summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authortoma <toma@283d02a7-25f6-0310-bc7c-ecb5cbfe19da>2009-11-25 17:56:58 +0000
committertoma <toma@283d02a7-25f6-0310-bc7c-ecb5cbfe19da>2009-11-25 17:56:58 +0000
commitbd9e6617827818fd043452c08c606f07b78014a0 (patch)
tree425bb4c3168f9c02f10150f235d2cb998dcc6108
downloadtdesdk-bd9e6617827818fd043452c08c606f07b78014a0.tar.gz
tdesdk-bd9e6617827818fd043452c08c606f07b78014a0.zip
Copy the KDE 3.5 branch to branches/trinity for new KDE 3.5 features.
BUG:215923 git-svn-id: svn://anonsvn.kde.org/home/kde/branches/trinity/kdesdk@1054174 283d02a7-25f6-0310-bc7c-ecb5cbfe19da
-rw-r--r--COPYING346
-rw-r--r--COPYING-DOCS397
-rw-r--r--Makefile.am.in19
-rw-r--r--Makefile.cvs15
-rw-r--r--README26
-rw-r--r--cervisia/COPYING339
-rw-r--r--cervisia/ChangeLog1543
-rw-r--r--cervisia/HACKING79
-rw-r--r--cervisia/Makefile.am73
-rw-r--r--cervisia/README19
-rw-r--r--cervisia/TODO26
-rw-r--r--cervisia/addremovedlg.cpp101
-rw-r--r--cervisia/addremovedlg.h49
-rw-r--r--cervisia/addrepositorydlg.cpp202
-rw-r--r--cervisia/addrepositorydlg.h73
-rw-r--r--cervisia/annotatectl.cpp198
-rw-r--r--cervisia/annotatectl.h44
-rw-r--r--cervisia/annotatedlg.cpp58
-rw-r--r--cervisia/annotatedlg.h59
-rw-r--r--cervisia/annotateview.cpp206
-rw-r--r--cervisia/annotateview.h56
-rw-r--r--cervisia/cervisia-change_repos_list.pl59
-rw-r--r--cervisia/cervisia-normalize_cvsroot.pl53
-rw-r--r--cervisia/cervisia.1.in217
-rw-r--r--cervisia/cervisia.desktop74
-rw-r--r--cervisia/cervisia.pod109
-rw-r--r--cervisia/cervisia.upd92
-rw-r--r--cervisia/cervisiapart.cpp1939
-rw-r--r--cervisia/cervisiapart.h219
-rw-r--r--cervisia/cervisiapart.kcfg37
-rw-r--r--cervisia/cervisiasettings.kcfgc4
-rw-r--r--cervisia/cervisiashell.cpp227
-rw-r--r--cervisia/cervisiashell.h71
-rw-r--r--cervisia/cervisiashellui.rc19
-rw-r--r--cervisia/cervisiaui.rc179
-rw-r--r--cervisia/change_colors.pl31
-rw-r--r--cervisia/changelogdlg.cpp188
-rw-r--r--cervisia/changelogdlg.h60
-rw-r--r--cervisia/checkoutdlg.cpp484
-rw-r--r--cervisia/checkoutdlg.h89
-rw-r--r--cervisia/commitdlg.cpp326
-rw-r--r--cervisia/commitdlg.h86
-rw-r--r--cervisia/cvsdir.cpp56
-rw-r--r--cervisia/cvsdir.h44
-rw-r--r--cervisia/cvsinitdlg.cpp91
-rw-r--r--cervisia/cvsinitdlg.h52
-rw-r--r--cervisia/cvsservice/DESIGN108
-rw-r--r--cervisia/cvsservice/Makefile.am54
-rw-r--r--cervisia/cvsservice/TODO12
-rw-r--r--cervisia/cvsservice/cvsaskpass.cpp77
-rw-r--r--cervisia/cvsservice/cvsjob.cpp236
-rw-r--r--cervisia/cvsservice/cvsjob.h83
-rw-r--r--cervisia/cvsservice/cvsloginjob.cpp156
-rw-r--r--cervisia/cvsservice/cvsloginjob.h58
-rw-r--r--cervisia/cvsservice/cvsservice.cpp1008
-rw-r--r--cervisia/cvsservice/cvsservice.desktop73
-rw-r--r--cervisia/cvsservice/cvsservice.h375
-rw-r--r--cervisia/cvsservice/cvsserviceutils.cpp45
-rw-r--r--cervisia/cvsservice/cvsserviceutils.h40
-rw-r--r--cervisia/cvsservice/main.cpp46
-rw-r--r--cervisia/cvsservice/repository.cpp266
-rw-r--r--cervisia/cvsservice/repository.h109
-rw-r--r--cervisia/cvsservice/sshagent.cpp237
-rw-r--r--cervisia/cvsservice/sshagent.h64
-rw-r--r--cervisia/diffdlg.cpp509
-rw-r--r--cervisia/diffdlg.h87
-rw-r--r--cervisia/diffview.cpp507
-rw-r--r--cervisia/diffview.h132
-rw-r--r--cervisia/dirignorelist.cpp47
-rw-r--r--cervisia/dirignorelist.h50
-rw-r--r--cervisia/editwithmenu.cpp78
-rw-r--r--cervisia/editwithmenu.h55
-rw-r--r--cervisia/entry.cpp34
-rw-r--r--cervisia/entry.h85
-rw-r--r--cervisia/entry_status.cpp81
-rw-r--r--cervisia/entry_status.h64
-rw-r--r--cervisia/entry_status_change.h54
-rw-r--r--cervisia/eventsrc88
-rw-r--r--cervisia/globalignorelist.cpp100
-rw-r--r--cervisia/globalignorelist.h55
-rw-r--r--cervisia/hi16-app-cervisia.pngbin0 -> 963 bytes
-rw-r--r--cervisia/hi22-app-cervisia.pngbin0 -> 1210 bytes
-rw-r--r--cervisia/hi32-app-cervisia.pngbin0 -> 2300 bytes
-rw-r--r--cervisia/hi48-app-cervisia.pngbin0 -> 4074 bytes
-rw-r--r--cervisia/historydlg.cpp397
-rw-r--r--cervisia/historydlg.h62
-rw-r--r--cervisia/ignorelistbase.cpp49
-rw-r--r--cervisia/ignorelistbase.h49
-rw-r--r--cervisia/logdlg.cpp620
-rw-r--r--cervisia/logdlg.h105
-rw-r--r--cervisia/loginfo.cpp140
-rw-r--r--cervisia/loginfo.h163
-rw-r--r--cervisia/loglist.cpp233
-rw-r--r--cervisia/loglist.h71
-rw-r--r--cervisia/logmessageedit.cpp204
-rw-r--r--cervisia/logmessageedit.h61
-rw-r--r--cervisia/logplainview.cpp203
-rw-r--r--cervisia/logplainview.h62
-rw-r--r--cervisia/logtree.cpp501
-rw-r--r--cervisia/logtree.h91
-rw-r--r--cervisia/main.cpp213
-rw-r--r--cervisia/mergedlg.cpp164
-rw-r--r--cervisia/mergedlg.h65
-rw-r--r--cervisia/misc.cpp350
-rw-r--r--cervisia/misc.h98
-rw-r--r--cervisia/move_repositories.pl42
-rw-r--r--cervisia/overview.h15
-rw-r--r--cervisia/patchoptiondlg.cpp115
-rw-r--r--cervisia/patchoptiondlg.h60
-rw-r--r--cervisia/pics/Makefile.am1
-rw-r--r--cervisia/pics/README9
-rw-r--r--cervisia/pics/cr16-action-vcs_add.pngbin0 -> 904 bytes
-rw-r--r--cervisia/pics/cr16-action-vcs_commit.pngbin0 -> 908 bytes
-rw-r--r--cervisia/pics/cr16-action-vcs_diff.pngbin0 -> 950 bytes
-rw-r--r--cervisia/pics/cr16-action-vcs_remove.pngbin0 -> 812 bytes
-rw-r--r--cervisia/pics/cr16-action-vcs_status.pngbin0 -> 942 bytes
-rw-r--r--cervisia/pics/cr16-action-vcs_update.pngbin0 -> 869 bytes
-rw-r--r--cervisia/pics/cr22-action-vcs_add.pngbin0 -> 1337 bytes
-rw-r--r--cervisia/pics/cr22-action-vcs_commit.pngbin0 -> 1355 bytes
-rw-r--r--cervisia/pics/cr22-action-vcs_diff.pngbin0 -> 1576 bytes
-rw-r--r--cervisia/pics/cr22-action-vcs_remove.pngbin0 -> 1186 bytes
-rw-r--r--cervisia/pics/cr22-action-vcs_status.pngbin0 -> 1443 bytes
-rw-r--r--cervisia/pics/cr22-action-vcs_update.pngbin0 -> 1277 bytes
-rw-r--r--cervisia/pics/cr32-action-vcs_add.pngbin0 -> 2135 bytes
-rw-r--r--cervisia/pics/cr32-action-vcs_commit.pngbin0 -> 2172 bytes
-rw-r--r--cervisia/pics/cr32-action-vcs_diff.pngbin0 -> 2833 bytes
-rw-r--r--cervisia/pics/cr32-action-vcs_remove.pngbin0 -> 1901 bytes
-rw-r--r--cervisia/pics/cr32-action-vcs_status.pngbin0 -> 2400 bytes
-rw-r--r--cervisia/pics/cr32-action-vcs_update.pngbin0 -> 2046 bytes
-rw-r--r--cervisia/pics/cr48-action-vcs_add.pngbin0 -> 3617 bytes
-rw-r--r--cervisia/pics/cr48-action-vcs_commit.pngbin0 -> 3712 bytes
-rw-r--r--cervisia/pics/cr48-action-vcs_diff.pngbin0 -> 5241 bytes
-rw-r--r--cervisia/pics/cr48-action-vcs_remove.pngbin0 -> 3212 bytes
-rw-r--r--cervisia/pics/cr48-action-vcs_status.pngbin0 -> 4265 bytes
-rw-r--r--cervisia/pics/cr48-action-vcs_update.pngbin0 -> 3554 bytes
-rw-r--r--cervisia/pics/crsc-action-vcs_add.svgzbin0 -> 6021 bytes
-rw-r--r--cervisia/pics/crsc-action-vcs_commit.svgzbin0 -> 6954 bytes
-rw-r--r--cervisia/pics/crsc-action-vcs_diff.svgzbin0 -> 6562 bytes
-rw-r--r--cervisia/pics/crsc-action-vcs_remove.svgzbin0 -> 5759 bytes
-rw-r--r--cervisia/pics/crsc-action-vcs_status.svgzbin0 -> 7371 bytes
-rw-r--r--cervisia/pics/crsc-action-vcs_update.svgzbin0 -> 6887 bytes
-rw-r--r--cervisia/progressdlg.cpp276
-rw-r--r--cervisia/progressdlg.h68
-rw-r--r--cervisia/protocolview.cpp196
-rw-r--r--cervisia/protocolview.h78
-rw-r--r--cervisia/qttableview.cpp2278
-rw-r--r--cervisia/qttableview.h252
-rw-r--r--cervisia/repositories.cpp129
-rw-r--r--cervisia/repositories.h38
-rw-r--r--cervisia/repositorydlg.cpp504
-rw-r--r--cervisia/repositorydlg.h77
-rw-r--r--cervisia/resolvedlg.cpp634
-rw-r--r--cervisia/resolvedlg.h98
-rw-r--r--cervisia/resolvedlg_p.cpp59
-rw-r--r--cervisia/resolvedlg_p.h51
-rw-r--r--cervisia/settingsdlg.cpp385
-rw-r--r--cervisia/settingsdlg.h104
-rw-r--r--cervisia/settingsdlg_advanced.ui97
-rw-r--r--cervisia/stringmatcher.cpp146
-rw-r--r--cervisia/stringmatcher.h77
-rw-r--r--cervisia/tagdlg.cpp147
-rw-r--r--cervisia/tagdlg.h74
-rw-r--r--cervisia/tests/resolvedlg-BR74903-test-01.txt4
-rw-r--r--cervisia/tests/resolvedlg-conflict-test-01.txt5
-rw-r--r--cervisia/tests/resolvedlg-conflict-test-02.txt9
-rw-r--r--cervisia/tooltip.cpp111
-rw-r--r--cervisia/tooltip.h75
-rw-r--r--cervisia/updatedlg.cpp161
-rw-r--r--cervisia/updatedlg.h66
-rw-r--r--cervisia/updateview.cpp629
-rw-r--r--cervisia/updateview.h117
-rw-r--r--cervisia/updateview_items.cpp826
-rw-r--r--cervisia/updateview_items.h169
-rw-r--r--cervisia/updateview_visitors.cpp98
-rw-r--r--cervisia/updateview_visitors.h69
-rw-r--r--cervisia/version.h2
-rw-r--r--cervisia/watchdlg.cpp107
-rw-r--r--cervisia/watchdlg.h52
-rw-r--r--cervisia/watchersdlg.cpp121
-rw-r--r--cervisia/watchersdlg.h45
-rw-r--r--configure.in.in5
-rw-r--r--doc/Makefile.am5
-rw-r--r--doc/cervisia/Makefile.am2
-rw-r--r--doc/cervisia/annotate.pngbin0 -> 8728 bytes
-rw-r--r--doc/cervisia/checkout.pngbin0 -> 8672 bytes
-rw-r--r--doc/cervisia/commit.pngbin0 -> 10511 bytes
-rw-r--r--doc/cervisia/diff.pngbin0 -> 15331 bytes
-rw-r--r--doc/cervisia/history.pngbin0 -> 10831 bytes
-rw-r--r--doc/cervisia/import.pngbin0 -> 7167 bytes
-rw-r--r--doc/cervisia/index.docbook3224
-rw-r--r--doc/cervisia/logtree.pngbin0 -> 13288 bytes
-rw-r--r--doc/cervisia/mainview.pngbin0 -> 26607 bytes
-rw-r--r--doc/cervisia/patch.pngbin0 -> 7065 bytes
-rw-r--r--doc/cervisia/popup.pngbin0 -> 8025 bytes
-rw-r--r--doc/cervisia/repositories.pngbin0 -> 16964 bytes
-rw-r--r--doc/cervisia/resolve.pngbin0 -> 14074 bytes
-rw-r--r--doc/cervisia/updatetag.pngbin0 -> 5939 bytes
-rw-r--r--doc/kapptemplate/Makefile.am2
-rw-r--r--doc/kapptemplate/man-kapptemplate.1.docbook115
-rw-r--r--doc/kbabel/Makefile.am3
-rw-r--r--doc/kbabel/TODO4
-rw-r--r--doc/kbabel/back.pngbin0 -> 1188 bytes
-rw-r--r--doc/kbabel/bottom.pngbin0 -> 599 bytes
-rw-r--r--doc/kbabel/catalogmanager.pngbin0 -> 1540 bytes
-rw-r--r--doc/kbabel/catalogmanager_broken.pngbin0 -> 188 bytes
-rw-r--r--doc/kbabel/catalogmanager_missing.pngbin0 -> 215 bytes
-rw-r--r--doc/kbabel/catalogmanager_needwork.pngbin0 -> 189 bytes
-rw-r--r--doc/kbabel/catalogmanager_nopot.pngbin0 -> 169 bytes
-rw-r--r--doc/kbabel/catalogmanager_nopot_ok.pngbin0 -> 267 bytes
-rw-r--r--doc/kbabel/catalogmanager_ok.pngbin0 -> 219 bytes
-rw-r--r--doc/kbabel/catalogmanager_reload.pngbin0 -> 1203 bytes
-rw-r--r--doc/kbabel/catman.docbook214
-rw-r--r--doc/kbabel/dbcan.pngbin0 -> 17645 bytes
-rw-r--r--doc/kbabel/dictionaries.docbook517
-rw-r--r--doc/kbabel/editcopy.pngbin0 -> 799 bytes
-rw-r--r--doc/kbabel/editcut.pngbin0 -> 833 bytes
-rw-r--r--doc/kbabel/editpaste.pngbin0 -> 979 bytes
-rw-r--r--doc/kbabel/faq.docbook66
-rw-r--r--doc/kbabel/fileopen.pngbin0 -> 554 bytes
-rw-r--r--doc/kbabel/filesave.pngbin0 -> 728 bytes
-rw-r--r--doc/kbabel/find.pngbin0 -> 1174 bytes
-rw-r--r--doc/kbabel/forward.pngbin0 -> 1173 bytes
-rw-r--r--doc/kbabel/glossary.docbook211
-rw-r--r--doc/kbabel/index.docbook174
-rw-r--r--doc/kbabel/kbabeldict.docbook85
-rw-r--r--doc/kbabel/man-catalogmanager.1.docbook77
-rw-r--r--doc/kbabel/menu.docbook2320
-rw-r--r--doc/kbabel/msgid2msgstr.pngbin0 -> 391 bytes
-rw-r--r--doc/kbabel/next.pngbin0 -> 247 bytes
-rw-r--r--doc/kbabel/nexterror.pngbin0 -> 375 bytes
-rw-r--r--doc/kbabel/nextfuzzy.pngbin0 -> 343 bytes
-rw-r--r--doc/kbabel/nextfuzzyuntrans.pngbin0 -> 351 bytes
-rw-r--r--doc/kbabel/nextuntranslated.pngbin0 -> 309 bytes
-rw-r--r--doc/kbabel/pref_diff.pngbin0 -> 9155 bytes
-rw-r--r--doc/kbabel/pref_edit_appearance.pngbin0 -> 9383 bytes
-rw-r--r--doc/kbabel/pref_edit_general.pngbin0 -> 12868 bytes
-rw-r--r--doc/kbabel/pref_fonts.pngbin0 -> 12317 bytes
-rw-r--r--doc/kbabel/pref_proj_catman.pngbin0 -> 10571 bytes
-rw-r--r--doc/kbabel/pref_proj_diff.pngbin0 -> 10616 bytes
-rw-r--r--doc/kbabel/pref_proj_file_commands.pngbin0 -> 13864 bytes
-rw-r--r--doc/kbabel/pref_proj_folder_commands.pngbin0 -> 12319 bytes
-rw-r--r--doc/kbabel/pref_proj_source.pngbin0 -> 14305 bytes
-rw-r--r--doc/kbabel/pref_search.pngbin0 -> 7939 bytes
-rw-r--r--doc/kbabel/pref_wizard_page1.pngbin0 -> 7117 bytes
-rw-r--r--doc/kbabel/pref_wizard_page2.pngbin0 -> 6475 bytes
-rw-r--r--doc/kbabel/preferences.docbook1418
-rw-r--r--doc/kbabel/preverror.pngbin0 -> 384 bytes
-rw-r--r--doc/kbabel/prevfuzzy.pngbin0 -> 341 bytes
-rw-r--r--doc/kbabel/prevfuzzyuntrans.pngbin0 -> 352 bytes
-rw-r--r--doc/kbabel/previous.pngbin0 -> 260 bytes
-rw-r--r--doc/kbabel/prevuntranslated.pngbin0 -> 308 bytes
-rw-r--r--doc/kbabel/redo.pngbin0 -> 632 bytes
-rw-r--r--doc/kbabel/roughtranslation.pngbin0 -> 16106 bytes
-rw-r--r--doc/kbabel/snap1.pngbin0 -> 37768 bytes
-rw-r--r--doc/kbabel/snap_catalogmanager.pngbin0 -> 38898 bytes
-rw-r--r--doc/kbabel/snap_kbabeldict.pngbin0 -> 19942 bytes
-rw-r--r--doc/kbabel/snap_kbabeldict2.pngbin0 -> 26772 bytes
-rw-r--r--doc/kbabel/stop.pngbin0 -> 821 bytes
-rw-r--r--doc/kbabel/top.pngbin0 -> 657 bytes
-rw-r--r--doc/kbabel/transsearch.pngbin0 -> 1357 bytes
-rw-r--r--doc/kbabel/undo.pngbin0 -> 578 bytes
-rw-r--r--doc/kbabel/using.docbook791
-rw-r--r--doc/kbugbuster/Makefile.am4
-rw-r--r--doc/kbugbuster/index.docbook78
-rw-r--r--doc/kcachegrind/Makefile.am4
-rw-r--r--doc/kcachegrind/index.docbook962
-rw-r--r--doc/kompare/Makefile.am4
-rw-r--r--doc/kompare/index.docbook910
-rw-r--r--doc/kompare/settings-diff1.pngbin0 -> 19714 bytes
-rw-r--r--doc/kompare/settings-diff2.pngbin0 -> 26853 bytes
-rw-r--r--doc/kompare/settings-diff3.pngbin0 -> 37895 bytes
-rw-r--r--doc/kompare/settings-diff4.pngbin0 -> 24142 bytes
-rw-r--r--doc/kompare/settings-view1.pngbin0 -> 30402 bytes
-rw-r--r--doc/kompare/settings-view2.pngbin0 -> 19989 bytes
-rw-r--r--doc/scripts/Makefile.am3
-rw-r--r--doc/scripts/kdesvn-build/Makefile.am2
-rw-r--r--doc/scripts/kdesvn-build/index.docbook1324
-rw-r--r--doc/scripts/man-adddebug.1.docbook66
-rw-r--r--doc/scripts/man-cheatmake.1.docbook103
-rw-r--r--doc/scripts/man-create_cvsignore.1.docbook50
-rw-r--r--doc/scripts/man-create_makefile.1.docbook94
-rw-r--r--doc/scripts/man-create_makefiles.1.docbook92
-rw-r--r--doc/scripts/man-cvscheck.1.docbook134
-rw-r--r--doc/scripts/man-cvslastchange.1.docbook52
-rw-r--r--doc/scripts/man-cvslastlog.1.docbook42
-rw-r--r--doc/scripts/man-cvsrevertlast.1.docbook48
-rw-r--r--doc/scripts/man-cxxmetric.1.docbook43
-rw-r--r--doc/scripts/man-demangle.1.docbook63
-rw-r--r--doc/scripts/man-extend_dmalloc.1.docbook54
-rw-r--r--doc/scripts/man-extractrc.1.docbook46
-rw-r--r--doc/scripts/man-fixincludes.1.docbook98
-rw-r--r--doc/scripts/man-po2xml.1.docbook58
-rw-r--r--doc/scripts/man-pruneemptydirs.1.docbook69
-rw-r--r--doc/scripts/man-qtdoc.1.docbook75
-rw-r--r--doc/scripts/man-reportview.1.docbook73
-rw-r--r--doc/scripts/man-split2po.1.docbook64
-rw-r--r--doc/scripts/man-swappo.1.docbook59
-rw-r--r--doc/scripts/man-transxx.1.docbook55
-rw-r--r--doc/scripts/man-xml2pot.1.docbook63
-rw-r--r--doc/scripts/man-zonetab2pot.1.docbook56
-rw-r--r--doc/umbrello/Makefile.am2
-rw-r--r--doc/umbrello/activity-diagram.pngbin0 -> 62231 bytes
-rw-r--r--doc/umbrello/add-remove-languages.pngbin0 -> 41025 bytes
-rw-r--r--doc/umbrello/aggregation.pngbin0 -> 1502 bytes
-rw-r--r--doc/umbrello/association.pngbin0 -> 2102 bytes
-rw-r--r--doc/umbrello/authors.docbook41
-rw-r--r--doc/umbrello/class-diagram.pngbin0 -> 44071 bytes
-rw-r--r--doc/umbrello/class.pngbin0 -> 4323 bytes
-rw-r--r--doc/umbrello/code-import.pngbin0 -> 28877 bytes
-rw-r--r--doc/umbrello/code_import_and_generation.docbook170
-rw-r--r--doc/umbrello/collaboration-diagram.pngbin0 -> 70040 bytes
-rw-r--r--doc/umbrello/composition.pngbin0 -> 1971 bytes
-rw-r--r--doc/umbrello/credits.docbook12
-rw-r--r--doc/umbrello/folders.pngbin0 -> 57871 bytes
-rw-r--r--doc/umbrello/generalization.pngbin0 -> 1805 bytes
-rw-r--r--doc/umbrello/generation-options.pngbin0 -> 47137 bytes
-rw-r--r--doc/umbrello/index.docbook69
-rw-r--r--doc/umbrello/introduction.docbook43
-rw-r--r--doc/umbrello/other_features.docbook61
-rw-r--r--doc/umbrello/sequence-diagram.pngbin0 -> 49267 bytes
-rw-r--r--doc/umbrello/state-diagram.pngbin0 -> 44030 bytes
-rw-r--r--doc/umbrello/umbrello-main-screen.pngbin0 -> 29106 bytes
-rw-r--r--doc/umbrello/umbrello-ui-clean.pngbin0 -> 28962 bytes
-rw-r--r--doc/umbrello/umbrello-ui.pngbin0 -> 31697 bytes
-rw-r--r--doc/umbrello/uml_basics.docbook616
-rw-r--r--doc/umbrello/use-case-diagram.pngbin0 -> 44945 bytes
-rw-r--r--doc/umbrello/working_with_umbrello.docbook448
-rw-r--r--kapptemplate/ChangeLog200
-rw-r--r--kapptemplate/Makefile.am19
-rw-r--r--kapptemplate/Makefile.cvs12
-rw-r--r--kapptemplate/README68
-rw-r--r--kapptemplate/VERSION1
-rw-r--r--kapptemplate/admin/Makefile.am12
-rw-r--r--kapptemplate/appframework/AUTHORS3
-rw-r--r--kapptemplate/appframework/COPYING2
-rw-r--r--kapptemplate/appframework/ChangeLog4
-rw-r--r--kapptemplate/appframework/INSTALL2
-rw-r--r--kapptemplate/appframework/Makefile.am6
-rw-r--r--kapptemplate/appframework/NEWS3
-rw-r--r--kapptemplate/appframework/README6
-rw-r--r--kapptemplate/appframework/VERSION3
-rw-r--r--kapptemplate/appframework/app.lsm18
-rw-r--r--kapptemplate/appframework/app.spec44
-rw-r--r--kapptemplate/appframework/base-Makefile.am11
-rw-r--r--kapptemplate/appframework/base-Makefile.cvs12
-rw-r--r--kapptemplate/appframework/configure.in.in.in3
-rw-r--r--kapptemplate/appframework/no-exe/COPYING339
-rw-r--r--kapptemplate/appframework/no-exe/INSTALL181
-rw-r--r--kapptemplate/appframework/no-exe/Makefile.am2
-rw-r--r--kapptemplate/appframework/po-Makefile.am3
-rw-r--r--kapptemplate/existing.module118
-rw-r--r--kapptemplate/existing/Makefile.am2
-rw-r--r--kapptemplate/existing/app-Makefile.am34
-rw-r--r--kapptemplate/existing/app-desktop9
-rw-r--r--kapptemplate/kapp/Makefile.am9
-rw-r--r--kapptemplate/kapp/app-Makefile.am47
-rw-r--r--kapptemplate/kapp/app-configure.in.in14
-rw-r--r--kapptemplate/kapp/app-desktop11
-rw-r--r--kapptemplate/kapp/app.cpp263
-rw-r--r--kapptemplate/kapp/app.h90
-rw-r--r--kapptemplate/kapp/app_client.cpp26
-rw-r--r--kapptemplate/kapp/appiface.h17
-rw-r--r--kapptemplate/kapp/apppref.cpp42
-rw-r--r--kapptemplate/kapp/apppref.h37
-rw-r--r--kapptemplate/kapp/appui.rc10
-rw-r--r--kapptemplate/kapp/appview.cpp106
-rw-r--r--kapptemplate/kapp/appview.h77
-rw-r--r--kapptemplate/kapp/doc-Makefile.am8
-rw-r--r--kapptemplate/kapp/doc-app-Makefile.am9
-rw-r--r--kapptemplate/kapp/hi16-app-app.png2
-rw-r--r--kapptemplate/kapp/hi32-app-app.png2
-rw-r--r--kapptemplate/kapp/hi48-app-app.png2
-rw-r--r--kapptemplate/kapp/index.docbook106
-rw-r--r--kapptemplate/kapp/lo16-app-app.png2
-rw-r--r--kapptemplate/kapp/lo32-app-app.png2
-rw-r--r--kapptemplate/kapp/main.cpp58
-rw-r--r--kapptemplate/kapp/no-exe/Makefile.am3
-rw-r--r--kapptemplate/kapp/no-exe/hi16-app-app.pngbin0 -> 845 bytes
-rw-r--r--kapptemplate/kapp/no-exe/hi32-app-app.pngbin0 -> 2595 bytes
-rw-r--r--kapptemplate/kapp/no-exe/hi48-app-app.pngbin0 -> 4954 bytes
-rw-r--r--kapptemplate/kapp/no-exe/lo16-app-app.pngbin0 -> 628 bytes
-rw-r--r--kapptemplate/kapp/no-exe/lo32-app-app.pngbin0 -> 1335 bytes
-rw-r--r--kapptemplate/kapp/pics-Makefile.am8
-rw-r--r--kapptemplate/kapptemplate.common496
-rw-r--r--kapptemplate/kapptemplate.in131
-rw-r--r--kapptemplate/kapptemplate.lsm18
-rw-r--r--kapptemplate/kapptemplate.module68
-rw-r--r--kapptemplate/kpartapp.module70
-rw-r--r--kapptemplate/kpartapp/Makefile.am10
-rw-r--r--kapptemplate/kpartapp/app-Makefile.am57
-rw-r--r--kapptemplate/kpartapp/app-configure.in.in14
-rw-r--r--kapptemplate/kpartapp/app-desktop11
-rw-r--r--kapptemplate/kpartapp/app.cpp176
-rw-r--r--kapptemplate/kpartapp/app.h70
-rw-r--r--kapptemplate/kpartapp/app_part-desktop9
-rw-r--r--kapptemplate/kpartapp/app_part.cpp148
-rw-r--r--kapptemplate/kpartapp/app_part.h69
-rw-r--r--kapptemplate/kpartapp/app_part.rc17
-rw-r--r--kapptemplate/kpartapp/app_shell.rc32
-rw-r--r--kapptemplate/kpartapp/doc-Makefile.am8
-rw-r--r--kapptemplate/kpartapp/doc-app-Makefile.am9
-rw-r--r--kapptemplate/kpartapp/hi16-app-app.png2
-rw-r--r--kapptemplate/kpartapp/hi32-app-app.png2
-rw-r--r--kapptemplate/kpartapp/hi48-app-app.png2
-rw-r--r--kapptemplate/kpartapp/index.docbook106
-rw-r--r--kapptemplate/kpartapp/lo16-app-app.png2
-rw-r--r--kapptemplate/kpartapp/lo32-app-app.png2
-rw-r--r--kapptemplate/kpartapp/main.cpp55
-rw-r--r--kapptemplate/kpartapp/no-exe/Makefile.am3
-rw-r--r--kapptemplate/kpartapp/no-exe/hi16-app-app.pngbin0 -> 845 bytes
-rw-r--r--kapptemplate/kpartapp/no-exe/hi32-app-app.pngbin0 -> 2595 bytes
-rw-r--r--kapptemplate/kpartapp/no-exe/hi48-app-app.pngbin0 -> 4954 bytes
-rw-r--r--kapptemplate/kpartapp/no-exe/lo16-app-app.pngbin0 -> 628 bytes
-rw-r--r--kapptemplate/kpartapp/no-exe/lo32-app-app.pngbin0 -> 1335 bytes
-rw-r--r--kapptemplate/kpartplugin.module69
-rw-r--r--kapptemplate/kpartplugin/Makefile.am5
-rw-r--r--kapptemplate/kpartplugin/hi16-action-plugin.png2
-rw-r--r--kapptemplate/kpartplugin/hi22-action-plugin.png2
-rw-r--r--kapptemplate/kpartplugin/no-exe/Makefile.am2
-rw-r--r--kapptemplate/kpartplugin/no-exe/hi16-action-plugin.pngbin0 -> 292 bytes
-rw-r--r--kapptemplate/kpartplugin/no-exe/hi22-action-plugin.pngbin0 -> 1151 bytes
-rw-r--r--kapptemplate/kpartplugin/plugin-Makefile.am20
-rw-r--r--kapptemplate/kpartplugin/plugin_app.cpp81
-rw-r--r--kapptemplate/kpartplugin/plugin_app.h20
-rw-r--r--kapptemplate/kpartplugin/plugin_app.rc13
-rwxr-xr-xkapptemplate/mkinstalldirs40
-rw-r--r--kbabel/AUTHORS7
-rw-r--r--kbabel/COPYING340
-rw-r--r--kbabel/ChangeLog287
-rw-r--r--kbabel/Makefile.am8
-rw-r--r--kbabel/README65
-rw-r--r--kbabel/TODO22
-rw-r--r--kbabel/VERSION1
-rw-r--r--kbabel/addons/Makefile.am3
-rw-r--r--kbabel/addons/kfile-plugins/Makefile.am22
-rw-r--r--kbabel/addons/kfile-plugins/kfile_po.cpp81
-rw-r--r--kbabel/addons/kfile-plugins/kfile_po.desktop61
-rw-r--r--kbabel/addons/kfile-plugins/kfile_po.h49
-rw-r--r--kbabel/addons/preview/Makefile.am15
-rw-r--r--kbabel/addons/preview/pothumbcreator.cpp360
-rw-r--r--kbabel/addons/preview/pothumbcreator.h54
-rw-r--r--kbabel/addons/preview/pothumbnail.desktop68
-rw-r--r--kbabel/catalogmanager/Makefile.am64
-rw-r--r--kbabel/catalogmanager/catalogmanager.cpp1371
-rw-r--r--kbabel/catalogmanager/catalogmanager.desktop98
-rw-r--r--kbabel/catalogmanager/catalogmanager.h218
-rw-r--r--kbabel/catalogmanager/catalogmanagerapp.h73
-rw-r--r--kbabel/catalogmanager/catalogmanageriface.h67
-rw-r--r--kbabel/catalogmanager/catalogmanagerui.rc262
-rw-r--r--kbabel/catalogmanager/catalogmanagerview.cpp3132
-rw-r--r--kbabel/catalogmanager/catalogmanagerview.h474
-rw-r--r--kbabel/catalogmanager/catmanlistitem.cpp932
-rw-r--r--kbabel/catalogmanager/catmanlistitem.h238
-rw-r--r--kbabel/catalogmanager/catmanresource.h73
-rw-r--r--kbabel/catalogmanager/findinfilesdialog.cpp229
-rw-r--r--kbabel/catalogmanager/findinfilesdialog.h85
-rw-r--r--kbabel/catalogmanager/future.cpp17
-rw-r--r--kbabel/catalogmanager/hi16-app-catalogmanager.pngbin0 -> 865 bytes
-rw-r--r--kbabel/catalogmanager/hi22-app-catalogmanager.pngbin0 -> 1396 bytes
-rw-r--r--kbabel/catalogmanager/hi32-app-catalogmanager.pngbin0 -> 2446 bytes
-rw-r--r--kbabel/catalogmanager/hi48-app-catalogmanager.pngbin0 -> 4498 bytes
-rw-r--r--kbabel/catalogmanager/icons/Makefile.am5
-rw-r--r--kbabel/catalogmanager/icons/hi16-action-nextmarked.pngbin0 -> 329 bytes
-rw-r--r--kbabel/catalogmanager/icons/hi16-action-nextpo.pngbin0 -> 348 bytes
-rw-r--r--kbabel/catalogmanager/icons/hi16-action-nexttemplate.pngbin0 -> 354 bytes
-rw-r--r--kbabel/catalogmanager/icons/hi16-action-prevmarked.pngbin0 -> 341 bytes
-rw-r--r--kbabel/catalogmanager/icons/hi16-action-prevpo.pngbin0 -> 356 bytes
-rw-r--r--kbabel/catalogmanager/icons/hi16-action-prevtemplate.pngbin0 -> 363 bytes
-rw-r--r--kbabel/catalogmanager/icons/hi16-action-statistics.pngbin0 -> 702 bytes
-rw-r--r--kbabel/catalogmanager/icons/hi16-action-syntax.pngbin0 -> 623 bytes
-rw-r--r--kbabel/catalogmanager/icons/hi22-action-nextmarked.pngbin0 -> 566 bytes
-rw-r--r--kbabel/catalogmanager/icons/hi22-action-nextpo.pngbin0 -> 454 bytes
-rw-r--r--kbabel/catalogmanager/icons/hi22-action-nexttemplate.pngbin0 -> 447 bytes
-rw-r--r--kbabel/catalogmanager/icons/hi22-action-prevmarked.pngbin0 -> 560 bytes
-rw-r--r--kbabel/catalogmanager/icons/hi22-action-prevpo.pngbin0 -> 440 bytes
-rw-r--r--kbabel/catalogmanager/icons/hi22-action-prevtemplate.pngbin0 -> 436 bytes
-rw-r--r--kbabel/catalogmanager/icons/hi22-action-statistics.pngbin0 -> 1180 bytes
-rw-r--r--kbabel/catalogmanager/icons/hi22-action-syntax.pngbin0 -> 1378 bytes
-rw-r--r--kbabel/catalogmanager/icons/hi32-action-nextmarked.pngbin0 -> 706 bytes
-rw-r--r--kbabel/catalogmanager/icons/hi32-action-nextpo.pngbin0 -> 593 bytes
-rw-r--r--kbabel/catalogmanager/icons/hi32-action-nexttemplate.pngbin0 -> 568 bytes
-rw-r--r--kbabel/catalogmanager/icons/hi32-action-prevmarked.pngbin0 -> 726 bytes
-rw-r--r--kbabel/catalogmanager/icons/hi32-action-prevpo.pngbin0 -> 624 bytes
-rw-r--r--kbabel/catalogmanager/icons/hi32-action-prevtemplate.pngbin0 -> 627 bytes
-rw-r--r--kbabel/catalogmanager/icons/hi32-action-statistics.pngbin0 -> 1456 bytes
-rw-r--r--kbabel/catalogmanager/icons/hi32-action-syntax.pngbin0 -> 1332 bytes
-rw-r--r--kbabel/catalogmanager/icons/lo16-action-nextmarked.pngbin0 -> 315 bytes
-rw-r--r--kbabel/catalogmanager/icons/lo16-action-nextpo.pngbin0 -> 353 bytes
-rw-r--r--kbabel/catalogmanager/icons/lo16-action-nexttemplate.pngbin0 -> 325 bytes
-rw-r--r--kbabel/catalogmanager/icons/lo16-action-prevmarked.pngbin0 -> 319 bytes
-rw-r--r--kbabel/catalogmanager/icons/lo16-action-prevpo.pngbin0 -> 362 bytes
-rw-r--r--kbabel/catalogmanager/icons/lo16-action-prevtemplate.pngbin0 -> 340 bytes
-rw-r--r--kbabel/catalogmanager/icons/lo16-action-statistics.pngbin0 -> 362 bytes
-rw-r--r--kbabel/catalogmanager/icons/lo16-action-syntax.pngbin0 -> 311 bytes
-rw-r--r--kbabel/catalogmanager/icons/lo22-action-statistics.pngbin0 -> 420 bytes
-rw-r--r--kbabel/catalogmanager/icons/lo22-action-syntax.pngbin0 -> 402 bytes
-rw-r--r--kbabel/catalogmanager/icons/lo32-action-nextmarked.pngbin0 -> 582 bytes
-rw-r--r--kbabel/catalogmanager/icons/lo32-action-nextpo.pngbin0 -> 593 bytes
-rw-r--r--kbabel/catalogmanager/icons/lo32-action-nexttemplate.pngbin0 -> 568 bytes
-rw-r--r--kbabel/catalogmanager/icons/lo32-action-prevmarked.pngbin0 -> 502 bytes
-rw-r--r--kbabel/catalogmanager/icons/lo32-action-prevpo.pngbin0 -> 497 bytes
-rw-r--r--kbabel/catalogmanager/icons/lo32-action-prevtemplate.pngbin0 -> 484 bytes
-rw-r--r--kbabel/catalogmanager/icons/lo32-action-statistics.pngbin0 -> 471 bytes
-rw-r--r--kbabel/catalogmanager/icons/lo32-action-syntax.pngbin0 -> 497 bytes
-rw-r--r--kbabel/catalogmanager/libcvs/Makefile.am11
-rw-r--r--kbabel/catalogmanager/libcvs/cvsdialog.cpp423
-rw-r--r--kbabel/catalogmanager/libcvs/cvsdialog.h158
-rw-r--r--kbabel/catalogmanager/libcvs/cvshandler.cpp398
-rw-r--r--kbabel/catalogmanager/libcvs/cvshandler.h114
-rw-r--r--kbabel/catalogmanager/libcvs/cvsresources.h41
-rw-r--r--kbabel/catalogmanager/libsvn/Makefile.am11
-rw-r--r--kbabel/catalogmanager/libsvn/svndialog.cpp400
-rw-r--r--kbabel/catalogmanager/libsvn/svndialog.h151
-rw-r--r--kbabel/catalogmanager/libsvn/svnhandler.cpp544
-rw-r--r--kbabel/catalogmanager/libsvn/svnhandler.h138
-rw-r--r--kbabel/catalogmanager/libsvn/svnresources.h50
-rw-r--r--kbabel/catalogmanager/lo16-app-catalogmanager.pngbin0 -> 323 bytes
-rw-r--r--kbabel/catalogmanager/lo32-app-catalogmanager.pngbin0 -> 554 bytes
-rw-r--r--kbabel/catalogmanager/main.cpp232
-rw-r--r--kbabel/catalogmanager/markpatterndialog.cpp172
-rw-r--r--kbabel/catalogmanager/markpatterndialog.h75
-rw-r--r--kbabel/catalogmanager/markpatternwidget.ui127
-rw-r--r--kbabel/catalogmanager/multiroughtransdlg.cpp148
-rw-r--r--kbabel/catalogmanager/multiroughtransdlg.h63
-rw-r--r--kbabel/catalogmanager/validateprogress.cpp313
-rw-r--r--kbabel/catalogmanager/validateprogress.h109
-rw-r--r--kbabel/catalogmanager/validateprogresswidget.ui129
-rw-r--r--kbabel/catalogmanager/validateprogresswidget.ui.h48
-rw-r--r--kbabel/catalogmanager/validationoptions.ui60
-rw-r--r--kbabel/common/Makefile.am67
-rw-r--r--kbabel/common/argextractor.cpp70
-rw-r--r--kbabel/common/argextractor.h83
-rw-r--r--kbabel/common/catalog.cpp3509
-rw-r--r--kbabel/common/catalog.h698
-rw-r--r--kbabel/common/catalog_private.h147
-rw-r--r--kbabel/common/catalogfileplugin.h205
-rw-r--r--kbabel/common/catalogitem.cpp521
-rw-r--r--kbabel/common/catalogitem.h220
-rw-r--r--kbabel/common/catalogitem_private.h90
-rw-r--r--kbabel/common/catalogsettings.cpp258
-rw-r--r--kbabel/common/catalogsettings.h176
-rw-r--r--kbabel/common/catalogview.h64
-rw-r--r--kbabel/common/diff.cpp465
-rw-r--r--kbabel/common/diff.h88
-rw-r--r--kbabel/common/editcmd.cpp106
-rw-r--r--kbabel/common/editcmd.h112
-rw-r--r--kbabel/common/exportplugin.cpp81
-rw-r--r--kbabel/common/findoptions.h86
-rw-r--r--kbabel/common/importplugin.cpp194
-rw-r--r--kbabel/common/importplugin_private.h69
-rw-r--r--kbabel/common/itempart.h37
-rw-r--r--kbabel/common/kbabel-projectrename.upd13
-rw-r--r--kbabel/common/kbabeldatatool.h63
-rw-r--r--kbabel/common/kbabelfilter.desktop60
-rw-r--r--kbabel/common/kbmailer.cpp244
-rw-r--r--kbabel/common/kbmailer.h166
-rw-r--r--kbabel/common/kbproject.cpp477
-rw-r--r--kbabel/common/kbproject.h109
-rw-r--r--kbabel/common/kbprojectmanager.cpp101
-rw-r--r--kbabel/common/kbprojectmanager.h62
-rw-r--r--kbabel/common/kbprojectsettings.kcfg354
-rw-r--r--kbabel/common/kbprojectsettings.kcfgc7
-rw-r--r--kbabel/common/libgettext/Makefile.am15
-rw-r--r--kbabel/common/libgettext/pofiles.h52
-rw-r--r--kbabel/common/libgettext/pofiles.ll107
-rw-r--r--kbabel/common/libgettext/tokens.h45
-rw-r--r--kbabel/common/msgfmt.cpp147
-rw-r--r--kbabel/common/msgfmt.h65
-rw-r--r--kbabel/common/pluralforms.h38
-rw-r--r--kbabel/common/poinfo.cpp781
-rw-r--r--kbabel/common/poinfo.h157
-rw-r--r--kbabel/common/projectsettings.cpp126
-rw-r--r--kbabel/common/projectsettings.h142
-rw-r--r--kbabel/common/regexpextractor.cpp271
-rw-r--r--kbabel/common/regexpextractor.h158
-rw-r--r--kbabel/common/resources.h43
-rw-r--r--kbabel/common/stringdistance.cpp182
-rw-r--r--kbabel/common/stringdistance.h131
-rw-r--r--kbabel/common/tagextractor.cpp54
-rw-r--r--kbabel/common/tagextractor.h58
-rw-r--r--kbabel/commonui/Makefile.am40
-rw-r--r--kbabel/commonui/cmdedit.cpp298
-rw-r--r--kbabel/commonui/cmdedit.h94
-rw-r--r--kbabel/commonui/context.cpp305
-rw-r--r--kbabel/commonui/context.h123
-rw-r--r--kbabel/commonui/diffpreferences.ui141
-rw-r--r--kbabel/commonui/diffpreferences.ui.h13
-rw-r--r--kbabel/commonui/finddialog.cpp553
-rw-r--r--kbabel/commonui/finddialog.h136
-rw-r--r--kbabel/commonui/kactionselector.cpp562
-rw-r--r--kbabel/commonui/kactionselector.h410
-rw-r--r--kbabel/commonui/kbabel_tool.desktop9
-rw-r--r--kbabel/commonui/kbabel_validator.desktop56
-rw-r--r--kbabel/commonui/klisteditor.ui261
-rw-r--r--kbabel/commonui/klisteditor.ui.h122
-rw-r--r--kbabel/commonui/projectpref.cpp278
-rw-r--r--kbabel/commonui/projectpref.h93
-rw-r--r--kbabel/commonui/projectprefwidgets.cpp1209
-rw-r--r--kbabel/commonui/projectprefwidgets.h285
-rw-r--r--kbabel/commonui/projectwizard.cpp172
-rw-r--r--kbabel/commonui/projectwizard.h74
-rw-r--r--kbabel/commonui/projectwizardwidget.ui266
-rw-r--r--kbabel/commonui/projectwizardwidget.ui.h40
-rw-r--r--kbabel/commonui/projectwizardwidget2.ui157
-rw-r--r--kbabel/commonui/roughtransdlg.cpp762
-rw-r--r--kbabel/commonui/roughtransdlg.h110
-rw-r--r--kbabel/commonui/toolaction.cpp108
-rw-r--r--kbabel/commonui/toolaction.h72
-rw-r--r--kbabel/commonui/toolselectionwidget.cpp105
-rw-r--r--kbabel/commonui/toolselectionwidget.h57
-rw-r--r--kbabel/configure.in.in12
-rw-r--r--kbabel/datatools/Makefile.am39
-rw-r--r--kbabel/datatools/accelerators/Makefile.am19
-rw-r--r--kbabel/datatools/accelerators/kbabel_accelstool.desktop105
-rw-r--r--kbabel/datatools/accelerators/main.cc137
-rw-r--r--kbabel/datatools/accelerators/main.h56
-rw-r--r--kbabel/datatools/arguments/Makefile.am19
-rw-r--r--kbabel/datatools/arguments/kbabel_argstool.desktop106
-rw-r--r--kbabel/datatools/arguments/main.cc277
-rw-r--r--kbabel/datatools/arguments/main.h55
-rw-r--r--kbabel/datatools/context/Makefile.am19
-rw-r--r--kbabel/datatools/context/kbabel_contexttool.desktop100
-rw-r--r--kbabel/datatools/context/main.cc115
-rw-r--r--kbabel/datatools/context/main.h52
-rw-r--r--kbabel/datatools/equations/Makefile.am19
-rw-r--r--kbabel/datatools/equations/kbabel_equationstool.desktop104
-rw-r--r--kbabel/datatools/equations/main.cc113
-rw-r--r--kbabel/datatools/equations/main.h50
-rw-r--r--kbabel/datatools/length/Makefile.am19
-rw-r--r--kbabel/datatools/length/kbabel_lengthtool.desktop98
-rw-r--r--kbabel/datatools/length/main.cc142
-rw-r--r--kbabel/datatools/length/main.h54
-rw-r--r--kbabel/datatools/length/test.po46
-rw-r--r--kbabel/datatools/not-translated/Makefile.am19
-rw-r--r--kbabel/datatools/not-translated/kbabel_nottranslatedtool.desktop97
-rw-r--r--kbabel/datatools/not-translated/main.cc129
-rw-r--r--kbabel/datatools/not-translated/main.h55
-rw-r--r--kbabel/datatools/not-translated/test.po48
-rw-r--r--kbabel/datatools/pluralforms/Makefile.am19
-rw-r--r--kbabel/datatools/pluralforms/kbabel_pluralformstool.desktop101
-rw-r--r--kbabel/datatools/pluralforms/main.cc129
-rw-r--r--kbabel/datatools/pluralforms/main.h53
-rw-r--r--kbabel/datatools/punctuation/Makefile.am19
-rw-r--r--kbabel/datatools/punctuation/kbabel_punctuationtool.desktop101
-rw-r--r--kbabel/datatools/punctuation/main.cc157
-rw-r--r--kbabel/datatools/punctuation/main.h47
-rw-r--r--kbabel/datatools/regexp/Makefile.am21
-rw-r--r--kbabel/datatools/regexp/kbabel_regexptool.desktop92
-rw-r--r--kbabel/datatools/regexp/main.cc181
-rw-r--r--kbabel/datatools/regexp/main.h73
-rw-r--r--kbabel/datatools/regexp/regexplist.xml303
-rw-r--r--kbabel/datatools/setfuzzy/Makefile.am19
-rw-r--r--kbabel/datatools/setfuzzy/kbabel_setfuzzytool.desktop98
-rw-r--r--kbabel/datatools/setfuzzy/main.cc98
-rw-r--r--kbabel/datatools/setfuzzy/main.h47
-rw-r--r--kbabel/datatools/whitespace/Makefile.am19
-rw-r--r--kbabel/datatools/whitespace/kbabel_whitespacetool.desktop98
-rw-r--r--kbabel/datatools/whitespace/main.cc144
-rw-r--r--kbabel/datatools/whitespace/main.h55
-rw-r--r--kbabel/datatools/whitespace/test.po92
-rw-r--r--kbabel/datatools/xml/Makefile.am19
-rw-r--r--kbabel/datatools/xml/kbabel_xmltool.desktop105
-rw-r--r--kbabel/datatools/xml/main.cc206
-rw-r--r--kbabel/datatools/xml/main.h59
-rw-r--r--kbabel/filters/Makefile.am3
-rw-r--r--kbabel/filters/gettext/Makefile.am20
-rw-r--r--kbabel/filters/gettext/gettextexport.cpp352
-rw-r--r--kbabel/filters/gettext/gettextexport.h88
-rw-r--r--kbabel/filters/gettext/gettextimport.cpp821
-rw-r--r--kbabel/filters/gettext/gettextimport.h70
-rw-r--r--kbabel/filters/gettext/kbabel_gettext_export.desktop53
-rw-r--r--kbabel/filters/gettext/kbabel_gettext_import.desktop53
-rw-r--r--kbabel/filters/linguist/Makefile.am18
-rw-r--r--kbabel/filters/linguist/kbabel_linguist_export.desktop53
-rw-r--r--kbabel/filters/linguist/kbabel_linguist_import.desktop53
-rw-r--r--kbabel/filters/linguist/linguistexport.cpp214
-rw-r--r--kbabel/filters/linguist/linguistexport.h68
-rw-r--r--kbabel/filters/linguist/linguistimport.cpp193
-rw-r--r--kbabel/filters/linguist/linguistimport.h68
-rw-r--r--kbabel/filters/xliff/Makefile.am18
-rw-r--r--kbabel/filters/xliff/kbabel_xliff_export.desktop47
-rw-r--r--kbabel/filters/xliff/kbabel_xliff_import.desktop47
-rw-r--r--kbabel/filters/xliff/xliffexport.cpp223
-rw-r--r--kbabel/filters/xliff/xliffexport.h66
-rw-r--r--kbabel/filters/xliff/xliffimport.cpp180
-rw-r--r--kbabel/filters/xliff/xliffimport.h68
-rw-r--r--kbabel/kbabel/Makefile.am92
-rw-r--r--kbabel/kbabel/charselectview.cpp115
-rw-r--r--kbabel/kbabel/charselectview.h71
-rw-r--r--kbabel/kbabel/colorpreferences.ui188
-rw-r--r--kbabel/kbabel/commentview.cpp221
-rw-r--r--kbabel/kbabel/commentview.h96
-rw-r--r--kbabel/kbabel/contextview.cpp158
-rw-r--r--kbabel/kbabel/contextview.h56
-rw-r--r--kbabel/kbabel/editordiffpreferences.ui192
-rw-r--r--kbabel/kbabel/editorpreferences.ui353
-rw-r--r--kbabel/kbabel/editorpreferences.ui.h23
-rw-r--r--kbabel/kbabel/errorlistview.cpp76
-rw-r--r--kbabel/kbabel/errorlistview.h55
-rw-r--r--kbabel/kbabel/fontpreferences.ui63
-rw-r--r--kbabel/kbabel/fontpreferences.ui.h14
-rw-r--r--kbabel/kbabel/gotodialog.cpp74
-rw-r--r--kbabel/kbabel/gotodialog.h63
-rw-r--r--kbabel/kbabel/headereditor.cpp214
-rw-r--r--kbabel/kbabel/headereditor.h85
-rw-r--r--kbabel/kbabel/headerwidget.ui64
-rw-r--r--kbabel/kbabel/hi16-app-kbabel.pngbin0 -> 952 bytes
-rw-r--r--kbabel/kbabel/hi32-app-kbabel.pngbin0 -> 2561 bytes
-rw-r--r--kbabel/kbabel/hi48-app-kbabel.pngbin0 -> 4753 bytes
-rw-r--r--kbabel/kbabel/hidingmsgedit.cpp426
-rw-r--r--kbabel/kbabel/hidingmsgedit.h161
-rw-r--r--kbabel/kbabel/icons/Makefile.am5
-rw-r--r--kbabel/kbabel/icons/hi16-action-autodiff.pngbin0 -> 242 bytes
-rw-r--r--kbabel/kbabel/icons/hi16-action-catalogmanager.pngbin0 -> 791 bytes
-rw-r--r--kbabel/kbabel/icons/hi16-action-diff.pngbin0 -> 203 bytes
-rw-r--r--kbabel/kbabel/icons/hi16-action-insert_arg.pngbin0 -> 303 bytes
-rw-r--r--kbabel/kbabel/icons/hi16-action-insert_tag.pngbin0 -> 329 bytes
-rw-r--r--kbabel/kbabel/icons/hi16-action-msgid2msgstr.pngbin0 -> 298 bytes
-rw-r--r--kbabel/kbabel/icons/hi16-action-nexterror.pngbin0 -> 416 bytes
-rw-r--r--kbabel/kbabel/icons/hi16-action-nextfuzzy.pngbin0 -> 299 bytes
-rw-r--r--kbabel/kbabel/icons/hi16-action-nextfuzzyuntrans.pngbin0 -> 422 bytes
-rw-r--r--kbabel/kbabel/icons/hi16-action-nextuntranslated.pngbin0 -> 323 bytes
-rw-r--r--kbabel/kbabel/icons/hi16-action-preverror.pngbin0 -> 443 bytes
-rw-r--r--kbabel/kbabel/icons/hi16-action-prevfuzzy.pngbin0 -> 346 bytes
-rw-r--r--kbabel/kbabel/icons/hi16-action-prevfuzzyuntrans.pngbin0 -> 469 bytes
-rw-r--r--kbabel/kbabel/icons/hi16-action-prevuntranslated.pngbin0 -> 350 bytes
-rw-r--r--kbabel/kbabel/icons/hi16-action-search2msgstr.pngbin0 -> 374 bytes
-rw-r--r--kbabel/kbabel/icons/hi16-action-spellcheck_actual.pngbin0 -> 223 bytes
-rw-r--r--kbabel/kbabel/icons/hi16-action-spellcheck_all.pngbin0 -> 204 bytes
-rw-r--r--kbabel/kbabel/icons/hi16-action-spellcheck_from_cursor.pngbin0 -> 216 bytes
-rw-r--r--kbabel/kbabel/icons/hi16-action-spellcheck_selected.pngbin0 -> 214 bytes
-rw-r--r--kbabel/kbabel/icons/hi16-action-togglefuzzy.pngbin0 -> 316 bytes
-rw-r--r--kbabel/kbabel/icons/hi16-action-transsearch.pngbin0 -> 694 bytes
-rw-r--r--kbabel/kbabel/icons/hi22-action-autodiff.pngbin0 -> 314 bytes
-rw-r--r--kbabel/kbabel/icons/hi22-action-catalogmanager.pngbin0 -> 1540 bytes
-rw-r--r--kbabel/kbabel/icons/hi22-action-diff.pngbin0 -> 227 bytes
-rw-r--r--kbabel/kbabel/icons/hi22-action-insert_arg.pngbin0 -> 316 bytes
-rw-r--r--kbabel/kbabel/icons/hi22-action-insert_tag.pngbin0 -> 332 bytes
-rw-r--r--kbabel/kbabel/icons/hi22-action-msgid2msgstr.pngbin0 -> 277 bytes
-rw-r--r--kbabel/kbabel/icons/hi22-action-nexterror.pngbin0 -> 530 bytes
-rw-r--r--kbabel/kbabel/icons/hi22-action-nextfuzzy.pngbin0 -> 471 bytes
-rw-r--r--kbabel/kbabel/icons/hi22-action-nextfuzzyuntrans.pngbin0 -> 561 bytes
-rw-r--r--kbabel/kbabel/icons/hi22-action-nextuntranslated.pngbin0 -> 459 bytes
-rw-r--r--kbabel/kbabel/icons/hi22-action-preverror.pngbin0 -> 465 bytes
-rw-r--r--kbabel/kbabel/icons/hi22-action-prevfuzzy.pngbin0 -> 413 bytes
-rw-r--r--kbabel/kbabel/icons/hi22-action-prevfuzzyuntrans.pngbin0 -> 490 bytes
-rw-r--r--kbabel/kbabel/icons/hi22-action-prevuntranslated.pngbin0 -> 399 bytes
-rw-r--r--kbabel/kbabel/icons/hi22-action-search2msgstr.pngbin0 -> 338 bytes
-rw-r--r--kbabel/kbabel/icons/hi22-action-togglefuzzy.pngbin0 -> 386 bytes
-rw-r--r--kbabel/kbabel/icons/hi22-action-transsearch.pngbin0 -> 1357 bytes
-rw-r--r--kbabel/kbabel/icons/hi32-action-autodiff.pngbin0 -> 571 bytes
-rw-r--r--kbabel/kbabel/icons/hi32-action-catalogmanager.pngbin0 -> 2201 bytes
-rw-r--r--kbabel/kbabel/icons/hi32-action-diff.pngbin0 -> 296 bytes
-rw-r--r--kbabel/kbabel/icons/hi32-action-insert_arg.pngbin0 -> 537 bytes
-rw-r--r--kbabel/kbabel/icons/hi32-action-insert_tag.pngbin0 -> 602 bytes
-rw-r--r--kbabel/kbabel/icons/hi32-action-msgid2msgstr.pngbin0 -> 531 bytes
-rw-r--r--kbabel/kbabel/icons/hi32-action-nexterror.pngbin0 -> 836 bytes
-rw-r--r--kbabel/kbabel/icons/hi32-action-nextfuzzy.pngbin0 -> 597 bytes
-rw-r--r--kbabel/kbabel/icons/hi32-action-nextfuzzyuntrans.pngbin0 -> 720 bytes
-rw-r--r--kbabel/kbabel/icons/hi32-action-nextuntranslated.pngbin0 -> 583 bytes
-rw-r--r--kbabel/kbabel/icons/hi32-action-preverror.pngbin0 -> 1334 bytes
-rw-r--r--kbabel/kbabel/icons/hi32-action-prevfuzzy.pngbin0 -> 1012 bytes
-rw-r--r--kbabel/kbabel/icons/hi32-action-prevfuzzyuntrans.pngbin0 -> 1140 bytes
-rw-r--r--kbabel/kbabel/icons/hi32-action-prevuntranslated.pngbin0 -> 1000 bytes
-rw-r--r--kbabel/kbabel/icons/hi32-action-search2msgstr.pngbin0 -> 756 bytes
-rw-r--r--kbabel/kbabel/icons/hi32-action-togglefuzzy.pngbin0 -> 854 bytes
-rw-r--r--kbabel/kbabel/icons/hi32-action-transsearch.pngbin0 -> 1807 bytes
-rw-r--r--kbabel/kbabel/icons/lo16-action-autodiff.pngbin0 -> 361 bytes
-rw-r--r--kbabel/kbabel/icons/lo16-action-catalogmanager.pngbin0 -> 588 bytes
-rw-r--r--kbabel/kbabel/icons/lo16-action-diff.pngbin0 -> 349 bytes
-rw-r--r--kbabel/kbabel/icons/lo16-action-insert_arg.pngbin0 -> 341 bytes
-rw-r--r--kbabel/kbabel/icons/lo16-action-insert_tag.pngbin0 -> 358 bytes
-rw-r--r--kbabel/kbabel/icons/lo16-action-msgid2msgstr.pngbin0 -> 342 bytes
-rw-r--r--kbabel/kbabel/icons/lo16-action-nexterror.pngbin0 -> 390 bytes
-rw-r--r--kbabel/kbabel/icons/lo16-action-nextfuzzy.pngbin0 -> 363 bytes
-rw-r--r--kbabel/kbabel/icons/lo16-action-nextfuzzyuntrans.pngbin0 -> 373 bytes
-rw-r--r--kbabel/kbabel/icons/lo16-action-nextuntranslated.pngbin0 -> 360 bytes
-rw-r--r--kbabel/kbabel/icons/lo16-action-preverror.pngbin0 -> 393 bytes
-rw-r--r--kbabel/kbabel/icons/lo16-action-prevfuzzy.pngbin0 -> 366 bytes
-rw-r--r--kbabel/kbabel/icons/lo16-action-prevfuzzyuntrans.pngbin0 -> 377 bytes
-rw-r--r--kbabel/kbabel/icons/lo16-action-prevuntranslated.pngbin0 -> 363 bytes
-rw-r--r--kbabel/kbabel/icons/lo16-action-search2msgstr.pngbin0 -> 370 bytes
-rw-r--r--kbabel/kbabel/icons/lo16-action-spellcheck_actual.pngbin0 -> 223 bytes
-rw-r--r--kbabel/kbabel/icons/lo16-action-spellcheck_all.pngbin0 -> 204 bytes
-rw-r--r--kbabel/kbabel/icons/lo16-action-spellcheck_from_cursor.pngbin0 -> 216 bytes
-rw-r--r--kbabel/kbabel/icons/lo16-action-spellcheck_selected.pngbin0 -> 214 bytes
-rw-r--r--kbabel/kbabel/icons/lo16-action-togglefuzzy.pngbin0 -> 316 bytes
-rw-r--r--kbabel/kbabel/icons/lo16-action-transsearch.pngbin0 -> 435 bytes
-rw-r--r--kbabel/kbabel/icons/lo32-action-autodiff.pngbin0 -> 478 bytes
-rw-r--r--kbabel/kbabel/icons/lo32-action-catalogmanager.pngbin0 -> 828 bytes
-rw-r--r--kbabel/kbabel/icons/lo32-action-diff.pngbin0 -> 390 bytes
-rw-r--r--kbabel/kbabel/icons/lo32-action-insert_arg.pngbin0 -> 409 bytes
-rw-r--r--kbabel/kbabel/icons/lo32-action-insert_tag.pngbin0 -> 431 bytes
-rw-r--r--kbabel/kbabel/icons/lo32-action-msgid2msgstr.pngbin0 -> 403 bytes
-rw-r--r--kbabel/kbabel/icons/lo32-action-nexterror.pngbin0 -> 539 bytes
-rw-r--r--kbabel/kbabel/icons/lo32-action-nextfuzzy.pngbin0 -> 430 bytes
-rw-r--r--kbabel/kbabel/icons/lo32-action-nextfuzzyuntrans.pngbin0 -> 472 bytes
-rw-r--r--kbabel/kbabel/icons/lo32-action-nextuntranslated.pngbin0 -> 429 bytes
-rw-r--r--kbabel/kbabel/icons/lo32-action-preverror.pngbin0 -> 547 bytes
-rw-r--r--kbabel/kbabel/icons/lo32-action-prevfuzzy.pngbin0 -> 428 bytes
-rw-r--r--kbabel/kbabel/icons/lo32-action-prevfuzzyuntrans.pngbin0 -> 474 bytes
-rw-r--r--kbabel/kbabel/icons/lo32-action-prevuntranslated.pngbin0 -> 427 bytes
-rw-r--r--kbabel/kbabel/icons/lo32-action-search2msgstr.pngbin0 -> 478 bytes
-rw-r--r--kbabel/kbabel/icons/lo32-action-togglefuzzy.pngbin0 -> 854 bytes
-rw-r--r--kbabel/kbabel/icons/lo32-action-transsearch.pngbin0 -> 1267 bytes
-rw-r--r--kbabel/kbabel/kbabel-difftoproject.upd6
-rw-r--r--kbabel/kbabel/kbabel-project.upd11
-rw-r--r--kbabel/kbabel/kbabel.cpp1825
-rw-r--r--kbabel/kbabel/kbabel.desktop83
-rw-r--r--kbabel/kbabel/kbabel.h325
-rw-r--r--kbabel/kbabel/kbabel.kcfg304
-rw-r--r--kbabel/kbabel/kbabeliface.h81
-rw-r--r--kbabel/kbabel/kbabelpref.cpp198
-rw-r--r--kbabel/kbabel/kbabelpref.h69
-rw-r--r--kbabel/kbabel/kbabelsettings.kcfgc5
-rw-r--r--kbabel/kbabel/kbabelsplash.cpp73
-rw-r--r--kbabel/kbabel/kbabelsplash.h55
-rw-r--r--kbabel/kbabel/kbabelui.rc235
-rw-r--r--kbabel/kbabel/kbabelview.cpp4473
-rw-r--r--kbabel/kbabel/kbabelview.h712
-rw-r--r--kbabel/kbabel/kbabelview2.cpp1025
-rw-r--r--kbabel/kbabel/kbbookmarkhandler.cpp131
-rw-r--r--kbabel/kbabel/kbbookmarkhandler.h155
-rw-r--r--kbabel/kbabel/kbcatalog.cpp63
-rw-r--r--kbabel/kbabel/kbcatalog.h61
-rw-r--r--kbabel/kbabel/kbcataloglistview.cpp136
-rw-r--r--kbabel/kbabel/kbcataloglistview.h82
-rw-r--r--kbabel/kbabel/kbcataloglistviewitem.cpp213
-rw-r--r--kbabel/kbabel/kbcataloglistviewitem.h72
-rw-r--r--kbabel/kbabel/kbcatalogview.cpp137
-rw-r--r--kbabel/kbabel/kbcatalogview.h102
-rw-r--r--kbabel/kbabel/kbcharselect.cpp94
-rw-r--r--kbabel/kbabel/kbcharselect.h65
-rw-r--r--kbabel/kbabel/kbhighlighting.cpp316
-rw-r--r--kbabel/kbabel/kbhighlighting.h104
-rw-r--r--kbabel/kbabel/lo16-app-kbabel.pngbin0 -> 352 bytes
-rw-r--r--kbabel/kbabel/lo32-app-kbabel.pngbin0 -> 546 bytes
-rw-r--r--kbabel/kbabel/main.cpp612
-rw-r--r--kbabel/kbabel/mymultilineedit.cpp1668
-rw-r--r--kbabel/kbabel/mymultilineedit.h307
-rw-r--r--kbabel/kbabel/pics/Makefile.am6
-rw-r--r--kbabel/kbabel/pics/broken.pngbin0 -> 188 bytes
-rw-r--r--kbabel/kbabel/pics/missing.pngbin0 -> 215 bytes
-rw-r--r--kbabel/kbabel/pics/needwork.pngbin0 -> 189 bytes
-rw-r--r--kbabel/kbabel/pics/noflag.pngbin0 -> 159 bytes
-rw-r--r--kbabel/kbabel/pics/ok.pngbin0 -> 219 bytes
-rw-r--r--kbabel/kbabel/pics/pref_identity.pngbin0 -> 1369 bytes
-rw-r--r--kbabel/kbabel/pics/splash.pngbin0 -> 24019 bytes
-rw-r--r--kbabel/kbabel/searchpreferences.ui109
-rw-r--r--kbabel/kbabel/sourceview.cpp75
-rw-r--r--kbabel/kbabel/sourceview.h57
-rw-r--r--kbabel/kbabel/spelldlg.cpp142
-rw-r--r--kbabel/kbabel/spelldlg.h63
-rw-r--r--kbabel/kbabel/spelldlgwidget.ui126
-rw-r--r--kbabel/kbabel/taglistview.cpp78
-rw-r--r--kbabel/kbabel/taglistview.h61
-rw-r--r--kbabel/kbabeldict/Makefile.am66
-rw-r--r--kbabel/kbabeldict/README5
-rw-r--r--kbabel/kbabeldict/README.modules34
-rw-r--r--kbabel/kbabeldict/aboutmoduledlg.cpp54
-rw-r--r--kbabel/kbabeldict/aboutmoduledlg.h55
-rw-r--r--kbabel/kbabeldict/dictchooser.cpp335
-rw-r--r--kbabel/kbabeldict/dictchooser.h94
-rw-r--r--kbabel/kbabeldict/dictionarymenu.cpp154
-rw-r--r--kbabel/kbabeldict/dictionarymenu.h81
-rw-r--r--kbabel/kbabeldict/hi16-app-kbabeldict.pngbin0 -> 829 bytes
-rw-r--r--kbabel/kbabeldict/hi32-app-kbabeldict.pngbin0 -> 2278 bytes
-rw-r--r--kbabel/kbabeldict/hi48-app-kbabeldict.pngbin0 -> 4127 bytes
-rw-r--r--kbabel/kbabeldict/kbabeldict.cpp113
-rw-r--r--kbabel/kbabeldict/kbabeldict.desktop96
-rw-r--r--kbabel/kbabeldict/kbabeldict.h62
-rw-r--r--kbabel/kbabeldict/kbabeldict_module.desktop54
-rw-r--r--kbabel/kbabeldict/kbabeldictbox.cpp1767
-rw-r--r--kbabel/kbabeldict/kbabeldictbox.h282
-rw-r--r--kbabel/kbabeldict/kbabeldictiface.h56
-rw-r--r--kbabel/kbabeldict/kbabeldictview.cpp294
-rw-r--r--kbabel/kbabeldict/kbabeldictview.h92
-rw-r--r--kbabel/kbabeldict/kbabelsplash.cpp73
-rw-r--r--kbabel/kbabeldict/kbabelsplash.h55
-rw-r--r--kbabel/kbabeldict/lo16-app-kbabeldict.pngbin0 -> 293 bytes
-rw-r--r--kbabel/kbabeldict/lo32-app-kbabeldict.pngbin0 -> 497 bytes
-rw-r--r--kbabel/kbabeldict/main.cpp136
-rw-r--r--kbabel/kbabeldict/modules/Makefile.am7
-rw-r--r--kbabel/kbabeldict/modules/dbsearchengine/AUTHOR1
-rw-r--r--kbabel/kbabeldict/modules/dbsearchengine/KDBSearchEngine.cpp1899
-rw-r--r--kbabel/kbabeldict/modules/dbsearchengine/KDBSearchEngine.h333
-rw-r--r--kbabel/kbabeldict/modules/dbsearchengine/Makefile.am34
-rw-r--r--kbabel/kbabeldict/modules/dbsearchengine/STRUCTURE25
-rw-r--r--kbabel/kbabeldict/modules/dbsearchengine/TODO27
-rw-r--r--kbabel/kbabeldict/modules/dbsearchengine/configure.in.bot5
-rw-r--r--kbabel/kbabeldict/modules/dbsearchengine/configure.in.in143
-rw-r--r--kbabel/kbabeldict/modules/dbsearchengine/database.cpp1533
-rw-r--r--kbabel/kbabeldict/modules/dbsearchengine/database.h329
-rw-r--r--kbabel/kbabeldict/modules/dbsearchengine/dbscan.cpp197
-rw-r--r--kbabel/kbabeldict/modules/dbsearchengine/dbscan.h86
-rw-r--r--kbabel/kbabeldict/modules/dbsearchengine/dbse_factory.cpp82
-rw-r--r--kbabel/kbabeldict/modules/dbsearchengine/dbse_factory.h26
-rw-r--r--kbabel/kbabeldict/modules/dbsearchengine/dbsearchengine.desktop52
-rw-r--r--kbabel/kbabeldict/modules/dbsearchengine/dbseprefwidget.ui1036
-rw-r--r--kbabel/kbabeldict/modules/dbsearchengine/makemsgdb.C327
-rw-r--r--kbabel/kbabeldict/modules/dbsearchengine/preferenceswidget.cpp111
-rw-r--r--kbabel/kbabeldict/modules/dbsearchengine/preferenceswidget.h28
-rw-r--r--kbabel/kbabeldict/modules/dbsearchengine2/AUTHOR1
-rw-r--r--kbabel/kbabeldict/modules/dbsearchengine2/KDBSearchEngine2.cpp686
-rw-r--r--kbabel/kbabeldict/modules/dbsearchengine2/KDBSearchEngine2.h202
-rw-r--r--kbabel/kbabeldict/modules/dbsearchengine2/Makefile.am34
-rw-r--r--kbabel/kbabeldict/modules/dbsearchengine2/README21
-rw-r--r--kbabel/kbabeldict/modules/dbsearchengine2/algorithms.cpp425
-rw-r--r--kbabel/kbabeldict/modules/dbsearchengine2/algorithms.h157
-rw-r--r--kbabel/kbabeldict/modules/dbsearchengine2/chunk.cpp203
-rw-r--r--kbabel/kbabeldict/modules/dbsearchengine2/chunk.h151
-rw-r--r--kbabel/kbabeldict/modules/dbsearchengine2/database.cpp752
-rw-r--r--kbabel/kbabeldict/modules/dbsearchengine2/database.h237
-rw-r--r--kbabel/kbabeldict/modules/dbsearchengine2/dbentries.cpp171
-rw-r--r--kbabel/kbabeldict/modules/dbsearchengine2/dbentries.h170
-rw-r--r--kbabel/kbabeldict/modules/dbsearchengine2/dbscan.cpp280
-rw-r--r--kbabel/kbabeldict/modules/dbsearchengine2/dbscan.h120
-rw-r--r--kbabel/kbabeldict/modules/dbsearchengine2/dbse2.ui732
-rw-r--r--kbabel/kbabeldict/modules/dbsearchengine2/dbse2_factory.cpp83
-rw-r--r--kbabel/kbabeldict/modules/dbsearchengine2/dbse2_factory.h26
-rw-r--r--kbabel/kbabeldict/modules/dbsearchengine2/dbsearchengine2.desktop52
-rw-r--r--kbabel/kbabeldict/modules/dbsearchengine2/dbseprefwidget.ui1039
-rw-r--r--kbabel/kbabeldict/modules/dbsearchengine2/preferenceswidget.cpp98
-rw-r--r--kbabel/kbabeldict/modules/dbsearchengine2/preferenceswidget.h26
-rw-r--r--kbabel/kbabeldict/modules/dbsearchengine2/sourcedialog.ui266
-rw-r--r--kbabel/kbabeldict/modules/poauxiliary/Makefile.am36
-rw-r--r--kbabel/kbabeldict/modules/poauxiliary/pa_factory.cpp110
-rw-r--r--kbabel/kbabeldict/modules/poauxiliary/pa_factory.h60
-rw-r--r--kbabel/kbabeldict/modules/poauxiliary/poauxiliary.cpp554
-rw-r--r--kbabel/kbabeldict/modules/poauxiliary/poauxiliary.desktop51
-rw-r--r--kbabel/kbabeldict/modules/poauxiliary/poauxiliary.h136
-rw-r--r--kbabel/kbabeldict/modules/poauxiliary/preferenceswidget.cpp115
-rw-r--r--kbabel/kbabeldict/modules/poauxiliary/preferenceswidget.h77
-rw-r--r--kbabel/kbabeldict/modules/poauxiliary/pwidget.ui133
-rw-r--r--kbabel/kbabeldict/modules/pocompendium/Makefile.am39
-rw-r--r--kbabel/kbabeldict/modules/pocompendium/compendiumdata.cpp261
-rw-r--r--kbabel/kbabeldict/modules/pocompendium/compendiumdata.h105
-rw-r--r--kbabel/kbabeldict/modules/pocompendium/pc_factory.cpp110
-rw-r--r--kbabel/kbabeldict/modules/pocompendium/pc_factory.h60
-rw-r--r--kbabel/kbabeldict/modules/pocompendium/pocompendium.cpp1246
-rw-r--r--kbabel/kbabeldict/modules/pocompendium/pocompendium.desktop50
-rw-r--r--kbabel/kbabeldict/modules/pocompendium/pocompendium.h147
-rw-r--r--kbabel/kbabeldict/modules/pocompendium/preferenceswidget.cpp352
-rw-r--r--kbabel/kbabeldict/modules/pocompendium/preferenceswidget.h97
-rw-r--r--kbabel/kbabeldict/modules/pocompendium/pwidget.ui280
-rw-r--r--kbabel/kbabeldict/modules/tmx/Makefile.am34
-rw-r--r--kbabel/kbabeldict/modules/tmx/pc_factory.cpp111
-rw-r--r--kbabel/kbabeldict/modules/tmx/pc_factory.h62
-rw-r--r--kbabel/kbabeldict/modules/tmx/preferenceswidget.cpp334
-rw-r--r--kbabel/kbabeldict/modules/tmx/preferenceswidget.h97
-rw-r--r--kbabel/kbabeldict/modules/tmx/pwidget.ui216
-rw-r--r--kbabel/kbabeldict/modules/tmx/tmxcompendium.cpp1007
-rw-r--r--kbabel/kbabeldict/modules/tmx/tmxcompendium.desktop50
-rw-r--r--kbabel/kbabeldict/modules/tmx/tmxcompendium.h137
-rw-r--r--kbabel/kbabeldict/modules/tmx/tmxcompendiumdata.cpp308
-rw-r--r--kbabel/kbabeldict/modules/tmx/tmxcompendiumdata.h106
-rw-r--r--kbabel/kbabeldict/searchengine.cpp283
-rw-r--r--kbabel/kbabeldict/searchengine.h534
-rw-r--r--kbugbuster/AUTHORS4
-rw-r--r--kbugbuster/COPYING340
-rw-r--r--kbugbuster/ChangeLog4
-rw-r--r--kbugbuster/INSTALL167
-rw-r--r--kbugbuster/Makefile.am28
-rw-r--r--kbugbuster/README2
-rw-r--r--kbugbuster/TODO4
-rw-r--r--kbugbuster/backend/Makefile.am16
-rw-r--r--kbugbuster/backend/bug.cpp240
-rw-r--r--kbugbuster/backend/bug.h92
-rw-r--r--kbugbuster/backend/bugcache.cpp289
-rw-r--r--kbugbuster/backend/bugcache.h47
-rw-r--r--kbugbuster/backend/bugcommand.cpp317
-rw-r--r--kbugbuster/backend/bugcommand.h217
-rw-r--r--kbugbuster/backend/bugdetails.cpp268
-rw-r--r--kbugbuster/backend/bugdetails.h55
-rw-r--r--kbugbuster/backend/bugdetailsimpl.h40
-rw-r--r--kbugbuster/backend/bugdetailsjob.cpp50
-rw-r--r--kbugbuster/backend/bugdetailsjob.h32
-rw-r--r--kbugbuster/backend/bugdetailspart.h21
-rw-r--r--kbugbuster/backend/bugimpl.h36
-rw-r--r--kbugbuster/backend/bugjob.cpp97
-rw-r--r--kbugbuster/backend/bugjob.h45
-rw-r--r--kbugbuster/backend/buglistjob.cpp75
-rw-r--r--kbugbuster/backend/buglistjob.h58
-rw-r--r--kbugbuster/backend/bugmybugsjob.cpp78
-rw-r--r--kbugbuster/backend/bugmybugsjob.h52
-rw-r--r--kbugbuster/backend/bugserver.cpp412
-rw-r--r--kbugbuster/backend/bugserver.h152
-rw-r--r--kbugbuster/backend/bugserverconfig.cpp150
-rw-r--r--kbugbuster/backend/bugserverconfig.h91
-rw-r--r--kbugbuster/backend/bugsystem.cpp436
-rw-r--r--kbugbuster/backend/bugsystem.h146
-rw-r--r--kbugbuster/backend/domprocessor.cpp407
-rw-r--r--kbugbuster/backend/domprocessor.h69
-rw-r--r--kbugbuster/backend/error.h43
-rw-r--r--kbugbuster/backend/htmlparser.cpp294
-rw-r--r--kbugbuster/backend/htmlparser.h116
-rw-r--r--kbugbuster/backend/kbbprefs.cpp170
-rw-r--r--kbugbuster/backend/kbbprefs.h82
-rw-r--r--kbugbuster/backend/mailsender.cpp212
-rw-r--r--kbugbuster/backend/mailsender.h50
-rw-r--r--kbugbuster/backend/package.cpp82
-rw-r--r--kbugbuster/backend/package.h43
-rw-r--r--kbugbuster/backend/packageimpl.h31
-rw-r--r--kbugbuster/backend/packagelistjob.cpp68
-rw-r--r--kbugbuster/backend/packagelistjob.h55
-rw-r--r--kbugbuster/backend/person.cpp74
-rw-r--r--kbugbuster/backend/person.h26
-rw-r--r--kbugbuster/backend/processor.cpp78
-rw-r--r--kbugbuster/backend/processor.h63
-rw-r--r--kbugbuster/backend/rdfprocessor.cpp107
-rw-r--r--kbugbuster/backend/rdfprocessor.h43
-rw-r--r--kbugbuster/backend/smtp.cpp181
-rw-r--r--kbugbuster/backend/smtp.h67
-rw-r--r--kbugbuster/configure.in.in8
-rw-r--r--kbugbuster/gui/Makefile.am24
-rw-r--r--kbugbuster/gui/README21
-rw-r--r--kbugbuster/gui/buglvi.cpp109
-rw-r--r--kbugbuster/gui/buglvi.h57
-rw-r--r--kbugbuster/gui/centralwidget.cpp507
-rw-r--r--kbugbuster/gui/centralwidget.h142
-rw-r--r--kbugbuster/gui/centralwidget_base.ui236
-rw-r--r--kbugbuster/gui/cwbugdetails.cpp212
-rw-r--r--kbugbuster/gui/cwbugdetails.h65
-rw-r--r--kbugbuster/gui/cwbugdetailscontainer.cpp269
-rw-r--r--kbugbuster/gui/cwbugdetailscontainer.h88
-rw-r--r--kbugbuster/gui/cwbugdetailscontainer_base.ui244
-rw-r--r--kbugbuster/gui/cwbuglistcontainer.cpp328
-rw-r--r--kbugbuster/gui/cwbuglistcontainer.h99
-rw-r--r--kbugbuster/gui/cwloadingwidget.cpp256
-rw-r--r--kbugbuster/gui/cwloadingwidget.h87
-rw-r--r--kbugbuster/gui/cwsearchwidget.cpp69
-rw-r--r--kbugbuster/gui/cwsearchwidget.h46
-rw-r--r--kbugbuster/gui/cwsearchwidget_base.ui198
-rw-r--r--kbugbuster/gui/kbbbookmarkmanager.h23
-rw-r--r--kbugbuster/gui/kbbmainwindow.cpp504
-rw-r--r--kbugbuster/gui/kbbmainwindow.h144
-rw-r--r--kbugbuster/gui/kbugbusterui.rc78
-rw-r--r--kbugbuster/gui/loadallbugsdlg.cpp92
-rw-r--r--kbugbuster/gui/loadallbugsdlg.h43
-rw-r--r--kbugbuster/gui/messageeditor.cpp117
-rw-r--r--kbugbuster/gui/messageeditor.h33
-rw-r--r--kbugbuster/gui/msginputdialog.cpp226
-rw-r--r--kbugbuster/gui/msginputdialog.h55
-rw-r--r--kbugbuster/gui/packagelvi.cpp38
-rw-r--r--kbugbuster/gui/packagelvi.h51
-rw-r--r--kbugbuster/gui/packageselectdialog.cpp214
-rw-r--r--kbugbuster/gui/packageselectdialog.h64
-rw-r--r--kbugbuster/gui/preferencesdialog.cpp306
-rw-r--r--kbugbuster/gui/preferencesdialog.h76
-rw-r--r--kbugbuster/gui/serverconfigdialog.cpp82
-rw-r--r--kbugbuster/gui/serverconfigdialog.h28
-rw-r--r--kbugbuster/gui/severityselectdialog.cpp40
-rw-r--r--kbugbuster/gui/severityselectdialog.h23
-rw-r--r--kbugbuster/hi128-app-kbugbuster.pngbin0 -> 13453 bytes
-rw-r--r--kbugbuster/hi16-app-kbugbuster.pngbin0 -> 1107 bytes
-rw-r--r--kbugbuster/hi22-app-kbugbuster.pngbin0 -> 1914 bytes
-rw-r--r--kbugbuster/hi32-app-kbugbuster.pngbin0 -> 2994 bytes
-rw-r--r--kbugbuster/hi48-app-kbugbuster.pngbin0 -> 5091 bytes
-rw-r--r--kbugbuster/hi64-app-kbugbuster.pngbin0 -> 7630 bytes
-rw-r--r--kbugbuster/kbugbuster.desktop78
-rw-r--r--kbugbuster/kresources/Makefile.am16
-rw-r--r--kbugbuster/kresources/bugzilla.desktop48
-rw-r--r--kbugbuster/kresources/kcalresource.cpp316
-rw-r--r--kbugbuster/kresources/kcalresource.h123
-rw-r--r--kbugbuster/kresources/kcalresource_plugin.cpp37
-rw-r--r--kbugbuster/kresources/kcalresourceconfig.cpp92
-rw-r--r--kbugbuster/kresources/kcalresourceconfig.h53
-rw-r--r--kbugbuster/kresources/kresources_kcal_bugzilla.kcfg20
-rw-r--r--kbugbuster/kresources/resourceprefs.kcfgc9
-rw-r--r--kbugbuster/lo16-app-kbugbuster.pngbin0 -> 305 bytes
-rw-r--r--kbugbuster/lo32-app-kbugbuster.pngbin0 -> 493 bytes
-rw-r--r--kbugbuster/main.cpp83
-rw-r--r--kbugbuster/pics/Makefile.am4
-rw-r--r--kbugbuster/pics/bars.pngbin0 -> 258 bytes
-rw-r--r--kbugbuster/pics/logo.pngbin0 -> 15734 bytes
-rw-r--r--kbugbuster/pics/tools.pngbin0 -> 76482 bytes
-rw-r--r--kbugbuster/pics/top-right.pngbin0 -> 13794 bytes
-rw-r--r--kcachegrind/AUTHORS1
-rw-r--r--kcachegrind/COPYING340
-rw-r--r--kcachegrind/ChangeLog89
-rw-r--r--kcachegrind/INSTALL167
-rw-r--r--kcachegrind/Makefile.am6
-rw-r--r--kcachegrind/NEWS0
-rw-r--r--kcachegrind/README62
-rw-r--r--kcachegrind/TODO100
-rw-r--r--kcachegrind/configure.in.in8
-rw-r--r--kcachegrind/converters/Makefile.am2
-rw-r--r--kcachegrind/converters/README24
-rw-r--r--kcachegrind/converters/dprof2calltree199
-rw-r--r--kcachegrind/converters/hotshot2calltree394
-rwxr-xr-xkcachegrind/converters/memprof2calltree38
-rwxr-xr-xkcachegrind/converters/op2calltree238
-rw-r--r--kcachegrind/converters/pprof2calltree218
-rw-r--r--kcachegrind/kcachegrind.lsm.in11
-rw-r--r--kcachegrind/kcachegrind.spec.in55
-rw-r--r--kcachegrind/kcachegrind/Doxyfile157
-rw-r--r--kcachegrind/kcachegrind/Makefile.am62
-rw-r--r--kcachegrind/kcachegrind/cachegrindloader.cpp1323
-rw-r--r--kcachegrind/kcachegrind/callgraphview.cpp2734
-rw-r--r--kcachegrind/kcachegrind/callgraphview.h499
-rw-r--r--kcachegrind/kcachegrind/callitem.cpp185
-rw-r--r--kcachegrind/kcachegrind/callitem.h50
-rw-r--r--kcachegrind/kcachegrind/callmapview.cpp999
-rw-r--r--kcachegrind/kcachegrind/callmapview.h129
-rw-r--r--kcachegrind/kcachegrind/callview.cpp256
-rw-r--r--kcachegrind/kcachegrind/callview.h55
-rw-r--r--kcachegrind/kcachegrind/configdlg.cpp398
-rw-r--r--kcachegrind/kcachegrind/configdlg.h64
-rw-r--r--kcachegrind/kcachegrind/configdlgbase.ui653
-rw-r--r--kcachegrind/kcachegrind/configuration.cpp490
-rw-r--r--kcachegrind/kcachegrind/configuration.h101
-rw-r--r--kcachegrind/kcachegrind/costlistitem.cpp136
-rw-r--r--kcachegrind/kcachegrind/costlistitem.h52
-rw-r--r--kcachegrind/kcachegrind/costtypeitem.cpp149
-rw-r--r--kcachegrind/kcachegrind/costtypeitem.h50
-rw-r--r--kcachegrind/kcachegrind/costtypeview.cpp310
-rw-r--r--kcachegrind/kcachegrind/costtypeview.h53
-rw-r--r--kcachegrind/kcachegrind/coverage.cpp329
-rw-r--r--kcachegrind/kcachegrind/coverage.h102
-rw-r--r--kcachegrind/kcachegrind/coverageitem.cpp343
-rw-r--r--kcachegrind/kcachegrind/coverageitem.h82
-rw-r--r--kcachegrind/kcachegrind/coverageview.cpp321
-rw-r--r--kcachegrind/kcachegrind/coverageview.h56
-rw-r--r--kcachegrind/kcachegrind/dumpmanager.cpp50
-rw-r--r--kcachegrind/kcachegrind/dumpmanager.h59
-rw-r--r--kcachegrind/kcachegrind/dumpselection.cpp33
-rw-r--r--kcachegrind/kcachegrind/dumpselection.h29
-rw-r--r--kcachegrind/kcachegrind/dumpselectionbase.ui1082
-rw-r--r--kcachegrind/kcachegrind/fixcost.cpp174
-rw-r--r--kcachegrind/kcachegrind/fixcost.h171
-rw-r--r--kcachegrind/kcachegrind/functionitem.cpp236
-rw-r--r--kcachegrind/kcachegrind/functionitem.h58
-rw-r--r--kcachegrind/kcachegrind/functionselection.cpp871
-rw-r--r--kcachegrind/kcachegrind/functionselection.h85
-rw-r--r--kcachegrind/kcachegrind/functionselectionbase.ui163
-rw-r--r--kcachegrind/kcachegrind/hi32-app-kcachegrind.pngbin0 -> 2411 bytes
-rw-r--r--kcachegrind/kcachegrind/hi48-app-kcachegrind.pngbin0 -> 9010 bytes
-rw-r--r--kcachegrind/kcachegrind/instritem.cpp469
-rw-r--r--kcachegrind/kcachegrind/instritem.h86
-rw-r--r--kcachegrind/kcachegrind/instrview.cpp949
-rw-r--r--kcachegrind/kcachegrind/instrview.h82
-rw-r--r--kcachegrind/kcachegrind/kcachegrind.desktop103
-rw-r--r--kcachegrind/kcachegrind/kcachegrindui.rc57
-rw-r--r--kcachegrind/kcachegrind/listutils.cpp266
-rw-r--r--kcachegrind/kcachegrind/listutils.h65
-rw-r--r--kcachegrind/kcachegrind/lo16-app-kcachegrind.pngbin0 -> 377 bytes
-rw-r--r--kcachegrind/kcachegrind/lo32-app-kcachegrind.pngbin0 -> 576 bytes
-rw-r--r--kcachegrind/kcachegrind/loader.cpp85
-rw-r--r--kcachegrind/kcachegrind/loader.h79
-rw-r--r--kcachegrind/kcachegrind/main.cpp95
-rw-r--r--kcachegrind/kcachegrind/multiview.cpp224
-rw-r--r--kcachegrind/kcachegrind/multiview.h66
-rw-r--r--kcachegrind/kcachegrind/partgraph.cpp534
-rw-r--r--kcachegrind/kcachegrind/partgraph.h131
-rw-r--r--kcachegrind/kcachegrind/partlistitem.cpp189
-rw-r--r--kcachegrind/kcachegrind/partlistitem.h54
-rw-r--r--kcachegrind/kcachegrind/partselection.cpp567
-rw-r--r--kcachegrind/kcachegrind/partselection.h95
-rw-r--r--kcachegrind/kcachegrind/partselectionbase.ui89
-rw-r--r--kcachegrind/kcachegrind/partview.cpp235
-rw-r--r--kcachegrind/kcachegrind/partview.h54
-rw-r--r--kcachegrind/kcachegrind/pool.cpp258
-rw-r--r--kcachegrind/kcachegrind/pool.h107
-rw-r--r--kcachegrind/kcachegrind/sourceitem.cpp444
-rw-r--r--kcachegrind/kcachegrind/sourceitem.h84
-rw-r--r--kcachegrind/kcachegrind/sourceview.cpp813
-rw-r--r--kcachegrind/kcachegrind/sourceview.h70
-rw-r--r--kcachegrind/kcachegrind/stackbrowser.cpp417
-rw-r--r--kcachegrind/kcachegrind/stackbrowser.h109
-rw-r--r--kcachegrind/kcachegrind/stackitem.cpp116
-rw-r--r--kcachegrind/kcachegrind/stackitem.h56
-rw-r--r--kcachegrind/kcachegrind/stackselection.cpp230
-rw-r--r--kcachegrind/kcachegrind/stackselection.h80
-rw-r--r--kcachegrind/kcachegrind/stackselectionbase.ui80
-rw-r--r--kcachegrind/kcachegrind/subcost.cpp62
-rw-r--r--kcachegrind/kcachegrind/subcost.h66
-rw-r--r--kcachegrind/kcachegrind/tabview.cpp890
-rw-r--r--kcachegrind/kcachegrind/tabview.h170
-rw-r--r--kcachegrind/kcachegrind/tips141
-rw-r--r--kcachegrind/kcachegrind/toplevel.cpp2399
-rw-r--r--kcachegrind/kcachegrind/toplevel.h274
-rw-r--r--kcachegrind/kcachegrind/tracedata.cpp5072
-rw-r--r--kcachegrind/kcachegrind/tracedata.h1967
-rw-r--r--kcachegrind/kcachegrind/traceitemview.cpp443
-rw-r--r--kcachegrind/kcachegrind/traceitemview.h206
-rw-r--r--kcachegrind/kcachegrind/treemap.cpp3214
-rw-r--r--kcachegrind/kcachegrind/treemap.h758
-rw-r--r--kcachegrind/kcachegrind/utils.cpp483
-rw-r--r--kcachegrind/kcachegrind/utils.h164
-rw-r--r--kcachegrind/kcachegrind/x-kcachegrind.desktop44
-rw-r--r--kcachegrind/pics/Makefile.am3
-rw-r--r--kcachegrind/pics/hicolor/Makefile.am2
-rw-r--r--kcachegrind/pics/hicolor/hi16-action-fromrec.pngbin0 -> 226 bytes
-rw-r--r--kcachegrind/pics/hicolor/hi16-action-percent.pngbin0 -> 261 bytes
-rw-r--r--kcachegrind/pics/hicolor/hi16-action-recrec.pngbin0 -> 266 bytes
-rw-r--r--kcachegrind/pics/hicolor/hi16-action-torec.pngbin0 -> 238 bytes
-rw-r--r--kcachegrind/pics/hicolor/hi22-action-percent.pngbin0 -> 351 bytes
-rw-r--r--kcachegrind/pics/hicolor/hi32-action-percent.pngbin0 -> 417 bytes
-rw-r--r--kcachegrind/tests/cg-badcompression117
-rw-r--r--kcachegrind/tests/cg-badcostline111
-rw-r--r--kcachegrind/tests/cg-badposition15
-rw-r--r--kcachegrind/version.h.in1
-rw-r--r--kdeaccounts-plugin/Makefile.am17
-rw-r--r--kdeaccounts-plugin/README15
-rw-r--r--kdeaccounts-plugin/kdeaccountsformat.cpp90
-rw-r--r--kdeaccounts-plugin/kdeaccountsformat.h51
-rw-r--r--kdeaccounts-plugin/kdeaccountsplugin.desktop44
-rw-r--r--kdepalettes/KDE_Gimp44
-rw-r--r--kdepalettes/README16
-rw-r--r--kdepalettes/kde_xpaintrc128
-rw-r--r--kdesdk.lsm11
-rw-r--r--kfile-plugins/Makefile.am1
-rw-r--r--kfile-plugins/c++/Makefile.am22
-rw-r--r--kfile-plugins/c++/kfile_cpp.cpp130
-rw-r--r--kfile-plugins/c++/kfile_cpp.desktop60
-rw-r--r--kfile-plugins/c++/kfile_cpp.h40
-rw-r--r--kfile-plugins/c++/kfile_h.desktop58
-rw-r--r--kfile-plugins/diff/Makefile.am22
-rw-r--r--kfile-plugins/diff/kfile_diff.cpp610
-rw-r--r--kfile-plugins/diff/kfile_diff.desktop57
-rw-r--r--kfile-plugins/diff/kfile_diff.h52
-rw-r--r--kfile-plugins/ts/Makefile.am21
-rw-r--r--kfile-plugins/ts/kfile_ts.cpp93
-rw-r--r--kfile-plugins/ts/kfile_ts.desktop54
-rw-r--r--kfile-plugins/ts/kfile_ts.h39
-rw-r--r--kioslave/Makefile.am6
-rw-r--r--kioslave/svn/AUTHORS1
-rw-r--r--kioslave/svn/COPYING481
-rw-r--r--kioslave/svn/Makefile.am15
-rw-r--r--kioslave/svn/README40
-rw-r--r--kioslave/svn/TODO74
-rw-r--r--kioslave/svn/configure.in.bot9
-rw-r--r--kioslave/svn/configure.in.in157
-rw-r--r--kioslave/svn/icons/Makefile.am1
-rw-r--r--kioslave/svn/icons/cr128-action-svn_add.pngbin0 -> 12287 bytes
-rw-r--r--kioslave/svn/icons/cr128-action-svn_branch.pngbin0 -> 12256 bytes
-rw-r--r--kioslave/svn/icons/cr128-action-svn_merge.pngbin0 -> 5183 bytes
-rw-r--r--kioslave/svn/icons/cr128-action-svn_remove.pngbin0 -> 12607 bytes
-rw-r--r--kioslave/svn/icons/cr128-action-svn_status.pngbin0 -> 14500 bytes
-rw-r--r--kioslave/svn/icons/cr128-action-svn_switch.pngbin0 -> 12428 bytes
-rw-r--r--kioslave/svn/icons/cr16-action-svn_add.pngbin0 -> 801 bytes
-rw-r--r--kioslave/svn/icons/cr16-action-svn_branch.pngbin0 -> 858 bytes
-rw-r--r--kioslave/svn/icons/cr16-action-svn_merge.pngbin0 -> 565 bytes
-rw-r--r--kioslave/svn/icons/cr16-action-svn_remove.pngbin0 -> 660 bytes
-rw-r--r--kioslave/svn/icons/cr16-action-svn_status.pngbin0 -> 926 bytes
-rw-r--r--kioslave/svn/icons/cr16-action-svn_switch.pngbin0 -> 752 bytes
-rw-r--r--kioslave/svn/icons/cr22-action-svn_add.pngbin0 -> 1232 bytes
-rw-r--r--kioslave/svn/icons/cr22-action-svn_branch.pngbin0 -> 1261 bytes
-rw-r--r--kioslave/svn/icons/cr22-action-svn_merge.pngbin0 -> 924 bytes
-rw-r--r--kioslave/svn/icons/cr22-action-svn_remove.pngbin0 -> 1041 bytes
-rw-r--r--kioslave/svn/icons/cr22-action-svn_status.pngbin0 -> 1392 bytes
-rw-r--r--kioslave/svn/icons/cr22-action-svn_switch.pngbin0 -> 1257 bytes
-rw-r--r--kioslave/svn/icons/cr32-action-svn_add.pngbin0 -> 1888 bytes
-rw-r--r--kioslave/svn/icons/cr32-action-svn_branch.pngbin0 -> 2093 bytes
-rw-r--r--kioslave/svn/icons/cr32-action-svn_merge.pngbin0 -> 1347 bytes
-rw-r--r--kioslave/svn/icons/cr32-action-svn_remove.pngbin0 -> 1694 bytes
-rw-r--r--kioslave/svn/icons/cr32-action-svn_status.pngbin0 -> 2326 bytes
-rw-r--r--kioslave/svn/icons/cr32-action-svn_switch.pngbin0 -> 2048 bytes
-rw-r--r--kioslave/svn/icons/cr48-action-svn_add.pngbin0 -> 3318 bytes
-rw-r--r--kioslave/svn/icons/cr48-action-svn_branch.pngbin0 -> 3527 bytes
-rw-r--r--kioslave/svn/icons/cr48-action-svn_merge.pngbin0 -> 2004 bytes
-rw-r--r--kioslave/svn/icons/cr48-action-svn_remove.pngbin0 -> 3064 bytes
-rw-r--r--kioslave/svn/icons/cr48-action-svn_status.pngbin0 -> 4072 bytes
-rw-r--r--kioslave/svn/icons/cr48-action-svn_switch.pngbin0 -> 3524 bytes
-rw-r--r--kioslave/svn/icons/cr64-action-svn_add.pngbin0 -> 4653 bytes
-rw-r--r--kioslave/svn/icons/cr64-action-svn_branch.pngbin0 -> 5140 bytes
-rw-r--r--kioslave/svn/icons/cr64-action-svn_merge.pngbin0 -> 2624 bytes
-rw-r--r--kioslave/svn/icons/cr64-action-svn_remove.pngbin0 -> 4472 bytes
-rw-r--r--kioslave/svn/icons/cr64-action-svn_status.pngbin0 -> 6036 bytes
-rw-r--r--kioslave/svn/icons/cr64-action-svn_switch.pngbin0 -> 5161 bytes
-rw-r--r--kioslave/svn/icons/crsc-action-svn_add.svgzbin0 -> 81728 bytes
-rw-r--r--kioslave/svn/icons/crsc-action-svn_branch.svgzbin0 -> 7200 bytes
-rw-r--r--kioslave/svn/icons/crsc-action-svn_merge.svgzbin0 -> 9170 bytes
-rw-r--r--kioslave/svn/icons/crsc-action-svn_remove.svgzbin0 -> 82210 bytes
-rw-r--r--kioslave/svn/icons/crsc-action-svn_status.svgzbin0 -> 3590 bytes
-rw-r--r--kioslave/svn/icons/crsc-action-svn_switch.svgzbin0 -> 8258 bytes
-rw-r--r--kioslave/svn/ksvnd/Makefile.am13
-rw-r--r--kioslave/svn/ksvnd/commitdlg.ui116
-rw-r--r--kioslave/svn/ksvnd/commitdlg.ui.h30
-rw-r--r--kioslave/svn/ksvnd/ksvnd.cpp351
-rw-r--r--kioslave/svn/ksvnd/ksvnd.desktop50
-rw-r--r--kioslave/svn/ksvnd/ksvnd.h69
-rw-r--r--kioslave/svn/svn+file.protocol43
-rw-r--r--kioslave/svn/svn+http.protocol43
-rw-r--r--kioslave/svn/svn+https.protocol43
-rw-r--r--kioslave/svn/svn+ssh.protocol43
-rw-r--r--kioslave/svn/svn.cpp1593
-rw-r--r--kioslave/svn/svn.h140
-rw-r--r--kioslave/svn/svn.protocol43
-rw-r--r--kioslave/svn/svnhelper/Makefile.am18
-rw-r--r--kioslave/svn/svnhelper/apply_patch.desktop94
-rw-r--r--kioslave/svn/svnhelper/kio_svn_helper.cpp292
-rw-r--r--kioslave/svn/svnhelper/kio_svn_helper.h41
-rw-r--r--kioslave/svn/svnhelper/subversion.desktop919
-rw-r--r--kioslave/svn/svnhelper/subversion_toplevel.desktop97
-rw-r--r--kioslave/svn/svnhelper/subversioncheckout.ui204
-rw-r--r--kioslave/svn/svnhelper/subversiondiff.ui100
-rw-r--r--kioslave/svn/svnhelper/subversionlog.ui100
-rw-r--r--kioslave/svn/svnhelper/subversionswitch.ui204
-rw-r--r--kmtrace/Makefile.am50
-rw-r--r--kmtrace/README110
-rw-r--r--kmtrace/configure.in.in18
-rw-r--r--kmtrace/demangle.cpp60
-rw-r--r--kmtrace/kde.excludes49
-rwxr-xr-xkmtrace/kminspector.in9
-rw-r--r--kmtrace/kmtrace.cpp721
-rw-r--r--kmtrace/ksotrace.cpp11
-rw-r--r--kmtrace/ktrace.c840
-rw-r--r--kmtrace/ktrace.h10
-rw-r--r--kmtrace/match.cpp73
-rw-r--r--kmtrace/mtrace.c383
-rw-r--r--kompare/AUTHORS2
-rw-r--r--kompare/COPYING340
-rw-r--r--kompare/ChangeLog423
-rw-r--r--kompare/DESIGN35
-rw-r--r--kompare/Makefile.am43
-rw-r--r--kompare/README16
-rw-r--r--kompare/TODO34
-rw-r--r--kompare/interfaces/Makefile.am8
-rw-r--r--kompare/interfaces/kompareinterface.cpp60
-rw-r--r--kompare/interfaces/kompareinterface.h105
-rw-r--r--kompare/kompare.desktop74
-rw-r--r--kompare/kompare_shell.cpp487
-rw-r--r--kompare/kompare_shell.h149
-rw-r--r--kompare/komparenavigationpart.desktop4
-rw-r--r--kompare/komparenavtreepart/Makefile.am29
-rw-r--r--kompare/komparenavtreepart/komparenavtreepart.cpp710
-rw-r--r--kompare/komparenavtreepart/komparenavtreepart.desktop11
-rw-r--r--kompare/komparenavtreepart/komparenavtreepart.h191
-rw-r--r--kompare/komparepart/Makefile.am49
-rw-r--r--kompare/komparepart/kompare_part.cpp759
-rw-r--r--kompare/komparepart/kompare_part.h223
-rw-r--r--kompare/komparepart/kompare_qsplitter.h213
-rw-r--r--kompare/komparepart/kompareconnectwidget.cpp285
-rw-r--r--kompare/komparepart/kompareconnectwidget.h95
-rw-r--r--kompare/komparepart/komparelistview.cpp783
-rw-r--r--kompare/komparepart/komparelistview.h225
-rw-r--r--kompare/komparepart/komparepart.desktop24
-rw-r--r--kompare/komparepart/komparepartui.rc44
-rw-r--r--kompare/komparepart/kompareprefdlg.cpp106
-rw-r--r--kompare/komparepart/kompareprefdlg.h54
-rw-r--r--kompare/komparepart/komparesaveoptionsbase.ui336
-rw-r--r--kompare/komparepart/komparesaveoptionswidget.cpp215
-rw-r--r--kompare/komparepart/komparesaveoptionswidget.h51
-rw-r--r--kompare/komparepart/komparesplitter.cpp712
-rw-r--r--kompare/komparepart/komparesplitter.h115
-rw-r--r--kompare/kompareui.rc33
-rw-r--r--kompare/kompareurldialog.cpp143
-rw-r--r--kompare/kompareurldialog.h76
-rw-r--r--kompare/kompareviewpart.desktop4
-rw-r--r--kompare/libdialogpages/Makefile.am32
-rw-r--r--kompare/libdialogpages/diffpage.cpp355
-rw-r--r--kompare/libdialogpages/diffpage.h100
-rw-r--r--kompare/libdialogpages/diffsettings.cpp108
-rw-r--r--kompare/libdialogpages/diffsettings.h66
-rw-r--r--kompare/libdialogpages/filespage.cpp170
-rw-r--r--kompare/libdialogpages/filespage.h83
-rw-r--r--kompare/libdialogpages/filessettings.cpp60
-rw-r--r--kompare/libdialogpages/filessettings.h53
-rw-r--r--kompare/libdialogpages/pagebase.cpp104
-rw-r--r--kompare/libdialogpages/pagebase.h49
-rw-r--r--kompare/libdialogpages/settingsbase.cpp42
-rw-r--r--kompare/libdialogpages/settingsbase.h42
-rw-r--r--kompare/libdialogpages/viewpage.cpp179
-rw-r--r--kompare/libdialogpages/viewpage.h64
-rw-r--r--kompare/libdialogpages/viewsettings.cpp101
-rw-r--r--kompare/libdialogpages/viewsettings.h61
-rw-r--r--kompare/libdiff2/Makefile.am37
-rw-r--r--kompare/libdiff2/cvsdiffparser.cpp160
-rw-r--r--kompare/libdiff2/cvsdiffparser.h61
-rw-r--r--kompare/libdiff2/difference.cpp137
-rw-r--r--kompare/libdiff2/difference.h223
-rw-r--r--kompare/libdiff2/diffhunk.cpp115
-rw-r--r--kompare/libdiff2/diffhunk.h69
-rw-r--r--kompare/libdiff2/diffmodel.cpp409
-rw-r--r--kompare/libdiff2/diffmodel.h150
-rw-r--r--kompare/libdiff2/diffmodellist.cpp29
-rw-r--r--kompare/libdiff2/diffmodellist.h49
-rw-r--r--kompare/libdiff2/diffparser.cpp81
-rw-r--r--kompare/libdiff2/diffparser.h38
-rw-r--r--kompare/libdiff2/kompare.h144
-rw-r--r--kompare/libdiff2/komparemodellist.cpp1423
-rw-r--r--kompare/libdiff2/komparemodellist.h213
-rw-r--r--kompare/libdiff2/kompareprocess.cpp269
-rw-r--r--kompare/libdiff2/kompareprocess.h67
-rw-r--r--kompare/libdiff2/levenshteintable.cpp332
-rw-r--r--kompare/libdiff2/levenshteintable.h69
-rw-r--r--kompare/libdiff2/parser.cpp139
-rw-r--r--kompare/libdiff2/parser.h58
-rw-r--r--kompare/libdiff2/parserbase.cpp739
-rw-r--r--kompare/libdiff2/parserbase.h133
-rw-r--r--kompare/libdiff2/perforceparser.cpp223
-rw-r--r--kompare/libdiff2/perforceparser.h44
-rw-r--r--kompare/main.cpp217
-rw-r--r--kompare/pics/Makefile.am3
-rw-r--r--kompare/pics/hi128-app-kompare.pngbin0 -> 19472 bytes
-rw-r--r--kompare/pics/hi16-app-kompare.pngbin0 -> 917 bytes
-rw-r--r--kompare/pics/hi22-app-kompare.pngbin0 -> 1237 bytes
-rw-r--r--kompare/pics/hi32-app-kompare.pngbin0 -> 2771 bytes
-rw-r--r--kompare/pics/hi48-app-kompare.pngbin0 -> 4780 bytes
-rw-r--r--kompare/pics/hisc-app-kompare.svgzbin0 -> 1474 bytes
-rw-r--r--kompare/tests/cvsdiff/context.diff83
-rw-r--r--kompare/tests/cvsdiff/contextm.diff1046
-rw-r--r--kompare/tests/cvsdiff/ed.diff24
-rw-r--r--kompare/tests/cvsdiff/edm.diff692
-rw-r--r--kompare/tests/cvsdiff/normal.diff29
-rw-r--r--kompare/tests/cvsdiff/normalm.diff861
-rw-r--r--kompare/tests/cvsdiff/rcs.diff24
-rw-r--r--kompare/tests/cvsdiff/rcsm.diff683
-rw-r--r--kompare/tests/cvsdiff/unified.diff50
-rw-r--r--kompare/tests/cvsdiff/unifiedm.diff924
-rw-r--r--kompare/tests/diff/context.diff27
-rw-r--r--kompare/tests/diff/contextm.diff1032
-rw-r--r--kompare/tests/diff/contextp.diff27
-rw-r--r--kompare/tests/diff/ed.diff10
-rw-r--r--kompare/tests/diff/edm.diff680
-rw-r--r--kompare/tests/diff/normal.diff12
-rw-r--r--kompare/tests/diff/normalm.diff849
-rw-r--r--kompare/tests/diff/rcs.diff9
-rw-r--r--kompare/tests/diff/rcsm.diff671
-rw-r--r--kompare/tests/diff/unified.diff19
-rw-r--r--kompare/tests/diff/unifiedm.diff911
-rw-r--r--kompare/tests/diff/unifiedp.diff19
-rw-r--r--kompare/tests/perforce/context.diff8
-rw-r--r--kompare/tests/perforce/contextm.diff23
-rw-r--r--kompare/tests/perforce/rcs.diff3
-rw-r--r--kompare/tests/perforce/rcsm.diff12
-rw-r--r--kompare/tests/perforce/unified.diff6
-rw-r--r--kompare/tests/perforce/unifiedm.diff19
-rw-r--r--kompare/tests/subversion/context.diff9
-rw-r--r--kompare/tests/subversion/contextm.diff180
-rw-r--r--kompare/tests/subversion/ed.diff5
-rw-r--r--kompare/tests/subversion/edm.diff57
-rw-r--r--kompare/tests/subversion/normal.diff6
-rw-r--r--kompare/tests/subversion/normalm.diff170
-rw-r--r--kompare/tests/subversion/rcs.diff5
-rw-r--r--kompare/tests/subversion/rcsm.diff55
-rw-r--r--kompare/tests/subversion/unified.diff7
-rw-r--r--kompare/tests/subversion/unifiedm.diff173
-rw-r--r--kprofilemethod/Makefile.am2
-rw-r--r--kprofilemethod/README21
-rw-r--r--kprofilemethod/kprofilemethod.h51
-rw-r--r--kspy/Makefile.am30
-rw-r--r--kspy/README12
-rw-r--r--kspy/classinfoview.cpp58
-rw-r--r--kspy/classinfoview.h40
-rw-r--r--kspy/kspy.h44
-rw-r--r--kspy/main.cpp52
-rw-r--r--kspy/navview.cpp88
-rw-r--r--kspy/navview.h57
-rw-r--r--kspy/navviewitem.cpp40
-rw-r--r--kspy/navviewitem.h38
-rw-r--r--kspy/propsview.cpp196
-rw-r--r--kspy/propsview.h40
-rw-r--r--kspy/receiversview.cpp80
-rw-r--r--kspy/receiversview.h40
-rw-r--r--kspy/sigslotview.cpp73
-rw-r--r--kspy/sigslotview.h40
-rw-r--r--kspy/spy.cpp115
-rw-r--r--kspy/spy.h59
-rw-r--r--kstartperf/Makefile.am14
-rw-r--r--kstartperf/README31
-rw-r--r--kstartperf/kstartperf.cpp124
-rw-r--r--kstartperf/libkstartperf.c122
-rw-r--r--kuiviewer/Makefile.am70
-rw-r--r--kuiviewer/designerthumbnail.desktop53
-rw-r--r--kuiviewer/hi16-app-kuiviewer.pngbin0 -> 845 bytes
-rw-r--r--kuiviewer/hi32-app-kuiviewer.pngbin0 -> 2595 bytes
-rw-r--r--kuiviewer/hi48-app-kuiviewer.pngbin0 -> 4954 bytes
-rw-r--r--kuiviewer/kuiviewer.cpp165
-rw-r--r--kuiviewer/kuiviewer.desktop58
-rw-r--r--kuiviewer/kuiviewer.h103
-rw-r--r--kuiviewer/kuiviewer_part.cpp211
-rw-r--r--kuiviewer/kuiviewer_part.desktop9
-rw-r--r--kuiviewer/kuiviewer_part.h80
-rw-r--r--kuiviewer/kuiviewer_part.rc17
-rw-r--r--kuiviewer/kuiviewerui.rc8
-rw-r--r--kuiviewer/lo16-app-kuiviewer.pngbin0 -> 309 bytes
-rw-r--r--kuiviewer/lo32-app-kuiviewer.pngbin0 -> 497 bytes
-rw-r--r--kuiviewer/main.cpp88
-rw-r--r--kuiviewer/quicreator.cpp61
-rw-r--r--kuiviewer/quicreator.h36
-rw-r--r--kunittest/Makefile.am21
-rw-r--r--kunittest/dcopinterface.h38
-rw-r--r--kunittest/example/Makefile.am1
-rw-r--r--kunittest/example/module/Makefile.am20
-rw-r--r--kunittest/example/module/sampleextra.cpp37
-rw-r--r--kunittest/example/module/sampleextra.h36
-rw-r--r--kunittest/example/module/samplemodule.cpp37
-rw-r--r--kunittest/example/module/samplemodule.h43
-rw-r--r--kunittest/example/module/samplemodule2.cpp61
-rw-r--r--kunittest/example/module/samplemodule2.h43
-rw-r--r--kunittest/example/module/sampletests.cpp82
-rw-r--r--kunittest/example/module/sampletests.h53
-rw-r--r--kunittest/example/simple/Makefile.am22
-rw-r--r--kunittest/example/simple/main.cpp32
-rw-r--r--kunittest/example/simple/maingui.cpp60
-rw-r--r--kunittest/example/simple/sampletest.cpp55
-rw-r--r--kunittest/example/simple/sampletest.h42
-rw-r--r--kunittest/guimodrunner.cpp72
-rwxr-xr-xkunittest/kunittest19
-rwxr-xr-xkunittest/kunittest_debughelper107
-rwxr-xr-xkunittest/kunittestmod37
-rw-r--r--kunittest/runnergui.cpp433
-rw-r--r--kunittest/runnergui.h78
-rw-r--r--kunittest/testerwidget.ui197
-rw-r--r--kunittest/testerwidget.ui.h46
-rw-r--r--poxml/GettextLexer.cpp550
-rw-r--r--poxml/GettextLexer.hpp47
-rw-r--r--poxml/GettextParser.cpp414
-rw-r--r--poxml/GettextParser.hpp53
-rw-r--r--poxml/GettextParserTokenTypes.hpp22
-rw-r--r--poxml/GettextParserTokenTypes.txt13
-rw-r--r--poxml/Makefile.am48
-rw-r--r--poxml/antlr/AUTHORS2
-rw-r--r--poxml/antlr/COPYING32
-rw-r--r--poxml/antlr/ChangeLog293
-rw-r--r--poxml/antlr/INSTALL183
-rw-r--r--poxml/antlr/Makefile.am2
-rw-r--r--poxml/antlr/README72
-rw-r--r--poxml/antlr/TODO34
-rw-r--r--poxml/antlr/antlr/ANTLRException.hpp60
-rw-r--r--poxml/antlr/antlr/AST.hpp108
-rw-r--r--poxml/antlr/antlr/ASTArray.hpp63
-rw-r--r--poxml/antlr/antlr/ASTFactory.hpp113
-rw-r--r--poxml/antlr/antlr/ASTNULLType.hpp72
-rw-r--r--poxml/antlr/antlr/ASTPair.hpp77
-rw-r--r--poxml/antlr/antlr/ASTRefCount.hpp104
-rw-r--r--poxml/antlr/antlr/BaseAST.hpp106
-rw-r--r--poxml/antlr/antlr/BitSet.hpp50
-rw-r--r--poxml/antlr/antlr/CharBuffer.hpp75
-rw-r--r--poxml/antlr/antlr/CharScanner.hpp265
-rw-r--r--poxml/antlr/antlr/CharStreamException.hpp18
-rw-r--r--poxml/antlr/antlr/CharStreamIOException.hpp20
-rw-r--r--poxml/antlr/antlr/CircularQueue.hpp88
-rw-r--r--poxml/antlr/antlr/CommonAST.hpp68
-rw-r--r--poxml/antlr/antlr/CommonASTWithHiddenTokens.hpp41
-rw-r--r--poxml/antlr/antlr/CommonHiddenStreamToken.hpp30
-rw-r--r--poxml/antlr/antlr/CommonToken.hpp77
-rw-r--r--poxml/antlr/antlr/InputBuffer.hpp158
-rw-r--r--poxml/antlr/antlr/LLkParser.hpp82
-rw-r--r--poxml/antlr/antlr/LexerSharedInputState.hpp49
-rw-r--r--poxml/antlr/antlr/Makefile.am45
-rw-r--r--poxml/antlr/antlr/MismatchedCharException.hpp127
-rw-r--r--poxml/antlr/antlr/MismatchedTokenException.hpp167
-rw-r--r--poxml/antlr/antlr/NoViableAltException.hpp71
-rw-r--r--poxml/antlr/antlr/NoViableAltForCharException.hpp64
-rw-r--r--poxml/antlr/antlr/Parser.hpp213
-rw-r--r--poxml/antlr/antlr/ParserSharedInputState.hpp42
-rw-r--r--poxml/antlr/antlr/RecognitionException.hpp78
-rw-r--r--poxml/antlr/antlr/RefCount.hpp87
-rw-r--r--poxml/antlr/antlr/SemanticException.hpp52
-rw-r--r--poxml/antlr/antlr/String.hpp47
-rw-r--r--poxml/antlr/antlr/Token.hpp106
-rw-r--r--poxml/antlr/antlr/TokenBuffer.hpp141
-rw-r--r--poxml/antlr/antlr/TokenStream.hpp54
-rw-r--r--poxml/antlr/antlr/TokenStreamBasicFilter.hpp35
-rw-r--r--poxml/antlr/antlr/TokenStreamException.hpp19
-rw-r--r--poxml/antlr/antlr/TokenStreamHiddenTokenFilter.hpp84
-rw-r--r--poxml/antlr/antlr/TokenStreamIOException.hpp22
-rw-r--r--poxml/antlr/antlr/TokenStreamRecognitionException.hpp21
-rw-r--r--poxml/antlr/antlr/TokenStreamRetryException.hpp17
-rw-r--r--poxml/antlr/antlr/TokenStreamSelector.hpp78
-rw-r--r--poxml/antlr/antlr/TreeParser.hpp159
-rw-r--r--poxml/antlr/antlr/TreeParserSharedInputState.hpp34
-rw-r--r--poxml/antlr/antlr/config.hpp168
-rw-r--r--poxml/antlr/configure.in22
-rw-r--r--poxml/antlr/src/ANTLRException.cpp57
-rw-r--r--poxml/antlr/src/ASTFactory.cpp218
-rw-r--r--poxml/antlr/src/ASTRefCount.cpp74
-rw-r--r--poxml/antlr/src/BaseAST.cpp320
-rw-r--r--poxml/antlr/src/BitSet.cpp76
-rw-r--r--poxml/antlr/src/CharBuffer.cpp67
-rw-r--r--poxml/antlr/src/CharScanner.cpp430
-rw-r--r--poxml/antlr/src/CommonAST.cpp100
-rw-r--r--poxml/antlr/src/CommonASTWithHiddenTokens.cpp29
-rw-r--r--poxml/antlr/src/CommonHiddenStreamToken.cpp46
-rw-r--r--poxml/antlr/src/CommonToken.cpp81
-rw-r--r--poxml/antlr/src/InputBuffer.cpp109
-rw-r--r--poxml/antlr/src/LLkParser.cpp105
-rw-r--r--poxml/antlr/src/LexerSharedInputState.cpp55
-rw-r--r--poxml/antlr/src/Makefile.am39
-rw-r--r--poxml/antlr/src/MismatchedCharException.cpp153
-rw-r--r--poxml/antlr/src/MismatchedTokenException.cpp223
-rw-r--r--poxml/antlr/src/NoViableAltException.cpp82
-rw-r--r--poxml/antlr/src/NoViableAltForCharException.cpp71
-rw-r--r--poxml/antlr/src/Parser.cpp304
-rw-r--r--poxml/antlr/src/ParserSharedInputState.cpp37
-rw-r--r--poxml/antlr/src/RecognitionException.cpp87
-rw-r--r--poxml/antlr/src/String.cpp61
-rw-r--r--poxml/antlr/src/Token.cpp108
-rw-r--r--poxml/antlr/src/TokenBuffer.cpp107
-rw-r--r--poxml/antlr/src/TokenStreamBasicFilter.cpp34
-rw-r--r--poxml/antlr/src/TokenStreamHiddenTokenFilter.cpp146
-rw-r--r--poxml/antlr/src/TokenStreamSelector.cpp97
-rw-r--r--poxml/antlr/src/TreeParser.cpp165
-rw-r--r--poxml/antlr/src/TreeParserSharedInputState.cpp22
-rw-r--r--poxml/gettext.g168
-rw-r--r--poxml/lauri.po442
-rw-r--r--poxml/lauri.xml241
-rw-r--r--poxml/parser.cpp1008
-rw-r--r--poxml/parser.h124
-rw-r--r--poxml/po2xml.cpp261
-rw-r--r--poxml/split.cpp162
-rw-r--r--poxml/swappo.cpp38
-rw-r--r--poxml/transxx.cpp130
-rw-r--r--poxml/xml2pot.cpp77
-rw-r--r--scheck/Makefile.am33
-rw-r--r--scheck/README22
-rw-r--r--scheck/bitmaps.h84
-rw-r--r--scheck/scheck.cpp2762
-rw-r--r--scheck/scheck.h173
-rw-r--r--scheck/scheck.themerc55
-rw-r--r--scheck/status.txt41
-rw-r--r--scripts/Makefile.am57
-rw-r--r--scripts/README186
-rw-r--r--scripts/add_trace.pl124
-rwxr-xr-xscripts/adddebug63
-rwxr-xr-xscripts/alldcop.rb91
-rwxr-xr-xscripts/authors2xml.pl27
-rw-r--r--scripts/build-progress.sh22
-rwxr-xr-xscripts/cheatmake80
-rwxr-xr-xscripts/check_licenses88
-rwxr-xr-xscripts/colorcvs175
-rw-r--r--scripts/colorcvsrc-sample36
-rwxr-xr-xscripts/colorsvn201
-rw-r--r--scripts/completions/bash/dcop52
-rw-r--r--scripts/completions/zsh/_dcop11
-rw-r--r--scripts/completions/zsh/_kcmshell16
-rw-r--r--scripts/completions/zsh/_kdeinit_wrapper6
-rw-r--r--scripts/completions/zsh/_kdekillall8
-rw-r--r--scripts/completions/zsh/_makeobj30
-rwxr-xr-xscripts/create_cvsignore55
-rwxr-xr-xscripts/create_makefile110
-rwxr-xr-xscripts/create_makefiles34
-rwxr-xr-xscripts/create_svnignore82
-rwxr-xr-xscripts/cvs-clean90
-rwxr-xr-xscripts/cvs2dist626
-rwxr-xr-xscripts/cvsaddcurrentdir30
-rwxr-xr-xscripts/cvsbackport32
-rwxr-xr-xscripts/cvsblame252
-rwxr-xr-xscripts/cvscheck385
-rwxr-xr-xscripts/cvsforwardport32
-rwxr-xr-xscripts/cvsgettags38
-rwxr-xr-xscripts/cvslastchange55
-rwxr-xr-xscripts/cvslastlog8
-rwxr-xr-xscripts/cvslastreferenced64
-rwxr-xr-xscripts/cvsrevertlast17
-rwxr-xr-xscripts/cvsversion30
-rwxr-xr-xscripts/cxxmetric223
-rwxr-xr-xscripts/extend_dmalloc159
-rwxr-xr-xscripts/extractattr158
-rwxr-xr-xscripts/extractrc174
-rwxr-xr-xscripts/findmissingcrystal32
-rw-r--r--scripts/fixfsfaddr.sed30
-rw-r--r--scripts/fixheaders214
-rw-r--r--scripts/fixkdeincludes756
-rwxr-xr-xscripts/fixuifiles293
-rw-r--r--scripts/gettext.patch194
-rwxr-xr-xscripts/includemocs102
-rwxr-xr-xscripts/kDebug2kdDebug.sh154
-rwxr-xr-xscripts/kde-build898
-rw-r--r--scripts/kde-buildrc205
-rw-r--r--scripts/kde-devel-emacs.el1890
-rw-r--r--scripts/kde-devel-gdb299
-rw-r--r--scripts/kde-devel-vim.vim428
-rw-r--r--scripts/kde-emacs/HACKING7
-rw-r--r--scripts/kde-emacs/dirvars.el200
-rw-r--r--scripts/kde-emacs/kde-emacs-bindings.el185
-rw-r--r--scripts/kde-emacs/kde-emacs-compat.el77
-rw-r--r--scripts/kde-emacs/kde-emacs-core.el3823
-rw-r--r--scripts/kde-emacs/kde-emacs-doc.el322
-rw-r--r--scripts/kde-emacs/kde-emacs-general.el179
-rw-r--r--scripts/kde-emacs/kde-emacs-semantic.el456
-rw-r--r--scripts/kde-emacs/kde-emacs-tips.texi257
-rw-r--r--scripts/kde-emacs/kde-emacs-utils.el894
-rw-r--r--scripts/kde-emacs/kde-emacs-vars.el147
-rw-r--r--scripts/kde-emacs/kde-emacs.el66
-rw-r--r--scripts/kde-emacs/klaralv.el422
-rwxr-xr-xscripts/kde-spellcheck.pl1537
-rw-r--r--scripts/kde.supp155
-rwxr-xr-xscripts/kdedoc48
-rwxr-xr-xscripts/kdekillall28
-rwxr-xr-xscripts/kdelnk2desktop.py21
-rwxr-xr-xscripts/kdemangen.pl250
-rwxr-xr-xscripts/kdesvn-build4286
-rw-r--r--scripts/kdesvn-buildrc-sample246
-rw-r--r--scripts/kdesvn-buildrc.xml152
-rwxr-xr-xscripts/licensecheck63
-rwxr-xr-xscripts/makeobj96
-rwxr-xr-xscripts/noncvslist127
-rwxr-xr-xscripts/nonsvnlist4
-rwxr-xr-xscripts/package_crystalsvg185
-rw-r--r--scripts/png2mng.pl193
-rwxr-xr-xscripts/pruneemptydirs46
-rwxr-xr-xscripts/qtdoc19
-rw-r--r--scripts/rc2kcfgxt.pl95
-rwxr-xr-xscripts/svn-clean113
-rwxr-xr-xscripts/svn2dist638
-rwxr-xr-xscripts/svnaddcurrentdir30
-rwxr-xr-xscripts/svnbackport64
-rwxr-xr-xscripts/svnchangesince63
-rwxr-xr-xscripts/svnforwardport64
-rwxr-xr-xscripts/svngettags3
-rwxr-xr-xscripts/svnlastchange172
-rwxr-xr-xscripts/svnlastlog4
-rwxr-xr-xscripts/svnrevertlast9
-rwxr-xr-xscripts/svnversions51
-rwxr-xr-xscripts/zonetab2pot.py24
-rw-r--r--umbrello/AUTHORS14
-rw-r--r--umbrello/COPYING340
-rw-r--r--umbrello/ChangeLog644
-rw-r--r--umbrello/INSTALL179
-rw-r--r--umbrello/Makefile.am12
-rw-r--r--umbrello/README10
-rw-r--r--umbrello/THANKS93
-rw-r--r--umbrello/TODO22
-rw-r--r--umbrello/VERSION1
-rw-r--r--umbrello/configure.in.in112
-rwxr-xr-xumbrello/make-umbrello-release.sh60
-rw-r--r--umbrello/umbrello/Makefile.am155
-rw-r--r--umbrello/umbrello/activitywidget.cpp235
-rw-r--r--umbrello/umbrello/activitywidget.h127
-rw-r--r--umbrello/umbrello/actor.cpp40
-rw-r--r--umbrello/umbrello/actor.h66
-rw-r--r--umbrello/umbrello/actorwidget.cpp79
-rw-r--r--umbrello/umbrello/actorwidget.h78
-rw-r--r--umbrello/umbrello/aligntoolbar.cpp391
-rw-r--r--umbrello/umbrello/aligntoolbar.h224
-rw-r--r--umbrello/umbrello/artifact.cpp57
-rw-r--r--umbrello/umbrello/artifact.h97
-rw-r--r--umbrello/umbrello/artifactwidget.cpp259
-rw-r--r--umbrello/umbrello/artifactwidget.h107
-rw-r--r--umbrello/umbrello/association.cpp574
-rw-r--r--umbrello/umbrello/association.h290
-rw-r--r--umbrello/umbrello/associationwidget.cpp3614
-rw-r--r--umbrello/umbrello/associationwidget.h1045
-rw-r--r--umbrello/umbrello/associationwidgetlist.h29
-rw-r--r--umbrello/umbrello/assocrules.cpp386
-rw-r--r--umbrello/umbrello/assocrules.h106
-rw-r--r--umbrello/umbrello/attribute.cpp327
-rw-r--r--umbrello/umbrello/attribute.h157
-rw-r--r--umbrello/umbrello/autolayout/Makefile.am20
-rw-r--r--umbrello/umbrello/autolayout/_graph.h34
-rw-r--r--umbrello/umbrello/autolayout/autolayout.h45
-rw-r--r--umbrello/umbrello/autolayout/autolayoutdlg.cpp184
-rw-r--r--umbrello/umbrello/autolayout/autolayoutdlg.h63
-rw-r--r--umbrello/umbrello/autolayout/autolayouter.cpp29
-rw-r--r--umbrello/umbrello/autolayout/autolayouter.h64
-rw-r--r--umbrello/umbrello/autolayout/autolayouteradapter.cpp191
-rw-r--r--umbrello/umbrello/autolayout/autolayouteradapter.h87
-rw-r--r--umbrello/umbrello/autolayout/baseinclude.h29
-rw-r--r--umbrello/umbrello/autolayout/canvas.h34
-rw-r--r--umbrello/umbrello/autolayout/diagram.h50
-rw-r--r--umbrello/umbrello/autolayout/diagram_interface.h31
-rw-r--r--umbrello/umbrello/autolayout/dotautolayouter.cpp43
-rw-r--r--umbrello/umbrello/autolayout/dotautolayouter.h38
-rw-r--r--umbrello/umbrello/autolayout/graphvizautolayouter.cpp54
-rw-r--r--umbrello/umbrello/autolayout/graphvizautolayouter.h50
-rw-r--r--umbrello/umbrello/autolayout/graphvizgraph.cpp150
-rw-r--r--umbrello/umbrello/autolayout/graphvizgraph.h58
-rw-r--r--umbrello/umbrello/autolayout/graphviznode.cpp46
-rw-r--r--umbrello/umbrello/autolayout/graphviznode.h42
-rw-r--r--umbrello/umbrello/autolayout/newautolayoutdialog.ui554
-rw-r--r--umbrello/umbrello/autolayout/node.h37
-rw-r--r--umbrello/umbrello/autolayout/simplecanvas.cpp20
-rw-r--r--umbrello/umbrello/autolayout/simplecanvas.h39
-rw-r--r--umbrello/umbrello/boxwidget.cpp44
-rw-r--r--umbrello/umbrello/boxwidget.h60
-rw-r--r--umbrello/umbrello/classifier.cpp1023
-rw-r--r--umbrello/umbrello/classifier.h496
-rw-r--r--umbrello/umbrello/classifiercodedocument.cpp742
-rw-r--r--umbrello/umbrello/classifiercodedocument.h251
-rw-r--r--umbrello/umbrello/classifierlistitem.cpp98
-rw-r--r--umbrello/umbrello/classifierlistitem.h126
-rw-r--r--umbrello/umbrello/classifierwidget.cpp803
-rw-r--r--umbrello/umbrello/classifierwidget.h390
-rw-r--r--umbrello/umbrello/clipboard/Makefile.am6
-rw-r--r--umbrello/umbrello/clipboard/idchangelog.cpp97
-rw-r--r--umbrello/umbrello/clipboard/idchangelog.h126
-rw-r--r--umbrello/umbrello/clipboard/umlclipboard.cpp694
-rw-r--r--umbrello/umbrello/clipboard/umlclipboard.h194
-rw-r--r--umbrello/umbrello/clipboard/umldrag.cpp773
-rw-r--r--umbrello/umbrello/clipboard/umldrag.h223
-rw-r--r--umbrello/umbrello/cmdlineexportallviewsevent.cpp48
-rw-r--r--umbrello/umbrello/cmdlineexportallviewsevent.h78
-rw-r--r--umbrello/umbrello/codeaccessormethod.cpp195
-rw-r--r--umbrello/umbrello/codeaccessormethod.h118
-rw-r--r--umbrello/umbrello/codeaccessormethodlist.h23
-rw-r--r--umbrello/umbrello/codeblock.cpp143
-rw-r--r--umbrello/umbrello/codeblock.h121
-rw-r--r--umbrello/umbrello/codeblockwithcomments.cpp181
-rw-r--r--umbrello/umbrello/codeblockwithcomments.h107
-rw-r--r--umbrello/umbrello/codeclassfield.cpp617
-rw-r--r--umbrello/umbrello/codeclassfield.h237
-rw-r--r--umbrello/umbrello/codeclassfielddeclarationblock.cpp174
-rw-r--r--umbrello/umbrello/codeclassfielddeclarationblock.h112
-rw-r--r--umbrello/umbrello/codeclassfieldlist.h23
-rw-r--r--umbrello/umbrello/codecomment.cpp62
-rw-r--r--umbrello/umbrello/codecomment.h68
-rw-r--r--umbrello/umbrello/codedocument.cpp502
-rw-r--r--umbrello/umbrello/codedocument.h273
-rw-r--r--umbrello/umbrello/codedocumentlist.h23
-rw-r--r--umbrello/umbrello/codegenerationpolicy.cpp587
-rw-r--r--umbrello/umbrello/codegenerationpolicy.h384
-rw-r--r--umbrello/umbrello/codegenerator.cpp723
-rw-r--r--umbrello/umbrello/codegenerator.h416
-rw-r--r--umbrello/umbrello/codegenerators/Makefile.am38
-rw-r--r--umbrello/umbrello/codegenerators/adawriter.cpp686
-rw-r--r--umbrello/umbrello/codegenerators/adawriter.h105
-rw-r--r--umbrello/umbrello/codegenerators/aswriter.cpp775
-rw-r--r--umbrello/umbrello/codegenerators/aswriter.h80
-rw-r--r--umbrello/umbrello/codegenerators/classifierinfo.cpp140
-rw-r--r--umbrello/umbrello/codegenerators/classifierinfo.h126
-rw-r--r--umbrello/umbrello/codegenerators/codegen_utils.cpp413
-rw-r--r--umbrello/umbrello/codegenerators/codegen_utils.h42
-rw-r--r--umbrello/umbrello/codegenerators/codegenfactory.cpp360
-rw-r--r--umbrello/umbrello/codegenerators/codegenfactory.h119
-rw-r--r--umbrello/umbrello/codegenerators/codegenpolicyext.h52
-rw-r--r--umbrello/umbrello/codegenerators/cppcodeclassfield.cpp108
-rw-r--r--umbrello/umbrello/codegenerators/cppcodeclassfield.h62
-rw-r--r--umbrello/umbrello/codegenerators/cppcodecomment.cpp98
-rw-r--r--umbrello/umbrello/codegenerators/cppcodecomment.h83
-rw-r--r--umbrello/umbrello/codegenerators/cppcodedocumentation.cpp141
-rw-r--r--umbrello/umbrello/codegenerators/cppcodedocumentation.h95
-rw-r--r--umbrello/umbrello/codegenerators/cppcodegenerationform.cpp305
-rw-r--r--umbrello/umbrello/codegenerators/cppcodegenerationform.h150
-rw-r--r--umbrello/umbrello/codegenerators/cppcodegenerationformbase.ui481
-rw-r--r--umbrello/umbrello/codegenerators/cppcodegenerationpolicy.cpp390
-rw-r--r--umbrello/umbrello/codegenerators/cppcodegenerationpolicy.h227
-rw-r--r--umbrello/umbrello/codegenerators/cppcodegenerationpolicypage.cpp94
-rw-r--r--umbrello/umbrello/codegenerators/cppcodegenerationpolicypage.h48
-rw-r--r--umbrello/umbrello/codegenerators/cppcodegenerator.cpp366
-rw-r--r--umbrello/umbrello/codegenerators/cppcodegenerator.h167
-rw-r--r--umbrello/umbrello/codegenerators/cppheaderclassdeclarationblock.cpp160
-rw-r--r--umbrello/umbrello/codegenerators/cppheaderclassdeclarationblock.h67
-rw-r--r--umbrello/umbrello/codegenerators/cppheadercodeaccessormethod.cpp170
-rw-r--r--umbrello/umbrello/codegenerators/cppheadercodeaccessormethod.h57
-rw-r--r--umbrello/umbrello/codegenerators/cppheadercodeclassfielddeclarationblock.cpp78
-rw-r--r--umbrello/umbrello/codegenerators/cppheadercodeclassfielddeclarationblock.h51
-rw-r--r--umbrello/umbrello/codegenerators/cppheadercodedocument.cpp813
-rw-r--r--umbrello/umbrello/codegenerators/cppheadercodedocument.h107
-rw-r--r--umbrello/umbrello/codegenerators/cppheadercodeoperation.cpp175
-rw-r--r--umbrello/umbrello/codegenerators/cppheadercodeoperation.h59
-rw-r--r--umbrello/umbrello/codegenerators/cppmakecodedocument.cpp78
-rw-r--r--umbrello/umbrello/codegenerators/cppmakecodedocument.h67
-rw-r--r--umbrello/umbrello/codegenerators/cppsourcecodeaccessormethod.cpp169
-rw-r--r--umbrello/umbrello/codegenerators/cppsourcecodeaccessormethod.h57
-rw-r--r--umbrello/umbrello/codegenerators/cppsourcecodeclassfielddeclarationblock.cpp74
-rw-r--r--umbrello/umbrello/codegenerators/cppsourcecodeclassfielddeclarationblock.h51
-rw-r--r--umbrello/umbrello/codegenerators/cppsourcecodedocument.cpp168
-rw-r--r--umbrello/umbrello/codegenerators/cppsourcecodedocument.h73
-rw-r--r--umbrello/umbrello/codegenerators/cppsourcecodeoperation.cpp193
-rw-r--r--umbrello/umbrello/codegenerators/cppsourcecodeoperation.h51
-rw-r--r--umbrello/umbrello/codegenerators/cppwriter.cpp1283
-rw-r--r--umbrello/umbrello/codegenerators/cppwriter.h293
-rw-r--r--umbrello/umbrello/codegenerators/csharpwriter.cpp725
-rw-r--r--umbrello/umbrello/codegenerators/csharpwriter.h163
-rw-r--r--umbrello/umbrello/codegenerators/dwriter.cpp970
-rw-r--r--umbrello/umbrello/codegenerators/dwriter.h276
-rw-r--r--umbrello/umbrello/codegenerators/idlwriter.cpp482
-rw-r--r--umbrello/umbrello/codegenerators/idlwriter.h74
-rw-r--r--umbrello/umbrello/codegenerators/javaantcodedocument.cpp312
-rw-r--r--umbrello/umbrello/codegenerators/javaantcodedocument.h100
-rw-r--r--umbrello/umbrello/codegenerators/javaclassdeclarationblock.cpp169
-rw-r--r--umbrello/umbrello/codegenerators/javaclassdeclarationblock.h66
-rw-r--r--umbrello/umbrello/codegenerators/javaclassifiercodedocument.cpp583
-rw-r--r--umbrello/umbrello/codegenerators/javaclassifiercodedocument.h110
-rw-r--r--umbrello/umbrello/codegenerators/javacodeaccessormethod.cpp223
-rw-r--r--umbrello/umbrello/codegenerators/javacodeaccessormethod.h65
-rw-r--r--umbrello/umbrello/codegenerators/javacodeclassfield.cpp111
-rw-r--r--umbrello/umbrello/codegenerators/javacodeclassfield.h59
-rw-r--r--umbrello/umbrello/codegenerators/javacodeclassfielddeclarationblock.cpp118
-rw-r--r--umbrello/umbrello/codegenerators/javacodeclassfielddeclarationblock.h51
-rw-r--r--umbrello/umbrello/codegenerators/javacodecomment.cpp84
-rw-r--r--umbrello/umbrello/codegenerators/javacodecomment.h77
-rw-r--r--umbrello/umbrello/codegenerators/javacodedocumentation.cpp143
-rw-r--r--umbrello/umbrello/codegenerators/javacodedocumentation.h95
-rw-r--r--umbrello/umbrello/codegenerators/javacodegenerationformbase.ui277
-rw-r--r--umbrello/umbrello/codegenerators/javacodegenerationpolicy.cpp188
-rw-r--r--umbrello/umbrello/codegenerators/javacodegenerationpolicy.h116
-rw-r--r--umbrello/umbrello/codegenerators/javacodegenerationpolicypage.cpp84
-rw-r--r--umbrello/umbrello/codegenerators/javacodegenerationpolicypage.h48
-rw-r--r--umbrello/umbrello/codegenerators/javacodegenerator.cpp339
-rw-r--r--umbrello/umbrello/codegenerators/javacodegenerator.h150
-rw-r--r--umbrello/umbrello/codegenerators/javacodeoperation.cpp132
-rw-r--r--umbrello/umbrello/codegenerators/javacodeoperation.h52
-rw-r--r--umbrello/umbrello/codegenerators/javawriter.cpp936
-rw-r--r--umbrello/umbrello/codegenerators/javawriter.h236
-rw-r--r--umbrello/umbrello/codegenerators/jswriter.cpp308
-rw-r--r--umbrello/umbrello/codegenerators/jswriter.h78
-rw-r--r--umbrello/umbrello/codegenerators/pascalwriter.cpp542
-rw-r--r--umbrello/umbrello/codegenerators/pascalwriter.h86
-rw-r--r--umbrello/umbrello/codegenerators/perlwriter.cpp716
-rw-r--r--umbrello/umbrello/codegenerators/perlwriter.h101
-rw-r--r--umbrello/umbrello/codegenerators/php5writer.cpp3418
-rw-r--r--umbrello/umbrello/codegenerators/php5writer.h95
-rw-r--r--umbrello/umbrello/codegenerators/phpwriter.cpp3339
-rw-r--r--umbrello/umbrello/codegenerators/phpwriter.h90
-rw-r--r--umbrello/umbrello/codegenerators/pythonwriter.cpp438
-rw-r--r--umbrello/umbrello/codegenerators/pythonwriter.h86
-rw-r--r--umbrello/umbrello/codegenerators/rubyclassdeclarationblock.cpp147
-rw-r--r--umbrello/umbrello/codegenerators/rubyclassdeclarationblock.h74
-rw-r--r--umbrello/umbrello/codegenerators/rubyclassifiercodedocument.cpp646
-rw-r--r--umbrello/umbrello/codegenerators/rubyclassifiercodedocument.h126
-rw-r--r--umbrello/umbrello/codegenerators/rubycodeaccessormethod.cpp233
-rw-r--r--umbrello/umbrello/codegenerators/rubycodeaccessormethod.h73
-rw-r--r--umbrello/umbrello/codegenerators/rubycodeclassfield.cpp113
-rw-r--r--umbrello/umbrello/codegenerators/rubycodeclassfield.h61
-rw-r--r--umbrello/umbrello/codegenerators/rubycodeclassfielddeclarationblock.cpp112
-rw-r--r--umbrello/umbrello/codegenerators/rubycodeclassfielddeclarationblock.h55
-rw-r--r--umbrello/umbrello/codegenerators/rubycodecomment.cpp85
-rw-r--r--umbrello/umbrello/codegenerators/rubycodecomment.h69
-rw-r--r--umbrello/umbrello/codegenerators/rubycodedocumentation.cpp145
-rw-r--r--umbrello/umbrello/codegenerators/rubycodedocumentation.h97
-rw-r--r--umbrello/umbrello/codegenerators/rubycodegenerationformbase.ui248
-rw-r--r--umbrello/umbrello/codegenerators/rubycodegenerationpolicy.cpp170
-rw-r--r--umbrello/umbrello/codegenerators/rubycodegenerationpolicy.h117
-rw-r--r--umbrello/umbrello/codegenerators/rubycodegenerationpolicypage.cpp75
-rw-r--r--umbrello/umbrello/codegenerators/rubycodegenerationpolicypage.h51
-rw-r--r--umbrello/umbrello/codegenerators/rubycodegenerator.cpp186
-rw-r--r--umbrello/umbrello/codegenerators/rubycodegenerator.h129
-rw-r--r--umbrello/umbrello/codegenerators/rubycodeoperation.cpp226
-rw-r--r--umbrello/umbrello/codegenerators/rubycodeoperation.h54
-rw-r--r--umbrello/umbrello/codegenerators/rubywriter.cpp448
-rw-r--r--umbrello/umbrello/codegenerators/rubywriter.h113
-rw-r--r--umbrello/umbrello/codegenerators/simplecodegenerator.cpp292
-rw-r--r--umbrello/umbrello/codegenerators/simplecodegenerator.h120
-rw-r--r--umbrello/umbrello/codegenerators/sqlwriter.cpp394
-rw-r--r--umbrello/umbrello/codegenerators/sqlwriter.h77
-rw-r--r--umbrello/umbrello/codegenerators/tclwriter.cpp951
-rw-r--r--umbrello/umbrello/codegenerators/tclwriter.h174
-rw-r--r--umbrello/umbrello/codegenerators/xmlcodecomment.cpp67
-rw-r--r--umbrello/umbrello/codegenerators/xmlcodecomment.h68
-rw-r--r--umbrello/umbrello/codegenerators/xmlelementcodeblock.cpp166
-rw-r--r--umbrello/umbrello/codegenerators/xmlelementcodeblock.h88
-rw-r--r--umbrello/umbrello/codegenerators/xmlschemawriter.cpp809
-rw-r--r--umbrello/umbrello/codegenerators/xmlschemawriter.h249
-rw-r--r--umbrello/umbrello/codegenobjectwithtextblocks.cpp517
-rw-r--r--umbrello/umbrello/codegenobjectwithtextblocks.h192
-rw-r--r--umbrello/umbrello/codeimport/Makefile.am6
-rw-r--r--umbrello/umbrello/codeimport/adaimport.cpp588
-rw-r--r--umbrello/umbrello/codeimport/adaimport.h88
-rw-r--r--umbrello/umbrello/codeimport/classimport.cpp58
-rw-r--r--umbrello/umbrello/codeimport/classimport.h61
-rw-r--r--umbrello/umbrello/codeimport/cppimport.cpp109
-rw-r--r--umbrello/umbrello/codeimport/cppimport.h59
-rw-r--r--umbrello/umbrello/codeimport/idlimport.cpp356
-rw-r--r--umbrello/umbrello/codeimport/idlimport.h54
-rw-r--r--umbrello/umbrello/codeimport/import_utils.cpp464
-rw-r--r--umbrello/umbrello/codeimport/import_utils.h175
-rw-r--r--umbrello/umbrello/codeimport/javaimport.cpp549
-rw-r--r--umbrello/umbrello/codeimport/javaimport.h106
-rw-r--r--umbrello/umbrello/codeimport/kdevcppparser/Makefile.am5
-rw-r--r--umbrello/umbrello/codeimport/kdevcppparser/README56
-rw-r--r--umbrello/umbrello/codeimport/kdevcppparser/ast.cpp1183
-rw-r--r--umbrello/umbrello/codeimport/kdevcppparser/ast.h1449
-rw-r--r--umbrello/umbrello/codeimport/kdevcppparser/ast_utils.cpp176
-rw-r--r--umbrello/umbrello/codeimport/kdevcppparser/ast_utils.h29
-rw-r--r--umbrello/umbrello/codeimport/kdevcppparser/cpptree2uml.cpp640
-rw-r--r--umbrello/umbrello/codeimport/kdevcppparser/cpptree2uml.h98
-rw-r--r--umbrello/umbrello/codeimport/kdevcppparser/driver.cpp435
-rw-r--r--umbrello/umbrello/codeimport/kdevcppparser/driver.h230
-rw-r--r--umbrello/umbrello/codeimport/kdevcppparser/errors.cpp25
-rw-r--r--umbrello/umbrello/codeimport/kdevcppparser/errors.h45
-rw-r--r--umbrello/umbrello/codeimport/kdevcppparser/keywords.lut.h123
-rw-r--r--umbrello/umbrello/codeimport/kdevcppparser/lexer.cpp1002
-rw-r--r--umbrello/umbrello/codeimport/kdevcppparser/lexer.h791
-rw-r--r--umbrello/umbrello/codeimport/kdevcppparser/lookup.cpp113
-rw-r--r--umbrello/umbrello/codeimport/kdevcppparser/lookup.h119
-rw-r--r--umbrello/umbrello/codeimport/kdevcppparser/parser.cpp4238
-rw-r--r--umbrello/umbrello/codeimport/kdevcppparser/parser.h221
-rw-r--r--umbrello/umbrello/codeimport/kdevcppparser/tree_parser.cpp207
-rw-r--r--umbrello/umbrello/codeimport/kdevcppparser/tree_parser.h59
-rw-r--r--umbrello/umbrello/codeimport/kdevcppparser/urlutil.cpp310
-rw-r--r--umbrello/umbrello/codeimport/kdevcppparser/urlutil.h132
-rw-r--r--umbrello/umbrello/codeimport/nativeimportbase.cpp340
-rw-r--r--umbrello/umbrello/codeimport/nativeimportbase.h227
-rw-r--r--umbrello/umbrello/codeimport/pascalimport.cpp413
-rw-r--r--umbrello/umbrello/codeimport/pascalimport.h66
-rw-r--r--umbrello/umbrello/codeimport/pythonimport.cpp190
-rw-r--r--umbrello/umbrello/codeimport/pythonimport.h76
-rw-r--r--umbrello/umbrello/codemethodblock.cpp191
-rw-r--r--umbrello/umbrello/codemethodblock.h133
-rw-r--r--umbrello/umbrello/codeoperation.cpp177
-rw-r--r--umbrello/umbrello/codeoperation.h94
-rw-r--r--umbrello/umbrello/codeparameter.cpp287
-rw-r--r--umbrello/umbrello/codeparameter.h160
-rw-r--r--umbrello/umbrello/codeviewerstate.h38
-rw-r--r--umbrello/umbrello/component.cpp100
-rw-r--r--umbrello/umbrello/component.h86
-rw-r--r--umbrello/umbrello/componentwidget.cpp141
-rw-r--r--umbrello/umbrello/componentwidget.h74
-rw-r--r--umbrello/umbrello/configurable.cpp81
-rw-r--r--umbrello/umbrello/configurable.h118
-rw-r--r--umbrello/umbrello/cr128-mime-umbrellofile.pngbin0 -> 6767 bytes
-rw-r--r--umbrello/umbrello/cr16-mime-umbrellofile.pngbin0 -> 835 bytes
-rw-r--r--umbrello/umbrello/cr22-mime-umbrellofile.pngbin0 -> 1134 bytes
-rw-r--r--umbrello/umbrello/cr32-mime-umbrellofile.pngbin0 -> 1717 bytes
-rw-r--r--umbrello/umbrello/cr48-mime-umbrellofile.pngbin0 -> 2665 bytes
-rw-r--r--umbrello/umbrello/cr64-mime-umbrellofile.pngbin0 -> 3515 bytes
-rw-r--r--umbrello/umbrello/crsc-mime-umbrellofile.svgzbin0 -> 2860 bytes
-rw-r--r--umbrello/umbrello/datatypewidget.cpp114
-rw-r--r--umbrello/umbrello/datatypewidget.h81
-rw-r--r--umbrello/umbrello/dialog_utils.cpp60
-rw-r--r--umbrello/umbrello/dialog_utils.h63
-rw-r--r--umbrello/umbrello/dialogs/Makefile.am54
-rw-r--r--umbrello/umbrello/dialogs/activitydialog.cpp125
-rw-r--r--umbrello/umbrello/dialogs/activitydialog.h136
-rw-r--r--umbrello/umbrello/dialogs/activitypage.cpp325
-rw-r--r--umbrello/umbrello/dialogs/activitypage.h94
-rw-r--r--umbrello/umbrello/dialogs/assocgenpage.cpp131
-rw-r--r--umbrello/umbrello/dialogs/assocgenpage.h93
-rw-r--r--umbrello/umbrello/dialogs/assocpage.cpp127
-rw-r--r--umbrello/umbrello/dialogs/assocpage.h76
-rw-r--r--umbrello/umbrello/dialogs/assocpropdlg.cpp115
-rw-r--r--umbrello/umbrello/dialogs/assocpropdlg.h72
-rw-r--r--umbrello/umbrello/dialogs/assocrolepage.cpp293
-rw-r--r--umbrello/umbrello/dialogs/assocrolepage.h85
-rw-r--r--umbrello/umbrello/dialogs/classgenpage.cpp472
-rw-r--r--umbrello/umbrello/dialogs/classgenpage.h109
-rw-r--r--umbrello/umbrello/dialogs/classifierlistpage.cpp607
-rw-r--r--umbrello/umbrello/dialogs/classifierlistpage.h191
-rw-r--r--umbrello/umbrello/dialogs/classoptionspage.cpp195
-rw-r--r--umbrello/umbrello/dialogs/classoptionspage.h106
-rw-r--r--umbrello/umbrello/dialogs/classpropdlg.cpp250
-rw-r--r--umbrello/umbrello/dialogs/classpropdlg.h129
-rw-r--r--umbrello/umbrello/dialogs/classwizard.cpp107
-rw-r--r--umbrello/umbrello/dialogs/classwizard.h104
-rw-r--r--umbrello/umbrello/dialogs/codeeditor.cpp1231
-rw-r--r--umbrello/umbrello/dialogs/codeeditor.h191
-rw-r--r--umbrello/umbrello/dialogs/codegenerationoptionsbase.ui533
-rw-r--r--umbrello/umbrello/dialogs/codegenerationoptionspage.cpp188
-rw-r--r--umbrello/umbrello/dialogs/codegenerationoptionspage.h74
-rw-r--r--umbrello/umbrello/dialogs/codegenerationpolicybase.ui39
-rw-r--r--umbrello/umbrello/dialogs/codegenerationpolicypage.cpp50
-rw-r--r--umbrello/umbrello/dialogs/codegenerationpolicypage.h55
-rw-r--r--umbrello/umbrello/dialogs/codegenerationwizard.cpp258
-rw-r--r--umbrello/umbrello/dialogs/codegenerationwizard.h88
-rw-r--r--umbrello/umbrello/dialogs/codegenerationwizardbase.ui309
-rw-r--r--umbrello/umbrello/dialogs/codeviewerdialog.cpp122
-rw-r--r--umbrello/umbrello/dialogs/codeviewerdialog.h80
-rw-r--r--umbrello/umbrello/dialogs/codeviewerdialogbase.ui113
-rw-r--r--umbrello/umbrello/dialogs/codevieweroptionsbase.ui369
-rw-r--r--umbrello/umbrello/dialogs/codevieweroptionspage.cpp70
-rw-r--r--umbrello/umbrello/dialogs/codevieweroptionspage.h52
-rw-r--r--umbrello/umbrello/dialogs/defaultcodegenpolicypage.cpp41
-rw-r--r--umbrello/umbrello/dialogs/defaultcodegenpolicypage.h42
-rw-r--r--umbrello/umbrello/dialogs/diagramprintpage.cpp225
-rw-r--r--umbrello/umbrello/dialogs/diagramprintpage.h101
-rw-r--r--umbrello/umbrello/dialogs/diagrampropertiespage.ui410
-rw-r--r--umbrello/umbrello/dialogs/exportallviewsdialog.cpp55
-rw-r--r--umbrello/umbrello/dialogs/exportallviewsdialog.h72
-rw-r--r--umbrello/umbrello/dialogs/exportallviewsdialogbase.ui216
-rw-r--r--umbrello/umbrello/dialogs/notedialog.cpp53
-rw-r--r--umbrello/umbrello/dialogs/notedialog.h55
-rw-r--r--umbrello/umbrello/dialogs/overwritedialogue.cpp62
-rw-r--r--umbrello/umbrello/dialogs/overwritedialogue.h72
-rw-r--r--umbrello/umbrello/dialogs/parmpropdlg.cpp257
-rw-r--r--umbrello/umbrello/dialogs/parmpropdlg.h125
-rw-r--r--umbrello/umbrello/dialogs/pkgcontentspage.cpp127
-rw-r--r--umbrello/umbrello/dialogs/pkgcontentspage.h62
-rw-r--r--umbrello/umbrello/dialogs/selectopdlg.cpp141
-rw-r--r--umbrello/umbrello/dialogs/selectopdlg.h120
-rw-r--r--umbrello/umbrello/dialogs/settingsdlg.cpp443
-rw-r--r--umbrello/umbrello/dialogs/settingsdlg.h177
-rw-r--r--umbrello/umbrello/dialogs/statedialog.cpp147
-rw-r--r--umbrello/umbrello/dialogs/statedialog.h144
-rw-r--r--umbrello/umbrello/dialogs/umlattributedialog.cpp235
-rw-r--r--umbrello/umbrello/dialogs/umlattributedialog.h81
-rw-r--r--umbrello/umbrello/dialogs/umlentityattributedialog.cpp262
-rw-r--r--umbrello/umbrello/dialogs/umlentityattributedialog.h87
-rw-r--r--umbrello/umbrello/dialogs/umloperationdialog.cpp530
-rw-r--r--umbrello/umbrello/dialogs/umloperationdialog.h135
-rw-r--r--umbrello/umbrello/dialogs/umlroledialog.cpp63
-rw-r--r--umbrello/umbrello/dialogs/umlroledialog.h75
-rw-r--r--umbrello/umbrello/dialogs/umlroleproperties.cpp114
-rw-r--r--umbrello/umbrello/dialogs/umlroleproperties.h59
-rw-r--r--umbrello/umbrello/dialogs/umlrolepropertiesbase.ui203
-rw-r--r--umbrello/umbrello/dialogs/umltemplatedialog.cpp161
-rw-r--r--umbrello/umbrello/dialogs/umltemplatedialog.h81
-rw-r--r--umbrello/umbrello/dialogs/umlviewdialog.cpp184
-rw-r--r--umbrello/umbrello/dialogs/umlviewdialog.h119
-rw-r--r--umbrello/umbrello/dialogs/umlwidgetcolorpage.cpp114
-rw-r--r--umbrello/umbrello/dialogs/umlwidgetcolorpage.h86
-rw-r--r--umbrello/umbrello/docgenerators/Makefile.am21
-rw-r--r--umbrello/umbrello/docgenerators/common.ent19
-rw-r--r--umbrello/umbrello/docgenerators/docbook2xhtml.xsl7
-rw-r--r--umbrello/umbrello/docgenerators/docbookgenerator.cpp145
-rw-r--r--umbrello/umbrello/docgenerators/docbookgenerator.h78
-rw-r--r--umbrello/umbrello/docgenerators/main.cpp94
-rw-r--r--umbrello/umbrello/docgenerators/xhtmlgenerator.cpp171
-rw-r--r--umbrello/umbrello/docgenerators/xhtmlgenerator.h104
-rw-r--r--umbrello/umbrello/docgenerators/xmi.css170
-rw-r--r--umbrello/umbrello/docgenerators/xmi2docbook.sh9
-rw-r--r--umbrello/umbrello/docgenerators/xmi2docbook.xsl998
-rw-r--r--umbrello/umbrello/docwindow.cpp223
-rw-r--r--umbrello/umbrello/docwindow.h168
-rw-r--r--umbrello/umbrello/entity.cpp217
-rw-r--r--umbrello/umbrello/entity.h155
-rw-r--r--umbrello/umbrello/entityattribute.cpp178
-rw-r--r--umbrello/umbrello/entityattribute.h183
-rw-r--r--umbrello/umbrello/entitywidget.cpp203
-rw-r--r--umbrello/umbrello/entitywidget.h82
-rw-r--r--umbrello/umbrello/enum.cpp206
-rw-r--r--umbrello/umbrello/enum.h145
-rw-r--r--umbrello/umbrello/enumliteral.cpp74
-rw-r--r--umbrello/umbrello/enumliteral.h85
-rw-r--r--umbrello/umbrello/enumwidget.cpp218
-rw-r--r--umbrello/umbrello/enumwidget.h109
-rw-r--r--umbrello/umbrello/floatingtextwidget.cpp453
-rw-r--r--umbrello/umbrello/floatingtextwidget.h303
-rw-r--r--umbrello/umbrello/floatingtextwidgetcontroller.cpp119
-rw-r--r--umbrello/umbrello/floatingtextwidgetcontroller.h152
-rw-r--r--umbrello/umbrello/folder.cpp412
-rw-r--r--umbrello/umbrello/folder.h199
-rw-r--r--umbrello/umbrello/forkjoinwidget.cpp112
-rw-r--r--umbrello/umbrello/forkjoinwidget.h103
-rw-r--r--umbrello/umbrello/headings/Makefile.am17
-rw-r--r--umbrello/umbrello/headings/heading.adb29
-rw-r--r--umbrello/umbrello/headings/heading.ads30
-rw-r--r--umbrello/umbrello/headings/heading.as29
-rw-r--r--umbrello/umbrello/headings/heading.cpp29
-rw-r--r--umbrello/umbrello/headings/heading.cs29
-rw-r--r--umbrello/umbrello/headings/heading.d29
-rw-r--r--umbrello/umbrello/headings/heading.h29
-rw-r--r--umbrello/umbrello/headings/heading.idl29
-rw-r--r--umbrello/umbrello/headings/heading.java29
-rw-r--r--umbrello/umbrello/headings/heading.js29
-rw-r--r--umbrello/umbrello/headings/heading.php30
-rw-r--r--umbrello/umbrello/headings/heading.pm29
-rw-r--r--umbrello/umbrello/headings/heading.py29
-rw-r--r--umbrello/umbrello/headings/heading.rb29
-rw-r--r--umbrello/umbrello/headings/heading.sql28
-rw-r--r--umbrello/umbrello/headings/heading.xsd4
-rw-r--r--umbrello/umbrello/hi128-app-umbrello.pngbin0 -> 4254 bytes
-rw-r--r--umbrello/umbrello/hi16-app-umbrello.pngbin0 -> 618 bytes
-rw-r--r--umbrello/umbrello/hi16-mime-umbrellofile.pngbin0 -> 554 bytes
-rw-r--r--umbrello/umbrello/hi22-app-umbrello.pngbin0 -> 794 bytes
-rw-r--r--umbrello/umbrello/hi32-app-umbrello.pngbin0 -> 1071 bytes
-rw-r--r--umbrello/umbrello/hi32-mime-umbrellofile.pngbin0 -> 1720 bytes
-rw-r--r--umbrello/umbrello/hi48-app-umbrello.pngbin0 -> 1625 bytes
-rw-r--r--umbrello/umbrello/hi64-app-umbrello.pngbin0 -> 2132 bytes
-rw-r--r--umbrello/umbrello/hierarchicalcodeblock.cpp386
-rw-r--r--umbrello/umbrello/hierarchicalcodeblock.h155
-rw-r--r--umbrello/umbrello/hisc-app-umbrello.svgzbin0 -> 1392 bytes
-rw-r--r--umbrello/umbrello/import_rose.cpp391
-rw-r--r--umbrello/umbrello/import_rose.h35
-rw-r--r--umbrello/umbrello/kplayerslideraction.cpp412
-rw-r--r--umbrello/umbrello/kplayerslideraction.h202
-rw-r--r--umbrello/umbrello/kstartuplogo.cpp55
-rw-r--r--umbrello/umbrello/kstartuplogo.h49
-rw-r--r--umbrello/umbrello/linepath.cpp957
-rw-r--r--umbrello/umbrello/linepath.h383
-rw-r--r--umbrello/umbrello/linkwidget.cpp61
-rw-r--r--umbrello/umbrello/linkwidget.h128
-rw-r--r--umbrello/umbrello/listpopupmenu.cpp1348
-rw-r--r--umbrello/umbrello/listpopupmenu.h330
-rw-r--r--umbrello/umbrello/main.cpp208
-rw-r--r--umbrello/umbrello/messagewidget.cpp792
-rw-r--r--umbrello/umbrello/messagewidget.h401
-rw-r--r--umbrello/umbrello/messagewidgetcontroller.cpp96
-rw-r--r--umbrello/umbrello/messagewidgetcontroller.h154
-rw-r--r--umbrello/umbrello/messagewidgetlist.h22
-rw-r--r--umbrello/umbrello/model_utils.cpp1221
-rw-r--r--umbrello/umbrello/model_utils.h328
-rw-r--r--umbrello/umbrello/node.cpp43
-rw-r--r--umbrello/umbrello/node.h67
-rw-r--r--umbrello/umbrello/nodewidget.cpp132
-rw-r--r--umbrello/umbrello/nodewidget.h64
-rw-r--r--umbrello/umbrello/notewidget.cpp316
-rw-r--r--umbrello/umbrello/notewidget.h146
-rw-r--r--umbrello/umbrello/notewidgetcontroller.cpp49
-rw-r--r--umbrello/umbrello/notewidgetcontroller.h81
-rw-r--r--umbrello/umbrello/object_factory.cpp283
-rw-r--r--umbrello/umbrello/object_factory.h84
-rw-r--r--umbrello/umbrello/objectwidget.cpp403
-rw-r--r--umbrello/umbrello/objectwidget.h331
-rw-r--r--umbrello/umbrello/objectwidgetcontroller.cpp44
-rw-r--r--umbrello/umbrello/objectwidgetcontroller.h92
-rw-r--r--umbrello/umbrello/operation.cpp431
-rw-r--r--umbrello/umbrello/operation.h209
-rw-r--r--umbrello/umbrello/optionstate.cpp27
-rw-r--r--umbrello/umbrello/optionstate.h81
-rw-r--r--umbrello/umbrello/ownedcodeblock.cpp180
-rw-r--r--umbrello/umbrello/ownedcodeblock.h100
-rw-r--r--umbrello/umbrello/ownedhierarchicalcodeblock.cpp113
-rw-r--r--umbrello/umbrello/ownedhierarchicalcodeblock.h98
-rw-r--r--umbrello/umbrello/package.cpp298
-rw-r--r--umbrello/umbrello/package.h198
-rw-r--r--umbrello/umbrello/packagewidget.cpp133
-rw-r--r--umbrello/umbrello/packagewidget.h74
-rw-r--r--umbrello/umbrello/petalnode.cpp61
-rw-r--r--umbrello/umbrello/petalnode.h86
-rw-r--r--umbrello/umbrello/petaltree2uml.cpp631
-rw-r--r--umbrello/umbrello/petaltree2uml.h39
-rw-r--r--umbrello/umbrello/pics/COPYING3
-rw-r--r--umbrello/umbrello/pics/CVglobal_meth.pngbin0 -> 342 bytes
-rw-r--r--umbrello/umbrello/pics/CVglobal_var.pngbin0 -> 313 bytes
-rw-r--r--umbrello/umbrello/pics/CVimplementation_meth.pngbin0 -> 372 bytes
-rw-r--r--umbrello/umbrello/pics/CVimplementation_signal.pngbin0 -> 391 bytes
-rw-r--r--umbrello/umbrello/pics/CVimplementation_slot.pngbin0 -> 392 bytes
-rw-r--r--umbrello/umbrello/pics/CVimplementation_var.pngbin0 -> 309 bytes
-rw-r--r--umbrello/umbrello/pics/CVnamespace.pngbin0 -> 451 bytes
-rw-r--r--umbrello/umbrello/pics/CVprivate_meth.pngbin0 -> 347 bytes
-rw-r--r--umbrello/umbrello/pics/CVprivate_signal.pngbin0 -> 354 bytes
-rw-r--r--umbrello/umbrello/pics/CVprivate_slot.pngbin0 -> 356 bytes
-rw-r--r--umbrello/umbrello/pics/CVprivate_var.pngbin0 -> 314 bytes
-rw-r--r--umbrello/umbrello/pics/CVprotected_meth.pngbin0 -> 346 bytes
-rw-r--r--umbrello/umbrello/pics/CVprotected_signal.pngbin0 -> 352 bytes
-rw-r--r--umbrello/umbrello/pics/CVprotected_slot.pngbin0 -> 353 bytes
-rw-r--r--umbrello/umbrello/pics/CVprotected_var.pngbin0 -> 321 bytes
-rw-r--r--umbrello/umbrello/pics/CVpublic_meth.pngbin0 -> 320 bytes
-rw-r--r--umbrello/umbrello/pics/CVpublic_signal.pngbin0 -> 327 bytes
-rw-r--r--umbrello/umbrello/pics/CVpublic_slot.pngbin0 -> 329 bytes
-rw-r--r--umbrello/umbrello/pics/CVpublic_var.pngbin0 -> 293 bytes
-rw-r--r--umbrello/umbrello/pics/CVstruct.pngbin0 -> 355 bytes
-rw-r--r--umbrello/umbrello/pics/Makefile.am112
-rw-r--r--umbrello/umbrello/pics/actor.pngbin0 -> 1081 bytes
-rw-r--r--umbrello/umbrello/pics/aggregation.pngbin0 -> 439 bytes
-rw-r--r--umbrello/umbrello/pics/align_bottom.pngbin0 -> 247 bytes
-rw-r--r--umbrello/umbrello/pics/align_hori_distribute.pngbin0 -> 297 bytes
-rw-r--r--umbrello/umbrello/pics/align_hori_middle.pngbin0 -> 295 bytes
-rw-r--r--umbrello/umbrello/pics/align_left.pngbin0 -> 248 bytes
-rw-r--r--umbrello/umbrello/pics/align_right.pngbin0 -> 249 bytes
-rw-r--r--umbrello/umbrello/pics/align_top.pngbin0 -> 246 bytes
-rw-r--r--umbrello/umbrello/pics/align_vert_distribute.pngbin0 -> 305 bytes
-rw-r--r--umbrello/umbrello/pics/align_vert_middle.pngbin0 -> 289 bytes
-rw-r--r--umbrello/umbrello/pics/anchor.pngbin0 -> 859 bytes
-rw-r--r--umbrello/umbrello/pics/andline.pngbin0 -> 788 bytes
-rw-r--r--umbrello/umbrello/pics/arrow.pngbin0 -> 436 bytes
-rw-r--r--umbrello/umbrello/pics/artifact.pngbin0 -> 726 bytes
-rw-r--r--umbrello/umbrello/pics/association.pngbin0 -> 167 bytes
-rw-r--r--umbrello/umbrello/pics/box.pngbin0 -> 184 bytes
-rw-r--r--umbrello/umbrello/pics/branch.pngbin0 -> 863 bytes
-rw-r--r--umbrello/umbrello/pics/choice-rhomb.pngbin0 -> 894 bytes
-rw-r--r--umbrello/umbrello/pics/choice-round.pngbin0 -> 971 bytes
-rw-r--r--umbrello/umbrello/pics/class.pngbin0 -> 827 bytes
-rw-r--r--umbrello/umbrello/pics/component.pngbin0 -> 577 bytes
-rw-r--r--umbrello/umbrello/pics/composition.pngbin0 -> 540 bytes
-rw-r--r--umbrello/umbrello/pics/containment.pngbin0 -> 447 bytes
-rw-r--r--umbrello/umbrello/pics/cr16-action-umbrello_diagram_activity.pngbin0 -> 789 bytes
-rw-r--r--umbrello/umbrello/pics/cr16-action-umbrello_diagram_class.pngbin0 -> 764 bytes
-rw-r--r--umbrello/umbrello/pics/cr16-action-umbrello_diagram_collaboration.pngbin0 -> 799 bytes
-rw-r--r--umbrello/umbrello/pics/cr16-action-umbrello_diagram_component.pngbin0 -> 754 bytes
-rw-r--r--umbrello/umbrello/pics/cr16-action-umbrello_diagram_deployment.pngbin0 -> 815 bytes
-rw-r--r--umbrello/umbrello/pics/cr16-action-umbrello_diagram_sequence.pngbin0 -> 821 bytes
-rw-r--r--umbrello/umbrello/pics/cr16-action-umbrello_diagram_state.pngbin0 -> 816 bytes
-rw-r--r--umbrello/umbrello/pics/cr16-action-umbrello_diagram_usecase.pngbin0 -> 823 bytes
-rw-r--r--umbrello/umbrello/pics/cr22-action-umbrello_diagram_activity.pngbin0 -> 1211 bytes
-rw-r--r--umbrello/umbrello/pics/cr22-action-umbrello_diagram_class.pngbin0 -> 1124 bytes
-rw-r--r--umbrello/umbrello/pics/cr22-action-umbrello_diagram_collaboration.pngbin0 -> 1169 bytes
-rw-r--r--umbrello/umbrello/pics/cr22-action-umbrello_diagram_component.pngbin0 -> 1090 bytes
-rw-r--r--umbrello/umbrello/pics/cr22-action-umbrello_diagram_deployment.pngbin0 -> 1177 bytes
-rw-r--r--umbrello/umbrello/pics/cr22-action-umbrello_diagram_entityrelationship.pngbin0 -> 1039 bytes
-rw-r--r--umbrello/umbrello/pics/cr22-action-umbrello_diagram_sequence.pngbin0 -> 1225 bytes
-rw-r--r--umbrello/umbrello/pics/cr22-action-umbrello_diagram_state.pngbin0 -> 1258 bytes
-rw-r--r--umbrello/umbrello/pics/cr22-action-umbrello_diagram_usecase.pngbin0 -> 1247 bytes
-rw-r--r--umbrello/umbrello/pics/cursor-actor.pngbin0 -> 1055 bytes
-rw-r--r--umbrello/umbrello/pics/cursor-aggregation.pngbin0 -> 880 bytes
-rw-r--r--umbrello/umbrello/pics/cursor-anchor.pngbin0 -> 1157 bytes
-rw-r--r--umbrello/umbrello/pics/cursor-andline.pngbin0 -> 1018 bytes
-rw-r--r--umbrello/umbrello/pics/cursor-artifact.pngbin0 -> 813 bytes
-rw-r--r--umbrello/umbrello/pics/cursor-association.pngbin0 -> 775 bytes
-rw-r--r--umbrello/umbrello/pics/cursor-box.pngbin0 -> 716 bytes
-rw-r--r--umbrello/umbrello/pics/cursor-branch.pngbin0 -> 1304 bytes
-rw-r--r--umbrello/umbrello/pics/cursor-choice-rhomb.pngbin0 -> 1179 bytes
-rw-r--r--umbrello/umbrello/pics/cursor-choice-round.pngbin0 -> 1042 bytes
-rw-r--r--umbrello/umbrello/pics/cursor-class.pngbin0 -> 852 bytes
-rw-r--r--umbrello/umbrello/pics/cursor-component.pngbin0 -> 678 bytes
-rw-r--r--umbrello/umbrello/pics/cursor-composition.pngbin0 -> 990 bytes
-rw-r--r--umbrello/umbrello/pics/cursor-containment.pngbin0 -> 888 bytes
-rw-r--r--umbrello/umbrello/pics/cursor-datatype.pngbin0 -> 1080 bytes
-rw-r--r--umbrello/umbrello/pics/cursor-deep-history.pngbin0 -> 826 bytes
-rw-r--r--umbrello/umbrello/pics/cursor-dependency.pngbin0 -> 1089 bytes
-rw-r--r--umbrello/umbrello/pics/cursor-end_state.pngbin0 -> 1250 bytes
-rw-r--r--umbrello/umbrello/pics/cursor-entity.pngbin0 -> 878 bytes
-rw-r--r--umbrello/umbrello/pics/cursor-enum.pngbin0 -> 1050 bytes
-rw-r--r--umbrello/umbrello/pics/cursor-fork.pngbin0 -> 860 bytes
-rw-r--r--umbrello/umbrello/pics/cursor-generalisation.pngbin0 -> 890 bytes
-rw-r--r--umbrello/umbrello/pics/cursor-initial_state.pngbin0 -> 1105 bytes
-rw-r--r--umbrello/umbrello/pics/cursor-interface.pngbin0 -> 1056 bytes
-rw-r--r--umbrello/umbrello/pics/cursor-join.pngbin0 -> 442 bytes
-rw-r--r--umbrello/umbrello/pics/cursor-junction.pngbin0 -> 606 bytes
-rw-r--r--umbrello/umbrello/pics/cursor-message-asynchronous.pngbin0 -> 1065 bytes
-rw-r--r--umbrello/umbrello/pics/cursor-message-synchronous.pngbin0 -> 1014 bytes
-rw-r--r--umbrello/umbrello/pics/cursor-node.pngbin0 -> 1137 bytes
-rw-r--r--umbrello/umbrello/pics/cursor-note.pngbin0 -> 1161 bytes
-rw-r--r--umbrello/umbrello/pics/cursor-object.pngbin0 -> 1013 bytes
-rw-r--r--umbrello/umbrello/pics/cursor-package.pngbin0 -> 1067 bytes
-rw-r--r--umbrello/umbrello/pics/cursor-relationship.pngbin0 -> 935 bytes
-rw-r--r--umbrello/umbrello/pics/cursor-shallow-history.pngbin0 -> 762 bytes
-rw-r--r--umbrello/umbrello/pics/cursor-state-fork.pngbin0 -> 390 bytes
-rw-r--r--umbrello/umbrello/pics/cursor-text.pngbin0 -> 1049 bytes
-rw-r--r--umbrello/umbrello/pics/cursor-uniassociation.pngbin0 -> 888 bytes
-rw-r--r--umbrello/umbrello/pics/cursor-usecase.pngbin0 -> 1189 bytes
-rw-r--r--umbrello/umbrello/pics/datatype.pngbin0 -> 752 bytes
-rw-r--r--umbrello/umbrello/pics/deep-history.pngbin0 -> 703 bytes
-rw-r--r--umbrello/umbrello/pics/dependency.pngbin0 -> 335 bytes
-rw-r--r--umbrello/umbrello/pics/end_state.pngbin0 -> 1186 bytes
-rw-r--r--umbrello/umbrello/pics/entity.pngbin0 -> 827 bytes
-rw-r--r--umbrello/umbrello/pics/enum.pngbin0 -> 999 bytes
-rw-r--r--umbrello/umbrello/pics/fork.pngbin0 -> 213 bytes
-rw-r--r--umbrello/umbrello/pics/generalisation.pngbin0 -> 346 bytes
-rw-r--r--umbrello/umbrello/pics/initial_state.pngbin0 -> 893 bytes
-rw-r--r--umbrello/umbrello/pics/interface.pngbin0 -> 883 bytes
-rw-r--r--umbrello/umbrello/pics/join.pngbin0 -> 281 bytes
-rw-r--r--umbrello/umbrello/pics/junction.pngbin0 -> 412 bytes
-rw-r--r--umbrello/umbrello/pics/message-asynchronous.pngbin0 -> 556 bytes
-rw-r--r--umbrello/umbrello/pics/message-synchronous.pngbin0 -> 594 bytes
-rw-r--r--umbrello/umbrello/pics/node.pngbin0 -> 1071 bytes
-rw-r--r--umbrello/umbrello/pics/note.pngbin0 -> 939 bytes
-rw-r--r--umbrello/umbrello/pics/object.pngbin0 -> 727 bytes
-rw-r--r--umbrello/umbrello/pics/package.pngbin0 -> 939 bytes
-rw-r--r--umbrello/umbrello/pics/relationship.pngbin0 -> 297 bytes
-rw-r--r--umbrello/umbrello/pics/shallow-history.pngbin0 -> 669 bytes
-rw-r--r--umbrello/umbrello/pics/sources/actor.svg172
-rw-r--r--umbrello/umbrello/pics/sources/aggregation.svg130
-rw-r--r--umbrello/umbrello/pics/sources/align_bottom.svg261
-rw-r--r--umbrello/umbrello/pics/sources/align_hori_distribute.svg273
-rw-r--r--umbrello/umbrello/pics/sources/align_hori_middle.svg257
-rw-r--r--umbrello/umbrello/pics/sources/align_left.svg260
-rw-r--r--umbrello/umbrello/pics/sources/align_right.svg260
-rw-r--r--umbrello/umbrello/pics/sources/align_top.svg251
-rw-r--r--umbrello/umbrello/pics/sources/align_vert_distribute.svg272
-rw-r--r--umbrello/umbrello/pics/sources/align_vert_middle.svg254
-rw-r--r--umbrello/umbrello/pics/sources/anchor.svg279
-rw-r--r--umbrello/umbrello/pics/sources/andline.svg102
-rw-r--r--umbrello/umbrello/pics/sources/artifact.svg153
-rw-r--r--umbrello/umbrello/pics/sources/association.svg115
-rw-r--r--umbrello/umbrello/pics/sources/asynchro.svg133
-rw-r--r--umbrello/umbrello/pics/sources/box.svg85
-rw-r--r--umbrello/umbrello/pics/sources/branch.svg128
-rw-r--r--umbrello/umbrello/pics/sources/choice-rhomb.svg160
-rw-r--r--umbrello/umbrello/pics/sources/choice-round.svg178
-rw-r--r--umbrello/umbrello/pics/sources/class.svg131
-rw-r--r--umbrello/umbrello/pics/sources/component.svg123
-rw-r--r--umbrello/umbrello/pics/sources/composition.svg128
-rw-r--r--umbrello/umbrello/pics/sources/containment.svg141
-rw-r--r--umbrello/umbrello/pics/sources/cursor-andline.svg496
-rw-r--r--umbrello/umbrello/pics/sources/cursor-choice-rhomb.svg439
-rw-r--r--umbrello/umbrello/pics/sources/cursor-choice-round.svg356
-rw-r--r--umbrello/umbrello/pics/sources/cursor-deep-history.svg206
-rw-r--r--umbrello/umbrello/pics/sources/cursor-join.svg289
-rw-r--r--umbrello/umbrello/pics/sources/cursor-junction.svg279
-rw-r--r--umbrello/umbrello/pics/sources/cursor-shallow-history.svg195
-rw-r--r--umbrello/umbrello/pics/sources/cursor-state-fork.svg289
-rw-r--r--umbrello/umbrello/pics/sources/datatype.svg121
-rw-r--r--umbrello/umbrello/pics/sources/deep-history.svg84
-rw-r--r--umbrello/umbrello/pics/sources/dependency.svg216
-rw-r--r--umbrello/umbrello/pics/sources/diag_activity.svg571
-rw-r--r--umbrello/umbrello/pics/sources/diag_class.svg360
-rw-r--r--umbrello/umbrello/pics/sources/diag_collaboration.svg1111
-rw-r--r--umbrello/umbrello/pics/sources/diag_component.svg732
-rw-r--r--umbrello/umbrello/pics/sources/diag_deployment.svg676
-rw-r--r--umbrello/umbrello/pics/sources/diag_entityrelationship.svg715
-rw-r--r--umbrello/umbrello/pics/sources/diag_sequence.svg729
-rw-r--r--umbrello/umbrello/pics/sources/diag_state.svg629
-rw-r--r--umbrello/umbrello/pics/sources/diag_usecase.svg489
-rw-r--r--umbrello/umbrello/pics/sources/diagbase.svg189
-rw-r--r--umbrello/umbrello/pics/sources/end_state.svg136
-rw-r--r--umbrello/umbrello/pics/sources/entity.svg151
-rw-r--r--umbrello/umbrello/pics/sources/enum.svg114
-rw-r--r--umbrello/umbrello/pics/sources/fork.svg115
-rw-r--r--umbrello/umbrello/pics/sources/generalise.svg127
-rw-r--r--umbrello/umbrello/pics/sources/initial.svg126
-rw-r--r--umbrello/umbrello/pics/sources/interface.svg130
-rw-r--r--umbrello/umbrello/pics/sources/join.svg175
-rw-r--r--umbrello/umbrello/pics/sources/junction.svg256
-rw-r--r--umbrello/umbrello/pics/sources/message-asynchronous.svg133
-rw-r--r--umbrello/umbrello/pics/sources/message-synchronous.svg169
-rw-r--r--umbrello/umbrello/pics/sources/node.svg114
-rw-r--r--umbrello/umbrello/pics/sources/note.svg164
-rw-r--r--umbrello/umbrello/pics/sources/object.svg110
-rw-r--r--umbrello/umbrello/pics/sources/package.svg121
-rw-r--r--umbrello/umbrello/pics/sources/relationship.svg243
-rw-r--r--umbrello/umbrello/pics/sources/shallow-history.svg73
-rw-r--r--umbrello/umbrello/pics/sources/state-fork.svg172
-rw-r--r--umbrello/umbrello/pics/sources/subsystem.svg135
-rw-r--r--umbrello/umbrello/pics/sources/template.svg146
-rw-r--r--umbrello/umbrello/pics/sources/text.svg91
-rw-r--r--umbrello/umbrello/pics/sources/uniassociation.svg221
-rw-r--r--umbrello/umbrello/pics/sources/usecase.svg131
-rw-r--r--umbrello/umbrello/pics/startlogo.pngbin0 -> 19738 bytes
-rw-r--r--umbrello/umbrello/pics/state-fork.pngbin0 -> 324 bytes
-rw-r--r--umbrello/umbrello/pics/subsystem.pngbin0 -> 629 bytes
-rw-r--r--umbrello/umbrello/pics/template.pngbin0 -> 577 bytes
-rw-r--r--umbrello/umbrello/pics/text.pngbin0 -> 484 bytes
-rw-r--r--umbrello/umbrello/pics/uniassociation.pngbin0 -> 307 bytes
-rw-r--r--umbrello/umbrello/pics/usecase.pngbin0 -> 751 bytes
-rw-r--r--umbrello/umbrello/plugin.cpp167
-rw-r--r--umbrello/umbrello/plugin.h163
-rw-r--r--umbrello/umbrello/pluginloader.cpp177
-rw-r--r--umbrello/umbrello/pluginloader.h132
-rw-r--r--umbrello/umbrello/refactoring/Makefile.am8
-rw-r--r--umbrello/umbrello/refactoring/refactoringassistant.cpp701
-rw-r--r--umbrello/umbrello/refactoring/refactoringassistant.h89
-rw-r--r--umbrello/umbrello/seqlinewidget.cpp124
-rw-r--r--umbrello/umbrello/seqlinewidget.h135
-rw-r--r--umbrello/umbrello/statewidget.cpp297
-rw-r--r--umbrello/umbrello/statewidget.h163
-rw-r--r--umbrello/umbrello/stereotype.cpp94
-rw-r--r--umbrello/umbrello/stereotype.h103
-rw-r--r--umbrello/umbrello/template.cpp95
-rw-r--r--umbrello/umbrello/template.h107
-rw-r--r--umbrello/umbrello/textblock.cpp320
-rw-r--r--umbrello/umbrello/textblock.h241
-rw-r--r--umbrello/umbrello/textblocklist.h23
-rw-r--r--umbrello/umbrello/tips129
-rw-r--r--umbrello/umbrello/toolbarstate.cpp260
-rw-r--r--umbrello/umbrello/toolbarstate.h365
-rw-r--r--umbrello/umbrello/toolbarstatearrow.cpp134
-rw-r--r--umbrello/umbrello/toolbarstatearrow.h158
-rw-r--r--umbrello/umbrello/toolbarstateassociation.cpp232
-rw-r--r--umbrello/umbrello/toolbarstateassociation.h168
-rw-r--r--umbrello/umbrello/toolbarstatefactory.cpp96
-rw-r--r--umbrello/umbrello/toolbarstatefactory.h53
-rw-r--r--umbrello/umbrello/toolbarstatemessages.cpp169
-rw-r--r--umbrello/umbrello/toolbarstatemessages.h187
-rw-r--r--umbrello/umbrello/toolbarstateother.cpp163
-rw-r--r--umbrello/umbrello/toolbarstateother.h83
-rw-r--r--umbrello/umbrello/toolbarstatepool.cpp30
-rw-r--r--umbrello/umbrello/toolbarstatepool.h71
-rw-r--r--umbrello/umbrello/umbrello.desktop57
-rw-r--r--umbrello/umbrello/umbrelloui.rc58
-rw-r--r--umbrello/umbrello/uml.cpp1708
-rw-r--r--umbrello/umbrello/uml.h1026
-rw-r--r--umbrello/umbrello/umlassociationlist.h23
-rw-r--r--umbrello/umbrello/umlattributelist.cpp39
-rw-r--r--umbrello/umbrello/umlattributelist.h43
-rw-r--r--umbrello/umbrello/umlcanvasobject.cpp322
-rw-r--r--umbrello/umbrello/umlcanvasobject.h249
-rw-r--r--umbrello/umbrello/umlclassifierlist.h23
-rw-r--r--umbrello/umbrello/umlclassifierlistitemlist.cpp42
-rw-r--r--umbrello/umbrello/umlclassifierlistitemlist.h45
-rw-r--r--umbrello/umbrello/umldoc.cpp2356
-rw-r--r--umbrello/umbrello/umldoc.h920
-rw-r--r--umbrello/umbrello/umlentityattributelist.cpp38
-rw-r--r--umbrello/umbrello/umlentityattributelist.h44
-rw-r--r--umbrello/umbrello/umlenumliterallist.h23
-rw-r--r--umbrello/umbrello/umllistview.cpp2703
-rw-r--r--umbrello/umbrello/umllistview.h473
-rw-r--r--umbrello/umbrello/umllistviewitem.cpp696
-rw-r--r--umbrello/umbrello/umllistviewitem.h285
-rw-r--r--umbrello/umbrello/umllistviewitemlist.h29
-rw-r--r--umbrello/umbrello/umlnamespace.cpp76
-rw-r--r--umbrello/umbrello/umlnamespace.h353
-rw-r--r--umbrello/umbrello/umlobject.cpp753
-rw-r--r--umbrello/umbrello/umlobject.h495
-rw-r--r--umbrello/umbrello/umlobjectlist.cpp42
-rw-r--r--umbrello/umbrello/umlobjectlist.h53
-rw-r--r--umbrello/umbrello/umloperationlist.h23
-rw-r--r--umbrello/umbrello/umlpackagelist.h22
-rw-r--r--umbrello/umbrello/umlrole.cpp339
-rw-r--r--umbrello/umbrello/umlrole.h128
-rw-r--r--umbrello/umbrello/umlstereotypelist.h23
-rw-r--r--umbrello/umbrello/umltemplatelist.h23
-rw-r--r--umbrello/umbrello/umlview.cpp3352
-rw-r--r--umbrello/umbrello/umlview.h1255
-rw-r--r--umbrello/umbrello/umlviewcanvas.cpp41
-rw-r--r--umbrello/umbrello/umlviewcanvas.h48
-rw-r--r--umbrello/umbrello/umlviewimageexporter.cpp128
-rw-r--r--umbrello/umbrello/umlviewimageexporter.h122
-rw-r--r--umbrello/umbrello/umlviewimageexporterall.cpp74
-rw-r--r--umbrello/umbrello/umlviewimageexporterall.h58
-rw-r--r--umbrello/umbrello/umlviewimageexportermodel.cpp366
-rw-r--r--umbrello/umbrello/umlviewimageexportermodel.h214
-rw-r--r--umbrello/umbrello/umlviewlist.h29
-rw-r--r--umbrello/umbrello/umlwidget.cpp1025
-rw-r--r--umbrello/umbrello/umlwidget.h728
-rw-r--r--umbrello/umbrello/umlwidgetcontroller.cpp540
-rw-r--r--umbrello/umbrello/umlwidgetcontroller.h476
-rw-r--r--umbrello/umbrello/umlwidgetlist.h29
-rw-r--r--umbrello/umbrello/uniqueid.cpp57
-rw-r--r--umbrello/umbrello/uniqueid.h50
-rw-r--r--umbrello/umbrello/usecase.cpp40
-rw-r--r--umbrello/umbrello/usecase.h63
-rw-r--r--umbrello/umbrello/usecasewidget.cpp72
-rw-r--r--umbrello/umbrello/usecasewidget.h74
-rw-r--r--umbrello/umbrello/widget_factory.cpp241
-rw-r--r--umbrello/umbrello/widget_factory.h41
-rw-r--r--umbrello/umbrello/widget_utils.cpp110
-rw-r--r--umbrello/umbrello/widget_utils.h52
-rw-r--r--umbrello/umbrello/widgetbase.cpp136
-rw-r--r--umbrello/umbrello/widgetbase.h201
-rw-r--r--umbrello/umbrello/worktoolbar.cpp315
-rw-r--r--umbrello/umbrello/worktoolbar.h183
-rw-r--r--umbrello/umbrello/x-umbrello.desktop53
-rw-r--r--umbrello/uml.kdevprj2154
-rw-r--r--umbrello/uml.lsm14
2490 files changed, 411231 insertions, 0 deletions
diff --git a/COPYING b/COPYING
new file mode 100644
index 00000000..5ff207a8
--- /dev/null
+++ b/COPYING
@@ -0,0 +1,346 @@
+NOTE! The GPL below is copyrighted by the Free Software Foundation, but
+the instance of code that it refers to (the kde programs) are copyrighted
+by the authors who actually wrote it.
+
+---------------------------------------------------------------------------
+
+ GNU GENERAL PUBLIC LICENSE
+ Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+ 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users. This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it. (Some other Free Software Foundation software is covered by
+the GNU Library General Public License instead.) You can apply it to
+your programs, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+ To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have. You must make sure that they, too, receive or can get the
+source code. And you must show them these terms so they know their
+rights.
+
+ We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+ Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software. If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+ Finally, any free program is threatened constantly by software
+patents. We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary. To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ GNU GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License. The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language. (Hereinafter, translation is included without limitation in
+the term "modification".) Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+ 1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+ 2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) You must cause the modified files to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ b) You must cause any work that you distribute or publish, that in
+ whole or in part contains or is derived from the Program or any
+ part thereof, to be licensed as a whole at no charge to all third
+ parties under the terms of this License.
+
+ c) If the modified program normally reads commands interactively
+ when run, you must cause it, when started running for such
+ interactive use in the most ordinary way, to print or display an
+ announcement including an appropriate copyright notice and a
+ notice that there is no warranty (or else, saying that you provide
+ a warranty) and that users may redistribute the program under
+ these conditions, and telling the user how to view a copy of this
+ License. (Exception: if the Program itself is interactive but
+ does not normally print such an announcement, your work based on
+ the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+ a) Accompany it with the complete corresponding machine-readable
+ source code, which must be distributed under the terms of Sections
+ 1 and 2 above on a medium customarily used for software interchange; or,
+
+ b) Accompany it with a written offer, valid for at least three
+ years, to give any third party, for a charge no more than your
+ cost of physically performing source distribution, a complete
+ machine-readable copy of the corresponding source code, to be
+ distributed under the terms of Sections 1 and 2 above on a medium
+ customarily used for software interchange; or,
+
+ c) Accompany it with the information you received as to the offer
+ to distribute corresponding source code. (This alternative is
+ allowed only for noncommercial distribution and only if you
+ received the program in object code or executable form with such
+ an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it. For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable. However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License. Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+ 5. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Program or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+ 6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+ 7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all. For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+ 8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded. In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+ 9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time. Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation. If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+ 10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission. For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this. Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+ NO WARRANTY
+
+ 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+ 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+ END OF TERMS AND CONDITIONS
+
+ How to Apply These Terms to Your New Programs
+
+ If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+ To do so, attach the following notices to the program. It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the program's name and a brief idea of what it does.>
+ Copyright (C) 19yy <name of author>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the 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, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+ Gnomovision version 69, Copyright (C) 19yy name of author
+ Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+ This is free software, and you are welcome to redistribute it
+ under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License. Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary. Here is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+ `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+ <signature of Ty Coon>, 1 April 1989
+ Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs. If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library. If this is what you want to do, use the GNU Library General
+Public License instead of this License.
diff --git a/COPYING-DOCS b/COPYING-DOCS
new file mode 100644
index 00000000..4a0fe1c8
--- /dev/null
+++ b/COPYING-DOCS
@@ -0,0 +1,397 @@
+ GNU Free Documentation License
+ Version 1.2, November 2002
+
+
+ Copyright (C) 2000,2001,2002 Free Software Foundation, Inc.
+ 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+
+0. PREAMBLE
+
+The purpose of this License is to make a manual, textbook, or other
+functional and useful document "free" in the sense of freedom: to
+assure everyone the effective freedom to copy and redistribute it,
+with or without modifying it, either commercially or noncommercially.
+Secondarily, this License preserves for the author and publisher a way
+to get credit for their work, while not being considered responsible
+for modifications made by others.
+
+This License is a kind of "copyleft", which means that derivative
+works of the document must themselves be free in the same sense. It
+complements the GNU General Public License, which is a copyleft
+license designed for free software.
+
+We have designed this License in order to use it for manuals for free
+software, because free software needs free documentation: a free
+program should come with manuals providing the same freedoms that the
+software does. But this License is not limited to software manuals;
+it can be used for any textual work, regardless of subject matter or
+whether it is published as a printed book. We recommend this License
+principally for works whose purpose is instruction or reference.
+
+
+1. APPLICABILITY AND DEFINITIONS
+
+This License applies to any manual or other work, in any medium, that
+contains a notice placed by the copyright holder saying it can be
+distributed under the terms of this License. Such a notice grants a
+world-wide, royalty-free license, unlimited in duration, to use that
+work under the conditions stated herein. The "Document", below,
+refers to any such manual or work. Any member of the public is a
+licensee, and is addressed as "you". You accept the license if you
+copy, modify or distribute the work in a way requiring permission
+under copyright law.
+
+A "Modified Version" of the Document means any work containing the
+Document or a portion of it, either copied verbatim, or with
+modifications and/or translated into another language.
+
+A "Secondary Section" is a named appendix or a front-matter section of
+the Document that deals exclusively with the relationship of the
+publishers or authors of the Document to the Document's overall subject
+(or to related matters) and contains nothing that could fall directly
+within that overall subject. (Thus, if the Document is in part a
+textbook of mathematics, a Secondary Section may not explain any
+mathematics.) The relationship could be a matter of historical
+connection with the subject or with related matters, or of legal,
+commercial, philosophical, ethical or political position regarding
+them.
+
+The "Invariant Sections" are certain Secondary Sections whose titles
+are designated, as being those of Invariant Sections, in the notice
+that says that the Document is released under this License. If a
+section does not fit the above definition of Secondary then it is not
+allowed to be designated as Invariant. The Document may contain zero
+Invariant Sections. If the Document does not identify any Invariant
+Sections then there are none.
+
+The "Cover Texts" are certain short passages of text that are listed,
+as Front-Cover Texts or Back-Cover Texts, in the notice that says that
+the Document is released under this License. A Front-Cover Text may
+be at most 5 words, and a Back-Cover Text may be at most 25 words.
+
+A "Transparent" copy of the Document means a machine-readable copy,
+represented in a format whose specification is available to the
+general public, that is suitable for revising the document
+straightforwardly with generic text editors or (for images composed of
+pixels) generic paint programs or (for drawings) some widely available
+drawing editor, and that is suitable for input to text formatters or
+for automatic translation to a variety of formats suitable for input
+to text formatters. A copy made in an otherwise Transparent file
+format whose markup, or absence of markup, has been arranged to thwart
+or discourage subsequent modification by readers is not Transparent.
+An image format is not Transparent if used for any substantial amount
+of text. A copy that is not "Transparent" is called "Opaque".
+
+Examples of suitable formats for Transparent copies include plain
+ASCII without markup, Texinfo input format, LaTeX input format, SGML
+or XML using a publicly available DTD, and standard-conforming simple
+HTML, PostScript or PDF designed for human modification. Examples of
+transparent image formats include PNG, XCF and JPG. Opaque formats
+include proprietary formats that can be read and edited only by
+proprietary word processors, SGML or XML for which the DTD and/or
+processing tools are not generally available, and the
+machine-generated HTML, PostScript or PDF produced by some word
+processors for output purposes only.
+
+The "Title Page" means, for a printed book, the title page itself,
+plus such following pages as are needed to hold, legibly, the material
+this License requires to appear in the title page. For works in
+formats which do not have any title page as such, "Title Page" means
+the text near the most prominent appearance of the work's title,
+preceding the beginning of the body of the text.
+
+A section "Entitled XYZ" means a named subunit of the Document whose
+title either is precisely XYZ or contains XYZ in parentheses following
+text that translates XYZ in another language. (Here XYZ stands for a
+specific section name mentioned below, such as "Acknowledgements",
+"Dedications", "Endorsements", or "History".) To "Preserve the Title"
+of such a section when you modify the Document means that it remains a
+section "Entitled XYZ" according to this definition.
+
+The Document may include Warranty Disclaimers next to the notice which
+states that this License applies to the Document. These Warranty
+Disclaimers are considered to be included by reference in this
+License, but only as regards disclaiming warranties: any other
+implication that these Warranty Disclaimers may have is void and has
+no effect on the meaning of this License.
+
+
+2. VERBATIM COPYING
+
+You may copy and distribute the Document in any medium, either
+commercially or noncommercially, provided that this License, the
+copyright notices, and the license notice saying this License applies
+to the Document are reproduced in all copies, and that you add no other
+conditions whatsoever to those of this License. You may not use
+technical measures to obstruct or control the reading or further
+copying of the copies you make or distribute. However, you may accept
+compensation in exchange for copies. If you distribute a large enough
+number of copies you must also follow the conditions in section 3.
+
+You may also lend copies, under the same conditions stated above, and
+you may publicly display copies.
+
+
+3. COPYING IN QUANTITY
+
+If you publish printed copies (or copies in media that commonly have
+printed covers) of the Document, numbering more than 100, and the
+Document's license notice requires Cover Texts, you must enclose the
+copies in covers that carry, clearly and legibly, all these Cover
+Texts: Front-Cover Texts on the front cover, and Back-Cover Texts on
+the back cover. Both covers must also clearly and legibly identify
+you as the publisher of these copies. The front cover must present
+the full title with all words of the title equally prominent and
+visible. You may add other material on the covers in addition.
+Copying with changes limited to the covers, as long as they preserve
+the title of the Document and satisfy these conditions, can be treated
+as verbatim copying in other respects.
+
+If the required texts for either cover are too voluminous to fit
+legibly, you should put the first ones listed (as many as fit
+reasonably) on the actual cover, and continue the rest onto adjacent
+pages.
+
+If you publish or distribute Opaque copies of the Document numbering
+more than 100, you must either include a machine-readable Transparent
+copy along with each Opaque copy, or state in or with each Opaque copy
+a computer-network location from which the general network-using
+public has access to download using public-standard network protocols
+a complete Transparent copy of the Document, free of added material.
+If you use the latter option, you must take reasonably prudent steps,
+when you begin distribution of Opaque copies in quantity, to ensure
+that this Transparent copy will remain thus accessible at the stated
+location until at least one year after the last time you distribute an
+Opaque copy (directly or through your agents or retailers) of that
+edition to the public.
+
+It is requested, but not required, that you contact the authors of the
+Document well before redistributing any large number of copies, to give
+them a chance to provide you with an updated version of the Document.
+
+
+4. MODIFICATIONS
+
+You may copy and distribute a Modified Version of the Document under
+the conditions of sections 2 and 3 above, provided that you release
+the Modified Version under precisely this License, with the Modified
+Version filling the role of the Document, thus licensing distribution
+and modification of the Modified Version to whoever possesses a copy
+of it. In addition, you must do these things in the Modified Version:
+
+A. Use in the Title Page (and on the covers, if any) a title distinct
+ from that of the Document, and from those of previous versions
+ (which should, if there were any, be listed in the History section
+ of the Document). You may use the same title as a previous version
+ if the original publisher of that version gives permission.
+B. List on the Title Page, as authors, one or more persons or entities
+ responsible for authorship of the modifications in the Modified
+ Version, together with at least five of the principal authors of the
+ Document (all of its principal authors, if it has fewer than five),
+ unless they release you from this requirement.
+C. State on the Title page the name of the publisher of the
+ Modified Version, as the publisher.
+D. Preserve all the copyright notices of the Document.
+E. Add an appropriate copyright notice for your modifications
+ adjacent to the other copyright notices.
+F. Include, immediately after the copyright notices, a license notice
+ giving the public permission to use the Modified Version under the
+ terms of this License, in the form shown in the Addendum below.
+G. Preserve in that license notice the full lists of Invariant Sections
+ and required Cover Texts given in the Document's license notice.
+H. Include an unaltered copy of this License.
+I. Preserve the section Entitled "History", Preserve its Title, and add
+ to it an item stating at least the title, year, new authors, and
+ publisher of the Modified Version as given on the Title Page. If
+ there is no section Entitled "History" in the Document, create one
+ stating the title, year, authors, and publisher of the Document as
+ given on its Title Page, then add an item describing the Modified
+ Version as stated in the previous sentence.
+J. Preserve the network location, if any, given in the Document for
+ public access to a Transparent copy of the Document, and likewise
+ the network locations given in the Document for previous versions
+ it was based on. These may be placed in the "History" section.
+ You may omit a network location for a work that was published at
+ least four years before the Document itself, or if the original
+ publisher of the version it refers to gives permission.
+K. For any section Entitled "Acknowledgements" or "Dedications",
+ Preserve the Title of the section, and preserve in the section all
+ the substance and tone of each of the contributor acknowledgements
+ and/or dedications given therein.
+L. Preserve all the Invariant Sections of the Document,
+ unaltered in their text and in their titles. Section numbers
+ or the equivalent are not considered part of the section titles.
+M. Delete any section Entitled "Endorsements". Such a section
+ may not be included in the Modified Version.
+N. Do not retitle any existing section to be Entitled "Endorsements"
+ or to conflict in title with any Invariant Section.
+O. Preserve any Warranty Disclaimers.
+
+If the Modified Version includes new front-matter sections or
+appendices that qualify as Secondary Sections and contain no material
+copied from the Document, you may at your option designate some or all
+of these sections as invariant. To do this, add their titles to the
+list of Invariant Sections in the Modified Version's license notice.
+These titles must be distinct from any other section titles.
+
+You may add a section Entitled "Endorsements", provided it contains
+nothing but endorsements of your Modified Version by various
+parties--for example, statements of peer review or that the text has
+been approved by an organization as the authoritative definition of a
+standard.
+
+You may add a passage of up to five words as a Front-Cover Text, and a
+passage of up to 25 words as a Back-Cover Text, to the end of the list
+of Cover Texts in the Modified Version. Only one passage of
+Front-Cover Text and one of Back-Cover Text may be added by (or
+through arrangements made by) any one entity. If the Document already
+includes a cover text for the same cover, previously added by you or
+by arrangement made by the same entity you are acting on behalf of,
+you may not add another; but you may replace the old one, on explicit
+permission from the previous publisher that added the old one.
+
+The author(s) and publisher(s) of the Document do not by this License
+give permission to use their names for publicity for or to assert or
+imply endorsement of any Modified Version.
+
+
+5. COMBINING DOCUMENTS
+
+You may combine the Document with other documents released under this
+License, under the terms defined in section 4 above for modified
+versions, provided that you include in the combination all of the
+Invariant Sections of all of the original documents, unmodified, and
+list them all as Invariant Sections of your combined work in its
+license notice, and that you preserve all their Warranty Disclaimers.
+
+The combined work need only contain one copy of this License, and
+multiple identical Invariant Sections may be replaced with a single
+copy. If there are multiple Invariant Sections with the same name but
+different contents, make the title of each such section unique by
+adding at the end of it, in parentheses, the name of the original
+author or publisher of that section if known, or else a unique number.
+Make the same adjustment to the section titles in the list of
+Invariant Sections in the license notice of the combined work.
+
+In the combination, you must combine any sections Entitled "History"
+in the various original documents, forming one section Entitled
+"History"; likewise combine any sections Entitled "Acknowledgements",
+and any sections Entitled "Dedications". You must delete all sections
+Entitled "Endorsements".
+
+
+6. COLLECTIONS OF DOCUMENTS
+
+You may make a collection consisting of the Document and other documents
+released under this License, and replace the individual copies of this
+License in the various documents with a single copy that is included in
+the collection, provided that you follow the rules of this License for
+verbatim copying of each of the documents in all other respects.
+
+You may extract a single document from such a collection, and distribute
+it individually under this License, provided you insert a copy of this
+License into the extracted document, and follow this License in all
+other respects regarding verbatim copying of that document.
+
+
+7. AGGREGATION WITH INDEPENDENT WORKS
+
+A compilation of the Document or its derivatives with other separate
+and independent documents or works, in or on a volume of a storage or
+distribution medium, is called an "aggregate" if the copyright
+resulting from the compilation is not used to limit the legal rights
+of the compilation's users beyond what the individual works permit.
+When the Document is included in an aggregate, this License does not
+apply to the other works in the aggregate which are not themselves
+derivative works of the Document.
+
+If the Cover Text requirement of section 3 is applicable to these
+copies of the Document, then if the Document is less than one half of
+the entire aggregate, the Document's Cover Texts may be placed on
+covers that bracket the Document within the aggregate, or the
+electronic equivalent of covers if the Document is in electronic form.
+Otherwise they must appear on printed covers that bracket the whole
+aggregate.
+
+
+8. TRANSLATION
+
+Translation is considered a kind of modification, so you may
+distribute translations of the Document under the terms of section 4.
+Replacing Invariant Sections with translations requires special
+permission from their copyright holders, but you may include
+translations of some or all Invariant Sections in addition to the
+original versions of these Invariant Sections. You may include a
+translation of this License, and all the license notices in the
+Document, and any Warranty Disclaimers, provided that you also include
+the original English version of this License and the original versions
+of those notices and disclaimers. In case of a disagreement between
+the translation and the original version of this License or a notice
+or disclaimer, the original version will prevail.
+
+If a section in the Document is Entitled "Acknowledgements",
+"Dedications", or "History", the requirement (section 4) to Preserve
+its Title (section 1) will typically require changing the actual
+title.
+
+
+9. TERMINATION
+
+You may not copy, modify, sublicense, or distribute the Document except
+as expressly provided for under this License. Any other attempt to
+copy, modify, sublicense or distribute the Document is void, and will
+automatically terminate your rights under this License. However,
+parties who have received copies, or rights, from you under this
+License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+
+10. FUTURE REVISIONS OF THIS LICENSE
+
+The Free Software Foundation may publish new, revised versions
+of the GNU Free Documentation License from time to time. Such new
+versions will be similar in spirit to the present version, but may
+differ in detail to address new problems or concerns. See
+http://www.gnu.org/copyleft/.
+
+Each version of the License is given a distinguishing version number.
+If the Document specifies that a particular numbered version of this
+License "or any later version" applies to it, you have the option of
+following the terms and conditions either of that specified version or
+of any later version that has been published (not as a draft) by the
+Free Software Foundation. If the Document does not specify a version
+number of this License, you may choose any version ever published (not
+as a draft) by the Free Software Foundation.
+
+
+ADDENDUM: How to use this License for your documents
+
+To use this License in a document you have written, include a copy of
+the License in the document and put the following copyright and
+license notices just after the title page:
+
+ Copyright (c) YEAR YOUR NAME.
+ Permission is granted to copy, distribute and/or modify this document
+ under the terms of the GNU Free Documentation License, Version 1.2
+ or any later version published by the Free Software Foundation;
+ with no Invariant Sections, no Front-Cover Texts, and no Back-Cover Texts.
+ A copy of the license is included in the section entitled "GNU
+ Free Documentation License".
+
+If you have Invariant Sections, Front-Cover Texts and Back-Cover Texts,
+replace the "with...Texts." line with this:
+
+ with the Invariant Sections being LIST THEIR TITLES, with the
+ Front-Cover Texts being LIST, and with the Back-Cover Texts being LIST.
+
+If you have Invariant Sections without Cover Texts, or some other
+combination of the three, merge those two alternatives to suit the
+situation.
+
+If your document contains nontrivial examples of program code, we
+recommend releasing these examples in parallel under your choice of
+free software license, such as the GNU General Public License,
+to permit their use in free software.
diff --git a/Makefile.am.in b/Makefile.am.in
new file mode 100644
index 00000000..ac039ee6
--- /dev/null
+++ b/Makefile.am.in
@@ -0,0 +1,19 @@
+## kdesdk/Makefile.am
+## (C) 1997 Stephan Kulow
+
+AUTOMAKE_OPTIONS = foreign 1.6.1
+DISTCLEANFILES = inst-apps
+
+MAINTAINERCLEANFILES = subdirs configure.in acinclude.m4 SUBDIRS
+
+cvs-local:
+ @for i in *; do \
+ if test -f $$i/Makefile.cvs; then \
+ echo "creating stuff in $$i"; \
+ (cd $$i && $(MAKE) -f Makefile.cvs); \
+ fi \
+ done
+ @perl -pi -e 'if (/\[\/\$$\]\*. INSTALL=/) { print $$_ ; $$_ = "\"\") ;;\n"; }' ` ls -1 configure */configure 2>/dev/null`
+
+include admin/deps.am
+
diff --git a/Makefile.cvs b/Makefile.cvs
new file mode 100644
index 00000000..030b1407
--- /dev/null
+++ b/Makefile.cvs
@@ -0,0 +1,15 @@
+
+all:
+ @echo "This Makefile is only for the CVS repository"
+ @echo "This will be deleted before making the distribution"
+ @echo ""
+ @if test ! -d admin; then \
+ echo "Please recheckout this module!" ;\
+ echo "for cvs: use checkout once and after that update again" ;\
+ echo "for cvsup: checkout kde-common from cvsup and" ;\
+ echo " link kde-common/admin to ./admin" ;\
+ exit 1 ;\
+ fi
+ $(MAKE) -f admin/Makefile.common cvs
+
+.SILENT:
diff --git a/README b/README
new file mode 100644
index 00000000..fe188f05
--- /dev/null
+++ b/README
@@ -0,0 +1,26 @@
+In this file:
+
+* What it is
+
+What it is
+----------
+
+This is a collection of applications and tools used by KDE developers.
+It also has example code for use in learning KDE programming or starting
+a new KDE application.
+
+* cervisia: CVS client part
+* kapptemplate: shell script to easy the beginning of new apps
+* kexample: a sample KDE application, heavily documented
+* kbabel: an editor for *.po files
+* kbugbuster: a graphical frontend for the KDE bug reporting system
+* kdepalettes: palettes matching KDE's style for Gimp and XPaint
+* kmtrace: converts glibc's mtrace log into a full backtrace
+* kspy: displays all used QObjects in an application
+* kstartperf: startup time measurement
+* poxml:
+* scripts: various helper scripts (see scripts/README)
+* scheck: An interface style to highlight accel and style guide conflicts
+* kuiviewer: A KPart that lets you view .ui files.
+* umbrello: A UML modeller.
+
diff --git a/cervisia/COPYING b/cervisia/COPYING
new file mode 100644
index 00000000..96bdc086
--- /dev/null
+++ b/cervisia/COPYING
@@ -0,0 +1,339 @@
+ GNU GENERAL PUBLIC LICENSE
+ Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+ 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users. This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it. (Some other Free Software Foundation software is covered by
+the GNU Library General Public License instead.) You can apply it to
+your programs, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+ To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have. You must make sure that they, too, receive or can get the
+source code. And you must show them these terms so they know their
+rights.
+
+ We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+ Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software. If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+ Finally, any free program is threatened constantly by software
+patents. We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary. To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ GNU GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License. The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language. (Hereinafter, translation is included without limitation in
+the term "modification".) Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+ 1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+ 2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) You must cause the modified files to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ b) You must cause any work that you distribute or publish, that in
+ whole or in part contains or is derived from the Program or any
+ part thereof, to be licensed as a whole at no charge to all third
+ parties under the terms of this License.
+
+ c) If the modified program normally reads commands interactively
+ when run, you must cause it, when started running for such
+ interactive use in the most ordinary way, to print or display an
+ announcement including an appropriate copyright notice and a
+ notice that there is no warranty (or else, saying that you provide
+ a warranty) and that users may redistribute the program under
+ these conditions, and telling the user how to view a copy of this
+ License. (Exception: if the Program itself is interactive but
+ does not normally print such an announcement, your work based on
+ the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+ a) Accompany it with the complete corresponding machine-readable
+ source code, which must be distributed under the terms of Sections
+ 1 and 2 above on a medium customarily used for software interchange; or,
+
+ b) Accompany it with a written offer, valid for at least three
+ years, to give any third party, for a charge no more than your
+ cost of physically performing source distribution, a complete
+ machine-readable copy of the corresponding source code, to be
+ distributed under the terms of Sections 1 and 2 above on a medium
+ customarily used for software interchange; or,
+
+ c) Accompany it with the information you received as to the offer
+ to distribute corresponding source code. (This alternative is
+ allowed only for noncommercial distribution and only if you
+ received the program in object code or executable form with such
+ an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it. For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable. However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License. Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+ 5. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Program or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+ 6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+ 7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all. For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+ 8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded. In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+ 9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time. Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation. If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+ 10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission. For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this. Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+ NO WARRANTY
+
+ 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+ 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+ END OF TERMS AND CONDITIONS
+
+ Appendix: How to Apply These Terms to Your New Programs
+
+ If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+ To do so, attach the following notices to the program. It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the program's name and a brief idea of what it does.>
+ Copyright (C) 19yy <name of author>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the 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, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+ Gnomovision version 69, Copyright (C) 19yy name of author
+ Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+ This is free software, and you are welcome to redistribute it
+ under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License. Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary. Here is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+ `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+ <signature of Ty Coon>, 1 April 1989
+ Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs. If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library. If this is what you want to do, use the GNU Library General
+Public License instead of this License.
diff --git a/cervisia/ChangeLog b/cervisia/ChangeLog
new file mode 100644
index 00000000..6461e67f
--- /dev/null
+++ b/cervisia/ChangeLog
@@ -0,0 +1,1543 @@
+2008-08-15 André Wöbbeking <Woebbeking@kde.org>
+
+ * Fix BR #162523:
+ Allow cvsnt users to login to repositories.
+
+2008-06-18 André Wöbbeking <Woebbeking@kde.org>
+
+ * Fix BR #164216:
+ Fixed crash when updating the status after adding a directory to a repository.
+
+2007-09-11 André Wöbbeking <Woebbeking@kde.org>
+
+ * Fix BR #148162:
+ Workaround a regression in Qt 3.3.8 QDateTime::fromString().
+ Patch by Martin Koller.
+
+2007-01-13 André Wöbbeking <Woebbeking@kde.org>
+
+ * Fix:
+ Handle '.' in user name when adding a repository.
+
+2006-09-02 André Wöbbeking <Woebbeking@kde.org>
+
+ * Fix BR #133129:
+ Dates from cvs history are parsed correctly.
+
+ While at it also made parsing more robust and added event 'P'
+ "Update, Patched".
+
+2006-08-12 André Wöbbeking <Woebbeking@kde.org>
+
+ * Fix BR #131695:
+ Broken repository locations don't crash cvsservice anymore.
+
+2005-08-03 Christian Loose <christian.loose@kdemail.net>
+
+ * Implemented wish #92938:
+ Added ability to exclude files in the commit dialog from
+ the subsequent commit.
+
+2005-03-30 Christian Loose <christian.loose@kdemail.net>
+
+ * Change License to GPL.
+
+2005-03-17 Christian Loose <christian.loose@kdemail.net>
+
+ * Implemented wish #40760:
+ New item in context menu to fold/unfold the
+ selected folder and its subfolders.
+
+2005-03-07 Christian Loose <christian.loose@kdemail.net>
+
+ * Added support for commit template message (CVS/Template) in
+ the commit dialog. Patch by Darrell Esau.
+
+2005-03-04 Christian Loose <christian.loose@kdemail.net>
+
+ * Fix BR #97664:
+ Fix statusbar when embedded in Konqueror.
+
+2005-01-31 Christian Loose <christian.loose@kdemail.net>
+
+ * Implemented wish #95257:
+ Added new setting for a color. It is used to highlight files in
+ the update view with status "Not in CVS".
+
+2005-01-09 André Wöbbeking <Woebbeking@kde.org>
+
+ * Added an icon for "Diff". Thanks to Jonathan Riddell.
+
+2004-12-08 Christian Loose <christian.loose@kdemail.net>
+
+ * Fix BR #90346:
+ Normalize user-entered CVSROOT specification before adding
+ a new group to the cvsservicerc configuration file. This
+ prevents duplicate entries in the repository list.
+
+2004-11-30 Christian Loose <christian.loose@kdemail.net>
+
+ * Fix BR #94083:
+ Don't crash while removing old 'Edit with...' menu item
+ from the context menu. This can happen after the user
+ switched tabs in Konqueror.
+
+2004-11-11 André Wöbbeking <Woebbeking@kde.org>
+
+ * Fix BR #92576:
+ Use correct encoding for status messages.
+
+2004-10-26 Christian Loose <christian.loose@kdemail.net>
+
+ * Implemented wish #78696:
+ Added possibility to get a notification, when a cvs commit job
+ has finished.
+
+2004-10-14 André Wöbbeking <Woebbeking@kde.org>
+
+ * Added a search line (ala JuK and KMail) to the CVS log list view.
+
+2004-09-10 Christian Loose <christian.loose@kdemail.net>
+
+ * Fix bug #89215:
+ Always make sure that directory entries '.' and '..'
+ are part of the ignore list to prevent an endless loop
+ in UpdateDirItem::maybeScanDir().
+
+2004-09-09 Christian Loose <christian.loose@kdemail.net>
+
+ * Added new command-line option -annotate.
+
+2004-08-30 Christian Loose <christian.loose@kdemail.net>
+
+ * Added new item 'Properties' to context menu. It
+ shows the properties dialog for the selected file.
+
+2004-08-28 Christian Loose <christian.loose@kdemail.net>
+
+ * Implemented wish #74751:
+ Added support for non-recursive checkouts to the
+ checkout dialog. Patch by Sergio Visinoni.
+
+2004-08-23 Christian Loose <christian.loose@kdemail.net>
+
+ * Implemented bug #74862:
+ In the checkout dialog, it's now possible to fetch
+ the existing branch/tag names for a module from the
+ cvs server.
+ * Fix bug #87830:
+ Always read the cvs client option from the configuration
+ file even when there is no sandbox open.
+
+2004-07-13 André Wöbbeking <Woebbeking@kde.org>
+
+ * Implemented FR #67805, #67806, #67807, #67809:
+ Hooray, icons for Cervisia's (main) actions.
+ Thanks to Marco Martin for the great artwork!
+
+2004-07-11 Christian Loose <christian.loose@kdemail.net>
+
+ * Fix bug #83239:
+ Fixed retrieving author from cvs log output.
+
+2004-07-09 Christian Loose <christian.loose@kdemail.net>
+
+ * Implemented wish #75825:
+ The context menu for the file view gained an
+ 'Edit With' menu. It's now possible to start a
+ different application for the selected file.
+
+2004-07-07 Christian Loose <christian.loose@kdemail.net>
+
+ * Implemented wish #75017:
+ Show the patch option dialog when the user called the
+ 'Create patch against repository' action and pass
+ the selected options to the 'cvs diff' command.
+
+2004-07-05 Christian Loose <christian.loose@kdemail.net>
+
+ * Added a new patch option dialog. This lets you choose
+ the options passed to the diff command when creating
+ a patch with the 'Create Patch' button in the log
+ dialog.
+
+2004-06-21 Christian Loose <christian.loose@kdemail.net>
+
+ * Implemented wish #66231:
+ Added new 'Create Patch' button to the log dialog. This
+ feature makes it possible to create a patch between
+ arbitrary CVS revisions.
+
+2004-06-02 Christian Loose <christian.loose@kdemail.net>
+
+ * Implemented wish #77894:
+ Added support for a checkout of a module without
+ the CVS folder. (cvs export)
+ Patch by Dermot Daly
+
+ * Implemented wish #80177:
+ It's now possible to checkout a project under an
+ alias name. (cvs checkout -d)
+ Patch by Dermot Daly
+
+2004-05-29 Christian Loose <christian.loose@kdemail.net>
+
+ * Implemented wish #63592:
+ Honor the CVSROOT/cvsignore file by downloading it from the
+ cvs server and adding it to the global ignore list.
+
+2004-05-29 André Wöbbeking <Woebbeking@kde.org>
+
+ * Fix BR #81665: don't show duplicated files in the file view (did
+ only occur when the option "Update Recursively" wasn't active).
+
+2004-05-21 Christian Loose <christian.loose@kdemail.net>
+
+ * Added a new method to download the CVSROOT/cvsignore file
+ from the cvs server to the DCOP service.
+
+2004-05-17 André Wöbbeking <Woebbeking@kde.org>
+
+ * Fix BR #58254: honor option "Hide Non-CVS Files" when opening
+ a branch in the file tree.
+
+2004-05-17 Christian Loose <christian.loose@kdemail.net>
+
+ * Implemented wish #41467:
+ Added possibility to hide files with status Unknown by
+ extending the current option "Hide Up-To-Date Files". This option
+ is now called "Hide Unmodified Files".
+
+2004-05-16 André Wöbbeking <Woebbeking@kde.org>
+
+ * Fix BR #81498: handle spaces in the working folder name correctly.
+
+2004-05-07 Christian Loose <christian.loose@kdemail.net>
+
+ * Added auto completion to the working folder line edit
+ in the checkout and the import dialog.
+
+2004-05-05 Christian Loose <christian.loose@kdemail.net>
+
+ * Added support for compression levels (-z) above three.
+
+2004-04-29 Christian Loose <christian.loose@kdemail.net>
+
+ * Activated spellchecking in changelog dialog.
+ * Implement BR #79957:
+ Spellchecking in commit dialog.
+ (patch by theboywho@ruddyperl.com)
+
+2004-04-23 Christian Loose <christian.loose@kdemail.net>
+
+ * Big cleanup - removed KDE 3.1 support
+
+2004-04-14 Christian Loose <christian.loose@kdemail.net>
+
+ * Fix session management
+
+2004-04-13 Christian Loose <christian.loose@kdemail.net>
+
+ * Implemented BR #74754:
+ Added support for 'cvs init' to create a new repository.
+
+2004-04-01 Christian Loose <christian.loose@hamburg.de>
+
+ * Fix BR #46871:
+ Preserve file content in resolve dialog:
+ - don't remove characters
+ - don't add or remove new line markers
+ - handle A+B/B+A cases with no new line marker at
+ the end of the first version correctly
+ * Fix BR #74903:
+ Don't choke on conflict markers that are not on a
+ separate line in the resolve dialog. This happens
+ when the file didn't end with a new line marker
+ before CVS encountered the conflict.
+ * Fix BR #78800:
+ Lock harder whether a directory really is under CVS control.
+ Fix by Frerich Raabe.
+
+2004-03-17 Christian Loose <christian.loose@hamburg.de>
+
+ * Don't execute shell scripts or .desktop files when the user used
+ the edit file function. (BR #77440)
+
+2004-03-02 André Wöbbeking <Woebbeking@kde.org>
+
+ * Fix BR #55871:
+ - truncate the tooltip text if necessary
+ - use a subclassed QToolTip instead of the own TipLabel.
+
+2004-03-01 Christian Loose <christian.loose@hamburg.de>
+
+ * Implemented BR #72861:
+ Added support for option "use the file's modification time as the time
+ of import" (-d) to the cvs import function.
+
+2004-02-24 André Wöbbeking <Woebbeking@kde.org>
+
+ * Fix BR #75201:
+ Prevent crash when you activate a CervisiaPart view with RMB in
+ a Koqueror with more than one view.
+
+2004-02-20 Christian Loose <christian.loose@hamburg.de>
+
+ * Fix remembering the last input values in checkout dialog.
+
+2004-02-01 Christian Loose <christian.loose@hamburg.de>
+
+ * LogTree now derives from QTable instead of the deprecated QtTableView
+
+2004-01-22 Christian Loose <christian.loose@hamburg.de>
+
+ * Fix BR #70936:
+ Prevent crash while embedded into Quanta because of
+ a name conflict between the TagDialog classes.
+
+2004-01-16 André Wöbbeking <Woebbeking@kde.org>
+
+ * Fix BR 72519 (file view):
+ Don't select hidden files when you select a range of files
+ with Shift key. This prevents you from evil accidents (i.e.
+ "Remove from Repository").
+
+2003-10-04 Christian Loose <christian.loose@hamburg.de>
+
+ * Do a cvs logout when a user removes a pserver repository item.
+ This way the repository isn't re-added because of the .cvspass file.
+
+2003-10-03 Christian Loose <christian.loose@hamburg.de>
+
+ * Added support to add or remove watches to the cvs DCOP service.
+
+2003-09-14 Christian Loose <christian.loose@hamburg.de>
+
+ * Added new function makePatch() to the cvs DCOP service
+ to create a patch against the repository.
+
+2003-09-05 Christian Loose <christian.loose@hamburg.de>
+
+ * Implemented BR #56716:
+ Added login/logout functionality for pserver cvs
+ servers.
+
+2003-08-30 Christian Loose <christian.loose@hamburg.de>
+
+ * Added editors() and import() methods to cvs DCOP service
+
+2003-08-29 Christian Loose <christian.loose@hamburg.de>
+
+ * Removed the editor option from the settings dialog. We
+ use KRun now to start the preferred editor for the given
+ mime-type.
+ * Fix BR #53815: Prevent the user from changing the directory
+ with konqueror's tree view while there is a job running
+ in the protocol view.
+
+2003-08-28 Christian Loose <christian.loose@hamburg.de>
+
+ * Added a new button (View) to the log dialog to view
+ the selected revision of a file in the preferred editor.
+ * Added method downloadRevision() to the cvs DCOP service
+ to download a specific revision of a file.
+
+2003-08-27 Christian Loose <christian.loose@hamburg.de>
+
+ * Revamped settings dialog:
+ - Used KJanusWidget::IconList instead of KJanusWidget::Tabbed
+ - Merged 'Appearance' and 'Colors' page
+ - Moved creation of option pages in separate methods
+
+2003-08-09 André Wöbbeking <Woebbeking@kde.org>
+
+ * Make file view configurable (column order/widths, sorting).
+
+2003-08-02 André Wöbbeking <Woebbeking@kde.org>
+
+ * Fix/Implement FR 56042:
+ Use the configured colors as foreground colors in the file AND
+ protocol view and a bold font to improve readability of the text
+ for modified, added and removed files.
+
+2003-07-30 Christian Loose <christian.loose@hamburg.de>
+
+ * Added lock() and unlock() methods to the DCOP service.
+ * Replace the lock and unlock implementation in CervisiaPart
+ by calls to the new methods in the DCOP service.
+
+2003-07-28 Christian Loose <christian.loose@hamburg.de>
+
+ * Add search functionality to the plain log view. Now you
+ can search for a word in the commit messages.
+
+2003-07-16 Christian Loose <christian.loose@hamburg.de>
+
+ * Added new view variant for cvs' log output to the log dialog.
+ This view shows the data in a format that is very similar to
+ the format of the command-line output of cvs log.
+
+2003-07-09 Christian Loose <christian.loose@hamburg.de>
+
+ * New watchers dialog: Cervisia now shows the watchers of
+ the selected files in a nice dialog instead of just showing cvs'
+ output in the protocol view.
+
+2003-07-07 Christian Loose <christian.loose@hamburg.de>
+
+ * Added createTag() and deleteTag() methods to the DCOP
+ service and use them in the part.
+
+2003-07-04 Christian Loose <christian.loose@hamburg.de>
+
+ * Implement BR #60604: It's now possible to select
+ revision B in Log dialog with Ctrl key + left mouse button in
+ addition to the middle mouse button.
+
+2003-06-26 Christian Loose <christian.loose@hamburg.de>
+
+ * Start/Stop the ssh-agent process and setup the cvs
+ job environment to use it.
+ * Initial version of our own little ssh-askpass program.
+ * Initial version of the SshAgent class which will later enable
+ the cvs DCOP service to utilize the ssh-agent program.
+
+2003-06-19 Christian Loose <christian.loose@hamburg.de>
+
+ * Added showWatchers() method to the DCOP service.
+
+2003-06-19 André Wöbbeking <Woebbeking@kde.org>
+
+ * Fix BR 59275 (DiffZoomWidget):
+ o Use QStyle::querySubControlMetrics() to get the exact
+ geometry of the scroll bar groove.
+ o Better performance for big files.
+
+2003-06-14 Christian Loose <christian.loose@hamburg.de>
+
+ * Implement BR #59644: Change key shortcuts for cvs add and
+ cvs remove to Insert and Delete. Now you can use the plus and
+ minus keys for the tree view.
+
+2003-06-08 Christian Loose <christian.loose@hamburg.de>
+
+ * Added possibility to DCOP service to retrieve the accumulated
+ output after cvs command finished.
+
+2003-06-04 Christian Loose <christian.loose@hamburg.de>
+
+ * Added new command line option to show a log dialog for
+ a given file without starting the whole program.
+ Usage: cervisia -log main.cpp
+
+2003-06-03 Christian Loose <christian.loose@hamburg.de>
+
+ * Fix BR #59267: Re-added "clear" command to the
+ RMB context menu of the ProtocolView
+
+2003-05-29 Christian Loose <christian.loose@hamburg.de>
+
+ * Font of ChangeLog dialog now configurable.
+
+2003-05-25 Christian Loose <christian.loose@hamburg.de>
+
+ * Added a method to retrieve a list of modules in the repository
+ to the cvs DCOP service (cvs checkout -c).
+ * Use the new method in the CheckoutDialog.
+
+2003-05-22 Christian Loose <christian.loose@hamburg.de>
+
+ * Added edit() and unedit() method to cvs DCOP service
+ and used them for the corresponding actions in
+ Cervisia.
+
+2003-05-14 Christian Loose <christian.loose@hamburg.de>
+
+ * Use DCOP service for history action
+ * Added history() method to cvs DCOP service
+
+2003-05-10 André Wöbbeking <Woebbeking@kde.org>
+
+ * Fix BR 50918:
+ o Added possibility to diff a selected file against the
+ newest version in the repository (cvs diff -r HEAD).
+ o Now External and internal diff show the same differences.
+
+2003-05-09 Christian Loose <christian.loose@hamburg.de>
+
+ * Use DCOP service for commit action
+ (CervisiaPart::slotCommit())
+ * Convert CervisiaPart::updateActions() from manually
+ changing the state of the menu items to using
+ KXMLGUIClient::stateChanged() with the corresponding
+ setup in the part's rc-file.
+
+2003-05-05 André Wöbbeking <Woebbeking@kde.org>
+
+ * Diff between any revision and the sandbox (only select
+ revision A in the log dialog).
+
+2003-04-18 Christian Loose <christian.loose@hamburg.de>
+
+ * Fix BR 56042: Better default colors for white
+ background
+ * Fix BR 56942: Escape output lines for protocol view
+ so html tags in commit messages aren't interpreted
+
+2003-02-28 Christian Loose <christian.loose@hamburg.de>
+
+ * Fix BR #54382: Display warning message in remove dialog
+ to make clear that the action will also remove the local
+ copy of the selected files.
+
+2003-02-24 Christian Loose <christian.loose@hamburg.de>
+
+ * Make shortcut keys of actions which are part of CervisiaPart
+ configurable (#55125).
+
+2003-02-21 Christian Loose <christian.loose@hamburg.de>
+
+ * Implemented BR #41263: Added splitters to resolve
+ dialog.
+
+2003-02-18 Christian Loose <christian.loose@hamburg.de>
+
+ * Big cleanup of parseCvsDiff() in diff dialog
+
+2003-02-17 Christian Loose <christian.loose@hamburg.de>
+
+ * Use DCOP service for diff dialog.
+ * Added private method callExternalDiff() in diff
+ dialog to make parseCvsDiff() more readable.
+
+2003-02-16 Christian Loose <christian.loose@hamburg.de>
+
+ * Improved size handling for Repository dialog,
+ Add repository dialog and Checkout dialog.
+
+2003-02-12 Christian Loose <christian.loose@hamburg.de>
+
+ * Bug 54106: Display error message when user tries to
+ access a remote repository
+ * Improved size handling for Commit dialog, History dialog,
+ Resolve dialog and Resolve edit dialog
+ * Removed code duplication in Commit dialog when
+ displaying the Diff dialog
+
+2003-02-11 Christian Loose <christian.loose@hamburg.de>
+
+ * Improved size handling for Diff dialog
+
+2003-02-10 Christian Loose <christian.loose@hamburg.de>
+
+ * Remove CervisiaShell's dependency on CervisiaPart
+ * Moved filter status indicator to CervisiaPart
+ * Improve dialog size handling for ChangeLog dialog
+ (use new KDialogBase methods to save the size into
+ CervisiaPart's configuration file)
+
+2003-02-06 Christian Loose <christian.loose@hamburg.de>
+
+ * Try to get the user name and email address for the
+ changelog from the control center settings (KEMailSettings)
+ before asking the system.
+
+2003-02-02 Christian Loose <christian.loose@hamburg.de>
+
+ * Added login() and logout() methods to DCOP service.
+
+2003-01-26 André Wöbbeking <Woebbeking@kde.org>
+
+ * Implemented new option "Hide Empty Directories"
+
+2003-01-23 Christian Loose <christian.loose@hamburg.de>
+
+ * Implemented wish #41468: Remember last open directory
+ in KDirSelect dialog
+
+2003-01-21 Christian Loose <christian.loose@hamburg.de>
+
+ * Added remove() method to cvs DCOP service
+ * Use DCOP service for cvs add and cvs remove
+
+2003-01-18 Christian Loose <christian.loose@hamburg.de>
+
+ * Remove custom dialog size handling from annotation
+ dialog. The size is stored globally to simulate
+ Cervisia's old behaviour.
+
+2003-01-17 Christian Loose <christian.loose@hamburg.de>
+
+ * Remove restorePseudo() hack
+ * We always want to save "Current Directory". So move out
+ of the session management methods.
+ * Settings for the part are now handle by the part. This
+ fixes partly the bug #38235.
+
+2003-01-16 Christian Loose <christian.loose@hamburg.de>
+
+ * Changed main window size handling. The window size is now
+ handled by KMainWindow.
+ * Added method openURL() to CervisiaShell. Use this method to
+ open the sandbox which was provided on the command line.
+ TODO: remove restorePseudo()
+
+2003-01-11 Christian Loose <christian.loose@hamburg.de>
+
+ * Added help button to CommitDialog
+ * Use DCOP service to retrieve Tags and Branches for TagDialog,
+ MergeDialog und UpdateDialog
+ * Added new AddRemoveDialog (extracted from CommitDialog)
+ * Make functionality to view diff in CommitDialog more visible
+ by adding diff button.
+
+2003-01-11 André Wöbbeking <Woebbeking@kde.org>
+
+ * unfoldTree(): reduced flicker and improved perfomance by disabling updates.
+
+2003-01-11 André Wöbbeking <Woebbeking@kde.org>
+
+ * Moved colors from UpdateViewItem to UpdateView:
+ o it's faster as you don't need KConfig in UpdateViewItem ctor
+ o it needs less memory (3 colors per item)
+
+2003-01-09 Christian Loose <christian.loose@hamburg.de>
+
+ * Use DCOP stubs to access the methods of the cvs DCOP service
+ * Added new method update() and checkout() to DCOP service
+ * Use KProcess::operator<< instead of QString::operator+= to
+ build the command line
+ * Make CVS_SERVER configurable in DCOP service
+ (GUI is missing)
+ * Break up updateOrStatus() method in cervisiapart.cpp
+ * Use DCOP service to update the working copy
+
+2003-01-04 Christian Loose <christian.loose@hamburg.de>
+
+ * Use DCOP service to update status for UpdateView
+
+2003-01-02 Christian Loose <christian.loose@hamburg.de>
+
+ * Added new startJob() method to ProtocolView
+ that uses the new cvs DCOP service
+
+2003-01-02 André Wöbbeking <Woebbeking@kde.org>
+
+ * Replaced deprecated Qt classes/methods with actual equivalents.
+
+2002-12-31 Christian Loose <christian.loose@hamburg.de>
+
+ * Separate GUI from functionality for AnnotateDialog
+ * Use DCOP service for log dialog
+
+2002-12-30 André Wöbbeking <Woebbeking@kde.org>
+
+ * Use user's settings (locale and timezone) to display dates.
+
+2002-12-29 André Wöbbeking <Woebbeking@kde.org>
+
+ * Fixed sorting in list views.
+
+2002-12-29 Christian Loose <christian.loose@hamburg.de>
+
+ * Extract AddRepositoryDialog from repositorydlg.cpp
+ * Save and read repository configuration to/from the
+ configuration file of the cvs DCOP service
+ * Added kconf_update script to copy repository configuration
+ to cvsservicerc
+
+2002-12-28 Christian Loose <christian.loose@hamburg.de>
+
+ * Start and stop cvs DCOP service in CervisiaPart
+ * Change working copy directory in DCOP service
+ * Use DCOP service for annotate dialog
+ * Several changes to the DCOP service
+ * Added new parseCvsLog() method to LogDialog that
+ uses the new cvs DCOP service
+ * Save and read cvs client and global compression level configuration
+ to/from the configuration file of the cvs DCOP service
+ * Added kconf_update script
+
+2002-12-26 André Wöbbeking <Woebbeking@kde.org>
+
+ * Fixed parsing of branch and tag names:
+ o no more trailing spaces
+ o names with more than 24 chars are identified now
+
+2002-12-23 André Wöbbeking <Woebbeking@kde.org>
+
+ * All dialogs:
+ - Inherit from KDialogBase instead of QDialog
+ -> less code and more KDE standard compliant.
+ - removed layout leftovers from old Qt versions.
+ - reduced header dependences.
+
+2002-12-19 Christian Loose <christian.loose@hamburg.de>
+
+ * Replace deprecated QMultiLineEdit with KTextEdit in
+ ChangeLog dialog
+ * Added new parseCvsAnnotate() method to AnnotateDialog
+ that uses the new cvs DCOP service
+
+2002-12-18 Christian Loose <christian.loose@hamburg.de>
+
+ * Added a new progress dialog that will replace
+ CvsProgressDialog in the near future
+
+2002-12-17 Christian Loose <christian.loose@hamburg.de>
+
+ * Fixed "fetch of branch list hangs in update dialog" (#50824)
+
+2002-12-14 Christian Loose <christian.loose@hamburg.de>
+
+ * Added first version of cvs DCOP service
+
+2002-12-14 André Wöbbeking <Woebbeking@kde.org>
+
+ * Removed ListViewItem. Use Q/KListViewItem instead.
+
+2002-12-14 André Wöbbeking <Woebbeking@kde.org>
+
+ * ProtocolView::appendLine(): removed trailing <br>
+ as QTextEdit::append() already adds a new paragraph.
+ Detect "U " as remote changed file.
+
+2002-12-12 Christian Loose <christian.loose@hamburg.de>
+
+ * Fix the too small scroll area of diff view when
+ tabs in source code
+
+2002-12-08 Christian Loose <christian.loose@hamburg.de>
+
+ * Make ChangeLog dialog more KDE standard conformant
+ QDialog -> KDialogBase
+
+2002-12-05 Christian Loose <christian.loose@hamburg.de>
+
+ * Don't add a new line to the end of changelog
+ * Use QFile instead of FILE* and remove unneeded
+ inheritance in cvsdir.cpp
+
+2002-12-02 Christian Loose <christian.loose@hamburg.de>
+
+ * Fixed commit dialog bigger than screen bug (#50735)
+
+2002-11-29 Christian Loose <christian.loose@hamburg.de>
+
+ * Fixed automatic cvs edit option which called cvs edit
+ for more files than necessary
+ * Added support for new .cvspass format introduced with
+ cvs 1.11.1
+ * Fixed checkout dialog bigger than screen bug
+ * Fixed sort order of the revision numbers in log view
+
+2002-07-25 Christian Loose <christian.loose@hamburg.de>
+
+ * Use KGenericFactory
+ * Revived old filter status indicator in statusbar
+ * Preserve empty lines in ChangeLog while adding a
+ new entry
+
+2002-06-28 Bernd Gehrmann <bernd@mail.berlios.de>
+
+ * Removed Qt1-specific layout management stuff
+ * More latin1 conversions removed
+ * Command line option --resolve filename
+ (Stanislav Visnovsky <visnovsky@nenya.ms.mff.cuni.cz>)
+
+2002-06-27 Bernd Gehrmann <bernd@mail.berlios.de>
+
+ * Mark files with option -kb with a binary icon
+ * Fixed restoration of the last loaded sandbox
+ * Use different instance names for part and shell,
+ otherwise KConfig get messed up
+
+2002-06-26 Bernd Gehrmann <bernd@mail.berlios.de>
+
+ * Made editor configurable again
+ * Readded manpage
+ * Put help buttons in all dialogs, linked to
+ the online docs
+
+2002-06-25 Bernd Gehrmann <bernd@mail.berlios.de>
+
+ * Fixed char buffer to QString conversion in
+ CvsProgressDialog, resulting in random garbage
+ inserted in the annotate view. Also a bug
+ introduced in 2002-06-11
+ * Changed annotate view to QListView. Based
+ on a patch by André Wöbbeking <Woebbeking@kde.org>
+ * Hide custom tooltips in list views when contents
+ are scrolled
+ * Simplified history dialog filtering by
+ using QListViewItem::setVisible()
+ * #include cleanup
+ * i18n fixes
+ * Rewritten repository settings dialog; its
+ functionality now comprises that of the former
+ dialog and the former add repository dialog
+ * Load .ui, .docbook and .xml files with utf8
+ encoding. This can be implemented in a cleaner way
+ * Resolved accelerator conflict in resolve dialog
+ * Escape all text inserted in richtext tooltips
+
+2002-06-22 Bernd Gehrmann <bernd@mail.berlios.de>
+
+ * Fixed diff dialog bug due to changes from 2002-06-11
+
+2002-06-18 Roland Krause <rokrau@yahoo.com>
+
+ * View Filter is now applied after Fold/Unfold of the
+ file tree.
+
+2002-06-11 Bernd Gehrmann <bernd@mail.berlios.de>
+
+ * Interpret all output from cvs in the user's locale
+
+2002-04-28 Bernd Gehrmann <bernd@mail.berlios.de>
+
+ * Little layout fix in log dialog by Christian Loose
+ * Patch by Andrew Speer <andrew.speer@isolutions.com.au>:
+ in tags list (produced by cvs status -v) accept tabs
+ as delimiter
+
+2002-04-22 Bernd Gehrmann <bernd@mail.berlios.de>
+
+ * Patch by Christian Loose <christian.loose@hamburg.de>:
+ - Allow to specify a comment when importing a module
+ - Enable checkout/import when no item is selected
+ * Always enable folding and unfolding the tree
+
+2002-04-17 Bernd Gehrmann <bernd@mail.berlios.de>
+
+ * Patch by Gregory Green <gregory.p.green@boeing.com>:
+ - Checkout of branches
+ * Patch by Roland Krause <rokrau@yahoo.com>:
+ - Added "Last change" to context menu
+ - Added filter for files which are not in cvs
+ * Ignore stderr in Make Patch (it would produce
+ invalid patches previously)
+
+2002-04-03 Bernd Gehrmann <bernd@mail.berlios.de>
+
+ * Release 1.5rich
+
+2002-02-04 Bernd Gehrmann <bernd@mail.berlios.de>
+
+ * Colored ProtocolView output
+ Based on a patch by Asaf Gery <asaf@telmap.com>
+
+2001-09-04 Bernd Gehrmann <bernd@physik.hu-berlin.de>
+
+ * Added 'Force tag creation' option to tag dialog
+ Patch by Alessandro Praduroux <pradu@thekompany.com>
+
+ ======> TODO Before Importing
+ ========================================
+ * Remove stale CVS directories and add to main repository
+ kdesdk/cervisia/CVS
+ kdesdk/po/cervisia/CVS
+ kdesdk/doc/cervisia/CVS
+
+ cd kdesdk
+ cvs add cervisia
+ cd cervisia
+ cvs add -kb *.png
+ cvs add Makefile.am README TODO .cvsignore ChangeLog LICENSE.QPL \
+ cervisia.lsm *.cpp *.h *.rc
+ ========================================
+
+
+2001-09-01 Richard Moore <rich@kde.org>
+
+ * Added support for KDE/Qt 3. At the moment I've just made the
+ minimum set of changes required to make it compile. Qt 2.x is
+ still supported of course.
+ * Moved README, TODO, ChangeLog, cervisia.lsm and LICENSE.QPL to
+ the main source directory.
+ * Moved version string from configure.in.in to version.h
+ * Updated version string
+ * Added a kdoc build target to Makefile.am so we can generate some
+ api documentation
+ * Imported to kdesdk CVS module
+
+2001-07-05 Bernd Gehrmann <bernd@physik.hu-berlin.de>
+
+ * Added missing icons to doc/common directory
+
+2001-07-04 Richard Moore <rich@kde.org>
+
+ * Converted to KParts
+ * Created a standalone shell app that embeds the part
+ * Converted Makefile to use METASOURCES = AUTO
+
+2001-06-23 Bernd Gehrmann <bernd@physik.hu-berlin.de>
+
+ * Avoid making NotInCVS files up-to-date
+ * Don't show attic directories
+ * DEBUGOUT -> kdDebug()
+
+2001-06-20 Bernd Gehrmann <bernd@physik.hu-berlin.de>
+
+ * Patch by Adrian Schroeter <adrian@suse.de>:
+ - Some QString -> char* conversion fixes
+ - fixes for autoconf 2.50
+ * Use Prune Empty Directories settings not only for updates,
+ but also for checkouts
+
+2001-06-19 Richard Moore <rich@kde.org>
+
+ * Ported UI implementation to use XMLGUI
+ * Made UI more style guide compliant
+ * Added toolbar configuration
+ * Ported settings dialog to use KDialogBase
+
+2001-06-19 Bernd Gehrmann <bernd@physik.hu-berlin.de>
+
+ * Again a patch by Colin Macleod <colin.macleod@ivata.com>
+ Compression argument is now configurable per
+ repository, with a global default. Also, -f
+ is given to all commands now.
+
+2001-05-21 Bernd Gehrmann <bernd@physik.hu-berlin.de>
+
+ * Made compression argument (-z) configurable.
+ Patch by Colin Macleod <colin.macleod@ivata.com>
+
+2001-05-17 Bernd Gehrmann <bernd@physik.hu-berlin.de>
+
+ * Fixed crash when closing settings dialog
+ * Fixed first line in annotate dialog disappearing
+ * Remade html documentation from docbook, bringing
+ it in line with the kde style
+ * Release 1.4.1
+
+2001-05-16 Bernd Gehrmann <bernd@physik.hu-berlin.de>
+
+ * Cleanup
+ * Release 1.4
+
+2001-05-14 Bernd Gehrmann <bernd@physik.hu-berlin.de>
+
+ * Patch by Francisco Jose Blasco Abril <francisco.blasco@ds2.es>
+ Adds to the resolve dialog buttons A and B the additional
+ choices A+B and B+A. It is also possible to freely edit
+ items.
+ * Use -f option also for cvs log
+
+2001-04-03 Bernd Gehrmann <bernd@physik.hu-berlin.de>
+
+ * Support for external diff frontends: Based
+ on a patch by Scott Moore <scott@netcharge.com>
+
+2001-03-27 Bernd Gehrmann <bernd@physik.hu-berlin.de>
+
+ * Fixed resolve dialog bug: The merged view was
+ not scrolled to the relevant position
+
+2001-03-18 Bernd Gehrmann <bernd@physik.hu-berlin.de>
+
+ * Copied and cleaned up the << and >> button stuff from resolve
+ dialog to the diff dialog. Now it is possible to jump between
+ differences by these buttons. Based on ideas and
+ code by Francois Biot <francois.biot@sabre.com>.
+ * Zoom widget in diff dialog improved. Ditto.
+ * Added a combo in the diff dialog which allows to jump
+ directly to a difference region
+ * Release 1.3
+
+2001-03-14 Bernd Gehrmann <bernd@physik.hu-berlin.de>
+
+ * Ignore symbolic links
+
+2001-03-12 Bernd Gehrmann <bernd@physik.hu-berlin.de>
+
+ * Hopefully fixed a crash in the listview which
+ I could not reproduce myself.
+
+2001-03-03 Bernd Gehrmann <bernd@physik.hu-berlin.de>
+
+ * Patch by Wynn Wilkes: Allow to open the editor
+ with multiple files
+ * Made tab width in diff view customizable
+ * Fix in doc/Makefile.am for Solaris.
+ Thanks to Timo Ruottinen <Timo.Ruottinen@iki.fi>
+ * Some cleanups wrt constness
+
+2001-03-02 Bernd Gehrmann <bernd@physik.hu-berlin.de>
+ * Patch by Cosmin Smeu <cosmin@cosmin.com>:
+ In diff view, replace tabs by spaces
+
+2001-02-17 Bernd Gehrmann <bernd@physik.hu-berlin.de>
+
+ * Fixed opening files by double clicking
+ * Added small icon to makefile
+ * Show directory items in file tree with folder icon
+ * Implemented Fold tree
+ * Implemented Lock files and Unlock files
+ * Implemented Edit files, Unedit Files, Show editors
+ * Implemented Hide removed files
+ * Added label in the status bar which shows
+ which items are hidden
+ * Release 1.2
+
+2001-02-09 Bernd Gehrmann <bernd@physik.hu-berlin.de>
+
+ * Changed behaviour of .cvsignore mechanisms
+ for directories: now directories are ignored,
+ _except_ if they appear in CVS/Entries. I'm
+ now quite sure that it matches the behaviour
+ of CVS itself :-)
+ * Release 1.1
+
+2001-02-08 Bernd Gehrmann <bernd@physik.hu-berlin.de>
+
+ * In main view, allow tabbing by keyboard between
+ file tree and protocol view
+ * Context menus in main view also by keyboard
+
+2001-02-07 Bernd Gehrmann <bernd@physik.hu-berlin.de>
+
+ * Apply ignore rules to files instead of directories
+ - Yet Another Bug introduced between Betas 2 and 3
+ * Ignore CVS directories
+ * Pressing Return now edits the current file, not one
+ of the selected files, and never a directory...
+ * Quote file name in diff dialog
+ * In Merge dialog, implemented buttons to fetch the
+ lists of possible tags and branches
+
+2001-02-06 Bernd Gehrmann <bernd@physik.hu-berlin.de>
+
+ * Finished filtering in main view - the cast orgy ;-)
+
+2001-02-04 Bernd Gehrmann <bernd@physik.hu-berlin.de>
+
+ * Save column sizes of log list
+ * In main view and history dialog, let the main column
+ take the remaining space of the list view
+ * Do not read in contents of directory repeatedly
+ if it is empty
+ * Tooltips for menu items
+ * Options -> Settings, in consistency with other KDE apps
+ * Rewritten some captions
+
+2001-02-03 Bernd Gehrmann <bernd@physik.hu-berlin.de>
+
+ * Implemented Revert - only for cvs 1.11
+
+2001-02-01 Bernd Gehrmann <bernd@physik.hu-berlin.de>
+
+ * In Update to tag dialog, introduced new option
+ Update to branch; implemented buttons to fetch the
+ lists of possible tags and branches
+ * In protocol view, added popup with items
+ Clear and Select All
+
+2001-01-31 Bernd Gehrmann <bernd@physik.hu-berlin.de>
+
+ * Fixed widgets not appearing in the import dialog
+ * Made several dialogs non-modal again which I
+ made modal by accident between Beta 2 and Beta 3
+ * Added button for fetching the list of possible tags
+ in Delete Tag dialog
+
+2001-01-30 Bernd Gehrmann <bernd@physik.hu-berlin.de>
+
+ * Updated screenshots in documentation
+ * Close CVS/Root file after reading
+ * Don't count diagnostic message from cvs server
+ as errors when making a patch
+ * Use configured cvs client when making patch
+
+2001-01-29 Bernd Gehrmann <bernd@physik.hu-berlin.de>
+
+ * Layout fix in Add Watch dialog
+ * Use bigger font in ChangeLog dialog, use
+ KGlobalSettings::fixedFont() for KDE2
+
+2001-01-28 Bernd Gehrmann <bernd@physik.hu-berlin.de>
+
+ * Put sort column indicators in all list views
+ * New Bonsai-like blame annotation view
+ * Reduced free space in log tree, cleaned up the calculation
+ * Tool tips in log tree contain revision, author and date now
+ and use Qt's richtext engine; improved positioning
+ * Session-save configuration (order and sort direction) of log list
+ * Removed KDE1 related legacy classes
+ * KDE2 conformant command line handling
+ * Updated manpage to KDE2
+ * Updated libtool/autoconf stuff, should support --prefix now,
+ removed support for --enable-final and --enable-fast-perl
+
+2001-01-27 Bernd Gehrmann <bernd@physik.hu-berlin.de>
+
+ * Removed superfluous line breaks in log tree tool tips
+ * Fixed bug that prevented cvs info from working when kdehelp
+ was not installed
+ * Layout fixes in settings dialog
+ * Fixed i18n issue in log list
+ * 1.0beta3 branches from here
+
+2001-01-23 Bernd Gehrmann <bernd@physik.hu-berlin.de>
+
+ * Now directories are now never ignored via the various .cvsignore mechanisms
+
+2001-01-21 Bernd Gehrmann <bernd@physik.hu-berlin.de>
+
+ * Try to find a nice user name for the change log dialog
+ automatically
+ * Don't use entry from change log dialog in commit dialog
+ if the change log dialog was cancelled
+ * Made close button in history dialog non-autodefault
+
+2001-01-20 Bernd Gehrmann <bernd@physik.hu-berlin.de>
+
+ * Made all dialogs maximizable/minimizable where it makes sense
+ * Layout fix
+ * Fixed doc/Makefile.am for non-Linux systems (hopefully :-)
+ * In the Old Messages combo in the commit dialog, remove
+ duplicate entries
+
+2001-01-17 Bernd Gehrmann <bernd@physik.hu-berlin.de>
+
+ * Patch by Florent Pillet <florent.pillet@opteway.com>:
+ - In the log dialog, use multi line edits instead of labels
+ - In the linear log list, additional column with branch
+ * Korean translation by Yu-Chan, Park <super@susekorea.net>
+ * Patch by Wynn Wilkes <wynnw@calderasystems.com>:
+ Making path to the cvs client configurable
+ * Some cleanup in function argument list order; don't
+ let dialogs include toplevel.h, instead turned
+ variable into a function in misc.h... I'm a purist about
+ this matter ;-)
+
+2001-01-04 Bernd Gehrmann <bernd@physik.hu-berlin.de>
+
+ * Always use /bin/sh as shell
+ * When the progress dialog is canceled, kill the
+ underlying process instead of destroying the
+ KProcess object. This avoids a (superfluous) warning
+ from KProcCtrl
+ * Removed Ok button from the dialog.
+ Patch by Guillaume Laurent <glaurent@telegraph-road.org>
+ * Use KAnimWidget for KDE2
+
+2000-12-21 Bernd Gehrmann <bernd@physik.hu-berlin.de>
+
+ * Release 1.0beta2
+
+2000-12-13 Bernd Gehrmann <bernd@physik.hu-berlin.de>
+
+ * Bug fixes for broken diff dialog in KDE 1 version:
+ + Do not create modeless dialogs with parent
+ + Create combo box in commit dialog with minimal size
+ * Bug fix in log tree: tool tips showed revisions
+ appearing on several branches with the same root
+ * Let cvs ignore ~/.cvsrc file when diffing, as that
+ may lead to conflicting options
+
+2000-11-24 Bernd Gehrmann <bernd@physik.hu-berlin.de>
+
+ * Layout improvements in watch dialog
+ * Implemented 'Create patch'
+ * More documentation
+ * Release 1.0beta1
+
+2000-11-21 Bernd Gehrmann <bernd@physik.hu-berlin.de>
+
+ * In Import dialog, added options for ignoring files
+ and for binary imports
+
+2000-11-19 Bernd Gehrmann <bernd@physik.hu-berlin.de>
+
+ * Fixes for srcdir != builddir
+
+2000-11-11 Bernd Gehrmann <bernd@physik.hu-berlin.de>
+
+ * Made some fonts and the orientation of the main
+ window splitter configurable
+ * Fixed log tree for nested branches
+
+2000-11-10 Bernd Gehrmann <bernd@physik.hu-berlin.de>
+
+ * History list can be sorted chronologically
+
+2000-11-09 Bernd Gehrmann <bernd@physik.hu-berlin.de>
+
+ * In Last Change dialog, show newer version on the right
+ * Session management for commit dialog
+ * Diff options now customizable
+
+2000-11-08 Bernd Gehrmann <bernd@physik.hu-berlin.de>
+
+ * Again a patch by Jan Borsodi <jb@ez.no>:
+ - In Commit dialog, diffs against repository
+ can be created by selecting files from the
+ list box
+ - List of 30 latest log messages is stored
+ and available via a combo box
+ - Wheel mouse support in diff view
+ - Shortcut F5 for Status
+ Thanks :-)
+
+2000-10-27 Bernd Gehrmann <bernd@physik.hu-berlin.de>
+
+ * Disabled dcop support which doesn't make sense
+ as long as there's no general convention about
+ an interface for loading files
+
+2000-10-17 Bernd Gehrmann <bernd@physik.hu-berlin.de>
+
+ * Ignore empty lines in output of cvs checkout -c
+ Patch by Jan Borsodi <jb@ez.no>
+ * Added /usr/local/include and /usr/local/lib
+ to autoconf-checked directories
+
+2000-10-01 Bernd Gehrmann <bernd@physik.hu-berlin.de>
+
+ * Protect file names with whitespace in them
+ Based on a patch by Jeff Cody <jcody@logikos.com>
+ * Allow it to execute a File->Status
+ automatically when a sandbox is opened. Separate
+ options for local and remote repositories
+
+2000-09-19 Bernd Gehrmann <bernd@physik.hu-berlin.de>
+
+ * Fixed wrong #ifdef statement which disabled
+ Deselect All and made the selection mechanism
+ almost unusable with KDE1
+ * In diff view, synchronize both horizontal
+ and vertical scrollbars
+ * Release 0.7.2
+
+2000-09-16 Bernd Gehrmann <bernd@physik.hu-berlin.de>
+
+ * Added horizontal scrollbars in diff view
+ * Made number of context lines configurable
+ * In directory listing, separate directories from files
+ * Display sticky date tags in a more friendly way
+ * Adjust columns widths in main view dynamically
+ * Set focus explicitly in TagDialog, UpdateDialog
+ and HistoryDialog whenever radio buttons change
+ * Set initial focus in some dialogs
+ * Added more accelerators in CheckoutDialog
+ and WatchDialog
+ * Fixed recursive removes
+ * Do no try to read non-existent directories
+ * More precise coordinate computation on change bar
+ avoids stripes in certain circumstances
+ * Fixed highlighted text color
+ * Show newest revisions first in log message list
+ * Release 0.7.1
+
+2000-09-15 Bernd Gehrmann <bernd@physik.hu-berlin.de>
+
+ * Avoid -no-rtti because some crap code in
+ kdelibs crashes without rtti
+ * Fixed selection by keyboard in log message list
+ * Avoid exploding status bar width with
+ long command lines
+ * Fixed "Deselect all" accelerator
+
+2000-09-10 Bernd Gehrmann <bernd@physik.hu-berlin.de>
+
+ * Fixed dist target
+ * Release 0.7.0
+
+2000-09-09 Bernd Gehrmann <bernd@physik.hu-berlin.de>
+
+ * Fixed spinning gear for KDE2
+ * Fixed misinterpretation of mouse events in
+ log list for KDE2
+
+2000-09-08 Bernd Gehrmann <bernd@physik.hu-berlin.de>
+
+ * Backporting to KDE1. It becomes annoying :-(
+ * Polished log tree and log list
+ * Reduced flicker a lot
+
+2000-09-05 Bernd Gehrmann <bernd@physik.hu-berlin.de>
+
+ * Implemented change bar in diff frontend
+
+2000-09-03 Bernd Gehrmann <bernd@physik.hu-berlin.de>
+
+ * New diff frontend, based on unified diffs instead
+ of --side-by-side.
+ * Keybindings for arrow keys in diff and resolve
+ dialogs.
+ * Fixed caption/about data for KDE2
+
+2000-08-29 Bernd Gehrmann <bernd@physik.hu-berlin.de>
+
+ * Fixed Remove behaviour, which may be recursive or not
+
+2000-07-13 Bernd Gehrmann <bernd@physik.hu-berlin.de>
+
+ * Fixed problems with latest kdelibs2 and gcc 2.96
+ (thanks to Stan Bubrouski)
+ * Error messages don't confuse the 'Fetch list'
+ item in the check out dialog any more
+ * Using QFileDialog instead of completely
+ broken KFileDialog::getExistingDirectory()
+
+2000-05-28 Bernd Gehrmann <bernd@physik.hu-berlin.de>
+
+ * Quote file name when calling an editor
+
+2000-05-17 Bernd Gehrmann <bernd@physik.hu-berlin.de>
+
+ * Improvements in the logdialog/log tree by
+ Florent Pillet <florent.pillet@opteway.com>
+ * Implemented 'Delete tag'
+
+2000-05-07 Bernd Gehrmann <bernd@physik.hu-berlin.de>
+
+ * Implemented Add Watch, Remove watch,
+ Show watchers
+
+2000-04-25 Bernd Gehrmann <bernd@physik.hu-berlin.de>
+
+ * Added option to automatically call 'cvs edit' whenever
+ a read-only file is edited. Based on a patch by
+ Steffen Dettmer <steffen@dett.de>. Thanks!
+
+2000-04-15 Bernd Gehrmann <bernd@physik.hu-berlin.de>
+
+ * Added documentation for repository access
+ * Release 0.6.0
+
+2000-04-14 Bernd Gehrmann <bernd@physik.hu-berlin.de>
+
+ * Fixed "Open recent" for Qt 2.x
+ * Fixed caption for KDE 2.x
+
+2000-04-11 Bernd Gehrmann <bernd@physik.hu-berlin.de>
+
+ * Made repositories dialog usable.
+
+2000-04-09 Bernd Gehrmann <bernd@physik.hu-berlin.de>
+
+ * New quoting mechanism which is reliable also when
+ log messages/file names contain $ or '
+ Thanks for the hint, Walter!
+
+2000-03-09 Bernd Gehrmann <bernd@physik.hu-berlin.de>
+
+ * Put ok and cancel buttons in the progress dialog
+ to avoid confusion
+
+2000-03-06 Bernd Gehrmann <bernd@physik.hu-berlin.de>
+
+ * The combo boxes in the log dialog now indicate
+ that chosing a branch tag selects the branch point
+ * Repository dialog, unfinished.
+
+2000-03-05 Bernd Gehrmann <bernd@physik.hu-berlin.de>
+
+ * Replaced all Done's with Close's
+ * Moved Add binary from Advanced to File menu
+ * Enabled tag selectors in log dialog now also for KDE 2
+ * Implemented "Open recent"
+ * Implemented "History"
+
+2000-03-04 Bernd Gehrmann <bernd@physik.hu-berlin.de>
+
+ * Added a button in the checkout dialog to obtain
+ a list of modules
+ * Improved error message detection
+ * Show sandbox in caption
+
+2000-03-02 Bernd Gehrmann <bernd@physik.hu-berlin.de>
+
+ * Much more detailed pseudo session management.
+ Please delete your cervisiarc file!
+
+2000-02-21 Bernd Gehrmann <bernd@physik.hu-berlin.de>
+
+ * Fixed Checkout and Import which were not working at all
+ * Check tag names in checkout and import dialog
+ * Fixed accelerators and added some more
+ * Implemented "Merge"
+ * Implemented "Prune empty directories"
+ * Implemented "Select by tag" in log dialog
+ * Release 0.5.0
+
+2000-02-20 Bernd Gehrmann <bernd@physik.hu-berlin.de>
+
+ * Fixed bug which caused tooltips for revisions
+ an branches to disappear in the log tree
+ * Tags, branches and branchpoints as tooltips in log tree
+ * Improved log dialog layout
+ * Implemented "Add binary"
+
+2000-02-17 Bernd Gehrmann <bernd@physik.hu-berlin.de>
+
+ * Handle hidden files correctly
+ * Do not ignore case in files sorting
+ * Implemented "Last change"
+ * Release 0.4.0
+
+2000-02-15 Bernd Gehrmann <bernd@physik.hu-berlin.de>
+
+ * Implemented "Update to tag" and "Update to HEAD"
+ * Implemented "Tag"
+
+2000-02-14 Bernd Gehrmann <bernd@physik.hu-berlin.de>
+
+ * Implemented options "Commit recursively" and
+ "Create directories"
+ * Ported Checkout/Import dialog to the new scheme
+
+2000-02-13 Bernd Gehrmann <bernd@physik.hu-berlin.de>
+
+ * Rewritten the whole UpdateView (well, almost :-). Now it allows
+ to show and update the revision and tag field.
+ * Real support for asynchronous operation of Update, Commit, Add
+ and remove: output goes to new ProtocolView
+ * Fixed "Unfold Tree"
+ * Fixed crash caused by too many open files
+ (.cvsignore files were never closed)
+
+
+2000-02-08 Bernd Gehrmann <bernd@physik.hu-berlin.de>
+
+ * Ported documentation to docbook, added some
+ more stuff and adjusted automake system accordingly
+
+2000-02-06 Bernd Gehrmann <bernd@physik.hu-berlin.de>
+
+ * Updated autoconf framework to work correctly
+ with both KDE 1 and KDE 2
+
+1999-12-19 Bernd Gehrmann <bernd@physik.hu-berlin.de>
+
+ * In Checkout dialog, use $CVSROOT as default repository
+ (if defined)
+ * Added command line arguments --help and --version
+
+1999-11-23 Bernd Gehrmann <bernd@physik.hu-berlin.de>
+
+ * Fixed bug which caused files mistakenly marked as up to date
+ * Fixed options menu
+ * Show wait cursor while child process runs in background
+ * Made Ok button in settings dialog the default
+ * Release 0.3.1
+
+1999-11-21 Bernd Gehrmann <bernd@physik.hu-berlin.de>
+
+ * ChangeLog editor
+ * Release 0.3.0
+
+1999-11-20 Bernd Gehrmann <bernd@physik.hu-berlin.de>
+
+ * Solution of the startup problem: pseudo-session management
+ * Simpler handling of command line argument
+ * Tooltips in LogTree show log message
+
+1999-10-31 Bernd Gehrmann <bernd@physik.hu-berlin.de>
+
+ * DCOP support for KDE HEAD branch
+ * Settings dialog
+ * Context menu
+ * Doubleclick opens file
+ * 'Open Sandbox'
+
+1999-09-22 Bernd Gehrmann <bernd@physik.hu-berlin.de>
+
+ * KDE2 is really a moving target => more porting:
+ replaced KQuickHelp by QWhatsThis,
+ #defined Icon BarIcon
+ * Made editor configurable
+
+1999-08-07 Bernd Gehrmann <bernd@physik.hu-berlin.de>
+
+ * Spinning gear for SubProcDialog and CvsProgressDialog
+ * Reorganized the whole 'mark updated' code. As
+ a side effect, there is no more confusion about
+ bogus 'Up to date' files
+ * Save/load options
+ * Implemented 'Unfold tree'
+ * man page
+ * Release 0.2.1
+
+1999-08-04 Bernd Gehrmann <bernd@physik.hu-berlin.de>
+
+ * Fixed disappearing revision in log tree view
+ when branch is longer than trunk
+ * Changed .kdelnk from Applications -> Development
+ * Release 0.2
+
+1999-08-03 Bernd Gehrmann <bernd@physik.hu-berlin.de>
+
+ * Implemented recursive update
+
+1999-08-02 Bernd Gehrmann <bernd@physik.hu-berlin.de>
+
+ * Changed update, diff and annotate to use
+ the new CvsProgressDialog
+ * Preparations for multi log dialog
+ * Fixed memory leaks in modeless dialogs
+ which didn't delete themselves on closeEvent()
+
+1999-08-01 Bernd Gehrmann <bernd@physik.hu-berlin.de>
+
+ * Implemented CvsProgressDialog which will show error
+ messages for things like 'update' and allow the user
+ to interrupt the operation if cvs hangs.
+ It's _very_ smart :-)
+
+1999-07-31 Bernd Gehrmann <bernd@physik.hu-berlin.de>
+
+ * Commit/Add/Remove now show SubProcDialog
+ to give the user feedback
+ * Preparations for better error handling:
+ parseXXX routines return bool now
+ * Commented out some of the DEBUGOUT.
+ It was just _too_ much ;-)
+
+1999-07-20 Bernd Gehrmann <bernd@physik.hu-berlin.de>
+
+ * Ported to KDE 2
+
+1999-07-19 Bernd Gehrmann <bernd@physik.hu-berlin.de>
+
+ * Implemented "Import"
+ * Release 0.1
+
+1999-07-17 Bernd Gehrmann <bernd@physik.hu-berlin.de>
+
+ * Another trial in the "Startup in non-CVS directories"
+ game
+ * Layout corrections in Checkout dialog
+ * Mark selections in LogTreeView,
+ synchronized with LogListView
+
+1999-07-15 Bernd Gehrmann <bernd@physik.hu-berlin.de>
+
+ * Gave up on learning docbook. Some documentation
+ in linuxdoc is now available.
+
+1999-06-01 Bernd Gehrmann <bernd@physik.hu-berlin.de>
+
+ * Option -askdir
+ * Update status field for 'up to date' files
+ * Release 0.0.2
+
+1999-05-25 Bernd Gehrmann <bernd@physik.hu-berlin.de>
+
+ * Set colors in DiffView explicitly
+
+1999-05-17 Bernd Gehrmann <bernd@physik.hu-berlin.de>
+
+ * Fixed 'cvs commit' command
+ * Preparations for i18n
+
+1999-05-11 Bernd Gehrmann <bernd@physik.hu-berlin.de>
+
+ * Release 0.0.1
+
+
+
+
diff --git a/cervisia/HACKING b/cervisia/HACKING
new file mode 100644
index 00000000..dfa61cdd
--- /dev/null
+++ b/cervisia/HACKING
@@ -0,0 +1,79 @@
+Coding Style
+============
+
+Formatting
+----------
+
+- No tabs.
+- Indent is 4 spaces.
+- A line should not exceed 80 chars.
+- Brackets are always on separate lines.
+- Put spaces between brackets of if, while and
+ similar statements.
+
+
+Example:
+
+void MyClass::myFunction(const QString& arg)
+{
+ if( blah == "halb" )
+ {
+ doSometing();
+ }
+ else
+ {
+ varA = varB;
+ }
+}
+
+
+
+Header Formatting
+-----------------
+
+- Access modifiers are not indented.
+- Double inclusion guard defines are all upper case
+ letters and are composed of the namespace (if available),
+ the classname and a H suffix separated by underscores.
+- Inside a namespace there is no indentation.
+
+
+Example:
+
+#ifndef NAMESPACE_MYCLASS_H
+#define NAMESPACE_MYCLASS_H
+
+namespace Namespace
+{
+
+class MyClass
+{
+public:
+ MyClass();
+
+private:
+ int m_intVar;
+ KProcess* m_proc;
+};
+
+}
+
+#endif
+
+
+
+Class and File Names
+--------------------
+
+
+
+Class and Variable Names
+------------------------
+
+- For class, variable and function names separate multiple
+ words by uppercasing the words preceded by other words.
+- Class names start with an uppercase letter.
+- Function names start with a lowercase letter.
+- Variable names start with a lowercase letter.
+- Member Variables of a class start with a 'm_' prefix
+ followed by an lowercase letter. \ No newline at end of file
diff --git a/cervisia/Makefile.am b/cervisia/Makefile.am
new file mode 100644
index 00000000..eb985ea3
--- /dev/null
+++ b/cervisia/Makefile.am
@@ -0,0 +1,73 @@
+CERVISIA_VERSION = 2.4.10
+INCLUDES = -I./cvsservice -D_BSD_SOURCE $(all_includes)
+
+SUBDIRS = cvsservice . pics
+
+bin_PROGRAMS =
+lib_LTLIBRARIES =
+kdeinit_LTLIBRARIES = cervisia.la
+kde_module_LTLIBRARIES = libcervisiapart.la
+noinst_LTLIBRARIES = libcervisia.la
+
+libcervisia_la_SOURCES = annotatedlg.cpp diffdlg.cpp patchoptiondlg.cpp logdlg.cpp \
+ progressdlg.cpp progressdlg.skel resolvedlg.cpp resolvedlg_p.cpp annotateview.cpp \
+ diffview.cpp loglist.cpp logplainview.cpp logtree.cpp annotatectl.cpp \
+ loginfo.cpp misc.cpp qttableview.cpp tooltip.cpp cervisiasettings.kcfgc \
+ settingsdlg.cpp settingsdlg_advanced.ui
+libcervisia_la_COMPILE_FIRST = cvsservice/cvsservice_stub.h cervisiasettings.h
+
+libcervisiapart_la_SOURCES = updateview.cpp protocolview.cpp protocolview.skel \
+ watchdlg.cpp changelogdlg.cpp historydlg.cpp \
+ repositorydlg.cpp commitdlg.cpp checkoutdlg.cpp updatedlg.cpp \
+ tagdlg.cpp mergedlg.cpp cvsdir.cpp repositories.cpp cervisiapart.cpp \
+ addrepositorydlg.cpp addremovedlg.cpp watchersdlg.cpp \
+ updateview_items.cpp updateview_visitors.cpp entry.cpp \
+ entry_status.cpp stringmatcher.cpp cvsinitdlg.cpp ignorelistbase.cpp dirignorelist.cpp \
+ globalignorelist.cpp editwithmenu.cpp logmessageedit.cpp
+libcervisiapart_la_LDFLAGS = -module $(KDE_PLUGIN) $(all_libraries)
+libcervisiapart_la_LIBADD = $(LIB_KFILE) $(LIB_KPARTS) $(LIB_KUTILS) \
+ cvsservice/libcvsservice.la libcervisia.la
+libcervisiapart_la_COMPILE_FIRST = cvsservice/cvsservice_stub.h cervisiasettings.h
+
+cervisia_la_SOURCES = main.cpp cervisiashell.cpp
+cervisia_la_LDFLAGS = $(all_libraries) $(KDE_RPATH) -module $(KDE_PLUGIN)
+cervisia_la_LIBADD = $(LIB_KPARTS) $(LIB_KUTILS) cvsservice/libcvsservice.la libcervisia.la
+cervisia_la_COMPILE_FIRST = cvsservice/cvsservice_stub.h cervisiasettings.h
+
+man_MANS = cervisia.1
+
+METASOURCES = AUTO
+KDE_ICON = AUTO
+
+EXTRA_DIST = cervisia.desktop cervisia.png cervisia-small.png
+CLEANFILES = cervisia.1
+
+xdg_apps_DATA = cervisia.desktop
+
+kde_kcfg_DATA = cervisiapart.kcfg
+
+partrcdir = $(kde_datadir)/cervisiapart
+partrc_DATA = cervisiaui.rc
+
+shellrcdir = $(kde_datadir)/cervisia
+shellrc_DATA = cervisiashellui.rc eventsrc
+
+update_DATA = cervisia.upd
+update_SCRIPTS = move_repositories.pl change_colors.pl cervisia-normalize_cvsroot.pl cervisia-change_repos_list.pl
+updatedir = $(kde_datadir)/kconf_update
+
+messages: rc.cpp
+ $(EXTRACTRC) *.rc >> rc.cpp
+ $(XGETTEXT) -C *.cpp *.h -o $(podir)/cervisia.pot
+
+srcdoc:
+ $(kde_bindir)/kdoc -a -p -d classdocs -n 'Cervisia' *.h -lqt -lkdecore -lkdeui -lkparts
+
+cervisia.1: $(srcdir)/cervisia.1.in
+ sed -e 's%_KDEHTMLDIR_%'${kde_htmldir}'%g;' \
+ -e 's%_KDECONFDIR_%'${kde_confdir}'%g;' \
+ < $(srcdir)/cervisia.1.in > cervisia.1
+
+cervisia.1.in: cervisia.pod
+ pod2man --center "Cervisia" --release "${CERVISIA_VERSION}" \
+ cervisia.pod > cervisia.1.in
diff --git a/cervisia/README b/cervisia/README
new file mode 100644
index 00000000..e310034e
--- /dev/null
+++ b/cervisia/README
@@ -0,0 +1,19 @@
+Cervisia requires cvs 1.10 on the cvs server. With
+cvs 1.9, diffs don't work! As this old version has a
+y2k bug, switching is advisable anyway.
+
+From version 1.1 on, Cervisia implements the menu item
+File->Revert. This hands over the command 'cvs update -C'
+to the cvs client. This works only for cvs >= 1.11.
+
+Bug reports are welcome. My time is limited, so don't
+expect wonders.
+If you want to contribute bugfixes or improvements,
+check out the source code from anonymous kde cvs.
+In order to bootstrap the package, you have to
+'make -f Makefile.cvs' there. Then you can make patches
+either by using 'cvs diff -u' or by using the 'Create
+patch' menu item in Cervisia.
+
+
+Christian Loose <christian.loose@hamburg.de>
diff --git a/cervisia/TODO b/cervisia/TODO
new file mode 100644
index 00000000..f31cb683
--- /dev/null
+++ b/cervisia/TODO
@@ -0,0 +1,26 @@
+Ideas in no special order
+
+* Per-repository settings like enabling of
+ watch/edit/lock features
+
+* Log dialog option: Show only tagged revisions
+
+* Log dialog option: Show only your revisions
+
+* Log dialog: Allow to select latest on branch
+
+* Multi Log view
+
+* Implement "Add to .cvsignore"
+
+* cvs init
+
+* Implement a nice workaround for $CVSROOT/CVSROOT/cvsignore
+
+* Maybe use ui files for dialogs
+
+* Watch open working copy directory for changes (KDirWatcher)
+
+* Automatic 'cvs -n update' in specified time intervals (QTimer)
+
+* Add commit message to ChangeLog file (checkbox in commit dialog)
diff --git a/cervisia/addremovedlg.cpp b/cervisia/addremovedlg.cpp
new file mode 100644
index 00000000..108ac80e
--- /dev/null
+++ b/cervisia/addremovedlg.cpp
@@ -0,0 +1,101 @@
+/*
+ * Copyright (C) 1999-2002 Bernd Gehrmann
+ * bernd@mail.berlios.de
+ * Copyright (c) 2003 Christian Loose <christian.loose@hamburg.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.
+ *
+ * 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, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#include "addremovedlg.h"
+
+#include <qfileinfo.h>
+#include <qlabel.h>
+#include <qlayout.h>
+#include <qlistbox.h>
+#include <qstringlist.h>
+#include <kapplication.h>
+#include <kiconloader.h>
+#include <klocale.h>
+
+
+AddRemoveDialog::AddRemoveDialog(ActionType action, QWidget* parent, const char* name)
+ : KDialogBase(parent, name, true, QString::null,
+ Ok | Cancel | Help, Ok, true)
+{
+ setCaption( (action==Add)? i18n("CVS Add") :
+ (action==AddBinary)? i18n("CVS Add Binary") :
+ i18n("CVS Remove") );
+
+ QFrame* mainWidget = makeMainWidget();
+
+ QBoxLayout *layout = new QVBoxLayout(mainWidget, 0, spacingHint());
+
+ QLabel *textlabel = new QLabel
+ ( (action==Add)? i18n("Add the following files to the repository:") :
+ (action==AddBinary)? i18n("Add the following binary files to the repository:") :
+ i18n("Remove the following files from the repository:") ,
+ mainWidget );
+ layout->addWidget(textlabel);
+
+ m_listBox = new QListBox(mainWidget);
+ m_listBox->setSelectionMode(QListBox::NoSelection);
+ layout->addWidget(m_listBox, 5);
+
+ // Add warning message to dialog when user wants to remove a file
+ if (action==Remove)
+ {
+ QBoxLayout *warningLayout = new QHBoxLayout;
+
+ QLabel *warningIcon = new QLabel(mainWidget);
+ KIconLoader *loader = kapp->iconLoader();
+ warningIcon->setPixmap(loader->loadIcon("messagebox_warning", KIcon::NoGroup,
+ KIcon::SizeMedium, KIcon::DefaultState,
+ 0, true));
+ warningLayout->addWidget(warningIcon);
+
+ QLabel *warningText = new QLabel(i18n("This will also remove the files from "
+ "your local working copy."), mainWidget);
+ warningLayout->addWidget(warningText);
+
+ layout->addSpacing(5);
+ layout->addLayout(warningLayout);
+ layout->addSpacing(5);
+ }
+
+ if( action == Remove )
+ setHelp("removingfiles");
+ else
+ setHelp("addingfiles");
+}
+
+
+void AddRemoveDialog::setFileList(const QStringList& files)
+{
+ // the dot for the root directory is hard to see, so
+ // we convert it to the absolut path
+ if( files.find(".") != files.end() )
+ {
+ QStringList copy(files);
+ int idx = copy.findIndex(".");
+ copy[idx] = QFileInfo(".").absFilePath();
+
+ m_listBox->insertStringList(copy);
+ }
+ else
+ m_listBox->insertStringList(files);
+}
+
+
+// kate: space-indent on; indent-width 4; replace-tabs on;
diff --git a/cervisia/addremovedlg.h b/cervisia/addremovedlg.h
new file mode 100644
index 00000000..06b98260
--- /dev/null
+++ b/cervisia/addremovedlg.h
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 1999-2002 Bernd Gehrmann
+ * bernd@mail.berlios.de
+ * Copyright (c) 2003 Christian Loose <christian.loose@hamburg.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.
+ *
+ * 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, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+
+#ifndef ADDREMOVEDLG_H
+#define ADDREMOVEDLG_H
+
+
+#include <kdialogbase.h>
+
+
+class QListBox;
+class QStringList;
+
+
+class AddRemoveDialog : public KDialogBase
+{
+public:
+ enum ActionType { Add, AddBinary, Remove };
+
+ explicit AddRemoveDialog(ActionType action, QWidget* parent=0, const char* name=0);
+
+ void setFileList(const QStringList& files);
+
+private:
+ QListBox* m_listBox;
+};
+
+#endif
+
+
+// kate: space-indent on; indent-width 4; replace-tabs on;
diff --git a/cervisia/addrepositorydlg.cpp b/cervisia/addrepositorydlg.cpp
new file mode 100644
index 00000000..d1d24cb0
--- /dev/null
+++ b/cervisia/addrepositorydlg.cpp
@@ -0,0 +1,202 @@
+/*
+ * Copyright (C) 1999-2002 Bernd Gehrmann
+ * bernd@mail.berlios.de
+ * Copyright (c) 2002-2004 Christian Loose <christian.loose@kdemail.net>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the 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, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+
+#include "addrepositorydlg.h"
+
+#include <qcheckbox.h>
+#include <qhbox.h>
+#include <qlabel.h>
+#include <qlayout.h>
+
+#include <kconfig.h>
+#include <klineedit.h>
+#include <klocale.h>
+#include <knuminput.h>
+
+
+AddRepositoryDialog::AddRepositoryDialog(KConfig& cfg, const QString& repo,
+ QWidget* parent, const char* name)
+ : KDialogBase(parent, name, true, i18n("Add Repository"),
+ Ok | Cancel, Ok, true)
+ , partConfig(cfg)
+{
+ QFrame* mainWidget = makeMainWidget();
+
+ QBoxLayout* layout = new QVBoxLayout(mainWidget, 0, spacingHint());
+
+ QLabel* repo_label = new QLabel(i18n("&Repository:"), mainWidget);
+ layout->addWidget(repo_label);
+
+ repo_edit = new KLineEdit(mainWidget);
+ repo_edit->setFocus();
+ repo_label->setBuddy(repo_edit);
+ if( !repo.isNull() )
+ {
+ repo_edit->setText(repo);
+ repo_edit->setEnabled(false);
+ }
+ layout->addWidget(repo_edit);
+
+ QLabel* rsh_label = new QLabel(i18n("Use remote &shell (only for :ext: repositories):"), mainWidget);
+ layout->addWidget(rsh_label);
+
+ rsh_edit = new KLineEdit(mainWidget);
+ rsh_label->setBuddy(rsh_edit);
+ layout->addWidget(rsh_edit);
+
+ QLabel* server_label = new QLabel(i18n("Invoke this program on the server side:"),
+ mainWidget);
+ layout->addWidget(server_label);
+
+ server_edit = new KLineEdit(mainWidget);
+ server_label->setBuddy(server_edit);
+ layout->addWidget(server_edit);
+
+ QHBox* compressionBox = new QHBox(mainWidget);
+ m_useDifferentCompression = new QCheckBox(i18n("Use different &compression level:"), compressionBox);
+
+ m_compressionLevel = new KIntNumInput(compressionBox);
+ m_compressionLevel->setRange(0, 9, 1, false);
+ layout->addWidget(compressionBox);
+
+ m_retrieveCvsignoreFile = new QCheckBox(i18n("Download cvsignore file from "
+ "server"), mainWidget);
+ layout->addWidget(m_retrieveCvsignoreFile);
+
+ connect( repo_edit, SIGNAL(textChanged(const QString&)),
+ this, SLOT(repoChanged()) );
+ connect( m_useDifferentCompression, SIGNAL(toggled(bool)),
+ this, SLOT(compressionToggled(bool)) );
+ repoChanged();
+
+ QSize size = configDialogSize(partConfig, "AddRepositoryDialog");
+ resize(size);
+}
+
+
+AddRepositoryDialog::~AddRepositoryDialog()
+{
+ saveDialogSize(partConfig, "AddRepositoryDialog");
+}
+
+
+void AddRepositoryDialog::setRsh(const QString& rsh)
+{
+ rsh_edit->setText(rsh);
+}
+
+
+void AddRepositoryDialog::setServer(const QString& server)
+{
+ server_edit->setText(server);
+}
+
+
+void AddRepositoryDialog::setCompression(int compression)
+{
+ if( compression < 0 )
+ {
+ // TODO: use KConfigXT to retrieve default compression level
+ m_compressionLevel->setValue(0);
+ m_useDifferentCompression->setChecked(false);
+ }
+ else
+ {
+ m_useDifferentCompression->setChecked(true);
+ m_compressionLevel->setValue(compression);
+ }
+
+ compressionToggled(m_useDifferentCompression->isChecked());
+}
+
+
+void AddRepositoryDialog::setRetrieveCvsignoreFile(bool enabled)
+{
+ m_retrieveCvsignoreFile->setChecked(enabled);
+}
+
+
+QString AddRepositoryDialog::repository() const
+{
+ return repo_edit->text();
+}
+
+
+QString AddRepositoryDialog::rsh() const
+{
+ return rsh_edit->text();
+}
+
+
+QString AddRepositoryDialog::server() const
+{
+ return server_edit->text();
+}
+
+
+int AddRepositoryDialog::compression() const
+{
+ if( m_useDifferentCompression->isChecked() )
+ return m_compressionLevel->value();
+ else
+ return -1;
+}
+
+
+bool AddRepositoryDialog::retrieveCvsignoreFile() const
+{
+ return m_retrieveCvsignoreFile->isChecked();
+}
+
+
+void AddRepositoryDialog::setRepository(const QString& repo)
+{
+ setCaption(i18n("Repository Settings"));
+
+ repo_edit->setText(repo);
+ repo_edit->setEnabled(false);
+}
+
+
+void AddRepositoryDialog::repoChanged()
+{
+ QString repo = repository();
+ rsh_edit->setEnabled((!repo.startsWith(":pserver:"))
+ && repo.contains(":"));
+ m_useDifferentCompression->setEnabled(repo.contains(":"));
+ if( !repo.contains(":") )
+ m_compressionLevel->setEnabled(false);
+ else
+ compressionToggled(m_useDifferentCompression->isChecked());
+}
+
+
+void AddRepositoryDialog::compressionToggled(bool checked)
+{
+ m_compressionLevel->setEnabled(checked);
+}
+
+#include "addrepositorydlg.moc"
+
+
+// Local Variables:
+// c-basic-offset: 4
+// End:
diff --git a/cervisia/addrepositorydlg.h b/cervisia/addrepositorydlg.h
new file mode 100644
index 00000000..8fbf66fd
--- /dev/null
+++ b/cervisia/addrepositorydlg.h
@@ -0,0 +1,73 @@
+/*
+ * Copyright (C) 1999-2002 Bernd Gehrmann
+ * bernd@mail.berlios.de
+ * Copyright (c) 2002-2004 Christian Loose <christian.loose@kdemail.net>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the 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, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+
+#ifndef ADDREPOSITORYDLG_H
+#define ADDREPOSITORYDLG_H
+
+#include <kdialogbase.h>
+
+class QCheckBox;
+class KConfig;
+class KIntNumInput;
+class KLineEdit;
+
+
+class AddRepositoryDialog : public KDialogBase
+{
+ Q_OBJECT
+
+public:
+ AddRepositoryDialog(KConfig& cfg, const QString& repo, QWidget* parent = 0,
+ const char* name = 0);
+ virtual ~AddRepositoryDialog();
+
+ void setRepository(const QString& repo);
+ void setRsh(const QString& rsh);
+ void setServer(const QString& server);
+ void setCompression(int compression);
+ void setRetrieveCvsignoreFile(bool enabled);
+
+ QString repository() const;
+ QString rsh() const;
+ QString server() const;
+ int compression() const;
+ bool retrieveCvsignoreFile() const;
+
+private slots:
+ void repoChanged();
+ void compressionToggled(bool checked);
+
+private:
+ KLineEdit* repo_edit;
+ KLineEdit* rsh_edit;
+ KLineEdit* server_edit;
+ QCheckBox* m_useDifferentCompression;
+ QCheckBox* m_retrieveCvsignoreFile;
+ KIntNumInput* m_compressionLevel;
+ KConfig& partConfig;
+};
+
+#endif
+
+
+// Local Variables:
+// c-basic-offset: 4
+// End:
diff --git a/cervisia/annotatectl.cpp b/cervisia/annotatectl.cpp
new file mode 100644
index 00000000..31f95f84
--- /dev/null
+++ b/cervisia/annotatectl.cpp
@@ -0,0 +1,198 @@
+/*
+ * Copyright (c) 2002-2003 Christian Loose <christian.loose@hamburg.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.
+ *
+ * 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, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+
+#include "annotatectl.h"
+
+#include <qdatetime.h>
+#include <qmap.h>
+
+#include <dcopref.h>
+#include <klocale.h>
+#include <krfcdate.h>
+
+#include "annotatedlg.h"
+#include "loginfo.h"
+#include "progressdlg.h"
+#include "cvsservice_stub.h"
+#include "cvsjob_stub.h"
+
+using namespace Cervisia;
+
+struct AnnotateController::Private
+{
+ typedef QMap<QString, QString> RevisionCommentMap;
+ RevisionCommentMap comments; // maps comment to a revision
+
+ CvsService_stub* cvsService;
+ AnnotateDialog* dialog;
+ ProgressDialog* progress;
+
+ bool execute(const QString& fileName, const QString& revision);
+ void parseCvsLogOutput();
+ void parseCvsAnnotateOutput();
+};
+
+
+AnnotateController::AnnotateController(AnnotateDialog* dialog, CvsService_stub* cvsService)
+ : d(new Private)
+{
+ // initialize private data
+ d->cvsService = cvsService;
+ d->dialog = dialog;
+ d->progress = 0;
+}
+
+
+AnnotateController::~AnnotateController()
+{
+ delete d;
+}
+
+
+void AnnotateController::showDialog(const QString& fileName, const QString& revision)
+{
+ if( !d->execute(fileName, revision) )
+ {
+ delete d->dialog;
+ return;
+ }
+
+ d->parseCvsLogOutput();
+ d->parseCvsAnnotateOutput();
+
+ // hide progress dialog
+ delete d->progress; d->progress = 0;
+
+ d->dialog->setCaption(i18n("CVS Annotate: %1").arg(fileName));
+ d->dialog->show();
+}
+
+
+bool AnnotateController::Private::execute(const QString& fileName, const QString& revision)
+{
+ DCOPRef job = cvsService->annotate(fileName, revision);
+ if( !cvsService->ok() )
+ return false;
+
+ progress = new ProgressDialog(dialog, "Annotate", job, "annotate", i18n("CVS Annotate"));
+
+ return progress->execute();
+}
+
+
+void AnnotateController::Private::parseCvsLogOutput()
+{
+ QString line, comment, rev;
+
+ enum { Begin, Tags, Admin, Revision,
+ Author, Branches, Comment, Finished } state;
+
+ state = Begin;
+ while( progress->getLine(line) )
+ {
+ switch( state )
+ {
+ case Begin:
+ if( line == "symbolic names:" )
+ state = Tags;
+ break;
+ case Tags:
+ if( line[0] != '\t' )
+ state = Admin;
+ break;
+ case Admin:
+ if( line == "----------------------------" )
+ state = Revision;
+ break;
+ case Revision:
+ rev = line.section(' ', 1, 1);
+ state = Author;
+ break;
+ case Author:
+ state = Branches;
+ break;
+ case Branches:
+ if( !line.startsWith("branches:") )
+ {
+ state = Comment;
+ comment = line;
+ }
+ break;
+ case Comment:
+ if( line == "----------------------------" )
+ state = Revision;
+ else if( line == "=============================================================================" )
+ state = Finished;
+ if( state == Comment )
+ comment += QString("\n") + line;
+ else
+ comments[rev] = comment;
+ break;
+ case Finished:
+ ;
+ }
+
+ if (state == Finished)
+ break;
+ }
+
+ // skip header part of cvs annotate output
+ bool notEof = true;
+ while( notEof && !line.startsWith("*****") )
+ notEof = progress->getLine(line);
+}
+
+
+void AnnotateController::Private::parseCvsAnnotateOutput()
+{
+ LogInfo logInfo;
+ QString rev, content, line;
+ QString oldRevision = "";
+ bool odd = false;
+
+ while( progress->getLine(line) )
+ {
+ QString dateString = line.mid(23, 9);
+ if( !dateString.isEmpty() )
+ logInfo.m_dateTime.setTime_t(KRFCDate::parseDate(dateString), Qt::UTC);
+
+ rev = line.left(13).stripWhiteSpace();
+ logInfo.m_author = line.mid(14, 8).stripWhiteSpace();
+ content = line.mid(35, line.length()-35);
+
+ logInfo.m_comment = comments[rev];
+ if( logInfo.m_comment.isNull() )
+ logInfo.m_comment = "";
+
+ if( rev == oldRevision )
+ {
+ logInfo.m_author = QString::null;
+ rev = QString::null;
+ }
+ else
+ {
+ oldRevision = rev;
+ odd = !odd;
+ }
+
+ logInfo.m_revision = rev;
+
+ dialog->addLine(logInfo, content, odd);
+ }
+}
diff --git a/cervisia/annotatectl.h b/cervisia/annotatectl.h
new file mode 100644
index 00000000..d6b76437
--- /dev/null
+++ b/cervisia/annotatectl.h
@@ -0,0 +1,44 @@
+/*
+ * Copyright (c) 2002 Christian Loose <christian.loose@hamburg.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.
+ *
+ * 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, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+
+#ifndef ANNOTATECTL_H
+#define ANNOTATECTL_H
+
+#include <qstring.h>
+
+class AnnotateDialog;
+class CvsService_stub;
+class QWidget;
+
+
+class AnnotateController
+{
+public:
+ AnnotateController(AnnotateDialog* dialog, CvsService_stub* cvsService);
+ ~AnnotateController();
+
+ void showDialog(const QString& fileName, const QString& revision = QString::null);
+
+private:
+ struct Private;
+ Private* d;
+};
+
+
+#endif
diff --git a/cervisia/annotatedlg.cpp b/cervisia/annotatedlg.cpp
new file mode 100644
index 00000000..40b0d555
--- /dev/null
+++ b/cervisia/annotatedlg.cpp
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 1999-2002 Bernd Gehrmann
+ * bernd@mail.berlios.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.
+ *
+ * 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, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+
+#include "annotatedlg.h"
+
+#include "annotateview.h"
+
+
+AnnotateDialog::AnnotateDialog(KConfig& cfg, QWidget *parent, const char *name)
+ : KDialogBase(parent, name, false, QString::null,
+ Close | Help, Close, true)
+ , partConfig(cfg)
+{
+ annotate = new AnnotateView(partConfig, this);
+ setMainWidget(annotate);
+
+ setHelp("annotate");
+
+ setWFlags(Qt::WDestructiveClose | getWFlags());
+
+ QSize size = configDialogSize(partConfig, "AnnotateDialog");
+ resize(size);
+}
+
+
+AnnotateDialog::~AnnotateDialog()
+{
+ saveDialogSize(partConfig, "AnnotateDialog");
+}
+
+
+void AnnotateDialog::addLine(const Cervisia::LogInfo& logInfo,
+ const QString& content, bool odd)
+{
+ annotate->addLine(logInfo, content, odd);
+}
+
+
+// Local Variables:
+// c-basic-offset: 4
+// End:
diff --git a/cervisia/annotatedlg.h b/cervisia/annotatedlg.h
new file mode 100644
index 00000000..48299cf3
--- /dev/null
+++ b/cervisia/annotatedlg.h
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 1999-2002 Bernd Gehrmann
+ * bernd@mail.berlios.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.
+ *
+ * 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, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+
+#ifndef ANNOTATEDLG_H
+#define ANNOTATEDLG_H
+
+
+#include <kdialogbase.h>
+
+
+class AnnotateView;
+class QDate;
+class KConfig;
+
+namespace Cervisia
+{
+struct LogInfo;
+}
+
+
+class AnnotateDialog : public KDialogBase
+{
+public:
+
+ explicit AnnotateDialog( KConfig& cfg, QWidget *parent=0, const char *name=0 );
+
+ virtual ~AnnotateDialog();
+
+ void addLine(const Cervisia::LogInfo& logInfo, const QString& content,
+ bool odd);
+
+private:
+ AnnotateView *annotate;
+ KConfig& partConfig;
+};
+
+#endif
+
+
+// Local Variables:
+// c-basic-offset: 4
+// End:
diff --git a/cervisia/annotateview.cpp b/cervisia/annotateview.cpp
new file mode 100644
index 00000000..594ca936
--- /dev/null
+++ b/cervisia/annotateview.cpp
@@ -0,0 +1,206 @@
+/*
+ * Copyright (C) 1999-2002 Bernd Gehrmann <bernd@mail.berlios.de>
+ * Copyright (c) 2003-2007 André Wöbbeking <Woebbeking@kde.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the 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, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#include "annotateview.h"
+
+#include <qheader.h>
+#include <qpainter.h>
+#include <kconfig.h>
+#include <kglobalsettings.h>
+
+#include "loginfo.h"
+#include "tooltip.h"
+
+
+using namespace Cervisia;
+
+
+class AnnotateViewItem : public QListViewItem
+{
+public:
+ enum { LineNumberColumn, AuthorColumn, ContentColumn };
+
+ AnnotateViewItem(AnnotateView *parent, const LogInfo& logInfo,
+ const QString &content, bool odd, int linenumber);
+
+ virtual int compare(QListViewItem *item, int col, bool ascending) const;
+ virtual int width(const QFontMetrics &, const QListView *, int col) const;
+ virtual QString text(int col) const;
+ virtual void paintCell(QPainter *, const QColorGroup &, int, int, int);
+
+private:
+ LogInfo m_logInfo;
+ QString m_content;
+ bool m_odd;
+ int m_lineNumber;
+ friend class AnnotateView;
+
+ static const int BORDER;
+};
+
+
+const int AnnotateViewItem::BORDER = 4;
+
+
+AnnotateViewItem::AnnotateViewItem(AnnotateView *parent, const LogInfo& logInfo,
+ const QString &content, bool odd, int linenumber)
+ : QListViewItem(parent)
+ , m_logInfo(logInfo)
+ , m_content(content)
+ , m_odd(odd)
+ , m_lineNumber(linenumber)
+{}
+
+
+int AnnotateViewItem::compare(QListViewItem *item, int, bool) const
+{
+ int linenum1 = m_lineNumber;
+ int linenum2 = static_cast<AnnotateViewItem*>(item)->m_lineNumber;
+
+ return (linenum2 > linenum1)? -1 : (linenum2 < linenum1)? 1 : 0;
+}
+
+
+QString AnnotateViewItem::text(int col) const
+{
+ switch (col)
+ {
+ case LineNumberColumn:
+ return QString::number(m_lineNumber);
+ case AuthorColumn:
+ if( m_logInfo.m_author.isNull() )
+ return QString::null;
+ else
+ return (m_logInfo.m_author + QChar(' ') + m_logInfo.m_revision);
+ case ContentColumn:
+ return m_content;
+ default:
+ ;
+ };
+
+ return QString::null;
+}
+
+
+void AnnotateViewItem::paintCell(QPainter *p, const QColorGroup &, int col, int width, int align)
+{
+ QColor backgroundColor;
+
+ switch (col)
+ {
+ case LineNumberColumn:
+ backgroundColor = KGlobalSettings::highlightColor();
+ p->setPen(KGlobalSettings::highlightedTextColor());
+ break;
+ default:
+ backgroundColor = m_odd ? KGlobalSettings::baseColor()
+ : KGlobalSettings::alternateBackgroundColor();
+ p->setPen(KGlobalSettings::textColor());
+ break;
+ };
+
+ p->fillRect(0, 0, width, height(), backgroundColor);
+
+ QString str = text(col);
+ if (str.isEmpty())
+ return;
+
+ if (align & (AlignTop || AlignBottom) == 0)
+ align |= AlignVCenter;
+
+ p->drawText(BORDER, 0, width - 2*BORDER, height(), align, str);
+}
+
+
+
+int AnnotateViewItem::width(const QFontMetrics &fm, const QListView *, int col) const
+{
+ return fm.width(text(col)) + 2*BORDER;
+}
+
+
+/*!
+ @todo The dummy column (remaining space eater) doesn't work
+ caused by a bug in QHeader::adjustHeaderSize() in Qt <= 3.0.4.
+*/
+
+AnnotateView::AnnotateView(KConfig &cfg, QWidget *parent, const char *name)
+ : QListView(parent, name, WRepaintNoErase | WResizeNoErase)
+{
+ setFrameStyle(QFrame::WinPanel | QFrame::Sunken);
+ setAllColumnsShowFocus(true);
+ setShowToolTips(false);
+ setSelectionMode(NoSelection);
+ header()->hide();
+ // setResizeMode(LastColumn);
+
+ addColumn(QString::null);
+ addColumn(QString::null);
+ addColumn(QString::null);
+
+ setSorting(AnnotateViewItem::LineNumberColumn);
+ setColumnAlignment(AnnotateViewItem::LineNumberColumn, Qt::AlignRight);
+
+ ToolTip* toolTip = new ToolTip(viewport());
+
+ connect(toolTip, SIGNAL(queryToolTip(const QPoint&, QRect&, QString&)),
+ this, SLOT(slotQueryToolTip(const QPoint&, QRect&, QString&)));
+
+ KConfigGroupSaver cs(&cfg, "LookAndFeel");
+ setFont(cfg.readFontEntry("AnnotateFont"));
+}
+
+
+
+void AnnotateView::addLine(const LogInfo& logInfo, const QString& content,
+ bool odd)
+{
+ new AnnotateViewItem(this, logInfo, content, odd, childCount()+1);
+}
+
+
+QSize AnnotateView::sizeHint() const
+{
+ QFontMetrics fm(fontMetrics());
+ return QSize(100 * fm.width("0"), 10 * fm.lineSpacing());
+}
+
+
+void AnnotateView::slotQueryToolTip(const QPoint& viewportPos,
+ QRect& viewportRect,
+ QString& text)
+{
+ if (const AnnotateViewItem* item = static_cast<AnnotateViewItem*>(itemAt(viewportPos)))
+ {
+ const int column(header()->sectionAt(viewportPos.x()));
+ if ((column == AnnotateViewItem::AuthorColumn) && !item->m_logInfo.m_author.isNull())
+ {
+ viewportRect = itemRect(item);
+ text = item->m_logInfo.createToolTipText(false);
+ }
+ }
+}
+
+
+#include "annotateview.moc"
+
+
+// Local Variables:
+// c-basic-offset: 4
+// End:
diff --git a/cervisia/annotateview.h b/cervisia/annotateview.h
new file mode 100644
index 00000000..be74d430
--- /dev/null
+++ b/cervisia/annotateview.h
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 1999-2002 Bernd Gehrmann <bernd@mail.berlios.de>
+ * Copyright (c) 2003-2007 André Wöbbeking <Woebbeking@kde.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the 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, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+
+#ifndef ANNOTATEVIEW_H
+#define ANNOTATEVIEW_H
+
+
+#include <qlistview.h>
+
+
+class KConfig;
+
+
+namespace Cervisia
+{
+struct LogInfo;
+}
+
+
+class AnnotateView : public QListView
+{
+ Q_OBJECT
+
+public:
+
+ explicit AnnotateView( KConfig &cfg, QWidget *parent=0, const char *name=0 );
+
+ void addLine(const Cervisia::LogInfo& logInfo, const QString& content,
+ bool odd);
+
+ virtual QSize sizeHint() const;
+
+private slots:
+
+ void slotQueryToolTip(const QPoint&, QRect&, QString&);
+};
+
+
+#endif
diff --git a/cervisia/cervisia-change_repos_list.pl b/cervisia/cervisia-change_repos_list.pl
new file mode 100644
index 00000000..925c49ee
--- /dev/null
+++ b/cervisia/cervisia-change_repos_list.pl
@@ -0,0 +1,59 @@
+#!/usr/bin/perl
+
+# (copied from kdesdk/cervisia/misc.cpp)
+# These regular expression parts aren't useful to check the validity of the
+# CVSROOT specification. They are just used to extract the different parts of it.
+$usernamerx = "([a-z0-9_][a-z0-9_-]*)?";
+$passwordrx = "(:[^@]+)?";
+$hostrx = "([^:/]+)";
+$portrx = "(:(\\d*))?";
+$pathrx = "(/.*)";
+
+# concat above regexps into a single expression
+$regexp = join('', ":pserver:(", $usernamerx, $passwordrx, "@)?", $hostrx, $portrx, $pathrx);
+
+$loginuser = getlogin || getpwuid($<);
+
+while(<>)
+{
+ ($key) = ($_ =~ /([^=]*)=(.*)$/);
+ ($value) = ($_ =~ /^[^=]*=(.*)$/);
+
+ if( $key eq "Repos" )
+ {
+ @repos = split(',', $value);
+
+ foreach $repo ( @repos )
+ {
+ # pserver CVSROOT specification?
+ if( $repo =~ m/($regexp)/ )
+ {
+ # extract username, hostname, port and path from CVSROOT
+ $username = $3;
+ $hostname = $5;
+ $port = $7;
+ $path = $8;
+
+ # replace empty port number
+ $port =~ s/^$/2401/;
+
+ # replace empty username
+ $username =~ s/^$/$loginuser/;
+
+ # create normalized CVSROOT specification
+ $repo = join('', ":pserver:", $username, "@", $hostname, ":", $port, $path);
+ }
+ }
+
+ # remove duplicates from array
+ %seen = ();
+ @repos = grep { ! $seen{$_} ++ } @repos;
+
+ $value = join(',', @repos);
+ print "# DELETE " . $key . "\n";
+ print $key . "=" . $value . "\n";
+ next;
+ }
+
+ print $_;
+}
diff --git a/cervisia/cervisia-normalize_cvsroot.pl b/cervisia/cervisia-normalize_cvsroot.pl
new file mode 100644
index 00000000..8a96dcb8
--- /dev/null
+++ b/cervisia/cervisia-normalize_cvsroot.pl
@@ -0,0 +1,53 @@
+#!/usr/bin/perl
+
+# (copied from kdesdk/cervisia/misc.cpp)
+# These regular expression parts aren't useful to check the validity of the
+# CVSROOT specification. They are just used to extract the different parts of it.
+$usernamerx = "([a-z0-9_][a-z0-9_-]*)?";
+$passwordrx = "(:[^@]+)?";
+$hostrx = "([^:/]+)";
+$portrx = "(:(\\d*))?";
+$pathrx = "(/.*)";
+
+# concat above regexps into a single expression
+$regexp = join('', ":pserver:(", $usernamerx, $passwordrx, "@)?", $hostrx, $portrx, $pathrx);
+
+$loginuser = getlogin || getpwuid($<);
+
+while(<>)
+{
+ # skip empty lines
+ next if /^$/;
+
+ # config group for a repository?
+ if( /^\[Repository-(.+)\]$/ )
+ {
+ $oldcvsroot = $1;
+
+ # pserver CVSROOT specification?
+ if( $oldcvsroot =~ m/($regexp)/ )
+ {
+ # extract username, hostname, port and path from CVSROOT
+ $username = $3;
+ $hostname = $5;
+ $port = $7;
+ $path = $8;
+
+ # replace empty port number
+ $port =~ s/^$/2401/;
+
+ # replace empty username
+ $username =~ s/^$/$loginuser/;
+
+ # create normalized CVSROOT specification
+ $newcvsroot = join('', ":pserver:", $username, "@", $hostname, ":", $port, $path);
+
+ print "# DELETEGROUP [Repository-$oldcvsroot]\n";
+ print "[Repository-$newcvsroot]\n";
+ }
+
+ next;
+ }
+
+ print $_;
+}
diff --git a/cervisia/cervisia.1.in b/cervisia/cervisia.1.in
new file mode 100644
index 00000000..b810f98c
--- /dev/null
+++ b/cervisia/cervisia.1.in
@@ -0,0 +1,217 @@
+.\" Automatically generated by Pod::Man v1.37, Pod::Parser v1.3
+.\"
+.\" Standard preamble:
+.\" ========================================================================
+.de Sh \" Subsection heading
+.br
+.if t .Sp
+.ne 5
+.PP
+\fB\\$1\fR
+.PP
+..
+.de Sp \" Vertical space (when we can't use .PP)
+.if t .sp .5v
+.if n .sp
+..
+.de Vb \" Begin verbatim text
+.ft CW
+.nf
+.ne \\$1
+..
+.de Ve \" End verbatim text
+.ft R
+.fi
+..
+.\" Set up some character translations and predefined strings. \*(-- will
+.\" give an unbreakable dash, \*(PI will give pi, \*(L" will give a left
+.\" double quote, and \*(R" will give a right double quote. | will give a
+.\" real vertical bar. \*(C+ will give a nicer C++. Capital omega is used to
+.\" do unbreakable dashes and therefore won't be available. \*(C` and \*(C'
+.\" expand to `' in nroff, nothing in troff, for use with C<>.
+.tr \(*W-|\(bv\*(Tr
+.ds C+ C\v'-.1v'\h'-1p'\s-2+\h'-1p'+\s0\v'.1v'\h'-1p'
+.ie n \{\
+. ds -- \(*W-
+. ds PI pi
+. if (\n(.H=4u)&(1m=24u) .ds -- \(*W\h'-12u'\(*W\h'-12u'-\" diablo 10 pitch
+. if (\n(.H=4u)&(1m=20u) .ds -- \(*W\h'-12u'\(*W\h'-8u'-\" diablo 12 pitch
+. ds L" ""
+. ds R" ""
+. ds C` ""
+. ds C' ""
+'br\}
+.el\{\
+. ds -- \|\(em\|
+. ds PI \(*p
+. ds L" ``
+. ds R" ''
+'br\}
+.\"
+.\" If the F register is turned on, we'll generate index entries on stderr for
+.\" titles (.TH), headers (.SH), subsections (.Sh), items (.Ip), and index
+.\" entries marked with X<> in POD. Of course, you'll have to process the
+.\" output yourself in some meaningful fashion.
+.if \nF \{\
+. de IX
+. tm Index:\\$1\t\\n%\t"\\$2"
+..
+. nr % 0
+. rr F
+.\}
+.\"
+.\" For nroff, turn off justification. Always turn off hyphenation; it makes
+.\" way too many mistakes in technical documents.
+.hy 0
+.if n .na
+.\"
+.\" Accent mark definitions (@(#)ms.acc 1.5 88/02/08 SMI; from UCB 4.2).
+.\" Fear. Run. Save yourself. No user-serviceable parts.
+. \" fudge factors for nroff and troff
+.if n \{\
+. ds #H 0
+. ds #V .8m
+. ds #F .3m
+. ds #[ \f1
+. ds #] \fP
+.\}
+.if t \{\
+. ds #H ((1u-(\\\\n(.fu%2u))*.13m)
+. ds #V .6m
+. ds #F 0
+. ds #[ \&
+. ds #] \&
+.\}
+. \" simple accents for nroff and troff
+.if n \{\
+. ds ' \&
+. ds ` \&
+. ds ^ \&
+. ds , \&
+. ds ~ ~
+. ds /
+.\}
+.if t \{\
+. ds ' \\k:\h'-(\\n(.wu*8/10-\*(#H)'\'\h"|\\n:u"
+. ds ` \\k:\h'-(\\n(.wu*8/10-\*(#H)'\`\h'|\\n:u'
+. ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'^\h'|\\n:u'
+. ds , \\k:\h'-(\\n(.wu*8/10)',\h'|\\n:u'
+. ds ~ \\k:\h'-(\\n(.wu-\*(#H-.1m)'~\h'|\\n:u'
+. ds / \\k:\h'-(\\n(.wu*8/10-\*(#H)'\z\(sl\h'|\\n:u'
+.\}
+. \" troff and (daisy-wheel) nroff accents
+.ds : \\k:\h'-(\\n(.wu*8/10-\*(#H+.1m+\*(#F)'\v'-\*(#V'\z.\h'.2m+\*(#F'.\h'|\\n:u'\v'\*(#V'
+.ds 8 \h'\*(#H'\(*b\h'-\*(#H'
+.ds o \\k:\h'-(\\n(.wu+\w'\(de'u-\*(#H)/2u'\v'-.3n'\*(#[\z\(de\v'.3n'\h'|\\n:u'\*(#]
+.ds d- \h'\*(#H'\(pd\h'-\w'~'u'\v'-.25m'\f2\(hy\fP\v'.25m'\h'-\*(#H'
+.ds D- D\\k:\h'-\w'D'u'\v'-.11m'\z\(hy\v'.11m'\h'|\\n:u'
+.ds th \*(#[\v'.3m'\s+1I\s-1\v'-.3m'\h'-(\w'I'u*2/3)'\s-1o\s+1\*(#]
+.ds Th \*(#[\s+2I\s-2\h'-\w'I'u*3/5'\v'-.3m'o\v'.3m'\*(#]
+.ds ae a\h'-(\w'a'u*4/10)'e
+.ds Ae A\h'-(\w'A'u*4/10)'E
+. \" corrections for vroff
+.if v .ds ~ \\k:\h'-(\\n(.wu*9/10-\*(#H)'\s-2\u~\d\s+2\h'|\\n:u'
+.if v .ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'\v'-.4m'^\v'.4m'\h'|\\n:u'
+. \" for low resolution devices (crt and lpr)
+.if \n(.H>23 .if \n(.V>19 \
+\{\
+. ds : e
+. ds 8 ss
+. ds o a
+. ds d- d\h'-1'\(ga
+. ds D- D\h'-1'\(hy
+. ds th \o'bp'
+. ds Th \o'LP'
+. ds ae ae
+. ds Ae AE
+.\}
+.rm #[ #] #H #V #F C
+.\" ========================================================================
+.\"
+.IX Title "CERVISIA 1"
+.TH CERVISIA 1 "2006-01-05" "2.4.0" "Cervisia"
+.SH "NAME"
+Cervisia \- Graphical CVS frontend
+.SH "SYNOPSIS"
+.IX Header "SYNOPSIS"
+\&\fBcervisia\fR
+ [\ \fB\-\-display\fR\ \fIdisplay\fR\ ]
+ [\ \fB\-\-caption\fR\ \fIcaption\fR\ ]
+ [\ \fB\-\-icon\fR\ \fIicon\fR\ ]
+ [\ \fB\-\-miniicon\fR\ \fIminiicon\fR\ ]
+ [\ \fB\-\-config\fR\ \fIfilename\fR\ ]
+ [\ \fB\-\-dcopserver\fR\ \fIserver\fR\ ]
+ [\ \fB\-\-nocrashhandler\fR\ ]
+ [\ \fB\-\-waitforwm\fR\ ]
+ [\ \fB\-\-style\fR\ \fIstyle\fR\ ]
+ [\ \fB\-\-geometry\fR\ \fIgeometry\fR\ ]
+ [\ \fB\-\-resolve\fR\ \fIfilename\fR\ ]
+ [\ \fB\-\-log\fR\ \fIfilename\fR\ ]
+ [\ \fB\-\-annotate\fR\ \fIfilename\fR\ ]
+ [\ \fIdirectory\fR\ ]
+.SH "DESCRIPTION"
+.IX Header "DESCRIPTION"
+Cervisia is a graphical user interface for the Concurrent Versions
+System. It is based on the \s-1KDE\s0 libraries and therefore shares
+their Look'n'Feel, configuration and help system.
+.SH "OPTIONS"
+.IX Header "OPTIONS"
+Cervisia accepts the following options:
+.IP "\fIdirectory\fR" 4
+.IX Item "directory"
+Tells Cervisia to open the sandbox in \fIdirectory\fR at startup
+.IP "\fB\-\-resolve\fR \fIfilename\fR" 4
+.IX Item "--resolve filename"
+Shows a resolve dialog for the given file
+.IP "\fB\-\-log\fR \fIfilename\fR" 4
+.IX Item "--log filename"
+Shows a log dialog for the given file
+.IP "\fB\-\-annotate\fR \fIfilename\fR" 4
+.IX Item "--annotate filename"
+Shows a annotation dialog for the given file
+.IP "\fB\-\-caption\fR \fIcaption\fR" 4
+.IX Item "--caption caption"
+Sets the caption, i. e. what is shown in the title bar
+.IP "\fB\-\-icon\fR \fIicon\fR" 4
+.IX Item "--icon icon"
+Sets the program's icon (used by window managers and panels)
+.IP "\fB\-\-miniicon\fR \fIminiicon\fR" 4
+.IX Item "--miniicon miniicon"
+Sets the program's mini icon (used by window managers and panels)
+.IP "\fB\-\-config\fR \fIfilename\fR" 4
+.IX Item "--config filename"
+Uses the given file for the configuration
+.IP "\fB\-\-dcopserver\fR \fIserver\fR" 4
+.IX Item "--dcopserver server"
+Sets the dcopserver the program should use
+.IP "\fB\-\-nocrashhandler\fR" 4
+.IX Item "--nocrashhandler"
+Disables the crash handler. Use this to get core dumps
+.IP "\fB\-\-waitforwm\fR" 4
+.IX Item "--waitforwm"
+Waits for a \s-1WM_NET\s0 compatible windowmanager
+.IP "\fB\-\-style\fR \fIstyle\fR" 4
+.IX Item "--style style"
+Sets the application \s-1GUI\s0 style
+.IP "\fB\-\-geometry\fR \fIgeometry\fR" 4
+.IX Item "--geometry geometry"
+Sets the geometry of the main window
+.SH "FILES"
+.IX Header "FILES"
+\&\fI_KDECONFDIR_/cervisiarc\fR \- global configuration file
+.Sp
+\&\fI$HOME/.kde/share/config/cervisiarc\fR \- user-specific configuration file
+.SH "SEE ALSO"
+.IX Header "SEE ALSO"
+\&\fI_KDEHTMLDIR_/en/cervisia/index.html\fR
+.Sp
+\&\fIcvs\fR\|(1)
+.Sp
+\&\fIhttp://cervisia.kde.org/\fR
+.SH "AUTHOR"
+.IX Header "AUTHOR"
+Cervisia was originally developed by Bernd Gehrmann and is now maintained by
+Christian Loose <christian.loose@kdemail.net>.
+.SH "REPORTING BUGS"
+.IX Header "REPORTING BUGS"
+Report bugs at http://bugs.kde.org.
diff --git a/cervisia/cervisia.desktop b/cervisia/cervisia.desktop
new file mode 100644
index 00000000..b8745e0f
--- /dev/null
+++ b/cervisia/cervisia.desktop
@@ -0,0 +1,74 @@
+[Desktop Entry]
+GenericName=CVS Frontend
+GenericName[af]=Cvs Voorprogram
+GenericName[az]=CVS Ara Üzü
+GenericName[bg]=Програма за CVS
+GenericName[ca]=Programa de CVS
+GenericName[cs]=Rozhraní pro CVS
+GenericName[cy]=Ochr Blaen CVS
+GenericName[da]=CVS-grænseflade
+GenericName[de]=Graphische Oberfläche für CVS
+GenericName[eo]=Fasado por la versioadministrilo "CVS"
+GenericName[es]=Interfaz CVS
+GenericName[et]=CVSi kasutajaliides
+GenericName[eu]=CVS interfazea
+GenericName[fa]=پایانۀ CVS
+GenericName[fi]=Käyttöliittymä CVS:lle
+GenericName[fr]=Interface graphique pour CVS
+GenericName[ga]=Comhéadan ar CVS
+GenericName[gl]=Interface para CVS
+GenericName[he]=ממשק CVS
+GenericName[hi]=सीवीà¤à¤¸ फà¥à¤°à¤¨à¥à¤Ÿà¤à¤£à¥à¤¡
+GenericName[hr]=CVS suÄelje
+GenericName[hu]=CVS-kliens
+GenericName[is]=Myndrænt viðmót á CVS
+GenericName[it]=Interfaccia CVS
+GenericName[ja]=CVS フロントエンド
+GenericName[kk]=CVS интерфейÑÑ–
+GenericName[lt]=CVS naudotojo sÄ…saja
+GenericName[lv]=CVS Frontends
+GenericName[ms]=Bahagian Depan CVS
+GenericName[nb]=CVS-grensesnitt
+GenericName[nds]=CVS-Böversiet
+GenericName[ne]=CVS फà¥à¤°à¤¨à¥à¤Ÿà¤‡à¤¨à¥à¤¡
+GenericName[nl]=CVS-hulpprogramma
+GenericName[nn]=CVS-grensesnitt
+GenericName[pa]=CVS ਮà©à©±à¨– à¨à¨²à¨•
+GenericName[pl]=Interfejs do CVS
+GenericName[pt]=Interface de CVS
+GenericName[pt_BR]=Interface para o CVS
+GenericName[ro]=Interfaţă grafică pentru CVS
+GenericName[ru]=Работа Ñ Ñ€ÐµÐ¿Ð¾Ð·Ð¸Ñ‚Ð¾Ñ€Ð¸Ñми CVS
+GenericName[sk]=Rozhranie pre CVS
+GenericName[sl]=Vmesnik CVS
+GenericName[sr]=Графички Ð¸Ð½Ñ‚ÐµÑ€Ñ„ÐµÑ˜Ñ Ð·Ð° CVS
+GenericName[sr@Latn]=GrafiÄki interfejs za CVS
+GenericName[sv]=CVS-gränssnitt
+GenericName[ta]=CVS à®®à¯à®©à¯à®ªà®•à¯à®¤à®¿
+GenericName[tg]=Ð˜Ð½Ñ‚ÐµÑ€Ñ„ÐµÐ¹Ñ Ð±Ð° CVS
+GenericName[th]=ฟร้อนต์เอนด์ CVS
+GenericName[tr]=CVS Önyüzü
+GenericName[uk]=Ð†Ð½Ñ‚ÐµÑ€Ñ„ÐµÐ¹Ñ Ð´Ð¾ CVS
+GenericName[ven]=CVS yo iswa phanda
+GenericName[xh]=CVS Isiqalo sesiphelo
+GenericName[zh_CN]=CVS å‰ç«¯
+GenericName[zh_TW]=CVS å‰ç«¯
+GenericName[zu]=CVSIsiqalo sokugcina
+Exec=cervisia -caption "%c" %i %m %u
+Path=
+Icon=cervisia
+DocPath=cervisia/index.html
+Type=Application
+Terminal=false
+MimeType=inode/directory;
+Name=Cervisia
+Name[hi]=सरà¥à¤µà¤¿à¤¸à¤¿à¤¯à¤¾
+Name[pa]=ਸਰਵੀਸੀਆ
+Name[ta]= செரà¯à®µà®¿à®¯à®¾
+Name[th]=เซอร์วิเซีย
+ServiceTypes=KParts/ReadOnlyPart,Browser/View
+X-KDE-Library=libcervisiapart
+X-KDE-BrowserView-Args=DetailedList
+
+X-DCOP-ServiceType=Multi
+Categories=Qt;KDE;Development;
diff --git a/cervisia/cervisia.pod b/cervisia/cervisia.pod
new file mode 100644
index 00000000..940ba8e0
--- /dev/null
+++ b/cervisia/cervisia.pod
@@ -0,0 +1,109 @@
+=head1 NAME
+
+Cervisia - Graphical CVS frontend
+
+=head1 SYNOPSIS
+
+B<cervisia>
+ S<[ B<--display> I<display> ]>
+ S<[ B<--caption> I<caption> ]>
+ S<[ B<--icon> I<icon> ]>
+ S<[ B<--miniicon> I<miniicon> ]>
+ S<[ B<--config> I<filename> ]>
+ S<[ B<--dcopserver> I<server> ]>
+ S<[ B<--nocrashhandler> ]>
+ S<[ B<--waitforwm> ]>
+ S<[ B<--style> I<style> ]>
+ S<[ B<--geometry> I<geometry> ]>
+ S<[ B<--resolve> I<filename> ]>
+ S<[ B<--log> I<filename> ]>
+ S<[ B<--annotate> I<filename> ]>
+ S<[ I<directory> ]>
+
+=head1 DESCRIPTION
+
+Cervisia is a graphical user interface for the Concurrent Versions
+System. It is based on the KDE libraries and therefore shares
+their Look'n'Feel, configuration and help system.
+
+=head1 OPTIONS
+
+Cervisia accepts the following options:
+
+=over
+
+=item I<directory>
+
+Tells Cervisia to open the sandbox in I<directory> at startup
+
+=item B<--resolve> I<filename>
+
+Shows a resolve dialog for the given file
+
+=item B<--log> I<filename>
+
+Shows a log dialog for the given file
+
+=item B<--annotate> I<filename>
+
+Shows a annotation dialog for the given file
+
+=item B<--caption> I<caption>
+
+Sets the caption, i. e. what is shown in the title bar
+
+=item B<--icon> I<icon>
+
+Sets the program's icon (used by window managers and panels)
+
+=item B<--miniicon> I<miniicon>
+
+Sets the program's mini icon (used by window managers and panels)
+
+=item B<--config> I<filename>
+
+Uses the given file for the configuration
+
+=item B<--dcopserver> I<server>
+
+Sets the dcopserver the program should use
+
+=item B<--nocrashhandler>
+
+Disables the crash handler. Use this to get core dumps
+
+=item B<--waitforwm>
+
+Waits for a WM_NET compatible windowmanager
+
+=item B<--style> I<style>
+
+Sets the application GUI style
+
+=item B<--geometry> I<geometry>
+
+Sets the geometry of the main window
+
+=head1 FILES
+
+F<_KDECONFDIR_/cervisiarc> - global configuration file
+
+F<$HOME/.kde/share/config/cervisiarc> - user-specific configuration file
+
+
+=head1 SEE ALSO
+
+F<_KDEHTMLDIR_/en/cervisia/index.html>
+
+L<cvs(1)>
+
+F<http://cervisia.kde.org/>
+
+=head1 AUTHOR
+
+Cervisia was originally developed by Bernd Gehrmann and is now maintained by
+Christian Loose <christian.loose@kdemail.net>.
+
+=head1 REPORTING BUGS
+
+Report bugs at http://bugs.kde.org.
diff --git a/cervisia/cervisia.upd b/cervisia/cervisia.upd
new file mode 100644
index 00000000..9c635ea1
--- /dev/null
+++ b/cervisia/cervisia.upd
@@ -0,0 +1,92 @@
+#
+Id=kde3.2/20021228
+File=cervisiapartrc,cvsservicerc
+Group=General
+Options=copy
+Key=CVSPath
+Options=copy
+Key=Compression
+#
+Id=kde3.2/20021229
+File=cervisiapartrc,cvsservicerc
+Script=move_repositories.pl,perl
+#
+Id=kde3.2/20030116
+File=cervisiapartrc
+RemoveGroup=Main window
+File=cervisiarc
+RemoveGroup=Main window
+#
+Id=kde3.2/20030117
+File=cervisiapartrc,cervisiarc
+Group=Session
+Key=Current Directory
+#
+Id=kde3.2/20030118
+File=cervisiapartrc
+RemoveGroup=Annotate dialog
+File=cervisiapartrc
+Group=LogList view
+Key=Columns,ColumnOrder
+Key=ColumnSizes,ColumnWidths
+RemoveKey=Customized
+#
+Id=kde3.2/20030205
+File=cervisiapartrc
+Group=Log dialog,LogDialog
+Key=ShowListTab
+RemoveGroup=Log dialog
+#
+Id=kde3.2/20030210
+File=cervisiapartrc
+RemoveGroup=ChangeLog dialog
+#
+Id=kde3.2/20030211
+File=cervisiapartrc
+Group=Diff dialog,DiffDialog
+Key=Sync
+RemoveGroup=Diff dialog
+#
+Id=kde3.2/20030212
+File=cervisiapartrc
+RemoveGroup=Commit dialog
+RemoveGroup=History dialog
+RemoveGroup=Resolve dialog
+RemoveGroup=Resolve edit dialog
+#
+Id=kde3.2/20030216
+File=cervisiapartrc
+RemoveGroup=AddRepository dialog
+RemoveGroup=Repository dialog
+Group=Checkout dialog,CheckoutDialog
+AllKeys
+#
+Id=kde3.2/20030725
+File=cervisiapartrc
+Group=LogDialog
+RemoveKey=ShowListTab
+#
+Id=kde3.2/20030730
+File=cervisiapartrc
+Group=Colors
+Script=change_colors.pl,perl
+#
+Id=kde3.2/20030829
+File=cervisiapartrc
+Group=Communication
+RemoveKey=Editor
+#
+Id=kde3.2/20031014
+File=cervisiapartrc
+Group=General
+RemoveKey=CVSPath
+RemoveKey=Compression
+#
+Id=kde3.4/20041112
+File=cvsservicerc
+Script=cervisia-normalize_cvsroot.pl,perl
+#
+Id=kde3.4/20041207
+File=cervisiapartrc
+Group=Repositories
+Script=cervisia-change_repos_list.pl,perl
diff --git a/cervisia/cervisiapart.cpp b/cervisia/cervisiapart.cpp
new file mode 100644
index 00000000..56b37ece
--- /dev/null
+++ b/cervisia/cervisiapart.cpp
@@ -0,0 +1,1939 @@
+/*
+ * Copyright (C) 1999-2002 Bernd Gehrmann
+ * bernd@mail.berlios.de
+ * Copyright (c) 2002-2006 Christian Loose <christian.loose@kdemail.net>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the 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, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#include <qlabel.h>
+#include <qmessagebox.h>
+#include <qpushbutton.h>
+#include <qpopupmenu.h>
+#include <qtextstream.h>
+#include <qtooltip.h>
+#include <kaboutdata.h>
+#include <kaction.h>
+#include <kapplication.h>
+#include <kfiledialog.h>
+#include <kinputdialog.h>
+#include <kinstance.h>
+#include <klocale.h>
+#include <knotifyclient.h>
+#include <kprocess.h>
+#include <kpropertiesdialog.h>
+#include <kstatusbar.h>
+#include <kstdaction.h>
+#include <kxmlguifactory.h>
+#include <krun.h>
+#include <kdebug.h>
+#include <kmessagebox.h>
+#include <kglobal.h>
+#include <kio/netaccess.h>
+
+#include "progressdlg.h"
+#include "logdlg.h"
+#include "diffdlg.h"
+#include "resolvedlg.h"
+#include "annotatedlg.h"
+#include "annotatectl.h"
+#include "commitdlg.h"
+#include "updatedlg.h"
+#include "checkoutdlg.h"
+#include "tagdlg.h"
+#include "mergedlg.h"
+#include "historydlg.h"
+#include "updateview.h"
+#include "updateview_items.h"
+#include "protocolview.h"
+#include "repositorydlg.h"
+#include "settingsdlg.h"
+#include "changelogdlg.h"
+#include "watchersdlg.h"
+#include "cvsinitdlg.h"
+#include "misc.h"
+#include "cvsservice_stub.h"
+#include "repository_stub.h"
+#include "globalignorelist.h"
+#include "patchoptiondlg.h"
+#include "editwithmenu.h"
+
+#include "cervisiapart.h"
+#include "version.h"
+#include "cervisiapart.moc"
+
+using Cervisia::TagDialog;
+
+#define COMMIT_SPLIT_CHAR '\r'
+
+K_EXPORT_COMPONENT_FACTORY( libcervisiapart, CervisiaFactory )
+
+CervisiaPart::CervisiaPart( QWidget *parentWidget, const char *widgetName,
+ QObject *parent, const char *name, const QStringList& /*args*/ )
+ : KParts::ReadOnlyPart( parent, name )
+ , hasRunningJob( false )
+ , opt_hideFiles( false )
+ , opt_hideUpToDate( false )
+ , opt_hideRemoved( false )
+ , opt_hideNotInCVS( false )
+ , opt_hideEmptyDirectories( false )
+ , opt_createDirs( false )
+ , opt_pruneDirs( false )
+ , opt_updateRecursive( true )
+ , opt_commitRecursive( true )
+ , opt_doCVSEdit( false )
+ , recent( 0 )
+ , cvsService( 0 )
+ , m_statusBar(new KParts::StatusBarExtension(this))
+ , m_browserExt( 0 )
+ , filterLabel( 0 )
+ , m_editWithId(0)
+ , m_currentEditMenu(0)
+ , m_jobType(Unknown)
+{
+ KGlobal::locale()->insertCatalogue("cervisia");
+
+ setInstance( CervisiaFactory::instance() );
+ m_browserExt = new CervisiaBrowserExtension( this );
+
+ // start the cvs DCOP service
+ QString error;
+ QCString appId;
+ if( KApplication::startServiceByDesktopName("cvsservice", QStringList(), &error, &appId) )
+ {
+ KMessageBox::sorry(0, i18n("Starting cvsservice failed with message: ") +
+ error, "Cervisia");
+ }
+ else
+ // create a reference to the service
+ cvsService = new CvsService_stub(appId, "CvsService");
+
+ // Create UI
+ KConfig *conf = config();
+ conf->setGroup("LookAndFeel");
+ bool splitHorz = conf->readBoolEntry("SplitHorizontally",true);
+
+ // When we couldn't start the DCOP service, we just display a QLabel with
+ // an explaination
+ if( cvsService )
+ {
+ Orientation o = splitHorz ? QSplitter::Vertical
+ : QSplitter::Horizontal;
+ splitter = new QSplitter(o, parentWidget, widgetName);
+ // avoid PartManager's warning that Part's window can't handle focus
+ splitter->setFocusPolicy( QWidget::StrongFocus );
+
+ update = new UpdateView(*config(), splitter);
+ update->setFocusPolicy( QWidget::StrongFocus );
+ update->setFocus();
+ connect( update, SIGNAL(contextMenu(KListView*, QListViewItem*, const QPoint&)),
+ this, SLOT(popupRequested(KListView*, QListViewItem*, const QPoint&)) );
+ connect( update, SIGNAL(fileOpened(QString)),
+ this, SLOT(openFile(QString)) );
+
+ protocol = new ProtocolView(appId, splitter);
+ protocol->setFocusPolicy( QWidget::StrongFocus );
+
+ setWidget(splitter);
+ }
+ else
+ setWidget(new QLabel(i18n("This KPart is non-functional, because the "
+ "cvs DCOP service could not be started."),
+ parentWidget));
+
+ if( cvsService )
+ {
+ setupActions();
+ readSettings();
+ connect( update, SIGNAL( selectionChanged() ), this, SLOT( updateActions() ) );
+ }
+
+ setXMLFile( "cervisiaui.rc" );
+
+ QTimer::singleShot(0, this, SLOT(slotSetupStatusBar()));
+}
+
+CervisiaPart::~CervisiaPart()
+{
+ // stop the cvs DCOP service and delete reference
+ if( cvsService )
+ cvsService->quit();
+ delete cvsService;
+
+ if( cvsService )
+ writeSettings();
+}
+
+KConfig *CervisiaPart::config()
+{
+ return CervisiaFactory::instance()->config();
+}
+
+bool CervisiaPart::openURL( const KURL &u )
+{
+ // support url protocols like system:// or home://
+ KURL url = KIO::NetAccess::mostLocalURL(u, widget());
+
+ // right now, we are unfortunately not network-aware
+ if( !url.isLocalFile() )
+ {
+ KMessageBox::sorry(widget(),
+ i18n("Remote CVS working folders are not "
+ "supported."),
+ "Cervisia");
+ return false;
+ }
+
+ if( hasRunningJob )
+ {
+ KMessageBox::sorry(widget(),
+ i18n("You cannot change to a different folder "
+ "while there is a running cvs job."),
+ "Cervisia");
+ return false;
+ }
+
+ return openSandbox( url.path() );
+}
+
+
+void CervisiaPart::slotSetupStatusBar()
+{
+ // create the active filter indicator and add it to the statusbar
+ filterLabel = new QLabel("UR", m_statusBar->statusBar());
+ filterLabel->setFixedSize(filterLabel->sizeHint());
+ filterLabel->setText("");
+ QToolTip::add(filterLabel,
+ i18n("F - All files are hidden, the tree shows only folders\n"
+ "N - All up-to-date files are hidden\n"
+ "R - All removed files are hidden"));
+ m_statusBar->addStatusBarItem(filterLabel, 0, true);
+}
+
+void CervisiaPart::setupActions()
+{
+ KAction *action;
+ QString hint;
+
+ actionCollection()->setHighlightingEnabled(true);
+
+ //
+ // File Menu
+ //
+ action = new KAction( i18n("O&pen Sandbox..."), "fileopen", CTRL+Key_O,
+ this, SLOT( slotOpenSandbox() ),
+ actionCollection(), "file_open" );
+ hint = i18n("Opens a CVS working folder in the main window");
+ action->setToolTip( hint );
+ action->setWhatsThis( hint );
+
+ recent = new KRecentFilesAction( i18n("Recent Sandboxes"), 0,
+ this, SLOT( openURL( const KURL & ) ),
+ actionCollection(), "file_open_recent" );
+
+ action = new KAction( i18n("&Insert ChangeLog Entry..."), 0,
+ this, SLOT( slotChangeLog() ),
+ actionCollection(), "insert_changelog_entry" );
+ hint = i18n("Inserts a new intro into the file ChangeLog in the toplevel folder");
+ action->setToolTip( hint );
+ action->setWhatsThis( hint );
+
+ action = new KAction( i18n("&Update"), "vcs_update", CTRL+Key_U,
+ this, SLOT( slotUpdate() ),
+ actionCollection(), "file_update" );
+ hint = i18n("Updates (cvs update) the selected files and folders");
+ action->setToolTip( hint );
+ action->setWhatsThis( hint );
+
+ action = new KAction( i18n("&Status"), "vcs_status", Key_F5,
+ this, SLOT( slotStatus() ),
+ actionCollection(), "file_status" );
+ hint = i18n("Updates the status (cvs -n update) of the selected files and folders");
+ action->setToolTip( hint );
+ action->setWhatsThis( hint );
+
+ action = new KAction( i18n("&Edit"), 0,
+ this, SLOT( slotOpen() ),
+ actionCollection(), "file_edit" );
+ hint = i18n("Opens the marked file for editing");
+ action->setToolTip( hint );
+ action->setWhatsThis( hint );
+
+ action = new KAction( i18n("Reso&lve..."), 0,
+ this, SLOT( slotResolve() ),
+ actionCollection(), "file_resolve" );
+ hint = i18n("Opens the resolve dialog with the selected file");
+ action->setToolTip( hint );
+ action->setWhatsThis( hint );
+
+ action = new KAction( i18n("&Commit..."), "vcs_commit", Key_NumberSign,
+ this, SLOT( slotCommit() ),
+ actionCollection(), "file_commit" );
+ hint = i18n("Commits the selected files");
+ action->setToolTip( hint );
+ action->setWhatsThis( hint );
+
+ action = new KAction( i18n("&Add to Repository..."), "vcs_add", Key_Insert,
+ this, SLOT( slotAdd() ),
+ actionCollection(), "file_add" );
+ hint = i18n("Adds (cvs add) the selected files to the repository");
+ action->setToolTip( hint );
+ action->setWhatsThis( hint );
+
+ action = new KAction( i18n("Add &Binary..."), 0,
+ this, SLOT( slotAddBinary() ),
+ actionCollection(), "file_add_binary" );
+ hint = i18n("Adds (cvs -kb add) the selected files as binaries to the repository");
+ action->setToolTip( hint );
+ action->setWhatsThis( hint );
+
+ action = new KAction( i18n("&Remove From Repository..."), "vcs_remove", Key_Delete,
+ this, SLOT( slotRemove() ),
+ actionCollection(), "file_remove" );
+ hint = i18n("Removes (cvs remove) the selected files from the repository");
+ action->setToolTip( hint );
+ action->setWhatsThis( hint );
+
+ action = new KAction( i18n("Rever&t"), 0,
+ this, SLOT( slotRevert() ),
+ actionCollection(), "file_revert_local_changes" );
+ hint = i18n("Reverts (cvs update -C) the selected files (only cvs 1.11)");
+ action->setToolTip( hint );
+ action->setWhatsThis( hint );
+
+ // context menu only
+ action = new KAction( i18n("&Properties"), 0,
+ this, SLOT( slotFileProperties() ),
+ actionCollection(), "file_properties" );
+
+ //
+ // View Menu
+ //
+ action = new KAction( i18n("Stop"), "stop", Key_Escape,
+ protocol, SLOT(cancelJob()),
+ actionCollection(), "stop_job" );
+ action->setEnabled( false );
+ hint = i18n("Stops any running sub-processes");
+ action->setToolTip( hint );
+ action->setWhatsThis( hint );
+
+
+ action = new KAction( i18n("Browse &Log..."), CTRL+Key_L,
+ this, SLOT(slotBrowseLog()),
+ actionCollection(), "view_log" );
+ hint = i18n("Shows the revision tree of the selected file");
+ action->setToolTip( hint );
+ action->setWhatsThis( hint );
+
+#if 0
+ action = new KAction( i18n("Browse Multi-File Log..."), 0,
+ this, SLOT(slotBrowseMultiLog()),
+ actionCollection() );
+#endif
+ action = new KAction( i18n("&Annotate..."), CTRL+Key_A,
+ this, SLOT(slotAnnotate()),
+ actionCollection(), "view_annotate" );
+ hint = i18n("Shows a blame-annotated view of the selected file");
+ action->setToolTip( hint );
+ action->setWhatsThis( hint );
+
+ action = new KAction( i18n("&Difference to Repository (BASE)..."), "vcs_diff", CTRL+Key_D,
+ this, SLOT(slotDiffBase()),
+ actionCollection(), "view_diff_base" );
+ hint = i18n("Shows the differences of the selected file to the checked out version (tag BASE)");
+ action->setToolTip( hint );
+ action->setWhatsThis( hint );
+
+ action = new KAction( i18n("Difference to Repository (HEAD)..."), "vcs_diff", CTRL+Key_H,
+ this, SLOT(slotDiffHead()),
+ actionCollection(), "view_diff_head" );
+ hint = i18n("Shows the differences of the selected file to the newest version in the repository (tag HEAD)");
+ action->setToolTip( hint );
+ action->setWhatsThis( hint );
+
+ action = new KAction( i18n("Last &Change..."), 0,
+ this, SLOT(slotLastChange()),
+ actionCollection(), "view_last_change" );
+ hint = i18n("Shows the differences between the last two revisions of the selected file");
+ action->setToolTip( hint );
+ action->setWhatsThis( hint );
+
+ action = new KAction( i18n("&History..."), 0,
+ this, SLOT(slotHistory()),
+ actionCollection(), "view_history" );
+ hint = i18n("Shows the CVS history as reported by the server");
+ action->setToolTip( hint );
+ action->setWhatsThis( hint );
+
+ action = new KAction( i18n("&Unfold File Tree"), 0,
+ this , SLOT(slotUnfoldTree()),
+ actionCollection(), "view_unfold_tree" );
+
+ hint = i18n("Opens all branches of the file tree");
+ action->setToolTip( hint );
+ action->setWhatsThis( hint );
+
+ action = new KAction( i18n("&Fold File Tree"), 0,
+ this, SLOT(slotFoldTree()),
+ actionCollection(), "view_fold_tree" );
+ hint = i18n("Closes all branches of the file tree");
+ action->setToolTip( hint );
+ action->setWhatsThis( hint );
+
+ //
+ // Advanced Menu
+ //
+ action = new KAction( i18n("&Tag/Branch..."), 0,
+ this, SLOT(slotCreateTag()),
+ actionCollection(), "create_tag" );
+ hint = i18n("Creates a tag or branch for the selected files");
+ action->setToolTip( hint );
+ action->setWhatsThis( hint );
+
+ action = new KAction( i18n("&Delete Tag..."), 0,
+ this, SLOT(slotDeleteTag()),
+ actionCollection(), "delete_tag" );
+ hint = i18n("Deletes a tag from the selected files");
+ action->setToolTip( hint );
+ action->setWhatsThis( hint );
+
+ action = new KAction( i18n("&Update to Tag/Date..."), 0,
+ this, SLOT(slotUpdateToTag()),
+ actionCollection(), "update_to_tag" );
+ hint = i18n("Updates the selected files to a given tag, branch or date");
+ action->setToolTip( hint );
+ action->setWhatsThis( hint );
+
+ action = new KAction( i18n("Update to &HEAD"), 0,
+ this, SLOT(slotUpdateToHead()),
+ actionCollection(), "update_to_head" );
+ hint = i18n("Updates the selected files to the HEAD revision");
+ action->setToolTip( hint );
+ action->setWhatsThis( hint );
+
+ action = new KAction( i18n("&Merge..."), 0,
+ this, SLOT(slotMerge()),
+ actionCollection(), "merge" );
+ hint = i18n("Merges a branch or a set of modifications into the selected files");
+ action->setToolTip( hint );
+ action->setWhatsThis( hint );
+
+ action = new KAction( i18n("&Add Watch..."), 0,
+ this, SLOT(slotAddWatch()),
+ actionCollection(), "add_watch" );
+ hint = i18n("Adds a watch for the selected files");
+ action->setToolTip( hint );
+ action->setWhatsThis( hint );
+
+ action = new KAction( i18n("&Remove Watch..."), 0,
+ this, SLOT(slotRemoveWatch()),
+ actionCollection(), "remove_watch" );
+ hint = i18n("Removes a watch from the selected files");
+ action->setToolTip( hint );
+ action->setWhatsThis( hint );
+
+ action = new KAction( i18n("Show &Watchers"), 0,
+ this, SLOT(slotShowWatchers()),
+ actionCollection(), "show_watchers" );
+ hint = i18n("Shows the watchers of the selected files");
+ action->setToolTip( hint );
+ action->setWhatsThis( hint );
+
+ action = new KAction( i18n("Ed&it Files"), 0,
+ this, SLOT(slotEdit()),
+ actionCollection(), "edit_files" );
+ hint = i18n("Edits (cvs edit) the selected files");
+ action->setToolTip( hint );
+ action->setWhatsThis( hint );
+
+ action = new KAction( i18n("U&nedit Files"), 0,
+ this, SLOT(slotUnedit()),
+ actionCollection(), "unedit_files" );
+ hint = i18n("Unedits (cvs unedit) the selected files");
+ action->setToolTip( hint );
+ action->setWhatsThis( hint );
+
+ action = new KAction( i18n("Show &Editors"), 0,
+ this, SLOT(slotShowEditors()),
+ actionCollection(), "show_editors" );
+ hint = i18n("Shows the editors of the selected files");
+ action->setToolTip( hint );
+ action->setWhatsThis( hint );
+
+ action = new KAction( i18n("&Lock Files"), 0,
+ this, SLOT(slotLock()),
+ actionCollection(), "lock_files" );
+ hint = i18n("Locks the selected files, so that others cannot modify them");
+ action->setToolTip( hint );
+ action->setWhatsThis( hint );
+
+ action = new KAction( i18n("Unl&ock Files"), 0,
+ this, SLOT(slotUnlock()),
+ actionCollection(), "unlock_files" );
+ hint = i18n("Unlocks the selected files");
+ action->setToolTip( hint );
+ action->setWhatsThis( hint );
+
+ action = new KAction( i18n("Create &Patch Against Repository..."), 0,
+ this, SLOT(slotMakePatch()),
+ actionCollection(), "make_patch" );
+ hint = i18n("Creates a patch from the modifications in your sandbox");
+ action->setToolTip( hint );
+ action->setWhatsThis( hint );
+
+ //
+ // Repository Menu
+ //
+ action = new KAction( i18n("&Create..."), 0,
+ this, SLOT(slotCreateRepository()),
+ actionCollection(), "repository_create" );
+
+ action = new KAction( i18n("&Checkout..."), 0,
+ this, SLOT(slotCheckout()),
+ actionCollection(), "repository_checkout" );
+ hint = i18n("Allows you to checkout a module from a repository");
+ action->setToolTip( hint );
+ action->setWhatsThis( hint );
+
+ action = new KAction( i18n("&Import..."), 0,
+ this, SLOT(slotImport()),
+ actionCollection(), "repository_import" );
+ hint = i18n("Allows you to import a module into a repository");
+ action->setToolTip( hint );
+ action->setWhatsThis( hint );
+
+ action = new KAction( i18n("&Repositories..."), 0,
+ this, SLOT(slotRepositories()),
+ actionCollection(), "show_repositories" );
+ hint = i18n("Configures a list of repositories you regularly use");
+ action->setToolTip( hint );
+ action->setWhatsThis( hint );
+
+ //
+ // Settings menu
+ //
+ KToggleAction* toggaction = new KToggleAction( i18n("Hide All &Files"), 0,
+ this, SLOT(slotHideFiles()),
+ actionCollection(), "settings_hide_files" );
+ toggaction->setCheckedState(i18n("Show All &Files"));
+ hint = i18n("Determines whether only folders are shown");
+ toggaction->setToolTip( hint );
+ toggaction->setWhatsThis( hint );
+
+ toggaction = new KToggleAction( i18n("Hide Unmodified Files"), 0,
+ this, SLOT(slotHideUpToDate()),
+ actionCollection(), "settings_hide_uptodate" );
+ toggaction->setCheckedState(i18n("Show Unmodified Files"));
+ hint = i18n("Determines whether files with status up-to-date or "
+ "unknown are hidden");
+ toggaction->setToolTip( hint );
+ toggaction->setWhatsThis( hint );
+
+ toggaction = new KToggleAction( i18n("Hide Removed Files"), 0,
+ this, SLOT(slotHideRemoved()),
+ actionCollection(), "settings_hide_removed" );
+ toggaction->setCheckedState(i18n("Show Removed Files"));
+ hint = i18n("Determines whether removed files are hidden");
+ toggaction->setToolTip( hint );
+ toggaction->setWhatsThis( hint );
+
+ toggaction = new KToggleAction( i18n("Hide Non-CVS Files"), 0,
+ this, SLOT(slotHideNotInCVS()),
+ actionCollection(), "settings_hide_notincvs" );
+ toggaction->setCheckedState(i18n("Show Non-CVS Files"));
+ hint = i18n("Determines whether files not in CVS are hidden");
+ toggaction->setToolTip( hint );
+ toggaction->setWhatsThis( hint );
+
+ toggaction = new KToggleAction( i18n("Hide Empty Folders"), 0,
+ this, SLOT(slotHideEmptyDirectories()),
+ actionCollection(), "settings_hide_empty_directories" );
+ toggaction->setCheckedState(i18n("Show Empty Folders"));
+ hint = i18n("Determines whether folders without visible entries are hidden");
+ toggaction->setToolTip( hint );
+ toggaction->setWhatsThis( hint );
+
+ action = new KToggleAction( i18n("Create &Folders on Update"), 0,
+ this, SLOT(slotCreateDirs()),
+ actionCollection(), "settings_create_dirs" );
+ hint = i18n("Determines whether updates create folders");
+ action->setToolTip( hint );
+ action->setWhatsThis( hint );
+
+ action = new KToggleAction( i18n("&Prune Empty Folders on Update"), 0,
+ this, SLOT(slotPruneDirs()),
+ actionCollection(), "settings_prune_dirs" );
+ hint = i18n("Determines whether updates remove empty folders");
+ action->setToolTip( hint );
+ action->setWhatsThis( hint );
+
+ action = new KToggleAction( i18n("&Update Recursively"), 0,
+ this, SLOT(slotUpdateRecursive()),
+ actionCollection(), "settings_update_recursively" );
+ hint = i18n("Determines whether updates are recursive");
+ action->setToolTip( hint );
+ action->setWhatsThis( hint );
+
+ action = new KToggleAction( i18n("C&ommit && Remove Recursively"), 0,
+ this, SLOT(slotCommitRecursive()),
+ actionCollection(), "settings_commit_recursively" );
+ hint = i18n("Determines whether commits and removes are recursive");
+ action->setToolTip( hint );
+ action->setWhatsThis( hint );
+
+ action = new KToggleAction( i18n("Do cvs &edit Automatically When Necessary"), 0,
+ this, SLOT(slotDoCVSEdit()),
+ actionCollection(), "settings_do_cvs_edit" );
+ hint = i18n("Determines whether automatic cvs editing is active");
+ action->setToolTip( hint );
+ action->setWhatsThis( hint );
+
+ action = new KAction( i18n("Configure Cervisia..."), "configure", 0,
+ this, SLOT(slotConfigure()),
+ actionCollection(), "configure_cervisia" );
+ hint = i18n("Allows you to configure the Cervisia KPart");
+ action->setToolTip( hint );
+ action->setWhatsThis( hint );
+
+ //
+ // Help Menu
+ //
+ action = KStdAction::help( this, SLOT(slotHelp()),
+ actionCollection() );
+
+ action = new KAction( i18n("CVS &Manual"), 0,
+ this, SLOT(slotCVSInfo()),
+ actionCollection(), "help_cvs_manual" );
+ hint = i18n("Opens the help browser with the CVS documentation");
+ action->setToolTip( hint );
+ action->setWhatsThis( hint );
+
+ //
+ // Folder context menu
+ //
+ toggaction = new KToggleAction( i18n("Unfold Folder"), 0,
+ this, SLOT( slotUnfoldFolder() ),
+ actionCollection(), "unfold_folder" );
+ toggaction->setCheckedState(i18n("Fold Folder"));
+
+ //action = KStdAction::aboutApp( this, SLOT(aboutCervisia()),
+ // actionCollection(), "help_about_cervisia" );
+}
+
+
+void CervisiaPart::popupRequested(KListView*, QListViewItem* item, const QPoint& p)
+{
+ QString xmlName = "context_popup";
+
+ if( isDirItem(item) && update->fileSelection().isEmpty() )
+ {
+ xmlName = "folder_context_popup";
+ KToggleAction* action = static_cast<KToggleAction*>(actionCollection()->action("unfold_folder"));
+ action->setChecked(item->isOpen());
+ }
+
+ if( QPopupMenu* popup = static_cast<QPopupMenu*>(hostContainer(xmlName)) )
+ {
+ if( isFileItem(item) )
+ {
+ // remove old 'Edit with...' menu
+ if( m_editWithId && popup->findItem(m_editWithId) != 0 )
+ {
+ popup->removeItem(m_editWithId);
+ delete m_currentEditMenu;
+
+ m_editWithId = 0;
+ m_currentEditMenu = 0;
+ }
+
+ // get name of selected file
+ QString selectedFile;
+ update->getSingleSelection(&selectedFile);
+
+ if( !selectedFile.isEmpty() )
+ {
+ KURL u;
+ u.setPath(sandbox + "/" + selectedFile);
+
+ m_currentEditMenu = new Cervisia::EditWithMenu(u, popup);
+
+ if( m_currentEditMenu->menu() )
+ m_editWithId = popup->insertItem(i18n("Edit With"),
+ m_currentEditMenu->menu(), -1, 1);
+ }
+ }
+
+ popup->exec(p);
+ }
+ else
+ kdDebug(8050) << "CervisiaPart: can't get XML definition for " << xmlName << ", factory()=" << factory() << endl;
+}
+
+void CervisiaPart::updateActions()
+{
+ bool hassandbox = !sandbox.isEmpty();
+ stateChanged("has_sandbox", hassandbox ? StateNoReverse : StateReverse);
+
+ bool single = update->hasSingleSelection();
+ stateChanged("has_single_selection", single ? StateNoReverse
+ : StateReverse);
+
+ bool singleFolder = (update->multipleSelection().count() == 1);
+ stateChanged("has_single_folder", singleFolder ? StateNoReverse
+ : StateReverse);
+
+ m_browserExt->setPropertiesActionEnabled(single);
+
+ // bool nojob = !( actionCollection()->action( "stop_job" )->isEnabled() );
+ bool selected = (update->currentItem() != 0);
+ bool nojob = !hasRunningJob && selected;
+
+ stateChanged("item_selected", selected ? StateNoReverse : StateReverse);
+ stateChanged("has_no_job", nojob ? StateNoReverse : StateReverse);
+ stateChanged("has_running_job", hasRunningJob ? StateNoReverse
+ : StateReverse);
+
+}
+
+
+void CervisiaPart::aboutCervisia()
+{
+ QString aboutstr(i18n("Cervisia %1\n"
+ "(Using KDE %2)\n"
+ "\n"
+ "Copyright (c) 1999-2002\n"
+ "Bernd Gehrmann <bernd@mail.berlios.de>\n"
+ "\n"
+ "This program is free software; you can redistribute it and/or modify\n"
+ "it under the terms of the GNU General Public License as published by\n"
+ "the Free Software Foundation; either version 2 of the License, or\n"
+ "(at your option) any later version.\n"
+ "This program is distributed in the hope that it will be useful,\n"
+ "but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
+ "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n"
+ "GNU General Public License for more details.\n"
+ "See the ChangeLog file for a list of contributors."));
+ QMessageBox::about(0, i18n("About Cervisia"),
+ aboutstr.arg(CERVISIA_VERSION).arg(KDE_VERSION_STRING));
+}
+
+
+KAboutData* CervisiaPart::createAboutData()
+{
+ KAboutData* about = new KAboutData(
+ "cervisiapart", I18N_NOOP("Cervisia Part"),
+ CERVISIA_VERSION, I18N_NOOP("A CVS frontend"),
+ KAboutData::License_GPL,
+ I18N_NOOP("Copyright (c) 1999-2002 Bernd Gehrmann"), 0,
+ "http://www.kde.org/apps/cervisia");
+
+ about->addAuthor("Bernd Gehrmann", I18N_NOOP("Original author and former "
+ "maintainer"), "bernd@mail.berlios.de", 0);
+ about->addAuthor("Christian Loose", I18N_NOOP("Maintainer"),
+ "christian.loose@hamburg.de", 0);
+ about->addAuthor("Andr\303\251 W\303\266bbeking", I18N_NOOP("Developer"),
+ "woebbeking@web.de", 0);
+
+ about->addCredit("Richard Moore", I18N_NOOP("Conversion to KPart"),
+ "rich@kde.org", 0);
+
+ return about;
+}
+
+
+void CervisiaPart::slotOpenSandbox()
+{
+ QString dirname = KFileDialog::getExistingDirectory(":CervisiaPart", widget(),
+ i18n("Open Sandbox"));
+ if (dirname.isEmpty())
+ return;
+
+ openSandbox(dirname);
+}
+
+
+void CervisiaPart::slotChangeLog()
+{
+ // Modal dialog
+ ChangeLogDialog dlg(*config(), widget());
+ if (dlg.readFile(sandbox + "/ChangeLog"))
+ {
+ if (dlg.exec())
+ changelogstr = dlg.message();
+ }
+}
+
+
+void CervisiaPart::slotOpen()
+{
+ QStringList filenames = update->fileSelection();
+ if (filenames.isEmpty())
+ return;
+ openFiles(filenames);
+}
+
+
+void CervisiaPart::openFile(QString filename)
+{
+ QStringList files;
+ files << filename;
+ openFiles(files);
+}
+
+
+void CervisiaPart::openFiles(const QStringList &filenames)
+{
+ // call cvs edit automatically?
+ if( opt_doCVSEdit )
+ {
+ QStringList files;
+
+ // only edit read-only files
+ QStringList::ConstIterator it = filenames.begin();
+ QStringList::ConstIterator end = filenames.end();
+ for( ; it != end; ++it )
+ {
+ if( !QFileInfo(*it).isWritable() )
+ files << *it;
+ }
+
+ if( files.count() )
+ {
+ DCOPRef job = cvsService->edit(files);
+
+ ProgressDialog dlg(widget(), "Edit", job, "edit", i18n("CVS Edit"));
+ if( !dlg.execute() )
+ return;
+ }
+ }
+
+ // Now open the files by using KRun
+ QDir dir(sandbox);
+
+ QStringList::ConstIterator it = filenames.begin();
+ QStringList::ConstIterator end = filenames.end();
+ for( ; it != end; ++it )
+ {
+ KURL u;
+ u.setPath(dir.absFilePath(*it));
+ KRun* run = new KRun(u, 0, true, false);
+ run->setRunExecutables(false);
+ }
+}
+
+
+void CervisiaPart::slotResolve()
+{
+ QString filename;
+ update->getSingleSelection(&filename);
+ if (filename.isEmpty())
+ return;
+
+ // Non-modal dialog
+ ResolveDialog *l = new ResolveDialog(*config());
+ if (l->parseFile(filename))
+ l->show();
+ else
+ delete l;
+}
+
+
+void CervisiaPart::slotUpdate()
+{
+ updateSandbox();
+}
+
+
+void CervisiaPart::slotStatus()
+{
+ QStringList list = update->multipleSelection();
+ if (list.isEmpty())
+ return;
+
+ // Bug #105097: Embedded in Konqueror, all Cervisia tabs share
+ // a common current directory. This confuses UpdateView. That's
+ // why we always change the current directory here.
+ QDir::setCurrent(sandbox);
+
+ update->prepareJob(opt_updateRecursive, UpdateView::UpdateNoAct);
+
+ DCOPRef cvsJob = cvsService->simulateUpdate(list, opt_updateRecursive,
+ opt_createDirs, opt_pruneDirs);
+
+ // get command line from cvs job
+ QString cmdline;
+ DCOPReply reply = cvsJob.call("cvsCommand()");
+ if( reply.isValid() )
+ reply.get<QString>(cmdline);
+
+ if( protocol->startJob(true) )
+ {
+ showJobStart(cmdline);
+ connect( protocol, SIGNAL(receivedLine(QString)), update, SLOT(processUpdateLine(QString)) );
+ connect( protocol, SIGNAL(jobFinished(bool, int)), update, SLOT(finishJob(bool, int)) );
+ connect( protocol, SIGNAL(jobFinished(bool, int)), this, SLOT(slotJobFinished()) );
+ }
+}
+
+
+void CervisiaPart::slotUpdateToTag()
+{
+ UpdateDialog *l = new UpdateDialog(cvsService, widget() );
+
+ if (l->exec())
+ {
+ QString tagopt;
+ if (l->byTag())
+ {
+ tagopt = "-r ";
+ tagopt += l->tag();
+ }
+ else
+ {
+ tagopt = "-D ";
+ tagopt += KProcess::quote(l->date());
+ }
+ tagopt += " ";
+ updateSandbox(tagopt);
+ }
+ delete l;
+}
+
+
+void CervisiaPart::slotUpdateToHead()
+{
+ updateSandbox("-A");
+}
+
+
+void CervisiaPart::slotRevert()
+{
+ updateSandbox("-C");
+}
+
+
+void CervisiaPart::slotMerge()
+{
+ MergeDialog dlg(cvsService, widget());
+
+ if (dlg.exec())
+ {
+ QString tagopt;
+ if (dlg.byBranch())
+ {
+ tagopt = "-j ";
+ tagopt += dlg.branch();
+ }
+ else
+ {
+ tagopt = "-j ";
+ tagopt += dlg.tag1();
+ tagopt += " -j ";
+ tagopt += dlg.tag2();
+ }
+ tagopt += " ";
+ updateSandbox(tagopt);
+ }
+}
+
+
+void CervisiaPart::slotCommit()
+{
+ QStringList list = update->multipleSelection();
+ if (list.isEmpty())
+ return;
+
+ // modal dialog
+ CommitDialog dlg(*config(), cvsService, widget());
+ dlg.setLogMessage(changelogstr);
+ dlg.setLogHistory(recentCommits);
+ dlg.setFileList(list);
+
+ if (dlg.exec())
+ {
+ // get new list of files
+ list = dlg.fileList();
+ if( list.isEmpty() )
+ return;
+
+ QString msg = dlg.logMessage();
+ if( !recentCommits.contains( msg ) )
+ {
+ recentCommits.prepend( msg );
+ while (recentCommits.count() > 50)
+ recentCommits.remove( recentCommits.last() );
+
+ KConfig* conf = config();
+ conf->setGroup( "CommitLogs" );
+ conf->writeEntry( sandbox, recentCommits, COMMIT_SPLIT_CHAR );
+ }
+
+ update->prepareJob(opt_commitRecursive, UpdateView::Commit);
+
+ DCOPRef cvsJob = cvsService->commit(list, dlg.logMessage(),
+ opt_commitRecursive);
+
+ // get command line from cvs job
+ QString cmdline = cvsJob.call("cvsCommand()");
+
+ if( protocol->startJob() )
+ {
+ m_jobType = Commit;
+ showJobStart(cmdline);
+ connect( protocol, SIGNAL(jobFinished(bool, int)), update, SLOT(finishJob(bool, int)) );
+ connect( protocol, SIGNAL(jobFinished(bool, int)), this, SLOT(slotJobFinished()) );
+ }
+ }
+}
+
+
+void CervisiaPart::slotAdd()
+{
+ addOrRemove(AddRemoveDialog::Add);
+}
+
+
+void CervisiaPart::slotAddBinary()
+{
+ addOrRemove(AddRemoveDialog::AddBinary);
+}
+
+
+void CervisiaPart::slotRemove()
+{
+ addOrRemove(AddRemoveDialog::Remove);
+}
+
+
+void CervisiaPart::slotFileProperties()
+{
+ QString filename;
+ update->getSingleSelection(&filename);
+ if( filename.isEmpty() )
+ return;
+
+ // Create URL from selected filename
+ QDir dir(sandbox);
+
+ KURL u;
+ u.setPath(dir.absFilePath(filename));
+
+ // show file properties dialog
+ (void)new KPropertiesDialog(u);
+}
+
+
+void CervisiaPart::updateSandbox(const QString &extraopt)
+{
+ QStringList list = update->multipleSelection();
+ if (list.isEmpty())
+ return;
+
+ // Bug #105097: Embedded in Konqueror, all Cervisia tabs share
+ // a common current directory. This confuses UpdateView. That's
+ // why we always change the current directory here.
+ QDir::setCurrent(sandbox);
+
+ update->prepareJob(opt_updateRecursive, UpdateView::Update);
+
+ DCOPRef cvsJob = cvsService->update(list, opt_updateRecursive,
+ opt_createDirs, opt_pruneDirs, extraopt);
+
+ // get command line from cvs job
+ QString cmdline;
+ DCOPReply reply = cvsJob.call("cvsCommand()");
+ if( reply.isValid() )
+ reply.get<QString>(cmdline);
+
+ if( protocol->startJob(true) )
+ {
+ showJobStart(cmdline);
+ connect( protocol, SIGNAL(receivedLine(QString)), update, SLOT(processUpdateLine(QString)) );
+ connect( protocol, SIGNAL(jobFinished(bool, int)), update, SLOT(finishJob(bool, int)) );
+ connect( protocol, SIGNAL(jobFinished(bool, int)), this, SLOT(slotJobFinished()) );
+ }
+}
+
+
+void CervisiaPart::addOrRemove(AddRemoveDialog::ActionType action)
+{
+ QStringList list = update->multipleSelection();
+ if (list.isEmpty())
+ return;
+
+ // modal dialog
+ AddRemoveDialog dlg(action, widget());
+ dlg.setFileList(list);
+
+ if (dlg.exec())
+ {
+ DCOPRef cvsJob;
+
+ switch (action)
+ {
+ case AddRemoveDialog::Add:
+ update->prepareJob(false, UpdateView::Add);
+ cvsJob = cvsService->add(list, false);
+ break;
+
+ case AddRemoveDialog::AddBinary:
+ update->prepareJob(false, UpdateView::Add);
+ cvsJob = cvsService->add(list, true);
+ break;
+
+ case AddRemoveDialog::Remove:
+ update->prepareJob(opt_commitRecursive, UpdateView::Remove);
+ cvsJob = cvsService->remove(list, opt_commitRecursive);
+ break;
+ }
+
+ // get command line from cvs job
+ QString cmdline;
+ DCOPReply reply = cvsJob.call("cvsCommand()");
+ if( reply.isValid() )
+ reply.get<QString>(cmdline);
+
+ if (protocol->startJob())
+ {
+ showJobStart(cmdline);
+ connect( protocol, SIGNAL(jobFinished(bool, int)),
+ update, SLOT(finishJob(bool, int)) );
+ connect( protocol, SIGNAL(jobFinished(bool, int)),
+ this, SLOT(slotJobFinished()) );
+ }
+ }
+}
+
+void CervisiaPart::slotBrowseLog()
+{
+ QString filename;
+ update->getSingleSelection(&filename);
+ if (filename.isEmpty())
+ return;
+
+ // Non-modal dialog
+ LogDialog *l = new LogDialog(*CervisiaPart::config());
+ if (l->parseCvsLog(cvsService, filename))
+ l->show();
+ else
+ delete l;
+}
+
+
+#if 0
+void CervisiaPart::slotBrowseMultiLog()
+{
+ QStrList list = update->multipleSelection();
+ if (!list.isEmpty())
+ {
+ // Non-modal dialog
+ MultiLogDialog *l = new MultiLogDialog();
+ if (l->parseCvsLog(".", list))
+ l->show();
+ else
+ delete l;
+ }
+}
+#endif
+
+
+void CervisiaPart::slotAnnotate()
+{
+ QString filename;
+ update->getSingleSelection(&filename);
+
+ if (filename.isEmpty())
+ return;
+
+ // Non-modal dialog
+ AnnotateDialog* dlg = new AnnotateDialog(*config());
+ AnnotateController ctl(dlg, cvsService);
+ ctl.showDialog(filename);
+}
+
+
+void CervisiaPart::slotDiffBase()
+{
+ showDiff(QString::fromLatin1("BASE"));
+}
+
+
+void CervisiaPart::slotDiffHead()
+{
+ showDiff(QString::fromLatin1("HEAD"));
+}
+
+
+void CervisiaPart::slotAddWatch()
+{
+ addOrRemoveWatch(WatchDialog::Add);
+}
+
+
+void CervisiaPart::slotRemoveWatch()
+{
+ addOrRemoveWatch(WatchDialog::Remove);
+}
+
+
+void CervisiaPart::addOrRemoveWatch(WatchDialog::ActionType action)
+{
+ QStringList list = update->multipleSelection();
+ if (list.isEmpty())
+ return;
+
+ WatchDialog dlg(action, widget());
+
+ if (dlg.exec() && dlg.events() != WatchDialog::None)
+ {
+ DCOPRef cvsJob;
+
+ if (action == WatchDialog::Add)
+ cvsJob = cvsService->addWatch(list, dlg.events());
+ else
+ cvsJob = cvsService->removeWatch(list, dlg.events());
+
+ // get command line from cvs job
+ QString cmdline = cvsJob.call("cvsCommand()");
+
+ if( protocol->startJob() )
+ {
+ showJobStart(cmdline);
+ connect( protocol, SIGNAL(jobFinished(bool, int)),
+ this, SLOT(slotJobFinished()) );
+ }
+ }
+}
+
+
+void CervisiaPart::slotShowWatchers()
+{
+ QStringList list = update->multipleSelection();
+ if (list.isEmpty())
+ return;
+
+ // Non-modal dialog
+ WatchersDialog* dlg = new WatchersDialog(*config());
+ if( dlg->parseWatchers(cvsService, list) )
+ dlg->show();
+ else
+ delete dlg;
+}
+
+
+void CervisiaPart::slotEdit()
+{
+ QStringList list = update->multipleSelection();
+ if (list.isEmpty())
+ return;
+
+ DCOPRef cvsJob = cvsService->edit(list);
+
+ // get command line from cvs job
+ QString cmdline = cvsJob.call("cvsCommand()");
+
+ if( protocol->startJob() )
+ {
+ showJobStart(cmdline);
+ connect( protocol, SIGNAL(jobFinished(bool, int)),
+ this, SLOT(slotJobFinished()) );
+ }
+}
+
+
+void CervisiaPart::slotUnedit()
+{
+ QStringList list = update->multipleSelection();
+ if (list.isEmpty())
+ return;
+
+ DCOPRef cvsJob = cvsService->unedit(list);
+
+ // get command line from cvs job
+ QString cmdline = cvsJob.call("cvsCommand()");
+
+ if( protocol->startJob() )
+ {
+ showJobStart(cmdline);
+ connect( protocol, SIGNAL(jobFinished(bool, int)),
+ this, SLOT(slotJobFinished()) );
+ }
+}
+
+
+void CervisiaPart::slotLock()
+{
+ QStringList list = update->multipleSelection();
+ if (list.isEmpty())
+ return;
+
+ DCOPRef cvsJob = cvsService->lock(list);
+
+ // get command line from cvs job
+ QString cmdline = cvsJob.call("cvsCommand()");
+
+ if( protocol->startJob() )
+ {
+ showJobStart(cmdline);
+ connect( protocol, SIGNAL(jobFinished(bool, int)),
+ this, SLOT(slotJobFinished()) );
+ }
+}
+
+
+void CervisiaPart::slotUnlock()
+{
+ QStringList list = update->multipleSelection();
+ if (list.isEmpty())
+ return;
+
+ DCOPRef cvsJob = cvsService->unlock(list);
+
+ // get command line from cvs job
+ QString cmdline = cvsJob.call("cvsCommand()");
+
+ if( protocol->startJob() )
+ {
+ showJobStart(cmdline);
+ connect( protocol, SIGNAL(jobFinished(bool, int)),
+ this, SLOT(slotJobFinished()) );
+ }
+}
+
+
+void CervisiaPart::slotShowEditors()
+{
+ QStringList list = update->multipleSelection();
+ if (list.isEmpty())
+ return;
+
+ DCOPRef cvsJob = cvsService->editors(list);
+
+ // get command line from cvs job
+ QString cmdline = cvsJob.call("cvsCommand()");
+
+ if( protocol->startJob() )
+ {
+ showJobStart(cmdline);
+ connect( protocol, SIGNAL(jobFinished(bool, int)),
+ this, SLOT(slotJobFinished()) );
+ }
+}
+
+
+void CervisiaPart::slotMakePatch()
+{
+ Cervisia::PatchOptionDialog optionDlg;
+ if( optionDlg.exec() == KDialogBase::Rejected )
+ return;
+
+ QString format = optionDlg.formatOption();
+ QString diffOptions = optionDlg.diffOptions();
+
+ DCOPRef job = cvsService->makePatch(diffOptions, format);
+ if( !cvsService->ok() )
+ return;
+
+ ProgressDialog dlg(widget(), "Diff", job, "", i18n("CVS Diff"));
+ if( !dlg.execute() )
+ return;
+
+ QString fileName = KFileDialog::getSaveFileName();
+ if( fileName.isEmpty() )
+ return;
+
+ if( !Cervisia::CheckOverwrite(fileName) )
+ return;
+
+ QFile f(fileName);
+ if( !f.open(IO_WriteOnly) )
+ {
+ KMessageBox::sorry(widget(),
+ i18n("Could not open file for writing."),
+ "Cervisia");
+ return;
+ }
+
+ QTextStream t(&f);
+ QString line;
+ while( dlg.getLine(line) )
+ t << line << '\n';
+
+ f.close();
+}
+
+
+void CervisiaPart::slotImport()
+{
+ CheckoutDialog dlg(*config(), cvsService, CheckoutDialog::Import, widget());
+
+ if( !dlg.exec() )
+ return;
+
+ DCOPRef cvsJob = cvsService->import(dlg.workingDirectory(), dlg.repository(),
+ dlg.module(), dlg.ignoreFiles(),
+ dlg.comment(), dlg.vendorTag(),
+ dlg.releaseTag(), dlg.importBinary(),
+ dlg.useModificationTime());
+
+ // get command line from cvs job
+ QString cmdline = cvsJob.call("cvsCommand()");
+
+ if( protocol->startJob() )
+ {
+ showJobStart(cmdline);
+ connect( protocol, SIGNAL(jobFinished(bool, int)),
+ this, SLOT(slotJobFinished()) );
+ }
+}
+
+
+void CervisiaPart::slotCreateRepository()
+{
+ Cervisia::CvsInitDialog dlg(widget());
+
+ if( !dlg.exec() )
+ return;
+
+ DCOPRef cvsJob = cvsService->createRepository(dlg.directory());
+
+ QString cmdline = cvsJob.call("cvsCommand()");
+
+ if( protocol->startJob() )
+ {
+ showJobStart(cmdline);
+ connect( protocol, SIGNAL(jobFinished(bool, int)),
+ this, SLOT(slotJobFinished()) );
+ }
+}
+
+
+void CervisiaPart::slotCheckout()
+{
+ CheckoutDialog dlg(*config(), cvsService, CheckoutDialog::Checkout, widget());
+
+ if( !dlg.exec() )
+ return;
+
+ DCOPRef cvsJob = cvsService->checkout(dlg.workingDirectory(), dlg.repository(),
+ dlg.module(), dlg.branch(), opt_pruneDirs,
+ dlg.alias(), dlg.exportOnly(), dlg.recursive());
+
+ // get command line from cvs job
+ QString cmdline = cvsJob.call("cvsCommand()");
+
+ if( protocol->startJob() )
+ {
+ showJobStart(cmdline);
+ connect( protocol, SIGNAL(jobFinished(bool, int)),
+ this, SLOT(slotJobFinished()) );
+ }
+}
+
+
+void CervisiaPart::slotRepositories()
+{
+ RepositoryDialog *l = new RepositoryDialog(*config(), cvsService, widget());
+ l->show();
+}
+
+
+void CervisiaPart::slotCreateTag()
+{
+ createOrDeleteTag(TagDialog::Create);
+}
+
+
+void CervisiaPart::slotDeleteTag()
+{
+ createOrDeleteTag(TagDialog::Delete);
+}
+
+
+void CervisiaPart::createOrDeleteTag(TagDialog::ActionType action)
+{
+ QStringList list = update->multipleSelection();
+ if (list.isEmpty())
+ return;
+
+ TagDialog dlg(action, cvsService, widget());
+
+ if (dlg.exec())
+ {
+ DCOPRef cvsJob;
+
+ if( action == TagDialog::Create )
+ cvsJob = cvsService->createTag(list, dlg.tag(), dlg.branchTag(),
+ dlg.forceTag());
+ else
+ cvsJob = cvsService->deleteTag(list, dlg.tag(), dlg.branchTag(),
+ dlg.forceTag());
+
+ // get command line from cvs job
+ QString cmdline = cvsJob.call("cvsCommand()");
+
+ if( protocol->startJob() )
+ {
+ showJobStart(cmdline);
+ connect( protocol, SIGNAL(jobFinished(bool, int)),
+ this, SLOT(slotJobFinished()) );
+ }
+ }
+}
+
+
+
+void CervisiaPart::slotLastChange()
+{
+ QString filename, revA, revB;
+ update->getSingleSelection(&filename, &revA);
+ if (filename.isEmpty())
+ return;
+
+ int pos, lastnumber;
+ bool ok;
+ if ( (pos = revA.findRev('.')) == -1
+ || (lastnumber=revA.right(revA.length()-pos-1).toUInt(&ok), !ok) )
+ {
+ KMessageBox::sorry(widget(),
+ i18n("The revision looks invalid."),
+ "Cervisia");
+ return;
+ }
+ if (lastnumber == 0)
+ {
+ KMessageBox::sorry(widget(),
+ i18n("This is the first revision of the branch."),
+ "Cervisia");
+ return;
+ }
+ revB = revA.left(pos+1);
+ revB += QString::number(lastnumber-1);
+
+ // Non-modal dialog
+ DiffDialog *l = new DiffDialog(*config());
+ if (l->parseCvsDiff(cvsService, filename, revB, revA))
+ l->show();
+ else
+ delete l;
+}
+
+
+void CervisiaPart::slotHistory()
+{
+ // Non-modal dialog
+ HistoryDialog *l = new HistoryDialog(*config());
+ if (l->parseHistory(cvsService))
+ l->show();
+ else
+ delete l;
+}
+
+
+void CervisiaPart::slotHideFiles()
+{
+ opt_hideFiles = !opt_hideFiles;
+ setFilter();
+}
+
+
+void CervisiaPart::slotHideUpToDate()
+{
+ opt_hideUpToDate = !opt_hideUpToDate;
+ setFilter();
+}
+
+
+void CervisiaPart::slotHideRemoved()
+{
+ opt_hideRemoved = !opt_hideRemoved;
+ setFilter();
+}
+
+
+void CervisiaPart::slotHideNotInCVS()
+{
+ opt_hideNotInCVS = !opt_hideNotInCVS;
+ setFilter();
+}
+
+
+void CervisiaPart::slotHideEmptyDirectories()
+{
+ opt_hideEmptyDirectories = !opt_hideEmptyDirectories;
+ setFilter();
+}
+
+
+void CervisiaPart::slotFoldTree()
+{
+ update->foldTree();
+ setFilter();
+}
+
+void CervisiaPart::slotUnfoldTree()
+{
+ update->unfoldTree();
+ setFilter();
+}
+
+
+void CervisiaPart::slotUnfoldFolder()
+{
+ update->unfoldSelectedFolders();
+ setFilter();
+}
+
+
+void CervisiaPart::slotCreateDirs()
+{
+ opt_createDirs = !opt_createDirs;
+}
+
+
+void CervisiaPart::slotPruneDirs()
+{
+ opt_pruneDirs = !opt_pruneDirs;
+}
+
+
+void CervisiaPart::slotUpdateRecursive()
+{
+ opt_updateRecursive = !opt_updateRecursive;
+}
+
+
+void CervisiaPart::slotCommitRecursive()
+{
+ opt_commitRecursive = !opt_commitRecursive;
+}
+
+
+void CervisiaPart::slotDoCVSEdit()
+{
+ opt_doCVSEdit = !opt_doCVSEdit;
+}
+
+void CervisiaPart::slotConfigure()
+{
+ KConfig *conf = config();
+ SettingsDialog *l = new SettingsDialog( conf, widget() );
+ l->exec();
+
+ conf->setGroup("LookAndFeel");
+ bool splitHorz = conf->readBoolEntry("SplitHorizontally",true);
+ splitter->setOrientation( splitHorz ?
+ QSplitter::Vertical :
+ QSplitter::Horizontal);
+}
+
+void CervisiaPart::slotHelp()
+{
+ emit setStatusBarText( i18n("Invoking help on Cervisia") );
+ KApplication::startServiceByDesktopName("khelpcenter", QString("help:/cervisia/index.html"));
+}
+
+
+void CervisiaPart::slotCVSInfo()
+{
+ emit setStatusBarText( i18n("Invoking help on CVS") );
+ KApplication::startServiceByDesktopName("khelpcenter", QString("info:/cvs/Top"));
+}
+
+
+void CervisiaPart::showJobStart(const QString &cmdline)
+{
+ hasRunningJob = true;
+ actionCollection()->action( "stop_job" )->setEnabled( true );
+
+ emit setStatusBarText( cmdline );
+ updateActions();
+}
+
+
+void CervisiaPart::showDiff(const QString& revision)
+{
+ QString fileName;
+ update->getSingleSelection(&fileName);
+
+ if (fileName.isEmpty())
+ return;
+
+ // Non-modal dialog
+ DiffDialog *l = new DiffDialog(*config());
+ if (l->parseCvsDiff(cvsService, fileName, revision, QString::null))
+ l->show();
+ else
+ delete l;
+}
+
+
+void CervisiaPart::slotJobFinished()
+{
+ actionCollection()->action( "stop_job" )->setEnabled( false );
+ hasRunningJob = false;
+ emit setStatusBarText( i18n("Done") );
+ updateActions();
+
+ disconnect( protocol, SIGNAL(receivedLine(QString)),
+ update, SLOT(processUpdateLine(QString)) );
+
+ if( m_jobType == Commit )
+ {
+ KNotifyClient::event(widget()->parentWidget()->winId(), "cvs_commit_done",
+ i18n("A CVS commit to repository %1 is done")
+ .arg(repository));
+ m_jobType = Unknown;
+ }
+}
+
+
+bool CervisiaPart::openSandbox(const QString &dirname)
+{
+ // Do we have a cvs service?
+ if( !cvsService )
+ return false;
+
+ Repository_stub cvsRepository(cvsService->app(), "CvsRepository");
+
+ // change the working copy directory for the cvs DCOP service
+ bool opened = cvsRepository.setWorkingCopy(dirname);
+
+ if( !cvsRepository.ok() || !opened )
+ {
+ KMessageBox::sorry(widget(),
+ i18n("This is not a CVS folder.\n"
+ "If you did not intend to use Cervisia, you can "
+ "switch view modes within Konqueror."),
+ "Cervisia");
+
+ // remove path from recent sandbox menu
+ QFileInfo fi(dirname);
+ recent->removeURL( KURL::fromPathOrURL(fi.absFilePath()) );
+
+ return false;
+ }
+
+ changelogstr = "";
+ sandbox = "";
+ repository = "";
+
+ // get path of sandbox for recent sandbox menu
+ sandbox = cvsRepository.workingCopy();
+ recent->addURL( KURL::fromPathOrURL(sandbox) );
+
+ // get repository for the caption of the window
+ repository = cvsRepository.location();
+ emit setWindowCaption(sandbox + "(" + repository + ")");
+
+ // set m_url member for tabbed window modus of Konqueror
+ m_url = KURL::fromPathOrURL(sandbox);
+
+ // *NOTICE*
+ // The order is important here. We have to set the m_url member before
+ // calling this function because the progress dialog uses the enter_loop()/
+ // exit_loop() methods. Those methods result in a call to queryExit() in
+ // cervisiashell.cpp which then uses the m_url member to save the last used
+ // directory.
+ if( cvsRepository.retrieveCvsignoreFile() )
+ Cervisia::GlobalIgnoreList().retrieveServerIgnoreList(cvsService,
+ repository);
+
+ QDir::setCurrent(sandbox);
+ update->openDirectory(sandbox);
+ setFilter();
+
+ KConfig *conf = config();
+ conf->setGroup("General");
+ bool dostatus = conf->readBoolEntry(repository.contains(":")?
+ "StatusForRemoteRepos" :
+ "StatusForLocalRepos",
+ false);
+ if (dostatus)
+ {
+ update->setSelected(update->firstChild(), true);
+ slotStatus();
+ }
+
+ //load the recentCommits for this app from the KConfig app
+ conf->setGroup( "CommitLogs" );
+ recentCommits = conf->readListEntry( sandbox, COMMIT_SPLIT_CHAR );
+
+ return true;
+}
+
+
+void CervisiaPart::setFilter()
+{
+ UpdateView::Filter filter = UpdateView::Filter(0);
+ if (opt_hideFiles)
+ filter = UpdateView::Filter(filter | UpdateView::OnlyDirectories);
+ if (opt_hideUpToDate)
+ filter = UpdateView::Filter(filter | UpdateView::NoUpToDate);
+ if (opt_hideRemoved)
+ filter = UpdateView::Filter(filter | UpdateView::NoRemoved);
+ if (opt_hideNotInCVS)
+ filter = UpdateView::Filter(filter | UpdateView::NoNotInCVS);
+ if (opt_hideEmptyDirectories)
+ filter = UpdateView::Filter(filter | UpdateView::NoEmptyDirectories);
+ update->setFilter(filter);
+
+ QString str;
+ if (opt_hideFiles)
+ str = "F";
+ else
+ {
+ if (opt_hideUpToDate)
+ str += "N";
+ if (opt_hideRemoved)
+ str += "R";
+ }
+
+ if( filterLabel )
+ filterLabel->setText(str);
+}
+
+
+void CervisiaPart::readSettings()
+{
+ KConfig* config = CervisiaFactory::instance()->config();
+
+ config->setGroup("Session");
+ recent->loadEntries( config );
+
+ // Unfortunately, the KConfig systems sucks and we have to live
+ // with all entries in one group for session management.
+
+ opt_createDirs = config->readBoolEntry("Create Dirs", true);
+ (static_cast<KToggleAction *> (actionCollection()->action( "settings_create_dirs" )))
+ ->setChecked( opt_createDirs );
+
+ opt_pruneDirs = config->readBoolEntry("Prune Dirs", true);
+ (static_cast<KToggleAction *> (actionCollection()->action( "settings_prune_dirs" )))
+ ->setChecked( opt_pruneDirs );
+
+ opt_updateRecursive = config->readBoolEntry("Update Recursive", false);
+ (static_cast<KToggleAction *> (actionCollection()->action( "settings_update_recursively" )))
+ ->setChecked( opt_updateRecursive );
+
+ opt_commitRecursive = config->readBoolEntry("Commit Recursive", false);
+ (static_cast<KToggleAction *> (actionCollection()->action( "settings_commit_recursively" )))
+ ->setChecked( opt_commitRecursive );
+
+ opt_doCVSEdit = config->readBoolEntry("Do cvs edit", false);
+ (static_cast<KToggleAction *> (actionCollection()->action( "settings_do_cvs_edit" )))
+ ->setChecked( opt_doCVSEdit );
+
+ opt_hideFiles = config->readBoolEntry("Hide Files", false);
+ (static_cast<KToggleAction *> (actionCollection()->action( "settings_hide_files" )))
+ ->setChecked( opt_hideFiles );
+
+ opt_hideUpToDate = config->readBoolEntry("Hide UpToDate Files", false);
+ (static_cast<KToggleAction *> (actionCollection()->action( "settings_hide_uptodate" )))
+ ->setChecked( opt_hideUpToDate );
+
+ opt_hideRemoved = config->readBoolEntry("Hide Removed Files", false);
+ (static_cast<KToggleAction *> (actionCollection()->action( "settings_hide_removed" )))
+ ->setChecked( opt_hideRemoved );
+
+ opt_hideNotInCVS = config->readBoolEntry("Hide Non CVS Files", false);
+ (static_cast<KToggleAction *> (actionCollection()->action( "settings_hide_notincvs" )))
+ ->setChecked( opt_hideNotInCVS );
+
+ opt_hideEmptyDirectories = config->readBoolEntry("Hide Empty Directories", false);
+ (static_cast<KToggleAction *> (actionCollection()->action( "settings_hide_empty_directories" )))
+ ->setChecked( opt_hideEmptyDirectories );
+
+ setFilter();
+
+ int splitterpos1 = config->readNumEntry("Splitter Pos 1", 0);
+ int splitterpos2 = config->readNumEntry("Splitter Pos 2", 0);
+ if (splitterpos1)
+ {
+ QValueList<int> sizes;
+ sizes << splitterpos1;
+ sizes << splitterpos2;
+ splitter->setSizes(sizes);
+ }
+}
+
+
+void CervisiaPart::writeSettings()
+{
+ KConfig* config = CervisiaFactory::instance()->config();
+
+ config->setGroup("Session");
+ recent->saveEntries( config );
+
+ config->writeEntry("Create Dirs", opt_createDirs);
+ config->writeEntry("Prune Dirs", opt_pruneDirs);
+ config->writeEntry("Update Recursive", opt_updateRecursive);
+ config->writeEntry("Commit Recursive", opt_commitRecursive);
+ config->writeEntry("Do cvs edit", opt_doCVSEdit);
+ config->writeEntry("Hide Files", opt_hideFiles);
+ config->writeEntry("Hide UpToDate Files", opt_hideUpToDate);
+ config->writeEntry("Hide Removed Files", opt_hideRemoved);
+ config->writeEntry("Hide Non CVS Files", opt_hideNotInCVS);
+ config->writeEntry("Hide Empty Directories", opt_hideEmptyDirectories);
+ QValueList<int> sizes = splitter->sizes();
+ config->writeEntry("Splitter Pos 1", sizes[0]);
+ config->writeEntry("Splitter Pos 2", sizes[1]);
+
+ // write to disk
+ config->sync();
+}
+
+
+void CervisiaPart::guiActivateEvent(KParts::GUIActivateEvent* event)
+{
+ if( event->activated() && cvsService )
+ {
+ // initial setup of the menu items' state
+ updateActions();
+ }
+
+ // don't call this as it overwrites Konqueror's caption (if you have a
+ // Konqueror with more than one view and switch back to Cervisia)
+ //
+ // KParts::ReadOnlyPart::guiActivateEvent(event);
+}
+
+
+CervisiaBrowserExtension::CervisiaBrowserExtension( CervisiaPart *p )
+ : KParts::BrowserExtension( p, "CervisiaBrowserExtension" )
+{
+ KGlobal::locale()->insertCatalogue("cervisia");
+}
+
+CervisiaBrowserExtension::~CervisiaBrowserExtension()
+{
+
+}
+
+
+void CervisiaBrowserExtension::setPropertiesActionEnabled(bool enabled)
+{
+ emit enableAction("properties", enabled);
+}
+
+
+void CervisiaBrowserExtension::properties()
+{
+ static_cast<CervisiaPart*>(parent())->slotFileProperties();
+}
+
+// Local Variables:
+// c-basic-offset: 4
+// End:
diff --git a/cervisia/cervisiapart.h b/cervisia/cervisiapart.h
new file mode 100644
index 00000000..e5881a8d
--- /dev/null
+++ b/cervisia/cervisiapart.h
@@ -0,0 +1,219 @@
+/*
+ * Copyright (C) 1999-2002 Bernd Gehrmann
+ * bernd@mail.berlios.de
+ * Copyright (c) 2002-2005 Christian Loose <christian.loose@kdemail.net>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the 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, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+
+#ifndef CERVISIAPART_H
+#define CERVISIAPART_H
+
+#include <kparts/part.h>
+#include <kparts/browserextension.h>
+#include <kparts/genericfactory.h>
+#include <kparts/statusbarextension.h>
+
+#include "addremovedlg.h"
+#include "commitdlg.h"
+#include "checkoutdlg.h"
+#include "watchdlg.h"
+#include "tagdlg.h"
+
+namespace Cervisia { class EditWithMenu; }
+class QLabel;
+class QListViewItem;
+class QSplitter;
+class QTimer;
+class UpdateView;
+class ProtocolView;
+class KAboutData;
+class KListView;
+class KRecentFilesAction;
+class CvsService_stub;
+class CervisiaBrowserExtension;
+
+
+/**
+ * An embeddable Cervisia viewer.
+ */
+class CervisiaPart : public KParts::ReadOnlyPart
+{
+ Q_OBJECT
+
+public:
+ CervisiaPart( QWidget *parentWidget, const char *widgetName,
+ QObject *parent, const char *name=0, const QStringList& args = QStringList());
+ virtual ~CervisiaPart();
+
+ /**
+ * Get the config object for the part's instance.
+ */
+ static KConfig *config();
+
+ QString sandBox() const { return sandbox; }
+
+ static KAboutData* createAboutData();
+
+public slots:
+ // unused because we overwrite the default behaviour of openURL()
+ virtual bool openFile() { return true; }
+ virtual bool openURL( const KURL & );
+
+ void openFile(QString filename);
+ void openFiles(const QStringList &filenames);
+ void popupRequested(KListView*, QListViewItem*, const QPoint&);
+ void updateActions();
+
+ void aboutCervisia();
+
+ void slotOpen();
+ void slotResolve();
+ void slotStatus();
+ void slotUpdate();
+ void slotChangeLog();
+ void slotCommit();
+ void slotAdd();
+ void slotAddBinary();
+
+ void slotRemove();
+ void slotFileProperties();
+ void slotRevert();
+ void slotBrowseLog();
+ // void slotBrowseMultiLog();
+ void slotAnnotate();
+ void slotDiffBase();
+ void slotDiffHead();
+ void slotLastChange();
+ void slotHistory();
+ void slotCreateRepository();
+ void slotCheckout();
+ void slotImport();
+ void slotRepositories();
+ void slotCreateTag();
+ void slotDeleteTag();
+ void slotUpdateToTag();
+ void slotUpdateToHead();
+ void slotMerge();
+ void slotAddWatch();
+ void slotRemoveWatch();
+ void slotShowWatchers();
+ void slotEdit();
+ void slotUnedit();
+ void slotShowEditors();
+ void slotLock();
+ void slotUnlock();
+ void slotMakePatch();
+ void slotCreateDirs();
+ void slotPruneDirs();
+ void slotHideFiles();
+ void slotHideUpToDate();
+ void slotHideRemoved();
+
+ void slotHideNotInCVS();
+ void slotHideEmptyDirectories();
+
+ void slotFoldTree();
+ void slotUnfoldTree();
+ void slotUnfoldFolder();
+
+ void slotUpdateRecursive();
+ void slotCommitRecursive();
+ void slotDoCVSEdit();
+ void slotConfigure();
+ void slotHelp();
+ void slotCVSInfo();
+
+protected slots:
+ void slotJobFinished();
+
+private slots:
+ // called by menu action "Open Sandbox..."
+ void slotOpenSandbox();
+ void slotSetupStatusBar();
+
+protected:
+ virtual void guiActivateEvent(KParts::GUIActivateEvent* event);
+
+private:
+ enum JobType { Unknown, Commit };
+
+ void setupActions();
+
+ void readSettings();
+ void writeSettings();
+
+ bool openSandbox(const QString &dirname);
+ void updateSandbox(const QString &extraopt = QString::null);
+ void addOrRemove(AddRemoveDialog::ActionType action);
+ void addOrRemoveWatch(WatchDialog::ActionType action);
+ void createOrDeleteTag(Cervisia::TagDialog::ActionType action);
+ void showJobStart(const QString &command);
+ void showDiff(const QString& revision);
+ void setFilter();
+
+ UpdateView *update;
+ ProtocolView *protocol;
+ bool hasRunningJob;
+ QSplitter *splitter;
+
+ QString sandbox;
+ QString repository;
+
+ QString changelogstr;
+ QStringList recentCommits;
+ bool opt_hideFiles, opt_hideUpToDate, opt_hideRemoved, opt_hideNotInCVS, opt_hideEmptyDirectories;
+ bool opt_createDirs, opt_pruneDirs;
+ bool opt_updateRecursive, opt_commitRecursive, opt_doCVSEdit;
+
+ //for the Open Recent directories
+ KRecentFilesAction *recent;
+
+ CvsService_stub* cvsService;
+ KParts::StatusBarExtension* m_statusBar;
+ CervisiaBrowserExtension* m_browserExt;
+ QLabel* filterLabel;
+
+ int m_editWithId;
+ Cervisia::EditWithMenu* m_currentEditMenu;
+ JobType m_jobType;
+};
+
+typedef KParts::GenericFactory<CervisiaPart> CervisiaFactory;
+
+/**
+ * A mysterious class, needed to make Konqueror intrgration work.
+ */
+class CervisiaBrowserExtension : public KParts::BrowserExtension
+{
+ Q_OBJECT
+
+public:
+ CervisiaBrowserExtension( CervisiaPart * );
+ ~CervisiaBrowserExtension();
+
+ void setPropertiesActionEnabled(bool enabled);
+
+public slots:
+ void properties();
+};
+
+#endif // CERVISIAPART_H
+
+
+// Local Variables:
+// c-basic-offset: 4
+// End:
diff --git a/cervisia/cervisiapart.kcfg b/cervisia/cervisiapart.kcfg
new file mode 100644
index 00000000..6dea38cf
--- /dev/null
+++ b/cervisia/cervisiapart.kcfg
@@ -0,0 +1,37 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<kcfg xmlns="http://www.kde.org/standards/kcfg/1.0"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://www.kde.org/standards/kcfg/1.0
+ http://www.kde.org/standards/kcfg/1.0/kcfg.xsd" >
+ <kcfgfile name="cervisiapartrc" />
+ <group name="Colors" >
+ <entry name="DiffChangeColor" key="DiffChange" type="Color">
+ <default>#edbebe</default>
+ </entry>
+ <entry name="DiffDeleteColor" key="DiffDelete" type="Color">
+ <default>#beedbe</default>
+ </entry>
+ <entry name="DiffInsertColor" key="DiffInsert" type="Color">
+ <default>#bebeed</default>
+ </entry>
+ <entry name="LocalChangeColor" key="LocalChange" type="Color">
+ <default>#8282ff</default>
+ </entry>
+ <entry name="RemoteChangeColor" key="RemoteChange" type="Color">
+ <default>#46d246</default>
+ </entry>
+ <entry name="ConflictColor" key="Conflict" type="Color">
+ <label>The foreground color used to highlight files with a conflict in the file view.</label>
+ <default>#ff8282</default>
+ </entry>
+ <entry name="NotInCvsColor" key="NotInCvsColor" type="Color">
+ <default code="true">KGlobalSettings::textColor()</default>
+ </entry>
+ </group>
+ <group name="General" >
+ <entry key="Timeout" type="UInt">
+ <label>Delay (ms) until the progress dialog appears.</label>
+ <default>4000</default>
+ </entry>
+ </group>
+</kcfg>
diff --git a/cervisia/cervisiasettings.kcfgc b/cervisia/cervisiasettings.kcfgc
new file mode 100644
index 00000000..00c14ab5
--- /dev/null
+++ b/cervisia/cervisiasettings.kcfgc
@@ -0,0 +1,4 @@
+File=cervisiapart.kcfg
+ClassName=CervisiaSettings
+Singleton=true
+Mutators=true
diff --git a/cervisia/cervisiashell.cpp b/cervisia/cervisiashell.cpp
new file mode 100644
index 00000000..33dac96c
--- /dev/null
+++ b/cervisia/cervisiashell.cpp
@@ -0,0 +1,227 @@
+/*
+ * Copyright (C) 1999-2002 Bernd Gehrmann
+ * bernd@mail.berlios.de
+ * Copyright (c) 2002-2004 Christian Loose <christian.loose@kdemail.net>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the 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, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+
+#include "cervisiashell.h"
+
+#include <kapplication.h>
+#include <kconfig.h>
+#include <kedittoolbar.h>
+#include <khelpmenu.h>
+#include <kkeydialog.h>
+#include <klibloader.h>
+#include <klocale.h>
+#include <kmessagebox.h>
+#include <kstatusbar.h>
+#include <kstdaction.h>
+#include <kurl.h>
+
+
+CervisiaShell::CervisiaShell( const char *name )
+ : KParts::MainWindow( name )
+ , m_part(0)
+{
+ setXMLFile( "cervisiashellui.rc" );
+
+ KLibFactory* factory = KLibLoader::self()->factory("libcervisiapart");
+ if( factory )
+ {
+ m_part = static_cast<KParts::ReadOnlyPart*>(factory->create(this,
+ "cervisiaview", "KParts::ReadOnlyPart"));
+ if( m_part )
+ setCentralWidget(m_part->widget());
+ }
+ else
+ {
+ KMessageBox::detailedError(this, i18n("The Cervisia library could not be loaded."),
+ KLibLoader::self()->lastErrorMessage());
+ kapp->quit();
+ return;
+ }
+
+ setupActions();
+
+ //
+ // Magic needed for status texts
+ //
+ actionCollection()->setHighlightingEnabled(true);
+ connect( actionCollection(), SIGNAL( actionStatusText(const QString &) ),
+ statusBar(), SLOT( message(const QString &) ) );
+ connect( actionCollection(), SIGNAL( clearStatusText() ),
+ statusBar(), SLOT( clear() ) );
+ m_part->actionCollection()->setHighlightingEnabled(true);
+ connect( m_part->actionCollection(), SIGNAL( actionStatusText(const QString &) ),
+ statusBar(), SLOT( message(const QString &) ) );
+ connect( m_part->actionCollection(), SIGNAL( clearStatusText() ),
+ statusBar(), SLOT( clear() ) );
+
+ createGUI( m_part );
+
+ // enable auto-save of toolbar/menubar/statusbar and window size settings
+ // and apply the previously saved settings
+ setAutoSaveSettings("MainWindow", true);
+
+ // if the session is restoring, we already read the settings
+ if( !kapp->isRestored() )
+ readSettings();
+}
+
+CervisiaShell::~CervisiaShell()
+{
+ delete m_part;
+}
+
+void CervisiaShell::setupActions()
+{
+ setStandardToolBarMenuEnabled( true );
+
+ KAction *action = KStdAction::configureToolbars( this, SLOT(slotConfigureToolBars()),
+ actionCollection() );
+ QString hint = i18n("Allows you to configure the toolbar");
+ action->setToolTip( hint );
+ action->setWhatsThis( hint );
+
+ action = KStdAction::keyBindings( this, SLOT(slotConfigureKeys()),
+ actionCollection() );
+ hint = i18n("Allows you to customize the keybindings");
+ action->setToolTip( hint );
+ action->setWhatsThis( hint );
+
+ action = KStdAction::quit( kapp, SLOT( quit() ), actionCollection() );
+ hint = i18n("Exits Cervisia");
+ action->setToolTip( hint );
+ action->setWhatsThis( hint );
+
+ setHelpMenuEnabled(false);
+ (void) new KHelpMenu(this, instance()->aboutData(), false, actionCollection());
+
+ action = actionCollection()->action("help_contents");
+ hint = i18n("Invokes the KDE help system with the Cervisia documentation");
+ action->setToolTip( hint );
+ action->setWhatsThis( hint );
+
+ action = actionCollection()->action("help_report_bug");
+ hint = i18n("Opens the bug report dialog");
+ action->setToolTip( hint );
+ action->setWhatsThis( hint );
+
+ action = actionCollection()->action("help_about_app");
+ hint = i18n("Displays the version number and copyright information");
+ action->setToolTip( hint );
+ action->setWhatsThis( hint );
+
+ action = actionCollection()->action("help_about_kde");
+ hint = i18n("Displays the information about KDE and its version number");
+ action->setToolTip( hint );
+ action->setWhatsThis( hint );
+}
+
+
+void CervisiaShell::openURL()
+{
+ if( !m_lastOpenDir.isEmpty() )
+ m_part->openURL(KURL::fromPathOrURL(m_lastOpenDir));
+}
+
+
+void CervisiaShell::openURL(const KURL& url)
+{
+ m_part->openURL(url);
+}
+
+
+void CervisiaShell::slotConfigureKeys()
+{
+ KKeyDialog dlg;
+ dlg.insert(actionCollection());
+ if( m_part )
+ dlg.insert(m_part->actionCollection());
+
+ dlg.configure();
+}
+
+void CervisiaShell::slotConfigureToolBars()
+{
+ saveMainWindowSettings( KGlobal::config(), autoSaveGroup() );
+ KEditToolbar dlg( factory() );
+ connect(&dlg,SIGNAL(newToolbarConfig()),this,SLOT(slotNewToolbarConfig()));
+ dlg.exec();
+}
+
+void CervisiaShell::slotNewToolbarConfig()
+{
+ applyMainWindowSettings( KGlobal::config(), autoSaveGroup() );
+}
+
+bool CervisiaShell::queryExit()
+{
+ writeSettings();
+ return true;
+}
+
+
+void CervisiaShell::readProperties(KConfig* config)
+{
+ m_lastOpenDir = config->readPathEntry("Current Directory");
+
+ // if the session is restoring, make sure we open the URL
+ // since it's not handled by main()
+ if( kapp->isRestored() )
+ openURL();
+}
+
+
+void CervisiaShell::saveProperties(KConfig* config)
+{
+ // Save current working directory (if part was created)
+ if( m_part )
+ {
+ config->writePathEntry("Current Directory", m_part->url().path());
+
+ // write to disk
+ config->sync();
+ }
+}
+
+
+void CervisiaShell::readSettings()
+{
+ KConfig* config = KGlobal::config();
+ config->setGroup("Session");
+
+ readProperties(config);
+}
+
+
+void CervisiaShell::writeSettings()
+{
+ KConfig* config = KGlobal::config();
+ config->setGroup("Session");
+
+ saveProperties(config);
+}
+
+
+#include "cervisiashell.moc"
+
+
+// Local Variables:
+// c-basic-offset: 4
+// End:
diff --git a/cervisia/cervisiashell.h b/cervisia/cervisiashell.h
new file mode 100644
index 00000000..6e19ce1d
--- /dev/null
+++ b/cervisia/cervisiashell.h
@@ -0,0 +1,71 @@
+/*
+ * Copyright (C) 1999-2002 Bernd Gehrmann
+ * bernd@mail.berlios.de
+ * Copyright (c) 2002-2004 Christian Loose <christian.loose@kdemail.net>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the 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, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+
+#ifndef CERVISIASHELL_H
+#define CERVISIASHELL_H
+
+#include <kparts/mainwindow.h>
+
+class KRecentFilesAction;
+
+
+/**
+ * A basic shell that embeds the Cervisia part directly to make a standalone
+ * GUI available.
+ */
+class CervisiaShell : public KParts::MainWindow
+{
+ Q_OBJECT
+
+public:
+ CervisiaShell(const char* name=0);
+ virtual ~CervisiaShell();
+
+public slots:
+ void openURL();
+ void openURL(const KURL& url);
+ void slotConfigureKeys();
+ void slotConfigureToolBars();
+
+protected slots:
+ void slotNewToolbarConfig();
+
+protected:
+ void setupActions();
+
+ bool queryExit();
+ virtual void readProperties(KConfig* config);
+ virtual void saveProperties(KConfig* config);
+
+private:
+ void readSettings();
+ void writeSettings();
+
+ KParts::ReadOnlyPart* m_part;
+ QString m_lastOpenDir;
+};
+
+
+#endif // CERVISIASHELL_H
+
+// Local Variables:
+// c-basic-offset: 4
+// End:
diff --git a/cervisia/cervisiashellui.rc b/cervisia/cervisiashellui.rc
new file mode 100644
index 00000000..4a8337c5
--- /dev/null
+++ b/cervisia/cervisiashellui.rc
@@ -0,0 +1,19 @@
+<!DOCTYPE kpartgui SYSTEM "kpartgui.dtd">
+<kpartgui name="cervisia" version="4">
+<MenuBar>
+ <Menu name="file"><text>&amp;File</text>
+ <Merge/>
+ </Menu>
+ <Menu name="settings"><text>&amp;Settings</text>
+ <DefineGroup name="configure_merge_group" append="configure_merge" />
+ <DefineGroup name="save_merge_group" append="show_merge" />
+ </Menu>
+ <Menu name="help"><text>&amp;Help</text>
+ <Merge/>
+ </Menu>
+ <Merge/>
+</MenuBar>
+<ToolBar name="mainToolBar"><text>Main Toolbar</text>
+</ToolBar>
+<StatusBar/>
+</kpartgui>
diff --git a/cervisia/cervisiaui.rc b/cervisia/cervisiaui.rc
new file mode 100644
index 00000000..89fb5124
--- /dev/null
+++ b/cervisia/cervisiaui.rc
@@ -0,0 +1,179 @@
+<!DOCTYPE kpartgui>
+<kpartgui name="cervisiapart" version="12">
+<MenuBar>
+ <Menu name="file"><text>&amp;File</text>
+ <Action name="file_open"/>
+ <Action name="file_open_recent"/>
+ <Separator/>
+ <Action name="insert_changelog_entry"/>
+ <Separator/>
+ <Action name="file_update"/>
+ <Action name="file_status"/>
+ <Separator/>
+ <Action name="file_edit"/>
+ <Action name="file_resolve"/>
+ <Separator/>
+ <Action name="file_commit"/>
+ <Action name="file_add"/>
+ <Action name="file_add_binary"/>
+ <Action name="file_remove"/>
+ <Action name="file_revert_local_changes"/>
+ <Separator/>
+ </Menu>
+ <Menu name="view"><text>&amp;View</text>
+ <Action name="stop_job"/>
+ <Separator/>
+ <Action name="view_log"/>
+ <Action name="view_annotate"/>
+ <Action name="view_diff_base"/>
+ <Action name="view_diff_head"/>
+ <Action name="view_last_change"/>
+ <Action name="view_history"/>
+ <Separator/>
+ <Action name="settings_hide_files"/>
+ <Action name="settings_hide_uptodate"/>
+ <Action name="settings_hide_removed"/>
+ <Action name="settings_hide_notincvs"/>
+ <Action name="settings_hide_empty_directories"/>
+ <Separator/>
+ <Action name="view_unfold_tree"/>
+ <Action name="view_fold_tree"/>
+ </Menu>
+ <Menu name="advanced"><text>&amp;Advanced</text>
+ <Action name="create_tag"/>
+ <Action name="delete_tag"/>
+ <Action name="update_to_tag"/>
+ <Action name="update_to_head"/>
+ <Action name="merge"/>
+ <Separator/>
+ <Action name="add_watch"/>
+ <Action name="remove_watch"/>
+ <Action name="show_watchers"/>
+ <Separator/>
+ <Action name="edit_files"/>
+ <Action name="unedit_files"/>
+ <Action name="show_editors"/>
+ <Separator/>
+ <Action name="lock_files"/>
+ <Action name="unlock_files"/>
+ <Separator/>
+ <Action name="make_patch"/>
+ </Menu>
+ <Menu name="repository"><text>&amp;Repository</text>
+ <Action name="repository_create"/>
+ <Action name="repository_checkout"/>
+ <Action name="repository_import"/>
+ <Separator/>
+ <Action name="show_repositories"/>
+ </Menu>
+ <Menu name="settings"><text>&amp;Settings</text>
+ <Separator group="save_merge_group"/>
+ <Action name="settings_create_dirs" group="save_merge_group"/>
+ <Action name="settings_prune_dirs" group="save_merge_group"/>
+ <Action name="settings_update_recursively" group="save_merge_group"/>
+ <Action name="settings_commit_recursively" group="save_merge_group"/>
+ <Action name="settings_do_cvs_edit" group="save_merge_group"/>
+ <Action name="configure_cervisia" group="configure_merge_group"/>
+ <Separator group="save_merge_group"/>
+ </Menu>
+ <Menu name="help"><text>&amp;Help</text>
+ <Action name="help_cvs_manual"/>
+ </Menu>
+</MenuBar>
+<ToolBar name="mainToolBar"><text>Main Toolbar</text>
+ <Action name="file_update"/>
+ <Action name="file_status"/>
+ <Separator lineSeparator="true"/>
+ <Action name="file_commit"/>
+ <Action name="file_add"/>
+ <Action name="file_remove"/>
+ <Separator lineSeparator="true"/>
+ <Action name="stop_job"/>
+</ToolBar>
+<Menu name="context_popup">
+ <Action name="file_edit"/>
+ <Separator/>
+ <Action name="view_diff_base"/>
+ <Action name="view_diff_head"/>
+ <Action name="view_last_change"/>
+ <Action name="file_resolve"/>
+ <Action name="view_log"/>
+ <Separator/>
+ <Action name="file_update"/>
+ <Action name="file_commit"/>
+ <Separator/>
+ <Action name="file_add"/>
+ <Action name="file_remove"/>
+ <Separator/>
+ <Action name="file_properties"/>
+</Menu>
+<Menu name="folder_context_popup">
+ <Action name="unfold_folder"/>
+ <Separator/>
+ <Action name="file_update"/>
+ <Action name="file_commit"/>
+ <Separator/>
+ <Action name="file_add"/>
+ <Action name="file_remove"/>
+</Menu>
+<State name="has_sandbox">
+ <Enable>
+ <Action name="insert_changelog_entry"/>
+ <Action name="view_unfold_tree"/>
+ <Action name="view_fold_tree"/>
+ </Enable>
+</State>
+<State name="has_single_folder">
+ <Enable>
+ <Action name="unfold_folder"/>
+ </Enable>
+</State>
+<State name="has_single_selection">
+ <Enable>
+ <Action name="file_edit"/>
+ <Action name="file_resolve"/>
+ <Action name="view_log"/>
+ <Action name="view_annotate"/>
+ <Action name="view_diff_base"/>
+ <Action name="view_diff_head"/>
+ <Action name="view_last_change"/>
+ <Action name="file_properties"/>
+ </Enable>
+</State>
+<State name="item_selected">
+ <Enable>
+ <Action name="view_history"/>
+ <Action name="make_patch"/>
+ </Enable>
+</State>
+<State name="has_no_job">
+ <Enable>
+ <Action name="file_update"/>
+ <Action name="file_status"/>
+ <Action name="file_commit"/>
+ <Action name="file_add"/>
+ <Action name="file_add_binary"/>
+ <Action name="file_remove"/>
+ <Action name="file_revert_local_changes"/>
+ <Action name="create_tag"/>
+ <Action name="delete_tag"/>
+ <Action name="update_to_tag"/>
+ <Action name="update_to_head"/>
+ <Action name="merge"/>
+ <Action name="add_watch"/>
+ <Action name="remove_watch"/>
+ <Action name="show_watchers"/>
+ <Action name="edit_files"/>
+ <Action name="unedit_files"/>
+ <Action name="show_editors"/>
+ <Action name="lock_files"/>
+ <Action name="unlock_files"/>
+ </Enable>
+</State>
+<State name="has_running_job">
+ <Disable>
+ <Action name="repository_checkout"/>
+ <Action name="repository_import"/>
+ </Disable>
+</State>
+</kpartgui>
diff --git a/cervisia/change_colors.pl b/cervisia/change_colors.pl
new file mode 100644
index 00000000..6f455251
--- /dev/null
+++ b/cervisia/change_colors.pl
@@ -0,0 +1,31 @@
+#!/usr/bin/perl
+
+
+while(<>)
+{
+ ($key) = ($_ =~ /([^=]*)=(.*)$/);
+ ($value) = ($_ =~ /^[^=]*=(.*)$/);
+
+ if( $key eq "Conflict" and $value eq "255,100,100" )
+ {
+ print "# DELETE " . $key . "\n";
+ print $key . "=255,130,130\n";
+ next;
+ }
+
+ if( $key eq "LocalChange" and $value eq "190,190,237" )
+ {
+ print "# DELETE " . $key . "\n";
+ print $key . "=130,130,255\n";
+ next;
+ }
+
+ if( $key eq "RemoteChange" and $value eq "255,240,190" )
+ {
+ print "# DELETE " . $key . "\n";
+ print $key . "=70,210,70\n";
+ next;
+ }
+
+ print $_;
+}
diff --git a/cervisia/changelogdlg.cpp b/cervisia/changelogdlg.cpp
new file mode 100644
index 00000000..902a40f3
--- /dev/null
+++ b/cervisia/changelogdlg.cpp
@@ -0,0 +1,188 @@
+/*
+ * Copyright (C) 1999-2002 Bernd Gehrmann
+ * bernd@mail.berlios.de
+ * Copyright (c) 2002-2003 Christian Loose <christian.loose@hamburg.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.
+ *
+ * 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, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+
+#include "changelogdlg.h"
+
+#include <qfile.h>
+#include <qtextstream.h>
+#include <kconfig.h>
+#include <kglobalsettings.h>
+#include <klocale.h>
+#include <kmessagebox.h>
+#include <ktextedit.h>
+#include "misc.h"
+
+
+static inline QString DateStringISO8601()
+{
+ return QDate::currentDate().toString(Qt::ISODate);
+}
+
+
+ChangeLogDialog::Options *ChangeLogDialog::options = 0;
+
+
+ChangeLogDialog::ChangeLogDialog(KConfig& cfg, QWidget *parent, const char *name)
+ : KDialogBase(parent, name, true, i18n("Edit ChangeLog"),
+ Ok | Cancel, Ok, true)
+ , partConfig(cfg)
+{
+ edit = new KTextEdit(this);
+
+ cfg.setGroup("LookAndFeel");
+ edit->setFont(cfg.readFontEntry("ChangeLogFont"));
+
+ edit->setFocus();
+ edit->setWordWrap(QTextEdit::NoWrap);
+ edit->setTextFormat(QTextEdit::PlainText);
+ edit->setCheckSpellingEnabled(true);
+ QFontMetrics const fm(edit->fontMetrics());
+ edit->setMinimumSize(fm.width('0') * 80,
+ fm.lineSpacing() * 20);
+
+ setMainWidget(edit);
+
+ QSize size = configDialogSize(partConfig, "ChangeLogDialog");
+ resize(size);
+}
+
+
+ChangeLogDialog::~ChangeLogDialog()
+{
+ saveDialogSize(partConfig, "ChangeLogDialog");
+}
+
+
+void ChangeLogDialog::slotOk()
+{
+ // Write changelog
+ QFile f(fname);
+ if (!f.open(IO_ReadWrite))
+ {
+ KMessageBox::sorry(this,
+ i18n("The ChangeLog file could not be written."),
+ "Cervisia");
+ return;
+ }
+
+ QTextStream stream(&f);
+ stream << edit->text();
+ f.close();
+
+ KDialogBase::slotOk();
+}
+
+
+bool ChangeLogDialog::readFile(const QString &filename)
+{
+ fname = filename;
+
+ if (!QFile::exists(filename))
+ {
+ if (KMessageBox::warningContinueCancel(this,
+ i18n("A ChangeLog file does not exist. Create one?"),
+ "Cervisia",
+ i18n("Create")) != KMessageBox::Continue)
+ return false;
+ }
+ else
+ {
+ QFile f(filename);
+ if (!f.open(IO_ReadWrite))
+ {
+ KMessageBox::sorry(this,
+ i18n("The ChangeLog file could not be read."),
+ "Cervisia");
+ return false;
+ }
+ QTextStream stream(&f);
+ edit->setText(stream.read());
+ f.close();
+ }
+
+ KConfigGroupSaver cs(&partConfig, "General");
+ const QString username = partConfig.readEntry("Username", Cervisia::UserName());
+
+ edit->insertParagraph("", 0);
+ edit->insertParagraph("\t* ", 0);
+ edit->insertParagraph("", 0);
+ edit->insertParagraph(DateStringISO8601() + " " + username, 0);
+ edit->setCursorPosition(2, 10);
+
+ return true;
+}
+
+
+QString ChangeLogDialog::message()
+{
+ int no = 0;
+ // Find first line which begins with non-whitespace
+ while (no < edit->lines())
+ {
+ QString str = edit->text(no);
+ if (!str.isEmpty() && !str[0].isSpace())
+ break;
+ ++no;
+ }
+ ++no;
+ // Skip empty lines
+ while (no < edit->lines())
+ {
+ QString str = edit->text(no);
+ if( str.isEmpty() || str == " " )
+ break;
+ ++no;
+ }
+ QString res;
+ // Use all lines until one which begins with non-whitespace
+ // Remove tabs or 8 whitespace at beginning of each line
+ while (no < edit->lines())
+ {
+ QString str = edit->text(no);
+ if (!str.isEmpty() && !str[0].isSpace())
+ break;
+ if (!str.isEmpty() && str[0] == '\t')
+ str.remove(0, 1);
+ else
+ {
+ int j;
+ for (j = 0; j < (int)str.length(); ++j)
+ if (!str[j].isSpace())
+ break;
+ str.remove(0, QMIN(j, 8));
+ }
+ res += str;
+ res += '\n';
+ ++no;
+ }
+ // Remove newlines at end
+ int l;
+ for (l = res.length()-1; l > 0; --l)
+ if (res[l] != '\n')
+ break;
+ res.truncate(l+1);
+ return res;
+}
+
+
+// Local Variables:
+// c-basic-offset: 4
+// End:
diff --git a/cervisia/changelogdlg.h b/cervisia/changelogdlg.h
new file mode 100644
index 00000000..6c1aa3e3
--- /dev/null
+++ b/cervisia/changelogdlg.h
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 1999-2001 Bernd Gehrmann
+ * bernd@mail.berlios.de
+ * Copyright (c) 2002-2003 Christian Loose <christian.loose@hamburg.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.
+ *
+ * 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, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+
+#ifndef CHANGELOGDLG_H
+#define CHANGELOGDLG_H
+
+#include <kdialogbase.h>
+
+class KTextEdit;
+class KConfig;
+
+
+class ChangeLogDialog : public KDialogBase
+{
+public:
+ explicit ChangeLogDialog( KConfig& cfg, QWidget *parent=0, const char *name=0 );
+
+ virtual ~ChangeLogDialog();
+
+ bool readFile(const QString &fileName);
+ QString message();
+
+protected:
+ virtual void slotOk();
+
+private:
+ struct Options {
+ QSize size;
+ };
+ static Options *options;
+
+ QString fname;
+ KTextEdit *edit;
+ KConfig& partConfig;
+};
+
+#endif
+
+
+// Local Variables:
+// c-basic-offset: 4
+// End:
diff --git a/cervisia/checkoutdlg.cpp b/cervisia/checkoutdlg.cpp
new file mode 100644
index 00000000..85a8b0a8
--- /dev/null
+++ b/cervisia/checkoutdlg.cpp
@@ -0,0 +1,484 @@
+/*
+ * Copyright (C) 1999-2002 Bernd Gehrmann
+ * bernd@mail.berlios.de
+ * Copyright (c) 2003-2004 Christian Loose <christian.loose@hamburg.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.
+ *
+ * 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, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+
+#include "checkoutdlg.h"
+
+#include <qcheckbox.h>
+#include <qcombobox.h>
+#include <qdir.h>
+#include <qlayout.h>
+#include <qlabel.h>
+#include <qpushbutton.h>
+#include <kprocess.h>
+#include <kfiledialog.h>
+#include <klineedit.h>
+#include <klocale.h>
+#include <kmessagebox.h>
+#include <kurlcompletion.h>
+
+#include "progressdlg.h"
+#include "repositories.h"
+#include "misc.h"
+#include "cvsservice_stub.h"
+
+using Cervisia::IsValidTag;
+
+
+CheckoutDialog::CheckoutDialog(KConfig& cfg, CvsService_stub* service,
+ ActionType action, QWidget* parent,
+ const char* name)
+ : KDialogBase(parent, name, true, QString::null,
+ Ok | Cancel | Help, Ok, true)
+ , act(action)
+ , partConfig(cfg)
+ , cvsService(service)
+{
+ setCaption( (action==Checkout)? i18n("CVS Checkout") : i18n("CVS Import") );
+
+ QFrame* mainWidget = makeMainWidget();
+
+ QBoxLayout* layout = new QVBoxLayout(mainWidget, 0, spacingHint());
+
+ QGridLayout* grid = new QGridLayout(layout);
+ grid->setColStretch(0, 1);
+ grid->setColStretch(1, 20);
+ for( int i = 0; i < ((action==Checkout)? 4 : 10); ++i )
+ grid->setRowStretch(i, 0);
+
+ repo_combo = new QComboBox(true, mainWidget);
+ repo_combo->setFocus();
+ // make sure combobox is smaller than the screen
+ repo_combo->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Fixed);
+ grid->addWidget(repo_combo, 0, 1);
+
+ QLabel* repo_label = new QLabel(repo_combo, i18n("&Repository:"), mainWidget);
+ grid->addWidget(repo_label, 0, 0, AlignLeft | AlignVCenter);
+
+ if( action == Import )
+ {
+ module_edit = new KLineEdit(mainWidget);
+ grid->addWidget(module_edit, 1, 1);
+ QLabel* module_label = new QLabel(module_edit, i18n("&Module:"), mainWidget);
+ grid->addWidget(module_label, 1, 0, AlignLeft | AlignVCenter);
+ }
+ else
+ {
+ module_combo = new QComboBox(true, mainWidget);
+
+ QPushButton* module_button = new QPushButton(i18n("Fetch &List"), mainWidget);
+ connect( module_button, SIGNAL(clicked()),
+ this, SLOT(moduleButtonClicked()) );
+
+ QBoxLayout* module_layout = new QHBoxLayout();
+ grid->addLayout(module_layout, 1, 1);
+ module_layout->addWidget(module_combo, 10);
+ module_layout->addWidget(module_button, 0, AlignVCenter);
+
+ QLabel* module_label = new QLabel(module_combo, i18n("&Module:"), mainWidget);
+ grid->addWidget(module_label, 1, 0, AlignLeft | AlignVCenter);
+
+ branchCombo = new QComboBox(true, mainWidget);
+
+ QPushButton* branchButton = new QPushButton(i18n("Fetch &List"), mainWidget);
+ connect( branchButton, SIGNAL(clicked()),
+ this, SLOT(branchButtonClicked()) );
+
+ QBoxLayout* branchLayout = new QHBoxLayout();
+ grid->addLayout(branchLayout, 2, 1);
+ branchLayout->addWidget(branchCombo, 10);
+ branchLayout->addWidget(branchButton, 0, AlignVCenter);
+
+ QLabel* branch_label = new QLabel(branchCombo, i18n("&Branch tag:"),
+ mainWidget);
+ grid->addWidget(branch_label, 2, 0, AlignLeft | AlignVCenter);
+
+ connect( branchCombo, SIGNAL( textChanged( const QString&)),
+ this, SLOT( branchTextChanged() ));
+
+ recursive_box = new QCheckBox(i18n("Re&cursive checkout"), mainWidget);
+ grid->addMultiCellWidget(recursive_box, 6, 6, 0, 1);
+ }
+
+ workdir_edit = new KLineEdit(mainWidget);
+ workdir_edit->setText(QDir::homeDirPath());
+ workdir_edit->setMinimumWidth(fontMetrics().width('X') * 40);
+
+ KURLCompletion* comp = new KURLCompletion();
+ workdir_edit->setCompletionObject(comp);
+ workdir_edit->setAutoDeleteCompletionObject(true);
+ connect( workdir_edit, SIGNAL(returnPressed(const QString&)),
+ comp, SLOT(addItem(const QString&)) );
+
+ QPushButton* dir_button = new QPushButton("...", mainWidget);
+ connect( dir_button, SIGNAL(clicked()),
+ this, SLOT(dirButtonClicked()) );
+ dir_button->setFixedWidth(30);
+
+ QBoxLayout* workdir_layout = new QHBoxLayout();
+ grid->addLayout(workdir_layout, (action==Import)? 2 : 3, 1);
+ workdir_layout->addWidget(workdir_edit, 10);
+ workdir_layout->addWidget(dir_button, 0, AlignVCenter);
+
+ QLabel* workdir_label = new QLabel(workdir_edit, i18n("Working &folder:"),
+ mainWidget);
+ grid->addWidget(workdir_label, (action==Import)? 2 : 3, 0, AlignLeft | AlignVCenter);
+
+ if( action == Import )
+ {
+ vendortag_edit = new KLineEdit(mainWidget);
+ grid->addWidget(vendortag_edit, 3, 1);
+
+ QLabel* vendortag_label = new QLabel(vendortag_edit, i18n("&Vendor tag:"),
+ mainWidget);
+ grid->addWidget(vendortag_label, 3, 0, AlignLeft | AlignVCenter);
+
+ releasetag_edit = new KLineEdit(mainWidget);
+ grid->addWidget(releasetag_edit, 4, 1);
+
+ QLabel* releasetag_label = new QLabel(releasetag_edit, i18n("&Release tag:"),
+ mainWidget);
+ grid->addWidget(releasetag_label, 4, 0, AlignLeft | AlignVCenter);
+
+ ignore_edit = new KLineEdit(mainWidget);
+ grid->addWidget(ignore_edit, 5, 1);
+
+ QLabel* ignore_label = new QLabel(ignore_edit, i18n("&Ignore files:"),
+ mainWidget);
+ grid->addWidget(ignore_label, 5, 0, AlignLeft | AlignVCenter);
+
+ comment_edit = new KLineEdit(mainWidget);
+ grid->addWidget(comment_edit, 6, 1);
+
+ QLabel* comment_label = new QLabel(comment_edit, i18n("&Comment:"),
+ mainWidget);
+ grid->addWidget(comment_label, 6, 0, AlignLeft | AlignVCenter);
+
+ binary_box = new QCheckBox(i18n("Import as &binaries"), mainWidget);
+ grid->addMultiCellWidget(binary_box, 7, 7, 0, 1);
+
+ m_useModificationTimeBox = new QCheckBox(
+ i18n("Use file's modification time as time of import"), mainWidget);
+ grid->addMultiCellWidget(m_useModificationTimeBox, 8, 8, 0, 1);
+ }
+ else
+ {
+ alias_edit = new KLineEdit(mainWidget);
+ grid->addWidget(alias_edit, 4, 1);
+
+ QLabel* alias_label = new QLabel(alias_edit, i18n("Chec&k out as:"), mainWidget);
+ grid->addWidget(alias_label, 4, 0, AlignLeft | AlignVCenter);
+
+ export_box = new QCheckBox(i18n("Ex&port only"), mainWidget);
+ grid->addMultiCellWidget(export_box, 5, 5, 0, 1);
+ }
+
+ QStringList list1 = Repositories::readCvsPassFile();
+ QStringList::ConstIterator it1;
+ for (it1 = list1.begin(); it1 != list1.end(); ++it1)
+ repo_combo->insertItem(*it1);
+
+ QStringList list2 = Repositories::readConfigFile();
+ QStringList::ConstIterator it2;
+ for (it2 = list2.begin(); it2 != list2.end(); ++it2)
+ if (!list1.contains(*it2))
+ repo_combo->insertItem(*it2);
+
+ setHelp((act == Import) ? "importing" : "checkingout");
+
+ restoreUserInput();
+}
+
+
+QString CheckoutDialog::workingDirectory() const
+{
+ return workdir_edit->text();
+}
+
+
+QString CheckoutDialog::repository() const
+{
+ return repo_combo->currentText();
+}
+
+
+QString CheckoutDialog::module() const
+{
+ return act==Import? module_edit->text() : module_combo->currentText();
+}
+
+
+QString CheckoutDialog::branch() const
+{
+ return branchCombo->currentText();
+}
+
+
+QString CheckoutDialog::vendorTag() const
+{
+ return vendortag_edit->text();
+}
+
+
+QString CheckoutDialog::releaseTag() const
+{
+ return releasetag_edit->text();
+}
+
+
+QString CheckoutDialog::ignoreFiles() const
+{
+ return ignore_edit->text();
+}
+
+
+QString CheckoutDialog::comment() const
+{
+ return comment_edit->text();
+}
+
+QString CheckoutDialog::alias() const
+{
+ return alias_edit->text();
+}
+
+bool CheckoutDialog::importBinary() const
+{
+ return binary_box->isChecked();
+}
+
+bool CheckoutDialog::useModificationTime() const
+{
+ return m_useModificationTimeBox->isChecked();
+}
+
+bool CheckoutDialog::exportOnly() const
+{
+ if( export_box->isEnabled() )
+ return export_box->isChecked();
+
+ return false;
+}
+
+bool CheckoutDialog::recursive() const
+{
+ return recursive_box->isChecked();
+}
+
+void CheckoutDialog::slotOk()
+{
+ QFileInfo fi(workingDirectory());
+ if (!fi.exists() || !fi.isDir())
+ {
+ KMessageBox::information(this, i18n("Please choose an existing working folder."));
+ return;
+ }
+ if (module().isEmpty())
+ {
+ KMessageBox::information(this, i18n("Please specify a module name."));
+ return;
+ }
+
+ if (act==Import)
+ {
+ if (vendorTag().isEmpty() || releaseTag().isEmpty())
+ {
+ KMessageBox::information(this,
+ i18n("Please specify a vendor tag and a release tag."));
+ return;
+ }
+ if (!IsValidTag(vendorTag()) || !IsValidTag(releaseTag()))
+ {
+ KMessageBox::information(this,
+ i18n("Tags must start with a letter and may contain\n"
+ "letters, digits and the characters '-' and '_'."));
+ return;
+ }
+ }
+ else
+ {
+ if( branch().isEmpty() && exportOnly() )
+ {
+ KMessageBox::information(this,
+ i18n("A branch must be specified for export."));
+ return;
+ }
+ }
+
+ saveUserInput();
+
+ KDialogBase::slotOk();
+}
+
+
+void CheckoutDialog::dirButtonClicked()
+{
+ QString dir = KFileDialog::getExistingDirectory(workdir_edit->text());
+ if (!dir.isEmpty())
+ workdir_edit->setText(dir);
+}
+
+
+void CheckoutDialog::moduleButtonClicked()
+{
+ DCOPRef cvsJob = cvsService->moduleList(repository());
+ if( !cvsService->ok() )
+ return;
+
+ ProgressDialog dlg(this, "Checkout", cvsJob, "checkout", i18n("CVS Checkout"));
+ if( !dlg.execute() )
+ return;
+
+ module_combo->clear();
+ QString str;
+ while (dlg.getLine(str))
+ {
+ if (str.left(12) == "Unknown host")
+ continue;
+
+ int pos = str.find(' ');
+ if (pos == -1)
+ pos = str.find('\t');
+ if (pos == -1)
+ pos = str.length();
+ QString module( str.left(pos).stripWhiteSpace() );
+ if ( !module.isEmpty() )
+ module_combo->insertItem(module);
+ }
+}
+
+
+void CheckoutDialog::branchButtonClicked()
+{
+ QStringList branchTagList;
+
+ if( repository().isEmpty() )
+ {
+ KMessageBox::information(this, i18n("Please specify a repository."));
+ return;
+ }
+
+ if( module().isEmpty() )
+ {
+ KMessageBox::information(this, i18n("Please specify a module name."));
+ return;
+ }
+
+ DCOPRef cvsJob = cvsService->rlog(repository(), module(),
+ false/*recursive*/);
+ if( !cvsService->ok() )
+ return;
+
+ ProgressDialog dlg(this, "Remote Log", cvsJob, QString::null,
+ i18n("CVS Remote Log"));
+ if( !dlg.execute() )
+ return;
+
+ QString line;
+ while( dlg.getLine(line) )
+ {
+ int colonPos;
+
+ if( line.isEmpty() || line[0] != '\t' )
+ continue;
+ if( (colonPos = line.find(':', 1)) < 0 )
+ continue;
+
+ const QString tag = line.mid(1, colonPos - 1);
+ if( !branchTagList.contains(tag) )
+ branchTagList.push_back(tag);
+ }
+
+ branchTagList.sort();
+
+ branchCombo->clear();
+ branchCombo->insertStringList(branchTagList);
+}
+
+
+void CheckoutDialog::restoreUserInput()
+{
+ KConfigGroupSaver cs(&partConfig, "CheckoutDialog");
+
+ repo_combo->setEditText(partConfig.readEntry("Repository"));
+ workdir_edit->setText(partConfig.readPathEntry("Working directory"));
+
+ if (act == Import)
+ {
+ module_edit->setText(partConfig.readEntry("Module"));
+ vendortag_edit->setText(partConfig.readEntry("Vendor tag"));
+ releasetag_edit->setText(partConfig.readEntry("Release tag"));
+ ignore_edit->setText(partConfig.readEntry("Ignore files"));
+ binary_box->setChecked(partConfig.readBoolEntry("Import binary"));
+ }
+ else
+ {
+ module_combo->setEditText(partConfig.readEntry("Module"));
+ branchCombo->setCurrentText(partConfig.readEntry("Branch"));
+ alias_edit->setText(partConfig.readEntry("Alias"));
+ export_box->setChecked(partConfig.readBoolEntry("ExportOnly"));
+ recursive_box->setChecked(true);
+ }
+}
+
+
+void CheckoutDialog::saveUserInput()
+{
+ KConfigGroupSaver cs(&partConfig, "CheckoutDialog");
+
+ partConfig.writeEntry("Repository", repository());
+ partConfig.writeEntry("Module", module());
+ partConfig.writeEntry("Working directory", workingDirectory());
+
+ if (act == Import)
+ {
+ partConfig.writeEntry("Vendor tag", vendorTag());
+ partConfig.writeEntry("Release tag", releaseTag());
+ partConfig.writeEntry("Ignore files", ignoreFiles());
+ partConfig.writeEntry("Import binary", importBinary());
+ }
+ else
+ {
+ partConfig.writeEntry("Branch", branch());
+ partConfig.writeEntry("Alias", alias());
+ partConfig.writeEntry("ExportOnly", exportOnly());
+ }
+}
+
+void CheckoutDialog::branchTextChanged()
+{
+ if( branch().isEmpty() )
+ {
+ export_box->setEnabled(false);
+ export_box->setChecked(false);
+ }
+ else
+ {
+ export_box->setEnabled(true);
+ }
+}
+
+
+#include "checkoutdlg.moc"
+
+
+// Local Variables:
+// c-basic-offset: 4
+// End:
diff --git a/cervisia/checkoutdlg.h b/cervisia/checkoutdlg.h
new file mode 100644
index 00000000..33f95f2b
--- /dev/null
+++ b/cervisia/checkoutdlg.h
@@ -0,0 +1,89 @@
+/*
+ * Copyright (C) 1999-2002 Bernd Gehrmann
+ * bernd@mail.berlios.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.
+ *
+ * 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, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+
+#ifndef CHECKOUTDLG_H
+#define CHECKOUTDLG_H
+
+
+#include <kdialogbase.h>
+
+
+class QCheckBox;
+class QComboBox;
+class KConfig;
+class KLineEdit;
+class CvsService_stub;
+
+
+class CheckoutDialog : public KDialogBase
+{
+ Q_OBJECT
+
+public:
+ enum ActionType { Checkout, Import };
+
+ CheckoutDialog( KConfig& cfg, CvsService_stub* service, ActionType action,
+ QWidget *parent=0, const char *name=0 );
+
+ QString workingDirectory() const;
+ QString repository() const;
+ QString module() const;
+ QString branch() const;
+ QString vendorTag() const;
+ QString releaseTag() const;
+ QString ignoreFiles() const;
+ QString comment() const;
+ QString alias() const;
+ bool importBinary() const;
+ bool useModificationTime() const;
+ bool exportOnly() const;
+ bool recursive() const;
+
+protected:
+ virtual void slotOk();
+
+private slots:
+ void dirButtonClicked();
+ void moduleButtonClicked();
+ void branchButtonClicked();
+ void branchTextChanged();
+
+private:
+ void saveUserInput();
+ void restoreUserInput();
+
+ QComboBox *repo_combo, *module_combo, *branchCombo;
+ KLineEdit *module_edit, *workdir_edit;
+ KLineEdit *comment_edit;
+ KLineEdit *vendortag_edit, *releasetag_edit, *ignore_edit, *alias_edit;
+ QCheckBox *binary_box, *export_box, *recursive_box;
+ QCheckBox* m_useModificationTimeBox;
+ ActionType act;
+ KConfig& partConfig;
+
+ CvsService_stub *cvsService;
+};
+
+#endif
+
+
+// Local Variables:
+// c-basic-offset: 4
+// End:
diff --git a/cervisia/commitdlg.cpp b/cervisia/commitdlg.cpp
new file mode 100644
index 00000000..53c91ba7
--- /dev/null
+++ b/cervisia/commitdlg.cpp
@@ -0,0 +1,326 @@
+/*
+ * Copyright (C) 1999-2002 Bernd Gehrmann
+ * bernd@mail.berlios.de
+ * Copyright (c) 2002-2005 Christian Loose <christian.loose@kdemail.net>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the 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, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#include "commitdlg.h"
+
+#include <qcombobox.h>
+#include <qcheckbox.h>
+#include <qdir.h>
+#include <qfileinfo.h>
+#include <qlabel.h>
+#include <qlayout.h>
+#include <qheader.h>
+#include <klistview.h>
+#include <kconfig.h>
+#include <klocale.h>
+
+#include "cvsservice_stub.h"
+#include "logmessageedit.h"
+#include "diffdlg.h"
+
+
+class CommitListItem : public QCheckListItem
+{
+public:
+ CommitListItem(QListView* parent, const QString& text, const QString fileName)
+ : QCheckListItem(parent, text, QCheckListItem::CheckBox)
+ , m_fileName(fileName)
+ {
+ }
+
+ QString fileName() const { return m_fileName; }
+
+private:
+ QString m_fileName;
+};
+
+
+CommitDialog::CommitDialog(KConfig& cfg, CvsService_stub* service,
+ QWidget *parent, const char *name)
+ : KDialogBase(parent, name, true, i18n("CVS Commit"),
+ Ok | Cancel | Help | User1, Ok, true)
+ , partConfig(cfg)
+ , cvsService(service)
+{
+ QFrame* mainWidget = makeMainWidget();
+
+ QBoxLayout *layout = new QVBoxLayout(mainWidget, 0, spacingHint());
+
+ QLabel *textlabel = new QLabel( i18n("Commit the following &files:"), mainWidget );
+ layout->addWidget(textlabel);
+
+ m_fileList = new KListView(mainWidget);
+ m_fileList->addColumn("");
+ m_fileList->setFullWidth(true);
+ m_fileList->header()->hide();
+ textlabel->setBuddy(m_fileList);
+ connect( m_fileList, SIGNAL(doubleClicked(QListViewItem*)),
+ this, SLOT(fileSelected(QListViewItem*)));
+ connect( m_fileList, SIGNAL(selectionChanged()),
+ this, SLOT(fileHighlighted()) );
+ layout->addWidget(m_fileList, 5);
+
+ QLabel *archivelabel = new QLabel(i18n("Older &messages:"), mainWidget);
+ layout->addWidget(archivelabel);
+
+ combo = new QComboBox(mainWidget);
+ archivelabel->setBuddy(combo);
+ connect( combo, SIGNAL(activated(int)), this, SLOT(comboActivated(int)) );
+ // make sure that combobox is smaller than the screen
+ combo->setSizePolicy(QSizePolicy(QSizePolicy::Preferred, QSizePolicy::Fixed));
+ layout->addWidget(combo);
+
+ QLabel *messagelabel = new QLabel(i18n("&Log message:"), mainWidget);
+ layout->addWidget(messagelabel);
+
+ edit = new Cervisia::LogMessageEdit(mainWidget);
+ messagelabel->setBuddy(edit);
+ edit->setCheckSpellingEnabled(true);
+ edit->setFocus();
+ edit->setMinimumSize(400, 100);
+ layout->addWidget(edit, 10);
+
+ m_useTemplateChk = new QCheckBox(i18n("Use log message &template"), mainWidget);
+ layout->addWidget(m_useTemplateChk);
+ connect( m_useTemplateChk, SIGNAL(clicked()), this, SLOT(useTemplateClicked()) );
+
+ checkForTemplateFile();
+
+ setButtonGuiItem(User1, KGuiItem(i18n("&Diff"), "vcs_diff"));
+ enableButton(User1, false);
+ connect( this, SIGNAL(user1Clicked()),
+ this, SLOT(diffClicked()) );
+
+ setHelp("commitingfiles");
+
+ QSize size = configDialogSize(partConfig, "CommitDialog");
+ resize(size);
+}
+
+
+CommitDialog::~CommitDialog()
+{
+ saveDialogSize(partConfig, "CommitDialog");
+
+ KConfigGroupSaver cs(&partConfig, "CommitDialog");
+ partConfig.writeEntry("UseTemplate", m_useTemplateChk->isChecked());
+}
+
+
+void CommitDialog::setFileList(const QStringList &list)
+{
+ QString currentDirName = QFileInfo(QChar('.')).absFilePath();
+
+ QStringList::ConstIterator it = list.begin();
+ for( ; it != list.end(); ++it )
+ {
+ // the dot for the root directory is hard to see, so
+ // we convert it to the absolut path
+ QString text = (*it != "." ? *it : currentDirName);
+
+ edit->compObj()->addItem(text);
+ CommitListItem* item = new CommitListItem(m_fileList, text, *it);
+ item->setOn(true);
+ }
+}
+
+
+QStringList CommitDialog::fileList() const
+{
+ QStringList files;
+
+ QListViewItemIterator it(m_fileList, QListViewItemIterator::Checked);
+ for( ; it.current(); ++it )
+ {
+ CommitListItem* item = static_cast<CommitListItem*>(it.current());
+ files.append(item->fileName());
+ }
+
+ return files;
+}
+
+
+void CommitDialog::setLogMessage(const QString &msg)
+{
+ edit->setText(msg);
+
+ if( m_useTemplateChk->isChecked() )
+ addTemplateText();
+}
+
+
+QString CommitDialog::logMessage() const
+{
+ return edit->text();
+}
+
+
+void CommitDialog::setLogHistory(const QStringList &list)
+{
+ commits = list;
+
+ combo->insertItem(i18n("Current"));
+
+ for ( QStringList::ConstIterator it = list.begin();
+ it != list.end(); ++it )
+ {
+ if( (*it).isEmpty() )
+ continue;
+
+ QString txt = *it;
+ int index = txt.find('\n', 0);
+ if ( index != -1 ) // Fetch first line
+ {
+ txt = txt.mid(0, index);
+ txt += "...";
+ }
+
+ combo->insertItem(txt);
+ }
+}
+
+
+void CommitDialog::comboActivated(int index)
+{
+ if (index == current_index)
+ return;
+
+ if (index == 0) // Handle current text
+ edit->setText(current_text);
+ else
+ {
+ if (current_index == 0) // Store current text
+ current_text = edit->text();
+
+ // Show archived text
+ edit->setText(commits[index-1]);
+ }
+ current_index = index;
+}
+
+
+void CommitDialog::fileSelected(QListViewItem* item)
+{
+ // double click on empty space?
+ if( !item )
+ return;
+
+ showDiffDialog(item->text(0));
+}
+
+
+void CommitDialog::fileHighlighted()
+{
+ bool isItemSelected = (m_fileList->selectedItem() != 0);
+ enableButton(User1, isItemSelected);
+}
+
+
+void CommitDialog::diffClicked()
+{
+ QListViewItem* item = m_fileList->selectedItem();
+ if( !item )
+ return;
+
+ showDiffDialog(item->text(0));
+}
+
+
+void CommitDialog::showDiffDialog(const QString& fileName)
+{
+ DiffDialog *l = new DiffDialog(partConfig, this, "diffdialog");
+
+ // disable diff button so user doesn't open the same diff several times (#83018)
+ enableButton(User1, false);
+
+ if (l->parseCvsDiff(cvsService, fileName, "", ""))
+ l->show();
+ else
+ delete l;
+
+ // re-enable diff button
+ enableButton(User1, true);
+}
+
+
+void CommitDialog::useTemplateClicked()
+{
+ if( m_useTemplateChk->isChecked() )
+ {
+ addTemplateText();
+ }
+ else
+ {
+ removeTemplateText();
+ }
+}
+
+
+void CommitDialog::checkForTemplateFile()
+{
+ QString filename = QDir::current().absPath() + "/CVS/Template";
+ if( QFile::exists(filename) )
+ {
+ QFile f(filename);
+ if( f.open(IO_ReadOnly) )
+ {
+ QTextStream stream(&f);
+ m_templateText = stream.read();
+ f.close();
+
+ m_useTemplateChk->setEnabled(true);
+ KConfigGroupSaver cs(&partConfig, "CommitDialog");
+ bool check = partConfig.readBoolEntry("UseTemplate", true);
+ m_useTemplateChk->setChecked(check);
+
+ addTemplateText();
+ }
+ else
+ {
+ m_useTemplateChk->setEnabled(false);
+ }
+ }
+ else
+ {
+ m_useTemplateChk->setEnabled(false);
+ }
+}
+
+
+void CommitDialog::addTemplateText()
+{
+ edit->append(m_templateText);
+ edit->moveCursor(QTextEdit::MoveHome, false);
+ edit->ensureCursorVisible();
+}
+
+
+void CommitDialog::removeTemplateText()
+{
+ edit->setText(edit->text().remove(m_templateText));
+}
+
+
+#include "commitdlg.moc"
+
+
+// Local Variables:
+// c-basic-offset: 4
+// End:
diff --git a/cervisia/commitdlg.h b/cervisia/commitdlg.h
new file mode 100644
index 00000000..fe3d9acf
--- /dev/null
+++ b/cervisia/commitdlg.h
@@ -0,0 +1,86 @@
+/*
+ * Copyright (C) 1999-2002 Bernd Gehrmann
+ * bernd@mail.berlios.de
+ * Copyright (c) 2003-2005 Christian Loose <christian.loose@kdemail.net>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the 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, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+
+#ifndef COMMITDLG_H
+#define COMMITDLG_H
+
+#include <qstringlist.h>
+#include <kdialogbase.h>
+
+namespace Cervisia { class LogMessageEdit; }
+
+class QComboBox;
+class QCheckBox;
+class KListView;
+class KConfig;
+class CvsService_stub;
+
+
+class CommitDialog : public KDialogBase
+{
+ Q_OBJECT
+
+public:
+ CommitDialog( KConfig& cfg, CvsService_stub* service, QWidget *parent=0,
+ const char *name=0 );
+
+ virtual ~CommitDialog();
+
+ void setFileList(const QStringList &list);
+ QStringList fileList() const;
+ void setLogMessage(const QString &msg);
+ QString logMessage() const;
+ void setLogHistory(const QStringList &list);
+
+private slots:
+ void comboActivated(int);
+ void fileSelected(QListViewItem* item);
+ void fileHighlighted();
+ void diffClicked();
+ void useTemplateClicked();
+
+private:
+ void showDiffDialog(const QString& fileName);
+ void checkForTemplateFile();
+ void addTemplateText();
+ void removeTemplateText();
+
+ KListView* m_fileList;
+ Cervisia::LogMessageEdit* edit;
+ QComboBox *combo;
+ QStringList commits;
+ int current_index;
+ QString current_text;
+ int highlightedFile;
+
+ QCheckBox* m_useTemplateChk;
+ QString m_templateText;
+
+ KConfig& partConfig;
+ CvsService_stub* cvsService; // for diff dialog
+};
+
+#endif
+
+
+// Local Variables:
+// c-basic-offset: 4
+// End:
diff --git a/cervisia/cvsdir.cpp b/cervisia/cvsdir.cpp
new file mode 100644
index 00000000..263fd704
--- /dev/null
+++ b/cervisia/cvsdir.cpp
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 1999-2002 Bernd Gehrmann
+ * bernd@mail.berlios.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.
+ *
+ * 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, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+
+#include "cvsdir.h"
+
+#include "dirignorelist.h"
+#include "globalignorelist.h"
+using namespace Cervisia;
+
+
+CvsDir::CvsDir(const QString &path)
+ : QDir( path, 0, QDir::Name,
+ QDir::All | QDir::Hidden | QDir::NoSymLinks )
+{}
+
+
+const QFileInfoList *CvsDir::entryInfoList() const
+{
+ DirIgnoreList ignorelist(absPath());
+ const QFileInfoList *fulllist = QDir::entryInfoList();
+ if (!fulllist)
+ return 0;
+
+ entrylist.clear();
+
+ QFileInfoListIterator it(*fulllist);
+ for (; it.current(); ++it)
+ {
+ if (!ignorelist.matches(it.current()) && !GlobalIgnoreList().matches(it.current()))
+ entrylist.append(it.current());
+ }
+
+ return &entrylist;
+}
+
+
+// Local Variables:
+// c-basic-offset: 4
+// End:
diff --git a/cervisia/cvsdir.h b/cervisia/cvsdir.h
new file mode 100644
index 00000000..8f732163
--- /dev/null
+++ b/cervisia/cvsdir.h
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 1999-2002 Bernd Gehrmann
+ * bernd@mail.berlios.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.
+ *
+ * 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, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+
+#ifndef CVSDIR_H
+#define CVSDIR_H
+
+#include <qdir.h>
+
+
+class CvsDir : public QDir
+{
+public:
+ explicit CvsDir(const QString &path);
+
+ const QFileInfoList *entryInfoList() const;
+
+private:
+ mutable QFileInfoList entrylist;
+};
+
+#endif
+
+
+// Local Variables:
+// c-basic-offset: 4
+// End:
+
diff --git a/cervisia/cvsinitdlg.cpp b/cervisia/cvsinitdlg.cpp
new file mode 100644
index 00000000..9de80759
--- /dev/null
+++ b/cervisia/cvsinitdlg.cpp
@@ -0,0 +1,91 @@
+/*
+ * Copyright (c) 2004 Christian Loose <christian.loose@kdemail.net>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the 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, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+
+#include "cvsinitdlg.h"
+
+#include <qlabel.h>
+#include <qlayout.h>
+#include <qpushbutton.h>
+
+#include <kfiledialog.h>
+#include <klineedit.h>
+#include <klocale.h>
+#include <kurlcompletion.h>
+
+
+using Cervisia::CvsInitDialog;
+
+
+CvsInitDialog::CvsInitDialog(QWidget* parent, const char* name)
+ : KDialogBase(parent, name, true, i18n("Create New Repository (cvs init)"),
+ Ok | Cancel, Ok, true)
+{
+ QFrame* mainWidget = makeMainWidget();
+ QVBoxLayout* mainLayout = new QVBoxLayout(mainWidget, 0, spacingHint());
+
+ QLabel* dirLabel = new QLabel(i18n("Repository folder:"), mainWidget);
+ mainLayout->addWidget(dirLabel);
+
+ QHBoxLayout* dirLayout = new QHBoxLayout(mainLayout);
+
+ m_directoryEdit = new KLineEdit(mainWidget);
+ m_directoryEdit->setFocus();
+
+ KURLCompletion* comp = new KURLCompletion();
+ m_directoryEdit->setCompletionObject(comp);
+ m_directoryEdit->setAutoDeleteCompletionObject(true);
+
+ dirLabel->setBuddy(m_directoryEdit);
+ dirLayout->addWidget(m_directoryEdit);
+
+ QPushButton* dirButton = new QPushButton("...", mainWidget);
+ dirButton->setFixedWidth(30);
+ dirLayout->addWidget(dirButton);
+
+ connect( dirButton, SIGNAL(clicked()),
+ this, SLOT(dirButtonClicked()) );
+ connect( m_directoryEdit, SIGNAL(textChanged(const QString&)),
+ this, SLOT(lineEditTextChanged(const QString&)));
+
+ enableButton(Ok, false);
+
+ setMinimumWidth(350);
+}
+
+
+QString CvsInitDialog::directory() const
+{
+ return m_directoryEdit->text();
+}
+
+
+void CvsInitDialog::dirButtonClicked()
+{
+ QString dir = KFileDialog::getExistingDirectory(m_directoryEdit->text());
+ if( !dir.isEmpty() )
+ m_directoryEdit->setText(dir);
+}
+
+
+void CvsInitDialog::lineEditTextChanged(const QString& text)
+{
+ enableButton(Ok, !text.stripWhiteSpace().isEmpty());
+}
+
+#include "cvsinitdlg.moc"
diff --git a/cervisia/cvsinitdlg.h b/cervisia/cvsinitdlg.h
new file mode 100644
index 00000000..007617a7
--- /dev/null
+++ b/cervisia/cvsinitdlg.h
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 2004 Christian Loose <christian.loose@kdemail.net>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the 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, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+
+#ifndef CERVISIA_CVSINITDLG_H
+#define CERVISIA_CVSINITDLG_H
+
+#include <kdialogbase.h>
+
+class KLineEdit;
+
+
+namespace Cervisia
+{
+
+
+class CvsInitDialog : public KDialogBase
+{
+ Q_OBJECT
+
+public:
+ CvsInitDialog(QWidget* parent = 0, const char* name = 0);
+
+ QString directory() const;
+
+private slots:
+ void dirButtonClicked();
+ void lineEditTextChanged(const QString& text);
+
+private:
+ KLineEdit* m_directoryEdit;
+};
+
+
+}
+
+#endif
diff --git a/cervisia/cvsservice/DESIGN b/cervisia/cvsservice/DESIGN
new file mode 100644
index 00000000..cbd414da
--- /dev/null
+++ b/cervisia/cvsservice/DESIGN
@@ -0,0 +1,108 @@
+OVERVIEW
+--------
+
+The cvs DCOP service consists of the following three parts:
+
+1. CvsService - The main interface to the functionality of the cvs command line
+ client. There is one method for each cvs command, e.g. add,
+ checkout, commit, etc... The methods assemble the command line
+ arguments, create a CvsJob and return a DCOPRef object for it
+ to the caller. There is one instance of this service for each
+ application instance.
+
+2. Repository - This DCOPObject manages the configuration data of the current
+ cvs repository. The data is automatically updated when other
+ service instances change it.
+
+3. CvsJob - This class represents a cvs job. You can execute and cancel it,
+ and you can retrieve the output of the cvs client by either
+ connecting to the proper DCOP signals or by using the output()
+ method. There are two types of jobs. First the non-concurrent
+ job which has to run alone, like cvs update or import. Second
+ the jobs which can run concurrently like cvs log or annotate.
+
+USAGE
+-----
+
+How-to use this service in C++ applications:
+
+ // start DCOP service
+ QString error;
+ QCString appId;
+
+ KApplication::startServiceByDesktopName("cvsservice", QStringList(), &error,
+ &appId);
+
+ // create stub for repository
+ Repository_stub repository(appId, "CvsRepository");
+
+ // set directory of working copy
+ repository.setWorkingCopy("/home/user/kde/kdesdk/cervisia");
+
+ // create stub for service
+ CvsService_stub cvsService(appId, "CvsService");
+
+ // call "cvs log" for cervisiapart.h
+ DCOPRef job = cvsService.log("cervisiapart.h");
+
+ // connect to signals to get output
+ connectDCOPSignal(job.app(), job.obj(), "jobExited(bool, int)", [MY SLOT]);
+ connectDCOPSignal(job.app(), job.obj(), "receivedStdout(QString)",
+ [MY SLOT]);
+
+ // execute the cvs command
+ job.execute();
+
+
+How-to use this service in a shell script:
+
+ #!/bin/sh
+
+ # start DCOP service
+ APP=`dcopstart cvsservice`
+
+ # set directory of working copy
+ dcop $APP CvsRepository setWorkingCopy /home/user/kde/kdesdk/cervisia
+
+ # call "cvs log" for cervisiapart.h
+ JOB=`dcop $APP CvsService log cervisiapart.h`
+
+ # execute the cvs command
+ dcop $JOB execute
+
+ # print the output on stdout
+ dcop $JOB output
+
+ # stop DCOP service
+ dcop $APP CvsService quit
+
+
+How-to use this service in a javascript:
+
+ #!/usr/bin/env kjscmd
+
+ var client = new DCOPClient(this);
+ if ( client.attach() )
+ {
+ // start DCOP service
+ var appID = client.dcopStart("cvsservice");
+
+ // set directory of working copy
+ client.send(appID, "CvsRepository", "setWorkingCopy(QString)", "/home/user/kde/kdesdk/cervisia");
+
+ // call "cvs log" for cervisiapart.h
+ var job = client.call(appID, "CvsService", "log(QString)", "cervisiapart.h");
+
+ // execute the cvs command
+ job.call("execute()");
+
+ // wait for job to finish
+ while( job.call("isRunning()") );
+
+ // print the output on stdout
+ var output = job.call("output()");
+ println(output);
+
+ // stop DCOP service
+ client.send(appID, "CvsService", "quit()");
+ }
diff --git a/cervisia/cvsservice/Makefile.am b/cervisia/cvsservice/Makefile.am
new file mode 100644
index 00000000..7b036036
--- /dev/null
+++ b/cervisia/cvsservice/Makefile.am
@@ -0,0 +1,54 @@
+#
+# CvsService Makefile.am
+#
+# Copyright (c) 2002-2003 Christian Loose <christian.loose@hamburg.de>
+#
+#
+
+INCLUDES = $(all_includes)
+
+# cvs DCOP service
+bin_PROGRAMS =
+kdeinit_LTLIBRARIES = cvsservice.la cvsaskpass.la
+
+cvsservice_la_LDFLAGS = $(all_libraries) $(KDE_PLUGIN) -module
+cvsservice_la_LIBADD = $(LIB_KIO)
+cvsservice_la_SOURCES = main.cpp cvsservice.cpp cvsjob.cpp \
+ cvsservice.skel cvsservice.stub cvsjob.skel cvsjob.stub \
+ repository.cpp repository.skel repository.stub sshagent.cpp \
+ cvsserviceutils.cpp cvsloginjob.cpp cvsloginjob.skel cvsloginjob.stub
+
+cvsaskpass_la_LDFLAGS = $(all_libraries) $(KDE_PLUGIN) -module
+cvsaskpass_la_LIBADD = $(LIB_KDEUI)
+cvsaskpass_la_SOURCES = cvsaskpass.cpp
+
+include_HEADERS = cvsservice_stub.h cvsjob_stub.h repository_stub.h
+noinst_HEADERS = cvsservice.h cvsjob.h repository.h cvsserviceutils.h \
+ sshagent.h
+
+# cvs DCOP service stub library
+lib_LTLIBRARIES = libcvsservice.la
+
+libcvsservice_la_LDFLAGS = $(all_libraries) -no-undefined -version-info 0:1
+libcvsservice_la_LIBADD = $(LIB_KDECORE)
+libcvsservice_la_SOURCES = cvsservice.stub cvsjob.stub repository.stub dummy.cpp
+
+dummy.cpp:
+ echo > dummy.cpp
+
+# let automoc handle all of the meta source files (moc)
+METASOURCES = AUTO
+
+# install .desktop file
+service_DATA = cvsservice.desktop
+servicedir = $(kde_servicesdir)
+
+# i18n
+messages:
+ $(XGETTEXT) *.cpp *.h -o $(podir)/cvsservice.pot
+
+# API documentation
+# Not activated because KDE_INIT_DOXYGEN is missing in
+# kdesdk's configure.in.in
+#DOXYGEN_REFERENCES = dcop kdecore kdeui
+#include ../../admin/Doxyfile.am
diff --git a/cervisia/cvsservice/TODO b/cervisia/cvsservice/TODO
new file mode 100644
index 00000000..d46d2f9a
--- /dev/null
+++ b/cervisia/cvsservice/TODO
@@ -0,0 +1,12 @@
+TODO
+----
+
+* Move handling of recent commit messages from CervisiaPart to
+ DCOP service
+
+* Add special job classes derived from CvsJob that take over
+ the parsing of cvs' output from Cervisia
+
+* Missing cvs functionality needed for Cervisia:
+ - cvs watch (add/remove)
+ - cvs diff (make patch)
diff --git a/cervisia/cvsservice/cvsaskpass.cpp b/cervisia/cvsservice/cvsaskpass.cpp
new file mode 100644
index 00000000..c5410dee
--- /dev/null
+++ b/cervisia/cvsservice/cvsaskpass.cpp
@@ -0,0 +1,77 @@
+/*
+ * Copyright (c) 2003 Christian Loose <christian.loose@hamburg.de>
+ *
+ * This program 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 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this program; see the file COPYING. If not, write to
+ * the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ */
+
+#include <qregexp.h>
+#include <kaboutdata.h>
+#include <kapplication.h>
+#include <kcmdlineargs.h>
+#include <klocale.h>
+#include <kpassdlg.h>
+
+#include <iostream>
+
+
+static KCmdLineOptions options[] =
+{
+ { "+[prompt]", I18N_NOOP("prompt"), 0 },
+ KCmdLineLastOption
+};
+
+
+extern "C" KDE_EXPORT int kdemain(int argc, char** argv)
+{
+ KAboutData about("cvsaskpass", I18N_NOOP("cvsaskpass"), "0.1",
+ I18N_NOOP("ssh-askpass for the CVS DCOP Service"),
+ KAboutData::License_LGPL,
+ I18N_NOOP("Copyright (c) 2003 Christian Loose"));
+
+ KCmdLineArgs::init(argc, argv, &about);
+ KCmdLineArgs::addCmdLineOptions(options);
+
+ // no need to register with the dcop server
+ KApplication::disableAutoDcopRegistration();
+ KApplication app;
+
+ // no need for session management
+ app.disableSessionManagement();
+
+ if( !KCmdLineArgs::parsedArgs()->count() )
+ return 1;
+
+ // parse repository name from the passed argument
+ QString prompt = KCmdLineArgs::parsedArgs()->arg(0);
+ QRegExp rx("(.*@.*)'s password:");
+ int pos = rx.search(prompt);
+
+ KPasswordDialog dlg(KPasswordDialog::Password, false, 0);
+ dlg.setPrompt(i18n("Please type in your password below."));
+
+ if( pos > -1 )
+ dlg.addLine(i18n("Repository:"), rx.cap(1));
+
+ int res = dlg.exec();
+ if( res == KPasswordDialog::Accepted )
+ {
+ std::cout << dlg.password() << std::endl;
+ return 0;
+ }
+
+ return 1;
+}
diff --git a/cervisia/cvsservice/cvsjob.cpp b/cervisia/cvsservice/cvsjob.cpp
new file mode 100644
index 00000000..1178de96
--- /dev/null
+++ b/cervisia/cvsservice/cvsjob.cpp
@@ -0,0 +1,236 @@
+/*
+ * Copyright (c) 2002-2003 Christian Loose <christian.loose@hamburg.de>
+ *
+ * This program 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 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this program; see the file COPYING. If not, write to
+ * the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ */
+
+#include "cvsjob.h"
+
+#include <qfile.h>
+#include <kdebug.h>
+#include <kprocess.h>
+
+#include "sshagent.h"
+
+
+struct CvsJob::Private
+{
+ Private() : isRunning(false)
+ {
+ childproc = new KProcess;
+ childproc->setUseShell(true, "/bin/sh");
+ }
+ ~Private() { delete childproc; }
+
+ KProcess* childproc;
+ QString server;
+ QString rsh;
+ QString directory;
+ bool isRunning;
+ QStringList outputLines;
+};
+
+
+CvsJob::CvsJob(unsigned jobNum)
+ : QObject()
+ , DCOPObject()
+ , d(new Private)
+{
+ QString objId("CvsJob" + QString::number(jobNum));
+ setObjId(objId.local8Bit());
+}
+
+
+CvsJob::CvsJob(const QString& objId)
+ : QObject()
+ , DCOPObject()
+ , d(new Private)
+{
+ setObjId(objId.local8Bit());
+}
+
+
+CvsJob::~CvsJob()
+{
+ delete d;
+}
+
+
+void CvsJob::clearCvsCommand()
+{
+ d->childproc->clearArguments();
+}
+
+
+void CvsJob::setRSH(const QString& rsh)
+{
+ d->rsh = rsh;
+}
+
+
+void CvsJob::setServer(const QString& server)
+{
+ d->server = server;
+}
+
+
+void CvsJob::setDirectory(const QString& directory)
+{
+ d->directory = directory;
+}
+
+
+bool CvsJob::isRunning() const
+{
+ return d->isRunning;
+}
+
+
+CvsJob& CvsJob::operator<<(const QString& arg)
+{
+ *d->childproc << arg;
+ return *this;
+}
+
+
+CvsJob& CvsJob::operator<<(const char* arg)
+{
+ *d->childproc << arg;
+ return *this;
+}
+
+
+CvsJob& CvsJob::operator<<(const QCString& arg)
+{
+ *d->childproc << arg;
+ return *this;
+}
+
+
+CvsJob& CvsJob::operator<<(const QStringList& args)
+{
+ *d->childproc << args;
+ return *this;
+}
+
+
+QString CvsJob::cvsCommand() const
+{
+ QString command;
+
+ const QValueList<QCString>& args(d->childproc->args());
+ for (QValueList<QCString>::const_iterator it = args.begin(), itEnd = args.end();
+ it != itEnd; ++it)
+ {
+ if (!command.isEmpty())
+ command += ' ';
+
+ command += QFile::decodeName(*it);
+ }
+
+ return command;
+}
+
+
+QStringList CvsJob::output() const
+{
+ return d->outputLines;
+}
+
+
+bool CvsJob::execute()
+{
+ // setup job environment to use the ssh-agent (if it is running)
+ SshAgent ssh;
+ if( !ssh.pid().isEmpty() )
+ {
+ // kdDebug(8051) << "PID = " << ssh.pid() << endl;
+ // kdDebug(8051) << "SOCK = " << ssh.authSock() << endl;
+
+ d->childproc->setEnvironment("SSH_AGENT_PID", ssh.pid());
+ d->childproc->setEnvironment("SSH_AUTH_SOCK", ssh.authSock());
+ }
+
+ d->childproc->setEnvironment("SSH_ASKPASS", "cvsaskpass");
+
+ if( !d->rsh.isEmpty() )
+ d->childproc->setEnvironment("CVS_RSH", d->rsh);
+
+ if( !d->server.isEmpty() )
+ d->childproc->setEnvironment("CVS_SERVER", d->server);
+
+ if( !d->directory.isEmpty() )
+ d->childproc->setWorkingDirectory(d->directory);
+
+ connect(d->childproc, SIGNAL(processExited(KProcess*)),
+ SLOT(slotProcessExited()));
+ connect(d->childproc, SIGNAL(receivedStdout(KProcess*, char*, int)),
+ SLOT(slotReceivedStdout(KProcess*, char*, int)));
+ connect(d->childproc, SIGNAL(receivedStderr(KProcess*, char*, int)),
+ SLOT(slotReceivedStderr(KProcess*, char*, int)) );
+
+ kdDebug(8051) << "Execute cvs command: " << cvsCommand() << endl;
+
+ d->isRunning = true;
+ return d->childproc->start(KProcess::NotifyOnExit, KProcess::AllOutput);
+}
+
+
+void CvsJob::cancel()
+{
+ d->childproc->kill();
+}
+
+
+void CvsJob::slotProcessExited()
+{
+ // disconnect all connections to childproc's signals
+ d->childproc->disconnect();
+ d->childproc->clearArguments();
+
+ d->isRunning = false;
+
+ emit jobExited(d->childproc->normalExit(), d->childproc->exitStatus());
+}
+
+
+void CvsJob::slotReceivedStdout(KProcess* proc, char* buffer, int buflen)
+{
+ Q_UNUSED(proc);
+
+ QString output = QString::fromLocal8Bit(buffer, buflen);
+
+ // accumulate output
+ d->outputLines += QStringList::split("\n", output);
+
+ emit receivedStdout(output);
+}
+
+
+void CvsJob::slotReceivedStderr(KProcess* proc, char* buffer, int buflen)
+{
+ Q_UNUSED(proc);
+
+ QString output = QString::fromLocal8Bit(buffer, buflen);
+
+ // accumulate output
+ d->outputLines += QStringList::split("\n", output);
+
+ emit receivedStderr(output);
+}
+
+#include "cvsjob.moc"
diff --git a/cervisia/cvsservice/cvsjob.h b/cervisia/cvsservice/cvsjob.h
new file mode 100644
index 00000000..14194499
--- /dev/null
+++ b/cervisia/cvsservice/cvsjob.h
@@ -0,0 +1,83 @@
+/*
+ * Copyright (c) 2002-2003 Christian Loose <christian.loose@hamburg.de>
+ *
+ * This program 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 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this program; see the file COPYING. If not, write to
+ * the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ */
+
+#ifndef CVSJOB_H
+#define CVSJOB_H
+
+#include <qobject.h>
+#include <qstring.h>
+#include <qstringlist.h>
+#include <dcopobject.h>
+
+class KProcess;
+
+
+class KDE_EXPORT CvsJob : public QObject, public DCOPObject
+{
+ Q_OBJECT
+ K_DCOP
+
+public:
+ explicit CvsJob(unsigned jobNum);
+ explicit CvsJob(const QString& objId);
+ virtual ~CvsJob();
+
+ void clearCvsCommand();
+ void setRSH(const QString& rsh);
+ void setServer(const QString& server);
+ void setDirectory(const QString& directory);
+
+ CvsJob& operator<<(const QString& arg);
+ CvsJob& operator<<(const char* arg);
+ CvsJob& operator<<(const QCString& arg);
+ CvsJob& operator<<(const QStringList& args);
+
+k_dcop:
+ bool execute();
+ void cancel();
+
+ bool isRunning() const;
+
+ /**
+ * Current cvs command.
+ *
+ * @return The current cvs command. Can be null if not set.
+ */
+ QString cvsCommand() const;
+
+ QStringList output() const;
+
+k_dcop_signals:
+ void jobExited(bool normalExit, int status);
+ void receivedStdout(const QString& buffer);
+ void receivedStderr(const QString& buffer);
+
+private slots:
+ void slotProcessExited();
+ void slotReceivedStdout(KProcess* proc, char* buffer, int buflen);
+ void slotReceivedStderr(KProcess* proc, char* buffer, int buflen);
+
+private:
+ struct Private;
+ Private* d;
+};
+
+
+#endif
diff --git a/cervisia/cvsservice/cvsloginjob.cpp b/cervisia/cvsservice/cvsloginjob.cpp
new file mode 100644
index 00000000..79a9fa08
--- /dev/null
+++ b/cervisia/cvsservice/cvsloginjob.cpp
@@ -0,0 +1,156 @@
+/*
+ * Copyright (c) 2003 Christian Loose <christian.loose@hamburg.de>
+ *
+ * This program 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 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this program; see the file COPYING. If not, write to
+ * the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ */
+
+#include "cvsloginjob.h"
+
+#include <kdebug.h>
+#include <klocale.h>
+#include <kpassdlg.h>
+
+#include <sys/types.h>
+#include <signal.h>
+
+static const char LOGIN_PHRASE[] = "Logging in to";
+static const char FAILURE_PHRASE[] = "authorization failed:";
+static const char PASS_PHRASE[] = "CVS password: ";
+
+
+CvsLoginJob::CvsLoginJob(unsigned jobNum)
+ : DCOPObject()
+ , m_Proc(0)
+{
+ QString objId("CvsLoginJob" + QString::number(jobNum));
+ setObjId(objId.local8Bit());
+
+ m_Proc = new PtyProcess;
+}
+
+
+CvsLoginJob::~CvsLoginJob()
+{
+ delete m_Proc;
+}
+
+
+void CvsLoginJob::setServer(const QString& server)
+{
+ m_Server = server;
+}
+
+
+void CvsLoginJob::setCvsClient(const QCString& cvsClient)
+{
+ m_CvsClient = cvsClient;
+
+ m_Arguments.clear();
+ m_Arguments += "-f";
+}
+
+
+void CvsLoginJob::setRepository(const QCString& repository)
+{
+ m_Arguments += "-d";
+ m_Arguments += repository;
+ m_Arguments += "login";
+}
+
+
+bool CvsLoginJob::execute()
+{
+ static QCString repository;
+
+ int res = m_Proc->exec(m_CvsClient, m_Arguments);
+ if( res < 0 )
+ {
+ kdDebug(8051) << "Couldn't start 'cvs login' process!" << endl;
+ return false;
+ }
+
+ bool result = false;
+ while( true )
+ {
+ QCString line = m_Proc->readLine();
+ if( line.isNull() )
+ {
+ return result;
+ }
+
+ // add line to output list
+ m_output << line;
+ kdDebug(8051) << "process output = " << line << endl;
+
+ // retrieve repository from 'Logging in to'-line
+ if( line.contains(LOGIN_PHRASE) )
+ {
+ repository = line.remove(0, line.find(":pserver:"));
+ continue;
+ }
+
+ // process asks for the password
+ // search case insensitive as cvs and cvsnt use different capitalization
+ if( line.contains(PASS_PHRASE, false) )
+ {
+ kdDebug(8051) << "process waits for the password." << endl;
+
+ // show password dialog
+ // TODO: We really should display the repository name. Unfortunately
+ // the dialog doesn't show part of the repository name, because
+ // it's too long. :-(
+ QCString password;
+ int res = KPasswordDialog::getPassword(password, i18n("Please type "
+ "in your password for the repository below."));
+ if( res == KPasswordDialog::Accepted )
+ {
+ // send password to process
+ m_Proc->WaitSlave();
+ m_Proc->writeLine(password);
+
+ // wait for the result
+ while( !line.contains(FAILURE_PHRASE) )
+ {
+ line = m_Proc->readLine();
+ if( line.isNull() )
+ return true;
+
+ // add line to output list
+ m_output << line;
+ kdDebug(8051) << "process output = " << line << endl;
+ }
+
+ result = false;
+ }
+ else
+ {
+ // user pressed cancel so kill the process
+ kill(m_Proc->pid(), SIGKILL);
+ m_Proc->waitForChild();
+ result = false;
+ }
+ }
+ }
+
+ return false;
+}
+
+
+QStringList CvsLoginJob::output()
+{
+ return m_output;
+}
diff --git a/cervisia/cvsservice/cvsloginjob.h b/cervisia/cvsservice/cvsloginjob.h
new file mode 100644
index 00000000..0754074c
--- /dev/null
+++ b/cervisia/cvsservice/cvsloginjob.h
@@ -0,0 +1,58 @@
+/*
+ * Copyright (c) 2003 Christian Loose <christian.loose@hamburg.de>
+ *
+ * This program 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 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this program; see the file COPYING. If not, write to
+ * the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ */
+
+#ifndef CVSLOGINJOB_H
+#define CVSLOGINJOB_H
+
+#include <qstring.h>
+#include <qstringlist.h>
+#include <dcopobject.h>
+
+#include <kdesu/process.h>
+
+
+class CvsLoginJob : public DCOPObject
+{
+ K_DCOP
+
+public:
+ explicit CvsLoginJob(unsigned jobNum);
+ virtual ~CvsLoginJob();
+
+ void setServer(const QString& server);
+
+ void setCvsClient(const QCString& cvsClient);
+ void setRepository(const QCString& repository);
+
+k_dcop:
+ bool execute();
+ QStringList output();
+
+private:
+ PtyProcess* m_Proc;
+ QString m_Server;
+ QString m_Rsh;
+ QCString m_CvsClient;
+ QCStringList m_Arguments;
+ QStringList m_output;
+};
+
+
+#endif
diff --git a/cervisia/cvsservice/cvsservice.cpp b/cervisia/cvsservice/cvsservice.cpp
new file mode 100644
index 00000000..a5f02e20
--- /dev/null
+++ b/cervisia/cvsservice/cvsservice.cpp
@@ -0,0 +1,1008 @@
+/*
+ * Copyright (c) 2002-2004 Christian Loose <christian.loose@kdemail.net>
+ *
+ * This program 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 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this program; see the file COPYING. If not, write to
+ * the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ */
+
+#include "cvsservice.h"
+
+#include <qintdict.h>
+#include <qstring.h>
+
+#include <dcopref.h>
+#include <dcopclient.h>
+#include <kapplication.h>
+#include <kconfig.h>
+#include <klocale.h>
+#include <kmessagebox.h>
+#include <kprocess.h>
+
+#include "cvsjob.h"
+#include "cvsloginjob.h"
+#include "cvsserviceutils.h"
+#include "repository.h"
+#include "sshagent.h"
+
+
+static const char SINGLE_JOB_ID[] = "NonConcurrentJob";
+static const char REDIRECT_STDERR[] = "2>&1";
+
+enum WatchEvents { None=0, All=1, Commits=2, Edits=4, Unedits=8 };
+
+struct CvsService::Private
+{
+ Private() : singleCvsJob(0), lastJobId(0), repository(0) {}
+ ~Private()
+ {
+ delete repository;
+ delete singleCvsJob;
+ }
+
+ CvsJob* singleCvsJob; // non-concurrent cvs job, like update or commit
+ DCOPRef singleJobRef; // DCOP reference to non-concurrent cvs job
+ QIntDict<CvsJob> cvsJobs; // concurrent cvs jobs, like diff or annotate
+ QIntDict<CvsLoginJob> loginJobs;
+ unsigned lastJobId;
+
+ QCString appId; // cache the DCOP clients app id
+
+ Repository* repository;
+
+ CvsJob* createCvsJob();
+ DCOPRef setupNonConcurrentJob(Repository* repo = 0);
+
+ bool hasWorkingCopy();
+ bool hasRunningJob();
+};
+
+
+CvsService::CvsService()
+ : DCOPObject("CvsService")
+ , d(new Private)
+{
+ d->appId = kapp->dcopClient()->appId();
+
+ // create non-concurrent cvs job
+ d->singleCvsJob = new CvsJob(SINGLE_JOB_ID);
+ d->singleJobRef.setRef(d->appId, d->singleCvsJob->objId());
+
+ // create repository manager
+ d->repository = new Repository();
+
+ d->cvsJobs.setAutoDelete(true);
+ d->loginJobs.setAutoDelete(true);
+
+ KConfig* config = kapp->config();
+ KConfigGroupSaver cs(config, "General");
+ if( config->readBoolEntry("UseSshAgent", false) )
+ {
+ // use the existing or start a new ssh-agent
+ SshAgent ssh;
+ // TODO CL do we need the return value?
+ //bool res = ssh.querySshAgent();
+ ssh.querySshAgent();
+ }
+}
+
+
+CvsService::~CvsService()
+{
+ // kill the ssh-agent (when we started it)
+ SshAgent ssh;
+ ssh.killSshAgent();
+
+ d->cvsJobs.clear();
+ d->loginJobs.clear();
+ delete d;
+}
+
+
+DCOPRef CvsService::add(const QStringList& files, bool isBinary)
+{
+ if( !d->hasWorkingCopy() || d->hasRunningJob() )
+ return DCOPRef();
+
+ // assemble the command line
+ // cvs add [-kb] [FILES]
+ d->singleCvsJob->clearCvsCommand();
+
+ *d->singleCvsJob << d->repository->cvsClient() << "add";
+
+ if( isBinary )
+ *d->singleCvsJob << "-kb";
+
+ *d->singleCvsJob << CvsServiceUtils::joinFileList(files) << REDIRECT_STDERR;
+
+ return d->setupNonConcurrentJob();
+}
+
+
+DCOPRef CvsService::addWatch(const QStringList& files, int events)
+{
+ if( !d->hasWorkingCopy() || d->hasRunningJob() )
+ return DCOPRef();
+
+ // assemble the command line
+ d->singleCvsJob->clearCvsCommand();
+
+ *d->singleCvsJob << d->repository->cvsClient() << "watch add";
+
+ if( events != All )
+ {
+ if( events & Commits )
+ *d->singleCvsJob << "-a commit";
+ if( events & Edits )
+ *d->singleCvsJob << "-a edit";
+ if( events & Unedits )
+ *d->singleCvsJob << "-a unedit";
+ }
+
+ *d->singleCvsJob << CvsServiceUtils::joinFileList(files);
+
+ return d->setupNonConcurrentJob();
+}
+
+
+DCOPRef CvsService::annotate(const QString& fileName, const QString& revision)
+{
+ if( !d->hasWorkingCopy() )
+ return DCOPRef();
+
+ // create a cvs job
+ CvsJob* job = d->createCvsJob();
+
+ // assemble the command line
+ // (cvs log [FILE] && cvs annotate [-r rev] [FILE])
+ QString quotedName = KProcess::quote(fileName);
+ QString cvsClient = d->repository->cvsClient();
+
+ *job << "(" << cvsClient << "log" << quotedName << "&&"
+ << cvsClient << "annotate";
+
+ if( !revision.isEmpty() )
+ *job << "-r" << revision;
+
+ // *Hack*
+ // because the string "Annotations for blabla" is
+ // printed to stderr even with option -Q.
+ *job << quotedName << ")" << REDIRECT_STDERR;
+
+ // return a DCOP reference to the cvs job
+ return DCOPRef(d->appId, job->objId());
+}
+
+
+DCOPRef CvsService::checkout(const QString& workingDir, const QString& repository,
+ const QString& module, const QString& tag,
+ bool pruneDirs)
+{
+ if( d->hasRunningJob() )
+ return DCOPRef();
+
+ Repository repo(repository);
+
+ // assemble the command line
+ // cd [DIRECTORY] && cvs -d [REPOSITORY] checkout [-r tag] [-P] [MODULE]
+ d->singleCvsJob->clearCvsCommand();
+
+ *d->singleCvsJob << "cd" << KProcess::quote(workingDir) << "&&"
+ << repo.cvsClient()
+ << "-d" << repository
+ << "checkout";
+
+ if( !tag.isEmpty() )
+ *d->singleCvsJob << "-r" << tag;
+
+ if( pruneDirs )
+ *d->singleCvsJob << "-P";
+
+ *d->singleCvsJob << module;
+
+ return d->setupNonConcurrentJob(&repo);
+}
+
+
+DCOPRef CvsService::checkout(const QString& workingDir, const QString& repository,
+ const QString& module, const QString& tag,
+ bool pruneDirs, const QString& alias, bool exportOnly)
+{
+ if( d->hasRunningJob() )
+ return DCOPRef();
+
+ Repository repo(repository);
+
+ // assemble the command line
+ // cd [DIRECTORY] && cvs -d [REPOSITORY] co [-r tag] [-P] [-d alias] [MODULE]
+ d->singleCvsJob->clearCvsCommand();
+
+ *d->singleCvsJob << "cd" << KProcess::quote(workingDir) << "&&"
+ << repo.cvsClient()
+ << "-d" << repository;
+ if( exportOnly)
+ *d->singleCvsJob << "export";
+ else
+ *d->singleCvsJob << "checkout";
+
+ if( !tag.isEmpty() )
+ *d->singleCvsJob << "-r" << tag;
+
+ if( pruneDirs && !exportOnly )
+ *d->singleCvsJob << "-P";
+
+ if( !alias.isEmpty() )
+ *d->singleCvsJob << "-d" << alias;
+
+ *d->singleCvsJob << module;
+
+ return d->setupNonConcurrentJob(&repo);
+}
+
+DCOPRef CvsService::checkout(const QString& workingDir, const QString& repository,
+ const QString& module, const QString& tag,
+ bool pruneDirs, const QString& alias, bool exportOnly,
+ bool recursive)
+{
+ if( d->hasRunningJob() )
+ return DCOPRef();
+
+ Repository repo(repository);
+
+ // assemble the command line
+ // cd [DIRECTORY] && cvs -d [REPOSITORY] co [-r tag] [-P] [-d alias] [MODULE]
+ d->singleCvsJob->clearCvsCommand();
+
+ *d->singleCvsJob << "cd" << KProcess::quote(workingDir) << "&&"
+ << repo.cvsClient()
+ << "-d" << repository;
+ if( exportOnly)
+ *d->singleCvsJob << "export";
+ else
+ *d->singleCvsJob << "checkout";
+
+ if( !tag.isEmpty() )
+ *d->singleCvsJob << "-r" << tag;
+
+ if( pruneDirs && !exportOnly )
+ *d->singleCvsJob << "-P";
+
+ if( !alias.isEmpty() )
+ *d->singleCvsJob << "-d" << alias;
+
+ if( ! recursive )
+ *d->singleCvsJob << "-l";
+
+ *d->singleCvsJob << module;
+
+ return d->setupNonConcurrentJob(&repo);
+}
+
+DCOPRef CvsService::commit(const QStringList& files, const QString& commitMessage,
+ bool recursive)
+{
+ if( !d->hasWorkingCopy() || d->hasRunningJob() )
+ return DCOPRef();
+
+ // assemble the command line
+ // cvs commit [-l] [-m MESSAGE] [FILES]
+ d->singleCvsJob->clearCvsCommand();
+
+ *d->singleCvsJob << d->repository->cvsClient() << "commit";
+
+ if( !recursive )
+ *d->singleCvsJob << "-l";
+
+ *d->singleCvsJob << "-m" << KProcess::quote(commitMessage)
+ << CvsServiceUtils::joinFileList(files) << REDIRECT_STDERR;
+
+ return d->setupNonConcurrentJob();
+}
+
+
+DCOPRef CvsService::createRepository(const QString& repository)
+{
+ if( d->hasRunningJob() )
+ return DCOPRef();
+
+ // assemble the command line
+ // cvs -d [REPOSITORY] init
+ d->singleCvsJob->clearCvsCommand();
+
+ *d->singleCvsJob << "mkdir -p" << KProcess::quote(repository) << "&&"
+ << d->repository->cvsClient()
+ << "-d" << KProcess::quote(repository)
+ << "init";
+
+ return d->setupNonConcurrentJob();
+}
+
+
+DCOPRef CvsService::createTag(const QStringList& files, const QString& tag,
+ bool branch, bool force)
+{
+ if( !d->hasWorkingCopy() || d->hasRunningJob() )
+ return DCOPRef();
+
+ // assemble the command line
+ // cvs tag [-b] [-F] [TAG] [FILES]
+ d->singleCvsJob->clearCvsCommand();
+
+ *d->singleCvsJob << d->repository->cvsClient() << "tag";
+
+ if( branch )
+ *d->singleCvsJob << "-b";
+
+ if( force )
+ *d->singleCvsJob << "-F";
+
+ *d->singleCvsJob << KProcess::quote(tag)
+ << CvsServiceUtils::joinFileList(files);
+
+ return d->setupNonConcurrentJob();
+}
+
+
+DCOPRef CvsService::deleteTag(const QStringList& files, const QString& tag,
+ bool branch, bool force)
+{
+ if( !d->hasWorkingCopy() || d->hasRunningJob() )
+ return DCOPRef();
+
+ // assemble the command line
+ // cvs tag -d [-b] [-F] [TAG] [FILES]
+ d->singleCvsJob->clearCvsCommand();
+
+ *d->singleCvsJob << d->repository->cvsClient() << "tag" << "-d";
+
+ if( branch )
+ *d->singleCvsJob << "-b";
+
+ if( force )
+ *d->singleCvsJob << "-F";
+
+ *d->singleCvsJob << KProcess::quote(tag)
+ << CvsServiceUtils::joinFileList(files);
+
+ return d->setupNonConcurrentJob();
+}
+
+
+DCOPRef CvsService::downloadCvsIgnoreFile(const QString& repository,
+ const QString& outputFile)
+{
+ Repository repo(repository);
+
+ // create a cvs job
+ CvsJob* job = d->createCvsJob();
+
+ // assemble the command line
+ // cvs -d [REPOSITORY] -q checkout -p CVSROOT/cvsignore > [OUTPUTFILE]
+ *job << repo.cvsClient() << "-d" << repository
+ << "-q checkout -p CVSROOT/cvsignore >"
+ << KProcess::quote(outputFile);
+
+ // return a DCOP reference to the cvs job
+ return DCOPRef(d->appId, job->objId());
+}
+
+
+DCOPRef CvsService::downloadRevision(const QString& fileName,
+ const QString& revision,
+ const QString& outputFile)
+{
+ if( !d->hasWorkingCopy() )
+ return DCOPRef();
+
+ // create a cvs job
+ CvsJob* job = d->createCvsJob();
+
+ // assemble the command line
+ // cvs update -p -r [REV] [FILE] > [OUTPUTFILE]
+ *job << d->repository->cvsClient() << "update -p";
+
+ if( !revision.isEmpty() )
+ *job << "-r" << KProcess::quote(revision);
+
+ *job << KProcess::quote(fileName) << ">" << KProcess::quote(outputFile);
+
+ // return a DCOP reference to the cvs job
+ return DCOPRef(d->appId, job->objId());
+}
+
+
+DCOPRef CvsService::downloadRevision(const QString& fileName,
+ const QString& revA,
+ const QString& outputFileA,
+ const QString& revB,
+ const QString& outputFileB)
+{
+ if( !d->hasWorkingCopy() )
+ return DCOPRef();
+
+ // create a cvs job
+ CvsJob* job = d->createCvsJob();
+
+ // assemble the command line
+ // cvs update -p -r [REVA] [FILE] > [OUTPUTFILEA] ;
+ // cvs update -p -r [REVB] [FILE] > [OUTPUTFILEB]
+ *job << d->repository->cvsClient() << "update -p"
+ << "-r" << KProcess::quote(revA)
+ << KProcess::quote(fileName) << ">" << KProcess::quote(outputFileA)
+ << ";" << d->repository->cvsClient() << "update -p"
+ << "-r" << KProcess::quote(revB)
+ << KProcess::quote(fileName) << ">" << KProcess::quote(outputFileB);
+
+ // return a DCOP reference to the cvs job
+ return DCOPRef(d->appId, job->objId());
+}
+
+
+DCOPRef CvsService::diff(const QString& fileName, const QString& revA,
+ const QString& revB, const QString& diffOptions,
+ unsigned contextLines)
+{
+ // cvs diff [DIFFOPTIONS] -U CONTEXTLINES [-r REVA] {-r REVB] [FILE]
+ QString format = "-U" + QString::number(contextLines);
+ return diff(fileName, revA, revB, diffOptions, format);
+}
+
+
+DCOPRef CvsService::diff(const QString& fileName, const QString& revA,
+ const QString& revB, const QString& diffOptions,
+ const QString& format)
+{
+ if( !d->hasWorkingCopy() )
+ return DCOPRef();
+
+ // create a cvs job
+ CvsJob* job = d->createCvsJob();
+
+ // assemble the command line
+ // cvs diff [DIFFOPTIONS] [FORMAT] [-r REVA] {-r REVB] [FILE]
+ *job << d->repository->cvsClient() << "diff" << diffOptions
+ << format;
+
+ if( !revA.isEmpty() )
+ *job << "-r" << KProcess::quote(revA);
+
+ if( !revB.isEmpty() )
+ *job << "-r" << KProcess::quote(revB);
+
+ *job << KProcess::quote(fileName);
+
+ // return a DCOP reference to the cvs job
+ return DCOPRef(d->appId, job->objId());
+}
+
+
+DCOPRef CvsService::edit(const QStringList& files)
+{
+ if( !d->hasWorkingCopy() || d->hasRunningJob() )
+ return DCOPRef();
+
+ // assemble the command line
+ // cvs edit [FILES]
+ d->singleCvsJob->clearCvsCommand();
+
+ *d->singleCvsJob << d->repository->cvsClient() << "edit"
+ << CvsServiceUtils::joinFileList(files);
+
+ return d->setupNonConcurrentJob();
+}
+
+
+DCOPRef CvsService::editors(const QStringList& files)
+{
+ if( !d->hasWorkingCopy() || d->hasRunningJob() )
+ return DCOPRef();
+
+ // assemble the command line
+ // cvs editors [FILES]
+ d->singleCvsJob->clearCvsCommand();
+
+ *d->singleCvsJob << d->repository->cvsClient() << "editors"
+ << CvsServiceUtils::joinFileList(files);
+
+ return d->setupNonConcurrentJob();
+}
+
+
+DCOPRef CvsService::history()
+{
+ if( !d->hasWorkingCopy() )
+ return DCOPRef();
+
+ // create a cvs job
+ CvsJob* job = d->createCvsJob();
+
+ // assemble the command line
+ // cvs history -e -a
+ *job << d->repository->cvsClient() << "history -e -a";
+
+ // return a DCOP reference to the cvs job
+ return DCOPRef(d->appId, job->objId());
+}
+
+
+DCOPRef CvsService::import(const QString& workingDir, const QString& repository,
+ const QString& module, const QString& ignoreList,
+ const QString& comment, const QString& vendorTag,
+ const QString& releaseTag, bool importAsBinary)
+{
+ if( d->hasRunningJob() )
+ return DCOPRef();
+
+ Repository repo(repository);
+
+ // assemble the command line
+ d->singleCvsJob->clearCvsCommand();
+
+ *d->singleCvsJob << "cd" << KProcess::quote(workingDir) << "&&"
+ << repo.cvsClient()
+ << "-d" << repository
+ << "import";
+
+ if( importAsBinary )
+ *d->singleCvsJob << "-kb";
+
+ const QString ignore = ignoreList.stripWhiteSpace();
+ if( !ignore.isEmpty() )
+ *d->singleCvsJob << "-I" << KProcess::quote(ignore);
+
+ QString logMessage = comment.stripWhiteSpace();
+ logMessage.prepend("\"");
+ logMessage.append("\"");
+ *d->singleCvsJob << "-m" << logMessage;
+
+ *d->singleCvsJob << module << vendorTag << releaseTag;
+
+ return d->setupNonConcurrentJob(&repo);
+}
+
+
+DCOPRef CvsService::import(const QString& workingDir, const QString& repository,
+ const QString& module, const QString& ignoreList,
+ const QString& comment, const QString& vendorTag,
+ const QString& releaseTag, bool importAsBinary,
+ bool useModificationTime)
+{
+ if( d->hasRunningJob() )
+ return DCOPRef();
+
+ Repository repo(repository);
+
+ // assemble the command line
+ d->singleCvsJob->clearCvsCommand();
+
+ *d->singleCvsJob << "cd" << KProcess::quote(workingDir) << "&&"
+ << repo.cvsClient()
+ << "-d" << repository
+ << "import";
+
+ if( importAsBinary )
+ *d->singleCvsJob << "-kb";
+
+ if( useModificationTime )
+ *d->singleCvsJob << "-d";
+
+ const QString ignore = ignoreList.stripWhiteSpace();
+ if( !ignore.isEmpty() )
+ *d->singleCvsJob << "-I" << KProcess::quote(ignore);
+
+ QString logMessage = comment.stripWhiteSpace();
+ logMessage.prepend("\"");
+ logMessage.append("\"");
+ *d->singleCvsJob << "-m" << logMessage;
+
+ *d->singleCvsJob << module << vendorTag << releaseTag;
+
+ return d->setupNonConcurrentJob(&repo);
+}
+
+
+DCOPRef CvsService::lock(const QStringList& files)
+{
+ if( !d->hasWorkingCopy() || d->hasRunningJob() )
+ return DCOPRef();
+
+ // assemble the command line
+ // cvs admin -l [FILES]
+ d->singleCvsJob->clearCvsCommand();
+
+ *d->singleCvsJob << d->repository->cvsClient() << "admin -l"
+ << CvsServiceUtils::joinFileList(files);
+
+ return d->setupNonConcurrentJob();
+}
+
+
+DCOPRef CvsService::log(const QString& fileName)
+{
+ if( !d->hasWorkingCopy() )
+ return DCOPRef();
+
+ // create a cvs job
+ CvsJob* job = d->createCvsJob();
+
+ // assemble the command line
+ // cvs log [FILE]
+ *job << d->repository->cvsClient() << "log" << KProcess::quote(fileName);
+
+ // return a DCOP reference to the cvs job
+ return DCOPRef(d->appId, job->objId());
+}
+
+
+DCOPRef CvsService::login(const QString& repository)
+{
+ if( repository.isEmpty() )
+ return DCOPRef();
+
+ Repository repo(repository);
+
+ // create a cvs job
+ ++(d->lastJobId);
+
+ CvsLoginJob* job = new CvsLoginJob(d->lastJobId);
+ d->loginJobs.insert(d->lastJobId, job);
+
+ // TODO: CVS_SERVER doesn't work ATM
+// job->setServer(repo.server());
+
+ // assemble the command line
+ // cvs -d [REPOSITORY] login
+ job->setCvsClient(repo.clientOnly().local8Bit());
+ job->setRepository(repository.local8Bit());
+
+ // return a DCOP reference to the cvs job
+ return DCOPRef(d->appId, job->objId());
+}
+
+
+DCOPRef CvsService::logout(const QString& repository)
+{
+ if( repository.isEmpty() )
+ return DCOPRef();
+
+ Repository repo(repository);
+
+ // create a cvs job
+ ++(d->lastJobId);
+
+ CvsJob* job = new CvsJob(d->lastJobId);
+ d->cvsJobs.insert(d->lastJobId, job);
+
+ job->setRSH(repo.rsh());
+ job->setServer(repo.server());
+ job->setDirectory(repo.workingCopy());
+
+ // assemble the command line
+ // cvs -d [REPOSITORY] logout
+ *job << repo.cvsClient() << "-d" << repository << "logout";
+
+ // return a DCOP reference to the cvs job
+ return DCOPRef(d->appId, job->objId());
+}
+
+
+DCOPRef CvsService::makePatch()
+{
+ return makePatch("", "-u");
+}
+
+
+DCOPRef CvsService::makePatch(const QString& diffOptions, const QString& format)
+{
+ if( !d->hasWorkingCopy() )
+ return DCOPRef();
+
+ // create a cvs job
+ CvsJob* job = d->createCvsJob();
+
+ // assemble the command line
+ // cvs diff [DIFFOPTIONS] [FORMAT] -R 2>/dev/null
+ *job << d->repository->cvsClient() << "diff" << diffOptions << format << "-R"
+ << "2>/dev/null";
+
+ // return a DCOP reference to the cvs job
+ return DCOPRef(d->appId, job->objId());
+}
+
+
+DCOPRef CvsService::moduleList(const QString& repository)
+{
+ Repository repo(repository);
+
+ // create a cvs job
+ ++(d->lastJobId);
+
+ CvsJob* job = new CvsJob(d->lastJobId);
+ d->cvsJobs.insert(d->lastJobId, job);
+
+ job->setRSH(repo.rsh());
+ job->setServer(repo.server());
+ job->setDirectory(repo.workingCopy());
+
+ // assemble the command line
+ // cvs -d [REPOSITORY] checkout -c
+ *job << repo.cvsClient() << "-d" << repository << "checkout -c";
+
+ // return a DCOP reference to the cvs job
+ return DCOPRef(d->appId, job->objId());
+}
+
+
+DCOPRef CvsService::remove(const QStringList& files, bool recursive)
+{
+ if( !d->hasWorkingCopy() || d->hasRunningJob() )
+ return DCOPRef();
+
+ // assemble the command line
+ // cvs remove -f [-l] [FILES]
+ d->singleCvsJob->clearCvsCommand();
+
+ *d->singleCvsJob << d->repository->cvsClient() << "remove -f";
+
+ if( !recursive )
+ *d->singleCvsJob << "-l";
+
+ *d->singleCvsJob << CvsServiceUtils::joinFileList(files) << REDIRECT_STDERR;
+
+ return d->setupNonConcurrentJob();
+}
+
+
+DCOPRef CvsService::removeWatch(const QStringList& files, int events)
+{
+ if( !d->hasWorkingCopy() || d->hasRunningJob() )
+ return DCOPRef();
+
+ // assemble the command line
+ d->singleCvsJob->clearCvsCommand();
+
+ *d->singleCvsJob << d->repository->cvsClient() << "watch remove";
+
+ if( events != All )
+ {
+ if( events & Commits )
+ *d->singleCvsJob << "-a commit";
+ if( events & Edits )
+ *d->singleCvsJob << "-a edit";
+ if( events & Unedits )
+ *d->singleCvsJob << "-a unedit";
+ }
+
+ *d->singleCvsJob << CvsServiceUtils::joinFileList(files);
+
+ return d->setupNonConcurrentJob();
+}
+
+
+DCOPRef CvsService::rlog(const QString& repository, const QString& module,
+ bool recursive)
+{
+ Repository repo(repository);
+
+ // create a cvs job
+ ++(d->lastJobId);
+
+ CvsJob* job = new CvsJob(d->lastJobId);
+ d->cvsJobs.insert(d->lastJobId, job);
+
+ job->setRSH(repo.rsh());
+ job->setServer(repo.server());
+
+ // assemble the command line
+ // cvs -d [REPOSITORY] rlog [-l] [MODULE]
+ *job << repo.cvsClient() << "-d" << repository << "rlog";
+
+ if( !recursive )
+ *job << "-l";
+
+ *job << module;
+
+ // return a DCOP reference to the cvs job
+ return DCOPRef(d->appId, job->objId());
+}
+
+
+DCOPRef CvsService::simulateUpdate(const QStringList& files, bool recursive,
+ bool createDirs, bool pruneDirs)
+{
+ if( !d->hasWorkingCopy() || d->hasRunningJob() )
+ return DCOPRef();
+
+ // assemble the command line
+ // cvs -n update [-l] [-d] [-P] [FILES]
+ d->singleCvsJob->clearCvsCommand();
+
+ *d->singleCvsJob << d->repository->cvsClient() << "-n -q update";
+
+ if( !recursive )
+ *d->singleCvsJob << "-l";
+
+ if( createDirs )
+ *d->singleCvsJob << "-d";
+
+ if( pruneDirs )
+ *d->singleCvsJob << "-P";
+
+ *d->singleCvsJob << CvsServiceUtils::joinFileList(files) << REDIRECT_STDERR;
+
+ return d->setupNonConcurrentJob();
+}
+
+
+DCOPRef CvsService::status(const QStringList& files, bool recursive, bool tagInfo)
+{
+ if( !d->hasWorkingCopy() )
+ return DCOPRef();
+
+ // create a cvs job
+ CvsJob* job = d->createCvsJob();
+
+ // assemble the command line
+ // cvs status [-l] [-v] [FILES]
+ *job << d->repository->cvsClient() << "status";
+
+ if( !recursive )
+ *job << "-l";
+
+ if( tagInfo )
+ *job << "-v";
+
+ *job << CvsServiceUtils::joinFileList(files);
+
+ // return a DCOP reference to the cvs job
+ return DCOPRef(d->appId, job->objId());
+}
+
+
+DCOPRef CvsService::unedit(const QStringList& files)
+{
+ if( !d->hasWorkingCopy() || d->hasRunningJob() )
+ return DCOPRef();
+
+ // assemble the command line
+ // echo y | cvs unedit [FILES]
+ d->singleCvsJob->clearCvsCommand();
+
+ *d->singleCvsJob << "echo y |"
+ << d->repository->cvsClient() << "unedit"
+ << CvsServiceUtils::joinFileList(files);
+
+ return d->setupNonConcurrentJob();
+}
+
+
+DCOPRef CvsService::unlock(const QStringList& files)
+{
+ if( !d->hasWorkingCopy() || d->hasRunningJob() )
+ return DCOPRef();
+
+ // assemble the command line
+ // cvs admin -u [FILES]
+ d->singleCvsJob->clearCvsCommand();
+
+ *d->singleCvsJob << d->repository->cvsClient() << "admin -u"
+ << CvsServiceUtils::joinFileList(files);
+
+ return d->setupNonConcurrentJob();
+}
+
+
+DCOPRef CvsService::update(const QStringList& files, bool recursive,
+ bool createDirs, bool pruneDirs, const QString& extraOpt)
+{
+ if( !d->hasWorkingCopy() || d->hasRunningJob() )
+ return DCOPRef();
+
+ // assemble the command line
+ // cvs update [-l] [-d] [-P] [EXTRAOPTIONS] [FILES]
+ d->singleCvsJob->clearCvsCommand();
+
+ *d->singleCvsJob << d->repository->cvsClient() << "-q update";
+
+ if( !recursive )
+ *d->singleCvsJob << "-l";
+
+ if( createDirs )
+ *d->singleCvsJob << "-d";
+
+ if( pruneDirs )
+ *d->singleCvsJob << "-P";
+
+ *d->singleCvsJob << extraOpt << CvsServiceUtils::joinFileList(files)
+ << REDIRECT_STDERR;
+
+ return d->setupNonConcurrentJob();
+}
+
+
+DCOPRef CvsService::watchers(const QStringList& files)
+{
+ if( !d->hasWorkingCopy() || d->hasRunningJob() )
+ return DCOPRef();
+
+ // assemble the command line
+ // cvs watchers [FILES]
+ d->singleCvsJob->clearCvsCommand();
+
+ *d->singleCvsJob << d->repository->cvsClient() << "watchers"
+ << CvsServiceUtils::joinFileList(files);
+
+ return d->setupNonConcurrentJob();
+}
+
+
+void CvsService::quit()
+{
+ kapp->quit();
+}
+
+
+CvsJob* CvsService::Private::createCvsJob()
+{
+ ++lastJobId;
+
+ // create a cvs job
+ CvsJob* job = new CvsJob(lastJobId);
+ cvsJobs.insert(lastJobId, job);
+
+ job->setRSH(repository->rsh());
+ job->setServer(repository->server());
+ job->setDirectory(repository->workingCopy());
+
+ return job;
+}
+
+
+DCOPRef CvsService::Private::setupNonConcurrentJob(Repository* repo)
+{
+ // no explicit repository provided?
+ if( !repo )
+ repo = repository;
+
+ singleCvsJob->setRSH(repo->rsh());
+ singleCvsJob->setServer(repo->server());
+ singleCvsJob->setDirectory(repo->workingCopy());
+
+ return singleJobRef;
+}
+
+
+bool CvsService::Private::hasWorkingCopy()
+{
+ if( repository->workingCopy().isEmpty() )
+ {
+ KMessageBox::sorry(0, i18n("You have to set a local working copy "
+ "directory before you can use this function!"));
+ return false;
+ }
+
+ return true;
+}
+
+
+bool CvsService::Private::hasRunningJob()
+{
+ bool result = singleCvsJob->isRunning();
+
+ if( result )
+ KMessageBox::sorry(0, i18n("There is already a job running"));
+
+ return result;
+}
diff --git a/cervisia/cvsservice/cvsservice.desktop b/cervisia/cvsservice/cvsservice.desktop
new file mode 100644
index 00000000..31cd6dad
--- /dev/null
+++ b/cervisia/cvsservice/cvsservice.desktop
@@ -0,0 +1,73 @@
+[Desktop Entry]
+Type=Service
+Name=CvsService
+Name[br]=Servij Cvs
+Name[bs]=CvsServis
+Name[ca]=Servei de CVS
+Name[cs]=CVS služba
+Name[cy]=GwasanaethCVS
+Name[de]=CVS-Dienst
+Name[el]=Cvs υπηÏεσία
+Name[eo]=CvsServo
+Name[es]=Servicio CVS
+Name[et]=CVS teenus
+Name[fi]=Cvs-palvelu
+Name[gl]=Servizo CVS
+Name[hi]=सीवीà¤à¤¸-सरà¥à¤µà¤¿à¤¸
+Name[hu]=CVS szolgáltatás
+Name[it]=Servizio CVS
+Name[ja]=CVS サービス
+Name[lt]=CvsTarnyba
+Name[nds]=CVS-Deenst
+Name[pt_BR]=ServiçoCVS
+Name[sv]=CVS-tjänst
+Name[ta]=Cvsசேவை
+Name[tg]=ҲизматиCvs
+Name[zh_TW]=CVS æœå‹™
+Exec=cvsservice
+X-DCOP-ServiceType=Multi
+X-KDE-StartupNotify=false
+Comment=A DCOP service that provides an interface to cvs
+Comment[bg]=УÑлуга на DCOP, коÑто предлага Ð¸Ð½Ñ‚ÐµÑ€Ñ„ÐµÐ¹Ñ ÐºÑŠÐ¼ CVS
+Comment[bs]=DCOP servis koji pruža interfejs na CVS
+Comment[ca]=Un servei DCOP que proporciona una interfície per al cvs
+Comment[cs]=DCOP služba poskytující rozhraní k CVS
+Comment[cy]=Gwasanaeth DCOP sy'n darparu rhyngwyneb i cvs
+Comment[da]=En DCOP-tjeneste der sørger for en CVS-grænseflade
+Comment[de]=Ein DCOP-Dienst, der eine Schnittstelle zu CVS bereitstellt
+Comment[el]=Μια υπηÏεσία DCOP που Ï€ÏοσφέÏει ένα πεÏιβάλλον χÏήσης για το cvs
+Comment[es]=Un servicio DCOP que proporciona una interfaz para cvs
+Comment[et]=CVSi DCOP liidese teenus
+Comment[eu]=cvs-rako interfazea eskeintzen duen DCOP zerbitzua
+Comment[fa]=خدمت DCOP Ú©Ù‡ واسطی را برای cvs Ùراهم می‌کند
+Comment[fi]=DCOP-palvelu, joka tarjoaa rajapinnan cvs:lle
+Comment[fr]=Un service DCOP qui fournit une interface à CVS
+Comment[gl]=Un servizo de DCOP que fornece unha interface para CVS
+Comment[hi]=à¤à¤• डीकॉप सरà¥à¤µà¤¿à¤¸ जो सीवीà¤à¤¸ को इंटरफेस पà¥à¤°à¤¦à¤¾à¤¨ करता है
+Comment[hu]=DCOP-alapú szolgáltatás a CVS eléréséhez
+Comment[is]=DCOP þjónusta sem veitir viðmót á cvs
+Comment[it]=Un servizio DCOP che fornisce un'interfaccia a cvs
+Comment[ja]=CVS インターフェースをæä¾›ã™ã‚‹ DCOP サービス
+Comment[ka]=DCOP სერვისი, რáƒáƒ›áƒ”ლიც cvs-ს ინტერფეისს შეიცáƒáƒ•áƒ¡
+Comment[kk]=CVS интерфейÑін қамтамаÑыз ететін DCOP қызметі
+Comment[lt]=DCOP tarnyba, pateikianti cvs sÄ…sajÄ…
+Comment[nb]=En DCOP-tjeneste som tilbyr et grensesnitt mot cvs
+Comment[nds]=En DCOP-Deenst, wat en Koppelsteed na CVS praatstellt
+Comment[ne]=cvs मा इनà¥à¤Ÿà¤°à¤«à¥‡à¤¸ उपलबà¥à¤§ गरà¥à¤¨à¥‡ à¤à¤‰à¤Ÿà¤¾ डीसीओपी कारà¥à¤¯
+Comment[nl]=Een DCOP-dienst die een interface naar cvs biedt
+Comment[nn]=Ei DCOP-teneste som tilbyr eit grensesnitt mot CVS
+Comment[pl]=Usługa DCOP pozwalająca na dostęp do CVS
+Comment[pt]=Um serviço de DCOP que oferece uma interface para o CVS
+Comment[pt_BR]=Um serviço DCOP que provê uma interface para o cvs
+Comment[ru]=Ð¡ÐµÑ€Ð²Ð¸Ñ DCOP Ð´Ð»Ñ Ð¸Ð½Ñ‚ÐµÑ€Ñ„ÐµÐ¹Ñа Ñ cvs
+Comment[sk]=Služba DCOP pre prístup k CVS
+Comment[sl]=Storitev DCOP, ki omogoÄa vmesnik do CVS
+Comment[sr]=DCOP ÑÐµÑ€Ð²Ð¸Ñ ÐºÐ¾Ñ˜Ð¸ пружа Ð¸Ð½Ñ‚ÐµÑ€Ñ„ÐµÑ˜Ñ Ð·Ð° CVS
+Comment[sr@Latn]=DCOP servis koji pruža interfejs za CVS
+Comment[sv]=DCOP-tjänst som tillhandahåller ett gränssnitt till CVS
+Comment[ta]=ஒர௠cvsகà¯à®•à¯ ஒர௠இடைமà¯à®•à®¤à¯à®¤à®¿à®©à¯ˆ அளிகà¯à®•à®•à¯à®•à¯‚டிய DCOPசேவை
+Comment[tg]=Хизмати DCOP барои Ð¸Ð½Ñ‚ÐµÑ€Ñ„ÐµÐ¹Ñ Ð±Ð¾ cvs
+Comment[tr]= CVS'ye arayüz sağlayan bir DCOP Servisi
+Comment[uk]=Служба DCOP, Ñка надає Ñ–Ð½Ñ‚ÐµÑ€Ñ„ÐµÐ¹Ñ Ð´Ð¾ cvs
+Comment[zh_CN]=æä¾› CVS 接å£çš„ DCOP æœåŠ¡
+Comment[zh_TW]=æä¾› cvs 介é¢çš„ DCOP æœå‹™
diff --git a/cervisia/cvsservice/cvsservice.h b/cervisia/cvsservice/cvsservice.h
new file mode 100644
index 00000000..0cc43e66
--- /dev/null
+++ b/cervisia/cvsservice/cvsservice.h
@@ -0,0 +1,375 @@
+/*
+ * Copyright (c) 2002-2004 Christian Loose <christian.loose@kdemail.net>
+ *
+ * This program 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 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this program; see the file COPYING. If not, write to
+ * the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ */
+
+#ifndef CVSSERVICE_H
+#define CVSSERVICE_H
+
+#include <qstringlist.h>
+#include <dcopref.h>
+#include <dcopobject.h>
+
+class QString;
+
+
+class KDE_EXPORT CvsService : public DCOPObject
+{
+ K_DCOP
+
+public:
+ CvsService();
+ ~CvsService();
+
+k_dcop:
+ /**
+ * Adds new files to an existing project. The files don't actually
+ * appear in the repository until a subsequent commit is performed.
+ *
+ * @param files A list of files that should be added to the repository.
+ * @param isBinary Set to true to treat the files as binary files (-kb)
+ *
+ * @return A DCOP reference to the cvs job or in case of failure a
+ * null reference.
+ */
+ DCOPRef add(const QStringList& files, bool isBinary);
+
+ /**
+ */
+ DCOPRef addWatch(const QStringList& files, int events);
+
+ /**
+ * Shows information on who last modified each line of a file and when.
+ *
+ * @param fileName the name of the file to show annotations for
+ * @param revision show annotations for this revision (number or tag)
+ *
+ * @return A DCOP reference to the cvs job or in case of failure a
+ * null reference.
+ */
+ DCOPRef annotate(const QString& fileName, const QString& revision);
+
+ /**
+ * Checks out a module from the repository into a working copy.
+ *
+ * @param workingDir path to a local working copy directory
+ * @param repository
+ * @param module the name of the module
+ * @param tag
+ * @param pruneDirs remove empty directories from the working copy.
+ *
+ * @return A DCOP reference to the cvs job or in case of failure a
+ * null reference.
+ */
+ DCOPRef checkout(const QString& workingDir, const QString& repository,
+ const QString& module, const QString& tag, bool pruneDirs);
+
+ /**
+ * Checks out a module from the repository into a working copy.
+ *
+ * @param workingDir path to a local working copy directory
+ * @param repository
+ * @param module the name of the module
+ * @param tag
+ * @param pruneDirs remove empty directories from the working copy.
+ * @param alias alternative directory to check out to
+ * @param exportOnly flag to show we want a cvs export rather than a checkout
+ *
+ * @return A DCOP reference to the cvs job or in case of failure a
+ * null reference.
+ */
+ //### KDE4: merge with above checkout() method
+ DCOPRef checkout(const QString& workingDir, const QString& repository,
+ const QString& module, const QString& tag, bool pruneDirs,
+ const QString& alias, bool exportOnly);
+
+ /**
+ * Checks out a module from the repository into a working copy.
+ *
+ * @param workingDir path to a local working copy directory
+ * @param repository
+ * @param module the name of the module
+ * @param tag
+ * @param pruneDirs remove empty directories from the working copy.
+ * @param alias alternative directory to check out to
+ * @param exportOnly flag to show we want a cvs export rather than a checkout
+ * @param recursive check out dirs recursively
+ *
+ * @return A DCOP reference to the cvs job or in case of failure a
+ * null reference.
+ */
+ DCOPRef checkout(const QString& workingDir, const QString& repository,
+ const QString& module, const QString& tag, bool pruneDirs,
+ const QString& alias, bool exportOnly, bool recursive);
+
+ /**
+ *
+ * @param files A list of files with changes that should be committed to
+ * the repository.
+ * @param commitMessage log message describing the changes
+ * @param recursive
+ *
+ * @return A DCOP reference to the cvs job or in case of failure a
+ * null reference.
+ */
+ DCOPRef commit(const QStringList& files, const QString& commitMessage,
+ bool recursive);
+
+ /**
+ * Creates a new root repository.
+ *
+ * @param repository
+ */
+ DCOPRef createRepository(const QString& repository);
+
+ /**
+ */
+ DCOPRef createTag(const QStringList& files, const QString& tag,
+ bool branch, bool force);
+
+ /**
+ */
+ DCOPRef deleteTag(const QStringList& files, const QString& tag,
+ bool branch, bool force);
+
+ /**
+ */
+ DCOPRef downloadCvsIgnoreFile(const QString& repository,
+ const QString& outputFile);
+
+ /**
+ */
+ DCOPRef downloadRevision(const QString& fileName, const QString& revision,
+ const QString& outputFile);
+
+ /**
+ */
+ DCOPRef downloadRevision(const QString& fileName, const QString& revA,
+ const QString& outputFileA, const QString& revB,
+ const QString& outputFileB);
+
+ /**
+ *
+ * @param fileName
+ * @param revA
+ * @param revB
+ * @param diffOptions
+ * @param contextLines
+ *
+ * @return A DCOP reference to the cvs job or in case of failure a
+ * null reference.
+ */
+ DCOPRef diff(const QString& fileName, const QString& revA,
+ const QString& revB, const QString& diffOptions,
+ unsigned contextLines);
+
+ /**
+ *
+ * @param fileName
+ * @param revA
+ * @param revB
+ * @param diffOptions
+ * @param format
+ *
+ * @return A DCOP reference to the cvs job or in case of failure a
+ * null reference.
+ */
+ DCOPRef diff(const QString& fileName, const QString& revA,
+ const QString& revB, const QString& diffOptions,
+ const QString& format);
+
+ /**
+ * @param files
+ */
+ DCOPRef edit(const QStringList& files);
+
+ /**
+ * @param files
+ */
+ DCOPRef editors(const QStringList& files);
+
+ /**
+ * Shows a history of activity (like checkouts, commits, etc) in the
+ * repository for all users and all record types.
+ *
+ * @return A DCOP reference to the cvs job or in case of failure a
+ * null reference.
+ */
+ DCOPRef history();
+
+ /**
+ * @return A DCOP reference to the cvs job or in case of failure a
+ * null reference.
+ */
+ DCOPRef import(const QString& workingDir, const QString& repository,
+ const QString& module, const QString& ignoreList,
+ const QString& comment, const QString& vendorTag,
+ const QString& releaseTag, bool importAsBinary);
+
+ /**
+ * @return A DCOP reference to the cvs job or in case of failure a
+ * null reference.
+ */
+ //### KDE4: merge with above import() method
+ DCOPRef import(const QString& workingDir, const QString& repository,
+ const QString& module, const QString& ignoreList,
+ const QString& comment, const QString& vendorTag,
+ const QString& releaseTag, bool importAsBinary,
+ bool useModificationTime);
+
+ /**
+ * @param files
+ */
+ DCOPRef lock(const QStringList& files);
+
+ /**
+ * Shows log messages for a file.
+ *
+ * @param fileName the name of the file to show log messages for
+ *
+ * @return A DCOP reference to the cvs job or in case of failure a
+ * null reference.
+ */
+ DCOPRef log(const QString& fileName);
+
+ /**
+ * @param repository
+ *
+ * @return A DCOP reference to the cvs job or in case of failure a
+ * null reference.
+ */
+ DCOPRef login(const QString& repository);
+
+ /**
+ * @param repository
+ *
+ * @return A DCOP reference to the cvs job or in case of failure a
+ * null reference.
+ */
+ DCOPRef logout(const QString& repository);
+
+ /**
+ */
+ DCOPRef makePatch();
+
+ /**
+ */
+ //### KDE4: merge with above makePatch() method
+ DCOPRef makePatch(const QString& diffOptions, const QString& format);
+
+ /**
+ * @param repository
+ *
+ * @return A DCOP reference to the cvs job or in case of failure a
+ * null reference.
+ */
+ DCOPRef moduleList(const QString& repository);
+
+ /**
+ * Deletes files from the local working copy and schedules them to be
+ * removed from the repository. The files don't actually disappear from
+ * the repository until a subsequent commit is performed.
+ *
+ * @param files A list of files that should be removed from the repository.
+ * @param recursive descend into subdirectories.
+ *
+ * @return A DCOP reference to the cvs job or in case of failure a
+ * null reference.
+ */
+ DCOPRef remove(const QStringList& files, bool recursive);
+
+ /**
+ */
+ DCOPRef removeWatch(const QStringList& files, int events);
+
+ /**
+ */
+ DCOPRef rlog(const QString& repository, const QString& module,
+ bool recursive);
+
+ /**
+ * Shows a summary of what's been done locally, without changing the
+ * working copy. (cvs -n update)
+ *
+ * @param files
+ * @param recursive descend into subdirectories.
+ * @param createDirs
+ * @param pruneDirs
+ *
+ * @return A DCOP reference to the cvs job or in case of failure a
+ * null reference.
+ */
+ DCOPRef simulateUpdate(const QStringList& files, bool recursive,
+ bool createDirs, bool pruneDirs);
+
+ /**
+ * Shows the status of the files in the working copy.
+ *
+ * @param files
+ * @param recursive descend into subdirectories.
+ * @param tagInfo show tag information for the file.
+ *
+ * @return A DCOP reference to the cvs job or in case of failure a
+ * null reference.
+ */
+ DCOPRef status(const QStringList& files, bool recursive, bool tagInfo);
+
+ /**
+ * @param files
+ */
+ DCOPRef unedit(const QStringList& files);
+
+ /**
+ * @param files
+ */
+ DCOPRef unlock(const QStringList& files);
+
+ /**
+ * Merges changes from the repository into the files of the
+ * working copy.
+ *
+ * @param files A list of files that should be updated.
+ * @param recursive descend into subdirectories.
+ * @param createDirs create directories that exist in the repository
+ * but not yet in the working copy.
+ * @param pruneDirs remove empty directories from the working copy.
+ * @param extraOpt
+ *
+ * @return A DCOP reference to the cvs job or in case of failure a
+ * null reference.
+ */
+ DCOPRef update(const QStringList& files, bool recursive, bool createDirs,
+ bool pruneDirs, const QString& extraOpt);
+
+ /**
+ * @param files
+ */
+ DCOPRef watchers(const QStringList& files);
+
+ /**
+ * Quits the DCOP service.
+ */
+ void quit();
+
+private:
+ struct Private;
+ Private* d;
+};
+
+
+#endif
diff --git a/cervisia/cvsservice/cvsserviceutils.cpp b/cervisia/cvsservice/cvsserviceutils.cpp
new file mode 100644
index 00000000..73bfc531
--- /dev/null
+++ b/cervisia/cvsservice/cvsserviceutils.cpp
@@ -0,0 +1,45 @@
+/*
+ * Copyright (c) 2003 Christian Loose <christian.loose@hamburg.de>
+ *
+ * This program 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 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this program; see the file COPYING. If not, write to
+ * the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ */
+
+#include "cvsserviceutils.h"
+
+#include <qstring.h>
+#include <qstringlist.h>
+#include <kprocess.h>
+
+
+QString CvsServiceUtils::joinFileList(const QStringList& files)
+{
+ QString result;
+
+ QStringList::ConstIterator it = files.begin();
+ QStringList::ConstIterator end = files.end();
+
+ for( ; it != end; ++it )
+ {
+ result += KProcess::quote(*it);
+ result += " ";
+ }
+
+ if( result.length() > 0 )
+ result.truncate(result.length()-1);
+
+ return result;
+}
diff --git a/cervisia/cvsservice/cvsserviceutils.h b/cervisia/cvsservice/cvsserviceutils.h
new file mode 100644
index 00000000..8fb7290f
--- /dev/null
+++ b/cervisia/cvsservice/cvsserviceutils.h
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2003 Christian Loose <christian.loose@hamburg.de>
+ *
+ * This program 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 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this program; see the file COPYING. If not, write to
+ * the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ */
+
+#ifndef CVSSERVICE_UTILS_H
+#define CVSSERVICE_UTILS_H
+
+class QString;
+class QStringList;
+
+
+namespace CvsServiceUtils
+{
+
+/**
+ * Joins a list of file names to one QString and quotes
+ * each name properly for usage with KProcess.
+ */
+QString joinFileList(const QStringList& files);
+
+}
+
+
+#endif
diff --git a/cervisia/cvsservice/main.cpp b/cervisia/cvsservice/main.cpp
new file mode 100644
index 00000000..4f6c748d
--- /dev/null
+++ b/cervisia/cvsservice/main.cpp
@@ -0,0 +1,46 @@
+/*
+ * Copyright (c) 2002 Christian Loose <christian.loose@hamburg.de>
+ *
+ * This program 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 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this program; see the file COPYING. If not, write to
+ * the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ */
+
+#include <kaboutdata.h>
+#include <kapplication.h>
+#include <kcmdlineargs.h>
+#include <klocale.h>
+#include "cvsservice.h"
+
+
+extern "C" KDE_EXPORT int kdemain(int argc, char** argv)
+{
+ KAboutData about("cvsservice", I18N_NOOP("CVS DCOP service"), "0.1",
+ I18N_NOOP("DCOP service for CVS"), KAboutData::License_LGPL,
+ "Copyright (c) 2002-2003 Christian Loose");
+ about.addAuthor("Christian Loose", I18N_NOOP("Developer"),
+ "christian.loose@hamburg.de");
+
+ KCmdLineArgs::init(argc, argv, &about);
+
+ KApplication app;
+
+ // This app is started automatically, no need for session management
+ app.disableSessionManagement();
+
+ CvsService service;
+
+ return app.exec();
+}
diff --git a/cervisia/cvsservice/repository.cpp b/cervisia/cvsservice/repository.cpp
new file mode 100644
index 00000000..d2cff113
--- /dev/null
+++ b/cervisia/cvsservice/repository.cpp
@@ -0,0 +1,266 @@
+/*
+ * Copyright (c) 2002-2004 Christian Loose <christian.loose@kdemail.net>
+ *
+ * This program 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 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this program; see the file COPYING. If not, write to
+ * the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ */
+
+#include "repository.h"
+
+#include <qdir.h>
+#include <qfile.h>
+#include <qstring.h>
+
+#include <kapplication.h>
+#include <kconfig.h>
+#include <kdirwatch.h>
+#include <kstandarddirs.h>
+
+#include "sshagent.h"
+
+
+struct Repository::Private
+{
+ Private() : compressionLevel(0) {}
+
+ QString configFileName;
+
+ QString workingCopy;
+ QString location;
+
+ QString client;
+ QString rsh;
+ QString server;
+ int compressionLevel;
+ bool retrieveCvsignoreFile;
+
+ void readConfig();
+ void readGeneralConfig();
+};
+
+
+
+Repository::Repository()
+ : QObject()
+ , DCOPObject("CvsRepository")
+ , d(new Private)
+{
+ d->readGeneralConfig();
+
+ // other cvsservice instances might change the configuration file
+ // so we watch it for changes
+ d->configFileName = locate("config", "cvsservicerc");
+ KDirWatch* fileWatcher = new KDirWatch(this);
+ connect(fileWatcher, SIGNAL(dirty(const QString&)),
+ this, SLOT(slotConfigDirty(const QString&)));
+ fileWatcher->addFile(d->configFileName);
+}
+
+
+Repository::Repository(const QString& repository)
+ : QObject()
+ , DCOPObject()
+ , d(new Private)
+{
+ d->location = repository;
+ d->readGeneralConfig();
+ d->readConfig();
+
+ // other cvsservice instances might change the configuration file
+ // so we watch it for changes
+ d->configFileName = locate("config", "cvsservicerc");
+ KDirWatch* fileWatcher = new KDirWatch(this);
+ connect(fileWatcher, SIGNAL(dirty(const QString&)),
+ this, SLOT(slotConfigDirty(const QString&)));
+ fileWatcher->addFile(d->configFileName);
+}
+
+
+Repository::~Repository()
+{
+ delete d;
+}
+
+
+QString Repository::cvsClient() const
+{
+ QString client(d->client);
+
+ // suppress reading of the '.cvsrc' file
+ client += " -f";
+
+ // we don't need the command line option if there is no compression level set
+ if( d->compressionLevel > 0 )
+ {
+ client += " -z" + QString::number(d->compressionLevel) + " ";
+ }
+
+ return client;
+}
+
+
+QString Repository::clientOnly() const
+{
+ return d->client;
+}
+
+
+QString Repository::rsh() const
+{
+ return d->rsh;
+}
+
+
+QString Repository::server() const
+{
+ return d->server;
+}
+
+
+bool Repository::setWorkingCopy(const QString& dirName)
+{
+ const QFileInfo fi(dirName);
+ const QString path = fi.absFilePath();
+
+ // is this really a cvs-controlled directory?
+ const QFileInfo cvsDirInfo(path + "/CVS");
+ if( !cvsDirInfo.exists() || !cvsDirInfo.isDir() ||
+ !QFile::exists( cvsDirInfo.filePath() + "/Entries" ) ||
+ !QFile::exists( cvsDirInfo.filePath() + "/Repository" ) ||
+ !QFile::exists( cvsDirInfo.filePath() + "/Root" ) )
+ return false;
+
+ d->workingCopy = path;
+ d->location = QString::null;
+
+ // determine path to the repository
+ QFile rootFile(path + "/CVS/Root");
+ if( rootFile.open(IO_ReadOnly) )
+ {
+ QTextStream stream(&rootFile);
+ d->location = stream.readLine();
+ }
+ rootFile.close();
+
+ // add identities (ssh-add) to ssh-agent
+ // TODO CL make sure this is called only once
+ if( d->location.contains(":ext:", false) > 0 )
+ {
+ SshAgent ssh;
+ ssh.addSshIdentities();
+ }
+
+ QDir::setCurrent(path);
+ d->readConfig();
+
+ return true;
+}
+
+
+QString Repository::workingCopy() const
+{
+ return d->workingCopy;
+}
+
+
+QString Repository::location() const
+{
+ return d->location;
+}
+
+
+bool Repository::retrieveCvsignoreFile() const
+{
+ return d->retrieveCvsignoreFile;
+}
+
+
+void Repository::slotConfigDirty(const QString& fileName)
+{
+ if( fileName == d->configFileName )
+ {
+ // reread the configuration data from disk
+ kapp->config()->reparseConfiguration();
+ d->readConfig();
+ }
+}
+
+
+void Repository::Private::readGeneralConfig()
+{
+ KConfig* config = kapp->config();
+
+ // get path to cvs client programm
+ config->setGroup("General");
+ client = config->readPathEntry("CVSPath", "cvs");
+}
+
+
+void Repository::Private::readConfig()
+{
+ KConfig* config = kapp->config();
+
+ // Sometimes the location can be unequal to the entry in the CVS/Root.
+ //
+ // This can happen when the checkout was done with a repository name
+ // like :pserver:user@cvs.kde.org:/home/kde. When cvs then saves the
+ // name into the .cvspass file, it adds the default cvs port to it like
+ // this :pserver:user@cvs.kde.org:2401/home/kde. This name is then also
+ // used for the configuration group.
+ //
+ // In order to be able to read this group, we then have to manually add
+ // the port number to it.
+ QString repositoryGroup = QString::fromLatin1("Repository-") + location;
+ if( !config->hasGroup(repositoryGroup) )
+ {
+ // find the position of the first path separator
+ const int insertPos = repositoryGroup.find('/');
+ if( insertPos > 0 )
+ {
+ // add port to location
+ // (1) :pserver:user@hostname.com:/path
+ if( repositoryGroup.at(insertPos - 1) == ':' )
+ repositoryGroup.insert(insertPos, "2401");
+ // (2) :pserver:user@hostname.com/path
+ else
+ repositoryGroup.insert(insertPos, ":2401");
+ }
+ }
+
+ config->setGroup(repositoryGroup);
+
+ // should we retrieve the CVSROOT/cvsignore file from the cvs server?
+ retrieveCvsignoreFile = config->readBoolEntry("RetrieveCvsignore", false);
+
+ // see if there is a specific compression level set for this repository
+ compressionLevel = config->readNumEntry("Compression", -1);
+
+ // use default global compression level instead?
+ if( compressionLevel < 0 )
+ {
+ KConfigGroupSaver cs(config, "General");
+ compressionLevel = config->readNumEntry("Compression", 0);
+ }
+
+ // get remote shell client to access the remote repository
+ rsh = config->readPathEntry("rsh");
+
+ // get program to start on the server side
+ server = config->readEntry("cvs_server");
+}
+
+
+#include "repository.moc"
diff --git a/cervisia/cvsservice/repository.h b/cervisia/cvsservice/repository.h
new file mode 100644
index 00000000..c90277bc
--- /dev/null
+++ b/cervisia/cvsservice/repository.h
@@ -0,0 +1,109 @@
+/*
+ * Copyright (c) 2002-2003 Christian Loose <christian.loose@hamburg.de>
+ *
+ * This program 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 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this program; see the file COPYING. If not, write to
+ * the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ */
+
+#ifndef REPOSITORY_H
+#define REPOSITORY_H
+
+#include <qobject.h>
+#include <dcopobject.h>
+
+class QString;
+
+
+/**
+ * Represents a local or remote cvs repository with
+ * its repository-specific configuration data.
+ */
+class KDE_EXPORT Repository : public QObject, public DCOPObject
+{
+ K_DCOP
+ Q_OBJECT
+
+public:
+ Repository();
+ explicit Repository(const QString& repository);
+ ~Repository();
+
+ /**
+ * cvs command (including the user-specified path) with the options
+ * for this repository.
+ *
+ * @return A cvs command (including path).
+ */
+ QString cvsClient() const;
+
+ /**
+ */
+ QString clientOnly() const;
+
+ /**
+ * Remote shell command line client which should be used to
+ * access the remote cvs repository, when :ext: access method
+ * is specified. ($CVS_RSH)
+ *
+ * @return The remote shell client. Can be null if not set.
+ */
+ QString rsh() const;
+
+ /**
+ * Program to start on the server side when accessing a remote
+ * repository using :ext: access method. ($CVS_SERVER)
+ *
+ * @return The server program. Can be null if not set.
+ */
+ QString server() const;
+
+k_dcop:
+ /**
+ * Changes the working copy and the corresponding cvs repository.
+ *
+ * @param dirName path to the local working copy directory.
+ */
+ bool setWorkingCopy(const QString& dirName);
+
+ /**
+ * Path to the current working copy.
+ *
+ * @return The working copy directory. Can be null if not set.
+ */
+ QString workingCopy() const;
+
+ /**
+ * Path and method to access the current cvs repository.
+ * i.e. :pserver:user@cvs.project.org:/home/project
+ *
+ * @return The path and method to access the cvs repository.
+ */
+ QString location() const;
+
+ /**
+ */
+ bool retrieveCvsignoreFile() const;
+
+private slots:
+ void slotConfigDirty(const QString& fileName);
+
+private:
+ struct Private;
+ Private* d;
+};
+
+
+#endif
diff --git a/cervisia/cvsservice/sshagent.cpp b/cervisia/cvsservice/sshagent.cpp
new file mode 100644
index 00000000..48bc5eef
--- /dev/null
+++ b/cervisia/cvsservice/sshagent.cpp
@@ -0,0 +1,237 @@
+/*
+ * Copyright (c) 2003 Christian Loose <christian.loose@hamburg.de>
+ *
+ * This program 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 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this program; see the file COPYING. If not, write to
+ * the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ */
+
+#include "sshagent.h"
+
+#include <qregexp.h>
+#include <kapplication.h>
+#include <kdebug.h>
+#include <kdeversion.h>
+#include <kprocess.h>
+
+#include <stdlib.h>
+
+
+// initialize static member variables
+bool SshAgent::m_isRunning = false;
+bool SshAgent::m_isOurAgent = false;
+QString SshAgent::m_authSock = QString::null;
+QString SshAgent::m_pid = QString::null;
+
+
+SshAgent::SshAgent(QObject* parent, const char* name)
+ : QObject(parent, name)
+{
+}
+
+
+SshAgent::~SshAgent()
+{
+}
+
+
+bool SshAgent::querySshAgent()
+{
+ kdDebug(8051) << "SshAgent::querySshAgent(): ENTER" << endl;
+
+ if( m_isRunning )
+ return true;
+
+ // Did the user already start a ssh-agent process?
+ char* pid;
+ if( (pid = ::getenv("SSH_AGENT_PID")) != 0 )
+ {
+ kdDebug(8051) << "SshAgent::querySshAgent(): ssh-agent already exists"
+ << endl;
+
+ m_pid = QString::fromLocal8Bit(pid);
+
+ char* sock = ::getenv("SSH_AUTH_SOCK");
+ if( sock )
+ m_authSock = QString::fromLocal8Bit(sock);
+
+ m_isOurAgent = false;
+ m_isRunning = true;
+ }
+ // We have to start a new ssh-agent process
+ else
+ {
+ kdDebug(8051) << "SshAgent::querySshAgent(): start ssh-agent" << endl;
+
+ m_isOurAgent = true;
+ m_isRunning = startSshAgent();
+ }
+
+ return m_isRunning;
+}
+
+
+bool SshAgent::addSshIdentities()
+{
+ kdDebug(8051) << "SshAgent::addSshIdentities(): ENTER" << endl;
+
+ if( !m_isRunning || !m_isOurAgent )
+ return false;
+
+ // add identities to ssh-agent
+ KProcess proc;
+
+ proc.setEnvironment("SSH_AGENT_PID", m_pid);
+ proc.setEnvironment("SSH_AUTH_SOCK", m_authSock);
+ proc.setEnvironment("SSH_ASKPASS", "cvsaskpass");
+
+ proc << "ssh-add";
+
+ connect(&proc, SIGNAL(receivedStdout(KProcess*, char*, int)),
+ SLOT(slotReceivedStdout(KProcess*, char*, int)));
+ connect(&proc, SIGNAL(receivedStderr(KProcess*, char*, int)),
+ SLOT(slotReceivedStderr(KProcess*, char*, int)));
+
+ proc.start(KProcess::DontCare, KProcess::AllOutput);
+
+ // wait for process to finish
+ // TODO CL use timeout?
+ proc.wait();
+
+ kdDebug(8051) << "SshAgent::slotProcessExited(): added identities" << endl;
+
+ return (proc.normalExit() && proc.exitStatus() == 0);
+}
+
+
+void SshAgent::killSshAgent()
+{
+ kdDebug(8051) << "SshAgent::killSshAgent(): ENTER" << endl;
+
+ if( !m_isRunning || !m_isOurAgent )
+ return;
+
+ KProcess proc;
+
+ proc << "kill" << m_pid;
+
+ proc.start(KProcess::DontCare, KProcess::NoCommunication);
+
+ kdDebug(8051) << "SshAgent::killSshAgent(): killed pid = " << m_pid << endl;
+}
+
+
+void SshAgent::slotProcessExited(KProcess*)
+{
+ kdDebug(8051) << "SshAgent::slotProcessExited(): ENTER" << endl;
+
+ QRegExp cshPidRx("setenv SSH_AGENT_PID (\\d*);");
+ QRegExp cshSockRx("setenv SSH_AUTH_SOCK (.*);");
+
+ QRegExp bashPidRx("SSH_AGENT_PID=(\\d*).*");
+ QRegExp bashSockRx("SSH_AUTH_SOCK=(.*\\.\\d*);.*");
+
+ QStringList::Iterator it = m_outputLines.begin();
+ QStringList::Iterator end = m_outputLines.end();
+ for( ; it != end; ++it )
+ {
+ if( m_pid.isEmpty() )
+ {
+ int pos = cshPidRx.search(*it);
+ if( pos > -1 )
+ {
+ m_pid = cshPidRx.cap(1);
+ continue;
+ }
+
+ pos = bashPidRx.search(*it);
+ if( pos > -1 )
+ {
+ m_pid = bashPidRx.cap(1);
+ continue;
+ }
+ }
+
+ if( m_authSock.isEmpty() )
+ {
+ int pos = cshSockRx.search(*it);
+ if( pos > -1 )
+ {
+ m_authSock = cshSockRx.cap(1);
+ continue;
+ }
+
+ pos = bashSockRx.search(*it);
+ if( pos > -1 )
+ {
+ m_authSock = bashSockRx.cap(1);
+ continue;
+ }
+ }
+ }
+
+ kdDebug(8051) << "SshAgent::slotProcessExited(): pid = " << m_pid
+ << ", socket = " << m_authSock << endl;
+}
+
+
+void SshAgent::slotReceivedStdout(KProcess* proc, char* buffer, int buflen)
+{
+ Q_UNUSED(proc);
+
+ QString output = QString::fromLocal8Bit(buffer, buflen);
+ m_outputLines += QStringList::split("\n", output);
+
+ kdDebug(8051) << "SshAgent::slotReceivedStdout(): output = " << output << endl;
+}
+
+
+void SshAgent::slotReceivedStderr(KProcess* proc, char* buffer, int buflen)
+{
+ Q_UNUSED(proc);
+
+ QString output = QString::fromLocal8Bit(buffer, buflen);
+ m_outputLines += QStringList::split("\n", output);
+
+ kdDebug(8051) << "SshAgent::slotReceivedStderr(): output = " << output << endl;
+}
+
+
+bool SshAgent::startSshAgent()
+{
+ kdDebug(8051) << "SshAgent::startSshAgent(): ENTER" << endl;
+
+ KProcess proc;
+
+ proc << "ssh-agent";
+
+ connect(&proc, SIGNAL(processExited(KProcess*)),
+ SLOT(slotProcessExited(KProcess*)));
+ connect(&proc, SIGNAL(receivedStdout(KProcess*, char*, int)),
+ SLOT(slotReceivedStdout(KProcess*, char*, int)));
+ connect(&proc, SIGNAL(receivedStderr(KProcess*, char*, int)),
+ SLOT(slotReceivedStderr(KProcess*, char*, int)) );
+
+ proc.start(KProcess::NotifyOnExit, KProcess::All);
+
+ // wait for process to finish
+ // TODO CL use timeout?
+ proc.wait();
+
+ return (proc.normalExit() && proc.exitStatus() == 0);
+}
+
+
+#include "sshagent.moc"
diff --git a/cervisia/cvsservice/sshagent.h b/cervisia/cvsservice/sshagent.h
new file mode 100644
index 00000000..894a9026
--- /dev/null
+++ b/cervisia/cvsservice/sshagent.h
@@ -0,0 +1,64 @@
+/*
+ * Copyright (c) 2003 Christian Loose <christian.loose@hamburg.de>
+ *
+ * This program 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 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this program; see the file COPYING. If not, write to
+ * the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ */
+
+#ifndef SSHAGENT_H
+#define SSHAGENT_H
+
+#include <qobject.h>
+#include <qstring.h>
+#include <qstringlist.h>
+
+class KProcess;
+
+
+class SshAgent : public QObject
+{
+ Q_OBJECT
+
+public:
+ SshAgent(QObject* parent = 0, const char* name = 0);
+ ~SshAgent();
+
+ bool querySshAgent();
+ bool addSshIdentities();
+ void killSshAgent();
+
+ bool isRunning() const { return m_isRunning; }
+ QString pid() const { return m_pid; }
+ QString authSock() const { return m_authSock; }
+
+private slots:
+ void slotProcessExited(KProcess*);
+ void slotReceivedStdout(KProcess* proc, char* buffer, int buflen);
+ void slotReceivedStderr(KProcess* proc, char* buffer, int buflen);
+
+private:
+ bool startSshAgent();
+
+ QStringList m_outputLines;
+
+ static bool m_isRunning;
+ static bool m_isOurAgent;
+ static QString m_authSock;
+ static QString m_pid;
+};
+
+
+#endif
diff --git a/cervisia/diffdlg.cpp b/cervisia/diffdlg.cpp
new file mode 100644
index 00000000..8dcb5bdf
--- /dev/null
+++ b/cervisia/diffdlg.cpp
@@ -0,0 +1,509 @@
+/*
+ * Copyright (C) 1999-2002 Bernd Gehrmann
+ * bernd@mail.berlios.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.
+ *
+ * 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, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#include "diffdlg.h"
+
+#include <qpushbutton.h>
+#include <qcheckbox.h>
+#include <qcombobox.h>
+#include <qlabel.h>
+#include <qlayout.h>
+#include <qkeycode.h>
+#include <qfileinfo.h>
+#include <qregexp.h>
+#include <kconfig.h>
+#include <kfiledialog.h>
+#include <klocale.h>
+#include <kmessagebox.h>
+#include <ktempfile.h>
+#include <kprocess.h>
+
+#include "cvsservice_stub.h"
+#include "repository_stub.h"
+#include "misc.h"
+#include "progressdlg.h"
+#include "diffview.h"
+
+
+DiffDialog::DiffDialog(KConfig& cfg, QWidget *parent, const char *name, bool modal)
+ : KDialogBase(parent, name, modal, QString::null,
+ Close | Help | User1, Close, true, KStdGuiItem::saveAs())
+ , partConfig(cfg)
+{
+ items.setAutoDelete(true);
+ markeditem = -1;
+
+ QFrame* mainWidget = makeMainWidget();
+
+ QBoxLayout *layout = new QVBoxLayout(mainWidget, 0, spacingHint());
+
+ QGridLayout *pairlayout = new QGridLayout(layout);
+ pairlayout->setRowStretch(0, 0);
+ pairlayout->setRowStretch(1, 1);
+ pairlayout->setColStretch(1, 0);
+ pairlayout->addColSpacing(1, 16);
+ pairlayout->setColStretch(0, 10);
+ pairlayout->setColStretch(2, 10);
+
+ revlabel1 = new QLabel(mainWidget);
+ pairlayout->addWidget(revlabel1, 0, 0);
+
+ revlabel2 = new QLabel(mainWidget);
+ pairlayout->addWidget(revlabel2, 0, 2);
+
+ diff1 = new DiffView(cfg, true, false, mainWidget);
+ diff2 = new DiffView(cfg, true, true, mainWidget);
+ DiffZoomWidget *zoom = new DiffZoomWidget(cfg, mainWidget);
+ zoom->setDiffView(diff2);
+
+ pairlayout->addWidget(diff1, 1, 0);
+ pairlayout->addWidget(zoom, 1, 1);
+ pairlayout->addWidget(diff2, 1, 2);
+
+ diff1->setPartner(diff2);
+ diff2->setPartner(diff1);
+
+ syncbox = new QCheckBox(i18n("Synchronize scroll bars"), mainWidget);
+ syncbox->setChecked(true);
+ connect( syncbox, SIGNAL(toggled(bool)),
+ this, SLOT(toggleSynchronize(bool)) );
+
+ itemscombo = new QComboBox(mainWidget);
+ itemscombo->insertItem(QString::null);
+ connect( itemscombo, SIGNAL(activated(int)),
+ this, SLOT(comboActivated(int)) );
+
+ nofnlabel = new QLabel(mainWidget);
+ // avoids auto resize when the text is changed
+ nofnlabel->setMinimumWidth(fontMetrics().width(i18n("%1 differences").arg(10000)));
+
+ backbutton = new QPushButton(QString::fromLatin1("&<<"), mainWidget);
+ connect( backbutton, SIGNAL(clicked()), SLOT(backClicked()) );
+
+ forwbutton = new QPushButton(QString::fromLatin1("&>>"), mainWidget);
+ connect( forwbutton, SIGNAL(clicked()), SLOT(forwClicked()) );
+
+ connect( this, SIGNAL(user1Clicked()), SLOT(saveAsClicked()) );
+
+ QBoxLayout *buttonlayout = new QHBoxLayout(layout);
+ buttonlayout->addWidget(syncbox, 0);
+ buttonlayout->addStretch(4);
+ buttonlayout->addWidget(itemscombo);
+ buttonlayout->addStretch(1);
+ buttonlayout->addWidget(nofnlabel);
+ buttonlayout->addStretch(1);
+ buttonlayout->addWidget(backbutton);
+ buttonlayout->addWidget(forwbutton);
+
+ setHelp("diff");
+
+ setWFlags(Qt::WDestructiveClose | getWFlags());
+
+ QSize size = configDialogSize(partConfig, "DiffDialog");
+ resize(size);
+
+ KConfigGroupSaver cs(&partConfig, "DiffDialog");
+ syncbox->setChecked(partConfig.readBoolEntry("Sync"));
+}
+
+
+DiffDialog::~DiffDialog()
+{
+ saveDialogSize(partConfig, "DiffDialog");
+
+ KConfigGroupSaver cs(&partConfig, "DiffDialog");
+ partConfig.writeEntry("Sync", syncbox->isChecked());
+}
+
+
+void DiffDialog::keyPressEvent(QKeyEvent *e)
+{
+ switch (e->key())
+ {
+ case Key_Up:
+ diff1->up();
+ diff2->up();
+ break;
+ case Key_Down:
+ diff1->down();
+ diff2->down();
+ break;
+ case Key_Next:
+ diff1->next();
+ diff2->next();
+ break;
+ case Key_Prior:
+ diff1->prior();
+ diff2->prior();
+ break;
+ default:
+ KDialogBase::keyPressEvent(e);
+ }
+}
+
+
+void DiffDialog::toggleSynchronize(bool b)
+{
+ diff1->setPartner(b? diff2 : 0);
+ diff2->setPartner(b? diff1 : 0);
+}
+
+
+void DiffDialog::comboActivated(int index)
+{
+ updateHighlight(index-1);
+}
+
+
+static void interpretRegion(QString line, int *linenoA, int *linenoB)
+{
+ QRegExp region( "^@@ -([0-9]+),([0-9]+) \\+([0-9]+),([0-9]+) @@.*$" );
+
+ if (!region.exactMatch(line))
+ return;
+
+ *linenoA = region.cap(1).toInt() - 1;
+ *linenoB = region.cap(3).toInt() - 1;
+}
+
+
+static QString regionAsString(int linenoA, int linecountA, int linenoB, int linecountB)
+{
+ int lineendA = linenoA+linecountA-1;
+ int lineendB = linenoB+linecountB-1;
+ QString res;
+ if (linecountB == 0)
+ res = QString("%1,%2d%3").arg(linenoA).arg(lineendA).arg(linenoB-1);
+ else if (linecountA == 0)
+ res = QString("%1a%2,%3").arg(linenoA-1).arg(linenoB).arg(lineendB);
+ else if (linenoA == lineendA)
+ if (linenoB == lineendB)
+ res = QString("%1c%2").arg(linenoA).arg(linenoB);
+ else
+ res = QString("%1c%2,%3").arg(linenoA).arg(linenoB).arg(lineendB);
+ else if (linenoB == lineendB)
+ res = QString("%1,%2c%3").arg(linenoA).arg(lineendA).arg(linenoB);
+ else
+ res = QString("%1,%2c%3,%4").arg(linenoA).arg(lineendA).arg(linenoB).arg(lineendB);
+
+ return res;
+
+}
+
+
+class DiffItem
+{
+public:
+ DiffView::DiffType type;
+ int linenoA, linecountA;
+ int linenoB, linecountB;
+};
+
+
+bool DiffDialog::parseCvsDiff(CvsService_stub* service, const QString& fileName,
+ const QString &revA, const QString &revB)
+{
+ QStringList linesA, linesB;
+ int linenoA, linenoB;
+
+ setCaption(i18n("CVS Diff: %1").arg(fileName));
+ revlabel1->setText( revA.isEmpty()?
+ i18n("Repository:")
+ : i18n("Revision ")+revA+":" );
+ revlabel2->setText( revB.isEmpty()?
+ i18n("Working dir:")
+ : i18n("Revision ")+revB+":" );
+
+ KConfigGroupSaver cs(&partConfig, "General");
+
+ // Ok, this is a hack: When the user wants an external diff
+ // front end, it is executed from here. Of course, in that
+ // case this dialog wouldn't have to be created in the first
+ // place, but this design at least makes the handling trans-
+ // parent for the calling routines
+
+ QString extdiff = partConfig.readPathEntry("ExternalDiff");
+ if (!extdiff.isEmpty())
+ {
+ callExternalDiff(extdiff, service, fileName, revA, revB);
+ return false;
+ }
+
+ const QString diffOptions = partConfig.readEntry("DiffOptions");
+ const unsigned contextLines = partConfig.readUnsignedNumEntry("ContextLines", 65535);
+
+ DCOPRef job = service->diff(fileName, revA, revB, diffOptions, contextLines);
+ if( !service->ok() )
+ return false;
+
+ ProgressDialog dlg(this, "Diff", job, "diff", i18n("CVS Diff"));
+ if( !dlg.execute() )
+ return false;
+
+ // remember diff output for "save as" action
+ m_diffOutput = dlg.getOutput();
+
+ QString line;
+ while ( dlg.getLine(line) && !line.startsWith("+++"))
+ ;
+
+ linenoA = linenoB = 0;
+ while ( dlg.getLine(line) )
+ {
+ // line contains diff region?
+ if (line.startsWith("@@"))
+ {
+ interpretRegion(line, &linenoA, &linenoB);
+ diff1->addLine(line, DiffView::Separator);
+ diff2->addLine(line, DiffView::Separator);
+ continue;
+ }
+
+ if (line.length() < 1)
+ continue;
+
+ QChar marker = line[0];
+ line.remove(0, 1);
+
+ if (marker == '-')
+ linesA.append(line);
+ else if (marker == '+')
+ linesB.append(line);
+ else
+ {
+ if (!linesA.isEmpty() || !linesB.isEmpty())
+ {
+ newDiffHunk(linenoA, linenoB, linesA, linesB);
+
+ linesA.clear();
+ linesB.clear();
+ }
+ diff1->addLine(line, DiffView::Unchanged, ++linenoA);
+ diff2->addLine(line, DiffView::Unchanged, ++linenoB);
+ }
+ }
+
+ if (!linesA.isEmpty() || !linesB.isEmpty())
+ newDiffHunk(linenoA, linenoB, linesA, linesB);
+
+ // sets the right size as there is no more auto resize in QComboBox
+ itemscombo->adjustSize();
+
+ updateNofN();
+
+ return true;
+}
+
+
+void DiffDialog::newDiffHunk(int& linenoA, int& linenoB,
+ const QStringList& linesA, const QStringList& linesB)
+{
+ DiffItem *item = new DiffItem;
+ item->linenoA = linenoA+1;
+ item->linenoB = linenoB+1;
+ item->linecountA = linesA.count();
+ item->linecountB = linesB.count();
+ items.append(item);
+
+ const QString region = regionAsString(linenoA+1, linesA.count(),
+ linenoB+1, linesB.count());
+ itemscombo->insertItem(region);
+
+ QStringList::ConstIterator itA = linesA.begin();
+ QStringList::ConstIterator itB = linesB.begin();
+ while (itA != linesA.end() || itB != linesB.end())
+ {
+ if (itA != linesA.end())
+ {
+ diff1->addLine(*itA, DiffView::Neutral, ++linenoA);
+ if (itB != linesB.end())
+ diff2->addLine(*itB, DiffView::Change, ++linenoB);
+ else
+ diff2->addLine("", DiffView::Delete);
+ }
+ else
+ {
+ diff1->addLine("", DiffView::Neutral);
+ diff2->addLine(*itB, DiffView::Insert, ++linenoB);
+ }
+
+ if (itA != linesA.end())
+ ++itA;
+ if (itB != linesB.end())
+ ++itB;
+ }
+}
+
+
+void DiffDialog::callExternalDiff(const QString& extdiff, CvsService_stub* service,
+ const QString& fileName, const QString &revA,
+ const QString &revB)
+{
+ QString extcmdline = extdiff;
+ extcmdline += " ";
+
+ // create suffix for temporary file (used QFileInfo to remove path from file name)
+ const QString suffix = "-" + QFileInfo(fileName).fileName();
+
+ DCOPRef job;
+ if (!revA.isEmpty() && !revB.isEmpty())
+ {
+ // We're comparing two revisions
+ QString revAFilename = tempFileName(suffix+QString("-")+revA);
+ QString revBFilename = tempFileName(suffix+QString("-")+revB);
+
+ // download the files for revision A and B
+ job = service->downloadRevision(fileName, revA, revAFilename,
+ revB, revBFilename);
+ if( !service->ok() )
+ return;
+
+ extcmdline += KProcess::quote(revAFilename);
+ extcmdline += " ";
+ extcmdline += KProcess::quote(revBFilename);
+ }
+ else
+ {
+ // We're comparing to a file, and perhaps one revision
+ QString revAFilename = tempFileName(suffix+QString("-")+revA);
+ job = service->downloadRevision(fileName, revA, revAFilename);
+ if( !service->ok() )
+ return;
+
+ extcmdline += KProcess::quote(revAFilename);
+ extcmdline += " ";
+ extcmdline += KProcess::quote(QFileInfo(fileName).absFilePath());
+ }
+
+ ProgressDialog dlg(this, "Diff", job, "diff");
+ if( dlg.execute() )
+ {
+ // call external diff application
+ // TODO CL maybe use system()?
+ KProcess proc;
+ proc.setUseShell(true, "/bin/sh");
+ proc << extcmdline;
+ proc.start(KProcess::DontCare);
+ }
+}
+
+
+void DiffDialog::updateNofN()
+{
+ QString str;
+ if (markeditem >= 0)
+ str = i18n("%1 of %2").arg(markeditem+1).arg(items.count());
+ else
+ str = i18n("%1 differences").arg(items.count());
+ nofnlabel->setText(str);
+
+ itemscombo->setCurrentItem(markeditem==-2? 0 : markeditem+1);
+
+ backbutton->setEnabled(markeditem != -1);
+ forwbutton->setEnabled(markeditem != -2 && items.count());
+}
+
+
+void DiffDialog::updateHighlight(int newitem)
+{
+ if (markeditem >= 0)
+ {
+ DiffItem *item = items.at(markeditem);
+ for (int i = item->linenoA; i < item->linenoA+item->linecountA; ++i)
+ diff1->setInverted(i, false);
+ for (int i = item->linenoB; i < item->linenoB+item->linecountB; ++i)
+ diff2->setInverted(i, false);
+ }
+
+ markeditem = newitem;
+
+ if (markeditem >= 0)
+ {
+ DiffItem *item = items.at(markeditem);
+ for (int i = item->linenoA; i < item->linenoA+item->linecountA; ++i)
+ diff1->setInverted(i, true);
+ for (int i = item->linenoB; i < item->linenoB+item->linecountB; ++i)
+ diff2->setInverted(i, true);
+ diff1->setCenterLine(item->linenoA);
+ diff2->setCenterLine(item->linenoB);
+ }
+ diff1->repaint();
+ diff2->repaint();
+ updateNofN();
+}
+
+
+void DiffDialog::backClicked()
+{
+ int newitem;
+ if (markeditem == -1)
+ return; // internal error (button not disabled)
+ else if (markeditem == -2) // past end
+ newitem = items.count()-1;
+ else
+ newitem = markeditem-1;
+ updateHighlight(newitem);
+}
+
+
+void DiffDialog::forwClicked()
+{
+ int newitem;
+ if (markeditem == -2 || (markeditem == -1 && !items.count()))
+ return; // internal error (button not disabled)
+ else if (markeditem+1 == (int)items.count()) // past end
+ newitem = -2;
+ else
+ newitem = markeditem+1;
+ updateHighlight(newitem);
+}
+
+
+void DiffDialog::saveAsClicked()
+{
+ QString fileName = KFileDialog::getSaveFileName(QString::null, QString::null, this);
+ if( fileName.isEmpty() )
+ return;
+
+ if( !Cervisia::CheckOverwrite(fileName, this) )
+ return;
+
+ QFile f(fileName);
+ if( !f.open(IO_WriteOnly) )
+ {
+ KMessageBox::sorry(this,
+ i18n("Could not open file for writing."),
+ "Cervisia");
+ return;
+ }
+
+ QTextStream ts(&f);
+ QStringList::Iterator it = m_diffOutput.begin();
+ for( ; it != m_diffOutput.end(); ++it )
+ ts << *it << "\n";
+
+ f.close();
+}
+
+#include "diffdlg.moc"
+
+
+// Local Variables:
+// c-basic-offset: 4
+// End:
diff --git a/cervisia/diffdlg.h b/cervisia/diffdlg.h
new file mode 100644
index 00000000..25407c96
--- /dev/null
+++ b/cervisia/diffdlg.h
@@ -0,0 +1,87 @@
+/*
+ * Copyright (C) 1999-2002 Bernd Gehrmann
+ * bernd@mail.berlios.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.
+ *
+ * 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, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+
+#ifndef DIFFDLG_H
+#define DIFFDLG_H
+
+#include <qptrlist.h>
+#include <kdialogbase.h>
+
+
+class QLabel;
+class QCheckBox;
+class QComboBox;
+class KConfig;
+class DiffItem;
+class DiffView;
+class CvsService_stub;
+
+
+class DiffDialog : public KDialogBase
+{
+ Q_OBJECT
+
+public:
+
+ explicit DiffDialog( KConfig& config, QWidget *parent=0, const char *name=0,
+ bool modal=false );
+
+ virtual ~DiffDialog();
+
+ bool parseCvsDiff(CvsService_stub* service, const QString &fileName,
+ const QString &revA, const QString &revB);
+
+protected:
+ virtual void keyPressEvent(QKeyEvent *e);
+
+private slots:
+ void toggleSynchronize(bool b);
+ void comboActivated(int index);
+ void backClicked();
+ void forwClicked();
+ void saveAsClicked();
+
+private:
+ void newDiffHunk(int& linenoA, int& linenoB, const QStringList& linesA,
+ const QStringList& linesB);
+ void callExternalDiff(const QString& extdiff, CvsService_stub* service,
+ const QString& fileName, const QString& revA,
+ const QString& revB);
+ void updateNofN();
+ void updateHighlight(int newitem);
+
+ QLabel *revlabel1, *revlabel2, *nofnlabel;
+ QCheckBox *syncbox;
+ QComboBox *itemscombo;
+ QPushButton *backbutton, *forwbutton;
+ DiffView *diff1, *diff2;
+
+ QPtrList<DiffItem> items;
+ int markeditem;
+ KConfig& partConfig;
+ QStringList m_diffOutput;
+};
+
+#endif
+
+
+// Local Variables:
+// c-basic-offset: 4
+// End:
diff --git a/cervisia/diffview.cpp b/cervisia/diffview.cpp
new file mode 100644
index 00000000..1892880e
--- /dev/null
+++ b/cervisia/diffview.cpp
@@ -0,0 +1,507 @@
+/*
+ * Copyright (C) 1999-2002 Bernd Gehrmann
+ * bernd@mail.berlios.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.
+ *
+ * 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, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+
+#include "diffview.h"
+
+#include <qpainter.h>
+#include <qscrollbar.h>
+#include <qpixmap.h>
+#include <qregexp.h>
+#include <qstyle.h>
+
+#include <kapplication.h>
+#include <kconfig.h>
+#include <kdebug.h>
+#include <kglobalsettings.h>
+#include <klocale.h>
+
+
+class DiffViewItem
+{
+public:
+ QString line;
+ DiffView::DiffType type;
+ bool inverted;
+ int no;
+};
+
+
+int DiffViewItemList::compareItems(QPtrCollection::Item item1, QPtrCollection::Item item2)
+{
+ return (static_cast<DiffViewItem*>(item1)->no
+ == static_cast<DiffViewItem*>(item2)->no)? 0 : 1;
+}
+
+
+const int DiffView::BORDER = 7;
+
+
+DiffView::DiffView( KConfig& cfg, bool withlinenos, bool withmarker,
+ QWidget *parent, const char *name )
+ : QtTableView(parent, name, WRepaintNoErase)
+ , partConfig(cfg)
+{
+ setNumRows(0);
+ setNumCols( 1 + (withlinenos?1:0) + (withmarker?1:0) );
+ setTableFlags( Tbl_autoVScrollBar|Tbl_autoHScrollBar|
+ Tbl_smoothVScrolling );
+ setFrameStyle( QFrame::WinPanel | QFrame::Sunken );
+ setBackgroundMode( PaletteBase );
+ setWFlags( WResizeNoErase );
+
+ partConfig.setGroup("LookAndFeel");
+ setFont(partConfig.readFontEntry("DiffFont"));
+ QFontMetrics fm(font());
+ setCellHeight(fm.lineSpacing());
+ setCellWidth(0);
+ textwidth = 0;
+
+ partConfig.setGroup("General");
+ m_tabWidth = partConfig.readNumEntry("TabWidth", 8);
+
+ items.setAutoDelete(true);
+ linenos = withlinenos;
+ marker = withmarker;
+
+ partConfig.setGroup("Colors");
+ QColor defaultColor=QColor(237, 190, 190);
+ diffChangeColor=partConfig.readColorEntry("DiffChange",&defaultColor);
+ defaultColor=QColor(190, 190, 237);
+ diffInsertColor=partConfig.readColorEntry("DiffInsert",&defaultColor);
+ defaultColor=QColor(190, 237, 190);
+ diffDeleteColor=partConfig.readColorEntry("DiffDelete",&defaultColor);
+}
+
+
+void DiffView::setFont(const QFont &font)
+{
+ QtTableView::setFont(font);
+ QFontMetrics fm(font);
+ setCellHeight(fm.lineSpacing());
+}
+
+
+void DiffView::setPartner(DiffView *other)
+{
+ partner = other;
+ if (partner)
+ {
+ connect( verticalScrollBar(), SIGNAL(valueChanged(int)),
+ SLOT(vertPositionChanged(int)) );
+ connect( verticalScrollBar(), SIGNAL(sliderMoved(int)),
+ SLOT(vertPositionChanged(int)) );
+ connect( horizontalScrollBar(), SIGNAL(valueChanged(int)),
+ SLOT(horzPositionChanged(int)) );
+ connect( horizontalScrollBar(), SIGNAL(sliderMoved(int)),
+ SLOT(horzPositionChanged(int)) );
+ }
+}
+
+
+void DiffView::vertPositionChanged(int val)
+{
+ if (partner)
+ partner->setYOffset(QMIN(val,partner->maxYOffset()));
+}
+
+
+void DiffView::horzPositionChanged(int val)
+{
+ if (partner)
+ partner->setXOffset(QMIN(val,partner->maxXOffset()));
+}
+
+
+// *offset methods are only for views withlineno
+void DiffView::removeAtOffset(int offset)
+{
+ items.remove(offset);
+ setNumRows(numRows()-1);
+}
+
+
+void DiffView::insertAtOffset(const QString &line, DiffType type, int offset)
+{
+ DiffViewItem *item = new DiffViewItem;
+ item->line = line;
+ item->type = type;
+ item->no = -1;
+ item->inverted = false;
+ items.insert(offset, item);
+ setNumRows(numRows()+1);
+}
+
+
+void DiffView::setCenterOffset(int offset)
+{
+ if (!rowIsVisible(offset))
+ {
+ int visiblerows = viewHeight()/cellHeight(0);
+ setTopCell( QMAX(0, offset - visiblerows/2) );
+ }
+}
+
+
+void DiffView::addLine(const QString &line, DiffType type, int no)
+{
+ QFont f(font());
+ f.setBold(true);
+ QFontMetrics fmbold(f);
+ QFontMetrics fm(font());
+
+
+ // calculate textwidth based on 'line' where tabs are expanded
+ //
+ // *Please note*
+ // For some fonts, e.g. "Clean", is fm.maxWidth() greater than
+ // fmbold.maxWidth().
+ QString copy(line);
+ const int numTabs = copy.contains('\t', false);
+ copy.replace( QRegExp("\t"), "");
+
+ const int tabSize = m_tabWidth * QMAX(fm.maxWidth(), fmbold.maxWidth());
+ const int copyWidth = QMAX(fm.width(copy), fmbold.width(copy));
+ textwidth = QMAX(textwidth, copyWidth + numTabs * tabSize);
+
+ DiffViewItem *item = new DiffViewItem;
+ item->line = line;
+ item->type = type;
+ item->no = no;
+ item->inverted = false;
+ items.append(item);
+ setNumRows(numRows()+1);
+}
+
+
+QString DiffView::stringAtOffset(int offset)
+{
+ if (offset >= (int)items.count())
+ {
+ kdDebug(8050) << "Internal error: lineAtOffset" << endl;
+ }
+ return items.at(offset)->line;
+}
+
+
+int DiffView::count()
+{
+ return items.count();
+}
+
+
+int DiffView::findLine(int lineno)
+{
+ int offset;
+ DiffViewItem tmp;
+ tmp.no = lineno;
+ if ( (offset = items.find(&tmp)) == -1)
+ {
+ kdDebug(8050) << "Internal Error: Line " << lineno << " not found" << endl;
+ return -1;
+ }
+ return offset;
+}
+
+
+void DiffView::setInverted(int lineno, bool inverted)
+{
+ int offset;
+ if ( (offset = findLine(lineno)) != -1)
+ items.at(offset)->inverted = inverted;
+}
+
+
+void DiffView::setCenterLine(int lineno)
+{
+ int offset;
+ if ( (offset = findLine(lineno)) != -1)
+ setCenterOffset(offset);
+}
+
+
+QString DiffView::stringAtLine(int lineno)
+{
+ int pos;
+ if ( (pos = findLine(lineno)) != -1 )
+ return items.at(pos)->line;
+ else
+ return QString();
+}
+
+
+QByteArray DiffView::compressedContent()
+{
+ QByteArray res(items.count());
+
+ QPtrListIterator<DiffViewItem> it(items);
+ int i=0;
+ for (; it.current(); ++it)
+ {
+ switch (it.current()->type)
+ {
+ case Change: res[i] = 'C'; break;
+ case Insert: res[i] = 'I'; break;
+ case Delete: res[i] = 'D'; break;
+ case Neutral: res[i] = 'N'; break;
+ case Unchanged:res[i] = 'U'; break;
+ default: res[i] = ' ';
+ }
+ ++i;
+ }
+ return res;
+}
+
+
+int DiffView::cellWidth(int col)
+{
+ if (col == 0 && linenos)
+ {
+ QFontMetrics fm(font());
+ return fm.width("10000");
+ }
+ else if (marker && (col == 0 || col == 1))
+ {
+ QFontMetrics fm( fontMetrics() );
+ return QMAX(QMAX( fm.width(i18n("Delete")),
+ fm.width(i18n("Insert"))),
+ fm.width(i18n("Change")))+2*BORDER;
+ }
+ else
+ {
+ int rest = (linenos || marker)? cellWidth(0) : 0;
+ if (linenos && marker)
+ rest += cellWidth(1);
+ return QMAX(textwidth, viewWidth()-rest);
+ }
+}
+
+
+QSize DiffView::sizeHint() const
+{
+ QFontMetrics fm(font());
+ return QSize( 4*fm.width("0123456789"), fm.lineSpacing()*8 );
+}
+
+
+void DiffView::paintCell(QPainter *p, int row, int col)
+{
+ QFontMetrics fm(font());
+ p->setTabStops(m_tabWidth * fm.maxWidth());
+
+ DiffViewItem *item = items.at(row);
+
+ int width = cellWidth(col);
+ int height = cellHeight();
+
+ QColor backgroundColor;
+ bool inverted;
+ int align;
+ int innerborder;
+ QString str;
+
+ QFont oldFont(p->font());
+ if (item->type==Separator)
+ {
+ backgroundColor = KGlobalSettings::highlightColor();
+ p->setPen(KGlobalSettings::highlightedTextColor());
+ inverted = false;
+ align = AlignLeft;
+ innerborder = 0;
+ if (col == (linenos?1:0) + (marker?1:0))
+ str = item->line;
+ QFont f(oldFont);
+ f.setBold(true);
+ p->setFont(f);
+ }
+ else if (col == 0 && linenos)
+ {
+ backgroundColor = KGlobalSettings::highlightColor();
+ p->setPen(KGlobalSettings::highlightedTextColor());
+ inverted = false;
+ align = AlignLeft;
+ innerborder = 0;
+ if (item->no == -1)
+ str = "+++++";
+ else
+ str.setNum(item->no);
+ }
+ else if (marker && (col == 0 || col == 1))
+ {
+ backgroundColor = KGlobalSettings::alternateBackgroundColor();
+ p->setPen(KGlobalSettings::textColor());
+ inverted = false;
+ align = AlignRight;
+ innerborder = BORDER;
+ str = (item->type==Change)? i18n("Change")
+ : (item->type==Insert)? i18n("Insert")
+ : (item->type==Delete)? i18n("Delete") : QString::null;
+ }
+ else
+ {
+ backgroundColor =
+ (item->type==Change)? diffChangeColor
+ : (item->type==Insert)? diffInsertColor
+ : (item->type==Delete)? diffDeleteColor
+ : (item->type==Neutral)? KGlobalSettings::alternateBackgroundColor() : KGlobalSettings::baseColor();
+ p->setPen(KGlobalSettings::textColor());
+ inverted = item->inverted;
+ align = AlignLeft;
+ innerborder = 0;
+ str = item->line;
+ }
+
+ if (inverted)
+ {
+ p->setPen(backgroundColor);
+ backgroundColor = KGlobalSettings::textColor();
+ QFont f(oldFont);
+ f.setBold(true);
+ p->setFont(f);
+ }
+
+ p->fillRect(0, 0, width, height, backgroundColor);
+ p->drawText(innerborder, 0, width-2*innerborder, height, align|ExpandTabs, str);
+ p->setFont(oldFont);
+}
+
+
+void DiffView::wheelEvent(QWheelEvent *e)
+{
+ QApplication::sendEvent(verticalScrollBar(), e);
+}
+
+
+DiffZoomWidget::DiffZoomWidget(KConfig& cfg, QWidget *parent, const char *name)
+ : QFrame(parent, name)
+{
+ setSizePolicy( QSizePolicy( QSizePolicy::Fixed, QSizePolicy::Minimum ) );
+
+ cfg.setGroup("Colors");
+ QColor defaultColor=QColor(237, 190, 190);
+ diffChangeColor=cfg.readColorEntry("DiffChange",&defaultColor);
+ defaultColor=QColor(190, 190, 237);
+ diffInsertColor=cfg.readColorEntry("DiffInsert",&defaultColor);
+ defaultColor=QColor(190, 237, 190);
+ diffDeleteColor=cfg.readColorEntry("DiffDelete",&defaultColor);
+}
+
+
+DiffZoomWidget::~DiffZoomWidget()
+{}
+
+
+void DiffZoomWidget::setDiffView(DiffView *view)
+{
+ diffview = view;
+ QScrollBar *sb = const_cast<QScrollBar*>(diffview->scrollBar());
+ sb->installEventFilter(this);
+}
+
+
+QSize DiffZoomWidget::sizeHint() const
+{
+ return QSize(25, style().pixelMetric(QStyle::PM_ScrollBarExtent, this));
+}
+
+
+bool DiffZoomWidget::eventFilter(QObject *o, QEvent *e)
+{
+ if (e->type() == QEvent::Show
+ || e->type() == QEvent::Hide
+ || e->type() == QEvent::Resize)
+ repaint();
+
+ return QFrame::eventFilter(o, e);
+}
+
+
+void DiffZoomWidget::paintEvent(QPaintEvent *)
+{
+ const QScrollBar* scrollBar = diffview->scrollBar();
+ if (!scrollBar)
+ return;
+
+ // only y and height are important
+ const QRect scrollBarGroove(scrollBar->isVisible()
+ ? style().querySubControlMetrics(QStyle::CC_ScrollBar,
+ scrollBar,
+ QStyle::SC_ScrollBarGroove)
+ : rect());
+
+ // draw rectangles at the positions of the differences
+
+ const QByteArray& lineTypes(diffview->compressedContent());
+
+ QPixmap pixbuf(width(), scrollBarGroove.height());
+ pixbuf.fill(KGlobalSettings::baseColor());
+
+ QPainter p(&pixbuf, this);
+ if (const unsigned int numberOfLines = lineTypes.size())
+ {
+ const double scale(((double) scrollBarGroove.height()) / numberOfLines);
+ for (unsigned int index(0); index < numberOfLines;)
+ {
+ const char lineType(lineTypes[index]);
+
+ // don't use qRound() to avoid painting outside of the pixmap
+ // (yPos1 must be lesser than scrollBarGroove.height())
+ const int yPos1(static_cast<int>(index * scale));
+
+ // search next line with different lineType
+ for (++index; index < numberOfLines && lineType == lineTypes[index]; ++index)
+ ;
+
+ QColor color;
+ switch (lineType)
+ {
+ case 'C':
+ color = diffChangeColor;
+ break;
+ case 'I':
+ color = diffInsertColor;
+ break;
+ case 'D':
+ color = diffDeleteColor;
+ break;
+ case ' ':
+ case 'N':
+ color = KGlobalSettings::alternateBackgroundColor();
+ break;
+ }
+
+ if (color.isValid())
+ {
+ const int yPos2(qRound(index * scale));
+ const int areaHeight((yPos2 != yPos1) ? yPos2 - yPos1 : 1);
+
+ p.fillRect(0, yPos1, pixbuf.width(), areaHeight, QBrush(color));
+ }
+ }
+ }
+ p.flush();
+ bitBlt(this, 0, scrollBarGroove.y(), &pixbuf);
+}
+
+#include "diffview.moc"
+
+
+// Local Variables:
+// c-basic-offset: 4
+// End:
diff --git a/cervisia/diffview.h b/cervisia/diffview.h
new file mode 100644
index 00000000..b79c7189
--- /dev/null
+++ b/cervisia/diffview.h
@@ -0,0 +1,132 @@
+/*
+ * Copyright (C) 1999-2002 Bernd Gehrmann
+ * bernd@mail.berlios.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.
+ *
+ * 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, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+
+#ifndef DIFFVIEW_H
+#define DIFFVIEW_H
+
+
+#include "qttableview.h"
+
+#include <qptrcollection.h>
+#include <qptrlist.h>
+
+
+class KConfig;
+class DiffViewItem;
+
+
+class DiffViewItemList : public QPtrList<DiffViewItem>
+{
+protected:
+ virtual int compareItems(QPtrCollection::Item item1, QPtrCollection::Item item2);
+};
+
+
+class DiffView : public QtTableView
+{
+ Q_OBJECT
+
+public:
+ enum DiffType { Change, Insert, Delete, Neutral, Unchanged, Separator };
+
+ DiffView( KConfig& cfg, bool withlinenos, bool withmarker,
+ QWidget *parent=0, const char *name=0 );
+
+ void setPartner(DiffView *other);
+
+ void up()
+ { setTopCell(topCell()-1); }
+ void down()
+ { setTopCell(topCell()+1); }
+ void next()
+ { setTopCell(topCell()+viewHeight()/cellHeight()); }
+ void prior()
+ { setTopCell(topCell()-viewHeight()/cellHeight()); }
+
+ void addLine(const QString &line, DiffType type, int no=-1);
+ QString stringAtLine(int lineno);
+ void setCenterLine(int lineno);
+ void setInverted(int lineno, bool inverted);
+ int count();
+ void removeAtOffset(int offset);
+ void insertAtOffset(const QString &line, DiffType type, int offset);
+ void setCenterOffset(int offset);
+ QString stringAtOffset(int offset);
+ QByteArray compressedContent();
+
+ virtual void setFont(const QFont &font);
+ virtual int cellWidth(int col);
+ virtual QSize sizeHint() const;
+ virtual void paintCell(QPainter *p, int row, int col);
+ virtual void wheelEvent(QWheelEvent *);
+ const QScrollBar *scrollBar() const
+ { return verticalScrollBar(); }
+
+protected slots:
+ void vertPositionChanged(int val);
+ void horzPositionChanged(int val);
+
+private:
+ int findLine(int lineno);
+ DiffViewItemList items;
+ bool linenos;
+ bool marker;
+ int textwidth;
+ DiffView *partner;
+ static const int BORDER;
+
+ QColor diffChangeColor;
+ QColor diffInsertColor;
+ QColor diffDeleteColor;
+
+ int m_tabWidth;
+ KConfig& partConfig;
+};
+
+
+class DiffZoomWidget : public QFrame
+{
+ Q_OBJECT
+
+public:
+ DiffZoomWidget(KConfig& cfg, QWidget *parent=0, const char *name=0);
+ ~DiffZoomWidget();
+
+ void setDiffView(DiffView *view);
+ QSize sizeHint() const;
+
+protected:
+ void paintEvent(QPaintEvent *);
+ bool eventFilter(QObject *, QEvent *e);
+
+private:
+ DiffView *diffview;
+
+ QColor diffChangeColor;
+ QColor diffInsertColor;
+ QColor diffDeleteColor;
+};
+
+#endif
+
+
+// Local Variables:
+// c-basic-offset: 4
+// End:
diff --git a/cervisia/dirignorelist.cpp b/cervisia/dirignorelist.cpp
new file mode 100644
index 00000000..d6ffcf2d
--- /dev/null
+++ b/cervisia/dirignorelist.cpp
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2004 Christian Loose <christian.loose@kdemail.net>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the 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, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#include "dirignorelist.h"
+using namespace Cervisia;
+
+#include <qfileinfo.h>
+
+
+DirIgnoreList::DirIgnoreList(const QString& path)
+{
+ addEntriesFromFile(path + "/.cvsignore");
+}
+
+
+void DirIgnoreList::addEntry(const QString& entry)
+{
+ if (entry != QChar('!'))
+ {
+ m_stringMatcher.add(entry);
+ }
+ else
+ {
+ m_stringMatcher.clear();
+ }
+}
+
+
+bool DirIgnoreList::matches(const QFileInfo* fi) const
+{
+ return m_stringMatcher.match(fi->fileName());
+}
diff --git a/cervisia/dirignorelist.h b/cervisia/dirignorelist.h
new file mode 100644
index 00000000..41f82982
--- /dev/null
+++ b/cervisia/dirignorelist.h
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2004 Christian Loose <christian.loose@kdemail.net>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the 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, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#ifndef CERVISIA_DIRIGNORELIST_H
+#define CERVISIA_DIRIGNORELIST_H
+
+#include "ignorelistbase.h"
+#include "stringmatcher.h"
+
+class QFileInfo;
+
+
+namespace Cervisia
+{
+
+
+/* Encapsulates the .cvsignore file inside a CVS-controlled directory. */
+class DirIgnoreList : public IgnoreListBase
+{
+public:
+ explicit DirIgnoreList(const QString& path);
+
+ virtual bool matches(const QFileInfo* fi) const;
+
+private:
+ virtual void addEntry(const QString& entry);
+
+ StringMatcher m_stringMatcher;
+};
+
+
+}
+
+
+#endif
diff --git a/cervisia/editwithmenu.cpp b/cervisia/editwithmenu.cpp
new file mode 100644
index 00000000..9ca0f14b
--- /dev/null
+++ b/cervisia/editwithmenu.cpp
@@ -0,0 +1,78 @@
+/*
+ * Copyright (c) 2004 Christian Loose <christian.loose@kdemail.net>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the 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, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#include "editwithmenu.h"
+using namespace Cervisia;
+
+#include <qpopupmenu.h>
+#include <kdebug.h>
+#include <kiconloader.h>
+#include <kmimetype.h>
+#include <krun.h>
+#include <kurl.h>
+
+
+EditWithMenu::EditWithMenu(const KURL& url, QWidget* parent)
+ : QObject(parent)
+ , m_menu(0)
+ , m_url(url)
+{
+ KMimeType::Ptr type = KMimeType::findByURL(url, 0, true);
+ if( type->name() == KMimeType::defaultMimeType() )
+ {
+ kdDebug() << "Couldn't find mime type!" << endl;
+ return;
+ }
+
+ m_offers = KTrader::self()->query(type->name(), "Type == 'Application'");
+
+ if( !m_offers.isEmpty() )
+ {
+ m_menu = new QPopupMenu();
+
+ KTrader::OfferList::ConstIterator it = m_offers.begin();
+ for( int i = 0 ; it != m_offers.end(); ++it, ++i )
+ {
+ int id = m_menu->insertItem(SmallIcon((*it)->icon()),
+ (*it)->name(),
+ this, SLOT(itemActivated(int)));
+ m_menu->setItemParameter(id, i);
+ }
+ }
+}
+
+
+QPopupMenu* EditWithMenu::menu()
+{
+ return m_menu;
+}
+
+
+void EditWithMenu::itemActivated(int item)
+{
+ KService::Ptr service = m_offers[item];
+
+ KURL::List list;
+ list.append(m_url);
+
+ KRun::run(*service, list);
+}
+
+
+#include "editwithmenu.moc"
+
diff --git a/cervisia/editwithmenu.h b/cervisia/editwithmenu.h
new file mode 100644
index 00000000..f78b7a2e
--- /dev/null
+++ b/cervisia/editwithmenu.h
@@ -0,0 +1,55 @@
+/*
+ * Copyright (c) 2004 Christian Loose <christian.loose@kdemail.net>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the 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, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#ifndef EDITWITHMENU_H
+#define EDITWITHMENU_H
+
+#include <qobject.h>
+#include <ktrader.h>
+#include <kurl.h>
+
+class QPopupMenu;
+
+
+namespace Cervisia
+{
+
+
+class EditWithMenu : public QObject
+{
+ Q_OBJECT
+
+public:
+ EditWithMenu(const KURL& url, QWidget* parent);
+ QPopupMenu* menu();
+
+private slots:
+ void itemActivated(int);
+
+private:
+ KTrader::OfferList m_offers;
+ QPopupMenu* m_menu;
+ KURL m_url;
+};
+
+
+}
+
+
+#endif
+
diff --git a/cervisia/entry.cpp b/cervisia/entry.cpp
new file mode 100644
index 00000000..3cda036d
--- /dev/null
+++ b/cervisia/entry.cpp
@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) 2003-2007 André Wöbbeking <Woebbeking@kde.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the 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, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+
+#include "entry.h"
+
+
+namespace Cervisia
+{
+
+
+Entry::Entry()
+ : m_type(File),
+ m_status(Unknown)
+{
+}
+
+
+} // namespace Cervisia
diff --git a/cervisia/entry.h b/cervisia/entry.h
new file mode 100644
index 00000000..875885d0
--- /dev/null
+++ b/cervisia/entry.h
@@ -0,0 +1,85 @@
+/*
+ * Copyright (c) 2003-2007 André Wöbbeking <Woebbeking@kde.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the 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, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+
+#ifndef CERVISIA_ENTRY_H
+#define CERVISIA_ENTRY_H
+
+
+#include <qdatetime.h>
+#include <qstring.h>
+
+#include "entry_status.h"
+
+
+namespace Cervisia
+{
+
+
+/**
+ * Dumb data struct to store an entry controlled by a version control system.
+ */
+struct Entry
+{
+ enum Type
+ {
+ Dir,
+ File
+ };
+
+ /**
+ * Sets status to \a EntryStatus::Unknown and type to \a File.
+ */
+ Entry();
+
+ /**
+ * The name of this entry (without path).
+ */
+ QString m_name;
+
+ /**
+ * The type of this entry.
+ */
+ Type m_type;
+
+ /**
+ * The status of this entry.
+ */
+ EntryStatus m_status;
+
+ /**
+ * The revision of this entry.
+ */
+ QString m_revision;
+
+ /**
+ * The modification date/time of this entry (in user's local time).
+ */
+ QDateTime m_dateTime;
+
+ /**
+ * The tag/branch of this entry.
+ */
+ QString m_tag;
+};
+
+
+} // namespace Cervisia
+
+
+#endif // CERVISIA_ENTRY_H
diff --git a/cervisia/entry_status.cpp b/cervisia/entry_status.cpp
new file mode 100644
index 00000000..8ad624fa
--- /dev/null
+++ b/cervisia/entry_status.cpp
@@ -0,0 +1,81 @@
+/*
+ * Copyright (c) 2004-2007 André Wöbbeking <Woebbeking@kde.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the 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, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+
+#include "entry_status.h"
+
+#include <qstring.h>
+
+#include <klocale.h>
+
+
+namespace Cervisia
+{
+
+
+QString toString(EntryStatus entryStatus)
+{
+ QString result;
+ switch (entryStatus)
+ {
+ case LocallyModified:
+ result = i18n("Locally Modified");
+ break;
+ case LocallyAdded:
+ result = i18n("Locally Added");
+ break;
+ case LocallyRemoved:
+ result = i18n("Locally Removed");
+ break;
+ case NeedsUpdate:
+ result = i18n("Needs Update");
+ break;
+ case NeedsPatch:
+ result = i18n("Needs Patch");
+ break;
+ case NeedsMerge:
+ result = i18n("Needs Merge");
+ break;
+ case UpToDate:
+ result = i18n("Up to Date");
+ break;
+ case Conflict:
+ result = i18n("Conflict");
+ break;
+ case Updated:
+ result = i18n("Updated");
+ break;
+ case Patched:
+ result = i18n("Patched");
+ break;
+ case Removed:
+ result = i18n("Removed");
+ break;
+ case NotInCVS:
+ result = i18n("Not in CVS");
+ break;
+ case Unknown:
+ result = i18n("Unknown");
+ break;
+ }
+
+ return result;
+}
+
+
+} // namespace Cervisia
diff --git a/cervisia/entry_status.h b/cervisia/entry_status.h
new file mode 100644
index 00000000..634e0a04
--- /dev/null
+++ b/cervisia/entry_status.h
@@ -0,0 +1,64 @@
+/*
+ * Copyright (c) 2004-2007 André Wöbbeking <Woebbeking@kde.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the 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, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+
+#ifndef CERVISIA_ENTRY_STATUS_H
+#define CERVISIA_ENTRY_STATUS_H
+
+
+class QString;
+
+
+namespace Cervisia
+{
+
+
+/**
+ * All stati a an entry could have.
+ */
+enum EntryStatus
+{
+ LocallyModified,
+ LocallyAdded,
+ LocallyRemoved,
+ NeedsUpdate,
+ NeedsPatch,
+ NeedsMerge,
+ UpToDate,
+ Conflict,
+ Updated,
+ Patched,
+ Removed,
+ NotInCVS,
+ Unknown
+};
+
+/**
+ * The entry status as translated string.
+ *
+ * @param entryStatus The entry status to translate.
+ *
+ * @return The translated string.
+ */
+QString toString(EntryStatus entryStatus);
+
+
+} // namespace Cervisia
+
+
+#endif // CERVISIA_ENTRY_STATUS_H
diff --git a/cervisia/entry_status_change.h b/cervisia/entry_status_change.h
new file mode 100644
index 00000000..63b5f089
--- /dev/null
+++ b/cervisia/entry_status_change.h
@@ -0,0 +1,54 @@
+/*
+ * Copyright (c) 2004-2007 André Wöbbeking <Woebbeking@kde.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the 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, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+
+#ifndef CERVISIA_ENTRY_STATUS_CHANGE_H
+#define CERVISIA_ENTRY_STATUS_CHANGE_H
+
+
+#include <qstring.h>
+
+#include "entry_status.h"
+
+
+namespace Cervisia
+{
+
+
+/**
+ * Dumb data struct to store a status change of an entry (i.e. for jobs like
+ * status, update, ...).
+ */
+struct EntryStatusChange
+{
+ /**
+ * The name of the changed entry (including the path inside the repository / working copy).
+ */
+ QString m_name;
+
+ /**
+ * The new status of the entry.
+ */
+ EntryStatus m_status;
+};
+
+
+} // namespace Cervisia
+
+
+#endif // CERVISIA_ENTRY_STATUS_CHANGE_H
diff --git a/cervisia/eventsrc b/cervisia/eventsrc
new file mode 100644
index 00000000..cc88f561
--- /dev/null
+++ b/cervisia/eventsrc
@@ -0,0 +1,88 @@
+[!Global!]
+IconName=cervisia
+Comment=Cervisia
+
+[cvs_commit_done]
+Name=CVS commit job done
+Name[bg]=Изпращането в CVS е завършено
+Name[ca]=Entrega al CVS completada
+Name[cs]=CVS commit úloha dokonÄena
+Name[da]=CVS-indsending udført
+Name[de]=CVS-Einspielvorgang ausgeführt
+Name[el]=Έγινε η εÏγασία καταχώÏησης CVS
+Name[es]=Entrega al CVS completada
+Name[et]=CVS sissekanne tehtud
+Name[eu]=CVS aldaketak egin dira
+Name[fa]=کار تصدیق CVS انجام شد
+Name[fi]=CVS-toimitustyö tehty
+Name[fr]=Validation CVS effectuée
+Name[ga]=Athruithe curtha i bhfeidhm ag CVS
+Name[gl]=Entrega CVS finalizada
+Name[hu]=CVS commit művelet kész
+Name[is]=CVS innsetningu lokið
+Name[it]=Processo di consegna a CVS eseguito
+Name[ja]=CVS コミットã¯çµ‚了ã—ã¾ã—ãŸã€‚
+Name[ka]=CVS შესრულებული დáƒáƒ•áƒáƒšáƒ”ბრშესრულდáƒ
+Name[kk]=CVS тапÑыру жұмыÑын аÑқтады
+Name[lt]=CVS įkėlimo veiksmas atliktas
+Name[nb]=CVS-innmeldingsjobb er gjort
+Name[nds]=CVS-Inspeelopgaav is fardig
+Name[ne]=CVS commit कारà¥à¤¯ समापà¥à¤¤
+Name[nl]=CVS vastleggen (commit) voltooid
+Name[nn]=CVS-innmeldingsjobb er gjort
+Name[pa]=CVS ਕਮਿਟ ਕੰਮ ਮà©à¨•à©°à¨®à¨²
+Name[pl]=Wysyłanie do repozytorium CVS zakończone
+Name[pt]=Trabalho de 'commit' de CVS terminado
+Name[pt_BR]=Trabalho de envio para o CVS feito
+Name[ru]=CVS Commit выполнен
+Name[sk]=CVS potvrdzujúca úloha ukonÄená
+Name[sl]=Opravilo udejanjanja v CVS konÄano
+Name[sr]=CVS предаја завршена
+Name[sr@Latn]=CVS predaja završena
+Name[sv]=CVS-arkiveringsjobb klart
+Name[tr]=CVS teslim etme işi tamamlandı
+Name[uk]=Ð—Ð°Ð²Ð´Ð°Ð½Ð½Ñ Ð¿ÐµÑ€ÐµÐ´Ð°Ñ‡Ñ– CVS виконане
+Name[zh_CN]=CVS æ交任务已完æˆ
+Name[zh_TW]=CVS æ交工作完æˆ
+Comment=A CVS commit job is done
+Comment[bg]=Изпращането в CVS е завършено
+Comment[ca]=S'ha completat una entrega al CVS
+Comment[cs]=CVS commit úloha je dokonÄena
+Comment[da]=En CVS-indsending er udført
+Comment[de]=Ein CVS-Einspielvorgang wurde ausgeführt
+Comment[el]=Μια εÏγασία καταχώÏησης CVS έγινε
+Comment[es]=Se ha completado una entrega al CVS
+Comment[et]=CVS sissekanne tehtud
+Comment[eu]=CVS aldaketa egin da
+Comment[fa]=کار تصدیق CVS انجام می‌شود.
+Comment[fi]=CVS-toimitustyö on tehty
+Comment[fr]=Une validation CVS a été effectué
+Comment[ga]=Athruithe curtha i bhfeidhm ag CVS
+Comment[gl]=Unha entrega CVS finalizou
+Comment[hu]=Egy CVS commit művelet sikeresen befejeződött
+Comment[is]=CVS innsetningu lokið
+Comment[it]=Un processo di deposito su CVS è stato eseguito
+Comment[ja]=CVS コミットã¯çµ‚了ã—ã¾ã—ãŸã€‚
+Comment[ka]=CVS შესრულებული დáƒáƒ•áƒáƒšáƒ”ბრშესრულდáƒ
+Comment[kk]=CVS тапÑыру жұмыÑÑ‹ аÑқталды
+Comment[lt]=CVS įkėlimo veiksmas atliktas
+Comment[nb]=En CVS-innmeldingsjobb er utført
+Comment[nds]=En CVS-Inspeelopgaav is fardig
+Comment[ne]=CVS commit कारà¥à¤¯ समापà¥à¤¤ भà¤à¤•à¥‹ छ
+Comment[nl]=Het vastleggen in CVS (commit) is voltooid
+Comment[nn]=Ein CVS-innmeldingsjobb er gjort
+Comment[pa]=ਇੱਕ CVS ਕਮਿਟ ਕੰਮ ਖਤਮ ਹੋਇਆ
+Comment[pl]=Wysyłanie do repozytorium CVS zostało zakończone
+Comment[pt]=Um trabalho de 'commit' de CVS terminou
+Comment[pt_BR]=Um trabalho de envio para o CVS foi feito
+Comment[ru]=CVS Commit выполнен
+Comment[sk]=CVS potvrdzujúca úloha ukonÄená
+Comment[sl]=Opravilo udejanjanja v CVS je konÄano
+Comment[sr]=ПоÑао CVS предаје је завршен
+Comment[sr@Latn]=Posao CVS predaje je završen
+Comment[sv]=Ett CVS-arkiveringsjobb är klart
+Comment[tr]=Bir CVS teslim etme işi tamamlandı
+Comment[uk]=Ð—Ð°Ð²Ð´Ð°Ð½Ð½Ñ Ð¿ÐµÑ€ÐµÐ´Ð°Ñ‡Ñ– CVS виконане
+Comment[zh_CN]=CVS æ交任务已完æˆ
+Comment[zh_TW]=CVS æ交工作完æˆ
+default_presentation=0
diff --git a/cervisia/globalignorelist.cpp b/cervisia/globalignorelist.cpp
new file mode 100644
index 00000000..6d905fc7
--- /dev/null
+++ b/cervisia/globalignorelist.cpp
@@ -0,0 +1,100 @@
+/*
+ * Copyright (C) 2004 Christian Loose <christian.loose@kdemail.net>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the 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, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#include "globalignorelist.h"
+using namespace Cervisia;
+
+#include <qdir.h>
+#include <kdebug.h>
+#include <ktempfile.h>
+#include <stdlib.h> // for getenv()
+
+#include "cvsservice_stub.h"
+#include "progressdlg.h"
+
+
+StringMatcher GlobalIgnoreList::m_stringMatcher;
+bool GlobalIgnoreList::m_isInitialized = false;
+
+
+GlobalIgnoreList::GlobalIgnoreList()
+{
+ if( !m_isInitialized )
+ setup();
+}
+
+
+bool GlobalIgnoreList::matches(const QFileInfo* fi) const
+{
+ return m_stringMatcher.match(fi->fileName());
+}
+
+
+void GlobalIgnoreList::retrieveServerIgnoreList(CvsService_stub* cvsService,
+ const QString& repository)
+{
+ KTempFile tmpFile;
+ tmpFile.setAutoDelete(true);
+
+ // clear old ignore list
+ m_stringMatcher.clear();
+
+ // now set it up again
+ setup();
+
+ DCOPRef ref = cvsService->downloadCvsIgnoreFile(repository,
+ tmpFile.name());
+
+ ProgressDialog dlg(0, "Edit", ref, "checkout", "CVS Edit");
+ if( !dlg.execute() )
+ return;
+
+ addEntriesFromFile(tmpFile.name());
+}
+
+
+void GlobalIgnoreList::addEntry(const QString& entry)
+{
+ if (entry != QChar('!'))
+ {
+ m_stringMatcher.add(entry);
+ }
+ else
+ {
+ m_stringMatcher.clear();
+
+ // Bug #89215:
+ // Make sure '.' and '..' are always in the ignore list, so
+ // UpdateDirItem::maybeScanDir() doesn't loop endlessly.
+ addEntriesFromString(QString::fromLatin1(". .."));
+ }
+}
+
+
+void GlobalIgnoreList::setup()
+{
+ static const char ignorestr[] = ". .. core RCSLOG tags TAGS RCS SCCS .make.state\
+.nse_depinfo #* .#* cvslog.* ,* CVS CVS.adm .del-* *.a *.olb *.o *.obj\
+*.so *.Z *~ *.old *.elc *.ln *.bak *.BAK *.orig *.rej *.exe _$* *$";
+
+ addEntriesFromString(QString::fromLatin1(ignorestr));
+ addEntriesFromString(QString::fromLocal8Bit(::getenv("CVSIGNORE")));
+ addEntriesFromFile(QDir::homeDirPath() + "/.cvsignore");
+
+ m_isInitialized = true;
+}
diff --git a/cervisia/globalignorelist.h b/cervisia/globalignorelist.h
new file mode 100644
index 00000000..b8f72664
--- /dev/null
+++ b/cervisia/globalignorelist.h
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2004 Christian Loose <christian.loose@kdemail.net>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the 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, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#ifndef CERVISIA_GLOBALIGNORELIST_H
+#define CERVISIA_GLOBALIGNORELIST_H
+
+#include "ignorelistbase.h"
+#include "stringmatcher.h"
+
+class QFileInfo;
+class CvsService_stub;
+
+
+namespace Cervisia
+{
+
+
+class GlobalIgnoreList : public IgnoreListBase
+{
+public:
+ GlobalIgnoreList();
+
+ virtual bool matches(const QFileInfo* fi) const;
+
+ void retrieveServerIgnoreList(CvsService_stub* cvsService,
+ const QString& repository);
+
+private:
+ void setup();
+ virtual void addEntry(const QString& entry);
+
+ static StringMatcher m_stringMatcher;
+ static bool m_isInitialized;
+};
+
+
+}
+
+
+#endif
diff --git a/cervisia/hi16-app-cervisia.png b/cervisia/hi16-app-cervisia.png
new file mode 100644
index 00000000..3850214d
--- /dev/null
+++ b/cervisia/hi16-app-cervisia.png
Binary files differ
diff --git a/cervisia/hi22-app-cervisia.png b/cervisia/hi22-app-cervisia.png
new file mode 100644
index 00000000..253ec4a0
--- /dev/null
+++ b/cervisia/hi22-app-cervisia.png
Binary files differ
diff --git a/cervisia/hi32-app-cervisia.png b/cervisia/hi32-app-cervisia.png
new file mode 100644
index 00000000..1eda7cb8
--- /dev/null
+++ b/cervisia/hi32-app-cervisia.png
Binary files differ
diff --git a/cervisia/hi48-app-cervisia.png b/cervisia/hi48-app-cervisia.png
new file mode 100644
index 00000000..309cc49f
--- /dev/null
+++ b/cervisia/hi48-app-cervisia.png
Binary files differ
diff --git a/cervisia/historydlg.cpp b/cervisia/historydlg.cpp
new file mode 100644
index 00000000..35eb5e01
--- /dev/null
+++ b/cervisia/historydlg.cpp
@@ -0,0 +1,397 @@
+/*
+ * Copyright (C) 1999-2002 Bernd Gehrmann
+ * bernd@mail.berlios.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.
+ *
+ * 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, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+
+#include "historydlg.h"
+
+#include <qcheckbox.h>
+#include <qdatetime.h>
+#include <qlayout.h>
+#include <qpushbutton.h>
+#include <qregexp.h>
+#include <kconfig.h>
+#include <klineedit.h>
+#include <klistview.h>
+#include <klocale.h>
+#include <krfcdate.h>
+
+#include "misc.h"
+#include "cvsservice_stub.h"
+#include "progressdlg.h"
+
+
+static QDateTime parseDate(const QString& date, const QString& _time, const QString& offset)
+{
+ // cvs history only prints hh:mm but parseDateISO8601 needs hh:mm:ss
+ QString time(_time);
+ if( time.contains(':') == 1 )
+ time += ":00";
+
+ QDateTime dateTime;
+ dateTime.setTime_t(KRFCDate::parseDateISO8601(date + 'T' + time + offset));
+
+ return dateTime;
+}
+
+
+class HistoryItem : public QListViewItem
+{
+public:
+
+ enum { Date, Event, Author, Revision, File, Path };
+
+ HistoryItem(QListView *parent, const QDateTime& date)
+ : QListViewItem(parent), m_date(date)
+ {}
+
+ virtual int compare(QListViewItem* i, int col, bool) const;
+
+ virtual QString text(int col) const;
+
+ bool isCommit();
+ bool isCheckout();
+ bool isTag();
+ bool isOther();
+
+private:
+
+ const QDateTime m_date;
+};
+
+
+int HistoryItem::compare(QListViewItem* i, int col, bool ascending) const
+{
+ const HistoryItem* pItem = static_cast<HistoryItem*>(i);
+
+ int iResult;
+ switch (col)
+ {
+ case Date:
+ iResult = ::compare(m_date, pItem->m_date);
+ break;
+ case Revision:
+ iResult = ::compareRevisions(text(Revision), pItem->text(Revision));
+ break;
+ default:
+ iResult = QListViewItem::compare(i, col, ascending);
+ }
+
+ return iResult;
+}
+
+
+QString HistoryItem::text(int col) const
+{
+ QString sText;
+ switch (col)
+ {
+ case Date:
+ sText = KGlobal::locale()->formatDateTime(m_date);
+ break;
+ default:
+ sText = QListViewItem::text(col);
+ }
+
+ return sText;
+}
+
+
+bool HistoryItem::isCommit()
+{
+ return text(1) == i18n("Commit, Modified ")
+ || text(1) == i18n("Commit, Added ")
+ || text(1) == i18n("Commit, Removed ");
+}
+
+
+bool HistoryItem::isCheckout()
+{
+ return text(1) == i18n("Checkout ");
+}
+
+
+bool HistoryItem::isTag()
+{
+ return text(1) == i18n("Tag");
+}
+
+
+bool HistoryItem::isOther()
+{
+ return !isCommit() && !isCheckout() && !isTag();
+}
+
+
+HistoryDialog::HistoryDialog(KConfig& cfg, QWidget *parent, const char *name)
+ : KDialogBase(parent, name, false, QString::null,
+ Close | Help, ButtonCode(0), true)
+ , partConfig(cfg)
+{
+ QFrame* mainWidget = makeMainWidget();
+
+ QBoxLayout *layout = new QVBoxLayout(mainWidget, 0, spacingHint());
+
+ listview = new KListView(mainWidget);
+ listview->setSelectionMode(QListView::NoSelection);
+ listview->setAllColumnsShowFocus(true);
+ listview->setShowSortIndicator(true);
+ listview->setSorting(HistoryItem::Date, false);
+ listview->addColumn(i18n("Date"));
+ listview->addColumn(i18n("Event"));
+ listview->addColumn(i18n("Author"));
+ listview->addColumn(i18n("Revision"));
+ listview->addColumn(i18n("File"));
+ listview->addColumn(i18n("Repo Path"));
+ listview->setFocus();
+ layout->addWidget(listview, 1);
+
+ commit_box = new QCheckBox(i18n("Show c&ommit events"), mainWidget);
+ commit_box->setChecked(true);
+
+ checkout_box = new QCheckBox(i18n("Show ch&eckout events"), mainWidget);
+ checkout_box->setChecked(true);
+
+ tag_box = new QCheckBox(i18n("Show &tag events"), mainWidget);
+ tag_box->setChecked(true);
+
+ other_box = new QCheckBox(i18n("Show &other events"), mainWidget);
+ other_box->setChecked(true);
+
+ onlyuser_box = new QCheckBox(i18n("Only &user:"), mainWidget);
+
+ onlyfilenames_box = new QCheckBox(i18n("Only &filenames matching:"), mainWidget);
+
+ onlydirnames_box = new QCheckBox(i18n("Only &folders matching:"), mainWidget);
+
+ user_edit = new KLineEdit(mainWidget);
+ user_edit->setEnabled(false);
+
+ filename_edit = new KLineEdit(mainWidget);
+ filename_edit->setEnabled(false);
+
+ dirname_edit = new KLineEdit(mainWidget);
+ dirname_edit->setEnabled(false);
+
+ connect( onlyuser_box, SIGNAL(toggled(bool)),
+ this, SLOT(toggled(bool)) );
+ connect( onlyfilenames_box, SIGNAL(toggled(bool)),
+ this, SLOT(toggled(bool)) );
+ connect( onlydirnames_box, SIGNAL(toggled(bool)),
+ this, SLOT(toggled(bool)) );
+ connect( commit_box, SIGNAL(toggled(bool)),
+ this, SLOT(choiceChanged()) );
+ connect( checkout_box, SIGNAL(toggled(bool)),
+ this, SLOT(choiceChanged()) );
+ connect( tag_box, SIGNAL(toggled(bool)),
+ this, SLOT(choiceChanged()) );
+ connect( other_box, SIGNAL(toggled(bool)),
+ this, SLOT(choiceChanged()) );
+ connect( onlyuser_box, SIGNAL(toggled(bool)),
+ this, SLOT(choiceChanged()) );
+ connect( onlyfilenames_box, SIGNAL(toggled(bool)),
+ this, SLOT(choiceChanged()) );
+ connect( onlydirnames_box, SIGNAL(toggled(bool)),
+ this, SLOT(choiceChanged()) );
+ connect( user_edit, SIGNAL(returnPressed()),
+ this, SLOT(choiceChanged()) );
+ connect( filename_edit, SIGNAL(returnPressed()),
+ this, SLOT(choiceChanged()) );
+ connect( dirname_edit, SIGNAL(returnPressed()),
+ this, SLOT(choiceChanged()) );
+
+ QGridLayout *grid = new QGridLayout(layout);
+ grid->setColStretch(0, 1);
+ grid->setColStretch(1, 0);
+ grid->setColStretch(2, 4);
+ grid->setColStretch(3, 1);
+ grid->addWidget(commit_box, 0, 0);
+ grid->addWidget(checkout_box, 1, 0);
+ grid->addWidget(tag_box, 2, 0);
+ grid->addWidget(other_box, 3, 0);
+ grid->addWidget(onlyuser_box, 0, 1);
+ grid->addWidget(user_edit, 0, 2);
+ grid->addWidget(onlyfilenames_box, 1, 1);
+ grid->addWidget(filename_edit, 1, 2);
+ grid->addWidget(onlydirnames_box, 2, 1);
+ grid->addWidget(dirname_edit, 2, 2);
+
+ // no default button because "return" is needed to activate the filters (line edits)
+ actionButton(Help)->setAutoDefault(false);
+ actionButton(Close)->setAutoDefault(false);
+
+ setHelp("browsinghistory");
+
+ setWFlags(Qt::WDestructiveClose | getWFlags());
+
+ QSize size = configDialogSize(partConfig, "HistoryDialog");
+ resize(size);
+
+ // without this restoreLayout() can't change the column widths
+ for (int i = 0; i < listview->columns(); ++i)
+ listview->setColumnWidthMode(i, QListView::Manual);
+
+ listview->restoreLayout(&partConfig, QString::fromLatin1("HistoryListView"));
+}
+
+
+HistoryDialog::~HistoryDialog()
+{
+ saveDialogSize(partConfig, "HistoryDialog");
+
+ listview->saveLayout(&partConfig, QString::fromLatin1("HistoryListView"));
+}
+
+
+void HistoryDialog::choiceChanged()
+{
+ const QString author(user_edit->text());
+ const QRegExp fileMatcher(filename_edit->text(), true, true);
+ const QRegExp pathMatcher(dirname_edit->text(), true, true);
+
+ const bool showCommitEvents(commit_box->isChecked());
+ const bool showCheckoutEvents(checkout_box->isChecked());
+ const bool showTagEvents(tag_box->isChecked());
+ const bool showOtherEvents(other_box->isChecked());
+ const bool filterByAuthor(onlyuser_box->isChecked() && !author.isEmpty());
+ const bool filterByFile(onlyfilenames_box->isChecked() && !fileMatcher.isEmpty());
+ const bool filterByPath(onlydirnames_box->isChecked() && !pathMatcher.isEmpty());
+
+ QListViewItemIterator it(listview);
+ for (; it.current(); ++it)
+ {
+ HistoryItem *item = static_cast<HistoryItem*>(it.current());
+
+ bool visible( (showCommitEvents && item->isCommit())
+ || (showCheckoutEvents && item->isCheckout())
+ || (showTagEvents && item->isTag())
+ || (showOtherEvents && item->isOther()));
+ visible = visible
+ && (!filterByAuthor || author == item->text(HistoryItem::Author))
+ && (!filterByFile || fileMatcher.search(item->text(HistoryItem::File)) >= 0)
+ && (!filterByPath || pathMatcher.search(item->text(HistoryItem::Path)) >= 0);
+
+ item->setVisible(visible);
+ }
+}
+
+
+void HistoryDialog::toggled(bool b)
+{
+ KLineEdit *edit = 0;
+
+ if (sender() == onlyuser_box)
+ edit = user_edit;
+ else if (sender() == onlyfilenames_box)
+ edit = filename_edit;
+ else if (sender() == onlydirnames_box)
+ edit = dirname_edit;
+
+ edit->setEnabled(b);
+ if (b)
+ edit->setFocus();
+}
+
+
+bool HistoryDialog::parseHistory(CvsService_stub* cvsService)
+{
+ setCaption(i18n("CVS History"));
+
+ DCOPRef job = cvsService->history();
+ if( !cvsService->ok() )
+ return false;
+
+ ProgressDialog dlg(this, "History", job, "history", i18n("CVS History"));
+ if( !dlg.execute() )
+ return false;
+
+ QString line;
+ while( dlg.getLine(line) )
+ {
+ const QStringList list(splitLine(line));
+ const int listSize(list.size());
+ if( listSize < 6)
+ continue;
+
+ QString cmd = list[0];
+ if( cmd.length() != 1 )
+ continue;
+
+ int ncol;
+ int cmd_code = cmd[0].latin1();
+ switch (cmd_code)
+ {
+ case 'O':
+ case 'F':
+ case 'E':
+ ncol = 8;
+ break;
+ default:
+ ncol = 10;
+ break;
+ }
+
+ if( ncol != (int)list.count() )
+ continue;
+
+ QString event;
+ switch( cmd_code )
+ {
+ case 'O': event = i18n("Checkout "); break;
+ case 'T': event = i18n("Tag "); break;
+ case 'F': event = i18n("Release "); break;
+ case 'W': event = i18n("Update, Deleted "); break;
+ case 'U': event = i18n("Update, Copied "); break;
+ case 'G': event = i18n("Update, Merged "); break;
+ case 'C': event = i18n("Update, Conflict "); break;
+ case 'P': event = i18n("Update, Patched "); break;
+ case 'M': event = i18n("Commit, Modified "); break;
+ case 'A': event = i18n("Commit, Added "); break;
+ case 'R': event = i18n("Commit, Removed "); break;
+ default: event = i18n("Unknown ");
+ }
+
+ const QDateTime date(parseDate(list[1], list[2], list[3]));
+
+ HistoryItem *item = new HistoryItem(listview, date);
+ item->setText(HistoryItem::Event, event);
+ item->setText(HistoryItem::Author, list[4]);
+ if( ncol == 10 )
+ {
+ item->setText(HistoryItem::Revision, list[5]);
+ if( listSize >= 8 )
+ {
+ item->setText(HistoryItem::File, list[6]);
+ item->setText(HistoryItem::Path, list[7]);
+ }
+ }
+ else
+ {
+ item->setText(HistoryItem::Path, list[5]);
+ }
+ }
+
+ return true;
+}
+
+#include "historydlg.moc"
+
+
+// Local Variables:
+// c-basic-offset: 4
+// End:
diff --git a/cervisia/historydlg.h b/cervisia/historydlg.h
new file mode 100644
index 00000000..ac2241d2
--- /dev/null
+++ b/cervisia/historydlg.h
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 1999-2002 Bernd Gehrmann
+ * bernd@mail.berlios.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.
+ *
+ * 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, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+
+#ifndef HISTORYDLG_H
+#define HISTORYDLG_H
+
+
+#include <kdialogbase.h>
+
+
+class QCheckBox;
+class KConfig;
+class KLineEdit;
+class KListView;
+class CvsService_stub;
+
+
+class HistoryDialog : public KDialogBase
+{
+ Q_OBJECT
+
+public:
+ explicit HistoryDialog( KConfig& cfg, QWidget *parent=0, const char *name=0 );
+ virtual ~HistoryDialog();
+
+ bool parseHistory(CvsService_stub* cvsService);
+
+private slots:
+ void choiceChanged();
+ void toggled(bool b);
+
+private:
+ KListView *listview;
+ QCheckBox *commit_box, *checkout_box, *tag_box, *other_box;
+ QCheckBox *onlyuser_box, *onlyfilenames_box, *onlydirnames_box;
+ KLineEdit *user_edit, *filename_edit, *dirname_edit;
+ KConfig& partConfig;
+};
+
+#endif
+
+
+// Local Variables:
+// c-basic-offset: 4
+// End:
diff --git a/cervisia/ignorelistbase.cpp b/cervisia/ignorelistbase.cpp
new file mode 100644
index 00000000..27b3d159
--- /dev/null
+++ b/cervisia/ignorelistbase.cpp
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2004 Christian Loose <christian.loose@kdemail.net>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the 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, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#include "ignorelistbase.h"
+using namespace Cervisia;
+
+#include <qfile.h>
+#include <qstringlist.h>
+#include <qtextstream.h>
+
+
+void IgnoreListBase::addEntriesFromString(const QString& str)
+{
+ QStringList entries = QStringList::split(' ', str);
+ for( QStringList::iterator it = entries.begin(); it != entries.end(); ++it )
+ {
+ addEntry(*it);
+ }
+}
+
+
+void IgnoreListBase::addEntriesFromFile(const QString& name)
+{
+ QFile file(name);
+
+ if( file.open(IO_ReadOnly) )
+ {
+ QTextStream stream(&file);
+ while( !stream.eof() )
+ {
+ addEntriesFromString(stream.readLine());
+ }
+ }
+}
diff --git a/cervisia/ignorelistbase.h b/cervisia/ignorelistbase.h
new file mode 100644
index 00000000..9d166796
--- /dev/null
+++ b/cervisia/ignorelistbase.h
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2004 Christian Loose <christian.loose@kdemail.net>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the 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, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#ifndef CERVISIA_IGNORELISTBASE_H
+#define CERVISIA_IGNORELISTBASE_H
+
+class QFileInfo;
+class QString;
+
+
+namespace Cervisia
+{
+
+
+class IgnoreListBase
+{
+public:
+ virtual ~IgnoreListBase() {}
+
+ virtual bool matches(const QFileInfo* fi) const = 0;
+
+protected:
+ void addEntriesFromString(const QString& str);
+ void addEntriesFromFile(const QString& name);
+
+private:
+ virtual void addEntry(const QString& entry) = 0;
+};
+
+
+}
+
+
+#endif
diff --git a/cervisia/logdlg.cpp b/cervisia/logdlg.cpp
new file mode 100644
index 00000000..41a0751c
--- /dev/null
+++ b/cervisia/logdlg.cpp
@@ -0,0 +1,620 @@
+/*
+ * Copyright (C) 1999-2002 Bernd Gehrmann
+ * bernd@mail.berlios.de
+ * Copyright (c) 2002-2004 Christian Loose <christian.loose@kdemail.net>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the 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, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+
+#include "logdlg.h"
+
+#include <qcombobox.h>
+#include <qfile.h>
+#include <qfileinfo.h>
+#include <qlabel.h>
+#include <qlayout.h>
+#include <qpushbutton.h>
+#include <qtabwidget.h>
+#include <qtextedit.h>
+#include <qwhatsthis.h>
+#include <kconfig.h>
+#include <kdebug.h>
+#include <kfiledialog.h>
+#include <kfinddialog.h>
+#include <kglobalsettings.h>
+#include <kiconloader.h>
+#include <klistviewsearchline.h>
+#include <klocale.h>
+#include <kmessagebox.h>
+#include <kprocess.h>
+#include <krfcdate.h>
+#include <krun.h>
+#include <kurl.h>
+
+#include "cvsservice_stub.h"
+#include "annotatedlg.h"
+#include "annotatectl.h"
+#include "diffdlg.h"
+#include "loginfo.h"
+#include "loglist.h"
+#include "logplainview.h"
+#include "logtree.h"
+#include "misc.h"
+#include "progressdlg.h"
+#include "patchoptiondlg.h"
+
+
+LogDialog::LogDialog(KConfig& cfg, QWidget *parent, const char *name)
+ : KDialogBase(parent, name, false, QString::null,
+ Ok | Apply | Close | Help | User1 | User2 | User3, Close, true,
+ KGuiItem(i18n("&Annotate")),
+ KGuiItem(i18n("&Diff"), "vcs_diff"),
+ KGuiItem(i18n("&Find..."), "find"))
+ , cvsService(0)
+ , partConfig(cfg)
+{
+ QSplitter *splitter = new QSplitter(Qt::Vertical, this);
+ setMainWidget(splitter);
+
+ tree = new LogTreeView(this);
+ connect( tree, SIGNAL(revisionClicked(QString,bool)),
+ this, SLOT(revisionSelected(QString,bool)) );
+
+ QWidget* listWidget = new QWidget(this);
+ QVBoxLayout* listLayout = new QVBoxLayout(listWidget);
+ QHBoxLayout* searchLayout = new QHBoxLayout(listLayout);
+ searchLayout->setMargin(KDialog::spacingHint());
+ searchLayout->setSpacing(KDialog::spacingHint());
+
+ list = new LogListView(partConfig, listWidget);
+ listLayout->addWidget(list, 1);
+
+ KListViewSearchLine* searchLine = new KListViewSearchLine(listWidget, list);
+ QLabel* searchLabel = new QLabel(searchLine, i18n("S&earch:"), listWidget);
+ searchLayout->addWidget(searchLabel);
+ searchLayout->addWidget(searchLine, 1);
+
+ connect( list, SIGNAL(revisionClicked(QString,bool)),
+ this, SLOT(revisionSelected(QString,bool)) );
+
+ plain = new LogPlainView(this);
+ connect( plain, SIGNAL(revisionClicked(QString,bool)),
+ this, SLOT(revisionSelected(QString,bool)) );
+
+ tabWidget = new QTabWidget(splitter);
+ tabWidget->addTab(tree, i18n("&Tree"));
+ tabWidget->addTab(listWidget, i18n("&List"));
+ tabWidget->addTab(plain, i18n("CVS &Output"));
+
+ connect(tabWidget, SIGNAL(currentChanged(QWidget*)),
+ this, SLOT(tabChanged(QWidget*)));
+
+ QWhatsThis::add(tree, i18n("Choose revision A by clicking with the left "
+ "mouse button,\nrevision B by clicking with "
+ "the middle mouse button."));
+
+ items.setAutoDelete(true);
+ tags.setAutoDelete(true);
+
+ QWidget *mainWidget = new QWidget(splitter);
+ QBoxLayout *layout = new QVBoxLayout(mainWidget, 0, spacingHint());
+
+ for (int i = 0; i < 2; ++i)
+ {
+ if ( i == 1 )
+ {
+ QFrame *frame = new QFrame(mainWidget);
+ frame->setFrameStyle(QFrame::HLine | QFrame::Sunken);
+ layout->addWidget(frame);
+ }
+
+ QGridLayout *grid = new QGridLayout(layout);
+ grid->setRowStretch(0, 0);
+ grid->setRowStretch(1, 0);
+ grid->setRowStretch(2, 1);
+ grid->setColStretch(0, 0);
+ grid->setColStretch(1, 1);
+ grid->setColStretch(2, 0);
+ grid->setColStretch(3, 1);
+ grid->setColStretch(4, 2);
+
+ QString versionident = (i==0)? i18n("Revision A:") : i18n("Revision B:");
+ QLabel *versionlabel = new QLabel(versionident, mainWidget);
+ grid->addWidget(versionlabel, 0, 0);
+
+ revbox[i] = new QLabel(mainWidget);
+ revbox[i]->setFrameStyle(QFrame::Panel | QFrame::Sunken);
+ grid->addWidget(revbox[i], 0, 1, Qt::AlignVCenter);
+
+ QLabel *selectlabel = new QLabel(i18n("Select by tag:"), mainWidget);
+ grid->addWidget(selectlabel, 0, 2);
+
+ tagcombo[i] = new QComboBox(mainWidget);
+ QFontMetrics fm(tagcombo[i]->fontMetrics());
+ tagcombo[i]->setMinimumWidth(fm.width("X")*20);
+ grid->addWidget(tagcombo[i], 0, 3);
+
+ QLabel *authorlabel = new QLabel(i18n("Author:"), mainWidget);
+ grid->addWidget(authorlabel, 1, 0);
+
+ authorbox[i] = new QLabel(mainWidget);
+ authorbox[i]->setFrameStyle(QFrame::Panel | QFrame::Sunken);
+ grid->addWidget(authorbox[i], 1, 1);
+
+ QLabel *datelabel = new QLabel(i18n("Date:"), mainWidget);
+ grid->addWidget(datelabel, 1, 2);
+
+ datebox[i] = new QLabel(mainWidget);
+ datebox[i]->setFrameStyle(QFrame::Panel | QFrame::Sunken);
+ grid->addWidget(datebox[i], 1, 3);
+
+ QLabel *commentlabel = new QLabel(i18n("Comment/Tags:"), mainWidget);
+ grid->addWidget(commentlabel, 2, 0);
+
+ commentbox[i] = new QTextEdit(mainWidget);
+ commentbox[i]->setReadOnly(true);
+ commentbox[i]->setTextFormat(Qt::PlainText);
+ fm = commentbox[i]->fontMetrics();
+ commentbox[i]->setMinimumHeight(2*fm.lineSpacing()+10);
+ grid->addMultiCellWidget(commentbox[i], 2, 2, 1, 3);
+
+ tagsbox[i] = new QTextEdit(mainWidget);
+ tagsbox[i]->setReadOnly(true);
+ tagsbox[i]->setMinimumHeight(2*fm.lineSpacing()+10);
+ grid->addWidget(tagsbox[i], 2, 4);
+ }
+
+ QWhatsThis::add(revbox[0], i18n("This revision is used when you click "
+ "Annotate.\nIt is also used as the first "
+ "item of a Diff operation."));
+ QWhatsThis::add(revbox[1], i18n("This revision is used as the second "
+ "item of a Diff operation."));
+
+ connect( tagcombo[0], SIGNAL(activated(int)),
+ this, SLOT(tagASelected(int)) );
+ connect( tagcombo[1], SIGNAL(activated(int)),
+ this, SLOT(tagBSelected(int)) );
+
+ connect( this, SIGNAL(user1Clicked()),
+ this, SLOT(annotateClicked()) );
+ connect( this, SIGNAL(user2Clicked()),
+ this, SLOT(diffClicked()) );
+ connect( this, SIGNAL(user3Clicked()),
+ this, SLOT(findClicked()) );
+
+ setButtonGuiItem(Ok, KGuiItem(i18n("to view something", "&View"),"fileopen"));
+ setButtonGuiItem(Apply, KGuiItem(i18n("Create Patch...")));
+ setHelp("browsinglogs");
+
+ setWFlags(Qt::WDestructiveClose | getWFlags());
+
+ QSize size = configDialogSize(partConfig, "LogDialog");
+ resize(size);
+
+ KConfigGroupSaver cs(&partConfig, "LogDialog");
+ tabWidget->setCurrentPage(partConfig.readNumEntry("ShowTab", 0));
+
+ updateButtons();
+}
+
+
+LogDialog::~LogDialog()
+{
+ saveDialogSize(partConfig, "LogDialog");
+
+ KConfigGroupSaver cs(&partConfig, "LogDialog");
+ partConfig.writeEntry("ShowTab", tabWidget->currentPageIndex());
+}
+
+
+bool LogDialog::parseCvsLog(CvsService_stub* service, const QString& fileName)
+{
+ QString rev;
+
+ Cervisia::LogInfo logInfo;
+
+ enum { Begin, Tags, Admin, Revision,
+ Author, Branches, Comment, Finished } state;
+
+ // remember DCOP reference and file name for diff or annotate
+ cvsService = service;
+ filename = fileName;
+
+ setCaption(i18n("CVS Log: %1").arg(filename));
+
+ DCOPRef job = cvsService->log(filename);
+ if( !cvsService->ok() )
+ return false;
+
+ ProgressDialog dlg(this, "Logging", job, "log", i18n("CVS Log"));
+ if( !dlg.execute() )
+ return false;
+
+ // process cvs log output
+ state = Begin;
+ QString line;
+ while( dlg.getLine(line) )
+ {
+ switch( state )
+ {
+ case Begin:
+ if( line == "symbolic names:" )
+ state = Tags;
+ break;
+ case Tags:
+ if( line[0] == '\t' )
+ {
+ const QStringList strlist(splitLine(line, ':'));
+ rev = strlist[1].simplifyWhiteSpace();
+ const QString tag(strlist[0].simplifyWhiteSpace());
+ QString branchpoint;
+ int pos1, pos2;
+ if( (pos2 = rev.findRev('.')) > 0 &&
+ (pos1 = rev.findRev('.', pos2-1)) > 0 &&
+ rev.mid(pos1+1, pos2-pos1-1) == "0" )
+ {
+ // For a branch tag 2.10.0.6, we want:
+ // branchpoint = "2.10"
+ // rev = "2.10.6"
+ branchpoint = rev.left(pos1);
+ rev.remove(pos1+1, pos2-pos1);
+ }
+ if( rev != "1.1.1" )
+ {
+ LogDialogTagInfo *taginfo = new LogDialogTagInfo;
+ taginfo->rev = rev;
+ taginfo->tag = tag;
+ taginfo->branchpoint = branchpoint;
+ tags.append(taginfo);
+ }
+ }
+ else
+ {
+ state = Admin;
+ }
+ break;
+ case Admin:
+ if( line == "----------------------------" )
+ {
+ state = Revision;
+ }
+ break;
+ case Revision:
+ logInfo.m_revision = rev = line.section(' ', 1, 1);
+ state = Author;
+ break;
+ case Author:
+ {
+ QStringList strList = QStringList::split(";", line);
+
+ // convert date into ISO format (YYYY-MM-DDTHH:MM:SS)
+ int len = strList[0].length();
+ QString dateTimeStr = strList[0].right(len-6); // remove 'date: '
+ dateTimeStr.replace('/', '-');
+
+ QString date = dateTimeStr.section(' ', 0, 0);
+ QString time = dateTimeStr.section(' ', 1, 1);
+ logInfo.m_dateTime.setTime_t(KRFCDate::parseDateISO8601(date + 'T' + time));
+
+ logInfo.m_author = strList[1].section(':', 1, 1).stripWhiteSpace();
+
+ state = Branches;
+ }
+ break;
+ case Branches:
+ if( !line.startsWith("branches:") )
+ {
+ logInfo.m_comment = line;
+ state = Comment;
+ }
+ break;
+ case Comment:
+ if( line == "----------------------------" )
+ {
+ state = Revision;
+ }
+ else if( line == "=============================================================================" )
+ {
+ state = Finished;
+ }
+ if( state == Comment ) // still in message
+ logInfo.m_comment += '\n' + line;
+ else
+ {
+ // Create tagcomment
+ QString branchrev;
+ int pos1, pos2;
+ // 1.60.x.y => revision belongs to branch 1.60.0.x
+ if( (pos2 = rev.findRev('.')) > 0 &&
+ (pos1 = rev.findRev('.', pos2-1)) > 0 )
+ branchrev = rev.left(pos2);
+
+ // Build Cervisia::TagInfo for logInfo
+ QPtrListIterator<LogDialogTagInfo> it(tags);
+ for( ; it.current(); ++it )
+ {
+ if( rev == it.current()->rev )
+ {
+ // This never matches branch tags...
+ logInfo.m_tags.push_back(Cervisia::TagInfo(it.current()->tag,
+ Cervisia::TagInfo::Tag));
+ }
+ if( rev == it.current()->branchpoint )
+ {
+ logInfo.m_tags.push_back(Cervisia::TagInfo(it.current()->tag,
+ Cervisia::TagInfo::Branch));
+ }
+ if( branchrev == it.current()->rev )
+ {
+ // ... and this never matches ordinary tags :-)
+ logInfo.m_tags.push_back(Cervisia::TagInfo(it.current()->tag,
+ Cervisia::TagInfo::OnBranch));
+ }
+ }
+
+ plain->addRevision(logInfo);
+ tree->addRevision(logInfo);
+ list->addRevision(logInfo);
+
+ items.append(new Cervisia::LogInfo(logInfo));
+
+ // reset for next entry
+ logInfo = Cervisia::LogInfo();
+ }
+ break;
+ case Finished:
+ ;
+ }
+ }
+
+ tagcombo[0]->insertItem(QString::null);
+ tagcombo[1]->insertItem(QString::null);
+ QPtrListIterator<LogDialogTagInfo> it(tags);
+ for( ; it.current(); ++it )
+ {
+ QString str = it.current()->tag;
+ if( !it.current()->branchpoint.isEmpty() )
+ str += i18n(" (Branchpoint)");
+ tagcombo[0]->insertItem(str);
+ tagcombo[1]->insertItem(str);
+ }
+
+ plain->scrollToTop();
+
+ tree->collectConnections();
+ tree->recomputeCellSizes();
+
+ return true; // successful
+}
+
+
+void LogDialog::slotOk()
+{
+ // make sure that the user selected a revision
+ if( selectionA.isEmpty() && selectionB.isEmpty() )
+ {
+ KMessageBox::information(this,
+ i18n("Please select revision A or B first."), "Cervisia");
+ return;
+ }
+
+ // retrieve the selected revision
+ QString revision;
+ if( !selectionA.isEmpty() )
+ revision = selectionA;
+ else
+ revision = selectionB;
+
+ // create a temporary file
+ const QString suffix("-" + revision + "-" + QFileInfo(filename).fileName());
+ const QString tempFileName(::tempFileName(suffix));
+
+ // retrieve the file with the selected revision from cvs
+ // and save the content into the temporary file
+ DCOPRef job = cvsService->downloadRevision(filename, revision, tempFileName);
+ if( !cvsService->ok() )
+ return;
+
+ ProgressDialog dlg(this, "View", job, "view", i18n("View File"));
+ if( dlg.execute() )
+ {
+ // make file read-only
+ chmod(QFile::encodeName(tempFileName), 0400);
+
+ // open file in preferred editor
+ KURL url;
+ url.setPath(tempFileName);
+ (void) new KRun(url, 0, true, false);
+ }
+}
+
+
+void LogDialog::slotApply()
+{
+ if( selectionA.isEmpty() )
+ {
+ KMessageBox::information(this,
+ i18n("Please select revision A or revisions A and B first."),
+ "Cervisia");
+ return;
+ }
+
+ Cervisia::PatchOptionDialog optionDlg;
+ if( optionDlg.exec() == KDialogBase::Rejected )
+ return;
+
+ QString format = optionDlg.formatOption();
+ QString diffOptions = optionDlg.diffOptions();
+
+ DCOPRef job = cvsService->diff(filename, selectionA, selectionB, diffOptions,
+ format);
+ if( !cvsService->ok() )
+ return;
+
+ ProgressDialog dlg(this, "Diff", job, "", i18n("CVS Diff"));
+ if( !dlg.execute() )
+ return;
+
+ QString fileName = KFileDialog::getSaveFileName();
+ if( fileName.isEmpty() )
+ return;
+
+ if( !Cervisia::CheckOverwrite(fileName) )
+ return;
+
+ QFile f(fileName);
+ if( !f.open(IO_WriteOnly) )
+ {
+ KMessageBox::sorry(this,
+ i18n("Could not open file for writing."),
+ "Cervisia");
+ return;
+ }
+
+ QTextStream t(&f);
+ QString line;
+ while( dlg.getLine(line) )
+ t << line << '\n';
+
+ f.close();
+}
+
+
+void LogDialog::findClicked()
+{
+ KFindDialog dlg(this);
+ if( dlg.exec() == KDialogBase::Accepted )
+ plain->searchText(dlg.options(), dlg.pattern());
+}
+
+
+void LogDialog::diffClicked()
+{
+ if (selectionA.isEmpty())
+ {
+ KMessageBox::information(this,
+ i18n("Please select revision A or revisions A and B first."),
+ "Cervisia");
+ return;
+ }
+
+ // Non-modal dialog
+ DiffDialog *l = new DiffDialog(partConfig);
+ if (l->parseCvsDiff(cvsService, filename, selectionA, selectionB))
+ l->show();
+ else
+ delete l;
+}
+
+
+void LogDialog::annotateClicked()
+{
+ AnnotateDialog *l = new AnnotateDialog(partConfig);
+ AnnotateController ctl(l, cvsService);
+ ctl.showDialog(filename, selectionA);
+}
+
+
+void LogDialog::revisionSelected(QString rev, bool rmb)
+{
+ QPtrListIterator<Cervisia::LogInfo> it(items);
+ for (; it.current(); ++it)
+ if (it.current()->m_revision == rev)
+ {
+ if (rmb)
+ selectionB = rev;
+ else
+ selectionA = rev;
+
+ revbox[rmb?1:0]->setText(rev);
+ authorbox[rmb?1:0]->setText(it.current()->m_author);
+ datebox[rmb?1:0]->setText(it.current()->dateTimeToString());
+ commentbox[rmb?1:0]->setText(it.current()->m_comment);
+ tagsbox[rmb?1:0]->setText(it.current()->tagsToString());
+
+ tree->setSelectedPair(selectionA, selectionB);
+ list->setSelectedPair(selectionA, selectionB);
+
+ updateButtons();
+ return;
+ }
+ kdDebug(8050) << "Internal error: Revision not found " << rev << "." << endl;
+}
+
+
+void LogDialog::tagSelected(LogDialogTagInfo* tag, bool rmb)
+{
+ if (tag->branchpoint.isEmpty())
+ revisionSelected(tag->rev, rmb);
+ else
+ revisionSelected(tag->branchpoint, rmb);
+}
+
+
+void LogDialog::updateButtons()
+{
+ // no versions selected?
+ if( selectionA.isEmpty() && selectionB.isEmpty() )
+ {
+ enableButton(User1, true); // annotate
+ enableButton(User2, false); // diff
+ enableButtonOK(false); // view
+ enableButtonApply(false); // create patch
+ }
+ // both versions selected?
+ else if( !selectionA.isEmpty() && !selectionB.isEmpty() )
+ {
+ enableButton(User1, false); // annotate
+ enableButton(User2, true); // diff
+ enableButtonOK(false); // view
+ enableButtonApply(true); // create patch
+ }
+ // only single version selected?
+ else
+ {
+ enableButton(User1, true); // annotate
+ enableButton(User2, true); // diff
+ enableButtonOK(true); // view
+ enableButtonApply(true); // create patch
+ }
+}
+
+
+void LogDialog::tagASelected(int n)
+{
+ if (n)
+ tagSelected(tags.at(n-1), false);
+}
+
+
+void LogDialog::tagBSelected(int n)
+{
+ if (n)
+ tagSelected(tags.at(n-1), true);
+}
+
+
+void LogDialog::tabChanged(QWidget* w)
+{
+ bool isPlainView = (w == plain);
+ showButton(User3, isPlainView);
+}
+
+#include "logdlg.moc"
+
+// Local Variables:
+// c-basic-offset: 4
+// End:
diff --git a/cervisia/logdlg.h b/cervisia/logdlg.h
new file mode 100644
index 00000000..c5cce4b3
--- /dev/null
+++ b/cervisia/logdlg.h
@@ -0,0 +1,105 @@
+/*
+ * Copyright (C) 1999-2002 Bernd Gehrmann
+ * bernd@mail.berlios.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.
+ *
+ * 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, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+
+#ifndef LOGDLG_H
+#define LOGDLG_H
+
+#include <kdialogbase.h>
+
+#include "loginfo.h"
+
+#include <qptrlist.h>
+
+
+class LogListView;
+class LogTreeView;
+class LogPlainView;
+
+class KConfig;
+
+class QComboBox;
+class QLabel;
+class QTabWidget;
+class QTextEdit;
+class CvsService_stub;
+
+class LogDialogTagInfo
+{
+public:
+ QString rev;
+ QString tag;
+ QString branchpoint;
+};
+
+
+class LogDialog : public KDialogBase
+{
+ Q_OBJECT
+
+public:
+ explicit LogDialog( KConfig& cfg, QWidget *parent=0, const char *name=0 );
+
+ virtual ~LogDialog();
+
+ bool parseCvsLog(CvsService_stub* service, const QString& fileName);
+
+protected slots:
+ void slotOk();
+ void slotApply();
+
+private slots:
+ void findClicked();
+ void diffClicked();
+ void annotateClicked();
+ void revisionSelected(QString rev, bool rmb);
+ void tagASelected(int n);
+ void tagBSelected(int n);
+ void tabChanged(QWidget* w);
+
+private:
+ void tagSelected(LogDialogTagInfo* tag, bool rmb);
+ void updateButtons();
+
+ QString filename;
+ QPtrList<Cervisia::LogInfo> items;
+ QPtrList<LogDialogTagInfo> tags;
+ QString selectionA;
+ QString selectionB;
+ LogTreeView *tree;
+ LogListView *list;
+ LogPlainView *plain;
+ QTabWidget *tabWidget;
+ QLabel *revbox[2];
+ QLabel *authorbox[2];
+ QLabel *datebox[2];
+ QTextEdit *commentbox[2];
+ QTextEdit *tagsbox[2];
+ QComboBox *tagcombo[2];
+
+ CvsService_stub* cvsService;
+ KConfig& partConfig;
+};
+
+#endif
+
+
+// Local Variables:
+// c-basic-offset: 4
+// End:
diff --git a/cervisia/loginfo.cpp b/cervisia/loginfo.cpp
new file mode 100644
index 00000000..49f7efb2
--- /dev/null
+++ b/cervisia/loginfo.cpp
@@ -0,0 +1,140 @@
+/*
+ * Copyright (c) 2003-2007 André Wöbbeking <Woebbeking@kde.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the 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, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+
+#include "loginfo.h"
+
+#include <qstylesheet.h>
+
+#include <kglobal.h>
+#include <klocale.h>
+
+
+namespace Cervisia
+{
+
+
+TagInfo::TagInfo(const QString& name, Type type)
+ : m_name(name),
+ m_type(type)
+{
+}
+
+
+QString TagInfo::toString(bool prefixWithType) const
+{
+ QString text;
+ if (prefixWithType)
+ {
+ text += typeToString() + QString::fromLatin1(": ");
+ }
+ text += m_name;
+
+ return text;
+}
+
+
+QString TagInfo::typeToString() const
+{
+ QString text;
+ switch (m_type)
+ {
+ case Branch:
+ text = i18n("Branchpoint");
+ break;
+ case OnBranch:
+ text = i18n("On Branch");
+ break;
+ case Tag:
+ text = i18n("Tag");
+ break;
+ }
+
+ return text;
+}
+
+
+QString LogInfo::createToolTipText(bool showTime) const
+{
+ QString text(QString::fromLatin1("<nobr><b>"));
+ text += QStyleSheet::escape(m_revision);
+ text += QString::fromLatin1("</b>&nbsp;&nbsp;");
+ text += QStyleSheet::escape(m_author);
+ text += QString::fromLatin1("&nbsp;&nbsp;<b>");
+ text += QStyleSheet::escape(dateTimeToString(showTime));
+ text += QString::fromLatin1("</b></nobr>");
+
+ if (!m_comment.isEmpty())
+ {
+ text += QString::fromLatin1("<pre>");
+ text += QStyleSheet::escape(m_comment);
+ text += QString::fromLatin1("</pre>");
+ }
+
+ if (!m_tags.isEmpty())
+ {
+ text += QString::fromLatin1("<i>");
+ for (TTagInfoSeq::const_iterator it = m_tags.begin();
+ it != m_tags.end(); ++it)
+ {
+ if (it != m_tags.begin() || m_comment.isEmpty())
+ text += QString::fromLatin1("<br>");
+ text += QStyleSheet::escape((*it).toString());
+ }
+ text += QString::fromLatin1("</i>");
+ }
+
+ return text;
+}
+
+
+QString LogInfo::dateTimeToString(bool showTime, bool shortFormat) const
+{
+ if( showTime )
+ return KGlobal::locale()->formatDateTime(m_dateTime, shortFormat);
+ else
+ return KGlobal::locale()->formatDate(m_dateTime.date(), shortFormat);
+}
+
+
+QString LogInfo::tagsToString(unsigned int types,
+ unsigned int prefixWithType,
+ const QString& separator) const
+{
+ QString text;
+ for (TTagInfoSeq::const_iterator it = m_tags.begin();
+ it != m_tags.end(); ++it)
+ {
+ const TagInfo& tagInfo(*it);
+
+ if (tagInfo.m_type & types)
+ {
+ if (!text.isEmpty())
+ {
+ text += separator;
+ }
+
+ text += tagInfo.toString(tagInfo.m_type & prefixWithType);
+ }
+ }
+
+ return text;
+}
+
+
+} // namespace Cervisia
diff --git a/cervisia/loginfo.h b/cervisia/loginfo.h
new file mode 100644
index 00000000..e4eb7071
--- /dev/null
+++ b/cervisia/loginfo.h
@@ -0,0 +1,163 @@
+/*
+ * Copyright (c) 2003-2007 André Wöbbeking <Woebbeking@kde.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the 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, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+
+#ifndef CERVISIA_LOGINFO_H
+#define CERVISIA_LOGINFO_H
+
+
+#include <qdatetime.h>
+#include <qstring.h>
+#include <qvaluelist.h>
+
+
+namespace Cervisia
+{
+
+
+/**
+ * Dumb data struct to store informations of a tag plus some
+ * convenience methods. The struct is used by the LogInfo struct.
+ */
+struct TagInfo
+{
+ /**
+ * The types of a tag.
+ */
+ enum Type
+ {
+ /**
+ * Branchpoint.
+ */
+ Branch = 1 << 0,
+
+ /**
+ * This type is for internal use. If the revision is in a branch
+ * this tag represents the branch.
+ */
+ OnBranch = 1 << 1,
+
+ /**
+ * Normal tag.
+ */
+ Tag = 1 << 2
+ };
+
+ explicit TagInfo(const QString& name = QString::null, Type type = Tag);
+
+ /**
+ * @param prefixWithType prefix the string with the type of the tag
+ * (e.g. Tag: KDE_3_1_3_RELEASE).
+ *
+ * @return tag as string.
+ */
+ QString toString(bool prefixWithType = true) const;
+
+ /**
+ * @return type of tag as string.
+ */
+ QString typeToString() const;
+
+ /**
+ * The name of the tag.
+ */
+ QString m_name;
+
+ /**
+ * The type of the tag.
+ */
+ Type m_type;
+};
+
+
+/**
+ * Dumb data struct to store the results of the log command plus some
+ * convenience methods.
+ */
+struct LogInfo
+{
+ typedef QValueList<TagInfo> TTagInfoSeq;
+
+ /**
+ * @param showTime show commit time in tooltip.
+ *
+ * @return rich text formatted tooltip text.
+ */
+ QString createToolTipText(bool showTime = true) const;
+
+ /**
+ * Calls KLocale::formatDateTime() to create a formatted string.
+ *
+ * @param showTime show commit time in tooltip.
+ * @param shortFormat using the short date format.
+ *
+ * @return The date/time formatted to the user's locale's conventions.
+ */
+ QString dateTimeToString(bool showTime = true, bool shortFormat = true) const;
+
+ enum
+ {
+ NoTagType = 0,
+ AllTagTypes = TagInfo::Branch | TagInfo::OnBranch | TagInfo::Tag
+ };
+
+ /**
+ * Creates a single string from alls tags.
+ *
+ * @param types tags that should be taken into account.
+ * @param prefixWithType tags that should be prefixed with their type
+ * (see TagInfo::toString()).
+ * @param separator string to separate the tags.
+ *
+ * @return string of joined tags.
+ */
+ QString tagsToString(unsigned int types = AllTagTypes,
+ unsigned int prefixWithType = AllTagTypes,
+ const QString& separator = QString(QChar('\n'))) const;
+
+ /**
+ * The revision of this entry.
+ */
+ QString m_revision;
+
+ /**
+ * The author who committed.
+ */
+ QString m_author;
+
+ /**
+ * The commit message.
+ */
+ QString m_comment;
+
+ /**
+ * The date/time of the commit.
+ */
+ QDateTime m_dateTime;
+
+ /**
+ * Sequence of tags of this entry.
+ */
+ TTagInfoSeq m_tags;
+};
+
+
+} // namespace Cervisia
+
+
+#endif // CERVISIA_LOGINFO_H
diff --git a/cervisia/loglist.cpp b/cervisia/loglist.cpp
new file mode 100644
index 00000000..101dd3d7
--- /dev/null
+++ b/cervisia/loglist.cpp
@@ -0,0 +1,233 @@
+/*
+ * Copyright (C) 1999-2002 Bernd Gehrmann
+ * bernd@mail.berlios.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.
+ *
+ * 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, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+
+#include "loglist.h"
+
+#include <qapplication.h>
+#include <qkeycode.h>
+#include <klocale.h>
+
+#include "loginfo.h"
+#include "misc.h"
+#include "tooltip.h"
+
+
+class LogListViewItem : public KListViewItem
+{
+public:
+
+ enum { Revision, Author, Date, Branch, Comment, Tags };
+
+ LogListViewItem(QListView* list, const Cervisia::LogInfo& logInfo);
+
+ virtual int compare(QListViewItem* i, int col, bool) const;
+
+private:
+ static QString truncateLine(const QString &s);
+
+ Cervisia::LogInfo m_logInfo;
+ friend class LogListView;
+};
+
+
+LogListViewItem::LogListViewItem(QListView* list, const Cervisia::LogInfo& logInfo)
+ : KListViewItem(list),
+ m_logInfo(logInfo)
+{
+ setText(Revision, logInfo.m_revision);
+ setText(Author, logInfo.m_author);
+ setText(Date, logInfo.dateTimeToString());
+ setText(Comment, truncateLine(logInfo.m_comment));
+
+ for (Cervisia::LogInfo::TTagInfoSeq::const_iterator it = logInfo.m_tags.begin();
+ it != logInfo.m_tags.end(); ++it)
+ {
+ const Cervisia::TagInfo& tagInfo(*it);
+
+ if (tagInfo.m_type == Cervisia::TagInfo::OnBranch)
+ {
+ setText(Branch, tagInfo.m_name);
+ }
+ }
+
+ setText(Tags, logInfo.tagsToString(Cervisia::TagInfo::Tag,
+ Cervisia::LogInfo::NoTagType,
+ QString::fromLatin1(", ")));
+}
+
+
+QString LogListViewItem::truncateLine(const QString &s)
+{
+ int pos;
+
+ QString res = s.simplifyWhiteSpace();
+ if ( (pos = res.find('\n')) != -1 )
+ res = res.left(pos) + "...";
+
+ return res;
+}
+
+
+int LogListViewItem::compare(QListViewItem* i, int col, bool ascending) const
+{
+ const LogListViewItem* item = static_cast<LogListViewItem*>(i);
+
+ int iResult;
+ switch (col)
+ {
+ case Revision:
+ iResult = ::compareRevisions(m_logInfo.m_revision, item->m_logInfo.m_revision);
+ break;
+ case Date:
+ iResult = ::compare(m_logInfo.m_dateTime, item->m_logInfo.m_dateTime);
+ break;
+ default:
+ iResult = QListViewItem::compare(i, col, ascending);
+ }
+
+ return iResult;
+}
+
+
+LogListView::LogListView(KConfig& cfg, QWidget *parent, const char *name)
+ : KListView(parent, name)
+ , partConfig(cfg)
+{
+ setAllColumnsShowFocus(true);
+ setShowToolTips(false);
+ setShowSortIndicator(true);
+ setMultiSelection(true);
+ setSorting(LogListViewItem::Revision, false);
+ addColumn(i18n("Revision"));
+ addColumn(i18n("Author"));
+ addColumn(i18n("Date"));
+ addColumn(i18n("Branch"));
+ addColumn(i18n("Comment"));
+ addColumn(i18n("Tags"));
+
+ Cervisia::ToolTip* toolTip = new Cervisia::ToolTip(viewport());
+
+ connect(toolTip, SIGNAL(queryToolTip(const QPoint&, QRect&, QString&)),
+ this, SLOT(slotQueryToolTip(const QPoint&, QRect&, QString&)));
+
+ // without this restoreLayout() can't change the column widths
+ for (int i = 0; i < columns(); ++i)
+ setColumnWidthMode(i, Manual);
+
+ restoreLayout(&partConfig, QString::fromLatin1("LogList view"));
+}
+
+
+LogListView::~LogListView()
+{
+ saveLayout(&partConfig, QString::fromLatin1("LogList view"));
+}
+
+
+void LogListView::addRevision(const Cervisia::LogInfo& logInfo)
+{
+ (void) new LogListViewItem(this, logInfo);
+}
+
+
+void LogListView::setSelectedPair(const QString &selectionA, const QString &selectionB)
+{
+ for ( QListViewItem *item = firstChild(); item;
+ item = item->nextSibling() )
+ {
+ LogListViewItem *i = static_cast<LogListViewItem*>(item);
+ setSelected(i, (selectionA == i->text(LogListViewItem::Revision) ||
+ selectionB == i->text(LogListViewItem::Revision)) );
+ }
+}
+
+void LogListView::contentsMousePressEvent(QMouseEvent *e)
+{
+ // Retrieve selected item
+ const LogListViewItem* selItem
+ = static_cast<LogListViewItem*>(itemAt(contentsToViewport(e->pos())));
+ if( !selItem )
+ return;
+
+ // Retrieve revision
+ const QString revision = selItem->text(LogListViewItem::Revision);
+
+ if ( e->button() == LeftButton )
+ {
+ // If the control key was pressed, then we change revision B not A
+ if( e->state() & ControlButton )
+ emit revisionClicked(revision, true);
+ else
+ emit revisionClicked(revision, false);
+ }
+ else if ( e->button() == MidButton )
+ emit revisionClicked(revision, true);
+}
+
+
+void LogListView::keyPressEvent(QKeyEvent *e)
+{
+ switch (e->key()) {
+ case Key_A:
+ if (currentItem())
+ emit revisionClicked(currentItem()->text(LogListViewItem::Revision), false);
+ break;
+ break;
+ case Key_B:
+ if (currentItem())
+ emit revisionClicked(currentItem()->text(LogListViewItem::Revision), true);
+ break;
+ case Key_Backspace:
+ case Key_Delete:
+ case Key_Down:
+ case Key_Up:
+ case Key_Home:
+ case Key_End:
+ case Key_Next:
+ case Key_Prior:
+ if (e->state() == 0)
+ QListView::keyPressEvent(e);
+ else
+ QApplication::postEvent(this, new QKeyEvent(QEvent::KeyPress, e->key(), e->ascii(), 0));
+ break;
+ default:
+ // Ignore Key_Enter, Key_Return
+ e->ignore();
+ }
+}
+
+
+void LogListView::slotQueryToolTip(const QPoint& viewportPos,
+ QRect& viewportRect,
+ QString& text)
+{
+ if (const LogListViewItem* item = static_cast<LogListViewItem*>(itemAt(viewportPos)))
+ {
+ viewportRect = itemRect(item);
+ text = item->m_logInfo.createToolTipText();
+ }
+}
+
+
+#include "loglist.moc"
+
+// Local Variables:
+// c-basic-offset: 4
+// End:
diff --git a/cervisia/loglist.h b/cervisia/loglist.h
new file mode 100644
index 00000000..dc2bca08
--- /dev/null
+++ b/cervisia/loglist.h
@@ -0,0 +1,71 @@
+/*
+ * Copyright (C) 1999-2002 Bernd Gehrmann
+ * bernd@mail.berlios.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.
+ *
+ * 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, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+
+#ifndef LOGLIST_H
+#define LOGLIST_H
+
+
+#include <klistview.h>
+
+
+class KConfig;
+
+class TipLabel;
+class LogListViewItem;
+
+namespace Cervisia
+{
+struct LogInfo;
+}
+
+
+class LogListView : public KListView
+{
+ Q_OBJECT
+
+public:
+ explicit LogListView( KConfig& cfg, QWidget *parent=0, const char *name=0 );
+ virtual ~LogListView();
+
+ void addRevision(const Cervisia::LogInfo& logInfo);
+ void setSelectedPair(const QString &selectionA, const QString &selectionB);
+
+signals:
+ void revisionClicked(QString rev, bool rmb);
+
+protected:
+ virtual void contentsMousePressEvent(QMouseEvent *e);
+ virtual void keyPressEvent(QKeyEvent *e);
+
+private slots:
+
+ void slotQueryToolTip(const QPoint&, QRect&, QString&);
+
+private:
+
+ KConfig& partConfig;
+};
+
+#endif
+
+
+// Local Variables:
+// c-basic-offset: 4
+// End:
diff --git a/cervisia/logmessageedit.cpp b/cervisia/logmessageedit.cpp
new file mode 100644
index 00000000..33599409
--- /dev/null
+++ b/cervisia/logmessageedit.cpp
@@ -0,0 +1,204 @@
+/*
+ * Copyright (c) 2004 Jason Kivlighn <mizunoami44@users.sourceforge.net>
+ * Copyright (c) 2005 Christian Loose <christian.loose@kdemail.net>
+ *
+ * based on work by Jason Kivlighn (krecipes/src/widgets/kretextedit.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.
+ *
+ * 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, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#include "logmessageedit.h"
+using Cervisia::LogMessageEdit;
+
+#include <qtextstream.h>
+#include <kaccel.h>
+
+
+LogMessageEdit::LogMessageEdit(QWidget* parent)
+ : KTextEdit(parent)
+ , KCompletionBase()
+ , m_completing(false)
+ , m_completionStartPos(0)
+{
+ // create the completion object
+ completionObject();
+
+ // a mouse click stops the completion process
+ connect( this, SIGNAL(clicked(int, int)), SLOT(stopCompletion()) );
+}
+
+
+void LogMessageEdit::setCompletedText(const QString& match)
+{
+ int para, index;
+ getCursorPosition(&para, &index);
+
+ QString paragraphText = text(para);
+ int length = index - m_completionStartPos;
+ QString word = match.right(match.length() - length);
+
+ insert(word);
+
+ setSelection(para, index, para, m_completionStartPos + match.length());
+ setCursorPosition(para, index);
+
+ m_completing = true;
+
+ // disable spellchecker during completion process. Otherwise we lose the
+ // text selection.
+ setCheckSpellingEnabled(false);
+}
+
+
+void LogMessageEdit::setCompletedItems(const QStringList&)
+{
+}
+
+
+void LogMessageEdit::keyPressEvent(QKeyEvent* event)
+{
+ bool noModifier = (event->state() == NoButton ||
+ event->state() == ShiftButton ||
+ event->state() == Keypad);
+
+ if( noModifier )
+ {
+ QString keycode = event->text();
+ if( !keycode.isEmpty() && keycode.unicode()->isPrint() )
+ {
+ KTextEdit::keyPressEvent(event);
+ tryCompletion();
+ event->accept();
+ return;
+ }
+ }
+
+ KeyBindingMap keys = getKeyBindings();
+
+ // handle text completion key
+ KShortcut shortcut = keys[TextCompletion];
+ if( shortcut.isNull() )
+ shortcut = KStdAccel::shortcut(KStdAccel::TextCompletion);
+
+ KKey key(event);
+
+ // accept the suggested completion?
+ if( m_completing && shortcut.contains(key) )
+ {
+ int paraFrom, indexFrom, paraTo, indexTo;
+ getSelection(&paraFrom, &indexFrom, &paraTo, &indexTo);
+
+ removeSelection();
+ setCursorPosition(paraTo, indexTo);
+
+ m_completing = false;
+ setCheckSpellingEnabled(true);
+
+ return;
+ }
+
+ // handle previous match key
+ shortcut = keys[PrevCompletionMatch];
+ if( shortcut.isNull() )
+ shortcut = KStdAccel::shortcut(KStdAccel::PrevCompletion);
+
+ if( shortcut.contains(key) )
+ {
+ rotateMatches(PrevCompletionMatch);
+ return;
+ }
+
+ // handle next match key
+ shortcut = keys[NextCompletionMatch];
+ if( shortcut.isNull() )
+ shortcut = KStdAccel::shortcut(KStdAccel::NextCompletion);
+
+ if( shortcut.contains(key) )
+ {
+ rotateMatches(NextCompletionMatch);
+ return;
+ }
+
+ // any other key (except modifiers) will end the text completion
+ if( event->key() != Qt::Key_Shift && event->key() != Qt::Key_Control &&
+ event->key() != Qt::Key_Alt && event->key() != Qt::Key_Meta )
+ {
+ m_completing = false;
+ setCheckSpellingEnabled(true);
+ }
+
+ KTextEdit::keyPressEvent(event);
+}
+
+
+void LogMessageEdit::stopCompletion()
+{
+ m_completing = false;
+ setCheckSpellingEnabled(true);
+}
+
+
+void LogMessageEdit::tryCompletion()
+{
+ int para, index;
+ getCursorPosition(&para, &index);
+
+ QString paragraphText = text(para);
+ if( paragraphText.at(index).isSpace() )
+ {
+ if( !m_completing )
+ m_completionStartPos = paragraphText.findRev(' ', index-1) + 1;
+
+ int length = index - m_completionStartPos;
+ QString word = paragraphText.mid(m_completionStartPos, length);
+
+ QString match = compObj()->makeCompletion(word);
+ if( !match.isNull() && match != word )
+ {
+ setCompletedText(match);
+ }
+ else
+ {
+ m_completing = false;
+ setCheckSpellingEnabled(true);
+ }
+ }
+}
+
+
+void LogMessageEdit::rotateMatches(KeyBindingType type)
+{
+ KCompletion* completionObj = compObj();
+ if( completionObj && m_completing &&
+ (type == PrevCompletionMatch || type == NextCompletionMatch) )
+ {
+ QString match = (type == PrevCompletionMatch) ? completionObj->previousMatch()
+ : completionObj->nextMatch();
+
+ int para, index;
+ getCursorPosition(&para, &index);
+
+ QString paragraphText = text(para);
+
+ QString word = paragraphText.mid(m_completionStartPos, index - m_completionStartPos);
+
+ if( match.isNull() || match == word )
+ return;
+
+ setCompletedText(match);
+ }
+}
+
+#include "logmessageedit.moc"
diff --git a/cervisia/logmessageedit.h b/cervisia/logmessageedit.h
new file mode 100644
index 00000000..05de18fa
--- /dev/null
+++ b/cervisia/logmessageedit.h
@@ -0,0 +1,61 @@
+/*
+ * Copyright (c) 2004 Jason Kivlighn <mizunoami44@users.sourceforge.net>
+ * Copyright (c) 2005 Christian Loose <christian.loose@kdemail.net>
+ *
+ * based on work by Jason Kivlighn (krecipes/src/widgets/kretextedit.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.
+ *
+ * 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, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#ifndef CERVISIA_LOGMESSAGEEDIT_H
+#define CERVISIA_LOGMESSAGEEDIT_H
+
+#include <ktextedit.h>
+#include <kcompletion.h>
+
+
+namespace Cervisia
+{
+
+
+class LogMessageEdit : public KTextEdit, public KCompletionBase
+{
+ Q_OBJECT
+
+public:
+ explicit LogMessageEdit(QWidget* parent);
+
+ virtual void setCompletedText(const QString& match);
+ virtual void setCompletedItems(const QStringList& items);
+
+protected:
+ void keyPressEvent(QKeyEvent* event);
+
+private slots:
+ void stopCompletion();
+
+private:
+ void tryCompletion();
+ void rotateMatches(KeyBindingType type);
+
+ bool m_completing;
+ int m_completionStartPos;
+};
+
+
+}
+
+
+#endif
diff --git a/cervisia/logplainview.cpp b/cervisia/logplainview.cpp
new file mode 100644
index 00000000..ca28f8b0
--- /dev/null
+++ b/cervisia/logplainview.cpp
@@ -0,0 +1,203 @@
+/*
+ * Copyright (c) 2003 Christian Loose <christian.loose@hamburg.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.
+ *
+ * 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, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+
+#include "logplainview.h"
+
+#include <qregexp.h>
+#include <qstringlist.h>
+#include <qstylesheet.h>
+#include <kfind.h>
+#include <kfinddialog.h>
+#include <klocale.h>
+
+#include "loginfo.h"
+
+using namespace Cervisia;
+
+
+LogPlainView::LogPlainView(QWidget* parent, const char* name)
+ : KTextBrowser(parent, name)
+ , m_find(0)
+ , m_findPos(0)
+{
+ setNotifyClick(false);
+}
+
+
+LogPlainView::~LogPlainView()
+{
+ delete m_find; m_find = 0;
+}
+
+
+void LogPlainView::addRevision(const LogInfo& logInfo)
+{
+ setTextFormat(QStyleSheet::RichText);
+
+ // assemble revision information lines
+ QString logEntry;
+
+ logEntry += "<b>" + i18n("revision %1").arg(QStyleSheet::escape(logInfo.m_revision)) +
+ "</b>";
+ logEntry += " &nbsp;[<a href=\"revA#" + QStyleSheet::escape(logInfo.m_revision) + "\">" +
+ i18n("Select for revision A") +
+ "</a>]";
+ logEntry += " [<a href=\"revB#" + QStyleSheet::escape(logInfo.m_revision) + "\">" +
+ i18n("Select for revision B") +
+ "</a>]<br>";
+ logEntry += "<i>" +
+ i18n("date: %1; author: %2").arg(QStyleSheet::escape(logInfo.dateTimeToString()))
+ .arg(QStyleSheet::escape(logInfo.m_author)) +
+ "</i>";
+
+ append(logEntry);
+
+ setTextFormat(QStyleSheet::PlainText);
+
+ const QChar newline('\n');
+
+ // split comment in separate lines
+ QStringList lines = QStringList::split(newline, logInfo.m_comment, true);
+
+ append(newline);
+ QStringList::Iterator it = lines.begin();
+ QStringList::Iterator end = lines.end();
+ for( ; it != end; ++it )
+ {
+ append((*it).isEmpty() ? QString(newline) : *it);
+ }
+ append(newline);
+
+ setTextFormat(QStyleSheet::RichText);
+
+ for( LogInfo::TTagInfoSeq::const_iterator it = logInfo.m_tags.begin();
+ it != logInfo.m_tags.end(); ++it )
+ {
+ append("<i>" + QStyleSheet::escape((*it).toString()) + "</i>");
+ }
+
+ // add an empty line when we had tags or branches
+ if( !logInfo.m_tags.empty() )
+ {
+ setTextFormat(QStyleSheet::PlainText);
+ append(newline);
+ }
+
+ // add horizontal line
+ setTextFormat(QStyleSheet::RichText);
+ append("<hr>");
+}
+
+
+void LogPlainView::searchText(int options, const QString& pattern)
+{
+ m_find = new KFind(pattern, options, this);
+
+ connect(m_find, SIGNAL(highlight(const QString&, int, int)),
+ this, SLOT(searchHighlight(const QString&, int, int)));
+ connect(m_find, SIGNAL(findNext()),
+ this, SLOT(findNext()));
+
+ m_findPos = 0;
+ if( options & KFindDialog::FromCursor )
+ {
+ const QPoint pos(contentsX(), contentsY());
+ m_findPos = paragraphAt(pos);
+ }
+
+ findNext();
+}
+
+
+void LogPlainView::scrollToTop()
+{
+ setContentsPos(0, 0);
+}
+
+
+void LogPlainView::findNext()
+{
+ static const QRegExp breakLineTag("<br[^>]*>");
+ static const QRegExp htmlTags("<[^>]*>");
+
+ KFind::Result res = KFind::NoMatch;
+
+ while( res == KFind::NoMatch && m_findPos < paragraphs() && m_findPos >= 0 )
+ {
+ if( m_find->needData() )
+ {
+ QString richText = text(m_findPos);
+
+ // replace <br/> with '\n'
+ richText.replace(breakLineTag, "\n");
+
+ // remove html tags from text
+ richText.replace(htmlTags, "");
+
+ m_find->setData(richText);
+ }
+
+ res = m_find->find();
+
+ if( res == KFind::NoMatch )
+ {
+ if( m_find->options() & KFindDialog::FindBackwards )
+ --m_findPos;
+ else
+ ++m_findPos;
+ }
+ }
+
+ // reached the end?
+ if( res == KFind::NoMatch )
+ {
+ if( m_find->shouldRestart() )
+ {
+ m_findPos = 0;
+ findNext();
+ }
+ else
+ {
+ delete m_find;
+ m_find = 0;
+ }
+ }
+}
+
+
+void LogPlainView::searchHighlight(const QString& text, int index, int length)
+{
+ Q_UNUSED(text);
+ setSelection(m_findPos, index, m_findPos, index + length);
+}
+
+
+void LogPlainView::setSource(const QString& name)
+{
+ if( name.isEmpty() )
+ return;
+
+ bool selectedRevisionB = name.startsWith("revB#");
+ if( selectedRevisionB || name.startsWith("revA#") )
+ {
+ emit revisionClicked(name.mid(5), selectedRevisionB);
+ }
+}
+
+#include "logplainview.moc"
diff --git a/cervisia/logplainview.h b/cervisia/logplainview.h
new file mode 100644
index 00000000..f5da46a5
--- /dev/null
+++ b/cervisia/logplainview.h
@@ -0,0 +1,62 @@
+/*
+ * Copyright (c) 2003 Christian Loose <christian.loose@hamburg.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.
+ *
+ * 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, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+
+#ifndef LOGPLAINVIEW_H
+#define LOGPLAINVIEW_H
+
+#include <ktextbrowser.h>
+
+class KConfig;
+class KFind;
+
+namespace Cervisia
+{
+struct LogInfo;
+}
+
+
+class LogPlainView : public KTextBrowser
+{
+ Q_OBJECT
+
+public:
+ explicit LogPlainView(QWidget* parent = 0, const char* name = 0);
+ ~LogPlainView();
+
+ void addRevision(const Cervisia::LogInfo& logInfo);
+
+ void searchText(int options, const QString& pattern);
+
+signals:
+ void revisionClicked(QString rev, bool rmb);
+
+public slots:
+ void scrollToTop();
+ void findNext();
+ void searchHighlight(const QString& text, int index, int length);
+
+protected:
+ virtual void setSource(const QString& name);
+
+private:
+ KFind* m_find;
+ int m_findPos;
+};
+
+#endif
diff --git a/cervisia/logtree.cpp b/cervisia/logtree.cpp
new file mode 100644
index 00000000..1b5258ad
--- /dev/null
+++ b/cervisia/logtree.cpp
@@ -0,0 +1,501 @@
+/*
+ * Copyright (C) 1999-2002 Bernd Gehrmann
+ * bernd@mail.berlios.de
+ * Copyright (c) 2003-2004 Christian Loose <christian.loose@hamburg.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.
+ *
+ * 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, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#include "logtree.h"
+
+#include <qpainter.h>
+#include <kdebug.h>
+#include <kglobal.h>
+#include <kglobalsettings.h>
+
+#include "loginfo.h"
+#include "tooltip.h"
+
+
+const int LogTreeView::BORDER = 8;
+const int LogTreeView::INSPACE = 3;
+
+namespace
+{
+ bool static_initialized = false;
+ int static_width;
+ int static_height;
+}
+
+class LogTreeItem
+{
+public:
+ Cervisia::LogInfo m_logInfo;
+ QString branchpoint;
+ bool firstonbranch;
+ int row;
+ int col;
+ bool selected;
+};
+
+
+class LogTreeConnection
+{
+public:
+ LogTreeItem *start;
+ LogTreeItem *end;
+};
+
+
+LogTreeView::LogTreeView(QWidget *parent, const char *name)
+ : QTable(parent, name)
+{
+ if (!static_initialized)
+ {
+ static_initialized = true;
+ QFontMetrics fm( fontMetrics() );
+ static_width = fm.width("1234567890") + 2*BORDER + 2*INSPACE;
+ static_height = 2*fm.height() + 2*BORDER + 3*INSPACE;
+ }
+
+ setNumCols(0);
+ setNumRows(0);
+ setReadOnly(true);
+ setFocusStyle(QTable::FollowStyle);
+ setSelectionMode(QTable::NoSelection);
+ setShowGrid(false);
+ horizontalHeader()->hide();
+ setTopMargin(0);
+ verticalHeader()->hide();
+ setLeftMargin(0);
+ setFrameStyle( QFrame::WinPanel | QFrame::Sunken );
+ setBackgroundMode(PaletteBase);
+ setFocusPolicy(NoFocus);
+
+ currentRow = -1;
+ currentCol = -1;
+
+ items.setAutoDelete(true);
+ connections.setAutoDelete(true);
+
+ Cervisia::ToolTip* toolTip = new Cervisia::ToolTip(viewport());
+
+ connect(toolTip, SIGNAL(queryToolTip(const QPoint&, QRect&, QString&)),
+ this, SLOT(slotQueryToolTip(const QPoint&, QRect&, QString&)));
+}
+
+
+void LogTreeView::addRevision(const Cervisia::LogInfo& logInfo)
+{
+ QString branchpoint, branchrev;
+
+ const QString rev(logInfo.m_revision);
+
+ // find branch
+ int pos1, pos2;
+ if ((pos2 = rev.findRev('.')) > 0 &&
+ (pos1 = rev.findRev('.', pos2-1)) > 0)
+ {
+ // e. g. for rev = 1.1.2.3 we have
+ // branchrev = 1.1.2, branchpoint = 1.1
+ branchrev = rev.left(pos2);
+ branchpoint = rev.left(pos1);
+ }
+
+ if (branchrev.isEmpty())
+ {
+ // Most probably we are on the trunk
+ setNumRows(numRows()+1);
+ setNumCols(1);
+ LogTreeItem *item = new LogTreeItem;
+ item->m_logInfo = logInfo;
+ item->branchpoint = branchpoint;
+ item->firstonbranch = false;
+ item->row = numRows()-1;
+ item->col = 0;
+ item->selected = false;
+ items.append(item);
+ return;
+ }
+
+ // look whether we have revisions on this branch
+ // shift them up
+ int row=-1, col=-1;
+ QPtrListIterator<LogTreeItem> it(items);
+ for (; it.current(); ++it)
+ {
+ if (branchrev == (it.current()->m_logInfo.m_revision).left(branchrev.length()))
+ {
+ it.current()->firstonbranch = false;
+ row = it.current()->row;
+ col = it.current()->col;
+ it.current()->row--;
+ // Are we at the top of the widget?
+ if (row == 0)
+ {
+ QPtrListIterator<LogTreeItem> it2(items);
+ for (; it2.current(); ++it2)
+ it2.current()->row++;
+ setNumRows(numRows()+1);
+ row = 1;
+ }
+ }
+ }
+
+ if (row == -1)
+ {
+ // Ok, so we must open a new branch
+ // Let's find the branch point
+ QPtrListIterator<LogTreeItem> it3(items);
+ for (it3.toLast(); it3.current(); --it3)
+ {
+ if (branchpoint == it3.current()->m_logInfo.m_revision)
+ {
+ // Move existing branches to the right
+ QPtrListIterator<LogTreeItem> it4(items);
+ for (; it4.current(); ++it4)
+ if (it4.current()->col > it3.current()->col)
+ {
+ it4.current()->col++;
+ }
+ setNumCols(numCols()+1);
+ row = it3.current()->row-1;
+ col = it3.current()->col+1;
+ if (row == -1)
+ {
+ QPtrListIterator<LogTreeItem> it5(items);
+ for (; it5.current(); ++it5)
+ it5.current()->row++;
+ setNumRows(numRows()+1);
+ row = 0;
+ }
+ break;
+ }
+ }
+ }
+
+ LogTreeItem *item = new LogTreeItem;
+ item->m_logInfo = logInfo;
+ item->branchpoint = branchpoint;
+ item->firstonbranch = true;
+ item->row = row;
+ item->col = col;
+ item->selected = false;
+ items.append(item);
+
+#if 0
+ cout << "Dump: " << endl;
+ cout << "Rows: " << numRows() << "Cols: " << numCols() << endl;
+ QPtrListIterator<LogTreeItem> it5(items);
+ for (; it5.current(); ++it5)
+ {
+ cout << "Rev: "<< it5.current()->rev << endl;
+ cout << "row: "<< it5.current()->row << ", col: " << it5.current()->col << endl;
+ cout << "fob: "<< it5.current()->firstonbranch << endl;
+ }
+ cout << "End Dump" << endl;
+#endif
+
+}
+
+
+void LogTreeView::collectConnections()
+{
+ QPtrListIterator<LogTreeItem> it(items);
+ for (; it.current(); ++it)
+ {
+ QString rev = it.current()->m_logInfo.m_revision;
+
+ QPtrListIterator<LogTreeItem> it2(items);
+ for (it2=it,++it2; it2.current(); ++it2)
+ if (it2.current()->branchpoint == rev &&
+ it2.current()->firstonbranch)
+ {
+ LogTreeConnection *conn = new LogTreeConnection;
+ conn->start = it.current();
+ conn->end = it2.current();
+ connections.append(conn);
+ }
+ }
+}
+
+
+void LogTreeView::setSelectedPair(QString selectionA, QString selectionB)
+{
+ QPtrListIterator<LogTreeItem> it(items);
+ for(; it.current(); ++it)
+ {
+ bool oldstate = it.current()->selected;
+ bool newstate = ( selectionA == it.current()->m_logInfo.m_revision ||
+ selectionB == it.current()->m_logInfo.m_revision );
+ if (oldstate != newstate)
+ {
+ it.current()->selected = newstate;
+ repaint(false);
+ }
+ }
+}
+
+
+QSize LogTreeView::sizeHint() const
+{
+ return QSize(2 * static_width, 3 * static_height);
+}
+
+
+QString LogTreeView::text(int row, int col) const
+{
+ LogTreeItem* item = 0;
+
+ QPtrListIterator<LogTreeItem> it(items);
+ for( ; it.current(); ++it )
+ {
+ if( it.current()->col == col && it.current()->row == row )
+ {
+ item = it.current();
+ break;
+ }
+ }
+
+ QString text;
+
+ if( item && !item->m_logInfo.m_author.isNull() )
+ text = item->m_logInfo.createToolTipText();
+
+ return text;
+}
+
+
+void LogTreeView::paintCell(QPainter *p, int row, int col, const QRect& cr,
+ bool selected, const QColorGroup& cg)
+{
+ Q_UNUSED(selected)
+ Q_UNUSED(cr)
+ bool followed, branched;
+ LogTreeItem *item;
+
+ branched = false;
+ followed = false;
+ item = 0;
+
+ QPtrListIterator<LogTreeItem> it(items);
+ for(; it.current(); ++it)
+ {
+ int itcol = it.current()->col;
+ int itrow = it.current()->row;
+ if (itrow == row-1 && itcol == col)
+ followed = true;
+ if (itrow == row && itcol == col)
+ item = it.current();
+ }
+ QPtrListIterator<LogTreeConnection> it2(connections);
+ for (; it2.current(); ++it2)
+ {
+ int itcol1 = it2.current()->start->col;
+ int itcol2 = it2.current()->end->col;
+ int itrow = it2.current()->start->row;
+ if (itrow == row && itcol1 <= col && itcol2 > col)
+ branched = true;
+ }
+
+ p->fillRect(0, 0, columnWidth(col), rowHeight(row),
+ cg.base());
+ p->setPen(cg.text());
+ if (item)
+ paintRevisionCell(p, row, col, item->m_logInfo,
+ followed, branched, item->selected);
+ else if (followed || branched)
+ paintConnector(p, row, col, followed, branched);
+}
+
+
+void LogTreeView::paintConnector(QPainter *p,
+ int row, int col, bool followed, bool branched)
+{
+ const int midx = columnWidth(col) / 2;
+ const int midy = rowHeight(row) / 2;
+
+ p->drawLine(0, midy, branched ? columnWidth(col) : midx, midy);
+ if (followed)
+ p->drawLine(midx, midy, midx, 0);
+}
+
+
+QSize LogTreeView::computeSize(const Cervisia::LogInfo& logInfo,
+ int* authorHeight,
+ int* tagsHeight) const
+{
+ const QFontMetrics fm(fontMetrics());
+
+ const QString tags(logInfo.tagsToString(Cervisia::TagInfo::Branch | Cervisia::TagInfo::Tag,
+ Cervisia::TagInfo::Branch));
+
+ const QSize r1 = fm.size(AlignCenter, logInfo.m_revision);
+ const QSize r3 = fm.size(AlignCenter, logInfo.m_author);
+
+ if (authorHeight)
+ *authorHeight = r3.height();
+
+ int infoWidth = kMax(static_width - 2 * BORDER, kMax(r1.width(), r3.width()));
+ int infoHeight = r1.height() + r3.height() + 3 * INSPACE;
+
+ if (!tags.isEmpty())
+ {
+ const QSize r2 = fm.size(AlignCenter, tags);
+ infoWidth = kMax(infoWidth, r2.width());
+ infoHeight += r2.height() + INSPACE;
+ if (tagsHeight)
+ *tagsHeight = r2.height();
+ }
+ else
+ {
+ if (tagsHeight)
+ *tagsHeight = 0;
+ }
+ infoWidth += 2 * INSPACE;
+
+ return QSize(infoWidth, infoHeight);
+}
+
+
+void LogTreeView::paintRevisionCell(QPainter *p,
+ int row, int col,
+ const Cervisia::LogInfo& logInfo,
+ bool followed, bool branched, bool selected)
+{
+ int authorHeight;
+ int tagsHeight;
+ const QSize infoSize(computeSize(logInfo, &authorHeight, &tagsHeight));
+ const QSize cellSize(columnWidth(col), rowHeight(row));
+
+ const int midx(cellSize.width() / 2);
+ const int midy(cellSize.height() / 2);
+
+ QRect rect(QPoint((cellSize.width() - infoSize.width()) / 2,
+ (cellSize.height() - infoSize.height()) / 2),
+ infoSize);
+
+ // Connectors
+ if (followed)
+ p->drawLine(midx, 0, midx, rect.y()); // to the top
+
+ if (branched)
+ p->drawLine(rect.x() + infoSize.width(), midy, cellSize.width(), midy); // to the right
+
+ p->drawLine(midx, rect.y() + infoSize.height(), midx, cellSize.height()); // to the bottom
+
+ // The box itself
+ if (selected)
+ {
+ p->fillRect(rect, KGlobalSettings::highlightColor());
+ p->setPen(KGlobalSettings::highlightedTextColor());
+ }
+ else
+ {
+ p->drawRoundRect(rect, 10, 10);
+ }
+
+ rect.setY(rect.y() + INSPACE);
+
+ p->drawText(rect, AlignHCenter, logInfo.m_author);
+ rect.setY(rect.y() + authorHeight + INSPACE);
+
+ const QString tags(logInfo.tagsToString(Cervisia::TagInfo::Branch | Cervisia::TagInfo::Tag,
+ Cervisia::TagInfo::Branch));
+ if (!tags.isEmpty())
+ {
+ const QFont font(p->font());
+ QFont underline(font);
+ underline.setUnderline(true);
+
+ p->setFont(underline);
+ p->drawText(rect, AlignHCenter, tags);
+ p->setFont(font);
+
+ rect.setY(rect.y() + tagsHeight + INSPACE);
+ }
+
+ p->drawText(rect, AlignHCenter, logInfo.m_revision);
+}
+
+
+void LogTreeView::contentsMousePressEvent(QMouseEvent *e)
+{
+ if ( e->button() == MidButton ||
+ e->button() == LeftButton)
+ {
+ int row = rowAt( e->pos().y() );
+ int col = columnAt( e->pos().x() );
+
+ QPtrListIterator<LogTreeItem> it(items);
+ for(; it.current(); ++it)
+ if (it.current()->row == row
+ && it.current()->col == col)
+ {
+ // Change selection for revision B if the middle mouse button or
+ // the left mouse button with the control key was pressed
+ bool changeRevB = (e->button() == MidButton) ||
+ (e->button() == LeftButton &&
+ e->state() & ControlButton);
+
+ emit revisionClicked(it.current()->m_logInfo.m_revision, changeRevB);
+ break;
+ }
+ }
+
+ viewport()->update();
+}
+
+
+void LogTreeView::recomputeCellSizes ()
+{
+ // Compute maximum for each column and row
+ for (QPtrListIterator<LogTreeItem> it(items); it.current(); ++it)
+ {
+ const LogTreeItem *item = it.current();
+
+ const QSize cellSize(computeSize(item->m_logInfo) + QSize(2 * BORDER, 2 * BORDER));
+
+ setColumnWidth(item->col, kMax(columnWidth(item->col), cellSize.width()));
+ setRowHeight(item->row, kMax(rowHeight(item->row), cellSize.height()));
+ }
+
+ viewport()->update();
+}
+
+
+void LogTreeView::slotQueryToolTip(const QPoint& viewportPos,
+ QRect& viewportRect,
+ QString& tipText)
+{
+ const QPoint contentsPos(viewportToContents(viewportPos));
+ const int column(columnAt(contentsPos.x()));
+ const int row(rowAt(contentsPos.y()));
+
+ tipText = text(row, column);
+ if (tipText.isEmpty())
+ return;
+
+ viewportRect = cellGeometry(row, column);
+ viewportRect.moveTopLeft(contentsToViewport(viewportRect.topLeft()));
+}
+
+
+#include "logtree.moc"
+
+
+// Local Variables:
+// c-basic-offset: 4
+// End:
diff --git a/cervisia/logtree.h b/cervisia/logtree.h
new file mode 100644
index 00000000..9ab505bc
--- /dev/null
+++ b/cervisia/logtree.h
@@ -0,0 +1,91 @@
+/*
+ * Copyright (C) 1999-2002 Bernd Gehrmann
+ * bernd@mail.berlios.de
+ * Copyright (c) 2004 Christian Loose <christian.loose@hamburg.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.
+ *
+ * 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, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+
+#ifndef LOGTREE_H
+#define LOGTREE_H
+
+
+#include <qptrlist.h>
+
+#include <qtable.h>
+
+
+class LogTreeItem;
+class LogTreeConnection;
+
+namespace Cervisia
+{
+struct LogInfo;
+}
+
+
+typedef QPtrList<LogTreeItem> LogTreeItemList;
+typedef QPtrList<LogTreeConnection> LogTreeConnectionList;
+
+
+class LogTreeView : public QTable
+{
+ Q_OBJECT
+
+public:
+ explicit LogTreeView( QWidget *parent=0, const char *name=0 );
+
+ void addRevision(const Cervisia::LogInfo& logInfo);
+ void setSelectedPair(QString selectionA, QString selectionB);
+ void collectConnections();
+ void recomputeCellSizes();
+ virtual void paintCell(QPainter *p, int row, int col, const QRect& cr,
+ bool selected, const QColorGroup& cg);
+
+ virtual QSize sizeHint() const;
+
+ virtual QString text(int row, int col) const;
+
+signals:
+ void revisionClicked(QString rev, bool rmb);
+
+protected:
+ virtual void contentsMousePressEvent(QMouseEvent *e);
+
+private slots:
+
+ void slotQueryToolTip(const QPoint&, QRect&, QString&);
+
+private:
+ QSize computeSize(const Cervisia::LogInfo&, int* = 0, int* = 0) const;
+ void paintRevisionCell(QPainter *p, int row, int col, const Cervisia::LogInfo& logInfo,
+ bool followed, bool branched, bool selected);
+ void paintConnector(QPainter *p, int row, int col, bool followed, bool branched);
+
+ LogTreeItemList items;
+ LogTreeConnectionList connections;
+ int currentRow, currentCol;
+
+ static const int BORDER;
+ static const int INSPACE;
+};
+
+#endif
+
+
+// Local Variables:
+// c-basic-offset: 4
+// End:
diff --git a/cervisia/main.cpp b/cervisia/main.cpp
new file mode 100644
index 00000000..e8e6a505
--- /dev/null
+++ b/cervisia/main.cpp
@@ -0,0 +1,213 @@
+/*
+ * Copyright (C) 1999-2002 Bernd Gehrmann
+ * bernd@mail.berlios.de
+ * Copyright (c) 2003-2004 Christian Loose <christian.loose@hamburg.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.
+ *
+ * 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, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#include <iostream>
+
+#include <qfileinfo.h>
+#include <kaboutdata.h>
+#include <kapplication.h>
+#include <kcmdlineargs.h>
+#include <kconfig.h>
+#include <klocale.h>
+#include <kurl.h>
+
+#include "misc.h"
+#include "cervisiashell.h"
+#include "cvsservice_stub.h"
+#include "annotatedlg.h"
+#include "annotatectl.h"
+#include "logdlg.h"
+#include "resolvedlg.h"
+#include "version.h"
+
+
+static CvsService_stub* StartDCOPService(const QString& directory)
+{
+ // start the cvs DCOP service
+ QString error;
+ QCString appId;
+ if( KApplication::startServiceByDesktopName("cvsservice", QStringList(),
+ &error, &appId) )
+ {
+ std::cerr << "Starting cvsservice failed with message: "
+ << error.latin1() << std::endl;
+ exit(1);
+ }
+
+ DCOPRef repository(appId, "CvsRepository");
+
+ repository.call("setWorkingCopy(QString)", directory);
+
+ // create a reference to the service
+ return new CvsService_stub(appId, "CvsService");
+}
+
+
+static int ShowResolveDialog(const QString& fileName)
+{
+ KConfig* config = new KConfig("cervisiapartrc");
+
+ ResolveDialog* dlg = new ResolveDialog(*config);
+ kapp->setMainWidget(dlg);
+ if( dlg->parseFile(fileName) )
+ dlg->show();
+ else
+ delete dlg;
+
+ int result = kapp->exec();
+
+ delete config;
+
+ return result;
+}
+
+
+static int ShowLogDialog(const QString& fileName)
+{
+ KConfig* config = new KConfig("cervisiapartrc");
+ LogDialog* dlg = new LogDialog(*config);
+ kapp->setMainWidget(dlg);
+
+ // get directory for file
+ const QFileInfo fi(fileName);
+ QString directory = fi.dirPath(true);
+
+ // start the cvs DCOP service
+ CvsService_stub* cvsService = StartDCOPService(directory);
+
+ if( dlg->parseCvsLog(cvsService, fi.fileName()) )
+ dlg->show();
+ else
+ delete dlg;
+
+ int result = kapp->exec();
+
+ // stop the cvs DCOP service
+ cvsService->quit();
+ delete cvsService;
+
+ delete config;
+
+ return result;
+}
+
+
+static int ShowAnnotateDialog(const QString& fileName)
+{
+ KConfig* config = new KConfig("cervisiapartrc");
+ AnnotateDialog* dlg = new AnnotateDialog(*config);
+ kapp->setMainWidget(dlg);
+
+ // get directory for file
+ const QFileInfo fi(fileName);
+ QString directory = fi.dirPath(true);
+
+ // start the cvs DCOP service
+ CvsService_stub* cvsService = StartDCOPService(directory);
+
+ AnnotateController ctl(dlg, cvsService);
+ ctl.showDialog(fi.fileName());
+
+ int result = kapp->exec();
+
+ // stop the cvs DCOP service
+ cvsService->quit();
+ delete cvsService;
+
+ delete config;
+
+ return result;
+}
+
+
+extern "C" KDE_EXPORT int kdemain(int argc, char **argv)
+{
+ static KCmdLineOptions options[] = {
+ { "+[directory]", I18N_NOOP("The sandbox to be loaded"), 0 },
+ { "resolve <file>", I18N_NOOP("Show resolve dialog for the given file"), 0 },
+ { "log <file>", I18N_NOOP("Show log dialog for the given file"), 0 },
+ { "annotate <file>", I18N_NOOP("Show annotation dialog for the given file"), 0 },
+ KCmdLineLastOption
+ };
+ KAboutData about("cervisia", I18N_NOOP("Cervisia"), CERVISIA_VERSION,
+ I18N_NOOP("A CVS frontend"), KAboutData::License_GPL,
+ I18N_NOOP("Copyright (c) 1999-2002 Bernd Gehrmann\n"
+ "Copyright (c) 2002-2007 the Cervisia authors"), 0,
+ "http://www.kde.org/apps/cervisia");
+
+ about.addAuthor("Bernd Gehrmann", I18N_NOOP("Original author and former "
+ "maintainer"), "bernd@mail.berlios.de", 0);
+ about.addAuthor("Christian Loose", I18N_NOOP("Maintainer"),
+ "christian.loose@kdemail.net", 0);
+ about.addAuthor("Andr\303\251 W\303\266bbeking", I18N_NOOP("Developer"),
+ "woebbeking@kde.org", 0);
+ about.addAuthor("Carlos Woelz", I18N_NOOP("Documentation"),
+ "carloswoelz@imap-mail.com", 0);
+
+ about.addCredit("Richard Moore", I18N_NOOP("Conversion to KPart"),
+ "rich@kde.org", 0);
+
+ KCmdLineArgs::init(argc, argv, &about);
+ KCmdLineArgs::addCmdLineOptions(options);
+
+ KApplication app;
+
+ QString resolvefile = KCmdLineArgs::parsedArgs()->getOption("resolve");
+ if (!resolvefile.isEmpty())
+ return ShowResolveDialog(resolvefile);
+
+ // is command line option 'show log dialog' specified?
+ QString logFile = KCmdLineArgs::parsedArgs()->getOption("log");
+ if( !logFile.isEmpty() )
+ return ShowLogDialog(logFile);
+
+ // is command line option 'show annotation dialog' specified?
+ QString annotateFile = KCmdLineArgs::parsedArgs()->getOption("annotate");
+ if( !annotateFile.isEmpty() )
+ return ShowAnnotateDialog(annotateFile);
+
+ if ( app.isRestored() ) {
+ RESTORE(CervisiaShell);
+ } else {
+ CervisiaShell* shell = new CervisiaShell();
+
+ const KCmdLineArgs* args = KCmdLineArgs::parsedArgs();
+ if( args->count() )
+ {
+ KURL directory = args->url(0);
+ shell->openURL(directory);
+ }
+ else
+ shell->openURL();
+
+ shell->setIcon(app.icon());
+ app.setMainWidget(shell);
+ shell->show();
+ }
+
+ int res = app.exec();
+ cleanupTempFiles();
+ return res;
+}
+
+
+// Local Variables:
+// c-basic-offset: 4
+// End:
diff --git a/cervisia/mergedlg.cpp b/cervisia/mergedlg.cpp
new file mode 100644
index 00000000..92d337d5
--- /dev/null
+++ b/cervisia/mergedlg.cpp
@@ -0,0 +1,164 @@
+/*
+ * Copyright (C) 1999-2002 Bernd Gehrmann
+ * bernd@mail.berlios.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.
+ *
+ * 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, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+
+#include "mergedlg.h"
+
+#include <qbuttongroup.h>
+#include <qcombobox.h>
+#include <qlabel.h>
+#include <qlayout.h>
+#include <qpushbutton.h>
+#include <qradiobutton.h>
+#include <qstyle.h>
+#include <klocale.h>
+
+#include "misc.h"
+#include "cvsservice_stub.h"
+
+
+MergeDialog::MergeDialog(CvsService_stub* service,
+ QWidget *parent, const char *name)
+ : KDialogBase(parent, name, true, i18n("CVS Merge"),
+ Ok | Cancel, Ok, true),
+ cvsService(service)
+{
+ int const iComboBoxMinWidth(30 * fontMetrics().width('0'));
+ int const iWidgetIndent(style().pixelMetric(QStyle::PM_ExclusiveIndicatorWidth, 0) + 6);
+
+ QFrame* mainWidget = makeMainWidget();
+
+ QBoxLayout *layout = new QVBoxLayout(mainWidget, 0, spacingHint());
+
+ bybranch_button = new QRadioButton(i18n("Merge from &branch:"), mainWidget);
+ bybranch_button->setChecked(true);
+ layout->addWidget(bybranch_button);
+
+ branch_combo = new QComboBox(true, mainWidget);
+ branch_combo->setMinimumWidth(iComboBoxMinWidth);
+
+ branch_button = new QPushButton(i18n("Fetch &List"), mainWidget);
+ connect( branch_button, SIGNAL(clicked()),
+ this, SLOT(branchButtonClicked()) );
+
+ QBoxLayout *branchedit_layout = new QHBoxLayout(layout);
+ branchedit_layout->addSpacing(iWidgetIndent);
+ branchedit_layout->addWidget(branch_combo, 2);
+ branchedit_layout->addWidget(branch_button, 0);
+
+ bytags_button = new QRadioButton(i18n("Merge &modifications:"), mainWidget);
+ layout->addWidget(bytags_button);
+
+ QLabel *tag1_label = new QLabel(i18n("between tag: "), mainWidget);
+ tag1_combo = new QComboBox(true, mainWidget);
+ tag1_combo->setMinimumWidth(iComboBoxMinWidth);
+
+ QLabel *tag2_label = new QLabel(i18n("and tag: "), mainWidget);
+ tag2_combo = new QComboBox(true, mainWidget);
+ tag2_combo->setMinimumWidth(iComboBoxMinWidth);
+
+ tag_button = new QPushButton(i18n("Fetch L&ist"), mainWidget);
+ connect( tag_button, SIGNAL(clicked()),
+ this, SLOT(tagButtonClicked()) );
+
+ QGridLayout *tagsedit_layout = new QGridLayout(layout);
+ tagsedit_layout->addColSpacing(0, iWidgetIndent);
+ tagsedit_layout->setColStretch(0, 0);
+ tagsedit_layout->setColStretch(1, 1);
+ tagsedit_layout->setColStretch(2, 2);
+ tagsedit_layout->setColStretch(3, 0);
+ tagsedit_layout->addWidget(tag1_label, 0, 1);
+ tagsedit_layout->addWidget(tag1_combo, 0, 2);
+ tagsedit_layout->addWidget(tag2_label, 1, 1);
+ tagsedit_layout->addWidget(tag2_combo, 1, 2);
+ tagsedit_layout->addMultiCellWidget(tag_button, 0, 1, 3, 3);
+
+ QButtonGroup* group = new QButtonGroup(mainWidget);
+ group->hide();
+ group->insert(bybranch_button);
+ group->insert(bytags_button);
+ connect( group, SIGNAL(clicked(int)),
+ this, SLOT(toggled()) );
+
+ // dis-/enable the widgets
+ toggled();
+}
+
+
+bool MergeDialog::byBranch() const
+{
+ return bybranch_button->isChecked();
+}
+
+
+QString MergeDialog::branch() const
+{
+ return branch_combo->currentText();
+}
+
+
+QString MergeDialog::tag1() const
+{
+ return tag1_combo->currentText();
+}
+
+
+QString MergeDialog::tag2() const
+{
+ return tag2_combo->currentText();
+}
+
+
+void MergeDialog::tagButtonClicked()
+{
+ QStringList const listTags(::fetchTags(cvsService, this));
+ tag1_combo->clear();
+ tag1_combo->insertStringList(listTags);
+ tag2_combo->clear();
+ tag2_combo->insertStringList(listTags);
+}
+
+
+void MergeDialog::branchButtonClicked()
+{
+ branch_combo->clear();
+ branch_combo->insertStringList(::fetchBranches(cvsService, this));
+}
+
+
+void MergeDialog::toggled()
+{
+ bool bybranch = bybranch_button->isChecked();
+ branch_combo->setEnabled(bybranch);
+ branch_button->setEnabled(bybranch);
+ tag1_combo->setEnabled(!bybranch);
+ tag2_combo->setEnabled(!bybranch);
+ tag_button->setEnabled(!bybranch);
+ if (bybranch)
+ branch_combo->setFocus();
+ else
+ tag1_combo->setFocus();
+}
+
+#include "mergedlg.moc"
+
+
+// Local Variables:
+// c-basic-offset: 4
+// End:
diff --git a/cervisia/mergedlg.h b/cervisia/mergedlg.h
new file mode 100644
index 00000000..bd4464c1
--- /dev/null
+++ b/cervisia/mergedlg.h
@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) 1999-2002 Bernd Gehrmann
+ * bernd@mail.berlios.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.
+ *
+ * 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, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+
+#ifndef MERGEDLG_H
+#define MERGEDLG_H
+
+
+#include <kdialogbase.h>
+
+
+class QComboBox;
+class QPushButton;
+class QRadioButton;
+class CvsService_stub;
+
+
+class MergeDialog : public KDialogBase
+{
+ Q_OBJECT
+
+public:
+ MergeDialog( CvsService_stub* service,
+ QWidget *parent=0, const char *name=0 );
+
+ bool byBranch() const;
+ QString branch() const;
+ QString tag1() const;
+ QString tag2() const;
+
+private slots:
+ void toggled();
+ void tagButtonClicked();
+ void branchButtonClicked();
+
+private:
+ CvsService_stub* cvsService;
+
+ QRadioButton *bybranch_button, *bytags_button;
+ QComboBox *branch_combo, *tag1_combo, *tag2_combo;
+ QPushButton *tag_button, *branch_button;
+};
+
+#endif
+
+
+// Local Variables:
+// c-basic-offset: 4
+// End:
diff --git a/cervisia/misc.cpp b/cervisia/misc.cpp
new file mode 100644
index 00000000..e1cfe208
--- /dev/null
+++ b/cervisia/misc.cpp
@@ -0,0 +1,350 @@
+/*
+ * Copyright (C) 1999-2002 Bernd Gehrmann
+ * bernd@mail.berlios.de
+ * Copyright (c) 2003 Christian Loose <christian.loose@hamburg.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.
+ *
+ * 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, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+
+#include "misc.h"
+
+#include <ctype.h>
+#include <pwd.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include <qfile.h>
+#include <qfileinfo.h>
+#include <qregexp.h>
+#include <qstringlist.h>
+#include <kconfig.h>
+#include <kemailsettings.h>
+#include <klocale.h>
+#include <kmessagebox.h>
+#include <kprocess.h>
+#include <ktempfile.h>
+#include <kuser.h>
+#include <kdebug.h>
+
+#include "cvsservice_stub.h"
+#include "progressdlg.h"
+
+// These regular expression parts aren't useful to check the validity of the
+// CVSROOT specification. They are just used to extract the different parts of it.
+static const QString userNameRegExp("([a-z0-9_][a-z0-9_-.]*)?");
+static const QString passwordRegExp("(:[^@]+)?");
+static const QString hostNameRegExp("([^:/@]+)");
+static const QString portRegExp("(:(\\d*))?");
+static const QString pathRegExp("(/.*)");
+
+
+static int FindWhiteSpace(const QString& str, int index)
+{
+ const int length = str.length();
+
+ if( index < 0 )
+ index += length;
+
+ if( index < 0 || index >= length )
+ return -1;
+
+ const QChar* const startPos = str.unicode();
+ const QChar* const endPos = startPos + length;
+
+ const QChar* pos = startPos + index;
+ while( pos < endPos && !pos->isSpace() )
+ ++pos;
+
+ const int foundIndex = pos - startPos;
+ return (foundIndex < length ? foundIndex : -1);
+}
+
+
+static const QStringList FetchBranchesAndTags(const QString& searchedType,
+ CvsService_stub* cvsService,
+ QWidget* parent)
+{
+ QStringList branchOrTagList;
+
+ DCOPRef job = cvsService->status(QStringList(), true, true);
+ if( !cvsService->ok() )
+ return branchOrTagList;
+
+ ProgressDialog dlg(parent, "Status", job, QString::null, i18n("CVS Status"));
+
+ if( dlg.execute() )
+ {
+ QString line;
+ while( dlg.getLine(line) )
+ {
+ int wsPos, bracketPos, colonPos;
+
+ if( line.isEmpty() || line[0] != '\t' )
+ continue;
+ if( (wsPos = FindWhiteSpace(line, 2)) < 0 )
+ continue;
+ if( (bracketPos = line.find('(', wsPos + 1)) < 0 )
+ continue;
+ if( (colonPos = line.find(':', bracketPos + 1)) < 0 )
+ continue;
+
+ const QString tag = line.mid(1, wsPos - 1);
+ const QString type = line.mid(bracketPos + 1, colonPos - bracketPos - 1);
+ if( type == searchedType && !branchOrTagList.contains(tag) )
+ branchOrTagList.push_back(tag);
+ }
+
+ branchOrTagList.sort();
+ }
+
+ return branchOrTagList;
+}
+
+
+bool Cervisia::IsValidTag(const QString& tag)
+{
+ static const QString prohibitedChars("$,.:;@");
+
+ if( !isalpha(tag[0].latin1()) )
+ return false;
+
+ for( uint i = 1; i < tag.length(); ++i )
+ {
+ if( !isgraph(tag[i].latin1()) || prohibitedChars.contains(tag[i]) )
+ return false;
+ }
+
+ return true;
+}
+
+
+QString Cervisia::UserName()
+{
+ // 1. Try to retrieve the information from the control center settings
+ KEMailSettings settings;
+ QString name = settings.getSetting(KEMailSettings::RealName);
+ QString email = settings.getSetting(KEMailSettings::EmailAddress);
+
+ if( name.isEmpty() || email.isEmpty() )
+ {
+ // 2. Try to retrieve the information from the system
+ struct passwd* pw = getpwuid(getuid());
+ if( !pw )
+ return QString::null;
+
+ char hostname[512];
+ hostname[0] = '\0';
+
+ if( !gethostname(hostname, sizeof(hostname)) )
+ hostname[sizeof(hostname)-1] = '0';
+
+ name = QString::fromLocal8Bit(pw->pw_gecos);
+ email = QString::fromLocal8Bit(pw->pw_name) + "@" +
+ QString::fromLocal8Bit(hostname);
+ }
+
+ QString result = name;
+ result += " <";
+ result += email;
+ result += ">";
+
+ return result;
+}
+
+
+QString Cervisia::NormalizeRepository(const QString& repository)
+{
+ // only :pserver: repositories
+ if( !repository.startsWith(":pserver:") )
+ return repository;
+
+ QRegExp rx(":pserver:(" + userNameRegExp + passwordRegExp + "@)?" +
+ hostNameRegExp + portRegExp + pathRegExp);
+
+ // extract username, hostname, port and path from CVSROOT
+ QString userName, hostName, port, path;
+ if( rx.search(repository) != -1 )
+ {
+ userName = rx.cap(2);
+ hostName = rx.cap(4);
+ port = rx.cap(6);
+ path = rx.cap(7);
+
+ kdDebug() << "NormalizeRepository(): username=" << userName << endl;
+ kdDebug() << "NormalizeRepository(): hostname=" << hostName << endl;
+ kdDebug() << "NormalizeRepository(): port =" << port << endl;
+ kdDebug() << "NormalizeRepository(): path =" << path << endl;
+
+ if( port.isEmpty() )
+ port = "2401";
+
+ if( userName.isEmpty() )
+ userName = KUser().loginName();
+
+ QString canonicalForm = ":pserver:" + userName + "@" + hostName +
+ ":" + port + path;
+
+ kdDebug() << "NormalizeRepository(): canonicalForm=" << canonicalForm
+ << endl;
+ return canonicalForm;
+ }
+ else
+ return repository;
+}
+
+
+bool Cervisia::CheckOverwrite(const QString& fileName, QWidget* parent)
+{
+ bool result = true;
+
+ QFileInfo fi(fileName);
+
+ // does the file already exist?
+ if( fi.exists() )
+ {
+ result = (KMessageBox::warningContinueCancel(parent,
+ i18n("A file named \"%1\" already exists. Are you sure you want to overwrite it?").arg(fileName),
+ i18n("Overwrite File?"),
+ KGuiItem(i18n("&Overwrite"), "filesave", i18n("Overwrite the file"))) == KMessageBox::Continue);
+ }
+
+ return result;
+}
+
+
+QString joinLine(const QStringList &list)
+{
+ QString line;
+ for ( QStringList::ConstIterator it = list.begin();
+ it != list.end(); ++it )
+ {
+ line += KShellProcess::quote(*it);
+ line += " ";
+ }
+
+ if (line.length() > 0)
+ line.truncate(line.length()-1);
+
+ return line;
+}
+
+
+// Should be replaceable by QStringList::split
+QStringList splitLine(QString line, char delim)
+{
+ int pos;
+ QStringList list;
+
+ line = line.simplifyWhiteSpace();
+ while ((pos = line.find(delim)) != -1)
+ {
+ list.append(line.left(pos));
+ line = line.mid(pos+1, line.length()-pos-1);
+ }
+ if (!line.isEmpty())
+ list.append(line);
+ return list;
+}
+
+
+const QStringList fetchBranches(CvsService_stub* cvsService, QWidget* parent)
+{
+ return FetchBranchesAndTags(QString::fromLatin1("branch"), cvsService,
+ parent);
+}
+
+
+const QStringList fetchTags(CvsService_stub* cvsService, QWidget* parent)
+{
+ return FetchBranchesAndTags(QString::fromLatin1("revision"), cvsService,
+ parent);
+}
+
+
+static QStringList *tempFiles = 0;
+
+void cleanupTempFiles()
+{
+ if (tempFiles)
+ {
+ QStringList::Iterator it;
+ for (it = tempFiles->begin(); it != tempFiles->end(); ++it)
+ QFile::remove(*it);
+ delete tempFiles;
+ }
+}
+
+
+QString tempFileName(const QString& suffix)
+{
+ if (!tempFiles)
+ tempFiles = new QStringList;
+
+ KTempFile f(QString::null, suffix);
+ tempFiles->append(f.name());
+ return f.name();
+}
+
+
+int compareRevisions(const QString& rev1, const QString& rev2)
+{
+ const int length1(rev1.length());
+ const int length2(rev2.length());
+
+ // compare all parts of the revision
+
+ int startPos1(0);
+ int startPos2(0);
+ while (startPos1 < length1 && startPos2 < length2)
+ {
+ int pos1(rev1.find('.', startPos1));
+ if (pos1 < 0)
+ pos1 = length1;
+ const int partLength1(pos1 - startPos1);
+
+ int pos2(rev2.find('.', startPos2));
+ if (pos2 < 0)
+ pos2 = length2;
+ const int partLength2(pos2 - startPos2);
+
+ // if the number of digits in both parts is not equal we are ready
+ if (const int comp = ::compare(partLength1, partLength2))
+ return comp;
+
+ // if the parts are not equal we are ready
+ if (const int comp = ::compare(rev1.mid(startPos1, partLength1),
+ rev2.mid(startPos2, partLength2)))
+ return comp;
+
+ // continue with next part
+ startPos1 = pos1 + 1;
+ startPos2 = pos2 + 1;
+ }
+
+ // rev1 has more parts than rev2: rev2 < rev1
+ if (startPos1 < length1)
+ return 1;
+ // rev2 has more parts than rev1: rev1 < rev2
+ else if (startPos2 < length2)
+ return -1;
+ // all parts of rev1 and rev2 were compared (the number of parts is equal): rev1 == rev2
+ else
+ return 0;
+}
+
+
+// Local Variables:
+// c-basic-offset: 4
+// End:
diff --git a/cervisia/misc.h b/cervisia/misc.h
new file mode 100644
index 00000000..b0d912e5
--- /dev/null
+++ b/cervisia/misc.h
@@ -0,0 +1,98 @@
+/*
+ * Copyright (C) 1999-2002 Bernd Gehrmann
+ * bernd@mail.berlios.de
+ * Copyright (c) 2003 Christian Loose <christian.loose@hamburg.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.
+ *
+ * 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, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+
+#ifndef MISC_H
+#define MISC_H
+
+
+class QString;
+class QStringList;
+class QWidget;
+class KConfig;
+class CvsService_stub;
+
+
+namespace Cervisia
+{
+
+/**
+ * Verifies that the passed tag name is a valid cvs tag.
+ */
+bool IsValidTag(const QString& tag);
+
+/**
+ * Returns the user name (real name + mail address) for the changelog entry.
+ */
+QString UserName();
+
+/**
+ * This method makes sure that the cvsroot specification for a pserver repository has
+ * always the form:
+ * :pserver:[user]@[host]:[port][path]
+ */
+QString NormalizeRepository(const QString& repository);
+
+bool CheckOverwrite(const QString& fileName, QWidget* parent=0);
+
+}
+
+
+QString joinLine(const QStringList &list);
+QStringList splitLine(QString, char delim=' ');
+
+QString tempFileName(const QString& suffix);
+void cleanupTempFiles();
+
+const QStringList fetchBranches(CvsService_stub* cvsService, QWidget* parent);
+const QStringList fetchTags(CvsService_stub* cvsService, QWidget* parent);
+
+/**
+ * Compares two revision numbers.
+ *
+ * @return -1 / 0 / 1 if rev1 is < / == / > rev2
+ */
+int compareRevisions(const QString& rev1, const QString& rev2);
+
+
+/**
+ * Generic compare for two objects of the same class. operator<() must
+ * be defined for this class.
+ *
+ * @return -1 / 0 / 1 if lhs is < / == / > rhs
+ */
+template<class C>
+int compare(const C& lhs, const C& rhs)
+{
+ if (lhs < rhs)
+ return -1;
+ else if (rhs < lhs)
+ return 1;
+ else
+ return 0;
+}
+
+
+#endif
+
+
+// Local Variables:
+// c-basic-offset: 4
+// End:
diff --git a/cervisia/move_repositories.pl b/cervisia/move_repositories.pl
new file mode 100644
index 00000000..c38b352d
--- /dev/null
+++ b/cervisia/move_repositories.pl
@@ -0,0 +1,42 @@
+#!/usr/bin/perl
+
+$DEBUG = 0;
+
+while(<>)
+{
+ if( /\[(Repository-.*)\]/ )
+ {
+ # remember group section
+ $section = $1;
+ print "[$section]\n";
+ next;
+ }
+ if( /\[(.*)\]/ )
+ {
+ # clear section variable for other groups
+ $section = "";
+ next;
+ }
+ if( /^Compression=(.*)$/ )
+ {
+ # skip if not in repository group
+ if( $section eq "" )
+ {
+ next;
+ }
+
+ print STDERR "\n[$section]Compression=$1\n" if ( $DEBUG );
+ print "Compression=$1\n";
+ }
+ if( /^rsh=(.*)$/ )
+ {
+ # skip if not in repository group
+ if( $section eq "" )
+ {
+ next;
+ }
+
+ print STDERR "\n[$section]rsh=$1\n" if ( $DEBUG );
+ print "rsh=$1\n";
+ }
+}
diff --git a/cervisia/overview.h b/cervisia/overview.h
new file mode 100644
index 00000000..e4af7af6
--- /dev/null
+++ b/cervisia/overview.h
@@ -0,0 +1,15 @@
+/**
+ * @libdoc Cervisia Class Overview
+ *
+ * This is the class documentation for the Cervisia CVS front end. At the moment,
+ * the only way this code can easily be used in other applications is via the
+ * KPart. Hopefully it should be possible to provide more flexible facilities in
+ * future versions.
+ *
+ * @li @ref CervisiaPart
+ * A KPart that provides a reusable way to embed the Cervisia interface in an app.
+ *
+ * @li @ref CervisiaShell
+ * A basic main window shell that embeds the CervisiaPart to provide the standalone
+ * Cervisia application.
+ */
diff --git a/cervisia/patchoptiondlg.cpp b/cervisia/patchoptiondlg.cpp
new file mode 100644
index 00000000..9e6f92d1
--- /dev/null
+++ b/cervisia/patchoptiondlg.cpp
@@ -0,0 +1,115 @@
+/*
+ * Copyright (C) 2004 Christian Loose <christian.loose@kdemail.net>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the 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, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#include "patchoptiondlg.h"
+using Cervisia::PatchOptionDialog;
+
+#include <qcheckbox.h>
+#include <qlabel.h>
+#include <qlayout.h>
+#include <qradiobutton.h>
+#include <qvbuttongroup.h>
+#include <knuminput.h>
+#include <klocale.h>
+
+
+PatchOptionDialog::PatchOptionDialog(QWidget* parent, const char* name)
+ : KDialogBase(parent, name, true/*modal*/, QString::null,
+ Ok | Cancel | Help, Ok, true/*separator*/)
+{
+ QFrame* mainWidget = makeMainWidget();
+ QBoxLayout* topLayout = new QVBoxLayout(mainWidget, 0, spacingHint());
+
+ m_formatBtnGroup = new QVButtonGroup(i18n("Output Format"), mainWidget, "");
+ topLayout->addWidget(m_formatBtnGroup);
+
+ connect(m_formatBtnGroup, SIGNAL(clicked(int)),
+ this, SLOT(formatChanged(int)));
+
+ new QRadioButton(i18n( "Context" ), m_formatBtnGroup);
+ new QRadioButton(i18n( "Normal" ), m_formatBtnGroup);
+ QRadioButton* unifiedFormatBtn = new QRadioButton(i18n( "Unified" ), m_formatBtnGroup);
+ unifiedFormatBtn->setChecked(true);
+
+ QLabel* contextLinesLbl = new QLabel(i18n("&Number of context lines:"),
+ mainWidget);
+ m_contextLines = new KIntNumInput(3, mainWidget);
+ m_contextLines->setRange(2, 65535, 1, false);
+ contextLinesLbl->setBuddy(m_contextLines);
+
+ QBoxLayout* contextLinesLayout = new QHBoxLayout(topLayout);
+ contextLinesLayout->addWidget(contextLinesLbl);
+ contextLinesLayout->addWidget(m_contextLines);
+
+ QVButtonGroup* ignoreBtnGroup = new QVButtonGroup(i18n("Ignore Options"), mainWidget);
+ topLayout->addWidget(ignoreBtnGroup);
+
+ m_blankLineChk = new QCheckBox(i18n("Ignore added or removed empty lines"),
+ ignoreBtnGroup);
+ m_spaceChangeChk = new QCheckBox(i18n("Ignore changes in the amount of whitespace"),
+ ignoreBtnGroup);
+ m_allSpaceChk = new QCheckBox(i18n("Ignore all whitespace"), ignoreBtnGroup);
+ m_caseChangesChk = new QCheckBox(i18n("Ignore changes in case"), ignoreBtnGroup);
+}
+
+
+PatchOptionDialog::~PatchOptionDialog()
+{
+}
+
+
+QString PatchOptionDialog::diffOptions() const
+{
+ QString options;
+
+ if( m_blankLineChk->isChecked() )
+ options += " -B ";
+
+ if( m_spaceChangeChk->isChecked() )
+ options += " -b ";
+
+ if( m_allSpaceChk->isChecked() )
+ options += " -w ";
+
+ if( m_caseChangesChk->isChecked() )
+ options += " -i ";
+
+ return options;
+}
+
+
+QString PatchOptionDialog::formatOption() const
+{
+ switch( m_formatBtnGroup->selectedId() )
+ {
+ case 0: return "-C " + QString::number(m_contextLines->value());
+ case 1: return "";
+ case 2: return "-U " + QString::number(m_contextLines->value());
+ }
+
+ return "";
+}
+
+
+void PatchOptionDialog::formatChanged(int buttonId)
+{
+ bool enabled = ( buttonId == 0 || buttonId == 2 );
+ m_contextLines->setEnabled(enabled);
+}
+
+#include "patchoptiondlg.moc"
diff --git a/cervisia/patchoptiondlg.h b/cervisia/patchoptiondlg.h
new file mode 100644
index 00000000..64109a2b
--- /dev/null
+++ b/cervisia/patchoptiondlg.h
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2004 Christian Loose <christian.loose@kdemail.net>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the 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, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+
+#ifndef PATCHOPTIONDLG_H
+#define PATCHOPTIONDLG_H
+
+#include <kdialogbase.h>
+
+class QCheckBox;
+class QVButtonGroup;
+class KIntNumInput;
+
+
+namespace Cervisia
+{
+
+
+class PatchOptionDialog : public KDialogBase
+{
+ Q_OBJECT
+
+public:
+ explicit PatchOptionDialog(QWidget* parent = 0, const char* name = 0);
+ virtual ~PatchOptionDialog();
+
+ QString diffOptions() const;
+ QString formatOption() const;
+
+private slots:
+ void formatChanged(int buttonId);
+
+private:
+ QVButtonGroup* m_formatBtnGroup;
+ KIntNumInput* m_contextLines;
+ QCheckBox* m_blankLineChk;
+ QCheckBox* m_allSpaceChk;
+ QCheckBox* m_spaceChangeChk;
+ QCheckBox* m_caseChangesChk;
+};
+
+
+}
+
+#endif
diff --git a/cervisia/pics/Makefile.am b/cervisia/pics/Makefile.am
new file mode 100644
index 00000000..a4b97f06
--- /dev/null
+++ b/cervisia/pics/Makefile.am
@@ -0,0 +1 @@
+KDE_ICON=AUTO
diff --git a/cervisia/pics/README b/cervisia/pics/README
new file mode 100644
index 00000000..6d8a6916
--- /dev/null
+++ b/cervisia/pics/README
@@ -0,0 +1,9 @@
+The following icons are created by Marco Martin <m4rt [at] libero [dot] it>
+and licensed with the GNU Lesser General Public License as published by the
+Free Software Foundation, version 2.1 of the License:
+
+vcs_add
+vcs_commit
+vcs_remove
+vcs_status
+vcs_update
diff --git a/cervisia/pics/cr16-action-vcs_add.png b/cervisia/pics/cr16-action-vcs_add.png
new file mode 100644
index 00000000..43c13620
--- /dev/null
+++ b/cervisia/pics/cr16-action-vcs_add.png
Binary files differ
diff --git a/cervisia/pics/cr16-action-vcs_commit.png b/cervisia/pics/cr16-action-vcs_commit.png
new file mode 100644
index 00000000..71f6b3dc
--- /dev/null
+++ b/cervisia/pics/cr16-action-vcs_commit.png
Binary files differ
diff --git a/cervisia/pics/cr16-action-vcs_diff.png b/cervisia/pics/cr16-action-vcs_diff.png
new file mode 100644
index 00000000..9cc127ee
--- /dev/null
+++ b/cervisia/pics/cr16-action-vcs_diff.png
Binary files differ
diff --git a/cervisia/pics/cr16-action-vcs_remove.png b/cervisia/pics/cr16-action-vcs_remove.png
new file mode 100644
index 00000000..8d4a9e72
--- /dev/null
+++ b/cervisia/pics/cr16-action-vcs_remove.png
Binary files differ
diff --git a/cervisia/pics/cr16-action-vcs_status.png b/cervisia/pics/cr16-action-vcs_status.png
new file mode 100644
index 00000000..186dcd70
--- /dev/null
+++ b/cervisia/pics/cr16-action-vcs_status.png
Binary files differ
diff --git a/cervisia/pics/cr16-action-vcs_update.png b/cervisia/pics/cr16-action-vcs_update.png
new file mode 100644
index 00000000..c3ba632c
--- /dev/null
+++ b/cervisia/pics/cr16-action-vcs_update.png
Binary files differ
diff --git a/cervisia/pics/cr22-action-vcs_add.png b/cervisia/pics/cr22-action-vcs_add.png
new file mode 100644
index 00000000..a083f822
--- /dev/null
+++ b/cervisia/pics/cr22-action-vcs_add.png
Binary files differ
diff --git a/cervisia/pics/cr22-action-vcs_commit.png b/cervisia/pics/cr22-action-vcs_commit.png
new file mode 100644
index 00000000..c0c96ef6
--- /dev/null
+++ b/cervisia/pics/cr22-action-vcs_commit.png
Binary files differ
diff --git a/cervisia/pics/cr22-action-vcs_diff.png b/cervisia/pics/cr22-action-vcs_diff.png
new file mode 100644
index 00000000..5c5d444b
--- /dev/null
+++ b/cervisia/pics/cr22-action-vcs_diff.png
Binary files differ
diff --git a/cervisia/pics/cr22-action-vcs_remove.png b/cervisia/pics/cr22-action-vcs_remove.png
new file mode 100644
index 00000000..b08c25e3
--- /dev/null
+++ b/cervisia/pics/cr22-action-vcs_remove.png
Binary files differ
diff --git a/cervisia/pics/cr22-action-vcs_status.png b/cervisia/pics/cr22-action-vcs_status.png
new file mode 100644
index 00000000..974fbb65
--- /dev/null
+++ b/cervisia/pics/cr22-action-vcs_status.png
Binary files differ
diff --git a/cervisia/pics/cr22-action-vcs_update.png b/cervisia/pics/cr22-action-vcs_update.png
new file mode 100644
index 00000000..5be225a7
--- /dev/null
+++ b/cervisia/pics/cr22-action-vcs_update.png
Binary files differ
diff --git a/cervisia/pics/cr32-action-vcs_add.png b/cervisia/pics/cr32-action-vcs_add.png
new file mode 100644
index 00000000..5d4ae629
--- /dev/null
+++ b/cervisia/pics/cr32-action-vcs_add.png
Binary files differ
diff --git a/cervisia/pics/cr32-action-vcs_commit.png b/cervisia/pics/cr32-action-vcs_commit.png
new file mode 100644
index 00000000..ae10315e
--- /dev/null
+++ b/cervisia/pics/cr32-action-vcs_commit.png
Binary files differ
diff --git a/cervisia/pics/cr32-action-vcs_diff.png b/cervisia/pics/cr32-action-vcs_diff.png
new file mode 100644
index 00000000..ee490e08
--- /dev/null
+++ b/cervisia/pics/cr32-action-vcs_diff.png
Binary files differ
diff --git a/cervisia/pics/cr32-action-vcs_remove.png b/cervisia/pics/cr32-action-vcs_remove.png
new file mode 100644
index 00000000..a4ef8905
--- /dev/null
+++ b/cervisia/pics/cr32-action-vcs_remove.png
Binary files differ
diff --git a/cervisia/pics/cr32-action-vcs_status.png b/cervisia/pics/cr32-action-vcs_status.png
new file mode 100644
index 00000000..804f5397
--- /dev/null
+++ b/cervisia/pics/cr32-action-vcs_status.png
Binary files differ
diff --git a/cervisia/pics/cr32-action-vcs_update.png b/cervisia/pics/cr32-action-vcs_update.png
new file mode 100644
index 00000000..13124fe5
--- /dev/null
+++ b/cervisia/pics/cr32-action-vcs_update.png
Binary files differ
diff --git a/cervisia/pics/cr48-action-vcs_add.png b/cervisia/pics/cr48-action-vcs_add.png
new file mode 100644
index 00000000..c0a8dee8
--- /dev/null
+++ b/cervisia/pics/cr48-action-vcs_add.png
Binary files differ
diff --git a/cervisia/pics/cr48-action-vcs_commit.png b/cervisia/pics/cr48-action-vcs_commit.png
new file mode 100644
index 00000000..aacc2b7e
--- /dev/null
+++ b/cervisia/pics/cr48-action-vcs_commit.png
Binary files differ
diff --git a/cervisia/pics/cr48-action-vcs_diff.png b/cervisia/pics/cr48-action-vcs_diff.png
new file mode 100644
index 00000000..5a954ee6
--- /dev/null
+++ b/cervisia/pics/cr48-action-vcs_diff.png
Binary files differ
diff --git a/cervisia/pics/cr48-action-vcs_remove.png b/cervisia/pics/cr48-action-vcs_remove.png
new file mode 100644
index 00000000..caa2fcc4
--- /dev/null
+++ b/cervisia/pics/cr48-action-vcs_remove.png
Binary files differ
diff --git a/cervisia/pics/cr48-action-vcs_status.png b/cervisia/pics/cr48-action-vcs_status.png
new file mode 100644
index 00000000..a98d15dc
--- /dev/null
+++ b/cervisia/pics/cr48-action-vcs_status.png
Binary files differ
diff --git a/cervisia/pics/cr48-action-vcs_update.png b/cervisia/pics/cr48-action-vcs_update.png
new file mode 100644
index 00000000..ab7b2d89
--- /dev/null
+++ b/cervisia/pics/cr48-action-vcs_update.png
Binary files differ
diff --git a/cervisia/pics/crsc-action-vcs_add.svgz b/cervisia/pics/crsc-action-vcs_add.svgz
new file mode 100644
index 00000000..b6e9fc62
--- /dev/null
+++ b/cervisia/pics/crsc-action-vcs_add.svgz
Binary files differ
diff --git a/cervisia/pics/crsc-action-vcs_commit.svgz b/cervisia/pics/crsc-action-vcs_commit.svgz
new file mode 100644
index 00000000..b1d63c7b
--- /dev/null
+++ b/cervisia/pics/crsc-action-vcs_commit.svgz
Binary files differ
diff --git a/cervisia/pics/crsc-action-vcs_diff.svgz b/cervisia/pics/crsc-action-vcs_diff.svgz
new file mode 100644
index 00000000..45549f69
--- /dev/null
+++ b/cervisia/pics/crsc-action-vcs_diff.svgz
Binary files differ
diff --git a/cervisia/pics/crsc-action-vcs_remove.svgz b/cervisia/pics/crsc-action-vcs_remove.svgz
new file mode 100644
index 00000000..b6165bb7
--- /dev/null
+++ b/cervisia/pics/crsc-action-vcs_remove.svgz
Binary files differ
diff --git a/cervisia/pics/crsc-action-vcs_status.svgz b/cervisia/pics/crsc-action-vcs_status.svgz
new file mode 100644
index 00000000..32b1ed9d
--- /dev/null
+++ b/cervisia/pics/crsc-action-vcs_status.svgz
Binary files differ
diff --git a/cervisia/pics/crsc-action-vcs_update.svgz b/cervisia/pics/crsc-action-vcs_update.svgz
new file mode 100644
index 00000000..b251d05f
--- /dev/null
+++ b/cervisia/pics/crsc-action-vcs_update.svgz
Binary files differ
diff --git a/cervisia/progressdlg.cpp b/cervisia/progressdlg.cpp
new file mode 100644
index 00000000..d72c6565
--- /dev/null
+++ b/cervisia/progressdlg.cpp
@@ -0,0 +1,276 @@
+/*
+ * Copyright (c) 1999-2002 Bernd Gehrmann <bernd@mail.berlios.de>
+ * Copyright (c) 2002-2004 Christian Loose <christian.loose@kdemail.net>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the 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, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#include "progressdlg.h"
+
+#include <qlabel.h>
+#include <qlayout.h>
+#include <qstring.h>
+#include <qstringlist.h>
+#include <qtimer.h>
+#include <qvbox.h>
+
+#include <cvsjob_stub.h>
+#include <dcopref.h>
+#include <kanimwidget.h>
+#include <kapplication.h>
+#include <kconfig.h>
+
+#include "cervisiasettings.h"
+
+
+struct ProgressDialog::Private
+{
+ bool isCancelled;
+ bool isShown;
+ bool hasError;
+
+ CvsJob_stub* cvsJob;
+ QString buffer;
+ QString errorId1, errorId2;
+ QStringList output;
+
+ QTimer* timer;
+ KAnimWidget* gear;
+ QListBox* resultbox;
+};
+
+
+ProgressDialog::ProgressDialog(QWidget* parent, const QString& heading,
+ const DCOPRef& job, const QString& errorIndicator,
+ const QString& caption)
+ : KDialogBase(parent, 0, true, caption, Cancel, Cancel, true)
+ , DCOPObject()
+ , d(new Private)
+{
+ // initialize private data
+ d->isCancelled = false;
+ d->isShown = false;
+ d->hasError = false;
+
+ d->cvsJob = new CvsJob_stub(job);
+ d->buffer = "";
+
+ d->errorId1 = "cvs " + errorIndicator + ":";
+ d->errorId2 = "cvs [" + errorIndicator + " aborted]:";
+
+ setupGui(heading);
+}
+
+
+ProgressDialog::~ProgressDialog()
+{
+ delete d->cvsJob;
+ delete d;
+}
+
+
+void ProgressDialog::setupGui(const QString& heading)
+{
+ QVBox* vbox = makeVBoxMainWidget();
+ vbox->setSpacing(10);
+
+ QWidget* headingBox = new QWidget(vbox);
+ QHBoxLayout* hboxLayout = new QHBoxLayout(headingBox);
+
+ QLabel* textLabel = new QLabel(heading, headingBox);
+ textLabel->setMinimumWidth(textLabel->sizeHint().width());
+ textLabel->setFixedHeight(textLabel->sizeHint().height());
+ hboxLayout->addWidget(textLabel);
+ hboxLayout->addStretch();
+
+ d->gear = new KAnimWidget(QString("kde"), 32, headingBox);
+ d->gear->setFixedSize(32, 32);
+ hboxLayout->addWidget(d->gear);
+
+ d->resultbox = new QListBox(vbox);
+ d->resultbox->setSelectionMode(QListBox::NoSelection);
+ QFontMetrics fm(d->resultbox->fontMetrics());
+ d->resultbox->setMinimumSize(fm.width("0")*70, fm.lineSpacing()*8);
+
+ resize(sizeHint());
+}
+
+
+bool ProgressDialog::execute()
+{
+ // get command line and display it
+ QString cmdLine = d->cvsJob->cvsCommand();
+ d->resultbox->insertItem(cmdLine);
+
+ // establish connections to the signals of the cvs job
+ connectDCOPSignal(d->cvsJob->app(), d->cvsJob->obj(), "jobExited(bool, int)",
+ "slotJobExited(bool, int)", true);
+ connectDCOPSignal(d->cvsJob->app(), d->cvsJob->obj(), "receivedStdout(QString)",
+ "slotReceivedOutputNonGui(QString)", true);
+ connectDCOPSignal(d->cvsJob->app(), d->cvsJob->obj(), "receivedStderr(QString)",
+ "slotReceivedOutputNonGui(QString)", true);
+
+ // we wait for 4 seconds (or the timeout set by the user) before we
+ // force the dialog to show up
+ d->timer = new QTimer(this);
+ connect(d->timer, SIGNAL(timeout()), this, SLOT(slotTimeoutOccurred()));
+ d->timer->start(CervisiaSettings::timeout(), true);
+
+ bool started = d->cvsJob->execute();
+ if( !started )
+ return false;
+
+ QApplication::setOverrideCursor(waitCursor);
+ kapp->enter_loop();
+ if (QApplication::overrideCursor())
+ QApplication::restoreOverrideCursor();
+
+ return !d->isCancelled;
+}
+
+
+bool ProgressDialog::getLine(QString& line)
+{
+ if( d->output.isEmpty() )
+ return false;
+
+ line = d->output.first();
+ d->output.remove(d->output.begin());
+
+ return true;
+}
+
+
+QStringList ProgressDialog::getOutput() const
+{
+ return d->output;
+}
+
+
+void ProgressDialog::slotReceivedOutputNonGui(QString buffer)
+{
+ d->buffer += buffer;
+
+ processOutput();
+ if( d->hasError )
+ {
+ stopNonGuiPart();
+ startGuiPart();
+ }
+}
+
+
+void ProgressDialog::slotReceivedOutput(QString buffer)
+{
+ d->buffer += buffer;
+ processOutput();
+}
+
+
+void ProgressDialog::slotJobExited(bool normalExit, int status)
+{
+ Q_UNUSED(status)
+
+ if( !d->isShown )
+ stopNonGuiPart();
+
+ d->gear->stop();
+ if( !d->buffer.isEmpty() )
+ {
+ d->buffer += '\n';
+ processOutput();
+ }
+
+ // Close the dialog automatically if there are no
+ // error messages or the process has been aborted
+ // 'by hand' (e.g. by clicking the cancel button)
+ if( !d->hasError || !normalExit )
+ kapp->exit_loop();
+}
+
+
+void ProgressDialog::slotCancel()
+{
+ d->isCancelled = true;
+
+ bool isRunning = d->cvsJob->isRunning();
+ if( isRunning )
+ d->cvsJob->cancel();
+ else
+ kapp->exit_loop();
+}
+
+
+void ProgressDialog::slotTimeoutOccurred()
+{
+ stopNonGuiPart();
+ startGuiPart();
+}
+
+
+void ProgressDialog::stopNonGuiPart()
+{
+ d->timer->stop();
+
+ disconnectDCOPSignal(d->cvsJob->app(), d->cvsJob->obj(), "receivedStdout(QString)",
+ "slotReceivedOutputNonGui(QString)");
+ disconnectDCOPSignal(d->cvsJob->app(), d->cvsJob->obj(), "receivedStderr(QString)",
+ "slotReceivedOutputNonGui(QString)");
+
+ kapp->exit_loop();
+}
+
+
+void ProgressDialog::startGuiPart()
+{
+ connectDCOPSignal(d->cvsJob->app(), d->cvsJob->obj(), "receivedStdout(QString)",
+ "slotReceivedOutput(QString)", true);
+ connectDCOPSignal(d->cvsJob->app(), d->cvsJob->obj(), "receivedStderr(QString)",
+ "slotReceivedOutput(QString)", true);
+
+ show();
+ d->isShown = true;
+
+ d->gear->start();
+ QApplication::restoreOverrideCursor();
+ kapp->enter_loop();
+}
+
+
+void ProgressDialog::processOutput()
+{
+ int pos;
+ while( (pos = d->buffer.find('\n')) != -1 )
+ {
+ QString item = d->buffer.left(pos);
+ if( item.startsWith(d->errorId1) ||
+ item.startsWith(d->errorId2) ||
+ item.startsWith("cvs [server aborted]:") )
+ {
+ d->hasError = true;
+ d->resultbox->insertItem(item);
+ }
+ else if( item.startsWith("cvs server:") )
+ d->resultbox->insertItem(item);
+ else
+ d->output.append(item);
+
+ // remove item from buffer
+ d->buffer.remove(0, pos+1);
+ }
+}
+
+
+#include "progressdlg.moc"
diff --git a/cervisia/progressdlg.h b/cervisia/progressdlg.h
new file mode 100644
index 00000000..3e9dfed1
--- /dev/null
+++ b/cervisia/progressdlg.h
@@ -0,0 +1,68 @@
+/*
+ * Copyright (c) 1999-2002 Bernd Gehrmann <bernd@mail.berlios.de>
+ * Copyright (c) 2002 Christian Loose <christian.loose@hamburg.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.
+ *
+ * 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, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#ifndef PROGRESSDLG_H
+#define PROGRESSDLG_H
+
+#include <dcopobject.h>
+#include <kdialogbase.h>
+
+class QString;
+class QWidget;
+class DCOPRef;
+
+
+class ProgressDialog : public KDialogBase, public DCOPObject
+{
+ K_DCOP
+ Q_OBJECT
+
+public:
+ ProgressDialog(QWidget* parent, const QString& heading, const DCOPRef& job,
+ const QString& errorIndicator, const QString& caption = "");
+ ~ProgressDialog();
+
+ bool execute();
+ bool getLine(QString& line);
+ QStringList getOutput() const;
+
+k_dcop:
+ void slotReceivedOutputNonGui(QString buffer);
+ void slotReceivedOutput(QString buffer);
+ void slotJobExited(bool normalExit, int status);
+
+protected slots:
+ virtual void slotCancel();
+
+private slots:
+ void slotTimeoutOccurred();
+
+private:
+ void setupGui(const QString& heading);
+ void stopNonGuiPart();
+ void startGuiPart();
+ void processOutput();
+
+ struct Private;
+ Private* d;
+};
+
+
+#endif
+
diff --git a/cervisia/protocolview.cpp b/cervisia/protocolview.cpp
new file mode 100644
index 00000000..8496b983
--- /dev/null
+++ b/cervisia/protocolview.cpp
@@ -0,0 +1,196 @@
+/*
+ * Copyright (C) 1999-2002 Bernd Gehrmann
+ * bernd@physik.hu-berlin.de
+ * Copyright (c) 2003-2004 Christian Loose <christian.loose@kdemail.net>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the 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, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+
+#include "protocolview.h"
+
+#include <qdir.h>
+#include <qpopupmenu.h>
+#include <dcopref.h>
+#include <kconfig.h>
+#include <klocale.h>
+#include <kmessagebox.h>
+
+#include "cervisiapart.h"
+#include "cvsjob_stub.h"
+
+
+ProtocolView::ProtocolView(const QCString& appId, QWidget *parent, const char *name)
+ : QTextEdit(parent, name)
+ , job(0)
+ , m_isUpdateJob(false)
+{
+ setReadOnly(true);
+ setUndoRedoEnabled(false);
+ setTabChangesFocus(true);
+ setTextFormat(Qt::LogText);
+
+ KConfig *config = CervisiaPart::config();
+ config->setGroup("LookAndFeel");
+ setFont(config->readFontEntry("ProtocolFont"));
+
+ config->setGroup("Colors");
+ QColor defaultColor = QColor(255, 130, 130);
+ conflictColor=config->readColorEntry("Conflict",&defaultColor);
+ defaultColor=QColor(130, 130, 255);
+ localChangeColor=config->readColorEntry("LocalChange",&defaultColor);
+ defaultColor=QColor(70, 210, 70);
+ remoteChangeColor=config->readColorEntry("RemoteChange",&defaultColor);
+
+ // create a DCOP stub for the non-concurrent cvs job
+ job = new CvsJob_stub(appId, "NonConcurrentJob");
+
+ // establish connections to the signals of the cvs job
+ connectDCOPSignal(job->app(), job->obj(), "jobExited(bool, int)",
+ "slotJobExited(bool, int)", true);
+ connectDCOPSignal(job->app(), job->obj(), "receivedStdout(QString)",
+ "slotReceivedOutput(QString)", true);
+ connectDCOPSignal(job->app(), job->obj(), "receivedStderr(QString)",
+ "slotReceivedOutput(QString)", true);
+}
+
+
+ProtocolView::~ProtocolView()
+{
+ delete job;
+}
+
+
+bool ProtocolView::startJob(bool isUpdateJob)
+{
+ m_isUpdateJob = isUpdateJob;
+
+ // get command line and add it to output buffer
+ QString cmdLine = job->cvsCommand();
+ buf += cmdLine;
+ buf += '\n';
+ processOutput();
+
+ // disconnect 3rd party slots from our signals
+ disconnect( SIGNAL(receivedLine(QString)) );
+ disconnect( SIGNAL(jobFinished(bool, int)) );
+
+ return job->execute();
+}
+
+
+QPopupMenu* ProtocolView::createPopupMenu(const QPoint &pos)
+{
+ QPopupMenu* menu = QTextEdit::createPopupMenu(pos);
+
+ int id = menu->insertItem(i18n("Clear"), this, SLOT( clear() ), 0, -1, 0);
+
+ if( length() == 0 )
+ menu->setItemEnabled(id, false);
+
+ return menu;
+}
+
+
+void ProtocolView::cancelJob()
+{
+ job->cancel();
+}
+
+
+void ProtocolView::slotReceivedOutput(QString buffer)
+{
+ buf += buffer;
+ processOutput();
+}
+
+
+void ProtocolView::slotJobExited(bool normalExit, int exitStatus)
+{
+ QString msg;
+
+ if( normalExit )
+ {
+ if( exitStatus )
+ msg = i18n("[Exited with status %1]\n").arg(exitStatus);
+ else
+ msg = i18n("[Finished]\n");
+ }
+ else
+ msg = i18n("[Aborted]\n");
+
+ buf += '\n';
+ buf += msg;
+ processOutput();
+
+ emit jobFinished(normalExit, exitStatus);
+}
+
+
+void ProtocolView::processOutput()
+{
+ int pos;
+ while ( (pos = buf.find('\n')) != -1)
+ {
+ QString line = buf.left(pos);
+ if (!line.isEmpty())
+ {
+ appendLine(line);
+ emit receivedLine(line);
+ }
+ buf = buf.right(buf.length()-pos-1);
+ }
+}
+
+
+void ProtocolView::appendLine(const QString &line)
+{
+ // Escape output line, so that html tags in commit
+ // messages aren't interpreted
+ const QString escapedLine = QStyleSheet::escape(line);
+
+ // When we don't get the output from an update job then
+ // just add it to the text edit.
+ if( !m_isUpdateJob )
+ {
+ append(escapedLine);
+ return;
+ }
+
+ QColor color;
+ // Colors are the same as in UpdateViewItem::paintCell()
+ if (line.startsWith("C "))
+ color = conflictColor;
+ else if (line.startsWith("M ")
+ || line.startsWith("A ") || line.startsWith("R "))
+ color = localChangeColor;
+ else if (line.startsWith("P ") || line.startsWith("U "))
+ color = remoteChangeColor;
+
+ append(color.isValid()
+ ? QString("<font color=\"%1\"><b>%2</b></font>").arg(color.name())
+ .arg(escapedLine)
+ : escapedLine);
+}
+
+
+#include "protocolview.moc"
+
+
+// Local Variables:
+// c-basic-offset: 4
+// End:
+
+
diff --git a/cervisia/protocolview.h b/cervisia/protocolview.h
new file mode 100644
index 00000000..0e0390d2
--- /dev/null
+++ b/cervisia/protocolview.h
@@ -0,0 +1,78 @@
+/*
+ * Copyright (C) 1999-2002 Bernd Gehrmann
+ * bernd@mail.berlios.de
+ * Copyright (c) 2003-2004 Christian Loose <christian.loose@kdemail.net>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the 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, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+
+#ifndef PROTOCOLVIEW_H
+#define PROTOCOLVIEW_H
+
+#include <qtextedit.h>
+#include <dcopobject.h>
+
+class QPoint;
+class QPopupMenu;
+class CvsJob_stub;
+
+
+class ProtocolView : public QTextEdit, public DCOPObject
+{
+ K_DCOP
+ Q_OBJECT
+
+public:
+ explicit ProtocolView(const QCString& appId, QWidget *parent=0, const char *name=0);
+ ~ProtocolView();
+
+ bool startJob(bool isUpdateJob = false);
+
+protected:
+ virtual QPopupMenu* createPopupMenu(const QPoint &pos);
+
+k_dcop:
+ void slotReceivedOutput(QString buffer);
+ void slotJobExited(bool normalExit, int exitStatus);
+
+signals:
+ void receivedLine(QString line);
+ void jobFinished(bool normalExit, int exitStatus);
+
+private slots:
+ void cancelJob();
+
+private:
+ void processOutput();
+ void appendLine(const QString &line);
+
+ QString buf;
+
+ QColor conflictColor;
+ QColor localChangeColor;
+ QColor remoteChangeColor;
+
+ CvsJob_stub* job;
+
+ bool m_isUpdateJob;
+};
+
+#endif
+
+
+// Local Variables:
+// c-basic-offset: 4
+// End:
diff --git a/cervisia/qttableview.cpp b/cervisia/qttableview.cpp
new file mode 100644
index 00000000..22b2993c
--- /dev/null
+++ b/cervisia/qttableview.cpp
@@ -0,0 +1,2278 @@
+/**********************************************************************
+** $Id$
+**
+** Implementation of QtTableView class
+**
+** Created : 941115
+**
+** Copyright (C) 1992-2000 Trolltech AS. All rights reserved.
+**
+** This file contains a class moved out of the Qt GUI Toolkit API. It
+** may be used, distributed and modified without limitation.
+**
+**********************************************************************/
+
+#include "qttableview.h"
+#include "qscrollbar.h"
+#include "qpainter.h"
+#include "qdrawutil.h"
+#include <qapplication.h>
+#include <limits.h>
+
+enum ScrollBarDirtyFlags {
+ verGeometry = 0x01,
+ verSteps = 0x02,
+ verRange = 0x04,
+ verValue = 0x08,
+ horGeometry = 0x10,
+ horSteps = 0x20,
+ horRange = 0x40,
+ horValue = 0x80,
+ verMask = 0x0F,
+ horMask = 0xF0
+};
+
+
+#define HSBEXT horizontalScrollBar()->sizeHint().height()
+#define VSBEXT verticalScrollBar()->sizeHint().width()
+
+
+class QCornerSquare : public QWidget // internal class
+{
+public:
+ QCornerSquare( QWidget *, const char* = 0 );
+ void paintEvent( QPaintEvent * );
+};
+
+QCornerSquare::QCornerSquare( QWidget *parent, const char *name )
+ : QWidget( parent, name )
+{
+}
+
+void QCornerSquare::paintEvent( QPaintEvent * )
+{
+}
+
+
+// NOT REVISED
+/*!
+ \class QtTableView qttableview.h
+ \brief The QtTableView class provides an abstract base for tables.
+
+ \obsolete
+
+ A table view consists of a number of abstract cells organized in rows
+ and columns, and a visible part called a view. The cells are identified
+ with a row index and a column index. The top-left cell is in row 0,
+ column 0.
+
+ The behavior of the widget can be finely tuned using
+ setTableFlags(); a typical subclass will consist of little more than a
+ call to setTableFlags(), some table content manipulation and an
+ implementation of paintCell(). Subclasses that need cells with
+ variable width or height must reimplement cellHeight() and/or
+ cellWidth(). Use updateTableSize() to tell QtTableView when the
+ width or height has changed.
+
+ When you read this documentation, it is important to understand the
+ distinctions among the four pixel coordinate systems involved.
+
+ \list 1
+ \i The \e cell coordinates. (0,0) is the top-left corner of a cell.
+ Cell coordinates are used by functions such as paintCell().
+
+ \i The \e table coordinates. (0,0) is the top-left corner of the cell at
+ row 0 and column 0. These coordinates are absolute; that is, they are
+ independent of what part of the table is visible at the moment. They are
+ used by functions such as setXOffset() or maxYOffset().
+
+ \i The \e widget coordinates. (0,0) is the top-left corner of the widget,
+ \e including the frame. They are used by functions such as repaint().
+
+ \i The \e view coordinates. (0,0) is the top-left corner of the view, \e
+ excluding the frame. This is the least-used coordinate system; it is used by
+ functions such as viewWidth(). \endlist
+
+ It is rather unfortunate that we have to use four different
+ coordinate systems, but there was no alternative to provide a flexible and
+ powerful base class.
+
+ Note: The row,column indices are always given in that order,
+ i.e., first the vertical (row), then the horizontal (column). This is
+ the opposite order of all pixel operations, which take first the
+ horizontal (x) and then the vertical (y).
+
+ <img src=qtablevw-m.png> <img src=qtablevw-w.png>
+
+ \warning the functions setNumRows(), setNumCols(), setCellHeight(),
+ setCellWidth(), setTableFlags() and clearTableFlags() may cause
+ virtual functions such as cellWidth() and cellHeight() to be called,
+ even if autoUpdate() is FALSE. This may cause errors if relevant
+ state variables are not initialized.
+
+ \warning Experience has shown that use of this widget tends to cause
+ more bugs than expected and our analysis indicates that the widget's
+ very flexibility is the problem. If QScrollView or QListBox can
+ easily be made to do the job you need, we recommend subclassing
+ those widgets rather than QtTableView. In addition, QScrollView makes
+ it easy to have child widgets inside tables, which QtTableView
+ doesn't support at all.
+
+ \sa QScrollView
+ \link guibooks.html#fowler GUI Design Handbook: Table\endlink
+*/
+
+
+/*!
+ Constructs a table view. The \a parent, \a name and \f arguments
+ are passed to the QFrame constructor.
+
+ The \link setTableFlags() table flags\endlink are all cleared (set to 0).
+ Set \c Tbl_autoVScrollBar or \c Tbl_autoHScrollBar to get automatic scroll
+ bars and \c Tbl_clipCellPainting to get safe clipping.
+
+ The \link setCellHeight() cell height\endlink and \link setCellWidth()
+ cell width\endlink are set to 0.
+
+ Frame line shapes (QFrame::HLink and QFrame::VLine) are disallowed;
+ see QFrame::setFrameStyle().
+
+ Note that the \a f argument is \e not \link setTableFlags() table
+ flags \endlink but rather \link QWidget::QWidget() widget
+ flags. \endlink
+
+*/
+
+QtTableView::QtTableView( QWidget *parent, const char *name, WFlags f )
+ : QFrame( parent, name, f )
+{
+ nRows = nCols = 0; // zero rows/cols
+ xCellOffs = yCellOffs = 0; // zero offset
+ xCellDelta = yCellDelta = 0; // zero cell offset
+ xOffs = yOffs = 0; // zero total pixel offset
+ cellH = cellW = 0; // user defined cell size
+ tFlags = 0;
+ vScrollBar = hScrollBar = 0; // no scroll bars
+ cornerSquare = 0;
+ sbDirty = 0;
+ eraseInPaint = FALSE;
+ verSliding = FALSE;
+ verSnappingOff = FALSE;
+ horSliding = FALSE;
+ horSnappingOff = FALSE;
+ coveringCornerSquare = FALSE;
+ inSbUpdate = FALSE;
+}
+
+/*!
+ Destroys the table view.
+*/
+
+QtTableView::~QtTableView()
+{
+ delete vScrollBar;
+ delete hScrollBar;
+ delete cornerSquare;
+}
+
+
+/*!
+ \internal
+ Reimplements QWidget::setBackgroundColor() for binary compatibility.
+ \sa setPalette()
+*/
+
+void QtTableView::setBackgroundColor( const QColor &c )
+{
+ QWidget::setBackgroundColor( c );
+}
+
+/*!\reimp
+*/
+
+void QtTableView::setPalette( const QPalette &p )
+{
+ QWidget::setPalette( p );
+}
+
+/*!\reimp
+*/
+
+void QtTableView::show()
+{
+ showOrHideScrollBars();
+ QWidget::show();
+}
+
+
+/*!
+ \overload void QtTableView::repaint( bool erase )
+ Repaints the entire view.
+*/
+
+/*!
+ Repaints the table view directly by calling paintEvent() directly
+ unless updates are disabled.
+
+ Erases the view area \a (x,y,w,h) if \a erase is TRUE. Parameters \a
+ (x,y) are in \e widget coordinates.
+
+ If \a w is negative, it is replaced with <code>width() - x</code>.
+ If \a h is negative, it is replaced with <code>height() - y</code>.
+
+ Doing a repaint() usually is faster than doing an update(), but
+ calling update() many times in a row will generate a single paint
+ event.
+
+ At present, QtTableView is the only widget that reimplements \link
+ QWidget::repaint() repaint()\endlink. It does this because by
+ clearing and then repainting one cell at at time, it can make the
+ screen flicker less than it would otherwise. */
+
+void QtTableView::repaint( int x, int y, int w, int h, bool erase )
+{
+ if ( !isVisible() || testWState(WState_BlockUpdates) )
+ return;
+ if ( w < 0 )
+ w = width() - x;
+ if ( h < 0 )
+ h = height() - y;
+ QRect r( x, y, w, h );
+ if ( r.isEmpty() )
+ return; // nothing to do
+ QPaintEvent e( r );
+ if ( erase && backgroundMode() != NoBackground )
+ eraseInPaint = TRUE; // erase when painting
+ paintEvent( &e );
+ eraseInPaint = FALSE;
+}
+
+/*!
+ \overload void QtTableView::repaint( const QRect &r, bool erase )
+ Replaints rectangle \a r. If \a erase is TRUE draws the background
+ using the palette's background.
+*/
+
+
+/*!
+ \fn int QtTableView::numRows() const
+ Returns the number of rows in the table.
+ \sa numCols(), setNumRows()
+*/
+
+/*!
+ Sets the number of rows of the table to \a rows (must be non-negative).
+ Does not change topCell().
+
+ The table repaints itself automatically if autoUpdate() is set.
+
+ \sa numCols(), setNumCols(), numRows()
+*/
+
+void QtTableView::setNumRows( int rows )
+{
+ if ( rows < 0 ) {
+#if defined(QT_CHECK_RANGE)
+ qWarning( "QtTableView::setNumRows: (%s) Negative argument %d.",
+ name( "unnamed" ), rows );
+#endif
+ return;
+ }
+ if ( nRows == rows )
+ return;
+
+ if ( autoUpdate() && isVisible() ) {
+ int oldLastVisible = lastRowVisible();
+ int oldTopCell = topCell();
+ nRows = rows;
+ if ( autoUpdate() && isVisible() &&
+ ( oldLastVisible != lastRowVisible() || oldTopCell != topCell() ) )
+ repaint( oldTopCell != topCell() );
+ } else {
+ // Be more careful - if destructing, bad things might happen.
+ nRows = rows;
+ }
+ updateScrollBars( verRange );
+ updateFrameSize();
+}
+
+/*!
+ \fn int QtTableView::numCols() const
+ Returns the number of columns in the table.
+ \sa numRows(), setNumCols()
+*/
+
+/*!
+ Sets the number of columns of the table to \a cols (must be non-negative).
+ Does not change leftCell().
+
+ The table repaints itself automatically if autoUpdate() is set.
+
+ \sa numCols(), numRows(), setNumRows()
+*/
+
+void QtTableView::setNumCols( int cols )
+{
+ if ( cols < 0 ) {
+#if defined(QT_CHECK_RANGE)
+ qWarning( "QtTableView::setNumCols: (%s) Negative argument %d.",
+ name( "unnamed" ), cols );
+#endif
+ return;
+ }
+ if ( nCols == cols )
+ return;
+ int oldCols = nCols;
+ nCols = cols;
+ if ( autoUpdate() && isVisible() ) {
+ int maxCol = lastColVisible();
+ if ( maxCol >= oldCols || maxCol >= nCols )
+ repaint();
+ }
+ updateScrollBars( horRange );
+ updateFrameSize();
+}
+
+
+/*!
+ \fn int QtTableView::topCell() const
+ Returns the index of the first row in the table that is visible in
+ the view. The index of the first row is 0.
+ \sa leftCell(), setTopCell()
+*/
+
+/*!
+ Scrolls the table so that \a row becomes the top row.
+ The index of the very first row is 0.
+ \sa setYOffset(), setTopLeftCell(), setLeftCell()
+*/
+
+void QtTableView::setTopCell( int row )
+{
+ setTopLeftCell( row, -1 );
+ return;
+}
+
+/*!
+ \fn int QtTableView::leftCell() const
+ Returns the index of the first column in the table that is visible in
+ the view. The index of the very leftmost column is 0.
+ \sa topCell(), setLeftCell()
+*/
+
+/*!
+ Scrolls the table so that \a col becomes the leftmost
+ column. The index of the leftmost column is 0.
+ \sa setXOffset(), setTopLeftCell(), setTopCell()
+*/
+
+void QtTableView::setLeftCell( int col )
+{
+ setTopLeftCell( -1, col );
+ return;
+}
+
+/*!
+ Scrolls the table so that the cell at row \a row and colum \a
+ col becomes the top-left cell in the view. The cell at the extreme
+ top left of the table is at position (0,0).
+ \sa setLeftCell(), setTopCell(), setOffset()
+*/
+
+void QtTableView::setTopLeftCell( int row, int col )
+{
+ int newX = xOffs;
+ int newY = yOffs;
+
+ if ( col >= 0 ) {
+ if ( cellW ) {
+ newX = col*cellW;
+ if ( newX > maxXOffset() )
+ newX = maxXOffset();
+ } else {
+ newX = 0;
+ while ( col )
+ newX += cellWidth( --col ); // optimize using current! ###
+ }
+ }
+ if ( row >= 0 ) {
+ if ( cellH ) {
+ newY = row*cellH;
+ if ( newY > maxYOffset() )
+ newY = maxYOffset();
+ } else {
+ newY = 0;
+ while ( row )
+ newY += cellHeight( --row ); // optimize using current! ###
+ }
+ }
+ setOffset( newX, newY );
+}
+
+
+/*!
+ \fn int QtTableView::xOffset() const
+
+ Returns the x coordinate in \e table coordinates of the pixel that is
+ currently on the left edge of the view.
+
+ \sa setXOffset(), yOffset(), leftCell() */
+
+/*!
+ Scrolls the table so that \a x becomes the leftmost pixel in the view.
+ The \a x parameter is in \e table coordinates.
+
+ The interaction with \link setTableFlags() Tbl_snapToHGrid
+ \endlink is tricky.
+
+ \sa xOffset(), setYOffset(), setOffset(), setLeftCell()
+*/
+
+void QtTableView::setXOffset( int x )
+{
+ setOffset( x, yOffset() );
+}
+
+/*!
+ \fn int QtTableView::yOffset() const
+
+ Returns the y coordinate in \e table coordinates of the pixel that is
+ currently on the top edge of the view.
+
+ \sa setYOffset(), xOffset(), topCell()
+*/
+
+
+/*!
+ Scrolls the table so that \a y becomes the top pixel in the view.
+ The \a y parameter is in \e table coordinates.
+
+ The interaction with \link setTableFlags() Tbl_snapToVGrid
+ \endlink is tricky.
+
+ \sa yOffset(), setXOffset(), setOffset(), setTopCell()
+*/
+
+void QtTableView::setYOffset( int y )
+{
+ setOffset( xOffset(), y );
+}
+
+/*!
+ Scrolls the table so that \a (x,y) becomes the top-left pixel
+ in the view. Parameters \a (x,y) are in \e table coordinates.
+
+ The interaction with \link setTableFlags() Tbl_snapTo*Grid \endlink
+ is tricky. If \a updateScrBars is TRUE, the scroll bars are
+ updated.
+
+ \sa xOffset(), yOffset(), setXOffset(), setYOffset(), setTopLeftCell()
+*/
+
+void QtTableView::setOffset( int x, int y, bool updateScrBars )
+{
+ if ( (!testTableFlags(Tbl_snapToHGrid) || xCellDelta == 0) &&
+ (!testTableFlags(Tbl_snapToVGrid) || yCellDelta == 0) &&
+ (x == xOffs && y == yOffs) )
+ return;
+
+ if ( x < 0 )
+ x = 0;
+ if ( y < 0 )
+ y = 0;
+
+ if ( cellW ) {
+ if ( x > maxXOffset() )
+ x = maxXOffset();
+ xCellOffs = x / cellW;
+ if ( !testTableFlags(Tbl_snapToHGrid) ) {
+ xCellDelta = (short)(x % cellW);
+ } else {
+ x = xCellOffs*cellW;
+ xCellDelta = 0;
+ }
+ } else {
+ int xn=0, xcd=0, col = 0;
+ while ( col < nCols-1 && x >= xn+(xcd=cellWidth(col)) ) {
+ xn += xcd;
+ col++;
+ }
+ xCellOffs = col;
+ if ( testTableFlags(Tbl_snapToHGrid) ) {
+ xCellDelta = 0;
+ x = xn;
+ } else {
+ xCellDelta = (short)(x-xn);
+ }
+ }
+ if ( cellH ) {
+ if ( y > maxYOffset() )
+ y = maxYOffset();
+ yCellOffs = y / cellH;
+ if ( !testTableFlags(Tbl_snapToVGrid) ) {
+ yCellDelta = (short)(y % cellH);
+ } else {
+ y = yCellOffs*cellH;
+ yCellDelta = 0;
+ }
+ } else {
+ int yn=0, yrd=0, row=0;
+ while ( row < nRows-1 && y >= yn+(yrd=cellHeight(row)) ) {
+ yn += yrd;
+ row++;
+ }
+ yCellOffs = row;
+ if ( testTableFlags(Tbl_snapToVGrid) ) {
+ yCellDelta = 0;
+ y = yn;
+ } else {
+ yCellDelta = (short)(y-yn);
+ }
+ }
+ int dx = (x - xOffs);
+ int dy = (y - yOffs);
+ xOffs = x;
+ yOffs = y;
+ if ( autoUpdate() && isVisible() )
+ scroll( dx, dy );
+ if ( updateScrBars )
+ updateScrollBars( verValue | horValue );
+}
+
+
+/*!
+ \overload int QtTableView::cellWidth() const
+
+ Returns the column width in pixels. Returns 0 if the columns have
+ variable widths.
+
+ \sa setCellWidth(), cellHeight()
+*/
+
+/*!
+ Returns the width of column \a col in pixels.
+
+ This function is virtual and must be reimplemented by subclasses that
+ have variable cell widths. Note that if the total table width
+ changes, updateTableSize() must be called.
+
+ \sa setCellWidth(), cellHeight(), totalWidth(), updateTableSize()
+*/
+
+int QtTableView::cellWidth( int )
+{
+ return cellW;
+}
+
+
+/*!
+ Sets the width in pixels of the table cells to \a cellWidth.
+
+ Setting it to 0 means that the column width is variable. When
+ set to 0 (this is the default) QtTableView calls the virtual function
+ cellWidth() to get the width.
+
+ \sa cellWidth(), setCellHeight(), totalWidth(), numCols()
+*/
+
+void QtTableView::setCellWidth( int cellWidth )
+{
+ if ( cellW == cellWidth )
+ return;
+#if defined(QT_CHECK_RANGE)
+ if ( cellWidth < 0 || cellWidth > SHRT_MAX ) {
+ qWarning( "QtTableView::setCellWidth: (%s) Argument out of range (%d)",
+ name( "unnamed" ), cellWidth );
+ return;
+ }
+#endif
+ cellW = (short)cellWidth;
+
+ updateScrollBars( horSteps | horRange );
+ if ( autoUpdate() && isVisible() )
+ repaint();
+
+}
+
+/*!
+ \overload int QtTableView::cellHeight() const
+
+ Returns the row height, in pixels. Returns 0 if the rows have
+ variable heights.
+
+ \sa setCellHeight(), cellWidth()
+*/
+
+
+/*!
+ Returns the height of row \a row in pixels.
+
+ This function is virtual and must be reimplemented by subclasses that
+ have variable cell heights. Note that if the total table height
+ changes, updateTableSize() must be called.
+
+ \sa setCellHeight(), cellWidth(), totalHeight()
+*/
+
+int QtTableView::cellHeight( int )
+{
+ return cellH;
+}
+
+/*!
+ Sets the height in pixels of the table cells to \a cellHeight.
+
+ Setting it to 0 means that the row height is variable. When set
+ to 0 (this is the default), QtTableView calls the virtual function
+ cellHeight() to get the height.
+
+ \sa cellHeight(), setCellWidth(), totalHeight(), numRows()
+*/
+
+void QtTableView::setCellHeight( int cellHeight )
+{
+ if ( cellH == cellHeight )
+ return;
+#if defined(QT_CHECK_RANGE)
+ if ( cellHeight < 0 || cellHeight > SHRT_MAX ) {
+ qWarning( "QtTableView::setCellHeight: (%s) Argument out of range (%d)",
+ name( "unnamed" ), cellHeight );
+ return;
+ }
+#endif
+ cellH = (short)cellHeight;
+ if ( autoUpdate() && isVisible() )
+ repaint();
+ updateScrollBars( verSteps | verRange );
+}
+
+
+/*!
+ Returns the total width of the table in pixels.
+
+ This function is virtual and should be reimplemented by subclasses that
+ have variable cell widths and a non-trivial cellWidth() function, or a
+ large number of columns in the table.
+
+ The default implementation may be slow for very wide tables.
+
+ \sa cellWidth(), totalHeight() */
+
+int QtTableView::totalWidth()
+{
+ if ( cellW ) {
+ return cellW*nCols;
+ } else {
+ int tw = 0;
+ for( int i = 0 ; i < nCols ; i++ )
+ tw += cellWidth( i );
+ return tw;
+ }
+}
+
+/*!
+ Returns the total height of the table in pixels.
+
+ This function is virtual and should be reimplemented by subclasses that
+ have variable cell heights and a non-trivial cellHeight() function, or a
+ large number of rows in the table.
+
+ The default implementation may be slow for very tall tables.
+
+ \sa cellHeight(), totalWidth()
+*/
+
+int QtTableView::totalHeight()
+{
+ if ( cellH ) {
+ return cellH*nRows;
+ } else {
+ int th = 0;
+ for( int i = 0 ; i < nRows ; i++ )
+ th += cellHeight( i );
+ return th;
+ }
+}
+
+
+/*!
+ \fn uint QtTableView::tableFlags() const
+
+ Returns the union of the table flags that are currently set.
+
+ \sa setTableFlags(), clearTableFlags(), testTableFlags()
+*/
+
+/*!
+ \fn bool QtTableView::testTableFlags( uint f ) const
+
+ Returns TRUE if any of the table flags in \a f are currently set,
+ otherwise FALSE.
+
+ \sa setTableFlags(), clearTableFlags(), tableFlags()
+*/
+
+/*!
+ Sets the table flags to \a f.
+
+ If a flag setting changes the appearance of the table, the table is
+ repainted if - and only if - autoUpdate() is TRUE.
+
+ The table flags are mostly single bits, though there are some multibit
+ flags for convenience. Here is a complete list:
+
+ <dl compact>
+ <dt> Tbl_vScrollBar <dd> - The table has a vertical scroll bar.
+ <dt> Tbl_hScrollBar <dd> - The table has a horizontal scroll bar.
+ <dt> Tbl_autoVScrollBar <dd> - The table has a vertical scroll bar if
+ - and only if - the table is taller than the view.
+ <dt> Tbl_autoHScrollBar <dd> The table has a horizontal scroll bar if
+ - and only if - the table is wider than the view.
+ <dt> Tbl_autoScrollBars <dd> - The union of the previous two flags.
+ <dt> Tbl_clipCellPainting <dd> - The table uses QPainter::setClipRect() to
+ make sure that paintCell() will not draw outside the cell
+ boundaries.
+ <dt> Tbl_cutCellsV <dd> - The table will never show part of a
+ cell at the bottom of the table; if there is not space for all of
+ a cell, the space is left blank.
+ <dt> Tbl_cutCellsH <dd> - The table will never show part of a
+ cell at the right side of the table; if there is not space for all of
+ a cell, the space is left blank.
+ <dt> Tbl_cutCells <dd> - The union of the previous two flags.
+ <dt> Tbl_scrollLastHCell <dd> - When the user scrolls horizontally,
+ let him/her scroll the last cell left until it is at the left
+ edge of the view. If this flag is not set, the user can only scroll
+ to the point where the last cell is completely visible.
+ <dt> Tbl_scrollLastVCell <dd> - When the user scrolls vertically, let
+ him/her scroll the last cell up until it is at the top edge of
+ the view. If this flag is not set, the user can only scroll to the
+ point where the last cell is completely visible.
+ <dt> Tbl_scrollLastCell <dd> - The union of the previous two flags.
+ <dt> Tbl_smoothHScrolling <dd> - The table scrolls as smoothly as
+ possible when the user scrolls horizontally. When this flag is not
+ set, scrolling is done one cell at a time.
+ <dt> Tbl_smoothVScrolling <dd> - The table scrolls as smoothly as
+ possible when scrolling vertically. When this flag is not set,
+ scrolling is done one cell at a time.
+ <dt> Tbl_smoothScrolling <dd> - The union of the previous two flags.
+ <dt> Tbl_snapToHGrid <dd> - Except when the user is actually scrolling,
+ the leftmost column shown snaps to the leftmost edge of the view.
+ <dt> Tbl_snapToVGrid <dd> - Except when the user is actually
+ scrolling, the top row snaps to the top edge of the view.
+ <dt> Tbl_snapToGrid <dd> - The union of the previous two flags.
+ </dl>
+
+ You can specify more than one flag at a time using bitwise OR.
+
+ Example:
+ \code
+ setTableFlags( Tbl_smoothScrolling | Tbl_autoScrollBars );
+ \endcode
+
+ \warning The cutCells options (\c Tbl_cutCells, \c Tbl_cutCellsH and
+ Tbl_cutCellsV) may cause painting problems when scrollbars are
+ enabled. Do not combine cutCells and scrollbars.
+
+
+ \sa clearTableFlags(), testTableFlags(), tableFlags()
+*/
+
+void QtTableView::setTableFlags( uint f )
+{
+ f = (f ^ tFlags) & f; // clear flags already set
+ tFlags |= f;
+
+ bool updateOn = autoUpdate();
+ setAutoUpdate( FALSE );
+
+ uint repaintMask = Tbl_cutCellsV | Tbl_cutCellsH;
+
+ if ( f & Tbl_vScrollBar ) {
+ setVerScrollBar( TRUE );
+ }
+ if ( f & Tbl_hScrollBar ) {
+ setHorScrollBar( TRUE );
+ }
+ if ( f & Tbl_autoVScrollBar ) {
+ updateScrollBars( verRange );
+ }
+ if ( f & Tbl_autoHScrollBar ) {
+ updateScrollBars( horRange );
+ }
+ if ( f & Tbl_scrollLastHCell ) {
+ updateScrollBars( horRange );
+ }
+ if ( f & Tbl_scrollLastVCell ) {
+ updateScrollBars( verRange );
+ }
+ if ( f & Tbl_snapToHGrid ) {
+ updateScrollBars( horRange );
+ }
+ if ( f & Tbl_snapToVGrid ) {
+ updateScrollBars( verRange );
+ }
+ if ( f & Tbl_snapToGrid ) { // Note: checks for 2 flags
+ if ( (f & Tbl_snapToHGrid) != 0 && xCellDelta != 0 || //have to scroll?
+ (f & Tbl_snapToVGrid) != 0 && yCellDelta != 0 ) {
+ snapToGrid( (f & Tbl_snapToHGrid) != 0, // do snapping
+ (f & Tbl_snapToVGrid) != 0 );
+ repaintMask |= Tbl_snapToGrid; // repaint table
+ }
+ }
+
+ if ( updateOn ) {
+ setAutoUpdate( TRUE );
+ updateScrollBars();
+ if ( isVisible() && (f & repaintMask) )
+ repaint();
+ }
+
+}
+
+/*!
+ Clears the \link setTableFlags() table flags\endlink that are set
+ in \a f.
+
+ Example (clears a single flag):
+ \code
+ clearTableFlags( Tbl_snapToGrid );
+ \endcode
+
+ The default argument clears all flags.
+
+ \sa setTableFlags(), testTableFlags(), tableFlags()
+*/
+
+void QtTableView::clearTableFlags( uint f )
+{
+ f = (f ^ ~tFlags) & f; // clear flags that are already 0
+ tFlags &= ~f;
+
+ bool updateOn = autoUpdate();
+ setAutoUpdate( FALSE );
+
+ uint repaintMask = Tbl_cutCellsV | Tbl_cutCellsH;
+
+ if ( f & Tbl_vScrollBar ) {
+ setVerScrollBar( FALSE );
+ }
+ if ( f & Tbl_hScrollBar ) {
+ setHorScrollBar( FALSE );
+ }
+ if ( f & Tbl_scrollLastHCell ) {
+ int maxX = maxXOffset();
+ if ( xOffs > maxX ) {
+ setOffset( maxX, yOffs );
+ repaintMask |= Tbl_scrollLastHCell;
+ }
+ updateScrollBars( horRange );
+ }
+ if ( f & Tbl_scrollLastVCell ) {
+ int maxY = maxYOffset();
+ if ( yOffs > maxY ) {
+ setOffset( xOffs, maxY );
+ repaintMask |= Tbl_scrollLastVCell;
+ }
+ updateScrollBars( verRange );
+ }
+ if ( f & Tbl_smoothScrolling ) { // Note: checks for 2 flags
+ if ((f & Tbl_smoothHScrolling) != 0 && xCellDelta != 0 ||//must scroll?
+ (f & Tbl_smoothVScrolling) != 0 && yCellDelta != 0 ) {
+ snapToGrid( (f & Tbl_smoothHScrolling) != 0, // do snapping
+ (f & Tbl_smoothVScrolling) != 0 );
+ repaintMask |= Tbl_smoothScrolling; // repaint table
+ }
+ }
+ if ( f & Tbl_snapToHGrid ) {
+ updateScrollBars( horRange );
+ }
+ if ( f & Tbl_snapToVGrid ) {
+ updateScrollBars( verRange );
+ }
+ if ( updateOn ) {
+ setAutoUpdate( TRUE );
+ updateScrollBars(); // returns immediately if nothing to do
+ if ( isVisible() && (f & repaintMask) )
+ repaint();
+ }
+
+}
+
+
+/*!
+ \fn bool QtTableView::autoUpdate() const
+
+ Returns TRUE if the view updates itself automatically whenever it
+ is changed in some way.
+
+ \sa setAutoUpdate()
+*/
+
+/*!
+ Sets the auto-update option of the table view to \a enable.
+
+ If \a enable is TRUE (this is the default), the view updates itself
+ automatically whenever it has changed in some way (for example, when a
+ \link setTableFlags() flag\endlink is changed).
+
+ If \a enable is FALSE, the view does NOT repaint itself or update
+ its internal state variables when it is changed. This can be
+ useful to avoid flicker during large changes and is singularly
+ useless otherwise. Disable auto-update, do the changes, re-enable
+ auto-update and call repaint().
+
+ \warning Do not leave the view in this state for a long time
+ (i.e., between events). If, for example, the user interacts with the
+ view when auto-update is off, strange things can happen.
+
+ Setting auto-update to TRUE does not repaint the view; you must call
+ repaint() to do this.
+
+ \sa autoUpdate(), repaint()
+*/
+
+void QtTableView::setAutoUpdate( bool enable )
+{
+ if ( isUpdatesEnabled() == enable )
+ return;
+ setUpdatesEnabled( enable );
+ if ( enable ) {
+ showOrHideScrollBars();
+ updateScrollBars();
+ }
+}
+
+
+/*!
+ Repaints the cell at row \a row, column \a col if it is inside the view.
+
+ If \a erase is TRUE, the relevant part of the view is cleared to the
+ background color/pixmap before the contents are repainted.
+
+ \sa isVisible()
+*/
+
+void QtTableView::updateCell( int row, int col, bool erase )
+{
+ int xPos, yPos;
+ if ( !colXPos( col, &xPos ) )
+ return;
+ if ( !rowYPos( row, &yPos ) )
+ return;
+ QRect uR = QRect( xPos, yPos,
+ cellW ? cellW : cellWidth(col),
+ cellH ? cellH : cellHeight(row) );
+ repaint( uR.intersect(viewRect()), erase );
+}
+
+
+/*!
+ \fn QRect QtTableView::cellUpdateRect() const
+
+ This function should be called only from the paintCell() function in
+ subclasses. It returns the portion of a cell that actually needs to be
+ updated in \e cell coordinates. This is useful only for non-trivial
+ paintCell().
+
+*/
+
+/*!
+ Returns the rectangle that is the actual table, excluding any
+ frame, in \e widget coordinates.
+*/
+
+QRect QtTableView::viewRect() const
+{
+ return QRect( frameWidth(), frameWidth(), viewWidth(), viewHeight() );
+}
+
+
+/*!
+ Returns the index of the last (bottom) row in the view.
+ The index of the first row is 0.
+
+ If no rows are visible it returns -1. This can happen if the
+ view is too small for the first row and Tbl_cutCellsV is set.
+
+ \sa lastColVisible()
+*/
+
+int QtTableView::lastRowVisible() const
+{
+ int cellMaxY;
+ int row = findRawRow( maxViewY(), &cellMaxY );
+ if ( row == -1 || row >= nRows ) { // maxViewY() past end?
+ row = nRows - 1; // yes: return last row
+ } else {
+ if ( testTableFlags(Tbl_cutCellsV) && cellMaxY > maxViewY() ) {
+ if ( row == yCellOffs ) // cut by right margin?
+ return -1; // yes, nothing in the view
+ else
+ row = row - 1; // cut by margin, one back
+ }
+ }
+ return row;
+}
+
+/*!
+ Returns the index of the last (right) column in the view.
+ The index of the first column is 0.
+
+ If no columns are visible it returns -1. This can happen if the
+ view is too narrow for the first column and Tbl_cutCellsH is set.
+
+ \sa lastRowVisible()
+*/
+
+int QtTableView::lastColVisible() const
+{
+ int cellMaxX;
+ int col = findRawCol( maxViewX(), &cellMaxX );
+ if ( col == -1 || col >= nCols ) { // maxViewX() past end?
+ col = nCols - 1; // yes: return last col
+ } else {
+ if ( testTableFlags(Tbl_cutCellsH) && cellMaxX > maxViewX() ) {
+ if ( col == xCellOffs ) // cut by bottom margin?
+ return -1; // yes, nothing in the view
+ else
+ col = col - 1; // cell by margin, one back
+ }
+ }
+ return col;
+}
+
+/*!
+ Returns TRUE if \a row is at least partially visible.
+ \sa colIsVisible()
+*/
+
+bool QtTableView::rowIsVisible( int row ) const
+{
+ return rowYPos( row, 0 );
+}
+
+/*!
+ Returns TRUE if \a col is at least partially visible.
+ \sa rowIsVisible()
+*/
+
+bool QtTableView::colIsVisible( int col ) const
+{
+ return colXPos( col, 0 );
+}
+
+
+/*!
+ \internal
+ Called when both scroll bars are active at the same time. Covers the
+ bottom left corner between the two scroll bars with an empty widget.
+*/
+
+void QtTableView::coverCornerSquare( bool enable )
+{
+ coveringCornerSquare = enable;
+ if ( !cornerSquare && enable ) {
+ cornerSquare = new QCornerSquare( this );
+ Q_CHECK_PTR( cornerSquare );
+ cornerSquare->setGeometry( maxViewX() + frameWidth() + 1,
+ maxViewY() + frameWidth() + 1,
+ VSBEXT,
+ HSBEXT);
+ }
+ if ( autoUpdate() && cornerSquare ) {
+ if ( enable )
+ cornerSquare->show();
+ else
+ cornerSquare->hide();
+ }
+}
+
+
+/*!
+ \internal
+ Scroll the view to a position such that:
+
+ If \a horizontal is TRUE, the leftmost column shown fits snugly
+ with the left edge of the view.
+
+ If \a vertical is TRUE, the top row shown fits snugly with the top
+ of the view.
+
+ You can achieve the same effect automatically by setting any of the
+ \link setTableFlags() Tbl_snapTo*Grid \endlink table flags.
+*/
+
+void QtTableView::snapToGrid( bool horizontal, bool vertical )
+{
+ int newXCell = -1;
+ int newYCell = -1;
+ if ( horizontal && xCellDelta != 0 ) {
+ int w = cellW ? cellW : cellWidth( xCellOffs );
+ if ( xCellDelta >= w/2 )
+ newXCell = xCellOffs + 1;
+ else
+ newXCell = xCellOffs;
+ }
+ if ( vertical && yCellDelta != 0 ) {
+ int h = cellH ? cellH : cellHeight( yCellOffs );
+ if ( yCellDelta >= h/2 )
+ newYCell = yCellOffs + 1;
+ else
+ newYCell = yCellOffs;
+ }
+ setTopLeftCell( newYCell, newXCell ); //row,column
+}
+
+/*!
+ \internal
+ This internal slot is connected to the horizontal scroll bar's
+ QScrollBar::valueChanged() signal.
+
+ Moves the table horizontally to offset \a val without updating the
+ scroll bar.
+*/
+
+void QtTableView::horSbValue( int val )
+{
+ if ( horSliding ) {
+ horSliding = FALSE;
+ if ( horSnappingOff ) {
+ horSnappingOff = FALSE;
+ tFlags |= Tbl_snapToHGrid;
+ }
+ }
+ setOffset( val, yOffs, FALSE );
+}
+
+/*!
+ \internal
+ This internal slot is connected to the horizontal scroll bar's
+ QScrollBar::sliderMoved() signal.
+
+ Scrolls the table smoothly horizontally even if \c Tbl_snapToHGrid is set.
+*/
+
+void QtTableView::horSbSliding( int val )
+{
+ if ( testTableFlags(Tbl_snapToHGrid) &&
+ testTableFlags(Tbl_smoothHScrolling) ) {
+ tFlags &= ~Tbl_snapToHGrid; // turn off snapping while sliding
+ setOffset( val, yOffs, FALSE );
+ tFlags |= Tbl_snapToHGrid; // turn on snapping again
+ } else {
+ setOffset( val, yOffs, FALSE );
+ }
+}
+
+/*!
+ \internal
+ This internal slot is connected to the horizontal scroll bar's
+ QScrollBar::sliderReleased() signal.
+*/
+
+void QtTableView::horSbSlidingDone( )
+{
+ if ( testTableFlags(Tbl_snapToHGrid) &&
+ testTableFlags(Tbl_smoothHScrolling) )
+ snapToGrid( TRUE, FALSE );
+}
+
+/*!
+ \internal
+ This internal slot is connected to the vertical scroll bar's
+ QScrollBar::valueChanged() signal.
+
+ Moves the table vertically to offset \a val without updating the
+ scroll bar.
+*/
+
+void QtTableView::verSbValue( int val )
+{
+ if ( verSliding ) {
+ verSliding = FALSE;
+ if ( verSnappingOff ) {
+ verSnappingOff = FALSE;
+ tFlags |= Tbl_snapToVGrid;
+ }
+ }
+ setOffset( xOffs, val, FALSE );
+}
+
+/*!
+ \internal
+ This internal slot is connected to the vertical scroll bar's
+ QScrollBar::sliderMoved() signal.
+
+ Scrolls the table smoothly vertically even if \c Tbl_snapToVGrid is set.
+*/
+
+void QtTableView::verSbSliding( int val )
+{
+ if ( testTableFlags(Tbl_snapToVGrid) &&
+ testTableFlags(Tbl_smoothVScrolling) ) {
+ tFlags &= ~Tbl_snapToVGrid; // turn off snapping while sliding
+ setOffset( xOffs, val, FALSE );
+ tFlags |= Tbl_snapToVGrid; // turn on snapping again
+ } else {
+ setOffset( xOffs, val, FALSE );
+ }
+}
+
+/*!
+ \internal
+ This internal slot is connected to the vertical scroll bar's
+ QScrollBar::sliderReleased() signal.
+*/
+
+void QtTableView::verSbSlidingDone( )
+{
+ if ( testTableFlags(Tbl_snapToVGrid) &&
+ testTableFlags(Tbl_smoothVScrolling) )
+ snapToGrid( FALSE, TRUE );
+}
+
+
+/*!
+ This virtual function is called before painting of table cells
+ is started. It can be reimplemented by subclasses that want to
+ to set up the painter in a special way and that do not want to
+ do so for each cell.
+*/
+
+void QtTableView::setupPainter( QPainter * )
+{
+}
+
+/*!
+ \fn void QtTableView::paintCell( QPainter *p, int row, int col )
+
+ This pure virtual function is called to paint the single cell at \a
+ (row,col) using \a p, which is open when paintCell() is called and
+ must remain open.
+
+ The coordinate system is \link QPainter::translate() translated \endlink
+ so that the origin is at the top-left corner of the cell to be
+ painted, i.e. \e cell coordinates. Do not scale or shear the coordinate
+ system (or if you do, restore the transformation matrix before you
+ return).
+
+ The painter is not clipped by default and for maximum efficiency. For safety,
+ call setTableFlags(Tbl_clipCellPainting) to enable clipping.
+
+ \sa paintEvent(), setTableFlags() */
+
+
+/*!
+ Handles paint events, \a e, for the table view.
+
+ Calls paintCell() for the cells that needs to be repainted.
+*/
+
+void QtTableView::paintEvent( QPaintEvent *e )
+{
+ QRect updateR = e->rect(); // update rectangle
+ if ( sbDirty ) {
+ bool e = eraseInPaint;
+ updateScrollBars();
+ eraseInPaint = e;
+ }
+
+ QPainter paint( this );
+
+ if ( !contentsRect().contains( updateR, TRUE ) ) {// update frame ?
+ drawFrame( &paint );
+ if ( updateR.left() < frameWidth() ) //###
+ updateR.setLeft( frameWidth() );
+ if ( updateR.top() < frameWidth() )
+ updateR.setTop( frameWidth() );
+ }
+
+ int maxWX = maxViewX();
+ int maxWY = maxViewY();
+ if ( updateR.right() > maxWX )
+ updateR.setRight( maxWX );
+ if ( updateR.bottom() > maxWY )
+ updateR.setBottom( maxWY );
+
+ setupPainter( &paint ); // prepare for painting table
+
+ int firstRow = findRow( updateR.y() );
+ int firstCol = findCol( updateR.x() );
+ int xStart, yStart;
+ if ( !colXPos( firstCol, &xStart ) || !rowYPos( firstRow, &yStart ) ) {
+ paint.eraseRect( updateR ); // erase area outside cells but in view
+ return;
+ }
+ int maxX = updateR.right();
+ int maxY = updateR.bottom();
+ int row = firstRow;
+ int col;
+ int yPos = yStart;
+ int xPos = maxX+1; // in case the while() is empty
+ int nextX;
+ int nextY;
+ QRect winR = viewRect();
+ QRect cellR;
+ QRect cellUR;
+#ifndef QT_NO_TRANSFORMATIONS
+ QWMatrix matrix;
+#endif
+
+ while ( yPos <= maxY && row < nRows ) {
+ nextY = yPos + (cellH ? cellH : cellHeight( row ));
+ if ( testTableFlags( Tbl_cutCellsV ) && nextY > ( maxWY + 1 ) )
+ break;
+ col = firstCol;
+ xPos = xStart;
+ while ( xPos <= maxX && col < nCols ) {
+ nextX = xPos + (cellW ? cellW : cellWidth( col ));
+ if ( testTableFlags( Tbl_cutCellsH ) && nextX > ( maxWX + 1 ) )
+ break;
+
+ cellR.setRect( xPos, yPos, cellW ? cellW : cellWidth(col),
+ cellH ? cellH : cellHeight(row) );
+ cellUR = cellR.intersect( updateR );
+ if ( cellUR.isValid() ) {
+ cellUpdateR = cellUR;
+ cellUpdateR.moveBy( -xPos, -yPos ); // cell coordinates
+ if ( eraseInPaint )
+ paint.eraseRect( cellUR );
+
+#ifndef QT_NO_TRANSFORMATIONS
+ matrix.translate( xPos, yPos );
+ paint.setWorldMatrix( matrix );
+ if ( testTableFlags(Tbl_clipCellPainting) ||
+ frameWidth() > 0 && !winR.contains( cellR ) ) { //##arnt
+ paint.setClipRect( cellUR );
+ paintCell( &paint, row, col );
+ paint.setClipping( FALSE );
+ } else {
+ paintCell( &paint, row, col );
+ }
+ matrix.reset();
+ paint.setWorldMatrix( matrix );
+#else
+ paint.translate( xPos, yPos );
+ if ( testTableFlags(Tbl_clipCellPainting) ||
+ frameWidth() > 0 && !winR.contains( cellR ) ) { //##arnt
+ paint.setClipRect( cellUR );
+ paintCell( &paint, row, col );
+ paint.setClipping( FALSE );
+ } else {
+ paintCell( &paint, row, col );
+ }
+ paint.translate( -xPos, -yPos );
+#endif
+ }
+ col++;
+ xPos = nextX;
+ }
+ row++;
+ yPos = nextY;
+ }
+
+ // while painting we have to erase any areas in the view that
+ // are not covered by cells but are covered by the paint event
+ // rectangle these must be erased. We know that xPos is the last
+ // x pixel updated + 1 and that yPos is the last y pixel updated + 1.
+
+ // Note that this needs to be done regardless whether we do
+ // eraseInPaint or not. Reason: a subclass may implement
+ // flicker-freeness and encourage the use of repaint(FALSE).
+ // The subclass, however, cannot draw all pixels, just those
+ // inside the cells. So QtTableView is reponsible for all pixels
+ // outside the cells.
+
+ QRect viewR = viewRect();
+ const QColorGroup g = colorGroup();
+
+ if ( xPos <= maxX ) {
+ QRect r = viewR;
+ r.setLeft( xPos );
+ r.setBottom( yPos<maxY?yPos:maxY );
+ if ( inherits( "QMultiLineEdit" ) )
+ paint.fillRect( r.intersect( updateR ), g.base() );
+ else
+ paint.eraseRect( r.intersect( updateR ) );
+ }
+ if ( yPos <= maxY ) {
+ QRect r = viewR;
+ r.setTop( yPos );
+ if ( inherits( "QMultiLineEdit" ) )
+ paint.fillRect( r.intersect( updateR ), g.base() );
+ else
+ paint.eraseRect( r.intersect( updateR ) );
+ }
+}
+
+/*!\reimp
+*/
+void QtTableView::resizeEvent( QResizeEvent * )
+{
+ updateScrollBars( horValue | verValue | horSteps | horGeometry | horRange |
+ verSteps | verGeometry | verRange );
+ showOrHideScrollBars();
+ updateFrameSize();
+ int maxX = QMIN( xOffs, maxXOffset() ); // ### can be slow
+ int maxY = QMIN( yOffs, maxYOffset() );
+ setOffset( maxX, maxY );
+}
+
+void QtTableView::wheelEvent( QWheelEvent * e )
+{
+ if( e->orientation() == Vertical && vScrollBar && vScrollBar->isVisible() )
+ QApplication::sendEvent( vScrollBar, e );
+}
+
+/*!
+ Redraws all visible cells in the table view.
+*/
+
+void QtTableView::updateView()
+{
+ repaint( viewRect() );
+}
+
+/*!
+ Returns a pointer to the vertical scroll bar mainly so you can
+ connect() to its signals. Note that the scroll bar works in pixel
+ values; use findRow() to translate to cell numbers.
+*/
+
+QScrollBar *QtTableView::verticalScrollBar() const
+{
+ QtTableView *that = (QtTableView*)this; // semantic const
+ if ( !vScrollBar ) {
+ QScrollBar *sb = new QScrollBar( QScrollBar::Vertical, that );
+#ifndef QT_NO_CURSOR
+ sb->setCursor( arrowCursor );
+#endif
+ sb->resize( sb->sizeHint() ); // height is irrelevant
+ Q_CHECK_PTR(sb);
+ sb->setTracking( FALSE );
+ sb->setFocusPolicy( NoFocus );
+ connect( sb, SIGNAL(valueChanged(int)),
+ SLOT(verSbValue(int)));
+ connect( sb, SIGNAL(sliderMoved(int)),
+ SLOT(verSbSliding(int)));
+ connect( sb, SIGNAL(sliderReleased()),
+ SLOT(verSbSlidingDone()));
+ sb->hide();
+ that->vScrollBar = sb;
+ return sb;
+ }
+ return vScrollBar;
+}
+
+/*!
+ Returns a pointer to the horizontal scroll bar mainly so you can
+ connect() to its signals. Note that the scroll bar works in pixel
+ values; use findCol() to translate to cell numbers.
+*/
+
+QScrollBar *QtTableView::horizontalScrollBar() const
+{
+ QtTableView *that = (QtTableView*)this; // semantic const
+ if ( !hScrollBar ) {
+ QScrollBar *sb = new QScrollBar( QScrollBar::Horizontal, that );
+#ifndef QT_NO_CURSOR
+ sb->setCursor( arrowCursor );
+#endif
+ sb->resize( sb->sizeHint() ); // width is irrelevant
+ sb->setFocusPolicy( NoFocus );
+ Q_CHECK_PTR(sb);
+ sb->setTracking( FALSE );
+ connect( sb, SIGNAL(valueChanged(int)),
+ SLOT(horSbValue(int)));
+ connect( sb, SIGNAL(sliderMoved(int)),
+ SLOT(horSbSliding(int)));
+ connect( sb, SIGNAL(sliderReleased()),
+ SLOT(horSbSlidingDone()));
+ sb->hide();
+ that->hScrollBar = sb;
+ return sb;
+ }
+ return hScrollBar;
+}
+
+/*!
+ Enables or disables the horizontal scroll bar, as required by
+ setAutoUpdate() and the \link setTableFlags() table flags\endlink.
+*/
+
+void QtTableView::setHorScrollBar( bool on, bool update )
+{
+ if ( on ) {
+ tFlags |= Tbl_hScrollBar;
+ horizontalScrollBar(); // created
+ if ( update )
+ updateScrollBars( horMask | verMask );
+ else
+ sbDirty = sbDirty | (horMask | verMask);
+ if ( testTableFlags( Tbl_vScrollBar ) )
+ coverCornerSquare( TRUE );
+ if ( autoUpdate() )
+ sbDirty = sbDirty | horMask;
+ } else {
+ tFlags &= ~Tbl_hScrollBar;
+ if ( !hScrollBar )
+ return;
+ coverCornerSquare( FALSE );
+ bool hideScrollBar = autoUpdate() && hScrollBar->isVisible();
+ if ( hideScrollBar )
+ hScrollBar->hide();
+ if ( update )
+ updateScrollBars( verMask );
+ else
+ sbDirty = sbDirty | verMask;
+ if ( hideScrollBar && isVisible() )
+ repaint( hScrollBar->x(), hScrollBar->y(),
+ width() - hScrollBar->x(), hScrollBar->height() );
+ }
+ if ( update )
+ updateFrameSize();
+}
+
+
+/*!
+ Enables or disables the vertical scroll bar, as required by
+ setAutoUpdate() and the \link setTableFlags() table flags\endlink.
+*/
+
+void QtTableView::setVerScrollBar( bool on, bool update )
+{
+ if ( on ) {
+ tFlags |= Tbl_vScrollBar;
+ verticalScrollBar(); // created
+ if ( update )
+ updateScrollBars( verMask | horMask );
+ else
+ sbDirty = sbDirty | (horMask | verMask);
+ if ( testTableFlags( Tbl_hScrollBar ) )
+ coverCornerSquare( TRUE );
+ if ( autoUpdate() )
+ sbDirty = sbDirty | verMask;
+ } else {
+ tFlags &= ~Tbl_vScrollBar;
+ if ( !vScrollBar )
+ return;
+ coverCornerSquare( FALSE );
+ bool hideScrollBar = autoUpdate() && vScrollBar->isVisible();
+ if ( hideScrollBar )
+ vScrollBar->hide();
+ if ( update )
+ updateScrollBars( horMask );
+ else
+ sbDirty = sbDirty | horMask;
+ if ( hideScrollBar && isVisible() )
+ repaint( vScrollBar->x(), vScrollBar->y(),
+ vScrollBar->width(), height() - vScrollBar->y() );
+ }
+ if ( update )
+ updateFrameSize();
+}
+
+
+
+
+int QtTableView::findRawRow( int yPos, int *cellMaxY, int *cellMinY,
+ bool goOutsideView ) const
+{
+ int r = -1;
+ if ( nRows == 0 )
+ return r;
+ if ( goOutsideView || yPos >= minViewY() && yPos <= maxViewY() ) {
+ if ( yPos < minViewY() ) {
+#if defined(QT_CHECK_RANGE)
+ qWarning( "QtTableView::findRawRow: (%s) internal error: "
+ "yPos < minViewY() && goOutsideView "
+ "not supported. (%d,%d)",
+ name( "unnamed" ), yPos, yOffs );
+#endif
+ return -1;
+ }
+ if ( cellH ) { // uniform cell height
+ r = (yPos - minViewY() + yCellDelta)/cellH; // cell offs from top
+ if ( cellMaxY )
+ *cellMaxY = (r + 1)*cellH + minViewY() - yCellDelta - 1;
+ if ( cellMinY )
+ *cellMinY = r*cellH + minViewY() - yCellDelta;
+ r += yCellOffs; // absolute cell index
+ } else { // variable cell height
+ QtTableView *tw = (QtTableView *)this;
+ r = yCellOffs;
+ int h = minViewY() - yCellDelta; //##arnt3
+ int oldH = h;
+ Q_ASSERT( r < nRows );
+ while ( r < nRows ) {
+ oldH = h;
+ h += tw->cellHeight( r ); // Start of next cell
+ if ( yPos < h )
+ break;
+ r++;
+ }
+ if ( cellMaxY )
+ *cellMaxY = h - 1;
+ if ( cellMinY )
+ *cellMinY = oldH;
+ }
+ }
+ return r;
+
+}
+
+
+int QtTableView::findRawCol( int xPos, int *cellMaxX, int *cellMinX ,
+ bool goOutsideView ) const
+{
+ int c = -1;
+ if ( nCols == 0 )
+ return c;
+ if ( goOutsideView || xPos >= minViewX() && xPos <= maxViewX() ) {
+ if ( xPos < minViewX() ) {
+#if defined(QT_CHECK_RANGE)
+ qWarning( "QtTableView::findRawCol: (%s) internal error: "
+ "xPos < minViewX() && goOutsideView "
+ "not supported. (%d,%d)",
+ name( "unnamed" ), xPos, xOffs );
+#endif
+ return -1;
+ }
+ if ( cellW ) { // uniform cell width
+ c = (xPos - minViewX() + xCellDelta)/cellW; //cell offs from left
+ if ( cellMaxX )
+ *cellMaxX = (c + 1)*cellW + minViewX() - xCellDelta - 1;
+ if ( cellMinX )
+ *cellMinX = c*cellW + minViewX() - xCellDelta;
+ c += xCellOffs; // absolute cell index
+ } else { // variable cell width
+ QtTableView *tw = (QtTableView *)this;
+ c = xCellOffs;
+ int w = minViewX() - xCellDelta; //##arnt3
+ int oldW = w;
+ Q_ASSERT( c < nCols );
+ while ( c < nCols ) {
+ oldW = w;
+ w += tw->cellWidth( c ); // Start of next cell
+ if ( xPos < w )
+ break;
+ c++;
+ }
+ if ( cellMaxX )
+ *cellMaxX = w - 1;
+ if ( cellMinX )
+ *cellMinX = oldW;
+ }
+ }
+ return c;
+}
+
+
+/*!
+ Returns the index of the row at position \a yPos, where \a yPos is in
+ \e widget coordinates. Returns -1 if \a yPos is outside the valid
+ range.
+
+ \sa findCol(), rowYPos()
+*/
+
+int QtTableView::findRow( int yPos ) const
+{
+ int cellMaxY;
+ int row = findRawRow( yPos, &cellMaxY );
+ if ( testTableFlags(Tbl_cutCellsV) && cellMaxY > maxViewY() )
+ row = - 1; // cell cut by bottom margin
+ if ( row >= nRows )
+ row = -1;
+ return row;
+}
+
+
+/*!
+ Returns the index of the column at position \a xPos, where \a xPos is
+ in \e widget coordinates. Returns -1 if \a xPos is outside the valid
+ range.
+
+ \sa findRow(), colXPos()
+*/
+
+int QtTableView::findCol( int xPos ) const
+{
+ int cellMaxX;
+ int col = findRawCol( xPos, &cellMaxX );
+ if ( testTableFlags(Tbl_cutCellsH) && cellMaxX > maxViewX() )
+ col = - 1; // cell cut by right margin
+ if ( col >= nCols )
+ col = -1;
+ return col;
+}
+
+
+/*!
+ Computes the position in the widget of row \a row.
+
+ Returns TRUE and stores the result in \a *yPos (in \e widget
+ coordinates) if the row is visible. Returns FALSE and does not modify
+ \a *yPos if \a row is invisible or invalid.
+
+ \sa colXPos(), findRow()
+*/
+
+bool QtTableView::rowYPos( int row, int *yPos ) const
+{
+ int y;
+ if ( row >= yCellOffs ) {
+ if ( cellH ) {
+ int lastVisible = lastRowVisible();
+ if ( row > lastVisible || lastVisible == -1 )
+ return FALSE;
+ y = (row - yCellOffs)*cellH + minViewY() - yCellDelta;
+ } else {
+ //##arnt3
+ y = minViewY() - yCellDelta; // y of leftmost cell in view
+ int r = yCellOffs;
+ QtTableView *tw = (QtTableView *)this;
+ int maxY = maxViewY();
+ while ( r < row && y <= maxY )
+ y += tw->cellHeight( r++ );
+ if ( y > maxY )
+ return FALSE;
+
+ }
+ } else {
+ return FALSE;
+ }
+ if ( yPos )
+ *yPos = y;
+ return TRUE;
+}
+
+
+/*!
+ Computes the position in the widget of column \a col.
+
+ Returns TRUE and stores the result in \a *xPos (in \e widget
+ coordinates) if the column is visible. Returns FALSE and does not
+ modify \a *xPos if \a col is invisible or invalid.
+
+ \sa rowYPos(), findCol()
+*/
+
+bool QtTableView::colXPos( int col, int *xPos ) const
+{
+ int x;
+ if ( col >= xCellOffs ) {
+ if ( cellW ) {
+ int lastVisible = lastColVisible();
+ if ( col > lastVisible || lastVisible == -1 )
+ return FALSE;
+ x = (col - xCellOffs)*cellW + minViewX() - xCellDelta;
+ } else {
+ //##arnt3
+ x = minViewX() - xCellDelta; // x of uppermost cell in view
+ int c = xCellOffs;
+ QtTableView *tw = (QtTableView *)this;
+ int maxX = maxViewX();
+ while ( c < col && x <= maxX )
+ x += tw->cellWidth( c++ );
+ if ( x > maxX )
+ return FALSE;
+ }
+ } else {
+ return FALSE;
+ }
+ if ( xPos )
+ *xPos = x;
+ return TRUE;
+}
+
+
+/*!
+ Moves the visible area of the table right by \a xPixels and
+ down by \a yPixels pixels. Both may be negative.
+
+ \warning You might find that QScrollView offers a higher-level of
+ functionality than using QtTableView and this function.
+
+ This function is \e not the same as QWidget::scroll(); in particular,
+ the signs of \a xPixels and \a yPixels have the reverse semantics.
+
+ \sa setXOffset(), setYOffset(), setOffset(), setTopCell(),
+ setLeftCell()
+*/
+
+void QtTableView::scroll( int xPixels, int yPixels )
+{
+ QWidget::scroll( -xPixels, -yPixels, contentsRect() );
+}
+
+
+/*!
+ Returns the leftmost pixel of the table view in \e view
+ coordinates. This excludes the frame and any header.
+
+ \sa maxViewY(), viewWidth(), contentsRect()
+*/
+
+int QtTableView::minViewX() const
+{
+ return frameWidth();
+}
+
+
+/*!
+ Returns the top pixel of the table view in \e view
+ coordinates. This excludes the frame and any header.
+
+ \sa maxViewX(), viewHeight(), contentsRect()
+*/
+
+int QtTableView::minViewY() const
+{
+ return frameWidth();
+}
+
+
+/*!
+ Returns the rightmost pixel of the table view in \e view
+ coordinates. This excludes the frame and any scroll bar, but
+ includes blank pixels to the right of the visible table data.
+
+ \sa maxViewY(), viewWidth(), contentsRect()
+*/
+
+int QtTableView::maxViewX() const
+{
+ return width() - 1 - frameWidth()
+ - (tFlags & Tbl_vScrollBar ? VSBEXT
+ : 0);
+}
+
+
+/*!
+ Returns the bottom pixel of the table view in \e view
+ coordinates. This excludes the frame and any scroll bar, but
+ includes blank pixels below the visible table data.
+
+ \sa maxViewX(), viewHeight(), contentsRect()
+*/
+
+int QtTableView::maxViewY() const
+{
+ return height() - 1 - frameWidth()
+ - (tFlags & Tbl_hScrollBar ? HSBEXT
+ : 0);
+}
+
+
+/*!
+ Returns the width of the table view, as such, in \e view
+ coordinates. This does not include any header, scroll bar or frame,
+ but it does include background pixels to the right of the table data.
+
+ \sa minViewX() maxViewX(), viewHeight(), contentsRect() viewRect()
+*/
+
+int QtTableView::viewWidth() const
+{
+ return maxViewX() - minViewX() + 1;
+}
+
+
+/*!
+ Returns the height of the table view, as such, in \e view
+ coordinates. This does not include any header, scroll bar or frame,
+ but it does include background pixels below the table data.
+
+ \sa minViewY() maxViewY() viewWidth() contentsRect() viewRect()
+*/
+
+int QtTableView::viewHeight() const
+{
+ return maxViewY() - minViewY() + 1;
+}
+
+
+void QtTableView::doAutoScrollBars()
+{
+ int viewW = width() - frameWidth() - minViewX();
+ int viewH = height() - frameWidth() - minViewY();
+ bool vScrollOn = testTableFlags(Tbl_vScrollBar);
+ bool hScrollOn = testTableFlags(Tbl_hScrollBar);
+ int w = 0;
+ int h = 0;
+ int i;
+
+ if ( testTableFlags(Tbl_autoHScrollBar) ) {
+ if ( cellW ) {
+ w = cellW*nCols;
+ } else {
+ i = 0;
+ while ( i < nCols && w <= viewW )
+ w += cellWidth( i++ );
+ }
+ if ( w > viewW )
+ hScrollOn = TRUE;
+ else
+ hScrollOn = FALSE;
+ }
+
+ if ( testTableFlags(Tbl_autoVScrollBar) ) {
+ if ( cellH ) {
+ h = cellH*nRows;
+ } else {
+ i = 0;
+ while ( i < nRows && h <= viewH )
+ h += cellHeight( i++ );
+ }
+
+ if ( h > viewH )
+ vScrollOn = TRUE;
+ else
+ vScrollOn = FALSE;
+ }
+
+ if ( testTableFlags(Tbl_autoHScrollBar) && vScrollOn && !hScrollOn )
+ if ( w > viewW - VSBEXT )
+ hScrollOn = TRUE;
+
+ if ( testTableFlags(Tbl_autoVScrollBar) && hScrollOn && !vScrollOn )
+ if ( h > viewH - HSBEXT )
+ vScrollOn = TRUE;
+
+ setHorScrollBar( hScrollOn, FALSE );
+ setVerScrollBar( vScrollOn, FALSE );
+ updateFrameSize();
+}
+
+
+/*!
+ \fn void QtTableView::updateScrollBars()
+
+ Updates the scroll bars' contents and presence to match the table's
+ state. Generally, you should not need to call this.
+
+ \sa setTableFlags()
+*/
+
+/*!
+ Updates the scroll bars' contents and presence to match the table's
+ state \c or \a f.
+
+ \sa setTableFlags()
+*/
+
+void QtTableView::updateScrollBars( uint f )
+{
+ sbDirty = sbDirty | f;
+ if ( inSbUpdate )
+ return;
+ inSbUpdate = TRUE;
+
+ if ( testTableFlags(Tbl_autoHScrollBar) && (sbDirty & horRange) ||
+ testTableFlags(Tbl_autoVScrollBar) && (sbDirty & verRange) )
+ // if range change and auto
+ doAutoScrollBars(); // turn scroll bars on/off if needed
+
+ if ( !autoUpdate() ) {
+ inSbUpdate = FALSE;
+ return;
+ }
+ if ( yOffset() > 0 && testTableFlags( Tbl_autoVScrollBar ) &&
+ !testTableFlags( Tbl_vScrollBar ) ) {
+ setYOffset( 0 );
+ }
+ if ( xOffset() > 0 && testTableFlags( Tbl_autoHScrollBar ) &&
+ !testTableFlags( Tbl_hScrollBar ) ) {
+ setXOffset( 0 );
+ }
+ if ( !isVisible() ) {
+ inSbUpdate = FALSE;
+ return;
+ }
+
+ if ( testTableFlags(Tbl_hScrollBar) && (sbDirty & horMask) != 0 ) {
+ if ( sbDirty & horGeometry )
+ hScrollBar->setGeometry( 0,height() - HSBEXT,
+ viewWidth() + frameWidth()*2,
+ HSBEXT);
+
+ if ( sbDirty & horSteps ) {
+ if ( cellW )
+ hScrollBar->setSteps( QMIN(cellW,viewWidth()/2), viewWidth() );
+ else
+ hScrollBar->setSteps( 16, viewWidth() );
+ }
+
+ if ( sbDirty & horRange )
+ hScrollBar->setRange( 0, maxXOffset() );
+
+ if ( sbDirty & horValue )
+ hScrollBar->setValue( xOffs );
+
+ // show scrollbar only when it has a sane geometry
+ if ( !hScrollBar->isVisible() )
+ hScrollBar->show();
+ }
+
+ if ( testTableFlags(Tbl_vScrollBar) && (sbDirty & verMask) != 0 ) {
+ if ( sbDirty & verGeometry )
+ vScrollBar->setGeometry( width() - VSBEXT, 0,
+ VSBEXT,
+ viewHeight() + frameWidth()*2 );
+
+ if ( sbDirty & verSteps ) {
+ if ( cellH )
+ vScrollBar->setSteps( QMIN(cellH,viewHeight()/2), viewHeight() );
+ else
+ vScrollBar->setSteps( 16, viewHeight() ); // fttb! ###
+ }
+
+ if ( sbDirty & verRange )
+ vScrollBar->setRange( 0, maxYOffset() );
+
+ if ( sbDirty & verValue )
+ vScrollBar->setValue( yOffs );
+
+ // show scrollbar only when it has a sane geometry
+ if ( !vScrollBar->isVisible() )
+ vScrollBar->show();
+ }
+ if ( coveringCornerSquare &&
+ ( (sbDirty & verGeometry ) || (sbDirty & horGeometry)) )
+ cornerSquare->move( maxViewX() + frameWidth() + 1,
+ maxViewY() + frameWidth() + 1 );
+
+ sbDirty = 0;
+ inSbUpdate = FALSE;
+}
+
+
+void QtTableView::updateFrameSize()
+{
+ int rw = width() - ( testTableFlags(Tbl_vScrollBar) ?
+ VSBEXT : 0 );
+ int rh = height() - ( testTableFlags(Tbl_hScrollBar) ?
+ HSBEXT : 0 );
+ if ( rw < 0 )
+ rw = 0;
+ if ( rh < 0 )
+ rh = 0;
+
+ if ( autoUpdate() ) {
+ int fh = frameRect().height();
+ int fw = frameRect().width();
+ setFrameRect( QRect(0,0,rw,rh) );
+
+ if ( rw != fw )
+ update( QMIN(fw,rw) - frameWidth() - 2, 0, frameWidth()+4, rh );
+ if ( rh != fh )
+ update( 0, QMIN(fh,rh) - frameWidth() - 2, rw, frameWidth()+4 );
+ }
+}
+
+
+/*!
+ Returns the maximum horizontal offset within the table of the
+ view's left edge in \e table coordinates.
+
+ This is used mainly to set the horizontal scroll bar's range.
+
+ \sa maxColOffset(), maxYOffset(), totalWidth()
+*/
+
+int QtTableView::maxXOffset()
+{
+ int tw = totalWidth();
+ int maxOffs;
+ if ( testTableFlags(Tbl_scrollLastHCell) ) {
+ if ( nCols != 1)
+ maxOffs = tw - ( cellW ? cellW : cellWidth( nCols - 1 ) );
+ else
+ maxOffs = tw - viewWidth();
+ } else {
+ if ( testTableFlags(Tbl_snapToHGrid) ) {
+ if ( cellW ) {
+ maxOffs = tw - (viewWidth()/cellW)*cellW;
+ } else {
+ int goal = tw - viewWidth();
+ int pos = tw;
+ int nextCol = nCols - 1;
+ int nextCellWidth = cellWidth( nextCol );
+ while( nextCol > 0 && pos > goal + nextCellWidth ) {
+ pos -= nextCellWidth;
+ nextCellWidth = cellWidth( --nextCol );
+ }
+ if ( goal + nextCellWidth == pos )
+ maxOffs = goal;
+ else if ( goal < pos )
+ maxOffs = pos;
+ else
+ maxOffs = 0;
+ }
+ } else {
+ maxOffs = tw - viewWidth();
+ }
+ }
+ return maxOffs > 0 ? maxOffs : 0;
+}
+
+
+/*!
+ Returns the maximum vertical offset within the table of the
+ view's top edge in \e table coordinates.
+
+ This is used mainly to set the vertical scroll bar's range.
+
+ \sa maxRowOffset(), maxXOffset(), totalHeight()
+*/
+
+int QtTableView::maxYOffset()
+{
+ int th = totalHeight();
+ int maxOffs;
+ if ( testTableFlags(Tbl_scrollLastVCell) ) {
+ if ( nRows != 1)
+ maxOffs = th - ( cellH ? cellH : cellHeight( nRows - 1 ) );
+ else
+ maxOffs = th - viewHeight();
+ } else {
+ if ( testTableFlags(Tbl_snapToVGrid) ) {
+ if ( cellH ) {
+ maxOffs = th - (viewHeight()/cellH)*cellH;
+ } else {
+ int goal = th - viewHeight();
+ int pos = th;
+ int nextRow = nRows - 1;
+ int nextCellHeight = cellHeight( nextRow );
+ while( nextRow > 0 && pos > goal + nextCellHeight ) {
+ pos -= nextCellHeight;
+ nextCellHeight = cellHeight( --nextRow );
+ }
+ if ( goal + nextCellHeight == pos )
+ maxOffs = goal;
+ else if ( goal < pos )
+ maxOffs = pos;
+ else
+ maxOffs = 0;
+ }
+ } else {
+ maxOffs = th - viewHeight();
+ }
+ }
+ return maxOffs > 0 ? maxOffs : 0;
+}
+
+
+/*!
+ Returns the index of the last column, which may be at the left edge
+ of the view.
+
+ Depending on the \link setTableFlags() Tbl_scrollLastHCell\endlink flag,
+ this may or may not be the last column.
+
+ \sa maxXOffset(), maxRowOffset()
+*/
+
+int QtTableView::maxColOffset()
+{
+ int mx = maxXOffset();
+ if ( cellW )
+ return mx/cellW;
+ else {
+ int xcd=0, col=0;
+ while ( col < nCols && mx > (xcd=cellWidth(col)) ) {
+ mx -= xcd;
+ col++;
+ }
+ return col;
+ }
+}
+
+
+/*!
+ Returns the index of the last row, which may be at the top edge of
+ the view.
+
+ Depending on the \link setTableFlags() Tbl_scrollLastVCell\endlink flag,
+ this may or may not be the last row.
+
+ \sa maxYOffset(), maxColOffset()
+*/
+
+int QtTableView::maxRowOffset()
+{
+ int my = maxYOffset();
+ if ( cellH )
+ return my/cellH;
+ else {
+ int ycd=0, row=0;
+ while ( row < nRows && my > (ycd=cellHeight(row)) ) {
+ my -= ycd;
+ row++;
+ }
+ return row;
+ }
+}
+
+
+void QtTableView::showOrHideScrollBars()
+{
+ if ( !autoUpdate() )
+ return;
+ if ( vScrollBar ) {
+ if ( testTableFlags(Tbl_vScrollBar) ) {
+ if ( !vScrollBar->isVisible() )
+ sbDirty = sbDirty | verMask;
+ } else {
+ if ( vScrollBar->isVisible() )
+ vScrollBar->hide();
+ }
+ }
+ if ( hScrollBar ) {
+ if ( testTableFlags(Tbl_hScrollBar) ) {
+ if ( !hScrollBar->isVisible() )
+ sbDirty = sbDirty | horMask;
+ } else {
+ if ( hScrollBar->isVisible() )
+ hScrollBar->hide();
+ }
+ }
+ if ( cornerSquare ) {
+ if ( testTableFlags(Tbl_hScrollBar) &&
+ testTableFlags(Tbl_vScrollBar) ) {
+ if ( !cornerSquare->isVisible() )
+ cornerSquare->show();
+ } else {
+ if ( cornerSquare->isVisible() )
+ cornerSquare->hide();
+ }
+ }
+}
+
+
+/*!
+ Updates the scroll bars and internal state.
+
+ Call this function when the table view's total size is changed;
+ typically because the result of cellHeight() or cellWidth() have changed.
+
+ This function does not repaint the widget.
+*/
+
+void QtTableView::updateTableSize()
+{
+ bool updateOn = autoUpdate();
+ setAutoUpdate( FALSE );
+ int xofs = xOffset();
+ xOffs++; //so that setOffset will not return immediately
+ setOffset(xofs,yOffset(),FALSE); //to calculate internal state correctly
+ setAutoUpdate(updateOn);
+
+ updateScrollBars( horSteps | horRange |
+ verSteps | verRange );
+ showOrHideScrollBars();
+}
+
+
+#include "qttableview.moc"
diff --git a/cervisia/qttableview.h b/cervisia/qttableview.h
new file mode 100644
index 00000000..6f8b8397
--- /dev/null
+++ b/cervisia/qttableview.h
@@ -0,0 +1,252 @@
+/**********************************************************************
+** $Id$
+**
+** Definition of QtTableView class
+**
+** Created : 941115
+**
+** Copyright (C) 1992-2000 Trolltech AS. All rights reserved.
+**
+** This file contains a class moved out of the Qt GUI Toolkit API. It
+** may be used, distributed and modified without limitation.
+**
+**********************************************************************/
+
+#ifndef QTTABLEVIEW_H
+#define QTTABLEVIEW_H
+
+#ifndef QT_H
+#include "qframe.h"
+#endif // QT_H
+
+#ifndef QT_NO_QTTABLEVIEW
+
+class QScrollBar;
+class QCornerSquare;
+
+
+class QtTableView : public QFrame
+{
+ Q_OBJECT
+public:
+ virtual void setBackgroundColor( const QColor & );
+ virtual void setPalette( const QPalette & );
+ void show();
+
+ void repaint( bool erase=TRUE );
+ void repaint( int x, int y, int w, int h, bool erase=TRUE );
+ void repaint( const QRect &, bool erase=TRUE );
+
+protected:
+ QtTableView( QWidget *parent=0, const char *name=0, WFlags f=0 );
+ ~QtTableView();
+
+ int numRows() const;
+ virtual void setNumRows( int );
+ int numCols() const;
+ virtual void setNumCols( int );
+
+ int topCell() const;
+ virtual void setTopCell( int row );
+ int leftCell() const;
+ virtual void setLeftCell( int col );
+ virtual void setTopLeftCell( int row, int col );
+
+ int xOffset() const;
+ virtual void setXOffset( int );
+ int yOffset() const;
+ virtual void setYOffset( int );
+ virtual void setOffset( int x, int y, bool updateScrBars = TRUE );
+
+ virtual int cellWidth( int col );
+ virtual int cellHeight( int row );
+ int cellWidth() const;
+ int cellHeight() const;
+ virtual void setCellWidth( int );
+ virtual void setCellHeight( int );
+
+ virtual int totalWidth();
+ virtual int totalHeight();
+
+ uint tableFlags() const;
+ bool testTableFlags( uint f ) const;
+ virtual void setTableFlags( uint f );
+ void clearTableFlags( uint f = ~0 );
+
+ bool autoUpdate() const;
+ virtual void setAutoUpdate( bool );
+
+ void updateCell( int row, int column, bool erase=TRUE );
+
+ QRect cellUpdateRect() const;
+ QRect viewRect() const;
+
+ int lastRowVisible() const;
+ int lastColVisible() const;
+
+ bool rowIsVisible( int row ) const;
+ bool colIsVisible( int col ) const;
+
+ QScrollBar *verticalScrollBar() const;
+ QScrollBar *horizontalScrollBar() const;
+
+private slots:
+ void horSbValue( int );
+ void horSbSliding( int );
+ void horSbSlidingDone();
+ void verSbValue( int );
+ void verSbSliding( int );
+ void verSbSlidingDone();
+
+protected:
+ virtual void paintCell( QPainter *, int row, int col ) = 0;
+ virtual void setupPainter( QPainter * );
+
+ void paintEvent( QPaintEvent * );
+ void resizeEvent( QResizeEvent * );
+ virtual void wheelEvent( QWheelEvent *e );
+
+ int findRow( int yPos ) const;
+ int findCol( int xPos ) const;
+
+ bool rowYPos( int row, int *yPos ) const;
+ bool colXPos( int col, int *xPos ) const;
+
+ int maxXOffset();
+ int maxYOffset();
+ int maxColOffset();
+ int maxRowOffset();
+
+ int minViewX() const;
+ int minViewY() const;
+ int maxViewX() const;
+ int maxViewY() const;
+ int viewWidth() const;
+ int viewHeight() const;
+
+ void scroll( int xPixels, int yPixels );
+ void updateScrollBars();
+ void updateTableSize();
+
+private:
+ void coverCornerSquare( bool );
+ void snapToGrid( bool horizontal, bool vertical );
+ virtual void setHorScrollBar( bool on, bool update = TRUE );
+ virtual void setVerScrollBar( bool on, bool update = TRUE );
+ void updateView();
+ int findRawRow( int yPos, int *cellMaxY, int *cellMinY = 0,
+ bool goOutsideView = FALSE ) const;
+ int findRawCol( int xPos, int *cellMaxX, int *cellMinX = 0,
+ bool goOutsideView = FALSE ) const;
+ int maxColsVisible() const;
+
+ void updateScrollBars( uint );
+ void updateFrameSize();
+
+ void doAutoScrollBars();
+ void showOrHideScrollBars();
+
+ int nRows;
+ int nCols;
+ int xOffs, yOffs;
+ int xCellOffs, yCellOffs;
+ short xCellDelta, yCellDelta;
+ short cellH, cellW;
+
+ uint eraseInPaint : 1;
+ uint verSliding : 1;
+ uint verSnappingOff : 1;
+ uint horSliding : 1;
+ uint horSnappingOff : 1;
+ uint coveringCornerSquare : 1;
+ uint sbDirty : 8;
+ uint inSbUpdate : 1;
+
+ uint tFlags;
+ QRect cellUpdateR;
+
+ QScrollBar *vScrollBar;
+ QScrollBar *hScrollBar;
+ QCornerSquare *cornerSquare;
+
+private: // Disabled copy constructor and operator=
+#if defined(Q_DISABLE_COPY)
+ QtTableView( const QtTableView & );
+ QtTableView &operator=( const QtTableView & );
+#endif
+};
+
+
+const uint Tbl_vScrollBar = 0x00000001;
+const uint Tbl_hScrollBar = 0x00000002;
+const uint Tbl_autoVScrollBar = 0x00000004;
+const uint Tbl_autoHScrollBar = 0x00000008;
+const uint Tbl_autoScrollBars = 0x0000000C;
+
+const uint Tbl_clipCellPainting = 0x00000100;
+const uint Tbl_cutCellsV = 0x00000200;
+const uint Tbl_cutCellsH = 0x00000400;
+const uint Tbl_cutCells = 0x00000600;
+
+const uint Tbl_scrollLastHCell = 0x00000800;
+const uint Tbl_scrollLastVCell = 0x00001000;
+const uint Tbl_scrollLastCell = 0x00001800;
+
+const uint Tbl_smoothHScrolling = 0x00002000;
+const uint Tbl_smoothVScrolling = 0x00004000;
+const uint Tbl_smoothScrolling = 0x00006000;
+
+const uint Tbl_snapToHGrid = 0x00008000;
+const uint Tbl_snapToVGrid = 0x00010000;
+const uint Tbl_snapToGrid = 0x00018000;
+
+
+inline int QtTableView::numRows() const
+{ return nRows; }
+
+inline int QtTableView::numCols() const
+{ return nCols; }
+
+inline int QtTableView::topCell() const
+{ return yCellOffs; }
+
+inline int QtTableView::leftCell() const
+{ return xCellOffs; }
+
+inline int QtTableView::xOffset() const
+{ return xOffs; }
+
+inline int QtTableView::yOffset() const
+{ return yOffs; }
+
+inline int QtTableView::cellHeight() const
+{ return cellH; }
+
+inline int QtTableView::cellWidth() const
+{ return cellW; }
+
+inline uint QtTableView::tableFlags() const
+{ return tFlags; }
+
+inline bool QtTableView::testTableFlags( uint f ) const
+{ return (tFlags & f) != 0; }
+
+inline QRect QtTableView::cellUpdateRect() const
+{ return cellUpdateR; }
+
+inline bool QtTableView::autoUpdate() const
+{ return isUpdatesEnabled(); }
+
+inline void QtTableView::repaint( bool erase )
+{ repaint( 0, 0, width(), height(), erase ); }
+
+inline void QtTableView::repaint( const QRect &r, bool erase )
+{ repaint( r.x(), r.y(), r.width(), r.height(), erase ); }
+
+inline void QtTableView::updateScrollBars()
+{ updateScrollBars( 0 ); }
+
+
+#endif // QT_NO_QTTABLEVIEW
+
+#endif // QTTABLEVIEW_H
diff --git a/cervisia/repositories.cpp b/cervisia/repositories.cpp
new file mode 100644
index 00000000..4c517116
--- /dev/null
+++ b/cervisia/repositories.cpp
@@ -0,0 +1,129 @@
+/*
+ * Copyright (C) 1999-2001 Bernd Gehrmann
+ * bernd@mail.berlios.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.
+ *
+ * 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, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+
+#include <stdlib.h>
+#include <qfile.h>
+#include <qdir.h>
+#include <qtextstream.h>
+#include <kapplication.h>
+#include <kconfig.h>
+
+#include "repositories.h"
+#include "cervisiapart.h"
+
+
+static QString fileNameCvs()
+{
+ return QDir::homeDirPath() + "/.cvspass";
+}
+
+
+static QString fileNameCvsnt()
+{
+ return QDir::homeDirPath() + "/.cvs/cvspass";
+}
+
+
+// old .cvspass format:
+// user@host:/path Acleartext_password
+//
+// new .cvspass format (since cvs 1.11.1):
+// /1 user@host:port/path Aencoded_password
+//
+static QStringList readCvsPassFile()
+{
+ QStringList list;
+
+ QFile f(fileNameCvs());
+ if (f.open(IO_ReadOnly))
+ {
+ QTextStream stream(&f);
+ while (!stream.eof())
+ {
+ int pos;
+ QString line = stream.readLine();
+ if ( (pos = line.find(' ')) != -1)
+ {
+ if (line[0] != '/') // old format
+ list.append(line.left(pos));
+ else // new format
+ list.append(line.section(' ', 1, 1));
+ }
+ }
+ }
+
+ return list;
+}
+
+
+// .cvs/cvspass format
+// user@host:port/path=Aencoded_password
+//
+static QStringList readCvsntPassFile()
+{
+ QStringList list;
+
+ QFile file(fileNameCvsnt());
+ if (file.open(IO_ReadOnly))
+ {
+ QTextStream stream(&file);
+ while (!stream.atEnd())
+ {
+ const QString line(stream.readLine());
+
+ const int pos(line.find("=A"));
+ if (pos >= 0)
+ list.append(line.left(pos));
+ }
+ }
+
+ return list;
+}
+
+
+QStringList Repositories::readCvsPassFile()
+{
+ return (QFileInfo(fileNameCvs()).lastModified()
+ < QFileInfo(fileNameCvsnt()).lastModified())
+ ? readCvsntPassFile()
+ : ::readCvsPassFile();
+}
+
+
+QStringList Repositories::readConfigFile()
+{
+ QStringList list;
+
+ KConfig *config = CervisiaPart::config();
+ config->setGroup("Repositories");
+ list = config->readListEntry("Repos");
+
+ // Some people actually use CVSROOT, so we add it here
+ char *env;
+ if ( (env = ::getenv("CVSROOT")) != 0 && !list.contains(env))
+ list.append(env);
+
+ return list;
+}
+
+
+// Local Variables:
+// c-basic-offset: 4
+// End:
diff --git a/cervisia/repositories.h b/cervisia/repositories.h
new file mode 100644
index 00000000..28d7a469
--- /dev/null
+++ b/cervisia/repositories.h
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 1999-2001 Bernd Gehrmann
+ * bernd@mail.berlios.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.
+ *
+ * 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, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+
+#ifndef REPOSITORIES_H
+#define REPOSITORIES_H
+
+
+class Repositories
+{
+public:
+ static QStringList readCvsPassFile();
+ static QStringList readConfigFile();
+};
+
+
+#endif
+
+
+// Local Variables:
+// c-basic-offset: 4
+// End:
diff --git a/cervisia/repositorydlg.cpp b/cervisia/repositorydlg.cpp
new file mode 100644
index 00000000..d0568398
--- /dev/null
+++ b/cervisia/repositorydlg.cpp
@@ -0,0 +1,504 @@
+/*
+ * Copyright (C) 1999-2002 Bernd Gehrmann
+ * bernd@mail.berlios.de
+ * Copyright (c) 2002-2006 Christian Loose <christian.loose@kdemail.net>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the 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, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+
+#include "repositorydlg.h"
+
+#include <qlayout.h>
+#include <qpushbutton.h>
+#include <kbuttonbox.h>
+#include <kconfig.h>
+#include <klistview.h>
+#include <klocale.h>
+#include <kmessagebox.h>
+#include <kdebug.h>
+
+#include "addrepositorydlg.h"
+#include "cvsservice_stub.h"
+#include "misc.h"
+#include "progressdlg.h"
+#include "repositories.h"
+
+
+class RepositoryListItem : public KListViewItem
+{
+public:
+ RepositoryListItem(KListView* parent, const QString& repo, bool loggedin);
+
+ void setRsh(const QString& rsh);
+ void setServer(const QString& server) { m_server = server; }
+ void setCompression(int compression);
+ void setIsLoggedIn(bool isLoggedIn);
+ void setRetrieveCvsignore(bool retrieve) { m_retrieveCvsignore = retrieve; }
+
+ QString repository() const
+ {
+ return text(0);
+ }
+ QString rsh() const
+ {
+ QString str = text(1);
+ return (str.startsWith("ext (") ? str.mid(5, str.length()-6)
+ : QString::null);
+ }
+ QString server() const { return m_server; }
+ int compression() const
+ {
+ bool ok;
+ int n = text(2).toInt(&ok);
+ return ok ? n : -1;
+ }
+ bool isLoggedIn() const { return m_isLoggedIn; }
+ bool retrieveCvsignore() const { return m_retrieveCvsignore; }
+
+private:
+ void changeLoginStatusColumn();
+
+private:
+ QString m_server;
+ bool m_isLoggedIn;
+ bool m_retrieveCvsignore;
+};
+
+
+static bool LoginNeeded(const QString& repository)
+{
+ return repository.startsWith(":pserver:") ||
+ repository.startsWith(":sspi:");
+}
+
+
+RepositoryListItem::RepositoryListItem(KListView* parent, const QString& repo,
+ bool loggedin)
+ : KListViewItem(parent)
+ , m_isLoggedIn(loggedin)
+{
+ setText(0, repo);
+
+ changeLoginStatusColumn();
+}
+
+
+void RepositoryListItem::setRsh(const QString& rsh)
+{
+ QString repo = repository();
+ QString method;
+
+ if( repo.startsWith(":pserver:") )
+ method = "pserver";
+ else if( repo.startsWith(":sspi:") )
+ method = "sspi";
+ else if( repo.contains(':') )
+ {
+ method = "ext";
+ if( !rsh.isEmpty() )
+ {
+ method += " (";
+ method += rsh;
+ method += ")";
+ }
+ }
+ else
+ method = "local";
+
+ setText(1, method);
+}
+
+
+void RepositoryListItem::setCompression(int compression)
+{
+ QString compressionStr = (compression >= 0) ? QString::number(compression)
+ : i18n("Default");
+
+ setText(2, compressionStr);
+}
+
+
+void RepositoryListItem::setIsLoggedIn(bool isLoggedIn)
+{
+ m_isLoggedIn = isLoggedIn;
+
+ changeLoginStatusColumn();
+}
+
+
+void RepositoryListItem::changeLoginStatusColumn()
+{
+ QString loginStatus;
+
+ if( LoginNeeded(repository()) )
+ loginStatus = m_isLoggedIn ? i18n("Logged in") : i18n("Not logged in");
+ else
+ loginStatus = i18n("No login required");
+
+ setText(3, loginStatus);
+}
+
+
+RepositoryDialog::RepositoryDialog(KConfig& cfg, CvsService_stub* cvsService,
+ QWidget* parent, const char* name)
+ : KDialogBase(parent, name, true, i18n("Configure Access to Repositories"),
+ Ok | Cancel | Help, Ok, true)
+ , m_partConfig(cfg)
+ , m_cvsService(cvsService)
+{
+ QFrame* mainWidget = makeMainWidget();
+
+ QBoxLayout* hbox = new QHBoxLayout(mainWidget, 0, spacingHint());
+
+ m_repoList = new KListView(mainWidget);
+ hbox->addWidget(m_repoList, 10);
+ m_repoList->setMinimumWidth(fontMetrics().width('0') * 60);
+ m_repoList->setAllColumnsShowFocus(true);
+ m_repoList->addColumn(i18n("Repository"));
+ m_repoList->addColumn(i18n("Method"));
+ m_repoList->addColumn(i18n("Compression"));
+ m_repoList->addColumn(i18n("Status"));
+ m_repoList->setFocus();
+
+ connect(m_repoList, SIGNAL(doubleClicked(QListViewItem*)),
+ this, SLOT(slotDoubleClicked(QListViewItem*)));
+ connect(m_repoList, SIGNAL(selectionChanged()),
+ this, SLOT(slotSelectionChanged()));
+
+ KButtonBox* actionbox = new KButtonBox(mainWidget, KButtonBox::Vertical);
+ QPushButton* addbutton = actionbox->addButton(i18n("&Add..."));
+ m_modifyButton = actionbox->addButton(i18n("&Modify..."));
+ m_removeButton = actionbox->addButton(i18n("&Remove"));
+ actionbox->addStretch();
+ m_loginButton = actionbox->addButton(i18n("Login..."));
+ m_logoutButton = actionbox->addButton(i18n("Logout"));
+ actionbox->addStretch();
+ actionbox->layout();
+ hbox->addWidget(actionbox, 0);
+
+ m_loginButton->setEnabled(false);
+ m_logoutButton->setEnabled(false);
+
+ connect( addbutton, SIGNAL(clicked()),
+ this, SLOT(slotAddClicked()) );
+ connect( m_modifyButton, SIGNAL(clicked()),
+ this, SLOT(slotModifyClicked()) );
+ connect( m_removeButton, SIGNAL(clicked()),
+ this, SLOT(slotRemoveClicked()) );
+ connect( m_loginButton, SIGNAL(clicked()),
+ this, SLOT(slotLoginClicked()) );
+ connect( m_logoutButton, SIGNAL(clicked()),
+ this, SLOT(slotLogoutClicked()) );
+
+ // open cvs DCOP service configuration file
+ m_serviceConfig = new KConfig("cvsservicerc");
+
+ readCvsPassFile();
+ readConfigFile();
+
+ if (QListViewItem* item = m_repoList->firstChild())
+ {
+ m_repoList->setCurrentItem(item);
+ m_repoList->setSelected(item, true);
+ }
+ else
+ {
+ // we have no item so disable modify and remove button
+ slotSelectionChanged();
+ }
+
+ setHelp("accessing-repository");
+
+ setWFlags(Qt::WDestructiveClose | getWFlags());
+
+ QSize size = configDialogSize(m_partConfig, "RepositoryDialog");
+ resize(size);
+
+ // without this restoreLayout() can't change the column widths
+ for (int i = 0; i < m_repoList->columns(); ++i)
+ m_repoList->setColumnWidthMode(i, QListView::Manual);
+
+ m_repoList->restoreLayout(&m_partConfig, QString::fromLatin1("RepositoryListView"));
+}
+
+
+RepositoryDialog::~RepositoryDialog()
+{
+ saveDialogSize(m_partConfig, "RepositoryDialog");
+
+ m_repoList->saveLayout(&m_partConfig, QString::fromLatin1("RepositoryListView"));
+
+ delete m_serviceConfig;
+}
+
+
+void RepositoryDialog::readCvsPassFile()
+{
+ QStringList list = Repositories::readCvsPassFile();
+ QStringList::ConstIterator it;
+ for( it = list.begin(); it != list.end(); ++it )
+ (void) new RepositoryListItem(m_repoList, (*it), true);
+}
+
+
+void RepositoryDialog::readConfigFile()
+{
+ QStringList list = Repositories::readConfigFile();
+
+ // Sort out all list elements which are already in the list view
+ QListViewItem* item = m_repoList->firstChild();
+ for( ; item; item = item->nextSibling() )
+ list.remove(item->text(0));
+
+ QStringList::ConstIterator it;
+ for( it = list.begin(); it != list.end(); ++it )
+ new RepositoryListItem(m_repoList, *it, false);
+
+ // Now look for the used methods
+ item = m_repoList->firstChild();
+ for( ; item; item = item->nextSibling() )
+ {
+ RepositoryListItem* ritem = static_cast<RepositoryListItem*>(item);
+
+ // read entries from cvs DCOP service configuration
+ m_serviceConfig->setGroup(QString::fromLatin1("Repository-") +
+ ritem->repository());
+
+ QString rsh = m_serviceConfig->readEntry("rsh", QString());
+ QString server = m_serviceConfig->readEntry("cvs_server", QString());
+ int compression = m_serviceConfig->readNumEntry("Compression", -1);
+ bool retrieveFile = m_serviceConfig->readBoolEntry("RetrieveCvsignore",
+ false);
+
+ ritem->setRsh(rsh);
+ ritem->setServer(server);
+ ritem->setCompression(compression);
+ ritem->setRetrieveCvsignore(retrieveFile);
+ }
+}
+
+
+void RepositoryDialog::slotOk()
+{
+ // Make list of repositories
+ QListViewItem* item;
+ QStringList list;
+ for( item = m_repoList->firstChild(); item; item = item->nextSibling() )
+ list.append(item->text(0));
+
+ m_partConfig.setGroup("Repositories");
+ m_partConfig.writeEntry("Repos", list);
+
+ for( item = m_repoList->firstChild(); item; item = item->nextSibling() )
+ {
+ RepositoryListItem* ritem = static_cast<RepositoryListItem*>(item);
+
+ // write entries to cvs DCOP service configuration
+ writeRepositoryData(ritem);
+ }
+
+ // write to disk so other services can reparse the configuration
+ m_serviceConfig->sync();
+
+ KDialogBase::slotOk();
+}
+
+
+void RepositoryDialog::slotAddClicked()
+{
+ AddRepositoryDialog dlg(m_partConfig, QString::null, this);
+ // default compression level
+ dlg.setCompression(-1);
+ if( dlg.exec() )
+ {
+ QString repo = Cervisia::NormalizeRepository(dlg.repository());
+ QString rsh = dlg.rsh();
+ QString server = dlg.server();
+ int compression = dlg.compression();
+ bool retrieveFile = dlg.retrieveCvsignoreFile();
+
+ QListViewItem* item = m_repoList->firstChild();
+ for( ; item; item = item->nextSibling() )
+ if( item->text(0) == repo )
+ {
+ KMessageBox::information(this, i18n("This repository is already known."));
+ return;
+ }
+
+ RepositoryListItem* ritem = new RepositoryListItem(m_repoList, repo, false);
+ ritem->setRsh(rsh);
+ ritem->setCompression(compression);
+ ritem->setRetrieveCvsignore(retrieveFile);
+
+ // write entries to cvs DCOP service configuration
+ writeRepositoryData(ritem);
+
+ // write to disk so other services can reparse the configuration
+ m_serviceConfig->sync();
+ }
+}
+
+
+void RepositoryDialog::slotModifyClicked()
+{
+ slotDoubleClicked(m_repoList->selectedItem());
+}
+
+
+void RepositoryDialog::slotRemoveClicked()
+{
+ // logout from pserver accounts so that they don't
+ // get re-added because of the .cvspass file. (BR #51129)
+ if( m_logoutButton->isEnabled() )
+ slotLogoutClicked();
+
+ delete m_repoList->currentItem();
+}
+
+
+void RepositoryDialog::slotDoubleClicked(QListViewItem* item)
+{
+ if( !item )
+ return;
+
+ RepositoryListItem* ritem = static_cast<RepositoryListItem*>(item);
+ QString repo = ritem->repository();
+ QString rsh = ritem->rsh();
+ QString server = ritem->server();
+ int compression = ritem->compression();
+ bool retrieveFile = ritem->retrieveCvsignore();
+
+ AddRepositoryDialog dlg(m_partConfig, repo, this);
+ dlg.setRepository(repo);
+ dlg.setRsh(rsh);
+ dlg.setServer(server);
+ dlg.setCompression(compression);
+ dlg.setRetrieveCvsignoreFile(retrieveFile);
+ if( dlg.exec() )
+ {
+ ritem->setRsh(dlg.rsh());
+ ritem->setServer(dlg.server());
+ ritem->setCompression(dlg.compression());
+ ritem->setRetrieveCvsignore(dlg.retrieveCvsignoreFile());
+
+ // write entries to cvs DCOP service configuration
+ writeRepositoryData(ritem);
+
+ // write to disk so other services can reparse the configuration
+ m_serviceConfig->sync();
+ }
+}
+
+
+void RepositoryDialog::slotLoginClicked()
+{
+ RepositoryListItem* item = (RepositoryListItem*)m_repoList->currentItem();
+ if( !item )
+ return;
+
+ kdDebug(8050) << k_funcinfo << "repository = " << item->repository() << endl;
+
+ DCOPRef job = m_cvsService->login(item->repository());
+ if( !m_cvsService->ok() )
+ {
+ kdError(8050) << "Failed to call login() method of the cvs DCOP service "
+ << "(" << m_cvsService->app() << ")" << endl;
+ return;
+ }
+
+ bool success = job.call("execute()");
+ if( !success )
+ {
+ QStringList output = job.call("output()");
+ KMessageBox::detailedError(this, i18n("Login failed."), output.join("\n"));
+ return;
+ }
+
+ item->setIsLoggedIn(true);
+ slotSelectionChanged();
+}
+
+
+void RepositoryDialog::slotLogoutClicked()
+{
+ RepositoryListItem* item = (RepositoryListItem*)m_repoList->currentItem();
+ if( !item )
+ return;
+
+ kdDebug(8050) << k_funcinfo << "repository = " << item->repository() << endl;
+
+ DCOPRef job = m_cvsService->logout(item->repository());
+ if( !m_cvsService->ok() )
+ {
+ kdError(8050) << "Failed to call logout() method of the cvs DCOP service "
+ << "(" << m_cvsService->app() << ")" << endl;
+ return;
+ }
+
+ ProgressDialog dlg(this, "Logout", job, "logout", i18n("CVS Logout"));
+ if( !dlg.execute() )
+ return;
+
+ item->setIsLoggedIn(false);
+ slotSelectionChanged();
+}
+
+
+void RepositoryDialog::slotSelectionChanged()
+{
+ // retrieve the selected item
+ RepositoryListItem* item = (RepositoryListItem*)m_repoList->selectedItem();
+
+ // is an item in the list view selected?
+ bool isItemSelected = (item != 0);
+ m_modifyButton->setEnabled(isItemSelected);
+ m_removeButton->setEnabled(isItemSelected);
+ m_loginButton->setEnabled(isItemSelected);
+ m_logoutButton->setEnabled(isItemSelected);
+
+ if( !isItemSelected )
+ return;
+
+ // is this a pserver repository?
+ if( !LoginNeeded(item->repository()) )
+ {
+ m_loginButton->setEnabled(false);
+ m_logoutButton->setEnabled(false);
+ return;
+ }
+
+ // are we logged in?
+ bool isLoggedIn = item->isLoggedIn();
+ m_loginButton->setEnabled(!isLoggedIn);
+ m_logoutButton->setEnabled(isLoggedIn);
+}
+
+
+void RepositoryDialog::writeRepositoryData(RepositoryListItem* item)
+{
+ // write entries to cvs DCOP service configuration
+ m_serviceConfig->setGroup(QString::fromLatin1("Repository-") +
+ item->repository());
+
+ m_serviceConfig->writeEntry("rsh", item->rsh());
+ m_serviceConfig->writeEntry("cvs_server", item->server());
+ m_serviceConfig->writeEntry("Compression", item->compression());
+ m_serviceConfig->writeEntry("RetrieveCvsignore", item->retrieveCvsignore());
+}
+
+#include "repositorydlg.moc"
+
+// kate: space-indent on; indent-width 4; replace-tabs on;
diff --git a/cervisia/repositorydlg.h b/cervisia/repositorydlg.h
new file mode 100644
index 00000000..c980b712
--- /dev/null
+++ b/cervisia/repositorydlg.h
@@ -0,0 +1,77 @@
+/*
+ * Copyright (C) 1999-2002 Bernd Gehrmann
+ * bernd@mail.berlios.de
+ * Copyright (c) 2003-2004 Christian Loose <christian.loose@kdemail.net>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the 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, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+
+#ifndef REPOSITORYDLG_H
+#define REPOSITORYDLG_H
+
+#include <kdialogbase.h>
+
+
+class QListViewItem;
+class QPushButton;
+class KConfig;
+class KListView;
+class CvsService_stub;
+class RepositoryListItem;
+
+
+class RepositoryDialog : public KDialogBase
+{
+ Q_OBJECT
+
+public:
+ RepositoryDialog(KConfig& cfg, CvsService_stub* cvsService,
+ QWidget* parent = 0, const char* name = 0);
+ virtual ~RepositoryDialog();
+
+ void readConfigFile();
+ void readCvsPassFile();
+
+protected:
+ virtual void slotOk();
+
+private slots:
+ void slotAddClicked();
+ void slotModifyClicked();
+ void slotRemoveClicked();
+ void slotDoubleClicked(QListViewItem *item);
+ void slotLoginClicked();
+ void slotLogoutClicked();
+ void slotSelectionChanged();
+
+private:
+ void writeRepositoryData(RepositoryListItem* item);
+
+private:
+ KConfig& m_partConfig;
+ CvsService_stub* m_cvsService;
+ KConfig* m_serviceConfig;
+ KListView* m_repoList;
+ QPushButton* m_modifyButton;
+ QPushButton* m_removeButton;
+ QPushButton* m_loginButton;
+ QPushButton* m_logoutButton;
+};
+
+#endif
+
+
+// kate: space-indent on; indent-width 4; replace-tabs on;
diff --git a/cervisia/resolvedlg.cpp b/cervisia/resolvedlg.cpp
new file mode 100644
index 00000000..2cf0ffd6
--- /dev/null
+++ b/cervisia/resolvedlg.cpp
@@ -0,0 +1,634 @@
+/*
+ * Copyright (C) 1999-2002 Bernd Gehrmann
+ * bernd@mail.berlios.de
+ * Copyright (c) 2003-2004 Christian Loose <christian.loose@hamburg.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.
+ *
+ * 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, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+
+#include "resolvedlg.h"
+
+#include <qfile.h>
+#include <qkeycode.h>
+#include <qlabel.h>
+#include <qlayout.h>
+#include <qpushbutton.h>
+#include <qtextcodec.h>
+#include <qtextstream.h>
+#include <kdebug.h>
+#include <kfiledialog.h>
+#include <klocale.h>
+#include <kmessagebox.h>
+#include <qregexp.h>
+#include "misc.h"
+#include "resolvedlg_p.h"
+using Cervisia::ResolveEditorDialog;
+
+
+// *UGLY HACK*
+// The following conditions are a rough hack
+static QTextCodec *DetectCodec(const QString &fileName)
+{
+ if (fileName.endsWith(".ui") || fileName.endsWith(".docbook")
+ || fileName.endsWith(".xml"))
+ return QTextCodec::codecForName("utf8");
+
+ return QTextCodec::codecForLocale();
+}
+
+
+namespace
+{
+
+class LineSeparator
+{
+public:
+ LineSeparator(const QString& text)
+ : m_text(text)
+ , m_startPos(0)
+ , m_endPos(0)
+ {
+ }
+
+ QString nextLine() const
+ {
+ // already reach end of text on previous call
+ if( m_endPos < 0 )
+ {
+ m_currentLine = QString::null;
+ return m_currentLine;
+ }
+
+ m_endPos = m_text.find('\n', m_startPos);
+
+ int length = m_endPos - m_startPos + 1;
+ m_currentLine = m_text.mid(m_startPos, length);
+ m_startPos = m_endPos + 1;
+
+ return m_currentLine;
+ }
+
+ bool atEnd() const
+ {
+ return (m_endPos < 0 && m_currentLine.isEmpty());
+ }
+
+private:
+ const QString m_text;
+ mutable QString m_currentLine;
+ mutable int m_startPos, m_endPos;
+};
+
+}
+
+
+ResolveDialog::ResolveDialog(KConfig& cfg, QWidget *parent, const char *name)
+ : KDialogBase(parent, name, false, QString::null,
+ Close | Help | User1 | User2, Close, true,
+ KStdGuiItem::saveAs(), KStdGuiItem::save())
+ , markeditem(-1)
+ , partConfig(cfg)
+{
+ items.setAutoDelete(true);
+
+ QFrame* mainWidget = makeMainWidget();
+
+ QBoxLayout *layout = new QVBoxLayout(mainWidget, 0, spacingHint());
+
+ QSplitter *vertSplitter = new QSplitter(QSplitter::Vertical, mainWidget);
+
+ QSplitter *splitter = new QSplitter(QSplitter::Horizontal, vertSplitter);
+
+ QWidget *versionALayoutWidget = new QWidget(splitter);
+ QBoxLayout *versionAlayout = new QVBoxLayout(versionALayoutWidget, 5);
+
+ QLabel *revlabel1 = new QLabel(i18n("Your version (A):"), versionALayoutWidget);
+ versionAlayout->addWidget(revlabel1);
+ diff1 = new DiffView(cfg, true, false, versionALayoutWidget);
+ versionAlayout->addWidget(diff1, 10);
+
+ QWidget* versionBLayoutWidget = new QWidget(splitter);
+ QBoxLayout *versionBlayout = new QVBoxLayout(versionBLayoutWidget, 5);
+
+ QLabel *revlabel2 = new QLabel(i18n("Other version (B):"), versionBLayoutWidget);
+ versionBlayout->addWidget(revlabel2);
+ diff2 = new DiffView(cfg, true, false, versionBLayoutWidget);
+ versionBlayout->addWidget(diff2, 10);
+
+ diff1->setPartner(diff2);
+ diff2->setPartner(diff1);
+
+ QWidget* mergeLayoutWidget = new QWidget(vertSplitter);
+ QBoxLayout *mergeLayout = new QVBoxLayout(mergeLayoutWidget, 5);
+
+ QLabel *mergelabel = new QLabel(i18n("Merged version:"), mergeLayoutWidget);
+ mergeLayout->addWidget(mergelabel);
+
+ merge = new DiffView(cfg, false, false, mergeLayoutWidget);
+ mergeLayout->addWidget(merge, 10);
+
+ layout->addWidget(vertSplitter);
+
+ abutton = new QPushButton("&A", mainWidget);
+ connect( abutton, SIGNAL(clicked()), SLOT(aClicked()) );
+
+ bbutton = new QPushButton("&B", mainWidget);
+ connect( bbutton, SIGNAL(clicked()), SLOT(bClicked()) );
+
+ abbutton = new QPushButton("A+B", mainWidget);
+ connect( abbutton, SIGNAL(clicked()), SLOT(abClicked()) );
+
+ babutton = new QPushButton("B+A", mainWidget);
+ connect( babutton, SIGNAL(clicked()), SLOT(baClicked()) );
+
+ editbutton = new QPushButton(i18n("&Edit"), mainWidget);
+ connect( editbutton, SIGNAL(clicked()), SLOT(editClicked()) );
+
+ nofnlabel = new QLabel(mainWidget);
+ nofnlabel->setAlignment(AlignCenter);
+
+ backbutton = new QPushButton("&<<", mainWidget);
+ connect( backbutton, SIGNAL(clicked()), SLOT(backClicked()) );
+
+ forwbutton = new QPushButton("&>>", mainWidget);
+ connect( forwbutton, SIGNAL(clicked()), SLOT(forwClicked()) );
+
+ QBoxLayout *buttonlayout = new QHBoxLayout(layout);
+ buttonlayout->addWidget(abutton, 1);
+ buttonlayout->addWidget(bbutton, 1);
+ buttonlayout->addWidget(abbutton, 1);
+ buttonlayout->addWidget(babutton, 1);
+ buttonlayout->addWidget(editbutton, 1);
+ buttonlayout->addStretch(1);
+ buttonlayout->addWidget(nofnlabel, 2);
+ buttonlayout->addStretch(1);
+ buttonlayout->addWidget(backbutton, 1);
+ buttonlayout->addWidget(forwbutton, 1);
+
+ connect( this, SIGNAL(user2Clicked()), SLOT(saveClicked()) );
+ connect( this, SIGNAL(user1Clicked()), SLOT(saveAsClicked()) );
+
+ QFontMetrics const fm(fontMetrics());
+ setMinimumSize(fm.width('0') * 120,
+ fm.lineSpacing() * 40);
+
+ setHelp("resolvingconflicts");
+
+ setWFlags(Qt::WDestructiveClose | getWFlags());
+
+ QSize size = configDialogSize(partConfig, "ResolveDialog");
+ resize(size);
+}
+
+
+ResolveDialog::~ResolveDialog()
+{
+ saveDialogSize(partConfig, "ResolveDialog");
+}
+
+
+// One resolve item has a line number range of linenoA:linenoA+linecountA-1
+// in A and linenoB:linenoB+linecountB-1 in B. If the user has chosen version A
+// for the merged file (indicated by chosenA==true), then the line number
+// range in the merged file is offsetM:offsetM+linecountA-1 (accordingly for
+// the other case).
+class ResolveItem
+{
+public:
+ int linenoA, linecountA;
+ int linenoB, linecountB;
+ int linecountTotal;
+ int offsetM;
+ ResolveDialog::ChooseType chosen;
+};
+
+
+bool ResolveDialog::parseFile(const QString &name)
+{
+ int lineno1, lineno2;
+ int advanced1, advanced2;
+ enum { Normal, VersionA, VersionB } state;
+
+ setCaption(i18n("CVS Resolve: %1").arg(name));
+
+ fname = name;
+
+ QString fileContent = readFile();
+ if( fileContent.isNull() )
+ return false;
+
+ LineSeparator separator(fileContent);
+
+ state = Normal;
+ lineno1 = lineno2 = 0;
+ advanced1 = advanced2 = 0;
+ do
+ {
+ QString line = separator.nextLine();
+
+ // reached end of file?
+ if( separator.atEnd() )
+ break;
+
+ switch( state )
+ {
+ case Normal:
+ {
+ // check for start of conflict block
+ // Set to look for <<<<<<< at begining of line with exaclty one
+ // space after then anything after that.
+ QRegExp rx( "^<{7}\\s.*$" );
+ int separatorPos = rx.search(line);
+ if( separatorPos >= 0 )
+ {
+ state = VersionA;
+ advanced1 = 0;
+ }
+ else
+ {
+ addToMergeAndVersionA(line, DiffView::Unchanged, lineno1);
+ addToVersionB(line, DiffView::Unchanged, lineno2);
+ }
+ }
+ break;
+ case VersionA:
+ {
+ // Set to look for ======= at begining of line which may have one
+ // or more spaces after then nothing else.
+ QRegExp rx( "^={7}\\s*$" );
+ int separatorPos = rx.search(line);
+ if( separatorPos < 0 ) // still in version A
+ {
+ advanced1++;
+ addToMergeAndVersionA(line, DiffView::Change, lineno1);
+ }
+ else
+ {
+ state = VersionB;
+ advanced2 = 0;
+ }
+ }
+ break;
+ case VersionB:
+ {
+ // Set to look for >>>>>>> at begining of line with exaclty one
+ // space after then anything after that.
+ QRegExp rx( "^>{7}\\s.*$" );
+ int separatorPos = rx.search(line);
+ if( separatorPos < 0 ) // still in version B
+ {
+ advanced2++;
+ addToVersionB(line, DiffView::Change, lineno2);
+ }
+ else
+ {
+ // create an resolve item
+ ResolveItem *item = new ResolveItem;
+ item->linenoA = lineno1-advanced1+1;
+ item->linecountA = advanced1;
+ item->linenoB = lineno2-advanced2+1;
+ item->linecountB = advanced2;
+ item->offsetM = item->linenoA-1;
+ item->chosen = ChA;
+ item->linecountTotal = item->linecountA;
+ items.append(item);
+
+ for (; advanced1 < advanced2; advanced1++)
+ diff1->addLine("", DiffView::Neutral);
+ for (; advanced2 < advanced1; advanced2++)
+ diff2->addLine("", DiffView::Neutral);
+
+ state = Normal;
+ }
+ }
+ break;
+ }
+ }
+ while( !separator.atEnd() );
+
+ updateNofN();
+
+ return true; // succesful
+}
+
+
+void ResolveDialog::addToMergeAndVersionA(const QString& line,
+ DiffView::DiffType type, int& lineNo)
+{
+ lineNo++;
+ diff1->addLine(line, type, lineNo);
+ merge->addLine(line, type, lineNo);
+}
+
+
+void ResolveDialog::addToVersionB(const QString& line, DiffView::DiffType type,
+ int& lineNo)
+{
+ lineNo++;
+ diff2->addLine(line, type, lineNo);
+}
+
+
+void ResolveDialog::saveFile(const QString &name)
+{
+ QFile f(name);
+ if (!f.open(IO_WriteOnly))
+ {
+ KMessageBox::sorry(this,
+ i18n("Could not open file for writing."),
+ "Cervisia");
+ return;
+ }
+ QTextStream stream(&f);
+ QTextCodec *fcodec = DetectCodec(name);
+ stream.setCodec(fcodec);
+
+ QString output;
+ for( int i = 0; i < merge->count(); i++ )
+ output +=merge->stringAtOffset(i);
+ stream << output;
+
+ f.close();
+}
+
+
+QString ResolveDialog::readFile()
+{
+ QFile f(fname);
+ if( !f.open(IO_ReadOnly) )
+ return QString::null;
+
+ QTextStream stream(&f);
+ QTextCodec* codec = DetectCodec(fname);
+ stream.setCodec(codec);
+
+ return stream.read();
+}
+
+
+void ResolveDialog::updateNofN()
+{
+ QString str;
+ if (markeditem >= 0)
+ str = i18n("%1 of %2").arg(markeditem+1).arg(items.count());
+ else
+ str = i18n("%1 conflicts").arg(items.count());
+ nofnlabel->setText(str);
+
+ backbutton->setEnabled(markeditem != -1);
+ forwbutton->setEnabled(markeditem != -2 && items.count());
+
+ bool marked = markeditem >= 0;
+ abutton->setEnabled(marked);
+ bbutton->setEnabled(marked);
+ abbutton->setEnabled(marked);
+ babutton->setEnabled(marked);
+ editbutton->setEnabled(marked);
+}
+
+
+void ResolveDialog::updateHighlight(int newitem)
+{
+ if (markeditem >= 0)
+ {
+ ResolveItem *item = items.at(markeditem);
+ for (int i = item->linenoA; i < item->linenoA+item->linecountA; ++i)
+ diff1->setInverted(i, false);
+ for (int i = item->linenoB; i < item->linenoB+item->linecountB; ++i)
+ diff2->setInverted(i, false);
+ }
+
+ markeditem = newitem;
+
+ if (markeditem >= 0)
+ {
+ ResolveItem *item = items.at(markeditem);
+ for (int i = item->linenoA; i < item->linenoA+item->linecountA; ++i)
+ diff1->setInverted(i, true);
+ for (int i = item->linenoB; i < item->linenoB+item->linecountB; ++i)
+ diff2->setInverted(i, true);
+ diff1->setCenterLine(item->linenoA);
+ diff2->setCenterLine(item->linenoB);
+ merge->setCenterOffset(item->offsetM);
+ }
+ diff1->repaint();
+ diff2->repaint();
+ merge->repaint();
+ updateNofN();
+}
+
+
+void ResolveDialog::updateMergedVersion(ResolveItem* item,
+ ResolveDialog::ChooseType chosen)
+{
+ // Remove old variant
+ for (int i = 0; i < item->linecountTotal; ++i)
+ merge->removeAtOffset(item->offsetM);
+
+ // Insert new
+ int total = 0;
+ LineSeparator separator(m_contentMergedVersion);
+ QString line = separator.nextLine();
+ while( !separator.atEnd() )
+ {
+ merge->insertAtOffset(line, DiffView::Change, item->offsetM+total);
+ line = separator.nextLine();
+ ++total;
+ }
+
+ // Adjust other items
+ int difference = total - item->linecountTotal;
+ item->chosen = chosen;
+ item->linecountTotal = total;
+ while ( (item = items.next()) != 0 )
+ item->offsetM += difference;
+
+ merge->repaint();
+}
+
+
+void ResolveDialog::backClicked()
+{
+ int newitem;
+ if (markeditem == -1)
+ return; // internal error (button not disabled)
+ else if (markeditem == -2) // past end
+ newitem = items.count()-1;
+ else
+ newitem = markeditem-1;
+ updateHighlight(newitem);
+}
+
+
+void ResolveDialog::forwClicked()
+{
+ int newitem;
+ if (markeditem == -2 || (markeditem == -1 && !items.count()))
+ return; // internal error (button not disabled)
+ else if (markeditem+1 == (int)items.count()) // past end
+ newitem = -2;
+ else
+ newitem = markeditem+1;
+ updateHighlight(newitem);
+}
+
+
+void ResolveDialog::choose(ChooseType ch)
+{
+ if (markeditem < 0)
+ return;
+
+ ResolveItem *item = items.at(markeditem);
+
+ switch (ch)
+ {
+ case ChA:
+ m_contentMergedVersion = contentVersionA(item);
+ break;
+ case ChB:
+ m_contentMergedVersion = contentVersionB(item);
+ break;
+ case ChAB:
+ m_contentMergedVersion = contentVersionA(item) + contentVersionB(item);
+ break;
+ case ChBA:
+ m_contentMergedVersion = contentVersionB(item) + contentVersionA(item);
+ break;
+ default:
+ kdDebug(8050) << "Internal error at switch" << endl;
+ }
+
+ updateMergedVersion(item, ch);
+}
+
+
+void ResolveDialog::aClicked()
+{
+ choose(ChA);
+}
+
+
+void ResolveDialog::bClicked()
+{
+ choose(ChB);
+}
+
+
+void ResolveDialog::abClicked()
+{
+ choose(ChAB);
+}
+
+
+void ResolveDialog::baClicked()
+{
+ choose(ChBA);
+}
+
+
+void ResolveDialog::editClicked()
+{
+ if (markeditem < 0)
+ return;
+
+ ResolveItem *item = items.at(markeditem);
+
+ QString mergedPart;
+ int total = item->linecountTotal;
+ int offset = item->offsetM;
+ for( int i = 0; i < total; ++i )
+ mergedPart += merge->stringAtOffset(offset+i);
+
+ ResolveEditorDialog *dlg = new ResolveEditorDialog(partConfig, this, "edit");
+ dlg->setContent(mergedPart);
+
+ if (dlg->exec())
+ {
+ m_contentMergedVersion = dlg->content();
+ updateMergedVersion(item, ChEdit);
+ }
+
+ delete dlg;
+ diff1->repaint();
+ diff2->repaint();
+ merge->repaint();
+}
+
+
+void ResolveDialog::saveClicked()
+{
+ saveFile(fname);
+}
+
+
+void ResolveDialog::saveAsClicked()
+{
+ QString filename =
+ KFileDialog::getSaveFileName(0, 0, this, 0);
+
+ if( !filename.isEmpty() && Cervisia::CheckOverwrite(filename) )
+ saveFile(filename);
+}
+
+
+void ResolveDialog::keyPressEvent(QKeyEvent *e)
+{
+ switch (e->key())
+ {
+ case Key_A: aClicked(); break;
+ case Key_B: bClicked(); break;
+ case Key_Left: backClicked(); break;
+ case Key_Right:forwClicked(); break;
+ case Key_Up: diff1->up(); break;
+ case Key_Down: diff1->down(); break;
+ default:
+ KDialogBase::keyPressEvent(e);
+ }
+}
+
+
+
+/* This will return the A side of the diff in a QString. */
+QString ResolveDialog::contentVersionA(const ResolveItem *item)
+{
+ QString result;
+ for( int i = item->linenoA; i < item->linenoA+item->linecountA; ++i )
+ {
+ result += diff1->stringAtLine(i);
+ }
+
+ return result;
+}
+
+
+/* This will return the B side of the diff item in a QString. */
+QString ResolveDialog::contentVersionB(const ResolveItem *item)
+{
+ QString result;
+ for( int i = item->linenoB; i < item->linenoB+item->linecountB; ++i )
+ {
+ result += diff2->stringAtLine(i);
+ }
+
+ return result;
+}
+
+#include "resolvedlg.moc"
+
+
+// Local Variables:
+// c-basic-offset: 4
+// End:
diff --git a/cervisia/resolvedlg.h b/cervisia/resolvedlg.h
new file mode 100644
index 00000000..1cee22b7
--- /dev/null
+++ b/cervisia/resolvedlg.h
@@ -0,0 +1,98 @@
+/*
+ * Copyright (C) 1999-2002 Bernd Gehrmann
+ * bernd@mail.berlios.de
+ * Copyright (c) 2003-2004 Christian Loose <christian.loose@hamburg.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.
+ *
+ * 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, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+
+#ifndef RESOLVEDLG_H
+#define RESOLVEDLG_H
+
+
+#include <kdialogbase.h>
+
+#include <qptrlist.h>
+#include "diffview.h"
+
+
+class QLabel;
+class QTextCodec;
+class KConfig;
+class ResolveItem;
+
+
+class ResolveDialog : public KDialogBase
+{
+ Q_OBJECT
+
+public:
+ enum ChooseType { ChA, ChB, ChAB, ChBA, ChEdit };
+
+ explicit ResolveDialog( KConfig& cfg, QWidget *parent=0, const char *name=0 );
+ virtual ~ResolveDialog();
+
+ bool parseFile(const QString &name);
+
+protected:
+ virtual void keyPressEvent(QKeyEvent *e);
+
+private slots:
+ void backClicked();
+ void forwClicked();
+ void aClicked();
+ void bClicked();
+ void abClicked();
+ void baClicked();
+ void editClicked();
+ void saveClicked();
+ void saveAsClicked();
+
+private:
+ void updateNofN();
+ void updateHighlight(int newitem);
+ void choose(ChooseType ch);
+ void chooseEdit();
+ void saveFile(const QString &name);
+ QString readFile();
+ void addToMergeAndVersionA(const QString& line, DiffView::DiffType type,
+ int& lineNo);
+ void addToVersionB(const QString& line, DiffView::DiffType type, int& lineNo);
+ void updateMergedVersion(ResolveItem* item, ChooseType chosen);
+ QString contentVersionA(const ResolveItem *item);
+ QString contentVersionB(const ResolveItem *item);
+
+ QLabel *nofnlabel;
+ QPushButton *backbutton, *forwbutton;
+ QPushButton *abutton, *bbutton, *abbutton, *babutton, *editbutton;
+ DiffView *diff1, *diff2, *merge;
+
+ QPtrList<ResolveItem> items;
+ QString fname;
+ QTextCodec *fcodec;
+ int markeditem;
+ KConfig& partConfig;
+
+ QString m_contentMergedVersion;
+};
+
+
+#endif
+
+
+// Local Variables:
+// c-basic-offset: 4
+// End:
diff --git a/cervisia/resolvedlg_p.cpp b/cervisia/resolvedlg_p.cpp
new file mode 100644
index 00000000..e925677d
--- /dev/null
+++ b/cervisia/resolvedlg_p.cpp
@@ -0,0 +1,59 @@
+/*
+ * Copyright (c) 2004 Christian Loose <christian.loose@kdemail.net>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the 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, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#include "resolvedlg_p.h"
+using namespace Cervisia;
+
+#include <ktextedit.h>
+
+
+ResolveEditorDialog::ResolveEditorDialog(KConfig& cfg, QWidget *parent, const char *name)
+ : KDialogBase(parent, name, true, QString::null,
+ Ok | Cancel, Ok, true)
+ , m_partConfig(cfg)
+{
+ m_edit = new KTextEdit(this);
+ m_edit->setFocus();
+
+ setMainWidget(m_edit);
+
+ QFontMetrics const fm(fontMetrics());
+ setMinimumSize(fm.width('0') * 120,
+ fm.lineSpacing() * 40);
+
+ QSize size = configDialogSize(m_partConfig, "ResolveEditDialog");
+ resize(size);
+}
+
+
+ResolveEditorDialog::~ResolveEditorDialog()
+{
+ saveDialogSize(m_partConfig, "ResolveEditDialog");
+}
+
+
+void ResolveEditorDialog::setContent(const QString& text)
+{
+ m_edit->setText(text);
+}
+
+
+QString ResolveEditorDialog::content() const
+{
+ return m_edit->text();
+}
diff --git a/cervisia/resolvedlg_p.h b/cervisia/resolvedlg_p.h
new file mode 100644
index 00000000..30b4559a
--- /dev/null
+++ b/cervisia/resolvedlg_p.h
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2004 Christian Loose <christian.loose@kdemail.net>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the 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, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#ifndef CERVISIA_RESOLVEEDITORDIALOG_H
+#define CERVISIA_RESOLVEEDITORDIALOG_H
+
+#include <kdialogbase.h>
+
+class KTextEdit;
+class QStringList;
+class KConfig;
+
+
+namespace Cervisia
+{
+
+
+class ResolveEditorDialog : public KDialogBase
+{
+public:
+ explicit ResolveEditorDialog(KConfig& cfg, QWidget* parent=0, const char* name=0);
+ virtual ~ResolveEditorDialog();
+
+ void setContent(const QString& text);
+ QString content() const;
+
+private:
+ KTextEdit* m_edit;
+ KConfig& m_partConfig;
+};
+
+
+}
+
+
+#endif
diff --git a/cervisia/settingsdlg.cpp b/cervisia/settingsdlg.cpp
new file mode 100644
index 00000000..71b8b32c
--- /dev/null
+++ b/cervisia/settingsdlg.cpp
@@ -0,0 +1,385 @@
+/*
+ * Copyright (C) 1999-2002 Bernd Gehrmann
+ * bernd@mail.berlios.de
+ * Copyright (c) 2002-2004 Christian Loose <christian.loose@kdemail.net>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the 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, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#include "settingsdlg.h"
+
+#include <qapplication.h>
+#include <qcheckbox.h>
+#include <qgrid.h>
+#include <qgroupbox.h>
+#include <qlabel.h>
+#include <qlayout.h>
+#include <qvbox.h>
+#include <qwidgetlist.h>
+#include <qhbuttongroup.h>
+#include <qradiobutton.h>
+#include <kbuttonbox.h>
+#include <kcolorbutton.h>
+#include <kconfig.h>
+#include <kfontdialog.h>
+#include <kglobal.h>
+#include <kiconloader.h>
+#include <klineedit.h>
+#include <klocale.h>
+#include <knuminput.h>
+#include <kurlrequester.h>
+
+#include "misc.h"
+#include "cervisiasettings.h"
+#include "settingsdlg_advanced.h"
+
+
+namespace
+{
+ // helper method to load icons for configuration pages
+ inline QPixmap LoadIcon(const char* iconName)
+ {
+ KIconLoader* loader = KGlobal::instance()->iconLoader();
+ return loader->loadIcon(QString::fromLatin1(iconName), KIcon::NoGroup,
+ KIcon::SizeMedium);
+ }
+}
+
+
+FontButton::FontButton( const QString &text, QWidget *parent, const char *name )
+ : QPushButton(text, parent, name)
+{
+ connect( this, SIGNAL(clicked()), this, SLOT(chooseFont()) );
+}
+
+
+void FontButton::chooseFont()
+{
+ QFont newFont(font());
+
+ if (KFontDialog::getFont(newFont, false, this) == QDialog::Rejected)
+ return;
+
+ setFont(newFont);
+ repaint(false);
+}
+
+
+SettingsDialog::SettingsDialog( KConfig *conf, QWidget *parent, const char *name )
+ : KDialogBase(KDialogBase::IconList, i18n("Configure Cervisia"),
+ KDialogBase::Ok | KDialogBase::Cancel | KDialogBase::Help,
+ KDialogBase::Ok,
+ parent, name, true)
+{
+ config = conf;
+
+ // open cvs DCOP service configuration file
+ serviceConfig = new KConfig("cvsservicerc");
+
+ //
+ // General Options
+ //
+ addGeneralPage();
+
+ //
+ // Diff Options
+ //
+ addDiffPage();
+
+ //
+ // Status Options
+ //
+ addStatusPage();
+
+ //
+ // Advanced Options
+ //
+ addAdvancedPage();
+
+ //
+ // Look and Feel Options
+ //
+ addLookAndFeelPage();
+
+ readSettings();
+
+ setHelp("customization", "cervisia");
+}
+
+SettingsDialog::~SettingsDialog()
+{
+ delete serviceConfig;
+}
+
+void SettingsDialog::readSettings()
+{
+ // read entries from cvs DCOP service configuration
+ serviceConfig->setGroup("General");
+ cvspathedit->setURL(serviceConfig->readPathEntry("CVSPath", "cvs"));
+ m_advancedPage->kcfg_Compression->setValue(serviceConfig->readNumEntry(
+ "Compression", 0));
+ m_advancedPage->kcfg_UseSshAgent->setChecked(serviceConfig->readBoolEntry(
+ "UseSshAgent", false));
+
+ config->setGroup("General");
+ m_advancedPage->kcfg_Timeout->setValue(CervisiaSettings::timeout());
+ usernameedit->setText(config->readEntry("Username", Cervisia::UserName()));
+
+ contextedit->setValue((int)config->readUnsignedNumEntry("ContextLines", 65535));
+ tabwidthedit->setValue((int)config->readUnsignedNumEntry("TabWidth", 8));
+ diffoptedit->setText(config->readEntry("DiffOptions"));
+ extdiffedit->setURL(config->readPathEntry("ExternalDiff"));
+ remotestatusbox->setChecked(config->readBoolEntry("StatusForRemoteRepos", false));
+ localstatusbox->setChecked(config->readBoolEntry("StatusForLocalRepos", false));
+
+ // read configuration for look and feel page
+ config->setGroup("LookAndFeel");
+ m_protocolFontBox->setFont(config->readFontEntry("ProtocolFont"));
+ m_annotateFontBox->setFont(config->readFontEntry("AnnotateFont"));
+ m_diffFontBox->setFont(config->readFontEntry("DiffFont"));
+ m_changelogFontBox->setFont(config->readFontEntry("ChangeLogFont"));
+ m_splitterBox->setChecked(config->readBoolEntry("SplitHorizontally",true));
+
+ m_conflictButton->setColor(CervisiaSettings::conflictColor());
+ m_localChangeButton->setColor(CervisiaSettings::localChangeColor());
+ m_remoteChangeButton->setColor(CervisiaSettings::remoteChangeColor());
+ m_notInCvsButton->setColor(CervisiaSettings::notInCvsColor());
+
+ m_diffChangeButton->setColor(CervisiaSettings::diffChangeColor());
+ m_diffInsertButton->setColor(CervisiaSettings::diffInsertColor());
+ m_diffDeleteButton->setColor(CervisiaSettings::diffDeleteColor());
+}
+
+
+void SettingsDialog::writeSettings()
+{
+ // write entries to cvs DCOP service configuration
+ serviceConfig->setGroup("General");
+ serviceConfig->writePathEntry("CVSPath", cvspathedit->url());
+ serviceConfig->writeEntry("Compression",
+ m_advancedPage->kcfg_Compression->value());
+ serviceConfig->writeEntry("UseSshAgent",
+ m_advancedPage->kcfg_UseSshAgent->isChecked());
+
+ // write to disk so other services can reparse the configuration
+ serviceConfig->sync();
+
+ config->setGroup("General");
+ CervisiaSettings::setTimeout(m_advancedPage->kcfg_Timeout->value());
+ config->writeEntry("Username", usernameedit->text());
+
+ config->writePathEntry("ExternalDiff", extdiffedit->url());
+
+ config->writeEntry("ContextLines", (unsigned)contextedit->value());
+ config->writeEntry("TabWidth", tabwidthedit->value());
+ config->writeEntry("DiffOptions", diffoptedit->text());
+ config->writeEntry("StatusForRemoteRepos", remotestatusbox->isChecked());
+ config->writeEntry("StatusForLocalRepos", localstatusbox->isChecked());
+
+ config->setGroup("LookAndFeel");
+ config->writeEntry("ProtocolFont", m_protocolFontBox->font());
+ config->writeEntry("AnnotateFont", m_annotateFontBox->font());
+ config->writeEntry("DiffFont", m_diffFontBox->font());
+ config->writeEntry("ChangeLogFont", m_changelogFontBox->font());
+ config->writeEntry("SplitHorizontally", m_splitterBox->isChecked());
+
+ CervisiaSettings::setConflictColor(m_conflictButton->color());
+ CervisiaSettings::setLocalChangeColor(m_localChangeButton->color());
+ CervisiaSettings::setRemoteChangeColor(m_remoteChangeButton->color());
+ CervisiaSettings::setNotInCvsColor(m_notInCvsButton->color());
+ CervisiaSettings::setDiffChangeColor(m_diffChangeButton->color());
+ CervisiaSettings::setDiffInsertColor(m_diffInsertButton->color());
+ CervisiaSettings::setDiffDeleteColor(m_diffDeleteButton->color());
+
+ // I'm not yet sure whether this is a hack or not :-)
+ QWidgetListIt it(*QApplication::allWidgets());
+ for (; it.current(); ++it)
+ {
+ QWidget *w = it.current();
+ if (w->inherits("ProtocolView"))
+ w->setFont(m_protocolFontBox->font());
+ if (w->inherits("AnnotateView"))
+ w->setFont(m_annotateFontBox->font());
+ if (w->inherits("DiffView"))
+ w->setFont(m_diffFontBox->font());
+ }
+ config->sync();
+
+ CervisiaSettings::writeConfig();
+}
+
+void SettingsDialog::done(int res)
+{
+ if (res == Accepted)
+ writeSettings();
+ KDialogBase::done(res);
+ delete this;
+}
+
+
+/*
+ * Create a page for the general options
+ */
+void SettingsDialog::addGeneralPage()
+{
+ QFrame* generalPage = addPage(i18n("General"), QString::null,
+ LoadIcon("misc"));
+ QVBoxLayout* layout = new QVBoxLayout(generalPage, 0, KDialog::spacingHint());
+
+ QLabel *usernamelabel = new QLabel( i18n("&User name for the change log editor:"), generalPage );
+ usernameedit = new KLineEdit(generalPage);
+ usernameedit->setFocus();
+ usernamelabel->setBuddy(usernameedit);
+
+ layout->addWidget(usernamelabel);
+ layout->addWidget(usernameedit);
+
+ QLabel *cvspathlabel = new QLabel( i18n("&Path to CVS executable, or 'cvs':"), generalPage );
+ cvspathedit = new KURLRequester(generalPage);
+ cvspathlabel->setBuddy(cvspathedit);
+
+ layout->addWidget(cvspathlabel);
+ layout->addWidget(cvspathedit);
+
+ layout->addStretch();
+}
+
+
+/*
+ * Create a page for the diff optionsw
+ */
+void SettingsDialog::addDiffPage()
+{
+ QGrid *diffPage = addGridPage(2, QGrid::Horizontal, i18n("Diff Viewer"),
+ QString::null, LoadIcon("vcs_diff"));
+
+ QLabel *contextlabel = new QLabel( i18n("&Number of context lines in diff dialog:"), diffPage );
+ contextedit = new KIntNumInput( 0, diffPage );
+ contextedit->setRange(0, 65535, 1, false);
+ contextlabel->setBuddy(contextedit);
+
+ QLabel *diffoptlabel = new QLabel(i18n("Additional &options for cvs diff:"), diffPage);
+ diffoptedit = new KLineEdit(diffPage);
+ diffoptlabel->setBuddy(diffoptedit);
+
+ QLabel *tabwidthlabel = new QLabel(i18n("Tab &width in diff dialog:"), diffPage);
+ tabwidthedit = new KIntNumInput(0, diffPage);
+ tabwidthedit->setRange(1, 16, 1, false);
+ tabwidthlabel->setBuddy(tabwidthedit);
+
+ QLabel *extdifflabel = new QLabel(i18n("External diff &frontend:"), diffPage);
+ extdiffedit = new KURLRequester(diffPage);
+ extdifflabel->setBuddy(extdiffedit);
+
+ // dummy widget to take up the vertical space
+ new QWidget(diffPage);
+}
+
+
+/*
+ * Create a page for the status options
+ */
+void SettingsDialog::addStatusPage()
+{
+ QVBox* statusPage = addVBoxPage(i18n("Status"), QString::null,
+ LoadIcon("fork"));
+
+ remotestatusbox = new QCheckBox(i18n("When opening a sandbox from a &remote repository,\n"
+ "start a File->Status command automatically"), statusPage);
+ localstatusbox = new QCheckBox(i18n("When opening a sandbox from a &local repository,\n"
+ "start a File->Status command automatically"), statusPage);
+
+ // dummy widget to take up the vertical space
+ new QWidget(statusPage);
+}
+
+
+/*
+ * Create a page for the advanced options
+ */
+void SettingsDialog::addAdvancedPage()
+{
+ QVBox* frame = addVBoxPage(i18n("Advanced"), QString::null,
+ LoadIcon("configure"));
+
+ m_advancedPage = new AdvancedPage(frame);
+ m_advancedPage->kcfg_Timeout->setRange(0, 50000, 100, false);
+ m_advancedPage->kcfg_Compression->setRange(0, 9, 1, false);
+}
+
+
+/*
+ * Create a page for the look & feel options
+ */
+void SettingsDialog::addLookAndFeelPage()
+{
+ QVBox* lookPage = addVBoxPage(i18n("Appearance"), QString::null,
+ LoadIcon("looknfeel"));
+
+ QGroupBox* fontGroupBox = new QGroupBox(4, Qt::Vertical, i18n("Fonts"),
+ lookPage);
+ fontGroupBox->setInsideSpacing(KDialog::spacingHint());
+
+ m_protocolFontBox = new FontButton(i18n("Font for &Protocol Window..."),
+ fontGroupBox);
+ m_annotateFontBox = new FontButton(i18n("Font for A&nnotate View..."),
+ fontGroupBox);
+ m_diffFontBox = new FontButton(i18n("Font for D&iff View..."),
+ fontGroupBox);
+ m_changelogFontBox = new FontButton(i18n("Font for ChangeLog View..."),
+ fontGroupBox);
+
+ QGroupBox* colorGroupBox = new QGroupBox(4, Qt::Horizontal,
+ i18n("Colors"), lookPage);
+ colorGroupBox->setColumns(4);
+ colorGroupBox->setInsideSpacing(KDialog::spacingHint());
+
+ QLabel* conflictLabel = new QLabel(i18n("Conflict:"), colorGroupBox);
+ m_conflictButton = new KColorButton(colorGroupBox);
+ conflictLabel->setBuddy(m_conflictButton);
+
+ QLabel* diffChangeLabel = new QLabel(i18n("Diff change:"), colorGroupBox);
+ m_diffChangeButton = new KColorButton(colorGroupBox);
+ diffChangeLabel->setBuddy(m_diffChangeButton);
+
+ QLabel* localChangeLabel = new QLabel(i18n("Local change:"), colorGroupBox);
+ m_localChangeButton = new KColorButton(colorGroupBox);
+ localChangeLabel->setBuddy(m_localChangeButton);
+
+ QLabel* diffInsertLabel = new QLabel(i18n("Diff insertion:"), colorGroupBox);
+ m_diffInsertButton = new KColorButton(colorGroupBox);
+ diffInsertLabel->setBuddy(m_diffInsertButton);
+
+ QLabel* remoteChangeLabel = new QLabel(i18n("Remote change:"), colorGroupBox);
+ m_remoteChangeButton = new KColorButton(colorGroupBox);
+ remoteChangeLabel->setBuddy( m_remoteChangeButton );
+
+ QLabel* diffDeleteLabel = new QLabel(i18n("Diff deletion:"), colorGroupBox);
+ m_diffDeleteButton = new KColorButton(colorGroupBox);
+ diffDeleteLabel->setBuddy(m_diffDeleteButton);
+
+ QLabel* notInCvsLabel = new QLabel(i18n("Not in cvs:"), colorGroupBox);
+ m_notInCvsButton = new KColorButton(colorGroupBox);
+ notInCvsLabel->setBuddy(m_notInCvsButton);
+
+ m_splitterBox = new QCheckBox(i18n("Split main window &horizontally"), lookPage);
+}
+
+#include "settingsdlg.moc"
+
+
+// Local Variables:
+// c-basic-offset: 4
+// End:
diff --git a/cervisia/settingsdlg.h b/cervisia/settingsdlg.h
new file mode 100644
index 00000000..2f7effb4
--- /dev/null
+++ b/cervisia/settingsdlg.h
@@ -0,0 +1,104 @@
+/*
+ * Copyright (C) 1999-2002 Bernd Gehrmann
+ * bernd@mail.berlios.de
+ * Copyright (c) 2002-2004 Christian Loose <christian.loose@kdemail.net>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the 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, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#ifndef SETTINGSDLG_H
+#define SETTINGSDLG_H
+
+
+#include <qpushbutton.h>
+#include <kdialogbase.h>
+
+
+class QCheckBox;
+class KIntNumInput;
+class KLineEdit;
+class KConfig;
+class KColorButton;
+class KURLRequester;
+class AdvancedPage;
+
+
+class FontButton : public QPushButton
+{
+ Q_OBJECT
+
+public:
+ FontButton( const QString &text, QWidget *parent=0, const char *name=0 );
+
+private slots:
+ void chooseFont();
+};
+
+
+class SettingsDialog : public KDialogBase
+{
+ Q_OBJECT
+
+public:
+ SettingsDialog( KConfig *conf, QWidget *parent=0, const char *name=0 );
+ virtual ~SettingsDialog();
+
+protected slots:
+ virtual void done(int res);
+
+private:
+ void readSettings();
+ void writeSettings();
+
+ void addGeneralPage();
+ void addDiffPage();
+ void addStatusPage();
+ void addAdvancedPage();
+ void addLookAndFeelPage();
+
+ KConfig *config;
+ KIntNumInput *contextedit;
+ KIntNumInput *tabwidthedit;
+ KURLRequester *cvspathedit;
+ KLineEdit *usernameedit;
+ KLineEdit *diffoptedit;
+ KURLRequester *extdiffedit;
+ QCheckBox *remotestatusbox;
+ QCheckBox *localstatusbox;
+ FontButton* m_protocolFontBox;
+ FontButton* m_annotateFontBox;
+ FontButton* m_diffFontBox;
+ FontButton* m_changelogFontBox;
+
+ KColorButton* m_conflictButton;
+ KColorButton* m_localChangeButton;
+ KColorButton* m_remoteChangeButton;
+ KColorButton* m_notInCvsButton;
+ KColorButton* m_diffChangeButton;
+ KColorButton* m_diffInsertButton;
+ KColorButton* m_diffDeleteButton;
+
+ QCheckBox* m_splitterBox;
+ AdvancedPage* m_advancedPage;
+
+ KConfig* serviceConfig;
+};
+
+#endif
+
+
+// Local Variables:
+// c-basic-offset: 4
+// End:
diff --git a/cervisia/settingsdlg_advanced.ui b/cervisia/settingsdlg_advanced.ui
new file mode 100644
index 00000000..232c2678
--- /dev/null
+++ b/cervisia/settingsdlg_advanced.ui
@@ -0,0 +1,97 @@
+<!DOCTYPE UI><UI version="3.3" stdsetdef="1">
+<class>AdvancedPage</class>
+<widget class="QWidget">
+ <property name="name">
+ <cstring>advancedPage</cstring>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>575</width>
+ <height>290</height>
+ </rect>
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <spacer row="3" column="1">
+ <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>31</width>
+ <height>41</height>
+ </size>
+ </property>
+ </spacer>
+ <widget class="QLabel" row="0" column="0">
+ <property name="name">
+ <cstring>timeoutLbl</cstring>
+ </property>
+ <property name="text">
+ <string>&amp;Timeout after which a progress dialog appears (in ms):</string>
+ </property>
+ <property name="buddy" stdset="0">
+ <cstring>kcfg_Timeout</cstring>
+ </property>
+ </widget>
+ <widget class="QLabel" row="1" column="0">
+ <property name="name">
+ <cstring>compressionLbl</cstring>
+ </property>
+ <property name="text">
+ <string>Default compression &amp;level:</string>
+ </property>
+ <property name="buddy" stdset="0">
+ <cstring>kcfg_Compression</cstring>
+ </property>
+ </widget>
+ <widget class="QCheckBox" row="2" column="0" rowspan="1" colspan="2">
+ <property name="name">
+ <cstring>kcfg_UseSshAgent</cstring>
+ </property>
+ <property name="text">
+ <string>Utilize a running or start a new ssh-agent process</string>
+ </property>
+ </widget>
+ <widget class="KIntNumInput" row="1" column="1">
+ <property name="name">
+ <cstring>kcfg_Compression</cstring>
+ </property>
+ <property name="minValue">
+ <number>0</number>
+ </property>
+ <property name="maxValue">
+ <number>9</number>
+ </property>
+ </widget>
+ <widget class="KIntNumInput" row="0" column="1">
+ <property name="name">
+ <cstring>kcfg_Timeout</cstring>
+ </property>
+ <property name="minValue">
+ <number>0</number>
+ </property>
+ <property name="maxValue">
+ <number>50000</number>
+ </property>
+ </widget>
+ </grid>
+</widget>
+<layoutdefaults spacing="6" margin="0"/>
+<includehints>
+ <includehint>knuminput.h</includehint>
+ <includehint>knuminput.h</includehint>
+ <includehint>knuminput.h</includehint>
+ <includehint>knuminput.h</includehint>
+</includehints>
+</UI>
diff --git a/cervisia/stringmatcher.cpp b/cervisia/stringmatcher.cpp
new file mode 100644
index 00000000..1f0b4de8
--- /dev/null
+++ b/cervisia/stringmatcher.cpp
@@ -0,0 +1,146 @@
+/*
+ * Copyright (c) 2003-2007 André Wöbbeking <Woebbeking@kde.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the 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, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+
+#include "stringmatcher.h"
+
+// For some reason fnmatch is defined as ap_fnmatch
+#define ap_fnmatch fnmatch
+#include <fnmatch.h>
+
+
+namespace Cervisia
+{
+namespace
+{
+ const QChar asterix('*');
+ const QChar question('?');
+
+ inline bool isMetaCharacter(QChar c)
+ {
+ return c == asterix || c == question;
+ }
+
+
+ unsigned int countMetaCharacters(const QString& text);
+}
+
+
+bool StringMatcher::match(const QString& text) const
+{
+ if (m_exactPatterns.find(text) != m_exactPatterns.end())
+ {
+ return true;
+ }
+
+ for (QStringList::const_iterator it(m_startPatterns.begin()),
+ itEnd(m_startPatterns.end());
+ it != itEnd; ++it)
+ {
+ if (text.startsWith(*it))
+ {
+ return true;
+ }
+ }
+
+ for (QStringList::const_iterator it(m_endPatterns.begin()),
+ itEnd(m_endPatterns.end());
+ it != itEnd; ++it)
+ {
+ if (text.endsWith(*it))
+ {
+ return true;
+ }
+ }
+
+ for (QValueList<QCString>::const_iterator it(m_generalPatterns.begin()),
+ itEnd(m_generalPatterns.end());
+ it != itEnd; ++it)
+ {
+ if (::fnmatch(*it, text.local8Bit(), FNM_PATHNAME) == 0)
+ {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+
+void StringMatcher::add(const QString& pattern)
+{
+ if (pattern.isEmpty())
+ {
+ return;
+ }
+
+ const int lengthMinusOne(pattern.length() - 1);
+ switch (countMetaCharacters(pattern))
+ {
+ case 0:
+ m_exactPatterns.push_back(pattern);
+ break;
+
+ case 1:
+ if (pattern.constref(0) == asterix)
+ {
+ m_endPatterns.push_back(pattern.right(lengthMinusOne));
+ }
+ else if (pattern.constref(lengthMinusOne) == asterix)
+ {
+ m_startPatterns.push_back(pattern.left(lengthMinusOne));
+ }
+ else
+ {
+ m_generalPatterns.push_back(pattern.local8Bit());
+ }
+ break;
+
+ default:
+ m_generalPatterns.push_back(pattern.local8Bit());
+ break;
+ }
+}
+
+
+void StringMatcher::clear()
+{
+ m_exactPatterns.clear();
+ m_startPatterns.clear();
+ m_endPatterns.clear();
+ m_generalPatterns.clear();
+}
+
+
+namespace
+{
+unsigned int countMetaCharacters(const QString& text)
+{
+ unsigned int count(0);
+
+ const QChar* pos(text.unicode());
+ const QChar* posEnd(pos + text.length());
+ while (pos < posEnd)
+ {
+ count += isMetaCharacter(*pos++);
+ }
+
+ return count;
+}
+}
+} // namespace Cervisia
diff --git a/cervisia/stringmatcher.h b/cervisia/stringmatcher.h
new file mode 100644
index 00000000..17ecd3e8
--- /dev/null
+++ b/cervisia/stringmatcher.h
@@ -0,0 +1,77 @@
+/*
+ * Copyright (c) 2003-2007 André Wöbbeking <Woebbeking@kde.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the 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, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+
+#ifndef CERVISIA_STRINGMATCHER_H
+#define CERVISIA_STRINGMATCHER_H
+
+
+#include <qstringlist.h>
+
+
+namespace Cervisia
+{
+
+
+class StringMatcher
+{
+public:
+
+ /**
+ * @return \c true, if text matches one of the given patterns.
+ */
+ bool match(const QString& text) const;
+
+ /**
+ * Adds pattern \a pattern.
+ */
+ void add(const QString& pattern);
+
+ /**
+ * Removes all patterns.
+ */
+ void clear();
+
+private:
+
+ /**
+ * The patterns which are tested in match().
+ */
+ QStringList m_exactPatterns;
+
+ /**
+ * The patterns which are tested in match().
+ */
+ QStringList m_startPatterns;
+
+ /**
+ * The patterns which are tested in match().
+ */
+ QStringList m_endPatterns;
+
+ /**
+ * The patterns which are tested in match().
+ */
+ QValueList<QCString> m_generalPatterns;
+};
+
+
+} // namespace Cervisia
+
+
+#endif // CERVISIA_STRINGMATCHER_H
diff --git a/cervisia/tagdlg.cpp b/cervisia/tagdlg.cpp
new file mode 100644
index 00000000..2f1e7e89
--- /dev/null
+++ b/cervisia/tagdlg.cpp
@@ -0,0 +1,147 @@
+/*
+ * Copyright (C) 1999-2002 Bernd Gehrmann
+ * bernd@mail.berlios.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.
+ *
+ * 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, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+
+#include "tagdlg.h"
+
+#include <qcheckbox.h>
+#include <qcombobox.h>
+#include <qlabel.h>
+#include <qlayout.h>
+#include <qlineedit.h>
+#include <qpushbutton.h>
+#include <klocale.h>
+#include <kmessagebox.h>
+
+#include "misc.h"
+#include "cvsservice_stub.h"
+
+using Cervisia::TagDialog;
+
+TagDialog::TagDialog(ActionType action, CvsService_stub* service,
+ QWidget *parent, const char *name)
+ : KDialogBase(parent, name, true, QString::null,
+ Ok | Cancel | Help, Ok, true),
+ act(action),
+ cvsService(service),
+ branchtag_button(0),
+ forcetag_button(0)
+{
+ setCaption( (action==Delete)? i18n("CVS Delete Tag") : i18n("CVS Tag") );
+
+ QFrame* mainWidget = makeMainWidget();
+
+ QBoxLayout *layout = new QVBoxLayout(mainWidget, 0, spacingHint());
+
+ if (action == Delete)
+ {
+ tag_combo = new QComboBox(true, mainWidget);
+ tag_combo->setFocus();
+ tag_combo->setMinimumWidth(fontMetrics().width('0') * 30);
+
+ QLabel *tag_label = new QLabel(tag_combo, i18n("&Name of tag:"), mainWidget);
+
+ QPushButton *tag_button = new QPushButton(i18n("Fetch &List"), mainWidget);
+ connect( tag_button, SIGNAL(clicked()),
+ this, SLOT(tagButtonClicked()) );
+
+ QBoxLayout *tagedit_layout = new QHBoxLayout(layout);
+ tagedit_layout->addWidget(tag_label);
+ tagedit_layout->addWidget(tag_combo);
+ tagedit_layout->addWidget(tag_button);
+ }
+ else
+ {
+ tag_edit = new QLineEdit(mainWidget);
+ tag_edit->setFocus();
+ tag_edit->setMinimumWidth(fontMetrics().width('0') * 30);
+
+ QLabel *tag_label = new QLabel(tag_edit, i18n("&Name of tag:"), mainWidget);
+
+ QBoxLayout *tagedit_layout = new QHBoxLayout(layout);
+ tagedit_layout->addWidget(tag_label);
+ tagedit_layout->addWidget(tag_edit);
+
+ branchtag_button = new QCheckBox(i18n("Create &branch with this tag"), mainWidget);
+ layout->addWidget(branchtag_button);
+
+ forcetag_button = new QCheckBox(i18n("&Force tag creation even if tag already exists"), mainWidget);
+ layout->addWidget(forcetag_button);
+ }
+
+ setHelp("taggingbranching");
+}
+
+
+bool TagDialog::branchTag() const
+{
+ return branchtag_button && branchtag_button->isChecked();
+}
+
+
+bool TagDialog::forceTag() const
+{
+ return forcetag_button && forcetag_button->isChecked();
+}
+
+
+QString TagDialog::tag() const
+{
+ return act==Delete? tag_combo->currentText() : tag_edit->text();
+}
+
+
+void TagDialog::slotOk()
+{
+ QString const str(tag());
+
+ if (str.isEmpty())
+ {
+ KMessageBox::sorry(this,
+ i18n("You must define a tag name."),
+ "Cervisia");
+ return;
+ }
+
+ if (!Cervisia::IsValidTag(str))
+ {
+ KMessageBox::sorry(this,
+ i18n("Tag must start with a letter and may contain "
+ "letters, digits and the characters '-' and '_'."),
+ "Cervisia");
+ return;
+ }
+
+ KDialogBase::slotOk();
+}
+
+
+void TagDialog::tagButtonClicked()
+{
+ tag_combo->clear();
+ tag_combo->insertStringList(::fetchTags(cvsService, this));
+}
+
+
+#include "tagdlg.moc"
+
+
+// Local Variables:
+// c-basic-offset: 4
+// End:
diff --git a/cervisia/tagdlg.h b/cervisia/tagdlg.h
new file mode 100644
index 00000000..4d1e4754
--- /dev/null
+++ b/cervisia/tagdlg.h
@@ -0,0 +1,74 @@
+/*
+ * Copyright (C) 1999-2002 Bernd Gehrmann
+ * bernd@mail.berlios.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.
+ *
+ * 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, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+
+#ifndef TAGDLG_H
+#define TAGDLG_H
+
+
+#include <kdialogbase.h>
+
+
+class QCheckBox;
+class QComboBox;
+class QLineEdit;
+class CvsService_stub;
+
+namespace Cervisia
+{
+
+class TagDialog : public KDialogBase
+{
+ Q_OBJECT
+
+public:
+ enum ActionType { Create, Delete };
+
+ TagDialog( ActionType action, CvsService_stub* service,
+ QWidget *parent=0, const char *name=0 );
+
+ bool branchTag() const;
+ bool forceTag() const;
+ QString tag() const;
+
+protected:
+ virtual void slotOk();
+
+private slots:
+ void tagButtonClicked();
+
+private:
+ ActionType act;
+ CvsService_stub* cvsService;
+
+ QCheckBox *branchtag_button;
+ QCheckBox *forcetag_button;
+ QLineEdit *tag_edit;
+ QComboBox *tag_combo;
+};
+
+}
+
+
+#endif
+
+
+// Local Variables:
+// c-basic-offset: 4
+// End:
diff --git a/cervisia/tests/resolvedlg-BR74903-test-01.txt b/cervisia/tests/resolvedlg-BR74903-test-01.txt
new file mode 100644
index 00000000..c4b8a22f
--- /dev/null
+++ b/cervisia/tests/resolvedlg-BR74903-test-01.txt
@@ -0,0 +1,4 @@
+123
+<<<<<<< resolvedlg-BR74903-test-01.txt
+conf=======
+456>>>>>>> 1.2
diff --git a/cervisia/tests/resolvedlg-conflict-test-01.txt b/cervisia/tests/resolvedlg-conflict-test-01.txt
new file mode 100644
index 00000000..bbcd08c3
--- /dev/null
+++ b/cervisia/tests/resolvedlg-conflict-test-01.txt
@@ -0,0 +1,5 @@
+<<<<<<< resolvedlg-conflict-test-01.txt
+Line 1 - modified on CONFLICT_BRANCH
+=======
+Line 1 - modified on HEAD
+>>>>>>> 1.2
diff --git a/cervisia/tests/resolvedlg-conflict-test-02.txt b/cervisia/tests/resolvedlg-conflict-test-02.txt
new file mode 100644
index 00000000..5d72025e
--- /dev/null
+++ b/cervisia/tests/resolvedlg-conflict-test-02.txt
@@ -0,0 +1,9 @@
+Line 1
+Line 2
+<<<<<<< resolvedlg-conflict-test-02.txt
+Line 3 - modified on CONFLICT_BRANCH
+=======
+Line 3 - modified on HEAD
+>>>>>>> 1.2
+Line 4
+Line 5
diff --git a/cervisia/tooltip.cpp b/cervisia/tooltip.cpp
new file mode 100644
index 00000000..7debf9d7
--- /dev/null
+++ b/cervisia/tooltip.cpp
@@ -0,0 +1,111 @@
+/*
+ * Copyright (c) 2004-2007 André Wöbbeking <Woebbeking@kde.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the 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, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+
+#include "tooltip.h"
+
+#include <kglobal.h>
+#include <kglobalsettings.h>
+
+#include <qsimplerichtext.h>
+
+
+namespace Cervisia
+{
+
+
+static QString truncateLines(const QString&, const QFontMetrics&, const QSize&);
+static QString truncateLines(const QString&, const QFont&, const QPoint&, const QRect&);
+
+
+ToolTip::ToolTip(QWidget* widget)
+ : QObject(widget), QToolTip(widget)
+{
+}
+
+
+void ToolTip::maybeTip(const QPoint& pos)
+{
+ QRect rect;
+ QString text;
+ emit queryToolTip(pos, rect, text);
+
+ if (rect.isValid() && !text.isEmpty())
+ {
+ text = truncateLines(text,
+ font(),
+ parentWidget()->mapToGlobal(pos),
+ KGlobalSettings::desktopGeometry(parentWidget()));
+ tip(rect, text);
+ }
+}
+
+
+// Primtive routine to truncate the text. size.width() is ignored, only
+// size.height() is used at the moment to keep it fast. It doesn't work
+// correct if text lines have different heights.
+QString truncateLines(const QString& text,
+ const QFontMetrics& fm,
+ const QSize& size)
+{
+ const QChar newLine('\n');
+
+ const int lineSpacing(fm.lineSpacing());
+ const int numberOfLines(text.contains(newLine) + 1);
+ const int maxNumberOfLines(size.height() / lineSpacing);
+
+ if (numberOfLines <= maxNumberOfLines)
+ return text;
+
+ const QChar* unicode(text.unicode());
+ for (int count(maxNumberOfLines); count; ++unicode)
+ if (*unicode == newLine)
+ --count;
+
+ return text.left(unicode - text.unicode() - 1);
+}
+
+
+// Truncate the tooltip's text if necessary
+QString truncateLines(const QString& text,
+ const QFont& font,
+ const QPoint& globalPos,
+ const QRect& desktopGeometry)
+{
+ // maximum size of the tooltip, - 10 just to be safe
+ const int maxWidth(kMax(desktopGeometry.width() - globalPos.x(), globalPos.x())
+ - desktopGeometry.left() - 10);
+ const int maxHeight(kMax(desktopGeometry.height() - globalPos.y(), globalPos.y())
+ - desktopGeometry.top() - 10);
+
+ // calculate the tooltip's size
+ const QSimpleRichText layoutedText(text, font);
+
+ // only if the tooltip's size is bigger in x- and y-direction the text must
+ // be truncated otherwise the tip is moved to a position where it fits
+ return ((layoutedText.widthUsed() > maxWidth)
+ && (layoutedText.height() > maxHeight))
+ ? truncateLines(text, QFontMetrics(font), QSize(maxWidth, maxHeight))
+ : text;
+}
+
+
+} // namespace Cervisia
+
+
+#include "tooltip.moc"
diff --git a/cervisia/tooltip.h b/cervisia/tooltip.h
new file mode 100644
index 00000000..fc0cd7be
--- /dev/null
+++ b/cervisia/tooltip.h
@@ -0,0 +1,75 @@
+/*
+ * Copyright (c) 2004-2007 André Wöbbeking <Woebbeking@kde.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the 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, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+
+#ifndef CERVISIA_TOOLTIP_H
+#define CERVISIA_TOOLTIP_H
+
+
+#include <qobject.h>
+#include <qtooltip.h>
+
+
+namespace Cervisia
+{
+
+
+/**
+ * This class extends QToolTip:
+ * - no more need to subclass just connect to the signal queryToolTip()
+ * - truncate too large tooltip texts.
+ */
+class ToolTip : public QObject, public QToolTip
+{
+ Q_OBJECT
+
+public:
+
+ /**
+ * @param widget The widget you want to add tooltips to. It's also used as
+ * parent for the QObject. So you don't have to free an instance of this
+ * class yourself.
+ */
+ explicit ToolTip(QWidget* widget);
+
+signals:
+
+ /**
+ * This signal is emitted when a tooltip could be displayed. When a client
+ * wants to display anythink it must set a valid tooltip rectangle and a
+ * non empty text.
+ *
+ * @param pos The position of the tooltip in the parent widget's coordinate system.
+ *
+ * @param rect The rectangle in the parent widget's coordinate system where the
+ * tooltip is valid.
+ *
+ * @param text The tooltip text.
+ */
+ void queryToolTip(const QPoint& pos, QRect& rect, QString& text);
+
+protected:
+
+ virtual void maybeTip(const QPoint&);
+};
+
+
+} // namespace Cervisia
+
+
+#endif // CERVISIA_TOOLTIP_H
diff --git a/cervisia/updatedlg.cpp b/cervisia/updatedlg.cpp
new file mode 100644
index 00000000..9a536763
--- /dev/null
+++ b/cervisia/updatedlg.cpp
@@ -0,0 +1,161 @@
+/*
+ * Copyright (C) 1999-2002 Bernd Gehrmann
+ * bernd@mail.berlios.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.
+ *
+ * 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, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+
+#include "updatedlg.h"
+
+#include <qbuttongroup.h>
+#include <qcombobox.h>
+#include <qlayout.h>
+#include <qpushbutton.h>
+#include <qradiobutton.h>
+#include <qstyle.h>
+#include <klineedit.h>
+#include <klocale.h>
+
+#include "misc.h"
+#include "cvsservice_stub.h"
+
+
+UpdateDialog::UpdateDialog(CvsService_stub* service,
+ QWidget *parent, const char *name)
+ : KDialogBase(parent, name, true, i18n("CVS Update"),
+ Ok | Cancel, Ok, true),
+ cvsService(service)
+{
+ int const iComboBoxMinWidth(40 * fontMetrics().width('0'));
+ int const iWidgetIndent(style().pixelMetric(QStyle::PM_ExclusiveIndicatorWidth, 0) + 6);
+
+ QFrame* mainWidget = makeMainWidget();
+
+ QBoxLayout *layout = new QVBoxLayout(mainWidget, 0, spacingHint());
+
+ bybranch_button = new QRadioButton(i18n("Update to &branch: "), mainWidget);
+ bybranch_button->setChecked(true);
+ layout->addWidget(bybranch_button);
+
+ branch_combo = new QComboBox(true, mainWidget);
+ branch_combo->setMinimumWidth(iComboBoxMinWidth);
+
+ branch_button = new QPushButton(i18n("Fetch &List"), mainWidget);
+ connect( branch_button, SIGNAL(clicked()),
+ this, SLOT(branchButtonClicked()) );
+
+ QBoxLayout *branchedit_layout = new QHBoxLayout(layout);
+ branchedit_layout->addSpacing(iWidgetIndent);
+ branchedit_layout->addWidget(branch_combo);
+ branchedit_layout->addWidget(branch_button);
+
+ bytag_button = new QRadioButton(i18n("Update to &tag: "), mainWidget);
+ layout->addWidget(bytag_button);
+
+ tag_combo = new QComboBox(true, mainWidget);
+ tag_combo->setMinimumWidth(iComboBoxMinWidth);
+
+ tag_button = new QPushButton(i18n("Fetch L&ist"), mainWidget);
+ connect( tag_button, SIGNAL(clicked()),
+ this, SLOT(tagButtonClicked()) );
+
+ QBoxLayout *tagedit_layout = new QHBoxLayout(layout);
+ tagedit_layout->addSpacing(iWidgetIndent);
+ tagedit_layout->addWidget(tag_combo);
+ tagedit_layout->addWidget(tag_button);
+
+ bydate_button = new QRadioButton(i18n("Update to &date ('yyyy-mm-dd'):"), mainWidget);
+ layout->addWidget(bydate_button);
+
+ date_edit = new KLineEdit(mainWidget);
+
+ QBoxLayout *dateedit_layout = new QHBoxLayout(layout);
+ dateedit_layout->addSpacing(iWidgetIndent);
+ dateedit_layout->addWidget(date_edit);
+
+ QButtonGroup* group = new QButtonGroup(mainWidget);
+ group->hide();
+ group->insert(bytag_button);
+ group->insert(bybranch_button);
+ group->insert(bydate_button);
+ connect( group, SIGNAL(clicked(int)),
+ this, SLOT(toggled()) );
+
+ // dis-/enable the widgets
+ toggled();
+}
+
+
+bool UpdateDialog::byTag() const
+{
+ return bybranch_button->isChecked() || bytag_button->isChecked();
+}
+
+
+QString UpdateDialog::tag() const
+{
+ return bybranch_button->isChecked()
+ ? branch_combo->currentText()
+ : tag_combo->currentText();
+}
+
+
+QString UpdateDialog::date() const
+{
+ return date_edit->text();
+}
+
+
+void UpdateDialog::tagButtonClicked()
+{
+ tag_combo->clear();
+ tag_combo->insertStringList(::fetchTags(cvsService, this));
+}
+
+
+void UpdateDialog::branchButtonClicked()
+{
+ branch_combo->clear();
+ branch_combo->insertStringList(::fetchBranches(cvsService, this));
+}
+
+
+void UpdateDialog::toggled()
+{
+ bool bytag = bytag_button->isChecked();
+ tag_combo->setEnabled(bytag);
+ tag_button->setEnabled(bytag);
+ if (bytag)
+ tag_combo->setFocus();
+
+ bool bybranch = bybranch_button->isChecked();
+ branch_combo->setEnabled(bybranch);
+ branch_button->setEnabled(bybranch);
+ if (bybranch)
+ branch_combo->setFocus();
+
+ bool bydate = bydate_button->isChecked();
+ date_edit->setEnabled(bydate);
+ if (bydate)
+ date_edit->setFocus();
+}
+
+#include "updatedlg.moc"
+
+
+// Local Variables:
+// c-basic-offset: 4
+// End:
diff --git a/cervisia/updatedlg.h b/cervisia/updatedlg.h
new file mode 100644
index 00000000..2ce143cf
--- /dev/null
+++ b/cervisia/updatedlg.h
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 1999-2002 Bernd Gehrmann
+ * bernd@mail.berlios.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.
+ *
+ * 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, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+
+#ifndef UPDATEDLG_H
+#define UPDATEDLG_H
+
+
+#include <kdialogbase.h>
+
+
+class QComboBox;
+class QPushButton;
+class QRadioButton;
+class KLineEdit;
+class CvsService_stub;
+
+
+class UpdateDialog : public KDialogBase
+{
+ Q_OBJECT
+
+public:
+ UpdateDialog( CvsService_stub* service,
+ QWidget *parent=0, const char *name=0 );
+
+ bool byTag() const;
+ QString tag() const;
+ QString date() const;
+
+private slots:
+ void toggled();
+ void tagButtonClicked();
+ void branchButtonClicked();
+
+private:
+ CvsService_stub* cvsService;
+
+ QRadioButton *bytag_button, *bybranch_button, *bydate_button;
+ QComboBox *tag_combo, *branch_combo;
+ QPushButton *tag_button, *branch_button;
+ KLineEdit *date_edit;
+};
+
+#endif
+
+
+// Local Variables:
+// c-basic-offset: 4
+// End:
diff --git a/cervisia/updateview.cpp b/cervisia/updateview.cpp
new file mode 100644
index 00000000..94679f6c
--- /dev/null
+++ b/cervisia/updateview.cpp
@@ -0,0 +1,629 @@
+/*
+ * Copyright (C) 1999-2002 Bernd Gehrmann <bernd@mail.berlios.de>
+ * Copyright (c) 2003-2007 André Wöbbeking <Woebbeking@kde.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the 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, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+
+#include "updateview.h"
+
+#include <set>
+
+#include <qapplication.h>
+#include <qfileinfo.h>
+#include <qptrstack.h>
+#include <kconfig.h>
+#include <klocale.h>
+
+#include "cervisiasettings.h"
+#include "entry.h"
+#include "updateview_items.h"
+#include "updateview_visitors.h"
+
+
+using Cervisia::Entry;
+using Cervisia::EntryStatus;
+
+
+UpdateView::UpdateView(KConfig& partConfig, QWidget *parent, const char *name)
+ : KListView(parent, name),
+ m_partConfig(partConfig),
+ m_unfoldingTree(false)
+{
+ setAllColumnsShowFocus(true);
+ setShowSortIndicator(true);
+ setSelectionModeExt(Extended);
+
+ addColumn(i18n("File Name"), 280);
+ addColumn(i18n("File Type"), 180);
+ addColumn(i18n("Status"), 90);
+ addColumn(i18n("Revision"), 70);
+ addColumn(i18n("Tag/Date"), 90);
+ addColumn(i18n("Timestamp"), 120);
+
+ setFilter(NoFilter);
+
+ connect( this, SIGNAL(doubleClicked(QListViewItem*)),
+ this, SLOT(itemExecuted(QListViewItem*)) );
+ connect( this, SIGNAL(returnPressed(QListViewItem*)),
+ this, SLOT(itemExecuted(QListViewItem*)) );
+
+ // without this restoreLayout() can't change the column widths
+ for (int col = 0; col < columns(); ++col)
+ setColumnWidthMode(col, QListView::Manual);
+
+ restoreLayout(&m_partConfig, QString::fromLatin1("UpdateView"));
+}
+
+
+UpdateView::~UpdateView()
+{
+ saveLayout(&m_partConfig, QString::fromLatin1("UpdateView"));
+}
+
+
+void UpdateView::setFilter(Filter filter)
+{
+ filt = filter;
+
+ if (UpdateDirItem* item = static_cast<UpdateDirItem*>(firstChild()))
+ {
+ ApplyFilterVisitor applyFilterVisitor(filter);
+ item->accept(applyFilterVisitor);
+ }
+
+ setSorting(columnSorted(), ascendingSort());
+}
+
+
+UpdateView::Filter UpdateView::filter() const
+{
+ return filt;
+}
+
+
+// returns true iff exactly one UpdateFileItem is selected
+bool UpdateView::hasSingleSelection() const
+{
+ const QPtrList<QListViewItem>& listSelectedItems(selectedItems());
+
+ return (listSelectedItems.count() == 1) && isFileItem(listSelectedItems.getFirst());
+}
+
+
+void UpdateView::getSingleSelection(QString *filename, QString *revision) const
+{
+ const QPtrList<QListViewItem>& listSelectedItems(selectedItems());
+
+ QString tmpFileName;
+ QString tmpRevision;
+ if ((listSelectedItems.count() == 1) && isFileItem(listSelectedItems.getFirst()))
+ {
+ UpdateFileItem* fileItem(static_cast<UpdateFileItem*>(listSelectedItems.getFirst()));
+ tmpFileName = fileItem->filePath();
+ tmpRevision = fileItem->entry().m_revision;
+ }
+
+ *filename = tmpFileName;
+ if (revision)
+ *revision = tmpRevision;
+}
+
+
+QStringList UpdateView::multipleSelection() const
+{
+ QStringList res;
+
+ const QPtrList<QListViewItem>& listSelectedItems(selectedItems());
+ for (QPtrListIterator<QListViewItem> it(listSelectedItems);
+ it.current() != 0; ++it)
+ {
+ if ((*it)->isVisible())
+ res.append(static_cast<UpdateItem*>(*it)->filePath());
+ }
+
+ return res;
+}
+
+
+QStringList UpdateView::fileSelection() const
+{
+ QStringList res;
+
+ const QPtrList<QListViewItem>& listSelectedItems(selectedItems());
+ for (QPtrListIterator<QListViewItem> it(listSelectedItems);
+ it.current() != 0; ++it)
+ {
+ QListViewItem* item(*it);
+
+ if (isFileItem(item) && item->isVisible())
+ res.append(static_cast<UpdateFileItem*>(item)->filePath());
+ }
+
+ return res;
+}
+
+
+const QColor& UpdateView::conflictColor() const
+{
+ return m_conflictColor;
+}
+
+
+const QColor& UpdateView::localChangeColor() const
+{
+ return m_localChangeColor;
+}
+
+
+const QColor& UpdateView::remoteChangeColor() const
+{
+ return m_remoteChangeColor;
+}
+
+
+const QColor& UpdateView::notInCvsColor() const
+{
+ return m_notInCvsColor;
+}
+
+
+bool UpdateView::isUnfoldingTree() const
+{
+ return m_unfoldingTree;
+}
+
+
+// updates internal data
+void UpdateView::replaceItem(QListViewItem* oldItem,
+ QListViewItem* newItem)
+{
+ const int index(relevantSelection.find(oldItem));
+ if (index >= 0)
+ relevantSelection.replace(index, newItem);
+}
+
+
+void UpdateView::unfoldSelectedFolders()
+{
+ QApplication::setOverrideCursor(waitCursor);
+
+ int previousDepth = 0;
+ bool isUnfolded = false;
+
+ QStringList selection = multipleSelection();
+
+ // setup name of selected folder
+ QString selectedItem = selection.first();
+ if( selectedItem.contains('/') )
+ selectedItem.remove(0, selectedItem.findRev('/')+1);
+
+ // avoid flicker
+ const bool updatesEnabled = isUpdatesEnabled();
+ setUpdatesEnabled(false);
+
+ QListViewItemIterator it(this);
+ while( QListViewItem* item = it.current() )
+ {
+ if( isDirItem(item) )
+ {
+ UpdateDirItem* dirItem = static_cast<UpdateDirItem*>(item);
+
+ // below selected folder?
+ if( previousDepth && dirItem->depth() > previousDepth )
+ {
+ // if this dir wasn't scanned already scan it recursive
+ // (this is only a hack to reduce the processEvents() calls,
+ // setOpen() would scan the dir too)
+ if (dirItem->wasScanned() == false)
+ {
+ const bool recursive = true;
+ dirItem->maybeScanDir(recursive);
+
+ // scanning can take some time so keep the gui alive
+ qApp->processEvents();
+ }
+
+ dirItem->setOpen(!isUnfolded);
+ }
+ // selected folder?
+ else if( selectedItem == dirItem->entry().m_name )
+ {
+ previousDepth = dirItem->depth();
+ isUnfolded = dirItem->isOpen();
+
+ // if this dir wasn't scanned already scan it recursive
+ // (this is only a hack to reduce the processEvents() calls,
+ // setOpen() would scan the dir too)
+ if (dirItem->wasScanned() == false)
+ {
+ const bool recursive = true;
+ dirItem->maybeScanDir(recursive);
+
+ // scanning can take some time so keep the gui alive
+ qApp->processEvents();
+ }
+
+ dirItem->setOpen(!isUnfolded);
+ }
+ // back to the level of the selected folder or above?
+ else if( previousDepth && dirItem->depth() >= previousDepth )
+ {
+ previousDepth = 0;
+ }
+ }
+
+ ++it;
+ }
+
+ // maybe some UpdateDirItem was opened the first time so check the whole tree
+ setFilter(filter());
+
+ setUpdatesEnabled(updatesEnabled);
+ triggerUpdate();
+
+ QApplication::restoreOverrideCursor();
+}
+
+
+void UpdateView::unfoldTree()
+{
+ QApplication::setOverrideCursor(waitCursor);
+
+ m_unfoldingTree = true;
+
+ const bool updatesEnabled(isUpdatesEnabled());
+
+ setUpdatesEnabled(false);
+
+ QListViewItemIterator it(this);
+ while (QListViewItem* item = it.current())
+ {
+ if (isDirItem(item))
+ {
+ UpdateDirItem* dirItem(static_cast<UpdateDirItem*>(item));
+
+ // if this dir wasn't scanned already scan it recursive
+ // (this is only a hack to reduce the processEvents() calls,
+ // setOpen() would scan the dir too)
+ if (dirItem->wasScanned() == false)
+ {
+ const bool recursive(true);
+ dirItem->maybeScanDir(recursive);
+
+ // scanning can take some time so keep the gui alive
+ qApp->processEvents();
+ }
+
+ dirItem->setOpen(true);
+ }
+
+ ++it;
+ }
+
+ // maybe some UpdateDirItem was opened the first time so check the whole tree
+ setFilter(filter());
+
+ setUpdatesEnabled(updatesEnabled);
+
+ triggerUpdate();
+
+ m_unfoldingTree = false;
+
+ QApplication::restoreOverrideCursor();
+}
+
+
+void UpdateView::foldTree()
+{
+ QListViewItemIterator it(this);
+ while (QListViewItem* item = it.current())
+ {
+ // don't close the top level directory
+ if (isDirItem(item) && item->parent())
+ item->setOpen(false);
+
+ ++it;
+ }
+}
+
+
+/**
+ * Clear the tree view and insert the directory dirname
+ * into it as the new root item
+ */
+void UpdateView::openDirectory(const QString& dirName)
+{
+ clear();
+
+ // do this each time as the configuration could be changed
+ updateColors();
+
+ Entry entry;
+ entry.m_name = dirName;
+ entry.m_type = Entry::Dir;
+
+ UpdateDirItem *item = new UpdateDirItem(this, entry);
+ item->setOpen(true);
+ setCurrentItem(item);
+ setSelected(item, true);
+}
+
+
+/**
+ * Start a job. We want to be able to change the status field
+ * correctly afterwards, so we have to remember the current
+ * selection (which the user may change during the update).
+ * In the recursive case, we collect all relevant directories.
+ * Furthermore, we have to change the items to undefined state.
+ */
+void UpdateView::prepareJob(bool recursive, Action action)
+{
+ act = action;
+
+ // Scan recursively all entries - there's no way around this here
+ if (recursive)
+ static_cast<UpdateDirItem*>(firstChild())->maybeScanDir(true);
+
+ rememberSelection(recursive);
+ if (act != Add)
+ markUpdated(false, false);
+}
+
+
+/**
+ * Finishes a job. What we do depends a bit on
+ * whether the command was successful or not.
+ */
+void UpdateView::finishJob(bool normalExit, int exitStatus)
+{
+ // cvs exitStatus == 1 only means that there're conflicts
+ const bool success(normalExit && (exitStatus == 0 || exitStatus == 1));
+ if (act != Add)
+ markUpdated(true, success);
+ syncSelection();
+
+ // maybe some new items were created or
+ // visibility of items changed so check the whole tree
+ setFilter(filter());
+}
+
+
+/**
+ * Marking non-selected items in a directory updated (as a consequence
+ * of not appearing in 'cvs update' output) is done in two steps: In the
+ * first, they are marked as 'indefinite', so that their status on the screen
+ * isn't misrepresented. In the second step, they are either set
+ * to 'UpToDate' (success=true) or 'Unknown'.
+ */
+void UpdateView::markUpdated(bool laststage, bool success)
+{
+ QPtrListIterator<QListViewItem> it(relevantSelection);
+ for ( ; it.current(); ++it)
+ if (isDirItem(it.current()))
+ {
+ for (QListViewItem *item = it.current()->firstChild(); item;
+ item = item->nextSibling() )
+ if (isFileItem(item))
+ {
+ UpdateFileItem* fileItem = static_cast<UpdateFileItem*>(item);
+ fileItem->markUpdated(laststage, success);
+ }
+ }
+ else
+ {
+ UpdateFileItem* fileItem = static_cast<UpdateFileItem*>(it.current());
+ fileItem->markUpdated(laststage, success);
+ }
+}
+
+
+/**
+ * Remember the selection, see prepareJob()
+ */
+void UpdateView::rememberSelection(bool recursive)
+{
+ std::set<QListViewItem*> setItems;
+ for (QListViewItemIterator it(this); it.current(); ++it)
+ {
+ QListViewItem* item(it.current());
+
+ // if this item is selected and if it was not inserted already
+ // and if we work recursive and if it is a dir item then insert
+ // all sub dirs
+ // DON'T CHANGE TESTING ORDER
+ if (item->isSelected()
+ && setItems.insert(item).second
+ && recursive
+ && isDirItem(item))
+ {
+ QPtrStack<QListViewItem> s;
+ for (QListViewItem* childItem = item->firstChild(); childItem;
+ childItem = childItem->nextSibling() ? childItem->nextSibling() : s.pop())
+ {
+ // if this item is a dir item and if it is was not
+ // inserted already then insert all sub dirs
+ // DON'T CHANGE TESTING ORDER
+ if (isDirItem(childItem) && setItems.insert(childItem).second)
+ {
+ if (QListViewItem* childChildItem = childItem->firstChild())
+ s.push(childChildItem);
+ }
+ }
+ }
+ }
+
+ // Copy the set to the list
+ relevantSelection.clear();
+ std::set<QListViewItem*>::const_iterator const itItemEnd = setItems.end();
+ for (std::set<QListViewItem*>::const_iterator itItem = setItems.begin();
+ itItem != itItemEnd; ++itItem)
+ relevantSelection.append(*itItem);
+
+#if 0
+ DEBUGOUT("Relevant:");
+ QPtrListIterator<QListViewItem> it44(relevantSelection);
+ for (; it44.current(); ++it44)
+ DEBUGOUT(" " << (*it44)->text(UpdateFileItem::File));
+ DEBUGOUT("End");
+#endif
+}
+
+
+/**
+ * Use the remembered selection to resynchronize
+ * with the actual directory and Entries content.
+ */
+void UpdateView::syncSelection()
+{
+ // compute all directories which are selected or contain a selected file
+ // (in recursive mode this includes all sub directories)
+ std::set<UpdateDirItem*> setDirItems;
+ for (QPtrListIterator<QListViewItem> itItem(relevantSelection);
+ itItem.current(); ++itItem)
+ {
+ QListViewItem* item(itItem.current());
+
+ UpdateDirItem* dirItem(0);
+ if (isDirItem(item))
+ dirItem = static_cast<UpdateDirItem*>(item);
+ else if (QListViewItem* parentItem = item->parent())
+ dirItem = static_cast<UpdateDirItem*>(parentItem);
+
+ if (dirItem)
+ setDirItems.insert(dirItem);
+ }
+
+ QApplication::setOverrideCursor(waitCursor);
+
+ std::set<UpdateDirItem*>::const_iterator const itDirItemEnd = setDirItems.end();
+ for (std::set<UpdateDirItem*>::const_iterator itDirItem = setDirItems.begin();
+ itDirItem != itDirItemEnd; ++itDirItem)
+ {
+ UpdateDirItem* dirItem = *itDirItem;
+
+ dirItem->syncWithDirectory();
+ dirItem->syncWithEntries();
+
+ qApp->processEvents();
+ }
+
+ QApplication::restoreOverrideCursor();
+}
+
+
+/**
+ * Get the colors from the configuration each time the list view items
+ * are created.
+ */
+void UpdateView::updateColors()
+{
+ KConfigGroupSaver cs(&m_partConfig, "Colors");
+ m_partConfig.setGroup("Colors");
+
+ QColor defaultColor = QColor(255, 130, 130);
+ m_conflictColor = m_partConfig.readColorEntry("Conflict", &defaultColor);
+
+ defaultColor = QColor(130, 130, 255);
+ m_localChangeColor = m_partConfig.readColorEntry("LocalChange", &defaultColor);
+
+ defaultColor = QColor(70, 210, 70);
+ m_remoteChangeColor = m_partConfig.readColorEntry("RemoteChange", &defaultColor);
+
+ m_notInCvsColor = CervisiaSettings::notInCvsColor();
+}
+
+
+/**
+ * Process one line from the output of 'cvs update'. If parseAsStatus
+ * is true, it is assumed that the output is from a command
+ * 'cvs update -n', i.e. cvs actually changes no files.
+ */
+void UpdateView::processUpdateLine(QString str)
+{
+ if (str.length() > 2 && str[1] == ' ')
+ {
+ EntryStatus status(Cervisia::Unknown);
+ switch (str[0].latin1())
+ {
+ case 'C':
+ status = Cervisia::Conflict;
+ break;
+ case 'A':
+ status = Cervisia::LocallyAdded;
+ break;
+ case 'R':
+ status = Cervisia::LocallyRemoved;
+ break;
+ case 'M':
+ status = Cervisia::LocallyModified;
+ break;
+ case 'U':
+ status = (act == UpdateNoAct) ? Cervisia::NeedsUpdate : Cervisia::Updated;
+ break;
+ case 'P':
+ status = (act == UpdateNoAct) ? Cervisia::NeedsPatch : Cervisia::Patched;
+ break;
+ case '?':
+ status = Cervisia::NotInCVS;
+ break;
+ default:
+ return;
+ }
+ updateItem(str.mid(2), status, false);
+ }
+
+ const QString removedFileStart(QString::fromLatin1("cvs server: "));
+ const QString removedFileEnd(QString::fromLatin1(" is no longer in the repository"));
+ if (str.startsWith(removedFileStart) && str.endsWith(removedFileEnd))
+ {
+ }
+
+#if 0
+ else if (str.left(21) == "cvs server: Updating " ||
+ str.left(21) == "cvs update: Updating ")
+ updateItem(str.right(str.length()-21), Unknown, true);
+#endif
+}
+
+
+void UpdateView::updateItem(const QString& filePath, EntryStatus status, bool isdir)
+{
+ if (isdir && filePath == QChar('.'))
+ return;
+
+ const QFileInfo fileInfo(filePath);
+
+ UpdateDirItem* rootItem = static_cast<UpdateDirItem*>(firstChild());
+ UpdateDirItem* dirItem = findOrCreateDirItem(fileInfo.dirPath(), rootItem);
+
+ dirItem->updateChildItem(fileInfo.fileName(), status, isdir);
+}
+
+
+void UpdateView::itemExecuted(QListViewItem *item)
+{
+ if (isFileItem(item))
+ emit fileOpened(static_cast<UpdateFileItem*>(item)->filePath());
+}
+
+
+#include "updateview.moc"
+
+
+// Local Variables:
+// c-basic-offset: 4
+// End:
diff --git a/cervisia/updateview.h b/cervisia/updateview.h
new file mode 100644
index 00000000..d01446a9
--- /dev/null
+++ b/cervisia/updateview.h
@@ -0,0 +1,117 @@
+/*
+ * Copyright (C) 1999-2002 Bernd Gehrmann <bernd@mail.berlios.de>
+ * Copyright (c) 2003-2007 André Wöbbeking <Woebbeking@kde.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the 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, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+
+#ifndef UPDATEVIEW_H
+#define UPDATEVIEW_H
+
+
+#include <klistview.h>
+
+#include <qptrlist.h>
+
+#include "entry.h"
+
+
+class KConfig;
+
+
+class UpdateView : public KListView
+{
+ Q_OBJECT
+
+public:
+
+ enum Filter { NoFilter=0, OnlyDirectories=1, NoUpToDate=2,
+ NoRemoved=4, NoNotInCVS=8 , NoEmptyDirectories = 16 };
+ enum Action { Add, Remove, Update, UpdateNoAct, Commit };
+
+ explicit UpdateView(KConfig& partConfig, QWidget *parent=0, const char *name=0);
+
+ virtual ~UpdateView();
+
+ void setFilter(Filter filter);
+ Filter filter() const;
+
+ bool hasSingleSelection() const;
+ void getSingleSelection(QString *filename, QString *revision=0) const;
+ /* Returns a list of all marked files and directories */
+ QStringList multipleSelection() const;
+ /* Returns a list of all marked files, excluding directories*/
+ QStringList fileSelection() const;
+
+ void openDirectory(const QString& dirname);
+ void prepareJob(bool recursive, Action action);
+
+ const QColor& conflictColor() const;
+ const QColor& localChangeColor() const;
+ const QColor& remoteChangeColor() const;
+ const QColor& notInCvsColor() const;
+
+ /**
+ * @return \c true iff unfoldTree() is active.
+ */
+ bool isUnfoldingTree() const;
+
+ void replaceItem(QListViewItem*, QListViewItem*);
+
+signals:
+ void fileOpened(QString filename);
+
+public slots:
+ void unfoldSelectedFolders();
+ void unfoldTree();
+ void foldTree();
+ void finishJob(bool normalExit, int exitStatus);
+ void processUpdateLine(QString line);
+
+private slots:
+ void itemExecuted(QListViewItem *item);
+
+private:
+ void updateItem(const QString &filename, Cervisia::EntryStatus status, bool isdir);
+ void rememberSelection(bool recursive);
+ void syncSelection();
+ void markUpdated(bool laststage, bool success);
+
+ void updateColors();
+
+ KConfig& m_partConfig;
+
+ Filter filt;
+ Action act;
+ QPtrList<QListViewItem> relevantSelection;
+
+ QColor m_conflictColor;
+ QColor m_localChangeColor;
+ QColor m_remoteChangeColor;
+ QColor m_notInCvsColor;
+
+ /**
+ * \c true iff unfoldTree() is active (is needed by UpdateDirItem::setOpen()).
+ */
+ bool m_unfoldingTree;
+};
+
+#endif
+
+
+// Local Variables:
+// c-basic-offset: 4
+// End:
diff --git a/cervisia/updateview_items.cpp b/cervisia/updateview_items.cpp
new file mode 100644
index 00000000..76223c24
--- /dev/null
+++ b/cervisia/updateview_items.cpp
@@ -0,0 +1,826 @@
+/*
+ * Copyright (C) 1999-2002 Bernd Gehrmann <bernd@mail.berlios.de>
+ * Copyright (c) 2003-2007 André Wöbbeking <Woebbeking@kde.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the 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, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+
+#include "updateview_items.h"
+
+#include <cassert>
+
+#include <qdir.h>
+#include <qpainter.h>
+#include <qregexp.h>
+
+#include <kdebug.h>
+#include <kglobalsettings.h>
+#include <kiconloader.h>
+#include <klocale.h>
+#include <kmimetype.h>
+
+#include "cvsdir.h"
+#include "entry.h"
+#include "misc.h"
+#include "updateview_visitors.h"
+
+
+using Cervisia::Entry;
+using Cervisia::EntryStatus;
+
+
+// ------------------------------------------------------------------------------
+// UpdateItem
+// ------------------------------------------------------------------------------
+
+
+QString UpdateItem::dirPath() const
+{
+ QString path;
+
+ const UpdateItem* item = static_cast<UpdateItem*>(parent());
+ while (item)
+ {
+ const UpdateItem* parentItem = static_cast<UpdateItem*>(item->parent());
+ if (parentItem)
+ {
+ path.prepend(item->m_entry.m_name + QDir::separator());
+ }
+
+ item = parentItem;
+ }
+
+ return path;
+}
+
+
+QString UpdateItem::filePath() const
+{
+ // the filePath of the root item is '.'
+ return parent() ? dirPath() + m_entry.m_name : QChar('.');
+}
+
+
+// ------------------------------------------------------------------------------
+// UpdateDirItem
+// ------------------------------------------------------------------------------
+
+
+UpdateDirItem::UpdateDirItem(UpdateDirItem* parent,
+ const Entry& entry)
+ : UpdateItem(parent, entry),
+ m_opened(false)
+{
+ setExpandable(true);
+ setPixmap(0, SmallIcon("folder"));
+}
+
+
+UpdateDirItem::UpdateDirItem(UpdateView* parent,
+ const Entry& entry)
+ : UpdateItem(parent, entry),
+ m_opened(false)
+{
+ setExpandable(true);
+ setPixmap(0, SmallIcon("folder"));
+}
+
+
+/**
+ * Update the status of an item; if it doesn't exist yet, create new one
+ */
+void UpdateDirItem::updateChildItem(const QString& name,
+ EntryStatus status,
+ bool isdir)
+{
+ if (UpdateItem* item = findItem(name))
+ {
+ if (isFileItem(item))
+ {
+ UpdateFileItem* fileItem = static_cast<UpdateFileItem*>(item);
+ fileItem->setStatus(status);
+ }
+ return;
+ }
+
+ // Not found, make new entry
+ Entry entry;
+ entry.m_name = name;
+ if (isdir)
+ {
+ entry.m_type = Entry::Dir;
+ createDirItem(entry)->maybeScanDir(true);
+ }
+ else
+ {
+ entry.m_type = Entry::File;
+ createFileItem(entry)->setStatus(status);
+ }
+}
+
+
+/**
+ * Update the revision and tag of an item. Use status only to create
+ * new items and for items which were NotInCVS.
+ */
+void UpdateDirItem::updateEntriesItem(const Entry& entry,
+ bool isBinary)
+{
+ if (UpdateItem* item = findItem(entry.m_name))
+ {
+ if (isFileItem(item))
+ {
+ UpdateFileItem* fileItem = static_cast<UpdateFileItem*>(item);
+ if (fileItem->entry().m_status == Cervisia::NotInCVS ||
+ fileItem->entry().m_status == Cervisia::LocallyRemoved ||
+ entry.m_status == Cervisia::LocallyAdded ||
+ entry.m_status == Cervisia::LocallyRemoved ||
+ entry.m_status == Cervisia::Conflict)
+ {
+ fileItem->setStatus(entry.m_status);
+ }
+ fileItem->setRevTag(entry.m_revision, entry.m_tag);
+ fileItem->setDate(entry.m_dateTime);
+ fileItem->setPixmap(0, isBinary ? SmallIcon("binary") : QPixmap());
+ }
+ return;
+ }
+
+ // Not found, make new entry
+ if (entry.m_type == Entry::Dir)
+ createDirItem(entry)->maybeScanDir(true);
+ else
+ createFileItem(entry);
+}
+
+
+void UpdateDirItem::scanDirectory()
+{
+ const QString& path(filePath());
+ if (!QFile::exists(path))
+ return;
+
+ const CvsDir dir(path);
+
+ const QFileInfoList *files = dir.entryInfoList();
+ if (files)
+ {
+ QFileInfoListIterator it(*files);
+ for (; it.current(); ++it)
+ {
+ Entry entry;
+ entry.m_name = it.current()->fileName();
+ if (it.current()->isDir())
+ {
+ entry.m_type = Entry::Dir;
+ createDirItem(entry);
+ }
+ else
+ {
+ entry.m_type = Entry::File;
+ entry.m_status = Cervisia::NotInCVS;
+ createFileItem(entry);
+ }
+ }
+ }
+}
+
+
+UpdateDirItem* UpdateDirItem::createDirItem(const Entry& entry)
+{
+ UpdateItem* item(insertItem(new UpdateDirItem(this, entry)));
+ assert(isDirItem(item));
+ return static_cast<UpdateDirItem*>(item);
+}
+
+
+UpdateFileItem* UpdateDirItem::createFileItem(const Entry& entry)
+{
+ UpdateItem* item(insertItem(new UpdateFileItem(this, entry)));
+ assert(isFileItem(item));
+ return static_cast<UpdateFileItem*>(item);
+}
+
+
+UpdateItem* UpdateDirItem::insertItem(UpdateItem* item)
+{
+ QPair<TMapItemsByName::iterator, bool> result
+ = m_itemsByName.insert(TMapItemsByName::value_type(item->entry().m_name, item));
+ if (!result.second)
+ {
+ // OK, an item with that name already exists. If the item type is the
+ // same then keep the old one to preserve it's status information
+ UpdateItem* existingItem = *result.first;
+ if (existingItem->rtti() == item->rtti())
+ {
+ delete item;
+ item = existingItem;
+ }
+ else
+ {
+ // avoid dangling pointers in the view
+ updateView()->replaceItem(existingItem, item);
+
+ delete existingItem;
+ *result.first = item;
+ }
+ }
+
+ return item;
+}
+
+
+UpdateItem* UpdateDirItem::findItem(const QString& name) const
+{
+ const TMapItemsByName::const_iterator it = m_itemsByName.find(name);
+
+ return (it != m_itemsByName.end()) ? *it : 0;
+}
+
+// Qt-3.3.8 changed the parsing in QDateTime::fromString() but introduced
+// a bug which leads to the problem that days with 1 digit will incorrectly being
+// parsed as day 0 - which is invalid.
+// workaround with the implementation from Qt-3.3.6
+QDateTime parseDateTime(const QString &s)
+{
+ static const char * const qt_shortMonthNames[] = {
+ "Jan", "Feb", "Mar", "Apr", "May", "Jun",
+ "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" };
+
+ QString monthName( s.mid( 4, 3 ) );
+ int month = -1;
+ // Assume that English monthnames are the default
+ for ( int i = 0; i < 12; ++i ) {
+ if ( monthName == qt_shortMonthNames[i] ) {
+ month = i + 1;
+ break;
+ }
+ }
+ // If English names can't be found, search the localized ones
+ if ( month == -1 ) {
+ for ( int i = 1; i <= 12; ++i ) {
+ if ( monthName == QDate::shortMonthName( i ) ) {
+ month = i;
+ break;
+ }
+ }
+ }
+ if ( month < 1 || month > 12 ) {
+ qWarning( "QDateTime::fromString: Parameter out of range" );
+ QDateTime dt;
+ return dt;
+ }
+ int day = s.mid( 8, 2 ).simplifyWhiteSpace().toInt();
+ int year = s.right( 4 ).toInt();
+ QDate date( year, month, day );
+ QTime time;
+ int hour, minute, second;
+ int pivot = s.find( QRegExp(QString::fromLatin1("[0-9][0-9]:[0-9][0-9]:[0-9][0-9]")) );
+ if ( pivot != -1 ) {
+ hour = s.mid( pivot, 2 ).toInt();
+ minute = s.mid( pivot+3, 2 ).toInt();
+ second = s.mid( pivot+6, 2 ).toInt();
+ time.setHMS( hour, minute, second );
+ }
+ return QDateTime( date, time );
+}
+
+// Format of the CVS/Entries file:
+// /NAME/REVISION/[CONFLICT+]TIMESTAMP/OPTIONS/TAGDATE
+
+void UpdateDirItem::syncWithEntries()
+{
+ const QString path(filePath() + QDir::separator());
+
+ QFile f(path + "CVS/Entries");
+ if( f.open(IO_ReadOnly) )
+ {
+ QTextStream stream(&f);
+ while( !stream.eof() )
+ {
+ QString line = stream.readLine();
+
+ Cervisia::Entry entry;
+
+ const bool isDir(line[0] == 'D');
+
+ if( isDir )
+ line.remove(0, 1);
+
+ if( line[0] != '/' )
+ continue;
+
+ entry.m_type = isDir ? Entry::Dir : Entry::File;
+ entry.m_name = line.section('/', 1, 1);
+
+ if (isDir)
+ {
+ updateEntriesItem(entry, false);
+ }
+ else
+ {
+ QString rev(line.section('/', 2, 2));
+ const QString timestamp(line.section('/', 3, 3));
+ const QString options(line.section('/', 4, 4));
+ entry.m_tag = line.section('/', 5, 5);
+
+ const bool isBinary(options.find("-kb") >= 0);
+
+ // file date in local time
+ entry.m_dateTime = QFileInfo(path + entry.m_name).lastModified();
+
+ if( rev == "0" )
+ entry.m_status = Cervisia::LocallyAdded;
+ else if( rev.length() > 2 && rev[0] == '-' )
+ {
+ entry.m_status = Cervisia::LocallyRemoved;
+ rev.remove(0, 1);
+ }
+ else if (timestamp.find('+') >= 0)
+ {
+ entry.m_status = Cervisia::Conflict;
+ }
+ else
+ {
+ // workaround Qt-3.3.8 bug with our own function (see function above)
+ // const QDateTime date(QDateTime::fromString(timestamp)); // UTC Time
+ const QDateTime date(parseDateTime(timestamp)); // UTC Time
+ QDateTime fileDateUTC;
+ fileDateUTC.setTime_t(entry.m_dateTime.toTime_t(), Qt::UTC);
+ if (date != fileDateUTC)
+ entry.m_status = Cervisia::LocallyModified;
+ }
+
+ entry.m_revision = rev;
+
+ updateEntriesItem(entry, isBinary);
+ }
+ }
+ }
+}
+
+
+/**
+ * Test if files was removed from repository.
+ */
+void UpdateDirItem::syncWithDirectory()
+{
+ QDir dir(filePath());
+
+ for (TMapItemsByName::iterator it(m_itemsByName.begin()),
+ itEnd(m_itemsByName.end());
+ it != itEnd; ++it)
+ {
+ // only files
+ if (isFileItem(*it))
+ {
+ UpdateFileItem* fileItem = static_cast<UpdateFileItem*>(*it);
+
+ // is file removed?
+ if (!dir.exists(it.key()))
+ {
+ fileItem->setStatus(Cervisia::Removed);
+ fileItem->setRevTag(QString::null, QString::null);
+ }
+ }
+ }
+}
+
+
+/**
+ * Read in the content of the directory. If recursive is false, this
+ * is shallow, otherwise all child directories are scanned recursively.
+ */
+void UpdateDirItem::maybeScanDir(bool recursive)
+{
+ if (!m_opened)
+ {
+ m_opened = true;
+ scanDirectory();
+ syncWithEntries();
+
+ // sort the created items
+ sort();
+ }
+
+ if (recursive)
+ {
+ for (TMapItemsByName::iterator it(m_itemsByName.begin()),
+ itEnd(m_itemsByName.end());
+ it != itEnd; ++it)
+ {
+ if (isDirItem(*it))
+ static_cast<UpdateDirItem*>(*it)->maybeScanDir(true);
+ }
+ }
+}
+
+
+void UpdateDirItem::accept(Visitor& visitor)
+{
+ visitor.preVisit(this);
+
+ for (TMapItemsByName::iterator it(m_itemsByName.begin()),
+ itEnd(m_itemsByName.end());
+ it != itEnd; ++it)
+ {
+ (*it)->accept(visitor);
+ }
+
+ visitor.postVisit(this);
+}
+
+
+void UpdateDirItem::setOpen(bool open)
+{
+ if ( open )
+ {
+ const bool openFirstTime(!wasScanned());
+
+ maybeScanDir(false);
+
+ // if new items were created their visibility must be checked
+ // (not while unfoldTree() as this could be slow and unfoldTree()
+ // calls setFilter() itself)
+ UpdateView* view = updateView();
+ if (openFirstTime && !view->isUnfoldingTree())
+ view->setFilter(view->filter());
+ }
+
+ QListViewItem::setOpen(open);
+}
+
+
+int UpdateDirItem::compare(QListViewItem* i,
+ int /*column*/,
+ bool bAscending) const
+{
+ // UpdateDirItems are always lesser than UpdateFileItems
+ if (isFileItem(i))
+ return bAscending ? -1 : 1;
+
+ const UpdateDirItem* item(static_cast<UpdateDirItem*>(i));
+
+ // for every column just compare the directory name
+ return entry().m_name.localeAwareCompare(item->entry().m_name);
+}
+
+
+QString UpdateDirItem::text(int column) const
+{
+ QString result;
+ if (column == Name)
+ result = entry().m_name;
+
+ return result;
+}
+
+
+// ------------------------------------------------------------------------------
+// UpdateFileItem
+// ------------------------------------------------------------------------------
+
+
+UpdateFileItem::UpdateFileItem(UpdateDirItem* parent, const Entry& entry)
+ : UpdateItem(parent, entry),
+ m_undefined(false)
+{
+}
+
+
+void UpdateFileItem::setStatus(EntryStatus status)
+{
+ if (status != m_entry.m_status)
+ {
+ m_entry.m_status = status;
+ const bool visible(applyFilter(updateView()->filter()));
+ if (visible)
+ repaint();
+ }
+ m_undefined = false;
+}
+
+
+void UpdateFileItem::accept(Visitor& visitor)
+{
+ visitor.visit(this);
+}
+
+
+bool UpdateFileItem::applyFilter(UpdateView::Filter filter)
+{
+ bool visible(true);
+ if (filter & UpdateView::OnlyDirectories)
+ visible = false;
+
+ bool unmodified = (entry().m_status == Cervisia::UpToDate) ||
+ (entry().m_status == Cervisia::Unknown);
+ if ((filter & UpdateView::NoUpToDate) && unmodified)
+ visible = false;
+ if ((filter & UpdateView::NoRemoved) && (entry().m_status == Cervisia::Removed))
+ visible = false;
+ if ((filter & UpdateView::NoNotInCVS) && (entry().m_status == Cervisia::NotInCVS))
+ visible = false;
+
+ setVisible(visible);
+
+ return visible;
+}
+
+
+void UpdateFileItem::setRevTag(const QString& rev, const QString& tag)
+{
+ m_entry.m_revision = rev;
+
+ if (tag.length() == 20 && tag[0] == 'D' && tag[5] == '.'
+ && tag[8] == '.' && tag[11] == '.' && tag[14] == '.'
+ && tag[17] == '.')
+ {
+ const QDate tagDate(tag.mid(1, 4).toInt(),
+ tag.mid(6, 2).toInt(),
+ tag.mid(9, 2).toInt());
+ const QTime tagTime(tag.mid(12, 2).toInt(),
+ tag.mid(15, 2).toInt(),
+ tag.mid(18, 2).toInt());
+ const QDateTime tagDateTimeUtc(tagDate, tagTime);
+
+ if (tagDateTimeUtc.isValid())
+ {
+ // This is in UTC and must be converted to local time.
+ //
+ // A bit strange but I didn't find anything easier which is portable.
+ // Compute the difference between UTC and local timezone for this
+ // tag date.
+ const unsigned int dateTimeInSeconds(tagDateTimeUtc.toTime_t());
+ QDateTime dateTime;
+ dateTime.setTime_t(dateTimeInSeconds, Qt::UTC);
+ const int localUtcOffset(dateTime.secsTo(tagDateTimeUtc));
+
+ const QDateTime tagDateTimeLocal(tagDateTimeUtc.addSecs(localUtcOffset));
+
+ m_entry.m_tag = KGlobal::locale()->formatDateTime(tagDateTimeLocal);
+ }
+ else
+ m_entry.m_tag = tag;
+ }
+ else if (tag.length() > 1 && tag[0] == 'T')
+ m_entry.m_tag = tag.mid(1);
+ else
+ m_entry.m_tag = tag;
+
+ if (isVisible())
+ {
+ widthChanged();
+ repaint();
+ }
+}
+
+
+void UpdateFileItem::setDate(const QDateTime& date)
+{
+ m_entry.m_dateTime = date;
+}
+
+
+void UpdateFileItem::markUpdated(bool laststage,
+ bool success)
+{
+ EntryStatus newstatus = m_entry.m_status;
+
+ if (laststage)
+ {
+ if (undefinedState() && m_entry.m_status != Cervisia::NotInCVS)
+ newstatus = success? Cervisia::UpToDate : Cervisia::Unknown;
+ setStatus(newstatus);
+ }
+ else
+ setUndefinedState(true);
+}
+
+
+int UpdateFileItem::statusClass() const
+{
+ int iResult(0);
+ switch (entry().m_status)
+ {
+ case Cervisia::Conflict:
+ iResult = 0;
+ break;
+ case Cervisia::LocallyAdded:
+ iResult = 1;
+ break;
+ case Cervisia::LocallyRemoved:
+ iResult = 2;
+ break;
+ case Cervisia::LocallyModified:
+ iResult = 3;
+ break;
+ case Cervisia::Updated:
+ case Cervisia::NeedsUpdate:
+ case Cervisia::Patched:
+ case Cervisia::Removed:
+ case Cervisia::NeedsPatch:
+ case Cervisia::NeedsMerge:
+ iResult = 4;
+ break;
+ case Cervisia::NotInCVS:
+ iResult = 5;
+ break;
+ case Cervisia::UpToDate:
+ case Cervisia::Unknown:
+ iResult = 6;
+ break;
+ }
+
+ return iResult;
+}
+
+
+int UpdateFileItem::compare(QListViewItem* i,
+ int column,
+ bool bAscending) const
+{
+ // UpdateDirItems are always lesser than UpdateFileItems
+ if (isDirItem(i))
+ return bAscending ? 1 : -1;
+
+ const UpdateFileItem* item = static_cast<UpdateFileItem*>(i);
+
+ int iResult(0);
+ switch (column)
+ {
+ case Name:
+ iResult = entry().m_name.localeAwareCompare(item->entry().m_name);
+ break;
+ case MimeType:
+ iResult = KMimeType::findByPath(entry().m_name)->comment().localeAwareCompare(KMimeType::findByPath(item->entry().m_name)->comment());
+ break;
+ case Status:
+ if ((iResult = ::compare(statusClass(), item->statusClass())) == 0)
+ iResult = entry().m_name.localeAwareCompare(item->entry().m_name);
+ break;
+ case Revision:
+ iResult = ::compareRevisions(entry().m_revision, item->entry().m_revision);
+ break;
+ case TagOrDate:
+ iResult = entry().m_tag.localeAwareCompare(item->entry().m_tag);
+ break;
+ case Timestamp:
+ iResult = ::compare(entry().m_dateTime, item->entry().m_dateTime);
+ break;
+ }
+
+ return iResult;
+}
+
+
+QString UpdateFileItem::text(int column) const
+{
+ QString result;
+ switch (column)
+ {
+ case Name:
+ result = entry().m_name;
+ break;
+ case MimeType:
+ result = KMimeType::findByPath(entry().m_name)->comment();
+ break;
+ case Status:
+ result = toString(entry().m_status);
+ break;
+ case Revision:
+ result = entry().m_revision;
+ break;
+ case TagOrDate:
+ result = entry().m_tag;
+ break;
+ case Timestamp:
+ if (entry().m_dateTime.isValid())
+ result = KGlobal::locale()->formatDateTime(entry().m_dateTime);
+ break;
+ }
+
+ return result;
+}
+
+
+void UpdateFileItem::paintCell(QPainter *p,
+ const QColorGroup &cg,
+ int col,
+ int width,
+ int align)
+{
+ const UpdateView* view(updateView());
+
+ QColor color;
+ switch (m_entry.m_status)
+ {
+ case Cervisia::Conflict:
+ color = view->conflictColor();
+ break;
+ case Cervisia::LocallyAdded:
+ case Cervisia::LocallyModified:
+ case Cervisia::LocallyRemoved:
+ color = view->localChangeColor();
+ break;
+ case Cervisia::NeedsMerge:
+ case Cervisia::NeedsPatch:
+ case Cervisia::NeedsUpdate:
+ case Cervisia::Patched:
+ case Cervisia::Removed:
+ case Cervisia::Updated:
+ color = view->remoteChangeColor();
+ break;
+ case Cervisia::NotInCVS:
+ color = view->notInCvsColor();
+ break;
+ case Cervisia::Unknown:
+ case Cervisia::UpToDate:
+ break;
+ }
+
+ const QFont oldFont(p->font());
+ QColorGroup mycg(cg);
+ if (color.isValid() && color != KGlobalSettings::textColor())
+ {
+ QFont myFont(oldFont);
+ myFont.setBold(true);
+ p->setFont(myFont);
+ mycg.setColor(QColorGroup::Text, color);
+ }
+
+ QListViewItem::paintCell(p, mycg, col, width, align);
+
+ if (color.isValid())
+ {
+ p->setFont(oldFont);
+ }
+}
+
+
+/**
+ * Finds or creates the UpdateDirItem with path \a dirPath. If \a dirPath
+ * is "." \a rootItem is returned.
+ */
+UpdateDirItem* findOrCreateDirItem(const QString& dirPath,
+ UpdateDirItem* rootItem)
+{
+ assert(!dirPath.isEmpty());
+ assert(rootItem);
+
+ UpdateDirItem* dirItem(rootItem);
+
+ if (dirPath != QChar('.'))
+ {
+ const QStringList& dirNames(QStringList::split('/', dirPath));
+ const QStringList::const_iterator itDirNameEnd(dirNames.end());
+ for (QStringList::const_iterator itDirName(dirNames.begin());
+ itDirName != itDirNameEnd; ++itDirName)
+ {
+ const QString& dirName(*itDirName);
+
+ UpdateItem* item = dirItem->findItem(dirName);
+ if (isFileItem(item))
+ {
+ // this happens if you
+ // - add a directory outside of Cervisia
+ // - update status (a file item is created for the directory)
+ // - add new directory in Cervisia
+ // - update status
+ kdDebug(8050) << "findOrCreateDirItem(): file changed to dir " << dirName << endl;
+
+ // just create a new dir item, createDirItem() will delete the
+ // file item and update the m_itemsByName map
+ item = 0;
+ }
+
+ if (!item)
+ {
+ kdDebug(8050) << "findOrCreateDirItem(): create dir item " << dirName << endl;
+ Entry entry;
+ entry.m_name = dirName;
+ entry.m_type = Entry::Dir;
+ item = dirItem->createDirItem(entry);
+ }
+
+ assert(isDirItem(item));
+
+ dirItem = static_cast<UpdateDirItem*>(item);
+ }
+ }
+
+ return dirItem;
+}
diff --git a/cervisia/updateview_items.h b/cervisia/updateview_items.h
new file mode 100644
index 00000000..49f5cf91
--- /dev/null
+++ b/cervisia/updateview_items.h
@@ -0,0 +1,169 @@
+/*
+ * Copyright (C) 1999-2002 Bernd Gehrmann <bernd@mail.berlios.de>
+ * Copyright (c) 2003-2007 André Wöbbeking <Woebbeking@kde.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the 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, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+
+#ifndef UPDATEVIEW_ITEMS_H
+#define UPDATEVIEW_ITEMS_H
+
+
+#include <qdatetime.h>
+#include <qlistview.h>
+#include <qmap.h>
+
+#include "entry.h"
+#include "updateview.h"
+
+
+class UpdateDirItem;
+class UpdateFileItem;
+class Visitor;
+
+
+UpdateDirItem* findOrCreateDirItem(const QString&, UpdateDirItem*);
+
+
+class UpdateItem : public QListViewItem
+{
+public:
+
+ UpdateItem(UpdateView* parent, const Cervisia::Entry& entry)
+ : QListViewItem(parent), m_entry(entry) {}
+ UpdateItem(UpdateItem* parent, const Cervisia::Entry& entry)
+ : QListViewItem(parent), m_entry(entry) {}
+
+ const Cervisia::Entry& entry() const { return m_entry; }
+
+ // Returns the path (relative to the repository).
+ // QString::null for the root item and its (direct) children.
+ // If it's not QString::null it ends with '/'.
+ QString dirPath() const;
+
+ // Returns the file name, including the path (relative to the repository)
+ QString filePath() const;
+
+ virtual void accept(Visitor&) = 0;
+
+protected:
+
+ UpdateView* updateView() const { return static_cast<UpdateView*>(listView()); }
+
+ Cervisia::Entry m_entry;
+};
+
+
+class UpdateDirItem : public UpdateItem
+{
+public:
+
+ enum { Name };
+
+ UpdateDirItem(UpdateView* parent, const Cervisia::Entry& entry);
+ UpdateDirItem(UpdateDirItem* parent, const Cervisia::Entry& entry);
+
+ void syncWithDirectory();
+ void syncWithEntries();
+ void updateChildItem(const QString& name, Cervisia::EntryStatus status, bool isdir);
+ void updateEntriesItem(const Cervisia::Entry& entry, bool isBinary);
+
+ bool wasScanned() const { return m_opened; }
+
+ virtual int compare(QListViewItem* i, int col, bool) const;
+ virtual QString text(int col) const;
+ virtual void setOpen(bool o);
+ virtual int rtti() const { return RTTI; }
+
+ void maybeScanDir(bool recursive);
+
+ virtual void accept(Visitor&);
+
+ enum { RTTI = 10000 };
+
+private:
+
+ void scanDirectory();
+
+ UpdateDirItem* createDirItem(const Cervisia::Entry& entry);
+ UpdateFileItem* createFileItem(const Cervisia::Entry& entry);
+
+ UpdateItem* insertItem(UpdateItem* item);
+
+ UpdateItem* findItem(const QString& name) const;
+
+ typedef QMap<QString, UpdateItem*> TMapItemsByName;
+
+ TMapItemsByName m_itemsByName;
+
+ bool m_opened;
+
+ friend UpdateDirItem* findOrCreateDirItem(const QString&, UpdateDirItem*);
+};
+
+
+class UpdateFileItem : public UpdateItem
+{
+public:
+
+ enum { Name, MimeType, Status, Revision, TagOrDate, Timestamp };
+
+ UpdateFileItem(UpdateDirItem* parent, const Cervisia::Entry& entry);
+
+ bool undefinedState() const
+ { return m_undefined; }
+
+ virtual int compare(QListViewItem* i, int col, bool) const;
+ virtual QString text(int col) const;
+ virtual void paintCell(QPainter *p, const QColorGroup &cg,
+ int col, int width, int align);
+ virtual int rtti() const { return RTTI; }
+
+ void setStatus(Cervisia::EntryStatus status);
+ void setRevTag(const QString& rev, const QString& tag);
+ void setDate(const QDateTime& date);
+ void setUndefinedState(bool b)
+ { m_undefined = b; }
+
+ void markUpdated(bool laststage, bool success);
+
+ virtual void accept(Visitor&);
+
+ bool applyFilter(UpdateView::Filter filter);
+
+ enum { RTTI = 10001 };
+
+private:
+
+ int statusClass() const;
+
+ bool m_undefined;
+};
+
+
+inline bool isDirItem(const QListViewItem* item)
+{
+ return item && item->rtti() == UpdateDirItem::RTTI;
+}
+
+
+inline bool isFileItem(const QListViewItem* item)
+{
+ return item && item->rtti() == UpdateFileItem::RTTI;
+}
+
+
+#endif // UPDATEVIEW_ITEMS_H
diff --git a/cervisia/updateview_visitors.cpp b/cervisia/updateview_visitors.cpp
new file mode 100644
index 00000000..e18b5b68
--- /dev/null
+++ b/cervisia/updateview_visitors.cpp
@@ -0,0 +1,98 @@
+/*
+ * Copyright (c) 2003-2007 André Wöbbeking <Woebbeking@kde.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the 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, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+
+#include "updateview_visitors.h"
+
+#include "updateview.h"
+#include "updateview_items.h"
+
+
+using Cervisia::Entry;
+
+
+ApplyFilterVisitor::ApplyFilterVisitor(UpdateView::Filter filter)
+ : m_filter(filter)
+{
+}
+
+
+void ApplyFilterVisitor::preVisit(UpdateDirItem* item)
+{
+ // as QListViewItem::setVisible() is recursive we have to make
+ // this UpdateDirItem visible first and later we can make it invisible
+ item->setVisible(true);
+
+ // assume that this item is invisible and correct it later
+ // (see markAllParentsAsVisible())
+ m_invisibleDirItems.insert(item);
+}
+
+
+void ApplyFilterVisitor::postVisit(UpdateDirItem* item)
+{
+ // a UpdateDirItem is visible if
+ // - it has visible children
+ // - it is not opened
+ // - empty directories are not hidden
+ // - it has no parent (top level item)
+ const bool visible(!m_invisibleDirItems.count(item)
+ || !item->wasScanned()
+ || !(m_filter & UpdateView::NoEmptyDirectories)
+ || !item->parent());
+
+ // only set invisible as QListViewItem::setVisible() is recursive
+ // and so maybe overrides the state applied by the filter
+ if (visible)
+ {
+ markAllParentsAsVisible(item);
+ }
+ else
+ {
+ item->setVisible(false);
+ }
+}
+
+
+void ApplyFilterVisitor::visit(UpdateFileItem* item)
+{
+ const bool visible(item->applyFilter(m_filter));
+ if (visible)
+ {
+ markAllParentsAsVisible(item);
+ }
+}
+
+
+void ApplyFilterVisitor::markAllParentsAsVisible(UpdateItem* item)
+{
+ while ((item = static_cast<UpdateDirItem*>(item->parent())))
+ {
+ TItemSet::iterator it = m_invisibleDirItems.find(item);
+ if (it != m_invisibleDirItems.end())
+ {
+ m_invisibleDirItems.erase(it);
+ }
+ else
+ {
+ // if this item isn't in the map anymore all parents
+ // are already removed too
+ break;
+ }
+ }
+}
diff --git a/cervisia/updateview_visitors.h b/cervisia/updateview_visitors.h
new file mode 100644
index 00000000..c92fd615
--- /dev/null
+++ b/cervisia/updateview_visitors.h
@@ -0,0 +1,69 @@
+/*
+ * Copyright (c) 2003-2007 André Wöbbeking <Woebbeking@kde.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the 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, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+
+#ifndef UPDATEVIEW_VISITORS_H
+#define UPDATEVIEW_VISITORS_H
+
+
+#include "updateview.h"
+
+#include <set>
+
+
+class UpdateItem;
+class UpdateDirItem;
+class UpdateFileItem;
+
+
+class Visitor
+{
+public:
+
+ virtual ~Visitor() {}
+
+ virtual void preVisit(UpdateDirItem*) = 0;
+ virtual void postVisit(UpdateDirItem*) = 0;
+
+ virtual void visit(UpdateFileItem*) = 0;
+};
+
+
+class ApplyFilterVisitor : public Visitor
+{
+public:
+
+ explicit ApplyFilterVisitor(UpdateView::Filter filter);
+
+ virtual void preVisit(UpdateDirItem*);
+ virtual void postVisit(UpdateDirItem*);
+
+ virtual void visit(UpdateFileItem*);
+
+private:
+
+ void markAllParentsAsVisible(UpdateItem*);
+
+ UpdateView::Filter m_filter;
+
+ typedef std::set<UpdateItem*> TItemSet;
+ TItemSet m_invisibleDirItems;
+};
+
+
+#endif // UPDATEVIEW_VISITORS_H
diff --git a/cervisia/version.h b/cervisia/version.h
new file mode 100644
index 00000000..a1fc5bf0
--- /dev/null
+++ b/cervisia/version.h
@@ -0,0 +1,2 @@
+#define CERVISIA_VERSION "2.4.10"
+
diff --git a/cervisia/watchdlg.cpp b/cervisia/watchdlg.cpp
new file mode 100644
index 00000000..317f5c95
--- /dev/null
+++ b/cervisia/watchdlg.cpp
@@ -0,0 +1,107 @@
+/*
+ * Copyright (C) 1999-2002 Bernd Gehrmann
+ * bernd@mail.berlios.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.
+ *
+ * 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, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+
+#include "watchdlg.h"
+
+#include <qbuttongroup.h>
+#include <qcheckbox.h>
+#include <qlabel.h>
+#include <qlayout.h>
+#include <qradiobutton.h>
+#include <klocale.h>
+
+
+WatchDialog::WatchDialog(ActionType action, QWidget *parent, const char *name)
+ : KDialogBase(parent, name, true, QString::null,
+ Ok | Cancel | Help, Ok, true)
+{
+ setCaption( (action==Add)? i18n("CVS Watch Add") : i18n("CVS Watch Remove") );
+
+ QFrame* mainWidget = makeMainWidget();
+
+ QBoxLayout *layout = new QVBoxLayout(mainWidget, 0, spacingHint());
+
+ QLabel *textlabel = new QLabel
+ ( (action==Add)? i18n("Add watches for the following events:")
+ : i18n("Remove watches for the following events:"), mainWidget );
+ layout->addWidget(textlabel, 0);
+
+ all_button = new QRadioButton(i18n("&All"), mainWidget);
+ all_button->setFocus();
+ all_button->setChecked(true);
+ layout->addWidget(all_button);
+
+ only_button = new QRadioButton(i18n("&Only:"), mainWidget);
+ layout->addWidget(only_button);
+
+ QGridLayout *eventslayout = new QGridLayout(layout);
+ eventslayout->addColSpacing(0, 20);
+ eventslayout->setColStretch(0, 0);
+ eventslayout->setColStretch(1, 1);
+
+ commitbox = new QCheckBox(i18n("&Commits"), mainWidget);
+ commitbox->setEnabled(false);
+ eventslayout->addWidget(commitbox, 0, 1);
+
+ editbox = new QCheckBox(i18n("&Edits"), mainWidget);
+ editbox->setEnabled(false);
+ eventslayout->addWidget(editbox, 1, 1);
+
+ uneditbox = new QCheckBox(i18n("&Unedits"), mainWidget);
+ uneditbox->setEnabled(false);
+ eventslayout->addWidget(uneditbox, 2, 1);
+
+ QButtonGroup* group = new QButtonGroup(mainWidget);
+ group->hide();
+ group->insert(all_button);
+ group->insert(only_button);
+
+ connect( only_button, SIGNAL(toggled(bool)),
+ commitbox, SLOT(setEnabled(bool)) );
+ connect( only_button, SIGNAL(toggled(bool)),
+ editbox, SLOT(setEnabled(bool)) );
+ connect( only_button, SIGNAL(toggled(bool)),
+ uneditbox, SLOT(setEnabled(bool)) );
+
+ setHelp("watches");
+}
+
+
+WatchDialog::Events WatchDialog::events() const
+{
+ Events res = None;
+ if (all_button->isChecked())
+ res = All;
+ else
+ {
+ if (commitbox->isChecked())
+ res = Events(res | Commits);
+ if (editbox->isChecked())
+ res = Events(res | Edits);
+ if (uneditbox->isChecked())
+ res = Events(res | Unedits);
+ }
+ return res;
+}
+
+
+// Local Variables:
+// c-basic-offset: 4
+// End:
diff --git a/cervisia/watchdlg.h b/cervisia/watchdlg.h
new file mode 100644
index 00000000..59510dc2
--- /dev/null
+++ b/cervisia/watchdlg.h
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 1999-2002 Bernd Gehrmann
+ * bernd@mail.berlios.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.
+ *
+ * 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, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+
+#ifndef WATCHDLG_H
+#define WATCHDLG_H
+
+
+#include <kdialogbase.h>
+
+
+class QRadioButton;
+class QCheckBox;
+
+
+class WatchDialog : public KDialogBase
+{
+public:
+ enum ActionType { Add, Remove };
+ enum Events { None=0, All=1, Commits=2, Edits=4, Unedits=8 };
+
+ explicit WatchDialog( ActionType action, QWidget *parent=0, const char *name=0 );
+
+ Events events() const;
+
+private:
+ QRadioButton *all_button, *only_button;
+ QCheckBox *commitbox, *editbox, *uneditbox;
+};
+
+#endif
+
+
+// Local Variables:
+// c-basic-offset: 4
+// End:
diff --git a/cervisia/watchersdlg.cpp b/cervisia/watchersdlg.cpp
new file mode 100644
index 00000000..d7d849bd
--- /dev/null
+++ b/cervisia/watchersdlg.cpp
@@ -0,0 +1,121 @@
+/*
+ * Copyright (c) 2003 Christian Loose <christian.loose@hamburg.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.
+ *
+ * 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, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+
+#include "watchersdlg.h"
+
+#include <qlayout.h>
+#include <qtable.h>
+#include <kconfig.h>
+#include <klineedit.h>
+#include <klocale.h>
+
+#include "misc.h"
+#include "cvsservice_stub.h"
+#include "progressdlg.h"
+
+
+WatchersDialog::WatchersDialog(KConfig& cfg, QWidget* parent, const char* name)
+ : KDialogBase(parent, name, false, QString::null,
+ Close, ButtonCode(0), true)
+ , partConfig(cfg)
+{
+ QFrame* mainWidget = makeMainWidget();
+
+ QBoxLayout *layout = new QVBoxLayout(mainWidget, 0, spacingHint());
+
+ table = new QTable(mainWidget, "watchersTable");
+ table->setNumCols(5);
+ table->setSelectionMode(QTable::NoSelection);
+ table->setColumnMovingEnabled(false);
+ table->setRowMovingEnabled(false);
+ table->setReadOnly(true);
+ table->setDragEnabled(false);
+ table->setSorting(true);
+ table->verticalHeader()->hide();
+ table->setLeftMargin(0);
+
+ QHeader* header = table->horizontalHeader();
+ header->setLabel(0, i18n("File"));
+ header->setLabel(1, i18n("Watcher"));
+ header->setLabel(2, i18n("Edit"));
+ header->setLabel(3, i18n("Unedit"));
+ header->setLabel(4, i18n("Commit"));
+
+ layout->addWidget(table, 1);
+
+ setWFlags(Qt::WDestructiveClose | getWFlags());
+
+ QSize size = configDialogSize(partConfig, "WatchersDialog");
+ resize(size);
+}
+
+
+WatchersDialog::~WatchersDialog()
+{
+ saveDialogSize(partConfig, "WatchersDialog");
+}
+
+
+bool WatchersDialog::parseWatchers(CvsService_stub* cvsService,
+ const QStringList& files)
+{
+ setCaption(i18n("CVS Watchers"));
+
+ DCOPRef job = cvsService->watchers(files);
+ if( !cvsService->ok() )
+ return false;
+
+ ProgressDialog dlg(this, "Watchers", job, "watchers", i18n("CVS Watchers"));
+ if( !dlg.execute() )
+ return false;
+
+ QString line;
+ int numRows = 0;
+ while( dlg.getLine(line) )
+ {
+ // parse the output line
+ QStringList list = splitLine(line);
+
+ // ignore empty lines and unknown files
+ if( list.isEmpty() || list[0] == "?" )
+ continue;
+
+ // add a new row to the table
+ table->setNumRows(numRows + 1);
+
+ table->setText(numRows, 0, list[0]);
+ table->setText(numRows, 1, list[1]);
+
+ QCheckTableItem* item = new QCheckTableItem(table, "");
+ item->setChecked(list.contains("edit"));
+ table->setItem(numRows, 2, item);
+
+ item = new QCheckTableItem(table, "");
+ item->setChecked(list.contains("unedit"));
+ table->setItem(numRows, 3, item);
+
+ item = new QCheckTableItem(table, "");
+ item->setChecked(list.contains("commit"));
+ table->setItem(numRows, 4, item);
+
+ ++numRows;
+ }
+
+ return true;
+}
diff --git a/cervisia/watchersdlg.h b/cervisia/watchersdlg.h
new file mode 100644
index 00000000..59b2d52c
--- /dev/null
+++ b/cervisia/watchersdlg.h
@@ -0,0 +1,45 @@
+/*
+ * Copyright (c) 2003 Christian Loose <christian.loose@hamburg.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.
+ *
+ * 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, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+
+#ifndef WATCHERSDLG_H
+#define WATCHERSDLG_H
+
+
+#include <kdialogbase.h>
+
+class QTable;
+class KConfig;
+class CvsService_stub;
+
+
+class WatchersDialog : public KDialogBase
+{
+public:
+ explicit WatchersDialog(KConfig& cfg, QWidget* parent = 0,
+ const char* name = 0);
+ virtual ~WatchersDialog();
+
+ bool parseWatchers(CvsService_stub* cvsService, const QStringList& files);
+
+private:
+ QTable* table;
+ KConfig& partConfig;
+};
+
+#endif
diff --git a/configure.in.in b/configure.in.in
new file mode 100644
index 00000000..6d7e9167
--- /dev/null
+++ b/configure.in.in
@@ -0,0 +1,5 @@
+#MIN_CONFIG
+KDE_ENABLE_HIDDEN_VISIBILITY
+
+DO_NOT_COMPILE="$DO_NOT_COMPILE kappgen kstartperf"
+CXXFLAGS="$CXXFLAGS $KDE_DEFAULT_CXXFLAGS"
diff --git a/doc/Makefile.am b/doc/Makefile.am
new file mode 100644
index 00000000..6812bd2d
--- /dev/null
+++ b/doc/Makefile.am
@@ -0,0 +1,5 @@
+
+KDE_LANG = en
+KDE_DOCS = AUTO
+SUBDIRS = $(AUTODIRS)
+
diff --git a/doc/cervisia/Makefile.am b/doc/cervisia/Makefile.am
new file mode 100644
index 00000000..171f575c
--- /dev/null
+++ b/doc/cervisia/Makefile.am
@@ -0,0 +1,2 @@
+KDE_LANG = en
+KDE_DOCS = AUTO
diff --git a/doc/cervisia/annotate.png b/doc/cervisia/annotate.png
new file mode 100644
index 00000000..279c33f5
--- /dev/null
+++ b/doc/cervisia/annotate.png
Binary files differ
diff --git a/doc/cervisia/checkout.png b/doc/cervisia/checkout.png
new file mode 100644
index 00000000..35e2836e
--- /dev/null
+++ b/doc/cervisia/checkout.png
Binary files differ
diff --git a/doc/cervisia/commit.png b/doc/cervisia/commit.png
new file mode 100644
index 00000000..dc72147f
--- /dev/null
+++ b/doc/cervisia/commit.png
Binary files differ
diff --git a/doc/cervisia/diff.png b/doc/cervisia/diff.png
new file mode 100644
index 00000000..3d3c7903
--- /dev/null
+++ b/doc/cervisia/diff.png
Binary files differ
diff --git a/doc/cervisia/history.png b/doc/cervisia/history.png
new file mode 100644
index 00000000..81da16fd
--- /dev/null
+++ b/doc/cervisia/history.png
Binary files differ
diff --git a/doc/cervisia/import.png b/doc/cervisia/import.png
new file mode 100644
index 00000000..46710567
--- /dev/null
+++ b/doc/cervisia/import.png
Binary files differ
diff --git a/doc/cervisia/index.docbook b/doc/cervisia/index.docbook
new file mode 100644
index 00000000..66e45dd9
--- /dev/null
+++ b/doc/cervisia/index.docbook
@@ -0,0 +1,3224 @@
+<?xml version="1.0" ?>
+<!DOCTYPE book PUBLIC "-//KDE//DTD DocBook XML V4.2-Based Variant V1.1//EN" "dtd/kdex.dtd" [
+ <!ENTITY kappname "&cervisia;">
+ <!ENTITY package "kdesdk">
+ <!ENTITY ssh "<command>ssh</command>">
+ <!ENTITY rsh "<command>rsh</command>">
+ <!ENTITY % addindex "IGNORE">
+ <!ENTITY % English "INCLUDE"> <!-- Change language only here -->
+ <!ENTITY CVS "<application>CVS</application>">
+]>
+
+<book lang="&language;">
+
+<bookinfo>
+<title>&cervisia; Manual</title>
+<authorgroup>
+<author>
+<firstname>Bernd</firstname><surname>Gehrmann</surname>
+<affiliation><address><email>bernd@mail.berlios.de</email></address></affiliation>
+</author>
+<author>
+<firstname>Carlos</firstname><surname>Woelz</surname>
+<affiliation><address><email>carloswoelz@imap-mail.com</email></address></affiliation>
+</author>
+
+
+<!-- TRANS:ROLES_OF_TRANSLATORS -->
+
+</authorgroup>
+
+<copyright>
+<year>1999</year>
+<year>2000</year>
+<year>2001</year>
+<year>2002</year>
+<holder>Bernd Gehrmann</holder>
+</copyright>
+
+<copyright>
+<year>2004</year>
+<holder>Carlos Woelz</holder>
+</copyright>
+
+<legalnotice>&FDLNotice;</legalnotice>
+
+<date>2004-06-06</date>
+<releaseinfo>2.01.90</releaseinfo>
+
+<abstract>
+<para>&cervisia; provides a graphical view of &CVS;.</para>
+</abstract>
+
+<keywordset>
+<keyword>KDE</keyword>
+<keyword>kdesdk</keyword>
+<keyword>Cervisia</keyword>
+<keyword>CVS</keyword>
+<keyword>version control</keyword>
+<keyword>revision control</keyword>
+</keywordset>
+
+</bookinfo>
+
+<chapter id="introduction">
+<title>Introduction</title>
+
+<para>
+<ulink url="http://www.kde.org/apps/cervisia/">&cervisia;</ulink> is a
+user friendly version control system front-end. The aim is to support &CVS; and
+other version control system programs in a unified interface, featuring conflict
+resolution, difference and history viewers, status for the working copy files,
+and support for most version control functions. You can get &cervisia;
+by building the kdesdk module or installing the kdesdk package provided by your
+distribution. Currently, only &CVS; is supported, but other version control
+systems may be integrated in the future.
+</para>
+
+<para>
+A version control system is a tool to record, manage, and distribute
+different versions of files. &CVS; is a version control system. It allows you
+to share your modifications easily, as each of the contributors can work on their
+local copy at the same time, without fear of overwriting each others'
+modifications. It allows the recovery of past versions (useful for tracking
+bugs), the creation of branches (for experimental development or for releases
+of code) and more.
+</para>
+
+<para>
+The main <firstterm>repository</firstterm> usually holds a collaborative
+project (commercial or not), but you can take advantage of the nice revision
+control features offered by &CVS; even for a project developed exclusively by
+you. It is easy to set up a local repository, and you will gain the ability to
+track changes that caused bugs, revert changes, avoid accidental loss of
+information, &etc;.
+</para>
+
+<para>
+The repository holds the project files, and every contributor keeps their
+own local copy, named <firstterm>working copy</firstterm> or
+<firstterm>sandbox</firstterm>; one can then add their modifications to the main
+repository (a process called &quot;committing&quot;) and/or update their own
+copy to reflect recent changes made by other contributors.
+</para>
+
+</chapter>
+
+<chapter id="getting-started">
+<title>Getting Started</title>
+
+<sect1 id="accessing-repository">
+<title>Accessing The Repository</title>
+
+<para>
+In this section, we show how to use the basic version control system
+functionality using &cervisia; to checkout modules from the
+repository and work with them. To do that, you must have access to the
+repository as a client, meaning that someone (probably the administrator of
+the &CVS; repository) gave you an account on the server machine. Alternatively,
+you can easily create a local repository for your own project.
+</para>
+
+<tip><para>
+If you plan to develop a complex project, it is a good idea to use the
+&CVS; features, even if you are the only developer. You can make all changes in
+the working copy, and use &cervisia; (or any other &CVS; tool) to update and
+commit. This way, you will gain the ability to track changes that caused bugs,
+revert changes, avoid accidental loss of information, &etc;. Using &cervisia;, it
+is simple to create a local repository.
+</para>
+
+<procedure>
+<title>Creating a Local Repository</title>
+
+<step><para>
+Open the <guilabel>Create New Repository (cvs init)</guilabel>
+dialog by choosing
+<menuchoice><guimenu>Repository</guimenu>
+<guimenuitem>Create...</guimenuitem></menuchoice>.
+</para></step>
+
+<step><para>
+Press the <guilabel>...</guilabel> button to select the folder where you want to
+create the repository, or enter its location in the text box. For instance, if you
+want to place the repository in the <filename>/home/user</filename> folder, and
+to name it <filename>cvsroot</filename>, you should type
+<filename>/home/user/cvsroot</filename> in the text box, or select the
+<filename>/home/user</filename> folder using the file picker, and add
+<filename>cvsroot</filename>.
+</para></step>
+
+<step><para>
+Confirm by pressing the <guibutton>OK</guibutton>
+button. &cervisia; will create and initialize the new repository folder.
+</para></step>
+
+<step><para>
+Now you can import your current work to the repository, or simply create a
+folder in the repository to start a new module from scratch.
+</para></step>
+
+</procedure>
+
+</tip>
+
+
+<para>
+&cervisia; offers an integrated front-end to manage all your repository
+locations, the <guilabel>Configure Access to Repositories</guilabel> dialog.
+To display it, select the <menuchoice><guimenu>Repository</guimenu>
+<guimenuitem>Repositories...</guimenuitem></menuchoice> menu item.
+</para>
+
+<figure id="screenshot-repositories" float="1">
+<title>A screenshot of &cervisia;'s Configure Access to Repositories dialog</title>
+<mediaobject>
+<imageobject><imagedata format="PNG" fileref="repositories.png"/></imageobject>
+<textobject><phrase>A screenshot of &cervisia;'s Configure Access to
+Repositories dialog</phrase></textobject>
+</mediaobject>
+</figure>
+
+<para>
+There are several methods to access a CVS repository. It may be reached via
+password authentication (:pserver:), secure shell (using :ext:), local
+repository (:local:), &etc;. The format for the repository location is
+(optional items appear between square brackets):
+</para>
+
+<para>
+<filename>[:method:][[user][:password]@]hostname[:[port]]/path/to/repository</filename>
+</para>
+
+<para>
+Not all these items (user, password, hostname, port) are always necessary
+to access the repository. The required information depends on the access method
+used, which can be categorized as follows:
+</para>
+
+<variablelist>
+
+<varlistentry>
+<term>Local</term>
+
+<listitem>
+<para>
+The local access method is the default method used by &CVS;. Therefore, it is
+optional to add the :local: method to the repository location: you can enter
+simply the path to the folder which stores the &CVS;
+repository, and is accessible from your computer, like
+<filename class="directory">/path/to/repository</filename> or to give a real
+life example, <filename class="directory">/home/cvs</filename>.</para>
+
+<para>
+It may physically be on a disk which is mounted via <acronym>NFS</acronym>,
+but this is an irrelevant detail. If you created a local repository, the
+location will be simple the path to it.
+</para>
+</listitem>
+</varlistentry>
+
+<varlistentry id="rsh">
+<term>rsh</term>
+
+<listitem>
+<para>
+The repository location is something like
+<filename>:ext:username@host.url.org:/path/to/repository</filename>.
+</para>
+
+<para>
+This method requires that you have a user account on the server machine (in
+this example, <systemitem class="systemname">host.url.org</systemitem>) and
+use a remote shell for communication. By default, &CVS; uses &rsh; for this
+purpose; however, &rsh; has long considered to be insecure, and is widely
+replaced by &ssh;.
+</para>
+
+<para>
+If you wish to use &ssh;, you must set the environment variable
+$<envar>CVS_RSH</envar> to &ssh; when using the <command>cvs</command>
+client. &cervisia; supports this easily.
+</para>
+
+<!-- TODO: verify if the above still apply -->
+
+<para>
+Note that &cervisia; cannot answer possible password requests from the
+server machine. You must make sure that a remote login works without requiring
+you to enter the password. With plain vanilla &rsh;, this can be achieved for
+example by creating a <filename>.rhosts</filename> file in your home folder
+with a list of trusted hosts (see the &rsh; manpage).
+</para>
+
+<para>
+With &ssh;, it can be achieved by copying your public key located in the file
+<filename>identity.pub</filename>, located in the
+<filename>$<envar>HOME</envar>/.ssh/</filename> folder to the server. In this
+case, the key must not be encrypted with a passphrase (see the &ssh; manpage and
+the &CVS;/<acronym>SSH</acronym> <acronym>FAQ</acronym> on
+SourceForge). If you are unsure about these issues, ask your system
+administrator.
+</para>
+
+</listitem>
+</varlistentry>
+
+<varlistentry>
+<term>pserver</term>
+
+<listitem>
+<para>
+The repository location looks like
+<filename>:pserver:username@host.url.org:/path/to/repository</filename>
+</para>
+
+<para>
+This method accesses the server via a special protocol with a relatively weak
+authentication (<literal>pserver</literal> stands for password
+authentication). Before you can use such a server, you need a username and
+password given by the &CVS; server administrator, and you have to login. Note
+that your &CVS; password authentication username does not necessarily match the
+system's username. Before accessing the &CVS; server, you will need to login.
+</para>
+
+<para>
+Open-source projects typically offer Anonymous CVS access to their
+sources. This means you can easily grab the latest sources, modify, and create
+patches (differences) against the repository without asking for a CVS account.
+As a general rule, Anonymous CVS uses password authentication (:pserver:), and
+is a read-only repository, not allowing you to upload your changes directly.
+</para>
+
+</listitem>
+</varlistentry>
+</variablelist>
+
+<para>
+Knowing the access method and location to the repository, you can add it
+to &cervisia;'s repositories list:
+</para>
+
+<procedure>
+<title>Adding a New Repository</title>
+
+<step><para>
+Open the <guilabel>Configure Access to Repositories</guilabel> dialog by
+choosing the <menuchoice><guimenu>Repository</guimenu>
+<guimenuitem>Repositories...</guimenuitem></menuchoice> menu item.
+</para></step>
+
+<step><para>
+Press the <guilabel>Add...</guilabel> button to open the
+<guilabel>Add Repository</guilabel> dialog.
+</para></step>
+
+<step><para>
+Enter the repository location in the <guilabel>Repository:</guilabel> text box.
+&cervisia; will automatically disable the areas of the dialog that are not
+relevant to the access method you entered.
+</para></step>
+
+<step><para>
+If you are using the ext method to access the repository, enter the remote shell
+you wish to use (&eg; &ssh;) in the <guilabel>Use remote shell (only for :ext:
+repositories):</guilabel> text box.
+</para></step>
+
+<step><para>
+Press <guibutton>OK</guibutton>. You will see the repository you just entered
+on the repositories list.
+</para></step>
+
+<step><para>
+If the access method to the repository you just entered is password
+authentication (pserver), you will need to login before connecting the server.
+Click the repository on the list to select it, and press the
+<guilabel>Login...</guilabel> button. Enter your password in the upcoming dialog.
+</para>
+<para>
+If you successfully enter your password, the <guilabel>Status</guilabel>
+column entry of the pserver repository will change from
+<guilabel>Not logged in</guilabel> to <guilabel>Logged in</guilabel>.
+</para></step>
+
+<step><para>
+Press <guibutton>OK</guibutton> to apply your modifications, or add another
+location to the list. &cervisia; will store as many locations as you like.
+</para></step>
+
+</procedure>
+
+</sect1>
+
+
+<sect1 id="importing">
+<title>Importing a Module Into the Repository</title>
+
+<para>
+In this section, we discuss how you can put a new project into the &CVS;
+repository. If you just want to work with an existing project which is already
+in a repository, you may skip this section.
+</para>
+
+<para>
+There are two ways to put a project into the &CVS;:
+</para>
+
+<itemizedlist>
+
+<listitem><para>
+Import the files and folders to a new <firstterm>module</firstterm>, using
+&cervisia;'s import dialog. Modules are the top folders in the &CVS; repository
+folder tree, and are used to separate and organize the different software
+projects inside the repository.
+</para></listitem>
+
+<listitem><para>
+Create an empty module and add the new files and folders manually. You will have
+more control, but it will probably take a little more time.
+</para></listitem>
+
+</itemizedlist>
+
+<important>
+<para>
+Keep in mind that &CVS; was initially designed to handle
+text files. Many features, like revision merging, creating differences in a
+readable form, &etc; are only performed to text files. This does not mean you
+cannot use CVS to keep binary files, it just means you have to
+<emphasis>explicitly tell CVS if it is a text or binary file</emphasis>. If
+you declare the wrong file type, you will experience problems with the &CVS;
+functionality for these files, and they may get corrupted.
+</para>
+</important>
+
+
+<para>
+Importing a project (as a new module) has some advantages: you will import all
+files and folders recursively, and the module will automatically be created
+for you. This makes importing large existing projects to the repository
+easier. However, there are some disadvantages: you cannot use &cervisia;'s import
+dialog to add files to existing modules, and you can either import the files
+as text or binary files. You can work around this limitation by creating a
+folder with files of only one of the types, or by informing the patterns
+of the files that should be ignored during the import process.
+</para>
+
+<para>
+For instance, suppose your project contains text files and some PNG images
+(binary files) only. You can tell &CVS; to ignore all files with the pattern
+<filename class="extension">*.png</filename> while importing the other files as
+text, or you can move the images to a separate folder, and then import
+the remaining files (as text files). Either way, you will have to
+<link linkend="checkingout">checkout</link> the newly imported module to a
+new working copy, copy the missing files and folders to it,
+<link linkend="addingfiles">add</link> and
+<link linkend="committingfiles">commit</link> them to the repository to complete
+the import process.
+</para>
+
+<para>
+As an alternative, you can add the files and folders manually, creating an empty
+module for them. To add an empty module to a repository, just create a new
+folder in the &CVS; repository root folder. The name of this new folder will be
+the name of the module. <link linkend="checkingout">Checkout</link> the new
+empty module. Then copy the files and folders to the working copy,
+<link linkend="addingfiles">add</link> and
+<link linkend="committingfiles">commit</link> to upload them to the &CVS;
+repository.
+</para>
+
+
+<figure id="screenshot-import" float="1">
+<title>A screenshot of &cervisia;'s import dialog</title>
+<mediaobject>
+<imageobject><imagedata format="PNG" fileref="import.png"/></imageobject>
+<textobject><phrase>A screenshot of &cervisia;'s import dialog</phrase></textobject>
+</mediaobject>
+</figure>
+
+<para>
+In <xref linkend="screenshot-import"/> you can see the dialog which helps you
+to <emphasis>import</emphasis> a project as a module. To access &cervisia;'s
+import dialog, choose the <menuchoice><guimenu>Repository</guimenu>
+<guimenuitem>Import...</guimenuitem></menuchoice>
+menu item.
+</para>
+
+<variablelist>
+
+<varlistentry>
+<term><guilabel>Repository:</guilabel> <xref linkend="co-repository" /></term>
+<listitem><para>
+Enter or select on the dropdown list the name of the &CVS; repository, also
+known as $<envar>CVSROOT</envar>. You must have write access to it, and the
+repository must be properly initialized. If the repository does not yet exist,
+you can create one choosing the
+<menuchoice>
+<guimenu>Repository</guimenu>
+<guimenuitem>Create...</guimenuitem>
+</menuchoice>
+menu item.
+</para>
+<para>
+The drop down box shows a
+list of the repositories you previously entered using the <guilabel>Configure
+Access to Repositories</guilabel> dialog box. If the repository is remote,
+make sure that authentication works. See <xref
+linkend="accessing-repository"/> for more information.
+</para></listitem>
+</varlistentry>
+
+<varlistentry>
+<term><guilabel>Module:</guilabel> <xref linkend="co-module" /></term>
+<listitem><para>
+The name of the module under which the project will be stored. After
+the import, the project can be checked out under this name. See
+<xref linkend="checkingout"/> for more information. This is also the name of
+the corresponding folder in the repository.
+</para></listitem>
+</varlistentry>
+
+<varlistentry>
+<term><guilabel>Working Folder:</guilabel></term>
+<listitem><para>
+The toplevel folder of the project you want to import. The import
+starts from this folder and goes down recursively.
+</para></listitem>
+</varlistentry>
+
+<varlistentry>
+<term><guilabel>Vendor tag:</guilabel> <xref linkend="co-vendortag" /></term>
+<listitem><para>
+The vendor tag is historically used for tracking third-party sources. Just use
+your user name if you have no better idea. It does not matter much what you
+enter here.
+</para></listitem>
+</varlistentry>
+
+<varlistentry>
+<term><guilabel>Release tag:</guilabel> <xref linkend="co-releasetag" /></term>
+<listitem><para>
+This tag is also historically used for importing different versions of
+third-party software. If you are not doing this, use the word
+<literal>start</literal> or a string <literal>FOO_1_0</literal> where
+<literal>FOO</literal> is the name of your project and <literal>1.0</literal>
+is the version number of the imported release.
+</para></listitem>
+</varlistentry>
+
+<varlistentry>
+<term><guilabel>Ignore files:</guilabel></term>
+<listitem><para>
+If you fill out this field, an additional <option>-I <replaceable>file names</replaceable></option>
+option is given go the <command>cvs import</command> command. This entry is
+interpreted as a whitespace-separated list of file name patterns which are
+ignored. In general, a cleaner and less error-prone way to control which files
+go into the repository is to create a folder with only the files which you
+want to import and start from that. Nevertheless, this entry may be useful if
+the project contains files which are by default ignored by &CVS;, &eg; files
+with the name <filename>core</filename>. In such a case, simply enter the
+character <literal>!</literal> in this field: this overrules &CVS;'s scheme of
+ignored files, see <xref linkend="ignoredfiles"/>.
+</para></listitem>
+</varlistentry>
+
+<varlistentry>
+<term><guilabel>Comment:</guilabel> <xref linkend="co-comment" /></term>
+<listitem><para>
+Use this field to record the comments you might have about the origin, use,
+development, &etc; of the files you are importing.
+</para></listitem>
+</varlistentry>
+
+<varlistentry>
+<term><guilabel>Import as binaries</guilabel></term>
+<listitem><para>
+If you check this box, all files are imported in binary mode, i.e. an argument
+<option>-kb</option> is given to <command>cvs import</command>.
+</para></listitem>
+</varlistentry>
+
+<varlistentry>
+<term><guilabel>Use file's modification as time of import</guilabel></term>
+<listitem><para>
+If you check this box, the time of import will be the file's modification time
+instead of the import time.
+</para></listitem>
+</varlistentry>
+
+</variablelist>
+
+
+<para>After you have filled out this form and confirmed by
+pressing <guibutton>OK</guibutton>, the following &CVS; command is used:</para>
+
+<screen><command>cvs</command> -d <co id="co-repository"></co><replaceable>repository</replaceable> import -m "<co id="co-comment"></co>" <co id="co-module"></co><replaceable>module</replaceable> <co id="co-vendortag"></co><replaceable>vendortag</replaceable> <co id="co-releasetag"></co><replaceable>releasetag</replaceable></screen>
+
+</sect1>
+
+
+<sect1 id="checkingout">
+<title>Checkout a Module From the Repository</title>
+<para>
+Now that you successfully defined your repository location, and imported the
+initial files to the repository, it is time to retrieve the module from the
+&CVS; repository, creating your working copy.
+</para>
+
+<para>
+You should also know the name of the <firstterm>branch</firstterm> or
+<firstterm>tag</firstterm> you want to use.
+</para>
+
+<para>
+Branches of a module are parallel versions of this module. A good real-life
+example of the use of this feature is the release of a software project. After a
+major release, there are bugs in the code that should be fixed, but people want
+to add new features to the application too. It is very hard to do both at the
+same time because new features usually introduce new bugs, making it hard to
+track down the old ones. To solve this dilemma, &CVS; lets you create a parallel
+version, that we will call the &quot;stable release branch&quot;, where you can
+only add bugfixes, leaving the main branch (HEAD) open for adding new features.
+</para>
+
+<para>
+Tags are used to mark a version of a project. &CVS; stamps one
+version of each file with the tag, so when you checkout or
+update to a specific tag, you will get always the same file versions.
+Therefore, in opposition to branches, tags are not dynamic: you cannot develop a
+tag. Tags are useful to mark releases, big changes in the code, &etc;.
+Using tags, you can easily return the project to a previous state, to reproduce and
+track bugs, generate the release code again, &etc;.
+</para>
+
+<figure id="screenshot-checkout" float="1">
+<title>A screenshot of &cervisia;'s checkout dialog</title>
+<mediaobject>
+<imageobject><imagedata format="PNG" fileref="checkout.png"/></imageobject>
+<textobject><phrase>A screenshot of &cervisia;'s checkout dialog</phrase></textobject>
+</mediaobject>
+</figure>
+
+<variablelist>
+
+<varlistentry>
+<term><guilabel>Repository:</guilabel></term>
+<listitem><para>
+The name of the &CVS; repository, also known as
+<filename><envar>$CVSROOT</envar></filename>. The drop-down box shows a
+list of the repositories you previously entered using the <guilabel>Configure
+Access to Repositories</guilabel> dialog box. If the repository is remote,
+make sure that authentication works. See <xref
+linkend="accessing-repository"/> for more information.
+</para></listitem>
+</varlistentry>
+
+<varlistentry>
+<term><guilabel>Module:</guilabel></term>
+<listitem><para>
+The name of the module to be checked out. If you are working with an existing
+repository, you can probably get this name from the system administrator;
+or, if it is an open-source repository, you can get the module names from the
+project web pages. If you want to create a new module from scratch using a local
+repository, just create a new folder in the local repository root folder. The
+name of the folder will be the same as the name of the empty module.
+</para>
+<para>
+Alternatively, if the repository has a
+<filename><envar>$CVSROOT</envar>/modules</filename> file, you can retrieve a
+list of available modules by pressing the <guibutton>Fetch list</guibutton>
+button.
+</para>
+<para>
+Note that it is possible to checkout any existing subfolder of the module,
+without retrieving the rest of the module. Just enter the path to the subfolder
+as well. For instance, if you want to get only the
+<filename class="directory">doc/cervisia</filename> subfolder of the kdesdk
+module, enter <filename class="directory">kdesdk/doc/cervisia</filename> in this
+field.
+</para></listitem>
+</varlistentry>
+
+<varlistentry>
+<term><guilabel>Branch tag:</guilabel></term>
+<listitem><para>
+The name of the branch or tag you want to check out. If you leave this field
+empty, &cervisia; will retrieve the main (HEAD) branch.
+</para></listitem>
+</varlistentry>
+
+<varlistentry>
+<term><guilabel>Working folder:</guilabel></term>
+<listitem><para>
+The folder under which the module should be checked out. Note that the
+the working copy toplevel folder is named after the module you are retrieving,
+unless you give it an alternative name in the <guilabel>Check out as:</guilabel>
+field.
+</para></listitem>
+</varlistentry>
+
+<varlistentry>
+<term><guilabel>Check out as:</guilabel></term>
+<listitem><para>
+This results in the working copy files being checked out to an alternative
+folder under the working folder rather than a folder named after the module.
+</para></listitem>
+</varlistentry>
+
+<varlistentry>
+<term><guilabel>Export only</guilabel></term>
+<listitem><para>
+If you check this box, the files will be exported rather than checked out.
+Exporting obtains a copy of the source for the module without the CVS
+administrative folders. For example, export may be used to prepare the
+source code for a release.
+</para></listitem>
+</varlistentry>
+
+</variablelist>
+
+</sect1>
+
+
+<sect1 id="mainscreen">
+<title>The Main Screen, Viewing File Status and Updating</title>
+<para>
+When you start &cervisia;, and open a working copy by choosing
+<menuchoice>
+<guimenu>File</guimenu>
+<guimenuitem>Open Sandbox...</guimenuitem>
+</menuchoice>,
+you can see two main areas in &cervisia;'s main window: the top one is a
+hierarchical (tree) view of the current working copy; the bottom area is
+used to display the &CVS; commands &cervisia; issues to perform its tasks, as
+well as the output generated by these commands.
+</para>
+
+<para>
+By default, &cervisia; does not display the files contained by the sub-folders,
+so you will have to click the folders you want to see. To display all files
+of the working copy, select
+<menuchoice>
+<guimenu>View</guimenu>
+<guimenuitem>Unfold File Tree</guimenuitem>
+</menuchoice>.
+To close back all folders from the working copy, choose
+<menuchoice>
+<guimenu>View</guimenu>
+<guimenuitem>Fold File Tree</guimenuitem>
+</menuchoice>.
+</para>
+
+<para>
+According to the settings in your
+<filename>.cvsignore</filename> files, the files you usually do not want to
+include into the repository - such as object files - are not shown in the tree
+view. For each file, you see its corresponding status. In the default setting,
+after opening the sandbox, this is "Unknown" because &cervisia; delays the
+fetching of information until you select the files and folders whose status you
+want to update or view and choose
+<menuchoice>
+<guimenu>File</guimenu>
+<guimenuitem>Update</guimenuitem>
+</menuchoice>
+or
+<menuchoice>
+<guimenu>File</guimenu>
+<guimenuitem>Status</guimenuitem>
+</menuchoice>. With this approach, you have a minimal
+amount of functionality available even if you do not have a permanent
+connection to the &CVS; server.
+</para>
+
+<figure id="screenshot-mainview" float="1">
+<title>A screenshot of &cervisia;'s main view</title>
+<mediaobject>
+<imageobject><imagedata format="PNG" fileref="mainview.png"/></imageobject>
+<textobject><phrase>A screenshot of &cervisia;'s main view</phrase></textobject>
+</mediaobject>
+</figure>
+
+<para>
+The commands in the File menu usually act only on the files which you have
+marked. You may also mark folders. Now choose
+<menuchoice>
+<guimenu>File</guimenu>
+<guimenuitem>Status</guimenuitem>
+</menuchoice> or press <keycap>F5</keycap>. &cervisia; issues a
+</para>
+
+<para>
+<screen><command>cvs update -n <replaceable>file names</replaceable></command></screen>
+</para>
+
+<para>
+command to get status information for the marked files. Note that &cervisia;
+goes recursively into subfolders only if you have the according option
+in the <guimenu>Settings</guimenu> menu set. According to the respective
+file's status, you now see an entry in the <guilabel>Status</guilabel> column:
+</para>
+
+<variablelist>
+
+<varlistentry>
+<term><guilabel>Locally Modified</guilabel></term>
+<listitem><para>
+This means you have modified the file compared to the
+version in the repository.
+</para></listitem>
+</varlistentry>
+
+
+<varlistentry>
+<term><guilabel>Locally Added</guilabel></term>
+<listitem><para>
+This means the file does not exist in the repository, but in
+your working copy and you have scheduled it for addition. The actual
+insertion into the repository only happens after a commit.
+</para></listitem>
+</varlistentry>
+
+<varlistentry>
+<term><guilabel>Locally Removed</guilabel></term>
+<listitem><para>
+This means you have scheduled the file for removal, but it
+still exists in the repository. The actual removal happens only after a
+commit.
+</para></listitem>
+</varlistentry>
+
+<varlistentry>
+<term><guilabel>Needs Update</guilabel></term>
+<listitem><para>
+This is shown if a newer version of the file exists in the
+repository, e.g. because someone committed a modification. Normally, you want
+to update this file so you have an up-to-date version in your folder.
+</para></listitem>
+</varlistentry>
+
+<varlistentry>
+<term><guilabel>Needs Patch</guilabel></term>
+<listitem><para>
+This is essentially the same as before; the difference is
+that in case of an update, the &CVS; server transfers only a patch
+instead of the whole file to you.
+</para></listitem>
+</varlistentry>
+
+<varlistentry>
+<term><guilabel>Needs Merge</guilabel></term>
+<listitem><para>
+Indicates that a merge of the revision of this file in your
+working copy with the version in the repository is necessary. This
+typically happens if you have made modifications to the file while
+someone else has committed his modifications. If you choose to update, the
+modifications in the repository are merged into your file. In case of a
+conflict (i.e. if someone else has changed some of the same lines like you)
+the new status is then "Conflict".
+</para></listitem>
+</varlistentry>
+
+<varlistentry>
+<term><guilabel>Up to Date</guilabel></term>
+<listitem><para>
+Indicates that the file is identical with the version in the
+repository.
+</para></listitem>
+</varlistentry>
+
+<varlistentry>
+<term><guilabel>Conflict</guilabel></term>
+<listitem><para>
+This is shown if this file still has conflict markers in it. Maybe
+you have previously updated the file and not resolved the conflicts.
+</para></listitem>
+</varlistentry>
+
+<varlistentry>
+<term><guilabel>Not In CVS</guilabel></term>
+<listitem><para>
+Indicates that the file is not registered in the &CVS;
+repository. If you want it to available for others, you should add it to the
+repository. If not, you may consider adding it to your
+<filename>.cvsignore</filename> file.
+</para></listitem>
+</varlistentry>
+
+</variablelist>
+
+<para>
+Now that you have got an overview of the current status of the CVS, you may
+want to do an update. Mark some files (or the root of the folder tree which
+is equivalent to marking all files in this folder). Now choose
+<menuchoice>
+<guimenu>File</guimenu>
+<guimenuitem>Update</guimenuitem>
+</menuchoice> (Of course, you could have chosen this at the beginning of
+the session). For some
+of the files the status may change now. Typically, files which had "Needs
+Patch" or "Needs Update" are updated. So the following new items are possible
+in the status column:
+</para>
+
+<variablelist>
+
+<varlistentry>
+<term><guilabel>Updated</guilabel></term>
+<listitem><para>
+Shown if the file was updated from the repository.
+</para></listitem>
+</varlistentry>
+
+<varlistentry>
+<term><guilabel>Patched</guilabel></term>
+<listitem><para>
+Indicates that the &CVS; server has sent a patch for this file and
+the patch has been successfully applied. If the patch was not successful
+because there was a conflict between your modifications and those someone else
+committed to the repository, the status is now <guilabel>Conflict</guilabel>.
+</para></listitem>
+</varlistentry>
+
+</variablelist>
+
+<para>
+You may have noticed that according to the status of the file, its row has a
+different color. The colors are chosen to somehow reflect the priority of the
+status. For example, a file with a conflict is marked red to show you that you
+have to resolve a conflict before you can continue working with the file. If
+your folder contains a high number of files, you may nevertheless lose the
+overview. To get more concise information about which files have an unusual
+status, simply click on the header of the <guilabel>Status</guilabel>
+column. The file list is then sorted by priority, so you have all important
+information at the top of the list. To get back to the alphabetically sorted
+view, click on the header of the <guilabel>File name</guilabel> column.
+</para>
+
+</sect1>
+
+</chapter>
+
+
+<chapter id="workingwithfiles">
+<title>Working With Files</title>
+
+<para>
+All commonly used &CVS; functionality is directly available in &cervisia;'s
+main view. Commands usually act on several files at once, namely all which
+currently selected. If the selection includes folders, its interpretation
+depends on the settings made under the <guimenu>Settings</guimenu> menu. For
+example, if <menuchoice><guimenu>Settings</guimenu><guimenuitem>Commit and
+Remove Recursively</guimenuitem></menuchoice> is checked and you choose
+<menuchoice><guimenu>File</guimenu><guimenuitem>Commit...</guimenuitem></menuchoice>
+while a folder is selected, then all files in the tree under that folder
+are committed. Otherwise, only the regular files in the folder itself are
+affected.
+</para>
+
+<figure id="screenshot-popup" float="1">
+<title>A screenshot of &cervisia;'s context menu</title>
+<mediaobject>
+<imageobject><imagedata format="PNG" fileref="popup.png"/></imageobject>
+</mediaobject>
+</figure>
+
+<para>
+The most used actions are also available by right clicking the files in the tree
+view, through the context menu. <xref linkend="screenshot-popup" /> shows
+&cervisia;'s main window pop-up menu.
+</para>
+
+<para>
+You can simply edit a file by double-clicking on it or selecting it and pressing
+&Enter;. This starts the default application that handles that
+file type (the default application for each file type is a KDE wide setting). If
+the default application is not the one you want to use, you can right click the
+file and choose the
+<menuchoice>
+<guisubmenu>Edit With</guisubmenu>
+</menuchoice>
+submenu, and select one of the other applications that handle that file type.
+</para>
+
+<sect1 id="addingfiles">
+<title>Adding Files</title>
+
+<para>
+Adding files to a project requires two steps: first, the files must be
+registered with &CVS;, or in other words,
+<emphasis>added to the repository</emphasis>. This is necessary, but not
+sufficient. In order to actually put the files into the repository, you must
+<emphasis>commit</emphasis> them. This procedure has an important advantage:
+you can commit the files together with modifications to other parts of the
+project. When doing this, one can easily see (&eg; in commit emails) that all
+these changes are part of a whole.
+</para>
+
+<para>
+To this end, mark all files to be added in &cervisia;'s
+main view. Then, choose <menuchoice><guimenu>File</guimenu><guimenuitem>Add to
+Repository...</guimenuitem></menuchoice>, or right click the marked files and
+choose <guimenuitem>Add to Repository...</guimenuitem>. The
+<guilabel>CVS Add</guilabel> dialog will appear, listing the files you marked, and
+asks for confirmation. Press <guibutton>OK</guibutton>.
+</para>
+
+<para>&cervisia; issues a command</para>
+
+<para>
+<screen><command>cvs add <replaceable>file names</replaceable></command></screen>
+</para>
+
+<para>
+If the operation was successful, the status column should have "Added to
+repository" for the added files.
+</para>
+
+<warning><para>
+&CVS; is not designed to provide meaningful revision control for binary
+files. For example, merging binary files normally does not make
+sense. Furthermore, by default &CVS; performs keyword expansion (&eg; on the
+string <literal>&dollar;Revision: 1.6 &dollar;</literal>) when a file is committed. In binary
+files, such replacements may corrupt the file and make it completely
+unusable.
+</para></warning>
+
+<para>
+In order to switch the above behavior off, you should commit binary files
+(or other files, like Postscript or PNG images) by choosing
+<menuchoice><guimenu>File</guimenu><guimenuitem>Add Binary...</guimenuitem></menuchoice>.
+The <guilabel>CVS Add</guilabel> dialog will appear, listing the binary files
+you marked, and asks for confirmation. Press <guibutton>OK</guibutton>.
+</para>
+
+<para>
+&cervisia; issues a command
+</para>
+
+<para>
+<screen><command>cvs add -kb <replaceable>file names</replaceable></command></screen>
+</para>
+
+</sect1>
+
+
+<sect1 id="removingfiles">
+<title>Removing Files</title>
+
+<para>
+Like adding files, removing files is done in two steps: First, the files have
+to be registered as removed by choosing
+<menuchoice><guimenu>File</guimenu><guimenuitem>Remove From
+Repository...</guimenuitem></menuchoice> or right clicking the marked files and
+choosing <guimenuitem>Remove From Repository...</guimenuitem> from the context
+menu. The <guilabel>CVS Remove</guilabel> dialog will appear, listing the files
+you marked, and asking for confirmation. Press <guibutton>OK</guibutton>.
+&cervisia; issues the command
+</para>
+<para>
+<screen><command>cvs remove -f <replaceable>file names</replaceable></command></screen>
+</para>
+
+<para>
+After that, this modification to the sandbox has to be committed, possibly
+together with other modifications to the project.
+</para>
+
+<note><para>
+The above command only works if the file is up-to-date. Otherwise, you get an
+error message. This behavior is sensible: If you have modified the file
+compared to the version in the repository, or if someone else has made any
+modifications, you will first want to check if you really want to discard
+them.
+</para></note>
+
+</sect1>
+
+
+<sect1 id="addingremovingdirs">
+<title>Adding and Removing Folders</title>
+
+<para>
+Folders are handled fundamentally different from ordinary files by
+&CVS;. They are not under revision control, i.e. you cannot tell which
+folders existed in the project at a certain time. Furthermore, folders
+can never be explicitly removed (except by removing them directly in the
+repository).
+</para>
+
+<para>
+As a substitute, &CVS; follows the convention that a folder is "non-existent"
+in a version of the project if it is empty. This convention can be
+enforced by using the option <option>-P</option> to <command>cvs
+update</command> and <command>cvs checkout</command>. This option can be set
+in the menu <menuchoice><guimenu>Settings</guimenu><guimenuitem>Prune Empty
+Folders on Update</guimenuitem></menuchoice>.
+</para>
+
+<para>
+A folder can be added to the repository choosing
+<menuchoice><guimenu>File</guimenu><guimenuitem>Add to
+Repository...</guimenuitem></menuchoice> or right clicking the marked folder and
+choosing <guimenuitem>Add to Repository...</guimenuitem> from the context menu.
+Note that in contrast to adding files, adding folders does not require a commit
+afterwards. &cervisia; issues the command
+</para>
+
+
+<para>
+<screen><command>cvs add <replaceable>dirname</replaceable></command></screen>
+</para>
+
+</sect1>
+
+
+<sect1 id="committingfiles">
+<title>Committing Files</title>
+
+<para>
+When you have made a certain number of changes to your working copy, and you
+want other developers to have access to them, you <emphasis>commit</emphasis>
+them. With a commit, you place your versions of the modified files as new
+revisions into the repository. A subsequent update by another developer will
+bring your modifications into their working copy.
+</para>
+
+<para>
+In order to commit a couple of files, select them in &cervisia;'s main view and
+choose
+<menuchoice><guimenu>File</guimenu><guimenuitem>Commit...</guimenuitem></menuchoice>
+or right click the marked files and choose
+<guimenuitem>Commit...</guimenuitem> from the context menu.
+</para>
+
+<figure id="screenshot-commit" float="1">
+<title>A screenshot of &cervisia;'s commit dialog</title>
+<mediaobject>
+<imageobject><imagedata format="PNG" fileref="commit.png"/></imageobject>
+</mediaobject>
+</figure>
+
+<para>
+You get a dialog that shows you a list of the selected files on the top section
+and a log message for your changes below. &cervisia; helps you in several ways
+to find a meaningful log message: first, in the file list you can double-click
+a file or press <keycap>Return</keycap> in order to see the changes you have
+made to the file. Second, it gives you a list of log messages you have
+previously used in a combo box. Third, this dialog is integrated with
+&cervisia;'s changelog editor described below. When you have finished the
+dialog, the command
+</para>
+
+<para>
+<screen><command>cvs commit -m <replaceable>message</replaceable> <replaceable>file names</replaceable></command></screen>
+</para>
+
+<para>
+is used.
+</para>
+
+
+<note><para>
+A common error you may encounter when committing is <errorname>Up-to-date check
+failed</errorname>. This indicates that someone has committed changes to the
+repository since you last updated; or, more technically, that your
+<literal>BASE</literal> revision is not the newest on its branch. In such a
+case, &CVS; refuses to merge your modifications into the repository. The
+solution is to update, resolve any conflicts and commit again. Of course, if
+you are working on a software project, it is normally good style to check if
+the program still works after you have updated - after all, there could be bad
+interactions between your modifications and the other modifications which
+break the code.
+</para></note>
+
+<note>
+<para>
+Another popular mistake results in the error message <errorname>Sticky tag 'X'
+for file 'X' is not a branch</errorname>. This happens if you try to commit a
+file which you have previously brought to a certain revision or tag with the command
+</para>
+<para>
+<screen><prompt>%</prompt><userinput>cvs update -r X</userinput></screen>
+</para>
+<para>
+(which is &eg; used by the menu item
+<menuchoice><guimenu>Advanced</guimenu><guimenuitem>Update to
+Tag/Date...</guimenuitem></menuchoice>). In such a case, the tag on the file
+gets sticky, i.e. further updates do not bring you to the newest revision on
+the branch. If you want to commit further revisions to the branch, you have to
+update to the branch tag before you do further commits.
+</para>
+</note>
+
+<para>
+With &cervisia;, it is quite easy to maintain a ChangeLog file that is
+compliant with the format laid out in the GNU coding guidelines. To use it,
+choose <menuchoice><guimenu>File</guimenu><guimenuitem>Insert ChangeLog
+Entry...</guimenuitem></menuchoice>. If a file with the name
+<filename>ChangeLog</filename> exists in the toplevel folder of your
+sandbox, this file will be loaded and you have the possibility to edit it. To
+this end, at the top of the file, an entry with the current date and your user
+name (which can be configured as described in <xref
+linkend="customize-general"/>) is inserted. When you finish the dialog this
+dialog by clicking <guibutton>OK</guibutton>, the next commit dialog you open
+will have the log message set to the message you last entered in the ChangeLog.
+</para>
+
+</sect1>
+
+
+<sect1 id="resolvingconflicts">
+<title>Resolving Conflicts</title>
+
+<para>
+Conflicts may occur whenever you have made changes to a file which was also
+modified by another developer. The conflict is detected by &CVS; when you
+update the modified file; &CVS; then tries to merge the modifications committed
+by the other developer into your working copy. The merge fails if both your
+and his modifications are in overlapping parts of the file, and the &CVS;
+server issues an error message.
+</para>
+
+<para>
+In &cervisia;'s main view, files with conflicts are indicated with "Conflict"
+in the status column and with a red color. It is your job now to resolve these
+conflicts before you commit the file. &CVS; will refuse to commit any files with
+conflicts until they have been edited. From the main view, you can of
+course resolve conflicts the traditional way: just double-click the file in
+question and edit it with your favorite editor.</para>
+
+<para>
+&CVS; marks the conflicting changes by placing marks in the middle
+of the files, in the following manner:</para>
+
+<screen>
+&lt;&lt;&lt;&lt;&lt;&lt;&lt;
+Changes in your working copy
+=======
+Changes in the repository
+&gt;&gt;&gt;&gt;&gt;&gt;&gt; revision_number
+</screen>
+
+<para>You should replace this whole block with the new merged version. Of
+course, you have a great amount of freedom when resolving a
+set of conflicts: for each conflict you can decide to take one of the two
+alternative versions. You can also decide that both approaches are broken
+and rewrite a whole routine or the complete file from scratch.
+</para>
+
+<para>
+Fortunately, &cervisia; offers a nicer interface for handling these conflicts.
+This does not mean that you will never need to manually edit the files, but
+at least can eliminate the need to do so for the trivial conflict resolution.
+To use &cervisia;'s <guilabel>CVS Resolve</guilabel> dialog choose
+<menuchoice><guimenu>File</guimenu><guimenuitem>Resolve...</guimenuitem></menuchoice>
+or right click the marked file and choose
+<guimenuitem>Resolve...</guimenuitem> from the context menu.
+</para>
+
+<figure id="screenshot-resolve" float="1">
+<title>A screenshot of &cervisia;'s resolve dialog</title>
+<mediaobject>
+<imageobject><imagedata format="PNG" fileref="resolve.png"/></imageobject>
+<textobject><phrase>A screenshot of &cervisia;'s resolve dialog</phrase></textobject>
+</mediaobject>
+</figure>
+
+<para>
+On the top of the dialog, you see <guilabel>Your version (A)</guilabel> of the
+file on the left hand side and the version in the repository, <guilabel>Other
+version (B)</guilabel>, on the right hand side. The differences
+between them are marked in red color. Below these two versions, you can see
+the <guilabel>Merged version</guilabel>. The merged version reflects what that
+section will be in your working copy if you press the <guibutton>Save</guibutton>
+button.
+</para>
+
+<para>
+You can go back and forward between the conflicting sections by pressing
+<guibutton>&lt;&lt;</guibutton> and <guibutton>&gt;&gt;</guibutton>. In the
+lower middle of the dialog you can see which section is currently marked. For
+example, <literal>2 of 3</literal> means that you are currently at the second
+differing section of 3 total.
+</para>
+
+<para>
+Now can can decide section by section which version you want to have in the
+merged file. By pressing <guibutton>A</guibutton>, you take over the version you
+edited. By pressing <guibutton>B</guibutton>, you take over the version from the
+repository. By pressing <guibutton>A+B</guibutton>, both versions will be added,
+and your version will come first. <guibutton>B+A</guibutton> yields the same
+result, but the order will be different: first the repository version, then
+yours.
+</para>
+
+<para>
+If you are not happy with any of these versions, press
+<guibutton>Edit</guibutton> to open a simple text editor where you can
+edit the section. When you are finished editing, press <guibutton>OK</guibutton>
+to return to the <guilabel>CVS Resolve</guilabel> dialog and resume solving
+conflicts. You will see the section you just edited in the
+<guilabel>Merged version</guilabel>, with your modifications.
+</para>
+
+<para>
+To save your modifications, overwriting the working copy version, press
+<guibutton>Save</guibutton>. Note that this will save the choices not only the
+section you are currently viewing, but all sections in the file. If you want to
+save it to another file, press <guibutton>Save As...</guibutton>.
+Press <guibutton>Close</guibutton> to exit the dialog. If you close the dialog
+without saving, the changes you made will be lost.
+</para>
+
+</sect1>
+
+</chapter>
+
+
+<chapter id="obtaininginformation">
+<title>Obtaining Information About Files and Creating Patches</title>
+
+<sect1 id="diff">
+<title>Watching Differences Between Revisions</title>
+
+<para>
+There are several places in &cervisia; where you can ask for a window showing
+the differences between revisions of a file:
+</para>
+
+<itemizedlist>
+
+<listitem><para>
+In the main view, you can choose
+<menuchoice><guimenu>View</guimenu><guimenuitem>Difference to
+Repository (BASE)...</guimenuitem></menuchoice>. This is based on the command
+<command>cvs diff</command> and shows you the differences between the version
+in your sandbox and the version to which you last updated (also known as
+<literal>BASE</literal>). This is in particular useful just before you commit
+a file, so you can find an appropriate log message.
+</para></listitem>
+
+<listitem><para>
+You can view the differences between the version in your sandbox and the version
+in the main development branch (also called <literal>HEAD</literal>) by choosing
+<menuchoice><guimenu>View</guimenu>
+<guimenuitem>Difference to Repository (HEAD)...</guimenuitem></menuchoice>.
+</para></listitem>
+
+<listitem><para>
+You can view the differences between the last two revisions of the selected file
+choosing <menuchoice><guimenu>View</guimenu>
+<guimenuitem>Last Change...</guimenuitem></menuchoice>.
+</para></listitem>
+
+<listitem><para>
+You can access the <guimenuitem>Difference to Repository (BASE)...</guimenuitem>,
+<guimenuitem>Difference to Repository (HEAD)...</guimenuitem> and
+<guimenuitem>Last Change...</guimenuitem> menu items from the main view context
+menu, by right-clicking the file you want to view.
+</para></listitem>
+
+<listitem><para>
+In the dialog that is shown when a you commit a set of files, you can request
+a difference window by selecting a file name in the selection list, either by
+double-clicking it or by pressing <keycap>Return</keycap>. This is quite
+similar to using <menuchoice><guimenu>View</guimenu><guimenuitem>Difference
+to Repository (BASE)...</guimenuitem></menuchoice> with the respective file in the
+main view.
+</para></listitem>
+
+<listitem><para>
+In the Browse Logs dialog, you can mark two revisions of a file and request a
+dialog showing the differences between them (see <xref linkend="browsinglogs"/>).
+</para></listitem>
+
+</itemizedlist>
+
+<para>
+As you may have expected, &cervisia; does not just dump the output of the
+<command>diff</command> command into your terminal, but shows you a graphical
+view as seen in <xref linkend="screenshot-log"/>.
+</para>
+
+<figure id="screenshot-log" float="1">
+<title>A screenshot of &cervisia;'s diff dialog</title>
+<mediaobject>
+<imageobject><imagedata format="PNG" fileref="diff.png"/></imageobject>
+<textobject><phrase>A screenshot of &cervisia;'s diff dialog</phrase></textobject>
+</mediaobject>
+</figure>
+
+<para>
+The text in the dialog is an improved variant of the text given by the diff
+command with the <option>-u</option> option. You can see the differing
+versions in two windows, with lines arranged such that you can do a
+side-by-side comparison. That means, where text has been added or deleted,
+the respective window shows empty lines with the marker
+<literal>+++++</literal> at the left hand side. Elsewhere, you can see the
+running number of each line in the left column.
+</para>
+
+<para>
+In the second column in the right window, you can see which kind of change has
+been made. Possible types are <literal>Add</literal>,
+<literal>Delete</literal> and <literal>Change</literal>. The respective lines
+are marked in blue, green and red color. In the middle of the dialog a
+compressed image of the color markers is shown. In this way, you can get a
+quick overview of the overall changes to the file. You can also use the
+position of the colored regions in the compressed image as an orientation when
+you using the scroll bars.
+</para>
+
+<para>
+Normally, the scrollbars at the left and the right window are synchronized,
+i.e. if you scroll on the left hand side, the right hand side is scrolled by
+the same amount. You can change this by checking the box
+<guibutton>Synchronize scroll bars</guibutton>.
+</para>
+
+<para>
+For information about how to customize the diff dialog, see <xref linkend="customize-diff"/>.
+</para>
+
+</sect1>
+
+<sect1 id="creatingpatches">
+<title>Creating Patches</title>
+
+<para>
+Sometimes you want to offer your modifications for review, before committing them,
+or you do not have write access to the repository (therefore you cannot
+commit). &CVS; offers standard formats to share the modifications in
+your working copy, so other people can review your changes, test them in their
+working copy and apply them to the &CVS; repository. A file containing these
+differences is called a <firstterm>patch</firstterm>, and is generated by the
+<command>cvs diff</command> command, in the same way as the differences in
+<xref linkend="diff"/>. Sharing patches instead of sets of files requires less
+bandwidth, and patches are easier to handle, as you can send only one patch
+file containing all the differences from many source files.
+</para>
+
+<para>
+&cervisia; gives you access to this feature by choosing
+<menuchoice><guimenu>Advanced</guimenu>
+<guimenuitem>Create Patch Against Repository...</guimenuitem></menuchoice>.
+</para>
+
+<important><para>
+The <guimenuitem>Create Patch Against Repository...</guimenuitem> action
+creates a patch with all modifications in all files in your working copy
+(sandbox) against the <literal>BASE</literal> repository. Therefore, the
+selection of files in the main view does not affect the patch that will be
+generated.
+</para></important>
+
+<para>
+Another possibility is to select one file in the main view and choose
+<guimenuitem>Browse Log...</guimenuitem> from the <guimenu>View</guimenu> menu
+or right click the marked file and choose
+<guimenuitem>Browse Log...</guimenuitem> from the context menu, in order to open
+the <link linkend="browsinglogs">Browse log dialog</link>. Now, select the
+version you want to create a patch against, as revision &quot;A&quot; and press
+the button <guilabel>Create Patch...</guilabel>. This will generate a patch with
+the differences between the <emphasis>marked file</emphasis> in your working
+copy and the version selected as revision &quot;A&quot;.
+</para>
+
+<para>
+Before generating the patch, &cervisia; displays a dialog allowing you to
+configure the output format.
+</para>
+
+<figure id="screenshot-patch" float="1">
+<title>A screenshot of &cervisia;'s patch dialog</title>
+<mediaobject>
+<imageobject><imagedata format="PNG" fileref="patch.png"/></imageobject>
+<textobject><phrase>A screenshot of &cervisia;'s patch dialog</phrase></textobject>
+</mediaobject>
+</figure>
+
+<variablelist>
+
+<varlistentry>
+<term><guilabel>Output Format</guilabel></term>
+<listitem><para>
+There are three output formats available:
+</para>
+<para>
+<guilabel>Normal</guilabel>: a format that can be used to cause the ed editor
+to automatically make another copy of the old file match the new file. In
+the normal output format, the characters &lt; and &gt; mark the changes, and
+there is no context information.
+</para>
+<para>
+<guilabel>Unified</guilabel>: the most used format for
+exchanging patches. The unified format uses context lines in addition to line
+numbers to record the differences. This makes the process of
+applying patches more robust. This format displays the
+differences in a compact and readable form, with a header for each file
+involved, and separate sections (chunks) for each difference. The context lines
+available for each difference make reading the modifications easier. In
+the unified output format, the characters + and - mark the changes.
+</para>
+<para>
+<guilabel>Context</guilabel>, which presents the same information as the unified
+format, but in a less compact way. In the context output format, the character !
+marks the changes.
+</para></listitem>
+</varlistentry>
+
+<varlistentry>
+<term><guilabel>Number of context lines:</guilabel></term>
+<listitem><para>
+Set here the number of context lines for the unified or context output formats.
+This option is not available for the normal output format, as in this format
+no context information is recorded. More context information makes reading the
+raw output easier, and applying the patch more precise, but increases the patch
+size. It is recommended to use at least two context lines for proper patch
+operation.
+</para></listitem>
+</varlistentry>
+
+<varlistentry>
+<term><guilabel>Ignore Options</guilabel></term>
+<listitem><para>
+Check here the changes that should not be considered as differences when
+generating the patch.
+</para></listitem>
+</varlistentry>
+
+</variablelist>
+
+
+<para>
+After setting the output format, &cervisia; generates the patch and displays the
+<guilabel>Save As</guilabel> dialog. Enter in this dialog the file name
+and location of the patch file.
+</para>
+
+
+</sect1>
+
+<sect1 id="annotate">
+<title>Watching an Annotated View of a File</title>
+
+<para>
+With the command <command>cvs annotate</command>, &CVS; offers the possibility
+to see - for each line in a file - who has modified a line the most recently.
+This view may be helpful in order to find out who has introduced a change in
+the behavior of a program or who should be asked about some change or bug in
+the code.
+</para>
+
+<para>
+&cervisia; gives you access to this feature, but it further enriches the
+information in an interactive way. You obtain an annotate view by choosing
+<menuchoice><guimenu>View</guimenu><guimenuitem>Annotate...</guimenuitem></menuchoice>.
+Another possibility is to press the button <guilabel>Annotate</guilabel> in
+the <link linkend="browsinglogs">Browse log dialog</link>, in which you can
+select which version of the file you want to display.
+In <xref linkend="screenshot-annotate"/> you can see a screenshot of the
+dialog.
+</para>
+
+<figure id="screenshot-annotate" float="1">
+<title>A screenshot of &cervisia;'s annotate dialog</title>
+<mediaobject>
+<imageobject><imagedata format="PNG" fileref="annotate.png"/></imageobject>
+<textobject><phrase>A screenshot of &cervisia;'s annotate dialog</phrase></textobject>
+</mediaobject>
+</figure>
+
+<para>
+In the annotate dialog, you see in a window the latest version of the selected
+file (or the revision &quot;A&quot; version, in case you launched the annotate
+dialog from the the <link linkend="browsinglogs">Browse log dialog</link>). In
+the columns before the text, you get some information related to the
+latest change in each line. In the first column the line number is
+displayed. In the second column you see the name of the author and
+revision number. Finally, in the third column you see the actual content of that
+line.
+</para>
+
+<para>
+Consequently, when a certain line appears strange to you or you assume a bug
+there, you can immediately see who is responsible for that line. But not only
+that, you can also find out <emphasis>why</emphasis> that line was
+changed. To this end, move the mouse cursor over the respective revision
+number. Then a tooltip appears that shows the log message and the date of the
+change.
+</para>
+
+</sect1>
+
+
+<sect1 id="browsinglogs">
+<title>Browsing &CVS; Logs</title>
+
+<para>
+When you mark one file in the main view and choose <guimenuitem>Browse
+Log...</guimenuitem> from the <guimenu>View</guimenu> menu
+or right click the marked file and choose
+<guimenuitem>Browse Log...</guimenuitem> from the context menu, the
+<guilabel>CVS Log</guilabel> dialog is shown (if you mark more than one, nothing
+happens, as &cervisia; can only generate and parse the log for one file at a
+time). This dialog offers functionality that is beyond viewing the file's
+history. Using it as a version browser you can:
+</para>
+
+<itemizedlist>
+
+<listitem><para>
+View the revision, author, date, branch, commit message, and tags for each
+version of the marked file.
+</para></listitem>
+
+<listitem><para>
+View a graphical tree representation showing the branching and tagging of the
+marked file.
+</para></listitem>
+
+<listitem><para>
+View any version of the marked file (with the default application).
+</para></listitem>
+
+<listitem><para>
+Watch an annotated view of any version of the marked file
+</para></listitem>
+
+<listitem><para>
+View the differences between any pair of versions of the marked file,
+including pairs with the current working copy version of the marked file.
+</para></listitem>
+
+<listitem><para>
+Create patches containing the differences between any pair of versions of the marked
+file, including pairs with the current working copy version of the marked file.
+</para></listitem>
+
+</itemizedlist>
+
+<figure float="1">
+<title>A screenshot of &cervisia;'s browse logs dialog</title>
+<mediaobject>
+<imageobject><imagedata format="PNG" fileref="logtree.png"/></imageobject>
+<textobject><phrase>A screenshot of &cervisia;'s browse logs dialog</phrase></textobject>
+</mediaobject>
+</figure>
+
+<para>
+You can choose to see the history as provided by the <command>cvs
+log</command> command (<guilabel>CVS Output</guilabel>), as a
+<guilabel>Tree</guilabel>, or in <guilabel>List</guilabel> form. What you prefer
+is of course a matter of taste and it depends on what information you are
+interested in. The tree is an intuitive representation of what has been done
+on different branches by which authors. As tooltips, you can see the corresponding
+log messages. The list is by its nature linear and, therefore, does not give an
+immediate view of branches; on the other hand, it concentrates more otherwise
+relevant information on less screen estate, namely the time of each change of
+the file and the first part of the log message. The CVS output information is
+complete, but long, and difficult to read. To alleviate these problems, you
+have the ability to search the text of the CVS output, by pressing the
+<guibutton>Find...</guibutton> button.
+</para>
+
+<para>
+To obtain more information about a certain revision, you can click on it
+either in the list or the tree view. The fields in the middle of the dialog
+are then filled with the complete information provided by <command>cvs
+log</command>. You can mark two revisions, called &quot;A&quot; and &quot;B&quot;, which are
+relevant if you make use of further features provided by the buttons.
+Revision &quot;A&quot; can be chosen with the left mouse button, revision &quot;B&quot;
+with the middle one. In the list view, you can also
+navigate with with your cursor keys. In order to mark revisions &quot;A&quot; and &quot;B&quot;,
+use the keybindings <keycombo><keycap>Ctrl</keycap><keycap>A</keycap></keycombo>,
+<keycombo><keycap>Ctrl</keycap><keycap>B</keycap></keycombo>, respectively.
+Using the <guilabel>CVS Output</guilabel> view, you can click on the
+<guilabel>Select for revision A</guilabel> and <guilabel>Select for
+revision B</guilabel> to mark the revisions.
+</para>
+
+<para>
+If you press the <guibutton>Annotate</guibutton> button, you get a dialog
+showing the text of file belonging to the revision marked as &quot;A&quot;.
+Every line is prefixed with the information about who edited this last time,
+and at which revision this happened. You can get more information about viewing
+annotated versions in <xref linkend="annotate" />.
+</para>
+
+<para>
+If you press the <guibutton>Diff</guibutton> button, a <command>cvs diff</command>
+call is issued and you get a dialog in which all the modifications between the
+two marked revisions are shown. If you mark revision &quot;A&quot;, but not
+revision &quot;B&quot;, &cervisia; will generate the modifications between
+the file version marked as revision &quot;A&quot; and the working copy version
+of the file. This allows you to view the differences between your version of the
+file and any version available in &CVS;. To make it easy to see the changes,
+different colors are used to mark lines which have been added, removed or simply
+changed. You can get more information about viewing differences in
+<xref linkend="diff" />.
+</para>
+
+<para>
+If you press the <guibutton>Create Patch...</guibutton> button, you get a dialog
+in which you can set the format options for generating a file containing all the
+modifications between the two marked revisions which are shown. If you mark
+revision &quot;A&quot;, but not revision &quot;B&quot;, &cervisia; will generate
+the modifications between the file version marked as revision &quot;A&quot; and
+the working copy version of the file. This allows you to generate a patch, or
+difference file, between your version of the file and any version available in
+&CVS;. After configuring the format of the patch in the dialog, and pressing
+<guibutton>OK</guibutton>, a <command>cvs diff</command> command is issued to
+generate the difference file. A <guilabel>Save As</guilabel> dialog will pop up.
+Enter the file name and location of the patch file &cervisia; generated, in order
+to save it. You can get more information about creating patches, and the patch
+format options in <xref linkend="creatingpatches" />.
+</para>
+
+<para>
+If you press the <guibutton>View</guibutton> button, &cervisia; will retrieve
+the revision marked as &quot;A&quot; and display it using the default
+application for its file type.
+</para>
+
+<para>
+Press the <guibutton>Close</guibutton> button to leave the dialog and return to
+the main view.
+</para>
+
+
+<para>
+To generate the log that is the base for the <guilabel>CVS Log</guilabel>
+dialog, &cervisia; issues the following command:
+</para>
+
+
+<para>
+<screen><command>cvs log <replaceable>file name</replaceable></command></screen>
+</para>
+
+</sect1>
+
+<sect1 id="browsinghistory">
+<title>Browsing the History</title>
+
+<para>
+If the used repository has logging enabled, &cervisia; can present you a
+history of certain events like checkouts, commits, rtags, updates and
+releases. Choose <guimenuitem>History</guimenuitem> from the
+<guimenu>View</guimenu> menu, and &cervisia; will issue the command
+</para>
+
+<para>
+<screen><command>cvs history -e -a</command></screen>
+</para>
+
+<note><para>
+This fetches the complete logging file from the server, i.e. a list of
+the events for all users and all modules. This can be a huge amount of data.
+</para></note>
+
+<para>
+Now you can see the list of events, sorted by date. In the second column, the
+type of the event is shown:
+</para>
+
+<itemizedlist>
+
+<listitem><para>
+Checkout - The user who is displayed in the 'Author' column
+has checked out a module
+</para></listitem>
+
+<listitem><para>
+Tag - A user has used the command <command>cvs rtag</command>. Note that the
+usage of <command>cvs tag</command> (as done by &cervisia;'s
+<menuchoice><guimenu>Advanced</guimenu><guimenuitem>Tag/Branch...</guimenuitem></menuchoice>
+command) is not recorded in the history database. This has historical reasons
+(see the &CVS; <acronym>FAQ</acronym>).
+</para></listitem>
+
+<listitem><para>
+Release - A user has released a module. Actually, this command is rarely used
+and not of much value.
+</para></listitem>
+
+<listitem><para>
+Update, Deleted - A user has made an update on a file which was deleted in the
+repository. As a consequence, the file was deleted in his working copy.
+</para></listitem>
+
+<listitem><para>
+Update, Copied - A user has made an update on a file. A new version was copied
+into working copy.
+</para></listitem>
+
+<listitem><para>
+Update, Merged - A user has made an update on a file. The modifications in the
+repository version on the file were merged into his working copy.
+</para></listitem>
+
+<listitem><para>
+Update, Conflict - A user has made an update on a file, and a conflict with
+his own modifications was detected.
+</para></listitem>
+
+<listitem><para>
+Commit, Modified - A user committed a modified file.
+</para></listitem>
+
+<listitem><para>
+Commit, Added - A user added a file and committed it.
+</para></listitem>
+
+<listitem><para>
+Commit, Removed - A user removed a file and committed it.
+</para></listitem>
+
+</itemizedlist>
+
+<figure id="screenshot-history" float="1">
+<title>A screenshot of &cervisia;'s history dialog</title>
+<mediaobject>
+<imageobject><imagedata format="PNG" fileref="history.png"/></imageobject>
+<textobject><phrase>A screenshot of &cervisia;'s history dialog</phrase></textobject>
+</mediaobject>
+</figure>
+
+<para>
+You can sort the list by other criteria simply by clicking on the respective
+column header. In order to sort out the history entries you are interested in,
+there are various filter options activated by check boxes:
+</para>
+
+<itemizedlist>
+<listitem><para>Show commit events - shows commits</para></listitem>
+<listitem><para>Show checkout events - shows checkouts</para></listitem>
+<listitem><para>Show tag events - shows taggings</para></listitem>
+<listitem><para>Show other events - shows events not included in the above</para></listitem>
+<listitem><para>Only user - shows only events caused by a certain user</para></listitem>
+<listitem><para>Only file names matching - filters file names by a regular expression</para></listitem>
+<listitem><para>Only dirnames matching - filters folder names by a regular expression</para></listitem>
+</itemizedlist>
+
+<para>
+Special characters recognized by the regular expression matcher are:
+</para>
+
+<itemizedlist>
+
+<listitem><para>
+<literal>x*</literal> matches any number of occurrences of the character
+<literal>x</literal>.
+</para></listitem>
+
+<listitem><para>
+<literal>x+</literal> matches one or more of occurrences of the character
+<literal>x</literal>.
+</para></listitem>
+
+<listitem><para>
+<literal>x?</literal> matches zero or one occurrences of the character
+<literal>x</literal>.
+</para></listitem>
+
+<listitem><para>
+<literal>^</literal> matches the start of the string.
+</para></listitem>
+
+<listitem><para>
+<literal>$</literal> matches the end of the string.
+</para></listitem>
+
+<listitem><para>
+<literal>[a-cx-z]</literal> matches a set of characters,
+&eg; here the set consisting of a,b,c,x,y,z.
+</para></listitem>
+
+</itemizedlist>
+
+</sect1>
+
+
+</chapter>
+
+<chapter id="advancedusage">
+<title>Advanced Usage</title>
+
+<sect1 id="updatingto">
+<title>Updating to Tag, Branch or Date</title>
+
+<para>
+Branches of a module are parallel versions of this module. A good real life
+example of the use of this feature is the release of a software project. After a
+major release, there are bugs in the code that should be fixed, but people want
+to add new features to the application too. It is very hard to do both at the
+same time because new features usually introduce new bugs, making it hard to
+track down the old ones. To solve this dilemma, &CVS; lets you create a parallel
+version, that we will call the &quot;stable release branch&quot;, where you can
+only add bugfixes, leaving the main branch (HEAD) open for adding new features.
+</para>
+
+<para>
+Tags are used to mark a version of a project. &CVS; stamps one
+version of each file with the tag, so when you checkout or
+update to a specific tag, you will get always the same file versions;
+therefore, as opposed to branches, tags are not dynamic: you cannot develop a
+tag. Tags are useful to mark releases, big changes in the code, &etc;
+</para>
+
+<para>
+When you are developing or following the development of a software project,
+you do not necessarily work with the main branch all the time. After a release,
+you may want to stay with the released branch for a while, to enjoy its relative
+stability, fix bugs, translate the sources, &etc; To do all that, you have to
+update to the released branch. All your files will be updated to the latest
+version of the files in that branch. After updating, all your new commits will
+be uploaded to the new branch as well.
+</para>
+
+<para>
+Also, if you want to track a bug that was reported
+against a past tagged release, &CVS; offers you the possibility to retrieve the
+software as it was released, by updating to that tag. Besides, if you want to
+fetch a past version of your project, you can update your working copy to a
+specific date. This may be useful if an error was introduced in the project
+between two releases, and you have an opinion on when that was. When you update
+to a date or tag, the versions of your files will be the same as the versions
+in that specific date or the versions stamped by that tag.
+</para>
+
+<warning><para>
+Before updating to a different branch or tag, make sure you committed all your
+changes to the branch you are working with. If your are not ready to
+commit your changes, but do not want to discard them, do not update to the new
+branch, as you may lose your changes. As an alternative, you can do a new
+<link linkend="checkingout">checkout</link>, to work in parallel with
+both versions.
+</para></warning>
+
+<figure id="screenshot-updatetag" float="1">
+<title>A screenshot of &cervisia;'s update to tag dialog</title>
+<mediaobject>
+<imageobject><imagedata format="PNG" fileref="updatetag.png"/></imageobject>
+<textobject><phrase>A screenshot of &cervisia;'s update to tag dialog</phrase></textobject>
+</mediaobject>
+</figure>
+
+<variablelist>
+<varlistentry>
+<term><guilabel>Update to branch</guilabel></term>
+<listitem><para>
+Select this option to update to a branch. Enter the name of the branch in the
+drop down text box (or press the <guilabel>Fetch List</guilabel> button to
+retrieve the list of branches from the &CVS; server, and select the one you want
+in the drop down list).
+</para></listitem>
+</varlistentry>
+
+<varlistentry>
+<term><guilabel>Update to tag</guilabel></term>
+<listitem><para>
+Select this option to update to a tag. Enter the name of the tag in the
+drop down text box (or press the <guilabel>Fetch List</guilabel> button to
+retrieve the list of tags from the &CVS; server, and select the one you want
+in the drop down list).
+</para></listitem>
+</varlistentry>
+
+<varlistentry>
+<term><guilabel>Update to date</guilabel></term>
+<listitem><para>
+Select this option to update to a date. In the field below, you can enter a wide
+variety of date formats. One possible format is <literal>yyyy-mm-dd</literal>
+where <literal>yyyy</literal> is the year, <literal>mm</literal> is the month
+(numerically) and <literal>dd</literal> is the day. Alternatives are some
+English phrases like <literal>yesterday</literal> or <literal>2 weeks
+ago</literal>.
+</para></listitem>
+</varlistentry>
+
+</variablelist>
+
+<note><para>
+Updating to a tag or date make them 'sticky', &ie; you can not commit
+further modifications on that files (unless the tag is a branch tag). In order
+to get back to the main branch, use the menu item
+<menuchoice><guimenu>Advanced</guimenu><guimenuitem>Update to
+HEAD</guimenuitem></menuchoice>.
+</para></note>
+
+<para>
+The comand issued to update to a branch or tag is:
+<screen><command>cvs update -r <replaceable>tag</replaceable></command></screen>
+</para>
+
+<para>
+The command issued to update to a date is:
+<screen><command>cvs update -D <replaceable>date</replaceable></command></screen>
+</para>
+
+<para>
+The command issued to update to the main branch (HEAD) is:
+<screen><command>cvs update <option>-A</option></command></screen>
+</para>
+
+</sect1>
+
+
+<sect1 id="taggingbranching">
+<title>Tagging and Branching</title>
+
+<para>
+We discuss here only the technical aspects of tagging and branching. If you
+are only a <emphasis>user</emphasis>, not the administrator of the repository,
+you will probably not be confronted with the problem. If however you are your
+own administrator, you should first read about the non-technical problems that
+accompany branching, in order to get an impression of how time-consuming and
+error-prone maintaining different branches of a project can be. The appendix
+includes some references about this topic.
+</para>
+
+<para>
+Simple tagging is something you usually do when a release is made, so that you
+can at any time easily get back to the project state at that time. Tags are
+usually given a name consisting of the project name and the version
+number. For example, &cervisia; 1.0 is available under the tag
+<literal>CERVISIA_1_0</literal>. &cervisia; enforces &CVS;'s strict rules
+about what constitutes valid tag name. It must begin with a letter and may
+contain letters, digits, hyphens and underscores.
+</para>
+
+<para>
+Normally, you will want to tag the whole project (although &CVS; of course
+allows you to tag only a subset). To this end, mark the toplevel folder in
+the view and choose
+<menuchoice><guimenu>Advanced</guimenu><guimenuitem>Tag/Branch</guimenuitem></menuchoice>.
+Now enter the name of the tag, press <keycap>Return</keycap> and you are done.
+</para>
+
+<para>
+Creating a branch is not significantly more difficult: In the tag dialog,
+check the box <guibutton>Create branch with this tag</guibutton>. You can also
+delete an existing tag: Choose
+<menuchoice><guimenu>Advanced</guimenu><guimenuitem>Delete
+Tag</guimenuitem></menuchoice> in the main view.
+</para>
+
+<para>
+Another aspect of branching is the merging of modifications from a branch to
+the current branch. If you are going to do this, choose
+<menuchoice><guimenu>Advanced</guimenu><guimenuitem>Merge...</guimenuitem></menuchoice>.
+The dialog that appears now gives you two options:
+</para>
+
+<para>
+Either you may merge all modifications done on a branch to the current
+branch. In that case, check the box <guibutton>Merge from branch</guibutton>
+and fill in the branch you want to merge from. &cervisia; will then execute
+the command
+</para>
+
+<para>
+<screen><command>cvs update <option>-j</option> <replaceable>branchtag</replaceable></command></screen>
+</para>
+
+<para>
+The other possibility is that you want to merge only the modifications made
+between two tags on a branch. This usually happens when you merge from the
+same branch to the trunk several times. In that case, check the box
+<guibutton>Merge modifications</guibutton> and enter (in the correct order)
+the two relevant tags. This will result in a command
+</para>
+
+<para>
+<screen><command>cvs update <option>-j</option> <replaceable>branchtag1</replaceable> <option>-j</option> <replaceable>branchtag2</replaceable></command></screen>
+</para>
+
+</sect1>
+
+
+<sect1 id="watches">
+<title>Using Watches</title>
+
+<para>
+A watch is the conventional name for &CVS;'s feature to notify users of the
+repository whenever a file has been changed or a developer has started editing
+a file. The usage of watches requires that the file
+<filename><envar>$CVSROOT</envar>/CVSROOT/notify</filename> has been set up
+properly. This is not discussed here; if you need further information on the
+setup from the administrator's point of view, read one of the books listed in
+the appendix.
+</para>
+
+<para>
+&cervisia;'s main support of watches are six menu items.
+</para>
+
+<para>
+In order to add a watch to one or several files, use
+<menuchoice><guimenu>Advanced</guimenu><guimenuitem>Add
+Watch...</guimenuitem></menuchoice>. In the dialog you get, you can choose to
+get notified for any of the types of events that &CVS; supports. For example,
+if you only want to get notified when a file is committed, check the boxes
+<guibutton>Only</guibutton> and <guibutton>Commits</guibutton>. If you want to
+get notified about any event related to the marked files, check the box
+<guibutton>All</guibutton>. The command line used when you accept the dialog
+is
+</para>
+
+<para>
+<screen><command>cvs watch add -a commit <replaceable>file names</replaceable></command></screen>
+</para>
+
+<para>
+or with a similar option, depending on the events you chose to watch.
+</para>
+
+<para>
+If you are not interested in some files anymore, you can remove your watches on
+them. To this end, use
+<menuchoice><guimenu>Advanced</guimenu><guimenuitem>Remove
+Watch...</guimenuitem></menuchoice>. In the dialog you get here, the same
+options are offered as in the form you filled out when adding the watch. When
+you confirm this dialog, &cervisia; issues the command
+</para>
+
+<para>
+<screen><command>cvs watch remove <replaceable>file names</replaceable></command></screen>
+</para>
+
+<para>
+possibly with an option <option>-a</option> for the chosen events.
+</para>
+
+<para>
+Finally, you can get a list of the people who are watching a couple of
+files. Choose <menuchoice><guimenu>Advanced</guimenu><guimenuitem>Show
+Watchers</guimenuitem></menuchoice>. Using this menu item will result in a
+command
+</para>
+
+<para>
+<screen><command>cvs watchers <replaceable>file names</replaceable></command></screen>
+</para>
+
+<para>
+In the normal usage scenario of &CVS;, each developer works separately in his
+checked out sandbox. When he wants to modify some file, he can just open it in
+his editor and start working on it. Nobody else will know about this work
+until the file gets committed.
+</para>
+
+<para>
+For some developer groups, this is not the preferred model of
+cooperation. They want to get notified about someone working on a file
+<emphasis>as soon as</emphasis> he starts with it. This can be achieved by some
+further &CVS; commands. Before you start editing a file, select it in
+&cervisia;'s main window and choose
+<menuchoice><guimenu>Advanced</guimenu><guimenuitem>Edit</guimenuitem></menuchoice>.
+This will execute the command
+</para>
+
+<para>
+<screen><command>cvs edit <replaceable>file names</replaceable></command></screen>
+</para>
+
+<para>
+This will send out a notification to everyone who has set an
+<literal>edit</literal> watch on this file. It will also register you as an
+<emphasis>editor</emphasis> of the file. You can obtain a list of all editors
+of a certain file by using
+<menuchoice><guimenu>Advanced</guimenu><guimenuitem>Show
+Editors</guimenuitem></menuchoice>. This is equivalent to typing on the
+command line
+</para>
+
+<para>
+<screen><command>cvs editors <replaceable>file names</replaceable></command></screen>
+</para>
+
+<para>
+An editing session is automatically ended when you commit the affected file.
+At that moment, an <literal>unedit</literal> notification gets sent out to all
+people who have registered a respective watch on the file. Of course,
+sometimes you may not want to commit the file, but abort the editing session
+and revert to the previous version of the file. This is done by using
+<menuchoice><guimenu>Advanced</guimenu><guimenuitem>Unedit</guimenuitem></menuchoice>.
+Note that &cervisia; will not ask you for confirmation; that means if you use
+this menu item, all your work done since you used
+<menuchoice><guimenu>Advanced</guimenu><guimenuitem>Edit</guimenuitem></menuchoice>
+will be lost. Precisely, &cervisia; uses the command line
+</para>
+
+<para>
+<screen><command>echo y | cvs unedit <replaceable>file names</replaceable></command></screen>
+</para>
+
+<para>
+So far, we have only the discussed the case where edits and unedits are used
+voluntarily be the developers. In addition &CVS; supports a model which
+<emphasis>enforces</emphasis> the usage of these commands. The responsible
+command to switch to this model is <command>cvs watch on</command> which we
+will not explain further because it is mostly used by the administrator of the
+repository. However, the important point from the developer's point of view is
+that when the project enforces edits, working copies are checked out
+<emphasis>readonly</emphasis>. That means you cannot edit a file by default
+(unless you use tricks like <command>chmod</command>). Only when you use
+<menuchoice><guimenu>Advanced</guimenu><guimenuitem>Edit</guimenuitem></menuchoice>,
+the file becomes writable. It is made read-only again when you commit the file
+or use
+<menuchoice><guimenu>Advanced</guimenu><guimenuitem>Unedit</guimenuitem></menuchoice>.
+</para>
+
+<para>
+&cervisia;'s editor interface helps you with projects that enforce watches
+also in a different way. If you just started an editor with a readonly file
+by double-clicking on it or by using
+<menuchoice><guimenu>File</guimenu><guimenuitem>Edit</guimenuitem></menuchoice>,
+you would not be able to save your modifications later. This has of course a
+reason: Whenever you want to change a file, you should run <command>cvs
+edit</command> before, so that all people watching the file get a notification
+that you are working on it.
+</para>
+
+<para>
+In such a case, it is advisable to check the option
+<menuchoice><guimenu>Settings</guimenu><guimenuitem>Do cvs edit Automatically
+When Necessary</guimenuitem></menuchoice>. Now, whenever you edit a file by
+double-clicking it, &cervisia; will run <command>cvs edit</command> before the
+editor is actually executed. Then you can edit your file as usual. When you
+have finished your work, commit your files, and the committed files are
+read-only again.
+</para>
+
+</sect1>
+
+
+<sect1 id="locking">
+<title>Locking</title>
+
+<para>
+The development model usually followed when &CVS; is used is called
+<emphasis>unreserved checkouts</emphasis>. Each developer has his own sandbox
+where he can edit files as he likes. If when the watch features - like
+<command>cvs edit</command> - are used, multiple developers can work on files
+synchronously. Changes done by a different developer are merged into the local
+sandbox when an update is performed.
+</para>
+
+<para>
+Other revision control systems - like <acronym>RCS</acronym> and
+<application>SourceSafe</application> use a different model. When a developer
+wants to a edit a file, he has to <emphasis>lock</emphasis> it. Only one
+developer at a time can a lock a file. When he has finished editing, the lock
+is released. On the one hand, with this model, conflicts can never happen. On
+the other hand, two developers can not work on the same file at the same time,
+even when their changes do not affect each other. This can be a bottleneck.
+We are not going to discuss the organizational benefits of both approaches.
+Nevertheless we mention that although &CVS; has some support for locking, it is
+not the preferred way of working with &CVS;. You should not use these features
+unless you are sure that your project manager allows them.
+</para>
+
+<para>
+With &cervisia;, you lock files as follows. Select the desired files in the
+main view. Then choose
+<menuchoice><guimenu>Advanced</guimenu><guimenuitem>Lock</guimenuitem></menuchoice>.
+This runs the command
+</para>
+
+<para>
+<screen><command>cvs admin -l <replaceable>file names</replaceable></command></screen>
+</para>
+
+<para>The reverse effect is achieved by using
+<menuchoice><guimenu>Advanced</guimenu><guimenuitem>Unlock</guimenuitem></menuchoice>.
+This runs the command</para>
+
+<para>
+<screen><command>cvs admin -u <replaceable>file names</replaceable></command></screen>
+</para>
+
+</sect1>
+
+</chapter>
+
+
+<chapter id="customization">
+<title>Customizing &cervisia;</title>
+
+<para>
+&cervisia; can be customized in various ways to your needs and
+preferences. Some options which you may want to change regularly are directly
+available in the <guimenu>Settings</guimenu> menu. Others are united in a common
+dialog which is available via
+<menuchoice><guimenu>Option</guimenu><guimenuitem>Settings...</guimenuitem></menuchoice>.
+</para>
+
+
+<sect1 id="customize-general">
+<title>General</title>
+
+<variablelist>
+
+<varlistentry id="customize-username">
+<term><guilabel>User name for the ChangeLog editor:</guilabel></term>
+<listitem><para>
+Whenever you use the menu item
+<menuchoice><guimenu>File</guimenu><guimenuitem>Insert ChangeLog
+Entry...</guimenuitem></menuchoice>, a new ChangeLog entry is generated with
+the current date and your username. Normally, it is considered good style to
+insert your full name and your email address into each of your ChangeLog
+entries. &cervisia; add automatically the full name and email address
+entered here.
+</para></listitem>
+</varlistentry>
+
+<varlistentry id="customize-cvspath">
+<term><guilabel>Path to cvs executable, or 'cvs':</guilabel></term>
+<listitem><para>
+Here you can set the name (or path) to the <command>cvs</command> command
+line client. By default, the &CVS; executable found in your <envar>$PATH</envar> is
+used by &cervisia;.
+</para></listitem>
+</varlistentry>
+
+</variablelist>
+
+</sect1>
+
+<sect1 id="customize-diff">
+<title>Diff Viewer</title>
+
+<variablelist>
+
+<varlistentry id="customize-context">
+<term><guilabel>Number of context lines in the diff dialog:</guilabel></term>
+<listitem><para>
+For the diff dialog, &cervisia; uses the option <option>-U</option> to
+<command>diff</command>. This lets <command>diff</command> show only a limited
+number of lines around each difference region (context lines). Here you can set
+the argument to <option>-U</option>.
+</para></listitem>
+</varlistentry>
+
+<varlistentry id="customize-diffopt">
+<term><guilabel>Additional options for cvs diff:</guilabel></term>
+<listitem><para>
+Here you can add additional arguments to the <command>diff</command>. A
+popular example is <option>-b</option> which lets <command>diff</command>
+ignore changes in the amount of whitespace.
+</para></listitem>
+</varlistentry>
+
+<varlistentry id="customize-tabwidth">
+<term><guilabel>Tab width in diff dialog:</guilabel></term>
+<listitem><para>
+In the diff dialog, tab characters present in your file or in the output
+of the <command>diff</command> command are expanded into a fixed number of
+space characters. By default, each tab is replaced by eight spaces, but here
+you can setup a different number.
+</para></listitem>
+</varlistentry>
+
+<varlistentry id="customize-difffrontend">
+<term><guilabel>External diff frontend:</guilabel></term>
+<listitem><para>
+When you use any of the features which show the diff dialog, like
+<menuchoice><guimenu>View</guimenu><guimenuitem>Difference to
+Repository...</guimenuitem></menuchoice>, &cervisia; invokes its internal diff
+frontend. If you prefer a different one, like
+<application>Kompare</application>, <application>TkDiff</application>, or
+<application>xxdiff</application>, enter its file name and path here.
+</para></listitem>
+</varlistentry>
+
+</variablelist>
+
+</sect1>
+
+<sect1 id="customize-status">
+<title>Status</title>
+
+<variablelist>
+
+<varlistentry id="customize-startstatus-remote">
+<term><guilabel>When opening a sandbox from a remote repository, start a
+File-&gt;Status command automatically</guilabel></term>
+<listitem><para>
+When you check this option, the
+<menuchoice><guimenu>File</guimenu><guimenuitem>Status</guimenuitem></menuchoice>
+command is started whenever you open a remote sandbox. This command may need some
+time and also needs a connection to the server for remote repositories (making
+it unusable for offline usage).
+</para></listitem>
+</varlistentry>
+
+<varlistentry id="customize-startstatus-local">
+<term><guilabel>When opening a sandbox from a local repository, start a
+File-&gt;Status command automatically</guilabel></term>
+<listitem><para>
+When you check this option, the
+<menuchoice><guimenu>File</guimenu><guimenuitem>Status</guimenuitem></menuchoice>
+command is started whenever you open a local sandbox.
+</para></listitem>
+</varlistentry>
+
+</variablelist>
+
+</sect1>
+
+<sect1 id="customize-advanced">
+<title>Advanced</title>
+
+<variablelist>
+
+<varlistentry id="customize-timeout">
+<term><guilabel>Timeout after which a progress dialog appears (in ms):</guilabel></term>
+<listitem><para>
+Practically all &CVS; commands started in a sandbox which belongs to a remote
+repository need a connection to the &CVS; server. This is affected by delays
+from the network connection or a high load on the server. For this reason, for
+commands like <menuchoice><guimenu>View</guimenu><guimenuitem>Difference to
+Repository...</guimenuitem></menuchoice> &cervisia; opens a dialog which
+indicates that the command is still running and which allows you to abort
+it. Furthermore, this dialog is used to show you error messages from &CVS;. As
+this dialog may become annoying after some time, it is shown only after a
+certain timeout which is 4 seconds by default. Here you can change this value.
+</para></listitem>
+</varlistentry>
+
+<varlistentry id="customize-compression">
+<term><guilabel>Default compression level:</guilabel></term>
+<listitem><para>
+The <command>cvs</command> client compresses files and patches when they are
+transferred over a network. With the command line option <option>-z</option>,
+the compression level can be set. You can setup &cervisia; to use this option
+by configuring the level here. The value set here is used only as a default;
+additionally there is a per-repository setting available in
+<menuchoice><guimenu>Repository</guimenu><guimenuitem>Repositories...</guimenuitem></menuchoice>.
+</para></listitem>
+</varlistentry>
+
+<varlistentry id="customize-sshagent">
+<term><guilabel>Utilize a running or start a new ssh-agent process</guilabel></term>
+<listitem><para>
+Check this box if you use <link linkend="rsh">ext (rsh) repositories</link>,
+the &ssh; remote shell to communicate with the repository and
+<application>ssh-agent</application> to manage your keys.
+</para></listitem>
+</varlistentry>
+
+</variablelist>
+
+</sect1>
+
+
+<sect1 id="customize-look">
+<title>Look'n'feel</title>
+
+<variablelist>
+
+<varlistentry id="customize-protocolfont">
+<term><guilabel>Font for protocol window...</guilabel></term>
+<listitem><para>
+Press this button to open the <guilabel>Set Font</guilabel> dialog, to set the
+font used in the protocol window (this is the window showing the
+output of the <command>cvs</command> client).
+</para></listitem>
+</varlistentry>
+
+<varlistentry id="customize-annotatefont">
+<term><guilabel>Font for annotate view...</guilabel></term>
+<listitem><para>
+Press this button to open the <guilabel>Set Font</guilabel> dialog, to set the
+font used in the <link linkend="annotate">annotate view</link>.
+</para></listitem>
+</varlistentry>
+
+<varlistentry id="customize-difffont">
+<term><guilabel>Font for diff view...</guilabel></term>
+<listitem><para>
+Press this button to open the <guilabel>Set Font</guilabel> dialog, to set the
+font used in <link linkend="diff">diff dialogs</link>.
+</para></listitem>
+</varlistentry>
+
+<varlistentry id="customize-colors">
+<term><guilabel>Colors</guilabel></term>
+<listitem><para>
+Press the colored buttons to open the <guilabel>Select Color</guilabel> dialog,
+to set the color used for <guilabel>Conflict</guilabel>, <guilabel>Local
+Change</guilabel>, or <guilabel>Remote Change</guilabel>, in the main view or
+<guilabel>Diff change</guilabel>, <guilabel>Diff insertion</guilabel>, or
+<guilabel>Diff deletion</guilabel>, in &cervisia;'s built-in diff frontend.
+</para></listitem>
+</varlistentry>
+
+<varlistentry id="customize-splitter">
+<term><guilabel>Split main window horizontally</guilabel></term>
+<listitem><para>
+&cervisia;'s main window is normally split vertically into a window with
+the file tree above and one with the &CVS; output below; alternatively, you can
+arrange them horizontally.
+</para></listitem>
+</varlistentry>
+
+</variablelist>
+
+</sect1>
+</chapter>
+
+
+<chapter id="appendix">
+<title>Appendix</title>
+
+<sect1 id="ignoredfiles">
+<title>Ignored Files</title>
+
+<para>
+In its main file tree, &cervisia; does not display all files which are
+actually there. This is analog to <command>cvs</command> itself and helps to
+avoid clutter caused by uninteresting stuff like object files. &cervisia;
+tries to mimic <command>cvs</command>'s behavior as close as possible,
+i.e. it gets ignore lists from the following sources:
+</para>
+
+<itemizedlist>
+
+<listitem><para>
+A static list of entries which includes things like <literal
+role="extension">*.o</literal> and <filename>core</filename>. For details,
+see the &CVS; documentation.
+</para></listitem>
+<listitem><para>
+The file <filename><envar>$HOME</envar>/.cvsignore</filename>.
+</para></listitem>
+
+<listitem><para>
+The environment variable <envar>$CVSIGNORE</envar>.
+</para></listitem>
+<listitem><para>
+The <filename>.cvsignore</filename> file in the respective folder.
+</para></listitem>
+
+</itemizedlist>
+
+<para>
+<command>cvs</command> itself additionally looks up entries in
+<filename><envar>$CVSROOT</envar>/CVSROOT/cvsignore</filename>, but this is a
+file on the server, and &cervisia; should be able to start up offline. If you
+are working with a group that prefers to use an ignore list on the server,
+it's probably a good idea to take a look which patterns are listed there and
+to put them into the <filename>.cvsignore</filename> file in your home
+folder.
+</para>
+
+</sect1>
+
+
+<sect1 id="information">
+<title>Further Information and Support</title>
+
+<itemizedlist>
+
+<listitem><para>
+&CVS; comes with a complete set of documentation in the form of info pages,
+known as "The Cederqvist". If it is properly installed, you get browse it by
+typing in <userinput>info:/cvs</userinput> into the locationbar of
+<application>kdehelp</application>, <application>khelpcenter</application>
+resp. Alternative, you can just choose
+<menuchoice><guimenu>Help</guimenu><guimenuitem>CVS
+Info</guimenuitem></menuchoice> in &cervisia;. An on-line HTML version of the
+Cederqvist is available <ulink
+url="http://cvshome.org/docs/manual/cvs.html">on the web</ulink>.
+</para>
+
+<para>
+As this book is maintained together with &CVS;, it is normally the most
+up-to-date reference; nevertheless, considering other documentation
+for learning to use &CVS; is recommended, in particular the following.
+</para></listitem>
+
+<listitem><para>
+Karl Fogel has written the excellent book <ulink
+url="http://cvsbook.red-bean.com/index.html">Open Source Development with
+CVS</ulink>. About half of this book is about the development process of Open
+Source software. The other half is a technical documentation of
+&CVS;. Thankfully, the technical part of the book has been made freely
+redistributable under the GPL, so that you can download a HTML version of
+it. A list of errata is available on the webpage mentioned above.
+</para></listitem>
+
+<listitem><para>
+&CVS; issues are discussed on a dedicated <ulink
+url="http://mail.gnu.org/mailman/listinfo/info-cvs">mailing list</ulink>.
+</para></listitem>
+
+<listitem><para>
+There is USENET group <literal>comp.software.config-mgmt</literal> dedicated
+to configuration management in general. &CVS; is only marginally a topic in
+this group, but nevertheless it may be interesting for discussing merits of
+various revision control systems compared to &CVS;.
+</para></listitem>
+
+<listitem><para>
+Last but not least, there is a (low traffic) <ulink
+url="http://lists.sourceforge.net/mailman/listinfo/cervisia-user">&cervisia;
+mailing list</ulink>.
+</para></listitem>
+
+</itemizedlist>
+
+</sect1>
+
+
+<sect1 id="commandreference">
+<title>Command Reference</title>
+
+<!-- File Menu -->
+<sect2 id="menufile">
+
+<title>The File Menu</title>
+
+<variablelist>
+
+<varlistentry>
+<term><menuchoice>
+<guimenu>File</guimenu><guimenuitem>Open Sandbox...</guimenuitem>
+</menuchoice></term>
+<listitem><para>
+Opens a sandbox in the main window. See <xref linkend="mainscreen" />.
+</para></listitem>
+</varlistentry>
+
+<varlistentry>
+<term><menuchoice>
+<guimenu>File</guimenu><guimenuitem>Recent sandboxes</guimenuitem>
+</menuchoice></term>
+<listitem><para>
+Opens one of the sandboxes that were in use recently.
+</para></listitem>
+</varlistentry>
+
+<varlistentry>
+<term><menuchoice>
+<guimenu>File</guimenu><guimenuitem>Insert ChangeLog Entry...</guimenuitem>
+</menuchoice></term>
+<listitem><para>
+Opens the ChangeLog editor, prepared such that you can add a new entry with
+the current date. See <xref linkend="committingfiles" />.
+</para></listitem>
+</varlistentry>
+
+<varlistentry>
+<term><menuchoice>
+<shortcut><keycombo><keycap>&Ctrl;</keycap><keycap>U</keycap></keycombo></shortcut>
+<guimenu>File</guimenu><guimenuitem>Update</guimenuitem>
+</menuchoice></term>
+<listitem><para>
+Runs 'cvs update' on selected files and changes the status and revision
+numbers in the listing accordingly. See <xref linkend="mainscreen" />.
+</para></listitem>
+</varlistentry>
+
+<varlistentry>
+<term><menuchoice>
+<shortcut><keycap>F5</keycap></shortcut>
+<guimenu>File</guimenu><guimenuitem>Status</guimenuitem>
+</menuchoice></term>
+<listitem><para>
+Runs 'cvs -n update' on selected files and changes the status and revision
+numbers in the listing accordingly. See <xref linkend="mainscreen" />.
+</para></listitem>
+</varlistentry>
+
+<varlistentry>
+<term><menuchoice>
+<guimenu>File</guimenu><guimenuitem>Edit</guimenuitem>
+</menuchoice></term>
+<listitem><para>
+Opens the selected file in KDE's default editor for the selected file's type.
+</para></listitem>
+</varlistentry>
+
+<varlistentry>
+<term><menuchoice>
+<guimenu>File</guimenu><guimenuitem>Resolve...</guimenuitem>
+</menuchoice></term>
+<listitem><para>
+Opens a dialog for the selected file which allows
+you to resolve merge conflicts in it. See <xref linkend="resolvingconflicts" />.
+</para></listitem>
+</varlistentry>
+
+<varlistentry>
+<term><menuchoice>
+<shortcut><keycap>#</keycap></shortcut>
+<guimenu>File</guimenu><guimenuitem>Commit...</guimenuitem>
+</menuchoice></term>
+<listitem><para>
+Allows you to commit the selected files. See <xref linkend="committingfiles" />.
+</para></listitem>
+</varlistentry>
+
+<varlistentry>
+<term><menuchoice>
+<shortcut><keycap>+</keycap></shortcut>
+<guimenu>File</guimenu><guimenuitem>Add to Repository...</guimenuitem>
+</menuchoice></term>
+<listitem><para>
+Allows you to add the selected files to the repository. See <xref linkend="addingfiles" />.
+</para></listitem>
+</varlistentry>
+
+<varlistentry>
+<term><menuchoice><guimenu>File</guimenu><guimenuitem>Add Binary...</guimenuitem>
+</menuchoice></term>
+<listitem><para>
+Allows you to add the selected files to the repository as binaries
+(<command>cvs add<option>-kb</option></command>). See <xref linkend="addingfiles" />.
+</para></listitem>
+</varlistentry>
+
+<varlistentry>
+<term><menuchoice>
+<shortcut><keycap>-</keycap></shortcut>
+<guimenu>File</guimenu><guimenuitem>Remove from Repository...</guimenuitem>
+</menuchoice></term>
+<listitem><para>
+Allows you to remove the selected files from the repository. See <xref linkend="removingfiles" />.
+</para></listitem>
+</varlistentry>
+
+<!--TODO: add the revert action to the working with files chapter -->
+
+<varlistentry>
+<term><menuchoice><guimenu>File</guimenu><guimenuitem>Revert</guimenuitem>
+</menuchoice></term>
+<listitem><para>
+Discards any local changes you have made to the selected files and reverts to
+the version in the repository (Option <option>-C</option> to <command>cvs
+update</command>).
+</para></listitem>
+</varlistentry>
+
+<varlistentry>
+<term><menuchoice>
+<shortcut><keycombo><keycap>&Ctrl;</keycap><keycap>Q</keycap></keycombo></shortcut>
+<guimenu>File</guimenu><guimenuitem>Exit</guimenuitem>
+</menuchoice></term>
+<listitem><para>Quits &cervisia;.
+</para></listitem>
+</varlistentry>
+
+</variablelist>
+
+</sect2>
+
+<!-- View Menu -->
+<sect2 id="menuview">
+
+<title>The View Menu</title>
+
+<variablelist>
+
+<varlistentry>
+<term><menuchoice>
+<shortcut><keycap>Escape</keycap></shortcut>
+<guimenu>View</guimenu><guimenuitem>Stop</guimenuitem>
+</menuchoice></term>
+<listitem><para>
+Aborts any running subprocesses.
+</para></listitem>
+</varlistentry>
+
+<varlistentry>
+<term><menuchoice>
+<shortcut><keycombo><keycap>&Ctrl;</keycap><keycap>L</keycap></keycombo></shortcut>
+<guimenu>View</guimenu><guimenuitem>Browse Log...</guimenuitem>
+</menuchoice></term>
+<listitem><para>
+Shows the log browser of the selected file versions. See <xref linkend="browsinglogs" />.
+</para></listitem>
+</varlistentry>
+
+<varlistentry>
+<term><menuchoice>
+<shortcut><keycombo><keycap>&Ctrl;</keycap><keycap>A</keycap></keycombo></shortcut>
+<guimenu>View</guimenu><guimenuitem>Annotate...</guimenuitem>
+</menuchoice></term>
+<listitem><para>
+Shows an annotated view of the selected file, i.e. a view where you
+can for each line see which author modified it last. See <xref linkend="annotate" />.
+</para></listitem>
+</varlistentry>
+
+<varlistentry>
+<term><menuchoice>
+<shortcut><keycombo><keycap>&Ctrl;</keycap><keycap>D</keycap></keycombo></shortcut>
+<guimenu>View</guimenu><guimenuitem>Difference to Repository (BASE)...</guimenuitem>
+</menuchoice></term>
+<listitem><para>
+Shows the differences between the selected file in the sandbox
+and the revision you last updated (BASE). See <xref linkend="diff" />.
+</para></listitem>
+</varlistentry>
+
+<varlistentry>
+<term><menuchoice>
+<shortcut><keycombo><keycap>&Ctrl;</keycap><keycap>H</keycap></keycombo></shortcut>
+<guimenu>View</guimenu><guimenuitem>Difference to Repository (HEAD)...</guimenuitem>
+</menuchoice></term>
+<listitem><para>
+Shows the differences between the selected file in the sandbox
+and the revision you last updated (HEAD). See <xref linkend="diff" />.
+</para></listitem>
+</varlistentry>
+
+
+<varlistentry>
+<term><menuchoice>
+<guimenu>View</guimenu><guimenuitem>Last Change...</guimenuitem>
+</menuchoice></term>
+<listitem><para>
+Shows the differences between the revision of the selected
+file you last updated (BASE) and the revision before. See <xref linkend="diff" />.
+</para></listitem>
+</varlistentry>
+
+<varlistentry>
+<term><menuchoice>
+<guimenu>View</guimenu><guimenuitem>History...</guimenuitem>
+</menuchoice></term>
+<listitem><para>
+Shows the &CVS; history as reported by the server. See <xref linkend="browsinghistory" />.
+</para></listitem>
+</varlistentry>
+
+<!--TODO: add hide menus to mainscreen section-->
+
+<varlistentry>
+<term><menuchoice>
+<guimenu>View</guimenu><guimenuitem>Hide All Files</guimenuitem>
+</menuchoice></term>
+<listitem><para>
+Determines whether only folders are shown in the main tree view. See <xref linkend="mainscreen" />.
+</para></listitem>
+</varlistentry>
+
+<varlistentry>
+<term><menuchoice>
+<guimenu>View</guimenu><guimenuitem>Hide Unmodified Files</guimenuitem>
+</menuchoice></term>
+<listitem><para>
+Determines whether unknown and up to date files are hidden in the main tree view. See <xref linkend="mainscreen" />.
+</para></listitem>
+</varlistentry>
+
+<varlistentry>
+<term><menuchoice>
+<guimenu>View</guimenu><guimenuitem>Hide Removed Files</guimenuitem>
+</menuchoice></term>
+<listitem><para>
+Determines whether removed files are hidden in the main tree view. See <xref linkend="mainscreen" />.
+</para></listitem>
+</varlistentry>
+
+<varlistentry>
+<term><menuchoice>
+<guimenu>View</guimenu><guimenuitem>Hide Non-CVS Files</guimenuitem>
+</menuchoice></term>
+<listitem><para>
+Determines whether files not in CVS are hidden in the main tree view. See <xref linkend="mainscreen" />.
+</para></listitem>
+</varlistentry>
+
+<varlistentry>
+<term><menuchoice>
+<guimenu>View</guimenu><guimenuitem>Hide Empty Folders</guimenuitem>
+</menuchoice></term>
+<listitem><para>
+Determines whether folders without visible entries are hidden in the main tree view. See <xref linkend="mainscreen" />.
+</para></listitem>
+</varlistentry>
+
+<varlistentry>
+<term><menuchoice>
+<guimenu>View</guimenu><guimenuitem>Unfold File Tree</guimenuitem>
+</menuchoice></term>
+<listitem><para>
+Opens all branches in the file tree so that you can
+see all files and folders. See <xref linkend="mainscreen" />.
+</para></listitem>
+</varlistentry>
+
+<varlistentry>
+<term><menuchoice>
+<guimenu>View</guimenu><guimenuitem>Fold File Tree</guimenuitem>
+</menuchoice></term>
+<listitem><para>
+Closes all branches in the file tree. See <xref linkend="mainscreen" />.
+</para></listitem>
+</varlistentry>
+
+</variablelist>
+
+</sect2>
+
+<!-- Advanced Menu -->
+<sect2 id="menuadvanced">
+
+<title>The Advanced Menu</title>
+
+<variablelist>
+
+<varlistentry>
+<term><menuchoice>
+<guimenu>Advanced</guimenu><guimenuitem>Tag/Branch...</guimenuitem>
+</menuchoice></term>
+<listitem><para>
+Tags or branches the selected files. See <xref linkend="taggingbranching" />.
+</para></listitem>
+</varlistentry>
+
+<varlistentry>
+<term><menuchoice>
+<guimenu>Advanced</guimenu><guimenuitem>Delete Tag...</guimenuitem>
+</menuchoice></term>
+<listitem><para>
+Removes a given tag from the selected files. See <xref linkend="taggingbranching" />.
+</para></listitem>
+</varlistentry>
+
+<varlistentry>
+<term><menuchoice>
+<guimenu>Advanced</guimenu><guimenuitem>Update to Tag/Date...</guimenuitem>
+</menuchoice></term>
+<listitem><para>
+Brings the selected files to a given tag or date,
+making it sticky. See <xref linkend="updatingto" />.
+</para></listitem>
+</varlistentry>
+
+<varlistentry>
+<term><menuchoice>
+<guimenu>Advanced</guimenu><guimenuitem>Update to HEAD...</guimenuitem>
+</menuchoice></term>
+<listitem><para>
+Brings the selected files to the respective HEAD revision. See <xref linkend="updatingto" />.
+</para></listitem>
+</varlistentry>
+
+<varlistentry>
+<term><menuchoice>
+<guimenu>Advanced</guimenu><guimenuitem>Merge...</guimenuitem>
+</menuchoice></term>
+<listitem><para>
+Merges either a given branch or the modifications
+between two tags into the selected files. See <xref linkend="taggingbranching" />.
+</para></listitem>
+</varlistentry>
+
+<varlistentry>
+<term><menuchoice>
+<guimenu>Advanced</guimenu><guimenuitem>Add Watch...</guimenuitem>
+</menuchoice></term>
+<listitem><para>
+Adds a watch for a set of events on the selected files. See <xref linkend="watches" />.
+</para></listitem>
+</varlistentry>
+<varlistentry>
+<term><menuchoice>
+<guimenu>Advanced</guimenu><guimenuitem>Remove Watch...</guimenuitem>
+</menuchoice></term>
+<listitem><para>Removes a watch for a set of events from the selected files. See <xref linkend="watches" />.
+</para></listitem>
+</varlistentry>
+
+<varlistentry>
+<term><menuchoice>
+<guimenu>Advanced</guimenu><guimenuitem>Show Watchers</guimenuitem>
+</menuchoice></term>
+<listitem><para>
+Lists the watchers of the selected files. See <xref linkend="watches" />.
+</para></listitem>
+</varlistentry>
+
+<varlistentry>
+<term><menuchoice>
+<guimenu>Advanced</guimenu><guimenuitem>Edit</guimenuitem>
+</menuchoice></term>
+<listitem><para>
+Runs <command>cvs edit</command> on the selected files. See <xref linkend="watches" />.
+</para></listitem>
+</varlistentry>
+
+<varlistentry>
+<term><menuchoice>
+<guimenu>Advanced</guimenu><guimenuitem>Unedit</guimenuitem>
+</menuchoice></term>
+<listitem><para>
+Runs <command>cvs unedit</command> on the selected files. See <xref linkend="watches" />.
+</para></listitem>
+</varlistentry>
+
+<varlistentry>
+<term><menuchoice>
+<guimenu>Advanced</guimenu><guimenuitem>Show Editors</guimenuitem>
+</menuchoice></term>
+<listitem><para>
+Runs <command>cvs editors</command> on the selected files. See <xref linkend="watches" />.
+</para></listitem>
+</varlistentry>
+
+<varlistentry>
+<term><menuchoice>
+<guimenu>Advanced</guimenu><guimenuitem>Lock</guimenuitem>
+</menuchoice></term>
+<listitem><para>
+Locks the selected files. See <xref linkend="locking" />.
+</para></listitem>
+</varlistentry>
+
+<varlistentry>
+<term><menuchoice>
+<guimenu>Advanced</guimenu><guimenuitem>Unlock</guimenuitem>
+</menuchoice></term>
+<listitem><para>
+Unlocks the selected files. See <xref linkend="locking" />.
+</para></listitem>
+</varlistentry>
+
+<varlistentry>
+<term><menuchoice>
+<guimenu>Advanced</guimenu><guimenuitem>Create Patch Against Repository...</guimenuitem>
+</menuchoice></term>
+<listitem><para>
+Creates a patch from the modifications in your sandbox. See <xref linkend="creatingpatches" />.
+</para></listitem>
+</varlistentry>
+
+</variablelist>
+
+</sect2>
+
+<!-- Repository Menu -->
+<sect2 id="menurepository">
+
+<title>The Repository Menu</title>
+
+<variablelist>
+
+<varlistentry>
+<term><menuchoice>
+<guimenu>Repository</guimenu><guimenuitem>Create...</guimenuitem>
+</menuchoice></term>
+<listitem><para>Opens a dialog which allows you to create a new local
+repository. See <xref linkend="accessing-repository" />.
+</para></listitem>
+</varlistentry>
+
+<varlistentry>
+<term><menuchoice>
+<guimenu>Repository</guimenu><guimenuitem>Checkout...</guimenuitem>
+</menuchoice></term>
+<listitem><para>
+Opens a dialog which allows you to checkout
+a module from a repository. See <xref linkend="checkingout" />.
+</para></listitem>
+</varlistentry>
+
+<varlistentry>
+<term><menuchoice>
+<guimenu>Repository</guimenu><guimenuitem>Import...</guimenuitem>
+</menuchoice></term>
+<listitem><para>
+Opens a dialog which allows you to import
+a package into the repository. See <xref linkend="importing" />.
+</para></listitem>
+</varlistentry>
+
+<varlistentry>
+<term><menuchoice>
+<guimenu>Repository</guimenu><guimenuitem>Repositories...</guimenuitem>
+</menuchoice></term>
+<listitem><para>Configures a list of repositories you often use
+and how to access them. See <xref linkend="accessing-repository" />.
+</para></listitem>
+</varlistentry>
+
+</variablelist>
+
+</sect2>
+
+<!-- Settings Menu -->
+<sect2 id="menuoptions">
+<title>The Settings Menu</title>
+
+<variablelist>
+
+<varlistentry>
+<term><menuchoice>
+<guimenu>Settings</guimenu><guimenuitem>Show Toolbar</guimenuitem>
+</menuchoice></term>
+<listitem><para>
+Determines whether the toolbar is displayed.
+</para></listitem>
+</varlistentry>
+
+<varlistentry>
+<term><menuchoice>
+<guimenu>Settings</guimenu><guimenuitem>Create Folders on Update</guimenuitem>
+</menuchoice></term>
+<listitem><para>
+Determines whether updates create folders in the sandbox which were not
+there before (Option <option>-d</option> to <command>cvs update</command>).
+</para></listitem>
+</varlistentry>
+
+<varlistentry>
+<term><menuchoice>
+<guimenu>Settings</guimenu><guimenuitem>Prune Empty Folders on Update</guimenuitem>
+</menuchoice></term>
+<listitem><para>
+Determines whether updates remove empty folders in the sandbox. (Option
+<option>-P</option> to <command>cvs update</command>).
+</para></listitem>
+</varlistentry>
+
+<varlistentry>
+<term><menuchoice>
+<guimenu>Settings</guimenu><guimenuitem>Update Recursively</guimenuitem>
+</menuchoice></term>
+<listitem><para>
+Determines whether updates are recursive (Option <option>-r</option> to
+<command>cvs update</command>).
+</para></listitem>
+</varlistentry>
+
+<varlistentry>
+<term><menuchoice>
+<guimenu>Settings</guimenu><guimenuitem>Commit and Remove Recursively</guimenuitem>
+</menuchoice></term>
+<listitem><para>Determines whether commits and removes are recursive
+(Option <option>-r</option> to <command>cvs add</command>,
+<command>cvs remove</command> resp.).
+</para></listitem>
+</varlistentry>
+
+<varlistentry>
+<term><menuchoice>
+<guimenu>Settings</guimenu><guimenuitem>Do cvs edit Automatically When Necessary</guimenuitem>
+</menuchoice></term>
+<listitem><para>
+Determines whether <command>cvs edit</command> is executed automatically
+whenever you edit a file.
+</para></listitem>
+</varlistentry>
+
+<varlistentry>
+<term><menuchoice>
+<guimenu>Settings</guimenu><guimenuitem>Configure Shortcuts...</guimenuitem>
+</menuchoice></term>
+<listitem><para>
+Opens a dialog for configuring keybindings.
+</para></listitem>
+</varlistentry>
+
+<varlistentry>
+<term><menuchoice>
+<guimenu>Settings</guimenu><guimenuitem>Configure Toolbars...</guimenuitem>
+</menuchoice></term>
+<listitem><para>
+Opens a dialog for configuring &cervisia;'s toolbars.
+</para></listitem>
+</varlistentry>
+
+<varlistentry>
+<term><menuchoice>
+<guimenu>Settings</guimenu><guimenuitem>Configure Cervisia...</guimenuitem>
+</menuchoice></term>
+<listitem><para>
+Opens a dialog for customizing &cervisia;.
+</para></listitem>
+</varlistentry>
+
+</variablelist>
+
+</sect2>
+
+<!-- Help -->
+<sect2 id="menuhelp">
+<title>The Help Menu</title>
+
+<variablelist>
+
+<varlistentry>
+<term><menuchoice>
+<shortcut><keycap>F1</keycap></shortcut>
+<guimenu>Help</guimenu><guimenuitem>Handbook</guimenuitem>
+</menuchoice></term>
+<listitem><para>
+Invokes the KDE Help system starting at the &cervisia; help pages. (this
+document).
+</para></listitem>
+</varlistentry>
+
+<varlistentry>
+<term><menuchoice>
+<guimenu>Help</guimenu><guimenuitem>Report Bug...</guimenuitem>
+</menuchoice></term>
+<listitem><para>
+Opens the Bug report dialog.
+</para></listitem>
+</varlistentry>
+
+<varlistentry>
+<term><menuchoice>
+<guimenu>Help</guimenu>
+<guimenuitem>About &cervisia;</guimenuitem>
+</menuchoice></term>
+<listitem><para>
+This will display version and author information.
+</para></listitem>
+</varlistentry>
+
+<varlistentry>
+<term><menuchoice>
+<guimenu>Help</guimenu><guimenuitem>About KDE</guimenuitem>
+</menuchoice></term>
+<listitem><para>
+This displays the KDE version and other basic information.
+</para></listitem>
+</varlistentry>
+
+<varlistentry>
+<term><menuchoice>
+<guimenu>Help</guimenu><guimenuitem>CVS Manual</guimenuitem>
+</menuchoice></term>
+<listitem><para>
+Opens the &CVS; info pages in the KDE help system.
+</para></listitem>
+</varlistentry>
+
+</variablelist>
+
+</sect2>
+
+</sect1>
+
+</chapter>
+
+
+<chapter id="credits-and-licenses">
+<title>Credits And Licenses</title>
+
+&underFDL;
+&underGPL;
+
+</chapter>
+</book>
diff --git a/doc/cervisia/logtree.png b/doc/cervisia/logtree.png
new file mode 100644
index 00000000..e8ad4b4d
--- /dev/null
+++ b/doc/cervisia/logtree.png
Binary files differ
diff --git a/doc/cervisia/mainview.png b/doc/cervisia/mainview.png
new file mode 100644
index 00000000..232239bd
--- /dev/null
+++ b/doc/cervisia/mainview.png
Binary files differ
diff --git a/doc/cervisia/patch.png b/doc/cervisia/patch.png
new file mode 100644
index 00000000..3a5d8482
--- /dev/null
+++ b/doc/cervisia/patch.png
Binary files differ
diff --git a/doc/cervisia/popup.png b/doc/cervisia/popup.png
new file mode 100644
index 00000000..c95ce8db
--- /dev/null
+++ b/doc/cervisia/popup.png
Binary files differ
diff --git a/doc/cervisia/repositories.png b/doc/cervisia/repositories.png
new file mode 100644
index 00000000..ea52aa53
--- /dev/null
+++ b/doc/cervisia/repositories.png
Binary files differ
diff --git a/doc/cervisia/resolve.png b/doc/cervisia/resolve.png
new file mode 100644
index 00000000..1f9b2582
--- /dev/null
+++ b/doc/cervisia/resolve.png
Binary files differ
diff --git a/doc/cervisia/updatetag.png b/doc/cervisia/updatetag.png
new file mode 100644
index 00000000..c8802ef3
--- /dev/null
+++ b/doc/cervisia/updatetag.png
Binary files differ
diff --git a/doc/kapptemplate/Makefile.am b/doc/kapptemplate/Makefile.am
new file mode 100644
index 00000000..07fc0b90
--- /dev/null
+++ b/doc/kapptemplate/Makefile.am
@@ -0,0 +1,2 @@
+KDE_LANG=en
+KDE_MANS=AUTO
diff --git a/doc/kapptemplate/man-kapptemplate.1.docbook b/doc/kapptemplate/man-kapptemplate.1.docbook
new file mode 100644
index 00000000..92eff12e
--- /dev/null
+++ b/doc/kapptemplate/man-kapptemplate.1.docbook
@@ -0,0 +1,115 @@
+<?xml version="1.0" ?>
+<!DOCTYPE refentry PUBLIC "-//KDE//DTD DocBook XML V4.2-Based Variant V1.1//EN" "dtd/kdex.dtd" [
+<!ENTITY % English "INCLUDE">
+]>
+
+<refentry lang="&language;">
+<refentryinfo>
+<author><personname><firstname>Ben</firstname><surname>Burton</surname></personname>
+<email></email></author>
+<date>April 12, 2003</date>
+</refentryinfo>
+
+<refmeta>
+<refentrytitle><command>kapptemplate</command></refentrytitle>
+<manvolnum>1</manvolnum>
+</refmeta>
+
+<refnamediv>
+<refname><command>kapptemplate</command></refname>
+<refpurpose>Creates a framework to develop a KDE application</refpurpose>
+</refnamediv>
+
+<refsynopsisdiv>
+<cmdsynopsis>
+<command>kapptemplate</command>
+<group><option>--noinit</option></group>
+<group><option>--default</option></group>
+<group><option>--full-app</option></group>
+<group><option>--kpart-app</option></group>
+<group><option>--kpart-plugin</option></group>
+<group><option>--existing</option></group>
+<group><option>--help</option></group>
+</cmdsynopsis>
+</refsynopsisdiv>
+
+<refsect1>
+<title>Description</title>
+
+<para><command>kapptemplate</command> is a shell script that will create the necessary framework to develop various &kde; applications. It takes care of the autoconf/automake code as well as providing a skeleton and example of what the code typically looks like. </para>
+
+<para>This utility is part of the &kde; Software Development Kit. </para>
+
+</refsect1>
+
+<refsect1>
+<title>Options</title>
+
+<variablelist>
+<title>General Options</title>
+<varlistentry>
+<term><option>--help</option></term>
+<listitem><para>Display a full summary of options. </para></listitem>
+</varlistentry>
+<varlistentry>
+<term><option>--no-init</option></term>
+<listitem><para>Don't run <command>make</command> <option>-f</option> <parameter>Makefile.cvs</parameter></para>
+</listitem>
+</varlistentry>
+<varlistentry>
+<term><option>--default</option></term>
+<listitem><para>Use default values instead of prompting.</para></listitem>
+</varlistentry>
+</variablelist>
+
+<variablelist>
+<title>Framework Types</title>
+<varlistentry>
+<term><option>--full-app</option></term>
+<listitem><para>Create a full featured KDE application. </para></listitem>
+</varlistentry>
+<varlistentry>
+<term><option>--kpart-app</option></term>
+<listitem><para>Create a full featured KPart application.</para></listitem>
+</varlistentry>
+<varlistentry>
+<term><option>--kpart-plugin</option></term>
+<listitem><para>Create a KPart plugin framework.</para></listitem>
+</varlistentry>
+<varlistentry>
+<term><option>--existing</option></term>
+<listitem><para>Converting existing source to an automake/autoconf KDE framework.</para></listitem>
+</varlistentry>
+</variablelist>
+</refsect1>
+
+<!-- The Following sections are optional, but recommended if they are
+applicable. -->
+
+<refsect1>
+<title>Files</title>
+
+<variablelist>
+<varlistentry>
+<term><filename>~/.kapptemplate</filename></term>
+<listitem><para>Stores default values</para></listitem>
+</varlistentry>
+</variablelist>
+
+</refsect1>
+
+<refsect1>
+<title>See Also</title>
+
+<para><filename>$PREFIX/share/doc/kapptemplate</filename></para>
+
+</refsect1>
+
+<refsect1>
+<title>Authors</title>
+
+<para><command>kapptemplate</command> was written by &Kurt.Granroth; &Kurt.Granroth.mail;</para>
+<para>This manual page was prepared by <personname><firstname>Ben</firstname><surname>Burton</surname></personname><email>bab@debian.org</email></para>
+</refsect1>
+
+</refentry>
diff --git a/doc/kbabel/Makefile.am b/doc/kbabel/Makefile.am
new file mode 100644
index 00000000..17a314c3
--- /dev/null
+++ b/doc/kbabel/Makefile.am
@@ -0,0 +1,3 @@
+KDE_LANG = en
+KDE_DOCS = AUTO
+KDE_MANS = AUTO
diff --git a/doc/kbabel/TODO b/doc/kbabel/TODO
new file mode 100644
index 00000000..916027bf
--- /dev/null
+++ b/doc/kbabel/TODO
@@ -0,0 +1,4 @@
+KBabel documentation TODO:
+
+missing:
+catman - find/replace dialogs
diff --git a/doc/kbabel/back.png b/doc/kbabel/back.png
new file mode 100644
index 00000000..2ffa9395
--- /dev/null
+++ b/doc/kbabel/back.png
Binary files differ
diff --git a/doc/kbabel/bottom.png b/doc/kbabel/bottom.png
new file mode 100644
index 00000000..caf4ea5a
--- /dev/null
+++ b/doc/kbabel/bottom.png
Binary files differ
diff --git a/doc/kbabel/catalogmanager.png b/doc/kbabel/catalogmanager.png
new file mode 100644
index 00000000..48bbade3
--- /dev/null
+++ b/doc/kbabel/catalogmanager.png
Binary files differ
diff --git a/doc/kbabel/catalogmanager_broken.png b/doc/kbabel/catalogmanager_broken.png
new file mode 100644
index 00000000..d0948e92
--- /dev/null
+++ b/doc/kbabel/catalogmanager_broken.png
Binary files differ
diff --git a/doc/kbabel/catalogmanager_missing.png b/doc/kbabel/catalogmanager_missing.png
new file mode 100644
index 00000000..e0311068
--- /dev/null
+++ b/doc/kbabel/catalogmanager_missing.png
Binary files differ
diff --git a/doc/kbabel/catalogmanager_needwork.png b/doc/kbabel/catalogmanager_needwork.png
new file mode 100644
index 00000000..e31413d8
--- /dev/null
+++ b/doc/kbabel/catalogmanager_needwork.png
Binary files differ
diff --git a/doc/kbabel/catalogmanager_nopot.png b/doc/kbabel/catalogmanager_nopot.png
new file mode 100644
index 00000000..1e220bee
--- /dev/null
+++ b/doc/kbabel/catalogmanager_nopot.png
Binary files differ
diff --git a/doc/kbabel/catalogmanager_nopot_ok.png b/doc/kbabel/catalogmanager_nopot_ok.png
new file mode 100644
index 00000000..50028c65
--- /dev/null
+++ b/doc/kbabel/catalogmanager_nopot_ok.png
Binary files differ
diff --git a/doc/kbabel/catalogmanager_ok.png b/doc/kbabel/catalogmanager_ok.png
new file mode 100644
index 00000000..f2b731a0
--- /dev/null
+++ b/doc/kbabel/catalogmanager_ok.png
Binary files differ
diff --git a/doc/kbabel/catalogmanager_reload.png b/doc/kbabel/catalogmanager_reload.png
new file mode 100644
index 00000000..e7aeaac5
--- /dev/null
+++ b/doc/kbabel/catalogmanager_reload.png
Binary files differ
diff --git a/doc/kbabel/catman.docbook b/doc/kbabel/catman.docbook
new file mode 100644
index 00000000..a55d46ec
--- /dev/null
+++ b/doc/kbabel/catman.docbook
@@ -0,0 +1,214 @@
+<!-- <?xml version="1.0" ?>
+<!DOCTYPE chapter PUBLIC "-//KDE//DTD DocBook XML V4.2-Based Variant V1.1//EN" "dtd/kdex.dtd"> -->
+<!-- Uncomment the previous two lines to validate this document -->
+<!-- standalone. Be sure to recomment them before attempting to -->
+<!-- process index.docbook -->
+
+<chapter id="using-catalogmanager">
+
+<chapterinfo>
+<!-- Fill in this section if this document has a different author -->
+<authorgroup>
+<author>
+<personname><firstname></firstname><surname></surname></personname>
+</author>
+</authorgroup>
+
+<!-- TRANS:ROLES_OF_TRANSLATORS -->
+</chapterinfo>
+
+<title>Using &catalogmanager;</title>
+<anchor id="catalogmanager"/>
+
+<screenshot>
+<screeninfo>Screenshot of &catalogmanager;</screeninfo>
+<mediaobject>
+<imageobject>
+<imagedata fileref="snap_catalogmanager.png" format="PNG"/>
+</imageobject>
+<textobject><phrase>Screenshot of &catalogmanager;</phrase></textobject>
+</mediaobject>
+</screenshot>
+<para>
+The Catalog Manager merges two folders into one tree and displays
+all the <acronym>PO</acronym> and <acronym>POT</acronym> files in
+these folders. The display allows you to easily see if a new
+template has been added or an old one has been removed. Some
+information is shown along with each file name: total number of
+entries, number of fuzzy entries, number of untranslated entries, the
+date of the last revision and the last translator of the file.
+</para>
+
+<important><para>
+KBabel's Catalog Manager is meant for projects structured like KDE,
+where the <acronym>POT</acronym> and <acronym>PO</acronym> files
+share a same name, save the extensions. However this is not the
+case of &GNU; projects and of many projects structured like &GNU; ones.
+Typically in such projects, the <acronym>PO</acronym> file is named
+following the language code and so is very different than the name
+of the <acronym>POT</acronym> files. Also such projects have
+one <acronym>POT</acronym> file sharing a directory with all its
+translated <acronym>PO</acronym> files. Unfortunately, all these reasons
+mean that the Catalog Manager is <emphasis>not</emphasis> suitable for
+such projects. (See <ulink url="http://bugs.kde.org/show_bug.cgi?id=76495">KDE bug #76495</ulink>.)
+</para></important>
+
+<para>
+To make it easier for you to find files that need work or are
+missing the status of each file is also displayed using an icon:
+</para>
+
+<itemizedlist>
+ <listitem>
+ <para>
+<inlinemediaobject>
+<imageobject>
+<imagedata fileref="catalogmanager_ok.png" format="PNG"/>
+</imageobject>
+</inlinemediaobject> All the messages in this file are translated.</para>
+ </listitem>
+ <listitem>
+ <para>
+<inlinemediaobject>
+<imageobject>
+<imagedata fileref="catalogmanager_needwork.png" format="PNG"/>
+</imageobject>
+</inlinemediaobject>
+Some of the messages in this file are fuzzy or untranslated
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+<inlinemediaobject>
+<imageobject>
+<imagedata fileref="catalogmanager_missing.png" format="PNG"/>
+</imageobject>
+</inlinemediaobject>
+This file does not exist in the folder of the <acronym>PO</acronym> files.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+<inlinemediaobject>
+<imageobject>
+<imagedata fileref="catalogmanager_broken.png" format="PNG"/>
+</imageobject>
+</inlinemediaobject>
+This file contains syntax errors.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+<inlinemediaobject>
+<imageobject>
+<imagedata fileref="catalogmanager_reload.png" format="PNG"/>
+</imageobject>
+</inlinemediaobject>
+Information about this file is being currently updated. When the update is
+finished, it will get one of the icons listed above to reflect its state.
+ </para>
+ </listitem>
+</itemizedlist>
+
+<para>
+If an icon is marked with this icon
+<inlinemediaobject>
+<imageobject>
+<imagedata fileref="catalogmanager_nopot.png" format="PNG"/>
+</imageobject>
+</inlinemediaobject>, like
+<inlinemediaobject>
+<imageobject>
+<imagedata fileref="catalogmanager_nopot_ok.png" format="PNG"/>
+</imageobject>
+</inlinemediaobject>,
+it indicates that this file or folder does not exist in the
+folder of the <acronym>POT</acronym> files.</para>
+
+<para> You can mark or unmark a file by selecting <guimenuitem>Toggle
+Marking</guimenuitem> in the context menu of a file.</para>
+
+<para>If you want to toggle or remove all markings in a folder,
+press the right mouse button over the folder and select
+<guimenuitem>Toggle Markings</guimenuitem> or <guimenuitem>Remove
+Markings</guimenuitem>. The markings are automatically saved when
+leaving &kbabel;.</para>
+
+<para>To open a file either double-click on the file, select
+<menuchoice><guimenuitem>Open</guimenuitem></menuchoice> from the
+context menu or press either <keycap>Return</keycap> or <keycombo
+action="simul">&Ctrl;<keycap>O</keycap> </keycombo>.</para>
+
+<para>You can configure the &catalogmanager; by
+<menuchoice><guimenu>Project</guimenu><guimenuitem>
+Configure...</guimenuitem></menuchoice>.
+See section <link linkend="preferences-project-settings">Project Settings</link> for more
+details.</para>
+
+<sect1 id="catman-features">
+<title>&catalogmanager; Features</title>
+<para>
+Besides the main feature for opening the files in &kbabel; &catalogmanager;
+supports number of other features for maintaining a tree of
+<acronym>PO</acronym>-files.
+</para>
+
+<sect2 id="catman-find">
+<title>Find and replace in multiple files</title>
+<para>
+One of the most requested features for &kbabel; was a possibility to search and replace in
+multiple files at once. &catalogmanager; supports this feature with
+a tight integration with &kbabel;
+</para>
+</sect2>
+
+<sect2 id="catman-statistics">
+<title>Statistics</title>
+<para>
+&catalogmanager; can show you a number of statistics about a single file
+or about the whole folders. The statistics contain number of files,
+how many of the files have their templates, how many templates are missing.
+It also counts number of messages in the files and shows statistics about
+how large parts of the messages are translated, fuzzy-translated or
+untranslated.
+</para>
+</sect2>
+
+<sect2 id="catman-syntax">
+<title>Checking the syntax</title>
+<para>
+This allows you to check the syntax of multiple <acronym>PO</acronym>-files
+using <command>msgfmt</command>. If a file fails this check, it cannot
+be used for generating a <acronym>MO</acronym>-file for binary distribution.
+Such an incorrect file will typically result in failing compilation of the package
+the <acronym>PO</acronym>-file belongs to.
+</para>
+</sect2>
+
+<sect2 id="catman-commands">
+<title>User-defined commands</title>
+<para>
+Because &catalogmanager; cannot provide any functionality you would like
+to use, you can extend it by defining your own commands.
+</para>
+<!-- ### TODO: we should lik to preferences-project-file-commands too -->
+<para>
+There are two sets of commands. One for folders and one for single files.
+You can set them in <link
+linkend="preferences-project-folder-commands">configuration dialog </link> and
+access by pressing &RMB; on an entry in the file list.</para>
+</sect2>
+
+</sect1>
+</chapter>
+<!--
+Local Variables:
+mode: xml
+sgml-minimize-attributes:nil
+sgml-general-insert-case:lower
+sgml-indent-step:0
+sgml-indent-data:nil
+End:
+
+vim:tabstop=2:shiftwidth=2:expandtab
+-->
diff --git a/doc/kbabel/dbcan.png b/doc/kbabel/dbcan.png
new file mode 100644
index 00000000..a8cf3080
--- /dev/null
+++ b/doc/kbabel/dbcan.png
Binary files differ
diff --git a/doc/kbabel/dictionaries.docbook b/doc/kbabel/dictionaries.docbook
new file mode 100644
index 00000000..a9e5ed70
--- /dev/null
+++ b/doc/kbabel/dictionaries.docbook
@@ -0,0 +1,517 @@
+<!-- <?xml version="1.0" ?>
+<!DOCTYPE chapter PUBLIC "-//KDE//DTD DocBook XML V4.2-Based Variant V1.1//EN" "dtd/kdex.dtd"> -->
+<!-- Uncomment the previous two lines to validate this document -->
+<!-- standalone. Be sure to recomment them before attempting to -->
+<!-- process index.docbook -->
+
+<chapter id="dictionaries">
+
+<chapterinfo>
+<!-- Fill in this section if this document has a different author -->
+<authorgroup>
+<author>
+<personname><firstname></firstname><surname></surname></personname>
+</author>
+</authorgroup>
+
+<!-- TRANS:ROLES_OF_TRANSLATORS -->
+</chapterinfo>
+
+<title>Dictionaries</title>
+
+<para>&kbabel; has 3 modes which can be used to search translated
+<acronym>PO</acronym> message strings:</para>
+
+<itemizedlist>
+ <listitem>
+ <para>Searching translation, using a translation database
+ </para>
+ </listitem>
+ <listitem>
+ <para>Rough translation
+ </para>
+ </listitem>
+ <listitem>
+ <para>&kbabeldict;
+ </para>
+ </listitem>
+</itemizedlist>
+
+<sect1 id="database">
+<!-- FIXME: settings -->
+<title>Translation database</title>
+
+<!-- ### TODO: only *one* file? Seems more to be four... -->
+<para>Translation database allows you to store translations in a
+database based on Berkeley Database IV, &ie; it is stored in a binary
+file on your disk. The database guarantees fast searching in a large
+number of translations.</para>
+
+<para>This mode is the one best integrated with &kbabel;. Besides
+searching and rough translation it also supports the following
+features:</para>
+
+<itemizedlist>
+<listitem>
+<para>Every new translation typed in the &kbabel; editor can be
+automatically stored in the database.</para>
+</listitem>
+<listitem>
+<para>This database can be used for <quote>diff</quote>-ing
+<acronym>msgid</acronym>.</para>
+</listitem>
+</itemizedlist>
+
+<para>Of course, the more translations are stored in the database, the
+more productive you can be. To fill the database, you can use the
+<guilabel>Database</guilabel> tab in the preferences dialog or you can
+turn on automatic addition of every translated messages on the same
+tab.</para>
+
+<sect2 id="database-settings">
+<title>Settings</title>
+<para>
+You can configure this searching mode and how it should be used by selecting
+<menuchoice>
+ <guisubmenu>Settings</guisubmenu>
+ <guisubmenu>Configure Dictionary</guisubmenu>
+ <guimenuitem>Translation Database</guimenuitem>
+</menuchoice>
+in &kbabel; menu.
+</para>
+<para>
+The <guilabel>Generic</guilabel> tab contains general settings for searching in the
+database.
+</para>
+<variablelist>
+ <varlistentry>
+ <term><guilabel>Search in whole database (slow)</guilabel></term>
+ <listitem>
+ <para>
+ Do not use <quote>good keys</quote>, search in the whole database.
+ This is slow, but will return the most precise results.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><guilabel>Search in list of "good keys" (best)</guilabel></term>
+ <listitem>
+ <para>
+ Use <quote>good keys</quote> strategy. This option will give you the
+ best tradeoff between speed and exact matching.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><guilabel>Return the list of "good keys" (fast)</guilabel></term>
+ <listitem>
+ <para>
+ Just return <quote>good keys</quote>, do not try to eliminate any more
+ texts. This is the fastest provided method, but can lead to a quite large
+ number of imprecise matches.
+ </para>
+ </listitem>
+ </varlistentry>
+<varlistentry>
+ <term><guibutton>Case sensitive</guibutton></term>
+ <listitem>
+ <para>
+ Distinguish case of letters when searching the text.
+ </para>
+ </listitem>
+ </varlistentry>
+<varlistentry>
+ <term><guibutton>Normalize white space</guibutton></term>
+ <listitem>
+ <para>
+ Skip unnecessary white space in the texts, so the searching will ignore small
+ differences of white space, &eg; number of spaces in the text.
+ </para>
+ </listitem>
+ </varlistentry>
+<varlistentry>
+ <term><guibutton>Remove context comment</guibutton></term>
+ <listitem>
+ <para>
+ Do not include context comments in search. You will want this to be turned on.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><guilabel>Character to be ignored</guilabel></term>
+ <listitem>
+ <para>Here you can enter characters, which should be ignored while searching.
+ Typical example would be accelerator mark, &ie; &amp; for &kde; texts.
+ </para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+<para>
+The <guilabel>Search</guilabel> tab contains finer specification for searching the text.
+You can define how to search and also allows to use another special way of searching
+called <emphasis><guilabel>Word substitution</guilabel></emphasis>. By substituting
+one or two words the approximate text can be found as well. For example, assume you
+are trying to find the text <userinput>My name is Andrea</userinput>.
+</para>
+<variablelist>
+ <varlistentry>
+ <term><guilabel>Equal</guilabel></term>
+ <listitem>
+ <para>
+ Text from database matches if it is the same as the searched string. In our example it can
+ be <emphasis>My name is &amp;Andrea</emphasis> (if &amp; is set as ignored character
+ in <guilabel>Characters to be ignored</guilabel> on <guilabel>Generic</guilabel> tab).
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><guilabel>Query is contained</guilabel></term>
+ <listitem>
+ <para>
+ Text from database matches if the searched string is contained in it. For our example it can
+ be <emphasis>My name is Andrea, you know?</emphasis>.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><guilabel>Query contains</guilabel></term>
+ <listitem>
+ <para>
+ Text from database matches if the searched string contains it. For our example it can
+ be <emphasis>Andrea</emphasis>. You can use this for enumerating the possibilities to
+ be found.
+ </para>
+ </listitem>
+ </varlistentry>
+<varlistentry>
+ <term><guibutton>Regular Expression</guibutton></term>
+ <listitem>
+ <para>
+ Consider searched text as a regular expression. This is mainly used for
+ &kbabeldict;. You can hardly expect regular expressions in PO files.
+ </para>
+ </listitem>
+ </varlistentry>
+<varlistentry>
+ <term><guibutton>Use one word substitution</guibutton></term>
+ <listitem>
+ <para>
+ If the query text contains less words than specified below, it also
+ tries to replace one of the words in the query. In our example it will
+ find <emphasis>Your name is Andrea</emphasis> as well.
+ </para>
+ </listitem>
+ </varlistentry>
+<varlistentry>
+ <term><guibutton>Max number of words in the query</guibutton></term>
+ <listitem>
+ <para>
+ Maximal number of words in a query to enable one word substitution.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><guilabel>Local characters for regular expressions</guilabel></term>
+ <listitem>
+ <para>
+ Characters to be considered part of regular expressions.
+ </para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+<note>
+<para>
+Two-word substitution is not implemented yet.
+</para>
+</note>
+</sect2>
+
+<sect2 id="database-fill">
+<title>Filling the database</title>
+<para>
+The <guilabel>Database</guilabel> tab allows to define where is the database stored on
+disk (<guilabel>Database folder</guilabel>) and if it should be used for automatic
+storing of the new translations (<guibutton>Auto add entry to database</guibutton>).
+In this case you should specify the author of the new translation in <guilabel>Auto added
+entry author</guilabel>.
+</para>
+<para>
+The rest of the tab allows you to fill the database from PO files that already exist. Use one
+of the buttons in the middle of the dialog box. The progress of the file load will be
+shown by progress bars below the buttons. The <guilabel>Repeated strings</guilabel>
+button should be used in the special case where one translated string is repeated many
+times, to prevent storing unnecessary copies. Here you can limit the stored strings.
+</para>
+<screenshot>
+<screeninfo>Filling the database</screeninfo>
+<mediaobject>
+<imageobject>
+<imagedata fileref="dbcan.png" format="PNG"/>
+</imageobject>
+<textobject><phrase>Filling the database by existing PO-files</phrase></textobject>
+</mediaobject>
+</screenshot></sect2>
+
+<sect2 id="database-goodkeys">
+<title>Defining good keys</title>
+<para>
+On the <guilabel>Good keys</guilabel> tab are the thresholds to specify how to fill
+the list of good keys.
+<guilabel>Minimum number of query words in the key (%)</guilabel> specifies exactly that.
+Text will need to contain only this per cent of the words to qualify as good key. Opposite can
+be specified via <guilabel>Minimum number of words of the key also in the query (%)</guilabel>.
+The length of the words can be set by <guilabel>Max length</guilabel> spinbox.
+</para>
+<para>Searched text typically contains number of generic words, &eg; articles. You can
+eliminate the words based on the frequency. You can discard them by
+<guilabel>Discard words more frequent than</guilabel> or consider as always present by
+<guilabel>frequent words are considered as in every key</guilabel>. This way the
+frequent words will be almost invisible for queries.
+</para>
+</sect2>
+</sect1>
+
+
+<sect1 id="auxiliary">
+<title>Auxiliary PO file</title>
+
+<para>This searching mode is based on matching the same original
+English string (the msgid) translated in some other language in an
+auxillary <acronym>PO</acronym> file. It is very common for Romance
+<!-- ### TODO: is "Anglo-Saxon" not too Romance or too technical for an English text? -->
+languages to have similar words, similarly for Anglo-Saxon and
+Slavic ones.</para>
+
+<para>
+For example, say I wanted to translate the word
+<quote>on</quote>, from <filename>kdelibs.po</filename>, into Romanian
+but have no clue. I look in the same file for French and find
+<foreignphrase lang="fr">actif</foreignphrase>, and in the Spanish one find
+<foreignphrase lang="es">activado</foreignphrase>. So, I conclude that the best one in Romanian
+will be <foreignphrase lang="ro">active</foreignphrase>.
+(Of course, in English instead of <quote>on</quote> the word could have been
+<quote>active</quote> or <quote>activated</quote>,
+which would have made the translation process easier.)
+&kbabel; automates this task. Currently you can define only one auxiliary file to search.
+</para>
+
+<sect2 id="auxiliary-settings">
+<title>Settings</title>
+<para>
+You can configure this searching mode by selecting
+<menuchoice>
+ <guisubmenu>Settings</guisubmenu>
+ <guisubmenu>Configure Dictionary</guisubmenu>
+ <guimenuitem>PO Auxiliary</guimenuitem>
+</menuchoice>
+from the &kbabel; menu.</para>
+
+<para>In the <guilabel>Configure Dictionary PO Auxiliary</guilabel>
+dialog you can select the path to the auxiliary <acronym>PO</acronym>
+file. To automate <acronym>PO</acronym>-file switching when you
+change current edited file there are many variables delimited by
+<literal>@</literal> char that are replaced by appropriate
+values:</para>
+
+<variablelist>
+ <varlistentry>
+ <term>@PACKAGE@</term>
+ <listitem><para>
+ The name of application or package currently being translated.
+ For example, it can expand to kbabel, kdelibs, konqueror
+ and so on.
+ </para></listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>@LANG@</term>
+ <listitem><para>
+ The language code.
+ For example can expand to: de, ro, fr etc.
+ </para></listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>@DIRn@</term>
+ <listitem><para>
+ where <quote>n</quote> is a positive integer. This expands to
+ the <quote>n</quote>-th folder counted from the filename (right to
+ left).
+ </para></listitem>
+ </varlistentry>
+</variablelist>
+
+<para>The edit line displays the actual path to the auxiliary
+<acronym>PO</acronym> file. While it is best to use the
+provided variables in a path it is possible to choose an absolute,
+real path to an existing <acronym>PO</acronym> file. Let's take an
+example.</para>
+
+<para>I'm Romanian and I have some knowledge about French language and
+I work on &kde; translation.</para>
+
+<!-- ### TODO: check URL, especially the kde-l10n part -->
+<para>First step is to download a very fresh
+<filename>kde-l10n-fr.tar.bz2</filename> from the <ulink
+url="ftp://ftp.kde.org/pub/kde/snapshots/kde-l10n">&kde; &FTP;
+site</ulink> or to use the <acronym>CVS</acronym> system to put on my
+hard-disk a French translation tree. I do this into
+<filename>/home/clau/cvs-cvs.kde.org/kde-l10n/fr</filename>.</para>
+
+<para>My <acronym>PO</acronym> sources folder is in
+<filename>/home/clau/cvs-cvs.kde.org/kde-l10n/ro</filename>. Do not
+forget to select <guilabel>PO Auxiliary</guilabel> as the default
+dictionary and check <guilabel>Automatically start search</guilabel>
+on the <guilabel>Search</guilabel> tab from &kbabel;'s
+<guilabel>Preferences</guilabel> dialog.</para>
+
+</sect2>
+</sect1>
+
+<sect1 id="compendium">
+<!-- FIXME: examples -->
+<title>PO compendium</title>
+
+<para>A compendium is a file containing a collection of all
+translation messages (pairs of <acronym>msgid</acronym> and
+<acronym>msgstr</acronym>) in a project, &eg; in &kde;. Typically,
+compendium for a given language is created by concatenating all
+<acronym>PO</acronym> files of the project for the
+language. Compendium can contain translated, untranslated and fuzzy
+messages. Untranslated ones are ignored by this module. </para>
+
+<para>Similarly to Auxiliary <acronym>PO</acronym>, this searching
+mode is based on matching the <quote>same</quote> original string
+(<acronym>msgid</acronym>) in a compendium. Currently you can define
+only one compendium file to search. </para>
+
+<para>This mode is very useful if you are not using the translation
+database and you want to achieve consistent translation with other
+translations. By the way, compendium files are much easier to share
+with other translators and even other translation projects because
+they can be generated for them as well. </para>
+
+<sect2 id="compendium-settings">
+<title>Settings</title>
+
+<para>
+You can configure this searching mode by selecting
+<menuchoice>
+ <guisubmenu>Settings</guisubmenu>
+ <guisubmenu>Configure Dictionary</guisubmenu>
+ <guimenuitem>PO Compendium</guimenuitem>
+</menuchoice>
+in &kbabel;'s menu.
+</para>
+
+<para>In <guilabel>Configure Dictionary PO Compendium</guilabel>
+dialog you can select the path to a compendium file. To automate
+compendium file switching when you change the translation language,
+there is a variable delimited by <literal>@</literal> char which si
+replaced by appropriate value:</para>
+
+<variablelist>
+ <varlistentry>
+ <term>@LANG@</term>
+ <listitem><para>
+ The language code.
+ For example can expand to: de, ro, fr etc.
+ </para></listitem>
+ </varlistentry>
+</variablelist>
+
+<para>In the edit line is displayed the actual path to compendium
+<acronym>PO</acronym> file. While you had best use provided variables in
+path, it's possible to choose an absolute, real path to an existing
+<acronym>PO</acronym> file to be used as a compendium.</para>
+
+<!-- ### TODO: check URL, especially the kde-l10n part -->
+<para>A very fresh compendium for &kde; translation into &eg; French
+you can download <filename>fr.messages.bz2</filename> from the <ulink
+url="ftp://ftp.kde.org/pub/kde/snapshots/kde-l10n">&kde; &FTP;
+site</ulink>. </para>
+
+<para>You can define how to search in the compendium using options
+below the path. They are divided into two groups: text-matching
+options, where you can specify how the text is compared and whether to
+ignore fuzzy translations, and message-matching options, which
+determine if the translation from compendium should be a substring of
+searching message or vice versa.</para>
+
+<variablelist>
+ <varlistentry>
+ <term><guilabel>Case sensitive</guilabel></term>
+ <listitem>
+ <para>
+ If the matching of message in compendium should distinguish between uppercase and lowercase letters.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><guilabel>Ignore fuzzy string</guilabel></term>
+ <listitem>
+ <para>
+ If the fuzzy messages in the compendium should be ignored for searching. The compendium can contain fuzzy messages, since it is typically created by concatenating the <acronym>PO</acronym> files of the project which can include fuzzy messages. Untranslated ones are ignored always (You can't search for translation in untranslated messages, right?)</para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><guilabel>Only whole words</guilabel></term>
+ <listitem>
+ <para>
+ If the matching text should start and end at the boundaries of words.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>A text matches if it <guilabel>is equal to search text</guilabel></term>
+ <listitem>
+ <para>
+ A text in compendium matches the search text only if it is exactly the same (of course using the options above).
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>A text matches if it <guilabel>is similar to search text</guilabel></term>
+ <listitem>
+ <para>
+ A text in compendium matches the search text only if it is <quote>similar</quote>. Both texts are compared by short chunks of letters (<quote>3-grams</quote>) and at least half of the chunks has to be same.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>A text matches if it <guilabel>contains search text</guilabel></term>
+ <listitem>
+ <para>
+ A text in compendium matches the search text if it contains the search text.</para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>A text matches if it <guilabel>is contained in search text</guilabel></term>
+ <listitem>
+ <para>
+ A text in compendium matches the search text if it is contained the search text.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>A text matches if it <guilabel>contains a word of search text</guilabel></term>
+ <listitem>
+ <para>
+ The texts are divided to words and a text in compendium matches the search text only if it contains some word from the search text.
+ </para>
+ </listitem>
+ </varlistentry>
+</variablelist>
+</sect2>
+</sect1>
+</chapter>
+<!--
+Local Variables:
+mode: xml
+sgml-minimize-attributes:nil
+sgml-general-insert-case:lower
+sgml-indent-step:0
+sgml-indent-data:nil
+End:
+
+vim:tabstop=2:shiftwidth=2:expandtab
+-->
+
diff --git a/doc/kbabel/editcopy.png b/doc/kbabel/editcopy.png
new file mode 100644
index 00000000..c600e997
--- /dev/null
+++ b/doc/kbabel/editcopy.png
Binary files differ
diff --git a/doc/kbabel/editcut.png b/doc/kbabel/editcut.png
new file mode 100644
index 00000000..21c36739
--- /dev/null
+++ b/doc/kbabel/editcut.png
Binary files differ
diff --git a/doc/kbabel/editpaste.png b/doc/kbabel/editpaste.png
new file mode 100644
index 00000000..f6a1db8f
--- /dev/null
+++ b/doc/kbabel/editpaste.png
Binary files differ
diff --git a/doc/kbabel/faq.docbook b/doc/kbabel/faq.docbook
new file mode 100644
index 00000000..ce8a6737
--- /dev/null
+++ b/doc/kbabel/faq.docbook
@@ -0,0 +1,66 @@
+<!-- <?xml version="1.0" ?>
+<!DOCTYPE chapter PUBLIC "-//KDE//DTD DocBook XML V4.2-Based Variant V1.1//EN" "dtd/kdex.dtd"> -->
+<!-- Uncomment the previous two lines to validate this document -->
+<!-- standalone. Be sure to recomment them before attempting to -->
+<!-- process index.docbook -->
+
+<chapter id="faq">
+<chapterinfo>
+<!-- Fill in this section if this document has a different author -->
+<authorgroup>
+<author>
+<personname><firstname></firstname><surname></surname></personname>
+</author>
+</authorgroup>
+
+<!-- TRANS:ROLES_OF_TRANSLATORS -->
+</chapterinfo>
+
+<title>Questions and Answers</title>
+<qandaset>
+ <!-- ### FIXME: describe better the situation of Qt3. (This text sounds like being for Qt2.) -->
+ <qandaentry>
+ <question>
+ <para>
+ Why does &kbabel; show question marks instead of language specific
+characters after loading a <acronym>PO</acronym> file?</para>
+ </question>
+ <answer>
+ <para>
+ The text contains characters, which can not be displayed with your system font. If you are sure, that the text contains no such characters, the file might have been corrupted somehow. In this case, mark such a question mark and press
+ <keycombo action="simul">&Ctrl;<keycap>F</keycap></keycombo> to find all the corrupted characters and replace them.<note>
+ <para>
+ Do not search for real question marks, because these characters are only displayed as question marks, but internally they are different characters.
+ </para>
+ </note>
+ Otherwise you might want to install an Unicode font, which contains all
+ necessary characters.
+ </para>
+ </answer>
+ </qandaentry>
+<qandaentry>
+<question>
+<para>
+How can I translate &kde;?
+</para>
+</question>
+<answer>
+<para>
+You can look for information about how to translate KDE in the
+<ulink url="http://i18n.kde.org/translation-howto/">The KDE Translation HOWTO</ulink>.
+</para>
+</answer>
+</qandaentry>
+</qandaset>
+</chapter>
+<!--
+Local Variables:
+mode: xml
+sgml-minimize-attributes:nil
+sgml-general-insert-case:lower
+sgml-indent-step:0
+sgml-indent-data:nil
+End:
+
+vim:tabstop=2:shiftwidth=2:expandtab
+--> \ No newline at end of file
diff --git a/doc/kbabel/fileopen.png b/doc/kbabel/fileopen.png
new file mode 100644
index 00000000..2d27efc8
--- /dev/null
+++ b/doc/kbabel/fileopen.png
Binary files differ
diff --git a/doc/kbabel/filesave.png b/doc/kbabel/filesave.png
new file mode 100644
index 00000000..14d339d8
--- /dev/null
+++ b/doc/kbabel/filesave.png
Binary files differ
diff --git a/doc/kbabel/find.png b/doc/kbabel/find.png
new file mode 100644
index 00000000..92ae8f30
--- /dev/null
+++ b/doc/kbabel/find.png
Binary files differ
diff --git a/doc/kbabel/forward.png b/doc/kbabel/forward.png
new file mode 100644
index 00000000..66315588
--- /dev/null
+++ b/doc/kbabel/forward.png
Binary files differ
diff --git a/doc/kbabel/glossary.docbook b/doc/kbabel/glossary.docbook
new file mode 100644
index 00000000..8138da5b
--- /dev/null
+++ b/doc/kbabel/glossary.docbook
@@ -0,0 +1,211 @@
+<!-- <?xml version="1.0" ?>
+<!DOCTYPE glossary PUBLIC "-//KDE//DTD DocBook XML V4.2-Based Variant V1.1//EN" "dtd/kdex.dtd"> -->
+<!-- Uncomment the previous two lines to validate this document -->
+<!-- standalone. Be sure to recomment them before attempting to -->
+<!-- process index.docbook -->
+
+<glossary id="glossary">
+<glossaryinfo>
+<!-- Fill in this section if this document has a different author -->
+<authorgroup>
+<author>
+<personname><firstname></firstname><surname></surname></personname>
+</author>
+</authorgroup>
+
+<!-- TRANS:ROLES_OF_TRANSLATORS -->
+</glossaryinfo>
+
+<title>Glossary</title>
+
+<glossdiv><title>A</title>
+ <glossentry id="gloss-auxiliary">
+ <glossterm>Auxiliary file</glossterm>
+ <glossdef>
+ <para>
+ is a &kbabel; specific issue. It is an option for the user to
+ set up one <acronym>PO</acronym> file to search through for original messages. For example,
+ if you're a member of French team and have some Spanish or Italian
+ knowledge you can grab and set-up an auxiliary Spanish <acronym>PO</acronym> file
+ associated with the file currently being translated.
+
+ </para>
+ </glossdef>
+ </glossentry>
+</glossdiv>
+
+<glossdiv><title>C</title>
+ <glossentry id="gloss-compendium">
+ <glossterm>Compendium file</glossterm>
+ <glossdef>
+ <para>
+ is a collection of all translations
+ for one language. This big <acronym>PO</acronym> file
+ is made by unique messages from all
+ applications' <acronym>PO</acronym> files. It can
+ be used to fill in all already translated
+ strings into a new yet untranslated
+ or partially translated <acronym>PO</acronym> file.
+ &kbabel; uses such a file in the <quote>PO Compendium</quote>
+ search engine.
+ </para>
+ </glossdef>
+ </glossentry>
+</glossdiv>
+
+<glossdiv><title>F</title>
+ <glossentry id="fuzzy">
+ <glossterm>Fuzzy</glossterm>
+ <glossdef>
+ <para>
+ This is a flag generated, in general,
+ by <command>msgmerge</command>. It shows
+ that a <acronym>msgstr</acronym> string
+ might not be a correct translation.
+ The translator must see and make modifications
+ to the string if necessary and then remove
+ the <quote>fuzzy</quote> flag
+ from the message's comment.
+ </para>
+ </glossdef>
+ </glossentry>
+</glossdiv>
+
+<glossdiv><title>I</title>
+ <glossentry id="i18n">
+ <glossterm>Internationalization</glossterm>
+ <acronym>i18n</acronym>
+ <glossdef>
+ <para>
+ is the operation by which an application
+ is made aware and able to support multiple
+ languages. The word <quote>internationalization</quote>
+ has 20 characters so, to shorten it,
+ people started to write only
+ the first and last characters and between them
+ write the number of intermediate characters (18)
+ forming the common abbreviation <acronym>i18n</acronym>.
+ </para>
+ <glossseealso otherterm="l10n"></glossseealso>
+ </glossdef>
+ </glossentry>
+</glossdiv>
+
+<glossdiv><title>L</title>
+ <glossentry id="l10n">
+ <glossterm>Localization</glossterm>
+ <acronym>l10n</acronym>
+ <glossdef>
+ <para>
+ is the operation by which an application
+ already internationalized is made
+ to process input and output in a fashion
+ desired by some cultural and language habits.
+ The word <quote>localization</quote>
+ has 12 characters so, to shorten it,
+ people started to write only
+ the first and last characters and between them
+ write the number of intermediate characters (10)
+ forming the common abbreviation <acronym>l10n</acronym>.
+ </para>
+ <glossseealso otherterm="i18n"></glossseealso>
+ </glossdef>
+ </glossentry>
+</glossdiv>
+
+<glossdiv><title>M</title>
+ <glossentry id="mofile">
+ <glossterm>MO file</glossterm>
+ <acronym>MO</acronym>
+ <glossdef>
+ <para>
+ <acronym>MO</acronym> stands for <quote>Machine Object</quote>. A <acronym>MO</acronym> file
+ contains binary data suitable
+ for reading by computers.
+ The contents of a <acronym>MO</acronym> file are organized as a database
+ to minimize the lookup time
+ for translated strings. <acronym>MO</acronym> files
+ are obtained by compiling <acronym>PO</acronym> files
+ using <command>msgfmt</command>.
+
+ </para>
+ <glossseealso otherterm="pofile"></glossseealso>
+ <glossseealso otherterm="potfile"></glossseealso>
+ </glossdef>
+ </glossentry>
+ <glossentry id="msgid">
+ <glossterm>Message ID</glossterm>
+ <acronym>msgid</acronym>
+ <glossdef>
+ <para>
+ <acronym>msgid</acronym> is the keyword
+ which introduces the original string in a <acronym>PO</acronym> file.
+ It is followed by a C-like string that spans
+ one or more lines.
+ </para>
+ <glossseealso otherterm="msgstr"></glossseealso>
+ </glossdef>
+ </glossentry>
+ <glossentry id="msgstr">
+ <glossterm>Message String</glossterm>
+ <acronym>msgstr</acronym>
+ <glossdef>
+ <para>
+ <acronym>msgstr</acronym> is the keyword
+ which introduce the translated string in <acronym>PO</acronym> file.
+ It is followed by C-like string that span
+ on one or multiple lines.
+ </para>
+ <glossseealso otherterm="msgid"></glossseealso>
+ </glossdef>
+ </glossentry>
+</glossdiv>
+
+<glossdiv><title>P</title>
+ <glossentry id="pofile">
+ <glossterm>PO file</glossterm>
+ <acronym>PO</acronym>
+ <glossdef>
+ <para>
+ <acronym>PO</acronym> stands for <quote>Portable Object</quote>. <acronym>PO</acronym> files
+ contain sets of strings which
+ associate each translatable string
+ with its translation in a particular
+ language. A single <acronym>PO</acronym> file relates
+ to only one language. A <acronym>PO</acronym> file is
+ derived from a <acronym>POT</acronym> file and is
+ edited either by hand or using &kbabel;.
+ </para>
+ <glossseealso otherterm="potfile"></glossseealso>
+ <glossseealso otherterm="mofile"></glossseealso>
+ </glossdef>
+ </glossentry>
+ <glossentry id="potfile">
+ <glossterm>POT file</glossterm>
+ <acronym>POT</acronym>
+ <glossdef>
+ <para>
+ <acronym>POT</acronym> stands for <quote>Portable Object Template</quote>. A <quote>POT</quote> file is built by extracting all the
+ translatable strings from application
+ source files. A <quote>POT</quote> file does not
+ contain translations into any particular language&mdash;
+ it is used by the translators as a template.
+ </para>
+ <glossseealso otherterm="pofile"></glossseealso>
+ <glossseealso otherterm="mofile"></glossseealso>
+ </glossdef>
+ </glossentry>
+</glossdiv>
+
+</glossary>
+<!--
+Local Variables:
+mode: xml
+sgml-minimize-attributes:nil
+sgml-general-insert-case:lower
+sgml-indent-step:0
+sgml-indent-data:nil
+End:
+
+vim:tabstop=2:shiftwidth=2:expandtab
+-->
diff --git a/doc/kbabel/index.docbook b/doc/kbabel/index.docbook
new file mode 100644
index 00000000..51cb8661
--- /dev/null
+++ b/doc/kbabel/index.docbook
@@ -0,0 +1,174 @@
+<?xml version="1.0" ?>
+<!DOCTYPE book PUBLIC "-//KDE//DTD DocBook XML V4.2-Based Variant V1.1//EN" "dtd/kdex.dtd" [
+ <!ENTITY using SYSTEM "using.docbook">
+ <!ENTITY kbabeldictchapter SYSTEM "kbabeldict.docbook">
+ <!ENTITY catman SYSTEM "catman.docbook">
+ <!ENTITY dictionaries SYSTEM "dictionaries.docbook">
+ <!ENTITY menu SYSTEM "menu.docbook">
+ <!ENTITY preferences SYSTEM "preferences.docbook">
+ <!ENTITY kbabelfaq SYSTEM "faq.docbook">
+ <!ENTITY glossary SYSTEM "glossary.docbook">
+ <!ENTITY kappname "&kbabel;">
+ <!ENTITY package "kdesdk">
+ <!ENTITY % addindex "IGNORE">
+ <!ENTITY % English "INCLUDE" > <!-- change language only here -->
+]>
+
+<book lang="&language;">
+
+<bookinfo>
+<title>The &kbabel; Handbook</title>
+
+<authorgroup>
+<author>
+&Stanislav.Visnovsky; &Stanislav.Visnovsky.mail;
+</author>
+<author>
+&Matthias.Kiefer;
+</author>
+<author>
+<firstname>Nicolas</firstname>
+<surname>Goutte</surname>
+<email>goutte@kde.org</email>
+</author>
+<!-- TRANS:ROLES_OF_TRANSLATORS -->
+</authorgroup>
+
+
+<date>2005-12-29</date>
+<releaseinfo>3.5.1.03</releaseinfo>
+
+<abstract>
+<para>
+&kbabel; is a suite of of an advanced and easy to use
+<acronym>PO</acronym> file editor comprising &kbabel;, a multi
+functional &catalogmanager; and a dictionary for translators
+&kbabeldict;. It supports many advanced features and it lets you
+customize many options.
+</para>
+</abstract>
+
+<keywordset>
+<keyword>KDE</keyword>
+<keyword>KBabel</keyword>
+<keyword>catalogmanager</keyword>
+<keyword>kdesdk</keyword>
+<keyword>gettext</keyword>
+<keyword>translation</keyword>
+<keyword>i18n</keyword>
+<keyword>internationalization</keyword>
+<keyword>l10n</keyword>
+<keyword>localization</keyword>
+</keywordset>
+
+</bookinfo>
+
+<chapter id="introduction">
+<title>Introduction</title>
+
+<important><para>
+In its current state, this KBabel documentation is partially outdated.
+The basic documentation was meant for KDE 3.2,
+the corrections are meant for KBabel 1.11.1 of KDE 3.5.1.
+</para></important>
+
+<para>
+&kbabel; is an advanced and easy to use <acronym>PO</acronym> file
+(&GNU; gettext message catalogs) editor. It has many features, that
+make it easy to edit and manage your <acronym>PO</acronym> files.
+This includes full navigation capabilities, extensive editing
+functionality, search functions, syntax checking and statistics
+function. &catalogmanager; is a file manager view, which helps you
+keep an overview over your <acronym>PO</acronym> files. &kbabeldict;
+allows you to translate any text using &kbabel; capabilities for
+automated translation. The &kbabel; suite will help you to translate
+quickly and also to keep translations consistent.
+</para>
+
+<para>
+With the &kde; project growing continuously, the number of
+<acronym>PO</acronym> messages is over 47000 at the time of writing
+this documentation (plus another 20000 messages used for translating
+application documentation). There is a need to stay organized and
+consistent across all translations.
+</para>
+
+</chapter>
+
+&using;
+&catman;
+&kbabeldictchapter;
+&dictionaries;
+&preferences;
+&menu;
+&kbabelfaq;
+
+
+<chapter id="credits">
+<title>Credits and License</title>
+
+<para>
+&kbabel;
+</para>
+<para>
+Program Copyright &copy; 1999-2000 &Matthias.Kiefer; &Matthias.Kiefer.mail;
+</para>
+<para>
+Contributors:
+<itemizedlist>
+<listitem><para>&Thomas.Diehl; &Thomas.Diehl.mail;</para>
+</listitem>
+<listitem><para>&Stephan.Kulow; &Stephan.Kulow.mail;</para>
+</listitem>
+</itemizedlist>
+</para>
+
+<para>Documentation Copyright &copy; 2000 &Claudiu.Costin;
+&Claudiu.Costin.mail; and &Matthias.Kiefer;
+&Matthias.Kiefer.mail;</para>
+
+<para>Update for &kde; 3.0 Copyright &copy; 2002 &Stanislav.Visnovsky;
+&Stanislav.Visnovsky.mail;</para>
+
+<para>Update for &kde; 3.5.1 Copyright &copy; 2005 Nicolas Goutte
+<email>goutte@kde.org</email></para>
+
+<!-- TRANS:CREDIT_FOR_TRANSLATORS -->
+
+&underFDL;
+&underGPL;
+
+</chapter>
+
+&glossary;
+
+<appendix id="mailing-list">
+<title>Mailing List For KBabel</title>
+
+<para>
+There is a mailing list for KBabel named kbabel.
+It is a mixed list for developers and for users of KBabel.
+</para>
+
+<para>
+You can subscribe it at
+<ulink url="http://mail.kde.org/mailman/listinfo/kbabel/">the Mailman interface</ulink>.
+</para>
+
+<para>
+The mailing list has
+<ulink url="http://mail.kde.org/pipermail/kbabel/">a public archive</ulink>.
+</para>
+
+</appendix>
+
+&documentation.index;
+</book>
+
+<!--
+Local Variables:
+mode: sgml
+sgml-minimize-attributes: nil
+sgml-general-insert-case: lower
+End:
+-->
diff --git a/doc/kbabel/kbabeldict.docbook b/doc/kbabel/kbabeldict.docbook
new file mode 100644
index 00000000..efe70b79
--- /dev/null
+++ b/doc/kbabel/kbabeldict.docbook
@@ -0,0 +1,85 @@
+<!-- <?xml version="1.0" ?>
+<!DOCTYPE chapter PUBLIC "-//KDE//DTD DocBook XML V4.2-Based Variant V1.1//EN" "dtd/kdex.dtd"> -->
+<!-- Uncomment the previous two lines to validate this document -->
+<!-- standalone. Be sure to recomment them before attempting to -->
+<!-- process index.docbook -->
+
+<!-- Note: the id attribute "using-kbabeldict" is used in KBabelDict's source code to call the help.
+So if you change this id attribute, the name *must* be changed in KBabelDict's source code too! -->
+<chapter id="using-kbabeldict">
+<chapterinfo>
+<!-- Fill in this section if this document has a different author -->
+<authorgroup>
+<author>
+<personname><firstname></firstname><surname></surname></personname>
+</author>
+</authorgroup>
+
+<!-- TRANS:ROLES_OF_TRANSLATORS -->
+</chapterinfo>
+
+<title>Using &kbabeldict;</title>
+<anchor id="kbabeldict"/>
+<para>
+&kbabeldict; is a simple interface for translation modules for
+&kbabel;. It allows you to search for translations.
+</para>
+<screenshot>
+<screeninfo>Screenshot of &kbabeldict;</screeninfo>
+<mediaobject>
+<imageobject>
+<imagedata fileref="snap_kbabeldict.png" format="PNG"/>
+</imageobject>
+<textobject><phrase>Screenshot of &kbabeldict;</phrase></textobject>
+</mediaobject>
+</screenshot>
+<para>
+The screenshot
+above does not contain settings for selected module. You can show
+them using <guibutton>Show Settings</guibutton>. Preferences
+widget for selected module will be shown on the
+right side of the window. The &kbabeldict;
+window then looks like this:
+</para>
+<screenshot>
+<screeninfo>Screenshot of &kbabeldict;</screeninfo>
+<mediaobject>
+<imageobject>
+<imagedata fileref="snap_kbabeldict2.png" format="PNG"/>
+</imageobject>
+<textobject><phrase>Screenshot of &kbabeldict; with shown settings</phrase></textobject>
+</mediaobject>
+</screenshot>
+<para>
+The usage is very simple. You select a module to in the
+<guilabel>Search in module</guilabel> combo-box.
+Then you enter the phrase to lookup and press <guibutton>Start
+Search</guibutton>. All found messages are shown in the list
+below, which is the same as a tool in the &kbabel; main window.
+Searching can be stopped by pressing <guilabel>Stop</guilabel>.
+In case you want to search in translated text, not in original English message,
+you should use <guilabel>Search in translations</guilabel>.
+</para>
+<para>
+Buttons on the bottom of the window can be used for closing &kbabeldict;,
+showing/hiding the module settings or displaying a dialog with credits for
+&kbabeldict; and the modules themselves.
+</para>
+<note>
+<para>
+For description of the standard modules and their settings see
+<xref linkend="dictionaries"/>.
+</para>
+</note>
+</chapter>
+<!--
+Local Variables:
+mode: xml
+sgml-minimize-attributes:nil
+sgml-general-insert-case:lower
+sgml-indent-step:0
+sgml-indent-data:nil
+End:
+
+vim:tabstop=2:shiftwidth=2:expandtab
+--> \ No newline at end of file
diff --git a/doc/kbabel/man-catalogmanager.1.docbook b/doc/kbabel/man-catalogmanager.1.docbook
new file mode 100644
index 00000000..00d500c0
--- /dev/null
+++ b/doc/kbabel/man-catalogmanager.1.docbook
@@ -0,0 +1,77 @@
+<?xml version="1.0" ?>
+<!DOCTYPE refentry PUBLIC "-//KDE//DTD DocBook XML V4.2-Based Variant V1.1//EN" "dtd/kdex.dtd" [
+<!ENTITY % English "INCLUDE">
+]>
+
+<refentry lang="&language;">
+<refentryinfo>
+<date>2003-03-07</date>
+</refentryinfo>
+
+<refmeta>
+<refentrytitle><command>catalogmanager</command></refentrytitle>
+<manvolnum>1</manvolnum>
+</refmeta>
+
+<refnamediv>
+<refname><command>catalogmanager</command></refname>
+<refpurpose>Advanced catalog manager for &kbabel;</refpurpose>
+</refnamediv>
+
+<refsynopsisdiv>
+<cmdsynopsis>
+<command>catalogmanager</command>
+<group><option>--project</option> <replaceable>config-file</replaceable></group>
+<group><option>KDE Generic Options</option></group>
+<group><option>Qt Generic Options</option></group>
+
+</cmdsynopsis>
+</refsynopsisdiv>
+
+<refsect1>
+<title>Description</title>
+
+<para>CatalogManager is part of a suite of programs for editing
+gettext message files (PO-files). This suite is designed to help you
+translate fast and consistently.</para>
+
+<para>This suite includes &kbabel;,
+<application>CatalogManager</application> and &kbabeldict;. &kbabel;
+is an advanced and easy to use PO-file editor with full navigational
+and editing capabilities, syntax checking and
+statistics. <application>CatalogManager</application> (this program)
+is a multi functional catalog manager which allows you to keep track
+of many PO-files at once. &kbabeldict; is a dictionary for
+translators.</para>
+<para>This utility is part of the &kde; Software Development Kit.</para>
+
+</refsect1>
+
+<refsect1>
+<title>Options</title>
+
+<variablelist>
+<varlistentry>
+<term><option>--project</option> <replaceable>config-file</replaceable></term>
+<listitem>
+<para>Load the configuration from the given file.</para>
+</listitem>
+</varlistentry>
+</variablelist>
+
+</refsect1>
+
+<refsect1>
+<title>See Also</title>
+
+<para>kbabel(1) kbabeldict(1)</para>
+
+<para>More detailed user documentation is available from <ulink
+url="help:/kbabel">help:/kbabel</ulink> (either enter this
+<acronym>URL</acronym> into &konqueror;, or run
+<userinput><command>khelpcenter</command>
+<parameter>help:/kbabel</parameter></userinput>).</para>
+
+</refsect1>
+
+</refentry>
diff --git a/doc/kbabel/menu.docbook b/doc/kbabel/menu.docbook
new file mode 100644
index 00000000..14c474b5
--- /dev/null
+++ b/doc/kbabel/menu.docbook
@@ -0,0 +1,2320 @@
+<!-- <?xml version="1.0" ?>
+<!DOCTYPE chapter PUBLIC "-//KDE//DTD DocBook XML V4.2-Based Variant V1.1//EN" "dtd/kdex.dtd"> -->
+<!-- Uncomment the previous two lines to validate this document -->
+<!-- standalone. Be sure to recomment them before attempting to -->
+<!-- process index.docbook -->
+
+<chapter id="commands">
+
+<chapterinfo>
+<!-- Fill in this section if this document has a different author -->
+<authorgroup>
+<author>
+<personname><firstname></firstname><surname></surname></personname>
+</author>
+</authorgroup>
+
+<!-- TRANS:ROLES_OF_TRANSLATORS -->
+</chapterinfo>
+
+<title>Command Reference</title>
+
+<sect1 id="kbabel-menu">
+<title>The &kbabel; menu</title>
+
+<sect2>
+<title>The File Menu</title>
+<variablelist>
+ <varlistentry>
+ <term>
+ <menuchoice>
+ <shortcut>
+ <keycombo action="simul">
+ &Ctrl;<keycap>O</keycap>
+ </keycombo>
+ </shortcut>
+ <guimenu>File</guimenu>
+ <guimenuitem>Open</guimenuitem>
+ </menuchoice>
+ </term>
+ <listitem>
+ <para>
+ <action>
+ Opens a PO file. If the current file
+ is modified you will be prompted to save it first.
+ </action>
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>
+ <menuchoice>
+ <guimenu>File</guimenu>
+ <guimenuitem>Open Recent</guimenuitem>
+ </menuchoice>
+ </term>
+ <listitem>
+ <para>
+ <action>
+ Opens a recently edited PO file from the recently-used documents menu
+ </action>
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>
+ <menuchoice>
+ <shortcut>
+ <keycombo action="simul">
+ &Ctrl;<keycap>S</keycap>
+ </keycombo>
+ </shortcut>
+ <guimenu>File</guimenu>
+ <guimenuitem>Save</guimenuitem>
+ </menuchoice>
+ </term>
+ <listitem>
+ <para>
+ <action>
+ Saves the current PO file. If it is not modified no action is taken.
+ </action>
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>
+ <menuchoice>
+ <guimenu>File</guimenu>
+ <guimenuitem>Save As</guimenuitem>
+ </menuchoice>
+ </term>
+ <listitem>
+ <para>
+ <action>
+ Saves the current PO file under a new name
+ </action>
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>
+ <menuchoice>
+ <guimenu>File</guimenu>
+ <guimenuitem>Save Special</guimenuitem>
+ </menuchoice>
+ </term>
+ <listitem>
+ <para>
+ <action>
+ Displays the Save Settings dialog and then saves the current PO file under a new name
+ </action>
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>
+ <menuchoice>
+ <guimenu>File</guimenu>
+ <guimenuitem>Revert</guimenuitem>
+ </menuchoice>
+ </term>
+ <listitem>
+ <para>
+ <action>
+ Loads the last saved version of the current PO file
+ </action>
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>
+ <menuchoice>
+ <guimenu>File</guimenu>
+ <guimenuitem>Mail</guimenuitem>
+ </menuchoice>
+ </term>
+ <listitem>
+ <para>
+ <action>
+ Prompts for an archive filename in which to store the current PO file then opens an email composer
+ window with the archive as an attachment
+ </action>
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>
+ <menuchoice>
+ <guimenu>File</guimenu>
+ <guimenuitem>New View</guimenuitem>
+ </menuchoice>
+ </term>
+ <listitem>
+ <para>
+ <action>
+ Opens a new window with the currently loaded file.
+ </action>
+ Very useful if you have to translate large
+ files and need to refer back to some strings.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>
+ <menuchoice>
+ <guimenu>File</guimenu>
+ <guimenuitem>New Window</guimenuitem>
+ </menuchoice>
+ </term>
+ <listitem>
+ <para>
+ <action>
+ Opens a new empty window
+ </action>
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>
+ <menuchoice>
+ <shortcut>
+ <keycombo action="simul">
+ &Ctrl;<keycap>Q</keycap>
+ </keycombo>
+ </shortcut>
+ <guimenu>File</guimenu>
+ <guimenuitem>Quit</guimenuitem>
+ </menuchoice>
+ </term>
+ <listitem>
+ <para>
+ <action>
+ Quits &kbabel; editor
+ </action>
+ </para>
+ </listitem>
+ </varlistentry>
+</variablelist>
+</sect2>
+
+<sect2>
+<title>The Edit Menu</title>
+<variablelist>
+ <varlistentry>
+ <term>
+ <menuchoice>
+ <shortcut>
+ <keycombo action="simul">
+ &Ctrl;<keycap>Z</keycap>
+ </keycombo>
+ </shortcut>
+ <guimenu>Edit</guimenu>
+ <guimenuitem>Undo</guimenuitem>
+ </menuchoice>
+ </term>
+ <listitem>
+ <para>
+ <action>
+ Undoes the last edit action in the translation edit box
+ </action>
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>
+ <menuchoice>
+ <shortcut>
+ <keycombo action="simul">
+ &Ctrl;&Shift;<keycap>Z</keycap>
+ </keycombo>
+ </shortcut>
+ <guimenu>Edit</guimenu>
+ <guimenuitem>Redo</guimenuitem>
+ </menuchoice>
+ </term>
+ <listitem>
+ <para>
+ <action>
+ Redoes the last undone edit action in the translation edit box
+ </action>
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>
+ <menuchoice>
+ <shortcut>
+ <keycombo action="simul">
+ &Ctrl;<keycap>X</keycap>
+ </keycombo>
+ </shortcut>
+ <guimenu>Edit</guimenu>
+ <guimenuitem>Cut</guimenuitem>
+ </menuchoice>
+ </term>
+ <listitem>
+ <para>
+ <action>
+ Cuts the selected text and moves it to the clipboard
+ </action>
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>
+ <menuchoice>
+ <shortcut>
+ <keycombo action="simul">
+ &Ctrl;<keycap>C</keycap>
+ </keycombo>
+ </shortcut>
+ <guimenu>Edit</guimenu>
+ <guimenuitem>Copy</guimenuitem>
+ </menuchoice>
+ </term>
+ <listitem>
+ <para>
+ <action>
+ Copies the selected text to the clipboard
+ </action>
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>
+ <menuchoice>
+ <shortcut>
+ <keycombo action="simul">
+ &Ctrl;<keycap>V</keycap>
+ </keycombo>
+ </shortcut>
+ <guimenu>Edit</guimenu>
+ <guimenuitem>Paste</guimenuitem>
+ </menuchoice>
+ </term>
+ <listitem>
+ <para>
+ <action>
+ Pastes the contents of the clipboard at the current cursor
+ position in the translation edit box.
+ </action>
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>
+ <menuchoice>
+ <guimenu>Edit</guimenu>
+ <guimenuitem>Select All</guimenuitem>
+ </menuchoice>
+ </term>
+ <listitem>
+ <para>
+ <action>
+ Selects all text in the translation edit box
+ </action>
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>
+ <menuchoice>
+ <shortcut>
+ <keycombo action="simul">
+ &Ctrl;<keycap>F</keycap>
+ </keycombo>
+ </shortcut>
+ <guimenu>Edit</guimenu>
+ <guimenuitem>Find...</guimenuitem>
+ </menuchoice>
+ </term>
+ <listitem>
+ <para>
+ <action>
+ Opens a Find dialog for searching for strings in the current PO file
+ </action>
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>
+ <menuchoice>
+ <shortcut>
+ <keycap>F3</keycap>
+ </shortcut>
+ <guimenu>Edit</guimenu>
+ <guimenuitem>Find Next</guimenuitem>
+ </menuchoice>
+ </term>
+ <listitem>
+ <para>
+ <action>
+ Finds the next occurrence of a string from the previous search action
+ </action>
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>
+ <menuchoice>
+ <shortcut>
+ <keycombo action="simul">
+ &Ctrl;<keycap>R</keycap>
+ </keycombo>
+ </shortcut>
+ <guimenu>Edit</guimenu>
+ <guimenuitem>Replace...</guimenuitem>
+ </menuchoice>
+ </term>
+ <listitem>
+ <para>
+ <action>
+ Opens the Replace dialog to search for and replace strings in the current PO file
+ </action>
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>
+ <menuchoice>
+ <shortcut>
+ <keycombo action="simul">
+ &Ctrl;<keycap>Delete</keycap>
+ </keycombo>
+ </shortcut>
+ <guimenu>Edit</guimenu>
+ <guimenuitem>Clear</guimenuitem>
+ </menuchoice>
+ </term>
+ <listitem>
+ <para>
+ <action>
+ Clears the translation for the current msgid
+ </action>
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>
+ <menuchoice>
+ <shortcut>
+ <keycombo action="simul">
+ &Ctrl;<keycap>Space</keycap>
+ </keycombo>
+ </shortcut>
+ <guimenu>Edit</guimenu>
+ <guimenuitem>Copy msgid to msgstr</guimenuitem>
+ </menuchoice>
+ </term>
+ <listitem>
+ <para>
+ <action>
+ Copies the original English string into the translation edit
+ box. This is useful when you do not need to make any changes
+ (or only minor changes) to the original English text (msgstr).
+ </action>
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>
+ <menuchoice>
+ <shortcut>
+ <keycombo action="simul">
+ &Ctrl;&Alt;<keycap>Space</keycap>
+ </keycombo>
+ </shortcut>
+ <guimenu>Edit</guimenu>
+ <guimenuitem>Copy search result to msgstr</guimenuitem>
+ </menuchoice>
+ </term>
+ <listitem>
+ <para>
+ <action>
+ Copies a string found after a translation search
+ into the msgstr edit box. This is
+ very useful if you do not want to keep
+ re-translating the same message again and again.
+ </action>
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>
+ <menuchoice>
+ <shortcut>
+ <keycombo action="simul">
+ &Ctrl;<keycap>U</keycap>
+ </keycombo>
+ </shortcut>
+ <guimenu>Edit</guimenu>
+ <guimenuitem>Toggle Fuzzy Status</guimenuitem>
+ </menuchoice>
+ </term>
+ <listitem>
+ <para>
+ <action>
+ Toggles the fuzzy status for the current entry.</action> It can be useful to turn fuzzy on,
+ &eg; to mark the translation for another review.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>
+ <menuchoice>
+ <shortcut>
+ <keycombo action="simul">
+ &Ctrl;&Alt;<keycap>N</keycap>
+ </keycombo>
+ </shortcut>
+ <guimenu>Edit</guimenu>
+ <guimenuitem>Insert Next Tag</guimenuitem>
+ </menuchoice>
+ </term>
+ <listitem>
+ <para>
+ <action>
+ Inserts the next tag found in the msgid into the translation, if the original English string contains markup tags
+ </action>
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>
+ <menuchoice>
+ <shortcut>
+ <keycombo action="simul">&Ctrl;&Alt;<keycap>N</keycap></keycombo>
+ </shortcut>
+ <guimenu>Edit</guimenu>
+ <guisubmenu>Insert Tag</guisubmenu>
+ </menuchoice>
+ </term>
+ <listitem>
+ <para>
+ <action>
+ This submenu contains all markup tags found in the original English string. By selecting one of them you can insert at the current position of cursor in translated text.
+ translation.
+ </action>
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>
+ <menuchoice>
+ <guimenu>Edit</guimenu>
+ <guimenuitem>Edit Header...</guimenuitem>
+ </menuchoice>
+ </term>
+ <listitem>
+ <para>
+ <action>
+ Edits the PO file header.
+ </action>
+ Actually there are many header lines, which
+ keep the last translated date, translator name and email, language and
+ translated text encoding, &etc;.
+ </para>
+ </listitem>
+ </varlistentry>
+</variablelist>
+</sect2>
+
+
+<sect2>
+<title>The Go Menu</title>
+<variablelist>
+ <varlistentry>
+ <term>
+ <menuchoice>
+ <shortcut>
+ <keycap>Page Up</keycap>
+ </shortcut>
+ <guimenu>Go</guimenu>
+ <guimenuitem>Previous</guimenuitem>
+ </menuchoice>
+ </term>
+ <listitem>
+ <para>
+ <action>
+ Skips to the previous entry in the PO file.
+ </action>
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>
+ <menuchoice>
+ <shortcut>
+ <keycap>Page Down</keycap>
+ </shortcut>
+ <guimenu>Go</guimenu>
+ <guimenuitem>Next</guimenuitem>
+ </menuchoice>
+ </term>
+ <listitem>
+ <para>
+ <action>
+ Skips to the next entry in the PO file.
+ </action>
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>
+ <menuchoice>
+ <guimenu>Go</guimenu>
+ <guimenuitem>Go to...</guimenuitem>
+ </menuchoice>
+ </term>
+ <listitem>
+ <para>
+ <action>
+ Opens a dialog to jump to a specific entry number within the PO file.
+ </action>
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>
+ <menuchoice>
+ <guimenu>Go</guimenu>
+ <guimenuitem>First Entry</guimenuitem>
+ </menuchoice>
+ </term>
+ <listitem>
+ <para>
+ <action>
+ Jumps to the first entry in the PO file.
+ </action>
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>
+ <menuchoice>
+ <guimenu>Go</guimenu>
+ <guimenuitem>Last Entry</guimenuitem>
+ </menuchoice>
+ </term>
+ <listitem>
+ <para>
+ <action>
+ Jumps to the last entry in the PO file.
+ </action>
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>
+ <menuchoice>
+ <shortcut>
+ <keycombo action="simul">
+ &Ctrl;&Shift;<keycap>Page Up</keycap>
+ </keycombo>
+ </shortcut>
+ <guimenu>Go</guimenu>
+ <guimenuitem>Previous fuzzy or untranslated</guimenuitem>
+ </menuchoice>
+ </term>
+ <listitem>
+ <para>
+ <action>
+ Jumps to the entry previous to the current one that is untranslated or
+ marked as fuzzy.
+ </action>
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>
+ <menuchoice>
+ <shortcut>
+ <keycombo action="simul">
+ &Ctrl;&Shift;<keycap>Page Down</keycap>
+ </keycombo>
+ </shortcut>
+ <guimenu>Go</guimenu>
+ <guimenuitem>Next fuzzy or untranslated</guimenuitem>
+ </menuchoice>
+ </term>
+ <listitem>
+ <para>
+ <action>
+ Jumps to the next entry after the current one which is untranslated or
+ marked as fuzzy.
+ </action>
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>
+ <menuchoice>
+ <shortcut>
+ <keycombo action="simul">
+ &Ctrl;<keycap>PgUp</keycap>
+ </keycombo>
+ </shortcut>
+ <guimenu>Go</guimenu>
+ <guimenuitem>Previous fuzzy</guimenuitem>
+ </menuchoice>
+ </term>
+ <listitem>
+ <para>
+ <action>
+ Jumps to the entry previous to the current one that is marked as fuzzy.
+ </action>
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>
+ <menuchoice>
+ <shortcut>
+ <keycombo action="simul">
+ &Ctrl;<keycap>Page Down</keycap>
+ </keycombo>
+ </shortcut>
+ <guimenu>Go</guimenu>
+ <guimenuitem>Next fuzzy</guimenuitem>
+ </menuchoice>
+ </term>
+ <listitem>
+ <para>
+ <action>
+ Jumps to the next entry after the current one that is marked as fuzzy.
+ </action>
+ </para>
+ </listitem>
+ </varlistentry>
+<varlistentry>
+ <term>
+ <menuchoice>
+ <shortcut>
+ <keycombo action="simul">
+ &Alt;<keycap>Page Up</keycap>
+ </keycombo>
+ </shortcut>
+ <guimenu>Go</guimenu>
+ <guimenuitem>Previous untranslated</guimenuitem>
+ </menuchoice>
+ </term>
+ <listitem>
+ <para>
+ <action>
+ Jumps to the entry previous to the current one that is untranslated.
+ </action>
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>
+ <menuchoice>
+ <shortcut>
+ <keycombo action="simul">
+ &Alt;<keycap>Page Down</keycap>
+ </keycombo>
+ </shortcut>
+ <guimenu>Go</guimenu>
+ <guimenuitem>Next untranslated</guimenuitem>
+ </menuchoice>
+ </term>
+ <listitem>
+ <para>
+ <action>
+ Jumps to the next entry after the current one that is untranslated.
+ </action>
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>
+ <menuchoice>
+ <shortcut>
+ <keycombo action="simul">
+ &Shift;<keycap>Page Up</keycap>
+ </keycombo>
+ </shortcut>
+ <guimenu>Go</guimenu>
+ <guimenuitem>Previous error</guimenuitem>
+ </menuchoice>
+ </term>
+ <listitem>
+ <para>
+ <action>
+ Jumps to the previous entry that has an error. This is usually when
+ double-quotes are not escaped or the original string ends with a
+ "newline" (\n) character and the translated string does not (and vice versa).
+ </action>
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>
+ <menuchoice>
+ <shortcut>
+ <keycombo action="simul">
+ &Shift;<keycap>Page Down</keycap>
+ </keycombo>
+ </shortcut>
+ <guimenu>Go</guimenu>
+ <guimenuitem>Next error</guimenuitem>
+ </menuchoice>
+ </term>
+ <listitem>
+ <para>
+ <action>
+ Jumps to the next entry with an error.
+ </action>
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>
+ <menuchoice>
+ <shortcut>
+ <keycombo action="simul">
+ &Alt;<keycap>Left Arrow</keycap>
+ </keycombo>
+ </shortcut>
+ <guimenu>Go</guimenu>
+ <guimenuitem>Back</guimenuitem>
+ </menuchoice>
+ </term>
+ <listitem>
+ <para>
+ <action>
+ Jump to last visited entry</action> in PO file.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>
+ <menuchoice>
+ <shortcut>
+ <keycombo action="simul">
+ &Alt;<keycap>Right Arrow</keycap>
+ </keycombo>
+ </shortcut>
+ <guimenu>Go</guimenu>
+ <guimenuitem>Forward</guimenuitem>
+ </menuchoice>
+ </term>
+ <listitem>
+ <para>
+ <action>
+ Jump to previous visited entry</action> in PO file.
+ </para>
+ </listitem>
+ </varlistentry>
+</variablelist>
+</sect2>
+
+
+<sect2>
+<title>The Dictionaries Menu</title>
+<para>
+Note that this menu is dynamic: it depends on the installed dictionaries plugins.
+By default are three of them.
+</para>
+
+<variablelist>
+ <varlistentry>
+ <term>
+ <menuchoice>
+ <guimenu>Dictionaries</guimenu>
+ <guimenuitem>Search Text</guimenuitem>
+ <guimenuitem>KDE Database Search Engine</guimenuitem>
+ </menuchoice>
+ </term>
+ <listitem>
+ <para>
+ <action>
+ Start searching translation for current original
+ English message</action> using &kde; Database Search Engine.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>
+ <menuchoice>
+ <guimenu>Dictionaries</guimenu>
+ <guimenuitem>Search Text</guimenuitem>
+ <guimenuitem>PO Auxiliary</guimenuitem>
+ </menuchoice>
+ </term>
+ <listitem>
+ <para>
+ <action>
+ Start searching translation for current original
+ English message</action> in <acronym>PO</acronym> file defined by user.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>
+ <menuchoice>
+ <guimenu>Dictionaries</guimenu>
+ <guimenuitem>Search Text</guimenuitem>
+ <guimenuitem>PO Compendium</guimenuitem>
+ </menuchoice>
+ </term>
+ <listitem>
+ <para>
+ <action>
+ Start searching translation for current original
+ English message in compendium file (made
+ by merging all translated messages for
+ one language).
+ </action>
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>
+ <menuchoice>
+ <guimenu>Dictionaries</guimenu>
+ <guimenuitem>Search Selected Text</guimenuitem>
+ <guimenuitem>KDE Database Search Engine</guimenuitem>
+ </menuchoice>
+ </term>
+ <listitem>
+ <para>
+ <action>
+ Start searching selected text</action>
+ using &kde; Database Search Engine.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>
+ <menuchoice>
+ <guimenu>Dictionaries</guimenu>
+ <guimenuitem>Search Selected Text</guimenuitem>
+ <guimenuitem>PO Auxiliary</guimenuitem>
+ </menuchoice>
+ </term>
+ <listitem>
+ <para>
+ <action>
+ Start searching selected text
+ using file defined by user.
+ </action>
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>
+ <menuchoice>
+ <guimenu>Dictionaries</guimenu>
+ <guimenuitem>Search Selected Text</guimenuitem>
+ <guimenuitem>PO Compendium</guimenuitem>
+ </menuchoice>
+ </term>
+ <listitem>
+ <para>
+ <action>
+ Start searching selected text
+ using compendium file with
+ all language translated messages.
+ </action>
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>
+ <menuchoice>
+ <guimenu>Dictionaries</guimenu>
+ <guimenuitem>Edit Dictionary</guimenuitem>
+ </menuchoice>
+ </term>
+ <listitem>
+ <para>
+ <action>
+ Allow you to edit content
+ of current dictionary. Useful
+ if you found errors in dictionary
+ and do not want errors to be reported
+ when searching and replacing
+ strings.
+ </action>
+ <emphasis>(Not implemented yet)</emphasis>
+ </para>
+ </listitem>
+ </varlistentry>
+</variablelist>
+</sect2>
+
+
+
+<sect2>
+<title>The Tools Menu</title>
+<variablelist>
+ <varlistentry>
+ <term>
+ <menuchoice>
+ <guimenu>Tools</guimenu>
+ <guimenuitem>Spelling</guimenuitem>
+ <guimenuitem>Spell check...</guimenuitem>
+ </menuchoice>
+ </term>
+ <listitem>
+ <para>
+ <action>
+ Display the spell-check configuration dialog.</action>
+ After you have chosen the desired options, hit
+ <guibutton>OK</guibutton> and the normal spell-checking
+ dialog will appear.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>
+ <menuchoice>
+ <guimenu>Tools</guimenu>
+ <guimenuitem>Spelling</guimenuitem>
+ <guimenuitem>Check All...</guimenuitem>
+ </menuchoice>
+ </term>
+ <listitem>
+ <para>
+ <action>
+ Start spell-checking all words</action>
+ for an opened <acronym>PO</acronym> file.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>
+ <menuchoice>
+ <guimenu>Tools</guimenu>
+ <guimenuitem>Spelling</guimenuitem>
+ <guimenuitem>Check From Cursor Position...</guimenuitem>
+ </menuchoice>
+ </term>
+ <listitem>
+ <para>
+ <action>
+ Start spell-checking
+ from current cursor position.
+ </action>
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>
+ <menuchoice>
+ <guimenu>Tools</guimenu>
+ <guimenuitem>Spelling</guimenuitem>
+ <guimenuitem>Check Current...</guimenuitem>
+ </menuchoice>
+ </term>
+ <listitem>
+ <para>
+ <action>
+ Spell-check only current</action>
+ entry from <acronym>PO</acronym> file.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>
+ <menuchoice>
+ <guimenu>Tools</guimenu>
+ <guimenuitem>Spelling</guimenuitem>
+ <guimenuitem>Check Marked Text...</guimenuitem>
+ </menuchoice>
+ </term>
+ <listitem>
+ <para>
+ <action>
+ Spell-check only
+ selected text in MsgStr editbox.
+ </action>
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>
+ <menuchoice>
+ <shortcut>
+ <keycombo action="simul">
+ &Ctrl;<keycap>T</keycap>
+ </keycombo>
+ </shortcut>
+ <guimenu>Tools</guimenu>
+ <guimenuitem>Validation</guimenuitem>
+ <guimenuitem>Check Syntax</guimenuitem>
+ </menuchoice>
+ </term>
+ <listitem>
+ <para>
+ <action>
+ Check syntax</action> for current <acronym>PO</acronym> file.
+ Errors may appear from <acronym>CVS</acronym> merging
+ or users' mistakes when the translating
+ process is performed by hand.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>
+ <menuchoice>
+ <shortcut>
+ <keycombo action="simul">
+ &Ctrl;<keycap>D</keycap>
+ </keycombo>
+ </shortcut>
+ <guimenu>Tools</guimenu>
+ <guimenuitem>Validation</guimenuitem>
+ <guimenuitem>Check Arguments</guimenuitem>
+ </menuchoice>
+ </term>
+ <listitem>
+ <para>
+ <action>
+ When this option is selected, C-format strings in the original message and
+ the translation are checked to ensure the number of
+ format sequences and the order are consistent.
+ </action>
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>
+ <menuchoice>
+ <shortcut>
+ <keycombo action="simul">
+ &Ctrl;<keycap>H</keycap>
+ </keycombo>
+ </shortcut>
+ <guimenu>Tools</guimenu>
+ <guimenuitem>Validation</guimenuitem>
+ <guimenuitem>Check Accelerators</guimenuitem>
+ </menuchoice>
+ </term>
+ <listitem>
+ <para>
+ When this option is selected, &kbabel; <action>checks if the number
+of accelerator
+ characters is identical in both the original and the translated
+ string.</action> Note that accelerator marker is &amp; in &kde;
+ (but not in every programming toolkit). See the
+ <link linkend="preferences-project-miscellaneous">Miscellaneous</link> section
+ below to find out how to change a keyboard accelerator.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>
+ <menuchoice>
+ <shortcut>
+ <keycombo action="simul">
+ &Ctrl;<keycap>K</keycap>
+ </keycombo>
+ </shortcut>
+ <guimenu>Tools</guimenu>
+ <guimenuitem>Validation</guimenuitem>
+ <guimenuitem>Look for Translated Context Info</guimenuitem>
+ </menuchoice>
+ </term>
+ <listitem>
+ <para>
+ Some original messages are marked with
+ context information to mark them as being unique even
+ if they represent same word. This is because
+ many simple words, such as <quote>Save</quote>, are translated into
+ many languages. Context information
+ is marked with <literal>_:</literal>. Many
+ unexperienced translators translate the context information
+ and fill their <quote>PO</quote> files with garbage. <action>Check this box to make sure you will be warned about these errors in a file.</action>
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>
+ <menuchoice>
+ <guimenu>Tools</guimenu>
+ <guimenuitem>Validation</guimenuitem>
+ <guimenuitem>Check Plural Forms (KDE only)</guimenuitem>
+ </menuchoice>
+ </term>
+ <listitem>
+ <para>
+ Check if the <acronym>PO</acronym> file <action>contains the correct number of translations</action> for each &kde;-specific plural form message.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>
+ <menuchoice>
+ <shortcut>
+ <keycombo action="simul">
+ &Ctrl;<keycap>J</keycap>
+ </keycombo>
+ </shortcut>
+ <guimenu>Tools</guimenu>
+ <guimenuitem>Validation</guimenuitem>
+ <guimenuitem>Check Equations</guimenuitem>
+ </menuchoice>
+ </term>
+ <listitem>
+ <para>
+ <action>
+ Check whether the left side of the translated string
+ is the same as the left side of the original string.
+ Sides are delimited by an equals-sign character.
+ </action>
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>
+ <menuchoice>
+ <shortcut>
+ <keycombo>
+ <keycap>F5</keycap>
+ </keycombo>
+ </shortcut>
+ <guimenu>Tools</guimenu>
+ <guimenuitem>Diff</guimenuitem>
+ <guimenuitem>Show Diff</guimenuitem>
+ </menuchoice>
+ </term>
+ <listitem>
+ <para>
+ <action>
+ Show difference found to the original translated message.
+ </action>
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>
+ <menuchoice>
+ <shortcut>
+ <keycombo>
+ <keycap>F6</keycap>
+ </keycombo>
+ </shortcut>
+ <guimenu>Tools</guimenu>
+ <guimenuitem>Diff</guimenuitem>
+ <guimenuitem>Show Original Text</guimenuitem>
+ </menuchoice>
+ </term>
+ <listitem>
+ <para>
+ <action>
+ Hide difference markings and show msgid only.
+ </action>
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>
+ <menuchoice>
+ <guimenu>Tools</guimenu>
+ <guimenuitem>Diff</guimenuitem>
+ <guimenuitem>Open File for Diff</guimenuitem>
+ </menuchoice>
+ </term>
+ <listitem>
+ <para>
+ <action>
+ Open file to be used for difference lookup.
+ </action>
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>
+ <menuchoice>
+ <guimenu>Tools</guimenu>
+ <guimenuitem>Diff</guimenuitem>
+ <guimenuitem>Diffmode</guimenuitem>
+ </menuchoice>
+ </term>
+ <listitem>
+ <para>
+ <action>
+ Toggle difference mode.
+ </action>
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>
+ <menuchoice>
+ <guimenu>Tools</guimenu>
+ <guimenuitem>Rough Translation...</guimenuitem>
+ </menuchoice>
+ </term>
+ <listitem>
+ <para>
+ <action>
+ Invoke rough-translation dialog for automated translation.
+ </action>
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>
+ <menuchoice>
+ <guimenu>Tools</guimenu>
+ <guimenuitem>Catalog Manager...</guimenuitem>
+ </menuchoice>
+ </term>
+ <listitem>
+ <para>
+ Open &catalogmanager;. Read
+ <link linkend="using-catalogmanager">&catalogmanager;</link> section
+ for more details.
+ </para>
+ </listitem>
+ </varlistentry>
+</variablelist>
+</sect2>
+
+<sect2>
+<title>The Settings Menu</title>
+<variablelist>
+ <varlistentry>
+ <term>
+ <menuchoice>
+ <guimenu>Settings</guimenu>
+ <guimenuitem>Show Toolbar</guimenuitem>
+ </menuchoice>
+ </term>
+ <listitem>
+ <para>
+ <action>
+ When checked, the standard toolbar is displayed.
+ </action>
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>
+ <menuchoice>
+ <guimenu>Settings</guimenu>
+ <guimenuitem>Show Statusbar</guimenuitem>
+ </menuchoice>
+ </term>
+ <listitem>
+ <para>
+ <action>
+ When checked, the bottom statusbar is displayed.
+ </action>
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>
+ <menuchoice>
+ <guimenu>Settings</guimenu>
+ <guimenuitem>Show Navigation Bar</guimenuitem>
+ </menuchoice>
+ </term>
+ <listitem>
+ <para>
+ <action>
+ When checked, the navigation bar is displayed.
+ </action>
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>
+ <menuchoice>
+ <guimenu>Settings</guimenu>
+ <guimenuitem>Show Comments</guimenuitem>
+ </menuchoice>
+ </term>
+ <listitem>
+ <para>
+ <action>
+ When checked, the upper-right part of main window,
+ which contains current entry's comments, will be displayed.
+ </action>
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>
+ <menuchoice>
+ <guimenu>Settings</guimenu>
+ <guimenuitem>Show Tools</guimenuitem>
+ </menuchoice>
+ </term>
+ <listitem>
+ <para>
+ <action>
+ When checked, the bottom-right part of main window,
+ which contain search results through the
+ dictionary, will be displayed.
+ </action>
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>
+ <menuchoice>
+ <guimenu>Settings</guimenu>
+ <guimenuitem>Configure Key Bindings...</guimenuitem>
+ </menuchoice>
+ </term>
+ <listitem>
+ <para>
+ <action>
+ Opens a configure dialog for binding keys to
+ actions. This will let you to customize the default
+ key bindings to suite your needs.
+ </action>
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>
+ <menuchoice>
+ <guimenu>Settings</guimenu>
+ <guimenuitem>Configure Toolbars...</guimenuitem>
+ </menuchoice>
+ </term>
+ <listitem>
+ <para>
+ <action>
+ Standard toolbar-configuration dialog will open. You can
+ choose which actions will go in which toolbars and what toolbar
+ to customize.
+ </action>
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>
+ <menuchoice>
+ <guimenu>Settings</guimenu>
+ <guimenuitem>Configure Kbabel...</guimenuitem>
+ </menuchoice>
+ </term>
+ <listitem>
+ <para>
+ All &kbabel;-specific settings go here.
+ Please read the <link linkend="preferences-global">&kbabel; Global Settings</link> section for specific topics.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>
+ <menuchoice>
+ <guimenu>Settings</guimenu>
+ <guimenuitem>Configure Dictionary</guimenuitem>
+ <guimenuitem>KDE Database Search Engine</guimenuitem>
+ </menuchoice>
+ </term>
+ <listitem>
+ <para>
+ Open dialog for &kde; Database Search Engine
+ configuration.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>
+ <menuchoice>
+ <guimenu>Settings</guimenu>
+ <guimenuitem>Configure Dictionary</guimenuitem>
+ <guimenuitem>PO Auxiliary</guimenuitem>
+ </menuchoice>
+ </term>
+ <listitem>
+ <para>
+ <action>
+ Open dialog</action> for <acronym>PO</acronym> auxiliary file
+ configuration.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>
+ <menuchoice>
+ <guimenu>Settings</guimenu>
+ <guimenuitem>Configure Dictionary</guimenuitem>
+ <guimenuitem>PO Compendium</guimenuitem>
+ </menuchoice>
+ </term>
+ <listitem>
+ <para>
+ <action>
+ Open dialog</action> for <acronym>PO</acronym> compendium file
+ configuration.
+ </para>
+ </listitem>
+ </varlistentry>
+</variablelist>
+</sect2>
+
+<sect2>
+<title>The Help Menu</title>
+
+<variablelist>
+ <varlistentry>
+ <term>
+ <menuchoice>
+ <shortcut>
+ <keycap>F1</keycap>
+ </shortcut>
+ <guimenu>Help</guimenu>
+ <guimenuitem>Contents</guimenuitem>
+ </menuchoice>
+ </term>
+ <listitem>
+ <para>
+ Open the &kbabel; handbook. It is what
+ you are reading now.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>
+ <menuchoice>
+ <shortcut>
+ <keycombo>
+ &Shift;<keycap>F1</keycap>
+ </keycombo>
+ </shortcut>
+ <guimenu>Help</guimenu>
+ <guimenuitem>What's This?</guimenuitem>
+ </menuchoice>
+ </term>
+ <listitem>
+ <para>
+ <action>
+ Cursor change to arrow with question mark and you can click with it
+ on various elements on main window. A quick help window will open.
+ </action>
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>
+ <menuchoice>
+ <guimenu>Help</guimenu>
+ <guimenuitem>Gettext Info</guimenuitem>
+ </menuchoice>
+ </term>
+ <listitem>
+ <para>
+ <action>
+ Open the gettext manual page</action> in the &kde; Help Center.
+ This package of tools helps the in process of handling
+ <acronym>POT</acronym> and <acronym>PO</acronym> files.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>
+ <menuchoice>
+ <guimenu>Help</guimenu>
+ <guimenuitem>Report Bug...</guimenuitem>
+ </menuchoice>
+ </term>
+ <listitem>
+ <para>
+ <action>
+ This will open a standard error-reporting dialog
+ </action> for &kde;
+ It is useful if
+ you experience abnormal behavior of &kbabel;.
+ &kbabel;'s developer will be glad to receive any comments, wishes, and
+ bug reports.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>
+ <menuchoice>
+ <guimenu>Help</guimenu>
+ <guimenuitem>About KBabel...</guimenuitem>
+ </menuchoice>
+ </term>
+ <listitem>
+ <para>
+ Open a message box which inform you about &kbabel;'s version, developer
+ name, and e-mail address.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>
+ <menuchoice>
+ <guimenu>Help</guimenu>
+ <guimenuitem>About KDE...</guimenuitem>
+ </menuchoice>
+ </term>
+ <listitem>
+ <para>
+ Open a message box which informs you about the &kde; project,
+ contact information, and how you can report bugs and
+ wishes.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>
+ <menuchoice>
+ <guimenu>Help</guimenu>
+ <guimenuitem>About Dictionary</guimenuitem>
+ <guimenuitem>KDE Database Search Engine</guimenuitem>
+ </menuchoice>
+ </term>
+ <listitem>
+ <para>
+ Display a message box with information
+ about the people who made the &kde; Database Search Engine.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>
+ <menuchoice>
+ <guimenu>Help</guimenu>
+ <guimenuitem>About Dictionary</guimenuitem>
+ <guimenuitem>PO Auxiliary</guimenuitem>
+ </menuchoice>
+ </term>
+ <listitem>
+ <para>
+ <action>
+ Display a message box with information
+ about the people who made searching in auxiliary file possible.
+ </action>
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>
+ <menuchoice>
+ <guimenu>Help</guimenu>
+ <guimenuitem>About Dictionary</guimenuitem>
+ <guimenuitem>PO Compendium</guimenuitem>
+ </menuchoice>
+ </term>
+ <listitem>
+ <para>
+ <action>
+ Display a message box with information
+ about people who made searching in compendium file possible.
+ </action>
+ </para>
+ </listitem>
+ </varlistentry>
+</variablelist>
+</sect2>
+</sect1>
+
+<sect1 id="kbabel-toolbars">
+<title>The &kbabel; toolbars</title>
+
+<sect2 id="standard-toolbar">
+<title>Standard Toolbar</title>
+<variablelist>
+ <varlistentry>
+ <term>
+ <inlinemediaobject>
+<imageobject>
+<imagedata fileref="fileopen.png" format="PNG"/>
+</imageobject>
+</inlinemediaobject> Open
+ </term>
+ <listitem>
+ <para>Load <acronym>PO</acronym> file in &kbabel; for editing.</para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>
+ <inlinemediaobject>
+<imageobject>
+<imagedata fileref="filesave.png" format="PNG"/>
+</imageobject>
+</inlinemediaobject> Save
+ </term>
+ <listitem>
+ <para>Save current <acronym>PO</acronym> file if it is modified.</para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>
+ <inlinemediaobject>
+<imageobject>
+<imagedata fileref="undo.png" format="PNG"/>
+</imageobject>
+</inlinemediaobject> Undo
+ </term>
+ <listitem>
+ <para>Undo last operation.</para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>
+ <inlinemediaobject>
+<imageobject>
+<imagedata fileref="redo.png" format="PNG"/>
+</imageobject>
+</inlinemediaobject> Redo
+ </term>
+ <listitem>
+ <para>Redo last operation.</para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>
+ <inlinemediaobject>
+<imageobject>
+<imagedata fileref="editcut.png" format="PNG"/>
+</imageobject>
+</inlinemediaobject> Cut
+ </term>
+ <listitem>
+ <para>Cut selected text and move it to the clipboard.</para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>
+ <inlinemediaobject>
+<imageobject>
+<imagedata fileref="editcopy.png" format="PNG"/>
+</imageobject>
+</inlinemediaobject> Copy
+ </term>
+ <listitem>
+ <para>Copy selected text to the clipboard.</para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>
+ <inlinemediaobject>
+<imageobject>
+<imagedata fileref="editpaste.png" format="PNG"/>
+</imageobject>
+</inlinemediaobject> Paste
+ </term>
+ <listitem>
+ <para>Paste text from clipboard at the current cursor position.</para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>
+ <inlinemediaobject>
+<imageobject>
+<imagedata fileref="find.png" format="PNG"/>
+</imageobject>
+</inlinemediaobject> Find
+ </term>
+ <listitem>
+ <para>Find specified string in current PO-file.</para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>
+ <inlinemediaobject>
+<imageobject>
+<imagedata fileref="previous.png" format="PNG"/>
+</imageobject>
+</inlinemediaobject> Previous
+ </term>
+ <listitem>
+ <para>Skip to previous entry in PO-file.</para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>
+ <inlinemediaobject>
+<imageobject>
+<imagedata fileref="next.png" format="PNG"/>
+</imageobject>
+</inlinemediaobject> Next
+ </term>
+ <listitem>
+ <para>Skip to next entry in <acronym>PO</acronym> file.</para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>
+ <inlinemediaobject>
+<imageobject>
+<imagedata fileref="msgid2msgstr.png" format="PNG"/>
+</imageobject>
+</inlinemediaobject> Copy <acronym>msgid</acronym> to <acronym>msgstr</acronym>
+ </term>
+ <listitem>
+ <para>Copy original string to translated string edit box.</para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>
+ <inlinemediaobject>
+<imageobject>
+<imagedata fileref="transsearch.png" format="PNG"/>
+</imageobject>
+</inlinemediaobject> Search Translations
+ </term>
+ <listitem>
+ <para>Drop-down toolbar for searching selected text using:
+ &kde; Database Search Engine, <acronym>PO</acronym> auxiliary file, <acronym>PO</acronym> compendium file,
+ and other dictionary plugins if available.</para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>
+ <inlinemediaobject>
+<imageobject>
+<imagedata fileref="stop.png" format="PNG"/>
+</imageobject>
+</inlinemediaobject> Stop
+ </term>
+ <listitem>
+ <para>Stop current search-in-progress.</para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>
+ <inlinemediaobject>
+<imageobject>
+<imagedata fileref="catalogmanager.png" format="PNG"/>
+</imageobject>
+</inlinemediaobject> Catalog Manager
+ </term>
+ <listitem>
+ <para>Open Catalog Manager window.</para>
+ </listitem>
+ </varlistentry>
+</variablelist>
+</sect2>
+
+<sect2 id="navigation-toolbar">
+<title>Navigation Toolbar</title>
+<variablelist>
+ <varlistentry>
+ <term>
+ <inlinemediaobject>
+<imageobject>
+<imagedata fileref="previous.png" format="PNG"/>
+</imageobject>
+</inlinemediaobject> Previous
+ </term>
+ <listitem>
+ <para>Skip to previous entry in <acronym>PO</acronym> file.</para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>
+ <inlinemediaobject>
+<imageobject>
+<imagedata fileref="next.png" format="PNG"/>
+</imageobject>
+</inlinemediaobject> Next
+ </term>
+ <listitem>
+ <para>Skip to next entry in <acronym>PO</acronym> file.</para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>
+ <inlinemediaobject>
+<imageobject>
+<imagedata fileref="top.png" format="PNG"/>
+</imageobject>
+</inlinemediaobject> First Entry
+ </term>
+ <listitem>
+ <para>Jump to first entry in <acronym>PO</acronym> file.</para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>
+ <inlinemediaobject>
+<imageobject>
+<imagedata fileref="bottom.png" format="PNG"/>
+</imageobject>
+</inlinemediaobject> Last Entry
+ </term>
+ <listitem>
+ <para>Jump to last entry in <acronym>PO</acronym> file.</para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>
+ <inlinemediaobject>
+<imageobject>
+<imagedata fileref="prevfuzzyuntrans.png" format="PNG"/>
+</imageobject>
+</inlinemediaobject> Previous fuzzy or untranslated
+ </term>
+ <listitem>
+ <para>Jump to previous fuzzy or untranslated entry in <acronym>PO</acronym> file.</para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>
+ <inlinemediaobject>
+<imageobject>
+<imagedata fileref="nextfuzzyuntrans.png" format="PNG"/>
+</imageobject>
+</inlinemediaobject> Next fuzzy or untranslated
+ </term>
+ <listitem>
+ <para>Jump to next fuzzy or untranslated entry in <acronym>PO</acronym> file.</para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>
+ <inlinemediaobject>
+<imageobject>
+<imagedata fileref="prevfuzzy.png" format="PNG"/>
+</imageobject>
+</inlinemediaobject> Previous fuzzy
+ </term>
+ <listitem>
+ <para>Jump to previous fuzzy entry in <acronym>PO</acronym> file.</para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>
+ <inlinemediaobject>
+<imageobject>
+<imagedata fileref="nextfuzzy.png" format="PNG"/>
+</imageobject>
+</inlinemediaobject> Next fuzzy
+ </term>
+ <listitem>
+ <para>Jump to next fuzzy entry in <acronym>PO</acronym> file.</para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>
+ <inlinemediaobject>
+<imageobject>
+<imagedata fileref="prevuntranslated.png" format="PNG"/>
+</imageobject>
+</inlinemediaobject> Previous untranslated
+ </term>
+ <listitem>
+ <para>Jump to previous untranslated entry in <acronym>PO</acronym> file.</para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>
+ <inlinemediaobject>
+<imageobject>
+<imagedata fileref="nextuntranslated.png" format="PNG"/>
+</imageobject>
+</inlinemediaobject> Next untranslated
+ </term>
+ <listitem>
+ <para>Jump to next untranslated entry in <acronym>PO</acronym> file.</para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>
+ <inlinemediaobject>
+<imageobject>
+<imagedata fileref="preverror.png" format="PNG"/>
+</imageobject>
+</inlinemediaobject> Previous error
+ </term>
+ <listitem>
+ <para>Jump to previous error in <acronym>PO</acronym> file.</para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>
+ <inlinemediaobject>
+<imageobject>
+<imagedata fileref="nexterror.png" format="PNG"/>
+</imageobject>
+</inlinemediaobject> Next error
+ </term>
+ <listitem>
+ <para>Jump to next error in <acronym>PO</acronym> file.</para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>
+ <inlinemediaobject>
+<imageobject>
+<imagedata fileref="back.png" format="PNG"/>
+</imageobject>
+</inlinemediaobject> Back
+ </term>
+ <listitem>
+ <para>Jump to last visited entry in <acronym>PO</acronym> file.</para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>
+ <inlinemediaobject>
+<imageobject>
+<imagedata fileref="forward.png" format="PNG"/>
+</imageobject>
+</inlinemediaobject> Forward
+ </term>
+ <listitem>
+ <para>Jump to previous visited entry in <acronym>PO</acronym> file.</para>
+ </listitem>
+ </varlistentry>
+</variablelist>
+</sect2>
+
+<sect2 id="status-bar">
+<title>Status Bar</title>
+<variablelist>
+ <varlistentry>
+ <term>Current</term>
+ <listitem>
+ <para>Current message in edited <acronym>PO</acronym> file.</para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>Total</term>
+ <listitem>
+ <para>Total number of messages in <acronym>PO</acronym> file.</para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>Fuzzy</term>
+ <listitem>
+ <para>Number of messages marked as fuzzy. They should be revised
+ and translated if needed.</para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>Untranslated</term>
+ <listitem>
+ <para>Number of yet untranslated messages.</para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>Editor status</term>
+ <listitem>
+ <para>INS - insert, and OVR - overwrite.
+ Same meaning like in every ordinary text editor.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>PO-file status</term>
+ <listitem>
+ <para>RO - read-only file, RW - read-write access on file.
+ When a file is read-only you cannot modify entries
+ in editor.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>Progress bar</term>
+ <listitem>
+ <para>
+ Usually, this bar is hidden; it is displayed
+ only when saving is being done, or if you are searching for messages
+ in a PO-file, compendium, or elsewhere.
+ </para>
+ </listitem>
+ </varlistentry>
+</variablelist>
+</sect2>
+
+</sect1>
+
+<sect1 id="catalogmanager-menu">
+<title>The &catalogmanager; menu</title>
+
+<sect2>
+<title>The File Menu</title>
+<variablelist>
+ <varlistentry>
+ <term>
+ <menuchoice>
+ <shortcut>
+ <keycombo action="simul">
+ &Ctrl;<keycap>Q</keycap>
+ </keycombo>
+ </shortcut>
+ <guimenu>File</guimenu>
+ <guimenuitem>Quit</guimenuitem>
+ </menuchoice>
+ </term>
+ <listitem>
+ <para>
+ <action>Quits &catalogmanager;</action>
+ </para>
+ </listitem>
+ </varlistentry>
+</variablelist>
+</sect2>
+
+<sect2>
+<title>The Edit Menu</title>
+<variablelist>
+ <varlistentry>
+ <term>
+ <menuchoice>
+ <shortcut>
+ <keycombo action="simul">
+ &Ctrl;<keycap>F</keycap>
+ </keycombo>
+ </shortcut>
+ <guimenu>Edit</guimenu>
+ <guimenuitem>Find in Files...</guimenuitem>
+ </menuchoice>
+ </term>
+ <listitem>
+ <para>
+ <action>
+ Open Find dialog for searching for strings in a set of PO files.
+ </action>
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>
+ <menuchoice>
+ <shortcut>
+ <keycombo action="simul">
+ &Ctrl;<keycap>R</keycap>
+ </keycombo>
+ </shortcut>
+ <guimenu>Edit</guimenu>
+ <guimenuitem>Replace in Files...</guimenuitem>
+ </menuchoice>
+ </term>
+ <listitem>
+ <para>
+ <action>
+ Open Replace dialog for searching for and replacing strings in a set of PO files.
+ </action>
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>
+ <menuchoice>
+ <shortcut>
+ <keycombo>
+ <keycap>Escape</keycap>
+ </keycombo>
+ </shortcut>
+ <guimenu>Edit</guimenu>
+ <guimenuitem>Stop Searching</guimenuitem>
+ </menuchoice>
+ </term>
+ <listitem>
+ <para>
+ <action>
+ Stop currently running find/replace operation.
+ </action>
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>
+ <menuchoice>
+ <shortcut>
+ <keycombo action="simul">
+ &Ctrl;<keycap>M</keycap>
+ </keycombo>
+ </shortcut>
+ <guimenu>Edit</guimenu>
+ <guimenuitem>Toggle Marking</guimenuitem>
+ </menuchoice>
+ </term>
+ <listitem>
+ <para>
+ <action>
+ Toggle mark for the selected file.
+ </action>
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>
+ <menuchoice>
+ <guimenu>Edit</guimenu>
+ <guimenuitem>Remove Marking</guimenuitem>
+ </menuchoice>
+ </term>
+ <listitem>
+ <para>
+ <action>
+ Removes mark for the selected file or folder.
+ </action>
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>
+ <menuchoice>
+ <guimenu>Edit</guimenu>
+ <guimenuitem>Toggle All Markings</guimenuitem>
+ </menuchoice>
+ </term>
+ <listitem>
+ <para>
+ <action>
+ Toggles marks for the selected file or folder (recursively).
+ </action>
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>
+ <menuchoice>
+ <guimenu>Edit</guimenu>
+ <guimenuitem>Remove All Markings</guimenuitem>
+ </menuchoice>
+ </term>
+ <listitem>
+ <para>
+ <action>
+ Remove marks for the selected file or folder (recursively).
+ </action>
+ </para>
+ </listitem>
+ </varlistentry>
+</variablelist>
+</sect2>
+
+<sect2>
+<title>The Tools Menu</title>
+<variablelist>
+ <varlistentry>
+ <term>
+ <menuchoice>
+ <shortcut>
+ <keycombo action="simul">
+ &Ctrl;<keycap>S</keycap>
+ </keycombo>
+ </shortcut>
+ <guimenu>Tools</guimenu>
+ <guimenuitem>Statistics</guimenuitem>
+ </menuchoice>
+ </term>
+ <listitem>
+ <para>
+ <action>
+ Show statistics about number of translated/untranslated/fuzzy messages
+ for the selected file or subtree.
+ </action>
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>
+ <menuchoice>
+ <shortcut>
+ <keycombo action="simul">
+ &Ctrl;<keycap>Y</keycap>
+ </keycombo>
+ </shortcut>
+ <guimenu>Tools</guimenu>
+ <guimenuitem>Check Syntax</guimenuitem>
+ </menuchoice>
+ </term>
+ <listitem>
+ <para>
+ <action>
+ Check syntax for the selected file or subtree using msgfmt.
+ </action>
+ </para>
+ </listitem>
+ </varlistentry>
+</variablelist>
+</sect2>
+
+<sect2>
+<title>The Settings Menu</title>
+<variablelist>
+ <varlistentry>
+ <term>
+ <menuchoice>
+ <guimenu>Settings</guimenu>
+ <guimenuitem>Show Toolbar</guimenuitem>
+ </menuchoice>
+ </term>
+ <listitem>
+ <para>
+ <action>
+ When checked, standard toolbar is displayed.
+ </action>
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>
+ <menuchoice>
+ <guimenu>Settings</guimenu>
+ <guimenuitem>Show Statusbar</guimenuitem>
+ </menuchoice>
+ </term>
+ <listitem>
+ <para>
+ <action>
+ When checked, bottom statusbar is displayed.
+ </action>
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>
+ <menuchoice>
+ <guimenu>Settings</guimenu>
+ <guimenuitem>Configure Key Bindings...</guimenuitem>
+ </menuchoice>
+ </term>
+ <listitem>
+ <para>
+ <action>
+ Opens a configure dialog for binding keys to
+ actions. This will let you to customize the default
+ key bindings to suite your needs.
+ </action>
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>
+ <menuchoice>
+ <guimenu>Settings</guimenu>
+ <guimenuitem>Configure Toolbars...</guimenuitem>
+ </menuchoice>
+ </term>
+ <listitem>
+ <para>
+ <action>
+ Standard toolbar-configuration dialog will open. You can
+ choose which actions will go in which toolbars and what toolbar
+ to customize.
+ </action>
+ </para>
+ </listitem>
+ </varlistentry>
+</variablelist>
+</sect2>
+
+<sect2>
+<title>The Help Menu</title>
+&help.menu.documentation;
+</sect2>
+
+</sect1></chapter>
+<!--
+Local Variables:
+mode: xml
+sgml-minimize-attributes:nil
+sgml-general-insert-case:lower
+sgml-indent-step:0
+sgml-indent-data:nil
+End:
+
+vim:tabstop=2:shiftwidth=2:expandtab
+-->
+
diff --git a/doc/kbabel/msgid2msgstr.png b/doc/kbabel/msgid2msgstr.png
new file mode 100644
index 00000000..938ea3ce
--- /dev/null
+++ b/doc/kbabel/msgid2msgstr.png
Binary files differ
diff --git a/doc/kbabel/next.png b/doc/kbabel/next.png
new file mode 100644
index 00000000..f0b977bf
--- /dev/null
+++ b/doc/kbabel/next.png
Binary files differ
diff --git a/doc/kbabel/nexterror.png b/doc/kbabel/nexterror.png
new file mode 100644
index 00000000..1009eae0
--- /dev/null
+++ b/doc/kbabel/nexterror.png
Binary files differ
diff --git a/doc/kbabel/nextfuzzy.png b/doc/kbabel/nextfuzzy.png
new file mode 100644
index 00000000..5912e52d
--- /dev/null
+++ b/doc/kbabel/nextfuzzy.png
Binary files differ
diff --git a/doc/kbabel/nextfuzzyuntrans.png b/doc/kbabel/nextfuzzyuntrans.png
new file mode 100644
index 00000000..fd373e2f
--- /dev/null
+++ b/doc/kbabel/nextfuzzyuntrans.png
Binary files differ
diff --git a/doc/kbabel/nextuntranslated.png b/doc/kbabel/nextuntranslated.png
new file mode 100644
index 00000000..3b4f8202
--- /dev/null
+++ b/doc/kbabel/nextuntranslated.png
Binary files differ
diff --git a/doc/kbabel/pref_diff.png b/doc/kbabel/pref_diff.png
new file mode 100644
index 00000000..014ea5ef
--- /dev/null
+++ b/doc/kbabel/pref_diff.png
Binary files differ
diff --git a/doc/kbabel/pref_edit_appearance.png b/doc/kbabel/pref_edit_appearance.png
new file mode 100644
index 00000000..1306704e
--- /dev/null
+++ b/doc/kbabel/pref_edit_appearance.png
Binary files differ
diff --git a/doc/kbabel/pref_edit_general.png b/doc/kbabel/pref_edit_general.png
new file mode 100644
index 00000000..d1542289
--- /dev/null
+++ b/doc/kbabel/pref_edit_general.png
Binary files differ
diff --git a/doc/kbabel/pref_fonts.png b/doc/kbabel/pref_fonts.png
new file mode 100644
index 00000000..b92e1b7a
--- /dev/null
+++ b/doc/kbabel/pref_fonts.png
Binary files differ
diff --git a/doc/kbabel/pref_proj_catman.png b/doc/kbabel/pref_proj_catman.png
new file mode 100644
index 00000000..1e30bb25
--- /dev/null
+++ b/doc/kbabel/pref_proj_catman.png
Binary files differ
diff --git a/doc/kbabel/pref_proj_diff.png b/doc/kbabel/pref_proj_diff.png
new file mode 100644
index 00000000..27cb370e
--- /dev/null
+++ b/doc/kbabel/pref_proj_diff.png
Binary files differ
diff --git a/doc/kbabel/pref_proj_file_commands.png b/doc/kbabel/pref_proj_file_commands.png
new file mode 100644
index 00000000..fe83050f
--- /dev/null
+++ b/doc/kbabel/pref_proj_file_commands.png
Binary files differ
diff --git a/doc/kbabel/pref_proj_folder_commands.png b/doc/kbabel/pref_proj_folder_commands.png
new file mode 100644
index 00000000..cf0f742f
--- /dev/null
+++ b/doc/kbabel/pref_proj_folder_commands.png
Binary files differ
diff --git a/doc/kbabel/pref_proj_source.png b/doc/kbabel/pref_proj_source.png
new file mode 100644
index 00000000..278e2ebd
--- /dev/null
+++ b/doc/kbabel/pref_proj_source.png
Binary files differ
diff --git a/doc/kbabel/pref_search.png b/doc/kbabel/pref_search.png
new file mode 100644
index 00000000..cdb5c6d1
--- /dev/null
+++ b/doc/kbabel/pref_search.png
Binary files differ
diff --git a/doc/kbabel/pref_wizard_page1.png b/doc/kbabel/pref_wizard_page1.png
new file mode 100644
index 00000000..b88b954d
--- /dev/null
+++ b/doc/kbabel/pref_wizard_page1.png
Binary files differ
diff --git a/doc/kbabel/pref_wizard_page2.png b/doc/kbabel/pref_wizard_page2.png
new file mode 100644
index 00000000..e561cff2
--- /dev/null
+++ b/doc/kbabel/pref_wizard_page2.png
Binary files differ
diff --git a/doc/kbabel/preferences.docbook b/doc/kbabel/preferences.docbook
new file mode 100644
index 00000000..fbaeee10
--- /dev/null
+++ b/doc/kbabel/preferences.docbook
@@ -0,0 +1,1418 @@
+<!-- <?xml version="1.0" ?>
+<!DOCTYPE chapter PUBLIC "-//KDE//DTD DocBook XML V4.2-Based Variant V1.1//EN" "dtd/kdex.dtd"> -->
+<!-- Uncomment the previous two lines to validate this document -->
+<!-- standalone. Be sure to recomment them before attempting to -->
+<!-- process index.docbook -->
+
+
+<chapter id="preferences">
+<chapterinfo>
+<!-- Fill in this section if this document has a different author -->
+<authorgroup>
+<author>
+<personname><firstname></firstname><surname></surname></personname>
+</author>
+</authorgroup>
+
+<!-- TRANS:ROLES_OF_TRANSLATORS -->
+</chapterinfo>
+
+<title>Preferences</title>
+
+
+<sect1 id="preferences-overview">
+<title>Global and project settings</title>
+
+<para>
+From KBabel 1.10 (KDE 3.4) on, KBabel has the concept of projects and therefore
+the settings have been split in two categories:
+the global settings and the project settings (also called project configuration).
+</para>
+
+<important><para>
+&GNU; gettext uses a term called "project", which has nothing to do with
+KBabel's projects. &GNU; gettext means by project an application which is
+related to the <acronym>PO</acronym> file. For KBabel, a project is
+much bigger. It can mean a set of applications, like &kde;.
+</para></important>
+
+<para>
+KBabel has <emphasis>always</emphasis> a current project, even if it is the
+default project. KBabel has not mode without any project. A project is always
+for KBabel's editor and KBabel's catalog manager.
+</para>
+
+
+<sect2 id="preferences-limitations">
+<title>Known limitations of the current implementation</title>
+
+<para>
+Unfortunately the current implementation of projects has a few known problems.
+</para>
+
+<para>
+An example is that in the global settings, there is no setting for the default user,
+his/her default language and other similar important global user data. It means that such
+data must be entered again each time that a new project is created.
+</para>
+
+<para>
+Another problem is the new project wizard. It does not ask enough information, especially
+it fails to ask for the team email address. So it is recommended to check the project
+settings after having run the wizard.
+</para>
+
+<tip><para>
+Currently you cannot copy projects from inside KBabel, so apparently you cannot easily share good settings.
+However you are free to copy the project outside KBabel and to load the copied project into KBabel.
+</para></tip>
+
+</sect2>
+
+<sect2 id="preferences-non-kde-projects">
+<title>Using KBabel for non-&kde; projects</title>
+
+<para>
+While &kbabel;'s defaults are oriented toward working with and for &kde;, &kbabel; can be used
+to translate <acronym>PO</acronym> files of other projects. However mostly you will have to tweak the
+settings to the need of your project. This is especially true for &GNU; and
+&GNU;-like projects, which need quite different defaults than for &kde;.
+</para>
+
+<para>
+One problem is that &kbabel; is relatively agressive when saving <acronym>PO</acronym> files and
+replaces setting of the <acronym>PO</acronym> files by settings of the projects, if not told otherwise.
+This might look very strange to somebody not used to &kde;. However &kde; has 900+
+<acronym>POT</acronym> files to translate for the <acronym>GUI</acronym> messages only.
+So for such a task, much automatisation is wanted. Taking time to set a project
+is little compared to the time gained thereafter. Of course, as non-&kde; user, you
+might be less fortunate. You need to do more settings, as the defaults are not entirely suitable
+and you will not gain much by doing many translations, as &GNU; projects have typically
+only one <acronym>POT</acronym> file to translate.
+</para>
+
+</sect2>
+
+</sect1>
+
+<sect1 id="preferences-global">
+<title>&kbabel; global settings</title>
+
+<para>
+To show the Preferences dialog choose
+<menuchoice><guimenu>Settings</guimenu> <guimenuitem>Configure
+KBabel...</guimenuitem></menuchoice> from &kbabel;'s menu. It uses a
+structured configuration dialog which makes it very easy to find an
+option without having to perform an extensive search for it.
+</para>
+
+<sect2 id="preferences-editor">
+<title>Edit</title>
+<para>
+The editor preferences category is divided in 3 subwindows:
+<guilabel>General</guilabel>, <guilabel>Appearance</guilabel>,
+<guilabel>Spell Check</guilabel> and <guilabel>Fonts</guilabel>.
+All these settings customize how the editor behaves and looks.
+</para>
+
+<sect3 id="preferences-editor-general">
+<title>General</title>
+
+<screenshot>
+<screeninfo>Dialog Edit General</screeninfo>
+<mediaobject>
+<imageobject>
+<imagedata fileref="pref_edit_general.png" format="PNG"/>
+</imageobject>
+<textobject><phrase>Dialog Edit General</phrase></textobject>
+</mediaobject>
+</screenshot>
+
+<para>This section contains a set of checkboxes.</para>
+
+<para>The first checkbox in the upper side sets if the fuzzy status is
+reset automatically when a character is inputted into the MsgStr
+editor. When this option is disabled you have to manually choose
+<menuchoice><guimenu>Edit</guimenu><guimenuitem>Unset Fuzzy Status
+</guimenuitem></menuchoice> or use the <keycombo
+action="simul">&Ctrl;<keycap>U</keycap></keycombo> shortcut. Note
+that this means the string <literal>, fuzzy</literal> is removed from
+the entry's comment.</para>
+
+<para>Next option allows you to enable <quote>clever</quote> editing,
+where editor automatically inserts special characters escaped
+correctly, &eg; <literal>\t</literal> after pressing
+<keycap>Tab</keycap> and it allows special handling of
+<keycap>Enter</keycap>.</para>
+
+<para>
+The lower checkboxes are very useful in assisting, not for the
+correctness of the translation, but if the translated string
+is a suitable replacement for the original. For
+example, many messages represent menu items with keyboard accelerator
+and C-like formatted strings whose structure must remain intact once
+translated.
+</para>
+
+<variablelist>
+ <varlistentry>
+ <term><guilabel>Check Arguments</guilabel></term>
+ <listitem>
+ <para>
+ When this option is selected, C-format strings in the original and
+ the translation are checked to ensure the number of
+ format sequences and the order are consistent.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><guilabel>Check Accelerator</guilabel></term>
+ <listitem>
+<para>When this option is selected, &kbabel; checks if the number
+accelerator characters is identical in both the original and the
+translated string. Note that accelerator marker is &amp; (but not in
+every programming toolkit). See the <link
+linkend="preferences-project-miscellaneous">Miscellaneous</link> section below
+to find how to change a keyboard accelerator.</para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><guilabel>Check Equation</guilabel></term>
+ <listitem>
+ <para>
+ This is a feature for the &kde; project development.
+ <filename>.desktop</filename> files are simply
+ text files which store various parameters in
+ <literal>value=key</literal> format. Some of
+ these <literal>key</literal>s are translatable.
+ The only restriction is to maintain the left
+ side of equality unchanged. Equation check
+ allows you to spot many errors determined
+ by the fuzzy <command>msgmerge</command> algorithm.
+ Note that there are situations where this function
+ generates false errors on some PO-files.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><guilabel>Look for Translated Context Info</guilabel></term>
+ <listitem>
+<para> Some original messages are marked with context information to
+mark them as being unique even if they represent same word. This is
+because many simple words, such as <quote>Save</quote>, are translated
+into many languages. Context information is marked with
+<literal>_:</literal>. Many unexperienced translators translate the
+context information and fill their PO files with garbage. Check this
+box to make sure you will be warned about these errors in a
+file.</para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><guilabel>Check Plural Forms</guilabel></term>
+ <listitem>
+ <para>
+ If you are translating &kde; project, it uses a special kind of
+ syntax for specifying plural forms of messages. This check automatically
+ counts the number of forms in <acronym>msgstr</acronym> and
+ compares it with the number specified in
+<link linkend="preferences-project-identity"><guilabel>Identity</guilabel></link>
+tab. Incorrect number of plural forms can result in crash of an application.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><guilabel>Beep on error</guilabel></term>
+ <listitem>
+ <para>
+ Your system bell will beep when you switch
+ on entries with errors like those described above.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><guilabel>Change text color on error</guilabel></term>
+ <listitem>
+ <para>
+ This is another type of warning about
+ errors in current message. It is a good solution for those who are
+ hearing impaired or dislike bell noise. See also the
+ <link linkend="preferences-editor-appearance">Appearance</link> tab
+ to find out how to change the text color on errors.
+ </para>
+ </listitem>
+ </varlistentry>
+</variablelist>
+
+</sect3>
+
+<sect3 id="preferences-editor-appearance">
+<title>Appearance</title>
+
+<screenshot>
+<screeninfo>Dialog Edit Appearance</screeninfo>
+<mediaobject>
+<imageobject>
+<imagedata fileref="pref_edit_appearance.png" format="PNG"/>
+</imageobject>
+<textobject><phrase>Dialog Edit Appearance</phrase></textobject>
+</mediaobject>
+</screenshot>
+
+<para>
+These options let
+you configure the appearance for the message editor. In upper part there
+are 4 checkboxes:
+</para>
+
+<variablelist>
+ <varlistentry>
+ <term><guibutton>Highlight syntax</guibutton></term>
+ <listitem><para>
+ Setting this option will enable syntax highlighting for
+ special characters, accelerators and text background in the msgid viewer
+ and msgstr editor. If don't have a monochrome display or have a visual impairment, you should enable this option.
+</para></listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><guibutton>Highlight background</guibutton></term>
+ <listitem><para>
+ The background will be highlighted only for existing characters in
+ the msgid and msgstr. This includes spaces. This is useful if you
+ don't want to see the surrounding quotes (see below) for the <acronym>PO</acronym> entry, and you will still
+ be able to observe starting and ending spaces in a text line.
+ </para></listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><guibutton>Mark whitespaces with points</guibutton></term>
+ <listitem><para>
+ When you feel the need to count spaces
+ and background highlighting is not your taste then you can
+ check this option to have a point sign drawn in the middle of
+ whitespace characters. Note that the point is a point sign in the
+ center of a character box and is not a decimal point.
+ </para></listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><guibutton>Show surrounding quotes</guibutton></term>
+ <listitem><para>
+ If you think that viewing the terminal characters in msgstr or
+ msgid's text line is better for you then check this option to view
+ the surrounding quotes for every text line.</para>
+ <para>If you are experienced editing <acronym>PO</acronym> files with
+ ordinary text editors you may feel safer if you can track starting and
+ ending double quotes in <acronym>PO</acronym> entry lines.
+ </para></listitem>
+ </varlistentry>
+</variablelist>
+
+<para>
+For the different items in edited text there are different color choices
+to make editing easy. Colors can be changed by clicking on color-picker
+buttons. From the 'select color' dialogs you can choose from standard
+colors, custom colors or just pick a color from any part of your screen.
+</para>
+
+<variablelist>
+ <varlistentry>
+ <term><guilabel>Background color</guilabel></term>
+ <listitem><para>
+ This sets the background color for characters in the MsgID view
+ and the MsgStr editor. To change the general background color
+ of edit boxes you must use the &kcontrolcenter;.
+ </para></listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><guilabel>Color for quoted characters</guilabel></term>
+ <listitem><para>
+ Here you can adjust the color for escaped characters like
+ (<literal>\&quot;</literal>) double quotes or (<literal>\n</literal>) newline. </para></listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><guilabel>Color for syntax errors</guilabel></term>
+ <listitem><para>
+ This is the color for the entire text entry if errors are
+ detected when you try to save <acronym>PO</acronym> file. Errors are
+ triggered by not terminating identically both <acronym>msgid</acronym> and <acronym>msgstr</acronym>, or
+ escaping characters incorrectly.
+ </para></listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><guilabel>Color for c-format characters</guilabel></term>
+ <listitem><para>
+ This sets the color for a characters sequence like in
+ C language <function>printf</function> or <function>scanf</function> functions. In general these start with (<literal>&percnt;</literal>) percent char and are continued by one char.
+ </para></listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><guilabel>Color for keyboard accelerators</guilabel></term>
+ <listitem><para>
+ Keyboard accelerators start with (&amp;) <quote>ampersand</quote>
+ character in &kde; but if you are translating for other projects there might be an different character marking the accelerator key.
+See <link linkend="preferences-project-miscellaneous">Miscellaneous</link>
+section below to find how to change keyboard accelerator.
+ </para></listitem>
+ </varlistentry>
+</variablelist>
+
+<para> The status for the current edited entry is marked by three
+<acronym>LED</acronym>s. For your convenience you can choose where to
+put these <acronym>LED</acronym>s&mdash;either on the statusbar or in
+the editor section (between the msgid and msgstr entry). If have
+difficulties viewing some colors or you want to be able to track
+<acronym>LED</acronym> status changes easily without moving your eye
+you can select the preferred color using the color button chooser.
+</para>
+
+</sect3>
+
+</sect2>
+
+<sect2 id="preferences-search">
+<title>Search</title>
+
+<screenshot>
+<screeninfo>Dialog Search</screeninfo>
+<mediaobject>
+<imageobject>
+<imagedata fileref="pref_search.png" format="PNG"/>
+</imageobject>
+<textobject><phrase>Dialog Search</phrase></textobject>
+</mediaobject>
+</screenshot>
+
+<para>
+The search section allows you to customize various settings
+for searching in previously translated strings.
+</para>
+
+<para>General settings are common for all search types. If you check
+the <guibutton>Automatically start search</guibutton> option then the
+search is automatically started whenever you switch to another entry
+in the editor. Currently, there are three possibilities you can choose
+from, but since &kbabel; can use dictionary plugins the available
+dictionaries depend on those installed. Using
+<menuchoice><guimenuitem>Settings</guimenuitem> <guimenuitem>Configure
+Dictionary</guimenuitem> <guimenuitem>...</guimenuitem></menuchoice>
+you can configure every search plugin.</para>
+
+<para>The dictionary plugins installed by default are:</para>
+
+<variablelist>
+<varlistentry>
+<term>&kde; Database Search Engine</term>
+<listitem>
+<para>This new method is still in alpha stage of development
+ and is based on &kbabeldict; which accompanies &kbabel;.
+ See &kbabeldict; documentation for further info on
+ configuring the search engine.
+ </para></listitem>
+</varlistentry>
+
+<varlistentry>
+<term>PO Compendium</term>
+<listitem><para>The compendium is a normal <acronym>PO</acronym> file,
+ which should contain a list of standard translations from your translation
+ team. If you don't have one, you can also use a file that contains all
+ the translations from your team (&eg; the <filename>$lang.messages</filename>
+ file in the &kde; Project, that can be found at
+ <ulink url="http://i18n.kde.org/po_overview/">i18n.kde.org</ulink>).
+ </para></listitem>
+</varlistentry>
+
+<varlistentry>
+<term>PO Auxiliary</term>
+<listitem><para>The auxiliary should help you find the
+ context of a translation by looking up the same message in a message
+ catalog of the same package but translated to another language. This way
+ you can have a look how this message is translated in another language.
+ </para></listitem>
+</varlistentry>
+</variablelist>
+
+<para>
+You can also start searching manually by choosing an
+entry in the popup menu that appears, either by clicking
+<menuchoice>
+<guimenu>Dictionaries</guimenu><guimenuitem>Search Text</guimenuitem>
+<guimenuitem>PO Compendium</guimenuitem></menuchoice>
+or by keeping the search button on the toolbar pressed down for a while.
+</para>
+
+</sect2>
+
+<sect2 id="preferences-diffmode">
+<title>Diff</title>
+
+<screenshot>
+<screeninfo>Dialog Diff</screeninfo>
+<mediaobject>
+<imageobject>
+<imagedata fileref="pref_diff.png" format="PNG"/>
+</imageobject>
+<textobject><phrase>Dialog Diff</phrase></textobject>
+</mediaobject>
+</screenshot>
+
+<para>The <guilabel>Diff</guilabel> section holds settings how to
+display differences in msgids. </para>
+
+<para>Every difference can be displayed by two added parts and by characters removed from the text. For both you can specify the method of display and the color to be used. <guilabel>Highlighted</guilabel> means that the background of the corresponding characters will be shown in the selected color, while
+<guilabel>Underlined</guilabel>(for added characters) or <guilabel>Stroked Out</guilabel>
+(for removed characters) will denote the changed parts by colored lines.
+</para>
+<para>
+Diff mode needs to find the original <acronym>msgid</acronym> to compare
+with. For this purpose, &kbabel; can use the <link linkend="database">translation database</link>
+if you turn in on by enabling <guilabel>Use messages from Translation Database</guilabel>.
+A second possibility is to use a tree of original PO files and specifying the root of
+the tree in <guilabel>Base folder for diff files</guilabel>.
+</para>
+</sect2>
+
+<sect2 id="preferences-fonts">
+<title>Fonts</title>
+
+<screenshot>
+<screeninfo>Dialog Fonts</screeninfo>
+<mediaobject>
+<imageobject>
+<imagedata fileref="pref_fonts.png" format="PNG"/>
+</imageobject>
+<textobject><phrase>Dialog Fonts</phrase></textobject>
+</mediaobject>
+</screenshot>
+
+<para>
+This is a standard &kde; font chooser dialog with a little addition. You can
+select to view only fixed fonts by checking the
+<guibutton>Show only fixed fonts</guibutton> option.
+This is highly recommended for easy translating. The font dialog lets you set
+font family, style, size and encoding. The bottom box shows a preview of the
+current font for user convenience.
+</para>
+</sect2>
+
+</sect1>
+
+<sect1 id="preferences-project-wizard">
+<title>New Project Wizard</title>
+
+<sect2 id="preferences-project-wizard-basic">
+<title>Page 1</title>
+
+<screenshot>
+<screeninfo>Project Wizard Page 1</screeninfo>
+<mediaobject>
+<imageobject>
+<imagedata fileref="pref_wizard_page1.png" format="PNG"/>
+</imageobject>
+<textobject><phrase>Project Wizard Page 1</phrase></textobject>
+</mediaobject>
+</screenshot>
+
+<para>
+The first page of the wizard ask about the basic data of the project.
+</para>
+
+<variablelist>
+<varlistentry>
+<term><guilabel>Project name</guilabel></term>
+<listitem><para>
+Enter here the name of the project, as it will be displayed in &kbabel;'s menu.
+</para></listitem>
+</varlistentry>
+<varlistentry>
+<term><guilabel>Configuration file name</guilabel></term>
+<listitem><para>
+Select here a file for holding your project settings.
+</para></listitem>
+</varlistentry>
+<varlistentry>
+<term><guilabel>Language</guilabel></term>
+<listitem><para>
+Select or enter here the language name used by this project.
+</para></listitem>
+</varlistentry>
+<varlistentry>
+<term><guilabel>Project type</guilabel></term>
+<listitem><para>
+Select here the type of your project.
+</para></listitem>
+</varlistentry>
+</variablelist>
+
+</sect2>
+
+<sect2 id="preferences-project-wizard-catman">
+<title>Page 2</title>
+
+<screenshot>
+<screeninfo>Project Wizard Page 2</screeninfo>
+<mediaobject>
+<imageobject>
+<imagedata fileref="pref_wizard_page2.png" format="PNG"/>
+</imageobject>
+<textobject><phrase>Project Wizard Page 2</phrase></textobject>
+</mediaobject>
+</screenshot>
+
+<para>
+The second page of the wizard asks about settings related to the
+Catalog Manager.
+</para>
+
+<variablelist>
+<varlistentry>
+<term><guilabel>Base folder for PO files</guilabel></term>
+<listitem><para>
+Select the base folder where your PO files are.
+</para></listitem>
+</varlistentry>
+<varlistentry>
+<term><guilabel>Base folder for POT files</guilabel></term>
+<listitem><para>
+Select the base folder where your POT files are.
+</para></listitem>
+</varlistentry>
+</variablelist>
+
+<para>
+Type in or select the folders that contains all your <acronym>PO</acronym> and respectively
+<acronym>POT</acronym> files. The files and the folders in these folders will then be
+merged into one tree in &catalogmanager; window.
+</para>
+
+
+</sect2>
+
+<sect2>
+<title>Checking Project Stettings</title>
+
+<important><para>
+As written earlier in this chapter, unfortunately the wizard is very simple and
+therefore fails to ask for some important settings.
+</para></important>
+
+<para>
+Now that you have <quote>finished</quote> your new project, you should verify the main settings in
+<menuchoice><guimenu>Project</guimenu> <guimenuitem>Configure...</guimenuitem></menuchoice>.
+Especially select the <guilabel>Identity</guilabel> page and fix the team email address in
+<guilabel>Language mailing list</guilabel>.
+(The default one created by the wizard from the language setting is only useful if you are part of a &GNU; project.)
+</para>
+
+<para>
+If the project settings are not for KDE, it is recommended that you check the
+<guilabel>Save</guilabel> page and checks the settings there.
+</para>
+
+</sect2>
+
+</sect1>
+
+<sect1 id="preferences-project-settings">
+<title>Project Settings</title>
+
+<para> To show the project setting dialog choose
+<menuchoice><guimenu>Project</guimenu> <guimenuitem>Configure...</guimenuitem></menuchoice>
+from &kbabel;'s or &catalogmanager;'s menu. It uses a
+structured configuration dialog which makes it very easy to find an
+option without having to perform an extensive search for it.</para>
+
+<para>The left side of the preferences dialog lists the categories of
+customizable items and the right side shows the corresponding tab for
+the selected category. &kbabel; keeps changes if you move between
+categories, so when you're finally happy click the
+<guibutton>OK</guibutton> button. At any time you can use quick
+help&mdash;just click on the question mark on the title bar and,
+after the cursor has changed to an arrow with a question mark,
+click on a button, label, or preference entry to find out more
+about it.</para>
+
+<note><para>
+Pages for settings for &kbabel; (the editor) and for &catalogmanager;
+are in the list.
+</para></note>
+
+<sect2 id="preferences-project-identity">
+<title>Identity</title>
+
+<para>These settings are for &kbabel;.</para>
+
+<para>This section allows you to set standard fields for every
+translated <acronym>PO</acronym> file. These are your name, email
+address, full language name, email address for your translation team
+mailing list. There is also a timezone field to track your
+<quote>last modified</quote> time for <acronym>PO</acronym> files.
+You can specify it as character sequence like <acronym>EEST</acronym>
+or offset from <acronym>GMT</acronym> time like +0200 (&ie; for
+Romania). This information is used when updating file headers. You
+can find the options that control what fields in the header should be
+updated in the <link linkend="preferences-project-save">Save</link> section of
+the Preferences dialog.</para>
+
+<warning><para>Character sequences for timezones are not standardized.
+So you should not use the string set here in time specification for
+saving in <link linkend="preferences-project-save">Save</link> tab. You should
+use <literal>%z</literal> instead.</para></warning>
+
+<variablelist>
+<varlistentry>
+<term><guilabel>Number of singular/plural forms</guilabel></term>
+<listitem>
+<para> Use this for setting number of plural forms for your
+language. For example, it is 2 for German (one for the singular and
+one for the plural form).</para>
+
+<note><para>This feature is currently implemented only for plural forms format used in &kde;. It does not work with &GNU; gettext plural forms.</para></note>
+</listitem>
+</varlistentry>
+</variablelist>
+
+</sect2>
+
+<sect2 id="preferences-project-save">
+<title>Save</title>
+
+<para>These settings are for &kbabel;.</para>
+
+<para><remark>
+TODO This seems to document only the "General" tab but not the "Header" and "Copyright" ones
+</remark></para>
+
+<para>
+This section allows you to edit the options for <acronym>PO</acronym> file saving. The first
+group of checkboxes controls general behavior for actions
+performed in <acronym>PO</acronym> file saving.
+</para>
+
+<variablelist>
+ <varlistentry>
+ <term><guibutton>Update header when saving</guibutton></term>
+ <listitem><para>
+Check this button, to update the header information of the file
+every time it is saved. The header normally keeps information
+about the date and time the file was last updated,the last translator
+etc. You can choose which information you want to update from the
+<guilabel>Fields to update</guilabel> checkboxes area below. Fields
+that do not exist are added to the header. If you want to add
+additional fields to the header you can edit the header manually by
+choosing <menuchoice><guimenu>Edit</guimenu> <guimenuitem>Edit
+Header</guimenuitem></menuchoice> in the editor window.
+ </para></listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><guibutton>Check syntax of file when saving</guibutton></term>
+ <listitem><para>
+Check this to automatically check syntax of file with
+<userinput><command>msgfmt</command> --statistics</userinput> when
+saving a file. You will only get a message if an error occurred. You
+should keep this validation enabled unless you know what you are doing.
+ </para></listitem>
+ </varlistentry>
+</variablelist>
+
+<para>If you do not want to touch some fields in a <acronym>PO</acronym>
+file header or want to force updating of specific fields, there are five
+checkboxes which control this: revision date, <acronym>PO</acronym> file
+language, text encoding, last translator name, charset. If a field
+does not exist, it is appended to the header. If you want to add other
+information to the header, you have to edit the header manually by
+choosing <menuchoice><guimenu>Edit</guimenu><guimenuitem>Edit
+Header</guimenuitem></menuchoice> in the editor window. Deactivate
+<guibutton>Update header when saving</guibutton> above if you don't
+want to have the header updated.</para>
+
+<para>For date and time of the header field
+<emphasis>PO-Revision-Date</emphasis> you can choose one of the
+formats: <guilabel>Default</guilabel>, <guilabel>Local</guilabel>, <guilabel>Custom</guilabel>.</para>
+
+<important><para>
+You should keep the default setting of <guilabel>Default</guilabel>. The two other settings
+make that the generated <acronym>PO</acronym> file is not a standard &GNU; gettext <acronym>PO</acronym> file
+anymore, so this should be avoided.
+</para></important>
+
+<itemizedlist>
+ <listitem><para>
+ <guilabel>Default</guilabel> is the format normally used in <acronym>PO</acronym> files.
+ </para></listitem>
+ <listitem><para>
+ <guilabel>Local</guilabel> is the format specific to your country.
+ </para></listitem>
+ <listitem><para>
+ <guilabel>Custom</guilabel> lets you define your own format, where you
+ can use the following C-like format strings:
+ <table>
+ <title>Year</title>
+ <tgroup cols="3">
+ <thead>
+ <row>
+ <entry>Format</entry><entry>Meaning</entry><entry>Range</entry>
+ </row>
+ </thead>
+ <tbody>
+ <row>
+ <entry>%y</entry><entry>year</entry><entry>00 to 99</entry>
+ </row>
+ <row>
+ <entry>%Y</entry><entry>year</entry><entry>0001 to 9999</entry>
+ </row>
+ </tbody>
+ </tgroup>
+ </table>
+ <table>
+ <title>Month</title>
+ <tgroup cols="3">
+ <thead>
+ <row>
+ <entry>Format</entry><entry>Meaning</entry><entry>Range</entry>
+ </row>
+ </thead>
+ <tbody>
+ <row>
+ <entry>%m</entry><entry>month of year</entry><entry>01 to 12</entry>
+ </row>
+ <row>
+ <entry>%f</entry><entry>month of year</entry><entry>1 to 12</entry>
+ </row>
+ <row>
+ <entry>%b,%h</entry><entry>month abbreviation</entry><entry>Jan to Dec</entry>
+ </row>
+ </tbody>
+ </tgroup>
+ </table>
+ <table>
+ <title>Day</title>
+ <tgroup cols="3">
+ <thead>
+ <row>
+ <entry>Format</entry><entry>Meaning</entry><entry>Range</entry>
+ </row>
+ </thead>
+ <tbody>
+ <row>
+ <entry>%j</entry><entry>day of the year</entry><entry>001 to 366</entry>
+ </row>
+ <row>
+ <entry>%d</entry><entry>day of month</entry><entry>01 to 31</entry>
+ </row>
+ <row>
+ <entry>%e</entry><entry>day of month</entry><entry>1 to 31</entry>
+ </row>
+ <row>
+ <entry>%a</entry><entry>weekday abbreviation</entry><entry>Sun to Sat</entry>
+ </row>
+ </tbody>
+ </tgroup>
+ </table>
+ <table>
+ <title>Hour</title>
+ <tgroup cols="3">
+ <thead>
+ <row>
+ <entry>Format</entry><entry>Meaning</entry><entry>Range</entry>
+ </row>
+ </thead>
+ <tbody>
+ <row>
+ <entry>%H</entry><entry>hour</entry><entry>00 to 23</entry>
+ </row>
+ <row>
+ <entry>%k</entry><entry>hour</entry><entry>0 to 23</entry>
+ </row>
+ <row>
+ <entry>%i</entry><entry>hour</entry><entry>1 to 12</entry>
+ </row>
+ <row>
+ <entry>%I</entry><entry>hour</entry><entry>01 to 12</entry>
+ </row>
+ <row>
+ <entry>%p</entry><entry></entry><entry>AM or PM</entry>
+ </row>
+ </tbody>
+ </tgroup>
+ </table>
+ <table>
+ <title>Minute, Second, Timezone</title>
+ <tgroup cols="3">
+ <thead>
+ <row>
+ <entry>Format</entry><entry>Meaning</entry><entry>Range</entry>
+ </row>
+ </thead>
+ <tbody>
+ <row>
+ <entry>%M</entry><entry>minute</entry><entry>00 to 59</entry>
+ </row>
+ <row>
+ <entry>%S</entry><entry>second</entry><entry>00 to 59</entry>
+ </row>
+ <row>
+ <entry>%Z</entry><entry>timezone</entry><entry>(given in identity settings)</entry>
+ </row>
+ <row>
+ <entry>%z</entry><entry>timezone</entry><entry>(numeric offset as specified by system settings)</entry>
+ </row>
+ </tbody>
+ </tgroup>
+ </table>
+ </para></listitem>
+</itemizedlist>
+
+<note><para>
+The option to select the date format for the <acronym>PO</acronym> file is considered to be deprecated,
+and will probably be removed in a future version of KBabel.
+</para></note>
+
+<para>The lower group covers encoding options for <acronym>PO</acronym>
+files when saving. If you work on the &kde; project you should be aware
+that at least <acronym>PO</acronym> files <emphasis>must</emphasis> be UTF-8 encoded in &kde;.
+Alternatively you can select the encoding corresponding to your locale.
+If, for some reason, you do not want to accidentally change the current PO
+file encoding, turn on <guibutton>Keep the encoding of the
+file</guibutton>.</para>
+
+<caution><para>
+For reason of informtation interchange, &GNU; gettext limits the encodings allowed for a
+<acronym>PO</acronym> file. &kbabel; does not know of this restriction, so the encoding
+correspondig to your locale might not be suitable. (UTF-8 is always supported by &GNU; gettext.)
+</para></caution>
+
+</sect2>
+
+<sect2 id="preferences-project-spellcheck">
+<title>Spell Check</title>
+
+<para>These settings are for &kbabel;.</para>
+
+<para>Here you can set your spell checking preferences. This is of
+interest if you have a dictionary file for the language you are
+translating to. Below are the items to consider setting:</para>
+
+<variablelist>
+ <varlistentry>
+ <term><guibutton>Create root/affix combinations not in dictionary</guibutton></term>
+ <listitem><para>
+ For new words added to the personal dictionary,
+ the spell checker will create root/affix
+ combinations to match more than one word (variations).
+ </para></listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><guibutton>Consider run-together words as spelling errors</guibutton></term>
+ <listitem><para>
+ If this is turned on, joined words will be treated
+ as errors. However, such words are very common in
+ the German language, which have a very large number of
+ compound words, so it should be left turned off in that case.
+ </para></listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><guilabel>Dictionary</guilabel></term>
+ <listitem><para>
+ From the popup list you can choose which dictionary to use. Note
+ that you must install an appropriate dictionary for your language.
+ Check your ispell or aspell distribution to find out if you have
+ one.
+ </para></listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><guilabel>Encoding</guilabel></term>
+ <listitem>
+<para>
+ Here you choose the encoding for your text. This option is passed
+ to the spellchecker, and is used as the encoding for your words
+ dictionary.
+ See the <ulink url="help:/kspell">kspell</ulink> documentation for
+ more details.
+</para>
+<note><para>
+The encoding selected here is not linked to encodings of the
+<acronym>PO</acronym> files. Depending on the spellchecker
+(especially in the case of <command>ispell</command>),
+you might not have much choice for the encoding.
+(For example, a few Western European languages can only work
+with <command>ispell</command> when using ISO-8859-1.)
+</para></note>
+ </listitem>
+
+ </varlistentry>
+ <varlistentry>
+ <term><guilabel>Client</guilabel></term>
+ <listitem><para>
+ Backend program to use for spell checking. Currently either
+ <command>ispell</command> (International Ispell) or aspell.
+ </para></listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><guibutton>Remember ignored words</guibutton></term>
+ <listitem><para>
+ Keep track of user-ignored words when spell-checking
+ <acronym>PO</acronym> files. It is very convenient to ignore the abbreviations or strange letter combinations you meet in &GUI; interfaces.
+ </para></listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><guilabel>File to store ignored words</guilabel></term>
+ <listitem><para>
+ Here you can set location of the file for ignored words. Click
+ on the folder icon to the right of the edit box. The default is
+ <filename>$<envar>HOME</envar>/.kde/share/apps/kbabel/spellignores</filename>,
+ where <filename>$<envar>HOME</envar></filename> is your home folder.
+ </para></listitem>
+ </varlistentry>
+</variablelist>
+</sect2>
+
+<sect2 id="preferences-project-source">
+<title>Source reference</title>
+
+<para>These settings are for &kbabel;.</para>
+
+<screenshot>
+<screeninfo>Project Settings, source reference</screeninfo>
+<mediaobject>
+<imageobject>
+<imagedata fileref="pref_proj_source.png" format="PNG"/>
+</imageobject>
+<textobject><phrase>Project Settings, source reference</phrase></textobject>
+</mediaobject>
+</screenshot>
+
+<para>
+This dialog is for setting how KBabel should construct the full path from each source references,
+which are in the comments of each entry of a <acronym>PO</acronym> file.
+</para>
+
+<sect3>
+<title>Dialog elements</title>
+
+<para>
+In the edit line <guilabel>Base folder for source code</guilabel>, you can set a
+base folder where the source code of your project is. This defines the value of the variable
+<userinput>@CODEROOT@</userinput>, which is described below.
+</para>
+
+<para>
+In the group <guilabel>Path Patterns</guilabel>, you can define patterns or rules
+to construct the paths with the help of a few variables:
+<userinput>@CODEROOT@</userinput>, <userinput>@PACKAGEDIR@</userinput>,
+<userinput>@PACKAGE@</userinput>, <userinput>@COMMENTPATH@</userinput>,
+<userinput>@POFILEDIR@</userinput>, which are defined below.
+</para>
+
+<note><para>
+The variable <userinput>@PODIRFILE@</userinput> was introduced in &kbabel; version 1.11.1 (for &kde; 3.5.1).
+</para></note>
+
+<para>
+With the button <guibutton>Add</guibutton>, you can add the line from the text box
+to the list of used path patterns. With the button <guibutton>Remove</guibutton>,
+you can remove the selected pattern from the list. With the buttons
+<guibutton>Up</guibutton> and <guibutton>Down</guibutton>, you can change the priority of
+the path patterns.
+</para>
+
+</sect3>
+
+<sect3>
+<title>The variables</title>
+
+<itemizedlist>
+<listitem><para>
+<userinput>@CODEROOT@</userinput>: The base folder of the source code.
+</para></listitem>
+<listitem><para>
+<userinput>@PACKAGEDIR@</userinput>: The folder of the package (i.e. <acronym>PO</acronym> file).
+</para></listitem>
+<listitem><para>
+<userinput>@PACKAGE@</userinput>: The package name (i.e. <acronym>PO</acronym> file name without extension).
+</para></listitem>
+<listitem><para>
+<userinput>@POFILEDIR@</userinput>: The folder of the <acronym>PO</acronym> file.
+</para></listitem>
+<listitem><para>
+<userinput>@COMMENTPATH@</userinput>: The relative path given as source reference in the comment of an entry of the <acronym>PO</acronym> file.
+</para></listitem>
+</itemizedlist>
+
+<important><para>
+The variables <userinput>@PACKAGEDIR@</userinput> and <userinput>@POFILEDIR@</userinput> have similar
+meaning but not the same result. The variable <userinput>@POFILEDIR@</userinput>
+will always hold the folder of <acronym>PO</acronym> file,
+<userinput>@PACKAGEDIR@</userinput> might not. If the <acronym>PO</acronym> file was loaded
+by the help of the &catalogmanager; then <userinput>@PACKAGEDIR@</userinput> has only the part of
+the path, based on the <acronym>PO</acronym> base path defined for the &catalogmanager;
+<link linkend="preferences-project-folders">(see below)</link>.
+</para></important>
+
+<note><para>
+The variables <userinput>@CODEROOT@</userinput> and <userinput>@POFILEDIR@</userinput> can only be used at
+the beginning of a pattern to be useful. The variable <userinput>@COMMENTPATH@</userinput> can only be used at the
+end of a pattern and is nearly mandatory.
+The variables <userinput>@PACKAGEDIR@</userinput> and <userinput>@POFILEDIR@</userinput>
+should not be used in the same pattern. The variables <userinput>@CODEROOT@</userinput> and <userinput>@POFILEDIR@</userinput> should not be used in the same pattern either.
+</para></note>
+
+</sect3>
+
+<sect3>
+<title>The default path patterns</title>
+
+<para>
+From &kbabel; 1.11.1 (of &kde; 3.5.1) on, there are five default path patterns:
+</para>
+
+<itemizedlist>
+<listitem><para>
+<userinput>@PACKAGEDIR@</userinput>/<userinput>@PACKAGE@</userinput>/<userinput>@COMMENTPATH@</userinput>
+</para></listitem>
+<listitem><para>
+<userinput>@CODEROOT@</userinput>/<userinput>@PACKAGEDIR@</userinput>/<userinput>@PACKAGE@</userinput>/<userinput>@COMMENTPATH@</userinput>
+</para></listitem>
+<listitem><para>
+<userinput>@CODEROOT@</userinput>/<userinput>@PACKAGE@</userinput>/<userinput>@COMMENTPATH@</userinput>
+</para></listitem>
+<listitem><para>
+<userinput>@POFILEDIR@</userinput>/<userinput>@COMMENTPATH@</userinput>
+</para></listitem>
+<listitem><para>
+<userinput>@POFILEDIR@</userinput>/../<userinput>@COMMENTPATH@</userinput>
+</para></listitem>
+</itemizedlist>
+
+<note><para>
+&kde; projects need typically the third pattern.
+The last pattern is typical for &GNU; projects, where the source references are related to
+the parent of the directory where the PO file is.
+</para></note>
+
+</sect3>
+
+<sect3>
+<title>Creating New Path Patterns</title>
+
+<para>
+In most cases the default path patterns should be enough, whatever
+the project is for KDE (assuming that you have set the correct base directory)
+or if the project is a &GNU; one (or structured like a &GNU; project).
+</para>
+
+<note><para>
+For &kde;, some <acronym>PO</acronym> files do not contain enough information
+(including the file path and name) for &kbabel; to find the right source file
+that is supposed to be refered. To fix that you would need precise path patterns
+for such files, which is nearly impossible to define by the numbers of such files
+in &kde;. But if you work often with such a file, may be it is worth to set
+a path pattern explicitely for supporting that <acronym>PO</acronym> file.
+</para></note>
+
+<para>
+For creating your own path patterns, you can use the variables defined above,
+but apart <userinput>@COMMENTPATH@</userinput> not any variable is mandatory to use.
+(To be exact, <userinput>@COMMENTPATH@</userinput> is not mandatory either,
+but not using it will probably lead to no result.)
+</para>
+
+<para>
+An example of path pattern could be that you want to display the source reference
+of &kde;'s file desktop_kdebase.po. In that case you will probably need a path pattern like:
+<userinput>@CODEROOT@</userinput>/<userinput>@PACKAGEDIR@</userinput>/kdebase/<userinput>@COMMENTPATH@</userinput>
+(compared to one of the default path patterns, the sequence <userinput>@PACKAGE@</userinput> has been
+replaced by kdebase).
+</para>
+
+<para>
+In case of really complex problems you can, of course, define an absolute path
+without any variables beside <userinput>@COMMENTPATH@</userinput>, like for example:
+/home/usr/kde-source/kdebase/<userinput>@COMMENTPATH@</userinput> assuming that
+/home/usr/kde-source/kdebase is the path where the kdebase source module is.
+</para>
+
+</sect3>
+
+</sect2>
+
+<sect2 id="preferences-project-miscellaneous">
+<title>Miscellaneous</title>
+
+<para>These settings are for &kbabel;.</para>
+
+<para>
+<guilabel>Miscellaneous</guilabel> section
+holds &kbabel; settings that do not fit anywhere else.
+</para>
+
+<variablelist>
+ <varlistentry>
+ <term><guilabel>Marker for keyboard accelerator</guilabel></term>
+ <listitem><para>
+ Here you can select your own character to serve
+ as the keyboard accelerator indicator in a &GUI;.
+ By default it is &amp; (ampersand), but in some
+ programming toolkits it may vary.
+ For example, in Gnome/GTK translations the underscore
+ character <quote>_</quote>
+ is the marker for the keyboard accelerator.
+ </para></listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><guilabel>Regular expression for context information</guilabel></term>
+ <listitem><para>
+ For inexperienced users "regular expression" may sound strange.
+ So you are advised to change the default value
+ only if you know what you are doing. Some &GUI; programming
+ toolkits provide their own context information description
+ methods. Consult an experienced developer if you
+ translate <acronym>PO</acronym> files other than standard &kde; files.
+ For the sake of completeness I will "translate" for you what the
+ default regular expression means:
+ "the text matches if it starts with _: and is followed
+ by one or more characters and ends with a newline".
+ </para></listitem>
+ </varlistentry>
+</variablelist>
+</sect2>
+
+<!-- Catalog Manager project settings -->
+
+<sect2 id="preferences-project-folders">
+<title>Project folders</title>
+
+<para>These settings are for &catalogmanager;.</para>
+
+<para>
+Here are two edit lines with folder buttons.
+Type in or select the folders that contains all your <acronym>PO</acronym> and respectively
+<acronym>POT</acronym> files. The files and the folders in these folders will then be
+merged into one tree in Catalog Manager window.
+</para>
+
+<para>
+Below you can turn on and off if:
+</para>
+
+<variablelist>
+ <varlistentry>
+ <term><guibutton>Open files in new window</guibutton></term>
+ <listitem><para>
+ If this is activated all files that are opened from the Catalog
+ Manager are opened in a new window.
+ </para></listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><guibutton>Kill processes on exit</guibutton></term>
+ <listitem><para>
+ If you check this, &kbabel; tries to kill the processes that are not
+ exited already when the program closes by sending a kill signal to them.
+ <note><para>
+ It's not guaranteed that the processes are killed.
+ </para></note>
+ </para></listitem>
+ </varlistentry>
+<varlistentry>
+ <term><guibutton>Create index for file contents</guibutton></term>
+ <listitem><para>
+ If you check this, &kbabel; will create an index of contents for every
+ file in the tree. This index is then used in find/replace operations.
+ <warning><para>There is a large speed trade-off. If you enable
+ <guibutton>Create index for file contents</guibutton>, the updating of
+ file information will be much slower. On the other hand, it speeds up
+ find/replace operations considerably.</para></warning>
+ </para></listitem>
+ </varlistentry>
+</variablelist>
+</sect2>
+
+<sect2 id="preferences-project-folder-commands">
+<title>Folder Commands</title>
+
+<para>These settings are for &catalogmanager;.</para>
+
+<screenshot>
+<screeninfo>Project Settings,folder commands</screeninfo>
+<mediaobject>
+<imageobject>
+<imagedata fileref="pref_proj_folder_commands.png" format="PNG"/>
+</imageobject>
+<textobject><phrase>Project Settings, folder commands</phrase></textobject>
+</mediaobject>
+</screenshot>
+
+<para>
+Here you can insert commands you want to execute in folders from the
+Catalog Manager. The commands are then shown in the submenu
+<menuchoice><guimenuitem>Commands</guimenuitem></menuchoice>
+in the Catalog Manager's context menu.
+
+</para><para>
+Insert in the <guilabel>Command Label</guilabel> field the
+label of the command. The label can be chosen freely and is only used to be displayed
+in the menu. In the <guilabel>Command</guilabel> field insert the command you want to
+have executed when selecting the corresponding menu item. Then press the <guibutton>Add</guibutton>
+button to add the command to your available commands.
+To edit a command, select it, press the
+<guibutton>Edit</guibutton> button and press <guibutton>Add</guibutton> after you have
+finished. To remove a command, select it from the list and press the
+<guibutton>Remove</guibutton> button. If you want a different order in the contextual
+submenu, you can use the up and down buttons.
+
+</para><para>
+The command is executed through your default shell, so you can execute
+multiple commands at once by separating them with a semicolon, and you can set environment
+variables if you need to. The commands are executed in the (<acronym>PO</acronym> file) folder you have
+selected in the Catalog Manager.
+
+</para><para>
+The following strings will be replaced in a command:
+</para>
+
+<itemizedlist>
+ <listitem><para>
+ <userinput>@PACKAGE@</userinput>: The name of the folder without path
+ </para></listitem>
+ <listitem><para>
+ <userinput>@PODIR@</userinput>: The name of the <acronym>PO</acronym>-folder with path
+ </para></listitem>
+ <listitem><para>
+ <userinput>@POTDIR@</userinput>: The name of the template folder with path
+ </para></listitem>
+</itemizedlist>
+
+<para>
+E.g.: If you want to execute <command>make</command> and then <command>make
+install</command> you could insert in <userinput>Make install</userinput> in the
+<guilabel>Name</guilabel> field, and <userinput>make; make install</userinput>
+in the <guilabel>Command</guilabel> field. If you then select
+<menuchoice><guimenuitem>Commands</guimenuitem>
+<guimenuitem>Make install</guimenuitem></menuchoice>
+from the context menu of a folder, the commands listed above will be
+executed in that folder.
+</para>
+</sect2>
+
+<sect2 id="preferences-project-file-commands">
+<title>File Commands</title>
+
+<para>These settings are for &catalogmanager;.</para>
+
+<screenshot>
+<screeninfo>Project Settings, file commands</screeninfo>
+<mediaobject>
+<imageobject>
+<imagedata fileref="pref_proj_file_commands.png" format="PNG"/>
+</imageobject>
+<textobject><phrase>Project Settings, file commands</phrase></textobject>
+</mediaobject>
+</screenshot>
+
+<para>
+Here you can insert the commands you want to execute on files from the Catalog
+Manager. The commands are then shown in the submenu
+<menuchoice><guimenuitem>Commands</guimenuitem></menuchoice> in the Catalog
+Manager's context menu.
+</para>
+
+<para>
+Insert in the <guilabel>Command Label</guilabel> field the label of the command. The label can be
+chosen freely and is only used to be displayed in the menu. In the
+<guilabel>Command</guilabel> field insert the command you want to have executed when
+selecting the corresponding menu item. Then press the <guibutton>Add</guibutton> button
+to add the command to your available commands. To edit a command, select it, press
+the <guibutton>Edit</guibutton> button and press the <guibutton>Add</guibutton> button after you have
+finished. To remove a command, select it from the list and press the
+<guibutton>Remove</guibutton> button. If you want a different order in the contextual
+submenu, you can use the up and down buttons.
+
+</para><para>
+The command is executed through your default shell, so you can execute
+multiple commands at once by separating them with a semicolon, and you can
+set environment variables, if you need. The commands are executed in the
+(<acronym>PO</acronym> file) folder, in which the file, you have selected in the Catalog
+Manager, is.
+
+</para><para>
+The following strings will be replaced in a command:
+</para>
+
+<itemizedlist>
+ <listitem><para>
+ <userinput>@PACKAGE@</userinput>: The name of the file without path and extension
+ </para></listitem>
+ <listitem><para>
+ <userinput>@POFILE@</userinput>: The name of the <acronym>PO</acronym> file with path and extension
+ </para></listitem>
+ <listitem><para>
+ <userinput>@POTFILE@</userinput>: The name of the corresponding template file
+ with path and extension
+ </para></listitem>
+ <listitem><para>
+ <userinput>@PODIR@</userinput>: The name of the folder the <acronym>PO</acronym> file is in, with path
+ </para></listitem>
+ <listitem><para>
+ <userinput>@POTDIR@</userinput>: The name of the folder the template file is
+ in, with path
+ </para></listitem>
+</itemizedlist>
+<para>
+For example, if you want to merge the template file into your <acronym>PO</acronym> file you could
+insert <userinput>Merge</userinput> in the <guilabel>Name</guilabel> field and
+<userinput>msgmerge @POFILE@ @POTFILE@ &gt; @PACKAGE@.new &amp;&amp; mv @PACKAGE@.new
+"@PACKAGE@.po</userinput> in the <guilabel>Command</guilabel> field.
+If you then select
+<menuchoice><guimenuitem>Commands</guimenuitem><guimenuitem>Merge</guimenuitem></menuchoice>
+from a file's context menu, the <acronym>PO</acronym> file will be merged with its template file.
+</para>
+</sect2>
+
+<sect2 id="preferences-project-catalog-manager">
+<title>Catalog Manager</title>
+
+<para>These settings are for &catalogmanager;.</para>
+
+<screenshot>
+<screeninfo>Project Settings, &catalogmanager;</screeninfo>
+<mediaobject>
+<imageobject>
+<imagedata fileref="pref_proj_catman.png" format="PNG"/>
+</imageobject>
+<textobject><phrase>Project Settings, &catalogmanager;</phrase></textobject>
+</mediaobject>
+</screenshot>
+
+<para>The checkboxes switches on or off the corresponding column of the &catalogmanager;'s view.</para>
+
+</sect2>
+
+<sect2 id="preferences-project-diff">
+<title>Diff</title>
+
+<para>These settings are for &catalogmanager;.</para>
+
+<screenshot>
+<screeninfo>Project Settings, diff</screeninfo>
+<mediaobject>
+<imageobject>
+<imagedata fileref="pref_proj_diff.png" format="PNG"/>
+</imageobject>
+<textobject><phrase>Project Settings, diff</phrase></textobject>
+</mediaobject>
+</screenshot>
+
+<para><remark>TODO</remark></para>
+
+</sect2>
+
+</sect1>
+</chapter>
+<!--
+Local Variables:
+mode: xml
+sgml-minimize-attributes:nil
+sgml-general-insert-case:lower
+sgml-indent-step:0
+sgml-indent-data:nil
+End:
+
+vim:tabstop=2:shiftwidth=2:expandtab
+-->
diff --git a/doc/kbabel/preverror.png b/doc/kbabel/preverror.png
new file mode 100644
index 00000000..d589b53b
--- /dev/null
+++ b/doc/kbabel/preverror.png
Binary files differ
diff --git a/doc/kbabel/prevfuzzy.png b/doc/kbabel/prevfuzzy.png
new file mode 100644
index 00000000..2e4cedfa
--- /dev/null
+++ b/doc/kbabel/prevfuzzy.png
Binary files differ
diff --git a/doc/kbabel/prevfuzzyuntrans.png b/doc/kbabel/prevfuzzyuntrans.png
new file mode 100644
index 00000000..cf6f43d4
--- /dev/null
+++ b/doc/kbabel/prevfuzzyuntrans.png
Binary files differ
diff --git a/doc/kbabel/previous.png b/doc/kbabel/previous.png
new file mode 100644
index 00000000..167e39e7
--- /dev/null
+++ b/doc/kbabel/previous.png
Binary files differ
diff --git a/doc/kbabel/prevuntranslated.png b/doc/kbabel/prevuntranslated.png
new file mode 100644
index 00000000..796a4e3d
--- /dev/null
+++ b/doc/kbabel/prevuntranslated.png
Binary files differ
diff --git a/doc/kbabel/redo.png b/doc/kbabel/redo.png
new file mode 100644
index 00000000..d6b3e8f1
--- /dev/null
+++ b/doc/kbabel/redo.png
Binary files differ
diff --git a/doc/kbabel/roughtranslation.png b/doc/kbabel/roughtranslation.png
new file mode 100644
index 00000000..cd96526c
--- /dev/null
+++ b/doc/kbabel/roughtranslation.png
Binary files differ
diff --git a/doc/kbabel/snap1.png b/doc/kbabel/snap1.png
new file mode 100644
index 00000000..55e3c9cd
--- /dev/null
+++ b/doc/kbabel/snap1.png
Binary files differ
diff --git a/doc/kbabel/snap_catalogmanager.png b/doc/kbabel/snap_catalogmanager.png
new file mode 100644
index 00000000..20aff2ec
--- /dev/null
+++ b/doc/kbabel/snap_catalogmanager.png
Binary files differ
diff --git a/doc/kbabel/snap_kbabeldict.png b/doc/kbabel/snap_kbabeldict.png
new file mode 100644
index 00000000..58d9db14
--- /dev/null
+++ b/doc/kbabel/snap_kbabeldict.png
Binary files differ
diff --git a/doc/kbabel/snap_kbabeldict2.png b/doc/kbabel/snap_kbabeldict2.png
new file mode 100644
index 00000000..562862e7
--- /dev/null
+++ b/doc/kbabel/snap_kbabeldict2.png
Binary files differ
diff --git a/doc/kbabel/stop.png b/doc/kbabel/stop.png
new file mode 100644
index 00000000..1cabc6e9
--- /dev/null
+++ b/doc/kbabel/stop.png
Binary files differ
diff --git a/doc/kbabel/top.png b/doc/kbabel/top.png
new file mode 100644
index 00000000..b626bf42
--- /dev/null
+++ b/doc/kbabel/top.png
Binary files differ
diff --git a/doc/kbabel/transsearch.png b/doc/kbabel/transsearch.png
new file mode 100644
index 00000000..06d5852c
--- /dev/null
+++ b/doc/kbabel/transsearch.png
Binary files differ
diff --git a/doc/kbabel/undo.png b/doc/kbabel/undo.png
new file mode 100644
index 00000000..f5ad210d
--- /dev/null
+++ b/doc/kbabel/undo.png
Binary files differ
diff --git a/doc/kbabel/using.docbook b/doc/kbabel/using.docbook
new file mode 100644
index 00000000..091361e6
--- /dev/null
+++ b/doc/kbabel/using.docbook
@@ -0,0 +1,791 @@
+<!-- <?xml version="1.0" ?>
+<!DOCTYPE chapter PUBLIC "-//KDE//DTD DocBook XML V4.2-Based Variant V1.1//EN" "dtd/kdex.dtd"> -->
+<!-- Uncomment the previous two lines to validate this document -->
+<!-- standalone. Be sure to recomment them before attempting to -->
+<!-- process index.docbook -->
+
+<chapter id="using-kbabel">
+<chapterinfo>
+<!-- Fill in this section if this document has a different author -->
+<authorgroup>
+<author>
+<personname><firstname></firstname><surname></surname></personname>
+</author>
+</authorgroup>
+
+<!-- TRANS:ROLES_OF_TRANSLATORS -->
+</chapterinfo>
+
+
+<title>Using &kbabel;</title>
+
+<sect1 id="using-introduction">
+<title>Introduction</title>
+
+<para>Usually program messages and documentation are written in
+English. Using a framework made of a set of tools and libraries, it
+is possible to have your favorite applications speak your native
+non-English language. This process of adapting an application to a
+specific language is known as localization. The localization process
+includes translating the program's interfaces and documentation to the
+various languages users need and, in some countries or regions, making
+the inputs and outputs conform to particular conventions. &kbabel; is
+a tool which will assist you in the localization process to
+make an application's interface speak many languages.</para>
+
+<para> Every internationalization-aware program makes available for
+translation one or more message-catalog files. The extension of these
+files is <literal role="extension">.pot</literal>.
+<acronym>POT</acronym> is an acronym for <quote>Portable Object
+Template</quote>.</para>
+
+<para>
+Each translator takes a copy of one of these <acronym>POT</acronym> templates and
+begins to fill in the blanks: each message is translated into the
+language desired. The file containing the translated text is referred
+to as a <acronym>PO</acronym> (Portable Object) file.
+</para>
+
+<para>
+Once all the messages have been translated, the
+<acronym>PO</acronym> file is compiled into a machine-readable binary
+format, known as a <acronym>MO</acronym> (Machine Object) file. These
+files, which will be stored with a <literal
+role="extension">.mo</literal> extension
+(or a <literal role="extension">.gmo</literal> extension to show
+that they were processed by &GNU; gettext), act as a database to
+minimize the time taken by the applications to look up each translated
+message.
+</para>
+
+<para> This suggests a question: do I need to know what is
+inside a <acronym>PO</acronym> file even though I have &kbabel;? The
+answer is, undoubtedly, yes. There are situations when a message
+catalog can become corrupted and needs to be manually fixed. Most of
+these problems are the so-hated <acronym>CVS</acronym> or <acronym>SVN</acronym> conflicts which
+occur when a translating process is coordinated by a version management
+system, like <acronym>CVS</acronym> or Subversion (<acronym>SVN</acronym>).
+&kbabel; cannot help you much if a problem like this arises so a
+text editor and some knowledge of <acronym>PO</acronym>-files are
+needed. Let's see how a <acronym>PO</acronym> file is made.</para>
+
+<para><acronym>PO</acronym> files consist of pairs of messages&mdash;a
+<emphasis>msgid</emphasis> and a <emphasis>msgstr</emphasis>. The
+msgid is the text in English and the msgstr is the text translated
+into the appropriate language. The text that accompanies each msgid
+and msgstr is enclosed within C-like double quotes. An example, taken
+from a <acronym>PO</acronym> file for &noatun;, is <literal>msgid
+&quot;Open a Playlist&quot;</literal> </para>
+
+<!-- ### TODO: we would need an example of an entry -->
+
+<para>Empty lines and those starting with <literal>#</literal> are
+ignored. Lines starting with a # represent comments and are a useful
+way of providing a note detailing which file this message is going
+to be used in and, in the case of the application writers, to provide
+additional comments to help translation. &kbabel; displays these
+comment lines for every message.</para>
+
+<para>In many cases the first msgid-msgstr pair in
+<acronym>PO</acronym> file is a fake entry (acting as
+<acronym>PO</acronym> file header) that contains various information
+about the translated <acronym>PO</acronym> file, such as the
+application name, translating date, translator name and so on.</para>
+
+<para>
+An useful feature is called <emphasis>plural forms</emphasis>.
+English uses only singular and one plural form of nouns, &eg; <quote>1 file
+</quote> and <quote>10 files</quote>. This leads many developers
+to an idea that the world is that simple and they can use messages like
+<quote>Do you want to delete %1 file(s)?</quote>, where
+<literal>%1</literal> denotes a number of files to be deleted.
+But this is fundamentally wrong and for many languages such a kind of translation
+will not work. For Slovak translation you need 3 different
+forms of the message. This number is different for different languages
+and even when it is the same, &eg; Czech uses 3 forms as well, the rule to decide which
+form to use can be very different. Plural forms in <acronym>PO</acronym> files are here to help.
+</para>
+
+<note><para>
+&kde; developers have chosen a different implementation for the plural forms than
+<application>&GNU; gettext</application> and they have introduced their own
+format and handling for them.
+It is planned to use &GNU; gettext's plural forms in &kde; version 4.
+</para></note>
+
+</sect1>
+
+<sect1 id="using-editor">
+<title>Editor</title>
+
+<para>Here is a screenshot of &kbabel;.</para>
+
+<screenshot>
+<screeninfo>Screenshot of &kbabel;</screeninfo>
+<mediaobject>
+<imageobject>
+<imagedata fileref="snap1.png" format="PNG"/>
+</imageobject>
+<textobject><phrase>Screenshot of &kbabel;</phrase></textobject>
+</mediaobject>
+</screenshot>
+
+<para>
+For convenience &kbabel; has
+toolbars to speed up many operations and, for busy users, there are
+many keyboard shortcuts. The main window is divided into four
+parts.
+</para>
+
+<para>The <emphasis>upper-left</emphasis> edit box is read-only and
+contains the current msgid field from the opened PO-file and its
+English text.</para>
+
+<para>The <emphasis>bottom-left</emphasis> edit box contains the
+msgstr field related to the msgid shown and here you can edit the
+translated text.</para>
+
+<para>The <emphasis>top-right</emphasis> part of the window is a comments
+panel where you can view the comments added for entry currently being
+edited.</para>
+
+<para>It can be used:</para>
+
+<itemizedlist>
+<listitem><para>
+to find out how the current message is treated by the
+application (c-formatted or simple)
+</para></listitem>
+<listitem><para>
+in some cases, to read helpful comments added by the application's
+developer to assist the translators in their work&mdash;for example,
+there may be technical hints (used to great effect in the
+<application>LyX</application> project)
+</para></listitem>
+<listitem><para>
+when you need to know which file a message is from because you
+want to report a spelling mistake in the original English string.
+</para></listitem>
+</itemizedlist>
+
+<para>
+The editor window (in the bottom right) is the most sophisticated part
+of &kbabel;'s main window. Its size can be
+adjusted using the splitter line between it and the comment panel
+(the panel in the top right).
+The editor window has two tabbed panels&mdash;one storing search
+information, the other context information. The context information
+tab contain a scrolled view which shows the previous and next 4 entries
+associated with the current entry&mdash;essentially it's a small
+'snapshot' of the PO file. While translating, it is very common for
+message strings to be related to subsequent and previous messages,
+so the context panel is useful for looking at the nearby messages to
+get a hint as to how the current message can best be
+translated. Dialog interface translation is a good example, or widgets
+with their associated text and "what's this" message.
+</para>
+
+<sect2 id="more-kbabel-features">
+<title>More &kbabel; Features</title>
+
+<para>
+Each msgid entry can be in three states:
+</para>
+
+<variablelist>
+ <varlistentry>
+ <term>untranslated</term>
+ <listitem>
+ <para>
+ there is no translated text currently associated with the msgstr
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>fuzzy</term>
+ <listitem>
+ <para>
+ <command>msgmerge</command> has tried to match a translated
+ string by looking in rest of PO-file entries. This does not work
+ perfectly and you must edit the translated text to fit the current
+ English text.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>translated</term>
+ <listitem>
+ <para>
+ the msgid is the completed translated form of the msgstr
+ </para>
+ </listitem>
+ </varlistentry>
+</variablelist>
+
+<para>The state of the current entry is indicated by two
+<acronym>LED</acronym>s. Depending on your configuration these can
+either be in the status bar or above the <guilabel>translated
+string</guilabel> edit box. Both have a customizable color (to
+reflect your visual requirements or taste). Please read the <link
+linkend="preferences">Preferences</link> section to see how you can
+adjust these settings.</para>
+
+</sect2>
+
+</sect1>
+
+<sect1 id="kbabel-features">
+<title>Advanced Translation</title>
+
+<para>
+Now you have an idea how to translate a PO-file. In this section we will follow the standard way
+of translating a new PO-file using the advanced features of &kbabel;. We assume you have already
+opened a template POT-file and saved it as a PO file.
+</para>
+
+<sect2 id="kbabel-navigation">
+<title>Navigation in PO-file</title>
+<para>&kbabel; allows you to easily navigate through the file according to the state of their
+translation. The untranslated/fuzzy status was introduced already. A message can be marked as erroneous
+as a result of <link linkend="kbabel-validation">validation checking</link> or validation done by <command>msgfmt</command>.
+And, of course, &kbabel; supports browsing the history of visited messages with
+<guilabel>Forward</guilabel>/<guilabel>Back</guilabel>, like in &konqueror;.</para>
+<para>
+All commands for navigation are in <menuchoice><guimenu>Go</guimenu></menuchoice> menu.
+</para>
+<informaltable>
+<tgroup cols="2">
+<tbody>
+
+<row>
+<entry><para><keycombo action="simul"><keycap>Page Up</keycap></keycombo></para></entry>
+<entry><para>Move to the previous message </para></entry>
+</row>
+<row>
+<entry><para><keycombo action="simul"><keycap>Page Down</keycap></keycombo></para></entry>
+<entry><para> Move to the next message</para></entry>
+</row>
+<row>
+<entry><para><keycombo action="simul">&Ctrl;<keycap>Page Up</keycap></keycombo></para></entry>
+<entry><para>Move to the previous fuzzy message</para></entry>
+</row>
+<row>
+<entry><para><keycombo action="simul">&Ctrl;<keycap>Page Down</keycap></keycombo></para></entry>
+<entry><para>Move to the next fuzzy message</para></entry>
+</row>
+<row>
+<entry><para><keycombo action="simul">&Alt;<keycap>Page Up</keycap></keycombo></para></entry>
+<entry><para>Move to the previous untranslated message</para></entry>
+</row>
+<row>
+<entry><para><keycombo action="simul">&Alt;<keycap>Page Down</keycap></keycombo></para></entry>
+<entry><para>Move to the next untranslated message</para></entry>
+</row>
+<row>
+<entry><para><keycombo action="simul">&Shift;<keycap>Page Up</keycap></keycombo></para></entry>
+<entry><para>Move to the previous error message</para></entry>
+</row>
+<row>
+<entry><para><keycombo action="simul">&Shift;<keycap>Page Down</keycap></keycombo></para></entry>
+<entry><para>Move to the next error message</para></entry>
+</row>
+<row>
+<entry><para><keycombo action="simul">&Ctrl;&Shift;<keycap>Page Up</keycap></keycombo></para></entry>
+<entry><para>Move to the previous fuzzy or untranslated message</para></entry>
+</row>
+<row>
+<entry><para><keycombo action="simul">&Ctrl;&Shift;<keycap>Page Down</keycap></keycombo></para></entry>
+<entry><para>Move to the next fuzzy or untranslated message</para></entry>
+</row>
+</tbody>
+</tgroup>
+</informaltable>
+</sect2>
+
+<sect2 id="kbabel-cleveredit">
+<title>Clever editing</title>
+<para><emphasis>Clever editing</emphasis> means that the editor will help you
+easily edit the translation while taking into account specials of the PO format.
+It will correctly <quote>escape</quote> as necessary.</para>
+<para>
+It also supports more than
+one mode for inserting end of the line. This is very useful because of the way
+gettext handles end of the lines. It simply ignores them. (You can imagine that
+all the text in <acronym>msgstr</acronym> is a single line.) If you want insert a <quote>real</quote> end of the
+line, you need to insert <userinput>\n</userinput>. But most of translators
+do not realize, that a new line in <acronym>msgstr</acronym> does not
+add any space between the lines. This can be easily solved by adding a space
+at the end of every line. But you can easily forget, so clever editing does this automatically
+for you.
+</para>
+<para>The table below summarizes clever editing features.
+</para>
+
+<informaltable>
+<tgroup cols="2">
+<tbody>
+<row>
+<entry><para><keycombo action="simul"><keycap>Tab</keycap></keycombo></para></entry>
+<entry><para>Insert <emphasis>\t</emphasis></para></entry>
+</row>
+<row>
+<entry><para><keycombo action="simul"><keycap>"</keycap></keycombo></para></entry>
+<entry><para>Insert <emphasis>\"</emphasis></para></entry>
+</row>
+<row>
+<entry><para><keycombo action="simul"><keycap>Enter</keycap></keycombo></para></entry>
+<entry><para>If the last character before cursor is not a space, insert one space.
+Then start a new line.</para></entry>
+</row><row>
+<entry><para><keycombo action="simul">&Ctrl;<keycap>Enter</keycap></keycombo></para></entry>
+<entry><para>Start a new line without any additional logic</para></entry>
+</row>
+<row>
+<entry><para><keycombo action="simul">&Shift;<keycap>Enter</keycap></keycombo></para></entry>
+<entry><para>Insert <emphasis>\n</emphasis> and start a new line</para></entry>
+</row>
+</tbody>
+</tgroup>
+</informaltable>
+<note>
+<para>
+If you want to see where spaces are, you can turn on <guibutton>Highlight background</guibutton>
+and/or <guibutton>Mark whitespaces with points</guibutton> in preferences dialog
+on tab <guilabel>Edit</guilabel> <guilabel>Appearance</guilabel>.
+</para>
+</note>
+</sect2>
+
+<sect2 id="kbabel-roughtranslation">
+<title>Automatic translation</title>
+<para>As the first step when starting a new translation, &kbabel; provides a function
+for automatic filling of the messages translations by the older translations. Choose
+<menuchoice><guimenu>Tools</guimenu><guimenuitem>Rough Translation</guimenuitem>
+</menuchoice>
+and &kbabel; will present the following dialog:
+</para>
+<para>
+<screenshot>
+<screeninfo>Rough translation dialog</screeninfo>
+<mediaobject>
+<imageobject>
+<imagedata fileref="roughtranslation.png" format="PNG"/>
+</imageobject>
+</mediaobject>
+</screenshot>
+</para>
+<para>
+In the dialog, you should specify what to translate and choose the sources for
+the old translations.
+</para>
+<para>
+At the top of the <guilabel>What to translate</guilabel> frame are three
+checkboxes (<guilabel>Untranslated entries</guilabel>, <guilabel>Fuzzy entries
+</guilabel>, <guilabel>Translated entries</guilabel>) for specifying the kind of
+messages you want to translate. Untranslated and fuzzy entries are natural
+choices for automatic translation, but you can change already translated
+messages as well.
+</para>
+<para>
+The exact matching for <acronym>msgid</acronym>s will always be used for
+rough translation. However, you can add more strategies, &ie;
+<guilabel>Allow fuzzy translation (slow)</guilabel> and
+<guilabel>Allow single word translation</guilabel>. Both of these
+additional strategies must be supported by the sources used (see below).
+There is no specification, what does <quote>fuzzy translation</quote> mean,
+but the purpose is quite obvious. <quote>Single word translation</quote>
+is suitable for only some of the languages. &kbabel; will try to translate
+each word in <acronym>msgid</acronym> separately and then
+put the translated words (or phrases) in the same order in <acronym>msgstr
+</acronym>.
+</para>
+<para>
+As a source for rough translation, any dictionary module available can be
+used. There is a list of <guilabel>Don't use</guilabel> modules and
+<guilabel>Use</guilabel> modules. Modules are used in the order
+in the <guilabel>Use</guilabel> list. First module is asked for
+translation. If it is not found, next module in the list is asked and so on.
+You can use the buttons with arrows for moving modules between the
+lists. Don't forget to change the order to suit your needs by <guibutton>Move Up
+</guibutton> and <guibutton>Move Down</guibutton> buttons.
+</para>
+<para>
+Normally &kbabel; will mark every roughly translated message as
+fuzzy, because it assumes that any automatic translation needs to
+be reviewed by a translator. If you are 100% sure that the automatic
+translation will be correct, or you will review all the translation anyway.
+<guilabel>Mark changed entries as fuzzy</guilabel> allows you to
+turn off this automatic fuzzy marking, but you will need to confirm this.
+</para>
+<para>
+If you have set all the options to suit your needs, push <guibutton>Start
+</guibutton> to automatically translate messages. You can follow the
+progress bar and in case, there is always the <guibutton>Stop</guibutton>
+button.
+</para>
+</sect2>
+
+<sect2 id="kbabel-validation">
+<title>Validate your translation</title>
+<para>Everyone makes mistakes. So &kbabel; supports a number
+of checks for typical problems in translations. These checks (not
+syntax check) can be basically performed in two ways.</para>
+<para>
+Checks can be done at each change of the translated text. These
+are called <emphasis>automatic</emphasis> checks and they can
+be turned on in <link linkend="preferences-editor">the &kbabel; configuration dialog</link>.
+Automatic checking of syntax is possible at each saving of the file.
+</para>
+<para>
+The automatic checks can slow down &kbabel;. If you have a slower
+computer, you can turn off the automatic checks and use only the
+second possibility. You can invoke every kind of check from the
+<menuchoice><guimenu>Tools</guimenu><guisubmenu>
+Validation</guisubmenu></menuchoice>. Then the check is
+performed for all messages in the file and faulty ones are marked as errors.
+</para>
+<variablelist>
+ <varlistentry>
+ <term><guimenuitem>Check Syntax</guimenuitem></term>
+ <listitem>
+ <para>
+ This invokes <command>msgfmt</command> to check validity of the PO file
+ as seen by &GNU; gettext package. It will show the result of the command
+ and mark error <acronym>msgstr</acronym>s.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><guimenuitem>Check Arguments</guimenuitem></term>
+ <listitem>
+ <para>
+ Incorrect translations can crash the application. The most dangerous
+ parts of translation are arguments, &eg; for printf-like functions. This check
+ compares the number and types of the arguments in <acronym>msgid</acronym>
+ and <acronym>msgstr</acronym>. They must match.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><guimenuitem>Check Accelerators</guimenuitem></term>
+ <listitem>
+ <para>
+ &GUI; text commonly contain accelerators, &ie; letters which can be used
+ for fast access to &GUI; elements by keyboard. They are denoted by
+ special character, &eg; &amp; in &kde;. Typical requirement of the
+ translation is that translated text should contain accelerator as well.
+ This check will notice this problem for you. The accelerator character
+ can be specified in <guilabel>Preferences</guilabel> on <guilabel>Misc</guilabel> tab.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><guimenuitem>Look for Translated Context Info</guimenuitem></term>
+ <listitem>
+ <para>
+ You will probably need this only for &kde; translation. Some of the text are too common
+ and they need to be translated differently in different contexts. In &kde; the context
+ is described at the beginning of <acronym>msgid</acronym> after the special sequence
+ <userinput>:_</userinput>. But if some translators are not aware of this convention
+ and they try to translate context information as well. This check will try to find these.
+ If the check founds translated context information, you should remove it.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><guimenuitem>Check Plural Forms</guimenuitem></term>
+ <listitem>
+ <para>
+ If the <acronym>msgid</acronym> is specified as a <quote>plural form</quote>,
+ the translation has to contain the correct number of translations separated by
+ <userinput>\n</userinput>. The correct number depends on the language of
+ translation and is specified on <guilabel>Identity</guilabel> tab in <guilabel>
+ Preferences</guilabel> dialog. This is implemented only for &kde; at the moment.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><guimenuitem>Check Equations</guimenuitem></term>
+ <listitem>
+ <para>
+ Equations are special format of <acronym>msgid</acronym> typically
+ used in <filename>.desktop</filename> files.
+ And because your translations will be merged back to these files, <acronym>msgstr</acronym>
+ must use this special format as well. This means that the translation must start (up to the
+ first occurrence of <literal>=</literal> with the same text as the original message, &eg;
+ <userinput>Name=</userinput>.
+ <!-- ### TODO: is this feature is specific to KDE too? How does e.g. GNOME translate them? -->
+ </para>
+ </listitem>
+ </varlistentry>
+</variablelist>
+</sect2>
+
+<sect2 id="kbabel-spellcheck">
+<title>Spellchecking the translation</title>
+<para>As always, it is very important to spell-check your translation before
+using your result. This way you can find typos and other problems in your translation.
+&kbabel; uses the standard &kde; library for spellchecking and its standard
+settings can be found in <link linkend="preferences-project-spellcheck">the project setting dialog</link>. Spell checking itself can be found in
+<menuchoice><guimenu>Tools</guimenu><guisubmenu>Spelling</guisubmenu>
+</menuchoice> submenu.
+You can use a number of modes for spell checking:
+</para>
+<variablelist>
+ <varlistentry>
+ <term><guimenuitem>Spell check...</guimenuitem></term>
+ <listitem>
+ <para>
+ This is a generic invocation of a dialog where you can choose
+ the spellchecking mode and set the default mode. This is
+ invoked by pressing <keycombo action="simul">&Ctrl;<keycap>I</keycap>
+ </keycombo>.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><guimenuitem>Check All...</guimenuitem></term>
+ <listitem>
+ <para>
+ Spellcheck all messages in the file.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><guimenuitem>Check from Cursor Position...</guimenuitem></term>
+ <listitem>
+ <para>
+ Start spellchecking at the position in the current message and
+ progress towards the end of the file.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><guimenuitem>Check Current...</guimenuitem></term>
+ <listitem>
+ <para>
+ Spellcheck the current message only.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><guimenuitem>Check Selected Text...</guimenuitem></term>
+ <listitem>
+ <para>
+ If there is a selected text in <acronym>msgstr</acronym> editor,
+ this option is available and will spellcheck this text only.
+ </para>
+ </listitem>
+ </varlistentry>
+</variablelist>
+</sect2>
+
+<sect2 id="kbabel-tags">
+<title>Translating &XML;, <acronym>HTML</acronym>, ...</title>
+<para>
+Markup languages are used more and more in &GUI;.
+&kde; project also uses <acronym>PO</acronym>-files for translating
+DocBook documentation files (which is also a markup language). &kbabel;
+contains quite a lot of functionality to support this trend.
+</para>
+<note>
+<para>
+Here, we will describe only functions related to tags used for markup itself. The
+other problem introduced by using markup languages is translation of
+longer texts. This issue is addressed by the <emphasis>diff</emphasis>
+feature described in <link linkend="kbabel-diff">the following section</link>.
+</para>
+</note>
+<para>
+The current version of &kbabel; is capable to find out which tags are
+used in <acronym>msgid</acronym> and provide an easy access to
+them using following actions from the <guimenu>Edit</guimenu>:
+</para>
+
+<variablelist>
+<varlistentry>
+ <term>
+ <guimenuitem>Insert Next Tag</guimenuitem>
+ </term>
+ <listitem>
+ <para>
+ <action>
+ This inserts next tag found in msgid to the translation. &kbabel; finds
+ the tag to be inserted by counting the number of tags from the
+ beginning of the translation.
+ </action>
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>
+ <menuchoice>
+ <guimenu>Edit</guimenu>
+ <guisubmenu>Insert Tag</guisubmenu>
+ </menuchoice>
+ </term>
+ <listitem>
+ <para>
+ <action>
+ This submenu contains all different markup tags found in original english string.
+ By selecting a tag you can insert it at the current position of cursor in translated text.
+ translation.
+ </action>
+ </para>
+ </listitem>
+ </varlistentry>
+</variablelist>
+</sect2>
+
+<sect2 id="kbabel-diff">
+<title>Showing the difference</title>
+<para>
+As explained already, current applications, trying to be user friendly, contain a lot of
+longer descriptive texts, including markup. If a developer changes
+a part of the text, the &GNU; gettext system will, in the best case, retain the old
+translation and mark it as fuzzy. (In the worst case you will lose the translation
+completely, depending on the size of the text changes). This works OK, if
+a <acronym>msgid</acronym> is short, because then you can find
+the changes quickly. But if the text is long enough, you will struggle to find out
+what has been changed (For example, it can be only an article change by proof-reading team.)
+</para>
+<para>
+To help, &kbabel; can be asked to lookup the original <acronym>msgid</acronym>
+and to show the difference. The changes are graphically displayed in
+the <guilabel>Original String</guilabel> window. The exact method can
+be set in the <link linkend="preferences-editor-appearance">&kbabel;
+configuration dialog</link>. <menuchoice><guimenu>Tools</guimenu>
+<guisubmenu>Diff</guisubmenu> <guimenuitem>Show Diff</guimenuitem>
+</menuchoice> will show the differences found. To see the current text
+without the mixture of original text and differences, use <menuchoice><guimenu>Tools</guimenu>
+<guisubmenu>Diff</guisubmenu> <guimenuitem>Show Original Text</guimenuitem>
+</menuchoice>.
+</para>
+<para>
+You can turn automatic lookup of difference on and off by choosing
+<menuchoice><guimenu>Tools</guimenu>
+<guisubmenu>Diff</guisubmenu> <guimenuitem>Diff Mode</guimenuitem>
+</menuchoice>. When the diff mode is on, difference searching starts when you
+go to another message.
+</para>
+<para>
+As always, you can use different sources for finding the old version of the
+text, all being set in in <link linkend="preferences-diffmode">&kbabel; configuration dialog</link>:
+</para>
+<variablelist>
+ <varlistentry>
+ <term>Translation Database</term>
+ <listitem>
+ <para>
+ You can use Translation Database for difference lookup.
+ We strongly recommend to turn on the automatic storing of the newly translated messages
+ into Translation Database in <link linkend="database-fill">
+ Translation Database configuration dialog</link>.
+ This mode can be turned on by <guilabel>Use messages from Translation
+ Database</guilabel>.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>Tree of the old files</term>
+ <listitem>
+ <para>
+ This will be used only if searching in Translation Database is turned off.
+ By setting <guilabel>Base folder for diff files</guilabel> you can
+ navigate &kbabel;, which file to use for difference.
+ It takes the relative path of the opened file and uses this relative
+ path in the folder specified here. If there is a corresponding file, it will
+ be used. To use this mode, you should make a copy of
+ old files before each update.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>Manually chosen file</term>
+ <listitem>
+ <para>
+ If the previous possibility does not work, correctly, you can always
+ set the difference file manually by choosing <menuchoice>
+ <guimenu>Tools</guimenu><guisubmenu>Diff</guisubmenu>
+ <guimenuitem>Open File for Diff</guimenuitem></menuchoice>.
+ </para>
+ </listitem>
+ </varlistentry>
+</variablelist>
+<note>
+<para>
+The difference lookup is not always accurate, because the
+<acronym>PO</acronym>-file does not contain any reference to the original
+message.
+</para>
+</note>
+</sect2>
+
+</sect1>
+
+<sect1 id="kbabel-pluralforms">
+<title>Plural Forms</title>
+<para>
+Because plural forms are quite a complicated issue, we devote a special section
+for their support in &kbabel;.
+</para>
+
+<note><para>
+This section handles about &kde; plural forms (to be precise of &kde; version 3).
+From &kbabel; version 1.11 (KDE 3.5) on, &kbabel; should be able to
+read, edit and save the &GNU; gettext plural forms too.
+</para></note>
+
+<para>
+Every language to which &kde; is translated must have set a correct
+number of plural forms. This is done by translating a specific entry in <filename>kdelibs.po</filename>.
+The number is set by selecting the name of a language, which uses
+the same number and <emphasis>rules</emphasis> for finding the
+right plural form. The up-to-date list of possible values can be found in the
+kdelibs source code, in the file <filename>kdecore/klocale.cpp</filename>.
+</para>
+
+<note><para>
+&GNU; gettext allows to define the number and type of plural forms by a formula and to set this
+formula independently for each PO file. &kde; can only define the number and type of plural forms
+one time in kdelibs.
+</para></note>
+
+<para>
+&kde; plural forms are denoted by comment <userinput>_n:</userinput> (including a trailing space) containing
+the <literal>%n</literal> argument. This argument is then used in the message
+itself and it controls which plural form of your language should be used
+depending on the rules for your language.
+</para>
+<para>
+The translation of a plural form message has to have a special format.
+It must contain the correct number of translations (one for each plural form)
+separated by an end of the line <literal>\n</literal>,
+<emphasis>without</emphasis> any <userinput>_n:</userinput> sequence (without the space either). For example,
+<quote>_n: Selected 1 file\nSelected %n files</quote> translated to Slovak would be:
+</para>
+<programlisting>
+Vybraný %n súbor\n
+Vybrané %n súbory\n
+Vybraných %n súborov
+</programlisting>
+<para>
+To check if your translation contains the correct number of
+plural forms, use the <menuchoice><guimenu>Tools</guimenu> <guisubmenu>Validation
+</guisubmenu> <guimenuitem>Check Plural Forms (KDE only)</guimenuitem>
+</menuchoice> menu.
+</para>
+</sect1>
+</chapter>
+
+<!--
+Local Variables:
+mode: xml
+sgml-minimize-attributes:nil
+sgml-general-insert-case:lower
+sgml-indent-step:0
+sgml-indent-data:nil
+End:
+
+vim:tabstop=2:shiftwidth=2:expandtab
+-->
diff --git a/doc/kbugbuster/Makefile.am b/doc/kbugbuster/Makefile.am
new file mode 100644
index 00000000..085981d9
--- /dev/null
+++ b/doc/kbugbuster/Makefile.am
@@ -0,0 +1,4 @@
+
+KDE_LANG = en
+KDE_DOCS = AUTO
+
diff --git a/doc/kbugbuster/index.docbook b/doc/kbugbuster/index.docbook
new file mode 100644
index 00000000..ed3acbb9
--- /dev/null
+++ b/doc/kbugbuster/index.docbook
@@ -0,0 +1,78 @@
+<?xml version="1.0" ?>
+<!DOCTYPE book PUBLIC "-//KDE//DTD DocBook XML V4.2-Based Variant V1.1//EN" "dtd/kdex.dtd" [
+ <!ENTITY kappname "&kbugbuster;">
+ <!ENTITY package "kdesdk">
+ <!ENTITY % addindex "IGNORE">
+ <!ENTITY % English "INCLUDE">
+]>
+
+<book lang="&language;">
+
+<bookinfo>
+<title>The &kbugbuster; Handbook</title>
+
+<authorgroup>
+<author>
+<firstname></firstname>
+<othername></othername>
+<surname></surname>
+<affiliation>
+<address><email></email></address>
+</affiliation>
+</author>
+<!-- TRANS:ROLES_OF_TRANSLATORS -->
+</authorgroup>
+
+<legalnotice>&FDLNotice;</legalnotice>
+
+<!-- Date and version information of the documentation
+Don't forget to include this last date and this last revision number, we
+need them for translation coordination !
+Please respect the format of the date (DD/MM/YYYY) and of the version
+(Major.minor.lesser), it could be used by automation scripts -->
+
+<date>2002-03-31</date>
+<releaseinfo>0.00.00</releaseinfo>
+
+<!-- Abstract about this handbook -->
+
+<abstract>
+<para>
+&kbugbuster; is part of the kdesdk package.
+</para>
+</abstract>
+
+
+<keywordset>
+<keyword>KDE</keyword>
+<keyword>kbugbuster</keyword>
+</keywordset>
+
+</bookinfo>
+
+<chapter id="introduction"> <title>Introduction</title> <para>
+The documentation for &kappname; was not finished when &kde; was installed on
+this computer.</para> <para>If you need help, please check <ulink
+url="http://www.kde.org">The &kde; Website</ulink> for updates, or by
+submitting your question to <ulink url="mailto:kde@kde.org">The
+&kde; User Mailing list</ulink>.</para> <para><emphasis>The &kde;
+Team</emphasis></para>
+
+&underFDL;
+
+</chapter>
+
+&documentation.index;
+</book>
+
+<!--
+Local Variables:
+mode: sgml
+sgml-minimize-attributes:nil
+sgml-general-insert-case:lower
+sgml-indent-step:0
+sgml-indent-data:nil
+End:
+
+// vim:ts=2:sw=2:tw=78:noet
+-->
diff --git a/doc/kcachegrind/Makefile.am b/doc/kcachegrind/Makefile.am
new file mode 100644
index 00000000..e748f2a2
--- /dev/null
+++ b/doc/kcachegrind/Makefile.am
@@ -0,0 +1,4 @@
+KDE_LANG = en
+KDE_DOCS = AUTO
+
+
diff --git a/doc/kcachegrind/index.docbook b/doc/kcachegrind/index.docbook
new file mode 100644
index 00000000..31cf322c
--- /dev/null
+++ b/doc/kcachegrind/index.docbook
@@ -0,0 +1,962 @@
+<?xml version="1.0" ?>
+<!DOCTYPE book PUBLIC "-//KDE//DTD DocBook XML V4.2-Based Variant V1.1//EN" "dtd/kdex.dtd" [
+ <!ENTITY kcachegrind '<application>KCachegrind</application>'>
+ <!ENTITY cachegrind "<application>Cachegrind</application>">
+ <!ENTITY calltree "<application>Calltree</application>">
+ <!ENTITY callgrind "<application>Callgrind</application>">
+ <!ENTITY valgrind "<application>Valgrind</application>">
+ <!ENTITY oprofile "<application>OProfile</application>">
+ <!ENTITY kappname "&kcachegrind;">
+ <!ENTITY package "kdesdk">
+ <!ENTITY % addindex "IGNORE">
+ <!ENTITY % English "INCLUDE">
+]>
+
+<!-- ................................................................ -->
+
+<book lang="&language;">
+
+<bookinfo>
+<title>The &kcachegrind; Handbook</title>
+
+<authorgroup>
+<author>
+<firstname>Josef</firstname>
+<surname>Weidendorfer</surname>
+<affiliation>
+<address><email>Josef.Weidendorfer@gmx.de</email></address>
+</affiliation>
+</author>
+
+<!-- TRANS:ROLES_OF_TRANSLATORS -->
+
+</authorgroup>
+
+<copyright>
+<year>2002-2004</year>
+<holder>Josef Weidendorfer</holder>
+</copyright>
+<legalnotice>&FDLNotice;</legalnotice>
+
+<date>2004-07-27</date>
+<releaseinfo>0.4.6</releaseinfo>
+
+<abstract>
+<para>
+&kcachegrind; is a profile data visualization tool, written using the &kde; environment.
+</para>
+</abstract>
+
+<keywordset>
+<keyword>KDE</keyword>
+<keyword>kdesdk</keyword>
+<keyword>Cachegrind</keyword>
+<keyword>Callgrind</keyword>
+<keyword>Valgrind</keyword>
+<keyword>Profiling</keyword>
+</keywordset>
+
+</bookinfo>
+
+
+<chapter id="introduction">
+<title>Introduction</title>
+
+<para>
+&kappname; is a browser for data produced by profiling tools.
+This chapter explains what profiling is for, how it is done, and
+gives some examples of profiling tools available.
+</para>
+
+<sect1 id="introduction-profiling">
+<title>Profiling</title>
+
+<para>
+When developing a program, one of the last steps often involves
+performance optimizations. As it makes no sense to optimize
+functions rarely used, because that would be a waste
+of time, one needs to know in
+which part of a program most of the time is spent.
+</para>
+
+<para>
+For sequential code, collecting statistical data of the programs
+runtime characteristic like time
+numbers spent in functions and code lines usually is enough.
+This is called Profiling. The program is run under control of a profiling tool, which gives the summary of an execution run at the end.
+In contrast, for parallel code, performance problems typically are caused when one processor is waiting for data from another. As this waiting time usually can not easily attributed, here it is better to generate timestamped event traces. KCachegrind can not visualize this kind of data.
+</para>
+
+<para>
+After analyzing the produced profile data, it should be easy
+to see the hot spots and bottlenecks of the code: for example, assumptions
+about call counts can be checked, and identified code regions can be optimized.
+Afterwards, the success of the optimization should be verified with another profile run.
+</para>
+</sect1>
+
+<sect1 id="introduction-methods">
+<title>Profiling Methods</title>
+
+<para>To exactly measure the time passed or record the events happening during the execution of a code region (e.g. a function), additional measurement code needs to be inserted before and after the given region. This code reads the time, or a global event count, and calculates differences. Thus, the original code has to be changed before execution. This is called instrumentation. Instrumentation can be done by the programmer itself, the compiler, or by the runtime system. As interesting regions usually are nested, the overhead of measurement always influences the measurement itself. Thus, instrumentation should be done selectively and results have to be interpreted with care. Of course, this makes performance analysis by exact measurement a very complex process.</para>
+
+<para>Exact measurement is possible because of hardware counters (including counters incrementing on a time tick) provided in modern processors, which are incremented whenever an event is happening. As we want to attribute events to code regions, without the counters, we would have to handle every event by incrementing a counter for the current code region ourself. Doing this in software is, of course, not possible; but, on the assumption that the event distribution over source code is similar when looking only at every n-th event instead of every event, a measurement method whose overhead is tunable has been developed: it is called Sampling. Time Based Sampling (TBS) uses a timer to regularly look at the program counter to create a histogram over the program code. Event Based Sampling (EBS) exploits the hardware counters of modern processors, and uses a mode where an interrupt handler is called on counter underflow to generate a histogram of the corresponding event distribution: in the handler, the event counter is always reinitialized to the 'n' of the sampling method. The advantage of sampling
+is that the code does not have to be changed, but it is still a compromise: the above assumption will be more correct if n is small, but the smaller the n, the higher the overhead of the interrupt handler.</para>
+
+<para>Another measurement method is to simulate things happening in the computer system when executing a given code, i.e. execution driven simulation. The simulation is always derived from a more or less accurate machine model; however, with very detailed machine models, giving very close approximations to reality, the simulation time can be unacceptably high in practice. The advantage of simulation is that arbitrarily complex measurement/simulation code can be inserted in a given code without perturbing results. Doing this directly before execution (called runtime instrumentation), using the original binary, is very comfortable for the user: no re-compilation is necessary. Simulation becomes usable when simulating only parts of a machine with a simple model; another advantage is that the results produced by simple models are often easier to understand: often, the problem with real hardware is that results include overlapping effects from different parts of the machine.</para>
+</sect1>
+
+<sect1 id="introduction-tools">
+<title>Profiling Tools</title>
+
+<para>
+Most known is the GCC profiling tool <application>gprof</application>:
+One needs to compile the program with option <option>-pg</option>;
+running the program generates a file <filename>gmon.out</filename>,
+which can be transformed into human-readable form with
+<command>gprof</command>. One disadvantage is the needed re-compilation
+step to prepare the executable, which has to be statically linked.
+The method used here is compiler-generated instrumention - which measures call arcs happening among functions and corresponding call counts - in conjunction with TBS - which gives a histogram of time distribution over the code. Using both pieces of information, it is possible to heuristically calculate inclusive time of functions, i.e. time spent in a function together with all functions called from it.
+</para>
+
+<para>For exact measurement of events happening, libraries exist with functions able to read out hardware performance counters. Most known here is the PerfCtr patch for Linux, and the architecture independent libraries PAPI and PCL. Still, exact measurement needs instrumentation of code, as stated above. Either one uses the libraries itself or uses automatic instrumentation systems like ADAPTOR (for FORTRAN source instrumentation) or DynaProf (code injection via DynInst).</para>
+
+<para>&oprofile; is a system-wide profiling tool for Linux using Sampling.</para>
+
+<para>
+In many aspects, a comfortable way of Profiling is using
+Cachegrind or Callgrind, which are simulators using the runtime
+instrumentation framework &valgrind;. Because there is no need
+to access hardware counters (often difficult with today's Linux installations), and binaries to be profiled can be left unmodified,
+it is a good alternative to other profiling tools.
+The disadvantage of simulation - slowdown - can be reduced by doing the simulation on only the interesting program parts, and perhaps only on a few iterations of a loop. Without measurement/simulation instrumentation, Valgrind's usage only has a slowdown factor in the range of 3 to 5.
+Also, when only the call graph and call counts
+are of interest, the cache simulator can be switched off.
+</para>
+
+<para>
+Cache simulation is the first step in approximating real times; as
+,on modern systems, runtime is very sensitive to the exploitation
+of so called caches (small and fast buffers which accelerate repeated
+accesses to the same main memory cells.)
+&cachegrind; does cache simulation by catching
+memory accesses.
+The data produced
+includes the number of instruction/data memory accesses and 1st/2nd
+level cache misses, and relates it to source lines and functions of
+the run program. By combining these miss counts, using miss latencies from typical processors, an estimation of spent time can be given.
+</para>
+
+<para>Callgrind is an extension of &cachegrind; that
+builds up the call graph of a program on-the-fly,
+&ie; how the functions call each other and how many events happen
+while running a function. Also, the profile data to be collected
+can separated by threads and call chain contexts. It can provide
+profiling data on an instruction level to allow for annotation of
+disassembled code.
+</para>
+</sect1>
+
+<sect1 id="introduction-visualization">
+<title>Visualization</title>
+
+<para>
+Profiling tools typically produce a large amount of data. The wish
+to easily browse down and up the call graph, together with fast switching of the sorting mode of functions and display of different event types, motivates a GUI application to accomplish this task.
+</para>
+
+<para>
+&kappname; is an visualization for profile data fulfilling these wishes. Despite being programmed first with browsing the data from &cachegrind; and &calltree; in mind, there are converters available to be able to display profile data produced by other tools. In the appendix, a description of the Cachegrind/Callgrind file format is given.
+</para>
+
+<para>
+Besides a list of functions sorted according exclusive or inclusive cost metrics, and optionally grouped by source file, shared library or C++ class,
+&kappname; features various visualization views for a selected function, namely
+
+<itemizedlist>
+<listitem><para>a call-graph view, which shows a section of the call graph around the selected function,</para>
+</listitem>
+<listitem><para>a tree-map view, which allows nested-call relations to be visualized, together with inclusive cost metric for fast visual detection of problematic functions,</para>
+</listitem>
+<listitem><para>source code and disassembler annotation views, allowing to see details of cost related to source lines and assembler instructions.</para>
+</listitem>
+</itemizedlist>
+
+</para>
+</sect1>
+</chapter>
+
+<chapter id="using-kcachegrind">
+<title>Using &kcachegrind;</title>
+
+<sect1 id="using-profile">
+<title>Generate Data to Visualize</title>
+
+<para>First, one wants to generate performance data by measuring aspects of the
+runtime characteristics of an application, using a profiling tool. &kcachegrind;
+itself does not include any profiling tool, but is good in being used together with
+&callgrind;, and by using a converter, also can be used to visualize data produced
+with &oprofile;. Although the scope of this manual is not to document profiling
+with these tools, the next section provides short quickstart tutorials to get you started.
+</para>
+
+<sect2>
+<title>&callgrind;</title>
+
+<para>
+&callgrind; is available from
+<ulink url="http://kcachegrind.sf.net">
+http://kcachegrind.sf.net</ulink>.
+Note that it previously was called &calltree;, but that name was misleading.
+</para>
+
+<para>
+Most common use is to prefix the command line to start your application with
+<application>callgrind</application>, like in
+
+<blockquote><para><command>callgrind myprogram myargs</command></para></blockquote>
+
+At program termination, a file <filename>callgrind.out.pid</filename> will be
+generated which can be loaded into &kcachegrind;.
+</para>
+
+<para>
+More advanced use is to dump out profile data whenever a given function of
+your application is called. E.g. for <command>konqueror</command>,
+to see profile data only
+for rendering a web page, you could decide to dump the data whenever you
+select the menu item View/Reload. This corresponds to a call to
+<symbol>KonqMainWindow::slotReload</symbol>. Use
+
+<blockquote><para><command>
+callgrind --dump-before=KonqMainWindow::slotReload konqueror </command></para></blockquote>
+
+This will produce multiple profile data files with an additional
+sequential number at the end of the filename. A file without such an
+number at the end (only ending in the process PID) will also be produced;
+by loading this file into &kcachegrind;, all others are loaded too, and can
+be seen in the Parts Overview and Parts list.
+</para>
+
+</sect2>
+
+<sect2>
+<title>&oprofile;</title>
+
+<para>
+&oprofile; is available from
+<ulink url="http://oprofile.sf.net">
+http://oprofile.sf.net</ulink>. Follow the installation instructions on the web site;
+but, before you do, check if your distribution does not already provide it as package (like SuSE).
+</para>
+
+<para>
+System-wide profiling is only permitted to the root user,
+as all actions on the system can be observed; therefore, the following has to be done as root.
+First, configure the profiling process, using the GUI <command>oprof_start</command> or the
+command-line tool opcontrol. Standard configuration should be timer mode (TBS, see introduction). To start the measurement, run
+<command>opcontrol -s</command>. Then run the application you are interested in and, afterwards, do a <command>opcontrol -d</command>. This will write out
+the measurement results into files under directory <filename>/var/lib/oprofile/samples/</filename>. To be able to visualize the data in &kcachegrind;, do in an empty directory:
+
+<blockquote><para><command>
+opreport -gdf | op2callgrind
+</command></para></blockquote>
+
+This will produce a lot of files, one for every program which was running
+on the system. Each one can be loaded into &kcachegrind; on its own.
+</para>
+
+</sect2>
+</sect1>
+
+<sect1 id="using-basics">
+<title>User Interface Basics</title>
+
+<para>
+When starting &kcachegrind; with a profile data file as argument, or after loading one with File/Open, you will see a sidebar containing the function list
+at the left; and, on the right the main part, an area with visualizations for
+a selected function. This visualization area can be arbitrarily configured to
+show multiple visualizations at once.
+</para>
+
+<para>
+At first start, this area will be
+divided into a top and a bottom part, each with different visualizations
+selectable by tabs. To move visualization views, use the context menu of
+the tabs, and adjust the splitters between visualizations. To quickly switch
+between different visualization layouts, use View/Layouts/Duplicate, change
+the layout and switch between layouts with View/Layout/Next (or, even better,
+use the corresponding keyboard shortcuts).
+</para>
+
+<para>
+The active event type is important for visualization: for &callgrind;, this
+is, for example, Cache Misses or Cycle Estimation; for &oprofile;, this is "Timer" in the simplest case. You can change the event type via a combobox in the toolbar or in the Event Type view.
+A first overview of the runtime characteristics should be given when you select function <symbol>main</symbol> in the left list, and look at the call graph visualization; there, you see calls happening in your program. Note that the call graph view only shows functions with high event count. By double-clicking a function in the graph, it will change to show the called functions around the selected one.
+</para>
+
+<para>
+To explore the GUI further, in addition to this manual, also have a look at the documentation section on the web site
+<ulink url="http://kcachegrind.sf.net">
+http://kcachegrind.sf.net</ulink>.
+Also,
+every widget in &kcachegrind; has <quote>What's this</quote> help.
+</para>
+</sect1>
+
+</chapter>
+
+
+<chapter id="kcachegrind-concepts">
+<title>Basic Concepts</title>
+
+<para>This chapter explains some concepts of the &kcachegrind;, and
+introduces terms used in the interface.
+</para>
+
+<sect1 id="concepts-model">
+<title>The Data Model for Profile Data</title>
+
+<sect2>
+<title>Cost Entities</title>
+
+<para>
+Cost counts of event types (like L2 Misses) are attributed to cost entities, which are items with relationship to source code or data structures of a given program. Cost entities not only can be simple code or data positions, but also position tuples. For example, a call has a source and a target, or a data address can have a data type and an code position where its allocation happened.
+</para>
+
+<para>
+The cost entities known to KCachegrind are given in the following.
+Simple Positions:
+<itemizedlist>
+<listitem><para>
+Instruction. An assembler instruction at a specified address.
+</para></listitem>
+<listitem><para>
+Source Line of a Function.
+All instructions that the compiler (via debug information) maps to a given source line specified by source file name and line number, and which are executed in the context of some function. The latter is needed because a source line inside of an inlined function can appear in the context of multiple functions. Instructions without any mapping to an actual source line are mapped to line number 0 in file "???".
+</para></listitem>
+<listitem><para>
+Function.
+All source lines of a given function make up the function itself. A function is specified by its name and its location in some binary object if available. The latter is needed because binary objects of a single program each can hold functions with the same name (these can be accessed e.g. with dlopen/dlsym; the runtime linker resolves functions in a given search order of binary objects used). If a profiling tool can not detect the symbol name of a function, e.g. because debug information is not available, either the address of the first executed instruction typically is used, or "???".
+</para></listitem>
+<listitem><para>
+Binary Object.
+All functions whose code is inside the range of a given binary object, either the main executable or a shared library.
+</para></listitem>
+<listitem><para>
+Source File.
+All functions whose first instruction is mapped to a line of the given source file.
+</para></listitem>
+<listitem><para>
+Class.
+Symbol names of functions typically are hierarchically ordered in name spaces, e.g. C++ namespaces, or classes of object oriented languages; thus, a class can hold functions of the class or embedded classes itself.
+</para></listitem>
+<listitem><para>
+Profile Part.
+Some time section of a profile run, with a given thread ID, process ID, and command line executed.
+</para></listitem>
+</itemizedlist>
+
+As can be seen from the list, a set of cost entities often defines another cost entity; thus, there is a inclusion hierarchy of cost entities which should be obvious from the description above.
+</para>
+
+<para>
+Positions tuples:
+<itemizedlist>
+<listitem><para>
+Call from instruction address to target function.
+</para></listitem>
+<listitem><para>
+Call from source line to target function.
+</para></listitem>
+<listitem><para>
+Call from source function to target function.
+</para></listitem>
+<listitem><para>
+(Un)conditional Jump from source to target instruction.
+</para></listitem>
+<listitem><para>
+(Un)conditional Jump from source to target line.
+</para></listitem>
+</itemizedlist>
+
+Jumps between functions are not allowed, as this makes no sense in a call graph; thus, constructs like exception handling and long jumps in C have to be translated to popping the call stack as needed.
+</para>
+
+</sect2>
+
+
+
+<sect2>
+<title>Event Types</title>
+
+<para>
+Arbitrary event types can be specified in the profile data by giving them a name. Their cost related to a cost entity is a 64-bit integer.
+</para>
+<para>
+Event types whose costs are specified in a profile data file are called real events. Additionally, one can specify formulas for event types calculated from real events, which are called inherited events.
+</para>
+</sect2>
+
+</sect1>
+
+<sect1 id="concepts-state">
+<title>Visualization State</title>
+
+<para>
+The Visualization state of a KCachegrind window includes:
+<itemizedlist>
+<listitem><para>
+the primary and secondary event type chosen for display,
+</para></listitem>
+<listitem><para>
+the function grouping (used in the Function Profile list and entity coloring),
+</para></listitem>
+<listitem><para>
+the profile parts whose costs are to be included in visualization,
+</para></listitem>
+<listitem><para>
+an active cost entity (e.g. a function selected from the function profile dockable),
+</para></listitem>
+<listitem><para>
+a selected cost entity.
+</para></listitem>
+</itemizedlist>
+
+This state influences visualizations.
+</para>
+<para>
+Visualizations always are shown for one, the active, cost entity. When a given visualization is not appropriate for a cost entity, it is disabled (e.g. when selecting an ELF object in the group list by double-clicking, source annotation for an ELF object make no sense).
+</para>
+<para>
+For example, for an active function, the callee list shows all the functions called from the active one: one can select one of these functions without making it active; also, if the call-graph is shown nearside, it will automatically select the same function.
+</para>
+
+</sect1>
+
+<sect1 id="concepts-guiparts">
+<title>Parts of the GUI</title>
+
+<sect2>
+<title>Sidedocks</title>
+<para>
+Sidedocks (Dockables) are side windows which can be placed at any border of an KCachegrind window. They always contain a list of cost entities sorted in some manner.
+<itemizedlist>
+<listitem><para>
+Function Profile.
+The Function Profile is a list of functions showing inclusive and exclusive cost, call count, name and position of functions.
+</para></listitem>
+<listitem><para>
+Parts Overview
+</para></listitem>
+<listitem><para>
+Call Stack
+</para></listitem>
+</itemizedlist>
+</para>
+</sect2>
+
+<sect2>
+<title>Visualization Area</title>
+<para>
+The visualization area, typically the right part of a KCachegrind main window, is made up of one (default) or more Tab Views, either lined up horizontally or vertically. Each tab view holds different visualization views of only one cost entity at a time. The name of this entity is given at the top of the tab view. If there are multiple tab views, only one is active. The entity name in the active tab view is shown in bold and determines the active cost entity of the KCachegrind window.
+</para>
+</sect2>
+
+<sect2>
+<title>Areas of a Tab View</title>
+<para>
+Each tab view can hold up to four view areas, namely Top, Right, Left, and Bottom. Each area can hold multiple stacked visualization views. The visible view of an area is selected by a tab bar. The tab bars of the top and right area are at the top; the tab bars of the left and bottom area are at the bottom. You can specify which kind of visualization should go into which area by using the context menus of the tabs.
+</para>
+</sect2>
+
+<sect2>
+<title>Synchronized Visualization via Selected Entity in a Tab View</title>
+<para>
+Besides an active entity, each tab view has an selected entity. As most visualization types show multiple entities with the active one somehow centered, you can change the selected item by navigating inside a visualization (by clicking with the mouse or using the keyboard). Typically, selected items are shown in an highlighted state. By changing the selected entity in one of the visualizations of a tab view, all other visualizations in the tab view accordingly highlight the new selected entity.
+</para>
+</sect2>
+
+<sect2>
+<title>Synchronization between Tab Views</title>
+<para>
+If there are multiple tab views, a selection change in one tab view leads to an activation change in the next (to right/to bottom) tab view. This kind of linkage should, for example, allow for fast browsing in call graphs.
+</para>
+</sect2>
+
+<sect2>
+<title>Layouts</title>
+<para>
+The layout of all the tab views of a window can be saved (see menu item View/Layout). After duplicating the current layout (Ctrl+Plus or menu) and changing some sizes or moving a visualization view to another area of an tab view, you can quickly switch between the old and the new layout via Ctrl+Left/Right. The set of layouts will be stored between KCachegrind sessions of the same profiled command. You can make the current set of layouts as the default one for new KCachegrind sessions, or restore to the default layout set.
+</para>
+</sect2>
+</sect1>
+
+<sect1 id="concepts-sidedocks">
+<title>Sidedocks</title>
+
+<sect2>
+<title>Flat Profile</title>
+<para>
+The flat profile contains a group list and a function list. The group list contains all groups where cost is spent in, depending on the chosen group type. The group list is hidden when grouping is switched off.
+</para>
+<para>
+The function list contains the functions of the selected group (or all functions if grouping is switched off), ordered by some column, e.g. inclusive or self costs spent therein. There is a maximal number of functions shown in the list, which is configurable in Settings/Configure KCachegrind.
+</para>
+</sect2>
+
+<sect2>
+<title>Parts Overview</title>
+<para>
+In a profile run, multiple profile data files can be produced, which can be loaded together into KCachegrind. The Parts Overview dockable shows these, horizontally ordered according creation time; the rectangle sizes are proportional to the cost spent in the parts. You can select one or several parts to constrain the costs shown in the other KCachegrind views to these parts only.
+</para>
+<para>
+The parts are further subdivided: there is a partitioning and an inclusive cost split mode:
+<itemizedlist>
+<listitem><para>
+Partitioning: You see the partitioning into groups for a profile data part, according to the group type selected. For example, if ELF object groups are selected, you see colored rectangles for each used ELF object (shared library or executable), sized according to the cost spent therein.
+</para></listitem>
+<listitem><para>
+Inclusive Cost Split: A rectangle showing the inclusive cost of the current active function in the part is shown. This, again, is split up to show inclusive costs of its callees.
+</para></listitem>
+</itemizedlist>
+</para>
+</sect2>
+
+<sect2>
+<title>Call Stack</title>
+<para>
+This is a purely fictional 'most probable' call stack. It is built up by starting with the current active function and adds the callers/callees with highest cost at the top and to bottom.
+</para>
+<para>
+The 'Cost' and 'Calls' columns show the cost used for all calls from the function in the line above.
+</para>
+</sect2>
+</sect1>
+
+<sect1 id="concepts-visualizations">
+<title>Visualizations</title>
+
+<sect2>
+<title>Event Types</title>
+<para>
+This list shows all cost types available and the corresponding self and inclusive cost of the current active function for that event type.
+</para>
+<para>
+By choosing an event type from the list, you change the type of costs shown all over KCachegrind to be the selected one.
+</para>
+</sect2>
+
+<sect2>
+<title>Call Lists</title>
+<para>
+These lists show calls to/from the current active function. With ''all' callers/callees functions are meant which can be reached in caller/callee direction, even when other functions are in between.
+</para>
+<para>
+Call list views include:
+<itemizedlist>
+<listitem><para>
+Direct Callers
+</para></listitem>
+<listitem><para>
+Direct Callees
+</para></listitem>
+<listitem><para>
+All Callers
+</para></listitem>
+<listitem><para>
+All Callees
+</para></listitem>
+</itemizedlist>
+</para>
+</sect2>
+
+<sect2>
+<title>Maps</title>
+<para>
+A treemap visualization of the primary event type, up or down the call hierarchy. Each colored rectangle represents a function; its size tries to be proportional to the cost spent therein while the active function is running (however, there are drawing constrains).
+</para>
+<para>
+For the Caller Map, the graph shows the nested hierarchy of all callers of the current activated function; for the Callee Map, it shows the nested hierarchy of all callees of the current activated function.
+</para>
+<para>
+Appearance options can be found in the in the context menu. To get exact size proportions, choose 'Hide incorrect borders'. As this mode can be very time consuming, you may want to limit the maximum drawn nesting level before. 'Best' determinates the split direction for children from the aspect ratio of the parent. 'Always Best' decides on remaining space for each sibling. 'Ignore Proportions' takes space for function name drawing before drawing children. Note that size proportions can get heavily wrong.
+</para>
+<para>
+Keyboard navigation is available with the left/right arrow keys for traversing siblings, and up/down arrow keys to go a nesting level up/down. 'Return' activates the current item.
+</para>
+</sect2>
+
+<sect2>
+<title>Call Graph</title>
+<para>
+This view shows the call graph around the active function.
+The shown cost is only the cost which is spent while the active function was actually running; i.e. the cost shown for main() - if it's visible - should be the same as the cost of the active function, as that is the part of inclusive cost of main() spent while the active function was running.
+</para>
+<para>
+For cycles, blue call arrows indicate that this is an artificial call added for correct drawing which actually never happened.
+</para>
+<para>
+If the graph is larger than the widget area, a bird's eye view is shown in one edge. There are similar visualization options as for the Call Treemap; the selected function is highlighted.
+</para>
+</sect2>
+
+<sect2>
+<title>Annotations</title>
+<para>
+The annotated source/assembler lists show the source lines/disassembled instructions of the current active function together with (self) cost spent while executing the code of a source line/instruction. If there was a call, lines with details on the call are inserted into the source: the (inclusive) cost spent inside of the call, the number of calls happening, and the call destination.
+</para>
+<para>
+Select such a call information line to activate the call destination.
+</para>
+</sect2>
+</sect1>
+
+</chapter>
+
+
+<chapter id="commands">
+<title>Command Reference</title>
+
+<sect1 id="kcachegrind-mainwindow">
+<title>The main &kcachegrind; window</title>
+<para></para>
+
+<sect2>
+<title>The <guimenu>File</guimenu> Menu</title>
+<para>
+<variablelist>
+
+<varlistentry>
+<term><menuchoice>
+<shortcut>
+<keycombo>&Ctrl;<keycap>N</keycap></keycombo>
+</shortcut>
+<guimenu>File</guimenu>
+<guimenuitem>New</guimenuitem>
+</menuchoice></term>
+<listitem><para><action>
+Opens an empty toplevel window into which you can load profile data.
+</action>
+This action is not really needed, as File/Open will give you a new toplevel window when the current one shows already some data.
+</para></listitem>
+</varlistentry>
+
+<varlistentry>
+<term><menuchoice>
+<shortcut>
+<keycombo>&Ctrl;<keycap>O</keycap></keycombo>
+</shortcut>
+<guimenu>File</guimenu>
+<guimenuitem>Open</guimenuitem>
+</menuchoice></term>
+<listitem><para><action>
+Pops up the File Open Dialog to choose a profile data file to be loaded.
+</action>
+If there is some data already shown in the current toplevel window, this will open a new window; if you want to open additional profile data in the current window, use File/Add.
+</para>
+<para>
+The name of profile data files usually ends in ..-, where and are optional and are used for multiple profile data files belonging to one application run. By loading a file ending only in ., eventually existing data files for this run, but with additional endings, are loaded too.
+</para>
+<para>
+Example: If there exist profile data files cachegrind.out.123 and cachegrind.out.123.1, by loading the first, the second will be automatically loaded too.
+</para></listitem>
+</varlistentry>
+
+<varlistentry>
+<term><menuchoice>
+<guimenu>File</guimenu>
+<guimenuitem>Add</guimenuitem>
+</menuchoice></term>
+<listitem><para><action>
+Adds a profile data file to the current window.
+</action>
+Using this, you can force multiple data files to be loaded into the same toplevel window even if they are not from the same run as given by the profile data file naming convention. This can, for example, be used for nearside comparison.
+</para></listitem>
+</varlistentry>
+
+<varlistentry>
+<term><menuchoice>
+<guimenu>File</guimenu>
+<guimenuitem>Reload</guimenuitem>
+</menuchoice></term>
+<listitem><para><action>
+Reload the profile data.
+</action>
+This is most interesting after another profile data file was generated for an already loaded application run.
+</para></listitem>
+</varlistentry>
+
+<varlistentry>
+<term><menuchoice>
+<shortcut>
+<keycombo>&Ctrl;<keycap>Q</keycap></keycombo>
+</shortcut>
+<guimenu>File</guimenu>
+<guimenuitem>Quit</guimenuitem>
+</menuchoice></term>
+<listitem><para><action>Quits</action> &kappname;</para></listitem>
+</varlistentry>
+</variablelist>
+</para>
+
+</sect2>
+
+<sect2>
+<title>The <guimenu>View</guimenu> Menu</title>
+<para>
+<variablelist>
+
+<varlistentry>
+<term><menuchoice>
+<guimenu>View</guimenu>
+<guimenuitem>Primary Event Type</guimenuitem>
+</menuchoice></term>
+<listitem><para><action>(To-do)</action></para></listitem>
+</varlistentry>
+
+<varlistentry>
+<term><menuchoice>
+<guimenu>View</guimenu>
+<guimenuitem>Secondary Event Type</guimenuitem>
+</menuchoice></term>
+<listitem><para><action>(To-do)</action></para></listitem>
+</varlistentry>
+
+<varlistentry>
+<term><menuchoice>
+<guimenu>View</guimenu>
+<guimenuitem>Grouping</guimenuitem>
+</menuchoice></term>
+<listitem><para><action>(To-do)</action></para></listitem>
+</varlistentry>
+
+<varlistentry>
+<term><menuchoice>
+<guimenu>View</guimenu>
+<guimenuitem>Layout</guimenuitem>
+</menuchoice></term>
+<listitem><para><action>(To-do)</action></para></listitem>
+</varlistentry>
+
+<varlistentry>
+<term><menuchoice>
+<guimenu>View</guimenu>
+<guimenuitem>Split</guimenuitem>
+</menuchoice></term>
+<listitem><para><action>(To-do)</action></para></listitem>
+</varlistentry>
+
+</variablelist>
+</para>
+
+</sect2>
+
+
+</sect1>
+</chapter>
+
+<chapter id="faq">
+<title>Questions and Answers</title>
+
+&reporting.bugs;
+&updating.documentation;
+
+<qandaset id="faqlist">
+
+
+<qandaentry>
+<question>
+<para>
+What is &kcachegrind; for? I have no idea.
+</para>
+</question>
+<answer>
+<para>
+&kcachegrind; is a helpful at a later stage in software development,
+called Profiling. If you don't develop applications, you don't need
+&kcachegrind;.
+</para>
+</answer>
+</qandaentry>
+
+<qandaentry>
+<question>
+<para>
+What is the difference between 'Incl.' and 'Self' ?
+</para>
+</question>
+<answer>
+<para>These are cost attributes for functions regarding some event type. As functions can call each other, it makes sense to distinguish the cost of the function itself ('Self Cost') and the cost including all called functions ('Inclusive Cost'). 'Self' is sometimes also referred to as 'Exclusive' costs.
+</para>
+<para>
+So, for example, for main(), you will always have a inclusive cost of almost 100%, whereas the self cost is negligible when the real work is done in another function.
+</para>
+</answer>
+</qandaentry>
+
+<qandaentry>
+<question>
+<para>The toolbar/menubar of my KCachegrind looks so spartanic. Is this normal?</para>
+</question>
+<answer>
+<para>
+Obviously KCachegrind is wrongly installed on your system. It is recommended to compile it with the installation prefix to be your system wide KDE base directory like <command>configure --prefix=/opt/kde3; make install</command>.
+If you choose another directory like $HOME/kde, you should set the environment variable KDEDIR to this directory before running KCachegrind.
+</para>
+</answer>
+</qandaentry>
+
+<qandaentry>
+<question>
+<para>
+If I double-click on a function down in the Call Graph View, it shows for the function main the same cost as the selected function. Isn't this supposed to be constant 100% ?
+</para>
+</question>
+<answer>
+<para>
+You have activated a function below main() with cost less than main(). For any function, only that part of the full cost of the function is shown, that is spent while the activated function is running; that is, the cost shown for any function can never be higher than the cost of the activated function.
+</para>
+</answer>
+</qandaentry>
+
+
+</qandaset>
+</chapter>
+
+<chapter id="glossary">
+<title>Glossary</title>
+
+<para>The following is a mixed list of terms.
+
+<itemizedlist>
+<listitem><para>
+Profiling: The process of collecting statistical information about runtime characteristics of program runs.
+</para></listitem>
+<listitem><para>
+Tracing: The process of supervising a program run and storing events happening sorted by a timestap in a output file, the Trace.
+</para></listitem>
+<listitem><para>
+Trace: A sequence of timestamped events that occurred while tracing a program run. Its size is typically linear to the execution time of the program run.
+</para></listitem>
+<listitem><para>
+Profile Data File: A file containing data measured in a profile experiment (or part of) or produced by postprocessing a trace. Its size is typically linear to the code size of the program.
+</para></listitem>
+<listitem><para>
+Profile Data Part (incorrectly used also: Trace Part): Data from a profile data file.
+</para></listitem>
+<listitem><para>
+Profile Experiment: A program run supervised by a profiling tool, producing possibly multiple profile data files from parts and/or threads of the run.
+</para></listitem>
+<listitem><para>
+Profile Project: A configuration for profile experiments used for one program which has to be profiled, perhaps in multiple versions. Comparisons of profile data typically only makes sense between profile data produced in experiments of one profile project.
+</para></listitem>
+<listitem><para>
+Cost Entity: An abstract item related to source code to which event counts can be attributed. Dimensions for cost entities are code location (e.g. source line, function), data location (e.g. accessed data type, data object), execution location (e.g. thread, process), and tuples or triples of the aforementioned positions (e.g. calls, object access from statement, evicted data from cache).
+</para></listitem>
+<listitem><para>
+Event Type: The kind of event of which costs can be attributed to a cost entity. There exist real event types and inherited event types.
+</para></listitem>
+<listitem><para>
+Real Event Type: A event type that can be measured by a tool. This needs the existence of a sensor for the given event type.
+</para></listitem>
+<listitem><para>
+Inherited Event Type: A virtual event type only visible in the visualization which is defined by a formula to be calculated from real event types.
+</para></listitem>
+<listitem><para>
+Event Costs: Sum of events of some event type occurring while the execution is related to some cost entity. The cost is attributed to the entity.
+</para></listitem>
+</itemizedlist>
+</para>
+</chapter>
+
+<chapter id="credits">
+
+
+<title>Credits and License</title>
+
+<para>
+&kappname;
+</para>
+<para>
+Thanks to Julian Seward for his excellent &valgrind;, and Nicholas
+Nethercote for the &cachegrind; addition. Without these programs,
+<application>KCachegrind</application> would not exist. Some ideas
+for this &GUI; were from them, too.
+</para>
+<para>
+And thanks for all the bug reports/suggestions from different
+users.
+</para>
+
+&underFDL; <!-- FDL License -->
+
+</chapter>
+
+<appendix id="installation">
+<title>Installation</title>
+
+<sect1 id="getting-kcachegrind">
+<title>How to obtain &kcachegrind;</title>
+
+<para>
+&kcachegrind; is part of the &package; package of &kde;. For less supported
+interim releases, &callgrind; and further documentation, see
+the homepage at
+<ulink url="http://kcachegrind.sf.net">
+http://kcachegrind.sf.net</ulink>. Look there for
+further installation and compile instructions.
+</para>
+</sect1>
+
+<sect1 id="requirements">
+<title>Requirements</title>
+
+<para>
+In order to successfully use &kcachegrind;, you need &kde; 3.x. For
+generating profile data, &cachegrind; or &calltree;/&callgrind; is recommend.
+</para>
+</sect1>
+
+<sect1 id="compilation">
+<title>Compilation and Installation</title>
+
+&install.compile.documentation;
+
+</sect1>
+
+<sect1 id="configuration">
+<title>Configuration</title>
+
+<para>All configuration options are either in the configuration dialog
+or in the context popup menus of the visualizations.
+</para>
+
+</sect1>
+
+</appendix>
+
+&documentation.index;
+</book>
+<!--
+Local Variables:
+mode: sgml
+sgml-minimize-attributes:nil
+sgml-general-insert-case:lower
+sgml-indent-step:0
+sgml-indent-data:nil
+End:
+-->
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/doc/kompare/Makefile.am b/doc/kompare/Makefile.am
new file mode 100644
index 00000000..085981d9
--- /dev/null
+++ b/doc/kompare/Makefile.am
@@ -0,0 +1,4 @@
+
+KDE_LANG = en
+KDE_DOCS = AUTO
+
diff --git a/doc/kompare/index.docbook b/doc/kompare/index.docbook
new file mode 100644
index 00000000..04f30a7f
--- /dev/null
+++ b/doc/kompare/index.docbook
@@ -0,0 +1,910 @@
+<?xml version="1.0" ?>
+<!DOCTYPE book PUBLIC "-//KDE//DTD DocBook XML V4.2-Based Variant V1.1//EN" "dtd/kdex.dtd" [
+ <!ENTITY kappname "&kompare;">
+ <!ENTITY version "3.4">
+ <!ENTITY package "kdesdk">
+ <!ENTITY % addindex "IGNORE">
+ <!ENTITY % English "INCLUDE">
+]>
+
+<book lang="&language;">
+
+<bookinfo>
+ <title>The &kompare; Handbook</title>
+
+ <authorgroup>
+
+<author><firstname>Sean</firstname><surname>Wheller</surname><email>sean@inwords.co.za</email></author>
+ <!-- TRANS:ROLES_OF_TRANSLATORS -->
+ </authorgroup>
+
+<copyright>
+<year>2007</year>
+<holder>Sean Wheller</holder>
+</copyright>
+
+ <legalnotice>&FDLNotice;</legalnotice>
+
+<date>2007-01-20</date>
+<releaseinfo>3.4</releaseinfo>
+
+<!-- Abstract about this handbook -->
+
+<abstract>
+<para>
+&kompare; is a &GUI; front-end program that enables differences between source files to be viewed and merged.
+&kompare; can be used to compare differences on files or the contents of folders. &kompare; supports a variety
+of diff formats and provide many options to customize the information level displayed.</para>
+<para>This document describes &kompare; version &version;.</para>
+</abstract>
+
+
+<keywordset>
+<keyword>KDE</keyword>
+<keyword>Kompare</keyword>
+<keyword>Diff</keyword>
+<keyword>Merge</keyword>
+<keyword>Patch</keyword>
+<keyword>Hunk</keyword>
+</keywordset>
+
+</bookinfo>
+
+<chapter id="introduction">
+<title>Introduction</title>
+
+<para>When two or more people are working on a file and passing it back and forth between one another, it becomes difficult to
+see what changes have been made to a new version or copy of the file. Opening the new copy and the original, side-by-side in the
+application used to create it is one solution but, laborious, time consuming, and prone to error. This is where a program to show
+differences, diffs for short, is useful.</para>
+
+<para>As would be expected, an appropriate name for such a program would be &quot;diff&quot;. As it happens, the program diff is installed on
+most &Linux;-based systems and is used for exactly this purpose. Developers often use diff, as a command line tool, to show differences
+between versions of a source code file. However, the use of diff is not limited to showing differences in code source files,
+it can be used on many text-based file types.</para>
+
+<para>Using diff from the command line can be confusing, learning the diff command syntax and deciphering the output can bewilder most people.
+This is where &kompare; comes into play. Providing a graphical front-end to the diff program, the interface displays source and destination files
+side-by-side with all differences automatically highlighted. From this starting point, changes in one file can be sequentially applied to the other file
+on a selective and controlled basis. Not all changes need to be applied and if you do apply a change it can always be &apos;unapplied&apos;.
+When all required changes have been applied they can be saved and will display as normal in the original application used to create the file.</para>
+
+<para>In addition to displaying differences between a source and destination file, &kompare; can be used to create and view a special file called a &apos;diff&apos;.
+This file captures the differences between the two sources into a single file that can be used to view and apply changes to any other copy of the file.
+For example, if two people are editing a document. The first person wants to make changes and send just the changes made to the second person.
+Normally, the first person would send a complete copy of the modified document to the second person, who would then have to compare the modified document
+side-by-side with unmodified version. The process for this is much like what we have described in the previous paragraphs. With &kompare; the first person
+would first make a local copy of the file to be modified, then make changes and compare the original and modified copy. Now using &kompare; a diff file
+can be created that captures only the changes made. This can be sent to the second person in place of a whole file containing the changes.</para>
+
+<para>Using &kompare; the second person can view the diff file, compare it to the local copy of the document and apply the changes made by the first person.
+So the process can go on for many versions of the document, each person making changes, creating diffs, distributing them and applying them.
+This process is commonly called &quot;patching&quot;, a term taken from the program named &quot;patch&quot; which is another command line
+tool specifically designed for the purpose of applying diff files.</para>
+
+<para>It sometimes happens that people edit a file at the same time. In this situation it is likely that people will make changes in the document at
+exactly the same line. This creates a problem because, without applied caution, people could be overwriting each others work as they apply the diff files they receive.
+Fortunately the developers of the diff and patch programs took this into consideration and so these tools will not allow such changes to be applied without manual intervention.
+When this state is reached, it is known as a &quot;conflict&quot;. &kompare; will display conflicts so that you can manually resolve them, deciding
+which changes should be applied to which file.</para>
+
+<para>&kompare; is also a great program for comparison of file changes on a folder level. When used to compare folders &kompare; recursively examines subfolders
+and their file contents for differences. In this use case, each file where differences are found are automatically opened and
+listed by &kompare; where easy navigation between the various files is possible.</para>
+
+</chapter>
+
+<chapter id="using">
+<title>Using &kompare;</title>
+
+<sect1 id="getting-started">
+<title>Getting Started</title>
+
+<para>This section provides instructions for starting &kompare; and provides a quick tour to the &kompare; main interface.</para>
+
+<sect2 id="starting-kompare">
+<title>Starting &kompare;</title>
+
+<para>A shortcut for starting &kompare; can be found in the K menu in the Development group
+<menuchoice><guimenu>Development</guimenu><guimenuitem>Kompare</guimenuitem></menuchoice>.</para>
+
+<para>When &kompare; starts the first thing it does is display a dialog from
+which to select the files you wish to compare. Special settings for the properties of the diff and the apprearance thereof can also be selected.
+In the file form select a source and destination source to compare. This can be any two files, folders or a &URL; and a file.
+Once the source and destination are selected click the <guibutton>Compare</guibutton> button.</para>
+
+<para>Once &kompare; has discovered the differences it will display the main interface.
+When comparing two files or a url and a file the process takes just a few seconds. However, when comparing folders
+with many subfolders and files, this process can take awhile.</para>
+
+<para>For explanation of the options available from diff and appearance forms see <xref linkend="configure-preferences"/>.</para>
+</sect2>
+
+<sect2 id="main-interface">
+<title>The Main Interface</title>
+
+<para>This section provides a quick tour of the main interface which is comprised of the following areas:</para>
+<itemizedlist>
+<listitem><para>Menus</para></listitem>
+<listitem><para>Toolbar</para></listitem>
+<listitem><para>Source and Destination Folders</para></listitem>
+<listitem><para>Source and Destination Files</para></listitem>
+<listitem><para>Source and Destination Line Changes</para></listitem>
+<listitem><para>Source and Destination Text View</para></listitem>
+<listitem><para>Statusbar</para></listitem>
+</itemizedlist>
+
+<sect3 id="menus">
+<title>Menus</title>
+<para>&kompare; provides a menu driven interface. Explanation to the menu items and their options is provided in <xref linkend="command-reference"/>.</para>
+</sect3>
+
+<sect3 id="toolbar">
+<title>Toolbar</title>
+<para>The &kompare; toolbar provides shortcuts to the most frequently used diff and merge operations.
+The toolbar orientation, text postioning, icon size properties and which shortcut icons are displayed can be customized from the
+toobar context menu accessed when right-clicking the toolbar with the mouse. The toobar content menu also enables the toobar to be hidden.
+If the toolbar is hidden and you wish to unhide it, select <menuchoice><guimenu>Settings</guimenu><guimenuitem>Show Toolbar</guimenuitem></menuchoice>.</para>
+</sect3>
+
+<sect3 id="source-destination-folders">
+<title>Source and Destination Folders</title>
+<para>The source folder and destination folder panes display the folders in which compared files reside.
+When many subfolders are included in the comparison, then selecting a folder will display the first document in
+that folder where a difference was found between the source and destination.</para>
+</sect3>
+
+<sect3 id="source-destination-files">
+<title>Source and Destination Files</title>
+<para>The source and destination file pane displays files where a difference was found for the currently selected source or destination folder.
+When a folder has multiple documents containing differences, all documents with a difference are listed. The selected document is displayed.</para>
+</sect3>
+
+<sect3 id="source-destination-lines">
+<title>Source and Destination Line Changes</title>
+<para>The source and destination line changes pane summarizes the differences found between the current source and destination documents.
+Selecting a record within the pane highlights and selects the difference. This is a useful way to navigate and inspect long documents with many differences.</para>
+</sect3>
+
+<sect3 id="source-destination-view">
+<title>Source and Destination View</title>
+<para>The source and destination view is the main workspace of &kompare;.
+The contents and highlighted differences of the currently selected source and destination file are displayed here with line numbers..</para>
+</sect3>
+
+<sect3 id="text-view">
+<title>Text View</title>
+<para>The <guilabel>Text View</guilabel> is not displayed by default. It can be opened by selecting
+<menuchoice><guimenu>Settings</guimenu><guimenuitem>Show Text View</guimenuitem></menuchoice>.</para>
+<!-- Other than a notepad, what is this text view good for? -->
+</sect3>
+
+<sect3 id="statusbar">
+<title>Statusbar</title>
+<para>The status bar provides a summary of the current source and destination file or folder under comparison.
+The status bar also reports the number of changes found in the current document and counts the differences that have been applied.
+Furthermore, the status bar shows the overall number of documents containing differences and the current document number selected from this set.
+For example, a comparison run over two folders may return 1890 files with differences. The currently selected document is number 18 of 1890.</para>
+</sect3>
+</sect2>
+</sect1>
+
+<sect1 id="viewing-differences">
+<title>Viewing Differences</title>
+
+<sect2 id="managing-screen-real-estate">
+<title>Managing Screen Real-Estate</title>
+<para>&kompare; displays the source and destination file under using equal percentage of the main interface view work area.
+This view area provides some features that help optimize use of screen real-estate while viewing differences, including:</para>
+<variablelist>
+<varlistentry>
+<term>Dual Scrollbars</term>
+<listitem><para>The most obvious feature is that scrollbars are provided both on the right and bottom edges of the view area.
+Using the scrollbars it is possible to move rapidly through the comparison.</para></listitem>
+</varlistentry>
+<varlistentry>
+<term>Share Grip Handle</term>
+<listitem><para>The vertical space between the source and destination view not only makes it possible to clearly see the start and end of lines in each of the panes,
+but is also a grip handle that allows adjustment of percentage occupied between the source and destinate views that comprise the view pane.
+To change pane size for one of the views, hover the mouse pointer over the grip handle then hold down the mouse button and drag left or right.
+Naturally, increasing the area of one pane will decrease the area available to the opposite pane within the view panel area.</para></listitem>
+</varlistentry>
+<varlistentry>
+<term>Docking</term>
+<listitem><para>The main workspace can be undocked from the main interface by clicking the <guibutton>undock</guibutton> button located top right of the main workspace panel.
+This opens the main workspace in a window of its own, allowing it to be maximized and resized across the screen.</para></listitem>
+</varlistentry>
+<varlistentry>
+<term>Statusbar Toggle</term>
+<listitem>
+<para>The status bar of the view panel can be toggled ON/OFF by selecting <menuchoice><guimenu>Settings</guimenu><guimenuitem>Hide/Show Statusbar</guimenuitem></menuchoice>.</para>
+</listitem>
+</varlistentry>
+</variablelist>
+</sect2>
+
+<sect2 id="switching-source-and-destination-view">
+<title>Switching Source and Destination Views</title>
+
+<para>Sometimes it can be useful to consider what the file to which differences where to be applied as the source.
+For example, when comparing two modified versions of a file and discovering that the one file has many more modifications that the other.
+The file with more changed would be better as the source, since then fewer differences would need to be applied.</para>
+<para>In this case select <menuchoice><guimenu>File</guimenu><guimenuitem>Swap Source with Destination</guimenuitem></menuchoice>.
+This will switch the files displayed in all &kompare; panels.</para>
+</sect2>
+
+<sect2 id="display-difference-statistics">
+<title>Displaying Difference Statistics</title>
+<para>For a quick overview of the differences, select <menuchoice><guimenu>File</guimenu><guimenuitem>Show Statistics</guimenuitem></menuchoice>.
+This will display the <guilabel>Diff Statistics</guilabel> dialog. The following information is provided:</para>
+<variablelist>
+<varlistentry>
+<term><guilabel>Old file:</guilabel></term>
+<listitem><para>The file name of what is usually the destination file or file that is unmodified and to which differences will be applied.</para></listitem>
+</varlistentry>
+<varlistentry>
+<term><guilabel>New file:</guilabel></term>
+<listitem><para>The file name of what is usually the source file or file that is modified.</para></listitem>
+</varlistentry>
+<varlistentry>
+<term><guilabel>Format:</guilabel></term>
+<listitem><para>The diff format used to display the difference (see <xref linkend="diff-format"/>).</para></listitem>
+</varlistentry>
+<varlistentry>
+<term><guilabel>Number of hunks:</guilabel></term>
+<listitem>
+<para>The number of hunks found in the difference.</para>
+<para>A hunk is a <quote>c<emphasis>hunk</emphasis></quote> of lines that have been marked as different between
+source and destination and may include context lines depending on the diff format <guilabel>Lines of Context</guilabel> value (see <xref linkend="diff-format"/>).</para></listitem>
+</varlistentry>
+<varlistentry>
+<term><guilabel>Number of differences</guilabel></term>
+<listitem><para>The actual number of differences found, not hunks. A hunk can contain one or more differences
+when the line change range and the context lines of any two or more changes overlap.</para></listitem>
+</varlistentry>
+</variablelist>
+</sect2>
+
+<sect2 id="navigating-the-difference-view">
+<title>Navigating the Difference View</title>
+<para>&kompare; enables rapid navigation of differences on a file level and of multiple difference files when comparing folder trees.</para>
+
+<sect3 id="selecting-a-difference">
+<title>Selecting a Difference</title>
+<para>A difference can be selected using by:</para>
+<itemizedlist>
+<listitem><para>clicking a line in the Source and Destination Line Changes pane (top right of the main window).</para></listitem>
+<listitem><para>clicking the highlighted difference in the View pane.</para></listitem>
+<listitem><para>traversing the listed differences in a comparison (see <xref linkend="traversing-differences"/>).</para></listitem>
+</itemizedlist>
+<para>When a difference is selected it is considered to be <quote>in focus</quote> and is displayed in a brighter color that non-selected differences.</para>
+</sect3>
+
+<sect3 id="traversing-differences">
+<title>Traversing Differences</title>
+<para>When a comparison finds many differences one of the best ways to approach reviewing them is to traverse the differences in a logical order, usually from top to bottom.</para>
+<para>By default &kompare; selects the first difference found in a comparison. By selecting
+<menuchoice><guimenu>Difference</guimenu><guimenuitem>Next Difference</guimenuitem></menuchoice>
+(<keycombo action="simul">&Ctrl;<keycap>Down</keycap></keycombo>) the difference following the current selection is brought into focus.
+To select the difference before the current difference
+select <menuchoice><guimenu>Difference</guimenu><guimenuitem>Previous Difference</guimenuitem></menuchoice>
+(<keycombo action="simul">&Ctrl;<keycap>Up</keycap></keycombo>).</para>
+<para>In this way it is possible to traverse differences in an orderly manner, applying and unapply differences upon review.</para>
+</sect3>
+
+<sect3 id="switching-between-files">
+<title>Switching Between Files</title>
+<para>When a comparison is performed on folder level, many files may be found with differences.
+A complete list of the files compared with difference found is provided in the <quote>Source and Destination Folders</quote>,
+and <quote>Source and Destination Files</quote> panes. However, &kompare; displays differences between source and destination one comparison at time.</para>
+<para>To switch between documents in this scenario the following options are available:</para>
+<itemizedlist>
+<listitem><para>Select the <quote>Source and Destination Folders</quote> pane to display file differences found in the
+<quote>Source and Destination Files</quote> pane, then select a file.</para></listitem>
+<listitem><para>Select <menuchoice><guimenu>Difference</guimenu><guimenuitem>Previous File</guimenuitem></menuchoice>
+(<keycombo action="simul">&Ctrl;<keycap>PageUp</keycap></keycombo>) or
+<menuchoice><guimenu>Difference</guimenu><guimenuitem>Next File</guimenuitem></menuchoice>
+(<keycombo action="simul">&Ctrl;<keycap>PageDown</keycap></keycombo>) to
+display the previous or next difference file found in the <quote>Source and Destination Files</quote> pane.</para>
+</listitem>
+</itemizedlist>
+</sect3>
+</sect2>
+</sect1>
+
+<sect1 id="merging-differences">
+<title>Merging Differences</title>
+
+<para>&kompare; makes the task of applying and unapplying differences as simple as point and click.
+Multiple apply and unapply operations can be performed on a difference as all operations are performed in memory and not written to the files on disk until the save operation is performed.</para>
+
+<sect2 id="applying-a-difference">
+<title>Applying a Difference</title>
+<para>To apply a difference, click the highlighted difference region, then select
+<menuchoice><guimenu>Difference</guimenu><guimenuitem>Apply Difference</guimenuitem></menuchoice> (<keycombo><keycap>Space</keycap></keycombo>).</para>
+</sect2>
+
+<sect2 id="unapplying-a-difference">
+<title>Unapplying a Difference</title>
+<para>To unapply a difference, click the highlighted difference region previously applied, then select
+<menuchoice><guimenu>Difference</guimenu><guimenuitem>Unapply Difference</guimenuitem></menuchoice> (<keycombo><keycap>Backspace</keycap></keycombo>).</para>
+</sect2>
+
+<sect2 id="applying-all-differences">
+<title>Applying All Differences</title>
+<para>After reviewing differences between files and finding all acceptable it is possible apply them all with a single operation by selecting
+<menuchoice><guimenu>Difference</guimenu><guimenuitem>Apply All</guimenuitem></menuchoice> (<keycombo action="simul">&Ctrl;<keycap>A</keycap></keycombo>).</para>
+</sect2>
+
+<sect2 id="unapplying-all-differences">
+<title>Unapplying All Differences</title>
+<para>To differences that have been applied select
+<menuchoice><guimenu>Difference</guimenu><guimenuitem>Unapply All</guimenuitem></menuchoice> (<keycombo action="simul">&Ctrl;<keycap>U</keycap></keycombo>).</para>
+</sect2>
+
+<sect2 id="saving-changes">
+<title>Saving Changes</title>
+<para>Once differences have been applied they can be saved by selecting
+<menuchoice><guimenu>File</guimenu><guimenuitem>Save</guimenuitem></menuchoice> or
+<menuchoice><guimenu>File</guimenu><guimenuitem>Save All...</guimenuitem></menuchoice>.</para>
+<para>Applied differences are saved to both the source and destination file.</para>
+</sect2>
+</sect1>
+
+<sect1 id="working-with-diff-files">
+<title>Working with Diff Files</title>
+<para>Diff files contain only the changes made between files, or a set of files within a folder system, and may or may not contain a number of context lines before and after line changes.
+The sum of a line change and its context lines is known a hunk. A diff file therefore may contain multiple hunks from one or more files.
+When the context lines of two or more hunks overlap, they are considered a single hunk. Diff files can be used to:</para>
+<itemizedlist>
+<listitem><para>Apply the changes contained in the hunks to an original file.</para></listitem>
+<listitem><para>Apply the changes contained in the hunks to a file or set of original files within a folder system.</para></listitem>
+<listitem><para>Modified before being applied to an original file or set of original files within a folder system.</para></listitem>
+</itemizedlist>
+
+<sect2 id="creating-a-diff">
+<title>Creating a Diff</title>
+<para>To create a diff file a comparison must be displayed in &kompare;. Assuming this is the case, then select <menuchoice><guimenu>File</guimenu><guimenuitem>Save .diff</guimenuitem></menuchoice>.
+This will display the <guilabel>Diff Options</guilabel> dialog (see <xref linkend="diff-settings"/> for more information on diff formats and options).
+After configuring these options, click the <guibutton>Save</guibutton> button and save the diff to a file with the extension <filename class="extension">.diff</filename>.</para>
+</sect2>
+
+<sect2 id="displaying-a-diff">
+<title>Displaying a Diff</title>
+<para>It is possible to display the contents of a diff file within &kompare; by opening the diff file from <menuchoice><guimenu>File</guimenu><guimenuitem>Open Diff...</guimenuitem></menuchoice>.</para>
+<para>When viewing a diff file the hunks between the source and destination file are shown, remember that only the hunks are shown, no unmodified lines will be shown.
+In some cases a diff file is created with 0 lines of context. In this case only the changed lines will be displayed.</para>
+<para>When a diff file contains hunks from multiple files &kompare; displays the hunks from each file one at a time and you can
+switch between files as though they were real files even though this information is only provided by the diff file contents.</para>
+</sect2>
+
+<sect2 id="applying-a-diff">
+<title>Applying Differences in a Diff File</title>
+<para>When viewing differences in a diff file it is possible to apply difference as you would when comparing source and destination files (see <xref linkend="merging-differences"/>).</para>
+</sect2>
+
+<sect2 id="blending-a-diff">
+<title>Blending a &URL; with a Diff</title>
+<para>In cases where a diff file is provided it is possible to compare the hunks in the diff against a file or folder.
+To do this select <menuchoice><guimenu>File</guimenu><guimenuitem>Blend URL with Diff...</guimenuitem></menuchoice>.
+Then input the <guilabel>File/Folder</guilabel> and <guilabel>Diff Output</guilabel> paths.</para>
+<para>When viewing differences between a source file and a diff file it is possible to apply difference as you would when comparing source and destination files (see <xref linkend="merging-differences"/>).</para>
+</sect2>
+
+</sect1>
+</chapter>
+
+<chapter id="configure-preferences">
+<title>Configuring Preferences</title>
+
+<para>&kompare; enables users to set appearance preferences for difference formatting in the main interface and set behavioural properties of the diff program.
+The <guilabel>Preferences</guilabel> dialog can be accessed by selecting
+<menuchoice><guimenu>Settings</guimenu><guisubmenu>Configure &kompare;...</guisubmenu></menuchoice>.</para>
+
+<para>To configure preferences for appearance select the <guilabel>View</guilabel> menu item (see <xref linkend="view-settings"/>).</para>
+
+<para>To configure preferences for diff program properties select the <guilabel>Diff</guilabel> menu item (see <xref linkend="diff-settings"/>).</para>
+
+<sect1 id="view-settings">
+<title>View Settings</title>
+<para>The <guimenu>View</guimenu> menu found on the <guilabel>Preferences</guilabel> dialog displays the <guilabel>Appearance</guilabel>
+and <guilabel>Fonts</guilabel> tabbed forms.</para>
+
+<sect2 id="appearance">
+<title>Appearance</title>
+<para>The <guilabel>Appearance</guilabel> form provides controls to manage the <guilabel>Colors</guilabel> used
+to denote difference in the main interface, behaviour of the <guilabel>Mouse Wheel</guilabel> when jogging up and down
+and how <guilabel>Tabs to Spaces</guilabel> conversion is managed.</para>
+<screenshot>
+<screeninfo>&kompare; Appearance Settings</screeninfo>
+ <mediaobject>
+ <imageobject>
+ <imagedata fileref="settings-view1.png" format="PNG"/>
+ </imageobject>
+ <textobject>
+ <phrase>&kompare; Appearance Settings</phrase>
+ </textobject>
+ </mediaobject>
+</screenshot>
+<variablelist>
+<title>Color Group</title>
+<para>To adjust color preferences used when displaying differences, click the color button to display the <guilabel>Select Color</guilabel> dialog for the following states:</para>
+<varlistentry>
+<term><guilabel>Removed color</guilabel></term>
+<listitem><para>Lines that have been removed, do not exist, between source and destination.</para></listitem>
+</varlistentry>
+<varlistentry>
+<term><guilabel>Changed color</guilabel></term>
+<listitem><para>Lines that have been changed, modified, between source and destination. </para></listitem>
+</varlistentry>
+<varlistentry>
+<term><guilabel>Added color</guilabel></term>
+<listitem><para>Lines that have been added between source and destination.</para></listitem>
+</varlistentry>
+<varlistentry>
+<term><guilabel>Applied color</guilabel></term>
+<listitem><para>Any of the above states where the difference has been applied between source and destination.</para></listitem>
+</varlistentry>
+</variablelist>
+<variablelist>
+<title>Mouse Wheel</title>
+<varlistentry>
+<term><guilabel>Number of lines</guilabel></term>
+<listitem><para>The number of lines to jog the differences when turning the mouse wheel forward or backward.</para></listitem>
+</varlistentry>
+</variablelist>
+<variablelist>
+<title>Tabs to Spaces</title>
+<varlistentry>
+<term><guilabel>Number of spaces to convert a tab character to</guilabel></term>
+<listitem><para>Convert each tab character to n space characters.</para></listitem>
+</varlistentry>
+</variablelist>
+</sect2>
+
+<sect2 id="fonts">
+<title>Fonts</title>
+<screenshot>
+<screeninfo>&kompare; Fonts Settings</screeninfo>
+ <mediaobject>
+ <imageobject>
+ <imagedata fileref="settings-view2.png" format="PNG"/>
+ </imageobject>
+ <textobject>
+ <phrase>&kompare; Fonts Settings</phrase>
+ </textobject>
+ </mediaobject>
+</screenshot>
+<para>Select the font family and size to display when displaying differences.</para>
+</sect2>
+</sect1>
+
+<sect1 id="diff-settings">
+<title>Diff Settings</title>
+<para>The <guimenu>Diff</guimenu> menu found on the <guilabel>Preferences</guilabel> dialog displays the <guilabel>Diff</guilabel>,
+<guilabel>Format</guilabel>, <guilabel>Options</guilabel> and <guilabel>Exclude</guilabel> tabbed forms. These forms can be used to configure the
+behavioural properties of the Diff program.</para>
+
+<sect2 id="diff">
+<title>Diff</title>
+<screenshot>
+<screeninfo>&kompare; Diff Settings</screeninfo>
+ <mediaobject>
+ <imageobject>
+ <imagedata fileref="settings-diff1.png" format="PNG"/>
+ </imageobject>
+ <textobject>
+ <phrase>&kompare; Diff Settings</phrase>
+ </textobject>
+ </mediaobject>
+</screenshot>
+<para>The command used to run the diff program (default <application>diff</application>).</para>
+</sect2>
+
+<sect2 id="diff-format">
+<title>Format</title>
+<screenshot>
+<screeninfo>&kompare; Format Settings</screeninfo>
+ <mediaobject>
+ <imageobject>
+ <imagedata fileref="settings-diff2.png" format="PNG"/>
+ </imageobject>
+ <textobject>
+ <phrase>&kompare; Format Settings</phrase>
+ </textobject>
+ </mediaobject>
+</screenshot>
+<para>Adjust options for the <guilabel>Output Format</guilabel> and number of <guilabel>Lines of Context</guilabel>.</para>
+<variablelist>
+<title>Output Format</title>
+<varlistentry>
+<term><guilabel>Context</guilabel></term>
+<listitem>
+<para>The context output format adds several lines of context around the lines that differ.</para>
+</listitem>
+</varlistentry>
+<varlistentry>
+<term><guilabel>Ed</guilabel></term>
+<listitem>
+<para>diff can produce commands that direct the ed text editor to change the first file into the second file.
+Historically, this was the only output mode suitable for automatically editing one file into another.
+With the advent of <application>patch</application> this option is hardly ever used.</para>
+</listitem>
+</varlistentry>
+<varlistentry>
+<term><guilabel>Normal</guilabel></term>
+<listitem>
+<para>The normal output format displays differing lines without any surrounding lines of context. </para>
+</listitem>
+</varlistentry>
+<varlistentry>
+<term><guilabel>RCS</guilabel></term>
+<listitem>
+<para>The RCS output format is designed specifically for use by the Revision Control System (<acronym>RCS</acronym>).
+Like Ed format, this format is rarely used since the <application>patch</application> program was introduced.</para>
+</listitem>
+</varlistentry>
+<varlistentry>
+<term><guilabel>Unified</guilabel></term>
+<listitem>
+<para>The unified output format is a variation on the context format. It is considered better than context because the
+output is more compact than that of context as it omits redundant context lines.</para>
+</listitem>
+</varlistentry>
+<varlistentry>
+<term><guilabel>Side-by-side</guilabel></term>
+<listitem>
+<para>Use the side by side output format which displays files listed in two columns with a gutter between them. This option is only available from the <guilabel>Diff Options</guilabel> dialog (see <xref linkend="creating-a-diff"/>).</para>
+</listitem>
+</varlistentry>
+</variablelist>
+<variablelist>
+<title>Lines of Context</title>
+<varlistentry>
+<term><guilabel>Number of context lines</guilabel></term>
+<listitem>
+<para>When performing a diff with context or unified output format use this parameter to control the number of context lines included.</para>
+</listitem>
+</varlistentry>
+</variablelist>
+</sect2>
+
+<sect2 id="options">
+<title>Options</title>
+<screenshot>
+<screeninfo>&kompare; OptionsSettings</screeninfo>
+ <mediaobject>
+ <imageobject>
+ <imagedata fileref="settings-diff3.png" format="PNG"/>
+ </imageobject>
+ <textobject>
+ <phrase>&kompare; Options Settings</phrase>
+ </textobject>
+ </mediaobject>
+</screenshot>
+<para>The <guilabel>Options</guilabel> tab form allows configuration of the options supported by the diff program.</para>
+<variablelist>
+<title>General</title>
+<varlistentry>
+<term><guilabel>Look for smaller changes</guilabel></term>
+<listitem><para>Forces diff to display changes in case, punctuation, space, &etc; when checked.</para></listitem>
+</varlistentry>
+<varlistentry>
+<term><guilabel>Optimise for large files</guilabel></term>
+<listitem><para>Switches diff to process files with high-speed when checked.</para></listitem>
+</varlistentry>
+<varlistentry>
+<term><guilabel>Ignore changes in case</guilabel></term>
+<listitem><para>Lower and Uppercase character changes are omitted when this option is checked.</para></listitem>
+</varlistentry>
+</variablelist>
+<variablelist>
+<title>Ignore regexp</title>
+<varlistentry>
+<term><guilabel>Ignore regexp</guilabel></term>
+<listitem><para>Ignore lines matching a regular expression.</para></listitem>
+</varlistentry>
+</variablelist>
+<variablelist>
+<title>Whitespace</title>
+<varlistentry>
+<term><guilabel>Expand tabs to spaces in output</guilabel></term>
+<listitem><para>When checked diff outputs will converts tab characters to the number of spaces defined in the
+<guilabel>Preferences</guilabel> dialog <guimenu>View</guimenu> menu <guilabel>Tabs to Spaces</guilabel> option.</para>
+</listitem>
+</varlistentry>
+<varlistentry>
+<term><guilabel>Ignore added or removed empty lines</guilabel></term>
+<listitem><para>lines of zero length that differ between source and destination are ignored when this option is checked.</para></listitem>
+</varlistentry>
+<varlistentry>
+<term><guilabel>Ignore changes in the amount of whitespace</guilabel></term>
+<listitem><para>White space before, after and between lines may change depending on different editors.
+When this option is checked such changes are ignored.</para></listitem>
+</varlistentry>
+<varlistentry>
+<term><guilabel>Ignore all whitespace</guilabel></term>
+<listitem><para>when checked white space differences are completely ignored.</para></listitem>
+</varlistentry>
+<varlistentry>
+<term><guilabel>Ignore changes due to tab expansion</guilabel></term>
+<listitem><para>when checked white space resulting from tab characters is ignored.</para></listitem>
+</varlistentry>
+</variablelist>
+</sect2>
+
+<sect2 id="exclude">
+<title>Exclude</title>
+<para>The <guilabel>Exclude</guilabel> form enables use of the filter options provided by the diff program.</para>
+<screenshot>
+<screeninfo>&kompare; Exclude Settings</screeninfo>
+ <mediaobject>
+ <imageobject>
+ <imagedata fileref="settings-diff4.png" format="PNG"/>
+ </imageobject>
+ <textobject>
+ <phrase>&kompare; Exclude Settings</phrase>
+ </textobject>
+ </mediaobject>
+</screenshot>
+<variablelist>
+<title>File Pattern to Exclude</title>
+<varlistentry>
+<term><guilabel>File Pattern to Exclude</guilabel></term>
+<listitem><para>Exclude files based on wild card filtering</para></listitem>
+</varlistentry>
+</variablelist>
+<variablelist>
+<title>File with Filenames to Exclude</title>
+<varlistentry>
+<term><guilabel>File with Filenames to Exclude</guilabel></term>
+<listitem><para>Define the filter based on the content of an externally managed file.</para></listitem>
+</varlistentry>
+</variablelist>
+</sect2>
+</sect1>
+
+</chapter>
+
+<chapter id="command-reference">
+<title>Command Reference</title>
+
+<sect1 id="file-menu">
+<title>The <guimenu>File</guimenu> Menu</title>
+<variablelist>
+<varlistentry>
+<term><menuchoice>
+<shortcut>
+<keycombo action="simul">&Ctrl;<keycap>O</keycap></keycombo>
+</shortcut>
+<guimenu>File</guimenu><guimenuitem>Open Diff...</guimenuitem></menuchoice></term>
+<listitem><para>Displays the <guilabel>Open</guilabel> dialog.</para></listitem>
+</varlistentry>
+
+<varlistentry>
+<term><menuchoice>
+<shortcut>
+<keycombo action="simul">&Ctrl;<keycap>C</keycap></keycombo>
+</shortcut>
+<guimenu>File</guimenu><guimenuitem>Compare Files...</guimenuitem></menuchoice></term>
+<listitem><para>Displays the <guilabel>Compare Files or Folders</guilabel> dialog.</para></listitem>
+</varlistentry>
+
+<varlistentry>
+<term><menuchoice>
+<shortcut>
+<keycombo action="simul">&Ctrl;<keycap>B</keycap></keycombo>
+</shortcut>
+<guimenu>File</guimenu><guimenuitem>Blend URL with Diff...</guimenuitem></menuchoice></term>
+<listitem><para>Displays the <guilabel>Blend File/Folder with diff Output</guilabel> dialog.</para></listitem>
+</varlistentry>
+
+<varlistentry>
+<term><menuchoice>
+<shortcut>
+<keycombo action="simul">&Ctrl;<keycap>S</keycap></keycombo>
+</shortcut>
+<guimenu>File</guimenu><guimenuitem>Save</guimenuitem></menuchoice></term>
+<listitem><para>Writes applied differences to current source and or destination file.</para></listitem>
+</varlistentry>
+
+<varlistentry>
+<term><menuchoice><guimenu>File</guimenu><guimenuitem>Save All</guimenuitem></menuchoice></term>
+<listitem><para>Writes applied differences to all source and or destination files.</para></listitem>
+</varlistentry>
+
+<varlistentry>
+<term><menuchoice><guimenu>File</guimenu><guimenuitem>Save .diff</guimenuitem></menuchoice></term>
+<listitem><para>Displays the <guilabel>Diff Options</guilabel> dialog to define diff format and options.</para></listitem>
+</varlistentry>
+
+<varlistentry>
+<term><menuchoice><guimenu>File</guimenu><guimenuitem>Swap Source with Destination</guimenuitem></menuchoice></term>
+<listitem><para>Changes source and destination.</para></listitem>
+</varlistentry>
+
+<varlistentry>
+<term><menuchoice>
+<guimenu>File</guimenu><guimenuitem>Show Statistics</guimenuitem></menuchoice></term>
+<listitem><para>Displays the <guilabel>Display Statistics</guilabel> dialog.</para></listitem>
+</varlistentry>
+
+<varlistentry>
+<term><menuchoice>
+<shortcut>
+<keycombo action="simul">&Ctrl;<keycap>Q</keycap></keycombo>
+</shortcut>
+<guimenu>File</guimenu><guimenuitem>Quit</guimenuitem></menuchoice></term>
+<listitem><para>Exits &kompare;.</para></listitem>
+</varlistentry>
+</variablelist>
+</sect1>
+
+<sect1 id="difference-menu">
+<title>The <guimenu>Difference</guimenu> Menu</title>
+<variablelist>
+<varlistentry>
+<term><menuchoice>
+<shortcut>
+<keycombo action="simul">&Ctrl;<keycap>U</keycap></keycombo>
+</shortcut>
+<guimenu>Difference</guimenu><guimenuitem>Unapply All</guimenuitem></menuchoice></term>
+<listitem><para>Unapply all differences previously applied between source and destination.</para></listitem>
+</varlistentry>
+
+<varlistentry>
+<term><menuchoice>
+<shortcut><keycap>Backspace</keycap></shortcut>
+<guimenu>Difference</guimenu><guimenuitem>Unapply Difference</guimenuitem></menuchoice></term>
+<listitem><para>Revert a selected difference previously applied.</para></listitem>
+</varlistentry>
+
+<varlistentry>
+<term><menuchoice>
+<shortcut><keycap>Space</keycap></shortcut>
+<guimenu>Difference</guimenu><guimenuitem>Apply Difference</guimenuitem></menuchoice></term>
+<listitem><para>Apply a selected difference.</para></listitem>
+</varlistentry>
+
+<varlistentry>
+<term><menuchoice>
+<shortcut>
+<keycombo action="simul">&Ctrl;<keycap>A</keycap></keycombo>
+</shortcut>
+<guimenu>Difference</guimenu><guimenuitem>Apply All</guimenuitem></menuchoice></term>
+<listitem><para>Apply all differences between source and destination.</para></listitem>
+</varlistentry>
+
+<varlistentry>
+<term><menuchoice>
+<shortcut>
+<keycombo action="simul">&Ctrl;<keycap>PageUp</keycap></keycombo>
+</shortcut>
+<guimenu>Difference</guimenu><guimenuitem>Previous File</guimenuitem></menuchoice></term>
+<listitem><para>Make the previous difference, in the list of differences, the current file in the view pane.</para></listitem>
+</varlistentry>
+
+<varlistentry>
+<term><menuchoice>
+<shortcut>
+<keycombo action="simul">&Ctrl;<keycap>PageDown</keycap></keycombo>
+</shortcut>
+<guimenu>Difference</guimenu><guimenuitem>Next File</guimenuitem></menuchoice></term>
+<listitem><para>Make the next difference, in the list of differences, the current file in the view pane.</para></listitem>
+</varlistentry>
+
+<varlistentry>
+<term><menuchoice>
+<shortcut>
+<keycombo action="simul">&Ctrl;<keycap>Up</keycap></keycombo>
+</shortcut>
+<guimenu>Difference</guimenu><guimenuitem>Previous Difference</guimenuitem></menuchoice></term>
+<listitem><para>Select the difference above the currently selected difference.</para></listitem>
+</varlistentry>
+
+<varlistentry>
+<term><menuchoice>
+<shortcut>
+<keycombo action="simul">&Ctrl;<keycap>Down</keycap></keycombo>
+</shortcut>
+<guimenu>Difference</guimenu><guimenuitem>Next Difference</guimenuitem></menuchoice></term>
+<listitem><para>Select the difference below the currently selected difference.</para></listitem>
+</varlistentry>
+</variablelist>
+</sect1>
+
+<sect1 id="settingsmenu">
+<title>The <guimenu>Settings</guimenu> Menu</title>
+<variablelist>
+<varlistentry>
+<term><menuchoice><guimenu>Settings</guimenu><guimenuitem>Hide/Show Toolbar</guimenuitem></menuchoice></term>
+<listitem><para>Toggle the toolbar display ON/OFF.</para></listitem>
+</varlistentry>
+<varlistentry>
+<term><menuchoice><guimenu>Settings</guimenu><guimenuitem>Show/Hide Statusbar</guimenuitem></menuchoice></term>
+<listitem><para>Toggle the status bar display ON/OFF.</para></listitem>
+</varlistentry>
+<varlistentry>
+<term><menuchoice><guimenu>Settings</guimenu><guimenuitem>Show Text View</guimenuitem></menuchoice></term>
+<listitem><para>Display the <guilabel>Text View</guilabel> pane.</para></listitem>
+</varlistentry>
+<varlistentry>
+<term><menuchoice><guimenu>Settings</guimenu><guimenuitem>Configure Shortcuts...</guimenuitem></menuchoice></term>
+<listitem><para>Display the <guilabel>Configure Shortcuts</guilabel> dialog.</para></listitem>
+</varlistentry>
+<varlistentry>
+<term><menuchoice><guimenu>Settings</guimenu><guimenuitem>Configure Toolbars...</guimenuitem></menuchoice></term>
+<listitem><para>Display the <guilabel>Configure Toolbar</guilabel>.</para></listitem>
+</varlistentry>
+<varlistentry>
+<term><menuchoice><guimenu>Settings</guimenu><guimenuitem>Configure &kompare;...</guimenuitem></menuchoice></term>
+<listitem><para>Display the &kompare; <guilabel>Preference</guilabel> dialog.</para></listitem>
+</varlistentry>
+</variablelist>
+</sect1>
+
+<sect1 id="help-menu">
+<title>The <guimenu>Help</guimenu> Menu</title>
+
+&help.menu.documentation;
+</sect1>
+</chapter>
+
+<chapter id="credits">
+
+<title>Credits and License</title>
+
+<para>
+&kompare;
+</para>
+<para>
+Program copyright 2001-2004, &John.Firebaugh; &John.Firebaugh.mail;
+and Otto Bruggeman<email>otto.bruggeman@home.nl</email>
+</para>
+
+<para>
+Documentation Copyright &copy; 2007 Sean Wheller <email>sean@inwords.co.za</email>
+</para>
+
+<!-- TRANS:CREDIT_FOR_TRANSLATORS -->
+
+&underFDL; <!-- FDL: do not remove -->
+&underGPL; <!-- GPL License -->
+
+</chapter>
+
+<appendix id="installation">
+<title>Installation</title>
+
+<sect1 id="getting-kapp">
+<title>How to obtain &kompare;</title>
+
+&install.intro.documentation;
+
+</sect1>
+
+
+<sect1 id="compilation">
+<title>Compilation and Installation</title>
+
+&install.compile.documentation;
+
+</sect1>
+
+
+</appendix>
+
+&documentation.index;
+</book>
+
+<!--
+Local Variables:
+mode: sgml
+sgml-minimize-attributes:nil
+sgml-general-insert-case:lower
+sgml-indent-step:0
+sgml-indent-data:nil
+End:
+
+// vim:ts=2:sw=2:tw=78:noet
+-->
diff --git a/doc/kompare/settings-diff1.png b/doc/kompare/settings-diff1.png
new file mode 100644
index 00000000..58059c94
--- /dev/null
+++ b/doc/kompare/settings-diff1.png
Binary files differ
diff --git a/doc/kompare/settings-diff2.png b/doc/kompare/settings-diff2.png
new file mode 100644
index 00000000..f442aa94
--- /dev/null
+++ b/doc/kompare/settings-diff2.png
Binary files differ
diff --git a/doc/kompare/settings-diff3.png b/doc/kompare/settings-diff3.png
new file mode 100644
index 00000000..3b1612ce
--- /dev/null
+++ b/doc/kompare/settings-diff3.png
Binary files differ
diff --git a/doc/kompare/settings-diff4.png b/doc/kompare/settings-diff4.png
new file mode 100644
index 00000000..b157afd3
--- /dev/null
+++ b/doc/kompare/settings-diff4.png
Binary files differ
diff --git a/doc/kompare/settings-view1.png b/doc/kompare/settings-view1.png
new file mode 100644
index 00000000..b07baa5b
--- /dev/null
+++ b/doc/kompare/settings-view1.png
Binary files differ
diff --git a/doc/kompare/settings-view2.png b/doc/kompare/settings-view2.png
new file mode 100644
index 00000000..3fdbdf6e
--- /dev/null
+++ b/doc/kompare/settings-view2.png
Binary files differ
diff --git a/doc/scripts/Makefile.am b/doc/scripts/Makefile.am
new file mode 100644
index 00000000..a695f510
--- /dev/null
+++ b/doc/scripts/Makefile.am
@@ -0,0 +1,3 @@
+KDE_LANG=en
+KDE_MANS=AUTO
+SUBDIRS = $(AUTODIRS)
diff --git a/doc/scripts/kdesvn-build/Makefile.am b/doc/scripts/kdesvn-build/Makefile.am
new file mode 100644
index 00000000..171f575c
--- /dev/null
+++ b/doc/scripts/kdesvn-build/Makefile.am
@@ -0,0 +1,2 @@
+KDE_LANG = en
+KDE_DOCS = AUTO
diff --git a/doc/scripts/kdesvn-build/index.docbook b/doc/scripts/kdesvn-build/index.docbook
new file mode 100644
index 00000000..8dcadc9b
--- /dev/null
+++ b/doc/scripts/kdesvn-build/index.docbook
@@ -0,0 +1,1324 @@
+<?xml version="1.0" ?>
+<!DOCTYPE book PUBLIC "-//KDE//DTD DocBook XML V4.2-Based Variant V1.1//EN" "dtd/kdex.dtd" [
+ <!ENTITY kappname "kdesvn-build">
+ <!ENTITY package "kdesdk">
+ <!ENTITY % addindex "IGNORE">
+ <!ENTITY % English "INCLUDE"> <!-- Change language only here -->
+ <!ENTITY svn "<application>Subversion</application>">
+ <!ENTITY kdesvn-build "<application>kdesvn-build</application>">
+]>
+
+<book lang="&language;">
+
+<bookinfo>
+<title>&kdesvn-build; Script Manual</title>
+
+<authorgroup id="authors">
+<author>
+<firstname>Michael</firstname><surname>Pyne</surname>
+<affiliation><address><email>michael.pyne@kdemail.net</email></address></affiliation>
+</author>
+<author>
+<firstname>Carlos</firstname><surname>Woelz</surname>
+<affiliation><address><email>carloswoelz@imap-mail.com</email></address></affiliation>
+</author>
+
+
+<!-- TRANS:ROLES_OF_TRANSLATORS -->
+
+</authorgroup>
+
+<copyright>
+<year>2005</year>
+<holder>Michael Pyne</holder>
+</copyright>
+
+<copyright>
+<year>2005</year>
+<holder>Carlos Woelz</holder>
+</copyright>
+
+
+<legalnotice>&FDLNotice;</legalnotice>
+
+<date>2005-06-18</date>
+<releaseinfo>0.98</releaseinfo>
+
+<abstract>
+<para>The &kdesvn-build; is a Perl script which builds and installs &kde; directly from the sources found in the &kde; &svn; repository.</para>
+</abstract>
+
+<keywordset>
+<keyword>KDE</keyword>
+<keyword>kdesdk</keyword>
+<keyword>SVN</keyword>
+<keyword>Subversion</keyword>
+<keyword>KDE development</keyword>
+</keywordset>
+
+</bookinfo>
+
+
+<chapter id="introduction">
+<title>Introduction</title>
+
+<para>
+&kdesvn-build; is a Perl script to help users install <ulink
+url="http://www.kde.org/">&kde;</ulink> from <ulink
+url="http://subversion.tigris.org/">&svn;</ulink>. You may also want to
+consider the kde-build script include with &kde;'s kdesdk module.
+</para>
+
+<para>
+Here we document the &kdesvn-build; configuration file syntax and options, its
+command line options, features, and an overview of all necessary steps required
+to build &kde; from source, including the steps which you should perform using
+other tools, or in other words, steps that are not automatically performed
+by the &kdesvn-build; script.
+</para>
+
+</chapter>
+
+<chapter id="getting-started">
+<title>Getting Started</title>
+
+<para>
+In this chapter, we show how to use the &kdesvn-build; to checkout modules from the
+&kde; repository and build them. We also provide a basic explanation of the &kde;
+&svn; structure and the steps you have to perform before running the script.
+</para>
+
+<para>
+All topics present in this chapter are covered with even more detail in the
+<ulink url="http://quality.kde.org/develop/cvsguide/buildstep.php">
+Building &kde; from Source Step by Step Guide</ulink>, at the
+<ulink url="http://quality.kde.org">&kde; Quality Team Website</ulink>.
+If you are compiling KDE for the first time, it is a good idea to read
+it, or consult it as a reference source. You will find detailed information
+about packaging tools and requirements, common compilation pitfalls and
+strategies and information about running your new &kde; installation.
+</para>
+
+<sect1 id="before-building">
+<title>Preparing the System to Build &kde;</title>
+
+<para>
+It is recommended that you download and build &kde; using a user
+account. If you already have &kde; packages installed, the best choice
+would be to create a different (dedicated) user to build and run the new &kde;.
+The advantage of building &kde; with a dedicated user is you can not break
+the base system, and you will always have a way to comfortably work when
+things go wrong.
+</para>
+
+<para>
+Later, you can do a root installation if you wish. This document
+does not cover a root installation. If you are performing a system
+wide install, you probably already know what you are doing anyway.
+</para>
+
+<para>Before using the &kdesvn-build; script (or any other building
+strategy) you must install the development tools and libraries needed for &kde;.
+You need the Qt library, version 3.3.0 or greater, Automake 1.8,
+Autoconf 2.5X (better if >=2.57 as a bug was reported with lower versions),
+the subversion (svn) client, the gcc compiler with C++ support, libxml2,
+openssl, libbz2, and many more (for a complete list, visit the
+<ulink url="http://www.kde.org/info/requirements/3.4.php">KDE Compilation
+Requirements</ulink>). You can usually get those tools packaged for your system
+from your distribution or vendor.
+</para>
+
+<para>
+Some of these packages are divided into libs, programs or utilities and
+development packages. You will need at least the program or library and
+its development package. If in doubt, install all. The libraries you need
+will change depending on the modules you intend to build, as each module
+has its own requirements. The
+<ulink url="http://quality.kde.org/develop/cvsguide/buildstep.php#step1">
+Building &kde; from Source Step by Step Guide</ulink> has more details
+about the specific tools and techniques used to install and find the
+required software.
+</para>
+
+<para>
+You probably already have a version of the &kdesvn-build; script installed
+in your system. &kdesvn-build;requires you to create a configuration file, named
+<filename>.kdesvn-buildrc</filename>. This file should be installed on
+the home folder (~/), and contain all configuration data
+required for the script to run, like configuration options,
+compiling options, location of the sources, the destination of the installation
+(prefix), the modules that should be built, &etc;. The default configuration
+data is provided by the <filename>kdesvn-buildrc-sample</filename> file.
+You can find more information about the syntax of the configuration file
+in <xref linkend="configure-data" /> and in <xref linkend="kdesvn-buildrc" />.
+</para>
+
+<para>
+A good way to get the latest version is to browse the kdesdk/scripts page
+at the <ulink url="http://websvn.kde.org/trunk/KDE">websvn.kde.org</ulink> website.
+You will see a list of the files available in the kdesdk/scripts directory in
+the &kde; &svn; repository. Click the &kdesvn-build; link and download
+the latest version of the script. Do the same for the
+<filename>kdesvn-buildrc-sample</filename> file.
+Make the script executable, and be sure it is in your path.
+</para>
+
+</sect1>
+
+<sect1 id="configure-data">
+<title>Setting the Configuration Data</title>
+
+<para>
+To use the script, you must have a file in your home directory called
+<filename>.kdesvn-buildrc</filename>, which sets the general options and sets the modules
+you would like to download and build.
+</para>
+
+<para>
+Use the <filename>kdesvn-buildrc-sample</filename> file as a
+template, setting global options, and the modules you want to build.
+</para>
+
+<para>
+Select the server used to check out from &svn;, by setting the svn-server
+global option. The default is the anonymous &svn; repository,
+<emphasis>svn://anonsvn.kde.org/</emphasis>, but change it
+if you have a <ulink url="http://developer.kde.org/documentation/misc/firststepsaccount">&kde;
+&svn; account</ulink>, or if there is <ulink url="http://developer.kde.org/source/anonsvn.html">
+a mirror close to you</ulink>.
+</para>
+
+<para>
+Pay close attention to the kdedir and qtdir global variables, as the first sets
+where your &kde; build is going to be installed, (by default to
+<filename>~/kde</filename>), and the second where (and if) your qt library is
+going to be built and installed, (by default to
+<filename>~/kdesvn/build/qt-copy</filename>). You will need to know the
+kdedir and qtdir location later, to set up the environment variables
+that are necessary to run your new installation.
+Check if the listed modules are in fact the modules you want to build.
+The default options from the <filename>kdesvn-buildrc-sample</filename> file
+should be enough to get a fairly complete &kde; installation.
+Save the resulting as <filename>.kdesvn-buildrc</filename> in your home
+folder.
+</para>
+
+<para>
+If you wish to fine tune your <filename>.kdesvn-buildrc</filename>,
+consult <xref linkend="kdesvn-buildrc" /> for detailed information
+about all configuration options.
+</para>
+
+</sect1>
+
+<sect1 id="building-and-troubleshooting">
+<title>Using the &kdesvn-build; script</title>
+
+<para>
+Now you are ready to run the script. From a terminal window,
+log in to the user you are using to compile &kde; and execute
+the script:
+<screen>
+<prompt>&percnt;</prompt><command>su</command> <option>-</option> <replaceable>devel-username</replaceable>
+<prompt>&percnt;</prompt><command>kdesvn-build</command>
+</screen>
+</para>
+
+<para>
+Now, the script should start downloading the sources and compiling them. It is
+unlikely that you will succeed in the first time you compile &kde;. Do not despair!
+Check the log files to see if you are missing some tools or development packages
+(the location of the log files is set by the log-dir variable in the configuration
+file). Sometimes, the main development branch get very unstable and hard to build,
+especially when a development freeze is close. Be patient. You can find more common
+examples of things that can go wrong and their solutions, as well as general tips and
+strategies to build &kde; in the
+<ulink url="http://quality.kde.org/develop/cvsguide/buildstep.php#step1">
+Building &kde; from Source Step by Step Guide</ulink>.
+</para>
+
+</sect1>
+
+<sect1 id="environment">
+<title>Setting the Environment to Run Your Fresh &kde;</title>
+
+<para>
+Assuming you are using a dedicated user to build &kde;, and you already have
+an installed &kde; version, running your new &kde; may be a bit tricky, as the new &kde;
+has to take precedence over the old. Change the environment variables to
+make sure it does.
+</para>
+
+<para>
+Open or create the <filename>.bash_profile</filename> file in the home directory with your favorite editor,
+and add to the end of the file:
+
+<programlisting>
+KDEDIR=(path to kdedir)
+KDEDIRS=$KDEDIR
+PATH=$KDEDIR/bin:$QTDIR/bin:$PATH
+LD_LIBRARY_PATH=$KDEDIR/lib:$LD_LIBRARY_PATH
+export KDEDIRS PATH LD_LIBRARY_PATH
+</programlisting>
+
+If you are building the qt-copy module, add instead:
+
+<programlisting>
+QTDIR=(path to qtdir)
+KDEDIR=(path to kdedir)
+KDEDIRS=$KDEDIR
+PATH=$KDEDIR/bin:$QTDIR/bin:$PATH
+MANPATH=$QTDIR/doc/man:$MANPATH
+LD_LIBRARY_PATH=$KDEDIR/lib:$QTDIR/lib:$LD_LIBRARY_PATH
+export QTDIR KDEDIRS PATH MANPATH LD_LIBRARY_PATH
+</programlisting>
+</para>
+
+<para>
+If you are not using a dedicated user, set a different <envar>$KDEHOME</envar> for your
+new environment in your <filename>.bash_profile</filename>:
+
+<programlisting>
+export KDEHOME="${HOME}/.kde-svn"
+
+# Create it if needed
+[ ! -e ~/.kde-svn ] &amp;&amp; mkdir ~/.kde-svn
+</programlisting>
+</para>
+
+<note>
+<para>
+If later your menu is empty or too crowded with applications from your distribution,
+you may have to set the xdg environment variables in your <filename>.bash_profile</filename>:
+
+<programlisting>
+XDG_CONFIG_DIRS="/etc/xdg"
+XDG_DATA_DIRS="${KDEDIR}/share:/usr/share"
+export XDG_CONFIG_DIRS XDG_DATA_DIRS
+</programlisting>
+
+</para>
+</note>
+
+<para>
+Now that we are done with the you have to make sure that the right <application>startkde</application>
+script is going to be used:
+</para>
+
+<para>
+Open the <filename>.xinitrc</filename> text file (or <filename>.xsession</filename>,
+depending on the distribution) from the home directory, or create it if necessary. Add the
+line:
+
+<programlisting>
+exec ${KDEDIR}/bin/startkde
+</programlisting>
+</para>
+
+<para>
+Now start your fresh &kde;: in BSD and Linux systems with virtual terminal support,
+Ctrl+Alt+F1...F12 keystroke combinations are used to switch to Virtual Console 1 through 12.
+This allows you to run more than one desktop environment at the same time. The fist six are
+text terminals and the following six are graphical displays.
+</para>
+
+<para>
+If when you boot you are presented to the graphical display manager instead, you can
+use the new KDE environment, even if it is not listed as an option. Press Crtl + Alt + F2,
+and you will be presented to a text terminal. Log in using the dedicated user and type:
+</para>
+
+<screen>
+startx -- :1
+</screen>
+
+<tip>
+<para>
+You can run the KDE from sources and the old KDE at the same time! Log in using your regular user,
+start the stable KDE desktop. Press Crtl + Alt + F2 (or F1, F3, etc..), and you will be presented
+to a text terminal. Log in using the dedicated user and type "startx -- :1". You can go back to the
+regular user by pressing Crtl + Alt + F6 (Or F7, F8, etc... Try them out! One of them is the right
+one.) To return to KDE from sources, press Crtl + Alt + F7 (or F6, F8,etc..). Now you can switch
+between your KDE versions, and test the new one knowing you can quickly return to the safety of
+the stable KDE desktop.
+</para>
+</tip>
+
+
+</sect1>
+
+</chapter>
+
+<chapter id="features">
+<title>Script Features</title>
+
+<para>
+&kdesvn-build; features include:
+</para>
+
+
+<itemizedlist>
+
+<listitem><para>
+Automatically checks out or updates modules from &svn;, as
+appropriate.
+</para></listitem>
+
+<listitem><para>
+Times the build process for modules.
+</para></listitem>
+
+<listitem><para>
+Automatically tries to rebuild modules that were using incremental
+make, which is prone to failure after certain kinds of commits.
+</para></listitem>
+
+<listitem><para>
+Can resume a previous script, or start the build process from a particular
+module.
+</para></listitem>
+
+<listitem><para>
+Comes built-in with a sane set of default options appropriate for building
+a base &kde; single-user installation from the anonymous &svn; repository.
+</para></listitem>
+
+<listitem><para>
+Comes with <ulink url="http://www.kde.me.uk/index.php?page=unsermake">Unsermake</ulink>
+support.
+</para></listitem>
+
+<listitem><para>
+Tilde-expansion for your configuration options. For example, you can
+specify:
+<programlisting>qtdir ~/kdesvn/build/qt-copy</programlisting>
+</para></listitem>
+
+<listitem><para>
+Configurable build, source, and logging directories
+</para></listitem>
+
+<listitem><para>
+Automatically sets up a build system, with the source directory not the
+same as the build directory, in order to keep the source directory
+pristine. The exception is <application>qt-copy</application>, which is not designed to be built like
+that (unless you would like to test the
+<link linkend="conf-use-qt-builddir-hack"><quote>qt with a separate build directory hack</quote></link>).
+</para></listitem>
+
+<listitem><para>
+You can specify global options to apply to every module to check out, and
+you can specify options to apply to individual modules as well.
+</para></listitem>
+
+<listitem><para>
+Since the autotools sometimes get out of sync with changes to the
+source tree, you can force a rebuild of a module by creating a file called
+.refresh-me in the build directory of the module in question, or by running
+&kdesvn-build; with the <option>--refresh-build</option> option.
+</para></listitem>
+
+<listitem><para>
+You can specify various environment values to be used during the build,
+including <envar>KDEDIR</envar>, <envar>QTDIR</envar>, <envar>DO_NOT_COMPILE</envar>,
+and <envar>CXXFLAGS</envar>.
+</para></listitem>
+
+<listitem><para>
+Command logging. Logs are dated and numbered so that you always have a
+log of a script run. Also, a special symlink called latest is created to
+always point to the most recent log entry in the log directory.
+</para></listitem>
+
+<listitem><para>
+If you are using a user build of &kde; instead of a system build (for which
+you must be root to install), you can use the script to install for you. I
+haven not audited this code, and it makes ample use of the <function>system()</function>
+call, so I would not recommend running it as root at this point.
+</para></listitem>
+
+<listitem><para>
+You can use <link linkend="conf-make-install-prefix">make-install-prefix</link> to
+prefix the make install command line with a separate command, which is useful
+for sudo.
+</para></listitem>
+
+<listitem><para>
+You can use the <link linkend="conf-apidox">apidox</link> option to automatically
+build and install the API documentation for some modules.
+</para></listitem>
+
+<listitem><para>
+You can check out only a portion of a &kde; &svn; module. For example,
+you could check out only the <application>taglib</application> from
+<application>kdesupport</application>, or only <application>K3B</application> from
+<application>extragear/multimedia</application>. The script will automatically pull in
+<application>kde-common</application> if necessary to make the build work.
+</para></listitem>
+
+<listitem><para>
+You can <quote>pretend</quote> to do the operations. If you pass
+<option>--pretend</option> or <option>-p</option> on the
+command line, the script will give a very verbose description of the commands
+it is about to execute, without actually executing it.
+</para></listitem>
+
+<listitem><para>
+Support for checking out specific branches of &svn;
+modules. This work still needs to be completed, but you already select the branch you
+want to build using the <link linkend="conf-module-base-path">module-base-path
+configuration option</link>.
+</para></listitem>
+
+</itemizedlist>
+
+<para>
+Things that &kdesvn-build; does NOT do:
+</para>
+
+<itemizedlist>
+
+<listitem><para>
+Find the fastest &kde; &svn; mirror. There is not even a list shipped
+with the script at this point, although the default server should work
+fine.
+</para></listitem>
+
+<listitem><para>
+Brush your teeth. You should remember to do that yourself.
+</para></listitem>
+
+<listitem><para>
+The script probably is not bug-free. Sorry.
+</para></listitem>
+
+</itemizedlist>
+
+</chapter>
+
+<chapter id="kdesvn-buildrc">
+<title>The Format of .kdesvn-buildrc</title>
+
+<para>
+To use the script, you must have a file in your home directory called
+<filename>.kdesvn-buildrc</filename>, which describes the modules you would
+like to download and build.
+</para>
+
+
+
+<para>
+It starts with the global options, specified like the following:
+</para>
+
+<programlisting>
+global
+<replaceable>option-name option-value</replaceable>
+<replaceable>[...]</replaceable>
+end global
+</programlisting>
+
+<para>
+It is then followed by one or more module sections, specified like the
+following:
+</para>
+
+<programlisting>
+module <replaceable>module-name</replaceable>
+<replaceable>option-name option-value</replaceable>
+<replaceable>[...]</replaceable>
+end module
+</programlisting>
+
+<para>
+<replaceable>module-name</replaceable> must be a module from the &kde; &svn; repository (for
+example, kdelibs or kdebase). Some options override global options, some
+add to global options, and some global options simply can't be overridden.
+</para>
+
+<para>
+The following is an alphabetized list of options you can use. Click on the
+option to find out more about it. If one is not documented, please e-mail the
+authors using the address you can find <link linkend="authors">above</link>.
+</para>
+
+<itemizedlist>
+<listitem><para><link linkend="conf-apidox">apidox</link>, to build API Documentation</para></listitem>
+<listitem><para><link linkend="conf-apply-qt-patches">apply-qt-patches</link>, to enhance qt-copy</para></listitem>
+<listitem><para><link linkend="conf-binpath">binpath</link>, to set the <envar>PATH</envar> variable.</para></listitem>
+<listitem><para><link linkend="conf-branch">branch</link>, to checkout from a branch instead of /trunk.</para></listitem>
+<listitem><para><link linkend="conf-build-dir">build-dir</link>, to set the directory to build in.</para></listitem>
+<listitem><para><link linkend="conf-checkout-only">checkout-only</link>, to checkout only parts of a module.</para></listitem>
+<listitem><para><link linkend="conf-colorful-output">colorful-output</link> to add color to the script output.</para></listitem>
+<listitem><para><link linkend="conf-configure-flags">configure-flags</link> to define what flags to configure a module with.</para></listitem>
+<listitem><para><link linkend="conf-cxxflags">cxxflags</link> to define the <envar>CXXFLAGS</envar> variable.</para></listitem>
+<listitem><para><link linkend="conf-dest-dir">dest-dir</link> to change the directory name for a module.</para></listitem>
+<listitem><para><link linkend="conf-disable-agent-check">disable-agent-check</link>, to keep kdesvn-build from checking on ssh-agent's status.</para></listitem>
+<listitem><para><link linkend="conf-do-not-compile">do-not-compile</link>, to mark directories to skip building.</para></listitem>
+<listitem><para><link linkend="conf-inst-apps">inst-apps</link>, to only build and install some directories.</para></listitem>
+<listitem><para><link linkend="conf-install-after-build">install-after-build</link>, to avoid installing after the build process.</para></listitem>
+<listitem><para><link linkend="conf-kdedir">kdedir</link>, to set the directory to install KDE to.</para></listitem>
+<listitem><para><link linkend="conf-libpath">libpath</link>, to set the <envar>LD_LIBRARY_PATH</envar> variable.</para></listitem>
+<listitem><para><link linkend="conf-make-install-prefix">make-install-prefix</link>, to run a helper program (like sudo) during make install.</para></listitem>
+<listitem><para><link linkend="conf-make-options">make-options</link>, to pass options to the make program.</para></listitem>
+<listitem><para><link linkend="conf-manual-build">manual-build</link>, to avoid building the module automatically.</para></listitem>
+<listitem><para><link linkend="conf-manual-update">manual-update</link>, to avoid doing anything to the module automatically.</para></listitem>
+<listitem><para><link linkend="conf-module-base-path">module-base-path</link>, to change where to download the module from (useful for branches and tags).</para></listitem>
+<listitem><para><link linkend="conf-niceness">niceness</link>, to change the CPU priority.</para></listitem>
+<listitem><para><link linkend="conf-no-rebuild-on-fail">no-rebuild-on-fail</link>, to avoid running make again if it fails.</para></listitem>
+<listitem><para><link linkend="conf-qtdir">qtdir</link>, to set the path to Qt.</para></listitem>
+<listitem><para><link linkend="conf-set-env">set-env</link>, to set an environment variable.</para></listitem>
+<listitem><para><link linkend="conf-source-dir">source-dir</link>, to change where to download the source code to.</para></listitem>
+<listitem><para><link linkend="conf-stop-on-failure">stop-on-failure</link>, to make kdesvn-build stop as soon as a failure is encountered.</para></listitem>
+<listitem><para><link linkend="conf-svn-server">svn-server</link>, to change the server the sources are downloaded from.</para></listitem>
+<listitem><para><link linkend="conf-use-qt-builddir-hack">use-qt-builddir-hack</link>, to give Qt a separate build directory from its source like KDE.</para></listitem>
+<listitem><para><link linkend="conf-use-unsermake">use-unsermake</link>, to use the advanced unsermake build system.</para></listitem>
+</itemizedlist>
+
+
+<para>
+Here is a table of the various options, and some comments on them. Any
+option which overrides the global option will override a command line setting
+as well.
+</para>
+
+<table id="option-table">
+<title>Table of Options</title>
+<tgroup cols="3">
+
+<thead>
+<row>
+<entry>Option-name</entry>
+<entry>Module -&gt; Global Behavior</entry>
+<entry>Notes</entry>
+</row>
+</thead>
+
+<tbody>
+
+<row id="conf-apidox">
+<entry>apidox</entry>
+<entry>Overrides global</entry>
+<entry>Set this option to <quote>true</quote> in order to have &kdesvn-build; automatically
+build and install the API documentation for the module after the normal build/install
+process. This only works for modules where <command>make apidox</command> does something,
+including kdelibs, kdebase, and koffice, among others.
+</entry>
+</row>
+
+<row id="conf-apply-qt-patches">
+<entry>apply-qt-patches</entry>
+<entry>Overrides global</entry>
+<entry>This option is only useful for qt-copy. If it is set to a non-zero value,
+then the apply-patches script in qt-copy will be run prior to building, in
+order to apply the non-official patches to the qt-copy. Since these patches
+are normally the reason for using qt-copy instead of a stock Qt, it shouldn't
+do any harm to enable it. The default is to enable the patches.</entry>
+</row>
+
+<row id="conf-binpath">
+<entry>binpath</entry>
+<entry>Can't be overridden</entry>
+<entry><para>Set this option to set the environment variable PATH while building.
+You can't override this setting in a module option. The default value is
+<filename class="directory">/bin:/usr/bin:/usr/local/bin:/usr/X11R6/bin</filename>. This environment
+variable should include the colon-separated paths of your development
+toolchain. The paths <filename class="directory">$KDEDIR/bin</filename> and
+<filename class="directory">$QTDIR/bin</filename> are automatically added. You
+may use the tilde (~) for any paths you add using this option.</para>
+</entry>
+</row>
+
+<row id="conf-branch">
+<entry>branch</entry>
+<entry>Overrides global</entry>
+<entry><para>Set this option to checkout from a branch of KDE instead of the
+default of "trunk", where KDE development occurs. For instance, to checkout
+KDE 3.4 branch, you would set this option to "3.4".</para>
+<para>Note that some modules use a different branch name. Notably, the
+required arts module doesn't go by KDE version numbers. The arts that
+accompanied KDE 3.4 was version 1.4.</para>
+<para>If kdesvn-build fails to properly download a branch with this option, you
+may have to manually specify the URL to download from using the <link
+linkend="conf-override-url">override-url</link> option.</para>
+</entry>
+</row>
+
+<row id="conf-build-dir">
+<entry>build-dir</entry>
+<entry>Overrides global</entry>
+<entry>Use this option to change the directory to contain the built sources. There
+are three different ways to use it:
+<itemizedlist>
+
+<listitem><para>Relative to the &kde; &svn; source directory (see <link
+linkend="conf-source-dir">the source-dir option</link>). This is the default, and
+the way the script worked up to version v0.61. This mode is selected if you
+type a directory name that doesn't start with a tilde (~) or a slash (/).</para>
+<para>The default value is <filename class="directory">build</filename>.</para></listitem>
+
+<listitem><para>Absolute path. If you specify a path that begins with a /, then that path
+is used directly. For example, <filename class="directory">/tmp/kde-obj-dir/</filename>.</para></listitem>
+
+<listitem><para>Relative to your home directory. If you specify a path that begins with a
+~, then the path is used relative to your home directory, analogous to the
+shell's tilde-expansion. For example, <filename class="directory">~/builddir</filename> would set the build
+directory to <filename class="directory">/home/user-name/builddir</filename>.</para></listitem>
+
+</itemizedlist>
+
+Perhaps surprisingly, this option can be changed per module.
+
+</entry>
+</row>
+
+<row id="conf-checkout-only">
+<entry>checkout-only</entry>
+<entry>Overrides global</entry>
+<entry>Set this option to checkout &svn; sources piece by piece. The value
+for this option should be a space separated list of directories to checkout.
+If you don't include the admin directory, it will automatically be included (if
+necessary). When checking out piece by piece, the admin directory will be
+pulled in from kde-common, which is where it exists on the &svn; server.
+Although this option overrides the global option, be aware that setting this as
+a global option makes no sense.
+</entry>
+</row>
+
+<row id="conf-configure-flags">
+<entry>configure-flags</entry>
+<entry>Appends to global option(except for qt-copy)</entry>
+<entry>Use this option to specify what flags to pass to ./configure when creating
+the build system for the module. When this is used as a global-option, it is
+applied to all modules that this script builds. qt-copy uses a much different
+set of configure options than the rest of &kde;, so this option
+<emphasis>overrides</emphasis> the global settings when applied to qt-copy.</entry>
+</row>
+
+<row id="conf-colorful-output">
+<entry>colorful-output</entry>
+<entry>Can't be overridden</entry>
+<entry>Set this option to false to disable the colorful output of &kdesvn-build;.
+This option defaults to <quote>true</quote>. Note that &kdesvn-build; won't output the
+color codes to anything but a terminal (such as xterm, &konsole;, or the normal
+Linux console).
+</entry>
+</row>
+
+<row id="conf-cxxflags">
+<entry>cxxflags</entry>
+<entry>Appends to global option</entry>
+<entry>Use this option to specify what flags to pass to <command>./configure</command> as the
+<envar>CXXFLAGS</envar> when creating the build system for the module. This option is
+specified here instead of with <link
+linkend="conf-configure-flags">configure-flags</link> because this option will also
+set the environment variable <envar>CXXFLAGS</envar> during the build process.
+</entry>
+</row>
+
+<row id="conf-dest-dir">
+<entry>dest-dir</entry>
+<entry>Overrides global</entry>
+<entry>Use this option to change the name a module is given on disk. For
+example, if your module was extragear/network, you could rename it to
+extragear-network using this option.
+</entry>
+</row>
+
+<row id="conf-disable-agent-check">
+<entry>disable-agent-check</entry>
+<entry>Can't be overridden</entry>
+<entry>Normally if you're using SSH to download the Subversion sources (such as
+if you're using the svn+ssh protocol), kdesvn-build will try and make sure that
+if you're using ssh-agent, it is actually managing some SSH identities. This is
+to try and prevent SSH from asking for your passphrase for every module. You can
+disable this check by setting disable-agent-check to true.
+</entry>
+</row>
+
+<row id="conf-do-not-compile">
+<entry>do-not-compile</entry>
+<entry>Overrides global</entry>
+<entry><para>Use this option to set the <envar>DO_NOT_COMPILE</envar> environment variable prior to
+running the configure script. According to the <ulink
+url="http://developer.kde.org/documentation/other/developer-faq.html">&kde;
+Developer FAQ</ulink>, this should cause any toplevel directory you pass to not be
+built. The directories should be space-separated.</para>
+
+<para>Note that the sources to the programs will still be downloaded. You can use
+the <link linkend="conf-checkout-only">checkout-only</link>
+directive to choose directories that you want to check out.</para>
+</entry>
+</row>
+
+<row id="conf-email-address">
+<entry>email-address</entry>
+<entry>Can't be overridden</entry>
+<entry>
+<para>Set this option to the e-mail address kdesvn-build should send from should
+it ever need to send e-mail. You do not need to worry about this if you don't
+use any feature which send e-mail. (They are all disabled by default).
+</para>
+
+<para>Currently only <link linkend="conf-email-on-compile-error">email-on-compile-error</link>
+needs this option.
+</para>
+</entry>
+</row>
+
+<row id="conf-email-on-compile-error">
+<entry>email-on-compile-error</entry>
+<entry>Can't be overridden</entry>
+<entry>
+<para>You can set this option to the email address to send a report to when a
+module fails to build. kdesvn-build will wait until all the modules are done
+and collate all of the results in the report. The report is only sent if a
+module fails to build.
+</para>
+
+<para>Please see the <link linkend="conf-email-address">email-address</link>
+option to set the address kdesvn-build should send from, since the default
+is usually not what you want.
+</para>
+</entry>
+</row>
+
+<row id="conf-inst-apps">
+<entry>inst-apps</entry>
+<entry>Overrides global</entry>
+<entry><para>This is the opposite of the <link
+linkend="conf-do-not-compile">do-not-compile</link> option. This option makes it
+so that only the given toplevel directories are built. The directories should
+be space-separated.</para>
+
+<para>Any changes don't take effect until the next time
+<command>make <option>-f</option> Makefile.cvs</command> is
+run, either automatically by the script, or manually by the <link
+linkend="cmdline-refresh-build"><option>--refresh-build</option></link> or <link
+linkend="cmdline-recreate-configure"><option>--recreate-configure</option></link> options.
+</para>
+
+<para>Note that the sources to the programs will still be downloaded. You can use
+the <link linkend="conf-checkout-only">checkout-only</link>
+directive to choose directories that you want to check out.</para>
+</entry>
+</row>
+
+<row id="conf-install-after-build">
+<entry>install-after-build</entry>
+<entry>Overrides global</entry>
+<entry>This option is used to install the package after it successfully builds.
+This option is enabled by default. If you want to disable this, you need to
+set this option to 0 in the configuration file. You can also use the
+<link linkend="cmdline-no-install"><option>--no-install</option></link> command line flag.
+</entry>
+</row>
+
+<row id="conf-kdedir">
+<entry>kdedir</entry>
+<entry>Can't be overridden</entry>
+<entry>This option sets the directory that &kde; will be installed to after it is
+built. It defaults to <filename class="directory">~/kde</filename>. If you change this to a directory
+needing root access, you may want to read about the <link
+linkend="conf-make-install-prefix">make-install-prefix</link> option as well.</entry>
+</row>
+
+<row id="conf-libpath">
+<entry>libpath</entry>
+<entry>Can't be overridden</entry>
+<entry>Set this option to set the environment variable LD_LIBRARY_PATH while
+building. You can't override this setting in a module option. The default
+value is blank, but the paths <filename class="directory">$KDEDIR/lib</filename> and
+<filename class="directory">$QTDIR/lib</filename> are automatically
+added. You may use the tilde (~) for any paths you add using this option.
+</entry>
+</row>
+
+<row id="conf-log-dir">
+<entry>log-dir</entry>
+<entry>Overrides global</entry>
+<entry>Use this option to change the directory used to hold the log files
+generated by the script. This setting can be set on a per-module basis as of
+version 0.64 or later.
+</entry>
+</row>
+
+<row id="conf-make-install-prefix">
+<entry>make-install-prefix</entry>
+<entry>Overrides global</entry>
+<entry>Set this variable to a space-separated list, which is interpreted as a
+command and its options to precede the make install command used to install
+modules. This is useful for installing packages with sudo for example, but
+please be careful while dealing with root privileges.</entry>
+</row>
+
+<row id="conf-make-options">
+<entry>make-options</entry>
+<entry>Overrides global</entry>
+<entry>Set this variable in order to pass command line options to the make
+command. This is useful for programs such as <ulink
+url="http://distcc.samba.org/"><application>distcc</application></ulink>.
+<application>distcc</application> allows you to share your
+compilation work among more than one computer. To use it, you must use the
+<option>-j</option> option to make. Now you can. According to the docs, 2 *
+number_of_network_cpus is recommended. I have 1 CPU total, so it would be
+<option>-j2</option> in my case.</entry>
+</row>
+
+<row id="conf-manual-build">
+<entry>manual-build</entry>
+<entry>Overrides global</entry>
+<entry>Set the option value to <quote>true</quote> to keep the build process from attempting to
+build this module. It will still be kept up-to-date when updating from &svn;.
+This option is exactly equivalent to the <link
+linkend="cmdline-no-build"><option>--no-build</option></link> command line option.
+</entry>
+</row>
+
+<row id="conf-manual-update">
+<entry>manual-update</entry>
+<entry>Overrides global</entry>
+<entry>Set the option value to <quote>true</quote> to keep the build process from attempting to
+update (and by extension, build or install) this module. If you set this
+option for a module, then you have pretty much commented it out.
+</entry>
+</row>
+
+<row id="conf-module-base-path">
+<entry>module-base-path</entry>
+<entry>Overrides global</entry>
+<entry><para>Set this option to override &kdesvn-build;'s default directory path to the
+module in question. This can be used, for example, to pull specific branches
+or tagged versions of libraries. <ulink url="http://websvn.kde.org/">The &kde;
+Source Viewer</ulink> is invaluable in helping to pick the right path.</para>
+<para>Note that &kdesvn-build; constructs the final path according to the
+following template:
+<varname>$svn-server</varname>/home/kde/<varname>$module-base-path</varname>/<varname>$module-name</varname>.
+</para>
+<para>The default value is either <quote>trunk</quote> or
+<quote>trunk/KDE</quote>, depending on the modulename.</para>
+</entry>
+</row>
+
+<row id="conf-niceness">
+<entry>niceness</entry>
+<entry>Can't be overridden</entry>
+<entry>Set this option to a number between 20 and 0. The higher the number, the
+lower a priority &kdesvn-build; will set for itself. The default is 10.
+</entry>
+</row>
+
+<row id="conf-no-rebuild-on-fail">
+<entry>no-rebuild-on-fail</entry>
+<entry>Overrides global</entry>
+<entry>Set this option value to <quote>true</quote> to always prevent &kdesvn-build; from trying
+to rebuild this module if it should fail an incremental build. Normally
+&kdesvn-build; will try to rebuild the module from scratch to counteract the
+effect of a stray &svn; update messing up the build system.</entry>
+</row>
+
+<row id="conf-override-url">
+<entry>override-url</entry>
+<entry>Overrides global</entry>
+<entry>If you set this option, kdesvn-build will use its value as the URL
+to pass to Subversion <emphasis>completely unchanged</emphasis>. You should
+generally use this if you want to download a specific release but kdesvn-build
+can't figure out what you mean using <link linkend="conf-branch">branch</link>.
+</entry>
+</row>
+
+<row id="conf-qtdir">
+<entry>qtdir</entry>
+<entry>Can't be overridden</entry>
+<entry>Set this option to set the environment variable QTDIR while building.
+You can't override this setting in a module option. If you don't specify
+this option, it defaults to
+<filename class="directory"><varname>$(source-dir)</varname>/build/qt-copy</filename>,
+which uses the qt-copy module included in the &kde; source repository.
+You may use a tilde (~) to represent your home directory.
+</entry>
+</row>
+
+<row id="conf-remove-after-install">
+<entry>remove-after-install</entry>
+<entry>Overrides global</entry>
+<entry><para>If you are low on hard disk space, you may want to use this option
+in order to automatically delete the build directory (or both the source and
+build directories for one-time installs) after the module is successfully
+installed.
+</para>
+<para>Possible values for this option are:
+<itemizedlist>
+<listitem><para>none - Do not delete anything (This is the default).</para></listitem>
+<listitem><para>builddir - Delete the build directory, but not the source.</para></listitem>
+<listitem><para>all - Delete both the source code and build directory.</para></listitem>
+</itemizedlist>
+</para>
+
+<para>Note that using this option can have a significant detrimental impact on
+both your bandwidth usage (if you use 'all') and the time taken to compile KDE,
+since kdesvn-build will be unable to perform incremental builds.</para>
+</entry>
+</row>
+
+<row id="conf-set-env">
+<entry>set-env</entry>
+<entry>Overrides global</entry>
+<entry><para>This option accepts a space-separated set of values, where the first value
+is the environment variable to set, and the rest of the values is what you
+want the variable set to. For example, to set the variable RONALD to
+McDonald, you would put in the appropriate section this command:</para>
+<screen><command>set-env</command> <envar>RONALD</envar> <userinput>McDonald</userinput></screen>
+<para>This option is special in that it can be repeated without overriding
+earlier set-env settings in the same section of the configuration file. This
+way you can set more than one environment variable per module (or
+globally).</para>
+</entry>
+</row>
+
+<row id="conf-source-dir">
+<entry>source-dir</entry>
+<entry>Can't be overridden</entry>
+<entry>This option is used to set the directory on your computer to store the &kde;
+&svn; sources at. If you don't specify this value, the default is
+<filename class="directory">~/kdesvn</filename>. If
+you do specify this value, use an absolute path name.
+</entry>
+</row>
+
+<row id="conf-svn-server">
+<entry>svn-server</entry>
+<entry>Can't be overridden</entry>
+<entry>This option is used to set the server used to check out from &svn;.
+The default is the anonymous &svn; repository, <emphasis>svn://anonsvn.kde.org/</emphasis></entry>
+</row>
+
+<row id="conf-stop-on-failure">
+<entry>stop-on-failure</entry>
+<entry>Overrides global</entry>
+<entry>Set this option value to <quote>true</quote> to cause the script to stop execution
+after an error occurs during the build or install process. This option is off
+by default.
+</entry>
+</row>
+
+<row id="conf-tag">
+<entry>tag</entry>
+<entry>Overrides global</entry>
+<entry><para>Use this option to download a specific release of a module.</para>
+<para><emphasis>NOTE:</emphasis> The odds are very good that you DO NOT WANT
+to use this option. KDE releases are available in tarball form from <ulink
+url="ftp://ftp.kde.org/">The KDE FTP site</ulink> or one of <ulink
+url="http://download.kde.org/download.php">its mirrors</ulink>.</para>
+<para>If you are using kdesvn-build because you have having trouble getting
+a KDE release to build on your distribution, consider using the <ulink
+url="http://developer.kde.org/build/konstruct/">Konstruct build tool</ulink>
+instead, which works from the release tarballs.</para>
+</entry>
+</row>
+
+<row id="conf-use-qt-builddir-hack">
+<entry>use-qt-builddir-hack</entry>
+<entry>Overrides global</entry>
+<entry>Although this option overrides the global option, it only makes sense for
+qt-copy. Set this option to <quote>true</quote> to enable the script's
+<emphasis>experimental</emphasis> srcdir != builddir mode. When enabled,
+&kdesvn-build; will copy the qt-copy source module to the build directory,
+and perform builds from there. That means your QTDIR environment variable
+should be set to
+<filename class="directory">$(qt-copy-build-dir)/qt-copy/lib</filename>
+instead. You should also change your <link linkend="conf-qtdir">qtdir</link>
+option accordingly. Incremental make should still work in this mode, as the
+timestamps will be preserved after the copy. If you use the
+<link linkend="conf-apply-qt-patches">apply-qt-patches</link> option, the patches
+will be applied in the build directory, not the source directory.
+This option defaults to <quote>true</quote>.
+</entry>
+</row>
+
+<row id="conf-use-unsermake">
+<entry>use-unsermake</entry>
+<entry>Overrides global</entry>
+<entry><para>Set this option to <quote>true</quote> in order to use the
+experimental unsermake program instead of automake when running the configure
+script. This can lead to some serious decreases in build time, especially for
+<ulink url="http://www.csh.rit.edu/slashdot/distcc.html">distributed building
+systems</ulink>. This option defaults to <quote>true</quote> (for most modules).
+</para>
+
+<para>Normally if you use this option kdesvn-build will automatically keep
+unsermake up-to-date. This may start to get annoying, especially if you are
+managing unsermake yourself. If this is the case, you can set this option to
+<quote>self</quote>, and kdesvn-build will still use unsermake, but will not
+do anything special to keep it updated.
+</para>
+</entry>
+</row>
+
+</tbody>
+
+</tgroup>
+</table>
+
+</chapter>
+
+<chapter id="cmdline">
+<title>Command Line Options and Environment Variables</title>
+
+<para>
+This script doesn't use environment variables. If you need to set environment
+variables for the build or install process, please see the <link
+linkend="conf-set-env">set-env</link> option.
+</para>
+
+<para>
+The script accepts the following command-line options:
+</para>
+
+<variablelist>
+
+<varlistentry id="cmdline-help">
+<term><option>--help</option></term>
+<listitem><para>
+only display simple help on this script.
+</para></listitem>
+</varlistentry>
+
+<varlistentry id="cmdline-version">
+<term><option>--version</option></term>
+<listitem><para>
+display the program version.
+</para></listitem>
+</varlistentry>
+
+<varlistentry id="cmdline-author">
+<term><option>--author</option></term>
+<listitem><para>
+display contact information for the
+author.
+</para></listitem>
+</varlistentry>
+
+<varlistentry id="cmdline-color">
+<term><option>--color</option></term>
+<listitem><para>
+enable colorful output.
+</para></listitem>
+</varlistentry>
+
+<varlistentry id="cmdline-no-color">
+<term><option>--no-color</option></term>
+<listitem><para>
+disable colorful output.
+</para></listitem>
+</varlistentry>
+
+<varlistentry id="cmdline-pretend">
+<term><option>--pretend</option> (or <option>-p</option>)</term>
+<listitem><para>
+don't actually DO anything, but act like you did.
+</para></listitem>
+</varlistentry>
+
+<varlistentry id="cmdline-quiet">
+<term><option>--quiet</option> (or <option>-q</option>)</term>
+<listitem><para>
+Don't be as noisy with the output. With this switch only the basics are
+output.
+</para></listitem>
+</varlistentry>
+
+<varlistentry id="cmdline-really-quiet">
+<term><option>--really-quiet</option></term>
+<listitem><para>
+Only output warnings and errors.
+</para></listitem>
+</varlistentry>
+
+<varlistentry id="cmdline-verbose">
+<term><option>--verbose</option></term>
+<listitem><para>
+Be very descriptive about what's going on, and what kdesvn-build is doing.
+</para></listitem>
+</varlistentry>
+
+<varlistentry id="cmdline-svn-only">
+<term><option>--svn-only</option></term>
+<listitem><para>
+only perform the source update.
+</para></listitem>
+</varlistentry>
+
+<varlistentry id="cmdline-build-only">
+<term><option>--build-only</option></term>
+<listitem><para>
+only perform the build process.
+</para></listitem>
+</varlistentry>
+
+<varlistentry id="cmdline-ignore-modules">
+<term><option>--ignore-modules</option></term>
+<listitem><para>
+don't include the modules passed on the rest of the command line in the update/build
+process.
+</para></listitem>
+</varlistentry>
+
+<varlistentry id="cmdline-no-svn">
+<term><option>--no-svn</option></term>
+<listitem><para>
+skip contacting the &svn; server.
+</para></listitem>
+</varlistentry>
+
+<varlistentry id="cmdline-no-build">
+<term><option>--no-build</option></term>
+<listitem><para>
+skip the build process.
+</para></listitem>
+</varlistentry>
+
+<varlistentry id="cmdline-no-install">
+<term><option>--no-install</option></term>
+<listitem><para>
+don't automatically install packages after they're built.
+</para></listitem>
+</varlistentry>
+
+<varlistentry id="cmdline-debug">
+<term><option>--debug</option></term>
+<listitem><para>
+enables debug mode for the script. Currently
+this means that all output will be dumped to STDOUT in addition to being
+logged in the log directory like normal. Also, many functions are much more
+verbose about what they're doing in debugging mode.
+</para></listitem>
+</varlistentry>
+
+<varlistentry id="cmdline-no-rebuild-on-fail">
+<term><option>--no-rebuild-on-fail</option></term>
+<listitem><para>
+don't try and
+rebuild modules that have failed building from scratch. &kdesvn-build; will
+never try to do this to a module that already was tried to be built from
+scratch.
+</para></listitem>
+</varlistentry>
+
+<varlistentry id="cmdline-refresh-build">
+<term><option>--refresh-build</option></term>
+<listitem><para>
+recreate the build system and make from scratch.
+</para></listitem>
+</varlistentry>
+
+<varlistentry id="cmdline-reconfigure">
+<term><option>--reconfigure</option></term>
+<listitem><para>
+run the configure script again
+without cleaning the build directory.
+</para></listitem>
+</varlistentry>
+
+<varlistentry id="cmdline-recreate-configure">
+<term><option>--recreate-configure</option></term>
+<listitem><para>
+run <command>make <option>-f</option>
+Makefile.cvs</command> again to create the configure script, and continue
+building as normal. This option implies <option><link linkend="cmdline-reconfigure">--reconfigure</link></option>.
+</para></listitem>
+</varlistentry>
+
+<varlistentry id="cmdline-resume">
+<term><option>--resume</option></term>
+<listitem><para>
+which tries to continue building from where
+the script stopped last time. The script starts building the module after the
+last module to be compiled last time the script was run, whether or not it
+succeeded. This option implies <link linkend="cmdline-no-svn"><option>--no-svn</option></link>. You
+should not specify other module names on the command line.
+</para></listitem>
+</varlistentry>
+
+<varlistentry id="cmdline-resume-from">
+<term><option>--resume-from</option></term>
+<listitem><para>
+which is like <link linkend="cmdline-resume"><option>--resume</option></link>, except that you supply
+the module to start building from as the next parameter on the command line. This option
+implies <link linkend="cmdline-no-svn"><option>--no-svn</option></link>. You should not specify
+other module names on the command line.
+</para></listitem>
+</varlistentry>
+
+<varlistentry id="cmdline-rc-file">
+<term><option>--rc-file</option></term>
+<listitem><para>
+which interprets the next command line
+parameter as the file to read the configuration options from. The default
+value for this parameter is ~/.kdesvn-buildrc.
+</para></listitem>
+</varlistentry>
+
+<varlistentry id="cmdline-prefix">
+<term><option>--prefix=&lt;/path/to/kde&gt;</option></term>
+<listitem><para>
+which allows you to change the directory that &kde; will be installed to from the command line.
+This option implies <link linkend="cmdline-reconfigure"><option>--reconfigure</option></link>.
+</para></listitem>
+</varlistentry>
+
+<varlistentry id="cmdline-build-system-only">
+<term><option>--build-system-only</option></term>
+<listitem><para>
+stop after running <command>make <option>-f</option> Makefile.cvs</command>. The configure
+script will still need to be run, which &kdesvn-build; will do next time. This lets you
+prepare all the configure scripts at once so you can view the <command>./configure
+<option>--help</option></command> for each module, and edit your configure-flags accordingly.
+</para></listitem>
+</varlistentry>
+
+<varlistentry id="cmdline-install"><term><option>--install</option></term>
+<listitem><para>
+If this is the only command-line option, it tries to install all of the modules contained in
+successfully-built, except for qt-copy, which doesn't need installation. If command-line
+options are specified after <option>--install</option>, they are all assumed to be modules to install.
+</para></listitem>
+</varlistentry>
+
+<varlistentry id="cmdline-global-option">
+<term><option>--&lt;option-name&gt;=</option></term>
+<listitem><para>
+You can use this option to override an option in your configuration file for
+every module. For instance, to override the <link
+linkend="conf-log-dir">log-dir</link> option, you would do:
+<option>--log-dir=/path/to/dir</option>.
+</para></listitem>
+</varlistentry>
+
+<varlistentry id="cmdline-module-option">
+<term><option>--&lt;module-name&gt;,&lt;option-name&gt;=</option></term>
+<listitem><para>
+You can use this option to override an option in your configuration file for
+a specific module. For instance, to override the <link
+linkend="conf-use-unsermake">use-unsermake</link> option for kdemultimedia, you
+would do: <option>--kdemultimedia,use-unsermake=false</option>.
+</para></listitem>
+</varlistentry>
+
+</variablelist>
+
+<para>
+Any other command-line options are assumed to be modules to update and build.
+Please, don't mix building with installing.
+</para>
+
+</chapter>
+
+<chapter id="credits-and-licenses">
+<title>Credits And Licenses</title>
+
+&underFDL;
+
+</chapter>
+
+</book>
diff --git a/doc/scripts/man-adddebug.1.docbook b/doc/scripts/man-adddebug.1.docbook
new file mode 100644
index 00000000..9069b486
--- /dev/null
+++ b/doc/scripts/man-adddebug.1.docbook
@@ -0,0 +1,66 @@
+<?xml version="1.0" ?>
+<!DOCTYPE refentry PUBLIC "-//KDE//DTD DocBook XML V4.2-Based Variant V1.1//EN" "dtd/kdex.dtd" [
+<!ENTITY % English "INCLUDE">
+]>
+
+<refentry lang="&language;">
+<refentryinfo>
+<author><personname><firstname>Ben</firstname><surname>Burton</surname></personname>
+<email>bab@debian.org</email></author>
+<date>March 7, 2003</date>
+</refentryinfo>
+
+<refmeta>
+<refentrytitle><command>addebug</command></refentrytitle>
+<manvolnum>1</manvolnum>
+</refmeta>
+
+<refnamediv>
+<refname><command>addebug</command></refname>
+<refpurpose>Modifies <filename>Makefile</filename>(s) to add debug info</refpurpose>
+</refnamediv>
+
+<refsynopsisdiv>
+<cmdsynopsis>
+<command>adddebug</command>
+<group><option>-k</option></group>
+<group><option>-r</option></group>
+<group><option>-n</option></group>
+</cmdsynopsis>
+</refsynopsisdiv>
+
+<refsect1>
+<title>Description</title>
+
+<para><command>adddebug</command> modifies the
+<filename>Makefile</filename> in the current directory (and optionally
+in its subdirectories) to add debug info (<option>-g3</option>). It
+will also remove optimisations (<option>-O[1-9]</option>).</para>
+
+<para>This utility is part of the &kde; Software Development Kit.</para>
+
+</refsect1>
+
+<refsect1>
+<title>Options</title>
+
+<variablelist>
+<varlistentry>
+<term><option>-k</option></term>
+<listitem><para>Keep optimisations (do not remove <option>-O[1-9]?</option> flags which are removed by default).</para>
+</listitem>
+</varlistentry>
+<varlistentry>
+<term><option>-r</option></term>
+<listitem>
+<para>Recursively search through all subdirectories of the current directory and operate on every <filename>Makefile</filename> that is found. </para>
+</listitem>
+</varlistentry>
+<varlistentry>
+<term><option>-n</option></term>
+<listitem><para>compile without NDEBUG and NO_DEBUG being defined (makes <function>kdDebug</function> calls work)</para></listitem>
+</varlistentry>
+</variablelist>
+</refsect1>
+
+</refentry>
diff --git a/doc/scripts/man-cheatmake.1.docbook b/doc/scripts/man-cheatmake.1.docbook
new file mode 100644
index 00000000..4fdb9498
--- /dev/null
+++ b/doc/scripts/man-cheatmake.1.docbook
@@ -0,0 +1,103 @@
+<?xml version="1.0" ?>
+<!DOCTYPE refentry PUBLIC "-//KDE//DTD DocBook XML V4.2-Based Variant V1.1//EN" "dtd/kdex.dtd" [
+<!ENTITY % English "INCLUDE">
+]>
+
+<refentry lang="&language;">
+<refentryinfo>
+<date>March 8, 2003</date>
+</refentryinfo>
+
+<refmeta>
+<refentrytitle><command>cheatmake</command></refentrytitle>
+<manvolnum>1</manvolnum>
+</refmeta>
+
+<refnamediv>
+<refname><command>cheatmake</command></refname>
+<refpurpose>fool <command>make</command> into not rebuilding certain files</refpurpose>
+</refnamediv>
+
+<refsynopsisdiv>
+<cmdsynopsis>
+<command>cheatmake</command>
+
+<group><option>hidechange</option> <replaceable>file</replaceable></group>
+<group><option>show</option></group>
+<group><option>why</option> <replaceable>file</replaceable></group>
+</cmdsynopsis>
+</refsynopsisdiv>
+
+<refsect1>
+<title>Description</title>
+
+<para><command>cheatmake</command> is used to save time when
+recompiling. It can fool make into skipping files that haven't changed
+in a meaningful way. This can be used for instance when you change a
+comment in a file but none of the actual code.</para>
+
+<para>This utility is part of the &kde; Software Development Kit. </para>
+
+</refsect1>
+
+<refsect1>
+<title>Options</title>
+
+<variablelist>
+<varlistentry>
+<term><option>hidechange</option> <replaceable>file</replaceable></term>
+<listitem><para>Hides the fact that file was changed by setting the timestamp into the past. Use with care!</para>
+</listitem>
+</varlistentry>
+<varlistentry>
+<term><option>show</option></term>
+<listitem><para>Lists what files <command>make</command> currently needs to rebuild</para></listitem>
+</varlistentry>
+<varlistentry>
+<term><option>why</option> <replaceable>file</replaceable></term>
+<listitem><para>Explains why make must rebuild file</para></listitem>
+</varlistentry>
+</variablelist>
+</refsect1>
+
+<refsect1>
+<title>Environment</title>
+
+<para>One of the following variables (but not both) should be set if
+the source directory is different from the build directory. If the
+build directory is simply a subdirectory of the source directory, the
+simpler variable <envar>OBJ_SUBDIR</envar> should be used. </para>
+
+<variablelist>
+<varlistentry>
+<term><envar>OBJ_SUBJDIR</envar></term>
+<listitem><para>Indicates that the build directory is in the given subdirectory of the source directory. For instance, if the source directory is <filename class="directory">kdesdk</filename> and the build directory is <filename class="directory">kdesdk/obj-i386-linux</filename>, then <envar>OBJ_SUBDIR</envar> should be set to <parameter>obj-i386-linux</parameter>.</para></listitem>
+</varlistentry>
+<varlistentry>
+<term><envar>OBJ_REPLACEMENT</envar></term>
+<listitem><para>A <command>sed</command> expression that is used to transform the source directory into the build directory. For instance, if the source directory is <filename class="directory">kdesdk/obj-i386-linux</filename>, then <envar>OBJ_REPLACEMENT</envar> should be set to <parameter>s#kdesdk#kdesdk-obj#</parameter>.</para>
+</listitem>
+</varlistentry>
+</variablelist>
+
+</refsect1>
+
+<refsect1>
+<title>See Also</title>
+
+<para>make(1)</para>
+
+</refsect1>
+
+<refsect1>
+<title>Authors</title>
+
+<para><command>cheatmake</command> was written by &David.Faure; &David.Faure.mail;. This manual page was
+prepared by <personname><firstname>Ben</firstname><surname>Burton</surname></personname>
+<email>bab@debian.org</email> for the Debian
+<acronym>GNU</acronym>/&Linux; system (but may be used by
+others).</para>
+
+</refsect1>
+
+</refentry>
diff --git a/doc/scripts/man-create_cvsignore.1.docbook b/doc/scripts/man-create_cvsignore.1.docbook
new file mode 100644
index 00000000..1433d4ea
--- /dev/null
+++ b/doc/scripts/man-create_cvsignore.1.docbook
@@ -0,0 +1,50 @@
+<?xml version="1.0" ?>
+<!DOCTYPE refentry PUBLIC "-//KDE//DTD DocBook XML V4.2-Based Variant V1.1//EN" "dtd/kdex.dtd" [
+<!ENTITY kdeoptions SYSTEM "kdeoptions.docbook">
+<!ENTITY qtoptions SYSTEM "qtoptions.docbook">
+<!ENTITY % English "INCLUDE">
+]>
+
+<refentry lang="&language;">
+<refentryinfo>
+<author><personname><firstname>Ben</firstname><surname>Burton</surname></personname>
+<email>bab@debian.org</email></author>
+<date>March 8, 2003</date>
+</refentryinfo>
+
+<refmeta>
+<refentrytitle><command>create_cvsignore</command></refentrytitle>
+<manvolnum>1</manvolnum>
+</refmeta>
+
+<refnamediv>
+<refname><command>create_cvsignore</command></refname>
+<refpurpose>Create preliminary .cvsignore in the current directory</refpurpose>
+</refnamediv>
+
+<refsynopsisdiv>
+<cmdsynopsis>
+<command>createcvsignore</command>
+</cmdsynopsis>
+</refsynopsisdiv>
+
+<refsect1>
+<title>Description</title>
+
+<para><command>create_cvsignore</command> is used to create a
+preliminary <filename>.cvsignore</filename> in the current directory.
+It does this based on certain contents it finds in
+<filename>Makefile.am</filename></para>
+
+<para>No lines will be removed from any existing
+<filename>.cvsignore</filename>. If there is not already a
+<filename>.cvsignore</filename> file, it will be added to the cvs
+repository.</para>
+
+<para>Note that you must have a <filename>Makefile.am</filename> in the current directory for this tool to work.</para>
+
+<para>This utility is part of the &kde; Software Development Kit.</para>
+
+</refsect1>
+
+</refentry> \ No newline at end of file
diff --git a/doc/scripts/man-create_makefile.1.docbook b/doc/scripts/man-create_makefile.1.docbook
new file mode 100644
index 00000000..553e2512
--- /dev/null
+++ b/doc/scripts/man-create_makefile.1.docbook
@@ -0,0 +1,94 @@
+<?xml version="1.0" ?>
+<!DOCTYPE refentry PUBLIC "-//KDE//DTD DocBook XML V4.2-Based Variant V1.1//EN" "dtd/kdex.dtd" [
+<!ENTITY kdeoptions SYSTEM "kdeoptions.docbook">
+<!ENTITY qtoptions SYSTEM "qtoptions.docbook">
+<!ENTITY % English "INCLUDE">
+]>
+
+<refentry lang="&language;">
+<refentryinfo>
+<date>March 8, 2003</date>
+</refentryinfo>
+
+<refmeta>
+<refentrytitle><command>create_makefile</command></refentrytitle>
+<manvolnum>1</manvolnum>
+</refmeta>
+
+<refnamediv>
+<refname><command>create_makefile</command></refname>
+<refpurpose>Creates <filename>Makefile.in</filename> and <filename>Makefile</filename> from a <filename>Makefile.am</filename></refpurpose>
+</refnamediv>
+
+<refsynopsisdiv>
+<cmdsynopsis>
+<command>create_makefile</command>
+<group><replaceable>relativepath/Makefile</replaceable></group>
+<group><replaceable>relativepath</replaceable></group>
+</cmdsynopsis>
+</refsynopsisdiv>
+
+<refsect1>
+<title>Description</title>
+
+<para><command>create_makefile</command> creates the
+<filename>Makefile.in</filename> and <filename>Makefile</filename> in
+a subdirectory containing a <filename>Makefile.am</filename>. This
+script saves time compared to re-running configure completely</para>
+
+<para>Note that you must supply the path to the desired
+<filename>Makefile</filename> <filename>Makefile.am</filename> (though
+the final <filename>/Makefile</filename> may be omitted).</para>
+
+<para>This script may be run from the toplevel directory (the one
+containing <filename>configure</filename> or from one of it's
+subdirectories.</para>
+
+<para>If the source directory is different from the build directory
+(see the environment variables below), it will be assumed that the
+<filename>Makefile.am</filename> and <filename>Makefile.in</filename>
+belong beneath the source directory and that the
+<filename>Makefile</filename> belongs beneath the build
+directory. </para>
+
+<para>This utility is part of the &kde; Software Development Kit.</para>
+
+</refsect1>
+
+<refsect1>
+<title>Environment</title>
+
+<para>One of the following variables (but not both) should be set if
+the source directory is different from the build directory. If the
+build directory is simply a subdirectory of the source directory, the
+simpler variable <envar>OBJ_SUBDIR</envar> should be used. </para>
+
+<variablelist>
+<varlistentry>
+<term><envar>OBJ_SUBJDIR</envar></term>
+<listitem><para>Indicates that the build directory is in the given subdirectory of the source directory. For instance, if the source directory is <filename class="directory">kdesdk</filename> and the build directory is <filename class="directory">kdesdk/obj-i386-linux</filename>, then <envar>OBJ_SUBDIR</envar> should be set to <parameter>obj-i386-linux</parameter>.</para></listitem>
+</varlistentry>
+<varlistentry>
+<term><envar>OBJ_REPLACEMENT</envar></term>
+<listitem><para>A <command>sed</command> expression that is used to transform the source directory into the build directory. For instance, if the source directory is <filename class="directory">kdesdk/obj-i386-linux</filename>, then <envar>OBJ_REPLACEMENT</envar> should be set to <parameter>s#kdesdk#kdesdk-obj#</parameter>.</para>
+</listitem>
+</varlistentry>
+</variablelist>
+
+</refsect1>
+
+<refsect1>
+<title>See Also</title>
+
+<para>create_makefiles(1)</para>
+</refsect1>
+<refsect1>
+<title>Authors</title>
+
+<para>create_makefile was written by &David.Faure; &David.Faure.mail; and
+ others. This manual page was prepared by
+ <personname><firstname>Ben</firstname><surname>Burton</surname></personname>
+ <email>bab@debian.org</email> for the Debian GNU/Linux system (but may be
+ used by others).</para>
+</refsect1>
+</refentry>
diff --git a/doc/scripts/man-create_makefiles.1.docbook b/doc/scripts/man-create_makefiles.1.docbook
new file mode 100644
index 00000000..edc11159
--- /dev/null
+++ b/doc/scripts/man-create_makefiles.1.docbook
@@ -0,0 +1,92 @@
+<?xml version="1.0" ?>
+<!DOCTYPE refentry PUBLIC "-//KDE//DTD DocBook XML V4.2-Based Variant V1.1//EN" "dtd/kdex.dtd" [
+<!ENTITY create_makefiles "<command>create_makefiles</command>">
+<!ENTITY % English "INCLUDE">
+]>
+
+<refentry lang="&language;">
+<refentryinfo>
+<date>March 8, 2003</date>
+</refentryinfo>
+
+<refmeta>
+<refentrytitle>&create_makefiles;</refentrytitle>
+<manvolnum>1</manvolnum>
+</refmeta>
+
+<refnamediv>
+<refname>&create_makefiles;</refname>
+<refpurpose>Recreates all <filename>Makefile</filename>s beneath a directory</refpurpose>
+</refnamediv>
+
+<refsynopsisdiv>
+<cmdsynopsis>
+&create_makefiles;
+<group><replaceable>dir</replaceable></group>
+
+</cmdsynopsis>
+</refsynopsisdiv>
+
+<refsect1>
+<title>Description</title>
+
+<para>&create_makefiles; recreates all <filename>Makefile</filename>s
+in <replaceable>dir</replaceable> and its
+(recursed) subdirectories from the corresponding
+<filename>Makefile.am</filename> templates.</para>
+
+<para>This script must be run from the toplevel directory (the one
+containing configure). This script saves time compared to re-running
+configure completely.</para>
+
+<para>If the source directory is different from the build directory
+(see the environment variables below), it will be assumed that each
+<filename>Makefile.am</filename> and <filename>Makefile.in</filename>
+belongs beneath the source directory and that each
+<filename>Makefile</filename> belongs beneath the build
+directory.</para>
+
+<para>This utility is part of the &kde; Software Development Kit.</para>
+</refsect1>
+
+
+<refsect1>
+<title>Environment</title>
+<para>One of the following variables (but not both) should be set if
+the source directory is different from the build directory. If the
+build directory is simply a subdirectory of the source directory, the
+simpler variable <envar>OBJ_SUBDIR</envar> should be used. </para>
+
+<variablelist>
+<varlistentry>
+<term><envar>OBJ_SUBJDIR</envar></term>
+<listitem><para>Indicates that the build directory is in the given subdirectory of the source directory. For instance, if the source directory is <filename class="directory">kdesdk</filename> and the build directory is <filename class="directory">kdesdk/obj-i386-linux</filename>, then <envar>OBJ_SUBDIR</envar> should be set to <parameter>obj-i386-linux</parameter>.</para></listitem>
+</varlistentry>
+<varlistentry>
+<term><envar>OBJ_REPLACEMENT</envar></term>
+<listitem><para>A <command>sed</command> expression that is used to transform the source directory into the build directory. For instance, if the source directory is <filename class="directory">kdesdk/obj-i386-linux</filename>, then <envar>OBJ_REPLACEMENT</envar> should be set to <parameter>s#kdesdk#kdesdk-obj#</parameter>.</para>
+</listitem>
+</varlistentry>
+</variablelist>
+</refsect1>
+
+<refsect1>
+<title>See Also</title>
+
+<para>create_makefile(1) make(2)</para>
+
+</refsect1>
+
+<refsect1>
+<title>Authors</title>
+
+<para>&create_makefiles; was written by &David.Faure; &David.Faure.mail;.</para>
+
+<para>This manual page was prepared by
+<personname><firstname>Ben</firstname><surname>Burton</surname></personname>
+<email>bab@debian.org</email> for the Debian GNU/Linux system (but may be
+used by others).</para>
+
+</refsect1>
+
+</refentry>
diff --git a/doc/scripts/man-cvscheck.1.docbook b/doc/scripts/man-cvscheck.1.docbook
new file mode 100644
index 00000000..f2673359
--- /dev/null
+++ b/doc/scripts/man-cvscheck.1.docbook
@@ -0,0 +1,134 @@
+<?xml version="1.0" ?>
+<!DOCTYPE refentry PUBLIC "-//KDE//DTD DocBook XML V4.2-Based Variant V1.1//EN" "dtd/kdex.dtd" [
+<!ENTITY cvscheck "<command>cvscheck</command>">
+<!ENTITY CVS "<acronym>CVS</acronym>">
+<!ENTITY % English "INCLUDE">
+]>
+
+<refentry lang="&language;">
+<refentryinfo>
+<date>March 8, 2003</date>
+</refentryinfo>
+
+<refmeta>
+<refentrytitle>&cvscheck;</refentrytitle>
+<manvolnum>1</manvolnum>
+</refmeta>
+
+<refnamediv>
+<refname>&cvscheck;</refname>
+<refpurpose>Offline status report for files in a checked-out &CVS; module.</refpurpose>
+</refnamediv>
+
+<refsynopsisdiv>
+<cmdsynopsis>
+&cvscheck;
+<group><replaceable>dir</replaceable></group>
+
+</cmdsynopsis>
+</refsynopsisdiv>
+
+<refsect1>
+<title>Description</title>
+
+<para>&cvscheck; prints information about the status of your local
+&CVS; checkout without communicating with the server. This means it is
+extremely fast and does not require a network connection.</para>
+
+<para>The given directory and all of its subdirectories will be
+processed recursively. If no directory is given, the current directory
+and its recursed subdirectories will be used.</para>
+
+<para>Each file with an interesting status will be printed with a
+status character in front of its name. The status characters are as
+follows.</para>
+
+<variablelist>
+<varlistentry>
+<term><returnvalue>?</returnvalue> <filename>foobar.c</filename></term>
+<listitem>
+<para>The file is not known to &CVS;</para>
+</listitem>
+</varlistentry>
+<varlistentry>
+<term><returnvalue>M</returnvalue>
+<filename>foobar.c</filename></term>
+<listitem>
+<para>The file is definitely locally modified</para>
+</listitem>
+</varlistentry>
+<varlistentry>
+<term><returnvalue>m</returnvalue>
+<filename>foobar.c</filename></term>
+<listitem>
+<para>The file <emphasis>might</emphasis> have local changes. You
+should <command>diff</command> with the server to make sure.</para>
+</listitem>
+</varlistentry>
+<varlistentry>
+<term><returnvalue>C</returnvalue>
+<filename>foobar.c</filename></term>
+<listitem>
+<para>The file has a &CVS; conflict and therefore cannot be
+committed.</para>
+</listitem>
+</varlistentry>
+<varlistentry>
+<term><returnvalue>U</returnvalue>
+<filename>foobar.c</filename></term>
+<listitem>
+<para>This file is in &CVS; but is missing in your local
+checkout.</para>
+</listitem>
+</varlistentry>
+<varlistentry>
+<term><returnvalue>T</returnvalue>
+<filename>foobar.c</filename></term>
+<listitem><para>This file has an unusual sticky &CVS;
+tag.</para></listitem>
+</varlistentry>
+<varlistentry>
+<term><returnvalue>A</returnvalue>
+<filename>foobar.c</filename></term>
+<listitem>
+<para>You have done a <userinput><command>cvs</command>
+<option>add</option></userinput> for this file, but have not yet committed
+it.</para>
+</listitem>
+</varlistentry>
+<varlistentry>
+<term><returnvalue>R</returnvalue>
+<filename>foobar.c</filename></term>
+<listitem>
+<para>You have done a <userinput><command>cvs</command>
+<option>rm</option></userinput> for this file, but have not yet committed
+it.</para>
+</listitem>
+</varlistentry>
+</variablelist>
+
+<para>This utility is part of the &kde; Software Development Kit.</para>
+
+</refsect1>
+
+<refsect1>
+<title>See Also</title>
+
+<para>cvs(1)</para>
+
+</refsect1>
+
+<refsect1>
+<title>Authors</title>
+
+<para>cvscheck was written by &Dirk.Mueller; &Dirk.Mueller.mail;
+ and Sirtaj.Singh.Kang; &Sirtaj.Singh.Kang.mail;</para>
+
+<para>This manual page was prepared by
+<personname><firstname>Ben</firstname>
+<surname>Burton</surname></personname> <email>bab@debian.org</email> for the
+Debian GNU/Linux system (but may be used by others).
+ </para>
+</refsect1>
+
+</refentry>
diff --git a/doc/scripts/man-cvslastchange.1.docbook b/doc/scripts/man-cvslastchange.1.docbook
new file mode 100644
index 00000000..eb86d966
--- /dev/null
+++ b/doc/scripts/man-cvslastchange.1.docbook
@@ -0,0 +1,52 @@
+<?xml version="1.0" ?>
+<!DOCTYPE refentry PUBLIC "-//KDE//DTD DocBook XML V4.2-Based Variant V1.1//EN" "dtd/kdex.dtd" [
+<!ENTITY cvslastchange "<command>cvslastchange</command>">
+<!ENTITY CVS "<acronym>CVS</acronym>">
+<!ENTITY % English "INCLUDE">
+]>
+
+<refentry lang="&language;">
+<refentryinfo>
+<author><personname><firstname>Ben</firstname><surname>Burton</surname></personname>
+<email>bab@debian.org</email></author>
+<date>March 8, 2003</date>
+</refentryinfo>
+
+<refmeta>
+<refentrytitle>&cvslastchange;</refentrytitle>
+<manvolnum>1</manvolnum>
+</refmeta>
+
+<refnamediv>
+<refname>&cvslastchange;</refname>
+<refpurpose>Display the last change committed to &CVS; for a file</refpurpose>
+</refnamediv>
+
+<refsynopsisdiv>
+<cmdsynopsis>
+&cvslastchange;
+<group><replaceable>file</replaceable></group>
+</cmdsynopsis>
+</refsynopsisdiv>
+
+<refsect1>
+<title>Description</title>
+
+<para>&cvslastchange; displays the last change committed to &CVS; for
+a file. It uses <command>cvs diff</command> and <command>cvs
+log</command> to do this.</para>
+
+<para>&cvslastchange; works on any &CVS; branch, not just HEAD.</para>
+
+<para>This utility is part of the &kde; Software Development Kit.</para>
+
+</refsect1>
+
+<refsect1>
+<title>See Also</title>
+
+<para>cvslastlog(1) cvsrevertlast(1) cvs(1)</para>
+
+</refsect1>
+
+</refentry>
diff --git a/doc/scripts/man-cvslastlog.1.docbook b/doc/scripts/man-cvslastlog.1.docbook
new file mode 100644
index 00000000..ed59f426
--- /dev/null
+++ b/doc/scripts/man-cvslastlog.1.docbook
@@ -0,0 +1,42 @@
+<?xml version="1.0" ?>
+<!DOCTYPE refentry PUBLIC "-//KDE//DTD DocBook XML V4.2-Based Variant V1.1//EN" "dtd/kdex.dtd" [
+<!ENTITY % English "INCLUDE">
+]>
+
+<refentry lang="&language;">
+<refentryinfo>
+<author><personname><firstname>Ben</firstname><surname>Burton</surname></personname>
+<email></email></author>
+<date>April 06, 2003</date>
+</refentryinfo>
+
+<refmeta>
+<refentrytitle><command>cvslastlog</command></refentrytitle>
+<manvolnum>1</manvolnum>
+</refmeta>
+
+<refnamediv>
+<refname><command>cvslastlog</command></refname>
+<refpurpose>Prints the log entry for the last commit for a file.</refpurpose>
+</refnamediv>
+
+<refsynopsisdiv>
+<cmdsynopsis>
+<command>cvslastlog</command>
+
+<group><option><replaceable>filename</replaceable></option></group>
+</cmdsynopsis>
+</refsynopsisdiv>
+
+<refsect1>
+<title>Description</title>
+
+<para><command>cvslastlog</command> shows the log associated with the
+last CVS commit for the given file. It depends on the version of the
+local file, not the one on the server. </para>
+
+<para>This utility is part of the &kde; Software Development Kit.</para>
+
+</refsect1>
+
+</refentry>
diff --git a/doc/scripts/man-cvsrevertlast.1.docbook b/doc/scripts/man-cvsrevertlast.1.docbook
new file mode 100644
index 00000000..8af8d658
--- /dev/null
+++ b/doc/scripts/man-cvsrevertlast.1.docbook
@@ -0,0 +1,48 @@
+<?xml version="1.0" ?>
+<!DOCTYPE refentry PUBLIC "-//KDE//DTD DocBook XML V4.2-Based Variant V1.1//EN" "dtd/kdex.dtd" [
+<!ENTITY % English "INCLUDE">
+]>
+
+<refentry lang="&language;">
+<refentryinfo>
+<author><personname><firstname>Ben</firstname><surname>Burton</surname></personname>
+<email></email></author>
+<date>Month Daynumber, 4-Digit-Year</date>
+</refentryinfo>
+
+<refmeta>
+<refentrytitle><command>cvsrevertlast</command></refentrytitle>
+<manvolnum>1</manvolnum>
+</refmeta>
+
+<refnamediv>
+<refname><command>cvsrevertlast</command></refname>
+<refpurpose>Revert files in CVS by one version</refpurpose>
+</refnamediv>
+
+<refsynopsisdiv>
+<cmdsynopsis>
+<command>cvsrevertlast</command>
+
+<group><option><replaceable>filename</replaceable></option></group>
+</cmdsynopsis>
+</refsynopsisdiv>
+
+<refsect1>
+<title>Description</title>
+
+<para>cvsrevertlast is used to revert all the files on the command
+line by one version in CVS. The files will not be committed.</para>
+
+<para>This utility is part of the KDE Software Development Kit. </para>
+
+</refsect1>
+
+<refsect1>
+<title>See Also</title>
+
+<para>cvsblame(1)</para>
+
+</refsect1>
+
+</refentry>
diff --git a/doc/scripts/man-cxxmetric.1.docbook b/doc/scripts/man-cxxmetric.1.docbook
new file mode 100644
index 00000000..f37d4a7c
--- /dev/null
+++ b/doc/scripts/man-cxxmetric.1.docbook
@@ -0,0 +1,43 @@
+<?xml version="1.0" ?>
+<!DOCTYPE refentry PUBLIC "-//KDE//DTD DocBook XML V4.2-Based Variant V1.1//EN" "dtd/kdex.dtd" [
+<!ENTITY % English "INCLUDE">
+]>
+
+<refentry lang="&language;">
+<refentryinfo>
+<author><personname><firstname>Ben</firstname><surname>Burton</surname></personname>
+<email>bab@debian.org</email></author>
+<date>April 07, 2003</date>
+</refentryinfo>
+
+<refmeta>
+<refentrytitle><command>cxxmetric</command></refentrytitle>
+<manvolnum>1</manvolnum>
+</refmeta>
+
+<refnamediv>
+<refname><command>cxxmetric</command></refname>
+<refpurpose>Simple source metrics for C and C++</refpurpose>
+</refnamediv>
+
+<refsynopsisdiv>
+<cmdsynopsis>
+<command>cxxmetric</command>
+
+<group><option><replaceable>file</replaceable></option></group>
+
+</cmdsynopsis>
+</refsynopsisdiv>
+
+<refsect1>
+<title>Description</title>
+
+<para>cxxmetric counts lines of code, comment and blank space and
+calculates various other statistics for each given source file. Source
+files must be in C or C++.</para>
+
+<para>This utility is part of the KDE Software Development Kit. </para>
+
+</refsect1>
+
+</refentry>
diff --git a/doc/scripts/man-demangle.1.docbook b/doc/scripts/man-demangle.1.docbook
new file mode 100644
index 00000000..40043252
--- /dev/null
+++ b/doc/scripts/man-demangle.1.docbook
@@ -0,0 +1,63 @@
+<?xml version="1.0" ?>
+<!DOCTYPE refentry PUBLIC "-//KDE//DTD DocBook XML V4.2-Based Variant V1.1//EN" "dtd/kdex.dtd" [
+<!ENTITY % English "INCLUDE">
+]>
+
+<refentry lang="&language;">
+<refentryinfo>
+<author><personname><firstname>Ben</firstname><surname>Burton</surname></personname>
+<email>bab@debian.org</email></author>
+<date>April 7, 2003</date>
+</refentryinfo>
+
+<refmeta>
+<refentrytitle><command>demangle</command></refentrytitle>
+<manvolnum>1</manvolnum>
+</refmeta>
+
+<refnamediv>
+<refname><command>demangle</command></refname>
+<refpurpose>Undo C++ name mangling for symbols</refpurpose>
+</refnamediv>
+
+<refsynopsisdiv>
+<cmdsynopsis>
+<command>demangle</command>
+</cmdsynopsis>
+</refsynopsisdiv>
+
+<refsect1>
+<title>Description</title>
+
+<para><command>demangle</command> reads a list of C++ mangled symbol names from standard input and converts these names to human-readable form on standard output.</para>
+
+<para>This utility is part of the &kde; Software Development Kit.</para>
+
+</refsect1>
+
+<refsect1>
+<title>Example</title>
+
+<para>Create a file called <filename>names</filename> containing the following mangled symbol names:</para>
+
+<programlisting>_ZNK6Object10metaObjectEv
+_ZN8QPtrListI5ArrowE5clearEv
+_ZTC4Kolf0_11KMainWindow</programlisting>
+
+<para>These names can then be demangled as follows:</para>
+
+<screen><prompt>example$</prompt> <userinput><command>demangle</command> &lt; <filename>names</filename></userinput>
+<computeroutput>Object::metaObject() const
+QPtrList&lt;Arrow&gt;::clear()
+construction vtable for KMainWindow-in-Kolf</computeroutput></screen>
+
+</refsect1>
+
+<refsect1>
+<title>See Also</title>
+
+<para>kminspector(1) kmtrace(1) match(1)</para>
+
+</refsect1>
+
+</refentry>
diff --git a/doc/scripts/man-extend_dmalloc.1.docbook b/doc/scripts/man-extend_dmalloc.1.docbook
new file mode 100644
index 00000000..ef85d1f8
--- /dev/null
+++ b/doc/scripts/man-extend_dmalloc.1.docbook
@@ -0,0 +1,54 @@
+<?xml version="1.0" ?>
+<!DOCTYPE refentry PUBLIC "-//KDE//DTD DocBook XML V4.2-Based Variant V1.1//EN" "dtd/kdex.dtd" [
+<!ENTITY % English "INCLUDE">
+]>
+
+<refentry lang="&language;">
+<refentryinfo>
+<author><personname><firstname>Ben</firstname><surname>Burton</surname></personname>
+<email>bab@debian.org</email></author>
+<date>April 7, 2003</date>
+</refentryinfo>
+
+<refmeta>
+<refentrytitle><command>extend_dmalloc</command></refentrytitle>
+<manvolnum>1</manvolnum>
+</refmeta>
+
+<refnamediv>
+<refname><command>extend_dmalloc</command></refname>
+<refpurpose>Analyze return-addresses from dmalloc logfiles.</refpurpose>
+</refnamediv>
+
+<refsynopsisdiv>
+<cmdsynopsis>
+<command>extend_dmalloc</command>
+<group><option><replaceable>dmalloc-log</replaceable> <command>binary</command></option></group>
+</cmdsynopsis>
+</refsynopsisdiv>
+
+<refsect1>
+<title>Description</title>
+
+<para><command>extend_dmalloc</command> will run <command>gdb</command>(1) to get information on the return-addresses from a <command>dmalloc</command>(1) logfile. Specifically it will examine any <literal>ra=</literal> lines and try to get the corresponding line numbers</para>
+
+<para>The argument
+<option><command>binary</command></option>
+must be the binary that generated the log
+<filename>dmalloc-log</filename>.</para>
+
+<para>This utility is part of the &kde; Software Development
+Kit.</para>
+
+</refsect1>
+
+
+<refsect1>
+<title>Notes</title>
+<para>You may wish to direct the output from
+<command>extend_dmalloc</command> to a file, since otherwise
+<command>gdb</command> seems to prompt for a return as if you are at
+the end of a page. </para>
+</refsect1>
+
+</refentry>
diff --git a/doc/scripts/man-extractrc.1.docbook b/doc/scripts/man-extractrc.1.docbook
new file mode 100644
index 00000000..6739c4a1
--- /dev/null
+++ b/doc/scripts/man-extractrc.1.docbook
@@ -0,0 +1,46 @@
+<?xml version="1.0" ?>
+<!DOCTYPE refentry PUBLIC "-//KDE//DTD DocBook XML V4.2-Based Variant V1.1//EN" "dtd/kdex.dtd" [
+<!ENTITY % English "INCLUDE">
+]>
+
+<refentry lang="&language;">
+<refentryinfo>
+<author><personname><firstname>Ben</firstname><surname>Burton</surname></personname>
+<email>bab@debian.org</email></author>
+<date>April 7, 2003</date>
+</refentryinfo>
+
+<refmeta>
+<refentrytitle><command>extractrc</command></refentrytitle>
+<manvolnum>1</manvolnum>
+</refmeta>
+
+<refnamediv>
+<refname><command>extractrc</command></refname>
+<refpurpose>Extract message strings from UI and GUI-RC files</refpurpose>
+</refnamediv>
+
+<refsynopsisdiv>
+<cmdsynopsis>
+<command>extractrc</command>
+
+<group><option><replaceable>filename</replaceable></option></group>
+</cmdsynopsis>
+</refsynopsisdiv>
+
+<refsect1>
+<title>Description</title>
+
+<para><command>extractrc</command> finds all text tags and other
+message strings in the given files and writes the corresponding i18n()
+calls to standard output so that xgettext can parse them.</para>
+
+<para>It understands both (&Qt;/&kde;)
+<application>designer</application>'s <acronym>UI</acronym> files and
+&XML; GUI-RC files. </para>
+
+<para>This utility is part of the KDE Software Development Kit. </para>
+
+</refsect1>
+
+</refentry>
diff --git a/doc/scripts/man-fixincludes.1.docbook b/doc/scripts/man-fixincludes.1.docbook
new file mode 100644
index 00000000..a4850ddc
--- /dev/null
+++ b/doc/scripts/man-fixincludes.1.docbook
@@ -0,0 +1,98 @@
+<?xml version="1.0" ?>
+<!DOCTYPE refentry PUBLIC "-//KDE//DTD DocBook XML V4.2-Based Variant V1.1//EN" "dtd/kdex.dtd" [
+<!ENTITY % English "INCLUDE">
+]>
+
+<refentry lang="&language;">
+<refentryinfo>
+<author><personname><firstname>Ben</firstname><surname>Burton</surname></personname>
+<email>bab@debian.org</email></author>
+<date>April 7, 2003</date>
+</refentryinfo>
+
+<refmeta>
+<refentrytitle><command>fixincludes</command></refentrytitle>
+<manvolnum>1</manvolnum>
+</refmeta>
+
+<refnamediv>
+<refname><command>fixincludes</command></refname>
+<refpurpose>Reduce the number of #includes in &kde; source files</refpurpose>
+</refnamediv>
+
+<refsynopsisdiv>
+<cmdsynopsis>
+<command>fixincludes</command>
+<group><option>-v, --verbose</option></group>
+<group><option>-e, --experimental</option></group>
+<group><option>-m, --modify</option></group>
+<group><option><replaceable>file</replaceable></option></group>
+<group><option>--help</option></group>
+</cmdsynopsis>
+</refsynopsisdiv>
+
+<refsect1>
+<title>Description</title>
+
+<para><command>fixincludes</command> tries to reduce the number of
+#includes in C++ source files. Much of it's processing is specific to
+&kde; sources and so it might not work so well with sources for
+non-&kde; applications.</para>
+
+<para>The following problems are identified by <command>fixincludes</command>:</para>
+
+<itemizedlist>
+<listitem>
+<para>Including headers that are no longer supported but which exist for compatibility with older Qt/KDE versions;</para>
+</listitem>
+<listitem>
+<para>Including the same file multiple times. </para>
+</listitem>
+</itemizedlist>
+
+<para>There is also an experimental mode which tries removing each
+#include one at a time (with a few exceptions) to see whether the
+source still compiles. Note that this experimental mode will modify
+the original sources. </para>
+
+<para>By default the sources will not be modified; the identified
+problems will simply be written to standard output. </para>
+
+<para>The list of C++ sources to examine should be given on the
+command-line. If no files are given, all C++ sources in or beneath the
+current directory will be examined (with the exception of directories
+whose <filename>Makefile.am</filename> contains
+<option>-UQT_NO_COMPAT</option> or
+<option>-UKDE_NO_COMPAT</option>)</para>
+
+<para>This utility is part of the KDE Software Development Kit. </para>
+
+</refsect1>
+
+<refsect1>
+<title>Options</title>
+
+<variablelist>
+<varlistentry>
+<term><option>-v, --verbose</option></term>
+<listitem><para>Verbose mode. Additional debugging output is written to standard output.</para></listitem>
+</varlistentry>
+<varlistentry>
+<term><option>-e, --experimental</option></term>
+<listitem><para>Experimental mode, as described above in detail. Note that this option implies <option>--modify</option>.</para></listitem>
+</varlistentry>
+<varlistentry>
+<term><option>-m, --modify</option></term>
+<listitem><para>As well as writing messages to standard output, actually modify the original sources to fix any problems that were found.</para></listitem>
+</varlistentry>
+</variablelist>
+
+</refsect1>
+
+<refsect1>
+<title>Authors</title>
+<para><command>fixincludes</command> was written by Dirk Mueller <email>mueller@kde.org</email>.
+</para>
+</refsect1>
+
+</refentry>
diff --git a/doc/scripts/man-po2xml.1.docbook b/doc/scripts/man-po2xml.1.docbook
new file mode 100644
index 00000000..d9fbd2ff
--- /dev/null
+++ b/doc/scripts/man-po2xml.1.docbook
@@ -0,0 +1,58 @@
+<?xml version="1.0" ?>
+<!DOCTYPE refentry PUBLIC "-//KDE//DTD DocBook XML V4.2-Based Variant V1.1//EN" "dtd/kdex.dtd" [
+<!ENTITY % English "INCLUDE">
+]>
+
+<refentry lang="&language;">
+<refentryinfo>
+<author><personname><firstname>Ben</firstname><surname>Burton</surname></personname>
+<email>bab@debian.org</email></author>
+<date>April 8, 2003</date>
+</refentryinfo>
+
+<refmeta>
+<refentrytitle><command>po2xml</command></refentrytitle>
+<manvolnum>1</manvolnum>
+</refmeta>
+
+<refnamediv>
+<refname><command>po2xml</command></refname>
+<refpurpose>Translates an DocBook XML file using a PO file</refpurpose>
+</refnamediv>
+
+<refsynopsisdiv>
+<cmdsynopsis>
+<command>po2xml</command>
+
+<group><option><replaceable>original-XML</replaceable> <replaceable>translated-PO</replaceable></option></group>
+
+</cmdsynopsis>
+</refsynopsisdiv>
+
+<refsect1>
+<title>Description</title>
+
+<para><command>po2xml</command> is a command-line tool that translates
+the DocBook XML file <replaceable>original-XML</replaceable> using the
+gettext message file <replaceable>translated-PO</replaceable>. The
+resulting translated XML file is sent to standard output.</para>
+
+<para>This utility is part of the KDE Software Development Kit.</para>
+
+</refsect1>
+
+<refsect1>
+<title>See Also</title>
+
+<para>split2po(1), swappo(1), transxx(1), xml2pot(1)</para>
+
+</refsect1>
+
+<refsect1>
+<title>Authors</title>
+<para>The PO-XML tools were written by &Stephan.Kulow; &Stephan.Kulow.mail;</para>
+<para>This manual page was prepared by <personname><firstname>Ben</firstname><surname>Burton</surname></personname><email>bab@debian.org</email></para>
+
+</refsect1>
+
+</refentry>
diff --git a/doc/scripts/man-pruneemptydirs.1.docbook b/doc/scripts/man-pruneemptydirs.1.docbook
new file mode 100644
index 00000000..ee5046a7
--- /dev/null
+++ b/doc/scripts/man-pruneemptydirs.1.docbook
@@ -0,0 +1,69 @@
+<?xml version="1.0" ?>
+<!DOCTYPE refentry PUBLIC "-//KDE//DTD DocBook XML V4.2-Based Variant V1.1//EN" "dtd/kdex.dtd" [
+<!ENTITY % English "INCLUDE">
+]>
+
+<refentry lang="&language;">
+<refentryinfo>
+<author><personname><firstname>Ben</firstname><surname>Burton</surname></personname><email>bab@debian.org</email></author>
+<date>April 8, 2003</date>
+</refentryinfo>
+
+<refmeta>
+<refentrytitle><command>pruneemptydirs</command></refentrytitle>
+<manvolnum>1</manvolnum>
+</refmeta>
+
+<refnamediv>
+<refname><command>pruneemptydirs</command></refname>
+<refpurpose>Detects stale source directories in a CVS tree</refpurpose>
+</refnamediv>
+
+<refsynopsisdiv>
+<cmdsynopsis>
+<command>pruneemptydirs</command>
+<group><option>-f</option></group>
+</cmdsynopsis>
+</refsynopsisdiv>
+
+<refsect1>
+<title>Description</title>
+
+<para><command>pruneemptydirs</command> is used to clean up a local
+CVS tree. It detects directories containing remnants of old stuff
+which has been removed from the CVS. Such stale directories often
+break compilation. The current directory and all directories beneath
+it will be examined.</para>
+
+<para>Note that this tool does not remove anything; it simply prints
+what to do as a series of remove commands. You can copy and paste
+these commands, or use them with eval in a script.</para>
+
+<para>This tool works better if the source directory is not the same
+as the build directory, since it will not print directories containing
+old executables.</para>
+
+<para>This utility is part of the KDE Software Development Kit.</para>
+
+</refsect1>
+
+<refsect1>
+<title>Options</title>
+
+<variablelist>
+<varlistentry>
+<term><option>-f</option></term>
+<listitem><para>Actually perform the deletions instead of just printing them out. Use this option with care.</para></listitem>
+</varlistentry>
+</variablelist>
+
+</refsect1>
+
+<refsect1>
+<title>Authors</title>
+
+<para><command>pruneemptydirs</command> was written by &David.Faure; &David.Faure.mail;</para>
+<para>This manual page was prepared by <personname><firstname>Ben</firstname><surname>Burton</surname></personname><email>bab@debian.org</email></para>
+</refsect1>
+
+</refentry>
diff --git a/doc/scripts/man-qtdoc.1.docbook b/doc/scripts/man-qtdoc.1.docbook
new file mode 100644
index 00000000..7491089e
--- /dev/null
+++ b/doc/scripts/man-qtdoc.1.docbook
@@ -0,0 +1,75 @@
+<?xml version="1.0" ?>
+<!DOCTYPE refentry PUBLIC "-//KDE//DTD DocBook XML V4.2-Based Variant V1.1//EN" "dtd/kdex.dtd" [
+<!ENTITY % English "INCLUDE">
+]>
+
+<refentry lang="&language;">
+<refentryinfo>
+<author><personname><firstname>Ben</firstname><surname>Burton</surname></personname><email>bab@debian.org</email></author>
+<date>April 8, 2003</date>
+</refentryinfo>
+
+<refmeta>
+<refentrytitle><command>qtdoc</command></refentrytitle>
+<manvolnum>1</manvolnum>
+</refmeta>
+
+<refnamediv>
+<refname><command>qtdoc</command></refname>
+<refpurpose>Open a &Qt; help page in &konqueror;</refpurpose>
+</refnamediv>
+
+<refsynopsisdiv>
+<cmdsynopsis>
+<command>qtdoc</command>
+
+<group><option><replaceable>classname</replaceable></option></group>
+</cmdsynopsis>
+</refsynopsisdiv>
+
+<refsect1>
+<title>Description</title>
+
+<para><command>qtdoc</command> opens a &Qt; help page in &konqueror;.
+If <replaceable>classname</replaceable> is given, it opens the help
+page for that class. Otherwise the main &Qt; help page is opened.
+<replaceable>classname</replaceable> is case insensitive.</para>
+
+<para>This utility is part of the &kde; Software Development Kit</para>
+
+</refsect1>
+
+<refsect1>
+<title>Environment</title>
+
+<variablelist>
+<varlistentry>
+<term><envar>QTDIR</envar></term>
+<listitem><para>The directory beneath which &Qt; is installed. The main &Qt; help page is expected to be in <filename class="directory">$<envar>QTDIR</envar>/doc/html/</filename>.</para></listitem>
+</varlistentry>
+</variablelist>
+
+</refsect1>
+
+<refsect1>
+<title>Examples</title>
+
+<para>To display the help on the class <classname>QString</classname>:</para>
+<screen><userinput><command>qtdoc</command> <option>QString</option></userinput></screen>
+</refsect1>
+
+<refsect1>
+<title>See Also</title>
+
+<para>kdedoc(1), assistant(1)</para>
+
+</refsect1>
+
+
+<refsect1>
+<title>Authors</title>
+
+<para>This manual page was prepared by <personname><firstname>Ben</firstname><surname>Burton</surname></personname><email>bab@debian.org</email></para>
+</refsect1>
+
+</refentry>
diff --git a/doc/scripts/man-reportview.1.docbook b/doc/scripts/man-reportview.1.docbook
new file mode 100644
index 00000000..9e050567
--- /dev/null
+++ b/doc/scripts/man-reportview.1.docbook
@@ -0,0 +1,73 @@
+<?xml version="1.0" ?>
+<!DOCTYPE refentry PUBLIC "-//KDE//DTD DocBook XML V4.2-Based Variant V1.1//EN" "dtd/kdex.dtd" [
+<!ENTITY Ian.Reinhart.Geiser "<personname><firstname>Ian</firstname><othername>Reinhart</othername><surname>Geiser</surname></personname>">
+<!ENTITY Ian.Reinhart.Geiser.mail "<email>geiseri@kde.org</email>">
+<!ENTITY kweather "<application>kweather</application>">
+<!ENTITY Nadeem.Hasan "<personname><firstname>Nadeem</firstname><surname>Hasan</surname></personname>">
+<!ENTITY Nadeem.Hasan.mail "<email>nhasan@kde.org</email>">
+<!ENTITY % English "INCLUDE">
+]>
+
+<refentry lang="&language;">
+<refentryinfo>
+<author><personname><firstname>Ben</firstname><surname>Burton</surname></personname><email>bab@debian.org</email></author>
+<date>April 7, 2003</date>
+</refentryinfo>
+
+<refmeta>
+<refentrytitle><command>reportview</command></refentrytitle>
+<manvolnum>1</manvolnum>
+</refmeta>
+
+<refnamediv>
+<refname><command>reportview</command></refname>
+<refpurpose>ask KWeatherService to display a weather report </refpurpose>
+</refnamediv>
+
+<refsynopsisdiv>
+<cmdsynopsis>
+<command>reportview;</command>
+<group><option>KDE Generic Options</option></group>
+<group><option>Qt Generic Options</option></group>
+</cmdsynopsis>
+</refsynopsisdiv>
+
+<refsect1>
+<title>Description</title>
+
+<para><command>reportview</command> is not intended to be used
+directly.</para>
+
+<para><command>reportview</command> is a small program that asks
+KWeatherService to display a weather report. Information shown
+includes the temperature, wind speed and air pressure.</para>
+
+<para>KWeatherService is a DCOP service used by both reportview and
+the &kweather; panel applet to provide weather data. There is no need to
+start KWeatherService separately; reportview will start the service
+itself if needed.</para>
+
+</refsect1>
+
+
+<refsect1>
+<title>See Also</title>
+
+<para>kweather(1)</para>
+
+<para>More detailed user documentation is available from <ulink
+url="help:/kweather">help:/kweather</ulink> (either enter this
+<acronym>URL</acronym> into &konqueror;, or run
+<userinput><command>khelpcenter</command>
+<parameter>help:/kweather</parameter></userinput>).</para>
+
+</refsect1>
+
+<refsect1>
+<title>Authors</title>
+
+<para>&kweather; was written by &Ian.Reinhart.Geiser; &Ian.Reinhart.Geiser.mail; and &Nadeem.Hasan; &Nadeem.Hasan.mail;</para>
+<para>This manual page was prepared by <personname><firstname>Ben</firstname><surname>Burton</surname></personname><email>bab@debian.org</email></para>
+</refsect1>
+
+</refentry>
diff --git a/doc/scripts/man-split2po.1.docbook b/doc/scripts/man-split2po.1.docbook
new file mode 100644
index 00000000..c2823b39
--- /dev/null
+++ b/doc/scripts/man-split2po.1.docbook
@@ -0,0 +1,64 @@
+<?xml version="1.0" ?>
+<!DOCTYPE refentry PUBLIC "-//KDE//DTD DocBook XML V4.2-Based Variant V1.1//EN" "dtd/kdex.dtd" [
+<!ENTITY % English "INCLUDE">
+]>
+
+<refentry lang="&language;">
+<refentryinfo>
+<author><personname><firstname>Ben</firstname><surname>Burton</surname></personname><email>bab@debian.org</email></author>
+<date>April 7, 2003</date>
+</refentryinfo>
+
+<refmeta>
+<refentrytitle><command>split2po</command></refentrytitle>
+<manvolnum>1</manvolnum>
+</refmeta>
+
+<refnamediv>
+<refname><command>split2po</command></refname>
+<refpurpose>Creates a po file from two DocBook XML files</refpurpose>
+</refnamediv>
+
+<refsynopsisdiv>
+<cmdsynopsis>
+<command>split2po</command>
+<group choice="req"><option><replaceable>Original-XML</replaceable></option>
+<option><replaceable>Translated-XML</replaceable></option></group>
+</cmdsynopsis>
+</refsynopsisdiv>
+
+<refsect1>
+<title>Description</title>
+
+<para><command>split2po</command> is a command-line tool that
+takes the two given DocBook XML files and produces a
+<command>gettext</command> message file (PO-file) that represents the
+changes between them. The resulting PO-file is sent to standard
+output.</para>
+
+<para><filename>translated-XML</filename> must be the result of
+translating <filename>original-XML</filename> into another
+language. It is this translation that the resulting PO-file will
+represent.</para>
+
+<para>This utility is part of the KDE Software Development Kit. </para>
+
+</refsect1>
+
+<refsect1>
+<title>See Also</title>
+
+<para>po2xml(1), swappo(1), transxx(1), xml2pot(1)</para>
+
+</refsect1>
+
+<refsect1>
+<title>Authors</title>
+
+<para>The PO XML tools were written by &Stephan.Kulow;
+&Stephan.Kulow.mail;</para>
+<para>This manual page was prepared by <personname><firstname>Ben</firstname><surname>Burton</surname></personname><email>bab@debian.org</email></para>
+
+</refsect1>
+
+</refentry>
diff --git a/doc/scripts/man-swappo.1.docbook b/doc/scripts/man-swappo.1.docbook
new file mode 100644
index 00000000..8df1f492
--- /dev/null
+++ b/doc/scripts/man-swappo.1.docbook
@@ -0,0 +1,59 @@
+<?xml version="1.0" ?>
+<!DOCTYPE refentry PUBLIC "-//KDE//DTD DocBook XML V4.2-Based Variant V1.1//EN" "dtd/kdex.dtd" [
+<!ENTITY % English "INCLUDE">
+]>
+
+<refentry lang="&language;">
+<refentryinfo>
+<author><personname><firstname>Ben</firstname><surname>Burton</surname></personname><email>bab@debian.org</email></author>
+<date>April 7, 2003</date>
+</refentryinfo>
+
+<refmeta>
+<refentrytitle><command>swappo</command></refentrytitle>
+<manvolnum>1</manvolnum>
+</refmeta>
+
+<refnamediv>
+<refname><command>swappo</command></refname>
+<refpurpose>swap msgid and msgstr fields in a PO file</refpurpose>
+</refnamediv>
+
+<refsynopsisdiv>
+<cmdsynopsis>
+<command>swappo</command>
+
+<group><option><replaceable>filename.po</replaceable></option></group>
+</cmdsynopsis>
+</refsynopsisdiv>
+
+<refsect1>
+<title>Description</title>
+
+<para><command>swappo</command> reads the given PO-file and swaps the
+msgid and msgstr fields for every message. The result is a new PO-file
+that translates in the opposite direction. For example, if PO-file
+translates from English to French, the new PO-file will translate from
+French to English.</para>
+
+<para>The new PO-file will be written to standard output. The old PO-file will remain untouched.</para>
+
+<para>This utility is part of the &kde; Software Development Kit</para>
+
+</refsect1>
+
+<refsect1>
+<title>See Also</title>
+
+<para>po2xml(1), split2po(1), transxx(1), xml2pot(1)</para>
+
+</refsect1>
+
+<refsect1>
+<title>Authors</title>
+<para>The PO-XML tools were written by &Stephan.Kulow; &Stephan.Kulow.mail;</para>
+<para>This manual page was prepared by <personname><firstname>Ben</firstname><surname>Burton</surname></personname><email>bab@debian.org</email></para>
+
+</refsect1>
+
+</refentry>
diff --git a/doc/scripts/man-transxx.1.docbook b/doc/scripts/man-transxx.1.docbook
new file mode 100644
index 00000000..629c6d1c
--- /dev/null
+++ b/doc/scripts/man-transxx.1.docbook
@@ -0,0 +1,55 @@
+<?xml version="1.0" ?>
+<!DOCTYPE refentry PUBLIC "-//KDE//DTD DocBook XML V4.2-Based Variant V1.1//EN" "dtd/kdex.dtd" [
+<!ENTITY % English "INCLUDE">
+]>
+
+<refentry lang="&language;">
+<refentryinfo>
+<author><personname><firstname>Ben</firstname><surname>Burton</surname></personname><email>bab@debian.org</email></author>
+<date>April 7, 2003</date>
+</refentryinfo>
+
+<refmeta>
+<refentrytitle><command>transxx</command></refentrytitle>
+<manvolnum>1</manvolnum>
+</refmeta>
+
+<refnamediv>
+<refname><command>transxx</command></refname>
+<refpurpose>Create a pseudo translated PO file from a PO template file</refpurpose>
+</refnamediv>
+
+<refsynopsisdiv>
+<cmdsynopsis>
+<command>transxx</command>
+<group><option><replaceable>template.pot</replaceable></option></group>
+</cmdsynopsis>
+</refsynopsisdiv>
+
+<refsect1>
+<title>Description</title>
+
+<para><command>transxx</command> is a command-line tool that produces
+a basic fleshed-out PO-file from a PO-template file. Some of the
+formatting and structure of the msgid strings will be copied to the
+msgstr strings, but otherwise text will be translated to
+<quote>xx</quote>.</para>
+
+<para>The fleshed-out PO-file is sent to standard output.</para>
+
+<para>Running your software with the language <quote>xx</quote> will
+quickly show you any user visible strings that are not
+translateable.</para>
+
+<para>This utility is part of the KDE Software Development Kit.</para>
+
+</refsect1>
+
+<refsect1>
+<title>Authors</title>
+
+<para>The PO-XML tools were written by &Stephan.Kulow; &Stephan.Kulow.mail;</para>
+<para>This manual page was prepared by <personname><firstname>Ben</firstname><surname>Burton</surname></personname><email>bab@debian.org</email></para>
+</refsect1>
+
+</refentry>
diff --git a/doc/scripts/man-xml2pot.1.docbook b/doc/scripts/man-xml2pot.1.docbook
new file mode 100644
index 00000000..01964972
--- /dev/null
+++ b/doc/scripts/man-xml2pot.1.docbook
@@ -0,0 +1,63 @@
+<?xml version="1.0" ?>
+<!DOCTYPE refentry PUBLIC "-//KDE//DTD DocBook XML V4.2-Based Variant V1.1//EN" "dtd/kdex.dtd" [
+<!ENTITY % English "INCLUDE">
+]>
+
+<refentry lang="&language;">
+<refentryinfo>
+<author><personname><firstname>Ben</firstname><surname>Burton</surname></personname><email>bab@debian.org</email></author>
+<date>April 7, 2003</date>
+</refentryinfo>
+
+<refmeta>
+<refentrytitle><command>xml2pot</command></refentrytitle>
+<manvolnum>1</manvolnum>
+</refmeta>
+
+<refnamediv>
+<refname><command>xml2pot</command></refname>
+<refpurpose>Creates a PO template file from a DocBook XML file.</refpurpose>
+</refnamediv>
+
+<refsynopsisdiv>
+<cmdsynopsis>
+<command>xml2pot</command>
+
+<group><option><replaceable>original-XML</replaceable></option></group>
+
+</cmdsynopsis>
+</refsynopsisdiv>
+
+<refsect1>
+<title>Description</title>
+
+<para><command>xml2pot</command> is a command-line tool that produces
+a gettext message template file from the DocBook XML file
+<filename>original-XML</filename>. The template file is sent to
+standard output.</para>
+
+<para>The resulting template file can be used to create gettext
+message files (PO-files) for a variety of languages. These can then be
+used in conjunction with <command>po2xml</command>(1) to translate the
+original XML file into these other languages.</para>
+
+
+<para>This utility is part of the KDE Software Development Kit.</para>
+
+</refsect1>
+
+<refsect1>
+<title>See Also</title>
+
+<para>po2xml(1), split2po(1), swappo(1), transxx(1)</para>
+
+</refsect1>
+
+<refsect1>
+<title>Authors</title>
+
+<para>The PO XML tools were written by &Stephan.Kulow; &Stephan.Kulow.mail;</para>
+<para>This manual page was prepared by <personname><firstname>Ben</firstname><surname>Burton</surname></personname><email>bab@debian.org</email></para>
+</refsect1>
+
+</refentry>
diff --git a/doc/scripts/man-zonetab2pot.1.docbook b/doc/scripts/man-zonetab2pot.1.docbook
new file mode 100644
index 00000000..308e7638
--- /dev/null
+++ b/doc/scripts/man-zonetab2pot.1.docbook
@@ -0,0 +1,56 @@
+<?xml version="1.0" ?>
+<!DOCTYPE refentry PUBLIC "-//KDE//DTD DocBook XML V4.2-Based Variant V1.1//EN" "dtd/kdex.dtd" [
+<!ENTITY % English "INCLUDE">
+]>
+
+<refentry lang="&language;">
+<refentryinfo>
+<author><personname><firstname>Ben</firstname><surname>Burton</surname></personname>
+<email></email></author>
+<date>April 7, 2003</date>
+</refentryinfo>
+
+<refmeta>
+<refentrytitle><command>zonetab2pot.py</command></refentrytitle>
+<manvolnum>1</manvolnum>
+</refmeta>
+
+<refnamediv>
+<refname><command>zonetab2pot.py</command></refname>
+<refpurpose>Converts a timezone list to a PO file template.</refpurpose>
+</refnamediv>
+
+<refsynopsisdiv>
+<cmdsynopsis>
+<command>zonetab2pot.py</command>
+
+<group><option><replaceable>timezone-list</replaceable></option></group>
+</cmdsynopsis>
+</refsynopsisdiv>
+
+<refsect1>
+<title>Description</title>
+
+<para><command>zonetab2pot.py</command> reads the timezone list given
+on the command-line and converts it to a gettext message file
+(PO-file) template containing the names of the individual
+timezones. </para>
+
+<para>The given timezone list should be in the same format as the system
+zone.tab. If no timezone list is specified on the command-line,
+<filename>/usr/share/zoneinfo/zone.tab</filename> will be used.</para>
+
+<para>The new PO-file template will be written to standard output.</para>
+
+<para>This utility is part of the KDE Software Development Kit. </para>
+
+</refsect1>
+
+<refsect1>
+<title>Authors</title>
+
+<para>zonetab2pot.py was written by <personname><firstname>Lukas</firstname><surname>Tinkl</surname></personname><email>lukas@kde.org</email></para>
+<para>This manual page was prepared by <personname><firstname>Ben</firstname><surname>Burton</surname></personname><email>bab@debian.org</email></para>
+</refsect1>
+
+</refentry>
diff --git a/doc/umbrello/Makefile.am b/doc/umbrello/Makefile.am
new file mode 100644
index 00000000..45fb6fde
--- /dev/null
+++ b/doc/umbrello/Makefile.am
@@ -0,0 +1,2 @@
+KDE_LANG = en
+KDE_DOCS = umbrello
diff --git a/doc/umbrello/activity-diagram.png b/doc/umbrello/activity-diagram.png
new file mode 100644
index 00000000..75234476
--- /dev/null
+++ b/doc/umbrello/activity-diagram.png
Binary files differ
diff --git a/doc/umbrello/add-remove-languages.png b/doc/umbrello/add-remove-languages.png
new file mode 100644
index 00000000..42c1d908
--- /dev/null
+++ b/doc/umbrello/add-remove-languages.png
Binary files differ
diff --git a/doc/umbrello/aggregation.png b/doc/umbrello/aggregation.png
new file mode 100644
index 00000000..46050842
--- /dev/null
+++ b/doc/umbrello/aggregation.png
Binary files differ
diff --git a/doc/umbrello/association.png b/doc/umbrello/association.png
new file mode 100644
index 00000000..ac984111
--- /dev/null
+++ b/doc/umbrello/association.png
Binary files differ
diff --git a/doc/umbrello/authors.docbook b/doc/umbrello/authors.docbook
new file mode 100644
index 00000000..1a079f02
--- /dev/null
+++ b/doc/umbrello/authors.docbook
@@ -0,0 +1,41 @@
+<chapter id="authors">
+<title>Authors and History</title>
+<para>
+This project was started by Paul Hensgen as one of his University projects.
+The original name of the application was <application>UML Modeller</application>. Paul did
+all the development until the end of 2001 when the program reached version 1.0.
+</para>
+<para>
+Version 1.0 already offered a lot of functionality, but after the project had been reviewed at
+Paul's University, other developers could join and they started making valuable contributions
+to <application>UML Modeller</application>, like switching from a binary file format to an &XML; file, support for more
+types of &UML; Diagrams, Code Generation and Code Import just to name a few.
+</para>
+<para>
+Paul had to retire from the development team in Summer 2002 but, as Free and Open Source Software, the
+program continues to improve and evolve and is being maintained by a group of developers from different
+parts of the world. In September 2002 the project changed its name from <application>&UML; Modeller</application>, to
+&umbrello;. There are several reasons for the change of names, the most
+important ones being that just <quote>uml</quote> &mdash; as it was commonly known &mdash; was a much too generic name
+and caused problems with some distributions. The other important reason is that the developers think
+<application>Umbrello</application> is a much cooler name.
+</para>
+<para>
+The development of &umbrello; as well as discussions as to where the program should head for future versions
+is open and takes place over the Internet. If you would like to contribute to the project, please do not
+hesitate to contact the developers. There are many ways in which you can help &umbrello;:
+</para>
+<itemizedlist>
+<listitem><para>Reporting bugs or improvements suggestions</para></listitem>
+<listitem><para>Fixing bugs or adding features</para></listitem>
+<listitem><para>Writing good documentation or translating it to other languages</para></listitem>
+<listitem><para>And of course...coding with us!</para></listitem>
+</itemizedlist>
+<para>
+As you see, there are many ways in which you can contribute. All of them are very important and
+everyone is welcome to participate.
+</para>
+<para>
+The &umbrello; developers can be reached at <email>uml-devel@lists.sourceforge.net</email>.
+</para>
+</chapter>
diff --git a/doc/umbrello/class-diagram.png b/doc/umbrello/class-diagram.png
new file mode 100644
index 00000000..3b12a4f6
--- /dev/null
+++ b/doc/umbrello/class-diagram.png
Binary files differ
diff --git a/doc/umbrello/class.png b/doc/umbrello/class.png
new file mode 100644
index 00000000..9c12a849
--- /dev/null
+++ b/doc/umbrello/class.png
Binary files differ
diff --git a/doc/umbrello/code-import.png b/doc/umbrello/code-import.png
new file mode 100644
index 00000000..49f477e5
--- /dev/null
+++ b/doc/umbrello/code-import.png
Binary files differ
diff --git a/doc/umbrello/code_import_and_generation.docbook b/doc/umbrello/code_import_and_generation.docbook
new file mode 100644
index 00000000..8beffcc3
--- /dev/null
+++ b/doc/umbrello/code_import_and_generation.docbook
@@ -0,0 +1,170 @@
+<chapter id="code-import-generation">
+<title>Code Import and Code Generation</title>
+<para>
+&umbrello; is a &UML; modelling tool, and as such its main purpose is to help you in the
+<emphasis>analysis and design</emphasis> of your systems. However, to make the transition
+between your design and your <emphasis>implementation</emphasis>, &umbrello; allows you to
+generate source code in different programming languages to get you started. Also, if you
+want to start using &UML; in an already started C++ project, &umbrello; can help you create a model
+of your system from the source code by analysing your source code and importing the classes
+found in it.
+</para>
+<sect1 id="code-generation">
+<title>Code Generation</title>
+<para>
+&umbrello; can generate source code for various programming languages based on your &UML; Model
+to help you get started with the implementation of your project. The code generated consists
+of the class declarations, with their methods and attributes so you can <quote>fill in the
+blanks</quote> by providing the functionality of your classes' operations.
+</para>
+<para>
+&umbrello; 1.2 comes with code generation support for ActionScript, Ada, C++, CORBA IDL, &Java;, JavaScript, <acronym>PHP</acronym>, Perl, Python, SQL and XMLSchema.
+</para>
+<sect2 id="generate-code">
+<title>Generating Code</title>
+<para>
+In order to generate code with &umbrello;, you first need to create or load a Model
+containing at least one class. When you are ready to start writing some code, select the
+<guimenuitem>Code Generation Wizard</guimenuitem> entry from the <guimenuitem>Code</guimenuitem> menu to
+start a wizard which will guide you trough the code generation process.
+</para>
+<para>
+The first step is to select the classes for which you want to generate source code.
+By default all the classes of your model are selected, and you can remove the ones
+for which you do not want to generate code by moving them to the left-hand side list.
+</para>
+<para>
+The next step of the wizard allows you to modify the parameters the Code Generator uses
+while writing your code. The following options are available:
+</para>
+<para>
+<screenshot>
+<screeninfo>Code Generation Options</screeninfo>
+ <mediaobject>
+ <imageobject>
+ <imagedata fileref="generation-options.png" format="PNG"/>
+ </imageobject>
+ <textobject>
+ <phrase>Options for the Code Generation in &umbrello;</phrase>
+ </textobject>
+ <caption>
+ <para>Options for the Code Generation in &umbrello;
+ </para>
+ </caption>
+ </mediaobject>
+</screenshot>
+</para>
+<sect3 id="generation-options">
+<title>Generation Options</title>
+<!-- LW; to rearrange -->
+
+<sect4>
+<title>Code Verbosity</title>
+<para>
+The option <guilabel>Write documentation comments even if empty</guilabel> instructs the
+ Code Generator to write comments of the /** blah */ style even if the comment blocks are empty.
+If you added documentation to your classes, methods or attributes in your Model, the
+Code Generator will write these comments as <application>Doxygen</application> documentation regardless of what you set here, but
+if you select this option &umbrello; will write comment blocks for all classes, methods and attributes
+even if there is no documentation in the Model, in which case you should document your classes
+later directly in the source code.
+</para>
+<para>
+<guilabel>Write comments for sections even if section is empty</guilabel> causes &umbrello; to write comments
+in the source code to delimit the different sections of a class. For example <quote>public methods</quote>
+ or <quote>Attributes</quote> before the corresponding sections. If you select this option &umbrello;
+ will write comments for all sections of the class even if the section is empty. For example,
+ it would write a comment saying <quote>protected methods</quote> even if there are no protected
+ methods in your class.
+</para>
+</sect4>
+<sect4>
+<title>Folders</title>
+<para>
+<guilabel>Write all generated files to folder</guilabel>. Here you should select the folder
+where you want &umbrello; to put the generated sources.
+</para>
+<para>
+The <guilabel>Include heading files from folder</guilabel> option allows you to insert a
+heading at the beginning of each generated file. Heading files can contain copyright or licensing
+ information and contain variables that are evaluated at generation time. You can take a look
+ at the template heading files shipped with &umbrello; to see how to use this variables for replacing
+ your name or the current date at generation time.
+</para>
+</sect4>
+<sect4>
+<title>Overwrite Policy</title>
+<!-- FIXME update for Umbrello 1.2's new C++ and Java code generators -->
+<para>
+This option tells &umbrello; what to do if the file it wants to create already exists in
+the destination folder. &umbrello; <emphasis>cannot modify existing source files</emphasis>,
+so you have to choose between overwriting the existing file, skipping the generation of
+that particular file or letting &umbrello; choose a different file name. If you choose the option
+to use a different name, &umbrello; will add a suffix to the file name.
+</para>
+</sect4>
+<sect4>
+<title>Language</title>
+<para>
+&umbrello; will by default generate code in the language you have selected as Active Language, but
+with the Code Generation Wizard you have the option to change this to another language.
+</para>
+</sect4>
+</sect3><!--generation-options-->
+<sect3 id="generation-wizard-generation">
+<title>Generation Wizard Generation</title>
+<para>
+The third and last step of the wizard shows the status of the Code Generation process.
+You need only to click on the Generate button to get your classes written for you.
+</para>
+<para>
+Note that the Options you select during the Code Generation Wizard are only valid for the current
+generation. The next time you run the wizard you will need to re-select all the options
+(your headings folder, overwrite policy, and so on). You can set the defaults used by &umbrello;
+in the <guilabel>Code Generation</guilabel> section of the &umbrello; settings, available
+at <menuchoice><guimenu>Settings</guimenu><guimenuitem>Configure &umbrello;...</guimenuitem></menuchoice>
+</para>
+<para>
+If you have set your Code Generation options to the right settings and want to generate
+some code right away without going through the wizard, you can select the entire
+<guimenuitem>Generate All Code</guimenuitem> from the Code menu.
+This will generate code for all the classes in your Model using the current settings
+(including Output Folder and Overwrite Policy, so use with care).
+</para>
+</sect3>
+</sect2><!--generate-code-->
+</sect1> <!--code-generation-->
+<sect1 id="code-import">
+<title>Code Import</title>
+<para>
+&umbrello; can import source code from your existing projects to help you build Model of
+your systems. &umbrello; 1.2 supports only C++ source code, but other languages
+should be available in future versions.
+</para>
+<para>
+To import classes into your Model, select the entry <guimenuitem>Import Classes...</guimenuitem> from
+the <guimenu>Code</guimenu> menu. In the file dialog select the files containing the C++
+class declarations and press OK. The classes will be imported and you will find them as part of
+your Model in the Tree View. Note that &umbrello; will not create any kind of Diagram for showing
+your classes, they will only be imported into your Model so that you can use them later in any
+diagram you want.
+</para>
+<para>
+<screenshot>
+<screeninfo>Code Import</screeninfo>
+ <mediaobject>
+ <imageobject>
+ <imagedata fileref="code-import.png" format="PNG"/>
+ </imageobject>
+ <textobject>
+ <phrase>Menu for importing source code in &umbrello;</phrase>
+ </textobject>
+ <caption>
+ <para>Menu for importing source code in &umbrello;
+ </para>
+ </caption>
+ </mediaobject>
+</screenshot>
+</para>
+</sect1>
+</chapter> <!--code-import-generation-->
diff --git a/doc/umbrello/collaboration-diagram.png b/doc/umbrello/collaboration-diagram.png
new file mode 100644
index 00000000..681d5c77
--- /dev/null
+++ b/doc/umbrello/collaboration-diagram.png
Binary files differ
diff --git a/doc/umbrello/composition.png b/doc/umbrello/composition.png
new file mode 100644
index 00000000..ad07e1d9
--- /dev/null
+++ b/doc/umbrello/composition.png
Binary files differ
diff --git a/doc/umbrello/credits.docbook b/doc/umbrello/credits.docbook
new file mode 100644
index 00000000..807089a5
--- /dev/null
+++ b/doc/umbrello/credits.docbook
@@ -0,0 +1,12 @@
+<chapter id="copyright">
+<title>Copyright</title>
+
+<para>Copyright 2001, Paul Hensgen</para>
+<para>Copyright 2002, 2003 The &umbrello; Authors. See
+<ulink url="http://uml.sf.net/developers.php">http://uml.sf.net/developers.php</ulink>
+for more information</para>
+
+&underFDL;
+&underGPL;
+
+</chapter>
diff --git a/doc/umbrello/folders.png b/doc/umbrello/folders.png
new file mode 100644
index 00000000..59680d97
--- /dev/null
+++ b/doc/umbrello/folders.png
Binary files differ
diff --git a/doc/umbrello/generalization.png b/doc/umbrello/generalization.png
new file mode 100644
index 00000000..8236cca3
--- /dev/null
+++ b/doc/umbrello/generalization.png
Binary files differ
diff --git a/doc/umbrello/generation-options.png b/doc/umbrello/generation-options.png
new file mode 100644
index 00000000..37c05697
--- /dev/null
+++ b/doc/umbrello/generation-options.png
Binary files differ
diff --git a/doc/umbrello/index.docbook b/doc/umbrello/index.docbook
new file mode 100644
index 00000000..0da7c91e
--- /dev/null
+++ b/doc/umbrello/index.docbook
@@ -0,0 +1,69 @@
+<?xml version="1.0" ?>
+<!DOCTYPE book PUBLIC "-//KDE//DTD DocBook XML V4.1.2-Based Variant V1.1//EN"
+ "dtd/kdex.dtd" [
+ <!ENTITY umbrello "<application>Umbrello &UML; Modeller</application>">
+ <!ENTITY kappname "&umbrello;">
+ <!ENTITY packagename "kdesdk">
+ <!ENTITY UML "<acronym>UML</acronym>">
+ <!ENTITY introduction-chapter SYSTEM "introduction.docbook">
+ <!ENTITY uml-basics-chapter SYSTEM "uml_basics.docbook">
+ <!ENTITY working-with-umbrello-chapter SYSTEM "working_with_umbrello.docbook">
+ <!ENTITY code-import-and-generation-chapter SYSTEM "code_import_and_generation.docbook">
+ <!ENTITY other-features-chapter SYSTEM "other_features.docbook">
+ <!ENTITY authors-chapter SYSTEM "authors.docbook">
+ <!ENTITY credits-chapter SYSTEM "credits.docbook">
+ <!ENTITY % addindex "IGNORE">
+ <!ENTITY % English "INCLUDE"><!-- change language only here -->
+ <!-- Do not define any other entities; instead, use the entities
+ from kde-genent.entities and $LANG/user.entities. -->
+]>
+
+<book id="Umbrello" lang="&language;">
+<bookinfo>
+<title>&umbrello; Handbook</title>
+
+<authorgroup>
+<corpauthor>&umbrello; Authors</corpauthor>
+</authorgroup>
+
+<copyright>
+<year>2001</year>
+<holder>Paul Hensgen</holder>
+</copyright>
+<copyright>
+<year>2002, 2003</year>
+<holder>&umbrello; Authors</holder>
+</copyright>
+
+
+<date>2003-10-15</date>
+<releaseinfo>1.2</releaseinfo>
+
+<abstract>
+<para>
+&umbrello; helps the software development
+process by using the industry standard Unified Modelling Language (&UML;)
+to enable you to create diagrams for designing and documenting your systems.
+</para>
+</abstract>
+
+<keywordset>
+<keyword>KDE</keyword>
+<keyword>UML</keyword>
+<keyword>modelling</keyword>
+<keyword>diagrams</keyword>
+<keyword>software development</keyword>
+<keyword>development</keyword>
+</keywordset>
+
+</bookinfo>
+
+&introduction-chapter;
+&uml-basics-chapter;
+&working-with-umbrello-chapter;
+&code-import-and-generation-chapter;
+&other-features-chapter;
+&authors-chapter;
+&credits-chapter;
+
+</book>
diff --git a/doc/umbrello/introduction.docbook b/doc/umbrello/introduction.docbook
new file mode 100644
index 00000000..3af9f719
--- /dev/null
+++ b/doc/umbrello/introduction.docbook
@@ -0,0 +1,43 @@
+<chapter id="introduction">
+<title>Introduction</title>
+
+<para>
+&umbrello; is a &UML; diagram tool that can support you
+in the software development process.
+Especially during the analysis and design phases of this process, &umbrello; will help you to
+get a high quality product. &UML; can also be used to document your software designs to help you and your
+fellow developers.
+</para>
+<para>
+Having a good model of your software is the best way to communicate with
+other developers working on the project and with your customers. A good model
+is extremely important for medium and big-size projects, but it is also very useful
+for small ones. Even if you are working on a small one man project you
+will benefit from a good model because it will give you an overview that will help
+you code things right the first time.
+</para>
+<para>
+&UML; is the diagramming language used to describing such models. You can represent your ideas in &UML;
+using different types of diagrams. &umbrello; 1.2 supports the following types:
+</para>
+<itemizedlist>
+<listitem><para>Class Diagram</para></listitem>
+<listitem><para>Sequence Diagram</para></listitem>
+<listitem><para>Collaboration Diagram</para></listitem>
+<listitem><para>Use Case Diagram</para></listitem>
+<listitem><para>State Diagram</para></listitem>
+<listitem><para>Activity Diagram</para></listitem>
+<listitem><para>Component Diagram</para></listitem>
+<listitem><para>Deployment Diagram</para></listitem>
+</itemizedlist>
+<para>
+More information about &UML; can be found at the website of
+<ulink url="http://www.omg.org"><acronym>OMG</acronym>, http://www.omg.org</ulink> who create the &UML; standard.
+</para>
+<para>
+We hope you enjoy &umbrello; and that it helps you create high quality software.
+&umbrello; is Free Software and available at no cost, the only thing we ask from you is to report any bugs, problems, or suggestions
+to the &umbrello; developers at <email>uml-devel@lists.sourceforge.net</email> or
+<ulink url="http://bugs.kde.org">http://bugs.kde.org</ulink>.
+</para>
+</chapter>
diff --git a/doc/umbrello/other_features.docbook b/doc/umbrello/other_features.docbook
new file mode 100644
index 00000000..1f368622
--- /dev/null
+++ b/doc/umbrello/other_features.docbook
@@ -0,0 +1,61 @@
+<chapter id="other-features">
+<title>Other Features</title>
+<sect1>
+<title>Other &umbrello; Features</title>
+<para>This chapter will briefly explain some other features &umbrello; offers you.</para>
+<sect2 id="copying-as-png">
+<title>Copying objects as PNG images</title>
+<para>
+Apart from offering you the normal copy, cut and paste functionality that you would expect to copy
+objects between different diagrams, &umbrello; can copy the objects as PNG pictures so that you can
+insert them into any other type of document. You do not need to do anything special to use this feature,
+just select an object from a diagram (Class, Actor, &etc;) and copy it (<keycombo>&Ctrl;<keycap>C</keycap></keycombo>,
+ or using the menu), then open a &kword; document (or any program into which you can paste images) and select <guimenuitem>Paste</guimenuitem>. This is a great feature
+to export parts of your diagram as simple pictures.
+</para>
+</sect2>
+<sect2 id="export-as-png">
+<title>Exporting to an Image</title>
+<para>
+You can also export a complete diagram as an image. The only thing you need to do is select
+the diagram you want to export, and then the option <guimenuitem>Export as Picture...</guimenuitem> from
+the <guimenu>Diagram</guimenu> menu.
+</para>
+</sect2>
+<sect2 id="printing">
+<title>Printing</title>
+<para>
+&umbrello; allows you to print individual diagrams. Press the <guiicon>Print</guiicon> button on the
+ application toolbar or selecting the <guimenuitem>Print</guimenuitem> option from the
+<guimenu>File</guimenu> menu will give you a standard &kde; Print dialog from where you can print
+your diagrams.
+</para>
+</sect2>
+<sect2 id="logical-folders">
+<title>Logical Folders</title>
+<para>
+To better organize your model, especially for larger projects, you can create logical folders in
+the Tree View. Just select the option <menuchoice><guimenu>New</guimenu><guimenuitem>Folder</guimenuitem></menuchoice> from the context menu
+of the default folders in the Tree View to create them. Folders can be nested, and you can
+move objects around by dragging them from one folder and dropping them into another.
+</para>
+
+<screenshot>
+<screeninfo>Organizing your Model with Folders</screeninfo>
+ <mediaobject>
+ <imageobject>
+ <imagedata fileref="folders.png" format="PNG"/>
+ </imageobject>
+ <textobject>
+ <phrase>Organizing a Model with Logical Folders in &umbrello;</phrase>
+ </textobject>
+ <caption>
+ <para>Organizing a Model with Logical Folders in &umbrello;
+ </para>
+ </caption>
+ </mediaobject>
+</screenshot>
+
+</sect2>
+</sect1>
+</chapter>
diff --git a/doc/umbrello/sequence-diagram.png b/doc/umbrello/sequence-diagram.png
new file mode 100644
index 00000000..a5f9fbbc
--- /dev/null
+++ b/doc/umbrello/sequence-diagram.png
Binary files differ
diff --git a/doc/umbrello/state-diagram.png b/doc/umbrello/state-diagram.png
new file mode 100644
index 00000000..610b2133
--- /dev/null
+++ b/doc/umbrello/state-diagram.png
Binary files differ
diff --git a/doc/umbrello/umbrello-main-screen.png b/doc/umbrello/umbrello-main-screen.png
new file mode 100644
index 00000000..52c48734
--- /dev/null
+++ b/doc/umbrello/umbrello-main-screen.png
Binary files differ
diff --git a/doc/umbrello/umbrello-ui-clean.png b/doc/umbrello/umbrello-ui-clean.png
new file mode 100644
index 00000000..8b147866
--- /dev/null
+++ b/doc/umbrello/umbrello-ui-clean.png
Binary files differ
diff --git a/doc/umbrello/umbrello-ui.png b/doc/umbrello/umbrello-ui.png
new file mode 100644
index 00000000..ee3d5911
--- /dev/null
+++ b/doc/umbrello/umbrello-ui.png
Binary files differ
diff --git a/doc/umbrello/uml_basics.docbook b/doc/umbrello/uml_basics.docbook
new file mode 100644
index 00000000..e9ad0d0d
--- /dev/null
+++ b/doc/umbrello/uml_basics.docbook
@@ -0,0 +1,616 @@
+<chapter id="uml-basics">
+<title>&UML; Basics</title>
+<sect1 id="about-uml">
+<title>About &UML;</title>
+<para>
+This chapter will give you a quick overview of the basics of &UML;. Keep in mind
+that this is not a comprehensive tutorial on &UML; but rather a brief introduction to &UML; which can be read as a &UML; tutorial.
+If you would like to learn more about the
+Unified Modelling Language, or in general about software analysis and design, refer to one of the
+many books available on the topic. There are also a lot of tutorials on the Internet which you
+can take as a starting point.
+</para>
+
+<para>
+The Unified Modelling Language (&UML;) is a diagramming language or notation to specify, visualize and document
+models of Object Orientated software systems. &UML; is not a development method, that means it does not tell you
+what to do first and what to do next or how to design your system, but it helps you to visualize
+your design and communicate with others. &UML; is controlled by the Object Management Group (<acronym>OMG</acronym>) and is the
+industry standard for graphically describing software.
+</para>
+<para>
+&UML; is designed for Object Orientated software design and has limited use for other programming paradigms.
+</para>
+<para>
+&UML; is composed of many model elements that represent the different parts of a software system.
+The &UML; elements are used to create diagrams, which represent a certain part, or a point of view of
+the system.
+The following types of diagrams are supported by &umbrello;:
+</para>
+
+<itemizedlist>
+
+<listitem><para><emphasis><link linkend="use-case-diagram">Use Case
+Diagrams</link></emphasis> show actors (people or other users of the
+system), use cases (the scenarios when they use the system), and their
+relationships</para> </listitem>
+
+<listitem><para><emphasis><link linkend="class-diagram">Class
+Diagrams</link></emphasis> show classes and the relationships between
+them</para> </listitem>
+
+<listitem><para><emphasis><link linkend="sequence-diagram">Sequence
+Diagrams</link></emphasis> show objects and a sequence of method calls
+they make to other objects.</para> </listitem>
+
+<listitem><para><emphasis><link
+linkend="collaboration-diagram">Collaboration
+Diagrams</link></emphasis> show objects and their relationship,
+ putting emphasis on the objects that participate in the message exchange</para>
+</listitem>
+
+<listitem><para><emphasis><link linkend="state-diagram">State
+Diagrams</link></emphasis> show states, state changes and events in an
+object or a part of the system</para> </listitem>
+
+<listitem><para><emphasis><link linkend="activity-diagram">Activity
+Diagrams</link></emphasis> show activities and the changes from one
+activity to another with the events occurring in some part of the
+system</para></listitem>
+
+<listitem><para><emphasis><link linkend="component-diagram">Component
+Diagrams</link></emphasis> show the high level programming components
+(such as KParts or Java Beans).</para></listitem>
+
+<listitem><para><emphasis><link
+linkend="deployment-diagram">Deployment Diagrams</link></emphasis> show
+the instances of the components and their
+relationships.</para></listitem>
+
+</itemizedlist>
+
+</sect1> <!-- about-uml -->
+
+<sect1 id="uml-elements">
+<title>&UML; Elements</title>
+<sect2 id="use-case-diagram">
+<title>Use Case Diagram</title>
+<para>Use Case Diagrams describe the relationships and dependencies between a group of <emphasis>Use Cases</emphasis>
+and the Actors participating in the process.</para>
+<para>It is important to notice that Use Case Diagrams are not suited to represent the design,
+and cannot describe the internals of a system. Use Case Diagrams are meant to facilitate the communication
+with the future users of the system, and with the customer, and are specially helpful to determine the required
+features the system is to have. Use Case Diagrams tell, <emphasis>what</emphasis> the system
+should do but do not &mdash; and cannot &mdash; specify <emphasis>how</emphasis> this is to be achieved.</para>
+<para>
+<screenshot>
+<screeninfo>An example Use Case diagram.</screeninfo>
+ <mediaobject>
+ <imageobject>
+ <imagedata fileref="use-case-diagram.png" format="PNG"/>
+ </imageobject>
+ <textobject>
+ <phrase>&umbrello; showing a Use Case Diagram</phrase>
+ </textobject>
+ <caption>
+ <para>&umbrello; showing a Use Case Diagram
+ </para>
+ </caption>
+ </mediaobject>
+</screenshot>
+</para>
+<sect3 id="use-case">
+<title>Use Case</title>
+<para>A <emphasis>Use Case</emphasis> describes &mdash; from the point of view of the actors &mdash; a group of activities
+in a system that produces a concrete, tangible result.</para>
+<para>
+Use Cases are descriptions of the typical interactions between the users of a system and the system itself.
+They represent the external interface of the system and specify a form of requirements of what the
+system has to do (remember, only what, not how).
+</para>
+<para>When working with Use Cases, it is important to remember some simple rules:
+ <itemizedlist>
+ <listitem><para>Each Use Case is related to at least one actor</para></listitem>
+ <listitem><para>Each Use Case has an initiator (&ie; an actor)</para></listitem>
+ <listitem><para>Each Use Case leads to a relevant result (a result with <quote>business value</quote>)</para>
+ </listitem>
+ </itemizedlist>
+</para>
+<para>
+Use Cases can also have relationships with other Use Cases. The three most typical types of relationships
+between Use Cases are:</para>
+<itemizedlist>
+<listitem><para><emphasis>&lt;&lt;include&gt;&gt;</emphasis> which specifies that a Use Case takes place <emphasis>inside</emphasis>
+another Use Case</para></listitem>
+<listitem><para><emphasis>&lt;&lt;extends&gt;&gt;</emphasis> which specifies that in certain situations, or at some point (called an
+extension point) a Use Case will be extended by another.</para></listitem>
+<listitem><para><emphasis>Generalization</emphasis> specifies that a Use Case inherits the characteristics
+of the <quote>Super</quote>-Use Case, and can override some of them or add new ones in a similar way as the
+inheritance between classes.
+</para>
+</listitem>
+</itemizedlist>
+</sect3>
+<sect3 id="actor">
+<title>Actor</title>
+<para>
+An actor is an external entity (outside of the system) that interacts with the system by participating
+(and often initiating) a Use Case. Actors can be in real life people (for example users of the system),
+other computer systems or external events.
+</para>
+<para>
+Actors do not represent the <emphasis>physical</emphasis> people or systems, but their <emphasis>role</emphasis>.
+This means that when a person interacts with the system in different ways (assuming different roles) he will be
+represented by several actors. For example a person that gives customer support by the telephone and takes
+orders from the customer into the system would be represented by an actor <quote>Support Staff</quote> and
+an actor <quote>Sales Representative</quote>
+</para>
+</sect3>
+<sect3 id="use-case-description">
+<title>Use Case Description</title>
+<para> <!-- FIXME this are not defined by UML. -->
+Use Case Descriptions are textual narratives of the Use Case. They usually take the form of a note or
+a document that is somehow linked to the Use Case, and explains the processes or activities that take
+place in the Use Case.
+</para>
+</sect3>
+</sect2> <!-- use-case-diagram -->
+
+<sect2 id="class-diagram">
+<title>Class Diagram</title>
+<para>
+Class Diagrams show the different classes that make up a system and how they relate to each other. Class Diagrams
+are said to be <quote>static</quote> diagrams because they show the classes, along with their methods and
+attributes as well as the static relationships between them: which classes <quote>know</quote> about which classes
+or which classes <quote>are part</quote> of another class, but do not show the method calls
+between them.
+</para>
+<para>
+<screenshot>
+<screeninfo>An example of a Class Diagram</screeninfo>
+ <mediaobject>
+ <imageobject>
+ <imagedata fileref="class-diagram.png" format="PNG"/>
+ </imageobject>
+ <textobject>
+ <phrase>&umbrello; showing a Class Diagram</phrase>
+ </textobject>
+ <caption>
+ <para>&umbrello; showing a Class Diagram
+ </para>
+ </caption>
+ </mediaobject>
+</screenshot>
+</para>
+<sect3 id="class">
+<title>Class</title>
+<para>
+A Class defines the attributes and the methods of a set of objects. All objects of this class (instances
+of this class) share the same behavior, and have the same set of attributes (each object has its own set).
+The term <quote>Type</quote> is sometimes used instead of Class, but it is important to mention that these
+two are not the same, and Type is a more general term.
+</para>
+<para>
+In &UML;, Classes are represented by rectangles, with the name of the class, and can also show
+the attributes and operations of the class in two other <quote>compartments</quote> inside the rectangle.
+</para>
+<para>
+<screenshot>
+<screeninfo>A Class in &UML;</screeninfo>
+ <mediaobject>
+ <imageobject>
+ <imagedata fileref="class.png" format="PNG"/>
+ </imageobject>
+ <textobject>
+ <phrase>Visual representation of a Class in &UML;</phrase>
+ </textobject>
+ <caption>
+ <para>Visual representation of a Class in &UML;
+ </para>
+ </caption>
+ </mediaobject>
+</screenshot>
+</para>
+<sect4 id="attribute">
+<title>Attributes</title>
+<para>
+In &UML;, Attributes are shown with at least their name, and can also show their type, initial value and
+other properties.
+Attributes can also be displayed with their visibility:
+</para>
+<itemizedlist>
+<listitem><para><literal>+</literal> Stands for <emphasis>public</emphasis> attributes</para></listitem>
+<listitem><para><literal>#</literal> Stands for <emphasis>protected</emphasis> attributes</para></listitem>
+<listitem><para><literal>-</literal> Stands for <emphasis>private</emphasis> attributes</para></listitem>
+</itemizedlist>
+</sect4>
+<sect4 id="operation">
+<title>Operations</title>
+<para>
+Operations (methods) are also displayed with at least their name, and can also show their parameters and return
+types.
+Operations can, just as Attributes, display their visibility:
+<itemizedlist>
+<listitem><para><literal>+</literal> Stands for <emphasis>public</emphasis> operations</para></listitem>
+<listitem><para><literal>#</literal> Stands for <emphasis>protected</emphasis> operations</para></listitem>
+<listitem><para><literal>-</literal> Stands for <emphasis>private</emphasis> operations</para></listitem>
+</itemizedlist>
+</para>
+</sect4>
+
+<sect4 id="templates">
+<title>Templates</title>
+<para>
+Classes can have templates, a value which is used for an unspecified class or type. The template type is specified
+when a class is initiated (&ie; an object is created). Templates exist in modern C++ and will be introduced in Java 1.5 where
+they will be called Generics.
+</para>
+</sect4>
+</sect3>
+
+<sect3 id="class-associations">
+<title>Class Associations</title>
+<para>Classes can relate (be associated with) to each other in different ways:</para>
+<sect4 id="generalization">
+<title>Generalization</title>
+<para>Inheritance is one of the fundamental concepts of Object Orientated programming, in which a class
+<quote>gains</quote> all of the attributes and operations of the class it inherits from, and can
+override/modify some of them, as well as add more attributes and operations of its own.</para>
+<para>
+In &UML;, a <emphasis>Generalization</emphasis> association between two classes puts them in a hierarchy
+representing the concept of inheritance of a derived class from a base class. In &UML;, Generalizations are
+represented by a line connecting the two classes, with an arrow on the side of the base class.
+<screenshot>
+<screeninfo>Generalization</screeninfo>
+ <mediaobject>
+ <imageobject>
+ <imagedata fileref="generalization.png" format="PNG"/>
+ </imageobject>
+ <textobject>
+ <phrase>Visual representation of a generalization in &UML;</phrase>
+ </textobject>
+ <caption>
+ <para>Visual representation of a generalization in &UML;
+ </para>
+ </caption>
+ </mediaobject>
+</screenshot>
+</para>
+</sect4>
+
+<sect4 id="uml-associations">
+<title>Associations</title>
+<para>An association represents a relationship between classes, and gives the common semantics and structure
+for many types of <quote>connections</quote> between objects.</para>
+<para>Associations are the mechanism that allows objects to communicate to each other. It describes the connection
+between different classes (the connection between the actual objects is called object connection, or
+<emphasis>link</emphasis>.
+</para>
+<para>
+Associations can have a role that specifies the purpose of the association and can be uni- or bidirectional
+(indicates if the two objects participating in the relationship can send messages to the other, of if only
+one of them knows about the other). Each end of the association also has a multiplicity value, which dictates
+how many objects on this side of the association can relate to one object on the other side.
+</para>
+<para>
+In &UML;, associations are represented as lines connecting the classes participating in the relationship,
+and can also show the role and the multiplicity of each of the participants. Multiplicity is displayed as a
+range [min..max] of non-negative values, with a star (<literal>*</literal>) on the maximum side representing infinite.
+<screenshot>
+<screeninfo>&UML; Association</screeninfo>
+ <mediaobject>
+ <imageobject>
+ <imagedata fileref="association.png" format="PNG"/>
+ </imageobject>
+ <textobject>
+ <phrase>Visual representation of an Association in &UML;</phrase>
+ </textobject>
+ <caption>
+ <para>Visual representation of an Association in &UML;
+ </para>
+ </caption>
+ </mediaobject>
+</screenshot>
+</para>
+</sect4>
+
+<sect4 id="aggregation">
+<title>Aggregation</title>
+<para>Aggregations are a special type of associations in which the two participating classes don't have
+an equal status, but make a <quote>whole-part</quote> relationship. An Aggregation describes how the class
+that takes the role of the whole, is composed (has) of other classes, which take the role of the parts.
+For Aggregations, the class acting as the whole always has a multiplicity of one.
+</para>
+<para>
+In &UML;, Aggregations are represented by an association that shows a rhomb on the side of the whole.
+<screenshot>
+<screeninfo>Aggregation</screeninfo>
+ <mediaobject>
+ <imageobject>
+ <imagedata fileref="aggregation.png" format="PNG"/>
+ </imageobject>
+ <textobject>
+ <phrase>Visual representation of an Aggregation relationship in &UML;</phrase>
+ </textobject>
+ <caption>
+ <para>Visual representation of an Aggregation relationship in &UML;
+ </para>
+ </caption>
+ </mediaobject>
+</screenshot>
+</para>
+</sect4>
+<sect4 id="composition">
+<title>Composition</title>
+<para>Compositions are associations that represent <emphasis>very strong</emphasis> aggregations. This means,
+Compositions form whole-part relationships as well, but the relationship is so strong that the parts cannot
+exist on its own. They exist only inside the whole, and if the whole is destroyed the parts die too.</para>
+<para>In &UML;, Compositions are represented by a solid rhomb on the side of the whole.
+</para>
+<para><screenshot>
+<screeninfo>Composition</screeninfo>
+ <mediaobject>
+ <imageobject>
+ <imagedata fileref="composition.png" format="PNG"/>
+ </imageobject>
+ <textobject>
+ <phrase>Visual representation of a Composition relationship in &UML;</phrase>
+ </textobject>
+ </mediaobject>
+</screenshot></para>
+</sect4>
+</sect3> <!--class-associations-->
+
+<sect3 id="other-class-diagram-items">
+<title>Other Class Diagram Items</title>
+<para>Class diagrams can contain several other items besides classes.</para>
+<sect4 id="interfaces">
+<title>Interfaces</title>
+<para>Interfaces are abstract classes which means instances can not be directly created of them. They can contain operations but no attributes. Classes can inherit from interfaces (through a realisation association) and instances can then be made of these diagrams.</para>
+<!-- FIXME screenshot -->
+</sect4>
+<sect4 id="datatype">
+<title>Datatypes</title>
+<para>Datatypes are primitives which are typically built into a programming language. Common examples include integers and booleans.
+They can not have relationships to classes but classes can have relationships to them.</para>
+<!-- FIXME screenshot -->
+</sect4>
+<sect4 id="enum">
+<title>Enums</title>
+<para>Enums are a simple list of values. A typical example is an enum for days of the week. The options of an enum are called Enum Literals.
+Like datatypes they can not have relationships to classes but classes can have relationships to them.</para>
+<!-- FIXME screenshot -->
+</sect4>
+<sect4 id="package">
+<title>Packages</title>
+<para>Packages represent a namespace in a programming language. In a diagram
+they are used to represent parts of a system which contain more than one class, maybe hundereds of classes.</para>
+<!-- FIXME screenshot -->
+</sect4>
+</sect3>
+
+</sect2> <!-- class diagram -->
+
+<sect2 id="sequence-diagram">
+<title>Sequence Diagrams</title>
+
+<para> Sequence Diagrams show the message exchange (&ie; method call)
+between several Objects in a specific time-delimited
+situation. Objects are instances of classes.
+Sequence Diagrams put special emphasis in the order and the
+times in which the messages to the objects are sent.</para>
+
+<para>
+In Sequence Diagrams objects are represented through vertical dashed lines, with the name of the Object
+on the top. The time axis is also vertical, increasing downwards, so that messages are sent from one Object
+to another in the form of arrows with the operation and parameters name.
+</para>
+
+<!-- FIXME update screenshot to show synchronous messages -->
+<screenshot>
+<screeninfo>Sequence Diagram</screeninfo>
+ <mediaobject>
+ <imageobject>
+ <imagedata fileref="sequence-diagram.png" format="PNG"/>
+ </imageobject>
+ <textobject>
+ <phrase>&umbrello; showing a Sequence Diagram</phrase>
+ </textobject>
+ <caption>
+ <para>&umbrello; showing a Sequence Diagram
+ </para>
+ </caption>
+ </mediaobject>
+</screenshot>
+
+<para>Messages can be either synchronous, the normal type of message call where control is passed to the called object until that
+method has finished running, or asynchronous where control is passed back directly to the calling object. Synchronous messages have
+a vertical box on the side of the called object to show the flow of program control.</para>
+</sect2> <!-- sequence diagrams -->
+
+<sect2 id="collaboration-diagram">
+<title>Collaboration Diagrams</title>
+
+<para>Collaboration Diagrams show the interactions occurring between the objects participating in a specific
+situation. This is more or less the same information shown by Sequence Diagrams but there the emphasis is
+put on how the interactions occur in time while the Collaboration Diagrams
+put the relationships between the objects and their topology in the foreground.</para>
+
+<para>In Collaboration Diagrams messages sent from one object to another are represented by arrows, showing
+the message name, parameters, and the sequence of the message. Collaboration Diagrams are specially well suited
+to showing a specific program flow or situation and are one of the best diagram types to quickly demonstrate
+or explain one process in the program logic.
+</para>
+
+<screenshot>
+<screeninfo>Collaboration</screeninfo>
+ <mediaobject>
+ <imageobject>
+ <imagedata fileref="collaboration-diagram.png" format="PNG"/>
+ </imageobject>
+ <textobject>
+ <phrase>&umbrello; showing a Collaboration Diagram</phrase>
+ </textobject>
+ <caption>
+ <para>&umbrello; showing a Collaboration Diagram
+ </para>
+ </caption>
+ </mediaobject>
+</screenshot>
+
+</sect2> <!-- collaboration diagrams -->
+
+<sect2 id="state-diagram">
+<title>State Diagram</title>
+<para>State Diagrams show the different states of an Object during its life and the stimuli that
+cause the Object to change its state.
+</para>
+<para>State Diagrams view Objects as <emphasis>state machines</emphasis> or finite automates that can
+be in one of a set of finite states and that can change its state via one of a finite set of stimuli. For example
+an Object of type <emphasis>NetServer</emphasis> can be in one of following states during its life:
+</para>
+<itemizedlist>
+<listitem><para>Ready</para></listitem>
+<listitem><para>Listening</para></listitem>
+<listitem><para>Working</para></listitem>
+<listitem><para>Stopped</para></listitem>
+</itemizedlist>
+<para>and the events that can cause the Object to change states are</para>
+<itemizedlist>
+<listitem><para>Object is created</para></listitem>
+<listitem><para>Object receives message listen</para></listitem>
+<listitem><para>A Client requests a connection over the network</para></listitem>
+<listitem><para>A Client terminates a request</para></listitem>
+<listitem><para>The request is executed and terminated</para></listitem>
+<listitem><para>Object receives message stop</para></listitem>
+<listitem><para>etc</para></listitem>
+</itemizedlist>
+<para>
+<screenshot>
+<screeninfo>State Diagram</screeninfo>
+ <mediaobject>
+ <imageobject>
+ <imagedata fileref="state-diagram.png" format="PNG"/>
+ </imageobject>
+ <textobject>
+ <phrase>&umbrello; showing a State Diagram</phrase>
+ </textobject>
+ <caption>
+ <para>&umbrello; showing a State Diagram
+ </para>
+ </caption>
+ </mediaobject>
+</screenshot>
+</para>
+<sect3 id="state">
+<title>State</title>
+<para>States are the building block of State Diagrams. A State belongs to exactly one class and represents
+a summary of the values the attributes of a class can take. A &UML; State describes the internal state of an
+object of one particular class
+</para>
+<para>Note that not every change in one of the attributes of an object should be represented by a State
+but only those changes that can significantly affect the workings of the object</para>
+<para>
+There are two special types of States: Start and End. They are special in that there is no event that
+can cause an Object to return to its Start state, in the same way as there is no event that can possible take
+an Object out of its End state once it has reached it.
+</para>
+</sect3>
+
+</sect2> <!-- state diagrams -->
+
+<sect2 id="activity-diagram">
+<title>Activity Diagram</title>
+<para>Activity Diagrams describe the sequence of activities in a system with the
+help of Activities. Activity Diagrams are a special form of State Diagrams, that only (or mostly) contains
+Activities.
+</para>
+<para>
+<screenshot>
+<screeninfo>An example Activity Diagram.</screeninfo>
+ <mediaobject>
+ <imageobject>
+ <imagedata fileref="activity-diagram.png" format="PNG"/>
+ </imageobject>
+ <textobject>
+ <phrase>&umbrello; showing an Activity Diagram</phrase>
+ </textobject>
+ <caption>
+ <para>&umbrello; showing an Activity Diagram
+ </para>
+ </caption>
+ </mediaobject>
+</screenshot>
+</para>
+<para>Activity Diagrams are similar to procedural Flux Diagrams, with the difference that all Activities
+are clearly attached to Objects.</para>
+
+<para>Activity Diagrams are always associated to a
+<emphasis>Class</emphasis>, an <emphasis>Operation</emphasis> or a
+<emphasis>Use Case</emphasis>.</para>
+
+<para>Activity Diagrams support sequential as well as parallel Activities. Parallel execution is represented
+via Fork/Wait icons, and for the Activities running
+in parallel, it is not important the order in which they are carried out (they can be executed at the same
+time or one after the other)</para>
+<sect3 id="activity">
+<title>Activity</title>
+<para>An Activity is a single step in a process. One Activity is one state
+in the system with internal activity and, at least, one outgoing transition. Activities can also have
+more than one outgoing transition if they have different conditions.
+</para>
+<para>Activities can form hierarchies, this means that an Activity can be composed of several <quote>detail</quote>
+Activities, in which case the incoming and outgoing transitions should match the incoming and outgoing transitions
+of the detail diagram.
+</para>
+
+</sect3>
+</sect2> <!-- activity diagram -->
+
+<sect2 id="helper-elements">
+<title>Helper Elements</title>
+<para>There are a few elements in &UML; that have no real semantic value for the model, but help to clarify
+parts of the diagram. These elements are </para>
+<itemizedlist>
+<listitem><para>Text lines</para></listitem>
+<listitem><para>Text Notes and anchors</para></listitem>
+<listitem><para>Boxes</para></listitem>
+</itemizedlist>
+<para>
+Text lines are useful to add short text information to a diagram. It is free-standing text and has no
+meaning to the Model itself.
+</para>
+
+<para>
+Notes are useful to add more detailed information about an
+object or a specific situation. They have the great advantage that
+notes can be anchored to &UML; Elements to show that the note
+<quote>belongs</quote> to a specific object or situation.
+</para>
+
+<para>Boxes are free-standing rectangles which can be used to group items together to make diagrams more readable. They
+have no logical meaning in the model.</para>
+
+<!-- FIXME, screenshot -->
+</sect2> <!-- helper elements -->
+
+<sect2 id="component-diagram">
+<title>Component Diagrams</title>
+<para>Component Diagrams show the software components (either component technologies such as KParts, CORBA components or Java Beans or
+just sections of the system which are clearly distinguishable) and the artifacts they
+are made out of such as source code files, programming libraries or relational database tables.</para>
+
+<para>Components can have interfaces (&ie; abstract classes with operations) that allow associations between components.</para>
+</sect2>
+
+<sect2 id="deployment-diagram">
+<title>Deployment Diagrams</title>
+
+<para>Deployment diagrams show the runtime component instances and their
+associations. They include Nodes which are physical resources,
+typically a single computer. They also show interfaces and objects (class instances).</para>
+
+</sect2>
+
+</sect1>
+</chapter>
diff --git a/doc/umbrello/use-case-diagram.png b/doc/umbrello/use-case-diagram.png
new file mode 100644
index 00000000..36f4320d
--- /dev/null
+++ b/doc/umbrello/use-case-diagram.png
Binary files differ
diff --git a/doc/umbrello/working_with_umbrello.docbook b/doc/umbrello/working_with_umbrello.docbook
new file mode 100644
index 00000000..3cf32f83
--- /dev/null
+++ b/doc/umbrello/working_with_umbrello.docbook
@@ -0,0 +1,448 @@
+<chapter id="working-with-umbrello">
+<title>Working with &umbrello;</title>
+<!-- Umbrello basics: creating diagrams, creating classes, adding objects to diagrams,
+ associations, editing properties, anchor points in associations, removing objects, removing
+ diagrams
+-->
+
+<para>
+This chapter will introduce you to &umbrello;'s user interface and will
+tell you all you need to know to start modelling. All actions in &umbrello; are accessible via the menu and
+the toolbars, but &umbrello; also makes extensive use of &RMB; context menus. You can &RMB; click on almost any element in
+&umbrello;'s work area or tree view to get a menu with the most useful
+functions that can be applied to the particular element you are
+working on. Some users find this a little confusing at the beginning because they are more used to working with the menu or tool bars, but
+once you get used to <mousebutton>right</mousebutton> clicking it will greatly speed up your work.
+</para>
+
+<sect1 id="user-interface">
+<title>User Interface</title>
+<para>
+&umbrello;'s main window is divided in three areas that will help you keep an overview of your entire system
+and access the different diagrams quickly while working on your model.
+</para>
+<para>These areas are called:</para>
+<itemizedlist>
+<listitem><para>Tree View</para></listitem>
+<listitem><para>Work Area</para></listitem>
+<listitem><para>Documentation Window</para></listitem>
+</itemizedlist>
+
+<screenshot>
+<screeninfo>&umbrello;'s User Interface</screeninfo>
+ <mediaobject>
+ <imageobject>
+ <imagedata fileref="umbrello-ui.png" format="PNG"/>
+ </imageobject>
+ <textobject>
+ <phrase>&umbrello;'s User Interface</phrase>
+ </textobject>
+ <caption>
+ <para>&umbrello;'s User Interface
+ </para>
+ </caption>
+ </mediaobject>
+</screenshot>
+
+<sect2 id="tree-view">
+<title>Tree View</title>
+<para>
+The Tree View is usually located on the top left hand side of the window and shows the all the diagrams,
+classes, actors and use cases that build up your model.
+The Tree View allows you to have a quick overview of the elements composing your model. The Tree View also
+gives you a quick way to switch between the different diagrams in your model and inserting elements from
+your model into the current diagram.
+</para>
+<para>
+If you are working on a model with more than just a few classes and diagrams, the Tree View may help
+you stay on top of things by organizing your model elements in folders. You can create
+folders by selecting the appropriate option from the context menu (&RMB; click on one of the folders
+in the tree view) and you can organize your elements by moving them to the appropriate folder (drag and drop)
+<!-- (screen shot) FIXME-->
+</para>
+</sect2>
+
+<sect2 id="documentation-window">
+<title>Documentation Window</title>
+<para>
+The Documentation Window is the small window located on the left bottom of &umbrello;, and it gives
+you a quick preview of the documentation for the currently selected item. The Documentation Window is
+rather small because it is intended to allow you just a quick pick into the element's documentation while
+taking as little screen space as possible. If you need to view the documentation in more detail you can always
+open the item's properties.
+</para>
+</sect2>
+<sect2 id="work-area">
+<title>Work Area</title>
+<para>
+The Work Area is the main window in &umbrello; and is where the real action takes place. You use the Work Area
+to edit and view the diagrams in your model. The Work Area shows the currently active diagram. Currently
+only one diagram can be shown on the Work Area at any time.
+</para>
+</sect2>
+</sect1> <!--user-interface-->
+<sect1 id="load-save">
+<title>Creating, Loading and Saving Models</title>
+<para>
+The first thing you need to start doing something useful with &umbrello; is to create a model to work on.
+When you start &umbrello; it always loads the last used model or creates a new, empty model (depending on
+your preferences set in the configuration dialog). This will allow you to start working right away.
+</para>
+<sect2 id="new-model">
+<title>New Model</title>
+<para>
+If at any time you need to create a new model you can do this by selecting the <guimenuitem>New</guimenuitem> entry from the
+<guimenu>File</guimenu> menu, or by clicking on the <guiicon>New</guiicon> icon from the application toolbar. If you are currently working on
+a model which has been modified &umbrello; will ask you if it should save your changes before loading the
+new model.
+</para>
+</sect2>
+<sect2 id="save-model">
+<title>Save Model</title>
+<para>
+You can save your model at any time by selecting the option <guimenuitem>Save</guimenuitem> from the <guimenu>File</guimenu> Menu or by clicking
+on the <guiicon>Save</guiicon> button from the application toolbar. If you need to save your model under a different name
+you can use the option <guimenuitem>Save As</guimenuitem> from the <guimenu>File</guimenu> Menu.
+</para>
+<para>For your convenience &umbrello; also offers you the option to automatically save your work
+each certain time period. You can configure if you want this option as well as the time intervals
+in the <guimenu>Settings</guimenu> from &umbrello;</para>
+</sect2>
+<sect2 id="load-model">
+<title>Load Model</title>
+<para>
+For loading an already existing model you may select the option <guimenuitem>Open</guimenuitem> from the <guimenu>File</guimenu> Menu or click on the <guiicon>Open</guiicon>
+icon from the application toolbar. The most recently used models are also available under the submenu
+<guimenuitem>Open Recent</guimenuitem> in the <guimenu>File</guimenu> Menu to speed up access to your most frequently used models.
+</para>
+<para>
+&umbrello; can only work on one model at a time, so if you ask the program to load a model for you and your
+current model has been modified since the last time you save it, &umbrello; will ask you whether your changes
+should be saved to prevent any loss of work. You can start two or more instances of &umbrello; at any one time, you can also copy and paste between instances.
+</para>
+</sect2>
+</sect1> <!--load-save-->
+<sect1 id="edit-model">
+<title>Editing Models</title>
+<para>
+In &umbrello;, there are basically two ways for editing the elements in your model.
+<itemizedlist>
+<listitem><para>Edit model elements directly through the Tree View</para></listitem>
+<listitem><para>Edit model elements through a Diagram</para></listitem>
+</itemizedlist>
+</para>
+<para>
+Using the context menu of the different items in the Tree View you are able to add, remove,
+and modify almost all the elements in your model. <mousebutton>Right</mousebutton> clicking on the folders in the Tree View
+will give you options for creating the different types of diagrams as well as, depending on whether
+the folder is a <emphasis>Use Case View</emphasis> or a <emphasis>Logical View</emphasis>, Actors,
+Use Cases, Classes, etc.
+</para>
+<para>
+Once you have added elements to your model you can also edit an element by accessing its properties
+dialog, which you find by selecting the option <emphasis>Properties</emphasis> from the context menu
+shown when <mousebutton>right</mousebutton> clicking on the items in the Tree View.
+</para>
+<para>
+You can also edit your model by creating or modifying elements through diagrams. More details on how
+to do this are given in the following sections.
+</para>
+</sect1>
+<sect1 id="add-remove-diagrams">
+<title>Adding and Removing Diagrams</title>
+<para>
+Your &UML; model consists of a set of &UML; elements and associations between them. However you cannot see the model
+directly, you use <emphasis>Diagrams</emphasis> to look at it.
+</para>
+<sect2 id="create-diagram">
+<title>Creating Diagrams</title>
+<para>
+To create a new diagram in your model simply select the diagram type you need from the <guimenuitem>New</guimenuitem> submenu in the <guimenu>Diagram</guimenu> menu and give a name to it. The diagram will be created and made active, and you will immediately
+see it in the tree view.
+</para>
+<para>
+Remember that &umbrello; makes extensive use of context menus: you can also &RMB; click on a folder in the Tree
+View and select the appropriate diagram type from the <guisubmenu>New</guisubmenu> submenu in the context menu. Note that you can create
+Use Case Diagrams only in Use Case View folders, and the other types of diagram can only be created in the
+Logical View folders.
+</para>
+</sect2>
+<sect2 id="remove-diagram">
+<title>Removing Diagrams</title>
+<para>
+Should you need to remove a diagram from your model, you can do this by making it active and selecting
+<guimenuitem>Delete</guimenuitem> from the <guimenu>Diagram</guimenu> Menu. You can also achieve this by selecting <guimenuitem>Delete</guimenuitem> from the diagrams context menu
+in the Tree View
+</para>
+<para>Since deleting a diagram is something serious that could cause loss of work if done by accident, &umbrello;
+will ask you to confirm the delete operation before actually removing the Diagram. Once a diagram has been
+deleted and the file has been saved there is no way to undo this action.
+</para>
+</sect2>
+<sect2 id="rename-diagram">
+<title>Renaming Diagrams</title>
+<para>
+If you want to change the name of an existing diagram you can easily do this by selecting the Rename option
+from its &RMB; menu in the Tree View.
+</para>
+<para>Another way to rename a diagram is to do this via its properties dialog, which you obtain by
+selecting Properties from its Context Menu or by double clicking on it in the Tree View.
+</para>
+</sect2>
+</sect1>
+<sect1 id="edit-diagram">
+<title>Editing Diagrams</title>
+<para>
+When working on a diagram, &umbrello; will try to guide you by applying some simple rules as to which
+elements are valid in the different types of diagrams, as well as the relationships that can exist
+between them. If you are an &UML; expert you will probably not even notice it, but this will help
+&UML; novices create standard-conformant diagrams.
+</para>
+<para>
+Once you have created your diagrams it is time to start editing them. Here you should notice
+the (for beginners subtle) difference between editing your diagram, and editing the
+<emphasis>model</emphasis>. As you already know, Diagrams are <emphasis>views</emphasis> of your model.
+For example, if you create a class by editing a Class Diagram, you are really editing both, your
+Diagram and your model. If you change the color or other display options of a Class in your Class
+Diagram, you are only editing the Diagram, but nothing is changed in your model.
+</para>
+<sect2 id="insert-elements">
+<title>Insert Elements</title>
+<para>
+One of the first things you will do when editing a new diagram is to insert elements into them (Classes,
+Actors, Use Cases, &etc;) There is basically two ways of doing this:</para>
+<itemizedlist>
+<listitem><para>Dragging existing elements in your model from the Tree View</para></listitem>
+<listitem><para>Creating new elements in your model and adding them to your diagram at the
+same time, by using one of the edit Tools in the Work Toolbar</para></listitem>
+</itemizedlist>
+<para>
+To insert elements that already exist in your model, just drag them from the Tree View and
+drop them where you want them to be in your diagram. You can always move elements around
+in your Diagram using the Select Tool
+</para>
+<para>
+The second way of adding elements to your diagram is by using the Work Toolbar's edit tools (note
+that this will also add the elements to your model).
+</para>
+<para>
+The Work Toolbar was by default located on the far right of the application window, &umbrello; 1.2 has moved this to the top of the window.
+You can dock it into other edge or have it floating around if you prefer. The tools available
+on this toolbar (the buttons you see on it) change depending on the type of diagram
+you are currently working on. The button for the currently
+selected tool is activated in the toolbar. You can switch to the select tool
+by pressing the &Esc; key.
+</para>
+<para>
+When you have selected an edit tool from the Work Toolbar (for example, the tool to insert classes)
+the mouse pointer changes to a cross, and you can insert the elements in your model by single clicking
+in your diagram. Note that elements in &UML; must have a <emphasis>Unique Name</emphasis>. So that if
+you have a class in one diagram whose name is <quote>ClassA</quote> and then you use the insert Class
+tool to insert a class into another diagram you cannot name this new class <quote>ClassA</quote> as well.
+If these two are supposed to be two different elements, you have to give them a unique name. If you are
+trying to add the <emphasis>same</emphasis> element to your diagram, then the Insert Class is not
+the right tool for that. You should drag and drop the class from the Tree View instead.
+</para>
+</sect2>
+<sect2 id="delete-elements">
+<title>Deleting Elements</title>
+<para>
+You can delete any element by selecting the option <guimenuitem>Delete</guimenuitem> from its context menu.
+</para>
+<para>
+Again, there is a <emphasis>big</emphasis> difference between removing an object from a diagram, and
+deleting an object from your model:
+If you delete an object from within a diagram, you are only removing the object from that particular
+diagram: the element will still be part of your model and if there are other diagrams using the same
+element they will not suffer any change.
+If, on the other hand, you delete the element from the Tree View, you are actually deleting the
+element from your <emphasis>model</emphasis>. Since the element no longer exist in your model,
+it will be automatically removed from all the diagrams it appears in.
+</para>
+</sect2>
+<sect2 id="edit-elements">
+<title>Editing Elements</title>
+<para>
+You can edit most of the &UML; elements in your model and diagrams by opening its Properties dialog
+and selecting the appropriate options.
+To edit the properties of an object, select <guimenuitem>Properties</guimenuitem> from its context menu (&RMB; click). Each element has a dialog consisting of several pages where you can configure the options
+corresponding to that element. For some elements, like actors you can only set a couple of options,
+like the object name and documentation, while for other elements, like classes, you can edit its
+attributes and operations, select what you want to be shown in the diagram (whole operation signature
+or just operation names, etc) and even the colors you want to use for the line and fill of the class'
+representation on the diagram.
+</para>
+
+<para>
+For most &UML; elements you can also open the properties dialog by
+double clicking on it if you are using the selection tool (arrow). The
+exception to this is Associations, in which case a double click
+creates an anchor point. For associations you need to use the &RMB; context menu to get the properties dialog.
+</para>
+
+<para>
+Note that you can also select the properties option from the context
+menu of the elements in the Tree View. This allows you to also edit
+the properties for the diagrams, like setting whether the grid should
+be shown or not.
+</para>
+</sect2>
+<sect2 id="edit-classes">
+<title>Editing Classes</title>
+<para>
+Even though editing the properties of all objects was already covered in the previous section,
+classes deserve a special section because they are a bit more complicated and have more options
+than most of the other &UML; elements.
+</para>
+<para>
+In the properties dialog for a class you can set everything, from the color it uses to the operations
+and attributes it has.
+</para>
+<sect3 id="class-general-settings">
+<title>Class General Settings</title>
+<para>
+The General Settings page of the properties dialog is self-explanatory. Here you can change the
+class' name, visibility, documentation, &etc;
+This page is always available.
+</para>
+</sect3>
+<sect3 id="class-attributes-settings">
+<title>Class Attribute Settings</title>
+<para>
+In the Attributes Settings page you can add, edit, or delete attributes (variables) of the class.
+You can move attributes up and down the list by pressing the arrow button
+on the side.
+This page is always available.
+</para>
+</sect3>
+<sect3 id="class-operations-settings">
+<title>Class Operations Settings</title>
+<para>
+Similar to the Attribute Settings Page, in the Operation Settings Page you can add, edit, or
+remove operations for your class. When adding or editing an operation, you enter the basic data in
+the <emphasis>Operation Properties</emphasis> dialog. If you want to add parameters to your operation
+you need to click the <guibutton>New Parameter</guibutton> button, which will show the
+<emphasis>Parameter Properties</emphasis> dialog.
+This page is always available
+</para>
+</sect3>
+<sect3 id="class-template-settings">
+<title>Class Template Settings</title>
+<para>
+This page allows you to add class templates which are unspecified classes or datatypes. In Java 1.5 these will be called Generics.
+</para>
+</sect3>
+<sect3 id="class-associations-page">
+<title>Class Associations Page</title>
+<para>
+The <guilabel>Class Associations</guilabel> page shows all the associations of this class
+in the current diagram. Double clicking on an association shows its properties, and depending
+on the type of association you may modify some parameters here such as setting multiplicity and Role
+name. If the association does not allow such options be be modified, the Association Properties dialog
+is read-only and you can only modify the documentation associated with this association.
+</para>
+<para>
+This page is only available if you open the Class Properties from within a diagram. If you select
+the class properties from the context menu in the Tree View this page is not available.
+</para>
+</sect3>
+<sect3 id="class-display-page">
+<title>Class Display Page</title>
+<para>
+In the <guilabel>Display Options</guilabel> page, you can set what is to be shown in the diagram.
+A class can be shown as only one rectangle with the class name in it (useful if you have many
+classes in your diagram, or are for the moment not interested in the details of each class) or
+as complete as showing packages, stereotypes, and attributes and operations with full signature and
+visibility
+</para>
+<para>Depending on the amount of information you want to see you can select the corresponding
+options in this page. The changes you make here are only <emphasis>display options</emphasis>
+for the diagram. This means that <quote>hiding</quote> a class' operations only makes them
+not to be shown in the diagram, but the operation are still there as part of your model.
+This option is only available if you select the class properties from within a Diagram. If you open
+the class properties from the Tree View this page is missing since such Display Options do not make sense
+in that case</para>
+</sect3>
+<sect3 id="class-color-page">
+<title>Class Color Page</title>
+<para>
+In the <guilabel>Widget Color</guilabel> page you can configure the colors you want for the line
+and the fill of the widget. This option obviously makes sense only for classes displayed in diagrams,
+and is missing if you open the class' properties dialog from the Tree View.
+</para>
+</sect3>
+</sect2>
+
+<sect2 id="associations">
+<title>Associations</title>
+<para>
+Associations relate two &UML; objects to each other. Normally associations are defined between two classes,
+but some types of associations can also exists between use cases and actors.
+</para>
+<para>
+To create an association select the appropriate tool from the Work Toolbar (generic Association,
+Generalization, Aggregation, &etc;) and single click on the first element participating in the association
+and then single click on the second item participating. Note that those are two clicks, one on each
+on the objects participating in the association, it is <emphasis>not</emphasis> a drag from one object
+to the other. <!-- yet :) -->
+</para>
+<para>
+If you try to use an association in a way against the &UML; specification &umbrello; will refuse to create
+the association and you will get an error message. This would be the case if, for example, a Generalization
+exists from class A to class B and then you try to create another Generalization from Class B to class A
+</para>
+<para>
+<mousebutton>Right</mousebutton> clicking on an association will show a context menu with the actions you can apply on it. If you need to delete an association simply select the <guimenuitem>Delete</guimenuitem> option from this context menu.
+You can also select the <guimenuitem>Properties</guimenuitem> option and, depending on the association type
+edit attributes such as roles and multiplicity.
+</para>
+<sect3 id="anchor-points">
+<title>Anchor Points</title>
+<para>
+Associations are drawn, by default, as a straight line connecting the two objects in the diagram.
+</para>
+<para>
+You can add anchor points to bend an association by <mousebutton>double</mousebutton> clicking some where along the association line. This will insert
+an anchor point (displayed as a blue point when the association line is selected) which you can move
+around to give shape to the association
+</para>
+<para>
+If you need to remove an anchor point, <mousebutton>double</mousebutton> click on it again to remove it
+</para>
+<para>
+Note that the only way to edit the properties of an association is through the context menu. If you
+try to <mousebutton>double</mousebutton> click on it as with other &UML; objects, this will only insert an anchor point.
+</para>
+</sect3>
+</sect2>
+
+<sect2 id="notes">
+<title>Notes, Text and Boxes</title>
+<para>
+Notes, Lines Of Text and Boxes are elements that can be present in any type of diagram and have no real
+semantic value, but are very helpful to add extra comments or explanations that can make your
+diagram easier to understand.
+</para>
+<para>
+To add a Note or a Line Of Text, select the corresponding tool from the Work Toolbar and single click
+on the diagram where you want to put your comment. You can edit the text by opening the element through
+its context menu or in the case of notes by <mousebutton>double</mousebutton> clicking on them as well.
+</para>
+<sect3 id="anchors">
+<title>Anchors</title>
+<para>
+Anchors are used to link a text note and another &UML; Element together. For example, you normally
+use a text note to explain or make some comment about a class or a particular association, in which
+case you can use the anchor to make it clear that the note <quote>belongs</quote> to that particular
+element.
+</para>
+<para>
+To add an anchor between a note and another &UML; element, use the anchor tool from the work toolbar.
+You first need to click on the note and then click on the &UML; element you want the note to be linked
+to.
+</para>
+</sect3>
+</sect2>
+</sect1>
+</chapter>
+<!--edit-diagram-->
diff --git a/kapptemplate/ChangeLog b/kapptemplate/ChangeLog
new file mode 100644
index 00000000..1c1721c3
--- /dev/null
+++ b/kapptemplate/ChangeLog
@@ -0,0 +1,200 @@
+July-01-2004 - Michael Goettsche
+ o Update some dates to 2004
+
+Jan-09-2003 - Kurt Granroth
+ o Use variable subst in kpartapp/main.cpp instead of my hard-coded
+ email address
+ o Update some dates to 2003
+
+Mar-25-2002 - Frerich Raabe (v1.1.1)
+ o Changes to make kapptemplate work better under *BSD (no more hard-
+ coded 'make')
+
+Feb-12-2002 - Kurt Granroth (v1.1)
+ o Restructuring change to make kapptemplate behave a little better
+ during installation. Now, the standard 'make' commands should
+ work. The 'install-me' script is gone.
+
+Nov-10-2001 - Simon Hausmann
+ o Added missing kstatusbar.h include in app.cpp
+ o Use KParts::GenericFactory and KGenericFactory to reduce
+ boilerplate code
+
+Jul-30-2001 - Kurt Granroth
+ o KAppTemplate isn't really a 'sh' shell script.. it's a 'bash'
+ shell script. Changed #! line to reflect this.
+
+Jul-06-2001 - Kurt Granroth
+ o Fixed 'configure toolbar' in part app template
+ o KIONetAccess is now (and has been for some time) KIO::NetAccess
+
+Jul-05-2001 - Kurt Granroth (v1.0.6)
+ o KPartApp's part should be in it's own directory. Did it ever work
+ as-was? XML merging between shell and part should now work.
+ o Added new hi-color default icons to kpartapp and kapp
+
+Jun-30-2001 - David Faure
+ o Include .moc files in .cpp files in kapp template
+
+Mar-29-2001 - Nikolas Zimmermann
+ o Converted kapp template to use new KPrinter printing framework
+
+Feb-16-2001 - Kurt Granroth (v1.0.5)
+ o KParts::Factory, it seems, should not be used with plugins
+
+Feb-15-2001 - Kurt Granroth (v1.0.4)
+ o Create a "real" factory for the KPart plugins instead of using a
+ generic one
+ o Use 'find' instead of 'ls' for listing files. Works better on
+ FreeBSD. Thanks to Jonathan Belson <jon@witchspace.com> for the
+ heads up.
+ o Fixed command line args and module selection code. Thanks to
+ David Jarvie <djarvie@lineone.net> for the fix.
+
+Feb-04-2001 - Kurt Granroth (v1.0.3)
+ o Converted App::load method to use KURL instead of QString in kapp
+ module
+ o Added +[URL] command line option in kapp module
+
+Feb-04-2001 - Simon Hausman (v1.0.2)
+ o Converted App::load method to use KURL instead of QString in kpart
+ module
+ o Used correct constructor for Part in kpart module
+ o Used correct instance() in kpart module
+ o Other random correctness fixes in kpart module
+ o Added +[URL] command line option in kpart module
+
+Feb-04-2001 - Simon Hausman (v1.0.1)
+ o Fixed memory leak in plugin module
+ o Use createObject instead of old create in plugin module
+ o Added version number to xml file in plugin module
+ o Fixed integration of configure.in.in in kdesdk
+
+Feb-04-2001 - Kurt Granroth (v1.0)
+ o GIGANTIC REWRITE. This was *almost* a complete rewrite from
+ scratch
+ o Made entire system much more modular allowing for future
+ frameworks to be easily added
+ o Added module to create a full KParts application
+ o Added module to create a KPart plugin
+ o Added module to create an autoconf/automake framework for existing
+ source code
+ o Added more command-line options to speed up creation of projects
+ o Dropped knewclass and knewfunction as they were next to useless
+
+Dec-10-2000 - Kurt Granroth (v0.7.5)
+ o Finally fixed --noinit for real
+ o kapptemplate no longer needs to be in your $PATH
+
+Nov-20-2000 - Kurt Granroth (v0.7.4)
+ o Added custom menu item and menu as example on how to do it
+ o Fixed some --noinit bugs
+
+Oct-27-2000 - Stephan Kulow (v0.7.3)
+ o Fixed pot file handling. 'make package-messages' should now work.
+
+Oct-14-2000 - Malte Starostik (v0.7.2)
+ o Added --help option
+ o Added option to not run ./configure on newly created project
+
+Sep-26-2000 - Kurt Granroth (v0.7.1)
+ o Added hooks for more KAboutData information
+ o Now building moc files as moc.cpp instead of #including them
+
+Jul-21-2000 - Kurt Granroth (v0.7)
+ o Now using an HTML KPart component instead of a widget since that
+ is The Right Thing to Do(tm)
+ o Renamed .png files to use sizes in the names
+
+Jun-09-2000 - Kurt Granroth (v0.6.3)
+ o Added i18n() around preference titles... mostly so it would
+ compile with the newly ambiguous KDialogBase::addPage methods
+
+May-30-2000 - Kurt Granroth (v0.6.2)
+ o Removed KAccel stuff... KKeyDialog can handle action collections
+ o Use KURLRequesterDlg instead of homemade job
+
+Mar-14-2000 - Kurt Granroth (v0.6.1)
+ o Added toolbar editor
+ o Changed sample html code to reflect khtml changes
+
+Feb-26-2000 - Kurt Granroth (v0.6)
+ o Converted to use the new XML UI framework (big change!)
+
+Jan-12-2000 - Kurt Granroth (v0.5.2)
+ o Use KAboutData and KCmdLineArgs
+
+Dec-28-1999 - Kurt Granroth (v0.5.1)
+ o The po Makefile now uses the autogenerated rules. I don't know
+ why I didn't notice that capability before
+
+Dec-25-1999 - Kurt Granroth (v0.5)
+ o Use standard actions instead of constructing everything manually
+ (big change!)
+ o Allow .po files to be installed in $DESTDIR
+ o Added .spec file for RPM fans
+
+Dec-05-1999 - Kurt Granroth (v0.4.5)
+ o Changed 'QCString' to QString in DCOP iface stuff...
+
+Nov-29-1999 - Kurt Granroth (v0.4.4)
+ o Added sample DCOP client for app
+ o Fixed .desktop file
+ o Made QPrinter a member var so settings are saved
+
+Nov-26-1999 - Kurt Granroth (v0.4.3)
+ o Beefed up the print function with more boilerplate stuff
+ o KAccel keys should now work
+
+Nov-20-1999 - Kurt Granroth (v0.4.2)
+ o Use mkinstalldirs instead of mkdir
+
+Nov-04-1999 - Kurt Granroth (v0.4.1)
+ o Removed a few files from common/ that are in admin/ (missing,
+ install-sh, mkinstalldirs)
+ o Renamed .png files to "proper" naming convention
+ o Got rid of admin/ directory from CVS. It is now copied over from
+ the common admin directory (found in kdesdk/admin). This should
+ prevent a lot of redundent updates
+
+Nov-02-1999 - Kurt Granroth (v0.4)
+ o Updated for KDE 2.x. The produced application now has a LOT more
+ functionality than before -- it is a scriptable web browser (see
+ dcopclient.py for more info on that)!
+
+Jan-24-1999 - Kurt Granroth (v0.3.2)
+ o Added LIB_X11 and LIB_QT to acinclude.m4
+
+Jan-18-1999 - Kurt Granroth (v0.3.1)
+ o AUGH!! I forgot 'acinclude.m4'!!
+ o Slightly modified 'install-me' so that kapptemplate will install from
+ CVS. It was wigging out when it tried to cp the CVS directory...
+
+Jan-01-1999 - Kurt Granroth (v0.3)
+ o Added kapptemplate to kdesdk
+ o HUGE clean-up of code
+ o Put in some session management stuff
+ o Changed main() to use 'App *widget = new App;' instead of 'App widget'.
+ The latter case caused the app to seg fault if the user closed it
+ any way other than File->Quit
+
+Dec-31-1998 - Kurt Granroth
+ o Added 'knewfunction' module that will add a function to an existing
+ class
+
+Dec-27-1998 - Kurt Granroth
+ o Split kapptemplate into modules. Added 'knewclass' module that will
+ create a new class
+
+Dec-25-1998 - Kurt Granroth (v0.2.2)
+ o Fixed bug in App class where AppWidget needed 'this' parent
+ o Added 'pics' directory
+
+Dec-18-1998 - Kurt Granroth
+ o Added patch from Helmut Bohr <Helmut.Bohr@t-online.de> to properly
+ escape backquotes in po-Makefile.am
+ o Changed 'cp' to 'cp -p' to hopefully preserve executable permissions
+ where needed.
+
+Dec-04-1998 - Kurt Granroth (v0.2.1)
+ o released 0.2.1
diff --git a/kapptemplate/Makefile.am b/kapptemplate/Makefile.am
new file mode 100644
index 00000000..bf58afdc
--- /dev/null
+++ b/kapptemplate/Makefile.am
@@ -0,0 +1,19 @@
+SUBDIRS=admin appframework existing kapp kpartapp kpartplugin
+
+VERSION := `cat $(srcdir)/VERSION`
+
+bin_SCRIPTS = kapptemplate
+
+kapptemplate: kapptemplate.in
+ echo "#!/usr/bin/env bash" > kapptemplate; \
+ echo "INSTALLED_SHARE_DIR=$(kde_datadir)/kapptemplate" >> kapptemplate; \
+ echo "KAPPTEMPLATEVERSION=$(VERSION)" >> kapptemplate; \
+ cat $(srcdir)/kapptemplate.in >> kapptemplate; \
+ chmod 755 kapptemplate
+
+databindir = $(kde_datadir)/kapptemplate/bin
+databin_SCRIPTS = mkinstalldirs
+
+moduledir = $(kde_datadir)/kapptemplate/include
+module_DATA = kapptemplate.common kapptemplate.module \
+ kpartplugin.module kpartapp.module existing.module
diff --git a/kapptemplate/Makefile.cvs b/kapptemplate/Makefile.cvs
new file mode 100644
index 00000000..2d5db15f
--- /dev/null
+++ b/kapptemplate/Makefile.cvs
@@ -0,0 +1,12 @@
+all:
+ @echo "Copying over the admin directory"; \
+ for file in admin/*; do \
+ if [ -f $$file -a $$file != 'admin/Makefile.am' -a $$file != 'admin/Makefile.in' ]; then \
+ /bin/rm -f $$file; \
+ fi \
+ done
+ @for file in ../admin/*; do \
+ if [ -f $$file ]; then \
+ cp -p $$file admin/; \
+ fi \
+ done
diff --git a/kapptemplate/README b/kapptemplate/README
new file mode 100644
index 00000000..9ee09553
--- /dev/null
+++ b/kapptemplate/README
@@ -0,0 +1,68 @@
+KAppTemplate v1.1
+Kurt Granroth <granroth@kde.org>
+----------------------------------------------------------------------
+
+What is it?
+-----------
+KAppTemplate is a shell script that will create the necessary
+framework to develop various KDE applications. It takes care of the
+autoconf/automake code as well as providing a skeleton and example of
+what the code typically looks like.
+
+Currently, KAppTemplate creates four different types of frameworks:
+
+1) Full featured KDE application
+
+ This is a "normal" KDE application with nearly every bleeding edge
+ feature.
+
+2) KPart application
+
+ This creates a KDE application that uses KParts as both the Shell
+ and the Part (KParts::MainWindow and KParts::ReadWritePart)
+
+3) KPart plugin
+
+ This creates a sample KPart plugin that acts on KHTMLPart
+
+4) Existing application conversion
+
+ This will take existing source and put it in a KDE automake/autoconf
+ framework
+
+What is a framework?
+--------------------
+When I say "framework", I mean all of the source files as well as the
+autoconf/automake stuff. When KAppTemplate is done, all you will need
+to do to compile and install your app is:
+ ./configure
+ make && make install
+
+What do I need to use this?
+---------------------------
+o KDE 3.x
+o autoconf
+o automake
+
+How do I install it?
+--------------------
+If you have a standalone kapptemplate.tar.bz2, do:
+ ./configure
+ make && make install
+If you are installing from kdesdk, then just
+ make && make install
+If you are installing from .deb or .rpm, then install like any other
+normal package
+
+How does <whatever> work?
+-------------------------
+Before you email me, look through the kapptemplate file. It is a
+shell script so it should be pretty easy to understand what is going
+on.
+
+I have a suggest, question, or comment
+--------------------------------------
+Well, email me, then!
+
+Have fun!
+Kurt Granroth <granroth@kde.org>
diff --git a/kapptemplate/VERSION b/kapptemplate/VERSION
new file mode 100644
index 00000000..524cb552
--- /dev/null
+++ b/kapptemplate/VERSION
@@ -0,0 +1 @@
+1.1.1
diff --git a/kapptemplate/admin/Makefile.am b/kapptemplate/admin/Makefile.am
new file mode 100644
index 00000000..fef6965c
--- /dev/null
+++ b/kapptemplate/admin/Makefile.am
@@ -0,0 +1,12 @@
+install-data-local:
+ $(mkinstalldirs) $(DESTDIR)$(kde_datadir)/kapptemplate/admin
+ for file in $(srcdir)/*; do \
+ if [ -f $$file -a $$file != 'Makefile' -a $$file != 'Makefile.in' -a $$file != 'Makefile.am' ]; then \
+ destfile=`basename $$file` \
+ $(INSTALL_DATA) $$file \
+ $(DESTDIR)$(kde_datadir)/kapptemplate/admin/$$destfile; \
+ fi \
+ done
+
+uninstall-local:
+ -/bin/rm -rf $(DESTDIR)$(kde_datadir)/kapptemplate/admin
diff --git a/kapptemplate/appframework/AUTHORS b/kapptemplate/appframework/AUTHORS
new file mode 100644
index 00000000..4c2a9fd3
--- /dev/null
+++ b/kapptemplate/appframework/AUTHORS
@@ -0,0 +1,3 @@
+echo "Creating $LOCATION_ROOT/AUTHORS...";
+cat << EOF > $LOCATION_ROOT/AUTHORS
+$AUTHOR <$EMAIL>
diff --git a/kapptemplate/appframework/COPYING b/kapptemplate/appframework/COPYING
new file mode 100644
index 00000000..7b7dedf5
--- /dev/null
+++ b/kapptemplate/appframework/COPYING
@@ -0,0 +1,2 @@
+echo "Creating $LOCATION_ROOT/COPYING...";
+cp $SHARE_DIR/appframework/no-exe/COPYING $LOCATION_ROOT/COPYING
diff --git a/kapptemplate/appframework/ChangeLog b/kapptemplate/appframework/ChangeLog
new file mode 100644
index 00000000..290f8348
--- /dev/null
+++ b/kapptemplate/appframework/ChangeLog
@@ -0,0 +1,4 @@
+echo "Creating $LOCATION_ROOT/ChangeLog...";
+cat << EOF > $LOCATION_ROOT/ChangeLog
+`date` - $AUTHOR <$EMAIL>
+ o Initial Creation
diff --git a/kapptemplate/appframework/INSTALL b/kapptemplate/appframework/INSTALL
new file mode 100644
index 00000000..79fa82c8
--- /dev/null
+++ b/kapptemplate/appframework/INSTALL
@@ -0,0 +1,2 @@
+echo "Creating $LOCATION_ROOT/INSTALL...";
+cp $SHARE_DIR/appframework/no-exe/INSTALL $LOCATION_ROOT/INSTALL
diff --git a/kapptemplate/appframework/Makefile.am b/kapptemplate/appframework/Makefile.am
new file mode 100644
index 00000000..25ad4464
--- /dev/null
+++ b/kapptemplate/appframework/Makefile.am
@@ -0,0 +1,6 @@
+SUBDIRS=no-exe
+
+frameworkdir = $(kde_datadir)/kapptemplate/appframework
+framework_DATA = AUTHORS INSTALL COPYING NEWS app.lsm \
+ app.spec configure.in.in.in README base-Makefile.am \
+ ChangeLog VERSION base-Makefile.cvs po-Makefile.am
diff --git a/kapptemplate/appframework/NEWS b/kapptemplate/appframework/NEWS
new file mode 100644
index 00000000..30fa36b4
--- /dev/null
+++ b/kapptemplate/appframework/NEWS
@@ -0,0 +1,3 @@
+echo "Creating $LOCATION_ROOT/NEWS...";
+cat << EOF > $LOCATION_ROOT/NEWS
+
diff --git a/kapptemplate/appframework/README b/kapptemplate/appframework/README
new file mode 100644
index 00000000..abfbcdb5
--- /dev/null
+++ b/kapptemplate/appframework/README
@@ -0,0 +1,6 @@
+echo "Creating $LOCATION_ROOT/README...";
+cat << EOF > $LOCATION_ROOT/README
+$APP_NAME v$APP_VERSION
+$AUTHOR <$EMAIL>
+----------------------------------------------------------------------
+This is where you should describe why $APP_NAME is so great
diff --git a/kapptemplate/appframework/VERSION b/kapptemplate/appframework/VERSION
new file mode 100644
index 00000000..2d8347f1
--- /dev/null
+++ b/kapptemplate/appframework/VERSION
@@ -0,0 +1,3 @@
+echo "Creating $LOCATION_ROOT/VERSION...";
+cat << EOF > $LOCATION_ROOT/VERSION
+$APP_NAME v$APP_VERSION
diff --git a/kapptemplate/appframework/app.lsm b/kapptemplate/appframework/app.lsm
new file mode 100644
index 00000000..bf4d32fb
--- /dev/null
+++ b/kapptemplate/appframework/app.lsm
@@ -0,0 +1,18 @@
+echo "Creating $LOCATION_ROOT/$APP_NAME_LC.lsm...";
+cat << EOF > $LOCATION_ROOT/$APP_NAME_LC.lsm
+Begin4
+Title: $APP_NAME -- Some description
+Version: $APP_VERSION
+Entered-date: YYYY-MM-DD
+Description:
+Keywords: KDE3 Qt
+Author: $AUTHOR <$EMAIL>
+Maintained-by: $AUTHOR <$EMAIL>
+Home-page:
+Alternate-site:
+Primary-site: ftp://ftp.kde.org/pub/kde/unstable/apps/utils
+ xxxxxx $APP_NAME_LC-$APP_VERSION.tar.gz
+ xxx $APP_NAME_LC-$APP_VERSION.lsm
+Platform: Linux. Needs KDE 2.x
+Copying-policy: GPL
+End
diff --git a/kapptemplate/appframework/app.spec b/kapptemplate/appframework/app.spec
new file mode 100644
index 00000000..b0f3fd48
--- /dev/null
+++ b/kapptemplate/appframework/app.spec
@@ -0,0 +1,44 @@
+echo "Creating $LOCATION_ROOT/$APP_NAME_LC.spec...";
+cat << EOF > $LOCATION_ROOT/$APP_NAME_LC.spec
+%define distversion %( perl -e '$_=\<\>;/(\\d+)\\.(\\d)\\.?(\\d)?/; print "$1$2".($3||0)' /etc/*-release)
+Name: ${APP_NAME_LC}
+Summary: ${APP_NAME} -- Some description
+Version: ${APP_VERSION}
+Release: %{_vendor}_%{distversion}
+Copyright: GPL
+Group: X11/KDE/Utilities
+Source: ftp://ftp.kde.org/pub/kde/unstable/apps/utils/%{name}-%{version}.tar.gz
+Packager: ${AUTHOR} <${EMAIL}>
+BuildRoot: /tmp/%{name}-%{version}
+Prefix: `kde-config --prefix`
+
+%description
+A long description
+
+%prep
+rm -rf \$RPM_BUILD_ROOT
+%setup -n %{name}-%{version}
+CFLAGS="$RPM_OPT_FLAGS" CXXFLAGS="$RPM_OPT_FLAGS" ./configure \
+ --disable-debug --enable-final --prefix=%{prefix}
+
+%build
+# Setup for parallel builds
+numprocs=`egrep -c ^cpu[0-9]+ /proc/stat || :`
+if [ "$numprocs" = "0" ]; then
+ numprocs=1
+fi
+
+make -j$numprocs
+
+%install
+make install-strip DESTDIR=\$RPM_BUILD_ROOT
+
+cd $RPM_BUILD_ROOT
+find . -type d | sed '1,2d;s,^\.,\%attr(-\,root\,root) \%dir ,' > $RPM_BUILD_DIR/%{name}-master.list
+find . -type f -o -type l | sed 's|^\.||' >> \$RPM_BUILD_DIR/%{name}-master.list
+
+%clean
+rm -rf \$RPM_BUILD_DIR/%{name}-%{version}
+rm -rf \$RPM_BUILD_DIR/${name}-master.list
+
+%files -f \$RPM_BUILD_DIR/%{name}-master.list
diff --git a/kapptemplate/appframework/base-Makefile.am b/kapptemplate/appframework/base-Makefile.am
new file mode 100644
index 00000000..eef7f78c
--- /dev/null
+++ b/kapptemplate/appframework/base-Makefile.am
@@ -0,0 +1,11 @@
+echo "Creating $LOCATION_ROOT/Makefile.am.in...";
+cat << EOF > $LOCATION_ROOT/Makefile.am.in
+
+AUTOMAKE_OPTIONS = foreign 1.5
+DISTCLEANFILES = inst-apps
+MAINTAINERCLEANFILES = subdirs configure.in acinclude.m4 configure.files
+
+include admin/deps.am
+
+include admin/Doxyfile.am
+
diff --git a/kapptemplate/appframework/base-Makefile.cvs b/kapptemplate/appframework/base-Makefile.cvs
new file mode 100644
index 00000000..60510887
--- /dev/null
+++ b/kapptemplate/appframework/base-Makefile.cvs
@@ -0,0 +1,12 @@
+echo "Creating $LOCATION_ROOT/Makefile.cvs...";
+cat << EOF > $LOCATION_ROOT/Makefile.cvs
+all:
+ @echo "This Makefile is only for the CVS repository"
+ @echo "This will be deleted before making the distribution"
+ @echo ""
+ \$(MAKE) -f admin/Makefile.common cvs
+
+dist:
+ \$(MAKE) -f admin/Makefile.common dist
+
+.SILENT:
diff --git a/kapptemplate/appframework/configure.in.in.in b/kapptemplate/appframework/configure.in.in.in
new file mode 100644
index 00000000..8b120500
--- /dev/null
+++ b/kapptemplate/appframework/configure.in.in.in
@@ -0,0 +1,3 @@
+echo "Creating $LOCATION_ROOT/configure.in.in...";
+cat << EOF > $LOCATION_ROOT/configure.in.in
+#MIN_CONFIG
diff --git a/kapptemplate/appframework/no-exe/COPYING b/kapptemplate/appframework/no-exe/COPYING
new file mode 100644
index 00000000..96bdc086
--- /dev/null
+++ b/kapptemplate/appframework/no-exe/COPYING
@@ -0,0 +1,339 @@
+ GNU GENERAL PUBLIC LICENSE
+ Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+ 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users. This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it. (Some other Free Software Foundation software is covered by
+the GNU Library General Public License instead.) You can apply it to
+your programs, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+ To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have. You must make sure that they, too, receive or can get the
+source code. And you must show them these terms so they know their
+rights.
+
+ We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+ Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software. If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+ Finally, any free program is threatened constantly by software
+patents. We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary. To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ GNU GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License. The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language. (Hereinafter, translation is included without limitation in
+the term "modification".) Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+ 1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+ 2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) You must cause the modified files to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ b) You must cause any work that you distribute or publish, that in
+ whole or in part contains or is derived from the Program or any
+ part thereof, to be licensed as a whole at no charge to all third
+ parties under the terms of this License.
+
+ c) If the modified program normally reads commands interactively
+ when run, you must cause it, when started running for such
+ interactive use in the most ordinary way, to print or display an
+ announcement including an appropriate copyright notice and a
+ notice that there is no warranty (or else, saying that you provide
+ a warranty) and that users may redistribute the program under
+ these conditions, and telling the user how to view a copy of this
+ License. (Exception: if the Program itself is interactive but
+ does not normally print such an announcement, your work based on
+ the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+ a) Accompany it with the complete corresponding machine-readable
+ source code, which must be distributed under the terms of Sections
+ 1 and 2 above on a medium customarily used for software interchange; or,
+
+ b) Accompany it with a written offer, valid for at least three
+ years, to give any third party, for a charge no more than your
+ cost of physically performing source distribution, a complete
+ machine-readable copy of the corresponding source code, to be
+ distributed under the terms of Sections 1 and 2 above on a medium
+ customarily used for software interchange; or,
+
+ c) Accompany it with the information you received as to the offer
+ to distribute corresponding source code. (This alternative is
+ allowed only for noncommercial distribution and only if you
+ received the program in object code or executable form with such
+ an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it. For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable. However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License. Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+ 5. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Program or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+ 6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+ 7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all. For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+ 8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded. In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+ 9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time. Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation. If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+ 10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission. For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this. Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+ NO WARRANTY
+
+ 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+ 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+ END OF TERMS AND CONDITIONS
+
+ Appendix: How to Apply These Terms to Your New Programs
+
+ If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+ To do so, attach the following notices to the program. It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the program's name and a brief idea of what it does.>
+ Copyright (C) 19yy <name of author>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the 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, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+ Gnomovision version 69, Copyright (C) 19yy name of author
+ Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+ This is free software, and you are welcome to redistribute it
+ under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License. Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary. Here is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+ `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+ <signature of Ty Coon>, 1 April 1989
+ Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs. If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library. If this is what you want to do, use the GNU Library General
+Public License instead of this License.
diff --git a/kapptemplate/appframework/no-exe/INSTALL b/kapptemplate/appframework/no-exe/INSTALL
new file mode 100644
index 00000000..28fadaa7
--- /dev/null
+++ b/kapptemplate/appframework/no-exe/INSTALL
@@ -0,0 +1,181 @@
+Basic Installation
+==================
+
+ These are generic installation instructions.
+
+ The `configure' shell script attempts to guess correct values for
+various system-dependent variables used during compilation. It uses
+those values to create a `Makefile' in each directory of the package.
+It may also create one or more `.h' files containing system-dependent
+definitions. Finally, it creates a shell script `config.status' that
+you can run in the future to recreate the current configuration, a file
+`config.cache' that saves the results of its tests to speed up
+reconfiguring, and a file `config.log' containing compiler output
+(useful mainly for debugging `configure').
+
+ If you need to do unusual things to compile the package, please try
+to figure out how `configure' could check whether to do them, and mail
+diffs or instructions to the address given in the `README' so they can
+be considered for the next release. If at some point `config.cache'
+contains results you don't want to keep, you may remove or edit it.
+
+ The file `configure.in' is used to create `configure' by a program
+called `autoconf'. You only need `configure.in' if you want to change
+it or regenerate `configure' using a newer version of `autoconf'.
+
+The simplest way to compile this package is:
+
+ 1. `cd' to the directory containing the package's source code and type
+ `./configure' to configure the package for your system. If you're
+ using `csh' on an old version of System V, you might need to type
+ `sh ./configure' instead to prevent `csh' from trying to execute
+ `configure' itself.
+
+ Running `configure' takes awhile. While running, it prints some
+ messages telling which features it is checking for.
+
+ 2. Type `make' to compile the package.
+
+ 3. Optionally, type `make check' to run any self-tests that come with
+ the package.
+
+ 4. Type `make install' to install the programs and any data files and
+ documentation.
+
+ 5. You can remove the program binaries and object files from the
+ source code directory by typing `make clean'. To also remove the
+ files that `configure' created (so you can compile the package for
+ a different kind of computer), type `make distclean'. There is
+ also a `make maintainer-clean' target, but that is intended mainly
+ for the package's developers. If you use it, you may have to get
+ all sorts of other programs in order to regenerate files that came
+ with the distribution.
+
+Compilers and Options
+=====================
+
+ Some systems require unusual options for compilation or linking that
+the `configure' script does not know about. You can give `configure'
+initial values for variables by setting them in the environment. Using
+a Bourne-compatible shell, you can do that on the command line like
+this:
+ CC=c89 CFLAGS=-O2 LIBS=-lposix ./configure
+
+Or on systems that have the `env' program, you can do it like this:
+ env CPPFLAGS=-I/usr/local/include LDFLAGS=-s ./configure
+
+Compiling For Multiple Architectures
+====================================
+
+ You can compile the package for more than one kind of computer at the
+same time, by placing the object files for each architecture in their
+own directory. To do this, you must use a version of `make' that
+supports the `VPATH' variable, such as GNU `make'. `cd' to the
+directory where you want the object files and executables to go and run
+the `configure' script. `configure' automatically checks for the
+source code in the directory that `configure' is in and in `..'.
+
+ If you have to use a `make' that does not supports the `VPATH'
+variable, you have to compile the package for one architecture at a time
+in the source code directory. After you have installed the package for
+one architecture, use `make distclean' before reconfiguring for another
+architecture.
+
+Installation Names
+==================
+
+ By default, `make install' will install the package's files in
+`/usr/local/bin', `/usr/local/man', etc. You can specify an
+installation prefix other than `/usr/local' by giving `configure' the
+option `--prefix=PATH'.
+
+ You can specify separate installation prefixes for
+architecture-specific files and architecture-independent files. If you
+give `configure' the option `--exec-prefix=PATH', the package will use
+PATH as the prefix for installing programs and libraries.
+Documentation and other data files will still use the regular prefix.
+
+ In addition, if you use an unusual directory layout you can give
+options like `--bindir=PATH' to specify different values for particular
+kinds of files. Run `configure --help' for a list of the directories
+you can set and what kinds of files go in them.
+
+ If the package supports it, you can cause programs to be installed
+with an extra prefix or suffix on their names by giving `configure' the
+option `--program-prefix=PREFIX' or `--program-suffix=SUFFIX'.
+
+Optional Features
+=================
+
+ Some packages pay attention to `--enable-FEATURE' options to
+`configure', where FEATURE indicates an optional part of the package.
+They may also pay attention to `--with-PACKAGE' options, where PACKAGE
+is something like `gnu-as' or `x' (for the X Window System). The
+`README' should mention any `--enable-' and `--with-' options that the
+package recognizes.
+
+ For packages that use the X Window System, `configure' can usually
+find the X include and library files automatically, but if it doesn't,
+you can use the `configure' options `--x-includes=DIR' and
+`--x-libraries=DIR' to specify their locations.
+
+Specifying the System Type
+==========================
+
+ There may be some features `configure' can not figure out
+automatically, but needs to determine by the type of host the package
+will run on. Usually `configure' can figure that out, but if it prints
+a message saying it can not guess the host type, give it the
+`--host=TYPE' option. TYPE can either be a short name for the system
+type, such as `sun4', or a canonical name with three fields:
+ CPU-COMPANY-SYSTEM
+
+See the file `config.sub' for the possible values of each field. If
+`config.sub' isn't included in this package, then this package doesn't
+need to know the host type.
+
+ If you are building compiler tools for cross-compiling, you can also
+use the `--target=TYPE' option to select the type of system they will
+produce code for and the `--build=TYPE' option to select the type of
+system on which you are compiling the package.
+
+Sharing Defaults
+================
+
+ If you want to set default values for `configure' scripts to share,
+you can create a site shell script called `config.site' that gives
+default values for variables like `CC', `cache_file', and `prefix'.
+`configure' looks for `PREFIX/share/config.site' if it exists, then
+`PREFIX/etc/config.site' if it exists. Or, you can set the
+`CONFIG_SITE' environment variable to the location of the site script.
+A warning: not all `configure' scripts look for a site script.
+
+Operation Controls
+==================
+
+ `configure' recognizes the following options to control how it
+operates.
+
+`--cache-file=FILE'
+ Use and save the results of the tests in FILE instead of
+ `./config.cache'. Set FILE to `/dev/null' to disable caching, for
+ debugging `configure'.
+
+`--help'
+ Print a summary of the options to `configure', and exit.
+
+`--quiet'
+`--silent'
+`-q'
+ Do not print messages saying which checks are being made.
+
+`--srcdir=DIR'
+ Look for the package's source code in directory DIR. Usually
+ `configure' can determine that directory automatically.
+
+`--version'
+ Print the version of Autoconf used to generate the `configure'
+ script, and exit.
+
+`configure' also accepts some other, not widely useful, options.
+
diff --git a/kapptemplate/appframework/no-exe/Makefile.am b/kapptemplate/appframework/no-exe/Makefile.am
new file mode 100644
index 00000000..d61ae693
--- /dev/null
+++ b/kapptemplate/appframework/no-exe/Makefile.am
@@ -0,0 +1,2 @@
+frameworkdir = $(kde_datadir)/kapptemplate/appframework/no-exe
+framework_DATA = COPYING INSTALL
diff --git a/kapptemplate/appframework/po-Makefile.am b/kapptemplate/appframework/po-Makefile.am
new file mode 100644
index 00000000..c06e6ff9
--- /dev/null
+++ b/kapptemplate/appframework/po-Makefile.am
@@ -0,0 +1,3 @@
+echo "Creating $LOCATION_ROOT/po/Makefile.am...";
+cat << EOF > $LOCATION_ROOT/po/Makefile.am
+POFILES = AUTO
diff --git a/kapptemplate/existing.module b/kapptemplate/existing.module
new file mode 100644
index 00000000..01a4e710
--- /dev/null
+++ b/kapptemplate/existing.module
@@ -0,0 +1,118 @@
+function GetCurrentSource
+{
+ # First, get the location of the existing source code
+ unset SOURCE_LOCATION;
+ while [ ! "$SOURCE_LOCATION" ];
+ do
+ $ECHO "What directory contains the existing files? [no default]";
+ $ECHO ": \c";
+ read SOURCE_LOCATION;
+
+ if [ ! -d $SOURCE_LOCATION ];
+ then
+ $ECHO "Directory does not exist. Try again.";
+ $ECHO;
+ unset SOURCE_LOCATION;
+ fi
+ done
+ $ECHO;
+
+ # Now, find C++ source and header files
+ CUR_PWD=$PWD;
+ cd $SOURCE_LOCATION;
+ EXISTING_SOURCE=`/bin/ls -x *.C *.cpp *.cc`;
+ EXISTING_HEADER=`/bin/ls -x *.h`;
+ cd $CUR_PWD;
+
+ # Sanity check
+ if [ "$EXISTING_SOURCE" -o "$EXISTING_HEADER" ];
+ then
+ $ECHO "Found these files: $EXISTING_SOURCE $EXISTING_HEADER";
+ else
+ $ECHO "Could not find any source files in that directory";
+ exit 1;
+ fi
+}
+
+###########################################################################
+#
+# STEP 1: GET USER INFORMATION
+#
+###########################################################################
+# Get the application name
+APPTYPE="existing application";
+unset APPDEFAULT;
+GetProperName
+
+# Get the application version
+GetVersion
+
+# Get where the sources currently are
+GetCurrentSource
+
+# Get the root where this framework will be installed
+GetLocationRoot
+
+# Get the author's name
+GetAuthorName
+
+# Get the author's email
+GetAuthorEmail
+
+# Verify that everything is grand
+$ECHO;
+$ECHO "Here is what I have:";
+$ECHO "The application: $APP_NAME v$APP_VERSION";
+$ECHO "Installed in: $LOCATION_ROOT";
+$ECHO "Source from: $SOURCE_LOCATION";
+$ECHO "Author: $AUTHOR <$EMAIL>";
+$ECHO;
+$ECHO "Is this correct (Y/n)? ";
+$ECHO ": \c";
+read Y_N;
+if [ $Y_N -a $Y_N = 'n' ];
+then
+ $ECHO "AUGH! Well, try again.";
+ exit 0;
+fi
+$ECHO;
+
+$ECHO "OK, Here we go!!";
+
+###########################################################################
+#
+# STEP 2: CREATE APPLICATION FRAMEWORK
+#
+###########################################################################
+CreateAppFramework
+
+###########################################################################
+#
+# STEP 3: HANDLE EXISTING FILES
+#
+###########################################################################
+for FILE in $EXISTING_SOURCE;
+do
+ cp -f $SOURCE_LOCATION/$FILE $LOCATION_ROOT/$APP_NAME_LC/$FILE
+done
+for FILE in $EXISTING_HEADER;
+do
+ cp -f $SOURCE_LOCATION/$FILE $LOCATION_ROOT/$APP_NAME_LC/$FILE
+done
+
+for EXE_FILE in $EXISTING_FILES;
+do
+ . $SHARE_DIR/existing/$EXE_FILE || exit 1;
+done
+
+###########################################################################
+#
+# STEP 4: FINAL STEPS
+#
+###########################################################################
+
+if [ ! $NOINIT ]; then
+ cd $LOCATION_ROOT && $MAKE -f Makefile.cvs
+fi
+
+$ECHO "DONE!";
diff --git a/kapptemplate/existing/Makefile.am b/kapptemplate/existing/Makefile.am
new file mode 100644
index 00000000..3abf5838
--- /dev/null
+++ b/kapptemplate/existing/Makefile.am
@@ -0,0 +1,2 @@
+existingdir = $(kde_datadir)/kapptemplate/existing
+existing_DATA = app-Makefile.am app-desktop
diff --git a/kapptemplate/existing/app-Makefile.am b/kapptemplate/existing/app-Makefile.am
new file mode 100644
index 00000000..79236a7f
--- /dev/null
+++ b/kapptemplate/existing/app-Makefile.am
@@ -0,0 +1,34 @@
+echo "Creating $LOCATION_ROOT/$APP_NAME_LC/Makefile.am...";
+cat << EOF > $LOCATION_ROOT/$APP_NAME_LC/Makefile.am
+# this has all of the subdirectories that make will recurse into. if
+# there are none, comment this out
+#SUBDIRS =
+
+# this is the program that gets installed. it's name is used for all
+# of the other Makefile.am variables
+bin_PROGRAMS = $APP_NAME_LC
+
+# set the include path for X, qt and KDE
+INCLUDES = \$(all_includes)
+
+# the library search path.
+${APP_NAME_LC}_LDFLAGS = \$(KDE_RPATH) \$(all_libraries)
+
+# the libraries to link against.
+${APP_NAME_LC}_LDADD = \$(LIB_KFILE)
+
+# which sources should be compiled for $APP_NAME_LC
+${APP_NAME_LC}_SOURCES = ${EXISTING_SOURCE}
+
+# these are the headers for your project that won't be installed
+noinst_HEADERS = ${EXISTING_HEADER}
+
+# let automoc handle all of the meta source files (moc)
+METASOURCES = AUTO
+
+messages: rc.cpp
+ \$(XGETTEXT) *.cpp -o \$(podir)/${APP_NAME_LC}.pot
+
+# this is where the desktop file will go
+desktopdir = \$(kde_appsdir)/Utilities
+desktop_DATA = ${APP_NAME_LC}.desktop
diff --git a/kapptemplate/existing/app-desktop b/kapptemplate/existing/app-desktop
new file mode 100644
index 00000000..857fb224
--- /dev/null
+++ b/kapptemplate/existing/app-desktop
@@ -0,0 +1,9 @@
+echo "Creating $LOCATION_ROOT/${APP_NAME_LC}/${APP_NAME_LC}.desktop...";
+cat << EOF > $LOCATION_ROOT/${APP_NAME_LC}/${APP_NAME_LC}.desktop
+[Desktop Entry]
+Encoding=UTF-8
+Name=${APP_NAME}
+Exec=${APP_NAME_LC} %i %m -caption "%c"
+Type=Application
+Terminal=0
+GenericName=A KDE Application
diff --git a/kapptemplate/kapp/Makefile.am b/kapptemplate/kapp/Makefile.am
new file mode 100644
index 00000000..6d1a196c
--- /dev/null
+++ b/kapptemplate/kapp/Makefile.am
@@ -0,0 +1,9 @@
+SUBDIRS=no-exe
+
+kappdir = $(kde_datadir)/kapptemplate/kapp
+kapp_DATA = app_client.cpp appview.h index.docbook \
+ app-Makefile.am appiface.h doc-Makefile.am lo16-app-app.png \
+ app-configure.in.in apppref.cpp doc-app-Makefile.am \
+ lo32-app-app.png app.cpp apppref.h hi16-app-app.png main.cpp \
+ app-desktop appui.rc hi32-app-app.png app.h appview.cpp \
+ hi48-app-app.png pics-Makefile.am
diff --git a/kapptemplate/kapp/app-Makefile.am b/kapptemplate/kapp/app-Makefile.am
new file mode 100644
index 00000000..9ed82a08
--- /dev/null
+++ b/kapptemplate/kapp/app-Makefile.am
@@ -0,0 +1,47 @@
+echo "Creating $LOCATION_ROOT/$APP_NAME_LC/Makefile.am...";
+cat << EOF > $LOCATION_ROOT/$APP_NAME_LC/Makefile.am
+## Makefile.am for $APP_NAME_LC
+
+# this has all of the subdirectories that make will recurse into. if
+# there are none, comment this out
+SUBDIRS = . pics
+
+# this is the program that gets installed. it's name is used for all
+# of the other Makefile.am variables
+bin_PROGRAMS = $APP_NAME_LC ${APP_NAME_LC}_client
+
+# set the include path for X, qt and KDE
+INCLUDES = \$(all_includes)
+
+# the library search path.
+${APP_NAME_LC}_LDFLAGS = \$(KDE_RPATH) \$(all_libraries)
+
+# the libraries to link against.
+${APP_NAME_LC}_LDADD = \$(LIB_KFILE) -lkdeprint
+
+# which sources should be compiled for $APP_NAME_LC
+${APP_NAME_LC}_SOURCES = main.cpp ${APP_NAME_LC}.cpp ${APP_NAME_LC}view.cpp \\
+ ${APP_NAME_LC}pref.cpp ${APP_NAME_LC}iface.skel
+
+# these are the headers for your project
+noinst_HEADERS = ${APP_NAME_LC}.h ${APP_NAME_LC}view.h ${APP_NAME_LC}pref.h
+
+# client stuff
+${APP_NAME_LC}_client_LDFLAGS = \$(KDE_RPATH) \$(all_libraries)
+${APP_NAME_LC}_client_LDADD = \$(LIB_KDECORE)
+${APP_NAME_LC}_client_SOURCES = ${APP_NAME_LC}_client.cpp
+
+# let automoc handle all of the meta source files (moc)
+METASOURCES = AUTO
+
+messages: rc.cpp
+ \$(XGETTEXT) *.cpp -o \$(podir)/${APP_NAME_LC}.pot
+
+KDE_ICON = $APP_NAME_LC
+
+# this is where the kdelnk file will go
+xdg_apps_data = ${APP_NAME_LC}.desktop
+
+# this is where the XML-GUI resource file goes
+rcdir = \$(kde_datadir)/${APP_NAME_LC}
+rc_DATA = ${APP_NAME_LC}ui.rc
diff --git a/kapptemplate/kapp/app-configure.in.in b/kapptemplate/kapp/app-configure.in.in
new file mode 100644
index 00000000..4d050a09
--- /dev/null
+++ b/kapptemplate/kapp/app-configure.in.in
@@ -0,0 +1,14 @@
+echo "Creating $LOCATION_ROOT/configure.in.in...";
+cat << EOF > $LOCATION_ROOT/configure.in.in
+#MIN_CONFIG
+
+AM_INIT_AUTOMAKE(${APP_NAME_LC}, ${APP_VERSION})
+
+dnl These are common macros that you might or might not want to use
+
+dnl Checks for header files.
+AC_HEADER_DIRENT
+AC_HEADER_STDC
+AC_HEADER_TIME
+AC_CHECK_HEADERS(fcntl.h sys/time.h unistd.h stdlib.h paths.h)
+AC_CHECK_FUNCS(usleep)
diff --git a/kapptemplate/kapp/app-desktop b/kapptemplate/kapp/app-desktop
new file mode 100644
index 00000000..118e0211
--- /dev/null
+++ b/kapptemplate/kapp/app-desktop
@@ -0,0 +1,11 @@
+echo "Creating $LOCATION_ROOT/${APP_NAME_LC}/${APP_NAME_LC}.desktop...";
+cat << EOF > $LOCATION_ROOT/${APP_NAME_LC}/${APP_NAME_LC}.desktop
+[Desktop Entry]
+Encoding=UTF-8
+Name=${APP_NAME}
+Exec=${APP_NAME_LC} %i %m -caption "%c"
+Icon=${APP_NAME_LC}
+Type=Application
+DocPath=${APP_NAME_LC}/${APP_NAME_LC}.html
+GenericName=A KDE Application
+Terminal=0
diff --git a/kapptemplate/kapp/app.cpp b/kapptemplate/kapp/app.cpp
new file mode 100644
index 00000000..58ed3415
--- /dev/null
+++ b/kapptemplate/kapp/app.cpp
@@ -0,0 +1,263 @@
+echo "Creating $LOCATION_ROOT/${APP_NAME_LC}/${APP_NAME_LC}.cpp...";
+cat << EOF > $LOCATION_ROOT/${APP_NAME_LC}/${APP_NAME_LC}.cpp
+/*
+ * ${APP_NAME_LC}.cpp
+ *
+ * Copyright (C) 2004 $AUTHOR <$EMAIL>
+ */
+#include "${APP_NAME_LC}.h"
+
+#include "${APP_NAME_LC}pref.h"
+
+#include <kprinter.h>
+#include <qpainter.h>
+#include <qpaintdevicemetrics.h>
+
+#include <kdeversion.h>
+#include <kglobal.h>
+#include <klocale.h>
+#include <kiconloader.h>
+#include <kmenubar.h>
+#include <kstatusbar.h>
+#include <kaccel.h>
+#include <kio/netaccess.h>
+#include <kfiledialog.h>
+#include <kconfig.h>
+#include <kurl.h>
+#include <kurldrag.h>
+#include <kurlrequesterdlg.h>
+
+#include <kedittoolbar.h>
+
+#include <kstdaccel.h>
+#include <kaction.h>
+#include <kstdaction.h>
+
+${APP_NAME}::${APP_NAME}()
+ : KMainWindow( 0, "${APP_NAME}" ),
+ m_view(new ${APP_NAME}View(this)),
+ m_printer(0)
+{
+ // accept dnd
+ setAcceptDrops(true);
+
+ // tell the KMainWindow that this is indeed the main widget
+ setCentralWidget(m_view);
+
+ // then, setup our actions
+ setupActions();
+
+ // Add typical actions and save size/toolbars/statusbar
+ setupGUI();
+
+ // allow the view to change the statusbar and caption
+ connect(m_view, SIGNAL(signalChangeStatusbar(const QString&)),
+ this, SLOT(changeStatusbar(const QString&)));
+ connect(m_view, SIGNAL(signalChangeCaption(const QString&)),
+ this, SLOT(changeCaption(const QString&)));
+
+}
+
+${APP_NAME}::~${APP_NAME}()
+{
+ delete m_printer;
+}
+
+void ${APP_NAME}::load(const KURL& url)
+{
+ QString target;
+ // the below code is what you should normally do. in this
+ // example case, we want the url to our own. you probably
+ // want to use this code instead for your app
+
+ #if 0
+ // download the contents
+ if (KIO::NetAccess::download(url, target))
+ {
+ // set our caption
+ setCaption(url.prettyURL());
+
+ // load in the file (target is always local)
+ loadFile(target);
+
+ // and remove the temp file
+ KIO::NetAccess::removeTempFile(target);
+ }
+ #endif
+
+ setCaption(url.prettyURL());
+ m_view->openURL(url);
+}
+
+void ${APP_NAME}::setupActions()
+{
+ KStdAction::openNew(this, SLOT(fileNew()), actionCollection());
+ KStdAction::open(this, SLOT(fileOpen()), actionCollection());
+ KStdAction::save(this, SLOT(fileSave()), actionCollection());
+ KStdAction::saveAs(this, SLOT(fileSaveAs()), actionCollection());
+ KStdAction::print(this, SLOT(filePrint()), actionCollection());
+ KStdAction::quit(kapp, SLOT(quit()), actionCollection());
+
+ KStdAction::preferences(this, SLOT(optionsPreferences()), actionCollection());
+
+ // this doesn't do anything useful. it's just here to illustrate
+ // how to insert a custom menu and menu item
+ KAction *custom = new KAction(i18n("Cus&tom Menuitem"), 0,
+ this, SLOT(optionsPreferences()),
+ actionCollection(), "custom_action");
+}
+
+void ${APP_NAME}::saveProperties(KConfig *config)
+{
+ // the 'config' object points to the session managed
+ // config file. anything you write here will be available
+ // later when this app is restored
+
+ if (!m_view->currentURL().isNull()) {
+#if KDE_IS_VERSION(3,1,3)
+ config->writePathEntry("lastURL", m_view->currentURL());
+#else
+ config->writeEntry("lastURL", m_view->currentURL());
+#endif
+ }
+}
+
+void ${APP_NAME}::readProperties(KConfig *config)
+{
+ // the 'config' object points to the session managed
+ // config file. this function is automatically called whenever
+ // the app is being restored. read in here whatever you wrote
+ // in 'saveProperties'
+
+ QString url = config->readPathEntry("lastURL");
+
+ if (!url.isEmpty())
+ m_view->openURL(KURL::fromPathOrURL(url));
+}
+
+void ${APP_NAME}::dragEnterEvent(QDragEnterEvent *event)
+{
+ // accept uri drops only
+ event->accept(KURLDrag::canDecode(event));
+}
+
+void ${APP_NAME}::dropEvent(QDropEvent *event)
+{
+ // this is a very simplistic implementation of a drop event. we
+ // will only accept a dropped URL. the Qt dnd code can do *much*
+ // much more, so please read the docs there
+ KURL::List urls;
+
+ // see if we can decode a URI.. if not, just ignore it
+ if (KURLDrag::decode(event, urls) && !urls.isEmpty())
+ {
+ // okay, we have a URI.. process it
+ const KURL &url = urls.first();
+
+ // load in the file
+ load(url);
+ }
+}
+
+void ${APP_NAME}::fileNew()
+{
+ // this slot is called whenever the File->New menu is selected,
+ // the New shortcut is pressed (usually CTRL+N) or the New toolbar
+ // button is clicked
+
+ // create a new window
+ (new ${APP_NAME})->show();
+}
+
+void ${APP_NAME}::fileOpen()
+{
+ // this slot is called whenever the File->Open menu is selected,
+ // the Open shortcut is pressed (usually CTRL+O) or the Open toolbar
+ // button is clicked
+ KURL url = KURLRequesterDlg::getURL(QString::null, this, i18n("Open Location") );
+ if (!url.isEmpty())
+ m_view->openURL(url);
+}
+
+void ${APP_NAME}::fileSave()
+{
+ // this slot is called whenever the File->Save menu is selected,
+ // the Save shortcut is pressed (usually CTRL+S) or the Save toolbar
+ // button is clicked
+
+ // save the current file
+}
+
+void ${APP_NAME}::fileSaveAs()
+{
+ // this slot is called whenever the File->Save As menu is selected,
+ KURL file_url = KFileDialog::getSaveURL();
+ if (!file_url.isEmpty() && file_url.isValid())
+ {
+ // save your info, here
+ }
+}
+
+void ${APP_NAME}::filePrint()
+{
+ // this slot is called whenever the File->Print menu is selected,
+ // the Print shortcut is pressed (usually CTRL+P) or the Print toolbar
+ // button is clicked
+ if (!m_printer) m_printer = new KPrinter;
+ if (m_printer->setup(this))
+ {
+ // setup the printer. with Qt, you always "print" to a
+ // QPainter.. whether the output medium is a pixmap, a screen,
+ // or paper
+ QPainter p;
+ p.begin(m_printer);
+
+ // we let our view do the actual printing
+ QPaintDeviceMetrics metrics(m_printer);
+ m_view->print(&p, metrics.height(), metrics.width());
+
+ // and send the result to the printer
+ p.end();
+ }
+}
+
+void ${APP_NAME}::optionsConfigureToolbars()
+{
+ // use the standard toolbar editor
+ saveMainWindowSettings( KGlobal::config(), autoSaveGroup() );
+ KEditToolbar dlg(actionCollection());
+ connect(&dlg, SIGNAL(newToolbarConfig()), this, SLOT(newToolbarConfig()));
+ dlg.exec();
+}
+
+void ${APP_NAME}::newToolbarConfig()
+{
+ // this slot is called when user clicks "Ok" or "Apply" in the toolbar editor.
+ // recreate our GUI, and re-apply the settings (e.g. "text under icons", etc.)
+ createGUI();
+ applyMainWindowSettings( KGlobal::config(), autoSaveGroup() );
+}
+
+void ${APP_NAME}::optionsPreferences()
+{
+ // popup some sort of preference dialog, here
+ ${APP_NAME}Preferences dlg;
+ if (dlg.exec())
+ {
+ // redo your settings
+ }
+}
+
+void ${APP_NAME}::changeStatusbar(const QString& text)
+{
+ // display the text on the statusbar
+ statusBar()->message(text);
+}
+
+void ${APP_NAME}::changeCaption(const QString& text)
+{
+ // display the text on the caption
+ setCaption(text);
+}
+
+#include "${APP_NAME_LC}.moc"
diff --git a/kapptemplate/kapp/app.h b/kapptemplate/kapp/app.h
new file mode 100644
index 00000000..7f7b0d39
--- /dev/null
+++ b/kapptemplate/kapp/app.h
@@ -0,0 +1,90 @@
+echo "Creating $LOCATION_ROOT/$APP_NAME_LC/${APP_NAME_LC}.h...";
+cat << EOF > $LOCATION_ROOT/$APP_NAME_LC/${APP_NAME_LC}.h
+#ifndef ${APP_NAME_UC}_H
+#define ${APP_NAME_UC}_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <kapplication.h>
+#include <kmainwindow.h>
+
+#include "${APP_NAME_LC}view.h"
+
+class KPrinter;
+class KURL;
+
+/**
+ * This class serves as the main window for ${APP_NAME}. It handles the
+ * menus, toolbars, and status bars.
+ *
+ * @short Main window class
+ * @author $AUTHOR <$EMAIL>
+ * @version $APP_VERSION
+ */
+class ${APP_NAME} : public KMainWindow
+{
+ Q_OBJECT
+public:
+ /**
+ * Default Constructor
+ */
+ ${APP_NAME}();
+
+ /**
+ * Default Destructor
+ */
+ virtual ~${APP_NAME}();
+
+ /**
+ * Use this method to load whatever file/URL you have
+ */
+ void load(const KURL& url);
+
+protected:
+ /**
+ * Overridden virtuals for Qt drag 'n drop (XDND)
+ */
+ virtual void dragEnterEvent(QDragEnterEvent *event);
+ virtual void dropEvent(QDropEvent *event);
+
+protected:
+ /**
+ * This function is called when it is time for the app to save its
+ * properties for session management purposes.
+ */
+ void saveProperties(KConfig *);
+
+ /**
+ * This function is called when this app is restored. The KConfig
+ * object points to the session management config file that was saved
+ * with @ref saveProperties
+ */
+ void readProperties(KConfig *);
+
+
+private slots:
+ void fileNew();
+ void fileOpen();
+ void fileSave();
+ void fileSaveAs();
+ void filePrint();
+ void optionsConfigureToolbars();
+ void optionsPreferences();
+ void newToolbarConfig();
+
+ void changeStatusbar(const QString& text);
+ void changeCaption(const QString& text);
+
+private:
+ void setupAccel();
+ void setupActions();
+
+private:
+ ${APP_NAME}View *m_view;
+
+ KPrinter *m_printer;
+};
+
+#endif // ${APP_NAME_UC}_H
diff --git a/kapptemplate/kapp/app_client.cpp b/kapptemplate/kapp/app_client.cpp
new file mode 100644
index 00000000..cd5e065d
--- /dev/null
+++ b/kapptemplate/kapp/app_client.cpp
@@ -0,0 +1,26 @@
+echo "Creating $LOCATION_ROOT/${APP_NAME_LC}/${APP_NAME_LC}_client.cpp...";
+cat << EOF > $LOCATION_ROOT/${APP_NAME_LC}/${APP_NAME_LC}_client.cpp
+#include <kapplication.h>
+#include <dcopclient.h>
+#include <qdatastream.h>
+#include <qstring.h>
+
+int main(int argc, char **argv)
+{
+ KApplication app(argc, argv, "${APP_NAME_LC}_client", false);
+
+ // get our DCOP client and attach so that we may use it
+ DCOPClient *client = app.dcopClient();
+ client->attach();
+
+ // do a 'send' for now
+ QByteArray data;
+ QDataStream ds(data, IO_WriteOnly);
+ if (argc > 1)
+ ds << QString(argv[1]);
+ else
+ ds << QString("http://www.kde.org");
+ client->send("${APP_NAME_LC}", "${APP_NAME}Iface", "openURL(QString)", data);
+
+ return app.exec();
+}
diff --git a/kapptemplate/kapp/appiface.h b/kapptemplate/kapp/appiface.h
new file mode 100644
index 00000000..2601df94
--- /dev/null
+++ b/kapptemplate/kapp/appiface.h
@@ -0,0 +1,17 @@
+echo "Creating $LOCATION_ROOT/$APP_NAME_LC/${APP_NAME_LC}iface.h...";
+cat << EOF > $LOCATION_ROOT/$APP_NAME_LC/${APP_NAME_LC}iface.h
+#ifndef ${APP_NAME_UC}IFACE_H
+#define ${APP_NAME_UC}IFACE_H
+
+#include <dcopobject.h>
+
+class ${APP_NAME}Iface : virtual public DCOPObject
+{
+ K_DCOP
+public:
+
+k_dcop:
+ virtual void openURL(QString url) = 0;
+};
+
+#endif // ${APP_NAME_UC}IFACE_H
diff --git a/kapptemplate/kapp/apppref.cpp b/kapptemplate/kapp/apppref.cpp
new file mode 100644
index 00000000..b025924a
--- /dev/null
+++ b/kapptemplate/kapp/apppref.cpp
@@ -0,0 +1,42 @@
+echo "Creating $LOCATION_ROOT/${APP_NAME_LC}/${APP_NAME_LC}pref.cpp...";
+cat << EOF > $LOCATION_ROOT/${APP_NAME_LC}/${APP_NAME_LC}pref.cpp
+#include "${APP_NAME_LC}pref.h"
+
+#include <klocale.h>
+
+#include <qlayout.h>
+#include <qlabel.h>
+
+${APP_NAME}Preferences::${APP_NAME}Preferences()
+ : KDialogBase(TreeList, "${APP_NAME} Preferences",
+ Help|Default|Ok|Apply|Cancel, Ok)
+{
+ // this is the base class for your preferences dialog. it is now
+ // a Treelist dialog.. but there are a number of other
+ // possibilities (including Tab, Swallow, and just Plain)
+ QFrame *frame;
+ frame = addPage(i18n("First Page"), i18n("Page One Options"));
+ m_pageOne = new ${APP_NAME}PrefPageOne(frame);
+
+ frame = addPage(i18n("Second Page"), i18n("Page Two Options"));
+ m_pageTwo = new ${APP_NAME}PrefPageTwo(frame);
+}
+
+${APP_NAME}PrefPageOne::${APP_NAME}PrefPageOne(QWidget *parent)
+ : QFrame(parent)
+{
+ QHBoxLayout *layout = new QHBoxLayout(this);
+ layout->setAutoAdd(true);
+
+ new QLabel("Add something here", this);
+}
+
+${APP_NAME}PrefPageTwo::${APP_NAME}PrefPageTwo(QWidget *parent)
+ : QFrame(parent)
+{
+ QHBoxLayout *layout = new QHBoxLayout(this);
+ layout->setAutoAdd(true);
+
+ new QLabel("Add something here", this);
+}
+#include "${APP_NAME_LC}pref.moc"
diff --git a/kapptemplate/kapp/apppref.h b/kapptemplate/kapp/apppref.h
new file mode 100644
index 00000000..97371936
--- /dev/null
+++ b/kapptemplate/kapp/apppref.h
@@ -0,0 +1,37 @@
+echo "Creating $LOCATION_ROOT/${APP_NAME_LC}/${APP_NAME_LC}pref.h...";
+cat << EOF > $LOCATION_ROOT/${APP_NAME_LC}/${APP_NAME_LC}pref.h
+#ifndef ${APP_NAME_UC}PREF_H
+#define ${APP_NAME_UC}PREF_H
+
+#include <kdialogbase.h>
+#include <qframe.h>
+
+class ${APP_NAME}PrefPageOne;
+class ${APP_NAME}PrefPageTwo;
+
+class ${APP_NAME}Preferences : public KDialogBase
+{
+ Q_OBJECT
+public:
+ ${APP_NAME}Preferences();
+
+private:
+ ${APP_NAME}PrefPageOne *m_pageOne;
+ ${APP_NAME}PrefPageTwo *m_pageTwo;
+};
+
+class ${APP_NAME}PrefPageOne : public QFrame
+{
+ Q_OBJECT
+public:
+ ${APP_NAME}PrefPageOne(QWidget *parent = 0);
+};
+
+class ${APP_NAME}PrefPageTwo : public QFrame
+{
+ Q_OBJECT
+public:
+ ${APP_NAME}PrefPageTwo(QWidget *parent = 0);
+};
+
+#endif // ${APP_NAME_UC}PREF_H
diff --git a/kapptemplate/kapp/appui.rc b/kapptemplate/kapp/appui.rc
new file mode 100644
index 00000000..f8914570
--- /dev/null
+++ b/kapptemplate/kapp/appui.rc
@@ -0,0 +1,10 @@
+echo "Creating $LOCATION_ROOT/${APP_NAME_LC}/${APP_NAME_LC}ui.rc...";
+cat << EOF > $LOCATION_ROOT/${APP_NAME_LC}/${APP_NAME_LC}ui.rc
+<!DOCTYPE kpartgui SYSTEM "kpartgui.dtd">
+<kpartgui name="${APP_NAME_LC}" version="1">
+<MenuBar>
+ <Menu name="custom"><text>C&amp;ustom</text>
+ <Action name="custom_action" />
+ </Menu>
+</MenuBar>
+</kpartgui>
diff --git a/kapptemplate/kapp/appview.cpp b/kapptemplate/kapp/appview.cpp
new file mode 100644
index 00000000..575e8a5d
--- /dev/null
+++ b/kapptemplate/kapp/appview.cpp
@@ -0,0 +1,106 @@
+echo "Creating $LOCATION_ROOT/${APP_NAME_LC}/${APP_NAME_LC}view.cpp...";
+cat << EOF > $LOCATION_ROOT/${APP_NAME_LC}/${APP_NAME_LC}view.cpp
+#include "${APP_NAME_LC}view.h"
+
+#include <qpainter.h>
+#include <qlayout.h>
+
+#include <kurl.h>
+
+#include <ktrader.h>
+#include <klibloader.h>
+#include <kmessagebox.h>
+#include <krun.h>
+
+${APP_NAME}View::${APP_NAME}View(QWidget *parent)
+ : QWidget(parent),
+ DCOPObject("${APP_NAME}Iface")
+{
+ // setup our layout manager to automatically add our widgets
+ QHBoxLayout *top_layout = new QHBoxLayout(this);
+ top_layout->setAutoAdd(true);
+
+ // we want to look for all components that satisfy our needs. the
+ // trader will actually search through *all* registered KDE
+ // applications and components -- not just KParts. So we have to
+ // specify two things: a service type and a constraint
+ //
+ // the service type is like a mime type. we say that we want all
+ // applications and components that can handle HTML -- 'text/html'
+ //
+ // however, by itself, this will return such things as Netscape..
+ // not what we wanted. so we constrain it by saying that the
+ // string 'KParts/ReadOnlyPart' must be found in the ServiceTypes
+ // field. with this, only components of the type we want will be
+ // returned.
+ KTrader::OfferList offers = KTrader::self()->query("text/html", "'KParts/ReadOnlyPart' in ServiceTypes");
+
+ KLibFactory *factory = 0;
+ // in theory, we only care about the first one.. but let's try all
+ // offers just in case the first can't be loaded for some reason
+ KTrader::OfferList::Iterator it(offers.begin());
+ for( ; it != offers.end(); ++it)
+ {
+ KService::Ptr ptr = (*it);
+
+ // we now know that our offer can handle HTML and is a part.
+ // since it is a part, it must also have a library... let's try to
+ // load that now
+ factory = KLibLoader::self()->factory( ptr->library() );
+ if (factory)
+ {
+ m_html = static_cast<KParts::ReadOnlyPart *>(factory->create(this, ptr->name(), "KParts::ReadOnlyPart"));
+ break;
+ }
+ }
+
+ // if our factory is invalid, then we never found our component
+ // and we might as well just exit now
+ if (!factory)
+ {
+ KMessageBox::error(this, "Could not find a suitable HTML component");
+ return;
+ }
+
+ connect(m_html, SIGNAL(setWindowCaption(const QString&)),
+ this, SLOT(slotSetTitle(const QString&)));
+ connect(m_html, SIGNAL(setStatusBarText(const QString&)),
+ this, SLOT(slotOnURL(const QString&)));
+
+}
+
+${APP_NAME}View::~${APP_NAME}View()
+{
+}
+
+void ${APP_NAME}View::print(QPainter *p, int height, int width)
+{
+ // do the actual printing, here
+ // p->drawText(etc..)
+}
+
+QString ${APP_NAME}View::currentURL()
+{
+ return m_html->url().url();
+}
+
+void ${APP_NAME}View::openURL(QString url)
+{
+ openURL(KURL(url));
+}
+
+void ${APP_NAME}View::openURL(const KURL& url)
+{
+ m_html->openURL(url);
+}
+
+void ${APP_NAME}View::slotOnURL(const QString& url)
+{
+ emit signalChangeStatusbar(url);
+}
+
+void ${APP_NAME}View::slotSetTitle(const QString& title)
+{
+ emit signalChangeCaption(title);
+}
+#include "${APP_NAME_LC}view.moc"
diff --git a/kapptemplate/kapp/appview.h b/kapptemplate/kapp/appview.h
new file mode 100644
index 00000000..881b979c
--- /dev/null
+++ b/kapptemplate/kapp/appview.h
@@ -0,0 +1,77 @@
+echo "Creating $LOCATION_ROOT/$APP_NAME_LC/${APP_NAME_LC}view.h...";
+cat << EOF > $LOCATION_ROOT/$APP_NAME_LC/${APP_NAME_LC}view.h
+#ifndef ${APP_NAME_UC}VIEW_H
+#define ${APP_NAME_UC}VIEW_H
+
+#include <qwidget.h>
+#include <kparts/part.h>
+#include <${APP_NAME_LC}iface.h>
+
+class QPainter;
+class KURL;
+
+/**
+ * This is the main view class for ${APP_NAME}. Most of the non-menu,
+ * non-toolbar, and non-statusbar (e.g., non frame) GUI code should go
+ * here.
+ *
+ * This ${APP_NAME_LC} uses an HTML component as an example.
+ *
+ * @short Main view
+ * @author $AUTHOR <$EMAIL>
+ * @version $APP_VERSION
+ */
+class ${APP_NAME}View : public QWidget, public ${APP_NAME}Iface
+{
+ Q_OBJECT
+public:
+ /**
+ * Default constructor
+ */
+ ${APP_NAME}View(QWidget *parent);
+
+ /**
+ * Destructor
+ */
+ virtual ~${APP_NAME}View();
+
+ /**
+ * Random 'get' function
+ */
+ QString currentURL();
+
+ /**
+ * Random 'set' function accessed by DCOP
+ */
+ virtual void openURL(QString url);
+
+ /**
+ * Random 'set' function
+ */
+ virtual void openURL(const KURL& url);
+
+ /**
+ * Print this view to any medium -- paper or not
+ */
+ void print(QPainter *, int height, int width);
+
+signals:
+ /**
+ * Use this signal to change the content of the statusbar
+ */
+ void signalChangeStatusbar(const QString& text);
+
+ /**
+ * Use this signal to change the content of the caption
+ */
+ void signalChangeCaption(const QString& text);
+
+private slots:
+ void slotOnURL(const QString& url);
+ void slotSetTitle(const QString& title);
+
+private:
+ KParts::ReadOnlyPart *m_html;
+};
+
+#endif // ${APP_NAME_UC}VIEW_H
diff --git a/kapptemplate/kapp/doc-Makefile.am b/kapptemplate/kapp/doc-Makefile.am
new file mode 100644
index 00000000..02611d03
--- /dev/null
+++ b/kapptemplate/kapp/doc-Makefile.am
@@ -0,0 +1,8 @@
+echo "Creating $LOCATION_ROOT/doc/Makefile.am...";
+$MKDIR $LOCATION_ROOT/doc
+cat << EOF > $LOCATION_ROOT/doc/Makefile.am
+
+SUBDIRS = \$(AUTODIRS)
+KDE_DOCS = $APP_NAME_LC
+KDE_LANG = en
+
diff --git a/kapptemplate/kapp/doc-app-Makefile.am b/kapptemplate/kapp/doc-app-Makefile.am
new file mode 100644
index 00000000..0356a93a
--- /dev/null
+++ b/kapptemplate/kapp/doc-app-Makefile.am
@@ -0,0 +1,9 @@
+echo "Creating $LOCATION_ROOT/doc/$APP_NAME_LC/Makefile.am...";
+$MKDIR $LOCATION_ROOT/doc/$APP_NAME_LC
+cat << EOF > $LOCATION_ROOT/doc/$APP_NAME_LC/Makefile.am
+
+# the SUBDIRS is filled automatically by am_edit. If files are
+# in this directory they are installed into the english dir
+KDE_LANG = en
+KDE_DOCS = $APP_NAME_LC
+SUBDIRS = \$(AUTODIRS)
diff --git a/kapptemplate/kapp/hi16-app-app.png b/kapptemplate/kapp/hi16-app-app.png
new file mode 100644
index 00000000..2f82a953
--- /dev/null
+++ b/kapptemplate/kapp/hi16-app-app.png
@@ -0,0 +1,2 @@
+echo "Creating $LOCATION_ROOT/$APP_NAME_LC/hi16-app-$APP_NAME_LC.png...";
+cp $SHARE_DIR/kapp/no-exe/hi16-app-app.png $LOCATION_ROOT/$APP_NAME_LC/hi16-app-$APP_NAME_LC.png
diff --git a/kapptemplate/kapp/hi32-app-app.png b/kapptemplate/kapp/hi32-app-app.png
new file mode 100644
index 00000000..767c9448
--- /dev/null
+++ b/kapptemplate/kapp/hi32-app-app.png
@@ -0,0 +1,2 @@
+echo "Creating $LOCATION_ROOT/$APP_NAME_LC/hi32-app-$APP_NAME_LC.png...";
+cp $SHARE_DIR/kapp/no-exe/hi32-app-app.png $LOCATION_ROOT/$APP_NAME_LC/hi32-app-$APP_NAME_LC.png
diff --git a/kapptemplate/kapp/hi48-app-app.png b/kapptemplate/kapp/hi48-app-app.png
new file mode 100644
index 00000000..08970c62
--- /dev/null
+++ b/kapptemplate/kapp/hi48-app-app.png
@@ -0,0 +1,2 @@
+echo "Creating $LOCATION_ROOT/$APP_NAME_LC/hi48-app-$APP_NAME_LC.png...";
+cp $SHARE_DIR/kapp/no-exe/hi48-app-app.png $LOCATION_ROOT/$APP_NAME_LC/hi48-app-$APP_NAME_LC.png
diff --git a/kapptemplate/kapp/index.docbook b/kapptemplate/kapp/index.docbook
new file mode 100644
index 00000000..5f8071ff
--- /dev/null
+++ b/kapptemplate/kapp/index.docbook
@@ -0,0 +1,106 @@
+echo "Creating $LOCATION_ROOT/doc/$APP_NAME_LC/index.docbook...";
+$MKDIR $LOCATION_ROOT/doc/$APP_NAME_LC
+echo "It is better to use template.docbook instead of this - please replace it"
+cat << EOF > $LOCATION_ROOT/doc/$APP_NAME_LC/index.docbook
+<?xml version="1.0" ?>
+<!DOCTYPE book PUBLIC "-//KDE//DTD DocBook XML V4.1.2-Based Variant V1.1//EN" "dtd/kdex.dtd" [
+ <!ENTITY $APP_NAME_LC "$APP_NAME">
+ <!ENTITY % addindex "IGNORE">
+ <!ENTITY % English "INCLUDE" > <!-- change language only here -->
+]>
+<!-- Important note: please use template.docbook instead of this file.
+ This is only the conversion of app.sgml into DocBook SGML.
+ template.docbook gives you more information on what you can and
+ should do. Thanks. -->
+<book lang="&language;">
+
+<bookinfo>
+<title>The &$APP_NAME_LC; Handbook</title>
+<authorgroup>
+<author>
+<firstname></firstname>
+<surname>$AUTHOR</surname>
+<affiliation><address><email>$EMAIL</email></address></affiliation>
+</author>
+</authorgroup>
+<date>`date "+%Y-%m-%d"`</date>
+<releaseinfo>$APP_VERSION</releaseinfo>
+<abstract>
+<para>SHORT DESCRIPTION GOES HERE</para>
+</abstract>
+<keywordset>
+<keyword>KDE</keyword>
+<keyword>$APP_NAME_LC</keyword>
+</keywordset>
+</bookinfo>
+
+ <chapter id="introduction">
+ <title>Introduction</title>
+
+ <sect1 id="features">
+ <title>Features</title>
+ <para></para>
+ </sect1>
+ </chapter>
+
+ <chapter id="installation">
+ <title>Installation</title>
+
+ <sect1 id="how-to-obtain-$APP_NAME_LC">
+ <title>How to obtain &$APP_NAME_LC;</title>
+ <para></para>
+ </sect1>
+
+ <sect1 id="requirements">
+ <title>Requirements</title>
+ <para></para>
+ </sect1>
+
+ <sect1 id="compilation-and-installation">
+ <title>Compilation and Installation</title>
+
+ <para>Compiling &$APP_NAME_LC; is very easy. The following should do
+ it: <screen>
+<prompt>%</prompt> <userinput><command>./configure</command></userinput>
+<prompt>%</prompt> <userinput><command>make</command></userinput>
+<prompt>%</prompt> <userinput><command>make</command> install</userinput></screen>
+ </para>
+
+ <para>That should do it! Should you run into any problems,
+ please report them to the <ulink
+ url="mailto:$EMAIL">author</ulink></para>
+ </sect1>
+ </chapter>
+
+ <chapter id="using-$APP_NAME_LC">
+ <title>Using &$APP_NAME_LC;</title>
+ <para></para>
+ </chapter>
+
+ <chapter id="questionsanswersandtips">
+ <title>Questions, Answers, and Tips</title>
+
+ <qandaset id="faq">
+ <title>Frequently asked questions</title>
+ <qandaentry>
+ <question>
+ <para>Question 1</para>
+ </question>
+ <answer>
+ <para>The answer</para>
+ </answer>
+ </qandaentry>
+ </qandaset>
+
+ </chapter>
+ &documentation.index;
+</book>
+<!--
+Local Variables:
+mode: sgml
+sgml-omittag: nil
+sgml-shorttag: t
+sgml-general-insert-case: lower
+End:
+-->
+
diff --git a/kapptemplate/kapp/lo16-app-app.png b/kapptemplate/kapp/lo16-app-app.png
new file mode 100644
index 00000000..c495e509
--- /dev/null
+++ b/kapptemplate/kapp/lo16-app-app.png
@@ -0,0 +1,2 @@
+echo "Creating $LOCATION_ROOT/$APP_NAME_LC/lo16-app-$APP_NAME_LC.png...";
+cp $SHARE_DIR/kapp/no-exe/lo16-app-app.png $LOCATION_ROOT/$APP_NAME_LC/lo16-app-$APP_NAME_LC.png
diff --git a/kapptemplate/kapp/lo32-app-app.png b/kapptemplate/kapp/lo32-app-app.png
new file mode 100644
index 00000000..6faac157
--- /dev/null
+++ b/kapptemplate/kapp/lo32-app-app.png
@@ -0,0 +1,2 @@
+echo "Creating $LOCATION_ROOT/$APP_NAME_LC/lo32-app-$APP_NAME_LC.png...";
+cp $SHARE_DIR/kapp/no-exe/lo32-app-app.png $LOCATION_ROOT/$APP_NAME_LC/lo32-app-$APP_NAME_LC.png
diff --git a/kapptemplate/kapp/main.cpp b/kapptemplate/kapp/main.cpp
new file mode 100644
index 00000000..40118215
--- /dev/null
+++ b/kapptemplate/kapp/main.cpp
@@ -0,0 +1,58 @@
+echo "Creating $LOCATION_ROOT/${APP_NAME_LC}/main.cpp...";
+cat << EOF > $LOCATION_ROOT/${APP_NAME_LC}/main.cpp
+#include "${APP_NAME_LC}.h"
+#include <kapplication.h>
+#include <dcopclient.h>
+#include <kaboutdata.h>
+#include <kcmdlineargs.h>
+#include <klocale.h>
+
+static const char description[] =
+ I18N_NOOP("A KDE Application");
+
+static const char version[] = "v${APP_VERSION}";
+
+static KCmdLineOptions options[] =
+{
+ { "+[URL]", I18N_NOOP( "Document to open" ), 0 },
+ KCmdLineLastOption
+};
+
+int main(int argc, char **argv)
+{
+ KAboutData about("${APP_NAME_LC}", I18N_NOOP("${APP_NAME}"), version, description, KAboutData::License_GPL, "(C) 2004 ${AUTHOR}", 0, 0, "${EMAIL}");
+ about.addAuthor( "${AUTHOR}", 0, "${EMAIL}" );
+ KCmdLineArgs::init(argc, argv, &about);
+ KCmdLineArgs::addCmdLineOptions(options);
+ KApplication app;
+
+ // register ourselves as a dcop client
+ app.dcopClient()->registerAs(app.name(), false);
+
+ // see if we are starting with session management
+ if (app.isRestored())
+ RESTORE(${APP_NAME})
+ else
+ {
+ // no session.. just start up normally
+ KCmdLineArgs *args = KCmdLineArgs::parsedArgs();
+ if (args->count() == 0)
+ {
+ ${APP_NAME} *widget = new ${APP_NAME};
+ widget->show();
+ }
+ else
+ {
+ int i = 0;
+ for (; i < args->count(); i++)
+ {
+ ${APP_NAME} *widget = new ${APP_NAME};
+ widget->show();
+ widget->load(args->url(i));
+ }
+ }
+ args->clear();
+ }
+
+ return app.exec();
+}
diff --git a/kapptemplate/kapp/no-exe/Makefile.am b/kapptemplate/kapp/no-exe/Makefile.am
new file mode 100644
index 00000000..a377e92a
--- /dev/null
+++ b/kapptemplate/kapp/no-exe/Makefile.am
@@ -0,0 +1,3 @@
+kappdir = $(kde_datadir)/kapptemplate/kapp/no-exe
+kapp_DATA = hi32-app-app.png lo16-app-app.png hi16-app-app.png \
+ hi48-app-app.png lo32-app-app.png
diff --git a/kapptemplate/kapp/no-exe/hi16-app-app.png b/kapptemplate/kapp/no-exe/hi16-app-app.png
new file mode 100644
index 00000000..43eab761
--- /dev/null
+++ b/kapptemplate/kapp/no-exe/hi16-app-app.png
Binary files differ
diff --git a/kapptemplate/kapp/no-exe/hi32-app-app.png b/kapptemplate/kapp/no-exe/hi32-app-app.png
new file mode 100644
index 00000000..ce9df987
--- /dev/null
+++ b/kapptemplate/kapp/no-exe/hi32-app-app.png
Binary files differ
diff --git a/kapptemplate/kapp/no-exe/hi48-app-app.png b/kapptemplate/kapp/no-exe/hi48-app-app.png
new file mode 100644
index 00000000..6464fb39
--- /dev/null
+++ b/kapptemplate/kapp/no-exe/hi48-app-app.png
Binary files differ
diff --git a/kapptemplate/kapp/no-exe/lo16-app-app.png b/kapptemplate/kapp/no-exe/lo16-app-app.png
new file mode 100644
index 00000000..e21db293
--- /dev/null
+++ b/kapptemplate/kapp/no-exe/lo16-app-app.png
Binary files differ
diff --git a/kapptemplate/kapp/no-exe/lo32-app-app.png b/kapptemplate/kapp/no-exe/lo32-app-app.png
new file mode 100644
index 00000000..4ecd9ce3
--- /dev/null
+++ b/kapptemplate/kapp/no-exe/lo32-app-app.png
Binary files differ
diff --git a/kapptemplate/kapp/pics-Makefile.am b/kapptemplate/kapp/pics-Makefile.am
new file mode 100644
index 00000000..93c2257e
--- /dev/null
+++ b/kapptemplate/kapp/pics-Makefile.am
@@ -0,0 +1,8 @@
+echo "Creating $LOCATION_ROOT/$APP_NAME_LC/pics/Makefile.am...";
+$MKDIR $LOCATION_ROOT/$APP_NAME_LC/pics
+cat << EOF > $LOCATION_ROOT/$APP_NAME_LC/pics/Makefile.am
+# Add all of your pixmaps here
+#picsdata_DATA =
+
+# This is where it will all be installed
+#picsdatadir = \$(kde_datadir)/$APP_NAME_LC/pics
diff --git a/kapptemplate/kapptemplate.common b/kapptemplate/kapptemplate.common
new file mode 100644
index 00000000..8cff2d60
--- /dev/null
+++ b/kapptemplate/kapptemplate.common
@@ -0,0 +1,496 @@
+#!/usr/bin/env bash
+###########################################################################
+#
+# kapptemplate.common
+#
+# This file contains a bunch of common function that may be used by
+# the various kapptemplate modules. Each function lists which
+# environment variables need to be set before the function is called
+# and which variables will be set after it's done. This file is
+# intended to be included or sourced by any module that uses its
+# functions.
+#
+###########################################################################
+
+###########################################################################
+#
+# Function: Usage
+#
+# Display the help output (--help)
+#
+###########################################################################
+function Usage
+{
+ $ECHO "Usage: kapptemplate [options]";
+ $ECHO "Options:";
+ $ECHO " --help Display this information";
+ $ECHO " --noinit Don't run '$MAKE -f Makefile.cvs'";
+ $ECHO " --default Use default values instead of prompting";
+ $ECHO;
+ $ECHO "Framework Types:";
+ $ECHO " --full-app Create full featured KDE application";
+ $ECHO " --kpart-app Create full KPart application";
+ $ECHO " --kpart-plugin Create KPart plugin framework";
+ $ECHO " --existing Convert existing source to KDE framework";
+}
+
+###########################################################################
+#
+# Function: ParseCommandLine
+#
+# Parse the commandline args (--help, --noinit, etc)
+#
+# OUTPUT: $NOINIT, $ALL_DEFAULTS, $WHICH_ONE
+#
+###########################################################################
+function ParseCommandLine
+{
+ unset NOINIT;
+ unset ALL_DEFAULTS;
+ unset WHICH_ONE;
+ if [ ! "$CMDLINE" ];
+ then
+ return;
+ fi
+
+ for CMD in $CMDLINE;
+ do
+ case $CMD in
+ --help)
+ Usage;
+ exit 0;;
+
+ --noinit)
+ NOINIT=1;;
+ --default)
+ ALL_DEFAULTS=1;;
+ --full-app)
+ WHICH_ONE=1;;
+ --kpart-app)
+ WHICH_ONE=2;;
+ --kpart-plugin)
+ WHICH_ONE=3;;
+ --existing)
+ WHICH_ONE=4;;
+ *)
+ $ECHO "Unknown option $1";
+ Usage;
+ exit 1;;
+ esac
+ done
+}
+
+###########################################################################
+#
+# Function: GetProperName
+#
+# Get the application or class or plugin or whatever's proper name
+#
+# INPUT : $APPTYPE, $APPDEFAULT
+# OUTPUT: $APP_NAME, $APP_NAME_UC, $APP_NAME_LC
+#
+###########################################################################
+function GetProperName
+{
+ # Make sure we have reasonable defaults
+ if [ ! "$APPTYPE" ];
+ then
+ APPTYPE="application";
+ fi
+ if [ ! "$APPDEFAULT" ];
+ then
+ APPDEFAULT="KMyApp";
+ fi
+
+ # See what we are getting
+ if [ ! "$ALL_DEFAULTS" ];
+ then
+ unset APP_NAME;
+ while [ ! $APP_NAME ];
+ do
+ $ECHO "What is the ${APPTYPE}'s proper name [default: ${APPDEFAULT}]";
+ $ECHO ": \c";
+ read APP_NAME;
+
+ if [ ! $APP_NAME ];
+ then
+ APP_NAME=${APPDEFAULT};
+ $ECHO "Going with default name '${APPDEFAULT}'";
+ fi
+ done
+ $ECHO;
+ else
+ APP_NAME=${APPDEFAULT};
+ fi
+
+ # Create some variations
+ APP_NAME_UC=`$ECHO $APP_NAME | tr a-z A-Z`;
+ APP_NAME_LC=`$ECHO $APP_NAME | tr A-Z a-z`;
+}
+
+###########################################################################
+#
+# Function: GetVersion
+#
+# Get the application or class or plugin or whatever's version
+#
+# INPUT : $APPTYPE
+# OUTPUT: $APP_VERSION
+#
+###########################################################################
+function GetVersion
+{
+ # Make sure we have reasonable defaults
+ if [ ! "$APPTYPE" ];
+ then
+ APPTYPE="application";
+ fi
+
+ # Get the application version
+ if [ ! "$ALL_DEFAULTS" ];
+ then
+ unset APP_VERSION;
+ while [ ! $APP_VERSION ];
+ do
+ $ECHO "What is the ${APPTYPE}'s version [default: 0.1]";
+ $ECHO ": \c";
+ read APP_VERSION;
+
+ if [ ! $APP_VERSION ];
+ then
+ APP_VERSION="0.1";
+ $ECHO "Going with default version '$APP_VERSION'";
+ fi
+ done
+ $ECHO;
+ else
+ APP_VERSION="0.1";
+ fi
+}
+
+###########################################################################
+#
+# Function: GetLocationRoot
+#
+# Get the directory where this all should be installed
+#
+# INPUT : $DEFAULT_ROOT, $APP_NAME_LC, $APP_VERSION
+# OUTPUT: $LOCATION_ROOT
+#
+###########################################################################
+function GetLocationRoot
+{
+ if [ ! "$ALL_DEFAULTS" ];
+ then
+ unset LOCATION_ROOT;
+ while [ ! $LOCATION_ROOT ];
+ do
+ $ECHO "Where should I create this [default: $DEFAULT_ROOT/$APP_NAME_LC-$APP_VERSION]";
+ $ECHO ": \c";
+ read LOCATION_ROOT;
+
+ if [ ! $LOCATION_ROOT ];
+ then
+ LOCATION_ROOT="$DEFAULT_ROOT/$APP_NAME_LC-$APP_VERSION";
+ $ECHO "Going with default root '$LOCATION_ROOT'";
+ fi
+
+ # We overwrite anything if the directory already exists
+ if [ -d $LOCATION_ROOT ];
+ then
+ $ECHO "This directory already exists. Will overwrite.";
+ $ECHO;
+ fi
+ done
+ $ECHO;
+ else
+ LOCATION_ROOT="$DEFAULT_ROOT/$APP_NAME_LC-$APP_VERSION";
+ fi
+
+}
+
+###########################################################################
+#
+# Function: GetAuthorName
+#
+# Get the name of the author
+#
+# INPUT: $DEFAULT_AUTHOR
+#
+###########################################################################
+function GetAuthorName
+{
+ unset AUTHOR;
+ while [ ! "$AUTHOR" ];
+ do
+ if [ "$ALL_DEFAULTS" -a "$DEFAULT_AUTHOR" ];
+ then
+ AUTHOR="$DEFAULT_AUTHOR";
+ else
+ if [ "$DEFAULT_AUTHOR" ];
+ then
+ $ECHO "What is your name [default: $DEFAULT_AUTHOR]";
+ else
+ $ECHO "What is your name [no default]";
+ fi
+ $ECHO ": \c";
+ read AUTHOR;
+
+ if [ "$DEFAULT_AUTHOR" -a ! "$AUTHOR" ];
+ then
+ AUTHOR="$DEFAULT_AUTHOR";
+ $ECHO "Going with default author '$AUTHOR'";
+ fi
+ fi
+ done
+ $ECHO;
+}
+
+###########################################################################
+#
+# Function: GetAuthorEmail
+#
+# Get the email of the author
+#
+# INPUT: $DEFAULT_EMAIL
+#
+###########################################################################
+function GetAuthorEmail
+{
+ unset EMAIL;
+ while [ ! "$EMAIL" ];
+ do
+ if [ "$ALL_DEFAULTS" -a "$DEFAULT_EMAIL" ];
+ then
+ EMAIL="$DEFAULT_EMAIL";
+ else
+ if [ "$DEFAULT_EMAIL" ];
+ then
+ $ECHO "What is your email address [default: $DEFAULT_EMAIL]";
+ else
+ $ECHO "What is your email address [no default]";
+ fi
+ $ECHO ": \c";
+ read EMAIL;
+
+ if [ "$DEFAULT_EMAIL" -a ! "$EMAIL" ];
+ then
+ EMAIL="$DEFAULT_EMAIL";
+ $ECHO "Going with default email address '$EMAIL'";
+ fi
+ fi
+ done
+ $ECHO;
+}
+
+###########################################################################
+#
+# Function: GetFileList
+#
+# Generic utility function to get a list of files in a directory
+#
+# INPUT : $DIRECTORY
+# OUTPUT: $FILES
+#
+###########################################################################
+function GetFileList
+{
+ unset FILES;
+ if [ -d "$DIRECTORY" ];
+ then
+# FILES=`/bin/ls -1 -I "no-exe" -I*~ $DIRECTORY`;
+ FILES=`cd $DIRECTORY; find . ! -name "*~" -maxdepth 1 -type f -print | sed 's,^\./,,' | sort`;
+
+ if [ ! "$FILES" ];
+ then
+ $ECHO "Cannot find files in $DIRECTORY!";
+ exit 1;
+ fi
+ else
+ $ECHO "$DIRECTORY directory does not exist!";
+ exit 1;
+ fi
+}
+
+###########################################################################
+#
+# Function: BuildModuleLists
+#
+# Build a list of files that correspond with each module
+#
+# INPUT : $SHARE_DIR
+#
+###########################################################################
+function BuildModuleLists
+{
+ # Make sure all the modules exist first
+ if [ ! -f "$INCLUDE_DIR/kapptemplate.module" ];
+ then
+ $ECHO "The 'kapptemplate.module' file can't be found.";
+ $ECHO;
+ exit 1;
+ fi
+
+ if [ ! -f "$INCLUDE_DIR/kpartplugin.module" ];
+ then
+ $ECHO "The 'kpartplugin.module' file can't be found.";
+ $ECHO;
+ exit 1;
+ fi
+
+ if [ ! -f "$INCLUDE_DIR/existing.module" ];
+ then
+ $ECHO "The 'existing.module' file can't be found.";
+ $ECHO;
+ exit 1;
+ fi
+
+ # Find the 'admin' files
+ DIRECTORY=$SHARE_DIR/admin;
+ GetFileList
+ ADMIN_FILES=$FILES;
+
+ # Find the 'appframework' files
+ DIRECTORY=$SHARE_DIR/appframework;
+ GetFileList
+ APPFRAMEWORK_FILES=$FILES;
+
+ # Find the 'kapp' files
+ DIRECTORY=$SHARE_DIR/kapp;
+ GetFileList
+ KAPP_FILES=$FILES;
+
+ # Find the 'kpartplugin' files
+ DIRECTORY=$SHARE_DIR/kpartplugin;
+ GetFileList
+ KPARTPLUGIN_FILES=$FILES;
+
+ # Find the 'existing' files
+ DIRECTORY=$SHARE_DIR/existing;
+ GetFileList
+ EXISTING_FILES=$FILES;
+
+ # Find the 'kpartapp' files
+ DIRECTORY=$SHARE_DIR/kpartapp;
+ GetFileList
+ KPARTAPP_FILES=$FILES;
+}
+
+###########################################################################
+#
+# Function: CreateAppFramework
+#
+# Create the initial directory structure of the application or plugin
+# and put in the common admin and configure files
+#
+# INPUT : $LOCATION_ROOT, $APP_NAME_LC, $SHARE_DIR
+#
+###########################################################################
+function CreateAppFramework
+{
+ # Create the directory tree
+ $ECHO;
+ $ECHO "Creating directory $LOCATION_ROOT...";
+ $MKDIR $LOCATION_ROOT || exit 1;
+
+ $ECHO "Creating directory $LOCATION_ROOT/admin...";
+ $MKDIR $LOCATION_ROOT/admin || exit 1;
+
+ $ECHO "Creating directory $LOCATION_ROOT/$APP_NAME_LC...";
+ $MKDIR $LOCATION_ROOT/$APP_NAME_LC || exit 1;
+
+ $ECHO "Creating directory $LOCATION_ROOT/po...";
+ $MKDIR $LOCATION_ROOT/po || exit 1;
+
+ for FILE in $ADMIN_FILES;
+ do
+ $ECHO "Copying $LOCATION_ROOT/$FILE...";
+ cp -p $SHARE_DIR/admin/$FILE $LOCATION_ROOT/admin/$FILE || exit 1;
+ done
+
+ for FILE in $APPFRAMEWORK_FILES;
+ do
+ . $SHARE_DIR/appframework/$FILE || exit 1;
+ done
+}
+
+###########################################################################
+#
+# Function: GetInitialDefaults
+#
+# This is run the first time a user uses kapptemplate. It gets a few
+# default values and installs them into $HOME/.kapptemplate
+#
+# INPUT: $KAPPTEMPLATEVERSION
+#
+###########################################################################
+function GetInitialDefaults
+{
+ $ECHO "I see that this is your first time using KAppTemplate. Excellent!";
+ $ECHO "To get started, I need you to answer the following questions. Your";
+ $ECHO "answers will be used as the default values every time you use this";
+ $ECHO "program in the future.";
+ unset THE_AUTHOR;
+ while [ ! "$THE_AUTHOR" ];
+ do
+ $ECHO "What is your full name? \c";
+ if [ "$DEFAULT_AUTHOR" ];
+ then
+ $ECHO "[default: $DEFAULT_AUTHOR]";
+ else
+ $ECHO "[no default]";
+ fi
+ $ECHO ": \c";
+ read THE_AUTHOR;
+
+ if [ "$DEFAULT_AUTHOR" -a ! "$THE_AUTHOR" ];
+ then
+ THE_AUTHOR="$DEFAULT_AUTHOR";
+ fi
+ done
+ $ECHO;
+
+ unset THE_EMAIL;
+ while [ ! "$THE_EMAIL" ];
+ do
+ $ECHO "What is your email address? \c";
+ if [ "$DEFAULT_EMAIL" ];
+ then
+ $ECHO "[default: $DEFAULT_EMAIL]";
+ else
+ $ECHO "[no default]";
+ fi
+ $ECHO ": \c";
+ read THE_EMAIL;
+
+ if [ "$DEFAULT_EMAIL" -a ! "$THE_EMAIL" ];
+ then
+ THE_EMAIL="$DEFAULT_EMAIL";
+ fi
+ done
+ $ECHO;
+
+ unset THE_ROOT;
+ $ECHO "Where should I construct apps? \c";
+ if [ ! "$DEFAULT_ROOT" ];
+ then
+ DEFAULT_ROOT="$HOME/src";
+ fi
+ $ECHO "[default: $DEFAULT_ROOT]";
+ $ECHO ": \c";
+ read THE_ROOT;
+
+ if [ ! "$THE_ROOT" ];
+ then
+ THE_ROOT="$DEFAULT_ROOT";
+ fi
+ $ECHO;
+
+ $ECHO "Constructing .kapptemplaterc...";
+ cat << ENDORC > $HOME/.kapptemplaterc
+DEFAULT_AUTHOR="$THE_AUTHOR";
+DEFAULT_EMAIL="$THE_EMAIL";
+DEFAULT_ROOT="$THE_ROOT";
+VERSION="$KAPPTEMPLATEVERSION";
+ENDORC
+}
diff --git a/kapptemplate/kapptemplate.in b/kapptemplate/kapptemplate.in
new file mode 100644
index 00000000..dde86d04
--- /dev/null
+++ b/kapptemplate/kapptemplate.in
@@ -0,0 +1,131 @@
+###########################################################################
+#
+# Function: LoadDefaults
+#
+# This will load in all the default values stored in the user's
+# .kapptemplaterc file
+#
+# INPUT : $KAPPTEMPLATEVERSION, $INSTALLED_SHARE_DIR
+# OUTPUT: $ECHO, $KAPPTEMPLATERC, $DEFAULT_AUTHOR, $DEFAULT_EMAIL,
+# $DEFAULT_ROOT, $SHARE_DIR, $BIN_DIR, $MKDIR, $BASENAME
+#
+###########################################################################
+function LoadDefaults
+{
+ # horrid hack to try and figure out what shell we are using
+ # basically, if we can find /usr/ucb/echo, then we are almost for sure
+ # NOT on a Linux system and probably 'echo "\c" works. if we don't
+ # find it, we'll assume that the shell is really bash.
+ if [ -f "/usr/ucb/echo" ];
+ then
+ ECHO="echo";
+ else
+ ECHO="echo -e";
+ fi
+
+ # If $MAKE hasn't been set yet, try to figure out how we reach GNU make
+ # ourselves.
+ if [ ! "$MAKE" ];
+ then
+ if [ -f "/usr/bin/gmake" ] || [ -f "/usr/local/bin/gmake" ];
+ then
+ MAKE="gmake";
+ else
+ MAKE="make";
+ fi
+ fi
+
+ $ECHO "KAppTemplate v${KAPPTEMPLATEVERSION} (C) 2003 Kurt Granroth <granroth@kde.org>";
+ $ECHO;
+
+ if [ ! "$KAPPTEMPLATERC" ];
+ then
+ KAPPTEMPLATERC=$HOME/.kapptemplaterc
+ fi
+
+ if [ -f $KAPPTEMPLATERC ];
+ then
+ . $KAPPTEMPLATERC
+ else
+ GetInitialDefaults
+ fi
+
+ if [ ! "$DEFAULT_AUTHOR" ];
+ then
+ DEFAULT_AUTHOR="Your Name";
+ fi
+
+ if [ ! "$DEFAULT_EMAIL" ];
+ then
+ DEFAULT_EMAIL="`whoami`@$HOST";
+ fi
+
+ if [ ! "$DEFAULT_ROOT" ];
+ then
+ DEFAULT_ROOT="$HOME/src";
+ fi
+
+ SHARE_DIR=$INSTALLED_SHARE_DIR;
+ INCLUDE_DIR="$SHARE_DIR/include";
+
+ if [ -f "$SHARE_DIR/bin/mkinstalldirs" ];
+ then
+ MKDIR=$SHARE_DIR/bin/mkinstalldirs
+ else
+ MKDIR=mkdir
+ fi
+
+ # Finally, get the name of the running program
+ BASENAME=`echo $0 | sed 's@^.*/@@g'`;
+}
+
+# We start by loading the 'common' file containing all useful
+# functions
+if [ -f $INSTALLED_SHARE_DIR/include/kapptemplate.common ];
+then
+ . $INSTALLED_SHARE_DIR/include/kapptemplate.common
+else
+ $ECHO "Could not find common file 'kapptemplate.common'";
+ $ECHO;
+ exit 1;
+fi
+
+# Then, we load all the default environment variables and perform
+# any necessary initialization
+LoadDefaults
+
+# Parse the command line
+CMDLINE=$@;
+ParseCommandLine
+
+# Do a sanity check and build the various module lists
+BuildModuleLists
+
+if [ ! "$WHICH_ONE" ] && [ "$ALL_DEFAULTS" ];
+then
+ WHICH_ONE=1;
+fi
+if [ ! "$WHICH_ONE" ];
+then
+ # Find out how to use kapptemplate this time
+ $ECHO "Please select the type of framework you wish to generate";
+ $ECHO "1. Full featured KDE application [default]";
+ $ECHO "2. Full featured KPart application";
+ $ECHO "3. KPart plugin";
+ $ECHO "4. Convert existing source to automake/autoconf framework";
+ $ECHO "Choose [1-4]: \c";
+ read WHICH_ONE;
+ $ECHO;
+fi;
+
+# Start the proper module
+case $WHICH_ONE in
+ 2)
+ . $INCLUDE_DIR/kpartapp.module;;
+ 3)
+ . $INCLUDE_DIR/kpartplugin.module;;
+ 4)
+ . $INCLUDE_DIR/existing.module;;
+ *)
+ . $INCLUDE_DIR/kapptemplate.module;;
+esac
diff --git a/kapptemplate/kapptemplate.lsm b/kapptemplate/kapptemplate.lsm
new file mode 100644
index 00000000..d557a8f7
--- /dev/null
+++ b/kapptemplate/kapptemplate.lsm
@@ -0,0 +1,18 @@
+Begin3
+Title: KAppTemplate
+Version: 1.0.6
+Entered-date: 05Jul01
+Description: Modular shell script that will automatically create a
+ framework for either a normal KDE 2.x application, a
+ KPart application, a KPart plugin, or convert an
+ existing application.
+Keywords: KDE application generator DCOP KParts Plugins XML-GUI
+Author: Kurt Granroth <granroth@kde.org>
+Maintained-by: Kurt Granroth <granroth@kde.org>
+Home-page: http://www.granroth.org/kapptemplate
+Primary-site: cvs.kde.org:/home/kde/kdesdk/kapptemplate
+ xxxxxx kapptemplate-1.0.6.tar.bz2
+ xxx kapptemplate-1.0.6.lsm
+Platform: Unix
+Copying-policy: GPL
+End
diff --git a/kapptemplate/kapptemplate.module b/kapptemplate/kapptemplate.module
new file mode 100644
index 00000000..90e78649
--- /dev/null
+++ b/kapptemplate/kapptemplate.module
@@ -0,0 +1,68 @@
+###########################################################################
+#
+# STEP 1: GET USER INFORMATION
+#
+###########################################################################
+# Get the application name
+GetProperName
+
+# Get the application version
+GetVersion
+
+# Get the root where this framework will be installed
+GetLocationRoot
+
+# Get the author's name
+GetAuthorName
+
+# Get the author's email
+GetAuthorEmail
+
+# Verify that everything is grand
+$ECHO;
+$ECHO "Here is what I have:";
+$ECHO "The app: $APP_NAME v$APP_VERSION";
+$ECHO "Installed in: $LOCATION_ROOT";
+$ECHO "Author: $AUTHOR <$EMAIL>";
+$ECHO;
+$ECHO "Is this correct (Y/n)? ";
+$ECHO ": \c";
+read Y_N;
+if [ $Y_N -a $Y_N = 'n' ];
+then
+ $ECHO "AUGH! Well, try again.";
+ exit 0;
+fi
+$ECHO;
+
+$ECHO "OK, Here we go!!";
+
+###########################################################################
+#
+# STEP 2: CREATE APPLICATION FRAMEWORK
+#
+###########################################################################
+CreateAppFramework
+
+###########################################################################
+#
+# STEP 3: GENERATE APP-SPECIFIC FILES
+#
+###########################################################################
+
+for EXE_FILE in $KAPP_FILES;
+do
+ . $SHARE_DIR/kapp/$EXE_FILE || exit 1;
+done
+
+###########################################################################
+#
+# STEP 4: FINAL STEPS
+#
+###########################################################################
+
+if [ ! $NOINIT ]; then
+ cd $LOCATION_ROOT && $MAKE -f Makefile.cvs
+fi
+
+$ECHO "DONE!";
diff --git a/kapptemplate/kpartapp.module b/kapptemplate/kpartapp.module
new file mode 100644
index 00000000..16c0e630
--- /dev/null
+++ b/kapptemplate/kpartapp.module
@@ -0,0 +1,70 @@
+###########################################################################
+#
+# STEP 1: GET USER INFORMATION
+#
+###########################################################################
+# Get the application name
+APPTYPE="KPart application";
+APPDEFAULT="KPartApp";
+GetProperName
+
+# Get the application version
+GetVersion
+
+# Get the root where this framework will be installed
+GetLocationRoot
+
+# Get the author's name
+GetAuthorName
+
+# Get the author's email
+GetAuthorEmail
+
+# Verify that everything is grand
+$ECHO;
+$ECHO "Here is what I have:";
+$ECHO "The app: $APP_NAME v$APP_VERSION";
+$ECHO "Installed in: $LOCATION_ROOT";
+$ECHO "Author: $AUTHOR <$EMAIL>";
+$ECHO;
+$ECHO "Is this correct (Y/n)? ";
+$ECHO ": \c";
+read Y_N;
+if [ $Y_N -a $Y_N = 'n' ];
+then
+ $ECHO "AUGH! Well, try again.";
+ exit 0;
+fi
+$ECHO;
+
+$ECHO "OK, Here we go!!";
+
+###########################################################################
+#
+# STEP 2: CREATE APPLICATION FRAMEWORK
+#
+###########################################################################
+CreateAppFramework
+
+###########################################################################
+#
+# STEP 3: GENERATE APP-SPECIFIC FILES
+#
+###########################################################################
+
+for EXE_FILE in $KPARTAPP_FILES;
+do
+ . $SHARE_DIR/kpartapp/$EXE_FILE || exit 1;
+done
+
+###########################################################################
+#
+# STEP 4: FINAL STEPS
+#
+###########################################################################
+
+if [ ! $NOINIT ]; then
+ cd $LOCATION_ROOT && $MAKE -f Makefile.cvs
+fi
+
+$ECHO "DONE!";
diff --git a/kapptemplate/kpartapp/Makefile.am b/kapptemplate/kpartapp/Makefile.am
new file mode 100644
index 00000000..26e92118
--- /dev/null
+++ b/kapptemplate/kpartapp/Makefile.am
@@ -0,0 +1,10 @@
+SUBDIRS=no-exe
+
+kpartappdir = $(kde_datadir)/kapptemplate/kpartapp
+kpartapp_DATA = app_part.cpp doc-app-Makefile.am \
+ lo32-app-app.png \
+ app-Makefile.am app_part-desktop hi16-app-app.png main.cpp \
+ app-configure.in.in app_part.h hi32-app-app.png \
+ app.cpp app_part.rc hi48-app-app.png \
+ app-desktop app_shell.rc index.docbook \
+ app.h doc-Makefile.am lo16-app-app.png
diff --git a/kapptemplate/kpartapp/app-Makefile.am b/kapptemplate/kpartapp/app-Makefile.am
new file mode 100644
index 00000000..3aa0495f
--- /dev/null
+++ b/kapptemplate/kpartapp/app-Makefile.am
@@ -0,0 +1,57 @@
+echo "Creating $LOCATION_ROOT/$APP_NAME_LC/Makefile.am...";
+cat << EOF > $LOCATION_ROOT/$APP_NAME_LC/Makefile.am
+# this has all of the subdirectories that make will recurse into. if
+# there are none, comment this out
+#SUBDIRS = .
+
+# set the include path for X, qt and KDE
+INCLUDES = \$(all_includes)
+
+# these are the headers for your project
+noinst_HEADERS = ${APP_NAME_LC}.h ${APP_NAME_LC}_part.h
+
+# let automoc handle all of the meta source files (moc)
+METASOURCES = AUTO
+
+messages: rc.cpp
+ \$(XGETTEXT) *.cpp -o \$(podir)/${APP_NAME_LC}.pot
+
+KDE_ICON = ${APP_NAME_LC}
+
+# this Makefile creates both a KPart application and a KPart
+#########################################################################
+# APPLICATION SECTION
+#########################################################################
+# this is the program that gets installed. it's name is used for all
+# of the other Makefile.am variables
+bin_PROGRAMS = ${APP_NAME_LC}
+
+# the application source, library search path, and link libraries
+${APP_NAME_LC}_SOURCES = main.cpp ${APP_NAME_LC}.cpp
+${APP_NAME_LC}_LDFLAGS = \$(KDE_RPATH) \$(all_libraries)
+${APP_NAME_LC}_LDADD = \$(LIB_KPARTS)
+
+# this is where the desktop file will go
+xdg_apps_DATA = ${APP_NAME_LC}.desktop
+
+# this is where the shell's XML-GUI resource file goes
+shellrcdir = \$(kde_datadir)/${APP_NAME_LC}
+shellrc_DATA = ${APP_NAME_LC}_shell.rc
+
+#########################################################################
+# KPART SECTION
+#########################################################################
+kde_module_LTLIBRARIES = lib${APP_NAME_LC}part.la
+
+# the Part's source, library search path, and link libraries
+lib${APP_NAME_LC}part_la_SOURCES = ${APP_NAME_LC}_part.cpp
+lib${APP_NAME_LC}part_la_LDFLAGS = -module \$(KDE_PLUGIN) \$(all_libraries)
+lib${APP_NAME_LC}part_la_LIBADD = \$(LIB_KPARTS) \$(LIB_KFILE)
+
+# this is where the desktop file will go
+partdesktopdir = \$(kde_servicesdir)
+partdesktop_DATA = ${APP_NAME_LC}_part.desktop
+
+# this is where the part's XML-GUI resource file goes
+partrcdir = \$(kde_datadir)/${APP_NAME_LC}part
+partrc_DATA = ${APP_NAME_LC}_part.rc
diff --git a/kapptemplate/kpartapp/app-configure.in.in b/kapptemplate/kpartapp/app-configure.in.in
new file mode 100644
index 00000000..4d050a09
--- /dev/null
+++ b/kapptemplate/kpartapp/app-configure.in.in
@@ -0,0 +1,14 @@
+echo "Creating $LOCATION_ROOT/configure.in.in...";
+cat << EOF > $LOCATION_ROOT/configure.in.in
+#MIN_CONFIG
+
+AM_INIT_AUTOMAKE(${APP_NAME_LC}, ${APP_VERSION})
+
+dnl These are common macros that you might or might not want to use
+
+dnl Checks for header files.
+AC_HEADER_DIRENT
+AC_HEADER_STDC
+AC_HEADER_TIME
+AC_CHECK_HEADERS(fcntl.h sys/time.h unistd.h stdlib.h paths.h)
+AC_CHECK_FUNCS(usleep)
diff --git a/kapptemplate/kpartapp/app-desktop b/kapptemplate/kpartapp/app-desktop
new file mode 100644
index 00000000..7b4090f1
--- /dev/null
+++ b/kapptemplate/kpartapp/app-desktop
@@ -0,0 +1,11 @@
+echo "Creating $LOCATION_ROOT/${APP_NAME_LC}/${APP_NAME_LC}.desktop...";
+cat << EOF > $LOCATION_ROOT/${APP_NAME_LC}/${APP_NAME_LC}.desktop
+[Desktop Entry]
+Encoding=UTF-8
+Name=${APP_NAME}
+Exec=${APP_NAME_LC} %i %m -caption "%c"
+Icon=${APP_NAME_LC}
+Type=Application
+DocPath=${APP_NAME_LC}/${APP_NAME_LC}.html
+GenericName=A KDE KPart Application
+Terminal=0
diff --git a/kapptemplate/kpartapp/app.cpp b/kapptemplate/kpartapp/app.cpp
new file mode 100644
index 00000000..8b04053e
--- /dev/null
+++ b/kapptemplate/kpartapp/app.cpp
@@ -0,0 +1,176 @@
+echo "Creating $LOCATION_ROOT/${APP_NAME_LC}/${APP_NAME_LC}.cpp...";
+cat << EOF > $LOCATION_ROOT/${APP_NAME_LC}/${APP_NAME_LC}.cpp
+/*
+ * ${APP_NAME_LC}.cpp
+ *
+ * Copyright (C) 2004 $AUTHOR <$EMAIL>
+ */
+#include "${APP_NAME_LC}.h"
+#include "${APP_NAME_LC}.moc"
+
+#include <kkeydialog.h>
+#include <kconfig.h>
+#include <kurl.h>
+
+#include <kedittoolbar.h>
+
+#include <kaction.h>
+#include <kstdaction.h>
+
+#include <klibloader.h>
+#include <kmessagebox.h>
+#include <kfiledialog.h>
+#include <kstatusbar.h>
+
+${APP_NAME}::${APP_NAME}()
+ : KParts::MainWindow( 0L, "${APP_NAME}" )
+{
+ // set the shell's ui resource file
+ setXMLFile("${APP_NAME_LC}_shell.rc");
+
+ // then, setup our actions
+ setupActions();
+
+ // this routine will find and load our Part. it finds the Part by
+ // name which is a bad idea usually.. but it's alright in this
+ // case since our Part is made for this Shell
+ KLibFactory *factory = KLibLoader::self()->factory("lib${APP_NAME_LC}part");
+ if (factory)
+ {
+ // now that the Part is loaded, we cast it to a Part to get
+ // our hands on it
+ m_part = static_cast<KParts::ReadWritePart *>(factory->create(this,
+ "${APP_NAME_LC}_part", "KParts::ReadWritePart" ));
+
+ if (m_part)
+ {
+ // tell the KParts::MainWindow that this is indeed the main widget
+ setCentralWidget(m_part->widget());
+
+ // and integrate the part's GUI with the shell's
+ createGUI(m_part);
+ }
+ }
+ else
+ {
+ // if we couldn't find our Part, we exit since the Shell by
+ // itself can't do anything useful
+ KMessageBox::error(this, "Could not find our Part!");
+ kapp->quit();
+ // we return here, cause kapp->quit() only means "exit the
+ // next time we enter the event loop...
+ return;
+ }
+
+ // apply the saved mainwindow settings, if any, and ask the mainwindow
+ // to automatically save settings if changed: window size, toolbar
+ // position, icon size, etc.
+ setAutoSaveSettings();
+}
+
+${APP_NAME}::~${APP_NAME}()
+{
+}
+
+void ${APP_NAME}::load(const KURL& url)
+{
+ m_part->openURL( url );
+}
+
+void ${APP_NAME}::setupActions()
+{
+ KStdAction::openNew(this, SLOT(fileNew()), actionCollection());
+ KStdAction::open(this, SLOT(fileOpen()), actionCollection());
+
+ KStdAction::quit(kapp, SLOT(quit()), actionCollection());
+
+ createStandardStatusBarAction();
+ setStandardToolBarMenuEnabled(true);
+
+ KStdAction::keyBindings(this, SLOT(optionsConfigureKeys()), actionCollection());
+ KStdAction::configureToolbars(this, SLOT(optionsConfigureToolbars()), actionCollection());
+}
+
+void ${APP_NAME}::saveProperties(KConfig* /*config*/)
+{
+ // the 'config' object points to the session managed
+ // config file. anything you write here will be available
+ // later when this app is restored
+}
+
+void ${APP_NAME}::readProperties(KConfig* /*config*/)
+{
+ // the 'config' object points to the session managed
+ // config file. this function is automatically called whenever
+ // the app is being restored. read in here whatever you wrote
+ // in 'saveProperties'
+}
+
+void ${APP_NAME}::fileNew()
+{
+ // this slot is called whenever the File->New menu is selected,
+ // the New shortcut is pressed (usually CTRL+N) or the New toolbar
+ // button is clicked
+
+ // About this function, the style guide (
+ // http://developer.kde.org/documentation/standards/kde/style/basics/index.html )
+ // says that it should open a new window if the document is _not_
+ // in its initial state. This is what we do here..
+ if ( ! m_part->url().isEmpty() || m_part->isModified() )
+ {
+ (new ${APP_NAME})->show();
+ };
+}
+
+void ${APP_NAME}::optionsConfigureKeys()
+{
+ KKeyDialog dlg( true, this );
+ dlg.insert( actionCollection(), "${APP_NAME_LC}_shell.rc" );
+ dlg.insert( m_part->actionCollection(), "${APP_NAME_LC}_part.rc" );
+ (void) dlg.configure( true );
+}
+
+void ${APP_NAME}::optionsConfigureToolbars()
+{
+ saveMainWindowSettings(KGlobal::config(), autoSaveGroup());
+
+ // use the standard toolbar editor
+ KEditToolbar dlg(factory());
+ connect(&dlg, SIGNAL(newToolbarConfig()),
+ this, SLOT(applyNewToolbarConfig()));
+ dlg.exec();
+}
+
+void ${APP_NAME}::applyNewToolbarConfig()
+{
+ applyMainWindowSettings(KGlobal::config(), autoSaveGroup());
+}
+
+void ${APP_NAME}::fileOpen()
+{
+ // this slot is called whenever the File->Open menu is selected,
+ // the Open shortcut is pressed (usually CTRL+O) or the Open toolbar
+ // button is clicked
+ KURL url =
+ KFileDialog::getOpenURL( QString::null, QString::null, this );
+
+ if (url.isEmpty() == false)
+ {
+ // About this function, the style guide (
+ // http://developer.kde.org/documentation/standards/kde/style/basics/index.html )
+ // says that it should open a new window if the document is _not_
+ // in its initial state. This is what we do here..
+ if ( m_part->url().isEmpty() && ! m_part->isModified() )
+ {
+ // we open the file in this window...
+ load( url );
+ }
+ else
+ {
+ // we open the file in a new window...
+ ${APP_NAME}* newWin = new ${APP_NAME};
+ newWin->load( url );
+ newWin->show();
+ }
+ }
+}
diff --git a/kapptemplate/kpartapp/app.h b/kapptemplate/kpartapp/app.h
new file mode 100644
index 00000000..41daea60
--- /dev/null
+++ b/kapptemplate/kpartapp/app.h
@@ -0,0 +1,70 @@
+echo "Creating $LOCATION_ROOT/$APP_NAME_LC/${APP_NAME_LC}.h...";
+cat << EOF > $LOCATION_ROOT/$APP_NAME_LC/${APP_NAME_LC}.h
+#ifndef ${APP_NAME_UC}_H
+#define ${APP_NAME_UC}_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <kapplication.h>
+#include <kparts/mainwindow.h>
+
+/**
+ * This is the application "Shell". It has a menubar, toolbar, and
+ * statusbar but relies on the "Part" to do all the real work.
+ *
+ * @short Application Shell
+ * @author ${AUTHOR} <${EMAIL}>
+ * @version ${APP_VERSION}
+ */
+class ${APP_NAME} : public KParts::MainWindow
+{
+ Q_OBJECT
+public:
+ /**
+ * Default Constructor
+ */
+ ${APP_NAME}();
+
+ /**
+ * Default Destructor
+ */
+ virtual ~${APP_NAME}();
+
+ /**
+ * Use this method to load whatever file/URL you have
+ */
+ void load(const KURL& url);
+
+protected:
+ /**
+ * This method is called when it is time for the app to save its
+ * properties for session management purposes.
+ */
+ void saveProperties(KConfig *);
+
+ /**
+ * This method is called when this app is restored. The KConfig
+ * object points to the session management config file that was saved
+ * with @ref saveProperties
+ */
+ void readProperties(KConfig *);
+
+private slots:
+ void fileNew();
+ void fileOpen();
+ void optionsConfigureKeys();
+ void optionsConfigureToolbars();
+
+ void applyNewToolbarConfig();
+
+private:
+ void setupAccel();
+ void setupActions();
+
+private:
+ KParts::ReadWritePart *m_part;
+};
+
+#endif // ${APP_NAME_UC}_H
diff --git a/kapptemplate/kpartapp/app_part-desktop b/kapptemplate/kpartapp/app_part-desktop
new file mode 100644
index 00000000..6ba3bf54
--- /dev/null
+++ b/kapptemplate/kpartapp/app_part-desktop
@@ -0,0 +1,9 @@
+echo "Creating $LOCATION_ROOT/${APP_NAME_LC}/${APP_NAME_LC}_part.desktop...";
+cat << EOF > $LOCATION_ROOT/${APP_NAME_LC}/${APP_NAME_LC}_part.desktop
+[Desktop Entry]
+Encoding=UTF-8
+Name=${APP_NAME}Part
+MimeType=text/english;text/plain;text/x-makefile;text/x-c++hdr;text/x-c++src;text/x-chdr;text/x-csrc;text/x-java;text/x-moc;text/x-pascal;text/x-tcl;text/x-tex;application/x-shellscript;text/x-c;text/x-c++;
+ServiceTypes=KParts/ReadOnlyPart,KParts/ReadWritePart
+X-KDE-Library=lib${APP_NAME_LC}part
+Type=Service
diff --git a/kapptemplate/kpartapp/app_part.cpp b/kapptemplate/kpartapp/app_part.cpp
new file mode 100644
index 00000000..c2821950
--- /dev/null
+++ b/kapptemplate/kpartapp/app_part.cpp
@@ -0,0 +1,148 @@
+echo "Creating $LOCATION_ROOT/${APP_NAME_LC}/${APP_NAME_LC}_part.cpp...";
+cat << EOF > $LOCATION_ROOT/${APP_NAME_LC}/${APP_NAME_LC}_part.cpp
+#include "${APP_NAME_LC}_part.h"
+
+#include "${APP_NAME_LC}_part.moc"
+
+#include <kinstance.h>
+#include <kaction.h>
+#include <kstdaction.h>
+#include <kfiledialog.h>
+#include <kparts/genericfactory.h>
+
+#include <qfile.h>
+#include <qtextstream.h>
+#include <qmultilineedit.h>
+
+typedef KParts::GenericFactory<${APP_NAME}Part> ${APP_NAME}PartFactory;
+K_EXPORT_COMPONENT_FACTORY( lib${APP_NAME_LC}part, ${APP_NAME}PartFactory )
+
+${APP_NAME}Part::${APP_NAME}Part( QWidget *parentWidget, const char *widgetName,
+ QObject *parent, const char *name,
+ const QStringList & /*args*/ )
+ : KParts::ReadWritePart(parent, name)
+{
+ // we need an instance
+ setInstance( ${APP_NAME}PartFactory::instance() );
+
+ // this should be your custom internal widget
+ m_widget = new QMultiLineEdit( parentWidget, widgetName );
+
+ // notify the part that this is our internal widget
+ setWidget(m_widget);
+
+ // create our actions
+ KStdAction::saveAs(this, SLOT(fileSaveAs()), actionCollection());
+ KStdAction::save(this, SLOT(save()), actionCollection());
+
+ // set our XML-UI resource file
+ setXMLFile("${APP_NAME_LC}_part.rc");
+
+ // we are read-write by default
+ setReadWrite(true);
+
+ // we are not modified since we haven't done anything yet
+ setModified(false);
+}
+
+${APP_NAME}Part::~${APP_NAME}Part()
+{
+}
+
+void ${APP_NAME}Part::setReadWrite(bool rw)
+{
+ // notify your internal widget of the read-write state
+ m_widget->setReadOnly(!rw);
+ if (rw)
+ connect(m_widget, SIGNAL(textChanged()),
+ this, SLOT(setModified()));
+ else
+ {
+ disconnect(m_widget, SIGNAL(textChanged()),
+ this, SLOT(setModified()));
+ }
+
+ ReadWritePart::setReadWrite(rw);
+}
+
+void ${APP_NAME}Part::setModified(bool modified)
+{
+ // get a handle on our Save action and make sure it is valid
+ KAction *save = actionCollection()->action(KStdAction::stdName(KStdAction::Save));
+ if (!save)
+ return;
+
+ // if so, we either enable or disable it based on the current
+ // state
+ if (modified)
+ save->setEnabled(true);
+ else
+ save->setEnabled(false);
+
+ // in any event, we want our parent to do it's thing
+ ReadWritePart::setModified(modified);
+}
+
+KAboutData *${APP_NAME}Part::createAboutData()
+{
+ // the non-i18n name here must be the same as the directory in
+ // which the part's rc file is installed ('partrcdir' in the
+ // Makefile)
+ KAboutData *aboutData = new KAboutData("${APP_NAME_LC}part", I18N_NOOP("${APP_NAME}Part"), "${APP_VERSION}");
+ aboutData->addAuthor("${AUTHOR}", 0, "${EMAIL}");
+ return aboutData;
+}
+
+bool ${APP_NAME}Part::openFile()
+{
+ // m_file is always local so we can use QFile on it
+ QFile file(m_file);
+ if (file.open(IO_ReadOnly) == false)
+ return false;
+
+ // our example widget is text-based, so we use QTextStream instead
+ // of a raw QDataStream
+ QTextStream stream(&file);
+ QString str;
+ while (!stream.eof())
+ str += stream.readLine() + "\n";
+
+ file.close();
+
+ // now that we have the entire file, display it
+ m_widget->setText(str);
+
+ // just for fun, set the status bar
+ emit setStatusBarText( m_url.prettyURL() );
+
+ return true;
+}
+
+bool ${APP_NAME}Part::saveFile()
+{
+ // if we aren't read-write, return immediately
+ if (isReadWrite() == false)
+ return false;
+
+ // m_file is always local, so we use QFile
+ QFile file(m_file);
+ if (file.open(IO_WriteOnly) == false)
+ return false;
+
+ // use QTextStream to dump the text to the file
+ QTextStream stream(&file);
+ stream << m_widget->text();
+
+ file.close();
+
+ return true;
+}
+
+void ${APP_NAME}Part::fileSaveAs()
+{
+ // this slot is called whenever the File->Save As menu is selected,
+ QString file_name = KFileDialog::getSaveFileName();
+ if (file_name.isEmpty() == false)
+ saveAs(file_name);
+}
+
diff --git a/kapptemplate/kpartapp/app_part.h b/kapptemplate/kpartapp/app_part.h
new file mode 100644
index 00000000..18841510
--- /dev/null
+++ b/kapptemplate/kpartapp/app_part.h
@@ -0,0 +1,69 @@
+echo "Creating $LOCATION_ROOT/${APP_NAME_LC}/${APP_NAME_LC}_part.h...";
+cat << EOF > $LOCATION_ROOT/${APP_NAME_LC}/${APP_NAME_LC}_part.h
+#ifndef ${APP_NAME_UC}PART_H
+#define ${APP_NAME_UC}PART_H
+
+#include <kparts/part.h>
+
+class QWidget;
+class QPainter;
+class KURL;
+class QMultiLineEdit;
+class KAboutData;
+
+/**
+ * This is a "Part". It that does all the real work in a KPart
+ * application.
+ *
+ * @short Main Part
+ * @author ${AUTHOR} <${EMAIL}>
+ * @version ${APP_VERSION}
+ */
+class ${APP_NAME}Part : public KParts::ReadWritePart
+{
+ Q_OBJECT
+public:
+ /**
+ * Default constructor
+ */
+ ${APP_NAME}Part(QWidget *parentWidget, const char *widgetName,
+ QObject *parent, const char *name, const QStringList &args);
+
+ /**
+ * Destructor
+ */
+ virtual ~${APP_NAME}Part();
+
+ /**
+ * This is a virtual function inherited from KParts::ReadWritePart.
+ * A shell will use this to inform this Part if it should act
+ * read-only
+ */
+ virtual void setReadWrite(bool rw);
+
+ /**
+ * Reimplemented to disable and enable Save action
+ */
+ virtual void setModified(bool modified);
+
+ static KAboutData *createAboutData();
+
+protected:
+ /**
+ * This must be implemented by each part
+ */
+ virtual bool openFile();
+
+ /**
+ * This must be implemented by each read-write part
+ */
+ virtual bool saveFile();
+
+protected slots:
+ void fileSaveAs();
+
+private:
+ QMultiLineEdit *m_widget;
+};
+
+#endif // ${APP_NAME_UC}PART_H
diff --git a/kapptemplate/kpartapp/app_part.rc b/kapptemplate/kpartapp/app_part.rc
new file mode 100644
index 00000000..793fe772
--- /dev/null
+++ b/kapptemplate/kpartapp/app_part.rc
@@ -0,0 +1,17 @@
+echo "Creating $LOCATION_ROOT/${APP_NAME_LC}/${APP_NAME_LC}_part.rc...";
+cat << EOF > $LOCATION_ROOT/${APP_NAME_LC}/${APP_NAME_LC}_part.rc
+<!DOCTYPE kpartgui SYSTEM "kpartgui.dtd">
+<kpartgui name="${APP_NAME_LC}_part" version="1">
+<MenuBar>
+ <Menu name="file">
+ <Action name="file_save"/>
+ <Action name="file_save_as"/>
+ </Menu>
+</MenuBar>
+<ToolBar name="mainToolBar">
+ <Action name="file_open"/>
+ <Action name="file_save"/>
+ <Action name="file_print"/>
+ <Separator/>
+</ToolBar>
+</kpartgui>
diff --git a/kapptemplate/kpartapp/app_shell.rc b/kapptemplate/kpartapp/app_shell.rc
new file mode 100644
index 00000000..22b95aad
--- /dev/null
+++ b/kapptemplate/kpartapp/app_shell.rc
@@ -0,0 +1,32 @@
+echo "Creating $LOCATION_ROOT/${APP_NAME_LC}/${APP_NAME_LC}_shell.rc...";
+cat << EOF > $LOCATION_ROOT/${APP_NAME_LC}/${APP_NAME_LC}_shell.rc
+<!DOCTYPE kpartgui SYSTEM "kpartgui.dtd">
+<kpartgui name="${APP_NAME_LC}_shell" version="1">
+<MenuBar>
+ <Menu noMerge="1" name="file"><text>&amp;File</text>
+ <Action name="file_new"/>
+ <Action name="file_open"/>
+ <Separator/>
+ <Merge/>
+ <Separator/>
+ <Action name="file_quit"/>
+ </Menu>
+ <Menu noMerge="1" name="settings"><text>&amp;Settings</text>
+ <Action name="options_show_toolbar"/>
+ <Action name="options_show_statusbar"/>
+ <Merge name="show_merge"/>
+ <Separator/>
+ <Action name="options_configure_keybinding"/>
+ <Action name="options_configure_toolbars"/>
+ <Action name="options_configure"/>
+ <Merge name="configure_merge"/>
+ <Separator/>
+ <Merge/>
+ </Menu>
+</MenuBar>
+<ToolBar noMerge="1" name="mainToolBar"><text>Main Toolbar</text>
+ <Action name="file_new"/>
+ <Merge/>
+ <Action name="help"/>
+</ToolBar>
+</kpartgui>
diff --git a/kapptemplate/kpartapp/doc-Makefile.am b/kapptemplate/kpartapp/doc-Makefile.am
new file mode 100644
index 00000000..02611d03
--- /dev/null
+++ b/kapptemplate/kpartapp/doc-Makefile.am
@@ -0,0 +1,8 @@
+echo "Creating $LOCATION_ROOT/doc/Makefile.am...";
+$MKDIR $LOCATION_ROOT/doc
+cat << EOF > $LOCATION_ROOT/doc/Makefile.am
+
+SUBDIRS = \$(AUTODIRS)
+KDE_DOCS = $APP_NAME_LC
+KDE_LANG = en
+
diff --git a/kapptemplate/kpartapp/doc-app-Makefile.am b/kapptemplate/kpartapp/doc-app-Makefile.am
new file mode 100644
index 00000000..0356a93a
--- /dev/null
+++ b/kapptemplate/kpartapp/doc-app-Makefile.am
@@ -0,0 +1,9 @@
+echo "Creating $LOCATION_ROOT/doc/$APP_NAME_LC/Makefile.am...";
+$MKDIR $LOCATION_ROOT/doc/$APP_NAME_LC
+cat << EOF > $LOCATION_ROOT/doc/$APP_NAME_LC/Makefile.am
+
+# the SUBDIRS is filled automatically by am_edit. If files are
+# in this directory they are installed into the english dir
+KDE_LANG = en
+KDE_DOCS = $APP_NAME_LC
+SUBDIRS = \$(AUTODIRS)
diff --git a/kapptemplate/kpartapp/hi16-app-app.png b/kapptemplate/kpartapp/hi16-app-app.png
new file mode 100644
index 00000000..2f82a953
--- /dev/null
+++ b/kapptemplate/kpartapp/hi16-app-app.png
@@ -0,0 +1,2 @@
+echo "Creating $LOCATION_ROOT/$APP_NAME_LC/hi16-app-$APP_NAME_LC.png...";
+cp $SHARE_DIR/kapp/no-exe/hi16-app-app.png $LOCATION_ROOT/$APP_NAME_LC/hi16-app-$APP_NAME_LC.png
diff --git a/kapptemplate/kpartapp/hi32-app-app.png b/kapptemplate/kpartapp/hi32-app-app.png
new file mode 100644
index 00000000..767c9448
--- /dev/null
+++ b/kapptemplate/kpartapp/hi32-app-app.png
@@ -0,0 +1,2 @@
+echo "Creating $LOCATION_ROOT/$APP_NAME_LC/hi32-app-$APP_NAME_LC.png...";
+cp $SHARE_DIR/kapp/no-exe/hi32-app-app.png $LOCATION_ROOT/$APP_NAME_LC/hi32-app-$APP_NAME_LC.png
diff --git a/kapptemplate/kpartapp/hi48-app-app.png b/kapptemplate/kpartapp/hi48-app-app.png
new file mode 100644
index 00000000..08970c62
--- /dev/null
+++ b/kapptemplate/kpartapp/hi48-app-app.png
@@ -0,0 +1,2 @@
+echo "Creating $LOCATION_ROOT/$APP_NAME_LC/hi48-app-$APP_NAME_LC.png...";
+cp $SHARE_DIR/kapp/no-exe/hi48-app-app.png $LOCATION_ROOT/$APP_NAME_LC/hi48-app-$APP_NAME_LC.png
diff --git a/kapptemplate/kpartapp/index.docbook b/kapptemplate/kpartapp/index.docbook
new file mode 100644
index 00000000..86d1ee8d
--- /dev/null
+++ b/kapptemplate/kpartapp/index.docbook
@@ -0,0 +1,106 @@
+echo "Creating $LOCATION_ROOT/doc/$APP_NAME_LC/index.docbook...";
+echo "It is better to use template.docbook instead of this - please replace it"
+cat << EOF > $LOCATION_ROOT/doc/$APP_NAME_LC/index.docbook
+<?xml version="1.0" ?>
+<!DOCTYPE book PUBLIC "-//KDE//DTD DocBook XML V4.1-Based Variant V1.0//EN" "dtd/kdex.dtd" [
+ <!ENTITY kappname "&$APP_NAME;">
+ <!ENTITY % addindex "IGNORE">
+ <!ENTITY % English "INCLUDE" > <!-- change language only here -->
+]>
+<!-- Important note: please use template.docbook instead of this file.
+ This is only the conversion of app.sgml into DocBook SGML.
+ template.docbook gives you more information on what you can and
+ should do. Thanks. -->
+
+<book lang="&language;">
+
+<bookinfo>
+<title>The $APP_NAME Handbook</title>
+<authorgroup>
+<author>
+<firstname></firstname>
+<surname>$AUTHOR</surname>
+<affiliation><address><email>$EMAIL</email></address></affiliation>
+</author>
+</authorgroup>
+<date>`date "+%Y-%m-%d"`</date>
+<releaseinfo>$APP_VERSION</releaseinfo>
+<abstract>
+<para>SHORT DESCRIPTION GOES HERE</para>
+</abstract>
+<keywordset>
+<keyword>KDE</keyword>
+<keyword>$APP_NAME</keyword>
+</keywordset>
+</bookinfo>
+
+ <chapter id="introduction">
+ <title>Introduction</title>
+
+ <sect1 id="features">
+ <title>Features</title>
+ <para></para>
+ </sect1>
+ </chapter>
+
+ <chapter id="installation">
+ <title>Installation</title>
+
+ <sect1 id="how-to-obtain-$APP_NAME">
+ <title>How to obtain $APP_NAME</title>
+ <para></para>
+ </sect1>
+
+ <sect1 id="requirements">
+ <title>Requirements</title>
+ <para></para>
+ </sect1>
+
+ <sect1 id="compilation-and-installation">
+ <title>Compilation and Installation</title>
+
+ <para>Compiling $APP_NAME is very easy. The following should do
+ it: <screen>
+<prompt>%</prompt> <userinput><command>./configure</command></userinput>
+<prompt>%</prompt> <userinput><command>make</command></userinput>
+<prompt>%</prompt> <userinput><command>make</command> install</userinput></screen>
+ </para>
+
+ <para>That should do it! Should you run into any problems,
+ please report them to the <ulink
+ url="mailto:$EMAIL">author</ulink></para>
+ </sect1>
+ </chapter>
+
+ <chapter id="using-$APP_NAME">
+ <title>Using $APP_NAME</title>
+ <para></para>
+ </chapter>
+
+ <chapter id="questionsanswersandtips">
+ <title>Questions, Answers, and Tips</title>
+
+ <qandaset id="faq">
+ <title>Frequently asked questions</title>
+ <qandaentry>
+ <question>
+ <para>Question 1</para>
+ </question>
+ <answer>
+ <para>The answer</para>
+ </answer>
+ </qandaentry>
+ </qandaset>
+
+ </chapter>
+ &documentation.index;
+</book>
+<!--
+Local Variables:
+mode: sgml
+sgml-omittag: nil
+sgml-shorttag: t
+sgml-general-insert-case: lower
+End:
+-->
+
diff --git a/kapptemplate/kpartapp/lo16-app-app.png b/kapptemplate/kpartapp/lo16-app-app.png
new file mode 100644
index 00000000..c495e509
--- /dev/null
+++ b/kapptemplate/kpartapp/lo16-app-app.png
@@ -0,0 +1,2 @@
+echo "Creating $LOCATION_ROOT/$APP_NAME_LC/lo16-app-$APP_NAME_LC.png...";
+cp $SHARE_DIR/kapp/no-exe/lo16-app-app.png $LOCATION_ROOT/$APP_NAME_LC/lo16-app-$APP_NAME_LC.png
diff --git a/kapptemplate/kpartapp/lo32-app-app.png b/kapptemplate/kpartapp/lo32-app-app.png
new file mode 100644
index 00000000..6faac157
--- /dev/null
+++ b/kapptemplate/kpartapp/lo32-app-app.png
@@ -0,0 +1,2 @@
+echo "Creating $LOCATION_ROOT/$APP_NAME_LC/lo32-app-$APP_NAME_LC.png...";
+cp $SHARE_DIR/kapp/no-exe/lo32-app-app.png $LOCATION_ROOT/$APP_NAME_LC/lo32-app-$APP_NAME_LC.png
diff --git a/kapptemplate/kpartapp/main.cpp b/kapptemplate/kpartapp/main.cpp
new file mode 100644
index 00000000..14bbf216
--- /dev/null
+++ b/kapptemplate/kpartapp/main.cpp
@@ -0,0 +1,55 @@
+echo "Creating $LOCATION_ROOT/${APP_NAME_LC}/main.cpp...";
+cat << EOF > $LOCATION_ROOT/${APP_NAME_LC}/main.cpp
+#include "${APP_NAME_LC}.h"
+#include <kapplication.h>
+#include <kaboutdata.h>
+#include <kcmdlineargs.h>
+#include <klocale.h>
+
+static const char description[] =
+ I18N_NOOP("A KDE KPart Application");
+
+static const char version[] = "v${APP_VERSION}";
+
+static KCmdLineOptions options[] =
+{
+ { "+[URL]", I18N_NOOP( "Document to open" ), 0 },
+ KCmdLineLastOption
+};
+
+int main(int argc, char **argv)
+{
+ KAboutData about("${APP_NAME_LC}", I18N_NOOP("${APP_NAME}"), version, description, KAboutData::License_GPL, "(C) 2004 ${AUTHOR}", 0, 0, "${EMAIL}");
+ about.addAuthor( "${AUTHOR}", 0, "${EMAIL}" );
+ KCmdLineArgs::init(argc, argv, &about);
+ KCmdLineArgs::addCmdLineOptions( options );
+ KApplication app;
+
+ // see if we are starting with session management
+ if (app.isRestored())
+ RESTORE(${APP_NAME})
+ else
+ {
+ // no session.. just start up normally
+ KCmdLineArgs *args = KCmdLineArgs::parsedArgs();
+
+ if ( args->count() == 0 )
+ {
+ ${APP_NAME} *widget = new ${APP_NAME};
+ widget->show();
+ }
+ else
+ {
+ int i = 0;
+ for (; i < args->count(); i++ )
+ {
+ ${APP_NAME} *widget = new ${APP_NAME};
+ widget->show();
+ widget->load( args->url( i ) );
+ }
+ }
+ args->clear();
+ }
+
+ return app.exec();
+}
diff --git a/kapptemplate/kpartapp/no-exe/Makefile.am b/kapptemplate/kpartapp/no-exe/Makefile.am
new file mode 100644
index 00000000..7e993c96
--- /dev/null
+++ b/kapptemplate/kpartapp/no-exe/Makefile.am
@@ -0,0 +1,3 @@
+kpartappdir = $(kde_datadir)/kapptemplate/kpartapp/no-exe
+kpartapp_DATA = hi32-app-app.png lo16-app-app.png hi16-app-app.png \
+ hi48-app-app.png lo32-app-app.png
diff --git a/kapptemplate/kpartapp/no-exe/hi16-app-app.png b/kapptemplate/kpartapp/no-exe/hi16-app-app.png
new file mode 100644
index 00000000..43eab761
--- /dev/null
+++ b/kapptemplate/kpartapp/no-exe/hi16-app-app.png
Binary files differ
diff --git a/kapptemplate/kpartapp/no-exe/hi32-app-app.png b/kapptemplate/kpartapp/no-exe/hi32-app-app.png
new file mode 100644
index 00000000..ce9df987
--- /dev/null
+++ b/kapptemplate/kpartapp/no-exe/hi32-app-app.png
Binary files differ
diff --git a/kapptemplate/kpartapp/no-exe/hi48-app-app.png b/kapptemplate/kpartapp/no-exe/hi48-app-app.png
new file mode 100644
index 00000000..6464fb39
--- /dev/null
+++ b/kapptemplate/kpartapp/no-exe/hi48-app-app.png
Binary files differ
diff --git a/kapptemplate/kpartapp/no-exe/lo16-app-app.png b/kapptemplate/kpartapp/no-exe/lo16-app-app.png
new file mode 100644
index 00000000..e21db293
--- /dev/null
+++ b/kapptemplate/kpartapp/no-exe/lo16-app-app.png
Binary files differ
diff --git a/kapptemplate/kpartapp/no-exe/lo32-app-app.png b/kapptemplate/kpartapp/no-exe/lo32-app-app.png
new file mode 100644
index 00000000..4ecd9ce3
--- /dev/null
+++ b/kapptemplate/kpartapp/no-exe/lo32-app-app.png
Binary files differ
diff --git a/kapptemplate/kpartplugin.module b/kapptemplate/kpartplugin.module
new file mode 100644
index 00000000..86d20120
--- /dev/null
+++ b/kapptemplate/kpartplugin.module
@@ -0,0 +1,69 @@
+###########################################################################
+#
+# STEP 1: GET USER INFORMATION
+#
+###########################################################################
+# Get the application name
+APPTYPE="plugin";
+APPDEFAULT="Test";
+GetProperName
+
+# Get the application version
+GetVersion
+
+# Get the root where this framework will be installed
+GetLocationRoot
+
+# Get the author's name
+GetAuthorName
+
+# Get the author's email
+GetAuthorEmail
+
+# Verify that everything is grand
+$ECHO;
+$ECHO "Here is what I have:";
+$ECHO "The plugin: $APP_NAME v$APP_VERSION";
+$ECHO "Installed in: $LOCATION_ROOT";
+$ECHO "Author: $AUTHOR <$EMAIL>";
+$ECHO;
+$ECHO "Is this correct (Y/n)? ";
+$ECHO ": \c";
+read Y_N;
+if [ $Y_N -a $Y_N = 'n' ];
+then
+ $ECHO "AUGH! Well, try again.";
+ exit 0;
+fi
+$ECHO;
+
+$ECHO "OK, Here we go!!";
+
+###########################################################################
+#
+# STEP 2: CREATE APPLICATION FRAMEWORK
+#
+###########################################################################
+CreateAppFramework
+
+###########################################################################
+#
+# STEP 3: GENERATE PLUGIN-SPECIFIC FILES
+#
+###########################################################################
+for EXE_FILE in $KPARTPLUGIN_FILES;
+do
+ . $SHARE_DIR/kpartplugin/$EXE_FILE || exit 1;
+done
+
+###########################################################################
+#
+# STEP 4: FINAL STEPS
+#
+###########################################################################
+
+if [ ! $NOINIT ]; then
+ cd $LOCATION_ROOT && $MAKE -f Makefile.cvs
+fi
+
+$ECHO "DONE!";
diff --git a/kapptemplate/kpartplugin/Makefile.am b/kapptemplate/kpartplugin/Makefile.am
new file mode 100644
index 00000000..abbef9fb
--- /dev/null
+++ b/kapptemplate/kpartplugin/Makefile.am
@@ -0,0 +1,5 @@
+SUBDIRS=no-exe
+
+kpartplugindir = $(kde_datadir)/kapptemplate/kpartplugin
+kpartplugin_DATA = plugin-Makefile.am plugin_app.cpp plugin_app.h \
+ plugin_app.rc hi16-action-plugin.png hi22-action-plugin.png
diff --git a/kapptemplate/kpartplugin/hi16-action-plugin.png b/kapptemplate/kpartplugin/hi16-action-plugin.png
new file mode 100644
index 00000000..f40bc9c5
--- /dev/null
+++ b/kapptemplate/kpartplugin/hi16-action-plugin.png
@@ -0,0 +1,2 @@
+echo "Creating $LOCATION_ROOT/$APP_NAME_LC/hi16-action-$APP_NAME_LC.png...";
+cp $SHARE_DIR/kpartplugin/no-exe/hi16-action-plugin.png $LOCATION_ROOT/$APP_NAME_LC/hi16-action-$APP_NAME_LC.png
diff --git a/kapptemplate/kpartplugin/hi22-action-plugin.png b/kapptemplate/kpartplugin/hi22-action-plugin.png
new file mode 100644
index 00000000..8e1a7616
--- /dev/null
+++ b/kapptemplate/kpartplugin/hi22-action-plugin.png
@@ -0,0 +1,2 @@
+echo "Creating $LOCATION_ROOT/$APP_NAME_LC/hi22-action-$APP_NAME_LC.png...";
+cp $SHARE_DIR/kpartplugin/no-exe/hi22-action-plugin.png $LOCATION_ROOT/$APP_NAME_LC/hi22-action-$APP_NAME_LC.png
diff --git a/kapptemplate/kpartplugin/no-exe/Makefile.am b/kapptemplate/kpartplugin/no-exe/Makefile.am
new file mode 100644
index 00000000..95586248
--- /dev/null
+++ b/kapptemplate/kpartplugin/no-exe/Makefile.am
@@ -0,0 +1,2 @@
+kpartplugindir = $(kde_datadir)/kapptemplate/kpartplugin/no-exe
+kpartplugin_DATA = hi16-action-plugin.png hi22-action-plugin.png
diff --git a/kapptemplate/kpartplugin/no-exe/hi16-action-plugin.png b/kapptemplate/kpartplugin/no-exe/hi16-action-plugin.png
new file mode 100644
index 00000000..e2d7bab8
--- /dev/null
+++ b/kapptemplate/kpartplugin/no-exe/hi16-action-plugin.png
Binary files differ
diff --git a/kapptemplate/kpartplugin/no-exe/hi22-action-plugin.png b/kapptemplate/kpartplugin/no-exe/hi22-action-plugin.png
new file mode 100644
index 00000000..4082bf10
--- /dev/null
+++ b/kapptemplate/kpartplugin/no-exe/hi22-action-plugin.png
Binary files differ
diff --git a/kapptemplate/kpartplugin/plugin-Makefile.am b/kapptemplate/kpartplugin/plugin-Makefile.am
new file mode 100644
index 00000000..cdb7d510
--- /dev/null
+++ b/kapptemplate/kpartplugin/plugin-Makefile.am
@@ -0,0 +1,20 @@
+echo "Creating $LOCATION_ROOT/$APP_NAME_LC/Makefile.am...";
+cat << EOF > $LOCATION_ROOT/$APP_NAME_LC/Makefile.am
+INCLUDES = \$(all_includes)
+METASOURCES = AUTO
+
+KDE_ICON = ${APP_NAME_LC}
+
+# Install this plugin in the KDE modules directory
+kde_module_LTLIBRARIES = lib${APP_NAME_LC}plugin.la
+
+# This is all standard. Remove the LIB_KHTML reference if you are not
+# using the KHTML Part
+lib${APP_NAME_LC}plugin_la_SOURCES = plugin_${APP_NAME_LC}.cpp
+lib${APP_NAME_LC}plugin_la_LIBADD = \$(LIB_KPARTS) \$(LIB_KHTML)
+lib${APP_NAME_LC}plugin_la_LDFLAGS = -module \$(KDE_PLUGIN) \$(all_libraries)
+
+# Install the .rc file in the Part's directory (in this case, the part
+# is KHTMLPart)
+pluginsdir = \$(kde_datadir)/khtml/kpartplugins
+plugins_DATA = plugin_${APP_NAME_LC}.rc
diff --git a/kapptemplate/kpartplugin/plugin_app.cpp b/kapptemplate/kpartplugin/plugin_app.cpp
new file mode 100644
index 00000000..71c68bc7
--- /dev/null
+++ b/kapptemplate/kpartplugin/plugin_app.cpp
@@ -0,0 +1,81 @@
+echo "Creating $LOCATION_ROOT/$APP_NAME_LC/plugin_${APP_NAME_LC}.cpp...";
+cat << EOF > $LOCATION_ROOT/$APP_NAME_LC/plugin_${APP_NAME_LC}.cpp
+#include "plugin_${APP_NAME_LC}.h"
+
+#include <khtml_part.h>
+#include <kaction.h>
+#include <kinstance.h>
+#include <kmessagebox.h>
+#include <klocale.h>
+#include <kgenericfactory.h>
+
+typedef KGenericFactory<Plugin${APP_NAME}> ${APP_NAME}Factory;
+K_EXPORT_COMPONENT_FACTORY( lib${APP_NAME_LC}plugin,
+ ${APP_NAME}Factory( "${APP_NAME_LC}" ) );
+
+Plugin${APP_NAME}::Plugin${APP_NAME}( QObject* parent, const char* name,
+ const QStringList & /*args*/ )
+ : Plugin( parent, name )
+{
+ // Instantiate all of your actions here. These will appear in
+ // Konqueror's menu and toolbars.
+ (void) new KAction( i18n("&Plugin Action"), "${APP_NAME_LC}", 0,
+ this, SLOT(slotAction()),
+ actionCollection(), "plugin_action" );
+}
+
+Plugin${APP_NAME}::~Plugin${APP_NAME}()
+{
+}
+
+void Plugin${APP_NAME}::slotAction()
+{
+ // This plugin assumes KHTMLPart. If your plugin can handle more
+ // than this or a different Part than this, simply delete or
+ // change the following block.
+ if ( !parent()->inherits("KHTMLPart") )
+ {
+ QString title( i18n( "Cannot Translate Source" ) );
+ QString text( i18n( "You cannot translate anything except web pages "
+ "with this plugin." ) );
+
+ KMessageBox::sorry( 0, text, title );
+ return;
+ }
+
+ // Get a handle on our parent so we may get the necessary data for
+ // processing
+ KHTMLPart *part = dynamic_cast<KHTMLPart *>(parent());
+
+ // This plugin only uses the URL. You may use whatever data you
+ // need.
+ KURL url( part->url() );
+
+ // This is a standard check to make sure we are dealing with a
+ // valid URL
+ if ( !url.isValid() )
+ {
+ QString title( i18n( "Malformed URL" ) );
+ QString text( i18n( "The URL you entered is not valid, please "
+ "correct it and try again." ) );
+
+ KMessageBox::sorry( 0, text, title );
+ return;
+ }
+
+// The following block is very plugin specific. In this example, we
+// translate the current page with AltaVista's BabelFish. You will
+// definitely want to change this.
+// BEGIN
+ KURL work( "http://babel.altavista.com/translate.dyn" );
+
+ QString query( "urltext=" );
+ query += KURL::encode_string( url.url() );
+ work.setQuery( query );
+// END
+
+ // Finally, execute the request
+ part->openURL( work );
+}
+
+#include <plugin_${APP_NAME_LC}.moc>
diff --git a/kapptemplate/kpartplugin/plugin_app.h b/kapptemplate/kpartplugin/plugin_app.h
new file mode 100644
index 00000000..3e651499
--- /dev/null
+++ b/kapptemplate/kpartplugin/plugin_app.h
@@ -0,0 +1,20 @@
+echo "Creating $LOCATION_ROOT/$APP_NAME_LC/plugin_${APP_NAME_LC}.h...";
+cat << EOF > $LOCATION_ROOT/$APP_NAME_LC/plugin_${APP_NAME_LC}.h
+#ifndef PLUGIN_${APP_NAME_UC}_H
+#define PLUGIN_${APP_NAME_UC}_H
+
+#include <kparts/plugin.h>
+
+class Plugin${APP_NAME} : public KParts::Plugin
+{
+ Q_OBJECT
+public:
+ Plugin${APP_NAME}( QObject* parent = 0, const char* name = 0,
+ const QStringList &args = QStringList() );
+ virtual ~Plugin${APP_NAME}();
+
+public slots:
+ void slotAction();
+};
+
+#endif // PLUGIN_${APP_NAME_UC}_H
diff --git a/kapptemplate/kpartplugin/plugin_app.rc b/kapptemplate/kpartplugin/plugin_app.rc
new file mode 100644
index 00000000..9d42f3b6
--- /dev/null
+++ b/kapptemplate/kpartplugin/plugin_app.rc
@@ -0,0 +1,13 @@
+echo "Creating $LOCATION_ROOT/$APP_NAME_LC/plugin_${APP_NAME_LC}.rc...";
+cat << EOF > $LOCATION_ROOT/$APP_NAME_LC/plugin_${APP_NAME_LC}.rc
+<!DOCTYPE kpartgui>
+<kpartplugin name="${APP_NAME_LC}" library="lib${APP_NAME_LC}plugin" version="1">
+<MenuBar>
+ <Menu name="tools"><Text>&amp;Tools</Text>
+ <Action name="plugin_action"/>
+ </Menu>
+</MenuBar>
+<ToolBar name="extraToolBar">
+ <Action name="plugin_action"/>
+</ToolBar>
+</kpartplugin>
diff --git a/kapptemplate/mkinstalldirs b/kapptemplate/mkinstalldirs
new file mode 100755
index 00000000..6b3b5fc5
--- /dev/null
+++ b/kapptemplate/mkinstalldirs
@@ -0,0 +1,40 @@
+#! /bin/sh
+# mkinstalldirs --- make directory hierarchy
+# Author: Noah Friedman <friedman@prep.ai.mit.edu>
+# Created: 1993-05-16
+# Public domain
+
+# $Id$
+
+errstatus=0
+
+for file
+do
+ set fnord `echo ":$file" | sed -ne 's/^:\//#/;s/^://;s/\// /g;s/^#/\//;p'`
+ shift
+
+ pathcomp=
+ for d
+ do
+ pathcomp="$pathcomp$d"
+ case "$pathcomp" in
+ -* ) pathcomp=./$pathcomp ;;
+ esac
+
+ if test ! -d "$pathcomp"; then
+ echo "mkdir $pathcomp"
+
+ mkdir "$pathcomp" || lasterr=$?
+
+ if test ! -d "$pathcomp"; then
+ errstatus=$lasterr
+ fi
+ fi
+
+ pathcomp="$pathcomp/"
+ done
+done
+
+exit $errstatus
+
+# mkinstalldirs ends here
diff --git a/kbabel/AUTHORS b/kbabel/AUTHORS
new file mode 100644
index 00000000..3ce9a203
--- /dev/null
+++ b/kbabel/AUTHORS
@@ -0,0 +1,7 @@
+Matthias Kiefer <kiefer@kde.org>
+Stanislav Visnovsky <visnovsky@kde.org>
+Dwayne Bailey <dwayne@translate.org.za>
+Bram Schoenmakers <bramschoenmakers@kde.nl>
+Asgeir Frimannsson <asgeirf@redhat.com>
+Albert Cervera Areny <albertca@hotpop.com>
+
diff --git a/kbabel/COPYING b/kbabel/COPYING
new file mode 100644
index 00000000..3912109b
--- /dev/null
+++ b/kbabel/COPYING
@@ -0,0 +1,340 @@
+ GNU GENERAL PUBLIC LICENSE
+ Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+ 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users. This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it. (Some other Free Software Foundation software is covered by
+the GNU Library General Public License instead.) You can apply it to
+your programs, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+ To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have. You must make sure that they, too, receive or can get the
+source code. And you must show them these terms so they know their
+rights.
+
+ We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+ Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software. If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+ Finally, any free program is threatened constantly by software
+patents. We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary. To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ GNU GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License. The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language. (Hereinafter, translation is included without limitation in
+the term "modification".) Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+ 1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+ 2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) You must cause the modified files to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ b) You must cause any work that you distribute or publish, that in
+ whole or in part contains or is derived from the Program or any
+ part thereof, to be licensed as a whole at no charge to all third
+ parties under the terms of this License.
+
+ c) If the modified program normally reads commands interactively
+ when run, you must cause it, when started running for such
+ interactive use in the most ordinary way, to print or display an
+ announcement including an appropriate copyright notice and a
+ notice that there is no warranty (or else, saying that you provide
+ a warranty) and that users may redistribute the program under
+ these conditions, and telling the user how to view a copy of this
+ License. (Exception: if the Program itself is interactive but
+ does not normally print such an announcement, your work based on
+ the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+ a) Accompany it with the complete corresponding machine-readable
+ source code, which must be distributed under the terms of Sections
+ 1 and 2 above on a medium customarily used for software interchange; or,
+
+ b) Accompany it with a written offer, valid for at least three
+ years, to give any third party, for a charge no more than your
+ cost of physically performing source distribution, a complete
+ machine-readable copy of the corresponding source code, to be
+ distributed under the terms of Sections 1 and 2 above on a medium
+ customarily used for software interchange; or,
+
+ c) Accompany it with the information you received as to the offer
+ to distribute corresponding source code. (This alternative is
+ allowed only for noncommercial distribution and only if you
+ received the program in object code or executable form with such
+ an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it. For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable. However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License. Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+ 5. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Program or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+ 6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+ 7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all. For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+ 8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded. In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+ 9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time. Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation. If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+ 10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission. For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this. Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+ NO WARRANTY
+
+ 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+ 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+ END OF TERMS AND CONDITIONS
+
+ How to Apply These Terms to Your New Programs
+
+ If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+ To do so, attach the following notices to the program. It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the program's name and a brief idea of what it does.>
+ Copyright (C) <year> <name of author>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the 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, write to the Free Software
+ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+ Gnomovision version 69, Copyright (C) year name of author
+ Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+ This is free software, and you are welcome to redistribute it
+ under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License. Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary. Here is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+ `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+ <signature of Ty Coon>, 1 April 1989
+ Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs. If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library. If this is what you want to do, use the GNU Library General
+Public License instead of this License.
diff --git a/kbabel/ChangeLog b/kbabel/ChangeLog
new file mode 100644
index 00000000..c62d9c40
--- /dev/null
+++ b/kbabel/ChangeLog
@@ -0,0 +1,287 @@
+Changes 1.11.4 (KDE 3.5.4)
+ - Update reference to KBabel's web site (now http://kbabel.kde.org )
+
+Changes 1.11.2 (KDE 3.5.2)
+ - Improve loading of Gettext PO files, especially in the case of recoverable
+ or unrecoverable errors (bugs #117968, #120200, #121236).
+ - Make CVS/SVN dialogs of KBabel's catalog manager depend on projects.
+ - Improve sending PO file(s) as email.
+
+Changes 1.11.1 (KDE 3.5.1)
+- Avoid user-visible strings that need to be translated in two ways (bug #114151)
+- Fix and improve source references
+- Add a new variable @POFILEDIR@ for source references.
+ This is for allowing search paths starting at the directory of the PO file,
+ like what is needed for GNU projects: starting at the parent directory (bug #114041)
+- Allow backslashes in source references in the PO file (bug #116393)
+- Clicking the help button of KBabelDict calls the corresponding section in the KBabel documentation
+- Improved documentation (including bug #85885)
+
+Changes 1.11 (KDE 3.5):
+- Diff settings part of a project (Stanislav Visnovsky)
+- View for current list of errors (Albert Cervera Areny)
+- Datatool for generic regexp validation (Albert Cervera Areny)
+- Separated editor color settings to its own page (Stanislav Visnovsky)
+- Improve CVS support of catalog manager
+- Allow the user to select an encoding for CVS (bug #66605)
+- Add SVN support to catalog manager (bug #105805)
+- Support for Gettext context (keyword "msgctxt")
+- Improve Gettext plural support
+- Abort load of a PO file with CVS/SVN conflict markers in it (bug #108285)
+- Make optional the ; character before the "charset" of a Content-Type declaration in a PO file (bug #106733)
+- Make the catalog manager work with PO files having CR/LF line endings (bug #105399)
+- Fix remote saving of files (bug #106738)
+- Improve writing the header while saving a PO file (bugs #64413, #107782, #115275, #115276, #115295)
+
+Changes 1.10:
+- XLIFF support (Stanislav Visnovsky)
+- word count tool (Stanislav Visnovsky)
+- projects UI enhancements - recent projects, etc (Stanislav Visnovsky)
+- use KConfigXT for projects
+- Fixed bugs: #91989, #92537, #89710, #88293, #91900
+
+Changes 1.9:
+- project manager implemented (Stanislav Visnovsky)
+- support for cvs diff (Bram Schoenmakers)
+- support for detachable views (Stanislav Visnovsky)
+- it's possible to sort on marked items (Bram Schoenmakers)
+- only modified files get committed when doing cvs commit in a directory (Bram Schoenmakers)
+
+Changes 1.3:
+- Fixed bugs: #63603, #64413
+- allow to set "Plural-Forms" header (Stanislav Visnovsky)
+- dictionary plugin interface overhauled to include more information (e.g. plural forms, projects)
+ (Andrea Rizzi, Stanislav Visnovsky)
+- punctuation validation tool (Stanislav Visnovsky)
+
+Changes 1.2:
+- implemented rough translation using dictionary settings (Stanislav Visnovsky)
+- diff is shown correctly for word wrapped text (Stanislav Visnovsky)
+- GNU argument reordering is implemented, #48971 (Stanislav Visnovsky)
+- Fixed bugs: #62449, crash on open in a new window
+
+Changes 1.2beta3:
+- internal structures speedup (Stanislav Visnovsky)
+- do single word rough translation for all words, the last one was skipped (Stanislav Visnovsky)
+- when mailing files, store files relatively to the PO base dir (Marco Wegner)
+- word wrapping enabled, fix #53832 (elonen at iki.fi)
+- spellcheck from the current message to the end of file, wishlist #50937 (Marco Wegner)
+- mark/unmark files in catalog manager using wildcards, wishlist #48840 (Marco Wegner)
+- XML entities can contain dots (Stanislav Visnovsky)
+
+Changes 1.2beta2:
+- Next tag selection using Ctrl+/Ctrl-, wishlist #51641 (Stanislav Visnovsky)
+- Enable/disable columns in Catalog Manager, wishlist #52949 (Stanislav Visnovsky)
+- Dictionary modules can be temporarily reconfigured for rough translation (Stanislav Visnovsky)
+- On-the-fly spellchecking (Lukas Tinkl, Stanislav Visnovsky)
+- Validation errors in Catalog manager can be ignored for next validation (Stanislav Visnovsky)
+- Mark selection using regexps/wildcards (Marco Wegner)
+- Option to ignore %n in argument checks (Stanislav Visnovsky)
+- Diff mode to find difference against msgstr (Stanislav Visnovsky)
+- Better support for Translation Project robot, #57642 (Stanislav Visnovsky)
+- Fixed bugs: #53836, #58323, #57398
+
+Changes 1.2beta1:
+- GNU gettext plural forms (Stanislav Visnovsky)
+- Msgstr2plural - copy single text into a plural form (Stanislav Visnovsky)
+- Validation tools are plugins now - integration in Catalog Manager as well (Stanislav Visnovsky)
+- Non-breaking space is shown differently (Stanislav Visnovsky)
+- Import/export plugin framework to load/save files. (Stanislav Visnovsky)
+- Ported GNU gettext load/save to the new plugin framework (Stanislav Visnovsky)
+- It is not possible to edit raw header anymore (Stanislav Visnovsky)
+- Character selection tool (Stanislav Visnovsky)
+- CVS support in Catalog Manager (Marco Wegner)
+- KBabelDict module lookup using standard KDE KTrader
+- Autosave feature (Marco Wegner)
+- DataTool to check for translations with only whitespace (Dwayne Bailey)
+- DataTool for translations that are not translated (Dwayne Bailey)
+- DataTool to highlight translations that are too short or too long (Dwayne Bailey)
+
+Changes 1.1:
+- Bookmarks (c) Marco Wegner
+- Catalog Manager caching (c) Stefan Asserhall
+- Highlighting rewrite (c) Marco Wegner
+- Ressurection of Delete in Catalog Manager
+- Catalog Manager can toggle mark using mouse (click in the column)
+- Fix spellchecking for Maltese
+
+Changes 1.0:
+- Bug fixes
+- Mail files (both from KBabel and Catalog manager)
+
+Changes 1.0beta2:
+- Bug fixes
+- rough translation in catalog manager
+- Alt+123 feature to type a character by its code
+- perform all checks at once (KBabel)
+- KFile plugin (c) Marco Wegner <dubbleu@web.de>
+
+Changes 1.0beta1:
+- Bug fixes
+- Automatic update of PO header comment
+- Automatic update of Project-Id-Version
+- Possibility to specify localized translator name
+- Show source code
+- Args support similar to tags
+- Editing of tag regexps
+- Validation & highlighting of XML
+- Tag structure tool added
+- KDE specifics added to rough translation (e.g. only add a new translator in TRANSLATORS_...)
+- Mail PO-file
+- Save special (the settings can be changed for the particular save)
+- Concept of "package" visually introduced (used in source code tool, dictionaries, automatic updates of headers...)
+- Force update in Catalog Manager
+- Spellchecking in more files
+- Load/Save markings in Catalog Manager
+- Navigation bar in Catalog Manager
+
+Changes 0.9.6:
+- Stanislav Visnovsky is the new maintainer.
+- Port to KDE3/Qt3. This version cannot be compiled with older versions of the libraries.
+- Catalog Manager is standalone application now. This improves stability and performance.
+- Find/Replace in multiple files (Catalog Manager) + corresponding new functions in DCOP interface.
+- Fuzzy flag can be toggled now (not only unset)
+- Obsolete entries in PO files are not lost anymore
+- Timezone can be specified as offset (e.g. +0100)
+- Fixed validation of context info, equations
+- Fixed "slow KBabel" bug
+
+Changes 0.9.5:
+- Workaround for bug which caused a unfinite loop in dbsearchengine.
+
+Changes 0.9.4:
+- Check if requested charset exists, otherwise use locale encoding
+- Don't stop reading files when the encoding is faulty.
+
+Changes 0.9.3:
+- set charset for displaying characters according to the encoding
+ of the file.
+
+Changes 0.9.2:
+- rudimentary support for files with plural forms introduced by
+ gettext 0.10.36 was implemented.
+
+Changes 0.9.1:
+- added clever editing feature which makes editing more comfortable
+- some improvements in settings for the test of plural forms
+- quite a lot of spelling and grammar corrections in messages
+ (thanks to Malcolm Hunter)
+
+Changes 0.9:
+- added diff feature, which allows to diff with messages in the translation
+ database or in other po-files (thanks to Wolfram Diestel who implemented
+ the diff algorithm)
+- kbabel now prevents opening of the same file more than once
+- added possibility to open a file from a searchresult and directly
+ go to this msgid
+- added test for KDE specific plural forms in messages
+- added possibility to search in translations in KBabelDict modules
+- improved performance of file parser
+- small structure improvement in preferences dialog
+- new and improved toolbar icons and new icons for KBabel and KBabelDict
+- fixed storing of ignored words in spell check
+- some bug fixes
+
+Changes 0.8.1:
+- some bug fixes
+
+Changes 0.8:
+- A new plugin framework for dictionaries was implemented
+- Added a "rough translation" function, that uses the available dictionaries
+ for making suggestions for translations
+- Added support for tag handling
+- Support for wheelmice was added
+
+
+Changes 0.7.1:
+- A new options was added to allow saving files in the same encoding as they
+ were read in.
+- Copy now copies also from context view und searchresults.
+
+
+Changes 0.7:
+- A powerful spell checker was added
+- some smaller bugfixes
+
+Changes 0.6:
+- Added four methods for checking consistency of the messages:
+ - Check, that printf and Qt arguments are the same in msgid and msgstr
+ - Check, that keyboard accelerators exists in msgstr if there is one
+ in msgid
+ - Check, that context information for message (as used in KDE) is not
+ translated
+ - Check, that left side of a equation is the same in msgid and msgstr.
+ This is useful when editing KDE's desktop.po files
+- Some smaller improvements like adding keyboard shortcuts, etc.
+- Some bug fixes
+
+Changes 0.5.5:
+- Added another tool window for showing the context of an entry in the PO file
+
+Changes 0.5.4:
+- Catalogmanager now displays in icons, when files in a directory need
+ work. Also now the icons do not display missing templates, when no template
+ directory is given.
+- Major bugfix with the catalogmanager not updating files, when template
+ was deleted or added
+- Fixed the catalog manager crash, when no template directory was given.
+
+Changes 0.5.3:
+- added first version of documentation by Claudiu Costin
+- bugfixes and some cleanups
+
+Changes 0.5.2:
+- bugfixes
+
+Changes 0.5.1:
+- KBabel is now more liberate in parsing files.
+ Questionable entries are then accessible with go->next error
+- some bugfixes
+
+Changes 0.5:
+- undo/redo implemented
+- find & replace implemented
+- added function to copy msgid to msgstr
+- added function to copy searchresult to msgstr
+ (thanks to Hans Petter Bieker)
+- KBabel now uses the XML-GUI feature of KDE 2
+- many bug fixes and smaller enhancements
+- package now contains a little commandline tool "extractmsg" from Stephan Kulow
+ to extract translations from po-files
+
+Changes 0.4:
+- syntax highlighting
+- added several methods to see whitespace
+- configurable font for message editors
+- back and forward function
+- when saving, non existing directories are created
+- Catalog Manager now displays progress in reading file information
+- made led colors configurable
+- fixed bug with geometry managment in preferences dialog
+- some other bugfixes
+
+Changes 0.3.3:
+- configurable format of date and time in header
+- now using getExistingDirectory for choosing a directory
+- now using standard KDialogBase
+
+Changes 0.3.2:
+- made changes due to some api changes in kdelibs
+- partly fixed layout problem in the preferences dialog
+- fixed bug in commands editor for catalog manager
+
+Changes 0.3.1:
+- some bugfixes
+- added support for writing in utf8 and detecting used charet when reading
+
+Changes 0.3:
+- full featured catalog manager implemented
+- syntax checking with msgfmt implemented
+
+Changes 0.2:
+- searching in compendium and auxiliary implemented
+- some bugfixes
+- parsing of files rewritten
+- cleaner classes
+- added whatsthis help
+
diff --git a/kbabel/Makefile.am b/kbabel/Makefile.am
new file mode 100644
index 00000000..c38a56f3
--- /dev/null
+++ b/kbabel/Makefile.am
@@ -0,0 +1,8 @@
+AUTOMAKE_OPTIONS = foreign 1.4
+
+SUBDIRS = common filters datatools kbabeldict commonui catalogmanager kbabel addons
+
+messages: rc.cpp
+ $(EXTRACTRC) `find . -name \*.rc -o -name \*.ui` >> rc.cpp
+ $(XGETTEXT) `find . -name \*.cpp -o -name \*.cc` -o $(podir)/kbabel.pot
+
diff --git a/kbabel/README b/kbabel/README
new file mode 100644
index 00000000..34dc745f
--- /dev/null
+++ b/kbabel/README
@@ -0,0 +1,65 @@
+KBabel
+Matthias Kiefer <kiefer@kde.org>
+Stanislav Visnovsky <visnovsky@kde.org>
+----------------------------------------------------------------------
+
+KBabel is an advanced and easy to use editor for PO files.
+It is written using the KDE libs and gives the user an
+easy to use GUI.
+
+
+If you find a bug or if you have any comment or feature request,
+please send a mail to Stanislav Visnovsky <visnovsky@kde.org>.
+
+
+For always up-to-date information about KBabel have a look at its homepage at
+http://kbabel.kde.org
+The always newest version of KBabel can be found in module kdesdk in
+KDE's SVN.
+
+
+Requirements:
+- KDE 3.2/Qt 3.3 or higher
+- For the dictionary plugin "Translation database" you need
+ Berkeley DB IV. Have a look at http://www.sleepycat.com
+
+
+KBabel is published under the terms of the GNU GPL.
+See file "COPYING" for more details.
+
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the 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, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+
+
+Credits:
+- Claudiu Costin for writing documentation and many bug reports
+ and useful feature requests
+- Thomas Diehl for many useful hints to the GUI design and the
+ behaviour of KBabel
+- Wolfram Diestel for fixing kspell and many useful hints.
+- Stephan Kulow for helping keeping KBabel in sync with
+ the frequently changing KDE api and for often giving me a helping hand.
+- Andrea Rizzi for writing the dictionary plugin for searching in a database
+- Stefan Asserhall for implementing tag highlighting and validation, catalog manager caching
+- SuSE GmbH for sponsoring the work of Matthias Kiefer on KBabel
+- Marco Wegner <dubbleu@web.de> for KFile plugin, bookmarks and bug fixes
+- Dwayne Bailey <dwayne@translate.org.za> some validation plugins
+- all the others who spent their time sending bug reports and feature requests.
+
+
+Have fun,
+ Matthias Kiefer
+
diff --git a/kbabel/TODO b/kbabel/TODO
new file mode 100644
index 00000000..b98e6d1e
--- /dev/null
+++ b/kbabel/TODO
@@ -0,0 +1,22 @@
+- Bugs, bugs, bugs...
+- Context menu handling for comment view
+
+KBabel:
+- non-modal search and replace dialog
+- ignore newlines in search and replace
+- spellchecking in original messages
+- offer help with broken po files
+- Integration of external dictionaries
+- Network transparency for source files
+- diff for plural forms support
+- use DCOPsignals for file update
+
+KBabelDict:
+- In Po-auxiliary: make it easier to search in different language files
+
+Catalog manager:
+- more file managment functions
+- support for different structure of file trees (template <-> po files)
+- support for different file types (docbook)
+- graphical statistics
+- rewrite reading to use QTimer instead (should improve stability)
diff --git a/kbabel/VERSION b/kbabel/VERSION
new file mode 100644
index 00000000..3d0e6231
--- /dev/null
+++ b/kbabel/VERSION
@@ -0,0 +1 @@
+1.11.4
diff --git a/kbabel/addons/Makefile.am b/kbabel/addons/Makefile.am
new file mode 100644
index 00000000..291996f0
--- /dev/null
+++ b/kbabel/addons/Makefile.am
@@ -0,0 +1,3 @@
+AUTOMAKE_OPTIONS = foreign 1.4
+
+SUBDIRS = preview kfile-plugins
diff --git a/kbabel/addons/kfile-plugins/Makefile.am b/kbabel/addons/kfile-plugins/Makefile.am
new file mode 100644
index 00000000..fab776e0
--- /dev/null
+++ b/kbabel/addons/kfile-plugins/Makefile.am
@@ -0,0 +1,22 @@
+## Makefile.am for po file meta info plugin
+
+# set the include path for X, qt and KDE
+INCLUDES = -I$(srcdir)/../../common/ $(all_includes)
+
+# these are the headers for the project
+noinst_HEADERS = kfile_po.h
+
+kde_module_LTLIBRARIES = kfile_po.la
+
+kfile_po_la_SOURCES = kfile_po.cpp
+kfile_po_la_LDFLAGS = $(all_libraries) -module $(KDE_PLUGIN)
+kfile_po_la_LIBADD = ../../common/libkbabelcommon.la $(LIB_KIO)
+
+# let automoc handle all of the meta source files (moc)
+METASOURCES = AUTO
+
+messages: rc.cpp
+ $(XGETTEXT) kfile_po.cpp -o $(podir)/kfile_po.pot
+
+services_DATA = kfile_po.desktop
+servicesdir = $(kde_servicesdir)
diff --git a/kbabel/addons/kfile-plugins/kfile_po.cpp b/kbabel/addons/kfile-plugins/kfile_po.cpp
new file mode 100644
index 00000000..3b9b1a49
--- /dev/null
+++ b/kbabel/addons/kfile-plugins/kfile_po.cpp
@@ -0,0 +1,81 @@
+/*
+ * Copyright (C) 2002 Marco Wegner <mail@marcowegner.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 version 2.
+ *
+ * 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; see the file COPYING. If not, write to
+ * the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ In addition, as a special exception, the copyright holders give
+ permission to link the code of this program with any edition of
+ the Qt library by Trolltech AS, Norway (or with modified versions
+ of Qt that use the same license as Qt), and distribute linked
+ combinations including the two. You must obey the GNU General
+ Public License in all respects for all of the code used other than
+ Qt. If you modify this file, you may extend this exception to
+ your version of the file, but you are not obligated to do so. If
+ you do not wish to do so, delete this exception statement from
+ your version.
+ */
+
+
+#include "kfile_po.h"
+
+#include <qstringlist.h>
+
+#include "poinfo.h"
+#include <kgenericfactory.h>
+
+using namespace KBabel;
+
+typedef KGenericFactory<KPoPlugin> POFactory;
+K_EXPORT_COMPONENT_FACTORY(kfile_po, POFactory("kfile_po"))
+
+KPoPlugin::KPoPlugin(QObject *parent, const char *name,
+ const QStringList& args)
+ : KFilePlugin(parent, name, args)
+{
+ KFileMimeTypeInfo* info = addMimeTypeInfo("application/x-gettext");
+
+ KFileMimeTypeInfo::GroupInfo* group =
+ addGroupInfo(info, "CatalogInfo", i18n("Catalog Information"));
+
+ KFileMimeTypeInfo::ItemInfo* item;
+ item = addItemInfo(group, "Total", i18n("Total Messages"), QVariant::Int);
+ item = addItemInfo(group, "Fuzzy", i18n("Fuzzy Messages"), QVariant::Int);
+ item = addItemInfo(group, "Untranslated", i18n("Untranslated Messages"), QVariant::Int);
+ item = addItemInfo(group, "LastTranslator", i18n("Last Translator"), QVariant::String);
+ item = addItemInfo(group, "LanguageTeam", i18n("Language Team"), QVariant::String);
+ item = addItemInfo(group, "Revision", i18n("Revision"), QVariant::String);
+}
+
+bool KPoPlugin::readInfo(KFileMetaInfo& metaInfo, uint)
+{
+ PoInfo poInfo;
+ QStringList wordList;
+ ConversionStatus status = PoInfo::info(metaInfo.path(), poInfo, wordList, false, false, false);
+ if (status == OK) {
+ KFileMetaInfoGroup group = appendGroup(metaInfo, "CatalogInfo");
+
+ appendItem(group, "Total", poInfo.total);
+ appendItem(group, "Fuzzy", poInfo.fuzzy);
+ appendItem(group, "Untranslated", poInfo.untranslated);
+ appendItem(group, "LastTranslator", poInfo.lastTranslator);
+ appendItem(group, "LanguageTeam", poInfo.languageTeam);
+ appendItem(group, "Revision", poInfo.revision);
+
+ return true;
+ }
+ return false;
+}
+
+#include "kfile_po.moc"
diff --git a/kbabel/addons/kfile-plugins/kfile_po.desktop b/kbabel/addons/kfile-plugins/kfile_po.desktop
new file mode 100644
index 00000000..c1848a58
--- /dev/null
+++ b/kbabel/addons/kfile-plugins/kfile_po.desktop
@@ -0,0 +1,61 @@
+[Desktop Entry]
+Type=Service
+Name=Catalog Information
+Name[af]=Katalogus Informasie
+Name[bg]=Ð˜Ð½Ñ„Ð¾Ñ€Ð¼Ð°Ñ†Ð¸Ñ Ð·Ð° каталог
+Name[br]=Titouroù diwar-benn ar c'hatalog
+Name[bs]=Katalog informacije
+Name[ca]=Informació de catàleg
+Name[cs]=Informace o katalogu
+Name[cy]=Gwybodaeth Catalog
+Name[da]=Kataloginformation
+Name[de]=Katalog-Information
+Name[el]=ΠληÏοφοÏίες καταλόγου
+Name[en_GB]=Catalogue Information
+Name[eo]=Kataloginformoj
+Name[es]=Información de catálogo
+Name[et]=Kataloogi info
+Name[eu]=Katalogo informatizioa
+Name[fa]=اطلاعات Ùهرست
+Name[fi]=Käännöspaketin tiedot
+Name[fr]=Informations du catalogue
+Name[ga]=Eolas Catalóga
+Name[gl]=Información do Catálogo
+Name[he]=מידע קטלוג
+Name[hi]=केटलॉग जानकारी
+Name[hr]=Informacije o katalogu
+Name[hu]=Katalógusjellemzők
+Name[is]=Upplýsingar um þýðingaskrár
+Name[it]=Informazioni sul catalogo
+Name[ja]=カタログ情報
+Name[ka]=კáƒáƒ¢áƒáƒšáƒáƒ’ის ინფáƒáƒ áƒ›áƒáƒªáƒ˜áƒ
+Name[kk]=Каталог мәліметі
+Name[lt]=Katalogo informacija
+Name[ms]=Maklumat Katalog
+Name[nb]=Kataloginformasjon
+Name[nds]=Katalooginformatschoon
+Name[ne]=विवरणिका सूचना
+Name[nl]=Catalogusinformatie
+Name[nn]=Kataloginformasjon
+Name[pa]=ਸੂਚੀ ਜਾਣਕਾਰੀ
+Name[pl]=Informacje o tłumaczeniu
+Name[pt]=Informações do Catálogo
+Name[pt_BR]=Informação do Catálogo
+Name[ru]=Ð¡Ð²ÐµÐ´ÐµÐ½Ð¸Ñ Ð¾ файле Ñообщений
+Name[sk]=Informácie o katalógu
+Name[sl]=Informacije o katalogu
+Name[sr]=Информације о каталогу
+Name[sr@Latn]=Informacije o katalogu
+Name[sv]=Kataloginformation
+Name[ta]=விவரபà¯à®ªà®Ÿà¯à®Ÿà®¿ தகவலà¯
+Name[tg]=Маълумот дар бораи каталог
+Name[tr]=Katalog Bilgisi
+Name[uk]=Ð†Ð½Ñ„Ð¾Ñ€Ð¼Ð°Ñ†Ñ–Ñ ÐºÐ°Ñ‚Ð°Ð»Ð¾Ð³Ñƒ
+Name[xh]=Ulwazi Lwencwadi yemifanekiso
+Name[zh_CN]=目录信æ¯
+Name[zh_TW]=類別資訊
+ServiceTypes=KFilePlugin
+X-KDE-Library=kfile_po
+MimeType=application/x-gettext
+PreferredGroups=CatalogInfo
+PreferredItems=Total,Fuzzy,Untranslated,LastTranslator,LanguageTeam,Revision
diff --git a/kbabel/addons/kfile-plugins/kfile_po.h b/kbabel/addons/kfile-plugins/kfile_po.h
new file mode 100644
index 00000000..942a62dc
--- /dev/null
+++ b/kbabel/addons/kfile-plugins/kfile_po.h
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2002 Marco Wegner <mail@marcowegner.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 version 2.
+ *
+ * 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; see the file COPYING. If not, write to
+ * the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ In addition, as a special exception, the copyright holders give
+ permission to link the code of this program with any edition of
+ the Qt library by Trolltech AS, Norway (or with modified versions
+ of Qt that use the same license as Qt), and distribute linked
+ combinations including the two. You must obey the GNU General
+ Public License in all respects for all of the code used other than
+ Qt. If you modify this file, you may extend this exception to
+ your version of the file, but you are not obligated to do so. If
+ you do not wish to do so, delete this exception statement from
+ your version.
+
+ */
+
+
+#ifndef KFILE_PO_H
+#define KFILE_PO_H
+
+#include <kfilemetainfo.h>
+
+class QStringList;
+
+
+class KPoPlugin : public KFilePlugin
+{
+ Q_OBJECT
+
+ public:
+ KPoPlugin(QObject *parent, const char *name, const QStringList& args);
+ virtual bool readInfo(KFileMetaInfo& info, uint);
+};
+
+#endif // KFILE_PO_H
diff --git a/kbabel/addons/preview/Makefile.am b/kbabel/addons/preview/Makefile.am
new file mode 100644
index 00000000..28afdfbd
--- /dev/null
+++ b/kbabel/addons/preview/Makefile.am
@@ -0,0 +1,15 @@
+
+INCLUDES = -I$(srcdir)/../../common $(all_includes)
+METASOURCES = AUTO
+
+kde_module_LTLIBRARIES = pothumbnail.la
+
+pothumbnail_la_SOURCES = pothumbcreator.cpp
+pothumbnail_la_LIBADD = ../../common/libkbabelcommon.la
+pothumbnail_la_LDFLAGS = $(all_libraries) -module $(KDE_PLUGIN)
+
+noinst_HEADERS = pothumbcreator.h
+
+services_DATA = pothumbnail.desktop
+servicesdir = $(kde_servicesdir)
+
diff --git a/kbabel/addons/preview/pothumbcreator.cpp b/kbabel/addons/preview/pothumbcreator.cpp
new file mode 100644
index 00000000..f067948a
--- /dev/null
+++ b/kbabel/addons/preview/pothumbcreator.cpp
@@ -0,0 +1,360 @@
+/*
+ This file is part of KBabel
+ Copyright (C) 2001 Matthias Kiefer <kiefer@kde.org>
+
+ Text painting code is based on the text file preview textthumbnail by
+ Copyright (C) 2000 Carsten Pfeiffer <pfeiffer@kde.org>
+ 2000 Malte Starostik <malte@kde.org>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the 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, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+ In addition, as a special exception, the copyright holders give
+ permission to link the code of this program with any edition of
+ the Qt library by Trolltech AS, Norway (or with modified versions
+ of Qt that use the same license as Qt), and distribute linked
+ combinations including the two. You must obey the GNU General
+ Public License in all respects for all of the code used other than
+ Qt. If you modify this file, you may extend this exception to
+ your version of the file, but you are not obligated to do so. If
+ you do not wish to do so, delete this exception statement from
+ your version.
+
+*/
+
+#include <qpainter.h>
+#include <qpixmap.h>
+#include <qimage.h>
+
+#include <kapplication.h>
+#include <kglobal.h>
+#include <kiconloader.h>
+#include <kstandarddirs.h>
+#include <kpixmapsplitter.h>
+
+#include "pothumbcreator.h"
+#include "poinfo.h"
+
+using namespace KBabel;
+
+extern "C"
+{
+ KDE_EXPORT ThumbCreator *new_creator()
+ {
+ return new PoThumbCreator;
+ }
+}
+
+PoThumbCreator::PoThumbCreator()
+ : m_splitter(0)
+{
+}
+
+PoThumbCreator::~PoThumbCreator()
+{
+ if(m_splitter)
+ delete m_splitter;
+}
+
+bool PoThumbCreator::create(const QString &path, int width, int height, QImage &img)
+{
+ if ( !m_splitter )
+ {
+ m_splitter = new KPixmapSplitter;
+ QString pixmap = locate( "data", "konqueror/pics/thumbnailfont_7x4.png" );
+ if ( !pixmap.isEmpty() )
+ {
+ m_splitter->setPixmap( QPixmap( pixmap ));
+ m_splitter->setItemSize( QSize( 4, 7 ));
+ }
+ }
+
+ bool ok = false;
+ PoInfo poInfo;
+ QStringList wordList;
+
+ // We do not call msgfmt, as a thumbnail must be created fast.
+ if( PoInfo::info( path, poInfo, wordList, false, true, false ) == OK )
+ {
+ ok = true;
+
+ QPixmap pix;
+ if (height * 3 > width * 4)
+ pix.resize(width, width * 4 / 3);
+ else
+ pix.resize(height * 3 / 4, height);
+
+ pix.fill( QColor( 245, 245, 245 ) ); // light-grey background
+
+
+
+ // one pixel for the rectangle, the rest. whitespace
+ int xBorder = 1 + pix.width()/16; // minimum x-border
+ int yBorder = 1 + pix.height()/16; // minimum y-border
+
+ int circle = 16*360;
+ int fuzzyAngle = poInfo.fuzzy*circle/poInfo.total;
+ int untransAngle = poInfo.untranslated*circle/poInfo.total;
+
+ int w = pix.width()-2*xBorder;
+ int h = pix.height()*2/3-2*yBorder;
+
+ int d = QMIN(w,h);
+ xBorder = (pix.width()-d)/2;
+ yBorder = (pix.height()*2/3-d)/2;
+
+ QPainter p(&pix);
+
+ if(fuzzyAngle>0)
+ {
+ p.setBrush(Qt::blue);
+
+ if(poInfo.total == poInfo.fuzzy)
+ {
+ p.drawEllipse(xBorder,yBorder,d,d);
+ }
+ else
+ {
+ p.drawPie(xBorder,yBorder, d, d, 0, -fuzzyAngle);
+ }
+ }
+
+ if(untransAngle>0)
+ {
+ p.setBrush(Qt::red);
+
+ if(poInfo.untranslated == poInfo.total)
+ {
+ p.drawEllipse(xBorder,yBorder,d,d);
+ }
+ else
+ {
+ p.drawPie(xBorder,yBorder, d, d, -fuzzyAngle, -untransAngle);
+ }
+ }
+
+ if(circle - fuzzyAngle - untransAngle>0)
+ {
+ p.setBrush(Qt::darkGreen);
+
+ if(poInfo.fuzzy==0 && poInfo.untranslated==0)
+ {
+ p.drawEllipse(xBorder,yBorder,d,d);
+ }
+ else
+ {
+ p.drawPie(xBorder,yBorder, d, d, -fuzzyAngle-untransAngle
+ , -(circle-fuzzyAngle-untransAngle) );
+ }
+ }
+
+ p.end();
+
+
+
+ QRect rect;
+
+ QSize chSize = m_splitter->itemSize(); // the size of one char
+ int xOffset = chSize.width();
+ int yOffset = chSize.height();
+
+ // one pixel for the rectangle, the rest. whitespace
+ xBorder = 1 + pix.width()/16; // minimum x-border
+ yBorder = 1 + pix.height()/16; // minimum y-border
+
+ // calculate a better border so that the text is centered
+ int canvasWidth = pix.width() - 2*xBorder;
+ int canvasHeight = pix.height()/3 - 2*yBorder;
+ int numCharsPerLine = (int) (canvasWidth / chSize.width());
+ int numLines = (int) (canvasHeight / chSize.height());
+
+ int rest = pix.width() - (numCharsPerLine * chSize.width());
+ xBorder = QMAX( xBorder, rest/2); // center horizontally
+ rest = pix.height()/3 - (numLines * chSize.height());
+ yBorder = QMAX( yBorder, rest/2); // center vertically
+ // end centering
+
+
+ QString text;
+
+ if(numCharsPerLine < 30)
+ {
+ if(!poInfo.revision.isEmpty())
+ text += poInfo.revision+'\n';
+ if(!poInfo.lastTranslator.isEmpty())
+ text += poInfo.lastTranslator+'\n';
+ if(!poInfo.languageTeam.isEmpty())
+ text += poInfo.languageTeam+'\n';
+ if(!poInfo.contentType.isEmpty())
+ text += poInfo.contentType+'\n';
+ if(!poInfo.creation.isEmpty())
+ text += poInfo.creation+'\n';
+ if(!poInfo.project.isEmpty())
+ text += poInfo.project+'\n';
+ if(!poInfo.mimeVersion.isEmpty())
+ text += "MIME-Version: "+poInfo.mimeVersion+'\n';
+ if(!poInfo.encoding.isEmpty())
+ text += poInfo.encoding+'\n';
+
+ int lines = text.contains('\n')+1;
+ if(lines < numLines)
+ {
+ text = poInfo.headerComment+'\n'+text;
+ if(!poInfo.others.isEmpty())
+ text += poInfo.others+'\n';
+ }
+
+ if(text.at(text.length()-1) == '\n')
+ text.truncate(text.length()-1);
+ }
+ else
+ {
+ if(!poInfo.headerComment.isEmpty())
+ text += poInfo.headerComment+'\n';
+ if(!poInfo.project.isEmpty())
+ text += "Project-Id-Version: "+poInfo.project+'\n';
+ if(!poInfo.creation.isEmpty())
+ text += "POT-Creation-Date: "+poInfo.creation+'\n';
+ if(!poInfo.revision.isEmpty())
+ text += "PO-Revision-Date: "+ poInfo.revision+'\n';
+ if(!poInfo.lastTranslator.isEmpty())
+ text += "Last-Translator: "+poInfo.lastTranslator+'\n';
+ if(!poInfo.languageTeam.isEmpty())
+ text += "Language-Team: "+poInfo.languageTeam+'\n';
+ if(!poInfo.contentType.isEmpty())
+ text += "Content-Type: "+poInfo.contentType+'\n';
+ if(!poInfo.mimeVersion.isEmpty())
+ text += "MIME-Version: "+poInfo.mimeVersion+'\n';
+ if(!poInfo.encoding.isEmpty())
+ text += "Content-Transfer-Encoding: "+poInfo.encoding+'\n';
+ if(!poInfo.others.isEmpty())
+ text += poInfo.others;
+
+
+ if(text.at(text.length()-1) == '\n')
+ text.truncate(text.length()-1);
+ }
+ /*
+ double p = ((double)(poInfo.total-poInfo.fuzzy-poInfo.untranslated))*100/poInfo.total;
+ text = locale->formatNumber(p,0)+'%';
+ */
+ // find the maximum string length to center the text
+ QStringList lineList=QStringList::split('\n',text);
+ uint max=0;
+ for( QStringList::Iterator it = lineList.begin(); it != lineList.end()
+ ; ++it )
+ {
+ if((*it).length() > max)
+ max = (*it).length();
+ }
+ rest = pix.width() - (max * chSize.width());
+ xBorder = QMAX( xBorder, rest/2); // center horizontally
+ rest = pix.height()/3 - (lineList.count() * chSize.height());
+ yBorder = QMAX( yBorder, rest/2); // center vertically
+
+ // where to paint the characters
+ int x = xBorder, y = pix.height()*2/3;
+ int posNewLine = pix.width() - (chSize.width() + xBorder);
+ int posLastLine = pix.height() - (chSize.height() + yBorder);
+ bool newLine = false;
+ Q_ASSERT( posNewLine > 0 );
+ const QPixmap *fontPixmap = &(m_splitter->pixmap());
+
+
+ for ( uint i = 0; i < text.length(); i++ )
+ {
+ if ( x > posNewLine || newLine ) // start a new line?
+ {
+ x = xBorder;
+ y += yOffset;
+
+ if ( y > posLastLine ) // more text than space
+ break;
+
+ // after starting a new line, we also jump to the next
+ // physical newline in the file if we don't come from one
+ if ( !newLine )
+ {
+ int pos = text.find( '\n', i );
+ if ( pos > (int) i )
+ i = pos +1;
+ }
+
+ newLine = false;
+ }
+
+ // check for newlines in the text (unix,dos)
+ QChar ch = text.at( i );
+ if ( ch == '\n' )
+ {
+ newLine = true;
+ continue;
+ }
+ else if ( ch == '\r' && text.at(i+1) == '\n' )
+ {
+ newLine = true;
+ i++; // skip the next character (\n) as well
+ continue;
+ }
+
+ rect = m_splitter->coordinates( ch );
+ if ( !rect.isEmpty() )
+ {
+ bitBlt( &pix, QPoint(x,y), fontPixmap, rect, Qt::CopyROP );
+ }
+
+ x += xOffset; // next character
+ }
+
+ // very very seldom a babelfish lives in po files and even
+ // in this seldom cases they are usually hidden ;-)
+ if(pix.width() > 40 && KApplication::random()%2000 == 0)
+ {
+ QPixmap kbabelPix;
+ if(pix.width() < 80)
+ {
+ kbabelPix = KGlobal::iconLoader()->loadIcon("kbabel"
+ ,KIcon::Small,16,KIcon::DefaultState,0,true);
+ }
+ else if(pix.width() < 150)
+ {
+ kbabelPix = KGlobal::iconLoader()->loadIcon("kbabel"
+ ,KIcon::Desktop,32,KIcon::DefaultState,0,true);
+ }
+ else
+ {
+ kbabelPix = KGlobal::iconLoader()->loadIcon("kbabel"
+ ,KIcon::Desktop,48,KIcon::DefaultState,0,true);
+ }
+
+ int x = pix.width()-kbabelPix.width()-4;
+ x = QMAX(x,0);
+ if(!kbabelPix.isNull())
+ {
+ bitBlt(&pix, QPoint(x,4), &kbabelPix, kbabelPix.rect()
+ , Qt::CopyROP);
+ }
+ }
+
+ img = pix.convertToImage();
+ }
+
+ return ok;
+}
+
+ThumbCreator::Flags PoThumbCreator::flags() const
+{
+ return (Flags)(DrawFrame);
+}
+
diff --git a/kbabel/addons/preview/pothumbcreator.h b/kbabel/addons/preview/pothumbcreator.h
new file mode 100644
index 00000000..401e9431
--- /dev/null
+++ b/kbabel/addons/preview/pothumbcreator.h
@@ -0,0 +1,54 @@
+/*
+ This file is part of KBabel
+ Copyright (C) 2001 Matthias Kiefer <kiefer@kde.org>
+
+ Text painting code is based on the text file preview textthumbnail by
+ Copyright (C) 2000 Carsten Pfeiffer <pfeiffer@kde.org>
+ 2000 Malte Starostik <malte@kde.org>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the 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, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+ In addition, as a special exception, the copyright holders give
+ permission to link the code of this program with any edition of
+ the Qt library by Trolltech AS, Norway (or with modified versions
+ of Qt that use the same license as Qt), and distribute linked
+ combinations including the two. You must obey the GNU General
+ Public License in all respects for all of the code used other than
+ Qt. If you modify this file, you may extend this exception to
+ your version of the file, but you are not obligated to do so. If
+ you do not wish to do so, delete this exception statement from
+ your version.
+
+*/
+#ifndef POTHUMBCREATOR_H
+#define POTHUMBCREATOR_H
+
+#include <kio/thumbcreator.h>
+
+class KPixmapSplitter;
+
+class PoThumbCreator : public ThumbCreator
+{
+public:
+ PoThumbCreator();
+ virtual ~PoThumbCreator();
+ virtual bool create(const QString &path, int width, int height, QImage &img);
+ virtual Flags flags() const;
+
+private:
+ KPixmapSplitter *m_splitter;
+};
+
+#endif
diff --git a/kbabel/addons/preview/pothumbnail.desktop b/kbabel/addons/preview/pothumbnail.desktop
new file mode 100644
index 00000000..2c15345b
--- /dev/null
+++ b/kbabel/addons/preview/pothumbnail.desktop
@@ -0,0 +1,68 @@
+[Desktop Entry]
+Type=Service
+Name=Message Catalogs
+Name[af]=Boodskap Katalogusse
+Name[az]=İsmarış Kataloqu
+Name[bg]=Каталози ÑÑŠÑ ÑъобщениÑ
+Name[br]=Katalogoù c'hemennadoù
+Name[bs]=Katalozi poruka
+Name[ca]=Catàlegs de missatges
+Name[cs]=Katalogy zpráv
+Name[cy]=Catalogau Negesau
+Name[da]=Beskedkataloger
+Name[de]=Nachrichtenkataloge
+Name[el]=Κατάλογοι μηνυμάτων
+Name[en_GB]=Message Catalogues
+Name[eo]=MesaÄkatalogoj
+Name[es]=Catálogos de mensajes
+Name[et]=Tõlkefailide kataloogid
+Name[eu]=Katalogo mezuak
+Name[fa]=Ùهرست پیامها
+Name[fi]=Käännöspaketit
+Name[fr]=Catalogues de messages
+Name[ga]=Catalóg teachtaireachtaí
+Name[gl]=Catálogos de Mensaxes
+Name[he]=קטלוגי הודעות
+Name[hi]=संदेश केटलॉग
+Name[hr]=Katalog poruka
+Name[hu]=Üzenetkatalógusok
+Name[is]=Þýðingaskrár
+Name[it]=Cataloghi di messaggi
+Name[ja]=メッセージカタログ
+Name[ka]=შეტყáƒáƒ‘ინებáƒáƒ—რკáƒáƒ¢áƒáƒšáƒáƒ’ი
+Name[kk]=Gettext жазулар каталогы
+Name[lt]=Pranešimų katalogai
+Name[lv]=Ziņojumu Katalogs
+Name[ms]=Mesej Katalog
+Name[mt]=Katalgu ta' Messaġġi
+Name[nb]=Meldingskataloger
+Name[nds]=Narichtenkatalogen
+Name[ne]=सनà¥à¤¦à¥‡à¤¶ विवरणिका
+Name[nl]=Gettext-catalogus
+Name[nn]=Meldingskatalogar
+Name[pa]=ਸà©à¨¨à©‡à¨¹à¨¾ ਸੂਚੀ
+Name[pl]=Katalog napisów
+Name[pt]=Catálogos de Mensagens
+Name[pt_BR]=Catálogo de mensagens
+Name[ro]=Cataloage de mesaje
+Name[ru]=Ð¡Ð¾Ð¾Ð±Ñ‰ÐµÐ½Ð¸Ñ Gettext
+Name[sk]=Katalógy správ
+Name[sl]=Katalogi s sporoÄili
+Name[sr]=Каталози порука
+Name[sr@Latn]=Katalozi poruka
+Name[sv]=Meddelandekataloger
+Name[ta]=செயà¯à®¤à®¿ விவரபà¯à®ªà®Ÿà¯à®Ÿà®¿
+Name[tg]=Каталоги хабарҳо
+Name[th]=à¹à¸„ตตาล็อà¸à¸‚้อความ
+Name[tr]=Mesaj Katalogları
+Name[uk]=Каталоги повідомлень
+Name[ven]=Khathalogo dza mulaedza
+Name[vi]=Mục lục các thông điệp
+Name[xh]=Umyalezo wemifanekiso esencwadini
+Name[zh_CN]=消æ¯ç›®å½•
+Name[zh_TW]=訊æ¯é¡žåˆ¥
+Name[zu]=Umyalezo Wemifanekiso esencwadini
+ServiceTypes=ThumbCreator
+MimeTypes=application/x-gettext
+X-KDE-Library=pothumbnail
+CacheThumbnail=false
diff --git a/kbabel/catalogmanager/Makefile.am b/kbabel/catalogmanager/Makefile.am
new file mode 100644
index 00000000..2d8d1836
--- /dev/null
+++ b/kbabel/catalogmanager/Makefile.am
@@ -0,0 +1,64 @@
+## Makefile.am for KBabel catalogmanager
+
+# this has all of the subdirectories that make will recurse into. If
+# there are none, comment this out
+SUBDIRS = libcvs libsvn icons
+
+# this is the program that gets installed. Its name is used for all
+# of the other Makefile.am variables
+noinst_LTLIBRARIES = libcatalogmanager.la
+bin_PROGRAMS = catalogmanager
+
+# set the include path for X, qt and KDE. Let $(all_includes) be always last.
+INCLUDES = -I$(srcdir)/../common -I../common -I$(srcdir)/../kbabeldict \
+-I$(srcdir)/../commonui -I../commonui -I./libsvn -I./libcvs \
+-I$(srcdir)/libsvn -I$(srcdir)/libcvs $(all_includes)
+
+
+# which sources should be compiled for kbabel
+libcatalogmanager_la_SOURCES = catalogmanageriface.skel \
+ validationoptions.ui \
+ catalogmanagerview.cpp \
+ catalogmanager.cpp findinfilesdialog.cpp \
+ catmanlistitem.cpp multiroughtransdlg.cpp validateprogresswidget.ui \
+ validateprogress.cpp markpatternwidget.ui markpatterndialog.cpp
+
+
+libcatalogmanager_la_LIBADD = ../commonui/libkbabelcommonui.la \
+../kbabeldict/libkbabeldict.la ./libcvs/libcatalogmanagercvs.la \
+./libsvn/libcatalogmanagersvn.la $(LIB_KIO)
+libcatalogmanager_la_LDFLAGS = $(all_libraries) -no-undefined
+
+
+catalogmanager_SOURCES = main.cpp
+
+# the libraries to link against.
+catalogmanager_LDADD = libcatalogmanager.la
+catalogmanager_LDFLAGS = $(all_libraries) $(KDE_RPATH)
+
+# these are the headers for your project
+noinst_HEADERS = catalogmanageriface.h catalogmanager.h \
+ catalogmanagerview.h catalogmanagerapp.h findinfilesdialog.h \
+ catmanlistitem.h catmanresource.h multiroughtransdlg.h
+
+# let automoc handle all of the meta source files (moc)
+METASOURCES = AUTO
+
+rcdir = $(kde_datadir)/catalogmanager
+rc_DATA = catalogmanagerui.rc
+
+
+api:
+ mkdir -p API && kdoc -d API -u $$PWD/API -p -lkdeui -lkdecore -lqt -ldcop $(noinst_HEADERS)
+
+distclean-local:
+ rm -r -f API
+
+KDE_ICON = AUTO
+
+# this is where the kdelnk file will go
+xdg_apps_DATA = catalogmanager.desktop
+
+catalogmanager.lo: ../common/version.h
+main.o: ../common/version.h
+
diff --git a/kbabel/catalogmanager/catalogmanager.cpp b/kbabel/catalogmanager/catalogmanager.cpp
new file mode 100644
index 00000000..6cbe964d
--- /dev/null
+++ b/kbabel/catalogmanager/catalogmanager.cpp
@@ -0,0 +1,1371 @@
+/*****************************************************************************
+ This file is part of KBabel
+
+ Copyright (C) 1999-2000 by Matthias Kiefer
+ <matthias.kiefer@gmx.de>
+ 2001-2004 by Stanislav Visnovsky <visnovsky@kde.org>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the 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, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+ In addition, as a special exception, the copyright holders give
+ permission to link the code of this program with any edition of
+ the Qt library by Trolltech AS, Norway (or with modified versions
+ of Qt that use the same license as Qt), and distribute linked
+ combinations including the two. You must obey the GNU General
+ Public License in all respects for all of the code used other than
+ Qt. If you modify this file, you may extend this exception to
+ your version of the file, but you are not obligated to do so. If
+ you do not wish to do so, delete this exception statement from
+ your version.
+
+**************************************************************************** */
+
+#include "catmanresource.h"
+#include "catalogmanager.h"
+#include "catalog.h"
+#include "catalogmanagerapp.h"
+#include "findinfilesdialog.h"
+#include "kbabeldictbox.h"
+#include "resources.h"
+#include "projectpref.h"
+#include "kbprojectmanager.h"
+#include "projectwizard.h"
+#include "msgfmt.h"
+#include "toolaction.h"
+
+#include <qlabel.h>
+#include <qpainter.h>
+
+#include <dcopclient.h>
+#include <kapplication.h>
+#include <kaction.h>
+#include <kcmenumngr.h>
+#include <kconfig.h>
+#include <kcursor.h>
+#include <kdatatool.h>
+#include <kdialogbase.h>
+//#include <kedittoolbar.h>
+#include <kfiledialog.h>
+#include <kglobal.h>
+#include <kglobalsettings.h>
+#include <kiconloader.h>
+#include <kmessagebox.h>
+#include <klocale.h>
+#include <kpopupmenu.h>
+#include <kprogress.h>
+#include <kstdaccel.h>
+#include <kstdaction.h>
+#include <kstandarddirs.h>
+#include <kstatusbar.h>
+#include <ktoolbar.h>
+#include <kwin.h>
+
+#include <qfileinfo.h>
+#include <qdir.h>
+#include <qtimer.h>
+#include <qbitmap.h>
+#include <qwhatsthis.h>
+#include <qheader.h>
+#include <qdragobject.h>
+#include <qlayout.h>
+#include <qhbox.h>
+
+using namespace KBabel;
+
+WId CatalogManagerApp::_preferredWindow = 0;
+
+QStringList CatalogManager::_foundFilesList;
+QStringList CatalogManager::_toBeSearched;
+
+CatalogManager::CatalogManager(QString configFile )
+ :KMainWindow(0,0)
+{
+ if ( configFile.isEmpty() )
+ configFile = KBabel::ProjectManager::defaultProjectName();
+ _configFile = configFile;
+
+ init();
+ restoreSettings();
+ updateSettings();
+}
+
+CatalogManager::~CatalogManager()
+{
+ saveView();
+ saveSettings(_configFile);
+ delete config;
+}
+
+void CatalogManager::init()
+{
+ _foundToBeSent = 0;
+ _totalFound = 0;
+ _foundFilesList.clear();
+ _toBeSearched.clear();
+ _timerFind = new QTimer( this );
+ connect(_timerFind, SIGNAL( timeout() ), this, SLOT(findNextFile()) );
+ _searchStopped = false;
+
+ _prefDialog=0;
+ _findDialog=0;
+ _replaceDialog=0;
+
+ _project = KBabel::ProjectManager::open(_configFile);
+
+ if ( _project == NULL )
+ {
+ KMessageBox::error( this, i18n("Cannot open project file\n%1").arg(_configFile)
+ , i18n("Project File Error"));
+
+ _project = KBabel::ProjectManager::open(KBabel::ProjectManager::defaultProjectName());
+ }
+
+ connect( _project, SIGNAL (signalCatManSettingsChanged())
+ , this, SLOT (updateSettings()));
+
+ QWidget *view = new QWidget(this);
+ QVBoxLayout* layout= new QVBoxLayout(view);
+ layout->setMargin(0);
+ layout->setSpacing(KDialog::spacingHint());
+
+ _catalogManager=new CatalogManagerView(_project, view,"catalog manager");
+ layout->addWidget(_catalogManager);
+ layout->setStretchFactor(_catalogManager,1);
+
+ connect(this,SIGNAL(settingsChanged(KBabel::CatManSettings))
+ ,_catalogManager,SLOT(setSettings(KBabel::CatManSettings)));
+ connect(_catalogManager,SIGNAL(openFile(QString,QString))
+ ,this,SLOT(openFile(QString,QString)));
+ connect(_catalogManager,SIGNAL(openFileInNewWindow(QString,QString))
+ ,this,SLOT(openFileInNewWindow(QString,QString)));
+ connect(_catalogManager,SIGNAL(openTemplate(QString,QString,QString))
+ ,this,SLOT(openTemplate(QString,QString,QString)));
+ connect(_catalogManager,SIGNAL(openTemplateInNewWindow(QString,QString,QString))
+ ,this,SLOT(openTemplateInNewWindow(QString,QString,QString)));
+ connect(_catalogManager,SIGNAL(gotoFileEntry(QString,QString,int))
+ ,this,SLOT(openFile(QString,QString,int)));
+ connect(_catalogManager, SIGNAL(selectedChanged(uint)),
+ this, SLOT(selectedChanged(uint)));
+
+ KWin::setIcons(winId(),BarIcon("catalogmanager",32)
+ ,SmallIcon("catalogmanager"));
+
+ QHBoxLayout* hBoxL = new QHBoxLayout(layout);
+ _progressLabel = new QLabel(view);
+ hBoxL->addWidget(_progressLabel);
+ _progressBar=new KProgress(view);
+ hBoxL->addWidget(_progressBar);
+ hBoxL->setStretchFactor(_progressBar,1);
+
+ _progressLabel->hide();
+ _progressBar->hide();
+
+ connect(_catalogManager,SIGNAL(prepareProgressBar(QString,int))
+ , this, SLOT(prepareProgressBar(QString,int)));
+ connect(_catalogManager,SIGNAL(clearProgressBar())
+ , this, SLOT(clearProgressBar()));
+ connect(_catalogManager,SIGNAL(progress(int))
+ , _progressBar, SLOT(setProgress(int)));
+// connect(_catalogManager, SIGNAL(signalBuildTree(bool))
+// , this, SLOT(enableMenuForFiles(bool)));
+ connect(_catalogManager, SIGNAL(signalBuildTree(bool))
+ , this, SLOT(enableActions(bool)));
+ connect(this, SIGNAL(searchStopped())
+ , _catalogManager, SLOT(stopSearch()));
+ connect(_catalogManager, SIGNAL(prepareFindProgressBar(int))
+ , this, SLOT(prepareStatusProgressBar(int)));
+
+ setCentralWidget(view);
+ resize( 600,300);
+
+ setupStatusBar();
+ setupActions();
+
+
+ QPopupMenu* popup;
+ popup = (QPopupMenu*)(factory()->container("rmb_file", this));
+ if(popup)
+ {
+ _catalogManager->setRMBMenuFile(popup);
+ }
+ popup = (QPopupMenu*)(factory()->container("rmb_dir", this));
+ if(popup)
+ {
+ _catalogManager->setRMBMenuDir(popup);
+ }
+
+ connect(_catalogManager, SIGNAL(signalSearchedFile(int))
+ , _statusProgressBar, SLOT(advance(int)));
+
+ restoreView();
+}
+
+void CatalogManager::setupActions()
+{
+ KGlobal::iconLoader()->addAppDir("kbabel");
+
+ KAction *action;
+
+ // the file menu
+ action = new KAction( i18n("&Open"), CTRL+Key_O, _catalogManager,
+ SLOT(slotOpenFile()),actionCollection(), "open");
+ action->setEnabled(false);
+ action = new KAction(i18n("&Open Template"),Key_Space,_catalogManager,
+ SLOT(slotOpenTemplate()),actionCollection(), "open_template");
+ action->setEnabled(false);
+ action = new KAction(i18n("Open in &New Window"),CTRL+SHIFT+Key_O,_catalogManager,
+ SLOT(slotOpenFileInNewWindow()),actionCollection(), "open_new_window");
+ action->setEnabled(false);
+
+ action = KStdAction::quit(kapp, SLOT (closeAllWindows()), actionCollection());
+
+ actionMap["open_template"] = NEEDS_POT;
+
+ // the edit menu
+ action = new KAction( i18n("Fi&nd in Files..."), CTRL+Key_F, this,
+ SLOT(find()), actionCollection(), "find_in_files");
+ action->setEnabled(false);
+ action = new KAction( i18n("Re&place in Files..."), CTRL+Key_R, this,
+ SLOT(replace()), actionCollection(), "replace_in_files");
+ action->setEnabled(false);
+ action = new KAction( i18n("&Stop Searching"), "stop", Key_Escape, this,
+ SLOT(stopSearching()), actionCollection(), "stop_search");
+ action->setEnabled(false);
+ action = new KAction( i18n("&Reload"), "reload", KStdAccel::reload(), _catalogManager,
+ SLOT(updateCurrent()), actionCollection(), "reload");
+ action->setEnabled(false);
+
+ // the marking menu
+ action = new KAction( i18n("&Toggle Marking"), CTRL+Key_M, _catalogManager,
+ SLOT(toggleMark()), actionCollection(), "toggle_marking");
+ action->setEnabled(false);
+ action = new KAction( i18n("Remove Marking"), 0, _catalogManager,
+ SLOT(slotClearMarksInDir()), actionCollection(), "remove_marking");
+ action->setEnabled(false);
+ action = new KAction( i18n("Toggle All Markings"), 0, _catalogManager,
+ SLOT(toggleAllMarks()), actionCollection(), "toggle_all_marking");
+ action->setEnabled(false);
+ action = new KAction( i18n("Remove All Markings"), 0, _catalogManager,
+ SLOT(clearAllMarks()), actionCollection(), "remove_all_marking");
+ action->setEnabled(false);
+ action = new KAction( i18n("Mark Modified Files"), 0, _catalogManager,
+ SLOT(markModifiedFiles()), actionCollection(), "mark_modified_files");
+ // fixme to enabling this when loading is done using updateFinished() signal
+ action->setEnabled(true);
+ action = new KAction( i18n("&Load Markings..."), 0, _catalogManager,
+ SLOT(loadMarks()), actionCollection(), "load_marking");
+ action->setEnabled(false);
+ action = new KAction( i18n("&Save Markings..."), 0, _catalogManager,
+ SLOT(saveMarks()), actionCollection(), "save_marking");
+ action->setEnabled(false);
+ (void)new KAction(i18n("&Mark Files..."), 0, _catalogManager,
+ SLOT(slotMarkPattern()), actionCollection(), "mark_pattern");
+ (void)new KAction(i18n("&Unmark Files..."), 0, _catalogManager,
+ SLOT(slotUnmarkPattern()), actionCollection(), "unmark_pattern");
+
+ actionMap["remove_marking"] = NEEDS_MARK;
+ actionMap["remove_all_marking"] = NEEDS_MARK;
+ actionMap["mark_pattern"] = NEEDS_DIR;
+ actionMap["unmark_pattern"] = NEEDS_DIR | NEEDS_MARK;
+
+ // go menu
+ action = new KAction(i18n("Nex&t Untranslated"), "nextuntranslated", ALT+Key_Next,
+ _catalogManager, SLOT(gotoNextUntranslated()),actionCollection(), "go_next_untrans");
+ action->setEnabled(false);
+ action = new KAction(i18n("Prev&ious Untranslated"), "prevuntranslated", ALT+Key_Prior,
+ _catalogManager, SLOT(gotoPreviousUntranslated()),actionCollection(), "go_prev_untrans");
+ action->setEnabled(false);
+ action = new KAction(i18n("Ne&xt Fuzzy"), "nextfuzzy", CTRL+Key_Next,
+ _catalogManager, SLOT(gotoNextFuzzy()),actionCollection(), "go_next_fuzzy");
+ action->setEnabled(false);
+ action = new KAction(i18n("Pre&vious Fuzzy"), "prevfuzzy", CTRL+Key_Prior,
+ _catalogManager, SLOT(gotoPreviousFuzzy()),actionCollection(), "go_prev_fuzzy");
+ action->setEnabled(false);
+ action = new KAction(i18n("N&ext Fuzzy or Untranslated"), "nextfuzzyuntrans", CTRL+SHIFT+Key_Next,
+ _catalogManager, SLOT(gotoNextFuzzyOrUntranslated()),actionCollection(), "go_next_fuzzyUntr");
+ action->setEnabled(false);
+ action = new KAction(i18n("P&revious Fuzzy or Untranslated"), "prevfuzzyuntrans", CTRL+SHIFT+Key_Prior,
+ _catalogManager, SLOT(gotoPreviousFuzzyOrUntranslated()),actionCollection(), "go_prev_fuzzyUntr");
+ action->setEnabled(false);
+
+ action = new KAction(i18n("Next Err&or"), "nexterror", ALT+SHIFT+Key_Next,
+ _catalogManager, SLOT(gotoNextError()),actionCollection(), "go_next_error");
+ action->setEnabled(false);
+ action = new KAction(i18n("Previo&us Error"), "preverror", ALT+SHIFT+Key_Prior,
+ _catalogManager, SLOT(gotoPreviousError()),actionCollection(), "go_prev_error");
+ action->setEnabled(false);
+ action = new KAction(i18n("Next Te&mplate Only"), "nexttemplate", CTRL+Key_Down,
+ _catalogManager, SLOT(gotoNextTemplate()),actionCollection(), "go_next_template");
+ action->setEnabled(false);
+ action = new KAction(i18n("Previous Temp&late Only"), "prevtemplate", CTRL+Key_Up,
+ _catalogManager, SLOT(gotoPreviousTemplate()),actionCollection(), "go_prev_template");
+ action->setEnabled(false);
+ action = new KAction(i18n("Next Tran&slation Exists"), "nextpo", ALT+Key_Down,
+ _catalogManager, SLOT(gotoNextPo()),actionCollection(), "go_next_po");
+ action->setEnabled(false);
+ action = new KAction(i18n("Previous Transl&ation Exists"), "prevpo", ALT+Key_Up,
+ _catalogManager, SLOT(gotoPreviousPo()),actionCollection(), "go_prev_po");
+ action->setEnabled(false);
+
+ action = new KAction(i18n("Previous Marke&d"), "prevmarked", SHIFT+Key_Up,
+ _catalogManager, SLOT(gotoPreviousMarked()),actionCollection(), "go_prev_marked");
+ action->setEnabled(false);
+ action = new KAction(i18n("Next &Marked"), "nextmarked", SHIFT+Key_Down,
+ _catalogManager, SLOT(gotoNextMarked()),actionCollection(), "go_next_marked");
+ action->setEnabled(false);
+
+ // project menu
+ // the project menu
+ action = new KAction(i18n("&New..."), "filenew"
+ , this, SLOT(projectNew()),actionCollection()
+ ,"project_new");
+
+ action = new KAction(i18n("&Open..."), "fileopen"
+ , this, SLOT(projectOpen()),actionCollection()
+ ,"project_open");
+
+ action = new KAction(i18n("C&lose"), "fileclose"
+ , this, SLOT(projectClose()),actionCollection()
+ ,"project_close");
+
+ action->setEnabled (_project->filename() != KBabel::ProjectManager::defaultProjectName() );
+
+ action = new KAction(i18n("&Configure..."), "configure"
+ , this, SLOT(projectConfigure()),actionCollection()
+ ,"project_settings");
+
+ // tools menu
+ action = new KAction( i18n("&Statistics"), "statistics", CTRL+Key_S,
+ _catalogManager, SLOT(statistics()), actionCollection(), "statistics");
+ action->setEnabled(false);
+ action = new KAction( i18n("S&tatistics in Marked"), "statistics", CTRL+ALT+Key_S,
+ _catalogManager, SLOT(markedStatistics()), actionCollection(), "statistics_marked");
+ action->setEnabled(false);
+ action = new KAction( i18n("Check S&yntax"), "syntax", CTRL+Key_Y,
+ _catalogManager, SLOT(checkSyntax()), actionCollection(), "syntax");
+ action->setEnabled(false);
+ action = new KAction( i18n("S&pell Check"), "spellcheck", CTRL+Key_I,
+ this, SLOT(spellcheck()), actionCollection(), "spellcheck");
+ action->setEnabled(false);
+ action = new KAction( i18n("Spell Check in &Marked"), "spellcheck", CTRL+ALT+Key_I,
+ this, SLOT(markedSpellcheck()), actionCollection(), "spellcheck_marked");
+ action->setEnabled(false);
+ action = new KAction( i18n("&Rough Translation"), CTRL+Key_T,
+ _catalogManager, SLOT(roughTranslation()), actionCollection(), "rough_translation");
+ action->setEnabled(false);
+ action = new KAction( i18n("Rough Translation in M&arked"), CTRL+ALT+Key_T,
+ _catalogManager, SLOT(markedRoughTranslation()), actionCollection(), "rough_translation_marked");
+ action->setEnabled(false);
+ action = new KAction( i18n("Mai&l"), "mail_send", CTRL+Key_A,
+ _catalogManager, SLOT(mailFiles()), actionCollection(), "mail_file");
+ action->setEnabled(false);
+ action = new KAction( i18n("Mail Mar&ked"), "mail_send", CTRL+ALT+Key_A,
+ _catalogManager, SLOT(mailMarkedFiles()), actionCollection(), "mail_file_marked");
+ action->setEnabled(false);
+
+ action = new KAction( i18n("&Pack"), "tar", CTRL+Key_B,
+ _catalogManager, SLOT(packageFiles()), actionCollection(), "package_file");
+ action = new KAction( i18n("Pack &Marked"), "tar", CTRL+ALT+Key_B, _catalogManager, SLOT(packageMarkedFiles()), actionCollection(), "package_file_marked");
+ action->setEnabled(false);
+
+ actionMap["statistics_marked"] = NEEDS_DIR | NEEDS_MARK;
+ actionMap["syntax"] = NEEDS_PO;
+ actionMap["spellcheck"] = NEEDS_PO;
+ actionMap["spellcheck_marked"] = NEEDS_PO | NEEDS_MARK;
+ actionMap["rough_translation_marked"] = NEEDS_MARK;
+ actionMap["mail_file"] = NEEDS_PO;
+ actionMap["mail_file_marked"] = NEEDS_PO | NEEDS_MARK;
+ actionMap["package_file_marked"] = NEEDS_PO | NEEDS_MARK;
+
+ // dynamic tools
+ QValueList<KDataToolInfo> tools = ToolAction::validationTools();
+
+ QPtrList<KAction> actions = ToolAction::dataToolActionList(
+ tools, _catalogManager, SLOT(validateUsingTool( const KDataToolInfo &, const QString& ))
+ ,"validate", false, actionCollection() );
+
+ KActionMenu* m_menu = new KActionMenu(i18n("&Validation"), actionCollection(),
+ "dynamic_validation");
+
+ KAction*ac;
+
+ for(ac = actions.first(); ac ; ac = actions.next() )
+ {
+ m_menu->insert(ac);
+ }
+
+ actions = ToolAction::dataToolActionList(
+ tools, _catalogManager, SLOT(validateMarkedUsingTool( const KDataToolInfo &, const QString& ))
+ ,"validate", false, actionCollection(), "marked_" );
+ m_menu = new KActionMenu(i18n("V&alidation Marked"), actionCollection(),
+ "dynamic_validation_marked");
+
+ for( ac = actions.first(); ac ; ac = actions.next() )
+ {
+ m_menu->insert(ac);
+ }
+
+ actionMap["dynamic_validation"] = NEEDS_PO;
+ actionMap["dynamic_validation_marked"] = NEEDS_PO | NEEDS_MARK;
+
+ // CVS submenu
+ // Actions for PO files
+ (void)new KAction( i18n( "Update" ), "down", 0, _catalogManager,
+ SLOT( cvsUpdate( ) ), actionCollection( ), "cvs_update" );
+ (void)new KAction( i18n( "Update Marked" ), 0, _catalogManager,
+ SLOT( cvsUpdateMarked( ) ), actionCollection( ), "cvs_update_marked" );
+ (void)new KAction( i18n( "Commit" ), "up", 0, _catalogManager,
+ SLOT( cvsCommit( ) ), actionCollection( ), "cvs_commit" );
+ (void)new KAction( i18n( "Commit Marked" ), 0, _catalogManager,
+ SLOT( cvsCommitMarked( ) ), actionCollection( ), "cvs_commit_marked" );
+ (void)new KAction( i18n( "Status" ), 0, _catalogManager,
+ SLOT( cvsStatus( ) ), actionCollection( ), "cvs_status" );
+ (void)new KAction( i18n( "Status for Marked" ), 0, _catalogManager,
+ SLOT( cvsStatusMarked( ) ), actionCollection( ), "cvs_status_marked" );
+ (void)new KAction( i18n( "Show Diff" ), 0, _catalogManager,
+ SLOT( cvsDiff( ) ), actionCollection( ), "cvs_diff" );
+
+ // CVS
+ actionMap["cvs_update"] = NEEDS_PO | NEEDS_PO_CVS;
+ actionMap["cvs_update_marked"] = NEEDS_PO | NEEDS_PO_CVS | NEEDS_MARK;
+ actionMap["cvs_commit"] = NEEDS_PO | NEEDS_PO_CVS;
+ actionMap["cvs_commit_marked"] = NEEDS_PO | NEEDS_PO_CVS | NEEDS_MARK;
+ actionMap["cvs_status"] = NEEDS_PO | NEEDS_PO_CVS;
+ actionMap["cvs_status_marked"] = NEEDS_PO | NEEDS_PO_CVS | NEEDS_MARK;
+ actionMap["cvs_diff"] = NEEDS_PO | NEEDS_PO_CVS;
+
+ // SVN submenu
+ // Actions for PO files
+ (void)new KAction( i18n( "Update" ), "down", 0, _catalogManager,
+ SLOT( svnUpdate( ) ), actionCollection( ), "svn_update" );
+ (void)new KAction( i18n( "Update Marked" ), 0, _catalogManager,
+ SLOT( svnUpdateMarked( ) ), actionCollection( ), "svn_update_marked" );
+ (void)new KAction( i18n( "Commit" ), "up", 0, _catalogManager,
+ SLOT( svnCommit( ) ), actionCollection( ), "svn_commit" );
+ (void)new KAction( i18n( "Commit Marked" ), 0, _catalogManager,
+ SLOT( svnCommitMarked( ) ), actionCollection( ), "svn_commit_marked" );
+ (void)new KAction( i18n( "Status (Local)" ), 0, _catalogManager,
+ SLOT( svnStatusLocal() ), actionCollection( ), "svn_status_local" );
+ (void)new KAction( i18n( "Status (Local) for Marked" ), 0, _catalogManager,
+ SLOT( svnStatusLocalMarked() ), actionCollection( ), "svn_status_local_marked" );
+ (void)new KAction( i18n( "Status (Remote)" ), 0, _catalogManager,
+ SLOT( svnStatusRemote() ), actionCollection( ), "svn_status_remote" );
+ (void)new KAction( i18n( "Status (Remote) for Marked" ), 0, _catalogManager,
+ SLOT( svnStatusRemoteMarked() ), actionCollection( ), "svn_status_remote_marked" );
+ (void)new KAction( i18n( "Show Diff" ), 0, _catalogManager,
+ SLOT( svnDiff( ) ), actionCollection( ), "svn_diff" );
+ (void)new KAction( i18n( "Show Information" ), 0, _catalogManager,
+ SLOT( svnInfo() ), actionCollection( ), "svn_info" );
+ (void)new KAction( i18n( "Show Information for Marked" ), 0, _catalogManager,
+ SLOT( svnInfoMarked() ), actionCollection( ), "svn_info_marked" );
+
+ // SVN
+ actionMap["svn_update"] = NEEDS_PO | NEEDS_PO_SVN;
+ actionMap["svn_update_marked"] = NEEDS_PO | NEEDS_PO_SVN | NEEDS_MARK;
+ actionMap["svn_commit"] = NEEDS_PO | NEEDS_PO_SVN;
+ actionMap["svn_commit_marked"] = NEEDS_PO | NEEDS_PO_SVN | NEEDS_MARK;
+ actionMap["svn_status_local"] = NEEDS_PO | NEEDS_PO_SVN;
+ actionMap["svn_status_local_marked"] = NEEDS_PO | NEEDS_PO_SVN | NEEDS_MARK;
+ actionMap["svn_status_remote"] = NEEDS_PO | NEEDS_PO_SVN;
+ actionMap["svn_status_remote_marked"] = NEEDS_PO | NEEDS_PO_SVN | NEEDS_MARK;
+ actionMap["svn_diff"] = NEEDS_PO | NEEDS_PO_SVN;
+ actionMap["svn_info"] = NEEDS_PO | NEEDS_PO_SVN;
+ actionMap["svn_info_marked"] = NEEDS_PO | NEEDS_PO_SVN | NEEDS_MARK;
+
+ // CVS Actions for POT files
+ (void)new KAction( i18n( "Update Templates" ), 0, _catalogManager,
+ SLOT( cvsUpdateTemplate( ) ), actionCollection( ), "cvs_update_template" );
+ (void)new KAction( i18n( "Update Marked Templates" ), 0, _catalogManager,
+ SLOT( cvsUpdateMarkedTemplate( ) ), actionCollection( ), "cvs_update_marked_template" );
+ (void)new KAction( i18n( "Commit Templates" ), 0, _catalogManager,
+ SLOT( cvsCommitTemplate( ) ), actionCollection( ), "cvs_commit_template" );
+ (void)new KAction( i18n( "Commit Marked Templates" ), 0, _catalogManager,
+ SLOT( cvsCommitMarkedTemplate( ) ), actionCollection( ), "cvs_commit_marked_template" );
+
+ actionMap["cvs_update_template"] = NEEDS_POT | NEEDS_POT_CVS;
+ actionMap["cvs_update_marked_template"] = NEEDS_POT | NEEDS_POT_CVS | NEEDS_MARK;
+ actionMap["cvs_commit_template"] = NEEDS_POT | NEEDS_POT_CVS;
+ actionMap["cvs_commit_marked_template"] = NEEDS_POT | NEEDS_POT_CVS | NEEDS_MARK;
+
+ // SVN Actions for POT files
+ (void)new KAction( i18n( "Update Templates" ), 0, _catalogManager,
+ SLOT( svnUpdateTemplate( ) ), actionCollection( ), "svn_update_template" );
+ (void)new KAction( i18n( "Update Marked Templates" ), 0, _catalogManager,
+ SLOT( svnUpdateMarkedTemplate( ) ), actionCollection( ), "svn_update_marked_template" );
+ (void)new KAction( i18n( "Commit Templates" ), 0, _catalogManager,
+ SLOT( svnCommitTemplate( ) ), actionCollection( ), "svn_commit_template" );
+ (void)new KAction( i18n( "Commit Marked Templates" ), 0, _catalogManager,
+ SLOT( svnCommitMarkedTemplate( ) ), actionCollection( ), "svn_commit_marked_template" );
+
+ actionMap["svn_update_template"] = NEEDS_POT | NEEDS_POT_SVN;
+ actionMap["svn_update_marked_template"] = NEEDS_POT | NEEDS_POT_SVN | NEEDS_MARK;
+ actionMap["svn_commit_template"] = NEEDS_POT | NEEDS_POT_SVN;
+ actionMap["svn_commit_marked_template"] = NEEDS_POT | NEEDS_POT_SVN | NEEDS_MARK;
+
+ // settings menu
+ // FIXME: KStdAction::preferences(this, SLOT( optionsPreferences()), actionCollection());
+
+ createStandardStatusBarAction();
+
+ setStandardToolBarMenuEnabled ( true );
+
+ // commands menus
+ KActionMenu* actionMenu=new KActionMenu(i18n("Commands"), 0,
+ actionCollection(), "dir_commands");
+ _catalogManager->setDirCommandsMenu( actionMenu->popupMenu());
+
+ actionMenu=new KActionMenu(i18n("Commands"), 0,
+ actionCollection(), "file_commands");
+ _catalogManager->setFileCommandsMenu( actionMenu->popupMenu());
+
+ action = new KAction(i18n("&Delete"),Key_Delete,_catalogManager,SLOT(slotDeleteFile()),actionCollection(), "delete");
+ action->setEnabled(false);
+
+#if KDE_IS_VERSION( 3, 2, 90 )
+ setupGUI();
+#else
+ createGUI();
+#endif
+}
+
+void CatalogManager::setupStatusBar()
+{
+ _foundLabel = new QLabel( " ", statusBar());
+ statusBar()->addWidget(_foundLabel,0);
+
+ QHBox* progressBox = new QHBox(statusBar(), "progressBox" );
+ progressBox->setSpacing(2);
+ _statusProgressLabel = new QLabel( "", progressBox );
+ _statusProgressBar = new KProgress( progressBox, "progressBar");
+ _statusProgressBar->hide();
+
+ statusBar()->addWidget(progressBox,1);
+ statusBar()->setMinimumHeight(_statusProgressBar->sizeHint().height());
+
+ QWhatsThis::add(statusBar(),
+ i18n("<qt><p><b>Statusbar</b></p>\n"
+ "<p>The statusbar displays information about progress of"
+ " the current find or replace operation. The first number in <b>Found:</b>"
+ " displays the number of files with an occurrence of the searched text not"
+ " yet shown in the KBabel window. The second shows the total number of files"
+ " containing the searched text found so far.</p></qt>"));
+}
+
+void CatalogManager::enableMenuForFiles(bool enable)
+{
+ stateChanged( "treeBuilt", enable ? StateNoReverse: StateReverse );
+}
+
+void CatalogManager::selectedChanged(uint actionValue)
+{
+ QMap<QString,uint>::Iterator it;
+ for (it = actionMap.begin( ); it != actionMap.end( ); ++it) {
+ KAction * action = actionCollection()->action(it.key( ).latin1( ));
+ if (action) action->setEnabled((actionValue & it.data( )) == it.data( ));
+ }
+}
+
+CatManSettings CatalogManager::settings() const
+{
+ return _catalogManager->settings();
+}
+
+void CatalogManager::updateSettings()
+{
+ _settings = _project->catManSettings();
+ _catalogManager->setSettings(_settings);
+ _openNewWindow=_settings.openWindow;
+}
+
+void CatalogManager::saveSettings( QString configFile )
+{
+ _settings = _catalogManager->settings(); // restore settings from the view
+
+ _project->setSettings( _settings );
+
+ config = new KConfig(configFile);
+
+ _catalogManager->saveView(config);
+
+ config->sync();
+}
+
+void CatalogManager::restoreSettings()
+{
+ _settings = _project->catManSettings();
+ _openNewWindow=_settings.openWindow;
+ _catalogManager->restoreView(_project->config());
+}
+
+void CatalogManager::setPreferredWindow(WId window)
+{
+ _preferredWindow = window;
+ kdDebug(KBABEL_CATMAN) << "setPrefereedWindow set to :" << _preferredWindow << endl;
+}
+
+void CatalogManager::updateFile(QString fileWithPath)
+{
+ _catalogManager->updateFile(fileWithPath,true); //force update
+}
+
+void CatalogManager::updateAfterSave(QString fileWithPath, PoInfo &info)
+{
+ _catalogManager->updateAfterSave(fileWithPath, info);
+}
+
+CatalogManagerView *CatalogManager::view()
+{
+ return _catalogManager;
+}
+
+void CatalogManager::openFile(QString filename, QString package)
+{
+ DCOPClient * client = kapp->dcopClient();
+
+ if( startKBabel() )
+ {
+
+ QByteArray data;
+ QCString url = filename.local8Bit();
+ QDataStream arg(data, IO_WriteOnly);
+ arg << url;
+ arg << package.utf8();
+ arg << CatalogManagerApp::_preferredWindow;
+ arg << ( _openNewWindow ? 1 : 0 );
+
+ kdDebug(KBABEL_CATMAN) << "Open file with project " << _configFile << endl;
+
+ QCString callfunc="openURL(QCString, QCString, WId,int)";
+ if(_configFile != "kbabelrc" )
+ {
+ arg << _configFile.utf8();
+ callfunc="openURL(QCString, QCString, WId,int,QCString)";
+ }
+
+ kdDebug(KBABEL_CATMAN) << callfunc << endl;
+
+ // update the user timestamp for KBabel to get it a focus
+ kapp->updateRemoteUserTimestamp ("kbabel");
+
+ if( !client->send("kbabel","KBabelIFace", callfunc, data) )
+ KMessageBox::error(this, i18n("Cannot send a message to KBabel.\n"
+ "Please check your installation of KDE."));
+ }
+}
+
+void CatalogManager::openFile(QString filename, QString package, int msgid)
+{
+ DCOPClient * client = kapp->dcopClient();
+
+ if( startKBabel() )
+ {
+ QByteArray data;
+ QCString url = filename.local8Bit();
+ QDataStream arg(data, IO_WriteOnly);
+ arg << url;
+ arg << package.utf8();
+ arg << msgid;
+
+ kdDebug(KBABEL_CATMAN) << "Open file with project " << _configFile << endl;
+
+ QCString callfunc="gotoFileEntry(QCString, QCString, int)";
+ if(_configFile != "kbabelrc" )
+ {
+ arg << _configFile.utf8();
+ callfunc="gotoFileEntry(QCString, QCString,int,QCString)";
+ }
+
+ kdDebug(KBABEL_CATMAN) << callfunc << endl;
+
+ // update the user timestamp for KBabel to get it a focus
+ kapp->updateRemoteUserTimestamp ("kbabel");
+
+ if( !client->send("kbabel","KBabelIFace", callfunc, data) )
+ KMessageBox::error(this, i18n("Cannot send a message to KBabel.\n"
+ "Please check your installation of KDE."));
+ }
+}
+
+void CatalogManager::openFileInNewWindow(QString filename, QString package)
+{
+ DCOPClient * client = kapp->dcopClient();
+
+ if( startKBabel() )
+ {
+
+ QByteArray data;
+ QCString url = filename.local8Bit();
+ QDataStream arg(data, IO_WriteOnly);
+ arg << url;
+ arg << package.utf8();
+ arg << CatalogManagerApp::_preferredWindow;
+ arg << ((int)1);
+
+ QCString callfunc="openURL(QCString, QCString, WId,int)";
+ if(_configFile != "kbabelrc" )
+ {
+ arg << _configFile.utf8();
+ callfunc="openURL(QCString, QCString, WId,int,QCString)";
+ }
+
+ // update the user timestamp for KBabel to get it a focus
+ kapp->updateRemoteUserTimestamp ("kbabel");
+
+ if( !client->send("kbabel","KBabelIFace", callfunc, data) )
+ KMessageBox::error(this, i18n("Cannot send a message to KBabel.\n"
+ "Please check your installation of KDE."));
+ }
+}
+
+void CatalogManager::openTemplate(QString openFilename,QString saveFilename,QString package)
+{
+ DCOPClient * client = kapp->dcopClient();
+
+ if( startKBabel() ) {
+ QByteArray data;
+ QCString url = openFilename.local8Bit();
+ QDataStream arg(data, IO_WriteOnly);
+ arg << url;
+ url = saveFilename.utf8();
+ arg << url;
+ arg << package.utf8();
+ arg << (_openNewWindow ? 1 : 0 );
+
+ QCString callfunc="openTemplate(QCString,QCString,QCString,int)";
+ if(_configFile != "kbabelrc" )
+ {
+ arg << _configFile.utf8();
+ callfunc="openTemplate(QCString,QCString,QCString,int,QCString)";
+ }
+
+ // update the user timestamp for KBabel to get it a focus
+ kapp->updateRemoteUserTimestamp ("kbabel");
+
+ if( !client->send("kbabel","KBabelIFace", callfunc, data) )
+ KMessageBox::error(this, i18n("Cannot send a message to KBabel.\n"
+ "Please check your installation of KDE."));
+ }
+}
+
+void CatalogManager::openTemplateInNewWindow(QString openFilename,QString saveFilename,QString package)
+{
+ DCOPClient * client = kapp->dcopClient();
+
+ if( startKBabel() ) {
+ QByteArray data;
+ QCString url = openFilename.local8Bit();
+ QDataStream arg(data, IO_WriteOnly);
+ arg << url;
+ url = saveFilename.utf8();
+ arg << url;
+ arg << package.utf8();
+ arg << ((int)1);
+
+ QCString callfunc="openTemplate(QCString,QCString,QCString,int)";
+ if(_configFile != "kbabelrc" )
+ {
+ arg << _configFile.utf8();
+ callfunc="openTemplate(QCString,QCString,QCString,int,QCString)";
+ }
+
+ // update the user timestamp for KBabel to get it a focus
+ kapp->updateRemoteUserTimestamp ("kbabel");
+
+ if( !client->send("kbabel","KBabelIFace", callfunc, data) )
+ KMessageBox::error(this, i18n("Cannot send a message to KBabel.\n"
+ "Please check your installation of KDE."));
+ }
+}
+
+void CatalogManager::spellcheck()
+{
+ DCOPClient * client = kapp->dcopClient();
+
+ QStringList fileList = _catalogManager->current();
+
+ if( startKBabel() ) {
+ QByteArray data;
+ QDataStream arg(data, IO_WriteOnly);
+ arg << fileList;
+
+ // update the user timestamp for KBabel to get it a focus
+ kapp->updateRemoteUserTimestamp ("kbabel");
+
+ if( !client->send("kbabel","KBabelIFace", "spellcheck(QStringList)", data) )
+ KMessageBox::error(this, i18n("Cannot send a message to KBabel.\n"
+ "Please check your installation of KDE."));
+ }
+}
+
+void CatalogManager::markedSpellcheck()
+{
+ DCOPClient * client = kapp->dcopClient();
+
+ QStringList fileList = _catalogManager->marked();
+
+ if( startKBabel() ) {
+ QByteArray data;
+ QDataStream arg(data, IO_WriteOnly);
+ arg << fileList;
+
+ // update the user timestamp for KBabel to get it a focus
+ kapp->updateRemoteUserTimestamp ("kbabel");
+
+ if( !client->send("kbabel","KBabelIFace", "spellcheck(QStringList)", data) )
+ KMessageBox::error(this, i18n("Cannot send a message to KBabel.\n"
+ "Please check your installation of KDE."));
+ }
+}
+
+bool CatalogManager::startKBabel()
+{
+ QCString service;
+ QString result;
+
+ DCOPClient * client = kapp->dcopClient();
+
+ // find out, if there is a running kbabel
+ QCStringList apps = client->registeredApplications();
+ for( QCStringList::Iterator it = apps.begin() ; it != apps.end() ; ++it )
+ {
+ QString clientID = *it;
+ if( clientID=="kbabel" )
+ {
+ service = *it;
+ break;
+ }
+ }
+
+ // if there is no running kbabel, start one
+ if( service.isEmpty() )
+ {
+ QString app = "kbabel";
+ QString url = "";
+ if( kapp->startServiceByDesktopName(app,url, &result, &service))
+ {
+ KMessageBox::error( this, i18n("Unable to use KLauncher to start KBabel.\n"
+ "You should check the installation of KDE.\n"
+ "Please start KBabel manually."));
+ return false;
+ } else sleep(1);
+ }
+
+ return true;
+}
+
+
+void CatalogManager::prepareProgressBar(QString msg, int max)
+{
+ _progressBar->setTotalSteps(max);
+ _progressBar->setProgress(0);
+ _progressLabel->setText(msg);
+
+ _progressBar->show();
+ _progressLabel->show();
+}
+
+void CatalogManager::clearProgressBar()
+{
+ _progressBar->setProgress(0);
+
+ _progressBar->hide();
+ _progressLabel->hide();
+}
+
+void CatalogManager::prepareStatusProgressBar(QString msg, int max)
+{
+ _totalFound = 0;
+ _foundToBeSent = 0;
+ _statusProgressBar->setTotalSteps(max);
+ _statusProgressLabel->setText(msg);
+ _foundLabel->setText( i18n("Found: 0/0") );
+
+ _statusProgressBar->show();
+ _statusProgressLabel->show();
+}
+
+void CatalogManager::prepareStatusProgressBar(int max)
+{
+ _statusProgressBar->setTotalSteps(max);
+}
+
+void CatalogManager::clearStatusProgressBar()
+{
+ _statusProgressBar->setValue(0);
+
+ _statusProgressBar->hide();
+ _statusProgressLabel->hide();
+ _foundLabel->setText(" ");
+}
+
+void CatalogManager::setNumberOfFound(int toBeSent, int total)
+{
+ _foundLabel->setText(i18n("Found: %1/%2").arg(toBeSent).arg(total));
+}
+
+void CatalogManager::decreaseNumberOfFound()
+{
+ if( _foundToBeSent > 0 ) {
+ _foundToBeSent--;
+ setNumberOfFound( _foundToBeSent, _totalFound );
+ }
+}
+
+void CatalogManager::slotHelp()
+{
+ kapp->invokeHelp("CATALOGMANAGER","kbabel");
+}
+
+void CatalogManager::find()
+{
+ if( !_findDialog ) _findDialog = new FindInFilesDialog(false,this);
+
+ if( _findDialog->exec("") == QDialog::Accepted )
+ {
+ _timerFind->stop();
+ _searchStopped = false;
+ _catalogManager->stop(false); // surely we are not in process of quitting, since there is no window and user cannot invoke Find
+ prepareStatusProgressBar(i18n("Searching"),1); // just show the progress bar
+
+ // enable stop action to stop searching
+ KAction *action = (KAction*)actionCollection()->action("stop_search");
+ action->setEnabled(true);
+
+ _findOptions = _findDialog->findOpts();
+
+ // get from options the information for ignoring text parts
+ _findOptions.contextInfo = QRegExp( _project->miscSettings().contextInfo );
+ _findOptions.accelMarker = _project->miscSettings().accelMarker;
+
+ _foundFilesList.clear();
+ kdDebug(KBABEL_CATMAN) << "Calling catalogmanagerview::find" << endl;
+ QString url = _catalogManager->find(_findOptions, _toBeSearched );
+
+ if( _catalogManager->isStopped() ) return;
+ if( !url.isEmpty() )
+ {
+ if( startKBabel() )
+ {
+ QCString funcCall("findInFile(QCString,QCString,QString,int,int,int,int,int,int,int,int,int,int)");
+ DCOPClient *client = kapp->dcopClient();
+ QByteArray data;
+ QDataStream arg(data, IO_WriteOnly);
+ arg << client->appId();
+ arg << url.utf8();
+ arg << _findOptions.findStr;
+ arg << (_findOptions.caseSensitive ? 1 : 0);
+ arg << (_findOptions.wholeWords ? 1 : 0);
+ arg << (_findOptions.isRegExp ? 1 : 0);
+ arg << (_findOptions.inMsgid ? 1 : 0);
+ arg << (_findOptions.inMsgstr ? 1 : 0);
+ arg << (_findOptions.inComment ? 1 : 0);
+ arg << (_findOptions.ignoreAccelMarker ? 1 : 0);
+ arg << (_findOptions.ignoreContextInfo ? 1 : 0);
+ arg << (_findOptions.askForNextFile ? 1 : 0);
+ arg << (_findOptions.askForSave ? 1 : 0);
+ if(_configFile != "kbabelrc" ) {
+ arg << _configFile.utf8();
+ funcCall="findInFile(QCString,QCString,QString,int,int,int,int,int,int,int,int,int,int,QCString)";
+ }
+ kdDebug(KBABEL) << "DCOP: " << QString(data.data()) << endl;
+ if( !client->send("kbabel","KBabelIFace",
+ funcCall, data)
+ ) {
+ KMessageBox::error( this, i18n("DCOP communication with KBabel failed."), i18n("DCOP Communication Error"));
+ stopSearching();
+ return;
+ }
+
+ if( !_toBeSearched.isEmpty() )
+ {
+ _totalFound = 1;
+ _foundToBeSent = 0;
+ setNumberOfFound( 0, 1 ); // one found, but already sent
+ _timerFind->start(100,true);
+ } else stopSearching();
+ }
+ else
+ {
+ KMessageBox::error( this, i18n("KBabel cannot be started."), i18n("Cannot Start KBabel"));
+ stopSearching();
+ }
+
+ }
+ else
+ {
+ if( !_searchStopped) KMessageBox::information(this, i18n("Search string not found!"));
+ stopSearching();
+ }
+ }
+}
+
+void CatalogManager::replace()
+{
+ if( !_replaceDialog ) _replaceDialog = new FindInFilesDialog(true,this);
+
+
+ if( _replaceDialog->exec("") == QDialog::Accepted )
+ {
+ _timerFind->stop();
+ _searchStopped = false;
+ _catalogManager->stop(false); // surely we are not in process of quitting, since there is no window and user cannot invoke Find
+ prepareStatusProgressBar(i18n("Searching"),1); // just show the progress bar
+
+ // enable stop action to stop searching
+ KAction *action = (KAction*)actionCollection()->action("stop_search");
+ action->setEnabled(true);
+
+ ReplaceOptions options = _replaceDialog->replaceOpts();
+
+ _findOptions = options;
+
+ // get from options the information for ignoring text parts
+ options.contextInfo = QRegExp( _project->miscSettings().contextInfo );
+ options.accelMarker = _project->miscSettings().accelMarker;
+
+ _foundFilesList.clear();
+ QString url = _catalogManager->find(options, _toBeSearched );
+
+ if( _catalogManager->isStopped() ) return;
+ if( !url.isEmpty() )
+ {
+ if( startKBabel() )
+ {
+ QCString funcCall("replaceInFile(QCString,QCString,QString,QString,int,int,int,int,int,int,int,int,int,int,int)");
+ DCOPClient *client = kapp->dcopClient();
+ QByteArray data;
+ QDataStream arg(data, IO_WriteOnly);
+
+ arg << client->appId();
+ arg << url.utf8();
+ arg << options.findStr;
+ arg << options.replaceStr;
+ arg << (options.caseSensitive ? 1 : 0);
+ arg << (options.wholeWords ? 1 : 0);
+ arg << (options.isRegExp ? 1 : 0);
+ arg << (options.inMsgid ? 1 : 0);
+ arg << (options.inMsgstr ? 1 : 0);
+ arg << (options.inComment ? 1 : 0);
+ arg << (options.ignoreAccelMarker ? 1 : 0);
+ arg << (options.ignoreContextInfo ? 1 : 0);
+ arg << (options.ask ? 1 : 0);
+ arg << (options.askForNextFile ? 1 : 0);
+ arg << (options.askForSave ? 1 : 0);
+ if(_configFile != "kbabelrc" ) {
+ arg << _configFile.utf8();
+ funcCall="replaceInFile(QCString,QCString,QString,QString,int,int,int,int,int,int,int,int,int,int,int,QCString)";
+ }
+ if( !client->send("kbabel","KBabelIFace",
+ funcCall, data)
+ ) {
+ KMessageBox::error( this, i18n("DCOP communication with KBabel failed."), i18n("DCOP Communication Error"));
+ stopSearching();
+ return;
+ }
+
+ if( !_toBeSearched.isEmpty() )
+ {
+ _totalFound = 1;
+ setNumberOfFound( 0, 1 );
+ _timerFind->start(100,true);
+ } else stopSearching();
+ }
+ else
+ {
+ KMessageBox::error( this, i18n("KBabel cannot be started."), i18n("Cannot Start KBabel"));
+ stopSearching(); // update window
+ }
+
+ }
+ else
+ {
+ if( !_searchStopped ) KMessageBox::information(this, i18n("Search string not found!"));
+ stopSearching(); // update window
+ }
+ }
+}
+
+void CatalogManager::findNextFile()
+{
+ _timerFind->stop(); // stop the timer for lookup time
+ if(_toBeSearched.empty() )
+ {
+ stopSearching();
+ return;
+ }
+ QString file = _toBeSearched.first();
+ _toBeSearched.pop_front();
+ if( PoInfo::findInFile( file, _findOptions ) )
+ {
+ _foundFilesList.append(file);
+ _totalFound++;
+ _foundToBeSent++;
+ setNumberOfFound(_foundToBeSent,_totalFound);
+ }
+ _statusProgressBar->advance(1);
+ if( !_toBeSearched.empty() )
+ _timerFind->start(100,true); // if there is more files to be searched, start the timer again
+ else
+ stopSearching();
+}
+
+void CatalogManager::stopSearching()
+{
+ _searchStopped = true;
+ emit searchStopped();
+ // clear the list of files to be searched
+ _toBeSearched.clear();
+
+ // fake that we are over (fake, because findNextFile can still be running for the last file
+ clearStatusProgressBar(); // clear the status bar, we are finished
+ // disable stop action as well
+ KAction *action = (KAction*)actionCollection()->action("stop_search");
+ action->setEnabled(false);
+}
+
+void CatalogManager::optionsPreferences()
+{
+ if(!_prefDialog)
+ {
+ _prefDialog = new KBabel::ProjectDialog(_project);
+ }
+
+ _prefDialog->exec();
+}
+
+void CatalogManager::newToolbarConfig()
+{
+ createGUI();
+ restoreView();
+}
+
+void CatalogManager::optionsShowStatusbar(bool on)
+{
+ if( on )
+ statusBar()->show();
+ else
+ statusBar()->hide();
+}
+
+bool CatalogManager::queryClose()
+{
+ _catalogManager->stop();
+ saveView();
+ saveSettings(_configFile);
+ return true;
+}
+
+void CatalogManager::saveView()
+{
+ saveMainWindowSettings( KGlobal::config(), "View");
+}
+
+
+void CatalogManager::restoreView()
+{
+ applyMainWindowSettings( KGlobal::config(), "View");
+
+ KToggleAction * toggle = (KToggleAction*)actionCollection()->
+ action(KStdAction::stdName(KStdAction::ShowStatusbar));
+ toggle->setChecked(!statusBar()->isHidden() );
+}
+
+
+void CatalogManager::projectNew()
+{
+ KBabel::Project::Ptr p = KBabel::ProjectWizard::newProject();
+ if( p )
+ {
+ disconnect( _project, SIGNAL (signalCatManSettingsChanged())
+ , this, SLOT (updateSettings()));
+ _project = p;
+ connect( _project, SIGNAL (signalCatManSettingsChanged())
+ , this, SLOT (updateSettings()));
+
+ _configFile = _project->filename();
+ restoreSettings();
+ updateSettings();
+ changeProjectActions(p->filename());
+ emit settingsChanged(_settings);
+ }
+}
+
+void CatalogManager::projectOpen()
+{
+ QString oldproject = _project->filename();
+ if( oldproject == KBabel::ProjectManager::defaultProjectName() )
+ {
+ oldproject = QString();
+ }
+ const QString file = KFileDialog::getOpenFileName(oldproject, QString::null, this);
+ if (file.isEmpty())
+ {
+ return;
+ }
+ KBabel::Project::Ptr p = KBabel::ProjectManager::open(file);
+ if( p )
+ {
+ disconnect( _project, SIGNAL (signalCatManSettingsChanged())
+ , this, SLOT (updateSettings()));
+ _project = p;
+ connect( _project, SIGNAL (signalCatManSettingsChanged())
+ , this, SLOT (updateSettings()));
+
+ _configFile = p->filename();
+ restoreSettings();
+ updateSettings();
+ changeProjectActions(file);
+ emit settingsChanged(_settings);
+
+ }
+ else
+ {
+ KMessageBox::error (this, i18n("Cannot open project file %1").arg(file));
+ }
+}
+
+void CatalogManager::projectClose()
+{
+ disconnect( _project, SIGNAL (signalCatManSettingsChanged())
+ , this, SLOT (updateSettings()));
+ _project = KBabel::ProjectManager::open(KBabel::ProjectManager::defaultProjectName());
+ connect( _project, SIGNAL (signalCatManSettingsChanged())
+ , this, SLOT (updateSettings()));
+ _configFile = _project->filename();
+ restoreSettings();
+ updateSettings();
+ changeProjectActions(KBabel::ProjectManager::defaultProjectName());
+ emit settingsChanged(_settings);
+}
+
+void CatalogManager::changeProjectActions(const QString& project)
+{
+ bool def = ( project == KBabel::ProjectManager::defaultProjectName() ) ;
+
+ KAction* saveAction=(KAction*)actionCollection()->action( "project_close" );
+ saveAction->setEnabled( ! def );
+}
+
+void CatalogManager::projectConfigure()
+{
+ KBabel::ProjectDialog* _projectDialog = new ProjectDialog(_project);
+
+ connect (_projectDialog, SIGNAL (settingsChanged())
+ , this, SLOT (updateSettings()));
+
+ // settings are updated via signals
+ _projectDialog->exec();
+
+ delete _projectDialog;
+}
+
+void CatalogManager::enableActions()
+{
+ enableActions(true);
+}
+
+void CatalogManager::disableActions()
+{
+ enableActions(false);
+}
+
+void CatalogManager::enableActions(bool enable)
+{
+ KAction* action;
+ // the file menu
+
+ action = (KAction*)actionCollection()->action( "open" );
+ action->setEnabled(enable);
+
+ action = (KAction*)actionCollection()->action( "open_new_window" );
+ action->setEnabled(enable);
+
+ action = (KAction*)actionCollection()->action( "find_in_files" );
+ action->setEnabled(enable);
+
+ action = (KAction*)actionCollection()->action( "replace_in_files" );
+ action->setEnabled(enable);
+
+ action = (KAction*)actionCollection()->action( "reload" );
+ action->setEnabled(enable);
+
+ action = (KAction*)actionCollection()->action( "toggle_marking" );
+ action->setEnabled(enable);
+
+ action = (KAction*)actionCollection()->action( "toggle_all_marking" );
+ action->setEnabled(enable);
+
+ action = (KAction*)actionCollection()->action( "mark_modified_files" );
+ action->setEnabled(enable);
+
+ action = (KAction*)actionCollection()->action( "load_marking" );
+ action->setEnabled(enable);
+
+ action = (KAction*)actionCollection()->action( "save_marking" );
+ action->setEnabled(enable);
+
+ action = (KAction*)actionCollection()->action( "go_next_untrans" );
+ action->setEnabled(enable);
+
+ action = (KAction*)actionCollection()->action( "go_prev_untrans" );
+ action->setEnabled(enable);
+
+ action = (KAction*)actionCollection()->action( "go_next_fuzzy" );
+ action->setEnabled(enable);
+
+ action = (KAction*)actionCollection()->action( "go_prev_fuzzy" );
+ action->setEnabled(enable);
+
+ action = (KAction*)actionCollection()->action( "go_next_fuzzyUntr" );
+ action->setEnabled(enable);
+
+ action = (KAction*)actionCollection()->action( "go_prev_fuzzyUntr" );
+ action->setEnabled(enable);
+
+ action = (KAction*)actionCollection()->action( "go_next_error" );
+ action->setEnabled(enable);
+
+ action = (KAction*)actionCollection()->action( "go_prev_error" );
+ action->setEnabled(enable);
+
+ action = (KAction*)actionCollection()->action( "go_next_template" );
+ action->setEnabled(enable);
+
+ action = (KAction*)actionCollection()->action( "go_prev_template" );
+ action->setEnabled(enable);
+
+ action = (KAction*)actionCollection()->action( "go_next_po" );
+ action->setEnabled(enable);
+
+ action = (KAction*)actionCollection()->action( "go_prev_po" );
+ action->setEnabled(enable);
+
+ action = (KAction*)actionCollection()->action( "go_next_marked" );
+ action->setEnabled(enable);
+
+ action = (KAction*)actionCollection()->action( "go_prev_marked" );
+ action->setEnabled(enable);
+
+ action = (KAction*)actionCollection()->action( "statistics" );
+ action->setEnabled(enable);
+
+ action = (KAction*)actionCollection()->action( "package_file" );
+ action->setEnabled(enable);
+
+ action = (KAction*)actionCollection()->action( "rough_translation" );
+ action->setEnabled(enable);
+}
+
+#include "catalogmanager.moc"
diff --git a/kbabel/catalogmanager/catalogmanager.desktop b/kbabel/catalogmanager/catalogmanager.desktop
new file mode 100644
index 00000000..3c470b1c
--- /dev/null
+++ b/kbabel/catalogmanager/catalogmanager.desktop
@@ -0,0 +1,98 @@
+[Desktop Entry]
+Name=KBabel Catalog Manager
+Name[bg]=Управление на каталога - KBabel
+Name[br]=Merour katalogoù KBabel
+Name[ca]=Gestor de catàlegs de KBabel
+Name[cs]=Správce katalogů
+Name[da]=KBabel kataloghåndtering
+Name[de]=KBabel-Katalogmanager
+Name[el]=ΔιαχειÏιστής καταλόγων του KBabel
+Name[en_GB]=KBabel Catalogue Manager
+Name[eo]=Babelo-katalogadministrilo
+Name[es]=Administrador de catálogos de KBabel
+Name[et]=Kataloogihaldur
+Name[eu]=KBabel katalogo kudeatzailea
+Name[fa]= مدیر Ùهرست KBabel
+Name[fi]=KBabel - käännöspakettien hallinta
+Name[fr]=Gestionnaire de catalogues de KBabel
+Name[ga]=KBabel - Bainisteoir na gCatalóg
+Name[gl]=Xestor de Catálogos de KBabel
+Name[he]=KBabel - מנהל הקטלוגי×
+Name[hu]=KBabel listakezelő
+Name[is]=KBabel Þýðingarstjóri
+Name[it]=Gestore dei cataloghi di KBabel
+Name[ja]=KBabel カタログマãƒãƒ¼ã‚¸ãƒ£
+Name[ka]=KBabel-ის კáƒáƒ¢áƒáƒšáƒáƒ’ის მმáƒáƒ áƒ—ველი
+Name[kk]=KBabel каталог менеджері
+Name[lt]=KBabel katalogo tvarkytuvÄ—
+Name[nb]=KBabel-katalogbehandler
+Name[nds]=KBabel-Kataloogpleger
+Name[ne]=केबà¥à¤¯à¤¾à¤¬à¤² विवरणिका पà¥à¤°à¤¬à¤¨à¥à¤§à¤•
+Name[nl]=KBabel catalogusbeheer
+Name[nn]=KBabel Kataloghandsamar
+Name[pa]=KBabel ਸੂਚੀ ਪà©à¨°à¨¬à©°à¨§à¨•
+Name[pl]=KBabel - Menedżer tłumaczeń
+Name[pt]=Gestor de Catálogos do KBabel
+Name[pt_BR]=Gerenciador de Catálogos do KBabel
+Name[ru]=Менеджер Ñообщений Gettext
+Name[sk]=KBabel - správca katalógov
+Name[sl]=Upravitelj katalogov KBabel
+Name[sr]=KBabel-ов Менаџер каталога
+Name[sr@Latn]=KBabel-ov Menadžer kataloga
+Name[sv]=Kbabel kataloghanterare
+Name[tr]=KBabel Katalog Yöneticisi
+Name[uk]=Менеджер каталогів KBabel
+Name[zh_CN]=KBabel 目录管ç†å™¨
+Name[zh_TW]=KBabel - 目錄管ç†å“¡
+GenericName=Translation Tool Catalog Manager
+GenericName[bg]=ИнÑтрумент за превод
+GenericName[ca]=Gestor de catàlegs de l'eina de traducció
+GenericName[cs]=Správce katalogů překladů
+GenericName[da]=Oversættelsesværktøjs kataloghåndtering
+GenericName[de]=Katalogmanager für Übersetzungsprogramm
+GenericName[el]=ΔιαχειÏιστής καταλόγων εÏγαλείου μετάφÏασης
+GenericName[en_GB]=Translation Tool Catalogue Manager
+GenericName[eo]=Katalogadministrilo por Tradukiloj
+GenericName[es]=Administrador de catálogos de la herramienta de traducción
+GenericName[et]=KBabel'i kataloogihaldur
+GenericName[eu]=Itzulpen tresnen katalogo kudeatzailea
+GenericName[fa]=مدیر Ùهرست ابزار ترجمه
+GenericName[fi]=Käännöstyökalun käännöspakettien hallinta
+GenericName[fr]=Gestionnaire de catalogues de traduction
+GenericName[ga]=Uirlis Aistriúcháin - Bainisteoir na gCatalóg
+GenericName[gl]=Xestor de Catálogos de Tradución
+GenericName[he]=מנהל ×”×§×˜×œ×•×’×™× ×©×œ כלי התרגו×
+GenericName[hu]=Fordítássegítő
+GenericName[is]=Þýðingarforrit - Þýðingarstjóri
+GenericName[it]=Gestore dei cataloghi di uno strumento di traduzione
+GenericName[ja]=翻訳ツール カタログマãƒãƒ¼ã‚¸ãƒ£
+GenericName[ka]=კáƒáƒ¢áƒáƒšáƒáƒ’ის მმáƒáƒ áƒ—ველის სáƒáƒ—áƒáƒ áƒ’მნი ხელსáƒáƒ¬áƒ§áƒ
+GenericName[kk]=Ðудару құралының Каталог менеджері
+GenericName[lt]=Vertimo įrankio katalogo tvarkytuvė
+GenericName[nb]=Verktøy for håndtering av oversettelseskataloger
+GenericName[nds]=Översettenwarktüüch-Kataloogpleger
+GenericName[ne]=अनà¥à¤¬à¤¾à¤¦ उपकरण विवरणिका पà¥à¤°à¤¬à¤¨à¥à¤§à¤•
+GenericName[nl]=Vertaalhulpmiddel catalogusbeheer
+GenericName[nn]=Verktøy for handtering av omsetjingskatalogar
+GenericName[pa]=ਅਨà©à¨µà¨¾à¨¦ ਸੰਦ ਲਈ ਸੂਚੀ ਪà©à¨°à¨¬à©°à¨§à¨•
+GenericName[pl]=Menedżer tłumaczeń
+GenericName[pt]=Gestor de Catálogos de Ferramenta de Tradução
+GenericName[pt_BR]=Gerenciador de Catálogo da Ferramenta de Tradução
+GenericName[ru]=Ð›Ð¾ÐºÐ°Ð»Ð¸Ð·Ð°Ñ†Ð¸Ñ Ð¿Ñ€Ð¸Ð»Ð¾Ð¶ÐµÐ½Ð¸Ð¹
+GenericName[sk]=Správca katalógov pre prekladací nástroj
+GenericName[sl]=Upravitelj katalogov orodja za prevajanje
+GenericName[sr]=Менаџер каталога преводилачких алата
+GenericName[sr@Latn]=Menadžer kataloga prevodilaÄkih alata
+GenericName[sv]=Översättningsverktyg kataloghanterare
+GenericName[tr]=Çeviri Aracı Katalog Yöneticisi
+GenericName[uk]=Менеджер каталогів заÑобу Ð´Ð»Ñ Ð¿ÐµÑ€ÐµÐºÐ»Ð°Ð´Ñ–Ð²
+GenericName[zh_CN]=翻译工具目录管ç†å™¨
+GenericName[zh_TW]=翻譯工具目錄管ç†å“¡
+Exec=catalogmanager %i %m -caption "%c" %U
+Icon=catalogmanager
+Type=Application
+DocPath=kbabel/index.html
+Terminal=false
+X-KDE-StartupNotify=true
+X-DCOP-ServiceType=Multi
+Categories=Qt;KDE;Development;Translation;
diff --git a/kbabel/catalogmanager/catalogmanager.h b/kbabel/catalogmanager/catalogmanager.h
new file mode 100644
index 00000000..67f871fa
--- /dev/null
+++ b/kbabel/catalogmanager/catalogmanager.h
@@ -0,0 +1,218 @@
+/* ****************************************************************************
+ This file is part of KBabel
+
+ Copyright (C) 1999-2000 by Matthias Kiefer
+ <matthias.kiefer@gmx.de>
+ 2001-2004 by Stanislav Visnovsky <visnovsky@kde.org>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the 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, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+ In addition, as a special exception, the copyright holders give
+ permission to link the code of this program with any edition of
+ the Qt library by Trolltech AS, Norway (or with modified versions
+ of Qt that use the same license as Qt), and distribute linked
+ combinations including the two. You must obey the GNU General
+ Public License in all respects for all of the code used other than
+ Qt. If you modify this file, you may extend this exception to
+ your version of the file, but you are not obligated to do so. If
+ you do not wish to do so, delete this exception statement from
+ your version.
+
+**************************************************************************** */
+#ifndef CATALOGMANAGER_H
+#define CATALOGMANAGER_H
+
+#include <qdict.h>
+#include <qlistview.h>
+#include <qdatetime.h>
+#include <qfileinfo.h>
+#include <qguardedptr.h>
+#include <qmap.h>
+
+#include <kdeversion.h>
+#include <kmainwindow.h>
+#include <kdirwatch.h>
+#include <kprocess.h>
+#include <qptrlist.h>
+
+#include "projectsettings.h"
+#include "kbproject.h"
+#include "catalog.h"
+#include "catalogmanagerview.h"
+
+class CatManListItem;
+class QPixmap;
+class QPopupMenu;
+class QTimer;
+class KProgress;
+class KAction;
+class KConfig;
+class FindInFilesDialog;
+
+namespace KBabel
+{
+ class PoInfo;
+ class ProjectDialog;
+}
+
+class CatalogManager : public KMainWindow
+{
+ Q_OBJECT
+public:
+ CatalogManager(QString configfile = QString() );
+ ~CatalogManager();
+
+ KBabel::CatManSettings settings() const;
+ /**
+ * Sets the window, in which the files should be opened.
+ * This is set by KBabel::openCatalogManager
+ */
+ void setPreferredWindow(WId id);
+
+ /** updates the file fileWithPath in the @ref CatalogManagerView */
+ void updateFile(QString fileWithPath);
+ void updateAfterSave(QString fileWithPath, KBabel::PoInfo &info);
+
+ CatalogManagerView *view();
+
+ void pause(bool flag) { if( _catalogManager ) _catalogManager->pause (flag); }
+
+ static QStringList _foundFilesList;
+ static QStringList _toBeSearched;
+
+public slots:
+ /** updates the settings from the project */
+ void updateSettings();
+ void enableMenuForFiles(bool enable);
+ void selectedChanged(uint actionValue);
+ virtual void slotHelp();
+
+ virtual void find();
+ virtual void replace();
+ virtual void stopSearching();
+ virtual void optionsPreferences();
+ virtual void optionsShowStatusbar(bool on);
+ virtual void dummySlot() {}
+
+ void projectNew();
+ void projectOpen();
+ void projectClose();
+ void projectConfigure();
+ void changeProjectActions(const QString& project);
+
+ virtual void clearProgressBar();
+ virtual void prepareProgressBar(QString msg, int max);
+
+ virtual void clearStatusProgressBar();
+ virtual void prepareStatusProgressBar(QString msg, int max);
+ virtual void prepareStatusProgressBar(int max);
+
+ virtual void setNumberOfFound( int toBeSent, int total );
+ virtual void decreaseNumberOfFound();
+
+protected slots:
+ virtual void findNextFile();
+ virtual bool queryClose();
+
+signals:
+ void settingsChanged(KBabel::CatManSettings);
+ void signalQuit();
+ void searchStopped();
+
+private:
+ void init();
+
+ void restoreView();
+ void saveView();
+
+ void saveSettings( QString configFile = QString::null );
+
+ void setupActions();
+ void setupStatusBar();
+
+ bool startKBabel();
+
+private slots:
+ /**
+ * calls @ref KBabel::open where as preferred windos _preferredWindow
+ * is used. If this is deleted meanwhile, the first window in
+ * @ref KMainWindow::memberList is used.
+ */
+ void openFile(QString filename,QString package);
+ void openFile(QString filename,QString package, int msgid);
+ void openFileInNewWindow(QString filename,QString package);
+ /**
+ * calls @ref KBabel::openTemplate where as preferred windos _preferredWindow
+ * is used. If this is deleted meanwhile, the first window in
+ * @ref KMainWindow::memberList is used.
+ */
+ void openTemplate(QString openFilename,QString saveFileName,QString package);
+ void openTemplateInNewWindow(QString openFilename,QString saveFileName,QString package);
+
+ void markedSpellcheck();
+ void spellcheck();
+
+ void newToolbarConfig();
+
+ /** updates views and _settings variable */
+ void restoreSettings();
+
+ void enableActions();
+ void disableActions();
+
+ void enableActions(bool enable);
+
+private:
+ CatalogManagerView* _catalogManager;
+
+ WId _preferredWindow;
+
+ bool _openNewWindow;
+
+ FindInFilesDialog* _findDialog;
+ FindInFilesDialog* _replaceDialog;
+ KBabel::ProjectDialog* _prefDialog;
+
+ /// update progress bar
+ KProgress* _progressBar;
+ QLabel* _progressLabel;
+
+ /// statusbar progress bar
+ KProgress* _statusProgressBar;
+ QLabel* _statusProgressLabel;
+ QLabel* _foundLabel;
+ int _foundToBeSent;
+ int _totalFound;
+
+ QTimer* _timerFind;
+ bool _searchStopped;
+
+ KBabel::CatManSettings _settings;
+ KBabel::MiscSettings _miscSettings;
+
+ /// options used in findNextFile
+ KBabel::FindOptions _findOptions;
+
+
+ /// project configuration file
+ QString _configFile;
+ KBabel::Project::Ptr _project;
+
+ KConfig* config;
+
+ QMap<QString,uint> actionMap;
+};
+
+#endif // CATALOGMANAGER_H
diff --git a/kbabel/catalogmanager/catalogmanagerapp.h b/kbabel/catalogmanager/catalogmanagerapp.h
new file mode 100644
index 00000000..e0762e5b
--- /dev/null
+++ b/kbabel/catalogmanager/catalogmanagerapp.h
@@ -0,0 +1,73 @@
+/* ****************************************************************************
+ This file is part of KBabel
+
+ Copyright (C) 1999-2001 by Matthias Kiefer
+ <matthias.kiefer@gmx.de>
+ 2001 by Stanislav Visnovsky
+ <visnovsky@kde.org>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the 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, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+ In addition, as a special exception, the copyright holders give
+ permission to link the code of this program with any edition of
+ the Qt library by Trolltech AS, Norway (or with modified versions
+ of Qt that use the same license as Qt), and distribute linked
+ combinations including the two. You must obey the GNU General
+ Public License in all respects for all of the code used other than
+ Qt. If you modify this file, you may extend this exception to
+ your version of the file, but you are not obligated to do so. If
+ you do not wish to do so, delete this exception statement from
+ your version.
+
+**************************************************************************** */
+#ifndef CATALOGMANAGERAPP_H
+#define CATALOGMANAGERAPP_H
+
+#include "catalogmanager.h"
+#include "catalogmanageriface.h"
+
+#include "version.h"
+
+#include <kapplication.h>
+#include <kwin.h>
+
+class CatalogManagerInterface : public CatalogManagerIface
+{
+public:
+ CatalogManagerInterface();
+
+ virtual void setPreferredWindow( WId id );
+ virtual QCString findNextFile();
+ virtual void updatedFile( QCString url );
+};
+
+class CatalogManagerApp : public KApplication
+{
+public:
+ CatalogManagerApp();
+ virtual ~CatalogManagerApp();
+
+ virtual int newInstance();
+
+ static void setPreferredWindow( WId id );
+ static QCString findNextFile();
+ static void updatedFile( QCString url );
+ static WId _preferredWindow;
+private:
+ CatalogManagerInterface *kbInterface;
+ static CatalogManager * _view;
+};
+
+#endif
diff --git a/kbabel/catalogmanager/catalogmanageriface.h b/kbabel/catalogmanager/catalogmanageriface.h
new file mode 100644
index 00000000..232a694c
--- /dev/null
+++ b/kbabel/catalogmanager/catalogmanageriface.h
@@ -0,0 +1,67 @@
+/* ****************************************************************************
+ This file is part of KBabel
+
+ Copyright (C) 2001 by Stanislav Visnovsky <visnovsky@kde.org>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the 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, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+ In addition, as a special exception, the copyright holders give
+ permission to link the code of this program with any edition of
+ the Qt library by Trolltech AS, Norway (or with modified versions
+ of Qt that use the same license as Qt), and distribute linked
+ combinations including the two. You must obey the GNU General
+ Public License in all respects for all of the code used other than
+ Qt. If you modify this file, you may extend this exception to
+ your version of the file, but you are not obligated to do so. If
+ you do not wish to do so, delete this exception statement from
+ your version.
+
+**************************************************************************** */
+#ifndef CATALOGMANAGERIFACE_H
+#define CATALOGMANAGERIFACE_H
+
+#include <dcopobject.h>
+
+class CatalogManagerIface : virtual public DCOPObject
+{
+ K_DCOP
+public:
+
+k_dcop:
+
+ /**
+ * Sets the WId of the preferred window. The window will get
+ * calls to open files or templates when requested in catalog manager.
+ * @param id is the WId of the window to be used
+ */
+ virtual void setPreferredWindow( WId id ) { id = 0; }
+
+ /**
+ * Returns a next file containing the searched string. Invoked from
+ * KBabel in case the FindNext() finishes a file and wants to continue in
+ * the next one.
+ * @returns a URL to the next file, QString:null if there is no more
+ * files to be searched or empty string if the search string
+ * is not found yet, but there is more files to be searched in.
+ */
+ virtual QCString findNextFile() = 0;
+
+ /**
+ * If you care about this file, you should update information shown.
+ */
+ virtual void updatedFile( QCString url) = 0;
+};
+
+#endif // CATALOGMANAGERIFACE_H
diff --git a/kbabel/catalogmanager/catalogmanagerui.rc b/kbabel/catalogmanager/catalogmanagerui.rc
new file mode 100644
index 00000000..498a4bc7
--- /dev/null
+++ b/kbabel/catalogmanager/catalogmanagerui.rc
@@ -0,0 +1,262 @@
+<!DOCTYPE kpartgui>
+<kpartgui name="catalogmanager" version="26">
+ <MenuBar>
+ <Menu name="edit"><text>&amp;Edit</text>
+ <Action name="find_in_files"/>
+ <Action name="replace_in_files"/>
+ <Action name="stop_search"/>
+ <Separator/>
+ <Action name="reload"/>
+ </Menu>
+ <Menu name="go"><text>&amp;Go</text>
+ <Action name="go_next_fuzzyUntr"/>
+ <Action name="go_prev_fuzzyUntr"/>
+ <Action name="go_next_fuzzy"/>
+ <Action name="go_prev_fuzzy"/>
+ <Action name="go_next_untrans"/>
+ <Action name="go_prev_untrans"/>
+ <Separator/>
+ <Action name="go_next_error"/>
+ <Action name="go_prev_error"/>
+ <Separator/>
+ <Action name="go_next_marked"/>
+ <Action name="go_prev_marked"/>
+ <Separator/>
+ <Action name="go_next_template"/>
+ <Action name="go_prev_template"/>
+ <Action name="go_next_po"/>
+ <Action name="go_prev_po"/>
+ </Menu>
+ <Menu name="markings"><text>&amp;Markings</text>
+ <Action name="toggle_marking"/>
+ <Action name="remove_marking"/>
+ <Action name="toggle_all_marking"/>
+ <Action name="remove_all_marking"/>
+ <Action name="mark_modified_files"/>
+ <Separator/>
+ <Action name="mark_pattern"/>
+ <Action name="unmark_pattern"/>
+ <Separator/>
+ <Action name="load_marking"/>
+ <Action name="save_marking"/>
+ </Menu>
+ <Menu name="projects"><text>&amp;Project</text>
+ <Action name="project_new"/>
+ <Action name="project_open"/>
+ <Action name="project_close"/>
+ <Action name="project_settings"/>
+ </Menu>
+ <Menu name="tools"><text>&amp;Tools</text>
+ <Action name="statistics"/>
+ <Action name="statistics_marked"/>
+ <Action name="syntax"/>
+ <Separator/>
+ <Action name="spellcheck"/>
+ <Action name="spellcheck_marked"/>
+ <Separator/>
+ <Action name="rough_translation"/>
+ <Action name="rough_translation_marked"/>
+ <Separator/>
+ <Menu name="cvs_menu"><text>CVS</text>
+ <Action name="cvs_update"/>
+ <Action name="cvs_update_marked"/>
+ <Separator/>
+ <Action name="cvs_commit"/>
+ <Action name="cvs_commit_marked"/>
+ <Separator/>
+ <Action name="cvs_status"/>
+ <Action name="cvs_status_marked"/>
+ <Separator/>
+ <Action name="cvs_update_template"/>
+ <Action name="cvs_update_marked_template"/>
+ <Separator/>
+ <Action name="cvs_commit_template"/>
+ <Action name="cvs_commit_marked_template"/>
+ <Separator/>
+ <Action name="cvs_diff"/>
+ </Menu>
+ <Menu name="svn_menu"><text>SVN</text>
+ <Action name="svn_update"/>
+ <Action name="svn_update_marked"/>
+ <Separator/>
+ <Action name="svn_commit"/>
+ <Action name="svn_commit_marked"/>
+ <Separator/>
+ <Action name="svn_status_local"/>
+ <Action name="svn_status_local_marked"/>
+ <Separator/>
+ <Action name="svn_status_remote"/>
+ <Action name="svn_status_remote_marked"/>
+ <Separator/>
+ <Action name="svn_update_template"/>
+ <Action name="svn_update_marked_template"/>
+ <Separator/>
+ <Action name="svn_commit_template"/>
+ <Action name="svn_commit_marked_template"/>
+ <Separator/>
+ <Action name="svn_diff"/>
+ <Separator/>
+ <Action name="svn_info"/>
+ <Action name="svn_info_marked"/>
+ </Menu>
+ <Separator/>
+ <Action name="mail_file"/>
+ <Action name="mail_file_marked"/>
+ <Separaator/>
+ <Action name="package_file"/>
+ <Action name="package_file_marked"/>
+ <Separator/>
+ <Action name="dynamic_validation"/>
+ <Action name="dynamic_validation_marked"/>
+ </Menu>
+ <Menu name="settings"><text>&amp;Settings</text>
+ <Action name="settings_show_navbar" append="show_merge"/>
+ <Action name="settings_show_comments" append="show_merge"/>
+ <Action name="settings_show_tools" append="show_merge"/>
+ </Menu>
+ <Menu name="help"><text>&amp;Help</text>
+ <Action name="help_gettext"/>
+ <Action name="dict_about" append="about_merge"/>
+ </Menu>
+ </MenuBar>
+ <ToolBar name="mainToolBar"><text>Main</text>
+ <Action name="reload"/>
+ <Action name="statistics"/>
+ <Action name="syntax"/>
+ <Action name="stop_search"/>
+ </ToolBar>
+ <ToolBar name="navigationbar"><text>Navigationbar</text>
+ <Action name="go_prev_entry"/>
+ <Action name="go_next_entry"/>
+ <Separator/>
+ <Action name="go_first"/>
+ <Action name="go_last"/>
+ <Action name="go_prev_fuzzyUntr"/>
+ <Action name="go_next_fuzzyUntr"/>
+ <Action name="go_prev_fuzzy"/>
+ <Action name="go_next_fuzzy"/>
+ <Action name="go_prev_untrans"/>
+ <Action name="go_next_untrans"/>
+ <Separator/>
+ <Action name="go_prev_error"/>
+ <Action name="go_next_error"/>
+ <Separator/>
+ <Action name="go_prev_marked"/>
+ <Action name="go_next_marked"/>
+ <Separator/>
+ <Action name="go_prev_template"/>
+ <Action name="go_next_template"/>
+ <Action name="go_prev_po"/>
+ <Action name="go_next_po"/>
+ </ToolBar>
+ <Menu name="rmb_file">
+ <Action name="open"/>
+ <Action name="open_new_window"/>
+ <Action name="open_template"/>
+ <Action name="toggle_marking"/>
+ <Separator/>
+ <Action name="reload"/>
+ <Separator/>
+ <Action name="syntax"/>
+ <Action name="statistics"/>
+ <Action name="dynamic_validation"/>
+ <Action name="file_commands"/>
+ <Separator/>
+ <Menu name="rmb_file_cvs"><text>CVS</text>
+ <Action name="cvs_update"/>
+ <Action name="cvs_commit"/>
+ <Action name="cvs_status"/>
+ <Separator/>
+ <Action name="cvs_update_template"/>
+ <Action name="cvs_commit_template"/>
+ <Separator/>
+ <Action name="cvs_diff"/>
+ </Menu>
+ <Menu name="rmb_file_svn"><text>SVN</text>
+ <Action name="svn_update"/>
+ <Action name="svn_commit"/>
+ <Action name="svn_status_local"/>
+ <Action name="svn_status_remote"/>
+ <Separator/>
+ <Action name="svn_update_template"/>
+ <Action name="svn_commit_template"/>
+ <Separator/>
+ <Action name="svn_diff"/>
+ </Menu>
+ <Separator/>
+ <Action name="delete"/>
+ </Menu>
+ <Menu name="rmb_dir">
+ <Action name="toggle_marking"/>
+ <Action name="remove_marking"/>
+ <Action name="toggle_all_marking"/>
+ <Action name="remove_all_marking"/>
+ <Separator/>
+ <Action name="reload"/>
+ <Separator/>
+ <Action name="syntax"/>
+ <Action name="statistics"/>
+ <Action name="dynamic_validation"/>
+ <Action name="dir_commands"/>
+ <Separator/>
+ <Menu name="rmb_dir_cvs"><text>CVS</text>
+ <Action name="cvs_update"/>
+ <Action name="cvs_commit"/>
+ <Action name="cvs_status"/>
+ <Separator/>
+ <Action name="cvs_update_template"/>
+ <Action name="cvs_commit_template"/>
+ <Separator/>
+ <Action name="cvs_diff"/>
+ </Menu>
+ <Menu name="rmb_dir_svn"><text>SVN</text>
+ <Action name="svn_update"/>
+ <Action name="svn_commit"/>
+ <Action name="svn_status_local"/>
+ <Action name="svn_status_remote"/>
+ <Separator/>
+ <Action name="svn_update_template"/>
+ <Action name="svn_commit_template"/>
+ <Separator/>
+ <Action name="svn_diff"/>
+ </Menu>
+ </Menu>
+
+<State name="treeBuilt">
+ <Enable>
+ <Action name="open"/>
+ <Action name="open_new_window"/>
+ <Action name="find_in_files"/>
+ <Action name="replace_in_files"/>
+ <Action name="reload"/>
+
+ <Action name="go_next_fuzzyUntr"/>
+ <Action name="go_prev_fuzzyUntr"/>
+ <Action name="go_next_fuzzy"/>
+ <Action name="go_prev_fuzzy"/>
+ <Action name="go_next_untrans"/>
+ <Action name="go_prev_untrans"/>
+ <Action name="go_next_error"/>
+ <Action name="go_prev_error"/>
+ <Action name="go_next_marked"/>
+ <Action name="go_prev_marked"/>
+ <Action name="go_next_template"/>
+ <Action name="go_prev_template"/>
+ <Action name="go_next_po"/>
+ <Action name="go_prev_po"/>
+ <Action name="load_marking"/>
+ <Action name="save_marking"/>
+ <Action name="toggle_marking"/>
+ <Action name="toggle_all_marking"/>
+ <Action name="statistics"/>
+ <Action name="rough_translation"/>
+ <Action name="reload"/>
+ <Action name="dynamic_validation"/>
+ <Action name="dynamic_validation_marked"/>
+ <Action name="mail_file"/>
+ <Action name="mark_pattern"/>
+ <Action name="unmark_pattern"/>
+ </Enable>
+</State>
+
+</kpartgui>
diff --git a/kbabel/catalogmanager/catalogmanagerview.cpp b/kbabel/catalogmanager/catalogmanagerview.cpp
new file mode 100644
index 00000000..6bb4c88f
--- /dev/null
+++ b/kbabel/catalogmanager/catalogmanagerview.cpp
@@ -0,0 +1,3132 @@
+/* ****************************************************************************
+ This file is part of KBabel
+
+ Copyright (C) 1999-2000 by Matthias Kiefer
+ <matthias.kiefer@gmx.de>
+ 2001-2004 by Stanislav Visnovsky
+ <visnovsky@kde.org>
+ Copyright (C) 2005, 2006 by Nicolas GOUTTE <goutte@kde.org>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the 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, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+ In addition, as a special exception, the copyright holders give
+ permission to link the code of this program with any edition of
+ the Qt library by Trolltech AS, Norway (or with modified versions
+ of Qt that use the same license as Qt), and distribute linked
+ combinations including the two. You must obey the GNU General
+ Public License in all respects for all of the code used other than
+ Qt. If you modify this file, you may extend this exception to
+ your version of the file, but you are not obligated to do so. If
+ you do not wish to do so, delete this exception statement from
+ your version.
+
+**************************************************************************** */
+
+#include "catmanresource.h"
+#include "catalogmanager.h"
+#include "catmanlistitem.h"
+#include "catalog.h"
+#include "kbabeldictbox.h"
+
+#include "resources.h"
+#include "multiroughtransdlg.h"
+#include "msgfmt.h"
+#include "kbmailer.h"
+#include "validateprogress.h"
+#include "cvshandler.h"
+#include "svnhandler.h"
+#include "markpatterndialog.h"
+#include "validationoptions.h"
+
+#include <qcheckbox.h>
+#include <qpopupmenu.h>
+#include <qlabel.h>
+#include <qpainter.h>
+
+#include <kcmenumngr.h>
+#include <kcursor.h>
+#include <klocale.h>
+#include <kglobal.h>
+#include <kglobalsettings.h>
+#include <kconfig.h>
+#include <kdatatool.h>
+#include <kiconloader.h>
+#include <kmessagebox.h>
+#include <kapplication.h>
+#include <kaction.h>
+#include <kfiledialog.h>
+#include <kio/netaccess.h>
+#include <kprogress.h>
+#include <kwin.h>
+#include <kdeversion.h>
+#include <ktempfile.h>
+
+#include <qfileinfo.h>
+#include <qdir.h>
+#include <qtimer.h>
+#include <qbitmap.h>
+#include <qwhatsthis.h>
+#include <qheader.h>
+#include <qdragobject.h>
+#include <qlayout.h>
+#include <qtextedit.h>
+
+using namespace KBabel;
+
+const char* columnNames[] = {
+ I18N_NOOP("Name"),
+ I18N_NOOP("M"),
+ I18N_NOOP("Fuzzy"),
+ I18N_NOOP("Untranslated"),
+ I18N_NOOP("Total"),
+ I18N_NOOP("CVS/SVN Status"),
+ I18N_NOOP("Last Revision"),
+ I18N_NOOP("Last Translator")
+};
+
+#define COLTEXT(a) (i18n(columnNames[a]))
+
+CatalogManagerView::CatalogManagerView(KBabel::Project::Ptr project, QWidget* parent,const char* name)
+ : QListView(parent,name)
+ , _dirWatch(0)
+ , _readInfoCount(0)
+ , _active(false)
+ , _stop(false)
+ , _stopSearch(false)
+ , _updateNesting(0)
+ , _logView(0)
+ , _logWindow(0)
+ , m_validPOCVSRepository( false )
+ , m_validPOTCVSRepository( false )
+ , m_validPOSVNRepository( false )
+ , m_validPOTSVNRepository( false )
+ , markPatternDialog(0)
+ , _validateDialog(0)
+ , _validateOptions(0)
+ , _validateOptionsDlg(0)
+ , _markAsFuzzy(false)
+ , _ignoreFuzzy(false)
+ , _project(project)
+{
+ _dirList.resize(200);
+ _fileList.resize(500);
+ _readInfoFileList.clear();
+
+ _pendingProcesses.setAutoDelete(true);
+
+ setSelectionMode(Single);
+
+ _dictBox = new KBabelDictBox(this, "dictbox");
+ _dictBox->hide();
+
+ _updateTimer = new QTimer(this);
+ connect(_updateTimer,SIGNAL(timeout()),this,SLOT(checkUpdate()));
+
+ addColumn(COLTEXT(COL_NAME));
+ addColumn(COLTEXT(COL_MARKER),25);
+ setColumnAlignment(1,AlignCenter);
+ addColumn(COLTEXT(COL_FUZZY));
+ setColumnAlignment(1,AlignCenter);
+ addColumn(COLTEXT(COL_UNTRANS));
+ setColumnAlignment(2,AlignCenter);
+ addColumn(COLTEXT(COL_TOTAL));
+ setColumnAlignment(3,AlignCenter);
+ addColumn(QString::null); // CVS/SVN column, header is set later
+ addColumn(COLTEXT(COL_REVISION));
+ addColumn(COLTEXT(COL_TRANSLATOR));
+
+
+ header()->setMovingEnabled(false);
+ setAllColumnsShowFocus(true);
+ setSorting(0);
+
+ if(KContextMenuManager::showOnButtonPress())
+ {
+ connect(this,SIGNAL(rightButtonPressed(QListViewItem*,const QPoint &, int))
+ ,this, SLOT(showContentsMenu(QListViewItem*,const QPoint &, int)));
+ }
+ else
+ {
+ connect(this,SIGNAL(rightButtonClicked(QListViewItem*,const QPoint &, int))
+ ,this, SLOT(showContentsMenu(QListViewItem*,const QPoint &, int)));
+ }
+ connect(this, SIGNAL(returnPressed(QListViewItem*))
+ ,this, SLOT(activateItem(QListViewItem*)));
+ connect(this, SIGNAL(doubleClicked(QListViewItem*))
+ ,this, SLOT(activateItem(QListViewItem*)));
+ connect(this,SIGNAL(selectionChanged()),this,SLOT(checkSelected()));
+ connect( this, SIGNAL( clicked(QListViewItem *, const QPoint &, int)),
+ this, SLOT( columnClicked(QListViewItem *, const QPoint &, int)));
+
+ _dirCommandsMenu = 0;
+ _fileCommandsMenu = 0;
+ _dirContentsMenu = 0;
+ _fileContentsMenu = 0;
+
+ _logWindow = new KDialogBase(0,"log window",false,i18n("Log Window")
+ ,KDialogBase::Close | KDialogBase::User1,KDialogBase::Close);
+ _logWindow->setButtonText(KDialogBase::User1,i18n("C&lear"));
+ _logWindow->setInitialSize(QSize(300,200));
+
+ QWhatsThis::add(_logWindow,i18n("<qt><p><b>Log window</b></p>\n"
+ "<p>In this window the output of "
+ "the executed commands are shown.</p></qt>"));
+
+ _logView = new QTextEdit(_logWindow);
+ _logView->setReadOnly(true);
+
+ _logWindow->setMainWidget(_logView);
+
+ connect(_logWindow,SIGNAL(user1Clicked()),_logView,SLOT(clear()));
+
+ QWhatsThis::add(this,i18n("<qt><p><b>Catalog Manager</b></p>\n"
+"<p>The Catalog Manager merges two folders into one tree and displays all\n"
+"PO and POT files in these folders. This way you can easily see if a\n"
+"template has been added or removed. Also some information about the files\n"
+"is displayed.</p>"
+"<p>For more information see section <b>The Catalog Manager</b>"
+" in the online help.</p></qt>"));
+
+ setAcceptDrops(true); // just to get the drag displayed immediately
+
+ mailer = new KBabelMailer( this, _project );
+
+ // CVS
+ cvshandler = new CVSHandler( );
+ connect( cvshandler, SIGNAL( signalIsPORepository( bool ) ),
+ this, SLOT( slotValidPOCVSRepository( bool ) ) );
+ connect( cvshandler, SIGNAL( signalIsPOTRepository( bool ) ),
+ this, SLOT( slotValidPOTCVSRepository( bool ) ) );
+ connect( cvshandler, SIGNAL( signalFilesCommitted( const QStringList& ) ),
+ this, SLOT( updateFiles( const QStringList& ) ) );
+
+ // SVN
+ svnhandler = new SVNHandler( );
+ connect( svnhandler, SIGNAL( signalIsPORepository( bool ) ),
+ this, SLOT( slotValidPOSVNRepository( bool ) ) );
+ connect( svnhandler, SIGNAL( signalIsPOTRepository( bool ) ),
+ this, SLOT( slotValidPOTSVNRepository( bool ) ) );
+ connect( svnhandler, SIGNAL( signalFilesCommitted( const QStringList& ) ),
+ this, SLOT( updateFiles( const QStringList& ) ) );
+
+ KConfig *config = KGlobal::config();
+ restoreView(config);
+
+ _dictBox->readSettings(_project->config());
+}
+
+CatalogManagerView::~CatalogManagerView()
+{
+ if(_active)
+ stop();
+
+ if(_dirWatch)
+ delete _dirWatch;
+
+ if(_settings.killCmdOnExit)
+ {
+ KProcess* proc;
+ for ( proc=_pendingProcesses.first(); proc != 0; proc=_pendingProcesses.next() )
+ {
+ proc->kill(SIGKILL);
+ }
+ }
+
+ delete _logWindow;
+ delete mailer;
+ delete cvshandler;
+ delete svnhandler;
+ if (markPatternDialog) delete markPatternDialog;
+}
+
+
+void CatalogManagerView::saveView( KConfig *config) const
+{
+ saveMarker(config);
+
+ KConfigGroupSaver( config, "CatalogManager" );
+
+ config->writeEntry( "ValidateMarkAsFuzzy", _markAsFuzzy );
+ config->writeEntry( "ValidateIgnoreFuzzy", _ignoreFuzzy );
+}
+
+
+void CatalogManagerView::restoreView( KConfig *config)
+{
+ readMarker(config);
+
+ _markAsFuzzy = config->readBoolEntry( "ValidateMarkAsFuzzy", false );
+ _ignoreFuzzy = config->readBoolEntry( "ValidateIgnoreFuzzy", false );
+}
+
+void CatalogManagerView::setRMBMenuFile( QPopupMenu *m )
+{
+ _fileContentsMenu = m;
+}
+
+void CatalogManagerView::setRMBMenuDir( QPopupMenu *m )
+{
+ _dirContentsMenu = m;
+}
+
+void CatalogManagerView::setDirCommandsMenu( QPopupMenu *m )
+{
+ _dirCommandsMenu = m;
+ connect(_dirCommandsMenu,SIGNAL(activated(int)),this,SLOT(slotDirCommand(int)));
+}
+
+void CatalogManagerView::setFileCommandsMenu( QPopupMenu *m )
+{
+ _fileCommandsMenu = m;
+ connect(_fileCommandsMenu,SIGNAL(activated(int)),this,SLOT(slotFileCommand(int)));
+}
+
+void CatalogManagerView::checkUpdate()
+{
+ _updateNesting++;
+ pause(true);
+
+ QDictIterator<CatManListItem> it( _fileList ); // iterator for dict
+
+ while ( it.current() && !_stop)
+ {
+ CatManListItem* item=it.current();
+
+ item->checkUpdate();
+ ++it;
+ }
+
+ pause(false);
+ --_updateNesting;
+ if( _updateNesting == 0 )
+ {
+ emit updateFinished();
+ }
+}
+
+
+
+void CatalogManagerView::pause(bool flag)
+{
+ if(flag)
+ {
+ _updateTimer->stop();
+ }
+ else
+ {
+ _updateTimer->start(10000);
+ }
+}
+
+
+void CatalogManagerView::stop(bool s)
+{
+ kdDebug(KBABEL_CATMAN) << "Stopping " << s << endl;
+ pause(s);
+ _stop=s;
+ PoInfo::stopStaticRead = true;
+}
+
+void CatalogManagerView::stopSearch()
+{
+ _stopSearch = true;
+}
+
+void CatalogManagerView::clear()
+{
+ pause(true);
+
+ // first clear up
+ if(_dirWatch)
+ delete _dirWatch;
+
+ _dirWatch= new KDirWatch();
+ connect(_dirWatch,SIGNAL(deleted(const QString&)),this
+ ,SLOT(directoryDeleted(const QString&)));
+ connect(_dirWatch,SIGNAL(dirty(const QString&)),this
+ ,SLOT(directoryChanged(const QString&)));
+ connect(_dirWatch,SIGNAL(created(const QString&)),this
+ ,SLOT(directoryChanged(const QString&)));
+
+ _dirList.clear();
+ _fileList.clear();
+
+ QListView::clear();
+}
+
+void CatalogManagerView::toggleAllMarks()
+{
+ _markerList.clear();
+
+ QListViewItemIterator it( this );
+ CatManListItem* item;
+
+ for ( ; it.current(); ++it )
+ {
+ item = (CatManListItem*) it.current();
+ if(item->isFile())
+ {
+ bool wasMarked=item->marked();
+ item->setMarked(!wasMarked);
+ if(!wasMarked)
+ {
+ _markerList.append(item->package());
+ }
+ else
+ {
+ _markerList.remove(item->package());
+ }
+ }
+ }
+
+ checkSelected();
+}
+
+void CatalogManagerView::clearAllMarks()
+{
+ _markerList.clear();
+ QDictIterator<CatManListItem> it( _fileList ); // iterator for dict
+
+ while ( it.current() )
+ {
+ CatManListItem* item=it.current();
+
+ if(item->marked())
+ _markerList.remove(item->package());
+
+ item->setMarked(false);
+ ++it;
+ }
+
+ checkSelected();
+}
+
+void CatalogManagerView::markModifiedFiles()
+{
+ QDictIterator<CatManListItem> it( _fileList );
+ while ( it.current() )
+ {
+ CatManListItem* item=it.current();
+ /*if(item->marked())
+ _markerList.remove(item->package());
+ */
+ if(item->isModified() && ! item->marked() ) {
+ item->setMarked(true);
+ _markerList.append(item->package( ));
+ }
+ ++it;
+ }
+
+ checkSelected();
+}
+
+void CatalogManagerView::loadMarks()
+{
+ const KURL url = KFileDialog::getOpenURL( QString(),"*.marklist", this );
+ if( url.isEmpty() ) return;
+
+ QString filename;
+#if KDE_IS_VERSION( 3, 2, 90 )
+ if (!KIO::NetAccess::download( url, filename, this ) )
+#else
+ if( !KIO::NetAccess::download( url, filename ) )
+#endif
+ {
+ KMessageBox::error(this,i18n(
+ "Error while trying to open file:\n %1").arg(url.prettyURL()));
+ return;
+ }
+
+ // now load from file
+ QStringList newMarkerList; // better create new list in case of problems
+ QFile f( filename );
+ if( f.open( IO_ReadOnly) )
+ {
+ QTextStream s(&f);
+
+ QString input;
+
+ s >> input ;
+ if( input == "[Markers]" )
+ {
+ while( !s.atEnd() )
+ {
+ s >> input;
+ newMarkerList.append(input);
+ }
+ }
+ else
+ {
+ KMessageBox::error(this
+ ,i18n("Error while trying to read file:\n %1\n"
+ "Maybe it is not a valid file with list of markings.").arg(url.prettyURL()));
+ f.close();
+ return;
+ }
+ f.close();
+ }
+ else
+ {
+ KMessageBox::error(this,i18n(
+ "Error while trying to open file:\n %1").arg(url.prettyURL()));
+ }
+
+ KIO::NetAccess::removeTempFile( filename );
+
+ // test validity of list items
+ QStringList testedList;
+ QStringList::const_iterator it;
+ for( it=newMarkerList.constBegin() ; it!=newMarkerList.constEnd() ; ++it )
+ if( _fileList[(*it)] != 0 ) testedList.append( (*it) );
+
+ // apply new list
+ for( it=_markerList.constBegin() ; it!=_markerList.constEnd() ; ++it )
+ {
+ CatManListItem* item = _fileList[(*it)];
+ if( item ) item->setMarked(false);
+ }
+
+ _markerList = testedList;
+ for( it=_markerList.constBegin() ; it!=_markerList.constEnd() ; ++it )
+ {
+ CatManListItem* item = _fileList[(*it)];
+ if( item ) item->setMarked(true);
+ }
+
+ checkSelected();
+}
+
+void CatalogManagerView::saveMarks()
+{
+ const KURL url2 = KFileDialog::getSaveURL( QString(), "*.marklist", this );
+ if( url2.isEmpty() ) return;
+
+ // ### FIXME: why is the file dialog not doing this?
+ if ( KIO::NetAccess::exists( url2, false, this ) )
+ {
+ if(KMessageBox::warningContinueCancel(this,QString("<qt>%1</qt>").arg(i18n("The file %1 already exists. "
+ "Do you want to overwrite it?").arg(url2.prettyURL())),i18n("Warning"),i18n("&Overwrite"))==KMessageBox::Cancel)
+ {
+ return;
+ }
+ }
+
+#if KDE_IS_VERSION( 3, 4, 92 )
+ // Support for partially remote KIO slave like media:
+ const KURL url ( KIO::NetAccess::mostLocalURL( url2, this ) );
+#else
+ const KURL url ( url2 );
+#endif
+ kdDebug() << "Saving marks: " << url2.prettyURL() << " most-local: " << url.prettyURL() << endl;
+
+ QFile* file = 0;
+ KTempFile* tempFile = 0;
+ QTextStream* stream = 0;
+ bool error = false;
+
+ const bool localFile = url.isLocalFile();
+ if ( localFile )
+ {
+ // We have a local file
+ file = new QFile( url.path() );
+ if ( file->open (IO_WriteOnly) )
+ {
+ stream = new QTextStream( file );
+ }
+ else
+ {
+ error = true;
+ }
+ }
+ else
+ {
+ tempFile = new KTempFile();
+ tempFile->setAutoDelete(true);
+ stream = tempFile->textStream();
+ error = !stream;
+ }
+ if ( !error )
+ {
+ // ### TODO: try to get a better file format for KDE4 (XML?), one working with real relative paths (no / at start) and working with UTF-8
+ *stream << "[Markers]" << endl;
+ for( QStringList::const_iterator it = _markerList.constBegin(); it!=_markerList.constEnd() ; ++it )
+ *stream << (*it) << endl;
+ }
+ if ( error )
+ {
+ // ### KDE4 FIXME: strip the final \n of the message
+ KMessageBox::error( this,
+ i18n( "An error occurred while trying to write to file:\n%1\n" ).arg( url.prettyURL()) );
+ }
+ else if ( !localFile )
+ {
+ tempFile->close();
+ if( !KIO::NetAccess::upload( tempFile->name(), url, this ) )
+ {
+ // ### KDE4 FIXME: strip the final \n of the message
+ KMessageBox::error(this,
+ i18n("An error occurred while trying to upload the file:\n%1\n").arg(url.prettyURL()));
+ }
+ }
+
+ // We have finished so clean up
+ if ( localFile )
+ {
+ delete stream;
+ file->close();
+ delete file;
+ }
+ else
+ {
+ delete tempFile;
+ }
+
+ checkSelected();
+}
+
+void CatalogManagerView::slotMarkPattern( )
+{
+ setPatternMarks(true);
+}
+
+void CatalogManagerView::slotUnmarkPattern( )
+{
+ setPatternMarks(false);
+}
+
+void CatalogManagerView::setPatternMarks(bool mark)
+{
+ CatManListItem * item = (CatManListItem*)currentItem( );
+ if (!item)
+ item = (CatManListItem*)_dirList["/"];
+ if (!item->isDir( ))
+ return;
+
+ if (!markPatternDialog)
+ markPatternDialog = new MarkPatternDialog(this);
+
+ markPatternDialog->setMode(mark);
+
+ if (markPatternDialog->exec( ) != KDialog::Accepted)
+ return;
+
+ QRegExp rx(markPatternDialog->pattern( ));
+ rx.setWildcard(!markPatternDialog->useRegExp( ));
+ rx.setCaseSensitive(markPatternDialog->isCaseSensitive( ));
+
+ QStringList fileList = item->allChildrenList(true);
+ for (QStringList::const_iterator it = fileList.constBegin( ); it != fileList.constEnd( ); ++it) {
+ CatManListItem * i = _fileList[*it];
+
+ QString matchName;
+ if (i->hasPo( ))
+ matchName = i->poFile( );
+ else if (i->hasPot( ) && markPatternDialog->includeTemplates( ))
+ matchName = i->potFile( );
+ matchName = QFileInfo(matchName).baseName( );
+
+ if (mark) {
+ if (!matchName.isEmpty( ) && rx.exactMatch(matchName) && !i->marked( )) {
+ i->setMarked(true);
+ _markerList.append(i->package( ));
+ }
+ } else {
+ if (!matchName.isEmpty( ) && rx.exactMatch(matchName) && i->marked( )) {
+ i->setMarked(false);
+ _markerList.remove(i->package( ));
+ }
+ }
+ }
+}
+
+void CatalogManagerView::statistics()
+{
+ CatManListItem* i=(CatManListItem*) currentItem();
+
+ if(!i)
+ i=(CatManListItem*)_dirList["/"];
+
+ if(isActive() && i->isDir())
+ {
+ if(KMessageBox::warningContinueCancel(this
+ ,i18n("The Catalog Manager is still updating information about the files.\n"
+"If you continue, it will try to update all necessary files, however this can take "
+"a long time and may lead to wrong results. Please wait until all files are updated."),i18n("Warning")
+ ,KStdGuiItem::cont()) == KMessageBox::Cancel)
+ {
+ return;
+ }
+ }
+
+ QStringList doList;
+
+ if( i->isFile() ) doList.append(i->package());
+ else doList = i->allChildrenList(true);
+
+ showStatistics( i, doList );
+}
+
+void CatalogManagerView::markedStatistics()
+{
+ CatManListItem* i=(CatManListItem*) currentItem();
+
+ if(!i)
+ i=(CatManListItem*)_dirList["/"];
+
+ if(isActive() && i->isDir())
+ {
+ if(KMessageBox::warningContinueCancel(this
+ ,i18n("The Catalog Manager is still updating information about the files.\n"
+"If you continue, it will try to update all necessary files, however this can take "
+"a long time and may lead to wrong results. Please wait until all files are updated."),i18n("Warning")
+ ,KStdGuiItem::cont()) == KMessageBox::Cancel)
+ {
+ return;
+ }
+ }
+
+ QStringList doList;
+
+ if( i->isFile() ) doList.append(i->package());
+ else doList = i->allChildrenList(true);
+
+ QStringList markedDoList;
+ QStringList::const_iterator it;
+ for( it = doList.constBegin(); it != doList.constEnd(); ++it )
+ {
+ CatManListItem* item = _fileList[(*it)];
+ if( item->marked() ) markedDoList.append(item->package());
+ }
+
+ showStatistics( i, markedDoList );
+}
+
+void CatalogManagerView::showStatistics( CatManListItem *i, QStringList &childrenList )
+{
+ KLocale *locale = KGlobal::locale();
+
+ QString msg;
+ int totalPackages=0;
+ int totalPo=0;
+ int totalNoPot=0;
+ int needworkPo=0;
+ int totalMsgid=0;
+ int totalFuzzy=0;
+ int totalUntranslated=0;
+
+ QStringList::const_iterator it;
+ for( it = childrenList.constBegin(); it != childrenList.constEnd(); ++it )
+ {
+ CatManListItem* item = _fileList[(*it)];
+
+ /*
+ KASSERT1(item,KDEBUG_FATAL,KBABEL_CATMAN,"CatalogManagerView::statistics: item not in list %s"
+ ,(*it).ascii());
+ */
+ // be sure, that the information is updated
+ _updateNesting++;
+ item->checkUpdate();
+ _updateNesting--;
+ if( _stop ) return;
+
+ totalPackages++;
+
+ int fuzzy=item->fuzzy();
+ int total=item->total();
+ int untrans=item->untranslated();
+
+ if(item->hasPo())
+ totalPo++;
+
+ if(!item->hasPot())
+ totalNoPot++;
+
+
+ if(fuzzy || untrans)
+ needworkPo++;
+
+ totalMsgid+=total;
+ totalFuzzy+=fuzzy;
+ totalUntranslated+=untrans;
+ }
+
+ double percent;
+
+ const QString name=i->package(false);
+ if(name.isEmpty())
+ msg = i18n("Statistics for all:\n");
+ else
+ msg = i18n("Statistics for %1:\n").arg(name);
+
+ msg+=i18n("Number of packages: %1\n").arg(locale->formatNumber(totalPackages, 0));
+
+ percent=100.0-((double)needworkPo*100.0)/totalPackages;
+ msg+=i18n("Complete translated: %1 % (%2)\n").arg(locale->formatNumber(percent,2)).arg(locale->formatNumber(totalPackages-needworkPo, 0));
+
+ percent=100.0-((double)totalPo*100.0)/totalPackages;
+ msg+=i18n("Only template available: %1 % (%2)\n").arg(locale->formatNumber(percent,2)).arg(locale->formatNumber(totalPackages-totalPo,0));
+ percent=((double)totalNoPot*100.0)/totalPackages;
+ msg+=i18n("Only PO file available: %1 % (%2)\n").arg(locale->formatNumber(percent,02)).arg(locale->formatNumber(totalNoPot, 0));
+
+ msg+=i18n("Number of messages: %1\n").arg(locale->formatNumber(totalMsgid, 0));
+
+ long int totalTranslated = totalMsgid - totalFuzzy - totalUntranslated;
+ percent=((double)totalTranslated*100.0)/totalMsgid;
+ msg+=i18n("Translated: %1 % (%2)\n").arg(locale->formatNumber(percent,2)).arg(locale->formatNumber(totalTranslated, 0));
+
+ percent=((double)totalFuzzy*100.0)/totalMsgid;
+ msg+=i18n("Fuzzy: %1 % (%2)\n").arg(locale->formatNumber(percent,2)).arg(locale->formatNumber(totalFuzzy, 0));
+
+ percent=((double)totalUntranslated*100.0)/totalMsgid;
+ msg+=i18n("Untranslated: %1 % (%2)\n").arg(locale->formatNumber(percent,2)).arg(locale->formatNumber(totalUntranslated, 0));
+
+ KMessageBox::information(this,msg,i18n("Statistics"));
+}
+
+void CatalogManagerView::checkSyntax()
+{
+ CatManListItem* item=(CatManListItem*) currentItem();
+
+ if(!item)
+ item=(CatManListItem*) _dirList["/"];
+
+ if(item->isFile())
+ {
+ if(!item->hasPo())
+ return;
+
+ Msgfmt::Status status;
+ QString output;
+ Msgfmt msgfmt;
+
+ status=msgfmt.checkSyntax(item->poFile(),output);
+
+ switch(status)
+ {
+ case Msgfmt::Ok:
+ {
+ KMessageBox::information(this,i18n("The file is syntactically correct.\nOutput of \"msgfmt --statistics\":")+"\n"+output);
+ break;
+ }
+ case Msgfmt::SyntaxError:
+ {
+ KMessageBox::information(this,i18n("The file has syntax errors.\nOutput of \"msgfmt --statistics\":")+"\n"+output);
+ break;
+ }
+ case Msgfmt::HeaderError:
+ {
+ KMessageBox::information(this,i18n("The file has header syntax error.\nOutput of \"msgfmt --statistics\":")+"\n"+output);
+ break;
+ }
+ case Msgfmt::Error:
+ {
+ KMessageBox::error(this,i18n("An error occurred while processing \"msgfmt --statistics\""));
+ break;
+ }
+ case Msgfmt::NoExecutable:
+ {
+ KMessageBox::sorry(this,i18n("Cannot execute msgfmt. Please make sure that you have msgfmt in your PATH."));
+ break;
+ }
+ case Msgfmt::Unsupported:
+ {
+ KMessageBox::sorry(this,i18n("You can use gettext tools only for checking PO files."));
+ break;
+ }
+ }
+
+ }
+ else
+ {
+ Msgfmt::Status status;
+ QString output;
+ Msgfmt msgfmt;
+
+ status=msgfmt.checkSyntaxInDir(item->poFile(), "*.po", output);
+
+ QString name=item->package(false);
+
+ switch(status)
+ {
+ case Msgfmt::Ok:
+ {
+ QString msg;
+ if(!name.isEmpty())
+ {
+ msg=i18n("All files in folder %1 are syntactically correct.\n"
+"Output of \"msgfmt --statistics\":\n").arg(name)+output;
+ }
+ else
+ {
+ msg=i18n("All files in the base folder are syntactically correct.\n"
+"Output of \"msgfmt --statistics\":\n")+output;
+ }
+ KMessageBox::information(this,msg);
+ break;
+ }
+ case Msgfmt::SyntaxError:
+ {
+ QString msg;
+ if(!name.isEmpty())
+ {
+ msg=i18n("At least one file in folder %1 has syntax errors.\n"
+"Output of \"msgfmt --statistics\":\n").arg(name)+output;
+ }
+ else
+ {
+ msg=i18n("At least one file in the base folder has syntax errors.\n"
+"Output of \"msgfmt --statistics\":\n")+output;
+ }
+ KMessageBox::information(this,msg);
+ break;
+ }
+ case Msgfmt::HeaderError:
+ {
+ QString msg;
+ if(!name.isEmpty())
+ {
+ msg=i18n("At least one file in folder %1 has header syntax errors.\n"
+"Output of \"msgfmt --statistics\":\n").arg(name)+output;
+ }
+ else
+ {
+ msg=i18n("At least one file in the base folder has header syntax errors.\n"
+"Output of \"msgfmt --statistics\":\n")+output;
+ }
+ KMessageBox::information(this,msg);
+ break;
+ }
+ case Msgfmt::Error:
+ {
+ QString msg;
+ if(!name.isEmpty())
+ {
+ msg=i18n("An error occurred while processing \"msgfmt --statistics *.po\" "
+"in folder %1").arg(name);
+ }
+ else
+ {
+ msg=i18n("An error occurred while processing \"msgfmt --statistics *.po\" "
+"in the base folder");
+ }
+ KMessageBox::error(this,msg);
+ break;
+ }
+ case Msgfmt::NoExecutable:
+ {
+ KMessageBox::sorry(this,i18n("Cannot execute msgfmt. Please make sure that you have msgfmt in your PATH."));
+ break;
+ }
+ case Msgfmt::Unsupported:
+ {
+ KMessageBox::sorry(this,i18n("You can use gettext tools only for checking PO files."));
+ break;
+ }
+ }
+ }
+}
+
+void CatalogManagerView::roughTranslation()
+{
+ QPtrList<CatManListItem> result;
+ CatManListItem *current = static_cast<CatManListItem *>(currentItem());
+ if( current->isDir() )
+ {
+ QStringList s = current->allChildrenList(true);
+ QStringList::const_iterator it;
+ for( it = s.constBegin() ; it != s.constEnd(); ++it )
+ {
+ CatManListItem *item = _fileList[(*it)];
+ if( item ) result.append( item );
+ }
+ }
+ else
+ {
+ result.append( current );
+ }
+
+ MultiRoughTransDlg* dialog=new MultiRoughTransDlg( _dictBox, result, this );
+ dialog->exec();
+ delete dialog;
+}
+
+void CatalogManagerView::markedRoughTranslation()
+{
+ if( _markerList.count() == 0 ) return;
+
+ QPtrList<CatManListItem> result;
+
+ QStringList::const_iterator it;
+ for( it = _markerList.constBegin() ; it != _markerList.constEnd(); ++it )
+ {
+ CatManListItem *item = _fileList[(*it)];
+ result.append( item );
+ }
+
+ MultiRoughTransDlg* dialog=new MultiRoughTransDlg( _dictBox, result, this );
+ dialog->exec();
+ delete dialog;
+}
+
+void CatalogManagerView::mailFiles()
+{
+ CatManListItem* item = (CatManListItem*)currentItem();
+ if(item->isDir()) {
+ QStringList filesToSend;
+ QStringList childrenList = item->allChildrenList(true);
+
+ QStringList::const_iterator it;
+ for (it = childrenList.constBegin(); it != childrenList.constEnd(); ++it) {
+ CatManListItem* i = _fileList[(*it)];
+ if (i->hasPo()) {
+ filesToSend << i->poFile();
+ }
+ }
+ mailer->sendFiles(filesToSend, item->text(0));
+ } else {
+ if (item->hasPo()) {
+ mailer->sendOneFile(item->poFile());
+ }
+ }
+}
+
+void CatalogManagerView::mailMarkedFiles()
+{
+ if (_markerList.count() == 0)
+ return;
+
+ QStringList filesToSend;
+ QStringList::const_iterator it;
+ for (it = _markerList.constBegin(); it != _markerList.constEnd(); ++it) {
+ CatManListItem* i = _fileList[(*it)];
+ if (i->hasPo()) {
+ filesToSend << i->poFile();
+ }
+ }
+ mailer->sendFiles(filesToSend);
+}
+
+void CatalogManagerView::packageFiles( )
+{
+ CatManListItem* item = (CatManListItem*)currentItem();
+ if(item->isDir()) {
+ QStringList filesToPackage;
+ QStringList childrenList = item->allChildrenList(true);
+
+ QStringList::const_iterator it;
+ for (it = childrenList.constBegin(); it != childrenList.constEnd(); ++it) {
+ CatManListItem* i = _fileList[(*it)];
+ if (i->hasPo()) {
+ filesToPackage << i->poFile();
+ }
+ }
+ QString packageFileName = KFileDialog::getSaveFileName(QString::null,"*.tar.bz2\n*.tar.gz",this);
+ mailer->buildArchive( filesToPackage, packageFileName, QString::null, false );
+ }
+ else {
+ if (item->hasPo()) {
+ QStringList fileToPackage(item->poFile());
+ QString packageFileName = KFileDialog::getSaveFileName(QString::null,"*.tar.bz2\n*.tar.gz",this);
+ mailer->buildArchive( fileToPackage, packageFileName, QString::null, false );
+ }
+ }
+}
+void CatalogManagerView::packageMarkedFiles( )
+{
+ if (_markerList.count() == 0)
+ return;
+
+ QStringList filesToPackage;
+ QStringList::const_iterator it;
+ for (it = _markerList.constBegin(); it != _markerList.constEnd(); ++it) {
+ CatManListItem* i = _fileList[(*it)];
+ if (i->hasPo()) {
+ filesToPackage << i->poFile();
+ }
+ }
+
+ QString packageFileName = KFileDialog::getSaveFileName(QString::null,"*.tar.bz2\n*.tar.gz",this);
+ mailer->buildArchive( filesToPackage, packageFileName, QString::null, false );
+}
+
+// CVS
+void CatalogManagerView::cvsUpdate( )
+{
+ doCVSCommand( CVS::Update );
+}
+
+void CatalogManagerView::cvsUpdateMarked( )
+{
+ doCVSCommand( CVS::Update, true );
+}
+
+void CatalogManagerView::cvsCommit( )
+{
+ doCVSCommand( CVS::Commit );
+}
+
+void CatalogManagerView::cvsCommitMarked( )
+{
+ doCVSCommand( CVS::Commit, true );
+}
+
+void CatalogManagerView::cvsStatus( )
+{
+ doCVSCommand( CVS::Status );
+}
+
+void CatalogManagerView::cvsStatusMarked( )
+{
+ doCVSCommand( CVS::Status, true );
+}
+
+void CatalogManagerView::cvsUpdateTemplate( )
+{
+ doCVSCommand( CVS::Update, false, true );
+}
+
+void CatalogManagerView::cvsUpdateMarkedTemplate( )
+{
+ doCVSCommand( CVS::Update, true, true );
+}
+
+void CatalogManagerView::cvsCommitTemplate( )
+{
+ doCVSCommand( CVS::Commit, false, true );
+}
+
+void CatalogManagerView::cvsCommitMarkedTemplate( )
+{
+ doCVSCommand( CVS::Commit, true, true );
+}
+
+void CatalogManagerView::cvsDiff( )
+{
+ doCVSCommand( CVS::Diff, false, false );
+}
+
+void CatalogManagerView::doCVSCommand( CVS::Command cmd, bool marked, bool templates )
+{
+ KSharedConfig* config = _project->sharedConfig();
+ if ( marked ) {
+ if ( _markerList.isEmpty() ) return;
+ QStringList fileList;
+ QStringList::const_iterator it;
+ for ( it = _markerList.constBegin( ); it != _markerList.constEnd( ); ++it ) {
+ CatManListItem * i = _fileList[(*it)];
+ if ( templates && i->hasPot( ) )
+ fileList << i->potFile( );
+ else if ( !templates && i->hasPo( ) )
+ fileList << i->poFile( );
+ }
+ cvshandler->execCVSCommand( this, cmd, fileList, templates, config );
+ } else {
+ const QString basedir = ( templates ? _settings.potBaseDir : _settings.poBaseDir );
+ QString cvsItem;
+ CatManListItem * item = (CatManListItem*)currentItem( );
+ if ( ( cmd == CVS::Commit || cmd == CVS::Diff ) && item->isDir( ) ) {
+ // all children including directories
+ QStringList cvsItems = item->allChildrenFileList (true, false, true);
+ if ( !cvsItems.isEmpty( ) )
+ cvshandler->execCVSCommand( this, cmd, cvsItems, templates, config );
+ } else {
+ if ( templates && item->hasPot( ) )
+ cvsItem = item->potFile( );
+ else if ( !templates && item->hasPo( ) )
+ cvsItem = item->poFile( );
+
+ if ( !cvsItem.isEmpty( ) )
+ cvshandler->execCVSCommand( this, cmd, cvsItem, templates, config );
+ }
+ }
+}
+
+//SVN
+void CatalogManagerView::svnUpdate( )
+{
+ doSVNCommand( SVN::Update );
+}
+
+void CatalogManagerView::svnUpdateMarked( )
+{
+ doSVNCommand( SVN::Update, true );
+}
+
+void CatalogManagerView::svnCommit( )
+{
+ doSVNCommand( SVN::Commit );
+}
+
+void CatalogManagerView::svnCommitMarked( )
+{
+ doSVNCommand( SVN::Commit, true );
+}
+
+void CatalogManagerView::svnStatusRemote( )
+{
+ doSVNCommand( SVN::StatusRemote );
+}
+
+void CatalogManagerView::svnStatusRemoteMarked( )
+{
+ doSVNCommand( SVN::StatusRemote, true );
+}
+
+void CatalogManagerView::svnStatusLocal( )
+{
+ doSVNCommand( SVN::StatusLocal );
+}
+
+void CatalogManagerView::svnStatusLocalMarked( )
+{
+ doSVNCommand( SVN::StatusLocal, true );
+}
+
+void CatalogManagerView::svnInfo()
+{
+ doSVNCommand( SVN::Info );
+}
+
+void CatalogManagerView::svnInfoMarked()
+{
+ doSVNCommand( SVN::Info, true );
+}
+
+void CatalogManagerView::svnUpdateTemplate( )
+{
+ doSVNCommand( SVN::Update, false, true );
+}
+
+void CatalogManagerView::svnUpdateMarkedTemplate( )
+{
+ doSVNCommand( SVN::Update, true, true );
+}
+
+void CatalogManagerView::svnCommitTemplate( )
+{
+ doSVNCommand( SVN::Commit, false, true );
+}
+
+void CatalogManagerView::svnCommitMarkedTemplate( )
+{
+ doSVNCommand( SVN::Commit, true, true );
+}
+
+void CatalogManagerView::svnDiff( )
+{
+ doSVNCommand( SVN::Diff, false, false );
+}
+
+void CatalogManagerView::doSVNCommand( SVN::Command cmd, bool marked, bool templates )
+{
+ KSharedConfig* config = _project->sharedConfig();
+ if ( marked ) {
+ if ( _markerList.isEmpty() ) return;
+ QStringList fileList;
+ QStringList::const_iterator it;
+ for ( it = _markerList.constBegin( ); it != _markerList.constEnd( ); ++it ) {
+ CatManListItem * i = _fileList[(*it)];
+ if ( templates && i->hasPot( ) )
+ fileList << i->potFile( );
+ else if ( !templates && i->hasPo( ) )
+ fileList << i->poFile( );
+ }
+ svnhandler->execSVNCommand( this, cmd, fileList, templates, config );
+ } else {
+ const QString basedir = ( templates ? _settings.potBaseDir : _settings.poBaseDir );
+ QString svnItem;
+ CatManListItem * item = (CatManListItem*)currentItem( );
+ if ( ( cmd == SVN::Commit || cmd == SVN::Diff ) && item->isDir( ) ) {
+ // all children including directories
+ QStringList svnItems = item->allChildrenFileList (true, false, true);
+ if ( !svnItems.isEmpty( ) )
+ svnhandler->execSVNCommand( this, cmd, svnItems, templates, config );
+ } else {
+ if ( templates && item->hasPot( ) )
+ svnItem = item->potFile( );
+ else if ( !templates && item->hasPo( ) )
+ svnItem = item->poFile( );
+
+ if ( !svnItem.isEmpty( ) )
+ svnhandler->execSVNCommand( this, cmd, svnItem, templates, config );
+ }
+ }
+}
+
+void CatalogManagerView::showLog()
+{
+ _logWindow->show();
+}
+
+QString CatalogManagerView::find( FindOptions &options, QStringList &rest )
+{
+ CatManListItem* i=(CatManListItem*) currentItem();
+
+ if(!i || options.inAllFiles)
+ i=(CatManListItem*)_dirList["/"];
+
+ QValueList<QString> foundFiles;
+ _stopSearch = false;
+
+ const QString search = options.findStr.lower().simplifyWhiteSpace();
+ QStringList searchWords = QStringList::split(' ', search);
+
+ QStringList childrenList;
+ if( i->isFile() ) childrenList.append(i->name());
+ else childrenList =i->allChildrenList(true);
+
+ emit prepareFindProgressBar(childrenList.size());
+
+ QStringList::const_iterator it;
+ for( it = childrenList.constBegin(); it != childrenList.constEnd(); ++it )
+ {
+ CatManListItem* item = _fileList[(*it)];
+
+ if( !item )
+ {
+ kdWarning(KBABEL_CATMAN) << "The file information not found, skipping" << endl;
+ continue;
+ }
+
+ // skip if not marked and we lookup in marked
+ if( options.inMarkedFiles && !item->marked() )
+ {
+ kdDebug(KBABEL_CATMAN) << "Skipping due marking " << item->name() << endl;
+ emit signalSearchedFile(1);
+ continue;
+ }
+
+ bool doSearch = options.isRegExp || options.inTemplates; // for regexp and templates we do not support index search
+ if( item->wordsUpdated() )
+ doSearch = doSearch || hasMatchingWords(item->wordList(), searchWords);
+ else doSearch = true; // we do not have index, we need to search
+ if( doSearch )
+ {
+ QString itemFile;
+ if( options.inTemplates )
+ {
+ if( item->hasPot() ) itemFile=item->potFile();
+ } else {
+ if( item->hasPo() ) itemFile=item->poFile();
+ }
+
+ if( itemFile.isNull() )
+ {
+ emit signalSearchedFile(1);
+ continue;
+ }
+
+ if( PoInfo::findInFile( itemFile , options ) )
+ {
+ emit signalSearchedFile(1);
+ rest.clear();
+ if( _stopSearch )
+ {
+ // if we are stopped, return what we found and clear the rest
+ _stopSearch = false;
+ return itemFile;
+ }
+ const QString foundItemFile = itemFile;
+
+ it++;
+ while( it != childrenList.constEnd() )
+ {
+ CatManListItem *item = _fileList[(*it)];
+
+ itemFile = QString::null;
+ if( options.inTemplates )
+ {
+ if( item->hasPot() ) itemFile=item->potFile();
+ } else {
+ if( item->hasPo() )itemFile=item->poFile();
+ }
+ if( options.inMarkedFiles && !item->marked() )
+ itemFile=QString::null;
+
+ if( !itemFile.isNull())
+ {
+ if( item->wordsUpdated() && !options.inTemplates )
+ {
+ if( options.isRegExp || hasMatchingWords(item->wordList(), searchWords) )
+ {
+ rest.append( itemFile );
+ }
+ else kdDebug(KBABEL_CATMAN) << "Don't try to lookup in " << itemFile << endl;
+ } else {
+ rest.append( itemFile ); // there is no word index, add the file
+ }
+ } else emit signalSearchedFile(1);
+
+ it++;
+ }
+ return foundItemFile;
+
+ }
+ } else kdDebug(KBABEL_CATMAN) << "Skipping " << item->poFile() << endl;
+ emit signalSearchedFile(1);
+ if( _stop || _stopSearch ) {
+ _stopSearch = false;
+ rest.clear();
+ if( _updateNesting == 0 && !_stop ) emit updateFinished();
+ return QString::null;
+ }
+ }
+ return QString::null;
+}
+
+bool CatalogManagerView::hasMatchingWords( QStringList &itemWords, QStringList &searchWords)
+{
+ for( QStringList::const_iterator it1 = searchWords.constBegin() ; it1 != searchWords.constEnd() ; ++it1 )
+ for( QStringList::const_iterator it2 = itemWords.constBegin() ; it2 != itemWords.constEnd() ; ++it2 )
+ if( *it1 == *it2
+ || (*it1).contains(*it2)
+ || (*it2).contains(*it1) ) return true;
+ return false;
+}
+
+void CatalogManagerView::showContentsMenu(QListViewItem *i, const QPoint &point, int)
+{
+ CatManListItem* item = (CatManListItem*) i;
+
+ if(!item)
+ return;
+
+ if(item->isDir())
+ {
+ _dirContentsMenu->exec(point);
+ }
+ else
+ {
+ _fileContentsMenu->exec(point);
+ }
+}
+
+void CatalogManagerView::checkSelected()
+{
+ CatManListItem* item=(CatManListItem*)selectedItem();
+ if(!item) return;
+
+ const uint actionValue =
+ NEEDS_PO * item->hasPo() + NEEDS_POT * item->hasPot() +
+ NEEDS_MARK * item->marked() + NEEDS_DIR * item->isDir() +
+ NEEDS_PO_CVS * m_validPOCVSRepository + NEEDS_POT_CVS * m_validPOTCVSRepository +
+ NEEDS_PO_SVN * m_validPOSVNRepository + NEEDS_POT_SVN * m_validPOTSVNRepository;
+
+ emit selectedChanged(actionValue);
+}
+
+void CatalogManagerView::activateItem(QListViewItem *)
+{
+ CatManListItem* item=(CatManListItem*) currentItem();
+
+ if(!item)
+ return;
+
+ if(item->isDir())
+ {
+ item->setOpen(!item->isOpen());
+ return;
+ }
+
+ if(item->hasPo())
+ {
+ emit openFile(item->poFile(),item->package());
+ }
+ else if(item->hasPot())
+ {
+ emit openTemplate(item->potFile(),item->poFile(),item->package());
+ }
+ else
+ {
+ kdError(KBABEL_CATMAN) << "CatalogManagerView::activateItem: item has no file?" << endl;
+ }
+
+}
+
+void CatalogManagerView::slotOpenFile()
+{
+ CatManListItem* item=(CatManListItem*) currentItem();
+
+ if(item && item->isFile())
+ {
+ activateItem(item);
+ }
+}
+
+void CatalogManagerView::slotOpenFileInNewWindow()
+{
+ CatManListItem* item=(CatManListItem*) currentItem();
+
+ if(item && item->isFile())
+ {
+ QString filename;
+ if(item->hasPo())
+ {
+ emit openFileInNewWindow(item->poFile(),item->package());
+ }
+ else if(item->hasPot())
+ {
+ emit openTemplateInNewWindow(item->potFile(),item->poFile(),item->package());
+ }
+ }
+}
+
+void CatalogManagerView::slotOpenTemplate()
+{
+ CatManListItem* item=(CatManListItem*) currentItem();
+
+ if(item && item->isFile())
+ {
+ emit openFile(item->potFile(),item->package());
+ }
+}
+
+void CatalogManagerView::slotDeleteFile()
+{
+ CatManListItem* item=(CatManListItem*) currentItem();
+
+ if(item && item->isFile() && item->hasPo() && !item->hasPot())
+ {
+ const QString msg=i18n("Do you really want to delete the file %1?").arg(item->poFile());
+ if(KMessageBox::warningContinueCancel(this,msg,i18n("Warning"),KGuiItem( i18n("Delete"), "editdelete"))== KMessageBox::Continue)
+ {
+ if(!QFile::remove(item->poFile()))
+ {
+ KMessageBox::sorry(this,i18n("Was not able to delete the file %1!").arg(item->poFile()));
+ }
+ }
+ }
+}
+
+void CatalogManagerView::toggleMark()
+{
+ CatManListItem* i = (CatManListItem*) currentItem();
+ if( i && i->isDir() ) slotToggleMarksInDir();
+ else slotToggleMark();
+}
+
+void CatalogManagerView::slotToggleMark()
+{
+ CatManListItem* item=(CatManListItem*) currentItem();
+
+ if(item && item->isFile())
+ {
+ bool wasMarked=item->marked();
+ item->setMarked(!wasMarked);
+
+ if(wasMarked)
+ {
+ _markerList.remove(item->package());
+ }
+ else
+ {
+ _markerList.append(item->package());
+ }
+ }
+
+ checkSelected();
+}
+
+void CatalogManagerView::slotToggleMarksInDir()
+{
+ CatManListItem* i=(CatManListItem*) currentItem();
+
+ if(i && i->isDir())
+ {
+ const QStringList contentList = i->allChildrenList(true);
+
+ QStringList::const_iterator it;
+ for( it = contentList.constBegin(); it != contentList.constEnd(); ++it )
+ {
+ CatManListItem* item = _fileList[(*it)];
+
+ if ( item == 0 )
+ kdFatal(KBABEL_CATMAN) << "CatalogManagerView::slotToggleMarkInDir: item not in list" << endl;
+
+ const bool wasMarked=item->marked();
+ item->setMarked(!wasMarked);
+
+ if(wasMarked)
+ {
+ _markerList.remove(item->package());
+ }
+ else
+ {
+ _markerList.append(item->package());
+ }
+ }
+ }
+
+ checkSelected();
+}
+
+
+void CatalogManagerView::slotClearMarksInDir()
+{
+ CatManListItem* i=(CatManListItem*) currentItem();
+
+ if(i && i->isDir())
+ {
+ const QStringList contentList=i->contentsList(true);
+
+ QStringList::const_iterator it;
+ for( it = contentList.constBegin(); it != contentList.constEnd(); ++it )
+ {
+ CatManListItem* item = _fileList[(*it)];
+
+ if ( item == 0 )
+ kdFatal(KBABEL_CATMAN) << "CatalogManagerView::slotClearMarkInDir: item not in list" << endl;
+
+ if(item->marked())
+ {
+ _markerList.remove(item->package());
+ }
+ item->setMarked(false);
+ }
+ }
+
+ checkSelected();
+}
+
+
+void CatalogManagerView::slotDirCommand(int index)
+{
+ CatManListItem* item=(CatManListItem*) currentItem();
+
+
+ if(index>=0 && item && item->isDir())
+ {
+ QString cmd=*(_settings.dirCommands).at(index);
+ cmd.replace("@PACKAGE@",item->name());
+ cmd.replace("@PODIR@",item->poFile());
+ cmd.replace("@POTDIR@",item->potFile());
+ cmd.replace("@POFILES@",current().join(" "));
+ cmd.replace("@MARKEDPOFILES@",marked().join(" "));
+
+ kdDebug(KBABEL_CATMAN) << cmd << endl;
+
+ KProcess* proc = new KShellProcess();
+ _pendingProcesses.append(proc);
+
+ connect( proc,SIGNAL( processExited(KProcess *) ), this
+ ,SLOT( processEnded(KProcess*) ) );
+ connect( proc,SIGNAL( receivedStdout(KProcess*,char*,int) ), this
+ ,SLOT( showOutput(KProcess*,char*,int) ) );
+ connect( proc,SIGNAL( receivedStderr(KProcess*,char*,int) ), this
+ ,SLOT( showOutput(KProcess*,char*,int) ) );
+
+ *proc << "cd" << item->poFile() << ";" << cmd;
+ proc->start(KProcess::NotifyOnExit,KProcess::AllOutput);
+ }
+}
+
+void CatalogManagerView::slotFileCommand(int index)
+{
+ CatManListItem* item=(CatManListItem*) currentItem();
+
+ if(index>=0 && item && item->isFile())
+ {
+ CatManListItem* parent = (CatManListItem*)item->parent();
+
+ QString cmd=*(_settings.fileCommands).at(index);
+ cmd.replace("@PACKAGE@",item->name());
+ cmd.replace("@POFILE@",item->poFile());
+ cmd.replace("@POTFILE@",item->potFile());
+ cmd.replace("@PODIR@",parent->poFile());
+ cmd.replace("@POTDIR@",parent->potFile());
+ cmd.replace("@POEMAIL@",item->text(COL_TRANSLATOR));
+
+ kdDebug(KBABEL_CATMAN) << cmd << endl;
+
+ KProcess* proc = new KShellProcess();
+ _pendingProcesses.append(proc);
+
+ connect( proc,SIGNAL( processExited(KProcess *) ), this
+ ,SLOT( processEnded(KProcess*) ) );
+ connect( proc,SIGNAL( receivedStdout(KProcess*,char*,int) ), this
+ ,SLOT( showOutput(KProcess*,char*,int) ) );
+ connect( proc,SIGNAL( receivedStderr(KProcess*,char*,int) ), this
+ ,SLOT( showOutput(KProcess*,char*,int) ) );
+
+ *proc << "cd" << parent->poFile() << ";" << cmd;
+ proc->start(KProcess::NotifyOnExit,KProcess::AllOutput);
+ }
+
+}
+
+
+void CatalogManagerView::updateFile(QString fileWithPath, bool force)
+{
+ QString relFile;
+ if(fileWithPath.startsWith(_settings.poBaseDir))
+ {
+ relFile=fileWithPath.mid(_settings.poBaseDir.length());
+ }
+ else if(fileWithPath.startsWith(_settings.potBaseDir))
+ {
+ relFile=fileWithPath.mid(_settings.potBaseDir.length());
+ }
+ else
+ {
+ return;
+ }
+
+ if(relFile.endsWith(".pot"))
+ {
+ relFile.truncate(relFile.length()-4);
+ }
+ else if(relFile.endsWith(".po"))
+ {
+ relFile.truncate(relFile.length()-3);
+ }
+
+ CatManListItem* item=_fileList[relFile];
+
+ if(item)
+ {
+ _updateNesting++;
+ if( force ) item->forceUpdate();
+ else item->checkUpdate();
+ _updateNesting--;
+ }
+
+}
+
+void CatalogManagerView::updateAfterSave(QString fileWithPath, PoInfo &newInfo)
+{
+ QString relFile;
+ if(fileWithPath.startsWith(_settings.poBaseDir))
+ {
+ relFile=fileWithPath.mid(_settings.poBaseDir.length());
+ }
+ else if(fileWithPath.startsWith(_settings.potBaseDir))
+ {
+ relFile=fileWithPath.mid(_settings.potBaseDir.length());
+ }
+ else
+ {
+ return;
+ }
+
+ if(relFile.endsWith(".pot"))
+ {
+ relFile.truncate(relFile.length()-4);
+ }
+ else if(relFile.endsWith(".po"))
+ {
+ relFile.truncate(relFile.length()-3);
+ }
+
+ CatManListItem* item=_fileList[relFile];
+
+ if(item)
+ {
+ item->updateAfterSave(newInfo);
+ }
+
+}
+
+void CatalogManagerView::buildTree()
+{
+ // in case we were called after settings update
+ disconnect( this, SIGNAL( updateFinished() ), this, SLOT(buildTree() ) );
+
+ emit signalBuildTree(false); // announce start of building
+
+ clear();
+
+ if(isActive())
+ return;
+
+ _updateNesting++;
+
+ _active=true;
+ _stop=false;
+
+
+ CatManListItem* root = new CatManListItem(this, this,_settings.poBaseDir,_settings.potBaseDir);
+ _dirList.insert("/",root);
+ //root->setSelectable(false);
+
+ QFileInfo fileInfo(_settings.poBaseDir);
+ if(!fileInfo.isDir())
+ {
+ KMessageBox::error(this,i18n("You have not specified a valid folder "
+"for the base folder of the PO files:\n%1\n"
+"Please check your settings in the project settings dialog.").arg(_settings.poBaseDir));
+
+ _active=false;
+ _updateNesting--;
+ if( _updateNesting == 0 ) emit updateFinished();
+ return;
+ }
+
+ cvshandler->setPOBaseDir( _settings.poBaseDir );
+ svnhandler->setPOBaseDir( _settings.poBaseDir );
+ mailer->setPOBaseDir(_settings.poBaseDir);
+
+ fileInfo.setFile(_settings.potBaseDir);
+ if(!fileInfo.isDir() && !_settings.potBaseDir.isEmpty())
+ {
+ KMessageBox::error(this,i18n("You have not specified a valid folder "
+"for the base folder of the PO template files:\n%1\n"
+"Please check your settings in the project settings dialog.").arg(_settings.potBaseDir));
+ }
+
+ cvshandler->setPOTBaseDir( _settings.potBaseDir );
+ svnhandler->setPOTBaseDir( _settings.potBaseDir );
+
+ setCursor(KCursor::waitCursor());
+
+ //"/" is the root item
+ buildDir("/",true); // build dir without updating the items...
+
+ if( _stop ) {
+ _active = false;
+ _updateNesting--;
+ if( _updateNesting == 0 ) emit updateFinished();
+ return;
+ }
+
+ _dirWatch->addDir(_settings.poBaseDir);
+ if(!_settings.potBaseDir.isEmpty())
+ _dirWatch->addDir(_settings.potBaseDir);
+
+ emit signalBuildTree(true); // announce beginning of tree building
+
+ unsetCursor();
+
+ if( _stop ) {
+ _active = false;
+ _updateNesting--;
+ if( _updateNesting == 0 ) emit updateFinished();
+ return;
+ }
+
+ updateMarkerList();
+
+ const int files=_fileList.count()+_dirList.count();
+
+ _readInfoCount = 0;
+
+ emit prepareProgressBar(i18n("Reading file information"),files);
+
+ root->setOpen(true);
+
+ if( _stop ) {
+ _active = false;
+ _updateNesting--;
+ if( _updateNesting == 0 ) emit updateFinished();
+ return;
+ }
+
+ // first read information about the files...
+ QDictIterator<CatManListItem> it( _fileList ); // iterator for dict
+
+ int i=0;
+ while ( it.current() && !_stop)
+ {
+ it.current()->checkUpdate(true);
+ ++i;
+ ++it;
+ }
+
+ // ...then update directories
+ QDictIterator<CatManListItem> dit( _dirList ); // iterator for dict
+
+ while ( dit.current() && !_stop)
+ {
+ dit.current()->checkUpdate();
+ ++i;
+ ++dit;
+ }
+
+ emit clearProgressBar();
+
+ _dirWatch->startScan();
+ pause(false);
+
+ _active=false;
+
+ _updateNesting--;
+
+ if( _updateNesting == 0 )
+ {
+ emit updateFinished();
+ }
+}
+
+bool CatalogManagerView::buildDir(QString relDir,bool fast)
+{
+ if( _stop ) return false;
+
+ bool haveTemplateDir=true;
+ QFileInfo fileInfo;
+
+ fileInfo.setFile(_settings.potBaseDir);
+ if(!fileInfo.isDir())
+ {
+ haveTemplateDir=false;
+ }
+
+ bool potHasFiles=false;
+ if(haveTemplateDir)
+ potHasFiles=buildDir(_settings.potBaseDir,relDir,".pot",fast);
+
+ bool poHasFiles=buildDir(_settings.poBaseDir,relDir,".po",fast);
+
+ return (poHasFiles | potHasFiles);
+}
+
+
+bool CatalogManagerView::buildDir(const QString& baseDir,const QString& relDir
+ , const QString extension , bool fast)
+{
+ if( _stop ) return false;
+
+ bool havePoFiles=false;
+
+ CatManListItem* thisItem=_dirList[relDir];
+ if(!thisItem)
+ {
+ kdFatal(KBABEL_CATMAN) << "null pointer to this item" << endl;
+ return false;
+ }
+
+ const QString poBaseDir=_settings.poBaseDir;
+ const QString potBaseDir=_settings.potBaseDir;
+
+ // traverse directory in poBaseDir
+ QDir dir(baseDir+relDir);
+ QStringList entryList=dir.entryList("*"+extension,QDir::Files,QDir::Name);
+
+ QStringList::const_iterator it;
+
+ for ( it = entryList.constBegin(); it != entryList.constEnd() && !_stop ; ++it )
+ {
+ if( _stop ) return false;
+
+ havePoFiles=true;
+
+ QString file=relDir+(*it);
+ file.remove(QRegExp(extension+"$"));
+ CatManListItem* item = _fileList[file];
+ if(!item)
+ {
+ item = new CatManListItem(this,thisItem,poBaseDir+file+".po",potBaseDir+file+".pot",file);
+ _fileList.insert(file,item);
+ _readInfoFileList.prepend(file);
+
+ if(_markerList.contains(file))
+ {
+ item->setMarked(true);
+ }
+
+ if(!fast)
+ {
+ item->checkUpdate();
+ }
+ }
+ }
+
+ entryList=dir.entryList(QDir::Dirs,QDir::Name);
+
+ for ( it = entryList.constBegin(); it != entryList.constEnd() && !_stop ; ++it )
+ {
+ if( _stop ) return false;
+
+ if((*it)=="." || (*it)=="..")
+ {
+ continue;
+ }
+
+ QString subDir=relDir+(*it)+"/";
+ if(!_dirWatch->contains(baseDir+subDir))
+ {
+ _dirWatch->addDir(baseDir+subDir);
+ }
+
+ bool otherHasFiles=true;
+
+ CatManListItem* item = _dirList[subDir];
+ if(!item && !_stop)
+ {
+ item = new CatManListItem(this, thisItem,poBaseDir+subDir,potBaseDir+subDir,subDir);
+ _dirList.insert(subDir,item);
+
+ otherHasFiles=false;
+ }
+
+ if( _stop ) return false;
+
+ // recursive call
+ if(!buildDir(baseDir,subDir,extension,fast) && !otherHasFiles)
+ {
+ kdDebug(KBABEL_CATMAN) << "skipping " << subDir << endl;
+ deleteDirItem(subDir);
+ item=0;
+ }
+ else
+ havePoFiles=true;
+
+ } // end looking up directories in po base dir
+
+ return havePoFiles;
+}
+
+
+void CatalogManagerView::updateDir(QString relDir)
+{
+ if( _stop ) return;
+
+ kdDebug(KBABEL_CATMAN) << "updating dir " << relDir << endl;
+
+ bool havePoFiles=false;
+
+ CatManListItem* thisItem=_dirList[relDir];
+ if(!thisItem)
+ {
+ kdFatal(KBABEL_CATMAN) << "null pointer to this item" << endl;
+ return;
+ }
+
+ QStringList contentList = thisItem->contentsList(true);
+
+ const QString poBaseDir=_settings.poBaseDir;
+ const QString potBaseDir=_settings.potBaseDir;
+
+ // first lookup template directory
+ QDir dir(potBaseDir+relDir);
+ QStringList entryList=dir.entryList("*.pot",QDir::Files,QDir::Name);
+
+ QStringList::const_iterator it;
+
+ for ( it = entryList.constBegin(); it != entryList.constEnd(); ++it )
+ {
+ if( _stop ) return;
+
+ havePoFiles=true;
+
+ QString file=relDir+(*it);
+ file.remove(QRegExp(".pot$"));
+ CatManListItem* item = _fileList[file];
+ if(!item)
+ {
+ item = new CatManListItem(this, thisItem,poBaseDir+file+".po",potBaseDir+file+".pot",file);
+ _fileList.insert(file,item);
+
+ if(_markerList.contains(file))
+ {
+ item->setMarked(true);
+ }
+
+ item->checkUpdate();
+ }
+ else
+ {
+ item->checkUpdate();
+ }
+
+ contentList.remove(file);
+ }
+
+ entryList=dir.entryList(QDir::Dirs,QDir::Name);
+
+ for ( it = entryList.constBegin(); it != entryList.constEnd(); ++it )
+ {
+ if( _stop ) return;
+
+ if((*it)=="." || (*it)=="..")
+ {
+ continue;
+ }
+
+ bool newDirAdded=false;
+
+ QString subDir=relDir+(*it)+"/";
+ if(!_dirWatch->contains(potBaseDir+subDir))
+ {
+ _dirWatch->addDir(potBaseDir+subDir);
+
+ newDirAdded=true;
+ }
+
+ CatManListItem* item = _dirList[subDir];
+ if(!item && newDirAdded)
+ {
+ item = new CatManListItem(this, thisItem,poBaseDir+subDir,potBaseDir+subDir,subDir);
+ _dirList.insert(subDir,item);
+
+ if(!buildDir(subDir,false))
+ {
+ kdDebug(KBABEL_CATMAN) << "skipping " << subDir << endl;
+ deleteDirItem(subDir);
+ item=0;
+ }
+ }
+ else if(newDirAdded)
+ {
+ updateDir(subDir);
+ }
+
+
+ // if directory was already here, but no item
+ // -> directory contains no files
+ if(item && !newDirAdded)
+ {
+ havePoFiles=true;
+ }
+
+ } // end looking up directories in template dir
+
+ // now traverse directory in poBaseDir
+ dir.setPath(poBaseDir+relDir);
+ entryList=dir.entryList("*.po",QDir::Files,QDir::Name);
+
+ for ( it = entryList.constBegin(); it != entryList.constEnd(); ++it )
+ {
+ havePoFiles=true;
+
+ if( _stop ) return;
+
+ QString file=relDir+(*it);
+ file.remove(QRegExp(".po$"));
+ CatManListItem* item = _fileList[file];
+ if(!item)
+ {
+ item = new CatManListItem(this, thisItem,poBaseDir+file+".po",potBaseDir+file+".pot",file);
+ _fileList.insert(file,item);
+
+ if(_markerList.contains(file))
+ {
+ item->setMarked(true);
+ }
+
+ item->checkUpdate();
+ }
+ else
+ {
+ item->checkUpdate();
+ }
+
+ contentList.remove(file);
+ }
+
+ entryList=dir.entryList(QDir::Dirs,QDir::Name);
+
+ for ( it = entryList.constBegin(); it != entryList.constEnd(); ++it )
+ {
+ if( _stop ) return;
+
+ if((*it)=="." || (*it)=="..")
+ {
+ continue;
+ }
+
+ bool newDirAdded=false;
+
+ QString subDir=relDir+(*it)+"/";
+ if(!_dirWatch->contains(poBaseDir+subDir))
+ {
+ _dirWatch->addDir(poBaseDir+subDir);
+ newDirAdded=true;
+ }
+
+ CatManListItem* item = _dirList[subDir];
+
+ bool templateHasFiles=(bool)item;
+
+ if(!item && newDirAdded)
+ {
+ item = new CatManListItem(this, thisItem,poBaseDir+subDir,potBaseDir+subDir,subDir);
+ _dirList.insert(subDir,item);
+
+ if(!buildDir(subDir,false) && !templateHasFiles)
+ {
+ kdDebug(KBABEL_CATMAN) << "skipping " << subDir << endl;
+ deleteDirItem(subDir);
+ item=0;
+ }
+ }
+ else if(newDirAdded)
+ {
+ updateDir(subDir);
+ }
+
+ // if directory was already here, but no item
+ // -> directory contains no files
+ if(item && !newDirAdded)
+ {
+ havePoFiles=true;
+ }
+
+
+ } // end looking up directories in po base dir
+
+
+ // check, if something in the directory has been deleted
+ // but only if we traversed also the template directory
+ if(contentList.count()>0)
+ {
+ QStringList::const_iterator it;
+ for( it = contentList.constBegin(); it != contentList.constEnd(); ++it )
+ {
+ QFileInfo po(poBaseDir+(*it));
+ QFileInfo pot(potBaseDir+(*it));
+
+ if(!po.exists() && !pot.exists())
+ {
+ CatManListItem* item = _fileList[(*it)];
+ if(item)
+ {
+ if(item->marked())
+ _markerList.remove(item->package());
+
+ _fileList.remove((*it));
+ delete item;
+ }
+ }
+ }
+ }
+
+ if(!havePoFiles)
+ {
+ deleteDirItem(relDir);
+
+ // if this directory has to be removed, check, if
+ // the parent directory has to be removed too
+ const int index=relDir.findRev("/",relDir.length()-2);
+ if(index<0)
+ {
+ relDir="/";
+ }
+ relDir=relDir.left(index+1);
+ updateDir(relDir);
+ }
+}
+
+void CatalogManagerView::directoryChanged(const QString& dir)
+{
+ pause(true);
+
+ QString relDir, relDirPo, relDirPot;
+ if(dir.startsWith(_settings.poBaseDir))
+ {
+ relDirPo=dir.mid(_settings.poBaseDir.length());
+ }
+ if(dir.startsWith(_settings.potBaseDir))
+ {
+ relDirPot=dir.mid(_settings.potBaseDir.length());
+ }
+
+ if( relDirPo.isEmpty() )
+ {
+ // use POT
+ relDir = relDirPot;
+ }
+ else if( relDirPot.isEmpty() )
+ {
+ // use PO
+ relDir = relDirPo;
+ }
+ else
+ {
+ // both PO and POT usable, find out the correct one
+ if( relDirPo.left(1) == "/" )
+ {
+ relDir = relDirPo;
+ }
+ else
+ {
+ relDir = relDirPot;
+ }
+ }
+
+ if(relDir.right(1)!="/")
+ {
+ relDir+="/";
+ }
+
+ kdDebug(KBABEL_CATMAN) << "directory changed: " << relDir << endl;
+
+ QFileInfo fileInfo(_settings.potBaseDir);
+
+ CatManListItem* thisItem=_dirList[relDir];
+ if(!thisItem)
+ {
+ // if this item is not in the list search for next existing parent item
+ QString prevRelDir;
+ do
+ {
+ prevRelDir=relDir;
+ const int index=relDir.findRev("/",relDir.length()-2);
+ if(index<0)
+ {
+ relDir="/";
+ }
+ relDir=relDir.left(index+1);
+
+ thisItem=_dirList[relDir];
+ }
+ while(relDir!="/" && !thisItem);
+
+ if(!thisItem)
+ {
+ kdFatal(KBABEL_CATMAN) << "null pointer to this item: " << relDir << endl;
+ return;
+ }
+ else
+ {
+ // if a parent item dir is found, create the needed item in this dir
+ // and build the tree from this item on
+ kdDebug(KBABEL_CATMAN) << "building dir: " << prevRelDir << endl;
+ CatManListItem* item = new CatManListItem(this, thisItem,_settings.poBaseDir+prevRelDir
+ ,_settings.potBaseDir+prevRelDir,prevRelDir);
+ _dirList.insert(prevRelDir,item);
+
+
+ if(!buildDir(prevRelDir,false))
+ {
+ deleteDirItem(prevRelDir);
+ }
+ }
+ }
+ else
+ {
+ updateDir(relDir);
+ }
+
+ pause(false);
+}
+
+
+void CatalogManagerView::directoryDeleted(const QString& dir)
+{
+ pause(true);
+
+ QString relDir, relDirPo, relDirPot;
+ if(dir.startsWith(_settings.poBaseDir))
+ {
+ relDirPo=dir.mid(_settings.poBaseDir.length());
+ }
+ if(dir.startsWith(_settings.potBaseDir))
+ {
+ relDirPot=dir.mid(_settings.potBaseDir.length());
+ }
+
+ if( relDirPo.isEmpty() )
+ {
+ // use POT
+ relDir = relDirPot;
+ }
+ else if( relDirPot.isEmpty() )
+ {
+ // use PO
+ relDir = relDirPo;
+ }
+ else
+ {
+ // both PO and POT usable, find out the correct one
+ if( relDirPo.left(1) == "/" )
+ {
+ relDir = relDirPo;
+ }
+ else
+ {
+ relDir = relDirPot;
+ }
+ }
+
+ if(relDir.right(1)!="/")
+ {
+ relDir+="/";
+ }
+
+ kdDebug(KBABEL_CATMAN) << "directory deleted: " << relDir << endl;
+
+ CatManListItem* thisItem=_dirList[relDir];
+ if(thisItem)
+ {
+ // we have to take care, if one directory still exists
+ const bool poDeleted=!thisItem->hasPo();
+ const bool potDeleted=!thisItem->hasPot();
+
+ // if neither the po- nor the pot-directory exists any more
+ // delete all sub items
+ if(poDeleted && potDeleted)
+ {
+ deleteDirItem(relDir);
+ }
+ else
+ {
+ QStringList childList = thisItem->contentsList();
+
+ CatManListItem* item;
+ QStringList::const_iterator it;
+ for( it = childList.constBegin();it != childList.constEnd(); ++it )
+ {
+ item=_fileList[(*it)];
+ if(item)
+ {
+ if( (poDeleted && !item->hasPot()) ||
+ (potDeleted && !item->hasPo()) )
+ {
+ _fileList.remove((*it));
+ delete item;
+ }
+ else
+ {
+ item->checkUpdate();
+ }
+ }
+ else
+ {
+ item=_dirList[(*it)];
+ if(item)
+ {
+ if( (poDeleted && !item->hasPot()) ||
+ (potDeleted && !item->hasPo()) )
+ {
+ deleteDirItem((*it));
+ }
+ }
+ else
+ {
+ kdDebug(KBABEL_CATMAN) << "directoryDeleted: don't have item "
+ << (*it) << endl;
+ }
+ }
+ }
+ }
+ }
+
+ pause(false);
+}
+
+void CatalogManagerView::fileInfoRead( QString filename )
+{
+ if( _readInfoFileList.find( filename ) != _readInfoFileList.end() ) {
+ emit progress( ++_readInfoCount);
+ _readInfoFileList.remove( filename );
+ }
+
+ if( _readInfoFileList.isEmpty() ) emit clearProgressBar();
+}
+
+void CatalogManagerView::setSettings(CatManSettings newSettings)
+{
+ CatManSettings oldSettings=_settings;
+ _settings=newSettings;
+
+ if(_settings.poBaseDir.right(1)=="/")
+ _settings.poBaseDir.truncate(_settings.poBaseDir.length()-1);
+ if(_settings.potBaseDir.right(1)=="/")
+ _settings.potBaseDir.truncate(_settings.potBaseDir.length()-1);
+
+ _dirCommandsMenu->clear();
+ int counter=0;
+ for ( QStringList::const_iterator it = _settings.dirCommandNames.constBegin()
+ ; it != _settings.dirCommandNames.constEnd(); ++it )
+ {
+ _dirCommandsMenu->insertItem((*it),counter);
+ counter++;
+ }
+ _dirCommandsMenu->insertSeparator();
+ _dirCommandsMenu->insertItem(i18n("Log Window"),this,SLOT(showLog()));
+
+ _fileCommandsMenu->clear();
+ counter=0;
+ for ( QStringList::const_iterator it = _settings.fileCommandNames.constBegin()
+ ; it != _settings.fileCommandNames.constEnd(); ++it )
+ {
+ _fileCommandsMenu->insertItem((*it),counter);
+ counter++;
+ }
+ _fileCommandsMenu->insertSeparator();
+ _fileCommandsMenu->insertItem(i18n("Log Window"),this,SLOT(showLog()));
+
+ const bool pathChanged = (oldSettings.poBaseDir!=_settings.poBaseDir)
+ || (oldSettings.potBaseDir!=_settings.potBaseDir);
+
+ if(pathChanged)
+ {
+ if( !isActive() ) {
+ QTimer::singleShot(100,this,SLOT(buildTree()));
+ } else {
+ stop();
+ connect( this, SIGNAL( updateFinished() ), this, SLOT(buildTree() ) );
+ }
+ }
+
+ toggleColumn( COL_MARKER, _settings.flagColumn );
+ toggleColumn( COL_FUZZY, _settings.fuzzyColumn );
+ toggleColumn( COL_UNTRANS, _settings.untranslatedColumn );
+ toggleColumn( COL_TOTAL, _settings.totalColumn );
+ // FIXME: follow CVS/SVN status
+ toggleColumn( COL_CVS_OR_SVN, _settings.cvsColumn );
+ toggleColumn( COL_REVISION, _settings.revisionColumn );
+ toggleColumn( COL_TRANSLATOR, _settings.translatorColumn );
+}
+
+
+CatManSettings CatalogManagerView::settings() const
+{
+ return _settings;
+}
+
+
+void CatalogManagerView::hideEvent(QHideEvent*)
+{
+ pause(true);
+
+ if(_dirWatch)
+ _dirWatch->stopScan();
+}
+
+void CatalogManagerView::showEvent(QShowEvent*)
+{
+ QTimer::singleShot(1,this,SLOT(checkUpdate()));
+
+ pause(false);
+
+ if(_dirWatch)
+ _dirWatch->startScan(true);
+}
+
+void CatalogManagerView::contentsMousePressEvent(QMouseEvent* event)
+{
+ if(event->button() == LeftButton)
+ _pressPos=event->pos();
+
+ QListView::contentsMousePressEvent( event );
+}
+
+void CatalogManagerView::contentsMouseMoveEvent(QMouseEvent* event)
+{
+ if(event->state() & LeftButton)
+ {
+ const int delay = KGlobalSettings::dndEventDelay();
+ if(QABS( event->pos().x() - _pressPos.x() ) >= delay ||
+ QABS( event->pos().y() - _pressPos.y() ) >= delay)
+ {
+ CatManListItem* item = (CatManListItem*)itemAt(contentsToViewport(_pressPos));
+ if(item && item->isFile())
+ {
+ // always add the po-file and if existing the pot-file to the drag and
+ // let the user decide what to do, when dropping into kbabel
+ QStrList uri;
+ uri.append(QUriDrag::localFileToUri(item->poFile()));
+ if(item->hasPot())
+ uri.append(QUriDrag::localFileToUri(item->potFile()));
+
+ QUriDrag* drag = new QUriDrag(uri,this);
+ QPixmap icon=KGlobal::iconLoader()->loadIcon("txt",KIcon::Desktop);
+ drag->setPixmap(icon,QPoint(icon.width()/2,icon.height()/2));
+ drag->drag();
+ }
+ else
+ {
+ QListView::contentsMouseMoveEvent(event);
+ }
+ }
+ else
+ {
+ QListView::contentsMouseMoveEvent(event);
+ }
+ }
+ else
+ {
+ QListView::contentsMouseMoveEvent(event);
+ }
+}
+
+void CatalogManagerView::readMarker( KConfig* config)
+{
+ KConfigGroupSaver cs(config,"CatalogManager");
+
+ _markerList = config->readListEntry("Marker");
+}
+
+void CatalogManagerView::saveMarker( KConfig* config) const
+{
+ KConfigGroupSaver cs(config,"CatalogManager");
+
+ config->writeEntry("Marker",_markerList);
+ config->sync();
+}
+
+
+void CatalogManagerView::deleteDirItem(QString relDir)
+{
+ CatManListItem* thisItem=_dirList[relDir];
+
+ if(!thisItem)
+ return;
+
+ _dirList.remove(relDir);
+
+ QStringList childList = thisItem->allChildrenList();
+
+ QStringList::const_iterator it;
+ for( it = childList.constBegin();it != childList.constEnd(); ++it )
+ {
+ if(!_fileList.remove((*it)))
+ _dirList.remove((*it));
+ }
+
+
+ // delete the item with all sub item
+ delete thisItem;
+}
+
+
+
+void CatalogManagerView::processEnded(KProcess* proc)
+{
+ _pendingProcesses.removeRef(proc);
+}
+
+
+void CatalogManagerView::showOutput(KProcess*, char *buffer, int buflen)
+{
+ const QCString output(buffer,buflen+1);
+
+ _logView->insert(output);
+}
+
+void CatalogManagerView::columnClicked(QListViewItem * item, const QPoint &, int c)
+{
+ if( item && c == COL_MARKER )
+ {
+ slotToggleMark();
+ }
+}
+
+CatManListItem *CatalogManagerView::itemBelow( CatManListItem *item )
+{
+ if( item->isDir() )
+ {
+ if( item->firstChild() )
+ return static_cast<CatManListItem *>( item->firstChild() );
+ else
+ {
+ while( !static_cast<CatManListItem *>( item->nextSibling() ) )
+ {
+ item = static_cast<CatManListItem *>( item->parent() );
+ if( !item ) return item;
+ }
+ return static_cast<CatManListItem *>( item->nextSibling() );
+ }
+ }
+ else
+ {
+ while( !static_cast<CatManListItem *>( item->nextSibling() ) )
+ {
+ item = static_cast<CatManListItem *>( item->parent());
+ if( !item ) return item;
+ }
+ return static_cast<CatManListItem *>( item->nextSibling() );
+ }
+}
+
+CatManListItem *CatalogManagerView::itemAbove( CatManListItem *item )
+{
+ if( item->isDir() )
+ {
+ if( item->firstChild() )
+ return static_cast<CatManListItem *>( item->lastChild() );
+ else
+ {
+ while( !static_cast<CatManListItem *>( item->previousSibling() ) )
+ {
+ item = static_cast<CatManListItem *>( item->parent() );
+ if( !item ) return item;
+ }
+ return static_cast<CatManListItem *>( item->previousSibling() );
+ }
+ }
+ else
+ {
+ while( !static_cast<CatManListItem *>( item->previousSibling() ) )
+ {
+ item = static_cast<CatManListItem *>( item->parent());
+ if( !item ) return item;
+ }
+ return static_cast<CatManListItem *>( item->previousSibling() );
+ }
+}
+
+void CatalogManagerView::gotoNextUntranslated()
+{
+ CatManListItem *i;
+ CatManListItem *current = static_cast<CatManListItem *>(currentItem());
+ while( ( i = itemBelow(current)) )
+ {
+ if( i->untranslated() > 0 )
+ {
+ setCurrentItem(i);
+ ensureItemVisible(i);
+ return;
+ } else current = i;
+ }
+}
+
+void CatalogManagerView::gotoPreviousUntranslated()
+{
+ CatManListItem *i;
+ CatManListItem *current = static_cast<CatManListItem *>(currentItem());
+ while( (i = itemAbove(current)) )
+ {
+ if( i->untranslated() > 0 )
+ {
+ setCurrentItem(i);
+ ensureItemVisible(i);
+ return;
+ } else current = i;
+ }
+}
+
+void CatalogManagerView::gotoNextFuzzy()
+{
+ CatManListItem *i;
+ CatManListItem *current = static_cast<CatManListItem *>(currentItem());
+ while( ( i = itemBelow(current)) )
+ {
+ if( i->fuzzy() > 0 )
+ {
+ setCurrentItem(i);
+ ensureItemVisible(i);
+ return;
+ } else current = i;
+ }
+}
+
+void CatalogManagerView::gotoPreviousFuzzy()
+{
+ CatManListItem *i;
+ CatManListItem *current = static_cast<CatManListItem *>(currentItem());
+ while( (i = itemAbove(current)) )
+ {
+ if( i->fuzzy() > 0 )
+ {
+ setCurrentItem(i);
+ ensureItemVisible(i);
+ return;
+ } else current = i;
+ }
+}
+
+void CatalogManagerView::gotoNextFuzzyOrUntranslated()
+{
+ CatManListItem *i;
+ CatManListItem *current = static_cast<CatManListItem *>(currentItem());
+ while( ( i = itemBelow(current)) )
+ {
+ if( i->untranslated() > 0 || i->fuzzy() > 0 )
+ {
+ setCurrentItem(i);
+ ensureItemVisible(i);
+ return;
+ } else current = i;
+ }
+}
+
+void CatalogManagerView::gotoPreviousFuzzyOrUntranslated()
+{
+ CatManListItem *i;
+ CatManListItem *current = static_cast<CatManListItem *>(currentItem());
+ while( (i = itemAbove(current)) )
+ {
+ if( i->untranslated() > 0 || i->fuzzy() > 0 )
+ {
+ setCurrentItem(i);
+ ensureItemVisible(i);
+ return;
+ } else current = i;
+ }
+}
+
+void CatalogManagerView::gotoNextError()
+{
+ CatManListItem *i;
+ CatManListItem *current = static_cast<CatManListItem *>(currentItem());
+ while( ( i = itemBelow(current)) )
+ {
+ if( i->hasErrors() )
+ {
+ setCurrentItem(i);
+ ensureItemVisible(i);
+ return;
+ } else current = i;
+ }
+}
+
+void CatalogManagerView::gotoPreviousError()
+{
+ CatManListItem *i;
+ CatManListItem *current = static_cast<CatManListItem *>(currentItem());
+ while( (i = itemAbove(current)) )
+ {
+ if( i->hasErrors() )
+ {
+ setCurrentItem(i);
+ ensureItemVisible(i);
+ return;
+ } else current = i;
+ }
+}
+
+void CatalogManagerView::gotoNextTemplate()
+{
+ CatManListItem *i;
+ CatManListItem *current = static_cast<CatManListItem *>(currentItem());
+ while( ( i = itemBelow(current)) )
+ {
+ if( i->hasPot() && !i->hasPo() )
+ {
+ setCurrentItem(i);
+ ensureItemVisible(i);
+ return;
+ } else current = i;
+ }
+}
+
+void CatalogManagerView::gotoPreviousTemplate()
+{
+ CatManListItem *i;
+ CatManListItem *current = static_cast<CatManListItem *>(currentItem());
+ while( (i = itemAbove(current)) )
+ {
+ if( i->hasPot() && !i->hasPo() )
+ {
+ setCurrentItem(i);
+ ensureItemVisible(i);
+ return;
+ } else current = i;
+ }
+}
+
+void CatalogManagerView::gotoNextPo()
+{
+ CatManListItem *i;
+ CatManListItem *current = static_cast<CatManListItem *>(currentItem());
+ while( ( i = itemBelow(current)) )
+ {
+ if( i->hasPo() )
+ {
+ setCurrentItem(i);
+ ensureItemVisible(i);
+ return;
+ } else current = i;
+ }
+}
+
+void CatalogManagerView::gotoPreviousPo()
+{
+ CatManListItem *i;
+ CatManListItem *current = static_cast<CatManListItem *>(currentItem());
+ while( (i = itemAbove(current)) )
+ {
+ if( i->hasPo() )
+ {
+ setCurrentItem(i);
+ ensureItemVisible(i);
+ return;
+ } else current = i;
+ }
+}
+
+void CatalogManagerView::gotoNextMarked()
+{
+ CatManListItem *i;
+ CatManListItem *current = static_cast<CatManListItem *>(currentItem());
+ while( ( i = itemBelow(current)) )
+ {
+ if( i->marked() )
+ {
+ setCurrentItem(i);
+ ensureItemVisible(i);
+ return;
+ } else current = i;
+ }
+}
+
+void CatalogManagerView::gotoPreviousMarked()
+{
+ CatManListItem *i;
+ CatManListItem *current = static_cast<CatManListItem *>(currentItem());
+ while( (i = itemAbove(current)) )
+ {
+ if( i->marked() )
+ {
+ setCurrentItem(i);
+ ensureItemVisible(i);
+ return;
+ } else current = i;
+ }
+}
+
+QStringList CatalogManagerView::current()
+{
+ QStringList result;
+ CatManListItem *current = static_cast<CatManListItem *>(currentItem());
+ if( current->isDir() )
+ {
+ QStringList s = current->allChildrenList(true);
+ QStringList::const_iterator it;
+ for( it = s.constBegin() ; it != s.constEnd(); ++it )
+ {
+ CatManListItem *item = _fileList[(*it)];
+ result.append( item->poFile() );
+ }
+ }
+ else
+ {
+ if( current->hasPo() ) result.append( current->poFile() );
+ }
+ return result;
+}
+
+QStringList CatalogManagerView::marked()
+{
+ QStringList result;
+
+ QStringList::const_iterator it;
+ for( it = _markerList.constBegin() ; it != _markerList.constEnd(); ++it )
+ {
+ CatManListItem *item = _fileList[(*it)];
+ result.append( item->poFile() );
+ }
+ return result;
+}
+
+void CatalogManagerView::updateCurrent()
+{
+ CatManListItem *current = static_cast<CatManListItem *>(currentItem());
+ if( !current->hasPo() && !current->hasPot() )
+ {
+ if( current->isFile() )
+ {
+ _fileList.remove(current->package());
+ delete current;
+ }
+ else
+ {
+ directoryDeleted(current->package());
+ }
+ }
+ else
+ {
+ if( current->isDir() )
+ {
+ directoryChanged(current->poFile() );
+ }
+
+ // check, if the item didn't get lost by the update in directoryChanged()
+ CatManListItem *new_current = static_cast<CatManListItem *>(currentItem());
+ if (new_current == current)
+ {
+ current->forceUpdate();
+ }
+ }
+}
+
+void CatalogManagerView::updateFiles( const QStringList& files )
+{
+ QStringList::ConstIterator it;
+ for ( it = files.constBegin( ); it != files.constEnd( ); ++it ) {
+ updateFile( *it, true );
+ }
+}
+
+CVSHandler * CatalogManagerView::cvsHandler( )
+{
+ return cvshandler;
+}
+
+SVNHandler * CatalogManagerView::svnHandler( )
+{
+ return svnhandler;
+}
+
+void CatalogManagerView::validateUsingTool( const KDataToolInfo &tool, const QString& command )
+{
+ QStringList result;
+ CatManListItem *current = static_cast<CatManListItem *>(currentItem());
+ if( current->isDir() )
+ {
+ const QStringList s = current->allChildrenList(true);
+ QStringList::const_iterator it;
+ for( it = s.constBegin() ; it != s.constEnd(); ++it )
+ {
+ CatManListItem *item = _fileList[(*it)];
+ if( item && item->hasPo() ) result.append( item->package() );
+ }
+ }
+ else
+ {
+ result.append( current->package() );
+ }
+
+ validate_internal( result, tool, command );
+}
+
+void CatalogManagerView::validateMarkedUsingTool( const KDataToolInfo &tool, const QString& command )
+{
+ validate_internal( _markerList, tool, command );
+}
+
+void CatalogManagerView::validate_internal( const QStringList& files, const KDataToolInfo &tool, const QString& )
+{
+ if( files.isEmpty() ) return;
+
+ KDataTool* t = tool.createTool();
+
+ if( !t )
+ {
+ KMessageBox::error( this, i18n("Cannot instantiate a validation tool.\n"
+ "Please check your installation."), i18n("Validation Tool Error") );
+ return;
+ }
+
+ // setup options
+ if( !_validateOptionsDlg )
+ {
+ _validateOptionsDlg = new KDialogBase( this, "validation options",
+ true, i18n("Validation Options"), KDialogBase::Ok|KDialogBase::Cancel);
+ _validateOptions = new ValidationOptions(_validateOptionsDlg);
+ _validateOptionsDlg->setMainWidget( _validateOptions );
+ _validateOptions->resize( _validateOptions->sizeHint() );
+
+ // setup stored values
+ _validateOptions->markAsFuzzy->setChecked( _markAsFuzzy );
+ _validateOptions->ignoreFuzzy->setChecked( _ignoreFuzzy );
+ }
+
+ if( _validateOptionsDlg->exec() != QDialog::Accepted )
+ {
+ delete t;
+
+ return;
+ }
+
+ if( !_validateDialog )
+ {
+ _validateDialog = new ValidateProgressDialog(_settings.ignoreURL, this);
+ connect( _validateDialog, SIGNAL( errorDoubleClicked(const QString,const int)),
+ this, SLOT(showError( const QString, const int )));
+ }
+
+ _markAsFuzzy = _validateOptions->markAsFuzzy->isChecked();
+ _ignoreFuzzy = _validateOptions->ignoreFuzzy->isChecked();
+
+ _validateDialog->setMarkAsFuzzy(_markAsFuzzy);
+ _validateDialog->setIgnoreFuzzy(_ignoreFuzzy);
+
+ QPtrList<CatManListItem> fileitems;
+
+ for( QValueListConstIterator<QString> it=files.begin() ; it!=files.end() ; ++it )
+ {
+ CatManListItem* item=_fileList[ (*it) ];
+ if( item ) {
+ fileitems.append(item);
+ } else kdDebug(KBABEL_CATMAN) << "Cannot find the file item for " << (*it) << endl;
+ }
+
+ _validateDialog->validate(tool, fileitems);
+
+ delete t;
+}
+
+void CatalogManagerView::showError( const QString package, const int num )
+{
+ CatManListItem* item = _fileList[ package];
+ if( !item )
+ {
+ kdWarning() << "Can not find error package: " << package << endl;
+ return;
+ }
+
+ emit gotoFileEntry( item->poFile(), package, num );
+}
+
+void CatalogManagerView::updateMarkerList()
+{
+ QStringList newMarkers;
+
+ for( QStringList::const_iterator it = _markerList.constBegin(); it != _markerList.constEnd(); ++it ) {
+ if( _fileList[ (*it) ] )
+ newMarkers.append( (*it) );
+ }
+
+ _markerList = newMarkers;
+}
+
+void CatalogManagerView::slotValidPOCVSRepository( bool valid )
+{
+ m_validPOCVSRepository = valid;
+ slotToggleCVSOrSVNColumn(valid);
+ // set initial state for CVS menu entries
+ emit selectedChanged(NEEDS_PO + NEEDS_PO_CVS * m_validPOCVSRepository);
+}
+
+void CatalogManagerView::slotValidPOSVNRepository( bool valid )
+{
+ m_validPOSVNRepository = valid;
+ slotToggleCVSOrSVNColumn(valid);
+ // set initial state for SVN menu entries
+ emit selectedChanged(NEEDS_PO + NEEDS_PO_SVN * m_validPOSVNRepository);
+}
+
+void CatalogManagerView::slotValidPOTCVSRepository( bool valid )
+{
+ m_validPOTCVSRepository = valid;
+ // set initial state for CVS menu entries
+ // ### TODO: something missing here?
+}
+
+void CatalogManagerView::slotValidPOTSVNRepository( bool valid )
+{
+ m_validPOTSVNRepository = valid;
+ // set initial state for SVN menu entries
+ // ### TODO: something missing here?
+}
+
+void CatalogManagerView::slotToggleCVSOrSVNColumn( bool show )
+{
+#if 0
+ toggleColumn( COL_CVS_OR_SVN, show );
+#else
+ // ### HACK
+ toggleColumn( COL_CVS_OR_SVN, m_validPOCVSRepository || m_validPOSVNRepository );
+
+#endif
+}
+
+void CatalogManagerView::toggleColumn( uint column, bool show )
+{
+ if ( show ) {
+ setColumnWidthMode( column, Maximum );
+ setColumnWidth( column, -1 );
+ // ensure that the column heading is always fully visible
+ setColumnText( column, COLTEXT(column));
+ } else {
+ setColumnWidthMode( column, Manual );
+ setColumnWidth( column, 0 );
+ }
+}
+
+#include "catalogmanagerview.moc"
+// kate: space-indent on; indent-width 4; replace-tabs on;
diff --git a/kbabel/catalogmanager/catalogmanagerview.h b/kbabel/catalogmanager/catalogmanagerview.h
new file mode 100644
index 00000000..e4421973
--- /dev/null
+++ b/kbabel/catalogmanager/catalogmanagerview.h
@@ -0,0 +1,474 @@
+/* ****************************************************************************
+ This file is part of KBabel
+
+ Copyright (C) 1999-2000 by Matthias Kiefer
+ <matthias.kiefer@gmx.de>
+ 2001-2004 by Stanislav Visnovsky <visnovsky@kde.org>
+ Copyright (C) 2005, 2006 by Nicolas GOUTTE <goutte@kde.org>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the 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, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+ In addition, as a special exception, the copyright holders give
+ permission to link the code of this program with any edition of
+ the Qt library by Trolltech AS, Norway (or with modified versions
+ of Qt that use the same license as Qt), and distribute linked
+ combinations including the two. You must obey the GNU General
+ Public License in all respects for all of the code used other than
+ Qt. If you modify this file, you may extend this exception to
+ your version of the file, but you are not obligated to do so. If
+ you do not wish to do so, delete this exception statement from
+ your version.
+
+**************************************************************************** */
+#ifndef CATALOGMANAGERVIEW_H
+#define CATALOGMANAGERVIEW_H
+
+#include <qdict.h>
+#include <qlistview.h>
+#include <qdatetime.h>
+#include <qtimer.h>
+#include <qfileinfo.h>
+#include <qguardedptr.h>
+
+#include <kdialogbase.h>
+#include <kdirwatch.h>
+#include <kprocess.h>
+#include <qptrlist.h>
+
+#include "kbproject.h"
+#include "projectsettings.h"
+#include "findoptions.h"
+#include "cvsresources.h"
+#include "svnresources.h"
+
+class CatManListItem;
+class QPixmap;
+class QPopupMenu;
+class KBabelDictBox;
+class CatManPreferences;
+class QTextEdit;
+class KProgress;
+class KConfig;
+class KDataToolInfo;
+class ValidateProgressDialog;
+class CVSHandler;
+class SVNHandler;
+class MarkPatternDialog;
+class ValidationOptions;
+
+namespace KBabel
+{
+ class KBabelMailer;
+ class PoInfo;
+}
+
+class CatalogManagerView : public QListView
+{
+ Q_OBJECT
+public:
+ CatalogManagerView(KBabel::Project::Ptr project, QWidget* parent=0, const char* name=0);
+ virtual ~CatalogManagerView();
+
+ KBabel::CatManSettings settings() const;
+ /** clears the tree */
+ virtual void clear();
+
+ /** pauses the update timer */
+ void pause(bool);
+
+ /** if file fileWithPath exists in the treeview, this is updated */
+ void updateFile(QString fileWithPath, bool force = false);
+
+ void updateAfterSave(QString fileWithPath, KBabel::PoInfo &info);
+
+ bool isActive() const {return _active;}
+ bool isStopped() const {return _stop;}
+
+ void restoreView(KConfig *config);
+ void saveView(KConfig *config) const;
+
+ void setRMBMenuFile( QPopupMenu *m);
+ void setRMBMenuDir( QPopupMenu *m);
+ void setDirCommandsMenu( QPopupMenu *m);
+ void setFileCommandsMenu( QPopupMenu *m);
+
+ CVSHandler * cvsHandler();
+ SVNHandler * svnHandler();
+
+public slots:
+ void setSettings(KBabel::CatManSettings newSettings);
+ void toggleMark();
+ /**
+ * removes all marks in directory of current item (must be a directory)
+ */
+ void slotClearMarksInDir();
+ void clearAllMarks();
+ void toggleAllMarks();
+ void markModifiedFiles();
+ void loadMarks();
+ void saveMarks();
+ void slotMarkPattern( );
+ void slotUnmarkPattern( );
+ /**
+ * traverses all childs in the directory of the current item
+ * (including all subdirectories) and displays some statistics
+ * about the translations. If the item is a file, its
+ * parent directory is used instead.
+ */
+ void statistics();
+ /**
+ * traverses all marked childs in the directory of the current item
+ * (including all subdirectories) and displays some statistics
+ * about the translations. If the item is a file, its
+ * parent directory is used instead.
+ */
+ void markedStatistics();
+ /**
+ * calls @ref Msgfmt::checkSyntax, to check the po-file of
+ * the selected item
+ */
+ void checkSyntax();
+
+ void roughTranslation();
+ void markedRoughTranslation();
+
+ /** Send the selected item as a compressed mail attachment. If the
+ * selected item is a directory send the items contained in the
+ * directory.
+ */
+ void mailFiles();
+ /** Send the marked items as a compressed mail attachment.
+ */
+ void mailMarkedFiles();
+
+ void packageFiles();
+ void packageMarkedFiles();
+
+ void cvsUpdate( );
+ void cvsUpdateMarked( );
+ void cvsCommit( );
+ void cvsCommitMarked( );
+ void cvsStatus( );
+ void cvsStatusMarked( );
+ void cvsUpdateTemplate( );
+ void cvsUpdateMarkedTemplate( );
+ void cvsCommitTemplate( );
+ void cvsCommitMarkedTemplate( );
+ void cvsDiff( );
+
+ void svnUpdate( );
+ void svnUpdateMarked( );
+ void svnCommit( );
+ void svnCommitMarked( );
+ void svnStatusRemote();
+ void svnStatusRemoteMarked();
+ void svnStatusLocal();
+ void svnStatusLocalMarked();
+ void svnUpdateTemplate( );
+ void svnUpdateMarkedTemplate( );
+ void svnCommitTemplate( );
+ void svnCommitMarkedTemplate( );
+ void svnDiff( );
+ void svnInfo();
+ void svnInfoMarked();
+
+ QString find(KBabel::FindOptions &options, QStringList &rest);
+
+ void showLog();
+
+ void stop(bool s = true);
+
+ /**
+ * Stop searching, do not try to proceed to the next file
+ * @ref @find will return clear list of rest to be searched
+ * and @ref QString::null, if search string was not is the last searched file
+ */
+ void stopSearch();
+
+ /**
+ * Information for this file has been read. If the file is in
+ * @ref @_readInfoFileList, it will update progress bar by emitting @ref @progress
+ */
+ void fileInfoRead( QString file );
+
+ void gotoNextUntranslated();
+ void gotoPreviousUntranslated();
+ void gotoNextFuzzy();
+ void gotoPreviousFuzzy();
+ void gotoNextFuzzyOrUntranslated();
+ void gotoPreviousFuzzyOrUntranslated();
+ void gotoNextError();
+ void gotoPreviousError();
+ void gotoNextTemplate();
+ void gotoPreviousTemplate();
+ void gotoNextPo();
+ void gotoPreviousPo();
+ void gotoNextMarked();
+ void gotoPreviousMarked();
+
+ void validateUsingTool( const KDataToolInfo &, const QString& );
+ void validateMarkedUsingTool( const KDataToolInfo &, const QString& );
+
+ void showError( const QString package, const int num);
+
+ void updateCurrent();
+
+ /**
+ * An update for more than one file has become necessary. For instance
+ * after 'cvs commit' or 'svn commit' the file contents have not changed
+ * but the CVS/SVN file status could have changed.
+ */
+ void updateFiles( const QStringList& files );
+
+ /**
+ * Returns the list of all currently selected files. If current selection is dir,
+ * it returns list of all its children.
+ */
+ QStringList current();
+ /**
+ * Returns the list of all currently marked files.
+ */
+ QStringList marked();
+
+signals:
+ void openFile(QString filename,QString package);
+ void openFileInNewWindow(QString filename,QString package);
+ void openTemplate(QString openFilename,QString saveFileName,QString package);
+ void openTemplateInNewWindow(QString openFilename,QString saveFileName,QString package);
+ void gotoFileEntry(QString filename,QString package,int msgid);
+ void prepareProgressBar(QString msg,int max);
+ void progress(int);
+ void clearProgressBar();
+ void prepareFindProgressBar(int max);
+ void signalBuildTree(bool done);
+ void signalSearchedFile(int count);
+
+ void newValidationFile(QString);
+ void newValidationTool(QString);
+ void setValidationProgressBar(int);
+ void advanceValidationFileProgressBar(int);
+ void setMaxValidationProgressBar(int);
+ void setMaxValidationFileProgressBar(int);
+
+ /**
+ * The selected item in the tree view has changed.
+ * This signal emits the corresponding action value for this item.
+ * @param actionValue Action value for the selected item.
+ */
+ void selectedChanged(uint actionValue);
+
+signals:
+ void updateFinished();
+
+protected:
+ /**
+ * builds the tree under dir relDir, but does not update any files
+ * this functions always traverses all subdirs
+ *
+ * @param relDir the relative dir under the po- and pot- base directories
+ * @param fast if true, no files will be updated
+ *
+ * @return true, if the directory contains any po or pot-files
+ * @see CatalogManagerView::buildDir
+ * @see CatalogManagerView::updateDir
+ */
+ bool buildDir(QString relDir,bool fast=true);
+
+ /**
+ * This function is traversing the real directory on the
+ * disc using baseDir as the
+ * base directory and starts at baseDir+relDir
+ * @param extension the extension of the files in this directory
+ * @param fast if true, no file will be updated
+ *
+ * @return true, if the directory contains any po or pot-files
+ * @see CatalogManagerView::buildDir
+ * @see CatalogManagerView::updateDir
+ */
+ bool buildDir(const QString& baseDir,const QString& relDir, const QString extension,bool fast=true);
+
+ /**
+ * updates dir relDir and if any new subdir is added
+ * builds this with @ref buildDir
+ *
+ * This function doesn't enters subdirs except when a new subdir is added.
+ * @see CatalogManagerView::buildDir
+ */
+ void updateDir(QString relDir);
+
+ /**
+ * stops the update timer and the dirwatch
+ * @see KDirWatch::stop
+ * @see QTimer::stop
+ */
+ virtual void hideEvent(QHideEvent*);
+ /**
+ * restarts the update timer and the dirwatch
+ * @see KDirWatch::start
+ * @see QTimer::start
+ */
+ virtual void showEvent(QShowEvent*);
+
+ /** used for dragging */
+ virtual void contentsMousePressEvent(QMouseEvent* e);
+ /** used for dragging */
+ virtual void contentsMouseMoveEvent(QMouseEvent* e);
+
+ void showStatistics( CatManListItem *i, QStringList &packages);
+
+protected slots:
+ /** rebuilds the tree*/
+ void buildTree();
+ /**
+ * recurse all visible files and updates them if necessary
+ * @see CatManListItem::checkUpdate
+ */
+ void checkUpdate();
+
+ /** this is called from KDirWatch when a directory has changed */
+ void directoryChanged(const QString& dir);
+ /** this is called from KDirWatch when a directory has been deleted */
+ void directoryDeleted(const QString& dir);
+
+ void showContentsMenu(QListViewItem *, const QPoint &, int col);
+ /** does the default action on the currently selected item*/
+ void activateItem(QListViewItem *);
+ /** emits the state of the selected item using selectedChanged*/
+ void checkSelected();
+ /** calls @ref activateItem with the selected item as argument*/
+ void slotOpenFile();
+ void slotOpenFileInNewWindow();
+ /** emits signal @ref openTemplate */
+ void slotOpenTemplate();
+ /** deletes the po-file on the disc, that belongs to the selected item */
+ void slotDeleteFile();
+ /** toggles the mark of the selected item */
+ void slotToggleMark();
+ /**
+ * toggles all marks in directory of current item (must be a directory)
+ */
+ void slotToggleMarksInDir();
+ void slotDirCommand(int);
+ void slotFileCommand(int);
+
+private slots:
+ void showOutput(KProcess *proc, char *buffer, int buflen);
+ void processEnded(KProcess *proc);
+ void columnClicked(QListViewItem * item, const QPoint & pnt, int c);
+
+ void slotToggleCVSOrSVNColumn( bool );
+
+ void slotValidPOCVSRepository( bool );
+ void slotValidPOSVNRepository( bool );
+ void slotValidPOTCVSRepository( bool );
+ void slotValidPOTSVNRepository( bool );
+
+private:
+ void toggleColumn( uint id, bool show);
+
+ void readMarker(KConfig *config);
+ void saveMarker(KConfig *config) const;
+ /**
+ * remove marked entries, which are not in the current file list
+ */
+ void updateMarkerList();
+
+ /**
+ * Mark or unmark entries.
+ *
+ * @param mark If true the items are marked, if false the marks are removed.
+ */
+ void setPatternMarks(bool mark);
+
+ /**
+ * deletes item with package name (relative directory) relDir
+ * and makes sure, that all subitems are removed from the lists
+ */
+ void deleteDirItem(QString relDir);
+
+ bool hasMatchingWords( QStringList &itemWords, QStringList &searchWords);
+
+ CatManListItem *itemBelow( CatManListItem *item );
+ CatManListItem *itemAbove( CatManListItem *item );
+
+ void validate_internal( const QStringList&, const KDataToolInfo &, const QString& );
+
+ void doCVSCommand( CVS::Command cmd, bool marked = false, bool templates = false );
+ void doSVNCommand( SVN::Command cmd, bool marked = false, bool templates = false );
+
+private:
+ QDict<CatManListItem> _dirList;
+ QDict<CatManListItem> _fileList;
+
+ KDirWatch *_dirWatch;
+ QTimer *_updateTimer;
+
+ // list of files for which was calculated the progress bar for reading file info
+ QStringList _readInfoFileList;
+ // current count of already read files in @ref @_readInfoFileList.
+ int _readInfoCount;
+
+ KBabel::CatManSettings _settings;
+
+ QStringList _markerList;
+
+ bool _active;
+ // stopping, application quit
+ bool _stop;
+ // stop searching, do not proceed to the next file
+ bool _stopSearch;
+ int _updateNesting;
+
+ QPtrList<KProcess> _pendingProcesses;
+
+ QTextEdit* _logView;
+ KDialogBase* _logWindow;
+ QPopupMenu* _fileContentsMenu;
+ QPopupMenu* _dirContentsMenu;
+ QPopupMenu* _dirCommandsMenu;
+ QPopupMenu* _fileCommandsMenu;
+
+ /** used for starting a drag */
+ QPoint _pressPos;
+
+ KBabelDictBox* _dictBox;
+
+ KBabel::KBabelMailer* mailer;
+
+ CVSHandler* cvshandler;
+ SVNHandler* svnhandler;
+
+ /// Is the PO path a valid CVS repository?
+ bool m_validPOCVSRepository;
+ /// Is the POT path a valid CVS repository?
+ bool m_validPOTCVSRepository;
+ /// Is the PO path a valid SVN repository?
+ bool m_validPOSVNRepository;
+ /// Is the POT path a valid SVN repository?
+ bool m_validPOTSVNRepository;
+
+ MarkPatternDialog * markPatternDialog;
+
+ //validation
+ ValidateProgressDialog* _validateDialog;
+ ValidationOptions* _validateOptions;
+ KDialogBase* _validateOptionsDlg;
+ bool _markAsFuzzy;
+ bool _ignoreFuzzy;
+
+ KBabel::Project::Ptr _project;
+};
+
+#endif // CATALOGMANAGERVIEW_H
diff --git a/kbabel/catalogmanager/catmanlistitem.cpp b/kbabel/catalogmanager/catmanlistitem.cpp
new file mode 100644
index 00000000..249cb053
--- /dev/null
+++ b/kbabel/catalogmanager/catmanlistitem.cpp
@@ -0,0 +1,932 @@
+/* ****************************************************************************
+ This file is part of KBabel
+
+ Copyright (C) 1999-2000 by Matthias Kiefer
+ <matthias.kiefer@gmx.de>
+ 2001-2003 by Stanislav Visnovsky
+ <visnovsky@kde.org>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the 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, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+ In addition, as a special exception, the copyright holders give
+ permission to link the code of this program with any edition of
+ the Qt library by Trolltech AS, Norway (or with modified versions
+ of Qt that use the same license as Qt), and distribute linked
+ combinations including the two. You must obey the GNU General
+ Public License in all respects for all of the code used other than
+ Qt. If you modify this file, you may extend this exception to
+ your version of the file, but you are not obligated to do so. If
+ you do not wish to do so, delete this exception statement from
+ your version.
+
+**************************************************************************** */
+
+#include "catmanresource.h"
+#include "catmanlistitem.h"
+#include "catalogmanagerview.h"
+#include "catalog.h"
+
+#include "resources.h"
+
+#include <klocale.h>
+
+#include <qfileinfo.h>
+#include <qdir.h>
+#include <qbitmap.h>
+#include <qlabel.h>
+#include <qpainter.h>
+
+#include <cvshandler.h>
+#include <svnhandler.h>
+
+using namespace KBabel;
+
+CatManListItem::CatManListItem(CatalogManagerView *view, QListViewItem* parent,QString fullPath,QString fullPotPath,QString package)
+ : QListViewItem(parent)
+{
+ _view = view;
+ init(fullPath,fullPotPath,package);
+}
+
+CatManListItem::CatManListItem(CatalogManagerView *view, QListView* parent,QString fullPath,QString fullPotPath)
+ : QListViewItem(parent)
+{
+ _primary=QFileInfo(fullPath);
+ _template=QFileInfo(fullPotPath);
+ _package="/";
+ _type=Dir;
+ _marked=false;
+ _view = view;
+
+ _hasPo=false;
+ _hasPot=false;
+ _hasErrors=false;
+
+ _primary.setCaching(false);
+ _template.setCaching(false);
+
+ setText(COL_NAME,i18n("Message Catalogs"));
+ setPixmap(COL_NAME,ICON_FOLDER_CLOSED_OK);
+}
+
+
+void CatManListItem::init(const QString& fullPath, const QString& fullPotPath, const QString& package)
+{
+ _primary=QFileInfo(fullPath);
+ _template=QFileInfo(fullPotPath);
+ _package=package;
+ _marked=false;
+
+ _hasPo=false;
+ _hasPot=false;
+ _hasErrors=false;
+
+ _primary.setCaching(false);
+ _template.setCaching(false);
+
+ // set
+ _lastUpdated=QDate(1900,1,1);
+
+ _wordList.clear();
+ _wordListUpdated = false;
+
+ update(parent()->isOpen(),false,true);
+
+ if( !isDir() ) setPixmap(COL_MARKER,ICON_NOFLAG);
+}
+
+void CatManListItem::setMarked(bool on)
+{
+ if(on)
+ {
+ setPixmap(COL_MARKER,ICON_FLAG);
+ }
+ else
+ {
+ setPixmap(COL_MARKER,ICON_NOFLAG);
+ }
+
+ _marked=on;
+}
+
+bool CatManListItem::marked() const
+{
+ if( isFile() ) return _marked;
+ else if( isDir() )
+ {
+ CatManListItem * myChild = (CatManListItem*)firstChild();
+ while( myChild )
+ {
+ if(myChild->isFile() && myChild->marked() ) return true;
+ else if(myChild->isDir() && myChild->marked() ) return true;
+ myChild = (CatManListItem*)myChild->nextSibling();
+ }
+
+ }
+ return false;
+}
+
+void CatManListItem::setOpen(bool open)
+{
+ bool needWork = needsWork();
+ QListViewItem::setOpen(open);
+
+ if(open && _type==Dir)
+ {
+ QPixmap icon;
+ icon = needWork ? ICON_FOLDER_OPEN_WORK : ICON_FOLDER_OPEN_OK;
+
+ if(!_template.exists())
+ {
+ icon=paintExclamation(&icon);
+ }
+
+ setPixmap(COL_NAME,icon);
+
+ CatManListItem * myChild = (CatManListItem*)firstChild();
+ while( myChild )
+ {
+ myChild->checkUpdate();
+ myChild = (CatManListItem*)myChild->nextSibling();
+ }
+ }
+ else
+ {
+ QPixmap icon;
+
+ if(needsWork())
+ icon = ICON_FOLDER_CLOSED_WORK;
+ else
+ icon = ICON_FOLDER_CLOSED_OK;
+
+ if(!_template.exists())
+ {
+ icon=paintExclamation(&icon);
+ }
+
+ setPixmap(COL_NAME,icon);
+ }
+
+}
+
+QStringList CatManListItem::allChildrenList(bool onlyFiles) const
+{
+ QStringList childrenList;
+
+ CatManListItem * myChild = (CatManListItem*)firstChild();
+ while( myChild )
+ {
+ QString name=myChild->package();
+
+ if(myChild->isFile())
+ {
+ childrenList.append(name);
+ }
+ else if(myChild->isDir())
+ {
+ if(!onlyFiles)
+ childrenList.append(name);
+
+ childrenList+=myChild->allChildrenList(onlyFiles);
+ }
+
+ myChild = (CatManListItem*)myChild->nextSibling();
+ }
+
+ return childrenList;
+}
+
+
+QStringList CatManListItem::allChildrenFileList(bool onlyFiles, bool emptyDirs, bool onlyModified) const
+{
+ QStringList childrenList;
+
+ CatManListItem * myChild = (CatManListItem*)firstChild();
+ while( myChild )
+ {
+ if(myChild->isFile() && myChild->hasPo() &&
+ !(!myChild->isModified() && onlyModified))
+ {
+ childrenList.append(myChild->poFile());
+ }
+ else if(myChild->isDir())
+ {
+ if(!onlyFiles && (emptyDirs || myChild->_primary.exists() ))
+ {
+ childrenList.append(myChild->poFile());
+ }
+
+ childrenList+=myChild->allChildrenFileList(onlyFiles,false,onlyModified);
+ }
+
+ myChild = (CatManListItem*)myChild->nextSibling();
+ }
+
+ return childrenList;
+}
+
+
+QStringList CatManListItem::contentsList(bool onlyFiles) const
+{
+ QStringList childList;
+
+ CatManListItem * myChild = (CatManListItem*)firstChild();
+ while( myChild )
+ {
+ QString name=myChild->package();
+
+ if(onlyFiles)
+ {
+ if(myChild->isFile())
+ {
+ childList.append(name);
+ }
+ }
+ else
+ {
+ childList.append(name);
+ }
+
+ myChild = (CatManListItem*)myChild->nextSibling();
+ }
+
+ return childList;
+}
+
+
+void CatManListItem::forceUpdate()
+{
+ update(true,true,false);
+}
+
+void CatManListItem::checkUpdate(bool noParents)
+{
+ // if a file has disappeared or is new
+ if(_hasPo != hasPo() || _hasPot != hasPot())
+ {
+ update(true,false,noParents);
+ }
+ else if(!isFile())
+ {
+ update(true,false,noParents);
+ }
+ else if(_hasPo && _lastUpdated < _primary.lastModified())
+ {
+ update(true,false,noParents);
+ }
+ else if(_hasPot && _lastUpdated < _template.lastModified())
+ {
+ update(true,false,noParents);
+ }
+}
+
+QString CatManListItem::key(int col, bool) const
+{
+ // show directories first
+ QString key=text(col);
+
+ if(col==COL_NAME)
+ {
+ if(_type==Dir)
+ {
+ key="a"+key;
+ }
+ else
+ {
+ key="b"+key;
+ }
+ }
+ // fuzzy, untranslated, total
+ else if(col==COL_FUZZY || col ==COL_TOTAL || col==COL_UNTRANS)
+ {
+ key=key.rightJustify(10,'0');
+ }
+ // marked po's
+ else if(col==COL_MARKER)
+ {
+ if(_marked)
+ {
+ key="1";
+ }
+ else
+ {
+ key="0";
+ }
+ }
+
+ return key;
+}
+
+void CatManListItem::update(bool showPoInfo,bool includeChildren
+ , bool noParents)
+{
+ if( _view->isStopped() ) return; // if parent view is stopped, we should stop as well
+
+ bool updateWordList = _view->settings().indexWords;
+
+ // flag, if something has changed and parent has to be updated
+ bool updateParent=false;
+
+ // update flags for files...
+ const bool hadPo=_hasPo;
+ _hasPo = hasPo();
+ const bool hadPot = _hasPot;
+ _hasPot = hasPot();
+
+ // and check if something changed
+ if(hadPo != _hasPo || hadPot != _hasPot)
+ updateParent=true;
+
+
+ if(_package!="/") // don't update root item
+ {
+ if(_primary.exists())
+ {
+ if(_primary.isDir())
+ {
+ QDir dir=_primary.dir();
+ setText(COL_NAME,dir.dirName());
+
+ // count the childen numbers
+ int fuzzy = 0;
+ int untrans = 0;
+ int total = 0;
+
+ CatManListItem* ch = static_cast<CatManListItem*>(firstChild ());
+
+ while (ch)
+ {
+ fuzzy += ch->fuzzy ();
+ untrans += ch->untranslated ();
+ total += ch->total ();
+ ch = static_cast<CatManListItem*>(ch->nextSibling());
+ }
+
+ setText(COL_FUZZY,QString::number(fuzzy));
+ setText(COL_UNTRANS,QString::number(untrans));
+ setText(COL_TOTAL,QString::number(total));
+
+ //setSelectable(false);
+ _type=Dir;
+
+ bool needWork = needsWork();
+ QPixmap icon;
+ if(!isOpen())
+ {
+ if( needWork )
+ icon = ICON_FOLDER_CLOSED_WORK;
+ else
+ icon = ICON_FOLDER_CLOSED_OK;
+ }
+ else
+ {
+ icon = needWork ? ICON_FOLDER_OPEN_WORK : ICON_FOLDER_OPEN_OK;
+ }
+
+ // check if the same directory exists also in the
+ // template directory
+ if(_template.isDir())
+ {
+ setPixmap( COL_NAME, icon );
+ }
+ else
+ {
+ QPixmap folder = icon;
+ icon=paintExclamation(&folder);
+
+ setPixmap(COL_NAME,folder);
+ }
+ }
+ else // primary is file
+ {
+ _type=File;
+ QString name=_primary.fileName();
+ setText(COL_NAME,name.left(name.length()-3));
+
+ if(showPoInfo)
+ {
+ _lastUpdated=QDateTime::currentDateTime();
+
+ bool neededWork=needsWork();
+ bool needWork=false;
+
+ PoInfo poInfo;
+ QPixmap icon = ICON_UPDATING;
+ setPixmap(COL_NAME,icon);
+ if ( PoInfo::info( _primary.absFilePath(), poInfo, _wordList, updateWordList, true, true ) == OK )
+ {
+ if( _view->isStopped() ) return;
+ if( updateWordList) _wordListUpdated = true;
+
+ _hasErrors=false;
+
+ const CVSHandler* cvsHandler = _view->cvsHandler();
+ const SVNHandler* svnHandler = _view->svnHandler();
+
+ const CVSHandler::FileStatus cvsFileStatus = cvsHandler->fstatus( poFile() );
+ const SVNHandler::FileStatus svnFileStatus = svnHandler->fstatus( poFile() );
+
+ _isModified = cvsHandler->isConsideredModified( cvsFileStatus )
+ || svnHandler->isConsideredModified( svnFileStatus );
+
+ QString versionControl;
+ if ( cvsFileStatus != CVSHandler::NO_REPOSITORY )
+ versionControl = cvsHandler->fileStatus( cvsFileStatus );
+ else if ( svnFileStatus != SVNHandler::NO_REPOSITORY )
+ versionControl = svnHandler->fileStatus( svnFileStatus );
+ else
+ versionControl = i18n("No version control");
+
+ setText(COL_FUZZY,QString::number(poInfo.fuzzy));
+ setText(COL_UNTRANS,QString::number(poInfo.untranslated));
+ setText(COL_TOTAL,QString::number(poInfo.total));
+ setText( COL_CVS_OR_SVN, versionControl );
+ setText(COL_REVISION,poInfo.revision);
+ setText(COL_TRANSLATOR,poInfo.lastTranslator);
+
+ if(needsWork())
+ {
+ icon=ICON_NEEDWORK;
+ needWork = true;
+ }
+ else
+ {
+ icon = ICON_OK;
+ needWork=false;
+ }
+ }
+ else
+ {
+ kdDebug(KBABEL_CATMAN) << "This file is broken" << endl;
+ if( _view->isStopped() ) return;
+ _hasErrors=true;
+ icon = ICON_BROKEN;
+ needWork=true;
+ }
+
+ if(!_template.exists())
+ {
+ icon=paintExclamation(&icon);
+ }
+
+ setPixmap(COL_NAME,icon);
+
+ updateParent=true;
+ }
+ }
+ }
+ // only the template exists
+ else if(_template.exists())
+ {
+ if(_template.isDir())
+ {
+ QDir dir=_template.dir();
+ setText(COL_NAME,dir.dirName());
+ //setSelectable(false);
+ _type=Dir;
+
+ // count the childen numbers
+ int total = 0;
+
+ CatManListItem* ch = static_cast<CatManListItem*>(firstChild ());
+
+ while (ch)
+ {
+ total += ch->total ();
+ ch = static_cast<CatManListItem*>(ch->nextSibling());
+ }
+
+ setText(COL_TOTAL,QString::number(total));
+
+
+ QPixmap icon;
+ if(!isOpen())
+ {
+ icon = ICON_FOLDER_CLOSED_WORK;
+ }
+ else
+ {
+ icon = needsWork() ? ICON_FOLDER_OPEN_WORK : ICON_FOLDER_OPEN_OK;
+ }
+
+ setPixmap(COL_NAME, icon );
+ }
+ // item is file
+ else
+ {
+ _type=File;
+ QString name=_primary.fileName();
+ setText(COL_NAME,name.left(name.length()-3));
+
+ if(showPoInfo)
+ {
+ _lastUpdated=QDateTime::currentDateTime();
+
+ // clean previous state information
+ setText(COL_FUZZY,QString::null);
+ setText(COL_UNTRANS,QString::null);
+ setText(COL_TOTAL,QString::null);
+ setText(COL_CVS_OR_SVN, QString::null);
+ setText(COL_REVISION, QString::null);
+ setText(COL_TRANSLATOR, QString::null);
+
+ setPixmap(COL_NAME,ICON_UPDATING);
+
+ PoInfo poInfo;
+ if ( PoInfo::info( _template.absFilePath(), poInfo, _wordList, false, true, true ) == OK )
+ {
+ if( _view->isStopped() ) return;
+ setText(COL_TOTAL,QString::number(poInfo.total));
+ }
+ if( _view->isStopped() ) return;
+ }
+ setPixmap(COL_NAME,ICON_MISSING);
+
+ updateParent = true;
+ }
+ }
+ else
+ {
+ kdWarning(KBABEL_CATMAN) << "whether po nor pot exists: " << _package << endl;
+ }
+ }
+
+ _view->fileInfoRead( package() );
+
+ if( _view->isStopped() ) return;
+
+ if(updateParent && !noParents)
+ {
+ updateParents();
+ }
+
+ if( _view->isStopped() ) return;
+
+ if(includeChildren)
+ {
+ CatManListItem *myChild = (CatManListItem*)firstChild();
+ while( myChild )
+ {
+ myChild->update(showPoInfo,includeChildren);
+ myChild = (CatManListItem*)myChild->nextSibling();
+ }
+ }
+
+ // HACK to get the signal emitted
+ if (isSelected( )) {
+ listView( )->setSelected(this, false);
+ listView( )->setSelected(this, true);
+ }
+}
+
+// we know that this item was saved and PoInfo contains new information
+// about this item, the item is file
+// however, is can be saved template or translation!!! - only translation is handled???
+void CatManListItem::updateAfterSave( PoInfo &poInfo )
+{
+ // flag, if something has changed and parent has to be updated
+ bool updateParent=false;
+
+ // update flags for files...
+ const bool hadPo=_hasPo;
+ _hasPo = hasPo();
+ const bool hadPot = _hasPot;
+ _hasPot = hasPot();
+
+ // and check if something changed
+ if(hadPo != _hasPo || hadPot != _hasPot)
+ updateParent=true;
+
+ if(_primary.exists())
+ {
+ // primary is existent file
+
+ _type=File;
+ QString name=_primary.fileName();
+ setText(COL_NAME,name.left(name.length()-3));
+
+ _lastUpdated=QDateTime::currentDateTime();
+
+ bool neededWork=needsWork();
+ bool needWork=false;
+
+ QPixmap icon;
+ _hasErrors=false;
+
+ const CVSHandler::FileStatus cvsFileStatus = _view->cvsHandler()->fstatus(poFile());
+ const SVNHandler::FileStatus svnFileStatus = _view->svnHandler()->fstatus(poFile());
+
+ QString versionControl;
+ if ( cvsFileStatus != CVSHandler::NO_REPOSITORY )
+ versionControl = _view->cvsHandler()->fileStatus( cvsFileStatus );
+ else if ( svnFileStatus != SVNHandler::NO_REPOSITORY )
+ versionControl = _view->svnHandler()->fileStatus( svnFileStatus );
+ else
+ versionControl = i18n("No version control");
+
+ setText(COL_FUZZY,QString::number(poInfo.fuzzy));
+ setText(COL_UNTRANS,QString::number(poInfo.untranslated));
+ setText(COL_TOTAL,QString::number(poInfo.total));
+ setText( COL_CVS_OR_SVN, versionControl );
+ setText(COL_REVISION,poInfo.revision);
+ setText(COL_TRANSLATOR,poInfo.lastTranslator);
+
+ if(needsWork())
+ {
+ icon=ICON_NEEDWORK;
+ needWork = true;
+ }
+ else
+ {
+ icon = ICON_OK;
+ needWork=false;
+ }
+
+ if(!_template.exists())
+ {
+ icon=paintExclamation(&icon);
+ }
+
+ setPixmap(COL_NAME,icon);
+
+ // if the status changed, update the parent item
+ if(needWork != neededWork)
+ {
+ updateParent=true;
+ }
+ }
+
+ if(updateParent)
+ {
+ updateParents();
+ }
+}
+
+
+void CatManListItem::updateParents()
+{
+ CatManListItem *item = (CatManListItem*)parent();
+ while( item && !_view->isStopped())
+ {
+ item->update(false,false);
+ item = (CatManListItem*)item->parent();
+ }
+}
+
+bool CatManListItem::hasPo() const
+{
+ return _primary.exists();
+}
+
+bool CatManListItem::hasPot() const
+{
+ return _template.exists();
+}
+
+bool CatManListItem::isModified() const
+{
+ return _isModified;
+}
+
+int CatManListItem::fuzzy() const
+{
+ bool success;
+ int number=text(COL_FUZZY).toInt(&success);
+ if(!success)
+ number=0;
+
+ return number;
+}
+
+int CatManListItem::untranslated() const
+{
+ bool success;
+ int number;
+ if( !hasPo() )
+ {
+ number=total();
+ }
+ else
+ {
+ number=text(COL_UNTRANS).toInt(&success);
+ if(!success)
+ number=0;
+ }
+
+ return number;
+}
+
+int CatManListItem::total() const
+{
+ bool success;
+ int number=text(COL_TOTAL).toInt(&success);
+ if(!success)
+ number=0;
+
+ return number;
+}
+
+bool CatManListItem::needsWork() const
+{
+ bool flag=false;
+
+ if(isFile())
+ {
+ if(!hasPo() || fuzzy() > 0 || untranslated() > 0 || _hasErrors)
+ flag=true;
+ }
+ else
+ {
+ CatManListItem *myChild = (CatManListItem*)firstChild();
+ while( myChild )
+ {
+ if( myChild->needsWork() )
+ {
+ flag=true;
+ myChild=0;
+ }
+ else
+ {
+ myChild = (CatManListItem*)myChild->nextSibling();
+ }
+ }
+ }
+
+ return flag;
+}
+
+bool CatManListItem::isDir() const
+{
+ return type()==Dir;
+}
+
+bool CatManListItem::isFile() const
+{
+ return type()==File;
+}
+
+QString CatManListItem::poFile() const
+{
+ return _primary.absFilePath();
+}
+
+QString CatManListItem::potFile() const
+{
+ return _template.absFilePath();
+}
+
+QString CatManListItem::package(bool rootSlash) const
+{
+ if(rootSlash)
+ return _package;
+ else
+ {
+ return _package.right(_package.length()-1);
+ }
+}
+
+QString CatManListItem::packageDir( ) const
+{
+ return ( _type == Dir ? _package : QString::null );
+}
+
+QString CatManListItem::name() const
+{
+ int index = _package.findRev("/");
+ return _package.right(_package.length()-index-1);
+}
+
+QPixmap CatManListItem::paintExclamation(QPixmap* pixmap)
+{
+ if(!pixmap || pixmap->isNull())
+ return QPixmap(0,0);
+
+ if(_package=="/" && _template.filePath().isEmpty())
+ return *pixmap;
+
+ if(isDir() && _package == _template.filePath())
+ return *pixmap;
+
+ if(isFile() && _package+".pot" == _template.filePath())
+ return *pixmap;
+
+ int width=pixmap->width();
+ int height=pixmap->height();
+
+ int diameter=QMIN(width,height);
+
+ QBitmap mask=pixmap->createHeuristicMask();
+
+ QPainter mp(&mask);
+ mp.setPen(QPen(Qt::color1,1));
+ mp.drawEllipse(width-diameter,height-diameter,diameter,diameter);
+
+ QPixmap result(width,height);
+
+ QPainter p(&result);
+ p.drawPixmap(0,0,*pixmap);
+ p.setPen( QPen(red,1) );
+ p.drawEllipse(width-diameter,height-diameter,diameter,diameter);
+
+ result.setMask(mask);
+
+ return result;
+}
+
+QListViewItem *CatManListItem::previousSibling()
+{
+ QListViewItem * i = parent();
+ if( !i ) return i;
+ i = i->firstChild();
+ if( !i ) return i;
+ if( i == this ) return 0;
+ while( i->nextSibling()!=this ) i = i->nextSibling();
+ return i;
+}
+
+QListViewItem *CatManListItem::lastChild()
+{
+ QListViewItem * i = firstChild();
+ if( !i ) return i;
+ while( i->nextSibling() ) i = i->nextSibling();
+ return i;
+}
+
+void CatManListItem::checkErrors(KDataTool* tool, QObject* progressSignalHandler, bool ignoreFuzzy, bool markAsFuzzy)
+{
+ bool hasError=false;
+ _errors.clear();
+ Catalog* cat = new Catalog();
+
+ QObject::connect( cat, SIGNAL( signalProgress(int) ), progressSignalHandler, SIGNAL( setValidationProgressBar(int)));
+ QObject::connect( cat, SIGNAL( signalResetProgressBar(QString, int) ), progressSignalHandler, SLOT( setupFileProgressBar(QString, int)));
+
+ if( cat->openURL(KURL( poFile() )) == OK )
+ {
+ kdDebug(KBABEL_CATMAN) << "File opened succesfully" << endl;
+ if( !cat->checkUsingTool(tool,true) )
+ {
+ hasError = true;
+ } else forceUpdate(); // no error, find out the new state
+ } else {
+ kdDebug(KBABEL_CATMAN) << "File not opened !!!!!" << endl;
+ hasError=true;
+ }
+
+ if( hasError )
+ {
+ QString errortext;
+ _hasErrors = true;
+
+ DocPosition dummy;
+ IgnoreItem i;
+ i.fileURL = poFile();
+
+ if( cat->hasError(0,dummy) && (!ignoreFuzzy || !cat->isFuzzy(0)))
+ {
+ i.msgid = cat->msgid(0);
+ i.msgstr = cat->msgstr(0);
+ i.index = 0;
+ _errors.append( i );
+
+ if( markAsFuzzy ) cat->setFuzzy(0, true);
+ }
+
+ int index=0;
+ do
+ {
+ index=cat->nextError(index,dummy);
+ if( index != -1 && (!ignoreFuzzy || !cat->isFuzzy(index) ) )
+ {
+ i.msgid = cat->msgid(index);
+ i.msgstr = cat->msgstr(index);
+ i.index = index;
+ _errors.append( i );
+ if( markAsFuzzy ) cat->setFuzzy(index, true);
+ }
+ } while(index>=0);
+
+ // change icon only if there were non-ignored errors
+ if( !_errors.isEmpty() )
+ {
+ setPixmap(COL_NAME, ICON_ERROR);
+ }
+
+ // if we changed fuzzy flags, save the result
+ if( cat->isModified() ) cat->saveFile();
+ }
+
+ delete cat;
+}
diff --git a/kbabel/catalogmanager/catmanlistitem.h b/kbabel/catalogmanager/catmanlistitem.h
new file mode 100644
index 00000000..a5f41e2f
--- /dev/null
+++ b/kbabel/catalogmanager/catmanlistitem.h
@@ -0,0 +1,238 @@
+/* ****************************************************************************
+ This file is part of KBabel
+
+ Copyright (C) 1999-2000 by Matthias Kiefer
+ <matthias.kiefer@gmx.de>
+ 2001-2003 by Stanislav Visnovsky <visnovsky@kde.org>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the 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, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+ In addition, as a special exception, the copyright holders give
+ permission to link the code of this program with any edition of
+ the Qt library by Trolltech AS, Norway (or with modified versions
+ of Qt that use the same license as Qt), and distribute linked
+ combinations including the two. You must obey the GNU General
+ Public License in all respects for all of the code used other than
+ Qt. If you modify this file, you may extend this exception to
+ your version of the file, but you are not obligated to do so. If
+ you do not wish to do so, delete this exception statement from
+ your version.
+
+**************************************************************************** */
+#ifndef CATMANLISTITEM_H
+#define CATMANLISTITEM_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <qstringlist.h>
+#include <qlistview.h>
+#include <qdatetime.h>
+#include <qfileinfo.h>
+
+#include "validateprogress.h"
+
+class CatalogManagerView;
+class QPixmap;
+class KDataTool;
+
+namespace KBabel
+{
+ class PoInfo;
+}
+
+class CatManListItem : public QListViewItem
+{
+public:
+ /** the type of this item */
+ enum Type{File,Dir};
+
+ CatManListItem(CatalogManagerView *view, QListViewItem* parent,QString fullPath
+ ,QString fullPotPath,QString package);
+
+ /** creates the toplevel root item with package name "/" */
+ CatManListItem(CatalogManagerView *view, QListView* parent,QString fullPath, QString fullPotPath);
+
+ /**
+ * returns the package names (including relative path) of the
+ * children of this item
+ */
+ QStringList contentsList(bool onlyFiles=false) const;
+ /**
+ * returns the package names of all children of this item
+ * (including all subdirectries)
+ * @param onlyFiles flag, if only the names of files should be returned
+ * @see CatManListItem::contentsList
+ */
+ QStringList allChildrenList(bool onlyFiles=false) const;
+
+ /**
+ * returns the relative file names of all children of this item
+ * (including all subdirectries)
+ * @param onlyFiles flag, if only the names of files should be returned
+ * @param emptyDirs flag, if the empty dirs (dirs without PO files in them) should be returned
+ * @param onlyModified, if only modified files should be returned
+ * @see CatManListItem::contentsList
+ */
+ QStringList allChildrenFileList(bool onlyFiles=false, bool emptyDirs=false, bool onlyModified=false) const;
+
+ void setMarked(bool on);
+ bool marked() const;
+ /**
+ * checks if the file on the disc has changed,
+ * reads information about the file and displays it
+ * @param noParents flag, if the update has to include the parent
+ * of the item, if the status has changed. Since at the first build of
+ * the tree, the status of every item changes, this is not useful then.
+ */
+ void checkUpdate(bool noParents=false);
+ void forceUpdate();
+
+ /**
+ * checks the corresponding PO file using validation tool. On
+ * errors it fills the list of errors, which can be accessed
+ * using @see errors().
+ * @param validator instance of KDataTool to be used for checking
+ * @param progressSignalHangler widget, to which the checks should send progress signals
+ * @param ignoreFuzzy flag, whether fuzzy messages in the file should be not checked
+ * @param markAsFuzzy flag, whether the error messages should be marked as fuzzy (this alters the PO file)
+ */
+ void checkErrors(KDataTool* validator, QObject* progressSignalHandler, bool ignoreFuzzy, bool markAsFuzzy);
+
+ /** return the absolute filename of the po-File */
+ QString poFile() const;
+ /** return the absolute filename of the pot-File */
+ QString potFile() const;
+ /** returns the package name (inlcuding relative path to base-directory) */
+ QString package(bool rootSlash=true) const;
+
+ /** returns the relative path of a dir or QString::null if not a dir. */
+ QString packageDir( ) const;
+
+ /** returns the package name (without path) */
+ QString name() const;
+
+ /**
+ * returns the type of this item
+ * @see CatManListItem::Type
+ */
+ Type type() const{return _type;}
+ bool isDir() const;
+ bool isFile() const;
+ /** returns true, if the po-file exists*/
+ bool hasPo() const;
+ /** returns true, if the pot-file exists*/
+ bool hasPot() const;
+ bool isModified() const;
+ /**
+ * @return the number of fuzzy messages in the po-file,
+ * 0 if no po-file exists
+ */
+ int fuzzy() const;
+ /**
+ * @return the number of untranslated messages in the po-file,
+ * @ref total if no po-file exists
+ */
+ int untranslated() const;
+ /** @return number of messages in the po- or pot-file */
+ int total() const;
+ /**
+ * @return true, if there are untranslated or fuzzy items.
+ * If this item is a directory, it returns true, if a subitem
+ * contains untranslated or fuzzy items
+ */
+ bool needsWork() const;
+ /**
+ * @return true, if there were errors while parsing the file
+ */
+ bool hasErrors() const {return _hasErrors;}
+ QValueList<IgnoreItem> errors() const {return _errors;}
+
+ virtual QString key(int col,bool) const;
+ virtual void setOpen(bool);
+
+ /** paints the marking, if this package has no template */
+ QPixmap paintExclamation(QPixmap*);
+
+ void updateAfterSave( KBabel::PoInfo &po);
+
+ QStringList &wordList() { return _wordList; }
+ bool wordsUpdated() { return _wordListUpdated; }
+
+ /** These are not in Qt, so we need to implement it ourselves*/
+ QListViewItem *previousSibling();
+ QListViewItem *lastChild();
+
+private:
+ void init(const QString& fullPath, const QString& fullPotPath,const QString& package);
+ /**
+ * updates the item
+ * @param showPoInfo if true, reads information about the
+ * file using @ref Catalog::info
+ * ( slow for big files )
+ * @param includeChildren flag, if possible children should be updated,too
+ * @param noParents flag, if parents should be updated, when state
+ * of the item has changed
+ */
+ void update(bool showPoInfo=true,bool includeChildren=false
+ , bool noParents=false );
+ void updateParents();
+
+private:
+ /**
+ * holds the date and the time this item was
+ * last updated. This is used to check, if the file
+ * on the disc has changed since last update.
+ */
+ QDateTime _lastUpdated;
+
+ /** the po-file */
+ QFileInfo _primary;
+ /** the pot-file */
+ QFileInfo _template;
+ /**
+ * The package name, includes the relative path beginning
+ * at the base directory.
+ * The package name begins with "/" and if this is a directory it end with "/"
+ * The root item has the package name "/"
+ * @see CatManListItem::CatManListItem
+ */
+ QString _package;
+ Type _type;
+ bool _marked;
+
+ /** flag, to detect if file has been deleted or is new */
+ bool _hasPo;
+ /** flag, to detect if file has been deleted or is new */
+ bool _hasPot;
+
+ bool _isModified;
+ /** flag, to detect if file has been modified or new */
+
+ /** flag, if the PO-file has a syntax error */
+ bool _hasErrors;
+ /** a list of errors found by validation tool*/
+ QValueList<IgnoreItem> _errors;
+
+ /** parent view for this item, used for stopping the activity */
+ CatalogManagerView *_view;
+
+ /** index of words, but it does not contain any useful information as values */
+ QStringList _wordList;
+ bool _wordListUpdated;
+};
+
+#endif // CATMANLISTITEM_H
diff --git a/kbabel/catalogmanager/catmanresource.h b/kbabel/catalogmanager/catmanresource.h
new file mode 100644
index 00000000..06b3ac33
--- /dev/null
+++ b/kbabel/catalogmanager/catmanresource.h
@@ -0,0 +1,73 @@
+/* ****************************************************************************
+ This file is part of KBabel
+
+ Copyright (C) 1999-2000 by Matthias Kiefer
+ <matthias.kiefer@gmx.de>
+ 2001-2002 by Stanislav Visnovsky
+ <visnovsky@kde.org>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the 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, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+ In addition, as a special exception, the copyright holders give
+ permission to link the code of this program with any edition of
+ the Qt library by Trolltech AS, Norway (or with modified versions
+ of Qt that use the same license as Qt), and distribute linked
+ combinations including the two. You must obey the GNU General
+ Public License in all respects for all of the code used other than
+ Qt. If you modify this file, you may extend this exception to
+ your version of the file, but you are not obligated to do so. If
+ you do not wish to do so, delete this exception statement from
+ your version.
+
+**************************************************************************** */
+
+#ifndef CATMANRESOURCE_H
+#define CATMANRESOURCE_H
+
+#include <kiconloader.h>
+
+#define COL_NAME 0
+#define COL_MARKER 1
+#define COL_FUZZY 2
+#define COL_UNTRANS 3
+#define COL_TOTAL 4
+#define COL_CVS_OR_SVN 5
+#define COL_REVISION 6
+#define COL_TRANSLATOR 7
+
+#define ICON_OK UserIcon("ok",KIcon::DefaultState)
+#define ICON_MISSING UserIcon("missing",KIcon::DefaultState)
+#define ICON_NEEDWORK UserIcon("needwork",KIcon::DefaultState)
+#define ICON_BROKEN UserIcon("broken",KIcon::DefaultState)
+#define ICON_UPDATING SmallIcon("reload")
+#define ICON_FLAG SmallIcon("flag")
+#define ICON_FOLDER_CLOSED_OK SmallIcon("folder_green")
+#define ICON_FOLDER_CLOSED_WORK SmallIcon("folder_red")
+#define ICON_FOLDER_OPEN_OK SmallIcon("folder_green_open")
+#define ICON_FOLDER_OPEN_WORK SmallIcon("folder_red_open")
+#define ICON_ERROR UserIcon("error",KIcon::DefaultState)
+#define ICON_NOFLAG UserIcon("noflag",KIcon::DefaultState)
+
+// Needed for determining which actions should be enabled and which not.
+#define NEEDS_PO 1
+#define NEEDS_POT 2
+#define NEEDS_MARK 4
+#define NEEDS_DIR 8
+#define NEEDS_PO_CVS 16
+#define NEEDS_POT_CVS 32
+#define NEEDS_PO_SVN 64
+#define NEEDS_POT_SVN 128
+
+#endif
diff --git a/kbabel/catalogmanager/findinfilesdialog.cpp b/kbabel/catalogmanager/findinfilesdialog.cpp
new file mode 100644
index 00000000..b11a20d8
--- /dev/null
+++ b/kbabel/catalogmanager/findinfilesdialog.cpp
@@ -0,0 +1,229 @@
+/* ****************************************************************************
+ This file is part of KBabel
+
+ Copyright (C) 1999-2000 by Matthias Kiefer
+ <matthias.kiefer@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.
+
+ 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, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+ In addition, as a special exception, the copyright holders give
+ permission to link the code of this program with any edition of
+ the Qt library by Trolltech AS, Norway (or with modified versions
+ of Qt that use the same license as Qt), and distribute linked
+ combinations including the two. You must obey the GNU General
+ Public License in all respects for all of the code used other than
+ Qt. If you modify this file, you may extend this exception to
+ your version of the file, but you are not obligated to do so. If
+ you do not wish to do so, delete this exception statement from
+ your version.
+
+**************************************************************************** */
+#include "findinfilesdialog.h"
+
+#include <qcheckbox.h>
+#include <qgroupbox.h>
+#include <qlayout.h>
+#include <qwhatsthis.h>
+
+#include <kconfig.h>
+#include <kdebug.h>
+#include <kglobal.h>
+#include <klocale.h>
+
+using namespace KBabel;
+
+FindInFilesDialog::FindInFilesDialog(bool forReplace, QWidget* parent)
+ :FindDialog(forReplace, parent)
+{
+ QGroupBox* box = new QGroupBox(2, Qt::Horizontal, i18n("File Options"), mainWidget());
+ mainWidget()->layout()->add(box);
+
+ _inAllFiles = new QCheckBox(i18n("&In all files"),box);
+ _inMarked = new QCheckBox(i18n("&Marked files"),box);
+ _inTemplates = new QCheckBox(i18n("In &templates"),box);
+ _askForNextFile = new QCheckBox(i18n("Ask before ne&xt file"),box);
+ _askForSave = new QCheckBox(i18n("Save &without asking"),box);
+
+ QWhatsThis::add(box,i18n("<qt><p><b>File Options</b></p>"
+ "<p>Here you can finetune where to find:"
+ "<ul><li><b>In all files</b>: search in all files, otherwise searched "
+ "is the selected file or files in the selected folder</li>"
+ "<li><b>Ask before next file</b>: show a dialog asking to proceed to the next file</li>"
+ "</ul></qt>"));
+
+ readSettings();
+}
+
+FindInFilesDialog::~FindInFilesDialog()
+{
+ saveSettings();
+}
+
+int FindInFilesDialog::show(QString initialStr)
+{
+
+ FindDialog::show(initialStr);
+
+ int r = result();
+
+ if( r == QDialog::Accepted ) {
+ if( isReplaceDialog() ) {
+ ReplaceOptions options = replaceOpts();
+ options.inAllFiles = _inAllFiles->isChecked();
+ options.inMarkedFiles = _inMarked->isChecked();
+ options.inTemplates = _inTemplates->isChecked();
+ options.askForNextFile = _askForNextFile->isChecked();
+ options.askForSave = !_askForSave->isChecked();
+ FindDialog::setReplaceOpts(options);
+ }
+ else {
+ FindOptions options = findOpts();
+ options.inAllFiles = _inAllFiles->isChecked();
+ options.inMarkedFiles = _inMarked->isChecked();
+ options.inTemplates = _inTemplates->isChecked();
+ options.askForNextFile = _askForNextFile->isChecked();
+ options.askForSave = !_askForSave->isChecked();
+ FindDialog::setFindOpts( options );
+ }
+ }
+
+ return r;
+}
+
+int FindInFilesDialog::exec(QString initialStr)
+{
+ FindDialog::exec(initialStr);
+
+ int r = result();
+
+ if( r == QDialog::Accepted ) {
+ if(isReplaceDialog()) {
+ ReplaceOptions options = replaceOpts();
+ options.inAllFiles = _inAllFiles->isChecked();
+ options.inMarkedFiles = _inMarked->isChecked();
+ options.inTemplates = _inTemplates->isChecked();
+ options.askForNextFile = _askForNextFile->isChecked();
+ options.askForSave = !_askForSave->isChecked();
+ FindDialog::setReplaceOpts(options);
+ }
+ else {
+ FindOptions options = findOpts();
+ options.inAllFiles = _inAllFiles->isChecked();
+ options.inMarkedFiles = _inMarked->isChecked();
+ options.inTemplates = _inTemplates->isChecked();
+ options.askForNextFile = _askForNextFile->isChecked();
+ options.askForSave = !_askForSave->isChecked();
+ FindDialog::setFindOpts( options );
+ }
+ }
+
+ return r;
+}
+
+void FindInFilesDialog::setFindOpts(FindOptions options)
+{
+ FindDialog::setFindOpts(options);
+
+ _inAllFiles->setChecked(options.inAllFiles);
+ _inTemplates->setChecked(options.inTemplates);
+ _inMarked->setChecked(options.inMarkedFiles);
+ _askForNextFile->setChecked(options.askForNextFile);
+ _askForSave->setChecked(!options.askForSave);
+}
+
+void FindInFilesDialog::setReplaceOpts(ReplaceOptions options)
+{
+ FindDialog::setReplaceOpts(options);
+
+ _inAllFiles->setChecked(options.inAllFiles);
+ _inTemplates->setChecked(options.inTemplates);
+ _inMarked->setChecked(options.inMarkedFiles);
+ _askForNextFile->setChecked(options.askForNextFile);
+ _askForSave->setChecked(!options.askForSave);
+}
+
+void FindInFilesDialog::readSettings()
+{
+ KConfig* config = KGlobal::config();
+
+ if(isReplaceDialog()) {
+ KConfigGroupSaver cgs(config,"ReplaceDialog");
+
+ ReplaceOptions options = replaceOpts();
+
+ options.inAllFiles = config->readBoolEntry("AllFiles", false);
+ options.inTemplates = config->readBoolEntry("InTemplates", false);
+ options.inMarkedFiles = config->readBoolEntry("InMarked", false);
+ options.askForNextFile = config->readBoolEntry("AskForNextFile", true);
+ options.askForSave = config->readBoolEntry("AskForSave", true);
+
+ _inAllFiles->setChecked(options.inAllFiles);
+ _inTemplates->setChecked(options.inTemplates);
+ _inMarked->setChecked(options.inMarkedFiles);
+ _askForNextFile->setChecked(options.askForNextFile);
+ _askForSave->setChecked(!options.askForSave);
+
+ FindDialog::setReplaceOpts(options);
+ }
+ else {
+ KConfigGroupSaver cgs(config,"FindDialog");
+
+ FindOptions options = findOpts();
+
+ options.inAllFiles = config->readBoolEntry("AllFiles", false);
+ options.inTemplates = config->readBoolEntry("InTemplates", false);
+ options.inMarkedFiles = config->readBoolEntry("InMarked", false);
+ options.askForNextFile = config->readBoolEntry("AskForNextFile", true);
+ options.askForSave = config->readBoolEntry("AskForSave", true);
+
+ _inAllFiles->setChecked(options.inAllFiles);
+ _inTemplates->setChecked(options.inTemplates);
+ _inMarked->setChecked(options.inMarkedFiles);
+ _askForNextFile->setChecked(options.askForNextFile);
+ _askForSave->setChecked(!options.askForSave);
+
+ FindDialog::setFindOpts(options);
+ }
+
+}
+
+void FindInFilesDialog::saveSettings()
+{
+ KConfig* config = KGlobal::config();
+
+ if(isReplaceDialog()) {
+ KConfigGroupSaver cgs(config,"ReplaceDialog");
+ ReplaceOptions options = replaceOpts();
+
+ config->writeEntry("AllFiles", options.inAllFiles);
+ config->writeEntry("InMarked", options.inMarkedFiles);
+ config->writeEntry("InTemplates", options.inTemplates);
+ config->writeEntry("AskForNextFile",options.askForNextFile);
+ config->writeEntry("AskForSave",options.askForSave);
+ }
+ else {
+ KConfigGroupSaver cgs(config,"FindDialog");
+
+ FindOptions options = findOpts();
+
+ config->writeEntry("AllFiles", options.inAllFiles);
+ config->writeEntry("InMarked", options.inMarkedFiles);
+ config->writeEntry("InTemplates", options.inTemplates);
+ config->writeEntry("AskForNextFile",options.askForNextFile);
+ config->writeEntry("AskForSave",options.askForSave);
+ }
+}
+
+#include "findinfilesdialog.moc"
diff --git a/kbabel/catalogmanager/findinfilesdialog.h b/kbabel/catalogmanager/findinfilesdialog.h
new file mode 100644
index 00000000..fd25f845
--- /dev/null
+++ b/kbabel/catalogmanager/findinfilesdialog.h
@@ -0,0 +1,85 @@
+/* ****************************************************************************
+ This file is part of KBabel
+
+ Copyright (C) 1999-2000 by Matthias Kiefer
+ <matthias.kiefer@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.
+
+ 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, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+ In addition, as a special exception, the copyright holders give
+ permission to link the code of this program with any edition of
+ the Qt library by Trolltech AS, Norway (or with modified versions
+ of Qt that use the same license as Qt), and distribute linked
+ combinations including the two. You must obey the GNU General
+ Public License in all respects for all of the code used other than
+ Qt. If you modify this file, you may extend this exception to
+ your version of the file, but you are not obligated to do so. If
+ you do not wish to do so, delete this exception statement from
+ your version.
+
+**************************************************************************** */
+#ifndef FINDINFILESDIALOG_H
+#define FINDINFILESDIALOG_H
+
+#include "findoptions.h"
+#include "finddialog.h"
+
+class QCheckBox;
+
+class FindInFilesDialog : public FindDialog
+{
+ Q_OBJECT
+public:
+ /**
+ * Constructor
+ * @param replaceDlg flag, if this is a replace dialog
+ */
+ FindInFilesDialog(bool replaceDlg, QWidget* parent);
+ ~FindInFilesDialog();
+
+ /**
+ * shows the dialog
+ * @param initialStr string to display in find field.
+ * If empty, the last used string is used.
+ *
+ * @return the result code of the dialog
+ */
+ int show(QString initialStr);
+
+ /**
+ * executes the dialog as modal
+ * @param initialStr string to display in find field.
+ * If empty, the last used string is used.
+ *
+ * @return the result code of the dialog
+ */
+ int exec(QString initialStr);
+
+ void setFindOpts(KBabel::FindOptions options);
+ void setReplaceOpts(KBabel::ReplaceOptions options);
+
+protected:
+ void readSettings();
+ void saveSettings();
+
+private:
+ QCheckBox *_inAllFiles;
+ QCheckBox *_inTemplates;
+ QCheckBox *_inMarked;
+ QCheckBox *_askForNextFile;
+ QCheckBox *_askForSave;
+};
+
+#endif // FINDDIALOG_H
diff --git a/kbabel/catalogmanager/future.cpp b/kbabel/catalogmanager/future.cpp
new file mode 100644
index 00000000..4c9c8a90
--- /dev/null
+++ b/kbabel/catalogmanager/future.cpp
@@ -0,0 +1,17 @@
+// This files holds a few user-visible messages that will be needed by the SVN support
+
+// Misc. messages already existing in the kbabel-svn branch
+i18n("SVN");
+i18n( "CVS/SVN Status" );
+
+// Messages for further SVN functions
+i18n( "Resolved" );
+i18n( "Resolved for Marked" );
+i18n( "Revert" );
+i18n( "Revert for Marked" );
+i18n( "Cleanup" );
+i18n( "Cleanup for Marked" );
+
+// Messages that will probably not be needed
+i18n( "No repository" );
+
diff --git a/kbabel/catalogmanager/hi16-app-catalogmanager.png b/kbabel/catalogmanager/hi16-app-catalogmanager.png
new file mode 100644
index 00000000..c2a3ef67
--- /dev/null
+++ b/kbabel/catalogmanager/hi16-app-catalogmanager.png
Binary files differ
diff --git a/kbabel/catalogmanager/hi22-app-catalogmanager.png b/kbabel/catalogmanager/hi22-app-catalogmanager.png
new file mode 100644
index 00000000..3b9dfecc
--- /dev/null
+++ b/kbabel/catalogmanager/hi22-app-catalogmanager.png
Binary files differ
diff --git a/kbabel/catalogmanager/hi32-app-catalogmanager.png b/kbabel/catalogmanager/hi32-app-catalogmanager.png
new file mode 100644
index 00000000..3601807e
--- /dev/null
+++ b/kbabel/catalogmanager/hi32-app-catalogmanager.png
Binary files differ
diff --git a/kbabel/catalogmanager/hi48-app-catalogmanager.png b/kbabel/catalogmanager/hi48-app-catalogmanager.png
new file mode 100644
index 00000000..8d5090ea
--- /dev/null
+++ b/kbabel/catalogmanager/hi48-app-catalogmanager.png
Binary files differ
diff --git a/kbabel/catalogmanager/icons/Makefile.am b/kbabel/catalogmanager/icons/Makefile.am
new file mode 100644
index 00000000..f6ca354f
--- /dev/null
+++ b/kbabel/catalogmanager/icons/Makefile.am
@@ -0,0 +1,5 @@
+# Add all of your pixmaps here
+icons_ICON = AUTO
+
+# This is where it will all be installed
+iconsdir = $(kde_datadir)/kbabel/icons
diff --git a/kbabel/catalogmanager/icons/hi16-action-nextmarked.png b/kbabel/catalogmanager/icons/hi16-action-nextmarked.png
new file mode 100644
index 00000000..1e71607f
--- /dev/null
+++ b/kbabel/catalogmanager/icons/hi16-action-nextmarked.png
Binary files differ
diff --git a/kbabel/catalogmanager/icons/hi16-action-nextpo.png b/kbabel/catalogmanager/icons/hi16-action-nextpo.png
new file mode 100644
index 00000000..650ec8e9
--- /dev/null
+++ b/kbabel/catalogmanager/icons/hi16-action-nextpo.png
Binary files differ
diff --git a/kbabel/catalogmanager/icons/hi16-action-nexttemplate.png b/kbabel/catalogmanager/icons/hi16-action-nexttemplate.png
new file mode 100644
index 00000000..8422a3c6
--- /dev/null
+++ b/kbabel/catalogmanager/icons/hi16-action-nexttemplate.png
Binary files differ
diff --git a/kbabel/catalogmanager/icons/hi16-action-prevmarked.png b/kbabel/catalogmanager/icons/hi16-action-prevmarked.png
new file mode 100644
index 00000000..880e694d
--- /dev/null
+++ b/kbabel/catalogmanager/icons/hi16-action-prevmarked.png
Binary files differ
diff --git a/kbabel/catalogmanager/icons/hi16-action-prevpo.png b/kbabel/catalogmanager/icons/hi16-action-prevpo.png
new file mode 100644
index 00000000..f5e668c4
--- /dev/null
+++ b/kbabel/catalogmanager/icons/hi16-action-prevpo.png
Binary files differ
diff --git a/kbabel/catalogmanager/icons/hi16-action-prevtemplate.png b/kbabel/catalogmanager/icons/hi16-action-prevtemplate.png
new file mode 100644
index 00000000..4b799896
--- /dev/null
+++ b/kbabel/catalogmanager/icons/hi16-action-prevtemplate.png
Binary files differ
diff --git a/kbabel/catalogmanager/icons/hi16-action-statistics.png b/kbabel/catalogmanager/icons/hi16-action-statistics.png
new file mode 100644
index 00000000..456be360
--- /dev/null
+++ b/kbabel/catalogmanager/icons/hi16-action-statistics.png
Binary files differ
diff --git a/kbabel/catalogmanager/icons/hi16-action-syntax.png b/kbabel/catalogmanager/icons/hi16-action-syntax.png
new file mode 100644
index 00000000..221c3b87
--- /dev/null
+++ b/kbabel/catalogmanager/icons/hi16-action-syntax.png
Binary files differ
diff --git a/kbabel/catalogmanager/icons/hi22-action-nextmarked.png b/kbabel/catalogmanager/icons/hi22-action-nextmarked.png
new file mode 100644
index 00000000..020ead66
--- /dev/null
+++ b/kbabel/catalogmanager/icons/hi22-action-nextmarked.png
Binary files differ
diff --git a/kbabel/catalogmanager/icons/hi22-action-nextpo.png b/kbabel/catalogmanager/icons/hi22-action-nextpo.png
new file mode 100644
index 00000000..8579fefd
--- /dev/null
+++ b/kbabel/catalogmanager/icons/hi22-action-nextpo.png
Binary files differ
diff --git a/kbabel/catalogmanager/icons/hi22-action-nexttemplate.png b/kbabel/catalogmanager/icons/hi22-action-nexttemplate.png
new file mode 100644
index 00000000..064ab5bd
--- /dev/null
+++ b/kbabel/catalogmanager/icons/hi22-action-nexttemplate.png
Binary files differ
diff --git a/kbabel/catalogmanager/icons/hi22-action-prevmarked.png b/kbabel/catalogmanager/icons/hi22-action-prevmarked.png
new file mode 100644
index 00000000..38113a73
--- /dev/null
+++ b/kbabel/catalogmanager/icons/hi22-action-prevmarked.png
Binary files differ
diff --git a/kbabel/catalogmanager/icons/hi22-action-prevpo.png b/kbabel/catalogmanager/icons/hi22-action-prevpo.png
new file mode 100644
index 00000000..883ca21a
--- /dev/null
+++ b/kbabel/catalogmanager/icons/hi22-action-prevpo.png
Binary files differ
diff --git a/kbabel/catalogmanager/icons/hi22-action-prevtemplate.png b/kbabel/catalogmanager/icons/hi22-action-prevtemplate.png
new file mode 100644
index 00000000..0def2356
--- /dev/null
+++ b/kbabel/catalogmanager/icons/hi22-action-prevtemplate.png
Binary files differ
diff --git a/kbabel/catalogmanager/icons/hi22-action-statistics.png b/kbabel/catalogmanager/icons/hi22-action-statistics.png
new file mode 100644
index 00000000..aff3294f
--- /dev/null
+++ b/kbabel/catalogmanager/icons/hi22-action-statistics.png
Binary files differ
diff --git a/kbabel/catalogmanager/icons/hi22-action-syntax.png b/kbabel/catalogmanager/icons/hi22-action-syntax.png
new file mode 100644
index 00000000..d0c7decc
--- /dev/null
+++ b/kbabel/catalogmanager/icons/hi22-action-syntax.png
Binary files differ
diff --git a/kbabel/catalogmanager/icons/hi32-action-nextmarked.png b/kbabel/catalogmanager/icons/hi32-action-nextmarked.png
new file mode 100644
index 00000000..32cd2f48
--- /dev/null
+++ b/kbabel/catalogmanager/icons/hi32-action-nextmarked.png
Binary files differ
diff --git a/kbabel/catalogmanager/icons/hi32-action-nextpo.png b/kbabel/catalogmanager/icons/hi32-action-nextpo.png
new file mode 100644
index 00000000..2320ecf8
--- /dev/null
+++ b/kbabel/catalogmanager/icons/hi32-action-nextpo.png
Binary files differ
diff --git a/kbabel/catalogmanager/icons/hi32-action-nexttemplate.png b/kbabel/catalogmanager/icons/hi32-action-nexttemplate.png
new file mode 100644
index 00000000..be6e8c04
--- /dev/null
+++ b/kbabel/catalogmanager/icons/hi32-action-nexttemplate.png
Binary files differ
diff --git a/kbabel/catalogmanager/icons/hi32-action-prevmarked.png b/kbabel/catalogmanager/icons/hi32-action-prevmarked.png
new file mode 100644
index 00000000..b9c85a05
--- /dev/null
+++ b/kbabel/catalogmanager/icons/hi32-action-prevmarked.png
Binary files differ
diff --git a/kbabel/catalogmanager/icons/hi32-action-prevpo.png b/kbabel/catalogmanager/icons/hi32-action-prevpo.png
new file mode 100644
index 00000000..28d31e80
--- /dev/null
+++ b/kbabel/catalogmanager/icons/hi32-action-prevpo.png
Binary files differ
diff --git a/kbabel/catalogmanager/icons/hi32-action-prevtemplate.png b/kbabel/catalogmanager/icons/hi32-action-prevtemplate.png
new file mode 100644
index 00000000..0f9e9c0c
--- /dev/null
+++ b/kbabel/catalogmanager/icons/hi32-action-prevtemplate.png
Binary files differ
diff --git a/kbabel/catalogmanager/icons/hi32-action-statistics.png b/kbabel/catalogmanager/icons/hi32-action-statistics.png
new file mode 100644
index 00000000..5f428a65
--- /dev/null
+++ b/kbabel/catalogmanager/icons/hi32-action-statistics.png
Binary files differ
diff --git a/kbabel/catalogmanager/icons/hi32-action-syntax.png b/kbabel/catalogmanager/icons/hi32-action-syntax.png
new file mode 100644
index 00000000..0be5c2db
--- /dev/null
+++ b/kbabel/catalogmanager/icons/hi32-action-syntax.png
Binary files differ
diff --git a/kbabel/catalogmanager/icons/lo16-action-nextmarked.png b/kbabel/catalogmanager/icons/lo16-action-nextmarked.png
new file mode 100644
index 00000000..fdbb9664
--- /dev/null
+++ b/kbabel/catalogmanager/icons/lo16-action-nextmarked.png
Binary files differ
diff --git a/kbabel/catalogmanager/icons/lo16-action-nextpo.png b/kbabel/catalogmanager/icons/lo16-action-nextpo.png
new file mode 100644
index 00000000..b9d0ce11
--- /dev/null
+++ b/kbabel/catalogmanager/icons/lo16-action-nextpo.png
Binary files differ
diff --git a/kbabel/catalogmanager/icons/lo16-action-nexttemplate.png b/kbabel/catalogmanager/icons/lo16-action-nexttemplate.png
new file mode 100644
index 00000000..979ba277
--- /dev/null
+++ b/kbabel/catalogmanager/icons/lo16-action-nexttemplate.png
Binary files differ
diff --git a/kbabel/catalogmanager/icons/lo16-action-prevmarked.png b/kbabel/catalogmanager/icons/lo16-action-prevmarked.png
new file mode 100644
index 00000000..b712b63c
--- /dev/null
+++ b/kbabel/catalogmanager/icons/lo16-action-prevmarked.png
Binary files differ
diff --git a/kbabel/catalogmanager/icons/lo16-action-prevpo.png b/kbabel/catalogmanager/icons/lo16-action-prevpo.png
new file mode 100644
index 00000000..3736c141
--- /dev/null
+++ b/kbabel/catalogmanager/icons/lo16-action-prevpo.png
Binary files differ
diff --git a/kbabel/catalogmanager/icons/lo16-action-prevtemplate.png b/kbabel/catalogmanager/icons/lo16-action-prevtemplate.png
new file mode 100644
index 00000000..62b3746d
--- /dev/null
+++ b/kbabel/catalogmanager/icons/lo16-action-prevtemplate.png
Binary files differ
diff --git a/kbabel/catalogmanager/icons/lo16-action-statistics.png b/kbabel/catalogmanager/icons/lo16-action-statistics.png
new file mode 100644
index 00000000..1c298a5b
--- /dev/null
+++ b/kbabel/catalogmanager/icons/lo16-action-statistics.png
Binary files differ
diff --git a/kbabel/catalogmanager/icons/lo16-action-syntax.png b/kbabel/catalogmanager/icons/lo16-action-syntax.png
new file mode 100644
index 00000000..79fea79a
--- /dev/null
+++ b/kbabel/catalogmanager/icons/lo16-action-syntax.png
Binary files differ
diff --git a/kbabel/catalogmanager/icons/lo22-action-statistics.png b/kbabel/catalogmanager/icons/lo22-action-statistics.png
new file mode 100644
index 00000000..00ee1475
--- /dev/null
+++ b/kbabel/catalogmanager/icons/lo22-action-statistics.png
Binary files differ
diff --git a/kbabel/catalogmanager/icons/lo22-action-syntax.png b/kbabel/catalogmanager/icons/lo22-action-syntax.png
new file mode 100644
index 00000000..801b8cc4
--- /dev/null
+++ b/kbabel/catalogmanager/icons/lo22-action-syntax.png
Binary files differ
diff --git a/kbabel/catalogmanager/icons/lo32-action-nextmarked.png b/kbabel/catalogmanager/icons/lo32-action-nextmarked.png
new file mode 100644
index 00000000..ded540c2
--- /dev/null
+++ b/kbabel/catalogmanager/icons/lo32-action-nextmarked.png
Binary files differ
diff --git a/kbabel/catalogmanager/icons/lo32-action-nextpo.png b/kbabel/catalogmanager/icons/lo32-action-nextpo.png
new file mode 100644
index 00000000..e0fcc825
--- /dev/null
+++ b/kbabel/catalogmanager/icons/lo32-action-nextpo.png
Binary files differ
diff --git a/kbabel/catalogmanager/icons/lo32-action-nexttemplate.png b/kbabel/catalogmanager/icons/lo32-action-nexttemplate.png
new file mode 100644
index 00000000..da024779
--- /dev/null
+++ b/kbabel/catalogmanager/icons/lo32-action-nexttemplate.png
Binary files differ
diff --git a/kbabel/catalogmanager/icons/lo32-action-prevmarked.png b/kbabel/catalogmanager/icons/lo32-action-prevmarked.png
new file mode 100644
index 00000000..942587eb
--- /dev/null
+++ b/kbabel/catalogmanager/icons/lo32-action-prevmarked.png
Binary files differ
diff --git a/kbabel/catalogmanager/icons/lo32-action-prevpo.png b/kbabel/catalogmanager/icons/lo32-action-prevpo.png
new file mode 100644
index 00000000..55cb73a3
--- /dev/null
+++ b/kbabel/catalogmanager/icons/lo32-action-prevpo.png
Binary files differ
diff --git a/kbabel/catalogmanager/icons/lo32-action-prevtemplate.png b/kbabel/catalogmanager/icons/lo32-action-prevtemplate.png
new file mode 100644
index 00000000..eb485afc
--- /dev/null
+++ b/kbabel/catalogmanager/icons/lo32-action-prevtemplate.png
Binary files differ
diff --git a/kbabel/catalogmanager/icons/lo32-action-statistics.png b/kbabel/catalogmanager/icons/lo32-action-statistics.png
new file mode 100644
index 00000000..298e4577
--- /dev/null
+++ b/kbabel/catalogmanager/icons/lo32-action-statistics.png
Binary files differ
diff --git a/kbabel/catalogmanager/icons/lo32-action-syntax.png b/kbabel/catalogmanager/icons/lo32-action-syntax.png
new file mode 100644
index 00000000..4292ffaf
--- /dev/null
+++ b/kbabel/catalogmanager/icons/lo32-action-syntax.png
Binary files differ
diff --git a/kbabel/catalogmanager/libcvs/Makefile.am b/kbabel/catalogmanager/libcvs/Makefile.am
new file mode 100644
index 00000000..e3e4f9ac
--- /dev/null
+++ b/kbabel/catalogmanager/libcvs/Makefile.am
@@ -0,0 +1,11 @@
+noinst_LTLIBRARIES = libcatalogmanagercvs.la
+
+# set the include path for X, qt and KDE
+INCLUDES = -I.. -I../../common $(all_includes)
+
+libcatalogmanagercvs_la_SOURCES = cvshandler.cpp cvsdialog.cpp
+
+noinst_HEADERS = cvshandler.h cvsdialog.h cvsresources.h
+
+# let automoc handle all of the meta source files (moc)
+METASOURCES = AUTO
diff --git a/kbabel/catalogmanager/libcvs/cvsdialog.cpp b/kbabel/catalogmanager/libcvs/cvsdialog.cpp
new file mode 100644
index 00000000..af76d9d0
--- /dev/null
+++ b/kbabel/catalogmanager/libcvs/cvsdialog.cpp
@@ -0,0 +1,423 @@
+/* ****************************************************************************
+ This file is part of KBabel
+
+ Copyright (C) 2002-2003 by Marco Wegner <mail@marcowegner.de>
+ Copyright (C) 2005, 2006 by Nicolas GOUTTE <goutte@kde.org>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the 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, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+ In addition, as a special exception, the copyright holders give
+ permission to link the code of this program with any edition of
+ the Qt library by Trolltech AS, Norway (or with modified versions
+ of Qt that use the same license as Qt), and distribute linked
+ combinations including the two. You must obey the GNU General
+ Public License in all respects for all of the code used other than
+ Qt. If you modify this file, you may extend this exception to
+ your version of the file, but you are not obligated to do so. If
+ you do not wish to do so, delete this exception statement from
+ your version.
+
+**************************************************************************** */
+
+
+// Qt include files
+#include <qcheckbox.h>
+#include <qcombobox.h>
+#include <qfileinfo.h>
+#include <qframe.h>
+#include <qlabel.h>
+#include <qlayout.h>
+#include <qlistbox.h>
+#include <qpushbutton.h>
+#include <qstring.h>
+#include <qstringlist.h>
+#include <qtextedit.h>
+#include <qtextcodec.h>
+// KDE include files
+#include <kconfig.h>
+#include <kdebug.h>
+#include <kglobal.h>
+#include <klocale.h>
+#include <kprocess.h>
+#include <ktempfile.h>
+#include <kmessagebox.h>
+#include <kstringhandler.h>
+#include <kcombobox.h>
+#include <kcharsets.h>
+// Project specific include files
+#include "cvsdialog.h"
+
+
+CVSDialog::CVSDialog( CVS::Command cmd, QWidget * parent, KSharedConfig* config )
+ : KDialog( parent, "CVSDIALOG", true ), m_config( config )
+{
+ _cmd = cmd;
+ p=0L;
+ setCaption( i18n( "CVS Dialog" ) );
+
+ QString temp;
+
+ QVBoxLayout * layout = new QVBoxLayout( this, 6, 6, "MAIN LAYOUT" );
+
+ // Set the label's text depending on the CVS command.
+ switch ( cmd ) {
+ case CVS::Update:
+ temp = i18n( "Update the following files:" );
+ break;
+ case CVS::Commit:
+ temp = i18n( "Commit the following files:" );
+ break;
+ case CVS::Status:
+ temp = i18n( "Get status for the following files:" );
+ break;
+ case CVS::Diff:
+ temp = i18n( "Get diff for the following files:" );
+ break;
+ }
+ layout->addWidget( new QLabel( temp, this ) );
+
+ // Widget for showing the list of files.
+ filebox = new QListBox( this );
+ layout->addWidget( filebox );
+
+ // Add special widgets for 'cvs commit'.
+ if ( cmd == CVS::Commit ) {
+ QLabel * label;
+
+ // Combobox for displaying old log messages.
+ label = new QLabel( i18n( "&Old messages:" ), this );
+ oldMessages = new QComboBox( this );
+ oldMessages->setDuplicatesEnabled( false );
+ label->setBuddy( oldMessages );
+ layout->addWidget( label );
+ layout->addWidget( oldMessages );
+
+ // Textfield for entering a log message.
+ label = new QLabel( i18n( "&Log message:" ), this );
+ logedit = new QTextEdit( this );
+ label->setBuddy( logedit );
+ layout->addWidget( label );
+ layout->addWidget( logedit );
+
+ label = new QLabel( i18n( "E&ncoding:" ), this );
+ m_encodingComboBox = new KComboBox( this );
+ label->setBuddy( m_encodingComboBox );
+ layout->addWidget( label );
+ layout->addWidget( m_encodingComboBox );
+ QStringList encodingList;
+ // The last encoding will be added at the top of the list, when the seetings will be read.
+ encodingList << i18n( "Descriptive encoding name", "Recommended ( %1 )" ).arg( "UTF-8" );
+ encodingList << i18n( "Descriptive encoding name", "Locale ( %1 )" ).arg( QTextCodec::codecForLocale()->mimeName() );
+ encodingList += KGlobal::charsets()->descriptiveEncodingNames();
+ m_encodingComboBox->insertStringList( encodingList );
+
+ connect( oldMessages, SIGNAL( activated( int ) ),
+ this, SLOT( slotComboActivated( int ) ) );
+ }
+
+ QHBoxLayout * buttons = new QHBoxLayout( 0, 0, 6, "BUTTON LAYOUT" );
+ // Add special buttons for 'cvs commit'.
+ if ( cmd == CVS::Commit ) {
+ autoAddBox = new QCheckBox( i18n( "Auto&matically add files if necessary" ), this );
+ buttons->addWidget( autoAddBox );
+ }
+ buttons->addItem( new QSpacerItem( 1, 0, QSizePolicy::Expanding, QSizePolicy::Minimum ) );
+
+ // Set the main button's text depending on the CVS comand.
+ switch ( cmd ) {
+ case CVS::Update:
+ temp = i18n( "&Update" );
+ break;
+ case CVS::Commit:
+ temp = i18n( "&Commit" );
+ break;
+ case CVS::Status:
+ temp = i18n( "&Get Status" );
+ break;
+ case CVS::Diff:
+ temp = i18n( "&Get Diff" );
+ break;
+ }
+ mainBtn = new QPushButton( temp, this );
+ mainBtn->setDefault( true );
+ buttons->addWidget( mainBtn );
+
+ cancelBtn = new QPushButton( i18n( "C&ancel" ), this );
+ buttons->addWidget( cancelBtn );
+ layout->addLayout( buttons );
+
+ QFrame * line = new QFrame( this );
+ line->setFrameStyle( QFrame::HLine | QFrame::Sunken );
+ layout->addWidget( line );
+
+ layout->addWidget( new QLabel( i18n( "Command output:" ), this ) );
+
+ output = new QTextEdit( this );
+ output->setReadOnly( true );
+ layout->addWidget( output );
+
+ resize( QSize( 600, 450 ).expandedTo( minimumSizeHint( ) ) );
+
+ if ( cmd == CVS::Commit )
+ logedit->setFocus( );
+
+ readSettings( );
+
+ connect( mainBtn, SIGNAL( clicked( ) ), this, SLOT( slotExecuteCommand( ) ) );
+ connect( cancelBtn, SIGNAL( clicked( ) ), this, SLOT( reject( ) ) );
+}
+
+void CVSDialog::slotComboActivated( int index )
+{
+ if ( index < 0 || index >= m_logMessages.count() )
+ return;
+ logedit->setText( m_logMessages[index] );
+}
+
+CVSDialog::~CVSDialog()
+{
+ delete p;
+}
+
+void CVSDialog::accept( )
+{
+ saveSettings( );
+ KDialog::accept( );
+}
+
+void CVSDialog::setFiles( const QStringList& files )
+{
+ filebox->insertStringList( files );
+}
+
+void CVSDialog::setCommandLine( const QString& command )
+{
+ _commandLine = command;
+}
+
+void CVSDialog::setAddCommand( const QString& command )
+{
+ _addCommand = command;
+}
+
+void CVSDialog::slotExecuteCommand( )
+{
+ // Nothing to do here.
+ if ( _commandLine.isEmpty( ) ) return;
+
+ kdDebug() << "Preparing KProcess" << endl;
+
+ // Create a new shell process
+ p = new KProcess;
+ p->setUseShell( true, "/bin/sh" );
+
+ if ( _cmd == CVS::Commit ) {
+ // Include command for 'cvs add'.
+ if ( autoAddBox->isChecked( ) && !_addCommand.isEmpty( ) )
+ _commandLine.prepend( _addCommand );
+
+ const QString msg( logedit->text() );
+
+ if ( msg.isEmpty() )
+ {
+ // A good commit should never have an empty comment, so ask the user if he really wants it.
+ const int res = KMessageBox::warningContinueCancel( this,
+ i18n( "The commit log message is empty. Do you want to continue?" ) );
+ if ( res != KMessageBox::Continue )
+ return;
+ }
+
+ m_encoding = KGlobal::charsets()->encodingForName( m_encodingComboBox->currentText() );
+ QTextCodec* codec = QTextCodec::codecForName( m_encoding.utf8() );
+
+ if ( !codec )
+ {
+ KMessageBox::error( this, i18n( "Cannot find encoding: %1" ).arg( m_encoding ) );
+ return;
+ }
+ else if ( !codec->canEncode( msg ) )
+ {
+ const int res = KMessageBox::warningContinueCancel( this,
+ i18n( "The commit log message cannot be encoded in the selected encoding: %1.\n"
+ "Do you want to continue?" ).arg( m_encoding ) );
+ if ( res != KMessageBox::Continue )
+ return;
+ }
+
+ // Write the commit log message from the input field to a temporary file
+ m_tempFile = new KTempFile;
+ m_tempFile->setAutoDelete( true );
+ QTextStream* stream = m_tempFile->textStream();
+ if ( !stream )
+ {
+ kdError() << "Could not create QTextStream for file " << m_tempFile->name();
+ delete m_tempFile;
+ m_tempFile = 0;
+ KMessageBox::error( this, i18n( "Cannot open temporary file for writing. Aborting.") );
+ return;
+ }
+ stream->setCodec( codec );
+ *stream << msg;
+ m_tempFile->close();
+
+ if ( m_tempFile->status() )
+ {
+ kdError() << "Could not write to file " << m_tempFile->name();
+ delete m_tempFile;
+ m_tempFile = 0;
+ KMessageBox::error( this, i18n( "Cannot write to temporary file. Aborting.") );
+ return;
+ }
+
+ // Change the command line to have the real name of the temporary file
+ _commandLine.replace( "@LOG@FILE@", KProcess::quote( m_tempFile->name() ) );
+
+ // Update the list of log messages
+ if ( !msg.isEmpty() ) {
+ const QString shortLog = KStringHandler::csqueeze( msg, 80 );
+
+
+ // Remove the message from the list if it already exists
+ m_logMessages.remove( msg );
+ // Prepend the current message to the list
+ m_logMessages.prepend( msg );
+
+ // At this time of the process, we do not need the combobox anymore, so we do not squeeze the changed strings.
+ }
+ }
+
+ // Set the KProcess' command line.
+ *p << _commandLine;
+
+ connect( p, SIGNAL( receivedStdout( KProcess*, char*, int ) ),
+ this, SLOT ( slotProcessStdout( KProcess*, char*, int ) ) );
+ connect( p, SIGNAL( receivedStderr( KProcess*, char*, int ) ),
+ this, SLOT ( slotProcessStderr( KProcess*, char*, int ) ) );
+ connect( p, SIGNAL( processExited( KProcess* ) ),
+ this, SLOT( slotProcessExited( KProcess* ) ) );
+
+ output->append( i18n( "[ Starting command ]" ) );
+
+ if ( p->start( KProcess::NotifyOnExit, KProcess::Communication( KProcess::AllOutput ) ) ) {
+ // Disable the main button (and the log edit if in commit mode) to
+ // indicate activity.
+ mainBtn->setEnabled( false );
+ if ( _cmd == CVS::Commit )
+ logedit->setEnabled( false );
+ } else
+ {
+ kdError() << "Process could not be started." << endl;
+ KMessageBox::error( this, i18n( "The process could not be started." ) );
+ }
+}
+
+void CVSDialog::slotProcessStdout( KProcess*, char * buffer, int len )
+{
+ output->append( QString::fromLocal8Bit( buffer, len ) );
+ // Set the cursor's position at the end of the output.
+ output->setCursorPosition( output->lines( ), 0 );
+
+ // If the command is 'cvs status' or 'cvs diff' collect the output of stdout.
+ if ( (_cmd == CVS::Status) || (_cmd == CVS::Diff) )
+ _statusOutput += QString::fromLocal8Bit( buffer, len );
+}
+
+void CVSDialog::slotProcessStderr( KProcess*, char * buffer, int len )
+{
+ // If an error occurs while executing the command display stderr in
+ // another color.
+ QColor oldColor( output->color( ) );
+ output->setColor( Qt::red );
+ output->append( QString::fromLocal8Bit( buffer, len ) );
+ output->setColor( oldColor );
+ output->setCursorPosition( output->lines( ), 0 );
+}
+
+void CVSDialog::slotProcessExited( KProcess * p )
+{
+ if ( p->exitStatus( ) )
+ output->append( i18n( "[ Exited with status %1 ]" ).arg( p->exitStatus( ) ) );
+ else
+ output->append( i18n( "[ Finished ]" ) );
+
+ // The command is finished. Now we can reconnect the main button.
+ disconnect( mainBtn, 0, 0, 0 );
+ if ( _cmd == CVS::Diff )
+ mainBtn->setText( i18n( "&Show Diff" ) );
+ else
+ mainBtn->setText( i18n( "&Close" ) );
+ connect( mainBtn, SIGNAL( clicked( ) ), this, SLOT( accept( ) ) );
+
+ // Reenable the button and the log edit now that the process is finished.
+ mainBtn->setEnabled( true );
+ if ( _cmd == CVS::Commit )
+ logedit->setEnabled( true );
+}
+
+QString CVSDialog::statusOutput( )
+{
+ return _statusOutput;
+}
+
+void CVSDialog::readSettings( )
+{
+ KSharedConfig * config = m_config;
+ config->setGroup( "CVSSupport" );
+
+ if ( _cmd == CVS::Commit ) {
+ autoAddBox->setChecked( config->readBoolEntry( "AutoAddFiles", true ) );
+
+ // Fill the combobox with old messages.
+ m_logMessages.clear();
+ m_squeezedLogMessages.clear();
+ for ( int cnt = 0; cnt < 10; cnt++ )
+ if ( config->hasKey( QString( "CommitLogMessage%1" ).arg( cnt ) ) )
+ {
+ const QString logMessage = config->readEntry( QString( "CommitLogMessage%1" ).arg( cnt ) );
+ if ( !logMessage.isEmpty() )
+ {
+ // If the message is too long, cut it to 80 characters (or the combo box becomes too wide)
+ // ### FIXME: if the string matches the squeezed 80 chars, it might overwrite another entry
+ const QString shortLog = KStringHandler::csqueeze( logMessage );
+ m_logMessages.append( logMessage );
+ m_squeezedLogMessages.append( shortLog );
+ oldMessages->insertItem( shortLog );
+ }
+ }
+
+ m_encoding = config->readEntry( "CVSEncoding", "UTF-8" );
+ m_encodingComboBox->insertItem( i18n( "Descriptive encoding name", "Last choice ( %1 )" ).arg( m_encoding ), 0);
+ }
+}
+
+void CVSDialog::saveSettings( )
+{
+ KSharedConfig * config = m_config;
+ config->setGroup( "CVSSupport" );
+ if ( _cmd == CVS::Commit ) {
+ config->writeEntry( "AutoAddFiles", autoAddBox->isChecked( ) );
+
+ // Write the log messages to the config file.
+ int cnt = 0;
+ QStringList::const_iterator it;
+ for ( it = m_logMessages.constBegin( ); it != m_logMessages.constEnd( ) && cnt < 10 ; ++it, ++cnt )
+ config->writeEntry( QString( "CommitLogMessage%1" ).arg( cnt ), *it );
+
+ config->writeEntry( "CVSEncoding", m_encoding );
+ }
+ m_config->sync();
+}
+
+#include "cvsdialog.moc"
diff --git a/kbabel/catalogmanager/libcvs/cvsdialog.h b/kbabel/catalogmanager/libcvs/cvsdialog.h
new file mode 100644
index 00000000..658e9883
--- /dev/null
+++ b/kbabel/catalogmanager/libcvs/cvsdialog.h
@@ -0,0 +1,158 @@
+/* ****************************************************************************
+ This file is part of KBabel
+
+ Copyright (C) 2002-2003 by Marco Wegner <mail@marcowegner.de>
+ Copyright (C) 2005, 2006 by Nicolas GOUTTE <goutte@kde.org>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the 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, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+ In addition, as a special exception, the copyright holders give
+ permission to link the code of this program with any edition of
+ the Qt library by Trolltech AS, Norway (or with modified versions
+ of Qt that use the same license as Qt), and distribute linked
+ combinations including the two. You must obey the GNU General
+ Public License in all respects for all of the code used other than
+ Qt. If you modify this file, you may extend this exception to
+ your version of the file, but you are not obligated to do so. If
+ you do not wish to do so, delete this exception statement from
+ your version.
+
+**************************************************************************** */
+
+
+#ifndef CVSDIALOG_H
+#define CVSDIALOG_H
+
+// KDE include files
+#include <kdialog.h>
+// Project specific include files
+#include "cvsresources.h"
+// Forwarding Qt classes
+class QCheckBox;
+class QComboBox;
+class QListBox;
+class QPushButton;
+class QString;
+class QStringList;
+class QTextEdit;
+// Forwarding KDE classes
+class KProcess;
+class KTempFile;
+class KComboBox;
+
+/**
+ * This class represents the dialog which is used for executing CVS commands
+ * in KBabel's Catalog Manager. The dialog shows the list of files to be
+ * processed as well as the output from the command.
+ *
+ * In Commit mode there is also an option for automatically executing
+ * 'cvs add' if necessary.
+ *
+ * @short Dialog for CVS support in Catalog Manager
+ * @author Marco Wegner <mail@marcowegner.de>
+ */
+class CVSDialog : public KDialog
+{
+ Q_OBJECT
+
+ public:
+ /**
+ * Constructor for creating the dialog.
+ * @param cmd The type of command to be executed.
+ */
+ CVSDialog( CVS::Command cmd, QWidget * parent, KSharedConfig* config );
+ ~CVSDialog();
+ /**
+ * Set the list of files which will be used for the CVS command.
+ * @param files The list of files.
+ */
+ void setFiles( const QStringList& files );
+ /**
+ * Set the command line for the execution of the CVS command.
+ * @param command The command line.
+ */
+ void setCommandLine( const QString& command );
+ /**
+ * Set the command line for adding files to the CVS repository.
+ * This method is only used together with a 'cvs commit' for automatically
+ * adding files which are not yet in the repository.
+ * @param command The command line.
+ */
+ void setAddCommand( const QString& command );
+ /**
+ * Return the output of a 'cvs status' command.
+ * @returns The complete output.
+ */
+ QString statusOutput( );
+
+ protected:
+ /**
+ * This method is overwritten so that the settings can be saved after
+ * pressing the 'Close' button.
+ */
+ virtual void accept( );
+ /** Read the dialog's settings. */
+ void readSettings( );
+ /** Save the dialog's settings. */
+ void saveSettings( );
+
+ protected slots:
+ /** Slot for executing the CVS Command. */
+ void slotExecuteCommand( );
+ /** Slot for processing the stdout of the CVS Command. */
+ void slotProcessStdout( KProcess*, char * buffer, int len );
+ /** Slot for processing the stderr of the CVS Command. */
+ void slotProcessStderr( KProcess*, char * buffer, int len );
+ /** Slot for post-processing after the CVS command is fninished. */
+ void slotProcessExited( KProcess * p );
+ /// Slot for combox having been activated
+ void slotComboActivated( int );
+
+ private:
+ CVS::Command _cmd;
+
+ QPushButton * mainBtn;
+ QPushButton * cancelBtn;
+ QListBox * filebox;
+ QComboBox * oldMessages;
+ QTextEdit * logedit;
+ QTextEdit * output;
+ QCheckBox * autoAddBox;
+
+ KProcess * p;
+
+ QString _commandLine;
+ QString _addCommand;
+ QString _statusOutput;
+
+ /// Log messages (long version)
+ QStringList m_logMessages;
+ /// Log messages (short version)
+ QStringList m_squeezedLogMessages;
+
+ /// Temporary file (for commits)
+ KTempFile* m_tempFile;
+
+ /// Encoding for the commit log message
+ QString m_encoding;
+
+ /// Combo box for the encoding
+ KComboBox* m_encodingComboBox;
+
+ /// Configuration data (of the KBabel project)
+ KSharedConfig* m_config;
+};
+
+#endif // CVSDIALOG_H
diff --git a/kbabel/catalogmanager/libcvs/cvshandler.cpp b/kbabel/catalogmanager/libcvs/cvshandler.cpp
new file mode 100644
index 00000000..d3f2ae18
--- /dev/null
+++ b/kbabel/catalogmanager/libcvs/cvshandler.cpp
@@ -0,0 +1,398 @@
+/* ****************************************************************************
+ This file is part of KBabel
+
+ Copyright (C) 2002-2003 by Marco Wegner <mail@marcowegner.de>
+ Copyright (C) 2005, 2006 by Nicolas GOUTTE <goutte@kde.org>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the 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, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+ In addition, as a special exception, the copyright holders give
+ permission to link the code of this program with any edition of
+ the Qt library by Trolltech AS, Norway (or with modified versions
+ of Qt that use the same license as Qt), and distribute linked
+ combinations including the two. You must obey the GNU General
+ Public License in all respects for all of the code used other than
+ Qt. If you modify this file, you may extend this exception to
+ your version of the file, but you are not obligated to do so. If
+ you do not wish to do so, delete this exception statement from
+ your version.
+
+**************************************************************************** */
+
+
+// System include files
+#include <sys/stat.h>
+#include <time.h>
+#include <unistd.h>
+// Qt include files
+#include <qdir.h>
+#include <qfile.h>
+#include <qfileinfo.h>
+#include <qregexp.h>
+#include <qstring.h>
+#include <qstringlist.h>
+// KDE include files
+#include <kapplication.h>
+#include <klocale.h>
+#include <kmessagebox.h>
+#include <ktempfile.h>
+// project specific include files
+#include "cvshandler.h"
+
+
+CVSHandler::CVSHandler( const QString& poBaseDir, const QString& potBaseDir )
+{
+ setPOBaseDir( poBaseDir );
+ setPOTBaseDir( potBaseDir );
+ _autoUpdateTemplates = false;
+}
+
+void CVSHandler::setPOBaseDir( const QString& dir )
+{
+ // check if 'CVS/Entries' exists in the PO base directory
+ if ( QFileInfo( dir + "/CVS/Entries" ).exists( ) ) {
+ _isPORepository = true;
+ _poBaseDir = dir;
+ } else
+ _isPORepository = false;
+ emit signalIsPORepository( _isPORepository );
+}
+
+void CVSHandler::setPOTBaseDir( const QString& dir )
+{
+ // check if 'CVS/Entries' exists in the POT base directory
+ if ( QFileInfo( dir + "/CVS/Entries" ).exists( ) ) {
+ _isPOTRepository = true;
+ _potBaseDir = dir;
+ } else
+ _isPOTRepository = false;
+ emit signalIsPOTRepository( _isPOTRepository );
+}
+
+QString CVSHandler::fileStatus( const FileStatus status ) const
+{
+ switch ( status ) {
+ case NO_REPOSITORY:
+ return i18n( "No CVS repository" );
+ break;
+ case NOT_IN_CVS:
+ return i18n( "Not in CVS" );
+ break;
+ case LOCALLY_ADDED:
+ return i18n( "Locally added" );
+ break;
+ case LOCALLY_REMOVED:
+ return i18n( "Locally removed" );
+ break;
+ case LOCALLY_MODIFIED:
+ return i18n( "Locally modified" );
+ break;
+ case UP_TO_DATE:
+ return i18n( "Up-to-date" );
+ break;
+ case CONFLICT:
+ return i18n( "Conflict" );
+ break;
+ default:
+ return i18n( "Unknown" );
+ break;
+ }
+}
+
+CVSHandler::FileStatus CVSHandler::fstatus( const QString& filename ) const
+{
+ // no valid repository
+ if ( !_isPORepository )
+ return NO_REPOSITORY;
+
+ QString fn( filename );
+ fn = fn.remove( QRegExp( "/$" ) );
+
+ QFileInfo info( fn );
+
+ // check if 'CVS/Entries' exists and can be read
+ QFile entries( info.dir( true ).path( ) + "/CVS/Entries" );
+ if ( !entries.open( IO_ReadOnly ) )
+ return NOT_IN_CVS; // we already know that it's a repository
+
+ // ### FIXME: it does not take care of CVS/Entries.Log
+ // a line in CVS/Entries has the following format:
+ // [D]/NAME/REVISION/[CONFLICT+]TIMESTAMP/OPTIONS/TAGDATE
+ QRegExp rx( QString( "^D?/%1/" ).arg( info.fileName( ) ) );
+
+ QString temp;
+ QTextStream stream( &entries );
+
+ bool isInRepository = false;
+ while ( !stream.atEnd() ) {
+ temp = stream.readLine( );
+ if ( temp.find( rx ) == 0 ) {
+ isInRepository = true;
+ break;
+ }
+ }
+ entries.close( );
+
+ // no entry found
+ if ( !isInRepository )
+ return NOT_IN_CVS;
+
+ const QStringList fields = QStringList::split( '/', temp, true );
+ // bool isDir = ( fields[0] == "D" );
+ const QString cvsname( fields[1] );
+ const QString revision( fields[2] );
+ const QString timestamp( fields[3] );
+ // ignore the other fields for now
+
+ if ( revision == "0" && timestamp == "dummy timestamp" )
+ return LOCALLY_ADDED;
+ if ( revision.startsWith( "-" ) && timestamp == "dummy timestamp" )
+ return LOCALLY_REMOVED;
+
+ // check for conflicts
+ if ( timestamp.find( '+' ) >= 0 )
+ return CONFLICT;
+
+ // calculate the UTC time from the file's last modified date
+ struct stat st;
+ lstat( QFile::encodeName(fn), &st );
+ struct tm * tm_p = gmtime( &st.st_mtime );
+ QString ftime = QString( asctime( tm_p ) );
+ ftime.truncate( ftime.length( ) - 1 );
+ if ( ftime != timestamp )
+ return LOCALLY_MODIFIED;
+
+ return UP_TO_DATE;
+}
+
+QString CVSHandler::cvsStatus( const QString& filename ) const
+{
+ return map[filename];
+}
+
+void CVSHandler::execCVSCommand( QWidget* parent, CVS::Command cmd, const QString& filename, bool templates, KSharedConfig* config )
+{
+ if ( !_isPORepository ) {
+ // This message box should never be visible but who knows... ;-)
+ KMessageBox::sorry( parent, i18n( "This is not a valid CVS repository. "
+ "The CVS commands cannot be executed." ) );
+ return;
+ }
+
+ QFileInfo info( filename );
+ if ( !info.isDir( ) ) {
+ execCVSCommand( parent, cmd, QStringList( filename ), templates, config );
+ return;
+ }
+
+ // ### FIXME: instead of making a QString, use KProcess directly, so that it cares about quoting.
+ // ### FIXME: use KProcess::setWorkingDirectory instead of using "cd" (therefore allowing to use KProcess without a shell.)
+ // it's a dir
+ QString command( "cd " + filename + " && cvs " );
+ switch ( cmd ) {
+ case CVS::Update:
+ command += "update -dP";
+ break;
+ case CVS::Commit:
+ // The cvs client does not care about the encoding, so we cannot set anything here
+ command += "commit -F @LOG@FILE@";
+ checkToAdd( QStringList( filename ) );
+ break;
+ case CVS::Status:
+ command += "status";
+ break;
+ case CVS::Diff:
+ command += "diff";
+ break;
+ }
+
+ showDialog( parent, cmd, QStringList( filename ), command, config );
+}
+
+void CVSHandler::execCVSCommand( QWidget* parent, CVS::Command cmd, const QStringList& files, bool templates, KSharedConfig* config )
+{
+ if ( !_isPORepository ) {
+ // This message box should never be visible but who knows... ;-)
+ KMessageBox::sorry( parent, i18n( "This is not a valid CVS repository. "
+ "The CVS commands cannot be executed." ) );
+ return;
+ }
+
+ // ### FIXME: instead of making a QString, use KProcess directly, so that it cares about quoting.
+ // ### FIXME: use KProcess::setWorkingDirectory instead of using "cd" (therefore allowing to use KProcess without a shell.)
+ QString command("cd " + (templates ? _potBaseDir : _poBaseDir) + " && cvs ");
+ switch ( cmd ) {
+ case CVS::Update:
+ command += "update -dP";
+ break;
+ case CVS::Commit:
+ command += "commit -F @LOG@FILE@";
+ checkToAdd( files );
+ break;
+ case CVS::Status:
+ command += "status";
+ break;
+ case CVS::Diff:
+ command += "diff";
+ break;
+ }
+
+ QRegExp rx;
+ if (templates)
+ rx.setPattern(_potBaseDir + "/?");
+ else
+ rx.setPattern(_poBaseDir + "/?");
+
+ QStringList::ConstIterator it;
+ for ( it = files.begin( ); it != files.end( ); ++it ) {
+ QString temp = *it;
+ temp.remove(rx);
+ command += " \'" + temp + "\'";
+ }
+
+ showDialog( parent, cmd, files, command, config );
+}
+
+void CVSHandler::setAutoUpdateTemplates( bool update )
+{
+ _autoUpdateTemplates = update;
+}
+
+void CVSHandler::showDialog( QWidget* parent, CVS::Command cmd, const QStringList& files, const QString& commandLine, KSharedConfig* config )
+{
+ CVSDialog * dia = new CVSDialog( cmd, parent, config );
+ dia->setFiles( files );
+ dia->setCommandLine( commandLine );
+ if ( cmd == CVS::Commit ) {
+ dia->setAddCommand( _addCommand );
+ }
+
+ if ( dia->exec( ) == KDialog::Accepted ) {
+ if ( cmd == CVS::Status )
+ processStatusOutput( dia->statusOutput( ) );
+ if ( cmd == CVS::Diff )
+ processDiff( dia->statusOutput( ) );
+ }
+
+ delete dia;
+
+ // file status display update necessary in Catalog Manager
+ if ( cmd == CVS::Commit )
+ emit signalFilesCommitted( files );
+}
+
+void CVSHandler::checkToAdd( const QStringList& files )
+{
+ if ( files.isEmpty( ) )
+ return;
+
+ QStringList toBeAdded;
+
+ QStringList::ConstIterator it;
+ for ( it = files.begin( ); it != files.end( ); ++it ) {
+ // check for every entry if it needs to be added
+ if ( fstatus( *it ) == NOT_IN_CVS ) {
+ QFileInfo info( *it );
+ QString temp; // will hold the dir path
+ if ( info.isDir( ) ) {
+ toBeAdded << *it;
+ temp = *it;
+ } else {
+ toBeAdded << *it;
+ temp = QFileInfo( *it ).dirPath( true );
+ }
+ // check recursivlely if parent dirs have to be added as well
+ while ( fstatus( temp ) == NOT_IN_CVS && toBeAdded.findIndex( temp ) == -1 ) {
+ toBeAdded << temp;
+ temp = QFileInfo( temp ).dirPath( true );
+ }
+ }
+ }
+
+ // remove an old command
+ _addCommand.setLength( 0 );
+
+ // make sure the diectories are added before the files
+ toBeAdded.sort( );
+
+ // create a command line for adding the files and dirs
+ for ( it = toBeAdded.begin( ); it != toBeAdded.end( ); ++it ) {
+ QFileInfo info( *it );
+ _addCommand += "cd " + info.dirPath( true ) + " && cvs add " + info.fileName( ) + "; ";
+ }
+}
+
+void CVSHandler::processStatusOutput( const QString& status )
+{
+ if ( !_isPORepository )
+ return;
+
+ // at first we need to extract the name of the base directory on the server
+ QFile f( _poBaseDir + "/CVS/Root" );
+ if ( !f.open( IO_ReadOnly ) )
+ return;
+
+ QTextStream stream( &f );
+ // extract the string after the last colon in the first line
+ QString basedir = stream.readLine( ).section( ':', -1 );
+
+ f.close( );
+
+ // divide the complete status output in little chunks for every file
+ QStringList entries = QStringList::split( QRegExp( "={67,67}" ), status );
+ QStringList::Iterator it;
+ for ( it = entries.begin( ); it != entries.end( ); ++it ) {
+ QString entr = *it;
+ // translate the filename from repository to local
+ QRegExp rx( basedir + ".*,v" );
+ int pos = entr.find( rx );
+ QString file = _poBaseDir + entr.mid( pos + basedir.length( ),
+ rx.matchedLength( ) - basedir.length( ) - 2 );
+
+ entr = "<qt>" + entr + "</qt>";
+
+ // TODO: do some markup
+
+ map.replace( file, entr );
+ }
+}
+
+void CVSHandler::processDiff( QString output )
+{
+ output.remove( QRegExp( "\\[ .* \\]$" ));
+ output.remove( QRegExp( "^" + i18n("[ Starting command ]" ).replace("[","\\[").replace("]","\\]")));
+
+ KTempFile tmpFile;
+ *(tmpFile.textStream()) << output;
+ tmpFile.close();
+
+ QString error;
+ if ( KApplication::startServiceByName( "Kompare", tmpFile.name(), &error ) )
+ KMessageBox::error( 0, error );
+}
+
+bool CVSHandler::isConsideredModified( const FileStatus status ) const
+{
+ /*
+ * A file is modified if it is either:
+ * - locally modified for CVS
+ * - directory under CVS control but not the file
+ */
+ return status == LOCALLY_MODIFIED || status == NOT_IN_CVS;
+}
+
+
+
+#include "cvshandler.moc"
diff --git a/kbabel/catalogmanager/libcvs/cvshandler.h b/kbabel/catalogmanager/libcvs/cvshandler.h
new file mode 100644
index 00000000..44777aa3
--- /dev/null
+++ b/kbabel/catalogmanager/libcvs/cvshandler.h
@@ -0,0 +1,114 @@
+/* ****************************************************************************
+ This file is part of KBabel
+
+ Copyright (C) 2002-2003 by Marco Wegner <mail@marcowegner.de>
+ Copyright (C) 2005, 2006 by Nicolas GOUTTE <goutte@kde.org>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the 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, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+ In addition, as a special exception, the copyright holders give
+ permission to link the code of this program with any edition of
+ the Qt library by Trolltech AS, Norway (or with modified versions
+ of Qt that use the same license as Qt), and distribute linked
+ combinations including the two. You must obey the GNU General
+ Public License in all respects for all of the code used other than
+ Qt. If you modify this file, you may extend this exception to
+ your version of the file, but you are not obligated to do so. If
+ you do not wish to do so, delete this exception statement from
+ your version.
+
+**************************************************************************** */
+
+
+#ifndef CVSHANDLER_H
+#define CVSHANDLER_H
+
+// Qt include files
+#include <qmap.h>
+#include <qobject.h>
+// Project specific include files
+#include "cvsdialog.h"
+#include "cvsresources.h"
+// Forwarding Qt classes
+class QString;
+class QStringList;
+class QWidget;
+
+class KSharedConfig;
+
+/**
+ * This class is the backend for CVS support in Catalog Manager.
+ *
+ * @short Backend for CVS support in Catalog Manager
+ * @author Marco Wegner <mail@marcowegner.de>
+ */
+class CVSHandler : public QObject
+{
+ Q_OBJECT
+
+ public:
+ enum FileStatus {
+ NO_REPOSITORY,
+ NOT_IN_CVS,
+ LOCALLY_ADDED,
+ LOCALLY_REMOVED,
+ LOCALLY_MODIFIED,
+ CONFLICT,
+ UP_TO_DATE
+ };
+
+ CVSHandler( const QString& poBaseDir = QString::null, const QString& potBaseDir = QString::null );
+
+ void setPOBaseDir( const QString& dir );
+ void setPOTBaseDir( const QString& dir );
+
+ FileStatus fstatus( const QString& filename ) const;
+ QString fileStatus( const FileStatus status ) const;
+ QString cvsStatus( const QString& filename ) const;
+
+ void execCVSCommand( QWidget* parent, CVS::Command cmd, const QString& filename, bool templates, KSharedConfig* config );
+ void execCVSCommand( QWidget* parent, CVS::Command cmd, const QStringList& files, bool templates, KSharedConfig* config );
+
+ void setAutoUpdateTemplates( bool update );
+
+ /**
+ * True if the file was modified or has another status considered as a modification
+ */
+ bool isConsideredModified( const FileStatus status ) const;
+
+ signals:
+ void signalIsPORepository( bool );
+ void signalIsPOTRepository( bool );
+ void signalFilesCommitted( const QStringList& );
+
+ private:
+ void showDialog( QWidget* parent, CVS::Command cmd, const QStringList& files, const QString& commandLine, KSharedConfig* config );
+ void checkToAdd( const QStringList& files );
+ void processStatusOutput( const QString& status );
+ void processDiff( QString output );
+
+ private:
+ QString _poBaseDir;
+ QString _potBaseDir;
+ bool _isPORepository;
+ bool _isPOTRepository;
+ bool _autoUpdateTemplates;
+ QString _addCommand;
+
+ /** Mapping the output of 'cvs status' against the filename. */
+ QMap<QString,QString> map;
+};
+
+#endif // CVSHANDLER_H
diff --git a/kbabel/catalogmanager/libcvs/cvsresources.h b/kbabel/catalogmanager/libcvs/cvsresources.h
new file mode 100644
index 00000000..627802f7
--- /dev/null
+++ b/kbabel/catalogmanager/libcvs/cvsresources.h
@@ -0,0 +1,41 @@
+/* ****************************************************************************
+ This file is part of KBabel
+
+ Copyright (C) 2002-2003 by Marco Wegner <mail@marcowegner.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.
+
+ 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, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+ In addition, as a special exception, the copyright holders give
+ permission to link the code of this program with any edition of
+ the Qt library by Trolltech AS, Norway (or with modified versions
+ of Qt that use the same license as Qt), and distribute linked
+ combinations including the two. You must obey the GNU General
+ Public License in all respects for all of the code used other than
+ Qt. If you modify this file, you may extend this exception to
+ your version of the file, but you are not obligated to do so. If
+ you do not wish to do so, delete this exception statement from
+ your version.
+
+**************************************************************************** */
+
+
+#ifndef CVSRESOURCES_H
+#define CVSRESOURCES_H
+
+namespace CVS {
+ enum Command { Update, Commit, Status, Diff };
+}
+
+#endif // CVSRESOURCES_H
diff --git a/kbabel/catalogmanager/libsvn/Makefile.am b/kbabel/catalogmanager/libsvn/Makefile.am
new file mode 100644
index 00000000..7c340974
--- /dev/null
+++ b/kbabel/catalogmanager/libsvn/Makefile.am
@@ -0,0 +1,11 @@
+noinst_LTLIBRARIES = libcatalogmanagersvn.la
+
+# set the include path for X, qt and KDE
+INCLUDES = -I.. -I../../common $(all_includes)
+
+libcatalogmanagersvn_la_SOURCES = svnhandler.cpp svndialog.cpp
+
+noinst_HEADERS = svnhandler.h svndialog.h svnresources.h
+
+# let automoc handle all of the meta source files (moc)
+METASOURCES = AUTO
diff --git a/kbabel/catalogmanager/libsvn/svndialog.cpp b/kbabel/catalogmanager/libsvn/svndialog.cpp
new file mode 100644
index 00000000..69653591
--- /dev/null
+++ b/kbabel/catalogmanager/libsvn/svndialog.cpp
@@ -0,0 +1,400 @@
+/* ****************************************************************************
+ This file is part of KBabel
+
+ Copyright (C) 2002-2003 by Marco Wegner <mail@marcowegner.de>
+ Copyright (C) 2005, 2006 by Nicolas GOUTTE <goutte@kde.org>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the 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, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+ In addition, as a special exception, the copyright holders give
+ permission to link the code of this program with any edition of
+ the Qt library by Trolltech AS, Norway (or with modified versions
+ of Qt that use the same license as Qt), and distribute linked
+ combinations including the two. You must obey the GNU General
+ Public License in all respects for all of the code used other than
+ Qt. If you modify this file, you may extend this exception to
+ your version of the file, but you are not obligated to do so. If
+ you do not wish to do so, delete this exception statement from
+ your version.
+
+**************************************************************************** */
+
+
+// Qt include files
+#include <qcheckbox.h>
+#include <qcombobox.h>
+#include <qfileinfo.h>
+#include <qframe.h>
+#include <qlabel.h>
+#include <qlayout.h>
+#include <qlistbox.h>
+#include <qpushbutton.h>
+#include <qstring.h>
+#include <qstringlist.h>
+#include <qtextedit.h>
+// KDE include files
+#include <kconfig.h>
+#include <kdebug.h>
+#include <kglobal.h>
+#include <klocale.h>
+#include <kprocess.h>
+#include <ktempfile.h>
+#include <kmessagebox.h>
+#include <kstringhandler.h>
+// Project specific include files
+#include "svndialog.h"
+
+
+SVNDialog::SVNDialog( SVN::Command cmd, QWidget * parent, KSharedConfig* config )
+ : KDialog( parent, "SVN DIALOG", true ), m_tempFile( 0 ), m_config( config )
+{
+ _cmd = cmd;
+ p=0L;
+ setCaption( i18n( "SVN Dialog" ) );
+
+ QString temp;
+
+ QVBoxLayout * layout = new QVBoxLayout( this, 6, 6, "MAIN LAYOUT" );
+
+ // Set the label's text depending on the SVN command.
+ switch ( cmd ) {
+ case SVN::Update:
+ temp = i18n( "Update the following files:" );
+ break;
+ case SVN::Commit:
+ temp = i18n( "Commit the following files:" );
+ break;
+ case SVN::StatusRemote:
+ temp = i18n( "Get remote status for the following files:" );
+ break;
+ case SVN::StatusLocal:
+ temp = i18n( "Get local status for the following files:" );
+ break;
+ case SVN::Diff:
+ temp = i18n( "Get diff for the following files:" );
+ break;
+ case SVN::Info:
+ temp = i18n( "Get information for the following files:" );
+ break;
+ }
+ layout->addWidget( new QLabel( temp, this ) );
+
+ // Widget for showing the list of files.
+ filebox = new QListBox( this );
+ layout->addWidget( filebox );
+
+ // Add special widgets for 'svn commit'.
+ if ( cmd == SVN::Commit ) {
+ QLabel * label;
+
+ // Combobox for displaying old log messages.
+ label = new QLabel( i18n( "&Old messages:" ), this );
+ oldMessages = new QComboBox( this );
+ oldMessages->setDuplicatesEnabled( false );
+ label->setBuddy( oldMessages );
+ layout->addWidget( label );
+ layout->addWidget( oldMessages );
+
+ // Textfield for entering a log message.
+ label = new QLabel( i18n( "&Log message:" ), this );
+ logedit = new QTextEdit( this );
+ label->setBuddy( logedit );
+ layout->addWidget( label );
+ layout->addWidget( logedit );
+
+ connect( oldMessages, SIGNAL( activated( int ) ),
+ this, SLOT( slotComboActivated( int ) ) );
+ }
+
+ QHBoxLayout * buttons = new QHBoxLayout( 0, 0, 6, "BUTTON LAYOUT" );
+ // Add special buttons for 'svn commit'.
+ if ( cmd == SVN::Commit ) {
+ autoAddBox = new QCheckBox( i18n( "Auto&matically add files if necessary" ), this );
+ buttons->addWidget( autoAddBox );
+ }
+ buttons->addItem( new QSpacerItem( 1, 0, QSizePolicy::Expanding, QSizePolicy::Minimum ) );
+
+ // Set the main button's text depending on the SVN comand.
+ switch ( cmd ) {
+ case SVN::Update:
+ temp = i18n( "&Update" );
+ break;
+ case SVN::Commit:
+ temp = i18n( "&Commit" );
+ break;
+ case SVN::StatusRemote:
+ case SVN::StatusLocal:
+ temp = i18n( "&Get Status" );
+ break;
+ case SVN::Diff:
+ temp = i18n( "&Get Diff" );
+ break;
+ case SVN::Info:
+ temp = i18n( "&Get Information" );
+ break;
+ }
+ mainBtn = new QPushButton( temp, this );
+ mainBtn->setDefault( true );
+ buttons->addWidget( mainBtn );
+
+ cancelBtn = new QPushButton( i18n( "C&ancel" ), this );
+ buttons->addWidget( cancelBtn );
+ layout->addLayout( buttons );
+
+ QFrame * line = new QFrame( this );
+ line->setFrameStyle( QFrame::HLine | QFrame::Sunken );
+ layout->addWidget( line );
+
+ layout->addWidget( new QLabel( i18n( "Command output:" ), this ) );
+
+ output = new QTextEdit( this );
+ output->setReadOnly( true );
+ layout->addWidget( output );
+
+ resize( QSize( 600, 450 ).expandedTo( minimumSizeHint( ) ) );
+
+ if ( cmd == SVN::Commit )
+ logedit->setFocus( );
+
+ readSettings( );
+
+ connect( mainBtn, SIGNAL( clicked( ) ), this, SLOT( slotExecuteCommand( ) ) );
+ connect( cancelBtn, SIGNAL( clicked( ) ), this, SLOT( reject( ) ) );
+}
+
+void SVNDialog::slotComboActivated( int index )
+{
+ if ( index < 0 || index >= m_logMessages.count() )
+ return;
+ logedit->setText( m_logMessages[index] );
+}
+
+SVNDialog::~SVNDialog()
+{
+ delete m_tempFile;
+ delete p;
+}
+
+void SVNDialog::accept( )
+{
+ saveSettings( );
+ KDialog::accept( );
+}
+
+void SVNDialog::setFiles( const QStringList& files )
+{
+ filebox->insertStringList( files );
+}
+
+void SVNDialog::setCommandLine( const QString& command )
+{
+ _commandLine = command;
+}
+
+void SVNDialog::setAddCommand( const QString& command )
+{
+ _addCommand = command;
+}
+
+void SVNDialog::slotExecuteCommand( )
+{
+ // Nothing to do here.
+ if ( _commandLine.isEmpty( ) ) return;
+
+ kdDebug() << "Preparing KProcess" << endl;
+
+ // Create a new shell process
+ p = new KProcess;
+ p->setUseShell( true, "/bin/sh" );
+
+ if ( _cmd == SVN::Commit ) {
+ // Include command for 'svn add'.
+ if ( autoAddBox->isChecked( ) && !_addCommand.isEmpty( ) )
+ _commandLine.prepend( _addCommand );
+
+ const QString msg( logedit->text() );
+
+ if ( msg.isEmpty() )
+ {
+ // A good commit should never have an empty comment, so ask the user if he really wants it.
+ const int res = KMessageBox::warningContinueCancel( this,
+ i18n( "The commit log message is empty. Do you want to continue?" ) );
+ if ( res != KMessageBox::Continue )
+ return;
+ }
+
+ // Write the commit log message from the input field to a temporary file
+ m_tempFile = new KTempFile;
+ m_tempFile->setAutoDelete( true );
+ QTextStream* stream = m_tempFile->textStream();
+ if ( !stream )
+ {
+ kdError() << "Could not create QTextStream for file " << m_tempFile->name();
+ delete m_tempFile;
+ m_tempFile = 0;
+ KMessageBox::error( this, i18n( "Cannot open temporary file for writing. Aborting.") );
+ return;
+ }
+ stream->setEncoding( QTextStream::UnicodeUTF8 );
+ *stream << msg;
+ m_tempFile->close();
+
+ if ( m_tempFile->status() )
+ {
+ kdError() << "Could not write to file " << m_tempFile->name();
+ delete m_tempFile;
+ m_tempFile = 0;
+ KMessageBox::error( this, i18n( "Cannot write to temporary file. Aborting.") );
+ return;
+ }
+
+ // Change the command line to have the real name of the temporary file
+ _commandLine.replace( "@LOG@FILE@", KProcess::quote( m_tempFile->name() ) );
+
+ // Update the list of log messages
+ if ( !msg.isEmpty() ) {
+ const QString shortLog = KStringHandler::csqueeze( msg, 80 );
+
+
+ // Remove the message from the list if it already exists
+ m_logMessages.remove( msg );
+ // Prepend the current message to the list
+ m_logMessages.prepend( msg );
+
+ // At this time of the process, we do not need the combobox anymore, so we do not squeeze the changed strings.
+ }
+ }
+
+ // Set the KProcess' command line.
+ *p << _commandLine;
+
+ connect( p, SIGNAL( receivedStdout( KProcess*, char*, int ) ),
+ this, SLOT ( slotProcessStdout( KProcess*, char*, int ) ) );
+ connect( p, SIGNAL( receivedStderr( KProcess*, char*, int ) ),
+ this, SLOT ( slotProcessStderr( KProcess*, char*, int ) ) );
+ connect( p, SIGNAL( processExited( KProcess* ) ),
+ this, SLOT( slotProcessExited( KProcess* ) ) );
+
+ output->append( i18n( "[ Starting command ]" ) );
+
+ if ( p->start( KProcess::NotifyOnExit, KProcess::Communication( KProcess::AllOutput ) ) ) {
+ // Disable the main button (and the log edit if in commit mode) to
+ // indicate activity.
+ mainBtn->setEnabled( false );
+ if ( _cmd == SVN::Commit )
+ logedit->setEnabled( false );
+ } else
+ {
+ kdError() << "Process could not be started." << endl;
+ KMessageBox::error( this, i18n( "The process could not be started." ) );
+ }
+}
+
+void SVNDialog::slotProcessStdout( KProcess*, char * buffer, int len )
+{
+ output->append( QString::fromLocal8Bit( buffer, len ) );
+ // Set the cursor's position at the end of the output.
+ output->setCursorPosition( output->lines( ), 0 );
+
+ // If the command is 'svn status' or 'svn diff' collect the output of stdout.
+ if ( ( _cmd == SVN::StatusLocal ) || ( _cmd == SVN::StatusRemote ) || ( _cmd == SVN::Diff ) )
+ _statusOutput += QString::fromLocal8Bit( buffer, len );
+}
+
+void SVNDialog::slotProcessStderr( KProcess*, char * buffer, int len )
+{
+ // If an error occurs while executing the command display stderr in
+ // another color.
+ QColor oldColor( output->color( ) );
+ output->setColor( Qt::red );
+ output->append( QString::fromLocal8Bit( buffer, len ) );
+ output->setColor( oldColor );
+ output->setCursorPosition( output->lines( ), 0 );
+}
+
+void SVNDialog::slotProcessExited( KProcess * p )
+{
+ if ( p->exitStatus( ) )
+ output->append( i18n( "[ Exited with status %1 ]" ).arg( p->exitStatus( ) ) );
+ else
+ output->append( i18n( "[ Finished ]" ) );
+
+ // The command is finished. Now we can reconnect the main button.
+ disconnect( mainBtn, 0, 0, 0 );
+ if ( _cmd == SVN::Diff )
+ mainBtn->setText( i18n( "&Show Diff" ) );
+ else
+ mainBtn->setText( i18n( "&Close" ) );
+ connect( mainBtn, SIGNAL( clicked( ) ), this, SLOT( accept( ) ) );
+
+ // Reenable the button and the log edit now that the process is finished.
+ mainBtn->setEnabled( true );
+ if ( _cmd == SVN::Commit )
+ logedit->setEnabled( true );
+}
+
+QString SVNDialog::statusOutput( )
+{
+ return _statusOutput;
+}
+
+void SVNDialog::readSettings( )
+{
+ KSharedConfig * config = m_config;
+ config->setGroup( "SVNSupport" );
+
+ if ( _cmd == SVN::Commit ) {
+ autoAddBox->setChecked( config->readBoolEntry( "AutoAddFiles", true ) );
+
+ // Fill the combobox with old messages.
+ m_logMessages.clear();
+ m_squeezedLogMessages.clear();
+ for ( int cnt = 0; cnt < 10; cnt++ )
+ if ( config->hasKey( QString( "CommitLogMessage%1" ).arg( cnt ) ) )
+ {
+ const QString logMessage = config->readEntry( QString( "CommitLogMessage%1" ).arg( cnt ) );
+ if ( !logMessage.isEmpty() )
+ {
+ // If the message is too long, cut it to 80 characters (or the combo box becomes too wide)
+ // ### FIXME: if the string matches the squeezed 80 chars, it might overwrite another entry
+ const QString shortLog = KStringHandler::csqueeze( logMessage );
+ m_logMessages.append( logMessage );
+ m_squeezedLogMessages.append( shortLog );
+ oldMessages->insertItem( shortLog );
+ }
+ }
+
+ }
+}
+
+void SVNDialog::saveSettings( )
+{
+ KSharedConfig * config = m_config;
+ config->setGroup( "SVNSupport" );
+ if ( _cmd == SVN::Commit ) {
+ config->writeEntry( "AutoAddFiles", autoAddBox->isChecked( ) );
+
+ // Write the log messages to the config file.
+ int cnt = 0;
+ QStringList::const_iterator it;
+ for ( it = m_logMessages.constBegin( ); it != m_logMessages.constEnd( ) && cnt < 10 ; ++it, ++cnt )
+ config->writeEntry( QString( "CommitLogMessage%1" ).arg( cnt ), *it );
+ }
+ m_config->sync();
+}
+
+#include "svndialog.moc"
+
+// kate: space-indent on; indent-width 2; replace-tabs on;
diff --git a/kbabel/catalogmanager/libsvn/svndialog.h b/kbabel/catalogmanager/libsvn/svndialog.h
new file mode 100644
index 00000000..0c824fa8
--- /dev/null
+++ b/kbabel/catalogmanager/libsvn/svndialog.h
@@ -0,0 +1,151 @@
+/* ****************************************************************************
+ This file is part of KBabel
+
+ Copyright (C) 2002-2003 by Marco Wegner <mail@marcowegner.de>
+ Copyright (C) 2005, 2006 by Nicolas GOUTTE <goutte@kde.org>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the 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, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+ In addition, as a special exception, the copyright holders give
+ permission to link the code of this program with any edition of
+ the Qt library by Trolltech AS, Norway (or with modified versions
+ of Qt that use the same license as Qt), and distribute linked
+ combinations including the two. You must obey the GNU General
+ Public License in all respects for all of the code used other than
+ Qt. If you modify this file, you may extend this exception to
+ your version of the file, but you are not obligated to do so. If
+ you do not wish to do so, delete this exception statement from
+ your version.
+
+**************************************************************************** */
+
+
+#ifndef SVNDIALOG_H
+#define SVNDIALOG_H
+
+// KDE include files
+#include <kdialog.h>
+// Project specific include files
+#include "svnresources.h"
+// Forwarding Qt classes
+class QCheckBox;
+class QComboBox;
+class QListBox;
+class QPushButton;
+class QString;
+class QStringList;
+class QTextEdit;
+// Forwarding KDE classes
+class KProcess;
+class KTempFile;
+class KSharedConfig;
+
+/**
+ * This class represents the dialog which is used for executing SVN commands
+ * in KBabel's Catalog Manager. The dialog shows the list of files to be
+ * processed as well as the output from the command.
+ *
+ * In Commit mode there is also an option for automatically executing
+ * 'svn add' if necessary.
+ *
+ * @short Dialog for SVN support in Catalog Manager
+ */
+class SVNDialog : public KDialog
+{
+ Q_OBJECT
+
+ public:
+ /**
+ * Constructor for creating the dialog.
+ * @param cmd The type of command to be executed.
+ */
+ SVNDialog( SVN::Command cmd, QWidget * parent, KSharedConfig* config );
+ ~SVNDialog();
+ /**
+ * Set the list of files which will be used for the SVN command.
+ * @param files The list of files.
+ */
+ void setFiles( const QStringList& files );
+ /**
+ * Set the command line for the execution of the SVN command.
+ * @param command The command line.
+ */
+ void setCommandLine( const QString& command );
+ /**
+ * Set the command line for adding files to the SVN repository.
+ * This method is only used together with a 'svn commit' for automatically
+ * adding files which are not yet in the repository.
+ * @param command The command line.
+ */
+ void setAddCommand( const QString& command );
+ /**
+ * Return the output of a 'svn status' command.
+ * @returns The complete output.
+ */
+ QString statusOutput( );
+
+ protected:
+ /**
+ * This method is overwritten so that the settings can be saved after
+ * pressing the 'Close' button.
+ */
+ virtual void accept( );
+ /** Read the dialog's settings. */
+ void readSettings( );
+ /** Save the dialog's settings. */
+ void saveSettings( );
+
+ protected slots:
+ /** Slot for executing the SVN Command. */
+ void slotExecuteCommand( );
+ /** Slot for processing the stdout of the SVN Command. */
+ void slotProcessStdout( KProcess*, char * buffer, int len );
+ /** Slot for processing the stderr of the SVN Command. */
+ void slotProcessStderr( KProcess*, char * buffer, int len );
+ /** Slot for post-processing after the SVN command is fninished. */
+ void slotProcessExited( KProcess * p );
+ /// Slot for combox having been activated
+ void slotComboActivated( int );
+
+ private:
+ SVN::Command _cmd;
+
+ QPushButton * mainBtn;
+ QPushButton * cancelBtn;
+ QListBox * filebox;
+ QComboBox * oldMessages;
+ QTextEdit * logedit;
+ QTextEdit * output;
+ QCheckBox * autoAddBox;
+
+ KProcess * p;
+
+ QString _commandLine;
+ QString _addCommand;
+ QString _statusOutput;
+
+ /// Log messages (long version)
+ QStringList m_logMessages;
+ /// Log messages (short version)
+ QStringList m_squeezedLogMessages;
+
+ /// Temporary file (for commits)
+ KTempFile* m_tempFile;
+
+ /// Configuration data (of the KBabel project)
+ KSharedConfig* m_config;
+};
+
+#endif // SVNDIALOG_H
diff --git a/kbabel/catalogmanager/libsvn/svnhandler.cpp b/kbabel/catalogmanager/libsvn/svnhandler.cpp
new file mode 100644
index 00000000..8117fe62
--- /dev/null
+++ b/kbabel/catalogmanager/libsvn/svnhandler.cpp
@@ -0,0 +1,544 @@
+/* ****************************************************************************
+ This file is part of KBabel
+
+ Copyright (C) 2002-2003 by Marco Wegner <mail@marcowegner.de>
+ Copyright (C) 2005, 2006 by Nicolas GOUTTE <goutte@kde.org>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the 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, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+ In addition, as a special exception, the copyright holders give
+ permission to link the code of this program with any edition of
+ the Qt library by Trolltech AS, Norway (or with modified versions
+ of Qt that use the same license as Qt), and distribute linked
+ combinations including the two. You must obey the GNU General
+ Public License in all respects for all of the code used other than
+ Qt. If you modify this file, you may extend this exception to
+ your version of the file, but you are not obligated to do so. If
+ you do not wish to do so, delete this exception statement from
+ your version.
+
+**************************************************************************** */
+
+
+// System include files
+#include <unistd.h>
+#include <sys/stat.h>
+#include <time.h>
+// Qt include files
+#include <qdir.h>
+#include <qfile.h>
+#include <qfileinfo.h>
+#include <qregexp.h>
+#include <qstring.h>
+#include <qstringlist.h>
+#include <qdom.h>
+// KDE include files
+#include <kapplication.h>
+#include <klocale.h>
+#include <kmessagebox.h>
+#include <ktempfile.h>
+#include <kdebug.h>
+#include <kprocess.h>
+// project specific include files
+#include "svnhandler.h"
+
+SVNHandler::SVNHandler( const QString& poBaseDir, const QString& potBaseDir )
+{
+ setPOBaseDir( poBaseDir );
+ setPOTBaseDir( potBaseDir );
+ _autoUpdateTemplates = false;
+}
+
+void SVNHandler::setPOBaseDir( const QString& dir )
+{
+ // check if '.svn/entries' exists in the PO base directory
+ if ( QFileInfo( dir + "/.svn/entries" ).exists( ) ) {
+ _isPORepository = true;
+ _poBaseDir = dir;
+ } else
+ _isPORepository = false;
+ emit signalIsPORepository( _isPORepository );
+}
+
+void SVNHandler::setPOTBaseDir( const QString& dir )
+{
+ // check if '.svn/entries' exists in the POT base directory
+ if ( QFileInfo( dir + "/.svn/entries" ).exists( ) ) {
+ _isPOTRepository = true;
+ _potBaseDir = dir;
+ } else
+ _isPOTRepository = false;
+ emit signalIsPOTRepository( _isPOTRepository );
+}
+
+QString SVNHandler::fileStatus( const FileStatus status ) const
+{
+ switch ( status ) {
+ case NO_REPOSITORY:
+ return i18n( "No SVN repository" );
+ break;
+ case NOT_IN_SVN:
+ return i18n( "Not in SVN" );
+ break;
+ case LOCALLY_ADDED:
+ return i18n( "Locally added" );
+ break;
+ case LOCALLY_REMOVED:
+ return i18n( "Locally removed" );
+ break;
+ case LOCALLY_MODIFIED:
+ return i18n( "Locally modified" );
+ break;
+ case UP_TO_DATE:
+ return i18n( "Up-to-date" );
+ break;
+ case CONFLICT:
+ return i18n( "Conflict" );
+ break;
+ case ERROR_IN_WC:
+ return i18n( "Error in Working Copy" );
+ default:
+ return i18n( "Unknown" );
+ break;
+ }
+}
+
+SVNHandler::FileStatus SVNHandler::fstatus( const QString& filename ) const
+{
+ // no valid repository
+ if ( !_isPORepository )
+ return NO_REPOSITORY;
+
+ QString fn( filename );
+ fn = fn.remove( QRegExp( "/$" ) );
+
+ QFileInfo info( fn );
+
+ // check if '.svn/entries' exists.
+ QFile entries( info.dir( true ).path( ) + "/.svn/entries" );
+
+ if ( !entries.exists() )
+ return NOT_IN_SVN;
+
+ KProcess proc;
+ SVNOutputCollector out( &proc );
+
+ proc << "svn" << "status" << "-v" << "--xml" << info.absFilePath();
+
+ if( !proc.start( KProcess::Block, KProcess::Stdout ) )
+ return ERROR_IN_WC;
+
+ QDomDocument doc;
+ QString errorMsg;
+ int errorLine, errorCol;
+ QDomNodeList nodelist;
+ QDomNode node;
+ QDomElement entry, wcStatus;
+
+ // Parse the output.
+ if ( !doc.setContent( out.getOutput(), &errorMsg, &errorLine, &errorCol ) ) {
+ kdDebug(8109) << "Cannot parse \"svn status -v --xml\" output for"
+ << filename << endl << "Line: " << errorLine << " Column: "
+ << errorCol << " Error: " << errorMsg << endl;
+ goto no_status_xml;
+ }
+
+ // There should be only one "entry" element. If it doesn't exist, path
+ // isn't repo path at all.
+ nodelist = doc.elementsByTagName("entry");
+ if (nodelist.count() < 1)
+ return NOT_IN_SVN;
+
+ entry = nodelist.item(0).toElement();
+
+ // Shouldn't fail, but just in case there is some weird error.
+ if ( entry.attributeNode("path").value() != info.absFilePath() )
+ return ERROR_IN_WC;
+
+ for ( node = entry.firstChild(); !node.isNull(); node = node.nextSibling() ) {
+ if ( !node.isElement() )
+ continue;
+ if (node.toElement().tagName() == "wc-status")
+ break;
+ }
+
+ if ( node.isNull() )
+ return ERROR_IN_WC;
+
+ wcStatus = node.toElement();
+
+ if ( wcStatus.attributeNode("item").value() == "normal" )
+ return UP_TO_DATE;
+ if ( wcStatus.attributeNode("item").value() == "modified" )
+ return LOCALLY_MODIFIED;
+ if ( wcStatus.attributeNode("item").value() == "conflicted" )
+ return CONFLICT;
+ if ( wcStatus.attributeNode("item").value() == "unversioned" )
+ return NOT_IN_SVN;
+ // TODO Ignored entry should have separate return value probably.
+ if ( wcStatus.attributeNode("item").value() == "ignored" )
+ return NOT_IN_SVN;
+ if ( wcStatus.attributeNode("item").value() == "added" )
+ return LOCALLY_ADDED;
+ if ( wcStatus.attributeNode("item").value() == "deleted" )
+ return LOCALLY_REMOVED;
+ // TODO What to do with "missing", "incomplete", "replaced", "merged",
+ // "obstructed", "external"? Can these appear at all in our case?
+
+ return ERROR_IN_WC;
+
+no_status_xml:
+ if ( !entries.open( IO_ReadOnly ) )
+ return ERROR_IN_WC; // we already know that it is a repository
+
+ // Parse the entries file
+ if ( !doc.setContent( &entries, &errorMsg, &errorLine, &errorCol ) ) {
+ kdDebug() << "Cannot parse .svn/entries file for " << filename << endl
+ << "Line: " << errorLine << " Column: " << errorCol << " Error: " << errorMsg << endl;
+ return ERROR_IN_WC;
+ }
+ entries.close();
+
+ QDomElement element;
+ // File name that we are searching
+ const QString findName = info.fileName();
+ // The entries are <entry> elements, so we have to check them
+ QDomNode child = doc.documentElement().firstChild();
+ for ( ; !child.isNull() ; child = child.nextSibling() )
+ {
+ if ( !child.isElement() )
+ continue;
+ element = child.toElement();
+ if ( element.tagName() != "entry" ) {
+ // We have another kind of element, so skip it
+ // Should not happend with svn 1.1.x
+ continue;
+ }
+ const QString name = element.attribute("name");
+ if ( name == findName )
+ break;
+ }
+
+ if ( child.isNull() ) {
+ // We have not found an entry for the file
+ return NOT_IN_SVN;
+ }
+
+ // ### TODO: should we check the attribute kind to be file and not dir?
+
+ // ### TODO: what do copy and move add here?
+ const QString onSchedule = element.attribute( "schedule" );
+ if ( onSchedule == "delete" )
+ return LOCALLY_REMOVED;
+ else if ( onSchedule == "added" )
+ return LOCALLY_ADDED;
+
+ if ( element.hasAttribute( "conflict-new" ) || element.hasAttribute( "conflict-old" ) || element.hasAttribute( "conflict-wrk" ) ) {
+ return CONFLICT;
+ }
+
+ // Note: we do not check the property time stamp
+ const QString textTimeStamp( element.attribute( "text-time" ) );
+
+ // calculate the UTC time from the file's last modified date
+ struct stat st;
+ lstat( QFile::encodeName(fn), &st );
+ struct tm * tm_p = gmtime( &st.st_mtime );
+ const int year = tm_p->tm_year + 1900;
+ const int month = tm_p->tm_mon + 1;
+ QString fileTime;
+ fileTime.sprintf( "%04i-%02i-%02iT%02i:%02i:%02i.000000Z",
+ year, month, tm_p->tm_mday, tm_p->tm_hour, tm_p->tm_min, tm_p->tm_sec );
+ //kdDebug() << "File: " << filename << " SVN time: " << textTimeStamp << " File time: " << fileTime << endl;
+ if ( fileTime > textTimeStamp ) // ISO 8601 dates/times can be compared as strings if they have the exact same format.
+ return LOCALLY_MODIFIED;
+
+ return UP_TO_DATE;
+
+}
+
+QString SVNHandler::svnStatus( const QString& filename ) const
+{
+ return map[filename];
+}
+
+void SVNHandler::execSVNCommand( QWidget* parent, SVN::Command cmd, const QString& filename, bool templates, KSharedConfig* config)
+{
+ // Unlike cvs, svn works also from outside the repository(as long as the path is in a repository of course!)
+ // ### FIXME: wrong, svn commit cannot work if the current directory is not a SVN one
+ execSVNCommand( parent, cmd, QStringList( filename ), templates, config );
+}
+
+void SVNHandler::execSVNCommand( QWidget* parent, SVN::Command cmd, const QStringList& files, bool templates, KSharedConfig* config )
+{
+ if ( !_isPORepository ) {
+ // This message box should never be visible but who knows... ;-)
+ KMessageBox::sorry( parent, i18n( "This is not a valid SVN repository. "
+ "The SVN commands cannot be executed." ) );
+ return;
+ }
+
+ // ### TODO: instead of making a QString, use KProcess directly, so that it cares about quoting.
+ // ### TODO: use KProcess::setWorkingDirectory instead of using "cd" (therefore allowing to use KProcess without a shell.)
+ QString command("cd " + (templates ? _potBaseDir : _poBaseDir) + " && svn ");
+ switch ( cmd ) {
+ case SVN::Update:
+ command += "update --non-interactive";
+ break;
+ case SVN::Commit:
+ // The svn client allows to choose the encoding, so we select UTF-8
+ command += "commit -F @LOG@FILE@ --encoding UTF-8 --non-interactive";
+ checkToAdd( files );
+ break;
+ case SVN::StatusRemote:
+ command += "status -u --non-interactive";
+ break;
+ case SVN::StatusLocal:
+ command += "status --non-interactive";
+ break;
+ case SVN::Diff:
+ command += "diff --non-interactive";
+ break;
+ case SVN::Info:
+ command += "info"; // Does not allow --non-interactive (at least svn 1.1.4).
+ }
+
+ QRegExp rx;
+ if (templates)
+ rx.setPattern(_potBaseDir + "/?");
+ else
+ rx.setPattern(_poBaseDir + "/?");
+
+ QStringList::ConstIterator it;
+ for ( it = files.begin( ); it != files.end( ); ++it ) {
+ QString temp = *it;
+ temp.remove(rx);
+ command += " \'" + temp + "\'";
+ }
+
+ showDialog( parent, cmd, files, command, config );
+}
+
+void SVNHandler::setAutoUpdateTemplates( bool update )
+{
+ _autoUpdateTemplates = update;
+}
+
+void SVNHandler::showDialog( QWidget* parent, SVN::Command cmd, const QStringList& files, const QString& commandLine, KSharedConfig* config )
+{
+ SVNDialog * dia = new SVNDialog( cmd, parent, config );
+ dia->setFiles( files );
+ dia->setCommandLine( commandLine );
+ if ( cmd == SVN::Commit ) {
+ dia->setAddCommand( _addCommand );
+ }
+
+ if ( dia->exec( ) == KDialog::Accepted ) {
+ if ( cmd == SVN::StatusLocal || cmd == SVN::StatusRemote )
+ processStatusOutput( dia->statusOutput( ) );
+ if ( cmd == SVN::Diff )
+ processDiff( dia->statusOutput( ) );
+ }
+
+ delete dia;
+
+ // file status display update necessary in Catalog Manager
+ if ( cmd == SVN::Commit )
+ emit signalFilesCommitted( files );
+}
+
+bool SVNHandler::isInSvn( const QString& path )
+{
+ if ( path.isEmpty() )
+ return false;
+
+ /*
+ * We need to check if a file is in a SVN repository.
+ *
+ * But as we want to do it quickly (because this function will be called for a few files in a row)
+ * we should avoid to parse the .svn/entries files
+ *
+ * Therefore we only check for the SVN auxilary files that are typical for a file controlled by SVN:
+ * - for a directory: checks if the directory has a .svn/entries file
+ * - for a file: check if there is a corresponding file in .svn/text-base/
+ */
+
+ const QFileInfo info( path );
+ if ( info.isDir() ) {
+ // It is a directory, so find a .svn/entries file
+ QDir dir( path );
+ return dir.exists( ".svn/entries", true );
+ }
+ else {
+ // It is a file, so find the corresponding file in .svn/text-base
+ QDir dir( info.dirPath() );
+ if ( ! dir.cd( ".svn/text-base" ) ) {
+ // There is not even a .svn/text-base directory, so the file is not under control
+ return false;
+ }
+ const QString textBaseFilename( info.fileName() + ".svn-base" );
+ return dir.exists( textBaseFilename, true );
+ }
+}
+
+void SVNHandler::checkToAdd( const QStringList& files )
+{
+ if ( files.isEmpty( ) )
+ return;
+
+ QStringList toBeAdded;
+
+ QStringList::ConstIterator it;
+ for ( it = files.begin( ); it != files.end( ); ++it ) {
+ // check for every entry if it needs to be added
+ if ( ! isInSvn( *it ) ) {
+ QFileInfo info( *it );
+ QString temp; // will hold the dir path
+ if ( info.isDir( ) ) {
+ toBeAdded << *it;
+ temp = *it;
+ } else {
+ toBeAdded << *it;
+ temp = QFileInfo( *it ).dirPath( true );
+ }
+
+ // ### TODO: does SVN really needs this or does it do it automatically?
+ // check recursivlely if parent dirs have to be added as well
+ while ( ! isInSvn( temp ) && toBeAdded.findIndex( temp ) == -1 ) {
+ toBeAdded << temp;
+ temp = QFileInfo( temp ).dirPath( true );
+ }
+
+ }
+ }
+
+ // remove an old command
+ _addCommand = QString();
+
+ // ### TODO: does SVN really need this?
+ // make sure the directories are added before the files
+ toBeAdded.sort( );
+
+ // ### TODO: try to make this better
+ // create a command line for adding the files and dirs
+ for ( it = toBeAdded.begin( ); it != toBeAdded.end( ); ++it ) {
+ QFileInfo info( *it );
+ _addCommand += "cd " + info.dirPath( true ) + " && svn add " + info.fileName( ) + "; ";
+ }
+}
+
+// ### TODO: convert to SVN
+void SVNHandler::processStatusOutput( const QString& status )
+{
+ if ( !_isPORepository )
+ return;
+
+#if 0
+ // at first we need to extract the name of the base directory on the server
+ QFile f( _poBaseDir + "/SVN/Root" ); // ### FIXME
+ if ( !f.open( IO_ReadOnly ) )
+ return;
+
+ QTextStream stream( &f );
+ // extract the string after the last colon in the first line
+ QString basedir = stream.readLine( ).section( ':', -1 );
+
+ f.close( );
+
+ // divide the complete status output in little chunks for every file
+ QStringList entries = QStringList::split( QRegExp( "={67,67}" ), status );
+ QStringList::Iterator it;
+ for ( it = entries.begin( ); it != entries.end( ); ++it ) {
+ QString entr = *it;
+ // translate the filename from repository to local
+ QRegExp rx( basedir + ".*,v" );
+ int pos = entr.find( rx );
+ QString file = _poBaseDir + entr.mid( pos + basedir.length( ),
+ rx.matchedLength( ) - basedir.length( ) - 2 );
+
+ entr = "<qt>" + entr + "</qt>";
+
+ // TODO: do some markup
+
+ map.replace( file, entr );
+ }
+#endif
+}
+
+void SVNHandler::processDiff( QString output )
+{
+ output.remove( QRegExp( "\\[ .* \\]$" ));
+ output.remove( QRegExp( "^" + i18n("[ Starting command ]" ).replace("[","\\[").replace("]","\\]")));
+
+ KTempFile tmpFile;
+ *(tmpFile.textStream()) << output;
+ tmpFile.close();
+
+ QString error;
+ if ( KApplication::startServiceByName( "Kompare", tmpFile.name(), &error ) )
+ KMessageBox::error( 0, error );
+}
+
+bool SVNHandler::isConsideredModified( const FileStatus status ) const
+{
+ /*
+ * A file is modified if it is either:
+ * - locally modified for SVN
+ * - directory under SVN control but not the file
+ */
+
+ // ### TODO: what about moved and copied?
+ return status == LOCALLY_MODIFIED || status == NOT_IN_SVN;
+}
+
+SVNOutputCollector::SVNOutputCollector( KProcess* p )
+ : m_process(0)
+{
+ setProcess( p );
+}
+
+void SVNOutputCollector::setProcess( KProcess* p )
+{
+ if( m_process )
+ m_process->disconnect( this );
+
+ m_process = p;
+ if( p ) {
+ connect( p, SIGNAL(receivedStdout(KProcess*, char*, int)),
+ this, SLOT(slotGatherStdout(KProcess*, char*, int)) );
+ connect( p, SIGNAL(receivedStderr(KProcess*, char*, int)),
+ this, SLOT(slotGatherStderr(KProcess*, char*, int)) );
+ }
+
+ m_gatheredOutput.truncate( 0 );
+ m_stderrOutput.truncate( 0 );
+ m_stdoutOutput.truncate( 0 );
+}
+
+void SVNOutputCollector::slotGatherStderr( KProcess*, char* data, int len )
+{
+ m_gatheredOutput.append( QString::fromLocal8Bit( data, len ) );
+ m_stderrOutput.append( QString::fromLocal8Bit( data, len ) );
+}
+
+void SVNOutputCollector::slotGatherStdout( KProcess*, char* data, int len )
+{
+ m_gatheredOutput.append( QString::fromLocal8Bit( data, len ) );
+ m_stdoutOutput.append( QString::fromLocal8Bit( data, len ) );
+}
+
+#include "svnhandler.moc"
+
+// kate: space-indent on; indent-width 2; replace-tabs on;
diff --git a/kbabel/catalogmanager/libsvn/svnhandler.h b/kbabel/catalogmanager/libsvn/svnhandler.h
new file mode 100644
index 00000000..67c86d73
--- /dev/null
+++ b/kbabel/catalogmanager/libsvn/svnhandler.h
@@ -0,0 +1,138 @@
+/* ****************************************************************************
+ This file is part of KBabel
+
+ Copyright (C) 2002-2003 by Marco Wegner <mail@marcowegner.de>
+ Copyright (C) 2005, 2006 by Nicolas GOUTTE <goutte@kde.org>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the 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, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+ In addition, as a special exception, the copyright holders give
+ permission to link the code of this program with any edition of
+ the Qt library by Trolltech AS, Norway (or with modified versions
+ of Qt that use the same license as Qt), and distribute linked
+ combinations including the two. You must obey the GNU General
+ Public License in all respects for all of the code used other than
+ Qt. If you modify this file, you may extend this exception to
+ your version of the file, but you are not obligated to do so. If
+ you do not wish to do so, delete this exception statement from
+ your version.
+
+**************************************************************************** */
+
+
+#ifndef SVNHANDLER_H
+#define SVNHANDLER_H
+
+// Qt include files
+#include <qmap.h>
+#include <qobject.h>
+// Project specific include files
+#include "svndialog.h"
+#include "svnresources.h"
+// Forwarding Qt classes
+class QString;
+class QStringList;
+
+class KSharedConfig;
+
+/**
+ * This class is the backend for SVN support in Catalog Manager.
+ *
+ * @short Backend for SVN support in Catalog Manager
+ */
+class SVNHandler : public QObject
+{
+ Q_OBJECT
+
+ public:
+ enum FileStatus {
+ NO_REPOSITORY,
+ NOT_IN_SVN,
+ LOCALLY_ADDED,
+ LOCALLY_REMOVED,
+ LOCALLY_MODIFIED,
+ CONFLICT,
+ UP_TO_DATE,
+ ERROR_IN_WC ///< The working copy has data that cannot be handled
+ };
+
+ SVNHandler( const QString& poBaseDir = QString::null, const QString& potBaseDir = QString::null );
+
+ void setPOBaseDir( const QString& dir );
+ void setPOTBaseDir( const QString& dir );
+
+ FileStatus fstatus( const QString& filename ) const;
+ QString fileStatus( const FileStatus status ) const;
+ QString svnStatus( const QString& filename ) const;
+
+ void execSVNCommand( QWidget* parent, SVN::Command cmd, const QString& filename, bool templates, KSharedConfig* config );
+ void execSVNCommand( QWidget* parent, SVN::Command cmd, const QStringList& files, bool templates, KSharedConfig* config );
+
+ void setAutoUpdateTemplates( bool update );
+
+ /**
+ * True if the file was modified or has another status considered as a modification
+ */
+ bool isConsideredModified( const FileStatus status ) const;
+
+ signals:
+ void signalIsPORepository( bool );
+ void signalIsPOTRepository( bool );
+ void signalFilesCommitted( const QStringList& );
+
+ private:
+ void showDialog( QWidget* parent, SVN::Command cmd, const QStringList& files, const QString& commandLine, KSharedConfig* config );
+ /// Check quickly if the file is part of a SVN repository
+ bool isInSvn( const QString& path );
+ void checkToAdd( const QStringList& files );
+ void processStatusOutput( const QString& status );
+ void processDiff( QString output );
+
+ private:
+ QString _poBaseDir;
+ QString _potBaseDir;
+ bool _isPORepository;
+ bool _isPOTRepository;
+ bool _autoUpdateTemplates;
+ QString _addCommand;
+
+ /** Mapping the output of 'svn status' against the filename. */
+ QMap<QString,QString> map;
+};
+
+class SVNOutputCollector: public QObject
+{
+ Q_OBJECT
+
+ public:
+ SVNOutputCollector( KProcess* );
+ void setProcess( KProcess* );
+
+ const QString& getOutput() const { return m_gatheredOutput; }
+ const QString& getStderr() const { return m_stderrOutput; }
+ const QString& getStdout() const { return m_stdoutOutput; }
+
+ private slots:
+ void slotGatherStderr( KProcess*, char*, int );
+ void slotGatherStdout( KProcess*, char*, int );
+
+ private:
+ QString m_gatheredOutput;
+ QString m_stderrOutput;
+ QString m_stdoutOutput;
+ KProcess* m_process;
+};
+
+#endif // SVNHANDLER_H
diff --git a/kbabel/catalogmanager/libsvn/svnresources.h b/kbabel/catalogmanager/libsvn/svnresources.h
new file mode 100644
index 00000000..d9032a4f
--- /dev/null
+++ b/kbabel/catalogmanager/libsvn/svnresources.h
@@ -0,0 +1,50 @@
+/* ****************************************************************************
+ This file is part of KBabel
+
+ Copyright (C) 2002-2003 by Marco Wegner <mail@marcowegner.de>
+ Copyright (C) 2005 by Nicolas GOUTTE <goutte@kde.org>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the 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, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+ In addition, as a special exception, the copyright holders give
+ permission to link the code of this program with any edition of
+ the Qt library by Trolltech AS, Norway (or with modified versions
+ of Qt that use the same license as Qt), and distribute linked
+ combinations including the two. You must obey the GNU General
+ Public License in all respects for all of the code used other than
+ Qt. If you modify this file, you may extend this exception to
+ your version of the file, but you are not obligated to do so. If
+ you do not wish to do so, delete this exception statement from
+ your version.
+
+**************************************************************************** */
+
+
+#ifndef SVNRESOURCES_H
+#define SVNRESOURCES_H
+
+namespace SVN {
+ enum Command
+ {
+ Update, ///< svn update
+ Commit, ///< svn commit
+ StatusLocal, ///< svn status
+ StatusRemote, ///< svn status -u
+ Diff, ///< svn diff
+ Info ///< svn info
+ };
+}
+
+#endif // SVNRESOURCES_H
diff --git a/kbabel/catalogmanager/lo16-app-catalogmanager.png b/kbabel/catalogmanager/lo16-app-catalogmanager.png
new file mode 100644
index 00000000..27a7f453
--- /dev/null
+++ b/kbabel/catalogmanager/lo16-app-catalogmanager.png
Binary files differ
diff --git a/kbabel/catalogmanager/lo32-app-catalogmanager.png b/kbabel/catalogmanager/lo32-app-catalogmanager.png
new file mode 100644
index 00000000..eef514b4
--- /dev/null
+++ b/kbabel/catalogmanager/lo32-app-catalogmanager.png
Binary files differ
diff --git a/kbabel/catalogmanager/main.cpp b/kbabel/catalogmanager/main.cpp
new file mode 100644
index 00000000..868df92a
--- /dev/null
+++ b/kbabel/catalogmanager/main.cpp
@@ -0,0 +1,232 @@
+/* ****************************************************************************
+ This file is part of KBabel
+
+ Copyright (C) 1999-2001 by Matthias Kiefer
+ <matthias.kiefer@gmx.de>
+ 2001-2004 by Stanislav Visnovsky
+ <visnovsky@kde.org>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the 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, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+ In addition, as a special exception, the copyright holders give
+ permission to link the code of this program with any edition of
+ the Qt library by Trolltech AS, Norway (or with modified versions
+ of Qt that use the same license as Qt), and distribute linked
+ combinations including the two. You must obey the GNU General
+ Public License in all respects for all of the code used other than
+ Qt. If you modify this file, you may extend this exception to
+ your version of the file, but you are not obligated to do so. If
+ you do not wish to do so, delete this exception statement from
+ your version.
+
+**************************************************************************** */
+#include "kbprojectmanager.h"
+#include "catalogmanager.h"
+#include "catalogmanageriface.h"
+#include "catalog.h"
+#include "catalogmanagerapp.h"
+#include "poinfo.h"
+
+#include "version.h"
+#include "resources.h"
+
+#include <dcopclient.h>
+#include <kaboutdata.h>
+#include <kcmdlineargs.h>
+#include <kcursor.h>
+#include <klocale.h>
+#include <kiconloader.h>
+#include <kmessagebox.h>
+#include <kapplication.h>
+#include <kwin.h>
+#include <kmainwindow.h>
+
+#include <qfile.h>
+#include <qfileinfo.h>
+#include <qregexp.h>
+#include <qtimer.h>
+
+CatalogManager *CatalogManagerApp::_view = 0;
+
+CatalogManagerApp::CatalogManagerApp()
+ : KApplication()
+{
+ kbInterface = new CatalogManagerInterface;
+ _view = 0;
+ _preferredWindow = 0;
+}
+
+CatalogManagerApp::~CatalogManagerApp()
+{
+ delete kbInterface;
+ KBabel::PoInfo::cacheWrite();
+}
+
+void CatalogManagerApp::setPreferredWindow(WId id)
+{
+ _preferredWindow = id;
+ if( _view )
+ {
+ _view->raise();
+ KWin::activateWindow(_view->winId());
+ }
+}
+
+void CatalogManagerApp::updatedFile(QCString url)
+{
+ if( _view )
+ _view->updateFile(url);
+}
+
+QCString CatalogManagerApp::findNextFile()
+{
+ QString reply = "";
+ if( !CatalogManager::_foundFilesList.isEmpty() )
+ {
+ reply = CatalogManager::_foundFilesList.first();
+ CatalogManager::_foundFilesList.pop_front();
+ if( _view ) _view->decreaseNumberOfFound();
+ } else
+ {
+ if( !CatalogManager::_toBeSearched.isEmpty() )
+ reply = QString(""); // nothing found yet
+ else
+ return QCString(); // not found definitely
+ }
+
+ return reply.utf8();
+}
+
+int CatalogManagerApp::newInstance()
+{
+ if( isRestored() )
+ {
+ int n = 1;
+ while (KMainWindow::canBeRestored(n)){
+ CatalogManager* cm = new CatalogManager();
+ cm->restore(n);
+ n++;
+
+ // this view will be used as DCOP dispatcher
+ if( !_view )
+ _view = cm;
+ }
+ }
+ else
+ {
+ KCmdLineArgs *args = KCmdLineArgs::parsedArgs();
+
+ QString configfile = args->getOption("project");
+
+ if( !configfile.isEmpty() )
+ {
+ QFileInfo fi( configfile );
+ configfile = fi.absFilePath();
+ }
+ else
+ {
+ configfile = KBabel::ProjectManager::defaultProjectName();
+ }
+
+ _view=new CatalogManager(configfile);
+
+ _view->setPreferredWindow( _preferredWindow );
+ _view->show();
+ _view->raise();
+ KWin::activateWindow(_view->winId());
+
+ args->clear();
+ }
+
+ return 0;
+}
+
+CatalogManagerInterface::CatalogManagerInterface()
+ : DCOPObject("CatalogManagerIFace")
+{
+}
+
+void CatalogManagerInterface::setPreferredWindow( WId id )
+{
+ CatalogManagerApp::setPreferredWindow(id);
+}
+
+QCString CatalogManagerInterface::findNextFile()
+{
+ return CatalogManagerApp::findNextFile();
+}
+
+void CatalogManagerInterface::updatedFile( QCString url )
+{
+ CatalogManagerApp::updatedFile(url);
+}
+
+static KCmdLineOptions options[] =
+{
+ {"project <configfile>",I18N_NOOP("File to load configuration from"),0},
+ KCmdLineLastOption
+};
+
+
+int main(int argc, char **argv)
+{
+ KLocale::setMainCatalogue("kbabel");
+ KAboutData about("catalogmanager",I18N_NOOP("KBabel - Catalog Manager"),VERSION,
+ I18N_NOOP("An advanced catalog manager for KBabel"),KAboutData::License_GPL,
+ I18N_NOOP("(c) 1999,2000,2001,2002,2003,2004,2005,2006 The KBabel developers"),0,"http://kbabel.kde.org");
+
+ about.addAuthor("Matthias Kiefer",I18N_NOOP("Original author"),"kiefer@kde.org");
+ about.addAuthor("Stanislav Visnovsky",I18N_NOOP("Current maintainer, porting to KDE3/Qt3.")
+ ,"visnovsky@kde.org");
+ about.addAuthor("Nicolas Goutte", I18N_NOOP("Current maintainer"), "goutte@kde.org");
+
+ about.addCredit("Claudiu Costin",I18N_NOOP("Wrote documentation and sent "
+ "many bug reports and suggestions for improvements.")
+ ,"claudiuc@kde.org");
+ about.addCredit("Thomas Diehl",I18N_NOOP("Gave many suggestions for the GUI "
+ "and the behavior of KBabel. He also contributed the beautiful splash screen.")
+ ,"thd@kde.org");
+ about.addCredit("Wolfram Diestel"
+ ,I18N_NOOP("Wrote diff algorithm, fixed KSpell and gave a lot "
+ "of useful hints."),"wolfram@steloj.de");
+ about.addCredit("Stephan Kulow",I18N_NOOP("Helped keep KBabel up to date "
+ "with the KDE API and gave a lot of other help."),"coolo@kde.org");
+ about.addCredit("Dwayne Bailey",I18N_NOOP("Various validation plugins.")
+ ,"dwayne@translate.org.za");
+ about.addCredit("SuSE GmbH"
+ ,I18N_NOOP("Sponsored development of KBabel for a while.")
+ ,"suse@suse.de","http://www.suse.de");
+ about.addCredit("Bram Schoenmakers",I18N_NOOP("Support for making diffs and some minor "
+ "improvements."),"bramschoenmakers@kde.nl");
+
+ about.addCredit("Trolltech", I18N_NOOP("KBabel contains code from Qt"), 0, "http://www.trolltech.com");
+
+ about.addCredit("GNU gettext", I18N_NOOP("KBabel contains code from GNU gettext"), 0, "http://www.gnu.org/software/gettext/");
+
+ // Initialize command line args
+ KCmdLineArgs::init(argc, argv, &about);
+
+ // Tell which options are supported
+ KCmdLineArgs::addCmdLineOptions( options );
+
+ // Add options from other components
+ KApplication::addCmdLineOptions();
+
+ CatalogManagerApp app;
+
+ app.newInstance();
+
+ return app.exec();
+}
diff --git a/kbabel/catalogmanager/markpatterndialog.cpp b/kbabel/catalogmanager/markpatterndialog.cpp
new file mode 100644
index 00000000..efe893a2
--- /dev/null
+++ b/kbabel/catalogmanager/markpatterndialog.cpp
@@ -0,0 +1,172 @@
+/* ****************************************************************************
+ This file is part of KBabel
+
+ Copyright (C) 2003 by Marco Wegner <mail@marcowegner.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.
+
+ 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, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+ In addition, as a special exception, the copyright holders give
+ permission to link the code of this program with any edition of
+ the Qt library by Trolltech AS, Norway (or with modified versions
+ of Qt that use the same license as Qt), and distribute linked
+ combinations including the two. You must obey the GNU General
+ Public License in all respects for all of the code used other than
+ Qt. If you modify this file, you may extend this exception to
+ your version of the file, but you are not obligated to do so. If
+ you do not wish to do so, delete this exception statement from
+ your version.
+
+**************************************************************************** */
+
+
+#include <qcheckbox.h>
+#include <qlabel.h>
+#include <qpushbutton.h>
+#include <qradiobutton.h>
+
+#include <kcombobox.h>
+#include <kcompletion.h>
+#include <kconfig.h>
+#include <kglobal.h>
+#include <klocale.h>
+#include <kparts/componentfactory.h>
+#include <kregexpeditorinterface.h>
+
+#include "markpatterndialog.h"
+#include "markpatternwidget.h"
+
+MarkPatternDialog::MarkPatternDialog(QWidget * parent, const char * name)
+ : KDialogBase(parent, name, true, 0, Ok|Cancel, Ok)
+{
+ actionButton(Ok)->setEnabled(false);
+
+ mainWidget = new MarkPatternWidget(this);
+
+ connect (mainWidget->combo, SIGNAL(textChanged(const QString&)),
+ this, SLOT(slotComboTextChanged(const QString&)));
+
+ comboCompletion = mainWidget->combo->completionObject( );
+
+ regexpEditDialog = 0;
+ if (!KTrader::self( )->query("KRegExpEditor/KRegExpEditor").isEmpty( )) {
+ connect(mainWidget->regexpButton, SIGNAL(clicked( )), this, SLOT(slotRegexpButtonClicked( )));
+ } else {
+ disconnect(mainWidget->useRegExp, 0, mainWidget->regexpButton, 0);
+ delete mainWidget->regexpButton;
+ mainWidget->regexpButton = 0;
+ }
+
+ restoreSettings( );
+
+ actionButton(Ok)->setEnabled(!mainWidget->combo->currentText( ).isEmpty( ));
+ mainWidget->combo->setFocus( );
+ setMainWidget( mainWidget);
+}
+
+void MarkPatternDialog::accept( )
+{
+ // Update the list of patterns.
+ patternList.remove(mainWidget->combo->currentText( ));
+ patternList.prepend(mainWidget->combo->currentText( ));
+ while (patternList.count( ) > 10)
+ patternList.remove(patternList.last( ));
+
+ saveSettings( );
+ KDialogBase::accept( );
+}
+
+QString MarkPatternDialog::pattern( )
+{
+ return mainWidget->combo->currentText( );
+}
+
+bool MarkPatternDialog::isCaseSensitive( )
+{
+ return mainWidget->caseSensitive->isChecked( );
+}
+
+bool MarkPatternDialog::includeTemplates( )
+{
+ return mainWidget->inclTemplates->isChecked( );
+}
+
+bool MarkPatternDialog::useRegExp( )
+{
+ return mainWidget->useRegExp->isChecked( );
+}
+
+void MarkPatternDialog::setMode(bool markMode)
+{
+ if (markMode) {
+ mainWidget->mainLabel->setText(i18n("Ma&rk files which match the following pattern:"));
+ setButtonOKText(i18n("&Mark Files"));
+ } else {
+ mainWidget->mainLabel->setText(i18n("Unma&rk files which match the following pattern:"));
+ setButtonOKText(i18n("Un&mark Files"));
+ }
+}
+
+void MarkPatternDialog::slotComboTextChanged(const QString& text)
+{
+ actionButton(Ok)->setEnabled(!text.isEmpty( ));
+}
+
+void MarkPatternDialog::slotRegexpButtonClicked( )
+{
+ if (!regexpEditDialog)
+ regexpEditDialog = KParts::ComponentFactory::createInstanceFromQuery<QDialog>(
+ "KRegExpEditor/KRegExpEditor", QString::null, this);
+
+ KRegExpEditorInterface * iface = dynamic_cast<KRegExpEditorInterface *>(regexpEditDialog);
+
+ if (iface) {
+ iface->setRegExp(mainWidget->combo->currentText( ));
+ if (regexpEditDialog->exec( ) == QDialog::Accepted)
+ mainWidget->combo->setCurrentText(iface->regExp( ));
+ }
+}
+
+void MarkPatternDialog::restoreSettings( )
+{
+ KConfig * config = KGlobal::config( );
+ config->setGroup("MarkPatternDialog");
+
+ patternList = config->readListEntry("Patterns");
+ mainWidget->combo->insertStringList(patternList);
+ comboCompletion->insertItems(patternList);
+ mainWidget->caseSensitive->setChecked(config->readBoolEntry("CaseSensitive", false));
+ mainWidget->inclTemplates->setChecked(config->readBoolEntry("IncludeTemplates", false));
+
+ bool rx = config->readBoolEntry("UseRegExp", false);
+ if (rx)
+ mainWidget->useRegExp->setChecked(true);
+ else
+ mainWidget->useWildcards->setChecked(true);
+ if (mainWidget->regexpButton)
+ mainWidget->regexpButton->setEnabled(mainWidget->useRegExp->isChecked( ));
+}
+
+void MarkPatternDialog::saveSettings( )
+{
+ KConfig * config = KGlobal::config( );
+ config->setGroup("MarkPatternDialog");
+
+ config->writeEntry("Patterns", patternList);
+ config->writeEntry("CaseSensitive", mainWidget->caseSensitive->isChecked( ));
+ config->writeEntry("IncludeTemplates", mainWidget->inclTemplates->isChecked( ));
+ config->writeEntry("UseRegExp", mainWidget->useRegExp->isChecked( ));
+}
+
+#include "markpatterndialog.moc"
diff --git a/kbabel/catalogmanager/markpatterndialog.h b/kbabel/catalogmanager/markpatterndialog.h
new file mode 100644
index 00000000..c8ec1218
--- /dev/null
+++ b/kbabel/catalogmanager/markpatterndialog.h
@@ -0,0 +1,75 @@
+/* ****************************************************************************
+ This file is part of KBabel
+
+ Copyright (C) 2003 by Marco Wegner <mail@marcowegner.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.
+
+ 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, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+ In addition, as a special exception, the copyright holders give
+ permission to link the code of this program with any edition of
+ the Qt library by Trolltech AS, Norway (or with modified versions
+ of Qt that use the same license as Qt), and distribute linked
+ combinations including the two. You must obey the GNU General
+ Public License in all respects for all of the code used other than
+ Qt. If you modify this file, you may extend this exception to
+ your version of the file, but you are not obligated to do so. If
+ you do not wish to do so, delete this exception statement from
+ your version.
+
+**************************************************************************** */
+
+
+#ifndef MARKPATTERNDIALOG_H
+#define MARKPATTERNDIALOG_H
+
+#include <kdialogbase.h>
+
+class KCompletion;
+
+class MarkPatternWidget;
+
+class MarkPatternDialog : public KDialogBase
+{
+ Q_OBJECT
+
+ public:
+ MarkPatternDialog(QWidget * parent, const char * name = 0);
+
+ QString pattern( );
+ bool isCaseSensitive( );
+ bool useRegExp( );
+ bool includeTemplates( );
+
+ void setMode(bool markMode);
+
+ protected:
+ virtual void accept( );
+ void restoreSettings( );
+ void saveSettings( );
+
+ protected slots:
+ void slotComboTextChanged(const QString& text);
+ void slotRegexpButtonClicked( );
+
+ private:
+ MarkPatternWidget * mainWidget;
+ QDialog * regexpEditDialog;
+
+ QStringList patternList;
+
+ KCompletion * comboCompletion;
+};
+
+#endif // MARKPATTERNDIALOG_H
diff --git a/kbabel/catalogmanager/markpatternwidget.ui b/kbabel/catalogmanager/markpatternwidget.ui
new file mode 100644
index 00000000..b4b8745e
--- /dev/null
+++ b/kbabel/catalogmanager/markpatternwidget.ui
@@ -0,0 +1,127 @@
+<!DOCTYPE UI><UI version="3.2" stdsetdef="1">
+<class>MarkPatternWidget</class>
+<widget class="QWidget">
+ <property name="name">
+ <cstring>MarkPatternWidget</cstring>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>374</width>
+ <height>276</height>
+ </rect>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>mainLabel</cstring>
+ </property>
+ <property name="text">
+ <string>To be set dynamically:</string>
+ </property>
+ <property name="buddy" stdset="0">
+ <cstring>combo</cstring>
+ </property>
+ </widget>
+ <widget class="KComboBox">
+ <property name="name">
+ <cstring>combo</cstring>
+ </property>
+ <property name="editable">
+ <bool>true</bool>
+ </property>
+ </widget>
+ <widget class="QButtonGroup">
+ <property name="name">
+ <cstring>buttonGroup1</cstring>
+ </property>
+ <property name="title">
+ <string>Options</string>
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QCheckBox" row="0" column="0" rowspan="1" colspan="2">
+ <property name="name">
+ <cstring>caseSensitive</cstring>
+ </property>
+ <property name="text">
+ <string>C&amp;ase sensitive</string>
+ </property>
+ </widget>
+ <widget class="QCheckBox" row="1" column="0" rowspan="1" colspan="2">
+ <property name="name">
+ <cstring>inclTemplates</cstring>
+ </property>
+ <property name="text">
+ <string>&amp;Include templates</string>
+ </property>
+ </widget>
+ <widget class="QRadioButton" row="3" column="0">
+ <property name="name">
+ <cstring>useWildcards</cstring>
+ </property>
+ <property name="text">
+ <string>Use &amp;wildcards</string>
+ </property>
+ </widget>
+ <widget class="QPushButton" row="4" column="1">
+ <property name="name">
+ <cstring>regexpButton</cstring>
+ </property>
+ <property name="text">
+ <string>&amp;Edit</string>
+ </property>
+ </widget>
+ <widget class="QRadioButton" row="4" column="0">
+ <property name="name">
+ <cstring>useRegExp</cstring>
+ </property>
+ <property name="text">
+ <string>Use regu&amp;lar expression</string>
+ </property>
+ </widget>
+ <widget class="Line" row="2" column="0" rowspan="1" colspan="2">
+ <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>
+ </grid>
+ </widget>
+ </vbox>
+</widget>
+<customwidgets>
+</customwidgets>
+<connections>
+ <connection>
+ <sender>useRegExp</sender>
+ <signal>toggled(bool)</signal>
+ <receiver>regexpButton</receiver>
+ <slot>setEnabled(bool)</slot>
+ </connection>
+</connections>
+<includes>
+ <include location="global" impldecl="in implementation">kcombobox.h</include>
+</includes>
+<forwards>
+ <forward>class KComboBox;</forward>
+</forwards>
+<layoutdefaults spacing="6" margin="11"/>
+<includehints>
+ <includehint>klineedit.h</includehint>
+</includehints>
+</UI>
diff --git a/kbabel/catalogmanager/multiroughtransdlg.cpp b/kbabel/catalogmanager/multiroughtransdlg.cpp
new file mode 100644
index 00000000..874b9c3e
--- /dev/null
+++ b/kbabel/catalogmanager/multiroughtransdlg.cpp
@@ -0,0 +1,148 @@
+/* ****************************************************************************
+ This file is part of KBabel
+
+ Copyright (C) 1999-2001 by Matthias Kiefer
+ <matthias.kiefer@gmx.de>
+ 2002 by Stanislav Visnovsky <visnovsky@kde.org>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the 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, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+ In addition, as a special exception, the copyright holders give
+ permission to link the code of this program with any edition of
+ the Qt library by Trolltech AS, Norway (or with modified versions
+ of Qt that use the same license as Qt), and distribute linked
+ combinations including the two. You must obey the GNU General
+ Public License in all respects for all of the code used other than
+ Qt. If you modify this file, you may extend this exception to
+ your version of the file, but you are not obligated to do so. If
+ you do not wish to do so, delete this exception statement from
+ your version.
+
+**************************************************************************** */
+#include "catalog.h"
+#include "catmanlistitem.h"
+#include "multiroughtransdlg.h"
+
+#include <qlabel.h>
+#include <qlayout.h>
+
+#include <kdebug.h>
+#include <kglobal.h>
+#include <klocale.h>
+#include <kmessagebox.h>
+#include <kprogress.h>
+#include <kurl.h>
+
+using namespace KBabel;
+
+MultiRoughTransDlg::MultiRoughTransDlg(KBabelDictBox *dict, QPtrList<CatManListItem> files
+ , QWidget *parent,const char *name)
+ : RoughTransDlg(dict, new Catalog(), parent, name )
+ ,_fileList(files)
+{
+ QWidget* bars = static_cast<QWidget*>(progressbar->parent());
+ QLabel* label = new QLabel( i18n("Files:"), bars );
+ filesProgressbar = new KProgress(bars,"files progressbar");
+ filesProgressbar->setTextEnabled(true);
+ filesProgressbar->setFormat("%v/%m (%p%)");
+ filesProgressbar->setTotalSteps(files.count());
+ QHBoxLayout* mylayout= new QHBoxLayout(bars->layout());
+ mylayout->add(label);
+ mylayout->add(filesProgressbar);
+
+ msgButtonClicked(0);
+}
+
+void MultiRoughTransDlg::msgButtonClicked(int id)
+{
+ RoughTransDlg::msgButtonClicked(id);
+
+ enableButton(User1,true);
+}
+
+void MultiRoughTransDlg::translate()
+{
+ for ( CatManListItem* it = _fileList.first(); it ; it = _fileList.next() )
+ {
+ if( it->hasPo() )
+ {
+ KURL url( it->poFile() );
+ if( catalog->openURL( url ) != OK )
+ {
+ KMessageBox::error(this, i18n("Error while trying to read file:\n %1\n"
+ "Maybe it is not a valid PO file.").arg(url.prettyURL()));
+ filesProgressbar->advance(1);
+ continue;
+ }
+ } else
+ if( it->hasPot() )
+ {
+ KURL url( it->poFile() );
+ KURL poturl( it->potFile() );
+ if( catalog->openURL( poturl, url ) != OK )
+ {
+ KMessageBox::error(this, i18n("Error while trying to read file:\n %1\n"
+ "Maybe it is not a valid PO file.").arg(poturl.prettyURL()));
+ filesProgressbar->advance(1);
+ continue;
+ }
+ }
+
+ RoughTransDlg::translate();
+
+ if( stop || cancel ) break;
+
+ if( catalog->isModified() ) catalog->saveFile();
+
+ it->forceUpdate();
+ filesProgressbar->advance(1);
+ }
+
+ filesProgressbar->setValue(_fileList.count());
+
+ showAllStatistics();
+}
+
+void MultiRoughTransDlg::showAllStatistics()
+{
+ int tt, ptc, etc;
+
+ statistics( tt, ptc, etc);
+
+ // sanity check
+ if( tt == 0 ) tt = 1;
+
+ int nothing=tt-ptc-etc;
+ KLocale *locale = KGlobal::locale();
+ QString statMsg = i18n("Result of the translation:\n"
+ "Edited entries: %1\n"
+ "Exact translations: %2 (%3%)\n"
+ "Approximate translations: %4 (%5%)\n"
+ "Nothing found: %6 (%7%)")
+ .arg( locale->formatNumber(tt,0) )
+ .arg( locale->formatNumber(etc,0) )
+ .arg( locale->formatNumber( ((double)(10000*etc/tt))/100) )
+ .arg( locale->formatNumber(ptc,0) )
+ .arg( locale->formatNumber(((double)(10000*ptc/tt))/100) )
+ .arg( locale->formatNumber(nothing,0) )
+ .arg( locale->formatNumber(((double)(10000*nothing/tt)/100) ) );
+
+ KMessageBox::information(this, statMsg
+ , i18n("Rough Translation Statistics"));
+
+ accept();
+}
+
+#include "multiroughtransdlg.moc"
diff --git a/kbabel/catalogmanager/multiroughtransdlg.h b/kbabel/catalogmanager/multiroughtransdlg.h
new file mode 100644
index 00000000..8bda58e2
--- /dev/null
+++ b/kbabel/catalogmanager/multiroughtransdlg.h
@@ -0,0 +1,63 @@
+/* ****************************************************************************
+ This file is part of KBabel
+
+ Copyright (C) 2002 by Stanislav Visnovsky
+ <visnovsky@kde.org>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the 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, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+ In addition, as a special exception, the copyright holders give
+ permission to link the code of this program with any edition of
+ the Qt library by Trolltech AS, Norway (or with modified versions
+ of Qt that use the same license as Qt), and distribute linked
+ combinations including the two. You must obey the GNU General
+ Public License in all respects for all of the code used other than
+ Qt. If you modify this file, you may extend this exception to
+ your version of the file, but you are not obligated to do so. If
+ you do not wish to do so, delete this exception statement from
+ your version.
+
+**************************************************************************** */
+#ifndef MULTIROUGHTRANSDLG_H
+#define MULTIROUGHTRANSDLG_H
+
+#include <roughtransdlg.h>
+
+class CatManListItem;
+
+class MultiRoughTransDlg : public RoughTransDlg
+{
+ Q_OBJECT
+
+public:
+ MultiRoughTransDlg(KBabelDictBox* dictBox, QPtrList<CatManListItem> list, QWidget *parent
+ , const char *name=0);
+
+protected slots:
+ virtual void translate();
+ // we show statistics at different point
+ virtual void showStatistics() {}
+ virtual void showAllStatistics();
+
+ // we need to enable Start button at different conditions
+ virtual void msgButtonClicked(int);
+
+private:
+
+ QPtrList<CatManListItem> _fileList;
+ KProgress *filesProgressbar;
+};
+
+#endif // ROUGHTRANSDLG_H
diff --git a/kbabel/catalogmanager/validateprogress.cpp b/kbabel/catalogmanager/validateprogress.cpp
new file mode 100644
index 00000000..9075f24e
--- /dev/null
+++ b/kbabel/catalogmanager/validateprogress.cpp
@@ -0,0 +1,313 @@
+/* ****************************************************************************
+ This file is part of KBabel
+
+ Copyright (C) 2002-2003 by Stanislav Visnovsky
+ <visnovsky@kde.org>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the 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, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+ In addition, as a special exception, the copyright holders give
+ permission to link the code of this program with any edition of
+ the Qt library by Trolltech AS, Norway (or with modified versions
+ of Qt that use the same license as Qt), and distribute linked
+ combinations including the two. You must obey the GNU General
+ Public License in all respects for all of the code used other than
+ Qt. If you modify this file, you may extend this exception to
+ your version of the file, but you are not obligated to do so. If
+ you do not wish to do so, delete this exception statement from
+ your version.
+
+**************************************************************************** */
+#include "validateprogress.h"
+#include "validateprogresswidget.h"
+#include "catmanlistitem.h"
+#include "catmanresource.h"
+
+#include <kdebug.h>
+#include <kdatatool.h>
+#include <klocale.h>
+#include <kmessagebox.h>
+#include <kpopupmenu.h>
+#include <kprogress.h>
+#include <ksqueezedtextlabel.h>
+
+#include <qlistbox.h>
+#include <qtimer.h>
+
+#define ID_ERROR_OPEN 1
+#define ID_ERROR_IGNORE 2
+
+// version identification for validation ignores
+#define IGNOREFILE_VERSION 0x00
+
+ValidateProgressDialog::ValidateProgressDialog(const QString& ignoreURL, QWidget *parent,const char *name)
+ : KDialogBase(parent,name,true,i18n("Caption of dialog","Validation")
+ , Close, Close)
+ , _ignoreURL(ignoreURL), _tool(0), _stopped(false)
+ , _ignoreFuzzy(false), _setAsFuzzy(false)
+
+{
+ _mainWidget = new ValidateProgressWidget(this);
+ setMainWidget(_mainWidget);
+ setInitialSize( QSize(400, 300) );
+
+ _errors.clear();
+ _ignores.clear();
+
+ readIgnores();
+
+ _errorMenu = new KPopupMenu(this);
+ _errorMenu->insertItem(i18n("&Open"),ID_ERROR_OPEN);
+ _errorMenu->insertItem(i18n("&Ignore"),ID_ERROR_IGNORE);
+
+ connect( this, SIGNAL(closeClicked()), this, SLOT(stop()));
+ connect( _mainWidget->_errorList, SIGNAL( doubleClicked(QListBoxItem *)),
+ this, SLOT( errorItemDoubleClicked(QListBoxItem *)));
+
+ connect( _mainWidget->_errorList, SIGNAL( contextMenuRequested(QListBoxItem *, const QPoint &)),
+ this, SLOT( showContextMenu(QListBoxItem *, const QPoint &)));
+}
+
+ValidateProgressDialog::~ValidateProgressDialog()
+{
+ writeIgnores();
+}
+
+void ValidateProgressDialog::validate( const KDataToolInfo &tool, const QPtrList<CatManListItem> files )
+{
+ if( files.isEmpty() ) return;
+
+ _errors.clear();
+
+ KDataTool* t = tool.createTool();
+
+ if( !t )
+ {
+ KMessageBox::error( this, i18n("Cannot instantiate a validation tool.\n"
+ "Please check your installation."), i18n("Validation Tool Error") );
+ return;
+ }
+
+ _tool = t;
+ _toolID = tool.service()->library();
+ _files = files;
+
+ _mainWidget->_errorList->clear();
+ _mainWidget->_currentTool->setText(*(tool.userCommands().at(0)));
+ _mainWidget->_overallProgress->setTotalSteps(files.count());
+ _mainWidget->_overallProgress->setValue(0);
+
+ _stopped = false;
+
+ QTimer::singleShot( 0, this, SLOT(validate_internal()) );
+
+ exec();
+
+ _stopped = true;
+}
+
+void ValidateProgressDialog::validate_internal()
+{
+ uint checked=0;
+ uint errors=0;
+ uint ignorederrors=0;
+
+ for( CatManListItem* it=_files.first() ; it && !_stopped ; it = _files.next() )
+ {
+ _mainWidget->_currentFile->setText( it->poFile() );
+
+ checked++;
+
+ _mainWidget->_currentFileProgress->setTotalSteps(100);
+ _mainWidget->_currentFileProgress->setValue(0);
+
+ it->checkErrors(_tool,_mainWidget, _ignoreFuzzy, _setAsFuzzy);
+
+ bool noHeader = true;
+
+ if( it->hasErrors() )
+ {
+ QValueList<IgnoreItem> err = it->errors();
+
+ for( QValueList<IgnoreItem>::Iterator errit = err.begin(); errit!=err.end() ; ++errit )
+ {
+ IgnoreItem item = (*errit);
+
+ QValueList<IgnoreItem>::Iterator ig;
+ for( ig = _ignores.begin() ; ig != _ignores.end() ; ++ig )
+ {
+ if( (*ig).validationTool == _toolID &&
+ (*ig).msgid == item.msgid &&
+ (*ig).msgstr == item.msgstr &&
+ (*ig).fileURL == item.fileURL ) break;
+ }
+
+ if( ig != _ignores.end() )
+ {
+ ++ignorederrors;
+ continue;
+ } ++errors;
+
+ if( noHeader )
+ {
+ _mainWidget->_errorList->insertItem( ICON_ERROR, it->package() );
+ _errors.insert( it->package(), err.first() );
+ noHeader = false;
+ }
+
+ QString errortext=QString::number(item.index+1)+": " + item.msgid.first().left(50);
+ errortext.replace("\n"," ");
+ if( item.msgid.first().length() > 50 ) errortext+="...";
+ _mainWidget->_errorList->insertItem( errortext);
+
+ _errors.insert( errortext, item );
+ }
+ }
+
+ _mainWidget->_currentFileProgress->setValue(100);
+
+ _mainWidget->_overallProgress->advance(1);
+ }
+
+ if( !_stopped )
+ {
+ KMessageBox::information(this, i18n("Validation done.\n"
+ "\n"
+ "Checked files: %1\n"
+ "Number of errors: %2\n"
+ "Number of ignored errors: %3").arg(checked).arg(errors).arg(ignorederrors),i18n("Validation Done"));
+ }
+
+ delete _tool;
+ _tool = 0;
+ _files.clear();
+}
+
+void ValidateProgressDialog::stop()
+{
+ _stopped = true;
+}
+
+void ValidateProgressDialog::errorItemDoubleClicked(QListBoxItem * item)
+{
+ QString it = item->text();
+
+ bool ok =false;
+ int offset = it.find(":");
+
+ int num;
+ if( offset < -1 ) num = 0;
+ else
+ {
+ num = it.left(offset).toInt(&ok);
+ if( !ok ) num = 0;
+ }
+
+ QListBoxItem* package=item;
+
+ while( package && !package->text().startsWith("/") ) package=package->prev();
+
+ if( !package )
+ {
+ kdWarning() << "Unable to find the package for the error" << endl;
+ return;
+ }
+
+ emit errorDoubleClicked(package->text(), num-1 );
+}
+
+void ValidateProgressDialog::showContextMenu(QListBoxItem * item, const QPoint & pos)
+{
+ // disable ignore for whole package
+ _errorMenu->setItemEnabled(ID_ERROR_IGNORE, item->pixmap()==0 );
+ int result = _errorMenu->exec(pos);
+ switch( result )
+ {
+ case ID_ERROR_OPEN:
+ errorItemDoubleClicked( item );
+ break;
+ case ID_ERROR_IGNORE:
+ IgnoreItem it = _errors.find(item->text()).data();
+
+ // if there is no pixmap, it's the whole file
+ if( !item->pixmap() )
+ {
+ it.validationTool = _toolID;
+ _ignores.append( it );
+ }
+ break;
+ }
+}
+
+void ValidateProgressDialog::readIgnores()
+{
+ IgnoreItem item;
+
+ QFile ignoreFile( _ignoreURL );
+ if( ignoreFile.open( IO_ReadOnly ) ) {
+ QDataStream s( &ignoreFile );
+ QString url;
+ int version;
+
+ s >> version;
+ if( version == IGNOREFILE_VERSION ) // Only read if correct versi
+ {
+ _ignores.clear();
+
+ while( !s.atEnd() ) {
+ s >> item;
+ _ignores.append(item);
+ }
+ }
+ ignoreFile.close();
+ }
+}
+
+void ValidateProgressDialog::writeIgnores()
+{
+ QFile ignoreFile( _ignoreURL );
+ if( ignoreFile.open( IO_WriteOnly ) ) {
+ QDataStream s( &ignoreFile );
+ QString url;
+ int version = IGNOREFILE_VERSION;
+
+ s << version;
+
+ for( QValueList<IgnoreItem>::Iterator it = _ignores.begin(); it!=_ignores.end(); ++it)
+ {
+ s << (*it);
+ }
+ ignoreFile.close();
+ }
+}
+
+QDataStream & operator<<( QDataStream & stream, const IgnoreItem & i )
+{
+ return stream << i.fileURL
+ << i.msgid
+ << i.msgstr
+ << i.index
+ << i.validationTool;
+}
+
+QDataStream & operator>>( QDataStream & stream, IgnoreItem & i ) {
+ return stream >> i.fileURL
+ >> i.msgid
+ >> i.msgstr
+ >> i.index
+ >> i.validationTool;
+}
+
+#include "validateprogress.moc"
diff --git a/kbabel/catalogmanager/validateprogress.h b/kbabel/catalogmanager/validateprogress.h
new file mode 100644
index 00000000..05133889
--- /dev/null
+++ b/kbabel/catalogmanager/validateprogress.h
@@ -0,0 +1,109 @@
+/* ****************************************************************************
+ This file is part of KBabel
+
+ Copyright (C) 2002-203 by Stanislav Visnovsky
+ <visnovsky@kde.org>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the 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, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+ In addition, as a special exception, the copyright holders give
+ permission to link the code of this program with any edition of
+ the Qt library by Trolltech AS, Norway (or with modified versions
+ of Qt that use the same license as Qt), and distribute linked
+ combinations including the two. You must obey the GNU General
+ Public License in all respects for all of the code used other than
+ Qt. If you modify this file, you may extend this exception to
+ your version of the file, but you are not obligated to do so. If
+ you do not wish to do so, delete this exception statement from
+ your version.
+
+**************************************************************************** */
+#ifndef VALIDATEDLG_H
+#define VALIDATEDLG_H
+
+#include <qmap.h>
+
+#include <kdialogbase.h>
+#include <kurl.h>
+
+class CatManListItem;
+class ValidateProgressWidget;
+class KDataToolInfo;
+class KDataTool;
+class KPopupMenu;
+
+struct IgnoreItem
+{
+ KURL fileURL;
+ QStringList msgid;
+ QStringList msgstr;
+ uint index;
+ QString validationTool;
+};
+
+QDataStream & operator<<( QDataStream & stream, const IgnoreItem &ident );
+QDataStream & operator>>( QDataStream & stream, IgnoreItem & ident);
+
+class ValidateProgressDialog : public KDialogBase
+{
+ Q_OBJECT
+
+public:
+ ValidateProgressDialog(const QString& ignoreURL, QWidget* parent, const char *name=0);
+ virtual ~ValidateProgressDialog();
+
+ void setIgnoreFuzzy(bool enable) { _ignoreFuzzy = enable; }
+ void setMarkAsFuzzy(bool enable) { _setAsFuzzy = enable; }
+
+public slots:
+ void validate(const KDataToolInfo &tool, const QPtrList<CatManListItem> files);
+
+signals:
+ void errorDoubleClicked(const QString file, const int messageNumber);
+
+private slots:
+ /** implementation of the validation itself */
+ void validate_internal();
+
+ /** call this to stop current validation*/
+ void stop();
+
+ /** If user doubleclicked an item, this slot will be invoked.
+ * It emits errorDoubleClicked signal for corresponding error*/
+ void errorItemDoubleClicked(QListBoxItem * item);
+
+ /** show our context menu */
+ void showContextMenu(QListBoxItem * item, const QPoint & pos);
+
+private:
+ void readIgnores();
+ void writeIgnores();
+
+ ValidateProgressWidget *_mainWidget;
+ QString _ignoreURL;
+ KDataTool* _tool;
+ QString _toolID;
+ QPtrList<CatManListItem> _files;
+ bool _stopped;
+ KPopupMenu* _errorMenu;
+
+ bool _ignoreFuzzy;
+ bool _setAsFuzzy;
+
+ QValueList<IgnoreItem> _ignores;
+ QMap<QString,IgnoreItem> _errors;
+};
+
+#endif // VALIDATEDLG_H
diff --git a/kbabel/catalogmanager/validateprogresswidget.ui b/kbabel/catalogmanager/validateprogresswidget.ui
new file mode 100644
index 00000000..a181806b
--- /dev/null
+++ b/kbabel/catalogmanager/validateprogresswidget.ui
@@ -0,0 +1,129 @@
+<!DOCTYPE UI><UI version="3.1" stdsetdef="1">
+<class>ValidateProgressWidget</class>
+<widget class="QWidget">
+ <property name="name">
+ <cstring>ValidateProgressWidget</cstring>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>448</width>
+ <height>295</height>
+ </rect>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>layout2</cstring>
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLabel" row="2" column="0">
+ <property name="name">
+ <cstring>_currentAction</cstring>
+ </property>
+ <property name="minimumSize">
+ <size>
+ <width>92</width>
+ <height>0</height>
+ </size>
+ </property>
+ <property name="text">
+ <string>Current:</string>
+ </property>
+ </widget>
+ <widget class="KProgress" row="3" column="1" rowspan="1" colspan="2">
+ <property name="name">
+ <cstring>_overallProgress</cstring>
+ </property>
+ </widget>
+ <widget class="KSqueezedTextLabel" row="0" column="2">
+ <property name="name">
+ <cstring>_currentTool</cstring>
+ </property>
+ <property name="text">
+ <string></string>
+ </property>
+ </widget>
+ <widget class="QLabel" row="3" column="0">
+ <property name="name">
+ <cstring>textLabel1_2</cstring>
+ </property>
+ <property name="text">
+ <string>Overall:</string>
+ </property>
+ </widget>
+ <widget class="KProgress" row="2" column="1" rowspan="1" colspan="2">
+ <property name="name">
+ <cstring>_currentFileProgress</cstring>
+ </property>
+ </widget>
+ <widget class="KSqueezedTextLabel" row="1" column="2">
+ <property name="name">
+ <cstring>_currentFile</cstring>
+ </property>
+ <property name="text">
+ <string></string>
+ </property>
+ </widget>
+ <widget class="QLabel" row="1" column="0" rowspan="1" colspan="2">
+ <property name="name">
+ <cstring>_currentLabel</cstring>
+ </property>
+ <property name="text">
+ <string>Current file:</string>
+ </property>
+ </widget>
+ <widget class="QLabel" row="0" column="0">
+ <property name="name">
+ <cstring>textLabel3_2</cstring>
+ </property>
+ <property name="text">
+ <string>Validation:</string>
+ </property>
+ </widget>
+ </grid>
+ </widget>
+ <widget class="QListBox">
+ <item>
+ <property name="text">
+ <string>New Item</string>
+ </property>
+ </item>
+ <property name="name">
+ <cstring>_errorList</cstring>
+ </property>
+ </widget>
+ </vbox>
+</widget>
+<connections>
+ <connection>
+ <sender>ValidateProgressWidget</sender>
+ <signal>setValidationProgressBar(int)</signal>
+ <receiver>_currentFileProgress</receiver>
+ <slot>setValue(int)</slot>
+ </connection>
+</connections>
+<includes>
+ <include location="local" impldecl="in implementation">validateprogresswidget.ui.h</include>
+</includes>
+<signals>
+ <signal>setValidationProgressBar(int)</signal>
+</signals>
+<slots>
+ <slot>setupFileProgressBar( QString text, int maxvalue )</slot>
+</slots>
+<layoutdefaults spacing="6" margin="11"/>
+<includehints>
+ <includehint>kprogress.h</includehint>
+ <includehint>ksqueezedtextlabel.h</includehint>
+ <includehint>kprogress.h</includehint>
+ <includehint>ksqueezedtextlabel.h</includehint>
+</includehints>
+</UI>
diff --git a/kbabel/catalogmanager/validateprogresswidget.ui.h b/kbabel/catalogmanager/validateprogresswidget.ui.h
new file mode 100644
index 00000000..88f36d60
--- /dev/null
+++ b/kbabel/catalogmanager/validateprogresswidget.ui.h
@@ -0,0 +1,48 @@
+/* ****************************************************************************
+ This file is part of KBabel
+
+ Copyright (C) 2004 by Stanislav Visnovsky
+ <visnovsky@kde.org>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the 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, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+ In addition, as a special exception, the copyright holders give
+ permission to link the code of this program with any edition of
+ the Qt library by Trolltech AS, Norway (or with modified versions
+ of Qt that use the same license as Qt), and distribute linked
+ combinations including the two. You must obey the GNU General
+ Public License in all respects for all of the code used other than
+ Qt. If you modify this file, you may extend this exception to
+ your version of the file, but you are not obligated to do so. If
+ you do not wish to do so, delete this exception statement from
+ your version.
+
+** 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.
+*****************************************************************************/
+
+void ValidateProgressWidget::setupFileProgressBar( QString text, int maxvalue )
+{
+ _currentFileProgress->setTotalSteps(maxvalue);
+
+ QString t = text[0].upper()+text.mid(1)+":";
+
+ _currentAction->setText(t);
+ _currentAction->repaint();
+}
diff --git a/kbabel/catalogmanager/validationoptions.ui b/kbabel/catalogmanager/validationoptions.ui
new file mode 100644
index 00000000..61079ff3
--- /dev/null
+++ b/kbabel/catalogmanager/validationoptions.ui
@@ -0,0 +1,60 @@
+<!DOCTYPE UI><UI version="3.1" stdsetdef="1">
+<class>ValidationOptions</class>
+<widget class="QWidget">
+ <property name="name">
+ <cstring>ValidationOptions</cstring>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>174</width>
+ <height>70</height>
+ </rect>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>layout1</cstring>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QCheckBox">
+ <property name="name">
+ <cstring>markAsFuzzy</cstring>
+ </property>
+ <property name="text">
+ <string>Mark invalid as &amp;fuzzy</string>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>&lt;qt&gt;&lt;p&gt;&lt;b&gt;Mark invalid as fuzzy&lt;/b&gt;&lt;p&gt;
+&lt;p&gt;If you select this option, all items,
+which identifies the tool as invalid, will be
+marked as fuzzy and the resulting file
+will be saved.&lt;/p&gt;&lt;/qt&gt;</string>
+ </property>
+ </widget>
+ <widget class="QCheckBox">
+ <property name="name">
+ <cstring>ignoreFuzzy</cstring>
+ </property>
+ <property name="text">
+ <string>&amp;Do not validate fuzzy</string>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>&lt;qt&gt;&lt;p&gt;&lt;b&gt;Do not validate fuzzy&lt;/b&gt;&lt;p&gt;
+&lt;p&gt;If you select this option, all items
+marked as fuzzy will not be validated at all.&lt;/p&gt;&lt;/qt&gt;</string>
+ </property>
+ </widget>
+ </vbox>
+ </widget>
+ </vbox>
+</widget>
+<layoutdefaults spacing="6" margin="11"/>
+</UI>
diff --git a/kbabel/common/Makefile.am b/kbabel/common/Makefile.am
new file mode 100644
index 00000000..462cc425
--- /dev/null
+++ b/kbabel/common/Makefile.am
@@ -0,0 +1,67 @@
+## Makefile.am for libkbabelcommon
+
+# this has all of the subdirectories that make will recurse into. if
+# there are none, comment this out
+SUBDIRS = libgettext
+
+pkgincludedir = $(includedir)/kbabel
+
+# this is the program that gets installed. it's name is used for all
+# of the other Makefile.am variables
+lib_LTLIBRARIES = libkbabelcommon.la
+
+# set the include path for X, qt and KDE
+INCLUDES = $(all_includes)
+
+# which sources should be compiled
+libkbabelcommon_la_SOURCES = catalog.cpp catalogitem.cpp editcmd.cpp\
+ msgfmt.cpp catalogsettings.cpp tagextractor.cpp diff.cpp\
+ argextractor.cpp kbmailer.cpp poinfo.cpp\
+ regexpextractor.cpp importplugin.cpp \
+ exportplugin.cpp \
+ kbproject.cpp \
+ kbprojectmanager.cpp \
+ kbprojectsettings.kcfgc \
+ projectsettings.cpp \
+ stringdistance.cpp
+
+libkbabelcommon_la_LIBADD = $(LIB_KIO) libgettext/libgettext.la
+libkbabelcommon_la_LDFLAGS = $(all_libraries) -version-info 5:0:2 -no-undefined
+
+# these are the headers for your project
+noinst_HEADERS = resources.h version.h catalogitem_private.h catalog_private.h kbmailer.h stringdistance.h
+pkginclude_HEADERS = catalog.h catalogitem.h editcmd.h msgfmt.h catalogsettings.h findoptions.h catalogview.h tagextractor.h poinfo.h\
+ regexpextractor.h itempart.h catalogfileplugin.h kbabeldatatool.h kbproject.h kbprojectmanager.h \
+ projectsettings.h
+
+
+# let automoc handle all of the meta source files (moc)
+METASOURCES = AUTO
+
+# KConfigXT project settings
+kde_kcfg_DATA=kbprojectsettings.kcfg
+
+# service type for the filters
+kde_servicetypes_DATA = kbabelfilter.desktop
+EXTRA_DIST = $(kde_servicetypes_DATA)
+
+KDE_OPTIONS = nofinal
+
+version.h: $(srcdir)/../VERSION
+ echo "/* Generated file - DO NOT EDIT */" > version.h
+ echo "#undef VERSION" >> version.h
+ echo "#define VERSION \"`cat $(srcdir)/../VERSION`\"" >> version.h
+
+catalog.lo: version.h
+
+# updating of project settings for default project
+update_DATA = kbabel-projectrename.upd
+updatedir = $(kde_datadir)/kconf_update
+
+api:
+ mkdir -p API && kdoc -d API -u $$PWD/API -p -lkdecore -lqt-mt -ldcop $(pkginclude_HEADERS)
+
+distclean-local:
+ rm -r -f API
+ rm -f version.h
+
diff --git a/kbabel/common/argextractor.cpp b/kbabel/common/argextractor.cpp
new file mode 100644
index 00000000..4146a5a7
--- /dev/null
+++ b/kbabel/common/argextractor.cpp
@@ -0,0 +1,70 @@
+/* ****************************************************************************
+ This file is part of KBabel
+
+ Copyright (C) 2001 by Matthias Kiefer <matthias.kiefer@gmx.de>
+ 2002 by Stanislav Visnovsky <visnovsky@nenya.ms.mff.cuni.cz>
+
+ based on code of Andrea Rizzi <rizzi@kde.org>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the 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, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+ In addition, as a special exception, the copyright holders give
+ permission to link the code of this program with any edition of
+ the Qt library by Trolltech AS, Norway (or with modified versions
+ of Qt that use the same license as Qt), and distribute linked
+ combinations including the two. You must obey the GNU General
+ Public License in all respects for all of the code used other than
+ Qt. If you modify this file, you may extend this exception to
+ your version of the file, but you are not obligated to do so. If
+ you do not wish to do so, delete this exception statement from
+ your version.
+
+**************************************************************************** */
+#include "catalogsettings.h"
+#include "argextractor.h"
+
+#include <kdebug.h>
+#include <kstaticdeleter.h>
+#include <qregexp.h>
+
+using namespace KBabel;
+
+ArgExtractor::ArgExtractor(QString string) : RegExpExtractor( string )
+{
+}
+
+QStringList *ArgExtractor::_argList=0;
+KStaticDeleter< QStringList > sdAL;
+
+QStringList *ArgExtractor::regExpList()
+{
+ if(!_argList)
+ {
+ sdAL.setObject( _argList, new QStringList );
+ //Build the default arg list
+ _argList->append("%[ndioxXucsfeEgGp]");
+ _argList->append("%([0-9]+(\\$))?[-+'#0]?[0-9]*(.[0-9]+)?[hlL]?[dioxXucsfeEgGp]");
+ _argList->append("%[0-9]+");
+ }
+
+ return _argList;
+}
+
+void ArgExtractor::setArgExpressions( QStringList* list )
+{
+ sdAL.setObject( _argList, new QStringList );
+ for( QStringList::Iterator it = list->begin() ; it != list->end() ; ++it )
+ _argList->append(*it);
+}
diff --git a/kbabel/common/argextractor.h b/kbabel/common/argextractor.h
new file mode 100644
index 00000000..31b28c8a
--- /dev/null
+++ b/kbabel/common/argextractor.h
@@ -0,0 +1,83 @@
+/* ****************************************************************************
+ This file is part of KBabel
+
+ Copyright (C) 2002 by Stanislav Visnovsky
+
+ based on code of Matthias Kiefer <matthias.kiefer@gmx.de> and
+ Andrea Rizzi <rizzi@kde.org>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the 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, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+ In addition, as a special exception, the copyright holders give
+ permission to link the code of this program with any edition of
+ the Qt library by Trolltech AS, Norway (or with modified versions
+ of Qt that use the same license as Qt), and distribute linked
+ combinations including the two. You must obey the GNU General
+ Public License in all respects for all of the code used other than
+ Qt. If you modify this file, you may extend this exception to
+ your version of the file, but you are not obligated to do so. If
+ you do not wish to do so, delete this exception statement from
+ your version.
+
+**************************************************************************** */
+#ifndef _ARG_EXTRACTOR_H_
+#define _ARG_EXTRACTOR_H_
+
+#include <qptrlist.h>
+#include <qstring.h>
+#include <qstringlist.h>
+#include <qvaluelist.h>
+#include <qregexp.h>
+
+#include "regexpextractor.h"
+
+namespace KBabel
+{
+
+/**
+ * class to extract arguments from a string
+ * @author Stanislav Visnovsky <visnovsky@kde.org>
+ * @author Andrea Rizzi <rizzi@kde.org>
+ */
+class ArgExtractor : public RegExpExtractor
+{
+
+public:
+ /**
+ * Create an argument extractor for "string"
+ */
+ ArgExtractor(QString string=QString::null);
+
+ /**
+ * Set a new list of tag regular expressions. It also
+ * deletes the old tags.
+ * @param list a list of regular expressions
+ */
+ static void setArgExpressions(QStringList* list);
+
+protected:
+ /**
+ * @return the static list of args
+ */
+ virtual QStringList *regExpList();
+
+private:
+ static QStringList *_argList;
+};
+
+}
+
+
+#endif
diff --git a/kbabel/common/catalog.cpp b/kbabel/common/catalog.cpp
new file mode 100644
index 00000000..ffd939b7
--- /dev/null
+++ b/kbabel/common/catalog.cpp
@@ -0,0 +1,3509 @@
+/* ****************************************************************************
+ This file is part of KBabel
+
+ Copyright (C) 1999-2000 by Matthias Kiefer <matthias.kiefer@gmx.de>
+ 2001-2005 by Stanislav Visnovsky <visnovsky@kde.org>
+ Copyright (C) 2006 by Nicolas GOUTTE <goutte@kde.org>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the 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, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+ In addition, as a special exception, the copyright holders give
+ permission to link the code of this program with any edition of
+ the Qt library by Trolltech AS, Norway (or with modified versions
+ of Qt that use the same license as Qt), and distribute linked
+ combinations including the two. You must obey the GNU General
+ Public License in all respects for all of the code used other than
+ Qt. If you modify this file, you may extend this exception to
+ your version of the file, but you are not obligated to do so. If
+ you do not wish to do so, delete this exception statement from
+ your version.
+
+**************************************************************************** */
+#include <qtextstream.h>
+#include <qfile.h>
+#include <qdir.h>
+#include <qfileinfo.h>
+#include <qregexp.h>
+#include <qstring.h>
+#include <qtextcodec.h>
+#include <qdatetime.h>
+
+#include <kconfig.h>
+#include <kdatatool.h>
+#include <kglobal.h>
+#include <klibloader.h>
+#include <klocale.h>
+#include <kmessagebox.h>
+#include <kmimetype.h>
+#include <kapplication.h>
+#include <kio/netaccess.h>
+#include <krfcdate.h>
+#include <ktrader.h>
+#include <kurl.h>
+
+#include "kbprojectmanager.h"
+#include "catalog.h"
+#include "catalog_private.h"
+#include "catalogitem.h"
+#include "diff.h"
+#include "findoptions.h"
+#include "catalogview.h"
+#include "editcmd.h"
+#include "kbprojectsettings.h"
+
+#include "resources.h"
+#include "version.h"
+#include "stringdistance.h"
+
+#include <kmessagebox.h>
+using namespace KBabel;
+
+Catalog::Catalog(QObject* parent, const char* name, QString projectFile)
+ : QObject(parent,name)
+{
+ if ( projectFile.isEmpty() )
+ projectFile = KBabel::ProjectManager::defaultProjectName();
+ d = new CatalogPrivate(ProjectManager::open(projectFile));
+ readPreferences();
+}
+
+Catalog::Catalog(const Catalog& c): QObject(c.parent(),c.name()
+)
+{
+ kdFatal() << "Copy constructor of Catalog, please report how to reproduce to the authors" << endl;
+}
+
+Catalog::~Catalog()
+{
+ delete d;
+}
+
+QString Catalog::msgctxt(uint index) const
+{
+ if ( d->_entries.isEmpty() )
+ return QString::null;
+ uint max=d->_entries.count()-1;
+ if(index > max)
+ index=max;
+ return d->_entries[index].msgctxt();
+}
+
+QStringList Catalog::msgid(uint index, const bool noNewlines) const
+{
+ if ( d->_entries.isEmpty() )
+ return QString::null;
+ uint max=d->_entries.count()-1;
+ if(index > max)
+ index=max;
+
+ return d->_entries[index].msgid(noNewlines);
+}
+
+QStringList Catalog::msgstr(uint index, const bool noNewlines) const
+{
+ if ( d->_entries.isEmpty() )
+ return QString::null;
+
+ uint max=d->_entries.count()-1;
+ if(index > max)
+ index=max;
+
+ return d->_entries[index].msgstr(noNewlines);
+}
+
+QString Catalog::comment(uint index) const
+{
+ if ( d->_entries.isEmpty() )
+ return QString::null;
+ uint max=d->_entries.count()-1;
+ if(index > max)
+ index=max;
+ return d->_entries[index].comment();
+}
+
+QString Catalog::context(uint index) const
+{
+ QString c = comment(index);
+
+ QStringList lines = QStringList::split("\n",c);
+
+ QString result;
+ for( QStringList::Iterator it=lines.begin(); it!=lines.end(); ++it)
+ {
+ if( (*it).startsWith( "#:") )
+ {
+ result+=(*it)+"\n";
+ }
+ }
+ return result.stripWhiteSpace();
+}
+
+CatalogItem Catalog::header() const
+{
+ return d->_header;
+}
+
+QString Catalog::lastTranslator() const
+{
+ return headerInfo( d->_header ).lastTranslator;
+}
+
+int Catalog::indexForMsgid(const QString& id) const
+{
+ int i=0;
+ QValueVector<CatalogItem>::ConstIterator it = d->_entries.begin();
+
+ while(it != d->_entries.end() && !((*it).msgid(true).contains(id)))
+ {
+ ++it;
+ i++;
+ }
+
+ if(it == d->_entries.end())
+ i=-1;
+
+ return i;
+}
+
+QStringList Catalog::tagList(uint index)
+{
+ if ( d->_entries.isEmpty() )
+ return QStringList();
+
+ uint max=d->_entries.count()-1;
+ if(index > max)
+ index=max;
+
+ return d->_entries[index].tagList(*(d->_tagExtractor));
+}
+
+
+QStringList Catalog::argList(uint index)
+{
+ if ( d->_entries.isEmpty() )
+ return QStringList();
+
+ uint max=d->_entries.count()-1;
+ if(index > max)
+ index=max;
+
+ return d->_entries[index].argList(*(d->_argExtractor));
+}
+
+
+/*
+bool Catalog::setMsgstr(uint index,QString msgstr)
+{
+ kdWarning() << "Catalog::setMsgstr()" << endl;
+
+ bool untranslatedChanged=false;
+
+ if(_entries[index].isUntranslated() && !msgstr.isEmpty())
+ {
+ _untransIndex.remove(index);
+ untranslatedChanged=true;
+ }
+ else if(msgstr.isEmpty())
+ {
+ QValueList<uint>::Iterator it;
+
+ // insert index in the right place in the list
+ it = _untransIndex.begin();
+ while(it != _untransIndex.end() && index > (*it))
+ {
+ ++it;
+ }
+ _untransIndex.insert(it,index);
+
+ untranslatedChanged=true;
+ }
+
+ _entries[index].setMsgstr(msgstr);
+
+ setModified(true);
+
+ if(untranslatedChanged)
+ emit signalNumberOfUntranslatedChanged(numberOfUntranslated());
+
+ return untranslatedChanged;
+}
+*/
+
+/*
+bool Catalog::setComment(uint index,QString comment)
+{
+ kdWarning() << "Catalog::setComment()" << endl;
+ bool fuzziesChanged=false;
+
+
+ bool wasFuzzy=_entries[index].isFuzzy();
+
+ _entries[index].setComment(comment);
+
+ bool isFuzzy=_entries[index].isFuzzy();
+
+ if(wasFuzzy && !isFuzzy)
+ {
+ _fuzzyIndex.remove(index);
+ fuzziesChanged=true;
+ }
+ else if(isFuzzy)
+ {
+ QValueList<uint>::Iterator it;
+
+ // insert index in the right place in the list
+ it = _fuzzyIndex.begin();
+ while(it != _fuzzyIndex.end() && index > (*it))
+ {
+ ++it;
+ }
+ _fuzzyIndex.insert(it,index);
+
+ fuzziesChanged=true;
+ }
+
+ setModified(true);
+
+ if(fuzziesChanged)
+ emit signalNumberOfFuzziesChanged(numberOfFuzzies());
+
+
+ return fuzziesChanged;
+}
+*/
+
+bool Catalog::setHeader(CatalogItem newHeader)
+{
+ if(newHeader.isValid())
+ {
+ // normalize the values - ensure every key:value pair is only on a single line
+ QString values = newHeader.msgstr().first();
+ values.replace ("\n", "");
+ values.replace ("\\n", "\\n\n");
+
+ kdDebug () << "Normalized header: " << values << endl;
+
+ d->_header=newHeader;
+ d->_header.setMsgstr (values);
+
+ setModified(true);
+
+ emit signalHeaderChanged();
+
+ return true;
+ }
+
+ return false;
+}
+
+KURL Catalog::currentURL() const
+{
+ return d->_url;
+}
+
+void Catalog::setCurrentURL(const KURL& url)
+{
+ d->_url=url;
+}
+
+
+CatalogItem Catalog::updatedHeader(CatalogItem oldHeader, bool usePrefs) const
+{
+ QStringList headerList=oldHeader.msgstrAsList();
+ QStringList commentList=QStringList::split('\n',oldHeader.comment());
+
+ QStringList::Iterator it,ait;
+ QString temp;
+ bool found;
+
+ const IdentitySettings identityOptions = identitySettings();
+ const SaveSettings saveOptions = saveSettings();
+
+ if(!usePrefs || saveOptions.updateLastTranslator)
+ {
+ found=false;
+
+ temp="Last-Translator: "+identityOptions.authorName;
+ if(!identityOptions.authorEmail.isEmpty())
+ {
+ temp+=(" <"+identityOptions.authorEmail+">");
+ }
+ temp+="\\n";
+ for( it = headerList.begin(); it != headerList.end(); ++it )
+ {
+ if((*it).contains(QRegExp("^ *Last-Translator:.*")))
+ {
+ (*it) = temp;
+ found=true;
+ break;
+ }
+ }
+ if(!found)
+ {
+ headerList.append(temp);
+ }
+ }
+ if(!usePrefs || saveOptions.updateRevisionDate)
+ {
+ found=false;
+
+ temp="PO-Revision-Date: "+dateTime()+"\\n";
+
+ for( it = headerList.begin(); it != headerList.end(); ++it )
+ {
+ if((*it).contains(QRegExp("^ *PO-Revision-Date:.*")))
+ {
+ (*it) = temp;
+ found=true;
+ break;
+ }
+ }
+ if(!found)
+ {
+ headerList.append(temp);
+ }
+ }
+ if(!usePrefs || saveOptions.updateProject)
+ {
+ found=false;
+
+ temp="Project-Id-Version: "+saveOptions.projectString+"\\n";
+ temp.replace( "@PACKAGE@", packageName());
+
+ for( it = headerList.begin(); it != headerList.end(); ++it )
+ {
+ if((*it).contains(QRegExp("^ *Project-Id-Version:.*")))
+ {
+ (*it) = temp;
+ found=true;
+ break;
+ }
+ }
+ if(!found)
+ {
+ headerList.append(temp);
+ }
+ }
+ if(!usePrefs || saveOptions.updateLanguageTeam)
+ {
+ found=false;
+
+ temp="Language-Team: "+identityOptions.languageName;
+ if(!identityOptions.mailingList.isEmpty())
+ {
+ temp+=(" <"+identityOptions.mailingList+">");
+ }
+ temp+="\\n";
+ for( it = headerList.begin(); it != headerList.end(); ++it )
+ {
+ if((*it).contains(QRegExp("^ *Language-Team:.*")))
+ {
+ (*it) = temp;
+ found=true;
+ break;
+ }
+ }
+ if(!found)
+ {
+ headerList.append(temp);
+ }
+ }
+ if(!usePrefs || saveOptions.updateCharset)
+ {
+
+ found=false;
+
+ QString encodingStr;
+ if(saveOptions.useOldEncoding && d->fileCodec)
+ {
+ encodingStr = charsetString(d->fileCodec);
+ }
+ else
+ {
+ encodingStr=charsetString(saveOptions.encoding);
+ }
+
+ temp = "Content-Type: text/plain; charset=" + encodingStr + "\\n";
+
+ it = headerList.begin();
+ while( it != headerList.end() )
+ {
+ if( (*it).find( QRegExp( "^ *Content-Type:.*" ) ) != -1 )
+ {
+ if ( found )
+ {
+ // We had already a Content-Type, so we do not need a duplicate
+ it = headerList.remove( it );
+ }
+ else
+ {
+ found=true;
+ QRegExp regexp( "^ *Content-Type:(.*/.*);?\\s*charset=.*$" );
+ QString mimeType;
+ if ( regexp.search( *it ) )
+ {
+ mimeType = regexp.cap( 1 ).stripWhiteSpace();
+ }
+ if ( mimeType.isEmpty() )
+ {
+ mimeType = "text/plain";
+ }
+ temp = "Content-Type: ";
+ temp += mimeType;
+ temp += "; charset=";
+ temp += encodingStr;
+ temp += "\\n";
+ (*it) = temp;
+ }
+ }
+ ++it;
+ }
+ if(!found)
+ {
+ headerList.append(temp);
+ }
+ }
+ if(!usePrefs || saveOptions.updateEncoding)
+ {
+ found=false;
+
+ temp="Content-Transfer-Encoding: 8bit\\n";
+
+ for( it = headerList.begin(); it != headerList.end(); ++it )
+ {
+ if((*it).contains(QRegExp("^ *Content-Transfer-Encoding:.*")))
+ {
+ (*it) = temp;
+ found=true;
+ break;
+ }
+ }
+ if(!found)
+ {
+ headerList.append(temp);
+ }
+ }
+
+ temp="X-Generator: KBabel %1\\n";
+ temp=temp.arg(VERSION);
+ found=false;
+
+ for( it = headerList.begin(); it != headerList.end(); ++it )
+ {
+ if((*it).contains(QRegExp("^ *X-Generator:.*")))
+ {
+ (*it) = temp;
+ found=true;
+ break;
+ }
+ }
+ if(!found)
+ {
+ headerList.append(temp);
+ }
+
+ // ensure MIME-Version header
+ temp="MIME-Version: 1.0\\n";
+ found=false;
+ for( it = headerList.begin(); it != headerList.end(); ++it )
+ {
+ if((*it).contains(QRegExp("^ *MIME-Version:")))
+ {
+ (*it) = temp;
+ found=true;
+ break;
+ }
+ }
+ if( !found )
+ {
+ headerList.append(temp);
+ }
+
+
+ temp="Plural-Forms: %1\\n";
+ temp=temp.arg(identityOptions.gnuPluralFormHeader);
+ found=false;
+
+ // update plural form header
+ if( !identityOptions.gnuPluralFormHeader.isEmpty() )
+ {
+ for( it = headerList.begin(); it != headerList.end(); ++it )
+ {
+ if((*it).contains(QRegExp("^ *Plural-Forms:")))
+ {
+ (*it) = temp;
+ found=true;
+ break;
+ }
+ }
+ if( !found )
+ {
+ headerList.append(temp);
+ }
+ }
+
+ oldHeader.setMsgstr( headerList.join( "\n" ) );
+
+ //comment = description, copyrights
+ if(!usePrefs || (saveOptions.FSFCopyright != ProjectSettingsBase::NoChange))
+ {
+ found=false;
+
+ for( it = commentList.begin(); it != commentList.end(); ++it )
+ {
+ // U+00A9 is the Copyright sign
+ if ( (*it).find( QRegExp("^# *Copyright (\\(C\\)|\\x00a9).*Free Software Foundation, Inc") ) != -1 )
+ {
+ found=true;
+ break;
+ }
+ }
+ if(found)
+ {
+ if ( (*it).find( QRegExp("^# *Copyright (\\(C\\)|\\x00a9) YEAR Free Software Foundation, Inc\\.") ) != -1 )
+ {
+ //template string
+ if( saveOptions.FSFCopyright == ProjectSettingsBase::Remove)
+ (*it).remove(" YEAR Free Software Foundation, Inc");
+ else
+ (*it).replace("YEAR", QDate::currentDate().toString("yyyy"));
+ } else
+ if( saveOptions.FSFCopyright == ProjectSettingsBase::Update )
+ {
+ //update years
+ QString cy = QDate::currentDate().toString("yyyy");
+ if( !(*it).contains( QRegExp(cy)) ) // is the year already included?
+ {
+ int index = (*it).findRev( QRegExp("[\\d]+[\\d\\-, ]*") );
+ if( index == -1 )
+ {
+ KMessageBox::information(0,i18n("Free Software Foundation Copyright does not contain any year. "
+ "It will not be updated."));
+ } else {
+ (*it).insert(index+1, QString(", ")+cy);
+ }
+ }
+ }
+ }
+ }
+
+ if ( ( !usePrefs || saveOptions.updateDescription )
+ && ( !saveOptions.descriptionString.isEmpty() ) )
+ {
+ temp = "# "+saveOptions.descriptionString;
+ temp.replace( "@PACKAGE@", packageName());
+ temp.replace( "@LANGUAGE@", identityOptions.languageName);
+ temp = temp.stripWhiteSpace();
+
+ // The description strings has often buggy variants already in the file, these must be removed
+ QString regexpstr = "^#\\s+" + QRegExp::escape( saveOptions.descriptionString.stripWhiteSpace() ) + "\\s*$";
+ regexpstr.replace( "@PACKAGE@", ".*" );
+ regexpstr.replace( "@LANGUAGE@", ".*" );
+ //kdDebug() << "REGEXPSTR: " << regexpstr << endl;
+ QRegExp regexp ( regexpstr );
+
+ // The buggy variants exist in English too (of a time before KBabel got a translation for the corresponding language)
+ QRegExp regexpUntranslated ( "^#\\s+Translation of .* into .*\\s*$" );
+
+ kdDebug () << "Temp is '" << temp << "'" << endl;
+
+ found=false;
+//not used anyway bool foundTemplate=false;
+
+ it = commentList.begin();
+ while ( it != commentList.end() )
+ {
+ kdDebug () << "testing '" << (*it) << "'" << endl;
+ bool deleteItem = false;
+
+ if ( (*it) == temp )
+ {
+ kdDebug () << "Match " << endl;
+ if ( found )
+ deleteItem = true;
+ else
+ found=true;
+ }
+ else if ( regexp.search( *it ) >= 0 )
+ {
+ // We have a similar (translated) string (from another project or another language (perhaps typos)). Remove it.
+ deleteItem = true;
+ }
+ else if ( regexpUntranslated.search( *it ) >= 0 )
+ {
+ // We have a similar (untranslated) string (from another project or another language (perhaps typos)). Remove it.
+ deleteItem = true;
+ }
+ else if ( (*it) == "# SOME DESCRIPTIVE TITLE." )
+ {
+ // We have the standard title placeholder, remove it
+ deleteItem = true;
+ }
+
+ if ( deleteItem )
+ it = commentList.remove( it );
+ else
+ ++it;
+ }
+ if(!found) commentList.prepend(temp);
+ }
+
+ // kdDebug() << "HEADER COMMENT: " << commentList << endl;
+
+ if ( (!usePrefs || saveOptions.updateTranslatorCopyright)
+ && ( ! identityOptions.authorName.isEmpty() )
+ && ( ! identityOptions.authorEmail.isEmpty() ) ) // An email address can be used as ersatz of a name
+ {
+ QStringList foundAuthors;
+
+ temp = "# ";
+ temp += identityOptions.authorName;
+ if(!identityOptions.authorEmail.isEmpty())
+ {
+ temp+=(" <"+identityOptions.authorEmail+">");
+ }
+ temp+=", "+QDate::currentDate().toString("yyyy")+".";
+
+ // ### TODO: it would be nice if the entry could start with "COPYRIGHT" and have the "(C)" symbol (both not mandatory)
+ QRegExp regexpAuthorYear( "^#.*(<.+@.+>)?,\\s*([\\d]+[\\d\\-, ]*|YEAR)" );
+ QRegExp regexpYearAlone( "^# , \\d{4}.?\\s*$" );
+ it = commentList.begin();
+ while ( it != commentList.end() )
+ {
+ bool deleteItem = false;
+ if ( (*it).find ( "copyright", 0, false ) != -1 )
+ {
+ // We have a line with a copyright. It should not be moved.
+ }
+ else if ( (*it).find ( regexpYearAlone ) != -1 )
+ {
+ // We have found a year number that is preceeded by a comma.
+ // That is typical of KBabel 1.10 (and earlier?) when there is neither an author name nor an email
+ // Remove the entry
+ deleteItem = true;
+ }
+ else if ( (*it) == "# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR." )
+ {
+ // Typical placeholder, remove it.
+ deleteItem = true;
+ }
+ else if ( (*it).find ( regexpAuthorYear ) != -1 ) // email address followed by year
+ {
+ if ( foundAuthors.find( (*it) ) == foundAuthors.end() )
+ {
+ // The author line is new (and not a duplicate), so add it to the author line list
+ foundAuthors.append( (*it) );
+ }
+ // Delete also non-duplicated entry, as now all what is needed will be processed in foundAuthors
+ deleteItem = true;
+ }
+
+ if ( deleteItem )
+ it = commentList.remove( it );
+ else
+ ++it;
+ }
+
+ if( !foundAuthors.isEmpty() )
+ {
+ found = false;
+ bool foundAuthor = false;
+
+ const QString cy = QDate::currentDate().toString("yyyy");
+
+ ait = foundAuthors.end();
+ for( it = foundAuthors.begin() ; it!=foundAuthors.end(); ++it )
+ {
+ if ( (*it).find( QRegExp(
+ QRegExp::escape( identityOptions.authorName )+".*"
+ + QRegExp::escape( identityOptions.authorEmail ) ) ) != -1 )
+ {
+ foundAuthor = true;
+ if( (*it).find( cy ) != -1 )
+ found = true;
+ else
+ ait = it;
+ }
+ }
+ if( !found )
+ {
+ if ( !foundAuthor )
+ foundAuthors.append(temp);
+ else if ( ait != foundAuthors.end() )
+ {
+ //update years
+ const int index = (*ait).findRev( QRegExp("[\\d]+[\\d\\-, ]*") );
+ if ( index == -1 )
+ (*ait)+=", "+cy;
+ else
+ (*ait).insert(index+1, QString(", ")+cy);
+ }
+ else
+ kdDebug() << "INTERNAL ERROR: author found but iterator dangling!" << endl;
+ }
+
+ }
+ else
+ foundAuthors.append(temp);
+ it=commentList.end();
+ do
+ --it;
+ while( ( it != commentList.begin() ) && ( (*it).find( QRegExp( "^#(\\s*$|[:,\\.])" ) ) == -1 ) );
+ ++it;
+ for( ait = foundAuthors.begin() ; ait != foundAuthors.end() ; ++ait )
+ {
+ QString s = (*ait);
+
+ // ensure dot at the end of copyright
+ if( !s.endsWith(".") ) s += ".";
+ commentList.insert(it, s);
+ }
+ }
+
+ oldHeader.setComment( commentList.join( "\n" ) );
+
+ return oldHeader;
+}
+
+void Catalog::setFuzzy(uint index, bool on)
+{
+ if ( d->_entries.isEmpty() )
+ return;
+
+ uint max=d->_entries.count()-1;
+ if(index > max)
+ return;
+
+ if(d->_entries[index].isFuzzy() != on)
+ {
+ applyBeginCommand( index, Comment, 0 );
+
+ QPtrList<EditCommand> editList;
+ if(on)
+ {
+ editList=d->_entries[index].addFuzzy(false);
+ }
+ else
+ {
+ editList=d->_entries[index].removeFuzzy(false);
+ d->_fuzzyIndex.remove(index);
+ }
+
+ for ( EditCommand* cmd=editList.first(); cmd != 0; cmd=editList.next() )
+ {
+ cmd->setIndex(index);
+ applyEditCommand(cmd,0);
+ }
+
+ setModified(true);
+
+ applyEndCommand( index, Comment, 0 );
+
+ emit signalNumberOfFuzziesChanged(numberOfFuzzies());
+ }
+
+}
+
+void Catalog::removeFuzzyStatus(uint index)
+{
+ setFuzzy(index,false);
+}
+
+
+void Catalog::setModified(bool flag)
+{
+ bool old=d->_modified;
+ d->_modified=flag;
+
+ if(old!=d->_modified)
+ emit signalModified(flag);
+}
+
+
+QString Catalog::packageName() const
+{
+ if( !d->_packageName.isNull() ) return d->_packageName;
+
+ QString package=d->_url.fileName();
+
+ int index=package.find(QRegExp("(\\."+identitySettings().languageCode+")?\\.pot?$"));
+
+ if(index>0)
+ package=package.left(index);
+
+ return package;
+}
+
+void Catalog::setPackage(const QString& package )
+{
+ const int pos = package.findRev( '/' );
+ if( pos < 0 )
+ {
+ d->_packageDir = QString();
+ d->_packageName = package;
+ }
+ else
+ {
+ d->_packageDir = package.left( pos + 1 ); // We want the / included
+ d->_packageName = package.mid( pos + 1 ); // We do not want /
+ }
+ kdDebug() << k_funcinfo << " " << package << " => " << d->_packageDir << " + " << d->_packageName << endl;
+}
+
+QString Catalog::packageDir() const
+{
+ QString result;
+ if( !d->_packageDir.isNull() ) result=d->_packageDir;
+ else result=d->_url.directory(false);
+
+ return result;
+}
+
+QString Catalog::encoding() const
+{
+ SaveSettings options = saveSettings();
+
+ QString encodingStr;
+ if(options.useOldEncoding && d->fileCodec)
+ {
+ encodingStr = charsetString(d->fileCodec);
+ }
+ else
+ {
+ encodingStr= charsetString(options.encoding);
+ }
+
+ return encodingStr;
+}
+
+ConversionStatus Catalog::openURL(const KURL& url, const QString& package)
+{
+ QString target;
+ ConversionStatus error = OK;
+
+ if(KIO::NetAccess::download(url, target, NULL))
+ {
+ CatalogImportPlugin* filter=0;
+
+ // gimme plugin for this MIME type
+ KMimeType::Ptr mime = KMimeType::findByURL( url, 0, true );
+ kdDebug() << "Found mimetype: " << mime->name() << endl;
+ KTrader::OfferList offers = KTrader::self()->query("KBabelFilter", "('"+mime->name()+"' in [X-KDE-Import])");
+ KService::Ptr ptr = offers.first();
+
+ // we have no offer for this MIME type
+ if( !ptr )
+ {
+ kdDebug(KBABEL) << "No plugin for this type, will try PO" << endl;
+ offers = KTrader::self()->query("KBabelFilter", "('application/x-gettext' in [X-KDE-Import])");
+ ptr = offers.first();
+ if( !ptr )
+ {
+ kdDebug(KBABEL) << "No plugin for PO files, giving up" << endl;
+ KIO::NetAccess::removeTempFile(target);
+ return NO_PLUGIN;
+ }
+ }
+
+ // try to load the library, if unsuccesfull, we have an installation problem
+ KLibFactory *factory = KLibLoader::self()->factory( ptr->library().local8Bit() );
+ if (!factory)
+ {
+ kdDebug(KBABEL) << "No factory" << endl;
+ KIO::NetAccess::removeTempFile(target);
+ return OS_ERROR;
+ }
+
+ // create the filter
+ filter = static_cast<CatalogImportPlugin*>(factory->create(0, 0));
+
+ // provide progress bar indication
+ connect( filter, SIGNAL( signalResetProgressBar(QString,int) ),
+ this, SIGNAL( signalResetProgressBar(QString,int) ));
+ connect( filter, SIGNAL( signalProgress(int) ),
+ this, SIGNAL( signalProgress(int) ));
+ connect( filter, SIGNAL( signalClearProgressBar() ),
+ this, SIGNAL( signalClearProgressBar() ));
+
+ connect( this, SIGNAL( signalStopActivity() ),
+ filter, SLOT( stop() ));
+
+ // load in the file (target is always local)
+ d->_active = true;
+ kdDebug(KBABEL) << "openURL active" << endl;
+ error = filter->open(target,mime->name(),this);
+ // we should be not freed yet
+ d->_active = false;
+ kdDebug(KBABEL) << "openURL not active" << endl;
+ if( error == STOPPED )
+ {
+ delete filter;
+ return STOPPED;
+ }
+
+ if( error == OK || error == RECOVERED_PARSE_ERROR || error == RECOVERED_HEADER_ERROR )
+ {
+ const uint entries = numberOfEntries();
+
+ if ( !entries )
+ {
+ // KBabel cannot work correctly with not any entry
+ kdWarning() << k_funcinfo << " No entries! Assuming parse error!" << endl;
+ delete filter;
+ return NO_ENTRY_ERROR;
+ }
+
+ //kdDebug( KBABEL ) << k_funcinfo << " Success (full or partial) " << entries << endl;
+ setModified(false);
+ d->_url=url;
+
+ if( package.isEmpty() )
+ {
+ d->_packageName=QString::null;
+ d->_packageDir=QString::null;
+ }
+ else setPackage(package);
+
+ emit signalFileOpened(d->_readOnly);
+ emit signalNumberOfFuzziesChanged(numberOfFuzzies());
+ emit signalNumberOfUntranslatedChanged(numberOfUntranslated());
+ emit signalTotalNumberChanged( entries );
+ }
+
+ delete filter;
+
+ return error;
+ }
+ else
+ {
+ return OS_ERROR;
+ }
+}
+
+ConversionStatus Catalog::openURL(const KURL& openUrl, const KURL& saveURL, const QString& package)
+{
+ QString target;
+ ConversionStatus error = OK;
+
+ if(KIO::NetAccess::download(openUrl, target, NULL))
+ {
+ CatalogImportPlugin* filter=0;
+
+ // gimme plugin for this MIME type
+ KMimeType::Ptr mime = KMimeType::findByURL( openUrl, 0, true );
+ KTrader::OfferList offers = KTrader::self()->query("KBabelFilter", "('"+mime->name()+"' in [X-KDE-Import])");
+ KService::Ptr ptr = offers.first();
+
+ // we have no offer for this MIME type
+ if( !ptr )
+ {
+ kdDebug(KBABEL) << "No plugin for this type" << endl;
+ KIO::NetAccess::removeTempFile(target);
+ return NO_PLUGIN;
+ }
+
+ // try to load the library, if unsuccesfull, we have an installation problem
+ KLibFactory *factory = KLibLoader::self()->factory( ptr->library().local8Bit() );
+ if (!factory)
+ {
+ kdDebug(KBABEL) << "No factory" << endl;
+ KIO::NetAccess::removeTempFile(target);
+ return OS_ERROR;
+ }
+
+ // create the filter
+ filter = static_cast<CatalogImportPlugin*>(factory->create(0, 0));
+
+ // provide progress bar indication
+ connect( filter, SIGNAL( signalResetProgressBar(QString,int) ),
+ this, SIGNAL( signalResetProgressBar(QString,int) ));
+ connect( filter, SIGNAL( signalProgress(int) ),
+ this, SIGNAL( signalProgress(int) ));
+ connect( filter, SIGNAL( signalClearProgressBar() ),
+ this, SIGNAL( signalClearProgressBar() ));
+
+ connect( this, SIGNAL( signalStopActivity() ),
+ filter, SLOT( stop() ));
+
+ // load in the file (target is always local)
+ d->_active = true;
+ kdDebug(KBABEL) << "openURL - template active" << endl;
+ error = filter->open(target,mime->name(),this);
+ // we should be not freed yet
+ kdDebug(KBABEL) << "openURL - template not active" << endl;
+ d->_active = false;
+ if( error == STOPPED )
+ {
+ delete filter;
+ KIO::NetAccess::removeTempFile(target);
+ return STOPPED;
+ }
+
+ // Templates should not have recoverable errors (or they are bad templates)
+ if( error == OK )
+ {
+ const uint entries = numberOfEntries();
+
+ if ( !entries )
+ {
+ // KBabel cannot work correctly with not any entry
+ kdWarning() << k_funcinfo << " No entries! Assuming parse error!" << endl;
+ delete filter;
+ KIO::NetAccess::removeTempFile(target);
+ return NO_ENTRY_ERROR;
+ }
+
+ setModified(false);
+ d->_url = saveURL;
+ if( package.isEmpty() )
+ {
+ d->_packageName=QString::null;
+ d->_packageDir=QString::null;
+ }
+ else setPackage(package);
+
+ emit signalFileOpened(d->_readOnly);
+ emit signalNumberOfFuzziesChanged(numberOfFuzzies());
+ emit signalNumberOfUntranslatedChanged(numberOfUntranslated());
+ emit signalTotalNumberChanged( entries );
+ }
+
+ delete filter;
+
+ // and remove the temp file
+ KIO::NetAccess::removeTempFile(target);
+
+ return error;
+ }
+ else
+ {
+ return OS_ERROR;
+ }
+}
+
+Msgfmt::Status Catalog::checkSyntax(QString& output, bool clearErrors)
+{
+ if( !d->_mimeTypes.contains( "application/x-gettext" ) )
+ return Msgfmt::Unsupported;
+
+ QString filename;
+ bool tempFileUsed=false;
+
+ if(d->_url.isLocalFile() && !isModified())
+ {
+ filename=d->_url.path(0);
+ }
+ else
+ {
+ tempFileUsed=true;
+ filename=saveTempFile();
+ }
+
+ Msgfmt msgfmt;
+ Msgfmt::Status result = msgfmt.checkSyntax( filename , output, pluralFormType() != KDESpecific );
+
+ if( clearErrors) clearErrorList();
+
+ if( result==Msgfmt::SyntaxError )
+ {
+ int currentIndex=-1;
+ int currentLine=0;
+
+ if( !d->_header.msgstr().isEmpty() )
+ currentLine=d->_header.totalLines()+1;
+
+ // ### KDE4: return "lines" not "output"
+ const QStringList lines = QStringList::split("\n",output);
+ for ( QStringList::const_iterator it = lines.constBegin(); it != lines.constEnd(); ++it )
+ {
+ if( (*it).find(QRegExp("^.+:\\d+:")) >= 0 )
+ {
+ const int begin=(*it).find(":",0)+1;
+ const int end=(*it).find(":",begin);
+
+ const QString line=(*it).mid(begin,end-begin);
+
+ while( line.toInt() > currentLine )
+ {
+ currentIndex++;
+ currentLine += ( d->_entries[currentIndex].totalLines() + 1 );
+ }
+
+ if( currentIndex == -1 )
+ {
+ // header error
+ result = Msgfmt::HeaderError;
+ continue;
+ }
+
+ if( !d->_errorIndex.contains(currentIndex) )
+ {
+ d->_errorIndex.append(currentIndex);
+ d->_entries[currentIndex].setSyntaxError(true);
+ }
+ }
+ }
+ }
+
+ if(tempFileUsed)
+ QFile::remove(filename);
+
+ return result;
+}
+
+void Catalog::clearErrorList()
+{
+ QValueList<uint>::Iterator it;
+ for(it = d->_errorIndex.begin(); it != d->_errorIndex.end(); ++it)
+ {
+ d->_entries[(*it)].setSyntaxError(false);
+ d->_entries[(*it)].clearErrors();
+ }
+
+ d->_errorIndex.clear();
+}
+
+void Catalog::removeFromErrorList(uint index)
+{
+ if(d->_errorIndex.contains(index))
+ {
+ d->_errorIndex.remove(index);
+ d->_entries[index].setSyntaxError(false);
+ d->_entries[index].clearErrors();
+ }
+}
+
+QStringList Catalog::itemStatus(uint index, bool recheck, QPtrList<KDataTool> whatToCheck)
+{
+ if ( d->_entries.isEmpty() )
+ return QStringList();
+
+ uint max=d->_entries.count()-1;
+ if(index > max)
+ index=max;
+
+ CatalogItem& item = d->_entries[index];
+
+ if(recheck)
+ {
+ for( KDataTool* t = whatToCheck.first(); t ; t=whatToCheck.next() )
+ {
+ t->run("validate", (void*)(&item), "CatalogItem", "application/x-kbabel-catalogitem" );
+ }
+ }
+
+ return item.errors();
+}
+
+QStringList Catalog::itemStatus(uint index)
+{
+ if ( d->_entries.isEmpty() )
+ return QStringList();
+
+ uint max=d->_entries.count()-1;
+ if(index > max)
+ index=max;
+
+ CatalogItem& item = d->_entries[index];
+
+ return item.errors();
+}
+
+bool Catalog::checkUsingTool(KDataTool* tool, bool clearErrors)
+{
+ if(clearErrors)
+ clearErrorList();
+
+ kdDebug(KBABEL) << "checkUsingTool active" << endl;
+ d->_active=true;
+ d->_stop=false;
+ connect( this, SIGNAL( signalStopActivity() ), this, SLOT( stopInternal() ));
+
+ int index = 0;
+ bool hasErrors=false;
+
+ emit signalResetProgressBar(i18n("validating file"),100);
+
+ for ( QValueVector<CatalogItem>::Iterator it = d->_entries.begin();
+ it != d->_entries.end(); ++it, index++ )
+ {
+ if( !tool->run( "validate", (void*)(&(*it)), "CatalogItem", "application/x-kbabel-catalogitem" ))
+ {
+ if( !d->_errorIndex.contains(index) )
+ {
+ d->_errorIndex.append(index);
+ hasErrors=true;
+ }
+ }
+ if( d->_stop ) break;
+ emit signalProgress((index*100)/d->_entries.count());
+ }
+
+ if( hasErrors && !clearErrors ) qHeapSort(d->_errorIndex);
+
+ kdDebug(KBABEL) << "checkUsingTool not active" << endl;
+ d->_active=false;
+ d->_stop=false;
+ disconnect( this, SIGNAL( signalStopActivity() ), this, SLOT( stopInternal() ));
+
+ emit signalClearProgressBar();
+
+ return !hasErrors;
+}
+
+void Catalog::modifyUsingTool(KDataTool* tool, const QString& command)
+{
+ kdDebug(KBABEL) << "modifyUsingTool active" << endl;
+ d->_active=true;
+ d->_stop=false;
+ connect( this, SIGNAL( signalStopActivity() ), this, SLOT( stopInternal() ));
+
+ int index = 0;
+ bool modified = false;
+
+ emit signalResetProgressBar(i18n("applying tool"),100);
+
+ for ( QValueVector<CatalogItem>::Iterator it = d->_entries.begin();
+ it != d->_entries.end(); ++it, index++ )
+ {
+ CatalogItem dummyItem( *it );
+
+ tool->run( command, (void*)(&dummyItem), "CatalogItem", "application/x-kbabel-catalogitem" );
+
+ if( (*it).msgstr() != dummyItem.msgstr() || (*it).comment() != dummyItem.comment() )
+ {
+ if( !modified )
+ {
+ applyBeginCommand(0,Msgstr,0);
+ modified = true;
+ }
+
+ if( (*it).msgstr() != dummyItem.msgstr() )
+ {
+ uint in = 0; // number of current lural form
+ // go over all plural forms and test, which changed
+ for ( QStringList::Iterator itorig = (*it).msgstr().begin()
+ , itchanged = dummyItem.msgstr().begin()
+ ; itorig != (*it).msgstr().end()
+ ; ++itorig, ++itchanged) {
+ if( (*itorig) != (*itchanged) )
+ {
+ EditCommand* cmd = new DelTextCmd(0,(*itorig),index);
+ cmd->setPart(Msgstr);
+ applyEditCommand(cmd,0);
+ cmd = new InsTextCmd(0,(*itchanged),index);
+ cmd->setPart(Msgstr);
+ applyEditCommand(cmd,0);
+ }
+ in++;
+ }
+ }
+
+ if( (*it).comment() != dummyItem.comment() )
+ {
+ EditCommand* cmd = new DelTextCmd(0,(*it).comment(),0);
+ cmd->setPart(Comment);
+ cmd->setIndex(index);
+ applyEditCommand(cmd,0);
+ cmd = new InsTextCmd(0,dummyItem.comment(),0);
+ cmd->setPart(Comment);
+ cmd->setIndex(index);
+ applyEditCommand(cmd,0);
+ kdDebug(KBABEL) << "DummyItem comment is " << dummyItem.comment() << endl;
+ }
+ }
+
+ if( d->_stop ) break;
+ emit signalProgress((index*100)/d->_entries.count());
+ }
+
+ if( modified ) applyEndCommand(0, Msgstr, 0);
+
+ kdDebug(KBABEL) << "modifyUsingTool not active" << endl;
+ d->_active=false;
+ d->_stop=false;
+ disconnect( this, SIGNAL( signalStopActivity() ), this, SLOT( stopInternal() ));
+
+ emit signalClearProgressBar();
+}
+
+void Catalog::clear()
+{
+ d->_errorIndex.clear();
+ d->_entries.clear();
+ d->_url=KURL();
+ d->_obsoleteEntries.clear();
+
+ if(d->_undoList.count() > 0)
+ emit signalUndoAvailable(false);
+ if(d->_redoList.count() > 0)
+ emit signalRedoAvailable(false);
+
+ d->_undoList.clear();
+ d->_redoList.clear();
+
+ d->msgidDiffList.clear();
+ d->msgstr2MsgidDiffList.clear();
+ d->diffCache.clear();
+}
+
+
+uint Catalog::numberOfEntries() const
+{
+ return d->_entries.count();
+}
+
+uint Catalog::numberOfFuzzies() const
+{
+ return d->_fuzzyIndex.count();
+}
+
+uint Catalog::numberOfUntranslated() const
+{
+ return d->_untransIndex.count();
+}
+
+
+bool Catalog::hasFuzzyInFront(uint index) const
+{
+ if(findPrevInList(d->_fuzzyIndex,index)>=0)
+ {
+ return true;
+ }
+
+ return false;
+}
+
+bool Catalog::hasFuzzyAfterwards(uint index) const
+{
+ if(findNextInList(d->_fuzzyIndex,index)>=0)
+ {
+ return true;
+ }
+
+ return false;
+}
+
+bool Catalog::hasUntranslatedInFront(uint index) const
+{
+ if(findPrevInList(d->_untransIndex,index)>=0)
+ {
+ return true;
+ }
+
+ return false;
+}
+
+bool Catalog::hasUntranslatedAfterwards(uint index) const
+{
+ if(findNextInList(d->_untransIndex,index)>=0)
+ {
+ return true;
+ }
+
+ return false;
+}
+
+bool Catalog::hasErrorInFront(uint index) const
+{
+ if(findPrevInList(d->_errorIndex,index)>=0)
+ {
+ return true;
+ }
+
+ return false;
+}
+
+bool Catalog::hasErrorAfterwards(uint index) const
+{
+ if(findNextInList(d->_errorIndex,index)>=0)
+ {
+ return true;
+ }
+
+ return false;
+}
+
+bool Catalog::isFuzzy(uint index) const
+{
+ if ( d->_entries.isEmpty() )
+ return false;
+
+ if(index > numberOfEntries())
+ return false;
+
+ return d->_entries[index].isFuzzy();
+}
+
+
+bool Catalog::isUntranslated(uint index) const
+{
+ if ( d->_entries.isEmpty() )
+ return false;
+
+ if(index > numberOfEntries())
+ return false;
+
+ return d->_entries[index].isUntranslated();
+}
+
+bool Catalog::hasError(uint index, DocPosition& pos) const
+{
+ if( d->_errorIndex.contains(index) )
+ {
+ pos.item=index;
+ pos.form=0;
+ return true;
+ }
+ return false;
+}
+
+PluralFormType Catalog::pluralForm(uint index) const
+{
+ if ( d->_entries.isEmpty() )
+ return NoPluralForm;
+
+ if(index > numberOfEntries())
+ return NoPluralForm;
+
+ return static_cast<PluralFormType>(d->_entries[index].pluralForm());
+}
+
+PluralFormType Catalog::pluralFormType() const
+{
+ if ( d->_entries.isEmpty() )
+ return NoPluralForm;
+
+ for( uint i = 0 ; i < numberOfEntries(); i++)
+ {
+ if( d->_entries[i].pluralForm() != NoPluralForm )
+ return d->_entries[i].pluralForm();
+ }
+
+ return NoPluralForm;
+}
+
+int Catalog::nextFuzzy(uint startIndex, DocPosition& pos) const
+{
+ pos.item=findNextInList(d->_fuzzyIndex,startIndex);
+ pos.form=0;
+ return pos.item;
+}
+
+int Catalog::prevFuzzy(uint startIndex, DocPosition& pos) const
+{
+ pos.item=findPrevInList(d->_fuzzyIndex,startIndex);
+ pos.form=0;
+ return pos.item;
+}
+
+int Catalog::nextUntranslated(uint startIndex, DocPosition& pos) const
+{
+ pos.item=findNextInList(d->_untransIndex,startIndex);
+ pos.form=0;
+ return pos.item;
+}
+
+int Catalog::prevUntranslated(uint startIndex, DocPosition& pos) const
+{
+ pos.item=findPrevInList(d->_untransIndex,startIndex);
+ pos.form=0;
+ return pos.item;
+}
+
+
+int Catalog::nextError(uint startIndex, DocPosition& pos) const
+{
+ pos.item=findNextInList(d->_errorIndex,startIndex);
+ pos.form=0;
+ return pos.item;
+}
+
+int Catalog::prevError(uint startIndex, DocPosition& pos) const
+{
+ pos.item=findPrevInList(d->_errorIndex,startIndex);
+ pos.form=0;
+ return pos.item;
+}
+
+
+void Catalog::registerView(CatalogView* view)
+{
+ if(d->_views.containsRef(view)==0)
+ {
+ d->_views.append(view);
+ }
+}
+
+
+void Catalog::removeView(CatalogView* view)
+{
+ d->_views.removeRef(view);
+}
+
+
+void Catalog::updateViews(EditCommand* cmd,CatalogView* view2exclude)
+{
+ CatalogView* view;
+ for ( view=d->_views.first(); view != 0; view=d->_views.next())
+ {
+ if(view!=view2exclude)
+ {
+ view->update(cmd);
+ }
+ }
+}
+
+
+
+bool Catalog::hasView() const
+{
+ if(d->_views.count()==0)
+ return false;
+
+ return true;
+}
+
+bool Catalog::isLastView() const
+{
+ if(d->_views.count()<=1)
+ return true;
+
+ return false;
+}
+
+
+void Catalog::useProject(Project::Ptr project)
+{
+ d->_project->config()->sync();
+ d->_project = project;
+ readPreferences();
+ emit signalSettingsChanged(saveSettings());
+ emit signalSettingsChanged(identitySettings());
+ emit signalSettingsChanged(miscSettings());
+ emit signalSettingsChanged(tagSettings());
+}
+
+Project::Ptr Catalog::project() const
+{
+ return d->_project;
+}
+
+void Catalog::readPreferences()
+{
+ getNumberOfPluralForms();
+
+ d->_project->config()->setGroup("Tags");
+ d->_tagSettings.tagExpressions=d->_project->config()->readListEntry("TagExpressions");
+ if( d->_tagSettings.tagExpressions.empty() ) d->_tagSettings.tagExpressions = Defaults::Tag::tagExpressions();
+ d->_tagExtractor->setRegExpList(d->_tagSettings.tagExpressions) ;
+
+ d->_tagSettings.argExpressions=d->_project->config()->readListEntry("ArgExpressions");
+ if( d->_tagSettings.argExpressions.empty() ) d->_tagSettings.argExpressions = Defaults::Tag::argExpressions();
+ d->_argExtractor->setRegExpList(d->_tagSettings.argExpressions) ;
+}
+
+void Catalog::savePreferences()
+{
+ d->_project->config()->setGroup("Tags");
+
+ d->_project->config()->writeEntry( "TagExpressions", d->_tagSettings.tagExpressions );
+ d->_project->config()->writeEntry( "ArgExpressions", d->_tagSettings.argExpressions );
+
+ d->_project->config()->sync();
+}
+
+IdentitySettings Catalog::identitySettings() const
+{
+ return d->_project->identitySettings();
+}
+
+SaveSettings Catalog::saveSettings() const
+{
+ return d->_project->saveSettings();
+
+}
+
+MiscSettings Catalog::miscSettings() const
+{
+ return d->_project->miscSettings();
+
+}
+
+TagSettings Catalog::tagSettings() const
+{
+ return d->_tagSettings;
+
+}
+
+bool Catalog::isGeneratedFromDocbook() const
+{
+ return d->_generatedFromDocbook;
+}
+
+QString Catalog::package() const
+{
+ return packageDir()+packageName();
+}
+
+bool Catalog::isReadOnly() const
+{
+ return d->_readOnly;
+}
+
+void Catalog::setSettings(SaveSettings settings)
+{
+ d->_project->setSettings(settings);
+}
+
+void Catalog::setSettings(IdentitySettings settings)
+{
+ IdentitySettings oldsettings = d->_project->identitySettings();
+
+ QString oldLanguageCode = oldsettings.languageCode;
+ int oldForms = oldsettings.numberOfPluralForms;
+
+
+ d->_project->setSettings(settings);
+
+ if(oldLanguageCode != settings.languageCode)
+ {
+ getNumberOfPluralForms();
+ }
+
+ if(oldForms != settings.numberOfPluralForms)
+ {
+ getNumberOfPluralForms();
+ }
+
+ emit signalSettingsChanged(settings);
+}
+
+void Catalog::setSettings(MiscSettings settings)
+{
+ d->_project->setSettings(settings);
+ emit signalSettingsChanged(settings);
+}
+
+void Catalog::setSettings(TagSettings settings)
+{
+ d->_tagSettings=settings;
+
+ emit signalSettingsChanged(settings);
+}
+
+void Catalog::generateIndexLists()
+{
+ d->_fuzzyIndex.clear();
+ d->_untransIndex.clear();
+ clearErrorList();
+
+ uint counter=0;
+ for ( QValueVector<CatalogItem>::Iterator it = d->_entries.begin(); it != d->_entries.end(); ++it )
+ {
+ if((*it).isUntranslated())
+ {
+ d->_untransIndex.append(counter);
+ }
+ else if((*it).isFuzzy())
+ {
+ d->_fuzzyIndex.append(counter);
+ }
+
+ counter++;
+ }
+
+}
+
+int Catalog::findNextInList(const QValueList<uint>& list,uint index) const
+{
+ QValueList<uint>::ConstIterator it;
+
+ int nextIndex=-1;
+
+ // find index in List
+ it=list.find(index);
+
+ // if the given index is found in the list and not the last entry
+ // in the list, return the next listentry
+ if(it!=list.end() && it!=list.fromLast())
+ {
+ ++it;
+ return (*it);
+ }
+
+ // if the index is not in the list, search the index in the list, that
+ // is the nearest to the given index
+ for( it = list.begin(); it != list.end(); ++it )
+ {
+ if((*it) > index)
+ {
+ nextIndex=(*it);
+ break;
+ }
+ }
+
+
+ return nextIndex;
+}
+
+int Catalog::findPrevInList(const QValueList<uint>& list,uint index) const
+{
+ QValueList<uint>::ConstIterator it;
+
+ int prevIndex=-1;
+
+ it=list.find(index);
+
+ // if the given index is found in the list and not the last entry
+ // in the list, return the next listentry
+ if(it!=list.end() && it!=list.begin())
+ {
+ --it;
+ return (*it);
+ }
+
+
+ // if the index is not in the list, search the index in the list, that
+ // is the nearest to the given index
+ for( it = list.fromLast(); it != list.end(); --it )
+ {
+ if((*it) < index)
+ {
+ prevIndex=(*it);
+ break;
+ }
+
+ if ( it == list.constBegin() )
+ {
+ // Decremeniting the iterator at the begin is undefined, so break the loop
+ break;
+ }
+ }
+
+
+ return prevIndex;
+}
+
+
+QString Catalog::dateTime() const
+{
+ const QDateTime dt = QDateTime::currentDateTime();
+ QString dateTimeString;
+
+ const SaveSettings options = d->_project->saveSettings();
+
+ switch(options.dateFormat)
+ {
+ case Qt::LocalDate:
+ {
+ dateTimeString = KGlobal::locale()->formatDateTime( dt );
+ break;
+ }
+ case Qt::ISODate:
+ {
+ dateTimeString = dt.toString("yyyy-MM-dd hh:mm");
+ QTime t;
+ const int offset = KRFCDate::localUTCOffset();
+ const int correction = offset < 0 ? -60 : 60 ;
+ t = t.addSecs( offset * correction );
+ dateTimeString += ( offset < 0 ? "-" : "+" );
+ dateTimeString += t.toString("hhmm");
+ break;
+ }
+ case Qt::TextDate:
+ {
+ dateTimeString = options.customDateFormat;
+
+ const QDate date = dt.date();
+ const QTime time = dt.time();
+
+ // the year
+ dateTimeString.replace( "%Y", QString::number( date.year() ) );
+ dateTimeString.replace( "%y", QString::number( date.year() ).right(2) );
+
+ // the month
+ if(date.month()<10)
+ {
+ dateTimeString.replace( "%m", "0"+QString::number( date.month() ) );
+ }
+ else
+ {
+ dateTimeString.replace( "%m", QString::number( date.month() ) );
+ }
+
+ dateTimeString.replace( "%f", QString::number( date.month() ) );
+
+ dateTimeString.replace( "%b", date.longMonthName(date.month()) );
+ dateTimeString.replace( "%h", date.longMonthName(date.month()) );
+
+ // the day
+ dateTimeString.replace( "%j", QString::number( date.dayOfYear() ) );
+ dateTimeString.replace( "%e", QString::number( date.day() ) );
+ if(date.day() < 10)
+ {
+ dateTimeString.replace( "%d", "0"+QString::number( date.day() ) );
+ }
+ else
+ {
+ dateTimeString.replace( "%d", QString::number( date.day() ) );
+ }
+
+ dateTimeString.replace( "%a", date.longDayName( date.dayOfWeek() ) );
+
+
+ // hour
+ dateTimeString.replace( "%k", QString::number( time.hour() ) );
+
+ if(time.hour() < 10)
+ {
+ dateTimeString.replace( "%H", "0"+QString::number( time.hour() ) );
+ }
+ else
+ {
+ dateTimeString.replace( "%H", QString::number( time.hour() ) );
+ }
+
+ QString zone; // AM or PM
+ int hour = time.hour();
+ if( hour > 12 )
+ {
+ zone="PM";
+ hour -= 12;
+ }
+ else
+ {
+ zone="AM";
+ }
+
+ dateTimeString.replace( "%I", QString::number( hour ) );
+
+ if(hour < 10)
+ {
+ dateTimeString.replace( "%i", "0"+QString::number( hour ) );
+ }
+ else
+ {
+ dateTimeString.replace( "%i", QString::number( hour ) );
+ }
+
+ dateTimeString.replace( "%p", zone );
+
+ // minutes
+ if(time.minute() < 10)
+ {
+ dateTimeString.replace( "%M", "0"+QString::number( time.minute() ) );
+ }
+ else
+ {
+ dateTimeString.replace( "%M", QString::number( time.minute() ) );
+ }
+
+ // seconds
+ if(time.second() < 10)
+ {
+ dateTimeString.replace( "%S", "0"+QString::number( time.second() ) );
+ }
+ else
+ {
+ dateTimeString.replace( "%S", QString::number( time.second() ) );
+ }
+
+ // timezone
+ dateTimeString.replace( "%Z", d->_project->identitySettings().timeZone );
+ QTime t;
+ const int offset = KRFCDate::localUTCOffset();
+ const int correction = offset < 0 ? -60 : 60;
+ t = t.addSecs( offset * correction );
+ dateTimeString.replace( "%z", ( offset < 0 ? "-" : "+" ) + t.toString("hhmm") );
+ break;
+ }
+ }
+ kdDebug(KBABEL) << "New date: " << dateTimeString << endl;
+ return dateTimeString;
+}
+
+
+ConversionStatus Catalog::saveFile()
+{
+ if(d->_url.isEmpty())
+ {
+ kdFatal(KBABEL) << "fatal error: empty filename" << endl;
+ return NO_FILE;
+ }
+
+ return saveFileAs(d->_url,true);
+}
+
+ConversionStatus Catalog::saveFileAs(const KURL &url, bool overwrite)
+{
+ if( d->_active ) return BUSY;
+
+ ConversionStatus status=OK;
+
+ bool newName=false;
+ KURL targetURL=d->_url;
+
+ if(url != d->_url)
+ {
+ newName = true;
+ targetURL=url;
+ }
+
+
+ if(d->_project->saveSettings().autoUpdate)
+ {
+ d->_header=updatedHeader(d->_header);
+ emit signalHeaderChanged();
+ }
+
+
+ if(targetURL.isLocalFile())
+ {
+ // test if the directory exists. If not, create it.
+ QDir dir( targetURL.directory());
+
+ QStringList dirList;
+ while(!dir.exists() && !dir.dirName().isEmpty())
+ {
+ dirList.prepend(dir.dirName());
+ dir.setPath(dir.path()+"/..");
+ }
+ for ( QStringList::Iterator it = dirList.begin(); it != dirList.end(); ++it )
+ {
+ if(!dir.mkdir(*it))
+ {
+ status=OS_ERROR;
+ break;
+ }
+ dir.cd(*it);
+ }
+
+ if(status==OK)
+ {
+ status=writeFile(targetURL.path(0),overwrite);
+ }
+ }
+ else
+ {
+ QString tempFile=kapp->tempSaveName(targetURL.path(0));
+
+ status = writeFile(tempFile,overwrite);
+
+ if(status == OK)
+ {
+ if( !KIO::NetAccess::upload( tempFile, targetURL, NULL ) )
+ {
+ status = OS_ERROR;
+ }
+ }
+
+ QFile::remove(tempFile);
+ }
+
+ if(status == OK)
+ {
+ setModified(false);
+
+ if(newName)
+ {
+ // if we saved a file, the catalog can not be any longer readOnly;
+ d->_readOnly=false;
+
+ d->_url=targetURL;
+
+ emit signalFileOpened(d->_readOnly);
+ }
+ }
+
+ return status;
+}
+
+QString Catalog::saveTempFile()
+{
+ QString filename = kapp->tempSaveName("/temp/kbabel_temp.po");
+ if( writeFile(filename) != OK )
+ {
+ filename = QString::null;
+ }
+
+ return filename;
+}
+
+
+ConversionStatus Catalog::writeFile(QString localFile , bool overwrite)
+{
+ QFileInfo info(localFile);
+
+ if(info.isDir())
+ return NO_FILE;
+
+ if(info.exists())
+ {
+ if(!overwrite || !info.isWritable())
+ {
+ return NO_PERMISSIONS;
+ }
+ }
+ else // check if the directory is writable
+ {
+ QFileInfo dir(info.dirPath());
+ if(!dir.isWritable())
+ {
+ return NO_PERMISSIONS;
+ }
+ }
+
+ ConversionStatus error = OK;
+ CatalogExportPlugin* filter=0;
+
+ // gimme plugin for this MIME type
+ KMimeType::Ptr mime = KMimeType::findByURL( KURL::fromPathOrURL( localFile ) );
+ KTrader::OfferList offers = KTrader::self()->query("KBabelFilter", "('"+mime->name()+"' in [X-KDE-Export])");
+ KService::Ptr ptr = offers.first();
+
+ // we have no offer for this MIME type
+ if( !ptr )
+ {
+ kdDebug(KBABEL) << "No plugin for this type" << endl;
+ return NO_PLUGIN;
+ }
+
+ // try to load the library, if unsuccesfull, we have an installation problem
+ KLibFactory *factory = KLibLoader::self()->factory( ptr->library().local8Bit() );
+ if (!factory)
+ {
+ kdDebug(KBABEL) << "No factory" << endl;
+ return OS_ERROR;
+ }
+
+ // create the filter
+ filter = static_cast<CatalogExportPlugin*>(factory->create(0, 0));
+
+ // provide progress bar indication
+ connect( filter, SIGNAL( signalResetProgressBar(QString,int) ),
+ this, SIGNAL( signalResetProgressBar(QString,int) ));
+ connect( filter, SIGNAL( signalProgress(int) ),
+ this, SIGNAL( signalProgress(int) ));
+ connect( filter, SIGNAL( signalClearProgressBar() ),
+ this, SIGNAL( signalClearProgressBar() ));
+
+ connect( this, SIGNAL( signalStopActivity() ),
+ filter, SLOT( stop() ));
+
+ // load in the file (target is always local)
+ kdDebug(KBABEL) << "writeFile active" << endl;
+ d->_active = true;
+ error = filter->save(localFile,mime->name(),this);
+ // we should be not freed yet
+ kdDebug(KBABEL) << "writeFile not active" << endl;
+ d->_active = false;
+ if( error == STOPPED ) return STOPPED;
+
+ delete filter;
+
+ return error;
+}
+
+QTextCodec* Catalog::codecForFile(QString gettextHeader)
+{
+ QString charset;
+
+ QString head = gettextHeader;
+
+ QRegExp r("Content-Type:\\s*\\w+/[-\\w]+;?\\s*charset\\s*=\\s*[^\\\"\\n]+");
+ int begin=r.search(head);
+ int len=r.matchedLength();
+ if(begin<0) {
+ kdDebug(KBABEL) << "no charset entry found" << endl;
+ return 0;
+ }
+
+ head = head.mid(begin,len);
+
+ QRegExp regexp("charset *= *([^\\\\\\\"]+)");
+ if( regexp.search( head ) > -1 )
+ {
+ charset = regexp.cap(1);
+ }
+
+ QTextCodec* codec=0;
+
+ if(!charset.isEmpty())
+ {
+ // "CHARSET" is the default charset entry in a template (pot).
+ // characters in a template should be either pure ascii or
+ // at least utf8, so utf8-codec can be used for both.
+ if( charset == "CHARSET")
+ {
+ codec=QTextCodec::codecForName("utf8");
+ kdDebug(KBABEL)
+ << QString("file seems to be a template: using utf8 encoding.")
+ << endl;
+ }
+ else
+ {
+ codec=QTextCodec::codecForName(charset.latin1());
+ }
+
+ if(!codec)
+ {
+ kdWarning() << "charset found, but no codec available, using UTF8 instead" << endl;
+ codec=QTextCodec::codecForName("utf8");
+ }
+ }
+
+ return codec;
+}
+
+PoInfo Catalog::headerInfo(const CatalogItem headerItem)
+{
+ QStringList header=headerItem.msgstrAsList();
+
+ QStringList::Iterator it;
+
+ PoInfo info;
+
+ // extract information from the header
+ for(it=header.begin();it!=header.end();++it)
+ {
+ if((*it).contains(QRegExp("^\\s*Project-Id-Version\\s*:\\s*.+\\s*$")))
+ {
+ info.project=(*it).replace(QRegExp("^\\s*Project-Id-Version\\s*:\\s*"),"");
+
+ if(info.project.right(2)=="\\n")
+ info.project.remove(info.project.length()-2,2);
+
+ info.project=info.project.simplifyWhiteSpace();
+ }
+ else if((*it).contains(QRegExp("^\\s*POT-Creation-Date\\s*:\\s*.+\\s*$")))
+ {
+ info.creation=(*it).replace(QRegExp("^\\s*POT-Creation-Date\\s*:\\s*"),"");
+
+ if(info.creation.right(2)=="\\n")
+ info.creation.remove(info.creation.length()-2,2);
+
+ info.creation=info.creation.simplifyWhiteSpace();
+ }
+ else if((*it).contains(QRegExp("^\\s*PO-Revision-Date\\s*:\\s*.+\\s*$")))
+ {
+ info.revision=(*it).replace(QRegExp("^\\s*PO-Revision-Date\\s*:\\s*"),"");
+
+ if(info.revision.right(2)=="\\n")
+ info.revision.remove(info.revision.length()-2,2);
+
+ info.revision=info.revision.simplifyWhiteSpace();
+ }
+ else if((*it).contains(QRegExp("^\\s*Last-Translator\\s*:\\s*.+\\s*$")))
+ {
+ info.lastTranslator=(*it).replace(QRegExp("^\\s*Last-Translator\\s*:\\s*"),"");
+
+ if(info.lastTranslator.right(2)=="\\n")
+ info.lastTranslator.remove(info.lastTranslator.length()-2,2);
+
+ info.lastTranslator=info.lastTranslator.simplifyWhiteSpace();
+ }
+ else if((*it).contains(QRegExp("^\\s*Language-Team\\s*:\\s*.+\\s*")))
+ {
+ info.languageTeam=(*it).replace(QRegExp("^\\s*Language-Team\\s*:\\s*"),"");
+
+ if(info.languageTeam.right(2)=="\\n")
+ info.languageTeam.remove(info.languageTeam.length()-2,2);
+
+ info.languageTeam=info.languageTeam.simplifyWhiteSpace();
+ }
+ else if((*it).contains(QRegExp("^\\s*MIME-Version\\s*:\\s*.+\\s*")))
+ {
+ info.mimeVersion=(*it).replace(QRegExp("^\\s*MIME-Version\\s*:\\s*"),"");
+
+ if(info.mimeVersion.right(2)=="\\n")
+ info.mimeVersion.remove(info.mimeVersion.length()-2,2);
+
+ info.mimeVersion=info.mimeVersion.simplifyWhiteSpace();
+ }
+ else if((*it).contains(QRegExp("^\\s*Content-Type\\s*:\\s*.+\\s*")))
+ {
+ info.contentType=(*it).replace(QRegExp("^\\s*Content-Type\\s*:\\s*"),"");
+
+ if(info.contentType.right(2)=="\\n")
+ info.contentType.remove(info.contentType.length()-2,2);
+
+ info.contentType=info.contentType.simplifyWhiteSpace();
+ }
+ else if((*it).contains(QRegExp("^\\s*Content-Transfer-Encoding\\s*:\\s*.+\\s*")))
+ {
+ info.encoding=(*it).replace(QRegExp("^\\s*Content-Transfer-Encoding\\s*:\\s*"),"");
+
+ if(info.encoding.right(2)=="\\n")
+ info.encoding.remove(info.encoding.length()-2,2);
+
+ info.encoding=info.encoding.simplifyWhiteSpace();
+ }
+ else
+ {
+ QString line=(*it);
+
+ if(line.right(2)=="\\n")
+ line.remove(line.length()-2,2);
+
+ line=line.simplifyWhiteSpace();
+ if(!info.others.isEmpty())
+ info.others+='\n';
+
+ info.others+=line;
+ }
+
+
+ }
+
+ info.headerComment=headerItem.comment();
+
+ return info;
+}
+
+bool Catalog::isUndoAvailable()
+{
+ return !d->_undoList.isEmpty();
+}
+
+bool Catalog::isRedoAvailable()
+{
+ return !d->_redoList.isEmpty();
+}
+
+int Catalog::undo()
+{
+ if(!isUndoAvailable())
+ return -1;
+
+ int macroLevel = 0;
+
+ EditCommand *command=0;
+ do
+ {
+ command = d->_undoList.take();
+ if ( !command )
+ {
+ kdError() << "undo command is NULL?" << endl;
+ return -1;
+ }
+
+ processCommand( command, 0, true );
+
+ macroLevel += command->terminator();
+
+ if ( d->_undoList.isEmpty() )
+ {
+ emit signalUndoAvailable( false );
+ }
+ if(d->_redoList.isEmpty())
+ {
+ emit signalRedoAvailable(true);
+ }
+ d->_redoList.append(command);
+
+ }
+ while(macroLevel != 0);
+
+ return command->index();
+}
+
+int Catalog::redo()
+{
+ if(!isRedoAvailable())
+ return -1;
+
+ int macroLevel = 0;
+ EditCommand *command=0;
+
+ do
+ {
+ command = d->_redoList.take();
+ if ( !command )
+ {
+ kdError() << "undo command is NULL?" << endl;
+ return -1;
+ }
+
+ processCommand( command, 0,false );
+
+ macroLevel += command->terminator();
+ if ( d->_redoList.isEmpty() )
+ {
+ emit signalRedoAvailable( false );
+ }
+ if ( d->_undoList.isEmpty() )
+ {
+ emit signalUndoAvailable( true );
+ }
+
+ d->_undoList.append( command );
+ }
+ while (macroLevel != 0);
+
+ return command->index();
+}
+
+void Catalog::applyEditCommand(EditCommand* cmd, CatalogView* view)
+{
+
+ processCommand(cmd,view);
+ setModified(true);
+
+ if ( d->_undoList.isEmpty() )
+ {
+ emit signalUndoAvailable(true);
+ }
+ else if ( cmd->merge( d->_undoList.last() ) )
+ {
+ delete cmd;
+ return;
+ }
+
+
+ d->_undoList.append(cmd);
+
+
+ if ( !d->_redoList.isEmpty() )
+ {
+ d->_redoList.clear();
+ emit signalRedoAvailable( false );
+ }
+
+}
+
+void Catalog::applyBeginCommand(uint index, Part part, CatalogView* view)
+{
+ applyEditCommand( new BeginCommand(index,part), view );
+}
+
+void Catalog::applyEndCommand(uint index, Part part, CatalogView* view)
+{
+ applyEditCommand( new EndCommand(index,part), view );
+}
+
+void Catalog::processCommand(EditCommand* cmd,CatalogView* view, bool undo)
+{
+ kdDebug(KBABEL) << "Catalog::processCommand()" << endl;
+ if(cmd->terminator()==0)
+ {
+ bool checkUntranslated=false;
+ bool checkFuzzy=false;
+ bool wasFuzzy=false;
+
+ CatalogItem &item=d->_entries[cmd->index()];
+
+ if(cmd->part() == Msgstr)
+ {
+ if( item.isUntranslated() )
+ {
+ d->_untransIndex.remove(cmd->index());
+
+ emit signalNumberOfUntranslatedChanged(numberOfUntranslated());
+ }
+ else
+ {
+ checkUntranslated=true;
+ }
+ }
+ else if(cmd->part() == Comment)
+ {
+ checkFuzzy=true;
+ wasFuzzy=item.isFuzzy();
+ }
+
+
+
+ item.processCommand(cmd,undo);
+
+ if(undo)
+ {
+ EditCommand* tmpCmd=0;
+ DelTextCmd* delcmd = (DelTextCmd*) cmd;
+ if (delcmd->type() == EditCommand::Delete )
+ {
+ tmpCmd = new InsTextCmd(delcmd->offset,delcmd->str,delcmd->pluralNumber);
+ }
+ else
+ {
+ tmpCmd = new DelTextCmd(delcmd->offset,delcmd->str,delcmd->pluralNumber);
+ }
+
+ tmpCmd->setIndex(cmd->index());
+ tmpCmd->setPart(cmd->part());
+
+ updateViews(tmpCmd,view);
+
+ delete tmpCmd;
+ }
+ else
+ {
+ updateViews(cmd,view);
+ }
+
+ if(checkUntranslated && item.isUntranslated())
+ {
+ QValueList<uint>::Iterator it;
+
+ // insert index in the right place in the list
+ it = d->_untransIndex.begin();
+ while(it != d->_untransIndex.end() && cmd->index() > (int)(*it))
+ {
+ ++it;
+ }
+ d->_untransIndex.insert( it,(uint)(cmd->index()) );
+
+ emit signalNumberOfUntranslatedChanged(numberOfUntranslated());
+ }
+ else if(checkFuzzy)
+ {
+ if(wasFuzzy != item.isFuzzy())
+ {
+ if(wasFuzzy)
+ {
+ d->_fuzzyIndex.remove(cmd->index());
+ emit signalNumberOfFuzziesChanged(numberOfFuzzies());
+ }
+ else
+ {
+ QValueList<uint>::Iterator it;
+
+ // insert index in the right place in the list
+ it = d->_fuzzyIndex.begin();
+ while(it != d->_fuzzyIndex.end() && cmd->index() > (int)(*it))
+ {
+ ++it;
+ }
+ d->_fuzzyIndex.insert( it,(uint)(cmd->index()) );
+
+ emit signalNumberOfFuzziesChanged(numberOfFuzzies());
+ }
+ }
+ }
+
+ }
+}
+
+bool Catalog::findNext(const FindOptions* findOpts, DocPosition& docPos, int& len)
+{
+ bool success = false; // true, when string found
+ bool endReached=false;
+
+ kdDebug(KBABEL) << "findNext active" << endl;
+ d->_active=true;
+ d->_stop=false;
+ connect( this, SIGNAL( signalStopActivity() ), this, SLOT( stopInternal() ));
+
+ MiscSettings miscOptions = miscSettings();
+
+ len=0;
+ int pos=0;
+
+ QString searchStr = findOpts->findStr;
+ QRegExp regexp(searchStr);
+
+ if( findOpts->isRegExp ) {
+ regexp.setCaseSensitive(findOpts->caseSensitive);
+ }
+
+ if( docPos.item == numberOfEntries()-1) {
+ switch(docPos.part) {
+ case Msgid:
+ // FIXME: we should search in plurals as well
+ if(!findOpts->inMsgstr && !findOpts->inComment
+ && docPos.offset >= msgid(docPos.item).first().length() ) {
+ endReached=true;
+ }
+ break;
+ case Msgstr:
+ if(!findOpts->inComment && (int)(docPos.form+1) >= numberOfPluralForms(docPos.item)
+ && docPos.offset >= msgstr(docPos.item).last().length() ) {
+ endReached=true;
+ }
+ break;
+ case Comment:
+ if(docPos.offset >= comment(docPos.item).length() ) {
+ endReached=true;
+ }
+ break;
+ case UndefPart:
+ break;
+ }
+ }
+
+ while(!success) {
+ int accelMarkerPos = -1;
+ int contextInfoLength = 0;
+ int contextInfoPos = -1;
+ QString targetStr;
+
+ kapp->processEvents(10);
+
+ if( d->_stop || endReached)
+ {
+ kdDebug(KBABEL) << "FindNext: endReached or stopped" << endl;
+ disconnect( this, SIGNAL( signalStopActivity() ), this, SLOT( stopInternal() ));
+ kdDebug(KBABEL) << "findNext not active" << endl;
+ d->_active=false;
+ d->_stop=false;
+ return false;
+ }
+
+ switch(docPos.part) {
+ case Msgid:
+ // FIXME: should care about plural forms in msgid
+ targetStr = msgid(docPos.item).first();
+ break;
+ case Msgstr:
+ targetStr = *(msgstr(docPos.item).at(docPos.form));
+ break;
+ case Comment:
+ targetStr = comment(docPos.item);
+ break;
+ case UndefPart:
+ break;
+ }
+
+ if(findOpts->ignoreContextInfo)
+ {
+ contextInfoPos = miscOptions.contextInfo.search(targetStr);
+ contextInfoLength = miscOptions.contextInfo.matchedLength();
+ if(contextInfoPos >= 0)
+ {
+ targetStr.remove(contextInfoPos,contextInfoLength);
+
+ if(docPos.offset > (uint)contextInfoPos)
+ docPos.offset -= contextInfoLength;
+ }
+ }
+
+ if(findOpts->ignoreAccelMarker
+ && targetStr.contains(miscOptions.accelMarker))
+ {
+ accelMarkerPos = targetStr.find(miscOptions.accelMarker);
+ targetStr.remove(accelMarkerPos,1);
+
+ if(docPos.offset > (uint)accelMarkerPos)
+ docPos.offset--;
+ }
+
+ if( findOpts->isRegExp ) {
+ if ((pos=regexp.search(targetStr,docPos.offset)) >= 0 ) {
+ len = regexp.matchedLength();
+ if(findOpts->wholeWords) {
+ QString pre=targetStr.mid(pos-1,1);
+ QString post=targetStr.mid(pos+len,1);
+ if(!pre.contains(QRegExp("[a-zA-Z0-9]")) && !post.contains(QRegExp("[a-zA-Z0-9]")) ){
+ success=true;
+ docPos.offset=pos;
+ }
+ }
+ else {
+ success=true;
+ docPos.offset=pos;
+ }
+ }
+ }
+ else {
+ if( (pos=targetStr.find(searchStr,docPos.offset,findOpts->caseSensitive)) >= 0 ) {
+ len=searchStr.length();
+
+ if(findOpts->wholeWords) {
+ QString pre=targetStr.mid(pos-1,1);
+ QString post=targetStr.mid(pos+len,1);
+ if(!pre.contains(QRegExp("[a-zA-Z0-9]")) && !post.contains(QRegExp("[a-zA-Z0-9]")) ){
+ success=true;
+ docPos.offset=pos;
+ }
+ }
+ else {
+ success=true;
+ docPos.offset=pos;
+ }
+ }
+ }
+
+
+ if(!success) {
+ docPos.offset=0;
+ switch(docPos.part) {
+ case Msgid:
+ {
+ if(findOpts->inMsgstr) {
+ docPos.part = Msgstr;
+ docPos.form = 0;
+ }
+ else if(findOpts->inComment) {
+ docPos.part = Comment;
+ }
+ else
+ {
+ if(docPos.item >= numberOfEntries()-1)
+ {
+ endReached=true;
+ }
+ else
+ {
+ docPos.item++;
+ docPos.form = 0;
+ }
+ }
+ break;
+ }
+ case Msgstr:
+ if( (int)docPos.form < numberOfPluralForms(docPos.item)-1 && pluralForm(docPos.item)==Gettext) {
+ docPos.form++;
+ }
+ else
+ if(findOpts->inComment) {
+ docPos.part = Comment;
+ }
+ else if(findOpts->inMsgid) {
+ if(docPos.item >= numberOfEntries()-1)
+ {
+ endReached=true;
+ }
+ else
+ {
+ docPos.part = Msgid;
+ docPos.item++;
+ }
+ }
+ else {
+ if(docPos.item >= numberOfEntries()-1)
+ {
+ endReached=true;
+ }
+ else
+ {
+ docPos.item++;
+ docPos.form = 0;
+ }
+ }
+ break;
+ case Comment:
+ if(findOpts->inMsgid) {
+ if(docPos.item >= numberOfEntries()-1)
+ {
+ endReached=true;
+ }
+ else
+ {
+ docPos.part = Msgid;
+ docPos.item++;
+ docPos.form = 0;
+ }
+ }
+ else if(findOpts->inMsgstr){
+ if(docPos.item >= numberOfEntries()-1)
+ {
+ endReached=true;
+ }
+ else
+ {
+ docPos.part = Msgstr;
+ docPos.form = 0;
+ docPos.item++;
+ }
+ }
+ else {
+ if(docPos.item >= numberOfEntries()-1)
+ {
+ endReached=true;
+ }
+ else
+ {
+ docPos.item++;
+ docPos.form = 0;
+ }
+ }
+ break;
+ case UndefPart:
+ break;
+ }
+ }
+ else
+ {
+ if(accelMarkerPos >= 0)
+ {
+ if(docPos.offset >= (uint)accelMarkerPos)
+ {
+ docPos.offset++;
+ }
+ else if(docPos.offset+len > (uint)accelMarkerPos)
+ {
+ len++;
+ }
+ }
+
+ if(contextInfoPos >= 0)
+ {
+ if(docPos.offset >= (uint)contextInfoPos)
+ {
+ docPos.offset+=contextInfoLength;
+ }
+ else if(docPos.offset+len > (uint)contextInfoPos)
+ {
+ len+=contextInfoLength;
+ }
+
+ }
+ }
+ }
+
+ disconnect( this, SIGNAL( signalStopActivity() ), this, SLOT( stopInternal() ));
+ kdDebug(KBABEL) << "findNext not active" << endl;
+ d->_active=false;
+ d->_stop=false;
+
+ return true;
+}
+
+bool Catalog::findPrev(const FindOptions* findOpts, DocPosition& docPos, int& len)
+{
+ bool success = false; // true, when found
+ bool beginReached = false;
+
+ kdDebug(KBABEL) << "findPrev active" << endl;
+ d->_active=true;
+ d->_stop=false;
+ connect( this, SIGNAL( signalStopActivity() ), this, SLOT( stopInternal() ));
+
+ MiscSettings miscOptions = miscSettings();
+
+ len=0;
+ int pos=0;
+
+ QString searchStr = findOpts->findStr;
+ QRegExp regexp(searchStr);
+
+ if( findOpts->isRegExp ) {
+ regexp.setCaseSensitive(findOpts->caseSensitive);
+ }
+ while(!success) {
+ int accelMarkerPos = -1;
+ int contextInfoLength = 0;
+ int contextInfoPos = -1;
+ QString targetStr;
+
+ kapp->processEvents(10);
+
+ if( d->_stop || beginReached)
+ {
+ kdDebug(KBABEL) << "FindNext: endReached or stopped" << endl;
+ disconnect( this, SIGNAL( signalStopActivity() ), this, SLOT( stopInternal() ));
+ kdDebug(KBABEL) << "findPrev active" << endl;
+ d->_active=false;
+ d->_stop=false;
+ return false;
+ }
+
+ switch(docPos.part) {
+ case Msgid:
+ // FIXME: should care about plural forms in msgid
+ targetStr = msgid(docPos.item).first();
+ break;
+ case Msgstr:
+ targetStr = *(msgstr(docPos.item).at(docPos.form));
+ break;
+ case Comment:
+ targetStr = comment(docPos.item);
+ break;
+ case UndefPart:
+ break;
+ }
+
+ if(findOpts->ignoreContextInfo)
+ {
+ contextInfoPos = miscOptions.contextInfo.search(targetStr);
+ contextInfoLength = miscOptions.contextInfo.matchedLength();
+ if(contextInfoPos >= 0)
+ {
+ targetStr.remove(contextInfoPos,contextInfoLength);
+
+ if(docPos.offset > (uint)contextInfoPos)
+ docPos.offset -= contextInfoLength;
+ }
+ }
+
+ if(findOpts->ignoreAccelMarker
+ && targetStr.contains(miscOptions.accelMarker))
+ {
+ accelMarkerPos = targetStr.find(miscOptions.accelMarker);
+ targetStr.remove(accelMarkerPos,1);
+
+ if(docPos.offset > (uint)accelMarkerPos)
+ docPos.offset--;
+ }
+
+ if(docPos.offset <= 0) {
+ success=false;
+ }
+ else if( findOpts->isRegExp ) {
+ /*
+ don't work!?
+ if((pos=targetStr.findRev(regexp,docPos.offset)) >= 0 ) {
+ regexp.match(targetStr,pos,&len); // to get the length of the string
+ */
+ bool found=false;
+ int tmpPos=docPos.offset;
+ while(!found && tmpPos>=0)
+ {
+ if( (pos=regexp.search(targetStr,tmpPos)) >= 0 && (uint)pos < docPos.offset)
+ found=true;
+ else
+ tmpPos--;
+ len = regexp.matchedLength();
+ }
+ if(found) {
+ if(findOpts->wholeWords) {
+ QString pre=targetStr.mid(pos-1,1);
+ QString post=targetStr.mid(pos+len,1);
+ if(!pre.contains(QRegExp("[a-zA-Z0-9]")) && !post.contains(QRegExp("[a-zA-Z0-9]")) ){
+ success=true;
+ docPos.offset=pos;
+ }
+ }
+ else {
+ success=true;
+ docPos.offset=pos;
+ }
+ }
+ }
+ else if( (pos=targetStr.findRev(searchStr,docPos.offset-1,findOpts->caseSensitive)) >= 0
+ && (uint)pos < docPos.offset) {
+ len=searchStr.length();
+ if(findOpts->wholeWords) {
+ QString pre=targetStr.mid(pos-1,1);
+ QString post=targetStr.mid(pos+len,1);
+ if(!pre.contains(QRegExp("[a-zA-Z0-9]")) && !post.contains(QRegExp("[a-zA-Z0-9]")) ){
+ success=true;
+ docPos.offset=pos;
+ }
+ }
+ else {
+ success=true;
+ docPos.offset=pos;
+ }
+ }
+
+ if(!success) {
+ switch(docPos.part) {
+ case Comment:
+ {
+ if(findOpts->inMsgstr) {
+ docPos.part = Msgstr;
+ docPos.form = msgstr(docPos.item).count()-1;
+ docPos.offset = msgstr(docPos.item).last().length();
+ }
+ else if(findOpts->inMsgid) {
+ docPos.part = Msgid;
+ // FIXME: should care about plural forms in msgid
+ docPos.offset = msgid(docPos.item).first().length();
+ }
+ else
+ {
+ if(docPos.item <= 0)
+ {
+ beginReached=true;
+ }
+ else
+ {
+ docPos.item--;
+ docPos.offset = comment(docPos.item).length();
+ }
+ }
+ break;
+ }
+ case Msgstr:
+ if(docPos.form != 0 ) {
+ docPos.form--;
+ docPos.offset = (*msgstr(docPos.item).at(docPos.form)).length();
+ }
+ else if(findOpts->inMsgid) {
+ docPos.part = Msgid;
+ // FIXME: should care about plural forms in msgid
+ docPos.offset = msgid(docPos.item).first().length();
+ }
+ else if(findOpts->inComment) {
+ if(docPos.item <= 0)
+ {
+ beginReached=true;
+ }
+ else
+ {
+ docPos.part = Comment;
+ docPos.item--;
+ docPos.offset = comment(docPos.item).length();
+ }
+ }
+ else {
+ if(docPos.item <= 0)
+ {
+ beginReached=true;
+ }
+ else
+ {
+ docPos.item--;
+ docPos.offset = msgstr(docPos.item).last().length();
+ docPos.form = msgstr(docPos.item).count()-1;
+ }
+ }
+ break;
+ case Msgid:
+ if(findOpts->inComment) {
+ if(docPos.item <= 0 )
+ {
+ beginReached=true;
+ }
+ else
+ {
+ docPos.part = Comment;
+ docPos.item--;
+ docPos.offset = comment(docPos.item).length();
+ }
+ }
+ else if(findOpts->inMsgstr){
+ if(docPos.item <= 0)
+ {
+ beginReached=true;
+ }
+ else
+ {
+ docPos.part = Msgstr;
+ docPos.item--;
+ docPos.offset = msgstr(docPos.item).last().length();
+ docPos.form = msgstr(docPos.item).count()-1;
+ }
+ }
+ else {
+ if(docPos.item <= 0)
+ {
+ beginReached=true;
+ }
+ else
+ {
+ docPos.item--;
+ // FIXME: should care about plural forms in msgid
+ docPos.offset = msgid(docPos.item).first().length();
+ }
+ }
+ break;
+ case UndefPart:
+ break;
+ }
+ }
+ else
+ {
+ if(accelMarkerPos >= 0)
+ {
+ if(docPos.offset >= (uint)accelMarkerPos)
+ {
+ docPos.offset++;
+ }
+ else if(docPos.offset+len > (uint)accelMarkerPos)
+ {
+ len++;
+ }
+ }
+
+ if(contextInfoPos >= 0)
+ {
+ if(docPos.offset >= (uint)contextInfoPos)
+ {
+ docPos.offset+=contextInfoLength;
+ }
+ else if(docPos.offset+len > (uint)contextInfoPos)
+ {
+ len+=contextInfoLength;
+ }
+
+ }
+ }
+ }
+
+ disconnect( this, SIGNAL( signalStopActivity() ), this, SLOT( stopInternal() ));
+ kdDebug(KBABEL) << "findPrev active" << endl;
+ d->_active=false;
+ d->_stop=false;
+
+ return true;
+}
+
+
+Catalog::DiffResult Catalog::diff(uint entry, QString *result)
+{
+ if(!result)
+ {
+ kdWarning() << "0 pointer for result" << endl;
+ return DiffNotFound;
+ }
+
+ if( d->msgidDiffList.isEmpty() )
+ {
+ return DiffNeedList;
+ }
+
+ // first look if the diff for this entry is in the cache
+ QString *s = d->diffCache[entry];
+ if(s)
+ {
+ if(s->isEmpty())
+ return DiffNotFound;
+
+
+ *result = *s;
+ return DiffOk;
+ }
+
+ // then look if the same msgid is contained in the diff file
+ // FIXME: should care about plural forms in msgid
+ QString id = msgid(entry).first();
+ id.replace( "\n","");
+ if(d->msgidDiffList.contains(id))
+ {
+ // FIXME:: should care about plural forms in msgid
+ *result = msgid(entry).first();
+
+ return DiffOk;
+ }
+
+ connect( this, SIGNAL( signalStopActivity() ), this, SLOT( stopInternal() ));
+ kdDebug(KBABEL) << "diffv active" << endl;
+ d->_active=true;
+ d->_stop=false;
+
+ QString idForDiff;
+
+
+ // then look if there are entries with the same translation
+ kdWarning() << "Diff feature (2) does not work with plural forms" << endl;
+ QString str = msgstr(entry).first();
+ str.replace("\n","");
+ if(d->msgstr2MsgidDiffList.contains(str))
+ {
+ QStringList list = d->msgstr2MsgidDiffList[str];
+
+ if(list.count() == 1)
+ {
+ idForDiff = list.first();
+ }
+ else
+ {
+ // find the best matching id
+ double bestWeight = 0.6;
+ QString bestId;
+
+ QStringList::ConstIterator it;
+ for(it = list.begin(); it != list.end(); ++it)
+ {
+ double weight = LevenshteinDistance()(id, (*it));
+ if(weight > bestWeight)
+ {
+ bestWeight = weight;
+ bestId = (*it);
+ }
+ }
+
+ if( !bestId.isEmpty() )
+ {
+ idForDiff = bestId;
+ }
+ }
+ }
+ else
+ {
+ emit signalResetProgressBar(i18n("searching matching message")
+ ,100);
+
+ // find the best matching id
+ double bestWeight = 0.6;
+ QString bestId;
+
+ int counter=0;
+ int oldPercent=0;
+ int max = QMAX( d->msgidDiffList.count()-1, 1);
+
+ QStringList::ConstIterator it;
+ for(it = d->msgidDiffList.begin();
+ it != d->msgidDiffList.end(); ++it)
+ {
+ counter++;
+ int percent = 100*counter/max;
+ if(percent > oldPercent)
+ {
+ oldPercent = percent;
+ emit signalProgress(percent);
+ }
+
+ double weight = LevenshteinDistance()( id, (*it) );
+ if(weight > bestWeight)
+ {
+ bestWeight = weight;
+ bestId = (*it);
+ }
+
+ kapp->processEvents(10);
+
+ if( d->_stop )
+ {
+ disconnect( this, SIGNAL( signalStopActivity() ), this, SLOT( stopInternal() ));
+ kdDebug
+
+ (KBABEL) << "diffv not active" << endl;
+ d->_active=false;
+ d->_stop=false;
+ return DiffNotFound;
+ }
+ }
+
+ if( !bestId.isEmpty() )
+ {
+ idForDiff = bestId;
+ }
+
+ emit signalClearProgressBar();
+
+ }
+
+ if( idForDiff.isEmpty() )
+ {
+ s = new QString(*result);
+ if( !d->diffCache.insert(entry,s) )
+ delete s;
+
+ kdDebug (KBABEL) << "diffv not active" << endl;
+ d->_active=false;
+ d->_stop=false;
+ return DiffNotFound;
+ }
+
+ QString r = wordDiff(idForDiff,id);
+
+ //esp for plural forms
+ *result = r.replace("\\n<KBABELADD>" + QString(QChar(0x00B6)) + "</KBABELADD>", "\\n\n");
+
+ s = new QString(*result);
+ if( !d->diffCache.insert(entry,s) )
+ delete s;
+
+ disconnect( this, SIGNAL( signalStopActivity() ), this, SLOT( stopInternal() ));
+ kdDebug(KBABEL) << "diffv not active" << endl;
+ d->_active=false;
+ d->_stop=false;
+
+ return DiffOk;
+}
+
+void Catalog::setDiffList( const QValueList<DiffEntry>& list)
+{
+ connect( this, SIGNAL( signalStopActivity() ), this, SLOT( stopInternal() ));
+ kdDebug(KBABEL) << "setDiffList active" << endl;
+ d->_active=true;
+ d->_stop=false;
+
+ emit signalResetProgressBar(i18n("preparing messages for diff"),100);
+
+ d->msgidDiffList.clear();
+ d->msgstr2MsgidDiffList.clear();
+ d->diffCache.clear();
+
+ uint max = QMAX(list.count()-1,1);
+ int oldPercent=0;
+ uint counter=0;
+ QValueList<DiffEntry>::ConstIterator it;
+ for(it = list.begin(); it != list.end(); ++it)
+ {
+ int percent = (100*counter)/max;
+ counter++;
+ if(percent > oldPercent)
+ {
+ oldPercent = percent;
+ emit signalProgress(percent);
+ kapp->processEvents(10);
+ }
+
+ QString id = (*it).msgid;
+ id.replace("\n","");
+ QString str = (*it).msgstr;
+ str.replace("\n","");
+ d->msgidDiffList.append(id);
+
+ if(!str.isEmpty())
+ {
+ if(d->msgstr2MsgidDiffList.contains(str))
+ {
+ QStringList sl = d->msgstr2MsgidDiffList[str];
+ sl.append(id);
+ }
+ else
+ {
+ QStringList sl;
+ sl.append(id);
+ d->msgstr2MsgidDiffList.insert(str,sl);
+ }
+ }
+ }
+
+ emit signalClearProgressBar();
+
+ disconnect( this, SIGNAL( signalStopActivity() ), this, SLOT( stopInternal() ));
+ kdDebug(KBABEL) << "setDiffList not active" << endl;
+ d->_active=false;
+ d->_stop=false;
+}
+
+QValueList<DiffEntry> Catalog::asDiffList()
+{
+ QValueList<DiffEntry> list;
+
+ for ( QValueVector<CatalogItem>::Iterator it = d->_entries.begin();
+ it != d->_entries.end(); ++it)
+ {
+ DiffEntry e;
+ e.msgid = (*it).msgid().first();
+ kdWarning() << "Diff feature does not support plural forms" << endl;
+ e.msgstr = (*it).msgstr().first();
+
+ list.append(e);
+ }
+
+ return list;
+
+}
+
+int Catalog::defaultNumberOfPluralForms() const
+{
+ return d->numberOfPluralForms;
+}
+
+void Catalog::getNumberOfPluralForms()
+{
+ IdentitySettings options = identitySettings();
+
+ if(options.numberOfPluralForms > 0)
+ {
+ d->numberOfPluralForms = options.numberOfPluralForms;
+ return;
+ }
+
+ QString lang=options.languageCode;
+ if(lang.isEmpty())
+ {
+ d->numberOfPluralForms=-1;
+ return;
+ }
+
+ d->numberOfPluralForms = getNumberOfPluralForms(lang);
+}
+
+int Catalog::getNumberOfPluralForms(const QString& lang)
+{
+ int nr=-1;
+
+ KLocale locale("kdelibs");
+ locale.setLanguage(lang);
+
+ const char* formsString =
+ "_: Dear translator, please do not translate this string in any form, but "
+ "pick the _right_ value out of NoPlural/TwoForms/French... If not sure what "
+ "to do mail thd@kde.org and coolo@kde.org, they will tell you. Better leave "
+ "that out if unsure, the programs will crash!!\n"
+ "Definition of PluralForm - to be set by the translator of kdelibs.po";
+
+ QString formsTranslation = locale.translate(formsString);
+
+ // no translation found
+ if(formsTranslation == formsString || formsTranslation.isEmpty())
+ {
+ kdDebug(KBABEL) << "no translation of PluralForms found" << endl;
+ return -1;
+ }
+ if ( formsTranslation == "NoPlural" )
+ nr = 1;
+ else if ( formsTranslation == "TwoForms" )
+ nr = 2;
+ else if ( formsTranslation == "French" )
+ nr = 2;
+ else if ( formsTranslation == "Gaeilge" || formsTranslation == "OneTwoRest" )
+ nr = 3;
+ else if ( formsTranslation == "Russian" )
+ nr = 3;
+ else if ( formsTranslation == "Polish" )
+ nr = 3;
+ else if ( formsTranslation == "Slovenian" )
+ nr = 4;
+ else if ( formsTranslation == "Lithuanian" )
+ nr = 3;
+ else if ( formsTranslation == "Czech" )
+ nr = 3;
+ else if ( formsTranslation == "Slovak" )
+ nr = 3;
+ else if ( formsTranslation == "Maltese" )
+ nr = 4;
+ else if ( formsTranslation == "Arabic" )
+ nr = 4;
+ else if ( formsTranslation == "Balcan" )
+ nr = 3;
+ else
+ {
+ kdDebug(KBABEL) << "unknown translation of PluralForms: "
+ << formsTranslation << endl;
+ nr=-1;
+ }
+
+ return nr;
+}
+
+int Catalog::numberOfPluralForms( uint index ) const
+{
+ if( index > numberOfEntries() ) return -1;
+
+ if ( d->_entries.isEmpty() )
+ return -1;
+ if( d->_entries[index].pluralForm() == NoPluralForm ) return 1;
+
+ if( d->numberOfPluralForms > 0 ) return d->numberOfPluralForms;
+
+ return 2; //default
+}
+
+bool Catalog::isModified() const
+{
+ return d->_modified;
+}
+
+void Catalog::setEntries(QValueVector<CatalogItem> entries)
+{
+ d->_entries=entries;
+
+ // update the project for entries
+ for ( QValueVector<CatalogItem>::Iterator it = d->_entries.begin();
+ it != d->_entries.end(); ++it)
+ {
+ it->setProject( d->_project );
+ }
+}
+
+void Catalog::setObsoleteEntries(QValueList<CatalogItem> entries)
+{
+ d->_obsoleteEntries=entries;
+}
+
+QValueList<CatalogItem> Catalog::obsoleteEntries() const
+{
+ return d->_obsoleteEntries;
+}
+
+void Catalog::setCatalogExtraData(const QStringList& data)
+{
+ d->_catalogExtra = data;
+}
+
+QStringList Catalog::catalogExtraData() const
+{
+ return d->_catalogExtra;
+}
+
+QString Catalog::importPluginID() const
+{
+ return d->_importID;
+}
+
+QTextCodec* Catalog::fileCodec() const
+{
+ return d->fileCodec;
+}
+
+void Catalog::setGeneratedFromDocbook(const bool generated)
+{
+ d->_generatedFromDocbook = generated;
+}
+
+void Catalog::setFileCodec( QTextCodec* codec )
+{
+ d->fileCodec = codec;
+}
+
+void Catalog::setErrorIndex( const QValueList<uint>& list )
+{
+ d->_errorIndex = list;
+}
+
+void Catalog::setImportPluginID( const QString& id )
+{
+ d->_importID = id;
+}
+
+void Catalog::stop()
+{
+ if( d->_active )
+ emit signalStopActivity();
+}
+
+void Catalog::stopInternal()
+{
+ d->_stop = true;
+}
+
+bool Catalog::isActive()
+{
+ return d->_active;
+}
+
+void Catalog::setMimeTypes( const QString& mimeTypes )
+{
+ d->_mimeTypes = mimeTypes;
+}
+
+QString Catalog::mimeTypes() const
+{
+ return d->_mimeTypes;
+}
+
+void Catalog::wordCount (uint &total, uint &fuzzy, uint &untranslated) const
+{
+ total = 0;
+ fuzzy = 0;
+ untranslated = 0;
+
+ QRegExp separator( "[ \n\t]+" );
+
+ for ( QValueVector<CatalogItem>::Iterator it = d->_entries.begin();
+ it != d->_entries.end(); ++it)
+ {
+ // find out the number of words for this message
+
+ // join all forms together
+ QString message = (*it).msgid ().join (" ");
+
+ // remove tags first
+ d->_tagExtractor->setString( message );
+ message = d->_tagExtractor->plainString(false);
+
+ QStringList words = QStringList::split ( separator, message );
+
+ total += words.count();
+
+ if ( (*it).isFuzzy() )
+ fuzzy += words.count();
+ else if ( (*it).isUntranslated() )
+ untranslated += words.count();
+ }
+}
+
+#include "catalog.moc"
+
+// kate: space-indent on; indent-width 4; replace-tabs on;
diff --git a/kbabel/common/catalog.h b/kbabel/common/catalog.h
new file mode 100644
index 00000000..db47c48b
--- /dev/null
+++ b/kbabel/common/catalog.h
@@ -0,0 +1,698 @@
+/*****************************************************************************
+ This file is part of KBabel
+
+ Copyright (C) 1999-2000 by Matthias Kiefer
+ <matthias.kiefer@gmx.de>
+ 2001-2004 by Stanislav Visnovsky
+ <visnovsky@kde.org>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the 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, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+ In addition, as a special exception, the copyright holders give
+ permission to link the code of this program with any edition of
+ the Qt library by Trolltech AS, Norway (or with modified versions
+ of Qt that use the same license as Qt), and distribute linked
+ combinations including the two. You must obey the GNU General
+ Public License in all respects for all of the code used other than
+ Qt. If you modify this file, you may extend this exception to
+ your version of the file, but you are not obligated to do so. If
+ you do not wish to do so, delete this exception statement from
+ your version.
+
+**************************************************************************** */
+#ifndef CATALOG_H
+#define CATALOG_H
+
+#include "pluralforms.h"
+#include "itempart.h"
+#include "msgfmt.h"
+#include "poinfo.h"
+#include "catalogfileplugin.h"
+#include "kbproject.h"
+
+#include <qptrlist.h>
+#include <qvaluevector.h>
+#include <kdemacros.h>
+#include <kstandarddirs.h>
+
+class KDataTool;
+class QString;
+class QTextStream;
+class KFileInfo;
+class QTextCodec;
+class QFile;
+class KDataTool;
+class KURL;
+
+namespace KBabel
+{
+
+class CatalogView;
+class EditCommand;
+class FindOptions;
+class CatalogItem;
+class IdentitySettings;
+class MiscSettings;
+class SaveSettings;
+class TagSettings;
+
+class CatalogPrivate;
+
+/**
+* This struct represents a position in a catalog.
+* A position is a tuple (index,pluralform,textoffset).
+*
+* @short Structure, that represents a position in a catalog.
+* @author Matthias Kiefer <matthias.kiefer@gmx.de>
+* @author Stanislav Visnovsky <visnovsky@kde.org>
+*/
+struct DocPosition
+{
+ DocPosition( ) : offset(0), part(UndefPart), item(0), form(0) { }
+ uint offset;
+
+ Part part;
+ uint item;
+ uint form;
+};
+
+/**
+* This struct represents an entry in diff-algorithm sresults.
+*
+* @short Structure, that represents a diff result.
+*/
+struct DiffEntry
+{
+ QString msgid;
+ QString msgstr;
+};
+
+/**
+* This class represents a catalog, saved in a po-file.
+* It has the ability to load from and save to a po-file.
+* Also it defines all necessary functions to set and get the entries
+*
+* @short Class, that represents a translation catalog(po-file)
+* @author Matthias Kiefer <matthias.kiefer@gmx.de>
+*/
+class KDE_EXPORT Catalog : public QObject
+{
+ Q_OBJECT
+
+public:
+ enum DiffResult{DiffOk, DiffNotFound, DiffNeedList};
+
+ /**
+ * reads header information from the file and searches for charset
+ * information.
+ * @param gettextHeader text containing gettext headers
+ *
+ * @return Codec for found charset or 0, if no information has been found
+ */
+ static QTextCodec* codecForFile(QString gettextHeader);
+
+ static PoInfo headerInfo(const CatalogItem headerItem);
+
+ /**
+ * A constructor for an empty message catalog.
+ * @param parent parent @ref QObject for this catalog
+ * @param name unique name for this object
+ * @param configFile configuration file to read config from
+ */
+ Catalog(QObject* parent=0, const char* name=0, QString projectFile = QString() );
+
+ /**
+ * Deprecated. A copy constructor. Do not use since each Catalog registers
+ * its views and there should be no more than one Catalog for a given file.
+ */
+ Catalog(const Catalog&);
+ virtual ~Catalog();
+
+ /**
+ * Get the message context for a given message.
+ *
+ * @param index index of the requested message
+ * @return context for the given message
+ */
+ QString msgctxt(uint index) const;
+
+ /**
+ * Get list of texts for a given message in original language. Each entry in the list
+ * represents a single singular/plural form.
+ *
+ * @param index index of the requested message
+ * @param noNewLines set true if the new lines should be eliminated in result
+ * (useful for searching etc)
+ * @return list of singular/plural forms of the original text
+ */
+ QStringList msgid(uint index, const bool noNewlines=false) const;
+
+ /**
+ * Get list of translated texts for a given message. Each entry in the list
+ * represents a single singular/plural form.
+ *
+ * @param index index of the requested message
+ * @param noNewLines set true if the new lines should be eliminated in result
+ * (useful for searching etc)
+ * @return list of translated singular/plural forms
+ */
+ QStringList msgstr(uint index, const bool noNewlines=false) const;
+
+ /**
+ * Get the comment for a given message.
+ *
+ * @param index index of the requested message
+ * @return comment for the given message
+ */
+ QString comment(uint index) const;
+
+ /**
+ * Get the context information for a given message. This works
+ * for GNU gettext PO files comments only. Finds and returns comment lines,
+ * which start with #:
+ *
+ * @param index index of the requested message
+ * @return context information found in the message comment
+ * @deprecated
+ */
+ QString context(uint index) const KDE_DEPRECATED;
+
+ /**
+ * Get the header for the current file.
+ *
+ * @return @ref CatalogItem representing the header
+ */
+ CatalogItem header() const;
+
+ /**
+ * Get the name and e-mail address of the last translator of the current file.
+ *
+ * @return string representation of the name and e-mail address
+ */
+ QString lastTranslator() const;
+
+ /**
+ * @return The list of obsolete entries. These cannot be changed at
+ * all and are stored for import/export purposes.
+ */
+ QValueList<CatalogItem> obsoleteEntries() const;
+
+ /**
+ * @return The index of the item, that has the msgid id.
+ * If no item is found, -1 is returned.
+ */
+ int indexForMsgid(const QString& id) const;
+
+ /** @return a list of tags in entry #index */
+ QStringList tagList(uint index);
+
+ /** @return a list of arguments in entry #index */
+ QStringList argList(uint index);
+
+ /**
+ * @return the list of errors found for a given item index
+ * @param index index of the item to check
+ */
+ QStringList itemStatus(uint index);
+
+ /**
+ * @return the list of errors found for a given item index
+ * @param index index of the item to check
+ * @param recheck flag, if the item status should be checked now
+ * @param whatToCheck what checks to do (a list of tools to be used
+ */
+ QStringList itemStatus(uint index, bool recheck, QPtrList<KDataTool> whatToCheck);
+
+ /**
+ * replaces msgstr in catalog item at index index with msgstr
+ * returns true, if untranslated status changed
+ */
+ //bool setMsgstr(uint index,QString msgstr);
+ /**
+ * replaces comment in catalog item at index index with comment
+ * returns true, if fuzzy status changed
+ */
+ //bool setComment(uint index,QString comment);
+ /**
+ * replaces header with given String
+ * @return false if the header is not valid
+ */
+ bool setHeader(CatalogItem header);
+
+ /** removes string ", fuzzy" from comment */
+ void removeFuzzyStatus(uint index);
+
+ /** sets or unsets fuzzy status of entry index */
+ void setFuzzy(uint index, bool on);
+
+ /**
+ * used for session managment when modified file is
+ * saved in a temp file
+ */
+ void setCurrentURL(const KURL& url);
+ /**
+ * @return URL currently represented by the catalog
+ */
+ KURL currentURL() const;
+
+ /**
+ * @return package name for the current catalog
+ */
+ QString packageName() const;
+ /**
+ * @return directory for the package of the current catalog
+ */
+ QString packageDir() const;
+ /**
+ * @return package name and directory for the current catalog
+ */
+ QString package() const;
+
+ /**
+ * Setup the package for the catalog. It tries to parse the
+ * package and split it to name and directory
+ * @param package the name and directory to be set as package
+ */
+ void setPackage(const QString& package);
+
+ /**
+ * @return encoding for the current catalog
+ */
+ QString encoding() const;
+
+ /**
+ * opens file url by using KDE's network downlad and calls
+ * openFile with a local filename
+ */
+ ConversionStatus openURL(const KURL& url, const QString& package=QString::null);
+
+ /**
+ * opens file openURL by using KDE's network downlad and calls
+ * openFile with a local filename
+ * sets current URL to saveURL
+ */
+ ConversionStatus openURL(const KURL& openURL, const KURL& saveURL, const QString& package=QString::null);
+
+ /** save the file under the old filename */
+ ConversionStatus saveFile();
+ /** saves the file under a new filename */
+ ConversionStatus saveFileAs(const KURL& url,bool overwrite=false);
+
+ /**
+ * saves the current catalog in a temporary file and
+ * returns the name and path of the file.
+ */
+ QString saveTempFile();
+
+ /**
+ * @return extra data for the catalog as set by the import filter
+ */
+ QStringList catalogExtraData() const;
+ /**
+ * @return ID string of the used import filter
+ */
+ QString importPluginID() const;
+ /**
+ * @return list of MIME types (separated by comma) this catalog
+ * can be viewed as. It is set by the used import filter.
+ */
+ QString mimeTypes() const;
+ /**
+ * @return the file codec used for the current catalog
+ */
+ QTextCodec* fileCodec() const;
+
+ /**
+ * Check syntax of the GNU gettext PO file using 'msgfmt'.
+ *
+ * @param output the result as returned by msgfmt
+ * @param clearError should the errors be cleared before running msgfmt
+ * @return the file codec used for the current catalog
+ */
+ Msgfmt::Status checkSyntax(QString& output, bool clearErrors=true);
+
+ /**
+ * checks using an external tool. The tool must provide the "validate" command
+ * with the datatype expected to be CatalogItem *. The MIME type
+ * is application/x-kbabel-catalogitem.
+ */
+ bool checkUsingTool(KDataTool* tool, bool clearErrors=true);
+
+ /**
+ * modifies catalog by applying an external tool on all items. The tool must provide the "validate" command
+ * with the datatype expected to be CatalogItem *. The MIME type
+ * is application/x-kbabel-catalogitem.
+ */
+ void modifyUsingTool(KDataTool* tool, const QString& command);
+
+ /**
+ * Returns true, if there is an ongoing activity, such as load/save
+ */
+ bool isActive();
+
+ /**
+ * Stop the current activity, for example load/save or validation
+ */
+ void stop();
+
+ /** closes the file and deletes all entries */
+ void clear();
+
+ /** @return whether the catalog has been modified since the last save */
+ bool isModified() const;
+ /** sets modified flag */
+ void setModified(bool flag);
+
+ /** @return whether the catalog is read-only */
+ bool isReadOnly() const;
+
+ /** set if file is generated from a docbook source file (with xml2pot) */
+ bool isGeneratedFromDocbook() const;
+
+ /** @return current number of entries */
+ uint numberOfEntries() const;
+ /** @return current number of fuzzies */
+ uint numberOfFuzzies() const;
+ /** @return current number of untranslated entries */
+ uint numberOfUntranslated() const;
+
+ /** returns the number of words total, in fuzzy and in untranslated messages */
+ void wordCount (uint &total, uint &fuzzy, uint &untranslated) const;
+
+ bool hasFuzzyInFront(uint index) const;
+ bool hasFuzzyAfterwards(uint index) const;
+ bool hasUntranslatedInFront(uint index) const;
+ bool hasUntranslatedAfterwards(uint index) const;
+ bool hasErrorInFront(uint index) const;
+ bool hasErrorAfterwards(uint index) const;
+ bool isFuzzy(uint index) const;
+ bool isUntranslated(uint index) const;
+ /** @return whether the entry has an error
+ * @param index index of the queried entry
+ * @param pos position of the error (currently only form is filled)
+ */
+ bool hasError(uint index, DocPosition& pos) const;
+ /** @return type of plural forms for the given entry
+ * @param index index of the queried entry
+ */
+ PluralFormType pluralForm(uint index) const;
+
+ /** @return type of plural forms this file uses.
+ */
+ PluralFormType pluralFormType() const;
+
+ /** @return number of the plural forms for a given entry
+ * @param index index of the queried entry
+ */
+ int numberOfPluralForms(uint index) const;
+
+ /**
+ * returns the expected number of plural forms
+ */
+ int defaultNumberOfPluralForms() const;
+
+ /**
+ * returns index of next fuzzy entry behind startIndex
+ * -1 if there is no entry behind. Further, it fills the
+ * pos parameter with correct index and sets the form to 0.
+ */
+ int nextFuzzy(uint startIndex, DocPosition &pos) const;
+ /**
+ * returns index of previous fuzzy entry before startIndex
+ * -1 if there is no entry before. Further, it fills the
+ * pos parameter with correct index and sets the form to 0.
+ */
+ int prevFuzzy(uint startIndex, DocPosition &pos) const;
+ /**
+ * returns index of next untranslated entry behind startIndex
+ * -1 if there is no entry behind. Further, it fills the
+ * pos parameter with correct index and the form.
+ */
+ int nextUntranslated(uint startIndex, DocPosition &pos) const;
+ /**
+ * returns index of previous untranslated entry before startIndex
+ * -1 if there is no entry before. Further, it fills the
+ * pos parameter with correct index and the form.
+ */
+ int prevUntranslated(uint startIndex, DocPosition &pos) const;
+ /**
+ * returns index of next error entry behind startIndex
+ * -1 if there is no entry behind
+ */
+ int nextError(uint startIndex, DocPosition &pos) const;
+ /**
+ * returns index of previous error entry before startIndex
+ * -1 if there is no entry before
+ */
+ int prevError(uint startIndex, DocPosition &pos) const;
+
+ /**
+ * returns the header with Information updated, but does _not_ change
+ * the header in the catalog
+ */
+ CatalogItem updatedHeader(CatalogItem oldHeader, bool usePrefs=true) const;
+
+ /** read settings from the apps config file/project */
+ void readPreferences();
+ /** save settings to the apps config file/project */
+ void savePreferences();
+
+ void useProject(Project::Ptr project);
+ Project::Ptr project() const;
+
+ SaveSettings saveSettings() const;
+ IdentitySettings identitySettings() const;
+ MiscSettings miscSettings() const;
+ TagSettings tagSettings() const;
+
+ /**
+ * reads the header from QTextstream and puts it in header
+ * I made it static to be able to use this function for
+ * the search in po-files. This way, I can easily find the first
+ * catalog entry in the textstream
+ */
+// static ConversionStatus readHeader(QTextStream& stream,CatalogItem& header);
+
+
+ void registerView(CatalogView* view);
+ void removeView(CatalogView* view);
+ bool hasView() const;
+ bool isLastView() const;
+
+ bool isUndoAvailable();
+ bool isRedoAvailable();
+ /**
+ * undo the last edit command
+ * @return the index of the item, which was modified or -1, if no undo available
+ */
+ int undo();
+ /**
+ * redo the last undo command
+ * @return the index of the item, which was modified or -1, if no redo available
+ */
+ int redo();
+
+ /**
+ * finds next occurence of searchstring using opts, starting at pos.
+ * @param pos starting position and if successful contains position
+ * of found string.
+ * @param len contains len of found string
+ * @ return true, if a string was found. false, if end was reached
+ */
+ bool findNext(const FindOptions* opts, DocPosition& pos, int& len);
+ /**
+ * finds previous occurence of searchstring using opts, starting at pos.
+ * @param pos starting position and if successful contains position
+ * of found string.
+ * @param len contains len of found string
+ * @ return true, if a string was found. false, if begin was reached
+ */
+ bool findPrev(const FindOptions* opts, DocPosition& pos, int& len);
+
+ /**
+ * Remove the index from the error list
+ * @param index index to be removed
+ */
+ void removeFromErrorList(uint index);
+
+ /**
+ * tries to find a corresponding entry for entry entry
+ * from the list of old messages and calculates the diff for it
+ */
+ DiffResult diff(uint entry, QString* result);
+
+ /**
+ * sets a list of entries to generate a diff from
+ */
+ void setDiffList( const QValueList<DiffEntry>& );
+
+ /**
+ * @return the contents of this catalog as list for diffs
+ */
+ QValueList<DiffEntry> asDiffList();
+
+ /**
+ * @return how many plural forms are used in language lang.
+ * If nothing is found -1 is returned.
+ */
+ static int getNumberOfPluralForms(const QString& lang);
+
+public slots:
+ /**
+ * Update the save setting using this one.
+ * @param settings the new settings.
+ */
+ void setSettings(KBabel::SaveSettings settings);
+ /**
+ * Update the identity setting using this one.
+ * @param settings the new settings.
+ */
+ void setSettings(KBabel::IdentitySettings settings);
+ /**
+ * Update the miscelanous setting using this one.
+ * @param settings the new settings.
+ */
+ void setSettings(KBabel::MiscSettings settings);
+ /**
+ * Update the tag setting using this one.
+ * @param settings the new settings.
+ */
+ void setSettings(KBabel::TagSettings settings);
+
+ /**
+ * Apply the given edit command.
+ *
+ * @param cmd the command to be applied
+ * @param souce the view which applies the command
+ */
+ void applyEditCommand(EditCommand* cmd,CatalogView* source);
+ /**
+ * Convenience method. Apply a begin edit command for a given message and catalog
+ * source.
+ *
+ * @param index index of to be changed message
+ * @param part part (msgid,msgstr,comment) of to be changed message
+ * @param source the view which applies the command
+ */
+ void applyBeginCommand(uint index, Part part, CatalogView* source);
+ /**
+ * Convenience method. Apply an end edit command for a given message and catalog
+ * source.
+ *
+ * @param index index of to be changed message
+ * @param part part (msgid,msgstr,comment) of to be changed message
+ * @param source the view which applies the command
+ */
+ void applyEndCommand(uint index, Part part, CatalogView* source);
+
+private slots:
+ /** slot used for internal long-term activity */
+ void stopInternal();
+
+private:
+ /** calls @ref CatalogView::update(EditCommand*) */
+ void updateViews(EditCommand* cmd,CatalogView* view2exclude=0);
+
+ /**
+ * takes over changes, but does not change undo/redo list
+ */
+ void processCommand(EditCommand* cmd, CatalogView* view2exclude=0, bool undo=false);
+
+ /** do the actual file write using plugin */
+ ConversionStatus writeFile(QString localfile, bool overwrite=false);
+
+ /**
+ * generates lists that contain indexes of all fuzzy and untranslated entries
+ */
+ void generateIndexLists();
+
+ /**
+ * returns value in list that is lower than parameter index
+ * or -1 if there is none
+ */
+ int findPrevInList(const QValueList<uint>& list,uint index) const;
+ /**
+ * returns value in list that is bigger than parameter index
+ * or -1 if there is none
+ */
+ int findNextInList(const QValueList<uint>& list,uint index) const;
+
+ /** returns the current date and time in the format of the users choice */
+ QString dateTime() const;
+
+ /** clear the list of all errors */
+ void clearErrorList();
+
+ /**
+ * Tries to find out how many plural forms are used in this language and
+ * sets numberOfPluralForms accordingly. If nothing is found,
+ * numberOfPLuralForms is set to -1.
+ */
+ void getNumberOfPluralForms();
+
+ // this class can fill our contents
+ friend class CatalogImportPlugin;
+
+ /** set the flag that the catalog is generated from docbook */
+ void setGeneratedFromDocbook(const bool generated);
+ /** set the entries of the catalog */
+ void setEntries( QValueVector<CatalogItem> entries);
+ /** set the obsolete entries of the catalog */
+ void setObsoleteEntries( QValueList<CatalogItem> entries);
+ /** set extra data for the catalog as defined by import plugin */
+ void setCatalogExtraData(const QStringList& data);
+ /** set file codec for the catalog */
+ void setFileCodec(QTextCodec* codec);
+ /** set the list of import errors */
+ void setErrorIndex(const QValueList<uint>&errors);
+ /** set ID of the used import plugin */
+ void setImportPluginID(const QString& id);
+ /** set the MIME types for the current catalog as defined by import plugin */
+ void setMimeTypes(const QString& mimeTypes);
+
+private:
+ CatalogPrivate* d;
+
+signals:
+ void signalError(QString);
+ void signalResetProgressBar(QString,int);
+ void signalProgress(int);
+ void signalClearProgressBar();
+
+ void signalModified(bool);
+ /** emitted when the header was changed, maybe when saving */
+ void signalHeaderChanged();
+ /** emitted when a file was opened or saved under another name */
+ void signalFileOpened(bool readOnly);
+
+ void signalNumberOfFuzziesChanged(uint number);
+ void signalNumberOfUntranslatedChanged(uint number);
+ void signalTotalNumberChanged(uint number);
+
+ void signalSettingsChanged(KBabel::SaveSettings);
+ void signalSettingsChanged(KBabel::IdentitySettings);
+ void signalSettingsChanged(KBabel::MiscSettings);
+ void signalSettingsChanged(KBabel::TagSettings);
+
+ void signalUndoAvailable(bool);
+ void signalRedoAvailable(bool);
+
+ /** internal signal sent to external part to stop current ongoing activity*/
+ void signalStopActivity();
+};
+
+}
+
+#endif //CATALOG_H
diff --git a/kbabel/common/catalog_private.h b/kbabel/common/catalog_private.h
new file mode 100644
index 00000000..645353f3
--- /dev/null
+++ b/kbabel/common/catalog_private.h
@@ -0,0 +1,147 @@
+/* ****************************************************************************
+ This file is part of KBabel
+
+ Copyright (C) 1999-2000 by Matthias Kiefer
+ <matthias.kiefer@gmx.de>
+ 2001-2004 by Stanislav Visnovsky
+ <visnovsky@kde.org>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the 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, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+ In addition, as a special exception, the copyright holders give
+ permission to link the code of this program with any edition of
+ the Qt library by Trolltech AS, Norway (or with modified versions
+ of Qt that use the same license as Qt), and distribute linked
+ combinations including the two. You must obey the GNU General
+ Public License in all respects for all of the code used other than
+ Qt. If you modify this file, you may extend this exception to
+ your version of the file, but you are not obligated to do so. If
+ you do not wish to do so, delete this exception statement from
+ your version.
+
+**************************************************************************** */
+#ifndef CATALOGPRIVATE_H
+#define CATALOGPRIVATE_H
+
+#include <qintcache.h>
+#include <qobject.h>
+#include <qptrlist.h>
+#include <qstringlist.h>
+#include <qmap.h>
+#include <qvaluevector.h>
+#include <kurl.h>
+
+#include "msgfmt.h"
+#include "catalogsettings.h"
+#include "catalogitem.h"
+#include "regexpextractor.h"
+
+class QString;
+class QTextStream;
+class KFileInfo;
+class QTextCodec;
+class QFile;
+class FindOptions;
+class KConfig;
+
+namespace KBabel
+{
+
+class CatalogPrivate
+{
+
+public:
+
+ /** url of the po-file, that belongs to this catalog */
+ KURL _url;
+ QString _packageName;
+ QString _packageDir;
+
+ /** holds the entries in the catalog */
+ QValueVector<CatalogItem> _entries;
+ /** The header of the po-file. */
+ CatalogItem _header;
+
+ /** list of obsolete entries */
+ QValueList<CatalogItem> _obsoleteEntries;
+
+ /** identification string for used import filter*/
+ QString _importID;
+ QString _mimeTypes;
+
+ bool _modified;
+ bool _readOnly;
+ bool _generatedFromDocbook;
+ bool _active;
+ bool _stop;
+
+ QValueList<uint> _fuzzyIndex;
+ QValueList<uint> _untransIndex;
+ QValueList<uint> _errorIndex;
+
+ QPtrList<CatalogView> _views;
+
+ TagSettings _tagSettings;
+
+ QPtrList<EditCommand> _undoList;
+ QPtrList<EditCommand> _redoList;
+
+ QTextCodec *fileCodec;
+
+ QStringList msgidDiffList;
+ QMap< QString, QStringList > msgstr2MsgidDiffList;
+ QIntCache<QString> diffCache;
+
+ int numberOfPluralForms;
+
+ Project::Ptr _project;
+ RegExpExtractor *_tagExtractor, *_argExtractor;
+
+ QStringList _catalogExtra;
+
+ CatalogPrivate(Project::Ptr project) :
+ _packageName( QString::null ), _packageDir( QString::null ),
+ _header (project),
+ _importID( QString::null ), _mimeTypes( "text/plain" ),
+ _modified(false), _readOnly(false), _generatedFromDocbook(false),
+ _active(false), _stop(false),
+ fileCodec(0), diffCache(30,76), numberOfPluralForms(-1),
+ _project(project)
+ {
+ _entries.clear();
+ _obsoleteEntries.clear();
+ diffCache.setAutoDelete(true);
+ diffCache.clear();
+
+ _views.setAutoDelete(false);
+
+ _undoList.setAutoDelete(true);
+ _redoList.setAutoDelete(true);
+ _tagExtractor = new RegExpExtractor(QStringList());
+ _argExtractor = new RegExpExtractor(QStringList());
+
+ _catalogExtra.clear();
+ }
+
+ ~CatalogPrivate()
+ {
+ delete _tagExtractor;
+ delete _argExtractor;
+ }
+};
+
+}
+
+#endif //CATALOGPRIVATE_H
diff --git a/kbabel/common/catalogfileplugin.h b/kbabel/common/catalogfileplugin.h
new file mode 100644
index 00000000..f47e0d89
--- /dev/null
+++ b/kbabel/common/catalogfileplugin.h
@@ -0,0 +1,205 @@
+/* ****************************************************************************
+ This file is part of KBabel
+
+ Copyright (C) 2002-2003 by Stanislav Visnovsky
+ <visnovsky@kde.org>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the 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, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+ In addition, as a special exception, the copyright holders give
+ permission to link the code of this program with any edition of
+ the Qt library by Trolltech AS, Norway (or with modified versions
+ of Qt that use the same license as Qt), and distribute linked
+ combinations including the two. You must obey the GNU General
+ Public License in all respects for all of the code used other than
+ Qt. If you modify this file, you may extend this exception to
+ your version of the file, but you are not obligated to do so. If
+ you do not wish to do so, delete this exception statement from
+ your version.
+**************************************************************************** */
+#ifndef IMPORTPLUGIN_H
+#define IMPORTPLUGIN_H
+
+#include <qobject.h>
+
+#include <kdemacros.h>
+
+class QString;
+
+namespace KBabel
+{
+
+class Catalog;
+class CatalogItem;
+class CatalogImportPluginPrivate;
+class CatalogExportPluginPrivate;
+
+// ### KDE4: force OK=0
+/**
+ * Result of the conversion
+ */
+enum ConversionStatus {
+ OK,
+ NOT_IMPLEMENTED,
+ NO_FILE,
+ NO_PERMISSIONS,
+ PARSE_ERROR,
+ RECOVERED_PARSE_ERROR,
+ OS_ERROR,
+ NO_PLUGIN,
+ UNSUPPORTED_TYPE,
+ HEADER_ERROR, ///< Old name for a recovered error in header @deprecated
+ RECOVERED_HEADER_ERROR = HEADER_ERROR, ///< Header error that could be recovered @since 1.11.2 (KDE 3.5.2)
+ STOPPED,
+ BUSY,
+ NO_ENTRY_ERROR ///< The loaded catalog has not any entry! @since 1.11.2 (KDE 3.5.2)
+};
+
+/**
+* This class is the base for import plugins for catalogs.
+* It provides "transactional behavior", so the changes are stored in
+* catalog only if the import process finishes successfully.
+*
+* To use it, just subclass and redefine load() and id() methods.
+* When importing, you can use the protected methods for setting
+* the catalog. New catalog items can be added using appendCatalogItem.
+*
+* @short Base class for Catalog import plugins
+* @author Stanislav Visnovsky <visnovsky@kde.org>
+*/
+class KDE_EXPORT CatalogImportPlugin: public QObject
+{
+ Q_OBJECT
+
+public:
+ CatalogImportPlugin(QObject* parent, const char* name);
+ virtual ~CatalogImportPlugin();
+
+ /**
+ * Load the file and fill the corresponding catalog. The file
+ * is considered to be of @ref mimetype MIME type.
+ *
+ * @param file local file name to be opened
+ * @param mimetype the MIME type is should be handled as
+ * @param catalog the catalog to be filled
+ * @return result of the operation
+ */
+ ConversionStatus open(const QString& file, const QString& mimetype, Catalog* catalog);
+
+ /**
+ * Reimplement this method to load the local file passed as an argument.
+ * Throughout the run, you can use the protected methods for setting
+ * the contents of the resulting catalog.
+ * This method must call \see setMimeTypes to setup correct MIME types
+ * for the loaded file. Also, it should use \see isStopped to
+ * abort loading and the signals for providing user feedback.
+ * @param file file to be loaded
+ * @param mimetype the expected MIME type (the type used for plugin selection
+ */
+ virtual ConversionStatus load(const QString& file, const QString& mimetype) = 0;
+ /**
+ * Reimplement this method to return unique identification of your plugin
+ */
+ virtual const QString id() = 0;
+
+ /** @return the list of all available MIME types for which there
+ * is a import plugin.
+ */
+ static QStringList availableImportMimeTypes();
+
+public slots:
+ /** stop the current operation */
+ void stop();
+
+protected:
+ /** Append a new catalog item, either as normal or as an obsolete one
+ * @param item the new item
+ * @param obsolete flag that the item is obsolete
+ */
+ void appendCatalogItem( const CatalogItem& item, const bool obsolete = false );
+
+ /** set flag that the file is generated from DocBook */
+ void setGeneratedFromDocbook(const bool fromDocbook);
+ /** set the list of parse error indexes */
+ void setErrorIndex(const QValueList<uint>& errors);
+ /** set the file codec */
+ void setFileCodec(QTextCodec* codec);
+
+ /** set extra data for the catalog, which can't be stored in
+ * @ref CatalogItem. The format can be arbitrary */
+ void setCatalogExtraData( const QStringList& data );
+ /** set the header catalog item */
+ void setHeader( const CatalogItem& header );
+ /** set the MIME types which can be used for this catalog */
+ void setMimeTypes( const QString& catalog );
+
+ /** start a new transaction. You should never call this method. */
+ void startTransaction();
+ /** commit the data in the current transaction. You should never call this method. */
+ void commitTransaction();
+
+ /** Flag, whether the operation should be stopped immediately.*/
+ bool isStopped() const;
+
+signals:
+ /** Signal start of the operation */
+ void signalResetProgressBar(QString,int);
+ /** Signal progress of the operation */
+ void signalProgress(int);
+ /** Signal end of the operation */
+ void signalClearProgressBar();
+
+private:
+ CatalogImportPluginPrivate* d;
+};
+
+
+/**
+* This class is the base for export plugins for catalogs.
+*
+* To use it, just subclass and redefine the save() method.
+*
+* @short Base class for Catalog export plugins
+* @author Stanislav Visnovsky <visnovsky@kde.org>
+*/
+class KDE_EXPORT CatalogExportPlugin: public QObject
+{
+ Q_OBJECT
+
+public:
+ CatalogExportPlugin(QObject* parent, const char* name);
+ virtual ~CatalogExportPlugin();
+ virtual ConversionStatus save(const QString& file, const QString& mimetype, const Catalog* catalog) = 0;
+
+ static QStringList availableExportMimeTypes();
+
+public slots:
+ void stop();
+
+protected:
+ bool isStopped() const;
+
+signals:
+ void signalResetProgressBar(QString,int);
+ void signalProgress(int);
+ void signalClearProgressBar();
+
+private:
+ CatalogExportPluginPrivate* d;
+};
+
+}
+
+#endif
diff --git a/kbabel/common/catalogitem.cpp b/kbabel/common/catalogitem.cpp
new file mode 100644
index 00000000..ced02e8c
--- /dev/null
+++ b/kbabel/common/catalogitem.cpp
@@ -0,0 +1,521 @@
+/* ****************************************************************************
+ This file is part of KBabel
+
+ Copyright (C) 1999-2000 by Matthias Kiefer <matthias.kiefer@gmx.de>
+ 2002 by Stanislav Visnovsky <visnovsky@nenya.ms.mff.cuni.cz>
+ Copyright (C) 2006 by Nicolas GOUTTE <goutte@kde.org>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the 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, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+ In addition, as a special exception, the copyright holders give
+ permission to link the code of this program with any edition of
+ the Qt library by Trolltech AS, Norway (or with modified versions
+ of Qt that use the same license as Qt), and distribute linked
+ combinations including the two. You must obey the GNU General
+ Public License in all respects for all of the code used other than
+ Qt. If you modify this file, you may extend this exception to
+ your version of the file, but you are not obligated to do so. If
+ you do not wish to do so, delete this exception statement from
+ your version.
+
+**************************************************************************** */
+#include "catalogitem.h"
+#include "catalogitem_private.h"
+#include "editcmd.h"
+#include "resources.h"
+#include "libgettext/pofiles.h"
+#include "libgettext/tokens.h"
+
+#include "regexpextractor.h"
+
+#include <qtextstream.h>
+#include <qtextcodec.h>
+#include <qdom.h>
+
+using namespace KBabel;
+
+CatalogItem::CatalogItem(Project::Ptr project)
+{
+ d=0;
+ clear();
+ d->_project = project;
+}
+
+CatalogItem::CatalogItem(const CatalogItem& item)
+{
+ d=0;
+ clear();
+ *d=*(item.d);
+}
+
+CatalogItem::~CatalogItem()
+{
+ delete d;
+}
+
+QString CatalogItem::comment() const
+{
+ return d->_comment;
+}
+
+QString CatalogItem::msgctxt(const bool noNewlines) const
+{
+ if( noNewlines )
+ {
+ QString tmp = d->_msgctxt;
+ tmp.replace("\n", " "); // ### TODO: " " or "" ?
+ return tmp;
+ }
+ else
+ return d->_msgctxt;
+}
+
+QStringList CatalogItem::msgid(const bool noNewlines) const
+{
+ QStringList result=d->_msgid;
+ if( noNewlines )
+ {
+ result.gres( "\n", "" );
+ }
+ return result;
+}
+
+QStringList CatalogItem::msgstr(const bool noNewlines) const
+{
+ QStringList result=d->_msgstr;
+ if( noNewlines )
+ {
+ result.gres( "\n", "" );
+ }
+ return result;
+}
+
+QStringList CatalogItem::msgstrAsList(int nr) const
+{
+ QString str;
+ if(d->_gettextPluralForm && nr > 0)
+ {
+ QStringList::ConstIterator it = d->_msgstr.at(nr);
+ if(it != d->_msgstr.end())
+ {
+ str = *it;
+ }
+ else
+ {
+ kdDebug(KBABEL) << "request for non existing plural form "
+ << nr << endl;
+ }
+ }
+ else
+ {
+ str = d->_msgstr.first();
+ }
+
+ QStringList list=QStringList::split("\n",str);
+
+ if(str.left(1)=="\n")
+ list.prepend("");
+
+ if(list.isEmpty())
+ list.append("");
+
+ return list;
+}
+
+bool CatalogItem::isValid() const
+{
+ return d->_valid;
+}
+
+void CatalogItem::setMsgctxt(QString msg)
+{
+ d->_msgctxt=msg;
+}
+
+void CatalogItem::setMsgid(QString msg)
+{
+ d->_msgid=msg;
+}
+
+void CatalogItem::setMsgid(QStringList msg)
+{
+ d->_msgid=msg;
+}
+
+void CatalogItem::setMsgstr(QString msg)
+{
+ d->_msgstr=msg;
+}
+
+void CatalogItem::setMsgstr(QStringList msg)
+{
+ d->_msgstr=msg;
+}
+
+void CatalogItem::setComment(QString com)
+{
+ d->_comment=com;
+}
+
+void CatalogItem::setGettextPluralForm( bool _gettextPlural )
+{
+ d->_gettextPluralForm = _gettextPlural;
+}
+
+QStringList CatalogItem::errors() const
+{
+ return d->_errors;
+}
+
+QStringList CatalogItem::tagList( RegExpExtractor& te)
+{
+ if(!d->_haveTagList)
+ {
+ // FIXME: should care about plural forms in msgid
+ te.setString(msgid(true).first());
+ d->_tagList = QStringList(te.matches());
+ d->_haveTagList = true;
+ }
+
+ return d->_tagList;
+}
+
+QStringList CatalogItem::argList( RegExpExtractor& te)
+{
+ if(!d->_haveArgList)
+ {
+ // FIXME: should care about plural forms in msgid
+ te.setString(msgid(true).first());
+ d->_argList = QStringList(te.matches());
+ }
+
+ return d->_argList;
+}
+
+
+bool CatalogItem::isFuzzy() const
+{
+ return d->_comment.find( QRegExp(",\\s*fuzzy") ) != -1;
+}
+
+bool CatalogItem::isCformat() const
+{
+ // Allow "possible-c-format" (from xgettext --debug) or "c-format"
+ // Note the regexp (?: ) is similar to () but it does not capture (so it is faster)
+ return d->_comment.find( QRegExp(",\\s*(?:possible-)c-format") ) == -1;
+}
+
+bool CatalogItem::isNoCformat() const
+{
+ return d->_comment.find( QRegExp(",\\s*no-c-format") ) == -1;
+}
+
+bool CatalogItem::isQtformat() const
+{
+ return d->_comment.find( QRegExp(",\\s*qt-format") ) == -1;
+}
+
+bool CatalogItem::isNoQtformat() const
+{
+ return d->_comment.find( QRegExp(",\\s*no-qt-format") ) == -1;
+}
+
+bool CatalogItem::isUntranslated() const
+{
+ return d->_msgstr.first().isEmpty();
+}
+
+PluralFormType CatalogItem::pluralForm() const
+{
+ if( d->_gettextPluralForm )
+ return Gettext;
+ if( d->_msgid.first().startsWith( "_n: " ) )
+ return KDESpecific;
+ else
+ return NoPluralForm;
+}
+
+int CatalogItem::totalLines() const
+{
+ int lines=0;
+ if(!d->_comment.isEmpty())
+ {
+ lines = d->_comment.contains('\n')+1;
+ }
+ int msgctxtLines=0;
+ if(!d->_msgctxt.isEmpty())
+ {
+ msgctxtLines=d->_msgctxt.contains('\n')+1;
+ }
+ int msgidLines=0;
+ QStringList::ConstIterator it;
+ for(it=d->_msgid.begin(); it != d->_msgid.end(); ++it)
+ {
+ msgidLines += (*it).contains('\n')+1;
+ }
+ int msgstrLines=0;
+ for(it=d->_msgstr.begin(); it != d->_msgstr.end(); ++it)
+ {
+ msgstrLines += (*it).contains('\n')+1;
+ }
+
+ if(msgctxtLines>1)
+ msgctxtLines++;
+ if(msgidLines>1)
+ msgidLines++;
+ if(msgstrLines>1)
+ msgstrLines++;
+
+ lines+=( msgctxtLines+msgidLines+msgstrLines );
+
+ return lines;
+}
+
+
+void CatalogItem::setSyntaxError(bool on)
+{
+ if(on && !d->_errors.contains("syntax error"))
+ d->_errors.append("syntax error");
+ else
+ d->_errors.remove("syntax error");
+}
+
+QPtrList<EditCommand> CatalogItem::removeFuzzy(bool doIt)
+{
+ QPtrList<EditCommand> editList;
+ editList.setAutoDelete(false);
+
+ QString comment=d->_comment;
+
+ if(isFuzzy())
+ {
+ EditCommand *cmd;
+ QRegExp fuzzyStr(",\\s*fuzzy");
+
+ int offset;
+ offset=comment.find(fuzzyStr);
+ while(offset>=0)
+ {
+ cmd = new DelTextCmd(offset,fuzzyStr.cap(),0);
+ cmd->setPart(Comment);
+ editList.append(cmd);
+
+ comment.remove(offset,fuzzyStr.cap().length());
+
+ offset=comment.find(fuzzyStr,offset+1);
+ }
+
+ // remove empty comment lines
+ if( comment.contains( QRegExp("^#\\s*$") ))
+ {
+ cmd = new DelTextCmd(0,comment,0);
+ cmd->setPart(Comment);
+ editList.append(cmd);
+
+ comment="";
+ }
+ if( comment.contains( QRegExp("\n#\\s*$") ))
+ {
+ offset=comment.find( QRegExp("\n#\\s*$") );
+ while(offset>=0)
+ {
+ cmd = new DelTextCmd(offset,comment.mid(offset),0);
+ cmd->setPart(Comment);
+ editList.append(cmd);
+
+ comment.remove(offset,comment.length()-offset);
+
+ offset=comment.find( QRegExp("\n#\\s*$"), offset+1 );
+ }
+ }
+ if( comment.contains( QRegExp("\n#\\s*\n") ))
+ {
+ offset=comment.find( QRegExp("\n#\\s*\n") )+1;
+ while(offset>=0)
+ {
+ int endIndex=comment.find("\n",offset)+1;
+
+ cmd = new DelTextCmd(offset,comment.mid(offset,endIndex-offset),0);
+ cmd->setPart(Comment);
+ editList.append(cmd);
+
+ comment.remove(offset,endIndex-offset);
+
+ offset=comment.find( QRegExp("\n#\\s*\n"), offset+1 );
+ }
+ }
+
+ if(doIt)
+ d->_comment=comment;
+
+ }
+
+ return editList;
+}
+
+
+
+QPtrList<EditCommand> CatalogItem::addFuzzy(bool doIt)
+{
+ QPtrList<EditCommand> editList;
+ editList.setAutoDelete(false);
+
+
+ if(!isFuzzy())
+ {
+ EditCommand *cmd;
+ int offset=d->_comment.length();
+
+ QString addStr;
+ if(offset > 0 && d->_comment[offset-1] != '\n')
+ {
+ addStr='\n';
+ }
+ addStr+="#, fuzzy";
+
+ cmd = new InsTextCmd(offset,addStr,0);
+ cmd->setPart(Comment);
+ editList.append(cmd);
+
+
+ if(doIt)
+ d->_comment+=addStr;
+ }
+
+ return editList;
+}
+
+
+void CatalogItem::processCommand(EditCommand* cmd, bool undo)
+{
+ kdDebug(KBABEL) << "CatalogItem::processCommand" << endl;
+ if(cmd->terminator()!=0)
+ return;
+
+ DelTextCmd* delcmd = (DelTextCmd*) cmd;
+
+ bool ins = true;
+ if (delcmd->type() == EditCommand::Delete )
+ ins = undo;
+ else if (delcmd->type() == EditCommand::Insert )
+ ins = !undo;
+ else
+ {
+ kdDebug(KBABEL) << "what kind of edit command is this?" << endl;
+ return;
+ }
+
+ if ( ins )
+ {
+ if(delcmd->part()==Msgstr)
+ {
+ if(delcmd->pluralNumber >= (int)d->_msgstr.count() )
+ {
+ for( uint i = d->_msgstr.count() ; i < (uint)(delcmd->pluralNumber+1) ; i++ )
+ d->_msgstr.append( "" );
+ }
+
+ (*(d->_msgstr).at(delcmd->pluralNumber)).insert(delcmd->offset,delcmd->str);
+ }
+ else if(delcmd->part()==Comment)
+ {
+ d->_comment.insert(delcmd->offset,delcmd->str);
+ }
+ }
+ else
+ { // del
+ if(delcmd->part()==Msgstr)
+ {
+ if(delcmd->pluralNumber >= (int)d->_msgstr.count() )
+ {
+ for( uint i = d->_msgstr.count() ; i < (uint)(delcmd->pluralNumber+1) ; i++ )
+ d->_msgstr.append( "" );
+ }
+
+ (*(d->_msgstr).at(delcmd->pluralNumber)).remove(delcmd->offset,delcmd->str.length());
+ }
+ else if(delcmd->part()==Comment)
+ {
+ d->_comment.remove(delcmd->offset,delcmd->str.length());
+ }
+ }
+}
+
+
+void CatalogItem::clear()
+{
+ if( !d ) d = new CatalogItemPrivate();
+ else {
+ d->_msgid.clear();
+ d->_msgstr.clear();
+ d->_errors.clear();
+
+ d->_tagList.clear();
+ d->_argList.clear();
+ }
+ d->_comment="";
+ d->_msgctxt="";
+ d->_valid=true;
+ d->_gettextPluralForm=false;
+ d->_haveTagList=false;
+ d->_haveArgList=false;
+
+ d->_msgid.append("");
+ d->_msgstr.append("");
+}
+
+void CatalogItem::operator=(const CatalogItem& rhs)
+{
+ d->_comment = rhs.d->_comment;
+ d->_msgctxt = rhs.d->_msgctxt;
+ d->_msgid = rhs.d->_msgid;
+ d->_msgstr = rhs.d->_msgstr;
+ d->_valid = rhs.d->_valid;
+ d->_errors = rhs.d->_errors;
+ d->_gettextPluralForm = rhs.d->_gettextPluralForm;
+}
+
+QString CatalogItem::nextError() const
+{
+ return d->_errors.first();
+}
+
+void CatalogItem::clearErrors()
+{
+ d->_errors.clear();
+}
+
+void CatalogItem::appendError(const QString& error )
+{
+ if( !d->_errors.contains( error ) )
+ d->_errors.append(error);
+}
+
+void CatalogItem::removeError(const QString& error )
+{
+ d->_errors.remove(error);
+}
+
+Project::Ptr CatalogItem::project() const
+{
+ return d->_project;
+}
+
+void CatalogItem::setProject( Project::Ptr project )
+{
+ d->_project = project;
+}
+
+// kate: space-indent on; indent-width 4; replace-tabs on;
diff --git a/kbabel/common/catalogitem.h b/kbabel/common/catalogitem.h
new file mode 100644
index 00000000..91e6cc25
--- /dev/null
+++ b/kbabel/common/catalogitem.h
@@ -0,0 +1,220 @@
+/* ****************************************************************************
+ This file is part of KBabel
+
+ Copyright (C) 1999-2000 by Matthias Kiefer <matthias.kiefer@gmx.de>
+ 2002-2003 by Stanislav Visnovsky <visnovsky@kde.org>
+ Copyright (C) 2006 by Nicolas GOUTTE <goutte@kde.org>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the 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, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+ In addition, as a special exception, the copyright holders give
+ permission to link the code of this program with any edition of
+ the Qt library by Trolltech AS, Norway (or with modified versions
+ of Qt that use the same license as Qt), and distribute linked
+ combinations including the two. You must obey the GNU General
+ Public License in all respects for all of the code used other than
+ Qt. If you modify this file, you may extend this exception to
+ your version of the file, but you are not obligated to do so. If
+ you do not wish to do so, delete this exception statement from
+ your version.
+
+**************************************************************************** */
+#ifndef CATALOGITEM_H
+#define CATALOGITEM_H
+
+#include <qstringlist.h>
+#include <qptrlist.h>
+
+#include "pluralforms.h"
+#include "editcmd.h"
+#include "catalogfileplugin.h"
+#include "kbproject.h"
+
+class QTextStream;
+class GettextFlexLexer;
+
+namespace KBabel
+{
+
+class RegExpExtractor;
+class CatalogItemPrivate;
+
+/**
+* This class represents an entry in a catalog.
+* It contains the comment, the Msgid and the Msgstr.
+* It defines some functions to query the state of the entry
+* (fuzzy, untranslated, cformat).
+*
+* @short Class, representing an entry in a catalog
+* @author Matthias Kiefer <matthias.kiefer@gmx.de>
+*/
+class KDE_EXPORT CatalogItem
+{
+
+public:
+ /** Constructor for empty item*/
+ CatalogItem(Project::Ptr project = 0);
+ /** Copy constructor */
+ CatalogItem(const CatalogItem&);
+ /** Destructor */
+ ~CatalogItem();
+
+ /**
+ * returns true, if the translation is fuzzy, this means
+ * if the string ", fuzzy" is contained in the comment
+ */
+ bool isFuzzy() const;
+
+ /**
+ * returns true, if the translation in c-format, this means
+ * if the string ", c-format" is contained in the comment
+ * @since 1.11.2 (KDE 3.5.2) not only "c-format" is supported but also
+ * "possible-c-format" (from the debug parameter of xgettext)
+ */
+ bool isCformat() const;
+
+ /**
+ * returns true, if the string ", no-c-format" is contained in the comment
+ */
+ bool isNoCformat() const;
+
+ /**
+ * returns true, if the translation in qt-format, this means
+ * if the string ", qt-format" is contained in the comment
+ * @since 1.11.2 (KDE 3.5.2)
+ */
+ bool isQtformat() const;
+
+ /**
+ * returns true,
+ * if the string ", no-qt-format" is contained in the comment
+ * @since 1.11.2 (KDE 3.5.2)
+ */
+ bool isNoQtformat() const;
+
+ /**
+ * returns true, if the Msgid is untranslated, this means the
+ * Msgstr is empty
+ */
+ bool isUntranslated() const;
+
+ /**
+ * @return type of the plural form, is any
+ */
+ PluralFormType pluralForm() const;
+
+ bool isValid() const;
+
+ void setSyntaxError(bool);
+
+ /** returns the number of lines, the entry will need in a file */
+ int totalLines() const;
+
+ /**
+ * removes the string ", fuzzy" from the comment
+ * @param doIt if false, the comment is not changed, just the
+ * commands for doing it are calculated
+ */
+ QPtrList<EditCommand> removeFuzzy(bool doIt=true);
+
+ /**
+ * adds the string ", fuzzy" to the comment
+ * @param doIt if false, the comment is not changed, just the
+ * commands for doing it are calculated
+ */
+ QPtrList<EditCommand> addFuzzy(bool doIt=true);
+
+
+ /** cleares the item */
+ void clear();
+
+
+ /** returns the comment of this entry */
+ QString comment() const;
+ /** returns the msgctxt of this entry */
+ QString msgctxt(const bool noNewlines = false) const;
+ /** returns the msgid of the entry */
+ QStringList msgid(const bool noNewlines = false) const;
+ /** returns the msgstr of the entry */
+ QStringList msgstr(const bool noNewlines = false) const;
+
+ /**
+ * @param pluralNr If this item is a gettext plural form item,
+ * it returns the plural form number pluralNr, else always the msgstr
+ * is returned
+ * @return the msgstr as list
+ */
+ QStringList msgstrAsList(int pluralNr=0) const;
+
+ void setComment(QString com);
+ void setMsgctxt(QString msg);
+ void setMsgid(QString msg);
+ void setMsgid(QStringList msg);
+ void setMsgstr(QString msg);
+ void setMsgstr(QStringList msg);
+
+ void setGettextPluralForm( bool _gettextPlurals );
+
+ void processCommand(EditCommand* cmd, bool undo=false);
+
+ Project::Ptr project() const;
+
+
+ /** @return a list of tags in the msgid */
+ QStringList tagList( RegExpExtractor& tagExtractor );
+
+ /** @return a list of args in the msgid */
+ QStringList argList( RegExpExtractor& argExtractor);
+
+ /**
+ * @return the list of all errors of this item
+ */
+ QStringList errors() const;
+
+ QString nextError() const;
+ void clearErrors();
+ void removeError(const QString& error);
+ void appendError(const QString& error);
+
+ /**
+ * makes some sanity checks and set status accordingly
+ * @return the new status of this item
+ * @see CatalogItem::Error
+ * @param accelMarker a char, that marks the keyboard accelerators
+ * @param contextInfo a regular expression, that determines what is
+ * the context information
+ * @param singularPlural a regular expression, that determines what is
+ * string with singular and plural form
+ * @param neededLines how many lines a string with singular-plural form
+ * must have
+ */
+ int checkErrors(QChar accelMarker, const QRegExp& contextInfo
+ , const QRegExp& singularPlural, const int neededLines);
+
+
+ void operator=(const CatalogItem& rhs);
+
+private:
+ void setProject( Project::Ptr project );
+
+ friend class Catalog;
+
+private:
+ CatalogItemPrivate* d;
+};
+
+}
+
+#endif // CATALOGITEM_H
diff --git a/kbabel/common/catalogitem_private.h b/kbabel/common/catalogitem_private.h
new file mode 100644
index 00000000..15c81fc7
--- /dev/null
+++ b/kbabel/common/catalogitem_private.h
@@ -0,0 +1,90 @@
+/* ****************************************************************************
+ This file is part of KBabel
+
+ Copyright (C) 1999-2000 by Matthias Kiefer
+ <matthias.kiefer@gmx.de>
+ 2002 by Stanislav Visnovsky <visnovsky@kde.org>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the 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, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+ In addition, as a special exception, the copyright holders give
+ permission to link the code of this program with any edition of
+ the Qt library by Trolltech AS, Norway (or with modified versions
+ of Qt that use the same license as Qt), and distribute linked
+ combinations including the two. You must obey the GNU General
+ Public License in all respects for all of the code used other than
+ Qt. If you modify this file, you may extend this exception to
+ your version of the file, but you are not obligated to do so. If
+ you do not wish to do so, delete this exception statement from
+ your version.
+
+**************************************************************************** */
+#ifndef CATALOGITEMPRIVATE_H
+#define CATALOGITEMPRIVATE_H
+
+#include <qstringlist.h>
+
+namespace KBabel
+{
+
+/**
+* This class represents data for an entry in a catalog.
+* It contains the comment, the Msgid and the Msgstr.
+* It defines some functions to query the state of the entry
+* (fuzzy, untranslated, cformat).
+*
+* @short Class, representing an entry in a catalog
+* @author Matthias Kiefer <matthias.kiefer@gmx.de>
+* @author Stanislav Visnovsky <visnovsky@kde.org>
+*/
+
+class CatalogItemPrivate
+{
+
+public:
+
+ QString _comment;
+ QString _msgctxt;
+ QStringList _msgid;
+ QStringList _msgstr;
+
+ QStringList _tagList;
+ QStringList _argList;
+
+ bool _valid;
+ bool _haveTagList;
+ bool _haveArgList;
+ QStringList _errors;
+
+ /** flag, if this entry is a plural forms entry */
+ bool _gettextPluralForm;
+
+ friend class CatalogItem;
+
+ KBabel::Project::Ptr _project;
+
+ CatalogItemPrivate()
+ {
+ _comment = "";
+ _valid=false;
+ _haveTagList=false;
+ _haveArgList=false;
+ _gettextPluralForm=false;
+ }
+};
+
+}
+
+#endif // CATALOGITEMPRIVATE_H
diff --git a/kbabel/common/catalogsettings.cpp b/kbabel/common/catalogsettings.cpp
new file mode 100644
index 00000000..480f4cb9
--- /dev/null
+++ b/kbabel/common/catalogsettings.cpp
@@ -0,0 +1,258 @@
+/* ****************************************************************************
+ This file is part of KBabel
+
+ Copyright (C) 1999-2000 by Matthias Kiefer
+ <matthias.kiefer@gmx.de>
+ 2004 by Stanislav Visnovsky
+ <visnovsky@kde.org>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the 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, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+ In addition, as a special exception, the copyright holders give
+ permission to link the code of this program with any edition of
+ the Qt library by Trolltech AS, Norway (or with modified versions
+ of Qt that use the same license as Qt), and distribute linked
+ combinations including the two. You must obey the GNU General
+ Public License in all respects for all of the code used other than
+ Qt. If you modify this file, you may extend this exception to
+ your version of the file, but you are not obligated to do so. If
+ you do not wish to do so, delete this exception statement from
+ your version.
+**************************************************************************** */
+#include "catalogsettings.h"
+#include "kbprojectsettings.h"
+#include <kconfig.h>
+#include <kdebug.h>
+#include <kemailsettings.h>
+#include <kglobal.h>
+#include <klocale.h>
+#include <kprocess.h>
+#include <ktempfile.h>
+
+#include <stdlib.h>
+
+#include <qfile.h>
+#include <qtextcodec.h>
+#include <qregexp.h>
+
+#include <stdlib.h>
+
+using namespace KBabel;
+
+QString KBabel::charsetString(const QTextCodec *codec)
+{
+ if(codec)
+ {
+ QString encodingStr = codec->mimeName();
+ if ( encodingStr.startsWith("CP " ) )
+ encodingStr.remove( 2, 1 );
+ else if ( encodingStr.startsWith("IBM " ) )
+ encodingStr.replace( "IBM ", "CP" );
+ return encodingStr;
+ }
+ else
+ return QString::null;
+}
+
+QString KBabel::GNUPluralForms(const QString& lang)
+{
+ KTempFile infile, outfile;
+
+ QTextStream* str = infile.textStream();
+
+ *str << "# SOME DESCRIPTIVE TITLE." << endl;
+ *str << "# Copyright (C) YEAR Free Software Foundation, Inc." << endl;
+ *str << "# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR." << endl;
+ *str << "#" << endl;
+ *str << "#, fuzzy" << endl;
+ *str << "msgid \"\"" << endl;
+ *str << "msgstr \"\"" << endl;
+ *str << "\"Project-Id-Version: PACKAGE VERSION\\n\"" << endl;
+ *str << "\"POT-Creation-Date: 2002-06-25 03:23+0200\\n\"" << endl;
+ *str << "\"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\\n\"" << endl;
+ *str << "\"Last-Translator: FULL NAME <EMAIL@ADDRESS>\\n\"" << endl;
+ *str << "\"Language-Team: LANGUAGE <LL@li.org>\\n\"" << endl;
+ *str << "\"MIME-Version: 1.0\\n\"" << endl;
+ *str << "\"Content-Type: text/plain; charset=CHARSET\\n\"" << endl;
+ *str << "\"Content-Transfer-Encoding: ENCODING\\n\"" << endl;
+
+ infile.close();
+
+ KProcess msginit;
+
+ msginit << "msginit";
+ msginit
+ << "-l"
+ << lang
+ << "-i"
+ << infile.name()
+ << "-o"
+ << outfile.name()
+ << "--no-translator"
+ << "--no-wrap" ;
+
+ msginit.start( KProcess::Block );
+
+ QString res("");
+
+ if( msginit.normalExit() )
+ {
+ // parse out the plural form string
+ QFile f(outfile.name());
+ if( f.open (IO_ReadOnly) )
+ {
+ QTextStream str(&f);
+
+ QString line;
+ do {
+ line = str.readLine();
+
+ if( line.startsWith( "\"Plural-Forms:" ) )
+ {
+ kdDebug() << "Plural form line: " << line << endl;
+ QRegExp re( "^\"Plural-Forms: *(.*)\\\\n\"" );
+ re.search( line );
+ res = re.cap(1);
+ break;
+ }
+ } while (!str.atEnd() );
+ }
+ else
+ {
+ kdWarning() << "Cannot open the file with plural form definition" << endl;
+ }
+ }
+
+ infile.unlink();
+ outfile.unlink();
+
+ return res;
+}
+
+QString KBabel::charsetString(const int e)
+{
+ QString encodingStr;
+
+ switch(e)
+ {
+ case ProjectSettingsBase::Locale:
+ {
+ QTextCodec *codec=QTextCodec::codecForLocale();
+ if(codec)
+ encodingStr=charsetString(codec);
+ else
+ encodingStr="unknown";
+
+ break;
+ }
+ case ProjectSettingsBase::UTF8:
+ {
+ encodingStr="UTF-8";
+ break;
+ }
+ case ProjectSettingsBase::UTF16:
+ {
+ encodingStr="UTF-16";
+ break;
+ }
+ }
+
+ return encodingStr;
+}
+
+QString Defaults::Identity::authorName()
+{
+ KEMailSettings emSet;
+ return emSet.getSetting(KEMailSettings::RealName);
+}
+
+QString Defaults::Identity::authorLocalizedName()
+{
+ return authorName();
+}
+
+QString Defaults::Identity::authorEmail()
+{
+ KEMailSettings emSet;
+ return emSet.getSetting(KEMailSettings::EmailAddress);
+}
+
+QString Defaults::Identity::mailingList()
+{
+ QString lang=Defaults::Identity::languageCode();
+ int temp=lang.find("_");
+ lang=lang.left(temp);
+ return lang+"@li.org";
+}
+
+QString Defaults::Identity::languageCode()
+{
+ // first try to get the language from KDE settings
+ KLocale *locale = KGlobal::locale();
+ QString lang;
+ if(locale)
+ {
+ lang=locale->languageList().first();
+ }
+
+ if(lang.isEmpty())
+ {
+ lang=getenv("LC_ALL");
+ if(lang.isEmpty())
+ {
+ lang=getenv("LC_MESSAGES");
+ if(lang.isEmpty())
+ {
+ lang=getenv("LANG");
+ }
+ }
+ }
+
+ return lang;
+}
+
+QString Defaults::Identity::timezone()
+{
+ QString timezone=getenv("TIMEZONE");
+ if(timezone.isEmpty())
+ timezone="GMT";
+
+ return timezone;
+}
+
+QStringList Defaults::Tag::tagExpressions()
+{
+ QStringList list;
+
+ list.append("</[A-Za-z0-9\\n]+>");
+ list.append("<[A-Za-z0-9\\n]+[^>]*/?>");
+ list.append("http:\\/\\/[a-zA-Z0-9\\.\\-_/~]+");
+ list.append("mailto:[a-z0-9\\.\\-_]+@[a-z0-9\\.\\-_]+");
+ list.append("<?[a-z0-9\\.\\-_]+@[a-z0-9\\.\\-_]+>?");
+ list.append("&[a-z,A-Z,\\-,0-9,#\\.]*;");
+
+ return list;
+}
+
+QStringList Defaults::Tag::argExpressions()
+{
+ QStringList list;
+
+ list.append("%[ndioxXucsfeEgGp]");
+ list.append("%([0-9]+(\\$))?[-+'#0]?[0-9]*(.[0-9]+)?[hlL]?[dioxXucsfeEgGp]");
+ list.append("%[0-9]+");
+
+ return list;
+}
diff --git a/kbabel/common/catalogsettings.h b/kbabel/common/catalogsettings.h
new file mode 100644
index 00000000..f87ec673
--- /dev/null
+++ b/kbabel/common/catalogsettings.h
@@ -0,0 +1,176 @@
+/* ****************************************************************************
+ This file is part of KBabel
+
+ Copyright (C) 1999-2000 by Matthias Kiefer
+ <matthias.kiefer@gmx.de>
+ 2001-2004 by Stanislav Visnovsky
+ <visnovsky@kde.org>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the 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, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+ In addition, as a special exception, the copyright holders give
+ permission to link the code of this program with any edition of
+ the Qt library by Trolltech AS, Norway (or with modified versions
+ of Qt that use the same license as Qt), and distribute linked
+ combinations including the two. You must obey the GNU General
+ Public License in all respects for all of the code used other than
+ Qt. If you modify this file, you may extend this exception to
+ your version of the file, but you are not obligated to do so. If
+ you do not wish to do so, delete this exception statement from
+ your version.
+**************************************************************************** */
+#ifndef CATALOGSETTINGS_H
+#define CATALOGSETTINGS_H
+
+#include <qstring.h>
+#include <qregexp.h>
+#include <qdatetime.h>
+#include <kdemacros.h>
+
+class QTextCodec;
+class QStringList;
+
+namespace KBabel
+{
+
+struct KDE_EXPORT SaveSettings
+{
+ bool autoUpdate;
+ bool updateLastTranslator;
+ bool updateRevisionDate;
+ bool updateLanguageTeam;
+ bool updateCharset;
+ bool updateEncoding;
+
+ bool updateProject;
+ bool updateDescription;
+ QString descriptionString;
+ bool updateTranslatorCopyright;
+ int FSFCopyright;
+
+ int encoding;
+ bool useOldEncoding;
+
+ Qt::DateFormat dateFormat;
+ QString customDateFormat;
+
+ QString projectString;
+
+ bool autoSyntaxCheck;
+ bool saveObsolete;
+
+ int autoSaveDelay;
+};
+
+struct KDE_EXPORT IdentitySettings
+{
+ QString authorName;
+ QString authorLocalizedName;
+ QString authorEmail;
+ QString languageName;
+ QString languageCode;
+ QString mailingList;
+ QString timeZone;
+
+ /**
+ * The number of plural forms. If <= 0 the number is determined
+ * automatically.
+ */
+ int numberOfPluralForms;
+ /**
+ * Whether the %n argument should be always present in translation
+ */
+ bool checkPluralArgument;
+
+ QString gnuPluralFormHeader;
+};
+
+
+struct KDE_EXPORT MiscSettings
+{
+ /**
+ * The char, that marks keyboard accelerators.
+ * Default is '&' as used by Qt
+ */
+ QChar accelMarker;
+
+ /**
+ * The regular expression for what is context information.
+ * Default is "^_:.+" as used in KDE
+ */
+ QRegExp contextInfo;
+
+ /**
+ * The regular expression for strings that contain a message for
+ * singular and one for plural
+ */
+ QRegExp singularPlural;
+
+ /**
+ * The method used for compresion of email attachments. Use
+ * tar/bzip2 if true, tar/gzip if false.
+ * Default is true.
+ */
+ bool useBzip;
+
+ /**
+ * Use compression for single file attachments.
+ * Default is true.
+ */
+ bool compressSingleFile;
+};
+
+struct TagSettings
+{
+ /**
+ * A list of regular expressions defining tags
+ */
+ QStringList tagExpressions;
+ /**
+ * A list of regular expressions defining arguments
+ */
+ QStringList argExpressions;
+};
+
+KDE_EXPORT QString charsetString(const int encoding);
+KDE_EXPORT QString charsetString(const QTextCodec *codec);
+KDE_EXPORT QString GNUPluralForms(const QString& lang);
+
+namespace Defaults
+{
+ class KDE_EXPORT Identity
+ {
+ public:
+ static QString authorName();
+ static QString authorLocalizedName();
+ static QString authorEmail();
+ static QString languageCode();
+ static QString mailingList();
+ static QString timezone();
+ };
+
+ class KDE_EXPORT Tag
+ {
+ public:
+ static QStringList tagExpressions();
+ static QStringList argExpressions();
+ };
+
+}
+
+}
+
+
+#endif
diff --git a/kbabel/common/catalogview.h b/kbabel/common/catalogview.h
new file mode 100644
index 00000000..03056c43
--- /dev/null
+++ b/kbabel/common/catalogview.h
@@ -0,0 +1,64 @@
+/* ****************************************************************************
+ This file is part of KBabel
+
+ Copyright (C) 1999-2000 by Matthias Kiefer
+ <matthias.kiefer@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.
+
+ 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, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+ In addition, as a special exception, the copyright holders give
+ permission to link the code of this program with any edition of
+ the Qt library by Trolltech AS, Norway (or with modified versions
+ of Qt that use the same license as Qt), and distribute linked
+ combinations including the two. You must obey the GNU General
+ Public License in all respects for all of the code used other than
+ Qt. If you modify this file, you may extend this exception to
+ your version of the file, but you are not obligated to do so. If
+ you do not wish to do so, delete this exception statement from
+ your version.
+
+**************************************************************************** */
+#ifndef CATALOGVIEW_H
+#define CATALOGVIEW_H
+
+namespace KBabel
+{
+
+class EditCommand;
+
+/**
+ * This class represents a base class for a @ref Catalog view. It declares
+ * an abstract method @ref update to be redefined by the actual
+ * view. Using this method, the catalog the view is registered for
+ * will inform the views about changes in the catalog.
+ *
+ * @short This class represents a base class for a catalog view.
+ * @author Matthias Kiefer <matthias.kiefer@gmx.de>
+ */
+class CatalogView
+{
+public:
+ /** The only method to be redefined in inherited classes.
+ * This method is called by @ref Catalog to update the view
+ * in case there are changes.
+ * @param cmd the command line performed on the catalog
+ * @param undo this is used for undo, reverse the operation
+ */
+ virtual void update(EditCommand* cmd, bool undo=false)=0;
+};
+
+}
+
+#endif // CATALOGVIEW_H
diff --git a/kbabel/common/diff.cpp b/kbabel/common/diff.cpp
new file mode 100644
index 00000000..7a54e4d3
--- /dev/null
+++ b/kbabel/common/diff.cpp
@@ -0,0 +1,465 @@
+/* **************************************************************************
+ This file is part of KBabel
+
+ Copyright (C) 2001 by Matthias Kiefer <kiefer@kde.org>
+ charDiff algorithm by Wolfram Diestel <wolfram@steloj.de>
+ wordDiff algorithm by Nick Shaforostoff <shafff@ukr.net>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the 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, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+ In addition, as a special exception, the copyright holders give
+ permission to link the code of this program with any edition of
+ the Qt library by Trolltech AS, Norway (or with modified versions
+ of Qt that use the same license as Qt), and distribute linked
+ combinations including the two. You must obey the GNU General
+ Public License in all respects for all of the code used other than
+ Qt. If you modify this file, you may extend this exception to
+ your version of the file, but you are not obligated to do so. If
+ you do not wish to do so, delete this exception statement from
+ your version.
+
+************************************************************************** */
+
+#include "diff.h"
+
+#include <kdebug.h>
+
+
+LCSprinter::LCSprinter(const QStringList &s_1, const QStringList &s_2, QValueVector<LCSMarker> *b_, const uint nT_, uint index):s1(s_1),s2(s_2),b(b_),nT(nT_)
+{
+ it1=s1.begin();
+ it2=s2.begin();
+ printLCS(index);
+}
+
+void LCSprinter::printLCS(uint index)
+{
+ //fprintf(stderr,"%2d. %2d. %2d. %2d\n",(uint)(*b)[index],nT,index%nT, index);
+ if (index % nT == 0 || index < nT)
+ {
+ //original LCS algo doesnt have to deal with ins before first common
+ uint bound = index%nT;
+ for (index=0; index<bound; ++index)
+ {
+ resultString.append("<KBABELADD>");
+ resultString.append(*it2);
+ ++it2;
+ resultString.append("</KBABELADD>");
+ }
+
+ return;
+ }
+
+ if (ARROW_UP_LEFT == (*b)[index])
+ {
+ printLCS(index-nT-1);
+ resultString.append(*it1);
+ ++it1;
+ ++it2;
+ return;
+ }
+ else if (ARROW_UP == (*b)[index])
+ {
+ printLCS(index-nT);
+ resultString.append("<KBABELDEL>");
+ resultString.append(*it1);
+ ++it1;
+ resultString.append("</KBABELDEL>");
+ return;
+ }
+ else
+ {
+ printLCS(index-1);
+ resultString.append("<KBABELADD>");
+ resultString.append(*it2);
+ ++it2;
+ resultString.append("</KBABELADD>");
+ return;
+ }
+
+}
+
+
+
+QString wordDiff(const QString& str1, const QString& str2)
+{
+ //separate punctuation marks etc from words as _only_ they may have changed
+ QStringList s1, s2;
+
+ uint i=0;
+ uint j=0;
+ uint l1=str1.length();
+ uint l2=str2.length();
+ QString temp;
+ temp.reserve(16);
+ /*
+ while ( i<l1 )
+ {
+ if (str1[i]==QChar(0x003C) && (str1[i+1]==QChar(0x002F) || str1[i+1].isLetter()) ) // 0x003C="<", 0x002F="/"
+ {// skip tag
+ while(i<l1 && str1[i]!=QChar(0x003E)) temp += str1[i++];
+ if (i++ <l1) temp += QChar(0x003E);
+ s1.append(temp);
+ temp.truncate(0);
+ }
+
+ while ( i<l1 && str1[i].isLetter() )
+ {
+ temp += str1[i++];
+ }
+ if (!temp.isEmpty())
+ {
+ s1.append(temp);
+ temp.truncate(0);
+ };
+
+ if (str1[i]==QChar(0x003C) && (str1[i+1]==QChar(0x002F) || str1[i+1].isLetter()) ) // 0x003C="<", 0x002F="/"
+ {// skip tag
+ while(i<l1 && str1[i]!=QChar(0x003E)) temp += str1[i++];
+ if (i++ <l1) temp += QChar(0x003E);
+ s1.append(temp);
+ temp.truncate(0);
+ }
+
+ while ( i<l1 && !(str1[i].isLetter() || str1[i]==QChar(0x003C)) )
+ {
+ temp += str1[i++];
+ }
+ if (!temp.isEmpty())
+ {
+ s1.append(temp);
+ temp.truncate(0);
+ };
+ }
+
+ i=0;
+ while ( i<l2 )
+ {
+ if (str2[i]==QChar(0x003C) && (str2[i+1]==QChar(0x002F) || str2[i+1].isLetter()) ) // 0x003C="<", 0x002F="/"
+ {// skip tag
+ while(i<l2 && str2[i]!=QChar(0x003E)) temp += str2[i++];
+ if (i++ <l2) temp += QChar(0x003E);
+ s2.append(temp);
+ temp.truncate(0);
+ }
+
+ while ( i<l2 && str2[i].isLetter() )
+ {
+ temp += str2[i++];
+ }
+ if (!temp.isEmpty())
+ {
+ s2.append(temp);
+ temp.truncate(0);
+ };
+ //FIXME bounds
+ if (str2[i]==QChar(0x003C) && (str2[i+1]==QChar(0x002F) || str2[i+1].isLetter()) ) // 0x003C="<", 0x002F="/"
+ {// skip tag
+ while(i<l2 && str2[i]!=QChar(0x003E)) temp += str2[i++];
+ if (i++ <l2) temp += QChar(0x003E);
+ s2.append(temp);
+ temp.truncate(0);
+ }
+
+ while ( i<l2 && !(str2[i].isLetter() || str2[i]==QChar(0x003C)) )
+ {
+ temp += str2[i++];
+ }
+ if (!temp.isEmpty())
+ {
+ s2.append(temp);
+ temp.truncate(0);
+ };
+ }
+*/
+
+ while ( i<l1 )
+ {
+ while ( i<l1 && str1[i].isLetter() )
+ {
+ temp += str1[i++];
+ }
+ if (!temp.isEmpty())
+ {
+ s1.append(temp);
+ temp.truncate(0);
+ };
+
+ while ( i<l1 && !str1[i].isLetter() )
+ {
+ s1.append(QString(str1[i++]));
+ }
+ }
+
+ i=0;
+ while ( i<l2 )
+ {
+ while ( i<l2 && str2[i].isLetter() )
+ {
+ temp += str2[i++];
+ }
+ if (!temp.isEmpty())
+ {
+ s2.append(temp);
+ temp.truncate(0);
+ };
+
+ while ( i<l2 && !str2[i].isLetter() )
+ {
+ s2.append(QString(str2[i++]));
+ }
+ }
+
+ uint mX = s1.count();
+ uint nY = s2.count();
+
+ uint mT = mX+1;
+ uint nT = nY+1;
+
+ QValueVector<LCSMarker> b(mT*nT, NOTHING);
+ QValueVector<uint> c(mT*nT, 0);
+
+
+// calculate the LCS
+ b[0] = FINAL;
+ uint index_cache;
+ QStringList::iterator it1, it2;
+
+ for (i=1, it1 = s1.begin(); i<mT; ++i, ++it1)
+ {
+ for (j=1, it2 = s2.begin(); j<nT; ++j, ++it2)
+ {
+ index_cache = i*nT+j;
+ if ((*it1)==(*it2))
+ {
+ c[index_cache] = c[index_cache-nT-1] + 1;
+ b[index_cache] = ARROW_UP_LEFT;
+ }
+ else if (c[index_cache-nT] >= c[index_cache-1])
+ {
+ c[index_cache] = c[index_cache-nT];
+ b[index_cache] = ARROW_UP;
+ }
+ else
+ {
+ c[index_cache] = c[index_cache-1];
+ b[index_cache] = ARROW_LEFT;
+ }
+ }
+ }
+
+ c.clear();
+
+
+ LCSprinter printer(s1, s2, &b, nT, index_cache);
+
+ /*//debug
+ fprintf(stderr,"b:\n");
+ for (i=0; i<=mT; i++) {
+ for (j=0; j<nY; j++) {
+// fprintf(stderr,"[%3d]%1d.",i*nT+j,(uint) b[i*nT+j]);
+ fprintf(stderr,"%1d.",(uint) b[i*nT+j]);
+}
+ fprintf(stderr,"%1d\n",(uint) b[i*nT+j]);
+}
+ fprintf(stderr,"\n");
+
+ // print the c table
+ fprintf(stderr,"c:\n");
+ for (i=0; i<=mX; i++) {
+ for (j=0; j<nY; j++) {
+ fprintf(stderr,"%2d.",(uint) c[i*nY+j]);
+}
+ fprintf(stderr,"%2d\n",(uint) c[i*nY+j]);
+}
+ fprintf(stderr,"\n");
+ */
+
+ return printer.getString();
+}
+
+
+
+
+/*
+// old algorithm by Wolfram Diestel <wolfram@steloj.de>
+QString Diff::charDiff(QString s1, QString s2)
+{
+ int n = 3;
+ s1+="xxx";
+ s2+="xxx";
+
+ int pos1=0;
+ int pos2=0;
+ int len1 = s1.length();
+ int len2 = s2.length();
+ QString resultstr;
+ bool found = true;
+ bool swap = false;
+ while (found && pos1+n < len1 && pos2+n < len2)
+ {
+ // while strings are equal, increase positions
+ int len = 0;
+ while (pos1+len < len1 && pos2+len < len2 &&
+ (s1[pos1+len] == s2[pos2+len]))
+ {
+ len++;
+ }
+
+ // write first result
+ resultstr += s1.mid(pos1,len);
+ pos1 += len;
+ pos2 += len;
+
+ // If strings are not equal try to find equal substrings of
+ // length n. For this increase positions alternating like
+ // 0 1, 1 0, 0 2, 1 1, 2 0, 0 3, 1 2, 2 1, 3 0 etc.
+
+ int x = 1;
+ found = false;
+
+ // If one position is already at the end stop processing
+ if (pos1+n >= len1 || pos2+n >= len2)
+ {
+ break;
+ }
+
+
+ // evtl. exchange
+ if (len2 - pos2 < len1 - pos1)
+ {
+ swap=true;
+
+ int pos = pos1;
+ pos1 = pos2;
+ pos2 = pos;
+
+ QString s = s1;
+ s1 = s2;
+ s2 = s;
+
+ int len = len1;
+ len1 = len2;
+ len2 = len;
+ }
+
+ while( !found && (pos1+x < len1 || pos2+x <len2))
+ {
+ int p1;
+ int p2;
+ for(p1 = 0, p2 = x; p1 <= x; p1++, p2--)
+ {
+ if( pos1+p1+n >= len1 || pos2+p2+n >= len2)
+ break;
+
+ if(s1.mid(pos1+p1,n) == s2.mid(pos2+p2,n))
+ {
+ found = true;
+
+ // evtl. exchange back
+ if(swap)
+ {
+ int pos = pos1;
+ pos1 = pos2;
+ pos2 = pos;
+
+ QString s = s1;
+ s1 = s2;
+ s2 = s;
+
+ int len = len1;
+ len1 = len2;
+ len2 = len;
+
+ int p = p1;
+ p1 = p2;
+ p2 = p;
+
+ swap=false;
+ }
+
+
+ // write current result
+ if (p1 > 0)
+ {
+ resultstr += "<KBABELDEL>";
+ resultstr += s1.mid(pos1,p1);
+ resultstr += "</KBABELDEL>";
+ pos1 += p1;
+ }
+
+ if (p2 > 0 )
+ {
+ resultstr += "<KBABELADD>";
+ resultstr += s2.mid(pos2,p2);
+ resultstr += "</KBABELADD>";
+ pos2 += p2;
+ }
+
+ break;
+ }
+ }
+
+ x++;
+
+ }
+
+ }
+
+ bool removed=false;
+
+ // evtl. exchange back
+ if(swap)
+ {
+ int pos = pos1;
+ pos1 = pos2;
+ pos2 = pos;
+
+ QString s = s1;
+ s1 = s2;
+ s2 = s;
+
+ int len = len1;
+ len1 = len2;
+ len2 = len;
+
+ swap=false;
+ }
+
+ // if there is a rest, add it
+ if(pos1+n < len1)
+ {
+ resultstr += "<KBABELDEL>";
+ resultstr += s1.mid(pos1,len1-pos1-n);
+ resultstr += "</KBABELDEL>";
+ removed=true;
+ }
+
+ if(pos2+n < len2)
+ {
+ resultstr += "<KBABELADD>";
+ resultstr += s2.mid(pos2,len2-pos2-n);
+ resultstr += "</KBABELADD>";
+ removed=true;
+ }
+
+ if( !removed )
+ {
+ resultstr.truncate( resultstr.length()-3 );
+ }
+
+ return resultstr;
+}
+*/
diff --git a/kbabel/common/diff.h b/kbabel/common/diff.h
new file mode 100644
index 00000000..4e7dfb72
--- /dev/null
+++ b/kbabel/common/diff.h
@@ -0,0 +1,88 @@
+/* **************************************************************************
+ This file is part of KBabel
+
+ Copyright (C) 2001 by Matthias Kiefer <kiefer@kde.org>
+ charDiff algorithm by Wolfram Diestel <wolfram@steloj.de>
+ wordDiff algorithm by Nick Shaforostoff <shafff@ukr.net>
+ (based on Markus Stengel's GPL implementation of LCS-Delta algorithm as it is described in "Introduction to Algorithms", MIT Press, 2001, Second Edition, written by Thomas H. Cormen et. al. It uses dynamic programming to solve the Longest Common Subsequence (LCS) problem. - http://www.markusstengel.de/text/en/i_4_1_5_3.html)
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the 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, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+ In addition, as a special exception, the copyright holders give
+ permission to link the code of this program with any edition of
+ the Qt library by Trolltech AS, Norway (or with modified versions
+ of Qt that use the same license as Qt), and distribute linked
+ combinations including the two. You must obey the GNU General
+ Public License in all respects for all of the code used other than
+ Qt. If you modify this file, you may extend this exception to
+ your version of the file, but you are not obligated to do so. If
+ you do not wish to do so, delete this exception statement from
+ your version.
+
+************************************************************************** */
+#ifndef DIFF_H
+#define DIFF_H
+
+#include <qvaluevector.h>
+#include <qstringlist.h>
+
+typedef enum
+{
+ NOTHING = 0,
+ ARROW_UP = 1,
+ ARROW_LEFT = 2,
+ ARROW_UP_LEFT = 3,
+ FINAL = 4
+} LCSMarker;
+
+
+/**
+ * Word-by-word diff algorithm
+ *
+ * @short Word-by-word diff algorithm
+ * @author Nick Shaforostoff <shafff@ukr.net>
+ */
+ QString wordDiff(const QString& oldString, const QString& newString);
+
+
+/**
+ * This class is for keeping "global" params of recursive function
+ *
+ * @short Class for keeping "global" params of recursive function
+ * @author Nick Shaforostoff <shafff@ukr.net>
+ */
+ class LCSprinter
+{
+ public:
+ LCSprinter(const QStringList &s_1, const QStringList &s_2, QValueVector<LCSMarker>* b_, const uint nT_, uint index);
+ void printLCS(uint index);
+ inline QString getString();
+
+ ~LCSprinter() {};
+ private:
+ QStringList s1, s2, resultString;
+ uint nT;//for use 1d vector as 2d
+ QValueVector<LCSMarker> *b;
+ QStringList::iterator it1, it2;
+};
+
+
+inline QString LCSprinter::getString()
+{
+ return resultString.join("").replace(QChar('\n'), ""); //w/o replace we'd get whole line colored
+}
+
+#endif // DIFF_H
+
diff --git a/kbabel/common/editcmd.cpp b/kbabel/common/editcmd.cpp
new file mode 100644
index 00000000..1643ed0b
--- /dev/null
+++ b/kbabel/common/editcmd.cpp
@@ -0,0 +1,106 @@
+/* ****************************************************************************
+ This file is part of KBabel
+
+ Copyright (C) 1999-2000 by Matthias Kiefer
+ <matthias.kiefer@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.
+
+ 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, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+ In addition, as a special exception, the copyright holders give
+ permission to link the code of this program with any edition of
+ the Qt library by Trolltech AS, Norway (or with modified versions
+ of Qt that use the same license as Qt), and distribute linked
+ combinations including the two. You must obey the GNU General
+ Public License in all respects for all of the code used other than
+ Qt. If you modify this file, you may extend this exception to
+ your version of the file, but you are not obligated to do so. If
+ you do not wish to do so, delete this exception statement from
+ your version.
+
+**************************************************************************** */
+#include "editcmd.h"
+#include <qregexp.h>
+
+using namespace KBabel;
+
+EditCommand::EditCommand()
+ :_part(UndefPart),
+ _index(-1)
+{
+}
+
+EditCommand::EditCommand(const int index, const Part part)
+ :_part(part),
+ _index(index)
+{
+}
+
+
+ // have to handle deletion of current selection
+DelTextCmd::DelTextCmd(int _offset, const QString &_str, int _pluralNumber )
+ : EditCommand(),
+ offset( _offset ),
+ str ( _str ),
+ pluralNumber( _pluralNumber )
+{
+}
+
+bool DelTextCmd::merge( EditCommand* other)
+{
+ if(other->terminator()!=0)
+ return false;
+
+ DelTextCmd* o = (DelTextCmd*)other;
+
+ if ( o->index() == index() && o->part() == part()
+ && o->type() == type() && o->pluralNumber==pluralNumber )
+ {
+ DelTextCmd* o = (DelTextCmd*) other;
+ if ( offset + int(str.length()) == o->offset && !str.contains(QRegExp("^\\s$")) )
+ {
+ o->str.prepend( str );
+ o->offset = offset;
+ return true;
+ }
+ }
+ return false;
+}
+
+
+
+InsTextCmd::InsTextCmd(int offset,const QString &str, int pluralNumber )
+ : DelTextCmd( offset, str, pluralNumber )
+{
+}
+
+bool InsTextCmd::merge( EditCommand* other)
+{
+ if(other->terminator()!=0)
+ return false;
+
+ DelTextCmd* o = (DelTextCmd*)other;
+
+ if ( o->index()==index() && o->part() == part()
+ && o->type() == type() && o->pluralNumber==pluralNumber )
+ {
+ if ( offset == o->offset + int(o->str.length()) && !str.contains(QRegExp("^\\s$")) )
+ {
+ o->str += str;
+ return true;
+ }
+ }
+ return false;
+}
+
diff --git a/kbabel/common/editcmd.h b/kbabel/common/editcmd.h
new file mode 100644
index 00000000..458d2c57
--- /dev/null
+++ b/kbabel/common/editcmd.h
@@ -0,0 +1,112 @@
+/* ****************************************************************************
+ This file is part of KBabel
+
+ Copyright (C) 1999-2000 by Matthias Kiefer
+ <matthias.kiefer@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.
+
+ 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, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+ In addition, as a special exception, the copyright holders give
+ permission to link the code of this program with any edition of
+ the Qt library by Trolltech AS, Norway (or with modified versions
+ of Qt that use the same license as Qt), and distribute linked
+ combinations including the two. You must obey the GNU General
+ Public License in all respects for all of the code used other than
+ Qt. If you modify this file, you may extend this exception to
+ your version of the file, but you are not obligated to do so. If
+ you do not wish to do so, delete this exception statement from
+ your version.
+**************************************************************************** */
+#ifndef EDITCMD_H
+#define EDITCMD_H
+
+#include "itempart.h"
+
+#include <qstring.h>
+#include <kdemacros.h>
+
+namespace KBabel
+{
+
+class KDE_EXPORT EditCommand
+{
+public:
+ enum Commands { Invalid, Begin, End, Insert, Delete };
+
+ EditCommand();
+ EditCommand( const int index, const Part part );
+ virtual ~EditCommand() {};
+ virtual Commands type() const { return Invalid; }
+ virtual int terminator() const { return 0; }
+
+ int index() const { return _index; }
+ void setIndex( int index ) { _index=index; }
+ Part part() const { return _part; }
+ void setPart(Part part) {_part=part;}
+
+ virtual bool merge( EditCommand* ) { return false;}
+
+private:
+ Part _part;
+ int _index;
+};
+
+
+class KDE_EXPORT BeginCommand : public EditCommand
+{
+public:
+ BeginCommand( const int index, const Part part ) : EditCommand(index,part) {}
+ virtual Commands type() const { return Begin; }
+ virtual int terminator() const { return 1; }
+};
+
+
+class KDE_EXPORT EndCommand : public EditCommand
+{
+public:
+ EndCommand( const int index, const Part part ) : EditCommand(index,part) {}
+ virtual Commands type() const { return End; }
+ virtual int terminator() const { return -1; }
+};
+
+
+
+class KDE_EXPORT DelTextCmd : public EditCommand
+{
+public:
+ int offset;
+ QString str;
+ int pluralNumber;
+
+ // have to handle deletion of current selection
+ DelTextCmd(int offset, const QString &str, int pluralNumber );
+ virtual Commands type() const { return Delete; }
+
+ bool merge( EditCommand* other);
+};
+
+class KDE_EXPORT InsTextCmd : public DelTextCmd
+{
+
+public:
+ InsTextCmd(int offset,const QString &str, int pluralNumber );
+ virtual Commands type() const { return Insert; }
+
+ bool merge( EditCommand* other);
+};
+
+}
+
+#endif // SETTINGS_H
diff --git a/kbabel/common/exportplugin.cpp b/kbabel/common/exportplugin.cpp
new file mode 100644
index 00000000..99a727f8
--- /dev/null
+++ b/kbabel/common/exportplugin.cpp
@@ -0,0 +1,81 @@
+/* ****************************************************************************
+ This file is part of KBabel
+
+ Copyright (C) 2002-2003 by Stanislav Visnovsky
+ <visnovsky@kde.org>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the 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, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+ In addition, as a special exception, the copyright holders give
+ permission to link the code of this program with any edition of
+ the Qt library by Trolltech AS, Norway (or with modified versions
+ of Qt that use the same license as Qt), and distribute linked
+ combinations including the two. You must obey the GNU General
+ Public License in all respects for all of the code used other than
+ Qt. If you modify this file, you may extend this exception to
+ your version of the file, but you are not obligated to do so. If
+ you do not wish to do so, delete this exception statement from
+ your version.
+
+**************************************************************************** */
+
+#include "catalogfileplugin.h"
+
+#include <qstringlist.h>
+
+#include <kdebug.h>
+#include <ktrader.h>
+
+using namespace KBabel;
+
+struct KBabel::CatalogExportPluginPrivate
+{
+ bool _stop;
+};
+
+CatalogExportPlugin::CatalogExportPlugin(QObject* parent, const char* name) : QObject(parent,name)
+{
+ d = new CatalogExportPluginPrivate;
+ d->_stop=false;
+}
+
+CatalogExportPlugin::~CatalogExportPlugin()
+{
+ delete d;
+}
+
+QStringList CatalogExportPlugin::availableExportMimeTypes()
+{
+ QStringList result;
+
+ KTrader::OfferList offers = KTrader::self()->query("KBabelFilter", "exist [X-KDE-Export]");
+
+ for( KTrader::OfferListIterator ptr = offers.begin(); ptr!=offers.end() ; ++ptr )
+ {
+ result += (*ptr)->property("X-KDE-Export").toStringList();
+ }
+
+ return result;
+}
+
+void CatalogExportPlugin::stop()
+{
+ d->_stop = true;
+}
+
+bool CatalogExportPlugin::isStopped() const
+{
+ return d->_stop;
+}
diff --git a/kbabel/common/findoptions.h b/kbabel/common/findoptions.h
new file mode 100644
index 00000000..45c29e25
--- /dev/null
+++ b/kbabel/common/findoptions.h
@@ -0,0 +1,86 @@
+/* ****************************************************************************
+ This file is part of KBabel
+
+ Copyright (C) 1999-2000 by Matthias Kiefer
+ <matthias.kiefer@gmx.de>
+ 2001 by Stanislav Visnovsky
+ <visnovsky@kde.org>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the 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, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+ In addition, as a special exception, the copyright holders give
+ permission to link the code of this program with any edition of
+ the Qt library by Trolltech AS, Norway (or with modified versions
+ of Qt that use the same license as Qt), and distribute linked
+ combinations including the two. You must obey the GNU General
+ Public License in all respects for all of the code used other than
+ Qt. If you modify this file, you may extend this exception to
+ your version of the file, but you are not obligated to do so. If
+ you do not wish to do so, delete this exception statement from
+ your version.
+
+**************************************************************************** */
+#ifndef FINDOPTIONS_H
+#define FINDOPTIONS_H
+
+#include <qregexp.h>
+
+class QString;
+class QChar;
+
+namespace KBabel
+{
+
+class FindOptions
+{
+public:
+ QString findStr;
+
+ bool caseSensitive;
+ bool wholeWords;
+ bool fromCursor;
+ bool backwards;
+ bool isRegExp;
+
+ bool inMsgid;
+ bool inMsgstr;
+ bool inComment;
+
+ bool ignoreAccelMarker;
+ bool ignoreContextInfo;
+
+ bool askForNextFile;
+ bool askForSave; // whether should ask before saving or save automatically when loading next file
+ bool inAllFiles; // whether search should be done in all files
+ bool inMarkedFiles; // whether search should be restricted to marked ones
+ bool inTemplates;
+
+ // these are non-persistent options - not saved into configuration database
+ bool askFile; // whether findNext should ask catalog manager for next file
+ QRegExp contextInfo; // actual settings of context info regular expression
+ QChar accelMarker; // actual settings of accelerator marker
+
+};
+
+class ReplaceOptions : public FindOptions
+{
+public:
+ QString replaceStr;
+ bool ask;
+};
+
+}
+
+#endif
diff --git a/kbabel/common/importplugin.cpp b/kbabel/common/importplugin.cpp
new file mode 100644
index 00000000..d763e670
--- /dev/null
+++ b/kbabel/common/importplugin.cpp
@@ -0,0 +1,194 @@
+/* ****************************************************************************
+ This file is part of KBabel
+
+ Copyright (C) 2002-2003 by Stanislav Visnovsky
+ <visnovsky@kde.org>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the 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, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+ In addition, as a special exception, the copyright holders give
+ permission to link the code of this program with any edition of
+ the Qt library by Trolltech AS, Norway (or with modified versions
+ of Qt that use the same license as Qt), and distribute linked
+ combinations including the two. You must obey the GNU General
+ Public License in all respects for all of the code used other than
+ Qt. If you modify this file, you may extend this exception to
+ your version of the file, but you are not obligated to do so. If
+ you do not wish to do so, delete this exception statement from
+ your version.
+
+**************************************************************************** */
+
+#include "catalogfileplugin.h"
+#include "importplugin_private.h"
+
+#include "catalog.h"
+
+#include <qstringlist.h>
+
+#include <kdebug.h>
+#include <ktrader.h>
+
+using namespace KBabel;
+
+CatalogImportPlugin::CatalogImportPlugin(QObject* parent, const char* name) : QObject(parent,name)
+{
+ d = new CatalogImportPluginPrivate;
+ d->_catalog = 0;
+ d->_started = false;
+ d->_stopped = false;
+}
+
+CatalogImportPlugin::~CatalogImportPlugin()
+{
+ delete d;
+}
+
+void CatalogImportPlugin::appendCatalogItem( const CatalogItem& item, const bool obsolete )
+{
+ if( obsolete )
+ d->_obsoleteEntries.append(item);
+ else
+ d->_entries.append(item);
+}
+
+void CatalogImportPlugin::setCatalogExtraData( const QStringList& data )
+{
+ d->_catalogExtraData=data;
+ d->_updateCatalogExtraData=true;
+}
+
+void CatalogImportPlugin::setGeneratedFromDocbook( const bool generated )
+{
+ d->_generatedFromDocbook = generated;
+ d->_updateGeneratedFromDocbook = true;
+}
+
+void CatalogImportPlugin::setErrorIndex(const QValueList<uint>& errors)
+{
+ d->_errorList = errors;
+ d->_updateErrorList = true;
+}
+
+void CatalogImportPlugin::setFileCodec(QTextCodec* codec)
+{
+ d->_codec=codec;
+ d->_updateCodec = true;
+}
+
+void CatalogImportPlugin::setHeader( const CatalogItem& item )
+{
+ d->_header=item;
+ d->_updateHeader=true;
+}
+
+void CatalogImportPlugin::setMimeTypes( const QString& mimetypes )
+{
+ d->_mimeTypes=mimetypes;
+}
+
+ConversionStatus CatalogImportPlugin::open(const QString& file, const QString& mimetype, Catalog* catalog)
+{
+ d->_stopped=false;
+ d->_catalog=catalog;
+ startTransaction();
+
+ ConversionStatus result = load(file, mimetype);
+ if( d->_stopped )
+ {
+ d->_started=false;
+ return STOPPED;
+ }
+
+ if( result == OK || result == RECOVERED_PARSE_ERROR || result == RECOVERED_HEADER_ERROR )
+ commitTransaction();
+
+ return result;
+}
+
+void CatalogImportPlugin::startTransaction()
+{
+ d->_started = (d->_catalog!=0);
+
+ d->_updateCodec = false;
+ d->_updateCatalogExtraData = false;
+ d->_updateGeneratedFromDocbook = false;
+ d->_updateErrorList = false;
+ d->_updateHeader = false;
+ d->_mimeTypes = "text/plain";
+ d->_entries.clear();
+}
+
+void CatalogImportPlugin::commitTransaction()
+{
+ if( d->_started )
+ {
+ d->_catalog->clear();
+
+ // fill in the entries
+ QValueVector<CatalogItem> e;
+ e.reserve( d->_entries.count() );
+ for( QValueList<CatalogItem>::const_iterator it = d->_entries.begin(); it != d->_entries.end(); ++it )
+ {
+ e.append( *it );
+ }
+ d->_catalog->setEntries( e );
+
+ d->_catalog->setObsoleteEntries( d->_obsoleteEntries );
+
+ if( d->_updateCodec ) d->_catalog->setFileCodec(d->_codec);
+ if( d->_updateCatalogExtraData )
+ d->_catalog->setCatalogExtraData(d->_catalogExtraData);
+ if( d->_updateGeneratedFromDocbook )
+ d->_catalog->setGeneratedFromDocbook(d->_generatedFromDocbook);
+ if( d->_updateHeader )
+ d->_catalog->setHeader(d->_header);
+ // generate before setting errors, since it clears the error list
+ d->_catalog->generateIndexLists();
+ if( d->_updateErrorList )
+ d->_catalog->setErrorIndex(d->_errorList);
+
+ d->_catalog->setImportPluginID(id());
+ d->_catalog->setMimeTypes( d->_mimeTypes );
+ }
+
+ d->_started = false;
+}
+
+QStringList CatalogImportPlugin::availableImportMimeTypes()
+{
+ QStringList result;
+
+ KTrader::OfferList offers = KTrader::self()->query("KBabelFilter", "exist [X-KDE-Import]");
+
+ for( KTrader::OfferListIterator ptr = offers.begin(); ptr!=offers.end() ; ++ptr )
+ {
+ result += (*ptr)->property("X-KDE-Import").toStringList();
+ }
+
+ return result;
+}
+
+bool CatalogImportPlugin::isStopped() const
+{
+ return d->_stopped;
+}
+
+void CatalogImportPlugin::stop()
+{
+ d->_stopped = true;
+}
+
+#include "catalogfileplugin.moc"
diff --git a/kbabel/common/importplugin_private.h b/kbabel/common/importplugin_private.h
new file mode 100644
index 00000000..3c45919c
--- /dev/null
+++ b/kbabel/common/importplugin_private.h
@@ -0,0 +1,69 @@
+/* ****************************************************************************
+ This file is part of KBabel
+
+ Copyright (C) 2002-2003 by Stanislav Visnovsky
+ <visnovsky@kde.org>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the 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, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+ In addition, as a special exception, the copyright holders give
+ permission to link the code of this program with any edition of
+ the Qt library by Trolltech AS, Norway (or with modified versions
+ of Qt that use the same license as Qt), and distribute linked
+ combinations including the two. You must obey the GNU General
+ Public License in all respects for all of the code used other than
+ Qt. If you modify this file, you may extend this exception to
+ your version of the file, but you are not obligated to do so. If
+ you do not wish to do so, delete this exception statement from
+ your version.
+
+**************************************************************************** */
+#ifndef IMPORTPLUGINPRIVATE_H
+#define IMPORTPLUGINPRIVATE_H
+
+#include "catalogitem.h"
+
+class QTextCodec;
+
+namespace KBabel {
+
+class Catalog;
+
+class CatalogImportPluginPrivate
+{
+public:
+ Catalog* _catalog;
+ bool _started;
+ bool _stopped;
+
+ QValueList<CatalogItem> _entries;
+ QValueList<CatalogItem> _obsoleteEntries;
+ CatalogItem _header;
+ bool _generatedFromDocbook;
+ QTextCodec* _codec;
+ QValueList<uint> _errorList;
+ QStringList _catalogExtraData;
+ QString _mimeTypes;
+
+ bool _updateHeader;
+ bool _updateGeneratedFromDocbook;
+ bool _updateCodec;
+ bool _updateErrorList;
+ bool _updateCatalogExtraData;
+};
+
+}
+
+#endif
diff --git a/kbabel/common/itempart.h b/kbabel/common/itempart.h
new file mode 100644
index 00000000..842f195b
--- /dev/null
+++ b/kbabel/common/itempart.h
@@ -0,0 +1,37 @@
+/* ****************************************************************************
+ This file is part of KBabel
+
+ Copyright (C) 2002-2005 by Stanislav Visnovsky
+ <visnovsky@kde.org>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the 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, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+ In addition, as a special exception, the copyright holders give
+ permission to link the code of this program with any edition of
+ the Qt library by Trolltech AS, Norway (or with modified versions
+ of Qt that use the same license as Qt), and distribute linked
+ combinations including the two. You must obey the GNU General
+ Public License in all respects for all of the code used other than
+ Qt. If you modify this file, you may extend this exception to
+ your version of the file, but you are not obligated to do so. If
+ you do not wish to do so, delete this exception statement from
+ your version.
+**************************************************************************** */
+#ifndef ITEMPART_H
+#define ITEMPART_H
+
+enum Part {UndefPart, Msgid, Msgstr, Comment};
+
+#endif
diff --git a/kbabel/common/kbabel-projectrename.upd b/kbabel/common/kbabel-projectrename.upd
new file mode 100644
index 00000000..f2e8510b
--- /dev/null
+++ b/kbabel/common/kbabel-projectrename.upd
@@ -0,0 +1,13 @@
+Id=kde34
+File=kbabel.defaultproject
+Group=Header
+Author-Email,AuthorEmail
+Author-Name,AuthorName
+Local-Author-Name,LocalAuthorName
+Update-Charset,UpdateCharset
+Update-Encoding,UpdateEncoding
+Update-Language-Team,UpdateLanguageTeam
+Update-Last-Translator,UpdateLastTranslator
+Update-Project,UpdateProject
+Update-Revision,UpdateRevision
+#eof
diff --git a/kbabel/common/kbabeldatatool.h b/kbabel/common/kbabeldatatool.h
new file mode 100644
index 00000000..57d9f771
--- /dev/null
+++ b/kbabel/common/kbabeldatatool.h
@@ -0,0 +1,63 @@
+/* ****************************************************************************
+ This file is part of KBabel
+
+ Copyright (C) 2003 by Stanislav Visnovsky
+ <visnovsky@kde.org>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the 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, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+ In addition, as a special exception, the copyright holders give
+ permission to link the code of this program with any edition of
+ the Qt library by Trolltech AS, Norway (or with modified versions
+ of Qt that use the same license as Qt), and distribute linked
+ combinations including the two. You must obey the GNU General
+ Public License in all respects for all of the code used other than
+ Qt. If you modify this file, you may extend this exception to
+ your version of the file, but you are not obligated to do so. If
+ you do not wish to do so, delete this exception statement from
+ your version.
+
+**************************************************************************** */
+#ifndef KBABELDATATOOL_H
+#define KBABELDATATOOL_H
+
+#include <kdatatool.h>
+
+namespace KBabel
+{
+
+/**
+ * This class represents a base class for a KBabel @ref KDataTool.
+ * It supports automatic settings management.
+ *
+ * @short This class represents a base class for a KBabel data tool.
+ */
+class KBabelDataTool: public KDataTool
+{
+ Q_OBJECT
+
+protected:
+ KBabelDataTool( QObject* parent, const char* name ) : KDataTool( parent, name ) {}
+public slots:
+ /** The only method to be redefined in inherited classes.
+ * This method is called everytime the settings are changed.
+ * @param project is ID of the project, for which the settings changed.
+ */
+ virtual void settingsChanged(const QString &project) = 0;
+};
+
+}
+
+#endif // KBABELDATATOOL_H
diff --git a/kbabel/common/kbabelfilter.desktop b/kbabel/common/kbabelfilter.desktop
new file mode 100644
index 00000000..f9573ad2
--- /dev/null
+++ b/kbabel/common/kbabelfilter.desktop
@@ -0,0 +1,60 @@
+[Desktop Entry]
+Type=ServiceType
+X-KDE-ServiceType=KBabelFilter
+Comment=KBabel filter
+Comment[bg]=Филтър - KBabel
+Comment[br]=Sil KBabel
+Comment[ca]=Filtre de KBabel
+Comment[cs]=KBabel filtr
+Comment[cy]=Hidlydd KBabel
+Comment[da]=KBabel-filter
+Comment[de]=KBabel-Filter
+Comment[el]=ΦίλτÏο KBabel
+Comment[es]=Filtro de KBabel
+Comment[et]=KBabeli filter
+Comment[eu]=KBabel iragazkia
+Comment[fa]=پالایۀ KBabel
+Comment[fi]=KBabel-suodatin
+Comment[fr]=Filtre pour KBabel
+Comment[ga]=Scagaire KBabel
+Comment[gl]=Filtro de KBabel
+Comment[he]=מסנן KBabel
+Comment[hi]=के-बेबल फ़िलà¥à¤Ÿà¤°
+Comment[hu]=KBabel-szűrő
+Comment[is]=KBabel sía
+Comment[it]=Filtro KBabel
+Comment[ja]=KBabel フィルタ
+Comment[ka]=KBabel ფილტრი
+Comment[kk]=KBabel ÑүзгіÑÑ–
+Comment[lt]=KBabel filtras
+Comment[ms]=Penapis KBabel
+Comment[nb]=KBabel-filter
+Comment[nds]=KBabel-Filter
+Comment[ne]=केबà¥à¤¯à¤¾à¤¬à¤² फिलà¥à¤Ÿà¤°
+Comment[nl]=KBabel-filter
+Comment[nn]=KBabel-filter
+Comment[pa]=KBabel ਫਿਲਟਰ
+Comment[pl]=Filtr KBabel
+Comment[pt]=Filtro do KBabel
+Comment[pt_BR]=Filtro KBabel
+Comment[ru]=Фильтр KBabel
+Comment[sk]=Filter pre KBabel
+Comment[sl]=Filter KBabel
+Comment[sr]=KBabel-ов филтер
+Comment[sr@Latn]=KBabel-ov filter
+Comment[sv]=Kbabel-filter
+Comment[ta]=Kபாபேல௠வடிகடà¯à®Ÿà®¿
+Comment[tg]=Филтри KBabel
+Comment[tr]=KBabel süzgeci
+Comment[uk]=Фільтр KBabel
+Comment[zh_CN]=KBabel 过滤器
+Comment[zh_TW]=KBabel éŽæ¿¾å™¨
+
+[PropertyDef::X-KDE-Import]
+Type=QStringList
+
+[PropertyDef::X-KDE-Export]
+Type=QStringList
+
+[PropertyDef::X-KDE-Available]
+Type=QString
diff --git a/kbabel/common/kbmailer.cpp b/kbabel/common/kbmailer.cpp
new file mode 100644
index 00000000..fb3ab3b1
--- /dev/null
+++ b/kbabel/common/kbmailer.cpp
@@ -0,0 +1,244 @@
+/* ****************************************************************************
+ This file is part of KBabel
+
+ Copyright (C) 2002-2003 by Marco Wegner <mail@marcowegner.de>
+ 2004 by Stanislav Visnovsky <visnovsky@kde.org>
+ Copyright (C) 2006 by Nicolas GOUTTE <goutte@kde.org>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the 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, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+ In addition, as a special exception, the copyright holders give
+ permission to link the code of this program with any edition of
+ the Qt library by Trolltech AS, Norway (or with modified versions
+ of Qt that use the same license as Qt), and distribute linked
+ combinations including the two. You must obey the GNU General
+ Public License in all respects for all of the code used other than
+ Qt. If you modify this file, you may extend this exception to
+ your version of the file, but you are not obligated to do so. If
+ you do not wish to do so, delete this exception statement from
+ your version.
+
+**************************************************************************** */
+
+
+#include <qfileinfo.h>
+#include <qregexp.h>
+#include <qstring.h>
+#include <qstringlist.h>
+#include <qwidget.h>
+
+#include <kapplication.h>
+#include <kio/netaccess.h>
+#include <klocale.h>
+#include <kmessagebox.h>
+#include <ktar.h>
+#include <kurl.h>
+#include <kdebug.h>
+#include <ktempdir.h>
+#include <kinputdialog.h>
+
+#include "kbmailer.h"
+
+using namespace KBabel;
+
+KBabelMailer::KBabelMailer( QWidget* parent, Project::Ptr project)
+ : _project( project ), m_parent( parent )
+{
+ m_tempDir.setAutoDelete( true );
+ readConfig();
+}
+
+KBabelMailer::~KBabelMailer()
+{
+ saveConfig( );
+}
+
+void KBabelMailer::sendOneFile(const QString& fileName)
+{
+ if (!singleFileCompression) {
+ kapp->invokeMailer("", "", "", "", "", "", fileName);
+ } else {
+ const QString archive ( createArchive( QStringList( fileName ), QFileInfo( fileName ).baseName() ) );
+ if ( !archive.isEmpty() ) {
+ kapp->invokeMailer("", "", "", "", "", "", archive);
+ }
+ }
+}
+
+void KBabelMailer::sendOneFile( const KURL& url)
+{
+#if KDE_IS_VERSION( 3, 5, 0)
+ const KURL localUrl( KIO::NetAccess::mostLocalURL( url, m_parent ) );
+#else
+ const KURL localUrl( url );
+#endif
+ if ( localUrl.isLocalFile() )
+ {
+ sendOneFile( localUrl.path() );
+ return;
+ }
+
+ if (!singleFileCompression) {
+ QString fileName( url.filename() );
+ if ( fileName.isEmpty() )
+ {
+ fileName = "attachment";
+ }
+ // ### TODO: the current implementation has the default to possibly overwrite an already existing temporary file
+ QString tempName( m_tempDir.name() );
+ tempName += fileName;
+ if ( KIO::NetAccess::download( url, tempName, m_parent ) )
+ kapp->invokeMailer("", "", "", "", "", "", fileName);
+ else
+ {
+ KMessageBox::error( m_parent, i18n("Error while trying to download file %1.").arg( url.prettyURL() ) );
+ }
+ }
+ else
+ {
+ const QString archive ( createArchive( QStringList( url.url() ), url.filename() ) );
+ if ( !archive.isEmpty() ) {
+ kapp->invokeMailer("", "", "", "", "", "", archive);
+ }
+ }
+}
+
+void KBabelMailer::sendFiles(QStringList fileList, const QString& initialName)
+{
+ const QString archive ( createArchive( fileList, initialName ) );
+ if ( !archive.isEmpty() ) {
+ kapp->invokeMailer("", "", "", "", "", "", archive);
+ }
+}
+
+QString KBabelMailer::createArchive(QStringList fileList, QString initialName)
+{
+ if ( m_tempDir.name().isEmpty() )
+ {
+ kdWarning() << "KBabelMailer has not a valid temporary directory!" << endl;
+ return QString(); // No temporary directory!
+ }
+
+ // do nothing if there are no files in the list
+ if (fileList.empty())
+ return QString::null;
+
+ // determine the name of the archive, do nothing if none is given
+ // or Cancel was pressed
+ initialName = ( initialName.isEmpty() ? QString("translations") : initialName );
+ bool ok = false;
+ QStringList list( archiveList );
+ list.prepend( initialName );
+ QString archiveName ( KInputDialog::getItem( i18n("Save"),
+ i18n( "Enter the name of the archive without file extension" ),
+ archiveList, 0, true, &ok, m_parent ) );
+ if ( !ok || archiveName.isEmpty() )
+ return QString();
+
+ // file extensions are determined from the type of compression
+ archiveName.remove( QRegExp( "\\.tar\\.(gz|bz2)$" ) );
+
+ // Update the list of archive names, keep only the ten most recent ones.
+ archiveList.remove( archiveName );
+ archiveList.prepend( archiveName );
+ if ( archiveList.count( ) > 10 )
+ archiveList.pop_back();
+
+ // set the correct extension and mimetype
+ QString mimetype;
+ if (bzipCompression) {
+ archiveName += ".tar.bz2";
+ mimetype = "application/x-bzip2";
+ } else {
+ archiveName += ".tar.gz";
+ mimetype = "application/x-gzip";
+ }
+
+ return buildArchive (fileList, m_tempDir.name()+archiveName, mimetype, true);
+}
+
+QString KBabelMailer::buildArchive(QStringList fileList, QString archiveName, QString mimetype, bool remove)
+{
+ Q_UNUSED( remove );
+ // create a new archive
+ KTar archive(archiveName, mimetype);
+ if (!archive.open(IO_WriteOnly)) {
+ KMessageBox::error( m_parent, i18n("Error while trying to create archive file.") );
+ return QString::null;
+ }
+
+ // add files to this archive
+ QStringList::const_iterator it;
+ for (it = fileList.constBegin(); it != fileList.constEnd(); ++it) {
+#if KDE_IS_VERSION( 3, 5, 0 )
+ // Try to get a local URL instead of a remote one
+ const KURL url( KIO::NetAccess::mostLocalURL( KURL::fromPathOrURL( *it ), m_parent ) );
+#else
+ const KURL url( KURL::fromPathOrURL( *it ) );
+#endif
+ QString poTempName;
+ if ( !KIO::NetAccess::download( url, poTempName, m_parent ) ) {
+ KMessageBox::error( m_parent, i18n("Error while trying to read file %1.").arg( url.prettyURL() ) );
+ continue;
+ }
+
+ // The files in the archive are stored relatively to the PO base dir
+ // but only if "PoBaseDir" in the config file is set and the files
+ // actually reside in one of its subdirectories. Else they are stored
+ // without relative path.
+ QString poArchFileName = url.path();
+ if (_poBaseDir.isEmpty( ) || poArchFileName.find(_poBaseDir) != 0)
+ poArchFileName = QFileInfo( poArchFileName ).fileName();
+ else
+ poArchFileName.remove( QRegExp( "^" + QRegExp::escape( _poBaseDir ) + "/?" ) );
+ if ( !archive.addLocalFile( poTempName, poArchFileName ) )
+ {
+ KMessageBox::error( m_parent, i18n("Error while trying to copy file %1 into archive.").arg( url.prettyURL() ) );
+ }
+
+ KIO::NetAccess::removeTempFile(poTempName);
+ }
+ archive.close();
+
+ return archive.fileName();
+}
+
+void KBabelMailer::readConfig()
+{
+ // The relevant variables are never stored in catalogmanagerrc but in
+ // project config file. Therefore they are read from the project.
+
+ MiscSettings _settings = _project->miscSettings();
+
+ bzipCompression = _settings.useBzip;
+ singleFileCompression = _settings.compressSingleFile;
+
+ KConfig* conf = _project->config();
+
+ conf->setGroup ("Misc");
+ archiveList = conf->readListEntry("MailArchiveNames");
+
+ _poBaseDir = _project->catManSettings().poBaseDir;
+}
+
+void KBabelMailer::saveConfig()
+{
+ // For an explanation see readConfig( )
+ KConfig* _config = _project->config();
+
+ _config->setGroup("Misc");
+ _config->writeEntry("MailArchiveNames", archiveList);
+}
+
diff --git a/kbabel/common/kbmailer.h b/kbabel/common/kbmailer.h
new file mode 100644
index 00000000..7df5ce9d
--- /dev/null
+++ b/kbabel/common/kbmailer.h
@@ -0,0 +1,166 @@
+/* ****************************************************************************
+ This file is part of KBabel
+
+ Copyright (C) 2002-2003 by Marco Wegner <mail@marcowegner.de>
+ 2004 by Stanislav Visnovsky <visnovsky@kde.org>
+ Copyright (C) 2006 by Nicolas GOUTTE <goutte@kde.org>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the 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, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+ In addition, as a special exception, the copyright holders give
+ permission to link the code of this program with any edition of
+ the Qt library by Trolltech AS, Norway (or with modified versions
+ of Qt that use the same license as Qt), and distribute linked
+ combinations including the two. You must obey the GNU General
+ Public License in all respects for all of the code used other than
+ Qt. If you modify this file, you may extend this exception to
+ your version of the file, but you are not obligated to do so. If
+ you do not wish to do so, delete this exception statement from
+ your version.
+
+**************************************************************************** */
+
+
+#ifndef KBMAILER_H
+#define KBMAILER_H
+
+#include <kbproject.h>
+#include <kdemacros.h>
+#include <ktempdir.h>
+
+class QWidget;
+
+class KURL;
+
+namespace KBabel
+{
+
+/**
+ * Utility class for providing the capability to send compressed mail
+ * archives from within KBabel and the Catalog Manager.
+ *
+ * @short Utility class for compressed mail attachments.
+ * @author Marco Wegner <mail@marcowegner.de>
+ *
+ * @internal
+ */
+class KDE_EXPORT KBabelMailer
+{
+ public:
+ /**
+ * Constructor.
+ *
+ * @param parent The parent widget.
+ * @param project The project to be used.
+ * @since 1.11.2 (KDE 3.5.2): @p parent parameter
+ */
+ KBabelMailer( QWidget* parent, Project::Ptr project);
+ virtual ~KBabelMailer();
+
+ /**
+ * Send only one file as a mail attachment. The file can either be sent
+ * as a compressed or an uncompressed file.
+ *
+ * @param fileName the name of the file to be sent.
+ */
+ void sendOneFile(const QString& fileName);
+ /**
+ * Send only one file as a mail attachment. The file can either be sent
+ * as a compressed or an uncompressed file.
+ *
+ * @param url the URL of the file to be sent.
+ * @since 1.11.2 (KDE 3.5.2)
+ */
+ void sendOneFile(const KURL& url);
+ /**
+ * Send several files as a mail attachment. The files will be included in
+ * an archive.
+ *
+ * @param fileList contains the names of the files to be sent.
+ * @param initialName the possible name of the archive
+ */
+ void sendFiles(QStringList fileList, const QString& initialName = QString::null);
+ /**
+ * Sets the the PO files' base directory.
+ *
+ * @param dir the PO file base dir.
+ */
+ void setPOBaseDir(const QString& dir) { _poBaseDir = dir; }
+
+
+ /**
+ * This is where the archive is actually created.
+ *
+ * @param fileList contains the names of the files to be included in
+ * the archive.
+ * @param initialName the name used as initial name when the archive
+ * name is queried.
+ *
+ * @return name of the archive if it was created successfully,
+ * otherwise QString::null.
+ */
+ QString createArchive(QStringList fileList, QString initialName);
+
+ /**
+ * Write the archive file.
+ */
+ QString buildArchive(QStringList fileList, QString fileName, QString mimetype, bool remove = true);
+ private:
+ /**
+ * Read the config file to extract the values for compression
+ * method and compression of single files.
+ */
+ void readConfig();
+ /**
+ * Save the config settings, only the list of recent archive names for now.
+ */
+ void saveConfig( );
+
+
+ private:
+ /**
+ * Temporary directory
+ * @since 1.11.2 (KDE 3.5.2)
+ */
+ KTempDir m_tempDir;
+
+ /**
+ * Whether to use bzip2 as compression method. If false use gzip.
+ */
+ bool bzipCompression;
+ /**
+ * Whether to compress single files as well.
+ */
+ bool singleFileCompression;
+ /**
+ * This QStringList stores the recently used archive names.
+ */
+ QStringList archiveList;
+ /**
+ * The project object.
+ */
+ Project::Ptr _project;
+ /**
+ * The path to the PO Base directory
+ */
+ QString _poBaseDir;
+
+ /// The parent widget
+ QWidget* m_parent;
+};
+
+}
+
+#endif // KBMAILER_H
diff --git a/kbabel/common/kbproject.cpp b/kbabel/common/kbproject.cpp
new file mode 100644
index 00000000..38996b51
--- /dev/null
+++ b/kbabel/common/kbproject.cpp
@@ -0,0 +1,477 @@
+/* ****************************************************************************
+ This file is part of KBabel
+
+ Copyright (C) 2004 by Stanislav Visnovsky <visnovsky@kde.org>
+ Copyright (C) 2006 by Nicolas GOUTTE <goutte@kde.org>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the 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, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+ In addition, as a special exception, the copyright holders give
+ permission to link the code of this program with any edition of
+ the Qt library by Trolltech AS, Norway (or with modified versions
+ of Qt that use the same license as Qt), and distribute linked
+ combinations including the two. You must obey the GNU General
+ Public License in all respects for all of the code used other than
+ Qt. If you modify this file, you may extend this exception to
+ your version of the file, but you are not obligated to do so. If
+ you do not wish to do so, delete this exception statement from
+ your version.
+
+**************************************************************************** */
+
+#include "resources.h"
+#include "kbproject.h"
+#include "kbprojectmanager.h"
+#include "kbprojectsettings.h"
+
+#include <qfileinfo.h>
+
+#include <kdebug.h>
+#include <klocale.h>
+#include <kmessagebox.h>
+#include <kmimetype.h>
+#include <kspell.h>
+
+namespace KBabel
+{
+
+Project::Project( const QString& file ) :
+ QObject ()
+ , _filename (file)
+ , _name (i18n("unnamed"))
+ , _valid (false)
+ , _config (NULL)
+ , _settings (NULL)
+{
+ QFileInfo info(file);
+
+ if(info.isDir())
+ return;
+
+ if(info.exists())
+ {
+ // ### TODO: can a setting file only be a text/plain file?
+ // ### TODO: why not use KMimeType::findByPath if the fileis always local?
+ // first, for existing file check the MIME type
+ // it has to be text file
+ KMimeType::Ptr mime = KMimeType::findByURL( KURL::fromPathOrURL( file ) );
+
+ if ( mime->name() == "text/plain" )
+ {
+ // Plain text, no problem!
+ }
+ else if ( mime->name() == "application/x-zerosize" )
+ {
+ // Empty files are allowed too
+ kdWarning() << "Empty KBabel project file!" << endl;
+ }
+ else if ( mime->name() == "application/octet-stream" )
+ {
+ // this can happen if the file has some very long lines
+ kdWarning() << "KBabel project file detected as octet-stream! Perhaps there are very long lines in it!" << endl;
+ }
+ else
+ {
+ // Unknown mime type, abort!
+ // ### TODO: should the user not be asked instead?
+ kdWarning () << "File type is " << mime->name() << endl;
+ return;
+ }
+ }
+
+ _config = KSharedConfig::openConfig (_filename, false, false);
+ kdDebug (KBABEL) << "Opened project " << _filename << endl;
+
+ // read the project name
+ _config->setGroup( "Project" );
+ _name = _config->readEntry( "Name", QString() );
+ if ( _name.isEmpty() )
+ _name = "Default-Project"; // set default project name
+
+ // ### FIXME: why is the Version number not written to the project file?
+ if ( _config->readEntry( "Version", QString() ) != "1.0.1" )
+ {
+ kdWarning() << "Old project format assumed" << endl;
+
+ // transform old entries to the new ones
+ _config->setGroup( "Header");
+
+ // TODO remove obsolete entries as well
+ if (_config->hasKey("Author-Email") && !_config->hasKey("AuthorEmail"))
+ {
+ _config->writeEntry ("AuthorEmail", _config->readEntry ("Author-Email", ""));
+ _config->deleteEntry ("Author-Email");
+ }
+
+ if (_config->hasKey("Author-Name") && !_config->hasKey("AuthorName"))
+ {
+ _config->writeEntry ("AuthorName", _config->readEntry ("Author-Name", ""));
+ _config->deleteEntry ("Author-Name");
+ }
+
+ if (_config->hasKey("Local-Author-Name") && !_config->hasKey("LocalAuthorName"))
+ {
+ _config->writeEntry ("LocalAuthorName", _config->readEntry ("Local-Author-Name", ""));
+ _config->deleteEntry ("Local-Author-Name");
+ }
+
+ if (_config->hasKey("Update-Charset") && !_config->hasKey("UpdateCharset"))
+ {
+ _config->writeEntry ("UpdateCharset", _config->readEntry ("Update-Charset", ""));
+ _config->deleteEntry ("Update-Charset");
+ }
+
+ if (_config->hasKey("Update-Encoding") && !_config->hasKey("UpdateEncoding"))
+ {
+ _config->writeEntry ("UpdateEncoding", _config->readEntry ("Update-Encoding", ""));
+ _config->deleteEntry ("Update-Encoding");
+ }
+
+ if (_config->hasKey("Update-Language-Team") && !_config->hasKey("UpdateLanguageTeam"))
+ {
+ _config->writeEntry ("UpdateLanguageTeam", _config->readEntry ("Update-Language-Team", ""));
+ _config->deleteEntry ("Update-Language-Team");
+ }
+
+ if (_config->hasKey("Update-Last-Translator") && !_config->hasKey("UpdateLastTranslator"))
+ {
+ _config->writeEntry ("UpdateLastTranslator", _config->readEntry ("Update-Last-Translator", ""));
+ _config->deleteEntry ("Update-Last-Translator");
+ }
+
+ if (_config->hasKey("Update-Project") && !_config->hasKey("UpdateProject"))
+ {
+ _config->writeEntry ("UpdateProject", _config->readEntry ("Update-Project", ""));
+ _config->deleteEntry ("Update-Project");
+ }
+
+ if (_config->hasKey("Update-Revision") && !_config->hasKey("UpdateRevision"))
+ {
+ _config->writeEntry ("UpdateRevision", _config->readEntry ("Update-Revision", ""));
+ _config->deleteEntry ("Update-Revision");
+ }
+
+ _config->sync();
+ }
+
+ _valid = true;
+
+ _settings = new KBabel::ProjectSettingsBase( _config );
+ _settings->readConfig();
+}
+
+Project::~Project ()
+{
+ if (_settings)
+ {
+ // store the project name
+ _settings->setVersion( "1.0.1" );
+ _settings->setName(_name);
+
+ kdDebug () << "Writing configuration" << endl;
+ _settings->writeConfig();
+
+ delete _settings;
+ }
+
+ // unregister in project manager
+ kdDebug () << "Freeing project " << _filename << endl;
+ ProjectManager::remove (this);
+}
+
+KConfig* Project::config ()
+{
+ return _config;
+}
+
+KSharedConfig* Project::sharedConfig( void )
+{
+ return _config;
+}
+
+ProjectSettingsBase* Project::settings ()
+{
+ return _settings;
+}
+
+IdentitySettings Project::identitySettings ()
+{
+ IdentitySettings settings;
+
+ settings.authorName=_settings->authorName();
+ settings.authorLocalizedName=_settings->localAuthorName();
+ settings.authorEmail=_settings->authorEmail();
+ settings.languageName=_settings->language();
+ settings.languageCode=_settings->languageCode();
+ settings.mailingList=_settings->mailinglist();
+ settings.timeZone=_settings->timezone();
+
+ settings.numberOfPluralForms=_settings->pluralForms();
+
+ if( settings.numberOfPluralForms < -1 )
+ {
+ kdWarning() << "Invalid number of plural forms, ignoring: " << settings.numberOfPluralForms << endl;
+ settings.numberOfPluralForms = 2;
+ }
+ settings.checkPluralArgument=_settings->checkPluralArgument();
+ settings.gnuPluralFormHeader=_settings->pluralFormsHeader();
+
+ return settings;
+}
+
+SaveSettings Project::saveSettings ()
+{
+ SaveSettings settings;
+
+ settings.autoUpdate=_settings->autoUpdate();
+ settings.updateLastTranslator=_settings->updateLastTranslator();
+ settings.updateRevisionDate=_settings->updateRevisionDate();
+ settings.updateLanguageTeam=_settings->updateLanguageTeam();
+ settings.updateCharset=_settings->updateCharset();
+ settings.updateEncoding=_settings->updateEncoding();
+ settings.encoding=_settings->encoding();
+ settings.useOldEncoding=_settings->useOldEncoding();
+
+ settings.updateProject=_settings->updateProject();
+ settings.projectString=_settings->projectString();
+
+ settings.autoSyntaxCheck = _settings->autoSyntaxCheck();
+ settings.saveObsolete = _settings->saveObsolete();
+ settings.customDateFormat = _settings->customDateFormat();
+ settings.dateFormat = (Qt::DateFormat)_settings->dateFormat();
+ settings.updateDescription = _settings->updateDescription();
+ settings.descriptionString = _settings->descriptionString();
+ settings.updateTranslatorCopyright = _settings->updateTranslatorCopyright();
+ settings.FSFCopyright = _settings->fSFCopyright();
+
+ settings.autoSaveDelay=_settings->autoSaveDelay();
+
+ return settings;
+}
+
+
+MiscSettings Project::miscSettings ()
+{
+ MiscSettings settings;
+
+ QString temp=_settings->accelMarker();
+ if(temp.length() > 0)
+ {
+ settings.accelMarker=temp[0];
+ }
+
+ temp = _settings->contextInfo();
+
+ settings.contextInfo.setPattern(temp);
+
+ temp = _settings->singularPlural();
+ settings.singularPlural.setPattern(temp);
+
+ settings.useBzip = _settings->bZipCompression();
+ settings.compressSingleFile = _settings->compressSingleFile();
+
+ return settings;
+}
+
+SpellcheckSettings Project::spellcheckSettings ()
+{
+ SpellcheckSettings settings;
+
+ settings.noRootAffix=_settings->noRootAffix();
+ settings.runTogether=_settings->runTogether();
+ settings.spellEncoding=_settings->spellEncoding();
+ settings.spellClient=_settings->spellClient();
+ settings.spellDict=_settings->spellDictionary();
+ settings.rememberIgnored=_settings->rememberIgnored();
+ settings.ignoreURL=_settings->ignoreURL();
+ settings.onFlySpellcheck=_settings->onFlySpellCheck();
+
+ settings.valid=true;
+
+ return settings;
+}
+
+SourceContextSettings Project::sourceContextSettings ()
+{
+ SourceContextSettings settings;
+
+ settings.codeRoot=_settings->codeRoot();
+ settings.sourcePaths=_settings->paths();
+
+ return settings;
+}
+
+CatManSettings Project::catManSettings ()
+{
+ CatManSettings settings;
+
+ settings.poBaseDir=_settings->poBaseDir();
+ settings.potBaseDir=_settings->potBaseDir();
+ settings.openWindow=_settings->openWindow();
+
+ settings.killCmdOnExit=_settings->killCmdOnExit();
+ settings.indexWords=_settings->indexWords();
+ settings.msgfmt=_settings->msgfmt();
+
+
+ settings.dirCommands = _settings->dirCommands();
+ settings.dirCommandNames = _settings->dirCommandNames();
+
+ settings.fileCommands = _settings->fileCommands();
+ settings.fileCommandNames = _settings->fileCommandNames();
+
+ settings.ignoreURL=_settings->ignoreURL();
+
+ settings.flagColumn=_settings->showFlagColumn();
+ settings.fuzzyColumn=_settings->showFuzzyColumn();
+ settings.untranslatedColumn=_settings->showUntranslatedColumn();
+ settings.totalColumn=_settings->showTotalColumn();
+ settings.cvsColumn=_settings->showCVSColumn();
+ settings.revisionColumn=_settings->showRevisionColumn();
+ settings.translatorColumn=_settings->showTranslatorColumn();
+
+ return settings;
+}
+
+void Project::setSettings (IdentitySettings settings)
+{
+ _settings->setAuthorName(settings.authorName);
+ _settings->setLocalAuthorName(settings.authorLocalizedName);
+ _settings->setAuthorEmail(settings.authorEmail);
+ _settings->setAuthorEmail(settings.authorEmail);
+ _settings->setLanguage(settings.languageName);
+ _settings->setLanguageCode(settings.languageCode);
+ _settings->setMailinglist(settings.mailingList);
+ _settings->setTimezone(settings.timeZone);
+ _settings->setPluralForms(settings.numberOfPluralForms);
+ _settings->setCheckPluralArgument(settings.checkPluralArgument);
+ _settings->setPluralFormsHeader(settings.gnuPluralFormHeader);
+
+ _settings->writeConfig();
+
+ emit signalIdentitySettingsChanged();
+ emit signalSettingsChanged();
+}
+
+void Project::setSettings (SaveSettings settings)
+{
+ _settings->setAutoUpdate(settings.autoUpdate);
+ _settings->setUpdateLastTranslator(settings.updateLastTranslator);
+ _settings->setUpdateRevisionDate(settings.updateRevisionDate);
+ _settings->setUpdateLanguageTeam(settings.updateLanguageTeam);
+ _settings->setUpdateCharset(settings.updateCharset);
+ _settings->setUpdateEncoding(settings.updateEncoding);
+ _settings->setEncoding(settings.encoding);
+ _settings->setUseOldEncoding(settings.useOldEncoding);
+
+ _settings->setUpdateProject(settings.updateProject);
+ _settings->setProjectString(settings.projectString);
+
+ _settings->setAutoSyntaxCheck(settings.autoSyntaxCheck);
+ _settings->setSaveObsolete(settings.saveObsolete);
+ _settings->setCustomDateFormat(settings.customDateFormat);
+ _settings->setDateFormat(settings.dateFormat);
+ _settings->setUpdateDescription(settings.updateDescription);
+ _settings->setDescriptionString(settings.descriptionString);
+ _settings->setUpdateTranslatorCopyright(settings.updateTranslatorCopyright);
+ _settings->setFSFCopyright(settings.FSFCopyright);
+
+ _settings->setAutoSaveDelay(settings.autoSaveDelay);
+
+ _settings->writeConfig();
+
+ emit signalSaveSettingsChanged();
+ emit signalSettingsChanged();
+}
+
+
+void Project::setSettings (MiscSettings settings)
+{
+ _settings->setAccelMarker(settings.accelMarker);
+ _settings->setContextInfo(settings.contextInfo.pattern());
+ _settings->setSingularPlural(settings.singularPlural.pattern());
+ _settings->setBZipCompression(settings.useBzip);
+ _settings->setCompressSingleFile(settings.compressSingleFile);
+
+ _settings->writeConfig();
+
+ emit signalMiscSettingsChanged();
+ emit signalSettingsChanged();
+}
+
+void Project::setSettings (SpellcheckSettings settings)
+{
+ _settings->setNoRootAffix(settings.noRootAffix);
+ _settings->setRunTogether(settings.runTogether);
+ _settings->setSpellEncoding(settings.spellEncoding);
+ _settings->setSpellClient(settings.spellClient);
+ _settings->setSpellDictionary(settings.spellDict);
+ _settings->setRememberIgnored(settings.rememberIgnored);
+ _settings->setIgnoreURL(settings.ignoreURL);
+ _settings->setOnFlySpellCheck(settings.onFlySpellcheck);
+
+ _settings->writeConfig();
+
+ emit signalSpellcheckSettingsChanged();
+ emit signalSettingsChanged();
+}
+
+void Project::setSettings (SourceContextSettings settings)
+{
+ KConfigGroupSaver saver(_config,"SourceContext");
+
+ _settings->setCodeRoot(settings.codeRoot);
+ _settings->setPaths(settings.sourcePaths);
+
+ _settings->writeConfig();
+
+ emit signalSourceContextSettingsChanged();
+ emit signalSettingsChanged();
+}
+
+void Project::setSettings (CatManSettings settings)
+{
+ _settings->setPoBaseDir(settings.poBaseDir);
+ _settings->setPotBaseDir(settings.potBaseDir);
+ _settings->setOpenWindow(settings.openWindow);
+
+ _settings->setKillCmdOnExit(settings.killCmdOnExit);
+ _settings->setIndexWords(settings.indexWords);
+
+ _settings->setDirCommands(settings.dirCommands);
+ _settings->setDirCommandNames(settings.dirCommandNames);
+
+ _settings->setFileCommands(settings.fileCommands);
+ _settings->setFileCommandNames(settings.fileCommandNames);
+
+ _settings->setValidationIgnoreURL(settings.ignoreURL);
+
+ _settings->setShowFlagColumn(settings.flagColumn);
+ _settings->setShowFuzzyColumn(settings.fuzzyColumn);
+ _settings->setShowUntranslatedColumn(settings.untranslatedColumn);
+ _settings->setShowTotalColumn(settings.totalColumn);
+ _settings->setShowCVSColumn(settings.cvsColumn);
+ _settings->setShowRevisionColumn(settings.revisionColumn);
+ _settings->setShowTranslatorColumn(settings.translatorColumn);
+
+ _settings->writeConfig();
+
+ emit signalCatManSettingsChanged();
+ emit signalSettingsChanged();
+}
+
+}
+
+#include "kbproject.moc"
diff --git a/kbabel/common/kbproject.h b/kbabel/common/kbproject.h
new file mode 100644
index 00000000..1e1ebc79
--- /dev/null
+++ b/kbabel/common/kbproject.h
@@ -0,0 +1,109 @@
+/* ****************************************************************************
+ This file is part of KBabel
+
+ Copyright (C) 2004 by Stanislav Visnovsky <visnovsky@kde.org>
+ Copyright (C) 2006 by Nicolas GOUTTE <goutte@kde.org>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the 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, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+ In addition, as a special exception, the copyright holders give
+ permission to link the code of this program with any edition of
+ the Qt library by Trolltech AS, Norway (or with modified versions
+ of Qt that use the same license as Qt), and distribute linked
+ combinations including the two. You must obey the GNU General
+ Public License in all respects for all of the code used other than
+ Qt. If you modify this file, you may extend this exception to
+ your version of the file, but you are not obligated to do so. If
+ you do not wish to do so, delete this exception statement from
+ your version.
+
+**************************************************************************** */
+#ifndef KBPROJECT_H
+#define KBPROJECT_H
+
+#include <qstring.h>
+
+#include <kconfig.h>
+#include "catalogsettings.h"
+#include "projectsettings.h"
+
+namespace KBabel
+{
+ class ProjectSettingsBase;
+
+ class KDE_EXPORT Project : public QObject, public KShared
+ {
+ Q_OBJECT
+ public:
+ typedef KSharedPtr <Project> Ptr;
+
+ Project( const QString& file );
+ virtual ~Project ();
+
+ QString filename () const { return _filename; }
+ QString name () const { return _name; }
+
+ void setName( const QString& name ) { _name = name; }
+
+ KConfig* config ();
+ /**
+ * Returns the KSharedConfig pointer of the project data
+ * @since 1.11.2 (KDE 3.5.2)
+ */
+ KSharedConfig* sharedConfig( void );
+
+ ProjectSettingsBase* settings ();
+
+ bool valid () { return _valid; }
+
+ IdentitySettings identitySettings ();
+ SaveSettings saveSettings ();
+ MiscSettings miscSettings ();
+ SpellcheckSettings spellcheckSettings ();
+ SourceContextSettings sourceContextSettings ();
+ CatManSettings catManSettings ();
+
+ void setSettings(KBabel::CatManSettings newSettings);
+ void setSettings(KBabel::SaveSettings newSettings);
+ void setSettings(KBabel::IdentitySettings newSettings);
+ void setSettings(KBabel::MiscSettings newSettings);
+ void setSettings(KBabel::SpellcheckSettings newSettings);
+ void setSettings(KBabel::SourceContextSettings newSettings);
+
+ signals:
+ void signalIdentitySettingsChanged();
+ void signalSaveSettingsChanged();
+ void signalMiscSettingsChanged();
+ void signalSpellcheckSettingsChanged();
+ void signalSourceContextSettingsChanged();
+ void signalCatManSettingsChanged();
+
+ /**
+ * This is general purpose signal emitted additionally
+ * to the signals above.
+ */
+ void signalSettingsChanged();
+
+ private:
+ QString _filename;
+ QString _name;
+ bool _valid;
+ KSharedConfig::Ptr _config;
+ ProjectSettingsBase* _settings;
+ };
+
+}
+
+#endif // KBPROJECT_H
diff --git a/kbabel/common/kbprojectmanager.cpp b/kbabel/common/kbprojectmanager.cpp
new file mode 100644
index 00000000..048c530a
--- /dev/null
+++ b/kbabel/common/kbprojectmanager.cpp
@@ -0,0 +1,101 @@
+/* ****************************************************************************
+ This file is part of KBabel
+
+ Copyright (C) 2004 by Stanislav Visnovsky
+ <visnovsky@kde.org>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the 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, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+ In addition, as a special exception, the copyright holders give
+ permission to link the code of this program with any edition of
+ the Qt library by Trolltech AS, Norway (or with modified versions
+ of Qt that use the same license as Qt), and distribute linked
+ combinations including the two. You must obey the GNU General
+ Public License in all respects for all of the code used other than
+ Qt. If you modify this file, you may extend this exception to
+ your version of the file, but you are not obligated to do so. If
+ you do not wish to do so, delete this exception statement from
+ your version.
+
+**************************************************************************** */
+
+#include <kdebug.h>
+#include <kstandarddirs.h>
+
+#include "kbprojectmanager.h"
+
+namespace KBabel
+{
+
+QPtrList<Project> ProjectManager::p_list;
+QString ProjectManager::strDefaultProjectName = QString();
+
+Project::Ptr ProjectManager::open( const QString& file )
+{
+ kdDebug() << k_funcinfo << " " << file << endl;
+ // TODO: ensure full path
+ // TODO: isn't a map better?
+ for(QPtrList<Project>::ConstIterator it = p_list.constBegin();
+ it != p_list.constEnd(); ++it)
+ {
+ if ((*it)->filename() == file)
+ {
+ kdDebug() << k_funcinfo << " returning existing project " << (void*) it << endl;
+ return (*it);
+ }
+ }
+
+ Project::Ptr f = new Project (file);
+
+ if( ! f->valid() )
+ {
+ kdWarning() << "New invalid project for " << file << endl;
+ return NULL;
+ }
+
+ kdDebug() << k_funcinfo << " creating new project " << (void*) f << endl;
+ p_list.append (f);
+ return f;
+}
+
+void ProjectManager::close( Project::Ptr project)
+{
+ // this does nothing, we don't really close projects ATM, just sync the configuration
+ kdDebug() << k_funcinfo << " closing project " << (void*) project << " count: " << project.count() << endl;
+ project->config()->sync();
+}
+
+QString ProjectManager::defaultProjectName( void )
+{
+ if ( strDefaultProjectName.isEmpty() )
+ strDefaultProjectName = locateLocal("config", "kbabel.defaultproject" );
+ return strDefaultProjectName;
+}
+
+Project::Ptr ProjectManager::create()
+{
+ kdWarning() << k_funcinfo << " was called!" << endl;
+ // TODO:
+ return 0;
+}
+
+void ProjectManager::remove( Project* ref )
+{
+ kdDebug() << k_funcinfo << " Final remove of project " << (void*) ref << " count remaining: " << ref->_KShared_count() << endl;
+ p_list.remove (ref);
+}
+
+}
+
diff --git a/kbabel/common/kbprojectmanager.h b/kbabel/common/kbprojectmanager.h
new file mode 100644
index 00000000..418183bb
--- /dev/null
+++ b/kbabel/common/kbprojectmanager.h
@@ -0,0 +1,62 @@
+/* ****************************************************************************
+ This file is part of KBabel
+
+ Copyright (C) 2004 by Stanislav Visnovsky
+ <visnovsky@kde.org>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the 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, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+ In addition, as a special exception, the copyright holders give
+ permission to link the code of this program with any edition of
+ the Qt library by Trolltech AS, Norway (or with modified versions
+ of Qt that use the same license as Qt), and distribute linked
+ combinations including the two. You must obey the GNU General
+ Public License in all respects for all of the code used other than
+ Qt. If you modify this file, you may extend this exception to
+ your version of the file, but you are not obligated to do so. If
+ you do not wish to do so, delete this exception statement from
+ your version.
+
+**************************************************************************** */
+#ifndef KBPROJECTMANAGER_H
+#define KBPROJECTMANAGER_H
+
+#include <qstring.h>
+#include <qptrlist.h>
+#include <kdemacros.h>
+
+#include "kbproject.h"
+
+namespace KBabel
+{
+
+ class KDE_EXPORT ProjectManager
+ {
+ public:
+ static Project::Ptr open( const QString& file );
+ static void close( Project::Ptr project );
+ static Project::Ptr create();
+ static QString defaultProjectName( void );
+
+ friend class Project;
+ private:
+ static void remove (Project*);
+ static QPtrList<Project> p_list;
+ static QString strDefaultProjectName;
+ };
+
+}
+
+#endif // KBPROJECTMANAGER_H
diff --git a/kbabel/common/kbprojectsettings.kcfg b/kbabel/common/kbprojectsettings.kcfg
new file mode 100644
index 00000000..784189ec
--- /dev/null
+++ b/kbabel/common/kbprojectsettings.kcfg
@@ -0,0 +1,354 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<kcfg xmlns="http://www.kde.org/standards/kcfg/1.0"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://www.kde.org/standards/kcfg/1.0
+ http://www.kde.org/standards/kcfg/1.0/kcfg.xsd" >
+ <kcfgfile arg="true"/>
+ <include>catalogsettings.h</include>
+ <include>projectsettings.h</include>
+
+ <entry name="ValidateIgnoreFuzzy" type="Bool">
+ <label>If the validation tools should ignore fuzzy translations</label>
+ <default>false</default>
+ </entry>
+ <entry name="ValidateMarkAsFuzzy" type="Bool">
+ <label>If the validation tools should mark error entries as fuzzy</label>
+ <default>false</default>
+ </entry>
+ <group name="CatalogManager">
+ <entry name="DirCommandNames" type="StringList">
+ <label>List of command names for directories</label>
+ <default>Make,Make install,CVS Update</default>
+ </entry>
+ <entry name="DirCommands" type="StringList">
+ <label>List of commands for directories</label>
+ <default>make,make install,cvs update</default>
+ </entry>
+ <entry name="FileCommandNames" type="StringList">
+ <label>List of command names for files</label>
+ <default>Start application,Compile,CVS Conflict Resolution</default>
+ </entry>
+ <entry name="FileCommands" type="StringList">
+ <label>List of commands for files</label>
+ <default>@PACKAGE@,msgfmt -o @PACKAGE@.gmo @PACKAGE@.po,cervisia @PODIR@ --resolve @PACKAGE@.po</default>
+ </entry>
+ <entry name="IndexWords" type="Bool">
+ <label>If the file cache should contain also index of words for faster searching</label>
+ <default>false</default>
+ </entry>
+ <entry name="KillCmdOnExit" type="Bool">
+ <label>If the Catalog Manager should kill all running its gettext tools at exit</label>
+ <default>true</default>
+ </entry>
+ <entry name="msgfmt" type="Bool">
+ <label></label>
+ <default>true</default>
+ </entry>
+ <entry name="Marker" type="StringList">
+ <label>List of files marked</label>
+ </entry>
+ <entry name="OpenWindow" type="Bool">
+ <label>If the files should be open in new KBabel editor windows</label>
+ <default>false</default>
+ </entry>
+ <entry name="PoBaseDir" type="String">
+ <label>The base directory for PO files (translations)</label>
+ <default></default>
+ </entry>
+ <entry name="PotBaseDir" type="String">
+ <label>The base directory for POT files (templates to be translated)</label>
+ <default></default>
+ </entry>
+ <entry name="ShowTotalColumn" type="Bool">
+ <label>
+ </label>
+ <default>true</default>
+ </entry>
+ <entry name="ShowCVSColumn" type="Bool">
+ <label>
+ </label>
+ <default>true</default>
+ </entry>
+ <entry name="ShowFlagColumn" type="Bool">
+ <label>
+ </label>
+ <default>true</default>
+ </entry>
+ <entry name="ShowFuzzyColumn" type="Bool">
+ <label>
+ </label>
+ <default>true</default>
+ </entry>
+ <entry name="ShowRevisionColumn" type="Bool">
+ <label>
+ </label>
+ <default>true</default>
+ </entry>
+ <entry name="ShowTranslatorColumn" type="Bool">
+ <label>
+ </label>
+ <default>true</default>
+ </entry>
+ <entry name="ShowUntranslatedColumn" type="Bool">
+ <label>
+ </label>
+ <default>true</default>
+ </entry>
+ <entry name="ValidationIgnoreURL" type="String">
+ <label>
+ </label>
+ <default code="true">KBabel::Defaults::CatalogManager::ignoreURL()</default>
+ </entry>
+ </group>
+ <group name="Header">
+ <entry name="AuthorEmail" type="String">
+ <label>Email of the translator</label>
+ <default code="true">Defaults::Identity::authorEmail()</default>
+ </entry>
+ <entry name="AuthorName" type="String">
+ <label>Name of the translator (non-localized)</label>
+ <default code="true">Defaults::Identity::authorName()</default>
+ </entry>
+ <entry name="AutoSaveDelay" type="UInt">
+ <label>Delay in minutes between autosaves. 0 disables autosave.</label>
+ <default>0</default>
+ </entry>
+ <entry name="AutoSyntaxCheck" type="Bool">
+ <label>If the syntax should be checked before save</label>
+ <default>true</default>
+ </entry>
+ <entry name="AutoUpdate" type="Bool">
+ <label>If the header should be automatically updated on save</label>
+ <default>true</default>
+ </entry>
+ <entry name="CheckPluralArgument" type="Bool">
+ <label>If the plural argument is required to be a part of translation</label>
+ <default>true</default>
+ </entry>
+ <entry name="CustomDateFormat" type="String">
+ <label>Custom date format used if DateFormat specifies that</label>
+ <default>%Y-%m-%d %H:%M%z</default>
+ </entry>
+ <entry name="DateFormat" type="Enum">
+ <label>Format of the dates stored</label>
+ <choices>
+ <choice name="Custom"/>
+ <choice name="Default"/>
+ <choice name="Local"/>
+ </choices>
+ <default>Default</default>
+ </entry>
+ <entry name="DescriptionString" type="String">
+ <label>Description of the translation</label>
+ <default>translation of @PACKAGE@.po to @LANGUAGE@</default>
+ </entry>
+ <entry name="Encoding" type="Enum">
+ <label>The encoding of the file</label>
+ <choices>
+ <choice name="Locale"/>
+ <choice name="UTF8"/>
+ <choice name="UTF16"/>
+ </choices>
+ <default>UTF8</default>
+ </entry>
+ <entry name="FSFCopyright" type="Enum">
+ <label>The way how to handle Free Software Foundation header</label>
+ <choices>
+ <choice name="Remove"/>
+ <choice name="Update"/>
+ <choice name="NoChange"/>
+ <choice name="RemoveLine"/>
+ </choices>
+ <default>Update</default>
+ </entry>
+ <entry name="Language" type="String">
+ <label>English name of the language</label>
+ <default></default>
+ </entry>
+ <entry name="LanguageCode" type="String">
+ <label>ISO 631 language code</label>
+ <default code="true">Defaults::Identity::languageCode()</default>
+ </entry>
+ <entry name="LocalAuthorName" type="String">
+ <label>Localized name of the author</label>
+ <default></default>
+ </entry>
+ <entry name="Mailinglist" type="String">
+ <label>Mailing list for i18n of the langauge</label>
+ <default code="true">Defaults::Identity::mailingList()</default>
+ </entry>
+ <entry name="PluralForms" type="UInt">
+ <label>Number of plural forms for the language</label>
+ <default>2</default>
+ </entry>
+ <entry name="PluralFormsHeader" type="String">
+ <label>Plural forms specification for GNU gettext</label>
+ <default></default>
+ </entry>
+ <entry name="ProjectString" type="String">
+ <label>Macro-based string to fill Project GNU header</label>
+ <default>@PACKAGE@</default>
+ </entry>
+ <entry name="SaveObsolete" type="Bool">
+ <label>If the obsolete translation entries should be saved</label>
+ <default>false</default>
+ </entry>
+ <entry name="Timezone" type="String">
+ <label>Timezone of the translation (needed for updating time stamps)</label>
+ <default code="true">Defaults::Identity::timezone()</default>
+ </entry>
+ <entry name="UpdateCharset" type="Bool">
+ <label>
+ </label>
+ <default>true</default>
+ </entry>
+ <entry name="UpdateEncoding" type="Bool">
+ <label>
+ </label>
+ <default>true</default>
+ </entry>
+ <entry name="UpdateLanguageTeam" type="Bool">
+ <label>
+ </label>
+ <default>true</default>
+ </entry>
+ <entry name="UpdateLastTranslator" type="Bool">
+ <label>
+ </label>
+ <default>true</default>
+ </entry>
+ <entry name="UpdateProject" type="Bool">
+ <label>
+ </label>
+ <default>true</default>
+ </entry>
+ <entry name="UpdateRevisionDate" type="Bool">
+ <label>
+ </label>
+ <default>true</default>
+ </entry>
+ <entry name="UpdateDescription" type="Bool">
+ <label>
+ </label>
+ <default>true</default>
+ </entry>
+ <entry name="UpdateTranslatorCopyright" type="Bool">
+ <label>
+ </label>
+ <default>true</default>
+ </entry>
+ <entry name="UseOldEncoding" type="Bool">
+ <label>If the saving should preserve the encoding of the file, if already defined
+ </label>
+ <default>true</default>
+ </entry>
+ </group>
+ <group name="Misc">
+ <entry name="AccelMarker" type="String">
+ <label>Marker for accelerators</label>
+ <default>&amp;</default>
+ </entry>
+ <entry name="BZipCompression" type="Bool">
+ <label>If the files should be compressed for mailing</label>
+ <default>true</default>
+ </entry>
+ <entry name="CompressSingleFile" type="Bool">
+ <label>If even single file should be compressed for mailing</label>
+ <default>true</default>
+ </entry>
+ <entry name="ContextInfo" type="String">
+ <label>Regular expression for identifying a context information in original text</label>
+ <default>^_:((?!\\n\n).)+\\n\n</default>
+ </entry>
+ <entry name="MailArchiveNames" type="StringList">
+ <label>List of recent mailed archives</label>
+ <default></default>
+ </entry>
+ <entry name="SingularPlural" type="String">
+ <label>Regular expression for identifying a KDE plural form</label>
+ <default>_n:\s</default>
+ </entry>
+ <entry name="DiffBaseDir" type="String">
+ <label>
+ </label>
+ <default></default>
+ </entry>
+ <entry name="UseDBForDiff" type="Enum">
+ <label>
+ </label>
+ <choices>
+ <choice name="File"/>
+ <choice name="Database"/>
+ <choice name="Msgstr"/>
+ </choices>
+ <default>Database</default>
+ </entry>
+ </group>
+ <group name="Project">
+ <entry name="Name" type="String">
+ <label>Name of the project</label>
+ <default></default>
+ </entry>
+ <entry name="Version" type="String">
+ <label>Version of the configuration file</label>
+ <default></default>
+ </entry>
+ </group>
+ <group name="Spellcheck">
+ <entry name="IgnoreURL" type="String">
+ <label>
+ </label>
+ <default code="true">Defaults::Spellcheck::ignoreURL()</default>
+ </entry>
+ <entry name="NoRootAffix" type="Bool">
+ <label>
+ </label>
+ <default code="true">Defaults::Spellcheck::noRootAffix()</default>
+ </entry>
+ <entry name="OnFlySpellCheck" type="Bool">
+ <label>
+ </label>
+ <default>true</default>
+ </entry>
+ <entry name="RememberIgnored" type="Bool">
+ <label>
+ </label>
+ <default>true</default>
+ </entry>
+ <entry name="RunTogether" type="Bool">
+ <label>
+ </label>
+ <default code="true">Defaults::Spellcheck::runTogether()</default>
+ </entry>
+ <entry name="SpellClient" type="UInt">
+ <label>
+ </label>
+ <default code="true">Defaults::Spellcheck::spellClient()</default>
+ </entry>
+ <entry name="SpellDictionary" type="String">
+ <label>
+ </label>
+ <default code="true">Defaults::Spellcheck::spellDictionary()</default>
+ </entry>
+ <entry name="SpellEncoding" type="UInt">
+ <label>
+ </label>
+ <default code="true">Defaults::Spellcheck::spellEncoding()</default>
+ </entry>
+ </group>
+ <group name="Tags">
+ <entry name="TagExpressions" type="String">
+ <label>
+ </label>
+ <default code="yes">Defaults::Tags::tagExpressions()</default>
+ </entry>
+ </group>
+ <group name="SourceContext">
+ <entry name="CodeRoot" type="String">
+ <default></default>
+ </entry>
+ <entry name="Paths" type="StringList">
+ <default>@PACKAGEDIR@/@PACKAGE@/@COMMENTPATH@,@CODEROOT@/@PACKAGEDIR@/@PACKAGE@/@COMMENTPATH@,@CODEROOT@/@PACKAGE@/@COMMENTPATH@,@POFILEDIR@/@COMMENTPATH@,@POFILEDIR@/../@COMMENTPATH@</default>
+ </entry>
+ </group>
+</kcfg>
diff --git a/kbabel/common/kbprojectsettings.kcfgc b/kbabel/common/kbprojectsettings.kcfgc
new file mode 100644
index 00000000..bf7df895
--- /dev/null
+++ b/kbabel/common/kbprojectsettings.kcfgc
@@ -0,0 +1,7 @@
+File=kbprojectsettings.kcfg
+NameSpace=KBabel
+ClassName=ProjectSettingsBase
+Singleton=false
+Mutators=true
+GlobalEnums=true
+
diff --git a/kbabel/common/libgettext/Makefile.am b/kbabel/common/libgettext/Makefile.am
new file mode 100644
index 00000000..eca54fda
--- /dev/null
+++ b/kbabel/common/libgettext/Makefile.am
@@ -0,0 +1,15 @@
+# this might be a naive way of seeing it, but
+# automake does not support C++ flex files.
+#LEX_OUTPUT_ROOT = lex.GettextBase
+#AM_LFLAGS = -+
+
+CLEANFILES = pofiles.cc
+
+noinst_LTLIBRARIES = libgettext.la
+
+libgettext_la_SOURCES = pofiles.cc
+
+pofiles.cc: $(srcdir)/pofiles.ll
+ $(LEX) -+ -opofiles.cc $(srcdir)/pofiles.ll
+
+noinst_HEADERS = tokens.h pofiles.h
diff --git a/kbabel/common/libgettext/pofiles.h b/kbabel/common/libgettext/pofiles.h
new file mode 100644
index 00000000..cf2e3ec8
--- /dev/null
+++ b/kbabel/common/libgettext/pofiles.h
@@ -0,0 +1,52 @@
+/*
+ This file is part of KBabel
+
+ Copyright (c) 2005 by Stanislav Visnovsky <visnovsky@kde.org>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the 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, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+ In addition, as a special exception, the copyright holders give
+ permission to link the code of this program with any edition of
+ the Qt library by Trolltech AS, Norway (or with modified versions
+ of Qt that use the same license as Qt), and distribute linked
+ combinations including the two. You must obey the GNU General
+ Public License in all respects for all of the code used other than
+ Qt. If you modify this file, you may extend this exception to
+ your version of the file, but you are not obligated to do so. If
+ you do not wish to do so, delete this exception statement from
+ your version.
+
+*/
+
+#ifndef POFILES_H
+#define POFILES_H
+
+#undef yyFlexLexer
+#define yyFlexLexer GettextBaseFlexLexer
+#include <FlexLexer.h>
+
+class GettextFlexLexer: public GettextBaseFlexLexer {
+public:
+ int lastToken;
+
+ GettextFlexLexer(std::istream*stream) : GettextBaseFlexLexer(stream) {}
+
+ int yylex()
+ {
+ return lastToken = GettextBaseFlexLexer::yylex();
+ }
+};
+
+#endif
diff --git a/kbabel/common/libgettext/pofiles.ll b/kbabel/common/libgettext/pofiles.ll
new file mode 100644
index 00000000..7466487a
--- /dev/null
+++ b/kbabel/common/libgettext/pofiles.ll
@@ -0,0 +1,107 @@
+
+/*
+ This file is a part of KBabel
+
+ Copyright (c) 2005 by Stanislav Visnovsky <visnovsky@kde.org>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the 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, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+ In addition, as a special exception, the copyright holders give
+ permission to link the code of this program with any edition of
+ the Qt library by Trolltech AS, Norway (or with modified versions
+ of Qt that use the same license as Qt), and distribute linked
+ combinations including the two. You must obey the GNU General
+ Public License in all respects for all of the code used other than
+ Qt. If you modify this file, you may extend this exception to
+ your version of the file, but you are not obligated to do so. If
+ you do not wish to do so, delete this exception statement from
+ your version.
+
+*/
+
+%{
+#define YY_NO_UNPUT
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <stdlib.h>
+
+#ifdef HAVE_STRINGS_H
+#include <strings.h>
+#endif
+
+#ifdef HAVE_STRING_H
+#include <string.h>
+#endif
+
+#include "tokens.h"
+
+
+%}
+
+%option prefix="GettextBase"
+
+%option noyywrap
+
+/* Any end of line */
+EOL [\r\n]
+/* No end of line */
+NOEOL [^\r\n]
+
+%%
+
+
+
+[ ]*{EOL}+ ; /* This catches empty lines or a LF after a CR */
+
+msgid {
+ return T_MSGID;
+ }
+msgid_plural {
+ return T_MSGIDPLURAL;
+ }
+msgstr\[[0-9]+\] {
+ return T_MSGSTR;
+ }
+msgstr {
+ return T_MSGSTR;
+ }
+msgctxt {
+ return T_MSGCTXT;
+ }
+#~{NOEOL}* {
+ return T_OBSOLETE;
+ }
+
+#{NOEOL}* {
+ return T_COMMENT;
+ }
+
+\"({NOEOL}*(\\\")?)*\"{EOL} {
+ yytext[strlen(yytext)-2] = 0;
+ yytext++;
+ return T_STRING;
+ }
+
+[a-z]+ |
+. ;
+
+<<EOF>> {
+ return T_EOF;
+ }
+
+%%
diff --git a/kbabel/common/libgettext/tokens.h b/kbabel/common/libgettext/tokens.h
new file mode 100644
index 00000000..dfbf693d
--- /dev/null
+++ b/kbabel/common/libgettext/tokens.h
@@ -0,0 +1,45 @@
+/*
+ This file is a part of KBabel
+
+ Copyright (c) 2005 by Stanislav Visnovsky <visnovsky@kde.org>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the 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, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+ In addition, as a special exception, the copyright holders give
+ permission to link the code of this program with any edition of
+ the Qt library by Trolltech AS, Norway (or with modified versions
+ of Qt that use the same license as Qt), and distribute linked
+ combinations including the two. You must obey the GNU General
+ Public License in all respects for all of the code used other than
+ Qt. If you modify this file, you may extend this exception to
+ your version of the file, but you are not obligated to do so. If
+ you do not wish to do so, delete this exception statement from
+ your version.
+
+*/
+
+#ifndef POTOKENS_H
+#define POTOKENS_H
+
+#define T_EOF 256
+#define T_COMMENT 257
+#define T_STRING 258
+#define T_MSGID 259
+#define T_MSGSTR 260
+#define T_OBSOLETE 261
+#define T_MSGIDPLURAL 262
+#define T_MSGCTXT 263
+
+#endif
diff --git a/kbabel/common/msgfmt.cpp b/kbabel/common/msgfmt.cpp
new file mode 100644
index 00000000..ef8ca895
--- /dev/null
+++ b/kbabel/common/msgfmt.cpp
@@ -0,0 +1,147 @@
+/* ****************************************************************************
+ This file is part of KBabel
+
+ Copyright (C) 1999-2000 by Matthias Kiefer
+ <matthias.kiefer@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.
+
+ 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, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+ In addition, as a special exception, the copyright holders give
+ permission to link the code of this program with any edition of
+ the Qt library by Trolltech AS, Norway (or with modified versions
+ of Qt that use the same license as Qt), and distribute linked
+ combinations including the two. You must obey the GNU General
+ Public License in all respects for all of the code used other than
+ Qt. If you modify this file, you may extend this exception to
+ your version of the file, but you are not obligated to do so. If
+ you do not wish to do so, delete this exception statement from
+ your version.
+
+**************************************************************************** */
+#include "msgfmt.h"
+
+#include <kapplication.h>
+#include <kprocess.h>
+
+#include <qfileinfo.h>
+#include <qdir.h>
+#include <qfile.h>
+#include <qregexp.h>
+#include <qtextstream.h>
+#include <qstring.h>
+
+#include <stdlib.h>
+
+using namespace KBabel;
+
+Msgfmt::Msgfmt(QObject* parent,const char* name)
+ : QObject(parent , name)
+{
+}
+
+Msgfmt::Status Msgfmt::checkSyntax(QString file,QString& output, bool gnu)
+{
+ Status stat=Ok;
+ // this method does not return the right retrun values at the moment :-(
+
+ KProcess proc;
+
+ connect(&proc,SIGNAL(receivedStdout(KProcess*, char*, int)),
+ this,SLOT(addToOutput(KProcess*,char *, int )));
+ connect(&proc,SIGNAL(receivedStderr(KProcess *, char *, int)),
+ this,SLOT(addToOutput(KProcess*,char *, int)));
+
+ // remove last output
+ _output="";
+
+
+ proc << "msgfmt" << "--statistics" << "-o" << "/dev/null" << file;
+
+ if( gnu )
+ {
+ proc << "-vc";
+ }
+
+ if(!proc.start(KProcess::Block,KProcess::Stderr))
+ {
+ stat=NoExecutable;
+ }
+ else if(proc.normalExit())
+ {
+ if( proc.exitStatus() || _output.contains(QRegExp("^.+:\\d+:")) ) // little workaround :-(
+ stat=SyntaxError;
+ }
+ else
+ stat=Error;
+
+ output=_output;
+
+
+ return stat;
+}
+
+Msgfmt::Status Msgfmt::checkSyntaxInDir(QString dir,QString regexp,QString& output)
+{
+ Status stat=Ok;
+
+ // this method does not return the right return values at the moment :-(
+ KProcess proc;
+ proc.setUseShell(true);
+
+ connect(&proc,SIGNAL(receivedStdout(KProcess*, char*, int)),
+ this,SLOT(addToOutput(KProcess*,char *, int )));
+ connect(&proc,SIGNAL(receivedStderr(KProcess *, char *, int)),
+ this,SLOT(addToOutput(KProcess*,char *, int)));
+
+ // remove last output
+ _output="";
+
+ proc << "IFS='\n'; msgfmt --statistics -o /dev/null "
+ "$(find" << KProcess::quote(dir) << "-name" << KProcess::quote(regexp) << ")";
+
+ if(!proc.start(KProcess::Block,KProcess::Stderr))
+ {
+ stat=NoExecutable;
+ }
+ else if(proc.normalExit())
+ {
+ if( proc.exitStatus() || _output.contains(QRegExp("^.+:\\d+:")) ) // little workaround :-(
+ stat=SyntaxError;
+ }
+ else
+ stat=Error;
+
+ output=_output;
+
+
+ return stat;
+}
+
+
+
+void Msgfmt::addToOutput(KProcess*,char *buffer, int buflen)
+{
+ QString newString = QString::fromLocal8Bit(buffer, buflen);
+
+ _output+=newString;
+}
+
+
+QString Msgfmt::tempSaveName()
+{
+ return kapp->tempSaveName("/tmp/kbabel_msgfmt.po");
+}
+
+#include "msgfmt.moc"
diff --git a/kbabel/common/msgfmt.h b/kbabel/common/msgfmt.h
new file mode 100644
index 00000000..bf983b2f
--- /dev/null
+++ b/kbabel/common/msgfmt.h
@@ -0,0 +1,65 @@
+/* ****************************************************************************
+ This file is part of KBabel
+
+ Copyright (C) 1999-2000 by Matthias Kiefer
+ <matthias.kiefer@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.
+
+ 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, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+ In addition, as a special exception, the copyright holders give
+ permission to link the code of this program with any edition of
+ the Qt library by Trolltech AS, Norway (or with modified versions
+ of Qt that use the same license as Qt), and distribute linked
+ combinations including the two. You must obey the GNU General
+ Public License in all respects for all of the code used other than
+ Qt. If you modify this file, you may extend this exception to
+ your version of the file, but you are not obligated to do so. If
+ you do not wish to do so, delete this exception statement from
+ your version.
+
+**************************************************************************** */
+#ifndef MSGFMT_H
+#define MSGFMT_H
+
+#include <qobject.h>
+#include <kdemacros.h>
+
+class KProcess;
+class QString;
+
+namespace KBabel
+{
+
+class KDE_EXPORT Msgfmt : private QObject
+{
+ Q_OBJECT
+public:
+ enum Status{NoExecutable,Ok,SyntaxError,HeaderError,Error,Unsupported};
+ Msgfmt(QObject* parent=0,const char* name=0);
+
+ Status checkSyntax(QString file,QString& output, bool gnu = false);
+ Status checkSyntaxInDir(QString dir,QString regexp,QString& output);
+
+private slots:
+ void addToOutput(KProcess*,char *buffer, int buflen);
+
+private:
+ static QString tempSaveName();
+ QString _output;
+};
+
+}
+
+#endif // MSGFMT_H
diff --git a/kbabel/common/pluralforms.h b/kbabel/common/pluralforms.h
new file mode 100644
index 00000000..f65dba01
--- /dev/null
+++ b/kbabel/common/pluralforms.h
@@ -0,0 +1,38 @@
+/* ****************************************************************************
+ This file is part of KBabel
+
+ Copyright (C) 2002-2005 by Stanislav Visnovsky
+ <visnovsky@kde.org>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the 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, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+ In addition, as a special exception, the copyright holders give
+ permission to link the code of this program with any edition of
+ the Qt library by Trolltech AS, Norway (or with modified versions
+ of Qt that use the same license as Qt), and distribute linked
+ combinations including the two. You must obey the GNU General
+ Public License in all respects for all of the code used other than
+ Qt. If you modify this file, you may extend this exception to
+ your version of the file, but you are not obligated to do so. If
+ you do not wish to do so, delete this exception statement from
+ your version.
+
+**************************************************************************** */
+#ifndef PLURALFORMS_H
+#define PLURALFORMS_H
+
+enum PluralFormType{NoPluralForm, Gettext, KDESpecific};
+
+#endif
diff --git a/kbabel/common/poinfo.cpp b/kbabel/common/poinfo.cpp
new file mode 100644
index 00000000..b7beba7d
--- /dev/null
+++ b/kbabel/common/poinfo.cpp
@@ -0,0 +1,781 @@
+/*
+ This file is part of KBabel
+ Copyright (C) 2002 Stefan Asserhäll <stefan.asserhall@telia.com>
+ 2003-2005 Stanislav Visnovsky <visnovsky@kde.org>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the 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, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+ In addition, as a special exception, the copyright holders give
+ permission to link the code of this program with any edition of
+ the Qt library by Trolltech AS, Norway (or with modified versions
+ of Qt that use the same license as Qt), and distribute linked
+ combinations including the two. You must obey the GNU General
+ Public License in all respects for all of the code used other than
+ Qt. If you modify this file, you may extend this exception to
+ your version of the file, but you are not obligated to do so. If
+ you do not wish to do so, delete this exception statement from
+ your version.
+
+*/
+
+#include "poinfo.h"
+
+#include "catalogitem.h"
+#include "findoptions.h"
+#include "msgfmt.h"
+#include "resources.h"
+
+#include <kapplication.h>
+#include <kio/netaccess.h>
+#include <kstandarddirs.h>
+#include <ksavefile.h>
+
+#include <qdatastream.h>
+#include <qdatetime.h>
+#include <qdict.h>
+#include <qfile.h>
+#include <qfileinfo.h>
+#include <qregexp.h>
+#include <qtextcodec.h>
+
+#include "libgettext/pofiles.h"
+#include "libgettext/tokens.h"
+
+#include <fstream>
+
+using namespace KBabel;
+
+// A PO-file cache item
+struct poInfoCacheItem
+{
+ PoInfo info;
+ QDateTime lastModified;
+};
+
+inline QDataStream& operator << ( QDataStream& stream, poInfoCacheItem* item )
+{
+ // Note: if you change anything here, do not forget to increase the #define POINFOCACHE_VERSION
+ stream << item->info.total;
+ stream << item->info.fuzzy;
+ stream << item->info.untranslated;
+ stream << item->info.project;
+ stream << item->info.creation;
+ stream << item->info.revision;
+ stream << item->info.lastTranslator;
+ stream << item->info.languageTeam;
+ stream << item->info.mimeVersion;
+ stream << item->info.contentType;
+ stream << item->info.encoding;
+ stream << item->info.others;
+ stream << item->info.headerComment;
+ stream << item->lastModified;
+ return stream;
+}
+
+inline QDataStream& operator >> ( QDataStream& stream, poInfoCacheItem* item )
+{
+ stream >> item->info.total;
+ stream >> item->info.fuzzy;
+ stream >> item->info.untranslated;
+ stream >> item->info.project;
+ stream >> item->info.creation;
+ stream >> item->info.revision;
+ stream >> item->info.lastTranslator;
+ stream >> item->info.languageTeam;
+ stream >> item->info.mimeVersion;
+ stream >> item->info.contentType;
+ stream >> item->info.encoding;
+ stream >> item->info.others;
+ stream >> item->info.headerComment;
+ stream >> item->lastModified;
+ return stream;
+}
+
+// Cache of PO-file items
+static QDict<poInfoCacheItem> _poInfoCache;
+
+// File name of cache
+static QString _poInfoCacheName;
+
+// flag to stop current reading
+bool PoInfo::stopStaticRead;
+
+bool PoInfo::_gettextPluralForm;
+
+// Note: We only read the cache file if the data seems usable. If not, we will re-generate the data.
+void PoInfo::cacheRead()
+{
+ QFile cacheFile( _poInfoCacheName );
+ if( cacheFile.open( IO_ReadOnly ) ) {
+ QDataStream s( &cacheFile );
+
+ // Check the file cache version.
+ // If it is not the current version, we do not read the cache file
+ Q_UINT32 version;
+ s >> version;
+ if( version != POINFOCACHE_VERSION ) {
+ // Wrong POINFOCACHE_VERSION, so abort
+ kdDebug(KBABEL) << "Wrong cache file version: " << version << endl;
+ return;
+ }
+
+ /*
+ * Check the version of the QDataStream with which the cache file was written
+ *
+ * If the cache file was written by an incompatible future version of Qt,
+ * the cache file will not be read.
+ *
+ * On the other side, a cache file written by a previous version of Qt can be read,
+ * by setting the version of the QDataStream used.
+ */
+ Q_INT32 qdatastreamVersion;
+ s >> qdatastreamVersion;
+ if( qdatastreamVersion > 0 && qdatastreamVersion <= s.version() ) {
+ s.setVersion( qdatastreamVersion );
+ }
+ else {
+ // QDataStream version seems stupid, so abort
+ kdDebug(KBABEL) << "Wrong QDataStream version: " << qdatastreamVersion << endl;
+ return;
+ }
+
+ QString url;
+ while( !s.atEnd() ) {
+ poInfoCacheItem* item = new poInfoCacheItem;
+ s >> url;
+ s >> item;
+ _poInfoCache.insert( url, item );
+ }
+ cacheFile.close();
+ }
+}
+
+void PoInfo::cacheWrite()
+{
+ // We use KSaveFile as otherwise we have no management about the cache file's integrity
+ // (especially if two instances would write into the same cache file)
+ KSaveFile cacheFile( _poInfoCacheName );
+
+ QDataStream* stream = cacheFile.dataStream();
+
+ if( stream ) {
+
+ // Write the cache file version
+ // We choose to fix a format (Q_UINT32) for compatibility (Qt version, platforms, architectures)
+ const Q_UINT32 version = POINFOCACHE_VERSION;
+ *stream << version;
+
+ // Write the version of the QDataStream
+ // Here too we choose a fixed format (Q_INT32) for compatibility
+ const Q_INT32 qdatastreamVersion = stream->version();
+ *stream << qdatastreamVersion;
+
+ QDictIterator<poInfoCacheItem> it( _poInfoCache ); // iterator for dict
+ for ( ; it.current(); ++it ) {
+ if( QFile::exists( it.currentKey() ) ) {
+ *stream << it.currentKey();
+ *stream << it.current();
+ }
+ }
+ if ( !cacheFile.close() ) {
+ kdWarning(KBABEL) << "Could not write cache file: " << _poInfoCacheName << endl;
+ }
+ }
+ else {
+ kdWarning(KBABEL) << "Could not create QDataStream for cache file: " << _poInfoCacheName << endl;
+ cacheFile.abort();
+ }
+}
+
+bool PoInfo::cacheFind(const QString url, PoInfo& info)
+{
+ // Read cache if it has not been read, and set up post routine to write it
+ static bool _cacheIsRead = false;
+ if( !_cacheIsRead ) {
+ _cacheIsRead = true;
+ _poInfoCacheName = locateLocal("cache", "kbabel/poinfocache");
+ cacheRead();
+ }
+
+ poInfoCacheItem *item = _poInfoCache.find( url );
+ if( item ) {
+ QFileInfo fi( url );
+
+ if( fi.lastModified() == item->lastModified ) {
+ info = item->info;
+ return true;
+ }
+ }
+ return false;
+}
+
+void PoInfo::cacheSave(const QString url, PoInfo& info)
+{
+ poInfoCacheItem *item = new poInfoCacheItem;
+ QFileInfo fi( url );
+
+ item->info = info;
+ item->lastModified = fi.lastModified();
+ _poInfoCache.insert( url, item );
+}
+
+QTextCodec* PoInfo::codecForFile(QString gettextHeader)
+{
+ QRegExp regexp("Content-Type:\\s*\\w+/[-\\w]+;?\\s*charset\\s*=\\s*(\\S+)\\s*\\\\n");
+ if( regexp.search(gettextHeader) == -1 )
+ {
+ kdDebug(KBABEL) << "no charset entry found" << endl;
+ return 0;
+ }
+
+ const QString charset = regexp.cap(1);
+ kdDebug(KBABEL) << "charset: " << charset << endl;
+
+ QTextCodec* codec=0;
+
+ if(!charset.isEmpty())
+ {
+ // "CHARSET" is the default charset entry in a template (pot).
+ // characters in a template should be either pure ascii or
+ // at least utf8, so utf8-codec can be used for both.
+ if( charset == "CHARSET")
+ {
+ codec=QTextCodec::codecForName("utf8");
+ kdDebug(KBABEL)
+ << QString("file seems to be a template: using utf8 encoding.")
+ << endl;
+ }
+ else
+ {
+ codec=QTextCodec::codecForName(charset.latin1());
+ }
+
+ if(!codec)
+ {
+ kdWarning(KBABEL) << "charset found, but no codec available, using UTF8 instead" << endl;
+ codec=QTextCodec::codecForName("utf8");
+ }
+ }
+ else
+ {
+ // No charset? So it is probably ASCII, therefore UTF-8
+ kdWarning(KBABEL) << "No charset defined! Assuming UTF-8!" << endl;
+ codec=QTextCodec::codecForName("utf8");
+ }
+
+ return codec;
+}
+
+PoInfo PoInfo::headerInfo(const CatalogItem& headerItem)
+{
+ // A header of a Gettext .po/.pot file is made of entries of the kind:
+ // key:value\n
+ // Note that the "line" defined by the \n can be different than the line of the file.
+
+ // We join all lines of the header and then split the result again at the \n sequence
+ const QStringList header=QStringList::split("\\n",headerItem.msgstrAsList().join(QString()));
+
+ PoInfo info;
+
+ // extract information from the header
+ QStringList::const_iterator it;
+
+ // The header of a Gettext .po file is consisted of lines of key and value
+ for(it=header.begin();it!=header.end();++it)
+ {
+ bool knownKey=false;
+ // We search for the : character, which is the separator between key and value
+ const int res=(*it).find(':');
+ if (res>=0)
+ {
+ knownKey=true; // We know most keys, if not it will be changed to false in the "else" case
+ const QString key=(*it).left(res).simplifyWhiteSpace();
+ QString value=(*it).mid(res+1);
+ // "Chop" the \n at the end
+ if (value.endsWith("\\n"))
+ value.remove(value.length()-2,2); // ### Qt4: use value.chop(2)
+ value=value.simplifyWhiteSpace();
+ kdDebug(KBABEL) << "Header key: " << key << " value: " << value << endl;
+ if (key=="Project-Id-Version")
+ info.project=value;
+ else if (key=="POT-Creation-Date")
+ info.creation=value;
+ else if (key=="PO-Revision-Date")
+ info.revision=value;
+ else if (key=="Last-Translator")
+ info.lastTranslator=value;
+ else if (key=="Language-Team")
+ info.languageTeam=value;
+ else if (key=="MIME-Version")
+ info.mimeVersion=value;
+ else if (key=="Content-Type")
+ info.contentType=value;
+ else if (key=="Content-Transfer-Encoding")
+ info.encoding=value;
+ else
+ {
+ kdDebug(KBABEL)<<"Unknown key: "<<key<<endl;
+ knownKey=false;
+ }
+ }
+ if (!knownKey)
+ {
+ QString line=(*it);
+
+ if(line.right(2)=="\\n")
+ line.remove(line.length()-2,2); // ### Qt4: use value.chop(2)
+
+ if(!info.others.isEmpty())
+ info.others+='\n';
+
+ info.others+=line.simplifyWhiteSpace();
+ }
+ }
+
+ info.headerComment=headerItem.comment();
+
+ return info;
+}
+
+
+ConversionStatus PoInfo::info(const QString& url, PoInfo& info, QStringList &wordList, bool updateWordList, bool interactive)
+{
+ return PoInfo::info( url, info, wordList, updateWordList, interactive, true);
+}
+
+ConversionStatus PoInfo::info(const QString& url, PoInfo& info, QStringList &wordList, bool updateWordList, bool interactive, bool msgfmt)
+{
+ stopStaticRead = false;
+
+ if( !updateWordList && PoInfo::cacheFind( url, info ) )
+ return OK;
+
+ QString target;
+ if(KIO::NetAccess::download(KURL( url ), target, 0))
+ {
+ QFile file(target);
+
+ if ( msgfmt )
+ {
+ // First check file with msgfmt to be sure, it is syntactically correct
+ Msgfmt msgfmt;
+ QString output;
+ Msgfmt::Status stat = msgfmt.checkSyntax( target , output );
+ if(stat == Msgfmt::SyntaxError)
+ {
+ KIO::NetAccess::removeTempFile(target);
+ return PARSE_ERROR;
+ }
+ }
+
+
+ std::ifstream* stream = new std::ifstream( file.name().local8Bit());
+ if( stream->is_open() )
+ {
+ CatalogItem temp;
+
+ info.total=0;
+ info.fuzzy=0;
+ info.untranslated=0;
+
+ GettextFlexLexer* lexer = new GettextFlexLexer( stream );
+
+ lexer->yylex();
+
+ // now parse the rest of the file
+ ConversionStatus success=OK;
+
+ while( lexer->lastToken != T_EOF && success==OK)
+ {
+ if( interactive ) kapp->processEvents(10);
+
+ if( stopStaticRead )
+ {
+ KIO::NetAccess::removeTempFile(target);
+ delete lexer;
+ delete stream;
+ return OK;
+ }
+
+ success=fastRead(temp,lexer,false);
+
+ if(success==OK || success==RECOVERED_PARSE_ERROR)
+ {
+ success=OK;
+
+ if( temp.comment().contains("\n#~") ) continue; // skip obsolete
+
+ if( temp.msgid().first().isEmpty()) //header
+ {
+ if( temp.isFuzzy() ) temp.removeFuzzy();
+
+ //find out the codec
+ QTextCodec* codec = codecForFile( temp.msgstr().first() );
+ if( !codec ) return PARSE_ERROR;
+
+ // convert from UTF-8 using codec
+ temp.setComment( codec->toUnicode(temp.comment().utf8()) );
+ temp.setMsgstr( codec->toUnicode(temp.msgstr().first().utf8()) );
+
+ PoInfo infoCounts = info;
+ info=PoInfo::headerInfo(temp);
+ info.total = infoCounts.total;
+ info.fuzzy = infoCounts.fuzzy;
+ info.untranslated = infoCounts.untranslated;
+ continue; // do not update counters and word list for header
+ }
+
+ info.total++;
+
+ if(temp.isFuzzy())
+ info.fuzzy++;
+ else if(temp.isUntranslated())
+ info.untranslated++;
+
+ if( updateWordList )
+ {
+ // FIXME: should care about plural forms in msgid
+ QString st = temp.msgid().first().simplifyWhiteSpace().lower();
+ QStringList sl = QStringList::split( ' ', st );
+ while(!sl.isEmpty())
+ {
+ QString w = sl.first();
+ sl.pop_front();
+ if( !wordList.contains(w) ) wordList.append( w );
+ }
+ st = temp.msgstr().join(" " ).simplifyWhiteSpace().lower();
+ sl = QStringList::split( ' ', st );
+ while(!sl.isEmpty())
+ {
+ QString w = sl.first();
+ sl.pop_front();
+ if( !wordList.contains(w) ) wordList.append( w );
+ }
+ st = temp.comment().simplifyWhiteSpace().lower();
+ sl = QStringList::split( ' ', st );
+ while(!sl.isEmpty())
+ {
+ QString w = sl.first();
+ sl.pop_front();
+ if( !wordList.contains(w) ) wordList.append( w );
+ }
+ }
+ }
+ }
+
+ delete lexer;
+ delete stream;
+
+ if(success==PARSE_ERROR)
+ {
+ KIO::NetAccess::removeTempFile(target);
+ return PARSE_ERROR;
+ }
+ }
+ else
+ {
+ delete stream;
+ KIO::NetAccess::removeTempFile(target);
+ return NO_PERMISSIONS;
+ }
+
+ KIO::NetAccess::removeTempFile(target);
+ if( target == url )
+ PoInfo::cacheSave( url, info );
+ return OK;
+ }
+ else
+ {
+ return OS_ERROR;
+ }
+
+ return OK;
+}
+
+bool PoInfo::findInFile( const QString& url, FindOptions options )
+{
+ enum {Begin, Comment, Msgid, Msgstr, Msgctxt} part = Begin;
+
+ stopStaticRead = false;
+ QString target;
+ if(KIO::NetAccess::download(KURL( url ), target, 0))
+ {
+ std::ifstream* stream = new std::ifstream( target.local8Bit());
+ if(stream->is_open())
+ {
+ KIO::NetAccess::removeTempFile(target);
+
+ GettextFlexLexer* lexer = new GettextFlexLexer( stream );
+
+ lexer->yylex();
+
+ // prepare the search
+
+ QString searchStr = options.findStr;
+ QRegExp regexp( searchStr );
+
+ if( options.isRegExp )
+ regexp.setCaseSensitive( options.caseSensitive );
+
+ // first read header
+ CatalogItem temp;
+
+ ConversionStatus status = fastRead( temp, lexer, true );
+ if( status != OK || !temp.msgid().first().isEmpty() )
+ {
+ delete lexer;
+ delete stream;
+ return false; // header is not at the beginning, broken file
+ }
+
+ QTextCodec* codec = codecForFile( temp.msgstr().first() );
+ if( !codec )
+ {
+ return false;
+ }
+
+ // now parse the rest of the file
+ QString text;
+ int pos,len;
+
+ while(lexer->lastToken != T_EOF)
+ {
+ switch( lexer->lastToken ) {
+ case T_COMMENT: {
+ part = Comment;
+ if( !options.inComment ) break;
+ text = codec->toUnicode(lexer->YYText());
+ if( options.isRegExp )
+ pos=regexp.search(text, 0 );
+ else
+ pos=text.find(searchStr,0,options.caseSensitive);
+ if( pos >= 0)
+ {
+ if( options.wholeWords) {
+ len = searchStr.length();
+ QString pre = text.mid(pos-1,1);
+ QString post = text.mid(pos+len,1);
+ if( !pre.contains( QRegExp("[a-zA-Z0-9]")) &&
+ !post.contains( QRegExp("[a-zA-Z0-9]") )
+ ) {
+ delete lexer;
+ delete stream;
+ return true;
+ }
+ }
+ else {
+ delete lexer;
+ delete stream;
+ return true;
+ };
+ }
+ break;
+ }
+ case T_STRING: {
+ if( part == Msgid && !options.inMsgid ) break;
+ else if( part == Msgstr && !options.inMsgstr ) break;
+ // HACK: We ignore any string following a msgctxt, as it does not change a statistic
+ else if( part == Msgctxt ) break;
+
+ text = codec->toUnicode(lexer->YYText());
+
+ if( options.ignoreContextInfo )
+ {
+ pos = options.contextInfo.search(text);
+ len = options.contextInfo.matchedLength();
+ if( pos >= 0 )
+ text.remove( pos, len );
+ }
+
+ if( options.ignoreAccelMarker )
+ {
+ pos = text.find( options.accelMarker );
+ if( pos >= 0 )
+ text.remove( pos, 1 );
+ }
+
+ if( options.isRegExp )
+ pos=regexp.search(text, 0 );
+ else
+ pos=text.find(searchStr,0,options.caseSensitive);
+
+ if( pos >= 0)
+ {
+ if( options.wholeWords) {
+ len = searchStr.length();
+ QString pre = text.mid(pos-1,1);
+ QString post = text.mid(pos+len,1);
+ if( !pre.contains( QRegExp("[a-zA-Z0-9]")) &&
+ !post.contains( QRegExp("[a-zA-Z0-9]") )
+ ) {
+ delete lexer;
+ delete stream;
+ return true;
+ }
+ }
+ else {
+ delete lexer;
+ delete stream;
+ return true;
+ };
+ }
+ break;
+ }
+ case T_MSGSTR: {
+ part = Msgstr;
+ break;
+ }
+ case T_MSGID:
+ case T_MSGIDPLURAL: {
+ kapp->processEvents(10);
+
+ // if stopped, return not found
+ if( stopStaticRead )
+ {
+ delete lexer;
+ delete stream;
+ return false;
+ }
+ part = Msgid;
+ break;
+ }
+ case T_MSGCTXT: {
+ part = Msgctxt;
+ break;
+ }
+ }
+ lexer->yylex();
+ }
+ delete lexer;
+ delete stream;
+ }
+ }
+ return false;
+}
+
+// this does not like any incorrect files
+ConversionStatus PoInfo::fastRead( CatalogItem& item, GettextFlexLexer *lexer, bool storeText)
+{
+ item.clear();
+ _gettextPluralForm = false;
+
+ // comment
+ if( lexer->lastToken == T_COMMENT )
+ {
+ QString _comment = QString::fromUtf8(lexer->YYText());
+ while( lexer->yylex() == T_COMMENT )
+ _comment += "\n"+QString::fromUtf8(lexer->YYText());
+ item.setComment( _comment );
+// kdDebug(KBABEL) << "Comment: " << _comment << endl;
+ }
+
+ //obsolete
+ if( lexer->lastToken == T_OBSOLETE ) {
+ lexer->yylex();
+ item.setComment("#~\n#~");
+ return OK;
+ }
+
+ // msgctxt
+ if( lexer->lastToken == T_MSGCTXT ) {
+ // HACK: we simply ignore the context, as it does not change a statistic
+ do {
+ lexer->yylex();
+ } while ( lexer->lastToken == T_STRING );
+ }
+
+ // msgid
+ if( lexer->lastToken != T_MSGID ) return PARSE_ERROR;
+
+ if( lexer->yylex() != T_STRING ) return PARSE_ERROR;
+ QStringList msgids = item.msgid();
+ QStringList::Iterator it = msgids.begin();
+ *it = QString::fromUtf8(lexer->YYText());
+ if( storeText )
+ while( lexer->yylex() == T_STRING )
+ (*it) += ("\n"+ QString::fromUtf8(lexer->YYText()) );
+ else {
+ if( lexer->yylex() == T_STRING ) // this is not header
+ {
+ *it = "SKIPPED";
+ while( lexer->yylex() == T_STRING );
+ }
+ }
+ item.setMsgid( msgids );
+
+// kdDebug(KBABEL) << "Msgid: " << *it << endl;
+
+ if( lexer->lastToken == T_MSGIDPLURAL )
+ {
+ _gettextPluralForm = true;
+ if( lexer->yylex() != T_STRING ) return PARSE_ERROR;
+ QStringList msgids = item.msgid();
+ it = msgids.fromLast();
+ *it = QString::fromUtf8(lexer->YYText());
+ if( storeText )
+ while( lexer->yylex() == T_STRING )
+ (*it)+="\n"+ QString::fromUtf8(lexer->YYText());
+ else while( lexer->yylex() == T_STRING );
+ item.setMsgid( msgids );
+// kdDebug(KBABEL) << "Msgid_plural: " << *it << endl;
+ }
+
+ // msgstr
+ if( lexer->lastToken != T_MSGSTR ) return PARSE_ERROR;
+
+ if( !_gettextPluralForm )
+ {
+ if( lexer->yylex() != T_STRING ) return PARSE_ERROR;
+
+ QStringList msgstrs = item.msgstr();
+ it = msgstrs.begin();
+ *it = QString::fromUtf8(lexer->YYText());
+ if( storeText || item.msgid().first().isEmpty() ) // if we should store the text or it is a header
+ while( lexer->yylex() == T_STRING )
+ (*it)+= ("\n"+ QString::fromUtf8(lexer->YYText()));
+ else
+ if( lexer->yylex() == T_STRING ) // check next token, whether it is really translated
+ {
+ *it = "SKIPPED";
+ while( lexer->yylex() == T_STRING );
+ }
+ item.setMsgstr( msgstrs );
+// kdDebug(KBABEL) << "Msgstr: " << *it << endl;
+ }
+ else
+ {
+ QStringList msgstrs = item.msgstr();
+ QString s = QString::fromUtf8(lexer->YYText());
+ while( lexer->lastToken == T_MSGSTR && s.contains( QRegExp("^msgstr\\[[0-9]+\\]" ) ) )
+ {
+ if( lexer->yylex() != T_STRING ) return PARSE_ERROR;
+ it = msgstrs.fromLast();
+ *it = QString::fromUtf8(lexer->YYText());
+
+ if( storeText )
+ do {
+ (*it)+="\n"+QString::fromUtf8(lexer->YYText());
+ } while( lexer->yylex() == T_STRING );
+ else while( lexer->yylex() == T_STRING );
+// kdDebug(KBABEL) << "Msgstr: " << *it << endl;
+ s = QString::fromUtf8(lexer->YYText());
+ }
+ item.setMsgstr( msgstrs );
+ }
+
+ return OK;
+}
+
+// kate: space-indent on; indent-width 4; replace-tabs on;
diff --git a/kbabel/common/poinfo.h b/kbabel/common/poinfo.h
new file mode 100644
index 00000000..21b8d72d
--- /dev/null
+++ b/kbabel/common/poinfo.h
@@ -0,0 +1,157 @@
+/*
+ This file is part of KBabel
+ Copyright (C) 2002 Stefan Asserhäll <stefan.asserhall@telia.com>
+ 2003-2005 Stanislav Visnovsky <visnovsky@kde.org>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the 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, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+ In addition, as a special exception, the copyright holders give
+ permission to link the code of this program with any edition of
+ the Qt library by Trolltech AS, Norway (or with modified versions
+ of Qt that use the same license as Qt), and distribute linked
+ combinations including the two. You must obey the GNU General
+ Public License in all respects for all of the code used other than
+ Qt. If you modify this file, you may extend this exception to
+ your version of the file, but you are not obligated to do so. If
+ you do not wish to do so, delete this exception statement from
+ your version.
+
+*/
+
+#ifndef POINFO_H
+#define POINFO_H
+
+
+#include "catalogfileplugin.h"
+
+#include <kdebug.h>
+
+#include <qstring.h>
+
+/**
+ * @brief File cache version number.
+ *
+ * @note If the existing file is outdated, it will not be read,
+ * instead we will overwrite it with a new file.
+ */
+#define POINFOCACHE_VERSION 2
+
+class GettextFlexLexer;
+
+namespace KBabel {
+
+class FindOptions;
+
+/**
+ * PO-file information class, with transparent caching of information.
+ */
+class KDE_EXPORT PoInfo
+{
+public:
+ int total;
+ int fuzzy;
+ int untranslated;
+
+ QString project;
+ QString creation;
+ QString revision;
+ QString lastTranslator;
+ QString languageTeam;
+ QString mimeVersion;
+ QString contentType;
+ QString encoding;
+ QString others;
+
+ QString headerComment;
+
+ /**
+ * Find PO-file information in the cache.
+ *
+ * @param url The URL of the PO-file.
+ * @param info Returned cached information.
+ * @return true if found, false otherwise.
+ */
+ static bool cacheFind(const QString url, PoInfo& info);
+
+ /**
+ * Save PO-file information in the cache.
+ *
+ * @param url The URL of the PO-file.
+ * @param info Information to save.
+ */
+ static void cacheSave(const QString url, PoInfo& info);
+
+ /**
+ * @brief Get information about the PO file
+ *
+ * @param url The path (not an URL) of the file
+ * @param info The information retrieved from the file
+ * @param wordList ???
+ * @param updateWordList ???
+ * @param interactive Can the function interact with the user?
+ * @param msgfmt Should each file be checked with Gettext's msgfmt before
+ * being parsed?
+ * @since KBabel 1.11 (KDE 3.5)
+ */
+ static ConversionStatus info(const QString& url,PoInfo& info, QStringList &wordList, bool updateWordList, bool interactive, bool msgfmt);
+
+ /**
+ * @brief Get information about the PO file
+ *
+ * @param url The path (not an URL) of the file
+ * @param info The information retrieved from the file
+ * @param wordList ???
+ * @param updateWordList ???
+ * @param interactive Can the function interact with the user?
+ * @deprecated
+ * @note This function is missing in KBabel 1.11 (KDE 3.5).
+ * The function was re-introduced for binary-compatibility in
+ * KBabel 1.11.1 (KDE 3.5.1)
+ * @note This function always call Gettext's mgfmt before parsing each file
+ */
+ static ConversionStatus info(const QString& url,PoInfo& info, QStringList &wordList, bool updateWordList, bool interactive = true);
+
+ static PoInfo headerInfo(const CatalogItem&);
+ static bool findInFile(const QString& url, FindOptions options );
+
+ static bool stopStaticRead;
+
+ /**
+ * reads header information from the file and searches for charset
+ * information.
+ * @param gettextHeader text containing gettext headers
+ *
+ * @return Codec for found charset or 0, if no information has been found
+ */
+ static QTextCodec* codecForFile(QString gettextHeader);
+
+ /**
+ * @brief Write the entire cache.
+ */
+ static void cacheWrite();
+private:
+ /**
+ * Read the entire cache.
+ */
+ static void cacheRead();
+
+ static ConversionStatus fastRead( CatalogItem& item, GettextFlexLexer* lexer, bool storeText );
+
+ static bool _gettextPluralForm;
+};
+
+}
+
+#endif // POINFO_H
diff --git a/kbabel/common/projectsettings.cpp b/kbabel/common/projectsettings.cpp
new file mode 100644
index 00000000..3687c9d4
--- /dev/null
+++ b/kbabel/common/projectsettings.cpp
@@ -0,0 +1,126 @@
+/* ****************************************************************************
+ This file is part of KBabel
+
+ Copyright (C) 1999-2000 by Matthias Kiefer
+ <matthias.kiefer@gmx.de>
+ 2001-2004 by Stanislav Visnovsky
+ <visnovsky@kde.org>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the 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, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+ In addition, as a special exception, the copyright holders give
+ permission to link the code of this program with any edition of
+ the Qt library by Trolltech AS, Norway (or with modified versions
+ of Qt that use the same license as Qt), and distribute linked
+ combinations including the two. You must obey the GNU General
+ Public License in all respects for all of the code used other than
+ Qt. If you modify this file, you may extend this exception to
+ your version of the file, but you are not obligated to do so. If
+ you do not wish to do so, delete this exception statement from
+ your version.
+
+**************************************************************************** */
+#include "projectsettings.h"
+#include "resources.h"
+
+#include <qstring.h>
+#include <kglobal.h>
+#include <klocale.h>
+#include <kstandarddirs.h>
+
+#include <kspell.h>
+
+QString KBabel::Defaults::Spellcheck::ignoreURL()
+{
+ QString _ignoreURL;
+
+ KStandardDirs * dirs = KGlobal::dirs();
+ if(dirs)
+ {
+ _ignoreURL = dirs->saveLocation("appdata");
+ if(_ignoreURL.right(1)!="/")
+ _ignoreURL+="/";
+ _ignoreURL += "spellignores";
+ }
+ return _ignoreURL;
+}
+
+KSpellConfig* KBabel::Defaults::Spellcheck::defaultsettings = NULL;
+
+bool KBabel::Defaults::Spellcheck::noRootAffix()
+{
+ if( ! defaultsettings )
+ {
+ defaultsettings = new KSpellConfig(0, "spellconfig");
+ }
+
+ return defaultsettings->noRootAffix();
+}
+
+bool KBabel::Defaults::Spellcheck::runTogether()
+{
+ if( ! defaultsettings )
+ {
+ defaultsettings = new KSpellConfig(0, "spellconfig");
+ }
+
+ return defaultsettings->runTogether();
+}
+
+int KBabel::Defaults::Spellcheck::spellClient()
+{
+ if( ! defaultsettings )
+ {
+ defaultsettings = new KSpellConfig(0, "spellconfig");
+ }
+
+ return defaultsettings->client();
+}
+
+QString KBabel::Defaults::Spellcheck::spellDictionary()
+{
+ if( ! defaultsettings )
+ {
+ defaultsettings = new KSpellConfig(0, "spellconfig");
+ }
+
+ return defaultsettings->dictionary();
+}
+
+int KBabel::Defaults::Spellcheck::spellEncoding()
+{
+ if( ! defaultsettings )
+ {
+ defaultsettings = new KSpellConfig(0, "spellconfig");
+ }
+
+ return defaultsettings->encoding();
+}
+
+QString KBabel::Defaults::CatalogManager::ignoreURL()
+{
+ QString _ignoreURL;
+
+ KStandardDirs * dirs = KGlobal::dirs();
+ if(dirs)
+ {
+ _ignoreURL = dirs->saveLocation("appdata");
+ if(_ignoreURL.right(1)!="/")
+ _ignoreURL+="/";
+ _ignoreURL += "validationignores";
+ }
+ return _ignoreURL;
+}
+
diff --git a/kbabel/common/projectsettings.h b/kbabel/common/projectsettings.h
new file mode 100644
index 00000000..186b21e5
--- /dev/null
+++ b/kbabel/common/projectsettings.h
@@ -0,0 +1,142 @@
+/* ****************************************************************************
+ This file is part of KBabel
+
+ Copyright (C) 1999-2000 by Matthias Kiefer
+ <matthias.kiefer@gmx.de>
+ 2001-2005 by Stanislav Visnovsky
+ <visnovsky@kde.org>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the 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, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+ In addition, as a special exception, the copyright holders give
+ permission to link the code of this program with any edition of
+ the Qt library by Trolltech AS, Norway (or with modified versions
+ of Qt that use the same license as Qt), and distribute linked
+ combinations including the two. You must obey the GNU General
+ Public License in all respects for all of the code used other than
+ Qt. If you modify this file, you may extend this exception to
+ your version of the file, but you are not obligated to do so. If
+ you do not wish to do so, delete this exception statement from
+ your version.
+
+**************************************************************************** */
+#ifndef PROJECTSETTINGS_H
+#define PROJECTSETTINGS_H
+
+#include <qstring.h>
+#include <qstringlist.h>
+#include <qfont.h>
+#include <qcolor.h>
+#include <kurl.h>
+
+#include "catalogsettings.h"
+
+class KSpellConfig;
+
+namespace KBabel {
+
+struct SpellcheckSettings
+{
+ bool valid;
+ bool noRootAffix;
+ bool runTogether;
+ int spellEncoding;
+ int spellClient;
+ QString spellDict;
+
+ bool rememberIgnored;
+ QString ignoreURL;
+
+ bool onFlySpellcheck;
+
+ SpellcheckSettings() { valid=false; }
+};
+
+struct CatManSettings
+{
+ QString poBaseDir;
+ QString potBaseDir;
+
+ bool openWindow;
+
+ QStringList dirCommands;
+ QStringList dirCommandNames;
+ QStringList fileCommands;
+ QStringList fileCommandNames;
+
+ QString ignoreURL;
+
+ bool killCmdOnExit;
+ bool indexWords;
+ /// Should be msgfmt be run before processing a file?
+ bool msgfmt;
+
+ bool flagColumn;
+ bool fuzzyColumn;
+ bool untranslatedColumn;
+ bool totalColumn;
+ bool cvsColumn;
+ bool revisionColumn;
+ bool translatorColumn;
+
+};
+
+struct SourceContextSettings
+{
+ /**
+ * A path, which can be used as @CODEROOT@ variable in @ref sourcePaths .
+ * Defaults to empty string.
+ */
+ QString codeRoot;
+
+ /**
+ * List of paths, where the source file should be lookup. Can use @CODEROOT@ (replaced by @ref codeRoot),
+ * @PACKAGE@ (replaced by package name), @PACKAGEDIR@ (replaced by the
+ * longest known path of the package) and @COMMENTPATH@ (path extracted from comment specs.
+ */
+ QStringList sourcePaths;
+
+ void SourceContextSettins() { codeRoot = QString::null; sourcePaths.clear(); }
+};
+
+/**
+* This namespace provides static methods and variables to get the default
+* values of configuration values
+*/
+namespace Defaults
+{
+ class KDE_EXPORT Spellcheck
+ {
+ public:
+ static QString ignoreURL();
+ static bool noRootAffix();
+ static bool runTogether();
+ static int spellClient();
+ static QString spellDictionary();
+ static int spellEncoding();
+ private:
+ static KSpellConfig* defaultsettings;
+ };
+
+ class KDE_EXPORT CatalogManager
+ {
+ public:
+ static QString ignoreURL();
+ };
+}
+
+}
+
+#endif // PROJECTSETTINGS_H
diff --git a/kbabel/common/regexpextractor.cpp b/kbabel/common/regexpextractor.cpp
new file mode 100644
index 00000000..b69398c6
--- /dev/null
+++ b/kbabel/common/regexpextractor.cpp
@@ -0,0 +1,271 @@
+/* ****************************************************************************
+ This file is part of KBabel
+
+ Copyright (C) 2001 by Matthias Kiefer <matthias.kiefer@gmx.de>
+ 2002 by Stanislav Visnovsky <visnovsky@nenya.ms.mff.cuni.cz>
+
+ based on code of Andrea Rizzi <rizzi@kde.org>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the 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, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+ In addition, as a special exception, the copyright holders give
+ permission to link the code of this program with any edition of
+ the Qt library by Trolltech AS, Norway (or with modified versions
+ of Qt that use the same license as Qt), and distribute linked
+ combinations including the two. You must obey the GNU General
+ Public License in all respects for all of the code used other than
+ Qt. If you modify this file, you may extend this exception to
+ your version of the file, but you are not obligated to do so. If
+ you do not wish to do so, delete this exception statement from
+ your version.
+
+**************************************************************************** */
+#include "regexpextractor.h"
+
+#include <kdebug.h>
+#include <qregexp.h>
+
+using namespace KBabel;
+
+RegExpExtractor::RegExpExtractor(const QStringList& regexps) :
+ _regExpList( regexps )
+{
+ _string=QString::null;
+ _matches.setAutoDelete(true);
+}
+
+void RegExpExtractor::setString(QString string)
+{
+ _string=string;
+ processString();
+}
+
+uint RegExpExtractor::countMatches()
+{
+ return _matches.count();
+}
+
+QString RegExpExtractor::firstMatch()
+{
+ MatchedEntryInfo *ti = _matches.first();
+
+ if(ti)
+ return ti->extracted;
+
+ return QString::null;
+}
+
+QString RegExpExtractor::nextMatch()
+{
+ MatchedEntryInfo *ti=_matches.next();
+ if(!ti)
+ ti=_matches.first();
+
+ if(ti)
+ return ti->extracted;
+
+ return QString::null;
+}
+
+QString RegExpExtractor::match(uint tagnumber)
+{
+ MatchedEntryInfo *ti=_matches.at(tagnumber);
+ if(ti)
+ return ti->extracted;
+
+ return QString::null;
+}
+
+int RegExpExtractor::matchIndex(uint tagnumber)
+{
+ MatchedEntryInfo *ti=_matches.at(tagnumber);
+ if(ti)
+ return ti->index;
+
+ return -1;
+}
+
+QString RegExpExtractor::prevMatch()
+{
+ MatchedEntryInfo *ti=_matches.prev();
+ if(ti)
+ return ti->extracted;
+
+ return QString::null;
+}
+
+QString RegExpExtractor::lastMatch()
+{
+ MatchedEntryInfo *ti=_matches.last();
+ if(ti)
+ return ti->extracted;
+
+ return QString::null;
+}
+
+QStringList RegExpExtractor::matches()
+{
+ QStringList list;
+ MatchedEntryInfo *ti;
+ for(ti=_matches.first(); ti!=0; ti = _matches.next())
+ {
+ list.append(ti->extracted);
+ }
+
+ return list;
+}
+
+QString RegExpExtractor::plainString(bool keepPos)
+{
+ QString tmp=_string;
+
+ MatchedEntryInfo *ti;
+ for(ti=_matches.first(); ti != 0; ti=_matches.next())
+ {
+ uint len=ti->extracted.length();
+ QString s;
+ for(uint i=0; i<len; i++)
+ {
+ s+=' ';
+ }
+ tmp.replace(ti->index,len,s);
+
+ }
+ if(!keepPos)
+ {
+ tmp=tmp.simplifyWhiteSpace();
+ }
+
+ return tmp;
+}
+
+QString RegExpExtractor::matchesReplaced(const QString& replace)
+{
+ QString tmp=_string;
+
+ int posCorrection=0;
+ int replaceLen=replace.length();
+
+ MatchedEntryInfo *ti;
+ for(ti=_matches.first(); ti != 0; ti=_matches.next())
+ {
+ uint len=ti->extracted.length();
+ tmp.replace(ti->index + posCorrection,len,replace);
+
+ posCorrection+=(replaceLen-len);
+ }
+
+ return tmp;
+}
+
+void RegExpExtractor::processString()
+{
+ _matches.clear();
+
+ // if there is no regexp to be matched, quit
+ if( regExpList().empty() ) return;
+
+ QValueList<MatchedEntryInfo> tmpList;
+
+ bool found=false;
+ QString tmp=_string;
+ do
+ {
+ found=false;
+ QStringList::Iterator it;
+ for(it=_regExpList.begin();it!=_regExpList.end();++it)
+ {
+ int pos=-1;
+ QString tag;
+
+ QRegExp reg = QRegExp((*it));
+
+ pos = reg.search(tmp);
+ int len=reg.matchedLength();
+ if(pos>=0)
+ {
+ tag=tmp.mid(pos,len);
+ }
+
+ if(pos >= 0)
+ {
+ found=true;
+
+ MatchedEntryInfo ti;
+ ti.index=pos;
+ ti.extracted=tag;
+ tmpList.append(ti);
+
+ QString s;
+ for(uint i=0; i<tag.length(); i++)
+ {
+ s+=' ';
+ }
+ tmp.replace(pos,tag.length(),s);
+
+ break;
+ }
+ }
+ }
+ while( found );
+
+ uint num=tmpList.count();
+
+ for(uint i=0; i < num; i++)
+ {
+ uint n= 0;
+ uint min=_string.length();
+ uint counter=0;
+ QValueList<MatchedEntryInfo>::Iterator it;
+ for(it=tmpList.begin();it!=tmpList.end();++it)
+ {
+ if((*it).index < min)
+ {
+ min=(*it).index;
+ n=counter;
+ }
+
+ counter++;
+ }
+
+ it=tmpList.at(n);
+ MatchedEntryInfo *ti = new MatchedEntryInfo;
+ ti->index=(*it).index;
+ ti->extracted=(*it).extracted;
+ _matches.append(ti);
+ tmpList.remove(it);
+ }
+}
+
+QStringList RegExpExtractor::regExpList()
+{
+ return _regExpList;
+}
+
+void RegExpExtractor::setRegExpList( const QStringList& regexps )
+{
+ _regExpList = regexps;
+}
+
+void RegExpExtractor::addRegExpIdentifier(QString regExp)
+{
+ _regExpList.append(regExp);
+}
+
+void RegExpExtractor::deleteRegExpIdentifier(QString regExp)
+{
+ _regExpList.remove(regExp);
+}
+
diff --git a/kbabel/common/regexpextractor.h b/kbabel/common/regexpextractor.h
new file mode 100644
index 00000000..89703fba
--- /dev/null
+++ b/kbabel/common/regexpextractor.h
@@ -0,0 +1,158 @@
+/* ****************************************************************************
+ This file is part of KBabel
+
+ Copyright (C) 2001 by Matthias Kiefer <matthias.kiefer@gmx.de>
+
+ based on code of Andrea Rizzi <rizzi@kde.org>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the 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, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+ In addition, as a special exception, the copyright holders give
+ permission to link the code of this program with any edition of
+ the Qt library by Trolltech AS, Norway (or with modified versions
+ of Qt that use the same license as Qt), and distribute linked
+ combinations including the two. You must obey the GNU General
+ Public License in all respects for all of the code used other than
+ Qt. If you modify this file, you may extend this exception to
+ your version of the file, but you are not obligated to do so. If
+ you do not wish to do so, delete this exception statement from
+ your version.
+
+**************************************************************************** */
+#ifndef _REGEXP_EXTRACTOR_H_
+#define _REGEXP_EXTRACTOR_H_
+
+#include <qptrlist.h>
+#include <qstring.h>
+#include <qstringlist.h>
+#include <qvaluelist.h>
+#include <qregexp.h>
+#include <kdemacros.h>
+
+namespace KBabel
+{
+
+struct KDE_EXPORT MatchedEntryInfo{
+ uint index;
+ QString extracted;
+};
+
+
+/**
+ * class to extract entries based on regexps from a string
+ * @author Andrea Rizzi <rizzi@kde.org>
+ */
+class KDE_EXPORT RegExpExtractor
+{
+
+public:
+ /**
+ * Create a regexp extractor for "string"
+ */
+ RegExpExtractor(const QStringList& regexps);
+
+ virtual ~RegExpExtractor() {}
+
+ /**
+ * Set the string of this extractor
+ */
+ void setString(QString string);
+
+ /**
+ * @return the number of matches found
+ */
+ uint countMatches();
+
+ /**
+ * @return the first match, and set the internal cursor to
+ * the beginning
+ */
+ QString firstMatch();
+
+ /**
+ * @return the next match and move cursor forward
+ */
+ QString nextMatch();
+
+ /**
+ * @return the n-th match. It also moves the cursor.
+ */
+ QString match(uint matchnumber);
+
+ /**
+ * @return the n-th match. It also moves the cursor. -1 is there
+ * is no such match.
+ */
+ int matchIndex(uint matchnumber);
+
+ /**
+ * @return the next match and move cursor forward
+ */
+ QString prevMatch();
+
+ /**
+ * @return the last match and move the cursor to the end
+ */
+ QString lastMatch();
+
+ /**
+ * @return a list of all matches
+ */
+ QStringList matches();
+
+ /**
+ * @return the string without matched text
+ *
+ * @param keepPos if false, the matches are just removed and so the
+ * position of the other words in the string will change. If true,
+ * the matches are replaced with ' ' and therefore the position of the
+ * words will not change
+ */
+ QString plainString(bool keepPos=false);
+
+ /**
+ * @return the string, where matches are replaced with the given string
+ */
+ QString matchesReplaced(const QString& replace);
+
+ //Functions that allow user to define his own regexps.
+
+ /**
+ * Add a regexp to the list of regexp identifier.
+ */
+ void addRegExpIdentifier(QString regexp);
+
+
+ /**
+ * Delete from the regexp list the regexp.
+ */
+ void deleteRegExpIdentifier(QString regexp);
+
+ void setRegExpList( const QStringList& regexps );
+
+ QStringList regExpList();
+
+protected:
+
+ void processString();
+ QPtrList<MatchedEntryInfo> _matches;
+ QString _string;
+ QStringList _regExpList;
+};
+
+
+}
+
+#endif
diff --git a/kbabel/common/resources.h b/kbabel/common/resources.h
new file mode 100644
index 00000000..d6054b43
--- /dev/null
+++ b/kbabel/common/resources.h
@@ -0,0 +1,43 @@
+/*
+ This file is part of KBabel
+
+ Copyright (c) 2005 by Stanislav Visnovsky <visnovsky@kde.org>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the 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, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+ In addition, as a special exception, the copyright holders give
+ permission to link the code of this program with any edition of
+ the Qt library by Trolltech AS, Norway (or with modified versions
+ of Qt that use the same license as Qt), and distribute linked
+ combinations including the two. You must obey the GNU General
+ Public License in all respects for all of the code used other than
+ Qt. If you modify this file, you may extend this exception to
+ your version of the file, but you are not obligated to do so. If
+ you do not wish to do so, delete this exception statement from
+ your version.
+
+*/
+
+#ifndef RESOURCES_H
+#define RESOURCES_H
+
+#include <kdebug.h>
+#define KBABEL 8107
+#define KBABEL_SEARCH 8108
+#define KBABEL_CATMAN 8109
+
+
+#endif // RESOURCES_H
+
diff --git a/kbabel/common/stringdistance.cpp b/kbabel/common/stringdistance.cpp
new file mode 100644
index 00000000..32cb9b96
--- /dev/null
+++ b/kbabel/common/stringdistance.cpp
@@ -0,0 +1,182 @@
+/* ****************************************************************************
+ Copyright (C) 2003-2004 Eva Brucherseifer <eva.brucherseifer@basyskom.com>
+ 2005 Stanislav visnovsky <visnovsky@kde.org>
+
+ This file is part of the KDE project
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the 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, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+ In addition, as a special exception, the copyright holders give
+ permission to link the code of this program with any edition of
+ the Qt library by Trolltech AS, Norway (or with modified versions
+ of Qt that use the same license as Qt), and distribute linked
+ combinations including the two. You must obey the GNU General
+ Public License in all respects for all of the code used other than
+ Qt. If you modify this file, you may extend this exception to
+ your version of the file, but you are not obligated to do so. If
+ you do not wish to do so, delete this exception statement from
+ your version.
+
+**************************************************************************** */
+
+#include "stringdistance.h"
+
+using namespace std;
+
+//! Debug-Messages 0 : off 1 : a few 10 : more
+int Distance::debug = 0;
+const int Distance::editCost_replace_base = 1;
+
+const int HammingDistance::editCost = 1;
+
+const int LevenshteinDistance::editCost_replace = 1;
+const int LevenshteinDistance::editCost_insert = 1;
+const int LevenshteinDistance::editCost_delete = 1;
+
+
+double relativeDistance(double distance, const QString& left_string, const QString& right_string)
+{
+ double maxsize=0;
+ double compsize=0;
+ maxsize = left_string.length();
+ compsize=right_string.length();
+ if (compsize>maxsize)
+ maxsize=compsize;
+ return distance/(double)maxsize;
+}
+
+
+/** This function walk trough the treeS(left & right) at the same time.
+ * There are in both entities the same number of trees!
+ * This function sums all the distances between all trees.
+ * For the calculation of the distance between two trees, it calls the function calculate.
+ */
+double Distance::operator()(const QString& left_string, const QString& right_string)
+{
+ m_distance = 0.00;
+ if (left_string == right_string)
+ return 0.00; // saves calculation time, both entities are the same
+
+ // swap strings, our matrix requires that
+ if (left_string.length () < right_string.length() )
+ {
+ m_distance = calculate(right_string, left_string);
+ }
+ else
+ {
+ m_distance = calculate(left_string, right_string);
+ }
+
+// if (debug > 0) cout << " --> total distance: " << m_distance << endl;
+ return m_distance;
+}
+
+/** This function calculates the distance between two nodes.
+ * For the calculation you can specify two variables gap & distance.
+ */
+int Distance::nodeDistance(const QString& left_letter, const QString& right_letter)
+{
+ if ( left_letter == right_letter )
+ {
+// if (debug > 0) cout << ".";
+ return 0;
+ }
+ else
+ {
+// if (debug > 0) cout << "!";
+ return editCostReplace();
+ }
+}
+
+/** This function walks along the treeS(left & right) at the same time.
+ * There are in both entities the same number of nodes, hopefully! But it doesn't care.
+ * This function sums all the distances between all nodes.
+ * For the calculation you can specify the distance between two nodes in variable distance
+ */
+double HammingDistance::calculate(const QString& left_string, const QString& right_string)
+{
+ double hammingDistance = 0.00;
+// if (debug > 0)
+// cout << left_string.length() << " " << right_string.length() << "\t";
+
+ unsigned int i=0;
+ unsigned int j=0;
+ for ( ; i != left_string.length() && j != right_string.length() ;
+ ++i,++j)
+ hammingDistance += double(nodeDistance(left_string[i], right_string[i]));
+ for ( ; i != left_string.length() ; ++i )
+ {
+ ++hammingDistance;
+// if (debug > 9) cout << "!";
+ }
+ for ( ; j != right_string.length() ; ++j)
+ {
+ ++hammingDistance;
+// if (debug > 9) cout << "!";
+ }
+ return hammingDistance;
+}
+
+
+/** This function walk along the treeS(left & right) at the same time.
+ * It uses the Levenshtein-algorithm for the calculation of the distance between two trees.
+ * A matrice D is generated which represent the distribution of distances between two trees.
+ * The last element represent the Levenshtein-distance.
+ */
+double LevenshteinDistance::calculate(const QString& left_string, const QString& right_string)
+{
+// if (debug > 0)
+// cout << left_string.length() << " " << right_string.length() << "\t";
+
+ unsigned int left_size = left_string.length()+1;
+ unsigned int right_size = right_string.length()+1;
+
+ int *_D = new int[left_size * right_size];
+
+ for (unsigned int i = 0 ; i < left_size * right_size; i++ )
+ _D[i] = 0;
+
+#define D(a,b) (_D[(a)+(b)*left_size])
+
+
+// boost::numeric::ublas::matrix<int> D(left_size, right_size);
+// D = zero_boost::numeric::ublas::matrix<int>(left_size, right_size);
+
+ unsigned int l,r;
+ D(0,0) = 0;
+ for(l = 1; l < left_size; l++)
+ D(l,0) = D(l-1,0) + editCost_delete;
+ for(r = 1; r < right_size; r++)
+ D(0,r) = D(0,r-1) + editCost_insert;
+
+ int tmp_value;
+ for(l = 1; l < left_size; l++)
+ {
+ for(r = 1; r < right_size; r++)
+ {
+ tmp_value = QMIN( ( D(l-1,r) + editCost_delete ),
+ ( D(l-1,r-1) + nodeDistance(left_string[l-1], right_string[r-1]) ) ) ;
+ D(l,r) = QMIN( tmp_value,
+ ( D(l,r-1) + editCost_insert ) );
+ }
+ }
+
+ double res (D(left_size-1,right_size-1));
+
+ delete[] _D;
+
+ return res;
+}
+
diff --git a/kbabel/common/stringdistance.h b/kbabel/common/stringdistance.h
new file mode 100644
index 00000000..6f5aa185
--- /dev/null
+++ b/kbabel/common/stringdistance.h
@@ -0,0 +1,131 @@
+/* ****************************************************************************
+ Copyright (C) 2003-2004 Eva Brucherseifer <eva.brucherseifer@basyskom.com>
+ 2005 Stanislav Visnovsky <visnovsky@kde.org>
+
+ This file is part of the KDE project
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the 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, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+ In addition, as a special exception, the copyright holders give
+ permission to link the code of this program with any edition of
+ the Qt library by Trolltech AS, Norway (or with modified versions
+ of Qt that use the same license as Qt), and distribute linked
+ combinations including the two. You must obey the GNU General
+ Public License in all respects for all of the code used other than
+ Qt. If you modify this file, you may extend this exception to
+ your version of the file, but you are not obligated to do so. If
+ you do not wish to do so, delete this exception statement from
+ your version.
+
+**************************************************************************** */
+
+#ifndef STRINGDISTANCE_H
+#define STRINGDISTANCE_H
+
+#include <qstring.h>
+
+//#include <boost/numeric/ublas/matrix.hpp>
+
+
+/** Private copy constructor and copy assignment ensure classes derived from
+ * class noncopyable cannot be copied.
+ * Taken from Boost library
+ * Contributed by Dave Abrahams
+ *
+ * If anyone needs a namespace here, please tell me at eva@rt.e-technik.tu-darmstadt.de
+ */
+class NonCopyable
+{
+protected:
+ NonCopyable(){}
+ virtual ~NonCopyable(){}
+private: // emphasize the following members are private
+ NonCopyable( const NonCopyable& );
+ const NonCopyable& operator=( const NonCopyable& );
+};
+
+
+/**
+ * @class Distance
+ * @author Eva Brucherseifer
+ *
+ * The class Distance calculates the distance
+ * between two Entities (left & right).
+ * It is the parent for other distance-classes.
+ */
+class Distance : public NonCopyable
+{
+public:
+ virtual ~Distance(){}
+ double operator()(const QString& left, const QString& right);
+
+ int editCostReplace() { return editCost_replace_base; }
+ static int debug;
+
+protected:
+ virtual double calculate(const QString& left_string, const QString& right_string) = 0;
+ int nodeDistance(const QString& left_letter, const QString& right_letter);
+ static const int editCost_replace_base;
+ double m_distance;
+};
+
+
+double relativeDistance(double distance, const QString& left_string, const QString right_string);
+
+
+/**
+ * @class HammingDistance
+ * @author Eva Brucherseifer
+ *
+ * The class HammingDistance is based on an algorithm
+ * of Hamming. It increase the distance if the nodes from
+ * the tree are not the same. Also called edit-distance.
+ */
+class HammingDistance : public Distance
+{
+protected:
+ virtual double calculate(const QString& left_string, const QString& right_string);
+ int editCostReplace() { return editCost; }
+ static const int editCost;
+};
+
+/**
+ * @class LevenshteinDistance
+ * @author Eva Brucherseifer
+ *
+ * The class LevenshteinDistance is based on an algorithm
+ * of Levenshtein. It search for the minimum distance of
+ * two trees. You can specify the distance between
+ * a gap & a node and between two different nodes.
+ */
+class LevenshteinDistance : public Distance
+{
+protected:
+ virtual double calculate(const QString& left_string, const QString& right_string);
+ int editCostReplace() { return editCost_replace; }
+ static const int editCost_replace;
+ static const int editCost_insert;
+ static const int editCost_delete;
+};
+
+
+/** wrapper function for replacement of fstrcmp from gettext */
+inline double fstrcmp(const QString& left, const QString& right)
+{
+ return LevenshteinDistance()(left,right);
+}
+
+
+#endif
diff --git a/kbabel/common/tagextractor.cpp b/kbabel/common/tagextractor.cpp
new file mode 100644
index 00000000..45b8ad9f
--- /dev/null
+++ b/kbabel/common/tagextractor.cpp
@@ -0,0 +1,54 @@
+/* ****************************************************************************
+ This file is part of KBabel
+
+ Copyright (C) 2001 by Matthias Kiefer <matthias.kiefer@gmx.de>
+ 2002 by Stanislav Visnovsky <visnovsky@nenya.ms.mff.cuni.cz>
+
+ based on code of Andrea Rizzi <rizzi@kde.org>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the 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, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+ In addition, as a special exception, the copyright holders give
+ permission to link the code of this program with any edition of
+ the Qt library by Trolltech AS, Norway (or with modified versions
+ of Qt that use the same license as Qt), and distribute linked
+ combinations including the two. You must obey the GNU General
+ Public License in all respects for all of the code used other than
+ Qt. If you modify this file, you may extend this exception to
+ your version of the file, but you are not obligated to do so. If
+ you do not wish to do so, delete this exception statement from
+ your version.
+
+**************************************************************************** */
+#include "catalogsettings.h"
+#include "tagextractor.h"
+
+#include <kglobal.h>
+#include <kconfig.h>
+
+using namespace KBabel;
+
+TagExtractor::TagExtractor() : RegExpExtractor(QStringList())
+{
+ KConfig* config = KGlobal::config();
+
+ config->setGroup("Tags");
+
+ QStringList s=config->readListEntry("TagExpressions");
+ if( s.empty() ) s = Defaults::Tag::tagExpressions();
+
+ RegExpExtractor::setRegExpList(s);
+}
+
diff --git a/kbabel/common/tagextractor.h b/kbabel/common/tagextractor.h
new file mode 100644
index 00000000..3845b9fd
--- /dev/null
+++ b/kbabel/common/tagextractor.h
@@ -0,0 +1,58 @@
+/* ****************************************************************************
+ This file is part of KBabel
+
+ Copyright (C) 2001 by Matthias Kiefer <matthias.kiefer@gmx.de>
+
+ based on code of Andrea Rizzi <rizzi@kde.org>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the 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, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+ In addition, as a special exception, the copyright holders give
+ permission to link the code of this program with any edition of
+ the Qt library by Trolltech AS, Norway (or with modified versions
+ of Qt that use the same license as Qt), and distribute linked
+ combinations including the two. You must obey the GNU General
+ Public License in all respects for all of the code used other than
+ Qt. If you modify this file, you may extend this exception to
+ your version of the file, but you are not obligated to do so. If
+ you do not wish to do so, delete this exception statement from
+ your version.
+
+**************************************************************************** */
+#ifndef _TAG_EXTRACTOR_H_
+#define _TAG_EXTRACTOR_H_
+
+#include "regexpextractor.h"
+
+namespace KBabel
+{
+
+/**
+ * class to extract tags from a string
+ * @author Andrea Rizzi <rizzi@kde.org>
+ */
+class KDE_EXPORT TagExtractor : public RegExpExtractor
+{
+
+public:
+ /**
+ * Create a tag extractor by using default settings for tag expressions
+ */
+ TagExtractor();
+};
+
+}
+
+#endif
diff --git a/kbabel/commonui/Makefile.am b/kbabel/commonui/Makefile.am
new file mode 100644
index 00000000..e0ca94ce
--- /dev/null
+++ b/kbabel/commonui/Makefile.am
@@ -0,0 +1,40 @@
+## Makefile.am for libkbabelcommon
+
+# this is the program that gets installed. it's name is used for all
+# of the other Makefile.am variables
+noinst_LTLIBRARIES = libkbabelcommonui.la
+
+# set the include path for X, qt and KDE. Put local paths before all_includes.
+INCLUDES = -I$(srcdir)/../common -I../common -I$(srcdir)/../kbabeldict -I../kbabeldict $(all_includes)
+
+# which sources should be compiled
+libkbabelcommonui_la_SOURCES = klisteditor.ui context.cpp kactionselector.cpp \
+ toolselectionwidget.cpp toolaction.cpp \
+ finddialog.cpp roughtransdlg.cpp \
+ projectprefwidgets.cpp \
+ projectpref.cpp \
+ projectwizard.cpp \
+ projectwizardwidget.ui \
+ projectwizardwidget2.ui \
+ cmdedit.cpp \
+ diffpreferences.ui
+
+libkbabelcommonui_la_LIBADD = $(LIB_KIO) -lktexteditor ../common/libkbabelcommon.la ../kbabeldict/libkbabeldict.la
+
+libkbabelcommonui_la_LDFLAGS = $(all_libraries)
+
+# these are the headers for your project
+noinst_HEADERS = context.h kactionselector.h finddialog.h \
+ roughtransdlg.h projectprefwidgets.h projectpref.h \
+ cmdedit.h projectwizard.h
+
+# let automoc handle all of the meta source files (moc)
+METASOURCES = AUTO
+
+# we need to define our own service type for our plugins. It's data tool with a shortcut :-((
+kde_servicetypes_DATA = kbabel_validator.desktop kbabel_tool.desktop
+EXTRA_DIST = $(kde_servicetypes_DATA)
+
+context.lo: ../common/kbprojectsettings.h
+projectpref.lo: ../common/kbprojectsettings.h
+projectprefwidgets.lo: ../common/kbprojectsettings.h
diff --git a/kbabel/commonui/cmdedit.cpp b/kbabel/commonui/cmdedit.cpp
new file mode 100644
index 00000000..bfe95293
--- /dev/null
+++ b/kbabel/commonui/cmdedit.cpp
@@ -0,0 +1,298 @@
+/* ****************************************************************************
+ This file is part of KBabel
+
+ Copyright (C) 1999-2000 by Matthias Kiefer
+ <matthias.kiefer@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.
+
+ 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, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+ In addition, as a special exception, the copyright holders give
+ permission to link the code of this program with any edition of
+ the Qt library by Trolltech AS, Norway (or with modified versions
+ of Qt that use the same license as Qt), and distribute linked
+ combinations including the two. You must obey the GNU General
+ Public License in all respects for all of the code used other than
+ Qt. If you modify this file, you may extend this exception to
+ your version of the file, but you are not obligated to do so. If
+ you do not wish to do so, delete this exception statement from
+ your version.
+
+**************************************************************************** */
+#include "cmdedit.h"
+
+#include <qlistbox.h>
+#include <qlineedit.h>
+#include <qpushbutton.h>
+#include <qlayout.h>
+#include <qlabel.h>
+#include <qtoolbutton.h>
+#include <klocale.h>
+#include <kdialog.h>
+
+
+CmdEdit::CmdEdit(QWidget* parent, const char* name)
+ : QWidget(parent,name)
+{
+ QGridLayout* layout = new QGridLayout( this , 1 , 1 );
+ layout->setSpacing( KDialog::spacingHint() );
+
+ QLabel* nameLabel = new QLabel( i18n("Command &Label:"), this);
+ QLabel* cmdLabel = new QLabel( i18n("Co&mmand:"), this);
+ layout->addWidget( nameLabel, 0 , 0 );
+ layout->addWidget( cmdLabel, 0 , 1 );
+
+ _cmdNameEdit = new QLineEdit( this , "cmdNameEdit" );
+ _cmdNameEdit->setMaxLength(20);
+ nameLabel->setBuddy(_cmdNameEdit);
+ layout->addWidget( _cmdNameEdit , 1 , 0 );
+
+ _cmdEdit = new QLineEdit( this , "cmdEdit" );
+ cmdLabel->setBuddy(_cmdEdit);
+ layout->addWidget( _cmdEdit , 1 , 1 );
+
+
+ _addButton = new QPushButton( i18n("&Add"), this );
+ _addButton->setEnabled(false);
+ layout->addWidget( _addButton , 1 , 2 );
+
+ _editButton = new QPushButton( i18n("&Edit"), this );
+ _editButton->setEnabled(false);
+ layout->addWidget( _editButton , 3 , 2 );
+
+ _removeButton = new QPushButton( i18n("&Remove"), this );
+ _removeButton->setEnabled(false);
+ layout->addWidget( _removeButton , 4 , 2 );
+
+ QHBoxLayout* hbox = new QHBoxLayout();
+ layout->addLayout(hbox,5,2);
+
+ _upButton = new QToolButton(UpArrow,this);
+ _upButton->setFixedSize(20,20);
+ _upButton->setEnabled(false);
+ hbox->addWidget( _upButton );
+
+ _downButton = new QToolButton(DownArrow,this);
+ _downButton->setFixedSize(20,20);
+ _downButton->setEnabled(false);
+ hbox->addWidget( _downButton);
+
+ _commandNames = new QListBox( this , "commandNamesBox" );
+ _commandNames->setMinimumSize(100, 100);
+ layout->addMultiCellWidget( _commandNames , 3 , 6 , 0 , 0);
+
+ _commands = new QListBox( this , "commandsBox" );
+ _commands->setMinimumSize(160, 100);
+ layout->addMultiCellWidget( _commands , 3 , 6 , 1 ,1 );
+
+
+ layout->setColStretch(0,1);
+ layout->setColStretch(1,2);
+ layout->setColStretch(2,0);
+
+ layout->addRowSpacing(2, KDialog::spacingHint());
+ layout->addRowSpacing(6, KDialog::spacingHint());
+
+ setMinimumSize(layout->sizeHint());
+
+
+ connect(_addButton , SIGNAL(clicked()) , this , SLOT(addCmd()) ) ;
+ connect(_editButton , SIGNAL(clicked()) , this , SLOT(editCmd()) );
+ connect(_removeButton , SIGNAL(clicked()) , this , SLOT(removeCmd()) );
+ connect(_upButton , SIGNAL(clicked()) , this , SLOT(upCmd()) ) ;
+ connect(_downButton , SIGNAL(clicked()) , this , SLOT(downCmd()) );
+
+ connect(_commands , SIGNAL(highlighted(int)) , this, SLOT(cmdHighlighted(int)) );
+ connect(_commandNames , SIGNAL(highlighted(int)) , this, SLOT(cmdNameHighlighted(int)) );
+ connect(_commands , SIGNAL(selected(int)) , this, SLOT(editCmd()) );
+ connect(_commandNames , SIGNAL(selected(int)) , this, SLOT(editCmd()) );
+
+ connect(_cmdEdit, SIGNAL(textChanged(const QString&)) , this , SLOT(checkAdd()) );
+ connect(_cmdNameEdit, SIGNAL(textChanged(const QString&)) , this , SLOT(checkAdd()) );
+}
+
+void CmdEdit::setCommands(const QStringList& commands,const QStringList& commandNames)
+{
+ _commands->clear();
+ _commands->insertStringList(commands);
+
+ _commandNames->clear();
+ _commandNames->insertStringList(commandNames);
+}
+
+void CmdEdit::commands(QStringList& commands, QStringList& commandNames)
+{
+ commands.clear();
+ commandNames.clear();
+
+ int items=_commands->count();
+
+ int i=0;
+ for( i=0 ; i< items ; i++)
+ {
+ commands.append( _commands->text(i) );
+ commandNames.append( _commandNames->text(i) );
+ }
+}
+
+void CmdEdit::addCmd()
+{
+ QString cmd = _cmdEdit->text();
+ QString cmdName = _cmdNameEdit->text();
+ _cmdEdit->clear();
+ _cmdNameEdit->clear();
+
+ if(_commands->currentText() == cmd || _commandNames->currentText() == cmdName)
+ {
+ int current = _commands->currentItem();
+ _commands->changeItem(cmd,current);
+ _commandNames->changeItem(cmdName,current);
+ }
+ else
+ {
+ _commands->insertItem(cmd);
+ _commandNames->insertItem(cmdName);
+ }
+
+ emit widgetChanged();
+}
+
+void CmdEdit::removeCmd()
+{
+ int current=_commands->currentItem();
+
+ _commands->removeItem(current);
+ _commandNames->removeItem(current);
+
+ if(_commands->count() == 0)
+ {
+ _removeButton->setEnabled(false);
+ _editButton->setEnabled(false);
+ _upButton->setEnabled(false);
+ _downButton->setEnabled(false);
+ }
+ else
+ {
+ if(current > (int)_commands->count()-1)
+ current=_commands->count()-1;
+
+ _commands->setSelected(current,true);
+ _commandNames->setSelected(current,true);
+ cmdHighlighted(current);
+ }
+
+ emit widgetChanged();
+}
+
+void CmdEdit::upCmd()
+{
+ QString cmd = _commands->currentText();
+ QString cmdName = _commandNames->currentText();
+ int index=_commands->currentItem();
+
+ _commands->removeItem(index);
+ _commandNames->removeItem(index);
+
+ _commands->insertItem(cmd , index-1);
+ _commandNames->insertItem(cmdName , index-1);
+
+ _commands->clearSelection();
+ _commandNames->clearSelection();
+
+ _commands->setSelected(index-1,true);
+ _commandNames->setSelected(index-1,true);
+
+ cmdHighlighted(index-1);
+
+ emit widgetChanged();
+}
+
+void CmdEdit::downCmd()
+{
+ QString cmd = _commands->currentText();
+ QString cmdName = _commandNames->currentText();
+ int index=_commands->currentItem();
+
+ _commands->removeItem(index);
+ _commandNames->removeItem(index);
+
+ _commands->insertItem(cmd , index+1);
+ _commandNames->insertItem(cmdName , index+1);
+
+ _commands->clearSelection();
+ _commandNames->clearSelection();
+
+ _commands->setSelected(index+1,true);
+ _commandNames->setSelected(index+1,true);
+
+ cmdHighlighted(index+1);
+
+ emit widgetChanged();
+}
+
+void CmdEdit::cmdHighlighted(int index)
+{
+ _commandNames->blockSignals(true);
+ _commandNames->setCurrentItem(index);
+ _commandNames->blockSignals(false);
+
+ _removeButton->setEnabled(true);
+ _editButton->setEnabled(true);
+
+ if(index == (int)(_commands->count()-1))
+ _downButton->setEnabled(false);
+ else
+ _downButton->setEnabled(true);
+
+ if(index==0)
+ _upButton->setEnabled(false);
+ else
+ _upButton->setEnabled(true);
+
+}
+
+void CmdEdit::cmdNameHighlighted(int index)
+{
+ _commands->blockSignals(true);
+ _commands->setCurrentItem(index);
+ _commands->blockSignals(false);
+
+ _removeButton->setEnabled(true);
+ _editButton->setEnabled(true);
+
+ if(index == (int)(_commands->count()-1))
+ _downButton->setEnabled(false);
+ else
+ _downButton->setEnabled(true);
+
+ if(index==0)
+ _upButton->setEnabled(false);
+ else
+ _upButton->setEnabled(true);
+}
+
+void CmdEdit::editCmd()
+{
+ _cmdEdit->setText(_commands->currentText());
+ _cmdNameEdit->setText(_commandNames->currentText());
+
+ emit widgetChanged();
+}
+
+void CmdEdit::checkAdd()
+{
+ _addButton->setEnabled( !(_cmdEdit->text().isEmpty() || _cmdNameEdit->text().isEmpty()) );
+}
+
+#include "cmdedit.moc"
diff --git a/kbabel/commonui/cmdedit.h b/kbabel/commonui/cmdedit.h
new file mode 100644
index 00000000..dc61679b
--- /dev/null
+++ b/kbabel/commonui/cmdedit.h
@@ -0,0 +1,94 @@
+/* ****************************************************************************
+ This file is part of KBabel
+
+ Copyright (C) 1999-2000 by Matthias Kiefer
+ <matthias.kiefer@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.
+
+ 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, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+ In addition, as a special exception, the copyright holders give
+ permission to link the code of this program with any edition of
+ the Qt library by Trolltech AS, Norway (or with modified versions
+ of Qt that use the same license as Qt), and distribute linked
+ combinations including the two. You must obey the GNU General
+ Public License in all respects for all of the code used other than
+ Qt. If you modify this file, you may extend this exception to
+ your version of the file, but you are not obligated to do so. If
+ you do not wish to do so, delete this exception statement from
+ your version.
+
+**************************************************************************** */
+#ifndef CMDEDIT_H
+#define CMDEDIT_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <qwidget.h>
+#include <qstringlist.h>
+
+class QListBox;
+class QLineEdit;
+class QPushButton;
+class QToolButton;
+
+class CmdEdit : public QWidget
+{
+ Q_OBJECT
+public:
+ CmdEdit(QWidget* parent=0,const char* name=0);
+
+ void setCommands(const QStringList& commands,const QStringList& commandNames);
+ void commands(QStringList& commands, QStringList& commandNames);
+
+signals:
+ void widgetChanged();
+
+private slots:
+ /**
+ * reads command and commandName from the line edits and
+ * inserts them at the end of the listbox
+ */
+ void addCmd();
+ /**
+ * removes the currently selected command and commandName from the listbox
+ */
+ void removeCmd();
+
+ void upCmd();
+ void downCmd();
+
+ void editCmd();
+ void cmdHighlighted(int index);
+ void cmdNameHighlighted(int index);
+
+ void checkAdd();
+
+private:
+ QListBox* _commands;
+ QListBox* _commandNames;
+
+ QLineEdit* _cmdEdit;
+ QLineEdit* _cmdNameEdit;
+
+ QPushButton* _addButton;
+ QPushButton* _editButton;
+ QPushButton* _removeButton;
+ QToolButton* _upButton;
+ QToolButton* _downButton;
+};
+
+#endif // CMDEDIT_H
diff --git a/kbabel/commonui/context.cpp b/kbabel/commonui/context.cpp
new file mode 100644
index 00000000..db468795
--- /dev/null
+++ b/kbabel/commonui/context.cpp
@@ -0,0 +1,305 @@
+/* ****************************************************************************
+ This file is part of KBabel
+
+ Copyright (C) 2002-2005 by Stanislav Visnovsky
+ <visnovsky@kde.org>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the 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, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+ In addition, as a special exception, the copyright holders give
+ permission to link the code of this program with any edition of
+ the Qt library by Trolltech AS, Norway (or with modified versions
+ of Qt that use the same license as Qt), and distribute linked
+ combinations including the two. You must obey the GNU General
+ Public License in all respects for all of the code used other than
+ Qt. If you modify this file, you may extend this exception to
+ your version of the file, but you are not obligated to do so. If
+ you do not wish to do so, delete this exception statement from
+ your version.
+
+**************************************************************************** */
+#include "context.h"
+#include "klisteditor.h"
+#include "kbprojectsettings.h"
+
+#include <qcombobox.h>
+#include <qfileinfo.h>
+#include <qframe.h>
+#include <qhbox.h>
+#include <qlabel.h>
+#include <qlayout.h>
+#include <qlineedit.h>
+#include <qlistbox.h>
+#include <qpushbutton.h>
+#include <qregexp.h>
+#include <qvgroupbox.h>
+
+#include <kconfig.h>
+#include <kdebug.h>
+#include <kdialog.h>
+#include <klocale.h>
+#include <kmessagebox.h>
+#include <kurl.h>
+#include <kdeversion.h>
+#include <kio/netaccess.h>
+
+#include <klibloader.h>
+#include <ktrader.h>
+#include <ktexteditor/document.h>
+#include <ktexteditor/editinterface.h>
+#include <ktexteditor/selectioninterface.h>
+#include <ktexteditor/viewcursorinterface.h>
+
+SourceContext::SourceContext(QWidget *parent, KBabel::Project::Ptr project): QWidget(parent)
+ , m_parent( parent )
+ , _part(0)
+ , _view(0)
+ , _referenceCombo(0)
+ , _layout(0)
+ , _project(project)
+{
+ _referenceList.clear();
+ _referenceCombo = new QComboBox( this );
+ connect( _referenceCombo, SIGNAL(activated(int)), this, SLOT(updateToSelected(int)));
+
+ _layout= new QVBoxLayout(this);
+ _layout->addWidget(_referenceCombo);
+}
+
+void SourceContext::setContext( const QString& packageDir, const QString& packageName, const QString& gettextComment, const KURL& urlPoFile )
+{
+ if( !_part && !loadPart() ) return;
+ _referenceCombo->clear();
+ _referenceList = resolvePath( packageDir, packageName, gettextComment, urlPoFile );
+
+ for( QValueList<ContextInfo>::const_iterator it = _referenceList.constBegin(); it != _referenceList.constEnd(); ++it )
+ _referenceCombo->insertItem((*it).path);
+
+ _referenceCombo->setEnabled( !_referenceList.isEmpty() );
+ if( _referenceList.isEmpty() )
+ {
+ _part->setReadWrite( true );
+ // We have to simulate a new document (like with File/New) by using openStream and closeStream
+ _part->openStream("text/plain","kbabel:error"); // KBabel does not show the URL kbabel:error
+ _part->closeStream();
+ (dynamic_cast<KTextEditor::EditInterface *>(_part))->setText(i18n("Corresponding source file not found"));
+ _part->setReadWrite(false);
+ _part->setModified(false);
+ }
+ else
+ {
+ _referenceCombo->setCurrentItem(0);
+ updateToSelected(0);
+ }
+}
+
+void SourceContext::updateToSelected(int index)
+{
+ if( !_part ) return;
+ ContextInfo ci = *(_referenceList.at(index));
+ KURL newUrl( KURL::fromPathOrURL( ci.path ) );
+ if( _part->url() != newUrl )
+ {
+ _part->setReadWrite( true );
+ _part->openURL( newUrl );
+ }
+ _part->setReadWrite( false );
+ (dynamic_cast<KTextEditor::ViewCursorInterface *>(_view))->setCursorPosition(ci.line,0);
+ (dynamic_cast<KTextEditor::SelectionInterface *>(_part))->setSelection(ci.line-1,0,ci.line,0);
+}
+
+QValueList<ContextInfo> SourceContext::resolvePath( const QString& packageDir, const QString& packageName, const QString& gettextComment, const KURL& urlPoFile )
+{
+ //kdDebug() << "GETTEXTCOMMENT:" << gettextComment << endl;
+
+ // Find the directory name of the PO file, if the PO file is local
+ // ### TODO: find a way to allow remote files too
+ QString poDir;
+#if KDE_IS_VERSION( 3, 5, 0 )
+ const KURL localUrl( KIO::NetAccess::mostLocalURL( urlPoFile, m_parent ) );
+ if ( localUrl.isLocalFile() )
+ {
+ const QFileInfo fi( localUrl.path() );
+ poDir = fi.dirPath( true );
+ }
+#else
+ if ( urlPoFile.isLocalFile() )
+ {
+ const QFileInfo fi( urlPoFile.path() );
+ poDir = fi.dirPath( true );
+ }
+#endif
+
+#if 0
+ kdDebug() << "CONTEXT VARIABLE START" << endl;
+ kdDebug() << "@CODEROOT@: " << _project->settings()->codeRoot() << endl;
+ kdDebug() << "@PACKAGEDIR@: " << packageDir << endl;
+ kdDebug() << "@PACKAGE@: " << packageName << endl;
+ kdDebug() << "@POFILEDIR@: " << poDir << endl;
+ kdDebug() << "CONTEXT VARIABLE END" << endl;
+#endif
+
+ QStringList prefixes;
+ const QStringList paths = _project->settings()->paths();
+
+ for( QStringList::const_iterator it = paths.constBegin(); it!=paths.constEnd() ; ++it )
+ {
+ QString pref = (*it);
+
+ if ( !poDir.isEmpty() )
+ {
+ pref.replace( "@POFILEDIR@", poDir );
+ }
+ else if ( pref.find( "@POFILEDIR@ " ) != -1 )
+ continue; // No need to keep this path pattern, as we have no PO file dir
+
+ pref.replace( "@PACKAGEDIR@", packageDir);
+ pref.replace( "@PACKAGE@", packageName);
+ pref.replace( "@CODEROOT@", _project->settings()->codeRoot());
+ prefixes.append(pref);
+ }
+
+ QValueList<ContextInfo> rawRefList; // raw references
+ QRegExp re("^\\s*(.+):(\\d+)\\s*$"); // Reg. exp. for Gettext references
+ QRegExp rex( "^#. i18n: file (.+) line (\\d+)\\s*$" ); //Reg. exp. for KDE extractrc/extractattr references
+ QRegExp res( "^# [Ff]ile: (.+), line(?: number)?: (\\d+)\\s*$"); // Reg. exp. for "strict" PO format
+ const QStringList lines = QStringList::split( "\n", gettextComment );
+ for ( QStringList::const_iterator it = lines.constBegin() ; it != lines.constEnd() ; ++it)
+ {
+ const QString curLine = (*it).stripWhiteSpace();
+ if( curLine.startsWith( "#:" ) )
+ {
+ // We have a Gettext line with references
+ const QStringList references( QStringList::split( " ", curLine.mid( 2 ), false ) );
+ for ( QStringList::const_iterator it = references.constBegin(); it != references.constEnd(); ++it )
+ {
+ if ( re.exactMatch( (*it) ) )
+ {
+ ContextInfo ref;
+ ref.line = re.cap(2).toInt();
+ ref.path = re.cap(1);
+ // ### TODO KDE4: perhaps we should not do the replace if compiled for Windows
+ ref.path.replace( QChar( '\\' ), QChar( '/' ) );
+ rawRefList.append( ref );
+ }
+ }
+
+ }
+ else if ( curLine.startsWith( "#," ) )
+ {
+ // We have a Gettext option line. There is no source reference here.
+ continue;
+ }
+ else if ( curLine.startsWith( "#. i18n:") )
+ {
+ // We might have a KDE reference from extractrc/extractattr
+ if ( rex.exactMatch( (*it) ) )
+ {
+ ContextInfo ref;
+ ref.line = rex.cap(2).toInt();
+ ref.path = rex.cap(1);
+ // KDE is not extracted on Windows, so no backslash conversion is needed.
+ rawRefList.append( ref );
+ }
+ }
+ else if ( curLine.startsWith( "# F" ) || curLine.startsWith( "# f" ) )
+ {
+ // We might have a "strict PO" reference
+ if ( res.exactMatch( (*it) ) )
+ {
+ ContextInfo ref;
+ ref.line = res.cap(2).toInt();
+ ref.path = res.cap(1);
+ // ### TODO KDE4: perhaps we should not do the replace if compiled for Windows
+ ref.path.replace( QChar( '\\' ), QChar( '/' ) );
+ rawRefList.append( ref );
+ }
+ }
+ else
+ continue;
+ }
+
+ // Now that we have gathered the references, we need to convert them to absolute paths
+ QValueList<ContextInfo> results;
+ for ( QValueList<ContextInfo>::const_iterator it = rawRefList.constBegin(); it != rawRefList.constEnd(); ++it )
+ {
+ const int lineNum = (*it).line;
+ const QString fileName = (*it).path;
+ for ( QStringList::const_iterator it1 = prefixes.constBegin(); it1 != prefixes.constEnd(); ++it1 )
+ {
+ QString path = (*it1);
+ path.replace( "@COMMENTPATH@", fileName);
+
+ //kdDebug() << "CONTEXT PATH: " << path << endl; // DEBUG
+ QFileInfo pathInfo( path );
+ if( pathInfo.exists() )
+ {
+ ContextInfo ref;
+ ref.path = pathInfo.absFilePath();
+ ref.line = lineNum;
+ results.append(ref);
+ }
+ }
+ }
+
+ return results;
+}
+
+bool SourceContext::loadPart()
+{
+ KTrader::OfferList offers = KTrader::self()->query( "KTextEditor/Document" );
+ if( offers.count() < 1 )
+ {
+ KMessageBox::error(this,i18n("KBabel cannot start a text editor component.\n"
+ "Please check your KDE installation."));
+ _part=0;
+ _view=0;
+ return false;
+ }
+ KService::Ptr service = *offers.begin();
+ KLibFactory *factory = KLibLoader::self()->factory( service->library().latin1() );
+ if( !factory )
+ {
+ KMessageBox::error(this,i18n("KBabel cannot start a text editor component.\n"
+ "Please check your KDE installation."));
+ _part=0;
+ _view=0;
+ return false;
+ }
+ _part = static_cast<KTextEditor::Document *>( factory->create( this, 0, "KTextEditor::Document" ) );
+
+ if( !_part )
+ {
+ KMessageBox::error(this,i18n("KBabel cannot start a text editor component.\n"
+ "Please check your KDE installation."));
+ _part=0;
+ _view=0;
+ return false;
+ }
+ _view = _part->createView( this, 0 );
+ _layout->addWidget(static_cast<QWidget *>(_view), 1);
+ static_cast<QWidget *>(_view)->show();
+
+ return true;
+}
+
+void SourceContext::setProject( KBabel::Project::Ptr project )
+{
+ _project = project;
+}
+
+#include "context.moc"
+
+// kate: space-indent on; indent-width 4; replace-tabs on;
diff --git a/kbabel/commonui/context.h b/kbabel/commonui/context.h
new file mode 100644
index 00000000..2ccceecd
--- /dev/null
+++ b/kbabel/commonui/context.h
@@ -0,0 +1,123 @@
+/* ****************************************************************************
+ This file is part of KBabel
+
+ Copyright (C) 2002-2005 Stanislav Visnovsky
+ <visnovsky@kde.org>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the 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, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+ In addition, as a special exception, the copyright holders give
+ permission to link the code of this program with any edition of
+ the Qt library by Trolltech AS, Norway (or with modified versions
+ of Qt that use the same license as Qt), and distribute linked
+ combinations including the two. You must obey the GNU General
+ Public License in all respects for all of the code used other than
+ Qt. If you modify this file, you may extend this exception to
+ your version of the file, but you are not obligated to do so. If
+ you do not wish to do so, delete this exception statement from
+ your version.
+
+**************************************************************************** */
+#ifndef CONTEXT_H
+#define CONTEXT_H
+
+#include <qvaluelist.h>
+#include <qwidget.h>
+
+#include <ktexteditor/document.h>
+#include <ktexteditor/view.h>
+
+#include <kbproject.h>
+
+class QComboBox;
+class QVBoxLayout;
+class QLineEdit;
+class KListEditor;
+class KConfig;
+class KURL;
+
+struct ContextInfo
+{
+ QString path;
+ uint line;
+};
+
+/**
+ * @short Class for displaying source code context
+ *
+ * Widget for displaying source code context of for the given GNU gettext comment.
+ * The searched paths can be configured using variables.
+ *
+ * The possible variables are:
+ * - \@POFILEDIR\@ absolute directory of the PO file (to create paths relatives to the PO file)
+ * - \@PACKAGE\@ name of the PO file
+ * - \@PACKAGEDIR\@ relative directory of the PO file (relative to \@CODEROOT\@)
+ * - \@CODEROOT\@ base directory (especially of the catalog manager)
+ * - \@COMMENTPATH\@ (relative) path given as source code reference in a comment of the PO file
+ *
+ * @note The difference between \@POFILEDIR\@ and a path constructed by
+ * \@CODEROOT\@\@PACKAGEDIR\@/ is that \@POFILEDIR\@ will also work if the file is external
+ * to the catalog manager's root
+ *
+ * @note It requires a KPart implementing KTextEditor interface with selections.
+ * @author Stanislav Visnovsky <visnovsky@kde.org>
+ */
+class KDE_EXPORT SourceContext : public QWidget
+{
+ Q_OBJECT
+public:
+ SourceContext(QWidget* parent, KBabel::Project::Ptr project);
+
+ void setProject(KBabel::Project::Ptr project);
+
+public slots:
+ /**
+ * Try to find the corresponding file and load it to this widget.
+ * @param packageDir path of the package, where to find the source file
+ * @param packageName name of the package, where to find the source file
+ * @param gettextComment comment string with context as generated by xgettext (can start with #:)
+ * @param urlPoFile URL of the PO file
+ * @todo even if @p urlPoFile is an URL SourceContext::resolvePath is not remote-aware yet
+ */
+ void setContext( const QString& packageDir, const QString& packageName, const QString& gettextComment, const KURL& urlPoFile );
+
+private:
+ /**
+ * Get a list of paths from the source references in the comment @p gettextComment
+ * @param packageDir path of the package, where to find the source file
+ * @param packageName name of the package, where to find the source file
+ * @param gettextComment comment string with context as generated by xgettext (can start with #:)
+ * @param urlPoFile URL of the PO file
+ * @todo even if @p urlPoFile is an URL SourceContext::resolvePath is not remote-aware yet
+ * @private
+ */
+ QValueList<ContextInfo> resolvePath( const QString& packageDir, const QString& packageName, const QString& gettextComment, const KURL& urlPoFile );
+ bool loadPart();
+
+ /// Parent widget (for KIO::NetAccess member functions)
+ QWidget* m_parent;
+ KTextEditor::Document* _part;
+ KTextEditor::View* _view;
+ QComboBox *_referenceCombo;
+ QVBoxLayout *_layout;
+
+ QValueList<ContextInfo> _referenceList;
+
+ KBabel::Project::Ptr _project;
+private slots:
+ void updateToSelected(int index);
+};
+
+#endif // CONTEXT_H
diff --git a/kbabel/commonui/diffpreferences.ui b/kbabel/commonui/diffpreferences.ui
new file mode 100644
index 00000000..a3ea5a4e
--- /dev/null
+++ b/kbabel/commonui/diffpreferences.ui
@@ -0,0 +1,141 @@
+<!DOCTYPE UI><UI version="3.3" stdsetdef="1">
+<class>DiffPreferences</class>
+<author>Stanislav Visnovsky</author>
+<widget class="QWidget">
+ <property name="name">
+ <cstring>DiffPreferences</cstring>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>538</width>
+ <height>462</height>
+ </rect>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QButtonGroup">
+ <property name="name">
+ <cstring>kcfg_UseDBForDiff</cstring>
+ </property>
+ <property name="title">
+ <string>Diff Source</string>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>&lt;qt&gt;&lt;p&gt;&lt;b&gt;Source for difference lookup&lt;/b&gt;&lt;/p&gt;
+&lt;p&gt;Here you can select a source, which should be used
+for finding a difference.&lt;/p&gt;
+&lt;p&gt;You can select file, translation database or
+corresponding msgstr.&lt;/p&gt;
+&lt;p&gt;If you choose the translation database, the messages to diff with are
+taken from the Translation Database; to be useful, you have
+to enable &lt;i&gt;Auto add entry to database&lt;/i&gt; in its
+preferences dialog.&lt;/p&gt;
+&lt;p&gt;The last option is useful for those using PO-files
+for proofreading.&lt;/p&gt;
+&lt;p&gt;You can temporarily diff with messages from a file
+by choosing &lt;i&gt;Tools-&gt;Diff-&gt;Open file for diff&lt;/i&gt;
+in KBabel's main window.&lt;/p&gt;&lt;/qt&gt;</string>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QRadioButton">
+ <property name="name">
+ <cstring>radioButton1</cstring>
+ </property>
+ <property name="text">
+ <string>Use &amp;file</string>
+ </property>
+ </widget>
+ <widget class="QRadioButton">
+ <property name="name">
+ <cstring>radioButton2</cstring>
+ </property>
+ <property name="text">
+ <string>Use messages from &amp;translation database</string>
+ </property>
+ </widget>
+ <widget class="QRadioButton">
+ <property name="name">
+ <cstring>radioButton3</cstring>
+ </property>
+ <property name="text">
+ <string>Use &amp;msgstr from the same file</string>
+ </property>
+ </widget>
+ </vbox>
+ </widget>
+ <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>textLabel1</cstring>
+ </property>
+ <property name="text">
+ <string>Base folder for diff files:</string>
+ </property>
+ <property name="buddy" stdset="0">
+ <cstring>kcfg_DiffBaseDir</cstring>
+ </property>
+ </widget>
+ <widget class="KURLRequester">
+ <property name="name">
+ <cstring>kcfg_DiffBaseDir</cstring>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>&lt;qt&gt;&lt;q&gt;&lt;b&gt;Base folder for diff files&lt;/b&gt;&lt;/q&gt;
+&lt;p&gt;Here you can define a folder in which the files to
+diff with are stored. If the files are stored at the same
+place beneath this folder as the original files beneath
+their base folder, KBabel can automatically open the correct
+file to diff with.&lt;/p&gt;
+&lt;p&gt;Note that this option has no effect if messages from
+the database are used for diffing.&lt;/p&gt;&lt;/qt&gt;</string>
+ </property>
+ </widget>
+ </hbox>
+ </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>
+<customwidgets>
+</customwidgets>
+<includes>
+ <include location="local" impldecl="in implementation">diffpreferences.ui.h</include>
+</includes>
+<functions>
+ <function>init()</function>
+</functions>
+<layoutdefaults spacing="6" margin="11"/>
+<includehints>
+ <includehint>klineedit.h</includehint>
+ <includehint>kpushbutton.h</includehint>
+</includehints>
+</UI>
diff --git a/kbabel/commonui/diffpreferences.ui.h b/kbabel/commonui/diffpreferences.ui.h
new file mode 100644
index 00000000..5b02d278
--- /dev/null
+++ b/kbabel/commonui/diffpreferences.ui.h
@@ -0,0 +1,13 @@
+/****************************************************************************
+** 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.
+*****************************************************************************/
+
+void DiffPreferences::init()
+{
+ kcfg_DiffBaseDir->setMode(KFile::Directory);
+}
diff --git a/kbabel/commonui/finddialog.cpp b/kbabel/commonui/finddialog.cpp
new file mode 100644
index 00000000..7335f30a
--- /dev/null
+++ b/kbabel/commonui/finddialog.cpp
@@ -0,0 +1,553 @@
+/* ****************************************************************************
+ This file is part of KBabel
+
+ Copyright (C) 1999-2000 by Matthias Kiefer
+ <matthias.kiefer@gmx.de>
+ 2002 by Stanislav Visnovsky
+ <visnovsky@kde.org>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the 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, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+ In addition, as a special exception, the copyright holders give
+ permission to link the code of this program with any edition of
+ the Qt library by Trolltech AS, Norway (or with modified versions
+ of Qt that use the same license as Qt), and distribute linked
+ combinations including the two. You must obey the GNU General
+ Public License in all respects for all of the code used other than
+ Qt. If you modify this file, you may extend this exception to
+ your version of the file, but you are not obligated to do so. If
+ you do not wish to do so, delete this exception statement from
+ your version.
+
+**************************************************************************** */
+#include "finddialog.h"
+
+#include <qbuttongroup.h>
+#include <qcheckbox.h>
+#include <qgroupbox.h>
+#include <qpushbutton.h>
+#include <qlabel.h>
+#include <qlayout.h>
+#include <qhbox.h>
+#include <qwhatsthis.h>
+
+#include <kcombobox.h>
+#include <kconfig.h>
+#include <kglobal.h>
+#include <klocale.h>
+#include <kparts/componentfactory.h>
+#include <kregexpeditorinterface.h>
+
+using namespace KBabel;
+
+FindDialog::FindDialog(bool forReplace, QWidget* parent)
+ :KDialogBase(parent, "finddialog",true, "", Ok|Cancel, Ok)
+ , _regExpEditDialog(0), _replaceDlg(forReplace)
+{
+ QWidget* page = new QWidget(this);
+ QVBoxLayout *layout = new QVBoxLayout(page, 0, spacingHint());
+
+ QLabel *label = new QLabel(i18n("&Find:"),page);
+ layout->addWidget(label);
+
+ _findCombo = new KComboBox(true, page, "findCombo");
+ _findCombo->setMaxCount(10);
+ _findCombo->setInsertionPolicy(KComboBox::AtTop);
+ layout->addWidget(_findCombo);
+ label->setBuddy(_findCombo);
+
+ QString msg=i18n("<qt><p><b>Find text</b></p>"
+ "<p>Here you can enter the text you want to search for. "
+ "If you want to search for a regular expression, "
+ "enable <b>Use regular expression</b> below.</p></qt>");
+
+
+ QWhatsThis::add(label,msg);
+ QWhatsThis::add(_findCombo,msg);
+
+ if(forReplace) {
+ setCaption(i18n("Replace"));
+ setButtonOK(i18n("&Replace"));
+
+ _replaceLabel = new QLabel(i18n("&Replace with:"),page);
+ layout->addWidget(_replaceLabel);
+ _replaceCombo = new KComboBox(true, page, "replaceCombo");
+ _replaceCombo->setMaxCount(10);
+ _replaceCombo->setInsertionPolicy(KComboBox::AtTop);
+ layout->addWidget(_replaceCombo);
+ _replaceLabel->setBuddy(_replaceCombo);
+
+ msg=i18n("<qt><p><b>Replace text</b></p>"
+ "<p>Here you can enter the text you want the found text to get "
+ "replaced with. The text is used as is. It is not possible to make a back "
+ "reference, if you have searched for a regular expression.</p></qt>");
+
+ QWhatsThis::add(_replaceLabel,msg);
+ QWhatsThis::add(_replaceCombo,msg);
+ }
+ else {
+ setCaption(i18n("Find"));
+ setButtonOK(KGuiItem(i18n("&Find"),"find"));
+
+ _replaceLabel=0;
+ _replaceCombo=0;
+ }
+
+ _buttonGrp = new QButtonGroup(3, Qt::Horizontal, i18n("Where to Search"), page);
+ connect(_buttonGrp,SIGNAL(clicked(int)), this, SLOT(inButtonsClicked(int)));
+ layout->addWidget(_buttonGrp);
+
+ _inMsgid = new QCheckBox(i18n("&Msgid"),_buttonGrp);
+ _inMsgstr = new QCheckBox(i18n("M&sgstr"),_buttonGrp);
+ _inComment = new QCheckBox(i18n("Comm&ent"),_buttonGrp);
+
+ QWhatsThis::add(_buttonGrp,i18n("<qt><p><b>Where to search</b></p>"
+ "<p>Select here in which parts of a catalog entry you want "
+ "to search.</p></qt>"));
+
+
+ QGroupBox* box = new QGroupBox(2, Qt::Horizontal, i18n("Options"), page);
+ layout->addWidget(box);
+
+ _caseSensitive = new QCheckBox(i18n("C&ase sensitive"),box);
+ _wholeWords = new QCheckBox(i18n("O&nly whole words"),box);
+ _ignoreAccelMarker = new QCheckBox(i18n("I&gnore marker for keyboard accelerator"),box);
+ _ignoreContextInfo = new QCheckBox(i18n("Ignore con&text information"),box);
+ _fromCursor = new QCheckBox(i18n("From c&ursor position"),box);
+ _backwards = new QCheckBox(i18n("F&ind backwards"),box);
+
+ QHBox *regexp = new QHBox(box);
+
+ _isRegExp = new QCheckBox(i18n("Use regu&lar expression"),regexp);
+ _regExpButton = 0;
+
+ if( !KTrader::self()->query("KRegExpEditor/KRegExpEditor").isEmpty() )
+ {
+ _regExpButton = new QPushButton( i18n("&Edit..."), regexp );
+ connect( _regExpButton, SIGNAL( clicked() ), this, SLOT( regExpButtonClicked()));
+ connect( _isRegExp, SIGNAL( toggled(bool) ), _regExpButton, SLOT(setEnabled(bool)));
+ }
+
+ if(forReplace)
+ {
+ _inMsgid->setEnabled(false);
+ _askForReplace = new QCheckBox(i18n("As&k before replacing"),box);
+ _ignoreContextInfo->setEnabled(false);
+
+ QWhatsThis::add(box,i18n("<qt><p><b>Options</b></p>"
+ "<p>Here you can finetune replacing:"
+ "<ul><li><b>Case sensitive</b>: does case of entered text have to be respected?</li>"
+ "<li><b>Only whole words</b>: text found must not be part of a longer word</li>"
+ "<li><b>From cursor position</b>: start replacing at the part of the document where "
+ "the cursor is. Otherwise replacing is started at the beginning or the end.</li>"
+ "<li><b>Find backwards</b>: Should be self-explanatory.</li>"
+ "<li><b>Use regular expression</b>: use text entered in field <b>Find</b> "
+ "as a regular expression. This option has no effect with the replace text, especially "
+ "no back references are possible.</li>"
+ "<li><b>Ask before replacing</b>: Enable, if you want to have control about "
+ "what is replaced. Otherwise all found text is replaced without asking.</li>"
+ "</ul></p></qt>"));
+ }
+ else {
+ _askForReplace=0;
+
+ QWhatsThis::add(box,i18n("<qt><p><b>Options</b></p>"
+ "<p>Here you can finetune the search:"
+ "<ul><li><b>Case sensitive</b>: does case of entered text have to be respected?</li>"
+ "<li><b>Only whole words</b>: text found must not be part of a longer word</li>"
+ "<li><b>From cursor position</b>: start search at the part of the document, where "
+ "the cursor is. Otherwise search is started at the beginning or the end.</li>"
+ "<li><b>Find backwards</b>: Should be self-explanatory.</li>"
+ "<li><b>Use regular expression</b>: use entered text as a regular expression.</li>"
+ "</ul></p></qt>"));
+ }
+
+
+ readSettings();
+
+
+ setMainWidget(page);
+}
+
+FindDialog::~FindDialog()
+{
+ saveSettings();
+}
+
+int FindDialog::show(QString initialStr)
+{
+ if( !initialStr.isEmpty() ) {
+ _findCombo->setEditText( initialStr );
+ }
+ _findCombo->lineEdit()->selectAll();
+ _findCombo->setFocus();
+
+
+ KDialogBase::show();
+
+ int r = result();
+
+ if( r == QDialog::Accepted ) {
+ if(_replaceDlg) {
+ _replaceList.remove(_replaceCombo->currentText());
+ _replaceList.prepend(_replaceCombo->currentText());
+ if(_replaceList.count() > 10 )
+ _replaceList.remove(_replaceList.fromLast());
+
+ _replaceCombo->clear();
+ _replaceCombo->insertStringList(_replaceList);
+
+ _replaceFindList.remove(_findCombo->currentText());
+ _replaceFindList.prepend(_findCombo->currentText());
+ if(_replaceFindList.count() > 10 )
+ _replaceFindList.remove(_replaceFindList.fromLast());
+
+ _findCombo->clear();
+ _findCombo->insertStringList(_replaceFindList);
+
+ _replaceOptions.findStr = _findCombo->currentText();
+ _replaceOptions.replaceStr = _replaceCombo->currentText();
+
+ _replaceOptions.inMsgstr = _inMsgstr->isChecked();
+ _replaceOptions.inComment = _inComment->isChecked();
+ _replaceOptions.inMsgid = false;
+
+ _replaceOptions.caseSensitive = _caseSensitive->isChecked();
+ _replaceOptions.wholeWords = _wholeWords->isChecked();
+ _replaceOptions.ignoreAccelMarker = _ignoreAccelMarker->isChecked();
+ _replaceOptions.ignoreContextInfo = false;
+ _replaceOptions.backwards = _backwards->isChecked();
+ _replaceOptions.fromCursor = _fromCursor->isChecked();
+ _replaceOptions.isRegExp = _isRegExp->isChecked();
+ _replaceOptions.ask = _askForReplace->isChecked();
+ }
+ else {
+ _findList.remove(_findCombo->currentText());
+ _findList.prepend(_findCombo->currentText());
+ if(_findList.count() > 10 )
+ _findList.remove(_findList.fromLast());
+
+ _findCombo->clear();
+ _findCombo->insertStringList(_findList);
+
+ _findOptions.findStr = _findCombo->currentText();
+ _findOptions.inMsgid = _inMsgid->isChecked();
+ _findOptions.inMsgstr = _inMsgstr->isChecked();
+ _findOptions.inComment = _inComment->isChecked();
+
+ _findOptions.caseSensitive = _caseSensitive->isChecked();
+ _findOptions.wholeWords = _wholeWords->isChecked();
+ _findOptions.ignoreAccelMarker = _ignoreAccelMarker->isChecked();
+ _findOptions.ignoreContextInfo = _ignoreContextInfo->isChecked();
+ _findOptions.backwards = _backwards->isChecked();
+ _findOptions.fromCursor = _fromCursor->isChecked();
+ _findOptions.isRegExp = _isRegExp->isChecked();
+ }
+ }
+
+ return r;
+}
+
+int FindDialog::exec(QString initialStr)
+{
+ if( !initialStr.isEmpty() ) {
+ _findCombo->setEditText( initialStr );
+ }
+ _findCombo->lineEdit()->selectAll();
+ _findCombo->setFocus();
+
+
+ KDialogBase::exec();
+
+ int r = result();
+
+ if( r == QDialog::Accepted ) {
+ if(_replaceDlg) {
+ _replaceList.remove(_replaceCombo->currentText());
+ _replaceList.prepend(_replaceCombo->currentText());
+ if(_replaceList.count() > 10 )
+ _replaceList.remove(_replaceList.fromLast());
+
+ _replaceCombo->clear();
+ _replaceCombo->insertStringList(_replaceList);
+
+ _replaceFindList.remove(_findCombo->currentText());
+ _replaceFindList.prepend(_findCombo->currentText());
+ if(_replaceFindList.count() > 10 )
+ _replaceFindList.remove(_replaceFindList.fromLast());
+
+ _findCombo->clear();
+ _findCombo->insertStringList(_replaceFindList);
+
+ _replaceOptions.findStr = _findCombo->currentText();
+ _replaceOptions.replaceStr = _replaceCombo->currentText();
+
+ _replaceOptions.inMsgstr = _inMsgstr->isChecked();
+ _replaceOptions.inComment = _inComment->isChecked();
+ _replaceOptions.inMsgid = false;
+
+ _replaceOptions.caseSensitive = _caseSensitive->isChecked();
+ _replaceOptions.wholeWords = _wholeWords->isChecked();
+ _replaceOptions.ignoreAccelMarker = _ignoreAccelMarker->isChecked();
+ _replaceOptions.ignoreContextInfo = false;
+ _replaceOptions.backwards = _backwards->isChecked();
+ _replaceOptions.fromCursor = _fromCursor->isChecked();
+ _replaceOptions.isRegExp = _isRegExp->isChecked();
+ _replaceOptions.ask = _askForReplace->isChecked();
+ }
+ else {
+ _findList.remove(_findCombo->currentText());
+ _findList.prepend(_findCombo->currentText());
+ if(_findList.count() > 10 )
+ _findList.remove(_findList.fromLast());
+
+ _findCombo->clear();
+ _findCombo->insertStringList(_findList);
+
+ _findOptions.findStr = _findCombo->currentText();
+ _findOptions.inMsgid = _inMsgid->isChecked();
+ _findOptions.inMsgstr = _inMsgstr->isChecked();
+ _findOptions.inComment = _inComment->isChecked();
+
+ _findOptions.caseSensitive = _caseSensitive->isChecked();
+ _findOptions.wholeWords = _wholeWords->isChecked();
+ _findOptions.ignoreAccelMarker = _ignoreAccelMarker->isChecked();
+ _findOptions.ignoreContextInfo = _ignoreContextInfo->isChecked();
+ _findOptions.backwards = _backwards->isChecked();
+ _findOptions.fromCursor = _fromCursor->isChecked();
+ _findOptions.isRegExp = _isRegExp->isChecked();
+ }
+ }
+
+ return r;
+}
+
+FindOptions FindDialog::findOpts()
+{
+ return _findOptions;
+}
+
+void FindDialog::setFindOpts(FindOptions options)
+{
+ _findOptions = options;
+ _inMsgid->setChecked(_findOptions.inMsgid);
+ _inMsgstr->setChecked(_findOptions.inMsgstr);
+ _inComment->setChecked(_findOptions.inComment);
+
+ _caseSensitive->setChecked(_findOptions.caseSensitive);
+ _wholeWords->setChecked(_findOptions.wholeWords);
+ _ignoreAccelMarker->setChecked(_findOptions.ignoreAccelMarker);
+ _ignoreContextInfo->setChecked(_findOptions.ignoreContextInfo);
+ _backwards->setChecked(_findOptions.backwards);
+ _fromCursor->setChecked(_findOptions.fromCursor);
+ _isRegExp->setChecked(_findOptions.isRegExp);
+ if( _regExpButton ) _regExpButton->setEnabled( _findOptions.isRegExp );
+
+ _findCombo->setEditText(_findOptions.findStr);
+}
+
+ReplaceOptions FindDialog::replaceOpts()
+{
+ return _replaceOptions;
+}
+
+void FindDialog::setReplaceOpts(ReplaceOptions options)
+{
+ _replaceOptions = options;
+ _inMsgid->setChecked(_replaceOptions.inMsgid);
+ _inMsgstr->setChecked(_replaceOptions.inMsgstr);
+ _inComment->setChecked(_replaceOptions.inComment);
+
+ _caseSensitive->setChecked(_replaceOptions.caseSensitive);
+ _wholeWords->setChecked(_replaceOptions.wholeWords);
+ _ignoreAccelMarker->setChecked(_replaceOptions.ignoreAccelMarker);
+ _ignoreContextInfo->setChecked(_replaceOptions.ignoreContextInfo);
+ _backwards->setChecked(_replaceOptions.backwards);
+ _fromCursor->setChecked(_replaceOptions.fromCursor);
+ _isRegExp->setChecked(_replaceOptions.isRegExp);
+ _askForReplace->setChecked(_replaceOptions.ask);
+ if( _regExpButton ) _regExpButton->setEnabled( _replaceOptions.isRegExp );
+
+ _findCombo->setEditText(_replaceOptions.findStr);
+ _replaceCombo->setEditText(_replaceOptions.replaceStr);
+}
+
+void FindDialog::readSettings()
+{
+ KConfig* config = KGlobal::config();
+
+ if(_replaceDlg) {
+ KConfigGroupSaver cgs(config,"ReplaceDialog");
+ _replaceOptions.inMsgstr = config->readBoolEntry("InMsgstr",true);
+ _replaceOptions.inComment = config->readBoolEntry("InComment",false);
+
+ _replaceOptions.caseSensitive =
+ config->readBoolEntry("CaseSensitive",true);
+ _replaceOptions.wholeWords = config->readBoolEntry("WholeWords",false);
+ _replaceOptions.ignoreAccelMarker =
+ config->readBoolEntry("IgnoreAccelMarker",true);
+ _replaceOptions.backwards = config->readBoolEntry("Backwards",false);
+ _replaceOptions.fromCursor = config->readBoolEntry("FromCursor",true);
+ _replaceOptions.isRegExp = config->readBoolEntry("RegExp",false);
+ _replaceOptions.ask = config->readBoolEntry("AskForReplace",true);
+ _replaceFindList = config->readListEntry("FindList");
+ _replaceList = config->readListEntry("ReplaceList");
+
+ _inMsgstr->setChecked(_replaceOptions.inMsgstr);
+ _inComment->setChecked(_replaceOptions.inComment);
+
+ _caseSensitive->setChecked(_replaceOptions.caseSensitive);
+ _wholeWords->setChecked(_replaceOptions.wholeWords);
+ _ignoreAccelMarker->setChecked(_findOptions.ignoreAccelMarker);
+ _backwards->setChecked(_replaceOptions.backwards);
+ _fromCursor->setChecked(_replaceOptions.fromCursor);
+ _isRegExp->setChecked(_replaceOptions.isRegExp);
+ _askForReplace->setChecked(_replaceOptions.ask);
+ if( _regExpButton ) _regExpButton->setEnabled( _findOptions.isRegExp );
+
+ _replaceCombo->insertStringList(_replaceList);
+ _findCombo->insertStringList(_replaceFindList);
+ }
+ else {
+ KConfigGroupSaver cgs(config,"FindDialog");
+
+ _findOptions.inMsgid = config->readBoolEntry("InMsgid",true);
+ _findOptions.inMsgstr = config->readBoolEntry("InMsgstr",true);
+ _findOptions.inComment = config->readBoolEntry("InComment",false);
+
+ _findOptions.caseSensitive = config->readBoolEntry("CaseSensitive"
+ ,false);
+ _findOptions.wholeWords = config->readBoolEntry("WholeWords",false);
+ _findOptions.ignoreAccelMarker =
+ config->readBoolEntry("IgnoreAccelMarker",true);
+ _findOptions.ignoreContextInfo =
+ config->readBoolEntry("IgnoreContextInfo",true);
+ _findOptions.backwards = config->readBoolEntry("Backwards",false);
+ _findOptions.fromCursor = config->readBoolEntry("FromCursor",false);
+ _findOptions.isRegExp = config->readBoolEntry("RegExp",false);
+ _findList = config->readListEntry("List");
+ if( _regExpButton ) _regExpButton->setEnabled( _findOptions.isRegExp );
+
+ _inMsgid->setChecked(_findOptions.inMsgid);
+ _inMsgstr->setChecked(_findOptions.inMsgstr);
+ _inComment->setChecked(_findOptions.inComment);
+
+ _caseSensitive->setChecked(_findOptions.caseSensitive);
+ _wholeWords->setChecked(_findOptions.wholeWords);
+ _ignoreAccelMarker->setChecked(_findOptions.ignoreAccelMarker);
+ _ignoreContextInfo->setChecked(_findOptions.ignoreContextInfo);
+ _backwards->setChecked(_findOptions.backwards);
+ _fromCursor->setChecked(_findOptions.fromCursor);
+ _isRegExp->setChecked(_findOptions.isRegExp);
+
+ _findCombo->insertStringList(_findList);
+ }
+
+}
+
+void FindDialog::saveSettings()
+{
+ KConfig* config = KGlobal::config();
+
+ if(_replaceDlg) {
+ KConfigGroupSaver cgs(config,"ReplaceDialog");
+ config->writeEntry("InMsgstr",_replaceOptions.inMsgstr);
+ config->writeEntry("InComment",_replaceOptions.inComment);
+
+ config->writeEntry("CaseSensitive",_replaceOptions.caseSensitive);
+ config->writeEntry("WholeWords",_replaceOptions.wholeWords);
+ config->writeEntry("IgnoreAccelMarker"
+ ,_replaceOptions.ignoreAccelMarker);
+ config->writeEntry("Backwards",_replaceOptions.backwards);
+ config->writeEntry("FromCursor",_replaceOptions.fromCursor);
+ config->writeEntry("RegExp",_replaceOptions.isRegExp);
+ config->writeEntry("AskForReplace",_replaceOptions.ask);
+ config->writeEntry("FindList",_replaceFindList);
+ config->writeEntry("ReplaceList",_replaceList);
+ }
+ else {
+ KConfigGroupSaver cgs(config,"FindDialog");
+
+ config->writeEntry("InMsgid",_findOptions.inMsgid);
+ config->writeEntry("InMsgstr",_findOptions.inMsgstr);
+ config->writeEntry("InComment",_findOptions.inComment);
+
+ config->writeEntry("CaseSensitive",_findOptions.caseSensitive);
+ config->writeEntry("WholeWords",_findOptions.wholeWords);
+ config->writeEntry("IgnoreAccelMarker"
+ ,_findOptions.ignoreAccelMarker);
+ config->writeEntry("IgnoreContextInfo"
+ ,_findOptions.ignoreContextInfo);
+ config->writeEntry("Backwards",_findOptions.backwards);
+ config->writeEntry("FromCursor",_findOptions.fromCursor);
+ config->writeEntry("RegExp",_findOptions.isRegExp);
+ config->writeEntry("List",_findList);
+ }
+}
+
+
+
+void FindDialog::inButtonsClicked(int id)
+{
+ // check if at least one button is checked
+ if(! _buttonGrp->find(id)->isOn() ) {
+ if(!_inMsgstr->isOn() && !_inComment->isOn() ) {
+ if(_inMsgid->isEnabled()) {
+ if( !_inMsgid->isOn() ) {
+ _buttonGrp->setButton(id);
+ }
+ }
+ else {
+ _buttonGrp->setButton(id);
+ }
+
+ }
+ }
+}
+
+void FindDialog::regExpButtonClicked()
+{
+ if ( _regExpEditDialog == 0 )
+ _regExpEditDialog = KParts::ComponentFactory::createInstanceFromQuery<QDialog>( "KRegExpEditor/KRegExpEditor", QString::null, this );
+
+ KRegExpEditorInterface *iface = dynamic_cast<KRegExpEditorInterface *>( _regExpEditDialog );
+ if( iface )
+ {
+ iface->setRegExp( _findCombo->currentText() );
+ if( _regExpEditDialog->exec() == QDialog::Accepted )
+ _findCombo->setCurrentText( iface->regExp() );
+ }
+}
+
+ReplaceDialog::ReplaceDialog(QWidget* parent)
+ :KDialogBase(Plain, "", Close|User1|User2|User3, User1, parent,"finddialog"
+ , true,false,i18n("&Replace"),i18n("&Goto Next"),i18n("R&eplace All"))
+{
+ QWidget* page = plainPage();
+ QVBoxLayout *layout = new QVBoxLayout(page, 0, spacingHint());
+
+ QLabel *label = new QLabel(i18n("Replace this string?"),page);
+ layout->addWidget(label);
+
+ connect(this,SIGNAL(user1Clicked()),this,SIGNAL(replace()));
+ connect(this,SIGNAL(user2Clicked()),this,SIGNAL(next()));
+ connect(this,SIGNAL(user3Clicked()),this,SIGNAL(replaceAll()));
+}
+
+ReplaceDialog::~ReplaceDialog()
+{
+}
+
+#include "finddialog.moc"
diff --git a/kbabel/commonui/finddialog.h b/kbabel/commonui/finddialog.h
new file mode 100644
index 00000000..7baa0675
--- /dev/null
+++ b/kbabel/commonui/finddialog.h
@@ -0,0 +1,136 @@
+/* ****************************************************************************
+ This file is part of KBabel
+
+ Copyright (C) 1999-2000 by Matthias Kiefer
+ <matthias.kiefer@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.
+
+ 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, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+ In addition, as a special exception, the copyright holders give
+ permission to link the code of this program with any edition of
+ the Qt library by Trolltech AS, Norway (or with modified versions
+ of Qt that use the same license as Qt), and distribute linked
+ combinations including the two. You must obey the GNU General
+ Public License in all respects for all of the code used other than
+ Qt. If you modify this file, you may extend this exception to
+ your version of the file, but you are not obligated to do so. If
+ you do not wish to do so, delete this exception statement from
+ your version.
+
+**************************************************************************** */
+#ifndef FINDDIALOG_H
+#define FINDDIALOG_H
+
+#include <qstring.h>
+#include <qstringlist.h>
+#include <kdialogbase.h>
+
+class QButtonGroup;
+class QCheckBox;
+class QLabel;
+class KComboBox;
+
+#include "findoptions.h"
+
+class KDE_EXPORT FindDialog : public KDialogBase
+{
+ Q_OBJECT
+public:
+ /**
+ * Constructor
+ * @param replaceDlg flag, if this is a replace dialog
+ */
+ FindDialog(bool replaceDlg, QWidget* parent);
+ ~FindDialog();
+
+ /**
+ * shows the dialog
+ * @param initialStr string to display in find field.
+ * If empty, the last used string is used.
+ *
+ * @return the result code of the dialog
+ */
+ int show(QString initialStr);
+
+ /**
+ * executes the dialog as modal
+ * @param initialStr string to display in find field.
+ * If empty, the last used string is used.
+ *
+ * @return the result code of the dialog
+ */
+ int exec(QString initialStr);
+ KBabel::FindOptions findOpts();
+ void setFindOpts(KBabel::FindOptions options);
+ KBabel::ReplaceOptions replaceOpts();
+ void setReplaceOpts(KBabel::ReplaceOptions options);
+
+protected:
+ void readSettings();
+ void saveSettings();
+
+ bool isReplaceDialog() { return _replaceDlg; }
+
+private slots:
+ void inButtonsClicked(int id);
+ void regExpButtonClicked();
+
+private:
+ KComboBox *_findCombo;
+ KComboBox *_replaceCombo;
+ QLabel *_replaceLabel;
+
+ QButtonGroup *_buttonGrp;
+ QCheckBox *_inMsgid;
+ QCheckBox *_inMsgstr;
+ QCheckBox *_inComment;
+
+ QCheckBox *_caseSensitive;
+ QCheckBox *_wholeWords;
+ QCheckBox *_ignoreAccelMarker;
+ QCheckBox *_ignoreContextInfo;
+ QCheckBox *_backwards;
+ QCheckBox *_fromCursor;
+ QCheckBox *_isRegExp;
+ QCheckBox *_askForReplace;
+
+ QPushButton *_regExpButton;
+ QDialog *_regExpEditDialog;
+
+ KBabel::FindOptions _findOptions;
+ KBabel::ReplaceOptions _replaceOptions;
+
+ QStringList _findList;
+ QStringList _replaceFindList;
+ QStringList _replaceList;
+
+ bool _replaceDlg;
+};
+
+class KDE_EXPORT ReplaceDialog : public KDialogBase
+{
+ Q_OBJECT
+public:
+ ReplaceDialog(QWidget* parent);
+ ~ReplaceDialog();
+
+signals:
+ void replace();
+ void replaceAll();
+ void next();
+
+};
+
+#endif // FINDDIALOG_H
diff --git a/kbabel/commonui/kactionselector.cpp b/kbabel/commonui/kactionselector.cpp
new file mode 100644
index 00000000..b214a49f
--- /dev/null
+++ b/kbabel/commonui/kactionselector.cpp
@@ -0,0 +1,562 @@
+/***************************************************************************
+ KActionSelector.cpp
+ A widget for selecting and arranging actions/objects
+ -------------------
+ begin : Mon June 3 2002
+ copyright : (C) 2002 by Anders Lund
+ email : anders@alweb.dk
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * *
+ * In addition, as a special exception, the copyright holders give *
+ * permission to link the code of this program with any edition of *
+ * the Qt library by Trolltech AS, Norway (or with modified versions *
+ * of Qt that use the same license as Qt), and distribute linked *
+ * combinations including the two. You must obey the GNU General *
+ * Public License in all respects for all of the code used other than *
+ * Qt. If you modify this file, you may extend this exception to *
+ * your version of the file, but you are not obligated to do so. If *
+ * you do not wish to do so, delete this exception statement from *
+ * your version. *
+ ***************************************************************************/
+
+#include "kactionselector.h"
+#include <resources.h>
+
+#include <klocale.h>
+#include <kiconloader.h>
+#include <kdialog.h> // for spacingHint()
+#include <kdebug.h>
+
+#include <qlistbox.h>
+#include <qtoolbutton.h>
+#include <qlabel.h>
+#include <qlayout.h>
+#include <qevent.h>
+#include <qwhatsthis.h>
+#include <qapplication.h>
+
+class KActionSelectorPrivate {
+ public:
+ QListBox *availableListBox, *selectedListBox;
+ QToolButton *btnAdd, *btnRemove, *btnUp, *btnDown;
+ QLabel *lAvailable, *lSelected;
+ bool moveOnDoubleClick, keyboardEnabled;
+ KActionSelector::ButtonIconSize iconSize;
+ QString addIcon, removeIcon, upIcon, downIcon;
+ KActionSelector::InsertionPolicy availableInsertionPolicy, selectedInsertionPolicy;
+ bool showUpDownButtons;
+};
+
+//BEGIN Constructor/destructor
+
+KActionSelector::KActionSelector( QWidget *parent, const char *name )
+ : QWidget( parent, name )
+{
+ d = new KActionSelectorPrivate();
+ d->moveOnDoubleClick = true;
+ d->keyboardEnabled = true;
+ d->iconSize = SmallIcon;
+ d->addIcon = QApplication::reverseLayout() ? "back" : "forward";
+ d->removeIcon = QApplication::reverseLayout() ? "forward" : "back";
+ d->upIcon = "up";
+ d->downIcon = "down";
+ d->availableInsertionPolicy = Sorted;
+ d->selectedInsertionPolicy = BelowCurrent;
+ d->showUpDownButtons = true;
+
+ //int isz = IconSize( KIcon::Small );
+
+ QHBoxLayout *lo = new QHBoxLayout( this );
+ lo->setSpacing( KDialog::spacingHint() );
+
+ QVBoxLayout *loAv = new QVBoxLayout( lo );
+ d->lAvailable = new QLabel( i18n("&Available:"), this );
+ loAv->addWidget( d->lAvailable );
+ d->availableListBox = new QListBox( this );
+ loAv->addWidget( d->availableListBox );
+ d->lAvailable->setBuddy( d->availableListBox );
+
+ QVBoxLayout *loHBtns = new QVBoxLayout( lo );
+ loHBtns->addStretch( 1 );
+ d->btnAdd = new QToolButton( this );
+ loHBtns->addWidget( d->btnAdd );
+ d->btnRemove = new QToolButton( this );
+ loHBtns->addWidget( d->btnRemove );
+ loHBtns->addStretch( 1 );
+
+ QVBoxLayout *loS = new QVBoxLayout( lo );
+ d->lSelected = new QLabel( i18n("&Selected:"), this );
+ loS->addWidget( d->lSelected );
+ d->selectedListBox = new QListBox( this );
+ loS->addWidget( d->selectedListBox );
+ d->lSelected->setBuddy( d->selectedListBox );
+
+ QVBoxLayout *loVBtns = new QVBoxLayout( lo );
+ loVBtns->addStretch( 1 );
+ d->btnUp = new QToolButton( this );
+ loVBtns->addWidget( d->btnUp );
+ d->btnDown = new QToolButton( this );
+ loVBtns->addWidget( d->btnDown );
+ loVBtns->addStretch( 1 );
+
+ loadIcons();
+
+ connect( d->btnAdd, SIGNAL(clicked()), this, SLOT(buttonAddClicked()) );
+ connect( d->btnRemove, SIGNAL(clicked()), this, SLOT(buttonRemoveClicked()) );
+ connect( d->btnUp, SIGNAL(clicked()), this, SLOT(buttonUpClicked()) );
+ connect( d->btnDown, SIGNAL(clicked()), this, SLOT(buttonDownClicked()) );
+ connect( d->availableListBox, SIGNAL(doubleClicked(QListBoxItem*)),
+ this, SLOT(itemDoubleClicked(QListBoxItem*)) );
+ connect( d->selectedListBox, SIGNAL(doubleClicked(QListBoxItem*)),
+ this, SLOT(itemDoubleClicked(QListBoxItem*)) );
+ connect( d->availableListBox, SIGNAL(currentChanged(QListBoxItem*)),
+ this, SLOT(slotCurrentChanged(QListBoxItem *)) );
+ connect( d->selectedListBox, SIGNAL(currentChanged(QListBoxItem*)),
+ this, SLOT(slotCurrentChanged(QListBoxItem *)) );
+
+ d->availableListBox->installEventFilter( this );
+ d->selectedListBox->installEventFilter( this );
+}
+
+KActionSelector::~KActionSelector()
+{
+ delete d;
+}
+
+//END Constructor/destroctor
+
+//BEGIN Public Methods
+
+QListBox *KActionSelector::availableListBox()
+{
+ return d->availableListBox;
+}
+
+QListBox *KActionSelector::selectedListBox()
+{
+ return d->selectedListBox;
+}
+
+void KActionSelector::setButtonIcon( const QString &icon, MoveButton button )
+{
+ int isz;
+ if ( d->iconSize == SmallIcon ) isz = IconSize( KIcon::Small );
+ else if ( d->iconSize == Small ) isz = 16;
+ else if ( d->iconSize == Medium ) isz = 22;
+ else if ( d->iconSize == Large ) isz = 32;
+ else if ( d->iconSize == XLarge ) isz = 48;
+
+ switch ( button )
+ {
+ case ButtonAdd:
+ d->addIcon = icon;
+ d->btnAdd->setIconSet( SmallIconSet( icon, isz ) );
+ break;
+ case ButtonRemove:
+ d->removeIcon = icon;
+ d->btnRemove->setIconSet( SmallIconSet( icon, isz ) );
+ break;
+ case ButtonUp:
+ d->upIcon = icon;
+ d->btnUp->setIconSet( SmallIconSet( icon, isz ) );
+ break;
+ case ButtonDown:
+ d->downIcon = icon;
+ d->btnDown->setIconSet( SmallIconSet( icon, isz ) );
+ break;
+ default:
+ kdDebug(KBABEL)<<"KActionSelector::setButtonIcon: DAINBREAD!"<<endl;
+ }
+}
+
+void KActionSelector::setButtonIconSet( const QIconSet &iconset, MoveButton button )
+{
+ switch ( button )
+ {
+ case ButtonAdd:
+ d->btnAdd->setIconSet( iconset );
+ break;
+ case ButtonRemove:
+ d->btnRemove->setIconSet( iconset );
+ break;
+ case ButtonUp:
+ d->btnUp->setIconSet( iconset );
+ break;
+ case ButtonDown:
+ d->btnDown->setIconSet( iconset );
+ break;
+ default:
+ kdDebug(KBABEL)<<"KActionSelector::setButtonIconSet: DAINBREAD!"<<endl;
+ }
+}
+
+void KActionSelector::setButtonTooltip( const QString &tip, MoveButton button )
+{
+ switch ( button )
+ {
+ case ButtonAdd:
+ d->btnAdd->setTextLabel( tip );
+ break;
+ case ButtonRemove:
+ d->btnRemove->setTextLabel( tip );
+ break;
+ case ButtonUp:
+ d->btnUp->setTextLabel( tip );
+ break;
+ case ButtonDown:
+ d->btnDown->setTextLabel( tip );
+ break;
+ default:
+ kdDebug(KBABEL)<<"KActionSelector::setButtonToolTip: DAINBREAD!"<<endl;
+ }
+}
+
+void KActionSelector::setButtonWhatsThis( const QString &text, MoveButton button )
+{
+ switch ( button )
+ {
+ case ButtonAdd:
+ QWhatsThis::add( d->btnAdd, text );
+ break;
+ case ButtonRemove:
+ QWhatsThis::add( d->btnRemove, text );
+ break;
+ case ButtonUp:
+ QWhatsThis::add( d->btnUp, text );
+ break;
+ case ButtonDown:
+ QWhatsThis::add( d->btnDown, text );
+ break;
+ default:
+ kdDebug(KBABEL)<<"KActionSelector::setButtonWhatsThis: DAINBREAD!"<<endl;
+ }
+}
+
+void KActionSelector::setButtonsEnabled()
+{
+ d->btnAdd->setEnabled( d->availableListBox->currentItem() > -1 );
+ d->btnRemove->setEnabled( d->selectedListBox->currentItem() > -1 );
+ d->btnUp->setEnabled( d->selectedListBox->currentItem() > 0 );
+ d->btnDown->setEnabled( d->selectedListBox->currentItem() > -1 &&
+ d->selectedListBox->currentItem() < (int)d->selectedListBox->count() - 1 );
+}
+
+//END Public Methods
+
+//BEGIN Properties
+
+bool KActionSelector::moveOnDoubleClick() const
+{
+ return d->moveOnDoubleClick;
+}
+
+void KActionSelector::setMoveOnDoubleClick( bool b )
+{
+ d->moveOnDoubleClick = b;
+}
+
+bool KActionSelector::keyboardEnabled() const
+{
+ return d->keyboardEnabled;
+}
+
+void KActionSelector::setKeyboardEnabled( bool b )
+{
+ d->keyboardEnabled = b;
+}
+
+QString KActionSelector::availableLabel() const
+{
+ return d->lAvailable->text();
+}
+
+void KActionSelector::setAvailableLabel( const QString &text )
+{
+ d->lAvailable->setText( text );
+}
+
+QString KActionSelector::selectedLabel() const
+{
+ return d->lSelected->text();
+}
+
+void KActionSelector::setSelectedLabel( const QString &text )
+{
+ d->lSelected->setText( text );
+}
+
+KActionSelector::ButtonIconSize KActionSelector::buttonIconSize() const
+{
+ return d->iconSize;
+}
+
+void KActionSelector::setButtonIconSize( ButtonIconSize size )
+{
+ d->iconSize = size;
+ // reload icons
+ loadIcons();
+}
+
+KActionSelector::InsertionPolicy KActionSelector::availableInsertionPolicy()
+{
+ return d->availableInsertionPolicy;
+}
+
+void KActionSelector::setAvailableInsertionPolicy( InsertionPolicy p )
+{
+ d->availableInsertionPolicy = p;
+}
+
+KActionSelector::InsertionPolicy KActionSelector::selectedInsertionPolicy()
+{
+ return d->selectedInsertionPolicy;
+}
+
+void KActionSelector::setSelectedInsertionPolicy( InsertionPolicy p )
+{
+ d->selectedInsertionPolicy = p;
+}
+
+bool KActionSelector::showUpDownButtons()
+{
+ return d->showUpDownButtons;
+}
+
+void KActionSelector::setShowUpDownButtons( bool show )
+{
+ d->showUpDownButtons = show;
+ if ( show )
+ {
+ d->btnUp->show();
+ d->btnDown->show();
+ }
+ else
+ {
+ d->btnUp->hide();
+ d->btnDown->hide();
+ }
+}
+
+//END Properties
+
+//BEGIN Public Slots
+
+void KActionSelector::polish()
+{
+ setButtonsEnabled();
+}
+
+//END Public Slots
+
+//BEGIN Protected
+void KActionSelector::keyPressEvent( QKeyEvent *e )
+{
+ if ( ! d->keyboardEnabled ) return;
+ if ( (e->state() & Qt::ControlButton) )
+ {
+ switch ( e->key() )
+ {
+ case Key_Right:
+ buttonAddClicked();
+ break;
+ case Key_Left:
+ buttonRemoveClicked();
+ break;
+ case Key_Up:
+ buttonUpClicked();
+ break;
+ case Key_Down:
+ buttonDownClicked();
+ break;
+ default:
+ e->ignore();
+ return;
+ }
+ }
+}
+
+bool KActionSelector::eventFilter( QObject *o, QEvent *e )
+{
+ if ( d->keyboardEnabled && e->type() == QEvent::KeyPress )
+ {
+ if ( (((QKeyEvent*)e)->state() & Qt::ControlButton) )
+ {
+ switch ( ((QKeyEvent*)e)->key() )
+ {
+ case Key_Right:
+ buttonAddClicked();
+ break;
+ case Key_Left:
+ buttonRemoveClicked();
+ break;
+ case Key_Up:
+ buttonUpClicked();
+ break;
+ case Key_Down:
+ buttonDownClicked();
+ break;
+ default:
+ return QWidget::eventFilter( o, e );
+ break;
+ }
+ return true;
+ }
+ else if ( o->inherits( "QListBox" ) )
+ {
+ switch ( ((QKeyEvent*)e)->key() )
+ {
+ case Key_Return:
+ case Key_Enter:
+ QListBox *lb = (QListBox*)o;
+ int index = lb->currentItem();
+ if ( index < 0 ) break;
+ moveItem( lb->item( index ) );
+ return true;
+ }
+ }
+ }
+ return QWidget::eventFilter( o, e );
+}
+
+//END Protected
+
+//BEGIN Private Slots
+
+void KActionSelector::buttonAddClicked()
+{
+ // move all selected items from available to selected listbox
+ QListBoxItem *item = d->availableListBox->firstItem();
+ while ( item ) {
+ if ( item->isSelected() ) {
+ d->availableListBox->takeItem( item );
+ d->selectedListBox->insertItem( item, insertionIndex( d->selectedListBox, d->selectedInsertionPolicy ) );
+ d->selectedListBox->setCurrentItem( item );
+ emit added( item );
+ }
+ item = item->next();
+ }
+ if ( d->selectedInsertionPolicy == Sorted )
+ d->selectedListBox->sort();
+ d->selectedListBox->setFocus();
+}
+
+void KActionSelector::buttonRemoveClicked()
+{
+ // move all selected items from selected to available listbox
+ QListBoxItem *item = d->selectedListBox->firstItem();
+ while ( item ) {
+ if ( item->isSelected() ) {
+ d->selectedListBox->takeItem( item );
+ d->availableListBox->insertItem( item, insertionIndex( d->availableListBox, d->availableInsertionPolicy ) );
+ d->availableListBox->setCurrentItem( item );
+ emit removed( item );
+ }
+ item = item->next();
+ }
+ if ( d->availableInsertionPolicy == Sorted )
+ d->availableListBox->sort();
+ d->availableListBox->setFocus();
+}
+
+void KActionSelector::buttonUpClicked()
+{
+ int c = d->selectedListBox->currentItem();
+ if ( c < 0 ) return;
+ QListBoxItem *item = d->selectedListBox->item( c );
+ d->selectedListBox->takeItem( item );
+ d->selectedListBox->insertItem( item, c-1 );
+ d->selectedListBox->setCurrentItem( item );
+ emit movedUp( item );
+}
+
+void KActionSelector::buttonDownClicked()
+{
+ int c = d->selectedListBox->currentItem();
+ if ( c < 0 ) return;
+ QListBoxItem *item = d->selectedListBox->item( c );
+ d->selectedListBox->takeItem( item );
+ d->selectedListBox->insertItem( item, c+1 );
+ d->selectedListBox->setCurrentItem( item );
+ emit movedDown( item );
+}
+
+void KActionSelector::itemDoubleClicked( QListBoxItem *item )
+{
+ if ( d->moveOnDoubleClick )
+ moveItem( item );
+}
+
+//END Private Slots
+
+//BEGIN Private Methods
+
+void KActionSelector::loadIcons()
+{
+ int isz;
+ if ( d->iconSize == SmallIcon ) isz = IconSize( KIcon::Small );
+ else if ( d->iconSize == Small ) isz = 16;
+ else if ( d->iconSize == Medium ) isz = 22;
+ else if ( d->iconSize == Large ) isz = 32;
+ else if ( d->iconSize == XLarge ) isz = 48;
+
+ d->btnAdd->setIconSet( SmallIconSet( d->addIcon, isz ) );
+ d->btnRemove->setIconSet( SmallIconSet( d->removeIcon, isz ) );
+ d->btnUp->setIconSet( SmallIconSet( d->upIcon, isz ) );
+ d->btnDown->setIconSet( SmallIconSet( d->downIcon, isz ) );
+}
+
+void KActionSelector::moveItem( QListBoxItem *item )
+{
+ QListBox *lbFrom = item->listBox();
+ QListBox *lbTo;
+ if ( lbFrom == d->availableListBox )
+ lbTo = d->selectedListBox;
+ else if ( lbFrom == d->selectedListBox )
+ lbTo = d->availableListBox;
+ else //?! somewhat unlikely...
+ return;
+
+ InsertionPolicy p = ( lbTo == d->availableListBox ) ?
+ d->availableInsertionPolicy : d->selectedInsertionPolicy;
+
+ lbFrom->takeItem( item );
+ lbTo->insertItem( item, insertionIndex( lbTo, p ) );
+ lbTo->setFocus();
+ lbTo->setCurrentItem( item );
+
+ if ( p == Sorted )
+ lbTo->sort();
+ if ( lbTo == d->selectedListBox )
+ emit added( item );
+ else
+ emit removed( item );
+}
+
+int KActionSelector::insertionIndex( QListBox *lb, InsertionPolicy policy )
+{
+ int index;
+ switch ( policy )
+ {
+ case BelowCurrent:
+ index = lb->currentItem();
+ if ( index > -1 ) index += 1;
+ break;
+ case AtTop:
+ index = 0;
+ break;
+ default:
+ index = -1;
+ }
+ return index;
+}
+
+//END Private Methods
+#include "kactionselector.moc"
diff --git a/kbabel/commonui/kactionselector.h b/kbabel/commonui/kactionselector.h
new file mode 100644
index 00000000..324ed54f
--- /dev/null
+++ b/kbabel/commonui/kactionselector.h
@@ -0,0 +1,410 @@
+/***************************************************************************
+ KActionSelector.h
+ A widget for selecting and arranging actions/objects
+ -------------------
+ begin : Mon June 3 2002
+ copyright : (C) 2002 by Anders Lund
+ email : anders@alweb.dk
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * *
+ * In addition, as a special exception, the copyright holders give *
+ * permission to link the code of this program with any edition of *
+ * the Qt library by Trolltech AS, Norway (or with modified versions *
+ * of Qt that use the same license as Qt), and distribute linked *
+ * combinations including the two. You must obey the GNU General *
+ * Public License in all respects for all of the code used other than *
+ * Qt. If you modify this file, you may extend this exception to *
+ * your version of the file, but you are not obligated to do so. If *
+ * you do not wish to do so, delete this exception statement from *
+ * your version. *
+ ***************************************************************************/
+
+#ifndef _KACTION_SELECTOR_H_
+#define _KACTION_SELECTOR_H_
+
+#include <qwidget.h>
+
+class QListBox;
+class QListBoxItem;
+class QKeyEvent;
+class QEvent;
+class QIconSet;
+
+class KActionSelectorPrivate;
+
+/**
+ @short A widget for selecting and arranging actions/objects
+ This widget allows the user to select from a set of objects and arrange
+ the order of the selected ones using two list boxes labeled "Available"
+ and "Used" with horizontal arrows in between to move selected objects between
+ the two, and vertical arrows on the right to arrange the order of the selected
+ objects.
+
+ The widget moves objects to the other listbox when doubleclicked if
+ the property moveOnDoubleClick is set to true (default). See moveOnDoubleClick()
+ and setMoveOnDoubleClick().
+
+ The user control the widget using the keyboard if enabled (default),
+ see keyboardEnabled.
+
+ Note that this may conflist with keyboard selection in the selected list box,
+ if you set that to anything else than QListBox::Single (which is the default).
+
+ To use it, simply construct an instance and then add items to the two listboxes,
+ available through lbAvailable() and lbSelected(). Whenever you want, you can retrieve
+ the selected options using QListBox methods on lbSelected().
+
+ This way, you can use your own QListBoxItem class, allowing you to easily
+ store object data in those.
+
+ When an item is moved to a listbox, it is placed below the current item
+ of that listbox.
+
+ Standard arrow icons are used, but you can use icons of your own choice if desired,
+ see setButtonIcon(). It is also possible to set tooltips and whatsthis help
+ for the buttons. See setButtonTooltip() and setButtonWhatsThis().
+
+ To set whatsthis or tooltips for the listboxes, access them through
+ availableListbox() and selectedListBox().
+
+ All the moving buttons are automatically set enabled as expected.
+
+ Signals are sent each time an item is moved, allowing you to follow the
+ users actions if you need to. See addedToSelection(), removedFromSelection(),
+ movedUp() and movedDown()
+
+ @author Anders Lund <anders@alweb.dk>
+*/
+
+class KActionSelector : public QWidget {
+ Q_OBJECT
+ Q_ENUMS( ButtonIconSize InsertionPolicy )
+ Q_PROPERTY( bool moveOnDoubleClick READ moveOnDoubleClick WRITE setMoveOnDoubleClick )
+ Q_PROPERTY( bool keyboardEnabled READ keyboardEnabled WRITE setKeyboardEnabled )
+ Q_PROPERTY( QString availableLabel READ availableLabel WRITE setAvailableLabel )
+ Q_PROPERTY( QString selectedLabel READ selectedLabel WRITE setSelectedLabel )
+ Q_PROPERTY( ButtonIconSize buttonIconSize READ buttonIconSize WRITE setButtonIconSize )
+ Q_PROPERTY( InsertionPolicy availableInsertionPolicy READ availableInsertionPolicy WRITE setAvailableInsertionPolicy )
+ Q_PROPERTY( InsertionPolicy selectedInsertionPolicy READ selectedInsertionPolicy WRITE setSelectedInsertionPolicy )
+ Q_PROPERTY( bool showUpDownButtons READ showUpDownButtons WRITE setShowUpDownButtons )
+
+public:
+ KActionSelector( QWidget *parent=0, const char *name=0 );
+ ~KActionSelector();
+
+ /**
+ @return The QListBox holding the available actions
+ */
+ QListBox *availableListBox();
+
+ /**
+ @return The QListBox holding the selected actions
+ */
+ QListBox *selectedListBox();
+
+ /**
+ This enum indentifies the moving buttons
+ */
+ enum MoveButton {
+ ButtonAdd,
+ ButtonRemove,
+ ButtonUp,
+ ButtonDown
+ };
+
+ /**
+ This enum identifies the icon sizes, used for the move buttons.
+ The values correspond to the following pixel sizes:
+ @li SmallIcon - the return value of IconSize( KIcon::Small ), the user defined size
+ of a small icon in KDE. This is the default setting.
+ @li Small - 16px
+ @li Medium - 22px
+ @li Large - 32px
+ @li XLarge - 48px
+ */
+ enum ButtonIconSize {
+ SmallIcon,
+ Small,
+ Medium,
+ Large,
+ XLarge
+ };
+
+ /**
+ This enum defines policies for where to insert moved items in a listbox.
+ The following policies are currently defined:
+ @li BelowCurrent - The item is inserted below the listbox'
+ currentItem() or at the end if there is no curent item.
+ @li Sorted - The listbox is sort()ed after one or more items are inserted.
+ @li AtTop - The item is inserted at index 0 in the listbox.
+ @li AtBottom - The item is inserted at the end of the listbox.
+
+ @sa availableInsertionPolicy(), setAvailableInsertionPolicy(),
+ selectedInsertionPolicy(), setSelectedInsertionPolicy().
+ */
+ enum InsertionPolicy {
+ BelowCurrent,
+ Sorted,
+ AtTop,
+ AtBottom
+ };
+
+ /**
+ @return Wheather moveOnDoubleClcik is enabled.
+
+ If enabled, an item in any listbox will be moved to the other one whenever
+ doubleclicked.
+ @sa setMoveOnDoubleClick()
+ */
+ bool moveOnDoubleClick() const;
+
+ /**
+ Sets moveOnDoubleClick to @p enable
+ @sa moveOnDoubleClick()
+ */
+ void setMoveOnDoubleClick( bool enable );
+
+ /**
+ @return Weather keyboard control is enabled.
+
+ When Keyboard control is enabled, the widget will react to
+ the following keyboard actions:
+ @li CTRL + Right - simulate clicking the add button
+ @li CTRL + Left - simulate clicking the remove button
+ @li CTRL + Up - simulate clicking the up button
+ @li CTRL + Down - simulate clicking the down button
+
+ Additionally, pressing RETURN or ENTER on one of the list boxes
+ will cause the current item of that listbox to be moved to the other
+ listbox.
+
+ The keyboard actions are enabled by default.
+
+ @sa setKeyboardEnabled()
+ */
+ bool keyboardEnabled() const;
+
+ /**
+ Sets the keyboard enabled depending on @p enable.
+ @sa keyboardEnabled()
+ */
+ void setKeyboardEnabled( bool enable );
+
+ /**
+ @return The text of the label for the available items listbox.
+ */
+ QString availableLabel() const;
+
+ /**
+ Sets the label for the available items listbox to @p text.
+ Note that this label has the listbox as its @e buddy, so that
+ if you have a single ampersand in the text, the following character
+ will become the accellerator to focus te listbox.
+ */
+ void setAvailableLabel( const QString & text );
+
+ /**
+ @return the label of the selected items listbox.
+ */
+ QString selectedLabel() const;
+
+ /**
+ Sets the label for the selected items listbox to @p text.
+ Note that this label has the listbox as its @e buddy, so that
+ if you have a single ampersand in the text, the following character
+ will become the accellerator to focus te listbox.
+ */
+ void setSelectedLabel( const QString & text );
+
+ /**
+ @return the current ButtonIconSize.
+ */
+ ButtonIconSize buttonIconSize() const;
+
+ /**
+ Sets the button icon size.
+ See ButtonIconSize for the possible values and their pixel meaning.
+ */
+ void setButtonIconSize( ButtonIconSize size );
+
+ /**
+ @return The current insertion policy for the available listbox.
+ The default policy for the available listbox is Sorted.
+ See also InsertionPolicy, setAvailableInsertionPolicy().
+ */
+ InsertionPolicy availableInsertionPolicy();
+
+ /**
+ Sets the insertion policy for the available listbox.
+ See also InsertionPolicy, availableInsertionPolicy().
+ */
+ void setAvailableInsertionPolicy( InsertionPolicy policy );
+
+ /**
+ @return The current insertion policy for the selected listbox.
+ The default policy for the selected listbox is BelowCurrent.
+ See also InsertionPolicy, setSelectedInsertionPolicy().
+ */
+ InsertionPolicy selectedInsertionPolicy();
+
+ /**
+ Sets the insertion policy for the selected listbox.
+ See also InsertionPolicy, selectedInsertionPolicy().
+ */
+ void setSelectedInsertionPolicy( InsertionPolicy policy );
+
+ /**
+ @return wheather the Up and Down buttons should be displayed.
+ */
+ bool showUpDownButtons();
+
+ /**
+ Sets wheather the Up and Down buttons should be displayed
+ according to @p show
+ */
+ void setShowUpDownButtons( bool show );
+
+ /**
+ Sets the pixmap of the button @p button to @p icon.
+ It calls @ref SmallIconSet(pm) to generate the icon set.
+ */
+ void setButtonIcon( const QString &icon, MoveButton button );
+
+ /**
+ Sets the iconset for button @p button to @p iconset.
+ You can use this method to et a costum icon set. Either
+ created by @ref QIconSet, or use the application instance of
+ @ref KIconLoader (recommended).
+ */
+ void setButtonIconSet( const QIconSet &iconset, MoveButton button );
+
+ /**
+ Sets the tooltip for the button @p button to @p tip.
+ */
+ void setButtonTooltip( const QString &tip, MoveButton button );
+
+ /**
+ Sets the whatsthis help for button @p button to @p text.
+ */
+ void setButtonWhatsThis( const QString &text, MoveButton button );
+
+ /**
+ Sets the enabled state of all moving buttons to reflect the current
+ options.
+
+ Be sure to call this if you add or removes items to either listbox after the
+ widget is show()n
+ */
+ void setButtonsEnabled();
+
+signals:
+ /**
+ Emitted when an item is moved to the "selected" listbox.
+ */
+ void added( QListBoxItem *item );
+
+ /**
+ Emitted when an item is moved out of the "selected" listbox.
+ */
+ void removed( QListBoxItem *item );
+
+ /**
+ Emitted when an item is moved upwards in the "selected" listbox.
+ */
+ void movedUp( QListBoxItem *item );
+
+ /**
+ Emitted when an item is moved downwards in the "selected" listbox.
+ */
+ void movedDown( QListBoxItem *item );
+
+ /**
+ Emitted when an item is moved to the "selected" listbox.
+ */
+// void addedToSelection( QListBoxItem *item );
+
+public slots:
+ /**
+ Reimplemented for internal reasons.
+ (calls setButtonsEnabled())
+ */
+ void polish();
+
+protected:
+ /**
+ Reimplamented for internal reasons.
+ */
+ void keyPressEvent( QKeyEvent * );
+
+ /**
+ Reimplemented for internal reasons.
+ */
+ bool eventFilter( QObject *, QEvent * );
+
+private slots:
+ /**
+ Move selected item from available box to the selected box
+ */
+ void buttonAddClicked();
+
+ /**
+ Move selected item from selected box to available box
+ */
+ void buttonRemoveClicked();
+
+ /**
+ Move selected item in selected box upwards
+ */
+ void buttonUpClicked();
+
+ /**
+ Move seleted item in selected box downwards
+ */
+ void buttonDownClicked();
+
+ /**
+ Moves the item @p item to the other listbox if moveOnDoubleClick is enabled.
+ */
+ void itemDoubleClicked( QListBoxItem *item );
+
+ /**
+ connected to both list boxes to set the buttons enabled
+ */
+ void slotCurrentChanged( QListBoxItem * ) { setButtonsEnabled(); };
+
+private:
+
+ /**
+ Move item @p item to the other listbox
+ */
+ void moveItem( QListBoxItem *item );
+
+ /**
+ loads the icons for the move buttons.
+ */
+ void loadIcons();
+
+ /**
+ @return the index to insert an item into listbox @p lb,
+ given InsertionPolicy @p policy.
+
+ Note that if policy is Sorted, this will return -1.
+ Sort the listbox after inserting the item in that case.
+ */
+ int insertionIndex( QListBox *lb, InsertionPolicy policy );
+
+ /** @private
+ Private data storage
+ */
+ KActionSelectorPrivate *d;
+};
+
+#endif // _KACTION_SELECTOR_H_
diff --git a/kbabel/commonui/kbabel_tool.desktop b/kbabel/commonui/kbabel_tool.desktop
new file mode 100644
index 00000000..3ae5922d
--- /dev/null
+++ b/kbabel/commonui/kbabel_tool.desktop
@@ -0,0 +1,9 @@
+[Desktop Entry]
+Type=ServiceType
+X-KDE-ServiceType=KBabelTool
+
+[PropertyDef::Shortcuts]
+Type=QStringList
+
+[PropertyDef::ValidationString]
+Type=QString
diff --git a/kbabel/commonui/kbabel_validator.desktop b/kbabel/commonui/kbabel_validator.desktop
new file mode 100644
index 00000000..fd8ad4ac
--- /dev/null
+++ b/kbabel/commonui/kbabel_validator.desktop
@@ -0,0 +1,56 @@
+[Desktop Entry]
+Type=ServiceType
+X-KDE-ServiceType=KBabelValidator
+Comment=KDE Data Tool for KBabel
+Comment[bg]=ИнÑтрумент за данни на KDE - KBabel
+Comment[br]=Ostilh roadoù KDE evit KBabel
+Comment[bs]=KDE podatkovni alat za KBabel
+Comment[ca]=Eina de dades KDE per a KBabel
+Comment[cs]=Datový nástroj pro KBabel
+Comment[cy]=Erfyn Data KDE i KBabel
+Comment[da]=KDE Data-værktøj for KBabel
+Comment[de]=KDE Datenbearbeitungswerkzeug für KBabel
+Comment[el]=ΕÏγαλείο δεδομένων για το KBabel του KDE
+Comment[es]=Herramienta de datos KDE para KBabel
+Comment[et]=KBabeli KDE andmete tööriist
+Comment[eu]=KBabel-erako KDE aatu tresna
+Comment[fa]=ابزار دادۀ KDE برای KBabel
+Comment[fi]=KBabelin KDE Data Tool
+Comment[fr]=Outil de données KDE pour KBabel
+Comment[gl]=Ferramenta de Datos de KDE para KBabel
+Comment[hi]=के-बेबल के लिठकेडीई डाटा औज़ार
+Comment[hu]=Adatkezelő a KBabelhez
+Comment[is]=KDE gagnatól fyrir KBabel
+Comment[it]=Strumento KDE per la gestione dati con KBabel
+Comment[ja]=KBabel ã®ãŸã‚ã® KDE データツール
+Comment[ka]=KBabel-ის KDE მáƒáƒœáƒáƒªáƒ”მთრხელსáƒáƒ¬áƒ§áƒ
+Comment[kk]=KDE-нің KBabel-дің деректер құралы
+Comment[lt]=KDE duomenų įrankis, skirtas KBabel
+Comment[ms]=Alatan Data KDE untuk KBabel
+Comment[nb]=KDE dataverktøy for KBabel
+Comment[nds]=KDE-Datenwarktüüch för KBabel
+Comment[ne]=केबà¥à¤¯à¤¾à¤¬à¤²à¤•à¤¾ लागि केडीई डाटा उपकरण
+Comment[nl]=KDE Dataprogramma voor KBabel
+Comment[nn]=KDE-dataverktøy for KBabel
+Comment[pa]=KBabel ਲਈ ਕੇਡੀਈ ਡਾਟਾ ਸੰਦ
+Comment[pl]=Narzędzie danych KDE dla KBabel
+Comment[pt]=Ferramenta de Dados do KDE para o KBabel
+Comment[pt_BR]=Ferramenta de Dados KDE para o KBabel
+Comment[ru]=Данные Ð´Ð»Ñ KBabel
+Comment[sk]=Dátový nástroj pre KBabel
+Comment[sl]=Podatkovno orodje KDE za KBabel
+Comment[sr]=KDE-ов алат за податке за KBabel
+Comment[sr@Latn]=KDE-ov alat za podatke za KBabel
+Comment[sv]=KDE dataverktyg för Kbabel
+Comment[ta]=KDE Kபாபேலின௠தரவà¯à®•à¯ கரà¯à®µà®¿
+Comment[tg]=Маълумоти аÑбоби KDE барои KBabel
+Comment[tr]=KBabel için KDE Veri Aracı
+Comment[uk]=ЗаÑіб роботи з даними KDE Ð´Ð»Ñ KBabel
+Comment[zh_CN]=KBabel çš„ KDE æ•°æ®å·¥å…·
+Comment[zh_TW]=KBabel 資料工具
+
+[PropertyDef::Shortcuts]
+Type=QStringList
+
+[PropertyDef::ValidationString]
+Type=QString
diff --git a/kbabel/commonui/klisteditor.ui b/kbabel/commonui/klisteditor.ui
new file mode 100644
index 00000000..63fbfceb
--- /dev/null
+++ b/kbabel/commonui/klisteditor.ui
@@ -0,0 +1,261 @@
+<!DOCTYPE UI><UI version="3.3" stdsetdef="1">
+<class>KListEditor</class>
+<widget class="QWidget">
+ <property name="name">
+ <cstring>KListEditor</cstring>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>334</width>
+ <height>274</height>
+ </rect>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>7</hsizetype>
+ <vsizetype>7</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </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="QGroupBox">
+ <property name="name">
+ <cstring>_frame</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>7</hsizetype>
+ <vsizetype>7</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="title">
+ <string></string>
+ </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>Layout3</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="QLineEdit">
+ <property name="name">
+ <cstring>_edit</cstring>
+ </property>
+ </widget>
+ <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>
+ <widget class="QListBox">
+ <item>
+ <property name="text">
+ <string>New Item</string>
+ </property>
+ </item>
+ <property name="name">
+ <cstring>_list</cstring>
+ </property>
+ <property name="minimumSize">
+ <size>
+ <width>200</width>
+ <height>200</height>
+ </size>
+ </property>
+ </widget>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>Layout5_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="QPushButton">
+ <property name="name">
+ <cstring>_addButton</cstring>
+ </property>
+ <property name="enabled">
+ <bool>false</bool>
+ </property>
+ <property name="text">
+ <string>Add</string>
+ </property>
+ </widget>
+ <widget class="QPushButton">
+ <property name="name">
+ <cstring>_removeButton</cstring>
+ </property>
+ <property name="enabled">
+ <bool>false</bool>
+ </property>
+ <property name="text">
+ <string>Remove</string>
+ </property>
+ </widget>
+ <widget class="QPushButton">
+ <property name="name">
+ <cstring>_upButton</cstring>
+ </property>
+ <property name="enabled">
+ <bool>false</bool>
+ </property>
+ <property name="text">
+ <string>Up</string>
+ </property>
+ </widget>
+ <widget class="QPushButton">
+ <property name="name">
+ <cstring>_downButton</cstring>
+ </property>
+ <property name="enabled">
+ <bool>false</bool>
+ </property>
+ <property name="text">
+ <string>Down</string>
+ </property>
+ </widget>
+ <spacer>
+ <property name="name">
+ <cstring>Spacer2_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>
+ </hbox>
+ </widget>
+ </vbox>
+ </widget>
+ </hbox>
+ </widget>
+ </hbox>
+</widget>
+<connections>
+ <connection>
+ <sender>_addButton</sender>
+ <signal>pressed()</signal>
+ <receiver>KListEditor</receiver>
+ <slot>addToList()</slot>
+ </connection>
+ <connection>
+ <sender>_removeButton</sender>
+ <signal>pressed()</signal>
+ <receiver>KListEditor</receiver>
+ <slot>removeFromList()</slot>
+ </connection>
+ <connection>
+ <sender>_upButton</sender>
+ <signal>pressed()</signal>
+ <receiver>KListEditor</receiver>
+ <slot>upInList()</slot>
+ </connection>
+ <connection>
+ <sender>_downButton</sender>
+ <signal>pressed()</signal>
+ <receiver>KListEditor</receiver>
+ <slot>downInList()</slot>
+ </connection>
+ <connection>
+ <sender>_edit</sender>
+ <signal>returnPressed()</signal>
+ <receiver>KListEditor</receiver>
+ <slot>updateList()</slot>
+ </connection>
+ <connection>
+ <sender>_edit</sender>
+ <signal>textChanged(const QString&amp;)</signal>
+ <receiver>KListEditor</receiver>
+ <slot>editChanged(const QString&amp;)</slot>
+ </connection>
+ <connection>
+ <sender>_list</sender>
+ <signal>highlighted(int)</signal>
+ <receiver>KListEditor</receiver>
+ <slot>updateButtons(int)</slot>
+ </connection>
+ <connection>
+ <sender>_list</sender>
+ <signal>highlighted(const QString&amp;)</signal>
+ <receiver>_edit</receiver>
+ <slot>setText(const QString&amp;)</slot>
+ </connection>
+</connections>
+<includes>
+ <include location="local" impldecl="in implementation">klisteditor.ui.h</include>
+</includes>
+<signals>
+ <signal>itemsChanged()</signal>
+</signals>
+<slots>
+ <slot>addToList()</slot>
+ <slot>downInList()</slot>
+ <slot>removeFromList()</slot>
+ <slot>upInList()</slot>
+ <slot>updateButtons( int newIndex )</slot>
+ <slot>updateList()</slot>
+ <slot>setList( QStringList contents )</slot>
+ <slot access="protected">editChanged( const QString &amp; s )</slot>
+ <slot>setTitle( const QString &amp; s )</slot>
+ <slot returnType="QStringList">list()</slot>
+</slots>
+<layoutdefaults spacing="6" margin="11"/>
+</UI>
diff --git a/kbabel/commonui/klisteditor.ui.h b/kbabel/commonui/klisteditor.ui.h
new file mode 100644
index 00000000..bc916e56
--- /dev/null
+++ b/kbabel/commonui/klisteditor.ui.h
@@ -0,0 +1,122 @@
+/* ****************************************************************************
+ This file is part of KBabel
+
+ Copyright (C) 2002-2005 by Stanislav Visnovsky
+ <visnovsky@kde.org>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the 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, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+ In addition, as a special exception, the copyright holders give
+ permission to link the code of this program with any edition of
+ the Qt library by Trolltech AS, Norway (or with modified versions
+ of Qt that use the same license as Qt), and distribute linked
+ combinations including the two. You must obey the GNU General
+ Public License in all respects for all of the code used other than
+ Qt. If you modify this file, you may extend this exception to
+ your version of the file, but you are not obligated to do so. If
+ you do not wish to do so, delete this exception statement from
+ your version.
+
+
+** ui.h extension file, included from the uic-generated form implementation.
+**
+** If you wish to add, delete or rename slots use Qt Designer which will
+** update this file, preserving your code. Create an init() slot in place of
+** a constructor, and a destroy() slot in place of a destructor.
+*****************************************************************************/
+
+
+void KListEditor::addToList()
+{
+ _list->insertItem(_edit->text());
+ _edit->clear();
+ _removeButton->setEnabled(true);
+ emit itemsChanged();
+}
+
+void KListEditor::downInList()
+{
+ int i=_list->currentItem();
+ if( i< (int)_list->count()-1 ) {
+ QString ci = _list->currentText();
+ _list->removeItem(i);
+ _list->insertItem(ci,i+1);
+ _list->setCurrentItem(i+1);
+ }
+ emit itemsChanged();
+}
+
+void KListEditor::removeFromList()
+{
+ _list->removeItem(_list->currentItem());
+ if( _list->count()==0 ) _edit->clear();
+ _removeButton->setEnabled(_list->count()>0);
+ emit itemsChanged();
+}
+
+void KListEditor::upInList()
+{
+ int i=_list->currentItem();
+ if( i>0 ) {
+ QString ci = _list->currentText();
+ _list->removeItem(i);
+ _list->insertItem(ci,i-1);
+ _list->setCurrentItem(i-1);
+ }
+ emit itemsChanged();
+}
+
+void KListEditor::updateButtons( int newIndex )
+{
+ _upButton->setEnabled(newIndex>0);
+ _downButton->setEnabled(newIndex+1 != (int)_list->count());
+ _removeButton->setEnabled(true);
+}
+
+void KListEditor::updateList()
+{
+ int i=_list->currentItem();
+ if( i==-1 ) addToList();
+ else _list->changeItem(_edit->text(), i );
+}
+
+void KListEditor::setList( QStringList contents )
+{
+ _list->clear();
+ _list->insertStringList(contents);
+ _list->setCurrentItem(0);
+ _removeButton->setEnabled(!contents.isEmpty());
+}
+
+
+void KListEditor::editChanged( const QString &s )
+{
+ _addButton->setEnabled(!s.isEmpty());
+}
+
+
+void KListEditor::setTitle( const QString &s )
+{
+ _frame->setTitle(s);
+}
+
+
+QStringList KListEditor::list()
+{
+ QStringList result;
+ for( uint i=0; i<_list->count() ; i++ )
+ result.append(_list->text(i));
+ return result;
+}
diff --git a/kbabel/commonui/projectpref.cpp b/kbabel/commonui/projectpref.cpp
new file mode 100644
index 00000000..1bffa2e6
--- /dev/null
+++ b/kbabel/commonui/projectpref.cpp
@@ -0,0 +1,278 @@
+/* ****************************************************************************
+ This file is part of KBabel
+
+ Copyright (C) 1999-2000 by Matthias Kiefer
+ <matthias.kiefer@gmx.de>
+ 2004-2005 by Stanislav Visnovsky
+ <visnovsky@kde.org>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the 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, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+ In addition, as a special exception, the copyright holders give
+ permission to link the code of this program with any edition of
+ the Qt library by Trolltech AS, Norway (or with modified versions
+ of Qt that use the same license as Qt), and distribute linked
+ combinations including the two. You must obey the GNU General
+ Public License in all respects for all of the code used other than
+ Qt. If you modify this file, you may extend this exception to
+ your version of the file, but you are not obligated to do so. If
+ you do not wish to do so, delete this exception statement from
+ your version.
+
+**************************************************************************** */
+#include "projectpref.h"
+#include "projectprefwidgets.h"
+#include "diffpreferences.h"
+#include "kbprojectsettings.h"
+
+#include <qlayout.h>
+#include <qwhatsthis.h>
+#include <qvbox.h>
+
+#include <kdebug.h>
+#include <klocale.h>
+#include <kiconloader.h>
+#include <kapplication.h>
+
+
+#define PAGE_IDENTITY 0
+#define PAGE_SAVE 1
+#define PAGE_SPELL 2
+#define PAGE_SOURCE 3
+#define PAGE_MISC 4
+#define PAGE_CATMAN 5
+#define PAGE_DIRCOMMANDS 6
+#define PAGE_FILECOMMANDS 7
+#define PAGE_VIEW 8
+#define PAGE_DIFF 9
+
+using namespace KBabel;
+
+ProjectDialog::ProjectDialog(Project::Ptr project)
+ : KConfigDialog(0, "project dialog", project->settings(),
+ IconList, Help|Default|Ok|Apply|Cancel)
+ , _project( project )
+{
+
+ _identityPage = new IdentityPreferences(0, project->name());
+ addPage(_identityPage, i18n("title of page in preferences dialog","Identity")
+ , "pref_identity"
+ , i18n("Information About You and Translation Team")
+ );
+
+ _savePage = new SavePreferences(0);
+ addPage(_savePage, i18n("title of page in preferences dialog","Save")
+ , "filesave"
+ , i18n("Options for File Saving"));
+
+
+ _spellPage = new SpellPreferences(0);
+ addPage(_spellPage, i18n("title of page in preferences dialog","Spelling")
+ , "spellcheck"
+ , i18n("Options for Spell Checking"));
+ connect( _spellPage, SIGNAL( settingsChanged() )
+ , this, SLOT(updateButtons()) );
+
+ _sourcePage = new SourceContextPreferences(0);
+ addPage(_sourcePage, i18n("title of page in preferences dialog","Source")
+ , "source"
+ ,i18n("Options for Showing Source Context"));
+ connect(_sourcePage, SIGNAL (itemsChanged())
+ , this, SLOT (updateButtons()) );
+
+ _miscPage = new MiscPreferences(0);
+ addPage(_miscPage, i18n("title of page in preferences dialog","Miscellaneous")
+ , "misc"
+ ,i18n("Miscellaneous Settings"));
+
+ _catmanPage = new CatmanPreferences(0);
+ addPage(_catmanPage, i18n("title of page in preferences dialog","Folders")
+ , "catalogmanager"
+ , i18n("Paths to Message Catalogs & Catalog Templates"));
+
+ _dirCommandsPage = new DirCommandsPreferences(0);
+ addPage(_dirCommandsPage, i18n("title of page in preferences dialog","Folder Commands")
+ , "folder"
+ , i18n("User-Defined Commands for Folder Items"));
+ connect( _dirCommandsPage, SIGNAL( settingsChanged() ),
+ this, SLOT(updateButtons()) );
+
+ _fileCommandsPage = new FileCommandsPreferences(0);
+ addPage(_fileCommandsPage, i18n("title of page in preferences dialog","File Commands")
+ , "files"
+ , i18n("User-Defined Commands for File Items"));
+ connect( _fileCommandsPage, SIGNAL( settingsChanged() ),
+ this, SLOT(updateButtons()) );
+
+ _viewPage = new ViewPreferences(0);
+ addPage(_viewPage, i18n("title of page in preferences dialog","Catalog Manager")
+ , "view_tree"
+ , i18n("Catalog Manager View Settings"));
+
+ _diffPage = new DiffPreferences(0);
+ addPage(_diffPage, i18n("title of page in preferences dialog","Diff")
+ , "diff"
+ , i18n("Searching for Differences"));
+
+ setHelp( "preferences-project-settings", "kbabel" );
+
+ adjustSize();
+}
+
+void ProjectDialog::slotDefault()
+{
+ // redefine the KConfigDialog behavior to push default on the
+ // current page only
+
+ _project->settings()->useDefaults(true);
+
+ switch(activePageIndex())
+ {
+ case PAGE_IDENTITY:
+ _identityPage->defaults(_project->identitySettings());
+ break;
+ case PAGE_SAVE:
+ _savePage->defaults(_project->saveSettings());
+ break;
+ case PAGE_MISC:
+ _miscPage->defaults(_project->miscSettings());
+ break;
+ case PAGE_SPELL:
+ _spellPage->defaults(_project->spellcheckSettings());
+ break;
+ case PAGE_SOURCE:
+ _sourcePage->defaults(_project->sourceContextSettings());
+ break;
+ case PAGE_CATMAN:
+ _catmanPage->defaults(_project->catManSettings());
+ break;
+ case PAGE_DIRCOMMANDS:
+ _dirCommandsPage->defaults(_project->catManSettings());
+ break;
+ case PAGE_FILECOMMANDS:
+ _fileCommandsPage->defaults(_project->catManSettings());
+ break;
+ case PAGE_VIEW:
+ _viewPage->defaults(_project->catManSettings());
+ break;
+ }
+
+ _project->settings()->useDefaults(false);
+}
+
+void ProjectDialog::updateSettings()
+{
+ KBabel::CatManSettings _CatManSettings;
+ SourceContextSettings contextSettings;
+
+ _spellPage->mergeSettings(_spellcheckSettings);
+ _dirCommandsPage->mergeSettings(_CatManSettings);
+ _fileCommandsPage->mergeSettings(_CatManSettings);
+ _sourcePage->mergeSettings(contextSettings);
+
+ _project->settings()->setDirCommands( _CatManSettings.dirCommands );
+ _project->settings()->setDirCommandNames( _CatManSettings.dirCommandNames );
+ _project->settings()->setFileCommands( _CatManSettings.fileCommands );
+ _project->settings()->setFileCommandNames( _CatManSettings.fileCommandNames );
+
+ _project->setSettings(_spellcheckSettings);
+
+ _project->settings()->setPaths( contextSettings.sourcePaths );
+}
+
+void ProjectDialog::updateWidgets()
+{
+ _spellPage->updateWidgets(_project->spellcheckSettings());
+ _dirCommandsPage->updateWidgets(_project->catManSettings());
+ _fileCommandsPage->updateWidgets(_project->catManSettings());
+ _sourcePage->updateWidgets(_project->sourceContextSettings());
+}
+
+void ProjectDialog::updateWidgetsDefault()
+{
+ _project->settings()->useDefaults( true );
+ updateWidgets();
+ _project->settings()->useDefaults( false );
+}
+
+bool ProjectDialog::isDefault()
+{
+ SourceContextSettings contextSettings, defaultContextSettings;
+
+ // get the current values
+ _spellPage->mergeSettings(_spellcheckSettings);
+ _dirCommandsPage->mergeSettings(_CatManSettings);
+ _fileCommandsPage->mergeSettings(_CatManSettings);
+ _sourcePage->mergeSettings(defaultContextSettings);
+
+ // get default values
+ _project->settings()->useDefaults(true);
+ SpellcheckSettings defaultSpell = _project->spellcheckSettings();
+ CatManSettings defaultCatMan = _project->catManSettings();
+ defaultContextSettings = _project->sourceContextSettings();
+ _project->settings()->useDefaults(false);
+
+ bool result = true;
+
+ result &= _spellcheckSettings.noRootAffix == defaultSpell.noRootAffix;
+ result &= _spellcheckSettings.runTogether == defaultSpell.runTogether;
+ result &= _spellcheckSettings.spellClient == defaultSpell.spellClient;
+ result &= _spellcheckSettings.spellDict == defaultSpell.spellDict;
+ result &= _spellcheckSettings.spellEncoding == defaultSpell.spellEncoding;
+
+ result &= _CatManSettings.dirCommandNames == defaultCatMan.dirCommandNames;
+ result &= _CatManSettings.dirCommands == defaultCatMan.dirCommands;
+ result &= _CatManSettings.fileCommandNames == defaultCatMan.fileCommandNames;
+ result &= _CatManSettings.fileCommands == defaultCatMan.fileCommands;
+
+ result &= contextSettings.sourcePaths != defaultContextSettings.sourcePaths;
+
+ return result;
+}
+
+bool ProjectDialog::hasChanged()
+{
+ SourceContextSettings contextSettings, defaultContextSettings;
+
+ // get the current values
+ _spellPage->mergeSettings(_spellcheckSettings);
+ _dirCommandsPage->mergeSettings(_CatManSettings);
+ _fileCommandsPage->mergeSettings(_CatManSettings);
+ _sourcePage->mergeSettings(contextSettings);
+
+ // get project values
+ SpellcheckSettings defaultSpell = _project->spellcheckSettings();
+ CatManSettings defaultCatMan = _project->catManSettings();
+ defaultContextSettings = _project->sourceContextSettings();
+
+ bool result = false;
+
+ result |= _spellcheckSettings.noRootAffix != defaultSpell.noRootAffix;
+ result |= _spellcheckSettings.runTogether != defaultSpell.runTogether;
+ result |= _spellcheckSettings.spellClient != defaultSpell.spellClient;
+ result |= _spellcheckSettings.spellDict != defaultSpell.spellDict;
+ result |= _spellcheckSettings.spellEncoding != defaultSpell.spellEncoding;
+
+ result |= _CatManSettings.dirCommandNames != defaultCatMan.dirCommandNames;
+ result |= _CatManSettings.dirCommands != defaultCatMan.dirCommands;
+ result |= _CatManSettings.fileCommandNames != defaultCatMan.fileCommandNames;
+ result |= _CatManSettings.fileCommands != defaultCatMan.fileCommands;
+
+ result |= contextSettings.sourcePaths != defaultContextSettings.sourcePaths;
+
+ return result;
+}
+
+#include "projectpref.moc"
diff --git a/kbabel/commonui/projectpref.h b/kbabel/commonui/projectpref.h
new file mode 100644
index 00000000..90561c5b
--- /dev/null
+++ b/kbabel/commonui/projectpref.h
@@ -0,0 +1,93 @@
+/* ****************************************************************************
+ This file is part of KBabel
+
+ Copyright (C) 1999-2000 by Matthias Kiefer
+ <matthias.kiefer@gmx.de>
+ 2004-2005 by Stanislav Visnovsky
+ <visnovsky@kde.org>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the 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, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+ In addition, as a special exception, the copyright holders give
+ permission to link the code of this program with any edition of
+ the Qt library by Trolltech AS, Norway (or with modified versions
+ of Qt that use the same license as Qt), and distribute linked
+ combinations including the two. You must obey the GNU General
+ Public License in all respects for all of the code used other than
+ Qt. If you modify this file, you may extend this exception to
+ your version of the file, but you are not obligated to do so. If
+ you do not wish to do so, delete this exception statement from
+ your version.
+
+**************************************************************************** */
+#ifndef PROJECTPREF_H
+#define PROJECTPREF_H
+
+#include <kconfigdialog.h>
+#include <qptrlist.h>
+
+class SavePreferences;
+class IdentityPreferences;
+class MiscPreferences;
+class SpellPreferences;
+class CatmanPreferences;
+class DirCommandsPreferences;
+class FileCommandsPreferences;
+class ViewPreferences;
+class SourceContextPreferences;
+class DiffPreferences;
+
+#include "kbproject.h"
+#include "projectsettings.h"
+#include "context.h"
+
+namespace KBabel {
+
+class KDE_EXPORT ProjectDialog : public KConfigDialog
+{
+ Q_OBJECT
+public:
+ ProjectDialog(Project::Ptr project);
+
+protected slots:
+ virtual void slotDefault();
+ virtual void updateSettings();
+ virtual void updateWidgets();
+ virtual void updateWidgetsDefault();
+
+private:
+ virtual bool hasChanged();
+ virtual bool isDefault();
+
+ SavePreferences *_savePage;
+ IdentityPreferences* _identityPage;
+ MiscPreferences* _miscPage;
+ SpellPreferences* _spellPage;
+ SourceContextPreferences* _sourcePage;
+ CatmanPreferences *_catmanPage;
+ DirCommandsPreferences *_dirCommandsPage;
+ FileCommandsPreferences *_fileCommandsPage;
+ ViewPreferences *_viewPage;
+ DiffPreferences *_diffPage;
+
+ KBabel::SpellcheckSettings _spellcheckSettings;
+ KBabel::CatManSettings _CatManSettings;
+
+ Project::Ptr _project;
+};
+
+}
+
+#endif // PROJECTPREF_H
diff --git a/kbabel/commonui/projectprefwidgets.cpp b/kbabel/commonui/projectprefwidgets.cpp
new file mode 100644
index 00000000..16bc2da4
--- /dev/null
+++ b/kbabel/commonui/projectprefwidgets.cpp
@@ -0,0 +1,1209 @@
+/* ****************************************************************************
+ This file is part of KBabel
+
+ Copyright (C) 1999-2000 by Matthias Kiefer
+ <matthias.kiefer@gmx.de>
+ 2001-2005 by Stanislav Visnovsky
+ <visnovsky@kde.org>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the 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, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+ In addition, as a special exception, the copyright holders give
+ permission to link the code of this program with any edition of
+ the Qt library by Trolltech AS, Norway (or with modified versions
+ of Qt that use the same license as Qt), and distribute linked
+ combinations including the two. You must obey the GNU General
+ Public License in all respects for all of the code used other than
+ Qt. If you modify this file, you may extend this exception to
+ your version of the file, but you are not obligated to do so. If
+ you do not wish to do so, delete this exception statement from
+ your version.
+
+**************************************************************************** */
+#include "klisteditor.h"
+#include "toolselectionwidget.h"
+#include "projectprefwidgets.h"
+#include "resources.h"
+#include "kbabeldictbox.h"
+#include "toolaction.h"
+#include "cmdedit.h"
+#include "kbprojectsettings.h"
+
+#include <kcombobox.h>
+#include <kdatatool.h>
+#include <klocale.h>
+#include <kdialog.h>
+#include <kfiledialog.h>
+#include <knuminput.h>
+#include <kmessagebox.h>
+#include <klineedit.h>
+#include <kurlcompletion.h>
+#include <kfontdialog.h>
+#include <kcolorbutton.h>
+#include <kparts/componentfactory.h>
+#include <kregexpeditorinterface.h>
+#include <ksconfig.h>
+#include <kurldrag.h>
+#include <kurlrequester.h>
+
+#include <qlayout.h>
+#include <qobjectlist.h>
+#include <qlabel.h>
+#include <qvbox.h>
+#include <qlineedit.h>
+#include <qcheckbox.h>
+#include <qgroupbox.h>
+#include <qhbuttongroup.h>
+#include <qvbuttongroup.h>
+#include <qpushbutton.h>
+#include <qcombobox.h>
+#include <qradiobutton.h>
+#include <qspinbox.h>
+#include <qtextcodec.h>
+#include <qwhatsthis.h>
+
+using namespace KBabel;
+
+static QSize sizeHintForWidget(const QWidget* widget)
+{
+ //
+ // The size is computed by adding the sizeHint().height() of all
+ // widget children and taking the width of the widest child and adding
+ // layout()->margin() and layout()->spacing()
+ //
+
+ QSize size;
+
+ int numChild = 0;
+ QObjectList *l = (QObjectList*)(widget->children());
+
+ for( uint i=0; i < l->count(); i++ )
+ {
+ QObject *o = l->at(i);
+ if( o->isWidgetType() )
+ {
+ numChild += 1;
+ QWidget *w=((QWidget*)o);
+
+ QSize s = w->sizeHint();
+ if( s.isEmpty() == true )
+ {
+ s = QSize( 50, 100 ); // Default size
+ }
+ size.setHeight( size.height() + s.height() );
+ if( s.width() > size.width() ) { size.setWidth( s.width() ); }
+ }
+ }
+
+ if( numChild > 0 )
+ {
+ size.setHeight( size.height() + widget->layout()->spacing()*(numChild-1) );
+ size += QSize( widget->layout()->margin()*2, widget->layout()->margin()*2 + 1 );
+ }
+ else
+ {
+ size = QSize( 1, 1 );
+ }
+
+ return( size );
+}
+
+
+
+
+SavePreferences::SavePreferences(QWidget *parent)
+ : KTabCtl(parent)
+{
+ QWidget* page = new QWidget(this);
+ QVBoxLayout* layout=new QVBoxLayout(page);
+ layout->setSpacing(KDialog::spacingHint());
+ layout->setMargin(KDialog::marginHint());
+
+ QGroupBox* box=new QGroupBox(1,Qt::Horizontal,page);
+ layout->addWidget(box);
+
+ box->setMargin(KDialog::marginHint());
+ _updateButton = new QCheckBox(i18n("&Update header when saving"),box, "kcfg_AutoUpdate");
+ _descriptionButton = new QCheckBox(i18n("Update &description comment when saving"),box, "kcfg_UpdateDescription");
+ _autoCheckButton = new QCheckBox(i18n("Chec&k syntax of file when saving"),box, "kcfg_AutoSyntaxCheck");
+ _saveObsoleteButton = new QCheckBox(i18n("Save &obsolete entries"),box, "kcfg_SaveObsolete");
+
+ QGroupBox* descBox=new QGroupBox(1,Qt::Horizontal,i18n("De&scription"),page);
+ layout->addWidget(descBox);
+
+ descBox->setMargin(KDialog::marginHint());
+ _descriptionEdit = new QLineEdit(descBox, "kcfg_DescriptionString");
+
+ QGroupBox* encodingBox = new QGroupBox(1,Qt::Horizontal,i18n("Encoding")
+ ,page);
+ encodingBox->setMargin(KDialog::marginHint());
+ layout->addWidget(encodingBox);
+ QHBox *b = new QHBox(encodingBox);
+
+ QLabel* tempLabel=new QLabel(i18n("Default:"),b);
+ _encodingBox = new QComboBox(b, "kcfg_Encoding");
+ b->setStretchFactor(_encodingBox,2);
+ b->setSpacing(KDialog::spacingHint());
+
+ QString defaultName=charsetString(ProjectSettingsBase::Locale);
+ defaultName+=" "+i18n("(default)");
+ QString utf8Name=charsetString(ProjectSettingsBase::UTF8);
+ QString utf16Name=charsetString(ProjectSettingsBase::UTF16);
+
+ _encodingBox->insertItem(defaultName,(int)ProjectSettingsBase::Locale);
+ _encodingBox->insertItem(utf8Name,(int)ProjectSettingsBase::UTF8);
+
+ // KBabel seems to crash somehow, when saving in utf16, so
+ // it's better to disable this, since it is useless anyway
+ // at the moment
+ //_encodingBox->insertItem(utf16Name,(int)UTF16);
+
+ tempLabel->setBuddy(_encodingBox);
+
+ _oldEncodingButton = new QCheckBox(i18n("Kee&p the encoding of the file")
+ ,encodingBox, "kcfg_UseOldEncoding");
+
+ _autoSaveBox = new QGroupBox( 1, Qt::Horizontal, i18n( "Automatic Saving" ), page );
+ _autoSaveBox->setMargin( KDialog::marginHint( ) );
+ layout->addWidget( _autoSaveBox );
+ _autoSaveDelay = new KIntNumInput( _autoSaveBox, "kcfg_AutoSaveDelay" );
+ _autoSaveDelay->setRange( 0, 60 );
+ _autoSaveDelay->setSuffix( i18n( "Short for minutes", " min" ) );
+ _autoSaveDelay->setSpecialValueText( i18n( "No autosave" ) );
+
+ layout->addStretch(1);
+ page->setMinimumSize(sizeHintForWidget(page));
+ addTab(page, i18n("&General"));
+
+ page = new QWidget(this);
+ layout=new QVBoxLayout(page);
+ layout->setSpacing(KDialog::spacingHint());
+ layout->setMargin(KDialog::marginHint());
+
+ QGroupBox* gridBox = new QGroupBox(2,Qt::Horizontal,i18n("Fields to Update"),page);
+ layout->addWidget(gridBox);
+ gridBox->setMargin(KDialog::marginHint());
+
+ _revisionButton = new QCheckBox(i18n("Re&vision-Date"),gridBox, "kcfg_UpdateRevisionDate");
+ _lastButton = new QCheckBox(i18n("Last-&Translator"),gridBox, "kcfg_UpdateLastTranslator");
+ _languageButton = new QCheckBox(i18n("&Language"),gridBox, "kcfg_UpdateLanguageTeam");
+ _charsetButton = new QCheckBox(i18n("Char&set"),gridBox, "kcfg_UpdateCharset");
+ _encodingButton = new QCheckBox(i18n("&Encoding"),gridBox, "kcfg_UpdateEncoding");
+ _projectButton = new QCheckBox(i18n("Pro&ject"),gridBox, "kcfg_UpdateProject");
+
+ QButtonGroup* dateBox = new QButtonGroup(2,Qt::Horizontal,i18n("Format of Revision-Date"),page, "kcfg_DateFormat");
+ layout->addWidget(dateBox);
+ box->setMargin(KDialog::marginHint());
+
+ // we remove/insert default date button to correctly map Qt::DateFormat to our Ids
+ _defaultDateButton = new QRadioButton( i18n("De&fault date format"),dateBox );
+ dateBox->remove (_defaultDateButton);
+ _localDateButton = new QRadioButton( i18n("Local date fo&rmat"),dateBox );
+ dateBox->remove (_localDateButton);
+ _customDateButton = new QRadioButton( i18n("Custo&m date format:"),dateBox );
+
+ dateBox->insert (_defaultDateButton);
+ dateBox->insert (_localDateButton);
+
+ _dateFormatEdit = new QLineEdit(dateBox, "kcfg_CustomDateFormat");
+ _dateFormatEdit->setEnabled(false);
+
+ connect( _customDateButton, SIGNAL(toggled(bool)), this, SLOT( customDateActivated(bool) ) );
+
+ QGroupBox* projectBox = new QGroupBox(1,Qt::Horizontal,i18n("Project String")
+ ,page);
+ projectBox->setMargin(KDialog::marginHint());
+ layout->addWidget(projectBox);
+ b = new QHBox(projectBox);
+
+ tempLabel=new QLabel(i18n("Project-Id:"),b);
+ _projectEdit = new QLineEdit(b, "kcfg_ProjectString");
+ b->setStretchFactor(_projectEdit,2);
+ b->setSpacing(KDialog::spacingHint());
+ tempLabel->setBuddy(_projectEdit);
+
+ layout->addStretch(1);
+ page->setMinimumSize(sizeHintForWidget(page));
+ addTab(page, i18n("&Header"));
+
+ page = new QWidget(this);
+ layout=new QVBoxLayout(page);
+ layout->setSpacing(KDialog::spacingHint());
+ layout->setMargin(KDialog::marginHint());
+
+ QGroupBox* translatorCopyrightBox = new QGroupBox(1,Qt::Horizontal, page);
+ translatorCopyrightBox->setMargin(KDialog::marginHint());
+ _translatorCopyrightButton =
+ new QCheckBox(i18n("Update &translator copyright")
+ ,translatorCopyrightBox, "kcfg_UpdateTranslatorCopyright");
+ layout->addWidget(translatorCopyrightBox);
+
+ QGroupBox* fsfBox=new QButtonGroup(1,Qt::Horizontal,i18n("Free Software Foundation Copyright"),page, "kcfg_FSFCopyright");
+ layout->addWidget(fsfBox);
+
+ fsfBox->setMargin(KDialog::marginHint());
+ _removeFSFButton = new QRadioButton(i18n("&Remove copyright if empty"),fsfBox);
+ _updateFSFButton = new QRadioButton(i18n("&Update copyright"),fsfBox);
+ _nochangeFSFButton = new QRadioButton(i18n("Do &not change"),fsfBox);
+
+ layout->addStretch(1);
+ page->setMinimumSize(sizeHintForWidget(page));
+ addTab(page, i18n("Cop&yright"));
+
+ QWhatsThis::add(_updateButton,
+ i18n("<qt><p><b>Update Header</b></p>\n"
+ "<p>Check this button to update the header "
+ "information of the file "
+ "every time it is saved.</p>\n"
+ "<p>The header normally keeps information about "
+ "the date and time the file was last\n"
+ "updated, the last translator etc.</p>\n"
+ "<p>You can choose which information you want to update from the checkboxes below.\n"
+ "Fields that do not exist are added to the header.\n"
+ "If you want to add additional fields to the header, you can edit the header manually by choosing\n"
+ "<b>Edit->Edit Header</b> in the editor window.</p></qt>"));
+
+ QWhatsThis::add(gridBox,i18n("<qt><p><b>Fields to update</b></p>\n"
+ "<p>Choose which fields in the header you want to have updated when saving.\n"
+ "If a field does not exist, it is appended to the header.</p>\n"
+ "<p>If you want to add other information to the header, you have to edit the header manually\n"
+ "by choosing <b>Edit->Edit Header</b> in the editor window.</p>\n"
+ "<p>Deactivate <b>Update Header</b> above if you do not want to have the header\n"
+ "updated when saving.</p></qt>"));
+
+ QWhatsThis::add(encodingBox,i18n("<qt><p><b>Encoding</b></p>"
+"<p>Choose how to encode characters when saving to a file. If you are unsure "
+"what encoding to use, please ask your translation coordinator.</p>"
+"<ul><li><b>%1</b>: this is the encoding that fits the character "
+"set of your system language.</li>"
+"<li><b>%2</b>: uses Unicode (UTF-8) encoding.</li>"
+"</ul></qt>").arg(defaultName).arg(utf8Name) );
+
+
+ QWhatsThis::add(_oldEncodingButton
+ ,i18n("<qt><p><b>Keep the encoding of the file</b></p>"
+ "<p>If this option is activated, files are always saved in the "
+ "same encoding as they were read in. Files without charset "
+ "information in the header (e.g. POT files) are saved in the "
+ "encoding set above.</p></qt>"));
+
+ QWhatsThis::add(_autoCheckButton,i18n("<qt><p><b>Check syntax of file when saving</b></p>\n"
+"<p>Check this to automatically check syntax of file with \"msgfmt --statistics\"\n"
+"when saving a file. You will only get a message, if an error occurred.</p></qt>"));
+
+ QWhatsThis::add(_saveObsoleteButton,i18n("<qt><p><b>Save obsolete entries</b></p>\n"
+"<p>If this option is activated, obsolete entries found when the file was open\n"
+"will be saved back to the file. Obsolete entries are marked by #~ and are\n"
+"created when the msgmerge does not need the translation anymore.\n"
+"If the text will appear again, the obsolete entries will be activated again.\n"
+"The main drawback is the size of the saved file.</p></qt>"));
+
+
+ QWhatsThis::add(dateBox, i18n("<qt><p><b>Format of Revision-Date</b></p>"
+"<p>Choose in which format the date and time of the header field\n"
+"<i>PO-Revision-Date</i> is saved: <ul>\n"
+"<li><b>Default</b> is the format normally used in PO files.</li>\n"
+"<li><b>Local</b> is the format specific to your country.\n"
+"It can be configured in KDE's Control Center.</li>\n"
+"<li><b>Custom</b> lets you define your own format.</li></ul></p> "
+"<p>It is recommended that you use the default format to avoid creating non-standard PO files.</p>"
+"<p>For more information, see section <b>The Preferences Dialog</b> "
+"in the online help.</p>"
+"</qt>") );
+
+ setMinimumSize(sizeHint());
+}
+
+
+void SavePreferences::defaults(const KBabel::SaveSettings& _settings)
+{
+ _updateButton->setChecked(_settings.autoUpdate);
+
+ _lastButton->setChecked(_settings.updateLastTranslator);
+ _revisionButton->setChecked(_settings.updateRevisionDate);
+ _languageButton->setChecked(_settings.updateLanguageTeam);
+ _charsetButton->setChecked(_settings.updateCharset);
+ _encodingButton->setChecked(_settings.updateEncoding);
+ _projectButton->setChecked(_settings.updateProject);
+
+ _encodingBox->setCurrentItem(_settings.encoding);
+ _oldEncodingButton->setChecked(_settings.useOldEncoding);
+
+ _projectEdit->setText(_settings.projectString);
+
+ _descriptionButton->setChecked(_settings.updateDescription);
+ _descriptionEdit->setText(_settings.descriptionString);
+ _translatorCopyrightButton->setChecked(_settings.updateTranslatorCopyright);
+
+ switch(_settings.FSFCopyright)
+ {
+ case ProjectSettingsBase::Update:
+ _updateFSFButton->setChecked(true);
+ break;
+ case ProjectSettingsBase::Remove:
+ _removeFSFButton->setChecked(true);
+ break;
+ case ProjectSettingsBase::NoChange:
+ _nochangeFSFButton->setChecked(true);
+ break;
+ case ProjectSettingsBase::RemoveLine:
+ break;
+ }
+
+ _autoCheckButton->setChecked(_settings.autoSyntaxCheck);
+ _saveObsoleteButton->setChecked(_settings.saveObsolete);
+
+ _dateFormatEdit->setText(_settings.customDateFormat);
+
+ switch(_settings.dateFormat)
+ {
+ case Qt::ISODate:
+ _defaultDateButton->setChecked(true);
+ break;
+ case Qt::LocalDate:
+ _localDateButton->setChecked(true);
+ break;
+ case Qt::TextDate:
+ _customDateButton->setChecked(true);
+ break;
+ }
+
+ _autoSaveDelay->setValue( _settings.autoSaveDelay );
+}
+
+
+void SavePreferences::customDateActivated(bool on)
+{
+ _dateFormatEdit->setEnabled(on);
+ _dateFormatEdit->setFocus();
+}
+
+void SavePreferences::setAutoSaveVisible( const bool on )
+{
+ if( on ) _autoSaveBox->show();
+ else _autoSaveBox->hide();
+}
+
+
+
+IdentityPreferences::IdentityPreferences(QWidget* parent, const QString& project)
+ : QWidget(parent)
+{
+ QWidget* page = this;
+ QVBoxLayout* layout=new QVBoxLayout(page);
+ layout->setSpacing(KDialog::spacingHint());
+ layout->setMargin(KDialog::marginHint());
+
+ if( !project.isEmpty() )
+ {
+ // show the project name in the widget at the top
+ layout->addWidget(new QLabel(i18n("<font size=\"+1\">Project: %1</font>").arg(project),page));
+ }
+
+ QGroupBox* group = new QGroupBox(2,Qt::Horizontal,page);
+ layout->addWidget(group);
+ group->setMargin(KDialog::marginHint());
+
+ QLabel* tempLabel=new QLabel(i18n("&Name:"),group);
+ _nameEdit = new QLineEdit(group, "kcfg_AuthorName");
+ tempLabel->setBuddy(_nameEdit);
+
+ tempLabel=new QLabel(i18n("Localized na&me:"),group);
+ _localNameEdit = new QLineEdit(group, "kcfg_LocalAuthorName");
+ tempLabel->setBuddy(_localNameEdit);
+
+ tempLabel=new QLabel(i18n("E&mail:"),group);
+ _mailEdit = new QLineEdit(group, "kcfg_AuthorEmail");
+ tempLabel->setBuddy(_mailEdit);
+
+
+ tempLabel=new QLabel(i18n("&Full language name:"),group);
+
+ QHBox *hbox = new QHBox(group);
+ hbox->setSpacing(KDialog::spacingHint());
+ _langEdit = new QLineEdit(hbox, "kcfg_Language");
+ tempLabel->setBuddy(_langEdit);
+ tempLabel=new QLabel(i18n("Lan&guage code:"),hbox);
+ _langCodeEdit = new QLineEdit(hbox, "kcfg_LanguageCode");
+ tempLabel->setBuddy(_langCodeEdit);
+ connect(_langCodeEdit,SIGNAL(textChanged(const QString&)), this
+ , SLOT(checkTestPluralButton()));
+
+ tempLabel=new QLabel(i18n("&Language mailing list:"),group);
+ _listEdit = new QLineEdit(group, "kcfg_Mailinglist");
+ _listEdit->setMinimumSize(100,_listEdit->sizeHint().height());
+ tempLabel->setBuddy(_listEdit);
+
+ tempLabel=new QLabel(i18n("&Timezone:"), group);
+ _timezoneEdit = new QLineEdit(group, "kcfg_Timezone");
+ _timezoneEdit->setMinimumSize(100,_timezoneEdit->sizeHint().height());
+ tempLabel->setBuddy(_timezoneEdit);
+
+
+ QString whatsThisMsg=i18n("<qt><p><b>Identity</b></p>\n"
+"<p>Fill in information about you and your translation team.\n"
+"This information is used when updating the header of a file.</p>\n"
+"<p>You can find the options if and what fields in the header should be updated\n"
+"on page <b>Save</b> in this dialog.</p></qt>");
+
+ QWhatsThis::add(group,whatsThisMsg);
+
+
+ group = new QGroupBox(1,Qt::Horizontal,page);
+ layout->addWidget(group);
+ group->setMargin(KDialog::marginHint());
+
+ hbox = new QHBox(group);
+ hbox->setSpacing(KDialog::spacingHint());
+
+ QLabel *label = new QLabel(i18n("&Number of singular/plural forms:"), hbox);
+ _pluralFormsBox = new QSpinBox(0,100,1,hbox, "kcfg_PluralForms");
+ _pluralFormsBox->setSpecialValueText(
+ i18n("automatic choose number of plural forms","Automatic"));
+ label->setBuddy(_pluralFormsBox);
+ connect(_pluralFormsBox,SIGNAL(valueChanged(int)), this
+ , SLOT(checkTestPluralButton()));
+
+ hbox->setStretchFactor(_pluralFormsBox,1);
+
+ _testPluralButton = new QPushButton(i18n("Te&st"),hbox);
+ _testPluralButton->setEnabled(false);
+ connect(_testPluralButton, SIGNAL(clicked()), this
+ , SLOT(testPluralForm()));
+
+ const QString msg=i18n("<qt><p><b>Number of singular/plural forms</b></p>"
+ "<p><b>Note</b>: This option is KDE specific. "
+ "If you are not translating a KDE application, you can safely "
+ "ignore this option.</p>"
+ "<p>Choose here how many singular and plural forms are used in "
+ "your language. "
+ "This number must correspond to the settings of your language "
+ "team.</p>"
+ "<p>Alternatively, you can set this option to "
+ "<i>Automatic</i> and KBabel will try to get this information "
+ "automatically from KDE. Use the <i>Test</i> button "
+ "to test if it can find it out.</p></qt>");
+ QWhatsThis::add(_pluralFormsBox,msg);
+ QWhatsThis::add(_testPluralButton,msg);
+
+ QVBox* vbox = new QVBox(group);
+ vbox->setSpacing(KDialog::spacingHint());
+
+ label = new QLabel(i18n("&GNU plural form header:"), vbox);
+
+ hbox = new QHBox(vbox);
+ hbox->setSpacing(KDialog::spacingHint());
+
+ _gnuPluralFormHeaderEdit = new QLineEdit(hbox, "kcfg_PluralFormsHeader");
+ label->setBuddy(_gnuPluralFormHeaderEdit);
+
+ hbox->setStretchFactor(_gnuPluralFormHeaderEdit,1);
+
+ _testGnuPluralFormButton = new QPushButton(i18n("&Lookup"),hbox);
+ connect(_testGnuPluralFormButton, SIGNAL(clicked()), this
+ , SLOT(lookupGnuPluralFormHeader()));
+
+ _checkPluralArgumentBox = new QCheckBox( i18n("Re&quire plural form arguments in translation")
+ , group, "kcfg_CheckPluralArgument" );
+ QWhatsThis::add(_checkPluralArgumentBox,
+ i18n("<qt><p><b>Require plural form arguments in translation</b></p>\n"
+ "<p><b>Note</b>: This option is KDE specific at the moment. "
+ "If you are not translating a KDE application, you can safely "
+ "ignore this option.</p>\n"
+ "<p>If is this option enabled, the validation check will "
+ "require the %n argument to be present in the message.</p></qt>"));
+
+ QWhatsThis::add(_gnuPluralFormHeaderEdit,
+ i18n("<qt><p><b>GNU plural form header</b></p>\n"
+ "<p>Here you can fill a header entry for GNU plural form handling; "
+ "if you leave the entry empty, the entry in the PO file will not be "
+ "changed or added.</p>\n"
+ "<p>KBabel can automatically try to determine value suggested by the "
+ "GNU gettext tools for currently set language; just press the <b>Lookup</b> "
+ "button.</p></qt>"));
+
+ layout->addStretch(1);
+
+ page->setMinimumSize(sizeHintForWidget(page));
+
+ setMinimumSize(sizeHint());
+
+ _mailEdit->installEventFilter(this);
+ _listEdit->installEventFilter(this);
+}
+
+void IdentityPreferences::defaults(const IdentitySettings& settings)
+{
+ _nameEdit->setText(settings.authorName);
+ _localNameEdit->setText(settings.authorLocalizedName);
+ _langEdit->setText(settings.languageName);
+ _langCodeEdit->setText(settings.languageCode);
+ _listEdit->setText(settings.mailingList);
+ _timezoneEdit->setText(settings.timeZone);
+ _pluralFormsBox->setValue(settings.numberOfPluralForms);
+ _gnuPluralFormHeaderEdit->setText(settings.gnuPluralFormHeader);
+ _checkPluralArgumentBox->setChecked(settings.checkPluralArgument);
+}
+
+bool IdentityPreferences::eventFilter(QObject *o, QEvent *e)
+{
+ if(e->type() == QEvent::Drop)
+ {
+ QDropEvent *de = static_cast<QDropEvent*>(e);
+ KURL::List urlList;
+ if(de && KURLDrag::decode(de,urlList))
+ {
+ KURL url(urlList.first());
+ if(url.protocol()== "mailto")
+ {
+ QString mail=url.path();
+
+ bool handled=false;
+ if(o == _mailEdit)
+ {
+ handled=true;
+ _mailEdit->setText(mail);
+ }
+ else if(o == _listEdit)
+ {
+ handled=true;
+ _listEdit->setText(mail);
+ }
+
+ if(handled)
+ return true;
+ }
+ }
+ }
+
+ return false;
+}
+
+void IdentityPreferences::checkTestPluralButton()
+{
+ int val = _pluralFormsBox->value();
+ QString lang=_langCodeEdit->text();
+
+ _testPluralButton->setEnabled(val==0 && !lang.isEmpty());
+}
+
+void IdentityPreferences::testPluralForm()
+{
+ QString lang=_langCodeEdit->text();
+
+ if(lang.isEmpty())
+ {
+ KMessageBox::sorry(this,i18n("Please insert a language code first."));
+ return;
+ }
+
+ int number=Catalog::getNumberOfPluralForms(lang);
+
+ QString msg;
+
+ if(number < 0)
+ {
+ msg = i18n("It is not possible to find out the number "
+ "of singular/plural forms automatically for the "
+ "language code \"%1\".\n"
+ "Do you have kdelibs.po installed for this language?\n"
+ "Please set the correct number manually.").arg(lang);
+ }
+ else
+ {
+ msg = i18n("The number of singular/plural forms found for "
+ "the language code \"%1\" is %2.").arg(lang).arg(number);
+ }
+
+ if(!msg.isEmpty())
+ {
+ KMessageBox::information(this,msg);
+ }
+}
+
+void IdentityPreferences::lookupGnuPluralFormHeader()
+{
+ QString lang=_langCodeEdit->text();
+
+ if(lang.isEmpty())
+ {
+ KMessageBox::sorry(this,i18n("Please insert a language code first."));
+ return;
+ }
+
+ QString header=GNUPluralForms(lang);
+
+ if( header.isEmpty() )
+ {
+ KMessageBox::information(this, i18n("It was not possible to determine "
+ "GNU header for plural forms. Maybe your GNU gettext tools are too "
+ "old or they do not contain a suggested value for your language.") );
+ }
+ else
+ {
+ _gnuPluralFormHeaderEdit->setText( header );
+ }
+}
+
+
+MiscPreferences::MiscPreferences(QWidget *parent)
+ : QWidget(parent), _regExpEditDialog(0)
+{
+ QWidget* page = this;
+
+ QVBoxLayout* layout=new QVBoxLayout(page);
+ layout->setSpacing(KDialog::spacingHint());
+ layout->setMargin(KDialog::marginHint());
+
+ QGroupBox* box=new QGroupBox(1,Qt::Horizontal,page);
+ box->setMargin(KDialog::marginHint());
+ layout->addWidget(box);
+
+ QHBox *hbox = new QHBox(box);
+ hbox->setSpacing(KDialog::spacingHint());
+
+ QLabel *label = new QLabel(i18n("&Marker for keyboard accelerator:"),hbox);
+ accelMarkerEdit = new KLineEdit(hbox, "kcfg_AccelMarker");
+ accelMarkerEdit->setMaxLength(1);
+ label->setBuddy(accelMarkerEdit);
+ hbox->setStretchFactor(accelMarkerEdit,1);
+ QString msg=i18n("<qt><p><b>Marker for keyboard accelerator</b></p>"
+ "<p>Define here, what character marks the following "
+ "character as keyboard accelerator. For example in Qt it is "
+ "'&amp;' and in Gtk it is '_'.</p></qt>");
+ QWhatsThis::add(label,msg);
+ QWhatsThis::add(accelMarkerEdit,msg);
+
+
+ hbox = new QHBox(box);
+ hbox->setSpacing(KDialog::spacingHint());
+
+ label = new QLabel(i18n("&Regular expression for context information:")
+ ,hbox);
+ contextInfoEdit = new KLineEdit(hbox, "kcfg_ContextInfo");
+ label->setBuddy(contextInfoEdit);
+ hbox->setStretchFactor(contextInfoEdit,1);
+
+ msg=i18n("<qt><p><b>Regular expression for context information</b></p>"
+ "<p>Enter a regular expression here which defines what is "
+ "context information in the message and must not get "
+ "translated.</p></qt>");
+ QWhatsThis::add(label,msg);
+ QWhatsThis::add(contextInfoEdit,msg);
+
+ if( !KTrader::self()->query("KRegExpEditor/KRegExpEditor").isEmpty() )
+ {
+ _regExpButton = new QPushButton( i18n("&Edit..."), hbox );
+ connect( _regExpButton, SIGNAL( clicked() ), this, SLOT( regExpButtonClicked()));
+ }
+
+
+ // preferences for mail attachments
+ QVButtonGroup* vbgroup = new QVButtonGroup(page);
+ vbgroup->setTitle(i18n("Compression Method for Mail Attachments"));
+ vbgroup->setRadioButtonExclusive(true);
+ vbgroup->setMargin(KDialog::marginHint());
+ layout->addWidget(vbgroup);
+
+ bzipButton = new QRadioButton(i18n("tar/&bzip2"), vbgroup, "kcfg_BZipCompression");
+ gzipButton = new QRadioButton(i18n("tar/&gzip"), vbgroup);
+
+ compressSingle = new QCheckBox(i18n("&Use compression when sending "
+ "a single file"), vbgroup, "kcfg_CompressSingleFile");
+
+ layout->addStretch(1);
+ page->setMinimumSize(sizeHintForWidget(page));
+}
+
+void MiscPreferences::defaults(const MiscSettings& settings)
+{
+ accelMarkerEdit->setText(settings.accelMarker);
+ contextInfoEdit->setText(settings.contextInfo.pattern());
+ if( settings.useBzip )
+ bzipButton->setChecked (true);
+ else
+ gzipButton->setChecked (true);
+
+ compressSingle->setChecked(settings.compressSingleFile);
+}
+
+QString MiscPreferences::contextInfo() const
+{
+ QString temp=contextInfoEdit->text();
+
+ bool quoted=false;
+ QString newStr;
+
+ for(uint i=0; i<temp.length(); i++)
+ {
+ if(temp[i]=='n')
+ {
+ quoted=!quoted;
+ newStr+=temp[i];
+ }
+ else if(temp[i]=='n' && quoted)
+ {
+ newStr[newStr.length()-1]='\n';
+ quoted=false;
+ }
+ else
+ {
+ quoted=false;
+ newStr+=temp[i];
+ }
+ }
+
+ return newStr;
+}
+
+void MiscPreferences::setContextInfo(QString reg)
+{
+ reg.replace("\n","\\n");
+ contextInfoEdit->setText(reg);
+}
+
+void MiscPreferences::regExpButtonClicked()
+{
+ if ( _regExpEditDialog==0 )
+ _regExpEditDialog = KParts::ComponentFactory::createInstanceFromQuery<QDialog>
+ ("KRegExpEditor/KRegExpEditor", QString::null, this );
+
+ KRegExpEditorInterface *iface = dynamic_cast<KRegExpEditorInterface *>( _regExpEditDialog );
+ if( iface )
+ {
+ iface->setRegExp( contextInfoEdit->text() );
+ if( _regExpEditDialog->exec() == QDialog::Accepted )
+ contextInfoEdit->setText( iface->regExp() );
+ }
+}
+
+
+SpellPreferences::SpellPreferences(QWidget* parent)
+ : QWidget(parent)
+{
+ QWidget* page = this;
+ QVBoxLayout* layout=new QVBoxLayout(page);
+ layout->setSpacing(KDialog::spacingHint());
+ layout->setMargin(KDialog::marginHint());
+
+
+ onFlyBtn = new QCheckBox(i18n("On the &fly spellchecking"),page, "kcfg_OnFlySpellCheck");
+ layout->addWidget(onFlyBtn);
+
+ QWhatsThis::add(onFlyBtn, i18n("<qt><p><b>On the fly spellchecking</b></p>"
+ "<p>Activate this to let KBabel spell check the text "
+ "as you type. Mispelled words will be colored by the error color.</p></qt>"));
+
+ spellConfig = new KSpellConfig(page,"spellConfigWidget",0,false);
+ layout->addWidget(spellConfig);
+ remIgnoredBtn = new QCheckBox(i18n("&Remember ignored words"),page, "kcfg_RememberIgnored");
+ layout->addWidget(remIgnoredBtn);
+
+ connect( spellConfig, SIGNAL( configChanged() )
+ , this, SIGNAL ( settingsChanged() ) );
+
+ QLabel *tempLabel = new QLabel(i18n("F&ile to store ignored words:"),page);
+ layout->addWidget(tempLabel);
+ ignoreURLEdit = new KURLRequester(page, "kcfg_IgnoreURL");
+ layout->addWidget(ignoreURLEdit);
+ tempLabel->setBuddy(ignoreURLEdit);
+
+ connect(remIgnoredBtn,SIGNAL(toggled(bool)),ignoreURLEdit
+ ,SLOT(setEnabled(bool)));
+
+
+ QString msg = i18n("<qt><p><b>Remember ignored words</b></p>"
+ "<p>Activate this, to let KBabel ignore the words, where you have "
+ "chosen <i>Ignore All</i> in the spell check dialog, "
+ "in every spell check.</p></qt>");
+
+ QWhatsThis::add(remIgnoredBtn,msg);
+ QWhatsThis::add(tempLabel,msg);
+ QWhatsThis::add(ignoreURLEdit,msg);
+
+ layout->addStretch(1);
+
+ page->setMinimumSize(sizeHintForWidget(page));
+
+ setMinimumSize(sizeHint());
+}
+
+
+
+void SpellPreferences::updateWidgets(const SpellcheckSettings& settings)
+{
+ spellConfig->setClient(settings.spellClient);
+ spellConfig->setNoRootAffix(settings.noRootAffix);
+ spellConfig->setRunTogether(settings.runTogether);
+ spellConfig->setEncoding(settings.spellEncoding);
+ spellConfig->setDictionary(settings.spellDict);
+}
+
+
+void SpellPreferences::mergeSettings(SpellcheckSettings& settings) const
+{
+ settings.noRootAffix=spellConfig->noRootAffix();
+ settings.runTogether=spellConfig->runTogether();
+ settings.spellClient=spellConfig->client();
+ settings.spellEncoding=spellConfig->encoding();
+ settings.spellDict=spellConfig->dictionary();
+
+ settings.valid=true;
+}
+
+void SpellPreferences::defaults(const SpellcheckSettings& settings)
+{
+ remIgnoredBtn->setChecked(settings.rememberIgnored);
+ ignoreURLEdit->setURL(settings.ignoreURL);
+
+ onFlyBtn->setChecked(settings.onFlySpellcheck);
+
+ KSpellConfig spCfg;
+ *spellConfig = spCfg;
+}
+
+CatmanPreferences::CatmanPreferences(QWidget* parent)
+ : QWidget(parent)
+{
+ QWidget* page = this;
+
+ QVBoxLayout* layout=new QVBoxLayout(page);
+ layout->setSpacing(KDialog::spacingHint());
+ layout->setMargin(KDialog::marginHint());
+
+ QGroupBox* box=new QGroupBox(1,Qt::Horizontal,page);
+ box->setMargin(KDialog::marginHint());
+ layout->addWidget(box);
+
+ QLabel* label=new QLabel(i18n("&Base folder of PO files:"),box);
+ QHBox* hbox = new QHBox(box);
+ hbox->setSpacing(KDialog::spacingHint());
+
+ const KFile::Mode mode = static_cast<KFile::Mode>( KFile::Directory | KFile::ExistingOnly | KFile::LocalOnly );
+
+
+ _poDirEdit = new KURLRequester(hbox, "kcfg_PoBaseDir");
+ _poDirEdit->setMode( mode );
+ _poDirEdit->setMinimumSize(250,_poDirEdit->sizeHint().height());
+ label->setBuddy(_poDirEdit);
+
+
+ label=new QLabel(i18n("Ba&se folder of POT files:"),box);
+ hbox = new QHBox(box);
+ hbox->setSpacing(KDialog::spacingHint());
+
+ _potDirEdit = new KURLRequester(hbox, "kcfg_PotBaseDir");
+ _potDirEdit->setMode( mode );
+ _potDirEdit->setMinimumSize(250,_potDirEdit->sizeHint().height());
+ label->setBuddy(_potDirEdit);
+
+
+
+ QWhatsThis::add(box,i18n("<qt><p><b>Base folders</b></p>\n"
+ "<p>Type in the folders which contain all your PO and POT files.\n"
+ "The files and the folders in these folders will then be merged into one\n"
+ "tree.</p></qt>"));
+
+
+ box=new QGroupBox(1,Qt::Horizontal,page);
+ box->setMargin(KDialog::marginHint());
+ layout->addWidget(box);
+
+ _openWindowButton = new QCheckBox(i18n("O&pen files in new window"),box, "kcfg_OpenWindow");
+
+
+ QWhatsThis::add(_openWindowButton,i18n("<qt><p><b>Open files in new window</b></p>\n"
+"<p>If this is activated all files that are opened from the Catalog Manager are opened\n"
+"in a new window.</p></qt>"));
+
+ _killButton = new QCheckBox( i18n("&Kill processes on exit") , box, "kcfg_KillCmdOnExit" );
+
+ QWhatsThis::add( _killButton , i18n("<qt><p><b>Kill processes on exit</b></p>\n"
+"<p>If you check this, KBabel tries to kill the processes, that have not exited already when KBabel exits,\n"
+"by sending a kill signal to them.</p>\n"
+"<p>NOTE: It is not guaranteed that the processes will be killed.</p></qt>") );
+
+
+ _indexButton = new QCheckBox( i18n("Create inde&x for file contents"), box, "kcfg_IndexWords" );
+
+ QWhatsThis::add( _indexButton , i18n("<qt><p><b>Create index for file contents</b></p>\n"
+"<p>If you check this, KBabel will create an index for each PO file to speed up the find/replace functions.</p>\n"
+"<p>NOTE: This will slow down updating the file information considerably.</p></qt>") );
+
+ m_msgfmtButton = new QCheckBox( i18n("Run &msgfmt before processing a file"), box, "kcfg_msgfmt" );
+
+ QWhatsThis::add( m_msgfmtButton, i18n("<qt><p><b>Run msgfmt before processing a file</b></p>"
+ "<p>If you enable this, KBabel will run Gettext's "
+ "msgfmt tool before processing a file.</p>"
+ "<p>Enabling this setting is recommended, even if it causes processing to be slower. "
+ "This setting is enabled by default.</p>"
+ "<p>Disabling is useful for slow computers and when you want "
+ "to translate PO files that are not supported by the current version "
+ "of the Gettext tools that are on your system. "
+ "The drawback of disabling is that hardly any syntax checking is done by the processing code, "
+ "so invalid PO files could be shown as good ones, "
+ "even if Gettext tools would reject such files.</p></qt>") );
+
+ layout->addStretch(1);
+
+ page->setMinimumSize(sizeHintForWidget(page));
+
+ setMinimumSize(sizeHint());
+}
+
+
+void CatmanPreferences::defaults(const CatManSettings& settings)
+{
+ _poDirEdit->setURL(settings.poBaseDir);
+ _potDirEdit->setURL(settings.potBaseDir);
+
+ _openWindowButton->setChecked(settings.openWindow);
+
+ _killButton->setChecked(settings.killCmdOnExit );
+ _indexButton->setChecked(settings.indexWords );
+ m_msgfmtButton->setChecked( settings.msgfmt );
+}
+
+DirCommandsPreferences::DirCommandsPreferences(QWidget* parent)
+ : QWidget(parent)
+{
+ QWidget* page = this;
+
+ QVBoxLayout* layout=new QVBoxLayout(page);
+ layout->setSpacing(KDialog::spacingHint());
+ layout->setMargin(KDialog::marginHint());
+
+ QGroupBox* box = new QGroupBox( 1 , Qt::Horizontal , i18n("Commands for Folders") , page );
+ box->setMargin( KDialog::marginHint() );
+ layout->addWidget( box );
+
+ _dirCmdEdit = new CmdEdit( box );
+ new QLabel( i18n("Replaceables:\n@PACKAGE@, @PODIR@, @POTDIR@\n"
+ "@POFILES@, @MARKEDPOFILES@"), box);
+
+ connect (_dirCmdEdit, SIGNAL(widgetChanged()), this, SIGNAL(settingsChanged()));
+
+ QWhatsThis::add( box , i18n("<qt><p><b>Commands for folders</b></p>"
+"<p>Insert here the commands you want to execute in folders from "
+"the Catalog Manager. The commands are then shown in the submenu "
+"<b>Commands</b> in the Catalog Manager's context menu.</p>"
+"<p>The following strings will be replaced in a command:<ul>"
+"<li>@PACKAGE@: The name of the folder without path</li>"
+"<li>@PODIR@: The name of the PO-folder with path</li>"
+"<li>@POTDIR@: The name of the template folder with path</li>"
+"<li>@POFILES@: The names of the PO files with path</li>"
+"<li>@MARKEDPOFILES@: The names of the marked PO files with path</li>"
+"</ul></p>"
+"</qt>") );
+
+
+
+ layout->addStretch(1);
+ page->setMinimumSize(sizeHintForWidget(page));
+
+ setMinimumSize(sizeHint());
+}
+
+
+DirCommandsPreferences::~DirCommandsPreferences()
+{
+}
+
+
+void DirCommandsPreferences::updateWidgets(const CatManSettings& settings)
+{
+ _dirCmdEdit->setCommands( settings.dirCommands , settings.dirCommandNames );
+}
+
+
+void DirCommandsPreferences::mergeSettings(CatManSettings& settings) const
+{
+ _dirCmdEdit->commands( settings.dirCommands , settings.dirCommandNames );
+}
+
+void DirCommandsPreferences::defaults(const CatManSettings& settings)
+{
+ _dirCmdEdit->setCommands( settings.dirCommands, settings.dirCommandNames );
+}
+
+
+FileCommandsPreferences::FileCommandsPreferences(QWidget* parent)
+ : QWidget(parent)
+{
+ QWidget* page = this;
+
+ QVBoxLayout* layout=new QVBoxLayout(page);
+ layout->setSpacing(KDialog::spacingHint());
+ layout->setMargin(KDialog::marginHint());
+
+ QGroupBox* box=new QGroupBox( 1 , Qt::Horizontal , i18n("Commands for Files") , page );
+ box->setMargin( KDialog::marginHint() );
+ layout->addWidget( box );
+
+ _fileCmdEdit = new CmdEdit( box );
+ new QLabel( i18n("Replaceables:\n"
+"@PACKAGE@, @POFILE@,@POTFILE@,\n@PODIR@, @POTDIR@"), box);
+
+ connect (_fileCmdEdit, SIGNAL(widgetChanged()), this, SIGNAL(settingsChanged()));
+
+ QWhatsThis::add( box , i18n("<qt><p><b>Commands for files</b></p>"
+"<p>Insert here the commands you want to execute on files from "
+"the Catalog Manager. The commands are then shown in the submenu "
+"<b>Commands</b> in the Catalog Manager's context menu.</p>"
+"<p>The following strings will be replaced in a command:<ul>"
+"<li>@PACKAGE@: The name of the file without path and extension</li>"
+"<li>@POFILE@: The name of the PO-file with path and extension</li>"
+"<li>@POTFILE@: The name of the corresponding template file with path "
+"and extension</li>"
+"<li>@POEMAIL@: The name and email address of the last translator</li>"
+"<li>@PODIR@: The name of the folder the PO-file is in, with path</li>"
+"<li>@POTDIR@: The name of the folder the template file is in, with "
+"path</li></ul></p></qt>") );
+
+
+
+ layout->addStretch(1);
+ page->setMinimumSize(sizeHintForWidget(page));
+
+ setMinimumSize(sizeHint());
+}
+
+
+FileCommandsPreferences::~FileCommandsPreferences()
+{
+}
+
+
+void FileCommandsPreferences::updateWidgets(const CatManSettings& settings)
+{
+ _fileCmdEdit->setCommands( settings.fileCommands , settings.fileCommandNames );
+}
+
+
+void FileCommandsPreferences::mergeSettings(CatManSettings& settings) const
+{
+ _fileCmdEdit->commands( settings.fileCommands , settings.fileCommandNames );
+}
+
+void FileCommandsPreferences::defaults(const CatManSettings& settings)
+{
+ _fileCmdEdit->setCommands( settings.fileCommands, settings.fileCommandNames );
+}
+
+ViewPreferences::ViewPreferences(QWidget* parent)
+ : QWidget(parent)
+{
+ QWidget* page = this;
+
+ QVBoxLayout* layout=new QVBoxLayout(page);
+ layout->setSpacing(KDialog::spacingHint());
+ layout->setMargin(KDialog::marginHint());
+
+ QGroupBox* box=new QGroupBox(2, Qt::Horizontal,i18n("Shown Columns"),page);
+ box->setMargin(KDialog::marginHint());
+ layout->addWidget(box);
+
+ _flagColumnCheckbox = new QCheckBox( i18n("Fla&g"), box, "kcfg_ShowFlagColumn" );
+ _fuzzyColumnCheckbox = new QCheckBox( i18n("&Fuzzy"), box, "kcfg_ShowFuzzyColumn" );
+ _untranslatedColumnCheckbox = new QCheckBox( i18n("&Untranslated"), box, "kcfg_ShowUntranslatedColumn" );
+ _totalColumnCheckbox = new QCheckBox( i18n("&Total"), box, "kcfg_ShowTotalColumn" );
+ _cvsColumnCheckbox = new QCheckBox( i18n("SVN/&CVS status"), box, "kcfg_ShowCVSColumn" );
+ _revisionColumnCheckbox = new QCheckBox( i18n("Last &revision"), box, "kcfg_ShowRevisionColumn" );
+ _translatorColumnCheckbox = new QCheckBox( i18n("Last t&ranslator"), box, "kcfg_ShowTranslatorColumn" );
+
+ QWhatsThis::add(box,i18n("<qt><p><b>Shown columns</b></p>\n"
+ "<p></p></qt>"));
+
+ layout->addStretch(1);
+
+ page->setMinimumSize(sizeHintForWidget(page));
+
+ setMinimumSize(sizeHint());
+}
+
+
+void ViewPreferences::defaults(const CatManSettings& _settings)
+{
+ _flagColumnCheckbox->setChecked(_settings.flagColumn);
+ _fuzzyColumnCheckbox->setChecked(_settings.fuzzyColumn);
+ _untranslatedColumnCheckbox->setChecked(_settings.untranslatedColumn);
+ _totalColumnCheckbox->setChecked(_settings.totalColumn);
+ _cvsColumnCheckbox->setChecked(_settings.cvsColumn);
+ _revisionColumnCheckbox->setChecked(_settings.revisionColumn);
+ _translatorColumnCheckbox->setChecked(_settings.translatorColumn);
+}
+
+SourceContextPreferences::SourceContextPreferences(QWidget* parent): QWidget(parent)
+{
+ QWidget* page = this;
+ QVBoxLayout* layout=new QVBoxLayout(page);
+ layout->setSpacing(KDialog::spacingHint());
+ layout->setMargin(KDialog::marginHint());
+
+ QHBox* box = new QHBox(page);
+ box->setSpacing(KDialog::spacingHint());
+ QLabel* tempLabel=new QLabel(i18n("&Base folder for source code:"),box);
+
+ const KFile::Mode mode = static_cast<KFile::Mode>( KFile::Directory | KFile::ExistingOnly | KFile::LocalOnly );
+ _coderootEdit = new KURLRequester ( box, "kcfg_CodeRoot" );
+ _coderootEdit->setMode( mode );
+ _coderootEdit->setMinimumSize( 250, _coderootEdit->sizeHint().height() );
+ tempLabel->setBuddy( _coderootEdit );
+ layout->addWidget(box);
+
+ // FIXME: use KConfigXT
+ _pathsEditor = new KListEditor(page);
+ _pathsEditor->setTitle(i18n("Path Patterns"));
+ layout->addWidget(_pathsEditor);
+
+ connect ( _pathsEditor, SIGNAL (itemsChanged ())
+ , this, SIGNAL (itemsChanged ()));
+
+ _pathsEditor->installEventFilter(this);
+
+ setMinimumSize(sizeHint());
+}
+
+SourceContextPreferences::~SourceContextPreferences()
+{
+}
+
+void SourceContextPreferences::mergeSettings(KBabel::SourceContextSettings& settings) const
+{
+ settings.sourcePaths=_pathsEditor->list();
+}
+
+void SourceContextPreferences::updateWidgets(const KBabel::SourceContextSettings& settings)
+{
+ _pathsEditor->setList(settings.sourcePaths);
+}
+
+void SourceContextPreferences::defaults(const KBabel::SourceContextSettings& settings)
+{
+ _pathsEditor->setList(settings.sourcePaths);
+}
+
+bool SourceContextPreferences::eventFilter( QObject *, QEvent *e )
+{
+ if( e->type() == QEvent::KeyPress )
+ {
+ QKeyEvent *ke = dynamic_cast<QKeyEvent*>(e);
+ if( ke->key() == Key_Return || ke->key() == Key_Enter )
+ return true;
+ }
+ return false;
+}
+
+#include "projectprefwidgets.moc"
diff --git a/kbabel/commonui/projectprefwidgets.h b/kbabel/commonui/projectprefwidgets.h
new file mode 100644
index 00000000..81a1b3e6
--- /dev/null
+++ b/kbabel/commonui/projectprefwidgets.h
@@ -0,0 +1,285 @@
+/* ****************************************************************************
+ This file is part of KBabel
+
+ Copyright (C) 1999-2001 by Matthias Kiefer
+ <matthias.kiefer@gmx.de>
+ 2001-2005 by Stanislav Visnovsky
+ <visnovsky@kde.org>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the 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, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+ In addition, as a special exception, the copyright holders give
+ permission to link the code of this program with any edition of
+ the Qt library by Trolltech AS, Norway (or with modified versions
+ of Qt that use the same license as Qt), and distribute linked
+ combinations including the two. You must obey the GNU General
+ Public License in all respects for all of the code used other than
+ Qt. If you modify this file, you may extend this exception to
+ your version of the file, but you are not obligated to do so. If
+ you do not wish to do so, delete this exception statement from
+ your version.
+
+**************************************************************************** */
+#ifndef PROJECTPREFWIDGETS_H
+#define PROJECTPREFWIDGETS_H
+
+#include <ktabctl.h>
+#include <qptrlist.h>
+#include "projectsettings.h"
+
+
+class KLineEdit;
+class QLineEdit;
+class QCheckBox;
+class QComboBox;
+class QListBox;
+class QRadioButton;
+class QSpinBox;
+class CmdEdit;
+class KFontChooser;
+class KColorButton;
+class KComboBox;
+class KSpellConfig;
+class KURLRequester;
+class QPushButton;
+class QGroupBox;
+class KListEditor;
+class ToolSelectionWidget;
+class KIntNumInput;
+class KURLRequester;
+
+struct ModuleInfo;
+
+class KDE_EXPORT SavePreferences : public KTabCtl
+{
+ Q_OBJECT
+public:
+ SavePreferences(QWidget* parent=0);
+ void defaults(const KBabel::SaveSettings& settings);
+ void setAutoSaveVisible(const bool on);
+
+private:
+ QCheckBox* _lastButton;
+ QCheckBox* _revisionButton;
+ QCheckBox* _languageButton;
+ QCheckBox* _charsetButton;
+ QCheckBox* _encodingButton;
+ QCheckBox* _projectButton;
+
+ QCheckBox* _updateButton;
+ QCheckBox* _autoCheckButton;
+ QCheckBox* _saveObsoleteButton;
+
+ QComboBox* _encodingBox;
+ QCheckBox* _oldEncodingButton;
+
+ QRadioButton* _defaultDateButton;
+ QRadioButton* _localDateButton;
+ QRadioButton* _customDateButton;
+ QLineEdit* _dateFormatEdit;
+
+ QLineEdit* _projectEdit;
+
+ QRadioButton* _removeFSFButton;
+ QRadioButton* _updateFSFButton;
+ QRadioButton* _nochangeFSFButton;
+ QCheckBox* _translatorCopyrightButton;
+
+ QCheckBox* _descriptionButton;
+ QLineEdit* _descriptionEdit;
+
+ KIntNumInput * _autoSaveDelay;
+ QGroupBox * _autoSaveBox;
+
+private slots:
+ void customDateActivated(bool on);
+};
+
+
+class IdentityPreferences : public QWidget
+{
+ Q_OBJECT
+public:
+ IdentityPreferences(QWidget *parent = 0, const QString& project = "");
+ virtual bool eventFilter(QObject *, QEvent*);
+ void defaults(const KBabel::IdentitySettings& settings);
+
+private slots:
+ void checkTestPluralButton();
+ void testPluralForm();
+ void lookupGnuPluralFormHeader();
+
+private:
+ QLineEdit* _nameEdit;
+ QLineEdit* _localNameEdit;
+ QLineEdit* _mailEdit;
+ QLineEdit* _langEdit;
+ QLineEdit* _langCodeEdit;
+ QLineEdit* _listEdit;
+
+ QLineEdit* _timezoneEdit;
+ QSpinBox *_pluralFormsBox;
+ QPushButton *_testPluralButton;
+ QCheckBox* _checkPluralArgumentBox;
+ QLineEdit* _gnuPluralFormHeaderEdit;
+ QPushButton *_testGnuPluralFormButton;
+};
+
+
+class MiscPreferences : public QWidget
+{
+ Q_OBJECT
+public:
+ MiscPreferences(QWidget *parent=0);
+ void defaults(const KBabel::MiscSettings& settings);
+
+private slots:
+ void regExpButtonClicked();
+
+private:
+ void setContextInfo(QString reg);
+ QString contextInfo() const;
+
+ KLineEdit *contextInfoEdit;
+ KLineEdit *accelMarkerEdit;
+
+ QDialog *_regExpEditDialog;
+ QPushButton *_regExpButton;
+
+ QRadioButton* bzipButton;
+ QRadioButton* gzipButton;
+ QCheckBox* compressSingle;
+};
+
+class SpellPreferences : public QWidget
+{
+ Q_OBJECT
+public:
+ SpellPreferences(QWidget *parent=0);
+
+ void mergeSettings(KBabel::SpellcheckSettings& set) const;
+ void updateWidgets(const KBabel::SpellcheckSettings& settings);
+ void defaults(const KBabel::SpellcheckSettings& settings);
+
+signals:
+ void settingsChanged();
+
+private:
+ KSpellConfig* spellConfig;
+ QCheckBox* remIgnoredBtn;
+ QCheckBox* onFlyBtn;
+ KURLRequester* ignoreURLEdit;
+
+};
+
+class CatmanPreferences : public QWidget
+{
+ Q_OBJECT
+public:
+ CatmanPreferences(QWidget *parent = 0);
+ void defaults(const KBabel::CatManSettings& settings);
+
+private:
+ KURLRequester* _poDirEdit;
+ KURLRequester* _potDirEdit;
+
+ QCheckBox* _openWindowButton;
+
+ QCheckBox* _killButton;
+ QCheckBox* _indexButton;
+ QCheckBox* m_msgfmtButton;
+};
+
+class DirCommandsPreferences : public QWidget
+{
+ Q_OBJECT
+public:
+ DirCommandsPreferences(QWidget *parent = 0);
+ virtual ~DirCommandsPreferences();
+
+ void mergeSettings(KBabel::CatManSettings& settings) const;
+ void updateWidgets(const KBabel::CatManSettings&);
+ void defaults(const KBabel::CatManSettings& settings);
+
+signals:
+ void settingsChanged();
+
+private:
+ CmdEdit* _dirCmdEdit;
+};
+
+class FileCommandsPreferences : public QWidget
+{
+ Q_OBJECT
+public:
+ FileCommandsPreferences(QWidget *parent = 0);
+ virtual ~FileCommandsPreferences();
+
+ void mergeSettings(KBabel::CatManSettings& settings) const;
+ void updateWidgets(const KBabel::CatManSettings& settings);
+ void defaults(const KBabel::CatManSettings& settings);
+
+signals:
+ void settingsChanged();
+
+private:
+ CmdEdit* _fileCmdEdit;
+};
+
+class ViewPreferences : public QWidget
+{
+ Q_OBJECT
+public:
+ ViewPreferences(QWidget *parent = 0);
+ void defaults(const KBabel::CatManSettings& settings);
+
+private:
+ QCheckBox* _flagColumnCheckbox;
+ QCheckBox* _fuzzyColumnCheckbox;
+ QCheckBox* _untranslatedColumnCheckbox;
+ QCheckBox* _totalColumnCheckbox;
+ QCheckBox* _cvsColumnCheckbox;
+ QCheckBox* _revisionColumnCheckbox;
+ QCheckBox* _translatorColumnCheckbox;
+};
+
+/**
+* This class implements preference widget for source context
+*
+* @short Class for setting preferences for source context
+* @author Stanislav Visnovsky <visnovsky@kde.org>
+*/
+class SourceContextPreferences : public QWidget
+{
+ Q_OBJECT
+public:
+ SourceContextPreferences(QWidget* parent=0);
+ virtual ~SourceContextPreferences();
+
+ void mergeSettings(KBabel::SourceContextSettings& settings) const;
+ void updateWidgets(const KBabel::SourceContextSettings& settings);
+ void defaults(const KBabel::SourceContextSettings& settings);
+
+ virtual bool eventFilter(QObject *, QEvent*);
+
+signals:
+ void itemsChanged ();
+
+private:
+ KURLRequester* _coderootEdit;
+ KListEditor* _pathsEditor;
+};
+
+#endif // PROJECTPREFWIDGETS_H
diff --git a/kbabel/commonui/projectwizard.cpp b/kbabel/commonui/projectwizard.cpp
new file mode 100644
index 00000000..d1202f4a
--- /dev/null
+++ b/kbabel/commonui/projectwizard.cpp
@@ -0,0 +1,172 @@
+/* ****************************************************************************
+ This file is part of KBabel
+
+ Copyright (C) 2004 by StanislavVsinovsky
+ <visnovsky@kde.org>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the 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, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+ In addition, as a special exception, the copyright holders give
+ permission to link the code of this program with any edition of
+ the Qt library by Trolltech AS, Norway (or with modified versions
+ of Qt that use the same license as Qt), and distribute linked
+ combinations including the two. You must obey the GNU General
+ Public License in all respects for all of the code used other than
+ Qt. If you modify this file, you may extend this exception to
+ your version of the file, but you are not obligated to do so. If
+ you do not wish to do so, delete this exception statement from
+ your version.
+
+**************************************************************************** */
+
+#include "projectwizard.h"
+#include "projectwizardwidget.h"
+#include "projectwizardwidget2.h"
+
+#include "kbprojectmanager.h"
+
+#include <qcombobox.h>
+
+#include <kapplication.h>
+#include <kmessagebox.h>
+#include <klineedit.h>
+#include <klocale.h>
+#include <kurlrequester.h>
+
+using namespace KBabel;
+
+ProjectWizard::ProjectWizard(QWidget *parent,const char *name)
+ : KWizard(parent,name,true)
+{
+ _wizard = new ProjectStep1(this,"project wizard widget");
+
+ // fill the known language codes
+ KConfig all_languages("all_languages", true, false, "locale");
+ QStringList lang_codes = KGlobal::locale()->allLanguagesTwoAlpha();
+ for (QStringList::iterator it = lang_codes.begin();
+ it != lang_codes.end(); ++it)
+ {
+ // we need untranslated entries here, because of Translation Robot!
+ QString entry = (*it);
+ const int i = entry.find('_');
+ entry.replace(0, i, entry.left(i).lower());
+ all_languages.setGroup(entry);
+ entry = all_languages.readEntryUntranslated("Name");
+ if( ! entry.isEmpty() )
+ {
+ _wizard->_projectLanguage->insertItem( entry );
+ m_language_codes[entry] = (*it);
+ }
+ }
+
+ connect( _wizard->_projectName, SIGNAL(textChanged(const QString &)), this, SLOT(textChanged(const QString &)));
+ connect( _wizard->_projectFile, SIGNAL(textChanged(const QString &)), this, SLOT(textChanged(const QString &)));
+ connect( this, SIGNAL( helpClicked( void ) ), this, SLOT( slotHelpClicked( void ) ) );
+
+ addPage(_wizard, i18n("Basic Project Information"));
+
+ _wizard2 = new ProjectStep2(this,"project wizard widget2");
+ _wizard2->_poDirEdit->setMode( KFile::Directory );
+ _wizard2->_potDirEdit->setMode( KFile::Directory );
+ addPage(_wizard2, i18n("Translation Files"));
+
+ setFinishEnabled (_wizard2, true);
+ setNextEnabled (_wizard, false);
+}
+
+QString ProjectWizard::url()
+{
+ return _wizard->_projectFile->url();
+}
+
+Project::Ptr ProjectWizard::project()
+{
+ Project::Ptr p = ProjectManager::open( _wizard->_projectFile->url() );
+ p->setName( _wizard->_projectName->text() );
+
+ enum type { KDE, GNOME, TP, Other };
+
+ type project_type = (type) _wizard->_projectType->currentItem();
+
+ KBabel::CatManSettings catman = p->catManSettings();
+ catman.poBaseDir = _wizard2->_poDirEdit->url();
+ catman.potBaseDir = _wizard2->_potDirEdit->url();
+ p->setSettings (catman);
+
+ KBabel::IdentitySettings identity = p->identitySettings();
+ // Language
+ identity.languageName = _wizard->_projectLanguage->currentText();
+ // LanguageCode
+ identity.languageCode = m_language_codes[identity.languageName];
+ p->setSettings (identity);
+
+ KBabel::SaveSettings save = p->saveSettings();
+ // autochecksyntax (not for KDE - it uses incompatible plural forms formatting)
+ if( project_type == KDE )
+ {
+ save.autoSyntaxCheck = false;
+ }
+ p->setSettings (save);
+
+ KBabel::MiscSettings misc = p->miscSettings();
+ if (project_type == GNOME)
+ {
+ misc.accelMarker = '_';
+ }
+ p->setSettings (misc);
+
+ return p;
+}
+
+void ProjectWizard::next()
+{
+ // check if the file exists
+ QFileInfo file(url());
+
+ if( file.exists() )
+ {
+ if (KMessageBox::warningContinueCancel(0, i18n("The file '%1' already exists.\n"
+ "Do you want to replace it?").arg(url()), i18n("File Exists"), i18n("Replace") ) == KMessageBox::Cancel)
+ return;
+ }
+
+ KWizard::next();
+}
+
+void ProjectWizard::textChanged(const QString &)
+{
+ setNextEnabled( _wizard, !_wizard->_projectName->text().isEmpty() && !_wizard->_projectFile->url().isEmpty() );
+}
+
+Project::Ptr ProjectWizard::newProject()
+{
+ ProjectWizard* dialog = new ProjectWizard();
+ if( dialog->exec() == QDialog::Accepted )
+ {
+ Project::Ptr res = dialog->project();
+ delete dialog;
+ res->config()->sync();
+ return res;
+ }
+
+ return 0;
+}
+
+void ProjectWizard::slotHelpClicked( void )
+{
+ kapp->invokeHelp( "preferences-project-wizard", "kbabel" );
+}
+
+#include "projectwizard.moc"
diff --git a/kbabel/commonui/projectwizard.h b/kbabel/commonui/projectwizard.h
new file mode 100644
index 00000000..5c994784
--- /dev/null
+++ b/kbabel/commonui/projectwizard.h
@@ -0,0 +1,74 @@
+/* ****************************************************************************
+ This file is part of KBabel
+
+ Copyright (C) 2004 by Stanislav Visnovsky
+ <visnovsky@kde.org>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the 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, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+ In addition, as a special exception, the copyright holders give
+ permission to link the code of this program with any edition of
+ the Qt library by Trolltech AS, Norway (or with modified versions
+ of Qt that use the same license as Qt), and distribute linked
+ combinations including the two. You must obey the GNU General
+ Public License in all respects for all of the code used other than
+ Qt. If you modify this file, you may extend this exception to
+ your version of the file, but you are not obligated to do so. If
+ you do not wish to do so, delete this exception statement from
+ your version.
+
+**************************************************************************** */
+#ifndef PROJECTWIZARD_H
+#define PROJECTWIZARD_H
+
+#include <kwizard.h>
+
+#include "kbproject.h"
+
+#include "qmap.h"
+#include "qstring.h"
+
+class ProjectStep1;
+class ProjectStep2;
+
+namespace KBabel {
+
+class KDE_EXPORT ProjectWizard : public KWizard
+{
+ Q_OBJECT
+public:
+ ProjectWizard(QWidget* parent = 0, const char * name = 0);
+
+ Project::Ptr project();
+
+ QString url();
+
+ static Project::Ptr newProject();
+
+private slots:
+ void textChanged(const QString &);
+ void slotHelpClicked( void );
+ virtual void next();
+
+private:
+ ProjectStep1* _wizard;
+ ProjectStep2* _wizard2;
+
+ QMap<QString, QString> m_language_codes;
+};
+
+}
+
+#endif // PROJECTPREF_H
diff --git a/kbabel/commonui/projectwizardwidget.ui b/kbabel/commonui/projectwizardwidget.ui
new file mode 100644
index 00000000..3ad04de7
--- /dev/null
+++ b/kbabel/commonui/projectwizardwidget.ui
@@ -0,0 +1,266 @@
+<!DOCTYPE UI><UI version="3.3" stdsetdef="1">
+<class>ProjectStep1</class>
+<author>Stanislav Visnovsky &lt;visnovsky@kde.org&gt;</author>
+<widget class="QWidget">
+ <property name="name">
+ <cstring>ProjectStep1</cstring>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>486</width>
+ <height>432</height>
+ </rect>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>textLabel1_3</cstring>
+ </property>
+ <property name="text">
+ <string>&lt;font size="+1"&gt;Welcome to Project Wizard!&lt;/font&gt;
+&lt;br/&gt;
+&lt;p&gt;
+The wizard will help you to setup a new translation
+project for KBabel.
+&lt;/p&gt;
+&lt;p&gt;
+First of all, you need to choose the project name
+and the file, where the configuration should be stored.
+&lt;/p&gt;
+&lt;p&gt;
+You should also choose a language to translate into
+and also a type of the translation project.
+&lt;/p&gt;</string>
+ </property>
+ </widget>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>layout3</cstring>
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="KURLRequester" row="1" column="1">
+ <property name="name">
+ <cstring>_projectFile</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>5</hsizetype>
+ <vsizetype>0</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>&lt;qt&gt;
+&lt;p&gt;&lt;b&gt;Configuration File Name&lt;/b&gt;&lt;br/&gt;
+The name of a file to store the configuration of the
+project.&lt;/p&gt;
+&lt;/qt&gt;</string>
+ </property>
+ </widget>
+ <widget class="QLabel" row="2" column="0">
+ <property name="name">
+ <cstring>textLabel1_2</cstring>
+ </property>
+ <property name="text">
+ <string>&amp;Language:</string>
+ </property>
+ <property name="buddy" stdset="0">
+ <cstring>_projectLanguage</cstring>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>&lt;qt&gt;
+&lt;p&gt;
+&lt;b&gt;Language&lt;/b&gt;&lt;br/&gt;
+The destination language of the project, i.e., the language
+to translate into. It should follow the ISO 631 language naming
+standard.&lt;/p&gt;
+&lt;/qt&gt;</string>
+ </property>
+ </widget>
+ <widget class="QLabel" row="0" column="0">
+ <property name="name">
+ <cstring>textLabel1</cstring>
+ </property>
+ <property name="enabled">
+ <bool>true</bool>
+ </property>
+ <property name="text">
+ <string>Project &amp;name:</string>
+ </property>
+ <property name="buddy" stdset="0">
+ <cstring>_projectName</cstring>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>&lt;qt&gt;&lt;p&gt;&lt;b&gt;Project name&lt;/b&gt;&lt;br/&gt;
+The project name is an identification of a project for
+you. It is shown in the project configuration dialog
+as well as in the title of windows opened for the project.
+&lt;br/&gt;
+&lt;br/&gt;
+&lt;b&gt;Note:&lt;/b&gt; The project name cannot be later changed.&lt;
+&lt;/p&gt;&lt;/qt&gt;</string>
+ </property>
+ </widget>
+ <widget class="QComboBox" row="2" column="1">
+ <property name="name">
+ <cstring>_projectLanguage</cstring>
+ </property>
+ <property name="editable">
+ <bool>true</bool>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>&lt;qt&gt;
+&lt;p&gt;
+&lt;b&gt;Language&lt;/b&gt;&lt;br/&gt;
+The destination language of the project, i.e., the language
+to translate into. It should follow the ISO 631 language naming
+standard.&lt;/p&gt;
+&lt;/qt&gt;</string>
+ </property>
+ </widget>
+ <widget class="QLabel" row="3" column="0">
+ <property name="name">
+ <cstring>textLabel2_2</cstring>
+ </property>
+ <property name="text">
+ <string>Project &amp;type:</string>
+ </property>
+ <property name="buddy" stdset="0">
+ <cstring>_projectType</cstring>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>&lt;qt&gt;
+&lt;p&gt;
+&lt;b&gt;Project Type&lt;/b&gt;
+The project type allows to tune the settings for the
+particular type of the well-known translation projects.
+For example, it sets up the validation tools,
+an accelerator marker and formatting of the header.
+&lt;/p&gt;
+&lt;p&gt;Currently known types:
+&lt;ul&gt;
+&lt;li&gt;&lt;b&gt;KDE&lt;/b&gt;: K Desktop Environment Internalization project&lt;/li&gt;
+&lt;li&gt;&lt;b&gt;GNOME&lt;/b&gt;: GNOME Translation project&lt;/li&gt;
+&lt;li&gt;&lt;b&gt;Translation Robot&lt;/b&gt;: Translation Project Robot&lt;/li&gt;
+&lt;li&gt;&lt;b&gt;Other&lt;/b&gt;: Other kind of project. No tuning will be
+done&lt;/li&gt;
+&lt;/ul&gt;
+&lt;/p&gt;
+&lt;/qt&gt;</string>
+ </property>
+ </widget>
+ <widget class="KLineEdit" row="0" column="1">
+ <property name="name">
+ <cstring>_projectName</cstring>
+ </property>
+ <property name="enabled">
+ <bool>true</bool>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>&lt;qt&gt;&lt;p&gt;&lt;b&gt;Project name&lt;/b&gt;&lt;br/&gt;
+The project name is an identification of a project for
+you. It is shown in the project configuration dialog
+as well as in the title of windows opened for the project.
+&lt;br/&gt;
+&lt;br/&gt;
+&lt;b&gt;Note:&lt;/b&gt; The project name cannot be later changed.&lt;
+&lt;/p&gt;&lt;/qt&gt;</string>
+ </property>
+ </widget>
+ <widget class="QLabel" row="1" column="0">
+ <property name="name">
+ <cstring>textLabel2</cstring>
+ </property>
+ <property name="text">
+ <string>Configuration &amp;file name:</string>
+ </property>
+ <property name="buddy" stdset="0">
+ <cstring>_projectFile</cstring>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>&lt;qt&gt;
+&lt;p&gt;&lt;b&gt;Configuration File Name&lt;/b&gt;&lt;br/&gt;
+The name of a file to store the configuration of the
+project.&lt;/p&gt;
+&lt;/qt&gt;</string>
+ </property>
+ </widget>
+ <widget class="QComboBox" row="3" column="1">
+ <item>
+ <property name="text">
+ <string>KDE</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>GNOME</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>Translation Project Robot</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>Other</string>
+ </property>
+ </item>
+ <property name="name">
+ <cstring>_projectType</cstring>
+ </property>
+ <property name="editable">
+ <bool>false</bool>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>&lt;qt&gt;
+&lt;p&gt;
+&lt;b&gt;Project Type&lt;/b&gt;
+The project type allows to tune the settings for the
+particular type of the well-known translation projects.
+For example, it sets up the validation tools,
+an accelerator marker and formatting of the header.
+&lt;/p&gt;
+&lt;p&gt;Currently known types:
+&lt;ul&gt;
+&lt;li&gt;&lt;b&gt;KDE&lt;/b&gt;: K Desktop Environment Internalization project&lt;/li&gt;
+&lt;li&gt;&lt;b&gt;GNOME&lt;/b&gt;: GNOME Translation project&lt;/li&gt;
+&lt;li&gt;&lt;b&gt;Translation Robot&lt;/b&gt;: Translation Project Robot&lt;/li&gt;
+&lt;li&gt;&lt;b&gt;Other&lt;/b&gt;: Other kind of project. No tuning will be
+done&lt;/li&gt;
+&lt;/ul&gt;
+&lt;/p&gt;
+&lt;/qt&gt;</string>
+ </property>
+ </widget>
+ </grid>
+ </widget>
+ </vbox>
+</widget>
+<tabstops>
+ <tabstop>_projectName</tabstop>
+ <tabstop>_projectFile</tabstop>
+ <tabstop>_projectLanguage</tabstop>
+ <tabstop>_projectType</tabstop>
+</tabstops>
+<includes>
+ <include location="local" impldecl="in implementation">projectwizardwidget.ui.h</include>
+</includes>
+<layoutdefaults spacing="6" margin="11"/>
+<layoutfunctions spacing="KDialog::spacingHint" margin="KDialog::marginHint"/>
+<includehints>
+ <includehint>kurlrequester.h</includehint>
+ <includehint>klineedit.h</includehint>
+ <includehint>kpushbutton.h</includehint>
+ <includehint>klineedit.h</includehint>
+</includehints>
+</UI>
diff --git a/kbabel/commonui/projectwizardwidget.ui.h b/kbabel/commonui/projectwizardwidget.ui.h
new file mode 100644
index 00000000..6f16e162
--- /dev/null
+++ b/kbabel/commonui/projectwizardwidget.ui.h
@@ -0,0 +1,40 @@
+/****************************************************************************
+ This file is part of KBabel
+
+ Copyright (C) 2004-2005 Stanislav Visnovsky
+ <visnovsky@kde.org>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the 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, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+ In addition, as a special exception, the copyright holders give
+ permission to link the code of this program with any edition of
+ the Qt library by Trolltech AS, Norway (or with modified versions
+ of Qt that use the same license as Qt), and distribute linked
+ combinations including the two. You must obey the GNU General
+ Public License in all respects for all of the code used other than
+ Qt. If you modify this file, you may extend this exception to
+ your version of the file, but you are not obligated to do so. If
+ you do not wish to do so, delete this exception statement from
+ your version.
+
+** 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.
+*****************************************************************************/
+
+#include <kdialog.h>
diff --git a/kbabel/commonui/projectwizardwidget2.ui b/kbabel/commonui/projectwizardwidget2.ui
new file mode 100644
index 00000000..05d21a20
--- /dev/null
+++ b/kbabel/commonui/projectwizardwidget2.ui
@@ -0,0 +1,157 @@
+<!DOCTYPE UI><UI version="3.3" stdsetdef="1">
+<class>ProjectStep2</class>
+<widget class="QWidget">
+ <property name="name">
+ <cstring>ProjectStep2</cstring>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>529</width>
+ <height>365</height>
+ </rect>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>&lt;qt&gt;&lt;p&gt;&lt;b&gt;Translation Files&lt;/b&gt;&lt;/p&gt;
+&lt;p&gt;Type in the folders which contain all your PO and POT files.
+The files and the folders in these folders will then be merged into one tree.&lt;/p&gt;&lt;/qt&gt;</string>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>textLabel2</cstring>
+ </property>
+ <property name="text">
+ <string>&lt;font size="+1"&gt;The Translation Files&lt;/font&gt;
+&lt;br/&gt;&lt;br/&gt;
+If the project contains more than one file to translate, it
+better to organize the files.
+
+KBabel distinguishes two kind of the translation files:
+
+&lt;ul&gt;
+&lt;li&gt;&lt;b&gt;Templates&lt;/b&gt;: the files to be translated&lt;/li&gt;
+&lt;li&gt;&lt;b&gt;Translated files&lt;/b&gt;: the files already translated (at least
+partially)&lt;/li&gt;
+&lt;/ul&gt;
+
+Choose the folders to store the files. If you
+leave the entries empty, the Catalog Manager
+will not work.</string>
+ </property>
+ </widget>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>layout5</cstring>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>textLabel4</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>5</hsizetype>
+ <vsizetype>0</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="text">
+ <string>&amp;Base folder of PO files:</string>
+ </property>
+ <property name="buddy" stdset="0">
+ <cstring>_poDirEdit</cstring>
+ </property>
+ </widget>
+ <widget class="KURLRequester">
+ <property name="name">
+ <cstring>_poDirEdit</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>5</hsizetype>
+ <vsizetype>0</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ </widget>
+ </vbox>
+ </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>textLabel3</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>5</hsizetype>
+ <vsizetype>0</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="text">
+ <string>Ba&amp;se folder of POT files:</string>
+ </property>
+ <property name="buddy" stdset="0">
+ <cstring>_potDirEdit</cstring>
+ </property>
+ </widget>
+ <widget class="KURLRequester">
+ <property name="name">
+ <cstring>_potDirEdit</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>5</hsizetype>
+ <vsizetype>0</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ </widget>
+ </vbox>
+ </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>31</width>
+ <height>100</height>
+ </size>
+ </property>
+ </spacer>
+ </vbox>
+</widget>
+<customwidgets>
+</customwidgets>
+<layoutdefaults spacing="6" margin="11"/>
+<includehints>
+ <includehint>kpushbutton.h</includehint>
+ <includehint>kpushbutton.h</includehint>
+</includehints>
+</UI>
diff --git a/kbabel/commonui/roughtransdlg.cpp b/kbabel/commonui/roughtransdlg.cpp
new file mode 100644
index 00000000..de321044
--- /dev/null
+++ b/kbabel/commonui/roughtransdlg.cpp
@@ -0,0 +1,762 @@
+/* ****************************************************************************
+ This file is part of KBabel
+
+ Copyright (C) 1999-2001 by Matthias Kiefer
+ <matthias.kiefer@gmx.de>
+ 2002-2003 by StanislavVsinovsky
+ <visnovsky@kde.org>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the 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, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+ In addition, as a special exception, the copyright holders give
+ permission to link the code of this program with any edition of
+ the Qt library by Trolltech AS, Norway (or with modified versions
+ of Qt that use the same license as Qt), and distribute linked
+ combinations including the two. You must obey the GNU General
+ Public License in all respects for all of the code used other than
+ Qt. If you modify this file, you may extend this exception to
+ your version of the file, but you are not obligated to do so. If
+ you do not wish to do so, delete this exception statement from
+ your version.
+
+**************************************************************************** */
+#include "catalog.h"
+#include "catalogsettings.h"
+#include "editcmd.h"
+#include "dictchooser.h"
+#include "kbabeldictbox.h"
+#include "regexpextractor.h"
+#include "roughtransdlg.h"
+
+#include <qmemarray.h>
+#include <qcheckbox.h>
+#include <qhbuttongroup.h>
+#include <qlabel.h>
+#include <qlayout.h>
+#include <qradiobutton.h>
+#include <qtimer.h>
+#include <qvgroupbox.h>
+#include <qvbox.h>
+#include <qwhatsthis.h>
+
+#include <kapplication.h>
+#include <kconfig.h>
+#include <kglobal.h>
+#include <klocale.h>
+#include <kmessagebox.h>
+#include <kprogress.h>
+
+
+#include <kdebug.h>
+
+using namespace KBabel;
+
+RoughTransDlg::RoughTransDlg(KBabelDictBox *dict, Catalog *cat
+ , QWidget *parent,const char *name)
+ : KDialogBase(parent,name,true
+ ,i18n("Caption of dialog","Rough Translation")
+ , User1|User2|User3|Close)
+ ,catalog(cat)
+ ,active(false)
+ ,stop(false)
+ ,cancel(false)
+ ,dictBox(dict)
+ ,exactTransCounter(0)
+ ,partTransCounter(0)
+ ,totalTried(0)
+{
+ setButtonBoxOrientation(Vertical);
+ setButtonText(User1,i18n("&Start"));
+ setButtonText(User2,i18n("S&top"));
+ setButtonText(User3,i18n("C&ancel"));
+
+ enableButton(User2,false);
+ enableButton(User3,false);
+
+ QWidget *mw = new QWidget(this);
+ setMainWidget(mw);
+
+ QVBoxLayout *mainLayout = new QVBoxLayout(mw);
+
+ configWidget = new QVBox(mw);
+ mainLayout->addWidget(configWidget);
+
+ QVGroupBox *box = new QVGroupBox(i18n("What to Translate"),configWidget);
+
+ QHButtonGroup *bBox = new QHButtonGroup(box);
+ bBox->setMargin(0);
+ bBox->setFrameStyle(QFrame::NoFrame);
+ whatBox = bBox;
+ untransButton = new QCheckBox(i18n("U&ntranslated entries"),bBox);
+ fuzzyButton = new QCheckBox(i18n("&Fuzzy entries"),bBox);
+ transButton = new QCheckBox(i18n("T&ranslated entries"),bBox);
+
+ connect(bBox,SIGNAL(clicked(int)),this,SLOT(msgButtonClicked(int)));
+
+ QWhatsThis::add(bBox,i18n("<qt><p><b>What entries to translate</b></p>"
+ "<p>Choose here, for which entries of the file KBabel "
+ "tries to find a translation. Changed entries are always "
+ "marked as fuzzy, no matter which option you choose.</p></qt>"));
+
+ box = new QVGroupBox(i18n("How to Translate"),configWidget);
+ bBox = new QHButtonGroup(box);
+ bBox->setFrameStyle(QFrame::NoFrame);
+ bBox->setMargin(0);
+
+ searchMatchButton = new QCheckBox(i18n("&Use dictionary settings")
+ ,bBox);
+
+ fuzzyMatchButton = new QCheckBox(i18n("Fu&zzy translation (slow)")
+ ,bBox);
+ singleWordButton = new QCheckBox(i18n("&Single word translation")
+ ,bBox);
+
+ QWhatsThis::add(bBox,i18n("<qt><p><b>How messages get translated</b></p>"
+ "<p>Here you can define if a message can only get translated "
+ "completely, if similar messages are acceptable or if KBabel "
+ "is supposed to try translating "
+ "the single words of a message if no translation of the "
+ "complete message or similar message was found.</p></qt>"));
+
+
+ box = new QVGroupBox(i18n("Options"),configWidget);
+
+ markFuzzyButton = new QCheckBox(i18n("&Mark changed entries as fuzzy"),box);
+ markFuzzyButton->setChecked(true);
+ QWhatsThis::add(markFuzzyButton,
+ i18n("<qt><p><b>Mark changed entries as fuzzy</b></p>"
+ "<p>When a translation for a message is found, the entry "
+ "will be marked <b>fuzzy</b> by default. This is because the "
+ "translation is just guessed by KBabel and you should always "
+ "check the results carefully. Deactivate this option only if "
+ "you know what you are doing.</p></qt>"));
+
+
+ connect(markFuzzyButton, SIGNAL(toggled(bool))
+ , this, SLOT(fuzzyButtonToggled(bool)));
+
+ kdeButton = new QCheckBox(i18n("Initialize &KDE-specific entries"),box);
+ kdeButton->setChecked(true);
+ QWhatsThis::add(kdeButton,
+ i18n("<qt><p><b>Initialize KDE-specific entries</b></p>"
+ "<p>Initialize \"Comment=\" and \"Name=\" entries "
+ "if a translation is not found. Also, \"NAME OF TRANSLATORS\" "
+ "and \"EMAIL OF TRANSLATORS\" is filled with identity settings.</p></qt>"));
+
+ QVGroupBox *dBox = new QVGroupBox(i18n("Dictionaries"),configWidget);
+ configWidget->setStretchFactor(dBox,1);
+
+ QPtrList<ModuleInfo> moduleList = dict->moduleInfos();
+
+ KConfig *config = KGlobal::config();
+ KConfigGroupSaver gs(config,"RoughTranslation");
+ QStringList selectedList=config->readListEntry("Selected");
+ if(selectedList.isEmpty())
+ {
+ int a = dict->activeModule();
+ ModuleInfo *mi = moduleList.at(a);
+ if(mi)
+ {
+ selectedList.append(mi->id);
+ }
+ }
+ dictChooser = new DictChooser(dict,selectedList,dBox,"dictChooser");
+
+ QWhatsThis::add(dictChooser,i18n("<qt><p><b>Dictionaries</b></p>"
+ "<p>Choose here, which dictionaries have to be used for "
+ "finding a translation. If you select more than one "
+ "dictionary, they are used in the same order as they "
+ "are displayed in the list.</p>"
+ "<p>The <b>Configure</b> button allows you to temporarily "
+ "configure selected dictionary. The original settings "
+ "will be restored after closing the dialog.</p></qt>"));
+
+ QLabel* label = new QLabel( i18n("Messages:"), mw );
+ progressbar = new KProgress(mw,"progressbar");
+ progressbar->setTextEnabled(true);
+ progressbar->setFormat("%v/%m (%p%)");
+ QHBoxLayout* pblayout= new QHBoxLayout(mainLayout);
+ pblayout->add(label);
+ pblayout->add(progressbar);
+
+ transButton->setChecked(config->readBoolEntry("Translated",false));
+ untransButton->setChecked(config->readBoolEntry("Untranslated",true));
+ fuzzyButton->setChecked(config->readBoolEntry("Fuzzies",false));
+
+ bool flag = config->readBoolEntry("fuzzyMatch",true);
+ fuzzyMatchButton->setChecked(flag);
+
+ flag = config->readBoolEntry("searchMatch",true);
+ searchMatchButton->setChecked(flag);
+
+ flag = config->readBoolEntry("singleWord",true);
+ singleWordButton->setChecked(flag);
+
+ flag = config->readBoolEntry("kdeSpecific",true);
+ kdeButton->setChecked(flag);
+
+ msgButtonClicked(0);
+}
+
+RoughTransDlg::~RoughTransDlg()
+{
+ KConfig *config=KGlobal::config();
+ KConfigGroupSaver gs(config,"RoughTranslation");
+ config->writeEntry("Selected",dictChooser->selectedDicts());
+
+ bool flag=transButton->isChecked();
+ config->writeEntry("Translated",flag);
+ flag=untransButton->isChecked();
+ config->writeEntry("Untranslated",flag);
+ flag=fuzzyButton->isChecked();
+ config->writeEntry("Fuzzies",flag);
+ flag=singleWordButton->isChecked();
+ config->writeEntry("singleWord",flag);
+ flag=fuzzyMatchButton->isChecked();
+ config->writeEntry("fuzzyMatch",flag);
+ flag=searchMatchButton->isChecked();
+ config->writeEntry("searchMatch",flag);
+ flag=kdeButton->isChecked();
+ config->writeEntry("kdeSpecific",flag);
+
+}
+
+void RoughTransDlg::slotUser1()
+{
+ configWidget->setEnabled(false);
+ enableButton(User1,false);
+ enableButton(Close,false);
+ enableButton(User2,true);
+ enableButton(User3,true);
+
+ active=true;
+ stop=false;
+ cancel=false;
+
+ exactTransCounter=0;
+ partTransCounter=0;
+ totalTried=0;
+
+ QTimer::singleShot(0,this, SLOT(translate()));
+}
+
+void RoughTransDlg::translate()
+{
+ bool markFuzzy = markFuzzyButton->isChecked();
+ bool translated = transButton->isChecked();
+ bool untranslated = untransButton->isChecked();
+ bool fuzzies = fuzzyButton->isChecked();
+ bool kdeSpecific=kdeButton->isChecked();
+
+ int total=catalog->numberOfEntries();
+ progressbar->setTotalSteps(total);
+
+ QStringList dictList = dictChooser->selectedDicts();
+
+ catalog->applyBeginCommand(0,Msgstr,0);
+
+ bool singleWords=singleWordButton->isChecked();
+ bool fuzzyMatch=fuzzyMatchButton->isChecked();
+ bool searchMatch=searchMatchButton->isChecked();
+ QRegExp contextReg=catalog->miscSettings().contextInfo;
+ QChar accelMarker=catalog->miscSettings().accelMarker;
+ QRegExp endPunctReg("[\\.?!: ]+$");
+
+
+ for(int i = 0; i < total; i++)
+ {
+ progressbar->setProgress(i+1);
+ kapp->processEvents(100);
+
+ if(stop || cancel) break;
+
+ // FIXME: should care about plural forms
+ QString msg=catalog->msgid(i,true).first();
+ QString translation;
+
+ // this is KDE specific:
+ if( kdeSpecific )
+ {
+ if( catalog->pluralForm(i) == NoPluralForm )
+ {
+ QString origTrans = catalog->msgstr(i).first();
+ if(msg.find("_: NAME OF TRANSLATORS\\n")==0)
+ {
+ QString authorName;
+ if( !catalog->identitySettings().authorLocalizedName.isEmpty() )
+ authorName = catalog->identitySettings().authorLocalizedName;
+ else // fallback to non-localized name
+ if( !catalog->identitySettings().authorName.isEmpty() )
+ authorName = catalog->identitySettings().authorName;
+ else continue; // there is no name to be inserted
+
+ if( !QStringList::split(',', origTrans).contains(authorName) )
+ {
+ if(origTrans.isEmpty() ) translation=authorName;
+ else translation+=origTrans+","+authorName;
+ }
+ }
+ else if(msg.find("_: EMAIL OF TRANSLATORS\\n")==0)
+ {
+ // skip, if email is not specified in settings
+ if( catalog->identitySettings().authorEmail.isEmpty() ) continue;
+
+ if( !QStringList::split(',', origTrans).contains(catalog->identitySettings().authorEmail) )
+ {
+ if(origTrans.isEmpty() ) translation=catalog->identitySettings().authorEmail;
+ else translation=origTrans+","+catalog->identitySettings().authorEmail;
+ }
+ }
+ else if (msg.find("ROLES_OF_TRANSLATORS") == 0)
+ {
+ QString temp = "<othercredit role=\\\"translator\\\">\n<firstname></firstname>"
+ "<surname></surname>\n<affiliation><address><email>" +
+ catalog->identitySettings( ).authorEmail+"</email></address>\n"
+ "</affiliation><contrib></contrib></othercredit>";
+ if (origTrans.isEmpty( ))
+ translation = temp;
+ else if (origTrans.find(catalog->identitySettings( ).authorEmail) < 0)
+ translation = origTrans + "\n" + temp;
+ }
+ else if (msg.find("CREDIT_FOR_TRANSLATORS") == 0)
+ {
+ QString authorName;
+ if (!catalog->identitySettings( ).authorLocalizedName.isEmpty( ))
+ authorName = catalog->identitySettings( ).authorLocalizedName;
+ else if (!catalog->identitySettings( ).authorName.isEmpty( ))
+ authorName = catalog->identitySettings( ).authorName;
+ QString temp = "<para>" + authorName + "\n" + "<email>" +
+ catalog->identitySettings( ).authorEmail + "</email></para>";
+ if (origTrans.isEmpty( ))
+ translation = temp;
+ else if (origTrans.find(authorName) < 0 &&
+ origTrans.find(catalog->identitySettings( ).authorEmail) < 0)
+ translation = origTrans + "\n" + temp;
+ }
+ }
+ }
+ else // not kdeSpecific
+ {
+ // skip KDE specific texts
+ if( msg.find("_: EMAIL OF TRANSLATORS\\n")==0 || msg.find("_: NAME OF TRANSLATORS\\n")==0 ||
+ msg.find("ROLES_OF_TRANSLATORS")==0 || msg.find("CREDIT_FOR_TRANSLATORS")==0)
+ continue;
+ }
+
+ if( translation.isEmpty() ) // KDE-specific translation didn't work
+ {
+ if( !untranslated && catalog->isUntranslated(i) ) continue;
+ if( !translated && !catalog->isUntranslated(i) && !catalog->isFuzzy(i) ) continue;
+ if( !fuzzies && catalog->isFuzzy(i) ) continue;
+ }
+
+ totalTried++;
+
+ if(msg.contains(contextReg))
+ {
+ msg.replace(contextReg,"");
+ }
+
+ // try exact translation
+ QStringList::Iterator dit = dictList.begin();
+ while(translation.isEmpty() && dit != dictList.end())
+ {
+ dictBox->setActiveModule(*dit);
+ translation = dictBox->translate(msg);
+
+ ++dit;
+ }
+
+ if(!translation.isEmpty())
+ {
+ exactTransCounter++;
+ }
+
+ // try search settings translation
+ else if (searchMatch) {
+ QString tr;
+ int score, best_score = 0;
+ dit = dictList.begin();
+ while(dit != dictList.end())
+ {
+ dictBox->setActiveModule(*dit);
+ tr = dictBox->searchTranslation(msg,score);
+ kdDebug() << "Found: " << tr << ", score " << score << endl;
+
+ if (score > best_score) {
+ kdDebug() << "Best score" << endl;
+ translation = tr;
+ best_score = score;
+ }
+
+ ++dit;
+ }
+
+ if(!translation.isEmpty())
+ {
+ partTransCounter++;
+ }
+ }
+
+ // try fuzzy translation
+ else if (fuzzyMatch) {
+ QString tr;
+ int score, best_score = 0;
+ dit = dictList.begin();
+ while(dit != dictList.end())
+ {
+ dictBox->setActiveModule(*dit);
+ tr = dictBox->fuzzyTranslation(msg,score);
+
+ if (score > best_score) {
+ translation = tr;
+ best_score = score;
+ }
+
+ ++dit;
+ }
+
+ if(!translation.isEmpty())
+ {
+ partTransCounter++;
+ }
+ }
+
+ kdDebug() << "Best translation so far: " << translation << endl;
+
+ // try single word translation
+ if(translation.isEmpty() && singleWords)
+ {
+ QStringList wordList;
+ QChar accel;
+ QString endingPunctuation;
+ int pos = msg.findRev(endPunctReg);
+ if(pos >= 0)
+ {
+ endingPunctuation = msg.right(msg.length()-pos);
+ }
+
+ msg=msg.simplifyWhiteSpace();
+ msg=msg.stripWhiteSpace();
+
+
+ RegExpExtractor te(catalog->tagSettings().tagExpressions);
+ te.setString(msg);
+ msg=te.matchesReplaced(" KBABELTAG ");
+
+ QString word;
+ int length = msg.length();
+ QRegExp digitReg("^[0-9]*$");
+ for(int index=0; index < length; index++)
+ {
+ QChar c=msg[index];
+
+ if(c==accelMarker)
+ {
+ index++;
+ if(index < length)
+ {
+ if(msg[index].isLetterOrNumber())
+ {
+ word+=msg[index];
+ accel=msg[index];
+ }
+ else if(!word.isEmpty() )
+ {
+ if(!word.contains(digitReg))
+ wordList.append(word);
+
+ word=QString::null;
+ }
+ }
+ else if(!word.isEmpty())
+ {
+ if(!word.contains(digitReg))
+ wordList.append(word);
+
+ word=QString::null;
+ }
+
+ }
+ else if(c.isLetterOrNumber())
+ {
+ word+=c;
+ }
+ else if(c == '\\')
+ {
+ if(index < length-2)
+ {
+ if(msg[index+1]=='n' && msg[index+2].isSpace())
+ {
+ if(!word.isEmpty() && !word.contains(digitReg))
+ wordList.append(word);
+
+ word=QString::null;
+
+ wordList.append("\\n\n");
+ index+=2;
+ }
+ else if(!word.isEmpty() )
+ {
+ if(!word.contains(digitReg))
+ wordList.append(word);
+
+ word=QString::null;
+ }
+ }
+ else if(!word.isEmpty())
+ {
+ if(!word.contains(digitReg))
+ wordList.append(word);
+
+ word=QString::null;
+ }
+ }
+ else if(!word.isEmpty())
+ {
+ if(!word.contains(digitReg)) {
+ wordList.append(word);
+ }
+
+ word=QString::null;
+ }
+ }
+
+ // handle the last word as well
+ if( !word.isEmpty() ) wordList.append(word);
+
+ dit = dictList.begin();
+ int wordCounter=0;
+ while(wordCounter==0 && dit != dictList.end())
+ {
+ dictBox->setActiveModule(*dit);
+
+ for(QStringList::Iterator it=wordList.begin();
+ it!=wordList.end(); ++it)
+ {
+ if( (*it)=="\\n\n" )
+ {
+ translation+="\\n\n";
+ }
+ else if( (*it)=="KBABELTAG" )
+ {
+ translation+=te.nextMatch();
+ }
+ else
+ {
+ QString trans = dictBox->translate(*it);
+
+ if(!trans.isEmpty())
+ {
+ wordCounter++;
+ if(!translation.isEmpty())
+ {
+ translation += ' ';
+ }
+ translation += trans;
+ }
+ }
+ }
+
+ if(wordCounter==0)
+ translation=QString::null;
+
+ ++dit;
+ }
+
+ if(!translation.isEmpty())
+ {
+ partTransCounter++;
+ // try to set the correct keyboard accelerator
+ if(!accel.isNull())
+ {
+ int index = translation.find(accel,0,false);
+ if(index >= 0)
+ {
+ translation.insert(index,accelMarker);
+ }
+ }
+
+ translation+=endingPunctuation;
+ }
+ }
+
+ // this is KDE specific:
+ if(kdeSpecific && translation.isEmpty())
+ {
+ if( msg.startsWith("Name=") ) {
+ translation="Name=";
+ partTransCounter++;
+ }
+ if( msg.startsWith("Comment=") ) {
+ translation="Comment=";
+ partTransCounter++;
+ }
+ }
+
+ if(!translation.isEmpty())
+ {
+ if(!catalog->isUntranslated(i))
+ {
+ QStringList msgs = catalog->msgstr(i);
+ uint counter = 0;
+ for( QStringList::Iterator it = msgs.begin() ; it != msgs.end() ; ++it)
+ {
+ DelTextCmd* delCmd = new DelTextCmd(0
+ ,(*it),counter++);
+ delCmd->setPart(Msgstr);
+ delCmd->setIndex(i);
+ catalog->applyEditCommand(delCmd,0);
+ }
+ }
+
+ for( int count=0; count < catalog->numberOfPluralForms(i) ; count++ )
+ {
+ InsTextCmd* insCmd = new InsTextCmd(0,translation,count);
+ insCmd->setPart(Msgstr);
+ insCmd->setIndex(i);
+ catalog->applyEditCommand(insCmd,0);
+ }
+
+ if(markFuzzy)
+ {
+ catalog->setFuzzy(i,true);
+ }
+ }
+ }
+
+ catalog->applyEndCommand(0,Msgstr,0);
+
+ if(stop || cancel)
+ {
+ if(cancel)
+ {
+ catalog->undo();
+ }
+ else
+ {
+ msgButtonClicked(0);
+ }
+ progressbar->setProgress(0);
+ configWidget->setEnabled(true);
+ active = false;
+
+ enableButton(User1,true);
+ enableButton(Close,true);
+ enableButton(User2,false);
+ enableButton(User3,false);
+
+ return;
+ }
+
+ showStatistics();
+}
+
+void RoughTransDlg::showStatistics()
+{
+ int nothing=totalTried-partTransCounter-exactTransCounter;
+ KLocale *locale = KGlobal::locale();
+ QString statMsg = i18n("Result of the translation:\n"
+ "Edited entries: %1\n"
+ "Exact translations: %2 (%3%)\n"
+ "Approximate translations: %4 (%5%)\n"
+ "Nothing found: %6 (%7%)")
+ .arg( locale->formatNumber(totalTried,0) )
+ .arg( locale->formatNumber(exactTransCounter,0) )
+ .arg( locale->formatNumber( ((double)(10000*exactTransCounter/QMAX(totalTried,1)))/100) )
+ .arg( locale->formatNumber(partTransCounter,0) )
+ .arg( locale->formatNumber(((double)(10000*partTransCounter/QMAX(totalTried,1)))/100) )
+ .arg( locale->formatNumber(nothing,0) )
+ .arg( locale->formatNumber(((double)(10000*nothing/QMAX(totalTried,1)))/100) );
+
+ KMessageBox::information(this, statMsg
+ , i18n("Rough Translation Statistics"));
+
+ dictChooser->restoreConfig();
+ accept();
+}
+
+void RoughTransDlg::slotClose()
+{
+ if(active)
+ {
+ cancel = true;
+ return;
+ }
+ else
+ {
+ dictChooser->restoreConfig();
+ accept();
+ }
+}
+
+void RoughTransDlg::slotUser2()
+{
+ stop=true;
+}
+
+void RoughTransDlg::slotUser3()
+{
+ cancel=true;
+}
+
+void RoughTransDlg::msgButtonClicked(int id)
+{
+ if(!transButton->isChecked() && !untransButton->isChecked()
+ && !fuzzyButton->isChecked())
+ {
+ QButton *button = whatBox->find(id);
+ if(button == transButton)
+ {
+ transButton->setChecked(true);
+ }
+ else if(button == untransButton)
+ {
+ untransButton->setChecked(true);
+ }
+ else if(button == fuzzyButton)
+ {
+ fuzzyButton->setChecked(true);
+ }
+ }
+
+ progressbar->setTotalSteps(catalog->numberOfEntries());
+
+ enableButton(User1,catalog->numberOfEntries());
+}
+
+void RoughTransDlg::fuzzyButtonToggled(bool on)
+{
+ if(!on)
+ {
+ QString msg=i18n("<qt><p>"
+ "When a translation for a message is found, the entry "
+ "will be marked <b>fuzzy</b> by default. This is because the "
+ "translation is just guessed by KBabel and you should always "
+ "check the results carefully. Deactivate this option only if "
+ "you know what you are doing.</p></qt>");
+
+ KMessageBox::information(this, msg, QString::null,"MarkFuzzyWarningInRoughTransDlg");
+ }
+}
+
+void RoughTransDlg::statistics(int &total, int& exact, int& part) const
+{
+ total = totalTried;
+ exact = exactTransCounter;
+ part = partTransCounter;
+}
+
+#include "roughtransdlg.moc"
diff --git a/kbabel/commonui/roughtransdlg.h b/kbabel/commonui/roughtransdlg.h
new file mode 100644
index 00000000..e51378a5
--- /dev/null
+++ b/kbabel/commonui/roughtransdlg.h
@@ -0,0 +1,110 @@
+/* ****************************************************************************
+ This file is part of KBabel
+
+ Copyright (C) 1999-2001 by Matthias Kiefer
+ <matthias.kiefer@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.
+
+ 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, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+ In addition, as a special exception, the copyright holders give
+ permission to link the code of this program with any edition of
+ the Qt library by Trolltech AS, Norway (or with modified versions
+ of Qt that use the same license as Qt), and distribute linked
+ combinations including the two. You must obey the GNU General
+ Public License in all respects for all of the code used other than
+ Qt. If you modify this file, you may extend this exception to
+ your version of the file, but you are not obligated to do so. If
+ you do not wish to do so, delete this exception statement from
+ your version.
+
+**************************************************************************** */
+#ifndef ROUGHTRANSDLG_H
+#define ROUGHTRANSDLG_H
+
+#include <kdialogbase.h>
+
+
+class KBabelDictBox;
+class DictChooser;
+
+namespace KBabel
+{
+ class Catalog;
+}
+
+class KProgress;
+class QCheckBox;
+class QHButtonGroup;
+class QRadioButton;
+class QVBox;
+
+class KDE_EXPORT RoughTransDlg : public KDialogBase
+{
+ Q_OBJECT
+
+public:
+ RoughTransDlg(KBabelDictBox* dictBox, KBabel::Catalog* catalog, QWidget *parent
+ , const char *name=0);
+ ~RoughTransDlg();
+
+ void statistics(int &total, int& exactTranslated
+ , int& partlyTranslated) const;
+
+protected slots:
+ void slotUser1();
+ void slotUser2();
+ void slotUser3();
+
+ void slotClose();
+
+ void fuzzyButtonToggled(bool);
+
+ virtual void msgButtonClicked(int);
+ virtual void translate();
+ virtual void showStatistics();
+
+protected:
+ KBabel::Catalog *catalog;
+
+ bool active;
+ bool stop;
+ bool cancel;
+
+ KProgress *progressbar;
+private:
+ KBabelDictBox *dictBox;
+
+ DictChooser *dictChooser;
+ QVBox *configWidget;
+
+
+ QHButtonGroup *whatBox;
+ QCheckBox *transButton;
+ QCheckBox *untransButton;
+ QCheckBox *fuzzyButton;
+
+ QCheckBox *singleWordButton;
+ QCheckBox *fuzzyMatchButton;
+ QCheckBox *searchMatchButton;
+
+ QCheckBox *markFuzzyButton;
+ QCheckBox *kdeButton;
+
+ int exactTransCounter;
+ int partTransCounter;
+ int totalTried;
+};
+
+#endif // ROUGHTRANSDLG_H
diff --git a/kbabel/commonui/toolaction.cpp b/kbabel/commonui/toolaction.cpp
new file mode 100644
index 00000000..14589996
--- /dev/null
+++ b/kbabel/commonui/toolaction.cpp
@@ -0,0 +1,108 @@
+/* This file is part of KBabel
+ Copyright (C) 2002 Stanislav Visnovsky <visnovsky@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.
+
+ In addition, as a special exception, the copyright holders give
+ permission to link the code of this program with any edition of
+ the Qt library by Trolltech AS, Norway (or with modified versions
+ of Qt that use the same license as Qt), and distribute linked
+ combinations including the two. You must obey the GNU General
+ Public License in all respects for all of the code used other than
+ Qt. If you modify this file, you may extend this exception to
+ your version of the file, but you are not obligated to do so. If
+ you do not wish to do so, delete this exception statement from
+ your version.
+
+*/
+
+#include "toolaction.h"
+
+#include <kdebug.h>
+
+ToolAction::ToolAction( const QString & text, const KShortcut& cut, const KDataToolInfo & info, const QString & command,
+ QObject * parent, const char * name )
+ : KAction( text, info.iconName() == "unknown" ? QString::null : info.iconName(), cut, parent, name ),
+ m_command( command ),
+ m_info( info )
+{
+}
+
+void ToolAction::slotActivated()
+{
+ emit toolActivated( m_info, m_command );
+}
+
+QPtrList<KAction> ToolAction::dataToolActionList( const QValueList<KDataToolInfo> & tools, const QObject *receiver, const char* slot, const QStringList& command, bool excludeCommand, KActionCollection* parent, const QString& namePrefix )
+{
+ QPtrList<KAction> actionList;
+ if ( tools.isEmpty() )
+ return actionList;
+
+ QValueList<KDataToolInfo>::ConstIterator entry = tools.begin();
+ for( ; entry != tools.end(); ++entry )
+ {
+ QStringList userCommands = (*entry).userCommands();
+ QStringList commands = (*entry).commands();
+ QStringList shortcuts = (*entry).service()->property("Shortcuts").toStringList();
+ Q_ASSERT(!commands.isEmpty());
+ if ( commands.count() != userCommands.count() )
+ kdWarning() << "KDataTool desktop file error (" << (*entry).service()
+ << "). " << commands.count() << " commands and "
+ << userCommands.count() << " descriptions." << endl;
+
+ QStringList::ConstIterator uit = userCommands.begin();
+ QStringList::ConstIterator cit = commands.begin();
+ QStringList::ConstIterator sit = shortcuts.begin();
+ for (; uit != userCommands.end() && cit != commands.end(); ++uit, ++cit)
+ {
+ if( !excludeCommand == command.contains(*cit) )
+ {
+ QString sc=*sit;
+
+ ToolAction * action = new ToolAction( *uit, (sc.isEmpty()?QString::null:sc), *entry, *cit
+ , parent
+ , QString(namePrefix+(*entry).service()->library()+"_"+(*cit)).utf8() );
+ connect( action, SIGNAL( toolActivated( const KDataToolInfo &, const QString & ) ),
+ receiver, slot );
+
+ actionList.append( action );
+ }
+ if( sit != shortcuts.end() ) sit++;
+ }
+ }
+
+ return actionList;
+}
+
+QValueList<KDataToolInfo> ToolAction::validationTools()
+{
+ QValueList<KDataToolInfo> result;
+
+ QValueList<KDataToolInfo> tools = KDataToolInfo::query("CatalogItem", "application/x-kbabel-catalogitem", KGlobal::instance());
+
+ for( QValueList<KDataToolInfo>::ConstIterator entry = tools.begin(); entry != tools.end(); ++entry )
+ {
+ if( (*entry).commands().contains("validate") )
+ {
+ result.append( *entry );
+ }
+ }
+
+ return result;
+}
+
+#include "toolaction.moc"
diff --git a/kbabel/commonui/toolaction.h b/kbabel/commonui/toolaction.h
new file mode 100644
index 00000000..11e32c89
--- /dev/null
+++ b/kbabel/commonui/toolaction.h
@@ -0,0 +1,72 @@
+/* This file is part of KBabel
+ Copyright (C) 2002 Stanislav Visnovsky <visnovsky@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.
+
+ In addition, as a special exception, the copyright holders give
+ permission to link the code of this program with any edition of
+ the Qt library by Trolltech AS, Norway (or with modified versions
+ of Qt that use the same license as Qt), and distribute linked
+ combinations including the two. You must obey the GNU General
+ Public License in all respects for all of the code used other than
+ Qt. If you modify this file, you may extend this exception to
+ your version of the file, but you are not obligated to do so. If
+ you do not wish to do so, delete this exception statement from
+ your version.
+
+*/
+
+#ifndef TOOLACTION_H
+#define TOOLACTION_H
+
+#include <qobject.h>
+#include <kaction.h>
+#include <kdatatool.h>
+
+class KShortcut;
+class KActionCollection;
+
+class KDE_EXPORT ToolAction : public KAction
+{
+ Q_OBJECT
+public:
+ ToolAction( const QString & text, const KShortcut& cut, const KDataToolInfo & info, const QString & command, QObject * parent = 0, const char * name = 0);
+
+ /**
+ * return the list of KActions created for a list of tools. @ref command
+ * allows to specify rescriction of commands, for which the list should
+ * or shouldn't be created according to the @ref excludeCommand flag.
+ */
+ static QPtrList<KAction> dataToolActionList( const QValueList<KDataToolInfo> & tools, const QObject *receiver, const char* slot, const QStringList& command, bool excludeCommand, KActionCollection* parent=0, const QString& namePrefix=QString::null );
+
+ /**
+ * returns information about all available validation tools (KDataTools with support for CatalogItem
+ * and the "validate" command.
+ */
+ static QValueList<KDataToolInfo> validationTools();
+
+signals:
+ void toolActivated( const KDataToolInfo & info, const QString & command );
+
+protected:
+ virtual void slotActivated();
+
+private:
+ QString m_command;
+ KDataToolInfo m_info;
+};
+
+#endif
diff --git a/kbabel/commonui/toolselectionwidget.cpp b/kbabel/commonui/toolselectionwidget.cpp
new file mode 100644
index 00000000..8657657d
--- /dev/null
+++ b/kbabel/commonui/toolselectionwidget.cpp
@@ -0,0 +1,105 @@
+/* This file is part of KBabel
+ Copyright (C) 2002 Stanislav Visnovsky <visnovsky@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.
+
+ In addition, as a special exception, the copyright holders give
+ permission to link the code of this program with any edition of
+ the Qt library by Trolltech AS, Norway (or with modified versions
+ of Qt that use the same license as Qt), and distribute linked
+ combinations including the two. You must obey the GNU General
+ Public License in all respects for all of the code used other than
+ Qt. If you modify this file, you may extend this exception to
+ your version of the file, but you are not obligated to do so. If
+ you do not wish to do so, delete this exception statement from
+ your version.
+
+*/
+
+#include "toolselectionwidget.h"
+
+#include <kdatatool.h>
+#include <kdebug.h>
+
+#include <qlistbox.h>
+
+ToolSelectionWidget::ToolSelectionWidget( QWidget * parent, const char * name )
+ : KActionSelector( parent, name )
+{
+}
+
+void ToolSelectionWidget::loadTools( const QStringList &commands,
+ const QValueList<KDataToolInfo>& tools)
+{
+ if ( tools.isEmpty() ) return;
+
+ _allTools = tools;
+
+ QValueList<KDataToolInfo>::ConstIterator entry = tools.begin();
+ for( ; entry != tools.end(); ++entry )
+ {
+ QStringList userCommands = (*entry).userCommands();
+ QStringList toolCommands = (*entry).commands();
+ Q_ASSERT(!toolCommands.isEmpty());
+ if ( toolCommands.count() != userCommands.count() )
+ kdWarning() << "KDataTool desktop file error (" << (*entry).service()
+ << "). " << toolCommands.count() << " commands and "
+ << userCommands.count() << " descriptions." << endl;
+
+ QStringList::ConstIterator uit = userCommands.begin();
+ QStringList::ConstIterator cit = toolCommands.begin();
+ for (; uit != userCommands.end() && cit != toolCommands.end(); ++uit, ++cit )
+ {
+ if( commands.contains(*cit) )
+ {
+ availableListBox()->insertItem( *uit );
+ }
+ }
+ }
+}
+
+void ToolSelectionWidget::setSelectedTools( const QStringList& tools )
+{
+ availableListBox()->clear();
+ selectedListBox()->clear();
+ QValueList<KDataToolInfo>::ConstIterator entry = _allTools.begin();
+ for( ; entry != _allTools.end(); ++entry )
+ {
+ QString uic=*(*entry).userCommands().at((*entry).commands().findIndex("validate"));
+ if( tools.contains((*entry).service()->library()) )
+ selectedListBox()->insertItem( uic );
+ else
+ availableListBox()->insertItem( uic );
+ }
+}
+
+QStringList ToolSelectionWidget::selectedTools()
+{
+ QStringList usedNames;
+ for( uint i=0; i<selectedListBox()->count() ; i++ )
+ usedNames += selectedListBox()->text(i);
+
+ QStringList result;
+ QValueList<KDataToolInfo>::ConstIterator entry = _allTools.begin();
+ for( ; entry != _allTools.end(); ++entry )
+ {
+ if( usedNames.contains(*((*entry).userCommands().at((*entry).commands().findIndex("validate")))) )
+ result += (*entry).service()->library();
+ }
+ return result;
+}
+
+#include "toolselectionwidget.moc"
diff --git a/kbabel/commonui/toolselectionwidget.h b/kbabel/commonui/toolselectionwidget.h
new file mode 100644
index 00000000..5bad520b
--- /dev/null
+++ b/kbabel/commonui/toolselectionwidget.h
@@ -0,0 +1,57 @@
+/* This file is part of KBabel
+ Copyright (C) 2002 Stanislav Visnovsky <visnovsky@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.
+
+ In addition, as a special exception, the copyright holders give
+ permission to link the code of this program with any edition of
+ the Qt library by Trolltech AS, Norway (or with modified versions
+ of Qt that use the same license as Qt), and distribute linked
+ combinations including the two. You must obey the GNU General
+ Public License in all respects for all of the code used other than
+ Qt. If you modify this file, you may extend this exception to
+ your version of the file, but you are not obligated to do so. If
+ you do not wish to do so, delete this exception statement from
+ your version.
+
+*/
+
+#ifndef TOOLSELECTIONWIDGET_H
+#define TOOLSELECTIONWIDGET_H
+
+#include "kactionselector.h"
+#include <kdemacros.h>
+
+class KDataToolInfo;
+
+class KDE_EXPORT ToolSelectionWidget : public KActionSelector
+{
+ Q_OBJECT
+public:
+ ToolSelectionWidget(QWidget* parent=0, const char* name=0 );
+
+ QStringList selectedTools();
+
+ void loadTools (const QStringList& commands, const QValueList<KDataToolInfo> & tools);
+
+public slots:
+ void setSelectedTools( const QStringList& tools );
+
+private:
+ QValueList<KDataToolInfo> _allTools;
+};
+
+#endif
diff --git a/kbabel/configure.in.in b/kbabel/configure.in.in
new file mode 100644
index 00000000..88312d46
--- /dev/null
+++ b/kbabel/configure.in.in
@@ -0,0 +1,12 @@
+AM_PROG_LEX
+
+AC_LANG_SAVE
+AC_LANG_CPLUSPLUS
+AC_CHECK_HEADER(FlexLexer.h,
+ [kde_have_flex=yes],
+ [kde_have_flex=no])
+
+if test "$kde_have_flex" = "no"; then
+ DO_NOT_COMPILE="$DO_NOT_COMPILE kbabel"
+fi
+AC_LANG_RESTORE
diff --git a/kbabel/datatools/Makefile.am b/kbabel/datatools/Makefile.am
new file mode 100644
index 00000000..07600eac
--- /dev/null
+++ b/kbabel/datatools/Makefile.am
@@ -0,0 +1,39 @@
+## Makefile.am for kbabeldict
+
+# this has all of the subdirectories that make will recurse into. if
+# there are none, comment this out
+SUBDIRS = arguments accelerators context equations pluralforms xml \
+not-translated whitespace length setfuzzy punctuation regexp
+
+#pkgincludedir = $(includedir)/kbabel
+
+# this is the program that gets installed. it's name is used for all
+# of the other Makefile.am variables
+#lib_LTLIBRARIES = libkbabeltools.la
+
+# set the include path for X, qt and KDE
+INCLUDES = $(all_includes)
+
+
+# which sources should be compiled for kbabeldict
+#libkbabeltools_la_SOURCES = toolaction.cpp kactionselector.cpp toolselectionwidget.cpp
+#libkbabeltools_la_LIBADD = $(LIB_KDECORE) $(LIB_KIO)
+#libkbabeltools_la_LDFLAGS = $(all_libraries) -module -version-info 1:0:0 -no-undefined
+
+# these are the headers for your project
+#noinst_HEADERS = kactionselector.h toolselectionwidget.h
+#pkginclude_HEADERS = toolaction.h
+
+# let automoc handle all of the meta source files (moc)
+METASOURCES = AUTO
+
+# KDE_OPTIONS = nofinal
+#rcdir = $(kde_datadir)/kbabel
+#rc_DATA = kbabelui.rc
+
+#api:
+# mkdir -p API && kdoc -d API -u $$PWD/API -p -lkdeui -lkdecore -lqt -ldcop *.h
+
+#distclean-local:
+# rm -r -f API
+
diff --git a/kbabel/datatools/accelerators/Makefile.am b/kbabel/datatools/accelerators/Makefile.am
new file mode 100644
index 00000000..f204e78a
--- /dev/null
+++ b/kbabel/datatools/accelerators/Makefile.am
@@ -0,0 +1,19 @@
+
+INCLUDES = -I$(srcdir)/../../common -I../../common $(all_includes)
+kbabel_accelstool_la_LIBADD = $(LIB_KIO) ../../common/libkbabelcommon.la
+
+####### Files
+
+kde_module_LTLIBRARIES = kbabel_accelstool.la
+
+kbabel_accelstool_la_SOURCES = main.cc
+
+kbabel_accelstool_la_LDFLAGS = $(all_libraries) -avoid-version -module -no-undefined
+
+noinst_HEADERS = main.h
+
+kbabel_accelstool_la_METASOURCES = AUTO
+
+service_DATA = kbabel_accelstool.desktop
+servicedir = $(kde_servicesdir)
+
diff --git a/kbabel/datatools/accelerators/kbabel_accelstool.desktop b/kbabel/datatools/accelerators/kbabel_accelstool.desktop
new file mode 100644
index 00000000..ffe5bb15
--- /dev/null
+++ b/kbabel/datatools/accelerators/kbabel_accelstool.desktop
@@ -0,0 +1,105 @@
+[Desktop Entry]
+Name=Accelerator Validation for KBabel
+Name[bg]=ВалидноÑÑ‚ на уÑкорител - KBabel
+Name[bs]=Provjera akceleratora za KBabel
+Name[ca]=Validació dels acceleradors per a KBabel
+Name[cs]=Validace akcelerátorů pro KBabel
+Name[cy]=Dilysiad Cyflymydd i KBabel
+Name[da]=Accelerator-validering for KBabel
+Name[de]=Kurzbefehl-Überprüfung für KBabel
+Name[el]=Έλεγχος εγκυÏότητας πλήκτÏων επιτάχυνσης για το KBabel
+Name[es]=Validación de accesos rápidos para KBabel
+Name[et]=KBabeli kiirklahvide kontrollija
+Name[eu]=Bizkortzaile balidazioa KBabel-entzat
+Name[fa]=اعتبارسنجی شتاب‌ده برای KBabel
+Name[fi]=Pikavalintojen tarkistus KBabelissa
+Name[fr]=Validation des accélérateurs clavier pour KBabel
+Name[ga]=Bailíochtú na nAicearraí le haghaidh KBabel
+Name[gl]=Validación de Aceleradores para KBabel
+Name[hi]=के-बेबल के लिठतà¥à¤µà¤°à¤• वेलिडेशन
+Name[hu]=Gyorsbillentyű-ellenőrző a KBabelhez
+Name[is]=Flýtilyklastaðfestir fyrir KBabel
+Name[it]=Convalida dei tasti acceleratori per KBabel
+Name[ja]=KBabel アクセラレータ検証
+Name[ka]=KBabel-ის áƒáƒ¥áƒ¡áƒ”ლერáƒáƒ¢áƒáƒ áƒ˜ დáƒáƒ›áƒ›áƒáƒ¬áƒ›áƒ”ბელი
+Name[kk]=KBabel-дің акÑелераторларды текÑеруі
+Name[lt]= KBabel prieigos klavišų žymių patikros įrankis
+Name[ms]=Pengesahan Kekunci Pintas untuk KBabel
+Name[nb]=Sjekk av snarveistaster i KBabel
+Name[nds]=Tastkombinatschoonprööv för KBabel
+Name[ne]=केबà¥à¤¯à¤¾à¤¬à¤²à¤•à¤¾ लागि गतिबरà¥à¤§à¤• पà¥à¤°à¤®à¤¾à¤£à¥€à¤•à¤°à¤£
+Name[nl]=Sneltoetsvalidatie voor KBabel
+Name[nn]=Sjekk av snarvegstastar i KBabel
+Name[pa]=ਕਬਬੇਲ ਲਈ ਪਰਵੇਸ਼ਕ ਪਰਮਾਣਕ
+Name[pl]=Sprawdzanie klawiszy skrótu w KBabel
+Name[pt]=Validação de Aceleradores para o KBabel
+Name[pt_BR]=Validação de Acelerador para o KBabel
+Name[ru]=Проверка акÑелераторов Ð´Ð»Ñ KBabel
+Name[sk]=Kontrola akcelerátorov pre KBabel
+Name[sl]=Pospeševalni potrjevalnik za KBabel
+Name[sr]=Овера таÑтера за брзи приÑтуп за KBabel
+Name[sr@Latn]=Overa tastera za brzi pristup za KBabel
+Name[sv]=Validering av snabbtangenter för Kbabel
+Name[ta]= Kபாபேலà¯à®•à¯à®•à¯ தரà¯à®®à®¤à®¿à®ªà¯à®ªà¯ செலà¯à®²à¯à®ªà®Ÿà®¿à®šà¯ சோதனை
+Name[tg]=Тафтиши акÑелаторҳо барои KBabel
+Name[tr]=KBabel için Hızlandırma Onayı
+Name[uk]=Перевірка акÑелератора Ð´Ð»Ñ KBabel
+Name[zh_CN]=KBabel çš„å¿«æ·é”®æ£€æŸ¥å™¨
+Name[zh_TW]=KBabel 的快速éµæª¢æŸ¥å™¨
+ValidationString=accelerator
+X-KDE-Library=kbabel_accelstool
+Type=Service
+Commands=validate
+Comment=Check Accelerators
+Comment[bg]=Проверка на уÑкорителите
+Comment[bs]=Provjeri akceleratore
+Comment[ca]=Comprova els acceleradors
+Comment[cs]=Zkontrolovat akcelerátory
+Comment[cy]=Gwirio Cyflymyddion
+Comment[da]=Tjek acceleratorer
+Comment[de]=Kurzbefehle prüfen
+Comment[el]=Έλεγχος πλήκτÏων επιτάχυνσης
+Comment[es]=Comprobar teclas rápidas
+Comment[et]=Kiirklahvide kontroll
+Comment[eu]=Egiaztatu bizkortzaileak
+Comment[fa]=بررسی شتاب‌دهها
+Comment[fi]=Tarkista pikavalinnat
+Comment[fr]=Vérification des accélérateurs clavier
+Comment[ga]=Seiceáil Aicearraí
+Comment[gl]=Verificación de Aceleradores
+Comment[he]=בודק מזנקי×
+Comment[hi]=तà¥à¤µà¤°à¤• जांच करें
+Comment[hu]=A gyorsbillentyűk ellenőrzése
+Comment[is]=Athuga flýtilykla
+Comment[it]=Controlla tasti acceleratori
+Comment[ja]=アクセラレータを検証
+Comment[ka]=áƒáƒ¥áƒ¡áƒ”ლერáƒáƒªáƒ˜áƒ˜áƒ¡ შემáƒáƒ¬áƒ›áƒ”ბáƒ
+Comment[kk]=ÐкÑелераторларды текÑеру
+Comment[lt]=Patikrinti prieigos klavišų žymes
+Comment[ms]=Periksa Kekunci Pintas
+Comment[nb]=Sjekk snarveistastene
+Comment[nds]=Tastkombinatschonen pröven
+Comment[ne]=गतिबरà¥à¤§à¤• जाà¤à¤š गरà¥à¤¨à¥à¤¹à¥‹à¤¸à¥
+Comment[nl]=Sneltoetsen controleren
+Comment[nn]=Sjekk snarvegstastar
+Comment[pa]=ਪਰਵੇਸ਼ਕ ਜਾਂਚ
+Comment[pl]=Sprawdzenie klawiszy skrótu
+Comment[pt]=Verificação de Aceleradores
+Comment[pt_BR]=Verifica Aceleradores
+Comment[ru]=Проверка акÑелераторов
+Comment[sk]=Kontrola akcelerátorov
+Comment[sl]=Preveri pospeševalnike
+Comment[sr]=Провери таÑтере за брзи приÑтуп
+Comment[sr@Latn]=Proveri tastere za brzi pristup
+Comment[sv]=Kontrollera snabbtangenter
+Comment[ta]=தரà¯à®®à®¤à®¿à®ªà¯à®ªà¯ சரிபாரà¯à®ªà¯à®ªà¯
+Comment[tg]=Тафтиши акÑелаторҳо
+Comment[tr]=Hızlandırıcıları Denetle
+Comment[uk]=Перевірити акÑелератори
+Comment[zh_CN]=检查快æ·é”®
+Comment[zh_TW]=檢查快速éµ
+Shortcuts=Ctrl+H
+ServiceTypes=KBabelValidator,KDataTool
+DataType=CatalogItem
+DataMimeTypes=application/x-kbabel-catalogitem
+ReadOnly=true
diff --git a/kbabel/datatools/accelerators/main.cc b/kbabel/datatools/accelerators/main.cc
new file mode 100644
index 00000000..4d94354e
--- /dev/null
+++ b/kbabel/datatools/accelerators/main.cc
@@ -0,0 +1,137 @@
+/* This file is part of KBabel
+ based Copyright (C) 1998, 1999 Torben Weis <weis@kde.org>
+ 2002 Stanislav Visnovsky <visnovsky@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.
+
+ In addition, as a special exception, the copyright holders give
+ permission to link the code of this program with any edition of
+ the Qt library by Trolltech AS, Norway (or with modified versions
+ of Qt that use the same license as Qt), and distribute linked
+ combinations including the two. You must obey the GNU General
+ Public License in all respects for all of the code used other than
+ Qt. If you modify this file, you may extend this exception to
+ your version of the file, but you are not obligated to do so. If
+ you do not wish to do so, delete this exception statement from
+ your version.
+
+*/
+
+#include <resources.h>
+#include "catalogitem.h"
+#include "catalogsettings.h"
+#include "main.h"
+
+#include <kconfig.h>
+#include <kdebug.h>
+#include <kgenericfactory.h>
+#include <klibloader.h>
+#include <klocale.h>
+
+/***************************************************
+ *
+ * Factory
+ *
+ ***************************************************/
+
+K_EXPORT_COMPONENT_FACTORY( kbabel_accelstool, KGenericFactory<AcceleratorTool> ( "kbabeldatatool" ) )
+
+using namespace KBabel;
+
+AcceleratorTool::AcceleratorTool( QObject* parent, const char* name, const QStringList & )
+ : KDataTool( parent, name ), _cache_origin( 0 )
+{
+ // bogus translation just for allowing the translation
+ i18n("what check found errors","accelerator");
+}
+
+bool AcceleratorTool::run( const QString& command, void* data, const QString& datatype, const QString& mimetype )
+{
+ if ( command != "validate" )
+ {
+ kdDebug(KBABEL) << "Accelerator Tool does only accept the command 'validate'" << endl;
+ kdDebug(KBABEL) << " The commands " << command << " is not accepted" << endl;
+ return FALSE;
+ }
+
+ // Check wether we can accept the data
+ if ( datatype != "CatalogItem" )
+ {
+ kdDebug(KBABEL) << "Accelerator Tool only accepts datatype CatalogItem" << endl;
+ return FALSE;
+ }
+
+ if ( mimetype != "application/x-kbabel-catalogitem" )
+ {
+ kdDebug(KBABEL) << "Accelerator Tool only accepts mimetype application/x-kbabel-catalogitem" << endl;
+ return FALSE;
+ }
+
+ if( command == "validate" )
+ {
+ CatalogItem* item = (CatalogItem*)(data);
+
+ if( _cache_origin != item->project() )
+ {
+ _context = item->project()->miscSettings().contextInfo;
+ _marker = item->project()->miscSettings().accelMarker;
+ _cache_origin = item->project();
+ }
+
+ bool hasError = false;
+
+ if(!item->isUntranslated())
+ {
+ // FIXME: this should care about plural forms in msgid
+ QString lineid=item->msgid().first();
+ lineid.replace( _context, "");
+ lineid.replace(QRegExp("\\n"),"");
+ lineid.simplifyWhiteSpace();
+ QString regStr(_marker);
+ regStr+="[^\\s]";
+ QRegExp reg(regStr);
+
+ QStringList str = item->msgstr(true);
+ for( QStringList::Iterator form = str.begin() ; form != str.end(); form++ )
+ {
+ QString linestr=(*form);
+ linestr.simplifyWhiteSpace();
+
+ int n = lineid.contains(reg);
+ if( _marker == '&' )
+ n = n - lineid.contains(QRegExp("(&[a-z,A-Z,\\-,0-9,#]*;)|(&&(?!&+))"));
+ int m = linestr.contains(reg);
+ if( _marker == '&' )
+ m = m - linestr.contains(QRegExp("(&[a-z,A-Z,\\-,0-9,#]*;)|(&&(?!&+))"));
+ hasError = hasError || ( n<=1 && m != n);
+ }
+ }
+
+ if(hasError)
+ {
+ item->appendError( "Accelerator" );
+ }
+ else
+ {
+ item->removeError( "Accelerator" );
+ }
+
+ return !hasError;
+ }
+ return FALSE;
+}
+
+#include "main.moc"
diff --git a/kbabel/datatools/accelerators/main.h b/kbabel/datatools/accelerators/main.h
new file mode 100644
index 00000000..559fe112
--- /dev/null
+++ b/kbabel/datatools/accelerators/main.h
@@ -0,0 +1,56 @@
+/* This file is part of KBabel
+ based on Copyright (C) 1998, 1999 Torben Weis <weis@kde.org>
+ 2002 Stanislav Visnovsky <visnovsky@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.
+
+ In addition, as a special exception, the copyright holders give
+ permission to link the code of this program with any edition of
+ the Qt library by Trolltech AS, Norway (or with modified versions
+ of Qt that use the same license as Qt), and distribute linked
+ combinations including the two. You must obey the GNU General
+ Public License in all respects for all of the code used other than
+ Qt. If you modify this file, you may extend this exception to
+ your version of the file, but you are not obligated to do so. If
+ you do not wish to do so, delete this exception statement from
+ your version.
+
+*/
+
+#ifndef __main_h__
+#define __main_h__
+
+#include "kbproject.h"
+
+#include <kdatatool.h>
+
+#include <qregexp.h>
+
+class AcceleratorTool : public KDataTool
+{
+ Q_OBJECT
+
+public:
+ AcceleratorTool( QObject* parent, const char* name, const QStringList & );
+ virtual bool run( const QString& command, void* data, const QString& datatype, const QString& mimetype);
+
+private:
+ QRegExp _context;
+ QChar _marker;
+ KBabel::Project::Ptr _cache_origin;
+};
+
+#endif
diff --git a/kbabel/datatools/arguments/Makefile.am b/kbabel/datatools/arguments/Makefile.am
new file mode 100644
index 00000000..5585d438
--- /dev/null
+++ b/kbabel/datatools/arguments/Makefile.am
@@ -0,0 +1,19 @@
+
+INCLUDES = -I$(srcdir)/../../common -I../../common $(all_includes)
+kbabel_argstool_la_LIBADD = $(LIB_KIO) ../../common/libkbabelcommon.la
+
+####### Files
+
+kde_module_LTLIBRARIES = kbabel_argstool.la
+
+kbabel_argstool_la_SOURCES = main.cc
+
+kbabel_argstool_la_LDFLAGS = $(all_libraries) -avoid-version -module -no-undefined
+
+noinst_HEADERS = main.h
+
+kbabel_argstool_la_METASOURCES = AUTO
+
+service_DATA = kbabel_argstool.desktop
+servicedir = $(kde_servicesdir)
+
diff --git a/kbabel/datatools/arguments/kbabel_argstool.desktop b/kbabel/datatools/arguments/kbabel_argstool.desktop
new file mode 100644
index 00000000..e90ba652
--- /dev/null
+++ b/kbabel/datatools/arguments/kbabel_argstool.desktop
@@ -0,0 +1,106 @@
+[Desktop Entry]
+Name=Argument Validation for KBabel
+Name[bg]=ВалидноÑÑ‚ на аргументите - KBabel
+Name[bs]=Provjera argumenata za KBabel
+Name[ca]=Validació dels arguments per a KBabel
+Name[cs]=Validace argumentů pro KBabel
+Name[cy]= Dilysiant Ymresymiad i KBabel
+Name[da]=Argument-validering for KBabel
+Name[de]=Argument-Überprüfung für KBabel
+Name[el]=Έλεγχος εγκυÏότητας οÏισμάτων για το KBabel
+Name[es]=Validació de argumentos para KBabel
+Name[et]=KBabeli argumentide kontrollija
+Name[eu]=Argumentu balidazioa KBabel-entzat
+Name[fa]=اعتبارسنجی نشانوند برای KBabel
+Name[fi]=Argumenttien tarkistus KBabelissa
+Name[fr]=Validation d'un argument pour KBabel
+Name[ga]=Bailíochtú Argóintí le haghaidh KBabel
+Name[gl]=Validación de Argumentos para KBabel
+Name[hi]=के-बेबल के लिठआरà¥à¤—à¥à¤®à¥‡à¤‚ट वेलिडेशन
+Name[hu]=Argumentumellenőrző a KBabelhez
+Name[is]=Viðfangastaðfestir fyrir KBabel
+Name[it]=Convalida argomenti per KBabel
+Name[ja]=KBabel 引数検証
+Name[ka]=KBabel-ის áƒáƒ áƒ’უმენტთრდáƒáƒ›áƒ›áƒáƒ¬áƒ›áƒ”ბელი
+Name[kk]=KBabel-дың аргументтерін текÑеруі
+Name[lt]=Kbabel argumentų patikros įrankis
+Name[ms]=Pengesahan Argumen untuk KBabel
+Name[nb]=Argumentsjekk for KBabel
+Name[nds]=Argumentenprööv för KBabel
+Name[ne]=केबà¥à¤¯à¤¾à¤¬à¤²à¤•à¤¾ लागि विषय पà¥à¤°à¤®à¤¾à¤£à¥€à¤•à¤°à¤£
+Name[nl]=Argumentenvalidatie voor KBabel
+Name[nn]=Argumentsjekk for KBabel
+Name[pa]=ਕੇਬਬੇਲ ਲਈ ਆਰਗੂਮਿੰਟ ਪੜਤਾਲ
+Name[pl]=Sprawdzenie argumentów w KBabel
+Name[pt]=Validação de Argumentos para o KBabel
+Name[pt_BR]=Validação de Argumentos para o KBabel
+Name[ru]=Проверка аргументов Ð´Ð»Ñ KBabel
+Name[sk]=Kontrola argumentov pre KBabel
+Name[sl]=Argumentni potrjevalnik za KBabel
+Name[sr]=Овера аргумената за KBabel
+Name[sr@Latn]=Overa argumenata za KBabel
+Name[sv]=Validering av parametrar för Kbabel
+Name[ta]= Kபாபேலà¯à®•à¯à®•à¯ தரà¯à®®à®¤à®¿à®ªà¯à®ªà¯ செலà¯à®²à¯à®ªà®Ÿà®¿à®šà¯ சோதனை
+Name[tg]=Тафтиши далелҳо барои KBabel
+Name[tr]=KBabel için Hızlandırma Argümanı
+Name[uk]=Перевірка аргументів Ð´Ð»Ñ KBabel
+Name[zh_CN]=KBabel çš„å‚数检查器
+Name[zh_TW]=KBabel çš„åƒæ•¸æª¢æŸ¥å™¨
+X-KDE-Library=kbabel_argstool
+Type=Service
+Commands=validate
+Comment=Check Arguments
+Comment[bg]=Проверка на аргументите
+Comment[bs]=Provjeri argumente
+Comment[ca]=Comprova els arguments
+Comment[cs]=Zkontrolovat argumenty
+Comment[cy]=Gwirio Ymresymiadau
+Comment[da]=Tjek argumenter
+Comment[de]=Argumente prüfen
+Comment[el]=Έλεγχος οÏισμάτων
+Comment[eo]=Kontroli argumentojn
+Comment[es]=Comprobar argumentos
+Comment[et]=Argumentide kontroll
+Comment[eu]=Egiaztatu argumentuak
+Comment[fa]=بررسی نشانوندها
+Comment[fi]=Tarkista argumentit
+Comment[fr]=Vérification des arguments
+Comment[ga]=Seiceáil Argóintí
+Comment[gl]=Verificación dos argumentos
+Comment[he]=בודק ×רגומנטי×
+Comment[hi]=आरà¥à¤—à¥à¤®à¥‡à¤‚ट जांच करें
+Comment[hu]=Az argumentumok ellenőrzése
+Comment[is]=Athuga viðföng
+Comment[it]=Controlla argomenti
+Comment[ja]=引数を検証
+Comment[ka]=áƒáƒ áƒ’უმენტების შემáƒáƒ¬áƒ›áƒ”ბáƒ
+Comment[kk]=Ðргументтерді текÑеру
+Comment[lt]=Patikrinti argumentus
+Comment[ms]=Periksa Argumen
+Comment[nb]=Sjekk argumenter
+Comment[nds]=Argumenten pröven
+Comment[ne]=विषय जाà¤à¤š गरà¥à¤¨à¥à¤¹à¥‹à¤¸à¥
+Comment[nl]=Argumenten controleren
+Comment[nn]=Sjekk argument
+Comment[pa]=ਆਰਗੂਮਿੰਟ ਜਾਂਚ
+Comment[pl]=Sprawdzenie argumentów
+Comment[pt]=Verificação dos argumentos
+Comment[pt_BR]=Verifica Argumentos
+Comment[ru]=Проверить аргументы
+Comment[sk]=Kontrola argumentov
+Comment[sl]=Preveri argumente
+Comment[sr]=Провери аргументе
+Comment[sr@Latn]=Proveri argumente
+Comment[sv]=Kontrollera parametrar
+Comment[ta]= தரà¯à®®à®¤à®¿à®ªà¯à®ªà¯à®•à®³à¯ˆ சரிபாரà¯à®ªà¯à®ªà¯
+Comment[tg]=Тафтиш кардани далелҳо
+Comment[tr]=Argümanların Denetimi
+Comment[uk]=Перевірити аргументи
+Comment[zh_CN]=检查å‚æ•°
+Comment[zh_TW]=檢查åƒæ•¸
+Shortcuts=Ctrl+D
+ValidationString=arguments
+ServiceTypes=KDataTool,KBabelValidator
+DataType=CatalogItem
+DataMimeTypes=application/x-kbabel-catalogitem
+ReadOnly=true
diff --git a/kbabel/datatools/arguments/main.cc b/kbabel/datatools/arguments/main.cc
new file mode 100644
index 00000000..92c9765c
--- /dev/null
+++ b/kbabel/datatools/arguments/main.cc
@@ -0,0 +1,277 @@
+/* This file is part of KBabel
+ based Copyright (C) 1998, 1999 Torben Weis <weis@kde.org>
+ 2002-2003 Stanislav Visnovsky <visnovsky@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.
+
+ In addition, as a special exception, the copyright holders give
+ permission to link the code of this program with any edition of
+ the Qt library by Trolltech AS, Norway (or with modified versions
+ of Qt that use the same license as Qt), and distribute linked
+ combinations including the two. You must obey the GNU General
+ Public License in all respects for all of the code used other than
+ Qt. If you modify this file, you may extend this exception to
+ your version of the file, but you are not obligated to do so. If
+ you do not wish to do so, delete this exception statement from
+ your version.
+
+*/
+
+#include <resources.h>
+#include "catalogitem.h"
+#include "catalogsettings.h"
+#include "main.h"
+
+#include <kconfig.h>
+#include <kdebug.h>
+#include <kgenericfactory.h>
+#include <klocale.h>
+#include <kmessagebox.h>
+
+/***************************************************
+ *
+ * Factory
+ *
+ ***************************************************/
+
+K_EXPORT_COMPONENT_FACTORY( kbabel_argstool, KGenericFactory<ArgumentTool> ( "kbabeldatatool" ) )
+
+using namespace KBabel;
+
+ArgumentTool::ArgumentTool( QObject* parent, const char* name, const QStringList & )
+ : KDataTool( parent, name ), _cache_origin( 0 )
+{
+ i18n( "what check found errors","arguments");
+}
+
+bool ArgumentTool::run( const QString& command, void* data, const QString& datatype, const QString& mimetype )
+{
+ if ( command != "validate" )
+ {
+ kdDebug(KBABEL) << "Argument Tool does only accept the command 'validate' and 'shortcut'" << endl;
+ kdDebug(KBABEL) << " The commands " << command << " is not accepted" << endl;
+ return FALSE;
+ }
+
+ // Check wether we can accept the data
+ if ( datatype != "CatalogItem" )
+ {
+ kdDebug(KBABEL) << "Argument Tool only accepts datatype CatalogItem" << endl;
+ return FALSE;
+ }
+
+ if ( mimetype != "application/x-kbabel-catalogitem" )
+ {
+ kdDebug(KBABEL) << "Argument Tool only accepts mimetype application/x-kbabel-catalogitem" << endl;
+ return FALSE;
+ }
+
+ if( command == "validate" )
+ {
+ CatalogItem* item = (CatalogItem*)(data);
+
+ if( item->isNoCformat() ) return true;
+ bool hasError = false;
+
+ if( _cache_origin != item->project() )
+ {
+ _context = item->project()->miscSettings().contextInfo;
+ _checkPlurals = item->project()->identitySettings().checkPluralArgument;
+ _cache_origin = item->project();
+ }
+
+ if(!item->isUntranslated())
+ {
+
+ QString formatChars="dioxXucsfeEgGp%";
+
+ if( _checkPlurals ) formatChars+="n";
+
+ // FIXME: this should care about plural forms in msgid
+ QString line=item->msgid().first();
+ QStringList argList;
+
+// if( isPluralForm() )
+ {
+ // FIXME: this is KDE specific
+ if( line.startsWith("_n:" ))
+ {
+ // truncate text after first \n to get args only once
+ line = line.mid(0,line.find("\\n"));
+ }
+ }
+ line.replace(_context, "");
+ line.replace(QRegExp("\\n"),"");
+ line.simplifyWhiteSpace();
+
+ // flag, for GNU only we can allow reordering
+ bool non_gnu = (item->pluralForm() == KDESpecific);
+
+ int index=line.find(QRegExp("%."));
+
+ while(index>=0)
+ {
+ int endIndex=line.find(QRegExp("[^\\d]"),index+1);
+ if(endIndex<0)
+ {
+ endIndex=line.length();
+ }
+ else if( formatChars.contains(line[endIndex]) )
+ {
+ endIndex++;
+ }
+
+ if(endIndex - index > 1 ) {
+ QString arg = line.mid(index,endIndex-index);
+ if( arg.contains( QRegExp("\\d") ) ) {
+ non_gnu = true;
+ }
+ argList.append(arg);
+
+ }
+
+ index=line.find(QRegExp("%."),endIndex);
+ }
+
+ if( item->pluralForm()==KDESpecific)
+ {
+ // FIXME: this is KDE specific
+ if( _checkPlurals && line.startsWith("_n:" ) && !argList.contains("%n") )
+ {
+ argList.append("%n");
+ }
+ }
+
+ // generate for each plural form to be checked separately
+ line=item->msgstr().first();
+ QStringList lines;
+
+ // FIXME; this is KDE specific
+ if( item->pluralForm() == KDESpecific )
+ {
+ lines = QStringList::split("\\n",line);
+ }
+ else
+ {
+ lines.append(line);
+ }
+
+ QStringList argCache = argList;
+ QStringList foundArgs;
+
+ for(QStringList::Iterator i = lines.begin() ; i!=lines.end() ; i++)
+ {
+ // initialize for the next plural form
+ foundArgs.clear();
+ argList = argCache;
+
+ line=(*i);
+
+ line.replace(QRegExp("\\n"),"");
+
+ QRegExp argdesc(
+ "%((["+formatChars+"])"
+ +"|(\\d)+"
+ +"|(\\d)+\\$(["+formatChars+"])"
+ +")" ) ;
+ index = -1;
+
+ do {
+
+ index = argdesc.search( line, index+1 );
+
+ if( index == -1 ) break;
+
+ // do not add a redundant argument, if it is non GNU
+ if( !non_gnu || !foundArgs.contains( argdesc.cap(0) ) )
+ foundArgs.append( argdesc.cap( 0 ) );
+ } while( true );
+
+ // now, compare the list
+ argList = argCache;
+
+ if( non_gnu ) {
+ for ( QStringList::Iterator it = foundArgs.begin(); it != foundArgs.end(); ++it ) {
+ if( argList.find( *it ) == argList.end() ) {
+ hasError = true;
+ break;
+ } else {
+ argList.remove( *it );
+ }
+ }
+
+ if( ! argList.isEmpty() ) {
+ hasError = true;
+ }
+ }
+ else
+ {
+ // handle GNU with replacements
+ QStringList::Iterator oit = argList.begin();
+ for ( QStringList::Iterator it = foundArgs.begin(); it != foundArgs.end(); ++it , ++oit) {
+ if( *it == *oit ) {
+ // argument is the same, mark as used
+ *oit = QString::null;
+ } else {
+ // try to strip replacement
+ int index = (*it).find( '$' );
+ if( index == -1 ) {
+ // there is no replacement, this is wrong
+ hasError = true;
+ break;
+ }
+ QString place = (*it).mid( 1, index-1 );
+ QString arg = (*it).right( index );
+ arg[0] = '%';
+ QStringList::Iterator a = argList.at( place.toInt()-1 );
+ if( a != argList.end() && (*a) == arg )
+ {
+ (*a) = QString::null;
+ }
+ else
+ {
+ // duplicate or index is too high
+ hasError = true;
+ }
+ }
+ }
+
+ for ( QStringList::Iterator it = argList.begin(); it != argList.end(); ++it) {
+ if( ! (*it).isNull () ) {
+ // argument is the same, mark as used
+ hasError = true;
+ break;
+ }
+ }
+ }
+ }
+ }
+
+ if(hasError)
+ {
+ item->appendError( "Arguments" );
+ }
+ else
+ {
+ item->removeError( "Arguments" );
+ }
+
+ return !hasError;
+ }
+ return FALSE;
+}
+
+#include "main.moc"
diff --git a/kbabel/datatools/arguments/main.h b/kbabel/datatools/arguments/main.h
new file mode 100644
index 00000000..a05cce49
--- /dev/null
+++ b/kbabel/datatools/arguments/main.h
@@ -0,0 +1,55 @@
+/* This file is part of KBabel
+ based on Copyright (C) 1998, 1999 Torben Weis <weis@kde.org>
+ 2002-2003 Stanislav Visnovsky <visnovsky@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.
+
+ In addition, as a special exception, the copyright holders give
+ permission to link the code of this program with any edition of
+ the Qt library by Trolltech AS, Norway (or with modified versions
+ of Qt that use the same license as Qt), and distribute linked
+ combinations including the two. You must obey the GNU General
+ Public License in all respects for all of the code used other than
+ Qt. If you modify this file, you may extend this exception to
+ your version of the file, but you are not obligated to do so. If
+ you do not wish to do so, delete this exception statement from
+ your version.
+
+*/
+
+#ifndef __main_h__
+#define __main_h__
+
+#include "kbproject.h"
+
+#include <kdatatool.h>
+
+#include <qregexp.h>
+
+class ArgumentTool : public KDataTool
+{
+ Q_OBJECT
+
+public:
+ ArgumentTool( QObject* parent, const char* name, const QStringList & );
+ virtual bool run( const QString& command, void* data, const QString& datatype, const QString& mimetype);
+private:
+ KBabel::Project::Ptr _cache_origin;
+ QRegExp _context;
+ bool _checkPlurals;
+};
+
+#endif
diff --git a/kbabel/datatools/context/Makefile.am b/kbabel/datatools/context/Makefile.am
new file mode 100644
index 00000000..4d4a7c0e
--- /dev/null
+++ b/kbabel/datatools/context/Makefile.am
@@ -0,0 +1,19 @@
+
+INCLUDES = -I$(srcdir)/../../common -I../../common $(all_includes)
+kbabel_contexttool_la_LIBADD = $(LIB_KIO) ../../common/libkbabelcommon.la
+
+####### Files
+
+kde_module_LTLIBRARIES = kbabel_contexttool.la
+
+kbabel_contexttool_la_SOURCES = main.cc
+
+kbabel_contexttool_la_LDFLAGS = $(all_libraries) -avoid-version -module -no-undefined
+
+noinst_HEADERS = main.h
+
+kbabel_contexttool_la_METASOURCES = AUTO
+
+service_DATA = kbabel_contexttool.desktop
+servicedir = $(kde_servicesdir)
+
diff --git a/kbabel/datatools/context/kbabel_contexttool.desktop b/kbabel/datatools/context/kbabel_contexttool.desktop
new file mode 100644
index 00000000..482fefcf
--- /dev/null
+++ b/kbabel/datatools/context/kbabel_contexttool.desktop
@@ -0,0 +1,100 @@
+[Desktop Entry]
+Name=Translated Context Info Validation for KBabel
+Name[bg]=ВалидноÑÑ‚ на контекÑтната Ð¸Ð½Ñ„Ð¾Ñ€Ð¼Ð°Ñ†Ð¸Ñ - KBabel
+Name[bs]=Provjera prevedenih kontekst informacija za KBabel
+Name[ca]=Validació de la informació al context traduït per a KBabel
+Name[cs]=Validace přeložených kontextových informací
+Name[cy]=Dilysiant Gwybodaeth Cyd-destun wedi'i cyfieithu i KBabel
+Name[da]=Oversat sammenhængsinfo-validering for KBabel
+Name[de]=Kontextinfo-Überprüfung für KBabel
+Name[el]=Έλεγχος εγκυÏότητας μεταφÏασμένων σχετικών πληÏοφοÏιών για το KBabel
+Name[es]=Validación de información de contexto traducida para KBabel
+Name[et]=KBabeli tõlgitud kontekstiinfo kontrollija
+Name[eu]=Itzulitako kontestuen informazioaren balidazioa KBabel-entzat
+Name[fa]=اعتبارسنجی اطلاعات متن ترجمه‌شده برای KBabel
+Name[fi]=Käännetyn kontekstitiedon tarkistus KBabelissa
+Name[fr]=Validation des informations de contexte de traduction pour KBabel
+Name[gl]=Validación da Información de Contexto para KBabel
+Name[hi]=के-बेबल के लिठअनूदित कॉनà¥à¤Ÿà¥‡à¤•à¥à¤¸à¥à¤Ÿ जानकारी वेलिडेशन
+Name[hu]=Ellenőrző a fordítási kontextushoz a KBabelben
+Name[is]=Staðfesting þýddra samhengisupplýsinga fyrir KBabel
+Name[it]=Convalida delle informazioni di contesto tradotte per KBabel
+Name[ja]=KBabel 翻訳ã•ã‚ŒãŸæ–‡è„ˆæƒ…報を検索
+Name[ka]=თáƒáƒ áƒ’მნის კáƒáƒœáƒ¢áƒ”ქსტის ინფáƒáƒ áƒ›áƒáƒªáƒ˜áƒ KBabel-სთვის
+Name[kk]=KBabel-дың аударылған контекÑтік мәліметін текÑеру
+Name[lt]=KBabel išverstos kontekstinės informacijos patikros įrankis
+Name[ms]=Pengesahan Info Konteks Telah Diterjemah untuk KBabel
+Name[nb]=Sjekk av oversatt sammenhengsinformasjon i KBabel
+Name[nds]=Prööv op översett Infokontext för KBabel
+Name[ne]=केबà¥à¤¯à¤¾à¤¬à¤²à¤•à¤¾ लागि अनà¥à¤¬à¤¾à¤¦ गरिà¤à¤•à¥‹ पà¥à¤°à¤¸à¤™à¥à¤— सूचना पà¥à¤°à¤®à¤¾à¤£à¥€à¤•à¤°à¤£
+Name[nl]=Vertaalde contextinformatie-validatie voor KBabel
+Name[nn]=Sjekk av omsett samanhengsinformasjon i KBabel
+Name[pl]=Sprawdzanie kontekstu tłumaczonej informacji dla KBabel
+Name[pt]=Validação da Informação de Contexto do KBabel
+Name[pt_BR]=Validação de Informações de Contexto Traduzidas para o KBabel
+Name[ru]=Проверка переведённой контекÑтной информации Ð´Ð»Ñ KBabel
+Name[sk]=Kontrola kontextu v preklade pre KBabel
+Name[sl]=Potrjevalnik informacij prevedene vsebine za KBabel
+Name[sr]=Овера преведених контекÑтних информација за KBabel
+Name[sr@Latn]=Overa prevedenih kontekstnih informacija za KBabel
+Name[sv]=Validering av översatt sammanhangsinformation för Kbabel
+Name[ta]= Kபாபேலà¯à®•à¯à®•à¯ மொழிபெயரà¯à®ªà¯à®ªà¯ சூழல௠தகவல௠செலà¯à®²à¯à®ªà®Ÿà®¿à®¯à®¾à®•à¯à®•à®®à¯
+Name[tg]=Тафтиши ахбороти тарҷумашудаи матнӣ барои KBabel
+Name[tr]=KBabel için Çevrilen Bağlam Bilgisi Denetimi
+Name[uk]=Перевірка інформації контекÑту перекладу Ð´Ð»Ñ KBabel
+Name[zh_CN]=KBabel 的上下文信æ¯ç¿»è¯‘检查器
+Name[zh_TW]=KBabel 的已翻譯內容資訊確èª
+ValidationString=context information
+X-KDE-Library=kbabel_contexttool
+Type=Service
+Commands=validate
+Comment=Look for Translated Context Info
+Comment[bg]=ТърÑене на контекÑтна Ð¸Ð½Ñ„Ð¾Ñ€Ð¼Ð°Ñ†Ð¸Ñ Ð·Ð° преведените
+Comment[bs]=Potraži prevedene kontekstne informacije
+Comment[ca]=Mira la informació al context traduït
+Comment[cs]=Vyhledat přeložené kontextové informace
+Comment[cy]=Chwilio am Gwybodaeth Cyd-destun wedi'i cyfieithu
+Comment[da]=Kig efter oversat sammenhængsinfo
+Comment[de]=Suche nach übersetzter Kontextinformation
+Comment[el]=Έλεγχος για μεταφÏασμένες σχετικές πληÏοφοÏίες
+Comment[es]=Buscar información de contexto traducida
+Comment[et]=Tõlgitud kontekstiinfo otsimine
+Comment[eu]=Bilatu itzulitako kontestuaren informazioa
+Comment[fa]=جستجوی اطلاعات متن ترجمه‌شده
+Comment[fi]=Etsi käännettyä kontekstitietoa
+Comment[fr]=Analyse les informations de contexte de traduction
+Comment[gl]=Verificar a información de contexto
+Comment[hi]=अनूदित कॉनà¥à¤Ÿà¥‡à¤•à¥à¤¸à¥à¤Ÿ जानकारी के लिठदेखें
+Comment[hu]=A kontextusfordítások kiszűrése
+Comment[is]=Leita að þýddum samhengisupplýsingum
+Comment[it]=Cerca informazioni di contesto tradotte
+Comment[ja]=翻訳ã•ã‚ŒãŸæ–‡è„ˆæƒ…報を検索
+Comment[ka]=თáƒáƒ áƒ’მნის კáƒáƒœáƒ¢áƒ”ქსტის ინფáƒáƒ áƒ›áƒáƒªáƒ˜áƒ˜áƒ¡ ძიებáƒ
+Comment[kk]=Ðударылған контекÑтік мәліметін қарау
+Comment[lt]=Ieškoti išverstos kontekstinės informacijos
+Comment[ms]=Cari Info Konteks Telah Diterjemah
+Comment[nb]=Se etter oversatt kontekstinformasjon
+Comment[nds]=Op översett Kontextinformatschonen pröven
+Comment[ne]=अनà¥à¤¬à¤¾à¤¦ गरिà¤à¤•à¥‹ पà¥à¤°à¤¸à¤™à¥à¤— सूचना अवलोकन
+Comment[nl]=Vertaalde contextinformatie zoeken
+Comment[nn]=Sjå etter omsett samanhengsinformasjon
+Comment[pl]=Sprawdzenie kontekstu tłumaczonej informacji
+Comment[pt]=Verificar a existência de traduções da informação de contexto
+Comment[pt_BR]=Procura por Informações de Contexto Traduzidas
+Comment[ru]=ПоиÑк переведённой контекÑтной информации
+Comment[sk]=Hľadanie preloženej kontextovej informácie
+Comment[sl]=Vpogled v Informacije prevedene vsebine
+Comment[sr]=Изглед за преведене контекÑтне информације
+Comment[sr@Latn]=Izgled za prevedene kontekstne informacije
+Comment[sv]=Leta efter översatt sammanhangsinformation
+Comment[ta]= மொழிபெயரà¯à®ªà¯à®ªà¯ சூழல௠தகவலை பாரà¯
+Comment[tg]=ҶуÑтуҷӯи ахбороти тарҷумашудаи матнӣ
+Comment[tr]=Çevrilen Bağlam Bilgisi için Görünüş
+Comment[uk]=Пошук за інформацією контекÑту перекладу
+Comment[zh_CN]=查找翻译的上下文信æ¯
+Comment[zh_TW]=尋找已翻譯的內容資訊
+Shortcuts=Ctrl+L
+ServiceTypes=KDataTool,KBabelValidator
+DataType=CatalogItem
+DataMimeTypes=application/x-kbabel-catalogitem
+ReadOnly=true
diff --git a/kbabel/datatools/context/main.cc b/kbabel/datatools/context/main.cc
new file mode 100644
index 00000000..19af3afd
--- /dev/null
+++ b/kbabel/datatools/context/main.cc
@@ -0,0 +1,115 @@
+/* This file is part of KBabel
+ based Copyright (C) 1998, 1999 Torben Weis <weis@kde.org>
+ 2002 Stanislav Visnovsky <visnovsky@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.
+
+ In addition, as a special exception, the copyright holders give
+ permission to link the code of this program with any edition of
+ the Qt library by Trolltech AS, Norway (or with modified versions
+ of Qt that use the same license as Qt), and distribute linked
+ combinations including the two. You must obey the GNU General
+ Public License in all respects for all of the code used other than
+ Qt. If you modify this file, you may extend this exception to
+ your version of the file, but you are not obligated to do so. If
+ you do not wish to do so, delete this exception statement from
+ your version.
+
+*/
+
+#include <resources.h>
+#include "catalogitem.h"
+#include "catalogsettings.h"
+#include "main.h"
+
+#include <kconfig.h>
+#include <kdebug.h>
+#include <kgenericfactory.h>
+#include <klibloader.h>
+#include <klocale.h>
+#include <kmessagebox.h>
+
+/***************************************************
+ *
+ * Factory
+ *
+ ***************************************************/
+
+K_EXPORT_COMPONENT_FACTORY( kbabel_contexttool, KGenericFactory<ContextTool> ( "kbabeldatatool" ) )
+
+using namespace KBabel;
+
+ContextTool::ContextTool( QObject* parent, const char* name, const QStringList & )
+ : KDataTool( parent, name ), _cache_origin( 0 )
+{
+ i18n("what check found errors","context info");
+}
+
+bool ContextTool::run( const QString& command, void* data, const QString& datatype, const QString& mimetype )
+{
+ if ( command != "validate" )
+ {
+ kdDebug(KBABEL) << "Context Tool does only accept the command 'validate' and 'shortcut'" << endl;
+ kdDebug(KBABEL) << " The commands " << command << " is not accepted" << endl;
+ return FALSE;
+ }
+
+ // Check wether we can accept the data
+ if ( datatype != "CatalogItem" )
+ {
+ kdDebug(KBABEL) << "Context Tool only accepts datatype CatalogItem" << endl;
+ return FALSE;
+ }
+
+ if ( mimetype != "application/x-kbabel-catalogitem" )
+ {
+ kdDebug(KBABEL) << "Context Tool only accepts mimetype application/x-kbabel-catalogitem" << endl;
+ return FALSE;
+ }
+
+ if( command == "validate" )
+ {
+ CatalogItem* item = (CatalogItem*)(data);
+
+ if( _cache_origin != item->project() )
+ {
+ _context = item->project()->miscSettings().contextInfo;
+ _cache_origin = item->project();
+ }
+
+ bool hasError = false;
+
+ if(!item->isUntranslated() && item->msgid().first().contains(_context)
+ && item->msgstr().first().contains(_context) )
+ {
+ hasError = true;
+ }
+
+ if(hasError)
+ {
+ item->appendError( "context info" );
+ }
+ else
+ {
+ item->removeError( "context info" );
+ }
+
+ return !hasError;
+ }
+ return FALSE;
+}
+
+#include "main.moc"
diff --git a/kbabel/datatools/context/main.h b/kbabel/datatools/context/main.h
new file mode 100644
index 00000000..99035691
--- /dev/null
+++ b/kbabel/datatools/context/main.h
@@ -0,0 +1,52 @@
+/* This file is part of KBabel
+ based on Copyright (C) 1998, 1999 Torben Weis <weis@kde.org>
+ 2002 Stanislav Visnovsky <visnovsky@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.
+
+ In addition, as a special exception, the copyright holders give
+ permission to link the code of this program with any edition of
+ the Qt library by Trolltech AS, Norway (or with modified versions
+ of Qt that use the same license as Qt), and distribute linked
+ combinations including the two. You must obey the GNU General
+ Public License in all respects for all of the code used other than
+ Qt. If you modify this file, you may extend this exception to
+ your version of the file, but you are not obligated to do so. If
+ you do not wish to do so, delete this exception statement from
+ your version.
+
+*/
+
+#ifndef __main_h__
+#define __main_h__
+
+#include "kbproject.h"
+
+#include <kdatatool.h>
+
+class ContextTool : public KDataTool
+{
+ Q_OBJECT
+
+public:
+ ContextTool( QObject* parent, const char* name, const QStringList & );
+ virtual bool run( const QString& command, void* data, const QString& datatype, const QString& mimetype);
+private:
+ KBabel::Project::Ptr _cache_origin;
+ QRegExp _context;
+};
+
+#endif
diff --git a/kbabel/datatools/equations/Makefile.am b/kbabel/datatools/equations/Makefile.am
new file mode 100644
index 00000000..9b49892d
--- /dev/null
+++ b/kbabel/datatools/equations/Makefile.am
@@ -0,0 +1,19 @@
+
+INCLUDES = -I$(srcdir)/../../common -I../../common $(all_includes)
+kbabel_equationstool_la_LIBADD = $(LIB_KIO) ../../common/libkbabelcommon.la
+
+####### Files
+
+kde_module_LTLIBRARIES = kbabel_equationstool.la
+
+kbabel_equationstool_la_SOURCES = main.cc
+
+kbabel_equationstool_la_LDFLAGS = $(all_libraries) -avoid-version -module -no-undefined
+
+noinst_HEADERS = main.h
+
+kbabel_equationstool_la_METASOURCES = AUTO
+
+service_DATA = kbabel_equationstool.desktop
+servicedir = $(kde_servicesdir)
+
diff --git a/kbabel/datatools/equations/kbabel_equationstool.desktop b/kbabel/datatools/equations/kbabel_equationstool.desktop
new file mode 100644
index 00000000..cc3544a5
--- /dev/null
+++ b/kbabel/datatools/equations/kbabel_equationstool.desktop
@@ -0,0 +1,104 @@
+[Desktop Entry]
+Name=Equation Validation for KBabel
+Name[bg]=ВалидноÑÑ‚ на изравнÑването - KBabel
+Name[bs]=Provjera jednakosti za KBabel
+Name[ca]=Validació de les equacions per a KBabel
+Name[cs]=Validace rovnic
+Name[cy]=Dilysiant Hafaliad i KBabel
+Name[da]=Lignings-validering for KBabel
+Name[de]=Formel-Überprüfung für KBabel
+Name[el]=Έλεγχος εγκυÏότητας εξισώσεων για το KBabel
+Name[es]=Validación de ecuaciones para KBabel
+Name[et]=KBabeli võrduste kontrollija
+Name[eu]=Ekuazioen balidazioa KBabel-entzat
+Name[fa]=اعتبارسنجی معادله برای KBabel
+Name[fi]=Yhtälöiden tarkistus KBabelissa
+Name[fr]=Validateur de similitudes pour KBabel
+Name[ga]=Bailíochtú Cothromóidí le haghaidh KBabel
+Name[gl]=Validación de ecuacións para KBabel
+Name[hi]=के-बेबल के लिठसमीकरण वेलिडेशन
+Name[hu]=Egyenletellenőrző a KBabelhez
+Name[is]=Jöfnustaðfesting fyrir KBabel
+Name[it]=Convalida delle equazioni per KBabel
+Name[ja]=KBabel ç­‰å¼æ¤œè¨¼
+Name[ka]=KBabel-ს ფáƒáƒ áƒ›áƒ£áƒšáƒáƒ—რდáƒáƒ›áƒáƒ¬áƒ›áƒ”ბáƒ
+Name[kk]=KBabel-дың баламаларын текÑеруі
+Name[lt]=KBabel lygybių patikros įrankis
+Name[ms]=Pengesahan Persamaan untuk KBabel
+Name[nb]=Likningssjekk for KBabel
+Name[nds]=Gliekenprööv för KBabel
+Name[ne]=केबà¥à¤¯à¤¾à¤¬à¤²à¤•à¤¾ लागि समीकरण पà¥à¤°à¤®à¤¾à¤£à¥€à¤•à¤°à¤£
+Name[nl]=Vergelijkingenvalidatie voor KBabel
+Name[nn]=Likningssjekk for KBabel
+Name[pl]=Sprawdzenie równań w KBabel
+Name[pt]=Validação de Equações para o KBabel
+Name[pt_BR]=Validação de Equação para o KBabel
+Name[ru]=Проверка уравнений Ð´Ð»Ñ KBabel
+Name[sk]=Kontrola rovníc pre KBabel
+Name[sl]=Potrjevalnik enaÄb za KBabel
+Name[sr]=Овера једначина за KBabel
+Name[sr@Latn]=Overa jednaÄina za KBabel
+Name[sv]=Validering av ekvationer för Kbabel
+Name[ta]= Kபாபேலà¯à®•à¯à®•à¯ சமனà¯à®ªà®¾à®Ÿà¯ செலà¯à®²à¯à®ªà®Ÿà®¿à®šà¯ சோதனை
+Name[tg]=Тафтиши баробар барои KBabel
+Name[tr]=KBabel için Denklem Denetimi
+Name[uk]=Перевірка рівнÑнь Ð´Ð»Ñ KBabel
+Name[zh_CN]=KBabel çš„ç­‰å¼æ£€æŸ¥å™¨
+Name[zh_TW]=KBabel çš„ç­‰å¼æª¢æŸ¥å™¨
+X-KDE-Library=kbabel_equationstool
+Type=Service
+Commands=validate
+Comment=Check Equations
+Comment[bg]=Проверка на изравнÑването
+Comment[bs]=Provjeri jednakosti
+Comment[ca]=Comprova les equacions
+Comment[cs]=Zkontrolovat rovnice
+Comment[cy]=Gwirio Hafaliadau
+Comment[da]=Tjek ligninger
+Comment[de]=Formeln prüfen
+Comment[el]=Έλεγχος εξισώσεων
+Comment[es]=Comprobar ecuaciones
+Comment[et]=Võrduste kontroll
+Comment[eu]=Egiaztatu ekuazioak
+Comment[fa]=بررسی معادله‌ها
+Comment[fi]=Tarkista yhtälöt
+Comment[fr]=Vérifier les identités
+Comment[ga]=Seiceáil Cothromóidí
+Comment[gl]=Verifica as ecuacións
+Comment[he]=בודק משוו×ות
+Comment[hi]=समीकरण जांच करें
+Comment[hu]=Az egyenletek ellenőrzése
+Comment[is]=Athuga jöfnur
+Comment[it]=Controlla equazioni
+Comment[ja]= ç­‰å¼ã‚’検証
+Comment[ka]=ფáƒáƒ áƒ›áƒ£áƒšáƒáƒ—რშემáƒáƒ¬áƒ›áƒ”ბáƒ
+Comment[kk]=Баламаларды текÑеру
+Comment[lt]=Tikrinti lygybes
+Comment[ms]=Periksa Persamaan
+Comment[nb]=Sjekk likninger
+Comment[nds]=Glieken pröven
+Comment[ne]=समीकरण जाà¤à¤š गरà¥à¤¨à¥à¤¹à¥‹à¤¸à¥
+Comment[nl]=Vergelijkingen controleren
+Comment[nn]=Sjekk likningar
+Comment[pa]=ਸਮੀਕਰਨ ਜਾਂਚ
+Comment[pl]=Sprawdzenie równań
+Comment[pt]=Verifica as equações
+Comment[pt_BR]=Verifica Equações
+Comment[ru]=Проверить уравнениÑ
+Comment[sk]=Kontrola rovníc
+Comment[sl]=Preveri enaÄbe
+Comment[sr]=Провери једначине
+Comment[sr@Latn]=Proveri jednaÄine
+Comment[sv]=Kontrollera ekvationer
+Comment[ta]= சமனà¯à®ªà®¾à®Ÿà¯ சரிபாரà¯à®ªà¯à®ªà¯
+Comment[tg]=Тафтиш кардани баробарҳо
+Comment[tr]=Denklemleri Denetle
+Comment[uk]=Перевірити рівнÑннÑ
+Comment[zh_CN]=检查等å¼
+Comment[zh_TW]=檢查等å¼
+ServiceTypes=KDataTool,KBabelValidator
+Shortcuts=Ctrl+J
+ValidationString=equations
+DataType=CatalogItem
+DataMimeTypes=application/x-kbabel-catalogitem
+ReadOnly=true
diff --git a/kbabel/datatools/equations/main.cc b/kbabel/datatools/equations/main.cc
new file mode 100644
index 00000000..bab01785
--- /dev/null
+++ b/kbabel/datatools/equations/main.cc
@@ -0,0 +1,113 @@
+/* This file is part of KBabel
+ based Copyright (C) 1998, 1999 Torben Weis <weis@kde.org>
+ 2002 Stanislav Visnovsky <visnovsky@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.
+
+ In addition, as a special exception, the copyright holders give
+ permission to link the code of this program with any edition of
+ the Qt library by Trolltech AS, Norway (or with modified versions
+ of Qt that use the same license as Qt), and distribute linked
+ combinations including the two. You must obey the GNU General
+ Public License in all respects for all of the code used other than
+ Qt. If you modify this file, you may extend this exception to
+ your version of the file, but you are not obligated to do so. If
+ you do not wish to do so, delete this exception statement from
+ your version.
+
+*/
+
+#include <resources.h>
+#include "catalogitem.h"
+#include "catalogsettings.h"
+#include "main.h"
+
+#include <kconfig.h>
+#include <kdebug.h>
+#include <kgenericfactory.h>
+#include <klibloader.h>
+#include <klocale.h>
+#include <kmessagebox.h>
+
+/***************************************************
+ *
+ * Factory
+ *
+ ***************************************************/
+
+K_EXPORT_COMPONENT_FACTORY( kbabel_equationstool, KGenericFactory<EquationsTool> ( "kbabeldatatool" ) )
+
+using namespace KBabel;
+
+EquationsTool::EquationsTool( QObject* parent, const char* name, const QStringList & )
+ : KDataTool( parent, name ), _equation("^[a-zA-Z0-9]+=.+")
+{
+ i18n("what check found errors","equations");
+}
+
+bool EquationsTool::run( const QString& command, void* data, const QString& datatype, const QString& mimetype )
+{
+ if ( command != "validate" )
+ {
+ kdDebug(KBABEL) << "Equations Tool does only accept the command 'validate' and 'shortcut'" << endl;
+ kdDebug(KBABEL) << " The commands " << command << " is not accepted" << endl;
+ return FALSE;
+ }
+
+ // Check wether we can accept the data
+ if ( datatype != "CatalogItem" )
+ {
+ kdDebug(KBABEL) << "Equations Tool only accepts datatype CatalogItem" << endl;
+ return FALSE;
+ }
+
+ if ( mimetype != "application/x-kbabel-catalogitem" )
+ {
+ kdDebug(KBABEL) << "Equations Tool only accepts mimetype application/x-kbabel-catalogitem" << endl;
+ return FALSE;
+ }
+
+ if( command == "validate" )
+ {
+ CatalogItem* item = (CatalogItem*)(data);
+
+ bool hasError = false;
+
+ if(!item->isUntranslated() && !item->msgid().first().contains('\n')
+ && item->msgid().first().contains(_equation))
+ {
+ int index = item->msgid().first().find('=');
+ QString left = item->msgid().first().left(index);
+ index = item->msgstr().first().find('=');
+ if(left != item->msgstr().first().left(index))
+ hasError = true;
+ }
+
+ if(hasError)
+ {
+ item->appendError( "equations" );
+ }
+ else
+ {
+ item->removeError( "equations" );
+ }
+
+ return !hasError;
+ }
+ return FALSE;
+}
+
+#include "main.moc"
diff --git a/kbabel/datatools/equations/main.h b/kbabel/datatools/equations/main.h
new file mode 100644
index 00000000..6edff1c6
--- /dev/null
+++ b/kbabel/datatools/equations/main.h
@@ -0,0 +1,50 @@
+/* This file is part of KBabel
+ based on Copyright (C) 1998, 1999 Torben Weis <weis@kde.org>
+ 2002 Stanislav Visnovsky <visnovsky@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.
+
+ In addition, as a special exception, the copyright holders give
+ permission to link the code of this program with any edition of
+ the Qt library by Trolltech AS, Norway (or with modified versions
+ of Qt that use the same license as Qt), and distribute linked
+ combinations including the two. You must obey the GNU General
+ Public License in all respects for all of the code used other than
+ Qt. If you modify this file, you may extend this exception to
+ your version of the file, but you are not obligated to do so. If
+ you do not wish to do so, delete this exception statement from
+ your version.
+
+*/
+
+#ifndef __main_h__
+#define __main_h__
+
+#include <qregexp.h>
+#include <kdatatool.h>
+
+class EquationsTool : public KDataTool
+{
+ Q_OBJECT
+
+public:
+ EquationsTool( QObject* parent, const char* name, const QStringList & );
+ virtual bool run( const QString& command, void* data, const QString& datatype, const QString& mimetype);
+private:
+ QRegExp _equation;
+};
+
+#endif
diff --git a/kbabel/datatools/length/Makefile.am b/kbabel/datatools/length/Makefile.am
new file mode 100644
index 00000000..62231402
--- /dev/null
+++ b/kbabel/datatools/length/Makefile.am
@@ -0,0 +1,19 @@
+
+INCLUDES = -I$(srcdir)/../../common -I../../common $(all_includes)
+kbabel_lengthtool_la_LIBADD = $(LIB_KIO) ../../common/libkbabelcommon.la
+
+####### Files
+
+kde_module_LTLIBRARIES = kbabel_lengthtool.la
+
+kbabel_lengthtool_la_SOURCES = main.cc
+
+kbabel_lengthtool_la_LDFLAGS = $(all_libraries) -avoid-version -module -no-undefined
+
+noinst_HEADERS = main.h
+
+kbabel_lengthtool_la_METASOURCES = AUTO
+
+service_DATA = kbabel_lengthtool.desktop
+servicedir = $(kde_servicesdir)
+
diff --git a/kbabel/datatools/length/kbabel_lengthtool.desktop b/kbabel/datatools/length/kbabel_lengthtool.desktop
new file mode 100644
index 00000000..2171f44e
--- /dev/null
+++ b/kbabel/datatools/length/kbabel_lengthtool.desktop
@@ -0,0 +1,98 @@
+[Desktop Entry]
+Name=Translated Message Length Validator for KBabel
+Name[bg]=ВалидноÑÑ‚ на дължината на преведените ÑÑŠÐ¾Ð±Ñ‰ÐµÐ½Ð¸Ñ - KBabel
+Name[bs]=Provjera dužine prevedenih poruka za KBabel
+Name[ca]=Un validador per a KBabel de la llargària dels missatges traduïts
+Name[cs]=Validátor délky přeložených zpráv
+Name[cy]=Dilysydd Hyd Neges wedi'i Gyfieithu ar gyfer KBabel
+Name[da]=Oversat beskedlængde godkender for KBabel
+Name[de]=Überprüfung der übersetzten Nachrichtenlänge für KBabel
+Name[el]=Ελεγκτής εγκυÏότητας μήκους μεταφÏασμένων μηνυμάτων για το KBabel
+Name[eo]=Longeckontrolilo por tradukitaj mesaÄoj
+Name[es]=Validador de longitud de mensajes traducidos para KBabel
+Name[et]=KBabeli tõlgitud teadete pikkuse kontrollija
+Name[eu]=Itzulitako mezu luzera balidatzailea KBabel-entzat
+Name[fa]=اعتبارسنج طول پیام ترجمه‌شده برای KBabel
+Name[fi]=Käännetyn viestin pituuden tarkistus KBabelissa
+Name[fr]=Un validateur de longueur de message pour KBabel
+Name[gl]=Validador do tamaño da mensaxe traducida para KBabel
+Name[hu]=Üzenethossz-ellenőrző a KBabelhez
+Name[is]=Staðfestir á lengd þýddra skeyta fyrir KBabel
+Name[it]=Convalidatore di KBabel per la lunghezza dei messaggi tradotti
+Name[ja]=KBabel 翻訳メッセージã®é•·ã•ã‚’検証
+Name[ka]=ნáƒáƒ—áƒáƒ áƒ’მნი შეტყáƒáƒ‘ინებების სიგრძის დáƒáƒ›áƒáƒ¬áƒ›áƒ”ბრKBabel-სთვის
+Name[kk]=KBabel-дың аударылған жазулардың ұзындығын текÑеруі
+Name[lt]=KBabel išverstų pranešimų ilgio patikros įrankis
+Name[nb]=Sjekk av lengden på oversatte strenger i KBabel
+Name[nds]=Textlängde-Prööv för KBabel
+Name[ne]=केबà¥à¤¯à¤¾à¤¬à¤²à¤•à¤¾ लागि अनà¥à¤¬à¤¾à¤¦ गरिà¤à¤•à¥‹ सनà¥à¤¦à¥‡à¤¶ लमà¥à¤¬à¤¾à¤‡ पà¥à¤°à¤®à¤¾à¤£à¤¿à¤¤à¤•à¤°à¥à¤¤à¤¾
+Name[nl]=Vertaalde-tekstlengte-validatie voor KBabel
+Name[nn]=Sjekk av lengda på omsette strengar i KBabel
+Name[pl]=Sprawdzenie długości przetłumaczonego komunikatu w KBabel
+Name[pt]=Validador do Tamanho da Mensagem Traduzida para o KBabel
+Name[pt_BR]=Um Validador de Tamanho de Mensagem Traduzida para o KBabel
+Name[ru]=Проверка длины переведённых Ñообщений Ð´Ð»Ñ KBabel
+Name[sk]=Kontrola dĺžky preložených textov pre KBabel
+Name[sl]=Potrjevalnik dolžin prevedenih sporoÄil za KBabel
+Name[sr]=Оверивач дужине преведених порука за KBabel
+Name[sr@Latn]=OverivaÄ dužine prevedenih poruka za KBabel
+Name[sv]=Validering av meddelandelängd för översättningar i Kbabel
+Name[ta]= Kபாபேலà¯à®•à¯à®•à®¾à®© மொழிபெயரà¯à®ªà¯à®ªà¯ செயà¯à®¤à®¿ அளவ௠மதிபà¯à®ªà¯€à®Ÿà¯à®Ÿà®¾à®³à®°à¯
+Name[tg]=Утилитаи тафтиши дарозии ахборҳои тарҷумакунанда барои KBabel
+Name[tr]=KBabel için Çevrilen Mesaj Uzunluk Kontrolü
+Name[uk]=Перевірка довжини перекладених фраз Ð´Ð»Ñ KBabel
+Name[zh_CN]=KBabel 已翻译消æ¯çš„长度检查器
+Name[zh_TW]=KBabel 的已翻譯訊æ¯é•·åº¦æª¢æŸ¥å™¨
+ValidationString=length checking
+X-KDE-Library=kbabel_lengthtool
+Type=Service
+Commands=validate
+Comment=Check Translated Message Length
+Comment[bg]=Проверка дължината на преведените ÑъобщениÑ
+Comment[bs]=Provjeri dužinu prevedenih poruka
+Comment[ca]=Comprova la llargària del missatge traduït
+Comment[cs]=Zkontrolovat délku přeložené zprávy
+Comment[cy]=Gwirio hyd neges wedi'i gyfieithu
+Comment[da]=Tjek oversat beskedlængde
+Comment[de]=Prüfung der übersetzten Nachrichtenlänge
+Comment[el]=Έλεγχος μήκους μεταφÏασμένων μηνυμάτων
+Comment[eo]=Kontrolu longecon de tradukita mesaÄo
+Comment[es]=Comprobar longitud de los mensajes traducidos
+Comment[et]=Tõlgitud teate pikkuse kontroll
+Comment[eu]=Egiaztatu itzulitako mezuen luzera
+Comment[fa]=بررسی طول پیام ترجمه‌شده
+Comment[fi]=Tarkista käännetyn viestin pituus
+Comment[fr]=Vérifie la longueur des messages traduits
+Comment[gl]=Verificación do tamaño da mensaxe traducida
+Comment[hi]=अनूदित संदेश लंबाई जाà¤à¤šà¥‡à¤‚
+Comment[hu]=A lefordított üzenetek hosszának ellenőrzése
+Comment[is]=Athuga lengd þýddra skeyta
+Comment[it]=Controlla la lunghezza dei messaggi tradotti
+Comment[ja]=翻訳メッセージã®é•·ã•ã‚’検証
+Comment[ka]=ნáƒáƒ—áƒáƒ áƒ’მნი შეტყáƒáƒ‘ინებების სიგრძის შემáƒáƒ¬áƒ›áƒ”ბáƒ
+Comment[kk]=Ðударылған жазулардың ұзындығын текÑеру
+Comment[lt]=Tikrinti išverstų pranešimų ilgį
+Comment[nb]=Sjekk lengden på oversatte strenger
+Comment[nds]=Översett Textlängde pröven
+Comment[ne]=अनà¥à¤¬à¤¾à¤¦ गरिà¤à¤•à¥‹ सनà¥à¤¦à¥‡à¤¶ लमà¥à¤¬à¤¾à¤‡ जाà¤à¤š गरà¥à¤¨à¥à¤¹à¥‹à¤¸à¥
+Comment[nl]=Lengte van vertaalde tekst controleren
+Comment[nn]=Sjekk lengda på omsette strengar
+Comment[pl]=Sprawdzenie długości przetłumaczonego komunikatu
+Comment[pt]=Verificação do Tamanho da Mensagem Traduzida
+Comment[pt_BR]=Verifica o Comprimento da Mensagem Traduzida
+Comment[ru]=Проверить длину переведённых Ñообщений
+Comment[sk]=Kontrola dĺžky preložených textov
+Comment[sl]=Preveri dolžino prevedenih sporoÄil
+Comment[sr]=Провери дужину преведених порука
+Comment[sr@Latn]=Proveri dužinu prevedenih poruka
+Comment[sv]=Kontrollera meddelandelängd för översättningar
+Comment[ta]= மொழிபெயர௠செயà¯à®¤à®¿ நீளம௠சரிபாரà¯à®ªà¯à®ªà¯
+Comment[tg]=Тафтиш кардани дарозии хабарҳои тарҷумашуда
+Comment[tr]=Çevrilen Mesaj Uzunluğunu Denetle
+Comment[uk]=Перевірити довжину перекладених фраз
+Comment[zh_CN]=检查已翻译消æ¯çš„长度
+Comment[zh_TW]=檢查已翻譯訊æ¯é•·åº¦
+ServiceTypes=KDataTool,KBabelValidator
+DataType=CatalogItem
+DataMimeTypes=application/x-kbabel-catalogitem
+ReadOnly=true
diff --git a/kbabel/datatools/length/main.cc b/kbabel/datatools/length/main.cc
new file mode 100644
index 00000000..ee595dc9
--- /dev/null
+++ b/kbabel/datatools/length/main.cc
@@ -0,0 +1,142 @@
+/* This file is part of KBabel
+ based Copyright (C) 1998, 1999 Torben Weis <weis@kde.org>
+ 2002 Stanislav Visnovsky <visnovsky@kde.org>
+ 2003 Dwayne Bailey <dwayne@translate.org.za>
+
+ 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.
+
+ In addition, as a special exception, the copyright holders give
+ permission to link the code of this program with any edition of
+ the Qt library by Trolltech AS, Norway (or with modified versions
+ of Qt that use the same license as Qt), and distribute linked
+ combinations including the two. You must obey the GNU General
+ Public License in all respects for all of the code used other than
+ Qt. If you modify this file, you may extend this exception to
+ your version of the file, but you are not obligated to do so. If
+ you do not wish to do so, delete this exception statement from
+ your version.
+
+*/
+
+#include <resources.h>
+#include "catalog.h"
+#include "catalogitem.h"
+#include "catalogsettings.h"
+#include "main.h"
+#include <math.h>
+
+#include <kconfig.h>
+#include <kdebug.h>
+#include <kgenericfactory.h>
+#include <klibloader.h>
+#include <klocale.h>
+#include <kmessagebox.h>
+
+/***************************************************
+ *
+ * Factory
+ *
+ ***************************************************/
+
+K_EXPORT_COMPONENT_FACTORY( kbabel_lengthtool, KGenericFactory<LengthTool> ( "kbabeldatatool" ) )
+
+using namespace KBabel;
+
+LengthTool::LengthTool( QObject* parent, const char* name, const QStringList & )
+ : KDataTool( parent, name ), _cache_origin( 0 )
+{
+ i18n("which check found errors","translation has inconsistent length");
+}
+
+bool LengthTool::run( const QString& command, void* data, const QString& datatype, const QString& mimetype )
+{
+
+ if ( command != "validate" )
+ {
+ kdDebug(KBABEL) << "Length Tool only accepts the 'validate' command" << endl;
+ kdDebug(KBABEL) << " The command " << command << " is not accepted" << endl;
+ return false;
+ }
+
+ // Check wether we can accept the data
+ if ( datatype != "CatalogItem" )
+ {
+ kdDebug(KBABEL) << "Length Tool only accept the CatalogItem datatype" << endl;
+ return false;
+ }
+
+ if ( mimetype != "application/x-kbabel-catalogitem" )
+ {
+ kdDebug(KBABEL) << "Length Tool only accept the 'application/x-kbabel-catalogitem' mimetype" << endl;
+ return false;
+ }
+
+ if( command == "validate" )
+ {
+
+ CatalogItem* item = (CatalogItem*)(data);
+ bool hasError = false;
+ QStringList str, id;
+
+ if(!item->isUntranslated()) {
+
+ if( _cache_origin != item->project() )
+ {
+ _context = item->project()->miscSettings().contextInfo;
+ _plurals = item->project()->miscSettings().singularPlural;
+ _cache_origin = item->project();
+ }
+
+ //Ensure KDE plural forms are in a StringList
+ if( item->pluralForm() == KDESpecific ) {
+ str = QStringList::split( "\\n", item->msgstr().first(), true );
+ id = QStringList::split( "\\n",
+ item->msgid().first().replace( QRegExp(_plurals), ""), true );
+ } else {
+ str = item->msgstr();
+ id = item->msgid();
+ }
+
+ //Check for translations that are too short or too long
+ //This may not be totally correct but we check both
+ //the singular and plural forms against each translated plural.
+ //FIXME: replace 10% check with configurable setting or a statistical
+ //based expected length relationship
+ int idlen, strlen;
+ for( QStringList::Iterator i = id.begin() ; i != id.end() ; i++ ) {
+ QString iditem = (*i);
+ idlen = iditem.replace( QRegExp(_context),"").length();
+ for( QStringList::Iterator j = str.begin() ; j != str.end() ; j++ ) {
+ QString stritem = (*j);
+ strlen = stritem.length();
+ hasError = hasError || (strlen < (0.1 * idlen))
+ || (strlen > (10 * idlen));
+ }
+ }
+
+ }
+
+ if(hasError)
+ item->appendError( "translation has inconsistant length" );
+ else
+ item->removeError( "translation has inconsistant length" );
+
+ return !hasError;
+ }
+ return false;
+}
+
+#include "main.moc"
diff --git a/kbabel/datatools/length/main.h b/kbabel/datatools/length/main.h
new file mode 100644
index 00000000..225c91ad
--- /dev/null
+++ b/kbabel/datatools/length/main.h
@@ -0,0 +1,54 @@
+/* This file is part of KBabel
+ based on Copyright (C) 1998, 1999 Torben Weis <weis@kde.org>
+ 2002 Stanislav Visnovsky <visnovsky@kde.org>
+ 2003 Dwayne Bailey <dwayne@translate.org.za>
+
+ 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.
+
+ In addition, as a special exception, the copyright holders give
+ permission to link the code of this program with any edition of
+ the Qt library by Trolltech AS, Norway (or with modified versions
+ of Qt that use the same license as Qt), and distribute linked
+ combinations including the two. You must obey the GNU General
+ Public License in all respects for all of the code used other than
+ Qt. If you modify this file, you may extend this exception to
+ your version of the file, but you are not obligated to do so. If
+ you do not wish to do so, delete this exception statement from
+ your version.
+
+*/
+
+#ifndef __main_h__
+#define __main_h__
+
+#include "kbproject.h"
+
+#include <kdatatool.h>
+
+class LengthTool : public KDataTool
+{
+ Q_OBJECT
+
+public:
+ LengthTool( QObject* parent, const char* name, const QStringList & );
+ virtual bool run( const QString& command, void* data, const QString& datatype, const QString& mimetype);
+private:
+ KBabel::Project::Ptr _cache_origin;
+ QRegExp _context;
+ QRegExp _plurals;
+};
+
+#endif
diff --git a/kbabel/datatools/length/test.po b/kbabel/datatools/length/test.po
new file mode 100644
index 00000000..d1bb209d
--- /dev/null
+++ b/kbabel/datatools/length/test.po
@@ -0,0 +1,46 @@
+# Test file to validate the length checking tool
+# Dwayne Bailey <dwayne@translate.org.za>, 2003
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: test\n"
+"Last-Translator: Dwayne Bailey <dwayne@translate.org.za>\n"
+"PO-Revision-Date: 2003-01-09 09:35+0200\n"
+"Language-Team: <english@translate.org.za>\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"X-Generator: KBabel 1.2\n"
+
+# msgstr < 10% of msgid
+# Expected Result = error
+msgid "Some translation string"
+msgstr "aa"
+
+# msgstr > 10 * length of msgid
+# Expected Result = error
+msgid "Short"
+msgstr "Very long translation of a very short string. "
+"This should be picked up. Not really sure what a more"
+" correct approach might be."
+
+# Shortness test with KDE plural forms
+# Expected Result = error
+msgid ""
+"_n: Some translation string\n"
+"Second form %n"
+msgstr ""
+"aa\n"
+"Second form %n transaltion"
+
+# SHortness test with GNU plural forms
+# Expected Result = error
+msgid "Some translation string"
+msgid_plural "The second form %n"
+msgstr[0] "aa"
+msgstr[1] "Second for %n"
+
+# Shortness test with KDE context info
+# Expected Result = error
+msgid "_: Translation comment\n"
+"Some translation string"
+msgstr "aa"
diff --git a/kbabel/datatools/not-translated/Makefile.am b/kbabel/datatools/not-translated/Makefile.am
new file mode 100644
index 00000000..7ae7fe1c
--- /dev/null
+++ b/kbabel/datatools/not-translated/Makefile.am
@@ -0,0 +1,19 @@
+
+INCLUDES = -I$(srcdir)/../../common -I../../common $(all_includes)
+kbabel_nottranslatedtool_la_LIBADD = $(LIB_KIO) ../../common/libkbabelcommon.la
+
+####### Files
+
+kde_module_LTLIBRARIES = kbabel_nottranslatedtool.la
+
+kbabel_nottranslatedtool_la_SOURCES = main.cc
+
+kbabel_nottranslatedtool_la_LDFLAGS = $(all_libraries) -avoid-version -module -no-undefined
+
+noinst_HEADERS = main.h
+
+kbabel_nottranslatedtool_la_METASOURCES = AUTO
+
+service_DATA = kbabel_nottranslatedtool.desktop
+servicedir = $(kde_servicesdir)
+
diff --git a/kbabel/datatools/not-translated/kbabel_nottranslatedtool.desktop b/kbabel/datatools/not-translated/kbabel_nottranslatedtool.desktop
new file mode 100644
index 00000000..e3c267bf
--- /dev/null
+++ b/kbabel/datatools/not-translated/kbabel_nottranslatedtool.desktop
@@ -0,0 +1,97 @@
+[Desktop Entry]
+Name=Check for Translated Strings Containing English for KBabel
+Name[bg]=Проверка за преведени низове, Ñъдържащи английÑки - KBabel
+Name[bs]=Provjera prevedenih stringova koji sadrže engleski za KBabel
+Name[ca]=Comprova per a KBabel les entrades traduïdes que contenen anglès
+Name[cs]=Vyhledat pÅ™eložené Å™etÄ›zce obsahující angliÄtinu
+Name[cy]=Gwirio am Linynnau wedi'u Cyfieithu sy'n Cynnwys Saesneg i KBabel
+Name[da]=Tjek for oversatte strenge der indeholder engelsk for KBabel
+Name[de]=Überprüfung übersetzter Texte, die Englisch enthalten, für KBabel
+Name[el]=Έλεγχος για μεταφÏασμένα κείμενα που πεÏιέχουν αγγλικά για το KBabel
+Name[es]=Comprobar cadenas traducidas con contenido en inglés para KBabel
+Name[et]=KBabeli inglise keelt sisaldavate tõlgitud teadete kontrollija
+Name[eu]=Bilatu ingeles hitzak itzulitako kateen artean KBabel-entzat
+Name[fa]=بررسی برای رشته‌های ترجمه‌شده حاوی انگلیسی برای KBabel
+Name[fi]=Englantia sisältävien merkkijonojen tarkistus KBabelissa
+Name[fr]=Vérifie si les chaînes traduites contiennent de l'anglais pour KBabel
+Name[gl]=Verificación de mensaxes traducidas que conteñan Inglés para KBabel
+Name[hu]=KBabel-eszköz angol nyelvű részek kereséséhez (a lefordított üzenetekben)
+Name[is]=Leita að þýddum strengjum sem innihalda ensku fyrir KBabel
+Name[it]=Controllo di stringhe tradotte contenenti inglese per KBabel
+Name[ja]=KBabel 翻訳文字列内ã®è‹±èªžã‚’検索
+Name[ka]=ინგლისურის შემცველი ნáƒáƒ—áƒáƒ áƒ’მნი სტრიქáƒáƒœáƒ”ბის შემáƒáƒ¬áƒ›áƒ”ბრKBabel-სთვის
+Name[kk]=KBabel аударылғанда ағылшын жазуы қалғанын текÑеруі
+Name[lt]=KBabel išverstų pranešimų, kuriuose yra anglų kalbos žodžių, patikra
+Name[nb]=Sjekk for oversatte strenger som inneholder engelsk i KBabel
+Name[nds]=Prööv op översett Texten mit Engelsch dor binnen för KBabel
+Name[ne]=केबà¥à¤¯à¤¾à¤¬à¤²à¤•à¤¾ लागि अनà¥à¤¬à¤¾à¤¦ गरिà¤à¤•à¤¾ अङà¥à¤—à¥à¤°à¥‡à¤œà¥€ समाविषà¥à¤Ÿ सà¥à¤Ÿà¥à¤°à¤¿à¤™à¤¹à¤°à¥‚को जाà¤à¤š
+Name[nl]=Controle op vertaalde tekst met Engelse termen voor KBabel
+Name[nn]=Sjekk for omsette strengar som inneheld engelsk i Kbabel
+Name[pl]=Sprawdzenie czy przetłumaczony komunikat zawiera angielskie słowa w KBabel
+Name[pt]=Verificação de Mensagens Traduzidas que Contenham Inglês para o KBabel
+Name[pt_BR]=Verifica por Strings Traduzidos Contendo Inglês para o KBabel
+Name[ru]=Проверка переведённых Ñтрок на равенÑтво оригинальным Ð´Ð»Ñ KBabel
+Name[sk]=Kontrola anglického textu v preklade pre KBabel
+Name[sl]=Preveri prevedene nize, ki vsebujejo angleÅ¡Äino; za KBabel
+Name[sr]=Провера за преведене низове знакова који Ñадрже енглеÑки за KBabel
+Name[sr@Latn]=Provera za prevedene nizove znakova koji sadrže engleski za KBabel
+Name[sv]=Kontrollera översatta strängar som innehåller engelska för Kbabel
+Name[ta]=கேபாபேலà¯à®•à¯à®•à®¾à®© ஆஙà¯à®•à®¿à®² மொழிபெயரà¯à®ªà¯à®ªà¯ சரஙà¯à®•à®³à¯ˆ சோதிகà¯à®•à®µà¯à®®à¯.
+Name[tg]=Тафтиши Ñатрҳои тарҷумашуда ба баробарии аÑлӣ барои KBabel
+Name[tr]=KBabel için İngilizce İhtiva Eden Çevrilen Dizgeler Denetimi
+Name[uk]=Перевірка перекладених фраз на вміÑÑ‚ англійÑької Ð´Ð»Ñ KBabel
+Name[zh_CN]=KBabel 检查已翻译字符串包å«è‹±è¯­çš„工具
+Name[zh_TW]=KBabel 的檢查包å«è‹±æ–‡çš„已翻譯字串
+ValidationString=whitespace checking
+X-KDE-Library=kbabel_nottranslatedtool
+Type=Service
+Commands=validate
+Comment=Translations Containing English
+Comment[bg]=Ðизове, Ñъдържащи английÑки
+Comment[bs]=Prijevodi koji sadrže engleski
+Comment[ca]=Traduccions que contenen l'anglès
+Comment[cs]=PÅ™eklady obsahující angliÄtinu
+Comment[cy]=Cyfieithiadau sy'n cynnwys Saesneg
+Comment[da]=Oversættelser der indeholder engelsk
+Comment[de]=Ãœbersetzungen melden, die englischen Text enthalten
+Comment[el]=ΜεταφÏάσεις που πεÏιέχουν αγγλικά
+Comment[es]=Traducciones con contenido en inglés
+Comment[et]=Inglise keelt sisaldavad tõlked
+Comment[eu]=Inglesa duten itzulpenak
+Comment[fa]=ترجمه‌های حاوی انگلیسی
+Comment[fi]=Käännös sisältää englantia
+Comment[fr]=Traductions contenant de l'anglais
+Comment[gl]=Traducións que conteñen Inglés
+Comment[he]=×ª×¨×’×•×ž×™× ×”×ž×›×™×œ×™× ×נגלית
+Comment[hi]=अंगà¥à¤°à¥‡à¤œà¤¼à¥€ यà¥à¤•à¥à¤¤ अनà¥à¤µà¤¾à¤¦
+Comment[hu]=Angol nyelvű részeket tartalmazó fordítások
+Comment[is]=Þýðingar sem innihalda ensku
+Comment[it]=Traduzioni contenenti inglese
+Comment[ja]=翻訳文字列内ã®è‹±èªžã‚’検索
+Comment[ka]=ინგლისურის შემცველი ნáƒáƒ—áƒáƒ áƒ’მნი
+Comment[kk]=Ðударылғанда ағылшын жазуы қалғанын текÑеру
+Comment[lt]=Vertimai, kuriuose yra anglų kalbos žodžių
+Comment[nb]=Oversettelser som inneholder engelsk
+Comment[nds]=Op Engelsch binnen Översetten pröven
+Comment[ne]=अङà¥à¤—à¥à¤°à¥‡à¤œà¥€ समाविषà¥à¤Ÿ अनà¥à¤¬à¤¾à¤¦
+Comment[nl]=Vertalingen die Engels bevatten controleren
+Comment[nn]=Omsetjingar som inneheld engelsk
+Comment[pa]=ਅੰਗਰੇਜ਼ੀ ਰੱਖਣ ਵਾਲੀ ਅਨà©à¨µà¨¾à¨¦
+Comment[pl]=Sprawdzenie czy przetłumaczony komunikat zawiera angielskie słowa
+Comment[pt]=Traduções Que Contêm Inglês
+Comment[pt_BR]=Traduções Contendo Inglês
+Comment[ru]=Переводы, Ñодержащие английÑкий
+Comment[sk]=Preklady obsahujúce angliÄtinu
+Comment[sl]=Prevodi, ki vsebujo angleÅ¡Äino
+Comment[sr]=Преводи који Ñадрже енглеÑки
+Comment[sr@Latn]=Prevodi koji sadrže engleski
+Comment[sv]=Översättningar som innehåller engelska
+Comment[ta]= ஆஙà¯à®•à®¿à®²à®¤à¯à®¤à®¿à®©à¯ மொழிபெயரà¯à®ªà¯à®ªà¯
+Comment[tg]=Тарҷумаҳое, ки англиÑÓ£ доранд
+Comment[tr]=İngilizce İhtiva eden Çeviriler
+Comment[uk]=Переклади, Ñкі міÑÑ‚ÑÑ‚ÑŒ англійÑьку
+Comment[zh_CN]=翻译包å«è‹±è¯­
+Comment[zh_TW]=包å«è‹±æ–‡çš„翻譯
+ServiceTypes=KDataTool,KBabelValidator
+DataType=CatalogItem
+DataMimeTypes=application/x-kbabel-catalogitem
diff --git a/kbabel/datatools/not-translated/main.cc b/kbabel/datatools/not-translated/main.cc
new file mode 100644
index 00000000..1a53db41
--- /dev/null
+++ b/kbabel/datatools/not-translated/main.cc
@@ -0,0 +1,129 @@
+/* This file is part of KBabel
+ based Copyright (C) 1998, 1999 Torben Weis <weis@kde.org>
+ 2002 Stanislav Visnovsky <visnovsky@kde.org>
+ 2003 Dwayne Bailey <dwayne@translate.org.za>
+
+ 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.
+
+ In addition, as a special exception, the copyright holders give
+ permission to link the code of this program with any edition of
+ the Qt library by Trolltech AS, Norway (or with modified versions
+ of Qt that use the same license as Qt), and distribute linked
+ combinations including the two. You must obey the GNU General
+ Public License in all respects for all of the code used other than
+ Qt. If you modify this file, you may extend this exception to
+ your version of the file, but you are not obligated to do so. If
+ you do not wish to do so, delete this exception statement from
+ your version.
+
+*/
+
+#include <resources.h>
+#include "catalog.h"
+#include "catalogitem.h"
+#include "catalogsettings.h"
+#include "main.h"
+
+#include <kconfig.h>
+#include <kdebug.h>
+#include <kgenericfactory.h>
+#include <klibloader.h>
+#include <klocale.h>
+#include <kmessagebox.h>
+
+/***************************************************
+ *
+ * Factory
+ *
+ ***************************************************/
+
+K_EXPORT_COMPONENT_FACTORY( kbabel_nottranslatedtool, KGenericFactory<NotTranslatedTool> ( "kbabeldatatool" ) )
+
+using namespace KBabel;
+
+NotTranslatedTool::NotTranslatedTool( QObject* parent, const char* name, const QStringList & )
+ : KDataTool( parent, name ) , _cache_origin( 0 )
+{
+ i18n("which check found errors","English text in translation");
+}
+
+bool NotTranslatedTool::run( const QString& command, void* data, const QString& datatype, const QString& mimetype )
+{
+
+ if ( command != "validate" )
+ {
+ kdDebug(KBABEL) << "Not Translated Tool only accepts the 'validate' command" << endl;
+ kdDebug(KBABEL) << " The command " << command << " is not accepted" << endl;
+ return false;
+ }
+
+ // Check wether we can accept the data
+ if ( datatype != "CatalogItem" )
+ {
+ kdDebug(KBABEL) << "Not Translated Tool only accept the CatalogItem datatype" << endl;
+ return false;
+ }
+
+ if ( mimetype != "application/x-kbabel-catalogitem" )
+ {
+ kdDebug(KBABEL) << "Not Translated Tool only accept the 'application/x-kbabel-catalogitem' mimetype" << endl;
+ return false;
+ }
+
+ if( command == "validate" )
+ {
+ CatalogItem* item = (CatalogItem*)(data);
+ bool hasError = false;
+
+ if(!item->isUntranslated()) {
+ if( _cache_origin != item->project() )
+ {
+ _context = item->project()->miscSettings().contextInfo;
+ _plurals = item->project()->miscSettings().singularPlural;
+ _cache_origin = item->project();
+ }
+
+ //FIXME Expand this to do substring matching of non-translation
+ QStringList id, str;
+ if( item->pluralForm() == KDESpecific ) {
+ str = QStringList::split( "\\n", item->msgstr().first(), true );
+ id = QStringList::split( "\\n",
+ item->msgid().first().replace( QRegExp(_plurals), ""), true );
+ } else {
+ str = item->msgstr();
+ id = item->msgid();
+ }
+ for( QStringList::Iterator i = id.begin() ; i != id.end() ; i++ ) {
+ QString id_str = (*i).replace( QRegExp(_context), "");
+ for( QStringList::Iterator j = str.begin() ; j != str.end() ; j++ ) {
+ QString str_str = (*j);
+ hasError = hasError || ( id_str == str_str );
+ }
+ }
+
+ }
+
+ if(hasError)
+ item->appendError( "english text in translation" );
+ else
+ item->removeError( "english text in translation" );
+
+ return !hasError;
+ }
+ return false;
+}
+
+#include "main.moc"
diff --git a/kbabel/datatools/not-translated/main.h b/kbabel/datatools/not-translated/main.h
new file mode 100644
index 00000000..7386c4d8
--- /dev/null
+++ b/kbabel/datatools/not-translated/main.h
@@ -0,0 +1,55 @@
+/* This file is part of KBabel
+ based on Copyright (C) 1998, 1999 Torben Weis <weis@kde.org>
+ 2002 Stanislav Visnovsky <visnovsky@kde.org>
+ 2003 Dwayne Bailey <dwayne@translate.org.za>
+
+ 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.
+
+ In addition, as a special exception, the copyright holders give
+ permission to link the code of this program with any edition of
+ the Qt library by Trolltech AS, Norway (or with modified versions
+ of Qt that use the same license as Qt), and distribute linked
+ combinations including the two. You must obey the GNU General
+ Public License in all respects for all of the code used other than
+ Qt. If you modify this file, you may extend this exception to
+ your version of the file, but you are not obligated to do so. If
+ you do not wish to do so, delete this exception statement from
+ your version.
+
+*/
+
+#ifndef __main_h__
+#define __main_h__
+
+#include "kbproject.h"
+
+#include <kdatatool.h>
+
+class NotTranslatedTool : public KDataTool
+{
+ Q_OBJECT
+
+public:
+ NotTranslatedTool( QObject* parent, const char* name, const QStringList & );
+ virtual bool run( const QString& command, void* data, const QString& datatype, const QString& mimetype);
+
+private:
+ KBabel::Project::Ptr _cache_origin;
+ QRegExp _context;
+ QRegExp _plurals;
+};
+
+#endif
diff --git a/kbabel/datatools/not-translated/test.po b/kbabel/datatools/not-translated/test.po
new file mode 100644
index 00000000..5af47fc5
--- /dev/null
+++ b/kbabel/datatools/not-translated/test.po
@@ -0,0 +1,48 @@
+# translation of test.po to
+# Test file to validate the not-translted checking tool
+# Dwayne Bailey <dwayne@translate.org.za>, 2003
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: test-not-translated\n"
+"Last-Translator: Dwayne Bailey <dwayne@translate.org.za>\n"
+"PO-Revision-Date: 2003-01-09 09:35+0200\n"
+"Language-Team: <english@translate.org.za>\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"X-Generator: KBabel 1.2\n"
+
+# msgid has not been translted but copied
+# Expected Result = error
+msgid "Same"
+msgstr "Same"
+
+# msgid has not been translted but copied
+# Expected Result = error
+msgid "Some translation string"
+msgstr "Some translation string"
+
+# msgstr contains a sentence that has not been translted
+# Expected Result = error
+msgid "The first sentence. A second sentence. Lastly a third."
+msgstr "Die eerste sin. A second sentence. Lastens 'n derde."
+
+# A same translation with context information
+# Expected Result = error
+msgid "_: Some context information\n"
+"Same"
+msgstr "Same"
+
+# A KDE plural form with the same translation
+# Expected Result == error
+msgid "_n: The first string\n"
+"The second string"
+msgstr "The first string\n"
+"The first string has not been translated"
+
+# A Gettext plural form with the same translation
+# Expected Result == error
+msgid "The first string"
+msgid_plural "The second string"
+msgstr[0] "The first string"
+msgstr[1] "The first string has not been translated"
diff --git a/kbabel/datatools/pluralforms/Makefile.am b/kbabel/datatools/pluralforms/Makefile.am
new file mode 100644
index 00000000..b7d50e80
--- /dev/null
+++ b/kbabel/datatools/pluralforms/Makefile.am
@@ -0,0 +1,19 @@
+
+INCLUDES = -I$(srcdir)/../../common -I../../common $(all_includes)
+kbabel_pluraltool_la_LIBADD = $(LIB_KIO) ../../common/libkbabelcommon.la
+
+####### Files
+
+kde_module_LTLIBRARIES = kbabel_pluraltool.la
+
+kbabel_pluraltool_la_SOURCES = main.cc
+
+kbabel_pluraltool_la_LDFLAGS = $(all_libraries) -avoid-version -module -no-undefined
+
+noinst_HEADERS = main.h
+
+kbabel_pluraltool_la_METASOURCES = AUTO
+
+service_DATA = kbabel_pluralformstool.desktop
+servicedir = $(kde_servicesdir)
+
diff --git a/kbabel/datatools/pluralforms/kbabel_pluralformstool.desktop b/kbabel/datatools/pluralforms/kbabel_pluralformstool.desktop
new file mode 100644
index 00000000..5d579994
--- /dev/null
+++ b/kbabel/datatools/pluralforms/kbabel_pluralformstool.desktop
@@ -0,0 +1,101 @@
+[Desktop Entry]
+Name=Plural Form Validation for KBabel
+Name[bg]=ВалидноÑÑ‚ на мн. форми - KBabel
+Name[bs]=Provjera formi množine za KBabel
+Name[ca]=Validació de les formes plurals per a KBabel
+Name[cs]=Validace množného Äísla
+Name[cy]=Dilysu Ffurf Lluosryw i KBabel
+Name[da]=Validering af flertalsformer for KBabel
+Name[de]=Pluralform-Überprüfung für KBabel
+Name[el]=Έλεγχος εγκυÏότητας φοÏμών Ï€Î»Î·Î¸Ï…Î½Ï„Î¹ÎºÎ¿Ï Î³Î¹Î± το KBabel
+Name[es]=Validación de formas plurales para KBabel
+Name[et]=KBabeli mitmusevormide kontrollija
+Name[eu]=Plural forma balidazioa KBabel-entzat
+Name[fa]=اعتبارسنجی شکل جمع برای KBabel
+Name[fi]=Monikkomuotojen tarkistus KBabelissa
+Name[fr]=Validation des formes plurielles pour KBabel
+Name[gl]=Validación de formas do plural para KBabel
+Name[hi]=के-बेबल के लिठबहà¥à¤µà¤šà¤¨ फारà¥à¤® वेलिडेशन
+Name[hu]=A többes szám ellenőrzése a KBabelben
+Name[is]=Staðfesting fleirtöluforma fyrir KBabel
+Name[it]=Convalida delle forme plurali per KBabel
+Name[ja]=KBabel 複数形検証
+Name[ka]=მრáƒáƒ•áƒšáƒáƒ‘ითი ფáƒáƒ áƒ›áƒ”ბის დáƒáƒ›áƒ›áƒáƒ¬áƒ›áƒ”ბელი KBabel-სთვის
+Name[kk]=KBabel-дың көптік жалғауын текÑеруі
+Name[lt]=KBabel daugiskaitos formų patikros įrankis
+Name[ms]=Pengesahan Bentuk Jama' untuk KBabel
+Name[nb]=Sjekk flertallsformer i KBabel
+Name[nds]=Pluralformprööv för KBabel
+Name[ne]=केबà¥à¤¯à¤¾à¤¬à¤²à¤•à¤¾ लागि बहà¥à¤¬à¤šà¤¨ पà¥à¤°à¤®à¤¾à¤£à¥€à¤•à¤°à¤£
+Name[nl]=Meervoudsvormenvalidatie voor KBabel
+Name[nn]=Sjekk fleirtalsformer i KBabel
+Name[pl]=Sprawdzenie form liczby mnogiej w KBabel
+Name[pt]=Validação de Formas Plurais para o KBabel
+Name[pt_BR]=Validação de Formas Plurais para o KBabel
+Name[ru]=Проверка множеÑтвенных форм Ð´Ð»Ñ KBabel
+Name[sk]=Kontrola množných Äísel pre KBabel
+Name[sl]=Potrjevalnik množinskih oblik za KBabel
+Name[sr]=Овера облика множине за KBabel
+Name[sr@Latn]=Overa oblika množine za KBabel
+Name[sv]=Validering av pluralformer för Kbabel
+Name[ta]= Kபாபேலலà¯à®•à¯à®•à¯ தரà¯à®®à®¤à®¿à®ªà¯à®ªà¯ பனà¯à®®à¯ˆ வடிவமà¯
+Name[tg]=Тафтиши шаклҳои биÑÑ‘Ñ€ барои KBabel
+Name[tr]=KBabel için Çoklu Form Denetimi
+Name[uk]=Перевірка форм множини Ð´Ð»Ñ KBabel
+Name[zh_CN]=KBabel çš„å¤æ•°å½¢å¼æ£€æŸ¥å™¨
+Name[zh_TW]=KBabel 的單複數型檢查器
+ValidationString=plural forms
+X-KDE-Library=kbabel_pluraltool
+Type=Service
+Commands=validate
+Comment=Check Plural Forms
+Comment[bg]=Проверка на мн. форми
+Comment[bs]=Provjeri forme množine
+Comment[ca]=Comprova les formes plurals
+Comment[cs]=Zkontrolovat množné Äíslo
+Comment[cy]=Gwirio Ffurfiau Lluosryw
+Comment[da]=Tjek flertalsformer
+Comment[de]=Überprüfung von Plural-Formen
+Comment[el]=Έλεγχος φοÏμών πληθυντικοÏ
+Comment[es]=Comprobar formas plurales
+Comment[et]=Mitmuse vormide kontroll
+Comment[eu]=Egiaztatu plural formak
+Comment[fa]=بررسی شکلهای جمع
+Comment[fi]=Tarkista monikkomuodot
+Comment[fr]=Vérifie les formes plurielles
+Comment[gl]=Verificación de formas plurais
+Comment[he]=בודק מצבי רבי×
+Comment[hi]=बहà¥à¤µà¤šà¤¨ जाà¤à¤šà¥‡à¤‚
+Comment[hu]=A többes számú alakok ellenőrzése
+Comment[is]=Athuga fleirtöluform
+Comment[it]=Controlla forme plurali
+Comment[ja]=複数形を検証
+Comment[ka]=მრáƒáƒ•áƒšáƒáƒ‘ითი ფáƒáƒ áƒ›áƒ”ბის შემáƒáƒ¬áƒ›áƒ”ბáƒ
+Comment[kk]=Көптік жалғауын текÑеру
+Comment[lt]=Tikrinti daugiskaitos formas
+Comment[ms]=Periksa Bentuk Jama'
+Comment[nb]=Sjekk flertallsformer
+Comment[nds]=Pluralformen pröven
+Comment[ne]=बहà¥à¤¬à¤šà¤¨ जाà¤à¤š गरà¥à¤¨à¥à¤¹à¥‹à¤¸à¥
+Comment[nl]=Meervoudsvormen controleren
+Comment[nn]=Sjekk fleirtalsformer
+Comment[pa]=ਬਹà©-ਵਚਨ ਫਾਰਮ ਜਾਂਚ
+Comment[pl]=Sprawdzenie form liczby mnogiej
+Comment[pt]=Verificação de Formas Plurais
+Comment[pt_BR]=Verifica Formas Plurais
+Comment[ru]=Проверить множеÑтвенные формы
+Comment[sk]=Kontrola množných Äísel
+Comment[sl]=Preveri množinske oblike
+Comment[sr]=Провери облике множине
+Comment[sr@Latn]=Proveri oblike množine
+Comment[sv]=Kontrollera pluralformer
+Comment[ta]= சரிபாரà¯à®ªà¯à®ªà¯
+Comment[tg]=Тафтиш кардани шаклҳои биÑÑ‘Ñ€
+Comment[tr]=Çoklu Formları denetle
+Comment[uk]=Перевірити форми множини
+Comment[zh_CN]=检查å¤æ•°å½¢å¼
+Comment[zh_TW]=檢查單複數型
+ServiceTypes=KDataTool,KBabelValidator
+DataType=CatalogItem
+DataMimeTypes=application/x-kbabel-catalogitem
+ReadOnly=true
diff --git a/kbabel/datatools/pluralforms/main.cc b/kbabel/datatools/pluralforms/main.cc
new file mode 100644
index 00000000..a534df6e
--- /dev/null
+++ b/kbabel/datatools/pluralforms/main.cc
@@ -0,0 +1,129 @@
+/* This file is part of KBabel
+ based Copyright (C) 1998, 1999 Torben Weis <weis@kde.org>
+ 2002 Stanislav Visnovsky <visnovsky@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.
+
+ In addition, as a special exception, the copyright holders give
+ permission to link the code of this program with any edition of
+ the Qt library by Trolltech AS, Norway (or with modified versions
+ of Qt that use the same license as Qt), and distribute linked
+ combinations including the two. You must obey the GNU General
+ Public License in all respects for all of the code used other than
+ Qt. If you modify this file, you may extend this exception to
+ your version of the file, but you are not obligated to do so. If
+ you do not wish to do so, delete this exception statement from
+ your version.
+
+*/
+
+#include <resources.h>
+#include "catalog.h"
+#include "catalogitem.h"
+#include "catalogsettings.h"
+#include "main.h"
+
+#include <kconfig.h>
+#include <kdebug.h>
+#include <kgenericfactory.h>
+#include <klibloader.h>
+#include <klocale.h>
+#include <kmessagebox.h>
+
+/***************************************************
+ *
+ * Factory
+ *
+ ***************************************************/
+
+K_EXPORT_COMPONENT_FACTORY( kbabel_pluraltool, KGenericFactory<PluralsTool> ( "kbabeldatatool" ) )
+
+using namespace KBabel;
+
+PluralsTool::PluralsTool( QObject* parent, const char* name, const QStringList & )
+ : KDataTool( parent, name ), _cache_origin( 0 ), _neededForms(-1)
+{
+ i18n("what check found errors", "plural forms");
+}
+
+bool PluralsTool::run( const QString& command, void* data, const QString& datatype, const QString& mimetype )
+{
+ if ( command != "validate" )
+ {
+ kdDebug(KBABEL) << "Plural Forms Tool does only accept the command 'validate' and 'shortcut'" << endl;
+ kdDebug(KBABEL) << " The commands " << command << " is not accepted" << endl;
+ return FALSE;
+ }
+
+ // Check wether we can accept the data
+ if ( datatype != "CatalogItem" )
+ {
+ kdDebug(KBABEL) << "Plural Forms Tool only accepts datatype CatalogItem" << endl;
+ return FALSE;
+ }
+
+ if ( mimetype != "application/x-kbabel-catalogitem" )
+ {
+ kdDebug(KBABEL) << "Plural Forms Tool only accepts mimetype application/x-kbabel-catalogitem" << endl;
+ return FALSE;
+ }
+
+ if( command == "validate" )
+ {
+ if( _neededForms < 0 )
+ {
+ Catalog* cat = new Catalog(this);
+ _neededForms = cat->defaultNumberOfPluralForms();
+ delete cat;
+ }
+
+ CatalogItem* item = (CatalogItem*)(data);
+
+ if( _cache_origin != item->project() )
+ {
+ _plurals = item->project()->miscSettings().singularPlural;
+ _cache_origin = item->project();
+ }
+
+ bool hasError = false;
+
+ if(!item->isUntranslated() && item->pluralForm() == KDESpecific )
+ {
+ if(_neededForms <= 0 || item->msgstr().first().contains(_plurals))
+ {
+ hasError = true;
+ }
+ else if( item->msgstr().first().contains(QString("\\n"))+1 != _neededForms )
+ {
+ hasError = true;
+ }
+ }
+
+ if(hasError)
+ {
+ item->appendError( "plural forms" );
+ }
+ else
+ {
+ item->removeError( "plural forms" );
+ }
+
+ return !hasError;
+ }
+ return FALSE;
+}
+
+#include "main.moc"
diff --git a/kbabel/datatools/pluralforms/main.h b/kbabel/datatools/pluralforms/main.h
new file mode 100644
index 00000000..1537f38f
--- /dev/null
+++ b/kbabel/datatools/pluralforms/main.h
@@ -0,0 +1,53 @@
+/* This file is part of KBabel
+ based on Copyright (C) 1998, 1999 Torben Weis <weis@kde.org>
+ 2002 Stanislav Visnovsky <visnovsky@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.
+
+ In addition, as a special exception, the copyright holders give
+ permission to link the code of this program with any edition of
+ the Qt library by Trolltech AS, Norway (or with modified versions
+ of Qt that use the same license as Qt), and distribute linked
+ combinations including the two. You must obey the GNU General
+ Public License in all respects for all of the code used other than
+ Qt. If you modify this file, you may extend this exception to
+ your version of the file, but you are not obligated to do so. If
+ you do not wish to do so, delete this exception statement from
+ your version.
+
+*/
+
+#ifndef __main_h__
+#define __main_h__
+
+#include "kbproject.h"
+
+#include <kdatatool.h>
+
+class PluralsTool : public KDataTool
+{
+ Q_OBJECT
+
+public:
+ PluralsTool( QObject* parent, const char* name, const QStringList & );
+ virtual bool run( const QString& command, void* data, const QString& datatype, const QString& mimetype);
+private:
+ KBabel::Project::Ptr _cache_origin;
+ QRegExp _plurals;
+ int _neededForms;
+};
+
+#endif
diff --git a/kbabel/datatools/punctuation/Makefile.am b/kbabel/datatools/punctuation/Makefile.am
new file mode 100644
index 00000000..5f00234c
--- /dev/null
+++ b/kbabel/datatools/punctuation/Makefile.am
@@ -0,0 +1,19 @@
+
+INCLUDES = -I$(srcdir)/../../common -I../../common $(all_includes)
+kbabel_punctuationtool_la_LIBADD = $(LIB_KIO) ../../common/libkbabelcommon.la
+
+####### Files
+
+kde_module_LTLIBRARIES = kbabel_punctuationtool.la
+
+kbabel_punctuationtool_la_SOURCES = main.cc
+
+kbabel_punctuationtool_la_LDFLAGS = $(all_libraries) -avoid-version -module -no-undefined
+
+noinst_HEADERS = main.h
+
+kbabel_punctuationtool_la_METASOURCES = AUTO
+
+service_DATA = kbabel_punctuationtool.desktop
+servicedir = $(kde_servicesdir)
+
diff --git a/kbabel/datatools/punctuation/kbabel_punctuationtool.desktop b/kbabel/datatools/punctuation/kbabel_punctuationtool.desktop
new file mode 100644
index 00000000..c24ff52e
--- /dev/null
+++ b/kbabel/datatools/punctuation/kbabel_punctuationtool.desktop
@@ -0,0 +1,101 @@
+[Desktop Entry]
+Name=Punctuation Validation for KBabel
+Name[bg]=ВалидноÑÑ‚ на препинателните знаци - KBabel
+Name[bs]=Provjera znakova interpunkcije za KBabel
+Name[ca]=Validació de la puntuació per a KBabel
+Name[cs]=Validace interpunkce
+Name[cy]=Dilysiant Hafaliad i KBabel
+Name[da]=Godkendelse af tegnsætning i KBabel
+Name[de]=Interpunktions-Überprüfung für KBabel
+Name[el]=Έλεγχος εγκυÏότητας στίξης για το KBabel
+Name[es]=Validación de puntuación para KBabel
+Name[et]=KBabeli kirjavahemärkide kontrollija
+Name[eu]=Puntuazio balidazioa KBabel-entzat
+Name[fa]=اعتبارسنجی نقطه‌گذاری برای KBabel
+Name[fi]=Välimerkkien tarkistus KBabelissa
+Name[fr]=Validation de ponctuation pour KBabel
+Name[ga]=Bailíochtú na Poncaíochta le haghaidh KBabel
+Name[gl]=Validación da puntuación para KBabel
+Name[hi]=के-बेबल के लिठविरामचिहà¥à¤¨ वेलिडेशन
+Name[hu]=ÃrásjelellenÅ‘rzÅ‘ a KBabelhez
+Name[is]=Staðfesting greinamerkja fyrir KBabel
+Name[it]=Convalida della punteggiatura per KBabel
+Name[ja]=KBabel å¥èª­ç‚¹æ¤œè¨¼
+Name[ka]=პუნქტუáƒáƒªáƒ˜áƒ˜áƒ¡ დáƒáƒ›áƒ›áƒáƒ¬áƒ›áƒ”ბელი KBabel-სთვის
+Name[kk]=KBabel-дың Ñ‚Ñ‹Ð½Ñ‹Ñ Ð±ÐµÐ»Ð³Ñ–Ð»ÐµÑ€Ñ–Ð½ текÑеруі
+Name[lt]=KBabel skyrybos patikros įrankis
+Name[nb]=Sjekk tegnsetting i KBabel
+Name[nds]=Interpunkschoonprööv för KBabel
+Name[ne]=केबà¥à¤¯à¤¾à¤¬à¤²à¤•à¤¾ लागि बिराम चिनà¥à¤¹ पà¥à¤°à¤®à¤¾à¤£à¥€à¤•à¤°à¤£
+Name[nl]=Punctuatievalidatie voor KBabel
+Name[nn]=Sjekk teiknsetjing i KBabel
+Name[pl]=Sprawdzenie interpunkcji w KBabel
+Name[pt]=Validação de Pontuação para o KBabel
+Name[pt_BR]=Validação de Pontuação para o KBabel
+Name[ru]=Проверка пунктуации Ð´Ð»Ñ KBabel
+Name[sk]=Kontrola interpunkcie pre KBabel
+Name[sl]=Potrjevalnik loÄil za KBabel
+Name[sr]=Овера интерпункције за KBabel
+Name[sr@Latn]=Overa interpunkcije za KBabel
+Name[sv]=Validering av skiljetecken för Kbabel
+Name[ta]= Kபாபேலà¯à®•à¯à®•à¯ தரà¯à®®à®¤à®¿à®ªà¯à®ªà¯ கà¯à®±à®¿à®•à®³à¯
+Name[tg]=Тафтиши пунктуатÑÐ¸Ñ Ð±Ð°Ñ€Ð¾Ð¸ KBabel
+Name[tr]=KBabel için Noktalama denetimi
+Name[uk]=Перевірка пунктуації Ð´Ð»Ñ KBabel
+Name[zh_CN]=KBabel 的标点检查器
+Name[zh_TW]=KBabel 的標點檢查器
+ValidationString=accelerator
+X-KDE-Library=kbabel_punctuationtool
+Type=Service
+Commands=validate
+Comment=Check Punctuation
+Comment[bg]=Проверка на препинателните знаци
+Comment[bs]=Provjeri interpunkciju
+Comment[ca]=Comprova la puntuació
+Comment[cs]=Zkontrolovat interpunkci
+Comment[cy]=Gwirio Hafaliadau
+Comment[da]=Tjek tegnsætning
+Comment[de]=Prüfung der Interpunktion in Übersetzungen
+Comment[el]=Έλεγχος στίξης
+Comment[es]=Comprobar puntuación
+Comment[et]=Kirjavahemärkide kontroll
+Comment[eu]=Egiaztatu puntuazioa
+Comment[fa]=بررسی نقطه‌سنجی
+Comment[fi]=Tarkista välimerkit
+Comment[fr]=Vérifie la ponctuation
+Comment[ga]=Seiceáil Poncaíocht
+Comment[gl]=Verifica a puntuación
+Comment[he]=בודק ניקוד
+Comment[hi]=विरामचिहà¥à¤¨ जांच करें
+Comment[hu]=Az írásjelek ellenőrzése
+Comment[is]=Athuga greinamerki
+Comment[it]=Controlla punteggiatura
+Comment[ja]=å¥èª­ç‚¹ã‚’検証
+Comment[ka]=პუნქტუáƒáƒªáƒ˜áƒ˜áƒ¡ შემáƒáƒ¬áƒ›áƒ”ბáƒ
+Comment[kk]=Ð¢Ñ‹Ð½Ñ‹Ñ Ð±ÐµÐ»Ð³Ñ–Ð»ÐµÑ€Ñ–Ð½ текÑеру
+Comment[lt]=Tikrinti skyrybÄ…
+Comment[nb]=Sjekk tegnsetting
+Comment[nds]=Interpunkschoon pröven
+Comment[ne]=बिराम चिनà¥à¤¹ जाà¤à¤š गरà¥à¤¨à¥à¤¹à¥‹à¤¸à¥
+Comment[nl]=Punctuatie controleren
+Comment[nn]=Sjekk teiknsetjing
+Comment[pl]=Sprawdzenie interpunkcji
+Comment[pt]=Verifica a pontuação
+Comment[pt_BR]=Verifica Pontuação
+Comment[ru]=Проверить пунктуацию
+Comment[sk]=Kontrola interpunkcie
+Comment[sl]=Preveri loÄila
+Comment[sr]=Провери интерпункцију
+Comment[sr@Latn]=Proveri interpunkciju
+Comment[sv]=Kontrollera skiljetecken
+Comment[ta]= நிறà¯à®¤à¯à®¤à®•à¯à®•à¯à®±à®¿à®¯à®¿à®Ÿà¯à®¤à®²à¯ சரிபாரà¯à®ªà¯à®ªà¯
+Comment[tg]=Тафтиш кардани пунктуатÑиÑ
+Comment[tr]=Noktalama Denetimi
+Comment[uk]=Перевірити пунктуацію
+Comment[zh_CN]=检查标点
+Comment[zh_TW]=檢查標點
+Shortcuts=Ctrl+P
+ServiceTypes=KBabelValidator,KDataTool
+DataType=CatalogItem
+DataMimeTypes=application/x-kbabel-catalogitem
+ReadOnly=true
diff --git a/kbabel/datatools/punctuation/main.cc b/kbabel/datatools/punctuation/main.cc
new file mode 100644
index 00000000..bd4f4107
--- /dev/null
+++ b/kbabel/datatools/punctuation/main.cc
@@ -0,0 +1,157 @@
+/* This file is part of KBabel
+ based Copyright (C) 1998, 1999 Torben Weis <weis@kde.org>
+ 2003 Stanislav Visnovsky <visnovsky@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.
+
+ In addition, as a special exception, the copyright holders give
+ permission to link the code of this program with any edition of
+ the Qt library by Trolltech AS, Norway (or with modified versions
+ of Qt that use the same license as Qt), and distribute linked
+ combinations including the two. You must obey the GNU General
+ Public License in all respects for all of the code used other than
+ Qt. If you modify this file, you may extend this exception to
+ your version of the file, but you are not obligated to do so. If
+ you do not wish to do so, delete this exception statement from
+ your version.
+
+*/
+
+#include <resources.h>
+#include "catalogitem.h"
+#include "catalogsettings.h"
+#include "main.h"
+
+#include <kconfig.h>
+#include <kdebug.h>
+#include <kgenericfactory.h>
+#include <klibloader.h>
+#include <klocale.h>
+
+/***************************************************
+ *
+ * Factory
+ *
+ ***************************************************/
+
+K_EXPORT_COMPONENT_FACTORY( kbabel_punctuationtool, KGenericFactory<PunctuationTool> ( "kbabeldatatool" ) )
+
+using namespace KBabel;
+
+PunctuationTool::PunctuationTool( QObject* parent, const char* name, const QStringList & )
+ : KDataTool( parent, name )
+{
+ // bogus translation just for allowing the translation
+ i18n("what check found errors","punctuation");
+}
+
+bool PunctuationTool::run( const QString& command, void* data, const QString& datatype, const QString& mimetype )
+{
+ if ( command != "validate" )
+ {
+ kdDebug(KBABEL) << "Punctuation Tool does only accept the command 'validate'" << endl;
+ kdDebug(KBABEL) << " The commands " << command << " is not accepted" << endl;
+ return FALSE;
+ }
+
+ // Check wether we can accept the data
+ if ( datatype != "CatalogItem" )
+ {
+ kdDebug(KBABEL) << "Punctuation Tool only accepts datatype CatalogItem" << endl;
+ return FALSE;
+ }
+
+ if ( mimetype != "application/x-kbabel-catalogitem" )
+ {
+ kdDebug(KBABEL) << "Punctuation Tool only accepts mimetype application/x-kbabel-catalogitem" << endl;
+ return FALSE;
+ }
+
+ if( command == "validate" )
+ {
+ CatalogItem* item = (CatalogItem*)(data);
+
+ bool hasError = false;
+
+ if(!item->isUntranslated())
+ {
+ QString lineid=item->msgid().first();
+
+ // lookup punctuation in original text
+ QRegExp punc("[\\.!\\?:]+$");
+ int i = lineid.find(punc);
+
+ QString t("");
+
+ if( i != -1 ) t = lineid.right(lineid.length()-i);
+
+ if( item->pluralForm() != NoPluralForm )
+ {
+ // check, that both plural forms contain the same punctuation
+ QString pl = *(item->msgid().at(1));
+ int j = pl.find(punc);
+
+ QString tp("");
+ if( j != -1 ) tp = pl.right(pl.length()-j);
+
+ if( tp != t )
+ {
+ kdWarning() << "Singular and plural form do not have the same punctuation" << endl;
+ }
+ }
+
+ QStringList forms = item->msgstr(true);
+ if( item->pluralForm() == KDESpecific ) {
+ forms = QStringList::split("\\n",*item->msgstr(true).at(0));
+ }
+
+ for( QStringList::Iterator form = forms.begin() ; form != forms.end(); form++ )
+ {
+ QString linestr=(*form);
+
+ int j = linestr.find(punc);
+
+ // there is no punctuation in original, but one in the translation
+ if( i == -1 && j != i )
+ {
+ hasError = true;
+ break;
+ }
+
+ // there is punctuation in original, but not same as in the translation
+ if( i != -1 && linestr.right(linestr.length()-j) != t )
+ {
+ hasError = true;
+ break;
+ }
+ }
+ }
+
+ if(hasError)
+ {
+ item->appendError( "punctuation" );
+ }
+ else
+ {
+ item->removeError( "punctuation" );
+ }
+
+ return !hasError;
+ }
+ return FALSE;
+}
+
+#include "main.moc"
diff --git a/kbabel/datatools/punctuation/main.h b/kbabel/datatools/punctuation/main.h
new file mode 100644
index 00000000..c0c68518
--- /dev/null
+++ b/kbabel/datatools/punctuation/main.h
@@ -0,0 +1,47 @@
+/* This file is part of KBabel
+ based on Copyright (C) 1998, 1999 Torben Weis <weis@kde.org>
+ 2003 Stanislav Visnovsky <visnovsky@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.
+
+ In addition, as a special exception, the copyright holders give
+ permission to link the code of this program with any edition of
+ the Qt library by Trolltech AS, Norway (or with modified versions
+ of Qt that use the same license as Qt), and distribute linked
+ combinations including the two. You must obey the GNU General
+ Public License in all respects for all of the code used other than
+ Qt. If you modify this file, you may extend this exception to
+ your version of the file, but you are not obligated to do so. If
+ you do not wish to do so, delete this exception statement from
+ your version.
+
+*/
+
+#ifndef __main_h__
+#define __main_h__
+
+#include <kdatatool.h>
+
+class PunctuationTool : public KDataTool
+{
+ Q_OBJECT
+
+public:
+ PunctuationTool( QObject* parent, const char* name, const QStringList & );
+ virtual bool run( const QString& command, void* data, const QString& datatype, const QString& mimetype);
+};
+
+#endif
diff --git a/kbabel/datatools/regexp/Makefile.am b/kbabel/datatools/regexp/Makefile.am
new file mode 100644
index 00000000..e727ca25
--- /dev/null
+++ b/kbabel/datatools/regexp/Makefile.am
@@ -0,0 +1,21 @@
+
+INCLUDES = -I$(srcdir)/../../common -I../../common $(all_includes)
+kbabel_regexptool_la_LIBADD = $(LIB_KIO) ../../common/libkbabelcommon.la
+
+####### Files
+
+kde_module_LTLIBRARIES = kbabel_regexptool.la
+
+kbabel_regexptool_la_SOURCES = main.cc
+
+kbabel_regexptool_la_LDFLAGS = $(all_libraries) -avoid-version -module -no-undefined
+
+noinst_HEADERS = main.h
+
+kbabel_regexptool_la_METASOURCES = AUTO
+
+service_DATA = kbabel_regexptool.desktop
+servicedir = $(kde_servicesdir)
+
+regexp_DATA = regexplist.xml
+regexpdir = $(kde_datadir)/kbabel
diff --git a/kbabel/datatools/regexp/kbabel_regexptool.desktop b/kbabel/datatools/regexp/kbabel_regexptool.desktop
new file mode 100644
index 00000000..dbd84491
--- /dev/null
+++ b/kbabel/datatools/regexp/kbabel_regexptool.desktop
@@ -0,0 +1,92 @@
+[Desktop Entry]
+Name=Catalan Grammar
+Name[br]=Yezhadur gatalaneg
+Name[ca]=Gramàtica catalana
+Name[cs]=Katalánská gramatika
+Name[da]=Katalansk grammatik
+Name[de]=Katalanische Grammatik
+Name[el]=ΓÏαμματική καταλανικών
+Name[eo]=Kataluna Gramatiko
+Name[es]=Gramática catalana
+Name[et]=Katalaani grammatika
+Name[eu]=Katalanaren gramatika
+Name[fa]=دستور زبان کاتالان
+Name[fi]=Katalaanin kielioppi
+Name[fr]=Grammaire du catalan
+Name[ga]=Gramadach na Catalóinise
+Name[gl]=Gramática catalá
+Name[he]=תחברי קט×לני
+Name[hu]=Katalán nyelvtan
+Name[is]=Katalónsk málfræði
+Name[it]=Grammatica catalana
+Name[ja]=カタロニア文節
+Name[ka]=კáƒáƒ¢áƒáƒšáƒáƒœáƒ£áƒ áƒ˜ გრáƒáƒ›áƒáƒ¢áƒ˜áƒ™áƒ
+Name[kk]=Каталон грамматикаÑÑ‹
+Name[lt]=Katalonų gramatika
+Name[nb]=Katalansk grammatikk
+Name[nds]=Katalaansch Grammatik
+Name[ne]=कà¥à¤¯à¤¾à¤Ÿà¤¾à¤²à¤¾à¤¨ बà¥à¤¯à¤¾à¤•à¤°à¤£
+Name[nl]=Catalaanse grammatica
+Name[nn]=Katalansk grammatikk
+Name[pa]=ਕਾਟਾਲਾਨ ਗਰਾਮਰ
+Name[pl]=Gramatyka katalońska
+Name[pt]=Gramática Catalã
+Name[pt_BR]=Gramática Catalã
+Name[ru]=КаталонÑÐºÐ°Ñ Ð³Ð°Ð¼Ð¼Ð°Ñ‚Ð¸ÐºÐ°
+Name[sk]=Katalánska gramatika
+Name[sl]=katalonska slovnica
+Name[sr]=КаталонијÑка граматика
+Name[sr@Latn]=Katalonijska gramatika
+Name[sv]=Katalansk grammatik
+Name[tr]=Katalan Dil Bilgisi
+Name[uk]=КаталонÑька граматика
+Name[zh_CN]=Catalan 语法
+Name[zh_TW]=Catalan 文法
+ValidationString=external script checking
+X-KDE-Library=kbabel_regexptool
+Type=Service
+Commands=validate
+Comment=Check Translated Messages with a set of Regular Expressions
+Comment[bg]=Проверка на преведените ÑÑŠÐ¾Ð±Ñ‰ÐµÐ½Ð¸Ñ Ñ Ñ€ÐµÐ³ÑƒÐ»Ñрни изрази
+Comment[ca]=Comprova els missatges traduïts amb un conjunt d'expressions regulars
+Comment[cs]=Zkontrolovat přeložené zprávy pomocí sady reg. výrazů
+Comment[da]=Tjek oversat besked med et sæt regulære udtryk
+Comment[de]=Überprüfung übersetzter Meldungen mit einem Satz regulärer Ausdrücke
+Comment[el]=Έλεγχος μεταφÏασμένων μηνυμάτων με ένα σÏνολο κανονικών εκφÏάσεων
+Comment[eo]=Kontroli tradukitajn mesaÄojn per aro da regulesprimoj
+Comment[es]=Comprobar mensajes traducidos mediante un juego de expresiones regulares
+Comment[et]=Tõlgitud teate kontroll regulaaravaldistega
+Comment[eu]=Egiaztatu itzulitako mezuak espresio erregular sorta batekin
+Comment[fa]=بررسی پیامهای ترجمه‌شده توسط مجموعه‌ای از عبارتهای منظم
+Comment[fi]=Tarkista käännetyt viestit säännöllisten lausekkeiden avulla
+Comment[fr]=Vérifie les messages traduits avec un jeu d'expressions rationnelles
+Comment[gl]=Verificación das mensaxes traducidas cun conxunto de expresións regulares
+Comment[hu]=A lefordított üzenetek ellenőrzése reguláris kifejezésekkel
+Comment[is]=Athuga þýdd skilaboð með reglulegum segðum
+Comment[it]=Controlla i messaggi tradotti con un insieme di espressioni regolari
+Comment[ja]=æ­£è¦è¡¨ç¾ã‚’用ã„ã¦ç¿»è¨³ãƒ¡ãƒƒã‚»ãƒ¼ã‚¸ã‚’検証
+Comment[ka]=რეგულáƒáƒ áƒ£áƒšáƒ˜ გáƒáƒ›áƒáƒ¡áƒáƒ®áƒ£áƒšáƒ”ბების შეცველი ნáƒáƒ—áƒáƒ áƒ’მნი შეტყáƒáƒ‘ინებების შემáƒáƒ¬áƒ›áƒ”ბáƒ
+Comment[kk]=Ðударылған жазуларды үлгі өрнегімен текÑеру
+Comment[lt]=Tikrinti išverstus pranešimus panaudojant įprastųjų išraiškų rinkinį
+Comment[nb]=Sjekk oversatte strenger med et sett regulære uttrykk
+Comment[nds]=Översett Mellen mit en Sett vun regulere Utdrück pröven
+Comment[ne]=नियमित अभिवà¥à¤¯à¤•à¥à¤¤à¤¿à¤•à¤¾ सेट भà¤à¤•à¤¾ अनà¥à¤¬à¤¾à¤¦ गरिà¤à¤•à¤¾ सनà¥à¤¦à¥‡à¤¶à¤•à¥‹ जाà¤à¤š गरà¥à¤¨à¥à¤¹à¥‹à¤¸à¥
+Comment[nl]=Vertaalde tekst controleren met behulp van reguliere expressies
+Comment[nn]=Sjekk omsette strengar med eit sett regulære uttrykk
+Comment[pl]=Sprawdzenie przetłumaczonych komunikatów za pomocą zestawu wyrażeń regularnych
+Comment[pt]=Verificação das Mensagens Traduzidas com um Conjunto de Expressões Regulares
+Comment[pt_BR]=Verificação das Mensagens Traduzidas com um Conjunto de Expressões Regulares
+Comment[ru]=Проверить переведенных ÑÐ¾Ð¾Ð±Ñ‰ÐµÐ½Ð¸Ñ Ð¿Ð¾ регулÑрному выражению
+Comment[sk]=Kontrola preložených textov pomocou sady regulárnych výrazov
+Comment[sl]=Preveri prevedena sporoÄila z naborom regularnih izrazov
+Comment[sr]=Провери преведене поруке Ñкупом регуларних израза
+Comment[sr@Latn]=Proveri prevedene poruke skupom regularnih izraza
+Comment[sv]=Kontrollera översatta meddelanden med en uppsättning reguljära uttryck
+Comment[tr]=Bir Düzgün Anlatım grubu ile birlikte çevrilen mesajları denetle
+Comment[uk]=Перевірити перекладені фрази за допомогою набору формальних виразів
+Comment[zh_CN]=用一组正则表达å¼æ£€æŸ¥å·²ç¿»è¯‘消æ¯
+Comment[zh_TW]=利用正è¦è¡¨ç¤ºå¼æª¢æŸ¥å·²ç¿»è­¯è¨Šæ¯
+ServiceTypes=KDataTool,KBabelValidator
+DataType=CatalogItem
+DataMimeTypes=application/x-kbabel-catalogitem
+ReadOnly=true
diff --git a/kbabel/datatools/regexp/main.cc b/kbabel/datatools/regexp/main.cc
new file mode 100644
index 00000000..4464170d
--- /dev/null
+++ b/kbabel/datatools/regexp/main.cc
@@ -0,0 +1,181 @@
+/* Copyright (C) 2005 Albert Cervera i Areny <albertca at hotpop dot com>
+
+ Based on Copyright (C) 1998, 1999 Torben Weis <weis@kde.org>
+ 2002 Stanislav Visnovsky <visnovsky@kde.org>
+ 2003 Dwayne Bailey <dwayne@translate.org.za>
+
+ 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.
+*/
+
+#include <resources.h>
+#include "catalog.h"
+#include "catalogitem.h"
+#include "catalogsettings.h"
+#include "main.h"
+#include <math.h>
+
+#include <qdir.h>
+#include <qfile.h>
+#include <qdom.h>
+#include <qstringlist.h>
+#include <qregexp.h>
+#include <kconfig.h>
+#include <kdebug.h>
+#include <kgenericfactory.h>
+#include <klibloader.h>
+#include <klocale.h>
+#include <kmessagebox.h>
+
+/***************************************************
+ *
+ * Factory
+ *
+ ***************************************************/
+
+K_EXPORT_COMPONENT_FACTORY( kbabel_regexptool, KGenericFactory<RegExpTool> ( "kbabeldatatool" ) )
+
+using namespace KBabel;
+
+RegExpTool::RegExpTool( QObject* parent, const char* name, const QStringList & )
+ : KDataTool( parent, name )
+{
+ i18n("which check found errors","translation has inconsistent length");
+ loadExpressions();
+ if ( ! _error.isNull() )
+ KMessageBox::error( (QWidget*)parent, i18n( "Error loading data (%1)" ).arg( _error ) );
+}
+
+bool RegExpTool::run( const QString& command, void* data, const QString& datatype, const QString& mimetype )
+{
+ if ( command != "validate" )
+ {
+ kdDebug(KBABEL) << "RegExpTool only accepts the 'validate' command" << endl;
+ kdDebug(KBABEL) << " The command " << command << " is not accepted" << endl;
+ return false;
+ }
+ // Check wether we can accept the data
+ if ( datatype != "CatalogItem" )
+ {
+ kdDebug(KBABEL) << "RegExpTool only accepts the CatalogItem datatype" << endl;
+ return false;
+ }
+ if ( mimetype != "application/x-kbabel-catalogitem" )
+ {
+ kdDebug(KBABEL) << "RegExpTool only accepts the 'application/x-kbabel-catalogitem' mimetype" << endl;
+ return false;
+ }
+
+ bool hasError = false;
+ if( command == "validate" )
+ {
+ CatalogItem* item = (CatalogItem*)(data);
+
+ if(!item->isUntranslated()) {
+ ExpressionList::Iterator it( _list.begin() );
+ ExpressionList::Iterator end( _list.end() );
+ QStringList msgs = item->msgstr();
+ QStringList results;
+ for ( ; it != end; ++it ) {
+ results.clear();
+ results = msgs.grep( (*it).regExp() );
+ if ( results.size() > 0 ) {
+ hasError = true;
+ break;
+ }
+ }
+ }
+ if(hasError) {
+ item->appendError( "regexp" );
+ } else {
+ item->removeError( "regexp" );
+ }
+ }
+ return !hasError;
+}
+
+
+void RegExpTool::loadExpressions()
+{
+ // TODO: Change file path
+ QFile file( QDir::homeDirPath() + "/.kde/share/apps/kbabel/regexplist.xml" );
+ QDomDocument doc;
+
+ if ( ! file.open( IO_ReadOnly ) ) {
+ kdDebug() << "File not found" << endl;
+ _error = i18n( "File not found" );
+ return;
+ }
+ if ( ! doc.setContent( &file ) ) {
+ kdDebug() << "Could not set content of xml file" << endl;
+ _error = i18n( "The file is not a XML" );
+ return;
+ }
+ file.close();
+
+ QDomElement docElem = doc.documentElement();
+ QDomNode n = docElem.firstChild();
+ while( !n.isNull() ) {
+ QDomElement e = n.toElement();
+ if( !e.isNull() )
+ elementToExpression( e );
+ if ( ! _error.isNull() )
+ break;
+ n = n.nextSibling();
+ }
+}
+
+void RegExpTool::elementToExpression( const QDomElement& e )
+{
+ QString name;
+ QString exp;
+ bool cs = false; //Expressions are case insensitive by default
+
+ if ( e.tagName().compare( "item" ) != 0 ) {
+ _error = i18n( "Expected tag 'item'" );
+ return;
+ }
+
+ QDomNode n = e.firstChild();
+ if ( n.isNull() ) {
+ _error = i18n( "First child of 'item' is not a node" );
+ return;
+ }
+
+ QDomElement el = n.toElement();
+ if ( el.isNull() || el.tagName().compare( "name" ) != 0 ) {
+ _error = i18n( "Expected tag 'name'" );
+ return;
+ }
+ name = el.text();
+
+ n = n.nextSibling();
+ el = n.toElement();
+ if ( el.isNull() || el.tagName().compare( "exp" ) != 0 ) {
+ _error = i18n( "Expected tag 'exp'" );
+ return;
+ }
+ exp = el.text();
+
+ n = n.nextSibling();
+ el = n.toElement();
+ if ( ! el.isNull() )
+ cs = true;
+
+ kdDebug(KBABEL) << "RegExpTool: Adding expression: " << name << endl;
+ _list.append( Expression( name, QRegExp( exp, cs ) ) );
+}
+
+#include "main.moc"
diff --git a/kbabel/datatools/regexp/main.h b/kbabel/datatools/regexp/main.h
new file mode 100644
index 00000000..690c5769
--- /dev/null
+++ b/kbabel/datatools/regexp/main.h
@@ -0,0 +1,73 @@
+/*
+ Copyright (C) 2005 Albert Cervera i Areny <albertca at hotpop dot com>
+
+ Based on Copyright (C) 1998, 1999 Torben Weis <weis@kde.org>
+ 2002 Stanislav Visnovsky <visnovsky@kde.org>
+ 2003 Dwayne Bailey <dwayne@translate.org.za>
+
+ 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 __main_h__
+#define __main_h__
+
+#include <kdatatool.h>
+#include <qvaluelist.h>
+
+class QDomElement;
+
+class Expression
+{
+public:
+ Expression() {};
+ Expression( const QString& name, const QRegExp& regExp )
+ {
+ _name = name;
+ _regExp = regExp;
+ }
+ const QString& name() const
+ {
+ return _name;
+ }
+ const QRegExp& regExp() const
+ {
+ return _regExp;
+ }
+
+private:
+ QString _name;
+ QRegExp _regExp;
+};
+
+typedef QValueList<Expression> ExpressionList;
+
+class RegExpTool : public KDataTool
+{
+ Q_OBJECT
+
+public:
+ RegExpTool( QObject* parent, const char* name, const QStringList & );
+ virtual bool run( const QString& command, void* data, const QString& datatype, const QString& mimetype);
+
+private:
+ void loadExpressions();
+ void elementToExpression( const QDomElement& e );
+
+ ExpressionList _list;
+ QString _error;
+};
+
+#endif
diff --git a/kbabel/datatools/regexp/regexplist.xml b/kbabel/datatools/regexp/regexplist.xml
new file mode 100644
index 00000000..1cd0b23d
--- /dev/null
+++ b/kbabel/datatools/regexp/regexplist.xml
@@ -0,0 +1,303 @@
+<!--
+ This file contains the list of regular expressions the plugin should check for.
+ Please, follow this syntax:
+ <regexplist>
+ <item>
+ <name></name>
+ <exp></exp>
+ <cs/> (only when the expression needs to be case sensitive)
+ </item>
+ ...
+ </regexplist>
+
+ Right now the file should be copied to ~/.kde/share/apps/kbabel/regexplist.xml. I'm sorry this cannot be configured but hope it will in the future. By the time if you need another location you have to modify the source code (main.cc)
+
+ You'll see in the example that most expressions start with '(^| |\\t)+' and then a word. This is to ensure it _is_ a word. Using the usual expressions to ensure we pick up a whole word doesn't work for the catalan language. Anyway, if you need to match a tab be sure you use the '\\t' expression.
+
+ Right now names in expressions aren't much useful, but I aim to modify kbabel in order to give more information about the error found. And I will probably add a description tag to enable long explanations of the mistake.
+
+ Also note the syntax of the file is quite strict. Mmmmm... too many words without a joke, this really doesn't seem to be open source :(
+ -->
+
+<regexplist>
+ <item>
+ <name>_el_ seguit de vocal</name>
+ <exp>(^| |\\t)+el +[a,e,i,o,u][a-z]+</exp>
+ </item>
+ <item>
+ <name>_la_ seguit de a,e,o</name>
+ <exp>(^| |\\t)+la +[a,e,o][a-z]+</exp>
+ </item>
+ <item>
+ <name>_per el_</name>
+ <exp>(^| |\\t)+per +el( |\\t|$)+</exp>
+ </item>
+ <item>
+ <name>_per els_</name>
+ <exp>(^| |\\t)+per +els( |\\t|$)+</exp>
+ </item>
+ <item>
+ <name>_de el_</name>
+ <exp>(^| |\\t)+de +el( |\\t|$)+</exp>
+ </item>
+ <item>
+ <name>_de els_</name>
+ <exp>(^| |\\t)+de +els( |\\t|$)+</exp>
+ </item>
+ <item>
+ <name>_a el_</name>
+ <exp>(^| |\\t)+a +el( |\\t|$)+</exp>
+ </item>
+ <item>
+ <name>_a els_</name>
+ <exp>(^| |\\t)+a +els( |\\t|$)+</exp>
+ </item>
+ <item>
+ <name>_al_ seguit de vocal</name>
+ <exp>(^| |\\t)+al +[a,e,i,o,u][a-z]+</exp>
+ </item>
+ <item>
+ <name>m'els</name>
+ <exp>(^| |\\t)m'els( |\\t|$)+</exp>
+ </item>
+ <item>
+ <name>mels</name>
+ <exp>(^| |\\t)mels( |\\t|$)+</exp>
+ </item>
+ <item>
+ <name>s'el</name>
+ <exp>(^| |\\t)s'el( |\\t|$)+</exp>
+ </item>
+ <item>
+ <name>sel</name>
+ <exp>(^| |\\t)sel( |\\t|$)+</exp>
+ </item>
+ <item>
+ <name>s'els</name>
+ <exp>(^| |\\t)s'els( |\\t|$)+</exp>
+ </item>
+ <item>
+ <name>sels</name>
+ <exp>(^| |\\t)sels( |\\t|$)+</exp>
+ </item>
+ <item>
+ <name>s'em</name>
+ <exp>(^| |\\t)s'em( |\\t|$)+</exp>
+ </item>
+ <item>
+ <name>sem</name>
+ <exp>(^| |\\t)sem( |\\t|$)+</exp>
+ </item>
+ <item>
+ <name>s'hem</name>
+ <exp>(^| |\\t)s'hem( |\\t|$)+</exp>
+ </item>
+ <item>
+ <name>s'ens</name>
+ <exp>(^| |\\t)s'ens( |\\t|$)+</exp>
+ </item>
+ <item>
+ <name>s'et</name>
+ <exp>(^| |\\t)s'et( |\\t|$)+</exp>
+ </item>
+ <item>
+ <name>susa</name>
+ <exp>(^| |\\t)susa( |\\t|$)+</exp>
+ </item>
+ <item>
+ <name>s'us</name>
+ <exp>(^| |\\t)s'us( |\\t|$)+</exp>
+ </item>
+ <item>
+ <name>su's</name>
+ <exp>(^| |\\t)su's( |\\t|$)+</exp>
+ </item>
+ <item>
+ <name>t'els</name>
+ <exp>(^| |\\t)t'els( |\\t|$)+</exp>
+ </item>
+ <item>
+ <name>t'el</name>
+ <exp>(^| |\\t)t'el( |\\t|$)+</exp>
+ </item>
+ <item>
+ <name>t'em</name>
+ <exp>(^| |\\t)t'em( |\\t|$)+</exp>
+ </item>
+ <item>
+ <name>t'ens</name>
+ <exp>(^| |\\t)t'ens( |\\t|$)+</exp>
+ </item>
+ <item>
+ <name>t'en</name>
+ <exp>(^| |\\t)t'en( |\\t|$)+</exp>
+ </item>
+ <item>
+ <name>ten</name>
+ <exp>(^| |\\t)ten( |\\t|$)+</exp>
+ </item>
+ <item>
+ <name>t'ens</name>
+ <exp>(^| |\\t)t'ens( |\\t|$)+</exp>
+ </item>
+ <item>
+ <name>vos sense accent</name>
+ <exp>(^| |\\t)vos( |\\t|$)</exp>
+ </item>
+ <item>
+ <name>Terminal és masculí (si es tracta d'informàtica): el terminal</name>
+ <exp>(^| |\\t)la +terminal( |\\t|$)</exp>
+ </item>
+ <item>
+ <name>Terminal és masculí (si es tracta d'informàtica): un terminal</name>
+ <exp>(^| |\\t)una +terminal( |\\t|$)</exp>
+ </item>
+ <item>
+ <name></name>
+ <exp>(^| |\\t)a +que( |\\t|$)</exp>
+ </item>
+ <item>
+ <name></name>
+ <exp>(^| |\\t)de +que( |\\t|$)</exp>
+ </item>
+ <item>
+ <name></name>
+ <exp>(^| |\\t)en +que( |\\t|$)</exp>
+ </item>
+ <item>
+ <name></name>
+ <exp>(^| |\\t)amb +que( |\\t|$)</exp>
+ </item>
+ <item>
+ <name></name>
+ <exp>(^| |\\t)per +que( |\\t|$)</exp>
+ </item>
+ <!-- En fase de test, últimes propostes d'en David -->
+
+ <!--
+ Abans de "aquest", "aquell", "algun", "un" i les seues variants no posarem
+ "a", sinó "en" (per a moviment i situació):
+ Voleu desar el fitxer en aquesta carpeta?
+ Tanmateix, per a la resta de casos cal posar "a"!
+
+ Probablement comprovar "a un" donaria massa falsos positius.
+ -->
+ <!--
+ <item>
+ <name></name>
+ <exp>(^| |\\t)a +(aquest|aquell|algun)( |\\t|$)</exp>
+ </item>
+ -->
+ <!--
+ El pronom es, davant d'un mot començat per sa-, se-, si-, so-, su-, ce- o
+ ci-, s'escriurà sempre en la forma plena (se):
+
+ Se sap que algunes característiques...
+ Les propietats d'aquest programa se sumen a les de...
+ -->
+ <item>
+ <name></name>
+ <exp>(^| |\\t)es +(sa|se|si|so|su|ce|ci)</exp>
+ </item>
+
+ <!--
+ En frases negatives, les partícules mai, cap, res, gens i ningú han de dur
+ no sempre:
+
+ No tragueu mai el disquet abans d'hora.
+ Cap ordre no s'ha d'escriure en majúscules.
+ Sense la contrasenya, ningú no està autoritzat a accedir a la informació.
+ -->
+ <!--
+ <item>
+ <name></name>
+ <exp>(((^| |\\t)(mai|cap|res|gens|ningú)( |\\t|$))(?!.*(^| |\\t)no( |\\t|$)))|(((^| |\\t)(mai|cap|res|gens|ningú)( |\\t|$))(?!.*(^| |\\t)no( |\\t|$)))</exp>
+ </item>
+ -->
+ <!--
+ 3.3. Construccions incorrectes
+ Podríem buscar "donat que" per a substituir-ho per "atès que".
+ "tals com" -> "com ara"
+ "tal i com" -> "tal com"
+ "teniu que" -> "heu de"/"heu d'"
+ "en quant a" -> "pel que fa a", "quant a"
+ -->
+ <!--
+ <item>
+ <name></name>
+ <exp>(^| |\\t)donat +que( |\\t|$)</exp>
+ </item>
+ -->
+ <item>
+ <name></name>
+ <exp>(^| |\\t)tals +com( |\\t|$)</exp>
+ </item>
+ <item>
+ <name></name>
+ <exp>(^| |\\t)tal +i +com( |\\t|$)</exp>
+ </item>
+ <item>
+ <name></name>
+ <exp>(^| |\\t)teniu +que( |\\t|$)</exp>
+ </item>
+ <item>
+ <name></name>
+ <exp>(^| |\\t)en +quant +a( |\\t|$)</exp>
+ </item>
+
+ <!--
+ Softcatalà:
+ * Hi han: El verb haver-hi és impersonal, per això no té plural en català central, atès que no té subjecte. Per tant, no es diu hi han, hi havien, hi hauran, sinó hi ha, hi havia, hi haurà, encara que el complement que el segueixi sigui plural.
+ -->
+ <item>
+ <name></name>
+ <exp>(^| |\\t)hi +han( |\\t|$)</exp>
+ </item>
+ <item>
+ <name></name>
+ <exp>(^| |\\t)hi +havien( |\\t|$)</exp>
+ </item>
+ <item>
+ <name></name>
+ <exp>(^| |\\t)hi +hauran( |\\t|$)</exp>
+ </item>
+
+ <!--
+ Softcatalà:
+ * Tenir que: És la traducció incorrecta al català de l'expressió castellana tener que. La forma correcta és haver de; també es pot utilitzar el verb impersonal caldre.
+ -->
+ <item>
+ <name></name>
+ <exp>(^| |\\t)teniu +que( |\\t|$)</exp>
+ </item>
+ <item>
+ <name></name>
+ <exp>(^| |\\t)tenim +que( |\\t|$)</exp>
+ </item>
+ <item>
+ <name></name>
+ <exp>(^| |\\t)tenen +que( |\\t|$)</exp>
+ </item>
+ <item>
+ <name></name>
+ <exp>(^| |\\t)en +quant +a( |\\t|$)</exp>
+ </item>
+ <item>
+ <name></name>
+ <exp>(^| |\\t)en +quant +a( |\\t|$)</exp>
+ </item>
+ <item>
+ <name></name>
+ <exp>(^| |\\t)en +quant +a( |\\t|$)</exp>
+ </item>
+ <item>
+ <name></name>
+ <exp>(^| |\\t)en +quant +a( |\\t|$)</exp>
+ </item>
+ <item>
+ <name></name>
+ <exp>(^| |\\t)en +quant +a( |\\t|$)</exp>
+ </item>
+
+
+</regexplist> \ No newline at end of file
diff --git a/kbabel/datatools/setfuzzy/Makefile.am b/kbabel/datatools/setfuzzy/Makefile.am
new file mode 100644
index 00000000..f1a5b8bc
--- /dev/null
+++ b/kbabel/datatools/setfuzzy/Makefile.am
@@ -0,0 +1,19 @@
+
+INCLUDES = -I$(srcdir)/../../common -I../../common $(all_includes)
+kbabel_setfuzzytool_la_LIBADD = ../../common/libkbabelcommon.la
+
+####### Files
+
+kde_module_LTLIBRARIES = kbabel_setfuzzytool.la
+
+kbabel_setfuzzytool_la_SOURCES = main.cc
+
+kbabel_setfuzzytool_la_LDFLAGS = $(all_libraries) -avoid-version -module -no-undefined
+
+noinst_HEADERS = main.h
+
+kbabel_setfuzzytool_la_METASOURCES = AUTO
+
+service_DATA = kbabel_setfuzzytool.desktop
+servicedir = $(kde_servicesdir)
+
diff --git a/kbabel/datatools/setfuzzy/kbabel_setfuzzytool.desktop b/kbabel/datatools/setfuzzy/kbabel_setfuzzytool.desktop
new file mode 100644
index 00000000..ead62f13
--- /dev/null
+++ b/kbabel/datatools/setfuzzy/kbabel_setfuzzytool.desktop
@@ -0,0 +1,98 @@
+[Desktop Entry]
+Name=Toggle Fuzzy Tool for KBabel
+Name[bs]=Fuzzy prekidaÄ - alat za KBabel
+Name[ca]=Eina per a KBabel que des/marca entrades inexactes
+Name[cs]=Nástroj pro přepínání fuzzy položek
+Name[cy]=Erfyn Newid i Bras i KBabel
+Name[da]=Slå fuzzy-værktøj til og fra for KBabel
+Name[de]=Umschalter für fragwürdige Einträge für KBabel
+Name[el]=ΕÏγαλείο εναλλαγής ασάφειας για το KBabel
+Name[es]=Herramienta de conmutación de entradas dudosas para KBabel
+Name[et]=KBabeli kahtlaste teadete lülitamise tööriist
+Name[eu]=Zalantzazko sarreren aldaketa tresna KBabel-entzat
+Name[fa]=زدن ضامن ابزار مبهم برای KBabel
+Name[fi]=KBabel-työkalu sumean tilan vaihtamiseksi
+Name[fr]=Outil d'inversion de fuzzy pour KBabel
+Name[gl]=Ferramenta de comutación da marca de dubida para KBabel
+Name[hu]=Ellenőrzési eszköz a KBabelhez
+Name[is]=Víxla loðnu tól fyrir KBabel
+Name[it]=Strumento di KBabel per commutare le voci fuzzy
+Name[ja]=KBabel ã‚ã„ã¾ã„状態切り替ãˆãƒ„ール
+Name[ka]=დáƒáƒ£áƒ–უსტებელის გáƒáƒ“áƒáƒ áƒ—ვის ხელსáƒáƒ¬áƒ§áƒ KBabel-სთვის
+Name[kk]=KBabel-дың жазу дүмбілездік күйін теріÑтеу құралы
+Name[lt]=KBabel įrankis, visus pranešimus pažymintis „neaiškiais“
+Name[ms]=Alat Togol Kabur untuk KBabel
+Name[nb]=Slå av/på uklar-statusen i KBabel
+Name[nds]=Twiefelhaftig-Status ümschalten för KBabel
+Name[ne]=केबà¥à¤¯à¤¾à¤¬à¤²à¤•à¤¾ लागि फजी उपकरण टगल गरà¥à¤¨à¥à¤¹à¥‹à¤¸à¥
+Name[nl]=Fuzzystatusomschakeling voor KBabel
+Name[nn]=Slå av/på uklar-statusen i KBabel
+Name[pa]=ਕੇਬਬੇਲ ਲਈ ਤਬਦੀਲੀ ਅਸਪਸ਼ਟ ਸੰਦ
+Name[pl]=Narzędzie do przełączania statusu wątpliwego komunikatu w KBabel
+Name[pt]=Classificação Global Aproximada para o KBabel
+Name[pt_BR]=Ferramenta para Alternar Aproximado para o KBabel
+Name[ru]=Изменение ÑтатуÑа черновой запиÑи Ð´Ð»Ñ KBabel
+Name[sk]=Nástroje pre prepnutie nepresného stavu per KBabel
+Name[sl]=Preklopi vse v ohlapno; za KBabel
+Name[sr]=Укључи/иÑкључи алат за нејаÑне поруке за KBabel
+Name[sr@Latn]=UkljuÄi/iskljuÄi alat za nejasne poruke za KBabel
+Name[sv]=Verktyg för att ändra inexakta för Kbabel
+Name[ta]= Kபாபேலà¯à®•à¯à®•à¯ நிலைமாறà¯à®±à®¿ இடைநிலை கரà¯à®µà®¿
+Name[tg]=Утилита барои ÑиёҳнавиÑÓ£ дар KBabel
+Name[tr]=KBabel için Geçiş Bulanık Aracı
+Name[uk]=ЗаÑіб Ð¿ÐµÑ€ÐµÐ¼Ð¸ÐºÐ°Ð½Ð½Ñ Ð½ÐµÑ‚Ð¾Ñ‡Ð½Ð¸Ñ… фраз Ð´Ð»Ñ KBabel
+Name[zh_CN]=KBabel 切æ¢æ¨¡ç³Šå·¥å…·
+Name[zh_TW]=KBabel 切æ›æ¨¡ç³Šç‹€æ…‹å·¥å…·
+X-KDE-Library=kbabel_setfuzzytool
+Type=Service
+Commands=allfuzzy
+Comment=Set All Fuzzy
+Comment[bg]=Маркиране на вÑички като неÑÑни
+Comment[bs]=Podesi sve kao fuzzy
+Comment[ca]=Estableix totes les entrades a inexacta
+Comment[cs]=Nastavit vše jako fuzzy
+Comment[cy]=Gosod Popeth i Fras
+Comment[da]=Sæt alle til fuzzy
+Comment[de]=Alle auf fragwürdig setzen
+Comment[el]=ΟÏισμός όλων ως ασαφή
+Comment[es]=Cambiar todo a dudoso
+Comment[et]=Kõigi teadete määramine kahtlaseks
+Comment[eu]=Ezarri denak zalantzazko bezala
+Comment[fa]=تنظیم همۀ مبهمها
+Comment[fi]=Aseta kaikki sumeiksi
+Comment[fr]=Mettre tout en fuzzy
+Comment[gl]=Marce todas as mensaxes como dúbidas
+Comment[hi]=सभी फजी नियत करें
+Comment[hu]=Az összes üzenet ellenőrzendővé alakítása
+Comment[is]=Setja öll loðin
+Comment[it]=Imposta tutte le voci come fuzzy
+Comment[ja]=ã™ã¹ã¦ã‚ã„ã¾ã„ã¨ã—ã¦ãƒžãƒ¼ã‚¯
+Comment[ka]=ყველáƒáƒ¡áƒ—ვის დáƒáƒ£áƒ–უსტებელის დáƒáƒ§áƒ”ნებáƒ
+Comment[kk]=Барлығын дүмбілез деп кою
+Comment[lt]=Žymėti visus neaiškiais
+Comment[ms]=Tetapkan Semua Kabur
+Comment[nb]=Sett alle strengene som uklare
+Comment[nds]=All op "twiefelhaftig" setten
+Comment[ne]=सबै फजी सेट गरà¥à¤¨à¥à¤¹à¥‹à¤¸à¥
+Comment[nl]=Alles fuzzy markeren
+Comment[nn]=Set alle strengane som uklare
+Comment[pa]= ਸਭ ਅਸਪਸ਼ਟ ਕਰੋ
+Comment[pl]=Ustawia wszystkie komunikaty jako wÄ…tpliwe
+Comment[pt]=Coloca todas as mensagens como aproximadas
+Comment[pt_BR]=Configura Todos Aproximados
+Comment[ru]=УÑтановить ÑÑ‚Ð°Ñ‚ÑƒÑ "черновые" Ð´Ð»Ñ Ð²Ñех запиÑей
+Comment[sk]=Nastaviť všetky ako nepresné
+Comment[sl]=Nastavi vse ohlapno
+Comment[sr]=ПоÑтави Ñве на нејаÑно
+Comment[sr@Latn]=Postavi sve na nejasno
+Comment[sv]=Gör alla inexakta
+Comment[ta]= எலà¯à®²à®¾ இடைநிலையையà¯à®®à¯ அமை
+Comment[tg]=Барқарор кардани ҳолати "ÑиёҳнавиÑҳо" барои ҳамаи Ñабтҳо
+Comment[tr]=Tümünü Bulanık Ata
+Comment[uk]=Ð’Ñтановити вÑÑ– фрази Ñк "неточні"
+Comment[zh_CN]=全部设为模糊
+Comment[zh_TW]=全部設為模糊
+ServiceTypes=KDataTool,KBabelTool
+DataType=Catalog
+DataMimeTypes=application/x-kbabel-catalog
+ReadOnly=false
diff --git a/kbabel/datatools/setfuzzy/main.cc b/kbabel/datatools/setfuzzy/main.cc
new file mode 100644
index 00000000..077004d8
--- /dev/null
+++ b/kbabel/datatools/setfuzzy/main.cc
@@ -0,0 +1,98 @@
+/* This file is part of KBabel
+ based Copyright (C) 1998, 1999 Torben Weis <weis@kde.org>
+ 2003 Stanislav Visnovsky <visnovsky@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.
+
+ In addition, as a special exception, the copyright holders give
+ permission to link the code of this program with any edition of
+ the Qt library by Trolltech AS, Norway (or with modified versions
+ of Qt that use the same license as Qt), and distribute linked
+ combinations including the two. You must obey the GNU General
+ Public License in all respects for all of the code used other than
+ Qt. If you modify this file, you may extend this exception to
+ your version of the file, but you are not obligated to do so. If
+ you do not wish to do so, delete this exception statement from
+ your version.
+
+*/
+
+#include <resources.h>
+#include "catalog.h"
+#include "main.h"
+
+#include <kdebug.h>
+#include <kgenericfactory.h>
+#include <klibloader.h>
+#include <klocale.h>
+
+/***************************************************
+ *
+ * Factory
+ *
+ ***************************************************/
+
+K_EXPORT_COMPONENT_FACTORY( kbabel_setfuzzytool, KGenericFactory<SetFuzzyTool> ( "kbabeldatatool" ) )
+
+using namespace KBabel;
+
+SetFuzzyTool::SetFuzzyTool( QObject* parent, const char* name, const QStringList & )
+ : KDataTool( parent, name )
+{
+}
+
+bool SetFuzzyTool::run( const QString& command, void* data, const QString& datatype, const QString& mimetype )
+{
+ if ( command != "allfuzzy" )
+ {
+ kdDebug(KBABEL) << "Fuzzy Toggling Tool does only accept the command 'allfuzzy'" << endl;
+ kdDebug(KBABEL) << " The commands " << command << " is not accepted" << endl;
+ return FALSE;
+ }
+
+ // Check wether we can accept the data
+ if ( datatype != "Catalog" )
+ {
+ kdDebug(KBABEL) << "Fuzzy Toggling Tool only accepts datatype Catalog" << endl;
+ return FALSE;
+ }
+
+ if ( mimetype != "application/x-kbabel-catalog" )
+ {
+ kdDebug(KBABEL) << "Plural Forms Tool only accepts mimetype application/x-kbabel-catalog" << endl;
+ return FALSE;
+ }
+
+ if( command == "allfuzzy" )
+ {
+ Catalog* catalog = (Catalog*)(data);
+
+ catalog->applyBeginCommand(0,Msgstr,0);
+
+ for( uint index=0; index < catalog->numberOfEntries(); index++ )
+ {
+ if( !catalog->isUntranslated(index) )
+ {
+ catalog->setFuzzy(index,true);
+ }
+ }
+
+ catalog->applyEndCommand(0,Msgstr,0);
+ }
+ return TRUE;
+}
+
+#include "main.moc"
diff --git a/kbabel/datatools/setfuzzy/main.h b/kbabel/datatools/setfuzzy/main.h
new file mode 100644
index 00000000..da28a9d1
--- /dev/null
+++ b/kbabel/datatools/setfuzzy/main.h
@@ -0,0 +1,47 @@
+/* This file is part of KBabel
+ based on Copyright (C) 1998, 1999 Torben Weis <weis@kde.org>
+ 2003 Stanislav Visnovsky <visnovsky@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.
+
+ In addition, as a special exception, the copyright holders give
+ permission to link the code of this program with any edition of
+ the Qt library by Trolltech AS, Norway (or with modified versions
+ of Qt that use the same license as Qt), and distribute linked
+ combinations including the two. You must obey the GNU General
+ Public License in all respects for all of the code used other than
+ Qt. If you modify this file, you may extend this exception to
+ your version of the file, but you are not obligated to do so. If
+ you do not wish to do so, delete this exception statement from
+ your version.
+
+*/
+
+#ifndef __main_h__
+#define __main_h__
+
+#include <kdatatool.h>
+
+class SetFuzzyTool : public KDataTool
+{
+ Q_OBJECT
+
+public:
+ SetFuzzyTool( QObject* parent, const char* name, const QStringList & );
+ virtual bool run( const QString& command, void* data, const QString& datatype, const QString& mimetype);
+};
+
+#endif
diff --git a/kbabel/datatools/whitespace/Makefile.am b/kbabel/datatools/whitespace/Makefile.am
new file mode 100644
index 00000000..f0987b4f
--- /dev/null
+++ b/kbabel/datatools/whitespace/Makefile.am
@@ -0,0 +1,19 @@
+
+INCLUDES = -I$(srcdir)/../../common -I../../common $(all_includes)
+kbabel_whitespacetool_la_LIBADD = $(LIB_KIO) ../../common/libkbabelcommon.la
+
+####### Files
+
+kde_module_LTLIBRARIES = kbabel_whitespacetool.la
+
+kbabel_whitespacetool_la_SOURCES = main.cc
+
+kbabel_whitespacetool_la_LDFLAGS = $(all_libraries) -avoid-version -module -no-undefined
+
+noinst_HEADERS = main.h
+
+kbabel_whitespacetool_la_METASOURCES = AUTO
+
+service_DATA = kbabel_whitespacetool.desktop
+servicedir = $(kde_servicesdir)
+
diff --git a/kbabel/datatools/whitespace/kbabel_whitespacetool.desktop b/kbabel/datatools/whitespace/kbabel_whitespacetool.desktop
new file mode 100644
index 00000000..74de2bc4
--- /dev/null
+++ b/kbabel/datatools/whitespace/kbabel_whitespacetool.desktop
@@ -0,0 +1,98 @@
+[Desktop Entry]
+Name=String Translated as Whitespace Validator for KBabel
+Name[bg]=ВалидноÑÑ‚ на низовете, преведени като интервали - KBabel
+Name[bs]=Provjera stringova prevedenih kao blanko znaci za KBabel
+Name[ca]=Validació de cadenes traduïdes com un espai en blanc per a KBabel
+Name[cs]=Validátor překladů bílých mezer
+Name[cy]=Dilysydd Llinyn wedi'i Gyfieithu fel Gofodnod ar gyfer KBabel
+Name[da]=Streng oversat som blanke tegn-validering for KBabel
+Name[de]=Prüfung auf Leerzeichenübersetzungen für KBabel
+Name[el]=Ελεγκτής εγκυÏότητας συμβολοσειÏών μεταφÏασμένα ως κενό για το KBabel
+Name[es]=Validador de cadenas traducidas como espacios en blanco.para KBabel
+Name[et]=KBabeli tühimärgiks tõlgitud teadete kontrollija
+Name[eu]=Zurigune bezala itzulitako kateen balidatzailea KBabel-entzat
+Name[fa]=رشتۀ ترجمه‌شده به عنوان اعتبارسنج Ùاصلۀ سÙید برای KBabel
+Name[fi]=Tyhjeinä käännettyjen merkkijonojen tarkistaja KBabelissa
+Name[fr]=Validateur de chaînes traduites comme des espaces pour KBabel
+Name[gl]=Validación de texto traducido como espazo para KBabel
+Name[hu]=Csak üres karaktereket tartalmazó fordítások kiszűrése a KBabelben
+Name[is]=Staðfestir fyrir KBabel fyrir strengi þýdda sem bil
+Name[it]=Convalidatore delle stringhe tradotte con spazi bianchi per KBabel
+Name[ja]=KBabel 空白ã¨ã—ã¦ç¿»è¨³ã•ã‚ŒãŸæ–‡å­—列を検索
+Name[ka]=სტრიქáƒáƒœáƒ˜ ნáƒáƒ—áƒáƒ áƒ’მნირრáƒáƒ’áƒáƒ áƒª Whitespace დáƒáƒ›áƒ›áƒáƒ¬áƒ›áƒ”ბელი KBabel-სთვის
+Name[kk]=KBabel-дың Ð±Ð¾Ñ Ð¾Ñ€Ñ‹Ð½ аудармаларын текÑеруі
+Name[lt]=KBabel eiluÄių, iÅ¡verstų tuÅ¡Äiais tarpais, patikros įrankis
+Name[nb]=Se etter tomme strenger i KBabel
+Name[nds]=Leertekenöversetten-Prööv för KBabel
+Name[ne]=कà¥à¤¯à¤¾à¤¬à¥‡à¤²à¤•à¤¾ लागि सेतो रिकà¥à¤¤à¤¸à¥à¤¥à¤¾à¤¨ पà¥à¤°à¤®à¤¾à¤£à¥€à¤¤à¤•à¤°à¥à¤¤à¤¾ अनà¥à¤°à¥à¤ª अनà¥à¤¬à¤¾à¤¦ गरिà¤à¤•à¤¾ सà¥à¤Ÿà¥à¤°à¤¿à¤™
+Name[nl]=Tekst-vertaald-als-witruimte-validatie voor KBabel
+Name[nn]=Sjå etter tomme strengar i KBabel
+Name[pl]=Sprawdzenie czy napis jest przetłumaczony jako białe znaki w KBabel
+Name[pt]=Validação de Texto Traduzido como Espaço para o KBabel
+Name[pt_BR]=Validador de String Traduzidos com Espaços em Branco para o KBabel
+Name[ru]=Проверка Ñтрок, переведённых как пробел Ð´Ð»Ñ KBabel
+Name[sk]=Kontrola textu preloženého ako prázdny pre KBabel
+Name[sl]=Potrjevalnik nizov, prevedenih kot presledki, za KBabel
+Name[sr]=Оверивач за низове знакова преведене као празан проÑтор за KBabel
+Name[sr@Latn]=OverivaÄ za nizove znakova prevedene kao prazan prostor za KBabel
+Name[sv]=Validering av sträng översatt som blanktecken för Kbabel
+Name[ta]=Kபாபேலà¯à®•à¯à®•à¯ சரம௠மொழிபெயரà¯à®ªà¯à®ªà¯ இடைவேலை மதிபà¯à®ªà¯€à®Ÿà¯à®Ÿà®¾à®³à®°à¯
+Name[tg]=Тафтиши Ñатр, ки миÑли фоÑила барои KBabel, тарҷума шудааÑÑ‚
+Name[tr]=KBabel için Ayırma Boşluğu gibi Çevrilen Dizge Denetimi
+Name[uk]=Перевірка фраз, перекладених Ñк пропуÑки, Ð´Ð»Ñ KBabel
+Name[zh_CN]=KBabel 的字符串译为空格的检查器
+Name[zh_TW]=KBabel 翻譯為空白字串檢查器
+ValidationString=whitespace checking
+X-KDE-Library=kbabel_whitespacetool
+Type=Service
+Commands=validate
+Comment=Whitespace Translations
+Comment[bg]=Ðизове, преведени като интервали
+Comment[bs]=Blanko prijevodi
+Comment[ca]=Traduccions amb espai en blanc
+Comment[cs]=Překlady mezer
+Comment[cy]=Cyfieithiadau Gofodnod
+Comment[da]=Oversatte blanke tegn
+Comment[de]=Leerzeichen-Ãœbersetzungen
+Comment[el]=ΜεταφÏάσεις με κενό
+Comment[es]=Traducciones de espacios en blanco
+Comment[et]=Tühimärkidest koosnevad tõlked
+Comment[eu]=Zurigune itzulpenak
+Comment[fa]=ترجمۀ Ùاصله‌های سÙید
+Comment[fi]=Tyhjeiden käännökset
+Comment[fr]=Traductions en espaces
+Comment[gl]=Traducións de espazos en branco
+Comment[he]=×ª×¨×’×•×ž×™× ×©×œ ×ª×•×•×™× × ×§×™×™×
+Comment[hi]=वà¥à¤¹à¤¾à¤‡à¤Ÿ-सà¥à¤ªà¥‡à¤¸ अनà¥à¤µà¤¾à¤¦
+Comment[hu]=Az üres fordítások kiszűrése
+Comment[is]=Þýðingar bila
+Comment[it]=Traduzioni con spazi bianchi
+Comment[ja]=空白翻訳文字列を検索
+Comment[ka]=Whitespace მთáƒáƒ áƒ’მნელები
+Comment[kk]=Ð‘Ð¾Ñ Ð¾Ñ€Ñ‹Ð½ аудармалары
+Comment[lt]=TuÅ¡Äių eiluÄių patikra
+Comment[ms]=Terjemahan Ruang Kosong
+Comment[nb]=Tomme strenger
+Comment[nds]=Leertekenöversetten pröven
+Comment[ne]=सेतो रिकà¥à¤¤à¤¸à¥à¤¥à¤¾à¤¨ अनà¥à¤¬à¤¾à¤¦
+Comment[nl]=Lege vertalingen
+Comment[nn]=Tomme strengar
+Comment[pl]=Tłumaczenia w postaci białych znaków
+Comment[pt]=Traduções de Espaços em Branco
+Comment[pt_BR]=Traduções com espaços em branco
+Comment[ru]=ПуÑтые переводы
+Comment[sk]=Prázdne preklady
+Comment[sl]=Prevodi presledkov
+Comment[sr]=Преводи као празан проÑтор
+Comment[sr@Latn]=Prevodi kao prazan prostor
+Comment[sv]=Översättning med blanktecken
+Comment[ta]= இடைவேலை பெயரà¯à®ªà¯à®ªà¯
+Comment[tg]=Тарҷумаҳои холӣ
+Comment[tr]=Ayırma Boşluğu Çevirileri
+Comment[uk]=Порожні переклади
+Comment[zh_CN]=空白翻译
+Comment[zh_TW]=空白翻譯
+ServiceTypes=KDataTool,KBabelValidator
+DataType=CatalogItem
+DataMimeTypes=application/x-kbabel-catalogitem
+ReadOnly=true
diff --git a/kbabel/datatools/whitespace/main.cc b/kbabel/datatools/whitespace/main.cc
new file mode 100644
index 00000000..9987c465
--- /dev/null
+++ b/kbabel/datatools/whitespace/main.cc
@@ -0,0 +1,144 @@
+/* This file is part of KBabel
+ based Copyright (C) 1998, 1999 Torben Weis <weis@kde.org>
+ 2002 Stanislav Visnovsky <visnovsky@kde.org>
+ 2003 Dwayne Bailey <dwayne@translate.org.za>
+
+ 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.
+
+ In addition, as a special exception, the copyright holders give
+ permission to link the code of this program with any edition of
+ the Qt library by Trolltech AS, Norway (or with modified versions
+ of Qt that use the same license as Qt), and distribute linked
+ combinations including the two. You must obey the GNU General
+ Public License in all respects for all of the code used other than
+ Qt. If you modify this file, you may extend this exception to
+ your version of the file, but you are not obligated to do so. If
+ you do not wish to do so, delete this exception statement from
+ your version.
+
+*/
+
+#include <resources.h>
+#include "catalog.h"
+#include "catalogitem.h"
+#include "catalogsettings.h"
+#include "main.h"
+
+#include <kconfig.h>
+#include <kdebug.h>
+#include <kgenericfactory.h>
+#include <klibloader.h>
+#include <klocale.h>
+#include <kmessagebox.h>
+
+/***************************************************
+ *
+ * Factory
+ *
+ ***************************************************/
+
+K_EXPORT_COMPONENT_FACTORY( kbabel_whitespacetool, KGenericFactory<WhitespaceTool> ( "kbabeldatatool" ) )
+
+using namespace KBabel;
+
+WhitespaceTool::WhitespaceTool( QObject* parent, const char* name, const QStringList & )
+ : KDataTool( parent, name ), _cache_origin( 0 ), _equation("^[a-zA-Z0-9]+=")
+{
+ i18n("which check found errors","whitespace only translation");
+}
+
+bool WhitespaceTool::run( const QString& command, void* data, const QString& datatype, const QString& mimetype )
+{
+
+ if ( command != "validate" )
+ {
+ kdDebug(KBABEL) << "Whitespace Tool only accepts the 'validate' command" << endl;
+ kdDebug(KBABEL) << " The command " << command << " is not accepted" << endl;
+ return false;
+ }
+
+ // Check wether we can accept the data
+ if ( datatype != "CatalogItem" )
+ {
+ kdDebug(KBABEL) << "Whitespace Tool only accept the CatalogItem datatype" << endl;
+ return false;
+ }
+
+ if ( mimetype != "application/x-kbabel-catalogitem" )
+ {
+ kdDebug(KBABEL) << "Whitespace Tool only accept the 'application/x-kbabel-catalogitem' mimetype" << endl;
+ return false;
+ }
+
+ if( command == "validate" )
+ {
+
+ CatalogItem* item = (CatalogItem*)(data);
+ bool hasIdError = false;
+ bool hasStrError = false;
+ QRegExp _whitespace("^\\s+$");
+ QStringList str, id;
+
+ if(!item->isUntranslated()) {
+ if( _cache_origin != item->project() )
+ {
+ _plurals = item->project()->miscSettings().singularPlural;
+ _cache_origin = item->project();
+ }
+
+ //Ensure KDE plural forms are in a StringList
+ //FIXME Eliminate context information and this could become a generic message splitter
+ if( item->pluralForm() == KDESpecific ) {
+ str = QStringList::split( "\\n", item->msgstr().first(), true );
+ id = QStringList::split( "\\n",
+ item->msgid().first().replace( QRegExp(_plurals), ""), true );
+ } else {
+ str = item->msgstr();
+ id = item->msgid();
+ }
+
+ //Strip equations
+ id.first().replace( QRegExp(_equation), "");
+ str.first().replace( QRegExp(_equation), "");
+
+ //Ignore Messages with blank msgid components
+ for( QStringList::Iterator it = id.begin() ; it != id.end() ; it++ ) {
+ QString resultstring = (*it);
+ hasIdError = hasIdError || resultstring.contains(_whitespace);
+ }
+ if( hasIdError ) return true;
+
+ //Check each QString in the List is not whitespace
+ for( QStringList::Iterator it = str.begin() ; it != str.end() ; it++ ) {
+ QString resultstring = (*it);
+ hasStrError = hasStrError || resultstring.contains(_whitespace);
+ }
+
+ }
+
+ if(hasStrError) {
+ item->appendError( "whitespace translation" );
+ return false;
+ } else {
+ item->removeError( "whitespace translation" );
+ return true;
+ }
+
+ }
+ return false;
+}
+
+#include "main.moc"
diff --git a/kbabel/datatools/whitespace/main.h b/kbabel/datatools/whitespace/main.h
new file mode 100644
index 00000000..9a0545cc
--- /dev/null
+++ b/kbabel/datatools/whitespace/main.h
@@ -0,0 +1,55 @@
+/* This file is part of KBabel
+ based on Copyright (C) 1998, 1999 Torben Weis <weis@kde.org>
+ 2002 Stanislav Visnovsky <visnovsky@kde.org>
+ 2003 Dwayne Bailey <dwayne@translate.org.za>
+
+ 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.
+
+ In addition, as a special exception, the copyright holders give
+ permission to link the code of this program with any edition of
+ the Qt library by Trolltech AS, Norway (or with modified versions
+ of Qt that use the same license as Qt), and distribute linked
+ combinations including the two. You must obey the GNU General
+ Public License in all respects for all of the code used other than
+ Qt. If you modify this file, you may extend this exception to
+ your version of the file, but you are not obligated to do so. If
+ you do not wish to do so, delete this exception statement from
+ your version.
+
+*/
+
+#ifndef __main_h__
+#define __main_h__
+
+#include "kbproject.h"
+
+#include <qregexp.h>
+#include <kdatatool.h>
+
+class WhitespaceTool : public KDataTool
+{
+ Q_OBJECT
+
+public:
+ WhitespaceTool( QObject* parent, const char* name, const QStringList & );
+ virtual bool run( const QString& command, void* data, const QString& datatype, const QString& mimetype);
+private:
+ KBabel::Project::Ptr _cache_origin;
+ QRegExp _plurals;
+ QRegExp _equation;
+};
+
+#endif
diff --git a/kbabel/datatools/whitespace/test.po b/kbabel/datatools/whitespace/test.po
new file mode 100644
index 00000000..96fb59d7
--- /dev/null
+++ b/kbabel/datatools/whitespace/test.po
@@ -0,0 +1,92 @@
+# Test file to validate the whitespace checking tool
+# Dwayne Bailey <dwayne@translate.org.za>, 2003
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: test\n"
+"Last-Translator: Dwayne Bailey <dwayne@translate.org.za>\n"
+"PO-Revision-Date: 2003-01-09 09:35+0200\n"
+"Language-Team: <english@translate.org.za>\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"X-Generator: KBabel 1.2\n"
+
+# msgstr incorrectly translated with whitespace - 2*<sp>
+# Expected Result = error
+msgid "Some translation string"
+msgstr " "
+
+# msgid with 3*<sp> translated to 2*<sp> This should be valid
+# Expected Result = valid
+msgid " "
+msgstr " "
+
+# plural checks for KDE with a blank msgstr
+# Expected Result = error
+msgid ""
+"_n: Plural translation\n"
+"Second form %n"
+msgstr ""
+"First fine second wrong\n"
+" "
+
+# plural checks for KDE with everything correct
+# Expected Result = valid
+msgid ""
+"_n: Plural translation\n"
+"Second form %n"
+msgstr ""
+"First fine\n"
+"Second fine"
+
+# plural checks for KDE with bad msgid
+# Expected Result = valid
+msgid ""
+"_n: \n"
+"First form missing"
+msgstr ""
+"\n"
+"Second fine"
+
+# plural checks for KDE with bad msgid
+# Expected Result = valid
+msgid ""
+"_n: Second is missing\n"
+""
+msgstr ""
+"First fine\n"
+""
+
+# Plural check on GNU format with a missing plural
+# Expected Result = error
+msgid "Plural translation"
+msgid_plural "The second form %n"
+msgstr[0] "First fine second wrong"
+msgstr[1] " "
+
+# Plural check on GNU format in order
+# Expected Result = valid
+msgid "Plural translation"
+msgid_plural "The second form %n"
+msgstr[0] "First fine"
+msgstr[1] "Second fine"
+
+# Plural check on GNU format with singular missing
+# Expected Result = valid
+msgid ""
+msgid_plural "Singluar is missing"
+msgstr[0] ""
+msgstr[1] "Plural was translated"
+
+# Plural check on GNU format with plural missing
+# Expected Result = valid
+msgid "Plural is missing"
+msgid_plural ""
+msgstr[0] "Singular is translated"
+msgstr[1] ""
+
+# KDE specific: desktop file contains whitespace transaltion
+# Expected Result = error
+msgid "Name=No Spaces"
+msgstr "Name= "
+
diff --git a/kbabel/datatools/xml/Makefile.am b/kbabel/datatools/xml/Makefile.am
new file mode 100644
index 00000000..dbba4740
--- /dev/null
+++ b/kbabel/datatools/xml/Makefile.am
@@ -0,0 +1,19 @@
+
+INCLUDES = -I$(srcdir)/../../common -I../../common $(all_includes)
+kbabel_xmltool_la_LIBADD = $(LIB_KIO) ../../common/libkbabelcommon.la
+
+####### Files
+
+kde_module_LTLIBRARIES = kbabel_xmltool.la
+
+kbabel_xmltool_la_SOURCES = main.cc
+
+kbabel_xmltool_la_LDFLAGS = $(all_libraries) -avoid-version -module -no-undefined
+
+noinst_HEADERS = main.h
+
+kbabel_xmltool_la_METASOURCES = AUTO
+
+service_DATA = kbabel_xmltool.desktop
+servicedir = $(kde_servicesdir)
+
diff --git a/kbabel/datatools/xml/kbabel_xmltool.desktop b/kbabel/datatools/xml/kbabel_xmltool.desktop
new file mode 100644
index 00000000..2b03bef9
--- /dev/null
+++ b/kbabel/datatools/xml/kbabel_xmltool.desktop
@@ -0,0 +1,105 @@
+[Desktop Entry]
+Name=XML Validation for KBabel
+Name[bg]=XML валидноÑÑ‚ - KBabel
+Name[bs]=XML provjera za KBabel
+Name[ca]=Validació XML per a KBabel
+Name[cs]=Validace XML pro KBabel
+Name[cy]=Dilysiant XML i KBabel
+Name[da]=XML-validering for KBabel
+Name[de]=XML-Überprüfung für KBabel
+Name[el]=Έλεγχος εγκυÏότητας XML για το KBabel
+Name[es]=Validación XML para KBabel
+Name[et]=KBabeli XML-i kontrollija
+Name[eu]=XML balidazioa KBabel-entzat
+Name[fa]=اعتبارسنجی XML برای KBabel
+Name[fi]=XML-validointi KBabelissa
+Name[fr]=Validation XML pour KBabel
+Name[ga]=Bailíochtú XML le haghaidh KBabel
+Name[gl]=Validación de XML para KBabel
+Name[hi]=के-बेबल के लिठà¤à¤•à¥à¤¸à¤à¤®à¤à¤² वेलिडेशन
+Name[hu]=XML-ellenőrzés a KBabelben
+Name[is]=XML staðfesting fyrir KBabel
+Name[it]=Convalidatore di XML per KBabel
+Name[ja]=KBabel XML 検証
+Name[ka]=XML დáƒáƒ›áƒáƒ¬áƒ›áƒ”ბრKBabel-თვის
+Name[kk]=KBabel-дың XML-ды текÑеруі
+Name[lt]=KBabel XML patikros įrankis
+Name[ms]=Pengesah XML untuk KBabel
+Name[nb]=XML-sjekk i KBabel
+Name[nds]=XML-Prööv för KBabel
+Name[ne]=केबà¥à¤¯à¤¾à¤¬à¤²à¤•à¤¾ लागि à¤à¤•à¥à¤¸à¤à¤®à¤à¤² पà¥à¤°à¤®à¤¾à¤£à¥€à¤•à¤°à¤£
+Name[nl]=XML-validatie voor KBabel
+Name[nn]=XML-sjekk i KBabel
+Name[pa]=ਕੇਬਬੇਲ ਲਈ XML ਪਰਮਾਣਕ
+Name[pl]=Sprawdzenie XML w KBabel
+Name[pt]=Validação de XML para o KBabel
+Name[pt_BR]=Validação XML para o KBabel
+Name[ru]=Проверка XML Ð´Ð»Ñ KBabel
+Name[sk]=Kontrola XML pre KBabel
+Name[sl]=Potrjevanje XML za KBabel
+Name[sr]=Овера XML-а за KBabel
+Name[sr@Latn]=Overa XML-a za KBabel
+Name[sv]=Validering av XML för Kbabel
+Name[ta]= Kபாபேலà¯à®•à¯à®•à¯ XML செலà¯à®²à¯à®ªà®Ÿà®¿ சோதனை
+Name[tg]=Тафтиши XML барои KBabel
+Name[tr]=KBabel için XML Onaylama
+Name[uk]=Перевірка XML Ð´Ð»Ñ KBabel
+Name[zh_CN]=KBabel 的 XML 检查器
+Name[zh_TW]=KBabel XML 檢查器
+ValidationString=XML tags
+X-KDE-Library=kbabel_xmltool
+Type=Service
+Commands=validate
+Comment=Check Tags
+Comment[bg]=Проверка на таговете
+Comment[br]=Gwiriekaat al liketennoù
+Comment[bs]=Provjeri tagove
+Comment[ca]=Comprova les etiquetes
+Comment[cs]=Zkontrolovat znaÄky
+Comment[cy]=Dilysu tagiau
+Comment[da]=Tjek mærker
+Comment[de]=Prüfung der Tags in Übersetzungen
+Comment[el]=Έλεγχος ετικετών
+Comment[es]=Comprobar etiquetas
+Comment[et]=Siltide kontroll
+Comment[eu]=Egiaztatu etiketak
+Comment[fa]=بررسی برچسبها
+Comment[fi]=Tarkista merkintäkoodit
+Comment[fr]=Vérifier les balises
+Comment[ga]=Seiceáil Clibeanna
+Comment[gl]=Verificación das marcas XML/HTML
+Comment[he]=בודק תגיות
+Comment[hi]=टैगà¥à¤¸ जांच करें
+Comment[hu]=A tag-ek ellenőrzése
+Comment[is]=Athuga tög
+Comment[it]=Controlla i tag
+Comment[ja]=タグを検証
+Comment[ka]=ჭდეების შემáƒáƒ¬áƒ›áƒ”ბáƒ
+Comment[kk]=Тегтерді текÑеру
+Comment[lt]=Tikrinti gaires
+Comment[ms]=Periksa Tag
+Comment[nb]=Sjekk tagger
+Comment[nds]=XML-Betekers pröven
+Comment[ne]=टà¥à¤¯à¤¾à¤— जाà¤à¤š गरà¥à¤¨à¥à¤¹à¥‹à¤¸à¥
+Comment[nl]=Tags controleren
+Comment[nn]=Sjekk taggar
+Comment[pa]=ਟੈਗ ਜਾਂਚ
+Comment[pl]=Sprawdzenie znaczników XML
+Comment[pt]=Verificação das Marcas
+Comment[pt_BR]=Verifica Tags
+Comment[ru]=Проверить теги
+Comment[sk]=Kontrola znaÄiek
+Comment[sl]=Preveri znaÄke
+Comment[sr]=Провери ознаке
+Comment[sr@Latn]=Proveri oznake
+Comment[sv]=Kontrollera taggar
+Comment[ta]= ஒடà¯à®Ÿà¯ சரிபாரà¯à®ªà¯à®ªà¯
+Comment[tg]=Тафтиш кардани тегҳо
+Comment[tr]=Biçim İmlerini Sına
+Comment[uk]=Перевірити мітки
+Comment[zh_CN]=检查标签
+Comment[zh_TW]=檢查標籤
+ServiceTypes=KDataTool,KBabelValidator
+DataType=CatalogItem
+DataMimeTypes=application/x-kbabel-catalogitem
+ReadOnly=true
diff --git a/kbabel/datatools/xml/main.cc b/kbabel/datatools/xml/main.cc
new file mode 100644
index 00000000..d9549014
--- /dev/null
+++ b/kbabel/datatools/xml/main.cc
@@ -0,0 +1,206 @@
+/* This file is part of KBabel
+ based Copyright (C) 1998, 1999 Torben Weis <weis@kde.org>
+ 2002-2003 Stanislav Visnovsky <visnovsky@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.
+
+ In addition, as a special exception, the copyright holders give
+ permission to link the code of this program with any edition of
+ the Qt library by Trolltech AS, Norway (or with modified versions
+ of Qt that use the same license as Qt), and distribute linked
+ combinations including the two. You must obey the GNU General
+ Public License in all respects for all of the code used other than
+ Qt. If you modify this file, you may extend this exception to
+ your version of the file, but you are not obligated to do so. If
+ you do not wish to do so, delete this exception statement from
+ your version.
+
+*/
+
+#include <resources.h>
+#include "catalogitem.h"
+#include "catalogsettings.h"
+#include "main.h"
+
+#include <qdom.h>
+
+#include <kconfig.h>
+#include <kdebug.h>
+#include <kgenericfactory.h>
+#include <klibloader.h>
+#include <klocale.h>
+#include <kmessagebox.h>
+
+/***************************************************
+ *
+ * Factory
+ *
+ ***************************************************/
+
+K_EXPORT_COMPONENT_FACTORY( kbabel_xmltool, KGenericFactory<XMLTool> ( "kbabeldatatool" ) )
+
+using namespace KBabel;
+
+XMLTool::XMLTool( QObject* parent, const char* name, const QStringList & )
+ : KDataTool( parent, name ), _cache_origin( 0 )
+{
+ i18n( "what check found errors", "XML tags" );
+}
+
+bool XMLTool::run( const QString& command, void* data, const QString& datatype, const QString& mimetype )
+{
+ if ( command != "validate" )
+ {
+ kdDebug(KBABEL) << "XML Tool does only accept the command 'validate' and 'shortcut'" << endl;
+ kdDebug(KBABEL) << " The commands " << command << " is not accepted" << endl;
+ return FALSE;
+ }
+
+ // Check wether we can accept the data
+ if ( datatype != "CatalogItem" )
+ {
+ kdDebug(KBABEL) << "XML Tool only accepts datatype CatalogItem" << endl;
+ return FALSE;
+ }
+
+ if ( mimetype != "application/x-kbabel-catalogitem" )
+ {
+ kdDebug(KBABEL) << "XML Tool only accepts mimetype application/x-kbabel-catalogitem" << endl;
+ return FALSE;
+ }
+
+ if( command == "validate" )
+ {
+ CatalogItem* item = (CatalogItem*)(data);
+
+ if( _cache_origin != item->project() )
+ {
+ _context = item->project()->miscSettings().contextInfo;
+ _cache_origin = item->project();
+ }
+
+ uint correctnessLevel = 0;
+ QString msgid = item->msgid().first();
+ msgid.replace( "\\\"", "\"" ); // Change '\"' to '"'
+ msgid.replace( QRegExp( "&(?![a-zA-Z0-9]+;)" ), "&amp;" );
+ msgid.replace( _context, "" );
+ msgid.replace("\n",""); // delete newlines
+
+ if( _levelCache.contains(msgid) )
+ {
+ correctnessLevel = _levelCache[msgid];
+ }
+ else
+ {
+ // identify the level of correctness
+ if( isFullyCompliant(msgid) )
+ {
+ correctnessLevel = 0;
+ }
+ else if( isNonCaseCompliant(msgid) )
+ {
+ correctnessLevel = 1;
+ }
+ else if( isNonCaseWithoutCommonCompliant(msgid) )
+ {
+ correctnessLevel = 2;
+ }
+ else
+ {
+ correctnessLevel = 3;
+ }
+
+ _levelCache[msgid] = correctnessLevel;
+ }
+
+ bool hasError = false;
+
+ if(!item->isUntranslated())
+ {
+ QStringList str = item->msgstr(true);
+ for( QStringList::Iterator form = str.begin() ; form != str.end() ; form++ )
+ {
+ QString text=(*form);
+ text.replace( "\\\"", "\"" ); // Change '\"' to '"'
+ text.replace( QRegExp( "&(?![a-zA-Z0-9]+;)" ), "&amp;" );
+
+ // isNonCaseWithoutCommonCompliant can fail
+ // even though higher level checks works
+ // see case 2.
+ switch( correctnessLevel )
+ {
+ case 0: hasError = !isFullyCompliant(text); break;
+ case 1: hasError = !isNonCaseCompliant(text); break;
+ case 2: hasError = !isNonCaseWithoutCommonCompliant(text);
+ if (hasError)
+ {
+ hasError = !isNonCaseCompliant(text) ||
+ !isFullyCompliant(text);
+ }
+ break;
+ case 3: hasError = false; break; // the original is broken
+ default: kdWarning() << "No compliance level, this should not happen" << endl;
+ }
+ }
+ }
+
+ if(hasError)
+ {
+ item->appendError( "XML tags" );
+ }
+ else
+ {
+ item->removeError( "XML tags" );
+ }
+
+ return !hasError;
+ }
+ return FALSE;
+}
+
+bool XMLTool::isFullyCompliant( const QString& text)
+{
+ QDomDocument doc;
+ return doc.setContent("<para>" + text + "</para>" );
+}
+
+bool XMLTool::isNonCaseCompliant( const QString& text)
+{
+ QDomDocument doc;
+ QString test = text.lower();
+ return doc.setContent("<para>" + test + "</para>" );
+}
+
+bool XMLTool::isNonCaseWithoutCommonCompliant( const QString& text)
+{
+ QDomDocument doc;
+ QString test = text.lower();
+ QRegExp rx( "(<br>)|(<hr>)|(<p>)||(<\\w+@(\\w+.)*\\w+>)" );
+ test.replace( rx, "" );
+
+ QString a;
+ do
+ {
+ a = test;
+ test.replace( QRegExp("<[^_:A-Za-z/]"), "" );
+ } while( a!=test);
+
+ test.replace( QRegExp("<$"), "" );
+
+ return doc.setContent("<para>" + test + "</para>" );
+}
+
+#include "main.moc"
diff --git a/kbabel/datatools/xml/main.h b/kbabel/datatools/xml/main.h
new file mode 100644
index 00000000..65b231e8
--- /dev/null
+++ b/kbabel/datatools/xml/main.h
@@ -0,0 +1,59 @@
+/* This file is part of KBabel
+ based on Copyright (C) 1998, 1999 Torben Weis <weis@kde.org>
+ 2002-2003 Stanislav Visnovsky <visnovsky@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.
+
+ In addition, as a special exception, the copyright holders give
+ permission to link the code of this program with any edition of
+ the Qt library by Trolltech AS, Norway (or with modified versions
+ of Qt that use the same license as Qt), and distribute linked
+ combinations including the two. You must obey the GNU General
+ Public License in all respects for all of the code used other than
+ Qt. If you modify this file, you may extend this exception to
+ your version of the file, but you are not obligated to do so. If
+ you do not wish to do so, delete this exception statement from
+ your version.
+
+*/
+
+#ifndef __main_h__
+#define __main_h__
+
+#include "kbproject.h"
+
+#include <qmap.h>
+#include <kdatatool.h>
+
+class XMLTool : public KDataTool
+{
+ Q_OBJECT
+
+public:
+ XMLTool( QObject* parent, const char* name, const QStringList & );
+ virtual bool run( const QString& command, void* data, const QString& datatype, const QString& mimetype);
+private:
+ bool isFullyCompliant( const QString& text);
+ bool isNonCaseCompliant( const QString& text);
+ bool isNonCaseWithoutCommonCompliant( const QString& text);
+
+ QMap<QString,int> _levelCache;
+
+ KBabel::Project::Ptr _cache_origin;
+ QRegExp _context;
+};
+
+#endif
diff --git a/kbabel/filters/Makefile.am b/kbabel/filters/Makefile.am
new file mode 100644
index 00000000..ed8a0b63
--- /dev/null
+++ b/kbabel/filters/Makefile.am
@@ -0,0 +1,3 @@
+SUBDIRS = gettext linguist xliff
+
+
diff --git a/kbabel/filters/gettext/Makefile.am b/kbabel/filters/gettext/Makefile.am
new file mode 100644
index 00000000..58186306
--- /dev/null
+++ b/kbabel/filters/gettext/Makefile.am
@@ -0,0 +1,20 @@
+####### General stuff
+
+INCLUDES= -I../../common -I$(srcdir)/../../common $(all_includes)
+
+kde_module_LTLIBRARIES = kbabel_gettextimport.la kbabel_gettextexport.la
+
+kbabel_gettextimport_la_SOURCES = gettextimport.cpp
+kbabel_gettextimport_la_LIBADD = ../../common/libkbabelcommon.la
+kbabel_gettextimport_la_LDFLAGS = -module $(KDE_PLUGIN) $(all_libraries)
+
+kbabel_gettextexport_la_SOURCES = gettextexport.cpp
+kbabel_gettextexport_la_LIBADD = ../../common/libkbabelcommon.la
+kbabel_gettextexport_la_LDFLAGS = -module $(KDE_PLUGIN) $(all_libraries)
+
+METASOURCES = AUTO
+
+service_DATA = kbabel_gettext_import.desktop kbabel_gettext_export.desktop
+servicedir = $(kde_servicesdir)
+
+gettextexport.lo: ../../common/kbprojectsettings.h
diff --git a/kbabel/filters/gettext/gettextexport.cpp b/kbabel/filters/gettext/gettextexport.cpp
new file mode 100644
index 00000000..e951847b
--- /dev/null
+++ b/kbabel/filters/gettext/gettextexport.cpp
@@ -0,0 +1,352 @@
+/* ****************************************************************************
+ This file is part of KBabel
+
+ Copyright (C) 1999-2000 by Matthias Kiefer <matthias.kiefer@gmx.de>
+ 2001-2002 by Stanislav Visnovsky <visnovsky@kde.org>
+ Copyright (C) 2005,2006 by Nicolas GOUTTE <goutte@kde.org>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the 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, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+ In addition, as a special exception, the copyright holders give
+ permission to link the code of this program with any edition of
+ the Qt library by Trolltech AS, Norway (or with modified versions
+ of Qt that use the same license as Qt), and distribute linked
+ combinations including the two. You must obey the GNU General
+ Public License in all respects for all of the code used other than
+ Qt. If you modify this file, you may extend this exception to
+ your version of the file, but you are not obligated to do so. If
+ you do not wish to do so, delete this exception statement from
+ your version.
+
+**************************************************************************** */
+
+#include "gettextexport.h"
+
+#include <resources.h>
+#include "catalog.h"
+#include "catalogitem.h"
+#include "catalogsettings.h"
+#include "kbprojectsettings.h"
+
+#include <qfile.h>
+#include <qtextcodec.h>
+
+#include <kapplication.h>
+#include <kdebug.h>
+#include <kgenericfactory.h>
+
+K_EXPORT_COMPONENT_FACTORY( kbabel_gettextexport, KGenericFactory<GettextExportPlugin> ( "kbabelgettextexportfilter" ) )
+
+using namespace KBabel;
+
+GettextExportPlugin::GettextExportPlugin(QObject* parent, const char* name, const QStringList &) :
+ CatalogExportPlugin(parent,name), m_wrapWidth( -1 )
+{
+}
+
+ConversionStatus GettextExportPlugin::save(const QString& localFile , const QString& mimetype, const Catalog* catalog)
+{
+ // check, whether we know how to handle the extra data
+ if( catalog->importPluginID() != "GNU gettext")
+ return UNSUPPORTED_TYPE;
+
+ // we support on the application/x-gettext MIME type
+ if( mimetype != "application/x-gettext")
+ return UNSUPPORTED_TYPE;
+
+ QFile file(localFile);
+
+ if(file.open(IO_WriteOnly))
+ {
+ int progressRatio = QMAX(100/ QMAX(catalog->numberOfEntries(),1), 1);
+ emit signalResetProgressBar(i18n("saving file"),100);
+
+ QTextStream stream(&file);
+
+ SaveSettings _saveSettings = catalog->saveSettings();
+
+ if(_saveSettings.useOldEncoding && catalog->fileCodec())
+ {
+ stream.setCodec(catalog->fileCodec());
+ }
+ else
+ {
+ switch(_saveSettings.encoding)
+ {
+ case ProjectSettingsBase::UTF8:
+ stream.setCodec(QTextCodec::codecForName("utf-8"));
+ break;
+ case ProjectSettingsBase::UTF16:
+ stream.setCodec(QTextCodec::codecForName("utf-16"));
+ break;
+ default:
+ stream.setCodec(QTextCodec::codecForLocale());
+ break;
+ }
+ }
+
+ // only save header if it is not empty
+ const QString headerComment( catalog->header().comment() );
+ // ### TODO: why is this useful to have a header with an empty msgstr?
+ if( !headerComment.isEmpty() || !catalog->header().msgstr().isEmpty() )
+ {
+ // write header
+ writeComment( stream, headerComment );
+
+ const QString headerMsgid = catalog->header().msgid().first();
+
+ // Gettext PO files should have an empty msgid as header
+ if ( !headerMsgid.isEmpty() )
+ {
+ // ### TODO: perhaps it is grave enough for a user message
+ kdWarning() << "Non-empty msgid for the header, assuming empty msgid!" << endl << headerMsgid << "---" << endl;
+ }
+
+ // ### FIXME: if it is the header, then the msgid should be empty! (Even if KBabel has made something out of a non-header first entry!)
+ stream << "msgid \"\"\n";
+
+ writeKeyword( stream, "msgstr", catalog->header().msgstr().first() );
+
+ stream << "\n";
+ }
+
+ QStringList list;
+ for( uint counter = 0; counter < catalog->numberOfEntries() ; counter++ )
+ {
+ if(counter%10==0) {
+ emit signalProgress(counter/progressRatio);
+ }
+
+ // write entry
+ writeComment( stream, catalog->comment(counter) );
+
+ const QString msgctxt = catalog->msgctxt(counter);
+ if (! msgctxt.isEmpty() )
+ {
+ writeKeyword( stream, "msgctxt", msgctxt );
+ }
+
+ writeKeyword( stream, "msgid", catalog->msgid( counter ).first() );
+ if( catalog->pluralForm( counter ) == Gettext )
+ {
+ writeKeyword( stream, "msgid_plural", catalog->msgid( counter ).last() );
+ }
+
+ if( catalog->pluralForm(counter) != Gettext)
+ {
+ writeKeyword( stream, "msgstr", catalog->msgstr( counter ).first() );
+ }
+ else
+ {
+ kdDebug(KBABEL) << "Saving gettext plural form" << endl;
+ const int forms = catalog->msgstr( counter ).count();
+ for ( int i = 0; i < forms; ++i )
+ {
+ QString keyword ( "msgstr[" );
+ keyword += QString::number( i );
+ keyword += ']';
+
+ writeKeyword( stream, keyword, *( catalog->msgstr( counter ).at( i ) ) );
+ }
+ }
+
+ stream << "\n";
+
+ kapp->processEvents(10);
+ if( isStopped() )
+ {
+ return STOPPED;
+ }
+ }
+
+ if( _saveSettings.saveObsolete )
+ {
+ QValueList<QString>::ConstIterator oit;
+
+ QStringList _obsolete = catalog->catalogExtraData();
+
+ for( oit = _obsolete.begin(); oit != _obsolete.end(); ++oit )
+ {
+ stream << (*oit) << "\n\n";
+
+ kapp->processEvents(10);
+ if( isStopped() )
+ {
+ return STOPPED;
+ }
+ }
+ }
+
+ emit signalProgress(100);
+ file.close();
+
+ emit signalClearProgressBar();
+ }
+ else
+ {
+ //emit signalError(i18n("Wasn't able to open file %1").arg(filename.ascii()));
+ return OS_ERROR;
+ }
+
+ return OK;
+}
+
+void GettextExportPlugin::writeComment( QTextStream& stream, const QString& comment ) const
+{
+ if( !comment.isEmpty() )
+ {
+ // We must check that each comment line really starts with a #, to avoid syntax errors
+ int pos = 0;
+ for(;;)
+ {
+ const int newpos = comment.find( '\n', pos, false );
+ if ( newpos == pos )
+ {
+ ++pos;
+ stream << "\n";
+ continue;
+ }
+ const QString span ( ( newpos == -1 ) ? comment.mid( pos ) : comment.mid( pos, newpos-pos ) );
+
+ const int len = span.length();
+ QString spaces; // Stored leading spaces
+ for ( int i = 0 ; i < len ; ++i )
+ {
+ const QChar& ch = span[ i ];
+ if ( ch == '#' )
+ {
+ stream << spaces << span.mid( i );
+ break;
+ }
+ else if ( ch == ' ' || ch == '\t' )
+ {
+ // We have a leading white space character, so store it temporary
+ spaces += ch;
+ }
+ else
+ {
+ // Not leading white space and not a # character. so consider that the # character was missing at first position.
+ stream << "# " << spaces << span.mid( i );
+ break;
+ }
+ }
+ stream << "\n";
+
+ if ( newpos == -1 )
+ break;
+ else
+ pos = newpos + 1;
+ }
+ }
+}
+
+void GettextExportPlugin::writeKeyword( QTextStream& stream, const QString& keyword, const QString& text ) const
+{
+ if ( text.isEmpty() )
+ {
+ // Whatever the wrapping mode, an empty line is an empty line
+ stream << keyword << " \"\"\n";
+ return;
+ }
+ else if ( m_wrapWidth == -1 )
+ {
+ // Traditional KBabel wrapping
+ QStringList list = QStringList::split( '\n', text );
+
+ if ( text.startsWith( "\n" ) )
+ list.prepend( QString() );
+
+ if(list.isEmpty())
+ list.append( QString() );
+
+ if( list.count() > 1 )
+ list.prepend( QString() );
+
+ stream << keyword << " ";
+
+ QStringList::const_iterator it;
+ for( it = list.constBegin(); it != list.constEnd(); ++it )
+ {
+ stream << "\"" << (*it) << "\"\n";
+ }
+ return;
+ }
+ else if ( ( !m_wrapWidth )
+ || ( m_wrapWidth < 0 ) // Unknown special wrapping, so assume "no wrap" instead
+ )
+ {
+ // No wrapping (like Gettext's --no.wrap or -w0 )
+
+ // we need to remove the \n characters, as they are extra characters
+ QString realText( text );
+ realText.remove( '\n' );
+ stream << keyword << " \"" << realText << "\"\n";
+ return;
+ }
+
+ // ### TODO: test!
+ // Normal wrapping like Gettext's -w parameter with a value bigger than 0
+ // From here on, we assume that we have an non-empty text and a positive non-null m_wrapWidth
+
+ // we need to remove the \n characters, as they are extra characters
+ QString realText( text );
+ realText.remove( '\n' );
+
+ bool needFirstEmptyLine = false;
+ if ( realText.find( "\\n" ) != -1 )
+ {
+ // We have more than one (logical) line, so write the extra empty line
+ needFirstEmptyLine = true;
+ }
+ else
+ {
+ // We must see if the text would fit in one line, including the keyword, a space and two quote characters.
+ const int rest = text.length() + keyword.length() + 3 - m_wrapWidth;
+ if ( rest > 0 )
+ {
+ needFirstEmptyLine = true;
+ }
+ }
+ int availableWidth = m_wrapWidth;
+ if ( needFirstEmptyLine )
+ {
+ stream << keyword << " \"\"\n";
+ }
+ else
+ {
+ stream << keyword << " ";
+ availableWidth -= keyword.length();
+ availableWidth--; // The space after the keyword
+ }
+
+ const int spanLength = realText.length();
+ for ( int pos = 0; pos < spanLength; )
+ {
+ availableWidth -= 2; // Count the quote characters
+ if ( availableWidth < 2 )
+ {
+ // Be sure that at least two useful characters are written, even if the wrap width is too small
+ availableWidth = 2;
+ }
+ const int newlinePos = realText.find ( "\\n", pos );
+ if ( ( newlinePos >= 0 ) && ( newlinePos - pos + 2 < availableWidth ) )
+ {
+ // The newline is near than the maximum available numbers of characters
+ availableWidth = newlinePos - pos + 2;
+ }
+ stream << '\"' << realText.mid( pos, availableWidth ) << "\"\n";
+ pos += availableWidth;
+ }
+}
diff --git a/kbabel/filters/gettext/gettextexport.h b/kbabel/filters/gettext/gettextexport.h
new file mode 100644
index 00000000..81cbe9c4
--- /dev/null
+++ b/kbabel/filters/gettext/gettextexport.h
@@ -0,0 +1,88 @@
+/* ****************************************************************************
+ This file is part of KBabel
+
+ Copyright (C) 2002 by Stanislav Visnovsky <visnovsky@kde.org>
+ Copyright (C) 2006 by Nicolas GOUTTE <goutte@kde.org>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the 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, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+ In addition, as a special exception, the copyright holders give
+ permission to link the code of this program with any edition of
+ the Qt library by Trolltech AS, Norway (or with modified versions
+ of Qt that use the same license as Qt), and distribute linked
+ combinations including the two. You must obey the GNU General
+ Public License in all respects for all of the code used other than
+ Qt. If you modify this file, you may extend this exception to
+ your version of the file, but you are not obligated to do so. If
+ you do not wish to do so, delete this exception statement from
+ your version.
+
+**************************************************************************** */
+#ifndef GETTEXTEXPORTPLUGIN_H
+#define GETTEXTEXPORTPLUGIN_H
+
+#include <catalogfileplugin.h>
+
+#include <qstringlist.h>
+
+namespace KBabel {
+class Catalog;
+}
+class KURL;
+class QFile;
+class QTextCodec;
+
+/**
+ * @brief The class for exporting GNU gettext PO files.
+ *
+ * As an extra information, it stores the list of all obsolete entries.
+ */
+
+class GettextExportPlugin: public KBabel::CatalogExportPlugin
+{
+public:
+ GettextExportPlugin(QObject* parent, const char* name, const QStringList &);
+ virtual KBabel::ConversionStatus save(const QString& file, const QString& mimetype, const KBabel::Catalog* catalog);
+
+private:
+ /**
+ * Write a PO comment to @p stream and take care that each comment lines start with a # character
+ */
+ void writeComment( QTextStream& stream, const QString& comment ) const;
+
+ /**
+ * Write a PO keyword (msgctxt, msgid, msgstr, msgstr_plural, msgstr[0]) and the corresponding text.
+ * This includes wrapping the text.
+ */
+ void writeKeyword( QTextStream& stream, const QString& keyword, const QString& text ) const;
+
+public:
+ /**
+ * @brief Width of the wrap
+ *
+ * This is the width of the wrap in characters (not bytes), including everything
+ * (e.g. keyword, quote characters, spaces).
+ *
+ * - A value of 0 means no wrap
+ * - A value of -1 means the traditional KBabel wrapping
+ * - Other negative values are reserved for future extensions (by default: no wrap)
+ * @note
+ * - Gettext's default value is 78 characters
+ * - Too small values might not be correctly supported.
+ */
+ int m_wrapWidth;
+};
+
+#endif
diff --git a/kbabel/filters/gettext/gettextimport.cpp b/kbabel/filters/gettext/gettextimport.cpp
new file mode 100644
index 00000000..3f54301d
--- /dev/null
+++ b/kbabel/filters/gettext/gettextimport.cpp
@@ -0,0 +1,821 @@
+// kate: space-indent on; indent-width 3; replace-tabs on;
+
+/* ****************************************************************************
+ This file is part of KBabel
+
+ Copyright (C) 1999-2000 by Matthias Kiefer <matthias.kiefer@gmx.de>
+ 2001-2003 by Stanislav Visnovsky <visnovsky@kde.org>
+ Copyright (C) 2006 by Nicolas GOUTTE <nicolasg@snafu.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.
+
+ 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, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+ In addition, as a special exception, the copyright holders give
+ permission to link the code of this program with any edition of
+ the Qt library by Trolltech AS, Norway (or with modified versions
+ of Qt that use the same license as Qt), and distribute linked
+ combinations including the two. You must obey the GNU General
+ Public License in all respects for all of the code used other than
+ Qt. If you modify this file, you may extend this exception to
+ your version of the file, but you are not obligated to do so. If
+ you do not wish to do so, delete this exception statement from
+ your version.
+
+**************************************************************************** */
+
+#include "gettextimport.h"
+
+#include <catalogitem.h>
+#include <resources.h>
+
+#include <qfile.h>
+#include <qfileinfo.h>
+#include <qregexp.h>
+#include <qtextcodec.h>
+
+#include <kapplication.h>
+#include <kdebug.h>
+#include <kgenericfactory.h>
+#include <klocale.h>
+
+K_EXPORT_COMPONENT_FACTORY( kbabel_gettextimport, KGenericFactory<GettextImportPlugin> ( "kbabelgettextimportfilter" ) )
+
+using namespace KBabel;
+
+GettextImportPlugin::GettextImportPlugin(QObject* parent, const char* name, const QStringList &) : CatalogImportPlugin(parent,name)
+{
+}
+
+ConversionStatus GettextImportPlugin::load(const QString& filename, const QString&)
+{
+ kdDebug( KBABEL ) << k_funcinfo << endl;
+
+ if ( filename.isEmpty() ) {
+ kdDebug(KBABEL) << "fatal error: empty filename to open" << endl;
+ return NO_FILE;
+ }
+
+ QFileInfo info(filename);
+
+ if(!info.exists() || info.isDir())
+ return NO_FILE;
+
+ if(!info.isReadable())
+ return NO_PERMISSIONS;
+
+ QFile file(filename);
+
+ if ( !file.open( IO_ReadOnly ) )
+ return NO_PERMISSIONS;
+
+ uint oldPercent = 0;
+ emit signalResetProgressBar(i18n("loading file"),100);
+
+ QByteArray ba = file.readAll();
+ file.close();
+
+ // find codec for file
+ bool hadCodec;
+ QTextCodec* codec=codecForArray( ba, &hadCodec );
+
+ bool recoveredErrorInHeader = false;
+
+ QTextStream stream(ba,IO_ReadOnly);
+
+ if(codec)
+ stream.setCodec(codec);
+ else
+ {
+ kdWarning() << "No encoding declared or found, using UTF-8" << endl;
+ stream.setEncoding( QTextStream::UnicodeUTF8 );
+#ifdef __GNUC__
+# warning Default UTF-8 encoding needs to be improved
+#endif
+ // Templates define CHARSET, so if e make it a recoverable error, the template is not loadable anymore, as for templates recoverable errors are disqualifying.
+ //recoveredErrorInHeader = true;
+ }
+
+ QIODevice *dev = stream.device();
+ int fileSize = dev->size();
+
+ // if somethings goes wrong with the parsing, we don't have deleted the old contents
+ CatalogItem tempHeader;
+ QStringList tempObsolete;
+
+
+ kdDebug(KBABEL) << "start parsing..." << endl;
+
+ // first read header
+ const ConversionStatus status = readHeader(stream);
+
+
+ if ( status == RECOVERED_PARSE_ERROR )
+ {
+ kdDebug( KBABEL ) << "Recovered error in header entry" << endl;
+ recoveredErrorInHeader = true;
+ }
+ else if ( status != OK )
+ {
+ emit signalClearProgressBar();
+
+ kdDebug( KBABEL ) << "Parse error in header entry" << endl;
+ return status;
+ }
+
+ kdDebug() << "HEADER MSGID: " << _msgid << endl;
+ kdDebug() << "HEADER MSGSTR: " << _msgstr << endl;
+ if ( !_msgid.isEmpty() && !_msgid.first().isEmpty() )
+ {
+ // The header must have an empty msgid
+ kdWarning(KBABEL) << "Header entry has non-empty msgid. Creating a temporary header! " << _msgid << endl;
+ tempHeader.setMsgid( QStringList() );
+ QStringList tmp;
+ tmp.append(
+ "Content-Type: text/plain; charset=UTF-8\\n" // Unknown charset
+ "Content-Transfer-Encoding: 8bit\\n"
+ "Mime-Version: 1.0" );
+ tempHeader.setMsgstr( tmp );
+ // We keep the comment of the first entry, as it might really be a header comment (at least partially)
+ const QString comment( "# Header entry was created by KBabel!\n#\n" + _comment );
+ tempHeader.setComment( comment );
+ recoveredErrorInHeader = true;
+ }
+ else
+ {
+ tempHeader.setMsgid( _msgid );
+ tempHeader.setMsgstr( _msgstr );
+ tempHeader.setComment( _comment );
+ }
+ if(tempHeader.isFuzzy())
+ {
+ tempHeader.removeFuzzy();
+ }
+
+ // check if header seems to indicate docbook content generated by xml2pot
+ const bool docbookContent = (tempHeader.msgstr().find("application/x-xml2pot") != tempHeader.msgstr().end());
+
+ // now parse the rest of the file
+ uint counter=0;
+ QValueList<uint> errorIndex;
+ bool recoveredError=false;
+ bool docbookFile=false;
+
+ while( !stream.eof() )
+ {
+ kapp->processEvents(10);
+ if( isStopped() )
+ {
+ return STOPPED;
+ }
+
+ const ConversionStatus success=readEntry(stream);
+
+ if(success==OK)
+ {
+ if( _obsolete )
+ {
+ tempObsolete.append(_comment);
+ }
+ else
+ {
+ CatalogItem tempCatItem;
+ tempCatItem.setMsgctxt( _msgctxt );
+ tempCatItem.setMsgid( _msgid );
+ tempCatItem.setMsgstr( _msgstr );
+ tempCatItem.setComment( _comment );
+ tempCatItem.setGettextPluralForm( _gettextPluralForm );
+
+ // add new entry to the list of entries
+ appendCatalogItem(tempCatItem);
+ // check if first comment seems to indicate a docbook source file
+ if(counter==0)
+ docbookFile = ( tempCatItem.comment().find(".docbook") != -1 );
+ }
+ }
+ else if(success==RECOVERED_PARSE_ERROR)
+ {
+ kdDebug( KBABEL ) << "Recovered parse error in entry: " << counter << endl;
+ recoveredError=true;
+ errorIndex.append(counter);
+
+ CatalogItem tempCatItem;
+ tempCatItem.setMsgctxt( _msgctxt );
+ tempCatItem.setMsgid( _msgid );
+ tempCatItem.setMsgstr( _msgstr );
+ tempCatItem.setComment( _comment );
+ tempCatItem.setGettextPluralForm( _gettextPluralForm );
+
+ // add new entry to the list of entries
+ appendCatalogItem(tempCatItem);
+ }
+ else if ( success == PARSE_ERROR )
+ {
+ kdDebug( KBABEL ) << "Parse error in entry: " << counter << endl;
+ return PARSE_ERROR;
+ }
+ else
+ {
+ kdWarning( KBABEL ) << "Unknown success status, assumig parse error " << success << endl;
+ return PARSE_ERROR;
+ }
+ counter++;
+
+ const uint newPercent = (100*dev->at())/fileSize;
+ if(newPercent > oldPercent)
+ {
+ oldPercent = newPercent;
+ emit signalProgress(oldPercent);
+ }
+ }
+
+
+ // to be sure it is set to 100, if someone don't connect to
+ // signalClearProgressBar()
+ emit signalProgress(100);
+
+ emit signalClearProgressBar();
+
+
+ // ### TODO: can we check that there is no useful entry?
+ if ( !counter )
+ {
+ // Empty file? (Otherwise, there would be a try of getting an entry and the count would be 1 !)
+ kdDebug( KBABEL ) << k_funcinfo << " Empty file?" << endl;
+ return PARSE_ERROR;
+ }
+
+ kdDebug(KBABEL) << k_funcinfo << " ready" << endl;
+
+ // We have succesfully loaded the file (perhaps with recovered errors)
+
+ setGeneratedFromDocbook(docbookContent || docbookFile);
+
+ setHeader(tempHeader);
+ setCatalogExtraData(tempObsolete);
+ setErrorIndex(errorIndex);
+
+ if(hadCodec)
+ setFileCodec(codec);
+ else
+ setFileCodec(0);
+
+ setMimeTypes( "application/x-gettext" );
+
+ if ( recoveredErrorInHeader )
+ {
+ kdDebug( KBABEL ) << k_funcinfo << " Returning: header error" << endl;
+ return RECOVERED_HEADER_ERROR;
+ }
+ else if ( recoveredError )
+ {
+ kdDebug( KBABEL ) << k_funcinfo << " Returning: recovered parse error" << endl;
+ return RECOVERED_PARSE_ERROR;
+ }
+ else
+ {
+ kdDebug( KBABEL ) << k_funcinfo << " Returning: OK! :-)" << endl;
+ return OK;
+ }
+}
+
+QTextCodec* GettextImportPlugin::codecForArray(QByteArray& array, bool* hadCodec)
+{
+ if(hadCodec)
+ {
+ *hadCodec=false;
+ }
+
+ QTextStream stream( array, IO_ReadOnly );
+ // ### TODO Qt4: see if it can be done with QByteArray alone, in an encoding-neutral way.
+ // Set ISO-8859-1 as it is a relatively neutral encoding when reading (compared to UTF-8 or a random locale encoing)
+ stream.setEncoding( QTextStream::Latin1 );
+
+ // first read header
+ ConversionStatus status = readHeader(stream);
+ if(status!=OK && status != RECOVERED_PARSE_ERROR)
+ {
+ kdDebug(KBABEL) << "wasn't able to read header" << endl;
+ return 0;
+ }
+
+ const QString head = _msgstr.first();
+
+ QRegExp regexp("Content-Type:\\s*\\w+/[-\\w]+;?\\s*charset\\s*=\\s*(\\S+)\\s*\\\\n");
+ if( regexp.search( head ) == -1 )
+ {
+ kdDebug(KBABEL) << "no charset entry found" << endl;
+ return 0;
+ }
+
+ const QString charset = regexp.cap(1);
+ kdDebug(KBABEL) << "charset: " << charset << endl;
+
+ QTextCodec* codec=0;
+
+ if(!charset.isEmpty())
+ {
+ // "CHARSET" is the default charset entry in a template (pot).
+ // characters in a template should be either pure ascii or
+ // at least utf8, so utf8-codec can be used for both.
+ if( charset == "CHARSET")
+ {
+ if(hadCodec)
+ *hadCodec=false;
+
+ codec=QTextCodec::codecForName("utf8");
+ kdDebug(KBABEL)
+ << QString("file seems to be a template: using utf-8 encoding.")
+ << endl;
+ }
+ else
+ {
+ codec=QTextCodec::codecForName(charset.latin1());
+ if(hadCodec)
+ *hadCodec=true;
+ }
+
+ if(!codec)
+ {
+ kdWarning(KBABEL) << "charset found, but no codec available, using UTF-8 instead" << endl;
+ }
+ }
+ else
+ {
+ // No charset? So it is probably ASCII, therefore UTF-8
+ kdWarning(KBABEL) << "No charset defined! Assuming UTF-8!" << endl;
+ }
+
+
+ return codec;
+}
+
+ConversionStatus GettextImportPlugin::readHeader(QTextStream& stream)
+{
+ CatalogItem temp;
+ int filePos=stream.device()->at();
+ ConversionStatus status=readEntry(stream);
+
+ if(status==OK || status==RECOVERED_PARSE_ERROR)
+ {
+ // test if this is the header
+ if(!_msgid.first().isEmpty())
+ {
+ stream.device()->at(filePos);
+ }
+
+ return status;
+ }
+
+ return PARSE_ERROR;
+}
+
+ConversionStatus GettextImportPlugin::readEntry(QTextStream& stream)
+{
+ //kdDebug( KBABEL ) << k_funcinfo << " START" << endl;
+ enum {Begin,Comment,Msgctxt,Msgid,Msgstr} part=Begin;
+
+ QString line;
+ bool error=false;
+ bool recoverableError=false;
+ bool seenMsgctxt=false;
+ _msgstr.clear();
+ _msgstr.append(QString());
+ _msgid.clear();
+ _msgid.append(QString());
+ _msgctxt=QString();
+ _comment=QString();
+ _gettextPluralForm=false;
+ _obsolete=false;
+
+ QStringList::Iterator msgstrIt=_msgstr.begin();
+
+ while( !stream.eof() )
+ {
+ const int pos=stream.device()->at();
+
+ line=stream.readLine();
+
+ //kdDebug() << "Parsing line: " << line << endl;
+
+ // ### Qt4: no need of a such a check
+ if(line.isNull()) // file end
+ break;
+ else if ( line.startsWith( "<<<<<<<" ) || line.startsWith( "=======" ) || line.startsWith( ">>>>>>>" ) )
+ {
+ // We have found a CVS/SVN conflict marker. Abort.
+ // (It cannot be any useful data of the PO file, as otherwise the line would start with at least a quote)
+ kdError(KBABEL) << "CVS/SVN conflict marker found! Aborting!" << endl << line << endl;
+ return PARSE_ERROR;
+ }
+
+ // remove whitespaces from beginning and end of line
+ line=line.stripWhiteSpace();
+
+ if(part==Begin)
+ {
+ // ignore trailing newlines
+ if(line.isEmpty())
+ continue;
+
+ if(line.startsWith("#~"))
+ {
+ _obsolete=true;
+ part=Comment;
+ _comment=line;
+ }
+ else if(line.startsWith("#"))
+ {
+ part=Comment;
+ _comment=line;
+ }
+ else if(line.find(QRegExp("^msgctxt\\s*\".*\"$")) != -1)
+ {
+ part=Msgctxt;
+
+ // remove quotes at beginning and the end of the lines
+ line.remove(QRegExp("^msgctxt\\s*\""));
+ line.remove(QRegExp("\"$"));
+ _msgctxt=line;
+ seenMsgctxt=true;
+ }
+ else if(line.find(QRegExp("^msgid\\s*\".*\"$")) != -1)
+ {
+ part=Msgid;
+
+ // remove quotes at beginning and the end of the lines
+ line.remove(QRegExp("^msgid\\s*\""));
+ line.remove(QRegExp("\"$"));
+
+ (*(_msgid).begin())=line;
+ }
+ // one of the quotation marks is missing
+ else if(line.find(QRegExp("^msgid\\s*\"?.*\"?$")) != -1)
+ {
+ part=Msgid;
+
+ // remove quotes at beginning and the end of the lines
+ line.remove(QRegExp("^msgid\\s*\"?"));
+ line.remove(QRegExp("\"$"));
+
+ (*(_msgid).begin())=line;
+
+ if(!line.isEmpty())
+ recoverableError=true;
+ }
+ else
+ {
+ kdDebug(KBABEL) << "no comment, msgctxt or msgid found after a comment: " << line << endl;
+ error=true;
+ break;
+ }
+ }
+ else if(part==Comment)
+ {
+ if(line.isEmpty() && _obsolete ) return OK;
+ if(line.isEmpty() )
+ continue;
+ else if(line.startsWith("#~"))
+ {
+ _comment+=("\n"+line);
+ _obsolete=true;
+ }
+ else if(line.startsWith("#"))
+ {
+ _comment+=("\n"+line);
+ }
+ else if(line.find(QRegExp("^msgctxt\\s*\".*\"$")) != -1)
+ {
+ part=Msgctxt;
+
+ // remove quotes at beginning and the end of the lines
+ line.remove(QRegExp("^msgctxt\\s*\""));
+ line.remove(QRegExp("\"$"));
+ _msgctxt=line;
+ seenMsgctxt=true;
+ }
+ else if(line.find(QRegExp("^msgid\\s*\".*\"$")) != -1)
+ {
+ part=Msgid;
+
+ // remove quotes at beginning and the end of the lines
+ line.remove(QRegExp("^msgid\\s*\""));
+ line.remove(QRegExp("\"$"));
+
+ (*(_msgid).begin())=line;
+ }
+ // one of the quotation marks is missing
+ else if(line.find(QRegExp("^msgid\\s*\"?.*\"?$")) != -1)
+ {
+ part=Msgid;
+
+ // remove quotes at beginning and the end of the lines
+ line.remove(QRegExp("^msgid\\s*\"?"));
+ line.remove(QRegExp("\"$"));
+
+ (*(_msgid).begin())=line;
+
+ if(!line.isEmpty())
+ recoverableError=true;
+ }
+ else
+ {
+ kdDebug(KBABEL) << "no comment or msgid found after a comment while parsing: " << _comment << endl;
+ error=true;
+ break;
+ }
+ }
+ else if(part==Msgctxt)
+ {
+ if(line.isEmpty())
+ continue;
+ else if(line.find(QRegExp("^\".*\\n?\"$")) != -1)
+ {
+ // remove quotes at beginning and the end of the lines
+ line.remove(QRegExp("^\""));
+ line.remove(QRegExp("\"$"));
+
+ // add Msgctxt line to item
+ if(_msgctxt.isEmpty())
+ _msgctxt=line;
+ else
+ _msgctxt+=("\n"+line);
+ }
+ else if(line.find(QRegExp("^msgid\\s*\".*\"$")) != -1)
+ {
+ part=Msgid;
+
+ // remove quotes at beginning and the end of the lines
+ line.remove(QRegExp("^msgid\\s*\""));
+ line.remove(QRegExp("\"$"));
+
+ (*(_msgid).begin())=line;
+ }
+ // one of the quotation marks is missing
+ else if(line.find(QRegExp("^msgid\\s*\"?.*\"?$")) != -1)
+ {
+ part=Msgid;
+
+ // remove quotes at beginning and the end of the lines
+ line.remove(QRegExp("^msgid\\s*\"?"));
+ line.remove(QRegExp("\"$"));
+
+ (*(_msgid).begin())=line;
+
+ if(!line.isEmpty())
+ recoverableError=true;
+ }
+ else
+ {
+ kdDebug(KBABEL) << "no msgid found after a msgctxt while parsing: " << _msgctxt << endl;
+ error=true;
+ break;
+ }
+ }
+ else if(part==Msgid)
+ {
+ if(line.isEmpty())
+ continue;
+ else if(line.find(QRegExp("^\".*\\n?\"$")) != -1)
+ {
+ // remove quotes at beginning and the end of the lines
+ line.remove(QRegExp("^\""));
+ line.remove(QRegExp("\"$"));
+
+ QStringList::Iterator it;
+ if(_gettextPluralForm)
+ it = _msgid.fromLast();
+ else
+ it = _msgid.begin();
+
+ // add Msgid line to item
+ if((*it).isEmpty())
+ (*it)=line;
+ else
+ (*it)+=("\n"+line);
+ }
+ else if(line.find(QRegExp("^msgid_plural\\s*\".*\"$")) != -1)
+ {
+ part=Msgid;
+ _gettextPluralForm = true;
+
+ // remove quotes at beginning and the end of the lines
+ line.remove(QRegExp("^msgid_plural\\s*\""));
+ line.remove(QRegExp("\"$"));
+
+ _msgid.append(line);
+ }
+ // one of the quotation marks is missing
+ else if(line.find(QRegExp("^msgid_plural\\s*\"?.*\"?$")) != -1)
+ {
+ part=Msgid;
+ _gettextPluralForm = true;
+
+ // remove quotes at beginning and the end of the lines
+ line.remove(QRegExp("^msgid_plural\\s*\"?"));
+ line.remove(QRegExp("\"$"));
+
+ _msgid.append(line);
+
+ if(!line.isEmpty())
+ recoverableError=true;
+ }
+ else if(!_gettextPluralForm
+ && (line.find(QRegExp("^msgstr\\s*\".*\\n?\"$")) != -1))
+ {
+ part=Msgstr;
+
+ // remove quotes at beginning and the end of the lines
+ line.remove(QRegExp("^msgstr\\s*\"?"));
+ line.remove(QRegExp("\"$"));
+
+ (*msgstrIt)=line;
+ }
+ else if(!_gettextPluralForm
+ && line.find(QRegExp("^msgstr\\s*\"?.*\\n?\"?$")) != -1)
+ {
+ part=Msgstr;
+
+ // remove quotes at beginning and the end of the lines
+ line.remove(QRegExp("^msgstr\\s*\"?"));
+ line.remove(QRegExp("\"$"));
+
+ (*msgstrIt)=line;
+
+ if(!line.isEmpty())
+ recoverableError=true;
+ }
+ else if( _gettextPluralForm
+ && (line.find(QRegExp("^msgstr\\[0\\]\\s*\".*\\n?\"$")) != -1))
+ {
+ part=Msgstr;
+
+ // remove quotes at beginning and the end of the lines
+ line.remove(QRegExp("^msgstr\\[0\\]\\s*\"?"));
+ line.remove(QRegExp("\"$"));
+
+ (*msgstrIt)=line;
+ }
+ else if( _gettextPluralForm
+ && (line.find(QRegExp("^msgstr\\[0\\]\\s*\"?.*\\n?\"?$")) != -1))
+ {
+ part=Msgstr;
+
+ // remove quotes at beginning and the end of the lines
+ line.remove(QRegExp("^msgstr\\[0\\]\\s*\"?"));
+ line.remove(QRegExp("\"$"));
+
+ (*msgstrIt)=line;
+
+ if(!line.isEmpty())
+ recoverableError=true;
+ }
+ else if ( line.startsWith( "#" ) )
+ {
+ // ### TODO: could this be considered recoverable?
+ kdDebug(KBABEL) << "comment found after a msgid while parsing: " << _msgid.first() << endl;
+ error=true;
+ break;
+ }
+ else if ( line.startsWith( "msgid" ) )
+ {
+ kdDebug(KBABEL) << "Another msgid found after a msgid while parsing: " << _msgid.first() << endl;
+ error=true;
+ break;
+ }
+ // a line of the msgid with a missing quotation mark
+ else if(line.find(QRegExp("^\"?.+\\n?\"?$")) != -1)
+ {
+ recoverableError=true;
+
+ // remove quotes at beginning and the end of the lines
+ line.remove(QRegExp("^\""));
+ line.remove(QRegExp("\"$"));
+
+ QStringList::Iterator it;
+ if( _gettextPluralForm )
+ it = _msgid.fromLast();
+ else
+ it = _msgid.begin();
+
+ // add Msgid line to item
+ if((*it).isEmpty())
+ (*it)=line;
+ else
+ (*it)+=("\n"+line);
+ }
+ else
+ {
+ kdDebug(KBABEL) << "no msgstr found after a msgid while parsing: " << _msgid.first() << endl;
+ error=true;
+ break;
+ }
+ }
+ else if(part==Msgstr)
+ {
+ if(line.isEmpty())
+ continue;
+ // another line of the msgstr
+ else if(line.find(QRegExp("^\".*\\n?\"$")) != -1)
+ {
+ // remove quotes at beginning and the end of the lines
+ line.remove(QRegExp("^\""));
+ line.remove(QRegExp("\"$"));
+
+ if((*msgstrIt).isEmpty())
+ (*msgstrIt)=line;
+ else
+ (*msgstrIt)+=("\n"+line);
+ }
+ else if( _gettextPluralForm
+ && (line.find(QRegExp("^msgstr\\[[0-9]+\\]\\s*\".*\\n?\"$")) != -1))
+ {
+ // remove quotes at beginning and the end of the lines
+ line.remove(QRegExp("^msgstr\\[[0-9]+\\]\\s*\"?"));
+ line.remove(QRegExp("\"$"));
+
+ msgstrIt=_msgstr.append(line);
+ }
+ else if( _gettextPluralForm
+ && (line.find(QRegExp("^msgstr\\[[0-9]\\]\\s*\"?.*\\n?\"?$")) != -1))
+ {
+ // remove quotes at beginning and the end of the lines
+ line.remove(QRegExp("^msgstr\\[[0-9]\\]\\s*\"?"));
+ line.remove(QRegExp("\"$"));
+
+ msgstrIt=_msgstr.append(line);
+
+ if(!line.isEmpty())
+ recoverableError=true;
+ }
+ else if((line.find(QRegExp("^\\s*msgid")) != -1) || (line.find(QRegExp("^\\s*#")) != -1))
+ {
+ // We have read successfully one entry, so end loop.
+ stream.device()->at(pos);// reset position in stream to beginning of this line
+ break;
+ }
+ else if(line.startsWith("msgstr"))
+ {
+ kdDebug(KBABEL) << "Another msgstr found after a msgstr while parsing: " << _msgstr.last() << endl;
+ error=true;
+ break;
+ }
+ // another line of the msgstr with a missing quotation mark
+ else if(line.find(QRegExp("^\"?.+\\n?\"?$")) != -1)
+ {
+ recoverableError=true;
+
+ // remove quotes at beginning and the end of the lines
+ line.remove(QRegExp("^\""));
+ line.remove(QRegExp("\"$"));
+
+ if((*msgstrIt).isEmpty())
+ (*msgstrIt)=line;
+ else
+ (*msgstrIt)+=("\n"+line);
+ }
+ else
+ {
+ kdDebug(KBABEL) << "no msgid or comment found after a msgstr while parsing: " << _msgstr.last() << endl;
+ error=true;
+ break;
+ }
+ }
+ }
+
+/*
+ if(_gettextPluralForm)
+ {
+ kdDebug(KBABEL) << "gettext plural form:\n"
+ << "msgid:\n" << _msgid.first() << "\n"
+ << "msgid_plural:\n" << _msgid.last() << "\n" << endl;
+ int counter=0;
+ for(QStringList::Iterator it = _msgstr.begin(); it != _msgstr.end(); ++it)
+ {
+ kdDebug(KBABEL) << "msgstr[" << counter << "]:\n"
+ << (*it) << endl;
+ counter++;
+ }
+ }
+ */
+
+ //kdDebug( KBABEL ) << k_funcinfo << " NEAR RETURN" << endl;
+ if(error)
+ return PARSE_ERROR;
+ else if(recoverableError)
+ return RECOVERED_PARSE_ERROR;
+ else
+ {
+ return OK;
+ }
+}
diff --git a/kbabel/filters/gettext/gettextimport.h b/kbabel/filters/gettext/gettextimport.h
new file mode 100644
index 00000000..e28ec790
--- /dev/null
+++ b/kbabel/filters/gettext/gettextimport.h
@@ -0,0 +1,70 @@
+/* ****************************************************************************
+ This file is part of KBabel
+
+ Copyright (C) 2002 by Stanislav Visnovsky
+ <visnovsky@kde.org>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the 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, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+ In addition, as a special exception, the copyright holders give
+ permission to link the code of this program with any edition of
+ the Qt library by Trolltech AS, Norway (or with modified versions
+ of Qt that use the same license as Qt), and distribute linked
+ combinations including the two. You must obey the GNU General
+ Public License in all respects for all of the code used other than
+ Qt. If you modify this file, you may extend this exception to
+ your version of the file, but you are not obligated to do so. If
+ you do not wish to do so, delete this exception statement from
+ your version.
+
+**************************************************************************** */
+#ifndef GETTEXTIMPORTPLUGIN_H
+#define GETTEXTIMPORTPLUGIN_H
+
+#include <catalogfileplugin.h>
+
+#include <qstringlist.h>
+
+class KURL;
+class QFile;
+class QTextCodec;
+
+/* ****************************************************************************
+ The class for importing GNU gettext PO files. As an extra information,
+ it stores the list of all obsolete entries.
+**************************************************************************** */
+
+class GettextImportPlugin: public KBabel::CatalogImportPlugin
+{
+public:
+ GettextImportPlugin(QObject* parent, const char* name, const QStringList &);
+ virtual KBabel::ConversionStatus load(const QString& file, const QString& mimetype);
+ virtual const QString id() { return "GNU gettext"; }
+
+private:
+ QTextCodec* codecForArray(QByteArray& arary, bool* hadCodec);
+ KBabel::ConversionStatus readHeader(QTextStream& stream);
+ KBabel::ConversionStatus readEntry(QTextStream& stream);
+
+ // description of the last read entry
+ QString _msgctxt;
+ QStringList _msgid;
+ QStringList _msgstr;
+ QString _comment;
+ bool _gettextPluralForm;
+ bool _obsolete;
+};
+
+#endif
diff --git a/kbabel/filters/gettext/kbabel_gettext_export.desktop b/kbabel/filters/gettext/kbabel_gettext_export.desktop
new file mode 100644
index 00000000..30cf0df5
--- /dev/null
+++ b/kbabel/filters/gettext/kbabel_gettext_export.desktop
@@ -0,0 +1,53 @@
+[Desktop Entry]
+Type=Service
+Name=KBabel GNU Gettext Export Filter
+Name[bg]=Филтър за екÑпортиране на GNU Gettext - KBabel
+Name[br]=Sil ezporzh GNU Gettext evit KBabel
+Name[bs]=KBabel GNU Gettext filter za izvoz
+Name[ca]=Filtre KBabel per exportar Gettext de GNU
+Name[cs]=Exportní filtr do formátu Gettext pro KBabel
+Name[cy]=Hidl Allforio GNU Gettext KBabel
+Name[da]=KBabel GNU Gettext eksportfilter
+Name[de]=GNU Gettext-Exportfilter für KBabel
+Name[el]=ΦίλτÏο εξαγωγής GNU Gettext του KBabel
+Name[es]=Filtro de exportación KBabel GNU Gettext
+Name[et]=KBabeli GNU Gettexti ekspordifilter
+Name[eu]=KBabel GNU gettext esportazio iragazkia
+Name[fa]=پالایۀ صادرات KBabel GNU Gettext
+Name[fi]=KBabel GNU Gettext -vientisuodatin
+Name[fr]=filtre d'exportation GNU Gettext pour KBabel
+Name[ga]=Scagaire Easpórtála Gettext GNU le haghaidh KBabel
+Name[gl]=Filtro de exportación de GNU/gettext para KBabel
+Name[hi]=के-बेबल गà¥à¤¨à¥‚ गेट-टेकà¥à¤¸à¥à¤Ÿ निरà¥à¤¯à¤¾à¤¤ फ़िलà¥à¤Ÿà¤°
+Name[hu]=KBabel GNU Gettext exportszűrő
+Name[is]=KBabel GNU Gettext útflutningssía
+Name[it]=Filtro di esportazione di GNU Gettext per KBabel
+Name[ja]=KBabel GNU Gettext エクスãƒãƒ¼ãƒˆãƒ•ã‚£ãƒ«ã‚¿
+Name[ka]=KBabel GNU Gettext ექსპáƒáƒ áƒ¢áƒ˜áƒ¡ ფილტრი
+Name[kk]=KBabel GNU Gettext ÑкÑпорттау ÑүзгіÑÑ–
+Name[lt]=KBabel GNU Gettext eksportavimo filtras
+Name[ms]=Penapis Eksport KBabel GNU Gettext
+Name[nb]=GNU Gettext-eksportfilter for KBabel
+Name[nds]=KBabel-Exportfilter för GNU Gettext
+Name[ne]=केबà¥à¤¯à¤¾à¤¬à¤² जीà¤à¤¨à¤¯à¥‚ गेटटेकà¥à¤¸à¥à¤Ÿ निरà¥à¤¯à¤¾à¤¤ फिलà¥à¤Ÿà¤°
+Name[nl]=KBabel GNU Gettext Exportfilter
+Name[nn]=GNU Gettext-eksportfilter for KBabel
+Name[pa]=KBabel GNU Gettext ਨਿਰਯਾਤ ਫਿਲਟਰ
+Name[pl]=Filtr KBabel do eksportu do formatu GNU Gettext
+Name[pt]=Filtro de Exportação do Gettext da GNU para o KBabel
+Name[pt_BR]=Filtro de Exportação GNU Gettext do KBabel
+Name[ru]=Фильтр ÑкÑпорта Ñообщений GNU Gettext
+Name[sk]=Exportný filter GNU gettext pre KBabel
+Name[sl]=Izvozni filter GNU Gettext za KBabel
+Name[sr]=KBabel-ов филтер за извоз у GNU Gettext
+Name[sr@Latn]=KBabel-ov filter za izvoz u GNU Gettext
+Name[sv]=Kbabel exportfilter för GNU Gettext
+Name[ta]=Kபாபேல௠GNU உரை எட௠à®à®±à¯à®±à¯à®®à®¤à®¿ வடிகடà¯à®Ÿà®¿
+Name[tg]=Филтри Ñодироти хабарҳо GNU Gettext
+Name[tr]=KBabel GNU Gettext Dışa Aktarma Süzgeci
+Name[uk]=Фільтр екÑпорту GNU Gettext Ð´Ð»Ñ KBabel
+Name[zh_CN]=KBabel GNU Gettext 导出过滤器
+Name[zh_TW]=KBabel GNU Gettext 匯出éŽæ¿¾å™¨
+X-KDE-Library=kbabel_gettextexport
+X-KDE-Export=application/x-gettext
+ServiceTypes=KBabelFilter
diff --git a/kbabel/filters/gettext/kbabel_gettext_import.desktop b/kbabel/filters/gettext/kbabel_gettext_import.desktop
new file mode 100644
index 00000000..c6b1b293
--- /dev/null
+++ b/kbabel/filters/gettext/kbabel_gettext_import.desktop
@@ -0,0 +1,53 @@
+[Desktop Entry]
+Type=Service
+Name=KBabel GNU Gettext Import Filter
+Name[bg]=Филтър за импортиране на GNU Gettext - KBabel
+Name[br]=Sil enporzh GNU Gettext evit KBabel
+Name[bs]=KBabel GNU Gettext filter za uvoz
+Name[ca]=Filtre KBabel per importar Gettext de GNU
+Name[cs]=Importní filtr Gettext pro KBabel
+Name[cy]=Hidl Mewnforio GNU Gettext KBabel
+Name[da]=KBabel GNU Gettext Import-filter
+Name[de]=GNU Gettext-Importfilter für KBabel
+Name[el]=ΦίλτÏο εισαγωγής GNU Gettext του KBabel
+Name[es]=Filtro de importación KBabel GNU Gettext
+Name[et]=KBabeli GNU Gettexti impordifilter
+Name[eu]=KBabel GNU gettext inportazio iragazkia
+Name[fa]=پالایۀ واردات KBabel GNU Gettext
+Name[fi]=KBabel GNU Gettext -tuontisuodatin
+Name[fr]=Filtre d'importation GNU Gettext pour KBabel
+Name[ga]=Scagaire Iompórtála Gettext GNU le haghaidh KBabel
+Name[gl]=Filtro de importación de GNU/gettext para KBabel
+Name[hi]=के-बेबल गà¥à¤¨à¥‚ गेट-टेकà¥à¤¸à¥à¤Ÿ आयात फ़िलà¥à¤Ÿà¤°
+Name[hu]=KBabel GNU Gettext importszűrő
+Name[is]=KBabel GNU Gettext innflutningssía
+Name[it]=Filtro di importazione di GNU Gettext per KBabel
+Name[ja]=KBabel GNU Gettext インãƒãƒ¼ãƒˆãƒ•ã‚£ãƒ«ã‚¿
+Name[ka]=KBabel GNU Gettext იმპáƒáƒ áƒ˜áƒ¡ ფილტრი
+Name[kk]=KBabel GNU Gettext импорттау ÑүзгіÑÑ–
+Name[lt]=KBabel GNU Gettext importavimo filtras
+Name[ms]=Penapis Import KBabel GNU Gettext
+Name[nb]=GNU Gettext-importfilter for KBabel
+Name[nds]=KBabel-Importfilter för GNU Gettext
+Name[ne]=केबà¥à¤¯à¤¾à¤¬à¤² जीà¤à¤¨à¤¯à¥‚ गेटटेकà¥à¤¸à¥à¤Ÿ आयात फिलà¥à¤Ÿà¤°
+Name[nl]=KBabel GNU Gettext Importfilter
+Name[nn]=GNU Gettext-importfilter for KBabel
+Name[pa]=KBabel GNU Gettext ਅਯਾਤ ਫਿਲਟਰ
+Name[pl]=Filtr KBabel do importu z formatu GNU Gettext
+Name[pt]=Filtro de Importação de Gettext da GNU para o KBabel
+Name[pt_BR]=Filtro de Importação GNU Gettext para o KBabel
+Name[ru]=Фильтр импорта Ñообщений GNU Gettext
+Name[sk]=Importný filter GNU gettext pre KBabel
+Name[sl]=Uvozni filter GNU Gettext za KBabel
+Name[sr]=KBabel-ов филтер за увоз из GNU Gettext-а
+Name[sr@Latn]=KBabel-ov filter za uvoz iz GNU Gettext-a
+Name[sv]=Kbabel importfilter för GNU Gettext
+Name[ta]=Kபாபேல௠GNU உரை எட௠இறகà¯à®•à¯à®®à®¤à®¿ வடிகடà¯à®Ÿà®¿
+Name[tg]=Филтри воридоти хабарҳо GNU Gettext
+Name[tr]=KBabel GNU Gettext İçe Aktarma Süzgeci
+Name[uk]=Фільтр імпорту GNU Gettext Ð´Ð»Ñ KBabel
+Name[zh_CN]=KBabel GNU Gettext 导入过滤器
+Name[zh_TW]=KBabel GNU Gettext 匯入éŽæ¿¾å™¨
+X-KDE-Library=kbabel_gettextimport
+X-KDE-Import=application/x-gettext
+ServiceTypes=KBabelFilter
diff --git a/kbabel/filters/linguist/Makefile.am b/kbabel/filters/linguist/Makefile.am
new file mode 100644
index 00000000..479c8052
--- /dev/null
+++ b/kbabel/filters/linguist/Makefile.am
@@ -0,0 +1,18 @@
+####### General stuff
+
+INCLUDES = -I../../common -I$(srcdir)/../../common $(all_includes)
+
+kde_module_LTLIBRARIES = kbabel_linguistexport.la kbabel_linguistimport.la
+
+kbabel_linguistexport_la_SOURCES = linguistexport.cpp
+kbabel_linguistexport_la_LIBADD = ../../common/libkbabelcommon.la
+kbabel_linguistexport_la_LDFLAGS = -module $(KDE_PLUGIN) $(all_libraries)
+
+kbabel_linguistimport_la_SOURCES = linguistimport.cpp
+kbabel_linguistimport_la_LIBADD = ../../common/libkbabelcommon.la
+kbabel_linguistimport_la_LDFLAGS = -module $(KDE_PLUGIN) $(all_libraries)
+
+METASOURCES = AUTO
+
+service_DATA = kbabel_linguist_export.desktop kbabel_linguist_import.desktop
+servicedir = $(kde_servicesdir)
diff --git a/kbabel/filters/linguist/kbabel_linguist_export.desktop b/kbabel/filters/linguist/kbabel_linguist_export.desktop
new file mode 100644
index 00000000..400abd26
--- /dev/null
+++ b/kbabel/filters/linguist/kbabel_linguist_export.desktop
@@ -0,0 +1,53 @@
+[Desktop Entry]
+Type=Service
+Name=KBabel Linguist Export Filter
+Name[bg]=ЛингвиÑтичен филтър за екÑпортиране - KBabel
+Name[br]=Sil ezporzh Linguist evit KBabel
+Name[bs]=KBabel Linguist filter za izvoz
+Name[ca]=Filtre KBabel per exportar Linguist
+Name[cs]=Exportní filtr do formátu Linguist pro KBabel
+Name[cy]=Hidl Allforio Ieithydd KBabel
+Name[da]=KBabel Linguist eksportfilter
+Name[de]=Linguist Export-Filter für KBabel
+Name[el]=ΦίλτÏο εξαγωγής Linguist του KBabel
+Name[es]=Filtro de exportación lingüístico de KBabel
+Name[et]=KBabeli Linguisti ekspordifilter
+Name[eu]=KBabel Linguist esportazio iragazkia
+Name[fa]=پالایۀ صادرات زبان‌شناس KBabel
+Name[fi]=KBabel Linguist -vientisuodatin
+Name[fr]=Filtre d'exportation Linguist pour KBabel
+Name[ga]=Scagaire Easpórtála Linguist le haghaidh KBabel
+Name[gl]=Filtro de exportación a Linguist para KBabel
+Name[hi]=के-बेबल लिंगà¥à¤µà¤¿à¤¸à¥à¤Ÿ निरà¥à¤¯à¤¾à¤¤ फ़िलà¥à¤Ÿà¤°
+Name[hu]=KBabel Linguist exportszűrő
+Name[is]=KBabel Linguist útflutningssía
+Name[it]=Filtro di esportazione di Linguist per KBabel
+Name[ja]=KBabel Linguist エクスãƒãƒ¼ãƒˆãƒ•ã‚£ãƒ«ã‚¿
+Name[ka]=KBabel Linguist ექსპáƒáƒ áƒ¢áƒ˜áƒ¡ ფილტრი
+Name[kk]=KBabel лингвиÑтік ÑкÑпорттау ÑүзгіÑÑ–
+Name[lt]=KBabel Linguist eksportavimo filtras
+Name[ms]=Penapis Eksport KBabel Linguist
+Name[nb]=Linguist-eksportfilter for KBabel
+Name[nds]=KBabel-Exportfilter för Linguist
+Name[ne]=केबà¥à¤¯à¤¾à¤¬à¤² बहà¥à¤­à¤¾à¤·à¥€ निरà¥à¤¯à¤¾à¤¤ फिलà¥à¤Ÿà¤°
+Name[nl]=KBabel Linguïst Exportfilter
+Name[nn]=Linguist-eksportfilter for KBabel
+Name[pa]=ਕੇਬਬੇਲ ਬੋਲੀ ਨਿਰਯਾਤ ਫਿਲਟਰ
+Name[pl]=Filtr KBabel do eksportu do formatu Linguist
+Name[pt]=Filtro de Exportação para Linguist para o KBabel
+Name[pt_BR]=Filtro de Exportação Linguist do KBabel
+Name[ru]=Фильтр ÑкÑпорта лингвиÑтичеÑких Ñообщений
+Name[sk]=Exportný filter Qt Linguist pre KBabel
+Name[sl]=Izvozni filter Linguist za KBabel
+Name[sr]=KBabel-ов филтер за извоз у Linguist
+Name[sr@Latn]=KBabel-ov filter za izvoz u Linguist
+Name[sv]=Kbabel exportfilter för Linguist
+Name[ta]=Kபாபேல௠மொழியியல௠à®à®±à¯à®±à¯à®®à®¤à®¿ வடிகடà¯à®Ÿà®¿
+Name[tg]=Филтри Ñодироти хабарҳои лингвиÑÑ‚Ó£
+Name[tr]=KBabel Linguist Dışa Aktarma Süzgeci
+Name[uk]=Фільтр екÑпорту Linguist Ð´Ð»Ñ KBabel
+Name[zh_CN]=KBabel Linguist 导出过滤器
+Name[zh_TW]=KBabel 語言匯出éŽæ¿¾å™¨
+X-KDE-Library=kbabel_linguistexport
+X-KDE-Export=application/x-linguist
+ServiceTypes=KBabelFilter
diff --git a/kbabel/filters/linguist/kbabel_linguist_import.desktop b/kbabel/filters/linguist/kbabel_linguist_import.desktop
new file mode 100644
index 00000000..ae8bd364
--- /dev/null
+++ b/kbabel/filters/linguist/kbabel_linguist_import.desktop
@@ -0,0 +1,53 @@
+[Desktop Entry]
+Type=Service
+Name=KBabel Linguist Import Filter
+Name[bg]=ЛингвиÑтичен филтър за импортиране - KBabel
+Name[br]=Sil enporzh Linguist evit KBabel
+Name[bs]=KBabel Linguist filter za izvoz
+Name[ca]=Filtre KBabel per importar Linguist
+Name[cs]=Importní filtr Linguist pro KBabel
+Name[cy]=Hidl Mewnforio Ieithydd KBabel
+Name[da]=KBabel Linguist importfilter
+Name[de]=Linguist Import-Filter für KBabel
+Name[el]=ΦίλτÏο εισαγωγής Linguist του KBabel
+Name[es]=Filtro de importación de lengua KBabel
+Name[et]=KBabeli Linguisti impordifilter
+Name[eu]=KBabel Linguist esportazio iragazkia
+Name[fa]=پالایۀ واردات زبان‌شناس KBabel
+Name[fi]=KBabel Linguist -tuontisuodatin
+Name[fr]=Filtre d'importation Linguist pour KBabel
+Name[ga]=Scagaire Iompórtála Linguist le haghaidh KBabel
+Name[gl]=Filtro de importación de Linguist para KBabel
+Name[hi]=के-बेबल लिंगà¥à¤µà¤¿à¤¸à¥à¤Ÿ आयात फ़िलà¥à¤Ÿà¤°
+Name[hu]=KBabel Linguist importszűrő
+Name[is]=KBabel Linguist innflutningssía
+Name[it]=Filtro di importazione di Linguist per KBabel
+Name[ja]=KBabel Linguist インãƒãƒ¼ãƒˆãƒ•ã‚£ãƒ«ã‚¿
+Name[ka]=KBabel Linguist იმპáƒáƒ áƒ˜áƒ¡ ფილტრი
+Name[kk]=KBabel лингвиÑтік импорттау ÑүзгіÑÑ–
+Name[lt]=KBabel Linguist importavimo filtras
+Name[ms]=Penapis Import KBabel Linguist
+Name[nb]=Linguist-importfilter for KBabel
+Name[nds]=KBabel-Importfilter för Linguist
+Name[ne]=केबà¥à¤¯à¤¾à¤¬à¤² बहà¥à¤­à¤¾à¤·à¥€ आयात फिलà¥à¤Ÿà¤°
+Name[nl]=KBabel Linguïst importfilter
+Name[nn]=Linguist-importfilter for KBabel
+Name[pa]=ਕੇਬਬੇਲ ਬੋਲੀ ਅਯਾਤ ਫਿਲਟਰ
+Name[pl]=Filtr KBabel do importu z formatu Linguist
+Name[pt]=Filtro de Importação de Linguist para o KBabel
+Name[pt_BR]=Filtro de Importação Linguist para o KBabel
+Name[ru]=Фильтр импорта лингвиÑтичеÑких Ñообщений
+Name[sk]=Importný filter Qt Linguist pre KBabel
+Name[sl]=Uvozni filter Linguist za KBabel
+Name[sr]=KBabel-ов филтер за увоз из Linguist-а
+Name[sr@Latn]=KBabel-ov filter za uvoz iz Linguist-a
+Name[sv]=Kbabel importfilter för Linguist
+Name[ta]=Kபாபேல௠மொழியியல௠இறகà¯à®•à¯à®®à®¤à®¿ வடிகடà¯à®Ÿà®¿
+Name[tg]=Филтри воридоти хабарҳои лингвиÑÑ‚Ó£
+Name[tr]=KBabel Linguist İçe Aktarma Süzgeci
+Name[uk]=Фільтр імпорту Linguist Ð´Ð»Ñ KBabel
+Name[zh_CN]=KBabel Linguist 导入过滤器
+Name[zh_TW]=KBabel 語言匯入éŽæ¿¾å™¨
+X-KDE-Library=kbabel_linguistimport
+X-KDE-Import=application/x-linguist
+ServiceTypes=KBabelFilter
diff --git a/kbabel/filters/linguist/linguistexport.cpp b/kbabel/filters/linguist/linguistexport.cpp
new file mode 100644
index 00000000..3b69e20a
--- /dev/null
+++ b/kbabel/filters/linguist/linguistexport.cpp
@@ -0,0 +1,214 @@
+/* ****************************************************************************
+ This file is part of KBabel
+
+ Copyright (C) 1999-2000 by Matthias Kiefer
+ <matthias.kiefer@gmx.de>
+ 2001-2002 by Stanislav Visnovsky
+ <visnovsky@kde.org>
+ 2002-2003 by Marco Wegner
+ <mail@marcowegner.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.
+
+ 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, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+ In addition, as a special exception, the copyright holders give
+ permission to link the code of this program with any edition of
+ the Qt library by Trolltech AS, Norway (or with modified versions
+ of Qt that use the same license as Qt), and distribute linked
+ combinations including the two. You must obey the GNU General
+ Public License in all respects for all of the code used other than
+ Qt. If you modify this file, you may extend this exception to
+ your version of the file, but you are not obligated to do so. If
+ you do not wish to do so, delete this exception statement from
+ your version.
+
+**************************************************************************** */
+
+
+#include <qfile.h>
+#include "qregexp.h"
+#include <qstring.h>
+#include <qstringlist.h>
+#include <qtextstream.h>
+
+#include <kgenericfactory.h>
+
+#include "catalog.h"
+#include "catalogitem.h"
+#include "catalogsettings.h"
+#include "linguistexport.h"
+
+K_EXPORT_COMPONENT_FACTORY( kbabel_linguistexport, KGenericFactory<LinguistExportPlugin> ( "kbabellinguistexportfilter" ) )
+
+using namespace KBabel;
+
+LinguistExportPlugin::LinguistExportPlugin( QObject * parent, const char * name, const QStringList& )
+ : CatalogExportPlugin( parent, name )
+{
+}
+
+ConversionStatus LinguistExportPlugin::save( const QString& filename, const QString&, const Catalog * catalog )
+{
+ // Check whether we know how to handle the extra data.
+ if ( catalog->importPluginID( ) != "Qt translation source" )
+ return UNSUPPORTED_TYPE;
+
+ QFile file( filename );
+ if ( !file.open( IO_WriteOnly ) )
+ return OS_ERROR;
+
+ SaveSettings settings = catalog->saveSettings( );
+
+ // New DOM document.
+ QDomDocument doc( "TS" );
+ // Create the root element.
+ doc.appendChild( doc.createElement( "TS" ) );
+
+ // Create a default context just in case none is given in the messages.
+ context = "Default"; // ### FIXME: Qt's default seems named "@default"
+
+ bool fuzzy;
+
+ // Regular messages.
+ for ( uint i = 0; i < catalog->numberOfEntries( ); i++ ) {
+ QString comment( extractComment( doc, catalog->comment( i ), fuzzy ) );
+ createMessage( doc, catalog->msgid( i ).join( "" ), catalog->msgstr( i ).join( "" ),
+ comment, false, fuzzy );
+ }
+
+ // Obsolete messages.
+ if ( settings.saveObsolete ) {
+ QValueList<CatalogItem> obsMessages = catalog->obsoleteEntries( );
+ QValueList<CatalogItem>::Iterator it;
+ for ( it = obsMessages.begin( ); it != obsMessages.end( ); ++it ) {
+ QString comment( extractComment( doc, (*it).comment( ), fuzzy ) );
+ createMessage( doc, (*it).msgid( true ).join( "" ), (*it).msgstr( true ).join( "" ),
+ comment, true, fuzzy );
+ }
+ }
+
+ QTextStream stream( &file );
+ doc.save( stream, 2 );
+ file.close( );
+
+ return OK;
+}
+
+const QString LinguistExportPlugin::extractComment( QDomDocument& doc, const QString& s, bool& fuzzy )
+{
+ fuzzy = false;
+ QString comment( s );
+ if ( !comment.isEmpty( ) ) {
+ // Extract the context and the actual comment.
+ comment.remove( QRegExp( "^Context:[\\s]*" ) );
+ /*
+ * HACK
+ *
+ * KBabel has not any flag to tell "this entry is fuzzy!"
+ * but it uses the corresponding Gettext comment instead.
+ *
+ * Therefore we have little choice, but to use "#, fuzzy" in the comment,
+ * even if it is very Linguist-unlike. So the "#, fuzzy" must be removed before
+ * writing the comment for Linguist
+ */
+
+ int pos = comment.find("#, fuzzy");
+ if ( pos >= 0) {
+ fuzzy = true;
+ comment.remove("#, fuzzy");
+ }
+
+ QString newContext;
+ pos = comment.find( '\n' );
+ if ( pos >= 0 ) {
+ newContext = comment.left( pos );
+ comment.replace( 0, pos + 1, "" ); // ### TODO: use QString::remove
+ } else {
+ newContext = comment;
+ comment = ""; // ### TODO: use QString() instead of ""
+ }
+ setContext( doc, newContext );
+ }
+ return comment;
+}
+
+void LinguistExportPlugin::createMessage( QDomDocument& doc, const QString& msgid,
+ const QString& msgstr, const QString& comment,
+ const bool obsolete, const bool fuzzy )
+{
+ QDomElement elem;
+ QDomText text;
+
+ QDomElement messageElement = doc.createElement( "message" );
+
+ elem = doc.createElement( "source" );
+ text = doc.createTextNode( msgid );
+ elem.appendChild( text );
+ messageElement.appendChild( elem );
+
+ if ( !comment.isEmpty( ) ) {
+ elem = doc.createElement( "comment" );
+ text = doc.createTextNode( comment );
+ elem.appendChild( text );
+ messageElement.appendChild( elem );
+ }
+
+ elem = doc.createElement( "translation" );
+ if ( obsolete )
+ elem.setAttribute( "type", "obsolete" );
+ else if ( msgstr.isEmpty( ) || fuzzy ) {
+ elem.setAttribute( "type", "unfinished" );
+ }
+ if ( !msgstr.isEmpty())
+ {
+ text = doc.createTextNode( msgstr );
+ elem.appendChild( text );
+ }
+ messageElement.appendChild( elem );
+ contextElement.appendChild( messageElement );
+}
+
+void LinguistExportPlugin::setContext( QDomDocument& doc, QString newContext )
+{
+ // Nothing to do here.
+ if ( newContext == context )
+ return;
+
+ // Find out whether there is already such a context in the QDomDocument.
+ QDomNode node = doc.documentElement( ).firstChild( );
+ while ( !node.isNull( ) ) {
+ if ( node.isElement( ) ) {
+ QDomElement elem = node.firstChild( ).toElement( );
+ if ( elem.isElement( ) && elem.tagName( ) == "name" && elem.text( ) == newContext ) {
+ // We found the context.
+ context = newContext;
+ contextElement = node.toElement( );
+ // Nothing more to do.
+ return;
+ }
+ }
+ node = node.nextSibling( );
+ }
+
+ // Create new context element.
+ contextElement = doc.createElement( "context" );
+ doc.documentElement( ).appendChild( contextElement );
+ // Appropriate name element.
+ QDomElement nameElement = doc.createElement( "name" );
+ QDomText text = doc.createTextNode( newContext );
+ nameElement.appendChild( text );
+ contextElement.appendChild( nameElement );
+ // Store new context.
+ context = newContext;
+}
diff --git a/kbabel/filters/linguist/linguistexport.h b/kbabel/filters/linguist/linguistexport.h
new file mode 100644
index 00000000..3201f95f
--- /dev/null
+++ b/kbabel/filters/linguist/linguistexport.h
@@ -0,0 +1,68 @@
+/* ****************************************************************************
+ This file is part of KBabel
+
+ Copyright (C) 2002 by Stanislav Visnovsky
+ <visnovsky@kde.org>
+ 2002-2003 by Marco Wegner
+ <mail@marcowegner.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.
+
+ 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, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+ In addition, as a special exception, the copyright holders give
+ permission to link the code of this program with any edition of
+ the Qt library by Trolltech AS, Norway (or with modified versions
+ of Qt that use the same license as Qt), and distribute linked
+ combinations including the two. You must obey the GNU General
+ Public License in all respects for all of the code used other than
+ Qt. If you modify this file, you may extend this exception to
+ your version of the file, but you are not obligated to do so. If
+ you do not wish to do so, delete this exception statement from
+ your version.
+
+**************************************************************************** */
+
+
+#ifndef LINGUISTEXPORT_H
+#define LINGUISTEXPORT_H
+
+#include <qdom.h>
+
+#include "catalogfileplugin.h"
+
+class QString;
+class QStringList;
+
+namespace KBabel {
+class Catalog;
+}
+
+class LinguistExportPlugin : public KBabel::CatalogExportPlugin
+{
+ public:
+ LinguistExportPlugin( QObject * parent, const char * name, const QStringList& );
+ virtual KBabel::ConversionStatus save( const QString& filename, const QString& mimetype, const KBabel::Catalog * catalog );
+
+ private:
+ const QString extractComment( QDomDocument& doc, const QString& s, bool& fuzzy );
+ void createMessage( QDomDocument& doc, const QString& msgid, const QString& msgstr,
+ const QString& comment, const bool obsolete, const bool fuzzy );
+ void setContext( QDomDocument& doc, QString newContext );
+
+ private:
+ QString context;
+ QDomElement contextElement;
+};
+
+#endif // LINGUISTEXPORT_H
diff --git a/kbabel/filters/linguist/linguistimport.cpp b/kbabel/filters/linguist/linguistimport.cpp
new file mode 100644
index 00000000..220c0634
--- /dev/null
+++ b/kbabel/filters/linguist/linguistimport.cpp
@@ -0,0 +1,193 @@
+// kate: space-indent on; indent-width 2; replace-tabs on;
+
+/* ****************************************************************************
+ This file is part of KBabel
+
+ Copyright (C) 1999-2000 by Matthias Kiefer
+ <matthias.kiefer@gmx.de>
+ 2001-2002 by Stanislav Visnovsky
+ <visnovsky@kde.org>
+ 2002-2003 by Marco Wegner
+ <mail@marcowegner.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.
+
+ 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, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+ In addition, as a special exception, the copyright holders give
+ permission to link the code of this program with any edition of
+ the Qt library by Trolltech AS, Norway (or with modified versions
+ of Qt that use the same license as Qt), and distribute linked
+ combinations including the two. You must obey the GNU General
+ Public License in all respects for all of the code used other than
+ Qt. If you modify this file, you may extend this exception to
+ your version of the file, but you are not obligated to do so. If
+ you do not wish to do so, delete this exception statement from
+ your version.
+
+**************************************************************************** */
+
+// Qt include files
+#include <qfile.h>
+#include <qfileinfo.h>
+#include <qobject.h>
+#include <qregexp.h>
+#include <qstring.h>
+#include <qstringlist.h>
+// KDE include files
+#include <kdebug.h>
+#include <kgenericfactory.h>
+// Project specific include files
+#include "catalogitem.h"
+#include "linguistimport.h"
+
+K_EXPORT_COMPONENT_FACTORY( kbabel_linguistimport, KGenericFactory<LinguistImportPlugin> ( "kbabellinguistimportfilter" ) )
+
+using namespace KBabel;
+
+LinguistImportPlugin::LinguistImportPlugin( QObject * parent, const char * name, const QStringList& )
+ : CatalogImportPlugin( parent, name )
+{
+}
+
+ConversionStatus LinguistImportPlugin::load( const QString& filename, const QString& )
+{
+ if ( filename.isEmpty( ) ) {
+ kdDebug( ) << "fatal error: empty filename to open" << endl;
+ return NO_FILE;
+ }
+
+ QFileInfo info( filename );
+
+ if ( !info.exists( ) || info.isDir( ) )
+ return NO_FILE;
+
+ if ( !info.isReadable( ) )
+ return NO_PERMISSIONS;
+
+ QFile file( filename );
+ if ( !file.open( IO_ReadOnly ) )
+ return NO_PERMISSIONS;
+
+ QString errorMsg;
+ int errorLine, errorColumn;
+
+ QDomDocument doc;
+ if ( !doc.setContent( &file, &errorMsg, &errorLine, &errorColumn ) ) {
+ file.close( );
+ kdError() << "Parsing error at line " << errorLine << ", column " << errorColumn << ", error " << errorMsg << endl;
+ return PARSE_ERROR;
+ }
+ file.close( );
+
+ const QDomElement documentElement( doc.documentElement() );
+ // Count the number of messages in this file. This is needed for updating
+ // the progress bar correctly.
+ msgcnt = documentElement.elementsByTagName( "message" ).count();
+
+ if ( documentElement.tagName() != "TS" )
+ return UNSUPPORTED_TYPE;
+
+ cnt = 0;
+ emit signalClearProgressBar( );
+ kdDebug( ) << "start parsing..." << endl;
+
+ parse( documentElement );
+ //setCatalogExtraData( obsMessages );
+
+ emit signalProgress( 100 );
+ kdDebug( ) << "finished parsing..." << endl;
+
+ setMimeTypes( "application/x-linguist" );
+
+ return OK;
+}
+
+void LinguistImportPlugin::parse( const QDomElement& parentElement )
+{
+ QDomNode node = parentElement.firstChild( );
+
+ while ( !node.isNull( ) ) {
+ if ( node.isElement( ) ) {
+ QDomElement elem = node.toElement( );
+
+ if ( elem.tagName( ) == "context" ) {
+ // nothing to do here
+ } else if ( elem.tagName( ) == "name" ) {
+ context = elem.text( );
+ } else if ( elem.tagName( ) == "message" ) {
+ CatalogItem item;
+ QString comment;
+ bool isObsolete = false;
+ bool isFuzzy = false;
+
+ QDomNode childNode = node.firstChild();
+ for ( ; ! childNode.isNull() ; childNode = childNode.nextSibling() )
+ {
+ const QDomElement elem = childNode.toElement();
+
+ if ( elem.isNull() )
+ continue;
+
+ if ( elem.tagName( ) == "source" ) {
+ item.setMsgid( elem.text( ) );
+ } else if ( elem.tagName( ) == "translation" ) {
+ item.setMsgstr( elem.text( ) );
+ if ( elem.attribute( "type" ) == "unfinished" ) {
+ // Only mark as fuzzy if there is a translation
+ isFuzzy = !elem.text().isEmpty();
+ } else if ( elem.attribute( "type" ) == "obsolete" ) {
+ isObsolete = true;
+ }
+ } else if ( elem.tagName( ) == "comment" ) {
+ if ( !elem.text( ).isEmpty( ) )
+ comment = elem.text( );
+ }
+ }
+
+ QString fullComment = "Context: " + context;
+ if ( isFuzzy )
+ {
+ /*
+ * HACK
+ *
+ * KBabel has not any flag to tell "this entry is fuzzy!"
+ * but it uses the corresponding Gettext comment instead.
+ *
+ * Therefore we have little choice, but to add "#, fuzzy" to the comment,
+ * even if it is very Linguist-unlike
+ */
+ fullComment += "\n";
+ fullComment += "#, fuzzy";
+ }
+ if ( !comment.isEmpty() )
+ {
+ fullComment += "\n";
+ fullComment += comment;
+ }
+ item.setComment( fullComment );
+
+ appendCatalogItem( item, isObsolete );
+
+ // Update the progress bar.
+ cnt++;
+ uint prog = 100*cnt/msgcnt;
+ emit signalProgress( prog );
+ }
+ // ### TODO: avoid recursing
+ // recursive parsing
+ parse( elem );
+ }
+ node = node.nextSibling( );
+ }
+}
diff --git a/kbabel/filters/linguist/linguistimport.h b/kbabel/filters/linguist/linguistimport.h
new file mode 100644
index 00000000..3cdbd7e3
--- /dev/null
+++ b/kbabel/filters/linguist/linguistimport.h
@@ -0,0 +1,68 @@
+/* ****************************************************************************
+ This file is part of KBabel
+
+ Copyright (C) 2002 by Stanislav Visnovsky
+ <visnovsky@kde.org>
+ 2002-2003 by Marco Wegner
+ <mail@marcowegner.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.
+
+ 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, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+ In addition, as a special exception, the copyright holders give
+ permission to link the code of this program with any edition of
+ the Qt library by Trolltech AS, Norway (or with modified versions
+ of Qt that use the same license as Qt), and distribute linked
+ combinations including the two. You must obey the GNU General
+ Public License in all respects for all of the code used other than
+ Qt. If you modify this file, you may extend this exception to
+ your version of the file, but you are not obligated to do so. If
+ you do not wish to do so, delete this exception statement from
+ your version.
+
+**************************************************************************** */
+
+
+#ifndef LINGUISTIMPORT_H
+#define LINGUISTIMPORT_H
+
+#include <qdom.h>
+
+#include "catalogfileplugin.h"
+
+class QString;
+class QStringList;
+
+/**
+ * The class for importing Qt's translation source files.
+ */
+class LinguistImportPlugin : public KBabel::CatalogImportPlugin
+{
+ public:
+ LinguistImportPlugin( QObject * parent, const char * name, const QStringList& );
+
+ virtual KBabel::ConversionStatus load( const QString& filename, const QString& mimetype );
+ virtual const QString id( ) { return "Qt translation source"; }
+
+ private:
+ void parse( const QDomElement& parentElement );
+
+ private:
+ uint msgcnt;
+ uint cnt;
+ QString context;
+ //QStringList obsMessages;
+};
+
+#endif // LINGUISTIMPORT_H
diff --git a/kbabel/filters/xliff/Makefile.am b/kbabel/filters/xliff/Makefile.am
new file mode 100644
index 00000000..d3f6cab1
--- /dev/null
+++ b/kbabel/filters/xliff/Makefile.am
@@ -0,0 +1,18 @@
+####### General stuff
+
+INCLUDES = -I../../common -I$(srcdir)/../../common $(all_includes)
+
+kde_module_LTLIBRARIES = kbabel_xliffexport.la kbabel_xliffimport.la
+
+kbabel_xliffexport_la_SOURCES = xliffexport.cpp
+kbabel_xliffexport_la_LDFLAGS = -module $(KDE_PLUGIN) $(all_libraries)
+kbabel_xliffexport_la_LIBADD = ../../common/libkbabelcommon.la
+
+kbabel_xliffimport_la_SOURCES = xliffimport.cpp
+kbabel_xliffimport_la_LDFLAGS = -module $(KDE_PLUGIN) $(all_libraries)
+kbabel_xliffimport_la_LIBADD = ../../common/libkbabelcommon.la
+
+METASOURCES = AUTO
+
+service_DATA = kbabel_xliff_export.desktop kbabel_xliff_import.desktop
+servicedir = $(kde_servicesdir)
diff --git a/kbabel/filters/xliff/kbabel_xliff_export.desktop b/kbabel/filters/xliff/kbabel_xliff_export.desktop
new file mode 100644
index 00000000..d4a8036d
--- /dev/null
+++ b/kbabel/filters/xliff/kbabel_xliff_export.desktop
@@ -0,0 +1,47 @@
+[Desktop Entry]
+Type=Service
+Name=KBabel XLIFF Export Filter
+Name[bg]=XLIFF филтър за екÑпортиране - KBabel
+Name[br]=Sil ezporzh XLIFF evit KBabel
+Name[ca]=Filtre KBabel per exportar a XLIFF
+Name[cs]=Exportní filtr do XLIFF pro KBabel
+Name[da]=KBabel XLIFF eksportfilter
+Name[de]=XLIFF-Export-Filter für KBabel
+Name[el]=ΦίλτÏο εξαγωγής XLIFF του KBabel
+Name[es]=Filtro de exportación XLIFF de KBabel
+Name[et]=KBabeli XLIFF ekspordifilter
+Name[eu]=KBabel XLIFF esportazio iragazkia
+Name[fa]=پالایۀ صادرات XLIFF KBabel
+Name[fi]=KBabel XLIFF -vientisuodatin
+Name[fr]=Filtre d'exportation XLIFF pour KBabel
+Name[ga]=Scagaire Easpórtála XLIFF le haghaidh KBabel
+Name[gl]=Filtro de exportación a XLIFF para KBabel
+Name[hu]=KBabel XLIFF exportszűrő
+Name[is]=KBabel XLIFF útfluttningssía
+Name[it]=Filtro di esportazione XLIFF per KBabel
+Name[ja]=KBabel XLIFF エクスãƒãƒ¼ãƒˆãƒ•ã‚£ãƒ«ã‚¿
+Name[ka]=KBabel XLIFF ექსპáƒáƒ áƒ¢áƒ˜áƒ¡ ფილტრი
+Name[kk]=KBabel XLIFF ÑкÑпорттау ÑүзгіÑÑ–
+Name[lt]=KBabel XLIFF eksportavimo filtras
+Name[nb]=XLIFF-eksportfilter for KBabel
+Name[nds]=KBabel-Exportfilter för XLIFF
+Name[ne]=केबà¥à¤¯à¤¾à¤¬à¤² à¤à¤•à¥à¤¸à¤à¤²à¤†à¤ˆà¤à¤«à¤à¤« निरà¥à¤¯à¤¾à¤¤ फिलà¥à¤Ÿà¤°
+Name[nl]=KBabel XLIFF-exportfilter
+Name[nn]=XLIFF-eksportfilter for KBabel
+Name[pa]=ਕੇਬਬੇਲ XLIFF ਨਿਰਯਾਤ ਫਿਲਟਰ
+Name[pl]=Filtr KBabel do eksportu do formatu XLIFF
+Name[pt]=Filtro de Exportação XLIFF para o KBabel
+Name[pt_BR]=Filtro de Exportação XLIFF do KBabel
+Name[ru]=Фильтр ÑкÑпорта XLIFF
+Name[sk]=Exportný filter pre KBabel XLIFF
+Name[sl]=Izvozni filter XLIFF za KBabel
+Name[sr]=KBabel-ов филтер за извоз у XLIFF
+Name[sr@Latn]=KBabel-ov filter za izvoz u XLIFF
+Name[sv]=Kbabel exportfilter för XLIFF
+Name[tr]=KBabel XLIFF Dışa Aktarma Süzgeci
+Name[uk]=Фільтр екÑпорту XLIFF Ð´Ð»Ñ KBabel
+Name[zh_CN]=KBabel XLIFF 导出过滤器
+Name[zh_TW]=KBabel XLIFF 匯出éŽæ¿¾å™¨
+X-KDE-Library=kbabel_xliffexport
+X-KDE-Export=application/x-xliff
+ServiceTypes=KBabelFilter
diff --git a/kbabel/filters/xliff/kbabel_xliff_import.desktop b/kbabel/filters/xliff/kbabel_xliff_import.desktop
new file mode 100644
index 00000000..260a30b4
--- /dev/null
+++ b/kbabel/filters/xliff/kbabel_xliff_import.desktop
@@ -0,0 +1,47 @@
+[Desktop Entry]
+Type=Service
+Name=KBabel XLIFF Import Filter
+Name[bg]=XLIFF филтър за импортиране - KBabel
+Name[br]=Sil enporzh XLIFF evit KBabel
+Name[ca]=Filtre KBabel per importar de XLIFF
+Name[cs]=Importní filtr XLIFF pro KBabel
+Name[da]=KBabel XLIFF importfilter
+Name[de]=XLIFF-Import-Filter für KBabel
+Name[el]=ΦίλτÏο εισαγωγής XLIFF του KBabel
+Name[es]=Filtro de importación de XLIFF de KBabel
+Name[et]=KBabeli XLIFF impordifilter
+Name[eu]=KBabel XLIFF inportazio iragazkia
+Name[fa]=پالایۀ واردات XLIFF KBabel
+Name[fi]=KBabel XLIFF -tuontisuodatin
+Name[fr]=Filtre d'importation XLIFF pour KBabel
+Name[ga]=Scagaire Iompórtála XLIFF le haghaidh KBabel
+Name[gl]=Filtro de importación a XLIFF para KBabel
+Name[hu]=KBabel XLIFF importszűrő
+Name[is]=KBabel XLIFF innfluttningssía
+Name[it]=Filtro di importazione di XLIFF per KBabel
+Name[ja]=KBabel XLIFF インãƒãƒ¼ãƒˆãƒ•ã‚£ãƒ«ã‚¿
+Name[ka]=KBabel XLIFF იმპáƒáƒ áƒ˜áƒ¡ ფილტრი
+Name[kk]=KBabel XLIFF импорттау ÑүзгіÑÑ–
+Name[lt]=KBabel XLIFF importavimo filtras
+Name[nb]=XLIFF-importfilter for KBabel
+Name[nds]=KBabel-Importfilter för XLIFF
+Name[ne]=केबà¥à¤¯à¤¾à¤¬à¤² à¤à¤•à¥à¤¸à¤à¤²à¤†à¤ˆà¤à¤«à¤à¤« आयात फिलà¥à¤Ÿà¤°
+Name[nl]=KBabel XLIFF-importfilter
+Name[nn]=XLIFF-importfilter for KBabel
+Name[pa]=ਕੇਬਬੇਲ XLIFF ਅਯਾਤ ਫਿਲਟਰ
+Name[pl]=Filtr KBabel do importu z formatu XLIFF
+Name[pt]=Filtro de Importação XLIFF para o KBabel
+Name[pt_BR]=Filtro de Importação XLIFF para o KBabel
+Name[ru]=Фильтр импорта XLIFF
+Name[sk]=Importný filter pre KBabel XLIFF
+Name[sl]=Uvozni filter XLIFF za KBabel
+Name[sr]=KBabel-ов филтер за увоз из XLIFF-а
+Name[sr@Latn]=KBabel-ov filter za uvoz iz XLIFF-a
+Name[sv]=Kbabel importfilter för XLIFF
+Name[tr]=KBabel XLIFF İçe Aktarma Süzgeci
+Name[uk]=Фільтр імпорту XLIFF Ð´Ð»Ñ KBabel
+Name[zh_CN]=KBabel XLIFF 导入过滤器
+Name[zh_TW]=KBabel XLIFF 匯入éŽæ¿¾å™¨
+X-KDE-Library=kbabel_xliffimport
+X-KDE-Import=application/x-xliff
+ServiceTypes=KBabelFilter
diff --git a/kbabel/filters/xliff/xliffexport.cpp b/kbabel/filters/xliff/xliffexport.cpp
new file mode 100644
index 00000000..53527f2c
--- /dev/null
+++ b/kbabel/filters/xliff/xliffexport.cpp
@@ -0,0 +1,223 @@
+/* ****************************************************************************
+ This file is part of KBabel
+
+ Copyright (C) 1999-2000 by Matthias Kiefer
+ <matthias.kiefer@gmx.de>
+ 2001-2004 by Stanislav Visnovsky
+ <visnovsky@kde.org>
+ 2002-2003 by Marco Wegner
+ <mail@marcowegner.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.
+
+ 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, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+ In addition, as a special exception, the copyright holders give
+ permission to link the code of this program with any edition of
+ the Qt library by Trolltech AS, Norway (or with modified versions
+ of Qt that use the same license as Qt), and distribute linked
+ combinations including the two. You must obey the GNU General
+ Public License in all respects for all of the code used other than
+ Qt. If you modify this file, you may extend this exception to
+ your version of the file, but you are not obligated to do so. If
+ you do not wish to do so, delete this exception statement from
+ your version.
+
+**************************************************************************** */
+
+
+#include <qfile.h>
+#include "qregexp.h"
+#include <qstring.h>
+#include <qstringlist.h>
+#include <qtextstream.h>
+
+#include <kgenericfactory.h>
+
+#include "catalog.h"
+#include "catalogitem.h"
+#include "catalogsettings.h"
+#include "xliffexport.h"
+
+K_EXPORT_COMPONENT_FACTORY( kbabel_xliffexport, KGenericFactory<XLIFFExportPlugin> ( "kbabelxliffexportfilter" ) )
+
+using namespace KBabel;
+
+XLIFFExportPlugin::XLIFFExportPlugin( QObject * parent, const char * name, const QStringList& )
+ : CatalogExportPlugin( parent, name )
+{
+}
+
+ConversionStatus XLIFFExportPlugin::save( const QString& filename, const QString&, const Catalog * catalog )
+{
+ // Check whether we know how to handle the extra data.
+ if ( catalog->importPluginID( ) != "XLIFF 1.1" )
+ return UNSUPPORTED_TYPE;
+
+ QFile file( filename );
+ if ( !file.open( IO_WriteOnly ) )
+ return OS_ERROR;
+
+ SaveSettings settings = catalog->saveSettings( );
+
+ // New DOM document.
+ QDomDocument doc( "" );
+
+ extraData = catalog->catalogExtraData();
+ kdDebug () << "Setting the document data: " << extraData.first () << endl;
+ doc.setContent ( extraData.first () );
+
+ // Regular messages.
+ for ( uint i = 0; i < catalog->numberOfEntries( ); i++ ) {
+ QDomElement element = extractComment( doc, *(extraData.at( i+1 )) );
+ createMessage( doc, element, catalog->msgid( i ).join( "" ), catalog->msgstr( i ).join( "" ) );
+ }
+
+ QTextStream stream( &file );
+ doc.save( stream, 2 );
+ file.close( );
+
+ return OK;
+}
+
+QDomElement XLIFFExportPlugin::extractComment( QDomDocument& doc, const QString& s )
+{
+ QString comment( s );
+
+ if ( comment.isEmpty () )
+ {
+ kdError () << "Empty comment, should not happen" << endl;
+ }
+
+ // Extract the context and the actual comment.
+ comment.remove( QRegExp( "^Context:[\\s]*" ) );
+ QString newContext;
+ QStringList commentlines = QStringList::split ( '\n', comment);
+
+ QString file = *(commentlines.at(0));
+ QString id = *(commentlines.at(1));
+
+ kdDebug () << "Looking for file " << file << endl;
+
+ return getContext( doc, file, id );
+}
+
+void XLIFFExportPlugin::createMessage( QDomDocument& doc, QDomElement& translationElement, const QString& msgid,
+ const QString& msgstr )
+{
+ // for empty messages, don't store anything
+ if (msgstr.isEmpty ())
+ return;
+
+ // find the trans element
+ QDomNode node = translationElement.firstChild( );
+ while ( !node.isNull( ) ) {
+ kdDebug () << node.nodeName () << endl;
+ if ( node.isElement() && node.toElement().tagName( ) == "target") {
+ kdDebug () << "Found the target: " <<
+ node.firstChild().nodeName () << endl;
+ // set the new translation
+ node.firstChild().toText().setData (msgstr);
+ break;
+ }
+ node = node.nextSibling( );
+ }
+
+ if ( node.isNull () )
+ {
+ // no target tag, create one
+ node = doc.createElement ("target");
+ translationElement.appendChild (node);
+
+ QDomText data = doc.createTextNode(msgstr );
+ node.appendChild( data );
+ }
+}
+
+QDomElement XLIFFExportPlugin::getContext( QDomDocument& doc, const QString& file, const QString& id )
+{
+ // Find out whether there is already such a context in the QDomDocument.
+ QDomNode parentelem = doc.documentElement();
+ QDomNode elem = doc.documentElement( ).firstChild( );
+ while ( !elem.isNull( ) ) {
+ if ( elem.isElement( ) && elem.toElement().tagName( ) == "file" && elem.toElement().attribute ("original") == file ) {
+ kdDebug () << "We have found the file" << endl;
+ break;
+ }
+ elem = elem.nextSibling( );
+ }
+
+ if (elem.isNull ())
+ {
+ kdError () << "File not found at all, creating" << endl;
+ QDomElement newelem = doc.createElement ("file");
+ newelem.setAttribute ("original", file);
+ parentelem.appendChild (newelem);
+ elem = newelem;
+ }
+
+ // lookup body tag
+ parentelem = elem;
+ elem = elem.firstChild ();
+ while ( !elem.isNull( ) ) {
+ if ( elem.isElement( ) && elem.toElement().tagName( ) == "body" ) {
+ kdDebug () << "We have found the file body" << endl;
+ break;
+ }
+ elem = elem.nextSibling( );
+ }
+
+ if (elem.isNull ())
+ {
+ kdError () << "File body not found at all, creating" << endl;
+ QDomElement newelem = doc.createElement ("body");
+ parentelem.appendChild (newelem);
+ elem = newelem;
+ }
+
+ elem = findTransUnit (elem, id);
+
+ if (elem.isNull ())
+ {
+ kdError () << "Trans-unit not found at all, creating" << endl;
+ QDomElement newelem = doc.createElement ("trans-unit");
+ newelem.setAttribute ("id", id);
+ parentelem.appendChild (newelem);
+ elem = newelem;
+ }
+
+ return elem.toElement ();
+}
+
+QDomElement XLIFFExportPlugin::findTransUnit( QDomNode& group, const QString& id )
+{
+ QDomNode elem = group.firstChild( );
+
+ // lookup correct trans-unit tag
+ while ( !elem.isNull( ) ) {
+ if ( elem.isElement( ) && elem.toElement().tagName() == "group" )
+ {
+ // search recursively
+ QDomElement res = findTransUnit( elem, id );
+ if (! res.isNull () )
+ return res.toElement();
+ }
+ else if ( elem.isElement( ) && elem.toElement().tagName( ) == "trans-unit" && elem.toElement().attribute ("id") == id ) {
+ kdDebug () << "We have found the trans-unit" << endl;
+ return elem.toElement ();
+ }
+ elem = elem.nextSibling( );
+ }
+
+ return elem.toElement ();
+}
diff --git a/kbabel/filters/xliff/xliffexport.h b/kbabel/filters/xliff/xliffexport.h
new file mode 100644
index 00000000..5bf64b25
--- /dev/null
+++ b/kbabel/filters/xliff/xliffexport.h
@@ -0,0 +1,66 @@
+/* ****************************************************************************
+ This file is part of KBabel
+
+ Copyright (C) 2002-2004 by Stanislav Visnovsky
+ <visnovsky@kde.org>
+ 2002-2003 by Marco Wegner
+ <mail@marcowegner.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.
+
+ 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, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+ In addition, as a special exception, the copyright holders give
+ permission to link the code of this program with any edition of
+ the Qt library by Trolltech AS, Norway (or with modified versions
+ of Qt that use the same license as Qt), and distribute linked
+ combinations including the two. You must obey the GNU General
+ Public License in all respects for all of the code used other than
+ Qt. If you modify this file, you may extend this exception to
+ your version of the file, but you are not obligated to do so. If
+ you do not wish to do so, delete this exception statement from
+ your version.
+
+**************************************************************************** */
+
+
+#ifndef XLIFFEXPORT_H
+#define XLIFFEXPORT_H
+
+#include <qdom.h>
+
+#include "catalogfileplugin.h"
+
+class QString;
+class QStringList;
+
+namespace KBabel {
+class Catalog;
+}
+
+class XLIFFExportPlugin : public KBabel::CatalogExportPlugin
+{
+ public:
+ XLIFFExportPlugin( QObject * parent, const char * name, const QStringList& );
+ virtual KBabel::ConversionStatus save( const QString& filename, const QString& mimetype, const KBabel::Catalog * catalog );
+
+ private:
+ QDomElement extractComment( QDomDocument& doc, const QString& s );
+ void createMessage( QDomDocument& doc, QDomElement& context, const QString& msgid, const QString& msgstr );
+ QDomElement getContext( QDomDocument& doc, const QString& file, const QString& id);
+ QDomElement findTransUnit( QDomNode& doc, const QString& id);
+
+ QStringList extraData;
+};
+
+#endif // XLIFFEXPORT_H
diff --git a/kbabel/filters/xliff/xliffimport.cpp b/kbabel/filters/xliff/xliffimport.cpp
new file mode 100644
index 00000000..f7de63ce
--- /dev/null
+++ b/kbabel/filters/xliff/xliffimport.cpp
@@ -0,0 +1,180 @@
+// kate: space-indent on; indent-width 2; replace-tabs on;
+
+/* ****************************************************************************
+ This file is part of KBabel
+
+ Copyright (C) 1999-2000 by Matthias Kiefer
+ <matthias.kiefer@gmx.de>
+ 2001-2004 by Stanislav Visnovsky
+ <visnovsky@kde.org>
+ 2002-2003 by Marco Wegner
+ <mail@marcowegner.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.
+
+ 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, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+ In addition, as a special exception, the copyright holders give
+ permission to link the code of this program with any edition of
+ the Qt library by Trolltech AS, Norway (or with modified versions
+ of Qt that use the same license as Qt), and distribute linked
+ combinations including the two. You must obey the GNU General
+ Public License in all respects for all of the code used other than
+ Qt. If you modify this file, you may extend this exception to
+ your version of the file, but you are not obligated to do so. If
+ you do not wish to do so, delete this exception statement from
+ your version.
+
+**************************************************************************** */
+
+
+/*******
+ design:
+
+ the file name and id data are stored in the comment like this:
+ file\n
+ id\n
+ optional comments
+ */
+
+// Qt include files
+#include <qfile.h>
+#include <qfileinfo.h>
+#include <qobject.h>
+#include <qregexp.h>
+#include <qstring.h>
+#include <qstringlist.h>
+// KDE include files
+#include <kdebug.h>
+#include <kgenericfactory.h>
+// Project specific include files
+#include "catalogitem.h"
+#include "xliffimport.h"
+
+// ### TODO: what is the kdebug area?
+#define KDEBUG_AREA
+
+K_EXPORT_COMPONENT_FACTORY( kbabel_xliffimport, KGenericFactory<XLIFFImportPlugin> ( "kbabelxliffimportfilter" ) )
+
+using namespace KBabel;
+
+XLIFFImportPlugin::XLIFFImportPlugin( QObject * parent, const char * name, const QStringList& )
+ : CatalogImportPlugin( parent, name )
+{
+}
+
+ConversionStatus XLIFFImportPlugin::load( const QString& filename, const QString& )
+{
+ if ( filename.isEmpty( ) ) {
+ kdDebug( KDEBUG_AREA ) << "fatal error: empty filename to open" << endl;
+ return NO_FILE;
+ }
+
+ QFileInfo info( filename );
+
+ if ( !info.exists( ) || info.isDir( ) )
+ return NO_FILE;
+
+ if ( !info.isReadable( ) )
+ return NO_PERMISSIONS;
+
+ QFile file( filename );
+ if ( !file.open( IO_ReadOnly ) )
+ return NO_PERMISSIONS;
+
+ QString errorMsg;
+ int errorLine, errorColumn;
+
+ QDomDocument doc;
+ if ( !doc.setContent( &file, &errorMsg, &errorLine, &errorColumn ) ) {
+ file.close( );
+ kdError ( KDEBUG_AREA ) << "Parsing error at line " << errorLine << ", column " << errorColumn << ", error " << errorMsg << endl;
+ return PARSE_ERROR;
+ }
+ file.close( );
+
+ extraData.clear();
+
+ const QDomElement documentElement( doc.documentElement() );
+ msgcnt = documentElement.elementsByTagName( "trans-unit" ).count();
+
+ extraData.append( doc.toString() );
+
+ cnt = 0;
+ emit signalClearProgressBar( );
+ kdDebug( KDEBUG_AREA ) << "start parsing..." << endl;
+
+ parse( documentElement );
+
+ // store full document in extra data at index 0, the rest
+ // contains contexts for each entry at(1) for entry 0, at(2) for entry 1 ...
+ setCatalogExtraData( extraData );
+
+ emit signalProgress( 100 );
+ kdDebug( KDEBUG_AREA ) << "finished parsing..." << endl;
+
+ setMimeTypes( "application/x-xliff" );
+
+ return OK;
+}
+
+void XLIFFImportPlugin::parse( const QDomElement& parentElement )
+{
+ QDomNode node = parentElement.firstChild( );
+
+ while ( !node.isNull( ) ) {
+ if ( node.isElement( ) ) {
+ QDomElement elem = node.toElement( );
+
+ if ( elem.tagName( ) == "body" ) {
+ // nothing to do here
+ } else if ( elem.tagName( ) == "file" ) {
+ context = elem.attribute( "original", QString() );
+ kdDebug ( KDEBUG_AREA ) << "Found file: " << context << endl;
+ } else if ( elem.tagName( ) == "trans-unit" ) {
+ CatalogItem item;
+ QString comment;
+ bool isObsolete = false;
+
+ const QString id = elem.attribute ("id");
+
+ QDomNode childNode = node.firstChild();
+ for ( ; ! childNode.isNull() ; childNode = childNode.nextSibling() )
+ {
+ if ( childNode.isElement() )
+ {
+ const QDomElement elem = childNode.toElement( );
+ if ( elem.tagName( ) == "source" ) {
+ item.setMsgid( elem.text( ) );
+ } else if ( elem.tagName( ) == "target" ) {
+ item.setMsgstr( elem.text( ) );
+ }
+ }
+ }
+
+ extraData.append ( context + '\n' + id );
+ item.setComment( "Context: " + context + '\n' + id + "\n" + comment );
+
+ appendCatalogItem( item, isObsolete );
+
+ // Update the progress bar.
+ cnt++;
+ uint prog = 100*cnt/msgcnt;
+ emit signalProgress( prog );
+ }
+ // recursive parsing
+ parse( elem );
+ }
+ node = node.nextSibling( );
+ }
+}
diff --git a/kbabel/filters/xliff/xliffimport.h b/kbabel/filters/xliff/xliffimport.h
new file mode 100644
index 00000000..9cf44835
--- /dev/null
+++ b/kbabel/filters/xliff/xliffimport.h
@@ -0,0 +1,68 @@
+/* ****************************************************************************
+ This file is part of KBabel
+
+ Copyright (C) 2002-2004 by Stanislav Visnovsky
+ <visnovsky@kde.org>
+ 2002-2003 by Marco Wegner
+ <mail@marcowegner.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.
+
+ 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, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+ In addition, as a special exception, the copyright holders give
+ permission to link the code of this program with any edition of
+ the Qt library by Trolltech AS, Norway (or with modified versions
+ of Qt that use the same license as Qt), and distribute linked
+ combinations including the two. You must obey the GNU General
+ Public License in all respects for all of the code used other than
+ Qt. If you modify this file, you may extend this exception to
+ your version of the file, but you are not obligated to do so. If
+ you do not wish to do so, delete this exception statement from
+ your version.
+
+**************************************************************************** */
+
+
+#ifndef XLIFFIMPORT_H
+#define XLIFFIMPORT_H
+
+#include <qdom.h>
+
+#include "catalogfileplugin.h"
+
+class QString;
+class QStringList;
+
+/**
+ * The class for importing XLIFF 1.1 translation source files.
+ */
+class XLIFFImportPlugin : public KBabel::CatalogImportPlugin
+{
+ public:
+ XLIFFImportPlugin( QObject * parent, const char * name, const QStringList& );
+
+ virtual KBabel::ConversionStatus load( const QString& filename, const QString& mimetype );
+ virtual const QString id( ) { return "XLIFF 1.1"; }
+
+ private:
+ void parse( const QDomElement& parentElement );
+
+ private:
+ uint msgcnt;
+ uint cnt;
+ QString context;
+ QStringList extraData;
+};
+
+#endif // XLIFFIMPORT_H
diff --git a/kbabel/kbabel/Makefile.am b/kbabel/kbabel/Makefile.am
new file mode 100644
index 00000000..29c8d576
--- /dev/null
+++ b/kbabel/kbabel/Makefile.am
@@ -0,0 +1,92 @@
+# this has all of the subdirectories that make will recurse into. if
+# there are none, comment this out
+SUBDIRS = pics icons
+
+# this is the program that gets installed. it's name is used for all
+# of the other Makefile.am variables
+noinst_LTLIBRARIES = libkbabel.la
+bin_PROGRAMS = kbabel
+
+# set the include path for X, qt and KDE
+INCLUDES = -I$(srcdir)/../common -I../common -I$(srcdir)/../commonui -I../commonui -I$(srcdir)/../kbabeldict -I../kbabeldict $(all_includes)
+
+
+# which sources should be compiled for kbabel
+libkbabel_la_SOURCES = kbbookmarkhandler.cpp \
+ kbcatalog.cpp headerwidget.ui headereditor.cpp \
+ spelldlgwidget.ui spelldlg.cpp gotodialog.cpp\
+ kbhighlighting.cpp mymultilineedit.cpp \
+ hidingmsgedit.cpp \
+ kbabelpref.cpp \
+ kbcatalogview.cpp \
+ commentview.cpp \
+ contextview.cpp \
+ charselectview.cpp \
+ taglistview.cpp \
+ sourceview.cpp \
+ kbabelview.cpp kbabelview2.cpp \
+ kbabel.cpp kbabeliface.skel kbabelsplash.cpp \
+ kbabelsettings.kcfgc \
+ fontpreferences.ui \
+ editordiffpreferences.ui \
+ editorpreferences.ui \
+ searchpreferences.ui \
+ colorpreferences.ui \
+ kbcataloglistview.cpp kbcataloglistviewitem.cpp \
+ errorlistview.cpp
+
+kde_kcfg_DATA=kbabel.kcfg
+
+libkbabel_la_LIBADD = ../commonui/libkbabelcommonui.la ../kbabeldict/libkbabeldict.la $(LIB_KIO) $(LIB_KSPELL)
+libkbabel_la_LDFLAGS = $(all_libraries)
+
+
+kbabel_SOURCES = main.cpp
+
+# the libraries to link against.
+kbabel_LDADD = libkbabel.la
+kbabel_LDFLAGS = $(all_libraries) $(KDE_RPATH)
+
+# these are the headers for your project
+noinst_HEADERS = kbabel.h kbabelview.h \
+ kbcatalogview.h \
+ commentview.h \
+ contextview.h \
+ charselectview.h \
+ taglistview.h \
+ sourceview.h \
+ kbabeliface.h kbabelpref.h\
+ headereditor.h mymultilineedit.h\
+ gotodialog.h hidingmsgedit.h\
+ kbcatalog.h spelldlg.h\
+ kbabelsplash.h kbbookmarkhandler.h \
+ kbhighlighting.h \
+ kbcataloglistview.h \
+ kbcataloglistviewitem.h \
+ errorlistview.h
+
+# let automoc handle all of the meta source files (moc)
+METASOURCES = AUTO
+
+rcdir = $(kde_datadir)/kbabel
+rc_DATA = kbabelui.rc
+
+update_DATA = kbabel-project.upd kbabel-difftoproject.upd
+updatedir = $(kde_datadir)/kconf_update
+
+api:
+ mkdir -p API && kdoc -d API -u $$PWD/API -p -lkdeui -lkdecore -lqt -ldcop $(noinst_HEADERS)
+
+distclean-local:
+ rm -r -f API
+
+KDE_ICON = kbabel
+
+ # this is where the kdelnk file will go
+xdg_apps_DATA = kbabel.desktop
+
+kbabel.lo: ../common/kbprojectsettings.h ../common/version.h
+kbabelview.lo: ../common/kbprojectsettings.h ../common/version.h
+kbabelview2.lo: ../common/kbprojectsettings.h
+main.o: ../common/version.h
+
diff --git a/kbabel/kbabel/charselectview.cpp b/kbabel/kbabel/charselectview.cpp
new file mode 100644
index 00000000..12cd765f
--- /dev/null
+++ b/kbabel/kbabel/charselectview.cpp
@@ -0,0 +1,115 @@
+/* ****************************************************************************
+ This file is part of KBabel
+
+ Copyright (C) 2004 by Stanislav Visnovsky
+ <visnovsky@kde.org>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the 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, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+ In addition, as a special exception, the copyright holders give
+ permission to link the code of this program with any edition of
+ the Qt library by Trolltech AS, Norway (or with modified versions
+ of Qt that use the same license as Qt), and distribute linked
+ combinations including the two. You must obey the GNU General
+ Public License in all respects for all of the code used other than
+ Qt. If you modify this file, you may extend this exception to
+ your version of the file, but you are not obligated to do so. If
+ you do not wish to do so, delete this exception statement from
+ your version.
+
+**************************************************************************** */
+
+#include "charselectview.h"
+
+#include <qlayout.h>
+#include <qwhatsthis.h>
+#include <qlabel.h>
+#include <qspinbox.h>
+#include <qscrollview.h>
+
+#include <kconfig.h>
+#include <kcursor.h>
+#include <kdialog.h>
+#include <klocale.h>
+#include <kcharselect.h>
+
+#include "kbcatalog.h"
+
+using namespace KBabel;
+
+CharacterSelectorView::CharacterSelectorView(KBCatalog* catalog,QWidget *parent, Project::Ptr project)
+ : KBCatalogView(catalog,parent,project)
+{
+ QVBoxLayout* layout = new QVBoxLayout( this );
+ layout->setResizeMode( QLayout::Minimum );
+
+ layout->setSpacing( KDialog::spacingHint() );
+
+ QHBox* bar = new QHBox(this);
+ bar->setSpacing( KDialog::spacingHint() );
+ layout->addWidget (bar);
+
+ QLabel *lTable = new QLabel( i18n( "Table:" ), bar );
+ _tableNum = new QSpinBox( 0, 255, 1, bar );
+ lTable->setBuddy( _tableNum );
+ bar->setStretchFactor( _tableNum, 1 );
+
+ QScrollView* scroll = new QScrollView( this );
+ _table = new KCharSelectTable(scroll,"charselector","helvetica",' ',0);
+ _table->setNumCols(16);
+ _table->setNumRows(16);
+
+ scroll->addChild(_table);
+ layout->addWidget (scroll);
+
+ connect( _table, SIGNAL( doubleClicked() ), this, SLOT( emitChar() ) );
+ connect( _tableNum, SIGNAL( valueChanged(int) ), this, SLOT( setTab(int) ));
+
+ connect( _catalog, SIGNAL( signalFileOpened(bool) ), this, SLOT (setDisabled (bool)));
+ connect( _catalog, SIGNAL( signalFileOpened(bool) ), _table, SLOT (setDisabled (bool)));
+
+ QWhatsThis::add(this,
+ i18n("<qt><p><b>Character Selector</b></p>"
+ "<p>This tool allows to insert special characters using "
+ "double click.</p></qt>"));
+}
+
+void CharacterSelectorView::emitChar()
+{
+ emit characterDoubleClicked( _table->chr() );
+}
+
+void CharacterSelectorView::setTab(int value)
+{
+ _table->setTableNum( value );
+}
+
+void CharacterSelectorView::saveSettings(KConfig* config)
+{
+ KConfigGroupSaver saver(config, "KBCharSelector" );
+
+ config->writeEntry( "TableNum", _tableNum->value() );
+ config->writeEntry( "SelectedChar", QString(_table->chr()) );
+}
+
+void CharacterSelectorView::restoreSettings(KConfig* config)
+{
+ KConfigGroupSaver saver(config, "KBCharSelector" );
+
+ _tableNum->setValue( config->readNumEntry("TableNum", 0 ));
+ _table->setChar( config->readEntry("SelectedChar"," ").at(0));
+}
+
+#include "charselectview.moc"
diff --git a/kbabel/kbabel/charselectview.h b/kbabel/kbabel/charselectview.h
new file mode 100644
index 00000000..76ee19b8
--- /dev/null
+++ b/kbabel/kbabel/charselectview.h
@@ -0,0 +1,71 @@
+/* ****************************************************************************
+ This file is part of KBabel
+
+ Copyright (C) 2004 by Stanislav Visnovsky
+ <visnovsky@kde.org>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the 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, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+ In addition, as a special exception, the copyright holders give
+ permission to link the code of this program with any edition of
+ the Qt library by Trolltech AS, Norway (or with modified versions
+ of Qt that use the same license as Qt), and distribute linked
+ combinations including the two. You must obey the GNU General
+ Public License in all respects for all of the code used other than
+ Qt. If you modify this file, you may extend this exception to
+ your version of the file, but you are not obligated to do so. If
+ you do not wish to do so, delete this exception statement from
+ your version.
+
+**************************************************************************** */
+#ifndef CHARSELECTVIEW_H
+#define CHARSELECTVIEW_H
+
+#include "kbcatalogview.h"
+
+class KCharSelectTable;
+class QSpinBox;
+
+class CharacterSelectorView : public KBCatalogView
+{
+ Q_OBJECT
+public:
+ /**
+ * Default constructor
+ */
+ CharacterSelectorView(KBCatalog* catalog,QWidget *parent, KBabel::Project::Ptr project);
+
+ void saveSettings(KConfig* config);
+ void restoreSettings(KConfig* config);
+
+public slots:
+ // this view does not depend on the current item
+ virtual void updateView() {}
+
+signals:
+ void characterDoubleClicked( QChar ch );
+
+public slots:
+ void emitChar();
+
+private slots:
+ void setTab( int value);
+
+private:
+ KCharSelectTable* _table;
+ QSpinBox* _tableNum;
+};
+
+#endif // CHARSELECTVIEW_H
diff --git a/kbabel/kbabel/colorpreferences.ui b/kbabel/kbabel/colorpreferences.ui
new file mode 100644
index 00000000..97e89df6
--- /dev/null
+++ b/kbabel/kbabel/colorpreferences.ui
@@ -0,0 +1,188 @@
+<!DOCTYPE UI><UI version="3.3" stdsetdef="1">
+<class>ColorPreferences</class>
+<author>Stanislav Visnovsky</author>
+<widget class="QWidget">
+ <property name="name">
+ <cstring>ColorPreferences</cstring>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>627</width>
+ <height>480</height>
+ </rect>
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="KColorButton" row="1" column="1">
+ <property name="name">
+ <cstring>kcfg_QuotedColor</cstring>
+ </property>
+ <property name="text">
+ <string></string>
+ </property>
+ </widget>
+ <widget class="KColorButton" row="0" column="1">
+ <property name="name">
+ <cstring>kcfg_BackgroundColor</cstring>
+ </property>
+ <property name="text">
+ <string></string>
+ </property>
+ </widget>
+ <widget class="QLabel" row="0" column="0">
+ <property name="name">
+ <cstring>textLabel1</cstring>
+ </property>
+ <property name="text">
+ <string>&amp;Background color:</string>
+ </property>
+ <property name="buddy" stdset="0">
+ <cstring>kcfg_BackgroundColor</cstring>
+ </property>
+ </widget>
+ <widget class="QLabel" row="1" column="0">
+ <property name="name">
+ <cstring>textLabel2</cstring>
+ </property>
+ <property name="text">
+ <string>Color for &amp;quoted characters:</string>
+ </property>
+ <property name="buddy" stdset="0">
+ <cstring>kcfg_QuotedColor</cstring>
+ </property>
+ </widget>
+ <widget class="QLabel" row="2" column="0">
+ <property name="name">
+ <cstring>textLabel3</cstring>
+ </property>
+ <property name="text">
+ <string>Color for &amp;syntax errors:</string>
+ </property>
+ <property name="buddy" stdset="0">
+ <cstring>kcfg_ErrorColor</cstring>
+ </property>
+ </widget>
+ <widget class="KColorButton" row="2" column="1">
+ <property name="name">
+ <cstring>kcfg_ErrorColor</cstring>
+ </property>
+ <property name="text">
+ <string></string>
+ </property>
+ </widget>
+ <widget class="QLabel" row="3" column="0">
+ <property name="name">
+ <cstring>label</cstring>
+ </property>
+ <property name="text">
+ <string>Color for s&amp;pellcheck errors:</string>
+ </property>
+ <property name="buddy" stdset="0">
+ <cstring>kcfg_ErrorColor</cstring>
+ </property>
+ </widget>
+ <widget class="KColorButton" row="3" column="1">
+ <property name="name">
+ <cstring>kcfg_SpellcheckErrorColor</cstring>
+ </property>
+ <property name="text">
+ <string></string>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>&lt;qt&gt;Here you can setup a color to display identified &lt;b&gt;mispelled&lt;/b&gt; words and
+phrases.&lt;/qt&gt;</string>
+ </property>
+ </widget>
+ <widget class="QLabel" row="5" column="0">
+ <property name="name">
+ <cstring>textLabel5</cstring>
+ </property>
+ <property name="text">
+ <string>Color for &amp;keyboard accelerators:</string>
+ </property>
+ <property name="buddy" stdset="0">
+ <cstring>kcfg_AccelColor</cstring>
+ </property>
+ </widget>
+ <widget class="KColorButton" row="6" column="1">
+ <property name="name">
+ <cstring>kcfg_TagColor</cstring>
+ </property>
+ <property name="text">
+ <string></string>
+ </property>
+ </widget>
+ <widget class="KColorButton" row="5" column="1">
+ <property name="name">
+ <cstring>kcfg_AccelColor</cstring>
+ </property>
+ <property name="text">
+ <string></string>
+ </property>
+ </widget>
+ <widget class="QLabel" row="4" column="0">
+ <property name="name">
+ <cstring>textLabel4</cstring>
+ </property>
+ <property name="text">
+ <string>Color for c-for&amp;mat characters:</string>
+ </property>
+ <property name="buddy" stdset="0">
+ <cstring>kcfg_CformatColor</cstring>
+ </property>
+ </widget>
+ <widget class="KColorButton" row="4" column="1">
+ <property name="name">
+ <cstring>kcfg_CformatColor</cstring>
+ </property>
+ <property name="text">
+ <string></string>
+ </property>
+ </widget>
+ <widget class="QLabel" row="6" column="0">
+ <property name="name">
+ <cstring>textLabel6</cstring>
+ </property>
+ <property name="text">
+ <string>Color for &amp;tags:</string>
+ </property>
+ <property name="buddy" stdset="0">
+ <cstring>kcfg_TagColor</cstring>
+ </property>
+ </widget>
+ <spacer row="7" column="0">
+ <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>
+ </grid>
+</widget>
+<customwidgets>
+</customwidgets>
+<layoutdefaults spacing="6" margin="11"/>
+<includehints>
+ <includehint>kcolorbutton.h</includehint>
+ <includehint>kcolorbutton.h</includehint>
+ <includehint>kcolorbutton.h</includehint>
+ <includehint>kcolorbutton.h</includehint>
+ <includehint>kcolorbutton.h</includehint>
+ <includehint>kcolorbutton.h</includehint>
+ <includehint>kcolorbutton.h</includehint>
+</includehints>
+</UI>
diff --git a/kbabel/kbabel/commentview.cpp b/kbabel/kbabel/commentview.cpp
new file mode 100644
index 00000000..bf2301de
--- /dev/null
+++ b/kbabel/kbabel/commentview.cpp
@@ -0,0 +1,221 @@
+/* ****************************************************************************
+ This file is part of KBabel
+
+ Copyright (C) 1999-2000 by Matthias Kiefer
+ <matthias.kiefer@gmx.de>
+ 2002-2004 by Stanislav Visnovsky
+ <visnovsky@kde.org>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the 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, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+ In addition, as a special exception, the copyright holders give
+ permission to link the code of this program with any edition of
+ the Qt library by Trolltech AS, Norway (or with modified versions
+ of Qt that use the same license as Qt), and distribute linked
+ combinations including the two. You must obey the GNU General
+ Public License in all respects for all of the code used other than
+ Qt. If you modify this file, you may extend this exception to
+ your version of the file, but you are not obligated to do so. If
+ you do not wish to do so, delete this exception statement from
+ your version.
+
+**************************************************************************** */
+
+#include "commentview.h"
+
+#include <qlayout.h>
+#include <qlabel.h>
+#include <qwhatsthis.h>
+#include <qdragobject.h>
+#include <qtextview.h>
+
+#include <kapplication.h>
+#include <kconfig.h>
+#include <kcursor.h>
+#include <kdialog.h>
+#include <klocale.h>
+#include <kurl.h>
+#include <kurldrag.h>
+
+#include "resources.h"
+
+#include "editcmd.h"
+#include "hidingmsgedit.h"
+#include "kbcatalog.h"
+
+#define ID_DROP_OPEN 1
+#define ID_DROP_OPEN_TEMPLATE 2
+
+#define MAX_HISTORY 50
+
+using namespace KBabel;
+
+CommentView::CommentView(KBCatalog* catalog,QWidget *parent, Project::Ptr project)
+ : KBCatalogView(catalog,parent, project)
+{
+ setAcceptDrops(true);
+
+ QVBoxLayout* layout=new QVBoxLayout(this);
+
+ commentEdit = new MsgMultiLineEdit(0, 0, this);
+ commentEdit->setMinimumHeight(50);
+ commentEdit->setSpacePoints(false);
+ commentEdit->setHighlightSyntax(false);
+ KCursor::setAutoHideCursor(commentEdit,true);
+
+ QLabel* label=new QLabel(commentEdit,i18n("&Comment:"),this);
+
+ QHBoxLayout* hb=new QHBoxLayout(layout);
+ hb->addSpacing(KDialog::marginHint());
+ hb->addWidget(label);
+
+ layout->addWidget(commentEdit);
+ layout->setStretchFactor(commentEdit,1);
+
+ QWhatsThis::add(this,
+ i18n("<qt><p><b>Comment Editor</b></p>\n\
+This edit window shows you the comments of the currently displayed message.<p>\n\
+<p>The comments normally contain information about where the message is found in the source\n\
+code and status information about this message (fuzzy, c-format).\n\
+Hints from other translators are also sometimes contained in comments.</p>\n\
+<p>You can hide the comment editor by deactivating\n\
+<b>Options->Show Comments</b>.</p></qt>"));
+
+ commentEdit->setReadOnly(true);
+ connect(commentEdit,SIGNAL(signalUndoCmd(KBabel::EditCommand*)),this,SLOT(forwardCommentEditCmd(KBabel::EditCommand*)));
+
+ connect(commentEdit,SIGNAL(cursorPositionChanged(int,int))
+ , this, SIGNAL(signalCursorPosChanged(int,int)));
+
+ connect(_catalog, SIGNAL(signalFileOpened(bool)), this, SLOT(setDisabled(bool)));
+}
+
+void CommentView::update(EditCommand* cmd, bool undo)
+{
+ if((int)_currentIndex==cmd->index())
+ {
+ if(cmd->part()==Comment)
+ {
+ commentEdit->processCommand(cmd,undo);
+ }
+ }
+}
+
+void CommentView::textCut()
+{
+ if(commentEdit->hasFocus())
+ {
+ commentEdit->cut();
+ }
+}
+
+void CommentView::textCopy()
+{
+ if(commentEdit->hasSelectedText())
+ {
+ commentEdit->copy();
+ }
+}
+
+void CommentView::textPaste()
+{
+ if(commentEdit->hasFocus())
+ {
+ commentEdit->paste();
+ }
+}
+
+void CommentView::textSelectAll()
+{
+ if(commentEdit->hasFocus())
+ {
+ commentEdit->selectAll();
+ }
+}
+
+void CommentView::textDeselectAll()
+{
+ commentEdit->selectAll(false);
+}
+
+void CommentView::updateView()
+{
+ commentEdit->setText ( _catalog->comment (_currentIndex) );
+}
+
+void CommentView::forwardCommentEditCmd(EditCommand* cmd)
+{
+ cmd->setPart(Comment);
+ cmd->setIndex(_currentIndex);
+
+ _catalog->applyEditCommand(cmd,this);
+}
+
+void CommentView::setReadOnly(bool on)
+{
+ commentEdit->setReadOnly( on );
+}
+
+void CommentView::setOverwriteMode(bool on)
+{
+ commentEdit->setOverwriteMode( on );
+}
+
+void CommentView::readFileSettings()
+{
+ setReadOnly( _catalog->isReadOnly() );
+}
+
+const QString CommentView::selectText(int from, int to)
+{
+ int line, col, endline, endcol;
+
+ commentEdit->selectAll(false);
+ commentEdit->setFocus();
+ commentEdit->offset2Pos(from,line,col);
+ commentEdit->offset2Pos(to,endline,endcol);
+
+ commentEdit->setSelection(line,col,endline,endcol);
+ commentEdit->setCursorPosition(endline,endcol);
+
+ return commentEdit->selectedText();
+}
+
+bool CommentView::isActiveView ()
+{
+ return hasFocus () || commentEdit->hasFocus ();
+}
+
+int CommentView::currentIndex ()
+{
+ return commentEdit->currentIndex ();
+}
+
+const QString CommentView::selectedText ()
+{
+ return commentEdit->selectedText ();
+}
+
+void CommentView::installEventFilter( const QObject * filterObj )
+{
+ commentEdit->installEventFilter( filterObj );
+}
+
+bool CommentView::hasFocus()
+{
+ return commentEdit->hasFocus();
+}
+
+#include "commentview.moc"
diff --git a/kbabel/kbabel/commentview.h b/kbabel/kbabel/commentview.h
new file mode 100644
index 00000000..1531683b
--- /dev/null
+++ b/kbabel/kbabel/commentview.h
@@ -0,0 +1,96 @@
+/* ****************************************************************************
+ This file is part of KBabel
+
+ Copyright (C) 2004 by Stanislav Visnovsky
+ <visnovsky@kde.org>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the 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, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+ In addition, as a special exception, the copyright holders give
+ permission to link the code of this program with any edition of
+ the Qt library by Trolltech AS, Norway (or with modified versions
+ of Qt that use the same license as Qt), and distribute linked
+ combinations including the two. You must obey the GNU General
+ Public License in all respects for all of the code used other than
+ Qt. If you modify this file, you may extend this exception to
+ your version of the file, but you are not obligated to do so. If
+ you do not wish to do so, delete this exception statement from
+ your version.
+
+**************************************************************************** */
+#ifndef COMMENTVIEW_H
+#define COMMENTVIEW_H
+
+class QTextView;
+
+#include <qwidget.h>
+
+#include "kbcatalogview.h"
+#include "kbcatalog.h"
+#include "kbproject.h"
+#include "projectsettings.h"
+
+class MsgMultiLineEdit;
+
+class CommentView : public KBCatalogView
+{
+ Q_OBJECT
+public:
+ /**
+ * Default constructor
+ */
+ CommentView(KBCatalog* catalog,QWidget *parent, KBabel::Project::Ptr project);
+
+ /**
+ * this is called from the catalog when updating his views.
+ * reimplemented from @ref CatalogView
+ * @param cmd the edit command that has been applied
+ */
+ virtual void update(KBabel::EditCommand* cmd, bool undo=false);
+
+ virtual void updateView();
+ virtual void textCut ();
+ virtual void textCopy ();
+ virtual void textPaste ();
+ virtual void textSelectAll ();
+ virtual void textDeselectAll ();
+
+ const QString selectText( int from, int to );
+ const QString selectedText ();
+ bool isActiveView ();
+ int currentIndex ();
+
+ // this method is not virtual!
+ void installEventFilter( const QObject * filterObj );
+
+ bool hasFocus ();
+
+public slots:
+ virtual void setReadOnly(bool on);
+ virtual void setOverwriteMode(bool on);
+
+ virtual void readFileSettings();
+
+signals:
+ void signalCommentsShown();
+
+private slots:
+ void forwardCommentEditCmd(KBabel::EditCommand*);
+
+private:
+ MsgMultiLineEdit* commentEdit;
+};
+
+#endif // COMMENTVIEW_H
diff --git a/kbabel/kbabel/contextview.cpp b/kbabel/kbabel/contextview.cpp
new file mode 100644
index 00000000..e56e15dc
--- /dev/null
+++ b/kbabel/kbabel/contextview.cpp
@@ -0,0 +1,158 @@
+/* ****************************************************************************
+ This file is part of KBabel
+
+ Copyright (C) 1999-2000 by Matthias Kiefer
+ <matthias.kiefer@gmx.de>
+ 2002-2004 by Stanislav Visnovsky
+ <visnovsky@kde.org>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the 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, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+ In addition, as a special exception, the copyright holders give
+ permission to link the code of this program with any edition of
+ the Qt library by Trolltech AS, Norway (or with modified versions
+ of Qt that use the same license as Qt), and distribute linked
+ combinations including the two. You must obey the GNU General
+ Public License in all respects for all of the code used other than
+ Qt. If you modify this file, you may extend this exception to
+ your version of the file, but you are not obligated to do so. If
+ you do not wish to do so, delete this exception statement from
+ your version.
+
+**************************************************************************** */
+
+#include "contextview.h"
+
+#include <qlayout.h>
+#include <qtextview.h>
+#include <qwhatsthis.h>
+
+#include <kcursor.h>
+#include <klocale.h>
+
+#include "resources.h"
+#include "kbcatalog.h"
+
+using namespace KBabel;
+
+ContextView::ContextView(KBCatalog* catalog,QWidget *parent, Project::Ptr project)
+ : KBCatalogView(catalog,parent,project)
+{
+ QVBoxLayout* layout = new QVBoxLayout( this );
+ layout->setResizeMode( QLayout::Minimum );
+
+ _textview = new QTextView (this, "context textview");
+ KCursor::setAutoHideCursor(_textview->viewport(),true);
+ _textview->setReadOnly(true);
+
+ layout->addWidget (_textview);
+
+ QWhatsThis::add(this,
+ i18n("<qt><p><b>PO Context</b></p>"
+ "<p>This window shows the context of the current message "
+ "in the PO file. Normally it shows four messages in front "
+ "of the current message and four after it.</p>"
+ "<p>You can hide the tools window by deactivating "
+ "<b>Options->Show Tools</b>.</p></qt></qt>"));
+
+ connect(_catalog, SIGNAL(signalFileOpened(bool)), this, SLOT(setDisabled(bool)));
+}
+
+void ContextView::updateView()
+{
+ uint total = _catalog->numberOfEntries();
+ if(total==0)
+ return;
+
+ QString text;
+ uint startIndex;
+ uint context = 4;
+ if(_currentIndex < context)
+ {
+ startIndex = 0;
+ }
+ else if(_currentIndex > total-2*context-2)
+ {
+ startIndex = total-2*context-1;
+ }
+ else
+ {
+ startIndex = _currentIndex-context;
+ }
+
+ for(uint i=startIndex; i < QMIN(startIndex+(2*context+1), total); i++)
+ {
+ if(i == _currentIndex)
+ {
+ text += "<p><hr/><b>"+i18n("current entry") +"</b><hr/></p>";
+ continue;
+ }
+
+ QString entry;
+ QString temp;
+ temp = _catalog->comment(i);
+ if(!temp.isEmpty())
+ {
+ temp = QStyleSheet::convertFromPlainText(temp);
+ temp.replace(QRegExp("^<p>"),"");
+ temp.replace(QRegExp("</p>$"),"");
+ entry += "<i>"+temp+"</i><br/>";
+ }
+
+ // FIXME: should care about plural forms
+ temp = QStyleSheet::convertFromPlainText(_catalog->msgid(i).first());
+ temp.replace(QRegExp("^<p>"),"");
+ temp.replace(QRegExp("</p>$"),"");
+ entry += temp + "<br/>---<br/>";
+
+ QStringList tempList = _catalog->msgstr(i);
+
+ if(tempList.isEmpty())
+ {
+ entry +="<i><b><font color=\"red\">"
+ +i18n("untranslated")
+ +"</font></b></i><br/>";
+ }
+ else
+ {
+ if( tempList.count() == 1 )
+ {
+ temp = tempList.first();
+ }
+ else
+ {
+ uint counter = 1;
+ temp = "";
+ for( QStringList::Iterator i=tempList.begin() ; i != tempList.end() ; ++i)
+ {
+ temp += i18n("Plural %1: %2\n").arg(counter++).arg(*i);
+ }
+ }
+ temp = QStyleSheet::convertFromPlainText(temp);
+ temp.replace(QRegExp("^<p>"),"");
+ temp.replace(QRegExp("</p>$"),"");
+
+ entry += temp+"<br/>";
+ }
+
+ text += "<p>"+entry+"</p>";
+ }
+ _textview->setText("<qt>"+text+"</qt>");
+
+ int height = _textview->contentsHeight();
+ _textview->setContentsPos(0,height/2);
+}
+
+#include "contextview.moc"
diff --git a/kbabel/kbabel/contextview.h b/kbabel/kbabel/contextview.h
new file mode 100644
index 00000000..18bd0f4e
--- /dev/null
+++ b/kbabel/kbabel/contextview.h
@@ -0,0 +1,56 @@
+/* ****************************************************************************
+ This file is part of KBabel
+
+ Copyright (C) 2004 by Stanislav Visnovsky
+ <visnovsky@kde.org>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the 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, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+ In addition, as a special exception, the copyright holders give
+ permission to link the code of this program with any edition of
+ the Qt library by Trolltech AS, Norway (or with modified versions
+ of Qt that use the same license as Qt), and distribute linked
+ combinations including the two. You must obey the GNU General
+ Public License in all respects for all of the code used other than
+ Qt. If you modify this file, you may extend this exception to
+ your version of the file, but you are not obligated to do so. If
+ you do not wish to do so, delete this exception statement from
+ your version.
+
+**************************************************************************** */
+#ifndef CONTEXTVIEW_H
+#define CONTEXTVIEW_H
+
+#include "kbcatalogview.h"
+
+class QTextView;
+
+class ContextView : public KBCatalogView
+{
+ Q_OBJECT
+public:
+ /**
+ * Default constructor
+ */
+ ContextView(KBCatalog* catalog,QWidget *parent, KBabel::Project::Ptr project);
+
+public slots:
+ virtual void updateView();
+
+private:
+ QTextView* _textview;
+};
+
+#endif // CONTEXTVIEW_H
diff --git a/kbabel/kbabel/editordiffpreferences.ui b/kbabel/kbabel/editordiffpreferences.ui
new file mode 100644
index 00000000..db21bc8e
--- /dev/null
+++ b/kbabel/kbabel/editordiffpreferences.ui
@@ -0,0 +1,192 @@
+<!DOCTYPE UI><UI version="3.3" stdsetdef="1">
+<class>EditorDiffPreferences</class>
+<author>Stanislav Visnovsky</author>
+<widget class="QWidget">
+ <property name="name">
+ <cstring>EditorDiffPreferences</cstring>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>538</width>
+ <height>462</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>Appearance</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>Added Characters</string>
+ </property>
+ </widget>
+ <widget class="QLabel" row="1" column="0">
+ <property name="name">
+ <cstring>textLabel3</cstring>
+ </property>
+ <property name="text">
+ <string>Ho&amp;w to display:</string>
+ </property>
+ <property name="buddy" stdset="0">
+ <cstring>kcfg_DiffAddUnderline</cstring>
+ </property>
+ </widget>
+ <widget class="QLabel" row="2" column="0">
+ <property name="name">
+ <cstring>textLabel4</cstring>
+ </property>
+ <property name="text">
+ <string>Co&amp;lor:</string>
+ </property>
+ <property name="buddy" stdset="0">
+ <cstring>kcfg_DiffAddColor</cstring>
+ </property>
+ </widget>
+ <widget class="QLabel" row="3" column="0">
+ <property name="name">
+ <cstring>textLabel5</cstring>
+ </property>
+ <property name="text">
+ <string>Removed Characters</string>
+ </property>
+ </widget>
+ <widget class="QLabel" row="4" column="0">
+ <property name="name">
+ <cstring>textLabel6</cstring>
+ </property>
+ <property name="text">
+ <string>How &amp;to display:</string>
+ </property>
+ <property name="buddy" stdset="0">
+ <cstring>kcfg_DiffDelStrikeOut</cstring>
+ </property>
+ </widget>
+ <widget class="QLabel" row="5" column="0">
+ <property name="name">
+ <cstring>textLabel7</cstring>
+ </property>
+ <property name="text">
+ <string>Colo&amp;r:</string>
+ </property>
+ <property name="buddy" stdset="0">
+ <cstring>kcfg_DiffDelColor</cstring>
+ </property>
+ </widget>
+ <widget class="QComboBox" row="1" column="1">
+ <item>
+ <property name="text">
+ <string>Highlighted</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>Underlined</string>
+ </property>
+ </item>
+ <property name="name">
+ <cstring>kcfg_DiffAddUnderline</cstring>
+ </property>
+ </widget>
+ <widget class="KColorButton" row="2" column="1">
+ <property name="name">
+ <cstring>kcfg_DiffAddColor</cstring>
+ </property>
+ <property name="text">
+ <string></string>
+ </property>
+ <property name="color">
+ <color>
+ <red>192</red>
+ <green>192</green>
+ <blue>255</blue>
+ </color>
+ </property>
+ </widget>
+ <widget class="QComboBox" row="4" column="1">
+ <item>
+ <property name="text">
+ <string>Highlighted</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>Stroked Out</string>
+ </property>
+ </item>
+ <property name="name">
+ <cstring>kcfg_DiffDelStrikeOut</cstring>
+ </property>
+ </widget>
+ <widget class="KColorButton" row="5" column="1">
+ <property name="name">
+ <cstring>kcfg_DiffDelColor</cstring>
+ </property>
+ <property name="text">
+ <string></string>
+ </property>
+ <property name="color">
+ <color>
+ <red>255</red>
+ <green>128</green>
+ <blue>128</blue>
+ </color>
+ </property>
+ </widget>
+ </grid>
+ </widget>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>layout1</cstring>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ </hbox>
+ </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>
+<customwidgets>
+</customwidgets>
+<functions>
+ <function>init()</function>
+</functions>
+<layoutdefaults spacing="6" margin="11"/>
+<includehints>
+ <includehint>kcolorbutton.h</includehint>
+ <includehint>kcolorbutton.h</includehint>
+</includehints>
+</UI>
diff --git a/kbabel/kbabel/editorpreferences.ui b/kbabel/kbabel/editorpreferences.ui
new file mode 100644
index 00000000..ee8632f9
--- /dev/null
+++ b/kbabel/kbabel/editorpreferences.ui
@@ -0,0 +1,353 @@
+<!DOCTYPE UI><UI version="3.3" stdsetdef="1">
+<class>EditorPreferences</class>
+<author>Stanislav Visnovsky</author>
+<widget class="QWidget">
+ <property name="name">
+ <cstring>EditorPreferences</cstring>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>627</width>
+ <height>480</height>
+ </rect>
+ </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>&amp;General</string>
+ </attribute>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QFrame">
+ <property name="name">
+ <cstring>frame6</cstring>
+ </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="QCheckBox">
+ <property name="name">
+ <cstring>kcfg_AutoUnsetFuzzy</cstring>
+ </property>
+ <property name="text">
+ <string>A&amp;utomatically unset fuzzy status</string>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>&lt;qt&gt;&lt;p&gt;&lt;b&gt;Automatically unset fuzzy status&lt;/b&gt;&lt;/p&gt;
+&lt;p&gt;If this is activated and you are editing a fuzzy entry, the fuzzy status is automatically
+unset (this means the string &lt;i&gt;, fuzzy&lt;/i&gt;
+is removed from the entry's comment).&lt;/p&gt;&lt;/qt&gt;</string>
+ </property>
+ </widget>
+ <widget class="QCheckBox">
+ <property name="name">
+ <cstring>kcfg_CleverEditing</cstring>
+ </property>
+ <property name="text">
+ <string>Use cle&amp;ver editing</string>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>&lt;qt&gt;&lt;p&gt;&lt;b&gt;Use clever editing&lt;/b&gt;&lt;/p&gt;
+&lt;p&gt;Check this to make typing text more comfortable and let
+KBabel take care of some special characters that have to
+be quoted. For example typing '\"' will result in
+'\\\"', pressing Return will automatically add whitespace
+at the end of the line, pressing Shift+Return will add
+'\\n' at the end of the line.&lt;/p&gt;
+&lt;p&gt;Note that this is just a hint: it is still possible to
+generate syntactically incorrect text.&lt;/p&gt;&lt;/qt&gt;</string>
+ </property>
+ </widget>
+ </hbox>
+ </widget>
+ <widget class="QGroupBox">
+ <property name="name">
+ <cstring>groupBox3</cstring>
+ </property>
+ <property name="title">
+ <string>Automatic Checks</string>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>&lt;qt&gt;&lt;p&gt;&lt;b&gt;Error recognition&lt;/b&gt;&lt;/p&gt;
+&lt;p&gt;Here you can set how to show that an error occurred.
+&lt;b&gt;Beep on error&lt;/b&gt; beeps and &lt;b&gt;Change text color on error
+&lt;/b&gt; changes the color of the translated text. If none is
+activated, you will still see a message in the statusbar.
+&lt;/p&gt;&lt;/qt&gt;</string>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="ToolSelectionWidget">
+ <property name="name">
+ <cstring>_kcfg_AutoCheckTools</cstring>
+ </property>
+ </widget>
+ <widget class="QCheckBox">
+ <property name="name">
+ <cstring>kcfg_BeepOnError</cstring>
+ </property>
+ <property name="text">
+ <string>&amp;Beep on error</string>
+ </property>
+ </widget>
+ <widget class="QCheckBox">
+ <property name="name">
+ <cstring>kcfg_AutoCheckColorError</cstring>
+ </property>
+ <property name="text">
+ <string>Change te&amp;xt color on error</string>
+ </property>
+ </widget>
+ </vbox>
+ </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>21</height>
+ </size>
+ </property>
+ </spacer>
+ </vbox>
+ </widget>
+ <widget class="QWidget">
+ <property name="name">
+ <cstring>tab</cstring>
+ </property>
+ <attribute name="title">
+ <string>A&amp;ppearance</string>
+ </attribute>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <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>
+ <widget class="QCheckBox" row="0" column="0">
+ <property name="name">
+ <cstring>kcfg_HighlightSyntax</cstring>
+ </property>
+ <property name="text">
+ <string>H&amp;ighlight syntax</string>
+ </property>
+ </widget>
+ <widget class="QCheckBox" row="1" column="0">
+ <property name="name">
+ <cstring>kcfg_HighlightBackground</cstring>
+ </property>
+ <property name="text">
+ <string>Highlight backgrou&amp;nd</string>
+ </property>
+ </widget>
+ <widget class="QCheckBox" row="0" column="1">
+ <property name="name">
+ <cstring>kcfg_WhitespacePoints</cstring>
+ </property>
+ <property name="text">
+ <string>Mark &amp;whitespaces with points</string>
+ </property>
+ </widget>
+ <widget class="QCheckBox" row="1" column="1">
+ <property name="name">
+ <cstring>kcfg_EnableQuotes</cstring>
+ </property>
+ <property name="text">
+ <string>&amp;Show surrounding quotes</string>
+ </property>
+ </widget>
+ </grid>
+ </widget>
+ <widget class="QButtonGroup">
+ <property name="name">
+ <cstring>buttonGroup1</cstring>
+ </property>
+ <property name="title">
+ <string>Status LEDs</string>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>&lt;qt&gt;&lt;p&gt;&lt;b&gt;Status LEDs&lt;/b&gt;&lt;/p&gt;
+&lt;p&gt;Choose here where the status LEDs are displayed and what color they have.&lt;/p&gt;&lt;/qt&gt;</string>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QRadioButton">
+ <property name="name">
+ <cstring>kcfg_LedInStatusbar</cstring>
+ </property>
+ <property name="text">
+ <string>Display in stat&amp;usbar</string>
+ </property>
+ </widget>
+ <widget class="QRadioButton">
+ <property name="name">
+ <cstring>radioButton2</cstring>
+ </property>
+ <property name="text">
+ <string>Display in edi&amp;tor</string>
+ </property>
+ <property name="checked">
+ <bool>true</bool>
+ </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>51</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>textLabel7</cstring>
+ </property>
+ <property name="text">
+ <string>Colo&amp;r:</string>
+ </property>
+ <property name="buddy" stdset="0">
+ <cstring>kcfg_LedColor</cstring>
+ </property>
+ </widget>
+ <widget class="KColorButton">
+ <property name="name">
+ <cstring>kcfg_LedColor</cstring>
+ </property>
+ <property name="text">
+ <string></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>29</height>
+ </size>
+ </property>
+ </spacer>
+ </vbox>
+ </widget>
+ </widget>
+ </vbox>
+</widget>
+<customwidgets>
+ <customwidget>
+ <class>ToolSelectionWidget</class>
+ <header location="global">toolselectionwidget.h</header>
+ <sizehint>
+ <width>200</width>
+ <height>200</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="XBM.GZ" length="79">789c534e494dcbcc4b554829cdcdad8c2fcf4c29c95030e0524611cd48cd4ccf28010a1797249664262b2467241641a592324b8aa363156c15aab914146aadb90067111b1f</data>
+ </image>
+</images>
+<connections>
+ <connection>
+ <sender>kcfg_LedInStatusbar</sender>
+ <signal>toggled(bool)</signal>
+ <receiver>EditorPreferences</receiver>
+ <slot>ledWarning(bool)</slot>
+ </connection>
+ <connection>
+ <sender>radioButton2</sender>
+ <signal>toggled(bool)</signal>
+ <receiver>EditorPreferences</receiver>
+ <slot>ledWarning(bool)</slot>
+ </connection>
+ <connection>
+ <sender>kcfg_LedInStatusbar</sender>
+ <signal>toggled(bool)</signal>
+ <receiver>EditorPreferences</receiver>
+ <slot>toggleOther(bool)</slot>
+ </connection>
+</connections>
+<includes>
+ <include location="local" impldecl="in implementation">editorpreferences.ui.h</include>
+</includes>
+<slots>
+ <slot specifier="non virtual">ledWarning( bool show )</slot>
+ <slot specifier="non virtual">toggleOther( bool other )</slot>
+</slots>
+<layoutdefaults spacing="6" margin="11"/>
+<includehints>
+ <includehint>toolselectionwidget.h</includehint>
+ <includehint>kcolorbutton.h</includehint>
+</includehints>
+</UI>
diff --git a/kbabel/kbabel/editorpreferences.ui.h b/kbabel/kbabel/editorpreferences.ui.h
new file mode 100644
index 00000000..b7f9827c
--- /dev/null
+++ b/kbabel/kbabel/editorpreferences.ui.h
@@ -0,0 +1,23 @@
+/****************************************************************************
+** 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.
+*****************************************************************************/
+
+#include <kmessagebox.h>
+#include "toolselectionwidget.h"
+
+void EditorPreferences::ledWarning( bool show )
+{
+if(show)
+ KMessageBox::information( this,i18n("This option takes no effect until KBabel is restarted.") );
+}
+
+
+void EditorPreferences::toggleOther( bool other )
+{
+ radioButton2->setChecked(! other);
+}
diff --git a/kbabel/kbabel/errorlistview.cpp b/kbabel/kbabel/errorlistview.cpp
new file mode 100644
index 00000000..2dcd3b12
--- /dev/null
+++ b/kbabel/kbabel/errorlistview.cpp
@@ -0,0 +1,76 @@
+/* ****************************************************************************
+ This file is part of KBabel
+
+ Copyright (C) 1999-2000 by Matthias Kiefer
+ <matthias.kiefer@gmx.de>
+ 2002-2004 by Stanislav Visnovsky
+ <visnovsky@kde.org>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the 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, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+ In addition, as a special exception, the copyright holders give
+ permission to link the code of this program with any edition of
+ the Qt library by Trolltech AS, Norway (or with modified versions
+ of Qt that use the same license as Qt), and distribute linked
+ combinations including the two. You must obey the GNU General
+ Public License in all respects for all of the code used other than
+ Qt. If you modify this file, you may extend this exception to
+ your version of the file, but you are not obligated to do so. If
+ you do not wish to do so, delete this exception statement from
+ your version.
+
+**************************************************************************** */
+
+#include "errorlistview.h"
+
+#include <qlayout.h>
+#include <qtextview.h>
+#include <qwhatsthis.h>
+
+#include <kcursor.h>
+#include <klocale.h>
+
+#include "resources.h"
+#include "kbcatalog.h"
+
+using namespace KBabel;
+
+ErrorListView::ErrorListView(KBCatalog* catalog,QWidget *parent, Project::Ptr project)
+ : KBCatalogView(catalog,parent,project)
+{
+ QVBoxLayout* layout = new QVBoxLayout( this );
+ layout->setResizeMode( QLayout::Minimum );
+
+ _textview = new QTextView (this);
+ KCursor::setAutoHideCursor(_textview->viewport(),true);
+ _textview->setReadOnly(true);
+
+ layout->addWidget(_textview);
+
+ QWhatsThis::add(this, i18n( "<qt><p><b>Error List</b></p>"
+ "<p>This window shows the list of errors found by validator tools "
+ "so you can know why the current message has been marked with an "
+ "error.</p></qt>" ) );
+}
+
+void ErrorListView::updateView()
+{
+ if( _catalog->numberOfEntries() == 0 )
+ return;
+
+ _textview->setText( _catalog->itemStatus( _currentIndex ).join( "\n---\n" ) );
+}
+
+#include "errorlistview.moc"
diff --git a/kbabel/kbabel/errorlistview.h b/kbabel/kbabel/errorlistview.h
new file mode 100644
index 00000000..d50e7ec7
--- /dev/null
+++ b/kbabel/kbabel/errorlistview.h
@@ -0,0 +1,55 @@
+/* ****************************************************************************
+ This file is part of KBabel
+
+ Copyright (C) 2004 by Albert Cervera Areny <albertca@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.
+
+ 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, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+ In addition, as a special exception, the copyright holders give
+ permission to link the code of this program with any edition of
+ the Qt library by Trolltech AS, Norway (or with modified versions
+ of Qt that use the same license as Qt), and distribute linked
+ combinations including the two. You must obey the GNU General
+ Public License in all respects for all of the code used other than
+ Qt. If you modify this file, you may extend this exception to
+ your version of the file, but you are not obligated to do so. If
+ you do not wish to do so, delete this exception statement from
+ your version.
+
+**************************************************************************** */
+#ifndef ERRORLISTVIEW_H
+#define ERRORLISTVIEW_H
+
+#include "kbcatalogview.h"
+
+class QTextView;
+
+class ErrorListView : public KBCatalogView
+{
+ Q_OBJECT
+public:
+ /**
+ * Default constructor
+ */
+ ErrorListView(KBCatalog* catalog,QWidget *parent, KBabel::Project::Ptr project);
+
+public slots:
+ virtual void updateView();
+
+private:
+ QTextView* _textview;
+};
+
+#endif // ERRORLISTVIEW_H
diff --git a/kbabel/kbabel/fontpreferences.ui b/kbabel/kbabel/fontpreferences.ui
new file mode 100644
index 00000000..aefb8c7e
--- /dev/null
+++ b/kbabel/kbabel/fontpreferences.ui
@@ -0,0 +1,63 @@
+<!DOCTYPE UI><UI version="3.2" stdsetdef="1">
+<class>FontPreferences</class>
+<author>Stanislav Visnovsky</author>
+<widget class="QWidget">
+ <property name="name">
+ <cstring>FontPreferences</cstring>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>595</width>
+ <height>515</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>Font for Messages</string>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QCheckBox">
+ <property name="name">
+ <cstring>checkBox1</cstring>
+ </property>
+ <property name="text">
+ <string>&amp;Show only fixed font</string>
+ </property>
+ </widget>
+ <widget class="KFontChooser">
+ <property name="name">
+ <cstring>kcfg_MsgFont</cstring>
+ </property>
+ </widget>
+ </vbox>
+ </widget>
+ </vbox>
+</widget>
+<connections>
+ <connection>
+ <sender>checkBox1</sender>
+ <signal>toggled(bool)</signal>
+ <receiver>FontPreferences</receiver>
+ <slot>showOnlyFixedFonts(bool)</slot>
+ </connection>
+</connections>
+<includes>
+ <include location="local" impldecl="in implementation">fontpreferences.ui.h</include>
+</includes>
+<slots>
+ <slot access="private">showOnlyFixedFonts( bool on )</slot>
+</slots>
+<layoutdefaults spacing="6" margin="11"/>
+</UI>
diff --git a/kbabel/kbabel/fontpreferences.ui.h b/kbabel/kbabel/fontpreferences.ui.h
new file mode 100644
index 00000000..065318f1
--- /dev/null
+++ b/kbabel/kbabel/fontpreferences.ui.h
@@ -0,0 +1,14 @@
+/****************************************************************************
+** 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.
+*****************************************************************************/
+
+
+void FontPreferences::showOnlyFixedFonts( bool on)
+{
+ kcfg_MsgFont->setFont(kcfg_MsgFont->font(), on);
+}
diff --git a/kbabel/kbabel/gotodialog.cpp b/kbabel/kbabel/gotodialog.cpp
new file mode 100644
index 00000000..f822f0dc
--- /dev/null
+++ b/kbabel/kbabel/gotodialog.cpp
@@ -0,0 +1,74 @@
+/* ****************************************************************************
+ This file is part of KBabel
+
+ Copyright (C) 1999-2000 by Matthias Kiefer
+ <matthias.kiefer@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.
+
+ 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, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+ In addition, as a special exception, the copyright holders give
+ permission to link the code of this program with any edition of
+ the Qt library by Trolltech AS, Norway (or with modified versions
+ of Qt that use the same license as Qt), and distribute linked
+ combinations including the two. You must obey the GNU General
+ Public License in all respects for all of the code used other than
+ Qt. If you modify this file, you may extend this exception to
+ your version of the file, but you are not obligated to do so. If
+ you do not wish to do so, delete this exception statement from
+ your version.
+
+**************************************************************************** */
+
+#include <qstring.h>
+#include <klocale.h>
+#include <knuminput.h>
+
+#include "gotodialog.h"
+
+GotoDialog::GotoDialog(int max,QWidget* parent)
+ : KDialogBase(parent,0,true,i18n("Go to Entry"),Ok|Cancel)
+{
+ QGroupBox* box=new QGroupBox(1,Qt::Horizontal,i18n("Go to Entry"),this);
+ _spinBox= new KIntSpinBox(1,max,1,1,10,box);
+
+ setMainWidget(box);
+
+ _spinBox->setFocus();
+}
+
+GotoDialog::~GotoDialog()
+{
+}
+
+
+void GotoDialog::show()
+{
+ _spinBox->setEditFocus(true);
+
+ KDialogBase::show();
+}
+
+
+int GotoDialog::number()
+{
+ return _spinBox->value();
+}
+
+void GotoDialog::setMax(int max)
+{
+ _spinBox->setRange(1,max);
+ if(_spinBox->value()>max)
+ _spinBox->setValue(max);
+}
diff --git a/kbabel/kbabel/gotodialog.h b/kbabel/kbabel/gotodialog.h
new file mode 100644
index 00000000..4c8378d8
--- /dev/null
+++ b/kbabel/kbabel/gotodialog.h
@@ -0,0 +1,63 @@
+/* ****************************************************************************
+ This file is part of KBabel
+
+ Copyright (C) 1999-2000 by Matthias Kiefer
+ <matthias.kiefer@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.
+
+ 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, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+ In addition, as a special exception, the copyright holders give
+ permission to link the code of this program with any edition of
+ the Qt library by Trolltech AS, Norway (or with modified versions
+ of Qt that use the same license as Qt), and distribute linked
+ combinations including the two. You must obey the GNU General
+ Public License in all respects for all of the code used other than
+ Qt. If you modify this file, you may extend this exception to
+ your version of the file, but you are not obligated to do so. If
+ you do not wish to do so, delete this exception statement from
+ your version.
+
+**************************************************************************** */
+#ifndef GOTODIALOG_H
+#define GOTODIALOG_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <kdialogbase.h>
+#include <qgroupbox.h>
+
+class KIntSpinBox;
+
+class GotoDialog : public KDialogBase
+{
+public:
+ GotoDialog(int max, QWidget* parent);
+ virtual ~GotoDialog();
+
+ /** reimplemented to select contents when shown*/
+ virtual void show();
+
+ int number();
+ void setMax(int max);
+
+private:
+ KIntSpinBox* _spinBox;
+
+};
+
+
+#endif // GOTODIALOG_H
diff --git a/kbabel/kbabel/headereditor.cpp b/kbabel/kbabel/headereditor.cpp
new file mode 100644
index 00000000..55ad4eb5
--- /dev/null
+++ b/kbabel/kbabel/headereditor.cpp
@@ -0,0 +1,214 @@
+/* ****************************************************************************
+ This file is part of KBabel
+
+ Copyright (C) 1999-2000 by Matthias Kiefer
+ <matthias.kiefer@gmx.de>
+ 2002-2003 by Stanislav Visnovsky
+ <visnovsky@kde.org>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the 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, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+ In addition, as a special exception, the copyright holders give
+ permission to link the code of this program with any edition of
+ the Qt library by Trolltech AS, Norway (or with modified versions
+ of Qt that use the same license as Qt), and distribute linked
+ combinations including the two. You must obey the GNU General
+ Public License in all respects for all of the code used other than
+ Qt. If you modify this file, you may extend this exception to
+ your version of the file, but you are not obligated to do so. If
+ you do not wish to do so, delete this exception statement from
+ your version.
+
+**************************************************************************** */
+#include <kcursor.h>
+#include <kglobalsettings.h>
+#include <kglobal.h>
+#include <kconfig.h>
+#include <klocale.h>
+#include <kmessagebox.h>
+#include <ktextedit.h>
+#include <kurl.h>
+
+#include "catalog.h"
+#include "catalogitem.h"
+#include "headereditor.h"
+#include "headerwidget.h"
+
+using namespace KBabel;
+
+HeaderEditor::HeaderEditor(Catalog* cat,const char* name)
+ : KDialogBase((QWidget*)0,name,false,QString::null, Ok|Cancel|Default|User1)
+{
+ restoreSettings();
+
+ _catalog=cat;
+ connect(_catalog,SIGNAL(signalFileOpened(bool)),this,SLOT(readHeader(bool)));
+ connect(_catalog,SIGNAL(signalHeaderChanged()),this,SLOT(updateHeader()));
+
+ setButtonText(User1,i18n("&Apply Settings"));
+ setButtonWhatsThis (User1, i18n("<qt><p>This button "
+ "updates the header using the current settings. "
+ "The resulting header is the one that would be written into the PO file "
+ "on saving.</p></qt>") );
+ setButtonText(Default,i18n("&Reset"));
+ setButtonWhatsThis (Default, i18n("<qt><p>This button "
+ "will revert all changes made so far.</p></qt>") );
+
+ _editor=new HeaderWidget(this,"internal headereditor");
+ _editor->setMinimumSize(_editorSize);
+
+ KCursor::setAutoHideCursor(_editor,true);
+
+ readHeader(cat->isReadOnly());
+ updateHeader();
+
+ setMainWidget(_editor);
+}
+
+HeaderEditor::~HeaderEditor()
+{
+ saveSettings();
+}
+
+void HeaderEditor::saveSettings()
+{
+ KConfig* config = KGlobal::config();
+
+ KConfigGroupSaver saver(config, "HeaderEditor" );
+
+ config->writeEntry( "Size", _editor->size() );
+}
+
+void HeaderEditor::restoreSettings()
+{
+ KConfig* config = KGlobal::config();
+
+ KConfigGroupSaver saver(config, "HeaderEditor" );
+
+ QSize defaultSize(350,250);
+ _editorSize = config->readSizeEntry("Size", &defaultSize );
+}
+
+bool HeaderEditor::isModified()
+{
+ return _editor->commentEdit->isModified() || _editor->headerEdit->isModified();
+}
+
+void HeaderEditor::readHeader(bool readOnly)
+{
+ setCaption(i18n("Header Editor for %1").arg(_catalog->currentURL().prettyURL()));
+
+ _editor->headerEdit->setReadOnly(readOnly);
+ _editor->commentEdit->setReadOnly(readOnly);
+ enableButton(User1,!readOnly);
+}
+
+void HeaderEditor::updateHeader()
+{
+ _editor->headerEdit->setText(_catalog->header().msgstr().first());
+ _editor->headerEdit->setModified(false);
+ _editor->commentEdit->setText(_catalog->header().comment());
+ _editor->commentEdit->setModified(false);
+}
+
+
+// update button
+void HeaderEditor::slotUser1()
+{
+ CatalogItem header;
+
+ bool error = !isValid();
+
+ if(error)
+ {
+ QString msg=i18n("<qt><p>This is not a valid header.</p>\n"
+ "<p>Please edit the header before updating!</p></qt>");
+
+ KMessageBox::sorry(this,msg);
+
+ return;
+ }
+
+ header.setComment( _editor->commentEdit->text() );
+ header.setMsgstr( _editor->headerEdit->text() );
+
+ header=_catalog->updatedHeader(header,true);
+
+ _editor->headerEdit->setText(header.msgstr().first());
+ _editor->commentEdit->setText(header.comment());
+}
+
+
+void HeaderEditor::slotDefault()
+{
+ updateHeader();
+}
+
+void HeaderEditor::slotCancel()
+{
+ updateHeader();
+
+ QDialog::reject();
+}
+
+void HeaderEditor::slotOk()
+{
+ if(isModified())
+ {
+ if(!isValid())
+ {
+ QString msg=i18n("<qt><p>This is not a valid header.</p>\n"
+ "<p>Please edit the header before updating.</p></qt>");
+
+ switch(KMessageBox::warningYesNo(this,msg,i18n("Warning"),KStdGuiItem::discard(),i18n("Edit")))
+ {
+ case KMessageBox::Yes:
+ {
+ slotCancel();
+ return;
+ }
+ default:
+ return;
+ }
+ }
+
+ CatalogItem header;
+
+ header.setComment( _editor->commentEdit->text() );
+ header.setMsgstr( _editor->headerEdit->text() );
+
+ _catalog->setHeader(header);
+ }
+
+ QDialog::accept();
+}
+
+bool HeaderEditor::isValid()
+{
+ // check the comments
+ QStringList comments = QStringList::split('\n',_editor->commentEdit->text());
+
+ for( QStringList::Iterator it = comments.begin(); it != comments.end(); ++it )
+ {
+ if( !(*it).startsWith("#") )
+ {
+ return false;
+ }
+ }
+
+ return true;
+}
+
+#include "headereditor.moc"
diff --git a/kbabel/kbabel/headereditor.h b/kbabel/kbabel/headereditor.h
new file mode 100644
index 00000000..9fb9d6fb
--- /dev/null
+++ b/kbabel/kbabel/headereditor.h
@@ -0,0 +1,85 @@
+/* ****************************************************************************
+ This file is part of KBabel
+
+ Copyright (C) 1999-2000 by Matthias Kiefer
+ <matthias.kiefer@gmx.de>
+ 2002-2003 by Stanislav Visnovsky
+ <visnovsky@kde.org>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the 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, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+ In addition, as a special exception, the copyright holders give
+ permission to link the code of this program with any edition of
+ the Qt library by Trolltech AS, Norway (or with modified versions
+ of Qt that use the same license as Qt), and distribute linked
+ combinations including the two. You must obey the GNU General
+ Public License in all respects for all of the code used other than
+ Qt. If you modify this file, you may extend this exception to
+ your version of the file, but you are not obligated to do so. If
+ you do not wish to do so, delete this exception statement from
+ your version.
+
+**************************************************************************** */
+#ifndef HEADEREDITOR_H
+#define HEADEREDITOR_H
+
+#include <kdialogbase.h>
+
+namespace KBabel
+{
+ class Catalog;
+}
+
+class HeaderWidget;
+
+class HeaderEditor : public KDialogBase
+{
+ Q_OBJECT
+public:
+ /**
+ * constructor for the HeaderEditor
+ * @param cat The Catalog from which the header is edited
+ */
+ HeaderEditor(KBabel::Catalog* cat,const char* name=0);
+ virtual ~HeaderEditor();
+
+ bool isModified();
+
+public slots:
+ void readHeader(bool);
+
+protected slots:
+
+ /** update button */
+ virtual void slotUser1();
+ virtual void slotCancel();
+ virtual void slotOk();
+ virtual void slotDefault();
+
+ /** updates the header when header was changed by the catalog */
+ void updateHeader();
+
+private:
+ void saveSettings();
+ void restoreSettings();
+ bool isValid();
+
+ KBabel::Catalog* _catalog;
+ HeaderWidget* _editor;
+
+ QSize _editorSize;
+};
+
+#endif // HEADEREDITOR_H
diff --git a/kbabel/kbabel/headerwidget.ui b/kbabel/kbabel/headerwidget.ui
new file mode 100644
index 00000000..f74a9ef5
--- /dev/null
+++ b/kbabel/kbabel/headerwidget.ui
@@ -0,0 +1,64 @@
+<!DOCTYPE UI><UI version="3.1" stdsetdef="1">
+<class>HeaderWidget</class>
+<widget class="QWidget">
+ <property name="name">
+ <cstring>HeaderWidget</cstring>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>401</width>
+ <height>380</height>
+ </rect>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>commentLabel</cstring>
+ </property>
+ <property name="text">
+ <string>&amp;Comment:</string>
+ </property>
+ <property name="buddy" stdset="0">
+ <cstring>commentEdit</cstring>
+ </property>
+ </widget>
+ <widget class="KTextEdit">
+ <property name="name">
+ <cstring>commentEdit</cstring>
+ </property>
+ <property name="wordWrap">
+ <enum>NoWrap</enum>
+ </property>
+ </widget>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>headerLabel</cstring>
+ </property>
+ <property name="text">
+ <string>&amp;Header:</string>
+ </property>
+ <property name="buddy" stdset="0">
+ <cstring>headerEdit</cstring>
+ </property>
+ </widget>
+ <widget class="KTextEdit">
+ <property name="name">
+ <cstring>headerEdit</cstring>
+ </property>
+ <property name="wordWrap">
+ <enum>NoWrap</enum>
+ </property>
+ </widget>
+ </vbox>
+</widget>
+<layoutdefaults spacing="6" margin="11"/>
+<includehints>
+ <includehint>ktextedit.h</includehint>
+ <includehint>ktextedit.h</includehint>
+</includehints>
+</UI>
diff --git a/kbabel/kbabel/hi16-app-kbabel.png b/kbabel/kbabel/hi16-app-kbabel.png
new file mode 100644
index 00000000..3b062e51
--- /dev/null
+++ b/kbabel/kbabel/hi16-app-kbabel.png
Binary files differ
diff --git a/kbabel/kbabel/hi32-app-kbabel.png b/kbabel/kbabel/hi32-app-kbabel.png
new file mode 100644
index 00000000..b7f1e843
--- /dev/null
+++ b/kbabel/kbabel/hi32-app-kbabel.png
Binary files differ
diff --git a/kbabel/kbabel/hi48-app-kbabel.png b/kbabel/kbabel/hi48-app-kbabel.png
new file mode 100644
index 00000000..77bd3530
--- /dev/null
+++ b/kbabel/kbabel/hi48-app-kbabel.png
Binary files differ
diff --git a/kbabel/kbabel/hidingmsgedit.cpp b/kbabel/kbabel/hidingmsgedit.cpp
new file mode 100644
index 00000000..f18f8b81
--- /dev/null
+++ b/kbabel/kbabel/hidingmsgedit.cpp
@@ -0,0 +1,426 @@
+/***************************************************************************
+ hidingmsgedit.cpp - description
+ -------------------
+ begin : So nov 2 2002
+ copyright : (C) 2002 by Stanislav Visnovsky
+ email : visnovsky@kde.org
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ In addition, as a special exception, the copyright holders give
+ permission to link the code of this program with any edition of
+ the Qt library by Trolltech AS, Norway (or with modified versions
+ of Qt that use the same license as Qt), and distribute linked
+ combinations including the two. You must obey the GNU General
+ Public License in all respects for all of the code used other than
+ Qt. If you modify this file, you may extend this exception to
+ your version of the file, but you are not obligated to do so. If
+ you do not wish to do so, delete this exception statement from
+ your version.
+
+ ***************************************************************************/
+
+#include "resources.h"
+#include "hidingmsgedit.h"
+#include "mymultilineedit.h"
+#include "editcmd.h"
+
+#include <qptrlist.h>
+#include <qsizepolicy.h>
+#include <qstringlist.h>
+#include <qtabwidget.h>
+
+#include <kdebug.h>
+#include <klocale.h>
+
+using namespace KBabel;
+
+HidingMsgEdit::HidingMsgEdit(uint numberOfPlurals, QWidget* eventFilter, KSpell* spell, QWidget *parent, const char *name ) :
+ QWidgetStack(parent,name)
+ , _singleEdit(0)
+ , _multipleEdit(0)
+ , _eventFilter(eventFilter)
+ , _currentEdit(0)
+ , _numberOfPlurals(numberOfPlurals)
+ , _spell(spell)
+{
+
+ _allEdits.clear();
+ setNumberOfPlurals( _numberOfPlurals );
+
+ connect( _multipleEdit, SIGNAL(currentChanged( QWidget* )),
+ this, SLOT( newCurrentMultiple( QWidget* )));
+
+ showSingle();
+}
+
+HidingMsgEdit::~HidingMsgEdit(){
+}
+
+void HidingMsgEdit::setText(QStringList texts, QString msgctxt){
+ if( texts.count() == 0 )
+ {
+ kdWarning() << "HidingMsgEdit::setText with empty text" << endl;
+ _singleEdit->clear();
+ showSingle();
+ return;
+ }
+
+ if (!msgctxt.isEmpty())
+ msgctxt = "\n>>>>> " + i18n("Context inserted by KBabel, do not translate:") + "\n" + msgctxt;
+
+ if( texts.count() == 1 )
+ {
+ _singleEdit->setText(*texts.at(0) + msgctxt);
+ showSingle();
+ }
+ else
+ {
+ if( _numberOfPlurals )
+ {
+ QStringList::iterator text = texts.begin();
+ uint i;
+ for( i=0 ; i < _numberOfPlurals && text!= texts.end() ; i++, text++ )
+ {
+ static_cast<MsgMultiLineEdit *>(_multipleEdit->page(i))->setText(*text + msgctxt);
+ }
+
+ // clean the non-initialized ones
+ while (i < _numberOfPlurals)
+ {
+ static_cast<MsgMultiLineEdit *>(_multipleEdit->page(i))->setText("");
+ i++;
+ }
+ }
+ showMultiple();
+ }
+}
+
+void HidingMsgEdit::showSingle(){
+ raiseWidget(_singleEdit);
+ _currentEdit=_singleEdit;
+ _currentEdit->setFocus();
+
+ emit currentFormChanged ( 0 );
+}
+
+void HidingMsgEdit::showMultiple(){
+ raiseWidget(_multipleEdit);
+ _currentEdit=static_cast<MsgMultiLineEdit*>(_multipleEdit->currentPage());
+ _currentEdit->setFocus();
+
+ emit currentFormChanged ( _multipleEdit->currentPageIndex () );
+}
+
+void HidingMsgEdit::showPlurals( bool on )
+{
+ if( on ) showMultiple();
+ else showSingle();
+}
+
+void HidingMsgEdit::showForm(int form)
+{
+ if( _currentEdit==_singleEdit && form>0 )
+ {
+ showMultiple();
+ _multipleEdit->setCurrentPage(form);
+ _currentEdit=static_cast<MsgMultiLineEdit*>(_multipleEdit->currentPage());
+ emit currentFormChanged ( form );
+ }
+ else
+ if( _currentEdit!=_singleEdit )
+ {
+ _multipleEdit->setCurrentPage(form);
+ _currentEdit=static_cast<MsgMultiLineEdit*>(_multipleEdit->currentPage());
+ emit currentFormChanged ( 0 );
+ }
+ _currentEdit->setFocus();
+}
+
+void HidingMsgEdit::setNumberOfPlurals( uint numberOfPlurals )
+{
+ _numberOfPlurals = numberOfPlurals;
+
+ // find out the current shown version
+ bool plurals = _currentEdit != _singleEdit;
+ bool readonly = _currentEdit ? _currentEdit->isReadOnly () : true;
+
+ // cleanup old
+ _currentEdit=0;
+ _allEdits.clear();
+ if( _singleEdit )
+ {
+ removeWidget( _singleEdit );
+ delete _singleEdit;
+ }
+
+ if( _multipleEdit )
+ {
+ removeWidget( _multipleEdit );
+ delete _multipleEdit;
+ }
+
+ // create new
+ _singleEdit = new MsgMultiLineEdit( 0, _spell, this, "singleEdit" );
+ _allEdits.append( _singleEdit );
+ if( _eventFilter )
+ _singleEdit->installEventFilter(_eventFilter);
+
+ _multipleEdit = new QTabWidget( this );
+
+ MsgMultiLineEdit* pl;
+ for(uint i=0 ; i< _numberOfPlurals ; i++)
+ {
+ pl = new MsgMultiLineEdit( i, _spell, _multipleEdit, QString("multipleEdit %1").arg(i).local8Bit());
+ _allEdits.append(pl);
+ _multipleEdit->addTab( pl, i18n("Plural %1").arg(i+1));
+ if( _eventFilter )
+ pl->installEventFilter(_eventFilter);
+ }
+
+ addWidget(_singleEdit);
+ addWidget(_multipleEdit);
+
+ for( MsgMultiLineEdit* e = _allEdits.first() ; e ; e = _allEdits.next() )
+ {
+ connect( e, SIGNAL( signalUndoCmd( KBabel::EditCommand* )),
+ this, SIGNAL( signalUndoCmd( KBabel::EditCommand* )));
+ connect( e, SIGNAL( textChanged() ) , this, SIGNAL( textChanged() ));
+ connect( e, SIGNAL( textChanged() ) , this, SLOT( emitTextChanged() ));
+ connect( e, SIGNAL( cursorPositionChanged( int, int )),
+ this, SLOT( emitCursorPositionChanged( int, int )) );
+ }
+
+ showPlurals( plurals );
+
+ _currentEdit->setReadOnly (readonly);
+}
+
+void HidingMsgEdit::emitTextChanged()
+{
+ emit textChanged(_currentEdit->text());
+}
+
+uint HidingMsgEdit::currentForm()
+{
+ if( _currentEdit == _singleEdit ) return 0;
+ else return _multipleEdit->currentPageIndex();
+}
+
+void HidingMsgEdit::newCurrentMultiple( QWidget* widget )
+{
+ _currentEdit = dynamic_cast<MsgMultiLineEdit*>(widget);
+ emit currentFormChanged ( _multipleEdit->currentPageIndex () );
+}
+
+bool HidingMsgEdit::isModified() {
+ for( MsgMultiLineEdit* e = _allEdits.first(); e ; e = _allEdits.next() )
+ {
+ if( e->isModified() )
+ {
+ return true;
+ }
+ }
+ return false;
+}
+
+void HidingMsgEdit::setReadOnly(bool on) {
+ for( MsgMultiLineEdit* e = _allEdits.first(); e ; e = _allEdits.next() )
+ {
+ e->setReadOnly( on );
+ }
+}
+
+void HidingMsgEdit::processCommand(EditCommand* cmd, bool undo)
+{
+ if( _currentEdit == _singleEdit )
+ {
+ _singleEdit->processCommand(cmd,undo);
+ }
+ else
+ {
+ if( cmd->terminator() == 0)
+ {
+ static_cast<MsgMultiLineEdit*>(
+ _multipleEdit->page(static_cast<DelTextCmd*>(cmd)->pluralNumber)
+ )->processCommand(cmd,undo);
+ }
+ }
+}
+
+void HidingMsgEdit::setSpacePoints(bool on)
+{
+ for( MsgMultiLineEdit* e = _allEdits.first(); e ; e = _allEdits.next() )
+ {
+ e->setSpacePoints( on );
+ }
+}
+
+void HidingMsgEdit::setHighlightSyntax( bool on )
+{
+ for( MsgMultiLineEdit* e = _allEdits.first(); e ; e = _allEdits.next() )
+ {
+ e->setHighlightSyntax( on );
+ }
+}
+
+void HidingMsgEdit::setQuotes(bool on)
+{
+ for( MsgMultiLineEdit* e = _allEdits.first(); e ; e = _allEdits.next() )
+ {
+ e->setQuotes( on );
+ }
+}
+
+void HidingMsgEdit::setBgColor( const QColor& color)
+{
+ for( MsgMultiLineEdit* e = _allEdits.first(); e ; e = _allEdits.next() )
+ {
+ e->setBgColor( color );
+ }
+}
+
+void HidingMsgEdit::setHighlightColors(const QColor& quoteColor, const QColor& unquoteColor
+ , const QColor& cformatColor, const QColor& accelColor, const QColor& tagColor)
+{
+ for( MsgMultiLineEdit* e = _allEdits.first(); e ; e = _allEdits.next() )
+ {
+ e->setHighlightColors( quoteColor, unquoteColor, cformatColor,
+ accelColor, tagColor );
+ }
+}
+
+void HidingMsgEdit::setOverwriteMode( bool b )
+{
+ for( MsgMultiLineEdit* e = _allEdits.first(); e ; e = _allEdits.next() )
+ {
+ e->setOverwriteMode( b );
+ }
+}
+
+void HidingMsgEdit::setModified( bool b )
+{
+ for( MsgMultiLineEdit* e = _allEdits.first(); e ; e = _allEdits.next() )
+ {
+ e->setModified( b );
+ }
+}
+
+void HidingMsgEdit::setCleverEditing( bool on )
+{
+ for( MsgMultiLineEdit* e = _allEdits.first(); e ; e = _allEdits.next() )
+ {
+ e->setCleverEditing( on );
+ }
+}
+
+void HidingMsgEdit::setHighlightBg( bool on )
+{
+ for( MsgMultiLineEdit* e = _allEdits.first(); e ; e = _allEdits.next() )
+ {
+ e->setHighlightBg( on );
+ }
+}
+
+void HidingMsgEdit::setContextMenu( QPopupMenu *menu )
+{
+ for( MsgMultiLineEdit* e = _allEdits.first(); e ; e = _allEdits.next() )
+ {
+ e->setContextMenu( menu );
+ }
+}
+
+void HidingMsgEdit::setCurrentColor( const MsgMultiLineEdit::TextColor color)
+{
+ for( MsgMultiLineEdit* e = _allEdits.first(); e ; e = _allEdits.next() )
+ {
+ e->setCurrentColor( color );
+ }
+}
+
+bool HidingMsgEdit::hasFocus ()
+{
+ for( MsgMultiLineEdit* e = _allEdits.first(); e ; e = _allEdits.next() )
+ {
+ if( e->hasFocus() ) return true;
+ }
+
+ return _multipleEdit->hasFocus() || QWidgetStack::hasFocus();
+}
+
+void HidingMsgEdit::setDiffColors(const QColor& addColor, const QColor& delColor)
+{
+ for( MsgMultiLineEdit* e = _allEdits.first(); e ; e = _allEdits.next() )
+ {
+ e->setDiffColors( addColor, delColor );
+ }
+}
+
+void HidingMsgEdit::setDiffMode(bool on)
+{
+ for( MsgMultiLineEdit* e = _allEdits.first(); e ; e = _allEdits.next() )
+ {
+ e->setDiffMode( on );
+ }
+}
+
+void HidingMsgEdit::setDiffDisplayMode(bool underlineAdded, bool strikeOutDeleted)
+{
+ for( MsgMultiLineEdit* e = _allEdits.first(); e ; e = _allEdits.next() )
+ {
+ e->setDiffDisplayMode( underlineAdded, strikeOutDeleted );
+ }
+}
+
+void HidingMsgEdit::setFont(const QFont& font)
+{
+ for( MsgMultiLineEdit* e = _allEdits.first(); e ; e = _allEdits.next() )
+ {
+ e->setFont( font );
+ }
+}
+
+void HidingMsgEdit::setSpellChecker(KSpell* spell)
+{
+ for( MsgMultiLineEdit* e = _allEdits.first(); e ; e = _allEdits.next() )
+ {
+ e->setSpellChecker( spell );
+ }
+ _spell = spell;
+}
+
+void HidingMsgEdit::emitCursorPositionChanged(int line, int col )
+{
+ int linestart = 0;
+ int indexline = _currentEdit->lineOfChar( line, col );
+ if ( indexline > 0 )
+ {
+ int min = 0, max = col;
+ int i = (min + max)/2;
+ int iline = _currentEdit->lineOfChar( line, i );
+ while ( iline != indexline-1 ||
+ _currentEdit->lineOfChar( line, i+1 ) != indexline )
+ {
+ Q_ASSERT( min != max && min != i && max != i );
+ if ( iline < indexline )
+ min = i;
+ else
+ max = i;
+ i = (min + max)/2;
+ iline = _currentEdit->lineOfChar( line, i );
+ }
+ linestart = i+1;
+ }
+ Q_ASSERT( linestart >= 0 );
+
+ emit cursorPositionChanged(line + _currentEdit->lineOfChar( line, col ) ,col-linestart);
+}
+
+#include "hidingmsgedit.moc"
+
diff --git a/kbabel/kbabel/hidingmsgedit.h b/kbabel/kbabel/hidingmsgedit.h
new file mode 100644
index 00000000..38e5d750
--- /dev/null
+++ b/kbabel/kbabel/hidingmsgedit.h
@@ -0,0 +1,161 @@
+/***************************************************************************
+ hidingmsgedit.h - description
+ -------------------
+ begin : So nov 2 2002
+ copyright : (C) 2002 by Stanislav Visnovsky
+ email : visnovsky@kde.org
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+
+ In addition, as a special exception, the copyright holders give
+ permission to link the code of this program with any edition of
+ the Qt library by Trolltech AS, Norway (or with modified versions
+ of Qt that use the same license as Qt), and distribute linked
+ combinations including the two. You must obey the GNU General
+ Public License in all respects for all of the code used other than
+ Qt. If you modify this file, you may extend this exception to
+ your version of the file, but you are not obligated to do so. If
+ you do not wish to do so, delete this exception statement from
+ your version.
+
+ * *
+ ***************************************************************************/
+
+#ifndef HIDINGMSGEDIT_H
+#define HIDINGMSGEDIT_H
+
+#include <qwidgetstack.h>
+#include <qguardedptr.h>
+#include <qptrlist.h>
+
+#include "mymultilineedit.h"
+
+class KSpell;
+class QTabWidget;
+class QPopupMenu;
+
+namespace KBabel
+{
+ class EditCommand;
+}
+
+/**
+ *@author Stanislav Visnovsky <visnovsky@kde.org>
+ */
+
+class HidingMsgEdit : public QWidgetStack {
+ Q_OBJECT
+public:
+ HidingMsgEdit(uint numberOfPlurals, QWidget* eventFilter=0, KSpell* spell=0, QWidget *parent=0, const char *name=0);
+ ~HidingMsgEdit();
+
+ void setNumberOfPlurals(uint numberOfPlurals);
+
+ // return index number for a currently shown plural form (0=singular or no plurals)
+ uint currentForm();
+
+ // MsgMultiLineEdit interface
+ bool isOverwriteMode() const { return _currentEdit->isOverwriteMode(); }
+ bool isModified();
+ bool hasSelectedText() const { return _currentEdit->hasSelectedText(); }
+ QString selectedText () const { return _currentEdit->selectedText(); }
+ void processCommand(KBabel::EditCommand* cmd, bool undo=false);
+ void offset2Pos(int offset, int &row, int &col) const
+ { return _currentEdit->offset2Pos(offset, row, col ); }
+ void getCursorPosition(int *para, int *index) const
+ { _currentEdit->getCursorPosition(para,index); }
+ int currentIndex() const
+ { return _currentEdit->currentIndex(); }
+ int beginOfLastMarkedText() const
+ { return _currentEdit->beginOfLastMarkedText(); }
+ virtual void setFont ( const QFont & );
+ void setCurrentColor(const MsgMultiLineEdit::TextColor color);
+ bool spacePoints() const { return _currentEdit->spacePoints(); }
+ void setSpacePoints(bool on);
+ bool quotes() const { return _currentEdit->quotes(); }
+ void setQuotes(bool on);
+ void setBgColor( const QColor& color);
+ bool highlightBg() const { return _currentEdit->highlightBg(); }
+ bool highlightSyntax() const { return _currentEdit->highlightSyntax(); }
+ void setHighlightColors(const QColor& quoteColor, const QColor& unquoteColor
+ , const QColor& cformatColor, const QColor& accelColor, const QColor& tagColor);
+ int beginOfMarkedText() { return _currentEdit->beginOfMarkedText(); }
+ virtual void insertAt ( const QString & s, int line, int col, bool mark = false )
+ { _currentEdit->insertAt( s, line, col, mark ); }
+
+ void setDiffMode(bool on);
+ void setDiffDisplayMode(bool underlineAdded, bool strikeOutDeleted);
+ void setDiffColors(const QColor& addColor, const QColor& delColor);
+ QString text(int para) { return _currentEdit->text(para); }
+
+ void setSpellChecker(KSpell* spell);
+
+ void selectTag(int start, int length) { _currentEdit->selectTag(start,length); }
+
+ // reiplemented to return correct value
+ bool hasFocus ();
+public slots: // Public slots
+ void setText(QStringList texts, QString msgctxt = QString::null);
+ void showSingle();
+ void showMultiple();
+ void showPlurals( bool on );
+ void showForm(int form);
+ virtual void setFocus() { _currentEdit->setFocus(); }
+ void forceUpdate() { _currentEdit->forceUpdate(); }
+
+ // MsgMultiLineEdit interface
+ virtual void setReadOnly( bool b );
+ virtual void setOverwriteMode( bool b );
+ virtual void setModified( bool b );
+ void setCleverEditing( bool on );
+ void setHighlightBg( bool on );
+ void setHighlightSyntax( bool on );
+ virtual void clear() { _currentEdit->clear(); }
+ virtual void cut() { _currentEdit->cut(); }
+ virtual void copy() { _currentEdit->copy(); }
+ virtual void paste() { _currentEdit->paste(); }
+ virtual void setSelection( int paraFrom, int indexFrom, int paraTo, int indexTo, int selNum = 0 )
+ { _currentEdit->setSelection( paraFrom, indexFrom, paraTo, indexTo, selNum) ; }
+ virtual void selectAll(bool select=true) { _currentEdit->selectAll(select); }
+ virtual void setCursorPosition ( int para, int index )
+ { _currentEdit->setCursorPosition(para,index); }
+ virtual void setContextMenu( QPopupMenu *menu );
+
+signals:
+ void signalUndoCmd(KBabel::EditCommand*);
+ void textChanged();
+ void textChanged(const QString&);
+ void cursorPositionChanged ( int para, int pos );
+ void currentFormChanged ( uint form );
+
+private slots:
+
+ void emitTextChanged();
+
+ // invoked if TabWidget changes the shown widget
+ void newCurrentMultiple( QWidget * );
+ // invoked by inner cursorPositionChanged() to transform line/col for wrapping
+ void emitCursorPositionChanged( int para, int pos );
+
+private: // Private attributes
+ /** Used for editting non-plural messages */
+ MsgMultiLineEdit* _singleEdit;
+ /** Used for editting plural forms */
+ QTabWidget* _multipleEdit;
+ QWidget* _eventFilter;
+
+ MsgMultiLineEdit* _currentEdit;
+ QPtrList<MsgMultiLineEdit> _allEdits;
+
+ uint _numberOfPlurals;
+
+ QGuardedPtr<KSpell> _spell;
+};
+
+#endif
diff --git a/kbabel/kbabel/icons/Makefile.am b/kbabel/kbabel/icons/Makefile.am
new file mode 100644
index 00000000..07f64107
--- /dev/null
+++ b/kbabel/kbabel/icons/Makefile.am
@@ -0,0 +1,5 @@
+# Add all of your pixmaps here
+icons_ICON = msgid2msgstr nexterror nextfuzzy nextfuzzyuntrans nextuntranslated preverror prevfuzzy prevfuzzyuntrans prevuntranslated search2msgstr transsearch insert_tag diff autodiff togglefuzzy insert_arg spellcheck_all spellcheck_actual spellcheck_from_cursor spellcheck_selected catalogmanager
+
+# This is where it will all be installed
+iconsdir = $(kde_datadir)/kbabel/icons
diff --git a/kbabel/kbabel/icons/hi16-action-autodiff.png b/kbabel/kbabel/icons/hi16-action-autodiff.png
new file mode 100644
index 00000000..d79e471f
--- /dev/null
+++ b/kbabel/kbabel/icons/hi16-action-autodiff.png
Binary files differ
diff --git a/kbabel/kbabel/icons/hi16-action-catalogmanager.png b/kbabel/kbabel/icons/hi16-action-catalogmanager.png
new file mode 100644
index 00000000..369ab591
--- /dev/null
+++ b/kbabel/kbabel/icons/hi16-action-catalogmanager.png
Binary files differ
diff --git a/kbabel/kbabel/icons/hi16-action-diff.png b/kbabel/kbabel/icons/hi16-action-diff.png
new file mode 100644
index 00000000..9e13d750
--- /dev/null
+++ b/kbabel/kbabel/icons/hi16-action-diff.png
Binary files differ
diff --git a/kbabel/kbabel/icons/hi16-action-insert_arg.png b/kbabel/kbabel/icons/hi16-action-insert_arg.png
new file mode 100644
index 00000000..e133f0e4
--- /dev/null
+++ b/kbabel/kbabel/icons/hi16-action-insert_arg.png
Binary files differ
diff --git a/kbabel/kbabel/icons/hi16-action-insert_tag.png b/kbabel/kbabel/icons/hi16-action-insert_tag.png
new file mode 100644
index 00000000..e0757463
--- /dev/null
+++ b/kbabel/kbabel/icons/hi16-action-insert_tag.png
Binary files differ
diff --git a/kbabel/kbabel/icons/hi16-action-msgid2msgstr.png b/kbabel/kbabel/icons/hi16-action-msgid2msgstr.png
new file mode 100644
index 00000000..6f5534fa
--- /dev/null
+++ b/kbabel/kbabel/icons/hi16-action-msgid2msgstr.png
Binary files differ
diff --git a/kbabel/kbabel/icons/hi16-action-nexterror.png b/kbabel/kbabel/icons/hi16-action-nexterror.png
new file mode 100644
index 00000000..78876d16
--- /dev/null
+++ b/kbabel/kbabel/icons/hi16-action-nexterror.png
Binary files differ
diff --git a/kbabel/kbabel/icons/hi16-action-nextfuzzy.png b/kbabel/kbabel/icons/hi16-action-nextfuzzy.png
new file mode 100644
index 00000000..6bcc43ed
--- /dev/null
+++ b/kbabel/kbabel/icons/hi16-action-nextfuzzy.png
Binary files differ
diff --git a/kbabel/kbabel/icons/hi16-action-nextfuzzyuntrans.png b/kbabel/kbabel/icons/hi16-action-nextfuzzyuntrans.png
new file mode 100644
index 00000000..d17b402f
--- /dev/null
+++ b/kbabel/kbabel/icons/hi16-action-nextfuzzyuntrans.png
Binary files differ
diff --git a/kbabel/kbabel/icons/hi16-action-nextuntranslated.png b/kbabel/kbabel/icons/hi16-action-nextuntranslated.png
new file mode 100644
index 00000000..317bb595
--- /dev/null
+++ b/kbabel/kbabel/icons/hi16-action-nextuntranslated.png
Binary files differ
diff --git a/kbabel/kbabel/icons/hi16-action-preverror.png b/kbabel/kbabel/icons/hi16-action-preverror.png
new file mode 100644
index 00000000..630da7d7
--- /dev/null
+++ b/kbabel/kbabel/icons/hi16-action-preverror.png
Binary files differ
diff --git a/kbabel/kbabel/icons/hi16-action-prevfuzzy.png b/kbabel/kbabel/icons/hi16-action-prevfuzzy.png
new file mode 100644
index 00000000..a381d93e
--- /dev/null
+++ b/kbabel/kbabel/icons/hi16-action-prevfuzzy.png
Binary files differ
diff --git a/kbabel/kbabel/icons/hi16-action-prevfuzzyuntrans.png b/kbabel/kbabel/icons/hi16-action-prevfuzzyuntrans.png
new file mode 100644
index 00000000..64995893
--- /dev/null
+++ b/kbabel/kbabel/icons/hi16-action-prevfuzzyuntrans.png
Binary files differ
diff --git a/kbabel/kbabel/icons/hi16-action-prevuntranslated.png b/kbabel/kbabel/icons/hi16-action-prevuntranslated.png
new file mode 100644
index 00000000..49610f03
--- /dev/null
+++ b/kbabel/kbabel/icons/hi16-action-prevuntranslated.png
Binary files differ
diff --git a/kbabel/kbabel/icons/hi16-action-search2msgstr.png b/kbabel/kbabel/icons/hi16-action-search2msgstr.png
new file mode 100644
index 00000000..99986bba
--- /dev/null
+++ b/kbabel/kbabel/icons/hi16-action-search2msgstr.png
Binary files differ
diff --git a/kbabel/kbabel/icons/hi16-action-spellcheck_actual.png b/kbabel/kbabel/icons/hi16-action-spellcheck_actual.png
new file mode 100644
index 00000000..1a653f5e
--- /dev/null
+++ b/kbabel/kbabel/icons/hi16-action-spellcheck_actual.png
Binary files differ
diff --git a/kbabel/kbabel/icons/hi16-action-spellcheck_all.png b/kbabel/kbabel/icons/hi16-action-spellcheck_all.png
new file mode 100644
index 00000000..c0b622d2
--- /dev/null
+++ b/kbabel/kbabel/icons/hi16-action-spellcheck_all.png
Binary files differ
diff --git a/kbabel/kbabel/icons/hi16-action-spellcheck_from_cursor.png b/kbabel/kbabel/icons/hi16-action-spellcheck_from_cursor.png
new file mode 100644
index 00000000..0bbd0a61
--- /dev/null
+++ b/kbabel/kbabel/icons/hi16-action-spellcheck_from_cursor.png
Binary files differ
diff --git a/kbabel/kbabel/icons/hi16-action-spellcheck_selected.png b/kbabel/kbabel/icons/hi16-action-spellcheck_selected.png
new file mode 100644
index 00000000..feacd83d
--- /dev/null
+++ b/kbabel/kbabel/icons/hi16-action-spellcheck_selected.png
Binary files differ
diff --git a/kbabel/kbabel/icons/hi16-action-togglefuzzy.png b/kbabel/kbabel/icons/hi16-action-togglefuzzy.png
new file mode 100644
index 00000000..3538fde6
--- /dev/null
+++ b/kbabel/kbabel/icons/hi16-action-togglefuzzy.png
Binary files differ
diff --git a/kbabel/kbabel/icons/hi16-action-transsearch.png b/kbabel/kbabel/icons/hi16-action-transsearch.png
new file mode 100644
index 00000000..e1776a6e
--- /dev/null
+++ b/kbabel/kbabel/icons/hi16-action-transsearch.png
Binary files differ
diff --git a/kbabel/kbabel/icons/hi22-action-autodiff.png b/kbabel/kbabel/icons/hi22-action-autodiff.png
new file mode 100644
index 00000000..91988ede
--- /dev/null
+++ b/kbabel/kbabel/icons/hi22-action-autodiff.png
Binary files differ
diff --git a/kbabel/kbabel/icons/hi22-action-catalogmanager.png b/kbabel/kbabel/icons/hi22-action-catalogmanager.png
new file mode 100644
index 00000000..48bbade3
--- /dev/null
+++ b/kbabel/kbabel/icons/hi22-action-catalogmanager.png
Binary files differ
diff --git a/kbabel/kbabel/icons/hi22-action-diff.png b/kbabel/kbabel/icons/hi22-action-diff.png
new file mode 100644
index 00000000..321ed59e
--- /dev/null
+++ b/kbabel/kbabel/icons/hi22-action-diff.png
Binary files differ
diff --git a/kbabel/kbabel/icons/hi22-action-insert_arg.png b/kbabel/kbabel/icons/hi22-action-insert_arg.png
new file mode 100644
index 00000000..6aa1da61
--- /dev/null
+++ b/kbabel/kbabel/icons/hi22-action-insert_arg.png
Binary files differ
diff --git a/kbabel/kbabel/icons/hi22-action-insert_tag.png b/kbabel/kbabel/icons/hi22-action-insert_tag.png
new file mode 100644
index 00000000..cbd50021
--- /dev/null
+++ b/kbabel/kbabel/icons/hi22-action-insert_tag.png
Binary files differ
diff --git a/kbabel/kbabel/icons/hi22-action-msgid2msgstr.png b/kbabel/kbabel/icons/hi22-action-msgid2msgstr.png
new file mode 100644
index 00000000..3323ada2
--- /dev/null
+++ b/kbabel/kbabel/icons/hi22-action-msgid2msgstr.png
Binary files differ
diff --git a/kbabel/kbabel/icons/hi22-action-nexterror.png b/kbabel/kbabel/icons/hi22-action-nexterror.png
new file mode 100644
index 00000000..24a94589
--- /dev/null
+++ b/kbabel/kbabel/icons/hi22-action-nexterror.png
Binary files differ
diff --git a/kbabel/kbabel/icons/hi22-action-nextfuzzy.png b/kbabel/kbabel/icons/hi22-action-nextfuzzy.png
new file mode 100644
index 00000000..2e302679
--- /dev/null
+++ b/kbabel/kbabel/icons/hi22-action-nextfuzzy.png
Binary files differ
diff --git a/kbabel/kbabel/icons/hi22-action-nextfuzzyuntrans.png b/kbabel/kbabel/icons/hi22-action-nextfuzzyuntrans.png
new file mode 100644
index 00000000..47a3c36a
--- /dev/null
+++ b/kbabel/kbabel/icons/hi22-action-nextfuzzyuntrans.png
Binary files differ
diff --git a/kbabel/kbabel/icons/hi22-action-nextuntranslated.png b/kbabel/kbabel/icons/hi22-action-nextuntranslated.png
new file mode 100644
index 00000000..eb4ea46c
--- /dev/null
+++ b/kbabel/kbabel/icons/hi22-action-nextuntranslated.png
Binary files differ
diff --git a/kbabel/kbabel/icons/hi22-action-preverror.png b/kbabel/kbabel/icons/hi22-action-preverror.png
new file mode 100644
index 00000000..089e5a12
--- /dev/null
+++ b/kbabel/kbabel/icons/hi22-action-preverror.png
Binary files differ
diff --git a/kbabel/kbabel/icons/hi22-action-prevfuzzy.png b/kbabel/kbabel/icons/hi22-action-prevfuzzy.png
new file mode 100644
index 00000000..aec1f219
--- /dev/null
+++ b/kbabel/kbabel/icons/hi22-action-prevfuzzy.png
Binary files differ
diff --git a/kbabel/kbabel/icons/hi22-action-prevfuzzyuntrans.png b/kbabel/kbabel/icons/hi22-action-prevfuzzyuntrans.png
new file mode 100644
index 00000000..4e7c88d4
--- /dev/null
+++ b/kbabel/kbabel/icons/hi22-action-prevfuzzyuntrans.png
Binary files differ
diff --git a/kbabel/kbabel/icons/hi22-action-prevuntranslated.png b/kbabel/kbabel/icons/hi22-action-prevuntranslated.png
new file mode 100644
index 00000000..8f5c764f
--- /dev/null
+++ b/kbabel/kbabel/icons/hi22-action-prevuntranslated.png
Binary files differ
diff --git a/kbabel/kbabel/icons/hi22-action-search2msgstr.png b/kbabel/kbabel/icons/hi22-action-search2msgstr.png
new file mode 100644
index 00000000..9df8dfca
--- /dev/null
+++ b/kbabel/kbabel/icons/hi22-action-search2msgstr.png
Binary files differ
diff --git a/kbabel/kbabel/icons/hi22-action-togglefuzzy.png b/kbabel/kbabel/icons/hi22-action-togglefuzzy.png
new file mode 100644
index 00000000..40227189
--- /dev/null
+++ b/kbabel/kbabel/icons/hi22-action-togglefuzzy.png
Binary files differ
diff --git a/kbabel/kbabel/icons/hi22-action-transsearch.png b/kbabel/kbabel/icons/hi22-action-transsearch.png
new file mode 100644
index 00000000..06d5852c
--- /dev/null
+++ b/kbabel/kbabel/icons/hi22-action-transsearch.png
Binary files differ
diff --git a/kbabel/kbabel/icons/hi32-action-autodiff.png b/kbabel/kbabel/icons/hi32-action-autodiff.png
new file mode 100644
index 00000000..471ece08
--- /dev/null
+++ b/kbabel/kbabel/icons/hi32-action-autodiff.png
Binary files differ
diff --git a/kbabel/kbabel/icons/hi32-action-catalogmanager.png b/kbabel/kbabel/icons/hi32-action-catalogmanager.png
new file mode 100644
index 00000000..d527b872
--- /dev/null
+++ b/kbabel/kbabel/icons/hi32-action-catalogmanager.png
Binary files differ
diff --git a/kbabel/kbabel/icons/hi32-action-diff.png b/kbabel/kbabel/icons/hi32-action-diff.png
new file mode 100644
index 00000000..535d508a
--- /dev/null
+++ b/kbabel/kbabel/icons/hi32-action-diff.png
Binary files differ
diff --git a/kbabel/kbabel/icons/hi32-action-insert_arg.png b/kbabel/kbabel/icons/hi32-action-insert_arg.png
new file mode 100644
index 00000000..ea8c8179
--- /dev/null
+++ b/kbabel/kbabel/icons/hi32-action-insert_arg.png
Binary files differ
diff --git a/kbabel/kbabel/icons/hi32-action-insert_tag.png b/kbabel/kbabel/icons/hi32-action-insert_tag.png
new file mode 100644
index 00000000..d11981ef
--- /dev/null
+++ b/kbabel/kbabel/icons/hi32-action-insert_tag.png
Binary files differ
diff --git a/kbabel/kbabel/icons/hi32-action-msgid2msgstr.png b/kbabel/kbabel/icons/hi32-action-msgid2msgstr.png
new file mode 100644
index 00000000..8dc03384
--- /dev/null
+++ b/kbabel/kbabel/icons/hi32-action-msgid2msgstr.png
Binary files differ
diff --git a/kbabel/kbabel/icons/hi32-action-nexterror.png b/kbabel/kbabel/icons/hi32-action-nexterror.png
new file mode 100644
index 00000000..ee458abc
--- /dev/null
+++ b/kbabel/kbabel/icons/hi32-action-nexterror.png
Binary files differ
diff --git a/kbabel/kbabel/icons/hi32-action-nextfuzzy.png b/kbabel/kbabel/icons/hi32-action-nextfuzzy.png
new file mode 100644
index 00000000..089e6357
--- /dev/null
+++ b/kbabel/kbabel/icons/hi32-action-nextfuzzy.png
Binary files differ
diff --git a/kbabel/kbabel/icons/hi32-action-nextfuzzyuntrans.png b/kbabel/kbabel/icons/hi32-action-nextfuzzyuntrans.png
new file mode 100644
index 00000000..82f535e6
--- /dev/null
+++ b/kbabel/kbabel/icons/hi32-action-nextfuzzyuntrans.png
Binary files differ
diff --git a/kbabel/kbabel/icons/hi32-action-nextuntranslated.png b/kbabel/kbabel/icons/hi32-action-nextuntranslated.png
new file mode 100644
index 00000000..8b9db6f7
--- /dev/null
+++ b/kbabel/kbabel/icons/hi32-action-nextuntranslated.png
Binary files differ
diff --git a/kbabel/kbabel/icons/hi32-action-preverror.png b/kbabel/kbabel/icons/hi32-action-preverror.png
new file mode 100644
index 00000000..7ff8da13
--- /dev/null
+++ b/kbabel/kbabel/icons/hi32-action-preverror.png
Binary files differ
diff --git a/kbabel/kbabel/icons/hi32-action-prevfuzzy.png b/kbabel/kbabel/icons/hi32-action-prevfuzzy.png
new file mode 100644
index 00000000..0280c02f
--- /dev/null
+++ b/kbabel/kbabel/icons/hi32-action-prevfuzzy.png
Binary files differ
diff --git a/kbabel/kbabel/icons/hi32-action-prevfuzzyuntrans.png b/kbabel/kbabel/icons/hi32-action-prevfuzzyuntrans.png
new file mode 100644
index 00000000..bcfb55aa
--- /dev/null
+++ b/kbabel/kbabel/icons/hi32-action-prevfuzzyuntrans.png
Binary files differ
diff --git a/kbabel/kbabel/icons/hi32-action-prevuntranslated.png b/kbabel/kbabel/icons/hi32-action-prevuntranslated.png
new file mode 100644
index 00000000..e4bdb694
--- /dev/null
+++ b/kbabel/kbabel/icons/hi32-action-prevuntranslated.png
Binary files differ
diff --git a/kbabel/kbabel/icons/hi32-action-search2msgstr.png b/kbabel/kbabel/icons/hi32-action-search2msgstr.png
new file mode 100644
index 00000000..3337b646
--- /dev/null
+++ b/kbabel/kbabel/icons/hi32-action-search2msgstr.png
Binary files differ
diff --git a/kbabel/kbabel/icons/hi32-action-togglefuzzy.png b/kbabel/kbabel/icons/hi32-action-togglefuzzy.png
new file mode 100644
index 00000000..0a9492a0
--- /dev/null
+++ b/kbabel/kbabel/icons/hi32-action-togglefuzzy.png
Binary files differ
diff --git a/kbabel/kbabel/icons/hi32-action-transsearch.png b/kbabel/kbabel/icons/hi32-action-transsearch.png
new file mode 100644
index 00000000..19e766c5
--- /dev/null
+++ b/kbabel/kbabel/icons/hi32-action-transsearch.png
Binary files differ
diff --git a/kbabel/kbabel/icons/lo16-action-autodiff.png b/kbabel/kbabel/icons/lo16-action-autodiff.png
new file mode 100644
index 00000000..7cb56260
--- /dev/null
+++ b/kbabel/kbabel/icons/lo16-action-autodiff.png
Binary files differ
diff --git a/kbabel/kbabel/icons/lo16-action-catalogmanager.png b/kbabel/kbabel/icons/lo16-action-catalogmanager.png
new file mode 100644
index 00000000..75a95c0c
--- /dev/null
+++ b/kbabel/kbabel/icons/lo16-action-catalogmanager.png
Binary files differ
diff --git a/kbabel/kbabel/icons/lo16-action-diff.png b/kbabel/kbabel/icons/lo16-action-diff.png
new file mode 100644
index 00000000..05b82b53
--- /dev/null
+++ b/kbabel/kbabel/icons/lo16-action-diff.png
Binary files differ
diff --git a/kbabel/kbabel/icons/lo16-action-insert_arg.png b/kbabel/kbabel/icons/lo16-action-insert_arg.png
new file mode 100644
index 00000000..bc67bc15
--- /dev/null
+++ b/kbabel/kbabel/icons/lo16-action-insert_arg.png
Binary files differ
diff --git a/kbabel/kbabel/icons/lo16-action-insert_tag.png b/kbabel/kbabel/icons/lo16-action-insert_tag.png
new file mode 100644
index 00000000..283b0793
--- /dev/null
+++ b/kbabel/kbabel/icons/lo16-action-insert_tag.png
Binary files differ
diff --git a/kbabel/kbabel/icons/lo16-action-msgid2msgstr.png b/kbabel/kbabel/icons/lo16-action-msgid2msgstr.png
new file mode 100644
index 00000000..8cb33ccb
--- /dev/null
+++ b/kbabel/kbabel/icons/lo16-action-msgid2msgstr.png
Binary files differ
diff --git a/kbabel/kbabel/icons/lo16-action-nexterror.png b/kbabel/kbabel/icons/lo16-action-nexterror.png
new file mode 100644
index 00000000..a2d48527
--- /dev/null
+++ b/kbabel/kbabel/icons/lo16-action-nexterror.png
Binary files differ
diff --git a/kbabel/kbabel/icons/lo16-action-nextfuzzy.png b/kbabel/kbabel/icons/lo16-action-nextfuzzy.png
new file mode 100644
index 00000000..828bfc3b
--- /dev/null
+++ b/kbabel/kbabel/icons/lo16-action-nextfuzzy.png
Binary files differ
diff --git a/kbabel/kbabel/icons/lo16-action-nextfuzzyuntrans.png b/kbabel/kbabel/icons/lo16-action-nextfuzzyuntrans.png
new file mode 100644
index 00000000..ad150c58
--- /dev/null
+++ b/kbabel/kbabel/icons/lo16-action-nextfuzzyuntrans.png
Binary files differ
diff --git a/kbabel/kbabel/icons/lo16-action-nextuntranslated.png b/kbabel/kbabel/icons/lo16-action-nextuntranslated.png
new file mode 100644
index 00000000..bbcda8c3
--- /dev/null
+++ b/kbabel/kbabel/icons/lo16-action-nextuntranslated.png
Binary files differ
diff --git a/kbabel/kbabel/icons/lo16-action-preverror.png b/kbabel/kbabel/icons/lo16-action-preverror.png
new file mode 100644
index 00000000..10c2f7e5
--- /dev/null
+++ b/kbabel/kbabel/icons/lo16-action-preverror.png
Binary files differ
diff --git a/kbabel/kbabel/icons/lo16-action-prevfuzzy.png b/kbabel/kbabel/icons/lo16-action-prevfuzzy.png
new file mode 100644
index 00000000..a19cb6ac
--- /dev/null
+++ b/kbabel/kbabel/icons/lo16-action-prevfuzzy.png
Binary files differ
diff --git a/kbabel/kbabel/icons/lo16-action-prevfuzzyuntrans.png b/kbabel/kbabel/icons/lo16-action-prevfuzzyuntrans.png
new file mode 100644
index 00000000..f63b3598
--- /dev/null
+++ b/kbabel/kbabel/icons/lo16-action-prevfuzzyuntrans.png
Binary files differ
diff --git a/kbabel/kbabel/icons/lo16-action-prevuntranslated.png b/kbabel/kbabel/icons/lo16-action-prevuntranslated.png
new file mode 100644
index 00000000..a3ad3431
--- /dev/null
+++ b/kbabel/kbabel/icons/lo16-action-prevuntranslated.png
Binary files differ
diff --git a/kbabel/kbabel/icons/lo16-action-search2msgstr.png b/kbabel/kbabel/icons/lo16-action-search2msgstr.png
new file mode 100644
index 00000000..36d25867
--- /dev/null
+++ b/kbabel/kbabel/icons/lo16-action-search2msgstr.png
Binary files differ
diff --git a/kbabel/kbabel/icons/lo16-action-spellcheck_actual.png b/kbabel/kbabel/icons/lo16-action-spellcheck_actual.png
new file mode 100644
index 00000000..1a653f5e
--- /dev/null
+++ b/kbabel/kbabel/icons/lo16-action-spellcheck_actual.png
Binary files differ
diff --git a/kbabel/kbabel/icons/lo16-action-spellcheck_all.png b/kbabel/kbabel/icons/lo16-action-spellcheck_all.png
new file mode 100644
index 00000000..c0b622d2
--- /dev/null
+++ b/kbabel/kbabel/icons/lo16-action-spellcheck_all.png
Binary files differ
diff --git a/kbabel/kbabel/icons/lo16-action-spellcheck_from_cursor.png b/kbabel/kbabel/icons/lo16-action-spellcheck_from_cursor.png
new file mode 100644
index 00000000..0bbd0a61
--- /dev/null
+++ b/kbabel/kbabel/icons/lo16-action-spellcheck_from_cursor.png
Binary files differ
diff --git a/kbabel/kbabel/icons/lo16-action-spellcheck_selected.png b/kbabel/kbabel/icons/lo16-action-spellcheck_selected.png
new file mode 100644
index 00000000..feacd83d
--- /dev/null
+++ b/kbabel/kbabel/icons/lo16-action-spellcheck_selected.png
Binary files differ
diff --git a/kbabel/kbabel/icons/lo16-action-togglefuzzy.png b/kbabel/kbabel/icons/lo16-action-togglefuzzy.png
new file mode 100644
index 00000000..3538fde6
--- /dev/null
+++ b/kbabel/kbabel/icons/lo16-action-togglefuzzy.png
Binary files differ
diff --git a/kbabel/kbabel/icons/lo16-action-transsearch.png b/kbabel/kbabel/icons/lo16-action-transsearch.png
new file mode 100644
index 00000000..f933a6eb
--- /dev/null
+++ b/kbabel/kbabel/icons/lo16-action-transsearch.png
Binary files differ
diff --git a/kbabel/kbabel/icons/lo32-action-autodiff.png b/kbabel/kbabel/icons/lo32-action-autodiff.png
new file mode 100644
index 00000000..b6cb074a
--- /dev/null
+++ b/kbabel/kbabel/icons/lo32-action-autodiff.png
Binary files differ
diff --git a/kbabel/kbabel/icons/lo32-action-catalogmanager.png b/kbabel/kbabel/icons/lo32-action-catalogmanager.png
new file mode 100644
index 00000000..1e9da58f
--- /dev/null
+++ b/kbabel/kbabel/icons/lo32-action-catalogmanager.png
Binary files differ
diff --git a/kbabel/kbabel/icons/lo32-action-diff.png b/kbabel/kbabel/icons/lo32-action-diff.png
new file mode 100644
index 00000000..8be1d0a4
--- /dev/null
+++ b/kbabel/kbabel/icons/lo32-action-diff.png
Binary files differ
diff --git a/kbabel/kbabel/icons/lo32-action-insert_arg.png b/kbabel/kbabel/icons/lo32-action-insert_arg.png
new file mode 100644
index 00000000..39fcf1fd
--- /dev/null
+++ b/kbabel/kbabel/icons/lo32-action-insert_arg.png
Binary files differ
diff --git a/kbabel/kbabel/icons/lo32-action-insert_tag.png b/kbabel/kbabel/icons/lo32-action-insert_tag.png
new file mode 100644
index 00000000..820bc66f
--- /dev/null
+++ b/kbabel/kbabel/icons/lo32-action-insert_tag.png
Binary files differ
diff --git a/kbabel/kbabel/icons/lo32-action-msgid2msgstr.png b/kbabel/kbabel/icons/lo32-action-msgid2msgstr.png
new file mode 100644
index 00000000..7497c265
--- /dev/null
+++ b/kbabel/kbabel/icons/lo32-action-msgid2msgstr.png
Binary files differ
diff --git a/kbabel/kbabel/icons/lo32-action-nexterror.png b/kbabel/kbabel/icons/lo32-action-nexterror.png
new file mode 100644
index 00000000..de06b7e8
--- /dev/null
+++ b/kbabel/kbabel/icons/lo32-action-nexterror.png
Binary files differ
diff --git a/kbabel/kbabel/icons/lo32-action-nextfuzzy.png b/kbabel/kbabel/icons/lo32-action-nextfuzzy.png
new file mode 100644
index 00000000..9218c291
--- /dev/null
+++ b/kbabel/kbabel/icons/lo32-action-nextfuzzy.png
Binary files differ
diff --git a/kbabel/kbabel/icons/lo32-action-nextfuzzyuntrans.png b/kbabel/kbabel/icons/lo32-action-nextfuzzyuntrans.png
new file mode 100644
index 00000000..6efbd5a7
--- /dev/null
+++ b/kbabel/kbabel/icons/lo32-action-nextfuzzyuntrans.png
Binary files differ
diff --git a/kbabel/kbabel/icons/lo32-action-nextuntranslated.png b/kbabel/kbabel/icons/lo32-action-nextuntranslated.png
new file mode 100644
index 00000000..c6954974
--- /dev/null
+++ b/kbabel/kbabel/icons/lo32-action-nextuntranslated.png
Binary files differ
diff --git a/kbabel/kbabel/icons/lo32-action-preverror.png b/kbabel/kbabel/icons/lo32-action-preverror.png
new file mode 100644
index 00000000..c8196a3e
--- /dev/null
+++ b/kbabel/kbabel/icons/lo32-action-preverror.png
Binary files differ
diff --git a/kbabel/kbabel/icons/lo32-action-prevfuzzy.png b/kbabel/kbabel/icons/lo32-action-prevfuzzy.png
new file mode 100644
index 00000000..4a078602
--- /dev/null
+++ b/kbabel/kbabel/icons/lo32-action-prevfuzzy.png
Binary files differ
diff --git a/kbabel/kbabel/icons/lo32-action-prevfuzzyuntrans.png b/kbabel/kbabel/icons/lo32-action-prevfuzzyuntrans.png
new file mode 100644
index 00000000..902c84cb
--- /dev/null
+++ b/kbabel/kbabel/icons/lo32-action-prevfuzzyuntrans.png
Binary files differ
diff --git a/kbabel/kbabel/icons/lo32-action-prevuntranslated.png b/kbabel/kbabel/icons/lo32-action-prevuntranslated.png
new file mode 100644
index 00000000..32ea00c4
--- /dev/null
+++ b/kbabel/kbabel/icons/lo32-action-prevuntranslated.png
Binary files differ
diff --git a/kbabel/kbabel/icons/lo32-action-search2msgstr.png b/kbabel/kbabel/icons/lo32-action-search2msgstr.png
new file mode 100644
index 00000000..b2a83b66
--- /dev/null
+++ b/kbabel/kbabel/icons/lo32-action-search2msgstr.png
Binary files differ
diff --git a/kbabel/kbabel/icons/lo32-action-togglefuzzy.png b/kbabel/kbabel/icons/lo32-action-togglefuzzy.png
new file mode 100644
index 00000000..0a9492a0
--- /dev/null
+++ b/kbabel/kbabel/icons/lo32-action-togglefuzzy.png
Binary files differ
diff --git a/kbabel/kbabel/icons/lo32-action-transsearch.png b/kbabel/kbabel/icons/lo32-action-transsearch.png
new file mode 100644
index 00000000..e91eedcc
--- /dev/null
+++ b/kbabel/kbabel/icons/lo32-action-transsearch.png
Binary files differ
diff --git a/kbabel/kbabel/kbabel-difftoproject.upd b/kbabel/kbabel/kbabel-difftoproject.upd
new file mode 100644
index 00000000..183f6268
--- /dev/null
+++ b/kbabel/kbabel/kbabel-difftoproject.upd
@@ -0,0 +1,6 @@
+Id=kde34
+File=kbabelrc,kbabel.defaultproject
+Group=Editor,Misc
+Key=DiffBaseDir
+Key=UseDBForDiff
+#eof
diff --git a/kbabel/kbabel/kbabel-project.upd b/kbabel/kbabel/kbabel-project.upd
new file mode 100644
index 00000000..20fcb958
--- /dev/null
+++ b/kbabel/kbabel/kbabel-project.upd
@@ -0,0 +1,11 @@
+Id=kde33
+File=kbabelrc,kbabel.defaultproject
+Group=CatalogManager
+AllKeys
+Group=Header
+AllKeys
+Group=Misc
+AllKeys
+Group=SourceContext
+AllKeys
+#eof
diff --git a/kbabel/kbabel/kbabel.cpp b/kbabel/kbabel/kbabel.cpp
new file mode 100644
index 00000000..cae7bf77
--- /dev/null
+++ b/kbabel/kbabel/kbabel.cpp
@@ -0,0 +1,1825 @@
+/* ****************************************************************************
+ This file is part of KBabel
+
+ Copyright (C) 1999-2000 by Matthias Kiefer
+ <matthias.kiefer@gmx.de>
+ 2002-2004 by Stanislav Visnovsky
+ <visnovsky@kde.org>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the 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, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+ In addition, as a special exception, the copyright holders give
+ permission to link the code of this program with any edition of
+ the Qt library by Trolltech AS, Norway (or with modified versions
+ of Qt that use the same license as Qt), and distribute linked
+ combinations including the two. You must obey the GNU General
+ Public License in all respects for all of the code used other than
+ Qt. If you modify this file, you may extend this exception to
+ your version of the file, but you are not obligated to do so. If
+ you do not wish to do so, delete this exception statement from
+ your version.
+
+**************************************************************************** */
+
+#include "kbabel.h"
+
+#include "kbabelsettings.h"
+#include "kbprojectsettings.h"
+#include "kbabelpref.h"
+#include "projectpref.h"
+#include "kbabelsplash.h"
+#include "regexpextractor.h"
+#include "toolaction.h"
+#include "commentview.h"
+#include "contextview.h"
+#include "charselectview.h"
+#include "taglistview.h"
+#include "sourceview.h"
+
+#include <qdragobject.h>
+#include <qlineedit.h>
+#include <qpopupmenu.h>
+#include <qhbox.h>
+#include <qwhatsthis.h>
+#include <qsize.h>
+#include <qtextcodec.h>
+#include <qtooltip.h>
+#include <qtimer.h>
+
+#include <dcopclient.h>
+#include <kdatatool.h>
+#include <kpopupmenu.h>
+#include <kstatusbar.h>
+#include <kstdaccel.h>
+#include <kedittoolbar.h>
+#include <kglobal.h>
+#include <kled.h>
+#include <klocale.h>
+#include <kiconloader.h>
+#include <ktoolbar.h>
+#include <kfiledialog.h>
+#include <kconfig.h>
+#include <kurl.h>
+#include <kdialogbase.h>
+#include <kprogress.h>
+#include <kpushbutton.h>
+#include <kmessagebox.h>
+#include <kwin.h>
+#include <kaction.h>
+#include <kstdaction.h>
+#include <kspelldlg.h>
+#include <ksqueezedtextlabel.h>
+#include <kurldrag.h>
+
+#include "resources.h"
+#include "kbcatalog.h"
+#include "dictionarymenu.h"
+#include "kbabeldictbox.h"
+#include "kbmailer.h"
+#include "kbbookmarkhandler.h"
+#include "kbprojectmanager.h"
+#include "projectpref.h"
+#include "projectwizard.h"
+
+#include "version.h"
+
+#define ID_STATUS_TOTAL 1
+#define ID_STATUS_CURRENT 2
+#define ID_STATUS_FUZZY 3
+#define ID_STATUS_UNTRANS 4
+#define ID_STATUS_EDITMODE 5
+#define ID_STATUS_READONLY 6
+#define ID_STATUS_CURSOR 7
+
+// maximum number of recent files
+#define MAX_RECENT 10
+
+using namespace KBabel;
+
+QPtrList<KBabelPreferences> KBabelMW::prefDialogs;
+
+class MyKProgress: public KProgress
+{
+public:
+ MyKProgress( QWidget *parent, const char *name ) : KProgress( parent, name )
+ {
+ setSizePolicy( QSizePolicy::Minimum, QSizePolicy::Preferred );
+ }
+ QSize sizeHint() const { return QSize( 1, 1);}
+};
+
+KBabelMW::KBabelMW(QString projectFile)
+ : KDockMainWindow (), m_charselectorview(0)
+{
+ if ( projectFile.isEmpty() )
+ projectFile = KBabel::ProjectManager::defaultProjectName();
+ _project = ProjectManager::open(projectFile);
+
+ if ( _project == NULL ) // FIXME should not happen anymore
+ {
+ KMessageBox::error( this, i18n("Cannot open project file\n%1").arg(projectFile)
+ , i18n("Project File Error"));
+ _project = ProjectManager::open(KBabel::ProjectManager::defaultProjectName());
+ }
+
+ KBCatalog* catalog=new KBCatalog(projectFile);
+ init(catalog);
+}
+
+KBabelMW::KBabelMW(KBCatalog* catalog, QString projectFile)
+ : KDockMainWindow (), m_charselectorview(0)
+{
+ if ( projectFile.isEmpty() )
+ projectFile = KBabel::ProjectManager::defaultProjectName();
+ _project = ProjectManager::open(projectFile);
+
+ if ( _project == NULL )
+ {
+ KMessageBox::error( this, i18n("Cannot open project file\n%1").arg(projectFile)
+ , i18n("Project File Error"));
+ _project = ProjectManager::open(KBabel::ProjectManager::defaultProjectName());
+ }
+
+ init(catalog);
+}
+
+void KBabelMW::init(KBCatalog* catalog)
+{
+ _config = KSharedConfig::openConfig( "kbabelrc" );
+
+ _toolsShortcuts.clear();
+
+ _fuzzyLed=0;
+ _untransLed=0;
+ _errorLed=0;
+
+ _projectDialog=0;
+
+ _prefDialog=0;
+ prefDialogs.setAutoDelete(true);
+
+ _statusbarTimer = new QTimer(this, "statusbartimer");
+ connect(_statusbarTimer,SIGNAL(timeout()),this
+ ,SLOT(clearStatusbarMsg()));
+
+ // FIXME:
+ Q_ASSERT(_project);
+
+ m_view=new KBabelView(catalog,this, _project);
+
+ setXMLFile ("kbabelui.rc");
+
+ createGUI (0);
+
+ // accept dnd
+ setAcceptDrops(true);
+
+
+ // setup our menubars and toolbars
+ setupStatusBar();
+ setupActions();
+ stateChanged( "fileopened" , StateReverse );
+ stateChanged( "readonly", StateNoReverse );
+
+ QPopupMenu* popup;
+ popup = (QPopupMenu*)(factory()->container("rmb_edit", this));
+ if(popup)
+ {
+ m_view->setRMBEditMenu(popup);
+ }
+ popup = (QPopupMenu*)(factory()->container("rmb_search", this));
+ if(popup)
+ {
+ m_view->setRMBSearchMenu(popup);
+ }
+
+
+ connect(catalog,SIGNAL(signalUndoAvailable(bool)),this
+ ,SLOT(enableUndo(bool)));
+ connect(catalog,SIGNAL(signalRedoAvailable(bool)),this
+ ,SLOT(enableRedo(bool)));
+ connect(catalog,SIGNAL(signalNumberOfFuzziesChanged(uint)),this
+ ,SLOT(setNumberOfFuzzies(uint)));
+ connect(catalog,SIGNAL(signalNumberOfUntranslatedChanged(uint)),this
+ ,SLOT(setNumberOfUntranslated(uint)));
+ connect(catalog,SIGNAL(signalTotalNumberChanged(uint)),this
+ ,SLOT(setNumberOfTotal(uint)));
+ connect(catalog,SIGNAL(signalProgress(int)),_progressBar,SLOT(setProgress(int)));
+ connect(catalog,SIGNAL(signalClearProgressBar()),this,SLOT(clearProgressBar()));
+ connect(catalog,SIGNAL(signalResetProgressBar(QString,int))
+ ,this,SLOT(prepareProgressBar(QString,int)));
+ connect(catalog,SIGNAL(signalFileOpened(bool)),this,SLOT(enableDefaults(bool)));
+ connect(catalog,SIGNAL(signalFileOpened(bool)),m_view,SLOT(newFileOpened(bool)));
+ connect(catalog,SIGNAL(signalModified(bool)),this,SLOT(showModified(bool)));
+
+ // allow the view to change the statusbar and caption
+ connect(m_view, SIGNAL(signalChangeStatusbar(const QString&)),
+ this, SLOT(changeStatusbar(const QString&)));
+ connect(m_view, SIGNAL(signalChangeCaption(const QString&)),
+ this, SLOT(changeCaption(const QString&)));
+ connect(m_view,SIGNAL(signalFirstDisplayed(bool, bool)),this
+ ,SLOT(firstEntryDisplayed(bool, bool)));
+ connect(m_view,SIGNAL(signalLastDisplayed(bool, bool)),this
+ ,SLOT(lastEntryDisplayed(bool, bool)));
+ connect(m_view,SIGNAL(signalFuzzyDisplayed(bool)),this
+ ,SLOT(fuzzyDisplayed(bool)));
+ connect(m_view,SIGNAL(signalUntranslatedDisplayed(bool)),this
+ ,SLOT(untranslatedDisplayed(bool)));
+ connect(m_view,SIGNAL(signalFaultyDisplayed(bool)),this
+ ,SLOT(faultyDisplayed(bool)));
+ connect(m_view,SIGNAL(signalDisplayed(const KBabel::DocPosition&)),this
+ ,SLOT(displayedEntryChanged(const KBabel::DocPosition&)));
+ connect(m_view,SIGNAL(signalFuzzyAfterwards(bool)),this
+ ,SLOT(hasFuzzyAfterwards(bool)));
+ connect(m_view,SIGNAL(signalFuzzyInFront(bool)),this
+ ,SLOT(hasFuzzyInFront(bool)));
+ connect(m_view,SIGNAL(signalUntranslatedAfterwards(bool)),this
+ ,SLOT(hasUntranslatedAfterwards(bool)));
+ connect(m_view,SIGNAL(signalUntranslatedInFront(bool)),this
+ ,SLOT(hasUntranslatedInFront(bool)));
+ connect(m_view,SIGNAL(signalErrorAfterwards(bool)),this
+ ,SLOT(hasErrorAfterwards(bool)));
+ connect(m_view,SIGNAL(signalErrorInFront(bool)),this
+ ,SLOT(hasErrorInFront(bool)));
+ connect(m_view,SIGNAL(signalBackHistory(bool)),this
+ ,SLOT(enableBackHistory(bool)));
+ connect(m_view,SIGNAL(signalForwardHistory(bool)),this
+ ,SLOT(enableForwardHistory(bool)));
+
+
+ connect(m_view,SIGNAL(ledColorChanged(const QColor&)),this
+ ,SLOT(setLedColor(const QColor&)));
+
+
+ connect(m_view,SIGNAL(signalSearchActive(bool)),this,SLOT(enableStop(bool)));
+
+ connect(m_view,SIGNAL(signalProgress(int)),_progressBar,SLOT(setProgress(int)));
+ connect(m_view,SIGNAL(signalClearProgressBar()),this,SLOT(clearProgressBar()));
+ connect(m_view,SIGNAL(signalResetProgressBar(QString,int))
+ ,this,SLOT(prepareProgressBar(QString,int)));
+
+ connect(m_view,SIGNAL(signalDictionariesChanged())
+ , this, SLOT(buildDictMenus()));
+ connect(m_view,SIGNAL(signalCursorPosChanged(int,int)), this
+ , SLOT(updateCursorPosition(int,int)));
+
+ if(!catalog->currentURL().isEmpty())
+ {
+ enableDefaults(catalog->isReadOnly());
+ setNumberOfFuzzies(catalog->numberOfFuzzies());
+ setNumberOfUntranslated(catalog->numberOfUntranslated());
+ setNumberOfTotal(catalog->numberOfEntries());
+
+ enableUndo(catalog->isUndoAvailable());
+ enableUndo(catalog->isRedoAvailable());
+
+ m_view->emitEntryState();
+
+ changeCaption(catalog->currentURL().prettyURL() );
+ }
+
+ mailer = new KBabelMailer( this, _project );
+
+ bmHandler = new KBabelBookmarkHandler((QPopupMenu*)factory()->container("bookmark", this));
+ // the earlier created KAction for "clear_bookmarks" is now reconnected
+ KAction* action = actionCollection()->action("clear_bookmarks");
+ if (action) {
+ action->disconnect(SIGNAL(activated()));
+ connect(action, SIGNAL(activated()),
+ bmHandler, SLOT(slotClearBookmarks()));
+ }
+ connect(bmHandler, SIGNAL(signalBookmarkSelected(int)),
+ this, SLOT(slotOpenBookmark(int)));
+ connect(m_view, SIGNAL(signalNewFileOpened(KURL)),
+ bmHandler, SLOT(slotClearBookmarks()));
+
+ _config = KSharedConfig::openConfig( "kbabelrc" );
+ restoreSettings();
+
+ _config->setGroup("KBabel");
+
+ if(!_config->hasKey("Version"))
+ {
+ QString encodingStr;
+ switch(catalog->saveSettings().encoding)
+ {
+ case KBabel::ProjectSettingsBase::UTF8:
+ encodingStr=QTextCodec::codecForName("UTF-8")->name();
+ break;
+ case KBabel::ProjectSettingsBase::UTF16:
+ encodingStr=QTextCodec::codecForName("UTF-16")->name();
+ break;
+ default:
+ encodingStr=QTextCodec::codecForLocale()->name();
+ }
+
+ if( KBabelSplash::instance ) KBabelSplash::instance->close(); //close splash screen window, if there is one
+
+ KMessageBox::information(0,i18n("You have not run KBabel before. "
+ "To allow KBabel to work correctly you must enter some "
+ "information in the preferences dialog first.\n"
+ "The minimum requirement is to fill out the Identity page.\n"
+ "Also check the encoding on the Save page, which is currently "
+ "set to %1. You may want to change this setting "
+ "according to the settings of your language team.").arg(encodingStr));
+
+ QTimer::singleShot(1,this,SLOT(projectConfigure()));
+ }
+
+ _config->writeEntry("Version",VERSION);
+ _config->sync();
+
+}
+
+KBabelMW::~KBabelMW()
+{
+ if(_prefDialog)
+ {
+ prefDialogs.remove(_prefDialog);
+ }
+ if(_projectDialog)
+ {
+ delete _projectDialog;
+ }
+ delete mailer;
+ delete bmHandler;
+}
+
+
+void KBabelMW::setSettings(SaveSettings saveOpts,IdentitySettings idOpts)
+{
+ m_view->updateSettings();
+ m_view->catalog()->setSettings(saveOpts);
+ m_view->catalog()->setSettings(idOpts);
+
+ if(_fuzzyLed)
+ {
+ _fuzzyLed->setColor(KBabelSettings::ledColor());
+ }
+ if(_untransLed)
+ {
+ _untransLed->setColor(KBabelSettings::ledColor());
+ }
+ if(_errorLed)
+ {
+ _errorLed->setColor(KBabelSettings::ledColor());
+ }
+
+}
+
+void KBabelMW::updateSettings()
+{
+ m_view->updateSettings();
+
+ if(_fuzzyLed)
+ {
+ _fuzzyLed->setColor(KBabelSettings::ledColor());
+ }
+ if(_untransLed)
+ {
+ _untransLed->setColor(KBabelSettings::ledColor());
+ }
+ if(_errorLed)
+ {
+ _errorLed->setColor(KBabelSettings::ledColor());
+ }
+
+}
+
+
+void KBabelMW::setupActions()
+{
+ KAction* action;
+
+ // the file menu
+ action = KStdAction::open(this, SLOT(fileOpen()), actionCollection());
+
+ a_recent = KStdAction::openRecent(this, SLOT(openRecent(const KURL&)), actionCollection());
+ a_recent->setMaxItems(MAX_RECENT);
+
+ action = KStdAction::revert(m_view,SLOT(revertToSaved()),actionCollection());
+ action=KStdAction::save(this, SLOT(fileSave()), actionCollection());
+ action = KStdAction::saveAs(this, SLOT(fileSaveAs()), actionCollection());
+ action = new KAction(i18n("Save Sp&ecial..."), 0, this, SLOT(fileSaveSpecial()),
+ actionCollection(), "save_special" );
+ action = new KAction(i18n("Set &Package..."), 0, m_view, SLOT(setFilePackage()),
+ actionCollection(), "set_package" );
+
+ action = KStdAction::mail(this, SLOT(fileMail()), actionCollection());
+
+ action = new KAction(i18n("&New View"), 0, this, SLOT(fileNewView()),
+ actionCollection(), "file_new_view");
+
+ action = new KAction(i18n("New &Window"), 0, this, SLOT(fileNewWindow()),
+ actionCollection(), "file_new_window");
+ action->setShortcut( KStdAccel::openNew() );
+
+ action = KStdAction::quit(this, SLOT(quit()), actionCollection());
+
+
+
+ // the edit menu
+ action = KStdAction::undo(m_view, SLOT(undo()), actionCollection());
+ action = KStdAction::redo(m_view, SLOT(redo()), actionCollection());
+ action = KStdAction::cut(m_view, SIGNAL(signalCut()), actionCollection());
+ action = KStdAction::copy(m_view, SIGNAL(signalCopy()), actionCollection());
+ action = KStdAction::paste(m_view, SIGNAL(signalPaste()), actionCollection());
+ action = KStdAction::selectAll(m_view, SIGNAL(signalSelectAll()), actionCollection());
+ action = KStdAction::find(m_view, SLOT(find()), actionCollection());
+ action = KStdAction::findNext(m_view, SLOT(findNext()), actionCollection());
+ action = KStdAction::findPrev(m_view, SLOT(findPrev()), actionCollection());
+ action = KStdAction::replace(m_view, SLOT(replace()), actionCollection());
+
+ action = KStdAction::clear( m_view, SLOT(clear()), actionCollection(), "clear" );
+
+ action = new KAction(i18n("Cop&y Msgid to Msgstr"), "msgid2msgstr", CTRL+Key_Space, m_view
+ ,SLOT(msgid2msgstr()), actionCollection(), "msgid2msgstr");
+ action = new KAction(i18n("Copy Searc&h Result to Msgstr"), "search2msgstr",
+ CTRL+ALT+Key_Space, m_view, SLOT(search2msgstr()),
+ actionCollection(), "search2msgstr");
+ action = new KAction(i18n("Copy Msgstr to Other &Plurals"), Key_F11, m_view
+ ,SLOT(plural2msgstr()), actionCollection(), "plural2msgstr");
+ action = new KAction(i18n("Copy Selected Character to Msgstr"), Key_F10, m_charselectorview
+ ,SLOT(emitChar()), actionCollection(), "char2msgstr");
+
+ a_unsetFuzzy = new KAction(i18n("To&ggle Fuzzy Status"), "togglefuzzy", CTRL+Key_U, m_view
+ , SLOT(removeFuzzyStatus()), actionCollection(), "edit_toggle_fuzzy");
+ action = new KAction(i18n("&Edit Header..."), 0, m_view, SLOT(editHeader()),
+ actionCollection(), "edit_edit_header");
+
+ action = new KAction(i18n("&Insert Next Tag"), "insert_tag", CTRL+ALT+Key_N
+ , m_view, SLOT(insertNextTag())
+ , actionCollection(),"insert_next_tag");
+ connect(m_view,SIGNAL(signalNextTagAvailable(bool)),action
+ ,SLOT(setEnabled(bool)));
+ action = new KAction(i18n("Insert Next Tag From Msgid P&osition"), "insert_tag", CTRL+Key_M
+ , m_view, SLOT(insertNextTagMsgid())
+ , actionCollection(),"insert_next_tag_msgid");
+ connect(m_view,SIGNAL(signalNextTagAvailable(bool)),action
+ ,SLOT(setEnabled(bool)));
+ KActionMenu *actionMenu= new KActionMenu(i18n("Inser&t Tag"), "insert_tag"
+ , actionCollection(),"insert_tag");
+ m_view->setTagsMenu(actionMenu->popupMenu());
+ connect(m_view,SIGNAL(signalTagsAvailable(bool)),actionMenu
+ ,SLOT(setEnabled(bool)));
+ connect(actionMenu,SIGNAL(activated()),m_view,SLOT(insertNextTag()));
+
+ action = new KAction(i18n("Show Tags Menu"),CTRL+Key_Less
+ , m_view, SLOT(showTagsMenu()), actionCollection(),"show_tags_menu");
+ action->setEnabled(false);
+
+ connect(m_view,SIGNAL(signalTagsAvailable(bool)),action
+ ,SLOT(setEnabled(bool)));
+
+ action = new KAction(i18n("Move to Next Tag"), 0, CTRL+ALT+Key_M
+ , m_view, SLOT(skipToNextTag())
+ , actionCollection(),"move_to_next_tag");
+
+ action = new KAction(i18n("Move to Previous Tag"), 0, CTRL+ALT+Key_B
+ , m_view, SLOT(skipToPreviousTag())
+ , actionCollection(),"move_to_prev_tag");
+
+ action = new KAction(i18n("Insert Next Argument"), "insert_arg", CTRL+ALT+Key_G
+ , m_view, SLOT(insertNextArg())
+ , actionCollection(),"insert_next_arg");
+ connect(m_view,SIGNAL(signalNextArgAvailable(bool)),action
+ ,SLOT(setEnabled(bool)));
+ actionMenu= new KActionMenu(i18n("Inser&t Argument"), "insert_arg"
+ , actionCollection(),"insert_arg");
+ m_view->setArgsMenu(actionMenu->popupMenu());
+ connect(m_view,SIGNAL(signalArgsAvailable(bool)),actionMenu
+ ,SLOT(setEnabled(bool)));
+ connect(actionMenu,SIGNAL(activated()),m_view,SLOT(insertNextArg()));
+
+ action = new KAction(i18n("Show Arguments Menu"),CTRL+Key_Percent
+ , m_view, SLOT(showArgsMenu()), actionCollection(),"show_args_menu");
+ action->setEnabled(false);
+
+ connect(m_view,SIGNAL(signalArgsAvailable(bool)),action
+ ,SLOT(setEnabled(bool)));
+
+ // next, the go-menu
+ action = new KAction(i18n("&Previous"), "previous",
+ KStdAccel::shortcut(KStdAccel::Prior), m_view , SLOT(gotoPrev()),
+ actionCollection(),"go_prev_entry");
+ action = new KAction(i18n("&Next"), "next",
+ KStdAccel::shortcut(KStdAccel::Next), m_view , SLOT(gotoNext()),
+ actionCollection(),"go_next_entry");
+ action = KStdAction::goTo(m_view, SLOT(gotoEntry()), actionCollection());
+ action->setShortcut( KStdAccel::gotoLine());
+ action = KStdAction::firstPage(m_view, SLOT(gotoFirst()),actionCollection());
+ action->setText(i18n("&First Entry"));
+ action->setShortcut(CTRL+ALT+Key_Home);
+ action = KStdAction::lastPage(m_view, SLOT(gotoLast()),actionCollection());
+ action->setText(i18n("&Last Entry"));
+ action->setShortcut(CTRL+ALT+Key_End);
+ a_prevFoU = new KAction(i18n("P&revious Fuzzy or Untranslated"),"prevfuzzyuntrans",
+ CTRL+SHIFT+Key_Prior, m_view,
+ SLOT(gotoPrevFuzzyOrUntrans()),actionCollection(), "go_prev_fuzzyUntr");
+ a_nextFoU = new KAction(i18n("N&ext Fuzzy or Untranslated"),"nextfuzzyuntrans",
+ CTRL+SHIFT+Key_Next, m_view,
+ SLOT(gotoNextFuzzyOrUntrans()),actionCollection(), "go_next_fuzzyUntr");
+ a_prevFuzzy = new KAction(i18n("Pre&vious Fuzzy"),"prevfuzzy",
+ CTRL+Key_Prior, m_view,
+ SLOT(gotoPrevFuzzy()),actionCollection(), "go_prev_fuzzy");
+ a_nextFuzzy = new KAction(i18n("Ne&xt Fuzzy"), "nextfuzzy",
+ CTRL+Key_Next, m_view,
+ SLOT(gotoNextFuzzy()),actionCollection(), "go_next_fuzzy");
+ a_prevUntrans = new KAction(i18n("Prev&ious Untranslated"), "prevuntranslated",
+ ALT+Key_Prior, m_view,
+ SLOT(gotoPrevUntranslated()),actionCollection(), "go_prev_untrans");
+ a_nextUntrans = new KAction(i18n("Nex&t Untranslated"), "nextuntranslated",
+ ALT+Key_Next, m_view,
+ SLOT(gotoNextUntranslated()),actionCollection(), "go_next_untrans");
+ action = new KAction(i18n("Previo&us Error"), "preverror",
+ SHIFT+Key_Prior, m_view,
+ SLOT(gotoPrevError()),actionCollection(), "go_prev_error");
+ action = new KAction(i18n("Next Err&or"), "nexterror",
+ SHIFT+Key_Next, m_view,
+ SLOT(gotoNextError()),actionCollection(), "go_next_error");
+ action = new KAction(i18n("&Back in History"), "back", ALT+Key_Left, m_view,
+ SLOT(backHistory()),actionCollection(), "go_back_history");
+ action = new KAction(i18n("For&ward in History"), "forward", ALT+Key_Right, m_view,
+ SLOT(forwardHistory()),actionCollection(), "go_forward_history");
+
+ // the search menu
+ actionMenu=new KActionMenu(i18n("&Find Text"),
+ "transsearch",actionCollection(),"dict_search_all");
+ connect(actionMenu,SIGNAL(activated()),m_view,SLOT(startSearch()));
+ dictMenu = new DictionaryMenu(actionMenu->popupMenu(),actionCollection(),this);
+ connect(dictMenu,SIGNAL(activated(const QString)), m_view
+ , SLOT(startSearch(const QString)));
+
+ actionMenu=new KActionMenu(i18n("F&ind Selected Text"),
+ "transsearch",actionCollection(),"dict_search_selected");
+ connect(actionMenu,SIGNAL(activated()),m_view,SLOT(startSelectionSearch()));
+ selectionDictMenu = new DictionaryMenu(actionMenu->popupMenu(),actionCollection(),this);
+ connect(selectionDictMenu,SIGNAL(activated(const QString)), m_view
+ , SLOT(startSelectionSearch(const QString)));
+
+ actionMenu=new KActionMenu(i18n("&Edit Dictionary"),
+ "transsearch",actionCollection(),"dict_edit");
+ editDictMenu = new DictionaryMenu(actionMenu->popupMenu(),actionCollection(),this);
+ connect(editDictMenu,SIGNAL(activated(const QString)), m_view
+ , SLOT(editDictionary(const QString)));
+
+
+ actionMenu=new KActionMenu(i18n("Con&figure Dictionary"),
+ "transsearch",actionCollection(),"dict_configure");
+ configDictMenu = new DictionaryMenu(actionMenu->popupMenu(),actionCollection(),this);
+ connect(configDictMenu,SIGNAL(activated(const QString)), m_view
+ , SLOT(configureDictionary(const QString)));
+
+ actionMenu=new KActionMenu(i18n("About Dictionary"), "transsearch",
+ actionCollection(), "dict_about");
+ aboutDictMenu = new DictionaryMenu(actionMenu->popupMenu(),actionCollection(),this);
+ connect(aboutDictMenu,SIGNAL(activated(const QString)), m_view
+ , SLOT(aboutDictionary(const QString)));
+
+ buildDictMenus();
+
+ // the project menu
+ action = new KAction(i18n("&New..."), "filenew"
+ , this, SLOT(projectNew()),actionCollection()
+ ,"project_new");
+
+ action = new KAction(i18n("&Open..."), "fileopen"
+ , this, SLOT(projectOpen()),actionCollection()
+ ,"project_open");
+
+ action = new KAction(i18n("C&lose"), "fileclose"
+ , this, SLOT(projectClose()),actionCollection()
+ ,"project_close");
+ action->setEnabled (_project->filename() != KBabel::ProjectManager::defaultProjectName() );
+
+ action = new KAction(i18n("&Configure..."), "configure"
+ , this, SLOT(projectConfigure()),actionCollection()
+ ,"project_settings");
+
+ a_recentprojects = new KRecentFilesAction(i18n("Open &Recent"), 0, this, SLOT(projectOpenRecent(const KURL&)), actionCollection(), "recent_projects");
+
+ // the tools menu
+ action = new KAction(i18n("&Spell Check..."), "spellcheck", CTRL+Key_I
+ , m_view, SLOT(spellcheckCommon()),actionCollection()
+ ,"spellcheck_common");
+ action = new KAction(i18n("&Check All..."), "spellcheck_all", 0
+ , m_view, SLOT(spellcheckAll()),actionCollection()
+ ,"spellcheck_all");
+ action = new KAction(i18n("C&heck From Cursor Position..."), "spellcheck_from_cursor", 0
+ , m_view, SLOT(spellcheckFromCursor()),actionCollection()
+ ,"spellcheck_from_cursor");
+ action = new KAction(i18n("Ch&eck Current..."), "spellcheck_actual", 0
+ , m_view, SLOT(spellcheckCurrent()),actionCollection()
+ ,"spellcheck_current");
+ action = new KAction(i18n("Check Fro&m Current to End of File..."), 0
+ , m_view, SLOT(spellcheckFromCurrent()),actionCollection()
+ ,"spellcheck_from_current");
+ action = new KAction(i18n("Chec&k Selected Text..."), "spellcheck_selected", 0
+ , m_view, SLOT(spellcheckMarked()),actionCollection()
+ ,"spellcheck_marked");
+
+ KToggleAction *toggleAction;
+
+ toggleAction = new KToggleAction(i18n("&Diffmode"), "autodiff", 0
+ ,actionCollection(), "diff_toggleDiff");
+ connect(toggleAction,SIGNAL(toggled(bool)), m_view, SLOT(toggleAutoDiff(bool)));
+ connect(m_view,SIGNAL(signalDiffEnabled(bool)), toggleAction
+ , SLOT(setChecked(bool)));
+ toggleAction->setChecked(m_view->autoDiffEnabled());
+
+ action = new KAction(i18n("&Show Diff"), "diff", Key_F5
+ , m_view, SLOT(diff()),actionCollection()
+ ,"diff_diff");
+ action = new KAction(i18n("S&how Original Text"), "contents", Key_F6
+ , m_view, SLOT(diffShowOrig()),actionCollection()
+ ,"diff_showOrig");
+
+ action = new KAction(i18n("&Open File for Diff"), "fileopen" ,0
+ , m_view, SLOT(openDiffFile()),actionCollection()
+ ,"diff_openFile");
+
+ action = new KAction(i18n("&Rough Translation..."), 0
+ , m_view, SLOT(roughTranslation()),actionCollection()
+ ,"rough_translation");
+
+ action = new KAction(i18n("&Catalog Manager..."),"catalogmanager", 0 , this,
+ SLOT(openCatalogManager()),actionCollection(), "open_catalog_manager");
+
+ new KAction( i18n("Toggle Edit Mode"), 0, Key_Insert,this,SLOT(toggleEditMode()), actionCollection(), "toggle_insert_mode");
+
+ new KAction( i18n("&Word Count"), 0, m_view, SLOT(wordCount()), actionCollection(), "word_count");
+
+ // next, the settings menu
+ createStandardStatusBarAction();
+
+ KStdAction::configureToolbars(this,SLOT(optionsEditToolbars()),actionCollection());
+
+ KStdAction::keyBindings(guiFactory(),SLOT(configureShortcuts()),actionCollection());
+ KStdAction::preferences(this,SLOT(optionsPreferences()),actionCollection());
+
+ setStandardToolBarMenuEnabled ( true );
+
+ action = new KAction(i18n("&Stop Searching"), "stop",Key_Escape, m_view,
+ SLOT(stopSearch()),actionCollection(), "stop_search");
+ action->setEnabled(false);
+
+ new KAction(i18n("&Gettext Info"), 0, this,
+ SLOT(gettextHelp()), actionCollection(), "help_gettext");
+
+
+ // the bookmarks menu
+
+ action = KStdAction::addBookmark(this, SLOT(slotAddBookmark()),
+ actionCollection(), "add_bookmark");
+ action->setEnabled(false);
+ // this action is now connected to dummySlot(), and later reconnected
+ // to bmHandler after that object actually is created
+ new KAction(i18n("Clear Bookmarks"), 0, this, SLOT(dummySlot()),
+ actionCollection(), "clear_bookmarks");
+
+ setupDynamicActions();
+
+ createGUI(0);
+
+ QPopupMenu *popup = static_cast<QPopupMenu*>(factory()->container("settings",this));
+ popup->insertItem( i18n("&Views"), dockHideShowMenu(), -1, 0 );
+}
+
+
+void KBabelMW::setupStatusBar()
+{
+ statusBar()->insertItem(i18n("Current: 0"),ID_STATUS_CURRENT);
+ statusBar()->insertItem(i18n("Total: 0"),ID_STATUS_TOTAL);
+ statusBar()->insertItem(i18n("Fuzzy: 0"),ID_STATUS_FUZZY);
+ statusBar()->insertItem(i18n("Untranslated: 0"),ID_STATUS_UNTRANS);
+
+ if(KBabelSettings::ledInStatusbar())
+ {
+ QColor ledColor=KBabelSettings::ledColor();
+ QHBox* statusBox = new QHBox(statusBar(),"statusBox");
+ statusBox->setSpacing(2);
+ new QLabel(" "+i18n("Status: "),statusBox);
+ _fuzzyLed = new KLed(ledColor,KLed::Off,KLed::Sunken,KLed::Rectangular
+ ,statusBox);
+ _fuzzyLed->setFixedSize(15,12);
+ new QLabel(i18n("fuzzy")+" ",statusBox);
+ _untransLed = new KLed(ledColor,KLed::Off,KLed::Sunken,KLed::Rectangular
+ ,statusBox);
+ _untransLed->setFixedSize(15,12);
+ new QLabel(i18n("untranslated")+" ",statusBox);
+ _errorLed = new KLed(ledColor,KLed::Off,KLed::Sunken,KLed::Rectangular
+ ,statusBox);
+ _errorLed->setFixedSize(15,12);
+ new QLabel(i18n("faulty")+" ",statusBox);
+
+ statusBox->setFixedWidth(statusBox->sizeHint().width());
+ statusBar()->addWidget(statusBox);
+ }
+
+ statusBar()->insertItem(i18n("INS"),ID_STATUS_EDITMODE);
+
+ statusBar()->insertItem(i18n("RW"),ID_STATUS_READONLY);
+
+ statusBar()->insertItem(i18n("Line: %1 Col: %2").arg(1).arg(1)
+ ,ID_STATUS_CURSOR);
+
+ QHBox* progressBox = new QHBox(statusBar(),"progressBox");
+ progressBox->setSpacing(2);
+ _progressLabel = new KSqueezedTextLabel( "", progressBox );
+ _progressBar=new MyKProgress(progressBox,"progressbar");
+ _progressBar->hide();
+ progressBox->setStretchFactor(_progressBar,1);
+
+ statusBar()->addWidget(progressBox,1);
+ statusBar()->setMinimumHeight(progressBox->sizeHint().height());
+
+ QWhatsThis::add(statusBar(),
+ i18n("<qt><p><b>Statusbar</b></p>\n\
+<p>The statusbar displays some information about the opened file,\n\
+like the total number of entries and the number of fuzzy and untranslated\n\
+messages. Also the index and the status of the currently displayed entry is shown.</p></qt>"));
+
+}
+
+void KBabelMW::setupDynamicActions()
+{
+ // dynamic validation tools
+ QValueList<KDataToolInfo> tools = ToolAction::validationTools();
+
+ QPtrList<KAction> actions = ToolAction::dataToolActionList(
+ tools, m_view, SLOT(validateUsingTool( const KDataToolInfo &, const QString & )),
+ "validate", false, actionCollection() );
+
+ KActionMenu* m_menu = new KActionMenu(i18n("&Validation"), actionCollection(), "dynamic_validation_tools");
+
+ KAction* ac = new KAction(i18n("Perform &All Checks"), CTRL+Key_E , m_view,
+ SLOT(checkAll()),actionCollection(), "check_all");
+ ac->setEnabled(false);
+ m_menu->insert(ac);
+
+ m_menu->insert( new KActionSeparator() );
+
+ ac = new KAction(i18n("C&heck Syntax"), CTRL+Key_T , m_view,
+ SLOT(checkSyntax()),actionCollection(), "check_syntax");
+ ac->setEnabled(false);
+ m_menu->insert(ac);
+
+ for( ac = actions.first(); ac ; ac = actions.next() )
+ {
+ m_menu->insert(ac);
+ }
+
+ // dynamic modify tools
+
+ // query available tools
+ QValueList<KDataToolInfo> allTools = KDataToolInfo::query
+ ("CatalogItem", "application/x-kbabel-catalogitem", KGlobal::instance());
+
+ // skip read-only tools for single items
+ QValueList<KDataToolInfo> modifyTools;
+
+ QValueList<KDataToolInfo>::ConstIterator entry = allTools.begin();
+ for( ; entry != allTools.end(); ++entry )
+ {
+ if( !(*entry).isReadOnly() )
+ {
+ modifyTools.append( (*entry) );
+ }
+ }
+
+ // create corresponding actions
+ actions = ToolAction::dataToolActionList(
+ modifyTools, m_view, SLOT(modifyUsingTool( const KDataToolInfo &, const QString & )),
+ "validate", true, actionCollection() );
+
+ // skip validation actions
+ for( ac = actions.first(); ac ; ac = actions.next() )
+ {
+ m_menu->insert(ac);
+ }
+
+ // insert tools
+ m_menu = new KActionMenu(i18n("&Modify"), actionCollection(), "dynamic_modify_tools");
+ for( ac = actions.first(); ac ; ac = actions.next() )
+ {
+ m_menu->insert(ac);
+ }
+
+ // query available tools for whole catalog
+ allTools = KDataToolInfo::query
+ ("Catalog", "application/x-kbabel-catalog", KGlobal::instance());
+
+ // skip read-only tools
+ entry = allTools.begin();
+ for( ; entry != allTools.end(); ++entry )
+ {
+ if( !(*entry).isReadOnly() )
+ {
+ modifyTools.append( (*entry) );
+ }
+ }
+
+ // create corresponding actions
+ actions = ToolAction::dataToolActionList(
+ modifyTools, m_view, SLOT(modifyUsingTool( const KDataToolInfo &, const QString & )),
+ "validate", true, actionCollection() );
+
+ // skip validation actions
+ for( ac = actions.first(); ac ; ac = actions.next() )
+ {
+ m_menu->insert(ac);
+ }
+
+ // create corresponding actions
+ actions = ToolAction::dataToolActionList(
+ modifyTools, m_view, SLOT(modifyCatalogUsingTool( const KDataToolInfo &, const QString & )),
+ "validate", true, actionCollection() );
+
+ // insert tools
+ m_menu = new KActionMenu(i18n("&Modify"), actionCollection(), "dynamic_modify_tools");
+ for( ac = actions.first(); ac ; ac = actions.next() )
+ {
+ m_menu->insert(ac);
+ }
+}
+
+void KBabelMW::saveSettings()
+{
+ {
+ saveMainWindowSettings(_config, "View");
+ writeDockConfig (_config, "View");
+ }
+
+ {
+ a_recent->saveEntries(_config);
+ a_recentprojects->saveEntries(_config,"Project");
+ }
+
+ _config->sync();
+}
+
+void KBabelMW::restoreSettings()
+{
+ {
+ applyMainWindowSettings(_config, "View");
+ KConfigGroupSaver saver(_config,"View");
+
+ _config->setGroup("View");
+ m_view->restoreView(_config);
+
+ readDockConfig (_config, "View");
+ }
+
+ {
+ a_recent->loadEntries(_config);
+
+ a_recentprojects->loadEntries(_config, "Project");
+ }
+}
+
+
+
+void KBabelMW::saveProperties(KConfig *config)
+{
+ m_view->saveSession(config);
+}
+
+void KBabelMW::readProperties(KConfig *config)
+{
+ m_view->restoreSession(config);
+
+ // need to ensure that the windows is propertly setup also
+ // for new views-only
+ if(!m_view->currentURL().isEmpty())
+ {
+ KBCatalog* catalog=m_view->catalog();
+ enableDefaults(catalog->isReadOnly());
+ setNumberOfFuzzies(catalog->numberOfFuzzies());
+ setNumberOfUntranslated(catalog->numberOfUntranslated());
+ setNumberOfTotal(catalog->numberOfEntries());
+
+ enableUndo(catalog->isUndoAvailable());
+ enableUndo(catalog->isRedoAvailable());
+
+ m_view->emitEntryState();
+
+ changeCaption(catalog->currentURL().prettyURL() );
+ }
+}
+
+bool KBabelMW::queryClose()
+{
+ if(m_view->isSearching())
+ {
+ connect(m_view,SIGNAL(signalSearchActive(bool)),this,SLOT(quit()));
+ m_view->stopSearch();
+ return false;
+ }
+
+ if(m_view->catalog()->isActive())
+ {
+ // stop the activity and try again
+ m_view->catalog()->stop();
+ QTimer::singleShot(0, this, SLOT( close() ));
+ return false;
+ }
+
+ if(m_view->isModified())
+ {
+ switch(KMessageBox::warningYesNoCancel(this,
+ i18n("The document contains unsaved changes.\n\
+Do you want to save your changes or discard them?"),i18n("Warning"),
+ KStdGuiItem::save(),KStdGuiItem::discard()))
+ {
+ case KMessageBox::Yes:
+ {
+ return m_view->saveFile();
+ }
+ case KMessageBox::No:
+ return true;
+ default:
+ return false;
+ }
+ }
+
+ return true;
+}
+
+bool KBabelMW::queryExit()
+{
+ saveSettings();
+ _config->setGroup("View");
+ m_view->saveView(_config);
+
+ m_view->saveSettings();
+ return true;
+}
+
+void KBabelMW::quit()
+{
+ close();
+}
+
+
+void KBabelMW::dragEnterEvent(QDragEnterEvent *event)
+{
+ // accept uri drops only
+ event->accept(KURLDrag::canDecode(event));
+}
+
+void KBabelMW::dropEvent(QDropEvent *event)
+{
+ KURL::List uri;
+ // see if we can decode a URI.. if not, just ignore it
+ if (KURLDrag::decode(event, uri))
+ {
+ m_view->processUriDrop(uri,mapToGlobal(event->pos()));
+ }
+}
+
+void KBabelMW::wheelEvent(QWheelEvent *e)
+{
+ m_view->wheelEvent(e);
+}
+
+void KBabelMW::openRecent(const KURL& url)
+{
+ KBabelView *view = KBabelView::viewForURL(url,QString::null);
+ if(view)
+ {
+ KWin::activateWindow(view->topLevelWidget()->winId());
+ return;
+ }
+
+ m_view->open(url);
+}
+
+void KBabelMW::open(const KURL& url)
+{
+ open(url,QString::null,false);
+}
+
+void KBabelMW::open(const KURL& url, const QString package, bool newWindow)
+{
+ kdDebug(KBABEL) << "opening file with project:" << _project->filename() << endl;
+ kdDebug(KBABEL) << "URL:" << url.prettyURL() << endl;
+ KBabelView *view = KBabelView::viewForURL(url, _project->filename());
+ if(view)
+ {
+ kdDebug(KBABEL) << "there is a such view" << endl;
+ KWin::activateWindow(view->topLevelWidget()->winId());
+ return;
+ }
+
+ addToRecentFiles(url);
+
+ if(newWindow)
+ {
+ kdDebug(KBABEL) << "creating new window"<< endl;
+ fileNewWindow()->open(url, package,false);
+ }
+ else
+ {
+ m_view->open(url,package);
+ }
+}
+
+void KBabelMW::openTemplate(const KURL& openURL,const KURL& saveURL,const QString& package, bool newWindow)
+{
+ if(newWindow)
+ {
+ fileNewWindow()->openTemplate(openURL,saveURL,package,false);
+ }
+ else
+ {
+ m_view->openTemplate(openURL,saveURL);
+ m_view->catalog()->setPackage(package);
+ }
+}
+
+void KBabelMW::fileOpen()
+{
+ m_view->open();
+
+ KURL url=m_view->currentURL();
+ addToRecentFiles(url);
+}
+
+
+void KBabelMW::addToRecentFiles(KURL url)
+{
+ if( url.isValid() && ! url.isEmpty() )
+ a_recent->addURL(url);
+}
+
+void KBabelMW::fileSave()
+{
+ // do it asynchronously due to kdelibs bug
+ QTimer::singleShot( 0, this, SLOT( fileSave_internal() ));
+}
+
+void KBabelMW::fileSave_internal()
+{
+ // this slot is called whenever the File->Save menu is selected,
+ // the Save shortcut is pressed (usually CTRL+S) or the Save toolbar
+ // button is clicked
+
+ if(!m_view->isModified())
+ {
+ statusBar()->message(i18n("There are no changes to save."),2000);
+ }
+ else
+ {
+ // disable save
+ KAction* saveAction=(KAction*)actionCollection()->action( KStdAction::name( KStdAction::Save) );
+ saveAction->setEnabled(false);
+
+ m_view->saveFile();
+
+ KURL url=m_view->currentURL();
+
+ DCOPClient *client = kapp->dcopClient();
+ QByteArray data;
+ QDataStream arg(data, IO_WriteOnly);
+ arg << ((url.directory(false)+url.fileName()).utf8()) ;
+ if( !client->send( "catalogmanager-*", "CatalogManagerIFace", "updatedFile(QCString)", data ))
+ kdDebug(KBABEL) << "Unable to send file update info via DCOP" << endl;
+
+ // reenable save action
+ saveAction->setEnabled(true);
+ }
+}
+
+void KBabelMW::fileSaveAs()
+{
+ m_view->saveFileAs();
+ KURL url=m_view->currentURL();
+
+ DCOPClient *client = kapp->dcopClient();
+ QByteArray data;
+ QDataStream arg(data, IO_WriteOnly);
+ arg << ((url.directory(false)+url.fileName()).utf8()) ;
+ if( !client->send( "catalogmanager-*", "CatalogManagerIFace", "updatedFile(QCString)", data ))
+ kdDebug(KBABEL) << "Unable to send file update info via DCOP" << endl;
+}
+
+void KBabelMW::fileSaveSpecial()
+{
+ if( !m_view->saveFileSpecial() ) return;
+
+ KURL url=m_view->currentURL();
+
+ DCOPClient *client = kapp->dcopClient();
+ QByteArray data;
+ QDataStream arg(data, IO_WriteOnly);
+ arg << ((url.directory(false)+url.fileName()).utf8()) ;
+ if( !client->send( "catalogmanager-*", "CatalogManagerIFace", "updatedFile(QCString)", data ))
+ kdDebug(KBABEL) << "Unable to send file update info via DCOP" << endl;
+}
+
+void KBabelMW::fileMail()
+{
+ if( m_view->isModified() ) fileSave();
+ mailer->sendOneFile( m_view->currentURL() );
+}
+
+void KBabelMW::fileNewView()
+{
+ KBabelMW* b=new KBabelMW(m_view->catalog(),_project->filename());
+ b->updateSettings();
+ b->initBookmarks(bmHandler->bookmarks());
+ b->show();
+}
+
+KBabelMW* KBabelMW::fileNewWindow()
+{
+ KBabelMW* b=new KBabelMW(_project->filename());
+ b->setSettings(m_view->catalog()->saveSettings(),m_view->catalog()->identitySettings());
+ b->show();
+
+ return b;
+}
+
+void KBabelMW::toggleEditMode()
+{
+ bool ovr=!m_view->isOverwriteMode();
+
+ m_view->setOverwriteMode(ovr);
+
+ if(ovr)
+ statusBar()->changeItem(i18n("OVR"),ID_STATUS_EDITMODE);
+ else
+ statusBar()->changeItem(i18n("INS"),ID_STATUS_EDITMODE);
+
+}
+
+void KBabelMW::optionsShowStatusbar(bool on)
+{
+ if(on)
+ {
+ statusBar()->show();
+ }
+ else
+ {
+ statusBar()->hide();
+ }
+}
+
+void KBabelMW::optionsEditToolbars()
+{
+ saveMainWindowSettings( KGlobal::config(), "View" );
+ KEditToolbar dlg(actionCollection());
+ connect(&dlg, SIGNAL(newToolbarConfig()), this, SLOT(newToolbarConfig()));
+ dlg.exec();
+}
+
+void KBabelMW::newToolbarConfig()
+{
+ createGUI(0);
+ applyMainWindowSettings( KGlobal::config(), "View" );
+}
+
+void KBabelMW::optionsPreferences()
+{
+ if(!_prefDialog)
+ {
+ _prefDialog = new KBabelPreferences(m_view->dictionaries());
+ prefDialogs.append(_prefDialog);
+
+ connect(_prefDialog,SIGNAL(settingsChanged())
+ ,m_view,SLOT(updateSettings()));
+ }
+
+ int prefHeight=_prefDialog->height();
+ int prefWidth=_prefDialog->width();
+ int width=this->width();
+ int height=this->height();
+
+ int x=width/2-prefWidth/2;
+ int y=height/2-prefHeight/2;
+
+ _prefDialog->move(mapToGlobal(QPoint(x,y)));
+
+ if(!_prefDialog->isVisible())
+ {
+ _prefDialog->show();
+ }
+
+ _prefDialog->raise();
+ KWin::activateWindow(_prefDialog->winId());
+}
+
+void KBabelMW::setLedColor(const QColor& color)
+{
+ if(_fuzzyLed)
+ {
+ _fuzzyLed->setColor(color);
+ }
+ if(_untransLed)
+ {
+ _untransLed->setColor(color);
+ }
+ if(_errorLed)
+ {
+ _errorLed->setColor(color);
+ }
+}
+
+void KBabelMW::openCatalogManager()
+{
+ QCString service;
+ QString result;
+
+ DCOPClient * client = kapp->dcopClient();
+
+ // find out, if there is a running catalog manager
+ QCStringList apps = client->registeredApplications();
+ for( QCStringList::Iterator it = apps.begin() ; it != apps.end() ; ++it )
+ {
+ QString clientID = *it;
+ if( clientID.startsWith("catalogmanager") )
+ {
+ service = *it;
+ break;
+ }
+ }
+
+ // if there is no running catalog manager, start one
+ if( service.isEmpty() )
+ {
+ QString prog = "catalogmanager";
+ QString url = "";
+ if( kapp->startServiceByDesktopName(prog,url, &result,&service))
+ {
+ KMessageBox::error(this, i18n("Unable to use KLauncher to start "
+ "Catalog Manager. You should check the installation of KDE.\n"
+ "Please start Catalog Manager manually."));
+ return;
+ }
+ }
+
+ // set preferred window
+ QByteArray data;
+ QDataStream arg(data, IO_WriteOnly);
+ arg << (this->winId()) ;
+ if( !client->send( service, "CatalogManagerIFace", "setPreferredWindow( WId )", data )) kdDebug(KBABEL) << "Unable to set preferred window via DCOP" << endl;
+}
+
+
+
+void KBabelMW::firstEntryDisplayed(bool firstEntry, bool firstForm)
+{
+ KAction* firstAction=(KAction*)actionCollection()->action(KStdAction::stdName(KStdAction::FirstPage));
+ KAction* prevAction=(KAction*)actionCollection()->action("go_prev_entry");
+
+ firstAction->setEnabled(!firstEntry);
+ prevAction->setEnabled(!(firstEntry && firstForm));
+
+}
+
+void KBabelMW::lastEntryDisplayed(bool lastEntry, bool lastForm)
+{
+ KAction* lastAction=(KAction*)actionCollection()->action(KStdAction::stdName(KStdAction::LastPage));
+ KAction* nextAction=(KAction*)actionCollection()->action("go_next_entry");
+
+ lastAction->setEnabled(!lastEntry);
+ nextAction->setEnabled(!(lastEntry && lastForm));
+}
+
+void KBabelMW::fuzzyDisplayed(bool flag)
+{
+ if(!_fuzzyLed)
+ return;
+
+ if(flag)
+ {
+ if(_fuzzyLed->state()==KLed::Off)
+ {
+ _fuzzyLed->on();
+ }
+ }
+ else
+ {
+ if(_fuzzyLed->state()==KLed::On)
+ _fuzzyLed->off();
+ }
+}
+
+void KBabelMW::untranslatedDisplayed(bool flag)
+{
+ if(!_untransLed)
+ return;
+
+ // do not allow fuzzy toggle for untranslated
+ KAction *action=actionCollection()->action("edit_toggle_fuzzy");
+ if(action)
+ action->setEnabled(!flag);
+
+
+ if(flag)
+ {
+ if(_untransLed->state()==KLed::Off)
+ _untransLed->on();
+ }
+ else
+ {
+ if(_untransLed->state()==KLed::On)
+ _untransLed->off();
+ }
+}
+
+
+void KBabelMW::faultyDisplayed(bool flag)
+{
+ if(!_errorLed)
+ return;
+
+ if(flag)
+ {
+ if(_errorLed->state()==KLed::Off)
+ _errorLed->on();
+ }
+ else
+ {
+ if(_errorLed->state()==KLed::On)
+ _errorLed->off();
+ }
+}
+
+
+void KBabelMW::displayedEntryChanged(const KBabel::DocPosition& pos)
+{
+ statusBar()->changeItem(i18n("Current: %1").arg(pos.item+1),ID_STATUS_CURRENT);
+ _currentIndex = pos.item;
+}
+
+void KBabelMW::setNumberOfTotal(uint number)
+{
+ statusBar()->changeItem(i18n("Total: %1").arg(number),ID_STATUS_TOTAL);
+}
+
+void KBabelMW::setNumberOfFuzzies(uint number)
+{
+ statusBar()->changeItem(i18n("Fuzzy: %1").arg(number),ID_STATUS_FUZZY);
+}
+
+void KBabelMW::setNumberOfUntranslated(uint number)
+{
+ statusBar()->changeItem(i18n("Untranslated: %1").arg(number),ID_STATUS_UNTRANS);
+}
+
+void KBabelMW::hasFuzzyAfterwards(bool flag)
+{
+ a_nextFuzzy->setEnabled(flag);
+
+ // check if there is a fuzzy or untranslated afterwards
+ if( flag || a_nextUntrans->isEnabled() )
+ {
+ a_nextFoU->setEnabled(true);
+ }
+ else
+ {
+ a_nextFoU->setEnabled(false);
+ }
+
+}
+
+void KBabelMW::hasFuzzyInFront(bool flag)
+{
+ a_prevFuzzy->setEnabled(flag);
+
+ // check if there is a fuzzy or untranslated in front
+ if( flag || a_prevUntrans->isEnabled() )
+ {
+ a_prevFoU->setEnabled(true);
+ }
+ else
+ {
+ a_prevFoU->setEnabled(false);
+ }
+}
+
+void KBabelMW::hasUntranslatedAfterwards(bool flag)
+{
+ a_nextUntrans->setEnabled(flag);
+
+ // check if there is a fuzzy or untranslated afterwards
+ if( flag || a_nextFuzzy->isEnabled() )
+ {
+ a_nextFoU->setEnabled(true);
+ }
+ else
+ {
+ a_nextFoU->setEnabled(false);
+ }
+}
+
+void KBabelMW::hasUntranslatedInFront(bool flag)
+{
+ a_prevUntrans->setEnabled(flag);
+
+ // check if there is a fuzzy or translated in front
+ if( flag || a_prevFuzzy->isEnabled() )
+ {
+ a_prevFoU->setEnabled(true);
+ }
+ else
+ {
+ a_prevFoU->setEnabled(false);
+ }
+}
+
+
+
+void KBabelMW::hasErrorAfterwards(bool flag)
+{
+ KAction* action=actionCollection()->action("go_next_error");
+ action->setEnabled(flag);
+}
+
+void KBabelMW::hasErrorInFront(bool flag)
+{
+ KAction* action=actionCollection()->action("go_prev_error");
+ action->setEnabled(flag);
+}
+
+
+void KBabelMW::enableBackHistory(bool on)
+{
+ KAction* action=actionCollection()->action("go_back_history");
+ action->setEnabled(on);
+}
+
+void KBabelMW::enableForwardHistory(bool on)
+{
+ KAction* action=actionCollection()->action("go_forward_history");
+ action->setEnabled(on);
+}
+
+
+void KBabelMW::prepareProgressBar(QString msg,int max)
+{
+ if(_statusbarTimer->isActive())
+ _statusbarTimer->stop();
+
+ _progressBar->show();
+ _progressLabel->setText(" "+msg);
+ _progressBar->setTotalSteps(max);
+ _progressBar->setProgress(0);
+
+}
+
+void KBabelMW::clearProgressBar()
+{
+ _progressBar->setProgress(0);
+ _progressBar->hide();
+ _progressLabel->setText(" ");
+}
+
+
+void KBabelMW::changeStatusbar(const QString& text)
+{
+ // display the text on the statusbar
+ _progressLabel->setText(" "+text);
+
+ if(_statusbarTimer->isActive())
+ _statusbarTimer->stop();
+
+ _statusbarTimer->start(5000,true);
+}
+
+void KBabelMW::clearStatusbarMsg()
+{
+ _progressLabel->setText("");
+}
+
+void KBabelMW::changeCaption(const QString& text)
+{
+ // display the text on the caption
+ setCaption(text + ( _project->filename () != KBabel::ProjectManager::defaultProjectName() ?
+ " (" + _project->name() + ")" : "" /* KDE 3.4: i18n("(No project)")*/ )
+ ,m_view->isModified());
+}
+
+
+void KBabelMW::showModified(bool on)
+{
+ // display the text on the caption
+ setCaption(m_view->catalog()->package(),on);
+
+ KAction *action=actionCollection()->action(
+ KStdAction::stdName(KStdAction::Save));
+ action->setEnabled(on);
+
+ action=actionCollection()->action(KStdAction::stdName(KStdAction::Revert));
+ action->setEnabled(on);
+}
+
+
+void KBabelMW::enableDefaults(bool readOnly)
+{
+ stateChanged( "readonly", readOnly ? StateNoReverse : StateReverse );
+ stateChanged( "fileopened", StateNoReverse );
+
+ if(readOnly)
+ statusBar()->changeItem(i18n("RO"),ID_STATUS_READONLY);
+ else
+ statusBar()->changeItem(i18n("RW"),ID_STATUS_READONLY);
+}
+
+void KBabelMW::enableUndo(bool on)
+{
+ KAction* action=actionCollection()->action(KStdAction::stdName(KStdAction::Undo));
+ action->setEnabled(on);
+}
+
+void KBabelMW::enableRedo(bool on)
+{
+ KAction* action=actionCollection()->action(KStdAction::stdName(KStdAction::Redo));
+ action->setEnabled(on);
+}
+
+void KBabelMW::enableStop(bool flag)
+{
+ KAction* action=(KAction*)actionCollection()->action("stop_search");
+ action->setEnabled(flag);
+}
+
+void KBabelMW::gettextHelp()
+{
+ QString error;
+ KApplication::startServiceByDesktopName("khelpcenter",
+ QString("info:/gettext"), &error);
+
+ if(!error.isEmpty())
+ {
+ KMessageBox::sorry(this,i18n("An error occurred while "
+ "trying to open the gettext info page:\n%1").arg(error));
+ }
+}
+
+void KBabelMW::buildDictMenus()
+{
+ QPtrList<ModuleInfo> dictList = m_view->dictionaries();
+ dictList.setAutoDelete(true);
+
+ dictMenu->clear();
+ selectionDictMenu->clear();
+ configDictMenu->clear();
+ editDictMenu->clear();
+ aboutDictMenu->clear();
+
+ ModuleInfo *info;
+ for(info = dictList.first(); info !=0; info = dictList.next())
+ {
+ QString accel="Ctrl+Alt+%1";
+ dictMenu->add(info->name,info->id, accel);
+
+ accel=QString("Ctrl+%1");
+ selectionDictMenu->add(info->name,info->id, accel);
+
+ configDictMenu->add(info->name,info->id);
+ aboutDictMenu->add(info->name,info->id);
+
+ if(info->editable)
+ {
+ dictMenu->add(info->name,info->id);
+ }
+ }
+}
+
+void KBabelMW::updateCursorPosition(int line, int col)
+{
+ statusBar()->changeItem(i18n("Line: %1 Col: %2").arg(line+1).arg(col+1)
+ ,ID_STATUS_CURSOR);
+}
+
+
+KBabelMW *KBabelMW::winForURL(const KURL& url, QString project)
+{
+ KBabelMW *kb=0;
+
+ KBabelView *v = KBabelView::viewForURL(url,project);
+ if(v)
+ {
+ QObject *p = v->parent();
+ while(p && !p->inherits("KBabelMW"))
+ {
+ p = p->parent();
+ }
+
+ if(p)
+ kb = static_cast<KBabelMW*>(p);
+ }
+
+ return kb;
+}
+
+KBabelMW *KBabelMW::emptyWin(QString project)
+{
+ KBabelMW *kb=0;
+
+ KBabelView *v = KBabelView::emptyView(project);
+ if(v)
+ {
+ QObject *p = v->parent();
+ while(p && !p->inherits("KBabelMW"))
+ {
+ p = p->parent();
+ }
+
+ if(p)
+ kb = static_cast<KBabelMW*>(p);
+ }
+
+ return kb;
+}
+
+void KBabelMW::spellcheckMoreFiles(QStringList filelist)
+{
+ if( filelist.isEmpty() ) return;
+ _toSpellcheck = filelist;
+ connect( m_view, SIGNAL( signalSpellcheckDone(int) ), this, SLOT( spellcheckDone(int)));
+ spellcheckDone( KS_IGNORE ); // use something else than KS_STOP
+}
+
+void KBabelMW::spellcheckDone( int result)
+{
+ if( _toSpellcheck.isEmpty() || result == KS_STOP)
+ {
+ disconnect( m_view, SIGNAL( signalSpellcheckDone(int)), this, SLOT(spellcheckDone( int)));
+ KMessageBox::information( this, i18n("MessageBox text", "Spellchecking of multiple files is finished."),
+ i18n("MessageBox caption", "Spellcheck Done"));
+ }
+ else
+ {
+ QString file = _toSpellcheck.first();
+ _toSpellcheck.pop_front();
+ if( m_view->isModified() ) fileSave();
+ open(KURL( file ), QString::null, false);
+ kdDebug(KBABEL) << "Starting another spellcheck" << endl;
+ QTimer::singleShot( 1, m_view, SLOT(spellcheckAllMulti()));
+ }
+}
+
+void KBabelMW::initBookmarks(QPtrList<KBabelBookmark> list)
+{
+ bmHandler->setBookmarks(list);
+}
+
+void KBabelMW::slotAddBookmark()
+{
+ bmHandler->addBookmark(_currentIndex+1, m_view->catalog()->msgid(_currentIndex).first());
+}
+
+void KBabelMW::slotOpenBookmark(int index)
+{
+ DocPosition pos;
+ pos.item=index-1;
+ pos.form=0;
+ m_view->gotoEntry(pos);
+}
+
+void KBabelMW::projectNew()
+{
+ KBabel::Project::Ptr p = KBabel::ProjectWizard::newProject();
+ if( p )
+ {
+ _project = p;
+ m_view->useProject(p);
+ changeProjectActions(p->filename());
+ }
+}
+
+void KBabelMW::projectOpen()
+{
+ QString oldproject = m_view->project();
+ if( oldproject == KBabel::ProjectManager::defaultProjectName() )
+ {
+ oldproject = QString();
+ }
+ const QString file = KFileDialog::getOpenFileName(oldproject, QString::null, this);
+ if (file.isEmpty())
+ {
+ return;
+ }
+
+ projectOpen (file);
+}
+
+void KBabelMW::projectOpenRecent(const KURL& url)
+{
+ projectOpen (url.path());
+ KBabel::Project::Ptr p = KBabel::ProjectManager::open(url.path());
+ if( p )
+ {
+ _project = p;
+ m_view->useProject(p);
+ changeProjectActions(url.path());
+ }
+}
+
+void KBabelMW::projectOpen(const QString& file)
+{
+ QString oldproject = m_view->project();
+ if( oldproject == KBabel::ProjectManager::defaultProjectName() )
+ {
+ oldproject = "";
+ }
+ if (file.isEmpty())
+ {
+ return;
+ }
+ KBabel::Project::Ptr p = KBabel::ProjectManager::open(file);
+ if( p )
+ {
+ _project = p;
+ m_view->useProject(p);
+ changeProjectActions(file);
+ }
+ else
+ {
+ KMessageBox::error( this, i18n("Cannot open project file\n%1").arg(file)
+ , i18n("Project File Error"));
+ _project = ProjectManager::open(KBabel::ProjectManager::defaultProjectName());
+ m_view->useProject(_project);
+ changeProjectActions(KBabel::ProjectManager::defaultProjectName());
+ }
+}
+
+void KBabelMW::projectClose()
+{
+ QString defaultProject = KBabel::ProjectManager::defaultProjectName();
+ m_view->useProject( KBabel::ProjectManager::open(defaultProject) );
+ _project = ProjectManager::open(defaultProject);
+ changeProjectActions(defaultProject);
+}
+
+void KBabelMW::changeProjectActions(const QString& project)
+{
+ bool def = (project == KBabel::ProjectManager::defaultProjectName());
+
+ KAction* saveAction=(KAction*)actionCollection()->action( "project_close" );
+ saveAction->setEnabled( ! def );
+
+ if (!def)
+ {
+ addToRecentProjects(project);
+ }
+
+ // if there is a project dialog, delete it (we have a different project now
+ if (_projectDialog)
+ {
+ delete _projectDialog;
+ _projectDialog = NULL;
+ }
+}
+
+void KBabelMW::projectConfigure()
+{
+ if(!_projectDialog)
+ {
+ _projectDialog = new ProjectDialog(_project);
+ connect (_projectDialog, SIGNAL (settingsChanged())
+ , m_view, SLOT (updateProjectSettings()));
+ }
+
+ int prefHeight=_projectDialog->height();
+ int prefWidth=_projectDialog->width();
+ int width=this->width();
+ int height=this->height();
+
+ int x=width/2-prefWidth/2;
+ int y=height/2-prefHeight/2;
+
+ _projectDialog->move(mapToGlobal(QPoint(x,y)));
+
+ if(!_projectDialog->isVisible())
+ {
+ _projectDialog->show();
+ }
+
+ _projectDialog->raise();
+ KWin::activateWindow(_projectDialog->winId());
+}
+
+void KBabelMW::addToRecentProjects(KURL url)
+{
+ if( url.isValid() && ! url.isEmpty() )
+ a_recentprojects->addURL(url);
+}
+
+
+#include "kbabel.moc"
diff --git a/kbabel/kbabel/kbabel.desktop b/kbabel/kbabel/kbabel.desktop
new file mode 100644
index 00000000..950e0dbd
--- /dev/null
+++ b/kbabel/kbabel/kbabel.desktop
@@ -0,0 +1,83 @@
+[Desktop Entry]
+Name=KBabel
+Name[af]=Kbabel
+Name[eo]=Babelo-tradukilo
+Name[hi]=के-बेबल
+Name[ko]=K바벨
+Name[ne]=केबà¥à¤¯à¤¾à¤¬à¤²
+Name[pa]=ਕੇਬਬੇਲ
+Name[pt_BR]=Editor de POTFiles
+Name[sv]=Kbabel
+Name[ta]=Kபாபேலà¯
+Exec=kbabel %i %m -caption "%c" %U
+Icon=kbabel
+Type=Application
+DocPath=kbabel/index.html
+MimeType=application/x-gettext;
+GenericName=Translation Tool
+GenericName[af]=Vertaling Program
+GenericName[ar]=أداة الترجمة
+GenericName[bg]=ИнÑтрумент за превод
+GenericName[br]=Ostilh troidigezh
+GenericName[bs]=Alat za prevođenje
+GenericName[ca]=Eina de traducció
+GenericName[cs]=Překladatelský nástroj
+GenericName[cy]=Erfyn Cyfieithu
+GenericName[da]=Oversættelsesværktøj
+GenericName[de]=Ãœbersetzungsprogramm
+GenericName[el]=ΕÏγαλείο μετάφÏασης
+GenericName[eo]=Tradukilo por Qt-programoj
+GenericName[es]=Herramienta de traducción
+GenericName[et]=Tõlkimise rakendus
+GenericName[eu]=Itzulpen tresna
+GenericName[fa]=ابزار ترجمه
+GenericName[fi]=Käännöstyökalu
+GenericName[fo]=Umsetingaramboð
+GenericName[fr]=Outil de traduction
+GenericName[ga]=Uirlis Aistriúcháin
+GenericName[gl]=Ferramenta de tradución
+GenericName[he]=כלי תרגו×
+GenericName[hi]=अनà¥à¤µà¤¾à¤¦ औज़ार
+GenericName[hr]=Uslužni program za prevođenje
+GenericName[hu]=Fordítássegítő eszköz
+GenericName[is]=Þýðingaforrit
+GenericName[it]=Strumento di traduzione
+GenericName[ja]=翻訳ツール
+GenericName[ka]=თáƒáƒ áƒ’მნის ხელსáƒáƒ¬áƒ§áƒ
+GenericName[kk]=Ðудару құралы
+GenericName[lt]=Vertimo įrankis
+GenericName[lv]=Tulkošanas Rīks
+GenericName[ms]=Perkakasan Penterjemahan
+GenericName[mt]=Għodda tat-traduzzjoni
+GenericName[nb]=Oversettingsverktøy
+GenericName[nds]=Översettenwarktüüch
+GenericName[ne]=अनà¥à¤¬à¤¾à¤¦ उपकरण
+GenericName[nl]=Vertaalprogramma
+GenericName[nn]=Omsetjingsverktøy
+GenericName[nso]=Sebereka sa Thlathollo
+GenericName[pa]=ਅਨà©à¨µà¨¾à¨¦ ਸੰਦ
+GenericName[pl]=Narzędzie dla tłumaczy
+GenericName[pt]=Ferramenta de Tradução
+GenericName[pt_BR]=Ferramenta de Tradução
+GenericName[ro]=Utilitar de traducere
+GenericName[ru]=Ð›Ð¾ÐºÐ°Ð»Ð¸Ð·Ð°Ñ†Ð¸Ñ Ð¿Ñ€Ð¸Ð»Ð¾Ð¶ÐµÐ½Ð¸Ð¹
+GenericName[sk]=Prekladací nástroj
+GenericName[sl]=Orodje za prevajanje
+GenericName[sr]=Ðлат за превођење
+GenericName[sr@Latn]=Alat za prevođenje
+GenericName[sv]=Översättningsverktyg
+GenericName[ta]=மொழிபெயரà¯à®ªà¯à®ªà¯ கரà¯à®µà®¿
+GenericName[tg]=Утилитаи маҳалликунонии гузориш
+GenericName[th]=เครื่องมือà¹à¸›à¸¥à¸ à¸²à¸©à¸²
+GenericName[tr]=Çeviri Aracı
+GenericName[uk]=ЗаÑіб Ð´Ð»Ñ Ð¿ÐµÑ€ÐµÐºÐ»Ð°Ð´Ñ–Ð²
+GenericName[ven]=Zwishumiswa zwau Dologa
+GenericName[vi]=Công cụ dịch
+GenericName[xh]=Isixhobo Soguqulelo lomsebenzi kolunye ulwimi
+GenericName[zh_CN]=翻译工具
+GenericName[zh_TW]=翻譯工具
+GenericName[zu]=Ithuluzi Lokuguqulela
+Terminal=false
+X-KDE-StartupNotify=true
+X-DCOP-ServiceType=Unique
+Categories=Qt;KDE;Development;Translation;
diff --git a/kbabel/kbabel/kbabel.h b/kbabel/kbabel/kbabel.h
new file mode 100644
index 00000000..4ff184c1
--- /dev/null
+++ b/kbabel/kbabel/kbabel.h
@@ -0,0 +1,325 @@
+/* ****************************************************************************
+ This file is part of KBabel
+
+ Copyright (C) 1999-2000 by Matthias Kiefer
+ <matthias.kiefer@gmx.de>
+ 2002-2004 by Stanislav Visnovsky
+ <visnovsky@kde.org>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the 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, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+ In addition, as a special exception, the copyright holders give
+ permission to link the code of this program with any edition of
+ the Qt library by Trolltech AS, Norway (or with modified versions
+ of Qt that use the same license as Qt), and distribute linked
+ combinations including the two. You must obey the GNU General
+ Public License in all respects for all of the code used other than
+ Qt. If you modify this file, you may extend this exception to
+ your version of the file, but you are not obligated to do so. If
+ you do not wish to do so, delete this exception statement from
+ your version.
+
+**************************************************************************** */
+#ifndef KBABEL_H
+#define KBABEL_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <kapplication.h>
+#include <kdeversion.h>
+#include <kdockwidget.h>
+#include <qstringlist.h>
+#include <qptrlist.h>
+#include <kmdimainfrm.h>
+
+#include "kbabelview.h"
+#include "kbproject.h"
+
+class KAction;
+class KRecentFilesAction;
+class KLed;
+class KProgress;
+class QHBox;
+class QLabel;
+class QTimer;
+
+class KBCatalog;
+class KBabelPreferences;
+class DictionaryMenu;
+class KBabelBookmark;
+class KBabelBookmarkHandler;
+class CommentView;
+class CharacterSelectorView;
+
+namespace KBabel
+{
+ class KBabelMailer;
+ class ProjectDialog;
+}
+
+/**
+ * This class serves as the main window for KBabel. It handles the
+ * menus, toolbars, and status bars.
+ *
+ * @short Main window class
+ * @author Matthias Kiefer <matthias.kiefer@gmx.de>
+ * @version 0.1
+ */
+class KBabelMW : public KDockMainWindow
+{
+ Q_OBJECT
+public:
+ /**
+ * Default Constructor
+ */
+ KBabelMW(QString projectFile = QString());
+
+ /** use this contructor, if you just want to create a new view of an existing catalog*/
+ KBabelMW(KBCatalog* catalog, QString projectFile = QString());
+
+ /**
+ * Default Destructor
+ */
+ virtual ~KBabelMW();
+
+ QString project() const { return _project->filename(); }
+
+ void open(const KURL& url, const QString package, bool newWindow);
+ void openTemplate(const KURL& openURL,const KURL& saveURL,const QString& package, bool newWindow=false);
+ void projectOpen(const QString& filename);
+
+ void spellcheckMoreFiles( QStringList filelist);
+
+ void setSettings(KBabel::SaveSettings,KBabel::IdentitySettings);
+ void updateSettings();
+
+ /**
+ * @return A pointer to a KBabel, that has opened file URL or 0 if no
+ * KBabel was found
+ */
+ static KBabelMW *winForURL(const KURL& url, QString projectFile = QString::null);
+
+ /**
+ * @return A pointer to a KBabel, that has opened no file URL or 0 if no
+ * KBabel was found
+ */
+ static KBabelMW *emptyWin(QString projectFile = QString::null);
+
+public slots:
+ void toggleEditMode();
+
+protected:
+ /**
+ * Overridden virtuals for Qt drag 'n drop (XDND)
+ */
+ virtual void dragEnterEvent(QDragEnterEvent *event);
+ virtual void dropEvent(QDropEvent *event);
+
+ /**
+ * Overrriden virtual for wheel event handling to forward to KBabelView
+ */
+ virtual void wheelEvent(QWheelEvent *e);
+
+ /**
+ * This function is called when it is time for the app to save its
+ * properties for session management purposes.
+ */
+ virtual void saveProperties(KConfig *);
+
+ /**
+ * This function is called when this app is restored. The KConfig
+ * object points to the session management config file that was saved
+ * with @ref saveProperties
+ */
+ virtual void readProperties(KConfig *);
+
+ virtual bool queryExit();
+ virtual bool queryClose();
+
+private slots:
+ void quit();
+
+ void open(const KURL& url);
+ void openRecent(const KURL& url);
+ void fileOpen();
+ void fileSave();
+ void fileSave_internal();
+ void fileSaveAs();
+ void fileSaveSpecial();
+ void fileMail();
+ void fileNewView();
+ KBabelMW* fileNewWindow();
+
+ void projectNew();
+ void projectOpen();
+ void projectClose();
+ void projectConfigure();
+ void projectOpenRecent(const KURL& url);
+
+ void addToRecentFiles(KURL url);
+ void addToRecentProjects(KURL url);
+
+ void optionsShowStatusbar(bool);
+ void optionsEditToolbars();
+ void newToolbarConfig();
+ void optionsPreferences();
+
+ /** opens the gettext info page */
+ void gettextHelp();
+
+ void firstEntryDisplayed(bool firstEntry, bool firstForm);
+ void lastEntryDisplayed(bool lastEntry, bool lastForm);
+ void fuzzyDisplayed(bool);
+ void untranslatedDisplayed(bool);
+ void faultyDisplayed(bool);
+ void displayedEntryChanged(const KBabel::DocPosition& pos);
+ void setNumberOfTotal(uint number);
+ void setNumberOfFuzzies(uint number);
+ void setNumberOfUntranslated(uint number);
+ void hasFuzzyAfterwards(bool);
+ void hasFuzzyInFront(bool);
+ void hasUntranslatedAfterwards(bool);
+ void hasUntranslatedInFront(bool);
+ void hasErrorAfterwards(bool);
+ void hasErrorInFront(bool);
+ void updateCursorPosition(int line, int col);
+
+ void enableBackHistory(bool);
+ void enableForwardHistory(bool);
+
+ void enableUndo(bool);
+ void enableRedo(bool);
+ void enableStop(bool);
+
+ void openCatalogManager();
+
+ /**
+ * prepare the window and the progressbar for showing
+ * activity. message is displayed left to the progressbar
+ * and max is the maximum number for the progressbar
+ */
+ void prepareProgressBar(QString message,int max);
+ /**
+ * resets the progressBar and enables the window
+ */
+ void clearProgressBar();
+
+ void changeStatusbar(const QString& text);
+ void clearStatusbarMsg();
+ void changeCaption(const QString& text);
+ void showModified(bool);
+
+ /**
+ * enables menu- and toolbar items that are always enabled when a cat is opened
+ */
+ void enableDefaults(bool readOnly);
+
+ void setLedColor(const QColor& color);
+
+
+ void buildDictMenus();
+
+ /**
+ * used when creating standard toggle actions, because I prefer
+ * using signal toggled(bool)
+ */
+ void dummySlot(){}
+
+ void spellcheckDone( int result);
+
+ /**
+ * Create a new bookmark for the current msgid and add it to the list.
+ */
+ void slotAddBookmark();
+ /**
+ * Open the bookmark whose entry was just clicked in the menu.
+ */
+ void slotOpenBookmark(int index);
+
+private:
+ void init(KBCatalog* catalog);
+ void setupActions();
+ void setupDynamicActions();
+ void changeProjectActions(const QString& project);
+ void setupStatusBar();
+ void saveSettings();
+ void restoreSettings();
+ /**
+ * Init a new view of the current window with this window's bookmarks.
+ *
+ * @param list the list of bookmarks.
+ */
+ void initBookmarks(QPtrList<KBabelBookmark> list);
+
+private:
+ KBabelView *m_view;
+ CharacterSelectorView * const m_charselectorview;
+ CommentView * m_commentview;
+
+ int _currentIndex;
+
+ KProgress* _progressBar;
+ QLabel* _progressLabel;
+ KLed* _fuzzyLed;
+ KLed* _untransLed;
+ KLed* _errorLed;
+
+ QTimer *_statusbarTimer;
+
+ KBabelPreferences* _prefDialog;
+
+ QStringList _toSpellcheck;
+
+ /**
+ * used for updating preferences, that are common in
+ * the whole application
+ */
+ static QPtrList<KBabelPreferences> prefDialogs;
+
+
+ // frequently used actions
+ KAction* a_unsetFuzzy;
+ KAction* a_prevFoU;
+ KAction* a_nextFoU;
+ KAction* a_prevFuzzy;
+ KAction* a_nextFuzzy;
+ KAction* a_prevUntrans;
+ KAction* a_nextUntrans;
+
+ KRecentFilesAction* a_recent;
+ KRecentFilesAction* a_recentprojects;
+
+ DictionaryMenu *dictMenu;
+ DictionaryMenu *selectionDictMenu;
+ DictionaryMenu *configDictMenu;
+ DictionaryMenu *editDictMenu;
+ DictionaryMenu *aboutDictMenu;
+
+ friend class KBabelInterface;
+
+ // project file
+ KBabel::Project::Ptr _project;
+ KSharedConfig::Ptr _config;
+ KBabel::ProjectDialog* _projectDialog;
+
+ QMap<QString,QString> _toolsShortcuts;
+
+ KBabel::KBabelMailer* mailer;
+ KBabelBookmarkHandler* bmHandler;
+};
+
+#endif // KBABEL_H
diff --git a/kbabel/kbabel/kbabel.kcfg b/kbabel/kbabel/kbabel.kcfg
new file mode 100644
index 00000000..0da6949c
--- /dev/null
+++ b/kbabel/kbabel/kbabel.kcfg
@@ -0,0 +1,304 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<kcfg xmlns="http://www.kde.org/standards/kcfg/1.0"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://www.kde.org/standards/kcfg/1.0
+ http://www.kde.org/standards/kcfg/1.0/kcfg.xsd" >
+ <group name="Editor">
+ <entry name="AccelColor" type="Color">
+ <label>
+ </label>
+ <default>128,0,128</default>
+ </entry>
+ <entry name="AutoCheckColorError" type="Bool">
+ <label>
+ </label>
+ <default>true</default>
+ </entry>
+ <entry name="AutoCheckTools" type="StringList">
+ <label>
+ </label>
+ <default></default>
+ </entry>
+ <entry name="AutoDiff" type="Bool">
+ <label>
+ </label>
+ <default>false</default>
+ </entry>
+ <entry name="AutoUnsetFuzzy" type="Bool">
+ <label>
+ </label>
+ <default>true</default>
+ </entry>
+ <entry name="BackgroundColor" type="Color">
+ <label>
+ </label>
+ <default>255,255,192</default>
+ </entry>
+ <entry name="BeepOnError" type="Bool">
+ <label>
+ </label>
+ <default>false</default>
+ </entry>
+ <entry name="CformatColor" type="Color">
+ <label>
+ </label>
+ <default>0,0,255</default>
+ </entry>
+ <entry name="CleverEditing" type="Bool">
+ <label>
+ </label>
+ <default>true</default>
+ </entry>
+ <entry name="DiffAddColor" type="Color">
+ <label>
+ </label>
+ <default>192,192,255</default>
+ </entry>
+ <entry name="DiffAddUnderline" type="Enum">
+ <label>
+ </label>
+ <choices>
+ <choice name="Highlighted"/>
+ <choice name="Underlined"/>
+ </choices>
+ <default>Underlined</default>
+ </entry>
+ <entry name="DiffDelColor" type="Color">
+ <label>
+ </label>
+ <default>255,128,128</default>
+ </entry>
+ <entry name="DiffDelStrikeOut" type="Enum">
+ <label>
+ </label>
+ <choices>
+ <choice name="Highlighted"/>
+ <choice name="StrokedOut"/>
+ </choices>
+ <default>StrokedOut</default>
+ </entry>
+ <entry name="EnableQuotes" type="Bool">
+ <label>
+ </label>
+ <default>false</default>
+ </entry>
+ <entry name="ErrorColor" type="Color">
+ <label>
+ </label>
+ <default>255,0,0</default>
+ </entry>
+ <entry name="HighlightBackground" type="Bool">
+ <label>
+ </label>
+ <default>false</default>
+ </entry>
+ <entry name="HighlightSyntax" type="Bool">
+ <label>
+ </label>
+ <default>true</default>
+ </entry>
+ <entry name="LedColor" type="Color">
+ <label>
+ </label>
+ <default>255,0,0</default>
+ </entry>
+ <entry name="LedInStatusbar" type="Bool">
+ <label>
+ </label>
+ <default>false</default>
+ </entry>
+ <entry name="MsgFont" type="Font">
+ <label>Font for Messages</label>
+ <default code="true">KGlobalSettings::generalFont()</default>
+ </entry>
+ <entry name="OnFlySpellCheck" type="Bool">
+ <label>
+ </label>
+ <default>true</default>
+ </entry>
+ <entry name="SpellcheckErrorColor" type="Color">
+ <label>
+ </label>
+ <default>255,128,0</default>
+ </entry>
+ <entry name="QuotedColor" type="Color">
+ <label>
+ </label>
+ <default>0,128,0</default>
+ </entry>
+ <entry name="TagColor" type="Color">
+ <label>
+ </label>
+ <default>0,0,128</default>
+ </entry>
+ <entry name="WhitespacePoints" type="Bool">
+ <label>
+ </label>
+ <default>true</default>
+ </entry>
+ </group>
+ <group name="FindDialog">
+ <entry name="Backwards" type="Bool">
+ <label>
+ </label>
+ <default>false</default>
+ </entry>
+ <entry name="CaseSensitive" type="Bool">
+ <label>
+ </label>
+ <default>false</default>
+ </entry>
+ <entry name="FromCursor" type="Bool">
+ <label>
+ </label>
+ <default>false</default>
+ </entry>
+ <entry name="IgnoreAccelMarker" type="Bool">
+ <label>
+ </label>
+ <default>true</default>
+ </entry>
+ <entry name="IgnoreContextInfo" type="Bool">
+ <label>
+ </label>
+ <default>true</default>
+ </entry>
+ <entry name="InComment" type="Bool">
+ <label>
+ </label>
+ <default>false</default>
+ </entry>
+ <entry name="InMsgid" type="Bool">
+ <label>
+ </label>
+ <default>true</default>
+ </entry>
+ <entry name="InMsgstr" type="Bool">
+ <label>
+ </label>
+ <default>true</default>
+ </entry>
+ <entry name="List" type="String">
+ <label>
+ </label>
+ <default>right as,Record here,sidereal,altitu</default>
+ </entry>
+ <entry name="RegExp" type="Bool">
+ <label>
+ </label>
+ <default>false</default>
+ </entry>
+ <entry name="WholeWords" type="Bool">
+ <label>
+ </label>
+ <default>false</default>
+ </entry>
+ </group>
+ <group name="KBCharSelector">
+ <entry name="SelectedChar" type="String">
+ <label>
+ </label>
+ <default> </default>
+ </entry>
+ <entry name="TableNum" type="UInt">
+ <label>
+ </label>
+ <default>0</default>
+ </entry>
+ </group>
+ <group name="KBabel">
+ <entry name="Version" type="String">
+ <label>
+ </label>
+ <default>1.3</default>
+ </entry>
+ </group>
+ <group name="KFileDialog Settings">
+ <entry name="AutomaticPreview" key="Automatic Preview" type="Bool">
+ <label>
+ </label>
+ <default>true</default>
+ </entry>
+ <entry name="PreviewSize" key="Preview Size" type="UInt">
+ <label>
+ </label>
+ <default>60</default>
+ </entry>
+ <entry name="RecentFiles" key="Recent Files" type="String">
+ <label>
+ </label>
+ <default></default>
+ </entry>
+ <entry name="ShowPreviews" type="Bool">
+ <label>
+ </label>
+ <default>false</default>
+ </entry>
+ <entry name="ViewMode" type="String">
+ <label>
+ </label>
+ <default>SmallColumns</default>
+ </entry>
+ </group>
+ <group name="KFileDialog Speedbar">
+ <entry name="SpeedbarIconSize" key="Speedbar IconSize" type="UInt">
+ <label>
+ </label>
+ <default>32</default>
+ </entry>
+ </group>
+ <group name="Search">
+ <entry name="AutoSearch" type="Bool">
+ <label>
+ </label>
+ <default>false</default>
+ </entry>
+ <entry name="DefaultModule" type="String">
+ <label>
+ </label>
+ <default>pocompendium</default>
+ </entry>
+ </group>
+ <group name="View">
+ <entry name="Comments" type="Bool">
+ <label>
+ </label>
+ <default>true</default>
+ </entry>
+ <entry name="EditSplitter" type="IntList">
+ <label>
+ </label>
+ <default>242,257</default>
+ </entry>
+ <entry name="Height768" key="Height 768" type="UInt">
+ <label>
+ </label>
+ <default>624</default>
+ </entry>
+ <entry name="MainSplitter" type="IntList">
+ <label>
+ </label>
+ <default>427,307</default>
+ </entry>
+ <entry name="Toolbox" type="UInt">
+ <label>
+ </label>
+ <default>0</default>
+ </entry>
+ <entry name="ToolboxSplitter" type="IntList">
+ <label>
+ </label>
+ <default>122,377</default>
+ </entry>
+ <entry name="Tools" type="Bool">
+ <label>
+ </label>
+ <default>true</default>
+ </entry>
+ <entry name="Width1024" key="Width 1024" type="UInt">
+ <label>
+ </label>
+ <default>739</default>
+ </entry>
+ </group>
+</kcfg>
diff --git a/kbabel/kbabel/kbabeliface.h b/kbabel/kbabel/kbabeliface.h
new file mode 100644
index 00000000..d03b927d
--- /dev/null
+++ b/kbabel/kbabel/kbabeliface.h
@@ -0,0 +1,81 @@
+/* ****************************************************************************
+ This file is part of KBabel
+
+ Copyright (C) 1999-2000 by Matthias Kiefer
+ <matthias.kiefer@gmx.de>
+ 2001-2002 by Stanislav Visnovsky
+ <visnovsky@kde.org>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the 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, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+ In addition, as a special exception, the copyright holders give
+ permission to link the code of this program with any edition of
+ the Qt library by Trolltech AS, Norway (or with modified versions
+ of Qt that use the same license as Qt), and distribute linked
+ combinations including the two. You must obey the GNU General
+ Public License in all respects for all of the code used other than
+ Qt. If you modify this file, you may extend this exception to
+ your version of the file, but you are not obligated to do so. If
+ you do not wish to do so, delete this exception statement from
+ your version.
+
+**************************************************************************** */
+#ifndef KBABELIFACE_H
+#define KBABELIFACE_H
+
+#include <dcopobject.h>
+#include <qstringlist.h>
+
+class KBabelIface : virtual public DCOPObject
+{
+ K_DCOP
+public:
+
+k_dcop:
+ virtual void openURL(QCString url, QCString package, WId window, int newWindow) { url = ""; window = 0; newWindow = 0; package= "";}
+ virtual void openURL(QCString url, QCString package, WId window, int newWindow, QCString projectFile)
+ { url = ""; window = 0; newWindow = 0; projectFile=""; package= "";}
+ virtual void openTemplate(QCString openFilename, QCString package, QCString saveFilename, int newWindow) { openFilename = ""; saveFilename = ""; newWindow = 0; package= "";}
+ virtual void openTemplate(QCString openFilename, QCString package, QCString saveFilename, int newWindow, QCString projectFile)
+ { openFilename = ""; saveFilename = ""; newWindow = 0; projectFile=""; package= "";}
+ /**
+ * open file url, if not already opened and goto entry
+ * that is equal msgid
+ */
+ virtual void gotoFileEntry(QCString url, QCString msgid)=0;
+ virtual void gotoFileEntry(QCString url, QCString package, int msgid)=0;
+ virtual void gotoFileEntry(QCString url, QCString package, int msgid, QCString projectFile)=0;
+
+
+ virtual bool findInFile(QCString fileSource, QCString url,
+ QString findStr, int caseSensitive, int wholeWords, int isRegExp,
+ int inMsgid, int inMsgstr, int inComment,
+ int ignoreAccelMarker, int ignoreContextInfo, int askForNextFile, int askForSave)=0;
+ virtual bool replaceInFile(QCString fileSource, QCString url,
+ QString findStr, QString replaceStr, int caseSensitive, int wholeWords, int isRegExp,
+ int inMsgid, int inMsgstr, int inComment, int ignoreAccelMarker,
+ int ignoreContextInfo, int ask, int askForNextFile, int askForSave)=0;
+ virtual bool findInFile(QCString fileSource, QCString url,
+ QString findStr, int caseSensitive, int wholeWords, int isRegExp,
+ int inMsgid, int inMsgstr, int inComment,
+ int ignoreAccelMarker, int ignoreContextInfo, int askForNextFile, int askForSave, QCString project )=0;
+ virtual bool replaceInFile(QCString fileSource, QCString url,
+ QString findStr, QString replaceStr, int caseSensitive, int wholeWords, int isRegExp,
+ int inMsgid, int inMsgstr, int inComment, int ignoreAccelMarker,
+ int ignoreContextInfo, int ask, int askForNextFile, int askForSave, QCString project )=0;
+ virtual void spellcheck(QStringList fileList)=0;
+};
+
+#endif // KBABELIFACE_H
diff --git a/kbabel/kbabel/kbabelpref.cpp b/kbabel/kbabel/kbabelpref.cpp
new file mode 100644
index 00000000..2907f060
--- /dev/null
+++ b/kbabel/kbabel/kbabelpref.cpp
@@ -0,0 +1,198 @@
+/* ****************************************************************************
+ This file is part of KBabel
+
+ Copyright (C) 1999-2000 by Matthias Kiefer
+ <matthias.kiefer@gmx.de>
+ 2004-2005 by Stanislav Visnovsky
+ <visnovsky@kde.org>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the 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, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+ In addition, as a special exception, the copyright holders give
+ permission to link the code of this program with any edition of
+ the Qt library by Trolltech AS, Norway (or with modified versions
+ of Qt that use the same license as Qt), and distribute linked
+ combinations including the two. You must obey the GNU General
+ Public License in all respects for all of the code used other than
+ Qt. If you modify this file, you may extend this exception to
+ your version of the file, but you are not obligated to do so. If
+ you do not wish to do so, delete this exception statement from
+ your version.
+
+**************************************************************************** */
+#include "kbabelpref.h"
+#include "kbabeldictbox.h"
+#include "kbabelsettings.h"
+#include "fontpreferences.h"
+#include "editordiffpreferences.h"
+#include "editorpreferences.h"
+#include "searchpreferences.h"
+#include "colorpreferences.h"
+#include "toolaction.h"
+#include "toolselectionwidget.h"
+#include "qcombobox.h"
+
+#include <klocale.h>
+#include <kapplication.h>
+
+using namespace KBabel;
+
+KBabelPreferences::KBabelPreferences(QPtrList<ModuleInfo> ml)
+ : KConfigDialog(0, "Preferences", KBabelSettings::self())
+{
+ _editorPage = new EditorPreferences(0, "editor");
+ addPage( _editorPage
+ , i18n("title of page in preferences dialog","Edit")
+ , "edit"
+ , i18n("Options for Editing"));
+
+ // this contains a custom widget for tool selection, set it up
+ QValueList<KDataToolInfo> tools = ToolAction::validationTools();
+ _editorPage->_kcfg_AutoCheckTools->loadTools( "validate", tools );
+ connect( _editorPage->_kcfg_AutoCheckTools, SIGNAL( added( QListBoxItem * ) ),
+ this, SLOT (updateButtons()));
+ connect( _editorPage->_kcfg_AutoCheckTools, SIGNAL( removed( QListBoxItem * ) ),
+ this, SLOT (updateButtons()));
+
+ addPage(_searchPage = new SearchPreferences(0, "search")
+ , i18n("title of page in preferences dialog","Search")
+ , "transsearch"
+ , i18n("Options for Searching Similar Translations"));
+
+ // setup the dictionary combobox contents
+ ModuleInfo *info;
+ for(info = ml.first(); info != 0; info = ml.next())
+ {
+ _searchPage->_kcfg_DefaultModule->insertItem(info->name);
+ }
+ moduleList = ml;
+ connect( _searchPage->_kcfg_DefaultModule, SIGNAL( activated(int) ),
+ this, SLOT (updateButtons()));
+
+ addPage(new EditorDiffPreferences(0, "diff")
+ ,i18n("title of page in preferences dialog","Diff")
+ , "diff"
+ , i18n("Options for Showing Differences"));
+
+ addPage(new FontPreferences(0, "fonts")
+ , i18n("name of page in preferences dialog icon list","Fonts")
+ , "font"
+ , i18n("title of page in preferences dialog","Font Settings"));
+
+ addPage(new ColorPreferences(0, "colors")
+ , i18n("name of page in preferences dialog icon list","Colors")
+ , "colorize"
+ , i18n("title of page in preferences dialog","Color Settings"));
+
+ adjustSize();
+}
+
+
+void KBabelPreferences::slotHelp()
+{
+ //TODO
+ kapp->invokeHelp("Preferences","");
+}
+
+bool KBabelPreferences::hasChanged()
+{
+ ModuleInfo *info = moduleList.at(_searchPage->_kcfg_DefaultModule->currentItem());
+
+ bool module_ret = true;
+ if( info )
+ {
+ module_ret = info->id != KBabelSettings::defaultModule();
+ }
+
+ return KConfigDialog::hasChanged()
+ || (_editorPage->_kcfg_AutoCheckTools->selectedTools() != KBabelSettings::autoCheckTools())
+ || (module_ret);
+}
+
+bool KBabelPreferences::isDefault()
+{
+ bool old_useDefault = KBabelSettings::self()->useDefaults(true);
+
+ ModuleInfo *info = moduleList.at(_searchPage->_kcfg_DefaultModule->currentItem());
+ bool module_ret = ( info && info->id == KBabelSettings::defaultModule() );
+
+ bool ret = KConfigDialog::isDefault()
+ && (_editorPage->_kcfg_AutoCheckTools->selectedTools().empty())
+ && (module_ret);
+
+ KBabelSettings::self()->useDefaults(old_useDefault);
+ return ret;
+}
+
+void KBabelPreferences::updateSettings()
+{
+ KConfigDialog::updateSettings();
+
+ KBabelSettings::setAutoCheckTools(_editorPage->_kcfg_AutoCheckTools->selectedTools());
+
+ int i=_searchPage->_kcfg_DefaultModule->currentItem();
+ ModuleInfo *info = moduleList.at(i);
+
+ if(info)
+ {
+ KBabelSettings::setDefaultModule(info->id);
+ }
+
+ emit settingsChanged();
+}
+
+void KBabelPreferences::updateWidgets()
+{
+ KConfigDialog::updateWidgets();
+ _editorPage->_kcfg_AutoCheckTools->setSelectedTools(KBabelSettings::autoCheckTools());
+
+ int i=0;
+ ModuleInfo *info;
+ for(info = moduleList.first(); info != 0; info = moduleList.next())
+ {
+ if(KBabelSettings::defaultModule() == info->id)
+ break;
+
+ i++;
+ }
+ _searchPage->_kcfg_DefaultModule->setCurrentItem(i);
+}
+
+void KBabelPreferences::updateWidgetsDefault()
+{
+ KConfigDialog::updateWidgetsDefault();
+
+ bool old_useDefault = KBabelSettings::self()->useDefaults(true);
+
+ kdDebug () << "Default tools: " << KBabelSettings::autoCheckTools() << endl;
+
+ _editorPage->_kcfg_AutoCheckTools->setSelectedTools(KBabelSettings::autoCheckTools());
+
+ int i=0;
+ ModuleInfo *info;
+ for(info = moduleList.first(); info != 0; info = moduleList.next())
+ {
+ if(KBabelSettings::defaultModule() == info->id)
+ break;
+
+ i++;
+ }
+
+ _searchPage->_kcfg_DefaultModule->setCurrentItem(i);
+
+ KBabelSettings::self()->useDefaults(old_useDefault);
+}
+
+#include "kbabelpref.moc"
diff --git a/kbabel/kbabel/kbabelpref.h b/kbabel/kbabel/kbabelpref.h
new file mode 100644
index 00000000..a275e11e
--- /dev/null
+++ b/kbabel/kbabel/kbabelpref.h
@@ -0,0 +1,69 @@
+/* ****************************************************************************
+ This file is part of KBabel
+
+ Copyright (C) 1999-2000 by Matthias Kiefer
+ <matthias.kiefer@gmx.de>
+ 2004 by Stanislav Visnovsky
+ <visnovsky@kde.org>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the 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, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+ In addition, as a special exception, the copyright holders give
+ permission to link the code of this program with any edition of
+ the Qt library by Trolltech AS, Norway (or with modified versions
+ of Qt that use the same license as Qt), and distribute linked
+ combinations including the two. You must obey the GNU General
+ Public License in all respects for all of the code used other than
+ Qt. If you modify this file, you may extend this exception to
+ your version of the file, but you are not obligated to do so. If
+ you do not wish to do so, delete this exception statement from
+ your version.
+
+**************************************************************************** */
+#ifndef KBABELPREF_H
+#define KBABELPREF_H
+
+#include <kconfigdialog.h>
+#include <qptrlist.h>
+
+class SearchPreferences;
+class EditorPreferences;
+struct ModuleInfo;
+
+class KBabelPreferences : public KConfigDialog
+{
+ Q_OBJECT
+public:
+ KBabelPreferences(QPtrList<ModuleInfo>);
+
+protected slots:
+ virtual void slotHelp();
+ virtual void updateSettings();
+ virtual void updateWidgets();
+ virtual void updateWidgetsDefault();
+
+protected:
+ virtual bool hasChanged(); // reimplemented from KConfigDialog for our ToolSelectionWidget
+ virtual bool isDefault(); // reimplemented from KConfigDialog for our ToolSelectionWidget
+
+private:
+ SearchPreferences* _searchPage;
+ EditorPreferences* _editorPage;
+
+ QPtrList<ModuleInfo> moduleList;
+};
+
+
+#endif // KBABELPREF_H
diff --git a/kbabel/kbabel/kbabelsettings.kcfgc b/kbabel/kbabel/kbabelsettings.kcfgc
new file mode 100644
index 00000000..93c75552
--- /dev/null
+++ b/kbabel/kbabel/kbabelsettings.kcfgc
@@ -0,0 +1,5 @@
+File=kbabel.kcfg
+ClassName=KBabelSettings
+Singleton=true
+Mutators=true
+
diff --git a/kbabel/kbabel/kbabelsplash.cpp b/kbabel/kbabel/kbabelsplash.cpp
new file mode 100644
index 00000000..a13d8cd7
--- /dev/null
+++ b/kbabel/kbabel/kbabelsplash.cpp
@@ -0,0 +1,73 @@
+/*
+ *
+ * $Id$
+ * Copyright (C) 2003 Sebastian Trueg <trueg@k3b.org>
+ * 2003 Stanislav Visnovsky <visnovsky@kde.org>
+ *
+ * This file is part of the KBabel project. It's taken from the K3b project,
+ * Copyright (C) 1998-2003 Sebastian Trueg <trueg@k3b.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ * See the file "COPYING" for the exact licensing terms.
+
+ In addition, as a special exception, the copyright holders give
+ permission to link the code of this program with any edition of
+ the Qt library by Trolltech AS, Norway (or with modified versions
+ of Qt that use the same license as Qt), and distribute linked
+ combinations including the two. You must obey the GNU General
+ Public License in all respects for all of the code used other than
+ Qt. If you modify this file, you may extend this exception to
+ your version of the file, but you are not obligated to do so. If
+ you do not wish to do so, delete this exception statement from
+ your version.
+
+ */
+
+#include "kbabelsplash.h"
+
+#include <qapplication.h>
+#include <qlabel.h>
+#include <qpixmap.h>
+#include <qevent.h>
+#include <qstring.h>
+#include <qfontmetrics.h>
+#include <qpainter.h>
+
+#include <kstandarddirs.h>
+
+KBabelSplash* KBabelSplash::instance = 0;
+
+KBabelSplash::KBabelSplash( QWidget* parent, const char* name )
+ : QVBox( parent, name, WType_Dialog|WShowModal|WStyle_Customize|WStyle_NoBorder|WDestructiveClose )
+{
+ setMargin( 0 );
+ setSpacing( 0 );
+
+ QLabel* picLabel = new QLabel( this );
+ QPixmap pixmap;
+ if( pixmap.load( locate( "data", "kbabel/pics/splash.png" ) ) )
+ picLabel->setPixmap( pixmap );
+
+ picLabel->setFrameStyle(QFrame::WinPanel | QFrame::Raised);
+
+ // Set geometry, with support for Xinerama systems
+ QRect r;
+ r.setSize(sizeHint());
+ int ps = QApplication::desktop()->primaryScreen();
+ r.moveCenter( QApplication::desktop()->screenGeometry(ps).center() );
+ setGeometry(r);
+
+ delete instance;
+ instance = this;
+}
+
+
+void KBabelSplash::mousePressEvent( QMouseEvent* )
+{
+ close();
+}
+
+#include "kbabelsplash.moc"
diff --git a/kbabel/kbabel/kbabelsplash.h b/kbabel/kbabel/kbabelsplash.h
new file mode 100644
index 00000000..3ae14c9a
--- /dev/null
+++ b/kbabel/kbabel/kbabelsplash.h
@@ -0,0 +1,55 @@
+/*
+ *
+ * $Id$
+ * Copyright (C) 2003 Sebastian Trueg <trueg@k3b.org>
+ * 2003 Stanislav Visnovsky <visnovsky@kde.org>
+ *
+ * This file is part of the KBabel project. It's taken from the K3b project,
+ * Copyright (C) 1998-2003 Sebastian Trueg <trueg@k3b.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ * See the file "COPYING" for the exact licensing terms.
+
+ In addition, as a special exception, the copyright holders give
+ permission to link the code of this program with any edition of
+ the Qt library by Trolltech AS, Norway (or with modified versions
+ of Qt that use the same license as Qt), and distribute linked
+ combinations including the two. You must obey the GNU General
+ Public License in all respects for all of the code used other than
+ Qt. If you modify this file, you may extend this exception to
+ your version of the file, but you are not obligated to do so. If
+ you do not wish to do so, delete this exception statement from
+ your version.
+
+ */
+
+
+#ifndef KBABELSPLASH_H
+#define KBABELSPLASH_H
+
+#include <qvbox.h>
+
+class QLabel;
+class QMouseEvent;
+class QPaintEvent;
+class QString;
+
+
+class KBabelSplash : public QVBox
+{
+Q_OBJECT
+
+ public:
+ KBabelSplash( QWidget* parent = 0, const char* name = 0 );
+ ~KBabelSplash() { instance = 0; }
+
+ static KBabelSplash* instance;
+
+ protected:
+ void mousePressEvent( QMouseEvent* );
+};
+
+#endif
diff --git a/kbabel/kbabel/kbabelui.rc b/kbabel/kbabel/kbabelui.rc
new file mode 100644
index 00000000..40b52241
--- /dev/null
+++ b/kbabel/kbabel/kbabelui.rc
@@ -0,0 +1,235 @@
+<!DOCTYPE kpartgui>
+<kpartgui name="kbabel" version="21">
+ <MenuBar>
+ <Menu name="file"><text>&amp;File</text>
+ <Action name="save_special" append="save_merge"/>
+ <Action name="set_package" append="open_merge"/>
+ <Action name="file_new_view"/>
+ <Action name="file_new_window"/>
+ </Menu>
+ <Menu name="edit"><text>&amp;Edit</text>
+ <Action name="clear"/>
+ <Action name="msgid2msgstr"/>
+ <Action name="search2msgstr"/>
+ <Action name="plural2msgstr"/>
+ <Action name="char2msgstr"/>
+ <Action name="edit_toggle_fuzzy"/>
+ <Separator/>
+ <Action name="insert_next_tag"/>
+ <Action name="insert_next_tag_msgid"/>
+ <Action name="insert_tag"/>
+ <Action name="move_to_next_tag"/>
+ <Action name="move_to_prev_tag"/>
+ <Separator/>
+ <Action name="insert_next_arg"/>
+ <Action name="insert_arg"/>
+ <Separator/>
+ <Action name="edit_edit_header"/>
+ </Menu>
+ <Menu noMerge="1" name="go_document"><text>&amp;Go</text>
+ <Action name="go_prev_entry"/>
+ <Action name="go_next_entry"/>
+ <Action name="go_goto"/>
+ <Separator/>
+ <Action name="go_first"/>
+ <Action name="go_last"/>
+ <Separator/>
+ <Action name="go_prev_fuzzyUntr"/>
+ <Action name="go_next_fuzzyUntr"/>
+ <Action name="go_prev_fuzzy"/>
+ <Action name="go_next_fuzzy"/>
+ <Action name="go_prev_untrans"/>
+ <Action name="go_next_untrans"/>
+ <Separator/>
+ <Action name="go_prev_error"/>
+ <Action name="go_next_error"/>
+ <Separator/>
+ <Action name="go_back_history"/>
+ <Action name="go_forward_history"/>
+ </Menu>
+ <Menu name="projects"><text>&amp;Project</text>
+ <Action name="project_new"/>
+ <Action name="project_open"/>
+ <Action name="project_close"/>
+ <Action name="project_settings"/>
+ <Action name="recent_projects"/>
+ </Menu>
+ <Menu name="tools"><text>&amp;Tools</text>
+ <Menu name="spellcheck" icon="spellcheck"><text>&amp;Spelling</text>
+ <Action name="spellcheck_common"/>
+ <Separator/>
+ <Action name="spellcheck_all"/>
+ <Action name="spellcheck_from_cursor"/>
+ <Action name="spellcheck_current"/>
+ <Action name="spellcheck_from_current" />
+ <Action name="spellcheck_marked"/>
+ </Menu>
+ <Action name="dynamic_validation_tools"/>
+ <Menu name="diff" icon="diff"><text>D&amp;iff</text>
+ <Action name="diff_diff"/>
+ <Action name="diff_showOrig"/>
+ <Action name="diff_openFile"/>
+ <Separator/>
+ <Action name="diff_toggleDiff"/>
+ </Menu>
+ <Action name="dynamic_modify_tools"/>
+ <Separator/>
+ <Action name="rough_translation"/>
+ <Action name="word_count"/>
+ <Separator/>
+ <Action name="open_catalog_manager"/>
+ </Menu>
+ <Menu name="dictionaries"><text>&amp;Dictionaries</text>
+ <Action name="dict_search_all"/>
+ <Action name="dict_search_selected"/>
+ <Action name="dict_edit"/>
+ </Menu>
+ <Menu name="settings"><text>&amp;Settings</text>
+ <Action name="dict_configure" append="configure_merge"/>
+ </Menu>
+ <Menu name="bookmark"><text>&amp;Bookmarks</text>
+ <Action name="add_bookmark"/>
+ <Action name="clear_bookmarks"/>
+ <Separator/>
+ </Menu>
+ <Menu name="help"><text>&amp;Help</text>
+ <Action name="help_gettext"/>
+ <Action name="dict_about" append="about_merge"/>
+ </Menu>
+ </MenuBar>
+ <ToolBar name="mainToolBar"><text>Main</text>
+ <Action name="msgid2msgstr"/>
+ <Action name="search2msgstr"/>
+ <Action name="insert_tag"/>
+ <Action name="insert_arg"/>
+ <Separator/>
+ <Action name="spellcheck_common"/>
+ <Action name="diff_toggleDiff"/>
+ <Action name="dict_search_selected"/>
+ <Action name="stop_search"/>
+ <Separator/>
+ <Action name="open_catalog_manager"/>
+ </ToolBar>
+ <ToolBar name="navigationbar"><text>Navigationbar</text>
+ <Action name="go_prev_entry"/>
+ <Action name="go_next_entry"/>
+ <Separator/>
+ <Action name="go_first"/>
+ <Action name="go_last"/>
+ <Action name="go_prev_fuzzyUntr"/>
+ <Action name="go_next_fuzzyUntr"/>
+ <Action name="go_prev_fuzzy"/>
+ <Action name="go_next_fuzzy"/>
+ <Action name="go_prev_untrans"/>
+ <Action name="go_next_untrans"/>
+ <Separator/>
+ <Action name="go_prev_error"/>
+ <Action name="go_next_error"/>
+ <Separator/>
+ <Action name="go_back_history"/>
+ <Action name="go_forward_history"/>
+ </ToolBar>
+ <Menu name="rmb_edit">
+ <Action name="edit_undo"/>
+ <Action name="edit_redo"/>
+ <Separator/>
+ <Action name="edit_cut"/>
+ <Action name="edit_copy"/>
+ <Action name="edit_paste"/>
+ <Action name="edit_select_all"/>
+ <Separator/>
+ <Action name="msgid2msgstr"/>
+ <Action name="search2msgstr"/>
+ <Action name="edit_unset_fuzzy"/>
+ <Separator/>
+ <Action name="insert_next_tag"/>
+ <Action name="insert_tag"/>
+ <Separator/>
+ <Action name="dict_search_all"/>
+ <Action name="dict_search_selected"/>
+ </Menu>
+ <Menu name="rmb_search">
+ <Action name="edit_copy"/>
+ <Action name="search2msgstr"/>
+ <Separator/>
+ <Action name="dict_search_all"/>
+ <Action name="dict_search_selected"/>
+ <Separator/>
+ <Action name="dict_edit"/>
+ <Action name="dict_configure"/>
+ <Separator/>
+ <Action name="stop_search"/>
+ </Menu>
+ <State name="readonly">
+ <Disable>
+ <Action name="file_save"/>
+ <Action name="file_revert"/>
+ <Action name="edit_undo"/>
+ <Action name="edit_redo"/>
+ <Action name="edit_cut"/>
+ <Action name="edit_copy"/>
+ <Action name="edit_paste"/>
+ <Action name="edit_replace"/>
+ <Action name="insert_next_tag"/>
+ <Action name="insert_next_tag_msgid"/>
+ <Action name="insert_tag"/>
+ <Action name="insert_next_arg"/>
+ <Action name="insert_arg"/>
+ <Action name="plural2msgstr"/>
+ <Action name="char2msgstr"/>
+ <Action name="clear"/>
+ <Action name="msgid2msgstr"/>
+ <Action name="search2msgstr"/>
+ <Action name="edit_edit_header"/>
+ <Action name="edit_toggle_fuzzy"/>
+ <Action name="spellcheck_common"/>
+ <Action name="spellcheck_all"/>
+ <Action name="spellcheck_from_cursor"/>
+ <Action name="spellcheck_current"/>
+ <Action name="spellcheck_from_current" />
+ <Action name="spellcheck_marked"/>
+ <Action name="rough_translation"/>
+ </Disable>
+ </State>
+ <State name="fileopened">
+ <Enable>
+ <Action name="file_save_as"/>
+ <Action name="save_special"/>
+ <Action name="set_package"/>
+ <Action name="file_mail"/>
+ <Action name="edit_find"/>
+ <Action name="edit_find_next"/>
+ <Action name="edit_find_last"/>
+ <Action name="edit_select_all"/>
+ <Action name="move_to_next_tag"/>
+ <Action name="move_to_prev_tag"/>
+ <Action name="go_goto"/>
+ <Action name="go_prev_entry"/>
+ <Action name="go_next_entry"/>
+ <Action name="go_first"/>
+ <Action name="go_last"/>
+ <Action name="go_prev_fuzzyUntr"/>
+ <Action name="go_next_fuzzyUntr"/>
+ <Action name="go_prev_fuzzy"/>
+ <Action name="go_next_fuzzy"/>
+ <Action name="go_prev_untrans"/>
+ <Action name="go_next_untrans"/>
+ <Action name="go_prev_error"/>
+ <Action name="go_next_error"/>
+ <Action name="go_back_history"/>
+ <Action name="go_forward_history"/>
+ <Action name="dict_search_selected"/>
+ <Action name="dict_search_all"/>
+ <Action name="diff_toggleDiff"/>
+ <Action name="diff_diff"/>
+ <Action name="diff_showOrig"/>
+ <Action name="diff_openFile"/>
+ <Action name="check_syntax"/>
+ <Action name="check_all"/>
+ <Action name="dynamic_validation_tools"/>
+ <Action name="dynamic_modify_tools"/>
+ <Action name="add_bookmark"/>
+ <Action name="word_found"/>
+ </Enable>
+ </State>
+</kpartgui>
diff --git a/kbabel/kbabel/kbabelview.cpp b/kbabel/kbabel/kbabelview.cpp
new file mode 100644
index 00000000..2e9ebfa3
--- /dev/null
+++ b/kbabel/kbabel/kbabelview.cpp
@@ -0,0 +1,4473 @@
+/* ****************************************************************************
+ This file is part of KBabel
+
+ Copyright (C) 1999-2000 by Matthias Kiefer <matthias.kiefer@gmx.de>
+ 2002-2005 by Stanislav Visnovsky <visnovsky@kde.org>
+ Copyright (C) 2006 by Nicolas GOUTTE <goutte@kde.org>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the 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, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+ In addition, as a special exception, the copyright holders give
+ permission to link the code of this program with any edition of
+ the Qt library by Trolltech AS, Norway (or with modified versions
+ of Qt that use the same license as Qt), and distribute linked
+ combinations including the two. You must obey the GNU General
+ Public License in all respects for all of the code used other than
+ Qt. If you modify this file, you may extend this exception to
+ your version of the file, but you are not obligated to do so. If
+ you do not wish to do so, delete this exception statement from
+ your version.
+
+**************************************************************************** */
+
+#include "kbabelview.h"
+
+#include "catalogfileplugin.h"
+#include "toolaction.h"
+#include "kbabelsettings.h"
+#include "kbprojectsettings.h"
+
+#include <qlayout.h>
+
+#include <qlabel.h>
+#include <qframe.h>
+#include <qfileinfo.h>
+#include <qvariant.h>
+#include <qwhatsthis.h>
+#include <qdragobject.h>
+#include <qpopupmenu.h>
+#include <qstylesheet.h>
+#include <qtabwidget.h>
+#include <qtextview.h>
+#include <qtextstream.h>
+#include <qtimer.h>
+#include <qvbox.h>
+
+#include <dcopclient.h>
+#include <kdeversion.h>
+#include <kcharsets.h>
+#include <kcmenumngr.h>
+#include <kconfigdialog.h>
+#include <kdatatool.h>
+#include <kglobal.h>
+#include <klocale.h>
+#include <kmessagebox.h>
+#include <kcursor.h>
+#include <kfiledialog.h>
+#include <kconfig.h>
+#include <kapplication.h>
+#include <kled.h>
+#include <klistbox.h>
+#include <kio/netaccess.h>
+#include <knotifyclient.h>
+#include <ktempfile.h>
+#include <kspell.h>
+#include <kwin.h>
+#include <kstdaccel.h>
+#include <kurldrag.h>
+#include <kglobalsettings.h>
+
+#include "resources.h"
+
+#include "editcmd.h"
+#include "finddialog.h"
+#include "gotodialog.h"
+#include "headereditor.h"
+#include "hidingmsgedit.h"
+#include "kbabeldictbox.h"
+#include "kbcatalog.h"
+#include "msgfmt.h"
+#include "spelldlg.h"
+#include "regexpextractor.h"
+#include "projectprefwidgets.h"
+#include "kbabel.h"
+#include "kbprojectmanager.h"
+
+#include "commentview.h"
+#include "contextview.h"
+#include "kbcataloglistview.h"
+#include "charselectview.h"
+#include "taglistview.h"
+#include "sourceview.h"
+#include "errorlistview.h"
+
+#include "version.h"
+
+
+#define ID_DROP_OPEN 1
+#define ID_DROP_OPEN_TEMPLATE 2
+
+#define MAX_HISTORY 50
+
+using namespace KBabel;
+
+QPtrList<KBabelView> *KBabelView::viewList = 0;
+
+KBabelView::KBabelView(KBCatalog* catalog,KBabelMW *parent, Project::Ptr project)
+ : QWidget(parent)
+ , _redirectedBackSearch (false)
+ , _project (project)
+ , m_mainwindow (parent)
+ , m_sourceview (0)
+{
+ if(!viewList)
+ viewList = new QPtrList<KBabelView>;
+
+ viewList->append(this);
+
+ if (catalog == 0)
+ kdFatal(KBABEL) << "catalog==0" << endl;
+
+ _catalog=catalog;
+ _catalog->registerView(this);
+
+ _config = KSharedConfig::openConfig ("kbabelrc");
+
+ KConfigGroupSaver gs(_config,"Editor");
+ bool buildLeds=! KBabelSettings::ledInStatusbar();
+
+ _fuzzyLed=0;
+ _untransLed=0;
+ _errorLed=0;
+ _currentIndex=0;
+ _currentPos.item=1; // to ensure update
+ _currentPos.form=0;
+ _gotoDialog=0;
+ _findDialog=0;
+ _replaceDialog=0;
+ _replaceAskDialog=0;
+ _tagsMenu=0;
+ _argsMenu=0;
+ _autoSearchTempDisabled=false;
+ _diffEnabled=false;
+ _loadingDiffFile=false;
+ _diffing=false;
+ _dontBeep=false;
+
+ m_overwrite = false;
+
+ autoSaveTimer = 0;
+
+ _showTryLaterBox=true;
+ _tagExtractor = new RegExpExtractor( catalog->tagSettings().tagExpressions );
+ _argExtractor = new RegExpExtractor( catalog->tagSettings().argExpressions );
+
+ _editingDocumentation=false;
+
+ _autocheckTools.clear();
+ _autocheckTools.setAutoDelete(true);
+
+ spell.posDict.setAutoDelete(true);
+ spell.active=false;
+
+ spell2.kspell = 0;
+ spell2.config = 0;
+
+ setAcceptDrops(true);
+
+ // this widget does not contain anything, we should hide it
+ hide();
+
+ dictBox = new KBabelDictBox(this,"dictBox");
+ QWhatsThis::add(dictBox,
+ i18n("<qt><p><b>Search results</b></p>"
+ "<p>This part of the window shows the results of searching in "
+ "dictionaries.<p>"
+ "<p>In the top is displayed the number of entries found and "
+ "where the currently displayed entry is found. Use the buttons "
+ "at the bottom to navigate through the search results.</p>"
+ "<p>Search is either started automatically when switching to "
+ "another entry in the editor window or by choosing the desired "
+ "dictionary in <b>Dictionaries->Find...</b>.</p>"
+ "<p>The common options can be configured in the preferences dialog "
+ "in section <b>Search</b> and the options for the different "
+ "dictionaries can be changed with "
+ "<b>Settings->Configure Dictionary</b>.</p></qt>"));
+
+ initDockWidgets();
+
+ msgstrEdit->setReadOnly(true);
+ dictBox->setEnabled(false);
+
+ connect(this, SIGNAL(signalNewFileOpened(KURL)),
+ m_cataloglistview, SLOT(slotNewFileOpened()));
+
+ connect(msgstrEdit,SIGNAL(signalUndoCmd(KBabel::EditCommand*)),this,SLOT(forwardMsgstrEditCmd(KBabel::EditCommand*)));
+ connect(msgstrEdit,SIGNAL(textChanged()),this
+ ,SIGNAL(signalMsgstrChanged()));
+
+ connect(msgstrEdit,SIGNAL(textChanged(const QString&)),m_cataloglistview
+ ,SLOT(msgstrChanged(const QString&)));
+
+ connect(this,SIGNAL(signalMsgstrChanged()),this,SLOT(autoCheck()));
+ connect(msgstrEdit,SIGNAL(currentFormChanged(uint)), this
+ ,SLOT(msgstrPluralFormChanged(uint)));
+
+ connect(msgidLabel,SIGNAL(cursorPositionChanged(int,int))
+ , this, SIGNAL(signalCursorPosChanged(int,int)));
+ connect(msgstrEdit,SIGNAL(cursorPositionChanged(int,int))
+ , this, SIGNAL(signalCursorPosChanged(int,int)));
+
+ connect(dictBox,SIGNAL(searchStarted()),this
+ ,SLOT(forwardSearchStart()));
+ connect(dictBox, SIGNAL(progressStarts(const QString&)), this
+ ,SLOT(forwardProgressStart(const QString&)));
+ connect(dictBox,SIGNAL(progressed(int)),this
+ ,SIGNAL(signalProgress(int)));
+ connect(dictBox,SIGNAL(searchStopped()),this
+ ,SLOT(forwardSearchStop()));
+ connect(dictBox,SIGNAL(progressEnds()),this
+ ,SIGNAL(signalClearProgressBar()));
+
+ connect(dictBox,SIGNAL(modulesChanged()),this,
+ SIGNAL(signalDictionariesChanged()));
+ connect(dictBox,SIGNAL(errorInModule(const QString&)),this
+ ,SLOT(showError(const QString&)));
+
+ connect(_catalog,SIGNAL(signalSettingsChanged(KBabel::IdentitySettings)),
+ this, SLOT(setNewLanguage()));
+
+ connect(_catalog,SIGNAL(signalNumberOfFuzziesChanged(uint)),
+ this, SLOT(checkFuzzies()));
+ connect(_catalog,SIGNAL(signalNumberOfUntranslatedChanged(uint)),
+ this, SLOT(checkUntranslated()));
+
+ if(buildLeds)
+ {
+ connect(this,SIGNAL(signalFuzzyDisplayed(bool))
+ ,this,SLOT(toggleFuzzyLed(bool)));
+ connect(this,SIGNAL(signalUntranslatedDisplayed(bool))
+ ,this,SLOT(toggleUntransLed(bool)));
+ connect(this,SIGNAL(signalFaultyDisplayed(bool))
+ ,this,SLOT(toggleErrorLed(bool)));
+ }
+
+ _dropMenu = new QPopupMenu(this);
+ _dropMenu->insertItem(i18n("Menu item", "Open"),ID_DROP_OPEN);
+ _dropMenu->insertItem(i18n("Open Template"),ID_DROP_OPEN_TEMPLATE);
+
+ readSettings(_config);
+ readProject(_project);
+
+ connect (project, SIGNAL(signalSpellcheckSettingsChanged()),
+ this, SLOT(updateProjectSettings()));
+
+ if(!_catalog->currentURL().isEmpty())
+ {
+ newFileOpened(_catalog->isReadOnly());
+ }
+
+ // take over the language settings from the catalog
+ setNewLanguage();
+}
+
+KBabelView::~KBabelView()
+{
+ viewList->remove(this);
+ if(viewList->isEmpty())
+ {
+ delete viewList;
+ viewList=0;
+ }
+
+ _catalog->removeView(this);
+
+ // check if this view was the last view and delete the catalog if necessary
+ if(!_catalog->hasView())
+ {
+ delete _catalog;
+ }
+
+ delete _argExtractor;
+ delete _tagExtractor;
+
+ if( spell2.kspell )
+ {
+ spell2.kspell = 0;
+ delete spell2.config;
+ spell2.config = 0;
+ }
+}
+
+void KBabelView::initDockWidgets()
+{
+ // setup main dock widget - original text
+ QWidget *tempWidget=new QWidget(this,"msgidWidget");
+ tempWidget->setMinimumSize(350,150);
+
+ QVBoxLayout *layout=new QVBoxLayout(tempWidget);
+
+ msgidLabel = new HidingMsgEdit(2, this, 0, tempWidget,"msgidLabel");
+ msgidLabel->installEventFilter(this);
+ msgidLabel->setReadOnly(true);
+ msgidLabel->setDiffMode(true);
+ KCursor::setAutoHideCursor(msgidLabel,true);
+
+ msgidLabel->setText(i18n("KBabel Version %1\n"
+"Copyright 1999-%2 by KBabel developers.\n"
+" Matthias Kiefer <kiefer@kde.org>\n"
+" Stanislav Visnovsky <visnovsky@kde.org>\n"
+" Marco Wegner <dubbleu@web.de>\n"
+" Dwayne Bailey <dwayne@translate.org.za>\n"
+" Andrea Rizzi <rizzi@kde.org>\n\n"
+"Any comments, suggestions, etc. should be sent to the mailing list <kbabel@kde.org>.\n\n"
+"This program is licensed under the terms of the GNU GPL.\n\n"
+"Special thanks to Thomas Diehl for many hints to the GUI\n"
+"and the behavior of KBabel and to Stephan Kulow, who always\n"
+"lends me a helping hand.\n\n"
+"Many good ideas, especially for the Catalog Manager, are taken\n"
+"from KTranslator by Andrea Rizzi.").arg(VERSION).arg(2006));
+
+ QLabel *label=new QLabel(msgidLabel,i18n("O&riginal string (msgid):"),tempWidget);
+
+ QHBoxLayout* hb=new QHBoxLayout(layout);
+ hb->addSpacing(KDialog::marginHint());
+ hb->addWidget(label);
+
+ layout->addWidget(msgidLabel);
+ layout->setStretchFactor(msgidLabel,1);
+
+ QWhatsThis::add(tempWidget,
+ i18n("<qt><p><b>Original String</b></p>\n\
+<p>This part of the window shows the original message\n\
+of the currently displayed entry.</p></qt>"));
+
+ KDockWidget* mainDock;
+ mainDock = m_mainwindow->createDockWidget( "Original", QPixmap ());
+ //i18n: translators: Dock window caption
+ mainDock->setCaption(i18n("Original Text"));
+ mainDock->setGeometry(50, 50, 100, 100);
+ // forbit docking abilities of mainDock itself
+ mainDock->setEnableDocking(KDockWidget::DockFullSite);
+
+ mainDock->setWidget(tempWidget);
+ m_mainwindow->setMainDockWidget(mainDock); // master dockwidget
+ mainDock->show ();
+ m_mainwindow->setView (mainDock);
+ connect (this, SIGNAL (signalCopy ()), this, SLOT (textCopy ()));
+ connect (this, SIGNAL (signalCut ()), this, SLOT (textCut ()));
+ connect (this, SIGNAL (signalPaste ()), this, SLOT (textPaste ()));
+ connect (this, SIGNAL (signalSelectAll ()), this, SLOT (selectAll ()));
+
+ KDockWidget* comment_dock = m_mainwindow->createDockWidget( "Comment", QPixmap ());
+ //i18n: translators: Dock window caption
+ comment_dock->setCaption(i18n("Comment"));
+ comment_dock->setGeometry(50, 50, 100, 100);
+ comment_dock->setEnableDocking(KDockWidget::DockCorner);
+ m_commentview = new CommentView(_catalog, comment_dock, _project);
+ comment_dock->setWidget(m_commentview);
+ comment_dock->manualDock( mainDock, // dock target
+ KDockWidget::DockRight, // dock site
+ 20 ); // relation target/this (in percent)
+ comment_dock->show ();
+ connect (this, SIGNAL (signalCopy ()), m_commentview, SLOT (textCopy ()));
+ connect (this, SIGNAL (signalCut ()), m_commentview, SLOT (textCut ()));
+ connect (this, SIGNAL (signalPaste ()), m_commentview, SLOT (textPaste ()));
+ connect (this, SIGNAL (signalSelectAll ()), m_commentview, SLOT (textSelectAll ()));
+ m_commentview->installEventFilter( this );
+
+ // build the msgstr widget
+ tempWidget=new QWidget(this,"msgstrWidget");
+ tempWidget->setMinimumSize(350,150);
+
+ layout=new QVBoxLayout(tempWidget);
+
+ // if undefined number of plural forms, use 1
+ int pf = _catalog->defaultNumberOfPluralForms();
+ if( pf < 1 )
+ pf = 1;
+
+ msgstrEdit = new HidingMsgEdit( pf,this,spell2.kspell,tempWidget,"msgstrEdit");
+ msgstrEdit->installEventFilter(this);
+ KCursor::setAutoHideCursor(msgstrEdit,true);
+
+ label=new QLabel(msgstrEdit,i18n("Trans&lated string (msgstr):"),tempWidget);
+
+ hb=new QHBoxLayout(layout);
+ hb->setSpacing(KDialog::spacingHint());
+
+ hb->addSpacing(KDialog::marginHint());
+ hb->addWidget(label);
+ hb->addStretch(1);
+
+ if(! KBabelSettings::ledInStatusbar())
+ {
+ _fuzzyLed = new KLed(Qt::red,KLed::Off,KLed::Sunken,KLed::Rectangular
+ ,tempWidget);
+ _fuzzyLed->setFixedSize(15,12);
+ label = new QLabel(i18n("fuzzy"),tempWidget);
+ hb->addWidget(_fuzzyLed);
+ hb->addWidget(label);
+
+ hb->addSpacing(KDialog::spacingHint());
+
+ _untransLed = new KLed(Qt::red,KLed::Off,KLed::Sunken,KLed::Rectangular
+ ,tempWidget);
+ _untransLed->setFixedSize(15,12);
+ label = new QLabel(i18n("untranslated"),tempWidget);
+ hb->addWidget(_untransLed);
+ hb->addWidget(label);
+
+ hb->addSpacing(KDialog::marginHint());
+
+ _errorLed = new KLed(Qt::red,KLed::Off,KLed::Sunken,KLed::Rectangular
+ ,tempWidget);
+ _errorLed->setFixedSize(15,12);
+ label = new QLabel(i18n("faulty"),tempWidget);
+ hb->addWidget(_errorLed);
+ hb->addWidget(label);
+
+ hb->addSpacing(KDialog::marginHint());
+
+ hb->addStretch(1);
+
+ // ### TODO: perhaps it should be moreprecise where the setting can be changed
+ QString ledMsg=i18n("<qt><p><b>Status LEDs</b></p>\n"
+ "<p>These LEDs display the status of the currently displayed message.\n"
+ "You can change their color in the preferences dialog section\n"
+ "<b>Editor</b> on page <b>Appearance</b></p></qt>");
+ QWhatsThis::add(_fuzzyLed,ledMsg);
+ QWhatsThis::add(_untransLed,ledMsg);
+ QWhatsThis::add(_errorLed,ledMsg);
+ }
+
+ layout->addWidget(msgstrEdit);
+ layout->setStretchFactor(msgstrEdit,1);
+
+ QWhatsThis::add(tempWidget,
+ i18n("<qt><p><b>Translation Editor</b></p>\n\
+<p>This editor displays and lets you edit the translation of the currently displayed message.<p></qt>"));
+
+
+ KDockWidget* msgstr_dock = m_mainwindow->createDockWidget( "Msgstr", QPixmap ());
+ //i18n: translators: Dock window caption
+ msgstr_dock->setCaption(i18n("Translated String"));
+ msgstr_dock->setEnableDocking(KDockWidget::DockCorner);
+ msgstr_dock->setWidget(tempWidget);
+ msgstr_dock->manualDock( mainDock, // dock target
+ KDockWidget::DockBottom, // dock site
+ 50 ); // relation target/this (in percent)
+ msgstr_dock->show ();
+
+ KDockWidget* dock = m_mainwindow->createDockWidget( "Search", QPixmap ());
+ //i18n: translators: Dock window caption
+ dock->setCaption(i18n("the search (noun)","Search"));
+ //i18n: translators: Dock tab caption
+ dock->setTabPageLabel(i18n("the search (noun)","Se&arch"));
+ dock->setGeometry(50, 50, 100, 100);
+ dock->setWidget(dictBox);
+ dock->manualDock( comment_dock, // dock target
+ KDockWidget::DockBottom, // dock site
+ 20 ); // relation target/this (in percent)
+ dock->show ();
+
+ KDockWidget* tools = dock;
+
+ dock = m_mainwindow->createDockWidget( "PO context", QPixmap ());
+ //i18n: translators: Dock window caption
+ dock->setCaption(i18n("PO Context"));
+ //i18n: translators: Dock tab caption
+ dock->setTabPageLabel(i18n("PO C&ontext"));
+ dock->setGeometry(50, 50, 100, 100);
+ ContextView * m_contextview = new ContextView(_catalog, dock, _project);
+ dock->setWidget(m_contextview);
+ dock->manualDock( tools, // dock target
+ KDockWidget::DockCenter, // dock site
+ 20 ); // relation target/this (in percent)
+ dock->show ();
+
+ dock = m_mainwindow->createDockWidget( "Charselector", QPixmap ());
+ //i18n: translators: Dock window caption
+ dock->setCaption(i18n("Character Table"));
+ //i18n: translators: Dock tab caption
+ dock->setTabPageLabel(i18n("C&hars"));
+ dock->setGeometry(50, 50, 100, 100);
+ m_charselectorview = new CharacterSelectorView(_catalog, dock, _project);
+ dock->setWidget(m_charselectorview);
+ dock->manualDock( tools, // dock target
+ KDockWidget::DockCenter, // dock site
+ 20 ); // relation target/this (in percent)
+ dock->show ();
+
+
+ dock = m_mainwindow->createDockWidget( "Tag List", QPixmap ());
+ //i18n: translators: Dock window caption
+ dock->setCaption(i18n("Tag List"));
+ //i18n: translators: Dock tab caption
+ dock->setTabPageLabel(i18n("Tags"));
+ dock->setGeometry(50, 50, 100, 100);
+ TagListView* m_taglistview = new TagListView(_catalog, dock, _project);
+ dock->setWidget(m_taglistview);
+ dock->manualDock( tools, // dock target
+ KDockWidget::DockCenter, // dock site
+ 20 ); // relation target/this (in percent)
+ dock->show ();
+
+ dock = m_mainwindow->createDockWidget( "Source Context", QPixmap ());
+ //i18n: translators: Dock window caption
+ dock->setCaption(i18n("Source Context"));
+ //i18n: translators: Dock tab caption
+ dock->setTabPageLabel(i18n("Source"));
+ dock->setGeometry(50, 50, 100, 100);
+ m_sourceview = new SourceView(_catalog, dock, _project);
+ dock->setWidget(m_sourceview);
+ dock->manualDock( tools, // dock target
+ KDockWidget::DockCenter, // dock site
+ 20 ); // relation target/this (in percent)
+ dock->show ();
+
+ KDockWidget* translist_dock = m_mainwindow->createDockWidget( "Translation List", QPixmap ());
+ translist_dock->setCaption(i18n("Translation List"));
+ translist_dock->setGeometry(50, 50, 100, 100);
+ translist_dock->setEnableDocking(KDockWidget::DockFullSite);
+ m_cataloglistview = new KBCatalogListView(_catalog, translist_dock, _project);
+ translist_dock->setWidget(m_cataloglistview);
+ translist_dock->manualDock( mainDock, KDockWidget::DockTop,100);
+ translist_dock->show ();
+
+ dock = m_mainwindow->createDockWidget( "Error List", QPixmap ());
+ //i18n: translators: Dock window caption
+ dock->setCaption(i18n("Error List"));
+ //i18n: translators: Dock tab caption
+ dock->setTabPageLabel(i18n("Errors"));
+ dock->setGeometry(50, 50, 100, 100);
+ ErrorListView* m_errorlistview = new ErrorListView(_catalog, dock, _project);
+ dock->setWidget(m_errorlistview);
+ dock->manualDock( tools, // dock target
+ KDockWidget::DockCenter, // dock site
+ 20 );
+ dock->show ();
+
+ connect(m_cataloglistview,SIGNAL(signalSelectionChanged(const KBabel::DocPosition&))
+ ,this,SLOT(gotoEntry(const KBabel::DocPosition&)));
+ connect(this,SIGNAL(signalDisplayed(const KBabel::DocPosition&))
+ ,m_commentview,SLOT(gotoEntry(const KBabel::DocPosition&)));
+ connect(this,SIGNAL(signalDisplayed(const KBabel::DocPosition&))
+ ,m_contextview,SLOT(gotoEntry(const KBabel::DocPosition&)));
+ connect(this,SIGNAL(signalDisplayed(const KBabel::DocPosition&))
+ ,m_taglistview,SLOT(gotoEntry(const KBabel::DocPosition&)));
+ connect(this,SIGNAL(signalDisplayed(const KBabel::DocPosition&))
+ ,m_sourceview,SLOT(gotoEntry(const KBabel::DocPosition&)));
+ connect(this,SIGNAL(signalDisplayed(const KBabel::DocPosition&))
+ ,m_errorlistview,SLOT(gotoEntry(const KBabel::DocPosition&)));
+ connect(this,SIGNAL(signalFaultyDisplayed(bool))
+ ,m_errorlistview,SLOT(updateView()));
+ connect(m_charselectorview, SIGNAL( characterDoubleClicked(QChar) )
+ ,this, SLOT( insertChar(QChar) ));
+ connect(m_taglistview,SIGNAL(signalTagSelected(const QString&))
+ , this, SLOT(insertTagFromTool(const QString&)));
+ connect(m_taglistview,SIGNAL(signalHighlightedTagChanged(int))
+ , this, SLOT(skipToTagFromTool(int)));
+ connect(this, SIGNAL(signalNextTag(int))
+ , m_taglistview, SLOT(highlightTag(int)));
+ connect(m_commentview,SIGNAL(signalCursorPosChanged(int,int))
+ , m_mainwindow, SLOT(updateCursorPosition(int,int)));
+}
+
+KBabelView *KBabelView::viewForURL(const KURL& url, const QString project)
+{
+ if(url.isEmpty())
+ return 0;
+
+ if(!viewList)
+ return 0;
+
+ KURL u = url;
+ u.cleanPath();
+
+ QPtrListIterator<KBabelView> it(*viewList);
+ KBabelView *view=0;
+ while( it.current() && !view)
+ {
+ KURL cu = it.current()->currentURL();
+ cu.cleanPath();
+
+ if(cu == u && it.current()->project()==project)
+ {
+ view = it.current();
+ }
+
+ ++it;
+ }
+
+ return view;
+}
+
+KBabelView *KBabelView::emptyView(const QString)
+{
+ if(!viewList)
+ return 0;
+
+ QPtrListIterator<KBabelView> it(*viewList);
+ KBabelView *view=0;
+ while( it.current() && !view)
+ {
+ KURL cu = it.current()->currentURL();
+ if( cu.isEmpty() )
+ return it.current();
+ ++it;
+ }
+
+ return 0;
+}
+
+KURL KBabelView::currentURL() const
+{
+ return _catalog->currentURL();
+}
+
+bool KBabelView::isLastView() const
+{
+ return _catalog->isLastView();
+}
+
+bool KBabelView::isModified() const
+{
+ return _catalog->isModified();
+}
+
+bool KBabelView::isReadOnly() const
+{
+ return _catalog->isReadOnly();
+}
+
+bool KBabelView::isOverwriteMode() const
+{
+ return m_overwrite;
+}
+
+
+void KBabelView::setOverwriteMode(bool ovr)
+{
+ m_overwrite = ovr;
+ msgstrEdit->setOverwriteMode(ovr);
+ m_commentview->setOverwriteMode(ovr);
+}
+
+
+bool KBabelView::isSearching() const
+{
+ return dictBox->isSearching();
+}
+
+
+void KBabelView::update(EditCommand* cmd, bool undo)
+{
+ if((int)_currentIndex==cmd->index())
+ {
+ emitEntryState();
+
+ if(cmd->part()==Msgstr)
+ {
+ msgstrEdit->processCommand(cmd,undo);
+ emit signalMsgstrChanged();
+ }
+ }
+}
+
+
+
+void KBabelView::readSettings(KConfig* config)
+{
+
+ if(KBabelSettings::autoUnsetFuzzy())
+ {
+ connect(msgstrEdit,SIGNAL(textChanged())
+ ,this,SLOT(autoRemoveFuzzyStatus()));
+ }
+
+ setupAutoCheckTools();
+
+ KConfigGroupSaver saver(config,"Editor");
+
+ _diffEnabled = config->readBoolEntry("AutoDiff", false);
+ emit signalDiffEnabled(_diffEnabled);
+
+ if(_fuzzyLed)
+ {
+ _fuzzyLed->setColor(KBabelSettings::ledColor());
+ }
+ if(_untransLed)
+ {
+ _untransLed->setColor(KBabelSettings::ledColor());
+ }
+ if(_errorLed)
+ {
+ _errorLed->setColor(KBabelSettings::ledColor());
+ }
+
+ msgstrEdit->setCleverEditing(KBabelSettings::cleverEditing());
+
+ msgstrEdit->setHighlightBg(KBabelSettings::highlightBackground());
+ msgidLabel->setHighlightBg(KBabelSettings::highlightBackground());
+
+ msgstrEdit->setHighlightSyntax(KBabelSettings::highlightSyntax());
+ msgidLabel->setHighlightSyntax(KBabelSettings::highlightSyntax());
+
+ msgstrEdit->setQuotes(KBabelSettings::enableQuotes());
+ msgidLabel->setQuotes(KBabelSettings::enableQuotes());
+
+ msgstrEdit->setSpacePoints(KBabelSettings::whitespacePoints());
+ msgidLabel->setSpacePoints(KBabelSettings::whitespacePoints());
+
+ msgstrEdit->setFont(KBabelSettings::msgFont());
+ msgidLabel->setFont(KBabelSettings::msgFont());
+
+ msgstrEdit->setBgColor(KBabelSettings::backgroundColor());
+ msgidLabel->setBgColor(KBabelSettings::backgroundColor());
+
+ msgstrEdit->setHighlightColors(KBabelSettings::quotedColor(),KBabelSettings::errorColor()
+ ,KBabelSettings::cformatColor(),KBabelSettings::accelColor(),KBabelSettings::tagColor());
+ msgidLabel->setHighlightColors(KBabelSettings::quotedColor(),KBabelSettings::errorColor()
+ ,KBabelSettings::cformatColor(),KBabelSettings::accelColor(),KBabelSettings::tagColor());
+
+ msgidLabel->setDiffDisplayMode( KBabelSettings::diffAddUnderline()
+ ,KBabelSettings::diffDelStrikeOut() );
+ msgidLabel->setDiffColors(KBabelSettings::diffAddColor(), KBabelSettings::diffDelColor() );
+}
+
+void KBabelView::updateProjectSettings()
+{
+ readProject(_project);
+}
+
+void KBabelView::readProject(Project::Ptr project)
+{
+ _spellcheckSettings = project->spellcheckSettings();
+
+ if( _spellcheckSettings.onFlySpellcheck )
+ {
+
+ // if there is a spellchecker already, free it
+ if( spell2.kspell )
+ {
+ // ensure the spellchecker is not used anymore
+ msgstrEdit->setSpellChecker(0L);
+
+ // free it
+ spell2.kspell->cleanUp();
+
+ delete spell2.kspell;
+ spell2.kspell = 0;
+ }
+
+ spell2.config = new KSpellConfig(0L, "tempSpellConfig");
+ spell2.config->setNoRootAffix(_spellcheckSettings.noRootAffix);
+ spell2.config->setRunTogether(_spellcheckSettings.runTogether);
+ spell2.config->setClient(_spellcheckSettings.spellClient);
+ spell2.config->setEncoding(_spellcheckSettings.spellEncoding);
+ spell2.config->setDictionary(_spellcheckSettings.spellDict);
+
+ spell2.kspell= new KSpell(this, "", this, SLOT(dummy(KSpell *)),
+ spell2.config, false, false);
+ if(spell2.kspell->status() == KSpell::Error)
+ kdWarning(KBABEL) << "Something's wrong with KSpell, can't start on-the-fly checking" << endl;
+ else
+ {
+ kdDebug() << "On the fly spellchecker: "
+ << spell2.kspell << endl;
+ msgstrEdit->setSpellChecker(spell2.kspell);
+ }
+
+ // spell2.kspell->setAutoDelete(true); // let KSpell handle delete
+ //on-the-fly spellcheck end
+ }
+ else
+ {
+ // turn off spellchecker
+ msgstrEdit->setSpellChecker(0);
+ // invalidate the current settings, to make sure they are updated when needed
+ _spellcheckSettings.valid = false;
+ }
+
+ dictBox->readSettings(project->config());
+
+ m_sourceview->setProject(project);
+}
+
+void KBabelView::saveSettings()
+{
+ KConfigGroupSaver saver(_config,"Editor");
+
+ _config->writeEntry("AutoDiff",_diffEnabled);
+
+ dictBox->saveSettings( _project->config() );
+
+ _catalog->savePreferences();
+
+ _config->sync();
+ _project->config()->sync();
+
+ KBabelSettings::writeConfig();
+}
+
+void KBabelView::updateSettings()
+{
+ msgstrEdit->setFont(KBabelSettings::msgFont());
+ msgidLabel->setFont(KBabelSettings::msgFont());
+
+ msgidLabel->setDiffDisplayMode( KBabelSettings::diffAddUnderline()
+ ,KBabelSettings::diffDelStrikeOut());
+ msgidLabel->setDiffColors(KBabelSettings::diffAddColor(), KBabelSettings::diffDelColor());
+
+ if( _diffEnabled && !_catalog->currentURL().isEmpty() )
+ {
+ diffShowOrig ();
+ diff();
+ }
+
+ msgstrEdit->setBgColor(KBabelSettings::backgroundColor());
+ msgidLabel->setBgColor(KBabelSettings::backgroundColor());
+
+ msgstrEdit->setHighlightColors(KBabelSettings::quotedColor(),KBabelSettings::errorColor()
+ ,KBabelSettings::cformatColor(),KBabelSettings::accelColor(),KBabelSettings::tagColor());
+ msgidLabel->setHighlightColors(KBabelSettings::quotedColor(),KBabelSettings::errorColor()
+ ,KBabelSettings::cformatColor(),KBabelSettings::accelColor(),KBabelSettings::tagColor());
+
+ msgidLabel->setDiffDisplayMode( KBabelSettings::diffAddUnderline()
+ ,KBabelSettings::diffDelStrikeOut());
+ msgidLabel->setDiffColors(KBabelSettings::diffAddColor(), KBabelSettings::diffDelColor());
+
+ if(_fuzzyLed)
+ {
+ _fuzzyLed->setColor(KBabelSettings::ledColor());
+ }
+ if(_untransLed)
+ {
+ _untransLed->setColor(KBabelSettings::ledColor());
+ }
+ if(_errorLed)
+ {
+ _errorLed->setColor(KBabelSettings::ledColor());
+ }
+
+ disconnect(msgstrEdit,SIGNAL(textChanged())
+ ,this,SLOT(autoRemoveFuzzyStatus()));
+
+ if(KBabelSettings::autoUnsetFuzzy())
+ {
+ connect(msgstrEdit,SIGNAL(textChanged())
+ ,this,SLOT(autoRemoveFuzzyStatus()));
+ }
+
+ msgstrEdit->setCleverEditing(KBabelSettings::cleverEditing());
+
+ msgstrEdit->setHighlightBg(KBabelSettings::highlightBackground());
+ msgidLabel->setHighlightBg(KBabelSettings::highlightBackground());
+ msgstrEdit->setHighlightSyntax(KBabelSettings::highlightSyntax());
+ msgidLabel->setHighlightSyntax(KBabelSettings::highlightSyntax());
+
+ msgstrEdit->setQuotes(KBabelSettings::enableQuotes());
+ msgidLabel->setQuotes(KBabelSettings::enableQuotes());
+
+ msgstrEdit->setSpacePoints(KBabelSettings::whitespacePoints());
+ msgidLabel->setSpacePoints(KBabelSettings::whitespacePoints());
+
+ msgstrEdit->setFont(KBabelSettings::msgFont());
+ msgidLabel->setFont(KBabelSettings::msgFont());
+
+ msgstrEdit->setBgColor(KBabelSettings::backgroundColor());
+ msgidLabel->setBgColor(KBabelSettings::backgroundColor());
+
+ msgstrEdit->setHighlightColors(KBabelSettings::quotedColor(),KBabelSettings::errorColor()
+ ,KBabelSettings::cformatColor(),KBabelSettings::accelColor(),KBabelSettings::tagColor());
+ msgidLabel->setHighlightColors(KBabelSettings::quotedColor(),KBabelSettings::errorColor()
+ ,KBabelSettings::cformatColor(),KBabelSettings::accelColor(),KBabelSettings::tagColor());
+
+ msgidLabel->setDiffDisplayMode( KBabelSettings::diffAddUnderline()
+ ,KBabelSettings::diffDelStrikeOut());
+ msgidLabel->setDiffColors(KBabelSettings::diffAddColor(), KBabelSettings::diffDelColor());
+
+ // if errors should not use special color, reset the color of the text
+ if(! KBabelSettings::autoCheckColorError())
+ {
+ msgstrEdit->setCurrentColor( MsgMultiLineEdit::NormalColor);
+ }
+
+ if(_fuzzyLed)
+ {
+ _fuzzyLed->setColor(KBabelSettings::ledColor());
+ }
+ if(_untransLed)
+ {
+ _untransLed->setColor(KBabelSettings::ledColor());
+ }
+ if(_errorLed)
+ {
+ _errorLed->setColor(KBabelSettings::ledColor());
+ }
+
+ emit ledColorChanged(KBabelSettings::ledColor());
+
+ setupAutoCheckTools();
+
+ if( _catalog->numberOfEntries() > 0 )
+ autoCheck(false);
+
+}
+
+void KBabelView::setupAutoCheckTools()
+{
+ _autocheckTools.clear();
+
+ kdDebug () << "Autocheck tools: " << KBabelSettings::autoCheckTools().join(",") << endl;
+
+ if(!KBabelSettings::autoCheckTools().isEmpty() )
+ {
+ QValueList<KDataToolInfo> tools = ToolAction::validationTools();
+
+ QValueList<KDataToolInfo>::Iterator it;
+ for( it=tools.begin(); it!=tools.end() ; ++it )
+ {
+ if(KBabelSettings::autoCheckTools().contains((*it).service()->library()) )
+ {
+ // maybe we can reuse the tools
+ KDataTool* t = (*it).createTool();
+
+ if( t ) _autocheckTools.append( t );
+ }
+ }
+ }
+}
+
+void KBabelView::setRMBEditMenu(QPopupMenu* popup)
+{
+ msgidLabel->setContextMenu( popup );
+ msgstrEdit->setContextMenu( popup );
+ KContextMenuManager::insert(this,popup);
+}
+
+void KBabelView::setRMBSearchMenu(QPopupMenu* popup)
+{
+ dictBox->setRMBMenu(popup);
+}
+
+
+void KBabelView::saveView(KConfig *)
+{
+}
+
+void KBabelView::restoreView(KConfig *)
+{
+}
+
+void KBabelView::saveSession(KConfig* config)
+{
+ QString focus;
+ int line=0,col=0;
+ if(msgstrEdit->hasFocus())
+ {
+ focus="msgstr";
+ msgstrEdit->getCursorPosition(&line,&col);
+ }
+ else if(msgidLabel->hasFocus())
+ {
+ focus="msgid";
+ msgidLabel->getCursorPosition(&line,&col);
+ }
+ else if(dictBox->hasFocus())
+ {
+ focus="searchbox";
+ }
+
+ config->writeEntry("Focus",focus);
+ config->writeEntry("CursorLine",line);
+ config->writeEntry("CursorCol",col);
+ config->writeEntry("Index",_currentIndex);
+ config->writeEntry("PluralForm",_currentPos.form);
+
+ config->writePathEntry("URL",currentURL().url());
+
+ config->writeEntry("AutoDiff",_diffEnabled);
+
+ if( _spellcheckSettings.valid )
+ {
+ KConfigGroupSaver (config, "Spellcheck");
+ config->writeEntry("NoRootAffix",_spellcheckSettings.noRootAffix);
+ config->writeEntry("RunTogether",_spellcheckSettings.runTogether);
+ config->writeEntry("SpellEncoding",_spellcheckSettings.spellEncoding);
+ config->writeEntry("SpellClient",_spellcheckSettings.spellClient);
+ config->writeEntry("SpellDictionary",_spellcheckSettings.spellDict);
+ config->writeEntry("RememberIgnored",_spellcheckSettings.rememberIgnored);
+ config->writePathEntry("IgnoreURL",_spellcheckSettings.ignoreURL);
+ }
+
+ saveView(config);
+}
+
+void KBabelView::restoreSession(KConfig* config)
+{
+ QString url=config->readPathEntry("URL");
+
+ if(!url.isEmpty())
+ {
+ open(KURL( url ), QString::null, false,true);
+ }
+
+
+ _diffEnabled = config->readBoolEntry("AutoDiff", false);
+ emit signalDiffEnabled(_diffEnabled);
+
+ msgidLabel->setDiffDisplayMode( KBabelSettings::diffAddUnderline()
+ , KBabelSettings::diffDelStrikeOut() );
+ msgidLabel->setDiffColors( KBabelSettings::diffAddColor()
+ , KBabelSettings::diffDelColor() );
+
+ // go to last displayed entry
+ DocPosition pos;
+ pos.item=config->readNumEntry("Index");
+ pos.form=config->readNumEntry("PluralForm");
+ gotoEntry(pos);
+
+ QString focus=config->readEntry("Focus");
+ int line=config->readNumEntry("CursorLine");
+ int col=config->readNumEntry("CursorCol");
+ if(focus=="msgstr")
+ {
+ msgstrEdit->setFocus();
+ msgstrEdit->setCursorPosition(line,col);
+ }
+ else if(focus=="msgid")
+ {
+ msgidLabel->setFocus();
+ msgstrEdit->setCursorPosition(line,col);
+ }
+ else if(focus=="searchbox")
+ {
+ dictBox->setFocus();
+ }
+
+ restoreView(config);
+}
+
+void KBabelView::newFileOpened(bool readOnly)
+{
+ // disable editing for empty files
+ if(_catalog->numberOfEntries() == 0)
+ readOnly = true;
+
+ if(_gotoDialog)
+ {
+ _gotoDialog->setMax(_catalog->numberOfEntries());
+ }
+
+ dictBox->setDisabled(readOnly);
+ msgstrEdit->setReadOnly(readOnly);
+ msgstrEdit->setFocus();
+
+ QString caption=_catalog->package();
+ if(readOnly)
+ caption+=i18n(" [readonly]");
+ emit signalChangeCaption(caption);
+ emit signalNewFileOpened(_catalog->currentURL());
+
+ dictBox->setEditedPackage(_catalog->packageDir()+_catalog->packageName());
+ dictBox->setEditedFile(_catalog->currentURL().url());
+
+ _editingDocumentation = _catalog->isGeneratedFromDocbook();
+
+ _backHistory.clear();
+ emit signalBackHistory(false);
+ _forwardHistory.clear();
+ emit signalForwardHistory(false);
+
+ DocPosition pos;
+ pos.item=0;
+ pos.form=0;
+ _autoSearchTempDisabled=true;
+ gotoEntry(pos,false);
+ _autoSearchTempDisabled=false;
+
+ emit signalDisplayed(pos);
+
+ if(isActiveWindow() && KBabelSettings::autoSearch())
+ {
+ startSearch(true);
+ }
+}
+
+void KBabelView::open()
+{
+ open(KURL());
+}
+
+void KBabelView::open(const KURL& _url, const QString & package, bool checkIfModified, bool newView)
+{
+#if KDE_IS_VERSION( 3, 5, 0)
+ KURL url = KIO::NetAccess::mostLocalURL(_url,this);
+#else
+ KURL url = _url;
+#endif
+ url.cleanPath();
+
+ KURL cu = currentURL();
+ cu.cleanPath();
+ if(checkIfModified && !url.isEmpty() && cu==url)
+ {
+ KWin::activateWindow(topLevelWidget()->winId());
+ return;
+ }
+
+ stopSearch();
+
+ if(!checkIfModified || checkModified())
+ {
+ if(url.isEmpty())
+ {
+ QString filename;
+ if ((url = KFileDialog::getOpenURL(currentURL().url(), CatalogImportPlugin::availableImportMimeTypes().join(" ")
+ ,this)).isEmpty())
+ {
+ return;
+ }
+ }
+ // deactive editor
+ /*setEnabled(false);
+ setCursor(KCursor::waitCursor());*/
+
+ KBabelView *v = viewForURL(url,_project->filename());
+
+ if(v && v != this)
+ {
+ if( newView )
+ {
+ // unregister old catalog
+ _catalog->removeView(this);
+ if( !_catalog->hasView() )
+ delete _catalog;
+
+ // setup new one
+ _catalog = v->catalog();
+ _catalog->registerView(this);
+ newFileOpened(_catalog->isReadOnly());
+ return;
+ }
+ else {
+ KWin::activateWindow(v->topLevelWidget()->winId());
+ return;
+ }
+ }
+
+ ConversionStatus stat=_catalog->openURL(url, package);
+
+ switch(stat)
+ {
+ case OK:
+ {
+ break;
+ }
+ case RECOVERED_HEADER_ERROR: // Old name HEADER_ERROR
+ {
+ KMessageBox::sorry(this,
+ i18n("There was an error while reading the file header. "
+ "Please check the header." ));
+ editHeader();
+ break;
+ }
+ case PARSE_ERROR:
+ {
+ KMessageBox::error(this
+ ,i18n("Error while trying to read file:\n %1\n"
+ "Maybe it is not a valid PO file.").arg(url.prettyURL()));
+ break;
+ }
+ case NO_ENTRY_ERROR:
+ {
+ KMessageBox::error(this
+ ,i18n("Error while reading the file:\n %1\n"
+ "No entry found.").arg(url.prettyURL()));
+ break;
+ }
+ case RECOVERED_PARSE_ERROR:
+ {
+ QString msg=i18n(
+ "The file contained syntax errors and an attempt has been "
+ "made to recover it.\n"
+ "Please check the questionable entries by using "
+ "Go->Next error");
+ KMessageBox::sorry(this,msg);
+ emitEntryState();
+ break;
+ }
+ case NO_PERMISSIONS:
+ {
+ KMessageBox::error(this,i18n(
+ "You do not have permissions to read file:\n %1").arg(url.prettyURL()));
+ break;
+ }
+ case NO_FILE:
+ {
+ KMessageBox::error(this,i18n(
+ "You have not specified a valid file:\n %1").arg(url.prettyURL()));
+ break;
+ }
+ case NO_PLUGIN:
+ {
+ KMessageBox::error(this,i18n(
+ "KBabel cannot find a corresponding plugin for the MIME type of the file:\n %1").arg(url.prettyURL()));
+ break;
+ }
+ case UNSUPPORTED_TYPE:
+ {
+ KMessageBox::error(this,i18n(
+ "The import plugin cannot handle this type of the file:\n %1").arg(url.prettyURL()));
+ break;
+ }
+ case STOPPED:
+ break;
+ default:
+ {
+ KMessageBox::error(this,i18n(
+ "Error while trying to open file:\n %1").arg(url.prettyURL()));
+ break;
+ }
+
+ }
+ /*
+ //activate editor
+ setEnabled(true);
+ setCursor(KCursor::arrowCursor());*/
+
+ _autoSaveDelay = _catalog->saveSettings( ).autoSaveDelay;
+ if ( _autoSaveDelay ) {
+ if ( !autoSaveTimer ) {
+ autoSaveTimer = new QTimer( this, "AUTOSAVE TIMER" );
+ connect( autoSaveTimer, SIGNAL( timeout( ) ), this, SLOT( slotAutoSaveTimeout( ) ) );
+ }
+ autoSaveTimer->stop( );
+ autoSaveTimer->start( 1000 * 60 * _autoSaveDelay );
+ }
+
+ }
+}
+
+void KBabelView::revertToSaved()
+{
+ if(isModified())
+ {
+ // ### TODO: "Cancel" should be the default
+ if(KMessageBox::warningContinueCancel(this
+ ,i18n("All changes will be lost if the file "
+ "is reverted to its last saved state.")
+ ,i18n("Warning"),i18n("&Revert"))
+ == KMessageBox::Cancel)
+ {
+ return;
+ }
+ }
+
+ open(_catalog->currentURL(),QString::null,false);
+}
+
+void KBabelView::openTemplate(const KURL& openURL, const KURL& saveURL)
+{
+ stopSearch();
+
+ if(checkModified())
+ {
+ // deactive editor
+ /*setEnabled(false);
+ setCursor(KCursor::waitCursor());*/
+
+
+ ConversionStatus stat=_catalog->openURL(openURL,saveURL);
+
+ switch(stat)
+ {
+ case OK:
+ {
+ break;
+ }
+ case RECOVERED_HEADER_ERROR:
+ {
+ // For a template, recoverable errors are disqualifying
+ KMessageBox::sorry(this,
+ i18n("There was an error while reading the file header of file:\n %1")
+ .arg(openURL.prettyURL()));
+ break;
+ }
+ case PARSE_ERROR:
+ {
+ KMessageBox::error(this
+ ,i18n("Error while trying to read file:\n %1\n"
+ "Maybe it is not a valid PO file.").arg(openURL.prettyURL()));
+ break;
+ }
+ case NO_ENTRY_ERROR:
+ {
+ KMessageBox::error(this
+ ,i18n("Error while reading the file:\n %1\n"
+ "No entry found.").arg(openURL.prettyURL()));
+ break;
+ }
+ case RECOVERED_PARSE_ERROR:
+ {
+ // For a template, recoverable errors are disqualifying
+ KMessageBox::sorry(this,
+ i18n("Minor syntax errors were found while reading file:\n %1")
+ .arg(openURL.prettyURL()));
+ break;
+ }
+ case NO_PERMISSIONS:
+ {
+ KMessageBox::error(this,i18n("You do not have permissions to read file:\n %1").arg(openURL.prettyURL()));
+ break;
+ }
+ case NO_FILE:
+ {
+ KMessageBox::error(this,i18n("You have not specified a valid file:\n %1").arg(openURL.prettyURL()));
+ break;
+ }
+ case NO_PLUGIN:
+ {
+ KMessageBox::error(this,i18n(
+ "KBabel cannot find a corresponding plugin for the MIME type of the file:\n %1").arg(openURL.prettyURL()));
+ break;
+ }
+ case UNSUPPORTED_TYPE:
+ {
+ KMessageBox::error(this,i18n(
+ "The import plugin cannot handle this type of the file:\n %1").arg(openURL.prettyURL()));
+ break;
+ }
+ case STOPPED:
+ break;
+ default:
+ {
+ KMessageBox::error(this,i18n("Error while trying to open file:\n %1").arg(openURL.prettyURL()));
+ break;
+ }
+
+ }
+
+ /*
+ //activate editor
+ setEnabled(true);
+
+ setCursor(KCursor::arrowCursor());*/
+ }
+}
+
+bool KBabelView::saveFile(bool syntaxCheck)
+{
+ if(_catalog->isReadOnly())
+ {
+ return saveFileAs();
+ }
+ else
+ {
+ ConversionStatus stat=_catalog->saveFile();
+
+ int whatToDo = -1;
+
+ switch(stat)
+ {
+ case OK:
+ {
+ informDictionary();
+ if(syntaxCheck && _catalog->saveSettings().autoSyntaxCheck )
+ return checkSyntax(true,false);
+ else
+ return true;
+ }
+ case NO_PERMISSIONS:
+ {
+ whatToDo=KMessageBox::warningContinueCancel(this,
+ i18n("You do not have permission to write to file:\n%1\n"
+ "Do you want to save to another file or cancel?").arg(_catalog->currentURL().prettyURL()),
+ i18n("Error"),KStdGuiItem::save());
+ break;
+ }
+ case NO_PLUGIN:
+ {
+ KMessageBox::error(this,i18n(
+ "KBabel cannot find a corresponding plugin for the MIME type of file:\n %1").arg(_catalog->currentURL().prettyURL()));
+ break;
+ }
+ case UNSUPPORTED_TYPE:
+ {
+ KMessageBox::error(this,i18n(
+ "The export plugin cannot handle this type of file:\n %1").arg(_catalog->currentURL().prettyURL()));
+ break;
+ }
+ case BUSY:
+ {
+ KMessageBox::error(this,i18n(
+ "KBabel has not finished the last operation yet.\n"
+ "Please wait."));
+ break;
+ }
+ case STOPPED:
+ break;
+ default:
+ {
+ whatToDo=KMessageBox::warningContinueCancel(this,
+ i18n("An error occurred while trying to write to file:\n%1\n"
+ "Do you want to save to another file or cancel?").arg(_catalog->currentURL().prettyURL()),
+ i18n("Error"),KStdGuiItem::save());
+ break;
+ }
+ }
+ switch(whatToDo)
+ {
+ case KMessageBox::Continue:
+ return saveFileAs();
+ default:
+ return false;
+
+ }
+
+ }
+
+ return true;
+}
+
+bool KBabelView::saveFileAs(KURL url, bool syntaxCheck)
+{
+ bool newName=false;
+ if(url.isEmpty())
+ {
+ if((url = KFileDialog::getSaveURL(currentURL().url(), CatalogExportPlugin::availableExportMimeTypes().join(" "),this)).isEmpty())
+ {
+ return false;
+ }
+ newName=true;
+ }
+
+ if (KIO::NetAccess::exists(url, false, this))
+ {
+ if(KMessageBox::warningContinueCancel(this,QString("<qt>%1</qt>").arg(i18n("The file %1 already exists. "
+ "Do you want to overwrite it?").arg(url.prettyURL())),i18n("Warning"),i18n("&Overwrite"))==KMessageBox::Cancel)
+ {
+ return false;
+ }
+
+ }
+
+ bool wasReadOnly=_catalog->isReadOnly();
+
+ ConversionStatus stat=_catalog->saveFileAs(url,true);
+
+
+ // if the file was not saved sucessfully ask for saving to another file
+ if(stat!=OK)
+ {
+ bool cancelLoop=false; // flag, if the saving loop should be canceled
+ do
+ {
+ // select the right error message
+ QString message;
+ switch(stat)
+ {
+ case NO_PERMISSIONS:
+ {
+ message=i18n("You do not have permission to write to file:\n%1\n"
+ "Do you want to save to another file or cancel?").arg(url.prettyURL());
+ break;
+ }
+ case NO_FILE:
+ {
+ message=i18n("You have specified a folder:\n%1\n"
+ "Do you want to save to another file or cancel?").arg(url.prettyURL());
+ break;
+ }
+ case NO_PLUGIN:
+ {
+ message=i18n("KBabel cannot find a corresponding plugin for the MIME type of the file:\n %1").arg(url.prettyURL());
+ break;
+ }
+ case UNSUPPORTED_TYPE:
+ {
+ message=i18n(
+ "The export plugin cannot handle this type of the file:\n %1").arg(url.prettyURL());
+ break;
+ }
+ default:
+ {
+ message=i18n("An error occurred while trying to write to file:\n%1\n"
+ "Do you want to save to another file or cancel?").arg(url.prettyURL());
+ break;
+ }
+ }
+
+ // now ask, if the user wants to save to another file or cancel
+ switch(KMessageBox::warningContinueCancel(this,message,i18n("Error"),KStdGuiItem::save()))
+ {
+ // save to another file
+ case KMessageBox::Continue:
+ {
+ // ask for new filename
+ if ((url = KFileDialog::getSaveURL(currentURL().url(), CatalogExportPlugin::availableExportMimeTypes().join(" "), this)).isEmpty())
+ {
+ // if no filename was given cancel all
+ return false;
+ }
+
+ if (KIO::NetAccess::exists(url, false, this))
+ {
+ if(KMessageBox::warningContinueCancel(this,i18n("The file %1 already exists.\n"
+ "Do you want to overwrite it?").arg(url.prettyURL()),i18n("Warning"),i18n("&Overwrite"))==KMessageBox::Continue)
+ {
+ stat=_catalog->saveFileAs(url);
+ if(stat!=OK)
+ cancelLoop=false;
+ else
+ cancelLoop=true;
+ }
+ }
+ else
+ {
+ stat=_catalog->saveFileAs(url);
+ if(stat!=OK)
+ cancelLoop=false;
+ else
+ cancelLoop=true;
+ }
+ break;
+ }
+ default: // the user do not want to save to another file
+ return false;
+ }
+ }
+ while(!cancelLoop);
+ }
+
+
+ if(wasReadOnly)
+ {
+ msgstrEdit->setReadOnly(false);
+ }
+
+ emit signalChangeCaption(_catalog->package());
+
+ if(newName)
+ {
+ dictBox->setEditedPackage(_catalog->packageName());
+ dictBox->setEditedFile(_catalog->currentURL().url());
+ }
+
+ // after save put current edit into dictionary as well
+ informDictionary();
+
+ if(syntaxCheck && _catalog->saveSettings().autoSyntaxCheck)
+ return checkSyntax(true,false);
+ else
+ return true;
+}
+
+bool KBabelView::saveFileSpecial()
+{
+ QString tmpname;
+ bool result = false;
+
+ {
+ // generate temporary name
+ KTempFile tmp;
+ tmp.setAutoDelete (true);
+ tmpname = tmp.name ();
+ }
+
+ {
+ // make sure the project is freed (pointer going out of scope)
+ KBabel::Project::Ptr project = KBabel::ProjectManager::open (tmpname);
+
+ project->setSettings( _catalog->saveSettings() );
+ KConfigDialog *_prefDialog = new KConfigDialog(this, "project dialog", project->settings(),
+ KDialogBase::IconList, KDialogBase::Cancel|KDialogBase::Ok|KDialogBase::Help);
+
+ _prefDialog->setCaption( i18n("Special Save Settings") );
+ _prefDialog->setHelp("preferences_save");
+
+ SavePreferences* _prefWidget = new SavePreferences(_prefDialog);
+ _prefWidget->setAutoSaveVisible(false);
+ _prefDialog->addPage(_prefWidget, i18n("title of page in preferences dialog","Save")
+ , "filesave"
+ , i18n("Options for File Saving"));
+
+ if( _prefDialog->exec() == QDialog::Accepted )
+ {
+ SaveSettings settings = project->saveSettings();
+ SaveSettings originalSettings = _catalog->saveSettings();
+ _catalog->setSettings(settings);
+ result = saveFileAs();
+
+ _catalog->setSettings(originalSettings);
+ }
+ }
+
+ QFile::remove( tmpname );
+
+ return result;
+}
+
+bool KBabelView::checkSyntax()
+{
+ return checkSyntax(false,false);
+}
+
+bool KBabelView::checkSyntax(bool msgOnlyAtError,bool question)
+{
+ if(currentURL().isEmpty())
+ return false;
+
+ bool returnCode=true;
+ QString output;
+
+ Msgfmt::Status result=_catalog->checkSyntax( output );
+
+ const QStringList outputLines = QStringList::split("\n",output);
+
+ switch(result)
+ {
+ case Msgfmt::Ok:
+ {
+ if(!msgOnlyAtError)
+ {
+ KMessageBox::informationList( this, i18n("The file is syntactically correct.\n\n"
+ "Output of \"msgfmt --statistics\":\n"), outputLines );
+ }
+ returnCode=true;
+ break;
+ }
+ case Msgfmt::Unsupported:
+ {
+ if(!msgOnlyAtError)
+ {
+ KMessageBox::sorry(this
+ ,i18n("You can use gettext tools only for checking PO files."));
+ }
+ returnCode=true;
+ break;
+ }
+ case Msgfmt::HeaderError:
+ case Msgfmt::SyntaxError:
+ {
+ QString msg = ( result == Msgfmt::SyntaxError )
+ ? i18n("msgfmt detected a syntax error.\n")
+ : i18n("msgfmt detected a header syntax error.\n");
+
+ if(question)
+ {
+ msg += i18n("\nDo you want to continue or cancel and edit the file again?");
+ msg += "\n\n";
+ msg += i18n("Output of \"msgfmt --statistics\":\n");
+ switch( KMessageBox::warningContinueCancelList( this, msg,
+ outputLines, i18n("Warning"), KStdGuiItem::cont()) )
+ {
+ case KMessageBox::Continue:
+ returnCode=true;
+ break;
+ default:
+ returnCode=false;
+ }
+ }
+ else
+ {
+#if KDE_IS_VERSION ( 3, 4, 0 )
+ msg += "\n";
+ msg += i18n("Please edit the file again.");
+ msg += "\n\n";
+ msg += i18n("Output of \"msgfmt --statistics\":\n");
+ KMessageBox::errorList( this, msg, outputLines );
+#else
+ msg += i18n("Output of \"msgfmt --statistics\":\n");
+ msg += output;
+ msg += "\n\n";
+ msg += i18n("Please edit the file again.");
+ KMessageBox::error( this, msg );
+#endif
+ returnCode=false;
+ }
+ break;
+ }
+ case Msgfmt::NoExecutable:
+ case Msgfmt::Error:
+ {
+ QString msg = i18n("While trying to check syntax with msgfmt an error occurred.\n"
+ "Please make sure that you have installed\n"
+ "the GNU gettext package properly.");
+ if(question)
+ {
+ msg += i18n("\nDo you want to continue or cancel and edit the file again?");
+ switch( KMessageBox::warningContinueCancelList( this, msg,
+ outputLines, i18n("Warning"), KStdGuiItem::cont() ))
+ {
+ case KMessageBox::Continue:
+ returnCode=true;
+ break;
+ default:
+ returnCode=false;
+ }
+ }
+ else
+ {
+#if KDE_IS_VERSION ( 3, 4, 0 )
+ msg += "\n";
+ msg += i18n("Please edit the file again.");
+ KMessageBox::errorList( this, msg, outputLines );
+#else
+ msg += output;
+ msg += "\n\n";
+ msg += i18n("Please edit the file again.");
+ KMessageBox::error( this, msg );
+#endif
+ returnCode=false;
+ }
+
+ break;
+ }
+ }
+
+ emitEntryState();
+
+ return returnCode;
+}
+
+bool KBabelView::checkAll()
+{
+ if(currentURL().isEmpty())
+ return false;
+
+ bool a,badresult=false;
+
+ QValueList<KDataToolInfo> tools = ToolAction::validationTools();
+
+ QValueList<KDataToolInfo>::ConstIterator entry = tools.begin();
+ for( ; entry != tools.end(); ++entry )
+ {
+ KDataTool* tool = (*entry).createTool();
+ if( tool )
+ {
+ a = _catalog->checkUsingTool(tool,entry==tools.begin());
+ badresult = badresult || !a;
+ delete tool;
+ }
+ }
+
+ QString output;
+
+ a = (_catalog->checkSyntax(output, false)!=Msgfmt::Ok);
+ badresult=badresult||a;
+
+ emitEntryState();
+
+ if(!badresult)
+ {
+ KMessageBox::information(this
+ ,i18n("No mismatch has been found.")
+ , i18n("Title in Dialog: Perform all checks","Perform All Checks"));
+ }
+ else
+ {
+ int index=0;
+ DocPosition pos;
+ if(!_catalog->hasError(0,pos))
+ index = _catalog->nextError(0, pos);
+ if(index>=0)
+ {
+ gotoEntry(pos);
+ }
+
+ KMessageBox::error(this
+ ,i18n("Some mismatches have been found.\n"
+ "Please check the questionable entries by using "
+ "Go->Next error")
+ , i18n("Title in Dialog: Perform all checks","Perform All Checks"));
+
+ }
+
+ return !badresult;
+}
+
+
+
+bool KBabelView::checkModified()
+{
+ bool flag=true;
+
+ if(isModified())
+ {
+ switch(KMessageBox::warningYesNoCancel(this,
+ i18n("The document contains unsaved changes.\n"
+ "Do you want to save your changes or discard them?"),i18n("Warning"),
+ KStdGuiItem::save(),KStdGuiItem::discard()))
+ {
+ case KMessageBox::Yes:
+ {
+ flag = saveFile(false);
+ if(flag && _catalog->saveSettings().autoSyntaxCheck)
+ {
+ flag = checkSyntax(true,true);
+ }
+ break;
+ }
+ case KMessageBox::No:
+ flag = true;
+ break;
+ default: // canceled
+ flag = false;
+ break;
+ }
+ }
+
+ return flag;
+}
+
+void KBabelView::updateEditor(int form, bool delay)
+{
+ msgstrEdit->blockSignals(true);
+
+ if(KBabelSettings::autoUnsetFuzzy() && !msgstrEdit->isModified())
+ {
+ disconnect(msgstrEdit,SIGNAL(textChanged()),this,SLOT(autoRemoveFuzzyStatus()));
+ }
+
+ msgidLabel->setText(_catalog->msgid(_currentIndex), _catalog->msgctxt(_currentIndex));
+ msgidLabel->repaint();
+
+ msgstrEdit->setText(_catalog->msgstr(_currentIndex));
+ msgstrEdit->showForm( form );
+ msgstrEdit->repaint();
+ m_cataloglistview->setSelectedItem(_currentIndex);
+
+ if(KBabelSettings::autoUnsetFuzzy() && _catalog->isFuzzy(_currentIndex))
+ {
+ connect(msgstrEdit,SIGNAL(textChanged()),this,SLOT(autoRemoveFuzzyStatus()));
+ }
+
+ msgstrEdit->blockSignals(false);
+
+ autoCheck(false);
+
+ // no need to display diff if this message wasn't translated
+ if(_diffEnabled && !(_catalog->isUntranslated(_currentIndex)))
+ {
+ autoDiff();
+ }
+
+ if(isActiveWindow() && KBabelSettings::autoSearch()
+ && !_autoSearchTempDisabled)
+ {
+ if (delay)
+ {
+ QTimer::singleShot(0, this, SLOT (startSearch()));
+ }
+ else
+ {
+ startSearch();
+ }
+ }
+
+ msgstrEdit->setFocus();
+ msgstrEdit->setModified(false);
+}
+
+
+void KBabelView::undo()
+{
+ if(!_catalog->isUndoAvailable())
+ return;
+
+ int newIndex=_catalog->undo();
+
+ if(newIndex != (int)_currentIndex)
+ {
+ DocPosition pos;
+ pos.item=newIndex;
+ pos.form=0;
+ gotoEntry(pos);
+ }
+}
+
+void KBabelView::redo()
+{
+ if(!_catalog->isRedoAvailable())
+ return;
+
+ int newIndex=_catalog->redo();
+
+ if(newIndex != (int)_currentIndex)
+ {
+ DocPosition pos;
+ pos.item=newIndex;
+ pos.form=0;
+ gotoEntry(pos);
+ }
+}
+
+void KBabelView::textCut()
+{
+ if(msgstrEdit->hasFocus())
+ {
+ msgstrEdit->cut();
+ }
+}
+
+void KBabelView::textCopy()
+{
+ if(msgstrEdit->hasSelectedText())
+ {
+ msgstrEdit->copy();
+ }
+ else if(msgidLabel->hasSelectedText())
+ {
+ msgidLabel->copy();
+ }
+ else if(dictBox->isVisible() && dictBox->hasSelectedText())
+ {
+ dictBox->copy();
+ }
+}
+
+void KBabelView::textPaste()
+{
+ msgstrEdit->paste();
+}
+
+
+bool KBabelView::findNext()
+{
+ if(!_findDialog)
+ return false;
+
+ if( !_redirectedBackSearch && _findDialog->findOpts().backwards )
+ {
+ _redirectedBackSearch = true;
+ bool res = findPrev();
+ _redirectedBackSearch = false;
+ return res;
+ }
+
+ DocPosition pos;
+ pos.item=_currentIndex;
+ pos.form=0;
+
+ if( m_commentview->hasFocus() ) {
+ pos.part = Comment;
+ pos.offset = m_commentview->currentIndex();
+ }
+ else
+ if(msgidLabel->hasFocus() ) {
+ pos.part = Msgid;
+ pos.offset = msgidLabel->currentIndex();
+ }
+ else {
+ pos.part = Msgstr;
+ pos.offset = msgstrEdit->currentIndex();
+ pos.form = msgstrEdit->currentForm();
+ }
+
+ _findStartPos=pos;
+ _findBreakAtEnd=false;
+
+ return findNext_internal(pos);
+}
+
+bool KBabelView::findPrev()
+{
+ if(!_findDialog)
+ return false;
+
+ if( !_redirectedBackSearch && _findDialog->findOpts().backwards )
+ {
+ _redirectedBackSearch = true;
+ bool res = findNext();
+ _redirectedBackSearch = false;
+ return res;
+ }
+
+ DocPosition pos;
+ pos.item=_currentIndex;
+
+ if( m_commentview->hasFocus()) {
+ pos.part = Comment;
+ pos.offset = m_commentview->currentIndex();
+ }
+ else
+ if(msgidLabel->hasFocus() ) {
+ pos.part = Msgid;
+ pos.offset = msgidLabel->currentIndex();
+ }
+ else {
+ pos.part = Msgstr;
+ pos.offset = msgstrEdit->currentIndex();
+ pos.form = msgstrEdit->currentForm();
+ }
+
+ _findStartPos=pos;
+ _findBreakAtEnd=false;
+
+ return findPrev_internal(pos);
+}
+
+
+bool KBabelView::findNext_internal(DocPosition& pos, bool forReplace, bool gui)
+{
+ FindOptions opts;
+ if(forReplace)
+ opts = _replaceDialog->replaceOpts();
+ else
+ opts = _findDialog->findOpts();
+ int len=0;
+ deselectAll();
+
+ bool success=false;
+ if( !opts.askFile ) // for find in all files ignore return to the beginning
+ if(!_findBreakAtEnd && !(success=_catalog->findNext(&opts,pos,len))) {
+ int r;
+ if(forReplace) {
+ _replaceWasAtEnd=true;
+ _findBreakAtEnd=true;
+ if(gui) {
+ r = KMessageBox::questionYesNo(this,
+ i18n("<qt>%n replacement made.<br>End of document reached.<br>Continue from the beginning?</qt>",
+ "<qt>%n replacements made.<br>End of document reached.<br>Continue from the beginning?</qt>",
+ _replacesTotal), QString::null, KStdGuiItem::cont(), KStdGuiItem::cancel());
+ }
+ else {
+ r = KMessageBox::Yes;
+ }
+ }
+ else {
+ r = KMessageBox::questionYesNo(this,i18n("End of document reached.\n"
+ "Continue from the beginning?"), QString::null, KStdGuiItem::cont(), KStdGuiItem::cancel());
+ }
+ if(r == KMessageBox::Yes) {
+ if(opts.inMsgid && !forReplace)
+ pos.part = Msgid;
+ else if(opts.inComment)
+ pos.part = Comment;
+ else
+ pos.part = Msgstr;
+
+ pos.item = 0;
+ pos.offset = 0;
+ pos.form = 0;
+
+ }
+ else
+ return false;
+ }
+
+
+ if(!success && !_catalog->findNext(&opts,pos,len)) { // reached end the second time
+ if( !opts.askFile )
+ {
+ if(forReplace) {
+ KMessageBox::information(this,i18n("%n replacement made","%n replacements made",_replacesTotal));
+ }
+ else {
+ KMessageBox::information(this,i18n("Search string not found."));
+ }
+ return false;
+ }
+ else
+ {
+ if( opts.askForNextFile )
+ {
+ int r = KMessageBox::questionYesNo(this,i18n("End of document reached.\n"
+ "Continue in the next file?"), QString::null, KStdGuiItem::cont(), KStdGuiItem::cancel());
+ if( r != KMessageBox::Yes ) return false;
+
+ }
+ if( isModified() && !opts.askForSave ) saveFile();
+ DCOPClient *client = kapp->dcopClient();
+ QByteArray data, replyData;
+ QCString replyType;
+ bool morefiles = false; // more files to lookup in
+ if( !client->call( _fileSource,"CatalogManagerIFace",
+ "findNextFile()", data, replyType, replyData) ) kdDebug(KBABEL) << "unable to call, reply type is " << replyType << endl;
+ else if( replyType == "QCString" )
+ {
+ QDataStream rep( replyData, IO_ReadOnly);
+ QCString f;
+ rep >> f;
+ QString foundFile = QString::fromUtf8(f);
+ morefiles = !f.isEmpty() && !f.isNull();
+ if( morefiles )
+ {
+ emit open( KURL(foundFile) );
+ pos.item = 0;
+ pos.part = Msgid;
+ pos.offset = 0;
+ _catalog->findNext(&opts,pos,len);
+ } else {
+ if( f.isNull() ) // is there possibility to get a new file?
+ {
+ // no, this is the end finally
+ if( forReplace )
+ KMessageBox::information(this,i18n("%n replacement made","%n replacements made",_replacesTotal));
+ else
+ KMessageBox::information(this,i18n("Search string not found."));
+ return false;
+ }
+ else
+ {
+ // there can be a new file, let user know
+ showTryLaterMessageBox();
+ if( forReplace ) return true; // let replace dialog stay
+ else return false;
+ }
+ }
+ } else {
+ KMessageBox::error(this,i18n("DCOP communication with Catalog Manager failed."));
+ return false;
+ }
+ }
+ }
+ if(gui) {
+ if( _currentIndex != pos.item
+ || (pos.part==Msgstr && msgstrEdit->currentForm() != pos.form) )
+ {
+ gotoEntry(pos);
+ }
+
+ int line,col,endline,endcol;
+ switch(pos.part) {
+ case Msgid:
+ msgidLabel->selectAll(false);
+ msgidLabel->setFocus();
+ msgidLabel->offset2Pos(pos.offset,line,col);
+ msgidLabel->offset2Pos(pos.offset+len,endline,endcol);
+
+ msgidLabel->setSelection(line,col,endline,endcol);
+ msgidLabel->setCursorPosition(endline,endcol);
+
+ _lastFoundString=msgidLabel->selectedText();
+ break;
+ case Msgstr:
+ msgstrEdit->selectAll(false);
+ msgstrEdit->setFocus();
+ msgstrEdit->offset2Pos(pos.offset,line,col);
+ msgstrEdit->offset2Pos(pos.offset+len,endline,endcol);
+
+ msgstrEdit->setSelection(line,col,endline,endcol);
+ msgstrEdit->setCursorPosition(endline,endcol);
+
+ _lastFoundString=msgstrEdit->selectedText();
+ break;
+ case Comment:
+ {
+ m_mainwindow->makeWidgetDockVisible (m_commentview);
+ _lastFoundString= m_commentview->selectText (pos.offset, pos.offset+len);
+ break;
+ }
+ case UndefPart:
+ break;
+ }
+ }
+
+ if(forReplace) {
+ kdDebug(KBABEL) << "This is forReplace" << endl;
+ _replaceLen=len;
+
+ bool finished=false;
+ // check if we had reached the beginning before and now are before our starting position
+ if(_replaceWasAtEnd) {
+ if( pos.item > _findStartPos.item ) {
+ finished=true;
+ }
+ else if(pos.item == _findStartPos.item) {
+ if(pos.part==Msgstr && !opts.inComment && pos.offset >= _findStartPos.offset+_replaceExtraOffset)
+ finished=true;
+ else if(pos.part==Comment && pos.offset >= _findStartPos.offset+_replaceExtraOffset)
+ finished=true;
+ }
+ }
+
+ if(finished) {
+ KMessageBox::information(this,i18n("%n replacement made","%n replacements made",_replacesTotal));
+ return false;
+ }
+
+ }
+
+ return true;
+}
+
+bool KBabelView::findPrev_internal(DocPosition& pos, bool forReplace, bool gui)
+{
+ FindOptions opts;
+ if(forReplace)
+ opts = _replaceDialog->replaceOpts();
+ else
+ opts = _findDialog->findOpts();
+
+ int len=0;
+
+ deselectAll();
+ bool success=false;
+ if(!_findBreakAtEnd && !(success=_catalog->findPrev(&opts,pos,len))) {
+ int r;
+
+ if(forReplace) {
+ _replaceWasAtEnd=true;
+ _findBreakAtEnd=true;
+ if(gui) {
+ r = KMessageBox::questionYesNo(this,
+ i18n("<qt>%n replacement made.<br>Beginning of document reached.<br>Continue from the end?</qt>",
+ "<qt>%n replacements made.<br>Beginning of document reached.<br>Continue from the end?</qt>",
+ _replacesTotal),QString::null, KStdGuiItem::cont(), KStdGuiItem::cancel());
+ }
+ else {
+ r = KMessageBox::Yes;
+ }
+
+ }
+ else {
+ r = KMessageBox::questionYesNo(this,i18n("Beginning of document reached.\n"
+ "Continue from the end?"), QString::null, KStdGuiItem::cont(), KStdGuiItem::cancel());
+ }
+ if(r == KMessageBox::Yes) {
+ pos.item = _catalog->numberOfEntries()-1;
+
+ if(opts.inComment) {
+ pos.part = Comment;
+ pos.offset = _catalog->comment(pos.item).length();
+ }
+ else if(opts.inMsgstr || forReplace) {
+ pos.part = Msgstr;
+ if( _catalog->msgstr(pos.item).empty() ) pos.offset=0;
+ else pos.offset = _catalog->msgstr(pos.item).last().length();
+ pos.form = _catalog->msgstr(pos.item).count()-1;
+ }
+ else {
+ pos.part = Msgid;
+ //FIXME: we should search in msgid plural forms
+ pos.offset = _catalog->msgid(pos.item).first().length();
+ }
+ }
+ else
+ return false;
+ }
+
+ // start at the end
+ if(!success && !_catalog->findPrev(&opts,pos,len)) {
+ if(forReplace) {
+ KMessageBox::information(this,i18n("%n replacement made","%n replacements made",_replacesTotal));
+ }
+ else {
+ KMessageBox::information(this,i18n("Search string not found."));
+ }
+ return false;
+ }
+ else if(gui) {
+ if(_currentIndex != pos.item
+ || (pos.part==Msgstr && msgstrEdit->currentForm() != pos.form) )
+ gotoEntry(pos);
+
+ int line,col,endline,endcol;
+ switch(pos.part) {
+ case Msgid:
+ msgidLabel->selectAll(false);
+ msgidLabel->setFocus();
+ msgidLabel->offset2Pos(pos.offset+len,line,col);
+ msgidLabel->offset2Pos(pos.offset,endline,endcol);
+
+ msgidLabel->setSelection(line,col,endline,endcol);
+ msgidLabel->setCursorPosition(endline,endcol);
+
+ _lastFoundString=msgidLabel->selectedText();
+ break;
+ case Msgstr:
+ msgstrEdit->selectAll(false);
+ msgstrEdit->setFocus();
+ msgstrEdit->offset2Pos(pos.offset+len,line,col);
+ msgstrEdit->offset2Pos(pos.offset,endline,endcol);
+
+ msgstrEdit->setSelection(line,col,endline,endcol);
+ msgstrEdit->setCursorPosition(endline,endcol);
+
+ _lastFoundString=msgstrEdit->selectedText();
+ break;
+ case Comment:
+ m_mainwindow->makeWidgetDockVisible (m_commentview);
+ _lastFoundString=m_commentview->
+ selectText(pos.offset, pos.offset+len);
+ break;
+ case UndefPart:
+ break;
+ }
+ }
+
+ if(forReplace) {
+ _replaceLen=len;
+
+ bool finished=false;
+ // check if we had reached the beginning before and now are before our starting position
+ if(_replaceWasAtEnd) {
+ if( pos.item < _findStartPos.item ) {
+ finished=true;
+ }
+ else if(pos.item == _findStartPos.item) {
+ if(pos.part==Comment && !opts.inMsgstr && pos.offset < _findStartPos.offset+_replaceExtraOffset)
+ finished=true;
+ else if(pos.part==Msgstr && pos.offset < _findStartPos.offset+_replaceExtraOffset)
+ finished=true;
+ }
+ }
+
+ if(finished) {
+ KMessageBox::information(this,i18n("%n replacement made","%n replacements made",_replacesTotal));
+ return false;
+ }
+
+ }
+
+
+ return true;
+}
+
+
+void KBabelView::find()
+{
+ Part hadFocus;
+ if(msgidLabel->hasFocus())
+ hadFocus=Msgid;
+ else if(m_commentview->hasFocus())
+ hadFocus=Comment;
+ else
+ hadFocus=Msgstr;
+
+ if( !_findDialog ) {
+ _findDialog = new FindDialog(false,this);
+ }
+
+ QString marked;
+ if(msgstrEdit->hasFocus()) {
+ marked=msgstrEdit->selectedText();
+ msgstrEdit->selectAll(false);
+ }
+ else if(m_commentview->hasFocus()) {
+ marked=m_commentview->selectedText();
+ m_commentview->textDeselectAll();
+ }
+ else if(msgidLabel->hasFocus()) {
+ marked=msgidLabel->selectedText();
+ msgidLabel->selectAll(false);
+ }
+
+
+ if(marked==_lastFoundString)
+ marked="";
+
+ if( _findDialog->exec(marked) == QDialog::Accepted ) {
+ DocPosition pos;
+ FindOptions opts=_findDialog->findOpts();
+ opts.askFile = false; // do not search in more files
+ _findDialog->setFindOpts(opts);
+
+ if(opts.fromCursor) {
+ _findBreakAtEnd=false;
+ pos.item=_currentIndex;
+
+ if(hadFocus == Comment && opts.inComment) {
+ pos.part = Comment;
+ pos.offset = m_commentview->currentIndex();
+ }
+ else
+ if( hadFocus == Msgid && opts.inMsgid) {
+ pos.part = Msgid;
+ pos.offset = msgidLabel->currentIndex();
+ }
+ else {
+ pos.part = Msgstr;
+ pos.offset = msgstrEdit->currentIndex();
+ }
+ }
+ else {
+ _findBreakAtEnd=true;
+
+ if(opts.backwards) {
+ pos.item=_catalog->numberOfEntries();
+ if(opts.inComment)
+ pos.part=Comment;
+ else if(opts.inMsgstr)
+ pos.part=Msgstr;
+ else
+ pos.part=Msgid;
+
+ pos.offset=1000; // set to a high number
+ }
+ else {
+ pos.item=0;
+ if(opts.inMsgid)
+ pos.part=Msgid;
+ else if(opts.inMsgstr)
+ pos.part=Msgstr;
+ else
+ pos.part=Comment;
+
+ pos.offset=0;
+ }
+ }
+
+ if( opts.backwards ) {
+ _findStartPos=pos;
+ findPrev_internal(pos);
+ }
+ else {
+ _findStartPos=pos;
+ findNext_internal(pos);
+ }
+ }
+}
+
+void KBabelView::replace()
+{
+ _replacesTotal=0;
+ _replaceLen=0;
+ _replaceWasAtEnd=false;
+ _replaceExtraOffset=0;
+
+ Part hadFocus;
+ if(msgidLabel->hasFocus())
+ hadFocus=Msgid;
+ else if(m_commentview->hasFocus())
+ hadFocus=Comment;
+ else
+ hadFocus=Msgstr;
+
+ if( !_replaceDialog ) {
+ _replaceDialog = new FindDialog(true,this);
+ }
+ QString marked;
+ if(msgstrEdit->hasFocus()) {
+ marked=msgstrEdit->selectedText();
+ msgstrEdit->selectAll(false);
+ }
+ else if(m_commentview->hasFocus()) {
+ marked=m_commentview->selectedText();
+ m_commentview->textDeselectAll();
+ }
+ else if(msgidLabel->hasFocus()) {
+ marked=msgidLabel->selectedText();
+ msgidLabel->selectAll(false);
+ }
+
+ if(marked==_lastFoundString)
+ marked="";
+
+ if( _replaceDialog->exec(marked) == QDialog::Accepted ) {
+ KBabel::ReplaceOptions opts=_replaceDialog->replaceOpts();
+ if(opts.fromCursor) {
+ _findBreakAtEnd=false;
+ _replacePos.item=_currentIndex;
+
+ if(hadFocus==Comment && opts.inComment) {
+ _replacePos.part = Comment;
+ _replacePos.offset = m_commentview->currentIndex();
+ }
+ else
+ {
+ _replacePos.part = Msgstr;
+ _replacePos.offset = msgstrEdit->currentIndex();
+ }
+ }
+ else {
+ _findBreakAtEnd=true;
+ if(opts.backwards) {
+ _replacePos.item=_catalog->numberOfEntries();
+ if(opts.inComment)
+ _replacePos.part=Comment;
+ else
+ _replacePos.part=Msgstr;
+
+ _replacePos.offset=1000; // set to a high number
+ }
+ else {
+ _replacePos.item=0;
+ if(opts.inMsgstr)
+ _replacePos.part=Msgstr;
+ else
+ _replacePos.part=Comment;
+
+ _replacePos.offset=0;
+ }
+ }
+
+ // do not ask for next file from catalog manager
+ opts.askFile = false;
+ _replaceDialog->setReplaceOpts(opts);
+
+ bool success;
+
+ if( opts.backwards ) {
+ _findStartPos=_replacePos;
+ success = findPrev_internal(_replacePos,true,opts.ask);
+ }
+ else {
+ _findStartPos=_replacePos;
+ success = findNext_internal(_replacePos,true,opts.ask);
+ }
+
+
+
+ if(success) {
+ if(!_replaceAskDialog) {
+ _replaceAskDialog = new ReplaceDialog(this);
+ connect(_replaceAskDialog,SIGNAL(replace()),this,SLOT(replaceNext()));
+ connect(_replaceAskDialog,SIGNAL(next()),this,SLOT(findNextReplace()));
+ connect(_replaceAskDialog,SIGNAL(replaceAll()),this,SLOT(replaceAll()));
+ }
+
+ if(opts.ask) {
+ _replaceAskDialog->exec();
+ }
+ else
+ replaceAll();
+ }
+
+ }
+}
+
+
+void KBabelView::replaceNext()
+{
+ _replacesTotal++;
+
+ KBabel::ReplaceOptions opts=_replaceDialog->replaceOpts();
+
+ // calculate the diff to original offset due to replacing a string
+ // in the starting item
+ if(_findStartPos.item == _replacePos.item ) {
+ if((opts.backwards && !_replaceWasAtEnd)
+ || (!opts.backwards && _replaceWasAtEnd)) {
+ _replaceExtraOffset += (opts.replaceStr.length()-_replaceLen);
+ }
+ }
+
+ Part part;
+ uint form = 0;
+ QString str;
+
+ if(_replacePos.part==Msgstr) {
+ part=Msgstr;
+ str = _catalog->msgstr(_replacePos.item).first()
+ .mid(_replacePos.offset,_replaceLen);
+ form=_replacePos.form;
+ }
+ else if(_replacePos.part==Comment) {
+ part = Comment;
+ str = _catalog->comment(_replacePos.item)
+ .mid(_replacePos.offset,_replaceLen);
+ }
+ else {
+ kdWarning() << "msgid can not be changed in KBabelView::replaceNext()"
+ << endl;
+ return;
+}
+
+ _catalog->applyBeginCommand( _replacePos.item,part,this);
+
+ DelTextCmd* delCmd = new DelTextCmd(_replacePos.offset,str,form);
+ delCmd->setPart(part);
+ delCmd->setIndex(_replacePos.item);
+ _catalog->applyEditCommand(delCmd,0);
+
+ InsTextCmd* insCmd = new InsTextCmd(_replacePos.offset,opts.replaceStr,form);
+ insCmd->setPart(part);
+ insCmd->setIndex(_replacePos.item);
+ _catalog->applyEditCommand(insCmd,0);
+
+ _catalog->applyEndCommand( _replacePos.item,part,this);
+
+ // now find next string
+ bool success;
+
+ if( opts.backwards ) {
+ success = findPrev_internal(_replacePos,true);
+ }
+ else {
+ _replacePos.offset+=opts.replaceStr.length();
+ success = findNext_internal(_replacePos,true);
+ }
+
+ if(!success) {
+ if(_replaceAskDialog && _replaceAskDialog->isVisible())
+ _replaceAskDialog->hide();
+ }
+
+}
+
+
+void KBabelView::replaceAll()
+{
+ if(_replaceAskDialog && _replaceAskDialog->isVisible())
+ _replaceAskDialog->hide();
+
+ KBabel::ReplaceOptions opts=_replaceDialog->replaceOpts();
+ bool success=true;
+
+ _catalog->applyBeginCommand(_replacePos.item,Msgstr,this);
+
+ while(success)
+ {
+ kapp->processEvents(100);
+
+ _replacesTotal++;
+
+ // calculate the diff to original offset due to replacing a string
+ // in the starting item
+ if(_findStartPos.item == _replacePos.item ) {
+ if((opts.backwards && !_replaceWasAtEnd) || (!opts.backwards && _replaceWasAtEnd)) {
+ _replaceExtraOffset += (opts.replaceStr.length()-_replaceLen);
+ }
+ }
+
+ Part part;
+ uint form=0;
+ QString str;
+
+ if(_replacePos.part==Msgstr) {
+ part=Msgstr;
+ form=_replacePos.form;
+ str = _catalog->msgstr(_replacePos.item).first().mid(_replacePos.offset,_replaceLen);
+ }
+ else if(_replacePos.part==Comment) {
+ part = Comment;
+ str = _catalog->comment(_replacePos.item).mid(_replacePos.offset,_replaceLen);
+ }
+ else {
+ kdWarning() << "msgid can not be changed in KBabelView::replaceNext()" << endl;
+ return;
+ }
+
+ DelTextCmd* delCmd = new DelTextCmd(_replacePos.offset,str,form);
+ delCmd->setPart(part);
+ delCmd->setIndex(_replacePos.item);
+ _catalog->applyEditCommand(delCmd,0);
+
+ InsTextCmd* insCmd = new InsTextCmd(_replacePos.offset,opts.replaceStr,form);
+ insCmd->setPart(part);
+ insCmd->setIndex(_replacePos.item);
+ _catalog->applyEditCommand(insCmd,0);
+
+
+ // now find next string
+ if( opts.backwards ) {
+ success = findPrev_internal(_replacePos,true,false);
+ }
+ else {
+ _replacePos.offset+=opts.replaceStr.length();
+ success = findNext_internal(_replacePos,true,false);
+ }
+ }
+
+ _catalog->applyEndCommand(_replacePos.item,Msgstr,this);
+}
+
+void KBabelView::findNextReplace()
+{
+ bool success;
+ KBabel::ReplaceOptions opts=_replaceDialog->replaceOpts();
+
+ if( opts.backwards ) {
+ success = findPrev_internal(_replacePos,true);
+ }
+ else {
+ _replacePos.offset++;
+ success = findNext_internal(_replacePos,true);
+ }
+
+ if(!success) {
+ if(_replaceAskDialog && _replaceAskDialog->isVisible())
+ _replaceAskDialog->hide();
+ }
+
+}
+
+void KBabelView::findInFile(QCString fileSource, FindOptions options)
+{
+ DocPosition pos;
+ pos.item=0;
+ pos.part=Msgid;
+ pos.offset=0;
+ _findStartPos=pos;
+ _findBreakAtEnd=true; // do not start from the beginning at the end
+ _showTryLaterBox=true;
+
+ // delete dontDisplayAgain from configuration
+ KConfig* config = KGlobal::config();
+ KConfigGroupSaver saver(config,"Notification Messages");
+ config->writeEntry("waitForNextFile",true);
+
+ // set that there can be more files
+ options.askFile = true;
+
+ _fileSource = fileSource;
+
+ if( !_findDialog ) _findDialog = new FindDialog(false,this);
+ _findDialog->setFindOpts(options);
+ findNext_internal(pos);
+}
+
+void KBabelView::replaceInFile(QCString fileSource, KBabel::ReplaceOptions options)
+{
+ _replacePos.item=0;
+ _replacePos.part=Msgid;
+ _replacePos.offset=0;
+
+ _replacesTotal=0;
+ _replaceLen=0;
+ _replaceWasAtEnd=false;
+ _replaceExtraOffset=0;
+
+ _findBreakAtEnd=true;
+ _showTryLaterBox=true;
+
+ // delete dontDisplayAgain from configuration
+ KConfig* config = KGlobal::config();
+ KConfigGroupSaver saver(config,"Notification Messages");
+ config->writeEntry("waitForNextFile",true);
+
+ // set that there can be more files
+ options.askFile = true;
+
+ _fileSource = fileSource;
+
+ if( !_replaceDialog ) _replaceDialog = new FindDialog(true,this);
+ _replaceDialog->setReplaceOpts(options);
+
+ bool success;
+
+ success = findNext_internal(_replacePos,true);
+
+ if(!success) kdDebug(KBABEL) << "Not found in file where catalog manager told us. This should not happen" << endl;
+ else {
+ if(!_replaceAskDialog) {
+ _replaceAskDialog = new ReplaceDialog(this);
+ connect(_replaceAskDialog,SIGNAL(replace()),this,SLOT(replaceNext()));
+ connect(_replaceAskDialog,SIGNAL(next()),this,SLOT(findNextReplace()));
+ connect(_replaceAskDialog,SIGNAL(replaceAll()),this,SLOT(replaceAll()));
+ }
+
+ if(options.ask) {
+ _replaceAskDialog->exec();
+ }
+ else replaceAll();
+ }
+}
+
+
+void KBabelView::deselectAll()
+{
+ msgstrEdit->selectAll(false);
+// FIXME: commentEdit->selectAll(false);
+ msgidLabel->selectAll(false);
+}
+
+void KBabelView::selectAll()
+{
+ if(msgstrEdit->hasFocus())
+ {
+ msgstrEdit->selectAll();
+ }
+// FIXME: else if(commentEdit->hasFocus())
+// FIXME: {
+// FIXME: commentEdit->selectAll();
+// FIXME: }
+ else if(msgidLabel->hasFocus())
+ {
+ msgidLabel->selectAll();
+ }
+}
+
+void KBabelView::clear()
+{
+ if(msgstrEdit->hasFocus())
+ {
+ msgstrEdit->clear();
+ }
+// FIXME: else if(commentEdit->hasFocus())
+// FIXME: {
+// FIXME: commentEdit->clear();
+// FIXME: }
+}
+
+void KBabelView::msgid2msgstr()
+{
+ // FIXME: should care about plural forms
+ QString text = _catalog->msgid(_currentIndex).first();
+
+ // this is KDE specific:
+ if(text.find("_: NAME OF TRANSLATORS\\n")==0)
+ {
+ text=_catalog->identitySettings().authorLocalizedName;
+ }
+ else if(text.find("_: EMAIL OF TRANSLATORS\\n")==0)
+ {
+ text=_catalog->identitySettings().authorEmail;
+ }
+ else if(_catalog->isGeneratedFromDocbook() && text.find("ROLES_OF_TRANSLATORS")==0)
+ {
+ text="<othercredit role=\\\"translator\\\">\n"
+ "<firstname></firstname><surname></surname>\n"
+ "<affiliation><address><email>"+_catalog->identitySettings().authorEmail+"</email></address>\n"
+ "</affiliation><contrib></contrib></othercredit>";
+ }
+ else if(_catalog->isGeneratedFromDocbook() && text.find("CREDIT_FOR_TRANSLATORS")==0)
+ {
+ text="<para>"+_catalog->identitySettings().authorLocalizedName+"\n"+
+ "<email>"+_catalog->identitySettings().authorEmail+"</email></para>";
+ }
+ else if(text.contains(_catalog->miscSettings().singularPlural))
+ {
+ text.replace(_catalog->miscSettings().singularPlural,"");
+ }
+ // end of KDE specific part
+
+
+ QRegExp reg=_catalog->miscSettings().contextInfo;
+ if(text.contains(reg))
+ {
+ text.replace(reg,"");
+ }
+
+ modifyMsgstrText(0,text,true);
+
+ msgstrEdit->setCursorPosition(0,0);
+}
+
+void KBabelView::search2msgstr()
+{
+ modifyMsgstrText(0,dictBox->translation(),true);
+
+ msgstrEdit->setCursorPosition(0,0);
+}
+
+
+void KBabelView::gotoFirst()
+{
+ DocPosition pos;
+ pos.item=0;
+ pos.form=0;
+ gotoEntry(pos);
+}
+
+void KBabelView::gotoLast()
+{
+ DocPosition pos;
+ pos.item=_catalog->numberOfEntries()-1;
+ pos.form=0;
+ gotoEntry(pos);
+}
+
+void KBabelView::gotoNext()
+{
+ DocPosition pos;
+ pos.item=_currentIndex;
+ pos.form=msgstrEdit->currentForm();
+
+ if( (int)pos.form+1 < _catalog->defaultNumberOfPluralForms()
+ && _catalog->pluralForm(_currentIndex)==Gettext )
+ {
+ pos.form++;
+ }
+ else
+ {
+ // check, if we are already showing the last entry
+ if(_currentIndex>=_catalog->numberOfEntries()-1)
+ {
+ return;
+ }
+ else
+ {
+ pos.item++;
+ pos.form=0;
+ }
+ }
+
+ gotoEntry(pos);
+}
+
+void KBabelView::gotoPrev()
+{
+ DocPosition pos;
+ pos.item=_currentIndex;
+ pos.form=msgstrEdit->currentForm();
+ // check, if we are already showing the first entry
+ if(_currentIndex==0 && pos.form==0)
+ {
+ return;
+ }
+ else
+ {
+ if( pos.form==0 )
+ {
+ pos.item--;
+ if( _catalog->pluralForm(pos.item)==Gettext )
+ pos.form=_catalog->defaultNumberOfPluralForms()-1;
+ } else pos.form--;
+
+ gotoEntry(pos);
+ }
+
+}
+
+void KBabelView::gotoEntry()
+{
+ if( !_gotoDialog )
+ {
+ _gotoDialog = new GotoDialog(_catalog->numberOfEntries(),this);
+ }
+
+ _gotoDialog->exec();
+ if( _gotoDialog->result() )
+ {
+ int number=_gotoDialog->number()-1;
+ int max=_catalog->numberOfEntries()-1;
+
+ if(number>max)
+ number=max;
+ else
+ if(number<0)
+ number=0;
+
+ DocPosition pos;
+ pos.item=number;
+ pos.form=0;
+ gotoEntry(pos);
+ }
+
+}
+
+void KBabelView::gotoNextFuzzy()
+{
+ DocPosition pos;
+ if( _catalog->nextFuzzy(_currentIndex,pos) >= 0 )
+ {
+ gotoEntry(pos);
+ }
+}
+
+void KBabelView::gotoPrevFuzzy()
+{
+ DocPosition pos;
+ if( _catalog->prevFuzzy(_currentIndex,pos) >= 0 )
+ {
+ gotoEntry(pos);
+ }
+}
+
+void KBabelView::gotoNextError()
+{
+ DocPosition pos;
+ if(_catalog->nextError(_currentIndex,pos) >= 0 )
+ {
+ _dontBeep=true;
+ gotoEntry(pos);
+ _dontBeep=false;
+ }
+}
+
+void KBabelView::gotoPrevError()
+{
+ DocPosition pos;
+ if(_catalog->prevError(_currentIndex,pos) >= 0)
+ {
+ _dontBeep=true;
+ gotoEntry(pos);
+ _dontBeep=false;
+ }
+}
+
+void KBabelView::gotoNextFuzzyOrUntrans()
+{
+ DocPosition fuzzyPos,untransPos;
+
+ int fuzzyIndex=_catalog->nextFuzzy(_currentIndex,fuzzyPos);
+ int untransIndex=_catalog->nextUntranslated(_currentIndex,untransPos);
+
+ if(fuzzyIndex<0 && untransIndex<0 ) return;
+
+ if(fuzzyIndex<0)
+ {
+ gotoEntry(untransPos);
+ return;
+ }
+ if(untransIndex<0)
+ {
+ gotoEntry(fuzzyPos);
+ return;
+ }
+
+ if( fuzzyIndex<untransIndex
+ || (fuzzyIndex==untransIndex && fuzzyPos.form<untransPos.form))
+ {
+ gotoEntry(fuzzyPos);
+ }
+ else
+ {
+ gotoEntry(untransPos);
+ }
+}
+
+void KBabelView::gotoPrevFuzzyOrUntrans()
+{
+ DocPosition fuzzyPos,untransPos;
+
+ int fuzzyIndex=_catalog->prevFuzzy(_currentIndex,fuzzyPos);
+ int untransIndex=_catalog->prevUntranslated(_currentIndex,untransPos);
+
+ if(fuzzyIndex<0 && untransIndex<0 ) return;
+
+ if(fuzzyIndex<0)
+ {
+ gotoEntry(untransPos);
+ return;
+ }
+ if(untransIndex<0)
+ {
+ gotoEntry(fuzzyPos);
+ return;
+ }
+
+ if( fuzzyIndex>untransIndex
+ || (fuzzyIndex==untransIndex && fuzzyPos.form>untransPos.form))
+ {
+ gotoEntry(fuzzyPos);
+ }
+ else
+ {
+ gotoEntry(untransPos);
+ }
+}
+
+void KBabelView::gotoNextUntranslated()
+{
+ DocPosition pos;
+ if(_catalog->nextUntranslated(_currentIndex,pos)>=0)
+ {
+ gotoEntry(pos);
+ }
+}
+
+void KBabelView::gotoPrevUntranslated()
+{
+ DocPosition pos;
+ if(_catalog->prevUntranslated(_currentIndex,pos)>=0)
+ {
+ gotoEntry(pos);
+ }
+}
+
+
+void KBabelView::gotoEntry(const DocPosition& pos, bool updateHistory)
+{
+ // clear up statusbar
+ emit signalChangeStatusbar("");
+
+ if(updateHistory)
+ {
+ if(_forwardHistory.count()>0)
+ {
+ emit signalForwardHistory(false);
+ }
+ _forwardHistory.clear();
+ _backHistory.append(_currentIndex);
+
+ if(_backHistory.count()==1)
+ {
+ emit signalBackHistory(true);
+ }
+ else if(_backHistory.count()>MAX_HISTORY)
+ {
+ _backHistory.remove(_backHistory.begin());
+ }
+ }
+
+ informDictionary();
+
+ _currentPos=pos;
+ _currentIndex=pos.item;
+ updateEditor(pos.form,true);
+ emitEntryState();
+ updateTags();
+ updateArgs();
+}
+
+void KBabelView::msgstrPluralFormChanged ( uint index )
+{
+ _currentPos.form = index;
+ emit signalDisplayed (_currentPos);
+}
+
+void KBabelView::backHistory()
+{
+ if(_backHistory.isEmpty())
+ {
+ kdDebug(KBABEL) << "KBabelView::backHistory called without any history." << endl;
+ return;
+ }
+
+ _forwardHistory.append(_currentIndex);
+ uint index=_backHistory.last();
+ _backHistory.remove(_backHistory.fromLast());
+
+ DocPosition pos;
+ pos.item=index;
+ pos.form=0;
+ gotoEntry(pos,false);
+
+ if(_backHistory.count()==0)
+ {
+ emit signalBackHistory(false);
+ }
+ if(_forwardHistory.count()==1)
+ {
+ emit signalForwardHistory(true);
+ }
+}
+
+void KBabelView::forwardHistory()
+{
+ if(_forwardHistory.isEmpty())
+ {
+ kdDebug(KBABEL) << "KBabelView::forwardHistory called without any history." << endl;
+ return;
+ }
+
+ _backHistory.append(_currentIndex);
+ uint index=_forwardHistory.last();
+ _forwardHistory.remove(_forwardHistory.fromLast());
+
+ DocPosition pos;
+ pos.item=index;
+ pos.form=0;
+ gotoEntry(pos,false);
+
+ if(_forwardHistory.count()==0)
+ {
+ emit signalForwardHistory(false);
+ }
+ if(_backHistory.count()==1)
+ {
+ emit signalBackHistory(true);
+ }
+}
+
+void KBabelView::removeFuzzyStatus()
+{
+ bool newState = !_catalog->isFuzzy(_currentIndex);
+ _catalog->setFuzzy(_currentIndex,newState);
+
+ // ensure we will update the translation memory as needed
+ msgstrEdit->setModified (true);
+ emit signalFuzzyDisplayed(newState);
+}
+
+
+void KBabelView::editHeader()
+{
+ HeaderEditor* editor=_catalog->headerEditor();
+
+ int editHeight=editor->height();
+ int editWidth=editor->width();
+ int w=width();
+ int h=height();
+
+ int x=w/2-editWidth/2;
+ int y=h/2-editHeight/2;
+
+ editor->move(mapToGlobal(QPoint(x,y)));
+
+ editor->show();
+ editor->raise();
+
+}
+
+
+void KBabelView::stopSearch()
+{
+ dictBox->stopSearch();
+}
+
+void KBabelView::startSearch()
+{
+ startSearch(false);
+}
+
+void KBabelView::startSearch(bool delay)
+{
+ QString msg = _catalog->msgid(_currentIndex,true).first();
+ QRegExp reg=_catalog->miscSettings().contextInfo;
+ if(msg.contains(reg))
+ {
+ msg.replace(reg,"");
+ }
+
+ dictBox->setActiveModule(KBabelSettings::defaultModule());
+ if(delay)
+ {
+ dictBox->startDelayedSearch(msg);
+ }
+ else
+ {
+ dictBox->startSearch(msg);
+ }
+}
+
+void KBabelView::startSearch(const QString module)
+{
+ // FIXME: should care about plural forms
+ QString msg = _catalog->msgid(_currentIndex,true).first();
+ QRegExp reg=_catalog->miscSettings().contextInfo;
+ if(msg.contains(reg))
+ {
+ msg.replace(reg,"");
+ }
+
+ dictBox->setActiveModule(module);
+ dictBox->startSearch(msg);
+
+}
+
+void KBabelView::startSelectionSearch()
+{
+ startSelectionSearch(KBabelSettings::defaultModule());
+}
+
+void KBabelView::startSelectionSearch(const QString module)
+{
+ dictBox->setActiveModule(module);
+
+ if(msgidLabel->hasSelectedText())
+ {
+ // TODO: should we care about end of lines?
+ dictBox->startSearch(msgidLabel->selectedText());
+ }
+ else if(msgstrEdit->hasSelectedText())
+ {
+ dictBox->startTranslationSearch(msgstrEdit->selectedText());
+ }
+ else
+ {
+ // should care about plural forms
+ QString msg = _catalog->msgid(_currentIndex,true).first();
+ QRegExp reg=_catalog->miscSettings().contextInfo;
+ if(msg.contains(reg))
+ {
+ msg.replace(reg,"");
+ }
+
+ dictBox->startSearch(msg);
+ }
+}
+
+
+void KBabelView::emitEntryState()
+{
+ // flag, so I don't have to always change the color of the text
+ static bool isError=false;
+
+ emit signalDisplayed(_currentPos);
+
+ emit signalFirstDisplayed(_currentIndex==0, msgstrEdit->currentForm()==0);
+ emit signalLastDisplayed((unsigned)(_currentIndex+1)==_catalog->numberOfEntries(), (signed)(msgstrEdit->currentForm())==_catalog->numberOfPluralForms(_currentIndex)-1);
+
+ bool fuzzy=_catalog->isFuzzy(_currentIndex);
+ bool untrans=_catalog->isUntranslated(_currentIndex);
+ emit signalFuzzyDisplayed(fuzzy);
+ emit signalUntranslatedDisplayed(untrans);
+ emit signalFuzzyAfterwards(_catalog->hasFuzzyAfterwards(_currentIndex));
+ emit signalUntranslatedAfterwards(_catalog->hasUntranslatedAfterwards(_currentIndex));
+ emit signalFuzzyInFront(_catalog->hasFuzzyInFront(_currentIndex));
+ emit signalUntranslatedInFront(_catalog->hasUntranslatedInFront(_currentIndex));
+
+ emit signalErrorAfterwards(_catalog->hasErrorAfterwards(_currentIndex));
+ emit signalErrorInFront(_catalog->hasErrorInFront(_currentIndex));
+
+ DocPosition pos;
+ if( _catalog->hasError(_currentIndex,pos) != isError )
+ {
+ isError = !isError;
+
+ emit signalFaultyDisplayed(isError);
+
+ if(isError)
+ {
+ QPalette palette=msgstrEdit->palette();
+ palette.setColor( QColorGroup::Text, red );
+
+ if( _catalog->itemStatus(_currentIndex).contains("syntax error"))
+ {
+ msgstrEdit->setCurrentColor( MsgMultiLineEdit::ErrorColor );
+ }
+ else
+ if( !_catalog->itemStatus(_currentIndex).isEmpty() && KBabelSettings::autoCheckColorError())
+ {
+ msgstrEdit->setCurrentColor( MsgMultiLineEdit::ErrorColor );
+ }
+ }
+ else
+ {
+ msgstrEdit->setCurrentColor( MsgMultiLineEdit::NormalColor );
+ }
+ }
+
+}
+
+void KBabelView::checkFuzzies()
+{
+ emit signalFuzzyAfterwards(_catalog->hasFuzzyAfterwards(_currentIndex));
+ emit signalFuzzyInFront(_catalog->hasFuzzyInFront(_currentIndex));
+}
+
+void KBabelView::checkUntranslated()
+{
+ emit signalUntranslatedAfterwards(_catalog->hasUntranslatedAfterwards(_currentIndex));
+ emit signalUntranslatedInFront(_catalog->hasUntranslatedInFront(_currentIndex));
+}
+
+void KBabelView::autoRemoveFuzzyStatus()
+{
+ // only at first text change remove fuzzy status
+ disconnect(msgstrEdit,SIGNAL(textChanged()),this,SLOT(autoRemoveFuzzyStatus()));
+
+ //removeFuzzyStatus();
+}
+
+void KBabelView::toggleFuzzyLed(bool on)
+{
+ if(!_fuzzyLed)
+ return;
+
+ if(on)
+ {
+ if(_fuzzyLed->state()==KLed::Off)
+ {
+ _fuzzyLed->on();
+ }
+ }
+ else
+ {
+ if(_fuzzyLed->state()==KLed::On)
+ _fuzzyLed->off();
+ }
+}
+
+void KBabelView::toggleUntransLed(bool on)
+{
+ if(!_untransLed)
+ return;
+
+ if(on)
+ {
+ if(_untransLed->state()==KLed::Off)
+ _untransLed->on();
+ }
+ else
+ {
+ if(_untransLed->state()==KLed::On)
+ _untransLed->off();
+ }
+}
+
+void KBabelView::toggleErrorLed(bool on)
+{
+ if(!_errorLed)
+ return;
+
+ if(on)
+ {
+ if(_errorLed->state()==KLed::Off)
+ {
+ _errorLed->on();
+ }
+ }
+ else
+ {
+ if(_errorLed->state()==KLed::On)
+ _errorLed->off();
+ }
+}
+
+
+
+
+void KBabelView::showError(const QString& message)
+{
+ KMessageBox::error(this,message);
+}
+
+void KBabelView::dragEnterEvent(QDragEnterEvent *event)
+{
+ // accept uri drops only
+ event->accept(KURLDrag::canDecode(event));
+}
+
+void KBabelView::dropEvent(QDropEvent *event)
+{
+ KURL::List uri;
+
+ // see if we can decode a URI.. if not, just ignore it
+ if (KURLDrag::decode(event, uri))
+ {
+ processUriDrop(uri , mapToGlobal(event->pos()));
+ }
+}
+
+
+bool KBabelView::eventFilter( QObject* object, QEvent* event)
+{
+ if(event->type() == QEvent::DragEnter)
+ {
+ QDragEnterEvent* e = (QDragEnterEvent*) event;
+ if(KURLDrag::canDecode(e))
+ {
+ e->accept(true);
+ return true;
+ }
+ }
+ else if(event->type() == QEvent::Drop)
+ {
+ KURL::List uri;
+ // see if we can decode a URI.. if not, just ignore it
+ if (KURLDrag::decode((QDropEvent*)event, uri))
+ {
+ processUriDrop(uri ,( (QWidget*)object)->mapToGlobal( ( (QDropEvent*)event )->pos()));
+ return true;
+ }
+ }
+ else if(event->type() == QEvent::KeyPress)
+ {
+ // This is a little workaround to use CTRL+ALT+Home, CTRL+ALT+End, Undo keys
+ // to go to the first and the last entry. Because otherwise
+ // CTRL+Home and CTRL+End and Undo are caught by QTextEdit
+ QKeyEvent *ke = (QKeyEvent*)event;
+
+ if(ke->key() == Key_Home && ke->state() == (AltButton | ControlButton))
+ {
+ gotoFirst();
+ return true;
+ }
+ else if(ke->key() == Key_End
+ && ke->state() == (AltButton | ControlButton))
+ {
+ gotoLast();
+ return true;
+ }
+ else if( KShortcut(KKey(ke)) == KStdAccel::undo() )
+ {
+ undo();
+ return true;
+ }
+ else if( KShortcut(KKey(ke)) == KStdAccel::redo() )
+ {
+ redo();
+ return true;
+ }
+ else if( ke->key() == Key_Insert )
+ {
+ m_mainwindow->toggleEditMode();
+ return true;
+ }
+ }
+
+ return false;
+}
+
+void KBabelView::processUriDrop(KURL::List& uriList, const QPoint& pos)
+{
+ // if we have two entries, the chance is high, that it
+ // is a drag from the catalog manager
+ if(uriList.count() == 2)
+ {
+ int result = _dropMenu->exec(pos);
+ switch(result)
+ {
+ case ID_DROP_OPEN:
+ {
+ KURL first(uriList.first());
+ KURL second(uriList.last());
+
+ if( KIO::NetAccess::exists(first, true, this) )
+ {
+ open(first);
+ }
+ else
+ {
+ openTemplate(second,first);
+ }
+ break;
+ }
+ case ID_DROP_OPEN_TEMPLATE:
+ {
+ open(uriList.last());
+ break;
+ }
+ }
+ }
+ else
+ {
+ // okay, we have one URI.. process it
+ KURL url( uriList.first() );
+
+ // load in the file
+ open(url);
+ }
+}
+
+void KBabelView::forwardMsgstrEditCmd(EditCommand* cmd)
+{
+/*
+ if(cmd->terminator()!=0)
+ {
+ kdDebug(KBABEL) << QString::number(cmd->terminator()) << endl;
+ }
+ else
+ {
+ DelTextCmd* delcmd = (DelTextCmd*) cmd;
+ kdDebug(KBABEL) << QString::number(delcmd->offset)+":"+delcmd->str+"|" << endl;
+ }
+*/
+ bool fuzzyRemoved=false;
+ if(KBabelSettings::autoUnsetFuzzy() && _catalog->isFuzzy(_currentIndex) )
+ {
+ fuzzyRemoved=true;
+
+ _catalog->applyBeginCommand(_currentIndex,Msgstr,this);
+
+ removeFuzzyStatus();
+ }
+
+ cmd->setPart(Msgstr);
+ cmd->setIndex(_currentIndex);
+
+ bool wasUntranslated=_catalog->isUntranslated(_currentIndex);
+
+ _catalog->applyEditCommand(cmd,this);
+
+ if( fuzzyRemoved )
+ {
+ _catalog->applyEndCommand(_currentIndex,Msgstr,this);
+ }
+
+
+ bool isUntranslated=_catalog->isUntranslated(_currentIndex);
+
+ if(wasUntranslated && !isUntranslated)
+ emit signalUntranslatedDisplayed(false);
+ else if(!wasUntranslated && isUntranslated)
+ emit signalUntranslatedDisplayed(true);
+
+}
+
+void KBabelView::autoCheck()
+{
+ autoCheck(true);
+}
+
+
+void KBabelView::autoCheck(bool onlyWhenChanged)
+{
+ if( !_autocheckTools.isEmpty() )
+ {
+ QStringList oldStatus = _catalog->itemStatus(_currentIndex);
+
+ QStringList status = _catalog->itemStatus( _currentIndex,true, _autocheckTools );
+
+ // if there is more than one view, the status changes only in
+ // one view, so we have to update always.
+ if(_catalog->isLastView() && onlyWhenChanged && oldStatus == status)
+ return;
+
+ if( !status.isEmpty() )
+ {
+ QString msg = "";
+
+ // ### TODO: whynot use i18n("context",text) directly?
+ KLocale* locale=KGlobal::locale();
+
+ for( QStringList::iterator it=status.begin() ; it != status.end() ; ++it )
+ {
+ if( msg.isEmpty() ) msg = locale->translate("what check found errors",(*it).utf8());
+ else msg += ", "+locale->translate("what check found errors",(*it).utf8());
+ }
+
+ //i18n: translators: Status bar text that automatic checks have found some errors
+ emit signalChangeStatusbar(i18n("1 error: %1", "%n errors: %1", status.size ()).arg(msg));
+ emit signalFaultyDisplayed(true);
+
+ if(KBabelSettings::autoCheckColorError())
+ {
+ msgstrEdit->setCurrentColor( MsgMultiLineEdit::ErrorColor );
+ }
+
+ if(KBabelSettings::beepOnError() && !_dontBeep)
+ {
+ if(onlyWhenChanged)
+ {
+ if(oldStatus != status && oldStatus.isEmpty() )
+ {
+ KNotifyClient::beep();
+ }
+ }
+ else if(isActiveWindow())
+ {
+ KNotifyClient::beep();
+ }
+ }
+ }
+ else if( _catalog->itemStatus(_currentIndex).isEmpty() )
+ {
+ _catalog->removeFromErrorList(_currentIndex);
+
+ emit signalFaultyDisplayed(false);
+
+ if(KBabelSettings::autoCheckColorError())
+ {
+ msgstrEdit->setCurrentColor( MsgMultiLineEdit::NormalColor );
+ }
+ }
+ }
+}
+
+void KBabelView::spellcheckAll()
+{
+ spell.what2Check=All;
+ spellcheck();
+}
+
+void KBabelView::spellcheckAllMulti()
+{
+ spell.what2Check=AllMulti;
+ spellcheck();
+}
+
+
+void KBabelView::spellcheckFromCursor()
+{
+ spell.what2Check=End;
+ spellcheck();
+}
+
+
+void KBabelView::spellcheckCurrent()
+{
+ spell.what2Check=Current;
+ spellcheck();
+}
+
+void KBabelView::spellcheckFromCurrent()
+{
+ spell.what2Check=BeginCurrent;
+ spellcheck();
+}
+
+
+void KBabelView::spellcheckMarked()
+{
+ if(!msgstrEdit->hasSelectedText())
+ {
+ return;
+ }
+
+ spell.what2Check=Marked;
+ spellcheck();
+}
+
+
+void KBabelView::spellcheckCommon()
+{
+ SpellDlg *spellDlg = new SpellDlg(msgstrEdit->hasSelectedText(),this
+ ,"SpellDlg");
+
+ if(spellDlg->exec())
+ {
+ if(spellDlg->all())
+ spell.what2Check=All;
+ else if(spellDlg->current())
+ spell.what2Check=Current;
+ else if(spellDlg->begin())
+ spell.what2Check=Begin;
+ else if(spellDlg->end())
+ spell.what2Check=End;
+ else if(spellDlg->marked())
+ spell.what2Check=Marked;
+ else if(spellDlg->beginCurrent())
+ spell.what2Check=BeginCurrent;
+ else
+ {
+ kdError() << "unhandled option in spell dialog" << endl;
+ return;
+ }
+
+ spellcheck();
+ }
+
+ delete spellDlg;
+}
+
+void KBabelView::addSpellcheckWords( uint pos, QString text, uint index, uint form )
+{
+ // special format chars
+ QString spclChars="abfnrtv'\"?\\";
+ QChar accelMarker=_catalog->miscSettings().accelMarker;
+
+ uint textLength=text.length();
+ do
+ {
+ QString word="";
+ bool wordBegin=false;
+ while(!wordBegin && pos < textLength)
+ {
+ QChar c=text[pos];
+ if(c.isLetter() || c==accelMarker)
+ {
+ wordBegin=true;
+ }
+ else if( c == '\\')
+ {
+ if(pos+1 < textLength && spclChars.contains(text[pos+1]) )
+ {
+ pos+=2;
+ }
+ else
+ {
+ // consider it to be unnecessary escaped character
+ pos++;
+ }
+ }
+ else
+ {
+ pos++;
+ }
+ }
+ int begin=pos;
+
+ bool wordEnd=false;
+ while(!wordEnd && pos < textLength)
+ {
+ if(text[pos].isLetter() || text[pos]=='-' || (text[pos]=='\'' && !spell.config->dictionary().startsWith("malti")))
+ {
+ word+=text[pos];
+ pos++;
+ }
+ else if(text[pos]==accelMarker)
+ {
+ pos++;
+ }
+ else if(text[pos]=='\n')
+ {
+ // newline without \n counts as nothing
+ pos++;
+ }
+ else
+ {
+ wordEnd=true;
+ }
+ }
+
+ int end=pos;
+
+ // remove '-' and accelMarker at the end of a word
+ while(text[end]=='-' || (text[pos]=='\'' && !spell.config->dictionary().startsWith("malti"))
+ || text[end]==accelMarker)
+ {
+ end--;
+ word.truncate(word.length()-1);
+ }
+
+ if(!word.isEmpty())
+ {
+ spell.wordList.append(word);
+ Position *pos = new Position;
+ pos->index=index;
+ pos->form=form;
+ pos->pos=begin;
+ pos->end=end;
+ spell.posDict.append(pos);
+ }
+ }
+ while(pos < textLength);
+}
+
+void KBabelView::spellcheck()
+{
+ if(isReadOnly() || spell.active)
+ return;
+
+ spell.wordList.clear();
+ spell.posDict.clear();
+ spell.ignoreList.clear();
+ spell.newIgnoreList.clear();
+
+ spell.misspelled=0;
+ spell.replaced=0;
+ spell.lastIndex=0;
+ spell.posCorrection=0;
+ spell.lastPos=0;
+ spell.inWordCorrection=0;
+
+ if( !_spellcheckSettings.valid )
+ {
+ _spellcheckSettings = _project->spellcheckSettings();
+ }
+
+ spell.config = new KSpellConfig(this,"tempSpellConfig");
+ spell.config->setNoRootAffix(_spellcheckSettings.noRootAffix);
+ spell.config->setRunTogether(_spellcheckSettings.runTogether);
+ spell.config->setClient(_spellcheckSettings.spellClient);
+ spell.config->setEncoding(_spellcheckSettings.spellEncoding);
+ spell.config->setDictionary(_spellcheckSettings.spellDict);
+
+ if(spell.what2Check==Marked)
+ {
+ spell.lastIndex=_currentIndex;
+
+ _tagExtractor->setString(msgstrEdit->selectedText());
+ QString marked=_tagExtractor->plainString(true);
+
+ addSpellcheckWords(msgstrEdit->beginOfMarkedText(),marked
+ ,_currentIndex,msgstrEdit->currentForm());
+ }
+ else
+ {
+ uint first=0;
+ uint last=_catalog->numberOfEntries()-1;
+ QString text;
+
+ bool emitProgress=false;
+
+ if(spell.what2Check==All || spell.what2Check==Begin
+ || spell.what2Check==End || spell.what2Check==AllMulti
+ || spell.what2Check==BeginCurrent)
+ {
+ emitProgress=true;
+ }
+
+ if(spell.what2Check==Begin)
+ {
+ first=0;
+ last=_currentIndex-1;
+ }
+ else if(spell.what2Check==End)
+ {
+ first=_currentIndex+1;
+ last=_catalog->numberOfEntries()-1;
+
+ int pos=msgstrEdit->currentIndex();
+ int form=msgstrEdit->currentForm();
+
+ QStringList msgs = _catalog->msgstr(_currentIndex);
+ _tagExtractor->setString((*msgs.at(form)));
+ text=_tagExtractor->plainString(true);
+ addSpellcheckWords( pos, text, _currentIndex, form++ );
+
+ for( QStringList::Iterator i=msgs.at(form++) ; i!=msgs.end(); i++)
+ {
+ _tagExtractor->setString(*i);
+ text=_tagExtractor->plainString(true);
+ addSpellcheckWords( pos, text, _currentIndex, form++ );
+ }
+ }
+ else if(spell.what2Check==BeginCurrent)
+ {
+ first=_currentIndex;
+ last=_catalog->numberOfEntries()-1;
+ }
+ else if(spell.what2Check!=All && spell.what2Check!=AllMulti)
+ {
+ first=last=_currentIndex;
+ }
+
+ if(emitProgress)
+ {
+ emit signalResetProgressBar(i18n("Preparing spell check"),100);
+ kapp->processEvents(100);
+ }
+
+ uint total=last-first+1;
+ uint lastPercent=0;
+ for(uint i=first; i <= last; i++)
+ {
+ if(emitProgress && 100*i/ QMAX(total,1) > lastPercent)
+ {
+ lastPercent++;
+ emit signalProgress(lastPercent);
+
+ kapp->processEvents(100);
+ }
+
+ QStringList msgs=_catalog->msgstr(i);
+ uint formCounter=0;
+ for(QStringList::Iterator j=msgs.begin() ; j!=msgs.end() ; ++j)
+ {
+ _tagExtractor->setString(*j);
+ text=_tagExtractor->plainString(true);
+ addSpellcheckWords(0,text,i,formCounter++);
+ }
+ }
+
+ if(spell.what2Check==Begin)
+ {
+ int pos=msgstrEdit->currentIndex();
+ int form=msgstrEdit->currentForm();
+
+ QStringList msgs = _catalog->msgstr(_currentIndex);
+ _tagExtractor->setString((*msgs.at(form)).left(pos));
+ text=_tagExtractor->plainString(true);
+ addSpellcheckWords( 0, text, _currentIndex, form++ );
+
+ for( QStringList::Iterator i=msgs.at(form++) ; i!=msgs.end(); i++)
+ {
+ _tagExtractor->setString(*i);
+ text=_tagExtractor->plainString(true);
+ addSpellcheckWords( 0, text, _currentIndex, form++ );
+ }
+ }
+
+ if(emitProgress)
+ {
+ emit signalClearProgressBar();
+ }
+ }
+
+ if(!spell.wordList.isEmpty())
+ {
+ spell.active=true;
+ _dontBeep=true;
+
+ spell.kspell= new KSpell (this, i18n("Spellcheck"),
+ this, SLOT(spellStart(KSpell *)), spell.config, true, true);
+ if( spell.kspell->status() == KSpell::Error )
+ {
+ KMessageBox::error( this, i18n("KBabel cannot start spell checker. "
+ "Please verify your KDE installation.") );
+ return;
+ }
+
+ connect(spell.kspell, SIGNAL(death()),this, SLOT(spellCleanDone()));
+
+ connect(spell.kspell, SIGNAL(misspelling(const QString &, const QStringList &
+ , unsigned int)), this
+ , SLOT(spellMisspelled(const QString &, const QStringList &, unsigned int)));
+
+ connect(spell.kspell, SIGNAL(corrected(const QString &, const QString &, unsigned int))
+ , this, SLOT(spellCorrected(const QString &, const QString &, unsigned int)));
+
+ connect(spell.kspell,SIGNAL(ignoreall(const QString &))
+ , this, SLOT(spellAddIgnore(const QString &)));
+
+ connect(spell.kspell, SIGNAL(done(bool))
+ , this, SLOT(spellResult(bool)));
+
+ spell.kspell->setAutoDelete(true); // let KSpell handle delete
+ }
+ else
+ {
+ KMessageBox::information(this,i18n(
+ "No relevant text has been found for spell checking."));
+ }
+}
+
+void KBabelView::spellStart(KSpell *)
+{
+ // set ignored words
+ if(_spellcheckSettings.rememberIgnored)
+ {
+ QString urlString = _spellcheckSettings.ignoreURL;
+ if(urlString.contains("@PACKAGE@"))
+ {
+ urlString.replace("@PACKAGE@",_catalog->packageName());
+ }
+ // ### TODO: correctly set the URL; support for MostLocalURL
+ KURL url(urlString);
+ if(url.isLocalFile())
+ {
+ QFile file(url.path());
+ if(file.open(IO_ReadOnly))
+ {
+ QTextStream stream(&file);
+ stream.setEncoding(QTextStream::UnicodeUTF8);
+ QString contents = stream.read();
+ file.close();
+
+ spell.ignoreList = QStringList::split('\n',contents);
+ }
+ else if(file.exists())
+ {
+ KMessageBox::sorry(this,
+ i18n("Error opening the file that contains words "
+ "to ignore during spell checking:\n"
+ "%1").arg(file.name()));
+ }
+ }
+ else
+ {
+ KMessageBox::sorry(this,
+ i18n("Only local files are allowed for saving "
+ "ignored words to during spell checking:\n"
+ "%1").arg(urlString));
+ }
+
+ if(spell.ignoreList.count() > 0)
+ {
+ emit signalResetProgressBar(i18n("Preparing spell check"),100);
+ kapp->processEvents(100);
+
+ uint total = spell.ignoreList.count();
+ uint oldPercent=0;
+ uint counter=0;
+ QStringList::Iterator it;
+ for(it=spell.ignoreList.begin(); it != spell.ignoreList.end(); ++it)
+ {
+ counter++;
+ if(counter/total > oldPercent)
+ {
+ oldPercent++;
+ emit signalProgress(oldPercent);
+ kapp->processEvents(100);
+ }
+
+ spell.kspell->ignore(*it);
+ }
+
+ emit signalClearProgressBar();
+ }
+ }
+
+ spell.kspell->checkList(&spell.wordList);
+}
+
+
+bool KBabelView::markMisspelled(const QString &orig, unsigned int pos)
+{
+ Position *p = spell.posDict.at(pos);
+ if(!p)
+ {
+ kdError() << "not a valid position: " << pos << endl;
+ return false;
+ }
+
+ if(p->index != _currentIndex || (p->index==_currentIndex && p->form!=msgstrEdit->currentForm()))
+ {
+ DocPosition pos;
+ pos.item=p->index;
+ pos.form=p->form;
+ gotoEntry(pos);
+ }
+
+
+ if(p->index != spell.lastIndex)
+ {
+ spell.lastIndex=p->index;
+ spell.posCorrection=0;
+ }
+ if(pos != spell.lastPos)
+ {
+ spell.lastPos=pos;
+ spell.inWordCorrection=0;
+ }
+
+ int x=0;
+ int y=0;
+
+ int begin=p->pos+spell.posCorrection-spell.inWordCorrection;
+ int end=p->end+spell.posCorrection-spell.inWordCorrection;
+
+ // check if this is the correct word
+ QString text = *_catalog->msgstr(p->index).at(p->form);
+ text=text.mid(begin,end-begin);
+ QChar accelMarker=_catalog->miscSettings().accelMarker;
+
+ if(text.contains(accelMarker))
+ {
+ text.replace(accelMarker,"");
+ }
+ if(text.contains('\n'))
+ {
+ text.replace("\n","");
+ }
+
+ bool textOk=true;
+ if(text != orig)
+ {
+ // if text and orig are not the same,
+ // maybe it was a word with hyphens
+ int n=text.contains('-');
+ n+=text.contains('\'');
+ if( n > 0 )
+ {
+ // re-get the original text since we replace some things above
+ QString text = *_catalog->msgstr(p->index).at(p->form);
+ text=text.mid(begin,end-begin);
+
+ bool textFound=false;
+ int i = 0;
+ int e=-1;
+ while(!textFound && i <= n)
+ {
+ int lastPos=e+1;
+ e = text.find('-',lastPos);
+ int tmp = text.find('\'',lastPos);
+ if(e < 0 && tmp > 0)
+ {
+ e=tmp;
+ }
+ else if(e > 0 && tmp > 0 && tmp < e)
+ {
+ e=tmp;
+ }
+
+ if(e<0) e=text.length();
+
+ QString w=text.mid(lastPos,e-lastPos);
+ if(w.contains(accelMarker))
+ {
+ w.replace(accelMarker,"");
+ }
+ if(text.contains('\n'))
+ {
+ text.replace("\n","");
+ }
+ if( w == orig)
+ {
+ textFound=true;
+ end=begin+e;
+ begin=begin+lastPos;
+ }
+
+ i++;
+ }
+
+ if(!textFound)
+ {
+ textOk=false;
+ }
+ }
+ else
+ {
+ textOk=false;
+ }
+ }
+
+ int beginx, beginy;
+
+ msgstrEdit->offset2Pos(end,y,x);
+ msgstrEdit->offset2Pos(begin,beginy,beginx);
+ msgstrEdit->setSelection(beginy,beginx,y,x);
+
+ if(!textOk)
+ {
+ text = *_catalog->msgstr(p->index).at(p->form);
+ text=text.mid(begin,end-begin);
+ kdDebug(KBABEL) << "Sync error: given: " << orig << " have: " << text << endl;
+ cancelSpellcheck();
+
+ KMessageBox::error(this,i18n(
+ "There seems to be an error with the synchronization "
+ "of the spell checking process and KBabel.\n"
+ "Please check that you have set the correct settings for "
+ "your language for spell checking.\n"
+ "If you have, and this problem is reproducible, please "
+ "send a detailed bug report (your spell checking options, "
+ "what file you have checked and what to do to reproduce "
+ "the problem) by using Help->Report Bug..."));
+ }
+
+ return textOk;
+}
+
+void KBabelView::spellMisspelled(const QString &orig, const QStringList &, unsigned int pos)
+{
+ kdDebug(KBABEL) << "misspelled: " << orig << " pos: " << pos << endl;
+
+ spell.misspelled++;
+
+ markMisspelled(orig,pos);
+}
+
+void KBabelView::spellCorrected(const QString &orig, const QString &word, unsigned int pos)
+{
+ if(orig != word)
+ {
+ QString newWord(word);
+ kdDebug(KBABEL) << "corrected: " << orig << " " << newWord
+ << " pos: " << pos << endl;
+
+ if(spell.replaced==0)
+ {
+ // handle the spell check as one action
+ int index;
+ Position *p = spell.posDict.at(pos);
+ if(p)
+ {
+ index=p->index;
+ }
+ else
+ {
+ index=_currentIndex;
+ }
+
+ _catalog->applyBeginCommand(index,Msgstr,this);
+ }
+
+ spell.replaced++;
+
+
+ if(markMisspelled(orig,pos))
+ {
+ QString marked=msgstrEdit->selectedText();
+ spell.origWords.append(marked);
+
+ if(marked.contains("\n") && !newWord.contains('\n'))
+ {
+ QString s1=newWord;
+ s1.replace(" ","\n");
+
+ // if only a newline has been replaced with a white space
+ if(s1==marked)
+ {
+ newWord.replace(" "," \n");
+ }
+
+ }
+ // check if the old word had an accelerator. If yes and the new
+ // word has no accelerator, try to add the accelerator for
+ // the same char else add in at the same position
+ QChar accelMarker=_catalog->miscSettings().accelMarker;
+ if(marked.contains(accelMarker) && !newWord.contains(accelMarker))
+ {
+ int b=marked.find(accelMarker);
+ QChar accel=marked[b+1];
+ int nb=newWord.find(accel,0,false);
+ if(nb>=0)
+ {
+ newWord.insert(nb,accelMarker);
+ }
+ // if the new word does not contain the old accel char
+ // set the accelerator to the same position as the old
+ else
+ {
+ if((uint)b >= newWord.length())
+ b = 0;
+ newWord.insert(b,accelMarker);
+ }
+ }
+
+ spell.newWords.append(newWord);
+
+ msgstrEdit->cut();
+ int row=0;
+ int col=0;
+ msgstrEdit->getCursorPosition(&row,&col);
+ msgstrEdit->insertAt(newWord,row,col,true);
+
+ int newCorrection = newWord.length() - marked.length();
+ spell.posCorrection += newCorrection;
+ spell.inWordCorrection += newCorrection;
+
+ // now store the new position
+ Position *p = spell.posDict.at(pos);
+ if(p)
+ {
+ p->end=p->end+newCorrection;
+ }
+ }
+ }
+}
+
+
+void KBabelView::spellResult(bool flag)
+{
+ kdDebug(KBABEL) << "spellResult: " << flag << endl;
+
+
+ if(spell.replaced > 0)
+ {
+ // close the spell check action
+ _catalog->applyEndCommand(spell.lastIndex,Msgstr,this);
+ }
+
+
+ if(flag)
+ {
+ emit signalChangeStatusbar(i18n("Spellcheck: %n word replaced","Spellcheck: %n words replaced",spell.replaced));
+
+ if(spell.misspelled==0)
+ {
+ KMessageBox::information(this,i18n(
+ "Spellcheck successfully finished.\n"
+ "No misspelled words have been found."));
+ }
+ else if(spell.replaced > 0 && spell.what2Check!=Current
+ && spell.what2Check!=Marked)
+ {
+ QStringList list;
+ QStringList::Iterator origIt;
+ QStringList::Iterator newIt;
+ origIt=spell.origWords.begin();
+ newIt=spell.newWords.begin();
+
+ for(;origIt != spell.origWords.end()
+ && newIt != spell.newWords.end(); origIt++,newIt++)
+ {
+ list.append(*origIt+" -> "+*newIt);
+ }
+
+ }
+
+ if( spell.what2Check!=AllMulti && spell.misspelled!=0 )
+ KMessageBox::information(this,i18n("Spellcheck: %n word replaced","Spellcheck: %n words replaced",spell.replaced));
+
+ if(_spellcheckSettings.rememberIgnored)
+ {
+ if(spell.newIgnoreList.count() > 0)
+ {
+ KURL url(_spellcheckSettings.ignoreURL);
+ if(url.isLocalFile())
+ {
+ QFile file(url.path());
+ if(file.open(IO_WriteOnly|IO_Append))
+ {
+ QStringList::Iterator it;
+ QTextStream stream(&file);
+ stream.setEncoding(QTextStream::UnicodeUTF8);
+
+ for(it=spell.newIgnoreList.begin();
+ it!=spell.newIgnoreList.end();
+ ++it)
+ {
+ stream << *it << "\n";
+ }
+
+ file.close();
+ }
+ }
+ else
+ {
+ kdDebug(KBABEL) << "only local files are supported for storing"
+ << "ignored words" << endl;
+ }
+ }
+ }
+ }
+ else
+ {
+ emit signalChangeStatusbar(i18n("Spellcheck canceled"));
+ if(spell.replaced > 0)
+ undo();
+ }
+
+ int s=spell.kspell->dlgResult();
+ spell.kspell->cleanUp();
+
+ emit signalSpellcheckDone(s);
+ QTimer::singleShot(0,this,SLOT(cleanUpSpellStruct()));
+}
+
+
+void KBabelView::spellCleanDone()
+{
+ kdDebug(KBABEL) << "spellCleanDone" << endl;
+
+ // if the pointer is cleared, you have finished correcly
+ if( !spell.kspell ) return;
+
+ KSpell::spellStatus status = spell.kspell->status();
+
+ if(status == KSpell::Error || status == KSpell::Crashed)
+ {
+ cleanUpSpellStruct();
+ }
+
+ if(status == KSpell::Error)
+ {
+ KMessageBox::sorry(this, i18n("The spell checker program could not be started.\n"
+ "Please make sure you have the spell checker program properly "
+ "configured and in your PATH."));
+ }
+ else if(status == KSpell::Crashed)
+ {
+ KMessageBox::sorry(this, i18n("The spell checker program seems to have crashed."));
+ }
+}
+
+void KBabelView::cleanUpSpellStruct()
+{
+ kdDebug(KBABEL) << "Cleaning structure" << endl;
+ // spell.kspell is set to be autodeleted
+ spell.kspell = 0;
+ delete spell.config;
+ spell.config=0;
+ spell.wordList.clear();
+ spell.posDict.clear();
+ spell.origWords.clear();
+ spell.newWords.clear();
+ spell.ignoreList.clear();
+ spell.newIgnoreList.clear();
+ spell.active = false;
+ _dontBeep=false;
+}
+
+void KBabelView::cancelSpellcheck()
+{
+ spell.active=false;
+}
+
+void KBabelView::spellAddIgnore(const QString &word)
+{
+ if(!spell.ignoreList.contains(word))
+ {
+ spell.newIgnoreList.append(word);
+ }
+}
+
+void KBabelView::forwardSearchStart()
+{
+ emit signalResetProgressBar(i18n("Searching"),100);
+ emit signalSearchActive(true);
+}
+
+void KBabelView::forwardSearchStop()
+{
+ emit signalClearProgressBar();
+ emit signalSearchActive(false);
+}
+
+void KBabelView::forwardProgressStart(const QString& msg)
+{
+ emit signalResetProgressBar(msg,100);
+}
+
+void KBabelView::slotAutoSaveTimeout( )
+{
+ if ( isModified( ) )
+ {
+ autoSaveTimer->stop( );
+ saveFile( false );
+ autoSaveTimer->start( 1000 * 60 * _autoSaveDelay );
+ }
+}
+
+void KBabelView::useProject (Project::Ptr project)
+{
+ // FIXME: close the current project first
+ disconnect (_project, SIGNAL(signalSpellcheckSettingsChanged()),
+ this, SLOT(updateProjectSettings()));
+
+ _project = project;
+ _catalog->useProject(_project);
+
+ readProject(_project);
+
+ connect (project, SIGNAL(signalSpellcheckSettingsChanged()),
+ this, SLOT(updateProjectSettings()));
+}
+
+#include "kbabelview.moc"
diff --git a/kbabel/kbabel/kbabelview.h b/kbabel/kbabel/kbabelview.h
new file mode 100644
index 00000000..a52ed4dc
--- /dev/null
+++ b/kbabel/kbabel/kbabelview.h
@@ -0,0 +1,712 @@
+/* ****************************************************************************
+ This file is part of KBabel
+
+ Copyright (C) 1999-2000 by Matthias Kiefer
+ <matthias.kiefer@gmx.de>
+ 2002-2005 by Stanislav Visnovsky
+ <visnovsky@kde.org>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the 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, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+ In addition, as a special exception, the copyright holders give
+ permission to link the code of this program with any edition of
+ the Qt library by Trolltech AS, Norway (or with modified versions
+ of Qt that use the same license as Qt), and distribute linked
+ combinations including the two. You must obey the GNU General
+ Public License in all respects for all of the code used other than
+ Qt. If you modify this file, you may extend this exception to
+ your version of the file, but you are not obligated to do so. If
+ you do not wish to do so, delete this exception statement from
+ your version.
+
+**************************************************************************** */
+#ifndef KBABELVIEW_H
+#define KBABELVIEW_H
+
+class HidingMsgEdit;
+class MsgMultiLineEdit;
+class GotoDialog;
+class QPopupMenu;
+class KLed;
+class FindDialog;
+class ReplaceDialog;
+
+namespace KBabel
+{
+ class EditCommand;
+ class RegExpExtractor;
+ class FindOptions;
+ class ReplaceOptions;
+}
+
+class QListBoxItem;
+class QTextView;
+class QTabWidget;
+class KListBox;
+class KSpell;
+class KSpellConfig;
+class KBabelDictBox;
+class KDataToolInfo;
+struct ReplaceOptions;
+struct ModuleInfo;
+
+#include <kdockwidget.h>
+#include <kurl.h>
+#include <kconfig.h>
+#include <qwidget.h>
+#include <qstrlist.h>
+#include <resources.h>
+
+#include <catalogview.h>
+#include "kbcatalog.h"
+#include "kbproject.h"
+#include "projectsettings.h"
+
+class KBabelMW;
+class CommentView;
+class ContextView;
+class KBCatalogListView;
+class CharacterSelectorView;
+class SourceView;
+class TagListView;
+
+/**
+ * This is the main view class for KBabel. Most of the non-menu,
+ * non-toolbar, and non-statusbar (e.g., non frame) GUI code should go
+ * here.
+ * @short Main view
+ * @author Matthias Kiefer <matthias.kiefer@gmx.de>
+ * @version 0.1
+ */
+class KBabelView : public QWidget, public KBabel::CatalogView
+{
+ Q_OBJECT
+public:
+ /**
+ * Default constructor
+ * @param buildLeds flag, if status leds should be created in editor
+ */
+ KBabelView(KBCatalog* catalog,KBabelMW *parent, KBabel::Project::Ptr project);
+
+ /**
+ * Destructor
+ */
+ virtual ~KBabelView();
+
+ /**
+ * @return the view, that has opened file url or 0 if this
+ * file is not opened
+ */
+ static KBabelView *viewForURL(const KURL& url, const QString project);
+
+ /**
+ * @return the view, that has no opened file url or 0 if there
+ * is no such view
+ */
+ static KBabelView *emptyView(const QString project);
+
+ KURL currentURL() const;
+ QString project() const { return _project->filename(); }
+ void useProject (KBabel::Project::Ptr project);
+
+ bool isLastView() const;
+ bool isModified() const;
+ /** the edit mode of the entry-editors*/
+ bool isOverwriteMode() const;
+ bool isReadOnly() const;
+ /** the edit mode of the entry-editors*/
+ void setOverwriteMode(bool ovr);
+ bool isSearching() const;
+
+ void saveView(KConfig *config);
+ void restoreView(KConfig *config);
+ void saveSession(KConfig*);
+ void restoreSession(KConfig*);
+
+ void readSettings(KConfig* config);
+ void saveSettings();
+
+ void readProject(KBabel::Project::Ptr project);
+ void saveProject(KConfig* config);
+
+ void openTemplate(const KURL& openURL, const KURL& saveURL);
+ bool saveFile(bool checkSyntax=true);
+ bool saveFileAs(KURL url = KURL(), bool checkSyntax=true);
+ bool saveFileSpecial();
+
+ /**
+ * Checks, if the file has been modified. If true, it askes the user if he wants
+ * to save, discard or cancel. If the users chose save, it saves the file.
+ * @return true, if it is allowed to open a new file. false, if the user wants
+ * to edit the file again.
+ */
+ bool checkModified();
+
+
+ /**
+ * Checks syntax of the current catalog. If the catalog is modified it
+ * saves it under a temporary filename ( using @ref Catalog::saveTempFile ).
+ *
+ * @param msgOnlyAtError flag, if a message should be shown, only if
+ * a error occured.
+ * @param question flag, if only a information about the result should
+ * be shown or a question, whether the user wants to continue or cancel
+ *
+ * @return true, if no error occured or if an error occured but the user
+ * wants to continue anyway.
+ */
+ bool checkSyntax(bool msgOnlyAtError, bool question);
+
+ /**
+ * this is called from the catalog when updating his views.
+ * reimplemented from @ref CatalogView
+ * @param cmd the edit command that has been applied
+ */
+ virtual void update(KBabel::EditCommand* cmd, bool undo=false);
+
+ KBCatalog* catalog() const{return _catalog;}
+
+ void processUriDrop(KURL::List& uriList, const QPoint & pos);
+
+ /**
+ * checks the status of the displayed entry: last, first, fuzzy,...
+ * and emits the appropriate signals
+ */
+ void emitEntryState();
+
+ void setRMBEditMenu(QPopupMenu*);
+ void setRMBSearchMenu(QPopupMenu*);
+ void setTagsMenu(QPopupMenu*);
+ void setArgsMenu(QPopupMenu*);
+
+ QPtrList<ModuleInfo> dictionaries();
+ KBabelDictBox* searchView() { return dictBox; }
+
+ bool autoDiffEnabled() const {return _diffEnabled;}
+
+public slots:
+
+ void gotoEntry(const KBabel::DocPosition& pos, bool updateHistory=true);
+
+ /** opens a filedialog and asks for an url */
+ void open();
+ void open(const KURL& url, const QString & package=QString::null, bool checkModified=true, bool newView=false);
+ void setFilePackage();
+ void revertToSaved();
+
+ void updateSettings();
+ void updateProjectSettings();
+
+ void undo();
+ void redo();
+ void textCut();
+ void textCopy();
+ void textPaste();
+ bool findNext();
+ bool findPrev();
+ void find();
+ void findInFile(QCString fileSource, KBabel::FindOptions options);
+ void replaceInFile(QCString fileSource, KBabel::ReplaceOptions options);
+ void replace();
+ void selectAll();
+ void deselectAll();
+ void clear();
+ void msgid2msgstr();
+ void search2msgstr();
+ void plural2msgstr();
+ void gotoFirst();
+ void gotoLast();
+ void gotoNext();
+ void gotoPrev();
+ void gotoEntry();
+ void gotoNextFuzzyOrUntrans();
+ void gotoPrevFuzzyOrUntrans();
+ void gotoNextFuzzy();
+ void gotoPrevFuzzy();
+ void gotoNextUntranslated();
+ void gotoPrevUntranslated();
+ void gotoNextError();
+ void gotoPrevError();
+
+ void forwardHistory();
+ void backHistory();
+
+ void spellcheckAll();
+ void spellcheckAllMulti();
+ void spellcheckFromCursor();
+ void spellcheckCurrent();
+ void spellcheckFromCurrent();
+ void spellcheckMarked();
+ void spellcheckCommon();
+
+ void roughTranslation();
+ void diff();
+ void toggleAutoDiff(bool on);
+ void diffShowOrig();
+ bool openDiffFile();
+ void insertNextTag();
+ void insertNextTagMsgid();
+ void insertNextArg();
+ void insertTagFromTool( const QString& tag );
+ void showTagsMenu();
+ void showArgsMenu();
+ void skipToNextTag();
+ void skipToPreviousTag();
+ void skipToTagFromTool(int index);
+ void wordCount();
+
+ void removeFuzzyStatus();
+ /** opens the header editor for the po-file */
+ void editHeader();
+
+ /** checks the syntax of the file by using msgftm */
+ bool checkSyntax();
+
+ /**
+ * perform all checks listed above
+ */
+ bool checkAll();
+
+ void stopSearch();
+ void startSearch();
+ void startSelectionSearch();
+ void startSearch(const QString id);
+ void startSelectionSearch(const QString id);
+
+ void configureDictionary(const QString id);
+ void editDictionary(const QString id);
+ void aboutDictionary(const QString id);
+
+ /**
+ * this was originally protected, but we need this to expose for
+ * KBabelMW forwarding
+ */
+ virtual void wheelEvent(QWheelEvent*);
+
+protected:
+ virtual void dragEnterEvent(QDragEnterEvent *event);
+ virtual void dropEvent(QDropEvent *event);
+ virtual bool eventFilter(QObject*, QEvent* event);
+
+signals:
+ /** emited when a fuzzy catalogentry is shown */
+ void signalFuzzyDisplayed(bool);
+ /** emited when a untranslated catalogentry is shown */
+ void signalUntranslatedDisplayed(bool);
+ void signalFaultyDisplayed(bool);
+ /** emited when the first catalogentry is shown */
+ void signalFirstDisplayed(bool firstEntry, bool firstForm);
+ /** emited when the last catalog entry is shown */
+ void signalLastDisplayed(bool lastEntry, bool lastForm);
+
+ void signalNextTag( int index );
+
+ /**
+ * emited when a new entry is shown
+ * pos: position (index and plural form) of the currently shown entry
+ */
+ void signalDisplayed(const KBabel::DocPosition& pos);
+
+ /**
+ * emited when new entry is displayed and there is no
+ * fuzzy entry afterwards in the catalog
+ */
+ void signalFuzzyAfterwards(bool);
+ /**
+ * emited when new entry is displayed and there is no
+ * fuzzy entry in front of it in the catalog
+ */
+ void signalFuzzyInFront(bool);
+ /**
+ * emited when new entry is displayed and there is no
+ * untranslated entry afterwards in the catalog
+ */
+ void signalUntranslatedAfterwards(bool);
+ /**
+ * emited when new entry is displayed and there is no
+ * fuzzy entry in fornt of it in the catalog
+ */
+ void signalUntranslatedInFront(bool);
+
+ void signalErrorAfterwards(bool);
+ void signalErrorInFront(bool);
+
+ /**
+ * Use this signal to change the content of the statusbar
+ */
+ void signalChangeStatusbar(const QString& text);
+ /**
+ * Use this signal to change the content of the caption
+ */
+ void signalChangeCaption(const QString& text);
+
+ void signalNewFileOpened(KURL url);
+
+ void signalResetProgressBar(QString,int);
+ void signalProgress(int);
+ void signalClearProgressBar();
+
+ void signalSearchActive(bool);
+
+ void signalDiffEnabled(bool);
+
+ void signalForwardHistory(bool have);
+ void signalBackHistory(bool have);
+
+ void ledColorChanged(const QColor& color);
+
+ void signalDictionariesChanged();
+
+ void signalMsgstrChanged();
+
+ void signalNextTagAvailable(bool);
+ void signalTagsAvailable(bool);
+
+ void signalNextArgAvailable(bool);
+ void signalArgsAvailable(bool);
+
+ void signalCursorPosChanged(int line, int col);
+
+ void signalSpellcheckDone(int result);
+
+ void signalCopy();
+ void signalCut();
+ void signalPaste();
+ void signalSelectAll();
+
+private:
+ /**
+ * inserts the content of the current catalog entry into
+ * the fields in the view
+ * @param delay flag, if the auto search should be started delayed
+ * this is useful when a new file is opened
+ * @param formID number of the plural form to be displayed. Use 0 for
+ * no plural form
+ */
+ void updateEditor(int formID=0, bool delay=false);
+
+ void initDockWidgets();
+
+ void startSearch(bool delay);
+
+ /**
+ * makes some checks like checkings arguments and accels etc
+ * @param onlyWhenChanged flag, if message should only be shown
+ * when status changed
+ */
+ void autoCheck(bool onlyWhenChanged);
+
+ /**
+ * Create instances of tools currently setup for autochecks
+ */
+ void setupAutoCheckTools();
+
+ /**
+ * internal function to find next string given with @ref FindDialog
+ * starting at position pos
+ * @return true, if search was successful
+ */
+ bool findNext_internal(KBabel::DocPosition& pos, bool forReplace=false, bool mark=true);
+ /**
+ * internal function to find previous string given with @ref FindDialog
+ * starting at position pos
+ * @return true, if search was successful
+ */
+ bool findPrev_internal(KBabel::DocPosition& pos, bool forReplace=false, bool mark=true);
+
+ /**
+ * makes the real work
+ * @param autoDiff flag, if called from @ref autoDiff()
+ */
+ void diffInternal(bool autoDiff);
+
+ /**
+ * @param autoDiff flag, if called from @ref autoDiff()
+ */
+ bool openDiffFile(bool autoDiff);
+
+ /**
+ * Inserts a text into the msgstr (into the current form) using undoable commands.
+ * if @param clearFirst is set to true, it will clear the contents of msgstr before inserting
+ */
+ void modifyMsgstrText(const uint offset, const QString& text, bool clearFirst=false);
+
+protected slots:
+ bool validateUsingTool( const KDataToolInfo & info, const QString & command );
+ void modifyUsingTool( const KDataToolInfo & info, const QString & command );
+ void modifyCatalogUsingTool( const KDataToolInfo & info, const QString & command );
+
+private slots:
+ void msgstrPluralFormChanged (uint index);
+ void autoRemoveFuzzyStatus();
+
+ /** connected to the catalog. it is called when a new file is opened*/
+ void newFileOpened(bool readOnly);
+
+ void showError(const QString& message);
+
+ void toggleFuzzyLed(bool on);
+ void toggleUntransLed(bool on);
+ void toggleErrorLed(bool on);
+
+ void forwardMsgstrEditCmd(KBabel::EditCommand*);
+
+ /**
+ * called from a signal from ReplaceDialog to replace the
+ * current found string. After that it searches the next string
+ */
+ void replaceNext();
+ /**
+ * called from a signal from ReplaceDialog to replace
+ * all without asking anymore.
+ */
+ void replaceAll();
+ /**
+ * called from a signal from ReplaceDialog to go to next
+ * string to replace
+ */
+ void findNextReplace();
+
+ /**
+ * makes some checks like checkings arguments and accels etc
+ */
+ void autoCheck();
+
+ void autoDiff();
+
+ /**
+ * called, when text in msgstrEdit changes to inform
+ * the dictionary about the changes
+ */
+ void informDictionary();
+ void setNewLanguage();
+
+ void forwardProgressStart(const QString& msg);
+ void forwardSearchStart();
+ void forwardSearchStop();
+
+ /**
+ * checks if there is are fuzzy entries in front or behind
+ * the current entry and emits the appropriate signals
+ */
+ void checkFuzzies();
+ /**
+ * checks if there is are untranslated entries in front or behind
+ * the current entry and emits the appropriate signals
+ */
+ void checkUntranslated();
+
+ /** inserts the nth tag from the available tags into msgstr*/
+ void insertTag(int n);
+
+ /** visually display the tag to be inserted next */
+ void selectTag();
+
+ void updateTags();
+
+ /** inserts the nth argument from the available arguments into msgstr*/
+ void insertArg(int n);
+
+ void updateArgs();
+ void insertChar(QChar ch);
+
+ void showTryLaterMessageBox();
+
+ void dummy(KSpell*) {}
+
+private:
+ static QPtrList<KBabelView> *viewList;
+
+ HidingMsgEdit* msgstrEdit;
+ HidingMsgEdit* msgidLabel;
+ KBabelDictBox* dictBox;
+ GotoDialog* _gotoDialog;
+ FindDialog* _findDialog;
+ FindDialog* _replaceDialog;
+ ReplaceDialog* _replaceAskDialog;
+
+ QPopupMenu* _dropMenu;
+
+ KLed* _fuzzyLed;
+ KLed* _untransLed;
+ KLed* _errorLed;
+
+ KBCatalog* _catalog;
+ uint _currentIndex;
+ KBabel::DocPosition _currentPos;
+
+ KBabel::SpellcheckSettings _spellcheckSettings;
+
+ bool _autoSearchTempDisabled;
+
+ QValueList<uint> _backHistory;
+ QValueList<uint> _forwardHistory;
+
+ // flag to not beep, when switching to the next entry, because
+ // go -> next or prev entry was used.
+ bool _dontBeep;
+
+ /**
+ * position in document were find or replace function
+ * started to search
+ */
+ KBabel::DocPosition _findStartPos;
+ /**
+ * the string that was marked during the last search
+ */
+ QString _lastFoundString;
+
+ /*
+ * flag, if internal find functions should break at end or ask for
+ * beginning at the other end of the document
+ */
+ bool _findBreakAtEnd;
+
+ /*
+ * flag, if we search backwards and the direction was already
+ * changed (see findNext and findPrev)
+ */
+ bool _redirectedBackSearch;
+
+ bool _showTryLaterBox;
+
+ KBabel::DocPosition _replacePos;
+ int _replaceLen;
+ int _replacesTotal;
+ bool _replaceWasAtEnd;
+ /** contains the diff to the offset, where we started to search */
+ int _replaceExtraOffset;
+
+ /** appId for a source of the next files to be searched */
+ QCString _fileSource;
+
+ QStringList _tags;
+ QPopupMenu *_tagsMenu;
+
+ QStringList _args;
+ QPopupMenu *_argsMenu;
+
+ bool _diffEnabled;
+ bool _loadingDiffFile;
+ bool _diffing;
+
+ /*
+ * flag, set if editing KDE documentation PO-file
+ */
+ bool _editingDocumentation;
+ QPtrList<KDataTool> _autocheckTools;
+
+//spellcheck things
+private:
+ struct Position
+ {
+ uint index;
+ uint form;
+ uint pos;
+ uint end;
+ };
+
+ enum SpellWhat{All,AllMulti,Current,Marked,Begin,End,BeginCurrent};
+
+ struct
+ {
+ KSpell *kspell;
+ KSpellConfig* config;
+ QStringList wordList;
+ bool active;
+ int misspelled;
+ int replaced;
+ int posCorrection;
+ uint lastIndex;
+ QPtrList<Position> posDict;
+ SpellWhat what2Check;
+
+ // the last word, that was misspelled
+ uint lastPos;
+ // the position correction in the last word.
+ // needed if words with '-' are treated as seperate words
+ int inWordCorrection;
+
+ QStringList origWords;
+ QStringList newWords;
+
+ QStringList ignoreList;
+ QStringList newIgnoreList;
+ } spell;
+
+ struct {
+ KSpell *kspell;
+ KSpellConfig* config;
+ } spell2; // on-the-fly spellchecking
+
+ //DictSpellChecker * flyspell;
+
+
+ /**
+ * Marks a misspelled word in the editor.
+ * After that, the cursor is at the beginning of the
+ * marked text
+ * @param orig the original word as given from KSpell
+ * @param pos the position of the word in the StringList
+ * spell.wordList
+ *
+ * @returns false, if the there is a synchronization error,
+ * means the word has not been found in the editor.
+ */
+ bool markMisspelled(const QString &orig, unsigned int pos);
+
+private slots:
+ void spellcheck();
+ void cancelSpellcheck();
+ void spellStart(KSpell*);
+ void spellMisspelled(const QString &orig, const QStringList &sug, unsigned int pos);
+ void spellCorrected(const QString &orig, const QString &newWord, unsigned int pos);
+ void spellResult(bool);
+ void spellCleanDone();
+ void spellAddIgnore(const QString &);
+ // initialize spellchecking struct
+ void cleanUpSpellStruct();
+ void slotAutoSaveTimeout( );
+
+private:
+ void addSpellcheckWords(uint pos, QString text, uint index, uint form);
+
+private:
+ // configuration file
+ KSharedConfig::Ptr _config;
+ // project file
+ KBabel::Project::Ptr _project;
+
+ KBabel::RegExpExtractor* _tagExtractor;
+ KBabel::RegExpExtractor* _argExtractor;
+
+ QTimer * autoSaveTimer;
+ int _autoSaveDelay;
+
+ int _currentTag;
+
+ KBabelMW* m_mainwindow;
+ CommentView* m_commentview;
+ ContextView* m_contextview;
+ KBCatalogListView* m_cataloglistview;
+
+ CharacterSelectorView* m_charselectorview;
+ TagListView* m_taglistview;
+ SourceView* m_sourceview;
+
+ bool m_overwrite;
+};
+
+#endif // KBABELVIEW_H
diff --git a/kbabel/kbabel/kbabelview2.cpp b/kbabel/kbabel/kbabelview2.cpp
new file mode 100644
index 00000000..c07990d0
--- /dev/null
+++ b/kbabel/kbabel/kbabelview2.cpp
@@ -0,0 +1,1025 @@
+/* ****************************************************************************
+ This file is part of KBabel
+
+ Copyright (C) 1999-2000 by Matthias Kiefer
+ <matthias.kiefer@gmx.de>
+ 2002-2004 by Stanislav Visnovsky
+ <visnovsky@kde.org>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the 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, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+ In addition, as a special exception, the copyright holders give
+ permission to link the code of this program with any edition of
+ the Qt library by Trolltech AS, Norway (or with modified versions
+ of Qt that use the same license as Qt), and distribute linked
+ combinations including the two. You must obey the GNU General
+ Public License in all respects for all of the code used other than
+ Qt. If you modify this file, you may extend this exception to
+ your version of the file, but you are not obligated to do so. If
+ you do not wish to do so, delete this exception statement from
+ your version.
+
+**************************************************************************** */
+
+#include <kdatatool.h>
+#include <kdebug.h>
+#include <kfiledialog.h>
+#include <kinputdialog.h>
+#include <klocale.h>
+#include <kmessagebox.h>
+#include <knotifyclient.h>
+#include <kurl.h>
+#include <kio/netaccess.h>
+
+#include <qcheckbox.h>
+#include <qlabel.h>
+#include <qlayout.h>
+#include <qmessagebox.h>
+#include <qpopupmenu.h>
+#include <qvbox.h>
+
+#include "catalogsettings.h"
+#include "editcmd.h"
+#include "tagextractor.h"
+#include "kbabelview.h"
+#include "kbabeldictbox.h"
+#include "mymultilineedit.h"
+#include "hidingmsgedit.h"
+#include "roughtransdlg.h"
+#include "kbabelsettings.h"
+#include "kbprojectsettings.h"
+
+#include "resources.h"
+
+using namespace KBabel;
+
+QPtrList<ModuleInfo> KBabelView::dictionaries()
+{
+ QPtrList<ModuleInfo> list = dictBox->moduleInfos();
+
+ return list;
+}
+
+void KBabelView::configureDictionary(const QString id)
+{
+ dictBox->configure(id);
+}
+
+void KBabelView::editDictionary(const QString id)
+{
+ dictBox->edit(id);
+}
+
+
+void KBabelView::aboutDictionary(const QString id)
+{
+ dictBox->aboutModule(id);
+}
+
+void KBabelView::informDictionary()
+{
+ if( isSearching () )
+ stopSearch ();
+
+ if( msgstrEdit->isModified() )
+ dictBox->setTextChanged(_catalog->msgid(_currentIndex,true)
+ ,*(_catalog->msgstr(_currentIndex).at(msgstrEdit->currentForm()))
+ ,msgstrEdit->currentForm()
+ ,_catalog->comment(_currentIndex));
+}
+
+void KBabelView::setNewLanguage()
+{
+ IdentitySettings s = _catalog->identitySettings();
+
+ dictBox->setLanguage(s.languageCode, s.languageName);
+
+ // setup new plural form number
+ int form = msgstrEdit->currentForm();
+ if( form >= s.numberOfPluralForms )
+ form = s.numberOfPluralForms-1;
+
+ msgstrEdit->setNumberOfPlurals (s.numberOfPluralForms);
+ updateSettings();
+
+ if (! _catalog->currentURL().isEmpty())
+ {
+ updateEditor( form );
+ }
+}
+
+
+void KBabelView::wheelEvent(QWheelEvent *e)
+{
+ if( _catalog->numberOfEntries() == 0 ) return;
+
+ if( (e->state() & ControlButton) && (e->state() & AltButton))
+ {
+ if(e->delta() > 0)
+ {
+ gotoPrevFuzzyOrUntrans();
+ }
+ else
+ {
+ gotoNextFuzzyOrUntrans();
+ }
+ }
+ else if(e->state() & ControlButton)
+ {
+ if(e->delta() > 0)
+ {
+ gotoPrevFuzzy();
+ }
+ else
+ {
+ gotoNextFuzzy();
+ }
+ }
+ else if(e->state() & AltButton)
+ {
+ if(e->delta() > 0)
+ {
+ gotoPrevUntranslated();
+ }
+ else
+ {
+ gotoNextUntranslated();
+ }
+ }
+ else
+ {
+ if(e->delta() > 0)
+ {
+ gotoPrev();
+ }
+ else
+ {
+ gotoNext();
+ }
+ }
+
+ e->accept();
+}
+
+
+
+void KBabelView::roughTranslation()
+{
+ RoughTransDlg *dlg = new RoughTransDlg(dictBox, _catalog, this
+ , "roughtransDlg");
+
+ dlg->exec();
+
+ delete dlg;
+}
+
+
+void KBabelView::updateTags()
+{
+ bool hadTags = _tags.count() > 0;
+
+ _tags = _catalog->tagList(_currentIndex);
+
+ if(_tagsMenu)
+ {
+ _tagsMenu->clear();
+
+ QStringList tList;
+ QStringList::Iterator it;
+ int counter=0;
+ for(it=_tags.begin(); it!=_tags.end(); ++it)
+ {
+ QString s = *it;
+ if( s.startsWith("&") ) s = "&"+s;
+ if(!tList.contains(s))
+ {
+ _tagsMenu->insertItem(s,counter);
+ tList.append(s);
+ }
+ counter++;
+ }
+ }
+
+ bool haveTags = (_tags.count() > 0);
+
+ if(isReadOnly())
+ haveTags=false;
+
+ if(haveTags != hadTags)
+ {
+ emit signalNextTagAvailable(haveTags);
+ emit signalTagsAvailable(haveTags);
+ }
+
+ _currentTag = 0;
+
+ if(haveTags)
+ {
+ _tagExtractor->setString(_catalog->msgid(_currentIndex).first());
+ }
+ // if there is no tag, it will set invalid tag
+ selectTag();
+}
+
+void KBabelView::skipToNextTag()
+{
+ if( (uint)_currentTag >= _tags.count()-1 ) return;
+ ++_currentTag;
+ selectTag();
+}
+
+void KBabelView::skipToPreviousTag()
+{
+ if( _currentTag == 0 ) return;
+ --_currentTag;
+ selectTag();
+}
+
+void KBabelView::selectTag()
+{
+ if( _tagExtractor->countMatches() == 0 ) {
+ // no tags, select none
+ kdDebug() << "No tags" << endl;
+ msgidLabel->selectTag(0,0);
+ return;
+ }
+
+ // count number of eofs in tag
+ uint diff=0;
+ // FIXME: what about plural forms
+ QString msgid = _catalog->msgid(_currentIndex).first();
+
+ for( uint i = _tagExtractor->matchIndex(_currentTag); i < _tagExtractor->matchIndex(_currentTag)+_tags[_currentTag].length()+1; i++ )
+ {
+ if( msgid[i] == '\n' ) diff++;
+ }
+ msgidLabel->selectTag(_tagExtractor->matchIndex(_currentTag),_tags[_currentTag].length()+diff);
+ emit signalNextTag (_currentTag);
+}
+
+void KBabelView::setTagsMenu(QPopupMenu *menu)
+{
+ _tagsMenu=menu;
+
+ connect(_tagsMenu,SIGNAL(activated(int)),this,SLOT(insertTag(int)));
+}
+
+void KBabelView::modifyMsgstrText(const uint offset, const QString& text, bool clearFirst)
+{
+ _catalog->applyBeginCommand( _currentIndex, Msgstr ,this);
+
+ if( clearFirst ) msgstrEdit->clear();
+
+ InsTextCmd* insCmd = new InsTextCmd(offset,text,msgstrEdit->currentForm());
+ insCmd->setPart(Msgstr);
+ insCmd->setIndex(_currentIndex);
+
+ msgstrEdit->processCommand(insCmd,false);
+ forwardMsgstrEditCmd(insCmd);
+
+ _catalog->applyEndCommand(_currentIndex, Msgstr,this);
+
+ autoCheck( true ); // check it NOW - it should not be needed, but it is, I don't know why :-(
+}
+
+void KBabelView::insertTag(int n)
+{
+ QString tag = _tagsMenu->text(n);
+ if( tag.startsWith( "&&" ) ) tag = tag.remove(0,1); // replace && -> &. && is used for correct menu display
+
+ modifyMsgstrText( msgstrEdit->currentIndex(), tag );
+}
+
+void KBabelView::insertNextTag()
+{
+ if(_currentTag >= (int)_tags.count())
+ {
+ KNotifyClient::beep();
+ return;
+ }
+
+ int offset = msgstrEdit->currentIndex();
+
+ _currentTag++;
+ selectTag();
+
+ modifyMsgstrText( offset, _tags[_currentTag-1] );
+}
+
+void KBabelView::insertNextTagMsgid()
+{
+ TagExtractor extractor;
+
+ int offset = msgstrEdit->beginOfLastMarkedText(); //msgstrEdit->currentIndex();
+
+ QString s = (*_catalog->msgstr(_currentIndex).at(msgstrEdit->currentForm())).left(offset);
+
+ QString t;
+
+ if( _catalog->pluralForm( _currentIndex ) == KDESpecific )
+ {
+ int pos = msgstrEdit->currentIndex();
+ int currentFormBegin=s.findRev("\\n",pos);
+ if( currentFormBegin == -1 ) currentFormBegin=0;
+ else currentFormBegin+=3; // skip the newline
+ int currentFormEnd=s.find("\\n",pos);
+ if( currentFormEnd == -1 ) currentFormEnd=s.length();
+
+ s=s.mid(currentFormBegin,currentFormEnd-currentFormBegin);
+ }
+
+ extractor.setString(s);
+ uint num= extractor.countMatches();
+ if(num >= _tags.count())
+ {
+ KNotifyClient::beep();
+ return;
+ }
+
+ t=_tags[num];
+
+ modifyMsgstrText( offset, t );
+}
+
+void KBabelView::showTagsMenu()
+{
+ if(_tagsMenu && _tags.count() > 0)
+ {
+ int y=msgstrEdit->height()/2;
+ int x=msgstrEdit->width()/2;
+ _tagsMenu->exec(msgstrEdit->mapToGlobal( QPoint(x,y) ) );
+
+ return;
+ }
+}
+
+
+void KBabelView::updateArgs()
+{
+ bool hadArgs = _args.count() > 0;
+
+ _args = _catalog->argList(_currentIndex);
+
+ if(_argsMenu)
+ {
+ _argsMenu->clear();
+
+ QStringList tList;
+ QStringList::Iterator it;
+ int counter=0;
+ for(it=_args.begin(); it!=_args.end(); ++it)
+ {
+ QString s = *it;
+ if(!tList.contains(s))
+ {
+ _argsMenu->insertItem(s,counter);
+ tList.append(s);
+ }
+ counter++;
+ }
+ }
+
+ bool haveArgs = (_args.count() > 0);
+
+ if(isReadOnly())
+ haveArgs=false;
+
+ if(haveArgs != hadArgs)
+ {
+ emit signalNextArgAvailable(haveArgs);
+ emit signalArgsAvailable(haveArgs);
+ }
+}
+
+void KBabelView::setArgsMenu(QPopupMenu *menu)
+{
+ _argsMenu=menu;
+
+ connect(_argsMenu,SIGNAL(activated(int)),this,SLOT(insertArg(int)));
+}
+
+
+void KBabelView::insertArg(int n)
+{
+ QString arg = _argsMenu->text(n);
+
+ modifyMsgstrText( msgstrEdit->currentIndex(), arg );
+}
+
+void KBabelView::insertNextArg()
+{
+ int offset = msgstrEdit->currentIndex();
+
+ QString s = (*_catalog->msgstr(_currentIndex).at(msgstrEdit->currentForm())).left(offset);
+
+ if( _catalog->pluralForm( _currentIndex ) == KDESpecific )
+ {
+ int pos = msgstrEdit->currentIndex();
+ int currentFormBegin=s.findRev("\\n",pos);
+ if( currentFormBegin == -1 ) currentFormBegin=0;
+ else currentFormBegin+=3; // skip the newline
+ int currentFormEnd=s.find("\\n",pos);
+ if( currentFormEnd == -1 ) currentFormEnd=s.length();
+
+ s=s.mid(currentFormBegin,currentFormEnd-currentFormBegin);
+ }
+
+ _argExtractor->setString(s);
+ uint num=_argExtractor->countMatches();
+ if(num >= _args.count())
+ {
+ KNotifyClient::beep();
+ return;
+ }
+
+ QString t=_args[num];
+
+ modifyMsgstrText( offset,t );
+}
+
+void KBabelView::showArgsMenu()
+{
+ if(_argsMenu && _args.count() > 0)
+ {
+ int y=msgstrEdit->height()/2;
+ int x=msgstrEdit->width()/2;
+ _argsMenu->exec(msgstrEdit->mapToGlobal( QPoint(x,y) ) );
+
+ return;
+ }
+}
+
+
+void KBabelView::diff()
+{
+ diffInternal(false);
+ msgstrEdit->setFocus();
+}
+
+void KBabelView::diffShowOrig()
+{
+ msgidLabel->setText(_catalog->msgid(_currentIndex));
+ msgidLabel->forceUpdate();
+ msgstrEdit->setFocus();
+}
+
+void KBabelView::toggleAutoDiff(bool on)
+{
+ if(on != _diffEnabled)
+ {
+ _diffEnabled = on;
+
+ if(on)
+ {
+ diff();
+ }
+ else
+ {
+ diffShowOrig();
+ }
+ }
+}
+
+void KBabelView::autoDiff()
+{
+ diffInternal(true);
+}
+
+void KBabelView::diffInternal(bool autoDf)
+{
+ if(_diffing || _loadingDiffFile)
+ {
+ return;
+ }
+
+ _diffing = true;
+ uint diffIndex = _currentIndex;
+
+ QString diffString;
+
+ Catalog::DiffResult r = _catalog->diff(_currentIndex, &diffString);
+
+ if(r == Catalog::DiffNeedList)
+ {
+ switch( _project->settings()->useDBForDiff() )
+ {
+ case 1:
+ {
+ _loadingDiffFile=true;
+ bool wasEnabled=_diffEnabled;
+ _diffEnabled=false;
+
+ QValueList<DiffEntry> diffList;
+ QString error;
+ QString package = _catalog->packageName()+".po";
+ kdDebug(KBABEL) << "getting list for " << package << endl;
+
+ if(dictBox->messagesForPackage(package,diffList,error))
+ {
+ kdDebug(KBABEL) << "got " << diffList.count()
+ << " messages" << endl;
+ _catalog->setDiffList(diffList);
+ }
+ else
+ {
+ KMessageBox::sorry(this
+ ,i18n("An error occurred while trying to get the list "
+ "of messages for this file from the database:\n"
+ "%1").arg(error));
+
+ _diffing=false;
+ _diffEnabled=false;
+ _loadingDiffFile=false;
+ emit signalDiffEnabled(false);
+
+ return;
+ }
+
+ _diffEnabled=wasEnabled;
+ _loadingDiffFile=false;
+ break;
+ }
+ case 0:
+ {
+ _diffing=false;
+ if(!openDiffFile(true))
+ {
+ _diffEnabled=false;
+ emit signalDiffEnabled(false);
+
+ _diffing=false;
+ return;
+ }
+
+ _diffing = true;
+ break;
+ }
+ case 2:
+ {
+ // get the list of all entries
+ QValueList<DiffEntry> diffList = _catalog->asDiffList();
+
+ QValueList<DiffEntry> resultList;
+
+ // swap msgstr and msgid
+ QValueList<DiffEntry>::iterator it;
+ DiffEntry entry;
+
+ for ( it = diffList.begin(); it != diffList.end(); ++it )
+ {
+ entry.msgstr = (*it).msgid;
+ // if there is no translation, do not show difference
+ if( !(*it).msgstr.isEmpty() )
+ {
+ entry.msgid = (*it).msgstr;
+ }
+ else
+ {
+ entry.msgid = (*it).msgid;
+ }
+ resultList.append(entry);
+ }
+
+ // set as a source for diff
+ _catalog->setDiffList(resultList);
+
+ _diffing=false;
+ _diffEnabled=true;
+ _loadingDiffFile=false;
+ emit signalDiffEnabled(true);
+ }
+ }
+
+ diffIndex = _currentIndex;
+ r = _catalog->diff(_currentIndex, &diffString);
+ }
+
+ // if the index changed in the meanwhile
+ while(diffIndex != _currentIndex)
+ {
+ diffIndex=_currentIndex;
+ r = _catalog->diff(_currentIndex,&diffString);
+ }
+
+ if(r == Catalog::DiffOk)
+ {
+ msgidLabel->setText(diffString);
+ msgidLabel->forceUpdate();
+
+ // FIXME: should care about plural forms
+ if(diffString == _catalog->msgid(_currentIndex).first() )
+ {
+ emit signalChangeStatusbar(i18n("No difference found"));
+ }
+ else
+ {
+ emit signalChangeStatusbar(i18n("Difference found"));
+ }
+ }
+ else
+ {
+ if(!autoDf)
+ {
+ KMessageBox::information(this
+ ,i18n("No corresponding message found."));
+ }
+ else
+ {
+ emit signalChangeStatusbar(
+ i18n("No corresponding message found"));
+ }
+ }
+
+ _diffing = false;
+}
+
+bool KBabelView::openDiffFile()
+{
+ return openDiffFile(false);
+}
+
+bool KBabelView::openDiffFile(bool autoDiff)
+{
+ if(_diffing || _loadingDiffFile)
+ return false;
+
+ KURL url;
+
+ if( autoDiff && ! _project->settings()->diffBaseDir().isEmpty() )
+ {
+ KURL fileURL = _catalog->currentURL();
+
+ KURL poBaseURL( _project->catManSettings().poBaseDir );
+
+ QString poBase = poBaseURL.path();
+ int len = poBase.length();
+ if(fileURL.path().left(len) == poBase)
+ {
+ QString fileRelPath = fileURL.path().mid(len);
+ if(fileRelPath[0] == '/')
+ fileRelPath=fileRelPath.mid(1);
+
+ if(_project->settings()->diffBaseDir().right(1) != "/")
+ _project->settings()->diffBaseDir() += '/';
+
+ QString diffFilePath = _project->settings()->diffBaseDir() + fileRelPath;
+
+
+ KURL diffFileURL(diffFilePath);
+
+ if(diffFileURL.isValid() && KIO::NetAccess::exists(diffFileURL,true,NULL))
+ {
+ url = diffFileURL;
+
+ kdDebug(KBABEL) << "using file " << diffFileURL.prettyURL()
+ << " as diff file" << endl;
+ }
+ }
+ }
+
+
+ if(url.isEmpty())
+ {
+ url = KFileDialog::getOpenURL(_project->settings()->diffBaseDir(),
+"application/x-gettext", this, i18n("Select File to Diff With"));
+ }
+
+ if(url.isEmpty())
+ return false;
+
+ _loadingDiffFile=true;
+ bool wasEnabled=_diffEnabled;
+ _diffEnabled=false;
+
+
+ Catalog cat;
+
+ connect(&cat,SIGNAL(signalProgress(int)),this,SIGNAL(signalProgress(int)));
+ emit signalResetProgressBar(i18n("loading file for diff"),100);
+
+ ConversionStatus stat = cat.openURL(url);
+
+ emit signalClearProgressBar();
+
+
+ if(stat != OK && stat != RECOVERED_PARSE_ERROR)
+ {
+ switch(stat)
+ {
+ case PARSE_ERROR:
+ {
+ KMessageBox::sorry(this
+ ,i18n("Error while trying to read file:\n %1\n"
+ "Maybe it is not a valid PO file.").arg(url.prettyURL()));
+ break;
+ }
+ case NO_PERMISSIONS:
+ {
+ KMessageBox::sorry(this,i18n(
+ "You do not have permissions to read file:\n %1")
+ .arg(url.prettyURL()));
+ break;
+ }
+ case NO_FILE:
+ {
+ KMessageBox::sorry(this,i18n(
+ "You have not specified a valid file:\n %1")
+ .arg(url.prettyURL()));
+ break;
+ }
+ case NO_PLUGIN:
+ {
+ KMessageBox::error(this,i18n(
+ "KBabel cannot find a corresponding plugin for the MIME type of the file:\n %1").arg(url.prettyURL()));
+ break;
+ }
+ case UNSUPPORTED_TYPE:
+ {
+ KMessageBox::error(this,i18n(
+ "The import plugin cannot handle this type of the file:\n %1").arg(url.prettyURL()));
+ break;
+ }
+ default:
+ {
+ KMessageBox::sorry(this,i18n(
+ "Error while trying to open file:\n %1")
+ .arg(url.prettyURL()));
+ break;
+ }
+
+ }
+
+ _diffEnabled=wasEnabled;
+ _loadingDiffFile=false;
+
+ return false;
+ }
+
+ _catalog->setDiffList( cat.asDiffList() );
+
+ _diffEnabled=wasEnabled;
+ _loadingDiffFile=false;
+
+ return true;
+}
+
+void KBabelView::showTryLaterMessageBox()
+{
+ if( !_showTryLaterBox ) return;
+
+ KDialogBase *dialog= new KDialogBase(
+ i18n("Information"),
+ KDialogBase::Yes,
+ KDialogBase::Yes, KDialogBase::Yes,
+ this, "information", true, true,
+ KStdGuiItem::ok() );
+
+ QVBox *topcontents = new QVBox (dialog);
+ topcontents->setSpacing(KDialog::spacingHint()*2);
+ topcontents->setMargin(KDialog::marginHint()*2);
+
+ QWidget *contents = new QWidget(topcontents);
+ QHBoxLayout * lay = new QHBoxLayout(contents);
+ lay->setSpacing(KDialog::spacingHint()*2);
+
+ lay->addStretch(1);
+ QLabel *label1 = new QLabel( contents);
+ label1->setPixmap(QMessageBox::standardIcon(QMessageBox::Information));
+ lay->add( label1 );
+ QLabel *label2 = new QLabel( i18n("The search string has not been found yet.\n"
+ "However, the string might be found "
+ "in the files being searched at the moment.\n"
+ "Please try later."), contents);
+ label2->setAlignment( Qt::AlignAuto | Qt::AlignVCenter | Qt::ExpandTabs | Qt::WordBreak );
+ label2->setMinimumSize(label2->sizeHint());
+ lay->add( label2 );
+ lay->addStretch(1);
+
+ QCheckBox *checkbox = new QCheckBox(i18n("Do not show in this find/replace session again"), topcontents);
+
+ dialog->setMainWidget(topcontents);
+ dialog->enableButtonSeparator(false);
+ dialog->incInitialSize( QSize(50,0) );
+
+ dialog->exec();
+
+ _showTryLaterBox = !checkbox->isChecked();
+ delete dialog;
+}
+
+void KBabelView::setFilePackage()
+{
+ bool result=false;
+ QString p = KInputDialog::getText(QString::null, i18n("Enter new package for the current file:"),_catalog->package(),&result,this);
+ if( result )
+ {
+ _catalog->setPackage(p);
+ emit signalChangeCaption(p);
+ }
+}
+
+void KBabelView::insertTagFromTool( const QString& tag )
+{
+ modifyMsgstrText(msgstrEdit->currentIndex(),tag);
+
+ msgstrEdit->setFocus();
+}
+
+void KBabelView::skipToTagFromTool( int index )
+{
+ _currentTag = index;
+ selectTag();
+}
+
+void KBabelView::plural2msgstr()
+{
+ int currentFormBegin, currentFormEnd, pos;
+ uint i;
+
+ QStringList msgs = _catalog->msgstr(_currentIndex);
+ QString text= *msgs.at(msgstrEdit->currentForm());
+ uint numForms = _catalog->numberOfPluralForms(_currentIndex);
+
+ if( text.isEmpty() || _catalog->pluralForm(_currentIndex) == NoPluralForm) return;
+
+
+ QString result;
+
+ switch( _catalog->pluralForm(_currentIndex) )
+ {
+ case Gettext:
+
+ _catalog->applyBeginCommand( _currentIndex, Msgstr ,this);
+
+ i=0;
+ for( QStringList::Iterator it=msgs.begin() ; it!=msgs.end() ; ++it )
+ {
+ if( i!= msgstrEdit->currentForm() )
+ {
+ // clear first
+ DelTextCmd* insCmd = new DelTextCmd(0,(*it),i);
+ insCmd->setPart(Msgstr);
+ insCmd->setIndex(_currentIndex);
+ msgstrEdit->processCommand(insCmd,false);
+ forwardMsgstrEditCmd(insCmd);
+
+ // insert text
+ insCmd = new InsTextCmd(0,text,i);
+ insCmd->setPart(Msgstr);
+ insCmd->setIndex(_currentIndex);
+ msgstrEdit->processCommand(insCmd,false);
+ forwardMsgstrEditCmd(insCmd);
+ }
+ i++;
+ }
+
+ // fill the non-initialized ones
+ while (i != numForms)
+ {
+ // insert text
+ DelTextCmd* insCmd = new InsTextCmd(0,text,i);
+ insCmd->setPart(Msgstr);
+ insCmd->setIndex(_currentIndex);
+ msgstrEdit->processCommand(insCmd,false);
+ forwardMsgstrEditCmd(insCmd);
+ i++;
+ }
+
+ _catalog->applyEndCommand( _currentIndex, Msgstr ,this);
+
+ break;
+
+ case KDESpecific:
+ {
+ pos = msgstrEdit->currentIndex();
+ currentFormBegin=text.findRev("\\n",pos);
+ if( currentFormBegin == -1 ) currentFormBegin=0;
+ else currentFormBegin+=3; // skip the newline
+ currentFormEnd=text.find("\\n",pos);
+ if( currentFormEnd == -1 ) currentFormEnd=text.length();
+
+ text=text.mid(currentFormBegin,currentFormEnd-currentFormBegin);
+
+ QString result=text;
+ for( i=1; i<numForms ; i++ )
+ result+="\\n\n"+text;
+
+ modifyMsgstrText( 0, result, true );
+ }
+ break;
+
+ case NoPluralForm: break;
+ }
+
+}
+
+bool KBabelView::validateUsingTool( const KDataToolInfo & info, const QString &command )
+{
+ if(currentURL().isEmpty())
+ return false;
+
+ KDataTool* tool = info.createTool();
+ if( !tool )
+ {
+ kdWarning() << "Cannot create tool" << endl;
+ return false;
+ }
+
+ bool result=_catalog->checkUsingTool(tool);
+ emitEntryState();
+
+ QString checkName = *(info.userCommands().at( info.commands().findIndex(command) ));
+
+ if(result)
+ {
+ KMessageBox::information(this
+ ,i18n("No mismatch has been found.")
+ ,checkName);
+ }
+ else
+ {
+ int index=0;
+ DocPosition pos;
+
+ if(!_catalog->hasError(0,pos))
+ index = _catalog->nextError(0,pos);
+ if(index>=0)
+ {
+ kdDebug(KBABEL) << "Going to " << pos.item << ", " << pos.form << endl;
+ gotoEntry(pos);
+ }
+
+ KMessageBox::error(this
+ ,i18n("Some mismatches have been found.\n"
+ "Please check the questionable entries by using "
+ "Go->Next error")
+ ,checkName);
+ }
+ delete tool;
+
+ return result;
+}
+
+void KBabelView::modifyUsingTool( const KDataToolInfo & info, const QString &command )
+{
+ KDataTool* tool = info.createTool();
+ if( !tool )
+ {
+ kdWarning() << "Cannot create tool" << endl;
+ return;
+ }
+
+ // do some stuff on all entries
+ _catalog->modifyUsingTool(tool, command);
+
+ delete tool;
+}
+
+void KBabelView::modifyCatalogUsingTool( const KDataToolInfo & info, const QString &command )
+{
+ KDataTool* tool = info.createTool();
+ if( !tool )
+ {
+ kdWarning() << "Cannot create tool" << endl;
+ return;
+ }
+
+ // do some stuff on the catalog
+ tool->run(command, _catalog, "Catalog", "application/x-kbabel-catalog");
+
+ delete tool;
+}
+
+void KBabelView::insertChar( QChar ch )
+{
+ if( isReadOnly() || _catalog->package().isEmpty() )
+ return;
+
+ modifyMsgstrText(msgstrEdit->currentIndex(),ch);
+ msgstrEdit->setFocus();
+}
+
+void KBabelView::wordCount()
+{
+ uint total, untranslated, fuzzy;
+
+ _catalog->wordCount( total, fuzzy, untranslated );
+
+ KMessageBox::information( this
+ , i18n("Total words: %1\n\n"
+"Words in untranslated messages: %2\n\n"
+"Words in fuzzy messages: %3").arg(total).arg(untranslated).arg(fuzzy)
+ , i18n("Word Count") );
+}
diff --git a/kbabel/kbabel/kbbookmarkhandler.cpp b/kbabel/kbabel/kbbookmarkhandler.cpp
new file mode 100644
index 00000000..fde1b051
--- /dev/null
+++ b/kbabel/kbabel/kbbookmarkhandler.cpp
@@ -0,0 +1,131 @@
+/* ****************************************************************************
+ This file is part of KBabel
+
+ Copyright (C) 2002 by Marco Wegner <mail@marcowegner.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.
+
+ 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, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+ In addition, as a special exception, the copyright holders give
+ permission to link the code of this program with any edition of
+ the Qt library by Trolltech AS, Norway (or with modified versions
+ of Qt that use the same license as Qt), and distribute linked
+ combinations including the two. You must obey the GNU General
+ Public License in all respects for all of the code used other than
+ Qt. If you modify this file, you may extend this exception to
+ your version of the file, but you are not obligated to do so. If
+ you do not wish to do so, delete this exception statement from
+ your version.
+
+**************************************************************************** */
+
+
+#include <qpopupmenu.h>
+#include <qregexp.h>
+#include <qstring.h>
+
+#include "kbbookmarkhandler.h"
+
+
+// implementation of KBabelBookmark
+KBabelBookmark::KBabelBookmark(int msgindex, QString msgtext)
+{
+ _msgindex = msgindex;
+ if (msgtext.length() > 32) {
+ msgtext.truncate(32);
+ msgtext.append("...");
+ }
+
+ // insert one '&' before every consecutive group of ampersands to keep the
+ // first of these from acting either as accelerator or mask in the menu
+ QRegExp rx("&+");
+ int pos = msgtext.find(rx);
+ while (pos >= 0) {
+ msgtext.insert(pos, '&');
+ pos = msgtext.find(rx, pos + rx.matchedLength() + 1);
+ }
+
+ _msgtext = msgtext;
+}
+
+int KBabelBookmark::msgindex() const
+{
+ return _msgindex;
+}
+
+QString KBabelBookmark::msgtext() const
+{
+ return _msgtext;
+}
+
+
+// implementation of KBabelBookmarkHandler
+KBabelBookmarkHandler::KBabelBookmarkHandler(QPopupMenu* menu)
+{
+ _menu = menu;
+ _list.setAutoDelete(true);
+}
+
+void KBabelBookmarkHandler::addBookmark(KBabelBookmark* b)
+{
+ // check if a bookmark to the current msgid exists already
+ QPtrListIterator<KBabelBookmark> it(_list);
+ KBabelBookmark* temp;
+
+ while((temp = it.current()) != 0) {
+ ++it;
+ if (temp->msgindex() == b->msgindex()) {
+ // gotcha
+ delete b;
+ return;
+ }
+ }
+
+ // if it's okay then add the bookmark
+ _list.append(b);
+ _menu->insertItem(QString("#%1 - %2").arg(b->msgindex()).arg(b->msgtext()),
+ this, SIGNAL(signalBookmarkSelected(int)), 0, b->msgindex());
+}
+
+void KBabelBookmarkHandler::addBookmark(int msgindex, QString msgtext)
+{
+ addBookmark(new KBabelBookmark(msgindex, msgtext));
+}
+
+void KBabelBookmarkHandler::setBookmarks(QPtrList<KBabelBookmark> list)
+{
+ QPtrListIterator<KBabelBookmark> it(list);
+ KBabelBookmark* temp;
+
+ while((temp = it.current()) != 0) {
+ ++it;
+ addBookmark(temp->msgindex(), temp->msgtext()); // make deep copy
+ }
+}
+
+QPtrList<KBabelBookmark> KBabelBookmarkHandler::bookmarks() const
+{
+ return _list;
+}
+
+void KBabelBookmarkHandler::slotClearBookmarks()
+{
+ while (!_list.isEmpty()) {
+ KBabelBookmark* b = _list.first();
+ _menu->removeItem(b->msgindex());
+ _list.remove(b);
+ }
+}
+
+#include "kbbookmarkhandler.moc"
diff --git a/kbabel/kbabel/kbbookmarkhandler.h b/kbabel/kbabel/kbbookmarkhandler.h
new file mode 100644
index 00000000..f47c2dbf
--- /dev/null
+++ b/kbabel/kbabel/kbbookmarkhandler.h
@@ -0,0 +1,155 @@
+/* ****************************************************************************
+ This file is part of KBabel
+
+ Copyright (C) 2002 by Marco Wegner <mail@marcowegner.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.
+
+ 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, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+ In addition, as a special exception, the copyright holders give
+ permission to link the code of this program with any edition of
+ the Qt library by Trolltech AS, Norway (or with modified versions
+ of Qt that use the same license as Qt), and distribute linked
+ combinations including the two. You must obey the GNU General
+ Public License in all respects for all of the code used other than
+ Qt. If you modify this file, you may extend this exception to
+ your version of the file, but you are not obligated to do so. If
+ you do not wish to do so, delete this exception statement from
+ your version.
+
+**************************************************************************** */
+
+
+#ifndef KBBOOKMARKHANDLER_H
+#define KBBOOKMARKHANDLER_H
+
+#include <qobject.h>
+#include <qptrlist.h>
+
+class QPopupMenu;
+class QString;
+
+
+/**
+ * Simple class representing a bookmark in KBabel.
+ * Stored in the class are the msgindex (msgid #) and part of its text.
+ */
+class KBabelBookmark
+{
+ public:
+ /**
+ * Constructor.
+ * The msgtext will be truncated automatically when creating the bookmark.
+ *
+ * @param msgindex the index of the bookmarked msgid.
+ * @param msgtext the msgid.
+ */
+ KBabelBookmark(int msgindex, QString msgtext);
+
+ /**
+ * Return the index of the msgid.
+ *
+ * @return the index of the bookmarked msgid.
+ */
+ int msgindex() const;
+ /**
+ * Return the msgid.
+ *
+ * @return the msgid.
+ */
+ QString msgtext() const;
+
+ private:
+ /**
+ * The classes' own copy of the msgindex.
+ */
+ int _msgindex;
+ /**
+ * The classes' own copy of the msgid.
+ */
+ QString _msgtext;
+};
+
+
+/**
+ * Simple class for managing bookmarks in KBabel.
+ */
+class KBabelBookmarkHandler : public QObject
+{
+ Q_OBJECT
+
+ public:
+ /**
+ * Constructor.
+ *
+ * @param menu the pointer to the menu where the bookmarks will be
+ * displayed.
+ */
+ KBabelBookmarkHandler(QPopupMenu* menu);
+
+ /**
+ * Add a bookmark.
+ * The bookmark is added to the internal list as well as to the menu.
+ *
+ * @param b the bookmark to be added.
+ */
+ void addBookmark(KBabelBookmark* b);
+ /**
+ * Add a bookmark.
+ * Overloaded member. The bookmark will first be created from msgindex
+ * and msgtext.
+ *
+ * @param msgindex the index of the bookmark's msgid.
+ * @param msgtext the msgindex of the bookmark to be added.
+ */
+ void addBookmark(int msgindex, QString msgtext);
+ /**
+ * Provide the handler with a list of bookmarks.
+ * Especially useful when creating a new view of the KBabel window.
+ *
+ * @param list the list to be copied.
+ */
+ void setBookmarks(QPtrList<KBabelBookmark> list);
+ /**
+ * Return the list of bookmarks for a new view of the KBabel window.
+ *
+ * @return the internal list of bookmarks
+ */
+ QPtrList<KBabelBookmark> bookmarks() const;
+
+ public slots:
+ /**
+ * Clear all bookmarks.
+ */
+ void slotClearBookmarks();
+
+ signals:
+ /**
+ * This signal is emitted if one of the bookmarks was activated.
+ * The signal contains the msgindex of the bookmark.
+ */
+ void signalBookmarkSelected(int);
+
+ private:
+ /**
+ * The pointer to the menu.
+ */
+ QPopupMenu* _menu;
+ /**
+ * The internal list for storing the bookmarks.
+ */
+ QPtrList<KBabelBookmark> _list;
+};
+
+#endif // KBBOOKMARKHANDLER_H
diff --git a/kbabel/kbabel/kbcatalog.cpp b/kbabel/kbabel/kbcatalog.cpp
new file mode 100644
index 00000000..52205484
--- /dev/null
+++ b/kbabel/kbabel/kbcatalog.cpp
@@ -0,0 +1,63 @@
+/* ****************************************************************************
+ This file is part of KBabel
+
+ Copyright (C) 1999-2000 by Matthias Kiefer
+ <matthias.kiefer@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.
+
+ 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, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+ In addition, as a special exception, the copyright holders give
+ permission to link the code of this program with any edition of
+ the Qt library by Trolltech AS, Norway (or with modified versions
+ of Qt that use the same license as Qt), and distribute linked
+ combinations including the two. You must obey the GNU General
+ Public License in all respects for all of the code used other than
+ Qt. If you modify this file, you may extend this exception to
+ your version of the file, but you are not obligated to do so. If
+ you do not wish to do so, delete this exception statement from
+ your version.
+
+**************************************************************************** */
+
+#include "kbcatalog.h"
+#include "headereditor.h"
+
+
+KBCatalog::KBCatalog(QString configFile, QObject* parent, const char* name)
+ : KBabel::Catalog(parent,name,configFile)
+{
+ _headerEditor=0;
+}
+
+
+KBCatalog::~KBCatalog()
+{
+ if(_headerEditor)
+ delete _headerEditor;
+}
+
+HeaderEditor* KBCatalog::headerEditor()
+{
+ if(!_headerEditor)
+ {
+ _headerEditor = new HeaderEditor(this,"_headerEditor");
+ }
+
+ return _headerEditor;
+}
+
+
+
+#include "kbcatalog.moc"
diff --git a/kbabel/kbabel/kbcatalog.h b/kbabel/kbabel/kbcatalog.h
new file mode 100644
index 00000000..ae6508cf
--- /dev/null
+++ b/kbabel/kbabel/kbcatalog.h
@@ -0,0 +1,61 @@
+/* ****************************************************************************
+ This file is part of KBabel
+
+ Copyright (C) 1999-2000 by Matthias Kiefer
+ <matthias.kiefer@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.
+
+ 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, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+ In addition, as a special exception, the copyright holders give
+ permission to link the code of this program with any edition of
+ the Qt library by Trolltech AS, Norway (or with modified versions
+ of Qt that use the same license as Qt), and distribute linked
+ combinations including the two. You must obey the GNU General
+ Public License in all respects for all of the code used other than
+ Qt. If you modify this file, you may extend this exception to
+ your version of the file, but you are not obligated to do so. If
+ you do not wish to do so, delete this exception statement from
+ your version.
+
+**************************************************************************** */
+#ifndef KBCATALOG_H
+#define KBCATALOG_H
+
+#include "catalog.h"
+
+class HeaderEditor;
+
+
+/**
+* This class adds some functionality to the catalog,
+* that is needed by the gui.
+* * @author Matthias Kiefer <matthias.kiefer@gmx.de>
+*/
+class KBCatalog : public KBabel::Catalog
+{
+ Q_OBJECT
+
+public:
+ KBCatalog(QString configFile = QString::null ,QObject* parent=0, const char* name=0);
+ virtual ~KBCatalog();
+
+ HeaderEditor* headerEditor();
+
+private:
+ HeaderEditor* _headerEditor;
+
+};
+
+#endif //CATALOG_H
diff --git a/kbabel/kbabel/kbcataloglistview.cpp b/kbabel/kbabel/kbcataloglistview.cpp
new file mode 100644
index 00000000..51f9b008
--- /dev/null
+++ b/kbabel/kbabel/kbcataloglistview.cpp
@@ -0,0 +1,136 @@
+/* ****************************************************************************
+ This file is part of KBabel
+
+ Copyright (C) 2004 by Asgeir Frimannsson
+ <asgeirf@redhat.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.
+
+ 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, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+**************************************************************************** */
+
+#include "kbcataloglistview.h"
+#include "kbcataloglistviewitem.h"
+#include "kbcatalog.h"
+#include "kbabel.h"
+#include "editcmd.h"
+
+#include <klocale.h>
+#include <klistview.h>
+#include <qcolor.h>
+#include <qlayout.h>
+#include <kglobalsettings.h>
+
+using namespace KBabel;
+
+KBCatalogListView::KBCatalogListView(KBCatalog* catalog, QWidget *parent, KBabel::Project::Ptr project)
+ : QWidget(parent)
+{
+ m_catalog= catalog;
+ QVBoxLayout* layout=new QVBoxLayout(this);
+
+ m_listview = new KListView(this, "catalogListView");
+ m_listview->addColumn(i18n("Id"));
+ m_listview->addColumn(i18n("Original String"));
+ m_listview->addColumn(i18n("Translated String"));
+ m_listview->setAlternateBackground(KGlobalSettings::alternateBackgroundColor());
+ m_listview->setFullWidth(true);
+ m_listview->setAllColumnsShowFocus(true);
+ m_listview->resize(this->size());
+
+ layout->addWidget(m_listview);
+ layout->setStretchFactor(m_listview,1);
+
+ connect(m_listview,SIGNAL(selectionChanged(QListViewItem *)), this,SLOT(selectionChanged(QListViewItem *)));
+}
+
+KBCatalogListView::~KBCatalogListView()
+{
+}
+
+
+void KBCatalogListView::selectionChanged ( QListViewItem * item)
+{
+ DocPosition pos;
+ int number = m_items->find(reinterpret_cast<KBCatalogListViewItem*>(item));
+ if(number<0) number = 0;
+
+ pos.item=number;
+ pos.form=0;
+
+ emit signalSelectionChanged(pos);
+}
+
+void KBCatalogListView::setSelectedItem(int index)
+{
+ QListViewItem * item = m_items->at(index);
+
+ // block signals - don't reemit the selected item signal
+ blockSignals(true);
+ m_listview->setSelected(item, true);
+ blockSignals(false);
+
+ m_listview->ensureItemVisible(item);
+}
+
+void KBCatalogListView::update(EditCommand* cmd, bool undo)
+{
+ /*
+ if((int)_currentIndex==cmd->index())
+ {
+ emitEntryState();
+
+ if(cmd->part()==Msgstr)
+ {
+ msgstrEdit->processCommand(cmd,undo);
+ emit signalMsgstrChanged();
+ }
+ }
+ */
+}
+
+void KBCatalogListView::msgstrChanged(const QString& str)
+{
+ KBCatalogListViewItem * item = reinterpret_cast<KBCatalogListViewItem *>(m_listview->selectedItem());
+ item->setMsgStr(str);
+}
+
+void KBCatalogListView::slotNewFileOpened()
+{
+ m_listview->clear();
+ KBCatalogListViewItem * tempItem;
+ if(m_catalog)
+ {
+ m_items = new QPtrVector<KBCatalogListViewItem>(m_catalog->numberOfEntries());
+
+ for(uint i=0;i<m_catalog->numberOfEntries();i++)
+ {
+ QString msgid = ( *m_catalog->msgid(i).at(0) );
+ QString msgstr = ( *m_catalog->msgstr(i).at(0) );
+ tempItem = new KBCatalogListViewItem(m_listview,0,i+1,
+ msgid,
+ msgstr);
+ m_items->insert(i, tempItem);
+ }
+ }
+
+ int width = m_listview->columnWidth(1) + m_listview->columnWidth(2);
+ m_listview->setColumnWidth(1,width/2);
+ m_listview->setColumnWidth(2,width/2);
+
+
+}
+
+
+#include "kbcataloglistview.moc"
diff --git a/kbabel/kbabel/kbcataloglistview.h b/kbabel/kbabel/kbcataloglistview.h
new file mode 100644
index 00000000..d9737871
--- /dev/null
+++ b/kbabel/kbabel/kbcataloglistview.h
@@ -0,0 +1,82 @@
+/* ****************************************************************************
+ This file is part of KBabel
+
+ Copyright (C) 2004 by Asgeir Frimannsson
+ <asgeirf@redhat.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.
+
+ 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, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+**************************************************************************** */
+
+#ifndef KBCATALOGLISTVIEW_H
+#define KBCATALOGLISTVIEW_H
+
+#include <qwidget.h>
+#include <catalogview.h>
+#include <kconfig.h>
+#include <qwidget.h>
+//#include <qstrlist.h>
+#include <resources.h>
+#include "catalog.h"
+#include "kbcatalog.h"
+#include "kbproject.h"
+#include "projectsettings.h"
+#include "kbcataloglistviewitem.h"
+
+namespace KBabel{
+ class EditCommand;
+}
+
+class KBabelMW;
+class KBCatalog;
+class KListView;
+
+
+/**
+@author
+*/
+class KBCatalogListView : public QWidget, public KBabel::CatalogView
+{
+ Q_OBJECT
+public:
+ KBCatalogListView(KBCatalog* catalog, QWidget *parent, KBabel::Project::Ptr project);
+
+ ~KBCatalogListView();
+
+ /**
+ * this is called from the catalog when updating his views.
+ * reimplemented from @ref CatalogView
+ * @param cmd the edit command that has been applied
+ */
+ virtual void update(KBabel::EditCommand* cmd, bool undo=false);
+
+ void setSelectedItem(int index);
+signals:
+ void signalSelectionChanged(const KBabel::DocPosition& pos);
+
+public slots:
+ virtual void slotNewFileOpened();
+ void msgstrChanged(const QString&);
+
+private:
+ KListView * m_listview;
+ KBCatalog* m_catalog;
+ QPtrVector<KBCatalogListViewItem>* m_items;
+
+private slots:
+ void selectionChanged ( QListViewItem * item);
+};
+
+#endif
diff --git a/kbabel/kbabel/kbcataloglistviewitem.cpp b/kbabel/kbabel/kbcataloglistviewitem.cpp
new file mode 100644
index 00000000..5a4012a2
--- /dev/null
+++ b/kbabel/kbabel/kbcataloglistviewitem.cpp
@@ -0,0 +1,213 @@
+/* ****************************************************************************
+ This file is part of KBabel
+
+ Copyright (C) 2004 by Asgeir Frimannsson
+ <asgeirf@redhat.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.
+
+ 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, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+**************************************************************************** */
+
+#include "kbcataloglistviewitem.h"
+#include <assert.h>
+
+KBCatalogListViewItem::KBCatalogListViewItem(KListView* lv, KListViewItem* parent, uint id, QString msgid, QString msgstr)
+ : Super(lv, parent, "","",""), m_id(id), m_msgid(msgid), m_msgstr(msgstr)
+{
+ setText(0,QString::number(id));
+}
+
+
+KBCatalogListViewItem::~KBCatalogListViewItem()
+{
+}
+
+void KBCatalogListViewItem::setMsgId(const QString& st)
+{
+ m_msgid = st;
+ setup();
+ repaint();
+}
+
+void KBCatalogListViewItem::setMsgStr(const QString& st)
+{
+ m_msgstr = st;
+ setup();
+ repaint();
+}
+
+uint KBCatalogListViewItem::getId()
+{
+ return m_id;
+}
+
+void KBCatalogListViewItem::setId(const uint id)
+{
+ m_id = id;
+ setup();
+ repaint();
+}
+
+QString KBCatalogListViewItem::key ( int column, bool ascending ) const{
+
+ if(column==0)
+ return QString().sprintf("%.8u", m_id);
+ else if(column==1)
+ return m_msgid;
+ else if(column==2)
+ return m_msgstr;
+ else
+ return Super::key(column, ascending);
+}
+
+
+void KBCatalogListViewItem::setup()
+{
+ assert(listView());
+
+ widthChanged();
+
+ m_doc_msgid.reset(0);
+ m_doc_msgstr.reset(0);
+
+ makeDocAvailable();
+
+ QListView* lv = listView();
+
+ m_doc_msgid->setWidth(std::max(1, int(lv->columnWidth(1))));
+ m_doc_msgstr->setWidth(std::max(1, int(lv->columnWidth(2))));
+
+ if(m_doc_msgid->height() > m_doc_msgstr->height())
+ setHeight(m_doc_msgid->height());
+ else
+ setHeight(m_doc_msgstr->height());
+
+}
+
+
+void KBCatalogListViewItem::paintMsgIdCell(QPainter* p, const QColorGroup& cg,
+ int column, int width, int align)
+{
+ // check width
+
+ int widthPrepared = m_doc_msgid->width();
+
+ if (width != widthPrepared)
+ m_doc_msgid->setWidth(p, std::max(1, int(width)));
+
+ // check height
+
+ if (height() < m_doc_msgid->height() )
+ {
+ // invalid height, don't draw
+
+ setHeight(m_doc_msgid->height());
+ return;
+ }
+
+ // draw appropriate background
+
+ Super::paintCell(p, cg, column, width, align);
+
+ // draw it
+
+ m_doc_msgid->draw(p, 0, 0, QRect(0,0, width, height()), cg);
+
+}
+
+void KBCatalogListViewItem::paintMsgStrCell(QPainter* p, const QColorGroup& cg,
+ int column, int width, int align)
+{
+ // check width
+
+ int widthPrepared = m_doc_msgstr->width();
+
+ if (width != widthPrepared)
+ m_doc_msgstr->setWidth(p, std::max(1, int(width)));
+
+ // check height
+
+ if (height() < m_doc_msgstr->height() )
+ {
+ // invalid height, don't draw
+
+ setHeight(m_doc_msgstr->height());
+ return;
+ }
+ else if(height() > m_doc_msgstr->height() && height() > m_doc_msgid->height())
+ {
+ if(m_doc_msgstr->height() > m_doc_msgid->height())
+ setHeight(m_doc_msgstr->height());
+ else
+ setHeight(m_doc_msgid->height());
+
+ return;
+ }
+
+ // draw appropriate background
+
+ Super::paintCell(p, cg, column, width, align);
+
+ // draw it
+
+ m_doc_msgstr->draw(p, 0, 0, QRect(0,0, width, height()), cg);
+
+}
+
+void KBCatalogListViewItem::paintCell(QPainter* p, const QColorGroup& cg,
+ int column, int width, int align)
+{
+ assert(m_doc_msgid.get() && m_doc_msgstr.get() && p);
+
+ // paint background (empty text)
+
+
+ switch(column)
+ {
+ case 0: // id
+ Super::paintCell(p, cg, column, width, align);
+ return;
+ case 1: // msgid
+ paintMsgIdCell(p,cg,column,width,align);
+ return;
+ case 2: // msgstr
+ paintMsgStrCell(p,cg,column,width,align);
+ return;
+ }
+}
+
+void KBCatalogListViewItem::makeDocAvailable()
+{
+ if (m_doc_msgid.get() && m_doc_msgstr.get())
+ return;
+
+ assert(listView());
+
+ m_doc_msgid.reset(new QSimpleRichText(
+ formatMsg(m_msgid), listView()->font()));
+ m_doc_msgstr.reset(new QSimpleRichText(
+ formatMsg(m_msgstr), listView()->font()));
+}
+
+QString KBCatalogListViewItem::formatMsg(const QString str)
+{
+ // TODO: Use KBHighlighting for this
+ QString tmp_msgid = str;
+ tmp_msgid = tmp_msgid.replace( "\\n", "<br>" );
+ tmp_msgid = tmp_msgid.replace( "<", "&lt;" );
+ tmp_msgid = tmp_msgid.replace( ">", "&gt;" );
+
+ return tmp_msgid;
+}
diff --git a/kbabel/kbabel/kbcataloglistviewitem.h b/kbabel/kbabel/kbcataloglistviewitem.h
new file mode 100644
index 00000000..8fa6704a
--- /dev/null
+++ b/kbabel/kbabel/kbcataloglistviewitem.h
@@ -0,0 +1,72 @@
+/* ****************************************************************************
+ This file is part of KBabel
+
+ Copyright (C) 2004 by Asgeir Frimannsson
+ <asgeirf@redhat.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.
+
+ 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, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+**************************************************************************** */
+
+#ifndef KBCATALOGLISTVIEWITEM_H
+#define KBCATALOGLISTVIEWITEM_H
+#include <memory>
+#include <klistview.h>
+#include <qsimplerichtext.h>
+#include "mymultilineedit.h"
+
+/**
+@author
+*/
+class KBCatalogListViewItem : public KListViewItem
+{
+ typedef KListViewItem Super;
+public:
+ KBCatalogListViewItem(KListView* lv, KListViewItem* parent, uint id, QString msgid, QString msgstr);
+
+ ~KBCatalogListViewItem();
+
+ void setMsgId(const QString& st);
+ void setMsgStr(const QString& st);
+ void setId(const uint id);
+ uint getId();
+
+protected:
+
+ virtual void setup();
+ virtual QString key ( int column, bool ascending ) const;
+
+ virtual void paintCell(QPainter* p, const QColorGroup& cg,
+ int column, int width, int align);
+
+
+private:
+ void makeDocAvailable();
+ void paintMsgIdCell(QPainter* p, const QColorGroup& cg,
+ int column, int width, int align);
+ void paintMsgStrCell(QPainter* p, const QColorGroup& cg,
+ int column, int width, int align);
+
+ QString formatMsg(const QString str);
+
+ uint m_id;
+ QString m_msgid;
+ QString m_msgstr;
+
+ std::auto_ptr<QSimpleRichText> m_doc_msgid;
+ std::auto_ptr<QSimpleRichText> m_doc_msgstr;
+};
+
+#endif
diff --git a/kbabel/kbabel/kbcatalogview.cpp b/kbabel/kbabel/kbcatalogview.cpp
new file mode 100644
index 00000000..ba8e9c03
--- /dev/null
+++ b/kbabel/kbabel/kbcatalogview.cpp
@@ -0,0 +1,137 @@
+/* ****************************************************************************
+ This file is part of KBabel
+
+ Copyright (C) 2004-2005 by Stanislav Visnovsky
+ <visnovsky@kde.org>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the 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, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+ In addition, as a special exception, the copyright holders give
+ permission to link the code of this program with any edition of
+ the Qt library by Trolltech AS, Norway (or with modified versions
+ of Qt that use the same license as Qt), and distribute linked
+ combinations including the two. You must obey the GNU General
+ Public License in all respects for all of the code used other than
+ Qt. If you modify this file, you may extend this exception to
+ your version of the file, but you are not obligated to do so. If
+ you do not wish to do so, delete this exception statement from
+ your version.
+
+**************************************************************************** */
+
+#include "kbcatalogview.h"
+#include "resources.h"
+
+using namespace KBabel;
+
+KBCatalogView::KBCatalogView(KBCatalog* catalog, QWidget* parent, Project::Ptr project)
+ : QWidget (parent), KBabel::CatalogView () , _project (project)
+{
+ if (catalog == 0)
+ kdFatal(KBABEL) << "catalog==0" << endl;
+
+ _catalog=catalog;
+ _catalog->registerView(this);
+
+ _config = KSharedConfig::openConfig ("kbabelrc");
+
+ _currentIndex=1; // here we use 1 to accept update at opening a file
+
+ connect ( _project, SIGNAL (signalSettingsChanged()), this, SLOT (readProjectSettings()) );
+ connect ( _catalog, SIGNAL (signalFileOpened(bool)), this, SLOT (readFileSettings() ) );
+
+ readProjectSettings();
+ readFileSettings();
+ readConfigurationSettings();
+}
+
+KBCatalogView::~KBCatalogView()
+{
+ _catalog->removeView(this);
+
+ // check if this view was the last view and delete the catalog if necessary
+ if(!_catalog->hasView())
+ {
+ delete _catalog;
+ }
+}
+
+void KBCatalogView::update(EditCommand*, bool )
+{
+}
+
+void KBCatalogView::textCut()
+{
+}
+
+void KBCatalogView::textCopy()
+{
+}
+
+void KBCatalogView::textPaste()
+{
+}
+
+void KBCatalogView::textSelectAll()
+{
+}
+
+void KBCatalogView::gotoEntry(const DocPosition& pos)
+{
+ if ( _currentIndex == pos.item )
+ return;
+
+ _currentIndex=pos.item;
+
+ updateView ();
+}
+
+void KBCatalogView::readProjectSettings()
+{
+}
+
+void KBCatalogView::readFileSettings()
+{
+ setReadOnly (_catalog->isReadOnly());
+}
+
+void KBCatalogView::readConfigurationSettings()
+{
+}
+
+void KBCatalogView::readSessionSettings(KConfig *)
+{
+}
+
+void KBCatalogView::writeConfigurationSettings(KConfig *)
+{
+}
+
+void KBCatalogView::writeSessionSettings(KConfig *)
+{
+}
+
+void KBCatalogView::setReadOnly (bool on)
+{
+ setEnabled (on);
+}
+
+void KBCatalogView::setProject(KBabel::Project::Ptr project)
+{
+ _project = project;
+ readProjectSettings();
+}
+
+#include "kbcatalogview.moc"
diff --git a/kbabel/kbabel/kbcatalogview.h b/kbabel/kbabel/kbcatalogview.h
new file mode 100644
index 00000000..5f23381a
--- /dev/null
+++ b/kbabel/kbabel/kbcatalogview.h
@@ -0,0 +1,102 @@
+/* ****************************************************************************
+ This file is part of KBabel
+
+ Copyright (C) 2004-2005 by Stanislav Visnovsky
+ <visnovsky@kde.org>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the 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, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+ In addition, as a special exception, the copyright holders give
+ permission to link the code of this program with any edition of
+ the Qt library by Trolltech AS, Norway (or with modified versions
+ of Qt that use the same license as Qt), and distribute linked
+ combinations including the two. You must obey the GNU General
+ Public License in all respects for all of the code used other than
+ Qt. If you modify this file, you may extend this exception to
+ your version of the file, but you are not obligated to do so. If
+ you do not wish to do so, delete this exception statement from
+ your version.
+
+**************************************************************************** */
+#ifndef KBCATALOGVIEW_H
+#define KBCATALOGVIEW_H
+
+#include <qwidget.h>
+
+#include <catalogview.h>
+#include "kbcatalog.h"
+#include "kbproject.h"
+#include "projectsettings.h"
+
+class KBCatalogView : public QWidget, public KBabel::CatalogView
+{
+ Q_OBJECT
+public:
+ /**
+ * Default constructor
+ */
+ KBCatalogView(KBCatalog* catalog, QWidget* parent, KBabel::Project::Ptr project);
+
+ /**
+ * Destructor
+ */
+ virtual ~KBCatalogView();
+
+ /**
+ * this is called from the catalog when updating his views.
+ * reimplemented from @ref CatalogView
+ * @param cmd the edit command that has been applied
+ */
+ virtual void update(KBabel::EditCommand* cmd, bool undo=false);
+
+ KBCatalog* catalog() const{return _catalog;}
+
+public slots:
+ virtual void textCut();
+ virtual void textCopy();
+ virtual void textPaste();
+ virtual void textSelectAll();
+ virtual void gotoEntry(const KBabel::DocPosition& pos);
+ virtual void setProject(KBabel::Project::Ptr project);
+ virtual void readProjectSettings();
+ virtual void readFileSettings();
+ virtual void readConfigurationSettings();
+ virtual void readSessionSettings(KConfig *config);
+
+ virtual void writeConfigurationSettings(KConfig *config);
+ virtual void writeSessionSettings(KConfig *config);
+
+ virtual void setReadOnly (bool on);
+
+ /**
+ * this is called when the view needs an updating.
+ * It's the only really needed method to reimplement
+ */
+ virtual void updateView() = 0;
+
+signals:
+ void signalCursorPosChanged(int line, int col);
+
+protected:
+ KBCatalog* _catalog;
+ uint _currentIndex;
+
+ // configuration file
+ KSharedConfig::Ptr _config;
+ // project file
+ KBabel::Project::Ptr _project;
+};
+
+#endif // KBCATALOGVIEW_H
diff --git a/kbabel/kbabel/kbcharselect.cpp b/kbabel/kbabel/kbcharselect.cpp
new file mode 100644
index 00000000..63316255
--- /dev/null
+++ b/kbabel/kbabel/kbcharselect.cpp
@@ -0,0 +1,94 @@
+/* ****************************************************************************
+ This file is part of KBabel
+
+ Copyright (C) 2002 by Stanislav Visnovsky
+ <visnovsky@kde.org>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the 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, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+ In addition, as a special exception, the copyright holders give
+ permission to link the code of this program with any edition of
+ the Qt library by Trolltech AS, Norway (or with modified versions
+ of Qt that use the same license as Qt), and distribute linked
+ combinations including the two. You must obey the GNU General
+ Public License in all respects for all of the code used other than
+ Qt. If you modify this file, you may extend this exception to
+ your version of the file, but you are not obligated to do so. If
+ you do not wish to do so, delete this exception statement from
+ your version.
+
+**************************************************************************** */
+#include "kbcharselect.h"
+
+#include <kconfig.h>
+#include <kcharselect.h>
+#include <kdialog.h>
+#include <klocale.h>
+
+#include <qlabel.h>
+#include <qspinbox.h>
+#include <qscrollview.h>
+
+KBCharSelect::KBCharSelect(QWidget* parent,const char* name)
+ : QVBox(parent,name)
+{
+ setSpacing( KDialog::spacingHint() );
+
+ QHBox* bar = new QHBox(this);
+ bar->setSpacing( KDialog::spacingHint() );
+
+ QLabel *lTable = new QLabel( i18n( "Table:" ), bar );
+ _tableNum = new QSpinBox( 0, 255, 1, bar );
+ lTable->setBuddy( _tableNum );
+ bar->setStretchFactor( _tableNum, 1 );
+
+ QScrollView* scroll = new QScrollView( this );
+ _table = new KCharSelectTable(scroll,"charselector","helvetica",' ',0);
+ _table->setNumCols(16);
+ _table->setNumRows(16);
+
+ scroll->addChild(_table);
+
+ connect( _table, SIGNAL( doubleClicked() ), this, SLOT( emitChar() ) );
+ connect( _tableNum, SIGNAL( valueChanged(int) ), this, SLOT( setTab(int) ));
+}
+
+void KBCharSelect::emitChar()
+{
+ emit characterDoubleClicked( _table->chr() );
+}
+
+void KBCharSelect::setTab(int value)
+{
+ _table->setTableNum( value );
+}
+
+void KBCharSelect::saveSettings(KConfig* config)
+{
+ KConfigGroupSaver saver(config, "KBCharSelector" );
+
+ config->writeEntry( "TableNum", _tableNum->value() );
+ config->writeEntry( "SelectedChar", QString(_table->chr()) );
+}
+
+void KBCharSelect::restoreSettings(KConfig* config)
+{
+ KConfigGroupSaver saver(config, "KBCharSelector" );
+
+ _tableNum->setValue( config->readNumEntry("TableNum", 0 ));
+ _table->setChar( config->readEntry("SelectedChar"," ").at(0));
+}
+
+#include "kbcharselect.moc"
diff --git a/kbabel/kbabel/kbcharselect.h b/kbabel/kbabel/kbcharselect.h
new file mode 100644
index 00000000..4de3460f
--- /dev/null
+++ b/kbabel/kbabel/kbcharselect.h
@@ -0,0 +1,65 @@
+/* ****************************************************************************
+ This file is part of KBabel
+
+ Copyright (C) 2002 by Stanislav Visnovsky
+ <visnovsky@kde.org>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the 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, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+ In addition, as a special exception, the copyright holders give
+ permission to link the code of this program with any edition of
+ the Qt library by Trolltech AS, Norway (or with modified versions
+ of Qt that use the same license as Qt), and distribute linked
+ combinations including the two. You must obey the GNU General
+ Public License in all respects for all of the code used other than
+ Qt. If you modify this file, you may extend this exception to
+ your version of the file, but you are not obligated to do so. If
+ you do not wish to do so, delete this exception statement from
+ your version.
+
+**************************************************************************** */
+#ifndef KBCHARSELECT_H
+#define KBCHARSELECT_H
+
+#include <qvbox.h>
+
+class KConfig;
+class KCharSelectTable;
+class QSpinBox;
+
+class KBCharSelect : public QVBox
+{
+ Q_OBJECT
+public:
+ KBCharSelect(QWidget* parent, const char* name=0);
+
+ void saveSettings(KConfig* config);
+ void restoreSettings(KConfig* config);
+
+signals:
+ void characterDoubleClicked( QChar ch );
+
+public slots:
+ void emitChar();
+
+private slots:
+ void setTab( int value);
+
+private:
+ KCharSelectTable* _table;
+ QSpinBox* _tableNum;
+};
+
+#endif // KBCHARSELECT_H
diff --git a/kbabel/kbabel/kbhighlighting.cpp b/kbabel/kbabel/kbhighlighting.cpp
new file mode 100644
index 00000000..ce58c483
--- /dev/null
+++ b/kbabel/kbabel/kbhighlighting.cpp
@@ -0,0 +1,316 @@
+/* ****************************************************************************
+ This file is part of KBabel
+
+ Copyright (C) 2002 by Marco Wegner <mail@marcowegner.de>
+ 2003 Trolltech AS
+ 2003 Lukas Tinkl <lukas@kde.org>
+ 2003-2005 Stanislav Visnovsky <visnovsky@kde.org>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the 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, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+ In addition, as a special exception, the copyright holders give
+ permission to link the code of this program with any edition of
+ the Qt library by Trolltech AS, Norway (or with modified versions
+ of Qt that use the same license as Qt), and distribute linked
+ combinations including the two. You must obey the GNU General
+ Public License in all respects for all of the code used other than
+ Qt. If you modify this file, you may extend this exception to
+ your version of the file, but you are not obligated to do so. If
+ you do not wish to do so, delete this exception statement from
+ your version.
+
+**************************************************************************** */
+
+
+#include <qcolor.h>
+#include <qregexp.h>
+#include <qstring.h>
+#include <qtextedit.h>
+
+#include "kapplication.h"
+#include <kconfig.h>
+#include <kglobal.h>
+#include <kglobalsettings.h>
+#include <kbabelsettings.h>
+#include <kspell.h>
+
+#include "kbhighlighting.h"
+#include "resources.h"
+
+KBabelHighlighter::KBabelHighlighter( QTextEdit * edit, KSpell *spell ) : QObject()
+ , _edit( edit )
+ , syntaxHighlighting(true)
+ , mSpell(0), alwaysEndsWithSpace(true)
+{
+ regexps << "(<[_:A-Za-z][-_.:A-Za-z0-9]*([\\s]*[_:A-Za-z][-_.:A-Za-z0-9]*=\\\\\"[^<>]*\\\\\")*[\\s]*/?>)|(</[_:A-Za-z][-_.:A-Za-z0-9]*[\\s]*>)";
+ regexps << "(&[A-Za-z_:][A-Za-z0-9_.:-]*;)";
+ regexps << "(%[\\ddioxXucsfeEgGphln]+)|(%\\d+\\$[dioxXucsfeEgGphln])";
+ regexps << "(\\\\[abfnrtv'\"\?\\\\])|(\\\\\\d+)|(\\\\x[\\dabcdef]+)";
+
+ colors.resize( 8 );
+ colors[Normal] = KGlobalSettings::textColor();
+ colors[Tag] = KBabelSettings::tagColor ();
+ colors[Entity] = KBabelSettings::tagColor ();
+ colors[CFormat] = KBabelSettings::cformatColor ();
+ colors[Masked] = KBabelSettings::quotedColor ();
+ colors[Accel] = KBabelSettings::accelColor ();
+ colors[Error] = KBabelSettings::errorColor ();
+ colors[SpellcheckError] = KBabelSettings::spellcheckErrorColor ();
+
+ _hasErrors = false;
+
+ readSettings( );
+ regexps << accelMarker + "[\\w]";
+
+ connect( _edit, SIGNAL( textChanged( ) ), this, SLOT( highlight( ) ) );
+
+ setSpellChecker(spell);
+}
+
+// spell check the current text and highlight (as red text) those words
+// that fail the spell check
+void KBabelHighlighter::highlight( )
+{
+ // no updates while we're highlighting
+ _edit->blockSignals( true );
+ _edit->setUpdatesEnabled( false );
+
+ // store cursor position
+ int cpara, cindex;
+ _edit->getCursorPosition( &cpara, &cindex );
+
+ _edit->selectAll( );
+ _edit->setColor( _hasErrors ? colors[Error] : colors[Normal] );
+ _edit->removeSelection( );
+
+ // create a single line out of the text: remove "\n", so that we only
+ // have to deal with one single line of text.
+ QString text = _edit->text( );
+ text.replace( "\n", "" );
+
+ QRegExp rx;
+ int pos;
+
+ if (syntaxHighlighting)
+ {
+ for ( uint i = 0; i < regexps.count( ); ++i ) {
+ rx.setPattern( regexps[i] );
+ pos = text.find( rx );
+ while ( pos >= 0 ) {
+ doHighlighting( (HighlightType)(i+1), pos, rx.matchedLength( ) );
+ pos = text.find( rx, pos + rx.matchedLength( ) );
+ }
+ }
+ }
+
+ if( mSpell )
+ {
+ // spell-on-fly start
+ if (!text.endsWith(" "))
+ alwaysEndsWithSpace = false;
+ else
+ alwaysEndsWithSpace = true;
+
+ //MessageHighlighter::highlightParagraph( text, endStateOfLastPara );
+
+ int len = text.length();
+ if (alwaysEndsWithSpace)
+ len--;
+
+ currentPos = 0;
+ currentWord = "";
+ for (int i = 0; i < len; i++) {
+ if (text[i].isSpace() || text[i] == '-' || (text[i]=='\\' && text[i+1]=='n')) {
+ flushCurrentWord();
+ if (text[i]=='\\') i++;
+ currentPos = i + 1;
+ } else {
+ currentWord += text[i];
+ }
+ }
+
+ // this was if (!text[len - 1].isLetter())
+ // but then the last word is never checked
+ if (text[len - 1].isLetter()) {
+ kdDebug(KBABEL) << "flushing last Current word: " << currentWord << endl;
+ flushCurrentWord();
+ }
+ else {
+ kdDebug(KBABEL) << "not flushing last Current word: " << currentWord << endl;
+ }
+ } // spell-on-fly end
+
+ _edit->setColor( colors[Normal] );
+
+ //restore cursor position
+ _edit->setCursorPosition( cpara, cindex );
+
+ // allow updates again now that we're finished highlighting
+ _edit->setUpdatesEnabled( true );
+ _edit->blockSignals( false );
+ _edit->updateContents( );
+ _edit->ensureCursorVisible();
+}
+
+void KBabelHighlighter::doHighlighting( HighlightType type, int pos, int length )
+{
+ uint startPara = 0, endPara = 0, startIndex = pos, endIndex = pos+length;
+
+ // transform the one-dimensional indexes into two-dimensional ones
+ while ( startIndex > _edit->text( startPara ).length( ) )
+ startIndex -= _edit->text( startPara++ ).length( ) - 1;
+ while ( endIndex > _edit->text( endPara ).length( ) )
+ endIndex -= _edit->text( endPara++ ).length( ) - 1;
+
+ // and finally do the actual highlighting
+ _edit->setSelection( startPara, startIndex, endPara, endIndex );
+ _edit->setColor( colors[type] );
+ _edit->removeSelection( );
+}
+
+void KBabelHighlighter::setHighlightColor( HighlightType type, QColor color )
+{
+ colors[type] = color;
+}
+
+void KBabelHighlighter::setHasErrors( bool err )
+{
+ _hasErrors = err;
+}
+
+void KBabelHighlighter::readSettings( )
+{
+ // FIXME: does not care about different projects yet
+ KConfig * config = KGlobal::config( );
+ config->setGroup( "Misc" );
+ QString temp = config->readEntry( "AccelMarker", "&" );
+ accelMarker = temp[0];
+}
+
+static int dummy, dummy2;
+static int *Okay = &dummy;
+static int *NotOkay = &dummy2;
+
+void KBabelHighlighter::flushCurrentWord()
+{
+ while (currentWord[0].isPunct()) {
+ currentWord = currentWord.mid(1);
+ currentPos++;
+ }
+
+ QChar ch;
+ while ((ch = currentWord[(int) currentWord.length() - 1]).isPunct()
+ && ch != '(' && ch != '@')
+ currentWord.truncate( currentWord.length() - 1 );
+
+ // try to remove tags (they might not be fully compliant, but
+ // we don't want to check them anyway
+ QRegExp tags("(<[-_.:A-Za-z0-9]*([\\s]*[-_.:A-Za-z0-9]*=\\\\\"[^<>]*\\\\\")*[\\s]*/?>)|(</[-_.:A-Za-z0-9]*[\\s]*>)");
+ if( tags.search (currentWord) != -1 )
+ {
+ currentPos += tags.matchedLength();
+ }
+
+ currentWord.replace ( tags, "" );
+
+ if (!currentWord.isEmpty()) {
+ bool isPlainWord = true;
+ for (int i = 0; i < (int) currentWord.length(); i++) {
+ QChar ch = currentWord[i];
+ if (ch.upper() == ch) {
+ isPlainWord = false;
+ break;
+ }
+ }
+
+ if (/*isPlainWord && currentWord.length() > 2 &&*/ isMisspelled(currentWord))
+ doHighlighting(SpellcheckError,currentPos, currentWord.length());
+ }
+ currentWord = "";
+}
+
+QDict<int> KBabelHighlighter::dict(50021);
+
+bool KBabelHighlighter::isMisspelled(const QString& wordRaw)
+{
+ // We have to treat ampersands (like in "&go" or "g&o") in a special way.
+ // they must not break the word. And we cannot change the parameter, as
+ // then the highlight would be one character short. So we have to copy the
+ // word first.
+ QString word = wordRaw;
+ kdDebug(KBABEL) << "isampersand: checking (raw):" << word << endl;
+ word.replace("&", "" );
+ kdDebug(KBABEL) << "isMisspelled: checking: " << word << endl;
+
+ // Normally isMisspelled would look up a dictionary and return
+ // true or false, but kspell is asynchronous and slow so things
+ // get tricky...
+
+ // "dict" is used as a cache to store the results of KSpell
+ if (!dict.isEmpty() && dict[word] == NotOkay)
+ return true;
+ if (!dict.isEmpty() && dict[word] == Okay)
+ return false;
+
+ // there is no 'spelt correctly' signal so default to Okay
+ kdDebug(KBABEL) << "Adding word " << word << endl;
+ dict.replace(word, Okay);
+ mSpell->checkWord(word, false);
+ return false;
+}
+
+void KBabelHighlighter::slotMisspelling(const QString & originalword,
+ const QStringList & suggestions, unsigned int)
+{
+ kdDebug(KBABEL) << "Misspelled " << originalword << ", " << suggestions << endl;
+ dict.replace( originalword, NotOkay );
+
+ // this is slow but since kspell is async this will have to do for now
+ highlight();
+}
+
+void KBabelHighlighter::setSpellChecker( KSpell* spell )
+{
+ if( mSpell )
+ {
+ disconnect(mSpell, SIGNAL(misspelling(const QString &, const QStringList &, unsigned int)),
+ this, SLOT(slotMisspelling(const QString &, const QStringList &, unsigned int)));
+
+ // cleanup the cache
+ dict.clear();
+ }
+
+ mSpell = spell;
+
+ if( mSpell )
+ {
+ connect(mSpell, SIGNAL(misspelling(const QString &, const QStringList &, unsigned int)),
+ this, SLOT(slotMisspelling(const QString &, const QStringList &, unsigned int)));
+
+ // wait for KSpell to startup correctly
+ kapp->processEvents(500);
+ }
+
+ highlight();
+}
+
+void KBabelHighlighter::setSyntaxHighlighting( bool enable )
+{
+ syntaxHighlighting = enable;
+
+ // update highlighting
+ highlight();
+}
+#include "kbhighlighting.moc"
diff --git a/kbabel/kbabel/kbhighlighting.h b/kbabel/kbabel/kbhighlighting.h
new file mode 100644
index 00000000..91a6202d
--- /dev/null
+++ b/kbabel/kbabel/kbhighlighting.h
@@ -0,0 +1,104 @@
+/* ****************************************************************************
+ This file is part of KBabel
+
+ Copyright (C) 2002 by Marco Wegner <mail@marcowegner.de>
+ (C) 2003 TrollTech AS
+ (C) 2003 Lukas Tinkl <lukas@kde.org>
+ (C) 2003-2005 Stanislav Visnovsky <visnovsky@kde.org>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the 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, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+ In addition, as a special exception, the copyright holders give
+ permission to link the code of this program with any edition of
+ the Qt library by Trolltech AS, Norway (or with modified versions
+ of Qt that use the same license as Qt), and distribute linked
+ combinations including the two. You must obey the GNU General
+ Public License in all respects for all of the code used other than
+ Qt. If you modify this file, you may extend this exception to
+ your version of the file, but you are not obligated to do so. If
+ you do not wish to do so, delete this exception statement from
+ your version.
+
+**************************************************************************** */
+
+
+#ifndef KBHIGHLIGHTING_H
+#define KBHIGHLIGHTING_H
+
+#include <qmemarray.h>
+#include <qobject.h>
+#include <qstringlist.h>
+#include <qguardedptr.h>
+
+class KSpell;
+class QColor;
+class QString;
+class QTextEdit;
+
+class KBabelHighlighter : public QObject
+{
+ Q_OBJECT
+
+ public:
+ enum HighlightType {
+ Normal = 0,
+ Tag,
+ Entity,
+ CFormat,
+ Masked,
+ Accel,
+ Error,
+ SpellcheckError
+ };
+
+ KBabelHighlighter( QTextEdit * edit, KSpell *spell );
+
+ void setHighlightColor( HighlightType type, QColor color );
+ void setHasErrors( bool err );
+ void setSpellChecker( KSpell* spell);
+
+ bool isMisspelled(const QString& word);
+
+ public slots:
+ void highlight( );
+ void setSyntaxHighlighting( bool enable );
+
+ protected slots:
+ void slotMisspelling (const QString & originalword,
+ const QStringList & suggestions, unsigned int pos);
+
+ private:
+ void doHighlighting( HighlightType type, int pos, int length );
+ void readSettings( );
+ void flushCurrentWord();
+
+ private:
+ QTextEdit * _edit;
+ bool syntaxHighlighting;
+
+ QStringList regexps;
+ QMemArray<QColor> colors;
+
+ bool _hasErrors;
+ QString accelMarker;
+
+ static QDict<int> dict;
+ QGuardedPtr<KSpell> mSpell;
+ QString currentWord;
+ int currentPos;
+ bool alwaysEndsWithSpace;
+};
+
+#endif // KBHIGHLIGHTING_H
diff --git a/kbabel/kbabel/lo16-app-kbabel.png b/kbabel/kbabel/lo16-app-kbabel.png
new file mode 100644
index 00000000..98ee2659
--- /dev/null
+++ b/kbabel/kbabel/lo16-app-kbabel.png
Binary files differ
diff --git a/kbabel/kbabel/lo32-app-kbabel.png b/kbabel/kbabel/lo32-app-kbabel.png
new file mode 100644
index 00000000..8d52961b
--- /dev/null
+++ b/kbabel/kbabel/lo32-app-kbabel.png
Binary files differ
diff --git a/kbabel/kbabel/main.cpp b/kbabel/kbabel/main.cpp
new file mode 100644
index 00000000..40c28926
--- /dev/null
+++ b/kbabel/kbabel/main.cpp
@@ -0,0 +1,612 @@
+/* ****************************************************************************
+ This file is part of KBabel
+
+ Copyright (C) 1999-2001 by Matthias Kiefer <matthias.kiefer@gmx.de>
+ 2002-2005 by Stanislav Visnovsky <visnovsky@kde.org>
+ Copyright (C) 2006 by Nicolas GOUTTE <goutte@kde.org>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the 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, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+ In addition, as a special exception, the copyright holders give
+ permission to link the code of this program with any edition of
+ the Qt library by Trolltech AS, Norway (or with modified versions
+ of Qt that use the same license as Qt), and distribute linked
+ combinations including the two. You must obey the GNU General
+ Public License in all respects for all of the code used other than
+ Qt. If you modify this file, you may extend this exception to
+ your version of the file, but you are not obligated to do so. If
+ you do not wish to do so, delete this exception statement from
+ your version.
+
+**************************************************************************** */
+#include "kbabel.h"
+#include "kbabeliface.h"
+#include "kbprojectmanager.h"
+#include "catalog.h"
+#include "kbabelsplash.h"
+#include "findoptions.h"
+
+#include "version.h"
+
+#include <dcopclient.h>
+#include <kaboutdata.h>
+#include <kcmdlineargs.h>
+#include <kcursor.h>
+#include <klocale.h>
+#include <kmessagebox.h>
+#include <kuniqueapplication.h>
+#include <kwin.h>
+
+#include <qfile.h>
+#include <qfileinfo.h>
+#include <qtimer.h>
+
+class KBabelInterface : public KBabelIface
+{
+public:
+ KBabelInterface();
+
+ virtual void openURL(QCString url, QCString package, WId window, int newWindow);
+ virtual void openURL(QCString url, QCString package, WId window, int newWindow, QCString projectFile);
+ virtual void openTemplate(QCString openFilename, QCString saveFilename, QCString package, int newWindow );
+ virtual void openTemplate(QCString openFilename, QCString saveFilename, QCString package, int newWindow, QCString projectFile );
+ virtual void gotoFileEntry(QCString url, QCString msgid);
+ virtual void gotoFileEntry(QCString url, QCString package, int msgid);
+ virtual void gotoFileEntry(QCString url, QCString package, int msgid, QCString projectFile);
+ virtual bool findInFile(QCString fileSource, QCString url,
+ QString findStr, int caseSensitive, int wholeWords, int isRegExp,
+ int inMsgid, int inMsgstr, int inComment,
+ int ignoreAccelMarker, int ignoreContextInfo, int askForNextFile, int askForSave);
+ virtual bool replaceInFile(QCString fileSource, QCString url,
+ QString findStr, QString replaceStr, int caseSensitive, int wholeWords, int isRegExp,
+ int inMsgid, int inMsgstr, int inComment,
+ int ignoreAccelMarker, int ignoreContextInfo, int ask, int askForNextFile, int askForSave);
+ virtual bool findInFile(QCString fileSource, QCString url,
+ QString findStr, int caseSensitive, int wholeWords, int isRegExp,
+ int inMsgid, int inMsgstr, int inComment,
+ int ignoreAccelMarker, int ignoreContextInfo, int askForNextFile, int askForSave, QCString project );
+ virtual bool replaceInFile(QCString fileSource, QCString url,
+ QString findStr, QString replaceStr, int caseSensitive, int wholeWords, int isRegExp,
+ int inMsgid, int inMsgstr, int inComment,
+ int ignoreAccelMarker, int ignoreContextInfo, int ask, int askForNextFile, int askForSave, QCString project );
+ virtual void spellcheck(QStringList fileList);
+private:
+ KBabelMW* findInstance( const KURL& url, const QString& project, const QString& package) const;
+};
+
+
+class KBabelApp : public KUniqueApplication
+{
+public:
+ KBabelApp();
+ virtual ~KBabelApp();
+
+ virtual int newInstance();
+
+private:
+ KBabelInterface *kbInterface;
+};
+
+KBabelApp::KBabelApp()
+ : KUniqueApplication()
+{
+ kbInterface = new KBabelInterface;
+}
+
+KBabelApp::~KBabelApp()
+{
+ delete kbInterface;
+}
+
+int KBabelApp::newInstance()
+{
+ bool first=true;
+ if(KBabelMW::memberList && !KBabelMW::memberList->isEmpty())
+ {
+ first=false;
+ }
+
+ // see if we are starting with session management
+#if KDE_IS_VERSION(3,3,0)
+ if (!restoringSession())
+#else
+ if (!isRestored() || !first)
+#endif
+ {
+ kdDebug () << "Suspending DCOP" << endl;
+ kapp->dcopClient()->suspend();
+
+ KCmdLineArgs *args = KCmdLineArgs::parsedArgs();
+
+ QTimer timer;
+ QWidget *splash=0;
+ bool showSplash=args->isSet("splash");
+
+ if( showSplash && first )
+ {
+ setOverrideCursor(KCursor::waitCursor());
+ splash = new KBabelSplash();
+ splash->show();
+ timer.start(4000,true);
+ }
+
+ QString projectFile=args->getOption("project");
+ if( !projectFile.isEmpty() )
+ {
+ QFileInfo fi(projectFile);
+ projectFile = fi.absFilePath();
+ }
+ else
+ {
+ projectFile = KBabel::ProjectManager::defaultProjectName();
+ kdDebug(KBABEL) << "Using the default project Project: " << projectFile << endl;
+ }
+
+ kdDebug() << "Project: " << projectFile << endl;
+ QCString msgid=args->getOption("gotomsgid");
+ if(!msgid.isEmpty() && args->count() > 0)
+ {
+ kdDebug(KBABEL) << "gotomsgid" << endl;
+ QString m = QString::fromLocal8Bit(msgid);
+
+ kdDebug () << "Resuming DCOP" << endl;
+ kapp->dcopClient()->resume();
+ kbInterface->gotoFileEntry(args->url(0).url().local8Bit(),m.utf8());
+ }
+ else
+ {
+ // no session.. just start up normally
+ KBabelMW *widget=0;
+ if(args->count() > 0)
+ {
+ KURL u = args->url(0);
+ widget=KBabelMW::winForURL(u,projectFile);
+ }
+
+ if(!widget)
+ widget=KBabelMW::emptyWin(projectFile);
+
+ if(!widget)
+ widget=new KBabelMW(projectFile);
+
+ while(timer.isActive()) // let the user admire the splash screen ;-)
+ processEvents();
+
+ widget->show();
+ for (int i=0; i < args->count(); i++)
+ {
+ widget->open( args->url(i) , QString::null, i != 0 );
+ }
+
+ kdDebug () << "Resuming DCOP" << endl;
+ kapp->dcopClient()->resume();
+ }
+
+
+ args->clear();
+
+ if(splash)
+ {
+ delete KBabelSplash::instance;
+ }
+ if(showSplash)
+ {
+ KApplication::restoreOverrideCursor();
+ /*
+ KMessageBox::information(0,
+ "This is a development version of KBabel!\n"
+ "Please double check the files you edit "
+ "and save with this version for correctness.\n"
+ "Please report any bug you find to kiefer@kde.org.\n"
+ "Thanks.", "Warning");
+ */
+ }
+ }
+
+ return 0;
+}
+
+KBabelInterface::KBabelInterface()
+ : DCOPObject("KBabelIFace")
+{
+}
+
+void KBabelInterface::openURL(QCString url, QCString package, WId window, int newWindow)
+{
+ openURL(url,package,window,newWindow, KBabel::ProjectManager::defaultProjectName().local8Bit());
+}
+
+void KBabelInterface::openURL(QCString url, QCString package, WId window, int newWindow, QCString projectFile)
+{
+ const QString project( QString::fromLocal8Bit( projectFile ) );
+
+ kdDebug() << "openURL " << url << endl;
+
+ KURL u(QString::fromLocal8Bit(url));
+
+ kdDebug () << "Suspending DCOP" << endl;
+ kapp->dcopClient()->suspend();
+
+ KBabelMW *kb = KBabelMW::winForURL(u,project);
+ if(kb)
+ {
+ KWin::activateWindow(kb->topLevelWidget()->winId());
+ }
+ else
+ {
+ KMainWindow *mw = 0;
+ if(KMainWindow::memberList && !KMainWindow::memberList->isEmpty())
+ mw=KMainWindow::memberList->first();
+
+ // first, try to lookup correct winid
+ while( mw ) {
+ if( mw->inherits("KBabelMW") && mw->winId() == window)
+ {
+ kb = static_cast<KBabelMW*>(mw);
+ KWin::activateWindow(kb->topLevelWidget()->winId());
+ kb->open(u, QString::fromUtf8(package),newWindow);
+
+ kdDebug () << "Resuming DCOP" << endl;
+ kapp->dcopClient()->resume();
+
+ return ;
+ }
+ mw = KMainWindow::memberList->next();
+ }
+
+ // now, the empty window
+ kb = KBabelMW::emptyWin(projectFile);
+ if (kb)
+ {
+ // here, we don't care about "open in new window", because
+ // it's empty
+ KWin::setActiveWindow(kb->topLevelWidget()->winId());
+ kb->projectOpen(projectFile);
+ kb->open(u,QString::fromUtf8(package),false);
+
+ kdDebug () << "Resuming DCOP" << endl;
+ kapp->dcopClient()->resume();
+
+ return;
+ }
+
+ if(KMainWindow::memberList && !KMainWindow::memberList->isEmpty())
+ mw=KMainWindow::memberList->first();
+
+ while( mw ) {
+ if( mw->inherits("KBabelMW") && static_cast<KBabelMW*>(mw)->project()==project)
+ {
+ kb = static_cast<KBabelMW*>(mw);
+ KWin::activateWindow(kb->topLevelWidget()->winId());
+ kb->open(u, QString::fromUtf8(package),newWindow);
+
+ kdDebug () << "Resuming DCOP" << endl;
+ kapp->dcopClient()->resume();
+
+ return ;
+ }
+ mw = KMainWindow::memberList->next();
+ }
+
+ if( !mw )
+ {
+ kb = new KBabelMW(project);
+ kb->show();
+ } else kb = static_cast<KBabelMW*>(mw);
+ KWin::activateWindow(kb->topLevelWidget()->winId());
+ kb->open(u,QString::fromUtf8(package),newWindow);
+ }
+
+ kdDebug () << "Resuming DCOP" << endl;
+ kapp->dcopClient()->resume();
+}
+
+void KBabelInterface::openTemplate(QCString openFilename, QCString saveFilename, QCString package, int newWindow)
+{
+ openTemplate(openFilename, saveFilename, package, newWindow, KBabel::ProjectManager::defaultProjectName().local8Bit());
+}
+
+void KBabelInterface::openTemplate(QCString openFilename, QCString saveFilename, QCString package, int newWindow, QCString projectFile)
+{
+ const QString project( QString::fromLocal8Bit( projectFile ) );
+
+ const KURL u( QString::fromLocal8Bit( saveFilename ) );
+ const KURL t( QString::fromLocal8Bit( openFilename ) );
+
+ kdDebug () << "Suspending DCOP" << endl;
+ kapp->dcopClient()->suspend();
+
+ KBabelMW *kb = KBabelMW::winForURL(u, project);
+ if(kb)
+ {
+ KWin::activateWindow(kb->topLevelWidget()->winId());
+ }
+ else
+ {
+ KMainWindow *mw = 0;
+ if(KMainWindow::memberList && !KMainWindow::memberList->isEmpty())
+ mw=KMainWindow::memberList->first();
+
+ if(mw && mw->inherits("KBabelMW") && static_cast<KBabelMW*>(mw)->project()==project)
+ {
+ kb = static_cast<KBabelMW*>(mw);
+ KWin::activateWindow(kb->topLevelWidget()->winId());
+ kb->projectOpen(projectFile);
+ kb->openTemplate(t,u,QString::fromUtf8(package),newWindow);
+ }
+ else
+ {
+ kb = new KBabelMW(project);
+ kb->show();
+ KWin::activateWindow(kb->topLevelWidget()->winId());
+ kb->openTemplate(t,u,QString::fromUtf8(package));
+ }
+ }
+
+ kdDebug () << "Resuming DCOP" << endl;
+ kapp->dcopClient()->resume();
+}
+
+void KBabelInterface::gotoFileEntry(QCString url, QCString m)
+{
+ const KURL u( QString::fromLocal8Bit( url ) );
+ KBabelMW *kb = findInstance( u, KBabel::ProjectManager::defaultProjectName(), QString() );
+
+ if(!kb) return;
+
+ QString msgid = QString::fromUtf8(m);
+ int index = kb->m_view->catalog()->indexForMsgid(msgid);
+ if(index >= 0)
+ {
+ KBabel::DocPosition pos;
+ pos.item=index;
+ pos.form=0;
+ kb->m_view->gotoEntry(pos);
+ }
+}
+
+void KBabelInterface::gotoFileEntry(QCString url, QCString package, int m)
+{
+ gotoFileEntry(url, package, m, KBabel::ProjectManager::defaultProjectName().local8Bit() );
+}
+
+void KBabelInterface::gotoFileEntry(QCString url, QCString package, int m, QCString projectFile)
+{
+ const KURL u ( QString::fromLocal8Bit( url ) );
+ const QString p ( QString::fromUtf8( package ) ); // ### VERIFY encoding!
+ KBabelMW *kb = findInstance( u, projectFile, p );
+
+ if(!kb) return;
+
+ KBabel::DocPosition pos;
+ pos.item=m;
+ pos.form=0;
+ kb->m_view->gotoEntry(pos);
+}
+
+bool KBabelInterface::findInFile(QCString fileSource, QCString url,
+ QString findStr, int caseSensitive, int wholeWords, int isRegExp,
+ int inMsgid, int inMsgstr, int inComment,
+ int ignoreAccelMarker, int ignoreContextInfo, int askForNextFile, int askForSave)
+{
+ // no project given, open with default project
+ return findInFile ( fileSource, url, findStr, caseSensitive,
+ wholeWords, isRegExp, inMsgid, inMsgstr, inComment, ignoreAccelMarker, ignoreContextInfo,
+ askForNextFile, askForSave,
+ KBabel::ProjectManager::defaultProjectName().utf8() );
+}
+
+bool KBabelInterface::findInFile(QCString fileSource, QCString url,
+ QString findStr, int caseSensitive, int wholeWords, int isRegExp,
+ int inMsgid, int inMsgstr, int inComment,
+ int ignoreAccelMarker, int ignoreContextInfo, int askForNextFile, int askForSave, QCString project )
+{
+ kdDebug(KBABEL) << "findInFile (" <<fileSource<< "): " << url << " for " << findStr << endl;
+
+ const KURL u( QString::fromLocal8Bit( url ) );
+ KBabelMW *kb = findInstance( u, QString::fromLocal8Bit(project), QString() );
+
+ if(!kb) return false;
+
+ KBabel::FindOptions options;
+ options.findStr = findStr;
+ options.caseSensitive = (caseSensitive>0);
+ options.fromCursor = false;
+ options.backwards = false;
+ options.wholeWords = (wholeWords>0);
+ options.isRegExp = (isRegExp>0);
+ options.inMsgid = (inMsgid>0);
+ options.inMsgstr = (inMsgstr>0);
+ options.inComment = (inComment>0);
+ options.ignoreAccelMarker = (ignoreAccelMarker>0);
+ options.ignoreContextInfo = (ignoreContextInfo>0);
+ options.askForNextFile = (askForNextFile>0);
+ options.askForSave = (askForSave>0);
+ kb->m_view->findInFile(fileSource, options);
+
+ return true;
+}
+
+bool KBabelInterface::replaceInFile(QCString fileSource, QCString url,
+ QString findStr, QString replaceStr, int caseSensitive, int wholeWords, int isRegExp,
+ int inMsgid, int inMsgstr, int inComment,
+ int ignoreAccelMarker, int ignoreContextInfo, int ask, int askForNextFile, int askForSave)
+{
+ return replaceInFile( fileSource, url,
+ findStr, replaceStr, caseSensitive, wholeWords, isRegExp,
+ inMsgid, inMsgstr, inComment, ignoreAccelMarker, ignoreContextInfo,
+ ask, askForNextFile, askForSave,
+ KBabel::ProjectManager::defaultProjectName().utf8() );
+}
+
+bool KBabelInterface::replaceInFile(QCString fileSource, QCString url,
+ QString findStr, QString replaceStr, int caseSensitive, int wholeWords, int isRegExp,
+ int inMsgid, int inMsgstr, int inComment,
+ int ignoreAccelMarker, int ignoreContextInfo, int ask, int askForNextFile, int askForSave,
+ QCString project )
+{
+ kdDebug(KBABEL) << "replaceInFile (" <<fileSource<< "): " << url << " for " << findStr << endl;
+
+ const KURL u ( QString::fromLocal8Bit( url ) );
+ KBabelMW *kb = findInstance( u, QString::fromLocal8Bit(project), QString() );
+
+ if( !kb ) return false;
+
+ KBabel::ReplaceOptions options;
+ options.findStr = findStr;
+ options.replaceStr = replaceStr;
+ options.caseSensitive = (caseSensitive>0);
+ options.fromCursor = false;
+ options.backwards = false;
+ options.wholeWords = (wholeWords>0);
+ options.isRegExp = (isRegExp>0);
+ options.inMsgid = (inMsgid>0);
+ options.inMsgstr = (inMsgstr>0);
+ options.inComment = (inComment>0);
+ options.ignoreAccelMarker = (ignoreAccelMarker>0);
+ options.ignoreContextInfo = (ignoreContextInfo>0);
+ options.ask = (ask>0);
+ options.askForNextFile = (askForNextFile>0);
+ options.askForSave = (askForSave>0);
+ kb->m_view->replaceInFile(fileSource, options);
+
+ return true;
+}
+
+void KBabelInterface::spellcheck(QStringList fileList)
+{
+ // ### FIXME: the default project might use the wrong language!
+ KBabelMW *kb = findInstance( KURL(), KBabel::ProjectManager::defaultProjectName(), QString() );
+ kb->show();
+ kb->spellcheckMoreFiles( fileList );
+}
+
+KBabelMW* KBabelInterface::findInstance( const KURL& url, const QString& project, const QString& package) const
+{
+ kdDebug () << "Suspending DCOP" << endl;
+ kapp->dcopClient()->suspend();
+
+ KBabelMW *kb = 0;
+ if( !url.isEmpty() )
+ {
+ kb = KBabelMW::winForURL( url, project );
+
+ if(kb)
+ {
+ KWin::activateWindow(kb->topLevelWidget()->winId());
+ }
+ }
+
+ if( !kb )
+ {
+ kb = KBabelMW::emptyWin(project);
+ if( !kb )
+ {
+ kb = new KBabelMW(project);
+ }
+ else
+ {
+ kb->projectOpen(project);
+ }
+
+ kb->show();
+ if ( !url.isEmpty() )
+ kb->open( url, package, false );
+ }
+
+ kdDebug () << "Resuming DCOP" << endl;
+ kapp->dcopClient()->resume();
+
+ return kb;
+}
+
+static KCmdLineOptions options[] =
+{
+ {"gotomsgid <msgid>",I18N_NOOP("Go to entry with msgid <msgid>"),0},
+ {"nosplash",I18N_NOOP("Disable splashscreen at startup"),0},
+ {"project <configfile>",I18N_NOOP("File to load configuration from"),0},
+ {"+[file]",I18N_NOOP("Files to open"),0},
+ KCmdLineLastOption
+};
+
+
+int main(int argc, char **argv)
+{
+ KAboutData about("kbabel",I18N_NOOP("KBabel"),VERSION,
+ I18N_NOOP("An advanced PO file editor"),KAboutData::License_GPL,
+ I18N_NOOP("(c) 1999,2000,2001,2002,2003,2004,2005,2006 The KBabel developers"),0,"http://kbabel.kde.org");
+
+ about.addAuthor("Matthias Kiefer",I18N_NOOP("Original author"),"kiefer@kde.org");
+ about.addAuthor("Wolfram Diestel"
+ ,I18N_NOOP("Wrote diff algorithm, fixed KSpell and gave a lot "
+ "of useful hints."),"wolfram@steloj.de");
+ about.addAuthor("Andrea Rizzi",I18N_NOOP("Wrote the dictionary plugin "
+ "for searching in a database and some other code.")
+ ,"rizzi@kde.org");
+ about.addAuthor("Stanislav Visnovsky",I18N_NOOP("Current maintainer, porting to KDE3/Qt3.")
+ ,"visnovsky@kde.org");
+ about.addAuthor("Marco Wegner",I18N_NOOP("Bug fixes, KFilePlugin for PO files, CVS support, mailing files")
+ ,"dubbleu@web.de");
+ about.addAuthor("Asgeir Frimannsson",I18N_NOOP("Translation List View")
+ ,"asgeirf@redhat.com");
+ about.addAuthor("Nicolas Goutte", I18N_NOOP("Current maintainer"), "goutte@kde.org");
+
+ about.addCredit("Claudiu Costin",I18N_NOOP("Wrote documentation and sent "
+ "many bug reports and suggestions for improvements.")
+ ,"claudiuc@geocities.com");
+ about.addCredit("Thomas Diehl",I18N_NOOP("Gave many suggestions for the GUI "
+ "and the behavior of KBabel. He also contributed the beautiful splash screen.")
+ ,"thd@kde.org");
+ about.addCredit("Stephan Kulow",I18N_NOOP("Helped keep KBabel up to date "
+ "with the KDE API and gave a lot of other help."),"coolo@kde.org");
+ about.addCredit("Stefan Asserhall",I18N_NOOP("Implemented XML validation/highlighting "
+ "plus other small fixes.") ,"stefan.asserhall@telia.com");
+ about.addCredit("Dwayne Bailey",I18N_NOOP("Various validation plugins.")
+ ,"dwayne@translate.org.za");
+ about.addCredit("SuSE GmbH"
+ ,I18N_NOOP("Sponsored development of KBabel for a while.")
+ ,"suse@suse.de","http://www.suse.de");
+ about.addCredit("Trolltech", I18N_NOOP("KBabel contains code from Qt"), 0, "http://www.trolltech.com");
+
+ about.addCredit("Eva Brucherseifer", I18N_NOOP("String distance algorithm implementation"), "eva@kde.org");
+
+ about.addCredit("Albert Cervera Areny", I18N_NOOP("Error list for current entry, regexp data tool"), "albertca@hotpop.com");
+
+ about.addCredit("Nick Shaforostoff", I18N_NOOP("Word-by-word string difference algorithm implementation"), "shafff@ukr.net");
+
+ // Initialize command line args
+ KCmdLineArgs::init(argc, argv, &about);
+
+ // Tell which options are supported
+ KCmdLineArgs::addCmdLineOptions( options );
+
+ // Add options from other components
+ KUniqueApplication::addCmdLineOptions();
+
+
+ if(!KUniqueApplication::start())
+ {
+ return 0;
+ }
+
+ KBabelApp app;
+
+ if( app.isRestored() )
+ {
+ RESTORE(KBabelMW)
+ }
+
+ return app.exec();
+}
diff --git a/kbabel/kbabel/mymultilineedit.cpp b/kbabel/kbabel/mymultilineedit.cpp
new file mode 100644
index 00000000..820d493e
--- /dev/null
+++ b/kbabel/kbabel/mymultilineedit.cpp
@@ -0,0 +1,1668 @@
+/* ****************************************************************************
+ This file is part of KBabel
+
+ Copyright (C) 1999-2000 by Matthias Kiefer
+ <matthias.kiefer@gmx.de>
+ 2001-2004 by Stanislav Visnovsky
+ <visnovsky@kde.org>
+
+ Alt+123 feature idea taken from KOffice by David Faure <david@mandrakesoft.com>.
+ Word wrap support by Jarno Elonen <elonen@iki.fi>, 2003
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the 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, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+ In addition, as a special exception, the copyright holders give
+ permission to link the code of this program with any edition of
+ the Qt library by Trolltech AS, Norway (or with modified versions
+ of Qt that use the same license as Qt), and distribute linked
+ combinations including the two. You must obey the GNU General
+ Public License in all respects for all of the code used other than
+ Qt. If you modify this file, you may extend this exception to
+ your version of the file, but you are not obligated to do so. If
+ you do not wish to do so, delete this exception statement from
+ your version.
+
+**************************************************************************** */
+
+
+#include "mymultilineedit.h"
+#include "editcmd.h"
+#include "resources.h"
+
+#include <qpixmap.h>
+#include <qpainter.h>
+#include <qvaluelist.h>
+#include <qstringlist.h>
+#include <qregexp.h>
+#include <qclipboard.h>
+#include <qapplication.h>
+#include <qdragobject.h>
+//#include <private/qrichtext_p.h>
+#include <qpopupmenu.h>
+
+#include <kdebug.h>
+#include <kglobal.h>
+#include <kglobalsettings.h>
+#include <kmessagebox.h>
+#include <kstdaccel.h>
+
+#include "kbhighlighting.h"
+
+using namespace KBabel;
+
+MyMultiLineEdit::MyMultiLineEdit(int ID, QWidget* parent,const char* name)
+ :KTextEdit(parent,name), emitUndo(true),
+ _firstChangedLine(0),
+ _lastChangedLine(0),
+ _lastParagraph(0),
+ _lastParagraphOffset(0),
+ _lastSelectionStart(-1),
+ _lastSelectionEnd(-1),
+ _dontUpdate(false), _myID (ID),
+ _menu(0), _overwrite(false)
+{
+ setUndoRedoEnabled(false); // we handle this ourselves
+ setWordWrap( WidgetWidth );
+ viewport()->setAcceptDrops( false ); // we need our parent to get drops
+
+ connect(this, SIGNAL(selectionChanged()), this, SLOT( onSelectionChanged() ) );
+}
+
+void MyMultiLineEdit::onSelectionChanged()
+{
+ kdDebug(KBABEL) << "MyMultiLineEdit::onSelectionChanged" << endl;
+ int parFrom, parTo, indexFrom, indexTo;
+ if ( hasSelectedText() ) {
+ getSelection( &parFrom, &indexFrom, &parTo, &indexTo );
+ kdDebug(KBABEL) << "parFrom=" << parFrom << "indexFrom=" << indexFrom << "parTo=" << parTo << "indexTo=" << indexTo << endl;
+ _lastSelectionStart = beginOfMarkedText();
+ }
+ else
+ {
+ _lastSelectionStart = -1; // no selection
+ _lastSelectionEnd = -1;
+ }
+
+ //kdDebug(KBABEL) << "_lastSelectionStart=" << _lastSelectionStart << endl;
+}
+
+void MyMultiLineEdit::processCommand(EditCommand* cmd, bool undo)
+{
+ if(cmd->terminator()!=0)
+ return;
+
+ DelTextCmd* delcmd = (DelTextCmd*) cmd;
+ bool ins = true;
+ if (delcmd->type() == EditCommand::Delete )
+ ins = undo;
+ else if (delcmd->type() == EditCommand::Insert )
+ ins = !undo;
+ else
+ {
+ return;
+ }
+
+ // avoid duplicate update of catalog
+ bool oldEmitUndo = emitUndo;
+ emitUndo = false;
+
+ QPalette _visibleHighlight( palette() );
+ QPalette _invisibleHighlight( palette() );
+ QColorGroup newcg( colorGroup() );
+ newcg.setColor( QColorGroup::HighlightedText, newcg.text() );
+ newcg.setColor( QColorGroup::Highlight, newcg.base() );
+ if( hasFocus() ) _invisibleHighlight.setActive( newcg );
+ else _invisibleHighlight.setInactive( newcg );
+ setPalette( _invisibleHighlight );
+
+ if(delcmd->offset <= (int)_lastParagraphOffset)
+ {
+ _lastParagraph=0;
+ _lastParagraphOffset=0;
+ }
+
+ if ( ins )
+ {
+ int row, col;
+
+ offset2Pos( delcmd->offset, row, col );
+ setCursorPosition( row, col );
+
+ _firstChangedLine=row;
+ if(delcmd->str.find("\n")>0 )_lastChangedLine=row+delcmd->str.contains("\n");
+ else _lastChangedLine=row;
+
+ KTextEdit::insert( delcmd->str );
+
+ offset2Pos( delcmd->offset+delcmd->str.length(), row, col );
+ setCursorPosition( row, col);
+ }
+ else
+ { // del
+
+ int row, col, rowEnd, colEnd;
+
+ offset2Pos( delcmd->offset, row, col );
+ offset2Pos( delcmd->offset + delcmd->str.length(), rowEnd, colEnd );
+
+ setSelection( row, col, rowEnd, colEnd, 0 );
+ _firstChangedLine=_lastChangedLine=row;
+ KTextEdit::removeSelectedText();
+ }
+
+
+ setPalette( _visibleHighlight );
+
+ emitUndo = oldEmitUndo;
+
+ emitCursorPosition();
+}
+
+int MyMultiLineEdit::beginOfLastMarkedText()
+{
+ if ( _lastSelectionStart != -1 )
+ return _lastSelectionStart;
+ else
+ return currentIndex();
+}
+
+int MyMultiLineEdit::endOfLastMarkedText()
+{
+ if ( _lastSelectionEnd != -1 )
+ return _lastSelectionEnd;
+ else
+ return currentIndex();
+}
+
+int MyMultiLineEdit::beginOfMarkedText()
+{
+ int beginX=0;
+ int beginY=0;
+ int endX=0;
+ int endY=0;
+
+ int pos=-1;
+
+ getSelection(&beginY,&beginX,&endY,&endX);
+ if( hasSelectedText() )
+ {
+ pos = pos2Offset(beginY,beginX);
+ }
+
+ return pos;
+}
+
+void MyMultiLineEdit::emitCursorPosition()
+{
+ int line=0;
+ int col=0;
+ getCursorPosition(&line,&col);
+
+ emit cursorPositionChanged(line, col);
+}
+
+void MyMultiLineEdit::wheelEvent(QWheelEvent *e)
+{
+ e->ignore();
+}
+
+void MyMultiLineEdit::focusInEvent(QFocusEvent *e)
+{
+ KTextEdit::focusInEvent(e);
+ emitCursorPosition();
+}
+
+void MyMultiLineEdit::contentsContextMenuEvent( QContextMenuEvent * e)
+{
+ e->accept();
+ if( _menu ) _menu->exec( e->globalPos() );
+}
+
+QPopupMenu * MyMultiLineEdit::createPopupMenu()
+{
+ return _menu;
+}
+
+QPopupMenu * MyMultiLineEdit::createPopupMenu(const QPoint &)
+{
+ return 0;
+}
+
+void MyMultiLineEdit::setContextMenu( QPopupMenu * menu )
+{
+ _menu = menu;
+}
+
+void MyMultiLineEdit::doKeyboardAction( KeyboardAction action )
+{
+ int row,col;
+ getCursorPosition(&row, &col);
+
+ switch( action ) {
+ case ActionDelete:
+ _firstChangedLine=_lastChangedLine=row;
+ my_del(); break;
+
+ case ActionBackspace:
+ _firstChangedLine=_lastChangedLine=row;
+ my_backspace(); break;
+
+ case ActionReturn:
+ if( emitUndo)
+ emit signalUndoCmd( new InsTextCmd(currentIndex(), "\n", _myID) );
+ break;
+
+ case ActionKill:
+ _firstChangedLine=_lastChangedLine=row;
+ if(emitUndo)
+ {
+ int x,y;
+ getCursorPosition( &x, &y );
+ QString s = text(x);
+ if( y < (int)s.length()-1 ) // not the end of paragraph
+ {
+ QString delText = s.mid( y, s.length()-y-1);
+ emit signalUndoCmd( new DelTextCmd(currentIndex(), delText, _myID ) );
+ } else
+ if( x < paragraphs()-1 ) // not the end of text
+ emit signalUndoCmd( new DelTextCmd(currentIndex(), "\n", _myID ) );
+ }
+ break;
+ default: break;
+ }
+
+ KTextEdit::doKeyboardAction( action );
+
+ emitCursorPosition();
+}
+
+void MyMultiLineEdit::setText(const QString& s)
+{
+ _lastParagraph=0;
+ _lastParagraphOffset=0;
+ // workaround, since insert does not interpret markup
+ setTextFormat( Qt::PlainText );
+ _firstChangedLine=_lastChangedLine=0;
+ KTextEdit::setText(s);
+ setTextFormat( Qt::AutoText );
+ // now the number of lines is known, let's do highlight
+ _lastChangedLine=paragraphs();
+ emit textChanged();
+ emitCursorPosition();
+}
+
+void MyMultiLineEdit::insertAt( const QString & s, int line, int col, bool mark )
+{
+ // it will invoke insert, don't need to send InsTextCmd
+ KTextEdit::insertAt(s,line,col);
+
+ // code from QMultiLineEdit
+ if( mark )
+ setSelection( line, col, line, col + s.length(), 0 );
+ // end of copied code
+
+ emitCursorPosition();
+}
+
+void MyMultiLineEdit::insert( const QString & text, bool indent, bool checkNewLine, bool removeSelected )
+{
+ int row,col;
+
+ bool noSelectionRemoved = true;
+ setUpdatesEnabled(false);
+ if( removeSelected && hasSelectedText() )
+ {
+ int endRow,endCol;
+ getSelection(&row,&col,&endRow,&endCol);
+
+ if( row < (int)_lastParagraph )
+ {
+ _lastParagraph=0;
+ _lastParagraphOffset=0;
+ }
+
+ _firstChangedLine=_lastChangedLine=row;
+ removeSelectedText();
+ noSelectionRemoved = false;
+ }
+
+ getCursorPosition(&row,&col);
+ _firstChangedLine=row;
+ _lastChangedLine=row;
+
+ if( emitUndo)
+ {
+ emit signalUndoCmd( new BeginCommand(-1,UndefPart));
+ // reimplemented overwrite
+ if( _overwrite && noSelectionRemoved)
+ {
+ doKeyboardAction( ActionDelete );
+ }
+
+ emit signalUndoCmd( new InsTextCmd(currentIndex(), text, _myID) );
+ emit signalUndoCmd( new EndCommand(-1,UndefPart));
+ }
+
+ int n=text.find("\n");
+ if( n > 0 ) _lastChangedLine+=n;
+
+ // setup palettes
+
+ QPalette _visibleHighlight( palette() );
+ QPalette _invisibleHighlight( palette() );
+ QColorGroup newcg( colorGroup() );
+ newcg.setColor( QColorGroup::HighlightedText, newcg.text() );
+ newcg.setColor( QColorGroup::Highlight, newcg.base() );
+ if( hasFocus() ) _invisibleHighlight.setActive( newcg );
+ else _invisibleHighlight.setInactive( newcg );
+ setPalette( _invisibleHighlight );
+ KTextEdit::insert(text, indent, checkNewLine, removeSelected);
+ setPalette( _visibleHighlight );
+
+ setUpdatesEnabled(true);
+
+ emitCursorPosition();
+}
+
+void MyMultiLineEdit::removeLine ( int line )
+{
+ kdDebug(KBABEL) << "removeLine invoked" << endl;
+
+ KTextEdit::removeParagraph(line);
+ emitCursorPosition();
+}
+
+void MyMultiLineEdit::clear()
+{
+ _lastParagraph=0;
+ _lastParagraphOffset=0;
+
+ _dontUpdate=true;
+
+ QString s = text();
+ if( !s.isEmpty() && emitUndo ) {
+ emit signalUndoCmd( new BeginCommand(-1,UndefPart) );
+ emit signalUndoCmd( new DelTextCmd(0,s,_myID) );
+ emit signalUndoCmd( new EndCommand(-1,UndefPart) );
+ }
+
+ KTextEdit::clear();
+
+ _dontUpdate=false;
+
+ _firstChangedLine=_lastChangedLine=0;
+ emitCursorPosition();
+}
+
+
+void MyMultiLineEdit::my_backspace()
+{
+
+ int cursorY, cursorX;
+ getCursorPosition( &cursorY, &cursorX );
+
+ if( hasSelectedText())
+ {
+ Q_ASSERT( "backspace: This should never happen, why is not invoked removeSelectedText()?");
+ }
+ else if(! (cursorY==0 && cursorX==0) )
+ {
+ if(emitUndo)
+ {
+ int offset = currentIndex();
+
+ QString s= text(cursorY);
+ if(cursorX != 0)
+ {
+ QString delTxt(s[cursorX-1]);
+ emit signalUndoCmd(new DelTextCmd(offset-1,delTxt,_myID));
+ }
+ else if( cursorY > 0 || cursorX > 0 ) // not at the beginning
+ {
+ emit signalUndoCmd(new DelTextCmd(offset-1,"\n",_myID));
+ }
+ }
+ }
+}
+
+void MyMultiLineEdit::my_del()
+{
+
+ int cursorY, cursorX;
+ getCursorPosition( &cursorY, &cursorX );
+
+ if( hasSelectedText())
+ {
+ Q_ASSERT( "del: This should never happen, why is not invoked removeSelectedText()?");
+ }
+ else if(! (cursorY==paragraphs()-1 && cursorX==paragraphLength( cursorY )) )
+ {
+ if(emitUndo)
+ {
+ int offset = pos2Offset(cursorY, cursorX);
+
+ QString s=text(cursorY);
+ if(cursorX != (int)s.length()-1)
+ {
+ QString delTxt(s[cursorX]);
+ emit signalUndoCmd(new DelTextCmd(offset,delTxt,_myID));
+ }
+ else if( cursorY < (int)paragraphs()-1 || ( (cursorY == (int)paragraphs()-1) && (cursorX < (int)text( paragraphs()-1 ).length()-1 ) ) )// !atEnd() )
+ {
+ emit signalUndoCmd(new DelTextCmd(offset,"\n",_myID));
+ }
+ }
+ }
+}
+
+void MyMultiLineEdit::removeSelectedText(int selNum)
+{
+ if( selNum != 0 )
+ {
+ _lastParagraph=0;
+ _lastParagraphOffset=0;
+
+ KTextEdit::removeSelectedText(selNum);
+ }
+ else
+ {
+ int paraFrom, idxFrom, paraTo, idxTo;
+ KTextEdit::getSelection( &paraFrom, &idxFrom, &paraTo, &idxTo );
+
+ if( paraFrom < (int)_lastParagraph )
+ {
+ _lastParagraph=0;
+ _lastParagraphOffset=0;
+ }
+
+ int offset = pos2Offset( paraFrom, idxFrom );
+ emit signalUndoCmd(new DelTextCmd( offset, selectedText(), _myID ) );
+ KTextEdit::removeSelectedText(selNum);
+ }
+
+ emitCursorPosition();
+}
+
+void MyMultiLineEdit::paste()
+{
+ KTextEdit::paste();
+ emitCursorPosition();
+}
+
+int MyMultiLineEdit::currentIndex()
+{
+ int para; // paragraph of current position
+ int index; // index in the current paragraph
+
+ KTextEdit::getCursorPosition(&para,&index);
+
+ return pos2Offset( para, index );
+}
+
+
+void MyMultiLineEdit::offset2Pos(int offset, int &paragraph, int &index) const
+{
+ if (offset <= 0)
+ {
+ paragraph = 0;
+ index = 0;
+ return;
+ }
+ else
+ {
+ int charsLeft = offset;
+ int i;
+
+ for( i = 0; i < paragraphs(); ++i )
+ {
+ if (paragraphLength( i ) < charsLeft)
+ charsLeft -= paragraphLength( i );
+ else
+ {
+ paragraph = i;
+ index = charsLeft;
+ return;
+ }
+ --charsLeft;
+ }
+
+ paragraph = i-1;
+ index = charsLeft;
+ return;
+ }
+}
+
+int MyMultiLineEdit::pos2Offset(uint paragraph, uint index)
+{
+ paragraph = QMAX( QMIN( (int)paragraph, paragraphs() - 1), 0 ); // Sanity check
+ index = QMAX( QMIN( (int)index, paragraphLength( paragraph )), 0 ); // Sanity check
+
+ {
+ uint lastI;
+ lastI = paragraphLength( paragraph );
+ uint i = 0;
+ uint tmp = 0;
+
+ if( paragraph>=_lastParagraph )
+ {
+ tmp = _lastParagraphOffset;
+ i = _lastParagraph;
+ }
+
+ for( ;i < paragraph ; i++ )
+ {
+ tmp += paragraphLength( i ) + 1;
+ }
+
+ _lastParagraphOffset=tmp;
+ _lastParagraph=paragraph;
+
+ tmp += QMIN( lastI, index );
+
+ return tmp;
+ }
+}
+
+void MyMultiLineEdit::setReadOnly(bool on)
+{
+ // I want this backgroundmode, also when readonly==true
+ if(on)
+ {
+ setBackgroundMode(PaletteBase);
+ }
+
+ QTextEdit::setReadOnly(on);
+}
+
+void MyMultiLineEdit::setOverwriteMode( bool b )
+{
+ _overwrite = b;
+}
+
+/*******************************************************************************/
+MsgMultiLineEdit::MsgMultiLineEdit(int ID, KSpell* spell, QWidget* parent,const char* name)
+ :MyMultiLineEdit(ID, parent,name),
+ _quotes(false),
+ _cleverEditing(false),
+ _highlightBg(false),
+ _spacePoints(false),
+ _bgColor(colorGroup().base().dark(110)),
+ _textColor(KGlobalSettings::textColor()),
+ _errorColor(Qt::red),
+ _currentColor(KGlobalSettings::textColor()),
+ _whitespace(0),
+ _hlSyntax(true),
+ _quoteColor(Qt::darkGreen),
+ _unquoteColor(Qt::red),
+ _cformatColor(Qt::blue),
+ _accelColor(Qt::darkMagenta),
+ _showDiff(false),
+ _diffUnderlineAdd(true),
+ _diffStrikeOutDel(true),
+ _diffAddColor(Qt::darkGreen),
+ _diffDelColor(Qt::darkRed),
+ _currentUnicodeNumber(0),
+ highlighter(0),
+ _tagStartPara(0), _tagStartIndex(0), _tagEndPara(0), _tagEndIndex(0)
+{
+ diffPos.setAutoDelete(true);
+ diffPos.clear();
+
+ _whitespace = new QPixmap(2,2,-1,QPixmap::BestOptim);
+ _whitespace->fill(_textColor);
+ _errorWhitespace = new QPixmap(2,2,-1,QPixmap::BestOptim);
+ _errorWhitespace->fill(_errorColor);
+
+ _whitespaceNB = new QPixmap(3,3,-1,QPixmap::BestOptim);
+ _whitespaceNB->fill();
+ _errorWhitespaceNB = new QPixmap(3,3,-1,QPixmap::BestOptim);
+ _errorWhitespaceNB->fill();
+
+ QPainter p(_whitespaceNB);
+ p.setPen( _textColor );
+ p.drawEllipse(_whitespaceNB->rect());
+
+ QPainter q(_errorWhitespaceNB);
+ q.setPen( _errorColor );
+ q.drawEllipse(_errorWhitespaceNB->rect());
+
+ // this will setup bitBlt pixmaps
+ setFont( font() );
+ highlighter = new KBabelHighlighter( this, spell );
+ connect( this, SIGNAL( signalSyntaxHighlightingChanged( bool ) ), highlighter, SLOT( setSyntaxHighlighting( bool ) ) );
+
+ connect( this, SIGNAL( selectionChanged() ), this, SLOT( paintSpacePoints() ) );
+ connect( this, SIGNAL( cursorPositionChanged( int, int ) ), this, SLOT( paintSpacePoints(int, int) ) );
+ connect( this, SIGNAL( textChanged() ), this, SLOT( emittedTextChanged() ) );
+}
+
+MsgMultiLineEdit::~MsgMultiLineEdit ()
+{
+ if(highlighter)
+ delete highlighter;
+}
+
+void MsgMultiLineEdit::setText(const QString& s)
+{
+ QString str = s;
+
+ if(_showDiff)
+ {
+ diffPos.clear();
+ int lines = s.contains('\n');
+ diffPos.resize(lines+1);
+
+ QStringList lineList = QStringList::split('\n',s,true);
+
+ int lineCounter=-1;
+ bool haveAdd=false;
+ bool haveDel=false;
+ bool multiline=false;
+ QStringList::Iterator it;
+ for(it = lineList.begin(); it != lineList.end(); ++it)
+ {
+ lineCounter++;
+
+ int lastPos=0;
+ bool atEnd=false;
+
+ while(!atEnd)
+ {
+ int addPos=-1;
+ int delPos=-1;
+
+ if(haveAdd && multiline)
+ {
+ addPos=0;
+ }
+ else
+ {
+ addPos = (*it).find("<KBABELADD>",lastPos);
+ }
+
+ if(haveDel && multiline)
+ {
+ delPos=0;
+ }
+ else
+ {
+ delPos = (*it).find("<KBABELDEL>",lastPos);
+ }
+
+ if(delPos >= 0 && addPos >= 0)
+ {
+ if(delPos <= addPos)
+ {
+ haveDel=true;
+ haveAdd=false;
+ }
+ else
+ {
+ haveDel=false;
+ haveAdd=true;
+ }
+ }
+ else if(delPos >= 0)
+ {
+ haveDel=true;
+ haveAdd=false;
+ }
+ else if(addPos >= 0)
+ {
+ haveDel=false;
+ haveAdd=true;
+ }
+ else
+ {
+ atEnd=true;
+ haveAdd=false;
+ haveDel=false;
+ }
+
+ DiffInfo di;
+ di.begin=-1;
+
+ if(haveAdd)
+ {
+ if(!multiline)
+ {
+ (*it).remove(addPos,11);
+ }
+
+ int endPos = (*it).find("</KBABELADD>",addPos);
+ if(endPos < 0)
+ {
+ endPos = (*it).length();
+ atEnd=true;
+ multiline=true;
+ }
+ else
+ {
+ (*it).remove(endPos,12);
+ haveAdd=false;
+ multiline=false;
+ }
+
+ lastPos=endPos;
+
+ di.begin=addPos;
+ di.end=endPos-1;
+ di.add=true;
+ }
+ else if(haveDel)
+ {
+ if(!multiline)
+ {
+ (*it).remove(delPos,11);
+ }
+
+ int endPos = (*it).find("</KBABELDEL>",delPos);
+ if(endPos < 0)
+ {
+ endPos = (*it).length();
+ atEnd=true;
+ multiline=true;
+ }
+ else
+ {
+ (*it).remove(endPos,12);
+ haveDel=false;
+ multiline=false;
+ }
+
+ lastPos=endPos;
+
+ di.begin=delPos;
+ di.end=endPos-1;
+ di.add=false;
+ }
+
+ if(di.begin >= 0)
+ {
+ QValueList<DiffInfo> *list = diffPos[lineCounter];
+ if(!list)
+ {
+ list = new QValueList<DiffInfo>;
+ diffPos.insert(lineCounter,list);
+ }
+
+ list->append(di);
+ }
+
+ }
+ }
+
+ QRegExp reg("</?KBABELADD>");
+ str.replace(reg,"");
+ reg.setPattern("</?KBABELDEL>");
+ str.replace(reg,"");
+ }
+
+ MyMultiLineEdit::setText(str);
+ paintSpacePoints();
+}
+
+void MsgMultiLineEdit::setQuotes(bool on)
+{
+ _quotes=on;
+ update();
+}
+
+void MsgMultiLineEdit::setCleverEditing(bool on)
+{
+ _cleverEditing=on;
+}
+
+
+void MsgMultiLineEdit::setHighlightBg(bool on)
+{
+ _highlightBg=on;
+ update();
+}
+
+
+void MsgMultiLineEdit::setBgColor(const QColor& color)
+{
+ _bgColor=color;
+
+ if(_highlightBg)
+ update();
+}
+
+void MsgMultiLineEdit::setSpacePoints(bool on)
+{
+ _spacePoints=on;
+
+ update();
+}
+
+void MsgMultiLineEdit::setHighlightSyntax(bool on)
+{
+ _hlSyntax=on;
+
+ emit signalSyntaxHighlightingChanged (on);
+
+ update();
+}
+
+void MsgMultiLineEdit::setHighlightColors(const QColor& quoteColor, const QColor& unquoteColor
+ , const QColor& cformatColor, const QColor& accelColor, const QColor& tagColor)
+{
+ _quoteColor=quoteColor;
+ _unquoteColor=unquoteColor;
+ _cformatColor=cformatColor;
+ _accelColor=accelColor;
+ _tagColor=tagColor;
+
+ highlighter->setHighlightColor( KBabelHighlighter::Tag, tagColor );
+ highlighter->setHighlightColor( KBabelHighlighter::Entity, accelColor );
+ highlighter->setHighlightColor( KBabelHighlighter::CFormat, cformatColor );
+ highlighter->setHighlightColor( KBabelHighlighter::Masked, quoteColor );
+
+ update();
+}
+
+
+void MsgMultiLineEdit::setFont(const QFont& font)
+{
+ KTextEdit::setFont(font);
+
+ // we don't need to calculate a special offset for non-breaking space, since
+ // they are very similar in size
+ QFontMetrics fm(font);
+ _wsOffsetX = QMAX(fm.width(' ')/2-2,1);
+ _wsOffsetY = QMAX(fm.height()/2-1,0);
+
+ repaint();
+}
+
+void MsgMultiLineEdit::setDiffDisplayMode(bool addUnderline, bool delStrikeOut)
+{
+ _diffUnderlineAdd = addUnderline;
+ _diffStrikeOutDel = delStrikeOut;
+
+ if(_showDiff)
+ update();
+}
+
+void MsgMultiLineEdit::setDiffColors(const QColor& addColor
+ , const QColor& delColor)
+{
+ _diffAddColor = addColor;
+ _diffDelColor = delColor;
+
+ if(_showDiff)
+ update();
+}
+
+void MsgMultiLineEdit::setTextColor(const QColor &color )
+{
+ QPalette p( palette() );
+ QColorGroup newcg( colorGroup() );
+ newcg.setColor( QColorGroup::Text, color );
+ if( hasFocus() ) p.setActive( newcg );
+ else p.setInactive( newcg );
+ setPalette( p );
+ _textColor = color;
+ highlighter->setHighlightColor( KBabelHighlighter::Normal, color );
+}
+
+void MsgMultiLineEdit::setErrorColor(const QColor &color )
+{
+ _errorColor = color;
+ highlighter->setHighlightColor( KBabelHighlighter::Error, color );
+}
+
+void MsgMultiLineEdit::setCurrentColor(const TextColor color)
+{
+ if( color == NormalColor ) {
+ _currentColor = _textColor;
+ highlighter->setHasErrors( false );
+ } else {
+ _currentColor = _errorColor;
+ highlighter->setHasErrors( true );
+ }
+
+ /*
+ setUpdatesEnabled(false);
+ // need to block signals (especially textChanged() to avoid recursion with KBabelView::autoCheck
+ blockSignals(true);
+ selectAll();
+ setColor( _currentColor );
+ removeSelection();
+ setColor(_currentColor);
+ blockSignals(false);
+ setUpdatesEnabled(true);
+ */
+ forceUpdate();
+}
+
+void MsgMultiLineEdit::setSpellChecker(KSpell* spell)
+{
+ highlighter->setSpellChecker(spell);
+}
+
+void MsgMultiLineEdit::paintSpacePoints(int, int )
+{
+ paintSpacePoints();
+}
+
+void MsgMultiLineEdit::paintSpacePoints()
+{
+ QRect r;
+ QPainter painter(viewport() );
+ const QFontMetrics& fm = fontMetrics();
+
+ int paranum = paragraphAt(QPoint(contentsX(), contentsY()));
+
+ if( _spacePoints )
+ {
+ int curpara = paranum;
+ painter.setPen( _currentColor );
+ QPixmap* ws, *wsnb;
+
+ if( _currentColor== _errorColor )
+ {
+ ws = _errorWhitespace;
+ wsnb = _errorWhitespaceNB;
+ }
+ else
+ {
+ ws = _whitespace;
+ wsnb = _whitespaceNB;
+ }
+
+ while( curpara < paragraphs())
+ {
+ if ( paragraphRect( curpara ).top() > contentsY()+visibleHeight()) break;
+
+ const QString& s = text(curpara);
+ int i = s.find( " " );
+ while( (i >= 0) && (i < (int)s.length()-1) ) // -1 because text will end by EOLN
+ {
+ QPixmap* pm = ( s.at(i).unicode() == 0x00A0U ) ? wsnb : ws;
+ QRect r = mapToView( curpara, i );
+ r.moveBy( r.width()/2, (r.height() - fm.descent())/2 );
+ r.moveBy( -pm->rect().width()/2, -pm->rect().height()/2-1 );
+ bitBlt(viewport(), r.topLeft(), pm, pm->rect(), Qt::CopyROP);
+ i = s.find( " ", i+1 );
+ }
+ ++curpara;
+ }
+ }
+
+ if( _quotes )
+ {
+ QFontMetrics fm( font());
+ QRect qs = fm.boundingRect("\"");
+
+ for( int curpara = paranum; curpara < paragraphs() ; curpara++ )
+ {
+ r = paragraphRect(curpara);
+ if( r.y() > contentsY()+visibleHeight() ) break;
+
+ painter.drawText( QPoint( 0, mapToView( curpara, 0 ).top()) +
+ QPoint(0, qs.height() + 4), "\""); // 4 = hardcoded margin in QT
+ painter.drawText( mapToView( curpara, QMAX( 0,
+ ((int)text( curpara ).length())-1)).topRight() +
+ QPoint(0, qs.height() + 4), "\""); // 4 = hardcoded margin in QT
+ }
+ }
+
+ if( _showDiff && (!_diffUnderlineAdd || !_diffStrikeOutDel) )
+ {
+ if( paragraphs() == (int)diffPos.size() ) // sanity check
+ {
+ painter.setRasterOp( Qt::AndROP );
+ for( int curpara = paranum; curpara < paragraphs() ; curpara++ )
+ {
+ r = paragraphRect(curpara);
+ if( r.y() > contentsY()+visibleHeight() ) break;
+
+ QValueList<DiffInfo> *list = diffPos[curpara];
+ if(list)
+ {
+ QValueList<DiffInfo>::ConstIterator it;
+ for(it = list->begin(); it != list->end(); ++it)
+ {
+ QRect beg = mapToView( curpara, (*it).begin );
+ QRect end = mapToView( curpara, (*it).end );
+
+ QColor* c = 0;
+ if( (*it).add && !_diffUnderlineAdd)
+ c = &_diffAddColor;
+ else if(!(*it).add && !_diffStrikeOutDel)
+ c = &_diffDelColor;
+
+ if ( c != 0 )
+ {
+ // Single or multiple lines?
+ if ( beg.top() == end.top())
+ {
+ painter.fillRect( QRect( beg.topLeft(),
+ QPoint( end.right(), end.bottom())), *c );
+ }
+ else
+ {
+ painter.fillRect( QRect(
+ beg.topLeft(),
+ QPoint( r.right(), beg.bottom())), *c );
+ if( end.top()-beg.bottom() > 2 ) {
+ // there is a line, not only thin space
+ painter.fillRect( QRect(
+ QPoint( r.left(), beg.bottom()),
+ QPoint( r.right(), end.top())), *c );
+ }
+ painter.fillRect( QRect(
+ QPoint( r.left(), end.top()),
+ QPoint( end.right(), end.bottom())), *c );
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ if( _showDiff && (_diffUnderlineAdd || _diffStrikeOutDel) )
+ {
+ if( paragraphs() == (int)diffPos.size() ) // sanity check
+ {
+ for( int curpara = paranum; curpara < paragraphs() ; curpara++ )
+ {
+ r = paragraphRect(curpara);
+ if( r.y() > contentsY()+visibleHeight() ) break;
+
+ QValueList<DiffInfo> *list = diffPos[curpara];
+ if(list)
+ {
+ QPen addPen(_diffAddColor,2);
+ QPen delPen(_diffDelColor,2);
+ QValueList<DiffInfo>::ConstIterator it;
+ for(it = list->begin(); it != list->end(); ++it)
+ {
+ QRect beg = mapToView( curpara, (*it).begin );
+ QRect end = mapToView( curpara, (*it).end );
+
+ QPen* p = 0;
+ int dy = 0;
+ if( (*it).add && _diffUnderlineAdd)
+ p = &addPen;
+ else if(!(*it).add && _diffStrikeOutDel)
+ {
+ p = &delPen;
+ dy = fm.ascent()/2-1;
+ }
+
+ if ( p != 0 )
+ {
+ painter.setPen( *p );
+
+ // Single or multiple lines?
+ if ( beg.top() == end.top())
+ painter.drawLine(
+ beg.topLeft() + QPoint(0, fm.ascent()-dy),
+ end.topRight()+ QPoint(0, fm.ascent()-dy));
+ else
+ {
+ int y = beg.top() + fm.ascent();
+ painter.drawLine(
+ QPoint(beg.left(), y),
+ QPoint(r.right(), y));
+ y += fm.lineSpacing();
+ while (y < end.top() + fm.ascent())
+ {
+ painter.drawLine(
+ QPoint(r.left(), y),
+ QPoint(r.right(), y));
+ y += fm.lineSpacing();
+ }
+ painter.drawLine(
+ QPoint(r.left(), end.top() + fm.ascent()),
+ QPoint(end.right(), end.top() + fm.ascent()));
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+}
+
+void MsgMultiLineEdit::repaint()
+{
+ highlight();
+ MyMultiLineEdit::repaint();
+}
+
+void MsgMultiLineEdit::forceUpdate()
+{
+ _firstChangedLine=0;
+ _lastChangedLine=paragraphs()-1;
+ highlighter->highlight();
+ MyMultiLineEdit::repaint();
+}
+
+void MsgMultiLineEdit::ensureCursorVisible()
+{
+ if( isUpdatesEnabled() )
+ MyMultiLineEdit::ensureCursorVisible();
+}
+
+void MsgMultiLineEdit::highlight()
+{
+/* if( _dontUpdate ) return;
+
+ QColor bg;
+ if( _highlightBg ) bg = _bgColor;
+ else bg = colorGroup().base();
+
+ for( int i = 0 ; i < paragraphs() ; i++ )
+ setParagraphBackgroundColor( i, bg );
+
+
+ if(_hlSyntax)
+ {
+ blockSignals(true); // block signals to avoid recursion
+ setUpdatesEnabled(false);
+ int cursorParagraph, cursorIndex;
+
+ getCursorPosition( &cursorParagraph, &cursorIndex );
+
+ // setup new colors
+
+ uint i;
+
+ QRegExp markup("(\\\\)|(\")|(\\\\[abfnrtv'\"\?\\\\])|(\\\\\\d+)|(\\\\x[\\dabcdef]+)"
+ "|(%[\\ddioxXucsfeEgGphln]+)|(&[^\\s])|(&[\\w-]+;)");
+
+ for( i = QMAX(_firstChangedLine,0) ; i < QMIN(_lastChangedLine+1,(uint)paragraphs()) ; i++ ) {
+
+ QString line=text(i);
+
+ //remove old highlighting
+ setSelection(i,0,i,line.length());
+ setColor( _currentColor );
+ removeSelection();
+
+ QColor colorToUse;
+
+ int index=0;
+ index=markup.search( line, index );
+ while(index>=0)
+ {
+ switch( line[index].latin1() )
+ {
+ case '\\':
+ if( markup.matchedLength() == 1 ) colorToUse=_unquoteColor;
+ else colorToUse=_quoteColor;
+ break;
+ case '\"':
+ colorToUse=_unquoteColor;
+ break;
+ case '%':
+ colorToUse=_cformatColor;
+ break;
+ case '&':
+ colorToUse=_accelColor;
+ break;
+ }
+
+ setSelection( i, index, i, index+markup.matchedLength(), 0);
+ setColor( colorToUse );
+ removeSelection();
+ index=markup.search( line, index+markup.matchedLength() );
+ }
+ }
+
+ // Color XML and HTML tags
+
+ int tagindex=0;
+ int taglength=0;
+ int lineindex=0;
+ uint index=0;
+ int startPara, endPara, startIndex, endIndex;
+ QString t= text();
+
+ if(_lastParagraph <= _firstChangedLine)
+ {
+ index=_lastParagraph;
+ lineindex=_lastParagraphOffset;
+ }
+
+ for( ; index<_firstChangedLine ; index++)
+ lineindex+=paragraphLength(index)+1;
+
+ QRegExp re("<.*>");
+ re.setMinimal(true);
+
+ if( _firstChangedLine >0 )
+ {
+ QColor c;
+ QFont f;
+ VerticalAlignment v;
+ getFormat(_firstChangedLine-1, paragraphLength(_firstChangedLine-1)-1, &f, &c, &v);
+ QString l = text(_firstChangedLine-1);
+ if( c==_tagColor && !l.endsWith(">") ) // hope _tagColor will be different than other colors
+ {
+ QRegExp endtag("[^<]*>");
+ tagindex=endtag.search(t, lineindex);
+ taglength=endtag.matchedLength();
+ } else {
+ tagindex=re.search(t, lineindex);
+ taglength=re.matchedLength();
+ }
+ } else {
+ tagindex=re.search( t, lineindex );
+ taglength=re.matchedLength();
+ }
+
+ while( tagindex >= 0 && (int)index<paragraphs())
+ {
+ while( tagindex>=lineindex && index<_lastChangedLine+2)
+ lineindex+=paragraphLength(index++)+1;
+ if(index==_lastChangedLine+2) break;
+ lineindex-=paragraphLength(index-1);
+ lineindex--;
+ index--;
+
+ startPara=index;
+ startIndex=tagindex-lineindex;
+
+ tagindex+=taglength;
+
+ while( tagindex>=lineindex && (int)index<paragraphs())
+ lineindex+=paragraphLength(index++)+1;
+ lineindex-=paragraphLength(index-1);
+ lineindex--;
+ index--;
+
+ endPara=index;
+ endIndex=tagindex-lineindex;
+
+ setSelection( startPara, startIndex, endPara, endIndex, 0 );
+ setColor( _tagColor );
+ removeSelection();
+
+ if(index>_lastChangedLine) break;
+ tagindex=re.search( t, tagindex );
+ taglength=re.matchedLength();
+ }
+
+ setCursorPosition( cursorParagraph, cursorIndex );
+ setColor( _textColor );
+ setUpdatesEnabled(true);
+ blockSignals(false); // block signals to avoid recursion
+ updateContents();
+ }
+ ensureCursorVisible();
+ */
+}
+
+void MsgMultiLineEdit::drawContents( QPainter *painter, int clipx, int clipy, int clipw, int cliph )
+{
+ MyMultiLineEdit::drawContents( painter, clipx, clipy, clipw, cliph );
+ paintSpacePoints();
+}
+
+void MsgMultiLineEdit::paintEvent( QPaintEvent *event )
+{
+ MyMultiLineEdit::paintEvent( event );
+ paintSpacePoints();
+}
+
+QRect MsgMultiLineEdit::mapToView( int para, int index )
+{
+ if( para < 0 || para > paragraphs() ||
+ index < 0 || index > paragraphLength(para) )
+ return QRect(); //invalid rectangle
+
+ const QFontMetrics& fm = fontMetrics();
+ const QString& paratext = text(para);
+
+ // Find index of the first character on the same line as parameter
+ // 'index' using binary search. Very fast, even for long texts.
+ int linestart = 0;
+ int indexline = lineOfChar( para, index );
+ if ( indexline > 0 )
+ {
+ int min = 0, max = index;
+ int i = (min + max)/2;
+ int iline = lineOfChar( para, i );
+ while ( iline != indexline-1 ||
+ lineOfChar( para, i+1 ) != indexline )
+ {
+ Q_ASSERT( min != max && min != i && max != i );
+ if ( iline < indexline )
+ min = i;
+ else
+ max = i;
+ i = (min + max)/2;
+ iline = lineOfChar( para, i );
+ }
+ linestart = i+1;
+ }
+ Q_ASSERT( linestart >= 0 );
+
+ int linewidth;
+
+ // if the tag is not valid, easy
+ if( (_tagStartPara == _tagEndPara) && (_tagStartIndex == _tagEndIndex) ) {
+ linewidth = fm.width( paratext.mid( linestart, index-linestart ));
+ } else {
+ int tso = pos2Offset( _tagStartPara, _tagStartIndex );
+ int teo = pos2Offset( _tagEndPara, _tagEndIndex );
+ int off = pos2Offset( para, index );
+
+ if( off < tso ) {
+ // it is surely before the tag
+ linewidth = fm.width( paratext.mid( linestart, index-linestart ));
+ } else if( off >= teo ) {
+ // it is surely after the tag
+
+ // is it on the same line as the end of the tag?
+ if( _tagEndPara < para || lineOfChar( _tagEndPara, _tagEndIndex ) < indexline ) {
+ // no tag on the line, no bold
+ linewidth = fm.width( paratext.mid( linestart, index-linestart ));
+ } else {
+ QFont f( font() );
+ f.setBold( true );
+ QFontMetrics bfm( f );
+ // is tag single displayed line?
+ if( _tagStartPara == _tagEndPara
+ && lineOfChar( _tagStartPara, _tagStartIndex ) == lineOfChar( _tagEndPara, _tagEndIndex ) )
+ {
+ // yes, count the non-bold before the tag start
+ linewidth = fm.width( paratext.mid( linestart, _tagStartIndex-linestart ) )
+ + bfm.width( paratext.mid( _tagStartIndex, _tagEndIndex-_tagStartIndex ) );
+ }
+ else
+ {
+ // count the part of the tag itself
+ linewidth = bfm.width( paratext.mid( linestart, _tagEndIndex-linestart ) );
+ }
+
+ // add the rest from tag to the index
+ linewidth += fm.width( paratext.mid( _tagEndIndex, index-_tagEndIndex ) );
+ }
+ }
+ else {
+ // in tag
+ QFont f( font() );
+ f.setBold( true );
+ QFontMetrics bfm( f );
+ // is it the first line of the tag?
+ if( para == _tagStartPara && indexline == lineOfChar( _tagStartPara, _tagStartIndex ) ) {
+ // start of the line is normal
+ linewidth = fm.width( paratext.mid( linestart, _tagStartIndex-linestart ) )
+ + bfm.width( paratext.mid( _tagStartIndex, index-_tagStartIndex ) );
+ } else {
+ // whole is bold
+ linewidth = bfm.width( paratext.mid( linestart, index-linestart ) );
+ }
+ }
+ }
+
+ // FIXME as soon as it's possible to ask real margins from QTextEdit:
+ const int left_margin = 4;
+ // const int top_margin = 4;
+
+ QPainter painter( viewport());
+ const QRect& linerect = paragraphRect(para);
+ return QRect(
+ contentsToViewport( QPoint(
+ left_margin + linerect.left() + linewidth ,
+ /*top_margin + */linerect.top() + indexline * fm.lineSpacing() + fm.leading())),
+ QSize(
+ fm.charWidth( paratext, index ),
+ fm.lineSpacing()
+ ));
+}
+
+void MsgMultiLineEdit::keyPressEvent(QKeyEvent *e)
+{
+ if(!_cleverEditing || isReadOnly())
+ {
+ MyMultiLineEdit::keyPressEvent(e);
+ return;
+ }
+
+ KKey key( e );
+
+ if(e->key() == Key_Return || e->key() == Key_Enter)
+ {
+ emit signalUndoCmd(new BeginCommand(-1,UndefPart));
+
+ int row, col;
+ getCursorPosition(&row,&col);
+ QString str=text(row);
+
+ if(e->state() & ShiftButton)
+ {
+ if(col > 0 && !str.isEmpty())
+ {
+ if(str.at(col-1) == '\\' && !isMasked(&str,col-1))
+ {
+ insert("n",false);
+ }
+ else
+ {
+ insert("\\n",false);
+ }
+ }
+ else
+ {
+ insert("\\n",false);
+ }
+ }
+ else if(!(e->state() & ControlButton))
+ {
+ if(col > 0 && !str.isEmpty() && !str.at(col-1).isSpace())
+ {
+ if(str.at(col-1)=='\\' && !isMasked(&str,col-1))
+ {
+ insert("\\",false);
+ }
+
+ // if there is not a new line at the end
+ if(col < 2 || str.mid(col-2,2)!="\\n")
+ {
+ insert(" ",false);
+ }
+ }
+ else if(str.isEmpty())
+ {
+ insert("\\n",false);
+ }
+ }
+
+ if( !str.isEmpty())
+ {
+ // construct new event without modifiers
+ MyMultiLineEdit::keyPressEvent( new QKeyEvent(e->type(), e->key(), e->ascii(), 0,
+ e->text(), e->isAutoRepeat(), e->count() ) );
+ e->accept();
+ }
+
+ emit signalUndoCmd(new EndCommand(-1,UndefPart));
+ return;
+ }
+ else if(e->key() == Key_Tab)
+ {
+ insert("\\t",false);
+ emit textChanged();
+ e->accept();
+ return;
+ }
+ else if((e->key() == Key_Delete && !(e->state() & ControlButton))
+ || ((e->state() & ControlButton) && e->key() == Key_D) )
+ {
+ emit signalUndoCmd(new BeginCommand(-1,UndefPart));
+
+ if(!hasSelectedText())
+ {
+ int row, col;
+ getCursorPosition(&row,&col);
+ QString str=text(row);
+
+ if(!str.isEmpty() && col < (int)str.length() && str.at(col) == '\\'
+ && !isMasked(&str,col))
+ {
+ QString spclChars="abfnrtv'\"?\\";
+ if(col < (int)str.length()-1
+ && spclChars.contains(str.at(col+1)))
+ {
+ del();
+ }
+ }
+ }
+
+ del();
+
+ emit signalUndoCmd(new EndCommand(-1,UndefPart));
+ emit textChanged();
+ e->accept();
+ return;
+ }
+ else if(e->key() == Key_BackSpace
+ || ((e->state() & ControlButton) && e->key() == Key_H) )
+ {
+ emit signalUndoCmd(new BeginCommand(-1,UndefPart));
+
+ if(!hasSelectedText())
+ {
+ int row, col;
+ getCursorPosition(&row,&col);
+ QString str=text(row);
+
+ QString spclChars="abfnrtv'\"?\\";
+ if(!str.isEmpty() && col > 0 && spclChars.contains(str.at(col-1)))
+ {
+ if(col > 1 && str.at(col-2)=='\\' && !isMasked(&str,col-2))
+ {
+ MyMultiLineEdit::keyPressEvent(e);
+ }
+ }
+
+ }
+
+ MyMultiLineEdit::keyPressEvent(e);
+
+ emit signalUndoCmd(new EndCommand(-1,UndefPart));
+
+ e->accept();
+ return;
+ }
+ else if(e->text() == "\"")
+ {
+ emit signalUndoCmd(new BeginCommand(-1,UndefPart));
+
+ int row, col;
+ getCursorPosition(&row,&col);
+ QString str=text(row);
+
+ if(col == 0 || str.at(col-1) != '\\' || isMasked(&str,col-1) )
+ {
+ insert("\\\"",false);
+ }
+ else
+ {
+ insert("\"",false);
+ }
+
+ e->accept();
+
+ emit signalUndoCmd(new EndCommand(-1,UndefPart));
+ return;
+ }
+ else if(e->key() == Key_Space && ( e->state() & AltButton ) )
+ {
+ insert( QChar( 0x00a0U ) );
+ e->accept();
+ return;
+ }
+ // ALT+123 feature
+ else if(( e->state() & AltButton ) && e->text()[0].isDigit() )
+ {
+ QString text=e->text();
+ while ( text[0].isDigit() ) {
+ _currentUnicodeNumber = 10*_currentUnicodeNumber+(text[0].digitValue());
+ text.remove( 0, 1 );
+ }
+ }
+ else
+ {
+ MyMultiLineEdit::keyPressEvent(e);
+ }
+}
+
+void MsgMultiLineEdit::keyReleaseEvent(QKeyEvent* e)
+{
+ if ( e->key() == Key_Alt && _currentUnicodeNumber >= 32 )
+ {
+ QString text = QChar( _currentUnicodeNumber );
+ _currentUnicodeNumber=0;
+ insert( text );
+ }
+}
+
+void MsgMultiLineEdit::setDiffMode(bool on)
+{
+ _showDiff=on;
+
+ if(!on)
+ {
+ diffPos.clear();
+ }
+}
+
+bool MsgMultiLineEdit::isMasked(QString *str, uint col)
+{
+ if(col == 0 || !str)
+ return false;
+
+ uint counter=0;
+ int pos=col;
+
+ while(pos >= 0 && str->at(pos) == '\\')
+ {
+ counter++;
+ pos--;
+ }
+
+ return !(bool)(counter%2);
+}
+
+void MsgMultiLineEdit::emittedTextChanged()
+{
+ highlight();
+ paintSpacePoints();
+}
+
+void MsgMultiLineEdit::selectTag(int start, int length)
+{
+ setUpdatesEnabled(false);
+ setSelection( _tagStartPara, _tagStartIndex, _tagEndPara, _tagEndIndex);
+ setBold( false );
+
+ offset2Pos(start, _tagStartPara, _tagStartIndex);
+ offset2Pos(start+length, _tagEndPara, _tagEndIndex);
+
+ setSelection( _tagStartPara, _tagStartIndex, _tagEndPara, _tagEndIndex);
+ setBold( true );
+ setUpdatesEnabled(true);
+}
+
+#include "mymultilineedit.moc"
diff --git a/kbabel/kbabel/mymultilineedit.h b/kbabel/kbabel/mymultilineedit.h
new file mode 100644
index 00000000..30771610
--- /dev/null
+++ b/kbabel/kbabel/mymultilineedit.h
@@ -0,0 +1,307 @@
+/* ****************************************************************************
+ This file is part of KBabel
+
+ Copyright (C) 1999-2000 by Matthias Kiefer
+ <matthias.kiefer@gmx.de>
+ 2001-2003 by Stanislav Visnovsky
+ <visnovsky@kde.org>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the 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, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+ In addition, as a special exception, the copyright holders give
+ permission to link the code of this program with any edition of
+ the Qt library by Trolltech AS, Norway (or with modified versions
+ of Qt that use the same license as Qt), and distribute linked
+ combinations including the two. You must obey the GNU General
+ Public License in all respects for all of the code used other than
+ Qt. If you modify this file, you may extend this exception to
+ your version of the file, but you are not obligated to do so. If
+ you do not wish to do so, delete this exception statement from
+ your version.
+
+**************************************************************************** */
+#ifndef MYMULTILINEEDIT_H
+#define MYMULTILINEEDIT_H
+
+#include <ktextedit.h>
+#include <qptrvector.h>
+
+namespace KBabel
+{
+ class EditCommand;
+}
+
+class KBabelHighlighter;
+class KSpell;
+class QPixmap;
+
+class MyMultiLineEdit : public KTextEdit
+{
+ Q_OBJECT
+public:
+ MyMultiLineEdit(int ID,QWidget* parent,const char* name=0);
+
+ /**
+ applies cmd to the displayed text, but does not emit
+ signalUndoCommand
+ */
+ void processCommand(KBabel::EditCommand* cmd, bool undo=false);
+
+ /**
+ * @returns the position in text, where the marked text begins
+ * -1, if there is no marked text
+ */
+ int beginOfMarkedText();
+
+ /**
+ * @returns the position in text, where the last marked text began
+ * or the current cursor position if there was no marked text.
+ * This is used for getting the start position for a text replacement
+ */
+ int beginOfLastMarkedText();
+
+ /**
+ * @returns the position in text, where the last marked text ended
+ * or the current cursor position if there was no marked text.
+ * This is used for getting the end position for a text replacement
+ */
+ int endOfLastMarkedText();
+
+ virtual void insertAt ( const QString & s, int line, int col, bool mark = false );
+ virtual void removeLine ( int line );
+
+ int pos2Offset(uint paragraph, uint index);
+ void offset2Pos(int offset, int &row, int &col) const;
+ /**
+ * @returns the current position in text, where the cursor is
+ */
+
+ int currentIndex();
+ /**
+ * processes Del key
+ */
+ void my_del();
+ void my_backspace();
+
+ /**
+ * need to override deleting of popup menus :-(
+ */
+ void contentsContextMenuEvent( QContextMenuEvent *e );
+
+ /**
+ * need to reimplement overwrite mode :-(
+ */
+ bool isOverwriteMode() { return _overwrite; }
+
+public slots:
+
+ virtual void clear();
+ virtual void paste();
+ virtual void setReadOnly(bool on);
+ virtual void setContextMenu( QPopupMenu *menu );
+ virtual void setText(const QString& s);
+ virtual void doKeyboardAction( KeyboardAction action );
+ virtual void removeSelectedText(int selNum = 0);
+
+ virtual void onSelectionChanged();
+
+ /**
+ reimplemented overwrite mode, since QTextEdit handles this internally and does
+ not use any accessible virtual methods :-((.
+ */
+ virtual void setOverwriteMode(bool b);
+
+protected:
+
+ virtual void focusInEvent(QFocusEvent*);
+ virtual QPopupMenu *createPopupMenu();
+ virtual QPopupMenu *createPopupMenu(const QPoint &pos);
+
+ /* the parent handles this */
+ virtual void wheelEvent(QWheelEvent*);
+
+ bool emitUndo;
+
+ /* First and the last line of the last change. They are only approximate. Used for faster display
+ * highlighting etc.
+ */
+ uint _firstChangedLine;
+ uint _lastChangedLine;
+
+ /* This is a cache. _lastPragraphOffset always correctly corresponds to _lastParagraphOffset
+ */
+ uint _lastParagraph;
+ uint _lastParagraphOffset;
+
+ /* We save the last selection positions. This is needed when a tag is inserted to get the
+ left cursor position of the originally used selection */
+ int _lastSelectionStart;
+ int _lastSelectionEnd;
+
+ /* flag to skip any work on updating, since it will be more changes */
+ bool _dontUpdate;
+
+protected slots:
+ virtual void insert ( const QString & text, bool indent = FALSE, bool checkNewLine = TRUE, bool removeSelected = TRUE );
+ virtual void emitCursorPosition();
+
+signals:
+ void signalUndoCmd(KBabel::EditCommand*);
+ void signalSyntaxHighlightingChanged (bool enable);
+
+protected:
+ int _myID;
+
+private:
+ QPopupMenu *_menu;
+ bool _overwrite;
+};
+
+
+class MsgMultiLineEdit : public MyMultiLineEdit
+{
+ Q_OBJECT
+public:
+ enum TextColor { NormalColor, ErrorColor };
+
+ MsgMultiLineEdit(int ID, KSpell* spell=0, QWidget* parent=0,const char* name=0);
+ virtual ~MsgMultiLineEdit();
+
+ /** is displaying surrounding quotes enabled? */
+ bool quotes() const { return _quotes;}
+ /** enable or disable displaying of surrounding quotes */
+ void setQuotes(bool on);
+
+ /** is clever editing enabled? */
+ bool cleverEditing() const { return _cleverEditing; }
+ /** enable or disable clever editing */
+ void setCleverEditing(bool on);
+ /** is highlighting background enabled? */
+ bool highlightBg() const { return _highlightBg; }
+ /** enable or disable highlighting background*/
+ void setHighlightBg(bool on);
+ QColor bgColor() const { return _bgColor; }
+ void setBgColor(const QColor& color);
+
+ bool spacePoints() const { return _spacePoints; }
+ void setSpacePoints(bool on);
+
+ bool highlightSyntax() const { return _hlSyntax; }
+ void highlight();
+ void setHighlightSyntax(bool on);
+ void setHighlightColors(const QColor& quoteColor, const QColor& unquoteColor
+ , const QColor& cformatColor, const QColor& accelColor, const QColor& tagColor);
+
+ void setFont(const QFont& font);
+
+ void setDiffMode(bool on);
+ void setDiffDisplayMode(bool underlineAdded, bool strikeOutDeleted);
+ void setDiffColors(const QColor& addColor, const QColor& delColor);
+
+ void setTextColor(const QColor &color);
+ void setErrorColor(const QColor &color);
+
+ void setCurrentColor(const TextColor color);
+
+ void setSpellChecker(KSpell* spell);
+
+ void selectTag(int start, int length);
+
+public slots:
+ virtual void setText(const QString& s);
+ void paintSpacePoints();
+ void paintSpacePoints( int para, int pos ); // overloaded for signal QTextEdit::cursorPositionChanged
+
+ /**
+ * reimplemented to call highlight()
+ */
+ void repaint();
+ void forceUpdate();
+ void emittedTextChanged();
+
+ /**
+ * reimplemented to skip in case of disabled updates
+ */
+ void ensureCursorVisible();
+
+protected:
+ virtual void paintEvent (QPaintEvent * event );
+ virtual void drawContents( QPainter *painter, int clipx, int clipy, int clipw, int cliph );
+
+ virtual void keyPressEvent(QKeyEvent*);
+ virtual void keyReleaseEvent(QKeyEvent*);
+
+private:
+ /**
+ * Computes the pixel position in line which corresponds to
+ * character position xIndex
+ */
+ QRect mapToView( int para, int index );
+
+ /**
+ * tests if the character in string str at position col is masked with
+ * '\' by counting the number of '\' backwards
+ */
+ static bool isMasked(QString *str,uint col);
+
+private:
+ bool _quotes;
+ bool _cleverEditing;
+ bool _highlightBg;
+ bool _spacePoints;
+ QColor _bgColor;
+ QColor _textColor;
+ QColor _errorColor;
+ QColor _currentColor;
+
+ QPixmap* _whitespace;
+ QPixmap* _whitespaceNB;
+ QPixmap* _errorWhitespace;
+ QPixmap* _errorWhitespaceNB;
+
+ int _wsOffsetX;
+ int _wsOffsetY;
+
+ bool _hlSyntax;
+ QColor _quoteColor;
+ QColor _unquoteColor;
+ QColor _cformatColor;
+ QColor _accelColor;
+ QColor _tagColor;
+
+ struct DiffInfo
+ {
+ bool add;
+ int begin;
+ int end;
+ };
+
+ QPtrVector< QValueList<DiffInfo> > diffPos;
+ bool _showDiff;
+ bool _diffUnderlineAdd;
+ bool _diffStrikeOutDel;
+ QColor _diffAddColor;
+ QColor _diffDelColor;
+
+ // for Alt+123 feature
+ int _currentUnicodeNumber;
+
+ KBabelHighlighter * highlighter;
+
+ // next tag highlighting
+ int _tagStartPara, _tagStartIndex, _tagEndPara, _tagEndIndex;
+};
+
+#endif // MYMULTILINEEDIT_H
diff --git a/kbabel/kbabel/pics/Makefile.am b/kbabel/kbabel/pics/Makefile.am
new file mode 100644
index 00000000..b5108197
--- /dev/null
+++ b/kbabel/kbabel/pics/Makefile.am
@@ -0,0 +1,6 @@
+# Add all of your pixmaps here
+pics_DATA = broken.png missing.png needwork.png ok.png pref_identity.png \
+ splash.png noflag.png
+
+# This is where it will all be installed
+picsdir = $(kde_datadir)/kbabel/pics
diff --git a/kbabel/kbabel/pics/broken.png b/kbabel/kbabel/pics/broken.png
new file mode 100644
index 00000000..d0948e92
--- /dev/null
+++ b/kbabel/kbabel/pics/broken.png
Binary files differ
diff --git a/kbabel/kbabel/pics/missing.png b/kbabel/kbabel/pics/missing.png
new file mode 100644
index 00000000..e0311068
--- /dev/null
+++ b/kbabel/kbabel/pics/missing.png
Binary files differ
diff --git a/kbabel/kbabel/pics/needwork.png b/kbabel/kbabel/pics/needwork.png
new file mode 100644
index 00000000..e31413d8
--- /dev/null
+++ b/kbabel/kbabel/pics/needwork.png
Binary files differ
diff --git a/kbabel/kbabel/pics/noflag.png b/kbabel/kbabel/pics/noflag.png
new file mode 100644
index 00000000..5b6ad0c2
--- /dev/null
+++ b/kbabel/kbabel/pics/noflag.png
Binary files differ
diff --git a/kbabel/kbabel/pics/ok.png b/kbabel/kbabel/pics/ok.png
new file mode 100644
index 00000000..f2b731a0
--- /dev/null
+++ b/kbabel/kbabel/pics/ok.png
Binary files differ
diff --git a/kbabel/kbabel/pics/pref_identity.png b/kbabel/kbabel/pics/pref_identity.png
new file mode 100644
index 00000000..de7e1459
--- /dev/null
+++ b/kbabel/kbabel/pics/pref_identity.png
Binary files differ
diff --git a/kbabel/kbabel/pics/splash.png b/kbabel/kbabel/pics/splash.png
new file mode 100644
index 00000000..26f908c7
--- /dev/null
+++ b/kbabel/kbabel/pics/splash.png
Binary files differ
diff --git a/kbabel/kbabel/searchpreferences.ui b/kbabel/kbabel/searchpreferences.ui
new file mode 100644
index 00000000..5e002657
--- /dev/null
+++ b/kbabel/kbabel/searchpreferences.ui
@@ -0,0 +1,109 @@
+<!DOCTYPE UI><UI version="3.2" stdsetdef="1">
+<class>SearchPreferences</class>
+<author>Stanislav Visnovsky</author>
+<widget class="QWidget">
+ <property name="name">
+ <cstring>SearchPreferences</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="QFrame">
+ <property name="name">
+ <cstring>frame3</cstring>
+ </property>
+ <property name="frameShape">
+ <enum>StyledPanel</enum>
+ </property>
+ <property name="frameShadow">
+ <enum>Raised</enum>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QCheckBox">
+ <property name="name">
+ <cstring>kcfg_AutoSearch</cstring>
+ </property>
+ <property name="text">
+ <string>Au&amp;tomatically start search</string>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>&lt;qt&gt;&lt;p&gt;&lt;b&gt;Automatically start search&lt;/b&gt;&lt;/p&gt;
+&lt;p&gt;If this is activated, the search is automatically started
+whenever you switch to another entry in the editor. You can
+choose where to search with the combo box &lt;b&gt;Default Dictionary&lt;/b&gt;.
+&lt;/p&gt;&lt;p&gt;You can also start searching manually by choosing an entry in
+the popup menu that appears either when clicking
+&lt;b&gt;Dictionaries-&gt;Find...&lt;/b&gt; or keeping the dictionary button
+in the toolbar pressed for a while.&lt;/p&gt;&lt;/qt&gt;</string>
+ </property>
+ </widget>
+ <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>textLabel1</cstring>
+ </property>
+ <property name="text">
+ <string>D&amp;efault dictionary:</string>
+ </property>
+ <property name="buddy" stdset="0">
+ <cstring>_kcfg_DefaultModule</cstring>
+ </property>
+ </widget>
+ <widget class="QComboBox">
+ <property name="name">
+ <cstring>_kcfg_DefaultModule</cstring>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>&lt;qt&gt;&lt;p&gt;&lt;b&gt;Default Dictionary&lt;/b&gt;&lt;/p&gt;
+&lt;p&gt;Choose here where to search as default.
+This setting is used when searching is started automatically
+or when pressing the dictionary button in the toolbar.&lt;/p&gt;
+&lt;p&gt;You can configure the different dictionaries by selecting
+the desired dictionary from &lt;b&gt;Settings-&gt;Configure Dictionary&lt;/b&gt;.
+&lt;/p&gt;&lt;/qt&gt;</string>
+ </property>
+ </widget>
+ </hbox>
+ </widget>
+ </vbox>
+ </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>31</width>
+ <height>91</height>
+ </size>
+ </property>
+ </spacer>
+ </vbox>
+</widget>
+<layoutdefaults spacing="6" margin="11"/>
+</UI>
diff --git a/kbabel/kbabel/sourceview.cpp b/kbabel/kbabel/sourceview.cpp
new file mode 100644
index 00000000..08c0f8a4
--- /dev/null
+++ b/kbabel/kbabel/sourceview.cpp
@@ -0,0 +1,75 @@
+/* ****************************************************************************
+ This file is part of KBabel
+
+ Copyright (C) 2004-2005 by Stanislav Visnovsky
+ <visnovsky@kde.org>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the 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, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+ In addition, as a special exception, the copyright holders give
+ permission to link the code of this program with any edition of
+ the Qt library by Trolltech AS, Norway (or with modified versions
+ of Qt that use the same license as Qt), and distribute linked
+ combinations including the two. You must obey the GNU General
+ Public License in all respects for all of the code used other than
+ Qt. If you modify this file, you may extend this exception to
+ your version of the file, but you are not obligated to do so. If
+ you do not wish to do so, delete this exception statement from
+ your version.
+
+**************************************************************************** */
+
+#include "sourceview.h"
+#include "context.h"
+
+#include <qlayout.h>
+#include <qwhatsthis.h>
+
+#include <kcursor.h>
+#include <klocale.h>
+
+#include "resources.h"
+#include "kbcatalog.h"
+
+using namespace KBabel;
+
+SourceView::SourceView(KBCatalog* catalog,QWidget *parent, Project::Ptr project)
+ : KBCatalogView(catalog,parent,project)
+{
+ QVBoxLayout* layout = new QVBoxLayout( this );
+ layout->setResizeMode( QLayout::Minimum );
+
+ _contextView = new SourceContext (this, project);
+ layout->addWidget (_contextView);
+
+ connect(_catalog, SIGNAL(signalFileOpened(bool)), this, SLOT(setDisabled(bool)));
+}
+
+void SourceView::updateView()
+{
+ if (isVisible ())
+ {
+ // Note: we use Catalog::comment instead of Catalog::context as SourceContext::setContext has to repeat the major part of the code of Catalog::context, so SourceContext::setContext can do the whole job alone.
+ _contextView->setContext( _catalog->packageDir(), _catalog->packageName(), _catalog->comment(_currentIndex), _catalog->currentURL() );
+ }
+}
+
+void SourceView::setProject(KBabel::Project::Ptr project)
+{
+ KBCatalogView::setProject(project);
+ _contextView->setProject(project);
+}
+
+#include "sourceview.moc"
diff --git a/kbabel/kbabel/sourceview.h b/kbabel/kbabel/sourceview.h
new file mode 100644
index 00000000..8caeed35
--- /dev/null
+++ b/kbabel/kbabel/sourceview.h
@@ -0,0 +1,57 @@
+/* ****************************************************************************
+ This file is part of KBabel
+
+ Copyright (C) 2004-2005 by Stanislav Visnovsky
+ <visnovsky@kde.org>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the 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, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+ In addition, as a special exception, the copyright holders give
+ permission to link the code of this program with any edition of
+ the Qt library by Trolltech AS, Norway (or with modified versions
+ of Qt that use the same license as Qt), and distribute linked
+ combinations including the two. You must obey the GNU General
+ Public License in all respects for all of the code used other than
+ Qt. If you modify this file, you may extend this exception to
+ your version of the file, but you are not obligated to do so. If
+ you do not wish to do so, delete this exception statement from
+ your version.
+
+**************************************************************************** */
+#ifndef SOURCEVIEW_H
+#define SOURCEVIEW_H
+
+#include "kbcatalogview.h"
+
+class SourceContext;
+
+class SourceView : public KBCatalogView
+{
+ Q_OBJECT
+public:
+ /**
+ * Default constructor
+ */
+ SourceView(KBCatalog* catalog,QWidget *parent, KBabel::Project::Ptr project);
+
+public slots:
+ virtual void updateView();
+ virtual void setProject(KBabel::Project::Ptr project);
+
+private:
+ SourceContext* _contextView;
+};
+
+#endif // SOURCEVIEW_H
diff --git a/kbabel/kbabel/spelldlg.cpp b/kbabel/kbabel/spelldlg.cpp
new file mode 100644
index 00000000..49500e09
--- /dev/null
+++ b/kbabel/kbabel/spelldlg.cpp
@@ -0,0 +1,142 @@
+/* ****************************************************************************
+ This file is part of KBabel
+
+ Copyright (C) 1999-2000 by Matthias Kiefer
+ <matthias.kiefer@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.
+
+ 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, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+ In addition, as a special exception, the copyright holders give
+ permission to link the code of this program with any edition of
+ the Qt library by Trolltech AS, Norway (or with modified versions
+ of Qt that use the same license as Qt), and distribute linked
+ combinations including the two. You must obey the GNU General
+ Public License in all respects for all of the code used other than
+ Qt. If you modify this file, you may extend this exception to
+ your version of the file, but you are not obligated to do so. If
+ you do not wish to do so, delete this exception statement from
+ your version.
+
+**************************************************************************** */
+#include "spelldlg.h"
+#include "spelldlgwidget.h"
+
+#include <qcheckbox.h>
+#include <qradiobutton.h>
+
+#include <kconfig.h>
+#include <kglobal.h>
+#include <klocale.h>
+
+SpellDlg::SpellDlg(bool haveMarkedText,QWidget *parent,const char *name)
+ : KDialogBase(parent,name,true,i18n("Caption of dialog","Spelling")
+ , Ok|Cancel)
+{
+ setButtonOK(KGuiItem(i18n("&Spell Check"),"spellcheck"));
+
+ _mainWidget = new SpellDlgWidget(this);
+ setMainWidget(_mainWidget);
+
+ if(haveMarkedText)
+ {
+ _mainWidget->markedBtn->setChecked(true);
+ _mainWidget->defaultBtn->setChecked(false);
+ _mainWidget->defaultBtn->setEnabled(false);
+ }
+ else
+ {
+ _mainWidget->markedBtn->setEnabled(false);
+
+ KConfig *config = KGlobal::config();
+ KConfigGroupSaver cs(config,"SpellDlg");
+ QString what=config->readEntry("Default","All");
+
+ if(what=="All")
+ _mainWidget->allBtn->setChecked(true);
+ else if(what=="Current")
+ _mainWidget->currentBtn->setChecked(true);
+ else if(what=="Begin")
+ _mainWidget->beginBtn->setChecked(true);
+ else if(what=="End")
+ _mainWidget->endBtn->setChecked(true);
+ else
+ _mainWidget->allBtn->setChecked(true);
+
+ }
+
+}
+
+SpellDlg::~SpellDlg()
+{
+ if(_mainWidget->defaultBtn->isChecked())
+ {
+ KConfig *config=KGlobal::config();
+ KConfigGroupSaver cs(config,"SpellDlg");
+
+ QString what="All";
+ if(_mainWidget->endBtn->isChecked())
+ what="End";
+ else if(_mainWidget->beginBtn->isChecked())
+ what="Begin";
+ else if(_mainWidget->currentBtn->isChecked())
+ what="Current";
+
+ config->writeEntry("Default",what);
+ }
+}
+
+bool SpellDlg::all() const
+{
+ return _mainWidget->allBtn->isChecked();
+}
+
+bool SpellDlg::current() const
+{
+ return _mainWidget->currentBtn->isChecked();
+}
+
+bool SpellDlg::begin() const
+{
+ return _mainWidget->beginBtn->isChecked();
+}
+
+bool SpellDlg::end() const
+{
+ return _mainWidget->endBtn->isChecked();
+}
+
+bool SpellDlg::marked() const
+{
+ return _mainWidget->markedBtn->isChecked();
+}
+
+
+void SpellDlg::markedChecked(bool on)
+{
+ if(on)
+ {
+ _mainWidget->defaultBtn->setChecked(false);
+ }
+
+ _mainWidget->defaultBtn->setEnabled(!on);
+}
+
+bool SpellDlg::beginCurrent( ) const
+{
+ return _mainWidget->beginCurrentMsgBtn->isChecked( );
+}
+
+
+#include "spelldlg.moc"
diff --git a/kbabel/kbabel/spelldlg.h b/kbabel/kbabel/spelldlg.h
new file mode 100644
index 00000000..ea857777
--- /dev/null
+++ b/kbabel/kbabel/spelldlg.h
@@ -0,0 +1,63 @@
+/* ****************************************************************************
+ This file is part of KBabel
+
+ Copyright (C) 1999-2000 by Matthias Kiefer
+ <matthias.kiefer@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.
+
+ 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, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+ In addition, as a special exception, the copyright holders give
+ permission to link the code of this program with any edition of
+ the Qt library by Trolltech AS, Norway (or with modified versions
+ of Qt that use the same license as Qt), and distribute linked
+ combinations including the two. You must obey the GNU General
+ Public License in all respects for all of the code used other than
+ Qt. If you modify this file, you may extend this exception to
+ your version of the file, but you are not obligated to do so. If
+ you do not wish to do so, delete this exception statement from
+ your version.
+
+**************************************************************************** */
+#ifndef SPELLDLG_H
+#define SPELLDLG_H
+
+#include <kdialogbase.h>
+
+
+class SpellDlgWidget;
+
+class SpellDlg : public KDialogBase
+{
+ Q_OBJECT
+
+public:
+ SpellDlg(bool haveMarkedText, QWidget* parent, const char *name=0);
+ ~SpellDlg();
+
+ bool all() const;
+ bool current() const;
+ bool begin() const;
+ bool end() const;
+ bool marked() const;
+ bool beginCurrent() const;
+
+private slots:
+ void markedChecked(bool);
+
+private:
+ SpellDlgWidget *_mainWidget;
+};
+
+#endif // SPELLDLG_H
diff --git a/kbabel/kbabel/spelldlgwidget.ui b/kbabel/kbabel/spelldlgwidget.ui
new file mode 100644
index 00000000..fe5a5d0b
--- /dev/null
+++ b/kbabel/kbabel/spelldlgwidget.ui
@@ -0,0 +1,126 @@
+<!DOCTYPE UI><UI version="3.1" stdsetdef="1">
+<class>SpellDlgWidget</class>
+<widget class="QWidget">
+ <property name="name">
+ <cstring>SpellDlgWidget</cstring>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>388</width>
+ <height>262</height>
+ </rect>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QButtonGroup">
+ <property name="name">
+ <cstring>buttonGroup1</cstring>
+ </property>
+ <property name="title">
+ <string>Choose What You Want to Spell Check</string>
+ </property>
+ <property name="flat">
+ <bool>false</bool>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>Spell check only the current message.</string>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QRadioButton">
+ <property name="name">
+ <cstring>allBtn</cstring>
+ </property>
+ <property name="text">
+ <string>A&amp;ll messages</string>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>Spell check all translated messages of this file.</string>
+ </property>
+ </widget>
+ <widget class="QRadioButton">
+ <property name="name">
+ <cstring>currentBtn</cstring>
+ </property>
+ <property name="text">
+ <string>C&amp;urrent message only</string>
+ </property>
+ <property name="toolTip" stdset="0">
+ <string></string>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>Spell check only the current message.</string>
+ </property>
+ </widget>
+ <widget class="QRadioButton">
+ <property name="name">
+ <cstring>beginCurrentMsgBtn</cstring>
+ </property>
+ <property name="text">
+ <string>Fro&amp;m beginning of current message to end of file</string>
+ </property>
+ </widget>
+ <widget class="QRadioButton">
+ <property name="name">
+ <cstring>beginBtn</cstring>
+ </property>
+ <property name="text">
+ <string>&amp;From beginning of file to cursor position</string>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>Spell check all text from the beginning of the file to the current cursor position.</string>
+ </property>
+ </widget>
+ <widget class="QRadioButton">
+ <property name="name">
+ <cstring>endBtn</cstring>
+ </property>
+ <property name="text">
+ <string>F&amp;rom cursor position to end of file</string>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>Spell check all text from the current cursor position to the end of the file.</string>
+ </property>
+ </widget>
+ <widget class="QRadioButton">
+ <property name="name">
+ <cstring>markedBtn</cstring>
+ </property>
+ <property name="text">
+ <string>S&amp;elected text only</string>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>Spell check only the selected text.</string>
+ </property>
+ </widget>
+ </vbox>
+ </widget>
+ <widget class="QCheckBox">
+ <property name="name">
+ <cstring>defaultBtn</cstring>
+ </property>
+ <property name="text">
+ <string>U&amp;se this selection as default</string>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>Check this, to store the current selection as default selection.</string>
+ </property>
+ </widget>
+ </vbox>
+</widget>
+<tabstops>
+ <tabstop>allBtn</tabstop>
+ <tabstop>beginBtn</tabstop>
+ <tabstop>markedBtn</tabstop>
+ <tabstop>currentBtn</tabstop>
+ <tabstop>endBtn</tabstop>
+ <tabstop>defaultBtn</tabstop>
+</tabstops>
+<layoutdefaults spacing="6" margin="11"/>
+</UI>
diff --git a/kbabel/kbabel/taglistview.cpp b/kbabel/kbabel/taglistview.cpp
new file mode 100644
index 00000000..8dedccea
--- /dev/null
+++ b/kbabel/kbabel/taglistview.cpp
@@ -0,0 +1,78 @@
+/* ****************************************************************************
+ This file is part of KBabel
+
+ Copyright (C) 2002-2004 by Stanislav Visnovsky
+ <visnovsky@kde.org>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the 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, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+ In addition, as a special exception, the copyright holders give
+ permission to link the code of this program with any edition of
+ the Qt library by Trolltech AS, Norway (or with modified versions
+ of Qt that use the same license as Qt), and distribute linked
+ combinations including the two. You must obey the GNU General
+ Public License in all respects for all of the code used other than
+ Qt. If you modify this file, you may extend this exception to
+ your version of the file, but you are not obligated to do so. If
+ you do not wish to do so, delete this exception statement from
+ your version.
+
+**************************************************************************** */
+
+#include "taglistview.h"
+
+#include <qlayout.h>
+#include <qwhatsthis.h>
+
+#include <kcursor.h>
+#include <klistbox.h>
+#include <klocale.h>
+
+#include "kbcatalog.h"
+
+using namespace KBabel;
+
+TagListView::TagListView(KBCatalog* catalog,QWidget *parent, Project::Ptr project)
+ : KBCatalogView(catalog,parent,project)
+{
+ QVBoxLayout* layout = new QVBoxLayout( this );
+ layout->setResizeMode( QLayout::Minimum );
+
+ _tagBox = new KListBox (this, "taglist textview");
+
+ layout->addWidget (_tagBox);
+
+ connect(_tagBox,SIGNAL(selected(const QString&))
+ , this, SIGNAL(signalTagSelected(const QString&)));
+ connect(_tagBox,SIGNAL(highlighted(int))
+ , this, SIGNAL(signalHighlightedTagChanged(int)));
+
+ connect(_catalog, SIGNAL(signalFileOpened(bool))
+ , this, SLOT(setDisabled(bool)));
+}
+
+void TagListView::updateView()
+{
+ _tagBox->clear();
+ _tagBox->insertStringList(_catalog->tagList(_currentIndex));
+ _tagBox->setCurrentItem(0);
+}
+
+void TagListView::highlightTag(int index)
+{
+ _tagBox->setCurrentItem(index);
+}
+
+#include "taglistview.moc"
diff --git a/kbabel/kbabel/taglistview.h b/kbabel/kbabel/taglistview.h
new file mode 100644
index 00000000..0435e3ba
--- /dev/null
+++ b/kbabel/kbabel/taglistview.h
@@ -0,0 +1,61 @@
+/* ****************************************************************************
+ This file is part of KBabel
+
+ Copyright (C) 2004 by Stanislav Visnovsky
+ <visnovsky@kde.org>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the 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, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+ In addition, as a special exception, the copyright holders give
+ permission to link the code of this program with any edition of
+ the Qt library by Trolltech AS, Norway (or with modified versions
+ of Qt that use the same license as Qt), and distribute linked
+ combinations including the two. You must obey the GNU General
+ Public License in all respects for all of the code used other than
+ Qt. If you modify this file, you may extend this exception to
+ your version of the file, but you are not obligated to do so. If
+ you do not wish to do so, delete this exception statement from
+ your version.
+
+**************************************************************************** */
+#ifndef TAGLISTVIEW_H
+#define TAGLISTVIEW_H
+
+#include "kbcatalogview.h"
+
+class KListBox;
+
+class TagListView : public KBCatalogView
+{
+ Q_OBJECT
+public:
+ /**
+ * Default constructor
+ */
+ TagListView(KBCatalog* catalog,QWidget *parent, KBabel::Project::Ptr project);
+
+public slots:
+ virtual void updateView();
+ void highlightTag (int index);
+
+signals:
+ void signalHighlightedTagChanged (int index);
+ void signalTagSelected (const QString& tag);
+
+private:
+ KListBox* _tagBox;
+};
+
+#endif // TAGLISTVIEW_H
diff --git a/kbabel/kbabeldict/Makefile.am b/kbabel/kbabeldict/Makefile.am
new file mode 100644
index 00000000..3720988f
--- /dev/null
+++ b/kbabel/kbabeldict/Makefile.am
@@ -0,0 +1,66 @@
+## Makefile.am for kbabeldict
+
+# this has all of the subdirectories that make will recurse into. if
+# there are none, comment this out
+SUBDIRS = . modules
+
+pkgincludedir = $(includedir)/kbabel
+
+# this is the program that gets installed. it's name is used for all
+# of the other Makefile.am variables
+noinst_LTLIBRARIES = libkbabeldict.la
+bin_PROGRAMS = kbabeldict
+
+# set the include path for X, qt and KDE
+INCLUDES = -I$(srcdir)/../common -I$(top_builddir)/kbabel/common $(all_includes)
+
+
+# library for babeldict plugins
+lib_LTLIBRARIES = libkbabeldictplugin.la
+libkbabeldictplugin_la_SOURCES = searchengine.cpp
+libkbabeldictplugin_la_LIBADD = $(LIB_KDECORE)
+libkbabeldictplugin_la_LDFLAGS = -version-info 3:0:2 $(all_libraries)
+
+libkbabeldict_la_SOURCES = kbabeldictbox.cpp \
+ kbabeldictiface.skel dictionarymenu.cpp dictchooser.cpp \
+ aboutmoduledlg.cpp
+libkbabeldict_la_LIBADD = ../common/libkbabelcommon.la libkbabeldictplugin.la $(LIB_KDEUI)
+libkbabeldict_la_LDFLAGS = $(all_libraries) -no-undefined
+
+
+kbabeldict_SOURCES = main.cpp kbabeldictview.cpp kbabeldict.cpp kbabelsplash.cpp
+
+# the libraries to link against.
+kbabeldict_LDADD = libkbabeldict.la
+kbabeldict_LDFLAGS = $(all_libraries) $(KDE_RPATH)
+
+# these are the headers for your project
+noinst_HEADERS = kbabeldict.h kbabeldictview.h kbabelsplash.h aboutmoduledlg.h
+pkginclude_HEADERS = searchengine.h kbabeldictbox.h kbabeldictiface.h \
+dictionarymenu.h dictchooser.h
+
+
+# let automoc handle all of the meta source files (moc)
+METASOURCES = AUTO
+
+KDE_OPTIONS = nofinal
+#rcdir = $(kde_datadir)/kbabel
+#rc_DATA = kbabelui.rc
+
+api:
+ mkdir -p API && kdoc -d API -u $$PWD/API -p -lkdeui -lkdecore -lqt -ldcop *.h
+
+distclean-local:
+ rm -r -f API
+
+KDE_ICON = kbabeldict
+
+ # this is where the kdelnk file will go
+xdg_apps_DATA = kbabeldict.desktop
+
+kde_servicetypes_DATA = kbabeldict_module.desktop
+EXTRA_DIST = $(kde_servicetypes_DATA)
+
+kbabeldictbox.lo: ../common/version.h
+main.o: ../common/version.h
+
diff --git a/kbabel/kbabeldict/README b/kbabel/kbabeldict/README
new file mode 100644
index 00000000..9a4eb950
--- /dev/null
+++ b/kbabel/kbabeldict/README
@@ -0,0 +1,5 @@
+This directory contains a standalone application to search for translations
+as you can do in KBabel and the framework for loading plugins for
+searching in different types of translation sources. This way
+KBabel can be easily extended. For more information about
+developing a search module for KBabel see file README.modules
diff --git a/kbabel/kbabeldict/README.modules b/kbabel/kbabeldict/README.modules
new file mode 100644
index 00000000..a672743b
--- /dev/null
+++ b/kbabel/kbabeldict/README.modules
@@ -0,0 +1,34 @@
+This directory contains the framework for KBabel to be easily extensible with
+plugins for searching translations.
+
+For an examples of modules see subdirectory "modules".
+
+
+Here is a short description, how to write an module:
+
+First off all, the module must inherit the interface class SearchEngine and
+has to implement all the virtual functions in there. Also a preferences
+widget must be available, that has to inherit from PrefWidget.
+Just include searchengine.h to have everything necessary available.
+
+Then you module has to be compiled as shared library and there must be a
+factory available, so that it can be loaded with KLibLoader. See
+documentation of KLibLoader for more details. The library should be prefixed
+by "kbabeldict_" instead of more common "lib". This is to indicate that it is
+a module for KBabelDict.
+
+The method of dictionary loading has changed in KBabel 1.2, but the
+modules for previous versions should work. Here is how to install
+the dictionary: You should define a standard KDE service desktop file.
+The most important entry is
+
+X-KDE-Library=<libname>
+
+where <libname> is the name of the shared library, that contains your
+SearchEngine, for example "kbabeldict_pocompendium".
+Additionally you can add a list of applications, to them your module is
+restricted to with "Applications=<list>". For example with "Applications=kbabel",
+your module will only be used in KBabel. If you omit the entry, the
+module can be used in any application.
+
+
diff --git a/kbabel/kbabeldict/aboutmoduledlg.cpp b/kbabel/kbabeldict/aboutmoduledlg.cpp
new file mode 100644
index 00000000..eaab8b3b
--- /dev/null
+++ b/kbabel/kbabeldict/aboutmoduledlg.cpp
@@ -0,0 +1,54 @@
+/* ****************************************************************************
+ This file is part of KBabel
+
+ Copyright (C) 1999-2001 by Matthias Kiefer
+ <matthias.kiefer@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.
+
+ 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, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+ In addition, as a special exception, the copyright holders give
+ permission to link the code of this program with any edition of
+ the Qt library by Trolltech AS, Norway (or with modified versions
+ of Qt that use the same license as Qt), and distribute linked
+ combinations including the two. You must obey the GNU General
+ Public License in all respects for all of the code used other than
+ Qt. If you modify this file, you may extend this exception to
+ your version of the file, but you are not obligated to do so. If
+ you do not wish to do so, delete this exception statement from
+ your version.
+
+**************************************************************************** */
+#include "aboutmoduledlg.h"
+
+#include <kbugreport.h>
+#include <klocale.h>
+
+AboutModuleDlg::AboutModuleDlg(const KAboutData *aboutData, QWidget *parent)
+ : KAboutApplication(aboutData, parent)
+ , _aboutData(aboutData)
+{
+ setHelpLinkText(i18n("Report Bug..."));
+ enableLinkedHelp(true);
+}
+
+void AboutModuleDlg::helpClickedSlot(const QString&)
+{
+ KBugReport *bugReport = new KBugReport(0,true,_aboutData);
+
+ bugReport->exec();
+
+ delete bugReport;
+}
+#include "aboutmoduledlg.moc"
diff --git a/kbabel/kbabeldict/aboutmoduledlg.h b/kbabel/kbabeldict/aboutmoduledlg.h
new file mode 100644
index 00000000..f79d77ec
--- /dev/null
+++ b/kbabel/kbabeldict/aboutmoduledlg.h
@@ -0,0 +1,55 @@
+/* ****************************************************************************
+ This file is part of KBabel
+
+ Copyright (C) 1999-2001 by Matthias Kiefer
+ <matthias.kiefer@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.
+
+ 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, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+ In addition, as a special exception, the copyright holders give
+ permission to link the code of this program with any edition of
+ the Qt library by Trolltech AS, Norway (or with modified versions
+ of Qt that use the same license as Qt), and distribute linked
+ combinations including the two. You must obey the GNU General
+ Public License in all respects for all of the code used other than
+ Qt. If you modify this file, you may extend this exception to
+ your version of the file, but you are not obligated to do so. If
+ you do not wish to do so, delete this exception statement from
+ your version.
+
+**************************************************************************** */
+
+
+#ifndef ABOUTMODULEDLG_H
+#define ABOUTMODULEDLG_H
+
+#include <kaboutapplication.h>
+
+
+class AboutModuleDlg : public KAboutApplication
+{
+ Q_OBJECT
+
+public:
+ AboutModuleDlg(const KAboutData *aboutData, QWidget* parent=0);
+
+public slots:
+ virtual void helpClickedSlot(const QString&);
+
+private:
+ const KAboutData *_aboutData;
+};
+
+#endif
diff --git a/kbabel/kbabeldict/dictchooser.cpp b/kbabel/kbabeldict/dictchooser.cpp
new file mode 100644
index 00000000..f9360b61
--- /dev/null
+++ b/kbabel/kbabeldict/dictchooser.cpp
@@ -0,0 +1,335 @@
+/* ****************************************************************************
+ This file is part of KBabel
+
+ Copyright (C) 1999-2001 by Matthias Kiefer
+ <matthias.kiefer@gmx.de>
+ 2003 by Stanislav Visnovsky
+ <visnovsky@kde.org>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the 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, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+ In addition, as a special exception, the copyright holders give
+ permission to link the code of this program with any edition of
+ the Qt library by Trolltech AS, Norway (or with modified versions
+ of Qt that use the same license as Qt), and distribute linked
+ combinations including the two. You must obey the GNU General
+ Public License in all respects for all of the code used other than
+ Qt. If you modify this file, you may extend this exception to
+ your version of the file, but you are not obligated to do so. If
+ you do not wish to do so, delete this exception statement from
+ your version.
+
+**************************************************************************** */
+#include "dictchooser.h"
+#include "resources.h"
+
+#include <qlabel.h>
+#include <qlayout.h>
+#include <qpushbutton.h>
+#include <kconfig.h>
+#include <klistbox.h>
+#include <klocale.h>
+#include <kdialog.h>
+#include <ktempfile.h>
+
+DictChooser::DictChooser(KBabelDictBox*b, QStringList selected
+ , QWidget *parent, const char *name)
+ : QWidget(parent,name), box(b)
+{
+ tempConfig.clear();
+ tempConfig.setAutoDelete(true);
+
+ dictList = box->moduleInfos();
+ QGridLayout *layout = new QGridLayout(this);
+ layout->setSpacing(KDialog::spacingHint());
+
+
+ QLabel *label = new QLabel(i18n("dictionary to not use","Do not use:"),this);
+ layout->addWidget(label,0,0);
+
+ label = new QLabel(i18n("dictionary to use","Use:"),this);
+ layout->addWidget(label,0,2);
+
+ unselectedBox = new KListBox(this,"unselectedBox");
+ layout->addWidget(unselectedBox,1,0);
+
+
+ QVBoxLayout *bLayout = new QVBoxLayout();
+ selectBtn = new QPushButton(" &>> ", this);
+ selectBtn->setEnabled(false);
+ bLayout->addWidget(selectBtn);
+ unselectBtn = new QPushButton(" &<< ", this);
+ unselectBtn->setEnabled(false);
+ bLayout->addWidget(unselectBtn);
+ bLayout->addStretch();
+ layout->addLayout(bLayout,1,1);
+
+ selectedBox = new KListBox(this,"selectedBox");
+ layout->addWidget(selectedBox,1,2);
+
+
+ bLayout = new QVBoxLayout();
+ upBtn = new QPushButton(i18n("Move &Up"), this);
+ upBtn->setEnabled(false);
+ bLayout->addWidget(upBtn);
+ downBtn = new QPushButton(i18n("Move &Down"), this);
+ downBtn->setEnabled(false);
+ bLayout->addWidget(downBtn);
+ configureBtn = new QPushButton(i18n("Con&figure..."), this);
+ bLayout->addWidget(configureBtn);
+ bLayout->addStretch();
+ layout->addLayout(bLayout,1,3);
+
+
+ dictList.setAutoDelete(true);
+ ModuleInfo *mi;
+ for(QStringList::Iterator it=selected.begin(); it!=selected.end();
+ ++it)
+ {
+ for(mi = dictList.first(); mi != 0; mi = dictList.next())
+ {
+ if(mi->id==*it)
+ {
+ selectedBox->insertItem(mi->name);
+ }
+ }
+ }
+
+ for(mi = dictList.first(); mi != 0; mi = dictList.next())
+ {
+ if(!selected.contains(mi->id))
+ {
+ unselectedBox->insertItem(mi->name);
+ }
+ }
+
+ if(selectedBox->count() == 0 && unselectedBox->count() > 0)
+ {
+ selectedBox->insertItem(unselectedBox->text(0));
+ unselectedBox->removeItem(0);
+ }
+
+
+ connect(selectedBox,SIGNAL(highlighted(int)), this
+ , SLOT(selectedMarked(int)));
+ connect(unselectedBox,SIGNAL(highlighted(int)), this
+ , SLOT(unselectedMarked(int)));
+
+ connect(selectBtn, SIGNAL(clicked()), this, SLOT(select()));
+ connect(unselectBtn, SIGNAL(clicked()), this, SLOT(unselect()));
+ connect(upBtn, SIGNAL(clicked()), this, SLOT(up()));
+ connect(downBtn, SIGNAL(clicked()), this, SLOT(down()));
+ connect(configureBtn,SIGNAL(clicked()), this
+ , SLOT(configureSelected()));
+
+
+ selectedBox->installEventFilter(this);
+ unselectedBox->installEventFilter(this);
+
+ int min = minimumHeight();
+ if(min < 100)
+ setMinimumHeight(100);
+}
+
+
+QStringList DictChooser::selectedDicts()
+{
+ QStringList selected;
+
+ for(int i = 0; i < (int)selectedBox->count(); i++)
+ {
+ QString text = selectedBox->text(i);
+
+ ModuleInfo *mi;
+ for(mi = dictList.first(); mi!=0; mi = dictList.next())
+ {
+ if(mi->name == text)
+ {
+ selected.append(mi->id);
+ }
+ }
+ }
+
+ return selected;
+}
+
+
+void DictChooser::selectedMarked(int index)
+{
+ unselectedBox->selectAll(false);
+
+ unselectBtn->setEnabled(selectedBox->count() > 1);
+ selectBtn->setEnabled(false);
+ downBtn->setEnabled((int)selectedBox->count()-1 > index);
+ upBtn->setEnabled(index > (int)0);
+}
+
+void DictChooser::unselectedMarked(int)
+{
+ selectedBox->selectAll(false);
+
+ selectBtn->setEnabled(true);
+ unselectBtn->setEnabled(false);
+ downBtn->setEnabled(false);
+ upBtn->setEnabled(false);
+}
+
+
+void DictChooser::select()
+{
+ int i = unselectedBox->currentItem();
+ if(i >= 0)
+ {
+ QString text = unselectedBox->text(i);
+ selectedBox->insertItem(text);
+
+ unselectedBox->removeItem(i);
+
+ if(unselectedBox->count() == 0)
+ {
+ selectBtn->setEnabled(false);
+ }
+ else
+ {
+ unselectedBox->setSelected(i,true);
+ }
+ }
+}
+
+
+void DictChooser::unselect()
+{
+ int i = selectedBox->currentItem();
+ if(i >= 0 && selectedBox->count() > 1)
+ {
+ QString text = selectedBox->text(i);
+ unselectedBox->insertItem(text);
+
+ selectedBox->removeItem(i);
+
+ if(i < (int)selectedBox->count()-1)
+ {
+ selectedBox->setSelected(i,true);
+ }
+ else
+ {
+ selectedBox->setSelected(i-1,true);
+ }
+ }
+}
+
+
+void DictChooser::up()
+{
+ int i = selectedBox->currentItem();
+ if(i > 0)
+ {
+ QString text = selectedBox->text(i);
+ selectedBox->changeItem(selectedBox->text(i-1),i);
+ selectedBox->changeItem(text,i-1);
+ selectedBox->setSelected(i-1,true);
+ }
+}
+
+
+void DictChooser::down()
+{
+ int i = selectedBox->currentItem();
+ if(i < (int)selectedBox->count()-1)
+ {
+ QString text = selectedBox->text(i);
+ selectedBox->changeItem(selectedBox->text(i+1),i);
+ selectedBox->changeItem(text,i+1);
+ selectedBox->setSelected(i+1,true);
+ }
+}
+
+
+bool DictChooser::eventFilter(QObject *object, QEvent *event)
+{
+ if(event->type() == QEvent::FocusIn)
+ {
+ if(object==selectedBox)
+ {
+ int i = selectedBox->currentItem();
+ selectedBox->setSelected(i,true);
+ selectedMarked(i);
+ unselectedBox->clearSelection();
+ }
+ else
+ {
+ int i = unselectedBox->currentItem();
+ if(i >= 0)
+ {
+ unselectedBox->setSelected(i,true);
+ unselectedMarked(i);
+ selectedBox->clearSelection();
+ }
+ }
+
+ return true;
+ }
+
+ return false;
+}
+
+void DictChooser::configureSelected()
+{
+ int ci = selectedBox->currentItem();
+ if( ci == -1 ) ci = 0; // there is always at least one item
+ QString module = selectedBox->text(ci);
+
+ ModuleInfo *mi;
+ for(mi = dictList.first(); mi!=0; mi = dictList.next())
+ {
+ if(mi->name == module)
+ {
+ // do backup first
+ if( !tempConfig[mi->id])
+ {
+ KTempFile* tmp=new KTempFile();
+ tmp->setAutoDelete(true);
+ tempConfig.insert(mi->id ,tmp);
+
+ kdDebug(KBABEL_SEARCH) << "Temp file: " << tmp->name() << endl;
+ KConfig config(tmp->name());
+ config.setGroup(mi->id);
+ box->saveSettings(mi->id, &config);
+ }
+
+ // now let user change configuration
+ box->configure(mi->id,true);
+ break;
+ }
+ }
+}
+
+void DictChooser::restoreConfig()
+{
+ kdDebug( KBABEL_SEARCH ) << "Cleanup" << endl;
+ // cleanup
+ QDictIterator<KTempFile> it( tempConfig ); // See QDictIterator
+ for( ; it.current(); ++it )
+ {
+ KConfig config( it.current()->name() );
+ config.setGroup( it.currentKey() );
+ box->readSettings( it.currentKey(), &config);
+ }
+
+ // there is no temporary configs
+ tempConfig.clear();
+}
+
+#include "dictchooser.moc"
diff --git a/kbabel/kbabeldict/dictchooser.h b/kbabel/kbabeldict/dictchooser.h
new file mode 100644
index 00000000..2b757455
--- /dev/null
+++ b/kbabel/kbabeldict/dictchooser.h
@@ -0,0 +1,94 @@
+/* ****************************************************************************
+ This file is part of KBabel
+
+ Copyright (C) 1999-2001 by Matthias Kiefer
+ <matthias.kiefer@gmx.de>
+ 2003 by Stanislav Visnovsky
+ <visnovsky@kde.org>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the 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, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+ In addition, as a special exception, the copyright holders give
+ permission to link the code of this program with any edition of
+ the Qt library by Trolltech AS, Norway (or with modified versions
+ of Qt that use the same license as Qt), and distribute linked
+ combinations including the two. You must obey the GNU General
+ Public License in all respects for all of the code used other than
+ Qt. If you modify this file, you may extend this exception to
+ your version of the file, but you are not obligated to do so. If
+ you do not wish to do so, delete this exception statement from
+ your version.
+
+**************************************************************************** */
+#ifndef DICTCHOOSER_H
+#define DICTCHOOSER_H
+
+#include <qptrlist.h>
+#include <qstringlist.h>
+#include <qwidget.h>
+#include <kbabeldictbox.h>
+
+class KListBox;
+class KTempFile;
+
+class QPushButton;
+class QListBoxItem;
+
+
+class KDE_EXPORT DictChooser : public QWidget
+{
+ Q_OBJECT
+
+public:
+ DictChooser(KBabelDictBox* box, QStringList selected,
+ QWidget *parent , const char *name=0);
+
+ QStringList selectedDicts();
+
+ /** If the user configured some of the modules, this
+ * restores the original configuration of all these modules
+ */
+ void restoreConfig();
+
+ virtual bool eventFilter(QObject *, QEvent *);
+
+private slots:
+ void select();
+ void unselect();
+ void up();
+ void down();
+
+ void selectedMarked(int);
+ void unselectedMarked(int);
+
+ void configureSelected();
+
+private:
+ KBabelDictBox* box;
+ QPtrList<ModuleInfo> dictList;
+
+ KListBox *selectedBox;
+ KListBox *unselectedBox;
+
+ QPushButton *selectBtn;
+ QPushButton *unselectBtn;
+ QPushButton *upBtn;
+ QPushButton *downBtn;
+ QPushButton *configureBtn;
+
+ QDict<KTempFile> tempConfig;
+};
+
+#endif // DICTCHOOSER_H
diff --git a/kbabel/kbabeldict/dictionarymenu.cpp b/kbabel/kbabeldict/dictionarymenu.cpp
new file mode 100644
index 00000000..2ed57d5f
--- /dev/null
+++ b/kbabel/kbabeldict/dictionarymenu.cpp
@@ -0,0 +1,154 @@
+/* ****************************************************************************
+ This file is part of KBabel
+
+ Copyright (C) 2000 by Matthias Kiefer
+ <matthias.kiefer@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.
+
+ 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, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+ In addition, as a special exception, the copyright holders give
+ permission to link the code of this program with any edition of
+ the Qt library by Trolltech AS, Norway (or with modified versions
+ of Qt that use the same license as Qt), and distribute linked
+ combinations including the two. You must obey the GNU General
+ Public License in all respects for all of the code used other than
+ Qt. If you modify this file, you may extend this exception to
+ your version of the file, but you are not obligated to do so. If
+ you do not wish to do so, delete this exception statement from
+ your version.
+
+**************************************************************************** */
+#include "dictionarymenu.h"
+#include <kpopupmenu.h>
+#include <kaction.h>
+#include <kdebug.h>
+#include <kshortcut.h>
+
+#include <qsignalmapper.h>
+
+DictionaryMenu::DictionaryMenu(KPopupMenu *popupMenu, KActionCollection *collection
+ , QObject *parent)
+ : QObject(parent, "dictionarymenu")
+ , popup(popupMenu)
+ , actionCollection(collection)
+ , maxId(10)
+{
+ num2id.setAutoDelete(true);
+ accel2id.setAutoDelete(true);
+
+ if(popup)
+ {
+ connect(popup,SIGNAL(activated(int)),this,SLOT(activated(int)));
+ }
+
+ dictionaryMapper = new QSignalMapper( this );
+ connect( dictionaryMapper, SIGNAL( mapped( int ) ),
+ this, SLOT( activated( int ) ) );
+
+}
+
+DictionaryMenu::~DictionaryMenu()
+{
+ clear();
+}
+
+void DictionaryMenu::clear()
+{
+ if(popup)
+ {
+ QIntDictIterator<QString> it( num2id ); // iterator for dict
+ while ( it.current() )
+ {
+ popup->removeItem(it.currentKey());
+ ++it;
+ }
+ }
+
+ num2id.clear();
+
+ // create new mapper
+ delete dictionaryMapper;
+ dictionaryMapper = new QSignalMapper( this );
+ connect( dictionaryMapper, SIGNAL( mapped( int ) ),
+ this, SLOT( activated( int ) ) );
+}
+
+void DictionaryMenu::add(const QString& name, const QString& moduleId)
+{
+ if(popup)
+ {
+ KAction* dictionaryAction = new KAction( name, 0, dictionaryMapper, SLOT(map()), actionCollection, moduleId.utf8() );
+
+ uint id = maxId++;
+ dictionaryAction->plug(popup, id);
+
+ dictionaryMapper->setMapping( dictionaryAction, id );
+
+ QString *idString = new QString(moduleId);
+ num2id.insert(id,idString);
+ }
+
+}
+
+void DictionaryMenu::add(const QString& n, const QString& moduleId
+ , const QString& key)
+{
+ if(popup)
+ {
+ QString name=n;
+
+ QString keyString=key;
+ if(keyString.contains("%1"))
+ {
+ keyString=key.arg(accel2id.count()+1);
+ }
+ KShortcut k(keyString);
+
+ KAction* dictionaryAction = new KAction( name, k, dictionaryMapper, SLOT(map()), actionCollection, key.arg(moduleId).utf8() );
+ uint id = maxId++;
+ dictionaryAction->plug(popup,id);
+
+ if(!k.isNull())
+ {
+ QString *idString = new QString(moduleId);
+ accel2id.insert(id,idString);
+
+ dictionaryMapper->setMapping( dictionaryAction, id );
+
+ name+='\t';
+ name+=k.toString();
+ }
+ else
+ {
+ kdWarning() << "key not valid" << endl;
+ }
+
+ QString *idString = new QString(moduleId);
+ num2id.insert(id,idString);
+ }
+}
+
+
+void DictionaryMenu::activated(int id)
+{
+ QString *idString = num2id[id];
+
+ if(idString)
+ {
+ emit activated(*idString);
+ }
+}
+
+#include "dictionarymenu.moc"
diff --git a/kbabel/kbabeldict/dictionarymenu.h b/kbabel/kbabeldict/dictionarymenu.h
new file mode 100644
index 00000000..c688508e
--- /dev/null
+++ b/kbabel/kbabeldict/dictionarymenu.h
@@ -0,0 +1,81 @@
+/* ****************************************************************************
+ This file is part of KBabel
+
+ Copyright (C) 2000 by Matthias Kiefer
+ <matthias.kiefer@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.
+
+ 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, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+ In addition, as a special exception, the copyright holders give
+ permission to link the code of this program with any edition of
+ the Qt library by Trolltech AS, Norway (or with modified versions
+ of Qt that use the same license as Qt), and distribute linked
+ combinations including the two. You must obey the GNU General
+ Public License in all respects for all of the code used other than
+ Qt. If you modify this file, you may extend this exception to
+ your version of the file, but you are not obligated to do so. If
+ you do not wish to do so, delete this exception statement from
+ your version.
+
+**************************************************************************** */
+#ifndef DICTIONARYMENU_H
+#define DICTIONARYMENU_H
+
+#include <qintdict.h>
+#include <qobject.h>
+#include <qstringlist.h>
+#include <qguardedptr.h>
+#include <kdemacros.h>
+
+class QSignalMapper;
+class KPopupMenu;
+class KActionCollection;
+
+class KDE_EXPORT DictionaryMenu : public QObject
+{
+ Q_OBJECT
+
+public:
+ DictionaryMenu(KPopupMenu *menu, KActionCollection *collection, QObject *parent=0);
+ ~DictionaryMenu();
+
+ void add(const QString& name,const QString& id);
+
+ /**
+ * Adds an item to this menu and to the keyboard accelerator.
+ * If key contains %1 it is replaced with a number 1-9
+ */
+ void add(const QString& name,const QString& id, const QString& key);
+
+ void clear();
+
+signals:
+ void activated(const QString moduleId);
+
+private slots:
+ void activated(int);
+
+private:
+ QGuardedPtr<KPopupMenu> popup;
+ QGuardedPtr<KActionCollection> actionCollection;
+ QIntDict<QString> num2id;
+ QIntDict<QString> accel2id;
+ QSignalMapper* dictionaryMapper;
+
+ uint maxId;
+};
+
+#endif
+
diff --git a/kbabel/kbabeldict/hi16-app-kbabeldict.png b/kbabel/kbabeldict/hi16-app-kbabeldict.png
new file mode 100644
index 00000000..eedcb0c1
--- /dev/null
+++ b/kbabel/kbabeldict/hi16-app-kbabeldict.png
Binary files differ
diff --git a/kbabel/kbabeldict/hi32-app-kbabeldict.png b/kbabel/kbabeldict/hi32-app-kbabeldict.png
new file mode 100644
index 00000000..d6d23a0a
--- /dev/null
+++ b/kbabel/kbabeldict/hi32-app-kbabeldict.png
Binary files differ
diff --git a/kbabel/kbabeldict/hi48-app-kbabeldict.png b/kbabel/kbabeldict/hi48-app-kbabeldict.png
new file mode 100644
index 00000000..75eb285b
--- /dev/null
+++ b/kbabel/kbabeldict/hi48-app-kbabeldict.png
Binary files differ
diff --git a/kbabel/kbabeldict/kbabeldict.cpp b/kbabel/kbabeldict/kbabeldict.cpp
new file mode 100644
index 00000000..ebb68227
--- /dev/null
+++ b/kbabel/kbabeldict/kbabeldict.cpp
@@ -0,0 +1,113 @@
+/* ****************************************************************************
+ This file is part of KBabel
+
+ Copyright (C) 2000 by Matthias Kiefer
+ <matthias.kiefer@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.
+
+ 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, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+ In addition, as a special exception, the copyright holders give
+ permission to link the code of this program with any edition of
+ the Qt library by Trolltech AS, Norway (or with modified versions
+ of Qt that use the same license as Qt), and distribute linked
+ combinations including the two. You must obey the GNU General
+ Public License in all respects for all of the code used other than
+ Qt. If you modify this file, you may extend this exception to
+ your version of the file, but you are not obligated to do so. If
+ you do not wish to do so, delete this exception statement from
+ your version.
+
+**************************************************************************** */
+
+
+#include <kapplication.h>
+#include <kconfig.h>
+#include <kglobal.h>
+#include <klocale.h>
+#include "kbabeldict.h"
+#include "kbabeldictview.h"
+
+#include <kdebug.h>
+
+KBabelDict::KBabelDict()
+ : KDialogBase(0,"kbabeldictmain",false,i18n("KBabelDict")
+ , Close|Help|User1|User2|User3|Ok, Ok, true
+ , i18n("About"), i18n("About Module")
+ , i18n("Hide Sett&ings"))
+{
+ connect(this, SIGNAL(closeClicked()),this,SLOT(saveConfig()));
+ connect(this, SIGNAL(closeClicked()),this,SLOT(quit()));
+
+ view = new KBabelDictView(this);
+ connect(this, SIGNAL(user1Clicked()), view, SLOT(about()));
+ connect(this, SIGNAL(user2Clicked()), view, SLOT(aboutModule()));
+ connect(this, SIGNAL(user3Clicked()), this, SLOT(togglePref()));
+
+ // HACK: hide default button, otherwise it would be Help button
+ showButtonOK(false);
+
+ // KBabelDict has not a separate help file, so point to the correct part of the KBabel documentation
+ setHelp( "using-kbabeldict", "kbabel" );
+
+ setMainWidget(view);
+
+ readConfig();
+}
+
+KBabelDict::~KBabelDict()
+{
+ delete(view);
+}
+
+void KBabelDict::saveConfig()
+{
+ KConfig *config=KGlobal::config();
+ KConfigGroupSaver gs(config,"KBabelDict");
+ config->writeEntry("Preferences",view->prefVisible());
+}
+
+void KBabelDict::readConfig()
+{
+ KConfig *config=KGlobal::config();
+ KConfigGroupSaver gs(config,"KBabelDict");
+ bool pref=config->readBoolEntry("Preferences",true);
+
+ if(view->prefVisible() != pref)
+ {
+ togglePref();
+ }
+}
+
+void KBabelDict::quit()
+{
+ kapp->quit();
+}
+
+void KBabelDict::togglePref()
+{
+ view->togglePref();
+
+ if(view->prefVisible())
+ {
+ setButtonText(User3,i18n("Hide Sett&ings"));
+ }
+ else
+ {
+ setButtonText(User3,i18n("Show Sett&ings"));
+ }
+}
+
+
+#include "kbabeldict.moc"
diff --git a/kbabel/kbabeldict/kbabeldict.desktop b/kbabel/kbabeldict/kbabeldict.desktop
new file mode 100644
index 00000000..21b60a04
--- /dev/null
+++ b/kbabel/kbabeldict/kbabeldict.desktop
@@ -0,0 +1,96 @@
+[Desktop Entry]
+Name=KBabel Dictionary
+Name[bg]=Речник - KBabel
+Name[br]=Geriadur KBabel
+Name[ca]=Diccionari de KBabel
+Name[cs]=Slovník (KBabel)
+Name[da]=KBabel ordbog
+Name[de]=KBabel-Wörterbuch
+Name[el]=Λεξικό του KBabel
+Name[eo]=Babelo-vortaro
+Name[es]=Diccionario de KBabel
+Name[et]=Sõnaraamat
+Name[eu]=KBabel hiztegia
+Name[fa]=واژه‌نامۀKBabel
+Name[fi]=KBabel-sanakirja
+Name[fr]=Dictionnaire de KBabel
+Name[ga]=Foclóir KBabel
+Name[gl]=Dicionario de KBabel
+Name[he]=KBabel - מילון
+Name[hu]=KBabel szótár
+Name[is]=KBabel orðabók
+Name[it]=Dizionario di KBabel
+Name[ja]=KBabel 辞書
+Name[ka]=KBabel ლექსიკáƒáƒœáƒ˜
+Name[kk]=KBabel Ñөздігі
+Name[lt]=KBabel žodynas
+Name[nb]=KBabel-ordbok
+Name[nds]=KBabel-Wöörbook
+Name[ne]=केबà¥à¤¯à¤¾à¤¬à¤² शबà¥à¤¦à¤•à¥‹à¤¶
+Name[nl]=KBabel woordenboek
+Name[nn]=KBabel-ordbok
+Name[pa]=ਕੇਬਬੇਲ ਸ਼ਬਦ-ਕੋਸ਼
+Name[pl]=SÅ‚ownik programu KBabel
+Name[pt]=Dicionário do KBabel
+Name[pt_BR]=Dicionário do KBabel
+Name[ru]=KBabel - Словарь
+Name[sk]=KBabel slovník
+Name[sl]=Slovar za KBabel
+Name[sr]=KBabel-ов Речник
+Name[sr@Latn]=KBabel-ov ReÄnik
+Name[sv]=Kbabel ordlista
+Name[tr]=KBabel Sözlüğü
+Name[uk]=Словник KBabel
+Name[zh_CN]=KBabel è¯å…¸
+Name[zh_TW]=KBabel å­—å…¸
+GenericName=Translation Tool Dictionary
+GenericName[bg]=Речник за инÑтрумента за превод
+GenericName[br]=Geriaoueg an ostilh troidigezh
+GenericName[ca]=Diccionari de l'eina de traducció
+GenericName[cs]=Překladový slovník
+GenericName[da]=Ordbog til oversættelsesværktøj
+GenericName[de]=Wörterbuch für Übersetzungsprogramm
+GenericName[el]=Λεξικό εÏγαλείου μετάφÏασης
+GenericName[eo]=Tradukila Vortaro
+GenericName[es]=Diccionario de la herramienta de traducción
+GenericName[et]=KBabel'i sõnaraamat
+GenericName[eu]=Itzulpen tresnen hiztegia
+GenericName[fa]=واژه‌نامۀ ابزار ترجمه
+GenericName[fi]=Käännöstyökalun sanakirja
+GenericName[fr]=Dictionnaire d'un outil de traduction
+GenericName[ga]=Uirlis Aistriúcháin - Foclóir
+GenericName[gl]=Dicionario da ferramenta de tradución
+GenericName[he]=מילון של כלי תרגו×
+GenericName[hu]=Fordítássegítő szótár
+GenericName[is]=Þýðingaforrit orðabók
+GenericName[it]=Dizionario di uno strumento di traduzione
+GenericName[ja]=翻訳ツール辞書
+GenericName[ka]=თáƒáƒ áƒ’მნის ხელსáƒáƒ¬áƒ§áƒáƒ¡ ლექსიკáƒáƒœáƒ˜
+GenericName[kk]=Ðудару құралының Ñөздігі
+GenericName[lt]=Vertimo įrankio žodynas
+GenericName[nb]=Ordbok for oversettingsverktøy
+GenericName[nds]=Översettenwarktüüch-Wöörbook
+GenericName[ne]=अनà¥à¤¬à¤¾à¤¦ उपकरण शबà¥à¤¦à¤•à¥‹à¤¶
+GenericName[nl]=Vertaalhulpmiddel woordenboek
+GenericName[nn]=Ordbok for omsetjingsverktøy
+GenericName[pa]=ਅਨà©à¨µà¨¾à¨¦ ਸੰਦ ਲਈ ਸ਼ਬਦ-ਕੋਸ਼
+GenericName[pl]=Słownik do narzędzia tłumaczy
+GenericName[pt]=Dicionário da Ferramenta de Tradução
+GenericName[pt_BR]=Dicionário da Ferramenta de Tradução
+GenericName[ru]=ПоиÑк в готовых переводах
+GenericName[sk]=Slovník pre prekladací nástroj
+GenericName[sl]=Slovar orodja za prevajanje
+GenericName[sr]=Речник преводилачких алата
+GenericName[sr@Latn]=ReÄnik prevodilaÄkih alata
+GenericName[sv]=Översättningsverktyg ordlista
+GenericName[tr]=Çeviri Aracı Sözlüğü
+GenericName[uk]=Словник заÑобу Ð´Ð»Ñ Ð¿ÐµÑ€ÐµÐºÐ»Ð°Ð´Ñ–Ð²
+GenericName[zh_CN]=翻译工具è¯å…¸
+GenericName[zh_TW]=翻譯工具字典
+Exec=kbabeldict %i %m -caption "%c"
+Icon=kbabeldict
+Type=Application
+Terminal=false
+X-KDE-StartupNotify=true
+X-DCOP-ServiceType=Unique
+Categories=Qt;KDE;Development;Translation;
diff --git a/kbabel/kbabeldict/kbabeldict.h b/kbabel/kbabeldict/kbabeldict.h
new file mode 100644
index 00000000..3bfca817
--- /dev/null
+++ b/kbabel/kbabeldict/kbabeldict.h
@@ -0,0 +1,62 @@
+/* ****************************************************************************
+ This file is part of KBabel
+
+ Copyright (C) 2000 by Matthias Kiefer
+ <matthias.kiefer@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.
+
+ 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, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+ In addition, as a special exception, the copyright holders give
+ permission to link the code of this program with any edition of
+ the Qt library by Trolltech AS, Norway (or with modified versions
+ of Qt that use the same license as Qt), and distribute linked
+ combinations including the two. You must obey the GNU General
+ Public License in all respects for all of the code used other than
+ Qt. If you modify this file, you may extend this exception to
+ your version of the file, but you are not obligated to do so. If
+ you do not wish to do so, delete this exception statement from
+ your version.
+
+**************************************************************************** */
+
+
+#ifndef KBABELDICT_H
+#define KBABELDICT_H
+
+#include <kdialogbase.h>
+
+class KBabelDictView;
+
+class KBabelDict : public KDialogBase
+{
+ Q_OBJECT
+
+public:
+ KBabelDict();
+ ~KBabelDict();
+
+protected slots:
+ void saveConfig();
+ void quit();
+ void togglePref();
+
+protected:
+ void readConfig();
+
+private:
+ KBabelDictView *view;
+};
+
+#endif
diff --git a/kbabel/kbabeldict/kbabeldict_module.desktop b/kbabel/kbabeldict/kbabeldict_module.desktop
new file mode 100644
index 00000000..c5a019d1
--- /dev/null
+++ b/kbabel/kbabeldict/kbabeldict_module.desktop
@@ -0,0 +1,54 @@
+[Desktop Entry]
+Type=ServiceType
+X-KDE-ServiceType=KBabelDictModule
+Comment=Dictionary module for KBabelDict
+Comment[bg]=Речников модул за KBabelDict
+Comment[br]=Mollad geriaoueg evit KBabelDict
+Comment[bs]=RjeÄniÄki modul za KBabelDict
+Comment[ca]=Mòdul de diccionari per a KBabelDict
+Comment[cs]=Modul se slovníkem pro KBabelDict
+Comment[cy]=Modiwl geiriadur i KBabelDict
+Comment[da]=Ordbogsmodul for KBabelDict
+Comment[de]=Wörterbuch-Modul für KBabelDict
+Comment[el]=ΆÏθÏωμα Î»ÎµÎ¾Î¹ÎºÎ¿Ï Î³Î¹Î± το KBabelDict
+Comment[es]=Módulo de diccionario para KBabelDict
+Comment[et]=KBabelDicti sõnaraamatumoodul
+Comment[eu]=Hiztegi modulua KBabelDict-entzat
+Comment[fa]=پیمانۀ واژه‌نامه برایKBabelDict
+Comment[fi]=KBabelDict-ohjelman sanakirjamoduuli
+Comment[fr]=Module de dictionnaire pour KBabelDict
+Comment[ga]=Modúl foclóra le haghaidh KBabelDict
+Comment[gl]=Módulo de dicionario para KBabelDict
+Comment[hi]=के-बेबल-डिकà¥à¤¶ के लिठशबà¥à¤¦à¤•à¥‹à¤¶ मॉडà¥à¤¯à¥‚ल
+Comment[hu]=Szótármodul a KBabelDicthez
+Comment[is]=Orðabókareining fyrir KBabel
+Comment[it]=Modulo dizionario per KBabelDict
+Comment[ja]=KBabelDict 辞書モジュール
+Comment[ka]=ლექსიკáƒáƒœáƒ˜áƒ¡ მáƒáƒ“ული KBabelDict-სთვის
+Comment[kk]=KBabelDict-Ñ‚Ñ–Ò£ Ñөздік модулі
+Comment[lt]=KBabelDict žodyno modulis
+Comment[ms]=Modul kamus untuk KBabelDict
+Comment[nb]=Ordboksmodul for KBabelDict
+Comment[nds]=Wöörbookmoduul för KBabelDict
+Comment[ne]=KBabelDict का लागि शबà¥à¤¦à¤•à¥‹à¤¶ मोडà¥à¤¯à¥à¤²
+Comment[nl]=Woordenboekmodule voor KBabelDict
+Comment[nn]=Ordboksmodul for KBabelDict
+Comment[pa]=ਕੇਬਬੇਲ-ਸ਼ਬਦਕੋਸ਼ ਲਈ ਸ਼ਬਦ-ਕੋਸ਼ ਮੈਡੀਊਲ
+Comment[pl]=Moduł słownika dla KBabelDict
+Comment[pt]=Módulo de dicionário para o KBabelDict
+Comment[pt_BR]=Módulo de dicionário para o KBabekDict
+Comment[ru]=Модуль ÑÐ»Ð¾Ð²Ð°Ñ€Ñ Ð´Ð»Ñ KBabelDict
+Comment[sk]=Modul slovníka pre KBabelDict
+Comment[sl]=Slovarski modul za KBabelDict
+Comment[sr]=Модул речника за KBabelDict
+Comment[sr@Latn]=Modul reÄnika za KBabelDict
+Comment[sv]=Ordlistemodul för Kbabeldict
+Comment[ta]= Kபாபேலà¯à®•à¯à®•à®¾à®© அகராதி கூறà¯
+Comment[tg]=Модули луғат барои KBabelDict
+Comment[tr]=KBabelDict için Sözlük Modülü
+Comment[uk]=Модуль Ñловника Ð´Ð»Ñ KBabelDict
+Comment[zh_CN]=KBabelDict çš„è¯å…¸æ¨¡å—
+Comment[zh_TW]=KBabelDict 字典模組
+
+[PropertyDef::Applications]
+Type=QStringList
diff --git a/kbabel/kbabeldict/kbabeldictbox.cpp b/kbabel/kbabeldict/kbabeldictbox.cpp
new file mode 100644
index 00000000..2beed684
--- /dev/null
+++ b/kbabel/kbabeldict/kbabeldictbox.cpp
@@ -0,0 +1,1767 @@
+/* ****************************************************************************
+ This file is part of KBabel
+
+ Copyright (C) 2000 by Matthias Kiefer
+ <matthias.kiefer@gmx.de>
+ 2003-2005 by Stanislav Visnovsky
+ <visnovsky@kde.org>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the 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, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+ In addition, as a special exception, the copyright holders give
+ permission to link the code of this program with any edition of
+ the Qt library by Trolltech AS, Norway (or with modified versions
+ of Qt that use the same license as Qt), and distribute linked
+ combinations including the two. You must obey the GNU General
+ Public License in all respects for all of the code used other than
+ Qt. If you modify this file, you may extend this exception to
+ your version of the file, but you are not obligated to do so. If
+ you do not wish to do so, delete this exception statement from
+ your version.
+
+**************************************************************************** */
+
+
+#include <dcopclient.h>
+#include <kaboutapplication.h>
+
+#include "aboutmoduledlg.h"
+#include "kbabeldictbox.h"
+#include <version.h>
+#include <resources.h>
+
+#include <kaboutdata.h>
+#include <kaboutdialog.h>
+#include <kapplication.h>
+#include <kconfig.h>
+#include <kcmenumngr.h>
+#include <kdialogbase.h>
+#include <klibloader.h>
+#include <klistview.h>
+#include <klocale.h>
+#include <kmessagebox.h>
+#include <kstandarddirs.h>
+#include <kglobal.h>
+#include <kdebug.h>
+#include <ktrader.h>
+#include <kwin.h>
+
+#include <qclipboard.h>
+#include <qdir.h>
+#include <qlabel.h>
+#include <qlayout.h>
+#include <qpopupmenu.h>
+#include <qpushbutton.h>
+#include <qtextview.h>
+#include <qstylesheet.h>
+#include <qtoolbutton.h>
+#include <qwhatsthis.h>
+#include <qtimer.h>
+
+#define KBABELDICT 5321
+
+using namespace KBabel;
+
+class ResultListItem : public QListViewItem
+{
+public:
+ ResultListItem(QListView *parent, const SearchResult& result,bool richText);
+
+ virtual QString key(int column, bool ascending) const;
+ const SearchResult* result() const;
+ bool richText() const { return _richText; }
+
+private:
+ SearchResult _result;
+ bool _richText;
+};
+
+ResultListItem::ResultListItem(QListView *parent, const SearchResult& result
+ , bool richText)
+ : QListViewItem(parent)
+ , _result(result)
+ , _richText(richText)
+{
+ int score=_result.score;
+ if(score<0)
+ score=0;
+ else if(score>100)
+ score=100;
+ setText(0,QString::number(score));
+
+ QString tmp;
+ if(richText)
+ tmp=_result.plainFound;
+ else
+ // FIXME: what about plural forms?
+ tmp=result.found.first();
+
+ bool cutted=false;
+ int index=tmp.find('\n');
+ if(index > 0)
+ {
+ tmp=tmp.left(index);
+ cutted=true;
+ }
+ if(tmp.length() > 30)
+ {
+ tmp=tmp.left(30);
+ cutted=true;
+ }
+ tmp=tmp.stripWhiteSpace();
+ if(cutted)
+ tmp+="...";
+
+ setText(1,tmp);
+
+ if(richText)
+ tmp=_result.plainTranslation;
+ else
+ tmp=result.translation;
+
+ cutted=false;
+ index=tmp.find('\n');
+ if(index > 0)
+ {
+ tmp=tmp.left(index);
+ cutted=true;
+ }
+ if(tmp.length() > 30)
+ {
+ tmp=tmp.left(30);
+ cutted=true;
+ }
+ tmp=tmp.stripWhiteSpace();
+ if(cutted)
+ tmp+="...";
+ setText(2,tmp);
+
+
+ if(!_result.descriptions.isEmpty())
+ {
+ TranslationInfo *ti = _result.descriptions.first();
+ if(ti)
+ {
+ setText(3,ti->location);
+ }
+ }
+
+}
+
+QString ResultListItem::key(int column, bool ascending) const
+{
+ if(column==0)
+ {
+ QString result=QString::number(_result.score);
+ result=result.rightJustify(10,'0');
+
+ return result;
+ }
+
+ return QListViewItem::key(column,ascending);
+}
+
+const SearchResult *ResultListItem::result() const
+{
+ return &_result;
+}
+
+/*
+ * Constructs a KBabelDictBox which is a child of 'parent', with the
+ * name 'name' and widget flags set to 'f'
+ */
+KBabelDictBox::KBabelDictBox( QWidget* parent, const char* name, WFlags fl )
+ : DCOPObject("KBabelDict"), QWidget( parent, name, fl )
+{
+ active=-1;
+ currentResult=0;
+ currentInfo=0;
+ moduleList.setAutoDelete(false);
+
+
+ QVBoxLayout *mainLayout = new QVBoxLayout(this);
+ mainLayout->setMargin(KDialog::marginHint());
+ mainLayout->setSpacing(KDialog::spacingHint());
+
+ QGridLayout *grid = new QGridLayout(mainLayout);
+
+ QHBoxLayout *hbox = new QHBoxLayout;
+ QLabel *label = new QLabel(i18n("Total:"),this);
+ hbox->addWidget(label);
+ totalResultsLabel = new QLabel("0",this);
+ hbox->addWidget(totalResultsLabel);
+ grid->addLayout(hbox,0,0);
+
+ hbox = new QHBoxLayout;
+ label = new QLabel(i18n("Current:"), this);
+ hbox->addWidget(label);
+ currentLabel = new QLabel("0",this);
+ hbox->addWidget(currentLabel);
+ grid->addLayout(hbox,1,0);
+
+
+ hbox = new QHBoxLayout;
+ label = new QLabel(i18n("Found in:"), this);
+ hbox->addWidget(label);
+ locationLabel = new QLabel(this);
+ hbox->addWidget(locationLabel);
+ hbox->setStretchFactor(locationLabel,2);
+ grid->addLayout(hbox,0,1);
+
+ hbox = new QHBoxLayout;
+ label = new QLabel(i18n("Translator:"), this);
+ hbox->addWidget(label);
+ translatorLabel = new QLabel(this);
+ translatorLabel->setMinimumSize(50,0);
+ hbox->addWidget(translatorLabel);
+ hbox->setStretchFactor(translatorLabel,2);
+ grid->addLayout(hbox,1,1);
+
+ grid->setColStretch(1,2);
+
+
+ hbox = new QHBoxLayout;
+ label = new QLabel(i18n("Date:"),this);
+ hbox->addWidget(label);
+ dateLabel = new QLabel(this);
+ dateLabel->setMinimumSize(50,0);
+ hbox->addWidget(dateLabel);
+ hbox->setStretchFactor(dateLabel,2);
+
+ moreButton = new QPushButton(this,"moreButton");
+ moreButton->setText(i18n("&More"));
+ moreButton->setEnabled(false);
+ moreButton->setAutoRepeat(true);
+ hbox->addWidget(moreButton);
+
+ mainLayout->addLayout(hbox);
+
+
+ hbox = new QHBoxLayout;
+ hbox->addStretch(1);
+ listButton = new QToolButton(Qt::UpArrow,this);
+ listButton->setFixedSize(20,15);
+ listButton->setAutoRepeat(false);
+ connect(listButton,SIGNAL(clicked()),this,SLOT(showListOnly()));
+ hbox->addWidget(listButton);
+ detailButton = new QToolButton(Qt::DownArrow,this);
+ detailButton->setFixedSize(20,15);
+ detailButton->setAutoRepeat(false);
+ connect(detailButton,SIGNAL(clicked()),this,SLOT(showDetailsOnly()));
+ hbox->addWidget(detailButton);
+
+ mainLayout->addLayout(hbox);
+
+
+ resultSplitter = new QSplitter(Qt::Vertical,this
+ ,"resultsplitter");
+ mainLayout->addWidget(resultSplitter);
+
+ viewContainer = new QSplitter(Qt::Vertical,resultSplitter, "singleEntrySplitter");
+ QVBoxLayout *vbox = new QVBoxLayout(viewContainer);
+ vbox->setResizeMode(QLayout::FreeResize);
+ origView = new QTextView(viewContainer,"origView");
+ origView->setWordWrap( QTextEdit::WidgetWidth );
+ origView->setMinimumSize(1,1);
+ vbox->addWidget(origView);
+ translationView = new QTextView(viewContainer,"translationView");
+ origView->setWordWrap( QTextEdit::WidgetWidth );
+ translationView->setMinimumSize(1,1);
+ vbox->addWidget(translationView);
+ viewContainer->setMinimumSize(1,1);
+
+ resultListView = new KListView( resultSplitter, "resultListView" );
+ resultListView->setMinimumSize(1,1);
+ resultListView->addColumn( i18n( "Score" ) );
+ resultListView->addColumn( i18n( "Original" ) );
+ resultListView->addColumn( i18n( "Translation" ) );
+ resultListView->addColumn( i18n( "Location" ) );
+
+ resultListView->installEventFilter(this);
+ connect(resultListView
+ , SIGNAL(doubleClicked(QListViewItem *,const QPoint&,int))
+ , this, SLOT(editFile()));
+ connect(resultListView, SIGNAL(returnPressed(QListViewItem *))
+ , this, SLOT(editFile()));
+ connect(resultListView
+ , SIGNAL(contextMenu(KListView *,QListViewItem *,const QPoint&))
+ , this
+ , SLOT(showContextMenu(KListView *,QListViewItem *,const QPoint&)));
+
+ resultSplitter->setResizeMode(viewContainer,QSplitter::KeepSize);
+ QValueList<int> sizes;
+ sizes.append(50);
+ sizes.append(50);
+ resultSplitter->setSizes(sizes);
+
+
+ hbox = new QHBoxLayout;
+ hbox->addStretch(1);
+
+ prevButton = new QPushButton(i18n("< &Previous"),this);
+ prevButton->setEnabled(false);
+ prevButton->setAutoRepeat(true);
+ hbox->addWidget(prevButton);
+
+ nextButton = new QPushButton(i18n("&Next >"),this);
+ nextButton->setEnabled(false);
+ nextButton->setAutoRepeat(true);
+ hbox->addWidget(nextButton);
+
+ hbox->addStretch(1);
+ mainLayout->addLayout(hbox);
+
+ totalResultsLabel->setNum(100000);
+ totalResultsLabel->setFixedSize(totalResultsLabel->sizeHint());
+ totalResultsLabel->setNum(0);
+ currentLabel->setNum(100000);
+ currentLabel->setFixedSize(currentLabel->sizeHint());
+ currentLabel->setNum(0);
+
+ setRMBMenu(new QPopupMenu(this));
+ QStringList fileList;
+#if 0
+ // try to find installed modules by looking into directories
+ // kbabeldict/modules and getting all files *.rc
+ QStringList dirList = KGlobal::dirs()->findDirs("data"
+ ,"kbabeldict/modules");
+
+ for ( QStringList::Iterator it = dirList.begin(); it != dirList.end()
+ ; ++it )
+ {
+ QDir dir((*it),"*.rc");
+ QStringList list = dir.entryList(QDir::Files|QDir::Readable);
+
+ for ( QStringList::Iterator fit = list.begin(); fit != list.end()
+ ; ++fit )
+ {
+ if(!fileList.contains((*fit)))
+ {
+ fileList.append((*fit));
+ }
+ }
+ }
+#endif
+
+ // use locate to locate the actual file, because rcfiles in the users
+ // directory is prefered for systemwide rc files
+ QStringList rcList;
+ for( QStringList::Iterator fit = fileList.begin(); fit != fileList.end();
+ ++fit)
+ {
+ rcList.append(locate("data","kbabeldict/modules/"+(*fit)));
+ }
+
+ for( QStringList::Iterator rit = rcList.begin(); rit != rcList.end();
+ ++rit)
+ {
+ KConfig rcConfig((*rit),true,false);
+
+ rcConfig.setGroup("SearchEngine");
+
+ QStringList appList = rcConfig.readListEntry("Applications");
+ KInstance *inst = KGlobal::instance();
+ if(inst && !appList.isEmpty() && !appList.contains(inst->instanceName()))
+ {
+ continue;
+ }
+
+ QString libName = rcConfig.readEntry("Lib");
+
+ if(!libName.isNull())
+ {
+ kdDebug(KBABELDICT) << "loading library " << libName << endl;
+
+ KLibFactory *factory=KLibLoader::self()->factory(libName.latin1());
+
+ if(factory)
+ {
+ SearchEngine *e = (SearchEngine *)factory->create(this
+ , "searchengine", "SearchEngine");
+ if(!e)
+ {
+ kdError() << "searchengine not initialized" << endl;
+ }
+ else
+ {
+ registerModule(e);
+ }
+ }
+ else
+ {
+ kdError() << "wasn't able to load library" << endl;
+ }
+
+ }
+ }
+
+ kdDebug(KBABEL_SEARCH) << "Now using trader for " << KGlobal::instance()->instanceName() << endl;
+
+ // try to find installed modules by KTrader
+ KTrader::OfferList offers = KTrader::self()->query("KBabelDictModule",
+ "('"+KGlobal::instance()->instanceName()+"' in [Applications])");
+
+ for(KTrader::OfferList::ConstIterator it = offers.begin(); it != offers.end(); ++it )
+ {
+ KLibFactory *factory = KLibLoader::self()->factory( (*it)->library().local8Bit() );
+
+ if(factory)
+ {
+ SearchEngine *e = (SearchEngine *)factory->create(this
+ , "searchengine", "SearchEngine");
+ if(!e)
+ {
+ kdError() << "searchengine not initialized" << endl;
+ }
+ else
+ {
+ registerModule(e);
+ }
+ }
+ else
+ {
+ kdError() << "wasn't able to load library" << endl;
+ }
+ }
+
+ kdDebug(KBABEL_SEARCH) << "Now for any application" << endl;
+
+ offers = KTrader::self()->query("KBabelDictModule",
+ "not ( exist Applications)");
+
+ for(KTrader::OfferList::ConstIterator it = offers.begin(); it != offers.end(); ++it )
+ {
+ KLibFactory *factory = KLibLoader::self()->factory( (*it)->library().local8Bit() );
+
+ if(factory)
+ {
+ SearchEngine *e = (SearchEngine *)factory->create(this
+ , "searchengine", "SearchEngine");
+ if(!e)
+ {
+ kdError() << "searchengine not initialized" << endl;
+ }
+ else
+ {
+ registerModule(e);
+ }
+ }
+ else
+ {
+ kdError() << "wasn't able to load library" << endl;
+ }
+ }
+
+ connect(nextButton,SIGNAL(clicked()),this,SLOT(slotNextResult()));
+ connect(prevButton,SIGNAL(clicked()),this,SLOT(slotPrevResult()));
+ connect(moreButton,SIGNAL(clicked()),this,SLOT(nextInfo()));
+
+
+ origView->installEventFilter(this);
+ translationView->installEventFilter(this);
+
+ resultListView->setSorting(0,false);
+ resultListView->setAllColumnsShowFocus(true);
+
+ connect(resultListView,SIGNAL(selectionChanged(QListViewItem*))
+ , this, SLOT(showResult(QListViewItem*)));
+}
+
+/*
+ * Destroys the object and frees any allocated resources
+ */
+KBabelDictBox::~KBabelDictBox()
+{
+}
+
+void KBabelDictBox::registerModule( SearchEngine* e )
+{
+ active = 0;
+ moduleList.append(e);
+ connect(e, SIGNAL(started()),this,SIGNAL(searchStarted()));
+ connect(e, SIGNAL(finished()),this,SIGNAL(searchStopped()));
+ connect(e, SIGNAL(finished()),this
+ ,SLOT(clearModuleResults()));
+ connect(e, SIGNAL(progress(int)),this,SIGNAL(progressed(int)));
+ connect(e, SIGNAL(progressStarts(const QString&)),this
+ , SIGNAL(progressStarts(const QString&)));
+ connect(e, SIGNAL(progressEnds()),this,SIGNAL(progressEnds()));
+ connect(e, SIGNAL(resultFound(const SearchResult*)), this
+ , SLOT(addResult(const SearchResult*)));
+ connect(e, SIGNAL(hasError(const QString&)), this
+ , SIGNAL(errorInModule(const QString&)));
+}
+
+void KBabelDictBox::saveSettings(KConfigBase *config)
+{
+ KConfigGroupSaver cs(config,"KBabelDict");
+
+ config->writeEntry("ResultSplitter",resultSplitter->sizes());
+
+ SearchEngine *e;
+
+ e = moduleList.at(active);
+ if(e)
+ {
+ config->writeEntry("ActiveModule",e->id());
+ }
+
+ for(e = moduleList.first(); e != 0; e = moduleList.next())
+ {
+ config->setGroup(e->id());
+ e->saveSettings(config);
+ }
+
+
+}
+
+void KBabelDictBox::saveSettings(const QString& moduleId, KConfigBase *config)
+{
+ SearchEngine *e;
+
+ for(e = moduleList.first(); e != 0; e = moduleList.next())
+ {
+ if(e->id() == moduleId)
+ {
+ e->saveSettings(config);
+ break;
+ }
+ }
+}
+
+void KBabelDictBox::readSettings(KConfigBase *config)
+{
+ SearchEngine *e;
+ KConfigGroupSaver cs(config,"KBabelDict");
+ QValueList<int> sizes=config->readIntListEntry("ResultSplitter");
+ if(!sizes.isEmpty())
+ resultSplitter->setSizes(sizes);
+
+ QString m = config->readEntry("ActiveModule");
+ if(!m.isEmpty())
+ {
+ setActiveModule(m);
+ }
+
+ for(e = moduleList.first(); e != 0; e = moduleList.next())
+ {
+ config->setGroup(e->id());
+ e->readSettings(config);
+ }
+}
+
+void KBabelDictBox::readSettings(const QString& moduleId, KConfigBase *config)
+{
+ SearchEngine *e;
+
+ for(e = moduleList.first(); e != 0; e = moduleList.next())
+ {
+ if(e->id() == moduleId)
+ {
+ e->readSettings(config);
+ break;
+ }
+ }
+}
+
+void KBabelDictBox::setAutoUpdateOptions(bool on)
+{
+ SearchEngine *e;
+
+ for(e = moduleList.first(); e != 0; e = moduleList.next())
+ {
+ e->setAutoUpdateOptions(on);
+ }
+}
+
+
+int KBabelDictBox::activeModule()
+{
+ return active;
+}
+
+/*
+ * public slot
+ */
+void KBabelDictBox::setActiveModule(int a)
+{
+ if( a == active)
+ return;
+
+ if( a < (int)moduleList.count())
+ {
+ SearchEngine *engine = moduleList.at(active);
+
+ if(!engine)
+ {
+ kdDebug(KBABELDICT) << "no module available" << endl;
+ }
+ else if(engine->isSearching())
+ {
+ engine->stopSearch();
+ engine->clearResults();
+ }
+
+ engine = moduleList.at(a);
+ if(engine)
+ {
+ active = a;
+ emit activeModuleChanged(active);
+ emit activeModuleChanged(engine->isEditable());
+ }
+
+
+ }
+}
+
+void KBabelDictBox::setActiveModule(QString id)
+{
+ SearchEngine *e;
+
+ int i=0;
+
+ for(e = moduleList.first(); e != 0; e = moduleList.next())
+ {
+ if(e->id() == id)
+ {
+ setActiveModule(i);
+ break;
+ }
+
+ i++;
+ }
+}
+
+/*
+ * public slot
+ */
+void KBabelDictBox::startSearch(const QString text)
+{
+ clear();
+ SearchEngine *engine = moduleList.at(active);
+
+ if(!engine)
+ {
+ kdDebug(KBABELDICT) << "no module available" << endl;
+ }
+ else
+ {
+ if(engine->isSearching())
+ {
+ engine->stopSearch();
+ connect(this, SIGNAL(searchStopped()), this
+ , SLOT(startDelayedSearch()));
+
+ searchText=text;
+ }
+ else engine->startSearch(text);
+ }
+}
+
+/*
+ * public slot
+ */
+void KBabelDictBox::startTranslationSearch(const QString text)
+{
+ clear();
+ SearchEngine *engine = moduleList.at(active);
+
+ if(!engine)
+ {
+ kdDebug(KBABELDICT) << "no module available" << endl;
+ }
+ else
+ {
+ if(engine->isSearching())
+ {
+ engine->stopSearch();
+ connect(this, SIGNAL(searchStopped()), this
+ , SLOT(startDelayedTranslationSearch()));
+
+ searchText=text;
+ }
+ else engine->startSearchInTranslation(text);
+ }
+}
+
+void KBabelDictBox::startDelayedSearch(const QString text)
+{
+ clear();
+ SearchEngine *engine = moduleList.at(active);
+
+ if(!engine)
+ {
+ kdDebug(KBABELDICT) << "no module available" << endl;
+ }
+ else
+ {
+ searchText=text;
+
+ if(engine->isSearching())
+ {
+ engine->stopSearch();
+
+ connect(this, SIGNAL(searchStopped()), this
+ , SLOT(startDelayedSearch()));
+
+ }
+ else
+ {
+ QTimer::singleShot(5,this,SLOT(startDelayedSearch()));
+ }
+ }
+}
+
+void KBabelDictBox::startDelayedTranslationSearch(const QString text)
+{
+ clear();
+ SearchEngine *engine = moduleList.at(active);
+
+ if(!engine)
+ {
+ kdDebug(KBABELDICT) << "no module available" << endl;
+ }
+ else
+ {
+ searchText=text;
+
+ if(engine->isSearching())
+ {
+ engine->stopSearch();
+
+ connect(this, SIGNAL(searchStopped()), this
+ , SLOT(startDelayedTranslationSearch()));
+
+ }
+ else
+ {
+ QTimer::singleShot(5,this,SLOT(startDelayedTranslationSearch()));
+ }
+ }
+}
+
+QString KBabelDictBox::translate(const QString text)
+{
+ SearchEngine *engine = moduleList.at(active);
+
+ if(!engine)
+ {
+ kdDebug(KBABELDICT) << "no module available" << endl;
+ return QString::null;
+ }
+ else
+ {
+ if(engine->isSearching())
+ {
+ engine->stopSearch();
+ }
+
+ return engine->translate(text);
+ }
+}
+
+QString KBabelDictBox::fuzzyTranslation(const QString text, int &score)
+{
+ SearchEngine *engine = moduleList.at(active);
+
+ if(!engine)
+ {
+ kdDebug(KBABELDICT) << "no module available" << endl;
+ return QString::null;
+ }
+ else
+ {
+ if(engine->isSearching())
+ {
+ engine->stopSearch();
+ }
+
+ return engine->fuzzyTranslation(text, score);
+ }
+}
+
+QString KBabelDictBox::searchTranslation(const QString text, int &score)
+{
+ SearchEngine *engine = moduleList.at(active);
+
+ if(!engine)
+ {
+ kdDebug(KBABELDICT) << "no module available" << endl;
+ return QString::null;
+ }
+ else
+ {
+ if(engine->isSearching())
+ {
+ engine->stopSearch();
+ }
+
+ return engine->searchTranslation(text, score);
+ }
+}
+
+void KBabelDictBox::startDelayedSearch()
+{
+ clear();
+
+ SearchEngine *engine = moduleList.at(active);
+
+ if(!engine)
+ {
+ kdDebug(KBABELDICT) << "no module available" << endl;
+ }
+ else
+ {
+ disconnect(this, SIGNAL(searchStopped()), this
+ , SLOT(startDelayedSearch()));
+
+
+ engine->startSearch(searchText);
+ }
+}
+
+void KBabelDictBox::startDelayedTranslationSearch()
+{
+ clear();
+
+ SearchEngine *engine = moduleList.at(active);
+
+ if(!engine)
+ {
+ kdDebug(KBABELDICT) << "no module available" << endl;
+ }
+ else
+ {
+ disconnect(this, SIGNAL(searchStopped()), this
+ , SLOT(startDelayedTranslationSearch()));
+
+
+ engine->startSearchInTranslation(searchText);
+ }
+}
+
+/*
+ * public slot
+ */
+void KBabelDictBox::stopSearch()
+{
+ SearchEngine *engine = moduleList.at(active);
+
+ if(!engine)
+ {
+ kdDebug(KBABELDICT) << "no module available" << endl;
+ }
+ else
+ {
+ engine->stopSearch();
+ }
+
+}
+
+bool KBabelDictBox::isSearching()
+{
+ SearchEngine *engine = moduleList.at(active);
+
+ if(!engine)
+ {
+ kdDebug(KBABELDICT) << "no module available" << endl;
+ return false;
+ }
+
+ return engine->isSearching();
+}
+
+
+QStringList KBabelDictBox::moduleNames()
+{
+ QStringList list;
+ SearchEngine *e;
+
+ for(e = moduleList.first(); e != 0; e = moduleList.next())
+ {
+ list.append(e->name());
+ }
+
+ return list;
+}
+
+QStringList KBabelDictBox::modules()
+{
+ QStringList list;
+ SearchEngine *e;
+
+ for(e = moduleList.first(); e != 0; e = moduleList.next())
+ {
+ list.append(e->id());
+ }
+
+ return list;
+}
+
+QPtrList<ModuleInfo> KBabelDictBox::moduleInfos()
+{
+ QPtrList<ModuleInfo> list;
+ SearchEngine *e;
+
+ for(e = moduleList.first(); e != 0; e = moduleList.next())
+ {
+ ModuleInfo *info = new ModuleInfo;
+ info->id=e->id();
+ info->name=e->name();
+ info->editable=e->isEditable();
+
+ list.append(info);
+ }
+
+ return list;
+}
+
+
+QPtrList<PrefWidget> KBabelDictBox::modPrefWidgets(QWidget *parent)
+{
+ QPtrList<PrefWidget> list;
+ list.setAutoDelete(false);
+ SearchEngine *e;
+
+ for(e = moduleList.first(); e != 0; e = moduleList.next())
+ {
+ list.append(e->preferencesWidget(parent));
+ }
+
+ return list;
+
+}
+
+
+void KBabelDictBox::showResult(QListViewItem *item)
+{
+ ResultListItem *resultItem = static_cast<ResultListItem*>(item);
+
+ if(!item)
+ {
+ kdError(KBABELDICT) << "no item" << endl;
+ if(rmbPopup)
+ {
+ rmbPopup->changeItem(editFileIndex, i18n("Edit File"));
+ rmbPopup->setItemEnabled(editFileIndex,false);
+ }
+ }
+ else
+ {
+ const SearchResult *result= resultItem->result();
+ if(!result)
+ return;
+
+ resultListView->ensureItemVisible(item);
+
+ currentResult = resultListView->itemIndex(item);
+ currentInfo = 0;
+
+ bool richText=resultItem->richText();
+ if(richText)
+ {
+ // FIXME: what about plural forms?
+ origView->setText(result->found.first());
+ translationView->setText(result->translation);
+ }
+ else
+ {
+ // FIXME: what about plural forms?
+ origView->setText(QStyleSheet::convertFromPlainText(result->found.first()));
+ translationView->setText(
+ QStyleSheet::convertFromPlainText(result->translation));
+ }
+
+ if(result->descriptions.count() > 0)
+ {
+ QPtrListIterator<TranslationInfo> it(result->descriptions);
+ TranslationInfo *info=it.current();
+ if(info)
+ {
+ if(info->lastChange.isValid())
+ {
+ dateLabel->setText(KGlobal::locale()->formatDate(
+ info->lastChange.date(),true));
+ }
+ else
+ {
+ dateLabel->setText("");
+ }
+ locationLabel->setText(info->location);
+ translatorLabel->setText(info->translator);
+
+ if(rmbPopup)
+ {
+ if(!info->filePath.isEmpty())
+ {
+ rmbPopup->changeItem(editFileIndex
+ ,i18n("Edit File %1").arg(info->location));
+ rmbPopup->setItemEnabled(editFileIndex,true);
+ }
+ else
+ {
+ rmbPopup->changeItem(editFileIndex, i18n("Edit File"));
+ rmbPopup->setItemEnabled(editFileIndex,false);
+ }
+ }
+ }
+ }
+ else
+ {
+ dateLabel->setText("");
+ locationLabel->setText("");
+ translatorLabel->setText("");
+
+ rmbPopup->changeItem(editFileIndex, i18n("Edit File"));
+ rmbPopup->setItemEnabled(editFileIndex,false);
+ }
+
+ moreButton->setEnabled((result->descriptions.count() > 1));
+
+ currentLabel->setText(QString::number(currentResult+1));
+
+ prevButton->setEnabled(currentResult > 0);
+ nextButton->setEnabled(currentResult+1 < total);
+ }
+
+}
+
+void KBabelDictBox::nextResult()
+{
+ QListViewItem *item=resultListView->selectedItem();
+ if(item)
+ {
+ item=item->itemBelow();
+ if(item)
+ {
+ resultListView->setSelected(item,true);
+ }
+ }
+}
+
+
+void KBabelDictBox::prevResult()
+{
+ QListViewItem *item=resultListView->selectedItem();
+ if(item)
+ {
+ item=item->itemAbove();
+ if(item)
+ {
+ resultListView->setSelected(item,true);
+ }
+ }
+
+}
+
+void KBabelDictBox::addResult(const SearchResult* result)
+{
+ SearchEngine *e;
+
+ e = moduleList.at(active);
+ if(!e)
+ {
+ kdError(KBABELDICT) << "no module available" << endl;
+ return;
+ }
+
+ QListViewItem *item=resultListView->selectedItem();
+ int index=0;
+ if(item)
+ {
+ index=resultListView->itemIndex(item);
+ }
+
+ new ResultListItem(resultListView, *result,e->usesRichTextResults());
+ total++;
+ totalResultsLabel->setText(QString::number(total));
+
+ if(total==1)
+ {
+ resultListView->setSelected(resultListView->firstChild(),true);
+ }
+ else
+ {
+ nextButton->setEnabled((currentResult+1) < total);
+ item=resultListView->itemAtIndex(index);
+ if(item)
+ {
+ resultListView->setSelected(item,true);
+ }
+ }
+}
+
+void KBabelDictBox::clear()
+{
+ dateLabel->setText("");
+ locationLabel->setText("");
+ translatorLabel->setText("");
+ currentLabel->setText(QString::number(0));
+ totalResultsLabel->setText(QString::number(0));
+ origView->setText("");
+ translationView->setText("");
+ currentResult=0;
+ currentInfo=0;
+ total=0;
+
+ resultListView->clear();
+ clearModuleResults();
+
+ moreButton->setEnabled(false);
+ prevButton->setEnabled(false);
+ nextButton->setEnabled(false);
+
+ if(rmbPopup)
+ {
+ rmbPopup->changeItem(editFileIndex,i18n("Edit File"));
+ rmbPopup->setItemEnabled(editFileIndex,false);
+ }
+}
+
+void KBabelDictBox::nextInfo()
+{
+ ResultListItem *item = static_cast<ResultListItem*>(resultListView->selectedItem());
+
+ if(!item)
+ {
+ kdDebug(KBABELDICT) << "no item available" << endl;
+ }
+ else
+ {
+ const SearchResult *result = item->result();
+ if(!result)
+ return;
+
+ if(result->descriptions.count() > 0)
+ {
+ currentInfo++;
+ TranslationInfo *info;
+ if(currentInfo == (int)result->descriptions.count())
+ {
+ QPtrListIterator<TranslationInfo> it(result->descriptions);
+ info = it.current();
+ currentInfo = 0;
+ }
+ else
+ {
+ QPtrListIterator<TranslationInfo> it(result->descriptions);
+ for(int i=0; i < currentInfo; i++)
+ {
+ ++it;
+ }
+ info=*it;
+ }
+
+ if(info->lastChange.isValid())
+ {
+ dateLabel->setText(KGlobal::locale()->formatDate(
+ info->lastChange.date(),true));
+ }
+ else
+ {
+ dateLabel->setText("");
+ }
+
+ locationLabel->setText(info->location);
+ translatorLabel->setText(info->translator);
+
+ if(rmbPopup)
+ {
+ if(!info->filePath.isEmpty())
+ {
+ rmbPopup->changeItem(editFileIndex
+ ,i18n("Edit File %1").arg(info->location));
+ rmbPopup->setItemEnabled(editFileIndex,true);
+ }
+ else
+ {
+ rmbPopup->changeItem(editFileIndex, i18n("Edit File"));
+ rmbPopup->setItemEnabled(editFileIndex,false);
+ }
+ }
+ }
+ }
+
+}
+
+void KBabelDictBox::showListOnly()
+{
+ int h=resultSplitter->height();
+ QValueList<int> sizes;
+ sizes.append(1);
+ sizes.append(h-1);
+ resultSplitter->setSizes(sizes);
+}
+
+void KBabelDictBox::showDetailsOnly()
+{
+ int h=resultSplitter->height();
+ QValueList<int> sizes;
+ sizes.append(h-1);
+ sizes.append(h);
+ resultSplitter->setSizes(sizes);
+}
+
+void KBabelDictBox::clearModuleResults()
+{
+ SearchEngine *engine = moduleList.at(active);
+ if(engine)
+ engine->clearResults();
+}
+
+void KBabelDictBox::about()
+{
+ KAboutApplication *aboutDlg = new KAboutApplication(this);
+
+ SearchEngine *e;
+ for(e = moduleList.first(); e != 0; e = moduleList.next())
+ {
+ KAboutContainer *page = aboutDlg->addScrolledContainerPage(e->name());
+
+ const KAboutData *aboutData = e->about();
+ if(aboutData)
+ {
+
+ QString text = aboutData->programName() + " " +
+ aboutData->version() + "\n";
+
+ text += "\n"+aboutData->shortDescription()+"\n";
+
+ if(!aboutData->homepage().isEmpty())
+ {
+ text += "\n" + aboutData->homepage() + "\n";
+ }
+ if(!aboutData->otherText().isEmpty())
+ {
+ text += "\n" + aboutData->otherText() + "\n";
+ }
+ if(!aboutData->copyrightStatement().isEmpty())
+ {
+ text += "\n" + aboutData->copyrightStatement() + "\n";
+ }
+
+ if(aboutData->bugAddress() != "submit@bugs.kde.org")
+ {
+ text += "\n" + i18n("Send bugs to %1")
+ .arg(aboutData->bugAddress()) +"\n";
+ }
+
+ QLabel *label = new QLabel(text,0);
+ page->addWidget(label);
+
+ int authorCount = aboutData->authors().count();
+ if(authorCount)
+ {
+ if(authorCount==1)
+ text=i18n("Author:");
+ else
+ text=i18n("Authors:");
+
+ label = new QLabel(text,0);
+ page->addWidget(label);
+
+ QValueList<KAboutPerson>::ConstIterator it;
+ for(it = aboutData->authors().begin();
+ it != aboutData->authors().end(); ++it)
+ {
+ page->addPerson( (*it).name(), (*it).emailAddress(),
+ (*it).webAddress(), (*it).task() );
+ }
+ }
+ int creditsCount = aboutData->credits().count();
+ if(creditsCount)
+ {
+ text = i18n("Thanks to:");
+ label = new QLabel(text,0);
+ page->addWidget(label);
+
+ QValueList<KAboutPerson>::ConstIterator it;
+ for(it = aboutData->credits().begin();
+ it != aboutData->credits().end(); ++it)
+ {
+ page->addPerson( (*it).name(), (*it).emailAddress(),
+ (*it).webAddress(), (*it).task() );
+ }
+
+ }
+ }
+ else
+ {
+ QString text = i18n("No information available.");
+ QLabel *label = new QLabel(text,0);
+ page->addWidget(label);
+ }
+
+ }
+
+ aboutDlg->setInitialSize(QSize(400,1));
+ aboutDlg->exec();
+
+ delete aboutDlg;
+}
+
+void KBabelDictBox::aboutActiveModule()
+{
+ SearchEngine *engine = moduleList.at(active);
+ if(!engine)
+ return;
+
+ aboutModule(engine->id());
+}
+
+void KBabelDictBox::aboutModule(const QString& id)
+{
+ SearchEngine *e;
+
+ for(e = moduleList.first(); e != 0; e = moduleList.next())
+ {
+ if(e->id() == id)
+ {
+ break;
+ }
+ }
+
+ if(!e)
+ return;
+
+ AboutModuleDlg *aboutDlg = new AboutModuleDlg(e->about(),this);
+ aboutDlg->exec();
+
+ delete aboutDlg;
+
+}
+
+
+void KBabelDictBox::slotNextResult()
+{
+ nextResult();
+}
+
+void KBabelDictBox::slotPrevResult()
+{
+ prevResult();
+}
+
+
+void KBabelDictBox::slotStopSearch()
+{
+ stopSearch();
+}
+
+void KBabelDictBox::slotStartSearch(const QString& text)
+{
+ startSearch(text);
+}
+
+void KBabelDictBox::setEditedPackage(const QString& name)
+{
+ SearchEngine *e;
+
+ for(e = moduleList.first(); e != 0; e = moduleList.next())
+ {
+ e->setEditedPackage(name);
+ }
+}
+
+
+void KBabelDictBox::setEditedFile(const QString& path)
+{
+ SearchEngine *e;
+
+ for(e = moduleList.first(); e != 0; e = moduleList.next())
+ {
+ e->setEditedFile(path);
+ }
+}
+
+void KBabelDictBox::setLanguage(const QString& languageCode,
+ const QString& languageName)
+{
+ SearchEngine *e;
+
+ for(e = moduleList.first(); e != 0; e = moduleList.next())
+ {
+ e->setLanguage(languageCode,languageName);
+ e->setLanguageCode(languageCode);
+ }
+}
+
+void KBabelDictBox::copy()
+{
+ if(origView->hasSelectedText())
+ {
+ origView->copy();
+ }
+ else if(translationView->hasSelectedText())
+ {
+ translationView->copy();
+ }
+ else
+ {
+ QClipboard *cb = KApplication::clipboard();
+ cb->setText(translation());
+ }
+}
+
+QString KBabelDictBox::translation()
+{
+ QString trans;
+
+ QListViewItem *item=resultListView->selectedItem();
+ if(item)
+ {
+ ResultListItem *r=static_cast<ResultListItem*>(item);
+ if(r)
+ {
+ const SearchResult *sr=r->result();
+ if(sr)
+ {
+ if(r->richText())
+ trans=sr->plainTranslation;
+ else
+ trans=sr->translation;
+ }
+ }
+ }
+
+ return trans;
+}
+
+void KBabelDictBox::setRMBMenu(QPopupMenu *popup)
+{
+ if(popup)
+ {
+ if(popup->count() > 0)
+ popup->insertSeparator();
+
+ editFileIndex = popup->insertItem(i18n("Edit File")
+ , this, SLOT(editFile()));
+ popup->setItemEnabled(editFileIndex,false);
+
+ KContextMenuManager::insert(origView,popup);
+ KContextMenuManager::insert(origView->viewport(),popup);
+ KContextMenuManager::insert(translationView,popup);
+ KContextMenuManager::insert(translationView->viewport(),popup);
+ KContextMenuManager::insert(this,popup);
+ //KContextMenuManager::insert(resultListView->viewport(),popup);
+
+ rmbPopup = popup;
+ }
+}
+
+bool KBabelDictBox::hasSelectedText() const
+{
+ bool have=false;
+ if(origView->hasSelectedText())
+ have=true;
+ else if(translationView->hasSelectedText())
+ have=true;
+ else if(resultListView->selectedItem() )
+ have=true;
+
+ return have;
+}
+
+QString KBabelDictBox::selectedText() const
+{
+ QString text;
+ if(origView->hasSelectedText())
+ text=origView->selectedText();
+ else if(translationView->hasSelectedText())
+ translationView->selectedText();
+
+ return text;
+}
+
+
+
+void KBabelDictBox::configure(const QString& id, bool modal)
+{
+
+ QWidget* w = prefDialogs[id];
+ if(w)
+ {
+ KWin::setActiveWindow(w->winId());
+ return;
+ }
+
+ SearchEngine *e;
+ for(e = moduleList.first(); e != 0; e = moduleList.next())
+ {
+ if(e->id() == id)
+ {
+ QString caption = i18n("Configure Dictionary %1").arg(e->name());
+ KDialogBase *dialog = new KDialogBase(this,"prefDialog"
+ , modal, caption
+ , KDialogBase::Ok|KDialogBase::Apply|KDialogBase::Cancel|
+ KDialogBase::Default);
+
+ QWhatsThis::add(dialog,"");
+
+ PrefWidget *prefWidget = e->preferencesWidget(dialog);
+ dialog->setMainWidget(prefWidget);
+
+ connect(dialog, SIGNAL(okClicked()),prefWidget,SLOT(apply()));
+ connect(dialog, SIGNAL(applyClicked()),prefWidget,SLOT(apply()));
+ connect(dialog, SIGNAL(defaultClicked()),prefWidget,SLOT(standard()));
+ connect(dialog, SIGNAL(cancelClicked()),prefWidget,SLOT(cancel()));
+
+ connect(dialog, SIGNAL(finished()),this,SLOT(destroyConfigDialog()));
+
+ prefDialogs.insert(id,dialog);
+
+ if( modal ) dialog->exec();
+ else dialog->show();
+
+ break;
+ }
+ }
+
+}
+
+
+void KBabelDictBox::destroyConfigDialog()
+{
+ const QObject *obj = sender();
+ if(obj && obj->inherits("KDialogBase"))
+ {
+ KDialogBase *dialog = (KDialogBase*)obj;
+ if(dialog)
+ {
+ dialog->delayedDestruct();
+
+ QDictIterator<QWidget> it(prefDialogs);
+ while(it.current() != dialog)
+ {
+ ++it;
+ }
+
+ prefDialogs.remove(it.currentKey());
+ }
+ }
+}
+
+void KBabelDictBox::edit(const QString& id)
+{
+ SearchEngine *e;
+
+ for(e = moduleList.first(); e != 0; e = moduleList.next())
+ {
+ if(e->id() == id)
+ {
+ if(e->isEditable())
+ e->edit();
+
+ break;
+ }
+ }
+}
+
+void KBabelDictBox::edit()
+{
+ SearchEngine *engine = moduleList.at(active);
+ if(!engine)
+ return;
+
+ if(engine->isEditable())
+ engine->edit();
+}
+
+void KBabelDictBox::setTextChanged(const QStringList& orig,
+ const QString& translation, uint pluralForm, const QString& description)
+{
+ SearchEngine *e;
+
+ for(e = moduleList.first(); e != 0; e = moduleList.next())
+ {
+ e->stringChanged(orig,translation,pluralForm,description);
+ }
+}
+
+
+void KBabelDictBox::wheelEvent(QWheelEvent *we)
+{
+ if(we->delta() > 0)
+ {
+ prevResult();
+ }
+ else
+ {
+ nextResult();
+ }
+
+ we->accept();
+}
+
+bool KBabelDictBox::eventFilter(QObject *o, QEvent *e)
+{
+ if(e->type() == QEvent::Wheel)
+ {
+ QWheelEvent *we = static_cast<QWheelEvent*>(e);
+ if(we)
+ {
+ wheelEvent(we);
+ return true;
+ }
+ }
+ else if(e->type() == QEvent::Resize && o == resultListView)
+ {
+ if(resultListView->height() < 2)
+ {
+ detailButton->setEnabled(false);
+ listButton->setEnabled(true);
+ }
+ else if(resultListView->height() > resultSplitter->height()-10)
+ {
+ detailButton->setEnabled(true);
+ listButton->setEnabled(false);
+ }
+ else
+ {
+ detailButton->setEnabled(true);
+ listButton->setEnabled(true);
+ }
+ }
+
+ return false;
+}
+
+void KBabelDictBox::editFile()
+{
+ ResultListItem *item = static_cast<ResultListItem*>(resultListView->currentItem());
+
+ if(!item)
+ {
+ kdDebug(KBABELDICT) << "no item available" << endl;
+ }
+ else
+ {
+ const SearchResult *result = item->result();
+ if(!result)
+ return;
+
+ if(!result->descriptions.isEmpty())
+ {
+ TranslationInfo *info;
+ QPtrListIterator<TranslationInfo> it(result->descriptions);
+ for(int i=0; i < currentInfo; i++)
+ {
+ ++it;
+ }
+ info=*it;
+
+ if(!info->filePath.isEmpty())
+ {
+ QString url = info->filePath;
+ QString msgid;
+
+ if( item->richText() )
+ {
+ msgid = result->plainFound;
+ }
+ else
+ {
+ msgid = result->found.first();
+ }
+
+ DCOPClient *dcop = kapp->dcopClient();
+
+ QCStringList list = dcop->registeredApplications();
+ int index = list.findIndex("kbabel");
+ if(index < 0)
+// if(!dcop->isApplicationRegistered("kbabel"));
+ {
+ kdDebug(KBABELDICT) << "kbabel is not registered" << endl;
+
+ QString error;
+ QStringList argList;
+ argList.append("--nosplash");
+ argList.append("--gotomsgid");
+ argList.append(msgid.local8Bit());
+ argList.append(url.local8Bit());
+ kapp->kdeinitExec("kbabel",argList,&error);
+ if(!error.isNull())
+ {
+ KMessageBox::sorry(this
+ ,i18n("There was an error starting KBabel:\n%1")
+ .arg(error));
+ return;
+ }
+ }
+ else
+ {
+ QByteArray data;
+ QDataStream arg(data, IO_WriteOnly);
+ arg << url.utf8() << msgid.utf8();
+ if (!dcop->send("kbabel", "KBabelIFace"
+ , "gotoFileEntry(QCString,QCString)",data))
+ {
+ KMessageBox::sorry(this
+ ,i18n("There was an error using DCOP."));
+ }
+ }
+ }
+ }
+ }
+}
+
+void KBabelDictBox::showContextMenu(KListView *,QListViewItem *,const QPoint& p)
+{
+ if(rmbPopup)
+ {
+ rmbPopup->exec(p);
+ }
+}
+
+
+bool KBabelDictBox::messagesForPackage(const QString& package
+ , QValueList<DiffEntry>& resultList, QString& error)
+{
+ setActiveModule("dbsearchengine");
+ SearchEngine *engine = moduleList.at(active);
+
+ if(!engine)
+ {
+ KMessageBox::sorry(this
+ ,i18n("The \"Translation Database\" module\n"
+ "appears not to be installed on your system."));
+ return false;
+ }
+
+ QValueList<SearchResult> rList;
+
+ SearchFilter* filter = new SearchFilter();
+ filter->setLocation(package);
+
+ bool success = engine->messagesForFilter(filter,rList,error);
+
+ if(success)
+ {
+ QValueList<SearchResult>::Iterator it;
+ for(it=rList.begin(); it != rList.end(); ++it)
+ {
+ // FIXME: what about plural forms?
+ DiffEntry e;
+ e.msgid = (*it).found.first();
+ e.msgstr = (*it).translation;
+ resultList.append(e);
+ }
+ }
+
+ return success;
+}
+
+#include "kbabeldictbox.moc"
+
diff --git a/kbabel/kbabeldict/kbabeldictbox.h b/kbabel/kbabeldict/kbabeldictbox.h
new file mode 100644
index 00000000..8168786e
--- /dev/null
+++ b/kbabel/kbabeldict/kbabeldictbox.h
@@ -0,0 +1,282 @@
+/* ****************************************************************************
+ This file is part of KBabel
+
+ Copyright (C) 2000 by Matthias Kiefer
+ <matthias.kiefer@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.
+
+ 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, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+ In addition, as a special exception, the copyright holders give
+ permission to link the code of this program with any edition of
+ the Qt library by Trolltech AS, Norway (or with modified versions
+ of Qt that use the same license as Qt), and distribute linked
+ combinations including the two. You must obey the GNU General
+ Public License in all respects for all of the code used other than
+ Qt. If you modify this file, you may extend this exception to
+ your version of the file, but you are not obligated to do so. If
+ you do not wish to do so, delete this exception statement from
+ your version.
+
+**************************************************************************** */
+#ifndef KBABELDICTBOX_H
+#define KBABELDICTBOX_H
+
+#include "kbabeldictiface.h"
+#include "searchengine.h"
+#include "catalog.h"
+
+#include <qdict.h>
+#include <qguardedptr.h>
+#include <qptrlist.h>
+#include <qstringlist.h>
+
+class KListView;
+class QLabel;
+class QListViewItem;
+class QPopupMenu;
+class QPushButton;
+class QSplitter;
+class QTextView;
+class QToolButton;
+
+struct ModuleInfo
+{
+ QString id;
+ QString name;
+
+ bool editable;
+};
+
+
+class KDE_EXPORT KBabelDictBox : public QWidget, virtual public KBabelDictIFace
+{
+ Q_OBJECT
+
+public:
+ KBabelDictBox( QWidget* parent = 0, const char* name = 0
+ , WFlags fl = 0 );
+ ~KBabelDictBox();
+
+ /** @returns ids of available modules */
+ virtual QStringList modules();
+
+ /** @returns (translated) names of available modules */
+ QStringList moduleNames();
+
+ /**
+ * @returns a list with information about the available modules
+ * Take care about, that you have to delete the items by yourself.
+ */
+ QPtrList<ModuleInfo> moduleInfos();
+
+ /** @returns preferencesWidgets of modules */
+ QPtrList<PrefWidget> modPrefWidgets(QWidget* parent);
+
+ int activeModule();
+ bool activeModuleEditable();
+
+ /**
+ * lets the modules always update their options before
+ * starting a new search
+ */
+ void setAutoUpdateOptions(bool on);
+
+ void nextResult();
+ void prevResult();
+ void startSearch(const QString);
+ void startTranslationSearch(const QString);
+ void startDelayedSearch(const QString);
+ void startDelayedTranslationSearch(const QString);
+ QString translate(const QString);
+ QString searchTranslation(const QString, int& score);
+ QString fuzzyTranslation(const QString, int& score);
+ void stopSearch();
+ void setActiveModule(QString name);
+
+ /**
+ * @returns true, if a search is active at the moment
+ */
+ bool isSearching();
+
+ /**
+ * Saves the settings including the settings of the different modules
+ * in the given config object.
+ */
+ void saveSettings(KConfigBase *config);
+
+ /**
+ * Saves the settings of the given module
+ * in the given config object.
+ */
+ void saveSettings(const QString& moduleId, KConfigBase *config);
+
+ /**
+ * Reads the settings including the settings of the different modules
+ * from the given config object.
+ */
+ void readSettings(KConfigBase *config);
+
+ /**
+ * Reads the settings of the given module
+ * from the given config object.
+ */
+ void readSettings(const QString& moduleId, KConfigBase *config);
+
+
+
+ /** @returns the translation of the current search result */
+ QString translation();
+
+ bool hasSelectedText() const;
+ QString selectedText() const;
+
+ void setRMBMenu(QPopupMenu *popup);
+
+
+ virtual bool eventFilter(QObject *, QEvent*);
+
+
+ /**
+ * A hack for kbabel to get a list of messages for a specific package
+ * from dbsearchengine. When dbsearchengine allows multiple access to
+ * the database this will get removed.
+ */
+ bool messagesForPackage(const QString& package
+ , QValueList<KBabel::DiffEntry>& resultList, QString& error);
+
+public slots:
+ virtual void setActiveModule(int);
+ void slotStartSearch(const QString&);
+ void slotStopSearch();
+ void slotNextResult();
+ void slotPrevResult();
+
+ void about();
+ void aboutModule(const QString& moduleID);
+ void aboutActiveModule();
+
+ /**
+ * sets the name of the package currently edited
+ */
+ void setEditedPackage(const QString& packageName);
+
+ /**
+ * sets the filepath of the package currently edited
+ */
+ void setEditedFile(const QString& path);
+
+ /** sets the language code to use */
+ void setLanguage(const QString& languageCode
+ , const QString& languageName);
+
+
+ void setTextChanged(const QStringList& orig, const QString& translation,
+ uint pluralForm, const QString& description);
+
+ /**
+ * if text is marked, copy this into the clipboard, otherwise
+ * copy the current translation into the clipboard
+ */
+ void copy();
+
+ void configure(const QString& moduleID, bool modal=false);
+ void edit(const QString& moduleID);
+ void edit();
+
+ void clear();
+
+
+signals:
+ void searchStarted();
+ void searchStopped();
+ void progressed(int);
+ void progressStarts(const QString&);
+ void progressEnds();
+ void activeModuleChanged(int);
+ void activeModuleChanged(bool editable);
+ void errorInModule(const QString& error);
+
+ /**
+ * emitted when either the order
+ * or the number of modules was changed
+ */
+ void modulesChanged();
+
+protected slots:
+ void showResult(QListViewItem*);
+ void addResult(const SearchResult*);
+ void nextInfo();
+ void showDetailsOnly();
+ void showListOnly();
+ void clearModuleResults();
+ void editFile();
+ void showContextMenu(KListView *, QListViewItem *, const QPoint&);
+
+ /**
+ * This slots gets connected to a SearchEngine's searchStopped() signal,
+ * when a new search is requested although a search is currently active.
+ */
+ void startDelayedSearch();
+ void startDelayedTranslationSearch();
+
+
+ /**
+ * This slot is connected to the finished signal of @ref KDialogBase
+ * to destroy this dialog after the user has closed it.
+ */
+ void destroyConfigDialog();
+
+protected:
+ virtual void wheelEvent(QWheelEvent*);
+
+private:
+ /**
+ * Register the module and connect the slots
+ */
+ void registerModule( SearchEngine* module);
+
+ QPtrList<SearchEngine> moduleList;
+ int active;
+ int currentResult;
+ int currentInfo;
+ int total;
+
+ /** stores a string to be used with delayed search */
+ QString searchText;
+
+ QDict<QWidget> prefDialogs;
+
+ QLabel *translatorLabel;
+ QLabel *locationLabel;
+ QLabel *totalResultsLabel;
+ QLabel *currentLabel;
+ QLabel *dateLabel;
+ QPushButton *moreButton;
+ QPushButton *nextButton;
+ QPushButton *prevButton;
+ QTextView *origView;
+ QTextView *translationView;
+ QSplitter *viewContainer;
+ KListView *resultListView;
+ QSplitter *resultSplitter;
+
+ QToolButton *listButton;
+ QToolButton *detailButton;
+
+ int editFileIndex;
+ QGuardedPtr<QPopupMenu> rmbPopup;
+};
+
+#endif // KBABELDICTBOX_H
diff --git a/kbabel/kbabeldict/kbabeldictiface.h b/kbabel/kbabeldict/kbabeldictiface.h
new file mode 100644
index 00000000..0b98a565
--- /dev/null
+++ b/kbabel/kbabeldict/kbabeldictiface.h
@@ -0,0 +1,56 @@
+/* ****************************************************************************
+ This file is part of KBabel
+
+ Copyright (C) 1999-2001 by Matthias Kiefer
+ <matthias.kiefer@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.
+
+ 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, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+ In addition, as a special exception, the copyright holders give
+ permission to link the code of this program with any edition of
+ the Qt library by Trolltech AS, Norway (or with modified versions
+ of Qt that use the same license as Qt), and distribute linked
+ combinations including the two. You must obey the GNU General
+ Public License in all respects for all of the code used other than
+ Qt. If you modify this file, you may extend this exception to
+ your version of the file, but you are not obligated to do so. If
+ you do not wish to do so, delete this exception statement from
+ your version.
+
+**************************************************************************** */
+
+#ifndef KBABELDICTINTERFACE_H
+#define KBABELDICTINTERFACE_H
+
+#include <dcopobject.h>
+#include <qstringlist.h>
+
+class KBabelDictIFace : virtual public DCOPObject
+{
+ K_DCOP
+
+k_dcop:
+ virtual QStringList modules() = 0;
+ virtual ASYNC setActiveModule(QString modulename) = 0;
+
+ virtual ASYNC startSearch(const QString searchstring) = 0;
+ virtual ASYNC stopSearch() = 0;
+
+ virtual ASYNC nextResult()=0;
+ virtual ASYNC prevResult()=0;
+
+};
+
+#endif
diff --git a/kbabel/kbabeldict/kbabeldictview.cpp b/kbabel/kbabeldict/kbabeldictview.cpp
new file mode 100644
index 00000000..26afd981
--- /dev/null
+++ b/kbabel/kbabeldict/kbabeldictview.cpp
@@ -0,0 +1,294 @@
+/* ****************************************************************************
+ This file is part of KBabel
+
+ Copyright (C) 2000 by Matthias Kiefer
+ <matthias.kiefer@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.
+
+ 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, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+ In addition, as a special exception, the copyright holders give
+ permission to link the code of this program with any edition of
+ the Qt library by Trolltech AS, Norway (or with modified versions
+ of Qt that use the same license as Qt), and distribute linked
+ combinations including the two. You must obey the GNU General
+ Public License in all respects for all of the code used other than
+ Qt. If you modify this file, you may extend this exception to
+ your version of the file, but you are not obligated to do so. If
+ you do not wish to do so, delete this exception statement from
+ your version.
+
+**************************************************************************** */
+
+
+#include "kbabeldictview.h"
+#include "kbabeldictbox.h"
+#include "searchengine.h"
+
+
+#include <qcheckbox.h>
+#include <qgroupbox.h>
+#include <qhbox.h>
+#include <qlabel.h>
+#include <qlayout.h>
+#include <qptrlist.h>
+#include <qpushbutton.h>
+#include <qstringlist.h>
+#include <qwidgetstack.h>
+#include <qsplitter.h>
+#include <qvbox.h>
+
+#include <kcombobox.h>
+#include <kconfig.h>
+#include <kdialog.h>
+#include <kglobal.h>
+#include <klineedit.h>
+#include <klocale.h>
+#include <kprogress.h>
+#include <kseparator.h>
+#include <kdebug.h>
+#include <kiconloader.h>
+
+/*
+ * Constructs a KBabelDictView which is a child of 'parent', with the
+ * name 'name' and widget flags set to 'f'
+ */
+KBabelDictView::KBabelDictView( QWidget* parent, const char* name, WFlags fl )
+ : QWidget( parent, name, fl )
+{
+ QVBoxLayout *mainLayout = new QVBoxLayout(this);
+ mainLayout->setSpacing(KDialog::spacingHint());
+ mainLayout->setMargin(KDialog::marginHint());
+
+ splitter = new QSplitter(this);
+ mainLayout->addWidget(splitter);
+
+ QWidget *w = new QWidget(splitter);
+ QVBoxLayout *wLayout= new QVBoxLayout(w);
+ wLayout->setSpacing(KDialog::spacingHint());
+ wLayout->setMargin(KDialog::marginHint());
+
+ QHBoxLayout *hbox = new QHBoxLayout(wLayout);
+ QLabel *label = new QLabel(i18n("Search in module:"), w);
+ hbox->addWidget(label);
+ moduleCombo = new KComboBox(w);
+ hbox->addWidget(moduleCombo);
+
+ QWidget *temp = new QWidget(w);
+ hbox->addWidget(temp);
+ hbox->setStretchFactor(temp,2);
+ editButton = new QPushButton(i18n("&Edit"),w);
+ editButton->setEnabled(false);
+ hbox->addWidget(editButton);
+
+ // added a button "clear search" here
+ hbox = new QHBoxLayout(wLayout);
+ QPushButton* clearButton = new QPushButton(w);
+ clearButton->setFlat(true);
+ clearButton->setPixmap(SmallIcon("locationbar_erase"));
+ hbox->addWidget(clearButton);
+ textEdit = new KLineEdit(w,"textedit");
+ textEdit->setFocus();
+ hbox->addWidget(textEdit);
+
+ hbox = new QHBoxLayout(wLayout);
+ startButton = new QPushButton(i18n("&Start Search"),w);
+ hbox->addWidget(startButton);
+ inTransButton = new QCheckBox(i18n("Sea&rch in translations"),w);
+ hbox->addWidget(inTransButton);
+ hbox->addStretch(1);
+ stopButton = new QPushButton(i18n("S&top"),w);
+ stopButton->setEnabled(false);
+ hbox->addWidget(stopButton);
+
+ KSeparator *sep = new KSeparator(w);
+ wLayout->addWidget(sep);
+ dictBox = new KBabelDictBox(w,"kbabeldictbox");
+ wLayout->addWidget(dictBox);
+
+ prefWidget = new QWidget(splitter);
+ QVBoxLayout *tempLayout= new QVBoxLayout(prefWidget);
+ tempLayout->setSpacing(KDialog::spacingHint());
+ tempLayout->setMargin(KDialog::marginHint());
+
+ label = new QLabel(i18n("Settings:"),prefWidget);
+ tempLayout->addWidget(label);
+
+ prefStack = new QWidgetStack(prefWidget);
+ tempLayout->addWidget(prefStack);
+ tempLayout->addStretch(1);
+
+ KConfig *config = KGlobal::config();
+ dictBox->readSettings(config);
+ dictBox->setAutoUpdateOptions(true);
+
+ QStringList modules = dictBox->moduleNames();
+ moduleCombo->insertStringList(modules);
+
+ QPtrList<PrefWidget> prefs = dictBox->modPrefWidgets(prefStack);
+ prefs.setAutoDelete(false);
+
+ PrefWidget *p;
+ int i=0;
+ for(p = prefs.first(); p != 0; p=prefs.next())
+ {
+ prefStack->addWidget(p,i);
+ i++;
+ }
+
+ int active=dictBox->activeModule();
+ prefStack->raiseWidget(active);
+ moduleCombo->setCurrentItem(active);
+
+
+ QHBox *h = new QHBox(this);
+ h->setSpacing(KDialog::spacingHint());
+ mainLayout->addWidget(h);
+ progressLabel = new QLabel(h);
+ progressBar = new KProgress(h);
+
+ connect(textEdit,SIGNAL(returnPressed()),startButton,SLOT(animateClick()));
+ connect(startButton,SIGNAL(clicked()),this, SLOT(startSearch()));
+ connect(stopButton, SIGNAL(clicked()), dictBox,SLOT(slotStopSearch()));
+ connect(editButton, SIGNAL(clicked()), dictBox, SLOT(edit()));
+ connect(dictBox, SIGNAL(searchStarted()), this, SLOT(searchStarted()));
+ connect(dictBox, SIGNAL(searchStopped()), this, SLOT(searchStopped()));
+ connect(dictBox, SIGNAL(progressed(int)), progressBar, SLOT(setProgress(int)));
+ connect(dictBox, SIGNAL(activeModuleChanged(bool))
+ , editButton, SLOT(setEnabled(bool)));
+
+ connect(dictBox, SIGNAL(progressStarts(const QString&))
+ , this, SLOT(progressStarted(const QString&)));
+ connect(dictBox, SIGNAL(progressEnds()), this, SLOT(progressStopped()));
+
+ connect(moduleCombo, SIGNAL(activated(int)),
+ dictBox, SLOT(setActiveModule(int)));
+ connect(dictBox, SIGNAL(activeModuleChanged(int))
+ , this, SLOT(switchModule(int)));
+ connect(clearButton, SIGNAL(clicked()), this, SLOT(slotClearSearch()));
+}
+
+/*
+ * Destroys the object and frees any allocated resources
+ */
+KBabelDictView::~KBabelDictView()
+{
+ // no need to delete child widgets, Qt does it all for us
+ KConfig *config = KGlobal::config();
+ dictBox->saveSettings(config);
+}
+
+/*
+ * public slot
+ */
+void KBabelDictView::startSearch()
+{
+ QString text = textEdit->text();
+
+ if(!text.isEmpty())
+ {
+ if(inTransButton->isChecked())
+ {
+ dictBox->startTranslationSearch(text);
+ }
+ else
+ {
+ dictBox->startSearch(text);
+ }
+ }
+
+
+}
+
+void KBabelDictView::progressStopped()
+{
+ progressBar->setProgress(0);
+ progressLabel->setText("");
+ startButton->setEnabled(true);
+ stopButton->setEnabled(false);
+}
+
+void KBabelDictView::progressStarted(const QString& msg)
+{
+ progressLabel->setText(msg);
+ startButton->setEnabled(false);
+ stopButton->setEnabled(true);
+}
+
+void KBabelDictView::searchStopped()
+{
+ progressLabel->setText("");
+ progressBar->setProgress(0);
+ startButton->setEnabled(true);
+ stopButton->setEnabled(false);
+}
+
+void KBabelDictView::searchStarted()
+{
+ progressLabel->setText(i18n("Searching"));
+ startButton->setEnabled(false);
+ stopButton->setEnabled(true);
+}
+
+void KBabelDictView::switchModule(int m)
+{
+ moduleCombo->blockSignals(true);
+ moduleCombo->setCurrentItem(m);
+ moduleCombo->blockSignals(false);
+
+ prefStack->raiseWidget(m);
+}
+
+
+void KBabelDictView::about()
+{
+ dictBox->about();
+}
+
+
+void KBabelDictView::aboutModule()
+{
+ dictBox->aboutActiveModule();
+}
+
+int KBabelDictView::togglePref()
+{
+ int prefWidth=0;
+ if(prefWidget->isVisibleTo(this))
+ {
+ prefWidget->hide();
+ prefWidth=prefWidget->width();
+ }
+ else
+ {
+ prefWidget->show();
+ prefWidth=prefWidget->width();
+ }
+
+ return prefWidth;
+}
+
+bool KBabelDictView::prefVisible()
+{
+ return prefWidget->isVisibleTo(this);
+}
+
+void KBabelDictView::slotClearSearch()
+{
+ textEdit->clear();
+ textEdit->setFocus();
+}
+
+#include "kbabeldictview.moc"
+
diff --git a/kbabel/kbabeldict/kbabeldictview.h b/kbabel/kbabeldict/kbabeldictview.h
new file mode 100644
index 00000000..510936c4
--- /dev/null
+++ b/kbabel/kbabeldict/kbabeldictview.h
@@ -0,0 +1,92 @@
+/* ****************************************************************************
+ This file is part of KBabel
+
+ Copyright (C) 2000 by Matthias Kiefer
+ <matthias.kiefer@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.
+
+ 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, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+ In addition, as a special exception, the copyright holders give
+ permission to link the code of this program with any edition of
+ the Qt library by Trolltech AS, Norway (or with modified versions
+ of Qt that use the same license as Qt), and distribute linked
+ combinations including the two. You must obey the GNU General
+ Public License in all respects for all of the code used other than
+ Qt. If you modify this file, you may extend this exception to
+ your version of the file, but you are not obligated to do so. If
+ you do not wish to do so, delete this exception statement from
+ your version.
+
+**************************************************************************** */
+
+
+#ifndef KBABELDICTVIEW_H
+#define KBABELDICTVIEW_H
+
+#include <qwidget.h>
+
+class KComboBox;
+class KLineEdit;
+class KProgress;
+class QCheckBox;
+class QLabel;
+class QPushButton;
+class QSplitter;
+class QWidgetStack;
+
+class KBabelDictBox;
+
+class KBabelDictView : public QWidget
+{
+ Q_OBJECT
+
+public:
+ KBabelDictView( QWidget* parent = 0, const char* name = 0, WFlags fl = 0 );
+ ~KBabelDictView();
+
+ bool prefVisible();
+
+public slots:
+ void startSearch();
+ void about();
+ void aboutModule();
+ int togglePref();
+
+private slots:
+ void searchStopped();
+ void searchStarted();
+ void switchModule(int);
+ void progressStopped();
+ void progressStarted(const QString&);
+ void slotClearSearch();
+
+private:
+ KBabelDictBox *dictBox;
+
+ KComboBox *moduleCombo;
+ KLineEdit *textEdit;
+ QCheckBox *inTransButton;
+ QPushButton *startButton;
+ QPushButton *stopButton;
+ QPushButton *editButton;
+ QWidgetStack *prefStack;
+ KProgress *progressBar;
+ QLabel *progressLabel;
+ QSplitter *splitter;
+
+ QWidget *prefWidget;
+};
+
+#endif // KBABELDICTVIEW_H
diff --git a/kbabel/kbabeldict/kbabelsplash.cpp b/kbabel/kbabeldict/kbabelsplash.cpp
new file mode 100644
index 00000000..16ac2352
--- /dev/null
+++ b/kbabel/kbabeldict/kbabelsplash.cpp
@@ -0,0 +1,73 @@
+/*
+ *
+ * $Id$
+ * Copyright (C) 2003 Sebastian Trueg <trueg@k3b.org>
+ * 2003 Stanislav Visnovsky <visnovsky@kde.org>
+ *
+ * This file is part of the KBabel project. It's taken from the K3b project,
+ * Copyright (C) 1998-2003 Sebastian Trueg <trueg@k3b.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ * See the file "COPYING" for the exact licensing terms.
+ *
+ * In addition, as a special exception, the copyright holders give
+ * permission to link the code of this program with any edition of
+ * the Qt library by Trolltech AS, Norway (or with modified versions
+ * of Qt that use the same license as Qt), and distribute linked
+ * combinations including the two. You must obey the GNU General
+ * Public License in all respects for all of the code used other than
+ * Qt. If you modify this file, you may extend this exception to
+ * your version of the file, but you are not obligated to do so. If
+ * you do not wish to do so, delete this exception statement from
+ * your version.
+ *
+ */
+
+#include "kbabelsplash.h"
+
+#include <qapplication.h>
+#include <qlabel.h>
+#include <qpixmap.h>
+#include <qevent.h>
+#include <qstring.h>
+#include <qfontmetrics.h>
+#include <qpainter.h>
+
+#include <kstandarddirs.h>
+
+KBabelSplash* KBabelSplash::instance = 0;
+
+KBabelSplash::KBabelSplash( QWidget* parent, const char* name )
+ : QVBox( parent, name, WType_Dialog|WShowModal|WStyle_Customize|WStyle_NoBorder|WDestructiveClose )
+{
+ setMargin( 0 );
+ setSpacing( 0 );
+
+ QLabel* picLabel = new QLabel( this );
+ QPixmap pixmap;
+ if( pixmap.load( locate( "data", "kbabel/pics/splash.png" ) ) )
+ picLabel->setPixmap( pixmap );
+
+ picLabel->setFrameStyle(QFrame::WinPanel | QFrame::Raised);
+
+ // Set geometry, with support for Xinerama systems
+ QRect r;
+ r.setSize(sizeHint());
+ int ps = QApplication::desktop()->primaryScreen();
+ r.moveCenter( QApplication::desktop()->screenGeometry(ps).center() );
+ setGeometry(r);
+
+ if( instance ) delete instance;
+ instance = this;
+}
+
+
+void KBabelSplash::mousePressEvent( QMouseEvent* )
+{
+ close();
+}
+
+#include "kbabelsplash.moc"
diff --git a/kbabel/kbabeldict/kbabelsplash.h b/kbabel/kbabeldict/kbabelsplash.h
new file mode 100644
index 00000000..c10b4fec
--- /dev/null
+++ b/kbabel/kbabeldict/kbabelsplash.h
@@ -0,0 +1,55 @@
+/*
+ *
+ * $Id$
+ * Copyright (C) 2003 Sebastian Trueg <trueg@k3b.org>
+ * 2003 Stanislav Visnovsky <visnovsky@kde.org>
+ *
+ * This file is part of the KBabel project. It's taken from the K3b project,
+ * Copyright (C) 1998-2003 Sebastian Trueg <trueg@k3b.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ * See the file "COPYING" for the exact licensing terms.
+ *
+ * In addition, as a special exception, the copyright holders give
+ * permission to link the code of this program with any edition of
+ * the Qt library by Trolltech AS, Norway (or with modified versions
+ * of Qt that use the same license as Qt), and distribute linked
+ * combinations including the two. You must obey the GNU General
+ * Public License in all respects for all of the code used other than
+ * Qt. If you modify this file, you may extend this exception to
+ * your version of the file, but you are not obligated to do so. If
+ * you do not wish to do so, delete this exception statement from
+ * your version.
+ *
+ */
+
+
+#ifndef KBABELSPLASH_H
+#define KBABELSPLASH_H
+
+#include <qvbox.h>
+
+class QLabel;
+class QMouseEvent;
+class QPaintEvent;
+class QString;
+
+
+class KBabelSplash : public QVBox
+{
+Q_OBJECT
+
+ public:
+ KBabelSplash( QWidget* parent = 0, const char* name = 0 );
+ ~KBabelSplash() { instance = 0; }
+
+ static KBabelSplash* instance;
+
+ protected:
+ void mousePressEvent( QMouseEvent* );
+};
+
+#endif
diff --git a/kbabel/kbabeldict/lo16-app-kbabeldict.png b/kbabel/kbabeldict/lo16-app-kbabeldict.png
new file mode 100644
index 00000000..a296a94f
--- /dev/null
+++ b/kbabel/kbabeldict/lo16-app-kbabeldict.png
Binary files differ
diff --git a/kbabel/kbabeldict/lo32-app-kbabeldict.png b/kbabel/kbabeldict/lo32-app-kbabeldict.png
new file mode 100644
index 00000000..6cc4e301
--- /dev/null
+++ b/kbabel/kbabeldict/lo32-app-kbabeldict.png
Binary files differ
diff --git a/kbabel/kbabeldict/main.cpp b/kbabel/kbabeldict/main.cpp
new file mode 100644
index 00000000..30d5a6c9
--- /dev/null
+++ b/kbabel/kbabeldict/main.cpp
@@ -0,0 +1,136 @@
+/* ****************************************************************************
+ This file is part of KBabel
+
+ Copyright (C) 2000 by Matthias Kiefer
+ <matthias.kiefer@gmx.de>
+ 2003 by Stanislav Visnovsky
+ <visnovsky@kde.org>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the 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, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+ MA 02111-1307, USA.
+
+ In addition, as a special exception, the copyright holders give
+ permission to link the code of this program with any edition of
+ the Qt library by Trolltech AS, Norway (or with modified versions
+ of Qt that use the same license as Qt), and distribute linked
+ combinations including the two. You must obey the GNU General
+ Public License in all respects for all of the code used other than
+ Qt. If you modify this file, you may extend this exception to
+ your version of the file, but you are not obligated to do so. If
+ you do not wish to do so, delete this exception statement from
+ your version.
+
+**************************************************************************** */
+#include <dcopclient.h>
+#include <kaboutdata.h>
+#include <kcmdlineargs.h>
+#include <kcursor.h>
+#include <klocale.h>
+#include <kapplication.h>
+#include <kwin.h>
+
+#include <qtimer.h>
+
+#include "kbabeldict.h"
+#include "kbabelsplash.h"
+#include <version.h>
+
+class KBabelDictApplication : public KApplication
+{
+public:
+ KBabelDictApplication();
+ ~KBabelDictApplication();
+
+private:
+ KBabelDict *topLevel;
+};
+
+KBabelDictApplication::KBabelDictApplication()
+ : KApplication()
+ , topLevel(0)
+{
+ KCmdLineArgs *args = KCmdLineArgs::parsedArgs();
+
+ QTimer timer;
+ QWidget *splash=0;
+ bool showSplash=args->isSet("splash");
+ if(showSplash)
+ {
+ timer.start(2000,true);
+ KApplication::setOverrideCursor(KCursor::waitCursor());
+ splash = new KBabelSplash();
+ splash->show();
+ }
+
+ topLevel = new KBabelDict();
+
+ while(timer.isActive()) // let the user admire the splash screen ;-)
+ processEvents();
+
+ setTopWidget(topLevel);
+ topLevel->show();
+
+ if(KBabelSplash::instance)
+ {
+ delete KBabelSplash::instance;
+ }
+ if(showSplash)
+ {
+ KApplication::restoreOverrideCursor();
+ }
+
+ QObject::connect( topLevel, SIGNAL( destroyed() ),
+ this, SLOT( quit() ) );
+}
+
+KBabelDictApplication::~KBabelDictApplication()
+{
+ delete(topLevel);
+}
+
+static KCmdLineOptions options[] =
+{
+ {"nosplash",I18N_NOOP("Disable splashscreen at startup"),0},
+ KCmdLineLastOption
+};
+
+
+int main(int argc, char **argv)
+{
+ KLocale::setMainCatalogue("kbabel");
+
+ KAboutData about("kbabeldict",I18N_NOOP("KBabel - Dictionary"),VERSION,
+ I18N_NOOP("A dictionary for translators"),KAboutData::License_GPL,
+ I18N_NOOP("(c) 2000,2001,2002,2003 The KBabeldict developers"),0,"http://kbabel.kde.org");
+
+ about.addAuthor("Matthias Kiefer",I18N_NOOP("Original author"),"kiefer@kde.org");
+ about.addAuthor("Stanislav Visnovsky",I18N_NOOP("Current maintainer"),"visnovsky@kde.org");
+
+ about.setTranslator( I18N_NOOP("_: NAME OF TRANSLATORS\nYour names")
+ , I18N_NOOP("_: EMAIL OF TRANSLATORS\nYour emails"));
+
+ // Initialize command line args
+ KCmdLineArgs::init(argc, argv, &about);
+
+ // Tell which options are supported
+ KCmdLineArgs::addCmdLineOptions( options );
+
+ // Add options from other components
+ KApplication::addCmdLineOptions();
+
+ KBabelDictApplication app;
+
+ return app.exec();
+}
diff --git a/kbabel/kbabeldict/modules/Makefile.am b/kbabel/kbabeldict/modules/Makefile.am
new file mode 100644
index 00000000..1807fb23
--- /dev/null
+++ b/kbabel/kbabeldict/modules/Makefile.am
@@ -0,0 +1,7 @@
+
+if include_DBSEARCHENGINE
+DB_SUBDIR=dbsearchengine
+endif
+
+SUBDIRS = pocompendium poauxiliary $(DB_SUBDIR) tmx
+
diff --git a/kbabel/kbabeldict/modules/dbsearchengine/AUTHOR b/kbabel/kbabeldict/modules/dbsearchengine/AUTHOR
new file mode 100644
index 00000000..2a79312d
--- /dev/null
+++ b/kbabel/kbabeldict/modules/dbsearchengine/AUTHOR
@@ -0,0 +1 @@
+Andrea Rizzi <rizzi@kde.org> \ No newline at end of file
diff --git a/kbabel/kbabeldict/modules/dbsearchengine/KDBSearchEngine.cpp b/kbabel/kbabeldict/modules/dbsearchengine/KDBSearchEngine.cpp
new file mode 100644
index 00000000..ac55335d
--- /dev/null
+++ b/kbabel/kbabeldict/modules/dbsearchengine/KDBSearchEngine.cpp
@@ -0,0 +1,1899 @@
+/***************************************************************************
+ KDBSearchEngine.cpp - description
+ -------------------
+ begin : Fri Sep 8 2000
+ copyright : (C) 2000 by Andrea Rizzi
+ (C) 2005 by Stanislav Visnovsky
+ email : rizzi@kde.org
+ ***************************************************************************/
+
+/*
+ Translation search engine
+
+
+ Copyright 2000
+ Andrea Rizzi rizzi@kde.org
+
+ License GPL v 2.0
+ * *
+ * In addition, as a special exception, the copyright holders give *
+ * permission to link the code of this program with any edition of *
+ * the Qt library by Trolltech AS, Norway (or with modified versions *
+ * of Qt that use the same license as Qt), and distribute linked *
+ * combinations including the two. You must obey the GNU General *
+ * Public License in all respects for all of the code used other than *
+ * Qt. If you modify this file, you may extend this exception to *
+ * your version of the file, but you are not obligated to do so. If *
+ * you do not wish to do so, delete this exception statement from *
+ * your version. *
+*/
+
+#include <qtextedit.h>
+#include <qprogressdialog.h>
+
+#include <qinputdialog.h>
+#include <kdeversion.h>
+#include <klocale.h>
+#include <kdebug.h>
+#include <kio/netaccess.h>
+#include <kmessagebox.h>
+#include <kfiledialog.h>
+#include <kurlrequester.h>
+#include <kstandarddirs.h>
+
+#include "kapplication.h"
+#include "KDBSearchEngine.h"
+
+#include "dbscan.h"
+
+#include "errno.h"
+#include "stdio.h"
+#include "stdlib.h"
+#include <sys/time.h>
+#include "preferenceswidget.h"
+#include "dbse_factory.h"
+#include <qprogressbar.h>
+#include <qpushbutton.h>
+#include <klineedit.h>
+#include <kconfig.h>
+
+#include <qdir.h>
+#include <qradiobutton.h>
+#include <qcheckbox.h>
+#include <qspinbox.h>
+#include <qslider.h>
+#include <qmemarray.h>
+
+#include "database.h"
+
+#include "catalogsettings.h"
+
+#define BIGNUMBER 400000000
+
+using namespace KBabel;
+
+KDBSearchEngine::KDBSearchEngine (QObject * parent, const char *name):
+SearchEngine (parent, name)
+{
+ edited = "unknown";
+ dm = 0; //Database Manager
+ pw = 0; //Preference widget
+ lang = "";
+ dbOpened = false;
+ dbname = "";
+ lasterror = i18n ("No error");
+ connect (this, SIGNAL (hasError (const QString &)),
+ SLOT (setLastError (const QString &)));
+
+ IAmReady = true; // I don't know if it is a good idea, no DB loaded!!!
+
+ scanInProgress = false;
+ searching = false;
+ stopNow = false;
+
+ norm = false; // Normalize white space = FALSE
+ comm = true; // Remove Comments = TRUE
+
+}
+
+
+KDBSearchEngine::~KDBSearchEngine ()
+{
+}
+
+
+
+bool
+KDBSearchEngine::loadDatabase (QString database, bool noask = false)
+{
+ bool ret = true;
+ bool asked = false;
+ if (noask)
+ asked = true;
+ if (dm != 0)
+ {
+ delete dm;
+ dm = 0;
+ }
+
+ QDir dir (database);
+ if (!dir.exists ())
+ {
+ if (asked
+ || KMessageBox::questionYesNo (0,
+ i18n
+ ("Database folder does not exist:\n%1\n"
+ "Do you want to create it now?").
+ arg (database), QString::null, i18n("Create Folder"), i18n("Do Not Create")) ==
+ KMessageBox::Yes)
+ {
+ asked = true;
+
+ QStringList dirList;
+ while (!dir.exists () && !dir.dirName ().isEmpty ())
+ {
+ dirList.prepend (dir.dirName ());
+ dir.setPath (dir.path () + "/..");
+ }
+
+ for (QStringList::Iterator it = dirList.begin ();
+ it != dirList.end (); ++it)
+ {
+ if (!dir.mkdir (*it))
+ {
+ KMessageBox::sorry (0,
+ i18n
+ ("It was not possible to create folder %1").
+ arg (dir.path () + "/" +
+ (*it)));
+ ret = false;
+ break;
+ }
+ dir.cd (*it);
+ }
+ }
+ else
+ {
+ ret = false;
+ }
+ }
+
+ if (ret)
+ {
+ // test, if there are both of ,old and standard databases
+ QString transFile = database + "/translations." + lang + ".db";
+
+ bool oldstuff = QFile::exists (transFile + ",old");
+ bool newstuff = QFile::exists (transFile);
+
+ if (oldstuff && newstuff)
+ {
+ // there is an old db2 database, ask user
+
+ if (KMessageBox::
+ questionYesNo (0,
+ i18n
+ ("<p>There are backup database files from previous versions "
+ "of KBabel. However, another version of KBabel (probably from KDE 3.1.1 or 3.1.2) "
+ "created a new database. As a result, your KBabel installation contains two versions "
+ "of database files. Unfortunatelly, the old and new version "
+ "can not be merged. You need to choose one of them.<br/><br/>"
+ "If you choose the old version, the new one will be removed. "
+ "If you choose the new version, the old database files will be left alone "
+ "and you need to remove them manually. Otherwise this message will be displayed "
+ "again (the old files are at $KDEHOME/share/apps/kbabeldict/dbsearchengine/*,old).</p>"),
+ i18n ("Old Database Found"),
+ i18n ("Use &Old Database"),
+ i18n ("Use &New Database")) ==
+ KMessageBox::Yes)
+ {
+ // remove the new files
+ QFile::remove (transFile);
+ QFile::remove (database + "/wordsindex." + lang +
+ ".db");
+ QFile::remove (database + "/keysindex." + lang + ".db");
+ QFile::remove (database + "/catalogsinfo." + lang +
+ ".db");
+
+ // rename the old files
+ KIO::NetAccess::copy (KURL (transFile + ",old"),
+ KURL (transFile), 0);
+ KIO::NetAccess::
+ copy (KURL
+ (database + "/wordsindex." + lang +
+ ".db,old"),
+ KURL (database + "/wordsindex." + lang +
+ ".db"), 0);
+ KIO::NetAccess::
+ copy (KURL
+ (database + "/keysindex." + lang + ".db,old"),
+ KURL (database + "/keysindex." + lang +
+ ".db"), 0);
+ KIO::NetAccess::
+ copy (KURL
+ (database + "/catalogsinfo." + lang +
+ ".db,old"),
+ KURL (database + "/catalogsinfo." + lang +
+ ".db"), 0);
+
+ QFile::remove (transFile + ",old");
+ QFile::remove (database + "/wordsindex." + lang +
+ ".db,old");
+ QFile::remove (database + "/keysindex." + lang +
+ ".db,old");
+ QFile::remove (database + "/catalogsinfo." + lang +
+ ".db,old");
+ }
+ }
+ else if (oldstuff)
+ {
+ // rename the old files
+ KIO::NetAccess::copy (KURL (transFile + ",old"),
+ KURL (transFile), 0);
+ KIO::NetAccess::
+ copy (KURL (database + "/wordsindex." + lang + ".db,old"),
+ KURL (database + "/wordsindex." + lang + ".db"), 0);
+ KIO::NetAccess::
+ copy (KURL (database + "/keysindex." + lang + ".db,old"),
+ KURL (database + "/keysindex." + lang + ".db"), 0);
+ KIO::NetAccess::
+ copy (KURL
+ (database + "/catalogsinfo." + lang + ".db,old"),
+ KURL (database + "/catalogsinfo." + lang + ".db"), 0);
+
+ QFile::remove (transFile + ",old");
+ QFile::remove (database + "/wordsindex." + lang + ".db,old");
+ QFile::remove (database + "/keysindex." + lang + ".db,old");
+ QFile::remove (database + "/catalogsinfo." + lang +
+ ".db,old");
+ }
+
+ dm = new DataBaseManager (database, lang, this, "Database manager");
+
+ if (!dm->isOk ())
+ {
+ if (asked
+ || KMessageBox::questionYesNo (0,
+ i18n
+ ("Database files not found.\nDo you want to create them now?"), QString::null, i18n("Create"), i18n("Do Not Create"))
+ == KMessageBox::Yes)
+ {
+ //fprintf(stderr,"SI\n");
+ ret = dm->createDataBase (database, lang);
+ }
+ else
+ ret = false;
+ }
+ else
+ ret = true;
+ }
+
+//Wrong errore hangdling
+
+ if (ret)
+ totalRecord = dm->count ();
+ else
+ totalRecord = 0;
+
+ return ret;
+}
+
+
+/*
+ Set if the research have to consider multiple spaces as a single one.
+ */
+
+void
+KDBSearchEngine::setNormalizeSpace (bool normalize)
+{
+ norm = normalize;
+}
+
+
+void
+KDBSearchEngine::setRemoveInternalComment (bool internalcomment)
+{
+ comm = internalcomment;
+}
+
+/*
+ Set if the research have to be Case Sensitive or not
+ */
+
+void
+KDBSearchEngine::setCaseSensitive (bool sensitive)
+{
+ sens = sensitive;
+}
+
+/*
+ Set the a string containing all char that must be ignored
+ during the search.
+ */
+
+void
+KDBSearchEngine::setRemoveCharString (QString chartoremove)
+{
+ remchar = chartoremove;
+}
+
+/*
+ Return true if there's a search in progress.
+ */
+bool
+KDBSearchEngine::isSearching () const
+{
+ return searching;
+}
+
+
+
+
+/*
+ Add a search string in the list of the string to search for.
+ Returns the ID of the string in the list.
+ Returns -1 if there is a problem (may be search in progress)
+ */
+
+int
+KDBSearchEngine::addSearchString (QString searchString, int rule)
+{
+ if (searching || scanInProgress)
+ return -1;
+ SearchEntry e;
+ e.string = QString (searchString);
+ e.rules = rule;
+ searchStringList.append (e);
+ return searchStringList.count ();
+}
+
+
+/*
+ Start the research in the database of all the string in the list
+
+ */
+
+bool
+KDBSearchEngine::startSearch (const QString & str, uint pluralForm,
+ const SearchFilter * filter)
+{
+
+ if (autoUpdate)
+ {
+ updateSettings ();
+ }
+
+
+ int l1 = 0, l2 = 0;
+ if (defSub1)
+ l1 = defLimit1;
+ if (defSub2)
+ l2 = defLimit2;
+
+ return startSingleSearch (str, l1, l2);
+
+
+}
+
+bool
+KDBSearchEngine::startSearchInTranslation (QString s)
+{
+
+ if (autoUpdate)
+ {
+ updateSettings ();
+ }
+
+
+ int l1 = 0, l2 = 0;
+ if (defSub1)
+ l1 = defLimit1;
+ if (defSub2)
+ l2 = defLimit2;
+
+
+ return startSingleSearch (s, l1, l2, true);
+
+}
+
+
+bool
+KDBSearchEngine::openDb (bool noask = false)
+{
+ if (!dbOpened)
+ {
+ dbOpened = loadDatabase (dbname, noask); //Try first to open it now
+ if (!dbOpened) // Still not opened!!
+ {
+ hasError (i18n ("Cannot open the database"));
+ return false;
+ }
+ }
+
+ return true;
+}
+
+
+
+
+bool
+KDBSearchEngine::messagesForFilter (const SearchFilter * filter,
+ QValueList < SearchResult > &resultList,
+ QString & error)
+{
+
+ int count = 0;
+ stopNow = false; // Remove dirty.
+ SearchResult m;
+
+ if (searching)
+ {
+ error = i18n ("Another search has already been started");
+ return false;
+ }
+
+ if (scanInProgress)
+ {
+ error =
+ i18n ("Unable to search now: a PO file scan is in progress");
+ return false;
+ }
+
+
+ if (!openDb ())
+ {
+ error = i18n ("Unable to open the database");
+ return false;
+ }
+
+ if (totalRecord <= 0)
+ {
+ error = i18n ("Database empty");
+ return false;
+ }
+
+ QString package = filter->location ();
+
+ int step = (totalRecord / 30) + 1;
+ int ntra, nref;
+ int req = dm->searchCatalogInfo (package);
+ if (req == -1)
+ {
+ error = i18n ("No entry for this package in the database.");
+ return false;
+ }
+ DataBaseItem item;
+ int i, h;
+ kdDebug (0) << "looking for catalog " << req << endl;
+
+ progressStarts (i18n ("Searching for %1 in database").arg (package));
+
+ for (item = dm->firstItem (); !item.isNull (); item = dm->nextItem ())
+ {
+ count++;
+ if (count % step == 0)
+ {
+ emit progress (100 * count / totalRecord);
+ kapp->processEvents (100);
+ }
+ if (stopNow)
+ {
+ stopNow = false;
+ searching = false;
+ emit finished ();
+ return true; // No error, stopped!
+ }
+
+ ntra = item.numTra;
+ for (i = 0; i < ntra; i++)
+ {
+ nref = item.translations[i].numRef;
+
+ for (h = 0; h < nref; h++)
+ {
+ if (item.translations[i].infoRef[h] == req)
+ {
+ m.found = item.key;
+ m.translation = item.translations[i].translation;
+ resultList.append (m);
+ }
+ }
+ }
+
+ }
+
+ return true;
+}
+
+void
+KDBSearchEngine::repeat ()
+{
+
+ int count = 0;
+ stopNow = false; // Remove dirty.
+
+ if (searching)
+ {
+ return;
+ }
+
+ if (scanInProgress)
+ {
+ return;
+ }
+
+
+ if (!openDb ())
+ {
+ return;
+ }
+
+ if (totalRecord <= 0)
+ {
+ return;
+ }
+
+ int step = (totalRecord / 30) + 1;
+ int ntra, nref;
+
+ DataBaseItem item;
+ int i, h, tot;
+
+ int req = dm->searchCatalogInfo ("kdelibs.po");
+ if (req == -1)
+ kdDebug (0) << "No kdelibs.po found!" << endl;
+
+
+ QProgressDialog *pd =
+ new QProgressDialog (i18n ("Looking for repetitions"), i18n ("Stop"),
+ 100);
+
+ connect (this, SIGNAL (progress (int)), pd, SLOT (setProgress (int)));
+ connect (this, SIGNAL (finished ()), pd, SLOT (close ()));
+ connect (pd, SIGNAL (cancelled ()), this, SLOT (stopSearch ()));
+
+
+ QString txt = "// %1 repetitions, %2 translation(s)\ni18n(\"%3\");\n";
+ QString id;
+ int min;
+ bool ok = false;
+
+ min =
+ QInputDialog::getInteger (i18n ("Minimum Repetition"),
+ i18n
+ ("Insert the minimum number of repetitions for a string:"),
+ 2, 1, 999999, 1, &ok);
+
+ if (!ok)
+ return;
+
+ pd->show ();
+
+ progressStarts (i18n ("Searching repeated string"));
+
+ static QTextEdit *mle = new QTextEdit ();
+ mle->clear ();
+
+ bool inlibs;
+
+ for (item = dm->firstItem (); !item.isNull (); item = dm->nextItem ())
+ {
+ count++;
+ if (count % step == 0)
+ {
+ emit progress (100 * count / totalRecord);
+ kapp->processEvents (100);
+ }
+ if (stopNow)
+ {
+ stopNow = false;
+ searching = false;
+ emit finished ();
+ return; // No error, stopped!
+ }
+ tot = 0;
+ inlibs = false;
+ ntra = item.numTra;
+ for (i = 0; i < ntra; i++)
+ {
+ nref = item.translations[i].numRef;
+ for (h = 0; h < nref; h++)
+ if (item.translations[i].infoRef[h] == req)
+ inlibs = true;
+
+ tot += nref;
+ }
+
+ if (tot >= min && !inlibs)
+ {
+ id = item.key;
+ id = id.replace ("\n", "\"\n\"");
+ mle->append (txt.arg (tot).arg (ntra).arg (id));
+
+ }
+ }
+
+
+ emit progress (100);
+ emit finished ();
+ mle->resize (400, 400);
+ mle->show ();
+
+ delete pd;
+ return;
+}
+
+
+
+bool
+KDBSearchEngine::startSearchNow (int searchmode)
+{
+ if (searchmode == -1)
+ searchmode = mode;
+ int count = 0;
+ stopNow = false; // Remove dirty.
+ clearResults ();
+
+
+ if (searching)
+ {
+ hasError (i18n ("Another search has already been started"));
+ return false;
+ }
+
+ if (scanInProgress)
+ {
+ hasError (i18n
+ ("Unable to search now: a PO file scan is in progress"));
+ return false;
+ }
+
+
+ if (!openDb ())
+ return false;
+
+
+ if (totalRecord <= 0)
+ {
+ hasError (i18n ("Database empty"));
+ return false;
+ }
+
+
+
+ searching = true;
+
+ emit started ();
+
+ bool allkey = (searchmode == MD_ALL_GOOD_KEYS);
+
+ bool equal, contains, contained, regexp, intra;
+
+ intra = searchmode & MD_IN_TRANSLATION;
+
+ QString msgIdFound;
+ QString msgId;
+ QString msgStr;
+ //QString msgIdRequested;
+ SearchResult *aresult;
+ TranslationInfo *adescription;
+ SearchList searchList;
+ int i, len, files, h;
+ len = remchar.length ();
+
+ int n, m; //,word;
+ QString *id;
+
+ QString mainRequest = searchStringList[0].string;
+
+
+ SearchList::Iterator it, it1;
+ QString *idMod;
+ bool foundSomething = false;
+
+ searchList = searchStringList; //Create a copy and modify it
+ if (!allkey)
+ {
+ for (it = searchList.begin (); it != searchList.end (); ++it)
+ {
+ idMod = &((*it).string);
+ int pos;
+ for (i = 0; i < len; i++)
+ {
+ while ((pos = idMod->find (remchar.at (i))) != -1)
+ idMod->remove (pos, 1);
+ }
+
+ if (comm)
+ idMod->replace (QRegExp ("\\_\\:.*\\\\n"), ""); //Read it from catalog !!! (NOT ONLY HERE)
+
+
+ if (norm)
+ idMod->simplifyWhiteSpace ();
+ if (!sens)
+ *idMod = idMod->upper ();
+ }
+
+ }
+
+ timeval now;
+ gettimeofday (&now, NULL);
+ //fprintf(stderr,"\n%ld.%ld\n",now.tv_sec,now.tv_usec);
+ //double tim=1.0*now.tv_usec/1000000.0+now.tv_sec;
+ int pos;
+
+
+
+ DataBaseItem item;
+
+
+ //Now we can browse the whole db or the "good keys"
+ QValueList < KeyAndScore > goodkeys;
+ int totalprogress;
+
+ bool gk = (searchmode == MD_GOOD_KEYS) || allkey;
+ int k = 0;
+
+ if (gk)
+ {
+ goodkeys = searchWords (mainRequest, thre, threorig, listmax); //FIX IT, mainReq?
+ if (stopNow)
+ {
+ stopNow = false;
+ searching = false;
+ emit finished ();
+ return false;
+ }
+ if (goodkeys.count () == 0)
+ gk = false; // if no good keys, use the whole database
+ }
+
+ // prepare progress values
+ totalprogress = gk ? goodkeys.count () : totalRecord;
+ int step = (totalprogress / 30) + 1;
+ if( step > 100 )
+ step = 100;
+
+ emit progress (0);
+ kapp->processEvents (100);
+ if (stopNow)
+ {
+ stopNow = false;
+ searching = false;
+ emit finished ();
+ return true; // No error, stopped!
+ }
+
+
+ for (item = gk ? (dm->getItem (goodkeys[0])) : (dm->firstItem ());
+ !item.isNull ();
+ item = gk ? (dm->getItem (goodkeys[++k])) : (dm->nextItem ()))
+ {
+
+// Emit progress, process event and check stop now
+ if (count % step == 0)
+ {
+ emit progress (100 * count / /*QMAX( */
+ totalprogress /*,1) */ );
+ kapp->processEvents (100);
+
+ if (stopNow)
+ {
+ stopNow = false;
+ searching = false;
+ emit finished ();
+ return true; // No error, stopped!
+ }
+ }
+
+ // fprintf(stderr,"%s\n",(const char *)item.key.utf8());
+ msgIdFound = item.key; //Check if this is OK with UTF8
+
+// searchmode && MD_IN_TRANSLATION)
+
+ count++;
+
+
+
+ msgId = msgIdFound;
+
+ if (!allkey)
+ {
+
+ //Remove character in list of character to be ignored
+ for (i = 0; i < len; i++)
+ while ((pos = msgId.find (remchar.at (i))) != -1)
+ msgId.remove (pos, 1);
+
+ //Remove context information from id found
+ if (comm)
+ msgId.replace (QRegExp ("\\_\\:.*\\\\n"), "");
+
+
+ if (norm)
+ msgId.simplifyWhiteSpace ();
+ if (!sens)
+ msgId = msgId.upper ();
+ }
+
+
+
+ it = searchList.begin ();
+ idMod = &((*it).string);
+ bool foundExact = false;
+
+ for (it1 = searchStringList.begin ();
+ it1 != searchStringList.end (); it1++)
+ {
+
+ id = &((*it1).string);
+ uint nn = 0;
+ do
+ {
+ if (intra)
+ {
+ msgId = item.translations[nn].translation;
+ if (!allkey)
+ {
+ //Remove character in list of character to be ignored
+ for (i = 0; i < len; i++)
+ while ((pos =
+ msgId.find (remchar.at (i))) !=
+ -1)
+ msgId.remove (pos, 1);
+
+ //Remove context information from id found
+ if (comm)
+ msgId.
+ replace (QRegExp ("\\_\\:.*\\\\n"),
+ "");
+
+
+ if (norm)
+ msgId.simplifyWhiteSpace ();
+ if (!sens)
+ msgId = msgId.upper ();
+ }
+
+
+ }
+
+
+ int rules = (*it).rules;
+
+ if (rules & Equal)
+ equal = (*idMod == msgId);
+ else
+ equal = false;
+
+ if (rules & Contains)
+ contains = idMod->contains (msgId);
+ else
+ contains = false;
+
+ if (rules & Contained)
+ contained = msgId.contains (*idMod);
+ else
+ contained = false;
+
+ if (!foundExact && (rules & RegExp))
+ {
+ QRegExp reg (*idMod);
+ regexp = (reg.search (msgId) != -1);
+ }
+ else
+ regexp = false;
+ nn++;
+ }
+ while (intra && nn < item.numTra);
+
+ if (equal || contains || contained || regexp || allkey)
+ {
+
+ if (equal)
+ foundExact = true;
+
+ m = item.numTra; //Translations found.
+
+ for (n = 0; n < m; n++)
+ {
+
+ foundSomething = true;
+
+
+ msgStr = item.translations[n].translation;
+
+ files = item.translations[n].numRef;
+
+ aresult = new SearchResult ();
+
+ results.setAutoDelete (true);
+ if (!gk)
+ aresult->score =
+ score (mainRequest, msgIdFound);
+ else
+ aresult->score = goodkeys[k].score;
+
+ if (intra)
+ aresult->score =
+ score (mainRequest,
+ item.translations[n].translation);
+
+
+ SearchResult *s = 0;
+ for (s = results.first (); s != 0;
+ s = results.next ())
+ {
+ if (s->score > aresult->score)
+ {
+ results.insert (results.at (),
+ aresult);
+ break;
+ }
+
+ }
+ if (s == 0) //no break or empty list
+ results.append (aresult);
+
+
+/* if(*id==msgIdFound) //Put it first of the list
+ results.prepend(aresult);
+ else
+ results.append(aresult);
+*/
+ aresult->requested = *id;
+ aresult->found = msgIdFound;
+ aresult->translation = msgStr;
+ aresult->descriptions.setAutoDelete (true);
+ for (h = 0; h < files; h++)
+ {
+
+ aresult->descriptions.append (adescription =
+ new
+ TranslationInfo
+ ());
+ int rr = item.translations[n].infoRef[h];
+
+ InfoItem info = dm->getCatalogInfo (rr);
+
+
+ adescription->location = info.catalogName;
+ adescription->translator =
+ info.lastTranslator;
+ adescription->filePath = info.lastFullPath;
+ }
+
+ emit numberOfResultsChanged (results.count ());
+ emit resultFound (aresult);
+
+// if(*id==msgIdFound) //Put it first of the list so th order change
+ emit resultsReordered ();
+
+
+
+ }
+ }
+ // idMod=searchList.next();
+ it++;
+ idMod = &((*it).string);
+ }
+
+
+ }
+ gettimeofday (&now, NULL);
+ //fprintf(stderr,"%ld.%ld\n",now.tv_sec,now.tv_usec);
+
+ //fprintf(stderr,"Finish, %d (of %d) records in %f seconds!!\n",count,totalRecord, 1.0*now.tv_usec/1000000.0+now.tv_sec-tim);
+ emit progress (100);
+ emit finished ();
+
+ searching = false;
+ return true; //foundSomething;
+}
+
+/*
+ Start a search for a single string
+ */
+
+bool
+KDBSearchEngine::startSingleSearch (QString searchString,
+ unsigned int pattern1Limit,
+ unsigned int /*pattern2Limit */ ,
+ bool inTranslation)
+{
+ /*
+ Check Ret
+ value.
+ */
+
+ unsigned int nw = 0;
+ int in = 0, len = 0;
+ clearList ();
+ addSearchString (searchString, defRule);
+
+
+
+ QRegExp reg ("[a-zA-Z0-9_%" /*+remchar */ + regaddchar + "]+");
+ while ((in = reg.search (searchString, in + len)) != -1)
+ {
+ nw++;
+ len = reg.matchedLength ();
+ }
+ in = 0;
+ len = 0;
+ // fprintf(stderr,"asas %d\n",nw);
+
+ if (mode == MD_ALL_GOOD_KEYS && !inTranslation)
+ return startSearchNow ();
+
+
+
+ if ((nw < pattern1Limit) && (nw > 1))
+ for (unsigned int k = 0; k < nw; k++)
+ {
+ in = reg.search (searchString, in + len);
+ len = reg.matchedLength ();
+ QString regToAdd = searchString;
+ regToAdd.replace (in, len, "[a-zA-Z0-9_%" + regaddchar + "]*");
+ regToAdd.append ("$");
+ regToAdd.prepend ("^");
+// fprintf(stderr,"%s",(const char *)regToAdd.local8Bit());
+ addSearchString (regToAdd, RegExp);
+ }
+
+ if (inTranslation)
+ return startSearchNow (MD_IN_TRANSLATION);
+ else
+ return startSearchNow ();
+
+ return false;
+
+}
+
+
+/*
+ Start a search for a list of string
+ */
+
+//bool KDBSearchEngine::startListSearch(QPtrList<QString> searchStrList)
+//{
+ // searchStringList=searchStrList;
+// return startSearchNow();
+//}
+/*
+ Stop the current search
+ */
+
+
+
+void
+KDBSearchEngine::setLanguageCode (const QString & ll)
+{
+ if (ll == lang)
+ return;
+
+ lang = ll;
+ if (dbOpened) //if opened open it again with new code, what about close before open ?
+ dbOpened = loadDatabase (dbname);
+
+}
+
+void
+KDBSearchEngine::setLanguage (const QString & languageCode,
+ const QString & /*languageName */ )
+{
+ setLanguageCode (languageCode);
+}
+
+void
+KDBSearchEngine::stopSearch ()
+{
+ stopNow = true;
+}
+
+
+void
+KDBSearchEngine::clearList ()
+{
+ searchStringList.clear ();
+}
+
+bool
+KDBSearchEngine::isReady () const
+{
+ return IAmReady;
+}
+
+
+void
+KDBSearchEngine::saveSettings (KConfigBase * config)
+{
+// updateSettings(); //maybe with autoupdate
+ KConfigGroupSaver cgs (config, "KDBSearchEngine");
+#if KDE_IS_VERSION(3,1,3)
+ config->writePathEntry ("Filename", dbname);
+#else
+ config->writeEntry ("Filename", dbname);
+#endif
+ config->writeEntry ("Language", lang);
+
+
+ config->writeEntry ("CaseSensitive", sens);
+ config->writeEntry ("Normalize", norm);
+ config->writeEntry ("RemoveContext", comm);
+
+ config->writeEntry ("Rules", defRule);
+ config->writeEntry ("Limit1", defLimit1);
+ config->writeEntry ("Limit2", defLimit2);
+ config->writeEntry ("Substitution1", defSub1);
+ config->writeEntry ("Substitution2", defSub2);
+
+ config->writeEntry ("RegExp", regaddchar);
+ config->writeEntry ("RemoveCharacter", remchar);
+
+ config->writeEntry ("Threshold1", thre);
+ config->writeEntry ("Threshold2", threorig);
+ config->writeEntry ("ListMax", listmax);
+ config->writeEntry ("Mode", mode);
+ config->writeEntry ("CommonThrs", commonthre);
+ config->writeEntry ("ReturnNothing", retnot);
+
+ config->writeEntry ("AutoAuthor", autoauthor);
+ config->writeEntry ("AutoUp", autoup);
+
+}
+
+
+void
+KDBSearchEngine::readSettings (KConfigBase * config)
+{
+ QString newName;
+
+ KConfigGroupSaver cgs (config, "KDBSearchEngine");
+
+ QString defaultLang;
+ QString oldLang = lang;
+ Defaults::Identity def;
+ defaultLang = def.languageCode ();
+ lang = config->readEntry ("Language", defaultLang);
+
+ QString defaultDir;
+ KStandardDirs *dirs = KGlobal::dirs ();
+ if (dirs)
+ {
+ defaultDir = dirs->saveLocation ("data");
+ if (defaultDir.right (1) != "/")
+ defaultDir += "/";
+ defaultDir += "kbabeldict/dbsearchengine";
+ }
+
+ newName = config->readPathEntry ("Filename", defaultDir);
+
+ if (newName != dbname || oldLang != lang)
+ {
+ dbname = newName;
+ if (dbOpened) //Reload only if it is opened
+ dbOpened = loadDatabase (dbname);
+ }
+
+ sens = config->readBoolEntry ("CaseSensitive", false);
+ norm = config->readBoolEntry ("Normalize", true);
+ comm = config->readBoolEntry ("RemoveContext", true);
+
+ defRule = config->readNumEntry ("Rules", 1);
+ defLimit1 = config->readNumEntry ("Limit1", 20);
+ defLimit2 = config->readNumEntry ("Limit2", 8);
+
+ thre = config->readNumEntry ("Threshold1", 50);
+ threorig = config->readNumEntry ("Threshold2", 50);
+ listmax = config->readNumEntry ("ListMax", 500);
+ mode = config->readNumEntry ("Mode", MD_GOOD_KEYS);
+
+ defSub1 = config->readBoolEntry ("Substitution1", true);
+ defSub2 = config->readBoolEntry ("Substitution2", false);
+
+ regaddchar = config->readEntry ("RegExp");
+ remchar = config->readEntry ("RemoveCharacter", "&.:");
+ commonthre = config->readNumEntry ("CommonThrs", 300);
+ retnot = config->readBoolEntry ("ReturnNothing", false);
+ autoauthor = config->readEntry ("AutoAuthor");
+ autoup = config->readBoolEntry ("AutoUp", true);
+
+ setSettings ();
+}
+
+PrefWidget *
+KDBSearchEngine::preferencesWidget (QWidget * parent)
+{
+
+ pw = new PreferencesWidget (parent);
+ setSettings ();
+ connect (pw, SIGNAL (restoreNow ()), this, SLOT (setSettings ()));
+ connect (pw, SIGNAL (applyNow ()), this, SLOT (updateSettings ()));
+ connect (pw, SIGNAL (destroyed ()), this, SLOT (prefDestr ()));
+ connect (pw->dbpw->scanPB_2, SIGNAL (clicked ()), this, SLOT (scan ()));
+ connect (pw->dbpw->scanrecPB, SIGNAL (clicked ()), this,
+ SLOT (scanRecur ()));
+ connect (pw->dbpw->scanFilePB, SIGNAL (clicked ()), this,
+ SLOT (scanFile ()));
+ connect (pw->dbpw->repeatPB, SIGNAL (clicked ()), this, SLOT (repeat ()));
+
+
+ return pw;
+}
+
+void
+KDBSearchEngine::scanRecur ()
+{
+ if (scanInProgress)
+ return;
+ updateSettings ();
+
+ if (!openDb ())
+ return;
+ scanInProgress = true;
+ PoScanner *sca = new PoScanner (dm, this, "Po Scanner");
+ QString cvsdir;
+ cvsdir =
+ KFileDialog::getExistingDirectory ("", 0,
+ i18n
+ ("Select Folder to Scan Recursively"));
+
+ if (cvsdir.isEmpty ())
+ {
+ scanInProgress = false;
+ return;
+ }
+ if (pw)
+ {
+ connect (sca, SIGNAL (patternProgress (int)), pw->dbpw->totalPB,
+ SLOT (setProgress (int)));
+ connect (sca, SIGNAL (fileLoading (int)), pw->dbpw->loadingPB,
+ SLOT (setProgress (int)));
+ connect (sca, SIGNAL (fileProgress (int)), pw->dbpw->processPB,
+ SLOT (setProgress (int)));
+ }
+
+ connect (sca, SIGNAL (patternProgress (int)), SIGNAL (progress (int))); //Kbabel progress bar
+
+ connect (sca, SIGNAL (added (int)), pw, SLOT (setEntries (int)));
+ connect (sca, SIGNAL (filename (QString)), pw, SLOT (setName (QString)));
+
+
+ progressStarts (i18n ("Scanning folder %1").arg (cvsdir));
+ connect (sca, SIGNAL (patternFinished ()), SIGNAL (progressEnds ()));
+
+ sca->scanPattern (cvsdir, "*.po", true);
+ disconnect (this, SIGNAL (progress (int)));
+//disconnect(SIGNAL(patternStarted()),this,SIGNAL(started()) );
+ disconnect (this, SIGNAL (progressEnds ()));
+ if (pw)
+ {
+ disconnect (pw->dbpw->totalPB, SLOT (setProgress (int)));
+ disconnect (pw->dbpw->loadingPB, SLOT (setProgress (int)));
+ disconnect (pw->dbpw->processPB, SLOT (setProgress (int)));
+ }
+ totalRecord = dm->count ();
+
+ scanInProgress = false;
+ dm->sync ();
+ delete sca;
+}
+
+
+void
+KDBSearchEngine::scan ()
+{
+ if (scanInProgress)
+ return;
+ updateSettings ();
+
+ if (!openDb ())
+ return;
+ scanInProgress = true;
+ PoScanner *sca = new PoScanner (dm, this, "Po Scanner");
+ QString cvsdir;
+
+ cvsdir =
+ KFileDialog::getExistingDirectory ("", 0,
+ i18n ("Select Folder to Scan"));
+ if (cvsdir.isEmpty ())
+ {
+ scanInProgress = false;
+ return;
+ }
+ if (pw)
+ {
+ connect (sca, SIGNAL (patternProgress (int)), pw->dbpw->totalPB,
+ SLOT (setProgress (int)));
+ connect (sca, SIGNAL (fileLoading (int)), pw->dbpw->loadingPB,
+ SLOT (setProgress (int)));
+ connect (sca, SIGNAL (fileProgress (int)), pw->dbpw->processPB,
+ SLOT (setProgress (int)));
+ }
+ connect (sca, SIGNAL (patternProgress (int)), SIGNAL (progress (int)));
+ progressStarts (i18n ("Scanning folder %1").arg (cvsdir));
+ connect (sca, SIGNAL (patternFinished ()), SIGNAL (progressEnds ()));
+
+ connect (sca, SIGNAL (added (int)), pw, SLOT (setEntries (int)));
+ connect (sca, SIGNAL (filename (QString)), pw, SLOT (setName (QString)));
+
+
+
+ sca->scanPattern (cvsdir, "*.po", false);
+
+ disconnect (this, SIGNAL (progress (int)));
+//disconnect(SIGNAL(patternStarted()),this,SIGNAL(started()) );
+ disconnect (this, SIGNAL (progressEnds ()));
+ if (pw)
+ {
+ disconnect (pw->dbpw->totalPB, SLOT (setProgress (int)));
+ disconnect (pw->dbpw->loadingPB, SLOT (setProgress (int)));
+ disconnect (pw->dbpw->processPB, SLOT (setProgress (int)));
+ }
+ totalRecord = dm->count ();
+
+ scanInProgress = false;
+
+ dm->sync ();
+ delete sca;
+}
+
+void
+KDBSearchEngine::scanFile ()
+{
+ if (scanInProgress)
+ return;
+ updateSettings ();
+
+ if (!openDb ())
+ return;
+ scanInProgress = true;
+ PoScanner *sca = new PoScanner (dm, this, "Po Scanner");
+ QString cvsdir;
+ pw->dbpw->totalPB->setProgress (0);
+
+ cvsdir =
+ KFileDialog::getOpenFileName ("", "*.po", 0,
+ i18n ("Select PO File to Scan"));
+ if (cvsdir.isEmpty ())
+ {
+ scanInProgress = false;
+ return;
+ }
+ if (pw)
+ {
+ connect (sca, SIGNAL (fileLoading (int)), pw->dbpw->loadingPB,
+ SLOT (setProgress (int)));
+ connect (sca, SIGNAL (fileProgress (int)), pw->dbpw->processPB,
+ SLOT (setProgress (int)));
+ }
+ connect (sca, SIGNAL (fileProgress (int)), SIGNAL (progress (int)));
+ progressStarts (i18n ("Scanning file %1").arg (directory (cvsdir, 0)));
+ connect (sca, SIGNAL (fileFinished ()), SIGNAL (progressEnds ()));
+
+ connect (sca, SIGNAL (added (int)), pw, SLOT (setEntries (int)));
+ connect (sca, SIGNAL (filename (QString)), pw, SLOT (setName (QString)));
+
+
+
+ sca->scanFile (cvsdir);
+
+ sca->disconnect (SIGNAL (fileProgress (int)), this,
+ SIGNAL (progress (int)));
+//disconnect(SIGNAL(patternStarted()),this,SIGNAL(started()) );
+ sca->disconnect (SIGNAL (fileFinished ()), this,
+ SIGNAL (progressEnds ()));
+ if (pw)
+ {
+ disconnect (pw->dbpw->loadingPB, SLOT (setProgress (int)));
+ disconnect (pw->dbpw->processPB, SLOT (setProgress (int)));
+ }
+
+ totalRecord = dm->count ();
+
+ scanInProgress = false;
+
+ dm->sync ();
+ delete sca;
+}
+
+const KAboutData *
+KDBSearchEngine::about () const
+{
+
+ return DbSeFactory::instance ()->aboutData ();
+
+}
+
+QString
+KDBSearchEngine::name () const
+{
+ return i18n ("Translation Database");
+}
+
+QString
+KDBSearchEngine::id () const
+{
+ return QString ("KDBSearchEngine");
+}
+
+QString
+KDBSearchEngine::lastError ()
+{
+ return lasterror;
+}
+
+void
+KDBSearchEngine::prefDestr ()
+{
+ pw = 0;
+}
+
+
+void
+KDBSearchEngine::setSettings ()
+{
+
+ if (pw == 0)
+ return;
+
+ pw->dbpw->dirInput->setURL (dbname);
+ pw->dbpw->caseSensitiveCB->setChecked (sens);
+ pw->dbpw->normalizeCB->setChecked (norm);
+ pw->dbpw->removeContextCB->setChecked (comm);
+
+ pw->dbpw->oneWordSubCB->setChecked (defSub1);
+ pw->dbpw->twoWordSubCB->setChecked (defSub2);
+
+
+ if (defRule == 8)
+ pw->dbpw->RegExpRB->setChecked (true);
+ else
+ {
+ pw->dbpw->normalTextRB->setChecked (true);
+ pw->dbpw->equalCB->setChecked (defRule & Equal);
+ pw->dbpw->containsCB->setChecked (defRule & Contains);
+ pw->dbpw->containedCB->setChecked (defRule & Contained);
+ }
+
+ pw->dbpw->oneWordSubSB->setValue (defLimit1);
+ pw->dbpw->twoWordSubSB->setValue (defLimit2);
+
+ pw->dbpw->maxSB->setValue (listmax);
+ pw->dbpw->thresholdSL->setValue (thre);
+ pw->dbpw->thresholdOrigSL->setValue (threorig);
+
+ pw->dbpw->allRB->setChecked (mode == MD_ALL_DB);
+ pw->dbpw->slistRB->setChecked (mode == MD_GOOD_KEYS);
+ pw->dbpw->rlistRB->setChecked (mode == MD_ALL_GOOD_KEYS);
+
+ pw->dbpw->nothingCB->setChecked (retnot);
+ pw->dbpw->freqSB->setValue (commonthre);
+
+ pw->dbpw->regExpLE->setText (regaddchar);
+ pw->dbpw->ignoreLE->setText (remchar);
+
+ pw->dbpw->authorLE->setText (autoauthor);
+ pw->dbpw->autoAddCB_2->setChecked (autoup);
+
+
+
+}
+
+
+void
+KDBSearchEngine::updateSettings ()
+{
+ if (pw == 0)
+ return;
+
+ QString newName = pw->dbpw->dirInput->url ();
+
+ if (newName != dbname)
+ {
+ kdDebug (0) << "Database changed" << endl;
+ dbname = newName;
+ if (dbOpened)
+ dbOpened = loadDatabase (dbname);
+ }
+
+ sens = pw->dbpw->caseSensitiveCB->isChecked ();
+ norm = pw->dbpw->normalizeCB->isChecked ();
+ comm = pw->dbpw->removeContextCB->isChecked ();
+
+ int tmpRule = 0;
+ if (pw->dbpw->RegExpRB->isChecked ())
+ tmpRule = RegExp;
+ else
+ {
+ if (pw->dbpw->equalCB->isChecked ())
+ tmpRule += Equal;
+ if (pw->dbpw->containsCB->isChecked ())
+ tmpRule += Contains;
+ if (pw->dbpw->containedCB->isChecked ())
+ tmpRule += Contained;
+ }
+
+ defRule = tmpRule;
+
+ defLimit1 = pw->dbpw->oneWordSubSB->text ().toInt ();
+ defLimit2 = pw->dbpw->twoWordSubSB->text ().toInt ();
+ defSub1 = pw->dbpw->oneWordSubCB->isChecked ();
+ defSub2 = pw->dbpw->twoWordSubCB->isChecked ();
+
+ listmax = pw->dbpw->maxSB->value ();
+ thre = pw->dbpw->thresholdSL->value ();
+ threorig = pw->dbpw->thresholdOrigSL->value ();
+
+ if (pw->dbpw->allRB->isChecked ())
+ mode = MD_ALL_DB;
+ if (pw->dbpw->slistRB->isChecked ())
+ mode = MD_GOOD_KEYS;
+ if (pw->dbpw->rlistRB->isChecked ())
+ mode = MD_ALL_GOOD_KEYS;
+
+
+ regaddchar = pw->dbpw->regExpLE->text ();
+ remchar = pw->dbpw->ignoreLE->text ();
+
+ retnot = pw->dbpw->nothingCB->isChecked ();
+ commonthre = pw->dbpw->freqSB->value ();
+
+ autoauthor = pw->dbpw->authorLE->text ();
+ autoup = pw->dbpw->autoAddCB_2->isChecked ();
+
+
+}
+
+void
+KDBSearchEngine::setLastError (const QString & er)
+{
+ lasterror = er;
+}
+
+QString
+KDBSearchEngine::translate (const QString & text, const uint pluralForm)
+{
+ if (!openDb ())
+ return QString::null;
+/*
+
+if(!dbOpened)
+ {
+ dbOpened=loadDatabase(dbname); //Try first to open it now
+ if(!dbOpened) // Still not opened!!
+ {
+ //emit anerror
+ hasError(i18n("Database not opened"));
+ return QString::null;
+ }
+ }
+*/
+
+ DataBaseItem dbit = dm->getItem (text);
+
+ if (dbit.isNull ())
+ return QString::null;
+ if (dbit.numTra == 1)
+ return dbit.translations[0].translation;
+
+ uint32 n = dbit.numTra;
+ uint32 max = 0, nmax = 0;
+ for (uint32 i = 0; i < n; i++)
+ if (dbit.translations[i].numRef > max)
+ {
+ nmax = i;
+ max = dbit.translations[i].numRef;
+ }
+
+ return dbit.translations[nmax].translation;
+
+
+}
+
+QValueList < KeyAndScore > KDBSearchEngine::searchWords (QString phrase,
+ int threshold,
+ int thresholdorig,
+ uint32 max)
+{
+ QValueList < QString > wordlist;
+
+ if (!openDb ())
+ {
+ QValueList < KeyAndScore > a;
+ return a;
+ }
+
+ progressStarts (i18n ("Searching words"));
+
+ QValueList < QString >::Iterator wlit;
+ wordlist = dm->wordsIn (phrase);
+ int
+ nw = wordlist.count ();
+//QMemArray<WordItem> wi(nw);
+ QMemArray < uint32 > numofloc (nw), currentloc (nw);
+ QMemArray < int >
+ score (nw);
+ QMemArray < uint32 * >loc (nw), locorig (nw);
+ QValueList < uint32 > resloc;
+ QValueList < int >
+ resfound;
+ QValueList < KeyAndScore > keylist;
+//wi.resize(wordlist.count());
+ int
+ totalprogress = 0;
+ int
+ totrec = dm->count ();
+ uint32
+ cthre = totrec * commonthre / 10000;
+ int
+ i = 0, common = 0;
+ for (wlit = wordlist.begin (); wlit != wordlist.end (); ++wlit)
+ {
+ WordItem
+ wi = dm->getWordLocations (*wlit);
+ if (!wi.notFound ())
+ {
+ if (wi.count < cthre)
+ score[i] = 1;
+ else
+ {
+ score[i] = 0;
+ common++;
+ }
+
+ locorig[i] = loc[i] = wi.locations;
+ totalprogress += numofloc[i] = wi.count;
+ currentloc[i] = 0;
+// score[i]=wi.score;
+ //wi[i]=WordItem(wi[i]);
+ //wi[i].locations.detach();
+ i++;
+// }
+ // else
+ // common++;
+
+
+
+ }
+ }
+ bool
+ cs = (common == nw); //All words are common;
+ if (totalprogress == 0)
+ totalprogress = 1;
+ int
+ step = totalprogress / 30 + 1;
+ int
+ count = 0;
+ int
+ thrs = (wordlist.count () * threshold) / 100;
+ if (thrs < 1)
+ thrs = 1; // whole database ???
+
+ int
+ tot = i;
+//nt32 jmin=0;
+ int
+ found;
+ uint32
+ min; //Big ?
+ bool
+ empty = false;
+
+
+ while (!empty)
+ {
+
+ empty = true;
+ found = retnot ? common : 0;
+ if (thrs <= found)
+ thrs = found + 1; // whole database ???
+
+ min = BIGNUMBER;
+ for (int j = 0; j < tot; j++)
+ if (cs || score[j])
+ {
+ if (numofloc[j] > currentloc[j]) // Check if there's still something to do.
+ empty = false;
+ if (loc[j][0] < min) //Found the minimum head
+ min = loc[j][0];
+
+
+ }
+ if (min != BIGNUMBER)
+ {
+ for (int j = 0; j < tot; j++)
+ if (cs || score[j])
+ {
+ if (loc[j][0] == min) //Count the heads, move forward
+ {
+ found++;
+ count++;
+ //check stopnow here
+ if (count % step == 0)
+ {
+ emit
+ progress (100 * count / totalprogress);
+ kapp->processEvents (100);
+ }
+ if (stopNow)
+ {
+ return keylist;
+ }
+
+ currentloc[j]++;
+ if (numofloc[j] == currentloc[j]) //End reached
+ loc[j][0] = BIGNUMBER; //so set head to a big number
+ else //Go on..
+ {
+ loc[j]++;
+ }
+ }
+ } //end of for
+ bool
+ inserted = false;
+
+
+
+ if (found >= thrs)
+ {
+ //Words count in key.
+ int
+ nword = 0;
+
+ int
+ in = 0, len = 0;
+ QString
+ keyst = dm->getKey (min);
+ QRegExp
+ reg ("[a-zA-Z0-9_%" /*+remchar */ + regaddchar + "]+");
+ while ((in = reg.search (keyst, in + len)) != -1)
+ {
+ nword++;
+ len = reg.matchedLength ();
+ }
+
+ if (found >= nword * thresholdorig / 100) //
+ {
+
+ if (resfound.count () <= max
+ || (*resfound.end () < found))
+ if ((*resfound.end ()) >= found)
+ {
+ inserted = true;
+ resloc.append (min);
+ resfound.append (found);
+
+ }
+ else
+ for (uint32 j = 0; j < resloc.count ();
+ j++)
+ {
+ if (resfound[j] < found || (resfound[j] == found && 0)) //Orig word
+ {
+ resloc.insert (resloc.at (j),
+ min);
+ resfound.insert (resfound.
+ at (j),
+ found);
+ inserted = true;
+ break;
+ }
+ }
+ if (!inserted)
+ {
+ resloc.append (min);
+ resfound.append (found);
+ }
+
+ }
+ }
+
+ }
+
+ }
+ int
+ nres = (resloc.count () < max) ? resloc.count () : max;
+
+ for (int j = 0; j < nres; j++)
+ {
+ QString
+ strkey = dm->getKey (resloc[j]);
+ int
+ stdscore = KDBSearchEngine::score (phrase, strkey);
+ int
+ sc = 0;
+
+ if (stdscore < 99)
+ {
+ int
+ in = 0, len = 0, nword = 0;
+ int
+ remove = retnot ? common : 0;
+ QRegExp
+ reg ("[a-zA-Z0-9_%" /*+remchar */ + regaddchar + "]+");
+ while ((in = reg.search (strkey, in + len)) != -1)
+ {
+ nword++;
+ len = reg.matchedLength ();
+ }
+
+// kdDebug(0) << nword << "NWORD " << resfound[j] << "FOUND "
+// << resfound[j]-remove << "REAL " << remove << "to be remove " << endl;
+ if (nword < 1)
+ nword = 1;
+ sc = 70 - resfound[j] * 70 / nw + abs (nword -
+ (resfound[j] -
+ remove)) * 30 /
+ nword + 2;
+ sc = 100 - sc;
+// kdDebug(0) <<" Score : " << sc << endl;
+
+ }
+ else
+ sc = stdscore;
+
+ KeyAndScore
+ key (strkey, sc);
+
+// kdDebug(0) << (QString) key << " [" << key.score << "]" << endl;
+ keylist.append (key);
+ }
+
+//kdDebug(0) << "Here!" << endl;
+
+ for (int j = 0; j < tot; j++)
+ {
+ free (locorig[j]);
+ }
+ progressStarts (i18n ("Process output"));
+ return keylist;
+}
+
+void
+KDBSearchEngine::stringChanged (const QStringList & o,
+ const QString & translated, const uint,
+ const QString &)
+{
+
+ QString orig = o.first (); // FIXME: plural forms
+
+ // skip empty originals or translated texts
+ if (orig.isEmpty () || translated.isEmpty ())
+ return;
+
+ if (autoup)
+ {
+ if (openDb (true)) //true= no ask
+ {
+
+ dm->putNewTranslation (orig, translated,
+ dm->catalogRef (directory (edited, 0),
+ autoauthor, edited));
+ //kdDebug(0) << "Changed " << orig << " " << translated << endl;
+ dm->sync ();
+ }
+ }
+
+}
+
+void
+KDBSearchEngine::setEditedFile (const QString & file)
+{
+
+ edited = file; //kdDebug(0) << edited << endl;
+}
+
+KeyAndScore::KeyAndScore (const QString & a, int sc):
+QString (a)
+{
+ score = sc;
+}
+
+KeyAndScore::KeyAndScore ():QString ()
+{
+ score = 0;
+}
+
+#include "KDBSearchEngine.moc"
diff --git a/kbabel/kbabeldict/modules/dbsearchengine/KDBSearchEngine.h b/kbabel/kbabeldict/modules/dbsearchengine/KDBSearchEngine.h
new file mode 100644
index 00000000..058444db
--- /dev/null
+++ b/kbabel/kbabeldict/modules/dbsearchengine/KDBSearchEngine.h
@@ -0,0 +1,333 @@
+
+/***************************************************************************
+ KDBSearchEngine.h - description
+ -------------------
+ begin : Fri Sep 8 2000
+ copyright : (C) 2000 by Andrea Rizzi
+ email : rizzi@kde.org
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; version 2 of the License. *
+ * *
+ * In addition, as a special exception, the copyright holders give *
+ * permission to link the code of this program with any edition of *
+ * the Qt library by Trolltech AS, Norway (or with modified versions *
+ * of Qt that use the same license as Qt), and distribute linked *
+ * combinations including the two. You must obey the GNU General *
+ * Public License in all respects for all of the code used other than *
+ * Qt. If you modify this file, you may extend this exception to *
+ * your version of the file, but you are not obligated to do so. If *
+ * you do not wish to do so, delete this exception statement from *
+ * your version. *
+ ***************************************************************************/
+/*
+ Translation search engine
+
+
+ Copyright 2000
+ Andrea Rizzi rizzi@kde.org
+
+*/
+
+
+/*
+ * This is a database engine specific
+ * structure, I think I must found a way to
+ * make it more "standard"
+ */
+
+#ifndef _KDBSEARCH_ENGINE_
+#define _KDBSEARCH_ENGINE_
+#include <qobject.h>
+#include <qptrlist.h>
+#include <qstring.h>
+#include <qmemarray.h>
+#include <qvaluelist.h>
+
+
+#include "database.h"
+#include "searchengine.h"
+#include "preferenceswidget.h"
+
+
+//value of mode
+#define MD_ALL_DB 1
+#define MD_GOOD_KEYS 2
+#define MD_ALL_GOOD_KEYS 3
+#define MD_IN_TRANSLATION 4
+
+class SearchEntry
+{
+ public:
+ QString string;
+ int rules;
+};
+
+class KeyAndScore : public QString
+{
+ public:
+ KeyAndScore();
+ KeyAndScore(const QString &a,int sc);
+ int score;
+};
+
+typedef QValueList<SearchEntry> SearchList;
+
+/* USE searchengine.h structure
+class CatalogDescription
+{
+ public:
+ char language[6]; // How many character chinese language needs?
+ // QString is better ?
+ QString filename;
+ QString dateOfScan; //When you add this to database (last time)
+ QString authorOfScan;
+ QString fileHeader; //msgid ""
+};
+
+ */
+
+class KDBSearchEngine : public SearchEngine
+{
+ Q_OBJECT
+
+public:
+
+
+ KDBSearchEngine(QObject *parent=0,const char *name=0);
+ ~KDBSearchEngine();
+ enum Rules {Equal = 1, Contains = 2, Contained = 4, RegExp = 8};
+ enum FormatRules { Dots = 1, Ampersand = 2, FirstWordUpper = 4, //Not yet used
+ AllWordUpper = 8, AmpersanAlwaysFirst = 16 };
+
+ /*
+ Set the directory where db file are located
+ */
+
+ void setDBName(QString filename);
+
+ /*
+ Set if the research have to consider multiple spaces as a single one.
+ */
+
+ void setNormalizeSpace(bool normalize);
+
+ /*
+ Set if the research have to be Case Sensitive or not
+ */
+
+ void setCaseSensitive(bool sensitive);
+
+
+ /*
+ ignore ":_ bla bla \n" in msgid
+
+ */
+
+ void setRemoveInternalComment(bool internalcomment);
+
+ /*
+ Set the a string containing all char that must be ignored
+ during the search.
+ */
+
+
+ void setRemoveCharString(QString chartoremove);
+
+ /*
+ Enable an output filter that format Uppercase/lowercase
+ method could be;
+ 0 = Disabled;
+ 1 = English pattern;
+ 2 = Only first;
+ */
+
+ void enableCapitalFilter(int method);
+
+ /*
+ Enable an output filter that format special characters
+ method could be;
+ 0 = Disabled;
+ 1 = Put ... at the end if needed (remove if present but no needed);
+ 2 = Put an accelerator (or remove);
+ 4 = Remove %* if not present in msgid.
+ 8 = Change %d,%s etc with %1 %2 etc if needed.
+ */
+
+ void enableCharFilter(int method);
+
+ /*
+ Sets the rules to decide when 2 string match (Uppercase and remove char
+ are not set here)
+ 1 = EQUAL
+ 2 = SEARCH STRING IS CONTAINED IN DATABASE STRING (use with care, if you search nothing
+ it will produce a dangerouse output)
+ 4 = DATABASE STRING IS CONTAINED IN SEARCH STRING (it exclude msgid "")
+ 8 = String is a regexp. (exclude 1 2 4)
+ */
+
+ void setMatchingRules(int rules);
+
+ /*
+ Search Engine methods reimplemented
+ */
+
+
+
+ virtual bool messagesForFilter(const SearchFilter* filter
+ , QValueList<SearchResult>& resultList, QString& error);
+
+
+ virtual void setLanguageCode(const QString& lang);
+ virtual void setLanguage(const QString& languageCode, const QString& languageName);
+
+ virtual void setEditedFile(const QString& file);
+
+ virtual bool isReady() const ;
+ virtual bool isSearching() const;
+
+ virtual void saveSettings(KConfigBase *config);
+ virtual void readSettings(KConfigBase *config);
+
+ virtual PrefWidget *preferencesWidget(QWidget *parent);
+
+ virtual const KAboutData *about() const;
+
+ virtual QString name() const;
+
+ virtual QString id() const;
+
+ virtual QString lastError();
+
+ virtual QString translate(const QString& text, uint pluralForm);
+
+ virtual void stringChanged( const QStringList& orig, const QString& translated
+ , const uint translationPluralForm, const QString& description);
+
+
+public slots:
+
+ void scan();
+ void scanRecur();
+ void scanFile();
+ /*
+ Add a search string in the list of the string to search for.
+ Returns the ID of the string in the list.
+ Returns -1 if there is a problem (may be search in
+ progress)
+ */
+
+ int addSearchString(QString searchString, int rule=Equal);
+
+ /*
+ Start the research in the database of all the string in the list
+ search mode -1 means use global mode;
+ */
+ bool startSearchNow(int searchmode=-1);
+
+ /*
+ Start a search for a single string
+ If the number of word of your string is less than patternXlimit
+ the KDBSearchEngine will search for all string with X * substituted to
+ X word.
+ For example if pattern1limit is 4 and you search "My name is Andrea"
+ This string will also match with:
+ "Your name is Andrea", "My dog is Andrea", "My name was Andrea", "My name is Joe"
+
+ Do not set pattern2limit too high.
+
+ If a patternlimit is > 0 rules 8 (* means any word) is added.
+
+ */
+
+ bool startSingleSearch(QString searchString,unsigned int pattern1Limit,unsigned int pattern2Limit,
+ bool inTranslation=false);
+
+ /*
+ Start a search for a list of string
+ */
+
+// bool startListSearch(QPtrList<QString> searchStrList);
+
+/*
+ * Return a list of key in database that contains some
+ * words of the given string phrase.
+ * thresholdin is a number from 0 to 100 a key is good
+ * if at least the threshold% of words are found
+ * thresholdout a key is good if the found words represnt
+ * at least the thresholdorig% of the words in the key
+ * max is the maximum number of results
+ */
+
+QValueList<KeyAndScore> searchWords(QString phrase,int threshold,
+ int thresholdorig ,uint32 max);
+
+
+ /*
+ Stop the current search
+ */
+
+ virtual void stopSearch();
+ virtual bool startSearch(const QString& text, uint pluralForm, const SearchFilter* filter);
+ virtual bool startSearchInTranslation(QString s);
+
+ void clearList();
+signals:
+ void found(SearchResult *);
+private slots:
+ void updateSettings(); //Use widget settings
+ void setSettings(); //Fill widget with actual settings
+ void prefDestr();
+ void setLastError(const QString&);
+ void repeat();
+private:
+ /*
+ Reload database info (and keep the dbase opened).
+ */
+ bool loadDatabase(QString database,bool);
+
+ bool openDb(bool);
+
+ PreferencesWidget *pw;
+ bool IAmReady;
+ int methodFilterChar;
+ int methodFilterCapital;
+ int defRule;
+ int defLimit1;
+ int defLimit2;
+ int thre;
+ int threorig;
+ int commonthre;
+ int listmax;
+ int mode;
+ bool retnot;
+ bool defSub1;
+ bool defSub2;
+ bool stopNow;
+ bool searching;
+ bool norm,sens,comm;
+ int numofresult;
+ char * filename;
+ QString remchar;
+ QString regaddchar;
+ QString dbname;
+ bool dbOpened;
+// GDBM_FILE db;
+ DataBaseManager * dm;
+// datum key, value;
+// QMemArray<CatalogDescription *> catinfo;
+ SearchList searchStringList;
+ int totalRecord;
+ QString lasterror;
+ QString lang;
+ bool scanInProgress;
+ QString edited;
+ bool autoup;
+ QString autoauthor;
+};
+
+#endif
diff --git a/kbabel/kbabeldict/modules/dbsearchengine/Makefile.am b/kbabel/kbabeldict/modules/dbsearchengine/Makefile.am
new file mode 100644
index 00000000..8504999a
--- /dev/null
+++ b/kbabel/kbabeldict/modules/dbsearchengine/Makefile.am
@@ -0,0 +1,34 @@
+## Makefile.am for DBSE
+
+# this has all of the subdirectories that make will recurse into. if
+# there are none, comment this out
+#SUBDIRS =
+
+
+# this is the program that gets installed. it's name is used for all
+# of the other Makefile.am variables
+kde_module_LTLIBRARIES = kbabeldict_dbsearchengine.la
+
+# set the include path for X, qt and KDE
+INCLUDES = -I$(srcdir)/../.. -I../../../common -I$(srcdir)/../../../common $(all_includes) $(DBIV_INCLUDES)
+
+# which sources should be compiled for kbabel
+kbabeldict_dbsearchengine_la_SOURCES = KDBSearchEngine.cpp preferenceswidget.cpp \
+ dbse_factory.cpp dbseprefwidget.ui database.cpp dbscan.cpp
+#database.cpp dbscan.cpp
+kbabeldict_dbsearchengine_la_LIBADD = ../../libkbabeldictplugin.la ../../../common/libkbabelcommon.la $(LIB_KDEUI) $(LIB_KIO) $(LIB_DBIV)
+kbabeldict_dbsearchengine_la_LDFLAGS = $(all_libraries) -module -avoid-version -no-undefined \
+ $(DBIV_LDFLAGS)
+
+
+# these are the headers for your project
+noinst_HEADERS = KDBSearchEngine.h preferenceswidget.h dbse_factory.h \
+ database.h dbscan.h
+
+
+# let automoc handle all of the meta source files (moc)
+METASOURCES = AUTO
+
+kde_services_DATA = dbsearchengine.desktop
+EXTRA_DIST = $(kde_services_DATA)
+
diff --git a/kbabel/kbabeldict/modules/dbsearchengine/STRUCTURE b/kbabel/kbabeldict/modules/dbsearchengine/STRUCTURE
new file mode 100644
index 00000000..0a53a0fe
--- /dev/null
+++ b/kbabel/kbabeldict/modules/dbsearchengine/STRUCTURE
@@ -0,0 +1,25 @@
+
+
+key = original text
+
+data
+ 0..3 num of translation (n)
+
+ translations
+ 0..3 num of file references (m)
+ 4..(4+m*4) file references
+ 4+m*4..first\0 translation
+
+
+----------------------------------------------------
+Files structure.
+
+
+"it" is the language
+
+catalogsinfo.it.db //Info about the catalog
+keysindex.it.db //index of numofkeys->key
+translations.it.db //guess.. (key->translation)
+wordsindex.it.db //index of word->numofkey
+
+
diff --git a/kbabel/kbabeldict/modules/dbsearchengine/TODO b/kbabel/kbabeldict/modules/dbsearchengine/TODO
new file mode 100644
index 00000000..0e7fbd3a
--- /dev/null
+++ b/kbabel/kbabeldict/modules/dbsearchengine/TODO
@@ -0,0 +1,27 @@
+TODO List fore KDE Database Translation Search Engine
+
+-Finish the port (use settings) done
+-Improve settings (filter output)
+-Database handling (and creation...) Done
+-output filters
+-fix fix fix...
+
+-delete item if putItem(nullitem)
+-use matthias mask function for regexp
+-remove bug of word split F&ormat is F ormat <- add remchar to charregexp
+
+
+Major rewrite:
+-New settings interface.
+-addFunction from dbscan to database Done ?
+-Edit function
+-database manager
+-download compendium from the internet
+
+Matthias ask:
+- searching in translations, equivalent to searching in msgids (SearchEngine::startTranslationSearch(QString s) )
+- the absolute path of the files and maybe the number of the entry in the file ( maybe I will add this information to the TranslationInfo )
+- the possibility to get a list of all entries in a po file from the database. For this, I think, I will create a interface and send it to you. Maybe something like this: class TranslationDatabase {
+public: // name is something like "kbabel.po" QList<CatalogItem> entriesOfFile(QString name); }
+
+
diff --git a/kbabel/kbabeldict/modules/dbsearchengine/configure.in.bot b/kbabel/kbabeldict/modules/dbsearchengine/configure.in.bot
new file mode 100644
index 00000000..58d6118f
--- /dev/null
+++ b/kbabel/kbabeldict/modules/dbsearchengine/configure.in.bot
@@ -0,0 +1,5 @@
+if test "x$with_berkeley_db" = xcheck && test -z "$LIB_DBIV"; then
+ echo ""
+ echo "Dictionary plugin \"Translation Database\" for KBabel will not be built! Please install Berkeley Database IV. See http://www.sleepycat.com for more information.)"
+ echo ""
+fi
diff --git a/kbabel/kbabeldict/modules/dbsearchengine/configure.in.in b/kbabel/kbabeldict/modules/dbsearchengine/configure.in.in
new file mode 100644
index 00000000..fbc3f1a8
--- /dev/null
+++ b/kbabel/kbabeldict/modules/dbsearchengine/configure.in.in
@@ -0,0 +1,143 @@
+AC_ARG_WITH(berkeley-db,
+ [AC_HELP_STRING(--with-berkeley-db,
+ [enable the dictionary plugin based on Berkeley DB IV @<:@default=check@:>@])],
+ [], with_berkeley_db=check)
+
+LIB_DBIV=""
+if test "x$with_berkeley_db" != xno; then
+
+AC_MSG_CHECKING([for Berkeley Database IV])
+
+db_libraries=""
+db_includes=""
+db_name=""
+ac_db_name="db"
+ac_db_includes=""
+ac_db_libraries=""
+ac_db_include_file="db.h"
+
+AC_ARG_WITH(db-dir,
+ AC_HELP_STRING([--with-db-dir=DIR],[where the root of Berkeley DB IV is installed]),
+ [ ac_db_includes=-I"$withval"/include
+ ac_db_libraries=-L"$withval"/lib
+ ])
+AC_ARG_WITH(db-include-dir,
+ AC_HELP_STRING([--with-db-include-dir=DIR],[where the includes of Berkeley DB IV are installed]),
+ [ ac_db_includes=-I"$withval"
+ ])
+AC_ARG_WITH(db-include,
+ AC_HELP_STRING([--with-db-include=FILE],[path to the Berkeley DB IV header file]),
+ [ ac_db_include_file=-I"$withval"
+ ])
+AC_ARG_WITH(db-lib-dir,
+ AC_HELP_STRING([--with-db-lib-dir=DIR],[where the libs of Berkeley DB IV are installed]),
+ [ ac_db_libraries=-L"$withval"
+ ])
+AC_ARG_WITH(db-name,
+ AC_HELP_STRING([--with-db-name=NAME],[name of the Berkeley DB IV library (default db)]),
+ [ ac_db_name="$withval"
+ ])
+
+AC_DEFUN([KDE_CHECK_DB_VERSION],
+[
+ifelse($3,,,[LIBS="$kde_db_safe -l$3"])
+AC_TRY_LINK([
+#include <$2>
+],
+[
+#if DB_VERSION_MAJOR == 4
+DB *db;
+#if DB_VERSION_MINOR > 0
+db->open( db, NULL, "test.db", NULL, DB_BTREE, DB_CREATE, 0644 );
+#else
+db->open( db, "test.db", NULL, DB_BTREE, DB_CREATE, 0644 );
+#endif
+#else
+error
+#endif
+],
+kde_cv_berk_database=$1
+)
+])
+
+AC_CACHE_VAL(kde_cv_berk_database,
+[
+kde_safe_LDFLAGS=$LDFLAGS
+kde_db_safe_LIBS=$LIBS
+LDFLAGS="$LDFLAGS $X_LDFLAGS $USER_LDFLAGS $all_libraries $ac_db_libraries $all_includes $ac_db_includes"
+
+kde_cv_berk_database=NO
+if test "xNO" = "x$kde_cv_berk_database" ; then
+ KDE_CHECK_DB_VERSION($ac_db_name, $ac_db_include_file, $ac_db_name)
+fi
+if test "xNO" = "x$kde_cv_berk_database" ; then
+ KDE_CHECK_DB_VERSION(db4, db4/db.h, db4)
+fi
+if test "xNO" = "x$kde_cv_berk_database" ; then
+ KDE_CHECK_DB_VERSION(db4-db, db.h, db4)
+fi
+if test "xNO" = "x$kde_cv_berk_database" ; then
+ KDE_CHECK_DB_VERSION(db, db.h, db)
+fi
+
+LIBS=$kde_db_safe_LIBS
+LDFLAGS=$kde_safe_LDFLAGS
+
+])
+
+kde_db_header=""
+DBSEARCHENGINE=dbsearchengine
+
+case "$kde_cv_berk_database" in
+ NO)
+ AC_MSG_RESULT(no)
+ LIB_DBIV=""
+ DBSEARCHENGINE=""
+ ;;
+ db)
+ LIB_DBIV="-l$ac_db_name"
+ kde_db_header=db.h
+ AC_MSG_RESULT(-l$ac_db_name)
+ AC_DEFINE_UNQUOTED(HAVE_DB_DB_H, 1, [DB 4 header location] )
+ ;;
+ db4-db)
+ LIB_DBIV='-ldb4'
+ kde_db_header=db.h
+ AC_MSG_RESULT("flag is -ldb4 and header is db.h")
+ AC_DEFINE_UNQUOTED(HAVE_DB_DB_H, 1, [DB 4 header location] )
+ ;;
+ db4)
+ LIB_DBIV='-ldb4'
+ kde_db_header=db4/db.h
+ AC_MSG_RESULT(-ldb4)
+ AC_DEFINE_UNQUOTED(HAVE_DB4_DB_H, 1, [DB 4 header location] )
+ ;;
+ $ac_db_name)
+ LIB_DBIV="-l$ac_db_name"
+ kde_db_header="$ac_db_include_file"
+ AC_MSG_RESULT(user specified $ac_db_name)
+ if test "x$ac_db_include_file" = "xdb.h" ; then
+ AC_DEFINE_UNQUOTED(HAVE_DB_DB_H, 1, [DB 4 header location] )
+ else
+ AC_DEFINE_UNQUOTED(USE_DB_H_PATH, <$ac_db_include_file>, [DB 4 header path])
+ fi
+
+ ;;
+esac
+
+DBIV_LDFLAGS="$ac_db_libraries"
+DBIV_INCLUDES="$ac_db_includes"
+DBIV_NAME="$ac_db_name"
+
+if test "x$with_berkeley_db" != xcheck && test -z "$LIB_DBIV"; then
+ AC_MSG_ERROR([--with-berkeley-db was given, but test for Berkeley DB IV failed])
+fi
+fi
+
+AC_SUBST(DBIV_INCLUDES)
+AC_SUBST(DBIV_LDFLAGS)
+AC_SUBST(DBIV_NAME)
+
+AC_SUBST(LIB_DBIV)
+
+AM_CONDITIONAL(include_DBSEARCHENGINE, test -n "$DBSEARCHENGINE")
diff --git a/kbabel/kbabeldict/modules/dbsearchengine/database.cpp b/kbabel/kbabeldict/modules/dbsearchengine/database.cpp
new file mode 100644
index 00000000..003a3a95
--- /dev/null
+++ b/kbabel/kbabeldict/modules/dbsearchengine/database.cpp
@@ -0,0 +1,1533 @@
+/***************************************************************************
+ database.cpp -
+ -------------------
+ begin : Fri Sep 8 2000
+ copyright : (C) 2000 by Andrea Rizzi
+ email : rizzi@kde.org
+ ***************************************************************************/
+
+/*
+ Translation search engine
+
+
+ Copyright 2000
+ Andrea Rizzi rizzi@kde.org
+ Copyright 2003 Stanislav Visnovsky visnovsky@kde.org
+
+ License GPL v 2.0
+
+ * *
+ * In addition, as a special exception, the copyright holders give *
+ * permission to link the code of this program with any edition of *
+ * the Qt library by Trolltech AS, Norway (or with modified versions *
+ * of Qt that use the same license as Qt), and distribute linked *
+ * combinations including the two. You must obey the GNU General *
+ * Public License in all respects for all of the code used other than *
+ * Qt. If you modify this file, you may extend this exception to *
+ * your version of the file, but you are not obligated to do so. If *
+ * you do not wish to do so, delete this exception statement from *
+ * your version. *
+
+*/
+#include <stdlib.h>
+#include <kdebug.h>
+#include <string.h>
+#include <resources.h>
+#include "database.h"
+#include <unistd.h>
+
+#include <qfile.h>
+
+#include <ktempfile.h>
+#include <kio/netaccess.h>
+
+WordItem::WordItem (char *data, QString w)
+{
+ word = w;
+
+ count = *(uint32 *) data;
+
+ data += 4;
+//score=*(int *)data;
+ data += 4;
+
+
+ locations = (uint32 *) malloc (4 * count);
+ memcpy (locations, data, 4 * count);
+
+
+}
+
+WordItem::WordItem (QString w)
+{
+ locations = NULL;
+ count = 0;
+ word = w;
+ score = -1; // it means no references found.
+}
+
+/*
+
+WordItem::WordItem(const WordItem &wi)
+{
+ count=wi.count;
+ score=wi.score;
+ word=wi.word;
+ locations.duplicate(wi.locations);
+ locations.detach();
+}
+
+WordItem& WordItem::operator=(const WordItem & wi )
+{
+WordItem *i=new WordItem(wi);
+i->locations.detach();
+return *i;
+}
+*/
+
+bool
+WordItem::notFound ()
+{
+ return (score == -1);
+}
+
+InfoItem::InfoItem ()
+{
+ catalogName = "No catalog";
+ lastTranslator = "No translator";
+ lastFullPath = "";
+ charset = "No charset";
+ language = "No language";
+}
+
+InfoItem::InfoItem (const char *rawData, QString lang)
+{
+ const char *rd;
+ rd = rawData;
+ int len;
+ unsigned int secs;
+ // I'll change the charset handling if needed
+
+ charset = "Utf8";
+
+ catalogName = QString::fromUtf8 (rd);
+ len = strlen (rd) + 1;
+ rd += len;
+ lastTranslator = QString::fromUtf8 (rd);
+ len = strlen (rd) + 1;
+ rd += len;
+ secs = *(unsigned int *) rd;
+ revisionDate.setTime_t (secs);
+ rd += 4;
+ lastFullPath = QString::fromUtf8 (rd);
+ len = strlen (rd) + 1;
+ rd += len;
+
+
+ language = lang;
+}
+
+void
+InfoItem::rawData (char *rawData)
+{
+ char *rd;
+ rd = rawData;
+
+ strcpy (rd, catalogName.utf8 ());
+ rd += strlen (rd) + 1;
+ strcpy (rd, lastTranslator.utf8 ());
+ rd += strlen (rd) + 1;
+
+
+ //QDate Time problem!!!!!!!!!!!
+ QDateTime zeroDate;
+ zeroDate.setTime_t (0);
+ *(unsigned int *) rd = -revisionDate.secsTo (zeroDate);
+ rd += 4;
+ strcpy (rd, lastFullPath.utf8 ());
+ rd += strlen (rd) + 1;
+
+ *rd = 0; //Empty for further info
+
+}
+
+int
+InfoItem::size ()
+{
+ int _size;
+ _size = 0;
+ _size += 1; // 1 Empty field;
+ _size += 3; // Terminating \0 of next 3 strings
+ _size += 4; // Int size (date)
+ _size += strlen (catalogName.utf8 ());
+ _size += strlen (lastTranslator.utf8 ());
+ _size += strlen (lastFullPath.utf8 ());
+
+ return _size;
+}
+
+// this is a quick hack to copy a local file
+int
+copy_hack (QFile & input, QFile & output)
+{
+ if (!input.isOpen ())
+ {
+ if (!input.open (IO_ReadOnly))
+ return -1;
+ }
+
+ if (!output.isOpen ())
+ {
+ if (!output.open (IO_WriteOnly))
+ return -1;
+ }
+
+ char buffer[10240];
+ int s = 0;
+ while (!input.atEnd ())
+ {
+ s = input.readBlock (buffer, 10240);
+ output.writeBlock (buffer, s);
+ }
+ output.close ();
+ input.close ();
+ return 0;
+}
+
+DataBaseItem::DataBaseItem ()
+{
+ numTra = 0;
+ location = 0;
+}
+
+DataBaseItem::DataBaseItem (char *_key, char *_data)
+{
+
+ char *data = _data;
+ key = QString::fromUtf8 (_key);
+
+ unsigned int i, r;
+ numTra = *(uint32 *) data;
+ data += 4;
+ location = *(uint32 *) data;
+ data += 4;
+
+ for (i = 0; i < numTra; i++)
+ {
+
+ TranslationItem tr;
+ tr.numRef = *(uint32 *) data;
+
+ data += 4;
+ for (r = 0; r < tr.numRef; r++)
+ {
+
+ int ref;
+ ref = *(uint32 *) data;
+ data += 4;
+
+ tr.infoRef.append (ref);
+ }
+ tr.translation = QString::fromUtf8 ((const char *) data);
+ translations.append (tr);
+ data += strlen (data) + 1;
+
+ }
+
+}
+
+uint32
+DataBaseItem::sizeKey ()
+{
+ return strlen (key.utf8 ()) + 1;
+}
+
+uint32
+DataBaseItem::sizeData ()
+{
+ unsigned int i, _size = 4;
+ _size += numTra * 4;
+ _size += 4; // location
+ for (i = 0; i < numTra; i++)
+ {
+ _size += strlen (translations[i].translation.utf8 ()) + 1; // +1 is for \0
+ _size += translations[i].numRef * 4;
+ }
+ return _size;
+}
+
+void
+DataBaseItem::toRawKey (char *_key)
+{
+ strcpy (_key, key.utf8 ());
+}
+
+void
+DataBaseItem::toRawData (char *_data)
+{
+ char *data = _data;
+ unsigned int i, r;
+
+ *(uint32 *) data = numTra;
+
+ data += 4;
+
+ *(uint32 *) data = location;
+ data += 4;
+
+ for (i = 0; i < numTra; i++)
+ {
+ TranslationItem tr (translations[i]);
+ *(uint32 *) data = tr.numRef;
+ data += 4;
+ for (r = 0; r < tr.numRef; r++)
+ {
+ *(uint32 *) data = tr.infoRef[r]; //sub i with r
+
+ data += 4;
+ }
+ strcpy ((char *) data, tr.translation.utf8 ());
+ data += strlen (tr.translation.utf8 ()) + 1;
+ }
+
+}
+
+
+DataBaseManager::DataBaseManager (QString directory, QString lang,
+ QObject * parent, const char *name):
+QObject (parent, name)
+{
+ QString filename;
+
+ language = lang;
+ iAmOk = true;
+ basedir = directory;
+ indexDb = wordDb = infoDb = db = 0;
+ openDataBase ();
+
+
+}
+
+void
+DataBaseManager::openDataBase ()
+{
+ kdDebug () << "Opendatabase" << endl;
+ QString directory;
+ directory = basedir;
+ QString ll = "." + language;
+ if (ll == ".")
+ ll = ".NOLANG";
+
+ QString transfilename = "%1/translations%2.db";
+ transfilename = transfilename.arg (directory).arg (ll);
+
+ QString infofilename = "%1/catalogsinfo%2.db";
+ infofilename = infofilename.arg (directory).arg (ll);
+
+ QString wordsfilename = "%1/wordsindex%2.db";
+ wordsfilename = wordsfilename.arg (directory).arg (ll);
+
+ QString keysfilename = "%1/keysindex%2.db";
+ keysfilename = keysfilename.arg (directory).arg (ll);
+
+ cursor = 0;
+ int ret;
+
+ if (!db)
+ db_create (&db, 0, 0);
+
+ db_create (&infoDb, 0, 0);
+ db_create (&wordDb, 0, 0);
+ db_create (&indexDb, 0, 0);
+
+ ret = db->open (db,
+#if DB_VERSION_MINOR > 0
+ NULL,
+#endif
+ transfilename.local8Bit (), 0, DB_BTREE, 0, 0644);
+
+ if (ret == DB_OLD_VERSION)
+ {
+ kdDebug (KBABEL_SEARCH) << "Trying upgrade" << endl;
+ // try upgrade
+
+ KTempFile transFile, infoFile, keysFile, wordsFile;
+
+ // do the upgrade on the translation file
+ QFile transfilenameFile (transfilename);
+
+ if ((ret = copy_hack (transfilenameFile, *transFile.file ())) == 0)
+ {
+ ret = db->upgrade (db, transFile.name ().local8Bit (), 0);
+ }
+
+ if (ret != 0)
+ {
+ kdDebug (KBABEL_SEARCH) << "Cannot upgrade translations, " <<
+ ret << endl;
+ // cleanup
+ transFile.unlink ();
+ iAmOk = false;
+ emit cannotOpenDB (ret);
+ return;
+ }
+
+ // do the upgrade on the info file
+ QFile infofilenameFile (infofilename);
+ if ((ret = copy_hack (infofilenameFile, *infoFile.file ())) == 0)
+ {
+ ret =
+ infoDb->upgrade (infoDb, infoFile.name ().local8Bit (),
+ 0);
+ }
+
+ if (ret != 0)
+ {
+ kdDebug (KBABEL_SEARCH) << "Cannot upgrade catalogsinfo" <<
+ endl;
+ // cleanup
+ transFile.unlink ();
+ infoFile.unlink ();
+ iAmOk = false;
+ emit cannotOpenDB (ret);
+ return;
+ }
+
+ // do the upgrade on the words file
+ QFile wordfilenameFile (wordsfilename);
+ if ((ret = copy_hack (wordfilenameFile, *wordsFile.file ())) == 0)
+ {
+ ret =
+ wordDb->upgrade (wordDb, wordsFile.name ().local8Bit (),
+ 0);
+ }
+
+ if (ret != 0)
+ {
+ kdDebug (KBABEL_SEARCH) << "Cannot upgrade words" << endl;
+ // cleanup
+ transFile.unlink ();
+ infoFile.unlink ();
+ wordsFile.unlink ();
+ iAmOk = false;
+ emit cannotOpenDB (ret);
+ return;
+ }
+
+ // do the upgrade on the keys file
+ QFile keysfilenameFile (keysfilename);
+ if ((ret = copy_hack (keysfilenameFile, *keysFile.file ())) == 0)
+ {
+ ret =
+ indexDb->upgrade (indexDb, keysFile.name ().local8Bit (),
+ 0);
+ }
+
+ if (ret != 0)
+ {
+ kdDebug (KBABEL_SEARCH) << "Cannot upgrade keys" << endl;
+ // cleanup
+ transFile.unlink ();
+ infoFile.unlink ();
+ wordsFile.unlink ();
+ keysFile.unlink ();
+ iAmOk = false;
+ emit cannotOpenDB (ret);
+ return;
+ }
+
+ kdDebug (KBABEL_SEARCH) << "Files upgraded, copying" << endl;
+ // use temporary file instead
+ if (ret == 0)
+ {
+ KIO::NetAccess::del (KURL::fromPathOrURL (transfilename));
+ copy_hack (*transFile.file (), transfilenameFile);
+ transFile.unlink ();
+
+ KIO::NetAccess::del (KURL::fromPathOrURL (infofilename));
+ copy_hack (*infoFile.file (), infofilenameFile);
+ infoFile.unlink ();
+
+ KIO::NetAccess::del (KURL::fromPathOrURL (wordsfilename));
+ copy_hack (*wordsFile.file (), wordfilenameFile);
+ wordsFile.unlink ();
+
+ KIO::NetAccess::del (KURL::fromPathOrURL (keysfilename));
+ copy_hack (*keysFile.file (), keysfilenameFile);
+ keysFile.unlink ();
+
+ ret = db->open (db,
+#if DB_VERSION_MINOR > 0
+ NULL,
+#endif
+ transfilename.local8Bit (), 0, DB_BTREE, 0,
+ 0644);
+ if (ret != 0)
+ {
+ kdWarning (KBABEL_SEARCH) <<
+ "transFilename database can't be opened." << endl;
+ kdWarning (KBABEL_SEARCH) <<
+ "Please, report this incident and how to reproduce it to kbabel@kde.org."
+ << endl;
+ iAmOk = false;
+ emit cannotOpenDB (ret);
+ return;
+ }
+
+ }
+ kdDebug (KBABEL_SEARCH) << "Upgrade done OK" << endl;
+ }
+
+// Open catalogs information database
+
+
+
+ ret = infoDb->open (infoDb,
+#if DB_VERSION_MINOR > 0
+ NULL,
+#endif
+ infofilename.local8Bit (), 0, DB_RECNO, 0, 0644);
+ if (ret != 0)
+ {
+ iAmOk = false;
+ emit cannotOpenDB (ret);
+ //Process error here.
+ }
+ else
+ loadInfo ();
+
+
+
+// Words index database
+
+ ret = wordDb->open (wordDb,
+#if DB_VERSION_MINOR > 0
+ NULL,
+#endif
+ wordsfilename.local8Bit (), 0, DB_BTREE, 0, 0644);
+ if (ret != 0)
+ {
+ iAmOk = false;
+ emit cannotOpenDB (ret);
+ //Process error here.
+ }
+
+//Index of keys.
+
+ ret = indexDb->open (indexDb,
+#if DB_VERSION_MINOR > 0
+ NULL,
+#endif
+ keysfilename.local8Bit (), 0, DB_RECNO, 0, 0644);
+ if (ret != 0)
+ {
+ iAmOk = false;
+ emit cannotOpenDB (ret);
+ //Process error here.
+ }
+
+
+}
+
+void
+DataBaseManager::closeDataBase ()
+{
+ if (iAmOk)
+ {
+ db->sync (db, 0);
+ db->close (db, 0);
+
+ infoDb->sync (infoDb, 0);
+ infoDb->close (infoDb, 0);
+
+ wordDb->sync (wordDb, 0);
+ wordDb->close (wordDb, 0);
+
+ indexDb->sync (indexDb, 0);
+ indexDb->close (indexDb, 0);
+
+ // can not be opened again
+ indexDb = wordDb = infoDb = db = 0;
+
+ }
+
+}
+
+
+// I'm not sure this is a good function !!!
+
+void
+DataBaseManager::sync ()
+{
+// if(iAmOk)
+// {
+// db->sync(db,0);
+// infoDb->sync(infoDb,0);
+// cursor=0;
+// }
+
+ // closeDataBase();
+// openDataBase();
+
+ db->sync (db, 0);
+ infoDb->sync (infoDb, 0);
+ wordDb->sync (wordDb, 0);
+ indexDb->sync (indexDb, 0);
+ loadInfo ();
+}
+
+
+DataBaseManager::~DataBaseManager ()
+{
+ closeDataBase ();
+}
+
+int
+DataBaseManager::putItem (DataBaseItem * item, bool ow)
+{
+ DBT key, data;
+
+ memset (&key, 0, sizeof (DBT));
+ memset (&data, 0, sizeof (DBT));
+
+ bool ret;
+
+ uint32 loc = 0;
+ if (item->location == 0)
+ {
+ loc = item->location = appendKey (item->key);
+// kdDebug(0) << "New key " << item->location << endl;
+ }
+ key.size = item->sizeKey ();
+ data.size = item->sizeData ();
+
+ key.data = malloc (key.size);
+ data.data = malloc (data.size);
+
+
+ item->toRawKey ((char *) key.data);
+ item->toRawData ((char *) data.data);
+
+
+ if (ow)
+ ret = db->put (db, 0, &key, &data, 0);
+ else
+ ret = db->put (db, 0, &key, &data, DB_NOOVERWRITE);
+
+//check ret
+
+ if (loc != 0) //I'm new!
+ {
+ uint32 location = loc;
+
+ QValueList < QString > wlist;
+
+ wlist = wordsIn (item->key);
+
+ QValueList < QString >::Iterator wlistit;
+
+ for (wlistit = wlist.begin (); wlistit != wlist.end (); ++wlistit)
+ {
+ addLocation (*wlistit, location);
+ }
+
+ }
+
+ free (key.data);
+ free (data.data); //READ DOCU !!!!
+
+ return ret;
+
+}
+
+DataBaseItem
+DataBaseManager::getItem (QString key)
+{
+ if (!iAmOk)
+ return DataBaseItem ();
+
+
+ DBT _key, data;
+
+ memset (&_key, 0, sizeof (DBT));
+
+ memset (&data, 0, sizeof (DBT));
+
+ int len = strlen (key.utf8 ());
+ _key.data = malloc (len + 1);
+ _key.size = len + 1;
+ strcpy ((char *) _key.data, key.utf8 ());
+
+
+ int ret;
+ ret = db->get (db, 0, &_key, &data, 0);
+
+ if (ret != 0)
+ {
+ free (_key.data);
+ return DataBaseItem (); //return an empty database item
+ }
+
+ DataBaseItem returnItem =
+ DataBaseItem ((char *) _key.data, (char *) data.data);
+
+ free (_key.data);
+ return returnItem;
+
+}
+
+
+
+
+DataBaseItem
+DataBaseManager::cursorGet (uint32 flags)
+{
+
+ if (!iAmOk)
+ return DataBaseItem ();
+ int re;
+ DBT key, data;
+
+ memset (&key, 0, sizeof (DBT));
+
+ memset (&data, 0, sizeof (DBT));
+
+ if (cursor == 0)
+ re = db->cursor (db, 0, &cursor, 0);
+
+ int ret;
+ if ((ret = cursor->c_get (cursor, &key, &data, flags)) == 0)
+ {
+ return DataBaseItem ((char *) key.data, (char *) data.data);
+ }
+ else
+ {
+ kdDebug (KBABEL_SEARCH) << QString ("...cursor getting...%1").
+ arg (ret) << endl;
+
+ return DataBaseItem ();
+ }
+}
+
+
+DataBaseItem
+DataBaseManager::firstItem ()
+{
+ return cursorGet (DB_FIRST);
+}
+
+DataBaseItem
+DataBaseManager::currentItem ()
+{
+ return cursorGet (DB_CURRENT);
+}
+
+
+DataBaseItem
+DataBaseManager::nextItem ()
+{
+ return cursorGet (DB_NEXT);
+}
+
+
+bool
+DataBaseManager::isOk ()
+{
+ return iAmOk;
+}
+
+int
+DataBaseManager::count ()
+{
+ DB_BTREE_STAT *dstat = 0;
+#if DB_VERSION_MAJOR == 4 && DB_VERSION_MINOR >= 3
+ db->stat (db, NULL, &dstat, DB_FAST_STAT);
+#else
+ db->stat (db, &dstat, DB_FAST_STAT);
+#endif
+ int ret = dstat->bt_nkeys;
+ free (dstat);
+
+ return ret;
+}
+
+int
+DataBaseManager::current ()
+{
+// THIS FUNCTION SEEM TO NOT WORK (not used)
+ if (!iAmOk)
+ return 0;
+
+ DBT key, data;
+ memset (&key, 0, sizeof (DBT));
+ memset (&data, 0, sizeof (DBT));
+
+ if (cursor != 0)
+ db->cursor (db, 0, &cursor, 0);
+ cursor->c_get (cursor, &key, &data, DB_GET_RECNO);
+ return *(uint32 *) (data.data);
+
+}
+
+int
+DataBaseManager::createDataBase (QString directory,
+ QString language, int mode)
+{
+ QString filename;
+ QString ll = "." + language;
+ if (ll == ".")
+ ll = ".NOLANG";
+ filename = "%1/translations%2.db";
+ filename = filename.arg (directory).arg (ll);
+
+ rename (filename.local8Bit (), filename.local8Bit () + ",old");
+
+//kdDebug(0) << QString("Creating %1").arg(filename) << endl;
+
+ iAmOk = true;
+
+ int ret;
+
+ if (!db)
+ {
+ if (db_create (&db, 0, 0) != 0)
+ {
+ kdDebug() << "db_create db failed" << endl;
+ iAmOk = false;
+ return false;
+ }
+ }
+
+ db->set_flags (db, DB_RECNUM);
+ ret = db->open (db,
+#if DB_VERSION_MINOR > 0
+ NULL,
+#endif
+ filename.local8Bit (), 0, DB_BTREE, DB_CREATE | DB_EXCL,
+ mode);
+ if (ret != 0)
+ {
+ kdDebug() << "db->open " << filename << " " << mode << " failed" << endl;
+ iAmOk = false;
+ }
+
+
+ filename = "%1/catalogsinfo%2.db";
+ filename = filename.arg (directory).arg (ll);
+ rename (filename.local8Bit (), filename.local8Bit () + ",old");
+
+ db_create (&infoDb, 0, 0);
+ ret = infoDb->open (infoDb,
+#if DB_VERSION_MINOR > 0
+ NULL,
+#endif
+ filename.local8Bit (), 0, DB_RECNO, DB_CREATE, mode);
+ if (ret != 0)
+ iAmOk = false;
+
+
+
+ filename = "%1/wordsindex%2.db";
+ filename = filename.arg (directory).arg (ll);
+ rename (filename.local8Bit (), filename.local8Bit () + ",old");
+
+ db_create (&wordDb, 0, 0);
+ ret = wordDb->open (wordDb,
+#if DB_VERSION_MINOR > 0
+ NULL,
+#endif
+ filename.local8Bit (), 0, DB_BTREE, DB_CREATE, mode);
+ if (ret != 0)
+ iAmOk = false;
+
+
+
+ filename = "%1/keysindex%2.db";
+ filename = filename.arg (directory).arg (ll);
+ rename (filename.local8Bit (), filename.local8Bit () + ",old");
+
+ db_create (&indexDb, 0, 0);
+ ret = indexDb->open (indexDb,
+#if DB_VERSION_MINOR > 0
+ NULL,
+#endif
+ filename.local8Bit (), 0, DB_RECNO, DB_CREATE, mode);
+ if (ret != 0)
+ iAmOk = false;
+
+
+
+ if (iAmOk)
+ loadInfo ();
+ else
+ kdDebug (KBABEL_SEARCH) << QString ("I am NOT ok : %1").
+ arg (ret) << endl;
+
+//THIS IS WRONG, rewrite the error handling.
+ return iAmOk;
+
+}
+
+InfoItem
+DataBaseManager::getCatalogInfo (int n)
+{
+
+ DBT key;
+ DBT data;
+
+ memset (&key, 0, sizeof (DBT));
+ memset (&data, 0, sizeof (DBT));
+
+ key.data = &n;
+ key.size = 4;
+
+//Check for errors
+ int ret = infoDb->get (infoDb, 0, &key, &data, 0); //DB_SET_RECNO);
+
+ if (ret)
+ {
+ return InfoItem ();
+ }
+
+// kdDebug(0) << QString("Trad %1").arg(ret) << endl;
+
+ InfoItem it ((char *) data.data, language);
+//free(data.data); // Read docu for this!!!!
+
+ return it;
+
+}
+
+int
+DataBaseManager::addCatalogInfo (InfoItem * catInfo, int cat = -1)
+{
+ DBT data;
+ DBT key;
+
+ // clean up data
+ memset (&data, 0, sizeof (DBT));
+ memset (&key, 0, sizeof (DBT));
+
+ int ret = 0, err;
+ if (cat >= 0)
+ ret = cat;
+ key.size = 4;
+ key.data = &ret;
+ data.size = catInfo->size ();
+ data.data = malloc (data.size);
+
+ catInfo->rawData ((char *) data.data);
+
+ // store the catalog data into database
+ if (cat >= 0)
+ err = infoDb->put (infoDb, 0, &key, &data, 0);
+ else
+ err = infoDb->put (infoDb, 0, &key, &data, DB_APPEND);
+
+
+ ret = *(int *) key.data;
+
+ // Append to the list of catalogInfo
+ info.append (*catInfo);
+
+ // cleanup unneeded data memory
+ free (data.data);
+ return ret;
+}
+
+int
+DataBaseManager::searchCatalogInfo (QString location)
+{
+ int n = 0;
+ QValueList < InfoItem >::Iterator it;
+ for (it = info.begin (); it != info.end (); ++it)
+ {
+ n++;
+ if ((*it).catalogName == location)
+ return n;
+ }
+ return -1;
+}
+
+bool
+DataBaseManager::putCatalogInfo (int refnum, InfoItem * catInfo)
+{
+ DBT data;
+ DBT key;
+
+ memset (&key, 0, sizeof (DBT));
+ memset (&data, 0, sizeof (DBT));
+
+ int ret;
+ key.size = 4;
+ key.data = &refnum;
+
+ data.size = catInfo->size ();
+ data.data = malloc (data.size);
+ catInfo->rawData ((char *) data.data);
+
+ ret = infoDb->put (infoDb, 0, &key, &data, 0);
+
+ free (data.data);
+
+ return (ret == 0);
+}
+
+void
+DataBaseManager::loadInfo ()
+{
+ int nrec;
+ DB_BTREE_STAT *stat;
+// memset(&stat,0,sizeof(DB_BTREE_STAT));
+#if DB_VERSION_MAJOR == 4 && DB_VERSION_MINOR >= 3
+ if (infoDb->stat (infoDb, NULL, &stat, DB_FAST_STAT))
+ fprintf (stderr, "Cannot stat\n");
+#else
+ if (infoDb->stat (infoDb, &stat, DB_FAST_STAT))
+ fprintf (stderr, "Cannot stat\n");
+#endif
+ nrec = stat->bt_nkeys;
+ free (stat);
+
+ info.clear ();
+ for (int i = 1; i <= nrec; i++) // I think DB2 Recno are 1 based.
+ {
+ info.append (getCatalogInfo (i));
+ }
+
+}
+
+
+QValueList < QString > DataBaseManager::wordsIn (QString string)
+{
+ QString
+ a;
+ QValueList < QString > words;
+ int
+ i,
+ l;
+
+ a = string.simplifyWhiteSpace ();
+ a = a.stripWhiteSpace ();
+ a = a.lower ();
+ l = a.length ();
+
+ int
+ c = 0;
+ //words.setAutoDelete(true); //Not sure... check if it is en.
+ QString
+ m;
+ for (i = 0; i < l; i++)
+ if (a[i].isLetterOrNumber ())
+ {
+ m += a[i];
+ }
+ else if (a[i].isSpace ())
+ {
+ words.append (m);
+ c++; // C++ ;-)
+ m = "";
+ }
+ words.append (m);
+
+ return words;
+}
+
+
+
+WordItem
+DataBaseManager::getWordLocations (QString word)
+{
+
+ QString keystring = word.lower ();
+
+ DBT key;
+ DBT data;
+
+ char *keydata;
+
+ int intlen = strlen (keystring.utf8 ());
+
+ keydata = (char *) malloc (intlen + 1);
+ strcpy (keydata, keystring.utf8 ());
+
+ memset (&key, 0, sizeof (DBT));
+ memset (&data, 0, sizeof (DBT));
+
+ key.data = keydata;
+ key.size = intlen + 1;
+
+//Check for errors
+ int ret = wordDb->get (wordDb, 0, &key, &data, 0); //DB_SET_RECNO);
+//MAYBE THIS WORD IS NO WHERE!!
+ if (ret)
+ {
+ free (keydata);
+ return WordItem (keystring);
+ }
+
+
+ WordItem it ((char *) data.data, keystring);
+
+ free (keydata);
+
+
+// kdDebug(0) << ((uint32 *)it.locations.data())[0] << endl;
+
+ return it;
+
+}
+
+
+bool
+DataBaseManager::addLocation (QString word, unsigned int location)
+{
+
+ QString keystring = word.lower ();
+
+
+ DBT key;
+ DBT data;
+
+ char *keydata;
+ char *newdata;
+
+ int intlen = strlen (keystring.utf8 ());
+
+ keydata = (char *) malloc (intlen + 1);
+ strcpy (keydata, keystring.utf8 ());
+
+ memset (&key, 0, sizeof (DBT));
+ memset (&data, 0, sizeof (DBT));
+
+ key.data = keydata;
+ key.size = intlen + 1;
+
+ strcpy ((char *) key.data, keystring.utf8 ());
+
+//Check for errors
+ int ret = wordDb->get (wordDb, 0, &key, &data, 0); //DB_SET_RECNO);
+
+//Check if you get something or not
+ if (ret == 0) // CHANGE IT!!!!! if found something
+ {
+ uint32 *d;
+ d = (uint32 *) data.data;
+ uint32 num = d[0];
+ uint32 loc = 0; //Position from 0 to num-1
+ int totalrecord = count ();
+ uint32 step = 1;
+
+ int antibounce = 0;
+//d+=4;
+//int score=d[1];
+//d+=4;
+ bool forward, end = false;
+
+ d[1] = 0; //Before the begin...
+
+ d += 2; //1 uint32!
+
+
+//Try to guess...
+ loc = location * num / totalrecord + 1;
+ if (loc >= num)
+ loc = num - 1;
+
+
+
+
+//Continue if next is smaller or if previous is greater
+//before the while check if it is ok
+ if (loc == 0)
+ {
+ if (d[loc] > location)
+ end = true;
+ else
+ loc = 1;
+ }
+
+ if ((loc == num) && !end)
+ {
+ if (d[loc - 1] < location)
+ end = true;
+ else
+ loc = num - 1;
+ }
+
+
+
+ while ((!end) && ((forward = (d[loc]) < location)
+ || ((loc > 0) && (d[loc - 1] > location))))
+ {
+
+ antibounce++;
+ //calculate step or use antibounce
+ if (abs ((int) d[loc] - (int) location) < 50
+ || antibounce > 100)
+ step = 1; //Go linear...
+ else
+ {
+ step =
+ (abs (d[loc] - location) * num) / totalrecord + 1;
+
+ }
+
+ kdDebug (KBABEL_SEARCH) << "Insert:" << location <<
+ " We are at: " << loc << " i.e. " << d[loc] << " Step:"
+ << step << endl;
+ if (loc > 0)
+ {
+ if (forward)
+ kdDebug (KBABEL_SEARCH) << "Go " << "forward" <<
+ " prev is " << d[loc - 1] << endl;
+ else
+ kdDebug (KBABEL_SEARCH) << "Go " << "backward" <<
+ " prev is " << d[loc - 1] << endl;
+ }
+
+ if (forward)
+ {
+ if (loc + step < num)
+ loc += step; // Go forward
+ else
+ loc = num; // Go to num
+ }
+ else
+ {
+ if (loc > step)
+ loc -= step; //Go backward
+ else
+ loc = 0; // Go to 0
+ }
+
+ //Now check if I am in the right place [THIS IS NOT NECESSARY]
+
+ //check if loc and loc -1 are well defined 1<loc<num-1
+ if (loc > num)
+ loc = num; //Must not happen, idem
+
+ if (loc == 0)
+ {
+ if (d[loc] > location)
+ end = true;
+ else
+ loc = 1;
+ }
+
+ if ((loc == num) && !end)
+ {
+ if (d[loc - 1] < location)
+ end = true;
+ else
+ loc = num - 1;
+ }
+
+ }
+
+ if (loc == num)
+ kdDebug (KBABEL_SEARCH) << "END" << endl;
+ if (loc == 0)
+ kdDebug (KBABEL_SEARCH) << "BEGIN" << endl;
+
+ if (loc > 0)
+ kdDebug (KBABEL_SEARCH) << location << " inserted between " <<
+ d[loc - 1] << " and " << d[loc] << endl;
+
+ if ((loc < num && location == d[loc]) || (loc > 0 && location == d[loc - 1])) //What about word repetition
+ {
+ free (keydata);
+ return true; //Why true ??
+ }
+
+
+
+//Now insert and put back in the database!
+ newdata = (char *) malloc (4 * (num + 3)); //uint32*(num+score+1..NUM+new)
+ memcpy (newdata, data.data, 4 + 4 + 4 * loc);
+ char *secondpart = (char *) data.data;
+ secondpart += 4 * (loc + 2);
+ memcpy ((newdata + 4 * (loc + 3)), secondpart, (num - loc) * 4);
+ uint32 *intdata = (uint32 *) newdata;
+ intdata[0] = num + 1;
+ //ADD HERE code to recalc score
+ intdata[loc + 2] = location;
+
+//ok send it to database!
+ memset (&data, 0, sizeof (DBT));
+
+ data.data = newdata;
+ data.size = 4 * (3 + num);
+ } //found sounthing
+ else
+ { //found nothing
+ newdata = (char *) malloc (4 * 3);
+ uint32 *intdata = (uint32 *) newdata;
+ intdata[0] = 1;
+ intdata[1] = 1;
+ intdata[2] = location;
+ memset (&data, 0, sizeof (DBT));
+ data.data = newdata;
+ data.size = 4 * 3;
+ }
+
+ memset (&key, 0, sizeof (DBT));
+//memset(&data,0,sizeof(DBT));
+
+ key.data = keydata;
+ key.size = intlen + 1;
+
+ ret = wordDb->put (wordDb, 0, &key, &data, 0); //DB_SET_RECNO);
+
+
+ free (newdata);
+ free (keydata);
+//return it;
+
+ return true;
+}
+
+
+bool
+DataBaseManager::removeLocation (QString /*word */ , int /*location */ )
+{
+
+//#warning TODO: REMOVE LOCATION
+ return true;
+
+}
+
+uint32
+DataBaseManager::appendKey (QString _key)
+{
+
+ DBT key;
+ DBT data;
+
+ memset (&key, 0, sizeof (DBT));
+ memset (&data, 0, sizeof (DBT));
+
+
+ uint32 ret = 0, err;
+ key.size = 4;
+ key.data = &ret;
+
+ data.size = strlen (_key.utf8 ()) + 1;
+ data.data = malloc (data.size);
+
+ strcpy ((char *) data.data, _key.utf8 ());
+
+ err = indexDb->put (indexDb, 0, &key, &data, DB_APPEND);
+
+ if (err)
+ ret = 0;
+ else
+ ret = *(uint32 *) key.data;
+
+//kdDebug(0) << QString("Append result %1,err = %1").arg(ret).arg(err) << endl;
+
+
+ free (data.data);
+
+ return ret;
+
+}
+
+QString
+DataBaseManager::getKey (uint32 n)
+{
+
+ DBT key;
+ DBT data;
+
+ memset (&key, 0, sizeof (DBT));
+ memset (&data, 0, sizeof (DBT));
+
+ key.data = &n;
+ key.size = 4;
+
+//Check for errors
+ int ret = indexDb->get (indexDb, 0, &key, &data, 0); //DB_SET_RECNO);
+ if (ret)
+ return QString::null;
+
+ return QString::fromUtf8 ((char *) data.data);
+
+// kdDebug(0) << QString("Trad %1").arg(ret) << endl;
+
+}
+
+int
+DataBaseManager::catalogRef (QString location, QString author, QString path)
+{
+ InfoItem cinfo;
+ int cat, catnum;
+ cat = searchCatalogInfo (location);
+
+ if (cat == -1) //Not exist
+ {
+ cinfo.catalogName = location;
+ cinfo.lastTranslator = author;
+ cinfo.lastFullPath = path;
+ //TO DO:
+ // //Add date info
+
+ kdDebug (0) << "New catalog " << endl;
+ catnum = addCatalogInfo (&cinfo);
+ //sync();
+ kdDebug (0) << "Ref " << catnum << endl;
+ }
+ else
+ {
+ cinfo = getCatalogInfo (cat);
+ //Update date.
+
+ //last path must be updated
+ cinfo.lastFullPath = path;
+ kdDebug (0) << "New full path " << path << endl;
+ kdDebug (0) << "Ref " << cat << endl;
+
+ catnum = addCatalogInfo (&cinfo, cat);
+ kdDebug (0) << " must be equal to " << catnum << endl;
+
+ catnum = cat;
+ }
+
+ return catnum;
+}
+
+int
+DataBaseManager::putNewTranslation (QString key, QString tran, int catalog,
+ bool ow)
+{
+ int catnum = catalog;
+ int count = 0;
+ QString msgid = key;
+ DataBaseItem dbit = getItem (msgid);
+
+ if (dbit.numTra == 0) //Not found
+ {
+ dbit.numTra += 1;
+
+ // use local variable, dbit.translations is QValueList and
+ // will create own copy
+ TranslationItem tra;
+ tra.numRef = 1;
+ tra.translation = tran;
+ tra.infoRef.append (catnum);
+ dbit.translations.append (tra);
+ dbit.key = key;
+
+ //Check ret value
+ count++;
+
+ int aa = putItem (&dbit);
+ if (aa)
+ kdDebug (0) << QString ("-----------put code ") << aa << endl;
+ }
+ else
+ {
+ // key exists
+
+ QString msgstr = tran;
+ bool found_catalog_info = false, foundTr = false, isThisOne = false;
+
+ QValueList < TranslationItem >::Iterator ittr;
+ bool rem = false;
+
+ // check all translations in the list
+ for (ittr = dbit.translations.begin ();
+ ittr != dbit.translations.end (); rem ? ittr : ++ittr)
+ {
+ rem = false;
+ found_catalog_info = false;
+
+ // is the translation one we should put there?
+ isThisOne = (*ittr).translation == msgstr;
+
+ // is there the catnum we are looking for?
+ if ((*ittr).infoRef.find (catnum) != (*ittr).infoRef.end ())
+ {
+ found_catalog_info = true;
+ if (ow && !isThisOne)
+ {
+ // I'll look for my catalog reference to del old
+ kdDebug (0) << "Removing the old translation " << endl;
+ (*ittr).numRef -= 1;
+ (*ittr).infoRef.remove (catnum);
+ if ((*ittr).numRef == 0)
+ {
+ dbit.numTra -= 1;
+ // point the iterator to the next valid item
+ ittr = dbit.translations.remove (ittr);
+ rem = true;
+ }
+ }
+ }
+
+ if (isThisOne)
+ {
+ if (!found_catalog_info)
+ {
+ //There are no reference of this catalog for this translation => add it
+ (*ittr).infoRef.append (catnum);
+ (*ittr).numRef += 1;
+ }
+ foundTr = true; // Ok, we found this translation, no need to add it.
+ }
+ }
+
+ if (!foundTr) //This translation is new => Add it !
+ {
+ count++;
+ TranslationItem tra;
+ tra.numRef = 1;
+ tra.translation = msgstr;
+ tra.infoRef.append (catnum);
+
+ dbit.translations.append (tra);
+ dbit.numTra += 1;
+ }
+
+ //put the new item in database overwriting the old one.
+ //Check ret value
+ int aa = putItem (&dbit, true);
+ if (aa)
+ kdDebug (0) << QString ("-----------put code ") << aa << endl;
+
+ }
+ return count;
+}
+
+
+void
+DataBaseManager::rebuildIndexes ()
+{
+// uint32 loc;
+#if 0
+//Reset the 2 databases here.
+
+ while (0 /*browse keys here */ )
+ {
+ loc = item->location = appendKey (item->key);
+
+ uint32 location = loc;
+
+ QValueList < QString > wlist;
+
+ wlist = wordsIn (item->key);
+
+ QValueList < QString >::Iterator wlistit;
+
+ for (wlistit = wlist.begin (); wlistit != wlist.end (); ++wlistit)
+ {
+ addLocation (*wlistit, location);
+ }
+
+ }
+#endif
+}
+
+
+
+#include "database.moc"
diff --git a/kbabel/kbabeldict/modules/dbsearchengine/database.h b/kbabel/kbabeldict/modules/dbsearchengine/database.h
new file mode 100644
index 00000000..bf4767df
--- /dev/null
+++ b/kbabel/kbabeldict/modules/dbsearchengine/database.h
@@ -0,0 +1,329 @@
+/***************************************************************************
+ database.h -
+ -------------------
+ begin : Fri Sep 8 2000
+ copyright : (C) 2000 by Andrea Rizzi
+ email : rizzi@kde.org
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * *
+ * In addition, as a special exception, the copyright holders give *
+ * permission to link the code of this program with any edition of *
+ * the Qt library by Trolltech AS, Norway (or with modified versions *
+ * of Qt that use the same license as Qt), and distribute linked *
+ * combinations including the two. You must obey the GNU General *
+ * Public License in all respects for all of the code used other than *
+ * Qt. If you modify this file, you may extend this exception to *
+ * your version of the file, but you are not obligated to do so. If *
+ * you do not wish to do so, delete this exception statement from *
+ * your version. *
+ ***************************************************************************/
+/*
+ Translation search engine
+
+
+ Copyright 2000
+ Andrea Rizzi rizzi@kde.org
+
+*/
+
+
+#ifndef _DATABASE_H_
+#define _DATABASE_H_
+
+#include <config.h>
+
+#ifdef USE_DB_H_PATH
+#include USE_DB_H_PATH
+#else
+#ifdef HAVE_DB4_DB_H
+#include <db4/db.h>
+#else
+#include <db.h>
+#endif
+#endif
+
+#define uint32 u_int32_t
+
+#include <qvaluelist.h>
+#include <qptrlist.h>
+#include <qstring.h>
+#include <qobject.h>
+#include <qdatetime.h>
+#include <qcstring.h> //bytearray
+
+
+class WordItem // Returned by getWordLocations
+{
+ public:
+
+ WordItem(char *data,QString w);
+ WordItem(QString w);
+ //WordItem(const WordItem &wi);
+ //WordItem& operator=(const WordItem & wi );
+
+ //The word (key in database)
+ QString word;
+ //Sorted locations
+ //QByteArray locations; //too many problems with this..
+ //NOTE:
+ //This is allocated only if you call WordItem(char *data,QString w);
+ //YOU MUST FREE IT when you do not need it anymore
+ //No destructor will do it !!!
+
+ uint32 *locations;
+
+
+ uint32 count;
+ //Is this word common ?
+ int score;
+
+ bool notFound();
+};
+
+
+class InfoItem
+{
+ public:
+
+ //Create the NO INFO item
+ InfoItem();
+
+ // Create an info item from raw data
+ InfoItem(const char *rawData,QString lang);
+
+ QString catalogName;
+ QString lastFullPath;
+
+ QString lastTranslator;
+ QDateTime revisionDate;
+ QString charset;
+ QString language;
+
+
+ int size();
+ void rawData(char *);
+
+};
+
+class TranslationItem
+{
+ public:
+ QString translation;
+ QValueList<int> infoRef;
+ uint32 numRef;
+
+};
+
+class DataBaseItem
+{
+ public:
+ /*
+ Create empty class;
+ */
+ DataBaseItem();
+
+ /*
+ Create a DataBaseItem from raw data
+ */
+ DataBaseItem(char *_key,char *_data);
+
+ /*
+ return the size (in raw data) of this item.
+ */
+ uint32 sizeData();
+ uint32 sizeKey();
+
+ bool isNull() { return (numTra==0); }
+
+ /*
+ You MUST allocate data of sizeData() byte.
+ */
+ void toRawData(char *_data);
+ void toRawKey(char *_key);
+
+ QString key;
+ QValueList<TranslationItem> translations;
+ uint32 numTra;
+ uint32 location;
+};
+
+class DataBaseManager : public QObject
+{
+
+ Q_OBJECT
+
+ public:
+ /*
+ Main constructor.
+ directory is the name of the directory where the database structre
+ is stored.
+
+ DIRECTORY/translations.$LANG.db The trasnaltion archive
+ DIRECTORY/catalogsinfo.$LANG.db Info about catalogs
+
+ //Not yet implemented
+ DIRECTORY/wordsindex.$LANG.db Index of words
+
+
+ */
+
+ DataBaseManager(QString directory,QString lang,QObject *parent=0,const char *name=0);
+ ~DataBaseManager();
+ /*
+ Create a new databse structure.
+
+ */
+ int createDataBase(QString directory,QString language,int mode=0664);
+
+
+
+
+ /*
+ Put a DataBaseItem into the database.
+
+ if ow==false enter the new DataBaseItem only
+ if the key of DataBaseItem does not previously exist
+
+ It also update the wordIndex.
+
+ */
+
+ int putItem(DataBaseItem *item,bool ow=false);
+
+ DataBaseItem getItem(QString key);
+
+ /*
+ @return the first entry in the database.
+ */
+
+ DataBaseItem firstItem();
+
+ /*
+ @return the current entry of the database.
+ */
+
+ DataBaseItem currentItem();
+
+ /*
+ @return the next entry in the database.
+ */
+
+ DataBaseItem nextItem();
+
+
+ /*
+ * Add a new translation to the database
+ * catalog is a valid catalog refnum (use catalogRef to get one)
+ * if ow is true a translation of a key coming from catalog is
+ * overwritten if you provide a new translation
+ */
+
+ int putNewTranslation(QString key,QString tran,int catalog,bool ow=true);
+
+ /*
+ @return info about catalog n
+ */
+
+ InfoItem getCatalogInfo(int n);
+
+ /*
+ Add an entry to catalogsinfo database and
+ @return a refnum for the new added item
+ */
+
+ int addCatalogInfo(InfoItem *catInfo,int);
+
+ /*
+ Search an Item with the same "location" and
+ @return its refnum.
+ */
+
+ int searchCatalogInfo(QString location);
+
+ /* Get a catalog info for location,
+ * if it doesn't exist it will create one.
+ * @return the refnum
+ */
+
+ int catalogRef(QString location,QString author,QString path);
+
+ /*
+ Put at refnum the catInfo
+ @return true if everything is OK
+ */
+
+ bool putCatalogInfo(int refnum, InfoItem *catInfo);
+
+ /*
+ Get word info
+ */
+ WordItem getWordLocations(QString word);
+
+ /*
+ Add a location for word
+ */
+ bool addLocation(QString word, unsigned int location);
+
+ /*
+ Remove location for word
+ */
+ bool removeLocation(QString word, int location);
+
+
+ /*
+ * Rebuild location and word indexes
+ */
+ void rebuildIndexes();
+
+ uint32 appendKey(class QString);
+
+ QString getKey(uint32 n);
+
+ /*
+ Load the catalogs info.
+ */
+ void loadInfo();
+
+
+ void sync();
+
+ bool isOk();
+ int count();
+ int current();
+
+ void openDataBase();
+ void closeDataBase();
+
+ static QValueList<QString> wordsIn(QString string);
+
+ signals:
+
+ void cannotOpenDB(int);
+
+
+ protected:
+ DataBaseItem cursorGet(uint32 flags);
+
+ QString language;
+ QString basedir;
+ QValueList<InfoItem> info;
+
+ DB *db,*infoDb,*wordDb,*indexDb;
+ DBC *cursor;
+ bool iAmOk;
+ bool indexOk; //Database could word without word index
+};
+
+
+
+
+
+#endif
diff --git a/kbabel/kbabeldict/modules/dbsearchengine/dbscan.cpp b/kbabel/kbabeldict/modules/dbsearchengine/dbscan.cpp
new file mode 100644
index 00000000..87b39e61
--- /dev/null
+++ b/kbabel/kbabeldict/modules/dbsearchengine/dbscan.cpp
@@ -0,0 +1,197 @@
+/***************************************************************************
+ dbscan.cpp - Scan for po files to add in the DB
+ -------------------
+ begin : Fri Sep 8 2000
+ copyright : (C) 2000 by Andrea Rizzi
+ email : rizzi@kde.org
+ ***************************************************************************/
+
+/*
+ Translation search engine
+
+
+ Copyright 2000
+ Andrea Rizzi rizzi@kde.org
+
+ License GPL v 2.0
+
+ * *
+ * In addition, as a special exception, the copyright holders give *
+ * permission to link the code of this program with any edition of *
+ * the Qt library by Trolltech AS, Norway (or with modified versions *
+ * of Qt that use the same license as Qt), and distribute linked *
+ * combinations including the two. You must obey the GNU General *
+ * Public License in all respects for all of the code used other than *
+ * Qt. If you modify this file, you may extend this exception to *
+ * your version of the file, but you are not obligated to do so. If *
+ * you do not wish to do so, delete this exception statement from *
+ * your version. *
+
+*/
+#include "dbscan.h"
+
+#include <qdir.h>
+#include <qfile.h>
+#include <kapplication.h>
+#include <kurl.h>
+#include <kdebug.h>
+
+using namespace KBabel;
+
+PoScanner::PoScanner(DataBaseManager *dbm,
+ QObject *parent,const char *name):QObject(parent,name)
+{
+dm=dbm;
+removeOldCatalogTranslation=false; //Check if this flag do something.
+count=0;
+}
+
+bool PoScanner::scanPattern(QString pathName,QString pattern,bool rec)
+{
+int tot;
+
+//Only one progress bar!!
+bool pb=false;
+static bool called=false;
+if (!called)
+{ pb=true; count=0;}
+called=true;
+
+kdDebug(0) << QString("cat: %1, %2").arg(pathName).arg(pattern) << endl;
+
+if(pb)
+{emit patternStarted();
+emit patternProgress(0);
+}
+ QDir d(pathName,pattern);
+ d.setMatchAllDirs(true);
+ const QFileInfoList* files = d.entryInfoList();
+ tot=files->count();
+ QPtrListIterator<QFileInfo> it(*files);
+kdDebug(0) << tot << endl;
+ for ( int i=0; i<tot; i++ )
+ {
+ if ((*it)->isDir())
+ {
+ if(rec)
+ {
+ kdDebug(0) << d[i] << endl;
+ if(d[i]!="." && d[i]!="..")
+ scanPattern(pathName+"/"+d[i],pattern,true);
+ }
+ } else
+ {
+ kdDebug(0) << d[i] << endl;
+ scanFile(pathName+"/"+d[i]);
+ }
+
+ if(pb)
+
+ emit patternProgress(100*i/tot);
+
+ //printf( "%s\n", d[i] );
+
+ ++it;
+ }
+
+
+
+if(pb)
+emit patternProgress(100);
+
+
+if(pb)
+emit patternFinished();
+if(pb){called=false;count=0;}
+
+return true;
+}
+
+
+
+
+bool PoScanner::scanFile(QString fileName)
+{
+
+
+emit fileStarted();
+
+InfoItem cinfo;
+Catalog * catalog=new Catalog(this,"ScanPoCatalog");
+
+
+QString location=fileName.right(fileName.length()-fileName.findRev("/")-1);
+connect(catalog,SIGNAL(signalProgress(int)),this,SIGNAL(fileLoading(int)));
+emit filename(location);
+emit fileProgress(0);
+emit fileLoading(0);
+
+KURL u(fileName);
+
+ConversionStatus rr=catalog->openURL(u);
+if(rr != OK && rr !=RECOVERED_PARSE_ERROR )
+{
+ delete catalog;
+ return false;
+}
+emit fileLoading(100);
+
+QString author;
+if(rr != HEADER_ERROR)
+ author=catalog->lastTranslator();
+else author=QString("unknown");
+
+int catnum=dm->catalogRef(location,author,fileName);
+
+uint i,tot;
+tot=catalog->numberOfEntries();
+//DataBaseItem dbit;
+bool fuzzy;
+bool untra;
+
+//kdDebug(0) << QString("Tot: %1").arg(tot) << endl;
+
+for (i=0;i<tot;i++) //Skip header = ????
+{
+
+ //Faster ?
+ if(i % 10==0)
+ {
+ emit fileProgress(100*i/tot);
+ emit added(count);
+ kapp->processEvents(100);
+ }
+
+ fuzzy=catalog->isFuzzy(i);
+ untra=catalog->isUntranslated(i);
+
+
+ if(!fuzzy && !untra)
+ {
+ int res;
+ QString msgid,msgstr;
+ msgid=catalog->msgid(i,true).first();
+ kdWarning() << "Translation database does not support plural forms" << endl;
+ msgstr=catalog->msgstr(i).first();
+ res=dm->putNewTranslation(msgid,msgstr,catnum,false);
+ count+=res;
+ }
+
+
+}
+
+
+// kdDebug(0) << QString("File finished") << endl;
+
+emit fileProgress(0);
+emit fileLoading(0);
+emit fileFinished();
+// dm->loadInfo(); // Sync the list of catalogs NOT NEEDED (?)
+
+delete catalog;
+
+//clear();
+return true;
+
+}
+#include "dbscan.moc"
diff --git a/kbabel/kbabeldict/modules/dbsearchengine/dbscan.h b/kbabel/kbabeldict/modules/dbsearchengine/dbscan.h
new file mode 100644
index 00000000..c151509e
--- /dev/null
+++ b/kbabel/kbabeldict/modules/dbsearchengine/dbscan.h
@@ -0,0 +1,86 @@
+/***************************************************************************
+ dbscan.h -
+ -------------------
+ begin : Fri Sep 8 2000
+ copyright : (C) 2000 by Andrea Rizzi
+ email : rizzi@kde.org
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * *
+ * In addition, as a special exception, the copyright holders give *
+ * permission to link the code of this program with any edition of *
+ * the Qt library by Trolltech AS, Norway (or with modified versions *
+ * of Qt that use the same license as Qt), and distribute linked *
+ * combinations including the two. You must obey the GNU General *
+ * Public License in all respects for all of the code used other than *
+ * Qt. If you modify this file, you may extend this exception to *
+ * your version of the file, but you are not obligated to do so. If *
+ * you do not wish to do so, delete this exception statement from *
+ * your version. *
+ ***************************************************************************/
+/*
+ Translation search engine
+
+
+ Copyright 2000
+ Andrea Rizzi rizzi@kde.org
+
+*/
+
+
+#ifndef _DBSCAN_H_
+#define _DBSCAN_H_
+
+#include <catalog.h>
+#include "database.h"
+
+class PoScanner : public QObject
+{
+ Q_OBJECT
+
+public:
+
+ PoScanner(DataBaseManager *dbm,QObject *parent=0,const char *name=0);
+
+ /*
+ Scan a single PO file.
+ */
+ bool scanFile(QString fileName);
+
+ /*
+ Scan a list of space separated files with possible MetaCharacters
+ */
+ bool scanPattern(QString pathName,QString pattern="*.po",bool rec=false);
+
+
+
+
+signals:
+ void fileStarted();
+ void fileProgress(int);
+ void fileFinished();
+ void fileLoading(int);
+ void patternStarted();
+ void patternProgress(int);
+ void patternFinished();
+ void added(int);
+ void filename(QString);
+private:
+
+ // If true when a translation is found in a CATALOG the old translation for this CATALOG
+ // will be removed
+ bool removeOldCatalogTranslation;
+ int count;
+ DataBaseManager *dm;
+// InfoItem cinfo;
+};
+
+
+#endif
diff --git a/kbabel/kbabeldict/modules/dbsearchengine/dbse_factory.cpp b/kbabel/kbabeldict/modules/dbsearchengine/dbse_factory.cpp
new file mode 100644
index 00000000..37332167
--- /dev/null
+++ b/kbabel/kbabeldict/modules/dbsearchengine/dbse_factory.cpp
@@ -0,0 +1,82 @@
+
+#include <klocale.h>
+#include <kinstance.h>
+#include <kaboutdata.h>
+#include <kdebug.h>
+
+#include "dbse_factory.h"
+#include "KDBSearchEngine.h"
+
+
+extern "C"
+{
+ KDE_EXPORT void *init_kbabeldict_dbsearchengine()
+ {
+ return new DbSeFactory;
+ }
+}
+
+
+KInstance *DbSeFactory::s_instance = 0;
+KAboutData *DbSeFactory::s_about = 0;
+
+
+DbSeFactory::DbSeFactory( QObject *parent, const char *name)
+ : KLibFactory(parent,name)
+{
+}
+
+DbSeFactory::~DbSeFactory()
+{
+ if(s_instance)
+ {
+ delete s_instance;
+ s_instance=0;
+ }
+
+ if(s_about)
+ {
+ delete s_about;
+ s_about=0;
+ }
+}
+
+
+QObject *DbSeFactory::createObject( QObject *parent, const char *name,
+ const char *classname, const QStringList &)
+{
+ if(QCString(classname) != "SearchEngine")
+ {
+ kdError() << "not a SearchEngine requested" << endl;
+ return 0;
+ }
+
+ KDBSearchEngine *se = new KDBSearchEngine(parent,name);
+
+ emit objectCreated(se);
+ return se;
+}
+
+
+KInstance *DbSeFactory::instance()
+{
+ if(!s_instance)
+ {
+
+ s_about = new KAboutData( "kdbsearchengine",
+ I18N_NOOP("Translation Database")
+ , "0.3" ,
+I18N_NOOP("A fast translation search engine based on databases")
+ , KAboutData::License_GPL
+ , I18N_NOOP("Copyright 2000-2001 by Andrea Rizzi")
+ ,0,0, "rizzi@kde.org");
+
+ s_about->addAuthor("Andrea Rizzi",0,"rizzi@kde.org");
+
+ s_instance = new KInstance(s_about);
+ }
+
+ return s_instance;
+}
+
+#include "dbse_factory.moc"
diff --git a/kbabel/kbabeldict/modules/dbsearchengine/dbse_factory.h b/kbabel/kbabeldict/modules/dbsearchengine/dbse_factory.h
new file mode 100644
index 00000000..6a9f9f3d
--- /dev/null
+++ b/kbabel/kbabeldict/modules/dbsearchengine/dbse_factory.h
@@ -0,0 +1,26 @@
+#ifndef DBSE_FACTORY_H
+#define DBSE_FACTORY_H
+
+#include <klibloader.h>
+class KInstance;
+class KAboutData;
+
+class DbSeFactory : public KLibFactory
+{
+ Q_OBJECT
+public:
+ DbSeFactory( QObject *parent=0, const char *name=0);
+ ~DbSeFactory();
+
+ virtual QObject *createObject( QObject *parent=0, const char *name=0,
+ const char *classname="QObject",
+ const QStringList &args = QStringList());
+
+ static KInstance *instance();
+
+private:
+ static KInstance *s_instance;
+ static KAboutData *s_about;
+};
+
+#endif
diff --git a/kbabel/kbabeldict/modules/dbsearchengine/dbsearchengine.desktop b/kbabel/kbabeldict/modules/dbsearchengine/dbsearchengine.desktop
new file mode 100644
index 00000000..6aed2e40
--- /dev/null
+++ b/kbabel/kbabeldict/modules/dbsearchengine/dbsearchengine.desktop
@@ -0,0 +1,52 @@
+[Desktop Entry]
+Type=Service
+Name=Translation Database for KBabelDict
+Name[bg]=БД Ñ Ð¿Ñ€ÐµÐ²Ð¾Ð´Ð¸ за KBabelDict
+Name[br]=Stlennvon geriaoueg evit KBabelDict
+Name[bs]=Baza prijevoda za KBabelDict
+Name[ca]=Base de dades de traducció per a KBabelDict
+Name[cs]=Databáze překladů pro KBabelDict
+Name[cy]=Cronfa ddata Cyfieithiadau i KBabelDict
+Name[da]=Oversættelsesdatabase for KBabelDict
+Name[de]=Übersetzungsdatenbank für KBabelDict
+Name[el]=Βάση δεδομένων μετάφÏασης για το KBabelDict
+Name[es]=Base de datos de traducciones para KBabelDict
+Name[et]=KBabelDicti tõlgete andmebaas
+Name[eu]=Itzulpen datu-basea KBabelDict-entzat
+Name[fa]=دادگان ترجمه برای KBabelDict
+Name[fi]=KBabelDict-ohjelman käännöstietokanta
+Name[fr]=Base de données des traductions pour KBabelDict
+Name[ga]=Cuimhne Aistriúcháin le haghaidh KBabelDict
+Name[gl]=Base de datos de traducións de KBabelDict
+Name[hi]=के-बेबल-डिकà¥à¤¶ के लिठअनà¥à¤µà¤¾à¤¦ डाटाबेस
+Name[hu]=Fordítási adatbázis a KBabelDicthez
+Name[is]=Þýðingagagnagrunnur fyrir KBabel orðabókina
+Name[it]=Banca dati di traduzioni per KBabelDict
+Name[ja]=KBabelDict トランザクションデータベース
+Name[ka]=თáƒáƒ áƒ’მნის მáƒáƒœáƒáƒªáƒ”მთრბáƒáƒ–რKBabelDict-სთვის
+Name[kk]=KBabelDict-тың аударма деректер қоры
+Name[lt]=KBabelDict vertimų duomenų bazė
+Name[ms]=Pangkalan Data Penterjemahan KBabelDict
+Name[nb]=Oversettelsesdatabase for KBabelDict
+Name[nds]=Översettendatenbank för KBabelDict
+Name[ne]=KBabelDict का लागि अनà¥à¤¬à¤¾à¤¦ डाटाबेस
+Name[nl]=Vertalingendatabase voor KBabelDict
+Name[nn]=Omsetjingsdatabase for KBabelDict
+Name[pa]=ਕੇਬਬੇਲ-ਸ਼ਬਦ-ਕੋਸ਼ ਲਈ ਅਨà©à¨µà¨¾à¨¦ ਡਾਟਾਬੇਸ
+Name[pl]=Baza tłumaczeń dla KBabelDict
+Name[pt]=Base de Dados de Traduções do KBabelDict
+Name[pt_BR]=Banco de Dados de Traduções para o KBabelDict
+Name[ru]=База данных переводов Ð´Ð»Ñ KBabelDict
+Name[sk]=Databáza prekladov pre KBabelDict
+Name[sl]=Zbirka prevodov za KBabelDict
+Name[sr]=Преводилачка база података за KBabelDict
+Name[sr@Latn]=PrevodilaÄka baza podataka za KBabelDict
+Name[sv]=Översättningsdatabas för Kbabeldict
+Name[ta]=Kபாபேலà¯à®•à¯à®•à®¾à®© மொழிபெயரà¯à®ªà¯à®ªà¯ தரவà¯à®¤à¯à®¤à®³à®®à¯
+Name[tg]=Базаи маълумоти тарҷумаҳо барои KBabelDict
+Name[tr]=KBabelDict için Çeviri Veritabanı
+Name[uk]=База даних перекладів Ð´Ð»Ñ KBabelDict
+Name[zh_CN]=KBabelDict 的翻译数æ®åº“
+Name[zh_TW]=KBabelDict 翻譯資料庫
+X-KDE-Library=kbabeldict_dbsearchengine
+ServiceTypes=KBabelDictModule
diff --git a/kbabel/kbabeldict/modules/dbsearchengine/dbseprefwidget.ui b/kbabel/kbabeldict/modules/dbsearchengine/dbseprefwidget.ui
new file mode 100644
index 00000000..d18ecaef
--- /dev/null
+++ b/kbabel/kbabeldict/modules/dbsearchengine/dbseprefwidget.ui
@@ -0,0 +1,1036 @@
+<!DOCTYPE UI><UI version="3.0" stdsetdef="1">
+<class>DBSearchEnginePref</class>
+<author>Andrea Rizzi &lt;rizzi@kde.org&gt;</author>
+<widget class="QWidget">
+ <property name="name">
+ <cstring>DBSEPrefWidget</cstring>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>414</width>
+ <height>426</height>
+ </rect>
+ </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="QTabWidget" row="0" column="0">
+ <property name="name">
+ <cstring>TabWidget6</cstring>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string></string>
+ </property>
+ <widget class="QWidget">
+ <property name="name">
+ <cstring>Widget4</cstring>
+ </property>
+ <attribute name="title">
+ <string>Generic</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="QButtonGroup">
+ <property name="name">
+ <cstring>ButtonGroup2</cstring>
+ </property>
+ <property name="title">
+ <string>Search Mode</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="QRadioButton" row="0" column="0">
+ <property name="name">
+ <cstring>allRB</cstring>
+ </property>
+ <property name="text">
+ <string>Search in whole database (slow)</string>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>&lt;qml&gt;Scroll the whole database and return everything that matches
+according to the rules defined in tabs &lt;strong&gt; Generic &lt;/strong&gt;
+and &lt;strong&gt;Match&lt;/strong&gt;</string>
+ </property>
+ </widget>
+ <widget class="QRadioButton" row="1" column="0">
+ <property name="name">
+ <cstring>slistRB</cstring>
+ </property>
+ <property name="text">
+ <string>Search in list of "good keys" (best)</string>
+ </property>
+ <property name="checked">
+ <bool>true</bool>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>&lt;qml&gt;Search in a list of &lt;em&gt;good keys&lt;/em&gt; (see &lt;strong&gt;Good keys&lt;/strong&gt; tab) with rules defined in &lt;strong&gt;Search&lt;/strong&gt; tab.
+This is the best way to search because the &lt;em&gt;good keys&lt;/em&gt; list probably contains all the keys that match with your query. However, it is smaller than the whole database.</string>
+ </property>
+ </widget>
+ <widget class="QRadioButton" row="2" column="0">
+ <property name="name">
+ <cstring>rlistRB</cstring>
+ </property>
+ <property name="text">
+ <string>Return the list of "good keys" (fast)</string>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>&lt;qml&gt;Returns the whole &lt;em&gt;good keys&lt;/em&gt; list. Rules defined in &lt;strong&gt;Search&lt;/strong&gt; tab are ignored.</string>
+ </property>
+ </widget>
+ </grid>
+ </widget>
+ <widget class="QCheckBox">
+ <property name="name">
+ <cstring>caseSensitiveCB</cstring>
+ </property>
+ <property name="text">
+ <string>Case sensitive</string>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>&lt;qml&gt;If it is checked the search will be case sensitive. It is ignored if you use &lt;em&gt;Return the list of "good keys"&lt;/em&gt; search mode.</string>
+ </property>
+ </widget>
+ <widget class="QCheckBox">
+ <property name="name">
+ <cstring>normalizeCB</cstring>
+ </property>
+ <property name="text">
+ <string>Normalize white space</string>
+ </property>
+ <property name="checked">
+ <bool>true</bool>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>Remove white spaces at the beginning and at the end of the phrase.
+It also substitutes groups of more than one space character with only one space character.</string>
+ </property>
+ </widget>
+ <widget class="QCheckBox">
+ <property name="name">
+ <cstring>removeContextCB</cstring>
+ </property>
+ <property name="text">
+ <string>Remove context comment</string>
+ </property>
+ <property name="checked">
+ <bool>true</bool>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>Remove, if exists, the _:comment</string>
+ </property>
+ </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>TextLabel3</cstring>
+ </property>
+ <property name="text">
+ <string>Character to be ignored:</string>
+ </property>
+ </widget>
+ <widget class="KLineEdit">
+ <property name="name">
+ <cstring>ignoreLE</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>7</hsizetype>
+ <vsizetype>5</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="minimumSize">
+ <size>
+ <width>0</width>
+ <height>20</height>
+ </size>
+ </property>
+ </widget>
+ </hbox>
+ </widget>
+ <spacer>
+ <property name="name">
+ <cstring>Spacer1</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Vertical</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ </spacer>
+ </vbox>
+ </widget>
+ <widget class="QWidget">
+ <property name="name">
+ <cstring>Widget5</cstring>
+ </property>
+ <attribute name="title">
+ <string>Search</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="QButtonGroup">
+ <property name="name">
+ <cstring>ButtonGroup1</cstring>
+ </property>
+ <property name="title">
+ <string>Matching Method</string>
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>11</number>
+ </property>
+ <property name="spacing">
+ <number>6</number>
+ </property>
+ <spacer row="1" column="0">
+ <property name="name">
+ <cstring>Spacer4</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>
+ <spacer row="2" column="0">
+ <property name="name">
+ <cstring>Spacer6</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="QCheckBox" row="2" column="1">
+ <property name="name">
+ <cstring>containedCB</cstring>
+ </property>
+ <property name="text">
+ <string>Query is contained</string>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>Match if query is contained in database string</string>
+ </property>
+ </widget>
+ <widget class="QCheckBox" row="3" column="1">
+ <property name="name">
+ <cstring>containsCB</cstring>
+ </property>
+ <property name="text">
+ <string>Query contains</string>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>Match if query contains the database string</string>
+ </property>
+ </widget>
+ <widget class="QRadioButton" row="0" column="0" rowspan="1" colspan="2">
+ <property name="name">
+ <cstring>normalTextRB</cstring>
+ </property>
+ <property name="text">
+ <string>Normal text</string>
+ </property>
+ <property name="checked">
+ <bool>true</bool>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>Consider the search string as normal text.</string>
+ </property>
+ </widget>
+ <widget class="QCheckBox" row="1" column="1">
+ <property name="name">
+ <cstring>equalCB</cstring>
+ </property>
+ <property name="text">
+ <string>Equal</string>
+ </property>
+ <property name="checked">
+ <bool>true</bool>
+ </property>
+ <property name="tristate">
+ <bool>false</bool>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>Match if query and database string are equal</string>
+ </property>
+ </widget>
+ <spacer row="3" column="0">
+ <property name="name">
+ <cstring>Spacer7</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="QRadioButton" row="4" column="0" rowspan="1" colspan="2">
+ <property name="name">
+ <cstring>RegExpRB</cstring>
+ </property>
+ <property name="text">
+ <string>Regular expression</string>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>Consider the search string as a regular expression</string>
+ </property>
+ </widget>
+ </grid>
+ </widget>
+ <widget class="QGroupBox">
+ <property name="name">
+ <cstring>GroupBox3</cstring>
+ </property>
+ <property name="title">
+ <string>Word Substitution</string>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>&lt;qml&gt;If you use one or two &lt;em&gt;word substitution&lt;/em&gt; each time you search a phrase with less than the specified number of words, the search engine will also search for all phrases that differ from the original one in one or two words.&lt;p&gt;
+&lt;strong&gt;Example:&lt;/strong&gt;&lt;br&gt;
+If you search for &lt;em&gt;My name is Andrea&lt;/em&gt; and you have activated &lt;em&gt;one word substitution&lt;/em&gt; you may also find phrases like &lt;em&gt;My name is Joe&lt;/em&gt; or &lt;em&gt;Your name is Andrea&lt;/em&gt;.</string>
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>11</number>
+ </property>
+ <property name="spacing">
+ <number>6</number>
+ </property>
+ <spacer row="3" column="0">
+ <property name="name">
+ <cstring>Spacer8</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="QCheckBox" row="0" column="0" rowspan="1" colspan="3">
+ <property name="name">
+ <cstring>oneWordSubCB</cstring>
+ </property>
+ <property name="text">
+ <string>Use one word substitution</string>
+ </property>
+ <property name="checked">
+ <bool>true</bool>
+ </property>
+ <property name="tristate">
+ <bool>false</bool>
+ </property>
+ </widget>
+ <spacer row="1" column="0">
+ <property name="name">
+ <cstring>Spacer9</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" row="1" column="1">
+ <property name="name">
+ <cstring>TextLabel1</cstring>
+ </property>
+ <property name="text">
+ <string>Max number of words in the query:</string>
+ </property>
+ </widget>
+ <widget class="QSpinBox" row="3" column="2">
+ <property name="name">
+ <cstring>twoWordSubSB</cstring>
+ </property>
+ <property name="enabled">
+ <bool>false</bool>
+ </property>
+ <property name="maxValue">
+ <number>14</number>
+ </property>
+ <property name="value">
+ <number>10</number>
+ </property>
+ </widget>
+ <widget class="QCheckBox" row="2" column="0" rowspan="1" colspan="2">
+ <property name="name">
+ <cstring>twoWordSubCB</cstring>
+ </property>
+ <property name="enabled">
+ <bool>false</bool>
+ </property>
+ <property name="text">
+ <string>Use two word substitution</string>
+ </property>
+ <property name="checked">
+ <bool>true</bool>
+ </property>
+ </widget>
+ <widget class="QLabel" row="3" column="1">
+ <property name="name">
+ <cstring>TextLabel2</cstring>
+ </property>
+ <property name="text">
+ <string>Max number of words in the query:</string>
+ </property>
+ </widget>
+ <widget class="QLayoutWidget" row="5" column="0" rowspan="1" colspan="3">
+ <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>TextLabel5_3</cstring>
+ </property>
+ <property name="text">
+ <string>[A-Za-z0-9_%</string>
+ </property>
+ <property name="alignment">
+ <set>AlignVCenter|AlignRight</set>
+ </property>
+ <property name="hAlign" stdset="0">
+ </property>
+ </widget>
+ <widget class="KLineEdit">
+ <property name="name">
+ <cstring>regExpLE</cstring>
+ </property>
+ </widget>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>TextLabel6_2</cstring>
+ </property>
+ <property name="text">
+ <string>]</string>
+ </property>
+ </widget>
+ </hbox>
+ </widget>
+ <widget class="QLabel" row="4" column="0" rowspan="1" colspan="3">
+ <property name="name">
+ <cstring>TextLabel4</cstring>
+ </property>
+ <property name="text">
+ <string>Local characters for regular expressions:</string>
+ </property>
+ </widget>
+ <widget class="QSpinBox" row="1" column="2">
+ <property name="name">
+ <cstring>oneWordSubSB</cstring>
+ </property>
+ <property name="maxValue">
+ <number>200</number>
+ </property>
+ <property name="minValue">
+ <number>2</number>
+ </property>
+ <property name="value">
+ <number>40</number>
+ </property>
+ </widget>
+ </grid>
+ </widget>
+ <spacer>
+ <property name="name">
+ <cstring>Spacer1_2</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Vertical</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ </spacer>
+ </vbox>
+ </widget>
+ <widget class="QWidget">
+ <property name="name">
+ <cstring>Widget6</cstring>
+ </property>
+ <attribute name="title">
+ <string>Database</string>
+ </attribute>
+ <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" rowspan="1" colspan="3">
+ <property name="name">
+ <cstring>TextLabel7_2</cstring>
+ </property>
+ <property name="text">
+ <string>Database folder:</string>
+ </property>
+ </widget>
+ <widget class="KURLRequester" row="1" column="0" rowspan="1" colspan="3">
+ <property name="name">
+ <cstring>dirInput</cstring>
+ </property>
+ </widget>
+ <widget class="QCheckBox" row="2" column="0" rowspan="1" colspan="3">
+ <property name="name">
+ <cstring>autoAddCB_2</cstring>
+ </property>
+ <property name="enabled">
+ <bool>true</bool>
+ </property>
+ <property name="text">
+ <string>Auto add entry to database</string>
+ </property>
+ <property name="checked">
+ <bool>true</bool>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>Automatically add an entry to the database if a new translation is notified by someone (may be kbabel)</string>
+ </property>
+ </widget>
+ <widget class="QLayoutWidget" row="3" column="0" rowspan="1" colspan="3">
+ <property name="name">
+ <cstring>Layout3</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>Auto added entry author:</string>
+ </property>
+ </widget>
+ <widget class="QLineEdit">
+ <property name="name">
+ <cstring>authorLE</cstring>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>&lt;qml&gt;Put here the name and email address that you want to use as &lt;em&gt;last translator&lt;/em&gt; filed when you auto-add entry to the database (e.g. when you modify a translation with kbabel).&lt;p&gt;</string>
+ </property>
+ </widget>
+ </hbox>
+ </widget>
+ <widget class="QPushButton" row="4" column="0" rowspan="1" colspan="3">
+ <property name="name">
+ <cstring>scanFilePB</cstring>
+ </property>
+ <property name="text">
+ <string>Scan Single PO File...</string>
+ </property>
+ </widget>
+ <widget class="QPushButton" row="5" column="0" rowspan="1" colspan="3">
+ <property name="name">
+ <cstring>scanPB_2</cstring>
+ </property>
+ <property name="text">
+ <string>Scan Folder...</string>
+ </property>
+ </widget>
+ <widget class="QPushButton" row="6" column="0" rowspan="1" colspan="3">
+ <property name="name">
+ <cstring>scanrecPB</cstring>
+ </property>
+ <property name="text">
+ <string>Scan Folder &amp;&amp; Subfolders...</string>
+ </property>
+ </widget>
+ <widget class="QLayoutWidget" row="8" column="0" rowspan="1" colspan="3">
+ <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>filenameLB</cstring>
+ </property>
+ <property name="text">
+ <string>Scanning file:</string>
+ </property>
+ </widget>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>entriesLB</cstring>
+ </property>
+ <property name="text">
+ <string>Entries added:</string>
+ </property>
+ </widget>
+ </vbox>
+ </widget>
+ <widget class="QLayoutWidget" row="9" column="0" rowspan="1" colspan="3">
+ <property name="name">
+ <cstring>Layout4</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="QProgressBar" row="2" column="1">
+ <property name="name">
+ <cstring>processPB</cstring>
+ </property>
+ <property name="frameShape">
+ <enum>Panel</enum>
+ </property>
+ <property name="frameShadow">
+ <enum>Sunken</enum>
+ </property>
+ <property name="centerIndicator">
+ <bool>true</bool>
+ </property>
+ <property name="indicatorFollowsStyle">
+ <bool>false</bool>
+ </property>
+ </widget>
+ <widget class="QLabel" row="0" column="0">
+ <property name="name">
+ <cstring>TextLabel1_3</cstring>
+ </property>
+ <property name="text">
+ <string>Total progress:</string>
+ </property>
+ </widget>
+ <widget class="QLabel" row="2" column="0">
+ <property name="name">
+ <cstring>TextLabel3_3</cstring>
+ </property>
+ <property name="text">
+ <string>Processing file:</string>
+ </property>
+ </widget>
+ <widget class="QProgressBar" row="0" column="1">
+ <property name="name">
+ <cstring>totalPB</cstring>
+ </property>
+ <property name="frameShape">
+ <enum>Panel</enum>
+ </property>
+ <property name="frameShadow">
+ <enum>Sunken</enum>
+ </property>
+ <property name="centerIndicator">
+ <bool>true</bool>
+ </property>
+ </widget>
+ <widget class="QProgressBar" row="1" column="1">
+ <property name="name">
+ <cstring>loadingPB</cstring>
+ </property>
+ <property name="frameShape">
+ <enum>Panel</enum>
+ </property>
+ <property name="frameShadow">
+ <enum>Sunken</enum>
+ </property>
+ <property name="centerIndicator">
+ <bool>true</bool>
+ </property>
+ </widget>
+ <widget class="QLabel" row="1" column="0">
+ <property name="name">
+ <cstring>TextLabel2_3</cstring>
+ </property>
+ <property name="text">
+ <string>Loading file:</string>
+ </property>
+ </widget>
+ </grid>
+ </widget>
+ <widget class="QPushButton" row="10" column="2">
+ <property name="name">
+ <cstring>exportPB</cstring>
+ </property>
+ <property name="enabled">
+ <bool>false</bool>
+ </property>
+ <property name="text">
+ <string>Export...</string>
+ </property>
+ </widget>
+ <widget class="QPushButton" row="10" column="0">
+ <property name="name">
+ <cstring>statPB</cstring>
+ </property>
+ <property name="enabled">
+ <bool>false</bool>
+ </property>
+ <property name="text">
+ <string>Statistics</string>
+ </property>
+ </widget>
+ <widget class="QPushButton" row="10" column="1">
+ <property name="name">
+ <cstring>repeatPB</cstring>
+ </property>
+ <property name="text">
+ <string>Repeated Strings</string>
+ </property>
+ </widget>
+ </grid>
+ </widget>
+ <widget class="QWidget">
+ <property name="name">
+ <cstring>tab</cstring>
+ </property>
+ <attribute name="title">
+ <string>Good Keys</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="QGroupBox">
+ <property name="name">
+ <cstring>GroupBox4</cstring>
+ </property>
+ <property name="title">
+ <string>Generic</string>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>&lt;qml&gt;Here you can define how to fill the &lt;em&gt;good keys list&lt;/em&gt;.&lt;p&gt;
+You can set the minimum number of words of the query that a key must have to be inserted in the &lt;em&gt;good keys list&lt;/em&gt;.&lt;p&gt;
+You can also set the minimum number of words of the key that the query must have to insert the key in the list.&lt;p&gt;
+These two numbers are the percentage of the total number of words. If the result of this percentage is less than one, the engine will set it to one.&lt;p&gt;
+Finally you can set the maximum number of entries in the list.</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="2" column="0" rowspan="1" colspan="2">
+ <property name="name">
+ <cstring>TextLabel3_2</cstring>
+ </property>
+ <property name="text">
+ <string>Minimum number of words of the key also in the query (%):</string>
+ </property>
+ <property name="textFormat">
+ <enum>RichText</enum>
+ </property>
+ </widget>
+ <widget class="QSlider" row="1" column="0">
+ <property name="name">
+ <cstring>thresholdSL</cstring>
+ </property>
+ <property name="maxValue">
+ <number>100</number>
+ </property>
+ <property name="value">
+ <number>50</number>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ </widget>
+ <widget class="QSpinBox" row="1" column="1">
+ <property name="name">
+ <cstring>SpinBox5</cstring>
+ </property>
+ <property name="suffix">
+ <string>%</string>
+ </property>
+ <property name="maxValue">
+ <number>100</number>
+ </property>
+ <property name="value">
+ <number>50</number>
+ </property>
+ </widget>
+ <widget class="QLabel" row="0" column="0" rowspan="1" colspan="2">
+ <property name="name">
+ <cstring>TextLabel2_2</cstring>
+ </property>
+ <property name="text">
+ <string>Minimum number of query words in the key (%):</string>
+ </property>
+ </widget>
+ <widget class="QSpinBox" row="4" column="1">
+ <property name="name">
+ <cstring>maxSB</cstring>
+ </property>
+ <property name="maxValue">
+ <number>5000</number>
+ </property>
+ <property name="value">
+ <number>30</number>
+ </property>
+ </widget>
+ <widget class="QSpinBox" row="3" column="1">
+ <property name="name">
+ <cstring>SpinBox6</cstring>
+ </property>
+ <property name="suffix">
+ <string>%</string>
+ </property>
+ <property name="maxValue">
+ <number>100</number>
+ </property>
+ <property name="value">
+ <number>50</number>
+ </property>
+ </widget>
+ <widget class="QLabel" row="4" column="0">
+ <property name="name">
+ <cstring>TextLabel4_2</cstring>
+ </property>
+ <property name="text">
+ <string>Max list length:</string>
+ </property>
+ </widget>
+ <widget class="QSlider" row="3" column="0">
+ <property name="name">
+ <cstring>thresholdOrigSL</cstring>
+ </property>
+ <property name="maxValue">
+ <number>100</number>
+ </property>
+ <property name="value">
+ <number>50</number>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ </widget>
+ </grid>
+ </widget>
+ <widget class="QGroupBox">
+ <property name="name">
+ <cstring>GroupBox3_2</cstring>
+ </property>
+ <property name="title">
+ <string>Frequent Words</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_2</cstring>
+ </property>
+ <property name="text">
+ <string>Discard words more frequent than:</string>
+ </property>
+ </widget>
+ <widget class="QSpinBox" row="0" column="1">
+ <property name="name">
+ <cstring>freqSB</cstring>
+ </property>
+ <property name="suffix">
+ <string>/10000</string>
+ </property>
+ <property name="maxValue">
+ <number>10000</number>
+ </property>
+ <property name="lineStep">
+ <number>1</number>
+ </property>
+ <property name="value">
+ <number>100</number>
+ </property>
+ </widget>
+ <widget class="QCheckBox" row="1" column="0" rowspan="1" colspan="2">
+ <property name="name">
+ <cstring>nothingCB</cstring>
+ </property>
+ <property name="text">
+ <string>Frequent words are considered as in every key</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>
+ </spacer>
+ </vbox>
+ </widget>
+ </widget>
+ </grid>
+</widget>
+<connections>
+ <connection>
+ <sender>thresholdSL</sender>
+ <signal>valueChanged(int)</signal>
+ <receiver>SpinBox5</receiver>
+ <slot>setValue(int)</slot>
+ </connection>
+ <connection>
+ <sender>thresholdOrigSL</sender>
+ <signal>valueChanged(int)</signal>
+ <receiver>SpinBox6</receiver>
+ <slot>setValue(int)</slot>
+ </connection>
+ <connection>
+ <sender>SpinBox5</sender>
+ <signal>valueChanged(int)</signal>
+ <receiver>thresholdSL</receiver>
+ <slot>setValue(int)</slot>
+ </connection>
+ <connection>
+ <sender>SpinBox6</sender>
+ <signal>valueChanged(int)</signal>
+ <receiver>thresholdOrigSL</receiver>
+ <slot>setValue(int)</slot>
+ </connection>
+</connections>
+<includes>
+ <include location="local" impldecl="in declaration">klocale.h</include>
+ <include location="global" impldecl="in declaration">kseparator.h</include>
+</includes>
+<layoutdefaults spacing="6" margin="11"/>
+</UI>
diff --git a/kbabel/kbabeldict/modules/dbsearchengine/makemsgdb.C b/kbabel/kbabeldict/modules/dbsearchengine/makemsgdb.C
new file mode 100644
index 00000000..a83d947b
--- /dev/null
+++ b/kbabel/kbabeldict/modules/dbsearchengine/makemsgdb.C
@@ -0,0 +1,327 @@
+#include <stdio.h>
+#include <time.h>
+#include <errno.h>
+#include <gdbm.h>
+#include <string.h>
+
+void removechar (char *s, int c)
+{
+ int i, l;
+ l = strlen (s);
+ if ((c >= l) || (c < 0))
+ return;
+ for (i = c; i < l; i++)
+ s[i] = s[i + 1];
+}
+void removeallc (char *s, char c)
+{
+ char *pos;
+ while ((pos = strchr (s, c)) != 0)
+ removechar (s, (long int) pos - (long int) s);
+
+}
+
+void normalizestr (char *s)
+{
+ char *pos;
+ while ((pos = strstr (s, "#~")) != 0) {
+ removechar (s, (long int) pos - (long int) s);
+ removechar (s, (long int) pos - (long int) s);
+ }
+ while (strchr (s, ' ') == s)
+ removechar (s, 0);
+}
+
+void freadline(char *buff,FILE *f)
+{
+char c;
+while ((fread(&c,1,1,f)==1) && (c!='\n'))
+ {
+ *buff=c;
+ buff++;
+ }
+*buff=0;
+
+}
+
+int makePoDb(const char* sourceName,const char* outputName)
+{
+static bool open = false;
+int m=0,n=0,h=0;
+GDBM_FILE db;
+datum key,value;
+char *s,a[20000],b[2000],k[2000],v[2000];
+int i,*np,nmax=0,co=-1,oldref[2000];
+long int tim;
+FILE *mlf;
+bool nextIsFuzzy;
+bool isAMsgId=true;
+/* char keystring[1000],valuestring[1000]; */
+
+/*Read headers, refnum end other info */
+db = gdbm_open((char *)outputName,1024,GDBM_READER,0666,0);
+mlf = fopen(sourceName,"r");
+if(strrchr(sourceName,'/')!=0)
+sourceName=strrchr(sourceName,'/')+1;
+
+if(!(db==0))
+ {
+ printf("ciao\n");
+ key.dptr=a;
+ strcpy(a,"__@REFNUM__");
+ key.dsize=strlen(a)+1;
+ value = gdbm_fetch(db,key);
+ np=(int*)value.dptr;
+ nmax=*np;
+ for(i=0;i<nmax;i++) {
+ sprintf(a,"__@%d__",i);
+ key.dsize=strlen(a)+1;
+ value = gdbm_fetch(db,key);
+ if(strcmp(value.dptr,sourceName)==0)
+ oldref[++co]=i;
+ // printf("File %s in Date %s\nRef # %d, oldref[%d]=%d\n",value.dptr,value.dptr+1+strlen(value.dptr),i,co,oldref[co]);
+ }
+ gdbm_close(db);
+ }
+
+
+db = gdbm_open((char *)outputName,1024,GDBM_WRCREAT,0666,0);
+if(db==0) return 0;
+
+nmax++;
+//sourceName=strrchr(sourceName,'/')+1;
+ if(open) return 0;
+ open=true;
+
+ key.dptr=a;
+ strcpy(a,"__@REFNUM__");
+ key.dsize=strlen(a)+1;
+ value.dptr=(char *)&nmax;
+ value.dsize=4;
+ gdbm_store(db,key,value,GDBM_REPLACE);
+ sprintf(a,"__@%d__",nmax-1);
+ key.dsize=strlen(a)+1;
+ strcpy(v,sourceName);
+ value.dptr=v;
+ time(&tim);
+// ctime(&tim);
+ // fprintf(stderr,"%s %s\n",v,ctime(&tim));
+ strcpy(v+strlen(v)+1,ctime(&tim));
+ value.dsize=strlen(v)+2+strlen(v+strlen(v)+1);
+ gdbm_store(db,key,value,GDBM_REPLACE);
+
+ while(!feof(mlf))
+ {
+ freadline(a,mlf);
+ normalizestr(a);
+// printf("#%s#\n",a);
+
+// while (st.find("#~")==0)
+// st = st.right(st.length()-2);
+// while (st.find(" ")==0)
+// st = st.right(st.length()-1);
+
+ if(isAMsgId) nextIsFuzzy=false;
+ if(strstr(a,"#,")==a)
+ if(strstr(a,"fuzzy")!=0) nextIsFuzzy=true;
+ isAMsgId=(strstr(a,"msgid"));
+ if(isAMsgId && !nextIsFuzzy)
+ {
+ *b='\0';
+ clearerr(mlf);
+ while(!feof(mlf) && !(strstr(a,"msgstr")==a))
+ {
+ strcat(b,strchr(a,'"')+1);
+ *strrchr(b,'\"')= '\0'; //"
+ freadline(a,mlf);
+ normalizestr(a);
+
+
+ if(b+strlen(b)==strstr(b,"\\n")+2)
+ {
+ b[strlen(b)-2]='\n';
+ b[strlen(b)-1]='\0';
+ }
+ }
+
+ // fprintf(stderr,"MSGID#%s#\n",b);
+ //}
+
+ if(b[0]!='\0') {
+ key.dptr=k;
+ strcpy(k,b);
+ key.dsize=strlen(key.dptr)+1;
+ int lines=0;
+ *b='\0';
+ while(!feof(mlf) && !(strstr(a,"msgid")==a) && !(strchr(a,'"')==0))
+ {
+ lines++;
+ strcat(b,strchr(a,'"')+1);
+ *strrchr(b,'\"')= '\0'; //"
+ freadline(a,mlf);
+ normalizestr(a);
+
+
+ if(b+strlen(b)==strstr(b,"\\n")+2)
+ {
+ b[strlen(b)-2]='\n';
+ b[strlen(b)-1]='\0';
+ }
+ }
+ value.dptr=v;
+ int *t;
+ int *nr,*re; //,*md; //Number of references,ref
+
+ t=(int *)value.dptr;
+ *t=1;
+ strcpy(value.dptr+4,b);
+ nr=(int *)(value.dptr+4+strlen(value.dptr+4)+1);
+ *nr=1;
+ nr++;
+ *nr=nmax-1;
+ value.dsize=strlen(value.dptr+4)+1+4+8;
+ // fprintf(stderr,"MSGSTR#%s#nref=%d\n",value.dptr+4,
+// *(int*)(value.dptr+4+strlen(value.dptr+4)+1 ));
+
+ if(b[0]!='\0') {
+ if(gdbm_store(db,key,value,GDBM_INSERT))
+ {
+ // fprintf(stderr,"*** Key exists ***\n");
+
+ gdbm_sync(db);
+ gdbm_close(db);
+ db = gdbm_open((char *)outputName,1024,GDBM_READER,0,0);
+ datum oldvalue;
+ oldvalue= gdbm_fetch(db,key);
+ gdbm_sync(db);
+ gdbm_close(db);
+ db = gdbm_open((char *)outputName,1024,GDBM_WRCREAT,0,0);
+
+ t=(int *)oldvalue.dptr;
+ int i,r,j; //counters
+ int v=*t; //Number of strings
+ int *nr,*re,*md; //Number of references,ref
+ bool exist=false,here,modif=false;
+ char *os=oldvalue.dptr+4;
+ // fprintf(stderr,"**Searching string #%s#\n",b);
+ for(i=0;i<v;i++)
+ {
+
+ exist=false; //REMOVE THIS LINE!!!
+ here=false;
+ // fprintf(stderr,"**STRING %d #%s# len=%d %s\n",i,os,strlen(os),b);
+ if(strcmp(os,b)==0) {
+ exist=true;
+ here=true;
+ // fprintf(stderr,"That's good\n");
+ }
+ os+=strlen(os)+1; //End of string
+ nr=(int *)os;
+ os+=(*nr+1)*4;
+ re=nr;
+ modif=false;
+ // fprintf(stderr,"refernces %d\n",*nr);
+ for(j=0;j<*nr;j++)
+ {
+ re++;
+
+ if(here)
+ {
+ // printf("reference #%d\n",*re);
+ for(r=0;r<=co;r++)
+ {
+ // fprintf(stderr,"%d==%d ?-->",oldref[co],*re);
+ if(oldref[r]==*re)
+ {
+ modif=true;
+ // fprintf(stderr,"Yes\n");
+ *re=(nmax-1);
+ } //else fprintf(stderr,"No\n");
+ }
+ // fprintf(stderr,"qui\n");
+ if(!modif)
+ md=nr;
+ // fprintf(stderr,"modif %s\n",modif ? "true":"false");
+ }
+ }
+
+ }
+
+ if(!exist)
+ {
+ int oldlen=(long int)os-(long int)oldvalue.dptr-4;
+ memcpy(a+4,oldvalue.dptr+4,oldlen);
+// fprintf(stderr,"***!exist Old len is %d+4 1st str is %s\n",oldlen,a+4);
+ v++;
+ t=(int *)a;
+ *t=v;
+ // fprintf(stderr,"b=%s",b);
+ strcpy(a+4+oldlen,b);
+ re=(int *)(a+4+oldlen+strlen(b)+1);
+ *re=1;
+ re++;
+ *re=nmax-1;
+ //fprintf(stderr,"a+4=%s a+4+oldlen=%s",a+4,a+4+oldlen);
+ value.dptr=a;
+ value.dsize=oldlen+strlen(b)+1+4+8;
+ gdbm_store(db,key,value,GDBM_REPLACE);
+ n++;
+ } else
+ {
+ if(!modif)
+ {
+// fprintf(stderr,"grossa crisi %d\n",*md);
+// fprintf(stderr,"Old num of ref \n");
+ int oldlen1=(long int)(md)-(long int)(oldvalue.dptr)-4;
+ int oldlen2=(long int)(os)-(long int)(md)-4; //-4 because nr
+ memcpy(a+4,oldvalue.dptr+4,oldlen1);
+ memcpy(a+4+oldlen1+8,oldvalue.dptr+4+oldlen1+4,oldlen2);
+ re=(int *)(a+4+oldlen1);
+ *re=(*md )+1;
+ // *re++;
+ re++;
+ *re=nmax-1;
+ t=(int *)a;
+ *t=v;
+ value.dptr=a;
+ value.dsize=oldlen1+oldlen2+4+8;
+ gdbm_store(db,key,value,GDBM_REPLACE);
+ n++;
+ }
+ else //if (modif)
+ {
+ value.dptr=oldvalue.dptr;
+ value.dsize=oldvalue.dsize;
+ gdbm_store(db,key,value,GDBM_REPLACE);
+ }
+ }
+
+ h++;
+ } else {
+
+ m++;
+ }
+ }
+ }
+
+ }
+
+
+ }
+
+ fclose(mlf);
+ gdbm_close(db);
+ open=false;
+ printf("new Key in database %d\n old key found %d\n value added %d\n",m,h,n);
+ return m+n;
+}
+
+
+
+main(int argc,char **argv)
+{
+int i;
+for(i=1;i<argc;i++)
+ printf("File %s:\nEntry added to dbase: %d\n",argv[i],makePoDb(argv[i],"messages2.db"));
+
+}
diff --git a/kbabel/kbabeldict/modules/dbsearchengine/preferenceswidget.cpp b/kbabel/kbabeldict/modules/dbsearchengine/preferenceswidget.cpp
new file mode 100644
index 00000000..3bb65934
--- /dev/null
+++ b/kbabel/kbabeldict/modules/dbsearchengine/preferenceswidget.cpp
@@ -0,0 +1,111 @@
+#include <qradiobutton.h>
+#include <qslider.h>
+#include <qspinbox.h>
+#include <qcheckbox.h>
+#include <qlabel.h>
+#include <qlayout.h>
+#include <klocale.h>
+#include <kfiledialog.h>
+#include <kurlrequester.h>
+#include <qtoolbutton.h>
+#include <klineedit.h>
+#include <kstandarddirs.h>
+
+#include "dbseprefwidget.h"
+#include "preferenceswidget.h"
+
+PreferencesWidget::PreferencesWidget(QWidget *parent, const char* name)
+ : PrefWidget(parent,name)
+{
+ QVBoxLayout *layout = new QVBoxLayout(this);
+// QLabel *label = new QLabel(i18n("Settings for KDE database search engine"),this);
+// layout->addWidget(label);
+
+ dbpw = new DBSearchEnginePref(this);
+ dbpw->dirInput->setMode(KFile::Directory | KFile::LocalOnly);
+
+ layout->addWidget(dbpw);
+ resize(QSize(200,200).expandedTo(minimumSizeHint()));
+
+// connect(dbpw->browseTB_3,SIGNAL(clicked()),SLOT(browse1()));
+
+ emit restoreNow(); //Fill with actual params.
+
+}
+
+PreferencesWidget::~PreferencesWidget()
+{
+}
+
+void PreferencesWidget::apply()
+{
+emit applyNow();
+}
+
+void PreferencesWidget::cancel()
+{
+emit restoreNow();
+}
+
+void PreferencesWidget::standard()
+{
+
+
+dbpw->caseSensitiveCB->setChecked(false);
+dbpw->normalizeCB->setChecked(true);
+dbpw->removeContextCB->setChecked(true);
+
+dbpw->oneWordSubCB->setChecked(true);
+dbpw->twoWordSubCB->setChecked(false);
+
+
+dbpw->RegExpRB->setChecked(false);
+dbpw->normalTextRB->setChecked(true);
+dbpw->equalCB->setChecked( true );
+dbpw->containsCB->setChecked( true);
+dbpw->containedCB->setChecked( true );
+
+
+dbpw->oneWordSubSB->setValue(20);
+dbpw->twoWordSubSB->setValue(8);
+
+dbpw->maxSB->setValue(500);
+dbpw->thresholdSL->setValue(50);
+dbpw->thresholdOrigSL->setValue(50);
+
+dbpw->allRB->setChecked( false);
+dbpw->slistRB->setChecked( true);
+dbpw->rlistRB->setChecked( false );
+
+dbpw->nothingCB->setChecked(true);
+dbpw->freqSB->setValue(300);
+
+dbpw->ignoreLE->setText("&.:");
+
+dbpw->autoAddCB_2->setChecked(true);
+
+QString defaultDir;
+ KStandardDirs * dirs = KGlobal::dirs();
+ if(dirs)
+ {
+ defaultDir = dirs->saveLocation("data");
+ if(defaultDir.right(1)!="/")
+ defaultDir+="/";
+ defaultDir += "kbabeldict/dbsearchengine";
+ }
+
+ dbpw->dirInput->setURL(defaultDir);
+}
+
+void PreferencesWidget::setName(QString n)
+{
+dbpw->filenameLB->setText(i18n("Scanning file: %1").arg(n));
+}
+
+void PreferencesWidget::setEntries(int i)
+{
+dbpw->entriesLB->setText(i18n("Entries added: %1").arg(i));
+
+}
+
+#include "preferenceswidget.moc"
diff --git a/kbabel/kbabeldict/modules/dbsearchengine/preferenceswidget.h b/kbabel/kbabeldict/modules/dbsearchengine/preferenceswidget.h
new file mode 100644
index 00000000..599408cd
--- /dev/null
+++ b/kbabel/kbabeldict/modules/dbsearchengine/preferenceswidget.h
@@ -0,0 +1,28 @@
+#ifndef PREFERENCESWIDGET_H
+#define PREFERENCESWIDGET_H
+
+#include "searchengine.h"
+#include "dbseprefwidget.h"
+
+class PreferencesWidget : public PrefWidget
+{
+ Q_OBJECT
+
+public:
+ PreferencesWidget(QWidget *parent=0, const char* name=0);
+ virtual ~PreferencesWidget();
+
+ virtual void apply();
+ virtual void cancel();
+ virtual void standard();
+ DBSearchEnginePref *dbpw;
+public slots:
+ void setName(QString);
+ void setEntries(int);
+signals:
+ void applyNow();
+ void restoreNow();
+
+};
+
+#endif
diff --git a/kbabel/kbabeldict/modules/dbsearchengine2/AUTHOR b/kbabel/kbabeldict/modules/dbsearchengine2/AUTHOR
new file mode 100644
index 00000000..2a79312d
--- /dev/null
+++ b/kbabel/kbabeldict/modules/dbsearchengine2/AUTHOR
@@ -0,0 +1 @@
+Andrea Rizzi <rizzi@kde.org> \ No newline at end of file
diff --git a/kbabel/kbabeldict/modules/dbsearchengine2/KDBSearchEngine2.cpp b/kbabel/kbabeldict/modules/dbsearchengine2/KDBSearchEngine2.cpp
new file mode 100644
index 00000000..5bf088b8
--- /dev/null
+++ b/kbabel/kbabeldict/modules/dbsearchengine2/KDBSearchEngine2.cpp
@@ -0,0 +1,686 @@
+/***************************************************************************
+ KDBSearchEngine2.cpp - description
+ -------------------
+ begin : Fri Sep 8 2000
+ copyright : (C) 2000-2003 by Andrea Rizzi
+ email : rizzi@kde.org
+***************************************************************************/
+
+/*
+ Translation search engine. Version II
+
+
+ Copyright 2000-2003
+ Andrea Rizzi rizzi@kde.org
+
+ License GPL v 2.0
+
+ * *
+ * In addition, as a special exception, the copyright holders give *
+ * permission to link the code of this program with any edition of *
+ * the Qt library by Trolltech AS, Norway (or with modified versions *
+ * of Qt that use the same license as Qt), and distribute linked *
+ * combinations including the two. You must obey the GNU General *
+ * Public License in all respects for all of the code used other than *
+ * Qt. If you modify this file, you may extend this exception to *
+ * your version of the file, but you are not obligated to do so. If *
+ * you do not wish to do so, delete this exception statement from *
+ * your version. *
+
+*/
+#include "algorithms.h"
+#include "chunk.h"
+#include "database.h"
+#include "KDBSearchEngine2.h"
+#include "dbscan.h"
+#include <klineedit.h>
+#include <kapplication.h>
+#include <qpushbutton.h>
+#include <kurlrequester.h>
+#include <qcheckbox.h>
+#include <knuminput.h>
+#include <kstandarddirs.h>
+#include <kmessagebox.h>
+
+#include <qmap.h>
+
+#include <kdebug.h>
+#define i18n (const char *)
+
+KDBSearchEngine2::KDBSearchEngine2(QObject *parent,const char*name)
+ : SearchEngine(parent,name)
+ {
+ pw=0;
+ dbDirectory=".";
+
+ di=0; //Database Interface is not yet initialized
+
+ connect(this,SIGNAL(hasError(QString)),SLOT(setLastError(QString)));
+
+ searching=false; // i'm not searching
+ iAmReady=true; //there are no reason to say I'm not ready.
+
+}
+
+
+KDBSearchEngine2::~KDBSearchEngine2()
+{
+ if(di)
+ delete di; //delete database interface
+}
+
+bool KDBSearchEngine2::startSearch(QString str)
+{
+ kdDebug(0) << "Start a new search. Looking for: " << str << endl;
+
+ static QString queryString;
+
+ queryString=str; //set the latest query string (note: it is static)
+
+ if(autoupdate)
+ {
+ updateSettings();
+ }
+
+
+ if(!init()) return false; //-check initialization
+ di->stop(true); //stop all new emits from database interface
+ emit started(); //say everybody we are starting
+
+ if(searching) return true; //We already have a search loop, as soon as we come back
+ //on the search loop we will start the new search (queryString).
+
+ searching=true; //really start searching
+
+ QString searchingString;
+
+ do //Search loop, it stops only when finished and latest searched string is the actual query string.
+ {
+ searchingString=queryString; //-set new search string
+ di->stop(false); //-unlock searching
+
+ if(numberOfResult<1) numberOfResult=1;
+
+// di->singleWordMatch(searchingString,0,true);
+
+ GenericSearchAlgorithm strategy(di,&settings);
+
+ //Let's create a search sequence:
+ ExactSearchAlgorithm exact(di,&settings);
+ AlphaSearchAlgorithm alpha(di,&settings);
+ SentenceArchiveSearchAlgorithm sent(di,&settings);
+ ChunkByChunkSearchAlgorithm sbys(di,&settings);
+ ChunkByChunkSearchAlgorithm wbyw(di,&settings);
+ CorrelationSearchAlgorithm corr(di,&settings);
+ FuzzyChunkSearchAlgorithm fs(di,&settings);
+ FuzzyChunkSearchAlgorithm fw(di,&settings);
+
+ SentenceChunkFactory sf(di);
+ sbys.setChunkFactory(&sf);
+ fs.setChunkFactory(&sf);
+
+
+ WordChunkFactory wf(di);
+ wbyw.setChunkFactory(&wf);
+ fw.setChunkFactory(&wf);
+
+ strategy.addAlgorithm(&exact);
+ strategy.addAlgorithm(&alpha);
+ strategy.addAlgorithm(&sent);
+ strategy.addAlgorithm(&sbys);
+ //strategy.addAlgorithm(&fs);
+ strategy.addAlgorithm(&fw);
+ strategy.addAlgorithm(&corr);
+ strategy.addAlgorithm(&wbyw);
+
+
+ connect(&strategy,SIGNAL(newResult(QueryResult)),this,SLOT(receiveResult(QueryResult)));
+ strategy.exec(searchingString); disconnect(&strategy,SIGNAL(newResult(QueryResult)),this,SLOT(receiveResult(QueryResult)));
+
+
+ kdDebug(0) << "End of search for " << searchingString << endl;
+ }
+ while(searchingString!=queryString);
+ kdDebug(0) << "Exiting the search loop" << endl;
+ //if != someone asked a different string when we was searching
+ //so we restart our search (maybe a cleanresult is needed?).
+
+
+ di->stop(false); //-clean searching locks
+ searching=false; //-clean searching locks
+ emit finished(); //Finished
+
+ return true;
+
+}
+
+
+
+
+
+bool KDBSearchEngine2::startSearchInTranslation(QString str)
+{
+ if(autoupdate)
+ {
+ updateSettings();
+ }
+
+ //TODO!!!!
+ return true;
+
+}
+
+
+
+bool KDBSearchEngine2::messagesForPackage(const QString& package
+ , QValueList<Message>& resultList, QString& error)
+{
+ //FIXME implement this (needs filters)
+ return true;
+}
+
+
+void KDBSearchEngine2::setLastError(QString er)
+{
+ lasterror=er;
+}
+
+QString KDBSearchEngine2::translate(const QString text)
+{
+ ExactSearchAlgorithm exact(di,&settings);
+
+ return exact.exec(text)[0].result();
+
+}
+
+
+void KDBSearchEngine2::receiveResult(QueryResult r)
+{
+
+ SearchResult se; // Create a new SearchResult for our QueryResult
+
+ se.translation=r.richResult();
+ se.found=r.richOriginal();
+
+ se.plainTranslation=r.result();
+ se.plainFound=r.original();
+ se.score=r.score();
+
+ emit resultFound(&se); // dispatch the new SearchResult
+
+}
+
+
+/* A SEARCH RESULT CONTAINS (see searchengine.h)
+ QString requested;
+ QString found;
+ QString translation;
+ QString plainTranslation;
+ QString plainFound;
+ QString plainRequested;
+ int score;
+ QPtrList<TranslationInfo> descriptions;
+*/
+
+
+
+bool KDBSearchEngine2::init()
+{
+ if(di!=0) return true; //if there already is a DBinterface we are ok
+ else
+ {
+ di = new DataBaseInterface(dbDirectory,&settings);
+ connect(di,SIGNAL(newResult(QueryResult)),this,SLOT(receiveResult(QueryResult)));
+ //FIXME: what wbout ready()
+ if(!di->mainOk()) return false; //check if the main DB is OK.
+
+ return true;
+ }
+
+}
+const KAboutData *KDBSearchEngine2::about() const
+{
+ return DbSe2Factory::instance()->aboutData();
+}
+
+void KDBSearchEngine2::stringChanged( QString orig, QString translated
+ , QString description)
+{
+
+ if(!init()) return;
+ //if(translated.isEmpty()) return;
+ InputInfo ii;
+ if(description.find("fuzzy",false)==-1)
+ di->addEntry(orig,translated,&ii);
+
+}
+
+PrefWidget * KDBSearchEngine2::preferencesWidget(QWidget *parent)
+{
+
+ pw = new KDB2PreferencesWidget(parent);
+ kdDebug(0) << "new KDB2 preferences widget" << endl;
+ setSettings();
+ connect(pw,SIGNAL(restoreNow()),this,SLOT(setSettings()));
+ connect(pw,SIGNAL(applyNow()),this,SLOT(updateSettings()));
+ connect(pw,SIGNAL(destroyed()),this,SLOT(prefDestr()));
+
+
+ connect(pw->dbpw->scanAll,SIGNAL(clicked()),this,SLOT(scanAllPressed()));
+ connect(pw->dbpw->scanSource,SIGNAL(clicked()),this,SLOT(scanNowPressed()));
+ connect(pw->dbpw->addSource,SIGNAL(clicked()),this,SLOT(addSource()));
+ connect(pw->dbpw->editSource,SIGNAL(clicked()),this,SLOT(editSource()));
+ connect(pw->dbpw->removeSource,SIGNAL(clicked()),this,SLOT(removeSource()));
+
+
+ return pw;
+}
+
+void KDBSearchEngine2::saveSettings(KConfigBase *config)
+{
+ KConfigGroupSaver cgs(config,"KDBSearchEngine2");
+
+
+
+ config->writeEntry("DBDirectory",dbDirectory);
+ config->writeEntry("AutoAdd",autoAdd);
+ config->writeEntry("UseSentence",useSentence);
+ config->writeEntry("UseGlossary",useGlossary);
+ config->writeEntry("UseExact",useExact);
+ config->writeEntry("UseDivide",useDivide);
+ config->writeEntry("UseAlpha",useAlpha);
+ config->writeEntry("UseWordByWord",useWordByWord);
+ config->writeEntry("UseDynamic",useDynamic);
+ config->writeEntry("NumberOfResults",numberOfResult);
+
+ config->writeEntry("ScoreDivide",settings.scoreDivide);
+ config->writeEntry("ScoreExact",settings.scoreExact);
+ config->writeEntry("ScoreSentence",settings.scoreSentence);
+ config->writeEntry("ScoreWordByWord",settings.scoreWordByWord);
+ config->writeEntry("ScoreGlossary",settings.scoreGlossary);
+ config->writeEntry("ScoreAlpha",settings.scoreAlpha);
+ config->writeEntry("ScoreDynamic",settings.scoreDynamic);
+ config->writeEntry("MinimumScore",settings.minScore);
+ config->writeEntry("FirstCapital",settings.firstCapital);
+ config->writeEntry("AllCapital",settings.allCapital);
+ config->writeEntry("Accelerator",settings.accelerator);
+ config->writeEntry("SameLetter",settings.sameLetter);
+
+ uint sourceNumber=0;
+ config->writeEntry("NumberOfDBImportSources",sources.count());
+
+ for(QMap<QString,MessagesSource>::iterator sourceIt=sources.begin() ; sourceIt!=sources.end(); ++sourceIt)
+ {
+ sourceNumber++;
+ config->setGroup("DBImportSource-"+QString::number(sourceNumber));
+ config->writeEntry("Name",sourceIt.key());
+ sourceIt.data().writeConfig(config);
+ }
+}
+
+void KDBSearchEngine2::readSettings(KConfigBase *config)
+{
+
+ /*QString defaultDir;
+ KStandardDirs * dirs = KGlobal::dirs();
+ if(dirs)
+ {
+ defaultDir = dirs->saveLocation("data");
+ if(defaultDir.right(1)!="/")
+ defaultDir+="/";
+ defaultDir += "kbabeldict/dbsearchengine2";
+ }
+*/
+ KConfigGroupSaver cgs(config,"KDBSearchEngine2");
+
+ // dbDirectory=config->readEntry("DBDirectory",defaultDir);
+ autoAdd=config->readBoolEntry("AutoAdd",true);
+ useSentence=config->readBoolEntry("UseSentence",true);
+ useGlossary=config->readBoolEntry("UseGlossary",true);
+ useExact=config->readBoolEntry("UseExact",true);
+ useDivide=config->readBoolEntry("UseDivide",true);
+ useAlpha=config->readBoolEntry("UseAlpha",true);
+ useWordByWord=config->readBoolEntry("UseWordByWord",true);
+ useDynamic=config->readBoolEntry("UseDynamic",true);
+ numberOfResult=config->readNumEntry("NumberOfResults",5);
+
+ settings.scoreDivide=config->readNumEntry("ScoreDivide",90);
+ settings.scoreExact=config->readNumEntry("ScoreExact",100);
+ settings.scoreSentence=config->readNumEntry("ScoreSentence",90);
+ settings.scoreWordByWord=config->readNumEntry("ScoreWordByWord",70);
+ settings.scoreGlossary=config->readNumEntry("ScoreGlossary",98);
+ settings.scoreAlpha=config->readNumEntry("ScoreAlpha",98);
+ settings.scoreDynamic=config->readNumEntry("ScoreDynamic",80);
+ settings.minScore=config->readNumEntry("MinimumScore",60);
+ settings.firstCapital=config->readBoolEntry("FirstCapital",true);
+ settings.allCapital=config->readBoolEntry("AllCapital",false);
+ settings.accelerator=config->readBoolEntry("Accelerator",true);
+ settings.sameLetter=config->readBoolEntry("SameLetter",true);
+
+ uint numberOfSources=config->readNumEntry("NumberOfDBImportSources",0);
+ kdDebug(0) << "Found "<< numberOfSources << " sources" << endl;
+ for(uint sourceNumber=1;sourceNumber<=numberOfSources;sourceNumber++)
+ {
+ config->setGroup("DBImportSource-"+QString::number(sourceNumber));
+ QString name=config->readEntry("Name");
+ sources[name].readConfig(config);
+ }
+ if(pw)
+ setSettings();
+
+}
+
+void KDBSearchEngine2::setSettings()
+{
+ if(pw) {
+ pw->dbpw->dbDirectory->setURL(dbDirectory);
+ pw->dbpw->autoUpdate->setChecked(autoAdd);
+
+ pw->dbpw->useSentence->setChecked(useSentence);
+ pw->dbpw->useGlossary->setChecked(useGlossary);
+ pw->dbpw->useExact->setChecked(useExact);
+ pw->dbpw->useDivide->setChecked(useDivide);
+ pw->dbpw->useAlpha->setChecked(useAlpha);
+ pw->dbpw->useWordByWord->setChecked(useWordByWord);
+ pw->dbpw->useDynamic->setChecked(useDynamic);
+ pw->dbpw->numberOfResult->setValue(numberOfResult);
+ pw->dbpw->scoreDivide->setValue(settings.scoreDivide);
+ pw->dbpw->scoreExact->setValue(settings.scoreExact);
+ pw->dbpw->scoreSentence->setValue(settings.scoreSentence);
+ pw->dbpw->scoreWordByWord->setValue(settings.scoreWordByWord);
+ pw->dbpw->scoreGlossary->setValue(settings.scoreGlossary);
+ pw->dbpw->scoreAlpha->setValue(settings.scoreAlpha);
+ pw->dbpw->scoreDynamic->setValue(settings.scoreDynamic);
+ pw->dbpw->minScore->setValue(settings.minScore);
+ pw->dbpw->firstCapital->setChecked(settings.firstCapital);
+ pw->dbpw->allCapital->setChecked(settings.allCapital);
+ pw->dbpw->accelerator->setChecked(settings.accelerator);
+ pw->dbpw->sameLetter->setChecked(settings.sameLetter);
+
+ //pw->dbpw->checkLang->setChecked(true);
+ //pw->dbpw->useFilters->setChecked(false);
+ //pw->dbpw->dateToday->setChecked(false);
+ pw->dbpw->sourceList->clear();
+ for(QMap<QString,MessagesSource>::iterator sourceIt=sources.begin() ; sourceIt!=sources.end(); ++sourceIt)
+ {
+ pw->dbpw->sourceList->insertItem(sourceIt.key());
+ }
+ }
+
+}
+
+void KDBSearchEngine2::updateSettings()
+{
+ if(!pw) return;
+
+ QString newdb = pw->dbpw->dbDirectory->url();
+ if(newdb !=dbDirectory)
+ {
+ kdDebug(0) << "Recreate DB-Interface cause dbdir is changed" << endl;
+ dbDirectory=newdb;
+ if (di!=0) delete di;
+ di= new DataBaseInterface(dbDirectory,&settings);
+ }
+
+ autoAdd=pw->dbpw->autoUpdate->isChecked();
+
+ useSentence=pw->dbpw->useSentence->isChecked();
+ useGlossary=pw->dbpw->useGlossary->isChecked();
+ useExact=pw->dbpw->useExact->isChecked();
+ useDivide=pw->dbpw->useDivide->isChecked();
+ useAlpha=pw->dbpw->useAlpha->isChecked();
+ useWordByWord=pw->dbpw->useWordByWord->isChecked();
+ useDynamic=pw->dbpw->useDynamic->isChecked();
+
+ numberOfResult=pw->dbpw->numberOfResult->value();
+
+ settings.scoreWordByWord=pw->dbpw->scoreWordByWord->value();
+ settings.scoreGlossary=pw->dbpw->scoreGlossary->value();
+ settings.scoreDivide=pw->dbpw->scoreDivide->value();
+ settings.scoreExact=pw->dbpw->scoreExact->value();
+ settings.scoreSentence=pw->dbpw->scoreSentence->value();
+ settings.scoreAlpha=pw->dbpw->scoreAlpha->value();
+ settings.scoreDynamic=pw->dbpw->scoreDynamic->value();
+
+ settings.minScore=pw->dbpw->minScore->value();
+
+ settings.firstCapital=pw->dbpw->firstCapital->isChecked();
+ settings.allCapital=pw->dbpw->allCapital->isChecked();
+ settings.accelerator=pw->dbpw->accelerator->isChecked();
+ settings.sameLetter=pw->dbpw->sameLetter->isChecked();
+
+ //pw->dbpw->editRule->
+ //pw->dbpw->deleteRule->
+ //pw->dbpw->customRules->
+
+ /*
+pw->dbpw->checkLang->
+pw->dbpw->useFilters->
+pw->dbpw->dateToday->
+
+pw->dbpw->removeSource->
+pw->dbpw->scanSource->
+pw->dbpw->addSource->
+pw->dbpw->sourceDir->
+pw->dbpw->scanAll->
+pw->dbpw->sourceList->
+*/
+
+}
+
+
+/*void KDBSearchEngine2::scanSource(QString sourceName)
+{
+ //FIXME: an error here would be nice
+ if(!init()) return;
+
+
+ for(QValueList<MessagesSource>::iterator sourceIt=sources.begin() ; sourceIt!=sources.end(); sourceIt++)
+ {
+ if((*sourceIt).getName()==sourceName)
+ {
+ QValueList<KURL> urls=(*sourceIt).urls();
+ PoScanner ps(di);
+ for(QValueList<KURL>::iterator urlIt=urls.begin();urlIt!=urls.end();urlIt++)
+ ps.scanFile(*urlIt);
+
+ //We suppose name are unique so no need for further scrolling
+ return ;
+ }
+ }
+}*/
+void KDBSearchEngine2::scanNowPressed()
+{
+ if(!pw)
+ {
+ kdDebug(0) << "We should not be here, scanNow called without a pw!" << endl;
+ return;
+ }
+ QString sourceName;
+ sourceName=pw->dbpw->sourceList->currentText();
+ if(!init()) return;
+ if(sources.contains(sourceName))
+ {
+ QValueList<KURL> urls=sources[sourceName].urls();
+ PoScanner ps(di);
+ for(QValueList<KURL>::iterator urlIt=urls.begin();urlIt!=urls.end();++urlIt)
+ ps.scanURL(*urlIt);
+
+ }
+ else
+ {
+ kdDebug(0) << "source name not found in our MAP. This is a bug." << endl;
+ }
+}
+
+void KDBSearchEngine2::scanAllPressed()
+{
+ //FIXME: an error here would be nice too
+ if(!init()) return;
+ PoScanner ps(di);
+
+
+ for(QMap<QString,MessagesSource>::iterator sourceIt=sources.begin() ; sourceIt!=sources.end(); ++sourceIt)
+ {
+ QValueList<KURL> urls=(*sourceIt).urls();
+ for(QValueList<KURL>::iterator urlIt=urls.begin();urlIt!=urls.end();++urlIt)
+ ps.scanURL(*urlIt);
+ }
+}
+
+void KDBSearchEngine2::editSource()
+{
+ if(!pw)
+ {
+ kdDebug(0) << "We should not be here, editSource called without a pw!" << endl;
+ return;
+ }
+ QString sourceName;
+ sourceName=pw->dbpw->sourceList->currentText();
+
+ if(sources.contains(sourceName))
+ {
+ bool nameIsNew;
+ QString newName;
+ SourceDialog sd;
+ do{
+ sources[sourceName].setDialogValues(&sd);
+ sd.sourceName->setText(sourceName);
+ if(sd.exec()==QDialog::Accepted)
+ {
+ sources[sourceName].getDialogValues(&sd);
+ newName= sd.sourceName->text();
+ } else
+ {
+ return;
+ }
+ nameIsNew=sources.contains(newName);
+ if(newName!=sourceName && !nameIsNew)
+ {
+
+ KMessageBox::error(0,
+ i18n("The name you chose is already used.\nPlease change the source name."),
+ i18n("Name is Not Unique"));
+ kdDebug(0) << "Name is not uniqe" << endl;
+ }
+ }while(newName!=sourceName && !nameIsNew);
+
+ if(newName!=sourceName){
+ sources[newName]=sources[sourceName];
+ sources.remove(sourceName);
+ }
+ pw->dbpw->sourceList->changeItem(newName,pw->dbpw->sourceList->currentItem());
+
+ }
+ else
+ {
+ kdDebug(0) << "source name not found in our MAP. This is a bug." << endl;
+ }
+
+}
+void KDBSearchEngine2::removeSource()
+{
+
+ if(!pw)
+ {
+ kdDebug(0) << "We should not be here, delteSource called without a pw!" << endl;
+ return;
+ }
+ QString sourceName;
+ sourceName=pw->dbpw->sourceList->currentText();
+ sources.remove(sourceName);
+ pw->dbpw->sourceList->removeItem(pw->dbpw->sourceList->currentItem());
+
+}
+
+void KDBSearchEngine2::addSource()
+{
+ QString newName;
+ SourceDialog sd;
+ bool nameIsNew;
+ do{
+ if(sd.exec()==QDialog::Accepted)
+ {
+ newName= sd.sourceName->text();
+ nameIsNew=!sources.contains(newName);
+ }
+ else
+ {
+ return;
+ }
+ // nameIsNew=sources.contains(newName);
+ if(!nameIsNew)
+ {
+ KMessageBox::error(0,i18n("The name you chose is already used.\nPlease change the source name."),
+ i18n("Name is Not Unique"));
+ kdDebug(0) << "Name is not uniqe" << endl;
+ }
+ else
+ {
+ sources[newName].getDialogValues(&sd);
+ }
+ }while(!nameIsNew);
+
+ pw->dbpw->sourceList->insertItem(newName);
+
+
+}
+QString KDBSearchEngine2::searchTranslation( const QString text, int & score )
+{
+ GenericSearchAlgorithm strategy(di,&settings);
+ strategy.setMaxResultNumber(1);
+
+ ExactSearchAlgorithm exact(di,&settings);
+ AlphaSearchAlgorithm alpha(di,&settings);
+ SentenceArchiveSearchAlgorithm sent(di,&settings);
+
+ strategy.addAlgorithm(&exact);
+ strategy.addAlgorithm(&alpha);
+ strategy.addAlgorithm(&sent);
+
+ QueryResult firstRes=strategy.exec(text)[0];
+ score=firstRes.score();
+ return firstRes.result();
+
+}
+
+QString KDBSearchEngine2::fuzzyTranslation( const QString text, int & score )
+{
+ GenericSearchAlgorithm strategy(di,&settings);
+ strategy.setMaxResultNumber(1);
+ ExactSearchAlgorithm exact(di,&settings);
+ AlphaSearchAlgorithm alpha(di,&settings);
+ SentenceArchiveSearchAlgorithm sent(di,&settings);
+ ChunkByChunkSearchAlgorithm sbys(di,&settings);
+ ChunkByChunkSearchAlgorithm wbyw(di,&settings);
+ FuzzyChunkSearchAlgorithm fs(di,&settings);
+ FuzzyChunkSearchAlgorithm fw(di,&settings);
+
+ SentenceChunkFactory sf(di);
+ sbys.setChunkFactory(&sf);
+ fs.setChunkFactory(&sf);
+
+
+ WordChunkFactory wf(di);
+ wbyw.setChunkFactory(&wf);
+ fw.setChunkFactory(&wf);
+
+ strategy.addAlgorithm(&exact);
+ strategy.addAlgorithm(&alpha);
+ strategy.addAlgorithm(&sent);
+ strategy.addAlgorithm(&sbys);
+ //strategy.addAlgorithm(&fs);
+ strategy.addAlgorithm(&fw);
+ strategy.addAlgorithm(&wbyw);
+
+
+ QueryResult firstRes=strategy.exec(text)[0];
+ score=firstRes.score();
+ return firstRes.result();
+
+
+}
+
+//FIXME: ProgressBasr, progressbar,progressbasr
+#include "KDBSearchEngine2.moc"
+
diff --git a/kbabel/kbabeldict/modules/dbsearchengine2/KDBSearchEngine2.h b/kbabel/kbabeldict/modules/dbsearchengine2/KDBSearchEngine2.h
new file mode 100644
index 00000000..0db19c6c
--- /dev/null
+++ b/kbabel/kbabeldict/modules/dbsearchengine2/KDBSearchEngine2.h
@@ -0,0 +1,202 @@
+/* ****************************************************************************
+
+DBSE2
+Andrea Rizzi
+
+**************************************************************************** */
+
+#ifndef DBSEARCH_ENGINE2_H
+#define DBSEARCH_ENGINE2_H
+
+#include <searchengine.h>
+#include <qdialog.h>
+
+#include "database.h"
+#include "dbse2_factory.h"
+#include "preferenceswidget.h"
+#include "dbscan.h"
+#include "sourcedialog.h"
+
+//#include "DBSESettings.h"
+
+class KDBSearchEngine2 : public SearchEngine
+{
+ Q_OBJECT
+
+ public:
+
+ KDBSearchEngine2(QObject *parent=0, const char *name=0);
+ virtual ~KDBSearchEngine2();
+
+ //init if needed.
+ bool init();
+
+ /** @return true, if a search is currently active */
+ bool isSearching() const {return searching;}
+
+ void stopSearch() { if(di) di->stop();}
+
+
+
+ /** @returns true, if it was initialized correctly */
+ bool isReady() const {return iAmReady; }
+
+
+ void saveSettings(KConfigBase *config);
+ void readSettings(KConfigBase *config);
+
+
+ QString translate(const QString text);
+
+ QString fuzzyTranslation(const QString text, int &score);
+ QString searchTranslation(const QString, int &score );
+
+ /**
+ * Finds all messages belonging to package package. If nothing is found,
+ * the list is empty.
+ * @param package The name of the file, something like "kbabel.po"
+ * @param resultList Will contain the found messages afterwards
+ * @param error If an error occured, this should contain a description
+ *
+ * @return true, if successfull
+ */
+ bool messagesForPackage(const QString& package
+ , QValueList<Message>& resultList, QString& error);
+
+ /**
+ * @returns true, if the searchresults are given as rich text
+ * the default implementation returns false
+ */
+ bool usesRichTextResults(){return true;}
+
+ /** @returns true, if the the entries in the database can be edited */
+ bool isEditable(){return false;}
+
+ /**
+ * @returns a widget which lets the user setup all preferences of this
+ * search engine. The returned widget should not be bigger than
+ * 400x400. If you need more space, you maybe want to use
+ * a tabbed widget.
+ * @param parent the parent of the returned widget
+ */
+ virtual PrefWidget* preferencesWidget(QWidget *parent);
+
+ /** @returns information about this SearchEngine */
+ virtual const KAboutData *about() const;
+
+ /** @returns the i18n name of this search engine */
+ QString name() const {return i18n("DB SearchEngine II");}
+
+ /** @returns a untranslated name of this engine */
+ QString id() const {return "dbse2";}
+
+ /** @returns the last error message */
+ QString lastError() {return lasterror;}
+
+
+ /**
+ * sets the engine to always ask the preferences dialog for settings
+ * if is existing before starting the search.
+ */
+ virtual void setAutoUpdateOptions(bool activate)
+ {
+ autoupdate=activate;
+ }
+
+
+
+ public slots:
+
+ void receiveResult(QueryResult r);
+
+ /**
+ * starts a search for string s in the original text
+ * @returns false, if an error occured. Use @ref lastError
+ * to get the last error message
+ */
+ bool startSearch(QString s);
+
+ /**
+ * starts a search for string s in the translated text
+ * @returns false, if an error occured. Use @ref lastError
+ * to get the last error message
+ */
+ bool startSearchInTranslation(QString s);
+
+
+ /** stops a search */
+ // virtual void stopSearch() ;
+
+
+ /**
+ * This method allows a search engine to use different settings depending
+ * on the edited file. The default implementation does nothing.
+ * @param file The edited file with path
+ */
+ // virtual void setEditedFile(QString file);
+
+ /**
+ * This method allows a search engine to use different settings depending
+ * on the edited package. The default implementation does nothing.
+ * @param package The name of the package, that is currently translated.
+ */
+ // virtual void setEditedPackage(QString package);
+
+ /**
+ * This method allows a search engine to use different settings depending
+ * on the language code. The default implementation does nothing.
+ * @param lang The current language code (e.g. de).
+ */
+ // virtual void setLanguageCode(QString lang);
+ // virtual void setLanguage(QString languageCode, QString languageName);
+
+
+
+ /**
+ * This method is called, if something has been changed in the
+ * current file. See @ref setEditedFile if you want to know the file
+ * name
+ * @param orig the original string
+ * @param translation the translated string
+ */
+
+ void stringChanged( QString orig, QString translated
+ , QString description);
+
+ //void scan();
+
+ void setLastError(QString er);
+
+ //Slots for preference dialog
+ // void scanSource(QString sourceName);
+ void scanNowPressed();
+ void scanAllPressed();
+ void editSource();
+ void removeSource();
+ void addSource();
+
+
+ private:
+ DataBaseInterface *di;
+ bool searching;
+ bool iAmReady;
+ bool autoupdate;
+ QString lasterror;
+ KDB2PreferencesWidget *pw;
+
+ //PrefWidg -> DBSE
+ void updateSettings();
+ //DBSE -> PrefWidg
+ void setSettings();
+
+ DBSESettings settings;
+ QString dbDirectory;
+ bool autoAdd,useSentence,useGlossary,useExact;
+ bool useDivide,useAlpha,useWordByWord,useDynamic;
+ uint numberOfResult;
+ QMap<QString,MessagesSource> sources;
+
+};
+
+
+#endif // SEARCH_ENGINE2_H
diff --git a/kbabel/kbabeldict/modules/dbsearchengine2/Makefile.am b/kbabel/kbabeldict/modules/dbsearchengine2/Makefile.am
new file mode 100644
index 00000000..cdcd3083
--- /dev/null
+++ b/kbabel/kbabeldict/modules/dbsearchengine2/Makefile.am
@@ -0,0 +1,34 @@
+## Makefile.am for DBSE2
+
+# this has all of the subdirectories that make will recurse into. if
+# there are none, comment this out
+#SUBDIRS =
+
+
+# this is the program that gets installed. it's name is used for all
+# of the other Makefile.am variables
+kde_module_LTLIBRARIES = kbabeldict_dbsearchengine2.la
+
+# set the include path for X, qt and KDE
+INCLUDES = -I$(srcdir)/../.. -I$(srcdir)/../../../common $(all_includes) -I$(DBIV_INCLUDES)
+
+# which sources should be compiled for kbabel
+kbabeldict_dbsearchengine2_la_SOURCES = dbscan.cpp preferenceswidget.cpp dbse2.ui KDBSearchEngine2.cpp database.cpp dbentries.cpp dbse2_factory.cpp sourcedialog.ui algorithms.cpp chunk.cpp
+
+#kbabeldict_dbsearchengine2_la_SOURCES = KDBSearchEngine2.cpp database.cpp dbentries.cpp dbse2_factory.cpp
+kbabeldict_dbsearchengine2_la_LIBADD = ../../libkbabeldictplugin.la ../../../common/libkbabelcommon.la $(LIB_KDEUI) $(LIB_KIO) $(LIB_DBIV)_cxx
+kbabeldict_dbsearchengine2_la_LDFLAGS = $(all_libraries) -module -avoid-version -no-undefined -L$(DBIV_LDFLAGS)
+
+
+# these are the headers for your project
+noinst_HEADERS = KDBSearchEngine2.h database.h dbentries.h dbse2_factory.h
+#chunk.h algorithms.h
+
+
+# let automoc handle all of the meta source files (moc)
+METASOURCES = AUTO
+
+kde_services_DATA = dbsearchengine2.desktop
+EXTRA_DIST = $(kde_services_DATA)
+
+
diff --git a/kbabel/kbabeldict/modules/dbsearchengine2/README b/kbabel/kbabeldict/modules/dbsearchengine2/README
new file mode 100644
index 00000000..907ab84e
--- /dev/null
+++ b/kbabel/kbabeldict/modules/dbsearchengine2/README
@@ -0,0 +1,21 @@
+If you want to test this new plugin:
+launch
+# make ; make install in this directory
+then (to create the database)
+# source compile
+# cp scan ~/mytestdir
+# cd ~/mytestdir
+# ./scan file.po (I suggest to download and scan $LANG.messages)
+
+ok now you can launch kbabel, you should be in the same
+directory you launched "scan" from.
+
+# kbabel
+
+
+change kbabel settings to use "DB Search Engine II" or use
+CTRL+2 to search.
+
+
+Bye
+Andrea
diff --git a/kbabel/kbabeldict/modules/dbsearchengine2/algorithms.cpp b/kbabel/kbabeldict/modules/dbsearchengine2/algorithms.cpp
new file mode 100644
index 00000000..0ca040e8
--- /dev/null
+++ b/kbabel/kbabeldict/modules/dbsearchengine2/algorithms.cpp
@@ -0,0 +1,425 @@
+//
+// C++ Implementation: algorithms
+//
+// Description:
+//
+//
+// Author: Andrea Rizzi <rizzi@kde.org>, (C) 2003
+//
+// Copyright: See COPYING file that comes with this distribution
+//
+//
+#include "algorithms.h"
+#include <qstringlist.h>
+#include <kdebug.h>
+
+//FIXME: remove
+#define i18n (const char*)
+
+DataBaseInterface::ResultList ExactSearchAlgorithm::exec(const QString& query )
+{
+ DataBaseInterface::ResultList res;
+ DataBaseInterface::MainEntry e=di->get(query,0);
+
+ QStringList trs=e.second.getTranslations();
+
+ for(QStringList::iterator it=trs.begin();it!=trs.end();++it)
+ {
+
+ emit newResult(QueryResult(*it,e.first.getString(),settings->scoreExact));
+
+ res.push_back(QueryResult(*it));
+ }
+ kdDebug(0) <<"Exact algo found " << res.count() << "entries" << endl;
+ return res;
+}
+
+
+DataBaseInterface::ResultList GenericSearchAlgorithm::exec(const QString& query )
+{
+ DataBaseInterface::ResultList res;
+ // ExactSearchAlgorithm exact(query,settings);
+ uint countResults=0;
+ for(QValueList<AbstractSearchAlgorithm *>::iterator algoit = algoChain.begin(); algoit!=algoChain.end() && countResults < maxResults; algoit++)
+ {
+ connect(*algoit,SIGNAL(newResult(QueryResult)),this,SIGNAL(newResult(QueryResult)));
+ kdDebug(0) << "Algo pointer" << (*algoit) << endl;
+ res+=(*algoit)->exec(query);
+ countResults=res.count();
+ kdDebug(0) << "Count = " << countResults << endl;
+ disconnect(*algoit,SIGNAL(newResult(QueryResult)),this,SIGNAL(newResult(QueryResult)));
+ }
+ return res;
+}
+
+void GenericSearchAlgorithm::addAlgorithm( AbstractSearchAlgorithm * algo )
+{
+ algoChain.append(algo);
+}
+
+DataBaseInterface::ResultList AlphaSearchAlgorithm::exec( const QString & query )
+{
+ DataBaseInterface::ResultList res;
+ DBItemMultiIndex::IndexList il=di->getAlpha(query);
+
+ for(DBItemMultiIndex::IndexList::iterator it=il.begin();it!=il.end()&&!di->stopNow();++it)
+ {
+ DataBaseInterface::MainEntry e=di->getFromIndex(*it);
+ QStringList trs=e.second.getTranslations();
+ for(QStringList::iterator it=trs.begin();it!=trs.end() && !di->stopNow();++it)
+ {
+ QueryResult r(di->format(di->simple(*it,true),query),e.first.getString(),settings->scoreAlpha);
+ emit newResult(r);
+ res.push_back(r);
+ }
+ }
+ kdDebug(0) <<"Alpha algo found " << res.count() << "entries" << endl;
+
+ return res;
+}
+
+DataBaseInterface::ResultList SentenceArchiveSearchAlgorithm::exec( const QString & query )
+{
+ DataBaseInterface::ResultList res;
+
+ DataBaseInterface::MainEntry e = di->getSentence(query);
+
+ QStringList trs=e.second.getTranslations();
+
+ kdDebug(0) << "Count in sentence archive " << trs.count()<< endl;
+
+ for(QStringList::iterator it=trs.begin();it!=trs.end();++it)
+ {
+ QueryResult r(di->format(di->simple(*it,true),query),e.first.getString(),settings->scoreSentence);
+ emit newResult(r);
+
+ res.push_back(r);
+ }
+ kdDebug(0) <<"Sentence algo found " << res.count() << "entries" << endl;
+
+ return res;
+}
+
+DataBaseInterface::ResultList ChunkByChunkSearchAlgorithm::exec( const QString & query )
+{
+ ResultList res;
+ factory->setQuery(query);
+ QPtrList<AbstractChunk> chunks=factory->chunks();
+ kdDebug(0) << "Number of chunks " << chunks.count() << endl;
+ chunks.setAutoDelete(true); //I should delete the chunks myself
+ QStringList querySeparators=factory->separators();
+
+ //This prevents recursive loop.
+ if (chunks.count()<=1) return res;
+
+ QStringList translations,tmpTranslations;
+
+ translations.push_back(""); //FIXME this is needed to start , but is not good
+ int finalscore=0;
+ int i=0;
+ QMap<QString,bool> translationUsed;
+
+ //Loop on all chunk
+ for(AbstractChunk *it=chunks.first();it && !di->stopNow(); it=chunks.next())
+ {
+ kdDebug(0) << "Process next chunk" << endl;
+ int chunkscore=0;
+ QValueList<QueryResult> r=it->translations();
+ kdDebug(0) << "Number of results for this chunk " << r.count() << endl;
+
+ if(r.count()<1) {
+ // kdDebug(0) << "Nothing found for:" << it->translations() << endl;
+ chunkscore=-10;
+
+ }
+ else
+ {
+ //FIXME: check this, why 0? it is the best one?
+ chunkscore=r[0].score();
+ kdDebug(0) << "ChunkScore " << chunkscore << endl;
+ tmpTranslations.clear();
+
+
+ //Loop on results
+ translationUsed.clear();
+ for(ResultList::iterator it1=r.begin();it1!=r.end() &&!di->stopNow(); ++it1)
+ {
+ QString chunkTranslation= (*it1).result();
+ if(!translationUsed.contains(chunkTranslation))
+ {
+ translationUsed[chunkTranslation]=true;
+ kdDebug(0) << "a translation is: " << chunkTranslation << endl;
+ for(QStringList::iterator it2=translations.begin();it2!=translations.end() && !di->stopNow() ; it2++)
+ {
+ QString prevTranslation=*it2;
+ tmpTranslations.push_back(prevTranslation+chunkTranslation+querySeparators[i]);
+ kdDebug(0) << "..appending it to " << prevTranslation << endl;
+ }
+ }
+ }
+
+ translations=tmpTranslations;
+
+ }
+
+ //kdDebug(0) << it-> << r[0].result() << "#" << querySeparators[i] << endl;
+ i++;
+ finalscore+=chunkscore;
+
+ kdDebug(0) << "partial score " << finalscore;
+ }
+ kdDebug(0) << "this is finishd" << endl;
+ if(settings->scoreChunkByChunk==0)
+ settings->scoreChunkByChunk=1;
+// FIXME:fix the score system
+// finalscore/=(i*100*100/settings->scoreChunkByChunk); //change 100 to 120(?) to lower this result (done)
+
+ if (finalscore<50) return res;
+
+ for(QStringList::iterator it2=translations.begin();it2!=translations.end() && !di->stopNow() ; it2++)
+ {
+ QString theTranslation=*it2;
+ QueryResult qr(di->format(theTranslation,query),i18n("CHUNK BY CHUNK"),finalscore);
+ qr.setRichOriginal(i18n("<h3>Chunk by chunk</h3>CHANGE THIS TEXT!!!!This translation is"
+ "obtained translating the sentences and using a"
+ "fuzzy sentence translation database.<br>"
+ " <b>Do not rely on it</b>. Translations may be fuzzy.<br>"));
+ qr.setRichResult("<font color=#800000>"+theTranslation+"</font>") ;
+ emit newResult(qr);
+ res.push_back(qr);
+ }
+
+
+ return res;
+
+
+}
+
+ChunkByChunkSearchAlgorithm::ChunkByChunkSearchAlgorithm( DataBaseInterface * dbi, DBSESettings * sets ): AbstractSearchAlgorithm(dbi,sets) , factory(0)
+{
+
+}
+
+
+SentenceArchiveSearchAlgorithm::SentenceArchiveSearchAlgorithm( DataBaseInterface * dbi, DBSESettings * sets ): AbstractSearchAlgorithm(dbi,sets)
+{
+}
+
+FuzzyChunkSearchAlgorithm::FuzzyChunkSearchAlgorithm( DataBaseInterface * dbi, DBSESettings * sets ) : AbstractSearchAlgorithm(dbi,sets)
+{
+
+}
+
+
+DataBaseInterface::ResultList FuzzyChunkSearchAlgorithm::exec( const QString & query )
+{
+ //FIXME: this code is shit too
+ ResultList res;
+ factory->setQuery(query);
+ QPtrList<AbstractChunk> querychunks = factory->chunks();
+ querychunks.setAutoDelete(true);
+
+ typedef QMap<QString,QValueList<unsigned int> > ResultMap;
+ ResultMap rmap; //result of words index query
+ unsigned int notfound=0,frequent=0,nchunks = querychunks.count();
+
+ //Get index list for each word
+ for(AbstractChunk *it=querychunks.first(); it &&!di->stopNow() ; it=querychunks.next() )
+ {
+ QValueList<uint> locations = (*it).locationReferences();
+
+ if(locations.count()>0)
+ {
+ rmap[(*it).chunkString()] = locations;
+
+ if(locations.count()>1000) //FIXME NORMALIZE THIS!!!
+ {
+ frequent++;
+ kdDebug(0) << "\""<<(*it).chunkString() << "\" is frequent" <<endl;
+ }
+ }
+ else
+ notfound++;
+
+ }
+
+
+ //Now we have a map (rmap) "word in query->list of occurency"
+
+ QValueList<unsigned int>::iterator countpos[nchunks+1];
+
+
+ QValueList<unsigned int> il;
+ for(int i = 0;i<=nchunks&&!di->stopNow();i++)
+ countpos[i]=il.end();
+
+ unsigned int bestcount=0;
+ while(!rmap.isEmpty())
+ {
+ unsigned int ref,count;
+ ref=(unsigned int)-1;
+ count=0;
+
+
+ //This will find the min head and count how many times it occurs
+ for(ResultMap::iterator it = rmap.begin();it!=rmap.end()&&!di->stopNow();++it)
+ {
+ unsigned int thisref=it.data().first();
+ if(thisref<ref)
+ {
+ ref=thisref;
+ count=0;
+ }
+ if(thisref==ref)
+ {
+ count++;
+ }
+
+ }
+
+
+ for(ResultMap::iterator it = rmap.begin();it!=rmap.end()&&!di->stopNow();)
+ {
+ it.data().remove(ref);
+
+ //kdDebug(0)<< ((frequent<(nwords-notfound)) && (it.data().count()>350)) <<endl;
+ //FIXME: I think the frequent word check is not in the right place
+ if(it.data().isEmpty() || (((frequent+notfound)<nchunks) && (it.data().count()>1000)))
+ //very dirty hack...
+ {
+
+ ResultMap::iterator it2=it;
+ it++;
+ rmap.remove(it2);
+ }
+ else it++;
+
+ }
+
+ //This should be configurable or optimized:
+ if(count>=(nchunks-notfound)*0.50 && count!=0)
+ {
+ il.insert(countpos[count],ref);
+ for(unsigned int i = nchunks;i>=count;i--)
+ if(countpos[i]==countpos[count])
+ countpos[i]--;
+ }
+ }
+
+ //loop on number of words found
+ int bestscore=0;
+
+ for(unsigned int wf=nchunks;wf>0;wf-- ){
+ for(QValueList<unsigned int>::iterator it=countpos[wf];it!=countpos[wf-1] ;++it)
+ { //loop on entries with same number of word found
+ DataBaseInterface::MainEntry e;
+ e=di->getFromIndex(*it);
+ QStringList trs=e.second.getTranslations();
+ for(QStringList::iterator it=trs.begin();it!=trs.end()&&!di->stopNow();++it)
+ {
+ unsigned int cinr=factory->chunks(*it).count(); //chunk in result
+ //compute a score, lets kbabel sort now, it should be fast...
+ int score=90*wf/nchunks-(signed int)90*(((nchunks-cinr)>0)?(nchunks-cinr):(cinr-nchunks))/(nchunks*10);
+ if(score>bestscore) bestscore=score;
+ if(score>bestscore*0.40)
+ {
+ // kdDebug(0) << "s: "<<score << " wf: "<<wf<<" nwords: "<<nwords<<" winr: "<<winr
+ // <<" 90*wf/nwords: "<<90*wf/nwords << " -:" << 90*(((nwords-winr)>0)?(nwords-winr):(winr-nwords))/(nwords*10)<< endl;
+ // FIXME: format better the richtext
+ QString ori=e.first.getString();
+ QString re=di->format(di->simple(*it,true),query);
+ QueryResult r(re,ori,score);
+ for(QPtrListIterator<AbstractChunk> it(querychunks); it.current() && di->stopNow() ; ++it){
+ ori=ori.replace(QRegExp((*it)->chunkString(),false),"<font color=#000080><u><b>"+(*it)->chunkString()+"</b></u></font>");
+ }
+ r.setRichOriginal(ori);
+ if(!di->stopNow())
+ emit newResult(r);
+ res.push_back(r);
+ }
+ }
+ }
+ }
+ return res;
+
+}
+
+DataBaseInterface::ResultList CorrelationSearchAlgorithm::exec( const QString & query )
+{
+ //FIXME, this code is shit.
+ DataBaseInterface::ResultList res;
+ if(di->words(query).count()>1) return res;
+ QMap<QString,float> corRes = di->correlation(query,0,false);
+ float max=0,max1=0,max2=0;
+ QString best,best1,best2;
+
+ for(QMap<QString,float>::iterator it = corRes.begin(); it !=corRes.end(); ++it)
+ {
+ if(it.data()>max)
+ {
+ max2=max1;
+ best2=best1;
+ max1=max;
+ best1=best;
+ best = it.key();
+ max=it.data();
+
+ }
+
+
+ }
+ if(!best.isEmpty())
+ {
+ double myscore=0.01*max*settings->scoreDynamic;
+ QueryResult r(di->format(best,query),i18n("DYNAMIC DICT:"),myscore);
+ r.setRichOriginal(i18n("<h3>Dynamic Dictionary</h3>This is a dynamic dictionary created"
+ " looking for correlation of original and translated words.<br>"
+ " <b>Do not rely on it</b>. Translations may be fuzzy.<br>"));
+ r.setRichResult("<font size=+2 color=#A00000>"+di->format(best,query)+"</font>") ;
+ res.push_back(r);
+ if(!di->stopNow())
+ emit newResult(r);
+ }
+ if(!best1.isEmpty())
+ {
+ double myscore=0.01*max1*settings->scoreDynamic;
+ QueryResult r(di->format(best1,query),i18n("DYNAMIC DICT:"),myscore);
+ r.setRichOriginal(i18n("<h3>Dynamic Dictionary</h3>This is a dynamic dictionary created"
+ " looking for correlation of original and translated words.<br>"
+ " <b>Do not rely on it</b>. Translations may be fuzzy.<br>"));
+ r.setRichResult("<font size=+2 color=#800000>"+di->format(best1,query)+"</font>") ;
+ res.push_back(r);
+ if(!di->stopNow())
+ emit newResult(r);
+ }
+
+ kdDebug(0) << "Correlation algorithm found" << res.count() << "results";
+ return res;
+
+}
+
+GenericSearchAlgorithm::GenericSearchAlgorithm( DataBaseInterface * dbi, DBSESettings * sets ): AbstractSearchAlgorithm(dbi,sets)
+{
+ maxResults = 5; //FIXME use as default somthing from DBSESettings
+}
+
+SingleWordSearchAlgorithm::SingleWordSearchAlgorithm( DataBaseInterface * dbi, DBSESettings * sets ) : GenericSearchAlgorithm(dbi,sets),
+ exact(dbi,sets), alpha(dbi,sets), sentence(dbi,sets), corr(dbi,sets), chunk(dbi,sets),casefactory(dbi)
+ {
+ addAlgorithm(&exact);
+ addAlgorithm(&alpha);
+ addAlgorithm(&sentence);
+ chunk.setChunkFactory(&casefactory);
+ addAlgorithm(&chunk);
+ addAlgorithm(&corr);
+}
+
+DataBaseInterface::ResultList SingleWordSearchAlgorithm::exec( const QString & query )
+{
+ if(di->words(query).count()>1)
+ return ResultList();
+ return GenericSearchAlgorithm::exec(query);
+}
+
+
+//#include "algorithms.moc"
diff --git a/kbabel/kbabeldict/modules/dbsearchengine2/algorithms.h b/kbabel/kbabeldict/modules/dbsearchengine2/algorithms.h
new file mode 100644
index 00000000..5f9ee682
--- /dev/null
+++ b/kbabel/kbabeldict/modules/dbsearchengine2/algorithms.h
@@ -0,0 +1,157 @@
+//
+// C++ Interface: strategies
+//
+// Description:
+//
+//
+// Author: Andrea Rizzi <rizzi@kde.org>, (C) 2003
+//
+// Copyright: See COPYING file that comes with this distribution
+//
+//
+#ifndef DBSE2_STRATEGIES_H
+#define DBSE2_STRATEGIES_H
+
+#include "database.h"
+#include "chunk.h"
+#include <qobject.h>
+
+class AbstractSearchAlgorithm : public QObject
+{
+ Q_OBJECT
+ public:
+
+ typedef QValueList<QueryResult> ResultList;
+
+ AbstractSearchAlgorithm(DataBaseInterface *dbi,DBSESettings *sets)
+ {
+ di=dbi;
+ settings=sets;
+ }
+ /**
+ * this contains the algo and return some results.
+ */
+ virtual DataBaseInterface::ResultList exec(const QString& query)=0;
+
+ signals:
+ void newResult(QueryResult);
+
+ protected:
+ DataBaseInterface *di;
+ DBSESettings *settings;
+
+};
+
+
+
+class ExactSearchAlgorithm : public AbstractSearchAlgorithm
+{
+ Q_OBJECT
+ public:
+ ExactSearchAlgorithm(DataBaseInterface *dbi,DBSESettings *sets) : AbstractSearchAlgorithm(dbi,sets) {}
+
+ virtual DataBaseInterface::ResultList exec(const QString& query);
+};
+
+class AlphaSearchAlgorithm : public AbstractSearchAlgorithm
+{
+ Q_OBJECT
+ public:
+ AlphaSearchAlgorithm(DataBaseInterface *dbi,DBSESettings *sets) : AbstractSearchAlgorithm(dbi,sets) {}
+
+ virtual DataBaseInterface::ResultList exec(const QString& query);
+};
+
+class SentenceArchiveSearchAlgorithm : public AbstractSearchAlgorithm
+{
+ Q_OBJECT
+ public:
+ SentenceArchiveSearchAlgorithm(DataBaseInterface *dbi,DBSESettings *sets) ;
+
+ virtual DataBaseInterface::ResultList exec(const QString& query);
+};
+
+class ChunkByChunkSearchAlgorithm : public AbstractSearchAlgorithm
+{
+ Q_OBJECT
+ public:
+ ChunkByChunkSearchAlgorithm(DataBaseInterface *dbi,DBSESettings *sets);
+
+ virtual DataBaseInterface::ResultList exec(const QString& query);
+
+ void setChunkFactory(AbstractChunkFactory *_factory)
+ {
+ factory=_factory;
+ }
+ protected:
+ AbstractChunkFactory *factory;
+};
+
+class FuzzyChunkSearchAlgorithm : public AbstractSearchAlgorithm
+{
+ Q_OBJECT
+ public:
+ FuzzyChunkSearchAlgorithm(DataBaseInterface *dbi,DBSESettings *sets);
+
+ virtual DataBaseInterface::ResultList exec(const QString& query);
+ void setChunkFactory(AbstractChunkFactory *_factory)
+ {
+ factory=_factory;
+ }
+ protected:
+ AbstractChunkFactory *factory;
+};
+
+class GenericSearchAlgorithm : public AbstractSearchAlgorithm
+{
+ Q_OBJECT
+ public:
+ GenericSearchAlgorithm(DataBaseInterface *dbi,DBSESettings *sets) ;
+
+ virtual ResultList exec(const QString& query);
+
+ void addAlgorithm(AbstractSearchAlgorithm *algo);
+ void setMaxResultNumber(uint num){maxResults=num;}
+
+
+ protected:
+ QValueList<AbstractSearchAlgorithm *> algoChain;
+ uint maxResults;
+ };
+
+
+class CorrelationSearchAlgorithm : public AbstractSearchAlgorithm
+{
+ Q_OBJECT
+ public:
+ CorrelationSearchAlgorithm(DataBaseInterface *dbi,DBSESettings *sets) : AbstractSearchAlgorithm(dbi,sets) {}
+ virtual ResultList exec(const QString& query);
+};
+
+
+
+class SingleWordSearchAlgorithm : public GenericSearchAlgorithm
+{
+ Q_OBJECT
+ public:
+ SingleWordSearchAlgorithm(DataBaseInterface *dbi,DBSESettings *sets);
+ virtual DataBaseInterface::ResultList exec(const QString& query);
+
+ private:
+ ExactSearchAlgorithm exact;
+ AlphaSearchAlgorithm alpha;
+ SentenceArchiveSearchAlgorithm sentence;
+ CorrelationSearchAlgorithm corr;
+ ChunkByChunkSearchAlgorithm chunk;
+ CaseBasedWordChunkFactory casefactory;
+};
+
+
+class UpdateChunkIndexAlgorithm
+{
+
+};
+
+
+
+#endif //DBSE2_STRATEGIES_H
diff --git a/kbabel/kbabeldict/modules/dbsearchengine2/chunk.cpp b/kbabel/kbabeldict/modules/dbsearchengine2/chunk.cpp
new file mode 100644
index 00000000..7c62748a
--- /dev/null
+++ b/kbabel/kbabeldict/modules/dbsearchengine2/chunk.cpp
@@ -0,0 +1,203 @@
+//
+// C++ Implementation: chunk
+//
+// Description:
+//
+//
+// Author: Andrea Rizzi <rizzi@kde.org>, (C) 2003
+//
+// Copyright: See COPYING file that comes with this distribution
+//
+//
+#include "chunk.h"
+#include "algorithms.h"
+#include <kdebug.h>
+
+
+
+AbstractChunk::~AbstractChunk( )
+{
+}
+
+WordChunk::WordChunk( DataBaseInterface * di, QString _word ) : AbstractChunk(di)
+{
+ word=_word;
+}
+
+QValueList<QueryResult> WordChunk::translations( )
+{
+ DataBaseInterface::ResultList r;
+ SingleWordSearchAlgorithm sa(di,di->getSettings());
+ r=sa.exec(word);
+ return r;
+}
+
+//QValueList<QueryResult> WordChunk::translationsFromReference( uint reference )
+//{
+//}
+
+QValueList< uint > WordChunk::locationReferences( )
+{
+ QValueList<uint> res=di->getWordIndex(word);
+ kdDebug(0) << "Number of locations " << res.count() <<endl ;
+ return res;
+/* DBItemMainKey *k = new DBItemMainKey(word);
+ DBItemMultiIndex *d = new DBItemMultiIndex();
+ if(wordsindex->get(k,d)!=DB_NOTFOUND)
+ return d->getList();
+ else
+ return QValueList<uint> tmpList;
+*/
+}
+
+void WordChunk::setLocationReferences( QValueList< uint > )
+{
+}
+
+SentenceChunk::SentenceChunk( DataBaseInterface * di, QString _sentence ): AbstractChunk(di)
+{
+ sentence=_sentence;
+}
+
+QValueList<QueryResult> SentenceChunk::translations( )
+{
+ GenericSearchAlgorithm g(di,di->getSettings());
+
+ ExactSearchAlgorithm e(di,di->getSettings());
+ AlphaSearchAlgorithm a(di,di->getSettings());
+ SentenceArchiveSearchAlgorithm s(di,di->getSettings());
+
+ g.addAlgorithm(&e);
+ g.addAlgorithm(&a);
+ g.addAlgorithm(&s);
+
+ return g.exec(sentence);
+
+}
+
+//QValueList<QueryResult> SentenceChunk::translationsFromReference( uint reference )
+//{
+//
+//}
+
+QValueList< uint > SentenceChunk::locationReferences( )
+{
+}
+
+void SentenceChunk::setLocationReferences( QValueList< uint > )
+{
+}
+
+QPtrList< AbstractChunk> WordChunkFactory::chunks()
+{
+ QString str=di->simple(string);
+ QPtrList<AbstractChunk> list;
+ if(str.isEmpty()) return list;
+ _separators.clear();
+ kdDebug(0) << "Word chunks of:" <<str << endl;
+ int pos;
+ QString sep;
+ QRegExp r("(\\s)");
+ do {
+ pos=r.search(str);
+
+ sep=r.cap(1);
+ if(!str.left(pos).isEmpty()){
+ //WordChunk *c=new WordChunk(di,di->simple(str.left(pos)))
+ list.append(new WordChunk(di,str.left(pos)));
+ _separators.append(sep);
+ }
+ else
+ {
+ uint current=_separators.count()-1;
+ _separators[current]=_separators[current]+sep;
+ }
+ str=str.remove(0,pos+1);
+ } while(!str.isEmpty() && pos != -1);
+
+ return list;
+}
+
+
+
+QPtrList<AbstractChunk> SentenceChunkFactory::chunks()
+{
+ QString str=string;
+ QPtrList<AbstractChunk> list;
+ if(str.isEmpty()) return list;
+
+ // kdDebug(0) << s << endl;
+
+ int pos;
+
+
+ do {
+ QRegExp re("((\\.|;|\\?|\\!|:)( |$|\\\\n\\n))");
+ pos=re.search(str);
+ QString sep=re.cap(1);
+
+ if(!str.left(pos).isEmpty())
+ {
+ list.append(new SentenceChunk(di,str.left(pos).stripWhiteSpace()));
+ _separators.append(sep);
+ }
+ else
+ {
+ uint current=_separators.count()-1;
+ _separators[current]=_separators[current]+sep;
+ }
+
+ str=str.remove(0,pos+re.cap(1).length());
+ } while(!str.isEmpty() && pos != -1);
+
+
+ return list;
+
+}
+QPtrList< AbstractChunk > CaseBasedWordChunkFactory::chunks( )
+{
+ QString str=string;
+ QPtrList<AbstractChunk> list;
+ if(str.isEmpty()) return list;
+ uint slen=str.length();
+ kdDebug(0) << "CaseWordChunk string:" << str << endl;
+ QString tmpWord;
+ bool upcase;
+ for(uint i=0;i<=slen;i++)
+ {
+ bool tmpCase=(str[i]==str[i].upper());
+ if(upcase!=tmpCase)
+ {
+ if(!tmpWord.isEmpty() && !tmpWord.isNull()){
+ list.append(new WordChunk(di,tmpWord));
+ _separators.append("");
+ }
+ kdDebug(0) << "CaseWordChunk:" << tmpWord << endl;
+ tmpWord="";
+
+ }
+ tmpWord+=str[i];
+ upcase=tmpCase;
+ }
+
+ return list;
+}
+
+WordChunkFactory::WordChunkFactory( DataBaseInterface * _di ) : AbstractChunkFactory(_di)
+{
+}
+
+SentenceChunkFactory::SentenceChunkFactory( DataBaseInterface * _di ): AbstractChunkFactory(_di)
+{
+}
+
+CaseBasedWordChunkFactory::CaseBasedWordChunkFactory( DataBaseInterface * _di ): AbstractChunkFactory(_di)
+{
+}
+
+
+
+
+
+
+
diff --git a/kbabel/kbabeldict/modules/dbsearchengine2/chunk.h b/kbabel/kbabeldict/modules/dbsearchengine2/chunk.h
new file mode 100644
index 00000000..5c5fcb93
--- /dev/null
+++ b/kbabel/kbabeldict/modules/dbsearchengine2/chunk.h
@@ -0,0 +1,151 @@
+//
+// C++ Interface: chunk
+//
+// Description:
+//
+//
+// Author: Andrea Rizzi <rizzi@kde.org>, (C) 2003
+//
+// Copyright: See COPYING file that comes with this distribution
+//
+//
+#ifndef DBSE2_CHUNK_H
+#define DBSE2_CHUNK_H
+#include <qstring.h>
+#include <qvaluelist.h>
+#include "database.h"
+
+/**
+ * Abstract class for text chunks.
+ * Examples of chunks are "Words" or "Sentences"
+ * This abstraction allow to use generic algorithm on chunks,
+ * like chunkByChunk translation or chunk indexing.
+ */
+class AbstractChunk
+{
+ public:
+ AbstractChunk(DataBaseInterface *_di) {di=_di;}
+ virtual ~AbstractChunk();
+ /**
+ * This function should return a list of translation for the current chunk.
+ */
+ virtual QValueList<QueryResult> translations()=0;
+
+ //FIXME: is this in the right place, better in factory? check that stuff
+ //virtual QValueList<QueryResult> translationsFromReference(uint reference)=0;
+ virtual QValueList<uint> locationReferences()=0;
+ virtual void setLocationReferences(QValueList<uint>)=0;
+ virtual QString chunkString()=0;
+
+ protected:
+ DataBaseInterface *di;
+};
+
+/**
+ * Concrete impl of Chunk, in this case chunks are words.
+ */
+class WordChunk : public AbstractChunk
+{
+ public:
+ WordChunk(DataBaseInterface *di,QString _word);
+ virtual QValueList<QueryResult> translations();
+ //virtual QValueList<QueryResult> translationsFromReference(uint reference);
+ virtual QValueList<uint> locationReferences();
+ virtual void setLocationReferences(QValueList<uint>);
+ virtual QString chunkString(){return word;}
+
+ //static QValueList<WordChunk> divide(QString);
+ private:
+ QString word;
+};
+
+/**
+ * Concrete impl of Chunk, in this case chunks are sentences.
+ */
+class SentenceChunk : public AbstractChunk
+{
+ public:
+ SentenceChunk(DataBaseInterface *di,QString _sentence);
+ virtual QValueList<QueryResult> translations();
+ //virtual QValueList<QueryResult> translationsFromReference(uint reference);
+ virtual QValueList<uint> locationReferences();
+ virtual void setLocationReferences(QValueList<uint>);
+ virtual QString chunkString(){return sentence;}
+
+ // static QValueList<SentenceChunk> divide(QString);
+
+ private:
+ QString sentence;
+};
+
+
+/**********************************
+ CHUNK FACTORIES
+**********************************/
+
+
+class AbstractChunkFactory
+{
+ public:
+ AbstractChunkFactory(DataBaseInterface *_di)
+ {
+ di=_di;
+ }
+ virtual ~AbstractChunkFactory(){}
+ virtual QPtrList<AbstractChunk> chunks()=0;
+ /**
+ Change th string and return the chunks
+ */
+ virtual QPtrList<AbstractChunk> chunks(const QString& s)
+ {
+ string=s;
+ return chunks();
+ }
+ /**
+ * Returns the list of separators of last @ref chunks() call
+ */
+
+ virtual QStringList separators(){ return _separators;}
+ void setQuery(const QString& s)
+ {
+ string=s;
+ }
+ protected:
+ QString string;
+ QStringList _separators;
+ DataBaseInterface *di;
+};
+
+class WordChunkFactory : public AbstractChunkFactory
+{
+ public:
+ WordChunkFactory(DataBaseInterface *_di);
+ /**
+ YOU SHOULD DELETE THE CHUNKS!!
+ */
+ virtual QPtrList<AbstractChunk> chunks();
+};
+
+class CaseBasedWordChunkFactory : public AbstractChunkFactory
+{
+ public:
+ CaseBasedWordChunkFactory(DataBaseInterface *_di);
+ /**
+ YOU SHOULD DELETE THE CHUNKS!!
+ */
+ virtual QPtrList<AbstractChunk> chunks();
+};
+
+class SentenceChunkFactory : public AbstractChunkFactory
+{
+ public:
+ SentenceChunkFactory(DataBaseInterface *_di);
+
+ /**
+ YOU SHOULD DELETE THE CHUNKS!!
+ */
+ virtual QPtrList<AbstractChunk> chunks();
+};
+
+
+#endif //_CHUNK_H_
diff --git a/kbabel/kbabeldict/modules/dbsearchengine2/database.cpp b/kbabel/kbabeldict/modules/dbsearchengine2/database.cpp
new file mode 100644
index 00000000..ea0e8379
--- /dev/null
+++ b/kbabel/kbabeldict/modules/dbsearchengine2/database.cpp
@@ -0,0 +1,752 @@
+/*
+
+DBSE 3
+(c) 2000-2003 Andrea Rizzi
+License: GPLv2
+
+*/
+#include <math.h>
+#include "database.h"
+
+#include <qregexp.h>
+#include <qdict.h>
+#include <kapplication.h>
+#include <kdebug.h>
+#include <kmessagebox.h>
+
+#define i18n (const char*)
+
+
+
+
+
+
+DataBase::DataBase(QString dbpath,QString dbname, QString dblang) : Db(0,DB_CXX_NO_EXCEPTIONS)
+{
+
+ filename=dbpath+"."+dblang+".db";
+ database=dbname;
+
+}
+
+int DataBase::open(DBTYPE type,unsigned int flags)
+{
+ int ret;
+ ret = Db::open(
+#if DB_VERSION_MINOR > 0
+ NULL,
+#endif
+ (const char*)filename.local8Bit(),(const char *)database.local8Bit(),type,flags,0644);
+ mytype=type;
+ return ret;
+}
+
+unsigned int DataBase::getLast()
+{
+ if(mytype!=DB_RECNO)
+ return 0;
+
+ Dbc *cur;
+ cursor(0,&cur,0);
+ DBItemNum index;
+ DBItemMainKey key;
+ cur->get(&index,&key,DB_LAST);
+ return index.getNum();
+
+}
+
+
+
+
+
+QueryResult::QueryResult(QString r)
+{
+ res=r;
+}
+QueryResult::QueryResult(QString r,QString o,int s)
+{
+ res=r;
+ richr=r;
+ orig=o;
+ richo=o;
+ sco=s;
+}
+
+QueryResult::QueryResult()
+{
+ res="";
+}
+
+
+
+
+DataBaseInterface::DataBaseInterface(QString dir, DBSESettings *sets)
+{
+
+ //FIXME Better db names!!
+ main = openMyDataBase(dir+"/testm","main","it",DB_BTREE);
+ alpha = openMyDataBase(dir+"/testa","alpha","it",DB_BTREE);
+ numindex = openMyDataBase(dir+"/testn","numindex","it",DB_RECNO);
+ wordsindex = openMyDataBase(dir+"/testw","wordsindex","it",DB_BTREE);
+ sentence = openMyDataBase(dir+"/tests","sentence","it",DB_BTREE);
+ corr = openMyDataBase(dir+"/testc","corr","it",DB_BTREE);
+ transword = openMyDataBase(dir+"/testt","transword","it",DB_RECNO);
+
+ // kdDebug(0) << main << endl;
+ // kdDebug(0) << alpha << endl;
+ settings=sets;
+ _stopNow=false;
+}
+
+DataBaseInterface::~DataBaseInterface()
+{
+
+ if(main){
+ main->close(0);
+ delete main;
+ }
+ if(numindex){
+ numindex->close(0);
+ delete numindex;
+ }
+
+ if(alpha){
+ alpha->close(0);
+ delete alpha;
+ }
+ if(wordsindex){
+ wordsindex->close(0);
+ delete wordsindex;
+ }
+ if(sentence){
+ sentence->close(0);
+ delete sentence;
+ }
+
+}
+
+DataBase *DataBaseInterface::openMyDataBase(const QString& prefix,const QString& name,const QString& l,DBTYPE tt)
+{
+
+ DataBase *aDb = new DataBase(prefix,name,l);
+ if(aDb==0){
+ return 0;
+ }
+ else
+ {
+ if(aDb->open(tt)!=0)
+ {
+ kdDebug(0) << "Database '"<< name <<"'do not exist, I try to create it.." << endl;
+ //ask only the first time.
+ static bool create=( KMessageBox::questionYesNo(0,"Database do not exist. Do you want to create it now?",
+ i18n("Create Database"), i18n("Create"), i18n("Do Not Create"))==KMessageBox::Yes);
+ if(create)
+ if(aDb->open(tt,DB_CREATE)!=0)
+ {
+ kdDebug(0) << "...cannot create!!"<< endl;
+ return 0;
+ }
+ else
+ {
+ kdDebug(0) << "...done!" << endl;
+ return aDb;
+ }
+ }
+
+ }
+ return aDb;
+}
+
+/*
+ * query functions.
+ *
+ */
+
+
+DataBaseInterface::MainEntry DataBaseInterface::get(const QString& query,SearchFilter *filter)
+{
+ static int counter=1;
+ counter++;
+ DBItemMainKey k(query);
+ DBItemMainData d;
+ //int r=
+ main->get(&k,&d);
+ // kdDebug(0) << "MAINDB->GET returned: " << r << endl;
+ if(counter%5==0) kapp->processEvents(100);
+ // kdDebug(0) << "events processed" << endl;
+ return qMakePair(k,d);
+
+}
+
+/*
+ * put functions
+ * *
+ */
+
+
+bool DataBaseInterface::addEntry(QString original,QString translated,InputInfo *info)
+{
+ DBItemMainKey mk(original);
+ DBItemMainData md;
+ QMap<QString, int> correlationDiff;
+ bool newentry=false;
+ //try to get
+ kdDebug(0) << "Inserting the pair:" << endl;
+ kdDebug(0) << "ORIGINAL:" << original << endl;
+ kdDebug(0) << "TRANSLATED:" << translated << endl;
+
+ if(main->get(&mk,&md)==DB_NOTFOUND)
+ {
+ kdDebug(0) << "new entry" << endl;
+ newentry=true;
+ //This is a new entry, create index entry
+ DBItemNum *nind;
+ int newid=numindex->getLast()+1;
+ nind=new DBItemNum(newid);
+ numindex->put(nind,&mk);
+
+ delete nind;
+
+ md.clear();
+ md.setIndexnumber(newid);
+
+
+ //Update secondary index alpha
+ DBItemMainKey ka(simple(original));
+ DBItemMultiIndex in;
+ if(alpha->get(&ka,&in)==DB_NOTFOUND) in.clear() ;
+ //alpha->get(&ka,&in);
+ in.addEntry(newid);
+ alpha->put(&ka,&in);
+ kdDebug(0) << "Updating the word index " << endl;
+ //Update words index
+ QStringList ws=words(original);
+ for(QStringList::iterator it = ws.begin(); it!=ws.end(); ++it)
+ {
+ DBItemMainKey word(*it);
+ DBItemMultiIndex win;
+ if(wordsindex->get(&word,&win)==DB_NOTFOUND) win.clear();
+ win.addEntry(newid);
+ wordsindex->put(&word,&win);
+ }
+
+ kdDebug(0) << "new entry preparation DONE" << endl;
+ }
+ else
+ {
+
+ kdDebug(0) << "It exists!" <<endl;
+ }
+
+
+ //Update sentence index
+ QStringList so=sentences(original);
+ QStringList st=sentences(translated);
+ if(so.count()==st.count() && st.count() >1 ) //we already hav a database for single string.
+ {
+ kdDebug(0) << "inside sentence loop" << endl;
+ for(int i=0; i< so.count() ; i++)
+ {
+ DBItemMainKey sk(so[i]);
+ DBItemMainData sd;
+ if(sentence->get(&sk,&sd)==DB_NOTFOUND&&!newentry)
+ kdDebug(0) << "Warning: new sentence for old entry, do we changed sentence definition? " << endl;
+
+ kdDebug(0) << "here alive" << endl;
+
+ // if(clean)
+ sd.removeRef(info->ref());
+ kdDebug(0) << "now alive" << endl;
+ sd.addTranslation(st[i],info->ref());
+ kdDebug(0) << "still alive" << endl;
+
+ sentence->put(&sk,&sd);
+
+ }
+
+
+
+ }
+ kdDebug(0) << "Fuzzy sentence archive updated" << endl;
+
+
+
+ //Add that translation, link to ref for information on that translation
+
+ if(!translated.isEmpty())
+ {
+ //loop on all translations to update correlation
+ QStringList tmpTranslations=md.getTranslations();
+ for(QStringList::iterator otIt=tmpTranslations.begin(); otIt!=tmpTranslations.end();++otIt)
+ {
+ QStringList wt=words(*otIt);
+ for(QStringList::iterator it = wt.begin(); it!=wt.end(); ++it)
+ {
+ if(correlationDiff.contains(*it))
+ correlationDiff[*it]--;
+ else
+ correlationDiff[*it]=-1;
+ }
+ }
+
+ //clean so that we have only one translation per catalog.
+ md.removeRef(info->ref());
+ md.addTranslation(translated,info->ref());
+
+ tmpTranslations=md.getTranslations();
+ for(QStringList::iterator otIt=tmpTranslations.begin(); otIt!=tmpTranslations.end();++otIt)
+ {
+ QStringList wt=words(*otIt);
+ for(QStringList::iterator it = wt.begin(); it!=wt.end(); ++it)
+ {
+ if(correlationDiff.contains(*it))
+ correlationDiff[*it]++;
+ else
+ correlationDiff[*it]=1;
+ }
+ }
+
+ //FIXME: use the correlationDIff map somehow
+
+ }
+
+ //finally put!
+ return (main->put(&mk,&md)==0);
+
+}
+
+
+bool DataBaseInterface::removeEntry(QString original)
+{
+ DBItemMainKey mk(original);
+ DBItemMainData md;
+
+ //FIXME implement remove
+ //try to get
+ if(main->get(&mk,&md)==DB_NOTFOUND)
+ {
+ /* //This is a new entry, create index entry
+ DBItemNum *nind;
+ int newid=numindex->getLast()+1;
+ nind=new DBItemNum(newid);
+ numindex->put(nind,&mk);
+
+ delete nind;
+
+ md.clear();
+ md.setIndexnumber(newid);
+
+
+ //Update secondary index alpha
+ DBItemMainKey ka(simple(original));
+ DBItemMultiIndex in;
+ if(alpha->get(&ka,&in)==DB_NOTFOUND) in.clear() ;
+ //alpha->get(&ka,&in);
+ in.addEntry(newid);
+ alpha->put(&ka,&in);
+
+ //Update words index
+ QStringList ws=words(original);
+ for(QStringList::iterator it = ws.begin(); it!=ws.end(); it++)
+ {
+ DBItemMainKey word(*it);
+ DBItemMultiIndex win;
+ if(wordsindex->get(&word,&win)==DB_NOTFOUND) win.clear();
+ win.addEntry(newid);
+ wordsindex->put(&word,&win);
+ }
+
+ //Update sentence index
+ QStringList so=sentences(original);
+ QStringList st=sentences(translated);
+ if(so.count()==st.count() && st.count() >1 ) //we already hav a database for single string.
+ {
+ for(int i=0; i< so.count() ; i++)
+ {
+ DBItemMainKey sk(so[i]);
+ DBItemMainKey sd(st[i]); //should be a list i.e. main data?
+ sentence->put(&sk,&sd);
+
+ }
+ }
+
+*/
+ }
+
+
+ return false;
+
+}
+
+
+
+QMap<QString,float> DataBaseInterface::correlation(QString word,SearchFilter *filter,bool notify, float minSign)
+{
+ QDict<unsigned int> res;
+ // res.setAutoDelete(true);
+ QMap<QString, float>final;
+ DBItemMultiIndex::IndexList il;
+ unsigned int tot=0;
+ unsigned int background=0;
+ unsigned int nocck;
+ QString sword=simple(word);
+ DBItemMainKey *k = new DBItemMainKey(sword);
+ DBItemMultiIndex *d = new DBItemMultiIndex();
+ if(wordsindex->get(k,d)!=DB_NOTFOUND)
+ {
+
+ il=d->getList();
+ kdDebug(0) << il.count()<<endl;
+ tot=0;
+ for(QValueList<unsigned int>::iterator it=il.begin();it!=il.end();++it)
+ {
+ numindex->get(*it,k);
+
+
+ // QValueList<QueryResult> trad=exactMatch(k->getString(),filter);
+
+ MainEntry e=get(k->getString(),filter);
+ QStringList trad=e.second.getTranslations();
+
+ nocck=words(k->getString()).contains(sword);
+ for( QStringList::iterator it2=trad.begin();it2!=trad.end();++it2)
+ {
+
+ QStringList w=words(*it2);
+ unsigned int numWords = w.count()*10+1;
+ unsigned int wei=100000/sqrt(numWords); //weight (is the best one?)
+
+ background+=(numWords-nocck)*wei;
+ QDict<uint> count;
+ //count.setAutoDelete(true);
+ //FIXME:SET AUTODELETE FOR ALL DICTS
+ for(QStringList::iterator it1=w.begin();it1!=w.end();it1++)
+ {
+ uint *ip;
+ if(!(ip=count[*it1])) count.insert(*it1,new uint(1));
+ else
+ (*ip)++;
+ }
+
+ for(QStringList::iterator it1=w.begin();it1!=w.end();it1++)
+ {
+ uint *ip;
+ if(*(count[*it1])==nocck) //add only if same number of entry (it cuts articles)
+ if(!(ip=res[*it1])) res.insert(*it1,new uint(wei));
+ else
+ (*ip)+=wei;
+ }
+
+ }
+ }
+
+ unsigned int sqrBG=sqrt((1.0*background+1)/10000);
+
+ for(QDictIterator<uint> it(res) ; it.current(); ++it)
+ {
+ float sign=1.0*(*(it.current()))/(10000.0*sqrBG);
+ if(sign >minSign){
+ final[it.currentKey()]=sign;
+ kdDebug(0) << it.currentKey() <<" Score:" << 1.0*(*(it.current()))/10000 << "/" <<sqrBG << " = " <<sign << endl;
+ }
+ }
+
+ kdDebug(0) << "final count " <<final.count()<< endl;
+ }
+
+ return final;
+}
+
+QStringList DataBaseInterface::words(QString s)
+{
+ QString str=simple(s);
+ QStringList list;
+
+ int pos;
+
+ do {
+ pos=str.find(QRegExp("\\s"));
+ // if(!simple(str.left(pos)).isEmpty())
+ // list.append(simple(str.left(pos)));
+ if(!str.left(pos).isEmpty())
+ list.append(str.left(pos));
+ str=str.remove(0,pos+1);
+ } while(!str.isEmpty() && pos != -1);
+
+ return list;
+}
+
+QString DataBaseInterface::simple(QString str,bool ck)
+{
+ QString res;
+ if(ck)
+ res=str; //case keep
+ else
+ res=str.lower(); //lowercase
+ //FIXME: uncoment the foll. line (check speed)
+ res=res.replace(QRegExp("(<(.*)>)(.*)(</\\2>)"),"\\3"); //remove enclosing tags
+
+
+ //Try to get rid of regexps.
+ // res=res.replace(QRegExp("(('|-|_|\\s|[^\\w%])+)")," "); //strip non-word char
+ // res=res.replace(QRegExp("(('|-|_)+)")," "); //strip non-word char
+ // res=res.replace(QRegExp("[^\\w\\s%]"),""); //strip non-word char
+
+ QString r;
+ QChar c;
+ bool wasSpace=true;
+ uint len=res.length();
+ for(uint i=0; i<len;i++)
+ {
+ c=res[i];
+ if(c.isLetterOrNumber())
+ {
+ r+=c;
+ wasSpace=false;
+ }
+ else
+ {
+ if(!wasSpace && c.isSpace())
+ {
+ r+=' ';
+ wasSpace=true;
+ }
+ else
+ {
+ if(!wasSpace && (c=='-' || c=='\'' || c=='_'))
+ {
+ r+=' ';
+ wasSpace=true;
+ }
+ else
+ {
+ if(c=='%'){
+ r+=c;
+ wasSpace=false;
+ }
+ }
+ }
+ }
+ // wasSpace=c.isSpace();
+ }
+ if(r[len-1].isSpace())
+ r.truncate(len-1);
+ res=r;
+ //kdDebug(0) << "Simple: "<<res<< endl;
+ //res=res.simplifyWhiteSpace(); //remove double spaces
+ //res=res.stripWhiteSpace(); //" as " -> "as"
+
+ // kdDebug(0) << res << endl;
+ return res;
+}
+
+QStringList DataBaseInterface::sentences(QString s)
+{
+ QString str=s;
+ QStringList list;
+
+ // kdDebug(0) << s << endl;
+
+ int pos;
+
+
+ do {
+ QRegExp re("((\\.|;|\\?|\\!|:)( |$|\\\\n\\n))");
+ pos=re.search(str);
+ if(!str.left(pos).isEmpty())
+ list.append(str.left(pos).stripWhiteSpace());
+
+ kdDebug(0) << str.left(pos) << endl;
+
+ str=str.remove(0,pos+re.cap(1).length());
+ } while(!str.isEmpty() && pos != -1);
+
+
+ return list;
+}
+
+QStringList DataBaseInterface::sentencesSeparator(QString s)
+{
+ QString str=s;
+ QStringList list;
+
+ // kdDebug(0) << s << endl;
+
+ int pos;
+
+ do {
+ QRegExp re;
+ re.setPattern("([.:?!;]( |$|\\\\n\\n))");
+ pos = re.search(str);
+ QString separator=re.cap(1);
+ if(pos!=-1){
+ list.append(separator);
+ }
+
+ str=str.remove(0,pos+1);
+ } while(!str.isEmpty() && pos != -1);
+
+ return list;
+}
+
+bool DataBaseInterface::isUpper(QChar s)
+{
+ return s==s.upper();
+}
+
+bool DataBaseInterface::isLower(QChar s)
+{
+ return s==s.lower();
+}
+
+
+
+QString DataBaseInterface::format(QString _s,QString t)
+{
+ //FIXME use settings
+ //FIXME use regexp
+
+ QString s=_s;
+ QString noTagT=t.replace(QRegExp("(<(.*)>)(.*)(</\\2>)"),"\\3");
+ QChar first=noTagT[noTagT.find(QRegExp("\\w"))];
+ bool firstCapital=isUpper(first);
+
+ /*
+bool dotsAtEnd=(t.find("...")+3==t.length());
+bool gtgtAtEnd=(t.find(">>")+2==t.length());
+bool ltltAtEnd=(t.find("<<")==t.length()-2);
+
+bool columnAtEnd=(t.find(":")+1==t.length());
+*/
+
+ bool allupper=(t.upper()==t);
+
+
+ if(firstCapital)
+ s[0]=s[0].upper();
+ else
+ s[0]=s[0].lower();
+
+ //if(dotsAtEnd)
+ // s+="...";
+
+ /*if(gtgtAtEnd)
+ s+=">>";
+
+if(ltltAtEnd)
+ s+="<<";
+
+if(columnAtEnd)
+ s+=":";
+*/
+
+ if(allupper)
+ s=s.upper();
+
+ int pos=t.find(QRegExp("&"));
+ if(pos>=0) {
+ QChar accel=t[t.find(QRegExp("&"))+1];
+ if(accel!='&')
+ {
+
+ pos=s.find(accel,false);
+ if(pos<0)
+ pos=0;
+ s.insert(pos,"&");
+ }
+ }
+ s=formatRegExp(s,t,".*(\\.\\.\\.|:|>>|<<|\\.|\\?)$",
+ "^(.*)$",
+ "\\1@CAP1@");
+ s=formatRegExp(s,t,"(<(.*)>).*(\\.\\.\\.|:|>>|<<|\\.|\\?)*(</\\2>)$",
+ "^(.*)$",
+ "@CAP1@\\1@CAP3@@CAP4@");
+
+ return s;
+
+}
+
+
+QString DataBaseInterface::formatRegExp(QString _s, QString t, QString tre,QString stringSearch,QString stringReplace)
+{
+ QString s=_s;
+ QRegExp templateRegExp(tre);
+ //QString stringSearch = "(.*)!@CAP1@$"; // use @CAP1.. fot caps in templates
+ //QString stringReplace = "\\1@CAP1@"; // use \1, \2 for caps in str and @CAP1 fot caps in template
+
+
+ if(templateRegExp.exactMatch(t))
+ {
+ QStringList caps=templateRegExp.capturedTexts();
+ int i=0;
+ for(QStringList::iterator capit=caps.begin();capit!=caps.end();++capit)
+ {
+ QString phRegExp="(?!\\\\)@CAP"+QString::number(i)+"@";
+ //kdDebug(0) << "phRegExp: " << phRegExp << endl;
+ //kdDebug(0) << "cap[" << i << "]: "<< *capit<< endl;
+
+ stringReplace = stringReplace.replace(QRegExp(phRegExp),*capit);
+ stringSearch = stringSearch.replace(QRegExp(phRegExp),*capit);
+ i++;
+
+ }
+ // kdDebug(0) << "stringSearch " << stringSearch << endl;
+ // kdDebug(0) << "stringReplace " << stringReplace << endl;
+ QRegExp stringSearchRegExp = QRegExp(stringSearch);
+ // kdDebug(0) << "before: "<<s<<endl;
+ s = s.replace(stringSearchRegExp,stringReplace);
+ // kdDebug(0) << "after: "<<s<<endl;
+
+ }
+
+ return s;
+}
+
+DBItemMultiIndex::IndexList DataBaseInterface::getAlpha( const QString & query )
+{
+ DBItemMainKey *k = new DBItemMainKey(simple(query));
+ DBItemMultiIndex *d = new DBItemMultiIndex();
+ alpha->get(k,d);
+
+ return d->getList();
+}
+
+DataBaseInterface::MainEntry DataBaseInterface::getFromIndex( uint i )
+{
+ DBItemMainKey k;
+ numindex->get(i,&k);
+ return get(k.getString(),0); //FIXME: this is a BUG right now but the filter should be removed
+}
+
+DataBaseInterface::MainEntry DataBaseInterface::getSentence( const QString & query )
+{
+
+ static int counter=1;
+ counter++;
+ DBItemMainKey k(query);
+ DBItemMainData d;
+ sentence->get(&k,&d);
+ if(counter%5==0) kapp->processEvents(100);
+ return qMakePair(k,d);
+
+}
+
+DBItemMultiIndex::IndexList DataBaseInterface::getWordIndex( const QString & query )
+{
+ DBItemMainKey k = DBItemMainKey(query);
+ DBItemMultiIndex d = DBItemMultiIndex();
+ if(wordsindex->get(&k,&d)!=DB_NOTFOUND){
+ return d.getList();
+ }
+ else
+ {
+ QValueList<unsigned int> tmpList;
+ return tmpList;
+ }
+
+}
+
+
+
+//#include "database.moc.cpp"
+
diff --git a/kbabel/kbabeldict/modules/dbsearchengine2/database.h b/kbabel/kbabeldict/modules/dbsearchengine2/database.h
new file mode 100644
index 00000000..c447fa59
--- /dev/null
+++ b/kbabel/kbabeldict/modules/dbsearchengine2/database.h
@@ -0,0 +1,237 @@
+/*
+
+ DBSE 3
+ (c) 2000-2003 Andrea Rizzi
+ License: GPLv2
+
+*/
+#ifndef DATABASE_2_H
+#define DATABASE_2_H
+
+#include <qstring.h>
+#include <qvaluelist.h>
+#include <db4/db_cxx.h>
+#include <qobject.h>
+#include <qregexp.h>
+
+#include "dbentries.h"
+
+
+class DBSESettings
+{
+public:
+ //DatabaseInterface Settings
+ uint scoreWordByWord;
+ uint scoreGlossary;
+ uint scoreDivide;
+ uint scoreExact;
+ uint scoreSentence;
+ uint scoreAlpha;
+ uint scoreDynamic;
+ uint scoreChunkByChunk;
+ uint minScore;
+ bool firstCapital;
+ bool allCapital;
+ bool accelerator;
+ bool sameLetter;
+
+
+
+};
+
+
+class DataBase : Db
+{
+ public:
+ DataBase(QString dbpath, QString dbname, QString dblang);
+
+ int open(DBTYPE type,unsigned int flags=0);
+
+//Standard access (overload std functions)
+
+
+
+int del(DBItem * key){
+ key->set();
+ int r = Db::del(0,key,0);
+ key->get();
+ return r;
+ }
+
+
+
+int get(DBItem * key,DBItem *data){
+ key->set();
+ data->set();
+ int r = Db::get(0,key,data,0);
+ key->get();
+ data->get();
+ return r;
+ }
+ int put(DBItem * key,DBItem *data,int fl=0){
+ key->set();
+ data->set();
+ int r= Db::put(0,key,data,0);
+ key->get();
+ data->get();
+ return r;
+ }
+
+ int del(DBItemNum * key){
+ int r = Db::del(0,key,0);
+ return r;
+ }
+
+ int get(DBItemNum * key,DBItem *data){
+ data->set();
+ int r = Db::get(0,key,data,0);
+ data->get();
+ return r;
+ }
+ int put(DBItemNum * key,DBItem *data)
+ {
+ data->set();
+ int r= Db::put(0,key,data,0);
+ data->get();
+ return r;
+ }
+
+//Overload, using this you loose the Key!!
+ int del(int i){DBItemNum n(i); return del(&n);}
+ int get(int i,DBItem *data){DBItemNum n(i); return get(&n,data);}
+ int put(int i,DBItem *data){DBItemNum n(i); return put(&n,data);}
+
+ unsigned int getLast();
+ int close(unsigned int i) {return Db::close( i); }
+
+//For scrolling
+ // int getFirst(DBItem *key,DBItem *data,QString table);
+ // int getNext(DBItem *key,DBItem *data,QString table);
+ // bool isEnd(QString table);
+private:
+ QString filename;
+ QString database;
+ DBTYPE mytype;
+};
+
+
+
+
+
+class QueryResult //from DBInterface to KDBSearchEngine
+{
+public:
+ QueryResult();
+ QueryResult(QString r);
+ QueryResult(QString r,QString o,int s);
+ void setRichResult(QString r) { richr=r; }
+ void setRichOriginal(QString r) { richo=r; }
+
+ QString richResult() {return richr;}
+ QString richOriginal() {return richo;}
+
+ QString result(){ return res; }
+ QString original() {return orig; }
+ int score() {return sco;}
+//info contains originalkey,catalog,date,author etc...
+ ResultInfo info(){ResultInfo i; i.info="no info"; return i;}
+
+
+private:
+ QString res;
+ QString orig;
+ QString richr;
+ QString richo;
+ int sco;
+
+};
+
+class SearchFilter
+{
+ int filter; //placeholder
+};
+
+
+
+class DataBaseInterface : public QObject
+{
+
+ public:
+ //move result list typedef to AbstractAlgorthm or somewhere else
+ typedef QValueList<QueryResult> ResultList;
+ typedef QPair<DBItemMainKey,DBItemMainData> MainEntry;
+
+ DataBaseInterface( QString dir, DBSESettings *sets);
+ ~DataBaseInterface();
+
+ //Ask the Database to stop now.
+ void stop(bool b=true) {_stopNow=b;}
+
+ //Search words
+ ResultList wordsMatch(QString query,SearchFilter *filter=0,bool notify=true);
+
+ //Edit database functions.
+ //addEntry and sync all the tables
+ bool addEntry(QString original,QString translated,InputInfo *info);
+ //FIXME:implement me!
+ bool removeEntry(QString original);
+
+ //FIXME: go persistent!
+ QMap<QString,float> correlation(QString word,SearchFilter *filter=0,bool notify=true,float minSign=0.2);
+
+
+ // Read the database
+ MainEntry get(const QString& query,SearchFilter *filter=0);
+ MainEntry getFromIndex(uint i);
+ DBItemMultiIndex::IndexList getAlpha(const QString& query);
+ DBItemMultiIndex::IndexList getWordIndex(const QString& query);
+ MainEntry getSentence(const QString& query);
+
+ //Database status check functions
+ bool mainOk() {return main!=0;}
+ bool catalogOk() {return catalog!=0;}
+ bool alphaOk() {return alpha!=0;}
+ bool sentenceOk() {return sentence!=0;}
+ bool numindexOk() {return numindex!=0;}
+ bool wordsindexOk() {return wordsindex!=0;}
+ bool externalOk() {return external!=0;}
+ bool wordOk() {return word!=0;}
+ bool transwordOk() {return transword!=0;}
+ bool correlationOk() {return corr!=0;}
+ bool stopNow() {return _stopNow;}
+
+ // signals:
+ // void newResult(QueryResult);
+
+ DBSESettings *getSettings() {return settings;}
+
+ private:
+ DataBase * openMyDataBase(const QString& prefix,const QString& name,const QString& l,DBTYPE tt);
+ DataBase *main;
+ DataBase *numindex;
+ DataBase *wordsindex;
+ DataBase *catalog;
+ DataBase *alpha;
+ DataBase *sentence;
+ DataBase *word;
+ DataBase *external;
+ DataBase *transword;
+ DataBase *corr;
+ bool _stopNow;
+ DBSESettings *settings;
+
+ //FIXME:Move to KBabel common library.
+ public:
+ QString format( QString _s,QString t);
+ QString formatRegExp(QString _s, QString t, QString tre,QString stringSearch,QString stringReplace);
+ static QStringList words(QString s);
+ static QStringList sentences(QString s);
+ static QStringList sentencesSeparator(QString s);
+ static QString simple(QString str,bool ck=false);
+ static bool isUpper(QChar s);
+ static bool isLower(QChar s);
+
+ };
+
+#endif
+
diff --git a/kbabel/kbabeldict/modules/dbsearchengine2/dbentries.cpp b/kbabel/kbabeldict/modules/dbsearchengine2/dbentries.cpp
new file mode 100644
index 00000000..4f048f9c
--- /dev/null
+++ b/kbabel/kbabeldict/modules/dbsearchengine2/dbentries.cpp
@@ -0,0 +1,171 @@
+#include "dbentries.h"
+#include <qdatastream.h>
+
+
+void DBItem::set()
+{
+ QBuffer b(mydata);
+ b.open( IO_WriteOnly );
+ QDataStream s(&b);
+ write(&s);
+ b.close();
+ set_data(mydata.data());
+ set_size(mydata.size());
+
+}
+ void DBItem::get()
+ {
+ mydata.resize(get_size());
+ mydata.duplicate((const char *)get_data(),(unsigned int)get_size());
+
+ QDataStream *s = new QDataStream(mydata,IO_ReadOnly);
+ read(s);
+ delete s;
+ }
+
+
+
+DBItemMainKey::DBItemMainKey()
+{
+ sstr="";
+ //set();
+}
+
+DBItemMainKey::DBItemMainKey(QString searchstring)
+{
+ sstr=searchstring;
+ //set();
+}
+
+void DBItemMainKey::read(QDataStream *s)
+{
+*s >> sstr;
+}
+
+void DBItemMainKey::write(QDataStream *s)
+{
+ *s << sstr;
+ }
+
+
+
+
+
+DBItemMainData::DBItemMainData()
+{
+ clear();
+ //set();
+}
+
+void DBItemMainData::clear()
+{
+ indexnumber=0;
+ translations.clear();
+ //set();
+}
+
+void DBItemMainData::read(QDataStream *s)
+{
+*s >> indexnumber >> translations;
+}
+
+void DBItemMainData::write(QDataStream *s)
+{
+ *s << (Q_UINT32)indexnumber << translations;
+}
+
+void DBItemMainData::addTranslation(QString str, unsigned int ref)
+{
+//get();
+ if(translations[str].find(ref)==translations[str].end()) // If it do not exists
+ translations[str].append(ref); //add a new reference.
+ else
+ {
+
+ }
+//set();
+
+}
+
+void DBItemMainData::removeTranslation(QString str, unsigned int ref)
+{
+//get();
+ translations[str].remove(ref);
+ if(translations[str].isEmpty())
+ translations.remove(str);
+//set();
+
+}
+
+void DBItemMainData::removeRef( unsigned int ref)
+{
+//get();
+QMapIterator<QString,QValueList<unsigned int> > it2;
+ for(QMapIterator<QString,QValueList<unsigned int> > it = translations.begin();
+ it!= translations.end(); /* it++*/)
+ { //Dirty hack
+ it2=it;
+ it++;
+ if(it2.data().find(ref)!=it2.data().end())
+ removeTranslation(it2.key(),ref);
+ }
+
+//set();
+}
+
+QStringList DBItemMainData::getTranslations()
+{
+//get();
+QStringList result;
+ for(QMapIterator<QString,QValueList<unsigned int> > it = translations.begin();
+ it!= translations.end(); it++)
+ result.append(it.key());
+
+return result;
+
+}
+
+QValueList<unsigned int> DBItemMainData::getReferences(QString str)
+{
+//get();
+return translations[str]; //this also add a "str" entry but we do not call set()!
+}
+
+
+
+DBItemMultiIndex::DBItemMultiIndex()
+{
+list.clear();
+//set();
+}
+
+void DBItemMultiIndex::addEntry(unsigned int index)
+{
+// get();
+ if(list.find(index)==list.end())
+ {
+ list.append(index);
+ qHeapSort(list);
+ // set();
+
+ }
+
+}
+
+void DBItemMultiIndex::removeEntry(unsigned int index)
+{
+// get();
+ list.remove(index);
+// set();
+}
+
+
+void DBItemMultiIndex::read(QDataStream *s)
+{
+*s >> list;
+}
+
+void DBItemMultiIndex::write(QDataStream *s)
+{
+ *s << list;
+ }
diff --git a/kbabel/kbabeldict/modules/dbsearchengine2/dbentries.h b/kbabel/kbabeldict/modules/dbsearchengine2/dbentries.h
new file mode 100644
index 00000000..0a40878c
--- /dev/null
+++ b/kbabel/kbabeldict/modules/dbsearchengine2/dbentries.h
@@ -0,0 +1,170 @@
+#ifndef DBENTRIES_H
+#define DBENTRIES_H
+
+#include <db4/db_cxx.h>
+#include <qstring.h>
+#include <qbuffer.h>
+#include <qmap.h>
+#include <qstringlist.h>
+#include <qdatetime.h>
+
+class CatalogInfo
+{
+
+ QString author;
+ QDateTime datetime;
+ QString filename;
+ QString filepath;
+
+
+};
+
+class ResultInfo
+{
+public:
+//Common info
+ QString original; //placeholder
+
+//
+//Multi reference info
+ QValueList<CatalogInfo> catalogs;
+
+ QString info;
+
+};
+
+class InputInfo
+{
+public:
+ unsigned int ref() {return 1;}
+
+};
+
+class DBItem : public Dbt
+{
+public:
+
+ virtual ~DBItem(){}
+
+ virtual bool isEmpty(){return empty;}
+//void fromDbt(Dbt *dbt);
+
+ void set();
+ void get();
+
+
+protected:
+ virtual void read(QDataStream *s) = 0;
+ virtual void write(QDataStream *s) = 0;
+ QByteArray mydata;
+ bool empty;
+
+};
+
+class DBItemMainKey : public DBItem
+{
+ public:
+ DBItemMainKey();
+ DBItemMainKey(QString searchstring);
+
+
+ QString getString(){ return sstr;}
+
+private:
+
+ virtual void read(QDataStream *s);
+ virtual void write(QDataStream *s);
+
+ QString sstr;
+
+};
+
+
+class DBItemMainData : public DBItem
+{
+ public:
+
+ typedef QMapIterator<QString,QValueList<unsigned int> > TranslationIterator;
+ typedef QMap<QString,QValueList<unsigned int> > TranslationMap;
+
+ DBItemMainData();
+
+ QStringList getTranslations();
+ QValueList<unsigned int> getReferences(QString str);
+
+ void clear();
+
+
+//Add a translation with reference ref, if translation exists append
+// ref to the list of references
+ void addTranslation(QString str,unsigned int ref);
+ void removeTranslation(QString str,unsigned int ref);
+
+//remove any reference to ref, if ref is the only reference of a translation
+// the translation is removed
+ void removeRef(unsigned int ref);
+
+ unsigned int getIndexnumber(){ return indexnumber; }
+ void setIndexnumber(int i){ indexnumber=i; }
+
+private:
+
+ virtual void read(QDataStream *s);
+ virtual void write(QDataStream *s);
+
+ unsigned int indexnumber;
+ TranslationMap translations;
+
+};
+
+
+class DBItemMultiIndex : public DBItem
+{
+ public:
+ typedef QValueList<unsigned int> IndexList;
+
+ DBItemMultiIndex();
+ // DBItemMultiIndex(IndexList l);
+
+ void addEntry(unsigned int index);
+ void removeEntry(unsigned int index);
+
+ IndexList getList(){ return list;}
+ void clear() {list.clear();}
+
+private:
+
+ virtual void read(QDataStream *s);
+ virtual void write(QDataStream *s);
+
+ IndexList list;
+
+};
+
+
+class DBItemNum : public Dbt
+{
+ public:
+ DBItemNum(){
+ set_data(&num);
+ set_size(4);
+ num=0;
+ }
+ DBItemNum(unsigned int i){
+ set_data(&num);
+ set_size(4);
+ num=i;
+ }
+
+ unsigned int getNum(){ num=*(unsigned int *)get_data(); return num;}
+
+private:
+
+ unsigned int num;
+
+};
+
+
+
+
+#endif
diff --git a/kbabel/kbabeldict/modules/dbsearchengine2/dbscan.cpp b/kbabel/kbabeldict/modules/dbsearchengine2/dbscan.cpp
new file mode 100644
index 00000000..b19b2db2
--- /dev/null
+++ b/kbabel/kbabeldict/modules/dbsearchengine2/dbscan.cpp
@@ -0,0 +1,280 @@
+/***************************************************************************
+ dbscan.cpp - Scan for po files to add in the DB
+ -------------------
+ begin : Fri Sep 8 2000
+ copyright : (C) 2000 by Andrea Rizzi
+ email : rizzi@kde.org
+ ***************************************************************************/
+
+/*
+ Translation search engine
+
+
+ Copyright 2000
+ Andrea Rizzi rizzi@kde.org
+
+ License GPL v 2.0
+
+*/
+#include "dbscan.h"
+#include <kconfig.h>
+#include <qdir.h>
+#include <qfile.h>
+#include <kapplication.h>
+#include <kurl.h>
+#include <kdebug.h>
+#include <klineedit.h>
+#include <kurlrequester.h>
+#include <kcombobox.h>
+
+using namespace KBabel;
+
+MessagesSource::MessagesSource()
+{
+ //FIXMR: check if we should put something in that constructor
+}
+void MessagesSource::writeConfig(KConfigBase *config)
+{
+ config->writeEntry("Location",location.url());
+ config->writeEntry("LocationType",type);
+ config->writeEntry("ProjectName",projectName);
+ config->writeEntry("ProjectKeywords",projectKeywords);
+ config->writeEntry("Status",status);
+}
+
+void MessagesSource::readConfig(KConfigBase *config)
+{
+ location=config->readEntry("Location");
+ type=config->readNumEntry("LocationType",0);
+ projectName=config->readEntry("ProjectName");
+ projectKeywords=config->readEntry("ProjectKeywords");
+ status=config->readEntry("Status");
+
+}
+
+void MessagesSource::setDialogValues(SourceDialog *sd)
+{
+ sd->projectName->setText(projectName);
+ sd->projectKeywords->setText(projectKeywords);
+ sd->sourceLocation->setURL(location.url());
+ sd->status->setCurrentText(status);
+ sd->type->setCurrentItem(type);
+}
+void MessagesSource::getDialogValues(SourceDialog *sd)
+{
+ projectName=sd->projectName->text();
+ projectKeywords=sd->projectKeywords->text();
+ location=sd->sourceLocation->url();
+ status=sd->status->currentText();
+ type=sd->type->currentItem();
+}
+
+QValueList<KURL> MessagesSource::urls()
+{
+ QValueList<KURL> urlList;
+ if(type==0)
+ urlList.append(location);
+ if(type==1|| type==2)
+ urlList=filesInDir(location,(type==2));
+
+ return urlList;
+
+}
+
+QValueList<KURL> MessagesSource::filesInDir(KURL url,bool recursive)
+{
+ QValueList<KURL> result;
+ QDir d(url.path());
+ d.setMatchAllDirs(true);
+ kdDebug(0) << d.count() << " files in dir "<< url.path()<<endl;
+ const QFileInfoList* files = d.entryInfoList();
+ kdDebug(0) << files << endl;
+
+ // QPtrListIterator<QFileInfo> it(*files);
+ if(files){
+ for (QPtrListIterator<QFileInfo> fileit(*files); !fileit.atLast(); ++fileit )
+ {
+ if ((*fileit)->isDir())
+ {
+ if(recursive)
+ {
+ if((*fileit)->fileName()!="." && (*fileit)->fileName() !="..")
+ {
+ result+=filesInDir(KURL((*fileit)->absFilePath()),recursive);
+ kdDebug(0) << "Recursion done for " << (*fileit)->fileName() << endl;
+ }
+ }
+
+ }
+ else
+ {
+ kdDebug(0) << (*fileit)->fileName() << endl;
+ result.append(KURL((*fileit)->absFilePath()));
+ }
+ }
+ }
+ kdDebug(0) << result.count() << endl;
+
+ return result;
+}
+
+//FIXME: clean this class
+PoScanner::PoScanner(DataBaseInterface *dbi,
+ QObject *parent,const char *name):QObject(parent,name)
+{
+ di=dbi;
+ removeOldCatalogTranslation=true;
+ count=0;
+}
+
+bool PoScanner::scanPattern(QString pathName,QString pattern,bool rec)
+{
+int tot;
+//Only one progress bar!!
+
+bool pb=false;
+static bool called=false;
+if (!called)
+{ pb=true; count=0;}
+called=true;
+
+kdDebug(0) << QString("Scanning: %1, %2").arg(pathName).arg(pattern) << endl;
+
+if(pb)
+{
+emit patternStarted();
+emit patternProgress(0);
+}
+ QDir d(pathName,pattern);
+ d.setMatchAllDirs(true);
+ const QFileInfoList* files = d.entryInfoList();
+ tot=files->count();
+ QPtrListIterator<QFileInfo> it(*files);
+kdDebug(0) << tot << endl;
+ for ( int i=0; i<tot; i++ )
+ {
+ if ((*it)->isDir())
+ {
+ if(rec)
+ {
+ kdDebug(0) << d[i] << endl;
+ if(d[i]!="." && d[i]!="..")
+ scanPattern(pathName+"/"+d[i],pattern,true);
+ }
+ } else
+ {
+ kdDebug(0) << d[i] << endl;
+ scanFile(pathName+"/"+d[i]);
+ }
+
+ if(pb)
+
+ emit patternProgress(100*i/tot);
+
+
+ ++it;
+ }
+
+
+
+if(pb)
+emit patternProgress(100);
+
+
+if(pb)
+emit patternFinished();
+if(pb){called=false;count=0;}
+
+return true;
+}
+
+bool PoScanner::scanFile(QString fileName)
+{
+ KURL u(fileName);
+ return scanURL(u);
+}
+
+bool PoScanner::scanURL(KURL u)
+{
+
+
+emit fileStarted();
+
+Catalog * catalog=new Catalog(this,"ScanPoCatalog");
+
+QString pretty=u.prettyURL();
+QString location=pretty.right(pretty.length()-pretty.findRev("/")-1);
+
+connect(catalog,SIGNAL(signalProgress(int)),this,SIGNAL(fileLoading(int)));
+emit filename(location);
+emit fileProgress(0);
+emit fileLoading(0);
+
+bool error;
+
+ConversionStatus rr=catalog->openURL(u);
+if(rr != OK && rr !=RECOVERED_PARSE_ERROR )
+{
+ delete catalog;
+ return false;
+}
+emit fileLoading(100);
+
+QString author;
+if(rr != HEADER_ERROR)
+ author=catalog->lastTranslator();
+else author=QString("");
+
+//int catnum=dm->catalogRef(location,author,fileName);
+InputInfo ii;
+
+
+uint i,tot;
+tot=catalog->numberOfEntries();
+
+bool fuzzy;
+bool untra;
+
+
+for (i=0;i<tot;i++) //Skip header = ????
+{
+
+ if(i % 10==0)
+ {
+ emit fileProgress(100*i/tot);
+ emit added(count);
+ kapp->processEvents(100);
+ }
+
+ fuzzy=catalog->isFuzzy(i);
+ untra=catalog->isUntranslated(i);
+
+
+ if(!fuzzy && !untra)
+ {
+ int res;
+ QString msgid,msgstr;
+ msgid=catalog->msgid(i,true).first();
+ msgstr=catalog->msgstr(i).first();
+ res=di->addEntry(msgid,msgstr,&ii);
+ count+=res;
+ }
+
+
+}
+
+
+// kdDebug(0) << QString("File finished") << endl;
+
+emit fileProgress(0);
+emit fileLoading(0);
+emit fileFinished();
+// dm->loadInfo(); // Sync the list of catalogs NOT NEEDED (?)
+
+delete catalog;
+
+//clear();
+return true;
+
+}
+#include "dbscan.moc"
diff --git a/kbabel/kbabeldict/modules/dbsearchengine2/dbscan.h b/kbabel/kbabeldict/modules/dbsearchengine2/dbscan.h
new file mode 100644
index 00000000..990d556c
--- /dev/null
+++ b/kbabel/kbabeldict/modules/dbsearchengine2/dbscan.h
@@ -0,0 +1,120 @@
+/***************************************************************************
+ dbscan.h -
+ -------------------
+ begin : Fri Sep 8 2000
+ copyright : (C) 2000 by Andrea Rizzi
+ email : rizzi@kde.org
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+/*
+ Translation search engine
+ Copyright 2000
+ Andrea Rizzi rizzi@kde.org
+
+*/
+
+
+#ifndef _DBSCAN_H_
+#define _DBSCAN_H_
+
+#include <catalog.h>
+#include <kurl.h>
+#include "database.h"
+
+#include "sourcedialog.h"
+
+class KConfigBase;
+
+class MessagesSource
+{
+ //FIXME Use KURL and add network support
+
+ public:
+ MessagesSource();
+ void writeConfig(KConfigBase *config);
+ void readConfig(KConfigBase *config);
+ void setDialogValues(SourceDialog *sd);
+ void getDialogValues(SourceDialog *sd);
+
+ /**
+ * It returns a list of urls to scan, the list contains single file if type is "SingleFile"
+ * or a list of files if type is "SingleDir" or "RecDir"
+ */
+ QValueList<KURL> urls();
+
+ private:
+ QValueList<KURL> filesInDir(KURL url,bool recursive);
+
+ KURL location;
+ // The source type "SingleFile" =0, "SingleDirectory"=1, "RecursiveDirectory"=2
+ uint type;
+
+ /**
+ * A filter to apply on source files
+*/
+
+ SearchFilter filter;
+
+ QString projectName;
+ QString projectKeywords;
+ QString status;
+};
+
+
+class PoScanner : public QObject
+{
+ Q_OBJECT;
+
+ public:
+
+ PoScanner(DataBaseInterface *dbi,QObject *parent=0,const char *name=0);
+
+ /*
+ Scan a single PO file.
+ */
+ bool scanFile(QString fileName);
+
+ /*
+ Scan a single URL file.
+ */
+ bool scanURL(KURL u);
+
+
+ /*
+ Scan a list of space separated files with possible MetaCharacters
+ */
+ bool scanPattern(QString pathName,QString pattern="*.po",bool rec=false);
+
+
+
+
+ signals:
+ void fileStarted();
+ void fileProgress(int);
+ void fileFinished();
+ void fileLoading(int);
+ void patternStarted();
+ void patternProgress(int);
+ void patternFinished();
+ void added(int);
+ void filename(QString);
+ private:
+
+ // If true when a translation is found in a CATALOG the old translation for this CATALOG
+ // will be removed
+ bool removeOldCatalogTranslation;
+ int count;
+ DataBaseInterface *di;
+ // InfoItem cinfo;
+};
+
+
+#endif
diff --git a/kbabel/kbabeldict/modules/dbsearchengine2/dbse2.ui b/kbabel/kbabeldict/modules/dbsearchengine2/dbse2.ui
new file mode 100644
index 00000000..327a9d9d
--- /dev/null
+++ b/kbabel/kbabeldict/modules/dbsearchengine2/dbse2.ui
@@ -0,0 +1,732 @@
+<!DOCTYPE UI><UI version="3.2" stdsetdef="1">
+<class>DBSearchEnginePrefWidget</class>
+<widget class="QWidget">
+ <property name="name">
+ <cstring>Form1</cstring>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>447</width>
+ <height>483</height>
+ </rect>
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QTabWidget" row="0" column="0">
+ <property name="name">
+ <cstring>tabWidget2</cstring>
+ </property>
+ <widget class="QWidget">
+ <property name="name">
+ <cstring>tab</cstring>
+ </property>
+ <attribute name="title">
+ <string>General</string>
+ </attribute>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QGroupBox" row="0" column="0">
+ <property name="name">
+ <cstring>groupBox1</cstring>
+ </property>
+ <property name="title">
+ <string>Database</string>
+ </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>DB folder:</string>
+ </property>
+ </widget>
+ <widget class="KURLRequester" row="0" column="1">
+ <property name="name">
+ <cstring>dbDirectory</cstring>
+ </property>
+ </widget>
+ <widget class="QCheckBox" row="1" column="0" rowspan="1" colspan="2">
+ <property name="name">
+ <cstring>autoUpdate</cstring>
+ </property>
+ <property name="text">
+ <string>Automatic update in kbabel</string>
+ </property>
+ </widget>
+ </grid>
+ </widget>
+ <widget class="QGroupBox" row="1" column="0">
+ <property name="name">
+ <cstring>groupBox2</cstring>
+ </property>
+ <property name="title">
+ <string>New Entries</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>Author:</string>
+ </property>
+ </widget>
+ <widget class="QCheckBox" row="0" column="2">
+ <property name="name">
+ <cstring>checkBox2</cstring>
+ </property>
+ <property name="text">
+ <string>From kbabel</string>
+ </property>
+ </widget>
+ <widget class="KLineEdit" row="0" column="1">
+ <property name="name">
+ <cstring>kLineEdit1</cstring>
+ </property>
+ </widget>
+ </grid>
+ </widget>
+ <spacer row="2" column="0">
+ <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>40</height>
+ </size>
+ </property>
+ </spacer>
+ </grid>
+ </widget>
+ <widget class="QWidget">
+ <property name="name">
+ <cstring>tab</cstring>
+ </property>
+ <attribute name="title">
+ <string>Algorithm</string>
+ </attribute>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLabel" row="3" column="0">
+ <property name="name">
+ <cstring>textLabel5</cstring>
+ </property>
+ <property name="text">
+ <string>Minimum score:</string>
+ </property>
+ </widget>
+ <spacer row="4" column="1">
+ <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>40</height>
+ </size>
+ </property>
+ </spacer>
+ <widget class="Line" row="1" column="0" rowspan="1" colspan="3">
+ <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="QGroupBox" row="0" column="0" rowspan="1" colspan="3">
+ <property name="name">
+ <cstring>groupBox3</cstring>
+ </property>
+ <property name="title">
+ <string>Algorithms to Use</string>
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLabel" row="1" column="1">
+ <property name="name">
+ <cstring>textLabel3_2</cstring>
+ </property>
+ <property name="text">
+ <string>Score:</string>
+ </property>
+ </widget>
+ <widget class="KIntSpinBox" row="6" column="2">
+ <property name="name">
+ <cstring>scoreWordByWord</cstring>
+ </property>
+ </widget>
+ <widget class="KIntSpinBox" row="1" column="2">
+ <property name="name">
+ <cstring>scoreGlossary</cstring>
+ </property>
+ </widget>
+ <widget class="QLabel" row="2" column="1">
+ <property name="name">
+ <cstring>textLabel3_2_2</cstring>
+ </property>
+ <property name="text">
+ <string>Score:</string>
+ </property>
+ </widget>
+ <widget class="QCheckBox" row="3" column="0">
+ <property name="name">
+ <cstring>useSentence</cstring>
+ </property>
+ <property name="text">
+ <string>Fuzzy sentence archive</string>
+ </property>
+ </widget>
+ <widget class="QCheckBox" row="1" column="0">
+ <property name="name">
+ <cstring>useGlossary</cstring>
+ </property>
+ <property name="text">
+ <string>Glossary</string>
+ </property>
+ </widget>
+ <widget class="QCheckBox" row="0" column="0">
+ <property name="name">
+ <cstring>useExact</cstring>
+ </property>
+ <property name="text">
+ <string>Exact </string>
+ </property>
+ </widget>
+ <widget class="KIntSpinBox" row="4" column="2">
+ <property name="name">
+ <cstring>scoreDivide</cstring>
+ </property>
+ </widget>
+ <widget class="KIntSpinBox" row="0" column="2">
+ <property name="name">
+ <cstring>scoreExact</cstring>
+ </property>
+ </widget>
+ <widget class="KIntSpinBox" row="3" column="2">
+ <property name="name">
+ <cstring>scoreSentence</cstring>
+ </property>
+ </widget>
+ <widget class="QCheckBox" row="4" column="0">
+ <property name="name">
+ <cstring>useDivide</cstring>
+ </property>
+ <property name="text">
+ <string>Sentence by sentence</string>
+ </property>
+ </widget>
+ <widget class="QCheckBox" row="2" column="0">
+ <property name="name">
+ <cstring>useAlpha</cstring>
+ </property>
+ <property name="text">
+ <string>Alphanumeric</string>
+ </property>
+ </widget>
+ <widget class="QLabel" row="3" column="1">
+ <property name="name">
+ <cstring>textLabel3_2_3</cstring>
+ </property>
+ <property name="text">
+ <string>Score:</string>
+ </property>
+ </widget>
+ <widget class="QLabel" row="4" column="1">
+ <property name="name">
+ <cstring>textLabel3_2_4</cstring>
+ </property>
+ <property name="text">
+ <string>Score:</string>
+ </property>
+ </widget>
+ <widget class="QLabel" row="0" column="1">
+ <property name="name">
+ <cstring>textLabel3</cstring>
+ </property>
+ <property name="text">
+ <string>Score:</string>
+ </property>
+ </widget>
+ <widget class="KIntSpinBox" row="2" column="2">
+ <property name="name">
+ <cstring>scoreAlpha</cstring>
+ </property>
+ </widget>
+ <widget class="QLabel" row="6" column="1">
+ <property name="name">
+ <cstring>textLabel3_2_6</cstring>
+ </property>
+ <property name="text">
+ <string>Score:</string>
+ </property>
+ </widget>
+ <widget class="QLabel" row="5" column="1">
+ <property name="name">
+ <cstring>textLabel3_2_5</cstring>
+ </property>
+ <property name="text">
+ <string>Score:</string>
+ </property>
+ </widget>
+ <widget class="QCheckBox" row="6" column="0">
+ <property name="name">
+ <cstring>useWordByWord</cstring>
+ </property>
+ <property name="text">
+ <string>Word by word</string>
+ </property>
+ </widget>
+ <widget class="QCheckBox" row="5" column="0">
+ <property name="name">
+ <cstring>useDynamic</cstring>
+ </property>
+ <property name="text">
+ <string>Dynamic dictionary</string>
+ </property>
+ </widget>
+ <widget class="KIntSpinBox" row="5" column="2">
+ <property name="name">
+ <cstring>scoreDynamic</cstring>
+ </property>
+ </widget>
+ </grid>
+ </widget>
+ <widget class="QLabel" row="2" column="0">
+ <property name="name">
+ <cstring>textLabel4</cstring>
+ </property>
+ <property name="text">
+ <string>Preferred number of results:</string>
+ </property>
+ </widget>
+ <widget class="KIntSpinBox" row="2" column="2">
+ <property name="name">
+ <cstring>numberOfResult</cstring>
+ </property>
+ </widget>
+ <widget class="KIntSpinBox" row="3" column="2">
+ <property name="name">
+ <cstring>minScore</cstring>
+ </property>
+ </widget>
+ </grid>
+ </widget>
+ <widget class="QWidget">
+ <property name="name">
+ <cstring>tab</cstring>
+ </property>
+ <attribute name="title">
+ <string>Output</string>
+ </attribute>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QGroupBox" row="0" column="0">
+ <property name="name">
+ <cstring>groupBox4</cstring>
+ </property>
+ <property name="title">
+ <string>Output Processing</string>
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <spacer row="3" column="0">
+ <property name="name">
+ <cstring>spacer2</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="QCheckBox" row="0" column="0" rowspan="1" colspan="2">
+ <property name="name">
+ <cstring>firstCapital</cstring>
+ </property>
+ <property name="text">
+ <string>First capital letter match</string>
+ </property>
+ </widget>
+ <widget class="QCheckBox" row="1" column="0" rowspan="1" colspan="2">
+ <property name="name">
+ <cstring>allCapital</cstring>
+ </property>
+ <property name="text">
+ <string>All capital letter match</string>
+ </property>
+ </widget>
+ <widget class="QCheckBox" row="2" column="0" rowspan="1" colspan="2">
+ <property name="name">
+ <cstring>accelerator</cstring>
+ </property>
+ <property name="text">
+ <string>Accelerator symbol (&amp;&amp;)</string>
+ </property>
+ </widget>
+ <widget class="QCheckBox" row="3" column="1">
+ <property name="name">
+ <cstring>sameLetter</cstring>
+ </property>
+ <property name="text">
+ <string>Try to use same letter</string>
+ </property>
+ </widget>
+ </grid>
+ </widget>
+ <widget class="QGroupBox" row="1" column="0">
+ <property name="name">
+ <cstring>groupBox5</cstring>
+ </property>
+ <property name="title">
+ <string>Custom Rules</string>
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLabel" row="0" column="0">
+ <property name="name">
+ <cstring>textLabel1_2</cstring>
+ </property>
+ <property name="text">
+ <string>Original string regexp:</string>
+ </property>
+ </widget>
+ <widget class="KLineEdit" row="0" column="1" rowspan="1" colspan="2">
+ <property name="name">
+ <cstring>kLineEdit1_2</cstring>
+ </property>
+ </widget>
+ <widget class="QListView" row="3" column="0" rowspan="3" colspan="2">
+ <column>
+ <property name="text">
+ <string>Enabled</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>
+ <item>
+ <property name="text">
+ <string>New Item</string>
+ </property>
+ <property name="text">
+ <string></string>
+ </property>
+ <property name="pixmap">
+ <pixmap></pixmap>
+ </property>
+ <property name="pixmap">
+ <pixmap></pixmap>
+ </property>
+ </item>
+ <property name="name">
+ <cstring>customRules</cstring>
+ </property>
+ </widget>
+ <spacer row="5" column="2">
+ <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>20</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ <widget class="KPushButton" row="4" column="2">
+ <property name="name">
+ <cstring>deleteRule</cstring>
+ </property>
+ <property name="text">
+ <string>Delete</string>
+ </property>
+ </widget>
+ <widget class="QPushButton" row="3" column="2">
+ <property name="name">
+ <cstring>addRule</cstring>
+ </property>
+ <property name="text">
+ <string>Add</string>
+ </property>
+ </widget>
+ <widget class="QLabel" row="2" column="0">
+ <property name="name">
+ <cstring>textLabel3_3</cstring>
+ </property>
+ <property name="text">
+ <string>Replace string:</string>
+ </property>
+ </widget>
+ <widget class="KLineEdit" row="2" column="1" rowspan="1" colspan="2">
+ <property name="name">
+ <cstring>kLineEdit3</cstring>
+ </property>
+ </widget>
+ <widget class="KLineEdit" row="1" column="1" rowspan="1" colspan="2">
+ <property name="name">
+ <cstring>kLineEdit2</cstring>
+ </property>
+ </widget>
+ <widget class="QLabel" row="1" column="0">
+ <property name="name">
+ <cstring>textLabel2_2</cstring>
+ </property>
+ <property name="text">
+ <string>Translated regexp(search):</string>
+ </property>
+ </widget>
+ </grid>
+ </widget>
+ </grid>
+ </widget>
+ <widget class="QWidget">
+ <property name="name">
+ <cstring>tab</cstring>
+ </property>
+ <attribute name="title">
+ <string>Import</string>
+ </attribute>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QGroupBox" row="0" column="0">
+ <property name="name">
+ <cstring>groupBox6</cstring>
+ </property>
+ <property name="title">
+ <string>Options</string>
+ </property>
+ <widget class="QCheckBox">
+ <property name="name">
+ <cstring>checkLang</cstring>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>20</x>
+ <y>30</y>
+ <width>150</width>
+ <height>21</height>
+ </rect>
+ </property>
+ <property name="text">
+ <string>Check language</string>
+ </property>
+ </widget>
+ <widget class="QCheckBox">
+ <property name="name">
+ <cstring>useFilters</cstring>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>20</x>
+ <y>60</y>
+ <width>140</width>
+ <height>21</height>
+ </rect>
+ </property>
+ <property name="text">
+ <string>Use current filters</string>
+ </property>
+ </widget>
+ <widget class="QCheckBox">
+ <property name="name">
+ <cstring>dateToday</cstring>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>20</x>
+ <y>90</y>
+ <width>180</width>
+ <height>21</height>
+ </rect>
+ </property>
+ <property name="text">
+ <string>Set date to today</string>
+ </property>
+ </widget>
+ </widget>
+ <widget class="QGroupBox" row="1" column="0">
+ <property name="name">
+ <cstring>groupBox7</cstring>
+ </property>
+ <property name="title">
+ <string>Sources</string>
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QPushButton" row="1" column="1">
+ <property name="name">
+ <cstring>editSource</cstring>
+ </property>
+ <property name="text">
+ <string>Edit</string>
+ </property>
+ </widget>
+ <widget class="KPushButton" row="2" column="1">
+ <property name="name">
+ <cstring>removeSource</cstring>
+ </property>
+ <property name="text">
+ <string>Remove</string>
+ </property>
+ </widget>
+ <widget class="KPushButton" row="3" column="1">
+ <property name="name">
+ <cstring>scanSource</cstring>
+ </property>
+ <property name="text">
+ <string>Scan Now</string>
+ </property>
+ </widget>
+ <widget class="KPushButton" row="0" column="1">
+ <property name="name">
+ <cstring>addSource</cstring>
+ </property>
+ <property name="text">
+ <string>Add</string>
+ </property>
+ </widget>
+ <spacer row="4" column="1">
+ <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>40</height>
+ </size>
+ </property>
+ </spacer>
+ <widget class="KPushButton" row="5" column="1">
+ <property name="name">
+ <cstring>scanAll</cstring>
+ </property>
+ <property name="text">
+ <string>Scan All</string>
+ </property>
+ </widget>
+ <widget class="QListBox" row="0" column="0" rowspan="6" colspan="1">
+ <property name="name">
+ <cstring>sourceList</cstring>
+ </property>
+ </widget>
+ </grid>
+ </widget>
+ </grid>
+ </widget>
+ <widget class="QWidget">
+ <property name="name">
+ <cstring>tab</cstring>
+ </property>
+ <attribute name="title">
+ <string>Filters</string>
+ </attribute>
+ </widget>
+ </widget>
+ </grid>
+</widget>
+<customwidgets>
+</customwidgets>
+<layoutdefaults spacing="6" margin="11"/>
+<includehints>
+ <includehint>klineedit.h</includehint>
+ <includehint>kpushbutton.h</includehint>
+ <includehint>klineedit.h</includehint>
+ <includehint>knuminput.h</includehint>
+ <includehint>knuminput.h</includehint>
+ <includehint>knuminput.h</includehint>
+ <includehint>knuminput.h</includehint>
+ <includehint>knuminput.h</includehint>
+ <includehint>knuminput.h</includehint>
+ <includehint>knuminput.h</includehint>
+ <includehint>knuminput.h</includehint>
+ <includehint>knuminput.h</includehint>
+ <includehint>klineedit.h</includehint>
+ <includehint>kpushbutton.h</includehint>
+ <includehint>klineedit.h</includehint>
+ <includehint>klineedit.h</includehint>
+ <includehint>kpushbutton.h</includehint>
+ <includehint>kpushbutton.h</includehint>
+ <includehint>kpushbutton.h</includehint>
+ <includehint>kpushbutton.h</includehint>
+</includehints>
+</UI>
diff --git a/kbabel/kbabeldict/modules/dbsearchengine2/dbse2_factory.cpp b/kbabel/kbabeldict/modules/dbsearchengine2/dbse2_factory.cpp
new file mode 100644
index 00000000..9c286052
--- /dev/null
+++ b/kbabel/kbabeldict/modules/dbsearchengine2/dbse2_factory.cpp
@@ -0,0 +1,83 @@
+
+#include <klocale.h>
+#include <kinstance.h>
+#include <kaboutdata.h>
+#include <kdebug.h>
+
+#include "dbse2_factory.h"
+#include "KDBSearchEngine2.h"
+
+
+extern "C"
+{
+ KDE_EXPORT void *init_kbabeldict_dbsearchengine2()
+// void *init_libdbsearchengine2()
+ {
+ return new DbSe2Factory;
+ }
+};
+
+
+KInstance *DbSe2Factory::s_instance = 0;
+KAboutData *DbSe2Factory::s_about = 0;
+
+
+DbSe2Factory::DbSe2Factory( QObject *parent, const char *name)
+ : KLibFactory(parent,name)
+{
+}
+
+DbSe2Factory::~DbSe2Factory()
+{
+ if(s_instance)
+ {
+ delete s_instance;
+ s_instance=0;
+ }
+
+ if(s_about)
+ {
+ delete s_about;
+ s_about=0;
+ }
+}
+
+
+QObject *DbSe2Factory::createObject( QObject *parent, const char *name,
+ const char *classname, const QStringList &)
+{
+ if(QCString(classname) != "SearchEngine")
+ {
+ kdError() << "not a SearchEngine requested" << endl;
+ return 0;
+ }
+
+ KDBSearchEngine2 *se = new KDBSearchEngine2(parent,name);
+
+ emit objectCreated(se);
+ return se;
+}
+
+
+KInstance *DbSe2Factory::instance()
+{
+ if(!s_instance)
+ {
+
+ s_about = new KAboutData( "kdbsearchengine2",
+ I18N_NOOP("Translation Database")
+ , "1.99" ,
+I18N_NOOP("A fast translation search engine based on databases")
+ , KAboutData::License_GPL
+ , I18N_NOOP("Copyright 2000-2003 by Andrea Rizzi")
+ ,0,0, "rizzi@kde.org");
+
+ s_about->addAuthor("Andrea Rizzi",0,"rizzi@kde.org");
+
+ s_instance = new KInstance(s_about);
+ }
+
+ return s_instance;
+}
+
+#include "dbse2_factory.moc"
diff --git a/kbabel/kbabeldict/modules/dbsearchengine2/dbse2_factory.h b/kbabel/kbabeldict/modules/dbsearchengine2/dbse2_factory.h
new file mode 100644
index 00000000..4285d53c
--- /dev/null
+++ b/kbabel/kbabeldict/modules/dbsearchengine2/dbse2_factory.h
@@ -0,0 +1,26 @@
+#ifndef DBSE2_FACTORY_H
+#define DBSE2_FACTORY_H
+
+#include <klibloader.h>
+class KInstance;
+class KAboutData;
+
+class DbSe2Factory : public KLibFactory
+{
+ Q_OBJECT
+public:
+ DbSe2Factory( QObject *parent=0, const char *name=0);
+ ~DbSe2Factory();
+
+ virtual QObject *createObject( QObject *parent=0, const char *name=0,
+ const char *classname="QObject",
+ const QStringList &args = QStringList());
+
+ static KInstance *instance();
+
+private:
+ static KInstance *s_instance;
+ static KAboutData *s_about;
+};
+
+#endif
diff --git a/kbabel/kbabeldict/modules/dbsearchengine2/dbsearchengine2.desktop b/kbabel/kbabeldict/modules/dbsearchengine2/dbsearchengine2.desktop
new file mode 100644
index 00000000..a46bfff1
--- /dev/null
+++ b/kbabel/kbabeldict/modules/dbsearchengine2/dbsearchengine2.desktop
@@ -0,0 +1,52 @@
+[Desktop Entry]
+Type=Service
+Name=Translation Database v2 for KBabelDict
+Name[bg]=БД Ñ Ð¿Ñ€ÐµÐ²Ð¾Ð´Ð¸ v2 за KBabelDict
+Name[br]=Stlennvon geriaoueg v2 evit KBabelDict
+Name[bs]=Baza prijevoda v2 za KBabelDict
+Name[ca]=Base de dades de traducció v2 per a KBabelDict
+Name[cs]=Databáze překladů v2 pro KBabelDict
+Name[cy]=Cronfa ddata Cyfieithiadau v2 i KBabelDict
+Name[da]=Oversættelsesdatabase v2 for KBabelDict
+Name[de]=Übersetzungsdatenbank Version 2 für KBabelDict
+Name[el]=Βάση δεδομένων μετάφÏασης έκδοση 2 για το KBabelDict
+Name[es]=Base de datos de traducciones v2 para KBabelDict
+Name[et]=KBabelDicti tõlgete andmebaas (versioon 2)
+Name[eu]=v2 itzulpen datu-basea KBabelDict-entzat
+Name[fa]=دادگان ترجمۀ نسخه ۲ برای KBabelDict
+Name[fi]=KBabelDict-ohjelman käännöstietokanta v2
+Name[fr]=Base de données des traductions v2 pour KBabelDict
+Name[ga]=Cuimhne Aistriúcháin (v2) le haghaidh KBabelDict
+Name[gl]=Base de datos de traducións v2 de KBabelDict
+Name[hi]=के-बेबल-डिकà¥à¤¶ के लिठअनà¥à¤µà¤¾à¤¦ डाटाबेस वी2
+Name[hu]=Fordítási adatbázis (v2) a KBabelDicthez
+Name[is]=Þýðingagagnagrunnur v2 fyrir KBabel orðabókina
+Name[it]=Banca dati delle traduzioni v2 per KBabelDict
+Name[ja]=KBabelDict トランザクションデータベース v2
+Name[ka]=თáƒáƒ áƒ’მნის მáƒáƒœáƒáƒªáƒ”მთრბáƒáƒ–რვ2 KBabelDict-სთვის
+Name[kk]=KBabelDict-Ñ‚Ñ‹Ò£ аударма деректер қорының 2-нұÑқаÑÑ‹
+Name[lt]=KBabelDict vertimų duomenų bazės 2 versija
+Name[ms]=Pangkalan Data Penterjemahan v2 KBabelDict
+Name[nb]=Oversettelsesdatabase versjon 2 for KBabelDict
+Name[nds]=Översettendatenbank V2 för KBabelDict
+Name[ne]=KBabelDict का लागि अनà¥à¤¬à¤¾à¤¦ डाटाबेस v2
+Name[nl]=Vertalingendatabase versie2 voor KBabelDict
+Name[nn]=Omsetjingsdatabase versjon 2 for KBabelDict
+Name[pa]=ਕੇਬਬੇਲ-ਸ਼ਬਦ-ਕੋਸ਼ ਲਈ ਅਨà©à¨µà¨¾à¨¦ ਡਾਟਾਬੇਸ ਵਰਜਨ2
+Name[pl]=Baza tłumaczeń v2 dla KBabelDict
+Name[pt]=Base de Dados de Traduções v2 do KBabelDict
+Name[pt_BR]=Banco de Dados de Traduções v2 para o KBabelDict
+Name[ru]=ВерÑÐ¸Ñ 2 базы данных перевода Ð´Ð»Ñ KBabelDict
+Name[sk]=Databáza prekladov v2 pre KBabelDict
+Name[sl]=Zbirka prevodov razliÄice 2 za KBabelDict
+Name[sr]=Преводилачка база података v2 за KBabelDict
+Name[sr@Latn]=PrevodilaÄka baza podataka v2 za KBabelDict
+Name[sv]=Översättningsdatabas version 2 för Kbabeldict
+Name[ta]= Kபாபேலà¯à®•à¯à®•à®¾à®© மொழிபெயரà¯à®ªà¯à®ªà¯ தரவà¯à®¤à¯à®¤à®³à®®à¯ v2
+Name[tg]=ТафÑири 2 базаи маълумоти тарҷумаҳо барои KBabelDict
+Name[tr]=KBabelDict için Çeviri Veritabanı v2
+Name[uk]=ВерÑÑ–Ñ 2 бази даних перекладів Ð´Ð»Ñ KBabelDict
+Name[zh_CN]=KBabelDict 的翻译数æ®åº“ v2
+Name[zh_TW]=KBabelDict 翻譯資料庫 v2
+X-KDE-Library=kbabeldict_dbsearchengine2
+ServiceTypes=KBabelDictModule
diff --git a/kbabel/kbabeldict/modules/dbsearchengine2/dbseprefwidget.ui b/kbabel/kbabeldict/modules/dbsearchengine2/dbseprefwidget.ui
new file mode 100644
index 00000000..c233265f
--- /dev/null
+++ b/kbabel/kbabeldict/modules/dbsearchengine2/dbseprefwidget.ui
@@ -0,0 +1,1039 @@
+<!DOCTYPE UI><UI version="3.0" stdsetdef="1">
+<class>DBSearchEnginePref</class>
+<author>Andrea Rizzi &lt;rizzi@kde.org&gt;</author>
+<widget class="QWidget">
+ <property name="name">
+ <cstring>DBSEPrefWidget</cstring>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>414</width>
+ <height>426</height>
+ </rect>
+ </property>
+ <property name="caption">
+ <string>DBSEPrefWidget</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="QTabWidget" row="0" column="0">
+ <property name="name">
+ <cstring>TabWidget6</cstring>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string></string>
+ </property>
+ <widget class="QWidget">
+ <property name="name">
+ <cstring>Widget4</cstring>
+ </property>
+ <attribute name="title">
+ <string>Generic</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="QButtonGroup">
+ <property name="name">
+ <cstring>ButtonGroup2</cstring>
+ </property>
+ <property name="title">
+ <string>Search Mode</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="QRadioButton" row="0" column="0">
+ <property name="name">
+ <cstring>allRB</cstring>
+ </property>
+ <property name="text">
+ <string>Search in whole database (slow)</string>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>&lt;qml&gt;Scroll the whole database and return everything that matches
+according to the rules defined in tabs &lt;strong&gt; Generic &lt;/strong&gt;
+and &lt;strong&gt;Match&lt;/strong&gt;</string>
+ </property>
+ </widget>
+ <widget class="QRadioButton" row="1" column="0">
+ <property name="name">
+ <cstring>slistRB</cstring>
+ </property>
+ <property name="text">
+ <string>Search in list of "good keys" (best)</string>
+ </property>
+ <property name="checked">
+ <bool>true</bool>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>&lt;qml&gt;Search in a list of &lt;em&gt;good keys&lt;/em&gt; (see &lt;strong&gt;Good keys&lt;/strong&gt; tab) with rules defined in &lt;strong&gt;Search&lt;/strong&gt; tab.
+This is the best way to search because the &lt;em&gt;good keys&lt;/em&gt; list probably contains all the keys that match with your query. However, it is smaller than the whole database.</string>
+ </property>
+ </widget>
+ <widget class="QRadioButton" row="2" column="0">
+ <property name="name">
+ <cstring>rlistRB</cstring>
+ </property>
+ <property name="text">
+ <string>Return the list of "good keys" (fast)</string>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>&lt;qml&gt;Returns the whole &lt;em&gt;good keys&lt;/em&gt; list. Rules defined in &lt;strong&gt;Search&lt;/strong&gt; tab are ignored.</string>
+ </property>
+ </widget>
+ </grid>
+ </widget>
+ <widget class="QCheckBox">
+ <property name="name">
+ <cstring>caseSensitiveCB</cstring>
+ </property>
+ <property name="text">
+ <string>Case sensitive</string>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>&lt;qml&gt;If it is checked the search will be case sensitive. It is ignored if you use &lt;em&gt;Return the list of "good keys"&lt;/em&gt; search mode.</string>
+ </property>
+ </widget>
+ <widget class="QCheckBox">
+ <property name="name">
+ <cstring>normalizeCB</cstring>
+ </property>
+ <property name="text">
+ <string>Normalize white space</string>
+ </property>
+ <property name="checked">
+ <bool>true</bool>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>Remove white spaces at the beginning and at the end of the phrase.
+It also substitutes groups of more than one space character with only one space character.</string>
+ </property>
+ </widget>
+ <widget class="QCheckBox">
+ <property name="name">
+ <cstring>removeContextCB</cstring>
+ </property>
+ <property name="text">
+ <string>Remove context comment</string>
+ </property>
+ <property name="checked">
+ <bool>true</bool>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>Remove, if exists, the _:comment</string>
+ </property>
+ </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>TextLabel3</cstring>
+ </property>
+ <property name="text">
+ <string>Character to be ignored:</string>
+ </property>
+ </widget>
+ <widget class="KLineEdit">
+ <property name="name">
+ <cstring>ignoreLE</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>7</hsizetype>
+ <vsizetype>5</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="minimumSize">
+ <size>
+ <width>0</width>
+ <height>20</height>
+ </size>
+ </property>
+ </widget>
+ </hbox>
+ </widget>
+ <spacer>
+ <property name="name">
+ <cstring>Spacer1</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Vertical</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ </spacer>
+ </vbox>
+ </widget>
+ <widget class="QWidget">
+ <property name="name">
+ <cstring>Widget5</cstring>
+ </property>
+ <attribute name="title">
+ <string>Search</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="QButtonGroup">
+ <property name="name">
+ <cstring>ButtonGroup1</cstring>
+ </property>
+ <property name="title">
+ <string>Matching Method</string>
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>11</number>
+ </property>
+ <property name="spacing">
+ <number>6</number>
+ </property>
+ <spacer row="1" column="0">
+ <property name="name">
+ <cstring>Spacer4</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>
+ <spacer row="2" column="0">
+ <property name="name">
+ <cstring>Spacer6</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="QCheckBox" row="2" column="1">
+ <property name="name">
+ <cstring>containedCB</cstring>
+ </property>
+ <property name="text">
+ <string>Query is contained</string>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>Match if query is contained in database string</string>
+ </property>
+ </widget>
+ <widget class="QCheckBox" row="3" column="1">
+ <property name="name">
+ <cstring>containsCB</cstring>
+ </property>
+ <property name="text">
+ <string>Query contains</string>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>Match if query contains the database string</string>
+ </property>
+ </widget>
+ <widget class="QRadioButton" row="0" column="0" rowspan="1" colspan="2">
+ <property name="name">
+ <cstring>normalTextRB</cstring>
+ </property>
+ <property name="text">
+ <string>Normal text</string>
+ </property>
+ <property name="checked">
+ <bool>true</bool>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>Consider the search string as normal text.</string>
+ </property>
+ </widget>
+ <widget class="QCheckBox" row="1" column="1">
+ <property name="name">
+ <cstring>equalCB</cstring>
+ </property>
+ <property name="text">
+ <string>Equal</string>
+ </property>
+ <property name="checked">
+ <bool>true</bool>
+ </property>
+ <property name="tristate">
+ <bool>false</bool>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>Match if query and database string are equal</string>
+ </property>
+ </widget>
+ <spacer row="3" column="0">
+ <property name="name">
+ <cstring>Spacer7</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="QRadioButton" row="4" column="0" rowspan="1" colspan="2">
+ <property name="name">
+ <cstring>RegExpRB</cstring>
+ </property>
+ <property name="text">
+ <string>Regular expression</string>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>Consider the search string as a regular expression</string>
+ </property>
+ </widget>
+ </grid>
+ </widget>
+ <widget class="QGroupBox">
+ <property name="name">
+ <cstring>GroupBox3</cstring>
+ </property>
+ <property name="title">
+ <string>Word Substitution</string>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>&lt;qml&gt;If you use one or two &lt;em&gt;word substitution&lt;/em&gt; each time you search a phrase with less than the specified number of words, the search engine will also search for all phrases that differ from the original one in one or two words.&lt;p&gt;
+&lt;strong&gt;Example:&lt;/strong&gt;&lt;br&gt;
+If you search for &lt;em&gt;My name is Andrea&lt;/em&gt; and you have activated &lt;em&gt;one word substitution&lt;/em&gt; you may also find phrases like &lt;em&gt;My name is Joe&lt;/em&gt; or &lt;em&gt;Your name is Andrea&lt;/em&gt;.</string>
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>11</number>
+ </property>
+ <property name="spacing">
+ <number>6</number>
+ </property>
+ <spacer row="3" column="0">
+ <property name="name">
+ <cstring>Spacer8</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="QCheckBox" row="0" column="0" rowspan="1" colspan="3">
+ <property name="name">
+ <cstring>oneWordSubCB</cstring>
+ </property>
+ <property name="text">
+ <string>Use one word substitution</string>
+ </property>
+ <property name="checked">
+ <bool>true</bool>
+ </property>
+ <property name="tristate">
+ <bool>false</bool>
+ </property>
+ </widget>
+ <spacer row="1" column="0">
+ <property name="name">
+ <cstring>Spacer9</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" row="1" column="1">
+ <property name="name">
+ <cstring>TextLabel1</cstring>
+ </property>
+ <property name="text">
+ <string>Max number of words in the query:</string>
+ </property>
+ </widget>
+ <widget class="QSpinBox" row="3" column="2">
+ <property name="name">
+ <cstring>twoWordSubSB</cstring>
+ </property>
+ <property name="enabled">
+ <bool>false</bool>
+ </property>
+ <property name="maxValue">
+ <number>14</number>
+ </property>
+ <property name="value">
+ <number>10</number>
+ </property>
+ </widget>
+ <widget class="QCheckBox" row="2" column="0" rowspan="1" colspan="2">
+ <property name="name">
+ <cstring>twoWordSubCB</cstring>
+ </property>
+ <property name="enabled">
+ <bool>false</bool>
+ </property>
+ <property name="text">
+ <string>Use two word substitution</string>
+ </property>
+ <property name="checked">
+ <bool>true</bool>
+ </property>
+ </widget>
+ <widget class="QLabel" row="3" column="1">
+ <property name="name">
+ <cstring>TextLabel2</cstring>
+ </property>
+ <property name="text">
+ <string>Max number of words in the query:</string>
+ </property>
+ </widget>
+ <widget class="QLayoutWidget" row="5" column="0" rowspan="1" colspan="3">
+ <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>TextLabel5_3</cstring>
+ </property>
+ <property name="text">
+ <string>[A-Za-z0-9_%</string>
+ </property>
+ <property name="alignment">
+ <set>AlignVCenter|AlignRight</set>
+ </property>
+ <property name="hAlign" stdset="0">
+ </property>
+ </widget>
+ <widget class="KLineEdit">
+ <property name="name">
+ <cstring>regExpLE</cstring>
+ </property>
+ </widget>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>TextLabel6_2</cstring>
+ </property>
+ <property name="text">
+ <string>]</string>
+ </property>
+ </widget>
+ </hbox>
+ </widget>
+ <widget class="QLabel" row="4" column="0" rowspan="1" colspan="3">
+ <property name="name">
+ <cstring>TextLabel4</cstring>
+ </property>
+ <property name="text">
+ <string>Local characters for regular expressions:</string>
+ </property>
+ </widget>
+ <widget class="QSpinBox" row="1" column="2">
+ <property name="name">
+ <cstring>oneWordSubSB</cstring>
+ </property>
+ <property name="maxValue">
+ <number>200</number>
+ </property>
+ <property name="minValue">
+ <number>2</number>
+ </property>
+ <property name="value">
+ <number>40</number>
+ </property>
+ </widget>
+ </grid>
+ </widget>
+ <spacer>
+ <property name="name">
+ <cstring>Spacer1_2</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Vertical</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ </spacer>
+ </vbox>
+ </widget>
+ <widget class="QWidget">
+ <property name="name">
+ <cstring>Widget6</cstring>
+ </property>
+ <attribute name="title">
+ <string>Database</string>
+ </attribute>
+ <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" rowspan="1" colspan="3">
+ <property name="name">
+ <cstring>TextLabel7_2</cstring>
+ </property>
+ <property name="text">
+ <string>Database folder:</string>
+ </property>
+ </widget>
+ <widget class="KURLRequester" row="1" column="0" rowspan="1" colspan="3">
+ <property name="name">
+ <cstring>dirInput</cstring>
+ </property>
+ </widget>
+ <widget class="QCheckBox" row="2" column="0" rowspan="1" colspan="3">
+ <property name="name">
+ <cstring>autoAddCB_2</cstring>
+ </property>
+ <property name="enabled">
+ <bool>true</bool>
+ </property>
+ <property name="text">
+ <string>Auto add entry to database</string>
+ </property>
+ <property name="checked">
+ <bool>true</bool>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>Automatically add an entry to the database if a new translation is notified by someone (may be kbabel)</string>
+ </property>
+ </widget>
+ <widget class="QLayoutWidget" row="3" column="0" rowspan="1" colspan="3">
+ <property name="name">
+ <cstring>Layout3</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>Auto added entry author:</string>
+ </property>
+ </widget>
+ <widget class="QLineEdit">
+ <property name="name">
+ <cstring>authorLE</cstring>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>&lt;qml&gt;Put here the name and email address that you want to use as &lt;em&gt;last translator&lt;/em&gt; filed when you auto-add entry to the database (e.g. when you modify a translation with kbabel).&lt;p&gt;</string>
+ </property>
+ </widget>
+ </hbox>
+ </widget>
+ <widget class="QPushButton" row="4" column="0" rowspan="1" colspan="3">
+ <property name="name">
+ <cstring>scanFilePB</cstring>
+ </property>
+ <property name="text">
+ <string>Scan Single PO File</string>
+ </property>
+ </widget>
+ <widget class="QPushButton" row="5" column="0" rowspan="1" colspan="3">
+ <property name="name">
+ <cstring>scanPB_2</cstring>
+ </property>
+ <property name="text">
+ <string>Scan Folder</string>
+ </property>
+ </widget>
+ <widget class="QPushButton" row="6" column="0" rowspan="1" colspan="3">
+ <property name="name">
+ <cstring>scanrecPB</cstring>
+ </property>
+ <property name="text">
+ <string>Scan Folder &amp;&amp; Subfolders</string>
+ </property>
+ </widget>
+ <widget class="QLayoutWidget" row="8" column="0" rowspan="1" colspan="3">
+ <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>filenameLB</cstring>
+ </property>
+ <property name="text">
+ <string>Scanning file:</string>
+ </property>
+ </widget>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>entriesLB</cstring>
+ </property>
+ <property name="text">
+ <string>Entries added:</string>
+ </property>
+ </widget>
+ </vbox>
+ </widget>
+ <widget class="QLayoutWidget" row="9" column="0" rowspan="1" colspan="3">
+ <property name="name">
+ <cstring>Layout4</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="QProgressBar" row="2" column="1">
+ <property name="name">
+ <cstring>processPB</cstring>
+ </property>
+ <property name="frameShape">
+ <enum>Panel</enum>
+ </property>
+ <property name="frameShadow">
+ <enum>Sunken</enum>
+ </property>
+ <property name="centerIndicator">
+ <bool>true</bool>
+ </property>
+ <property name="indicatorFollowsStyle">
+ <bool>false</bool>
+ </property>
+ </widget>
+ <widget class="QLabel" row="0" column="0">
+ <property name="name">
+ <cstring>TextLabel1_3</cstring>
+ </property>
+ <property name="text">
+ <string>Total progress:</string>
+ </property>
+ </widget>
+ <widget class="QLabel" row="2" column="0">
+ <property name="name">
+ <cstring>TextLabel3_3</cstring>
+ </property>
+ <property name="text">
+ <string>Processing file:</string>
+ </property>
+ </widget>
+ <widget class="QProgressBar" row="0" column="1">
+ <property name="name">
+ <cstring>totalPB</cstring>
+ </property>
+ <property name="frameShape">
+ <enum>Panel</enum>
+ </property>
+ <property name="frameShadow">
+ <enum>Sunken</enum>
+ </property>
+ <property name="centerIndicator">
+ <bool>true</bool>
+ </property>
+ </widget>
+ <widget class="QProgressBar" row="1" column="1">
+ <property name="name">
+ <cstring>loadingPB</cstring>
+ </property>
+ <property name="frameShape">
+ <enum>Panel</enum>
+ </property>
+ <property name="frameShadow">
+ <enum>Sunken</enum>
+ </property>
+ <property name="centerIndicator">
+ <bool>true</bool>
+ </property>
+ </widget>
+ <widget class="QLabel" row="1" column="0">
+ <property name="name">
+ <cstring>TextLabel2_3</cstring>
+ </property>
+ <property name="text">
+ <string>Loading file:</string>
+ </property>
+ </widget>
+ </grid>
+ </widget>
+ <widget class="QPushButton" row="10" column="2">
+ <property name="name">
+ <cstring>exportPB</cstring>
+ </property>
+ <property name="enabled">
+ <bool>false</bool>
+ </property>
+ <property name="text">
+ <string>Export...</string>
+ </property>
+ </widget>
+ <widget class="QPushButton" row="10" column="0">
+ <property name="name">
+ <cstring>statPB</cstring>
+ </property>
+ <property name="enabled">
+ <bool>false</bool>
+ </property>
+ <property name="text">
+ <string>Statistics</string>
+ </property>
+ </widget>
+ <widget class="QPushButton" row="10" column="1">
+ <property name="name">
+ <cstring>repeatPB</cstring>
+ </property>
+ <property name="text">
+ <string>Repeated Strings</string>
+ </property>
+ </widget>
+ </grid>
+ </widget>
+ <widget class="QWidget">
+ <property name="name">
+ <cstring>tab</cstring>
+ </property>
+ <attribute name="title">
+ <string>Good Keys</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="QGroupBox">
+ <property name="name">
+ <cstring>GroupBox4</cstring>
+ </property>
+ <property name="title">
+ <string>Generic</string>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>&lt;qml&gt;Here you can define how to fill the &lt;em&gt;good keys list&lt;/em&gt;.&lt;p&gt;
+You can set the minimum number of words of the query that a key must have to be inserted in the &lt;em&gt;good keys list&lt;/em&gt;.&lt;p&gt;
+You can also set the minimum number of words of the key that the query must have to insert the key in the list.&lt;p&gt;
+These two numbers are the percentage of the total number of words. If the result of this percentage is less than one, the engine will set it to one.&lt;p&gt;
+Finally you can set the maximum number of entries in the list.</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="2" column="0" rowspan="1" colspan="2">
+ <property name="name">
+ <cstring>TextLabel3_2</cstring>
+ </property>
+ <property name="text">
+ <string>Minimum number of words of the key also in the query (%):</string>
+ </property>
+ <property name="textFormat">
+ <enum>RichText</enum>
+ </property>
+ </widget>
+ <widget class="QSlider" row="1" column="0">
+ <property name="name">
+ <cstring>thresholdSL</cstring>
+ </property>
+ <property name="maxValue">
+ <number>100</number>
+ </property>
+ <property name="value">
+ <number>50</number>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ </widget>
+ <widget class="QSpinBox" row="1" column="1">
+ <property name="name">
+ <cstring>SpinBox5</cstring>
+ </property>
+ <property name="suffix">
+ <string>%</string>
+ </property>
+ <property name="maxValue">
+ <number>100</number>
+ </property>
+ <property name="value">
+ <number>50</number>
+ </property>
+ </widget>
+ <widget class="QLabel" row="0" column="0" rowspan="1" colspan="2">
+ <property name="name">
+ <cstring>TextLabel2_2</cstring>
+ </property>
+ <property name="text">
+ <string>Minimum number of query words in the key (%):</string>
+ </property>
+ </widget>
+ <widget class="QSpinBox" row="4" column="1">
+ <property name="name">
+ <cstring>maxSB</cstring>
+ </property>
+ <property name="maxValue">
+ <number>5000</number>
+ </property>
+ <property name="value">
+ <number>30</number>
+ </property>
+ </widget>
+ <widget class="QSpinBox" row="3" column="1">
+ <property name="name">
+ <cstring>SpinBox6</cstring>
+ </property>
+ <property name="suffix">
+ <string>%</string>
+ </property>
+ <property name="maxValue">
+ <number>100</number>
+ </property>
+ <property name="value">
+ <number>50</number>
+ </property>
+ </widget>
+ <widget class="QLabel" row="4" column="0">
+ <property name="name">
+ <cstring>TextLabel4_2</cstring>
+ </property>
+ <property name="text">
+ <string>Max list length:</string>
+ </property>
+ </widget>
+ <widget class="QSlider" row="3" column="0">
+ <property name="name">
+ <cstring>thresholdOrigSL</cstring>
+ </property>
+ <property name="maxValue">
+ <number>100</number>
+ </property>
+ <property name="value">
+ <number>50</number>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ </widget>
+ </grid>
+ </widget>
+ <widget class="QGroupBox">
+ <property name="name">
+ <cstring>GroupBox3_2</cstring>
+ </property>
+ <property name="title">
+ <string>Frequent Words</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_2</cstring>
+ </property>
+ <property name="text">
+ <string>Discard words more frequent than:</string>
+ </property>
+ </widget>
+ <widget class="QSpinBox" row="0" column="1">
+ <property name="name">
+ <cstring>freqSB</cstring>
+ </property>
+ <property name="suffix">
+ <string>/10000</string>
+ </property>
+ <property name="maxValue">
+ <number>10000</number>
+ </property>
+ <property name="lineStep">
+ <number>1</number>
+ </property>
+ <property name="value">
+ <number>100</number>
+ </property>
+ </widget>
+ <widget class="QCheckBox" row="1" column="0" rowspan="1" colspan="2">
+ <property name="name">
+ <cstring>nothingCB</cstring>
+ </property>
+ <property name="text">
+ <string>Frequent words are considered as in every key</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>
+ </spacer>
+ </vbox>
+ </widget>
+ </widget>
+ </grid>
+</widget>
+<connections>
+ <connection>
+ <sender>thresholdSL</sender>
+ <signal>valueChanged(int)</signal>
+ <receiver>SpinBox5</receiver>
+ <slot>setValue(int)</slot>
+ </connection>
+ <connection>
+ <sender>thresholdOrigSL</sender>
+ <signal>valueChanged(int)</signal>
+ <receiver>SpinBox6</receiver>
+ <slot>setValue(int)</slot>
+ </connection>
+ <connection>
+ <sender>SpinBox5</sender>
+ <signal>valueChanged(int)</signal>
+ <receiver>thresholdSL</receiver>
+ <slot>setValue(int)</slot>
+ </connection>
+ <connection>
+ <sender>SpinBox6</sender>
+ <signal>valueChanged(int)</signal>
+ <receiver>thresholdOrigSL</receiver>
+ <slot>setValue(int)</slot>
+ </connection>
+</connections>
+<includes>
+ <include location="local" impldecl="in declaration">klocale.h</include>
+ <include location="global" impldecl="in declaration">kseparator.h</include>
+</includes>
+<layoutdefaults spacing="6" margin="11"/>
+</UI>
diff --git a/kbabel/kbabeldict/modules/dbsearchengine2/preferenceswidget.cpp b/kbabel/kbabeldict/modules/dbsearchengine2/preferenceswidget.cpp
new file mode 100644
index 00000000..7634a799
--- /dev/null
+++ b/kbabel/kbabeldict/modules/dbsearchengine2/preferenceswidget.cpp
@@ -0,0 +1,98 @@
+#include <qradiobutton.h>
+#include <qslider.h>
+#include <qspinbox.h>
+#include <qcheckbox.h>
+#include <qlabel.h>
+#include <qlayout.h>
+#include <klocale.h>
+#include <kfiledialog.h>
+#include <kurlrequester.h>
+#include <qtoolbutton.h>
+#include <klineedit.h>
+#include <kstandarddirs.h>
+#include <knuminput.h>
+
+#include "dbse2.h"
+#include "preferenceswidget.h"
+
+KDB2PreferencesWidget::KDB2PreferencesWidget(QWidget *parent, const char* name)
+ : PrefWidget(parent,name)
+{
+ QVBoxLayout *layout = new QVBoxLayout(this);
+// QLabel *label = new QLabel(i18n("Settings for KDE Database Search Engine"),this);
+// layout->addWidget(label);
+
+ dbpw = new DBSearchEnginePrefWidget(this);
+ dbpw->dbDirectory->setMode(KFile::Directory | KFile::LocalOnly);
+ dbpw->show();
+ layout->addWidget(dbpw);
+ setMinimumSize(300,300);
+
+ standard();
+
+// connect(dbpw->browseTB_3,SIGNAL(clicked()),SLOT(browse1()));
+
+ emit restoreNow(); //Fill with actual params.
+
+}
+
+KDB2PreferencesWidget::~KDB2PreferencesWidget()
+{
+}
+
+void KDB2PreferencesWidget::apply()
+{
+emit applyNow();
+}
+
+void KDB2PreferencesWidget::cancel()
+{
+emit restoreNow();
+}
+
+void KDB2PreferencesWidget::standard()
+{
+QString defaultDir;
+ KStandardDirs * dirs = KGlobal::dirs();
+ if(dirs)
+ {
+ defaultDir = dirs->saveLocation("data");
+ if(defaultDir.right(1)!="/")
+ defaultDir+="/";
+ defaultDir += "kbabeldict/dbsearchengine2";
+ }
+dbpw->dbDirectory->setURL(defaultDir);
+
+dbpw->autoUpdate->setChecked(true);
+
+dbpw->useSentence->setChecked(true);
+dbpw->useGlossary->setChecked(true);
+dbpw->useExact->setChecked(true);
+dbpw->useDivide->setChecked(true);
+dbpw->useAlpha->setChecked(true);
+dbpw->useWordByWord->setChecked(true);
+dbpw->useDynamic->setChecked(true);
+dbpw->scoreDivide->setValue(90);
+dbpw->scoreExact->setValue(100);
+dbpw->scoreSentence->setValue(90);
+dbpw->scoreWordByWord->setValue(70);
+dbpw->scoreGlossary->setValue(98);
+dbpw->scoreAlpha->setValue(98);
+dbpw->scoreDynamic->setValue(80);
+
+dbpw->numberOfResult->setValue(5);
+dbpw->minScore->setValue(60);
+
+dbpw->firstCapital->setChecked(true);
+dbpw->allCapital->setChecked(false);
+dbpw->accelerator->setChecked(true);
+dbpw->sameLetter->setChecked(true);
+dbpw->checkLang->setChecked(true);
+dbpw->useFilters->setChecked(false);
+dbpw->dateToday->setChecked(false);
+/*
+ */
+ //dbpw->dirInput->setURL(defaultDir);
+}
+
+#include "preferenceswidget.moc"
diff --git a/kbabel/kbabeldict/modules/dbsearchengine2/preferenceswidget.h b/kbabel/kbabeldict/modules/dbsearchengine2/preferenceswidget.h
new file mode 100644
index 00000000..4714fd13
--- /dev/null
+++ b/kbabel/kbabeldict/modules/dbsearchengine2/preferenceswidget.h
@@ -0,0 +1,26 @@
+#ifndef PREFERENCESWIDGET_H
+#define PREFERENCESWIDGET_H
+
+#include "searchengine.h"
+#include "dbse2.h"
+
+class KDB2PreferencesWidget : public PrefWidget
+{
+ Q_OBJECT
+
+public:
+ KDB2PreferencesWidget(QWidget *parent=0, const char* name=0);
+ virtual ~KDB2PreferencesWidget();
+
+ virtual void apply();
+ virtual void cancel();
+ virtual void standard();
+ DBSearchEnginePrefWidget *dbpw;
+
+signals:
+ void applyNow();
+ void restoreNow();
+
+};
+
+#endif
diff --git a/kbabel/kbabeldict/modules/dbsearchengine2/sourcedialog.ui b/kbabel/kbabeldict/modules/dbsearchengine2/sourcedialog.ui
new file mode 100644
index 00000000..3f4030a0
--- /dev/null
+++ b/kbabel/kbabeldict/modules/dbsearchengine2/sourcedialog.ui
@@ -0,0 +1,266 @@
+<!DOCTYPE UI><UI version="3.2" stdsetdef="1">
+<class>SourceDialog</class>
+<widget class="QDialog">
+ <property name="name">
+ <cstring>SourceDialog</cstring>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>415</width>
+ <height>385</height>
+ </rect>
+ </property>
+ <property name="caption">
+ <string>Edit Source</string>
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <spacer row="2" 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>40</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ <widget class="KPushButton" row="2" column="0">
+ <property name="name">
+ <cstring>ok</cstring>
+ </property>
+ <property name="text">
+ <string>&amp;OK</string>
+ </property>
+ </widget>
+ <widget class="KPushButton" row="2" column="2">
+ <property name="name">
+ <cstring>cancel</cstring>
+ </property>
+ <property name="text">
+ <string>&amp;Cancel</string>
+ </property>
+ </widget>
+ <widget class="QGroupBox" row="1" column="0" rowspan="1" colspan="3">
+ <property name="name">
+ <cstring>groupBox1</cstring>
+ </property>
+ <property name="title">
+ <string>Additional Informations</string>
+ </property>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>textLabel6</cstring>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>11</x>
+ <y>76</y>
+ <width>108</width>
+ <height>29</height>
+ </rect>
+ </property>
+ <property name="text">
+ <string>Status: </string>
+ </property>
+ </widget>
+ <widget class="KLineEdit">
+ <property name="name">
+ <cstring>projectName</cstring>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>125</x>
+ <y>22</y>
+ <width>182</width>
+ <height>21</height>
+ </rect>
+ </property>
+ </widget>
+ <widget class="KLineEdit">
+ <property name="name">
+ <cstring>projectKeywords</cstring>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>125</x>
+ <y>49</y>
+ <width>182</width>
+ <height>21</height>
+ </rect>
+ </property>
+ </widget>
+ <widget class="KComboBox">
+ <property name="name">
+ <cstring>status</cstring>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>125</x>
+ <y>76</y>
+ <width>182</width>
+ <height>29</height>
+ </rect>
+ </property>
+ <property name="editable">
+ <bool>true</bool>
+ </property>
+ </widget>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>textLabel4</cstring>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>11</x>
+ <y>22</y>
+ <width>108</width>
+ <height>21</height>
+ </rect>
+ </property>
+ <property name="text">
+ <string>Project name:</string>
+ </property>
+ </widget>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>textLabel5</cstring>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>11</x>
+ <y>49</y>
+ <width>108</width>
+ <height>21</height>
+ </rect>
+ </property>
+ <property name="text">
+ <string>Project keywords:</string>
+ </property>
+ </widget>
+ </widget>
+ <widget class="QGroupBox" row="0" column="0" rowspan="1" colspan="3">
+ <property name="name">
+ <cstring>groupBox2</cstring>
+ </property>
+ <property name="title">
+ <string>General Info</string>
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="KLineEdit" row="0" column="1">
+ <property name="name">
+ <cstring>sourceName</cstring>
+ </property>
+ </widget>
+ <widget class="KComboBox" row="1" column="1">
+ <item>
+ <property name="text">
+ <string>Single File</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>Single Folder</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>Recursive Folder</string>
+ </property>
+ </item>
+ <property name="name">
+ <cstring>type</cstring>
+ </property>
+ </widget>
+ <widget class="QLabel" row="0" column="0">
+ <property name="name">
+ <cstring>textLabel1</cstring>
+ </property>
+ <property name="text">
+ <string>Source name:</string>
+ </property>
+ </widget>
+ <widget class="KURLRequester" row="2" column="1">
+ <property name="name">
+ <cstring>sourceLocation</cstring>
+ </property>
+ </widget>
+ <widget class="QLabel" row="1" column="0">
+ <property name="name">
+ <cstring>textLabel3</cstring>
+ </property>
+ <property name="text">
+ <string>Type:</string>
+ </property>
+ </widget>
+ <widget class="KPushButton" row="3" column="1">
+ <property name="name">
+ <cstring>filterDialog</cstring>
+ </property>
+ <property name="text">
+ <string>Setup Filter...</string>
+ </property>
+ </widget>
+ <widget class="QLabel" row="2" column="0">
+ <property name="name">
+ <cstring>textLabel2</cstring>
+ </property>
+ <property name="text">
+ <string>Location:</string>
+ </property>
+ </widget>
+ <widget class="QCheckBox" row="3" column="0">
+ <property name="name">
+ <cstring>useFilter</cstring>
+ </property>
+ <property name="text">
+ <string>Use filter</string>
+ </property>
+ </widget>
+ </grid>
+ </widget>
+ </grid>
+</widget>
+<customwidgets>
+</customwidgets>
+<connections>
+ <connection>
+ <sender>ok</sender>
+ <signal>clicked()</signal>
+ <receiver>SourceDialog</receiver>
+ <slot>accept()</slot>
+ </connection>
+ <connection>
+ <sender>cancel</sender>
+ <signal>clicked()</signal>
+ <receiver>SourceDialog</receiver>
+ <slot>reject()</slot>
+ </connection>
+</connections>
+<layoutdefaults spacing="6" margin="11"/>
+<includehints>
+ <includehint>kpushbutton.h</includehint>
+ <includehint>kpushbutton.h</includehint>
+ <includehint>klineedit.h</includehint>
+ <includehint>klineedit.h</includehint>
+ <includehint>klineedit.h</includehint>
+ <includehint>klineedit.h</includehint>
+ <includehint>klineedit.h</includehint>
+ <includehint>kpushbutton.h</includehint>
+ <includehint>kpushbutton.h</includehint>
+</includehints>
+</UI>
diff --git a/kbabel/kbabeldict/modules/poauxiliary/Makefile.am b/kbabel/kbabeldict/modules/poauxiliary/Makefile.am
new file mode 100644
index 00000000..75509337
--- /dev/null
+++ b/kbabel/kbabeldict/modules/poauxiliary/Makefile.am
@@ -0,0 +1,36 @@
+## Makefile.am for poauxiliary
+
+# this has all of the subdirectories that make will recurse into. if
+# there are none, comment this out
+#SUBDIRS =
+
+
+# this is the program that gets installed. it's name is used for all
+# of the other Makefile.am variables
+kde_module_LTLIBRARIES = kbabeldict_poauxiliary.la
+
+# set the include path for X, qt and KDE
+INCLUDES = -I$(srcdir)/../.. -I../../../common -I$(srcdir)/../../../common $(all_includes)
+
+
+kbabeldict_poauxiliary_la_SOURCES = poauxiliary.cpp preferenceswidget.cpp\
+ pa_factory.cpp pwidget.ui
+kbabeldict_poauxiliary_la_LIBADD = ../../libkbabeldictplugin.la ../../../common/libkbabelcommon.la $(LIB_KDEUI) $(LIB_KIO)
+kbabeldict_poauxiliary_la_LDFLAGS = $(all_libraries) -module -avoid-version -no-undefined
+
+
+
+# these are the headers for your project
+noinst_HEADERS = poauxiliary.h preferenceswidget.h pa_factory.h
+
+
+# let automoc handle all of the meta source files (moc)
+METASOURCES = AUTO
+
+
+# this is where the kdelnk file will go
+#datadir = $(kde_datadir)/kbabeldict/modules
+#data_DATA = poauxiliary.rc
+
+kde_services_DATA = poauxiliary.desktop
+EXTRA_DIST = $(kde_services_DATA)
diff --git a/kbabel/kbabeldict/modules/poauxiliary/pa_factory.cpp b/kbabel/kbabeldict/modules/poauxiliary/pa_factory.cpp
new file mode 100644
index 00000000..1448e2b0
--- /dev/null
+++ b/kbabel/kbabeldict/modules/poauxiliary/pa_factory.cpp
@@ -0,0 +1,110 @@
+/* ****************************************************************************
+ This file is part of KBabel
+
+ Copyright (C) 2000 by Matthias Kiefer
+ <matthias.kiefer@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.
+
+ 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, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+ In addition, as a special exception, the copyright holders give
+ permission to link the code of this program with any edition of
+ the Qt library by Trolltech AS, Norway (or with modified versions
+ of Qt that use the same license as Qt), and distribute linked
+ combinations including the two. You must obey the GNU General
+ Public License in all respects for all of the code used other than
+ Qt. If you modify this file, you may extend this exception to
+ your version of the file, but you are not obligated to do so. If
+ you do not wish to do so, delete this exception statement from
+ your version.
+
+**************************************************************************** */
+
+
+#include <klocale.h>
+#include <kinstance.h>
+#include <kaboutdata.h>
+#include <kdebug.h>
+
+#include "pa_factory.h"
+#include "poauxiliary.h"
+
+
+extern "C"
+{
+ KDE_EXPORT void *init_kbabeldict_poauxiliary()
+ {
+ return new PaFactory;
+ }
+}
+
+
+KInstance *PaFactory::s_instance = 0;
+KAboutData *PaFactory::s_about = 0;
+
+
+PaFactory::PaFactory( QObject *parent, const char *name)
+ : KLibFactory(parent,name)
+{
+}
+
+PaFactory::~PaFactory()
+{
+ if(s_instance)
+ {
+ delete s_instance;
+ s_instance=0;
+ }
+
+ if(s_about)
+ {
+ delete s_about;
+ s_about=0;
+ }
+}
+
+
+QObject *PaFactory::createObject( QObject *parent, const char *name
+ , const char *classname, const QStringList &)
+{
+ if(QCString(classname) != "SearchEngine")
+ {
+ kdError() << "not a SearchEngine requested" << endl;
+ return 0;
+ }
+
+ return new PoAuxiliary(parent,name);
+}
+
+
+KInstance *PaFactory::instance()
+{
+ if(!s_instance)
+ {
+ s_about = new KAboutData( "poauxiliary", I18N_NOOP("PO Auxiliary")
+ , "1.0"
+ , I18N_NOOP("A simple module for exact searching in a PO file")
+ , KAboutData::License_GPL
+ , "Copyright 2000, Matthias Kiefer"
+ ,0,0, "kiefer@kde.org");
+
+ s_about->addAuthor("Matthias Kiefer",0,"kiefer@kde.org");
+
+ s_instance = new KInstance(s_about);
+ }
+
+ return s_instance;
+}
+
+#include "pa_factory.moc"
diff --git a/kbabel/kbabeldict/modules/poauxiliary/pa_factory.h b/kbabel/kbabeldict/modules/poauxiliary/pa_factory.h
new file mode 100644
index 00000000..8871a538
--- /dev/null
+++ b/kbabel/kbabeldict/modules/poauxiliary/pa_factory.h
@@ -0,0 +1,60 @@
+/* ****************************************************************************
+ This file is part of KBabel
+
+ Copyright (C) 2000 by Matthias Kiefer
+ <matthias.kiefer@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.
+
+ 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, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+ In addition, as a special exception, the copyright holders give
+ permission to link the code of this program with any edition of
+ the Qt library by Trolltech AS, Norway (or with modified versions
+ of Qt that use the same license as Qt), and distribute linked
+ combinations including the two. You must obey the GNU General
+ Public License in all respects for all of the code used other than
+ Qt. If you modify this file, you may extend this exception to
+ your version of the file, but you are not obligated to do so. If
+ you do not wish to do so, delete this exception statement from
+ your version.
+
+**************************************************************************** */
+
+
+#ifndef PA_FACTORY_H
+#define PA_FACTORY_H
+
+#include <klibloader.h>
+class KInstance;
+class KAboutData;
+
+class PaFactory : public KLibFactory
+{
+ Q_OBJECT
+public:
+ PaFactory( QObject *parent=0, const char *name=0);
+ ~PaFactory();
+
+ virtual QObject *createObject( QObject *parent=0, const char *name=0
+ , const char *classname="QObject"
+ , const QStringList &args = QStringList());
+
+ static KInstance *instance();
+
+private:
+ static KInstance *s_instance;
+ static KAboutData *s_about;
+};
+
+#endif
diff --git a/kbabel/kbabeldict/modules/poauxiliary/poauxiliary.cpp b/kbabel/kbabeldict/modules/poauxiliary/poauxiliary.cpp
new file mode 100644
index 00000000..373f123d
--- /dev/null
+++ b/kbabel/kbabeldict/modules/poauxiliary/poauxiliary.cpp
@@ -0,0 +1,554 @@
+/* ****************************************************************************
+ This file is part of KBabel
+
+ Copyright (C) 2000 by Matthias Kiefer
+ <matthias.kiefer@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.
+
+ 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, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+ In addition, as a special exception, the copyright holders give
+ permission to link the code of this program with any edition of
+ the Qt library by Trolltech AS, Norway (or with modified versions
+ of Qt that use the same license as Qt), and distribute linked
+ combinations including the two. You must obey the GNU General
+ Public License in all respects for all of the code used other than
+ Qt. If you modify this file, you may extend this exception to
+ your version of the file, but you are not obligated to do so. If
+ you do not wish to do so, delete this exception statement from
+ your version.
+
+**************************************************************************** */
+#include <klocale.h>
+#include <kapplication.h>
+#include <kcmdlineargs.h>
+#include <kdebug.h>
+#include <kglobal.h>
+#include <kinstance.h>
+
+#include <qregexp.h>
+#include <qtimer.h>
+#include <qstylesheet.h>
+
+#include "poauxiliary.h"
+#include "preferenceswidget.h"
+#include "pa_factory.h"
+
+#include <resources.h>
+#include <catalog.h>
+
+using namespace KBabel;
+
+PoAuxiliary::PoAuxiliary(QObject *parent, const char *name)
+ : SearchEngine(parent, name)
+{
+ catalog = new Catalog(this, "PoAuxiliary::catalog");
+ prefWidget=0;
+ error=false;
+ stop=false;
+ active=false;
+ loading=false;
+ initialized=false;
+
+ ignoreFuzzy=true;
+
+ loadTimer = new QTimer(this);
+ connect(loadTimer,SIGNAL(timeout()),this,SLOT(loadAuxiliary()));
+
+ msgidDict.setAutoDelete(true);
+}
+
+PoAuxiliary::~PoAuxiliary()
+{
+ results.clear();
+}
+
+bool PoAuxiliary::isReady() const
+{
+ return !error;
+}
+
+
+bool PoAuxiliary::isSearching() const
+{
+ return active;
+}
+
+
+void PoAuxiliary::saveSettings(KConfigBase *config)
+{
+ if(autoUpdate && prefWidget && prefWidget->settingsChanged())
+ {
+ applySettings();
+ }
+
+ config->writeEntry("Auxiliary", url);
+ config->writeEntry("IgnoreFuzzy",ignoreFuzzy);
+}
+
+void PoAuxiliary::readSettings(KConfigBase *config)
+{
+ bool needLoading=false;
+
+ QString newPath = config->readEntry("Auxiliary"
+ ,"../../../de/messages/@DIR1@/@PACKAGE@.po");
+ if(!initialized)
+ {
+ url = newPath;
+ }
+ else if(newPath != url)
+ {
+ url = newPath;
+ needLoading = true;
+ }
+
+ ignoreFuzzy = config->readBoolEntry("IgnoreFuzzy",true);
+
+ if(needLoading && !loadTimer->isActive())
+ {
+ kdDebug(KBABEL_SEARCH) << "readSettings" << endl;
+ loadTimer->start(100,true);
+ }
+
+ restoreSettings();
+}
+
+PrefWidget *PoAuxiliary::preferencesWidget(QWidget *parent)
+{
+ prefWidget = new AuxiliaryPreferencesWidget(parent,"pocompendium_prefwidget");
+ connect(prefWidget, SIGNAL(applySettings()), this, SLOT(applySettings()));
+ connect(prefWidget, SIGNAL(restoreSettings())
+ , this, SLOT(restoreSettings()));
+
+ restoreSettings();
+
+ return prefWidget;
+}
+
+const KAboutData *PoAuxiliary::about() const
+{
+ return PaFactory::instance()->aboutData();
+}
+
+
+QString PoAuxiliary::name() const
+{
+ return i18n("PO Auxiliary");
+}
+
+QString PoAuxiliary::id() const
+{
+ return "poauxiliary";
+}
+
+QString PoAuxiliary::lastError()
+{
+ return errorMsg;
+}
+
+bool PoAuxiliary::startSearch(const QString& t, uint pluralForm, const SearchFilter*filter)
+{
+ QString text(t);
+ if(autoUpdate && prefWidget && prefWidget->settingsChanged())
+ {
+ applySettings();
+ }
+
+ if(!initialized)
+ {
+ loadAuxiliary();
+ }
+
+ if(error)
+ return false;
+
+ if(isSearching())
+ return false;
+
+ stop=false;
+ active = true;
+ emit started();
+
+ clearResults();
+
+ kapp->processEvents(100);
+
+ text.replace("\n","");
+
+ Entry *entry = msgidDict[text];
+ if(entry)
+ {
+ if( !(entry->fuzzy && ignoreFuzzy) )
+ {
+ SearchResult *result = new SearchResult;
+ result->requested =QStyleSheet::convertFromPlainText(text);
+ result->found = QStyleSheet::convertFromPlainText(text);
+ result->translation =
+ QStyleSheet::convertFromPlainText(entry->translation);
+
+ result->plainRequested = text;
+ result->plainFound=text;
+ result->plainTranslation=entry->translation;
+ result->score=100;
+
+ if(entry->fuzzy)
+ {
+ result->translation="<qt><font color=\"red\">"+i18n("fuzzy")
+ +"</font><hr/>" + result->translation+"</qt>";
+ }
+
+ TranslationInfo *info = new TranslationInfo;
+ info->location = auxPackage;
+ info->translator = auxTranslator;
+ info->description = entry->comment;
+ info->filePath = auxURL;
+ result->descriptions.append(info);
+
+ results.append(result);
+
+ emit numberOfResultsChanged(1);
+ emit resultFound(result);
+ }
+ }
+
+
+ active = false;
+ stop = false;
+ emit finished();
+
+ return true;
+}
+
+
+bool PoAuxiliary::startSearchInTranslation(const QString& text)
+{
+ if(autoUpdate && prefWidget && prefWidget->settingsChanged())
+ {
+ applySettings();
+ }
+
+ if(!initialized)
+ {
+ loadAuxiliary();
+ }
+
+ if(error)
+ return false;
+
+ if(isSearching())
+ return false;
+
+ stop=false;
+ active = true;
+ emit started();
+
+ clearResults();
+
+ kapp->processEvents(100);
+
+ Entry *entry = msgstrDict[text];
+ if(entry)
+ {
+ if( !(entry->fuzzy && ignoreFuzzy) )
+ {
+ SearchResult *result = new SearchResult;
+ result->requested =QStyleSheet::convertFromPlainText(entry->orig);
+ result->found = QStyleSheet::convertFromPlainText(entry->orig);
+ result->translation =
+ QStyleSheet::convertFromPlainText(text);
+
+ result->plainRequested = entry->orig;
+ result->plainFound=entry->orig;
+ result->plainTranslation=text;
+ result->score=100;
+
+ if(entry->fuzzy)
+ {
+ result->translation="<qt><font color=\"red\">"+i18n("fuzzy")
+ +"</font><hr/>" + result->translation+"</qt>";
+ }
+
+ TranslationInfo *info = new TranslationInfo;
+ info->location = auxPackage;
+ info->translator = auxTranslator;
+ info->description = entry->comment;
+ info->filePath = auxURL;
+ result->descriptions.append(info);
+
+ results.append(result);
+
+ emit numberOfResultsChanged(1);
+ emit resultFound(result);
+ }
+ }
+
+
+ active = false;
+ stop = false;
+ emit finished();
+
+ return true;
+}
+
+void PoAuxiliary::stopSearch()
+{
+ stop=true;
+}
+
+
+void PoAuxiliary::applySettings()
+{
+ if(!prefWidget)
+ return;
+
+ bool needLoading=false;
+
+ if(isSearching())
+ stopSearch();
+
+ QString newPath = prefWidget->url();
+ if(!initialized)
+ {
+ url = newPath;
+ }
+ else if(newPath != url)
+ {
+ url = newPath;
+ needLoading=true;
+ }
+
+ ignoreFuzzy = prefWidget->ignoreFuzzy();
+
+ if(needLoading && !loadTimer->isActive())
+ {
+ loadTimer->start(100,true);
+ }
+}
+
+void PoAuxiliary::restoreSettings()
+{
+ if(!prefWidget)
+ return;
+
+ prefWidget->setURL(url);
+ prefWidget->setIgnoreFuzzy(ignoreFuzzy);
+}
+
+void PoAuxiliary::loadAuxiliary()
+{
+ if(loadTimer->isActive())
+ loadTimer->stop();
+
+ if(loading)
+ return;
+
+ loading=true;
+ error=false;
+
+ QString path=url;
+
+ if(path.contains("@LANG@"))
+ {
+ path.replace("@LANG@",langCode);
+ }
+ if(path.contains("@PACKAGE@"))
+ {
+ int pos=package.findRev("/");
+ if( pos<0 ) pos=0;
+ path.replace("@PACKAGE@",package.mid(pos));
+ }
+ if(path.contains("@PACKAGEDIR@"))
+ {
+ QString packagedir;
+ int pos=package.findRev("/");
+ if( pos > 0 ) packagedir=package.left(pos);
+ else packagedir="";
+ path.replace("@PACKAGEDIR@",packagedir);
+ kdDebug(KBABEL_SEARCH) << "Packagedir found " << packagedir << endl;
+ }
+ QRegExp reg("@DIR[0-9]+@");
+ if(path.contains(reg))
+ {
+ int pos=reg.search(path);
+ int len = reg.matchedLength();
+
+ while(pos>=0)
+ {
+ QString num=path.mid(pos+4,len-5);
+
+ bool ok;
+ int number=num.toInt(&ok);
+ if(ok)
+ {
+ QString dir=directory(editedFile,number);
+ QString s("@DIR%1@");
+ path.replace(s.arg(number),dir);
+
+ pos+=dir.length();
+ }
+
+ pos=reg.search(path);
+ len = reg.matchedLength();
+ }
+ }
+
+ KURL u;
+ QRegExp rel("^[a-zA-Z]+:");
+ if(rel.search(path) >= 0)
+ {
+ u=path;
+ }
+ else if(path[0] != '/') // relative path
+ {
+ KURL temp(editedFile);
+ QString dir = temp.directory();
+ kdDebug(KBABEL_SEARCH) << dir << endl;
+ u.setPath(dir+"/"+path);
+ u.cleanPath();
+ kdDebug(KBABEL_SEARCH) << u.prettyURL() << endl;
+ }
+ else
+ {
+ u.setPath(path);
+ }
+
+ emit progressStarts(i18n("Loading PO auxiliary"));
+ connect(catalog, SIGNAL(signalProgress(int))
+ , this, SIGNAL(progress(int)));
+
+ ConversionStatus stat = catalog->openURL(u);
+ if( stat != OK && stat != RECOVERED_PARSE_ERROR)
+ {
+ kdDebug(KBABEL_SEARCH) << "error while opening file " << u.prettyURL() << endl;
+
+ if( !error )
+ {
+ error = true;
+ errorMsg = i18n("Error while trying to open file for PO Auxiliary module:\n%1")
+ .arg(u.prettyURL());
+ emit hasError(errorMsg);
+ }
+ }
+ else
+ {
+ error = false;
+ // build index for fast search
+ msgidDict.clear();
+ msgstrDict.clear();
+
+ emit progressStarts(i18n("Building index"));
+
+ int total = catalog->numberOfEntries();
+ for(int i=0; i < total; i++)
+ {
+ if( (100*(i+1))%total < 100 )
+ {
+ emit progress((100*(i+1))/total);
+ kapp->processEvents(100);
+ }
+
+ Entry *e = new Entry;
+ // FIXME: should care about plural forms
+ e->orig = catalog->msgid(i).first();
+ e->orig.replace("\n","");
+ kdWarning() << "PoAuxialiary does not support plural forms" << endl;
+ e->translation = catalog->msgstr(i).first();
+ e->comment = catalog->comment(i);
+ e->fuzzy = catalog->isFuzzy(i);
+
+ msgidDict.insert(catalog->msgid(i,true).first(),e);
+ msgstrDict.insert(e->translation,e);
+ }
+
+ auxPackage = catalog->packageName();
+ auxURL = catalog->currentURL().url();
+ auxTranslator = catalog->lastTranslator();
+ }
+
+ disconnect(catalog, SIGNAL(signalProgress(int))
+ , this, SIGNAL(progress(int)));
+
+ emit progressEnds();
+
+ initialized=true;
+
+ loading=false;
+
+ catalog->clear();
+}
+
+
+void PoAuxiliary::setEditedFile(const QString& file)
+{
+ if(initialized && (url.contains("@DIR") || KURL::isRelativeURL(url))
+ && file!=editedFile && !loadTimer->isActive() )
+ {
+ initialized=false;
+ }
+
+ editedFile=file;
+}
+
+
+void PoAuxiliary::setEditedPackage(const QString& pack)
+{
+ if(initialized && url.contains("@PACKAGE@") && pack!=package
+ && !loadTimer->isActive() )
+ {
+ initialized=false;
+ }
+
+ package=pack;
+}
+
+
+void PoAuxiliary::setLanguageCode(const QString& lang)
+{
+ if(initialized && url.contains("@LANG@") && lang!=langCode
+ && !loadTimer->isActive() )
+ {
+ initialized=false;
+ }
+
+ langCode=lang;
+}
+
+bool PoAuxiliary::usesRichTextResults()
+{
+ return true;
+}
+
+QString PoAuxiliary::translate(const QString& text, uint pluralForm)
+{
+ if(!initialized)
+ {
+ loadAuxiliary();
+ }
+
+ if(error)
+ {
+ return QString::null;
+ }
+
+ Entry *entry = msgidDict[text];
+ if(entry)
+ {
+ return entry->translation;
+ }
+
+ return QString::null;
+}
+
+
+#include "poauxiliary.moc"
diff --git a/kbabel/kbabeldict/modules/poauxiliary/poauxiliary.desktop b/kbabel/kbabeldict/modules/poauxiliary/poauxiliary.desktop
new file mode 100644
index 00000000..5629930e
--- /dev/null
+++ b/kbabel/kbabeldict/modules/poauxiliary/poauxiliary.desktop
@@ -0,0 +1,51 @@
+[Desktop Entry]
+Type=Service
+Name=Auxiliary PO Module for KBabelDict
+Name[bg]=Помощен PO модул за KBabelDict
+Name[bs]=Pomoćni PO modul za KBabelDict
+Name[ca]=Mòdul PO auxiliar per a KBabelDict
+Name[cs]=Doplňkový PO modul pro KBabelDict
+Name[cy]=Modiwl PO Ategol i KBabelDict
+Name[da]=Auxiliary PO-module for KBabelDict
+Name[de]=PO-Hilfsdatei-Modul für KBabelDict
+Name[el]=ΆÏθÏωμα Î²Î¿Î·Î¸Î·Ï„Î¹ÎºÎ¿Ï PO για το KBabelDict
+Name[es]=Módulo PO auxiliar para KBabelDict
+Name[et]=KBabelDicti PO liitlasfaili moodul
+Name[eu]=PO modulu laguntzailea KBabelDict-entzat
+Name[fa]=پیمانۀ کمکی PO برای KBabelDict
+Name[fi]=KBabelDict-ohjelman PO-apumoduuli
+Name[fr]=Module de PO auxiliaire pour KBabelDict
+Name[gl]=Módulo de PO auxiliar para KBabelDict
+Name[hi]=के-बेबल-डिकà¥à¤¶ के लिठऑकà¥à¤œà¤¿à¤²à¤°à¥€ पीओ मॉडà¥à¤¯à¥‚ल
+Name[hu]=Kiegészítő PO modul a KBabelDicthez
+Name[is]=Viðbótar PO eining fyrir KBabel orðabókina
+Name[it]=Modulo ausiliario PO per KBabelDict
+Name[ja]=KBabelDict 補助 PO モジュール
+Name[ka]=დáƒáƒ›áƒ®áƒ›áƒáƒ áƒ” PO მáƒáƒ“ული KBabelDict-სთვის
+Name[kk]=KBabelDict-Ñ‚Ñ‹Ò£ қоÑымша PO модулі
+Name[lt]=KBabelDict papildomo PO žodyno modulis
+Name[ms]=Modul Auksillari PO untuk KBabelDict
+Name[nb]=Hjelpeordlistemodul for KBabelDict
+Name[nds]=PO-Hülpdateimoduul för KBabelDict
+Name[ne]=KBabelDict का लागि सहायक पीओ मोडà¥à¤¯à¥à¤²
+Name[nl]=Alternatieve PO-module voor KBabelDict
+Name[nn]=Jamføringsmodul for KBabelDict
+Name[pa]=ਕੇਬਬੇਲ-ਸ਼ਬਦਕੋਸ਼ ਲਈ ਸਹਾਇਕ PO ਸਹਾਇਕ
+Name[pl]=Moduł pomocniczego pliku PO dla KBabelDict
+Name[pt]=Módulo de PO Auxiliar para o KBabelDict
+Name[pt_BR]=Módulo Auxiliar PO para o KBabelDict
+Name[ru]=Ð’Ñпомогательный модуль PO Ð´Ð»Ñ KBabelDict
+Name[sk]=Iný PO súbore pre KBabelDict
+Name[sl]=Dodatni modul PO za KBabelDict
+Name[sr]=Помоћни PO модул за KBabelDict
+Name[sr@Latn]=Pomoćni PO modul za KBabelDict
+Name[sv]=Hjälp-PO modul för Kbabeldict
+Name[ta]=Kபாபேலà¯à®•à¯à®•à®¾à®© இரணà¯à®Ÿà®¾à®®à¯ PO கூறà¯
+Name[tg]=Модули ёрираÑони PO барои KBabelDict
+Name[tr]=KBabelDict için Yardımcı PO Modülü
+Name[uk]=Модуль допоміжного Ñловника PO Ð´Ð»Ñ KBabelDict
+Name[zh_CN]=KBabelDict çš„ PO 辅助è¯å…¸æ¨¡å—
+Name[zh_TW]=KBabelDict 輔助 PO 模組
+X-KDE-Library=kbabeldict_poauxiliary
+ServiceTypes=KBabelDictModule
+Applications=kbabel
diff --git a/kbabel/kbabeldict/modules/poauxiliary/poauxiliary.h b/kbabel/kbabeldict/modules/poauxiliary/poauxiliary.h
new file mode 100644
index 00000000..27fecba6
--- /dev/null
+++ b/kbabel/kbabeldict/modules/poauxiliary/poauxiliary.h
@@ -0,0 +1,136 @@
+/* ****************************************************************************
+ This file is part of KBabel
+
+ Copyright (C) 2000 by Matthias Kiefer
+ <matthias.kiefer@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.
+
+ 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, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+ In addition, as a special exception, the copyright holders give
+ permission to link the code of this program with any edition of
+ the Qt library by Trolltech AS, Norway (or with modified versions
+ of Qt that use the same license as Qt), and distribute linked
+ combinations including the two. You must obey the GNU General
+ Public License in all respects for all of the code used other than
+ Qt. If you modify this file, you may extend this exception to
+ your version of the file, but you are not obligated to do so. If
+ you do not wish to do so, delete this exception statement from
+ your version.
+
+**************************************************************************** */
+
+#ifndef POAUXILIARY_H
+#define POAUXILIARY_H
+
+#include "searchengine.h"
+
+#include <qguardedptr.h>
+#include <qdict.h>
+class QTimer;
+
+namespace KBabel
+{
+ class Catalog;
+}
+
+class AuxiliaryPreferencesWidget;
+
+class PoAuxiliary : public SearchEngine
+{
+ Q_OBJECT
+
+public:
+ PoAuxiliary(QObject *parent=0, const char *name=0);
+ virtual ~PoAuxiliary();
+
+ virtual bool isReady() const;
+
+ virtual QString translate(const QString& text, uint pluralForm);
+
+ virtual bool isSearching() const;
+
+ virtual void saveSettings(KConfigBase *config);
+ virtual void readSettings(KConfigBase *config);
+
+ virtual PrefWidget *preferencesWidget(QWidget *parent);
+
+ virtual const KAboutData *about() const;
+
+ virtual QString name() const;
+
+ virtual QString id() const;
+
+ virtual QString lastError();
+
+ virtual bool usesRichTextResults();
+
+public slots:
+ virtual bool startSearch(const QString& text, unsigned int pluralForm
+ , const SearchFilter*filter);
+ virtual bool startSearchInTranslation(const QString& text);
+
+ virtual void stopSearch();
+
+ virtual void setEditedFile(const QString&);
+ virtual void setEditedPackage(const QString&);
+ virtual void setLanguageCode(const QString&);
+
+
+protected slots:
+ /** reads the current settings from the preferences dialog */
+ void applySettings();
+
+ /** sets the current settings in the preferences dialog */
+ void restoreSettings();
+
+ void loadAuxiliary();
+
+private:
+ QGuardedPtr<AuxiliaryPreferencesWidget> prefWidget;
+ KBabel::Catalog *catalog;
+ QString auxPackage;
+ QString auxTranslator;
+ QString auxURL;
+
+ QString url;
+ bool ignoreFuzzy;
+
+ QString editedFile;
+ QString package;
+ QString langCode;
+
+ bool error;
+ QString errorMsg;
+
+ bool stop;
+ bool active;
+ bool loading;
+ bool initialized;
+
+ QTimer *loadTimer;
+
+ struct Entry
+ {
+ QString orig;
+ QString translation;
+ QString comment;
+ bool fuzzy;
+ };
+
+ QDict<Entry> msgidDict;
+ QDict<Entry> msgstrDict;
+};
+
+#endif
diff --git a/kbabel/kbabeldict/modules/poauxiliary/preferenceswidget.cpp b/kbabel/kbabeldict/modules/poauxiliary/preferenceswidget.cpp
new file mode 100644
index 00000000..e8d48032
--- /dev/null
+++ b/kbabel/kbabeldict/modules/poauxiliary/preferenceswidget.cpp
@@ -0,0 +1,115 @@
+/* ****************************************************************************
+ This file is part of KBabel
+
+ Copyright (C) 2000 by Matthias Kiefer
+ <matthias.kiefer@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.
+
+ 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, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+ In addition, as a special exception, the copyright holders give
+ permission to link the code of this program with any edition of
+ the Qt library by Trolltech AS, Norway (or with modified versions
+ of Qt that use the same license as Qt), and distribute linked
+ combinations including the two. You must obey the GNU General
+ Public License in all respects for all of the code used other than
+ Qt. If you modify this file, you may extend this exception to
+ your version of the file, but you are not obligated to do so. If
+ you do not wish to do so, delete this exception statement from
+ your version.
+
+**************************************************************************** */
+#include <qcheckbox.h>
+#include <qlabel.h>
+#include <qlayout.h>
+
+#include <kfiledialog.h>
+#include <qpushbutton.h>
+#include <klineedit.h>
+#include <klocale.h>
+#include <kurlrequester.h>
+
+#include "preferenceswidget.h"
+#include "pwidget.h"
+
+AuxiliaryPreferencesWidget::AuxiliaryPreferencesWidget(QWidget *parent, const char* name)
+ : PrefWidget(parent,name)
+ , changed(false)
+{
+ QVBoxLayout *layout = new QVBoxLayout(this);
+
+ prefWidget = new PWidget(this);
+ layout->addWidget(prefWidget);
+
+
+ connect(prefWidget->urlInput->lineEdit(),SIGNAL(textChanged(const QString&))
+ , this, SLOT(setChanged()));
+}
+
+AuxiliaryPreferencesWidget::~AuxiliaryPreferencesWidget()
+{
+}
+
+
+void AuxiliaryPreferencesWidget::apply()
+{
+ emit applySettings();
+}
+
+void AuxiliaryPreferencesWidget::cancel()
+{
+ emit restoreSettings();
+}
+
+void AuxiliaryPreferencesWidget::standard()
+{
+ prefWidget->urlInput->setURL("@PACKAGE@.po");
+ changed=true;
+}
+
+void AuxiliaryPreferencesWidget::setURL(const QString url)
+{
+ prefWidget->urlInput->setURL(url);
+ changed=false;
+}
+
+QString AuxiliaryPreferencesWidget::url()
+{
+ changed = false;
+ return prefWidget->urlInput->url();
+}
+
+bool AuxiliaryPreferencesWidget::ignoreFuzzy()
+{
+ changed=false;
+ return prefWidget->fuzzyBtn->isChecked();
+}
+
+void AuxiliaryPreferencesWidget::setIgnoreFuzzy(bool flag)
+{
+ prefWidget->fuzzyBtn->setChecked(flag);
+}
+
+bool AuxiliaryPreferencesWidget::settingsChanged() const
+{
+ return changed;
+}
+
+void AuxiliaryPreferencesWidget::setChanged()
+{
+ changed=true;
+}
+
+
+#include "preferenceswidget.moc"
diff --git a/kbabel/kbabeldict/modules/poauxiliary/preferenceswidget.h b/kbabel/kbabeldict/modules/poauxiliary/preferenceswidget.h
new file mode 100644
index 00000000..45488158
--- /dev/null
+++ b/kbabel/kbabeldict/modules/poauxiliary/preferenceswidget.h
@@ -0,0 +1,77 @@
+/* ****************************************************************************
+ This file is part of KBabel
+
+ Copyright (C) 2000 by Matthias Kiefer
+ <matthias.kiefer@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.
+
+ 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, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+ In addition, as a special exception, the copyright holders give
+ permission to link the code of this program with any edition of
+ the Qt library by Trolltech AS, Norway (or with modified versions
+ of Qt that use the same license as Qt), and distribute linked
+ combinations including the two. You must obey the GNU General
+ Public License in all respects for all of the code used other than
+ Qt. If you modify this file, you may extend this exception to
+ your version of the file, but you are not obligated to do so. If
+ you do not wish to do so, delete this exception statement from
+ your version.
+
+**************************************************************************** */
+
+
+#ifndef PREFERENCESWIDGET_H
+#define PREFERENCESWIDGET_H
+
+#include "searchengine.h"
+
+class PWidget;
+
+class AuxiliaryPreferencesWidget : public PrefWidget
+{
+ Q_OBJECT
+
+public:
+ AuxiliaryPreferencesWidget(QWidget *parent=0, const char* name=0);
+ virtual ~AuxiliaryPreferencesWidget();
+
+ virtual void apply();
+ virtual void cancel();
+ virtual void standard();
+
+ void setURL(const QString url);
+ QString url();
+
+ void setIgnoreFuzzy(bool);
+ bool ignoreFuzzy();
+
+ bool settingsChanged() const;
+
+signals:
+ void restoreSettings();
+ void applySettings();
+
+public:
+ PWidget *prefWidget;
+
+protected slots:
+ void setChanged();
+
+private:
+ bool changed;
+
+};
+
+#endif
diff --git a/kbabel/kbabeldict/modules/poauxiliary/pwidget.ui b/kbabel/kbabeldict/modules/poauxiliary/pwidget.ui
new file mode 100644
index 00000000..8179caed
--- /dev/null
+++ b/kbabel/kbabeldict/modules/poauxiliary/pwidget.ui
@@ -0,0 +1,133 @@
+<!DOCTYPE UI><UI>
+<class>PWidget</class>
+<widget>
+ <class>QWidget</class>
+ <property stdset="1">
+ <name>name</name>
+ <cstring>PWidget</cstring>
+ </property>
+ <property stdset="1">
+ <name>geometry</name>
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>335</width>
+ <height>306</height>
+ </rect>
+ </property>
+ <property stdset="1">
+ <name>caption</name>
+ <string></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>QLabel</class>
+ <property stdset="1">
+ <name>name</name>
+ <cstring>TextLabel1</cstring>
+ </property>
+ <property stdset="1">
+ <name>text</name>
+ <string>&amp;Path to auxiliary file:</string>
+ </property>
+ <property>
+ <name>buddy</name>
+ <cstring>urlInput</cstring>
+ </property>
+ </widget>
+ <widget>
+ <class>KURLRequester</class>
+ <property stdset="1">
+ <name>name</name>
+ <cstring>urlInput</cstring>
+ </property>
+ </widget>
+ <widget>
+ <class>QCheckBox</class>
+ <property stdset="1">
+ <name>name</name>
+ <cstring>fuzzyBtn</cstring>
+ </property>
+ <property stdset="1">
+ <name>text</name>
+ <string>&amp;Ignore fuzzy entries</string>
+ </property>
+ </widget>
+ <widget>
+ <class>QLabel</class>
+ <property stdset="1">
+ <name>name</name>
+ <cstring>TextLabel1_2</cstring>
+ </property>
+ <property stdset="1">
+ <name>text</name>
+ <string>&lt;qt&gt;&lt;p&gt;
+The following variables will be replaced in the path if available:
+&lt;ul&gt;
+&lt;li&gt;&lt;b&gt;@PACKAGE@&lt;/b&gt;: the name of the currently translated application or package&lt;/li&gt;
+&lt;li&gt;&lt;b&gt;@LANG@&lt;/b&gt;: the language code&lt;/li&gt;
+&lt;li&gt;&lt;b&gt;@DIR&lt;em&gt;n&lt;/em&gt;@&lt;/b&gt;: where n is a positive integer. This expands to the nth folder counted from the filename&lt;/li&gt;
+&lt;/ul&gt;&lt;/p&gt;&lt;/qt&gt;</string>
+ </property>
+ </widget>
+ <spacer>
+ <property>
+ <name>name</name>
+ <cstring>Spacer1</cstring>
+ </property>
+ <property stdset="1">
+ <name>orientation</name>
+ <enum>Vertical</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>
+ <property>
+ <name>sizeHint</name>
+ <size>
+ <width>20</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </vbox>
+</widget>
+<customwidgets>
+ <customwidget>
+ <class>KURLRequester</class>
+ <header location="global">kurlrequester.h</header>
+ <sizehint>
+ <width>-1</width>
+ <height>-1</height>
+ </sizehint>
+ <container>0</container>
+ <sizepolicy>
+ <hordata>5</hordata>
+ <verdata>5</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/kbabel/kbabeldict/modules/pocompendium/Makefile.am b/kbabel/kbabeldict/modules/pocompendium/Makefile.am
new file mode 100644
index 00000000..b4fe4974
--- /dev/null
+++ b/kbabel/kbabeldict/modules/pocompendium/Makefile.am
@@ -0,0 +1,39 @@
+## Makefile.am for pocompendium
+
+# this has all of the subdirectories that make will recurse into. if
+# there are none, comment this out
+#SUBDIRS =
+
+
+# this is the program that gets installed. it's name is used for all
+# of the other Makefile.am variables
+kde_module_LTLIBRARIES = kbabeldict_pocompendium.la
+
+# set the include path for X, qt and KDE
+INCLUDES = -I$(srcdir)/../.. -I../../../common -I$(srcdir)/../../../common $(all_includes)
+
+
+# which sources should be compiled for kbabel
+kbabeldict_pocompendium_la_SOURCES = pocompendium.cpp preferenceswidget.cpp \
+ pc_factory.cpp pwidget.ui compendiumdata.cpp
+
+kbabeldict_pocompendium_la_LIBADD = ../../libkbabeldictplugin.la ../../../common/libkbabelcommon.la $(LIB_KDEUI) $(LIB_KIO)
+kbabeldict_pocompendium_la_LDFLAGS = $(all_libraries) -module -avoid-version -no-undefined
+
+
+
+# these are the headers for your project
+noinst_HEADERS = pocompendium.h preferenceswidget.h pc_factory.h \
+ compendiumdata.h
+
+
+# let automoc handle all of the meta source files (moc)
+METASOURCES = AUTO
+
+
+# this is where the kdelnk file will go
+#datadir = $(kde_datadir)/kbabeldict/modules
+#data_DATA = pocompendium.rc
+
+kde_services_DATA = pocompendium.desktop
+EXTRA_DIST = $(kde_services_DATA)
diff --git a/kbabel/kbabeldict/modules/pocompendium/compendiumdata.cpp b/kbabel/kbabeldict/modules/pocompendium/compendiumdata.cpp
new file mode 100644
index 00000000..d862b236
--- /dev/null
+++ b/kbabel/kbabeldict/modules/pocompendium/compendiumdata.cpp
@@ -0,0 +1,261 @@
+/* ****************************************************************************
+ This file is part of KBabel
+
+ Copyright (C) 2001 by Matthias Kiefer
+ <matthias.kiefer@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.
+
+ 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, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+ In addition, as a special exception, the copyright holders give
+ permission to link the code of this program with any edition of
+ the Qt library by Trolltech AS, Norway (or with modified versions
+ of Qt that use the same license as Qt), and distribute linked
+ combinations including the two. You must obey the GNU General
+ Public License in all respects for all of the code used other than
+ Qt. If you modify this file, you may extend this exception to
+ your version of the file, but you are not obligated to do so. If
+ you do not wish to do so, delete this exception statement from
+ your version.
+
+**************************************************************************** */
+#include "compendiumdata.h"
+
+#include <resources.h>
+#include <catalog.h>
+#include <tagextractor.h>
+
+#include <kapplication.h>
+#include <kdebug.h>
+#include <klocale.h>
+
+using namespace KBabel;
+
+CompendiumData::CompendiumData(QObject *parent)
+ : QObject(parent)
+ , _active(false)
+ , _error(false)
+ , _initialized(false)
+ , _catalog(0)
+ , _exactDict(9887)
+ , _allDict(9887)
+ , _wordDict(9887)
+ , _textonlyDict(9887)
+{
+ _catalog = new Catalog(this, "CompendiumData::catalog", QString::null);
+ _exactDict.setAutoDelete(true);
+ _allDict.setAutoDelete(true);
+ _wordDict.setAutoDelete(true);
+ _textonlyDict.setAutoDelete(true);
+}
+
+
+bool CompendiumData::load(KURL url)
+{
+ if(_active)
+ return false;
+
+
+ _error = false;
+ _active = true;
+
+ _exactDict.clear();
+ _allDict.clear();
+ _wordDict.clear();
+ _textonlyDict.clear();
+
+
+ emit progressStarts(i18n("Loading PO compendium"));
+ connect(_catalog, SIGNAL(signalProgress(int)), this, SIGNAL(progress(int)));
+
+ ConversionStatus stat=_catalog->openURL(url);
+
+ disconnect(_catalog, SIGNAL(signalProgress(int))
+ , this, SIGNAL(progress(int)));
+
+
+ if( stat!= OK && stat != RECOVERED_PARSE_ERROR)
+ {
+ kdDebug(KBABEL_SEARCH) << "error while opening file " << url.prettyURL() << endl;
+
+ _error = true;
+ _errorMsg = i18n("Error while trying to read file for PO Compendium module:\n%1")
+ .arg(url.prettyURL());
+
+ emit progressEnds();
+
+ _active = false;
+ _initialized=true;
+
+ return false;
+ }
+
+ emit progressStarts(i18n("Building indices"));
+
+ int total = _catalog->numberOfEntries();
+ for(int i=0; i < total; i++)
+ {
+ if( (100*(i+1))%total < 100 )
+ {
+ emit progress((100*(i+1))/total);
+ kapp->processEvents(100);
+ }
+
+ // FIXME: shoudl care about plural forms
+ QString temp = _catalog->msgid(i,true).first();
+
+ int *index = new int(i);
+ _exactDict.insert(temp,index);
+
+
+ temp = simplify(temp);
+ temp = temp.lower();
+
+ if(!temp.isEmpty() && temp.length() > 1)
+ {
+ // add to allDict
+ QValueList<int> *indexList=_allDict[temp];
+
+ if(!indexList)
+ {
+ indexList = new QValueList<int>;
+ _allDict.insert(temp,indexList);
+ }
+
+ indexList->append(i);
+
+ // add to textonlyDict
+ QString temp1 = temp;
+ temp1.remove( ' ' );
+
+ indexList=_textonlyDict[temp1];
+
+ if(!indexList)
+ {
+ indexList = new QValueList<int>;
+ _textonlyDict.insert(temp1,indexList);
+ kdDebug() << "Adding " << temp1 << endl;
+ }
+
+ indexList->append(i);
+
+ // add to wordDict
+ QStringList wList = wordList(temp);
+ for ( QStringList::Iterator it = wList.begin()
+ ; it != wList.end(); ++it )
+ {
+ if( (*it).length() > 1)
+ {
+ indexList=_wordDict[*it];
+
+ if(!indexList)
+ {
+ indexList = new QValueList<int>;
+ _wordDict.insert(*it,indexList);
+ }
+
+ indexList->append(i);
+ }
+ }
+ }
+ }
+
+ // remove words, that are too frequent
+ uint max=_allDict.count()/10;
+ QDictIterator< QValueList<int> > it(_wordDict);
+ while ( it.current() )
+ {
+ if(it.current()->count() > max)
+ {
+ _wordDict.remove(it.currentKey());
+ }
+ else
+ {
+ ++it;
+ }
+ }
+
+
+ _initialized=true;
+
+ emit progressEnds();
+
+
+
+ _active = false;
+
+ return true;
+}
+
+const int* CompendiumData::exactDict(const QString text) const
+{
+ return _exactDict[text];
+}
+
+const QValueList<int>* CompendiumData::allDict(const QString text) const
+{
+ return _allDict[text];
+}
+
+const QValueList<int>* CompendiumData::wordDict(const QString text) const
+{
+ return _wordDict[text];
+}
+
+const QValueList<int>* CompendiumData::textonlyDict(const QString text) const
+{
+ return _textonlyDict[text];
+}
+
+
+void CompendiumData::registerObject(QObject *obj)
+{
+ if(!_registered.containsRef(obj))
+ _registered.append(obj);
+}
+
+bool CompendiumData::unregisterObject(QObject *obj)
+{
+ _registered.removeRef(obj);
+
+ return _registered.count()==0;
+}
+
+bool CompendiumData::hasObjects() const
+{
+ return _registered.count()==0;
+}
+
+QString CompendiumData::simplify(const QString string)
+{
+ QString result;
+
+ TagExtractor te;
+ te.setString(string);
+ result=te.plainString();
+
+ result=result.simplifyWhiteSpace();
+ result=result.stripWhiteSpace();
+
+ return result;
+}
+
+QStringList CompendiumData::wordList(const QString string)
+{
+ QString result=CompendiumData::simplify(string);
+
+ return QStringList::split(' ',result);
+}
+
+#include "compendiumdata.moc"
diff --git a/kbabel/kbabeldict/modules/pocompendium/compendiumdata.h b/kbabel/kbabeldict/modules/pocompendium/compendiumdata.h
new file mode 100644
index 00000000..2fec45cb
--- /dev/null
+++ b/kbabel/kbabeldict/modules/pocompendium/compendiumdata.h
@@ -0,0 +1,105 @@
+/* ****************************************************************************
+ This file is part of KBabel
+
+ Copyright (C) 2001 by Matthias Kiefer
+ <matthias.kiefer@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.
+
+ 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, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+ In addition, as a special exception, the copyright holders give
+ permission to link the code of this program with any edition of
+ the Qt library by Trolltech AS, Norway (or with modified versions
+ of Qt that use the same license as Qt), and distribute linked
+ combinations including the two. You must obey the GNU General
+ Public License in all respects for all of the code used other than
+ Qt. If you modify this file, you may extend this exception to
+ your version of the file, but you are not obligated to do so. If
+ you do not wish to do so, delete this exception statement from
+ your version.
+
+**************************************************************************** */
+#ifndef COMPENDIUMDATA_H
+#define COMPENDIUMDATA_H
+
+
+#include <kurl.h>
+#include <qdict.h>
+#include <qobject.h>
+#include <qstringlist.h>
+#include <qvaluelist.h>
+#include <qptrlist.h>
+
+namespace KBabel
+{
+class Catalog;
+}
+
+class CompendiumData : public QObject
+{
+ Q_OBJECT
+
+public:
+ CompendiumData(QObject *parent=0);
+
+ bool load(KURL url);
+
+ const KBabel::Catalog *catalog() const { return _catalog; }
+ const int *exactDict(const QString text) const;
+ const QValueList<int> *allDict(const QString text) const;
+ const QValueList<int> *wordDict(const QString text) const;
+ const QValueList<int> *textonlyDict(const QString text) const;
+
+ bool active() const { return _active; }
+ bool initialized() const { return _initialized; }
+ bool hasErrors() const { return _error; }
+ QString errorMsg() const { return _errorMsg; }
+
+ /** registers an object, that uses this data */
+ void registerObject(QObject *);
+ /**
+ * unregisters an object, that uses this data
+ *
+ * @return true, if this was the last object
+ */
+ bool unregisterObject(QObject *);
+
+ bool hasObjects() const;
+
+
+ static QString simplify(const QString text);
+ static QStringList wordList(const QString text);
+
+signals:
+ void progressStarts(const QString);
+ void progressEnds();
+ void progress(int);
+
+
+private:
+ bool _active;
+ bool _error;
+ bool _initialized;
+ QString _errorMsg;
+
+ KBabel::Catalog *_catalog;
+ QDict<int> _exactDict;
+ QDict< QValueList<int> > _allDict;
+ QDict< QValueList<int> > _wordDict;
+ QDict< QValueList<int> > _textonlyDict;
+
+ QPtrList<QObject> _registered;
+};
+
+#endif
diff --git a/kbabel/kbabeldict/modules/pocompendium/pc_factory.cpp b/kbabel/kbabeldict/modules/pocompendium/pc_factory.cpp
new file mode 100644
index 00000000..882cc064
--- /dev/null
+++ b/kbabel/kbabeldict/modules/pocompendium/pc_factory.cpp
@@ -0,0 +1,110 @@
+/* ****************************************************************************
+ This file is part of KBabel
+
+ Copyright (C) 2000 by Matthias Kiefer
+ <matthias.kiefer@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.
+
+ 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, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+ In addition, as a special exception, the copyright holders give
+ permission to link the code of this program with any edition of
+ the Qt library by Trolltech AS, Norway (or with modified versions
+ of Qt that use the same license as Qt), and distribute linked
+ combinations including the two. You must obey the GNU General
+ Public License in all respects for all of the code used other than
+ Qt. If you modify this file, you may extend this exception to
+ your version of the file, but you are not obligated to do so. If
+ you do not wish to do so, delete this exception statement from
+ your version.
+
+**************************************************************************** */
+
+
+#include <klocale.h>
+#include <kinstance.h>
+#include <kaboutdata.h>
+#include <kdebug.h>
+
+#include "pc_factory.h"
+#include "pocompendium.h"
+
+
+extern "C"
+{
+ KDE_EXPORT void *init_kbabeldict_pocompendium()
+ {
+ return new PcFactory;
+ }
+}
+
+
+KInstance *PcFactory::s_instance = 0;
+KAboutData *PcFactory::s_about = 0;
+
+
+PcFactory::PcFactory( QObject *parent, const char *name)
+ : KLibFactory(parent,name)
+{
+}
+
+PcFactory::~PcFactory()
+{
+ if(s_instance)
+ {
+ delete s_instance;
+ s_instance=0;
+ }
+
+ if(s_about)
+ {
+ delete s_about;
+ s_about=0;
+ }
+}
+
+
+QObject *PcFactory::createObject( QObject *parent, const char *name
+ , const char *classname, const QStringList &)
+{
+ if(QCString(classname) != "SearchEngine")
+ {
+ kdError() << "not a SearchEngine requested" << endl;
+ return 0;
+ }
+
+ return new PoCompendium(parent,name);
+}
+
+
+KInstance *PcFactory::instance()
+{
+ if(!s_instance)
+ {
+ s_about = new KAboutData( "pocompendium", I18N_NOOP("PO Compendium")
+ , "1.0"
+ , I18N_NOOP("A module for searching in a PO file")
+ , KAboutData::License_GPL
+ , "Copyright 2000-2001, Matthias Kiefer"
+ ,0,0, "kiefer@kde.org");
+
+ s_about->addAuthor("Matthias Kiefer",0,"kiefer@kde.org");
+
+ s_instance = new KInstance(s_about);
+ }
+
+ return s_instance;
+}
+
+#include "pc_factory.moc"
diff --git a/kbabel/kbabeldict/modules/pocompendium/pc_factory.h b/kbabel/kbabeldict/modules/pocompendium/pc_factory.h
new file mode 100644
index 00000000..d52fadfe
--- /dev/null
+++ b/kbabel/kbabeldict/modules/pocompendium/pc_factory.h
@@ -0,0 +1,60 @@
+/* ****************************************************************************
+ This file is part of KBabel
+
+ Copyright (C) 2000 by Matthias Kiefer
+ <matthias.kiefer@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.
+
+ 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, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+ In addition, as a special exception, the copyright holders give
+ permission to link the code of this program with any edition of
+ the Qt library by Trolltech AS, Norway (or with modified versions
+ of Qt that use the same license as Qt), and distribute linked
+ combinations including the two. You must obey the GNU General
+ Public License in all respects for all of the code used other than
+ Qt. If you modify this file, you may extend this exception to
+ your version of the file, but you are not obligated to do so. If
+ you do not wish to do so, delete this exception statement from
+ your version.
+
+**************************************************************************** */
+
+
+#ifndef PC_FACTORY_H
+#define PC_FACTORY_H
+
+#include <klibloader.h>
+class KInstance;
+class KAboutData;
+
+class PcFactory : public KLibFactory
+{
+ Q_OBJECT
+public:
+ PcFactory( QObject *parent=0, const char *name=0);
+ ~PcFactory();
+
+ virtual QObject *createObject( QObject *parent=0, const char *name=0
+ , const char *classname="QObject"
+ , const QStringList &args = QStringList());
+
+ static KInstance *instance();
+
+private:
+ static KInstance *s_instance;
+ static KAboutData *s_about;
+};
+
+#endif
diff --git a/kbabel/kbabeldict/modules/pocompendium/pocompendium.cpp b/kbabel/kbabeldict/modules/pocompendium/pocompendium.cpp
new file mode 100644
index 00000000..0cd79fb3
--- /dev/null
+++ b/kbabel/kbabeldict/modules/pocompendium/pocompendium.cpp
@@ -0,0 +1,1246 @@
+/* ****************************************************************************
+ This file is part of KBabel
+
+ Copyright (C) 2000 by Matthias Kiefer
+ <matthias.kiefer@gmx.de>
+ 2003 by Stanislav Visnovsky
+ <visnovsky@kde.org>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the 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, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+ In addition, as a special exception, the copyright holders give
+ permission to link the code of this program with any edition of
+ the Qt library by Trolltech AS, Norway (or with modified versions
+ of Qt that use the same license as Qt), and distribute linked
+ combinations including the two. You must obey the GNU General
+ Public License in all respects for all of the code used other than
+ Qt. If you modify this file, you may extend this exception to
+ your version of the file, but you are not obligated to do so. If
+ you do not wish to do so, delete this exception statement from
+ your version.
+
+**************************************************************************** */
+#include <klocale.h>
+#include <kapplication.h>
+#include <kcmdlineargs.h>
+#include <kstaticdeleter.h>
+#include <kdebug.h>
+#include <kglobal.h>
+#include <kinstance.h>
+#include <kio/netaccess.h>
+
+#include <qregexp.h>
+#include <qtextstream.h>
+#include <qtimer.h>
+
+#include "resources.h"
+#include "compendiumdata.h"
+#include "pocompendium.h"
+#include "preferenceswidget.h"
+#include "pc_factory.h"
+
+#include <catalog.h>
+#include <catalogitem.h>
+
+// ngram length and minimal matching for fuzzy search
+#define NGRAM_LEN 3
+#define LIM_NGRAM 50
+
+using namespace KBabel;
+
+static KStaticDeleter< QDict<CompendiumData> > compDataDeleter;
+QDict<CompendiumData> *PoCompendium::_compDict = 0;
+
+PoCompendium::PoCompendium(QObject *parent, const char *name)
+ : SearchEngine(parent, name)
+{
+ prefWidget=0;
+ data=0;
+ error=false;
+ stop=false;
+ active=false;
+ initialized=false;
+ loading=false;
+
+ langCode = KGlobal::locale()->language();
+
+ caseSensitive = false;
+ ignoreFuzzy=true;
+ wholeWords=true;
+
+ matchEqual = true;
+ matchNGram = true;
+ matchIsContained = false;
+ matchContains = true;
+ matchWords=true;
+
+
+ loadTimer = new QTimer(this);
+ connect(loadTimer,SIGNAL(timeout()),this,SLOT(slotLoadCompendium()));
+}
+
+PoCompendium::~PoCompendium()
+{
+ if(isSearching())
+ {
+ stopSearch();
+ }
+
+ unregisterData();
+}
+
+bool PoCompendium::isReady() const
+{
+ return (isSearching() || !error);
+}
+
+
+bool PoCompendium::isSearching() const
+{
+ return (active || loading);
+}
+
+
+void PoCompendium::saveSettings(KConfigBase *config )
+{
+ if(autoUpdate && prefWidget && prefWidget->settingsChanged())
+ {
+ applySettings();
+ }
+
+ config->writeEntry("CaseSensitive",caseSensitive);
+ config->writeEntry("IgnoreFuzzy", ignoreFuzzy);
+ config->writeEntry("WholeWords", wholeWords);
+
+ config->writeEntry("MatchEqual", matchEqual);
+ config->writeEntry("MatchIsContained",matchIsContained);
+ config->writeEntry("MatchContains", matchContains);
+ config->writeEntry("MatchWords", matchWords);
+ config->writeEntry("MatchNGram", matchNGram);
+
+ config->writeEntry("Compendium", url);
+}
+
+void PoCompendium::readSettings(KConfigBase *config)
+{
+ caseSensitive = config->readBoolEntry("CaseSensitive", false);
+ ignoreFuzzy = config->readBoolEntry("IgnoreFuzzy",true);
+ wholeWords = config->readBoolEntry("WholeWords",true);
+
+ matchEqual = config->readBoolEntry("MatchEqual", true);
+ matchIsContained = config->readBoolEntry("MatchIsContained", false);
+ matchContains = config->readBoolEntry("MatchContains",true);
+ matchWords = config->readBoolEntry("MatchWords",true);
+ matchNGram = config->readBoolEntry("MatchNGram",true);
+
+ QString newPath = config->readEntry("Compendium","http://i18n.kde.org/po_overview/@LANG@.messages");
+ if(!initialized)
+ {
+ url = newPath;
+ }
+ else if(newPath != url)
+ {
+ url = newPath;
+ loadCompendium();
+ }
+
+
+ restoreSettings();
+}
+
+PrefWidget *PoCompendium::preferencesWidget(QWidget *parent)
+{
+ prefWidget = new CompendiumPreferencesWidget(parent,"pocompendium_prefwidget");
+ kdDebug(KBABEL_SEARCH) << "PreferencesWidget is " << prefWidget << endl;
+ connect(prefWidget, SIGNAL(applySettings()), this, SLOT(applySettings()));
+ connect(prefWidget, SIGNAL(restoreSettings())
+ , this, SLOT(restoreSettings()));
+
+ restoreSettings();
+
+ return prefWidget;
+}
+
+const KAboutData *PoCompendium::about() const
+{
+ return PcFactory::instance()->aboutData();
+}
+
+
+QString PoCompendium::name() const
+{
+ return i18n("PO Compendium");
+}
+
+QString PoCompendium::id() const
+{
+ return "pocompendium";
+}
+
+QString PoCompendium::lastError()
+{
+ return errorMsg;
+}
+
+bool PoCompendium::searchExact(const QString& text, uint pluralForm, QPtrList<SearchResult>& results, QValueList<int>& foundIndices, QValueList<int>& )
+{
+ const int *index = data->exactDict(text);
+ if(index)
+ {
+ foundIndices.append(*index);
+
+ SearchResult *result = new SearchResult;
+ result->requested = text;
+ result->found = data->catalog()->msgid(*index);
+#warning kdWarning() << "PoCompendium can't return plural form translation" << endl;
+ result->translation = data->catalog()->msgstr(*index).first();
+ result->score = 100;
+
+ TranslationInfo *info = new TranslationInfo;
+ info->location = directory(realURL,0);
+ info->translator = catalogInfo.lastTranslator;
+ info->description = data->catalog()->comment(*index);
+ result->descriptions.append(info);
+
+ addResult(result, results);
+ return true;
+ }
+
+ return false;
+
+}
+
+bool PoCompendium::searchCaseInsensitive(const QString& text, uint pluralForm, QPtrList<SearchResult>& results, QValueList<int>& foundIndices, QValueList<int>& )
+{
+ QString searchStr = text.lower();
+
+ const QValueList<int> *indexList = data->allDict(text.lower());
+ if(indexList)
+ {
+ QValueList<int>::ConstIterator it;
+ for( it = indexList->begin(); it != indexList->end(); ++it )
+ {
+ if(foundIndices.contains(*it))
+ {
+ continue;
+ }
+
+ if(ignoreFuzzy && data->catalog()->isFuzzy(*it))
+ {
+ continue;
+ }
+
+
+ QString origStr = data->catalog()->msgid(*it).first();
+ origStr = CompendiumData::simplify(origStr);
+
+
+ if(!caseSensitive)
+ {
+ origStr = origStr.lower();
+ }
+
+ if(origStr==searchStr)
+ {
+ foundIndices.append(*it);
+
+ SearchResult *result = new SearchResult;
+ result->requested = text;
+ result->found = data->catalog()->msgid(*it);
+ result->translation = *(data->catalog()->msgstr(*it).at(pluralForm));
+ result->score = score(result->requested,*(result->found.at(pluralForm)));
+
+ TranslationInfo *info = new TranslationInfo;
+ info->location = directory(realURL,0);
+ info->translator = catalogInfo.lastTranslator;
+ info->description = data->catalog()->comment(*it);
+ result->descriptions.append(info);
+
+ addResult(result, results);
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
+bool PoCompendium::searchTextOnly(const QString& text, uint pluralForm, QPtrList<SearchResult>& results, QValueList<int>& foundIndices, QValueList<int>& )
+{
+ QString searchStr = text.lower();
+ QString t = text;
+ t.remove( " " );
+
+ const QValueList<int> *indexList = data->textonlyDict(t.lower());
+ if(indexList)
+ {
+ QValueList<int>::ConstIterator it;
+ for( it = indexList->begin(); it != indexList->end(); ++it )
+ {
+ if(foundIndices.contains(*it))
+ {
+ continue;
+ }
+
+ if(ignoreFuzzy && data->catalog()->isFuzzy(*it))
+ {
+ continue;
+ }
+
+
+ QString origStr = data->catalog()->msgid(*it).first();
+ origStr = CompendiumData::simplify(origStr);
+
+
+ foundIndices.append(*it);
+
+ SearchResult *result = new SearchResult;
+ result->requested = text;
+ result->found = data->catalog()->msgid(*it).first();
+#warning kdWarning() << "PoCompendium can't return plural form translation" << endl;
+ result->translation = data->catalog()->msgstr(*it).first();
+ result->score = score(result->requested,*(result->found.at(pluralForm)));
+
+ TranslationInfo *info = new TranslationInfo;
+ info->location = directory(realURL,0);
+ info->translator = catalogInfo.lastTranslator;
+ info->description = data->catalog()->comment(*it);
+ result->descriptions.append(info);
+
+ addResult(result, results);
+ return true;
+ }
+ }
+ return false;
+}
+
+bool PoCompendium::searchWords(const QString& searchStr, uint pluralForm, QPtrList<SearchResult>& results, QValueList<int>& foundIndices, QValueList<int>& checkedIndices )
+{
+ uint checkCounter = 0;
+ bool foundResults = false;
+
+ QStringList wList = CompendiumData::wordList(searchStr);
+ for ( QStringList::Iterator wit = wList.begin()
+ ; wit != wList.end(); ++wit )
+ {
+ if(stop)
+ break;
+
+ const QValueList<int> *indexList = data->wordDict((*wit).lower());
+ if(indexList)
+ {
+ QValueList<int>::ConstIterator it;
+ for( it = indexList->begin(); it != indexList->end(); ++it )
+ {
+ if(stop)
+ break;
+
+ if(foundIndices.contains(*it))
+ {
+ continue;
+ }
+
+ if(checkedIndices.contains(*it))
+ {
+ continue;
+ }
+
+ checkedIndices.append(*it);
+ checkCounter++;
+
+ if(ignoreFuzzy && data->catalog()->isFuzzy(*it))
+ {
+ continue;
+ }
+
+ if( (100*(checkCounter+1))%catalogInfo.total < 100)
+ {
+ emit progress( (50*checkCounter+1)/catalogInfo.total);
+ }
+
+ kapp->processEvents(100);
+
+ QString origStr = data->catalog()->msgid(*it).first();
+ origStr = CompendiumData::simplify(origStr);
+
+
+ if(!caseSensitive)
+ {
+ origStr = origStr.lower();
+ }
+
+ bool found = false;
+ if(matchWords)
+ {
+ if(!caseSensitive)
+ {
+ found=true;
+ }
+ else
+ {
+ QString s=*wit;
+ QString o=origStr;
+
+ if(wholeWords)
+ {
+ s=" "+*wit+" ";
+ o=" "+origStr+" ";
+ }
+ if(o.contains(s))
+ {
+ found=true;
+ }
+ }
+ }
+
+
+ if(!found && origStr==searchStr)
+ {
+ found =true;
+ }
+
+ // if there is an string which just contains ignored characters,
+ // continue
+ if(!found && origStr.isEmpty() ||
+ (origStr.length() == 1 && searchStr.length() > 1))
+ {
+ continue;
+ }
+
+
+ if(!found && matchContains && !wholeWords)
+ {
+ QString s=maskString(searchStr);
+ QRegExp searchReg(s);
+
+ if(searchReg.search(origStr) >= 0)
+ found=true;
+ }
+
+ if(!found && matchIsContained && !wholeWords)
+ {
+ QString s=maskString(origStr);
+ QRegExp reg(s);
+
+ if(reg.search(searchStr) >= 0)
+ {
+ found = true;
+ }
+ }
+ if(!found && matchWords && !wholeWords)
+ {
+ QStringList list = CompendiumData::wordList(searchStr);
+
+ for ( QStringList::Iterator wit2 = list.begin()
+ ; wit2 != list.end(); ++wit2 )
+ {
+ QString s=maskString(*wit2);
+ QRegExp reg(s);
+
+ if(reg.search(origStr) >= 0)
+ {
+ found = true;
+ }
+ }
+ }
+
+ if(found)
+ {
+ foundIndices.append(*it);
+
+ SearchResult *result = new SearchResult;
+ result->requested = searchStr; // FIXME:here should be the original text
+ result->found = data->catalog()->msgid(*it).first();
+#warning kdWarning() << "PoCompendium can't return plural form translation" << endl;
+ result->translation = data->catalog()->msgstr(*it).first();
+ result->score = score(result->requested,*(result->found.at(pluralForm)));
+
+ TranslationInfo *info = new TranslationInfo;
+ info->location = directory(realURL,0);
+ info->translator = catalogInfo.lastTranslator;
+ info->description = data->catalog()->comment(*it);
+ result->descriptions.append(info);
+
+ addResult(result, results);
+
+ foundResults = true;
+ }
+ }
+ }
+ }
+
+ return foundResults;
+}
+
+bool PoCompendium::searchNGram(const QString& searchStr, uint pluralForm, QPtrList<SearchResult>& results, QValueList<int>& foundIndices, QValueList<int>& checkedIndices )
+{
+ uint checkCounter = 0;
+ bool foundResults = false;
+
+ QRegExp searchReg;
+ if(matchContains)
+ {
+ QString s=maskString(searchStr);
+ searchReg.setPattern(s);
+ }
+
+
+ bool breakLoop=false;
+ int i=-1;
+ while(!breakLoop)
+ {
+ if(stop)
+ {
+ breakLoop=true;
+ break;
+ }
+
+ i++;
+
+ if(i >= catalogInfo.total)
+ {
+ breakLoop = true;
+ break;
+ }
+
+ if( (100*(checkCounter+1))%catalogInfo.total < 100)
+ {
+ emit progress( 50+(50*(checkCounter+1))/catalogInfo.total);
+ }
+
+ if(checkedIndices.contains(i))
+ {
+ continue;
+ }
+
+ checkedIndices.append(i);
+ checkCounter++;
+
+ if(ignoreFuzzy && data->catalog()->isFuzzy(i))
+ {
+ continue;
+ }
+
+ if(foundIndices.contains(i))
+ {
+ continue;
+ }
+
+ kapp->processEvents(100);
+
+ QString origStr = data->catalog()->msgid(i).first();
+ origStr = CompendiumData::simplify(origStr);
+
+ if(!caseSensitive)
+ {
+ origStr = origStr.lower();
+ }
+
+
+ // if there is an string which just contains ignored characters,
+ // continue
+ if(origStr.isEmpty() ||
+ (origStr.length() == 1 && searchStr.length() > 1))
+ {
+ continue;
+ }
+
+ bool found = false;
+ if(matchContains && searchReg.search(origStr) >= 0)
+ {
+ found=true;
+ }
+
+ if(!found && matchIsContained)
+ {
+ QString s=maskString(origStr);
+ QRegExp reg(s);
+
+ if(reg.search(searchStr) >= 0)
+ {
+ found = true;
+ }
+ }
+
+ if(!found && matchWords)
+ {
+ QStringList list = CompendiumData::wordList(searchStr);
+
+ for ( QStringList::Iterator wit2 = list.begin()
+ ; wit2 != list.end(); ++wit2 )
+ {
+ QString s=maskString(*wit2);
+
+ if(wholeWords)
+ {
+ origStr = " "+origStr+" ";
+ s=" "+s+" ";
+ }
+ QRegExp reg(s);
+
+ if(reg.search(origStr) >= 0)
+ {
+ found = true;
+ }
+ }
+ }
+
+ if(!found && matchNGram)
+ {
+ // to get more results one could
+ // interchange searchStr and origStr when
+ // the latter is shorter
+
+ found = ( ngramMatch(searchStr,origStr,NGRAM_LEN)
+ > LIM_NGRAM );
+ }
+
+ if(found)
+ {
+ foundIndices.append(i);
+
+ SearchResult *result = new SearchResult;
+ result->requested = searchStr;
+ result->found = data->catalog()->msgid(i).first();
+ result->translation = data->catalog()->msgstr(i).first();
+#warning kdWarning() << "PoCompendium can't return plural form translation" << endl;
+ result->score = score(result->requested,*(result->found.at(pluralForm)));
+
+ TranslationInfo *info = new TranslationInfo;
+ info->location = directory(realURL,0);
+ info->translator = catalogInfo.lastTranslator;
+ info->description = data->catalog()->comment(i);
+ result->descriptions.append(info);
+
+ addResult(result, results);
+
+ foundResults = true;
+ }
+ }
+
+ return foundResults;
+}
+
+bool PoCompendium::startSearch(const QString& text, uint pluralForm, const SearchFilter* filter)
+{
+ if(autoUpdate && prefWidget && prefWidget->settingsChanged())
+ {
+ applySettings();
+ }
+
+ if(isSearching())
+ return false;
+
+ clearResults();
+ stop = false;
+ active = true;
+
+ if(!initialized)
+ {
+ if(loadTimer->isActive())
+ loadTimer->stop();
+
+ slotLoadCompendium();
+ }
+
+ if(error || !data)
+ {
+ active = false;
+ return false;
+ }
+
+ if(data->active())
+ {
+ active = false;
+ return true;
+ }
+
+ emit started();
+
+
+ QValueList<int> foundIndices;
+ QValueList<int> checkedIndices;
+
+ // first, exact search
+ searchExact(text, pluralForm, results, foundIndices, checkedIndices);
+
+ QString searchStr=CompendiumData::simplify(text);
+
+
+ if(!caseSensitive)
+ {
+ searchStr = searchStr.lower();
+
+ // do case insensite search if necessary
+ searchCaseInsensitive(searchStr, pluralForm, results, foundIndices, checkedIndices);
+ }
+
+ // search without whitespace
+ searchTextOnly(searchStr, pluralForm, results, foundIndices, checkedIndices);
+
+ // now, search based on words (contains, is contained, etc)
+ searchWords(searchStr, pluralForm, results, foundIndices, checkedIndices);
+
+
+ if( matchNGram ||
+ (!wholeWords && (matchContains || matchIsContained || matchWords))
+ )
+ {
+ // search based on ngrams
+ searchNGram(searchStr, pluralForm, results, foundIndices, checkedIndices);
+ }
+
+ emit progress(100);
+
+ active = false;
+ stop = false;
+ emit finished();
+
+ return true;
+}
+
+void PoCompendium::stopSearch()
+{
+ stop=true;
+}
+
+
+void PoCompendium::applySettings()
+{
+ if(!prefWidget)
+ return;
+
+ if(isSearching())
+ stopSearch();
+
+ caseSensitive = prefWidget->caseSensitive();
+ ignoreFuzzy = prefWidget->ignoreFuzzy();
+ wholeWords = prefWidget->wholeWords();
+
+ matchEqual = prefWidget->matchEqual();
+ matchNGram = prefWidget->matchNGram();
+ matchIsContained = prefWidget->matchIsContained();
+ matchContains = prefWidget->matchContains();
+ matchWords = prefWidget->matchWords();
+
+
+ bool needLoading=false;
+
+
+ QString newPath = prefWidget->url();
+ if(!initialized)
+ {
+ url = newPath;
+ }
+ else if(newPath != url)
+ {
+ url = newPath;
+ needLoading = true;
+ }
+
+ if(needLoading)
+ {
+ loadCompendium();
+ initialized=false;
+ }
+}
+
+void PoCompendium::restoreSettings()
+{
+ if(!prefWidget)
+ return;
+
+ prefWidget->setCaseSensitive(caseSensitive);
+ prefWidget->setIgnoreFuzzy(ignoreFuzzy);
+ prefWidget->setWholeWords(wholeWords);
+ prefWidget->setURL(url);
+
+ prefWidget->setMatchEqual(matchEqual);
+ prefWidget->setMatchNGram(matchNGram);
+ prefWidget->setMatchIsContained(matchIsContained);
+ prefWidget->setMatchContains(matchContains);
+ prefWidget->setMatchWords(matchWords);
+}
+
+void PoCompendium::loadCompendium()
+{
+ if(!loading && !loadTimer->isActive())
+ loadTimer->start(100,true);
+}
+
+void PoCompendium::slotLoadCompendium()
+{
+ if(loading)
+ return;
+
+ if(loadTimer->isActive())
+ loadTimer->stop();
+
+ loading = true;
+
+ if(data)
+ {
+ unregisterData();
+ }
+
+
+ QString path=url;
+
+ if(path.contains("@LANG@"))
+ {
+ path.replace("@LANG@",langCode);
+ }
+ KURL u=KCmdLineArgs::makeURL(path.local8Bit());
+ realURL = u.url();
+
+ registerData();
+
+
+ if(!data)
+ {
+ kdError() << "no data object in pocompendium?" << endl;
+
+ loading=false;
+ return;
+ }
+
+ if(!data->initialized())
+ {
+ if(!data->active())
+ {
+ data->load(u);
+ recheckData();
+ if(error)
+ {
+ emit hasError(errorMsg);
+ }
+ }
+ else
+ {
+ connect(data, SIGNAL(progressEnds()), this, SLOT(recheckData()));
+ }
+ }
+ else
+ {
+ recheckData();
+ if(error)
+ {
+ emit hasError(errorMsg);
+ }
+ }
+
+ initialized=true;
+}
+
+void PoCompendium::recheckData()
+{
+ if(data)
+ {
+ disconnect(data, SIGNAL(progressEnds()), this, SLOT(recheckData()));
+
+ error = data->hasErrors();
+ errorMsg = data->errorMsg();
+
+ if(!error)
+ {
+ catalogInfo = Catalog::headerInfo(data->catalog()->header());
+ catalogInfo.total = data->catalog()->numberOfEntries();
+ catalogInfo.fuzzy = data->catalog()->numberOfFuzzies();
+ catalogInfo.untranslated = data->catalog()->numberOfUntranslated();
+ }
+ }
+
+ loading=false;
+}
+
+QString PoCompendium::maskString(QString s)
+{
+ s.replace("\\","\\\\");
+ s.replace("\?","\\?");
+ s.replace("[","\\[");
+ s.replace(".","\\.");
+ s.replace("*","\\*");
+ s.replace("+","\\+");
+ s.replace("^","\\^");
+ s.replace("$","\\$");
+ s.replace("(","\\(");
+ s.replace(")","\\)");
+ s.replace("{","\\{");
+ s.replace("}","\\}");
+ s.replace("|","\\|");
+
+ return s;
+}
+
+void PoCompendium::addResult(SearchResult *result, QPtrList<SearchResult>& res)
+{
+ if(res.last() && res.last()->score >= result->score)
+ {
+ res.append(result);
+ }
+ else
+ {
+ SearchResult *sr;
+ for(sr = res.first(); sr != 0; sr=res.next())
+ {
+ if(sr->score < result->score)
+ {
+ int pos = res.at();
+ if( pos < 0 ) pos = 0;
+ res.insert( pos,result);
+ emit resultsReordered();
+ break;
+ }
+ }
+
+ if(!sr)
+ {
+ res.append(result);
+ }
+ }
+
+ emit numberOfResultsChanged(res.count());
+ emit resultFound(result);
+}
+
+
+void PoCompendium::setLanguageCode(const QString& lang)
+{
+ if(initialized && url.contains("@LANG@") && lang!=langCode
+ && !loadTimer->isActive() )
+ {
+ initialized=false;
+ }
+
+ langCode=lang;
+}
+
+QString PoCompendium::translate(const QString& text, uint pluralForm)
+{
+ if(!initialized)
+ {
+ if(loadTimer->isActive())
+ loadTimer->stop();
+
+ slotLoadCompendium();
+ }
+
+ if(error || !data || data->active())
+ {
+ return QString::null;
+ }
+
+
+ const int *index = data->exactDict(text);
+
+ if(index)
+ {
+#warning kdWarning() << "PoCompendium can't return plural form translation" << endl;
+ return data->catalog()->msgstr(*index).first();
+ }
+
+ return QString::null;
+}
+
+QString PoCompendium::fuzzyTranslation(const QString& text, int &score, const uint pluralForm)
+{
+ if(!initialized)
+ {
+ if(loadTimer->isActive())
+ loadTimer->stop();
+
+ slotLoadCompendium();
+ }
+
+ if(error || !data || data->active())
+ {
+ return QString::null;
+ }
+
+ // try to find fuzzy string
+ bool breakLoop = false;
+ stop = false;
+ int i=-1;
+ int best_matching = -1;
+ int best_match = 0;
+ int total = data->catalog()->numberOfEntries();
+
+ QString searchStr = CompendiumData::simplify(text);
+
+ //kdDebug(750) << "find best match for " << searchStr << endl;
+
+ while(!breakLoop)
+ {
+
+ // progress and loop control
+ if(stop)
+ {
+ breakLoop=true;
+ break;
+ }
+
+ i++;
+
+ if(i >= total)
+ {
+ breakLoop = true;
+ break;
+ }
+
+ if( (100*(i+1))%total < 100)
+ {
+ emit progress( (100*(i+1))/total);
+ }
+
+ // get a message from the catalog FIXME: plurals
+ QString origStr = data->catalog()->msgid(i).first();
+ origStr = CompendiumData::simplify(origStr);
+
+ // don't match too long strings for short search string
+ if (origStr.length() > 2*searchStr.length())
+ continue;
+ // kdDebug(750) << i << ": matching " << origStr << endl;
+
+ int ngram_result = ngramMatch(searchStr,origStr);
+
+ if (ngram_result > best_match) {
+ best_match = ngram_result;
+ best_matching = i;
+
+ // kdDebug(750) << "[" << ngram_result << "] " << text << "-"
+ // << origStr << endl;
+ }
+ }
+
+ if (best_match > LIM_NGRAM) {
+ score = best_match;
+#warning kdWarning() << "PoCompendium can't return plural form translation" << endl;
+ return data->catalog()->msgstr(best_matching).first();
+ }
+
+ return QString::null;
+}
+
+
+QString PoCompendium::searchTranslation(const QString& text, int &sc, const uint pluralForm)
+{
+ if(autoUpdate && prefWidget && prefWidget->settingsChanged())
+ {
+ applySettings();
+ }
+
+ if(isSearching())
+ return QString::null;
+
+ clearResults();
+ stop = false;
+ active = true;
+
+ if(!initialized)
+ {
+ if(loadTimer->isActive())
+ loadTimer->stop();
+
+ slotLoadCompendium();
+ }
+
+ if(error || !data)
+ {
+ active = false;
+ return QString::null;
+ }
+
+ if(data->active())
+ {
+ active = false;
+ return QString::null;
+ }
+
+ emit started();
+
+ QPtrList<SearchResult> res;
+
+ QValueList<int> foundIndices;
+ QValueList<int> checkedIndices;
+
+ // first, exact search
+ if( searchExact(text, pluralForm, res, foundIndices, checkedIndices) )
+ {
+ active = false;
+ stop = false;
+ emit finished();
+
+ // found, this is the best
+ sc = res.first()->score;
+ return res.first()->translation;
+ }
+
+ QString searchStr=CompendiumData::simplify(text);
+
+
+ if(!caseSensitive)
+ {
+ searchStr = searchStr.lower();
+
+ // do case insensite search if necessary
+ if( searchCaseInsensitive(searchStr, pluralForm, res, foundIndices, checkedIndices) )
+ {
+ active = false;
+ stop = false;
+ emit finished();
+
+ // found, return this one
+ sc = res.first()->score;
+ return res.first()->translation;
+ }
+ }
+
+ // search without whitespace
+ QString s = searchStr;
+ s.remove( ' ' );
+ if( searchTextOnly(s, pluralForm, res, foundIndices, checkedIndices) )
+ {
+ active = false;
+ stop = false;
+ emit finished();
+
+ // found, return this one
+ sc = res.first()->score;
+ return res.first()->translation;
+ }
+
+ // now, search based on words (contains, is contained, etc)
+ searchWords(searchStr, pluralForm, res, foundIndices, checkedIndices);
+
+ if( matchNGram ||
+ (!wholeWords && (matchContains || matchIsContained || matchWords))
+ )
+ {
+ // search based on ngrams
+ searchNGram(searchStr, pluralForm, res, foundIndices, checkedIndices);
+ }
+
+ active = false;
+ stop = false;
+
+ // now, pick up the best one from not exact translations
+ if( res.count() > 0 ) {
+
+ emit finished();
+
+ sc = res.first()->score;
+ return res.first()->translation;
+ }
+
+ sc = 0;
+
+ return QString::null;
+}
+
+
+void PoCompendium::unregisterData()
+{
+ if(data)
+ {
+ disconnect(data, SIGNAL(progressStarts(const QString&)), this
+ , SIGNAL(progressStarts(const QString&)));
+ disconnect(data, SIGNAL(progressEnds()), this , SIGNAL(progressEnds()));
+ disconnect(data, SIGNAL(progress(int)), this , SIGNAL(progress(int)));
+
+ if(data->active())
+ {
+ disconnect(data,SIGNAL(progressEnds()),this,SLOT(recheckData()));
+ }
+
+ if(data->unregisterObject(this))
+ {
+ if(!data->active())
+ {
+ compendiumDict()->remove(realURL);
+ }
+ else
+ {
+ connect(data,SIGNAL(progressEnds()),this,SLOT(removeData()));
+ }
+ }
+
+ data=0;
+ }
+}
+
+void PoCompendium::registerData()
+{
+ data = compendiumDict()->find(realURL);
+ if(!data)
+ {
+ data = new CompendiumData;
+ compendiumDict()->insert(realURL,data);
+ }
+
+ data->registerObject(this);
+
+ if(data->active())
+ {
+ emit progressStarts(i18n("Loading PO compendium"));
+ }
+
+ connect(data, SIGNAL(
+ progressStarts(const QString&)), this
+ , SIGNAL(progressStarts(const QString&)));
+ connect(data, SIGNAL(progressEnds()), this , SIGNAL(progressEnds()));
+ connect(data, SIGNAL(progress(int)), this , SIGNAL(progress(int)));
+}
+
+void PoCompendium::removeData()
+{
+ const QObject *s=sender();
+ if(s && s->inherits("CompendiumData"))
+ {
+ const CompendiumData *d=static_cast<const CompendiumData*>(s);
+ if(d)
+ {
+ QDictIterator<CompendiumData> it(*compendiumDict());
+ while(it.current())
+ {
+ if(it.current() == d)
+ {
+ if(!d->hasObjects())
+ {
+ compendiumDict()->remove(it.currentKey());
+ }
+
+ break;
+ }
+
+ ++it;
+ }
+ }
+
+ }
+}
+
+QDict<CompendiumData> *PoCompendium::compendiumDict()
+{
+ if(!_compDict)
+ {
+ _compDict=compDataDeleter.setObject( new QDict<CompendiumData> );
+ _compDict->setAutoDelete(true);
+ }
+
+ return _compDict;
+}
+
+
+
+#include "pocompendium.moc"
diff --git a/kbabel/kbabeldict/modules/pocompendium/pocompendium.desktop b/kbabel/kbabeldict/modules/pocompendium/pocompendium.desktop
new file mode 100644
index 00000000..ac9ee368
--- /dev/null
+++ b/kbabel/kbabeldict/modules/pocompendium/pocompendium.desktop
@@ -0,0 +1,50 @@
+[Desktop Entry]
+Type=Service
+Name=PO Compendium Module for KBabelDict
+Name[bg]=PO компендиум за KBabelDict
+Name[bs]=Modul PO kompendijuma za KBabelDict
+Name[ca]=Mòdul del Compendi PO per a KBabelDict
+Name[cs]=Modul s PO kompendiem pro KBabelDict
+Name[cy]=Modiwl Compendiwm PO i KBabelDict
+Name[da]=PO-kompendium-module for KBabelDict
+Name[de]=PO-Kompendium-Modul für KBabelDict
+Name[el]=ΆÏθÏωμα επιτομής PO για το KBabelDict
+Name[es]=Módulo de compendio de PO para KBabelDict
+Name[et]=KBabelDicti PO kompendiumi moodul
+Name[eu]=PO laburpen modulua KBabelDict-entzat
+Name[fa]=پیمانۀ مختصر PO برای KBabelDict
+Name[fi]=KBabelDict-ohjelman PO-kokoelmatiedostomoduuli
+Name[fr]=Module de fichier de référence PO pour KBabelDict
+Name[gl]=Módulo de compendio PO para KBabelDict
+Name[hi]=के-बेबल-डिकà¥à¤¶ के लिठपीओ कमà¥à¤ªà¥‡à¤‚डियम मॉडà¥à¤¯à¥‚ल
+Name[hu]=PO összefoglaló modul a KBabelDicthez
+Name[is]=PO ágrips eining fyrir KBabel orðabókina
+Name[it]=Modulo PO Compendium per KBabelDict
+Name[ja]=KBabelDict PO è¦ç´„モジュール
+Name[ka]=PO კáƒáƒœáƒ¡áƒžáƒ”ქტის მáƒáƒ“ული KBabelDict-სთვის
+Name[kk]=KBabelDict-тың PO аудармалар жиынтық модулі
+Name[lt]=KBabelDict PO tekstyno modulis
+Name[ms]=Modul Kompendium PO untuk KBabelDict
+Name[nb]=PO-kompendiummodul for KBabelDict
+Name[nds]=PO-Kompendiummoduul för KBabelDict
+Name[ne]=KBabelDict का लागि संकà¥à¤·à¥‡à¤ª पीओ मोडà¥à¤¯à¥à¤²
+Name[nl]=PO-samenvattingmodule voor KBabelDict
+Name[nn]=PO-kompendiemodul for KBabelDict
+Name[pa]=ਕੇਬਬੇਲ-ਸ਼ਬਦਕੋਸ਼ ਲਈ PO ਸੰਖੇਪ ਮੈਡੀਊਲ
+Name[pl]=Moduł Kompendium PO dla KBabelDict
+Name[pt]=Módulo de Compêndio de PO para o KBabelDict
+Name[pt_BR]=Módulo de Compêndio PO para o KBabelDict
+Name[ru]=Модуль опиÑÐ°Ð½Ð¸Ñ PO Ð´Ð»Ñ KBabelDict
+Name[sk]=Kompendium pre KBabelDict
+Name[sl]=Modul zbornika PO za KBabelDict
+Name[sr]=Модул PO зборника за KBabelDict
+Name[sr@Latn]=Modul PO zbornika za KBabelDict
+Name[sv]=PO-kompendiemodul för Kbabeldict
+Name[ta]=Kபாபேலà¯à®•à¯à®•à®¾à®© காமà¯à®ªà¯†à®©à¯à®Ÿà®¿à®¯à®®à¯ PO கூறà¯
+Name[tg]=Модули таÑвири PO барои KBabelDict
+Name[tr]=KBabelDict için PO Özet Modülü
+Name[uk]=Модуль збірки перекладів PO Ð´Ð»Ñ KBabelDict
+Name[zh_CN]=KBabelDict çš„ PO 概è¦è¯å…¸æ¨¡å—
+Name[zh_TW]=KBabelDict PO 摘è¦æ¨¡çµ„
+X-KDE-Library=kbabeldict_pocompendium
+ServiceTypes=KBabelDictModule
diff --git a/kbabel/kbabeldict/modules/pocompendium/pocompendium.h b/kbabel/kbabeldict/modules/pocompendium/pocompendium.h
new file mode 100644
index 00000000..6d92fb58
--- /dev/null
+++ b/kbabel/kbabeldict/modules/pocompendium/pocompendium.h
@@ -0,0 +1,147 @@
+/* ****************************************************************************
+ This file is part of KBabel
+
+ Copyright (C) 2000 by Matthias Kiefer
+ <matthias.kiefer@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.
+
+ 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, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+ In addition, as a special exception, the copyright holders give
+ permission to link the code of this program with any edition of
+ the Qt library by Trolltech AS, Norway (or with modified versions
+ of Qt that use the same license as Qt), and distribute linked
+ combinations including the two. You must obey the GNU General
+ Public License in all respects for all of the code used other than
+ Qt. If you modify this file, you may extend this exception to
+ your version of the file, but you are not obligated to do so. If
+ you do not wish to do so, delete this exception statement from
+ your version.
+
+**************************************************************************** */
+
+#ifndef POCOMPENDIUM_H
+#define POCOMPENDIUM_H
+
+#include <poinfo.h>
+
+#include "compendiumdata.h"
+#include "searchengine.h"
+
+#include <qdict.h>
+#include <qfile.h>
+#include <qguardedptr.h>
+#include <qptrlist.h>
+
+class CompendiumPreferencesWidget;
+class KConfigBase;
+class QTimer;
+
+class PoCompendium : public SearchEngine
+{
+ Q_OBJECT
+
+public:
+ PoCompendium(QObject *parent=0, const char *name=0);
+ virtual ~PoCompendium();
+
+ virtual bool isReady() const;
+
+ virtual QString translate(const QString&text, uint pluralForm);
+ virtual QString searchTranslation(const QString&, int &score, const uint pluralForm);
+ virtual QString fuzzyTranslation(const QString&, int &score, const uint pluralForm);
+
+ virtual bool isSearching() const;
+
+ virtual void saveSettings(KConfigBase *config);
+ virtual void readSettings(KConfigBase *config);
+
+ virtual PrefWidget *preferencesWidget(QWidget *parent);
+
+ virtual const KAboutData *about() const;
+
+ virtual QString name() const;
+
+ virtual QString id() const;
+
+ virtual QString lastError();
+
+
+public slots:
+ virtual bool startSearch(const QString& s, uint pluralForm = 0, const SearchFilter* filter = 0);
+ virtual void stopSearch();
+ virtual void setLanguageCode(const QString& lang);
+
+protected slots:
+ /** reads the current settings from the preferences dialog */
+ void applySettings();
+
+ /** sets the current settings in the preferences dialog */
+ void restoreSettings();
+
+ void slotLoadCompendium();
+
+ void recheckData();
+ void removeData();
+
+protected:
+ void loadCompendium();
+ void addResult(SearchResult *, QPtrList<SearchResult>& allResults);
+ QString maskString(QString string);
+
+ void registerData();
+ void unregisterData();
+
+ bool searchExact(const QString& searchString, uint pluralForm, QPtrList<SearchResult>& results, QValueList<int>& foundIndices, QValueList<int>& checkedIndices );
+ bool searchTextOnly(const QString& searchString, uint pluralForm, QPtrList<SearchResult>& results, QValueList<int>& foundIndices, QValueList<int>& checkedIndices );
+ bool searchCaseInsensitive(const QString& searchString, uint pluralForm, QPtrList<SearchResult>& results, QValueList<int>& foundIndices, QValueList<int>& checkedIndices );
+ bool searchWords(const QString& searchString, uint pluralForm, QPtrList<SearchResult>& results, QValueList<int>& foundIndices, QValueList<int>& checkedIndices );
+ bool searchNGram(const QString& searchString, uint pluralForm, QPtrList<SearchResult>& results, QValueList<int>& foundIndices, QValueList<int>& checkedIndices );
+
+private:
+ QGuardedPtr<CompendiumPreferencesWidget> prefWidget;
+ CompendiumData *data;
+ KBabel::PoInfo catalogInfo;
+ QTimer *loadTimer;
+
+ QString url;
+ QString realURL;
+ QString langCode;
+
+ bool caseSensitive;
+ bool ignoreFuzzy;
+ bool wholeWords;
+
+ bool matchEqual;
+ bool matchIsContained;
+ bool matchContains;
+ bool matchWords;
+ bool matchNGram;
+
+ bool buildIndex;
+ uint freeMemDelay;
+
+ bool error;
+ QString errorMsg;
+
+ bool stop;
+ bool active;
+ bool initialized;
+ bool loading;
+
+ static QDict<CompendiumData> *_compDict;
+ static QDict<CompendiumData> *compendiumDict();
+};
+
+#endif
diff --git a/kbabel/kbabeldict/modules/pocompendium/preferenceswidget.cpp b/kbabel/kbabeldict/modules/pocompendium/preferenceswidget.cpp
new file mode 100644
index 00000000..c3ce730d
--- /dev/null
+++ b/kbabel/kbabeldict/modules/pocompendium/preferenceswidget.cpp
@@ -0,0 +1,352 @@
+/* ****************************************************************************
+ This file is part of KBabel
+
+ Copyright (C) 2000 by Matthias Kiefer
+ <matthias.kiefer@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.
+
+ 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, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+ In addition, as a special exception, the copyright holders give
+ permission to link the code of this program with any edition of
+ the Qt library by Trolltech AS, Norway (or with modified versions
+ of Qt that use the same license as Qt), and distribute linked
+ combinations including the two. You must obey the GNU General
+ Public License in all respects for all of the code used other than
+ Qt. If you modify this file, you may extend this exception to
+ your version of the file, but you are not obligated to do so. If
+ you do not wish to do so, delete this exception statement from
+ your version.
+
+**************************************************************************** */
+#include <qcheckbox.h>
+#include <qlabel.h>
+#include <qlayout.h>
+
+#include <kfiledialog.h>
+#include <qpushbutton.h>
+#include <qwhatsthis.h>
+#include <klineedit.h>
+#include <klocale.h>
+#include <kurlrequester.h>
+
+#include "preferenceswidget.h"
+#include "pwidget.h"
+
+CompendiumPreferencesWidget::CompendiumPreferencesWidget(QWidget *parent, const char* name)
+ : PrefWidget(parent,name)
+ , changed(false)
+{
+ QVBoxLayout *layout = new QVBoxLayout(this);
+
+ prefWidget = new CompendiumPWidget(this);
+ layout->addWidget(prefWidget);
+
+ connect(prefWidget->caseBtn, SIGNAL(toggled(bool))
+ , this, SLOT(setChanged()));
+ connect(prefWidget->equalBtn, SIGNAL(toggled(bool))
+ , this, SLOT(setChanged()));
+ connect(prefWidget->ngramBtn, SIGNAL(toggled(bool))
+ , this, SLOT(setChanged()));
+ connect(prefWidget->isContainedBtn, SIGNAL(toggled(bool))
+ , this, SLOT(setChanged()));
+ connect(prefWidget->containsBtn, SIGNAL(toggled(bool))
+ , this, SLOT(setChanged()));
+ connect(prefWidget->fuzzyBtn, SIGNAL(toggled(bool))
+ , this, SLOT(setChanged()));
+ connect(prefWidget->hasWordBtn, SIGNAL(toggled(bool))
+ , this, SLOT(setChanged()));
+ connect(prefWidget->wholeBtn, SIGNAL(toggled(bool))
+ , this, SLOT(setChanged()));
+
+ connect(prefWidget->urlInput->lineEdit(),SIGNAL(textChanged(const QString&))
+ , this, SLOT(setChanged()));
+
+ connect(prefWidget->equalBtn, SIGNAL(toggled(bool))
+ , this, SLOT(equalBtnToggled(bool)));
+ connect(prefWidget->ngramBtn, SIGNAL(toggled(bool))
+ , this, SLOT(ngramBtnToggled(bool)));
+ connect(prefWidget->isContainedBtn, SIGNAL(toggled(bool))
+ , this, SLOT(isContainedBtnToggled(bool)));
+ connect(prefWidget->containsBtn, SIGNAL(toggled(bool))
+ , this, SLOT(containsBtnToggled(bool)));
+ connect(prefWidget->hasWordBtn, SIGNAL(toggled(bool))
+ , this, SLOT(hasWordBtnToggled(bool)));
+
+
+ QString whatsthis=i18n("<qt><p><b>Parameters</b></p>"
+ "<p>Here you can fine-tune searching within the PO file. "
+ "For example if you want to perform a case sensitive search, or if "
+ "you want fuzzy messages to be ignored.</p></qt>" );
+ QWhatsThis::add(prefWidget->caseBtn,whatsthis);
+ QWhatsThis::add(prefWidget->fuzzyBtn,whatsthis);
+ QWhatsThis::add(prefWidget->wholeBtn,whatsthis);
+
+ whatsthis = i18n("<qt><p><b>Comparison Options</b></p>"
+ "<p>Choose here which messages you want to have treated as a matching "
+ "message.</p></qt>");
+ QWhatsThis::add(prefWidget->equalBtn,whatsthis);
+ QWhatsThis::add(prefWidget->containsBtn,whatsthis);
+ QWhatsThis::add(prefWidget->isContainedBtn,whatsthis);
+ QWhatsThis::add(prefWidget->hasWordBtn,whatsthis);
+
+ whatsthis = i18n("<qt><p><b>3-Gram-matching</b></p>"
+ "<p>A message matches another if most of its 3-letter groups are "
+ "contained in the other message. e.g. 'abc123' matches 'abcx123c12'.</p></qt>");
+ QWhatsThis::add(prefWidget->ngramBtn,whatsthis);
+
+ whatsthis = i18n("<qt><p><b>Location</b></p>"
+ "<p>Configure here which file is to be used for searching."
+ "</p></qt>");
+ QWhatsThis::add(prefWidget->urlInput,whatsthis);
+}
+
+CompendiumPreferencesWidget::~CompendiumPreferencesWidget()
+{
+}
+
+
+void CompendiumPreferencesWidget::apply()
+{
+ emit applySettings();
+}
+
+void CompendiumPreferencesWidget::cancel()
+{
+ emit restoreSettings();
+}
+
+void CompendiumPreferencesWidget::standard()
+{
+ prefWidget->urlInput->setURL("http://i18n.kde.org/po_overview/@LANG@.messages");
+ prefWidget->caseBtn->setChecked(false);
+ prefWidget->equalBtn->setChecked(true);
+ prefWidget->ngramBtn->setChecked(true);
+ prefWidget->isContainedBtn->setChecked(false);
+ prefWidget->containsBtn->setChecked(false);
+ prefWidget->wholeBtn->setChecked(true);
+ prefWidget->hasWordBtn->setChecked(true);
+
+ prefWidget->fuzzyBtn->setChecked(true);
+
+ changed=true;
+}
+
+void CompendiumPreferencesWidget::setURL(const QString url)
+{
+ prefWidget->urlInput->setURL(url);
+ changed=false;
+}
+
+void CompendiumPreferencesWidget::setCaseSensitive(bool on)
+{
+ prefWidget->caseBtn->setChecked(on);
+ changed=false;
+}
+
+void CompendiumPreferencesWidget::setMatchEqual(bool on)
+{
+ prefWidget->equalBtn->setChecked(on);
+ changed=false;
+}
+
+void CompendiumPreferencesWidget::setMatchNGram(bool on)
+{
+ prefWidget->ngramBtn->setChecked(on);
+ changed=false;
+}
+
+void CompendiumPreferencesWidget::setMatchIsContained(bool on)
+{
+ prefWidget->isContainedBtn->setChecked(on);
+ changed=false;
+}
+
+void CompendiumPreferencesWidget::setMatchContains(bool on)
+{
+ prefWidget->containsBtn->setChecked(on);
+ changed=false;
+}
+
+void CompendiumPreferencesWidget::setIgnoreFuzzy(bool on)
+{
+ prefWidget->fuzzyBtn->setChecked(on);
+ changed=false;
+}
+
+void CompendiumPreferencesWidget::setWholeWords(bool on)
+{
+ prefWidget->wholeBtn->setChecked(on);
+ changed=false;
+}
+
+
+void CompendiumPreferencesWidget::setMatchWords(bool on)
+{
+ prefWidget->hasWordBtn->setChecked(on);
+ changed=false;
+}
+
+
+
+QString CompendiumPreferencesWidget::url()
+{
+ changed=false;
+ return prefWidget->urlInput->url();
+}
+
+bool CompendiumPreferencesWidget::caseSensitive()
+{
+ changed=false;
+
+ return prefWidget->caseBtn->isChecked();
+}
+
+bool CompendiumPreferencesWidget::matchEqual()
+{
+ changed=false;
+
+ return prefWidget->equalBtn->isChecked();
+}
+
+bool CompendiumPreferencesWidget::matchNGram()
+{
+ changed=false;
+
+ return prefWidget->ngramBtn->isChecked();
+}
+
+bool CompendiumPreferencesWidget::matchIsContained()
+{
+ changed=false;
+
+ return prefWidget->isContainedBtn->isChecked();
+}
+
+bool CompendiumPreferencesWidget::matchContains()
+{
+ changed=false;
+
+ return prefWidget->containsBtn->isChecked();
+}
+
+bool CompendiumPreferencesWidget::ignoreFuzzy()
+{
+ changed=false;
+
+ return prefWidget->fuzzyBtn->isChecked();
+}
+
+
+bool CompendiumPreferencesWidget::wholeWords()
+{
+ changed=false;
+
+ return prefWidget->wholeBtn->isChecked();
+}
+
+
+bool CompendiumPreferencesWidget::matchWords()
+{
+ changed=false;
+
+ return prefWidget->hasWordBtn->isChecked();
+}
+
+
+
+bool CompendiumPreferencesWidget::settingsChanged() const
+{
+ return changed;
+}
+
+void CompendiumPreferencesWidget::setChanged()
+{
+ changed=true;
+}
+
+
+void CompendiumPreferencesWidget::equalBtnToggled(bool on)
+{
+ if(!on)
+ {
+ if(!prefWidget->isContainedBtn->isChecked()
+ && !prefWidget->ngramBtn->isChecked()
+ && !prefWidget->containsBtn->isChecked()
+ && !prefWidget->hasWordBtn->isChecked())
+ {
+ prefWidget->equalBtn->setChecked(true);
+ }
+ }
+}
+
+void CompendiumPreferencesWidget::ngramBtnToggled(bool on)
+{
+ if(!on)
+ {
+ if(!prefWidget->isContainedBtn->isChecked()
+ && !prefWidget->equalBtn->isChecked()
+ && !prefWidget->containsBtn->isChecked()
+ && !prefWidget->hasWordBtn->isChecked())
+ {
+ prefWidget->equalBtn->setChecked(true);
+ }
+ }
+}
+
+void CompendiumPreferencesWidget::isContainedBtnToggled(bool on)
+{
+ if(!on)
+ {
+ if(!prefWidget->equalBtn->isChecked()
+ && !prefWidget->ngramBtn->isChecked()
+ && !prefWidget->containsBtn->isChecked()
+ && !prefWidget->hasWordBtn->isChecked())
+ {
+ prefWidget->isContainedBtn->setChecked(true);
+ }
+ }
+}
+
+void CompendiumPreferencesWidget::containsBtnToggled(bool on)
+{
+ if(!on)
+ {
+ if(!prefWidget->isContainedBtn->isChecked()
+ && !prefWidget->ngramBtn->isChecked()
+ && !prefWidget->equalBtn->isChecked()
+ && !prefWidget->hasWordBtn->isChecked())
+ {
+ prefWidget->containsBtn->setChecked(true);
+ }
+ }
+}
+
+void CompendiumPreferencesWidget::hasWordBtnToggled(bool on)
+{
+ if(!on)
+ {
+ if(!prefWidget->isContainedBtn->isChecked()
+ && !prefWidget->ngramBtn->isChecked()
+ && !prefWidget->equalBtn->isChecked()
+ && !prefWidget->containsBtn->isChecked())
+ {
+ prefWidget->hasWordBtn->setChecked(true);
+ }
+ }
+}
+
+
+
+#include "preferenceswidget.moc"
diff --git a/kbabel/kbabeldict/modules/pocompendium/preferenceswidget.h b/kbabel/kbabeldict/modules/pocompendium/preferenceswidget.h
new file mode 100644
index 00000000..db70df4d
--- /dev/null
+++ b/kbabel/kbabeldict/modules/pocompendium/preferenceswidget.h
@@ -0,0 +1,97 @@
+/* ****************************************************************************
+ This file is part of KBabel
+
+ Copyright (C) 2000 by Matthias Kiefer
+ <matthias.kiefer@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.
+
+ 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, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+ In addition, as a special exception, the copyright holders give
+ permission to link the code of this program with any edition of
+ the Qt library by Trolltech AS, Norway (or with modified versions
+ of Qt that use the same license as Qt), and distribute linked
+ combinations including the two. You must obey the GNU General
+ Public License in all respects for all of the code used other than
+ Qt. If you modify this file, you may extend this exception to
+ your version of the file, but you are not obligated to do so. If
+ you do not wish to do so, delete this exception statement from
+ your version.
+
+**************************************************************************** */
+
+
+#ifndef PREFERENCESWIDGET_H
+#define PREFERENCESWIDGET_H
+
+#include "searchengine.h"
+
+class CompendiumPWidget;
+
+class CompendiumPreferencesWidget : public PrefWidget
+{
+ Q_OBJECT
+
+public:
+ CompendiumPreferencesWidget(QWidget *parent=0, const char* name=0);
+ virtual ~CompendiumPreferencesWidget();
+
+ virtual void apply();
+ virtual void cancel();
+ virtual void standard();
+
+ void setURL(const QString url);
+ void setMatchEqual(bool);
+ void setMatchNGram(bool);
+ void setMatchIsContained(bool);
+ void setMatchContains(bool);
+ void setIgnoreFuzzy(bool);
+ void setMatchWords(bool);
+ void setWholeWords(bool);
+ void setCaseSensitive(bool);
+
+ QString url();
+ bool matchEqual();
+ bool matchNGram();
+ bool matchIsContained();
+ bool matchContains();
+ bool ignoreFuzzy();
+ bool matchWords();
+ bool wholeWords();
+ bool caseSensitive();
+
+
+ bool settingsChanged() const;
+
+signals:
+ void restoreSettings();
+ void applySettings();
+
+public:
+ CompendiumPWidget *prefWidget;
+
+protected slots:
+ void setChanged();
+ void equalBtnToggled(bool);
+ void ngramBtnToggled(bool);
+ void isContainedBtnToggled(bool);
+ void containsBtnToggled(bool);
+ void hasWordBtnToggled(bool);
+
+private:
+ bool changed;
+
+};
+
+#endif
diff --git a/kbabel/kbabeldict/modules/pocompendium/pwidget.ui b/kbabel/kbabeldict/modules/pocompendium/pwidget.ui
new file mode 100644
index 00000000..8f54b087
--- /dev/null
+++ b/kbabel/kbabeldict/modules/pocompendium/pwidget.ui
@@ -0,0 +1,280 @@
+<!DOCTYPE UI><UI>
+<class>CompendiumPWidget</class>
+<include location="global">kseparator.h</include>
+<widget>
+ <class>QWidget</class>
+ <property stdset="1">
+ <name>name</name>
+ <cstring>PWidget</cstring>
+ </property>
+ <property stdset="1">
+ <name>geometry</name>
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>452</width>
+ <height>291</height>
+ </rect>
+ </property>
+ <property stdset="1">
+ <name>caption</name>
+ <string></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>QGroupBox</class>
+ <property stdset="1">
+ <name>name</name>
+ <cstring>GroupBox1</cstring>
+ </property>
+ <property stdset="1">
+ <name>title</name>
+ <string>&amp;Path to Compendium File</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>KURLRequester</class>
+ <property stdset="1">
+ <name>name</name>
+ <cstring>urlInput</cstring>
+ </property>
+ </widget>
+ </vbox>
+ </widget>
+ <widget>
+ <class>QButtonGroup</class>
+ <property stdset="1">
+ <name>name</name>
+ <cstring>ButtonGroup1</cstring>
+ </property>
+ <property stdset="1">
+ <name>title</name>
+ <string>Options</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>
+ <grid>
+ <property stdset="1">
+ <name>margin</name>
+ <number>0</number>
+ </property>
+ <property stdset="1">
+ <name>spacing</name>
+ <number>6</number>
+ </property>
+ <widget row="1" column="0" >
+ <class>QCheckBox</class>
+ <property stdset="1">
+ <name>name</name>
+ <cstring>fuzzyBtn</cstring>
+ </property>
+ <property stdset="1">
+ <name>text</name>
+ <string>Ignore &amp;fuzzy strings</string>
+ </property>
+ </widget>
+ <widget row="0" column="1" >
+ <class>QCheckBox</class>
+ <property stdset="1">
+ <name>name</name>
+ <cstring>wholeBtn</cstring>
+ </property>
+ <property stdset="1">
+ <name>text</name>
+ <string>Onl&amp;y whole words</string>
+ </property>
+ </widget>
+ <widget row="0" column="0" >
+ <class>QCheckBox</class>
+ <property stdset="1">
+ <name>name</name>
+ <cstring>caseBtn</cstring>
+ </property>
+ <property stdset="1">
+ <name>text</name>
+ <string>Case sensiti&amp;ve</string>
+ </property>
+ </widget>
+ </grid>
+ </widget>
+ <widget>
+ <class>KSeparator</class>
+ <property stdset="1">
+ <name>name</name>
+ <cstring>Line1</cstring>
+ </property>
+ <property stdset="1">
+ <name>orientation</name>
+ <enum>Horizontal</enum>
+ </property>
+ </widget>
+ <widget>
+ <class>QLabel</class>
+ <property stdset="1">
+ <name>name</name>
+ <cstring>TextLabel3</cstring>
+ </property>
+ <property stdset="1">
+ <name>text</name>
+ <string>A text matches if:</string>
+ </property>
+ </widget>
+ <widget>
+ <class>QLayoutWidget</class>
+ <property stdset="1">
+ <name>name</name>
+ <cstring>Layout3</cstring>
+ </property>
+ <grid>
+ <property stdset="1">
+ <name>margin</name>
+ <number>0</number>
+ </property>
+ <property stdset="1">
+ <name>spacing</name>
+ <number>6</number>
+ </property>
+ <widget row="0" column="0" >
+ <class>QCheckBox</class>
+ <property stdset="1">
+ <name>name</name>
+ <cstring>equalBtn</cstring>
+ </property>
+ <property stdset="1">
+ <name>text</name>
+ <string>E&amp;qual to searched text</string>
+ </property>
+ </widget>
+ <widget row="2" column="1" >
+ <class>QCheckBox</class>
+ <property stdset="1">
+ <name>name</name>
+ <cstring>hasWordBtn</cstring>
+ </property>
+ <property stdset="1">
+ <name>text</name>
+ <string>Contains a &amp;word of searched text</string>
+ </property>
+ </widget>
+ <widget row="1" column="1" >
+ <class>QCheckBox</class>
+ <property stdset="1">
+ <name>name</name>
+ <cstring>isContainedBtn</cstring>
+ </property>
+ <property stdset="1">
+ <name>text</name>
+ <string>Co&amp;ntained in searched text</string>
+ </property>
+ </widget>
+ <widget row="1" column="0" >
+ <class>QCheckBox</class>
+ <property stdset="1">
+ <name>name</name>
+ <cstring>ngramBtn</cstring>
+ </property>
+ <property stdset="1">
+ <name>text</name>
+ <string>&amp;Similar to searched text</string>
+ </property>
+ </widget>
+ <widget row="0" column="1" >
+ <class>QCheckBox</class>
+ <property stdset="1">
+ <name>name</name>
+ <cstring>containsBtn</cstring>
+ </property>
+ <property stdset="1">
+ <name>text</name>
+ <string>Contains searched te&amp;xt</string>
+ </property>
+ </widget>
+ </grid>
+ </widget>
+ </vbox>
+ </widget>
+ <spacer>
+ <property>
+ <name>name</name>
+ <cstring>Spacer1</cstring>
+ </property>
+ <property stdset="1">
+ <name>orientation</name>
+ <enum>Vertical</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>
+ <property>
+ <name>sizeHint</name>
+ <size>
+ <width>20</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </vbox>
+</widget>
+<customwidgets>
+ <customwidget>
+ <class>KURLRequester</class>
+ <header location="global">kurlrequester.h</header>
+ <sizehint>
+ <width>-1</width>
+ <height>-1</height>
+ </sizehint>
+ <container>0</container>
+ <sizepolicy>
+ <hordata>5</hordata>
+ <verdata>5</verdata>
+ </sizepolicy>
+ <pixmap>image0</pixmap>
+ </customwidget>
+</customwidgets>
+<images>
+ <image>
+ <name>image0</name>
+ <data format="XPM.GZ" length="646">789c6dd2c10ac2300c00d07bbf2234b7229d1be245fc04c5a3201e4615f430059d0711ff5ddb2e6bb236ec90eed134cb5a19d8ef36602af5ecdbfeeac05dda0798d3abebde87e3faa374d3807fa0d633a52d38d8de6f679fe33fc776e196f53cd010188256a3600a292882096246517815ca99884606e18044a3a40d91824820924265a7923a2e8bcd05f33db1173e002913175f2a6be6d3294871a2d95fa00e8a94ee017b69d339d90df1e77c57ea072ede6758</data>
+ </image>
+</images>
+<tabstops>
+ <tabstop>caseBtn</tabstop>
+</tabstops>
+</UI>
diff --git a/kbabel/kbabeldict/modules/tmx/Makefile.am b/kbabel/kbabeldict/modules/tmx/Makefile.am
new file mode 100644
index 00000000..f0f54b01
--- /dev/null
+++ b/kbabel/kbabeldict/modules/tmx/Makefile.am
@@ -0,0 +1,34 @@
+## Makefile.am for tmxcompendium
+
+# this has all of the subdirectories that make will recurse into. if
+# there are none, comment this out
+#SUBDIRS =
+
+
+# this is the program that gets installed. it's name is used for all
+# of the other Makefile.am variables
+kde_module_LTLIBRARIES = kbabeldict_tmxcompendium.la
+
+# set the include path for X, qt and KDE
+INCLUDES = -I$(srcdir)/../.. -I../../../common -I$(srcdir)/../../../common $(all_includes)
+
+
+# which sources should be compiled for kbabel
+kbabeldict_tmxcompendium_la_SOURCES = tmxcompendium.cpp preferenceswidget.cpp \
+ pc_factory.cpp pwidget.ui tmxcompendiumdata.cpp
+
+kbabeldict_tmxcompendium_la_LIBADD = ../../libkbabeldictplugin.la ../../../common/libkbabelcommon.la $(LIB_KDEUI) $(LIB_KIO)
+kbabeldict_tmxcompendium_la_LDFLAGS = $(all_libraries) -module -avoid-version -no-undefined
+
+
+
+# these are the headers for your project
+noinst_HEADERS = tmxcompendium.h preferenceswidget.h pc_factory.h \
+ tmxcompendiumdata.h
+
+
+# let automoc handle all of the meta source files (moc)
+METASOURCES = AUTO
+
+kde_services_DATA = tmxcompendium.desktop
+EXTRA_DIST = $(kde_services_DATA)
diff --git a/kbabel/kbabeldict/modules/tmx/pc_factory.cpp b/kbabel/kbabeldict/modules/tmx/pc_factory.cpp
new file mode 100644
index 00000000..a3dcfdf9
--- /dev/null
+++ b/kbabel/kbabeldict/modules/tmx/pc_factory.cpp
@@ -0,0 +1,111 @@
+/* ****************************************************************************
+ This file is part of KBabel
+
+ Copyright (C) 2000 by Matthias Kiefer <matthias.kiefer@gmx.de>
+ 2002 by Stanislav Visnovsky <visnovsky@kde.org>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the 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, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+ In addition, as a special exception, the copyright holders give
+ permission to link the code of this program with any edition of
+ the Qt library by Trolltech AS, Norway (or with modified versions
+ of Qt that use the same license as Qt), and distribute linked
+ combinations including the two. You must obey the GNU General
+ Public License in all respects for all of the code used other than
+ Qt. If you modify this file, you may extend this exception to
+ your version of the file, but you are not obligated to do so. If
+ you do not wish to do so, delete this exception statement from
+ your version.
+
+**************************************************************************** */
+
+
+#include <klocale.h>
+#include <kinstance.h>
+#include <kaboutdata.h>
+#include <kdebug.h>
+
+#include "pc_factory.h"
+#include "tmxcompendium.h"
+
+
+extern "C"
+{
+ KDE_EXPORT void *init_kbabeldict_tmxcompendium()
+ {
+ return new PcFactory;
+ }
+}
+
+
+KInstance *PcFactory::s_instance = 0;
+KAboutData *PcFactory::s_about = 0;
+
+
+PcFactory::PcFactory( QObject *parent, const char *name)
+ : KLibFactory(parent,name)
+{
+}
+
+PcFactory::~PcFactory()
+{
+ if(s_instance)
+ {
+ delete s_instance;
+ s_instance=0;
+ }
+
+ if(s_about)
+ {
+ delete s_about;
+ s_about=0;
+ }
+}
+
+
+QObject *PcFactory::createObject( QObject *parent, const char *name
+ , const char *classname, const QStringList &)
+{
+ if(QCString(classname) != "SearchEngine")
+ {
+ kdError() << "not a SearchEngine requested" << endl;
+ return 0;
+ }
+
+ return new TmxCompendium(parent,name);
+}
+
+
+KInstance *PcFactory::instance()
+{
+ if(!s_instance)
+ {
+ s_about = new KAboutData( "tmxcompendium", I18N_NOOP("TMX Compendium")
+ , "1.0"
+ , I18N_NOOP("A module for searching in a TMX file")
+ , KAboutData::License_GPL
+ , "Copyright 2002, Stanislav Visnovsky"
+ ,0,0, "visnovsky@kde.org");
+
+ s_about->addAuthor("Matthias Kiefer",0,"kiefer@kde.org");
+ s_about->addAuthor("Stanislav Visnovsky",0,"visnovsky@kde.org");
+
+ s_instance = new KInstance(s_about);
+ }
+
+ return s_instance;
+}
+
+#include "pc_factory.moc"
diff --git a/kbabel/kbabeldict/modules/tmx/pc_factory.h b/kbabel/kbabeldict/modules/tmx/pc_factory.h
new file mode 100644
index 00000000..5ef08277
--- /dev/null
+++ b/kbabel/kbabeldict/modules/tmx/pc_factory.h
@@ -0,0 +1,62 @@
+/* ****************************************************************************
+ This file is part of KBabel
+
+ Copyright (C) 2000 by Matthias Kiefer
+ <matthias.kiefer@gmx.de>
+ 2002 by Stanislav Visnovsky
+ <visnovsky@kde.org>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the 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, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+ In addition, as a special exception, the copyright holders give
+ permission to link the code of this program with any edition of
+ the Qt library by Trolltech AS, Norway (or with modified versions
+ of Qt that use the same license as Qt), and distribute linked
+ combinations including the two. You must obey the GNU General
+ Public License in all respects for all of the code used other than
+ Qt. If you modify this file, you may extend this exception to
+ your version of the file, but you are not obligated to do so. If
+ you do not wish to do so, delete this exception statement from
+ your version.
+
+**************************************************************************** */
+
+
+#ifndef PC_FACTORY_H
+#define PC_FACTORY_H
+
+#include <klibloader.h>
+class KInstance;
+class KAboutData;
+
+class PcFactory : public KLibFactory
+{
+ Q_OBJECT
+public:
+ PcFactory( QObject *parent=0, const char *name=0);
+ ~PcFactory();
+
+ virtual QObject *createObject( QObject *parent=0, const char *name=0
+ , const char *classname="QObject"
+ , const QStringList &args = QStringList());
+
+ static KInstance *instance();
+
+private:
+ static KInstance *s_instance;
+ static KAboutData *s_about;
+};
+
+#endif
diff --git a/kbabel/kbabeldict/modules/tmx/preferenceswidget.cpp b/kbabel/kbabeldict/modules/tmx/preferenceswidget.cpp
new file mode 100644
index 00000000..1202496d
--- /dev/null
+++ b/kbabel/kbabeldict/modules/tmx/preferenceswidget.cpp
@@ -0,0 +1,334 @@
+/* ****************************************************************************
+ This file is part of KBabel
+
+ Copyright (C) 2000 by Matthias Kiefer
+ <matthias.kiefer@gmx.de>
+ 2002 by Stanislav Visnovsky
+ <visnovsky@kde.org>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the 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, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+ In addition, as a special exception, the copyright holders give
+ permission to link the code of this program with any edition of
+ the Qt library by Trolltech AS, Norway (or with modified versions
+ of Qt that use the same license as Qt), and distribute linked
+ combinations including the two. You must obey the GNU General
+ Public License in all respects for all of the code used other than
+ Qt. If you modify this file, you may extend this exception to
+ your version of the file, but you are not obligated to do so. If
+ you do not wish to do so, delete this exception statement from
+ your version.
+
+**************************************************************************** */
+#include <qcheckbox.h>
+#include <qlabel.h>
+#include <qlayout.h>
+
+#include <kfiledialog.h>
+#include <qpushbutton.h>
+#include <qwhatsthis.h>
+#include <klineedit.h>
+#include <klocale.h>
+#include <kurlrequester.h>
+
+#include "preferenceswidget.h"
+#include "pwidget.h"
+
+TmxCompendiumPreferencesWidget::TmxCompendiumPreferencesWidget(QWidget *parent, const char* name)
+ : PrefWidget(parent,name)
+ , changed(false)
+{
+ QVBoxLayout *layout = new QVBoxLayout(this);
+
+ prefWidget = new TmxCompendiumPWidget(this);
+ layout->addWidget(prefWidget);
+
+ connect(prefWidget->caseBtn, SIGNAL(toggled(bool))
+ , this, SLOT(setChanged()));
+ connect(prefWidget->equalBtn, SIGNAL(toggled(bool))
+ , this, SLOT(setChanged()));
+ connect(prefWidget->ngramBtn, SIGNAL(toggled(bool))
+ , this, SLOT(setChanged()));
+ connect(prefWidget->isContainedBtn, SIGNAL(toggled(bool))
+ , this, SLOT(setChanged()));
+ connect(prefWidget->containsBtn, SIGNAL(toggled(bool))
+ , this, SLOT(setChanged()));
+ connect(prefWidget->hasWordBtn, SIGNAL(toggled(bool))
+ , this, SLOT(setChanged()));
+ connect(prefWidget->wholeBtn, SIGNAL(toggled(bool))
+ , this, SLOT(setChanged()));
+
+ connect(prefWidget->urlInput->lineEdit(),SIGNAL(textChanged(const QString&))
+ , this, SLOT(setChanged()));
+
+ connect(prefWidget->equalBtn, SIGNAL(toggled(bool))
+ , this, SLOT(equalBtnToggled(bool)));
+ connect(prefWidget->ngramBtn, SIGNAL(toggled(bool))
+ , this, SLOT(ngramBtnToggled(bool)));
+ connect(prefWidget->isContainedBtn, SIGNAL(toggled(bool))
+ , this, SLOT(isContainedBtnToggled(bool)));
+ connect(prefWidget->containsBtn, SIGNAL(toggled(bool))
+ , this, SLOT(containsBtnToggled(bool)));
+ connect(prefWidget->hasWordBtn, SIGNAL(toggled(bool))
+ , this, SLOT(hasWordBtnToggled(bool)));
+
+
+ QString whatsthis=i18n("<qt><p><b>Parameters</b></p>"
+ "<p>Here you can fine-tune searching within the PO file. "
+ "For example, if you want to perform a case sensitive search.</p></qt>" );
+ QWhatsThis::add(prefWidget->caseBtn,whatsthis);
+ QWhatsThis::add(prefWidget->wholeBtn,whatsthis);
+
+ whatsthis = i18n("<qt><p><b>Comparison Options</b></p>"
+ "<p>Choose here which messages you want to have treated as a matching "
+ "message.</p></qt>");
+ QWhatsThis::add(prefWidget->equalBtn,whatsthis);
+ QWhatsThis::add(prefWidget->containsBtn,whatsthis);
+ QWhatsThis::add(prefWidget->isContainedBtn,whatsthis);
+ QWhatsThis::add(prefWidget->hasWordBtn,whatsthis);
+
+ whatsthis = i18n("<qt><p><b>3-Gram-matching</b></p>"
+ "<p>A message matches another if most of its 3-letter groups are "
+ "contained in the other message. e.g. 'abc123' matches 'abcx123c12'.</p></qt>");
+ QWhatsThis::add(prefWidget->ngramBtn,whatsthis);
+
+ whatsthis = i18n("<qt><p><b>Location</b></p>"
+ "<p>Configure here which file is to be used for searching."
+ "</p></qt>");
+ QWhatsThis::add(prefWidget->urlInput,whatsthis);
+}
+
+TmxCompendiumPreferencesWidget::~TmxCompendiumPreferencesWidget()
+{
+}
+
+
+void TmxCompendiumPreferencesWidget::apply()
+{
+ emit applySettings();
+}
+
+void TmxCompendiumPreferencesWidget::cancel()
+{
+ emit restoreSettings();
+}
+
+void TmxCompendiumPreferencesWidget::standard()
+{
+ prefWidget->urlInput->setURL("http://i18n.kde.org/po_overview/@LANG@.messages");
+ prefWidget->caseBtn->setChecked(false);
+ prefWidget->equalBtn->setChecked(true);
+ prefWidget->ngramBtn->setChecked(true);
+ prefWidget->isContainedBtn->setChecked(false);
+ prefWidget->containsBtn->setChecked(false);
+ prefWidget->wholeBtn->setChecked(true);
+ prefWidget->hasWordBtn->setChecked(true);
+
+ changed=true;
+}
+
+void TmxCompendiumPreferencesWidget::setURL(const QString url)
+{
+ prefWidget->urlInput->setURL(url);
+ changed=false;
+}
+
+void TmxCompendiumPreferencesWidget::setCaseSensitive(bool on)
+{
+ prefWidget->caseBtn->setChecked(on);
+ changed=false;
+}
+
+void TmxCompendiumPreferencesWidget::setMatchEqual(bool on)
+{
+ prefWidget->equalBtn->setChecked(on);
+ changed=false;
+}
+
+void TmxCompendiumPreferencesWidget::setMatchNGram(bool on)
+{
+ prefWidget->ngramBtn->setChecked(on);
+ changed=false;
+}
+
+void TmxCompendiumPreferencesWidget::setMatchIsContained(bool on)
+{
+ prefWidget->isContainedBtn->setChecked(on);
+ changed=false;
+}
+
+void TmxCompendiumPreferencesWidget::setMatchContains(bool on)
+{
+ prefWidget->containsBtn->setChecked(on);
+ changed=false;
+}
+
+void TmxCompendiumPreferencesWidget::setWholeWords(bool on)
+{
+ prefWidget->wholeBtn->setChecked(on);
+ changed=false;
+}
+
+
+void TmxCompendiumPreferencesWidget::setMatchWords(bool on)
+{
+ prefWidget->hasWordBtn->setChecked(on);
+ changed=false;
+}
+
+
+
+QString TmxCompendiumPreferencesWidget::url()
+{
+ changed=false;
+ return prefWidget->urlInput->url();
+}
+
+bool TmxCompendiumPreferencesWidget::caseSensitive()
+{
+ changed=false;
+
+ return prefWidget->caseBtn->isChecked();
+}
+
+bool TmxCompendiumPreferencesWidget::matchEqual()
+{
+ changed=false;
+
+ return prefWidget->equalBtn->isChecked();
+}
+
+bool TmxCompendiumPreferencesWidget::matchNGram()
+{
+ changed=false;
+
+ return prefWidget->ngramBtn->isChecked();
+}
+
+bool TmxCompendiumPreferencesWidget::matchIsContained()
+{
+ changed=false;
+
+ return prefWidget->isContainedBtn->isChecked();
+}
+
+bool TmxCompendiumPreferencesWidget::matchContains()
+{
+ changed=false;
+
+ return prefWidget->containsBtn->isChecked();
+}
+
+bool TmxCompendiumPreferencesWidget::wholeWords()
+{
+ changed=false;
+
+ return prefWidget->wholeBtn->isChecked();
+}
+
+
+bool TmxCompendiumPreferencesWidget::matchWords()
+{
+ changed=false;
+
+ return prefWidget->hasWordBtn->isChecked();
+}
+
+
+
+bool TmxCompendiumPreferencesWidget::settingsChanged() const
+{
+ return changed;
+}
+
+void TmxCompendiumPreferencesWidget::setChanged()
+{
+ changed=true;
+}
+
+
+void TmxCompendiumPreferencesWidget::equalBtnToggled(bool on)
+{
+ if(!on)
+ {
+ if(!prefWidget->isContainedBtn->isChecked()
+ && !prefWidget->ngramBtn->isChecked()
+ && !prefWidget->containsBtn->isChecked()
+ && !prefWidget->hasWordBtn->isChecked())
+ {
+ prefWidget->equalBtn->setChecked(true);
+ }
+ }
+}
+
+void TmxCompendiumPreferencesWidget::ngramBtnToggled(bool on)
+{
+ if(!on)
+ {
+ if(!prefWidget->isContainedBtn->isChecked()
+ && !prefWidget->equalBtn->isChecked()
+ && !prefWidget->containsBtn->isChecked()
+ && !prefWidget->hasWordBtn->isChecked())
+ {
+ prefWidget->equalBtn->setChecked(true);
+ }
+ }
+}
+
+void TmxCompendiumPreferencesWidget::isContainedBtnToggled(bool on)
+{
+ if(!on)
+ {
+ if(!prefWidget->equalBtn->isChecked()
+ && !prefWidget->ngramBtn->isChecked()
+ && !prefWidget->containsBtn->isChecked()
+ && !prefWidget->hasWordBtn->isChecked())
+ {
+ prefWidget->isContainedBtn->setChecked(true);
+ }
+ }
+}
+
+void TmxCompendiumPreferencesWidget::containsBtnToggled(bool on)
+{
+ if(!on)
+ {
+ if(!prefWidget->isContainedBtn->isChecked()
+ && !prefWidget->ngramBtn->isChecked()
+ && !prefWidget->equalBtn->isChecked()
+ && !prefWidget->hasWordBtn->isChecked())
+ {
+ prefWidget->containsBtn->setChecked(true);
+ }
+ }
+}
+
+void TmxCompendiumPreferencesWidget::hasWordBtnToggled(bool on)
+{
+ if(!on)
+ {
+ if(!prefWidget->isContainedBtn->isChecked()
+ && !prefWidget->ngramBtn->isChecked()
+ && !prefWidget->equalBtn->isChecked()
+ && !prefWidget->containsBtn->isChecked())
+ {
+ prefWidget->hasWordBtn->setChecked(true);
+ }
+ }
+}
+
+
+
+#include "preferenceswidget.moc"
diff --git a/kbabel/kbabeldict/modules/tmx/preferenceswidget.h b/kbabel/kbabeldict/modules/tmx/preferenceswidget.h
new file mode 100644
index 00000000..c8356c3d
--- /dev/null
+++ b/kbabel/kbabeldict/modules/tmx/preferenceswidget.h
@@ -0,0 +1,97 @@
+/* ****************************************************************************
+ This file is part of KBabel
+
+ Copyright (C) 2000 by Matthias Kiefer
+ <matthias.kiefer@gmx.de>
+ 2002 by Stanislav Visnovsky
+ <visnovsky@kde.org>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the 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, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+ In addition, as a special exception, the copyright holders give
+ permission to link the code of this program with any edition of
+ the Qt library by Trolltech AS, Norway (or with modified versions
+ of Qt that use the same license as Qt), and distribute linked
+ combinations including the two. You must obey the GNU General
+ Public License in all respects for all of the code used other than
+ Qt. If you modify this file, you may extend this exception to
+ your version of the file, but you are not obligated to do so. If
+ you do not wish to do so, delete this exception statement from
+ your version.
+
+**************************************************************************** */
+
+
+#ifndef PREFERENCESWIDGET_H
+#define PREFERENCESWIDGET_H
+
+#include "searchengine.h"
+
+class TmxCompendiumPWidget;
+
+class TmxCompendiumPreferencesWidget : public PrefWidget
+{
+ Q_OBJECT
+
+public:
+ TmxCompendiumPreferencesWidget(QWidget *parent=0, const char* name=0);
+ virtual ~TmxCompendiumPreferencesWidget();
+
+ virtual void apply();
+ virtual void cancel();
+ virtual void standard();
+
+ void setURL(const QString url);
+ void setMatchEqual(bool);
+ void setMatchNGram(bool);
+ void setMatchIsContained(bool);
+ void setMatchContains(bool);
+ void setMatchWords(bool);
+ void setWholeWords(bool);
+ void setCaseSensitive(bool);
+
+ QString url();
+ bool matchEqual();
+ bool matchNGram();
+ bool matchIsContained();
+ bool matchContains();
+ bool matchWords();
+ bool wholeWords();
+ bool caseSensitive();
+
+
+ bool settingsChanged() const;
+
+signals:
+ void restoreSettings();
+ void applySettings();
+
+public:
+ TmxCompendiumPWidget *prefWidget;
+
+protected slots:
+ void setChanged();
+ void equalBtnToggled(bool);
+ void ngramBtnToggled(bool);
+ void isContainedBtnToggled(bool);
+ void containsBtnToggled(bool);
+ void hasWordBtnToggled(bool);
+
+private:
+ bool changed;
+
+};
+
+#endif
diff --git a/kbabel/kbabeldict/modules/tmx/pwidget.ui b/kbabel/kbabeldict/modules/tmx/pwidget.ui
new file mode 100644
index 00000000..ef6c9967
--- /dev/null
+++ b/kbabel/kbabeldict/modules/tmx/pwidget.ui
@@ -0,0 +1,216 @@
+<!DOCTYPE UI><UI version="3.1" stdsetdef="1">
+<class>TmxCompendiumPWidget</class>
+<widget class="QWidget">
+ <property name="name">
+ <cstring>TMXPWidget</cstring>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>452</width>
+ <height>291</height>
+ </rect>
+ </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>&amp;Path to Compendium File</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="KURLRequester">
+ <property name="name">
+ <cstring>urlInput</cstring>
+ </property>
+ </widget>
+ </vbox>
+ </widget>
+ <widget class="QButtonGroup">
+ <property name="name">
+ <cstring>ButtonGroup1</cstring>
+ </property>
+ <property name="title">
+ <string>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>Layout4</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="QCheckBox" row="0" column="1">
+ <property name="name">
+ <cstring>wholeBtn</cstring>
+ </property>
+ <property name="text">
+ <string>Onl&amp;y whole words</string>
+ </property>
+ </widget>
+ <widget class="QCheckBox" row="0" column="0">
+ <property name="name">
+ <cstring>caseBtn</cstring>
+ </property>
+ <property name="text">
+ <string>Case sensiti&amp;ve</string>
+ </property>
+ </widget>
+ </grid>
+ </widget>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>TextLabel3</cstring>
+ </property>
+ <property name="text">
+ <string>A text matches if:</string>
+ </property>
+ </widget>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>Layout3</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="QCheckBox" row="0" column="0">
+ <property name="name">
+ <cstring>equalBtn</cstring>
+ </property>
+ <property name="text">
+ <string>E&amp;qual to searched text</string>
+ </property>
+ </widget>
+ <widget class="QCheckBox" row="2" column="1">
+ <property name="name">
+ <cstring>hasWordBtn</cstring>
+ </property>
+ <property name="text">
+ <string>Contains a &amp;word of searched text</string>
+ </property>
+ </widget>
+ <widget class="QCheckBox" row="1" column="1">
+ <property name="name">
+ <cstring>isContainedBtn</cstring>
+ </property>
+ <property name="text">
+ <string>Co&amp;ntained in searched text</string>
+ </property>
+ </widget>
+ <widget class="QCheckBox" row="1" column="0">
+ <property name="name">
+ <cstring>ngramBtn</cstring>
+ </property>
+ <property name="text">
+ <string>&amp;Similar to searched text</string>
+ </property>
+ </widget>
+ <widget class="QCheckBox" row="0" column="1">
+ <property name="name">
+ <cstring>containsBtn</cstring>
+ </property>
+ <property name="text">
+ <string>Contains searched te&amp;xt</string>
+ </property>
+ </widget>
+ </grid>
+ </widget>
+ </vbox>
+ </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>20</height>
+ </size>
+ </property>
+ </spacer>
+ </vbox>
+</widget>
+<customwidgets>
+ <customwidget>
+ <class>KURLRequester</class>
+ <header location="global">kurlrequester.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="XPM.GZ" length="646">789c6dd2c10ac2300c00d07bbf2234b7229d1be245fc04c5a3201e4615f430059d0711ff5ddb2e6bb236ec90eed134cb5a19d8ef36602af5ecdbfeeac05dda0798d3abebde87e3faa374d3807fa0d633a52d38d8de6f679fe33fc776e196f53cd010188256a3600a292882096246517815ca99884606e18044a3a40d91824820924265a7923a2e8bcd05f33db1173e002913175f2a6be6d3294871a2d95fa00e8a94ee017b69d339d90df1e77c57ea072ede6758</data>
+ </image>
+</images>
+<tabstops>
+ <tabstop>caseBtn</tabstop>
+</tabstops>
+<includes>
+ <include location="global" impldecl="in declaration">kseparator.h</include>
+</includes>
+<layoutdefaults spacing="6" margin="11"/>
+<includehints>
+ <includehint>kurlrequester.h</includehint>
+</includehints>
+</UI>
diff --git a/kbabel/kbabeldict/modules/tmx/tmxcompendium.cpp b/kbabel/kbabeldict/modules/tmx/tmxcompendium.cpp
new file mode 100644
index 00000000..152bc536
--- /dev/null
+++ b/kbabel/kbabeldict/modules/tmx/tmxcompendium.cpp
@@ -0,0 +1,1007 @@
+/* ****************************************************************************
+ This file is part of KBabel
+
+ Copyright (C) 2000 by Matthias Kiefer
+ <matthias.kiefer@gmx.de>
+ 2002 by Stanislav Visnovsky
+ <visnovsky@kde.org>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the 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, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+ In addition, as a special exception, the copyright holders give
+ permission to link the code of this program with any edition of
+ the Qt library by Trolltech AS, Norway (or with modified versions
+ of Qt that use the same license as Qt), and distribute linked
+ combinations including the two. You must obey the GNU General
+ Public License in all respects for all of the code used other than
+ Qt. If you modify this file, you may extend this exception to
+ your version of the file, but you are not obligated to do so. If
+ you do not wish to do so, delete this exception statement from
+ your version.
+
+**************************************************************************** */
+#include <klocale.h>
+#include <kapplication.h>
+#include <kcmdlineargs.h>
+#include <kstaticdeleter.h>
+#include <kdebug.h>
+#include <kglobal.h>
+#include <kinstance.h>
+#include <kio/netaccess.h>
+
+#include <qtextstream.h>
+#include <qtimer.h>
+
+#include "tmxcompendiumdata.h"
+#include "tmxcompendium.h"
+#include "preferenceswidget.h"
+#include "pc_factory.h"
+
+#include <catalogitem.h>
+
+// ngram length and minimal matching for fuzzy search
+#define NGRAM_LEN 3
+#define LIM_NGRAM 50
+
+static KStaticDeleter< QDict<TmxCompendiumData> > compDataDeleter;
+QDict<TmxCompendiumData> *TmxCompendium::_compDict = 0;
+
+TmxCompendium::TmxCompendium(QObject *parent, const char *name)
+ : SearchEngine(parent, name)
+{
+ prefWidget=0;
+ data=0;
+ error=false;
+ stop=false;
+ active=false;
+ initialized=false;
+ loading=false;
+
+ langCode = KGlobal::locale()->language();
+
+ caseSensitive = false;
+ wholeWords=true;
+
+ matchEqual = true;
+ matchNGram = true;
+ matchIsContained = false;
+ matchContains = true;
+ matchWords=true;
+
+
+ loadTimer = new QTimer(this);
+ connect(loadTimer,SIGNAL(timeout()),this,SLOT(slotLoadCompendium()));
+}
+
+TmxCompendium::~TmxCompendium()
+{
+ if(isSearching())
+ {
+ stopSearch();
+ }
+
+ unregisterData();
+}
+
+bool TmxCompendium::isReady() const
+{
+ return (isSearching() || !error);
+}
+
+
+bool TmxCompendium::isSearching() const
+{
+ return (active || loading);
+}
+
+
+void TmxCompendium::saveSettings(KConfigBase *config)
+{
+ if(autoUpdate && prefWidget && prefWidget->settingsChanged())
+ {
+ applySettings();
+ }
+
+ config->writeEntry("CaseSensitive",caseSensitive);
+ config->writeEntry("WholeWords", wholeWords);
+
+ config->writeEntry("MatchEqual", matchEqual);
+ config->writeEntry("MatchIsContained",matchIsContained);
+ config->writeEntry("MatchContains", matchContains);
+ config->writeEntry("MatchWords", matchWords);
+ config->writeEntry("MatchNGram", matchNGram);
+
+ config->writeEntry("Compendium", url);
+}
+
+void TmxCompendium::readSettings(KConfigBase *config)
+{
+ caseSensitive = config->readBoolEntry("CaseSensitive", false);
+ wholeWords = config->readBoolEntry("WholeWords",true);
+
+ matchEqual = config->readBoolEntry("MatchEqual", true);
+ matchIsContained = config->readBoolEntry("MatchIsContained", false);
+ matchContains = config->readBoolEntry("MatchContains",true);
+ matchWords = config->readBoolEntry("MatchWords",true);
+ matchNGram = config->readBoolEntry("MatchNGram",true);
+
+ QString newPath = config->readEntry("Compendium","http://i18n.kde.org/po_overview/@LANG@.messages");
+ if(!initialized)
+ {
+ url = newPath;
+ }
+ else if(newPath != url)
+ {
+ url = newPath;
+ loadCompendium();
+ }
+
+
+ restoreSettings();
+}
+
+PrefWidget *TmxCompendium::preferencesWidget(QWidget *parent)
+{
+ prefWidget = new TmxCompendiumPreferencesWidget(parent,"tmxcompendium_prefwidget");
+ connect(prefWidget, SIGNAL(applySettings()), this, SLOT(applySettings()));
+ connect(prefWidget, SIGNAL(restoreSettings())
+ , this, SLOT(restoreSettings()));
+
+ restoreSettings();
+
+ return prefWidget;
+}
+
+const KAboutData *TmxCompendium::about() const
+{
+ return PcFactory::instance()->aboutData();
+}
+
+
+QString TmxCompendium::name() const
+{
+ return i18n("TMX Compendium");
+}
+
+QString TmxCompendium::id() const
+{
+ return "tmxcompendium";
+}
+
+QString TmxCompendium::lastError()
+{
+ return errorMsg;
+}
+
+
+bool TmxCompendium::startSearch(const QString& text, uint pluralForm, const SearchFilter*)
+{
+ if(autoUpdate && prefWidget && prefWidget->settingsChanged())
+ {
+ applySettings();
+ }
+
+ if(isSearching())
+ return false;
+
+ clearResults();
+ stop = false;
+ active = true;
+
+ if(!initialized)
+ {
+ if(loadTimer->isActive())
+ loadTimer->stop();
+
+ slotLoadCompendium();
+ }
+
+ if(error || !data)
+ {
+ active = false;
+ return false;
+ }
+
+ if(data->active())
+ {
+ active = false;
+ return true;
+ }
+
+ emit started();
+
+
+ QValueList<int> foundIndices;
+ QValueList<int> checkedIndices;
+ uint checkCounter=0;
+
+ const int *index = data->exactDict(text);
+ if(index)
+ {
+ foundIndices.append(*index);
+
+ SearchResult *result = new SearchResult;
+ result->requested = text;
+ result->found = data->msgid(*index);
+ result->translation = data->msgstr(*index);
+ result->score = 100;
+
+ TranslationInfo *info = new TranslationInfo;
+ info->location = directory(realURL,0);
+ info->translator = QString::null;
+ info->description = QString::null;
+ result->descriptions.append(info);
+
+ results.append(result);
+
+ emit numberOfResultsChanged(results.count());
+ emit resultFound(result);
+ }
+
+ QString searchStr=TmxCompendiumData::simplify(text);
+
+
+ if(!caseSensitive)
+ {
+ searchStr = searchStr.lower();
+ }
+
+ QString temp = searchStr;
+ temp = temp.lower();
+
+ const QValueList<int> *indexList = data->allDict(temp);
+ if(indexList)
+ {
+ QValueList<int>::ConstIterator it;
+ for( it = indexList->begin(); it != indexList->end(); ++it )
+ {
+ if(foundIndices.contains(*it))
+ {
+ continue;
+ }
+
+ QString origStr = data->msgid(*it);
+ origStr = TmxCompendiumData::simplify(origStr);
+
+
+ if(!caseSensitive)
+ {
+ origStr = origStr.lower();
+ }
+
+ if(origStr==searchStr)
+ {
+ foundIndices.append(*it);
+
+ SearchResult *result = new SearchResult;
+ result->requested = text;
+ result->found = data->msgid(*it);
+ result->translation = data->msgstr(*it);
+ // FIXME: handle plural forms properly
+ result->score = score(result->requested,result->found.first());
+
+ TranslationInfo *info = new TranslationInfo;
+ info->location = directory(realURL,0);
+ info->translator = QString::null;
+ info->description = QString::null;
+ result->descriptions.append(info);
+
+ addResult(result);
+ }
+ }
+ }
+
+ QStringList wList = TmxCompendiumData::wordList(searchStr);
+ for ( QStringList::Iterator wit = wList.begin()
+ ; wit != wList.end(); ++wit )
+ {
+ if(stop)
+ break;
+
+ indexList = data->wordDict((*wit).lower());
+ if(indexList)
+ {
+ QValueList<int>::ConstIterator it;
+ for( it = indexList->begin(); it != indexList->end(); ++it )
+ {
+ if(stop)
+ break;
+
+ if(foundIndices.contains(*it))
+ {
+ continue;
+ }
+
+ if(checkedIndices.contains(*it))
+ {
+ continue;
+ }
+
+ checkedIndices.append(*it);
+ checkCounter++;
+
+ if( (100*(checkCounter+1))%data->numberOfEntries() < 100)
+ {
+ emit progress( (100*(checkCounter+1))/data->numberOfEntries());
+ }
+
+ kapp->processEvents(100);
+
+ QString origStr = data->msgid(*it);
+ origStr = TmxCompendiumData::simplify(origStr);
+
+
+ if(!caseSensitive)
+ {
+ origStr = origStr.lower();
+ }
+
+ bool found = false;
+ if(matchWords)
+ {
+ if(!caseSensitive)
+ {
+ found=true;
+ }
+ else
+ {
+ QString s=*wit;
+ QString o=origStr;
+
+ if(wholeWords)
+ {
+ s=" "+*wit+" ";
+ o=" "+origStr+" ";
+ }
+ if(o.contains(s))
+ {
+ found=true;
+ }
+ }
+ }
+
+
+ if(!found && origStr==searchStr)
+ {
+ found =true;
+ }
+
+ // if there is an string which just contains ignored characters,
+ // continue
+ if(!found && origStr.isEmpty() ||
+ (origStr.length() == 1 && text.length() > 1))
+ {
+ continue;
+ }
+
+
+ if(!found && matchContains && !wholeWords)
+ {
+ QString s=maskString(searchStr);
+ QRegExp searchReg(s);
+
+ if(searchReg.search(origStr) >= 0)
+ found=true;
+ }
+
+ if(!found && matchIsContained && !wholeWords)
+ {
+ QString s=maskString(origStr);
+ QRegExp reg(s);
+
+ if(reg.search(searchStr) >= 0)
+ {
+ found = true;
+ }
+ }
+ if(!found && matchWords && !wholeWords)
+ {
+ QStringList list = TmxCompendiumData::wordList(searchStr);
+
+ for ( QStringList::Iterator wit2 = list.begin()
+ ; wit2 != list.end(); ++wit2 )
+ {
+ QString s=maskString(*wit2);
+ QRegExp reg(s);
+
+ if(reg.search(origStr) >= 0)
+ {
+ found = true;
+ }
+ }
+ }
+
+ if(found)
+ {
+ foundIndices.append(*it);
+
+ SearchResult *result = new SearchResult;
+ result->requested = text;
+ result->found = data->msgid(*it);
+ result->translation = data->msgstr(*it);
+ // FIXME: handle plural forms properly
+ result->score = score(result->requested,(result->found.first()));
+
+ TranslationInfo *info = new TranslationInfo;
+ info->location = directory(realURL,0);
+ info->translator = QString::null;
+ info->description = QString::null;
+ result->descriptions.append(info);
+
+ addResult(result);
+ }
+ }
+ }
+ }
+
+
+ if( matchNGram ||
+ (!wholeWords && (matchContains || matchIsContained || matchWords))
+ )
+ {
+ QRegExp searchReg;
+ if(matchContains)
+ {
+ QString s=maskString(searchStr);
+ searchReg.setPattern(s);
+ }
+
+
+ bool breakLoop=false;
+ int i=-1;
+ while(!breakLoop)
+ {
+ if(stop)
+ {
+ breakLoop=true;
+ break;
+ }
+
+ i++;
+
+ if(checkedIndices.contains(i))
+ {
+ continue;
+ }
+
+ checkedIndices.append(i);
+ checkCounter++;
+
+ if(foundIndices.contains(i))
+ {
+ continue;
+ }
+
+ kapp->processEvents(100);
+
+ if(i >= data->numberOfEntries())
+ {
+ breakLoop = true;
+ break;
+ }
+
+ if( (100*(checkCounter+1))%data->numberOfEntries() < 100)
+ {
+ emit progress( (100*(checkCounter+1))/data->numberOfEntries());
+ }
+
+ QString origStr = data->msgid(i);
+ origStr = TmxCompendiumData::simplify(origStr);
+
+ if(!caseSensitive)
+ {
+ origStr = origStr.lower();
+ }
+
+
+ // if there is an string which just contains ignored characters,
+ // continue
+ if(origStr.isEmpty() ||
+ (origStr.length() == 1 && text.length() > 1))
+ {
+ continue;
+ }
+
+ bool found = false;
+ if(matchContains && searchReg.search(origStr) >= 0)
+ {
+ found=true;
+ }
+
+
+ if(!found && matchIsContained)
+ {
+ QString s=maskString(origStr);
+ QRegExp reg(s);
+
+ if(reg.search(searchStr) >= 0)
+ {
+ found = true;
+ }
+ }
+ if(!found && matchWords)
+ {
+ QStringList list = TmxCompendiumData::wordList(searchStr);
+
+ for ( QStringList::Iterator wit2 = list.begin()
+ ; wit2 != list.end(); ++wit2 )
+ {
+ QString s=maskString(*wit2);
+
+ if(wholeWords)
+ {
+ origStr = " "+origStr+" ";
+ s=" "+s+" ";
+ }
+ QRegExp reg(s);
+
+ if(reg.search(origStr) >= 0)
+ {
+ found = true;
+ }
+ }
+ }
+
+ if(!found && matchNGram)
+ {
+ // to get more results one could
+ // interchange searchStr and origStr when
+ // the latter is shorter
+
+ found = ( ngramMatch(searchStr,origStr,NGRAM_LEN)
+ > LIM_NGRAM );
+ }
+
+ if(found)
+ {
+ foundIndices.append(i);
+
+ SearchResult *result = new SearchResult;
+ result->requested = text;
+ result->found = data->msgid(i);
+ result->translation = data->msgstr(i);
+ // FIXME: handle plural forms properly
+ result->score = score(result->requested,(result->found.first()));
+
+ TranslationInfo *info = new TranslationInfo;
+ info->location = directory(realURL,0);
+ info->translator = QString::null;
+ info->description = QString::null;
+ result->descriptions.append(info);
+
+ addResult(result);
+ }
+ }
+ }
+
+ if( (100*(checkCounter+1))/data->numberOfEntries() < 100 && !stop)
+ {
+ for(int i=(100*(checkCounter+1))/data->numberOfEntries(); i<=100; i++)
+ {
+ emit progress(i);
+ }
+ }
+
+
+ active = false;
+ stop = false;
+ emit finished();
+
+ return true;
+}
+
+void TmxCompendium::stopSearch()
+{
+ stop=true;
+}
+
+
+void TmxCompendium::applySettings()
+{
+ if(!prefWidget)
+ return;
+
+ if(isSearching())
+ stopSearch();
+
+ caseSensitive = prefWidget->caseSensitive();
+ wholeWords = prefWidget->wholeWords();
+
+ matchEqual = prefWidget->matchEqual();
+ matchNGram = prefWidget->matchNGram();
+ matchIsContained = prefWidget->matchIsContained();
+ matchContains = prefWidget->matchContains();
+ matchWords = prefWidget->matchWords();
+
+
+ bool needLoading=false;
+
+
+ QString newPath = prefWidget->url();
+ if(!initialized)
+ {
+ url = newPath;
+ }
+ else if(newPath != url)
+ {
+ url = newPath;
+ needLoading = true;
+ }
+
+ if(needLoading)
+ {
+ loadCompendium();
+ initialized=false;
+ }
+}
+
+void TmxCompendium::restoreSettings()
+{
+ if(!prefWidget)
+ return;
+
+ prefWidget->setCaseSensitive(caseSensitive);
+ prefWidget->setWholeWords(wholeWords);
+ prefWidget->setURL(url);
+
+ prefWidget->setMatchEqual(matchEqual);
+ prefWidget->setMatchNGram(matchNGram);
+ prefWidget->setMatchIsContained(matchIsContained);
+ prefWidget->setMatchContains(matchContains);
+ prefWidget->setMatchWords(matchWords);
+}
+
+void TmxCompendium::loadCompendium()
+{
+ if(!loading && !loadTimer->isActive())
+ loadTimer->start(100,true);
+}
+
+void TmxCompendium::slotLoadCompendium()
+{
+ if(loading)
+ return;
+
+ if(loadTimer->isActive())
+ loadTimer->stop();
+
+ loading = true;
+
+ if(data)
+ {
+ unregisterData();
+ }
+
+
+ QString path=url;
+
+ if(path.contains("@LANG@"))
+ {
+ path.replace("@LANG@",langCode);
+ }
+ KURL u=KCmdLineArgs::makeURL(path.local8Bit());
+ realURL = u.url();
+
+ registerData();
+
+
+ if(!data)
+ {
+ kdError() << "no data object in tmxcompendium?" << endl;
+
+ loading=false;
+ return;
+ }
+
+ if(!data->initialized())
+ {
+ if(!data->active())
+ {
+ data->load(u,langCode);
+ recheckData();
+ if(error)
+ {
+ emit hasError(errorMsg);
+ }
+ }
+ else
+ {
+ connect(data, SIGNAL(progressEnds()), this, SLOT(recheckData()));
+ }
+ }
+ else
+ {
+ recheckData();
+ if(error)
+ {
+ emit hasError(errorMsg);
+ }
+ }
+
+ initialized=true;
+}
+
+void TmxCompendium::recheckData()
+{
+ if(data)
+ {
+ disconnect(data, SIGNAL(progressEnds()), this, SLOT(recheckData()));
+
+ error = data->hasErrors();
+ errorMsg = data->errorMsg();
+ }
+
+ loading=false;
+}
+
+QString TmxCompendium::maskString(QString s) const
+{
+ s.replace('\\',"\\\\");
+ s.replace('?',"\\?");
+ s.replace('[',"\\[");
+ s.replace('.',"\\.");
+ s.replace('*',"\\*");
+ s.replace('+',"\\+");
+ s.replace('^',"\\^");
+ s.replace('$',"\\$");
+ s.replace('(',"\\(");
+ s.replace(')',"\\)");
+ s.replace('{',"\\{");
+ s.replace('}',"\\}");
+ s.replace('|',"\\|");
+
+ return s;
+}
+
+void TmxCompendium::addResult(SearchResult *result)
+{
+ if(results.last() && results.last()->score >= result->score)
+ {
+ results.append(result);
+ }
+ else
+ {
+ SearchResult *sr;
+ for(sr = results.first(); sr != 0; sr=results.next())
+ {
+ if(sr->score < result->score)
+ {
+ results.insert(results.at(),result);
+ emit resultsReordered();
+ break;
+ }
+ }
+
+ if(!sr)
+ {
+ results.append(result);
+ }
+ }
+
+ emit numberOfResultsChanged(results.count());
+ emit resultFound(result);
+}
+
+
+void TmxCompendium::setLanguageCode(const QString& lang)
+{
+ if(initialized && url.contains("@LANG@") && lang!=langCode
+ && !loadTimer->isActive() )
+ {
+ initialized=false;
+ }
+
+ langCode=lang;
+}
+
+QString TmxCompendium::translate(const QString& text, uint pluralForm)
+{
+ if(!initialized)
+ {
+ if(loadTimer->isActive())
+ loadTimer->stop();
+
+ slotLoadCompendium();
+ }
+
+ if(error || !data || data->active())
+ {
+ return QString::null;
+ }
+
+
+ const int *index = data->exactDict(text);
+
+ if(index)
+ {
+ return data->msgstr(*index);
+ }
+
+ return QString::null;
+}
+
+QString TmxCompendium::fuzzyTranslation(const QString& text, int &score, uint pluralForm)
+{
+ if(!initialized)
+ {
+ if(loadTimer->isActive())
+ loadTimer->stop();
+
+ slotLoadCompendium();
+ }
+
+ if(error || !data || data->active())
+ {
+ return QString::null;
+ }
+
+ // try to find fuzzy string
+ bool breakLoop = false;
+ stop = false;
+ int i=-1;
+ int best_matching = -1;
+ int best_match = 0;
+ int total = data->numberOfEntries();
+
+ QString searchStr = TmxCompendiumData::simplify(text);
+
+ //kdDebug(750) << "find best match for " << searchStr << endl;
+
+ while(!breakLoop)
+ {
+
+ // progress and loop control
+ if(stop)
+ {
+ breakLoop=true;
+ break;
+ }
+
+ i++;
+
+ if(i >= total)
+ {
+ breakLoop = true;
+ break;
+ }
+
+ if( (100*(i+1))%total < 100)
+ {
+ emit progress( (100*(i+1))/total);
+ }
+
+ // get a message from the catalog
+ QString origStr = data->msgid(i);
+ origStr = TmxCompendiumData::simplify(origStr);
+
+ // don't match too long strings for short search string
+ if (origStr.length() > 2*searchStr.length())
+ continue;
+ // kdDebug(750) << i << ": matching " << origStr << endl;
+
+ int ngram_result = ngramMatch(searchStr,origStr);
+
+ if (ngram_result > best_match) {
+ best_match = ngram_result;
+ best_matching = i;
+
+ // kdDebug(750) << "[" << ngram_result << "] " << text << "-"
+ // << origStr << endl;
+ }
+ }
+
+ if (best_match > LIM_NGRAM) {
+ score = best_match;
+ return data->msgstr(best_matching);
+ }
+
+ return QString::null;
+}
+
+
+void TmxCompendium::unregisterData()
+{
+ if(data)
+ {
+ disconnect(data, SIGNAL(progressStarts(const QString&)), this
+ , SIGNAL(progressStarts(const QString&)));
+ disconnect(data, SIGNAL(progressEnds()), this , SIGNAL(progressEnds()));
+ disconnect(data, SIGNAL(progress(int)), this , SIGNAL(progress(int)));
+
+ if(data->active())
+ {
+ disconnect(data,SIGNAL(progressEnds()),this,SLOT(recheckData()));
+ }
+
+ if(data->unregisterObject(this))
+ {
+ if(!data->active())
+ {
+ compendiumDict()->remove(realURL);
+ }
+ else
+ {
+ connect(data,SIGNAL(progressEnds()),this,SLOT(removeData()));
+ }
+ }
+
+ data=0;
+ }
+}
+
+void TmxCompendium::registerData()
+{
+ data = compendiumDict()->find(realURL);
+ if(!data)
+ {
+ data = new TmxCompendiumData;
+ compendiumDict()->insert(realURL,data);
+ }
+
+ data->registerObject(this);
+
+ if(data->active())
+ {
+ emit progressStarts(i18n("Loading PO compendium"));
+ }
+
+ connect(data, SIGNAL(progressStarts(const QString&)), this
+ , SIGNAL(progressStarts(const QString&)));
+ connect(data, SIGNAL(progressEnds()), this , SIGNAL(progressEnds()));
+ connect(data, SIGNAL(progress(int)), this , SIGNAL(progress(int)));
+}
+
+void TmxCompendium::removeData()
+{
+ const QObject *s=sender();
+ if(s && s->inherits("TmxCompendiumData"))
+ {
+ const TmxCompendiumData *d=static_cast<const TmxCompendiumData*>(s);
+ if(d)
+ {
+ QDictIterator<TmxCompendiumData> it(*compendiumDict());
+ while(it.current())
+ {
+ if(it.current() == d)
+ {
+ if(!d->hasObjects())
+ {
+ compendiumDict()->remove(it.currentKey());
+ }
+
+ break;
+ }
+
+ ++it;
+ }
+ }
+
+ }
+}
+
+QDict<TmxCompendiumData> *TmxCompendium::compendiumDict()
+{
+ if(!_compDict)
+ {
+ _compDict=compDataDeleter.setObject( new QDict<TmxCompendiumData> );
+ _compDict->setAutoDelete(true);
+ }
+
+ return _compDict;
+}
+
+
+
+#include "tmxcompendium.moc"
diff --git a/kbabel/kbabeldict/modules/tmx/tmxcompendium.desktop b/kbabel/kbabeldict/modules/tmx/tmxcompendium.desktop
new file mode 100644
index 00000000..cae7d333
--- /dev/null
+++ b/kbabel/kbabeldict/modules/tmx/tmxcompendium.desktop
@@ -0,0 +1,50 @@
+[Desktop Entry]
+Type=Service
+Name=TMX Compendium Module for KBabelDict
+Name[bg]=TMX компендиум за KBabelDict
+Name[bs]=Modul TMX kompendijuma za KBabelDict
+Name[ca]=Mòdul del Compendi TMX per a KBabelDict
+Name[cs]=Modul s TMX kompendiem pro KBabelDict
+Name[cy]=Modiwl Compendiwm TMX i KBabelDict
+Name[da]=TMX kompendium-module for KBabelDict
+Name[de]=TMX-Kompendium-Modul für KBabelDict
+Name[el]=ΆÏθÏωμα επιτομής TMX για το KBabelDict
+Name[es]=Módulo de compendio TMX para KBabelDict
+Name[et]=KBabelDicti TMX kompendiumi moodul
+Name[eu]=TMX laburpen modulua KBabelDict-entzat
+Name[fa]=پیمانۀ مختصر TMX برای KBabelDict
+Name[fi]=KBabelDict-ohjelman TMX-kokoelmatiedostomoduuli
+Name[fr]=Module de fichier de référence des TMX pour KBabelDict
+Name[gl]=Módulo de compendio TMX para KBabelDict
+Name[hi]=के-बेबल-डिकà¥à¤¶ के लिठटीà¤à¤®à¤à¤•à¥à¤¸ कमà¥à¤ªà¥‡à¤‚डियम मॉडà¥à¤¯à¥‚ल
+Name[hu]=TMX összefoglaló modul a KBabelDicthez
+Name[is]=TMX ágrips eining fyrir KBabel orðabókina
+Name[it]=Modulo TMX Compendium per KBabelDict
+Name[ja]=KBabelDict TMX è¦ç´„モジュール
+Name[ka]=TMX კáƒáƒœáƒ¡áƒžáƒ”ქტის მáƒáƒ“ული KBabelDict-სთვის
+Name[kk]=KBabelDict-тың TMX аудармалар жиынтық модулі
+Name[lt]=KBabelDict TMX tekstyno modulis
+Name[ms]=Modul Kompendium TMX untuk KBabelDict
+Name[nb]=TMX-kompendium-modul for KBabelDict
+Name[nds]=TMX-Kompendiummoduul för KBabelDict
+Name[ne]=KBabelDict का लागि टीà¤à¤®à¤à¤•à¥à¤¸ संकà¥à¤·à¥‡à¤ª मोडà¥à¤¯à¥à¤²
+Name[nl]=TMX-samenvattingmodule voor KBabelDict
+Name[nn]=TMX-kompendiemodul for KBabelDict
+Name[pa]=ਕੇਬਬੇਲ-ਸ਼ਬਦਕੋਸ਼ ਲਈ TMX ਅਨà©à¨µà¨¾à¨¦ ਮੈਡੀਊਲ
+Name[pl]=Moduł Kompendium TMX dla KBabelDict
+Name[pt]=Módulo de Compêndio de TMX para o KBabelDict
+Name[pt_BR]=Módulo de Compêndio TMX para o KBabelDict
+Name[ru]=Модуль опиÑÐ°Ð½Ð¸Ñ TMX Ð´Ð»Ñ KBabelDict
+Name[sk]=TMX kompendium pre KBabelDict
+Name[sl]=Modul zbornika TMX za KBabelDict
+Name[sr]=Модул TMX зборника за KBabelDict
+Name[sr@Latn]=Modul TMX zbornika za KBabelDict
+Name[sv]=TMX-kompendiemodul för Kbabeldict
+Name[ta]=Kபாபேலà¯à®•à¯à®•à®¾à®© காமà¯à®ªà¯†à®©à¯à®Ÿà®¿à®¯à®®à¯ TMX கூறà¯
+Name[tg]=Модули таÑвири TMX барои KBabelDict
+Name[tr]=KBabelDict için TMX Özet Modülü
+Name[uk]=Модуль збірки перекладів TMX Ð´Ð»Ñ KBabelDict
+Name[zh_CN]=KBabelDict çš„ TMX 概è¦è¯å…¸æ¨¡å—
+Name[zh_TW]=KBabelDict TMX 摘è¦æ¨¡çµ„
+X-KDE-Library=kbabeldict_tmxcompendium
+ServiceTypes=KBabelDictModule
diff --git a/kbabel/kbabeldict/modules/tmx/tmxcompendium.h b/kbabel/kbabeldict/modules/tmx/tmxcompendium.h
new file mode 100644
index 00000000..9a2f8fba
--- /dev/null
+++ b/kbabel/kbabeldict/modules/tmx/tmxcompendium.h
@@ -0,0 +1,137 @@
+/* ****************************************************************************
+ This file is part of KBabel
+
+ Copyright (C) 2000 by Matthias Kiefer
+ <matthias.kiefer@gmx.de>
+ 2002 by Stanislav Visnovsky
+ <visnovsky@kde.org>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the 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, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+ In addition, as a special exception, the copyright holders give
+ permission to link the code of this program with any edition of
+ the Qt library by Trolltech AS, Norway (or with modified versions
+ of Qt that use the same license as Qt), and distribute linked
+ combinations including the two. You must obey the GNU General
+ Public License in all respects for all of the code used other than
+ Qt. If you modify this file, you may extend this exception to
+ your version of the file, but you are not obligated to do so. If
+ you do not wish to do so, delete this exception statement from
+ your version.
+
+**************************************************************************** */
+
+#ifndef TMXCOMPENDIUM_H
+#define TMXCOMPENDIUM_H
+
+#include "tmxcompendiumdata.h"
+#include "searchengine.h"
+
+#include <qdict.h>
+#include <qfile.h>
+#include <qguardedptr.h>
+
+class TmxCompendiumPreferencesWidget;
+class KConfigBase;
+class QTimer;
+
+class TmxCompendium : public SearchEngine
+{
+ Q_OBJECT
+
+public:
+ TmxCompendium(QObject *parent=0, const char *name=0);
+ virtual ~TmxCompendium();
+
+ virtual bool isReady() const;
+
+ virtual QString translate(const QString& text, uint pluralForm);
+ virtual QString fuzzyTranslation(const QString& text, int &score, uint pluralForm);
+
+ virtual bool isSearching() const;
+
+ virtual void saveSettings(KConfigBase *config);
+ virtual void readSettings(KConfigBase *config);
+
+ virtual PrefWidget *preferencesWidget(QWidget *parent);
+
+ virtual const KAboutData *about() const;
+
+ virtual QString name() const;
+
+ virtual QString id() const;
+
+ virtual QString lastError();
+
+
+public slots:
+ virtual bool startSearch(const QString& text, uint pluralForm, const SearchFilter* filter);
+ virtual void stopSearch();
+ virtual void setLanguageCode(const QString& lang);
+
+protected slots:
+ /** reads the current settings from the preferences dialog */
+ void applySettings();
+
+ /** sets the current settings in the preferences dialog */
+ void restoreSettings();
+
+ void slotLoadCompendium();
+
+ void recheckData();
+ void removeData();
+
+protected:
+ void loadCompendium();
+ void addResult(SearchResult *);
+ QString maskString(QString string) const;
+
+ void registerData();
+ void unregisterData();
+
+private:
+ QGuardedPtr<TmxCompendiumPreferencesWidget> prefWidget;
+ TmxCompendiumData *data;
+ QTimer *loadTimer;
+
+ QString url;
+ QString realURL;
+ QString langCode;
+
+ bool caseSensitive;
+ bool wholeWords;
+
+ bool matchEqual;
+ bool matchIsContained;
+ bool matchContains;
+ bool matchWords;
+ bool matchNGram;
+
+ bool buildIndex;
+ uint freeMemDelay;
+
+ bool error;
+ QString errorMsg;
+
+ bool stop;
+ bool active;
+ bool initialized;
+ bool loading;
+
+ static QDict<TmxCompendiumData> *_compDict;
+ static QDict<TmxCompendiumData> *compendiumDict();
+};
+
+#endif
diff --git a/kbabel/kbabeldict/modules/tmx/tmxcompendiumdata.cpp b/kbabel/kbabeldict/modules/tmx/tmxcompendiumdata.cpp
new file mode 100644
index 00000000..3fa84aa4
--- /dev/null
+++ b/kbabel/kbabeldict/modules/tmx/tmxcompendiumdata.cpp
@@ -0,0 +1,308 @@
+/* ****************************************************************************
+ This file is part of KBabel
+
+ Copyright (C) 2001 by Matthias Kiefer
+ <matthias.kiefer@gmx.de>
+ 2002 by Stanislav Visnovsky
+ <visnovsky@kde.org>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the 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, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+ In addition, as a special exception, the copyright holders give
+ permission to link the code of this program with any edition of
+ the Qt library by Trolltech AS, Norway (or with modified versions
+ of Qt that use the same license as Qt), and distribute linked
+ combinations including the two. You must obey the GNU General
+ Public License in all respects for all of the code used other than
+ Qt. If you modify this file, you may extend this exception to
+ your version of the file, but you are not obligated to do so. If
+ you do not wish to do so, delete this exception statement from
+ your version.
+
+**************************************************************************** */
+#include "tmxcompendiumdata.h"
+
+#include <qdom.h>
+#include <qfile.h>
+
+#include <tagextractor.h>
+#include <resources.h>
+
+#include <kapplication.h>
+#include <kdebug.h>
+#include <klocale.h>
+#include <kio/netaccess.h>
+
+using namespace KBabel;
+
+TmxCompendiumData::TmxCompendiumData(QObject *parent)
+ : QObject(parent)
+ , _active(false)
+ , _error(false)
+ , _initialized(false)
+ , _exactDict(9887)
+ , _allDict(9887)
+ , _wordDict(9887)
+{
+ _exactDict.setAutoDelete(true);
+ _allDict.setAutoDelete(true);
+ _wordDict.setAutoDelete(true);
+}
+
+
+bool TmxCompendiumData::load(const KURL& url, const QString& language)
+{
+ kdDebug(KBABEL_SEARCH) << "Load " << url.url() << " in " << language << endl;
+ if(_active)
+ return false;
+
+
+ _error = false;
+ _active = true;
+
+ _exactDict.clear();
+ _allDict.clear();
+ _wordDict.clear();
+
+
+ emit progressStarts(i18n("Loading TMX compendium"));
+
+ QDomDocument doc( "mydocument" );
+
+ QString target;
+
+ if( KIO::NetAccess::download( url, target ) )
+ {
+ QFile f( target );
+ if ( !f.open( IO_ReadOnly ) )
+ {
+ _error = true;
+ _errorMsg = i18n( "Cannot open the file." );
+ }
+ else if ( !doc.setContent( &f ) ) {
+ _error = true;
+ _errorMsg = i18n( "Cannot parse XML data." );
+ }
+ f.close();
+ KIO::NetAccess::removeTempFile(target);
+ } else {
+ _error = true;
+ _errorMsg = i18n( "Cannot open the file." );
+ }
+
+ QDomElement docElem = doc.documentElement();
+
+ if( docElem.tagName() != "tmx" || !(docElem.hasAttribute("version")
+ && docElem.attribute("version") == "1.4" ) )
+ {
+ _error = true;
+ _errorMsg = i18n( "Unsupported format.");
+ }
+
+
+ if( _error )
+ {
+ _errorMsg = i18n("Error while trying to read file for TMX Compendium module:\n"
+ "%1\n"
+ "Reason: %2")
+ .arg(url.prettyURL()).arg(_errorMsg);
+
+ kdDebug(KBABEL_SEARCH) << "Error: " << _errorMsg << endl;
+
+ emit progressEnds();
+
+ _active = false;
+ _initialized=true;
+
+ return false;
+ }
+
+ emit progressStarts(i18n("Building indices"));
+
+ QDomNodeList tuTags = docElem.elementsByTagName("tu");
+ uint total = tuTags.count();
+
+ _originals.clear();
+ _originals.resize(total);
+ _translations.clear();
+ _translations.resize(total);
+
+ uint lastindex = 0;
+
+ for(uint i=0; i < total; i++)
+ {
+ if( (100*(i+1))%total < 100 )
+ {
+ emit progress((100*(i+1))/total);
+ kapp->processEvents(100);
+ }
+
+ QDomNodeList tuvTags = tuTags.item(i).toElement().elementsByTagName("tuv");
+ QString english, other;
+ for( uint j = 0 ; j < tuvTags.count() ; j++ )
+ {
+ QDomElement el = tuvTags.item(j).toElement();
+ if( el.attribute("xml:lang").upper() == "EN" ) english = el.text();
+ if( el.attribute("xml:lang").upper().startsWith(language.upper()) )
+ other = el.text();
+ }
+
+ if( !english.isEmpty() && !other.isEmpty() )
+ {
+ kdDebug(KBABEL_SEARCH) << english << " to " << lastindex << endl;
+ _originals[lastindex] = english;
+ _translations[lastindex] = other;
+
+ QString temp = english;
+
+ int *index = new int(lastindex);
+ _exactDict.insert(temp,index);
+
+ temp = simplify(temp);
+ temp = temp.lower();
+
+ if(!temp.isEmpty() && temp.length() > 1)
+ {
+ QValueList<int> *indexList=_allDict[temp];
+
+ if(!indexList)
+ {
+ indexList = new QValueList<int>;
+ _allDict.insert(temp,indexList);
+ }
+
+ indexList->append(lastindex);
+
+ QStringList wList = wordList(temp);
+ for ( QStringList::Iterator it = wList.begin()
+ ; it != wList.end(); ++it )
+ {
+ if( (*it).length() > 1)
+ {
+ indexList=_wordDict[*it];
+
+ if(!indexList)
+ {
+ indexList = new QValueList<int>;
+ _wordDict.insert(*it,indexList);
+ }
+
+ indexList->append(lastindex);
+ }
+ }
+ }
+ lastindex++;
+ }
+ }
+
+
+ // remove words, that are too frequent
+ uint max=_allDict.count()/10;
+ QDictIterator< QValueList<int> > it(_wordDict);
+ while ( it.current() )
+ {
+ if(it.current()->count() > max)
+ {
+ _wordDict.remove(it.currentKey());
+ }
+ else
+ {
+ ++it;
+ }
+ }
+
+ if( lastindex == 0)
+ {
+ _error = true;
+ _errorMsg = i18n("Empty database.");
+ }
+
+ kdDebug(KBABEL_SEARCH) << "load done" << endl;
+
+ _initialized=true;
+
+ emit progressEnds();
+
+ _active = false;
+
+ return true;
+}
+
+const int* TmxCompendiumData::exactDict(const QString& text) const
+{
+ return _exactDict[text];
+}
+
+const QValueList<int>* TmxCompendiumData::allDict(const QString& text) const
+{
+ return _allDict[text];
+}
+
+const QValueList<int>* TmxCompendiumData::wordDict(const QString& text) const
+{
+ return _wordDict[text];
+}
+
+const QString TmxCompendiumData::msgid(const int index) const
+{
+ return _originals[index];
+}
+
+const QString TmxCompendiumData::msgstr(const int index) const
+{
+ return _translations[index];
+}
+
+
+void TmxCompendiumData::registerObject(QObject *obj)
+{
+ if(!_registered.containsRef(obj))
+ _registered.append(obj);
+}
+
+bool TmxCompendiumData::unregisterObject(QObject *obj)
+{
+ _registered.removeRef(obj);
+
+ return _registered.count()==0;
+}
+
+bool TmxCompendiumData::hasObjects() const
+{
+ return _registered.count()==0;
+}
+
+QString TmxCompendiumData::simplify(const QString& string)
+{
+ QString result;
+
+ TagExtractor te;
+ te.setString(string);
+ result=te.plainString();
+
+ result=result.simplifyWhiteSpace();
+ result=result.stripWhiteSpace();
+
+ return result;
+}
+
+QStringList TmxCompendiumData::wordList(const QString& string)
+{
+ QString result=TmxCompendiumData::simplify(string);
+
+ return QStringList::split(' ',result);
+}
+
+#include "tmxcompendiumdata.moc"
diff --git a/kbabel/kbabeldict/modules/tmx/tmxcompendiumdata.h b/kbabel/kbabeldict/modules/tmx/tmxcompendiumdata.h
new file mode 100644
index 00000000..bc88a92e
--- /dev/null
+++ b/kbabel/kbabeldict/modules/tmx/tmxcompendiumdata.h
@@ -0,0 +1,106 @@
+/* ****************************************************************************
+ This file is part of KBabel
+
+ Copyright (C) 2001 by Matthias Kiefer
+ <matthias.kiefer@gmx.de>
+ 2002 by Stanislav Visnovsky
+ <visnovsky@kde.org>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the 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, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+ In addition, as a special exception, the copyright holders give
+ permission to link the code of this program with any edition of
+ the Qt library by Trolltech AS, Norway (or with modified versions
+ of Qt that use the same license as Qt), and distribute linked
+ combinations including the two. You must obey the GNU General
+ Public License in all respects for all of the code used other than
+ Qt. If you modify this file, you may extend this exception to
+ your version of the file, but you are not obligated to do so. If
+ you do not wish to do so, delete this exception statement from
+ your version.
+
+**************************************************************************** */
+#ifndef TMXCOMPENDIUMDATA_H
+#define TMXCOMPENDIUMDATA_H
+
+
+#include <kurl.h>
+#include <qdict.h>
+#include <qobject.h>
+#include <qstringlist.h>
+#include <qvaluelist.h>
+#include <qvaluevector.h>
+#include <qptrlist.h>
+
+class TmxCompendiumData : public QObject
+{
+ Q_OBJECT
+
+public:
+ TmxCompendiumData(QObject *parent=0);
+
+ bool load(const KURL& url, const QString& language);
+
+ const int *exactDict(const QString& text) const;
+ const QValueList<int> *allDict(const QString& text) const;
+ const QValueList<int> *wordDict(const QString& text) const;
+
+ const QString msgid(const int index) const;
+ const QString msgstr(const int index) const;
+ const int numberOfEntries() const { return _exactDict.count(); }
+
+ bool active() const { return _active; }
+ bool initialized() const { return _initialized; }
+ bool hasErrors() const { return _error; }
+ QString errorMsg() const { return _errorMsg; }
+
+ /** registers an object, that uses this data */
+ void registerObject(QObject *);
+ /**
+ * unregisters an object, that uses this data
+ *
+ * @return true, if this was the last object
+ */
+ bool unregisterObject(QObject *);
+
+ bool hasObjects() const;
+
+
+ static QString simplify(const QString& text);
+ static QStringList wordList(const QString& text);
+
+signals:
+ void progressStarts(const QString&);
+ void progressEnds();
+ void progress(int);
+
+
+private:
+ bool _active;
+ bool _error;
+ bool _initialized;
+ QString _errorMsg;
+
+ QDict<int> _exactDict;
+ QDict< QValueList<int> > _allDict;
+ QDict< QValueList<int> > _wordDict;
+
+ QValueVector<QString> _originals;
+ QValueVector<QString> _translations;
+
+ QPtrList<QObject> _registered;
+};
+
+#endif
diff --git a/kbabel/kbabeldict/searchengine.cpp b/kbabel/kbabeldict/searchengine.cpp
new file mode 100644
index 00000000..95ab5694
--- /dev/null
+++ b/kbabel/kbabeldict/searchengine.cpp
@@ -0,0 +1,283 @@
+/* ****************************************************************************
+ This file is part of KBabel
+
+ Copyright (C) 2000 by Matthias Kiefer
+ <matthias.kiefer@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.
+
+ 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, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+ In addition, as a special exception, the copyright holders give
+ permission to link the code of this program with any edition of
+ the Qt library by Trolltech AS, Norway (or with modified versions
+ of Qt that use the same license as Qt), and distribute linked
+ combinations including the two. You must obey the GNU General
+ Public License in all respects for all of the code used other than
+ Qt. If you modify this file, you may extend this exception to
+ your version of the file, but you are not obligated to do so. If
+ you do not wish to do so, delete this exception statement from
+ your version.
+
+**************************************************************************** */
+
+
+#include "searchengine.h"
+
+#include <kdebug.h>
+
+SearchResult::SearchResult()
+{
+ score=0;
+ descriptions.setAutoDelete(true);
+}
+
+SearchResult::SearchResult(const SearchResult& r)
+{
+ requested=r.requested;
+ found=r.found;
+ translation=r.translation;
+ plainTranslation=r.plainTranslation;
+ plainFound=r.plainFound;
+ plainRequested=r.plainRequested;
+ descriptions.setAutoDelete(true);
+ score=r.score;
+
+ QPtrListIterator<TranslationInfo> it(r.descriptions);
+ for ( ; it.current(); ++it )
+ {
+ TranslationInfo *ti=new TranslationInfo(*(*it));
+ descriptions.append(ti);
+ }
+
+}
+
+PrefWidget::PrefWidget(QWidget *parent, const char *name)
+ : QWidget(parent,name)
+{
+}
+
+PrefWidget::~PrefWidget()
+{
+}
+
+
+SearchEngine::SearchEngine(QObject *parent, const char *name)
+ : QObject(parent, name)
+{
+ autoUpdate=false;
+ results.setAutoDelete(true);
+}
+
+SearchEngine::~SearchEngine()
+{
+}
+
+bool SearchEngine::startSearchInTranslation(const QString&, unsigned int, const SearchFilter*)
+{
+ return true;
+}
+
+bool SearchEngine::usesRichTextResults()
+{
+ return false;
+}
+
+bool SearchEngine::isEditable()
+{
+ return false;
+}
+
+void SearchEngine::edit()
+{
+}
+
+void SearchEngine::setAutoUpdateOptions(bool activate)
+{
+ autoUpdate=activate;
+}
+
+SearchResult *SearchEngine::result(int n)
+{
+ SearchResult *r=0;
+
+ if(n >= 0 && n < (int)results.count())
+ r = results.at(n);
+
+ return r;
+}
+
+int SearchEngine::numberOfResults() const
+{
+ return results.count();
+}
+
+SearchResult *SearchEngine::nextResult()
+{
+ SearchResult *r= results.next();
+ if(r)
+ return r;
+ else
+ {
+ return 0;
+ }
+}
+
+SearchResult *SearchEngine::prevResult()
+{
+ SearchResult *r= results.prev();
+ if(r)
+ return r;
+ else
+ {
+ return 0;
+ }
+}
+
+SearchResult *SearchEngine::firstResult()
+{
+ SearchResult *r= results.first();
+ if(r)
+ return r;
+ else
+ {
+ return 0;
+ }
+}
+
+
+SearchResult *SearchEngine::lastResult()
+{
+ SearchResult *r= results.last();
+ if(r)
+ return r;
+ else
+ {
+ return 0;
+ }
+}
+
+void SearchEngine::clearResults()
+{
+ results.clear();
+ emit numberOfResultsChanged(0);
+}
+
+
+
+void SearchEngine::setEditedFile(const QString&)
+{
+}
+
+
+void SearchEngine::setEditedPackage(const QString&)
+{
+}
+
+void SearchEngine::setLanguageCode(const QString&)
+{
+}
+
+void SearchEngine::setLanguage(const QString&,const QString&)
+{
+}
+
+
+
+void SearchEngine::stringChanged(const QStringList&,const QString&,unsigned int, const QString&)
+{
+}
+
+
+QString SearchEngine::directory(const QString& path, int n)
+{
+ if(n<0)
+ return QString::null;
+
+ int begin=path.findRev('/');
+ int end=path.length();
+
+ if(begin < 0)
+ {
+ kdDebug() << "not found" << endl;
+ if(n==0)
+ return path;
+ else
+ return QString::null;
+ }
+
+ for(int i=0; i < n; i++)
+ {
+ if(begin==0)
+ {
+ return QString::null;
+ }
+
+ end = begin;
+ begin = path.findRev('/', end-1);
+
+ if(begin < 0)
+ {
+ return QString::null;
+ }
+ }
+
+ begin++;
+ return path.mid(begin,end-begin);
+}
+
+
+uint SearchEngine::score(const QString& orig, const QString& found)
+{
+ if(orig == found)
+ return 100;
+
+ uint scoreA = ngramMatch(found, orig);
+ uint scoreB = ngramMatch(orig,found);
+ uint score = QMIN(scoreA, scoreB);
+
+ QString f = found.lower();
+ QString o = orig.lower();
+
+ scoreA = ngramMatch(f, o);
+ scoreB = ngramMatch(o, f);
+ score = (QMIN(scoreA, scoreB)+score)/2;
+
+ return score;
+}
+
+uint SearchEngine::ngramMatch (const QString& text1, const QString& text2,
+ uint ngram_len)
+{
+ if (text1.length() < ngram_len || text2.length() < ngram_len)
+ return 0;
+
+ uint cnt=0;
+ uint ngram_cnt = text1.length() - ngram_len + 1;
+
+ for (uint i = 0; i < ngram_cnt; i++) {
+ if (text2.find(text1.mid(i,ngram_len)) >= 0)
+ cnt++;
+ }
+
+ return (cnt*100) / ngram_cnt;
+}
+
+
+bool SearchFilter::match( const TranslationInfo& toCheck )
+{
+ // FIXME: not implemented yet
+ return true;
+}
+
+#include "searchengine.moc"
diff --git a/kbabel/kbabeldict/searchengine.h b/kbabel/kbabeldict/searchengine.h
new file mode 100644
index 00000000..db722362
--- /dev/null
+++ b/kbabel/kbabeldict/searchengine.h
@@ -0,0 +1,534 @@
+/* ****************************************************************************
+ This file is part of KBabel
+
+ Copyright (C) 2000 by Matthias Kiefer
+ <matthias.kiefer@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.
+
+ 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, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+ In addition, as a special exception, the copyright holders give
+ permission to link the code of this program with any edition of
+ the Qt library by Trolltech AS, Norway (or with modified versions
+ of Qt that use the same license as Qt), and distribute linked
+ combinations including the two. You must obey the GNU General
+ Public License in all respects for all of the code used other than
+ Qt. If you modify this file, you may extend this exception to
+ your version of the file, but you are not obligated to do so. If
+ you do not wish to do so, delete this exception statement from
+ your version.
+
+**************************************************************************** */
+
+#ifndef SEARCH_ENGINE_H
+#define SEARCH_ENGINE_H
+
+#include <qdatetime.h>
+#include <qptrlist.h>
+#include <qobject.h>
+#include <qstring.h>
+#include <qwidget.h>
+#include <kaboutdata.h>
+#include <kconfigbase.h>
+
+
+/*
+ * This class gives information about the translator, etc.
+ * Information, that is not available in a specific implementation of
+ * the SearchEngine, should be left empty.
+ */
+class KDE_EXPORT TranslationInfo
+{
+public:
+ /**
+ * Information about the location, where this entry was found.
+ * For example the PO-file it was found in, etc.
+ * */
+ QString location;
+
+ /**
+ * The complete path of the file, where this entry was found
+ */
+ QString filePath;
+
+
+ /** The date of the last change */
+ QDateTime lastChange;
+
+ /** The language, the translation belongs to */
+ QString languageCode;
+
+ /**
+ * The translator of this string
+ * For example the translator found in the header of the PO-file.
+ */
+ QString translator;
+
+ /**
+ * The name of a project this translation is a part of.
+ */
+ QString projectName;
+
+ /**
+ * Keywords defined for @ref projectName. For example KDE_3_1_BRANCH (project branch)
+ */
+ QStringList projectKeywords;
+
+ /**
+ * Part/context in a project, for example "multimedia", "admin", etc.
+ */
+ QString projectContext;
+
+ /**
+ * Status of the translation, for example "approved", "spellchecked", "unknown"
+ */
+ QString status;
+
+ /**
+ * Additional information to be presented to the user, for example a comment
+ */
+ QString description;
+};
+
+
+/**
+ * This class contains a result from the search
+ * plus additional information where it was found,
+ * the date and time of the last change, the translator, etc.
+ */
+class KDE_EXPORT SearchResult
+{
+public:
+ SearchResult();
+ SearchResult(const SearchResult&);
+
+ /** The requested string to search for */
+ QString requested;
+
+ /** The string that, was found (a list if it is a plural form) */
+ QStringList found;
+
+ /** The number of a plural form to search for */
+ uint requestedPluralForm;
+
+ /** The translation of the found string */
+ QString translation;
+
+ /** The number of a plural form of the translated string found */
+ uint translationPluralForm;
+
+ /**
+ * This string contains the plain translation if you are
+ * using rich text. If you don't use rich text, you can leave
+ * it empty
+ */
+ QString plainTranslation;
+
+ /**
+ * This string contains the plain string, that was found, if you are
+ * using rich text. If you don't use rich text, you can leave
+ * it empty
+ */
+ QString plainFound;
+
+ /**
+ * This string contains the plain requested string if you are
+ * using rich text. If you don't use rich text, you can leave
+ * it empty
+ */
+ QString plainRequested;
+
+ /**
+ * Constains a score for the found translation. 0 means exact matching.
+ * The higher the score is, the worse is the matching.
+ * How to compute the score is not yet really clear :-(
+ */
+ int score;
+
+ QPtrList<TranslationInfo> descriptions;
+};
+
+/**
+ *
+ */
+class KDE_EXPORT SearchFilter
+{
+public:
+ SearchFilter() :
+ _projects()
+ , _location( QString::null )
+ , _languageCode( QString::null )
+ , _origLanguageCode( QString::null )
+ , _translators()
+ , _projectKeywords()
+ , _projectContexts()
+ , _translationStatus()
+ {}
+
+ virtual ~SearchFilter() {}
+
+ void setProjectName( const QString& project ) { _projects = project; }
+ void setProjectName( const QStringList& projects ) { _projects = projects; }
+
+ /**
+ * Information about the location, where this entry was found.
+ * For example the PO-file it was found in, etc.
+ * */
+ void setLocation( const QString& location) { _location = location; }
+ QString location() const { return _location; }
+
+ /** The original language, the translation was made from */
+ void setOriginalLanguage( const QString& languageCode) { _origLanguageCode = languageCode; }
+
+ /** The language, the translation belongs to */
+ void setTranslationLanguage( const QString& languageCode) { _languageCode = languageCode; }
+
+ /**
+ * The translator of this string
+ * For example the translator found in the header of the PO-file.
+ */
+ void setTranslator( const QString& translator) { _translators = translator ; }
+ void setTranslator( const QStringList& translators) { _translators = translators ; }
+
+ /**
+ * Keywords defined for @ref projectName. For example KDE_3_1_BRANCH (project branch)
+ */
+ void setProjectKeywords( const QStringList& projectKeywords ) { _projectKeywords = projectKeywords; }
+
+ /**
+ * Part/context in a project, for example "multimedia", "admin", etc.
+ */
+ void setProjectContext( const QString& projectContext) { _projectContexts = projectContext; }
+ void setProjectContext( const QStringList& projectContexts) { _projectContexts = projectContexts; }
+
+ /**
+ * Status of the translation, for example "approved", "spellchecked", "unknown"
+ */
+ void setStatus( const QString& translationStatus) { _translationStatus = translationStatus; }
+ void setStatus( const QStringList& translationStati) { _translationStatus = translationStati; }
+
+ /**
+ * The key method of the class - check, if the argument
+ * matches this filter.
+ */
+ virtual bool match( const TranslationInfo& toCheck );
+
+private:
+ QStringList _projects;
+ QString _location;
+ QString _languageCode;
+ QString _origLanguageCode;
+ QStringList _translators;
+ QStringList _projectKeywords ;
+ QStringList _projectContexts;
+ QStringList _translationStatus;
+};
+
+/**
+ * This class is the base class for the preferences widget used to
+ * setup the search engines. Inherit from this and reimplement all
+ * necessary function. The widget should not be bigger than 400x400.
+ * If you need more space, you maybe want to use a tabbed widget.
+ */
+class KDE_EXPORT PrefWidget : public QWidget
+{
+ Q_OBJECT
+
+public:
+ PrefWidget(QWidget *parent, const char* name=0);
+ virtual ~PrefWidget();
+
+public slots:
+ /**
+ * apply changes of the settings
+ */
+ virtual void apply()=0;
+ /**
+ * revert made changes
+ */
+ virtual void cancel()=0;
+ /**
+ * set settings to the standard options
+ */
+ virtual void standard()=0;
+};
+
+
+class KDE_EXPORT SearchEngine : public QObject
+{
+ Q_OBJECT
+
+public:
+ SearchEngine(QObject *parent=0, const char *name=0);
+ virtual ~SearchEngine();
+
+
+
+ /** @return the search result number n */
+ virtual SearchResult *result(int n);
+
+ /** @return the number of search results */
+ virtual int numberOfResults() const;
+
+ /** @return true, if a search is currently active */
+ virtual bool isSearching() const = 0;
+
+
+ /** save the settings in the given config object */
+ virtual void saveSettings(KConfigBase *config) = 0;
+ virtual void readSettings(KConfigBase *config) = 0;
+
+ /** @returns true, if it was initialized correctly */
+ virtual bool isReady() const =0;
+
+
+ /**
+ * @returns the exact translation of text or a empty string
+ * if no exact match was found.
+ */
+ virtual QString translate(const QString& text, const uint pluralForm = 0)=0;
+
+ /**
+ * @returns the translation of text according to the plugin settings or a empty string
+ * if no match was found.
+ */
+ virtual QString searchTranslation(const QString&, int &score, const uint pluralForm = 0) {
+ Q_UNUSED(pluralForm);
+
+ score = 0; return QString::null;
+ }
+
+ /**
+ * @returns a fuzzy translation of text or a empty string
+ * if no good match was found.
+ */
+ virtual QString fuzzyTranslation(const QString& /*text*/, int &score, const uint pluralForm = 0) {
+ Q_UNUSED(pluralForm);
+
+ score = 0; return QString::null; };
+
+
+ /**
+ * Finds all messages belonging to package package. If nothing is found,
+ * the list is empty.
+ * @param package The name of the file, something like "kbabel.po"
+ * @param resultList Will contain the found messages afterwards
+ * @param error If an error occured, this should contain a description
+ *
+ * @return true, if successfull
+ */
+ virtual bool messagesForFilter(const SearchFilter* filter
+ , QValueList<SearchResult>& resultList, QString& error)
+ {
+ Q_UNUSED(filter);
+ Q_UNUSED(resultList);
+
+ error = i18n("not implemented");
+ return false;
+ }
+
+ /**
+ * @returns true, if the searchresults are given as rich text
+ * the default implementation returns false
+ */
+ virtual bool usesRichTextResults();
+
+ /** @returns true, if the the entries in the database can be edited */
+ virtual bool isEditable();
+
+ /**
+ * @returns a widget which lets the user setup all preferences of this
+ * search engine. The returned widget should not be bigger than
+ * 400x400. If you need more space, you maybe want to use
+ * a tabbed widget.
+ * @param parent the parent of the returned widget
+ */
+ virtual PrefWidget* preferencesWidget(QWidget *parent)=0;
+
+ /** @returns information about this SearchEngine */
+ virtual const KAboutData *about() const= 0;
+
+ /** @returns the i18n name of this search engine */
+ virtual QString name() const= 0;
+
+ /** @returns a untranslated name of this engine */
+ virtual QString id() const= 0;
+
+ /** @returns the last error message */
+ virtual QString lastError() = 0;
+
+
+ /**
+ * sets the engine to always ask the preferences dialog for settings
+ * if is existing before starting the search.
+ */
+ virtual void setAutoUpdateOptions(bool activate);
+
+
+ /**
+ * @returns how good @param text1 matches @param text2
+ * comparing 3-grams .. n-grams, the returned value is
+ * a number between 0 and 100. @param ngram_len should be
+ * a value between 3 and 5.
+ */
+ static uint ngramMatch (const QString& text1, const QString& text2,
+ uint ngram_len=3);
+
+public slots:
+ /**
+ * starts a search for string s in the original text
+ * @returns false, if an error occured. Use @ref lastError
+ * to get the last error message
+ */
+ virtual bool startSearch(const QString& s, uint pluralForm = 0, const SearchFilter* filter = 0) = 0;
+
+ /**
+ * starts a search for string s in the translated text
+ * @returns false, if an error occured. Use @ref lastError
+ * to get the last error message
+ */
+ virtual bool startSearchInTranslation(const QString& s, uint pluralForm = 0, const SearchFilter* filter = 0);
+
+
+ /** stops a search */
+ virtual void stopSearch() = 0;
+
+ /** @return the next search result */
+ virtual SearchResult *nextResult();
+
+ /** @return the previous search result */
+ virtual SearchResult *prevResult();
+
+ /** @return the first search result */
+ virtual SearchResult *firstResult();
+
+ /** @return the last search result */
+ virtual SearchResult *lastResult();
+
+ /** clears the result list */
+ virtual void clearResults();
+
+
+ /**
+ * This method allows a search engine to use different settings depending
+ * on the edited file. The default implementation does nothing.
+ * @param file The edited file with path
+ */
+ virtual void setEditedFile(const QString& file);
+
+ /**
+ * This method allows a search engine to use different settings depending
+ * on the edited package. The default implementation does nothing.
+ * @param package The name of the package, that is currently translated.
+ */
+ virtual void setEditedPackage(const QString& package);
+
+ /**
+ * This method allows a search engine to use different settings depending
+ * on the language code. The default implementation does nothing.
+ * @param lang The current language code (e.g. de).
+ */
+ virtual void setLanguageCode(const QString& lang);
+ virtual void setLanguage(const QString& languageCode, const QString& languageName);
+
+
+
+ /**
+ * This method is called, if something has been changed in the
+ * current file. See @ref setEditedFile if you want to know the file
+ * name
+ * @param orig the original string (list of all plural forms)
+ * @param translation the translated string
+ * @param pluralForm the number of the plural form of the translation
+ * @param description the additional description, e.g., a PO comment
+ */
+ virtual void stringChanged( const QStringList& orig, const QString& translated
+ , const uint translationPluralForm, const QString& description);
+
+ /**
+ * If the database is editable this slot should open an dialog to let
+ * the user edit the contents of the database.
+ */
+ virtual void edit();
+
+ /************ convenience functions for distring normalization, etc.**********/
+
+ /**
+ * @returns the n-th directory name of path. Counting is started at
+ * end of path. Example: directory("/usr/local/src/foobar, 0")
+ * returns "foobar", while n=1 would return "src"
+ * FIXME: isn't it a code duplication?
+ */
+ static QString directory(const QString& path, int n);
+
+ /**
+ * computes a score to assess the match of the two strings:
+ * 0 means exact match, bigger means worse
+ */
+ static uint score(const QString& orig, const QString& found);
+
+signals:
+ /** signals, that a new search started */
+ void started();
+
+ /**
+ * signals progress in searching
+ * @param p should be between 0 and 100
+ * */
+ void progress(int p);
+
+ /**
+ * Use this, if you want to set your own message on the
+ * progressbar or if you do something else then searching,
+ * maybe loading a big file
+ */
+ void progressStarts(const QString&);
+
+ void progressEnds();
+
+ /**
+ * signals, that the number of search results has changed
+ * @param n the new number of results
+ * */
+ void numberOfResultsChanged(int n);
+
+ /**
+ * signals, that the order of the results in the list has changed.
+ * For example because a better matching string has been prepended.
+ */
+ void resultsReordered();
+
+ /**
+ * signals, that a new result was found
+ */
+ void resultFound(const SearchResult*);
+
+ /**
+ * signals, that search has finished
+ */
+ void finished();
+
+ /**
+ * signals, that an error occured, for example, that you wasn't
+ * able to open a database.
+ */
+ void hasError(const QString& error);
+
+protected:
+ QPtrList<SearchResult> results;
+ bool autoUpdate;
+};
+
+
+#endif // SEARCH_ENGINE_H
diff --git a/kbugbuster/AUTHORS b/kbugbuster/AUTHORS
new file mode 100644
index 00000000..08de29fa
--- /dev/null
+++ b/kbugbuster/AUTHORS
@@ -0,0 +1,4 @@
+Martijn Klingens <klingens@kde.org>
+Simon Hausmann <hausmann@kde.org>
+Cornelius Schumacher <schumacher@kde.org>
+David Faure <faure@kde.org>
diff --git a/kbugbuster/COPYING b/kbugbuster/COPYING
new file mode 100644
index 00000000..8832c184
--- /dev/null
+++ b/kbugbuster/COPYING
@@ -0,0 +1,340 @@
+ GNU GENERAL PUBLIC LICENSE
+ Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+ 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users. This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it. (Some other Free Software Foundation software is covered by
+the GNU Library General Public License instead.) You can apply it to
+your programs, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+ To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have. You must make sure that they, too, receive or can get the
+source code. And you must show them these terms so they know their
+rights.
+
+ We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+ Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software. If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+ Finally, any free program is threatened constantly by software
+patents. We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary. To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ GNU GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License. The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language. (Hereinafter, translation is included without limitation in
+the term "modification".) Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+ 1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+ 2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) You must cause the modified files to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ b) You must cause any work that you distribute or publish, that in
+ whole or in part contains or is derived from the Program or any
+ part thereof, to be licensed as a whole at no charge to all third
+ parties under the terms of this License.
+
+ c) If the modified program normally reads commands interactively
+ when run, you must cause it, when started running for such
+ interactive use in the most ordinary way, to print or display an
+ announcement including an appropriate copyright notice and a
+ notice that there is no warranty (or else, saying that you provide
+ a warranty) and that users may redistribute the program under
+ these conditions, and telling the user how to view a copy of this
+ License. (Exception: if the Program itself is interactive but
+ does not normally print such an announcement, your work based on
+ the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+ a) Accompany it with the complete corresponding machine-readable
+ source code, which must be distributed under the terms of Sections
+ 1 and 2 above on a medium customarily used for software interchange; or,
+
+ b) Accompany it with a written offer, valid for at least three
+ years, to give any third party, for a charge no more than your
+ cost of physically performing source distribution, a complete
+ machine-readable copy of the corresponding source code, to be
+ distributed under the terms of Sections 1 and 2 above on a medium
+ customarily used for software interchange; or,
+
+ c) Accompany it with the information you received as to the offer
+ to distribute corresponding source code. (This alternative is
+ allowed only for noncommercial distribution and only if you
+ received the program in object code or executable form with such
+ an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it. For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable. However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License. Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+ 5. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Program or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+ 6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+ 7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all. For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+ 8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded. In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+ 9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time. Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation. If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+ 10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission. For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this. Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+ NO WARRANTY
+
+ 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+ 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+ END OF TERMS AND CONDITIONS
+
+ How to Apply These Terms to Your New Programs
+
+ If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+ To do so, attach the following notices to the program. It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the program's name and a brief idea of what it does.>
+ Copyright (C) 19yy <name of author>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the 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, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+ Gnomovision version 69, Copyright (C) 19yy name of author
+ Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+ This is free software, and you are welcome to redistribute it
+ under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License. Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary. Here is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+ `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+ <signature of Ty Coon>, 1 April 1989
+ Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs. If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library. If this is what you want to do, use the GNU Library General
+Public License instead of this License.
diff --git a/kbugbuster/ChangeLog b/kbugbuster/ChangeLog
new file mode 100644
index 00000000..b17cae8f
--- /dev/null
+++ b/kbugbuster/ChangeLog
@@ -0,0 +1,4 @@
+CHANGELOG FOR KBUGBUSTER
+------------------------
+30 Jul 2001 - Started development
+
diff --git a/kbugbuster/INSTALL b/kbugbuster/INSTALL
new file mode 100644
index 00000000..02a4a074
--- /dev/null
+++ b/kbugbuster/INSTALL
@@ -0,0 +1,167 @@
+Basic Installation
+==================
+
+ These are generic installation instructions.
+
+ The `configure' shell script attempts to guess correct values for
+various system-dependent variables used during compilation. It uses
+those values to create a `Makefile' in each directory of the package.
+It may also create one or more `.h' files containing system-dependent
+definitions. Finally, it creates a shell script `config.status' that
+you can run in the future to recreate the current configuration, a file
+`config.cache' that saves the results of its tests to speed up
+reconfiguring, and a file `config.log' containing compiler output
+(useful mainly for debugging `configure').
+
+ If you need to do unusual things to compile the package, please try
+to figure out how `configure' could check whether to do them, and mail
+diffs or instructions to the address given in the `README' so they can
+be considered for the next release. If at some point `config.cache'
+contains results you don't want to keep, you may remove or edit it.
+
+ The file `configure.in' is used to create `configure' by a program
+called `autoconf'. You only need `configure.in' if you want to change
+it or regenerate `configure' using a newer version of `autoconf'.
+
+The simplest way to compile this package is:
+
+ 1. `cd' to the directory containing the package's source code and type
+ `./configure' to configure the package for your system. If you're
+ using `csh' on an old version of System V, you might need to type
+ `sh ./configure' instead to prevent `csh' from trying to execute
+ `configure' itself.
+
+ Running `configure' takes a while. While running, it prints some
+ messages telling which features it is checking for.
+
+ 2. Type `make' to compile the package.
+
+ 3. Type `make install' to install the programs and any data files and
+ documentation.
+
+ 4. You can remove the program binaries and object files from the
+ source code directory by typing `make clean'.
+
+Compilers and Options
+=====================
+
+ Some systems require unusual options for compilation or linking that
+the `configure' script does not know about. You can give `configure'
+initial values for variables by setting them in the environment. Using
+a Bourne-compatible shell, you can do that on the command line like
+this:
+ CC=c89 CFLAGS=-O2 LIBS=-lposix ./configure
+
+Or on systems that have the `env' program, you can do it like this:
+ env CPPFLAGS=-I/usr/local/include LDFLAGS=-s ./configure
+
+Compiling For Multiple Architectures
+====================================
+
+ You can compile the package for more than one kind of computer at the
+same time, by placing the object files for each architecture in their
+own directory. To do this, you must use a version of `make' that
+supports the `VPATH' variable, such as GNU `make'. `cd' to the
+directory where you want the object files and executables to go and run
+the `configure' script. `configure' automatically checks for the
+source code in the directory that `configure' is in and in `..'.
+
+ If you have to use a `make' that does not supports the `VPATH'
+variable, you have to compile the package for one architecture at a time
+in the source code directory. After you have installed the package for
+one architecture, use `make distclean' before reconfiguring for another
+architecture.
+
+Installation Names
+==================
+
+ By default, `make install' will install the package's files in
+`/usr/local/bin', `/usr/local/man', etc. You can specify an
+installation prefix other than `/usr/local' by giving `configure' the
+option `--prefix=PATH'.
+
+ You can specify separate installation prefixes for
+architecture-specific files and architecture-independent files. If you
+give `configure' the option `--exec-prefix=PATH', the package will use
+PATH as the prefix for installing programs and libraries.
+Documentation and other data files will still use the regular prefix.
+
+ If the package supports it, you can cause programs to be installed
+with an extra prefix or suffix on their names by giving `configure' the
+option `--program-prefix=PREFIX' or `--program-suffix=SUFFIX'.
+
+Optional Features
+=================
+
+ Some packages pay attention to `--enable-FEATURE' options to
+`configure', where FEATURE indicates an optional part of the package.
+They may also pay attention to `--with-PACKAGE' options, where PACKAGE
+is something like `gnu-as' or `x' (for the X Window System). The
+`README' should mention any `--enable-' and `--with-' options that the
+package recognizes.
+
+ For packages that use the X Window System, `configure' can usually
+find the X include and library files automatically, but if it doesn't,
+you can use the `configure' options `--x-includes=DIR' and
+`--x-libraries=DIR' to specify their locations.
+
+Specifying the System Type
+==========================
+
+ There may be some features `configure' can not figure out
+automatically, but needs to determine by the type of host the package
+will run on. Usually `configure' can figure that out, but if it prints
+a message saying it can not guess the host type, give it the
+`--host=TYPE' option. TYPE can either be a short name for the system
+type, such as `sun4', or a canonical name with three fields:
+ CPU-COMPANY-SYSTEM
+
+See the file `config.sub' for the possible values of each field. If
+`config.sub' isn't included in this package, then this package doesn't
+need to know the host type.
+
+ If you are building compiler tools for cross-compiling, you can also
+use the `--target=TYPE' option to select the type of system they will
+produce code for and the `--build=TYPE' option to select the type of
+system on which you are compiling the package.
+
+Sharing Defaults
+================
+
+ If you want to set default values for `configure' scripts to share,
+you can create a site shell script called `config.site' that gives
+default values for variables like `CC', `cache_file', and `prefix'.
+`configure' looks for `PREFIX/share/config.site' if it exists, then
+`PREFIX/etc/config.site' if it exists. Or, you can set the
+`CONFIG_SITE' environment variable to the location of the site script.
+A warning: not all `configure' scripts look for a site script.
+
+Operation Controls
+==================
+
+ `configure' recognizes the following options to control how it
+operates.
+
+`--cache-file=FILE'
+ Use and save the results of the tests in FILE instead of
+ `./config.cache'. Set FILE to `/dev/null' to disable caching, for
+ debugging `configure'.
+
+`--help'
+ Print a summary of the options to `configure', and exit.
+
+`--quiet'
+`--silent'
+`-q'
+ Do not print messages saying which checks are being made.
+
+`--srcdir=DIR'
+ Look for the package's source code in directory DIR. Usually
+ `configure' can determine that directory automatically.
+
+`--version'
+ Print the version of Autoconf used to generate the `configure'
+ script, and exit.
+
+`configure' also accepts some other, not widely useful, options.
+
diff --git a/kbugbuster/Makefile.am b/kbugbuster/Makefile.am
new file mode 100644
index 00000000..44b31733
--- /dev/null
+++ b/kbugbuster/Makefile.am
@@ -0,0 +1,28 @@
+INCLUDES= -I$(top_srcdir)/kbugbuster/backend $(all_includes)
+
+if include_kcalresource
+KRESOURCES_SUBDIR = kresources
+endif
+
+SUBDIRS = backend gui pics $(KRESOURCES_SUBDIR)
+
+bin_PROGRAMS = kbugbuster
+
+kbugbuster_SOURCES = main.cpp
+kbugbuster_LDADD = -lkutils gui/libkbbmainwindow.la \
+ backend/libkbbbackend.la $(LIB_KHTML) $(LIB_KIO)
+kbugbuster_LDFLAGS = $(all_libraries) $(KDE_RPATH)
+
+xdg_apps_DATA = kbugbuster.desktop
+
+KDE_ICON = kbugbuster
+
+METASOURCES = AUTO
+
+EXTRA_DIST = AUTHORS COPYING ChangeLog INSTALL README TODO kbugbuster.lsm
+
+messages: rc.cpp
+ $(EXTRACTRC) */*.kcfg >> rc.cpp
+ $(EXTRACTRC) gui/*.rc >> rc.cpp
+ $(EXTRACTRC) gui/*.ui >> rc.cpp
+ $(XGETTEXT) *.cpp */*.h */*.cpp -o $(podir)/kbugbuster.pot
diff --git a/kbugbuster/README b/kbugbuster/README
new file mode 100644
index 00000000..aee7659d
--- /dev/null
+++ b/kbugbuster/README
@@ -0,0 +1,2 @@
+This is still heavily under development, use at your own risk ;-)
+
diff --git a/kbugbuster/TODO b/kbugbuster/TODO
new file mode 100644
index 00000000..e4b4622b
--- /dev/null
+++ b/kbugbuster/TODO
@@ -0,0 +1,4 @@
+TODO
+----
+
+- Consistently use KBB namespace (at least in backend)
diff --git a/kbugbuster/backend/Makefile.am b/kbugbuster/backend/Makefile.am
new file mode 100644
index 00000000..e1bfd266
--- /dev/null
+++ b/kbugbuster/backend/Makefile.am
@@ -0,0 +1,16 @@
+INCLUDES= -I$(srcdir)/.. $(all_includes)
+
+noinst_LTLIBRARIES = libkbbbackend.la
+
+libkbbbackend_la_SOURCES = packagelistjob.cpp bugjob.cpp \
+ package.cpp bugsystem.cpp bug.cpp bugdetails.cpp \
+ bugcommand.cpp buglistjob.cpp bugmybugsjob.cpp \
+ mailsender.cpp bugcache.cpp bugdetailsjob.cpp \
+ person.cpp smtp.cpp bugserver.cpp \
+ bugserverconfig.cpp \
+ processor.cpp \
+ domprocessor.cpp rdfprocessor.cpp htmlparser.cpp \
+ kbbprefs.cpp
+
+METASOURCES = AUTO
+
diff --git a/kbugbuster/backend/bug.cpp b/kbugbuster/backend/bug.cpp
new file mode 100644
index 00000000..4523652e
--- /dev/null
+++ b/kbugbuster/backend/bug.cpp
@@ -0,0 +1,240 @@
+
+#include "bug.h"
+
+#include "bugimpl.h"
+
+#include <assert.h>
+#include <kdebug.h>
+
+Bug::Bug()
+: m_impl( NULL )
+{
+}
+
+Bug::Bug( BugImpl *impl )
+: m_impl( impl )
+{
+}
+
+Bug::Bug( const Bug &other )
+{
+ (*this) = other;
+}
+
+Bug Bug::fromNumber( const QString &bugNumber )
+{
+ return new BugImpl( QString::null, Person(), bugNumber, 0xFFFFFFFF, Normal, Person(),
+ Unconfirmed, Bug::BugMergeList() );
+}
+
+Bug &Bug::operator=( const Bug &rhs )
+{
+ m_impl = rhs.m_impl;
+ return *this;
+}
+
+Bug::~Bug()
+{
+}
+
+QString Bug::severityLabel( Bug::Severity s )
+{
+ switch ( s )
+ {
+ case Critical: return i18n("Critical");
+ case Grave: return i18n("Grave");
+ case Major: return i18n("Major");
+ case Crash: return i18n("Crash");
+ case Normal: return i18n("Normal");
+ case Minor: return i18n("Minor");
+ case Wishlist: return i18n("Wishlist");
+ default:
+ case SeverityUndefined: return i18n("Undefined");
+ }
+}
+
+QString Bug::severityToString( Bug::Severity s )
+{
+ switch ( s ) {
+ case Critical: return QString::fromLatin1( "critical" );
+ case Grave: return QString::fromLatin1( "grave" );
+ case Major: return QString::fromLatin1( "major" );
+ case Crash: return QString::fromLatin1( "crash" );
+ case Normal: return QString::fromLatin1( "normal" );
+ case Minor: return QString::fromLatin1( "minor" );
+ case Wishlist: return QString::fromLatin1( "wishlist" );
+ default:
+ kdWarning() << "Bug::severityToString invalid severity " << s << endl;
+ return QString::fromLatin1( "<invalid>" );
+ }
+}
+
+Bug::Severity Bug::stringToSeverity( const QString &s, bool *ok )
+{
+ if ( ok )
+ *ok = true;
+
+ if ( s == "critical" ) return Critical;
+ else if ( s == "grave" ) return Grave;
+ else if ( s == "major" ) return Major;
+ else if ( s == "crash" || s == "drkonqi" ) return Crash;
+ else if ( s == "normal" ) return Normal;
+ else if ( s == "minor" ) return Minor;
+ else if ( s == "wishlist" ) return Wishlist;
+
+ kdWarning() << "Bug::stringToSeverity: invalid severity: " << s << endl;
+ if ( ok )
+ *ok = false;
+ return SeverityUndefined;
+}
+
+QValueList<Bug::Severity> Bug::severities()
+{
+ QValueList<Severity> s;
+ s << Critical << Grave << Major << Crash << Normal << Minor << Wishlist;
+ return s;
+}
+
+QString Bug::statusLabel( Bug::Status s )
+{
+ switch ( s )
+ {
+ case Unconfirmed: return i18n("Unconfirmed");
+ case New: return i18n("New");
+ case Assigned: return i18n("Assigned");
+ case Reopened: return i18n("Reopened");
+ case Closed: return i18n("Closed");
+ default:
+ case StatusUndefined: return i18n("Undefined");
+ }
+}
+
+QString Bug::statusToString( Bug::Status s )
+{
+ switch ( s ) {
+ case Unconfirmed: return QString::fromLatin1( "unconfirmed" );
+ case New: return QString::fromLatin1( "new" );
+ case Assigned: return QString::fromLatin1( "assigned" );
+ case Reopened: return QString::fromLatin1( "reopened" );
+ case Closed: return QString::fromLatin1( "closed" );
+ default:
+ kdWarning() << "Bug::statusToString invalid status " << s << endl;
+ return QString::fromLatin1( "<invalid>" );
+ }
+}
+
+Bug::Status Bug::stringToStatus( const QString &s, bool *ok )
+{
+ if ( ok )
+ *ok = true;
+
+ if ( s == "unconfirmed" ) return Unconfirmed;
+ else if ( s == "new" ) return New;
+ else if ( s == "assigned" ) return Assigned;
+ else if ( s == "reopened" ) return Reopened;
+ else if ( s == "closed" ) return Closed;
+
+ kdWarning() << "Bug::stringToStatus: invalid status: " << s << endl;
+ if ( ok )
+ *ok = false;
+ return StatusUndefined;
+}
+
+QString Bug::title() const
+{
+ if ( !m_impl )
+ return QString::null;
+
+ return m_impl->title;
+}
+
+void Bug::setTitle( QString title)
+{
+ if ( m_impl )
+ m_impl->title = title;
+}
+
+uint Bug::age() const
+{
+ if ( !m_impl )
+ return 0;
+
+ return m_impl->age;
+}
+
+void Bug::setAge( uint age )
+{
+ if ( m_impl )
+ m_impl->age = age;
+}
+
+struct Person Bug::submitter() const
+{
+ if ( !m_impl )
+ return Person( QString::null, QString::null );
+
+ return m_impl->submitter;
+}
+
+QString Bug::number() const
+{
+ if ( !m_impl )
+ return QString::null;
+
+ return m_impl->number;
+}
+
+Bug::Severity Bug::severity() const
+{
+ if ( !m_impl )
+ return Normal;
+
+ return m_impl->severity;
+}
+
+void Bug::setSeverity( Bug::Severity severity )
+{
+ if ( m_impl )
+ m_impl->severity = severity;
+}
+
+Bug::BugMergeList Bug::mergedWith() const
+{
+ if ( !m_impl )
+ return Bug::BugMergeList();
+
+ return m_impl->mergedWith;
+}
+
+
+Bug::Status Bug::status() const
+{
+ if ( !m_impl )
+ return StatusUndefined;
+
+ return m_impl->status;
+}
+
+QString Bug::severityAsString() const
+{
+ return severityToString( severity() );
+}
+
+Person Bug::developerTODO() const
+{
+ return (m_impl == NULL) ? Person( QString::null, QString::null ) :
+ m_impl->developerTODO;
+}
+
+bool Bug::operator==( const Bug &rhs )
+{
+ return m_impl == rhs.m_impl;
+}
+
+bool Bug::operator<( const Bug &rhs ) const
+{
+ return m_impl < rhs.m_impl;
+}
+
+/* vim: set ts=4 sw=4 et softtabstop=4: */
+
diff --git a/kbugbuster/backend/bug.h b/kbugbuster/backend/bug.h
new file mode 100644
index 00000000..9a5ae8b6
--- /dev/null
+++ b/kbugbuster/backend/bug.h
@@ -0,0 +1,92 @@
+#ifndef __bug_h__
+#define __bug_h__
+
+#include "person.h"
+
+#include <qvaluelist.h>
+
+#include <ksharedptr.h>
+
+class BugImpl;
+
+class Bug
+{
+public:
+ typedef QValueList<Bug> List;
+ typedef QValueList<int> BugMergeList;
+
+ enum Severity { SeverityUndefined, Critical, Grave, Major, Crash, Normal,
+ Minor, Wishlist };
+ enum Status { StatusUndefined, Unconfirmed, New, Assigned, Reopened,
+ Closed };
+
+ Bug();
+ Bug( BugImpl *impl );
+ Bug( const Bug &other );
+ Bug &operator=( const Bug &rhs );
+ ~Bug();
+
+ static QString severityLabel( Severity s );
+ /**
+ Return string representation of severity. This function is symmetric to
+ stringToSeverity().
+ */
+ static QString severityToString( Severity s );
+ /**
+ Return severity code of string representation. This function is symmetric
+ to severityToString().
+ */
+ static Severity stringToSeverity( const QString &, bool *ok = 0 );
+
+ static QValueList<Severity> severities();
+
+ uint age() const;
+ void setAge( uint days );
+
+ QString title() const;
+ void setTitle( QString title );
+ Person submitter() const;
+ QString number() const;
+ Severity severity() const;
+ void setSeverity( Severity severity );
+ QString severityAsString() const;
+ Person developerTODO() const;
+
+ BugMergeList mergedWith() const;
+
+ /**
+ * Status of a bug. Currently open or closed.
+ * TODO: Should we add a status 'deleted' here ?
+ */
+ Status status() const;
+ void setStatus( Status newStatus );
+
+ static QString statusLabel( Status s );
+ /**
+ Return string representation of status. This function is symmetric to
+ stringToStatus().
+ */
+ static QString statusToString( Status s );
+ /**
+ Return status code of string representation. This function is symmetric
+ to statusToString().
+ */
+ static Status stringToStatus( const QString &, bool *ok = 0 );
+
+ bool operator==( const Bug &rhs );
+ bool operator<( const Bug &rhs ) const;
+
+ bool isNull() const { return m_impl == 0; }
+
+ static Bug fromNumber( const QString &bugNumber );
+
+private:
+ BugImpl *impl() const { return m_impl; }
+
+ KSharedPtr<BugImpl> m_impl;
+};
+
+#endif
+
+/* vim: set sw=4 ts=4 et softtabstop=4: */
+
diff --git a/kbugbuster/backend/bugcache.cpp b/kbugbuster/backend/bugcache.cpp
new file mode 100644
index 00000000..0eb44c8c
--- /dev/null
+++ b/kbugbuster/backend/bugcache.cpp
@@ -0,0 +1,289 @@
+// (C) 2001, Cornelius Schumacher
+
+#include <qstringlist.h>
+#include <qfile.h>
+
+#include <ksimpleconfig.h>
+#include <kstandarddirs.h>
+#include <kurl.h>
+#include <kdebug.h>
+
+#include "packageimpl.h"
+#include "bugimpl.h"
+#include "bugdetailsimpl.h"
+
+#include "bugcache.h"
+
+BugCache::BugCache( const QString &id )
+{
+ mId = id;
+
+ init();
+}
+
+BugCache::~BugCache()
+{
+ m_cachePackages->sync();
+ m_cacheBugs->sync();
+
+ delete m_cachePackages;
+ delete m_cacheBugs;
+}
+
+void BugCache::init()
+{
+ mCachePackagesFileName = locateLocal( "appdata", mId + "-packages.cache" );
+ mCacheBugsFileName = locateLocal( "appdata", mId + "-bugs.cache" );
+
+ m_cachePackages = new KSimpleConfig( mCachePackagesFileName );
+ m_cacheBugs = new KSimpleConfig( mCacheBugsFileName );
+}
+
+void BugCache::savePackageList( const Package::List &pkgs )
+{
+ Package::List::ConstIterator it;
+ for (it = pkgs.begin(); it != pkgs.end(); ++it) {
+ m_cachePackages->setGroup((*it).name());
+ m_cachePackages->writeEntry("description",(*it).description());
+ m_cachePackages->writeEntry("numberOfBugs",(*it).numberOfBugs());
+ m_cachePackages->writeEntry("components",(*it).components());
+ writePerson(m_cachePackages,"Maintainer",(*it).maintainer());
+ }
+}
+
+Package::List BugCache::loadPackageList()
+{
+ Package::List pkgs;
+
+ QStringList packages = m_cachePackages->groupList();
+ QStringList::ConstIterator it;
+ for( it = packages.begin(); it != packages.end(); ++it ) {
+ if ((*it) == "<default>") continue;
+ if ((*it).contains("/")) continue;
+
+ m_cachePackages->setGroup(*it);
+
+ QString description = m_cachePackages->readEntry("description");
+ int numberOfBugs = m_cachePackages->readNumEntry("numberOfBugs");
+ Person maintainer = readPerson( m_cachePackages, "Maintainer");
+ QStringList components = m_cachePackages->readListEntry("components");
+
+ pkgs.append( Package( new PackageImpl( (*it), description, numberOfBugs,
+ maintainer, components ) ) );
+ }
+
+ return pkgs;
+}
+
+void BugCache::invalidatePackageList()
+{
+ // Completely wipe out packages.cache
+ QStringList packages = m_cachePackages->groupList();
+ QStringList::ConstIterator it;
+ for( it = packages.begin(); it != packages.end(); ++it ) {
+ if ((*it) == "<default>") continue;
+ m_cachePackages->deleteGroup(*it, true);
+ }
+}
+
+void BugCache::saveBugList( const Package &pkg, const QString &component, const Bug::List &bugs )
+{
+ QStringList bugList;
+
+ Bug::List::ConstIterator it;
+ for( it = bugs.begin(); it != bugs.end(); ++it ) {
+ QString number = (*it).number();
+ bugList.append( number );
+ m_cacheBugs->setGroup( number );
+ m_cacheBugs->writeEntry( "Title", (*it).title() );
+ m_cacheBugs->writeEntry( "Severity", Bug::severityToString((*it).severity()) );
+ m_cacheBugs->writeEntry( "Status", Bug::statusToString((*it).status()) );
+ m_cacheBugs->writeEntry( "MergedWith" , (*it).mergedWith() );
+ m_cacheBugs->writeEntry( "Age", ( *it ).age() );
+ writePerson( m_cacheBugs, "Submitter", (*it).submitter() );
+ writePerson( m_cacheBugs, "TODO", (*it).developerTODO() );
+ }
+
+ if ( component.isEmpty() )
+ m_cachePackages->setGroup( pkg.name() );
+ else {
+ m_cachePackages->setGroup( pkg.name() + "/" + component );
+ }
+
+ m_cachePackages->writeEntry( "bugList", bugList );
+}
+
+Bug::List BugCache::loadBugList( const Package &pkg, const QString &component, bool disconnected )
+{
+// kdDebug() << "Loading bug list for " << pkg.name() << endl;
+
+ Bug::List bugList;
+
+ if ( component.isEmpty() )
+ m_cachePackages->setGroup( pkg.name() );
+ else
+ m_cachePackages->setGroup( pkg.name() + "/" + component );
+
+ QStringList bugs = m_cachePackages->readListEntry( "bugList" );
+
+// kdDebug() << " Bugs: " << (bugs.join(",")) << endl;
+
+ QStringList::ConstIterator it;
+ for( it = bugs.begin(); it != bugs.end(); ++it ) {
+ if ( m_cacheBugs->hasGroup(*it) )
+ {
+ m_cacheBugs->setGroup(*it);
+ QString title = m_cacheBugs->readEntry("Title");
+ if ( !title.isEmpty() ) // dunno how I ended up with an all empty bug in the cache
+ {
+ Person submitter = readPerson( m_cacheBugs, "Submitter" );
+ Bug::Status status = Bug::stringToStatus( m_cacheBugs->readEntry("Status") );
+ Bug::Severity severity = Bug::stringToSeverity( m_cacheBugs->readEntry("Severity") );
+ Person developerTODO = readPerson( m_cacheBugs, "TODO" );
+ Bug::BugMergeList mergedWith = m_cacheBugs->readIntListEntry( "MergedWith" );
+ uint age = m_cacheBugs->readUnsignedNumEntry( "Age", 0xFFFFFFFF );
+ bugList.append( Bug( new BugImpl( title, submitter, ( *it ), age,
+ severity, developerTODO,
+ status, mergedWith ) ) );
+ }
+ } else {
+ // This bug is in the package cache's buglist but not in the bugs cache
+ // Probably a new bug, we need to fetch it - if we're not in disconnected mode
+ kdWarning() << "Bug " << *it << " not in bug cache" << endl;
+ if ( !disconnected )
+ return Bug::List(); // returning an empty list will trigger a reload of the buglist
+ }
+ }
+
+ return bugList;
+}
+
+void BugCache::invalidateBugList( const Package& pkg, const QString &component )
+{
+ kdDebug() << "BugCache::invalidateBugList " << pkg.name()
+ << " (" << component << ")" << endl;
+
+ // Erase bug list for this package
+ if ( component.isEmpty() ) {
+ m_cachePackages->setGroup( pkg.name() );
+ } else {
+ QString key = pkg.name() + "/" + component;
+ m_cachePackages->setGroup( key );
+ m_cachePackages->setGroup( pkg.name() + "/" + component );
+ }
+
+ m_cachePackages->writeEntry("bugList",QString::null);
+}
+
+void BugCache::saveBugDetails( const Bug &bug, const BugDetails &details )
+{
+ m_cacheBugs->setGroup( bug.number() );
+
+ m_cacheBugs->writeEntry( "Version", details.version() );
+ m_cacheBugs->writeEntry( "Source", details.source() );
+ m_cacheBugs->writeEntry( "Compiler", details.compiler() );
+ m_cacheBugs->writeEntry( "OS", details.os() );
+
+ QStringList senders;
+ QStringList texts;
+ QStringList dates;
+
+ BugDetailsPart::List parts = details.parts();
+ BugDetailsPart::List::ConstIterator it;
+ for ( it = parts.begin(); it != parts.end(); ++it ) {
+ senders.append( (*it).sender.fullName() );
+ texts.append( (*it).text );
+ dates.append( (*it).date.toString( Qt::ISODate ) );
+ }
+
+ m_cacheBugs->writeEntry( "Details", texts );
+ m_cacheBugs->writeEntry( "Senders", senders );
+ m_cacheBugs->writeEntry( "Dates", dates );
+}
+
+bool BugCache::hasBugDetails( const Bug& bug ) const
+{
+ if ( !m_cacheBugs->hasGroup( bug.number() ) )
+ return false;
+
+ m_cacheBugs->setGroup( bug.number() );
+ return m_cacheBugs->hasKey( "Details" );
+}
+
+BugDetails BugCache::loadBugDetails( const Bug &bug )
+{
+ if ( !m_cacheBugs->hasGroup( bug.number() ) ) {
+ return BugDetails();
+ }
+
+ m_cacheBugs->setGroup( bug.number() );
+
+ BugDetailsPart::List parts;
+
+ QStringList texts = m_cacheBugs->readListEntry( "Details" );
+ QStringList senders = m_cacheBugs->readListEntry( "Senders" );
+ QStringList dates = m_cacheBugs->readListEntry( "Dates" );
+
+ QStringList::ConstIterator itTexts = texts.begin();
+ QStringList::ConstIterator itSenders = senders.begin();
+ QStringList::ConstIterator itDates = dates.begin();
+ while( itTexts != texts.end() ) {
+ QDateTime date = QDateTime::fromString( *itDates, Qt::ISODate );
+ parts.append( BugDetailsPart( Person(*itSenders), date, *itTexts ) );
+
+ ++itTexts;
+ ++itSenders;
+ ++itDates;
+ }
+
+ if ( parts.count() == 0 ) {
+ return BugDetails();
+ }
+
+ QString version = m_cacheBugs->readEntry( "Version" );
+ QString source = m_cacheBugs->readEntry( "Source" );
+ QString compiler = m_cacheBugs->readEntry( "Compiler" );
+ QString os = m_cacheBugs->readEntry( "OS" );
+
+ return BugDetails( new BugDetailsImpl( version, source, compiler, os,
+ parts ) );
+}
+
+void BugCache::invalidateBugDetails( const Bug& bug )
+{
+ m_cacheBugs->deleteGroup( bug.number(), true );
+}
+
+void BugCache::clear()
+{
+ delete m_cachePackages;
+ delete m_cacheBugs;
+
+ QFile f1( mCachePackagesFileName );
+ f1.remove();
+
+ QFile f2( mCacheBugsFileName );
+ f2.remove();
+
+ init();
+}
+
+void BugCache::writePerson( KSimpleConfig *file, const QString &key,
+ const Person &p )
+{
+ QStringList values;
+ values.append(p.name);
+ values.append(p.email);
+ file->writeEntry( key, values );
+}
+
+struct Person BugCache::readPerson( KSimpleConfig *file, const QString &key )
+{
+ struct Person p;
+ QStringList values = file->readListEntry(key);
+ if ( values.count() > 0 )
+ p.name = values[0];
+ if ( values.count() > 1 )
+ p.email = values[1];
+ return p;
+}
diff --git a/kbugbuster/backend/bugcache.h b/kbugbuster/backend/bugcache.h
new file mode 100644
index 00000000..af1aed11
--- /dev/null
+++ b/kbugbuster/backend/bugcache.h
@@ -0,0 +1,47 @@
+#ifndef BUGCACHE_H
+#define BUGCACHE_H
+
+class KSimpleConfig;
+
+#include "package.h"
+#include "bug.h"
+#include "bugdetails.h"
+
+class BugCache
+{
+ public:
+ BugCache( const QString &id );
+ ~BugCache();
+
+ void savePackageList( const Package::List &pkgs );
+ Package::List loadPackageList();
+ void invalidatePackageList();
+
+ void saveBugList( const Package &pkg, const QString &component, const Bug::List & );
+ Bug::List loadBugList( const Package &pkg, const QString &component, bool disconnected );
+ void invalidateBugList( const Package &pkg, const QString &component );
+
+ void saveBugDetails( const Bug &bug, const BugDetails & );
+ BugDetails loadBugDetails( const Bug &bug );
+ void invalidateBugDetails( const Bug &bug );
+ bool hasBugDetails( const Bug& bug ) const;
+
+ void clear();
+
+ private:
+ void init();
+
+ void writePerson( KSimpleConfig *file, const QString &key,
+ const Person &p );
+ struct Person readPerson (KSimpleConfig *file, const QString &key );
+
+ QString mId;
+
+ KSimpleConfig *m_cachePackages;
+ KSimpleConfig *m_cacheBugs;
+
+ QString mCachePackagesFileName;
+ QString mCacheBugsFileName;
+};
+
+#endif
diff --git a/kbugbuster/backend/bugcommand.cpp b/kbugbuster/backend/bugcommand.cpp
new file mode 100644
index 00000000..332c937d
--- /dev/null
+++ b/kbugbuster/backend/bugcommand.cpp
@@ -0,0 +1,317 @@
+#include <kdebug.h>
+#include <kconfig.h>
+#include <klocale.h>
+
+#include "bugcommand.h"
+
+QString BugCommand::name()
+{
+ return i18n("Unknown");
+}
+
+QString BugCommand::details()
+{
+ return QString::null;
+}
+
+BugCommand *BugCommand::load( KConfig *config, const QString &type )
+{
+ QString bugNumber = config->group();
+ // ### this sucks. we better let Bug implement proper persistance,
+ // because this way of instantiating a bug object doesn't bring back
+ // properties like title, package, etc. (Simon)
+ Bug bug = Bug::fromNumber( bugNumber );
+ Package pkg = Package(); // hack
+
+ if ( type == "Close" ) {
+ return new BugCommandClose( bug, config->readEntry( type ), pkg );
+ } else if ( type == "Reopen" ) {
+ return new BugCommandReopen( bug, pkg );
+ } else if ( type == "Merge" ) {
+ return new BugCommandMerge( config->readListEntry( type ), pkg );
+ } else if ( type == "Unmerge" ) {
+ return new BugCommandUnmerge( bug, pkg );
+ } else if ( type == "Reassign" ) {
+ return new BugCommandReassign( bug, config->readEntry( type ), pkg );
+ } else if ( type == "Retitle" ) {
+ return new BugCommandRetitle( bug, config->readEntry( type ), pkg );
+ } else if ( type == "Severity" ) {
+ return new BugCommandSeverity( bug, config->readEntry( type ), pkg );
+ } else if ( type == "Reply" ) {
+ return new BugCommandReply( bug, config->readEntry( type ), config->readNumEntry("Recipient",Normal) );
+ } else if ( type == "ReplyPrivate" ) {
+ QStringList args = config->readListEntry( type );
+ if ( args.count() != 2 ) return 0;
+ return new BugCommandReplyPrivate( bug, *(args.at(0)), *(args.at(1)) );
+ } else {
+ kdDebug() << "Warning! Unknown bug command '" << type << "'" << endl;
+ return 0;
+ }
+}
+
+///////////////////// Close /////////////////////
+
+QString BugCommandClose::controlString() const
+{
+ if (m_message.isEmpty()) {
+ return "close " + m_bug.number();
+ } else {
+ return QString::null;
+ }
+}
+
+QString BugCommandClose::mailAddress() const
+{
+ kdDebug() << "BugCommandClose::mailAddress(): number: " << m_bug.number() << endl;
+
+ if (m_message.isEmpty()) {
+ return QString::null;
+ } else {
+ return m_bug.number() + "-done@bugs.kde.org";
+ }
+}
+
+QString BugCommandClose::mailText() const
+{
+ if (m_message.isEmpty()) {
+ return QString::null;
+ } else {
+ return m_message;
+ }
+}
+
+QString BugCommandClose::name()
+{
+ return i18n("Close");
+}
+
+QString BugCommandClose::details() const
+{
+ return m_message;
+}
+
+void BugCommandClose::save( KConfig *config )
+{
+ config->writeEntry( "Close",m_message );
+}
+
+///////////////////// Close Silently /////////////////////
+
+QString BugCommandCloseSilently::controlString() const
+{
+ return "done " + m_bug.number();
+}
+
+QString BugCommandCloseSilently::name()
+{
+ return i18n("Close Silently");
+}
+
+void BugCommandCloseSilently::save( KConfig *config )
+{
+ config->writeEntry( "CloseSilently", true );
+}
+
+///////////////////// Reopen /////////////////////
+
+QString BugCommandReopen::controlString() const
+{
+ return "reopen " + m_bug.number();
+}
+
+QString BugCommandReopen::name()
+{
+ return i18n("Reopen");
+}
+
+void BugCommandReopen::save( KConfig *config )
+{
+ config->writeEntry( "Reopen", true );
+}
+
+///////////////////// Retitle /////////////////////
+
+QString BugCommandRetitle::controlString() const
+{
+ return "retitle " + m_bug.number() + " " + m_title;
+}
+
+QString BugCommandRetitle::name()
+{
+ return i18n("Retitle");
+}
+
+QString BugCommandRetitle::details() const
+{
+ return m_title;
+}
+
+void BugCommandRetitle::save( KConfig *config )
+{
+ config->writeEntry( "Retitle", m_title );
+}
+
+///////////////////// Merge /////////////////////
+
+QString BugCommandMerge::controlString() const
+{
+ return "merge " + m_bugNumbers.join(" ");
+}
+
+QString BugCommandMerge::name()
+{
+ return i18n("Merge");
+}
+
+QString BugCommandMerge::details() const
+{
+ return m_bugNumbers.join(", ");
+}
+
+void BugCommandMerge::save( KConfig *config )
+{
+ config->writeEntry( "Merge", m_bugNumbers );
+}
+
+///////////////////// Unmerge /////////////////////
+
+QString BugCommandUnmerge::controlString() const
+{
+ return "unmerge " + m_bug.number();
+}
+
+QString BugCommandUnmerge::name()
+{
+ return i18n("Unmerge");
+}
+
+void BugCommandUnmerge::save( KConfig *config )
+{
+ config->writeEntry( "Unmerge", true );
+}
+
+///////////////////// Reply /////////////////////
+
+QString BugCommandReply::mailAddress() const
+{
+ return m_bug.number() + "@bugs.kde.org";
+#if 0
+ switch ( m_recipient ) {
+ case Normal:
+ return m_bug.number() + "@bugs.kde.org";
+ case Maintonly:
+ return m_bug.number() + "-maintonly@bugs.kde.org";
+ case Quiet:
+ return m_bug.number() + "-quiet@bugs.kde.org";
+ }
+ return QString::null;
+#endif
+}
+
+QString BugCommandReply::mailText() const
+{
+ return m_message;
+}
+
+QString BugCommandReply::name()
+{
+ return i18n("Reply");
+#if 0
+ switch ( m_recipient ) {
+ case Normal:
+ return i18n("Reply");
+ case Maintonly:
+ return i18n("Reply (Maintonly)");
+ case Quiet:
+ return i18n("Reply (Quiet)");
+ }
+ return QString::null;
+#endif
+}
+
+QString BugCommandReply::details() const
+{
+ return m_message;
+}
+
+void BugCommandReply::save( KConfig *config )
+{
+ config->writeEntry( "Reply", m_message );
+#if 0
+ config->writeEntry( "Recipient", m_recipient );
+#endif
+}
+
+///////////////////// Reply Private /////////////////////
+
+QString BugCommandReplyPrivate::mailAddress() const
+{
+ return m_address;
+}
+
+QString BugCommandReplyPrivate::mailText() const
+{
+ return m_message;
+}
+
+QString BugCommandReplyPrivate::name()
+{
+ return i18n("Private Reply");
+}
+
+QString BugCommandReplyPrivate::details() const
+{
+ return m_message;
+}
+
+void BugCommandReplyPrivate::save( KConfig *config )
+{
+ QStringList args;
+ args << m_address;
+ args << m_message;
+ config->writeEntry( "ReplyPrivate", args );
+}
+
+///////////////////// Severity /////////////////////
+
+QString BugCommandSeverity::controlString() const
+{
+ return "severity " + m_bug.number() + " " + m_severity.lower();
+}
+
+QString BugCommandSeverity::name()
+{
+ return i18n("Severity");
+}
+
+QString BugCommandSeverity::details() const
+{
+ return m_severity;
+}
+
+void BugCommandSeverity::save( KConfig *config )
+{
+ config->writeEntry( "Severity", m_severity );
+}
+
+///////////////////// Reassign /////////////////////
+
+QString BugCommandReassign::controlString() const
+{
+ return "reassign " + m_bug.number() + " " + m_package;
+}
+
+QString BugCommandReassign::name()
+{
+ return i18n("Reassign");
+}
+
+QString BugCommandReassign::details() const
+{
+ return m_package;
+}
+
+void BugCommandReassign::save( KConfig *config )
+{
+ config->writeEntry( "Reassign", m_package );
+}
diff --git a/kbugbuster/backend/bugcommand.h b/kbugbuster/backend/bugcommand.h
new file mode 100644
index 00000000..96b9c85c
--- /dev/null
+++ b/kbugbuster/backend/bugcommand.h
@@ -0,0 +1,217 @@
+#ifndef BUGCOMMAND_H
+#define BUGCOMMAND_H
+
+#include <qstring.h>
+#include <qstringlist.h>
+
+#include "bug.h"
+#include "package.h"
+
+class KConfig;
+
+class BugCommand {
+ public:
+ enum Mode { Normal, Maintonly, Quiet };
+ enum State { None, Queued, Sent };
+
+ BugCommand( const Bug &bug ) : m_bug( bug ) {}
+ BugCommand( const Bug &bug, const Package &pkg ) : m_bug( bug ), m_package( pkg ) {}
+ virtual ~BugCommand() {}
+
+ virtual QString controlString() const { return QString::null; }
+
+ virtual QString mailAddress() const { return QString::null; }
+ virtual QString mailText() const { return QString::null; }
+
+ Bug bug() const { return m_bug; }
+ Package package() const { return m_package; }
+
+ virtual QString name();
+ virtual QString details();
+
+ virtual QString type() const { return QString::null; }
+
+ virtual void save( KConfig * ) = 0;
+ static BugCommand *load( KConfig *, const QString &type );
+
+ protected:
+ Bug m_bug;
+ Package m_package;
+};
+
+class BugCommandClose : public BugCommand {
+ public:
+ BugCommandClose( const Bug &bug, const QString &message, const Package &pkg ) :
+ BugCommand( bug, pkg ), m_message( message ) {}
+
+ QString controlString() const;
+ QString mailAddress() const;
+ QString mailText() const;
+
+ QString name();
+ QString details() const;
+
+ QString type() const { return QString::fromLatin1("Close"); }
+
+ void save( KConfig * );
+
+ private:
+ QString m_message;
+};
+
+class BugCommandCloseSilently : public BugCommand {
+ public:
+ BugCommandCloseSilently( const Bug &bug, const Package &pkg ) :
+ BugCommand( bug, pkg ) {}
+
+ QString controlString() const;
+
+ QString name();
+
+ QString type() const { return QString::fromLatin1("CloseSilently"); }
+
+ void save( KConfig * );
+};
+
+class BugCommandReopen : public BugCommand {
+ public:
+ BugCommandReopen( const Bug &bug, const Package &pkg ) :
+ BugCommand( bug, pkg ) {}
+
+ QString controlString() const;
+
+ QString name();
+
+ QString type() const { return QString::fromLatin1("Reopen"); }
+
+ void save( KConfig * );
+};
+
+class BugCommandRetitle : public BugCommand {
+ public:
+ BugCommandRetitle( const Bug &bug, const QString &title, const Package &pkg ) :
+ BugCommand( bug, pkg ), m_title( title ) {}
+
+ QString controlString() const;
+
+ QString name();
+ QString details() const;
+
+ QString type() const { return QString::fromLatin1("Retitle"); }
+
+ void save( KConfig * );
+
+ private:
+ QString m_title;
+};
+
+class BugCommandMerge : public BugCommand {
+ public:
+ BugCommandMerge( const QStringList &bugNumbers, const Package &pkg ) :
+ BugCommand( Bug(), pkg ), m_bugNumbers( bugNumbers ) {}
+
+ QString controlString() const;
+
+ QString name();
+ QString details() const;
+
+ QString type() const { return QString::fromLatin1("Merge"); }
+
+ void save( KConfig * );
+
+ private:
+ QStringList m_bugNumbers;
+};
+
+class BugCommandUnmerge : public BugCommand {
+ public:
+ BugCommandUnmerge( const Bug &bug, const Package &pkg ) :
+ BugCommand( bug, pkg ) {}
+
+ QString name();
+
+ QString type() const { return QString::fromLatin1("Unmerge"); }
+
+ void save( KConfig * );
+
+ QString controlString() const;
+};
+
+class BugCommandReply : public BugCommand {
+ public:
+ BugCommandReply( const Bug &bug, const QString &message, const int &recipient) :
+ BugCommand( bug ), m_message( message ), m_recipient( recipient ) {}
+
+ QString mailAddress() const;
+ QString mailText() const;
+
+ QString name();
+ QString details() const;
+
+ QString type() const { return QString::fromLatin1("Reply"); }
+
+ void save( KConfig * );
+
+ private:
+ QString m_message;
+ int m_recipient;
+};
+
+class BugCommandReplyPrivate : public BugCommand {
+ public:
+ BugCommandReplyPrivate( const Bug &bug, const QString &address,
+ const QString &message ) :
+ BugCommand( bug ), m_address( address ), m_message( message ) {}
+
+ QString mailAddress() const;
+ QString mailText() const;
+
+ QString name();
+ QString details() const;
+
+ QString type() const { return QString::fromLatin1("ReplyPrivate"); }
+
+ void save( KConfig * );
+
+ private:
+ QString m_address;
+ QString m_message;
+};
+
+class BugCommandSeverity : public BugCommand {
+ public:
+ BugCommandSeverity( const Bug &bug, const QString &severity, const Package &pkg ) :
+ BugCommand( bug, pkg ), m_severity( severity ) {}
+
+ QString name();
+ QString details() const;
+
+ QString type() const { return QString::fromLatin1("Severity"); }
+
+ QString controlString() const;
+
+ void save( KConfig * );
+
+ private:
+ QString m_severity;
+};
+
+class BugCommandReassign : public BugCommand {
+ public:
+ BugCommandReassign( const Bug &bug, const QString &package, const Package &pkg ) :
+ BugCommand( bug, pkg ), m_package( package ) {}
+
+ QString name();
+ QString details() const;
+
+ QString type() const { return QString::fromLatin1("Reassign"); }
+
+ QString controlString() const;
+
+ void save( KConfig * );
+
+ private:
+ QString m_package;
+};
+
+#endif
diff --git a/kbugbuster/backend/bugdetails.cpp b/kbugbuster/backend/bugdetails.cpp
new file mode 100644
index 00000000..ec512d79
--- /dev/null
+++ b/kbugbuster/backend/bugdetails.cpp
@@ -0,0 +1,268 @@
+
+#include "bugdetails.h"
+
+#include "bugdetailsimpl.h"
+#include <qstringlist.h>
+#include <kdebug.h>
+#include <kmdcodec.h>
+#include <kmessagebox.h>
+#include <qregexp.h>
+
+BugDetails::BugDetails()
+{
+}
+
+BugDetails::BugDetails( BugDetailsImpl *impl ) :
+ m_impl( impl )
+{
+}
+
+BugDetails::BugDetails( const BugDetails &other )
+{
+ (*this) = other;
+}
+
+BugDetails &BugDetails::operator=( const BugDetails &rhs )
+{
+ m_impl = rhs.m_impl;
+ return *this;
+}
+
+BugDetails::~BugDetails()
+{
+}
+
+QString BugDetails::version() const
+{
+ if ( !m_impl )
+ return QString::null;
+
+ return m_impl->version;
+}
+
+QString BugDetails::source() const
+{
+ if ( !m_impl )
+ return QString::null;
+
+ return m_impl->source;
+}
+
+QString BugDetails::compiler() const
+{
+ if ( !m_impl )
+ return QString::null;
+
+ return m_impl->compiler;
+}
+
+QString BugDetails::os() const
+{
+ if ( !m_impl )
+ return QString::null;
+
+ return m_impl->os;
+}
+
+QDateTime BugDetails::submissionDate() const
+{
+ if ( !m_impl ) return QDateTime();
+
+ if ( m_impl->parts.count() > 0 ) {
+ return m_impl->parts.last().date;
+ }
+ return QDateTime();
+}
+
+int BugDetails::age() const
+{
+ if ( !m_impl )
+ return 0;
+
+ return submissionDate().daysTo( QDateTime::currentDateTime() );
+}
+
+BugDetailsPart::List BugDetails::parts() const
+{
+ if ( !m_impl )
+ return BugDetailsPart::List();
+
+ return m_impl->parts;
+}
+
+QValueList<BugDetailsImpl::AttachmentDetails> BugDetails::attachmentDetails() const
+{
+ if ( m_impl )
+ return m_impl->attachments;
+ else
+ return QValueList<BugDetailsImpl::AttachmentDetails>();
+}
+
+void BugDetails::addAttachmentDetails( const QValueList<BugDetailsImpl::AttachmentDetails>& attch )
+{
+ if ( m_impl )
+ m_impl->attachments = attch;
+}
+
+QValueList<BugDetails::Attachment> BugDetails::extractAttachments() const
+{
+ QValueList<BugDetails::Attachment> lst;
+ if ( !m_impl )
+ return lst;
+ BugDetailsPart::List parts = m_impl->parts;
+ for ( BugDetailsPart::List::ConstIterator it = parts.begin(); it != parts.end(); ++it ) {
+ lst += extractAttachments( (*it).text );
+ }
+ return lst;
+}
+
+//#define DEBUG_EXTRACT
+
+QValueList<BugDetails::Attachment> BugDetails::extractAttachments( const QString& text )
+{
+ QValueList<BugDetails::Attachment> lst;
+ QStringList lines = QStringList::split( '\n', text );
+#ifdef DEBUG_EXTRACT
+ kdDebug() << k_funcinfo << lines.count() << " lines." << endl;
+#endif
+ QString boundary;
+ for ( QStringList::Iterator it = lines.begin() ; it != lines.end() ; ++it )
+ {
+#ifdef DEBUG_EXTRACT
+ kdDebug() << "Line: " << *it << endl;
+#endif
+ if ( (*it).startsWith( " Content-Type" ) ) // ## leading space comes from khtml
+ {
+#ifdef DEBUG_EXTRACT
+ //kdDebug() << "BugDetails::extractAttachments going back, looking for empty or boundary=" << boundary << endl;
+#endif
+ // Rewind until last empty line
+ QStringList::Iterator rit = it;
+ for ( ; rit != lines.begin() ; --rit ) {
+ QString line = *rit;
+ if ( line.endsWith( "<br />" ) )
+ line = line.left( line.length() - 6 );
+ while ( !line.isEmpty() && line[0] == ' ' )
+ line.remove( 0, 1 );
+#ifdef DEBUG_EXTRACT
+ kdDebug() << "Back: '" << line << "'" << endl;
+#endif
+ if ( line.isEmpty() ) {
+ ++rit; // boundary is next line
+ boundary = *rit;
+ if ( boundary.endsWith( "<br />" ) )
+ boundary = boundary.left( boundary.length() - 6 );
+ if ( boundary[0] == ' ' )
+ boundary.remove( 0, 1 );
+ kdDebug() << "BugDetails::extractAttachments boundary=" << boundary << endl;
+ break;
+ }
+ if ( line == boundary )
+ break;
+ }
+ // Forward until next empty line (end of headers) - and parse filename
+ QString filename;
+ QString encoding;
+ rit = it;
+ for ( ; rit != lines.end() ; ++rit ) {
+ QString header = *rit;
+ if ( header.endsWith( "<br />" ) )
+ header = header.left( header.length() - 6 );
+ if ( header[0] == ' ' )
+ header.remove( 0, 1 );
+#ifdef DEBUG_EXTRACT
+ kdDebug() << "Header: '" << header << "'" << endl;
+#endif
+ if ( header.isEmpty() )
+ break;
+ if ( header.startsWith( "Content-Disposition:" ) )
+ {
+#ifdef DEBUG_EXTRACT
+ kdDebug() << "BugDetails::extractAttachments found header " << *rit << endl;
+#endif
+ // Taken from libkdenetwork/kmime_headers.cpp
+ int pos=header.find("filename=", 0, false);
+ QString fn;
+ if(pos>-1) {
+ pos+=9;
+ fn=header.mid(pos, header.length()-pos);
+ if ( fn.startsWith( "\"" ) && fn.endsWith( "\"" ) )
+ fn = fn.mid( 1, fn.length() - 2 );
+ //filename=decodeRFC2047String(fn, &e_ncCS, defaultCS(), forceCS());
+ filename = fn; // hack
+ kdDebug() << "BugDetails::extractAttachments filename=" << filename << endl;
+ }
+
+ }
+ else if ( header.startsWith( "Content-Transfer-Encoding:" ) )
+ {
+ encoding = header.mid( 26 ).lower();
+ while ( encoding[0] == ' ' )
+ encoding.remove( 0, 1 );
+ kdDebug() << "BugDetails::extractAttachments encoding=" << encoding << endl;
+ }
+ } //for
+ if ( rit == lines.end() )
+ break;
+
+ it = rit;
+ if ( rit != lines.end() && !filename.isEmpty() )
+ {
+ ++it;
+ if ( it == lines.end() )
+ break;
+ // Read encoded contents
+ QString contents;
+ for ( ; it != lines.end() ; ++it )
+ {
+ QString line = *it;
+ if ( line.endsWith( "</tt>" ) )
+ line = line.left( line.length() - 5 );
+ if ( line.endsWith( "<br />" ) ) // necessary for the boundary check
+ line = line.left( line.length() - 6 );
+ while ( !line.isEmpty() && line[0] == ' ' )
+ line.remove( 0, 1 );
+ if ( line.isEmpty() || line == boundary ) // end of attachment
+ break;
+ if ( line == boundary+"--" ) // end of last attachment
+ {
+ boundary = QString::null;
+ break;
+ }
+ contents += line; // no newline, because of linebreaking between <br and />
+ }
+ contents = contents.replace( QRegExp("<br */>"), QString::null );
+#ifdef DEBUG_EXTRACT
+ kdDebug() << "BugDetails::extractAttachments contents=***\n" << contents << "\n***" << endl;
+#endif
+ kdDebug() << "BugDetails::extractAttachments creating attachment " << filename << endl;
+ Attachment a;
+ if ( encoding == "base64" )
+ KCodecs::base64Decode( contents.local8Bit(), a.contents /*out*/ );
+ else
+ //KCodecs::uudecode( contents.local8Bit(), a.contents /*out*/ );
+ KMessageBox::information( 0, i18n("Attachment %1 could not be decoded.\nEncoding: %2").arg(filename).arg(encoding) );
+#ifdef DEBUG_EXTRACT
+ kdDebug() << "Result: ***\n" << QCString( a.contents.data(), a.contents.size()+1 ) << "\n*+*" << endl;
+#endif
+ a.filename = filename;
+ lst.append(a);
+ if ( it == lines.end() )
+ break;
+ }
+ }
+ }
+#ifdef DEBUG_EXTRACT
+ kdDebug() << "BugDetails::extractAttachments returning " << lst.count() << " attachments for this part." << endl;
+#endif
+ return lst;
+}
+
+bool BugDetails::operator==( const BugDetails &rhs )
+{
+ return m_impl == rhs.m_impl;
+}
+
+/**
+ * vim:ts=4:sw=4:et
+ */
diff --git a/kbugbuster/backend/bugdetails.h b/kbugbuster/backend/bugdetails.h
new file mode 100644
index 00000000..08d20777
--- /dev/null
+++ b/kbugbuster/backend/bugdetails.h
@@ -0,0 +1,55 @@
+#ifndef __bugdetails_h__
+#define __bugdetails_h__
+
+#include "person.h"
+#include "bugdetailspart.h"
+#include "bugdetailsimpl.h"
+
+#include <qvaluelist.h>
+
+#include <ksharedptr.h>
+
+class BugDetailsImpl;
+
+class BugDetails
+{
+public:
+ typedef QValueList<BugDetails> List;
+ struct Attachment {
+ QByteArray contents;
+ QString filename;
+ };
+
+ BugDetails();
+ BugDetails( BugDetailsImpl *impl );
+ BugDetails( const BugDetails &other );
+ BugDetails &operator=( const BugDetails &rhs );
+ ~BugDetails();
+
+ QString version() const;
+ QString source() const;
+ QString compiler() const;
+ QString os() const;
+ BugDetailsPart::List parts() const;
+ void addAttachmentDetails( const QValueList<BugDetailsImpl::AttachmentDetails>& attch );
+ QValueList<BugDetailsImpl::AttachmentDetails> attachmentDetails() const;
+ QValueList<BugDetails::Attachment> extractAttachments() const;
+ static QValueList<BugDetails::Attachment> extractAttachments( const QString& text );
+
+ QDateTime submissionDate() const;
+ int age() const;
+
+ bool operator==( const BugDetails &rhs );
+
+ bool isNull() const { return m_impl == 0; }
+
+private:
+ BugDetailsImpl *impl() const { return m_impl; }
+
+ KSharedPtr<BugDetailsImpl> m_impl;
+};
+
+#endif
+
+/* vim: set sw=4 ts=4 et softtabstop=4: */
+
diff --git a/kbugbuster/backend/bugdetailsimpl.h b/kbugbuster/backend/bugdetailsimpl.h
new file mode 100644
index 00000000..df3e5d6d
--- /dev/null
+++ b/kbugbuster/backend/bugdetailsimpl.h
@@ -0,0 +1,40 @@
+#ifndef __bugdetails_impl_h__
+#define __bugdetails_impl_h__
+
+#include <ksharedptr.h>
+
+#include "bugdetailspart.h"
+
+struct BugDetailsImpl : public KShared
+{
+public:
+ BugDetailsImpl( const QString &_version, const QString &_source,
+ const QString &_compiler, const QString &_os,
+ const BugDetailsPart::List &_parts )
+ : version( _version ), source( _source ), compiler( _compiler ),
+ os( _os ), parts( _parts ) {}
+
+ struct AttachmentDetails {
+ AttachmentDetails() { }
+ AttachmentDetails( const QString& descr, const QString& dt,
+ const QString& idf ) : description( descr ),
+ date( dt ),
+ id( idf ) { }
+ QString description;
+ QString date;
+ QString id;
+ };
+
+ QString version;
+ QString source;
+ QString compiler;
+ QString os;
+ BugDetailsPart::List parts;
+ QValueList<BugDetailsImpl::AttachmentDetails> attachments;
+};
+
+#endif
+
+/*
+ * vim:sw=4:ts=4:et
+ */
diff --git a/kbugbuster/backend/bugdetailsjob.cpp b/kbugbuster/backend/bugdetailsjob.cpp
new file mode 100644
index 00000000..83599c1d
--- /dev/null
+++ b/kbugbuster/backend/bugdetailsjob.cpp
@@ -0,0 +1,50 @@
+
+#include "bugdetailsjob.h"
+#include "bug.h"
+#include "bugdetails.h"
+#include "bugdetailsimpl.h"
+#include "packageimpl.h"
+#include "bugserver.h"
+#include "processor.h"
+
+#include <kdebug.h>
+#include <assert.h>
+
+BugDetailsJob::BugDetailsJob( BugServer *server )
+ : BugJob( server )
+{
+}
+
+BugDetailsJob::~BugDetailsJob()
+{
+}
+
+void BugDetailsJob::start( const Bug &bug )
+{
+ m_bug = bug;
+
+ KURL bugUrl = server()->bugDetailsUrl( bug );
+
+ kdDebug() << "BugDetailsJob::start(): " << bugUrl.url() << endl;
+ BugJob::start( bugUrl );
+}
+
+void BugDetailsJob::process( const QByteArray &data )
+{
+ BugDetails bugDetails;
+
+ KBB::Error err = server()->processor()->parseBugDetails( data, bugDetails );
+
+ if ( err ) {
+ emit error( i18n("Bug %1: %2").arg( m_bug.number() )
+ .arg( err.message() ) );
+ } else {
+ emit bugDetailsAvailable( m_bug, bugDetails );
+ }
+}
+
+#include "bugdetailsjob.moc"
+
+/*
+ * vim:sw=4:ts=4:et
+ */
diff --git a/kbugbuster/backend/bugdetailsjob.h b/kbugbuster/backend/bugdetailsjob.h
new file mode 100644
index 00000000..e07ad3a2
--- /dev/null
+++ b/kbugbuster/backend/bugdetailsjob.h
@@ -0,0 +1,32 @@
+#ifndef __bugdetailsjob_h__
+#define __bugdetailsjob_h__
+
+#include "bugjob.h"
+#include "bug.h"
+#include "bugdetails.h"
+#include "bugdetailspart.h"
+
+class BugDetailsJob : public BugJob
+{
+ Q_OBJECT
+ public:
+ BugDetailsJob( BugServer * );
+ virtual ~BugDetailsJob();
+
+ void start( const Bug &bug );
+
+ signals:
+ void bugDetailsAvailable( const Bug &bug, const BugDetails &details );
+
+ protected:
+ virtual void process( const QByteArray &data );
+
+ private:
+ Bug m_bug;
+};
+
+#endif
+
+/*
+ * vim:ts=4:sw=4:et
+ */
diff --git a/kbugbuster/backend/bugdetailspart.h b/kbugbuster/backend/bugdetailspart.h
new file mode 100644
index 00000000..483057c8
--- /dev/null
+++ b/kbugbuster/backend/bugdetailspart.h
@@ -0,0 +1,21 @@
+#ifndef BUGDETAILSPART_H
+#define BUGDETAILSPART_H
+
+#include <qvaluelist.h>
+#include <qdatetime.h>
+
+struct BugDetailsPart
+{
+ typedef QValueList<BugDetailsPart> List;
+
+ BugDetailsPart () {}
+ BugDetailsPart( const Person &_sender, const QDateTime &_date,
+ const QString &_text )
+ : sender( _sender ), date( _date ), text( _text ) {}
+
+ Person sender;
+ QDateTime date;
+ QString text;
+};
+
+#endif
diff --git a/kbugbuster/backend/bugimpl.h b/kbugbuster/backend/bugimpl.h
new file mode 100644
index 00000000..630105a1
--- /dev/null
+++ b/kbugbuster/backend/bugimpl.h
@@ -0,0 +1,36 @@
+#ifndef __bug_impl_h__
+#define __bug_impl_h__
+
+#include "person.h"
+#include "bug.h"
+
+#include <kurl.h>
+#include <ksharedptr.h>
+
+struct BugImpl : public KShared
+{
+public:
+ BugImpl( const QString &_title, const Person &_submitter, QString _number,
+ uint _age, Bug::Severity _severity, Person _developerTODO,
+ Bug::Status _status, const Bug::BugMergeList& _mergedWith )
+ : age( _age ), title( _title ), submitter( _submitter ), number( _number ),
+ severity( _severity ), developerTODO( _developerTODO ),
+ status( _status ), mergedWith( _mergedWith )
+ {
+ }
+
+ uint age;
+ QString title;
+ Person submitter;
+ QString number;
+ Bug::Severity severity;
+ Person developerTODO;
+ Bug::Status status;
+
+ Bug::BugMergeList mergedWith;
+};
+
+#endif
+
+// vim: set sw=4 ts=4 sts=4 et:
+
diff --git a/kbugbuster/backend/bugjob.cpp b/kbugbuster/backend/bugjob.cpp
new file mode 100644
index 00000000..6f32fb97
--- /dev/null
+++ b/kbugbuster/backend/bugjob.cpp
@@ -0,0 +1,97 @@
+
+#include "bugjob.h"
+
+#include "kbbprefs.h"
+
+#include <kio/job.h>
+
+#include <string.h>
+#include <klocale.h>
+#include <kdebug.h>
+
+BugJob::BugJob( BugServer *server )
+ : Job( false ), mServer( server )
+{
+}
+
+BugJob::~BugJob()
+{
+}
+
+void BugJob::start( const KURL &url )
+{
+ kdDebug() << "BugJob::start(): " << url.url() << endl;
+
+ if ( KBBPrefs::instance()->mDebugMode ) {
+ BugSystem::saveQuery( url );
+ }
+
+ // ### obey post, if necessary
+
+ KIO::Job *job = KIO::get( url, true /*always 'reload=true', we have our own cache*/, false );
+
+ connect( job, SIGNAL( result( KIO::Job * ) ),
+ this, SLOT( ioResult( KIO::Job * ) ) );
+ connect( job, SIGNAL( data( KIO::Job *, const QByteArray & ) ),
+ this, SLOT( ioData( KIO::Job *, const QByteArray & ) ) );
+ connect( job, SIGNAL( infoMessage( KIO::Job *, const QString & ) ),
+ this, SLOT( ioInfoMessage( KIO::Job *, const QString & ) ) );
+ connect( job, SIGNAL( percent( KIO::Job *, unsigned long ) ),
+ this, SLOT( ioInfoPercent( KIO::Job *, unsigned long ) ) );
+}
+
+void BugJob::ioResult( KIO::Job *job )
+{
+ m_error = job->error();
+ m_errorText = job->errorText();
+
+ if ( job->error() )
+ {
+ emit error( m_errorText );
+ BugSystem::self()->unregisterJob(this);
+ this->kill();
+ return;
+ }
+
+ infoMessage( i18n( "Parsing..." ) );
+
+#if 0
+ kdDebug() << "--START:" << m_data << ":END--" << endl;
+#endif
+
+ if ( KBBPrefs::instance()->mDebugMode ) {
+ BugSystem::saveResponse( m_data );
+ }
+
+ process( m_data );
+ infoMessage( i18n( "Ready." ) );
+
+ emit jobEnded( this );
+
+ delete this;
+}
+
+void BugJob::ioData( KIO::Job *, const QByteArray &data )
+{
+ unsigned int start = m_data.size();
+
+ m_data.resize( m_data.size() + data.size() );
+ memcpy( m_data.data() + start, data.data(), data.size() );
+}
+
+void BugJob::ioInfoMessage( KIO::Job *, const QString &_text )
+{
+ QString text = _text;
+ emit infoMessage( text );
+}
+
+void BugJob::ioInfoPercent( KIO::Job *, unsigned long percent )
+{
+ emit infoPercent( percent );
+}
+
+#include "bugjob.moc"
+
+/*
+ * vim:sw=4:ts=4:et
+ */
diff --git a/kbugbuster/backend/bugjob.h b/kbugbuster/backend/bugjob.h
new file mode 100644
index 00000000..2c439810
--- /dev/null
+++ b/kbugbuster/backend/bugjob.h
@@ -0,0 +1,45 @@
+#ifndef KBB_BUGJOB_H
+#define KBB_BUGJOB_H
+
+#include <kio/jobclasses.h>
+
+#include "bugserver.h"
+
+class BugJob : public KIO::Job
+{
+ Q_OBJECT
+ public:
+ BugJob( BugServer * );
+ virtual ~BugJob();
+
+ BugServer *server() const { return mServer; }
+
+ signals:
+ void infoMessage( const QString &text );
+ void infoPercent( unsigned long percent );
+ void error( const QString &text );
+ void jobEnded( BugJob * );
+
+ protected:
+ void start( const KURL &url /*, const KParts::URLArgs &args = KParts::URLArgs()*/ );
+
+ virtual void process( const QByteArray &data ) = 0;
+
+ private slots:
+ void ioResult( KIO::Job *job );
+
+ void ioData( KIO::Job *job, const QByteArray &data );
+
+ void ioInfoMessage( KIO::Job *job, const QString &text );
+
+ void ioInfoPercent( KIO::Job *job, unsigned long percent );
+
+ private:
+ QByteArray m_data;
+ BugServer *mServer;
+};
+
+#endif
+/*
+ * vim:sw=4:ts=4:et
+ */
diff --git a/kbugbuster/backend/buglistjob.cpp b/kbugbuster/backend/buglistjob.cpp
new file mode 100644
index 00000000..e1dea2f4
--- /dev/null
+++ b/kbugbuster/backend/buglistjob.cpp
@@ -0,0 +1,75 @@
+/*
+ This file is part of KBugBuster.
+
+ Copyright (c) 2002,2003 Cornelius Schumacher <schumacher@kde.org>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the 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, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+ As a special exception, permission is given to link this program
+ with any edition of Qt, and distribute the resulting executable,
+ without including the source code for Qt in the source distribution.
+*/
+
+#include "buglistjob.h"
+#include "bug.h"
+#include "bugimpl.h"
+#include "packageimpl.h"
+#include "bugserver.h"
+#include "domprocessor.h"
+#include "htmlparser.h"
+
+#include <kdebug.h>
+
+#include <qbuffer.h>
+#include <qregexp.h>
+
+BugListJob::BugListJob( BugServer *server )
+ : BugJob( server )
+{
+}
+
+BugListJob::~BugListJob()
+{
+}
+
+void BugListJob::start( const Package &pkg, const QString &component )
+{
+ m_package = pkg;
+ m_component = component;
+
+ BugJob::start( server()->bugListUrl( pkg, component ) );
+}
+
+
+void BugListJob::process( const QByteArray &data )
+{
+ Bug::List bugs;
+
+ KBB::Error err = server()->processor()->parseBugList( data, bugs );
+
+ if ( err ) {
+ emit error( i18n("Package %1: %2").arg( m_package.name() )
+ .arg( err.message() ) );
+ } else {
+ emit bugListAvailable( m_package, m_component, bugs );
+ }
+}
+
+
+#include "buglistjob.moc"
+
+/*
+ * vim:sw=4:ts=4:et
+ */
diff --git a/kbugbuster/backend/buglistjob.h b/kbugbuster/backend/buglistjob.h
new file mode 100644
index 00000000..0260d3a0
--- /dev/null
+++ b/kbugbuster/backend/buglistjob.h
@@ -0,0 +1,58 @@
+/*
+ This file is part of KBugBuster.
+
+ Copyright (c) 2002,2003 Cornelius Schumacher <schumacher@kde.org>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the 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, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+ As a special exception, permission is given to link this program
+ with any edition of Qt, and distribute the resulting executable,
+ without including the source code for Qt in the source distribution.
+*/
+#ifndef BUGLISTJOB_H
+#define BUGLISTJOB_H
+
+#include "bugjob.h"
+#include "package.h"
+#include "bug.h"
+
+#include <qdom.h>
+
+class BugListJob : public BugJob
+{
+ Q_OBJECT
+ public:
+ BugListJob( BugServer * );
+ virtual ~BugListJob();
+
+ void start( const Package &pkg, const QString &component );
+
+ protected:
+ void process( const QByteArray &data );
+
+ signals:
+ void bugListAvailable( const Package &pkg, const QString &component, const Bug::List &bugs );
+
+ protected:
+ Package m_package;
+ QString m_component;
+};
+
+
+#endif
+
+/*
+ * vim:ts=4:sw=4:et
+ */
diff --git a/kbugbuster/backend/bugmybugsjob.cpp b/kbugbuster/backend/bugmybugsjob.cpp
new file mode 100644
index 00000000..92aa4448
--- /dev/null
+++ b/kbugbuster/backend/bugmybugsjob.cpp
@@ -0,0 +1,78 @@
+/*
+ This file is part of KBugBuster.
+
+ Copyright (c) 2002-2003 Cornelius Schumacher <schumacher@kde.org>
+ Copyright (c) 2004 Martijn Klingens <klingens@kde.org>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the 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, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+ As a special exception, permission is given to link this program
+ with any edition of Qt, and distribute the resulting executable,
+ without including the source code for Qt in the source distribution.
+*/
+
+#include "bugmybugsjob.h"
+#include "bug.h"
+#include "bugimpl.h"
+#include "packageimpl.h"
+#include "bugserver.h"
+#include "domprocessor.h"
+#include "htmlparser.h"
+
+#include <kdebug.h>
+
+#include <qbuffer.h>
+#include <qregexp.h>
+
+BugMyBugsJob::BugMyBugsJob( BugServer *server )
+: BugJob( server )
+{
+}
+
+BugMyBugsJob::~BugMyBugsJob()
+{
+}
+
+void BugMyBugsJob::start()
+{
+ KURL url = server()->serverConfig().baseUrl();
+ url.setFileName( "buglist.cgi" );
+ url.setQuery( "bug_status=NEW&bug_status=ASSIGNED&bug_status=UNCONFIRMED&bug_status=REOPENED" );
+ url.addQueryItem( "email1", server()->serverConfig().user() );
+ url.addQueryItem( "emailtype1", "exact" );
+ url.addQueryItem( "emailassigned_to1", "1" );
+ url.addQueryItem( "emailreporter1", "1" );
+ url.addQueryItem( "format", "rdf" );
+ BugJob::start( url );
+}
+
+void BugMyBugsJob::process( const QByteArray &data )
+{
+ Bug::List bugs;
+
+ Processor *processor = new RdfProcessor( server() );
+ KBB::Error err = processor->parseBugList( data, bugs );
+ delete processor;
+
+ if ( err )
+ emit error( i18n( "My Bugs: %2" ).arg( err.message() ) );
+ else
+ emit bugListAvailable( i18n( "My Bugs" ), bugs );
+}
+
+#include "bugmybugsjob.moc"
+
+// vim: set sw=4 ts=4 et:
+
diff --git a/kbugbuster/backend/bugmybugsjob.h b/kbugbuster/backend/bugmybugsjob.h
new file mode 100644
index 00000000..f51ee229
--- /dev/null
+++ b/kbugbuster/backend/bugmybugsjob.h
@@ -0,0 +1,52 @@
+/*
+ This file is part of KBugBuster.
+
+ Copyright (c) 2002-2003 Cornelius Schumacher <schumacher@kde.org>
+ Copyright (c) 2004 Martijn Klingens <klingens@kde.org>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the 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, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+ As a special exception, permission is given to link this program
+ with any edition of Qt, and distribute the resulting executable,
+ without including the source code for Qt in the source distribution.
+*/
+
+#ifndef BUGMYBUGSJOB_H
+#define BUGMYBUGSJOB_H
+
+#include "bugjob.h"
+#include "bug.h"
+
+class BugMyBugsJob : public BugJob
+{
+ Q_OBJECT
+
+public:
+ BugMyBugsJob( BugServer * );
+ virtual ~BugMyBugsJob();
+
+ void start();
+
+protected:
+ void process( const QByteArray &data );
+
+signals:
+ void bugListAvailable( const QString &label, const Bug::List &bugs );
+};
+
+#endif
+
+// vim: set ts=4 sw=4 et:
+
diff --git a/kbugbuster/backend/bugserver.cpp b/kbugbuster/backend/bugserver.cpp
new file mode 100644
index 00000000..0e6a70e6
--- /dev/null
+++ b/kbugbuster/backend/bugserver.cpp
@@ -0,0 +1,412 @@
+/*
+ This file is part of KBugBuster.
+ Copyright (c) 2002,2003 Cornelius Schumacher <schumacher@kde.org>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the 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, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+ As a special exception, permission is given to link this program
+ with any edition of Qt, and distribute the resulting executable,
+ without including the source code for Qt in the source distribution.
+*/
+
+#include "bugserver.h"
+#include "kbbprefs.h"
+#include "rdfprocessor.h"
+#include "bugcache.h"
+#include "bugcommand.h"
+#include "mailsender.h"
+#include "bugserverconfig.h"
+#include "htmlparser.h"
+
+#include <kstandarddirs.h>
+#include <ksimpleconfig.h>
+#include <kdebug.h>
+
+BugServer::BugServer()
+{
+ init();
+}
+
+BugServer::BugServer( const BugServerConfig &cfg )
+ : mServerConfig( cfg )
+{
+ init();
+}
+
+void BugServer::init()
+{
+ mCache = new BugCache( identifier() );
+
+ QString commandsFile = locateLocal( "appdata", identifier() + "commands" );
+ mCommandsFile = new KSimpleConfig( commandsFile );
+
+ QString bugzilla = mServerConfig.bugzillaVersion();
+
+ if ( bugzilla == "KDE" ) mProcessor = new DomProcessor( this );
+ else if ( bugzilla == "2.10" ) mProcessor = new HtmlParser_2_10( this );
+ else if ( bugzilla == "2.14.2" ) mProcessor = new HtmlParser_2_14_2( this );
+ else if ( bugzilla == "2.17.1" ) mProcessor = new HtmlParser_2_17_1( this );
+ else mProcessor = new HtmlParser( this );
+
+ loadCommands();
+}
+
+BugServer::~BugServer()
+{
+ saveCommands();
+
+ delete mProcessor;
+ delete mCommandsFile;
+ delete mCache;
+}
+
+void BugServer::setServerConfig( const BugServerConfig &cfg )
+{
+ mServerConfig = cfg;
+}
+
+BugServerConfig &BugServer::serverConfig()
+{
+ return mServerConfig;
+}
+
+QString BugServer::identifier()
+{
+ QString id = mServerConfig.baseUrl().host();
+ return id;
+}
+
+Processor *BugServer::processor() const
+{
+ return mProcessor;
+}
+
+KURL BugServer::packageListUrl()
+{
+ KURL url = mServerConfig.baseUrl();
+
+ mProcessor->setPackageListQuery( url );
+
+ return url;
+}
+
+KURL BugServer::bugListUrl( const Package &product, const QString &component )
+{
+ KURL url = mServerConfig.baseUrl();
+
+ mProcessor->setBugListQuery( url, product, component );
+
+ return url;
+}
+
+KURL BugServer::bugDetailsUrl( const Bug &bug )
+{
+ KURL url = mServerConfig.baseUrl();
+
+ mProcessor->setBugDetailsQuery( url, bug );
+
+ return url;
+}
+
+KURL BugServer::bugLink( const Bug &bug )
+{
+ KURL url = mServerConfig.baseUrl();
+
+ url.setFileName( "show_bug.cgi" );
+ url.setQuery( "id=" + bug.number() );
+
+ kdDebug() << "URL: " << url.url() << endl;
+
+ return url;
+}
+
+KURL BugServer::attachmentViewLink( const QString &id )
+{
+ KURL url = mServerConfig.baseUrl();
+
+ url.setFileName( "attachment.cgi" );
+ url.setQuery( "id=" + id + "&action=view" );
+
+ return url;
+}
+
+KURL BugServer::attachmentEditLink( const QString &id )
+{
+ KURL url = mServerConfig.baseUrl();
+
+ url.setFileName( "attachment.cgi" );
+ url.setQuery( "id=" + id + "&action=edit" );
+
+ return url;
+}
+
+Bug::Status BugServer::bugStatus( const QString &str )
+{
+ if ( str == "UNCONFIRMED" ) {
+ return Bug::Unconfirmed;
+ } else if ( str == "NEW" ) {
+ return Bug::New;
+ } else if ( str == "ASSIGNED" ) {
+ return Bug::Assigned;
+ } else if ( str == "REOPENED" ) {
+ return Bug::Reopened;
+ } else if ( str == "RESOLVED" ) {
+ return Bug::Closed;
+ } else if ( str == "VERIFIED" ) {
+ return Bug::Closed;
+ } else if ( str == "CLOSED" ) {
+ return Bug::Closed;
+ } else {
+ return Bug::StatusUndefined;
+ }
+}
+
+Bug::Severity BugServer::bugSeverity( const QString &str )
+{
+ if ( str == "critical" ) {
+ return Bug::Critical;
+ } else if ( str == "grave" ) {
+ return Bug::Grave;
+ } else if ( str == "major" ) {
+ return Bug::Major;
+ } else if ( str == "crash" ) {
+ return Bug::Crash;
+ } else if ( str == "normal" ) {
+ return Bug::Normal;
+ } else if ( str == "minor" ) {
+ return Bug::Minor;
+ } else if ( str == "wishlist" ) {
+ return Bug::Wishlist;
+ } else {
+ return Bug::SeverityUndefined;
+ }
+}
+
+void BugServer::readConfig( KConfig * /*config*/ )
+{
+}
+
+void BugServer::writeConfig( KConfig * /*config*/ )
+{
+}
+
+bool BugServer::queueCommand( BugCommand *cmd )
+{
+ // mCommands[bug] is a QPtrList. Get or create, set to autodelete, then append command.
+ mCommands[cmd->bug().number()].setAutoDelete( true );
+ QPtrListIterator<BugCommand> cmdIt( mCommands[cmd->bug().number()] );
+ for ( ; cmdIt.current(); ++cmdIt )
+ if ( cmdIt.current()->type() == cmd->type() )
+ return false;
+ mCommands[cmd->bug().number()].append( cmd );
+ return true;
+}
+
+QPtrList<BugCommand> BugServer::queryCommands( const Bug &bug ) const
+{
+ CommandsMap::ConstIterator it = mCommands.find( bug.number() );
+ if (it == mCommands.end()) return QPtrList<BugCommand>();
+ else return *it;
+}
+
+bool BugServer::hasCommandsFor( const Bug &bug ) const
+{
+ CommandsMap::ConstIterator it = mCommands.find( bug.number() );
+ return it != mCommands.end();
+}
+
+void BugServer::sendCommands( MailSender *mailer, const QString &senderName,
+ const QString &senderEmail, bool sendBCC,
+ const QString &recipient )
+{
+ // Disable mail commands for non-KDE servers
+ if ( mServerConfig.baseUrl() != KURL( "http://bugs.kde.org" ) ) return;
+
+ QString controlText;
+
+ // For each bug that has commands.....
+ CommandsMap::ConstIterator it;
+ for(it = mCommands.begin(); it != mCommands.end(); ++it ) {
+ Bug bug;
+ Package pkg;
+ // And for each command....
+ QPtrListIterator<BugCommand> cmdIt( *it );
+ for ( ; cmdIt.current() ; ++cmdIt ) {
+ BugCommand* cmd = cmdIt.current();
+ bug = cmd->bug();
+ if (!cmd->package().isNull())
+ pkg = cmd->package();
+ if (!cmd->controlString().isNull()) {
+ kdDebug() << "control@bugs.kde.org: " << cmd->controlString() << endl;
+ controlText += cmd->controlString() + "\n";
+ } else {
+ kdDebug() << cmd->mailAddress() << ": " << cmd->mailText() << endl;
+ // ### hm, should probably re-use the existing mailer instance and
+ // implement message queueing for smtp
+ MailSender *directMailer = mailer->clone();
+#if 0
+ connect( directMailer, SIGNAL( status( const QString & ) ),
+ this, SIGNAL( infoMessage( const QString & ) ) );
+#endif
+ if (!directMailer->send( senderName, senderEmail, cmd->mailAddress(),
+ cmd->bug().title().prepend( "Re: " ),
+ cmd->mailText(), sendBCC, recipient )) {
+ delete mailer;
+ return;
+ }
+ }
+ }
+ if (!bug.isNull()) {
+ mCommandsFile->deleteGroup( bug.number(), true ); // done, remove command
+ mCache->invalidateBugDetails( bug );
+ if ( !pkg.isNull() ) {
+ mCache->invalidateBugList( pkg, QString::null ); // the status of the bug comes from the buglist...
+
+ QStringList::ConstIterator it2;
+ for (it2 = pkg.components().begin();it2 != pkg.components().end();++it2) {
+ mCache->invalidateBugList( pkg, (*it2) ); // the status of the bug comes from the buglist...
+ }
+ }
+ }
+ }
+
+ if (!controlText.isEmpty()) {
+ kdDebug() << "control@bugs.kde.org doesn't work anymore" << endl;
+#if 0
+ if ( !mailer->send( senderName, senderEmail, "control@bugs.kde.org",
+ i18n("Mail generated by KBugBuster"), controlText,
+ sendBCC, recipient ))
+ return;
+#endif
+ } else {
+ delete mailer;
+ }
+
+ mCommands.clear();
+}
+
+void BugServer::clearCommands( const QString &bug )
+{
+ mCommands.remove( bug );
+ mCommandsFile->deleteGroup( bug, true );
+}
+
+bool BugServer::commandsPending() const
+{
+ if ( mCommands.count() > 0 ) return true;
+ else return false;
+}
+
+QStringList BugServer::listCommands() const
+{
+ QStringList result;
+ CommandsMap::ConstIterator it;
+ for(it = mCommands.begin(); it != mCommands.end(); ++it ) {
+ QPtrListIterator<BugCommand> cmdIt( *it );
+ for ( ; cmdIt.current() ; ++cmdIt ) {
+ BugCommand* cmd = cmdIt.current();
+ if (!cmd->controlString().isNull())
+ result.append( i18n("Control command: %1").arg(cmd->controlString()) );
+ else
+ result.append( i18n("Mail to %1").arg(cmd->mailAddress()) );
+ }
+ }
+ return result;
+}
+
+QStringList BugServer::bugsWithCommands() const
+{
+ QStringList bugs;
+
+ CommandsMap::ConstIterator it;
+ for(it = mCommands.begin(); it != mCommands.end(); ++it ) {
+ bugs.append( it.key() );
+ }
+
+ return bugs;
+}
+
+void BugServer::saveCommands() const
+{
+ CommandsMap::ConstIterator it;
+ for(it = mCommands.begin(); it != mCommands.end(); ++it ) {
+ mCommandsFile->setGroup( it.key() );
+ QPtrListIterator<BugCommand> cmdIt( *it );
+ for ( ; cmdIt.current() ; ++cmdIt ) {
+ BugCommand* cmd = cmdIt.current();
+ cmd->save( mCommandsFile );
+ }
+ }
+
+ mCommandsFile->sync();
+}
+
+void BugServer::loadCommands()
+{
+ mCommands.clear();
+
+ QStringList bugs = mCommandsFile->groupList();
+ QStringList::ConstIterator it;
+ for( it = bugs.begin(); it != bugs.end(); ++it ) {
+ mCommandsFile->setGroup( *it );
+ QMap<QString, QString> entries = mCommandsFile->entryMap ( *it );
+ QMap<QString, QString>::ConstIterator it;
+ for( it = entries.begin(); it != entries.end(); ++it ) {
+ QString type = it.key();
+ BugCommand *cmd = BugCommand::load( mCommandsFile, type );
+ if ( cmd ) {
+ mCommands[cmd->bug().number()].setAutoDelete(true);
+ mCommands[cmd->bug().number()].append(cmd);
+ }
+ }
+ }
+}
+
+void BugServer::setPackages( const Package::List &packages )
+{
+ mPackages = packages;
+}
+
+const Package::List &BugServer::packages() const
+{
+ return mPackages;
+}
+
+void BugServer::setBugs( const Package &pkg, const QString &component,
+ const Bug::List &bugs )
+{
+ QPair<Package, QString> pkg_key = QPair<Package, QString>(pkg, component);
+ mBugs[ pkg_key ] = bugs;
+}
+
+const Bug::List &BugServer::bugs( const Package &pkg, const QString &component )
+{
+ QPair<Package, QString> pkg_key = QPair<Package, QString>(pkg, component);
+ return mBugs[ pkg_key ];
+}
+
+void BugServer::setBugDetails( const Bug &bug, const BugDetails &details )
+{
+ mBugDetails[ bug ] = details;
+}
+
+const BugDetails &BugServer::bugDetails( const Bug &bug )
+{
+ return mBugDetails[ bug ];
+}
+
+/*
+ * vim:sw=4:ts=4:et
+ */
diff --git a/kbugbuster/backend/bugserver.h b/kbugbuster/backend/bugserver.h
new file mode 100644
index 00000000..3b534fa0
--- /dev/null
+++ b/kbugbuster/backend/bugserver.h
@@ -0,0 +1,152 @@
+/*
+ This file is part of KBugBuster.
+ Copyright (c) 2002,2003 Cornelius Schumacher <schumacher@kde.org>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the 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, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+ As a special exception, permission is given to link this program
+ with any edition of Qt, and distribute the resulting executable,
+ without including the source code for Qt in the source distribution.
+*/
+#ifndef BUGSERVER_H
+#define BUGSERVER_H
+
+#include <qstring.h>
+
+#include <kurl.h>
+
+#include "bug.h"
+#include "package.h"
+#include "bugsystem.h"
+#include "bugserverconfig.h"
+
+class Processor;
+class BugCache;
+class MailSender;
+class BugServerConfig;
+
+class BugServer
+{
+ public:
+ BugServer();
+ BugServer( const BugServerConfig & );
+ ~BugServer();
+
+ /**
+ BugServer takes ownership of the BugServerConfig object.
+ */
+ void setServerConfig( const BugServerConfig & );
+ BugServerConfig &serverConfig();
+
+ QString identifier();
+
+ BugCache *cache() const { return mCache; }
+
+ KURL packageListUrl();
+
+ KURL bugListUrl( const Package &, const QString &component );
+
+ KURL bugDetailsUrl( const Bug & );
+
+ KURL bugLink( const Bug & );
+ KURL attachmentViewLink( const QString &id );
+ KURL attachmentEditLink( const QString &id );
+
+ Bug::Status bugStatus( const QString & );
+
+ Bug::Severity bugSeverity( const QString & );
+
+ Processor *processor() const;
+
+ void readConfig( KConfig * );
+
+ void writeConfig( KConfig * );
+
+ /**
+ Queue a new command.
+ */
+ bool queueCommand( BugCommand * );
+ /**
+ Return all the commands for a given bug.
+ */
+ QPtrList<BugCommand> queryCommands( const Bug & ) const;
+ /**
+ Return true if we have a least one command for this bug.
+ */
+ bool hasCommandsFor( const Bug &bug ) const;
+ /**
+ Send all commands (generate the mails).
+ */
+ void sendCommands( MailSender *, const QString &senderName,
+ const QString &senderEmail, bool sendBCC,
+ const QString &recipient );
+ /**
+ Forget all commands for a given bug.
+ */
+ void clearCommands( const QString &bug );
+ /**
+ Return true if any command has been created.
+ */
+ bool commandsPending() const;
+ /**
+ List all pending commands.
+ */
+ QStringList listCommands() const;
+ /**
+ Return numbers of all bugs having at least one command queued.
+ */
+ QStringList bugsWithCommands() const;
+
+ void saveCommands() const;
+ void loadCommands();
+
+ void setPackages( const Package::List & );
+ const Package::List &packages() const;
+
+ void setBugs( const Package &, const QString &component,
+ const Bug::List & );
+ const Bug::List &bugs( const Package &, const QString &component );
+
+ void setBugDetails( const Bug &, const BugDetails & );
+ const BugDetails &bugDetails( const Bug & );
+
+ private:
+ void init();
+
+ BugServerConfig mServerConfig;
+
+ Processor *mProcessor;
+
+ BugCache *mCache;
+
+ Package::List mPackages;
+ // Map package -> list of bugs
+ typedef QMap< QPair<Package, QString>, Bug::List > BugListMap;
+ BugListMap mBugs;
+ // Map bug -> bug details (i.e. contents of the report)
+ typedef QMap< Bug, BugDetails > BugDetailsMap;
+ BugDetailsMap mBugDetails;
+ // Map bug-number -> list of commands
+ typedef QMap< QString, QPtrList<BugCommand> > CommandsMap;
+ CommandsMap mCommands;
+
+ KSimpleConfig *mCommandsFile;
+};
+
+#endif
+
+/*
+ * vim:sw=4:ts=4:et
+ */
diff --git a/kbugbuster/backend/bugserverconfig.cpp b/kbugbuster/backend/bugserverconfig.cpp
new file mode 100644
index 00000000..0669c0ab
--- /dev/null
+++ b/kbugbuster/backend/bugserverconfig.cpp
@@ -0,0 +1,150 @@
+/*
+ This file is part of KBugBuster.
+
+ Copyright (c) 2003 Cornelius Schumacher <schumacher@kde.org>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the 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, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+ As a special exception, permission is given to link this program
+ with any edition of Qt, and distribute the resulting executable,
+ without including the source code for Qt in the source distribution.
+*/
+
+#include "bugserverconfig.h"
+
+#include "kbbprefs.h"
+
+#include <kdebug.h>
+#include <kconfig.h>
+
+BugServerConfig::BugServerConfig()
+{
+ mName = "KDE";
+ mBaseUrl = "http://bugs.kde.org";
+ mUser = "bugzilla@kde.org";
+ mBugzillaVersion = "KDE";
+}
+
+BugServerConfig::BugServerConfig( const QString &name, const KURL &baseUrl )
+ : mName( name ), mBaseUrl( baseUrl ), mBugzillaVersion( "KDE" )
+{
+}
+
+BugServerConfig::~BugServerConfig()
+{
+}
+
+void BugServerConfig::setName( const QString &name )
+{
+ mName = name;
+}
+
+QString BugServerConfig::name() const
+{
+ return mName;
+}
+
+void BugServerConfig::setBaseUrl( const KURL &baseUrl )
+{
+ mBaseUrl = baseUrl;
+}
+
+KURL BugServerConfig::baseUrl() const
+{
+ return mBaseUrl;
+}
+
+void BugServerConfig::setUser( const QString &user )
+{
+ mUser = user;
+}
+
+QString BugServerConfig::user() const
+{
+ return mUser;
+}
+
+void BugServerConfig::setPassword( const QString &password )
+{
+ mPassword = password;
+}
+
+QString BugServerConfig::password() const
+{
+ return mPassword;
+}
+
+void BugServerConfig::setBugzillaVersion( const QString &s )
+{
+ mBugzillaVersion = s;
+}
+
+QString BugServerConfig::bugzillaVersion() const
+{
+ return mBugzillaVersion;
+}
+
+QStringList BugServerConfig::bugzillaVersions()
+{
+ QStringList v;
+
+ v << "2.10";
+ v << "2.14.2";
+ v << "2.16.2";
+ v << "2.17.1";
+ v << "KDE";
+ v << "Bugworld";
+
+ return v;
+}
+
+void BugServerConfig::readConfig( KConfig *cfg, const QString &name )
+{
+ mName = name;
+
+ cfg->setGroup( "BugServer " + name );
+
+ mBaseUrl = cfg->readEntry( "BaseUrl" );
+ mUser = cfg->readEntry( "User" );
+ mPassword = cfg->readEntry( "Password" );
+
+ mBugzillaVersion = cfg->readEntry( "BugzillaVersion", "KDE" );
+
+ mRecentPackages = cfg->readListEntry( "RecentPackages" );
+ mCurrentPackage = cfg->readEntry( "CurrentPackage" );
+ mCurrentComponent = cfg->readEntry( "CurrentComponent" );
+ mCurrentBug = cfg->readEntry( "CurrentBug" );
+}
+
+void BugServerConfig::writeConfig( KConfig *cfg )
+{
+ cfg->setGroup( "BugServer " + mName );
+
+ cfg->writeEntry( "BaseUrl", mBaseUrl.url() );
+ cfg->writeEntry( "User", mUser );
+ cfg->writeEntry( "Password", mPassword );
+
+ cfg->writeEntry( "BugzillaVersion", mBugzillaVersion );
+
+ cfg->writeEntry( "RecentPackages", mRecentPackages );
+ cfg->writeEntry( "CurrentPackage", mCurrentPackage );
+ cfg->writeEntry( "CurrentComponent", mCurrentComponent );
+ cfg->writeEntry( "CurrentBug", mCurrentBug );
+}
+
+
+/*
+ * vim:sw=4:ts=4:et
+ */
diff --git a/kbugbuster/backend/bugserverconfig.h b/kbugbuster/backend/bugserverconfig.h
new file mode 100644
index 00000000..2c9be828
--- /dev/null
+++ b/kbugbuster/backend/bugserverconfig.h
@@ -0,0 +1,91 @@
+/*
+ This file is part of KBugBuster.
+
+ Copyright (c) 2003 Cornelius Schumacher <schumacher@kde.org>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the 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, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+ As a special exception, permission is given to link this program
+ with any edition of Qt, and distribute the resulting executable,
+ without including the source code for Qt in the source distribution.
+*/
+#ifndef BUGSERVERCONFIG_H
+#define BUGSERVERCONFIG_H
+
+#include <qstring.h>
+#include <qstringlist.h>
+
+#include <kurl.h>
+
+class KConfig;
+
+class BugServerConfig
+{
+ public:
+ BugServerConfig();
+ BugServerConfig( const QString &name, const KURL &baseUrl );
+ ~BugServerConfig();
+
+ void setName( const QString &name );
+ QString name() const;
+
+ void setBaseUrl( const KURL &url );
+ KURL baseUrl() const;
+
+ void setUser( const QString &user );
+ QString user() const;
+
+ void setPassword( const QString &password );
+ QString password() const;
+
+ void readConfig( KConfig *, const QString &name );
+ void writeConfig( KConfig * );
+
+ static QStringList bugzillaVersions();
+
+ void setBugzillaVersion( const QString & );
+ QString bugzillaVersion() const;
+
+ void setRecentPackages( const QStringList &v ) { mRecentPackages = v; }
+ QStringList recentPackages() const { return mRecentPackages; }
+
+ void setCurrentPackage( const QString &v ) { mCurrentPackage = v; }
+ QString currentPackage() const { return mCurrentPackage; }
+
+ void setCurrentComponent( const QString &v ) { mCurrentComponent = v; }
+ QString currentComponent() const { return mCurrentComponent; }
+
+ void setCurrentBug( const QString &v ) { mCurrentBug = v; }
+ QString currentBug() const { return mCurrentBug; }
+
+ private:
+ QString mName;
+ KURL mBaseUrl;
+ QString mUser;
+ QString mPassword;
+
+ QString mBugzillaVersion;
+
+ QStringList mRecentPackages;
+ QString mCurrentPackage;
+ QString mCurrentComponent;
+ QString mCurrentBug;
+};
+
+#endif
+
+/*
+ * vim:sw=4:ts=4:et
+ */
diff --git a/kbugbuster/backend/bugsystem.cpp b/kbugbuster/backend/bugsystem.cpp
new file mode 100644
index 00000000..26432e08
--- /dev/null
+++ b/kbugbuster/backend/bugsystem.cpp
@@ -0,0 +1,436 @@
+
+#include "bugsystem.h"
+#include "packagelistjob.h"
+#include "buglistjob.h"
+#include "bugmybugsjob.h"
+#include "bugdetailsjob.h"
+#include "bugcommand.h"
+
+#include <kstaticdeleter.h>
+#include <kdebug.h>
+#include <klocale.h>
+#include <kemailsettings.h>
+#include <kstandarddirs.h>
+#include <ksimpleconfig.h>
+#include <kconfig.h>
+
+#include "packageimpl.h"
+#include "bugimpl.h"
+#include "bugdetailsimpl.h"
+#include "mailsender.h"
+#include "kbbprefs.h"
+#include "bugserver.h"
+#include "bugserverconfig.h"
+#include "bugcache.h"
+
+KStaticDeleter<BugSystem> bssd;
+
+BugSystem *BugSystem::s_self = 0;
+
+QString BugSystem::mLastResponse;
+
+BugSystem *BugSystem::self()
+{
+ if ( !s_self )
+ s_self = bssd.setObject( s_self, new BugSystem );
+
+ return s_self;
+}
+
+BugSystem::BugSystem()
+ : m_disconnected( false )
+{
+ mServer = 0;
+}
+
+BugSystem::~BugSystem()
+{
+ QValueList<BugServer *>::ConstIterator it;
+ for( it = mServerList.begin(); it != mServerList.end(); ++it ) {
+ delete *it;
+ }
+}
+
+BugCache *BugSystem::cache()const
+{
+ return mServer->cache();
+}
+
+void BugSystem::setDisconnected( bool disconnected )
+{
+ m_disconnected = disconnected;
+}
+
+bool BugSystem::disconnected() const
+{
+ return m_disconnected;
+}
+
+void BugSystem::retrievePackageList()
+{
+ mServer->setPackages( mServer->cache()->loadPackageList() );
+
+ if( !mServer->packages().isEmpty() ) {
+ emit packageListAvailable( mServer->packages() );
+ } else {
+ emit packageListCacheMiss();
+
+ if ( !m_disconnected )
+ {
+ emit packageListLoading();
+
+ PackageListJob *job = new PackageListJob( mServer );
+ connect( job, SIGNAL( packageListAvailable( const Package::List & ) ),
+ this, SIGNAL( packageListAvailable( const Package::List & ) ) );
+ connect( job, SIGNAL( packageListAvailable( const Package::List & ) ),
+ this, SLOT( setPackageList( const Package::List & ) ) );
+ connect( job, SIGNAL( error( const QString & ) ),
+ this, SIGNAL( loadingError( const QString & ) ) );
+ connectJob( job );
+
+ registerJob( job );
+
+ job->start();
+ }
+ }
+}
+
+void BugSystem::retrieveBugList( const Package &pkg, const QString &component )
+{
+ kdDebug() << "BugSystem::retrieveBugList(): " << pkg.name() << endl;
+
+ if ( pkg.isNull() )
+ return;
+
+ mServer->setBugs( pkg, component,
+ mServer->cache()->loadBugList( pkg, component,
+ m_disconnected ) );
+
+ // Since the GUI stops showing the splash widget after this signal,
+ // we should not emit anything on a cache miss...
+ if( !mServer->bugs( pkg, component ).isEmpty() )
+ emit bugListAvailable( pkg, component, mServer->bugs( pkg, component ) );
+ else
+ {
+ emit bugListCacheMiss( pkg );
+
+ if ( !m_disconnected )
+ {
+ kdDebug() << "BugSystem::retrieveBugList() starting job" << endl;
+ emit bugListLoading( pkg, component );
+
+ BugListJob *job = new BugListJob( mServer );
+ connect( job, SIGNAL( bugListAvailable( const Package &, const QString &, const Bug::List & ) ),
+ this, SIGNAL( bugListAvailable( const Package &, const QString &, const Bug::List & ) ) );
+ connect( job, SIGNAL( bugListAvailable( const Package &, const QString &, const Bug::List & ) ),
+ this, SLOT( setBugList( const Package &, const QString &, const Bug::List & ) ) );
+ connect( job, SIGNAL( error( const QString & ) ),
+ this, SIGNAL( loadingError( const QString & ) ) );
+ connectJob( job );
+
+ registerJob( job );
+
+ job->start( pkg, component );
+ }
+ }
+}
+
+void BugSystem::retrieveMyBugsList()
+{
+ kdDebug() << k_funcinfo << endl;
+
+ if ( m_disconnected )
+ {
+ // This function is not cached for now
+ emit bugListCacheMiss( i18n( "My Bugs" ) );
+ }
+ else
+ {
+ kdDebug() << k_funcinfo << "Starting job" << endl;
+
+ emit bugListLoading( i18n( "Retrieving My Bugs list..." ) );
+
+ BugMyBugsJob *job = new BugMyBugsJob( mServer );
+
+ connect( job, SIGNAL( bugListAvailable( const QString &, const Bug::List & ) ),
+ this, SIGNAL( bugListAvailable( const QString &, const Bug::List & ) ) );
+ connect( job, SIGNAL( error( const QString & ) ),
+ this, SIGNAL( loadingError( const QString & ) ) );
+ connectJob( job );
+
+ registerJob( job );
+
+ job->start();
+ }
+}
+
+void BugSystem::retrieveBugDetails( const Bug &bug )
+{
+ if ( bug.isNull() )
+ return;
+
+ kdDebug() << "BugSystem::retrieveBugDetails(): " << bug.number() << endl;
+
+ mServer->setBugDetails( bug, mServer->cache()->loadBugDetails( bug ) );
+
+ if ( !mServer->bugDetails( bug ).isNull() ) {
+// kdDebug() << "Found in cache." << endl;
+ emit bugDetailsAvailable( bug, mServer->bugDetails( bug ) );
+ } else {
+// kdDebug() << "Not found in cache." << endl;
+ emit bugDetailsCacheMiss( bug );
+
+ if ( !m_disconnected ) {
+ emit bugDetailsLoading( bug );
+
+ BugDetailsJob *job = new BugDetailsJob( mServer );
+ connect( job, SIGNAL( bugDetailsAvailable( const Bug &, const BugDetails & ) ),
+ this, SIGNAL( bugDetailsAvailable( const Bug &, const BugDetails & ) ) );
+ connect( job, SIGNAL( bugDetailsAvailable( const Bug &, const BugDetails & ) ),
+ this, SLOT( setBugDetails( const Bug &, const BugDetails & ) ) );
+ connect( job, SIGNAL( error( const QString & ) ),
+ this, SIGNAL( bugDetailsLoadingError() ) );
+ connectJob( job );
+
+ registerJob( job );
+
+ job->start( bug );
+ }
+ }
+}
+
+void BugSystem::connectJob( BugJob *job )
+{
+ connect( job, SIGNAL( infoMessage( const QString & ) ),
+ this, SIGNAL( infoMessage( const QString & ) ) );
+ connect( job, SIGNAL( infoPercent( unsigned long ) ),
+ this, SIGNAL( infoPercent( unsigned long ) ) );
+ connect( job, SIGNAL( jobEnded( BugJob * ) ),
+ SLOT( unregisterJob( BugJob * ) ) );
+}
+
+void BugSystem::setPackageList( const Package::List &pkgs )
+{
+ mServer->setPackages( pkgs );
+
+ mServer->cache()->savePackageList( pkgs );
+}
+
+void BugSystem::setBugList( const Package &pkg, const QString &component, const Bug::List &bugs )
+{
+ mServer->setBugs( pkg, component, bugs );
+ mServer->cache()->saveBugList( pkg, component, bugs );
+}
+
+void BugSystem::setBugDetails( const Bug &bug, const BugDetails &details )
+{
+ mServer->setBugDetails( bug , details );
+
+ mServer->cache()->saveBugDetails( bug, details );
+}
+
+Package::List BugSystem::packageList() const
+{
+ return mServer->packages();
+}
+
+Package BugSystem::package( const QString &pkgname ) const
+{
+ Package::List::ConstIterator it;
+ for( it = mServer->packages().begin(); it != mServer->packages().end(); ++it ) {
+ if( pkgname == (*it).name() ) return (*it);
+ }
+ return Package();
+}
+
+Bug BugSystem::bug( const Package &pkg, const QString &component, const QString &number ) const
+{
+ Bug::List bugs = mServer->bugs( pkg, component );
+
+ Bug::List::ConstIterator it;
+ for( it = bugs.begin(); it != bugs.end(); ++it ) {
+ if( number == (*it).number() ) return (*it);
+ }
+ return Bug();
+}
+
+void BugSystem::queueCommand( BugCommand *cmd )
+{
+ if ( mServer->queueCommand( cmd ) ) emit commandQueued( cmd );
+}
+
+void BugSystem::clearCommands( const QString &bug )
+{
+ mServer->clearCommands( bug );
+
+ emit commandCanceled( bug );
+}
+
+void BugSystem::clearCommands()
+{
+ QStringList bugs = mServer->bugsWithCommands();
+
+ QStringList::ConstIterator it;
+ for( it = bugs.begin(); it != bugs.end(); ++it ) {
+ clearCommands( *it );
+ }
+}
+
+void BugSystem::sendCommands()
+{
+ QString recipient = KBBPrefs::instance()->mOverrideRecipient;
+ bool sendBCC = KBBPrefs::instance()->mSendBCC;
+
+ KEMailSettings emailSettings;
+ QString senderName = emailSettings.getSetting( KEMailSettings::RealName );
+ QString senderEmail = emailSettings.getSetting( KEMailSettings::EmailAddress );
+ QString smtpServer = emailSettings.getSetting( KEMailSettings::OutServer );
+
+ MailSender::MailClient client = (MailSender::MailClient)KBBPrefs::instance()->mMailClient;
+
+ // ### connect to signals
+ MailSender *mailer = new MailSender( client, smtpServer );
+ connect( mailer, SIGNAL( status( const QString & ) ),
+ SIGNAL( infoMessage( const QString & ) ) );
+
+ mServer->sendCommands( mailer, senderName, senderEmail, sendBCC, recipient );
+}
+
+void BugSystem::setServerList( const QValueList<BugServerConfig> &servers )
+{
+ if ( servers.isEmpty() ) return;
+
+ QString currentServer;
+ if ( mServer ) currentServer = mServer->serverConfig().name();
+ else currentServer = KBBPrefs::instance()->mCurrentServer;
+
+ killAllJobs();
+
+ QValueList<BugServer *>::ConstIterator serverIt;
+ for( serverIt = mServerList.begin(); serverIt != mServerList.end();
+ ++serverIt ) {
+ delete *serverIt;
+ }
+ mServerList.clear();
+
+ QValueList<BugServerConfig>::ConstIterator cfgIt;
+ for( cfgIt = servers.begin(); cfgIt != servers.end(); ++cfgIt ) {
+ mServerList.append( new BugServer( *cfgIt ) );
+ }
+
+ setCurrentServer( currentServer );
+}
+
+QValueList<BugServer *> BugSystem::serverList()
+{
+ return mServerList;
+}
+
+void BugSystem::setCurrentServer( const QString &name )
+{
+ killAllJobs();
+
+ BugServer *server = findServer( name );
+ if ( server ) {
+ mServer = server;
+ } else {
+ kdError() << "Server '" << name << "' not known." << endl;
+ if ( mServerList.isEmpty() ) {
+ kdError() << "Fatal error: server list empty." << endl;
+ } else {
+ mServer = mServerList.first();
+ }
+ }
+
+ if ( mServer ) {
+ KBBPrefs::instance()->mCurrentServer = mServer->serverConfig().name();
+ }
+}
+
+BugServer *BugSystem::findServer( const QString &name )
+{
+ QValueList<BugServer *>::ConstIterator serverIt;
+ for( serverIt = mServerList.begin(); serverIt != mServerList.end();
+ ++serverIt ) {
+ if ( (*serverIt)->serverConfig().name() == name ) return *serverIt;
+ }
+ return 0;
+}
+
+void BugSystem::saveQuery( const KURL &url )
+{
+ mLastResponse = "Query: " + url.url();
+ mLastResponse += "\n\n";
+}
+
+void BugSystem::saveResponse( const QByteArray &response )
+{
+ mLastResponse += response;
+}
+
+QString BugSystem::lastResponse()
+{
+ return mLastResponse;
+}
+
+void BugSystem::readConfig( KConfig *config )
+{
+ config->setGroup("Servers");
+ QStringList servers = config->readListEntry( "Servers" );
+
+ QValueList<BugServerConfig> serverList;
+
+ if ( servers.isEmpty() ) {
+ serverList.append( BugServerConfig() );
+ } else {
+ QStringList::ConstIterator it;
+ for( it = servers.begin(); it != servers.end(); ++it ) {
+ BugServerConfig cfg;
+ cfg.readConfig( config, *it );
+ serverList.append( cfg );
+ }
+ }
+
+ setServerList( serverList );
+}
+
+void BugSystem::writeConfig( KConfig *config )
+{
+ QValueList<BugServer *>::ConstIterator itServer;
+ QStringList servers;
+ QValueList<BugServer *> serverList = BugSystem::self()->serverList();
+ for( itServer = serverList.begin(); itServer != serverList.end();
+ ++itServer ) {
+ BugServerConfig serverConfig = (*itServer)->serverConfig();
+ servers.append( serverConfig.name() );
+ serverConfig.writeConfig( config );
+ }
+
+ config->setGroup("Servers");
+ config->writeEntry( "Servers", servers );
+}
+
+void BugSystem::registerJob( BugJob *job )
+{
+ mJobs.append( job );
+}
+
+void BugSystem::unregisterJob( BugJob *job )
+{
+ mJobs.removeRef( job );
+}
+
+void BugSystem::killAllJobs()
+{
+ BugJob *job;
+ for( job = mJobs.first(); job; job = mJobs.next() ) {
+ job->kill();
+ unregisterJob( job );
+ }
+}
+
+#include "bugsystem.moc"
+
+/*
+ * vim:sw=4:ts=4:et
+ */
diff --git a/kbugbuster/backend/bugsystem.h b/kbugbuster/backend/bugsystem.h
new file mode 100644
index 00000000..c573698b
--- /dev/null
+++ b/kbugbuster/backend/bugsystem.h
@@ -0,0 +1,146 @@
+#ifndef __bugsystem_h__
+#define __bugsystem_h__
+
+#include "package.h"
+#include "bug.h"
+#include "bugdetails.h"
+#include "bugcache.h"
+
+#include <kurl.h>
+
+#include <qobject.h>
+#include <qptrlist.h>
+#include <qmap.h>
+#include <qpair.h>
+
+class KConfig;
+
+class BugCommand;
+class BugServer;
+class BugServerConfig;
+class BugJob;
+
+class BugSystem : public QObject
+{
+ Q_OBJECT
+ friend class BugJob;
+ public:
+ BugSystem();
+ virtual ~BugSystem();
+
+ static BugSystem *self();
+
+ BugCache *cache()const;
+ BugServer *server() const { return mServer; }
+
+ /**
+ BugSystem takes ownership of the BugServerConfig objects.
+ */
+ void setServerList( const QValueList<BugServerConfig> &servers );
+ QValueList<BugServer *> serverList();
+
+ void setCurrentServer( const QString & );
+
+ void retrievePackageList();
+ void retrieveBugList( const Package &, const QString &component );
+ void retrieveBugDetails( const Bug & );
+
+ /**
+ * Load the bugs the user reported himself, or for which he is the assigned to person
+ */
+ void retrieveMyBugsList();
+
+ /**
+ Queue a new command.
+ */
+ void queueCommand( BugCommand * );
+ /**
+ Forget all commands for a given bug.
+ */
+ void clearCommands( const QString &bug );
+ /**
+ Forget all commands for all bugs.
+ */
+ void clearCommands();
+ /**
+ Send all commands (generate the mails).
+ */
+ void sendCommands();
+
+ void setDisconnected( bool );
+ bool disconnected() const;
+
+ Package::List packageList() const;
+
+ Package package( const QString &pkgname ) const;
+ Bug bug( const Package &pkg, const QString &component, const QString &number ) const;
+
+ static void saveQuery( const KURL &url );
+ static void saveResponse( const QByteArray &d );
+ static QString lastResponse();
+
+ void readConfig( KConfig * );
+ void writeConfig( KConfig * );
+
+ signals:
+ void packageListAvailable( const Package::List &pkgs );
+ void bugListAvailable( const Package &pkg, const QString &component, const Bug::List & );
+ void bugListAvailable( const QString &label, const Bug::List & );
+ void bugDetailsAvailable( const Bug &, const BugDetails & );
+
+ void packageListLoading();
+ void bugListLoading( const Package &, const QString &component );
+ void bugListLoading( const QString &label );
+ void bugDetailsLoading( const Bug & );
+
+ void packageListCacheMiss();
+ void bugListCacheMiss( const Package &package );
+ void bugListCacheMiss( const QString &label );
+ void bugDetailsCacheMiss( const Bug & );
+
+ void bugDetailsLoadingError();
+
+ void infoMessage( const QString &message );
+ void infoPercent( unsigned long percent );
+
+ void commandQueued( BugCommand * );
+ void commandCanceled( const QString & );
+
+ void loadingError( const QString &text );
+
+ protected:
+ BugServer *findServer( const QString &name );
+
+ void registerJob( BugJob * );
+
+ void connectJob( BugJob * );
+
+ void killAllJobs();
+
+ protected slots:
+ void unregisterJob( BugJob * );
+
+ private slots:
+ void setPackageList( const Package::List &pkgs );
+ void setBugList( const Package &pkg, const QString &component, const Bug::List &bugs );
+ void setBugDetails( const Bug &bug, const BugDetails &details );
+
+ private:
+ bool m_disconnected;
+
+ BugServer *mServer;
+
+ QValueList<BugServer *> mServerList;
+
+ QPtrList<BugJob> mJobs;
+
+ static BugSystem *s_self;
+
+ static QString mLastResponse;
+};
+
+#endif
+
+/*
+ * vim:sw=4:ts=4:et
+ */
diff --git a/kbugbuster/backend/domprocessor.cpp b/kbugbuster/backend/domprocessor.cpp
new file mode 100644
index 00000000..7643ca11
--- /dev/null
+++ b/kbugbuster/backend/domprocessor.cpp
@@ -0,0 +1,407 @@
+/*
+ This file is part of KBugBuster.
+ Copyright (c) 2002 Cornelius Schumacher <schumacher@kde.org>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the 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, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+ As a special exception, permission is given to link this program
+ with any edition of Qt, and distribute the resulting executable,
+ without including the source code for Qt in the source distribution.
+*/
+
+#include "domprocessor.h"
+
+#include <qregexp.h>
+#include <qstylesheet.h>
+
+#include <kdebug.h>
+#include <kmdcodec.h>
+
+#include "bugserver.h"
+#include "packageimpl.h"
+#include "bugimpl.h"
+#include "bugdetailsimpl.h"
+#include "kbbprefs.h"
+
+DomProcessor::DomProcessor( BugServer *server )
+ : Processor( server )
+{
+}
+
+DomProcessor::~DomProcessor()
+{
+}
+
+KBB::Error DomProcessor::parsePackageList( const QByteArray &data,
+ Package::List &packages )
+{
+ QDomDocument doc;
+ if ( !doc.setContent( data ) ) {
+ return KBB::Error( "Error parsing xml response for package list request." );
+ }
+
+ QDomElement bugzilla = doc.documentElement();
+
+ if ( bugzilla.isNull() ) {
+ return KBB::Error( "No document in xml response." );
+ }
+
+ KBB::Error err = parseDomPackageList( bugzilla, packages );
+
+ return err;
+}
+
+KBB::Error DomProcessor::parseBugList( const QByteArray &data, Bug::List &bugs )
+{
+ QDomDocument doc;
+ if ( !doc.setContent( data ) ) {
+ return KBB::Error( "Error parsing xml response for bug list request" );
+ }
+
+ QDomElement bugzilla = doc.documentElement();
+
+ if ( bugzilla.isNull() ) {
+ return KBB::Error( "No document in xml response." );
+ }
+
+ KBB::Error err = parseDomBugList( bugzilla, bugs );
+
+ return err;
+}
+
+KBB::Error DomProcessor::parseBugDetails( const QByteArray &data,
+ BugDetails &bugDetails )
+{
+ QDomDocument doc;
+ if ( !doc.setContent( data ) ) {
+ return KBB::Error( "Error parsing xml response for bug details request." );
+ }
+
+ QDomElement bugzilla = doc.documentElement();
+
+ if ( bugzilla.isNull() ) {
+ return KBB::Error( "No document in xml response." );
+ }
+
+ QDomNode p;
+ for ( p = bugzilla.firstChild(); !p.isNull(); p = p.nextSibling() ) {
+ QDomElement bug = p.toElement();
+ if ( bug.tagName() != "bug" ) continue;
+
+ KBB::Error err = parseDomBugDetails( bug, bugDetails );
+
+ if ( err ) return err;
+ }
+
+ return KBB::Error();
+}
+
+
+KBB::Error DomProcessor::parseDomPackageList( const QDomElement &element,
+ Package::List &packages )
+{
+ QDomNode p;
+ for ( p = element.firstChild(); !p.isNull(); p = p.nextSibling() ) {
+ QDomElement bug = p.toElement();
+
+ if ( bug.tagName() != "product" ) continue;
+
+ QString pkgName = bug.attribute( "name" );
+ uint bugCount = 999;
+ Person maintainer;
+ QString description;
+ QStringList components;
+
+ QDomNode n;
+ for( n = bug.firstChild(); !n.isNull(); n = n.nextSibling() ) {
+ QDomElement e = n.toElement();
+ if ( e.tagName() == "descr" ) description= e.text().stripWhiteSpace();
+ if ( e.tagName() == "component" ) components += e.text().stripWhiteSpace();
+ }
+
+ Package pkg( new PackageImpl( pkgName, description, bugCount, maintainer, components ) );
+
+ if ( !pkg.isNull() ) {
+ packages.append( pkg );
+ }
+ }
+
+ return KBB::Error();
+}
+
+KBB::Error DomProcessor::parseDomBugList( const QDomElement &topElement,
+ Bug::List &bugs )
+{
+ QDomElement element;
+
+ if ( topElement.tagName() != "querybugids" ) {
+ QDomNode buglist = topElement.namedItem( "querybugids" );
+ element = buglist.toElement();
+ if ( element.isNull() ) {
+ return KBB::Error( "No querybugids element found." );
+ }
+ } else {
+ element = topElement;
+ }
+
+ QDomNode p;
+ for ( p = element.firstChild(); !p.isNull(); p = p.nextSibling() ) {
+ QDomElement hit = p.toElement();
+
+ kdDebug() << "DomProcessor::parseDomBugList(): tag: " << hit.tagName() << endl;
+
+ if ( hit.tagName() == "error" ) {
+ return KBB::Error( "Error: " + hit.text() );
+ } else if ( hit.tagName() != "hit" ) continue;
+
+ QString title;
+ QString submitterName;
+ QString submitterEmail;
+ QString bugNr;
+ Bug::Status status = Bug::StatusUndefined;
+ Bug::Severity severity = Bug::SeverityUndefined;
+ Person developerTodo;
+ Bug::BugMergeList mergedList;
+ uint age = 0xFFFFFFFF;
+
+ QDomNode n;
+ for ( n = hit.firstChild(); !n.isNull(); n = n.nextSibling() )
+ {
+ QDomElement e = n.toElement();
+
+ if ( e.tagName() == "bugid" )
+ bugNr = e.text();
+ else if ( e.tagName() == "status" )
+ status = server()->bugStatus( e.text() );
+ else if ( e.tagName() == "descr" )
+ title = e.text();
+ else if ( e.tagName() == "reporter" )
+ submitterEmail = e.text();
+ else if ( e.tagName() == "reporterName" )
+ submitterName = e.text();
+ else if ( e.tagName() == "severity" )
+ severity = Bug::stringToSeverity( e.text() );
+ else if ( e.tagName() == "creationdate" )
+ age = ( QDateTime::fromString( e.text(), Qt::ISODate ) ).daysTo( QDateTime::currentDateTime() );
+ }
+
+ Person submitter( submitterName, submitterEmail );
+
+ Bug bug( new BugImpl( title, submitter, bugNr, age, severity,
+ developerTodo, status, mergedList ) );
+
+ if ( !bug.isNull() ) {
+ bugs.append( bug );
+ }
+ }
+
+ return KBB::Error();
+}
+
+KBB::Error DomProcessor::parseDomBugDetails( const QDomElement &element,
+ BugDetails &bugDetails )
+{
+ if ( element.tagName() != "bug" ) return KBB::Error( "No <bug> tag found" );
+
+ BugDetailsPart::List parts;
+ QValueList<BugDetailsImpl::AttachmentDetails> attachments;
+
+ QString versionXml;
+ QString osXml;
+
+ QString version;
+ QString source;
+ QString compiler;
+ QString os;
+
+ QDomNode n;
+ for( n = element.firstChild(); !n.isNull(); n = n.nextSibling() ) {
+ QDomElement e = n.toElement();
+ if ( e.tagName() == "version" ) versionXml = e.text().stripWhiteSpace();
+ if ( e.tagName() == "op_sys" ) osXml = e.text().stripWhiteSpace();
+
+ if ( e.tagName() == "long_desc" ) {
+
+ QString encoding = e.attribute( "encoding" );
+
+ Person sender;
+ QDateTime date;
+ QString text;
+
+ QDomNode n2;
+ for( n2 = e.firstChild(); !n2.isNull(); n2 = n2.nextSibling() ) {
+ QDomElement e2 = n2.toElement();
+ if ( e2.tagName() == "who" ) {
+ sender = Person::parseFromString( e2.text() );
+ } else if ( e2.tagName() == "bug_when" ) {
+ date = parseDate( e2.text().stripWhiteSpace() );
+ } else if ( e2.tagName() == "thetext" ) {
+ QString in;
+ if ( encoding == "base64" ) {
+ in = KCodecs::base64Decode( e2.text().latin1() );
+ } else {
+ in = e2.text();
+ }
+
+ QString raw = QStyleSheet::escape( in );
+
+ if ( parts.isEmpty() )
+ {
+ QTextStream ts( &raw, IO_ReadOnly );
+ QString line;
+ while( !( line = ts.readLine() ).isNull() ) {
+ if ( parseAttributeLine( line, "Version", version ) ) continue;
+ if ( parseAttributeLine( line, "Installed from", source ) ) continue;
+ if ( parseAttributeLine( line, "Compiler", compiler ) ) continue;
+ if ( parseAttributeLine( line, "OS", os ) ) continue;
+
+ text += line + "\n";
+ }
+ } else {
+ text += raw;
+ }
+ QString bugBaseURL = server()->serverConfig().baseUrl().htmlURL();
+ text = "<pre>" + wrapLines( text ).replace( QRegExp( "(Created an attachment \\(id=([0-9]+)\\))" ),
+ "<a href=\"" + bugBaseURL + "/attachment.cgi?id=\\2&action=view\">\\1</a>" ) + "\n</pre>";
+ }
+ }
+
+ parts.prepend( BugDetailsPart( sender, date, text ) );
+ }
+
+ if ( e.tagName() == "attachment" ) {
+ QString attachid, date, desc;
+ for( QDomNode node = e.firstChild(); !node.isNull(); node = node.nextSibling() ) {
+ QDomElement e2 = node.toElement();
+ if ( e2.tagName() == "attachid" ) {
+ attachid = e2.text();
+ } else if ( e2.tagName() == "date" ) {
+ date = e2.text().stripWhiteSpace();
+ } else if ( e2.tagName() == "desc" ) {
+ desc = "<pre>" + wrapLines( QStyleSheet::escape(e2.text()) ) + "\n</pre>";
+ }
+ }
+ attachments.append( BugDetailsImpl::AttachmentDetails( desc, date, attachid ) );
+ }
+ }
+
+ if ( version.isEmpty() ) version = versionXml;
+ if ( os.isEmpty() ) os = osXml;
+
+ bugDetails = BugDetails( new BugDetailsImpl( version, source, compiler, os,
+ parts ) );
+ bugDetails.addAttachmentDetails( attachments );
+
+ return KBB::Error();
+}
+
+void DomProcessor::setPackageListQuery( KURL &url )
+{
+ url.setFileName( "xml.cgi" );
+ url.setQuery( "?data=versiontable" );
+}
+
+void DomProcessor::setBugListQuery( KURL &url, const Package &product, const QString &component )
+{
+ if ( server()->serverConfig().bugzillaVersion() == "Bugworld" ) {
+ url.setFileName( "bugworld.cgi" );
+ } else {
+ url.setFileName( "xmlquery.cgi" );
+ }
+
+ QString user = server()->serverConfig().user();
+
+ if ( component.isEmpty() )
+ url.setQuery( "?user=" + user + "&product=" + product.name() );
+ else
+ url.setQuery( "?user=" + user + "&product=" + product.name() + "&component=" + component );
+
+ if ( KBBPrefs::instance()->mShowClosedBugs )
+ url.addQueryItem( "addClosed", "1" );
+}
+
+void DomProcessor::setBugDetailsQuery( KURL &url, const Bug &bug )
+{
+ url.setFileName( "xml.cgi" );
+ url.setQuery( "?id=" + bug.number() );
+}
+
+QString DomProcessor::wrapLines( const QString &text )
+{
+ int wrap = KBBPrefs::instance()->mWrapColumn;
+
+ QStringList lines = QStringList::split( '\n', text, true );
+ //kdDebug() << lines.count() << " lines." << endl;
+
+ QString out;
+ bool removeBlankLines = true;
+ for ( QStringList::Iterator it = lines.begin() ; it != lines.end() ; ++it )
+ {
+ QString line = *it;
+
+ if ( removeBlankLines ) {
+ if ( line.isEmpty() ) continue;
+ else removeBlankLines = false;
+ }
+
+ //kdDebug() << "BugDetailsJob::processNode IN line='" << line << "'" << endl;
+
+ QString wrappedLine;
+ while ( line.length() > uint( wrap ) )
+ {
+ int breakPoint = line.findRev( ' ', wrap );
+ //kdDebug() << "Breaking at " << breakPoint << endl;
+ if( breakPoint == -1 ) {
+ wrappedLine += line.left( wrap ) + '\n';
+ line = line.mid( wrap );
+ } else {
+ wrappedLine += line.left( breakPoint ) + '\n';
+ line = line.mid( breakPoint + 1 );
+ }
+ }
+ wrappedLine += line; // the remainder
+ //kdDebug() << "BugDetailsJob::processNode OUT wrappedLine='" << wrappedLine << "'" << endl;
+
+ out += wrappedLine + "\n";
+ }
+
+ return out;
+}
+
+bool DomProcessor::parseAttributeLine( const QString &line, const QString &key,
+ QString &result )
+{
+ if ( !result.isEmpty() ) return false;
+
+ if ( !line.startsWith( key + ":" ) ) return false;
+
+ QString value = line.mid( key.length() + 1 );
+ value = value.stripWhiteSpace();
+
+ result = value;
+
+ return true;
+}
+
+QDateTime DomProcessor::parseDate( const QString &dateStr )
+{
+ QDateTime date = QDateTime::fromString( dateStr, Qt::ISODate );
+
+ return date;
+}
+
+/*
+ * vim:sw=4:ts=4:et
+ */
diff --git a/kbugbuster/backend/domprocessor.h b/kbugbuster/backend/domprocessor.h
new file mode 100644
index 00000000..1553ae4a
--- /dev/null
+++ b/kbugbuster/backend/domprocessor.h
@@ -0,0 +1,69 @@
+/*
+ This file is part of KBugBuster.
+ Copyright (c) 2002 Cornelius Schumacher <schumacher@kde.org>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the 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, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+ As a special exception, permission is given to link this program
+ with any edition of Qt, and distribute the resulting executable,
+ without including the source code for Qt in the source distribution.
+*/
+#ifndef DOMPROCESSOR_H
+#define DOMPROCESSOR_H
+
+#include "bug.h"
+#include "bugdetails.h"
+#include "package.h"
+#include "error.h"
+#include "processor.h"
+
+#include <kurl.h>
+
+#include <qdom.h>
+
+class BugServer;
+
+class DomProcessor : public Processor
+{
+ public:
+ DomProcessor( BugServer * );
+ virtual ~DomProcessor();
+
+ KBB::Error parsePackageList( const QByteArray &data,
+ Package::List &packages );
+ KBB::Error parseBugList( const QByteArray &data, Bug::List &bugs );
+ KBB::Error parseBugDetails( const QByteArray &, BugDetails & );
+
+ void setPackageListQuery( KURL & );
+ void setBugListQuery( KURL &, const Package &, const QString &component );
+ void setBugDetailsQuery( KURL &, const Bug & );
+
+ protected:
+ virtual KBB::Error parseDomPackageList( const QDomElement &,
+ Package::List & );
+ virtual KBB::Error parseDomBugList( const QDomElement &, Bug::List & );
+ virtual KBB::Error parseDomBugDetails( const QDomElement &, BugDetails & );
+
+ QString wrapLines( const QString & );
+ bool parseAttributeLine( const QString &line, const QString &key,
+ QString &result );
+ QDateTime parseDate( const QString & );
+};
+
+#endif
+
+/*
+ * vim:sw=4:ts=4:et
+ */
diff --git a/kbugbuster/backend/error.h b/kbugbuster/backend/error.h
new file mode 100644
index 00000000..e12bcf61
--- /dev/null
+++ b/kbugbuster/backend/error.h
@@ -0,0 +1,43 @@
+/*
+ This file is part of KBugBuster.
+ Copyright (c) 2003 Cornelius Schumacher <schumacher@kde.org>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the 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, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+ As a special exception, permission is given to link this program
+ with any edition of Qt, and distribute the resulting executable,
+ without including the source code for Qt in the source distribution.
+*/
+#ifndef KBB_ERROR_H
+#define KBB_ERROR_H
+
+namespace KBB {
+
+class Error
+{
+ public:
+ Error( const QString &msg = QString::null ) : mMsg( msg ) {}
+
+ operator bool() { return !mMsg.isEmpty(); }
+
+ QString message() const { return mMsg; }
+
+ private:
+ QString mMsg;
+};
+
+}
+
+#endif
diff --git a/kbugbuster/backend/htmlparser.cpp b/kbugbuster/backend/htmlparser.cpp
new file mode 100644
index 00000000..7e53c1bd
--- /dev/null
+++ b/kbugbuster/backend/htmlparser.cpp
@@ -0,0 +1,294 @@
+/*
+ This file is part of KBugBuster.
+
+ Copyright (c) 2003 Cornelius Schumacher <schumacher@kde.org>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the 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, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+ As a special exception, permission is given to link this program
+ with any edition of Qt, and distribute the resulting executable,
+ without including the source code for Qt in the source distribution.
+*/
+
+#include "htmlparser.h"
+#include "bugimpl.h"
+#include "packageimpl.h"
+
+#include <kdebug.h>
+
+#include <qbuffer.h>
+#include <qregexp.h>
+#include <qtextstream.h>
+
+KBB::Error HtmlParser::parseBugList( const QByteArray &data, Bug::List &bugs )
+{
+ QBuffer buffer( data );
+ if ( !buffer.open( IO_ReadOnly ) ) {
+ return KBB::Error( "Can't open buffer" );
+ }
+
+ QTextStream ts( &buffer );
+
+ mState = Idle;
+
+ QString line;
+ while ( !( line = ts.readLine() ).isNull() ) {
+ KBB::Error err = parseLine( line, bugs );
+ if ( err ) return err;
+ }
+
+ return KBB::Error();
+}
+
+KBB::Error HtmlParser::parsePackageList( const QByteArray &data,
+ Package::List &packages )
+{
+ init();
+
+ QBuffer buffer( data );
+ if ( !buffer.open( IO_ReadOnly ) ) {
+ return KBB::Error( "Can't open buffer" );
+ }
+
+ QTextStream ts( &buffer );
+
+ QString line;
+ while ( !( line = ts.readLine() ).isNull() ) {
+ KBB::Error err = parseLine( line, packages );
+ if ( err ) return err;
+ }
+
+ processResult( packages );
+
+ return KBB::Error();
+}
+
+void HtmlParser::init()
+{
+}
+
+void HtmlParser::setPackageListQuery( KURL &url )
+{
+ url.setFileName( "query.cgi" );
+}
+
+KBB::Error HtmlParser::parseLine( const QString &, Bug::List & )
+{
+ return KBB::Error();
+}
+
+KBB::Error HtmlParser::parseLine( const QString &, Package::List & )
+{
+ return KBB::Error();
+}
+
+void HtmlParser::processResult( Package::List & )
+{
+}
+
+QString HtmlParser::getAttribute( const QString &line, const QString &name )
+{
+ int pos1 = line.find( name + "=\"" );
+ if ( pos1 < 1 ) return QString::null;
+ pos1 += name.length() + 2;
+ int pos2 = line.find( "\"", pos1 );
+ if ( pos2 < 1 ) return QString::null;
+ return line.mid( pos1, pos2 - pos1 );
+}
+
+bool HtmlParser::getCpts( const QString &line, QString &key,
+ QStringList &values )
+{
+ if ( !line.contains( QRegExp( "\\s*cpts" ) ) ) return false;
+
+// kdDebug() << "LINE: " << line << endl;
+ int pos1 = line.find( "[" );
+ if ( pos1 < 0 ) return false;
+ int pos2 = line.find( "]", ++pos1 );
+ if ( pos2 < 0 ) return false;
+
+ key = line.mid( pos1, pos2 - pos1 );
+ int pos3 = key.find( "'" );
+ if ( pos3 >= 0 ) {
+ int pos4 = key.find( "'", ++pos3 );
+ if ( pos4 >= 0 ) key = key.mid( pos3, pos4 - pos3 );
+ }
+// kdDebug() << " KEY: " << key << endl;
+
+ pos1 = line.find( "'", ++pos2 );
+ if ( pos1 >= 0 ) pos2 = line.find( "'", ++pos1 );
+
+ while ( pos1 >= 0 && pos2 >= 0 ) {
+ QString value = line.mid( pos1, pos2 - pos1 );
+// kdDebug() << " VALUE: " << value << endl;
+
+ values.append( value );
+
+ pos1 = line.find( "'", ++pos2 );
+ if ( pos1 >= 0 ) pos2 = line.find( "'", ++pos1 );
+ }
+
+ return true;
+}
+
+KBB::Error HtmlParser_2_10::parseLine( const QString &line, Bug::List &bugs )
+{
+ if ( line.startsWith( "<TR VALIGN" ) ) {
+// kdDebug() << "LINE: " << line << endl;
+ QRegExp re( "show_bug\\.cgi\\?id=(\\d+)" );
+ re.search( line );
+ QString number = re.cap( 1 );
+// kdDebug() << " NUMBER: " << number << endl;
+
+ QString summary;
+ int pos = line.findRev( "summary>" );
+ if ( pos >= 0 ) summary = line.mid( pos + 8 );
+
+ Bug bug( new BugImpl( summary, Person(), number, 0xFFFFFFFF, Bug::SeverityUndefined,
+ Person(), Bug::StatusUndefined,
+ Bug::BugMergeList() ) );
+
+ if ( !bug.isNull() ) {
+ bugs.append( bug );
+ }
+ }
+
+ return KBB::Error();
+}
+
+KBB::Error HtmlParser_2_10::parseLine( const QString &line,
+ Package::List &packages )
+{
+ QString package;
+ QStringList components;
+
+ if ( getCpts( line, package, components ) ) {
+ packages.append( Package( new PackageImpl( package, "", 0, Person(),
+ components ) ) );
+ }
+
+ return KBB::Error();
+}
+
+
+void HtmlParser_2_14_2::init()
+{
+ mComponentsMap.clear();
+
+ mState = Idle;
+}
+
+KBB::Error HtmlParser_2_14_2::parseLine( const QString &line,
+ Package::List & )
+{
+ switch ( mState ) {
+ case Idle:
+ if ( line.startsWith( "tms[" ) ) mState = Components;
+ break;
+ case Components: {
+ if ( line.startsWith( "function" ) ) mState = Finished;
+ QString key;
+ QStringList values;
+ if ( getCpts( line, key, values ) ) {
+// kdDebug() << "KEY: " << key << " VALUES: " << values.join(",") << endl;
+ if ( values.count() == 2 ) {
+ mComponentsMap[ values.last() ].append( key );
+ }
+ }
+ }
+ default:
+ break;
+ }
+
+ return KBB::Error();
+}
+
+void HtmlParser_2_14_2::processResult( Package::List &packages )
+{
+ QMap<QString,QStringList>::ConstIterator it;
+ for ( it = mComponentsMap.begin(); it != mComponentsMap.end(); ++it ) {
+ packages.append( Package( new PackageImpl( it.key(), "", 0, Person(),
+ it.data() ) ) );
+ }
+}
+
+
+void HtmlParser_2_17_1::init()
+{
+ mProducts.clear();
+ mComponents.clear();
+
+ mState = Idle;
+}
+
+KBB::Error HtmlParser_2_17_1::parseBugList( const QByteArray &data, Bug::List &bugs )
+{
+ return RdfProcessor::parseBugList( data, bugs );
+}
+
+KBB::Error HtmlParser_2_17_1::parseLine( const QString & /*line*/, Bug::List &/*bugs*/ )
+{
+ return KBB::Error( "Not implemented" );
+}
+
+KBB::Error HtmlParser_2_17_1::parseLine( const QString &line, Package::List & )
+{
+ switch ( mState ) {
+ case Idle:
+ case SearchComponents:
+ if ( line.contains( "var cpts" ) ) mState = Components;
+ break;
+ case SearchProducts:
+ if ( line.contains( "onchange=\"selectProduct" ) ) mState = Products;
+ break;
+ case Components: {
+ if ( line.contains( QRegExp( "\\s*function" ) ) ) {
+ mState = SearchProducts;
+ }
+ QString key;
+ QStringList components;
+ if ( getCpts( line, key, components ) ) {
+ mComponents.append( components );
+ }
+ }
+ case Products: {
+ if ( line.contains( "</select>" ) ) mState = Finished;
+ QString product = getAttribute( line, "value" );
+ if ( !product.isEmpty() ) {
+ kdDebug() << "PRODUCT: " << product << endl;
+ mProducts.append( product );
+ }
+ break;
+ }
+ case Finished:
+ default:
+ break;
+ }
+
+ return KBB::Error();
+}
+
+void HtmlParser_2_17_1::processResult( Package::List &packages )
+{
+ QStringList::ConstIterator itProduct = mProducts.begin();
+ QValueList<QStringList>::ConstIterator itComponents = mComponents.begin();
+
+ while( itProduct != mProducts.end() && itComponents != mComponents.end() ) {
+ packages.append( Package( new PackageImpl( *itProduct, "", 0, Person(),
+ *itComponents ) ) );
+ ++itProduct;
+ ++itComponents;
+ }
+}
diff --git a/kbugbuster/backend/htmlparser.h b/kbugbuster/backend/htmlparser.h
new file mode 100644
index 00000000..ffb0a22a
--- /dev/null
+++ b/kbugbuster/backend/htmlparser.h
@@ -0,0 +1,116 @@
+/*
+ This file is part of KBugBuster.
+
+ Copyright (c) 2003 Cornelius Schumacher <schumacher@kde.org>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the 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, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+ As a special exception, permission is given to link this program
+ with any edition of Qt, and distribute the resulting executable,
+ without including the source code for Qt in the source distribution.
+*/
+#ifndef HTMLPARSER_H
+#define HTMLPARSER_H
+
+#include "package.h"
+#include "bug.h"
+#include "error.h"
+#include "rdfprocessor.h"
+
+#include <qstringlist.h>
+#include <qvaluelist.h>
+#include <qmap.h>
+
+class HtmlParser : public RdfProcessor
+{
+ protected:
+ enum State { Idle, SearchComponents, SearchProducts, Components, Products,
+ Finished };
+ State mState;
+
+ public:
+ HtmlParser( BugServer *s ) : RdfProcessor( s ), mState( Idle ) {}
+ virtual ~HtmlParser() {}
+
+ KBB::Error parseBugList( const QByteArray &data, Bug::List &bugs );
+ KBB::Error parsePackageList( const QByteArray &data,
+ Package::List &packages );
+
+ void setPackageListQuery( KURL & );
+
+ protected:
+ virtual void init();
+
+ virtual KBB::Error parseLine( const QString &line, Bug::List &bugs );
+ virtual KBB::Error parseLine( const QString &line,
+ Package::List &packages );
+
+ virtual void processResult( Package::List &packages );
+
+ QString getAttribute( const QString &line, const QString &name );
+ bool getCpts( const QString &line, QString &key, QStringList &values );
+};
+
+
+class HtmlParser_2_10 : public HtmlParser
+{
+ public:
+ HtmlParser_2_10( BugServer *s ) : HtmlParser( s ) {}
+
+ protected:
+ KBB::Error parseLine( const QString &line, Bug::List &bugs );
+ KBB::Error parseLine( const QString &line, Package::List &packages );
+};
+
+
+class HtmlParser_2_14_2 : public HtmlParser_2_10
+{
+ public:
+ HtmlParser_2_14_2( BugServer *s ) : HtmlParser_2_10( s ) {}
+
+ protected:
+ void init();
+
+ KBB::Error parseLine( const QString &line, Package::List &packages );
+
+ void processResult( Package::List &packages );
+
+ private:
+ QMap<QString, QStringList> mComponentsMap;
+};
+
+
+
+class HtmlParser_2_17_1 : public HtmlParser
+{
+ public:
+ HtmlParser_2_17_1( BugServer *s ) : HtmlParser( s ) {}
+
+ KBB::Error parseBugList( const QByteArray &data, Bug::List &bugs );
+
+ protected:
+ void init();
+
+ KBB::Error parseLine( const QString &line, Bug::List &bugs );
+ KBB::Error parseLine( const QString &line, Package::List &packages );
+
+ void processResult( Package::List &packages );
+
+ private:
+ QStringList mProducts;
+ QValueList<QStringList> mComponents;
+};
+
+#endif
diff --git a/kbugbuster/backend/kbbprefs.cpp b/kbugbuster/backend/kbbprefs.cpp
new file mode 100644
index 00000000..30f337ab
--- /dev/null
+++ b/kbugbuster/backend/kbbprefs.cpp
@@ -0,0 +1,170 @@
+/*
+ This file is part of KBugBuster.
+
+ Copyright (c) 2001,2003 Cornelius Schumacher <schumacher@kde.org>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the 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, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+ As a special exception, permission is given to link this program
+ with any edition of Qt, and distribute the resulting executable,
+ without including the source code for Qt in the source distribution.
+*/
+
+#include <qstring.h>
+#include <qstringlist.h>
+
+#include <klocale.h>
+#include <kdebug.h>
+#include <kconfig.h>
+
+#include "bugsystem.h"
+#include "bugserver.h"
+#include "bugserverconfig.h"
+
+#include "kbbprefs.h"
+
+KBBPrefs *KBBPrefs::mInstance = 0;
+
+KBBPrefs::KBBPrefs() : KConfigSkeleton()
+{
+ setCurrentGroup("History");
+
+ addItemInt("RecentPackagesCount",mRecentPackagesCount,7);
+ addItemIntList("Splitter1",mSplitter1);
+ addItemIntList("Splitter2",mSplitter2);
+
+
+ setCurrentGroup("Personal Settings");
+
+ addItemInt("MailClient",mMailClient,MailSender::KMail,"Mail Client");
+ addItemBool("ShowClosedBugs",mShowClosedBugs,false);
+ addItemBool("ShowWishes",mShowWishes,true);
+ addItemBool("ShowVotes", mShowVoted, false);
+ addItemInt("MinimumVotes", mMinVotes, 0);
+ addItemBool("SendBCC",mSendBCC,false);
+ addItemString("OverrideRecipient",mOverrideRecipient,QString::null);
+ addItemInt("WrapColumn",mWrapColumn,90);
+
+
+ setCurrentGroup("MsgInputDlg");
+
+ addItemInt("MsgDialogWidth",mMsgDlgWidth);
+ addItemInt("MsgDialogHeight",mMsgDlgHeight);
+ addItemIntList("MsgDialogSplitter",mMsgDlgSplitter);
+
+
+ setCurrentGroup( "Debug" );
+
+ addItemBool( "DebugMode", mDebugMode, false );
+
+
+ setCurrentGroup( "Servers" );
+
+ addItemString("CurrentServer",mCurrentServer);
+}
+
+
+KBBPrefs::~KBBPrefs()
+{
+ delete mInstance;
+ mInstance = 0;
+}
+
+
+KBBPrefs *KBBPrefs::instance()
+{
+ if (!mInstance) {
+ mInstance = new KBBPrefs();
+ mInstance->readConfig();
+ }
+
+ return mInstance;
+}
+
+void KBBPrefs::usrSetDefaults()
+{
+ setMessageButtonsDefault();
+}
+
+void KBBPrefs::usrReadConfig()
+{
+ mMessageButtons.clear();
+
+ config()->setGroup("MessageButtons");
+ QStringList buttonList = config()->readListEntry("ButtonList");
+ if (buttonList.isEmpty()) {
+ setMessageButtonsDefault();
+ } else {
+ QStringList::ConstIterator it;
+ for(it = buttonList.begin(); it != buttonList.end(); ++it) {
+ QString text = config()->readEntry(*it);
+ mMessageButtons.insert(*it,text);
+ }
+ }
+
+ BugSystem::self()->readConfig( config() );
+}
+
+void KBBPrefs::usrWriteConfig()
+{
+ config()->setGroup("MessageButtons");
+ QStringList buttonList;
+ QMap<QString,QString>::ConstIterator it;
+ for(it = mMessageButtons.begin();it != mMessageButtons.end();++it) {
+ buttonList.append(it.key());
+ config()->writeEntry(it.key(),it.data());
+ }
+ config()->writeEntry("ButtonList",buttonList);
+
+ BugSystem::self()->writeConfig( config() );
+}
+
+void KBBPrefs::setMessageButtonsDefault()
+{
+ mMessageButtons.clear();
+ mMessageButtons.insert(i18n("Bug Fixed in CVS"),"Thank you for your bug report.\n"
+ "The bug that you reported has been identified and has been fixed in the\n"
+ "latest development (CVS) version of KDE. The bug report will be closed.\n");
+ mMessageButtons.insert(i18n("Duplicate Report"),"Thank you for your bug report.\n"
+ "This bug/feature request has already been reported and this report will\n"
+ "be marked as a duplicate.\n");
+ mMessageButtons.insert(i18n("Packaging Bug"),"Thank you for your bug report.\n"
+ "The bug that you reported appears to be a packaging bug, due to a\n"
+ "problem in the way in which your distribution/vendor has packaged\n"
+ "KDE for distribution.\n"
+ "The bug report will be closed since it is not a KDE problem.\n"
+ "Please send the bug report to your distribution/vendor instead.\n");
+ mMessageButtons.insert(i18n("Feature Implemented in CVS"),"Thank you for your bug report.\n"
+ "The feature that you requested has been implemented in the latest\n"
+ "development (CVS) version of KDE. The feature request will be closed.\n");
+ mMessageButtons.insert(i18n("More Information Required"),"Thank you for your bug report.\n"
+ "You have not provided enough information for us to be able to reproduce\n"
+ "the bug. Please provide a detailed account of the steps required to\n"
+ "trigger and reproduce the bug. Without this information, we will not be\n"
+ "able to reproduce, identify and fix the bug.\n");
+ mMessageButtons.insert(i18n("No Longer Applicable"),"Thank you for your bug report.\n"
+ "The bug that your reported no longer applies to the latest development\n"
+ "(CVS) version of KDE. This is most probably because it has been fixed,\n"
+ "the application has been substantially modified or the application no\n"
+ "longer exists. The bug report will be closed.\n");
+ mMessageButtons.insert(i18n("Won't Fix Bug"),"Thank you for your bug report/feature request.\n"
+ "Unfortunately, this bug will never be fixed or the feature never\n"
+ "implemented. The bug report/feature request will be closed.\n");
+ mMessageButtons.insert(i18n("Cannot Reproduce Bug"),"Thank you for your bug report.\n"
+ "This bug can not be reproduced using the current development (CVS)\n"
+ "version of KDE. This suggests that the bug has already been fixed.\n"
+ "The bug report will be closed.\n");
+}
+
diff --git a/kbugbuster/backend/kbbprefs.h b/kbugbuster/backend/kbbprefs.h
new file mode 100644
index 00000000..64d7f20d
--- /dev/null
+++ b/kbugbuster/backend/kbbprefs.h
@@ -0,0 +1,82 @@
+/*
+ This file is part of KBugBuster.
+
+ Copyright (c) 2001,2003 Cornelius Schumacher <schumacher@kde.org>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the 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, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+ As a special exception, permission is given to link this program
+ with any edition of Qt, and distribute the resulting executable,
+ without including the source code for Qt in the source distribution.
+*/
+#ifndef KBBPREFS_H
+#define KBBPREFS_H
+
+#include <qmap.h>
+
+#include <kconfigskeleton.h>
+
+#include "mailsender.h"
+
+class QStringList;
+
+class KBBPrefs : public KConfigSkeleton
+{
+ public:
+ virtual ~KBBPrefs();
+
+ static KBBPrefs *instance();
+
+ protected:
+ void usrSetDefaults();
+ void usrReadConfig();
+ void usrWriteConfig();
+
+ void setMessageButtonsDefault();
+
+ private:
+ KBBPrefs();
+
+ static KBBPrefs *mInstance;
+
+ public:
+ int mRecentPackagesCount;
+
+ QValueList<int> mSplitter1;
+ QValueList<int> mSplitter2;
+
+ int mMailClient;
+ bool mShowClosedBugs;
+ bool mShowWishes;
+ bool mSendBCC;
+ QString mOverrideRecipient;
+
+ bool mShowVoted;
+ int mMinVotes;
+
+ int mWrapColumn;
+
+ QMap<QString,QString> mMessageButtons;
+
+ int mMsgDlgWidth;
+ int mMsgDlgHeight;
+ QValueList<int> mMsgDlgSplitter;
+
+ bool mDebugMode;
+
+ QString mCurrentServer;
+};
+
+#endif
diff --git a/kbugbuster/backend/mailsender.cpp b/kbugbuster/backend/mailsender.cpp
new file mode 100644
index 00000000..ec32405d
--- /dev/null
+++ b/kbugbuster/backend/mailsender.cpp
@@ -0,0 +1,212 @@
+#ifndef QT_NO_ASCII_CAST
+#define QT_NO_ASCII_CAST
+#endif
+
+#include <unistd.h>
+#include <stdio.h>
+
+#include <qtimer.h>
+
+#include <klocale.h>
+#include <kstandarddirs.h>
+#include <kdebug.h>
+#include <kmessagebox.h>
+#include <kurl.h>
+#include <kapplication.h>
+#include <dcopclient.h>
+#include <kprocess.h>
+
+#include "mailsender.h"
+#include "smtp.h"
+
+MailSender::MailSender(MailClient client,const QString &smtpServer) :
+ m_client( client ), m_smtpServer( smtpServer )
+{
+}
+
+MailSender::~MailSender()
+{
+}
+
+MailSender *MailSender::clone() const
+{
+ return new MailSender(m_client,m_smtpServer);
+}
+
+bool MailSender::send(const QString &fromName,const QString &fromEmail,const QString &to,
+ const QString &subject,const QString &body,bool bcc,
+ const QString &recipient)
+{
+ QString from( fromName );
+ if ( !fromEmail.isEmpty() )
+ from += QString::fromLatin1( " <%2>" ).arg( fromEmail );
+ kdDebug() << "MailSender::sendMail():\nFrom: " << from << "\nTo: " << to
+ << "\nbccflag:" << bcc
+ << "\nRecipient:" << recipient
+ << "\nSubject: " << subject << "\nBody: \n" << body << endl;
+
+ // ### FIXME: bcc is not supported in direct mode and recipient is not
+ // supported in sendmail and kmail mode
+
+ if (m_client == Sendmail) {
+ kdDebug() << "Sending per Sendmail" << endl;
+
+ bool needHeaders = true;
+
+ QString command = KStandardDirs::findExe(QString::fromLatin1("sendmail"),
+ QString::fromLatin1("/sbin:/usr/sbin:/usr/lib"));
+ if (!command.isNull()) command += QString::fromLatin1(" -oi -t");
+ else {
+ command = KStandardDirs::findExe(QString::fromLatin1("mail"));
+ if (command.isNull()) return false; // give up
+
+ command.append(QString::fromLatin1(" -s "));
+ command.append(KProcess::quote(subject));
+
+ if (bcc) {
+ command.append(QString::fromLatin1(" -b "));
+ command.append(KProcess::quote(from));
+ }
+
+ command.append(" ");
+ command.append(KProcess::quote(to));
+
+ needHeaders = false;
+ }
+
+ FILE * fd = popen(command.local8Bit(),"w");
+ if (!fd)
+ {
+ kdError() << "Unable to open a pipe to " << command << endl;
+ QTimer::singleShot( 0, this, SLOT( deleteLater() ) );
+ return false;
+ }
+
+ QString textComplete;
+ if (needHeaders)
+ {
+ textComplete += QString::fromLatin1("From: ") + from + '\n';
+ textComplete += QString::fromLatin1("To: ") + to + '\n';
+ if (bcc) textComplete += QString::fromLatin1("Bcc: ") + from + '\n';
+ textComplete += QString::fromLatin1("Subject: ") + subject + '\n';
+ textComplete += QString::fromLatin1("X-Mailer: KBugBuster") + '\n';
+ }
+ textComplete += '\n'; // end of headers
+ textComplete += body;
+
+ emit status( i18n( "Sending through sendmail..." ) );
+ fwrite(textComplete.local8Bit(),textComplete.length(),1,fd);
+
+ pclose(fd);
+ } else if ( m_client == KMail ) {
+ kdDebug() << "Sending per KMail" << endl;
+
+ if (!kapp->dcopClient()->isApplicationRegistered("kmail")) {
+ KMessageBox::error(0,i18n("No running instance of KMail found."));
+ QTimer::singleShot( 0, this, SLOT( deleteLater() ) );
+ return false;
+ }
+
+ emit status( i18n( "Passing mail to KDE email program..." ) );
+ if (!kMailOpenComposer(to,"", (bcc ? from : ""), subject,body,0,KURL())) {
+ QTimer::singleShot( 0, this, SLOT( deleteLater() ) );
+ return false;
+ }
+ } else if ( m_client == Direct ) {
+ kdDebug() << "Sending Direct" << endl;
+
+ QStringList recipients;
+ if ( !recipient.isEmpty() )
+ recipients << recipient;
+ else
+ recipients << to;
+
+ QString message = QString::fromLatin1( "From: " ) + from +
+ QString::fromLatin1( "\nTo: " ) + to +
+ QString::fromLatin1( "\nSubject: " ) + subject +
+ QString::fromLatin1( "\nX-Mailer: KBugBuster" ) +
+ QString::fromLatin1( "\n\n" ) + body;
+
+ Smtp *smtp = new Smtp( fromEmail, recipients, message, m_smtpServer );
+ connect( smtp, SIGNAL( status( const QString & ) ),
+ this, SIGNAL( status( const QString & ) ) );
+ connect( smtp, SIGNAL( success() ),
+ this, SLOT( smtpSuccess() ) );
+ connect( smtp, SIGNAL( error( const QString &, const QString & ) ),
+ this, SLOT( smtpError( const QString &, const QString & ) ) );
+
+ smtp->insertChild( this ); // die when smtp dies
+ } else {
+ kdDebug() << "Invalid mail client setting." << endl;
+ }
+
+ if (m_client != Direct)
+ {
+ emit finished();
+ QTimer::singleShot( 0, this, SLOT( deleteLater() ) );
+ }
+
+ return true;
+}
+
+void MailSender::smtpSuccess()
+{
+ if ( parent() != sender() || !parent()->inherits( "Smtp" ) )
+ return;
+
+ static_cast<Smtp *>( parent() )->quit();
+ emit finished();
+}
+
+void MailSender::smtpError(const QString &_command, const QString &_response)
+{
+ if ( parent() != sender() || !parent()->inherits( "Smtp" ) )
+ return;
+
+ QString command = _command;
+ QString response = _response;
+
+ Smtp *smtp = static_cast<Smtp *>( parent() );
+ smtp->removeChild( this );
+ delete smtp;
+
+ KMessageBox::error( qApp->activeWindow(),
+ i18n( "Error during SMTP transfer.\n"
+ "command: %1\n"
+ "response: %2" ).arg( command ).arg( response ) );
+
+ emit finished();
+ QTimer::singleShot( 0, this, SLOT( deleteLater() ) );
+}
+
+int MailSender::kMailOpenComposer(const QString& arg0,const QString& arg1,
+ const QString& arg2,const QString& arg3,const QString& arg4,int arg5,
+ const KURL& arg6)
+{
+ int result = 0;
+
+ QByteArray data, replyData;
+ QCString replyType;
+ QDataStream arg( data, IO_WriteOnly );
+ arg << arg0;
+ arg << arg1;
+ arg << arg2;
+ arg << arg3;
+ arg << arg4;
+ arg << arg5;
+ arg << arg6;
+ if (kapp->dcopClient()->call("kmail","KMailIface","openComposer(QString,QString,QString,QString,QString,int,KURL)", data, replyType, replyData ) ) {
+ if ( replyType == "int" ) {
+ QDataStream _reply_stream( replyData, IO_ReadOnly );
+ _reply_stream >> result;
+ } else {
+ kdDebug() << "kMailOpenComposer() call failed." << endl;
+ }
+ } else {
+ kdDebug() << "kMailOpenComposer() call failed." << endl;
+ }
+ return result;
+}
+
+#include "mailsender.moc"
+
diff --git a/kbugbuster/backend/mailsender.h b/kbugbuster/backend/mailsender.h
new file mode 100644
index 00000000..06517f9c
--- /dev/null
+++ b/kbugbuster/backend/mailsender.h
@@ -0,0 +1,50 @@
+#ifndef MAILSENDER_H
+#define MAILSENDER_H
+
+#include <qstring.h>
+#include <qobject.h>
+
+class KURL;
+class Smtp;
+
+class MailSender : public QObject
+{
+ Q_OBJECT
+ public:
+ enum MailClient { Sendmail = 0, KMail = 1, Direct = 2 };
+
+ MailSender(MailClient,const QString &smtpServer=QString::null);
+ virtual ~MailSender();
+
+ MailSender *clone() const;
+
+ /**
+ Send mail with specified from, to and subject field and body as text. If
+ bcc is set, send a blind carbon copy to the sender from.
+ If recipient is specified the mail is sent to the specified address
+ instead of 'to' . (this currently only works in for direct mail
+ sending through SMTP.
+ */
+ bool send(const QString &fromName, const QString &fromEmail,
+ const QString &to,const QString &subject,
+ const QString &body,bool bcc=false,
+ const QString &recipient = QString::null);
+
+ signals:
+ void status( const QString &message );
+ void finished();
+
+ private slots:
+ void smtpSuccess();
+ void smtpError(const QString &command, const QString &response);
+
+ private:
+ int kMailOpenComposer(const QString& arg0,const QString& arg1,
+ const QString& arg2,const QString& arg3,
+ const QString& arg4,int arg5,const KURL& arg6);
+
+ MailClient m_client;
+ QString m_smtpServer;
+};
+
+#endif
diff --git a/kbugbuster/backend/package.cpp b/kbugbuster/backend/package.cpp
new file mode 100644
index 00000000..ae009397
--- /dev/null
+++ b/kbugbuster/backend/package.cpp
@@ -0,0 +1,82 @@
+
+#include "package.h"
+
+#include "packageimpl.h"
+
+Package::Package()
+{
+}
+
+Package::Package( PackageImpl *impl )
+ : m_impl( impl )
+{
+}
+
+Package::Package( const Package &other )
+{
+ (*this) = other;
+}
+
+Package &Package::operator=( const Package &rhs )
+{
+ m_impl = rhs.m_impl;
+ return *this;
+}
+
+Package::~Package()
+{
+}
+
+QString Package::name() const
+{
+ if ( !m_impl )
+ return QString::null;
+
+ return m_impl->name;
+}
+
+QString Package::description() const
+{
+ if ( !m_impl )
+ return QString::null;
+
+ return m_impl->description;
+}
+
+uint Package::numberOfBugs() const
+{
+ if ( !m_impl )
+ return 0;
+
+ return m_impl->numberOfBugs;
+}
+
+Person Package::maintainer() const
+{
+ if ( !m_impl )
+ return Person();
+
+ return m_impl->maintainer;
+}
+
+const QStringList Package::components() const
+{
+ if ( !m_impl )
+ return QStringList();
+
+ return m_impl->components;
+}
+
+bool Package::operator==( const Package &rhs )
+{
+ return m_impl == rhs.m_impl;
+}
+
+bool Package::operator<( const Package &rhs ) const
+{
+ return m_impl < rhs.m_impl;
+}
+
+/**
+ * vim:ts=4:sw=4:et
+ */
diff --git a/kbugbuster/backend/package.h b/kbugbuster/backend/package.h
new file mode 100644
index 00000000..7b5c69a1
--- /dev/null
+++ b/kbugbuster/backend/package.h
@@ -0,0 +1,43 @@
+#ifndef __package_h__
+#define __package_h__
+
+#include "person.h"
+
+#include <qvaluelist.h>
+
+#include <ksharedptr.h>
+
+class PackageImpl;
+
+class Package
+{
+public:
+ typedef QValueList<Package> List;
+
+ Package();
+ Package( PackageImpl *impl );
+ Package( const Package &other );
+ Package &operator=( const Package &rhs );
+ ~Package();
+
+ QString name() const;
+ QString description() const;
+ uint numberOfBugs() const;
+ Person maintainer() const;
+ const QStringList components() const;
+
+ bool isNull() const { return m_impl == 0; }
+
+ PackageImpl *impl() const { return m_impl; }
+
+ bool operator==( const Package &rhs );
+ bool operator<( const Package &rhs ) const;
+
+private:
+ KSharedPtr<PackageImpl> m_impl;
+};
+
+#endif
+
+/* vim: set sw=4 ts=4 et softtabstop=4: */
+
diff --git a/kbugbuster/backend/packageimpl.h b/kbugbuster/backend/packageimpl.h
new file mode 100644
index 00000000..c60a1079
--- /dev/null
+++ b/kbugbuster/backend/packageimpl.h
@@ -0,0 +1,31 @@
+#ifndef __packageimpl_h__
+#define __packageimpl_h__
+
+#include "person.h"
+
+#include <qstringlist.h>
+#include <kurl.h>
+#include <ksharedptr.h>
+
+struct PackageImpl : public KShared
+{
+public:
+ PackageImpl( const QString &_name, const QString &_description,
+ uint _numberOfBugs, const Person &_maintainer,
+ const QStringList &_components )
+ : name( _name ), description( _description ),numberOfBugs( _numberOfBugs ),
+ maintainer( _maintainer ), components(_components)
+ {}
+
+ QString name;
+ QString description;
+ uint numberOfBugs;
+ Person maintainer;
+ QStringList components;
+};
+
+#endif
+
+/*
+ * vim:sw=4:ts=4:et
+ */
diff --git a/kbugbuster/backend/packagelistjob.cpp b/kbugbuster/backend/packagelistjob.cpp
new file mode 100644
index 00000000..6b05badf
--- /dev/null
+++ b/kbugbuster/backend/packagelistjob.cpp
@@ -0,0 +1,68 @@
+/*
+ This file is part of KBugBuster.
+
+ Copyright (c) 2002,2003 Cornelius Schumacher <schumacher@kde.org>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the 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, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+ As a special exception, permission is given to link this program
+ with any edition of Qt, and distribute the resulting executable,
+ without including the source code for Qt in the source distribution.
+*/
+
+#include "packagelistjob.h"
+#include "package.h"
+#include "packageimpl.h"
+#include "bugserver.h"
+#include "domprocessor.h"
+#include "htmlparser.h"
+
+#include <kdebug.h>
+#include <assert.h>
+
+#include <qdom.h>
+#include <qbuffer.h>
+
+PackageListJob::PackageListJob( BugServer *server )
+ : BugJob( server )
+{
+}
+
+PackageListJob::~PackageListJob()
+{
+}
+
+void PackageListJob::start()
+{
+ BugJob::start( server()->packageListUrl() );
+}
+
+void PackageListJob::process( const QByteArray &data )
+{
+ Package::List packages;
+ KBB::Error err = server()->processor()->parsePackageList( data, packages );
+ if ( err ) {
+ emit error( err.message() );
+ } else {
+ emit packageListAvailable( packages );
+ }
+}
+
+
+#include "packagelistjob.moc"
+
+/*
+ * vim:sw=4:ts=4:et
+ */
diff --git a/kbugbuster/backend/packagelistjob.h b/kbugbuster/backend/packagelistjob.h
new file mode 100644
index 00000000..0e1bca99
--- /dev/null
+++ b/kbugbuster/backend/packagelistjob.h
@@ -0,0 +1,55 @@
+/*
+ This file is part of KBugBuster.
+
+ Copyright (c) 2002,2003 Cornelius Schumacher <schumacher@kde.org>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the 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, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+ As a special exception, permission is given to link this program
+ with any edition of Qt, and distribute the resulting executable,
+ without including the source code for Qt in the source distribution.
+*/
+
+#ifndef __packagelistjob_h__
+#define __packagelistjob_h__
+
+#include "bugjob.h"
+
+#include "package.h"
+
+#include <qdom.h>
+
+class PackageListJob : public BugJob
+{
+ Q_OBJECT
+ public:
+ PackageListJob( BugServer * );
+ virtual ~PackageListJob();
+
+ void start();
+
+ protected:
+ void process( const QByteArray &data );
+
+ signals:
+ void packageListAvailable( const Package::List &pkgs );
+};
+
+
+#endif
+
+/*
+ * vim:ts=4:sw=4:et
+ */
diff --git a/kbugbuster/backend/person.cpp b/kbugbuster/backend/person.cpp
new file mode 100644
index 00000000..a9f63be0
--- /dev/null
+++ b/kbugbuster/backend/person.cpp
@@ -0,0 +1,74 @@
+#include <kdebug.h>
+
+#include "person.h"
+
+Person::Person( const QString &fullName )
+{
+ int emailPos = fullName.find( '<' );
+ if ( emailPos < 0 ) {
+ email = fullName;
+ } else {
+ email = fullName.mid( emailPos + 1, fullName.length() - 1 );
+ name = fullName.left( emailPos - 1 );
+ }
+}
+
+QString Person::fullName(bool html) const
+{
+ if( name.isEmpty() )
+ {
+ if( email.isEmpty() )
+ return i18n( "Unknown" );
+ else
+ return email;
+ }
+ else
+ {
+ if( email.isEmpty() )
+ return name;
+ else
+ if ( html ) {
+ return name + " &lt;" + email + "&gt;";
+ } else {
+ return name + " <" + email + ">";
+ }
+ }
+}
+
+Person Person::parseFromString( const QString &_str )
+{
+ Person res;
+
+ QString str = _str;
+
+ int ltPos = str.find( '<' );
+ if ( ltPos != -1 )
+ {
+ int gtPos = str.find( '>', ltPos );
+ if ( gtPos != -1 )
+ {
+ res.name = str.left( ltPos - 1 );
+ str = str.mid( ltPos + 1, gtPos - ( ltPos + 1 ) );
+ }
+ }
+
+ int atPos = str.find( '@' );
+ int spacedAtPos = str.find( QString::fromLatin1( " at " ) );
+ if ( atPos == -1 && spacedAtPos != -1 )
+ str.replace( spacedAtPos, 4, QString::fromLatin1( "@" ) );
+
+ int spacePos = str.find( ' ' );
+ while ( spacePos != -1 )
+ {
+ str[ spacePos ] = '.';
+ spacePos = str.find( ' ', spacePos );
+ }
+
+ res.email = str;
+
+ return res;
+}
+
+/**
+ * vim:et:ts=4:sw=4
+ */
diff --git a/kbugbuster/backend/person.h b/kbugbuster/backend/person.h
new file mode 100644
index 00000000..f29074f9
--- /dev/null
+++ b/kbugbuster/backend/person.h
@@ -0,0 +1,26 @@
+#ifndef __person_h__
+#define __person_h__
+
+#include <qstring.h>
+#include <klocale.h>
+
+struct Person
+{
+ Person() {}
+ Person( const QString &fullName );
+ Person( const QString &_name, const QString &_email )
+ : name( _name ), email( _email ) {}
+
+ QString name;
+ QString email;
+
+ QString fullName( bool html = false ) const;
+
+ static Person parseFromString( const QString &str );
+};
+
+#endif
+
+/*
+ * vim:sw=4:ts=4:et
+ */
diff --git a/kbugbuster/backend/processor.cpp b/kbugbuster/backend/processor.cpp
new file mode 100644
index 00000000..332b4418
--- /dev/null
+++ b/kbugbuster/backend/processor.cpp
@@ -0,0 +1,78 @@
+/*
+ This file is part of KBugBuster.
+
+ Copyright (c) 2003 Cornelius Schumacher <schumacher@kde.org>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the 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, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+ As a special exception, permission is given to link this program
+ with any edition of Qt, and distribute the resulting executable,
+ without including the source code for Qt in the source distribution.
+*/
+
+#include <qstylesheet.h>
+
+#include <kdebug.h>
+#include <kmdcodec.h>
+
+#include "processor.h"
+
+#include "bugserver.h"
+#include "packageimpl.h"
+#include "bugimpl.h"
+#include "bugdetailsimpl.h"
+#include "kbbprefs.h"
+
+Processor::Processor( BugServer *server )
+ : mServer( server )
+{
+}
+
+Processor::~Processor()
+{
+}
+
+void Processor::setPackageListQuery( KURL &url )
+{
+ url.setFileName( "xml.cgi" );
+ url.setQuery( "?data=versiontable" );
+}
+
+void Processor::setBugListQuery( KURL &url, const Package &product, const QString &component )
+{
+ if ( mServer->serverConfig().bugzillaVersion() == "Bugworld" ) {
+ url.setFileName( "bugworld.cgi" );
+ } else {
+ url.setFileName( "xmlquery.cgi" );
+ }
+
+ QString user = mServer->serverConfig().user();
+
+ if ( component.isEmpty() )
+ url.setQuery( "?user=" + user + "&product=" + product.name() );
+ else
+ url.setQuery( "?user=" + user + "&product=" + product.name() + "&component=" + component );
+}
+
+void Processor::setBugDetailsQuery( KURL &url, const Bug &bug )
+{
+ url.setFileName( "xml.cgi" );
+ url.setQuery( "?id=" + bug.number() );
+}
+
+
+/*
+ * vim:sw=4:ts=4:et
+ */
diff --git a/kbugbuster/backend/processor.h b/kbugbuster/backend/processor.h
new file mode 100644
index 00000000..cadaa407
--- /dev/null
+++ b/kbugbuster/backend/processor.h
@@ -0,0 +1,63 @@
+/*
+ This file is part of KBugBuster.
+
+ Copyright (c) 2003 Cornelius Schumacher <schumacher@kde.org>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the 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, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+ As a special exception, permission is given to link this program
+ with any edition of Qt, and distribute the resulting executable,
+ without including the source code for Qt in the source distribution.
+*/
+#ifndef KBB_PROCESSOR_H
+#define KBB_PROCESSOR_H
+
+#include "bug.h"
+#include "bugdetails.h"
+#include "package.h"
+#include "error.h"
+
+#include <kurl.h>
+
+class BugServer;
+
+class Processor
+{
+ public:
+ Processor( BugServer * );
+ virtual ~Processor();
+
+ BugServer *server() const { return mServer; }
+
+ virtual KBB::Error parseBugList( const QByteArray &data,
+ Bug::List &bugs ) = 0;
+ virtual KBB::Error parsePackageList( const QByteArray &data,
+ Package::List &packages ) = 0;
+ virtual KBB::Error parseBugDetails( const QByteArray &, BugDetails & ) = 0;
+
+ virtual void setPackageListQuery( KURL & ) = 0;
+ virtual void setBugListQuery( KURL &, const Package &,
+ const QString &component ) = 0;
+ virtual void setBugDetailsQuery( KURL &, const Bug & ) = 0;
+
+ private:
+ BugServer *mServer;
+};
+
+#endif
+
+/*
+ * vim:sw=4:ts=4:et
+ */
diff --git a/kbugbuster/backend/rdfprocessor.cpp b/kbugbuster/backend/rdfprocessor.cpp
new file mode 100644
index 00000000..89bb3402
--- /dev/null
+++ b/kbugbuster/backend/rdfprocessor.cpp
@@ -0,0 +1,107 @@
+/*
+ This file is part of KBugBuster.
+ Copyright (c) 2002 Cornelius Schumacher <schumacher@kde.org>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the 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, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+ As a special exception, permission is given to link this program
+ with any edition of Qt, and distribute the resulting executable,
+ without including the source code for Qt in the source distribution.
+*/
+
+#include "rdfprocessor.h"
+
+#include "bugserver.h"
+#include "packageimpl.h"
+#include "bugimpl.h"
+#include "bugdetailsimpl.h"
+#include "kbbprefs.h"
+
+#include "kdebug.h"
+
+RdfProcessor::RdfProcessor( BugServer *server )
+ : DomProcessor( server )
+{
+}
+
+RdfProcessor::~RdfProcessor()
+{
+}
+
+KBB::Error RdfProcessor::parseDomBugList( const QDomElement &element,
+ Bug::List &bugs )
+{
+ if ( element.tagName() != "RDF" ) {
+ kdDebug() << "RdfProcessor::parseBugList(): no RDF element." << endl;
+ return KBB::Error( "No RDF element found" );
+ }
+
+ QDomNodeList bugNodes = element.elementsByTagName( "bz:bug" );
+
+ for( uint i = 0; i < bugNodes.count(); ++i ) {
+ QString title;
+ Person submitter;
+ QString bugNr;
+ Bug::Status status = Bug::StatusUndefined;
+ Bug::Severity severity = Bug::SeverityUndefined;
+ Person developerTodo;
+ Bug::BugMergeList mergedList;
+
+ QDomNode hit = bugNodes.item( i );
+
+ QDomNode n;
+ for( n = hit.firstChild(); !n.isNull(); n = n.nextSibling() ) {
+ QDomElement e = n.toElement();
+
+ if ( e.tagName() == "bz:id" ) {
+ bugNr = e.text();
+ } else if ( e.tagName() == "bz:status" ) {
+ status = server()->bugStatus( e.text() );
+ } else if ( e.tagName() == "bz:severity" ) {
+ severity = server()->bugSeverity( e.text() );
+ } else if ( e.tagName() == "bz:summary" ) {
+ title = e.text();
+ }
+ }
+
+ Bug bug( new BugImpl( title, submitter, bugNr, 0xFFFFFFFF, severity,
+ developerTodo, status, mergedList ) );
+
+ if ( !bug.isNull() ) {
+ bugs.append( bug );
+ }
+ }
+
+ return KBB::Error();
+}
+
+void RdfProcessor::setBugListQuery( KURL &url, const Package &product, const QString &component )
+{
+ url.setFileName( "buglist.cgi" );
+ if ( component.isEmpty() )
+ url.setQuery( "?format=rdf&product=" + product.name() );
+ else
+ url.setQuery( "?format=rdf&product=" + product.name() + "&component=" + component );
+ if ( KBBPrefs::instance()->mShowVoted ) {
+ url.addQueryItem( "field0-0-0", "votes" );
+ url.addQueryItem( "type0-0-0", "greaterthan" );
+ QString num = QString::number( KBBPrefs::instance()->mMinVotes );;
+ url.addQueryItem( "value0-0-0", num );
+ }
+}
+
+/*
+ * vim:sw=4:ts=4:et
+ */
diff --git a/kbugbuster/backend/rdfprocessor.h b/kbugbuster/backend/rdfprocessor.h
new file mode 100644
index 00000000..0e0bd780
--- /dev/null
+++ b/kbugbuster/backend/rdfprocessor.h
@@ -0,0 +1,43 @@
+/*
+ This file is part of KBugBuster.
+ Copyright (c) 2002 Cornelius Schumacher <schumacher@kde.org>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the 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, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+ As a special exception, permission is given to link this program
+ with any edition of Qt, and distribute the resulting executable,
+ without including the source code for Qt in the source distribution.
+*/
+#ifndef RDFPROCESSOR_H
+#define RDFPROCESSOR_H
+
+#include "domprocessor.h"
+
+class RdfProcessor : public DomProcessor
+{
+ public:
+ RdfProcessor( BugServer * );
+ virtual ~RdfProcessor();
+
+ KBB::Error parseDomBugList( const QDomElement &, Bug::List & );
+
+ void setBugListQuery( KURL &, const Package &, const QString &component );
+};
+
+#endif
+
+/*
+ * vim:sw=4:ts=4:et
+ */
diff --git a/kbugbuster/backend/smtp.cpp b/kbugbuster/backend/smtp.cpp
new file mode 100644
index 00000000..d54cafab
--- /dev/null
+++ b/kbugbuster/backend/smtp.cpp
@@ -0,0 +1,181 @@
+/****************************************************************************
+**
+** This file is a modified version of part of an example program for Qt.
+** This file may be used, distributed and modified without limitation.
+**
+** Don Sanders <sanders@kde.org>
+**
+*****************************************************************************/
+
+#include "smtp.h"
+
+#include <qtextstream.h>
+#include <qsocket.h>
+#include <qtimer.h>
+#include <kapplication.h>
+#include <kmessagebox.h>
+#include <klocale.h>
+
+Smtp::Smtp( const QString &from, const QStringList &to,
+ const QString &aMessage,
+ const QString &server,
+ unsigned short int port )
+{
+ skipReadResponse = false;
+ mSocket = new QSocket( this );
+ connect ( mSocket, SIGNAL( readyRead() ),
+ this, SLOT( readyRead() ) );
+ connect ( mSocket, SIGNAL( connected() ),
+ this, SLOT( connected() ) );
+ connect ( mSocket, SIGNAL( error(int) ),
+ this, SLOT( socketError(int) ) );
+
+ message = aMessage;
+
+ this->from = from;
+ rcpt = to;
+ state = smtpInit;
+ command = "";
+
+ emit status( i18n( "Connecting to %1" ).arg( server ) );
+
+ mSocket->connectToHost( server, port );
+ t = new QTextStream( mSocket );
+ t->setEncoding(QTextStream::Latin1);
+}
+
+
+Smtp::~Smtp()
+{
+ if (t)
+ delete t;
+ if (mSocket)
+ delete mSocket;
+}
+
+
+void Smtp::send( const QString &from, const QStringList &to,
+ const QString &aMessage )
+{
+ skipReadResponse = true;
+ message = aMessage;
+ this->from = from;
+ rcpt = to;
+
+ state = smtpMail;
+ command = "";
+ readyRead();
+}
+
+
+void Smtp::quit()
+{
+ skipReadResponse = true;
+ state = smtpQuit;
+ command = "";
+ readyRead();
+}
+
+
+void Smtp::connected()
+{
+ emit status( i18n( "Connected to %1" ).arg( mSocket->peerName() ) );
+}
+
+void Smtp::socketError(int errorCode)
+{
+ command = "CONNECT";
+ switch ( errorCode ) {
+ case QSocket::ErrConnectionRefused:
+ responseLine = i18n( "Connection refused." );
+ break;
+ case QSocket::ErrHostNotFound:
+ responseLine = i18n( "Host Not Found." );
+ break;
+ case QSocket::ErrSocketRead:
+ responseLine = i18n( "Error reading socket." );
+ break;
+ default:
+ responseLine = i18n( "Internal error, unrecognized error." );
+ }
+ QTimer::singleShot( 0, this, SLOT(emitError()) );
+}
+
+void Smtp::emitError() {
+ error( command, responseLine );
+}
+
+void Smtp::readyRead()
+{
+ if (!skipReadResponse) {
+ // SMTP is line-oriented
+ if ( !mSocket->canReadLine() )
+ return;
+
+ do {
+ responseLine = mSocket->readLine();
+ response += responseLine;
+ } while( mSocket->canReadLine() && responseLine[3] != ' ' );
+ }
+ skipReadResponse = false;
+
+ if ( state == smtpInit && responseLine[0] == '2' ) {
+ // banner was okay, let's go on
+ command = "HELO there";
+ *t << "HELO there\r\n";
+ state = smtpMail;
+ } else if ( state == smtpMail && responseLine[0] == '2' ) {
+ // HELO response was okay (well, it has to be)
+ command = "MAIL";
+ *t << "MAIL FROM: <" << from << ">\r\n";
+ state = smtpRcpt;
+ } else if ( state == smtpRcpt && responseLine[0] == '2' && (rcpt.begin() != rcpt.end())) {
+ command = "RCPT";
+ *t << "RCPT TO: <" << *(rcpt.begin()) << ">\r\n";
+ rcpt.remove( rcpt.begin() );
+ if (rcpt.begin() == rcpt.end())
+ state = smtpData;
+ } else if ( state == smtpData && responseLine[0] == '2' ) {
+ command = "DATA";
+ *t << "DATA\r\n";
+ state = smtpBody;
+ } else if ( state == smtpBody && responseLine[0] == '3' ) {
+ command = "DATA";
+ QString seperator = "";
+ if (message[message.length() - 1] != '\n')
+ seperator = "\r\n";
+ *t << message << seperator << ".\r\n";
+ state = smtpSuccess;
+ } else if ( state == smtpSuccess && responseLine[0] == '2' ) {
+ QTimer::singleShot( 0, this, SIGNAL(success()) );
+ } else if ( state == smtpQuit && responseLine[0] == '2' ) {
+ command = "QUIT";
+ *t << "QUIT\r\n";
+ // here, we just close.
+ state = smtpClose;
+ emit status( i18n( "Message sent" ) );
+ } else if ( state == smtpClose ) {
+ // we ignore it
+ } else { // error occurred
+ QTimer::singleShot( 0, this, SLOT(emitError()) );
+ state = smtpClose;
+ }
+
+ response = "";
+
+ if ( state == smtpClose ) {
+ delete t;
+ t = 0;
+ delete mSocket;
+ mSocket = 0;
+ QTimer::singleShot( 0, this, SLOT(deleteMe()) );
+ }
+}
+
+
+void Smtp::deleteMe()
+{
+ delete this;
+}
+
+#include "smtp.moc"
diff --git a/kbugbuster/backend/smtp.h b/kbugbuster/backend/smtp.h
new file mode 100644
index 00000000..d800cb77
--- /dev/null
+++ b/kbugbuster/backend/smtp.h
@@ -0,0 +1,67 @@
+/****************************************************************************
+**
+** This file is a modified version of part of an example program for Qt.
+** This file may be used, distributed and modified without limitation.
+**
+** Don Sanders <sanders@kde.org>
+**
+*****************************************************************************/
+
+#ifndef SMTP_H
+#define SMTP_H
+
+#include <qobject.h>
+#include <qstring.h>
+#include <qstringlist.h>
+
+class QSocket;
+class QTextStream;
+
+class Smtp : public QObject
+{
+ Q_OBJECT
+
+public:
+ Smtp( const QString &from, const QStringList &to, const QString &message,
+ const QString &server, unsigned short int port = 25 );
+ ~Smtp();
+ void send( const QString &, const QStringList &, const QString & );
+ void quit();
+
+
+signals:
+ void success();
+ void status( const QString & );
+ void error( const QString &command, const QString &response );
+
+private slots:
+ void readyRead();
+ void connected();
+ void deleteMe();
+ void socketError(int err);
+ void emitError();
+
+private:
+ enum State {
+ smtpInit,
+ smtpMail,
+ smtpRcpt,
+ smtpData,
+ smtpBody,
+ smtpSuccess,
+ smtpQuit,
+ smtpClose
+ };
+
+ QString message;
+ QString from;
+ QStringList rcpt;
+ QSocket *mSocket;
+ QTextStream * t;
+ int state;
+ QString response, responseLine;
+ bool skipReadResponse;
+ QString command;
+};
+
+#endif
diff --git a/kbugbuster/configure.in.in b/kbugbuster/configure.in.in
new file mode 100644
index 00000000..92b239ee
--- /dev/null
+++ b/kbugbuster/configure.in.in
@@ -0,0 +1,8 @@
+AC_DEFUN([KBUGBUSTER_CHECK_KCAL],[HAVE_KCAL=0
+KDE_CHECK_HEADER(libkcal/resourcecalendar.h,HAVE_KCAL=1,
+ AC_MSG_WARN([Unable to find libkcal. The Bugzilla todo list \
+ resource for KOrganizer won't be compiled.]))
+AM_CONDITIONAL(include_kcalresource, test "$HAVE_KCAL" = 1)
+])
+
+KBUGBUSTER_CHECK_KCAL
diff --git a/kbugbuster/gui/Makefile.am b/kbugbuster/gui/Makefile.am
new file mode 100644
index 00000000..f1a13327
--- /dev/null
+++ b/kbugbuster/gui/Makefile.am
@@ -0,0 +1,24 @@
+INCLUDES= -I$(top_srcdir)/kbugbuster/backend -I$(top_srcdir)/kbugbuster/ $(all_includes)
+
+noinst_LTLIBRARIES = libkbbmainwindow.la
+
+libkbbmainwindow_la_SOURCES = packagelvi.cpp buglvi.cpp cwloadingwidget.cpp \
+ cwsearchwidget_base.ui cwsearchwidget.cpp \
+ cwbugdetailscontainer_base.ui \
+ cwbugdetailscontainer.cpp \
+ cwbuglistcontainer.cpp \
+ cwbugdetails.cpp \
+ centralwidget_base.ui centralwidget.cpp \
+ kbbmainwindow.cpp msginputdialog.cpp \
+ packageselectdialog.cpp messageeditor.cpp \
+ severityselectdialog.cpp \
+ preferencesdialog.cpp loadallbugsdlg.cpp \
+ serverconfigdialog.cpp
+
+METASOURCES = AUTO
+
+EXTRA_DIST = kbugbusterui.rc
+
+rcdir = $(kde_datadir)/kbugbuster
+rc_DATA = kbugbusterui.rc
+
diff --git a/kbugbuster/gui/README b/kbugbuster/gui/README
new file mode 100644
index 00000000..54e5fa67
--- /dev/null
+++ b/kbugbuster/gui/README
@@ -0,0 +1,21 @@
+Normal classes:
+===============
+kbbmainwindow.* KBugBuster's main window
+buglvi.* QListViewItem representing a bug
+packagelvi.* QListViewItem representing a package
+cwloadingwidget.* The temporary widget shown initially, while loading
+
+msginputdialog.* The dialog for entering a message for closing the bug
+messageeditor.* The dialog for editing the custom messages, associated with buttons
+packageselectdialog.* Dialog for selecting a package
+severityselectdialog.* Dialog for selecting a severity
+
+Widgets, including a Qt designer .ui file:
+==========================================
+centralwidget* The main widget of kbbmainwindow
+cwbuglistcontainer* The widget containing the bug list (top of central widget)
+cwbugdetailscontainer* The widget containing the bug details + the buttons in its right (bottom of central widget).
+cwbugdetails* The widget showing details of a bug report, using KHTMLPart
+cwsearchwidget* A future search widget on the left of the bug details.
+ Same functionality is in the menus, this would take too much screen space IMHO (DF)
+preferencesdialog* Preferences dialog
diff --git a/kbugbuster/gui/buglvi.cpp b/kbugbuster/gui/buglvi.cpp
new file mode 100644
index 00000000..be629510
--- /dev/null
+++ b/kbugbuster/gui/buglvi.cpp
@@ -0,0 +1,109 @@
+/*
+ buglvi.cpp - Custom QListViewItem that holds a Bug object
+
+ copyright : (c) 2001 by Martijn Klingens
+ email : klingens@kde.org
+
+ *************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the 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 <qfont.h>
+#include <qpainter.h>
+
+#include <kstringhandler.h>
+#include <kdebug.h>
+
+#include "bugsystem.h"
+#include "bugserver.h"
+
+#include "buglvi.h"
+
+using namespace KBugBusterMainWindow;
+
+BugLVI::BugLVI( KListView *parent , const Bug &bug )
+: KListViewItem( parent, bug.number() + " ",
+ i18n( "1 day", "%n days", bug.age() ),
+ bug.title(), //KStringHandler::csqueeze( bug.title(), 70 ),
+ Bug::statusLabel( bug.status() ),
+ Bug::severityLabel( bug.severity() ),
+ bug.submitter().fullName() )
+{
+ m_bug = bug;
+
+ bool hasCommands = BugSystem::self()->server()->hasCommandsFor( bug );
+ mCommandState = hasCommands ? BugCommand::Queued : BugCommand::None;
+
+ if ( bug.age() == 0xFFFFFFFF )
+ setText( 1, i18n( "Unknown" ) );
+
+ Person developer = bug.developerTODO();
+ if ( !developer.name.isEmpty() )
+ setText( 3, i18n( "%1 (%2)" ).arg( Bug::statusLabel( bug.status() ), developer.name ) );
+}
+
+BugLVI::~BugLVI()
+{
+}
+
+QString BugLVI::key( int column, bool /* ascending */ ) const
+{
+ QString key;
+
+ if ( column == 0 )
+ {
+ key = text( 0 ).rightJustify( 10, '0' );
+ }
+ else if ( column == 1 )
+ {
+ if ( m_bug.age() == 0xFFFFFFFF )
+ key = "0";
+ else
+ key = QString::number( m_bug.age() ).rightJustify( 10, '0' );
+ }
+ else if ( column == 4 )
+ {
+ key = QString::number( 10 - m_bug.severity() );
+ key += m_bug.number().rightJustify( 10, '0' );
+ }
+ else
+ {
+ key = text( column );
+ }
+
+ return key;
+}
+
+void BugLVI::paintCell(QPainter* p, const QColorGroup& cg,
+ int column, int width, int align)
+{
+ QColorGroup newCg = cg;
+ if ( mCommandState == BugCommand::Queued ) {
+ QFont font = p->font();
+ font.setBold( true );
+ p->setFont( font );
+ } else if ( mCommandState == BugCommand::Sent ) {
+ QFont font = p->font();
+ font.setItalic( true );
+ p->setFont( font );
+ } else if ( m_bug.status() == Bug::Closed ) {
+ // Different color for closed bugs
+ newCg.setColor( QColorGroup::Text, cg.color( QColorGroup::Dark ) );
+ }
+
+ KListViewItem::paintCell( p, newCg, column, width, align );
+}
+
+void BugLVI::setCommandState( BugCommand::State state)
+{
+ mCommandState = state;
+}
+
+// vim: set et ts=4 sw=4 sts=4:
+
diff --git a/kbugbuster/gui/buglvi.h b/kbugbuster/gui/buglvi.h
new file mode 100644
index 00000000..ff8fa7f9
--- /dev/null
+++ b/kbugbuster/gui/buglvi.h
@@ -0,0 +1,57 @@
+/*
+ buglvi.h - Custom QListViewItem that holds a Bug object
+
+ copyright : (c) 2001 by Martijn Klingens
+ email : klingens@kde.org
+
+ *************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the 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 KBBMAINWINDOW_BUGLVI_H
+#define KBBMAINWINDOW_BUGLVI_H
+
+#include <klistview.h>
+
+#include "bug.h"
+#include "bugcommand.h"
+
+namespace KBugBusterMainWindow
+{
+
+/**
+ * @author Martijn Klingens
+ */
+class BugLVI : public KListViewItem
+{
+public:
+ BugLVI( KListView *parent , const Bug &bug );
+ ~BugLVI();
+
+ Bug& bug() { return m_bug; }
+ void setBug( Bug &bug ) { m_bug = bug; }
+
+ QString key ( int column, bool ascending ) const;
+
+ void setCommandState( BugCommand::State state );
+
+ void paintCell(QPainter* p, const QColorGroup& cg,
+ int column, int width, int align);
+
+private:
+ Bug m_bug;
+ BugCommand::State mCommandState;
+};
+
+} // namespace
+
+#endif // KBBMAINWINDOW_BUGLVI_H
+
+/* vim: set et ts=4 softtabstop=4 sw=4: */
+
diff --git a/kbugbuster/gui/centralwidget.cpp b/kbugbuster/gui/centralwidget.cpp
new file mode 100644
index 00000000..80bd0672
--- /dev/null
+++ b/kbugbuster/gui/centralwidget.cpp
@@ -0,0 +1,507 @@
+/*
+ centralwidget.cpp - Central widget for the KBB main window
+
+ copyright : (c) 2001 by Martijn Klingens
+ email : klingens@kde.org
+
+ *************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the 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 <qsplitter.h>
+#include <qpushbutton.h>
+#include <qwidgetstack.h>
+#include <qlayout.h>
+
+#include <kdialog.h>
+#include <kdebug.h>
+#include <kcombobox.h>
+#include <klistview.h>
+#include <kinputdialog.h>
+
+#include "kbbprefs.h"
+#include "bugsystem.h"
+#include "packagelvi.h"
+#include "buglvi.h"
+#include "msginputdialog.h"
+#include "packageselectdialog.h"
+#include "cwbugdetails.h"
+#include "bugcommand.h"
+#include "severityselectdialog.h"
+#include "cwsearchwidget.h"
+#include "cwbuglistcontainer.h"
+#include "cwbugdetailscontainer.h"
+#include "bugserver.h"
+
+#include "centralwidget.h"
+#include <kfiledialog.h>
+#include <kmessagebox.h>
+#include "loadallbugsdlg.h"
+
+using namespace KBugBusterMainWindow;
+
+CentralWidget::CentralWidget( const QCString &initialPackage,
+ const QCString &initialComponent,
+ const QCString &initialBug, QWidget *parent,
+ const char * name )
+ : QWidget( parent, name )
+{
+ // Master layout
+ ( new QVBoxLayout( this, 0,
+ KDialog::spacingHint() ) )->setAutoAdd( true );
+
+ // Create QSplitter children
+ m_vertSplitter = new QSplitter( QSplitter::Vertical, this );
+ m_listPane = new CWBugListContainer( m_vertSplitter );
+ m_horSplitter = new QSplitter( QSplitter::Horizontal,m_vertSplitter );
+// The search pane isn't used. Should we remove the code?
+ m_searchPane = new CWSearchWidget( m_horSplitter );
+ m_bugPane = new CWBugDetailsContainer( m_horSplitter );
+
+ m_searchPane->hide();
+// m_listPane->hide();
+
+ m_searchPane->setSizePolicy( QSizePolicy( QSizePolicy::Minimum,
+ QSizePolicy::Minimum ) );
+ m_horSplitter->setResizeMode( m_searchPane, QSplitter::FollowSizeHint );
+
+ connect( m_listPane, SIGNAL( resetProgressBar() ),
+ SIGNAL( resetProgressBar() ) );
+ connect( m_bugPane, SIGNAL( resetProgressBar() ),
+ SIGNAL( resetProgressBar() ) );
+
+ // Start the proper jobs for loading the package lists
+ connect( BugSystem::self(),
+ SIGNAL( packageListAvailable( const Package::List & ) ),
+ SLOT( updatePackageList( const Package::List & ) ) );
+ connect( BugSystem::self(),
+ SIGNAL( bugListAvailable( const Package &, const QString &, const Bug::List & ) ),
+ SLOT( updateBugList( const Package &, const QString &, const Bug::List & ) ) );
+ connect( BugSystem::self(),
+ SIGNAL( bugListAvailable( const QString &, const Bug::List & ) ),
+ SLOT( updateBugList( const QString &, const Bug::List & ) ) );
+ connect( BugSystem::self(),
+ SIGNAL( bugDetailsAvailable( const Bug &, const BugDetails & ) ),
+ SLOT( updateBugDetails( const Bug &, const BugDetails & ) ) );
+
+ connect( BugSystem::self(), SIGNAL( loadingError( const QString & ) ),
+ SLOT( showLoadingError( const QString & ) ) );
+
+ connect( m_bugPane, SIGNAL( signalCloseBug() ), SLOT( closeBug() ) );
+ connect( m_bugPane, SIGNAL( signalCloseBugSilently() ), SLOT( closeBugSilently() ) );
+ connect( m_bugPane, SIGNAL( signalReopenBug() ), SLOT( reopenBug() ) );
+ connect( m_bugPane, SIGNAL( signalReassignBug() ), SLOT( reassignBug() ) );
+ connect( m_bugPane, SIGNAL( signalTitleBug() ), SLOT( titleBug() ) );
+ connect( m_bugPane, SIGNAL( signalSeverityBug() ), SLOT( severityBug() ) );
+ connect( m_bugPane, SIGNAL( signalReplyBug() ), SLOT( replyBug() ) );
+ connect( m_bugPane, SIGNAL( signalReplyPrivateBug() ), SLOT( replyPrivateBug() ) );
+
+ connect( m_bugPane, SIGNAL( signalClearCommand() ), SLOT( clearCommand() ) );
+
+ // Add the selection slots for the listviews
+ connect( m_searchPane->m_searchPackages,
+ SIGNAL( activated( const QString & ) ),
+ SLOT( slotRetrieveBugList( const QString & ) ) );
+
+ connect( m_listPane, SIGNAL( executed( const Bug & ) ),
+ SLOT( slotRetrieveBugDetails( const Bug & ) ) );
+ connect( m_listPane, SIGNAL( currentChanged( const Bug & ) ),
+ SLOT( slotSetActiveBug( const Bug & ) ) );
+
+ connect( m_listPane, SIGNAL( searchPackage() ), SIGNAL( searchPackage() ) );
+ connect( m_bugPane, SIGNAL( searchBugNumber() ), SIGNAL( searchBugNumber() ) );
+
+ m_bLoadingAllBugs = false;
+
+ initialize( initialPackage, initialComponent, initialBug );
+}
+
+CentralWidget::~CentralWidget()
+{
+// kdDebug() << "CentralWidget::~CentralWidget()" << endl;
+}
+
+void CentralWidget::initialize( const QString& p, const QString &c, const QString& b )
+{
+// kdDebug() << "CentralWidget::initialize(): package: '" << p
+// << "' bug: '" << b << "'" << endl;
+
+ BugServerConfig cfg = BugSystem::self()->server()->serverConfig();
+ QString package = p.isEmpty() ? cfg.currentPackage() : p;
+ QString bug = b.isEmpty() ? cfg.currentBug() : b;
+ QString component = c.isEmpty() ? cfg.currentComponent() : c;
+
+ m_listPane->setNoList();
+ m_bugPane->setNoBug();
+
+ BugSystem::self()->retrievePackageList();
+ if ( !package.isEmpty() ) {
+ m_currentPackage = BugSystem::self()->package( package );
+ m_currentComponent = component;
+ BugSystem::self()->retrieveBugList( m_currentPackage, m_currentComponent );
+
+ if ( !bug.isEmpty() ) {
+ m_currentBug = BugSystem::self()->bug( m_currentPackage,
+ m_currentComponent, bug );
+ BugSystem::self()->retrieveBugDetails( m_currentBug );
+ }
+ } else {
+ if ( !bug.isEmpty() ) {
+ // ### bad way to instanciating a bug object! doesn't restore details!
+ m_currentBug = Bug::fromNumber( bug ); // bug number specified on cmdline. Is it a problem that we don't have details ?
+ BugSystem::self()->retrieveBugDetails( m_currentBug );
+ }
+ }
+}
+
+void CentralWidget::readConfig()
+{
+ m_horSplitter->setSizes( KBBPrefs::instance()->mSplitter2 );
+ m_vertSplitter->setSizes( KBBPrefs::instance()->mSplitter1 );
+}
+
+void CentralWidget::writeConfig()
+{
+#if 0
+ kdDebug() << "m_vertSplitter" << endl;
+ QValueList<int> sizes = m_vertSplitter->sizes();
+ QValueList<int>::ConstIterator it;
+ for( it = sizes.begin(); it != sizes.end(); ++it ) {
+ kdDebug() << " " << (*it) << endl;
+ }
+#endif
+
+ KBBPrefs::instance()->mSplitter1 = m_vertSplitter->sizes();
+ KBBPrefs::instance()->mSplitter2 = m_horSplitter->sizes();
+
+ BugServer *server = BugSystem::self()->server();
+ server->serverConfig().setCurrentPackage( m_currentPackage.name() );
+ server->serverConfig().setCurrentComponent( m_currentComponent );
+ server->serverConfig().setCurrentBug( m_currentBug.number() );
+}
+
+void CentralWidget::slotRetrieveBugList( const QString &package )
+{
+ slotRetrieveBugList( package, QString::null );
+}
+
+void CentralWidget::slotRetrieveBugList( const QString &p, const QString &component )
+{
+ if ( p.isEmpty() ) return;
+
+ Package package = m_packageList[ p ];
+
+ if ( package.isNull() ) {
+ // Invalid package, return
+ return;
+ }
+
+ if ( ( package == m_currentPackage ) && ( m_currentComponent == component ) ) {
+ return; // Nothing to do
+ }
+
+ m_currentComponent = component;
+ m_currentPackage = package;
+
+ BugSystem::self()->retrieveBugList( m_currentPackage, m_currentComponent );
+}
+
+QString CentralWidget::currentNumber() const
+{
+ if( m_currentBug.isNull() )
+ return "";
+ else
+ return m_currentBug.number();
+}
+
+QString CentralWidget::currentTitle() const
+{
+ if( m_currentBug.isNull() )
+ return "";
+ else
+ return m_currentBug.title();
+}
+
+void CentralWidget::slotRetrieveBugDetails( const Bug &bug )
+{
+ if( m_currentBug == bug )
+ return; // Nothing to do
+
+ m_currentBug = bug;
+ BugSystem::self()->retrieveBugDetails( m_currentBug );
+}
+
+void CentralWidget::slotSetActiveBug( const Bug &bug )
+{
+ if( bug.isNull() )
+ {
+ return;
+ }
+
+ if( m_activeBug == bug )
+ return; // Nothing to do
+
+ m_activeBug = bug;
+}
+
+void CentralWidget::updatePackageList( const Package::List &pkgs )
+{
+ // ### needs proper implementation ;-)
+
+ m_searchPane->m_searchPackages->clear();
+ m_searchPane->m_searchPackages->completionObject()->clear();
+// m_bugPane->m_bugDetails->m_bugPackage->clear();
+ emit resetProgressBar();
+
+ Package::List::ConstIterator it = pkgs.begin();
+ for ( ; it != pkgs.end(); ++it )
+ {
+ m_packageList[ ( *it ).name() ] = *it;
+ m_searchPane->m_searchPackages->insertItem( ( *it ).name() );
+ m_searchPane->m_searchPackages->
+ completionObject()->addItem( ( *it ).name() );
+// m_bugPane->m_bugDetails->m_bugPackage->insertItem( ( *it ).name() );
+ }
+
+/*
+ if( m_bugPane->m_bugStack->id(
+ m_bugPane->m_bugStack->visibleWidget() ) != 0 )
+ {
+ m_bugPane->m_bugDetails->m_bugPackage->setCurrentItem( -1 );
+ }
+*/
+}
+
+void CentralWidget::updateBugList( const Package &pkg, const QString &component, const Bug::List &bugs )
+{
+ m_listPane->setBugList( pkg, component, bugs );
+}
+
+void CentralWidget::updateBugList( const QString &label, const Bug::List &bugs )
+{
+ m_listPane->setBugList( label, bugs );
+}
+
+void CentralWidget::updateBugDetails( const Bug &bug, const BugDetails &bd )
+{
+ if ( !m_bLoadingAllBugs )
+ m_bugPane->setBug( bug, bd );
+}
+
+void CentralWidget::slotReloadPackageList()
+{
+ BugSystem::self()->cache()->invalidatePackageList();
+ BugSystem::self()->retrievePackageList();
+}
+
+void CentralWidget::slotReloadPackage()
+{
+ if (!m_currentPackage.isNull()) {
+ BugSystem::self()->cache()->invalidateBugList( m_currentPackage, m_currentComponent );
+ BugSystem::self()->retrieveBugList( m_currentPackage, m_currentComponent );
+ }
+}
+
+void CentralWidget::slotLoadMyBugs()
+{
+ BugSystem::self()->retrieveMyBugsList();
+}
+
+void CentralWidget::slotReloadBug()
+{
+ if (!m_currentBug.isNull()) {
+ BugSystem::self()->cache()->invalidateBugDetails( m_currentBug );
+ BugSystem::self()->retrieveBugDetails( m_currentBug );
+ }
+}
+
+void CentralWidget::updatePackage()
+{
+ if (!m_currentPackage.isNull()) {
+ BugSystem::self()->retrieveBugList( m_currentPackage, m_currentComponent );
+ }
+}
+
+void CentralWidget::slotExtractAttachments()
+{
+ if (!m_currentBug.isNull()) {
+ // Grab bug details (i.e. full-text) from cache, then extract attachments from it
+ BugDetails details = BugSystem::self()->cache()->loadBugDetails( m_currentBug );
+ QValueList<BugDetails::Attachment> attachments = details.extractAttachments();
+ if ( !attachments.isEmpty() )
+ {
+ QStringList fileList;
+ for ( QValueList<BugDetails::Attachment>::Iterator it = attachments.begin() ; it != attachments.end() ; ++it )
+ {
+ // Handle duplicates
+ if ( fileList.contains( (*it).filename ) )
+ {
+ int n = 2; // looks stupid to have "blah" and "1-blah", start at 2
+ QString fn = QString::number(n) + '-' + (*it).filename;
+ while ( fileList.contains( fn ) )
+ {
+ ++n;
+ fn = QString::number(n) + '-' + (*it).filename;
+ }
+ (*it).filename = fn;
+ }
+ fileList += (*it).filename;
+ }
+
+ int res = KMessageBox::questionYesNoList( this,
+ i18n("Found the following attachments. Save?"),
+ fileList, QString::null, KStdGuiItem::save(), KStdGuiItem::dontSave() );
+ if ( res == KMessageBox::No )
+ return;
+ QString dir = KFileDialog::getExistingDirectory( QString::null, this, i18n("Select Folder Where to Save Attachments") );
+ if ( !dir.isEmpty() )
+ {
+ if ( !dir.endsWith( "/" ) )
+ dir += '/';
+ for ( QValueList<BugDetails::Attachment>::Iterator it = attachments.begin() ; it != attachments.end() ; ++it )
+ {
+ QString filename = m_currentBug.number() + '-' + (*it).filename;
+ QFile file( dir + filename );
+ if ( file.open( IO_WriteOnly ) )
+ file.writeBlock( (*it).contents );
+ else
+ kdError() << "Couldn't save attachment to " << filename << endl;
+ file.close();
+ }
+ }
+ }
+ }
+}
+
+void CentralWidget::mergeBugs()
+{
+ QStringList bugNumbers = m_listPane->selectedBugs();
+ if ( bugNumbers.count() >= 2 ) {
+ BugSystem::self()->queueCommand(
+ new BugCommandMerge( bugNumbers, m_currentPackage ) );
+ }
+}
+
+void CentralWidget::unmergeBugs()
+{
+ BugSystem::self()->queueCommand(
+ new BugCommandUnmerge( m_currentBug, m_currentPackage ) );
+}
+
+void CentralWidget::closeBug()
+{
+ MsgInputDialog *dlg = new MsgInputDialog( MsgInputDialog::Close,
+ m_currentBug, m_currentPackage,
+ m_bugPane->bugDetailsWidget()->selectedText(), this );
+ dlg->show();
+}
+
+void CentralWidget::closeBugSilently()
+{
+ BugSystem::self()->queueCommand(
+ new BugCommandCloseSilently( m_currentBug, m_currentPackage ) );
+}
+
+void CentralWidget::reopenBug()
+{
+ BugSystem::self()->queueCommand(
+ new BugCommandReopen( m_currentBug, m_currentPackage ) );
+}
+
+void CentralWidget::reassignBug()
+{
+ PackageSelectDialog *dlg = new PackageSelectDialog( this );
+ dlg->exec();
+
+ dlg->setPackages( BugSystem::self()->packageList() );
+ BugServerConfig cfg = BugSystem::self()->server()->serverConfig();
+ dlg->setRecentPackages( cfg.recentPackages() );
+
+ Package package = dlg->selectedPackage();
+
+ if ( package.isNull() ) {
+ return;
+ }
+
+ BugSystem::self()->queueCommand(
+ new BugCommandReassign( m_currentBug, package.name(), m_currentPackage ) );
+}
+
+void CentralWidget::titleBug()
+{
+ bool ok = false;
+ QString title = KInputDialog::getText( i18n("Change Bug Title"),
+ i18n( "Please enter a new title:" ),
+ m_currentBug.title(), &ok, this );
+ if ( ok && !title.isEmpty() ) {
+ BugSystem::self()->queueCommand(
+ new BugCommandRetitle( m_currentBug, title, m_currentPackage ) );
+ }
+}
+
+void CentralWidget::severityBug()
+{
+ SeveritySelectDialog *dlg = new SeveritySelectDialog( this );
+ dlg->setSeverity( m_currentBug.severity() );
+ int result = dlg->exec();
+ if ( result == QDialog::Accepted ) {
+ BugSystem::self()->queueCommand(
+ new BugCommandSeverity( m_currentBug,
+ dlg->selectedSeverityAsString(), m_currentPackage ) );
+ }
+}
+
+void CentralWidget::replyBug()
+{
+ MsgInputDialog *dlg = new MsgInputDialog( MsgInputDialog::Reply,
+ m_currentBug, m_currentPackage,
+ m_bugPane->bugDetailsWidget()->selectedText(), this );
+ dlg->show();
+}
+
+void CentralWidget::replyPrivateBug()
+{
+ MsgInputDialog *dlg = new MsgInputDialog( MsgInputDialog::ReplyPrivate,
+ m_currentBug, m_currentPackage,
+ m_bugPane->bugDetailsWidget()->selectedText(), this );
+ dlg->show();
+}
+
+void CentralWidget::clearCommand()
+{
+ BugSystem::self()->clearCommands( m_currentBug.number() );
+}
+
+void CentralWidget::searchBugByTitle( int options, const QString& pattern )
+{
+ m_listPane->searchBugByTitle( options, pattern );
+}
+
+void CentralWidget::slotRetrieveAllBugDetails()
+{
+ m_bLoadingAllBugs = true;
+ // Make a modal dialog to show the progress, and block usage of main window.
+ LoadAllBugsDlg dlg( m_currentPackage, m_currentComponent );
+ dlg.exec();
+ m_bLoadingAllBugs = false;
+}
+
+void CentralWidget::showLoadingError( const QString &text )
+{
+ KMessageBox::error( this, text );
+}
+
+CWBugDetails *CentralWidget::bugDetailsWidget()
+{
+ return m_bugPane->bugDetailsWidget();
+}
+
+#include "centralwidget.moc"
+
+/* vim: set et ts=4 sw=4 softtabstop=4: */
diff --git a/kbugbuster/gui/centralwidget.h b/kbugbuster/gui/centralwidget.h
new file mode 100644
index 00000000..85b97eca
--- /dev/null
+++ b/kbugbuster/gui/centralwidget.h
@@ -0,0 +1,142 @@
+/*
+ centralwidget.h - Central widget for the KBB main window
+
+ copyright : (c) 2001 by Martijn Klingens
+ email : klingens@kde.org
+
+ *************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the 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 KBBMAINWINDOW_CENTRALWIDGET_H
+#define KBBMAINWINDOW_CENTRALWIDGET_H
+
+#include <qwidget.h>
+
+#include "package.h"
+#include "bug.h"
+#include "bugdetails.h"
+
+class QSplitter;
+class QListViewItem;
+
+namespace KBugBusterMainWindow
+{
+
+class CWSearchWidget;
+class CWBugListContainer;
+class CWBugDetailsContainer;
+class CWBugDetails;
+
+/**
+ * @author Martijn Klingens
+ */
+class CentralWidget : public QWidget
+{
+ Q_OBJECT
+
+public:
+ CentralWidget( const QCString &initialPackage,
+ const QCString &initalComponent,const QCString& initialBug,
+ QWidget* parent = 0, const char* name = 0 );
+ ~CentralWidget();
+
+ void initialize( const QString &initialPackage = QString::null,
+ const QString &initalComponent = QString::null,
+ const QString &initialBug = QString::null );
+
+ void readConfig();
+ void writeConfig();
+
+ void searchBugByTitle( int options, const QString& pattern );
+
+ virtual QString currentNumber() const;
+ virtual QString currentTitle() const;
+
+ void updatePackage();
+
+ CWBugDetails *bugDetailsWidget();
+
+public slots:
+ void slotRetrieveBugList( const QString &package, const QString &component );
+ void slotRetrieveBugList( const QString &package );
+ void slotRetrieveBugDetails( const Bug & );
+ void slotSetActiveBug( const Bug & );
+ void slotRetrieveAllBugDetails();
+
+ void updatePackageList( const Package::List &pkgs );
+ void updateBugList( const Package &pkg, const QString &component, const Bug::List &bugs );
+ void updateBugList( const QString &label, const Bug::List &bugs );
+ void updateBugDetails( const Bug &, const BugDetails & );
+
+ void slotReloadPackageList();
+ void slotReloadPackage();
+ void slotReloadBug();
+ void slotExtractAttachments();
+
+ /**
+ * Load the bugs the user reported himself, or for which he is the assigned to person
+ */
+ void slotLoadMyBugs();
+
+ void mergeBugs();
+ void unmergeBugs();
+
+ void closeBug();
+ void closeBugSilently();
+ void reopenBug();
+ void titleBug();
+ void severityBug();
+ void replyBug();
+ void replyPrivateBug();
+ void reassignBug();
+
+ void clearCommand();
+
+signals:
+ void resetProgressBar();
+ void searchPackage(); // when clicking on the initial package widget
+ void searchBugNumber(); // when clicking on the initial bug-details widget
+
+protected slots:
+ void showLoadingError( const QString & );
+
+private:
+ CWSearchWidget *m_searchPane;
+ CWBugListContainer *m_listPane;
+ CWBugDetailsContainer *m_bugPane;
+
+ QSplitter *m_vertSplitter;
+ QSplitter *m_horSplitter;
+
+ /**
+ * Other status info
+ */
+ Package m_currentPackage;
+ QString m_currentComponent;
+ Bug m_currentBug;
+
+ QMap<QString, Package> m_packageList;
+
+ /**
+ * We do multi-select, but the close/reopen buttons are per-item and
+ * on highlight instead of on execute! Hence this different member
+ */
+ Bug m_activeBug;
+
+ // For "load all bugs"
+ bool m_bLoadingAllBugs;
+};
+
+} // namespace
+
+#endif // KBBMAINWINDOW_CENTRALWIGET_H
+
+/* vim: set et ts=4 softtabstop=4 sw=4: */
+
diff --git a/kbugbuster/gui/centralwidget_base.ui b/kbugbuster/gui/centralwidget_base.ui
new file mode 100644
index 00000000..d2f707de
--- /dev/null
+++ b/kbugbuster/gui/centralwidget_base.ui
@@ -0,0 +1,236 @@
+<!DOCTYPE UI><UI version="3.0" stdsetdef="1">
+<class>CentralWidget_Base</class>
+<widget class="QWidget">
+ <property name="name">
+ <cstring>CentralWidget_Base</cstring>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>630</width>
+ <height>518</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="QGroupBox">
+ <property name="name">
+ <cstring>m_searchGroup</cstring>
+ </property>
+ <property name="title">
+ <string>Search</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="QWidget">
+ <property name="name">
+ <cstring>m_searchContainer</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>5</hsizetype>
+ <vsizetype>7</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </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="QWidgetStack">
+ <property name="name">
+ <cstring>m_searchStack</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>5</hsizetype>
+ <vsizetype>7</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ </widget>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>TextLabel9</cstring>
+ </property>
+ <property name="text">
+ <string>Bug &amp;number:</string>
+ </property>
+ <property name="buddy" stdset="0">
+ <cstring>m_searchBugNumber</cstring>
+ </property>
+ </widget>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>Layout17</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="QLineEdit">
+ <property name="name">
+ <cstring>m_searchBugNumber</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>1</hsizetype>
+ <vsizetype>0</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ </widget>
+ <widget class="QPushButton">
+ <property name="name">
+ <cstring>m_searchBugNumberBtn</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="pixmap">
+ <pixmap>image0</pixmap>
+ </property>
+ </widget>
+ </hbox>
+ </widget>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>TextLabel7</cstring>
+ </property>
+ <property name="text">
+ <string>&amp;Description:</string>
+ </property>
+ <property name="buddy" stdset="0">
+ <cstring>m_searchDesc</cstring>
+ </property>
+ </widget>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>Layout15</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="QLineEdit">
+ <property name="name">
+ <cstring>m_searchDesc</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>1</hsizetype>
+ <vsizetype>0</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ </widget>
+ <widget class="QPushButton">
+ <property name="name">
+ <cstring>m_searchDescBtn</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="pixmap">
+ <pixmap>image0</pixmap>
+ </property>
+ </widget>
+ </hbox>
+ </widget>
+ </vbox>
+ </widget>
+ </vbox>
+ </widget>
+ <widget class="QSplitter">
+ <property name="name">
+ <cstring>m_splitter</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ </widget>
+ </hbox>
+</widget>
+<customwidgets>
+ <customwidget>
+ <class>QWidgetStack</class>
+ <header location="global">qwidgetstack.h</header>
+ <sizehint>
+ <width>-1</width>
+ <height>-1</height>
+ </sizehint>
+ <container>1</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="XPM.GZ" length="1725">789c75d4594fdb401405e0777e4584df5075b0e325b6aa3eb015ca1e76a8fa309ea518ca9eb055fdef9d39774815447311e4c3c73377c6cbfc5cef6477ab37373ff33052a34ef7f4b9baefcd99f1d5d5cbf71f5f7ecfcc6655cfff544daf3ffb69667638eae9def6cdb50d40e791a4fc04274aac7df1f840ecfc87bea3b350b4a5fba1787e420f42f1f8906e42d16b741b8a6e691b8a7e09e6f0323fc7eb0f42d179706e956a739afde62e146dde5cc8f93ab8487d49bf2774def65b4d1f0797b96e4c416f0757a9ceb4a1fb74ad2b23e73fd146175acecf68e7cdfe13ae87cb97fc0a9de94a8e23a52bdd9a92de129b8195f51cd1b5a9a3bfd28d56b1bf92567e3ed9bf535aeb26f67b41bbba5fcbfcb7c1755ae735af0f76e8526b23aee846d746f6eb9056a6b5d2df01ddfafee4f832ed8cb3355d0437a9298df4f318dd18b91e9b746933abe8bd60559b2caeff3adaca7c0968632a23f9fd6863a5df1bb12de2fc67b4f579997f8976b671d2ef46709b5a65a59f57baf2fdc97ed57463fc90f46a741bd7fb4c2babe3f963da5ae3647fcf8375660a53b17fde6f3a0fc5e3eb623fbfdc2f5774691b2bf335b4f2c7a59f5dda581dfb77b435b591e76731d8a42e73b27f0b74e9fa4eee8f6ff4c09696fde0e7c4b25fbf68edf3d2df88b6ae74f27c5d065b3e40f47d7411f30fb472ad53f23291420285f64df17f7a387acbc0c0c2e127ced1c14ce724e31317b8c42f5ce11a37fe7b4ce116b793cc1deef18011c678c4139ed1c5840e25ef0fbc62c12716b18465ace02b56b136c924f24ec137acfb3136b0892d6c6307bb18c655243217d6b0877d1ce0104738c6094e7126b34df5dcf9515264e8fb44eebf77ff59d718054a54feef853f67f03ec354871a4d82b03f18f8dfddfb0c73774982bbe12851e89236d16fa9c9387aea0a74d0ff5253e3e88f53b167eef9bbab3949c97b45f6fce319a732c9fb91980a73fdf93cf317e4bbac85</data>
+ </image>
+ <image name="image1">
+ <data format="XPM.GZ" length="646">789c6dd2c10ac2300c00d07bbf2234b7229d1be245fc04c5a3201e4615f430059d0711ff5ddb2e6bb236ec90eed134cb5a19d8ef36602af5ecdbfeeac05dda0798d3abebde87e3faa374d3807fa0d633a52d38d8de6f679fe33fc776e196f53cd010188256a3600a292882096246517815ca99884606e18044a3a40d91824820924265a7923a2e8bcd05f33db1173e002913175f2a6be6d3294871a2d95fa00e8a94ee017b69d339d90df1e77c57ea072ede6758</data>
+ </image>
+</images>
+<layoutdefaults spacing="6" margin="11"/>
+</UI>
diff --git a/kbugbuster/gui/cwbugdetails.cpp b/kbugbuster/gui/cwbugdetails.cpp
new file mode 100644
index 00000000..7aaf16a4
--- /dev/null
+++ b/kbugbuster/gui/cwbugdetails.cpp
@@ -0,0 +1,212 @@
+/*
+ cwbugdetails.cpp - Details of a bug report
+
+ copyright : (c) 2001 by Martijn Klingens
+ email : klingens@kde.org
+
+ *************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the 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 <qtextview.h>
+#include <qlineedit.h>
+#include <qcombobox.h>
+#include <qlabel.h>
+
+#include "cwbugdetails.h"
+#include "kbbprefs.h"
+#include "bugsystem.h"
+#include "bugserver.h"
+
+#include <khtml_part.h>
+#include <khtmlview.h>
+#include <kdebug.h>
+#include <kglobal.h>
+#include <krun.h>
+
+#include <qlayout.h>
+#include <qpalette.h>
+
+using namespace KBugBusterMainWindow;
+
+CWBugDetails::CWBugDetails( QWidget *parent , const char * name )
+ : QWidget( parent, name )
+{
+ QBoxLayout *topLayout = new QVBoxLayout( this );
+
+ m_bugDesc = new KHTMLPart( this, "m_bugDesc" );
+ connect( m_bugDesc->browserExtension(), SIGNAL( openURLRequest( const KURL &, const KParts::URLArgs & ) ),
+ this, SLOT( handleOpenURLRequest( const KURL &, const KParts::URLArgs & ) ) );
+
+ topLayout->addWidget( m_bugDesc->view() );
+}
+
+CWBugDetails::~CWBugDetails()
+{
+}
+
+void CWBugDetails::setBug( const Bug &bug, const BugDetails &details )
+{
+ QColorGroup cg = m_bugDesc->view()->palette().active();
+ QString text =
+ "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.0 Transitional//EN\">\n"
+ "<html><head><title></title></head>\n"
+ "<style>";
+
+ text.append(
+ QString( "table.helpT { text-align: center; font-family: Verdana; font-weight: normal; font-size: 11px; color: #404040; width: 100%; background-color: #fafafa; border: 1px #6699CC solid; border-collapse: collapse; border-spacing: 0px; }\n"
+ "td.helpHed { border-bottom: 2px solid #000000; border-left: 1px solid #000000; background-color: %1; text-align: center; text-indent: 5px; font-family: Verdana; font-weight: bold; font-size: 11px; color: %2; }\n"
+ "td.helpBod { border-bottom: 1px solid #9CF; border-top: 0px; border-left: 1px solid #9CF; border-right: 0px; text-align: center; text-indent: 10px; font-family: Verdana, sans-serif, Arial; font-weight: normal; font-size: 11px; color: #404040; background-color: #000000; }\n"
+ "table.sofT { text-align: center; font-family: Verdana; font-weight: normal; font-size: 11px; color: #404040; width: 100%; background-color: #fafafa; border: 1px #000000 solid; border-collapse: collapse; border-spacing: 0px; }\n"
+ "</style>\n" )
+ .arg( cg.highlight().name() )
+ .arg( cg.highlightedText().name() ) );
+
+ text.append( "<body style=\"margin: 0px\">\n" );
+
+ QString highlightStyle = QString( "background: %1; color: %2; " )
+ .arg( cg.highlight().name() )
+ .arg( cg.highlightedText().name() );
+ QString borderBottomStyle = QString( "border-bottom: solid %1 1px; " )
+ .arg( cg.foreground().name() );
+ QString borderTopStyle = QString( "border-top: solid %1 1px; " )
+ .arg( cg.foreground().name() );
+
+ QString submitter = bug.submitter().fullName( true );
+ int age = details.age();
+ text.append( "<div style=\"" + highlightStyle + "padding: 8px; float: left\">" );
+ text.append( "<a href=\"" + BugSystem::self()->server()->bugLink( bug ).url()
+ + "\">" + i18n("Bug Report</a> from <b>%1</b> " )
+ .arg( submitter ) );
+ int replies = details.parts().count() - 1;
+ if ( replies >= 1 ) text += i18n( "(1 reply)", "(%n replies)", replies );
+ text += "</div>";
+ text += "<div style=\"" + highlightStyle + borderBottomStyle +
+ " text-align: right; padding: 8px\">" +
+ i18n( "1 day old", "%n days old", age ) + "</div>\n";
+
+ text.append(
+ QString( "<div style=\"background: %1; color: %2; " +
+ borderBottomStyle +
+ "border-bottom: solid %3 1px; "
+ "padding: 4px\">"
+ "<table cellspacing=\"0\" cellpadding=\"4\" width=\"100%\">" )
+ .arg( cg.background().name() )
+ .arg( cg.foreground().name() ) );
+ text.append( textBugDetailsAttribute( details.version(), i18n("Version") ) );
+ text.append( textBugDetailsAttribute( details.source(), i18n("Source") ) );
+ text.append( textBugDetailsAttribute( details.compiler(), i18n("Compiler") ) );
+ text.append( textBugDetailsAttribute( details.os(), i18n("OS") ) );
+ text.append( "</table></div>\n" );
+
+ BugDetailsPart::List bdp = details.parts();
+ BugDetailsPart::List::ConstIterator it;
+ bool firstHeader = true;
+
+ for ( it = bdp.begin(); it != bdp.end(); ++it ) {
+ if ( bdp.count() > 1 ) {
+ text.append( "<div style=\"" + highlightStyle + "padding: 8px; float: left; " );
+ if ( !firstHeader ) text += borderTopStyle;
+
+ text.append( borderBottomStyle + "\">" );
+ QString sender = (*it).sender.fullName( true );
+ QString date = KGlobal::locale()->formatDateTime( (*it).date, false );
+ BugDetailsPart::List::ConstIterator it2 = it;
+ if ( ++it2 == bdp.end() )
+ text.append( "<a href=\"" + BugSystem::self()->server()->bugLink( bug ).url()
+ + "\">" + i18n("Bug Report</a> from <b>%1</b>")
+ .arg( sender ) );
+ else {
+ text.append( "<a href=\"" + BugSystem::self()->server()->bugLink( bug ).url() + QString("#c%1").arg( replies )
+ + "\">" + i18n("Reply #%1</a> from <b>%2</b>")
+ .arg( replies ).arg( sender ) );
+ replies--;
+ }
+ text.append( "</div>\n" );
+ text += "<div style=\"" + highlightStyle + borderBottomStyle;
+ if ( !firstHeader ) text += borderTopStyle;
+ text += "text-align: right; padding: 8px\">" + date + "</div>\n";
+
+ firstHeader = false;
+ }
+
+ // Adding of <pre> tags is now done by BugDetailsJob::processNode. This
+ // was breaking the display of attachments because they have <br/>\n
+ // after each line -> two newlines with <pre>
+ text.append( "<div style=\"padding: 8px\">" );
+ text.append( (*it).text );
+ text.append( "</div>\n" );
+ }
+
+ QValueList<BugDetailsImpl::AttachmentDetails> atts = details.attachmentDetails();
+ if ( atts.count() > 0 ) {
+ text.append( "<table summary=\"Attachment data table\" class=\"sofT\" cellspacing=\"0\">" );
+ text.append( QString( "<tr> <td colspan=\"4\" class=\"helpHed\">%1</td> </tr>")
+ .arg( i18n( "Attachment List") ) );
+ text.append( QString("<tr> <td class=\"helpHed\">%1</td> <td class=\"helpHed\">%2</td> <td class=\"helpHed\">%3</td> <td class=\"helpHed\">%4</td> </tr>")
+ .arg( i18n("Description") )
+ .arg( i18n("Date") )
+ .arg( i18n("View") )
+ .arg( i18n("Edit") ) );
+ QValueList<BugDetailsImpl::AttachmentDetails>::iterator it;
+ for ( it = atts.begin() ; it != atts.end() ; ++it ) {
+ text.append( QString("<tr><td>%1</td>").arg( (*it).description ) ) ;
+ text.append( QString("<td>%1</td>").arg( (*it).date ) );
+ text.append( "<td><a href=\"" +
+ BugSystem::self()->server()->attachmentViewLink( (*it).id ).url() +
+ "\">" + i18n("View") + "</a></td>" );
+ text.append( "<td><a href=\"" +
+ BugSystem::self()->server()->attachmentEditLink( (*it).id ).url() +
+ "\">" + i18n("Edit") + "</a></td>" );
+ text.append( "</tr>" );
+ }
+ }
+
+ text.append( "</body></html>" );
+
+ //kdDebug() << "BEGIN OUTPUT" << text << "END OUTPUT" << endl;
+
+ m_bugDesc->view()->setContentsPos(0,0);
+ m_bugDesc->begin();
+ m_bugDesc->write( text );
+ m_bugDesc->end();
+
+ if ( KBBPrefs::instance()->mDebugMode ) mSource = text;
+}
+
+void CWBugDetails::handleOpenURLRequest( const KURL &url, const KParts::URLArgs & )
+{
+ new KRun( url );
+}
+
+QString CWBugDetails::textBugDetailsAttribute( const QString &value,
+ const QString &name )
+{
+ QString text = "";
+ if ( !value.isEmpty() ) {
+ text.append( "<tr><td style=\"width: 20%\"><b>" + name + "</b></td>"
+ "<td>" + value + "</td></tr>" );
+ }
+ return text;
+}
+
+QString CWBugDetails::source() const
+{
+ return mSource;
+}
+
+QString CWBugDetails::selectedText() const
+{
+ return m_bugDesc->selectedText();
+}
+
+#include "cwbugdetails.moc"
+
+/* vim: set et ts=4 sw=4 softtabstop=4: */
+
diff --git a/kbugbuster/gui/cwbugdetails.h b/kbugbuster/gui/cwbugdetails.h
new file mode 100644
index 00000000..31a5339f
--- /dev/null
+++ b/kbugbuster/gui/cwbugdetails.h
@@ -0,0 +1,65 @@
+/*
+ cwbugdetails.h - Details of a bug report
+
+ copyright : (c) 2001 by Martijn Klingens
+ email : klingens@kde.org
+
+ *************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the 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 KBBMAINWINDOW_CWBUGDETAILS_H
+#define KBBMAINWINDOW_CWBUGDETAILS_H
+
+#include "bug.h"
+#include "bugdetails.h"
+
+#include <qwidget.h>
+
+#include <kparts/browserextension.h>
+
+class KHTMLPart;
+
+namespace KBugBusterMainWindow
+{
+
+/**
+ * @author Martijn Klingens
+ */
+class CWBugDetails : public QWidget
+{
+ Q_OBJECT
+
+ public:
+ CWBugDetails( QWidget* parent = 0, const char* name = 0 );
+ ~CWBugDetails();
+
+ void setBug( const Bug &, const BugDetails & );
+
+ QString source() const;
+ QString selectedText() const;
+
+ private slots:
+ void handleOpenURLRequest( const KURL &url, const KParts::URLArgs & );
+
+ private:
+ QString textBugDetailsAttribute( const QString &value,
+ const QString &name );
+
+ KHTMLPart *m_bugDesc;
+
+ QString mSource;
+};
+
+} // namespace
+
+#endif
+
+/* vim: set et ts=4 softtabstop=4 sw=4: */
+
diff --git a/kbugbuster/gui/cwbugdetailscontainer.cpp b/kbugbuster/gui/cwbugdetailscontainer.cpp
new file mode 100644
index 00000000..b33ec3b1
--- /dev/null
+++ b/kbugbuster/gui/cwbugdetailscontainer.cpp
@@ -0,0 +1,269 @@
+/*
+ cwbugdetailscontainer.cpp - Container for bug details
+
+ copyright : (c) 2001 by Martijn Klingens
+ email : klingens@kde.org
+
+ *************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the 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 <qpushbutton.h>
+#include <qwidgetstack.h>
+#include <qlayout.h>
+#include <qtooltip.h>
+
+#include <kiconloader.h>
+#include <klocale.h>
+#include <kactivelabel.h>
+#include <kdialog.h>
+
+#include "bugsystem.h"
+#include "bugcommand.h"
+#include "bugserver.h"
+
+#include "cwbugdetails.h"
+#include "cwloadingwidget.h"
+
+#include "cwbugdetailscontainer.h"
+#include <kstringhandler.h>
+
+using namespace KBugBusterMainWindow;
+
+CWBugDetailsContainer::CWBugDetailsContainer( QWidget *parent , const char * name )
+: CWBugDetailsContainer_Base( parent, name )
+{
+ // Do some stuff Designer can't do:
+ m_bugCloseBtn->setIconSet( BarIconSet( "edittrash" ) );
+ m_bugCloseSilentlyBtn->setIconSet( BarIconSet( "edittrash" ) );
+ m_bugReopenBtn->setIconSet( SmallIconSet( "idea" ) );
+ m_bugReassignBtn->setIconSet( BarIconSet( "folder_new" ) );
+ m_bugTitleBtn->setIconSet( SmallIconSet( "text_under" ) );
+ m_bugSeverityBtn->setIconSet( SmallIconSet( "edit" ) );
+ m_bugReplyBtn->setIconSet( SmallIconSet( "mail_replyall" ) );
+ m_bugReplyPrivBtn->setIconSet( SmallIconSet( "mail_reply" ) );
+
+ // The Bugzilla mail interface doesn't support all commands yet.
+ m_bugCloseSilentlyBtn->hide();
+ m_bugReassignBtn->hide();
+ m_bugTitleBtn->hide();
+ m_bugSeverityBtn->hide();
+
+ // Create Bug Details pane
+ m_bugDetails = new CWBugDetails( m_bugStack );
+
+ // Fill WidgetStack in Bug Details pane
+ m_bugLoading = new CWLoadingWidget( CWLoadingWidget::BottomFrame,
+ m_bugStack );
+ connect( m_bugLoading, SIGNAL( clicked() ), SIGNAL( searchBugNumber() ) );
+
+ m_bugStack->addWidget( m_bugDetails, 0 );
+ m_bugStack->addWidget( m_bugLoading, 1 );
+
+ setNoBug();
+
+ QFont f = m_bugLabel->font();
+ f.setBold( true );
+ m_bugLabel->setFont( f );
+
+ // Set fonts and margins
+ CWBugDetailsContainer_BaseLayout->setSpacing( KDialog::spacingHint() );
+ CWBugDetailsContainer_BaseLayout->setMargin( KDialog::marginHint() );
+
+ connect( m_bugCloseBtn, SIGNAL( clicked() ), SIGNAL( signalCloseBug() ) );
+ connect( m_bugCloseSilentlyBtn, SIGNAL( clicked() ), SIGNAL( signalCloseBugSilently() ) );
+ connect( m_bugReopenBtn, SIGNAL( clicked() ), SIGNAL( signalReopenBug() ) );
+ connect( m_bugReassignBtn, SIGNAL( clicked() ), SIGNAL( signalReassignBug() ) );
+ connect( m_bugTitleBtn, SIGNAL( clicked() ), SIGNAL( signalTitleBug() ) );
+ connect( m_bugSeverityBtn, SIGNAL( clicked() ), SIGNAL( signalSeverityBug() ) );
+ connect( m_bugReplyBtn, SIGNAL( clicked() ), SIGNAL( signalReplyBug() ) );
+ connect( m_bugReplyPrivBtn, SIGNAL( clicked() ), SIGNAL( signalReplyPrivateBug() ) );
+
+ connect( m_cmdClearBtn, SIGNAL( clicked() ), SIGNAL( signalClearCommand() ) );
+
+ connect( BugSystem::self(), SIGNAL( bugDetailsLoading( const Bug & ) ),
+ SLOT( setLoading( const Bug & ) ) );
+ connect( BugSystem::self(), SIGNAL( bugDetailsCacheMiss( const Bug & ) ),
+ SLOT( setCacheMiss( const Bug & ) ) );
+ connect( BugSystem::self(), SIGNAL( commandQueued( BugCommand * ) ),
+ SLOT( commandQueued( BugCommand * ) ) );
+ connect( BugSystem::self(), SIGNAL( commandCanceled( const QString & ) ),
+ SLOT( clearCommand( const QString & ) ) );
+}
+
+CWBugDetailsContainer::~CWBugDetailsContainer()
+{
+}
+
+void CWBugDetailsContainer::setBug( const Bug &bug, const BugDetails &details )
+{
+ m_bug = bug;
+ m_bugDetails->setBug( bug, details );
+
+ QString labelText;
+
+ if ( bug.mergedWith().size() )
+ {
+ //FIXME: What should the separator be for lists? Don't see anything in KLocale for that
+ QString list;
+ Bug::BugMergeList mergedWith = bug.mergedWith();
+ for (Bug::BugMergeList::ConstIterator i = mergedWith.begin(); i != mergedWith.end(); ++i)
+ {
+ list += QString::number(*i)+", ";
+ }
+
+ list.truncate( list.length()-2 ); //Strip off the last ", "
+
+ labelText = i18n("bug #number [Merged with: a list of bugs] (severity): title","Bug #%1 [Merged with: %2] (%3): %4")
+ .arg( bug.number() )
+ .arg( list )
+ .arg( bug.severityAsString() )
+ .arg( bug.title() );
+
+ }
+ else
+ {
+ labelText = i18n("bug #number (severity): title","Bug #%1 (%2): %3")
+ .arg( bug.number() ).arg( bug.severityAsString() )
+ .arg( bug.title() );
+ }
+
+ m_bugLabel->setText( KStringHandler::tagURLs( labelText ) );
+
+ showCommands( bug );
+
+ enableButtons( bug );
+
+ m_bugStack->raiseWidget( 0 );
+ emit resetProgressBar();
+}
+
+void CWBugDetailsContainer::showCommands( const Bug& bug )
+{
+ QPtrList<BugCommand> commands = BugSystem::self()->server()->queryCommands( bug );
+ if ( !commands.isEmpty() ) {
+ QString cmdDetails;
+ QString cmdText = i18n("Pending commands:")+" ";
+ bool first = true;
+ QPtrListIterator<BugCommand> cmdIt( commands );
+ for( ; cmdIt.current(); ++cmdIt )
+ {
+ BugCommand *cmd = cmdIt.current();
+ if (!first)
+ cmdText += " | "; // separator in case of multiple commands
+ first = false;
+ cmdText += QString("<b>%1</b>").arg( cmd->name() );
+ if (!cmdDetails.isEmpty())
+ cmdDetails += " | "; // separator in case of multiple commands
+ cmdDetails += cmd->details();
+ }
+ // Set summary as text label, details into tooltip
+ m_cmdLabel->setText( cmdText );
+ if ( !cmdDetails.isEmpty() ) {
+ QToolTip::add( m_cmdLabel, cmdDetails );
+ } else {
+ QToolTip::remove( m_cmdLabel );
+ }
+ m_cmdLabel->show();
+ } else {
+ hideCommands();
+ }
+}
+
+void CWBugDetailsContainer::hideCommands()
+{
+ m_cmdLabel->hide();
+}
+
+void CWBugDetailsContainer::clearCommand( const QString &bug )
+{
+ if ( bug == m_bug.number() )
+ showCommands( m_bug );
+}
+
+void CWBugDetailsContainer::commandQueued( BugCommand *cmd )
+{
+ // ### use == operator instead?
+ // (might not work because impl is different)
+ if ( cmd && cmd->bug().number() == m_bug.number() )
+ showCommands( m_bug );
+}
+
+void CWBugDetailsContainer::setNoBug()
+{
+ m_bugLabel->setText( i18n("Bug Title") );
+
+ m_bug = Bug();
+ showCommands( m_bug );
+
+ m_bugLoading->setText( i18n( "Click here to select a bug by number" ) );
+ m_bugStack->raiseWidget( 1 );
+}
+
+void CWBugDetailsContainer::setLoading( const Bug &bug )
+{
+ m_bug = bug;
+ showCommands( bug );
+
+ m_bugLoading->setText(i18n( "Retrieving Details for Bug %1\n\n(%2)" )
+ .arg( bug.number() ).arg( bug.title() ) );
+ m_bugStack->raiseWidget( 1 );
+}
+
+void CWBugDetailsContainer::setCacheMiss( const Bug &bug )
+{
+ m_bug = bug;
+ showCommands( bug );
+
+ QString msg;
+ if( BugSystem::self()->disconnected() )
+ msg = i18n( "Bug #%1 (%2) is not available offline." ).
+ arg( bug.number() ).arg( bug.title() );
+ else
+ msg = i18n( "Retrieving details for bug #%1\n"
+ "(%2)" ).
+ arg( bug.number() ).arg( bug.title() );
+ m_bugLoading->setText( msg );
+ m_bugStack->raiseWidget( 1 );
+}
+
+
+void CWBugDetailsContainer::enableButtons( const Bug &bug )
+{
+ if( bug.isNull() ) {
+ m_bugCloseBtn->setEnabled( false );
+ m_bugCloseSilentlyBtn->setEnabled( false );
+ m_bugReopenBtn->setEnabled( false );
+ m_bugReassignBtn->setEnabled( false );
+ m_bugTitleBtn->setEnabled( false );
+ m_bugSeverityBtn->setEnabled( false );
+ m_bugReplyBtn->setEnabled( false );
+ m_bugReplyPrivBtn->setEnabled( false );
+ } else {
+ if( bug.status() != Bug::Closed ) {
+ m_bugCloseBtn->setEnabled( true );
+ m_bugCloseSilentlyBtn->setEnabled( true );
+ m_bugReopenBtn->setEnabled( false );
+ } else {
+ m_bugCloseBtn->setEnabled( false );
+ m_bugCloseSilentlyBtn->setEnabled( false );
+ m_bugReopenBtn->setEnabled( true );
+ }
+ m_bugReassignBtn->setEnabled( true );
+ m_bugTitleBtn->setEnabled( true );
+ m_bugSeverityBtn->setEnabled( true );
+ m_bugReplyBtn->setEnabled( true );
+ m_bugReplyPrivBtn->setEnabled( true );
+ }
+}
+
+#include "cwbugdetailscontainer.moc"
+
+/* vim: set et ts=4 sw=4 softtabstop=4: */
+
diff --git a/kbugbuster/gui/cwbugdetailscontainer.h b/kbugbuster/gui/cwbugdetailscontainer.h
new file mode 100644
index 00000000..c183a8ea
--- /dev/null
+++ b/kbugbuster/gui/cwbugdetailscontainer.h
@@ -0,0 +1,88 @@
+/*
+ cwbugdetailscontainer.h - Container for bug details
+
+ copyright : (c) 2001 by Martijn Klingens
+ email : klingens@kde.org
+
+ *************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the 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 KBBMAINWINDOW_CWBUGDETAILSCONTAINER_H
+#define KBBMAINWINDOW_CWBUGDETAILSCONTAINER_H
+
+#include "bug.h"
+#include "bugdetails.h"
+
+#include "cwbugdetailscontainer_base.h"
+
+class BugCommand;
+
+namespace KBugBusterMainWindow
+{
+
+class CWBugDetails;
+class CWLoadingWidget;
+
+/**
+ * @author Martijn Klingens
+ */
+class CWBugDetailsContainer : public CWBugDetailsContainer_Base
+{
+ Q_OBJECT
+
+public:
+ CWBugDetailsContainer( QWidget* parent = 0, const char* name = 0 );
+ ~CWBugDetailsContainer();
+
+ void setBug( const Bug &, const BugDetails & );
+
+ CWBugDetails *bugDetailsWidget() { return m_bugDetails; }
+
+public slots:
+ void setNoBug();
+ void setLoading( const Bug &bug );
+ void setCacheMiss( const Bug &bug );
+
+ void enableButtons( const Bug & );
+
+signals:
+ void resetProgressBar();
+ void searchBugNumber();
+
+ void signalCloseBug();
+ void signalCloseBugSilently();
+ void signalReopenBug();
+ void signalReassignBug();
+ void signalTitleBug();
+ void signalSeverityBug();
+ void signalReplyBug();
+ void signalReplyPrivateBug();
+
+ void signalClearCommand();
+
+private slots:
+ void showCommands( const Bug & );
+ void clearCommand( const QString & );
+ void commandQueued( BugCommand * );
+
+private:
+ void hideCommands();
+
+ CWLoadingWidget *m_bugLoading;
+ CWBugDetails *m_bugDetails;
+ Bug m_bug;
+};
+
+} // namespace
+
+#endif
+
+/* vim: set et ts=4 softtabstop=4 sw=4: */
+
diff --git a/kbugbuster/gui/cwbugdetailscontainer_base.ui b/kbugbuster/gui/cwbugdetailscontainer_base.ui
new file mode 100644
index 00000000..c5ef87b7
--- /dev/null
+++ b/kbugbuster/gui/cwbugdetailscontainer_base.ui
@@ -0,0 +1,244 @@
+<!DOCTYPE UI><UI version="3.0" stdsetdef="1">
+<class>CWBugDetailsContainer_Base</class>
+<widget class="QWidget">
+ <property name="name">
+ <cstring>CWBugDetailsContainer_Base</cstring>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>507</width>
+ <height>559</height>
+ </rect>
+ </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="QWidgetStack" row="1" column="0">
+ <property name="name">
+ <cstring>m_bugStack</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>7</hsizetype>
+ <vsizetype>7</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ </widget>
+ <widget class="QLayoutWidget" row="0" column="0">
+ <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>0</number>
+ </property>
+ <widget class="KActiveLabel">
+ <property name="name">
+ <cstring>m_bugLabel</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>7</hsizetype>
+ <vsizetype>0</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="minimumSize">
+ <size>
+ <width>100</width>
+ <height>20</height>
+ </size>
+ </property>
+ <property name="text">
+ <string>Bug Title</string>
+ </property>
+ </widget>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>m_cmdLabel</cstring>
+ </property>
+ <property name="text">
+ <string>Bug Commands</string>
+ </property>
+ </widget>
+ </vbox>
+ </widget>
+ <widget class="QLayoutWidget" row="1" column="1">
+ <property name="name">
+ <cstring>Layout3</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="QPushButton">
+ <property name="name">
+ <cstring>m_cmdClearBtn</cstring>
+ </property>
+ <property name="text">
+ <string>Clear Co&amp;mmands</string>
+ </property>
+ </widget>
+ <spacer>
+ <property name="name">
+ <cstring>Spacer1</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Vertical</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ </spacer>
+ <widget class="QPushButton">
+ <property name="name">
+ <cstring>m_bugCloseBtn</cstring>
+ </property>
+ <property name="enabled">
+ <bool>false</bool>
+ </property>
+ <property name="text">
+ <string>C&amp;lose...</string>
+ </property>
+ </widget>
+ <widget class="QPushButton">
+ <property name="name">
+ <cstring>m_bugCloseSilentlyBtn</cstring>
+ </property>
+ <property name="enabled">
+ <bool>false</bool>
+ </property>
+ <property name="text">
+ <string>Close Silentl&amp;y</string>
+ </property>
+ </widget>
+ <widget class="QPushButton">
+ <property name="name">
+ <cstring>m_bugReopenBtn</cstring>
+ </property>
+ <property name="enabled">
+ <bool>false</bool>
+ </property>
+ <property name="text">
+ <string>Re&amp;open</string>
+ </property>
+ </widget>
+ <widget class="QPushButton">
+ <property name="name">
+ <cstring>m_bugReassignBtn</cstring>
+ </property>
+ <property name="enabled">
+ <bool>false</bool>
+ </property>
+ <property name="text">
+ <string>Re&amp;assign...</string>
+ </property>
+ </widget>
+ <widget class="QPushButton">
+ <property name="name">
+ <cstring>m_bugTitleBtn</cstring>
+ </property>
+ <property name="enabled">
+ <bool>false</bool>
+ </property>
+ <property name="text">
+ <string>Change &amp;Title...</string>
+ </property>
+ </widget>
+ <widget class="QPushButton">
+ <property name="name">
+ <cstring>m_bugSeverityBtn</cstring>
+ </property>
+ <property name="enabled">
+ <bool>false</bool>
+ </property>
+ <property name="text">
+ <string>Chan&amp;ge Severity...</string>
+ </property>
+ </widget>
+ <spacer>
+ <property name="name">
+ <cstring>Spacer1_2</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Vertical</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ </spacer>
+ <widget class="QPushButton">
+ <property name="name">
+ <cstring>m_bugReplyBtn</cstring>
+ </property>
+ <property name="enabled">
+ <bool>false</bool>
+ </property>
+ <property name="text">
+ <string>&amp;Reply...</string>
+ </property>
+ </widget>
+ <widget class="QPushButton">
+ <property name="name">
+ <cstring>m_bugReplyPrivBtn</cstring>
+ </property>
+ <property name="enabled">
+ <bool>false</bool>
+ </property>
+ <property name="text">
+ <string>Reply &amp;Privately...</string>
+ </property>
+ </widget>
+ </vbox>
+ </widget>
+ </grid>
+</widget>
+<customwidgets>
+ <customwidget>
+ <class>QWidgetStack</class>
+ <header location="global">qwidgetstack.h</header>
+ <sizehint>
+ <width>-1</width>
+ <height>-1</height>
+ </sizehint>
+ <container>1</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="XPM.GZ" length="646">789c6dd2c10ac2300c00d07bbf2234b7229d1ddec44f503c0ae2a154410f53d0ed20e2bf6bdb656dd6861dd23d9a66591b0587fd1654235ebded6f0edcd53e419d87ae7b1f4f9b8f906d0bfe012317426a70b07bdc2f3ec77f8ed6b89559061a0343d06a124cc105596482585094bc0ae599b04646c9018926491b2205e140c485cace25755c175d0a967b622ff900b8cc9c7d29af594ea722d589167f813aa852ba07d94b9dce296e883fe7bb163f23896753</data>
+ </image>
+</images>
+<layoutdefaults spacing="6" margin="11"/>
+</UI>
diff --git a/kbugbuster/gui/cwbuglistcontainer.cpp b/kbugbuster/gui/cwbuglistcontainer.cpp
new file mode 100644
index 00000000..0188a996
--- /dev/null
+++ b/kbugbuster/gui/cwbuglistcontainer.cpp
@@ -0,0 +1,328 @@
+/*
+ cwbuglistcontainer.cpp - Container for the bug list
+
+ copyright : (c) 2001 by Martijn Klingens
+ email : klingens@kde.org
+
+ *************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the 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 <qpushbutton.h>
+#include <qlabel.h>
+#include <qlayout.h>
+#include <qwidgetstack.h>
+
+#include <kapplication.h>
+#include <kiconloader.h>
+#include <klistview.h>
+#include <klocale.h>
+#include <kdialog.h>
+#if KDE_IS_VERSION( 3, 2, 90 )
+#include <klistviewsearchline.h>
+#endif
+#include <kdebug.h>
+
+#include "bugsystem.h"
+
+#include "cwloadingwidget.h"
+#include "buglvi.h"
+#include "kbbprefs.h"
+#include "kfind.h"
+
+#include "cwbuglistcontainer.h"
+#include <kfinddialog.h>
+
+using namespace KBugBusterMainWindow;
+
+CWBugListContainer::CWBugListContainer( QWidget *parent , const char * name )
+ : QWidget( parent, name ), m_find(0), m_findItem(0)
+{
+ QBoxLayout *topLayout = new QVBoxLayout( this );
+ topLayout->setSpacing( KDialog::spacingHint() );
+ topLayout->setMargin( KDialog::marginHint() );
+
+ m_listLabel = new QLabel( this );
+ topLayout->addWidget( m_listLabel );
+ topLayout->setStretchFactor( m_listLabel, 0 );
+
+ QFont f = m_listLabel->font();
+ f.setBold( true );
+ m_listLabel->setFont( f );
+
+ m_listStack = new QWidgetStack( this );
+
+ // Create Outstanding Bugs listview
+ m_listBugs = new KListView( m_listStack );
+
+ topLayout->addWidget( new KListViewSearchLineWidget( m_listBugs, this ) );
+ topLayout->addWidget( m_listStack );
+ topLayout->setStretchFactor( m_listStack, 1 );
+
+ m_listBugs->addColumn( i18n( "Number" ) );
+ m_listBugs->addColumn( i18n( "Age" ) );
+ m_listBugs->addColumn( i18n( "Title" ), 500 ); // so that the widthmode isn't "Maximum"
+ m_listBugs->addColumn( i18n( "Status" ) );
+ m_listBugs->addColumn( i18n( "Severity" ) );
+ m_listBugs->addColumn( i18n( "Sender" ), 150 ); // idem. hardcoded widths suck a bit, but...
+ m_listBugs->setAllColumnsShowFocus( true );
+ m_listBugs->setColumnAlignment( 0, AlignRight );
+ m_listBugs->setSorting( 0, false );
+ m_listBugs->setShowSortIndicator( true );
+ m_listBugs->setSelectionMode( QListView::Extended ); // needed for merging bugs
+
+ m_listBugs->restoreLayout( KBBPrefs::instance()->config(), "BugListLayout" );
+
+ connect( m_listBugs, SIGNAL( executed( QListViewItem * ) ),
+ SLOT( execute( QListViewItem * ) ) );
+ connect( m_listBugs, SIGNAL( returnPressed( QListViewItem * ) ),
+ SLOT( execute( QListViewItem * ) ) );
+ connect( m_listBugs, SIGNAL( currentChanged( QListViewItem * ) ),
+ SLOT( changeCurrent( QListViewItem * ) ) );
+
+ // Fill WidgetStack in Outstanding Bugs pane
+ m_listLoading = new CWLoadingWidget( CWLoadingWidget::TopFrame,
+ m_listStack );
+ connect( m_listLoading, SIGNAL( clicked() ), SIGNAL( searchPackage() ) );
+
+ m_listStack->addWidget( m_listBugs, 0 );
+ m_listStack->addWidget( m_listLoading, 1 );
+
+ setNoList();
+
+ connect( BugSystem::self(), SIGNAL( bugListLoading( const Package &, const QString & ) ),
+ SLOT( setLoading( const Package &, const QString & ) ) );
+ connect( BugSystem::self(), SIGNAL( bugListLoading( const QString & ) ),
+ SLOT( setLoading( const QString & ) ) );
+ connect( BugSystem::self(), SIGNAL( bugListCacheMiss( const Package & ) ),
+ SLOT( setCacheMiss( const Package & ) ) );
+ connect( BugSystem::self(), SIGNAL( bugListCacheMiss( const QString & ) ),
+ SLOT( setCacheMiss( const QString & ) ) );
+ connect( BugSystem::self(), SIGNAL( commandQueued( BugCommand * ) ),
+ SLOT( markBugCommand( BugCommand * ) ) );
+ connect( BugSystem::self(), SIGNAL( commandCanceled( const QString & ) ),
+ SLOT( clearCommand( const QString & ) ) );
+}
+
+CWBugListContainer::~CWBugListContainer()
+{
+ m_listBugs->saveLayout( KBBPrefs::instance()->config(), "BugListLayout" );
+ KBBPrefs::instance()->writeConfig();
+ delete m_find;
+}
+
+void CWBugListContainer::setBugList( const QString &label, const Bug::List &bugs )
+{
+ // List pane is invisible by default, make visible
+ show();
+
+ m_listBugs->clear();
+ emit resetProgressBar();
+ bool showClosed = KBBPrefs::instance()->mShowClosedBugs;
+ bool showWishes = KBBPrefs::instance()->mShowWishes;
+ uint noBugs = 0;
+ uint noWishes = 0;
+
+ for ( Bug::List::ConstIterator it = bugs.begin(); it != bugs.end(); ++it )
+ {
+ if ( ( *it ).status() != Bug::Closed || showClosed )
+ {
+ if ( ( *it ).severity() != Bug::Wishlist || showWishes )
+ new BugLVI( m_listBugs, *it );
+
+ if ( ( *it ).severity() != Bug::Wishlist )
+ noBugs++;
+ else
+ noWishes++;
+ }
+ }
+
+ m_listLabel->setText( i18n( "%1 (%2 bugs, %3 wishes)" ).arg( label ).arg( noBugs ).arg( noWishes ) );
+ m_listStack->raiseWidget( 0 );
+}
+
+void CWBugListContainer::setBugList( const Package &package, const QString &component, const Bug::List &bugs )
+{
+ QString listLabel;
+ if ( component.isEmpty() )
+ {
+ if ( package.components().count() > 1 )
+ listLabel = i18n( "Product '%1', all components" ).arg( package.name() );
+ else
+ listLabel = i18n( "Product '%1'" ).arg( package.name() );
+ }
+ else
+ {
+ listLabel = i18n( "Product '%1', component '%2'" ).arg( package.name(), component );
+ }
+
+ setBugList( listLabel, bugs );
+}
+
+void CWBugListContainer::execute( QListViewItem *lvi )
+{
+ BugLVI *item = dynamic_cast<BugLVI *>( lvi );
+ if( !item )
+ {
+ kdWarning() << "CWBugListContainer::execute() Selected bug "
+ << lvi->text( 0 )
+ << " is not a BugLVI! Ignoring event." << endl;
+ return;
+ }
+
+ emit executed( item->bug() );
+}
+
+void CWBugListContainer::changeCurrent( QListViewItem *lvi )
+{
+ if( !lvi ) {
+ emit currentChanged( Bug() );
+ return;
+ }
+
+ BugLVI *item = dynamic_cast<BugLVI *>( lvi );
+ if( !item )
+ {
+ kdWarning() << "CWBugListContainer::changeCurrent() Selected bug "
+ << lvi->text( 0 )
+ << " is not a BugLVI! Ignoring event." << endl;
+ return;
+ }
+
+ emit currentChanged( item->bug() );
+}
+
+void CWBugListContainer::setNoList()
+{
+ m_listLabel->setText( i18n("Outstanding Bugs") );
+ m_listLoading->setText( i18n( "Click here to select a product" ) );
+ m_listStack->raiseWidget( 1 );
+}
+
+void CWBugListContainer::setLoading( const Package &package, const QString &component )
+{
+ if ( component.isEmpty() )
+ setLoading( i18n( "Retrieving List of Outstanding Bugs for Product '%1'..." ).arg( package.name() ) );
+ else
+ setLoading( i18n( "Retrieving List of Outstanding Bugs for Product '%1' (Component %2)..." ).arg( package.name(), component ) );
+}
+
+void CWBugListContainer::setLoading( const QString &label )
+{
+ m_listLoading->setText( label );
+ m_listStack->raiseWidget( 1 );
+}
+
+void CWBugListContainer::setCacheMiss( const Package &package )
+{
+ setCacheMiss( i18n( "Package '%1'" ).arg( package.name() ) );
+}
+
+void CWBugListContainer::setCacheMiss( const QString &label )
+{
+ m_listLoading->setText( i18n( "%1 is not available offline." ).arg( label ) );
+ m_listStack->raiseWidget( 1 );
+}
+
+void CWBugListContainer::markBugCommand( BugCommand *cmd )
+{
+ BugLVI *item = (BugLVI *)m_listBugs->firstChild();
+ while( item ) {
+ if ( item->bug().number() == cmd->bug().number() ) {
+ item->setCommandState( BugCommand::Queued );
+ break;
+ }
+ item = (BugLVI *)item->nextSibling();
+ }
+ m_listBugs->triggerUpdate();
+}
+
+void CWBugListContainer::clearCommand( const QString &bug )
+{
+ BugLVI *item = (BugLVI *)m_listBugs->firstChild();
+ while( item ) {
+ if ( item->bug().number() == bug ) {
+ item->setCommandState( BugCommand::None );
+ break;
+ }
+ item = (BugLVI *)item->nextSibling();
+ }
+ m_listBugs->triggerUpdate();
+}
+
+void CWBugListContainer::searchBugByTitle( int options, const QString& pattern )
+{
+ m_find = new KFind( pattern, options, this );
+ // Connect signals to code which handles highlighting
+ // of found text.
+ connect(m_find, SIGNAL( highlight( const QString &, int, int ) ),
+ this, SLOT( searchHighlight( const QString &, int, int ) ) );
+ connect(m_find, SIGNAL( findNext() ), this, SLOT( slotFindNext() ) );
+
+ m_findItem = (BugLVI *)m_listBugs->firstChild();
+ if ( options & KFindDialog::FromCursor && m_listBugs->currentItem() )
+ m_findItem = (BugLVI *)m_listBugs->currentItem();
+
+ slotFindNext();
+}
+
+// Note: if a 'find next' action is added, then one should also ensure
+// that m_findItem never becomes dangling (i.e. clear it when clearing the listview).
+void CWBugListContainer::slotFindNext()
+{
+ KFind::Result res = KFind::NoMatch;
+ while( res == KFind::NoMatch && m_findItem ) {
+
+ if ( m_find->needData() )
+ m_find->setData( m_findItem->text(2) );
+
+ // Let KFind inspect the text fragment, and display a dialog if a match is found
+ res = m_find->find();
+
+ if ( res == KFind::NoMatch ) {
+ if ( m_find->options() & KFindDialog::FindBackwards )
+ m_findItem = (BugLVI *)m_findItem->itemAbove();
+ else
+ m_findItem = (BugLVI *)m_findItem->itemBelow();
+ }
+ }
+ if ( res == KFind::NoMatch ) // i.e. at end
+ if ( m_find->shouldRestart() ) {
+ m_findItem = (BugLVI *)m_listBugs->firstChild();
+ slotFindNext();
+ } else {
+ delete m_find;
+ m_find = 0L;
+ }
+}
+
+void CWBugListContainer::searchHighlight( const QString &, int, int )
+{
+ if ( m_findItem ) {
+ m_listBugs->clearSelection();
+ m_listBugs->setSelected( m_findItem, true );
+ m_listBugs->ensureItemVisible( m_findItem );
+ }
+}
+
+QStringList CWBugListContainer::selectedBugs() const
+{
+ QStringList lst;
+ BugLVI *item = (BugLVI *)m_listBugs->firstChild();
+ while( item ) {
+ if ( item->isSelected() )
+ lst.append( item->bug().number() );
+ item = (BugLVI *)item->nextSibling();
+ }
+ return lst;
+}
+
+#include "cwbuglistcontainer.moc"
+
+/* vim: set et ts=4 sw=4 softtabstop=4: */
diff --git a/kbugbuster/gui/cwbuglistcontainer.h b/kbugbuster/gui/cwbuglistcontainer.h
new file mode 100644
index 00000000..bcda4c15
--- /dev/null
+++ b/kbugbuster/gui/cwbuglistcontainer.h
@@ -0,0 +1,99 @@
+/*
+ cwbuglistcontainer.h - Container for the bug list
+
+ copyright : (c) 2001 by Martijn Klingens
+ email : klingens@kde.org
+
+ *************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the 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 KBBMAINWINDOW_CWBUGLISTCONTAINER_H
+#define KBBMAINWINDOW_CWBUGLISTCONTAINER_H
+
+#include "package.h"
+#include "bug.h"
+
+#include <qwidget.h>
+
+class KListView;
+class KFind;
+class BugCommand;
+class BugLVI;
+
+namespace KBugBusterMainWindow
+{
+
+class CWLoadingWidget;
+
+/**
+ * @author Martijn Klingens
+ */
+class CWBugListContainer : public QWidget
+{
+ Q_OBJECT
+
+public:
+ CWBugListContainer( QWidget* parent = 0, const char* name = 0 );
+ ~CWBugListContainer();
+
+ void setBugList( const Package &package, const QString &component, const Bug::List &bugs );
+
+ /**
+ * Overloaded method that takes a QString for the label. To be used when the
+ * bug list doesn't belong to a package, liek search results
+ */
+ void setBugList( const QString &label, const Bug::List &bugs );
+
+ void searchBugByTitle( int options, const QString& pattern );
+
+ /** Return list of selected bugs in the listview. Used for merging. */
+ QStringList selectedBugs() const;
+
+public slots:
+ void setNoList();
+ void setLoading( const Package &package, const QString &component );
+ void setLoading( const QString &label );
+ void setCacheMiss( const Package &package );
+ void setCacheMiss( const QString &label );
+ void slotFindNext();
+
+signals:
+ void resetProgressBar();
+ void searchPackage();
+
+ void executed( const Bug & );
+ void currentChanged( const Bug & );
+
+private slots:
+ void execute( QListViewItem * );
+ void changeCurrent( QListViewItem * );
+
+ void markBugCommand( BugCommand * );
+ void clearCommand( const QString & );
+
+ void searchHighlight( const QString &, int, int );
+
+private:
+ QLabel *m_listLabel;
+ QWidgetStack *m_listStack;
+
+ KListView *m_listBugs;
+ KFind *m_find;
+ BugLVI *m_findItem;
+
+ CWLoadingWidget *m_listLoading;
+};
+
+} // namespace
+
+#endif
+
+/* vim: set et ts=4 softtabstop=4 sw=4: */
+
diff --git a/kbugbuster/gui/cwloadingwidget.cpp b/kbugbuster/gui/cwloadingwidget.cpp
new file mode 100644
index 00000000..ddd218a5
--- /dev/null
+++ b/kbugbuster/gui/cwloadingwidget.cpp
@@ -0,0 +1,256 @@
+/*
+ cwloadingwidget.cpp - Widget to be shown while loading data
+
+ copyright : (c) 2001 by Martijn Klingens
+ email : klingens@kde.org
+
+ *************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the 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 "cwloadingwidget.h"
+
+#include <qpainter.h>
+#include <qpixmap.h>
+#include <kpixmap.h>
+#include <kpixmapeffect.h>
+
+#include <kstandarddirs.h>
+#include <klocale.h>
+#include <kglobalsettings.h>
+
+using namespace KBugBusterMainWindow;
+
+CWLoadingWidget::CWLoadingWidget( WidgetMode mode, QWidget *parent,
+ const char * name )
+: QFrame( parent, name )
+{
+ init( mode );
+}
+
+CWLoadingWidget::CWLoadingWidget( const QString &text, WidgetMode mode,
+ QWidget *parent, const char * name )
+: QFrame( parent, name )
+{
+ init( mode );
+ setText( text );
+}
+
+void CWLoadingWidget::init( WidgetMode mode )
+{
+ m_mode = mode;
+
+ QPalette pal = palette();
+ pal.setColor( QPalette::Active, QColorGroup::Background,
+ QColor( 49, 121, 173 ) );
+ pal.setColor( QPalette::Inactive, QColorGroup::Background,
+ QColor( 49, 121, 173 ) );
+ pal.setColor( QPalette::Disabled, QColorGroup::Background,
+ QColor( 49, 121, 173 ) );
+ setPalette( pal );
+
+ setFrameShape( StyledPanel );
+ setFrameShadow( Sunken );
+ setLineWidth( 2 );
+
+ setBackgroundMode( NoBackground ); // no flicker
+
+ // Load images and prepare pixmap effect
+ if( m_mode == TopFrame )
+ {
+ m_logoPixmap =
+ new QPixmap( locate( "data", "kbugbuster/pics/logo.png" ) );
+ m_topRightPixmap =
+ new QPixmap( locate( "data", "kbugbuster/pics/top-right.png" ) );
+ m_barsPixmap =
+ new QPixmap( locate( "data", "kbugbuster/pics/bars.png" ) );
+ m_toolsPixmap = 0L;
+ m_toolsPixmapEffect = 0L;
+ }
+ else
+ {
+ m_toolsPixmap =
+ new QPixmap( locate( "data", "kbugbuster/pics/tools.png" ) );
+
+ m_toolsPixmapEffect = new KPixmap( m_toolsPixmap->size() );
+
+ QPainter pb;
+ pb.begin( m_toolsPixmapEffect );
+ pb.fillRect( 0, 0, m_toolsPixmap->width(), m_toolsPixmap->height(),
+ QBrush( QColor( 49, 121, 172 ) ) );
+ pb.drawPixmap( 0, 0, *m_toolsPixmap );
+ pb.end();
+
+ KPixmapEffect::fade( *m_toolsPixmapEffect, 0.75, white );
+
+ m_logoPixmap = 0L;
+ m_topRightPixmap = 0L;
+ m_barsPixmap = 0L;
+ }
+
+ // Create and fill the buffer
+ m_buffer = new QPixmap;
+}
+
+void CWLoadingWidget::resizeEvent( QResizeEvent * )
+{
+ updatePixmap();
+}
+
+void CWLoadingWidget::setText( const QString &text )
+{
+ m_text = text;
+ updatePixmap();
+ repaint();
+}
+
+void CWLoadingWidget::updatePixmap()
+{
+ QRect cr = contentsRect();
+ cr.setWidth( cr.width() + 2 );
+ cr.setHeight( cr.height() + 2 );
+ m_buffer->resize( cr.width(), cr.height() );
+
+ QPainter p( m_buffer );
+
+ // fill background
+ p.fillRect( 0, 0, cr.width(), cr.height(),
+ QBrush( QColor( 49, 121, 173 ) ) );
+
+ if( m_mode == TopFrame )
+ {
+ QFont bigFont = QFont( KGlobalSettings::generalFont().family(),
+ 28, QFont::Bold, true );
+
+ int xoffset = m_logoPixmap->width();
+
+ // Draw bars tiled
+ int xpos = xoffset;
+ if( width() > xpos )
+ p.drawTiledPixmap( xpos, 0, cr.width() - xpos,
+ m_barsPixmap->height(), *m_barsPixmap );
+
+ // Draw logo
+ p.drawPixmap(width() - m_topRightPixmap->width(), 0, *m_topRightPixmap);
+ p.drawPixmap( 0, 0, *m_logoPixmap );
+
+ // Draw title text
+ p.setPen( black );
+ p.drawText( 150, 84, cr.width() - 150, 108 - 84,
+ AlignAuto | AlignVCenter, m_text );
+
+ // Draw intro text
+ QString desc = i18n( "Welcome to KBugBuster, a tool to manage the "
+ "KDE Bug Report System. With KBugBuster you can "
+ "manage outstanding bug reports for KDE from a "
+ "convenient front end." );
+ p.setPen( black );
+ p.drawText( 28, 128, cr.width() - 28, 184 - 128,
+ AlignAuto | AlignVCenter | WordBreak, desc );
+
+ // Draw the caption text
+ QString caption = i18n( "KBugBuster" );
+ p.setFont( bigFont );
+ p.setPen( QColor(139, 183, 222) );
+ p.drawText( 220, 60, caption );
+ p.setPen( black );
+ p.drawText( 217, 57, caption );
+ }
+ else
+ {
+ // draw tools image
+ if( cr.height() <= 24 )
+ return;
+
+ int toolsEffectY = cr.height() - m_toolsPixmap->height();
+ int toolsEffectX = cr.width() - m_toolsPixmap->width();
+ if ( toolsEffectX < 0)
+ toolsEffectX = 0;
+ if ( height() < 24 + m_toolsPixmap->height() )
+ toolsEffectY = 24;
+
+ p.drawPixmap( toolsEffectX, toolsEffectY, *m_toolsPixmap );
+
+ // draw textbox
+ if( cr.height() <= 24 + 50 )
+ return;
+
+ int fheight = fontMetrics().height();
+
+ int boxX = 25;
+ int boxY = 24 + 50;
+ int boxW = cr.width() - 2 * boxX - 2 * 10;
+ if( boxW > 500 )
+ boxW = 500;
+
+ QRect br = fontMetrics().boundingRect( boxX, boxY,
+ boxW, cr.height() - boxY - 10 - 2 * fheight,
+ AlignAuto | AlignTop | WordBreak, m_text );
+
+ QRect box = br;
+ box.setHeight( box.height() + 2 * fheight );
+ box.setWidth( box.width() + 2 * 10 );
+ if( box.width() < cr.width() - 2 * boxX )
+ box.setWidth( QMIN( cr.width() - 2 * boxX, 500 + 2 * 10 ) );
+ if( box.height() < 100 )
+ box.setHeight( QMIN( cr.height() - boxY - 2 * fheight - 10, 100 ) );
+
+ p.setClipRect( box );
+ p.fillRect( box, QBrush( QColor( 204, 222, 234 ) ) );
+ p.drawPixmap( toolsEffectX, toolsEffectY, *m_toolsPixmapEffect );
+
+ p.setViewport( box );
+ p.setWindow( 0, 0, box.width(), box.height() );
+
+ p.drawText( 10, fheight, br.width(),
+ QMAX( br.height(), box.height() - 2 * fheight ),
+ AlignAuto | AlignVCenter | WordBreak, m_text );
+ }
+}
+
+CWLoadingWidget::~CWLoadingWidget()
+{
+ if( m_toolsPixmap )
+ delete m_toolsPixmap;
+ if( m_logoPixmap )
+ delete m_logoPixmap;
+ if( m_topRightPixmap )
+ delete m_topRightPixmap;
+ if( m_barsPixmap )
+ delete m_barsPixmap;
+ if( m_toolsPixmapEffect )
+ delete m_toolsPixmapEffect;
+
+ delete m_buffer;
+
+ m_toolsPixmap = 0L;
+ m_logoPixmap = 0L;
+ m_topRightPixmap = 0L;
+ m_barsPixmap = 0L;
+ m_toolsPixmapEffect = 0L;
+ m_buffer = 0L;
+}
+
+void CWLoadingWidget::mouseReleaseEvent( QMouseEvent * )
+{
+ emit clicked();
+}
+
+void CWLoadingWidget::drawContents( QPainter *p )
+{
+ if( !m_buffer || m_buffer->isNull() )
+ p->fillRect( contentsRect(), QBrush( QColor( 255, 121, 172 ) ) );
+ else
+ p->drawPixmap( QPoint( contentsRect().x(), contentsRect().y()),
+ *m_buffer, contentsRect() );
+}
+
+#include "cwloadingwidget.moc"
+
+/* vim: set et ts=4 sw=4 softtabstop=4: */
diff --git a/kbugbuster/gui/cwloadingwidget.h b/kbugbuster/gui/cwloadingwidget.h
new file mode 100644
index 00000000..17c91f05
--- /dev/null
+++ b/kbugbuster/gui/cwloadingwidget.h
@@ -0,0 +1,87 @@
+/*
+ cwloadingwidget.h - Widget to be shown while loading data
+
+ begin : sun march 18 17:12:24 CET 2001
+ copyright : (c) 2001 by Martijn Klingens
+ email : klingens@kde.org
+
+ *************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the 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 KBBMAINWINDOW_CWLOADINGWIDGET_H
+#define KBBMAINWINDOW_CWLOADINGWIDGET_H
+
+#include <qlabel.h>
+#include <qframe.h>
+
+class QPixmap;
+class KPixmap;
+
+namespace KBugBusterMainWindow
+{
+
+/**
+ * @author Martijn Klingens
+ */
+class CWLoadingWidget : public QFrame
+{
+ Q_OBJECT
+
+public:
+ /**
+ * Use WidgetMode to specify the layout for the background images
+ * TopFrame loads and uses the logo and horizontal bars,
+ * BottomFrame loads the tools and the translucent block.
+ */
+ enum WidgetMode { TopFrame = 0, BottomFrame };
+
+ CWLoadingWidget( WidgetMode mode = TopFrame, QWidget* parent = 0,
+ const char* name = 0 );
+ CWLoadingWidget( const QString &text, WidgetMode mode = TopFrame,
+ QWidget* parent = 0, const char* name = 0 );
+ ~CWLoadingWidget();
+
+ QString text() const { return m_text; }
+ void setText( const QString &text );
+
+protected:
+ virtual void mouseReleaseEvent( QMouseEvent * );
+ virtual void drawContents( QPainter *p );
+ virtual void resizeEvent( QResizeEvent * );
+
+signals:
+ void clicked();
+
+private:
+ void init( WidgetMode mode );
+ void updatePixmap();
+
+ QString m_text;
+ WidgetMode m_mode;
+
+ // Pixmaps used
+ QPixmap *m_toolsPixmap;
+ QPixmap *m_logoPixmap;
+ QPixmap *m_topRightPixmap;
+ QPixmap *m_barsPixmap;
+
+ // For performance reasons we apply the KPixmapEffect only once
+ KPixmap *m_toolsPixmapEffect;
+
+ QPixmap *m_buffer;
+
+};
+
+} // namespace
+
+#endif // KBBMAINWINDOW_CWLOADINGWIDGET_H
+
+/* vim: set et ts=4 softtabstop=4 sw=4: */
+
diff --git a/kbugbuster/gui/cwsearchwidget.cpp b/kbugbuster/gui/cwsearchwidget.cpp
new file mode 100644
index 00000000..8f7fcb26
--- /dev/null
+++ b/kbugbuster/gui/cwsearchwidget.cpp
@@ -0,0 +1,69 @@
+/*
+ cwsearchwidget.cpp - Search Pane
+
+ copyright : (c) 2001 by Martijn Klingens
+ email : klingens@kde.org
+
+ *************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the 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 <qpushbutton.h>
+#include <klocale.h>
+#include <kdialog.h>
+#include <qlineedit.h>
+#include <qlayout.h>
+#include <kcombobox.h>
+#include <qlabel.h>
+
+#include "cwsearchwidget.h"
+
+using namespace KBugBusterMainWindow;
+
+CWSearchWidget::CWSearchWidget( QWidget *parent , const char * name )
+: CWSearchWidget_Base( parent, name )
+{
+ // Set fonts and margins
+ CWSearchWidget_BaseLayout->setSpacing( KDialog::spacingHint() );
+ CWSearchWidget_BaseLayout->setMargin( KDialog::marginHint() );
+
+ QFont f = m_searchLabel->font();
+ f.setBold( true );
+ m_searchLabel->setFont( f );
+
+ connect( m_searchDesc, SIGNAL( textChanged ( const QString & ) ),
+ this, SLOT( textDescriptionChanged ( const QString & ) ) );
+
+ connect( m_searchBugNumber, SIGNAL( textChanged ( const QString & ) ),
+ this, SLOT( textNumberChanged ( const QString & ) ) );
+
+ m_searchDescBtn->setEnabled( !m_searchDesc->text().isEmpty() );
+ m_searchBugNumberBtn->setEnabled( !m_searchBugNumber->text().isEmpty() );
+
+// m_searchPackages->setCompletionMode( KGlobalSettings::CompletionAuto );
+}
+
+CWSearchWidget::~CWSearchWidget()
+{
+}
+
+void CWSearchWidget::textDescriptionChanged ( const QString &_text )
+{
+ m_searchDescBtn->setEnabled( !_text.isEmpty() );
+}
+
+void CWSearchWidget::textNumberChanged ( const QString &_text )
+{
+ m_searchBugNumberBtn->setEnabled( !_text.isEmpty() );
+}
+
+#include "cwsearchwidget.moc"
+
+/* vim: set et ts=4 sw=4 softtabstop=4: */
+
diff --git a/kbugbuster/gui/cwsearchwidget.h b/kbugbuster/gui/cwsearchwidget.h
new file mode 100644
index 00000000..4cf65720
--- /dev/null
+++ b/kbugbuster/gui/cwsearchwidget.h
@@ -0,0 +1,46 @@
+/*
+ cwsearchwidget.h - Search Pane
+
+ copyright : (c) 2001 by Martijn Klingens
+ email : klingens@kde.org
+
+ *************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the 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 KBBMAINWINDOW_CWSEARCHWIDGET_H
+#define KBBMAINWINDOW_CWSEARCHWIDGET_H
+
+#include "cwsearchwidget_base.h"
+
+namespace KBugBusterMainWindow
+{
+
+/**
+ * @author Martijn Klingens
+ */
+class CWSearchWidget : public CWSearchWidget_Base
+{
+ Q_OBJECT
+
+public:
+ CWSearchWidget( QWidget* parent = 0, const char* name = 0 );
+ ~CWSearchWidget();
+
+public slots:
+ void textNumberChanged ( const QString & );
+ void textDescriptionChanged ( const QString & );
+};
+
+} // namespace
+
+#endif
+
+/* vim: set et ts=4 softtabstop=4 sw=4: */
+
diff --git a/kbugbuster/gui/cwsearchwidget_base.ui b/kbugbuster/gui/cwsearchwidget_base.ui
new file mode 100644
index 00000000..c5e9b860
--- /dev/null
+++ b/kbugbuster/gui/cwsearchwidget_base.ui
@@ -0,0 +1,198 @@
+<!DOCTYPE UI><UI version="3.0" stdsetdef="1">
+<class>CWSearchWidget_Base</class>
+<widget class="QWidget">
+ <property name="name">
+ <cstring>CWSearchWidget_Base</cstring>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>165</width>
+ <height>266</height>
+ </rect>
+ </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>m_searchLabel</cstring>
+ </property>
+ <property name="text">
+ <string>Search</string>
+ </property>
+ </widget>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>TextLabel2</cstring>
+ </property>
+ <property name="text">
+ <string>&amp;Package:</string>
+ </property>
+ <property name="buddy" stdset="0">
+ <cstring>m_searchPackages</cstring>
+ </property>
+ </widget>
+ <widget class="KComboBox">
+ <property name="name">
+ <cstring>m_searchPackages</cstring>
+ </property>
+ <property name="focusPolicy">
+ <enum>StrongFocus</enum>
+ </property>
+ <property name="editable">
+ <bool>true</bool>
+ </property>
+ <property name="insertionPolicy">
+ <enum>NoInsertion</enum>
+ </property>
+ </widget>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>TextLabel9</cstring>
+ </property>
+ <property name="text">
+ <string>Bug &amp;number:</string>
+ </property>
+ <property name="buddy" stdset="0">
+ <cstring>m_searchBugNumber</cstring>
+ </property>
+ </widget>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>Layout17</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="QLineEdit">
+ <property name="name">
+ <cstring>m_searchBugNumber</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>1</hsizetype>
+ <vsizetype>0</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ </widget>
+ <widget class="QPushButton">
+ <property name="name">
+ <cstring>m_searchBugNumberBtn</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="pixmap">
+ <pixmap>image0</pixmap>
+ </property>
+ </widget>
+ </hbox>
+ </widget>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>TextLabel7</cstring>
+ </property>
+ <property name="text">
+ <string>&amp;Description:</string>
+ </property>
+ <property name="buddy" stdset="0">
+ <cstring>m_searchDesc</cstring>
+ </property>
+ </widget>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>Layout15</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="QLineEdit">
+ <property name="name">
+ <cstring>m_searchDesc</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>1</hsizetype>
+ <vsizetype>0</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ </widget>
+ <widget class="QPushButton">
+ <property name="name">
+ <cstring>m_searchDescBtn</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="pixmap">
+ <pixmap>image0</pixmap>
+ </property>
+ </widget>
+ </hbox>
+ </widget>
+ <spacer>
+ <property name="name">
+ <cstring>Spacer1</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Vertical</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ </spacer>
+ </vbox>
+</widget>
+<images>
+ <image name="image0">
+ <data format="XPM.GZ" length="1725">789c75d4594fdb401405e0777e4584df5075b0e325b6aa3eb015ca1e76a8fa309ea518ca9eb055fdef9d39774815447311e4c3c73377c6cbfc5cef6477ab37373ff33052a34ef7f4b9baefcd99f1d5d5cbf71f5f7ecfcc6655cfff544daf3ffb69667638eae9def6cdb50d40e791a4fc04274aac7df1f840ecfc87bea3b350b4a5fba1787e420f42f1f8906e42d16b741b8a6e691b8a7e09e6f0323fc7eb0f42d179706e956a739afde62e146dde5cc8f93ab8487d49bf2774def65b4d1f0797b96e4c416f0757a9ceb4a1fb74ad2b23e73fd146175acecf68e7cdfe13ae87cb97fc0a9de94a8e23a52bdd9a92de129b8195f51cd1b5a9a3bfd28d56b1bf92567e3ed9bf535aeb26f67b41bbba5fcbfcb7c1755ae735af0f76e8526b23aee846d746f6eb9056a6b5d2df01ddfafee4f832ed8cb3355d0437a9298df4f318dd18b91e9b746933abe8bd60559b2caeff3adaca7c0968632a23f9fd6863a5df1bb12de2fc67b4f579997f8976b671d2ef46709b5a65a59f57baf2fdc97ed57463fc90f46a741bd7fb4c2babe3f963da5ae3647fcf8375660a53b17fde6f3a0fc5e3eb623fbfdc2f5774691b2bf335b4f2c7a59f5dda581dfb77b435b591e76731d8a42e73b27f0b74e9fa4eee8f6ff4c09696fde0e7c4b25fbf68edf3d2df88b6ae74f27c5d065b3e40f47d7411f30fb472ad53f23291420285f64df17f7a387acbc0c0c2e127ced1c14ce724e31317b8c42f5ce11a37fe7b4ce116b793cc1deef18011c678c4139ed1c5840e25ef0fbc62c12716b18465ace02b56b136c924f24ec137acfb3136b0892d6c6307bb18c655243217d6b0877d1ce0104738c6094e7126b34df5dcf9515264e8fb44eebf77ff59d718054a54feef853f67f03ec354871a4d82b03f18f8dfddfb0c73774982bbe12851e89236d16fa9c9387aea0a74d0ff5253e3e88f53b167eef9bbab3949c97b45f6fce319a732c9fb91980a73fdf93cf317e4bbac85</data>
+ </image>
+</images>
+<includes>
+ <include location="global" impldecl="in declaration">kcombobox.h</include>
+</includes>
+<layoutdefaults spacing="6" margin="11"/>
+</UI>
diff --git a/kbugbuster/gui/kbbbookmarkmanager.h b/kbugbuster/gui/kbbbookmarkmanager.h
new file mode 100644
index 00000000..64edfc24
--- /dev/null
+++ b/kbugbuster/gui/kbbbookmarkmanager.h
@@ -0,0 +1,23 @@
+#ifndef KBBBOOKMARKMANAGER_H
+#define KBBBOOKMARKMANAGER_H
+
+#include <kbookmarkmanager.h>
+#include <kstandarddirs.h>
+
+class KBBBookmarkManager
+{
+public:
+ static KBookmarkManager * self() {
+ if ( !s_bookmarkManager )
+ {
+ QString bookmarksFile = locateLocal("data", QString::fromLatin1("kbugbuster/bookmarks.xml"));
+ s_bookmarkManager = KBookmarkManager::managerForFile( bookmarksFile );
+ }
+ return s_bookmarkManager;
+ }
+
+
+ static KBookmarkManager *s_bookmarkManager;
+};
+
+#endif
diff --git a/kbugbuster/gui/kbbmainwindow.cpp b/kbugbuster/gui/kbbmainwindow.cpp
new file mode 100644
index 00000000..66a9b588
--- /dev/null
+++ b/kbugbuster/gui/kbbmainwindow.cpp
@@ -0,0 +1,504 @@
+/***************************************************************************
+ kbbmainwindow.cpp - description
+ -------------------
+ copyright : (C) 2001 by Martijn Klingens
+ email : klingens@kde.org
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the 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 "kbbmainwindow.h"
+
+#include <qlabel.h>
+#include <qlayout.h>
+#include <qmultilineedit.h>
+#include <qprogressbar.h>
+#include <qpushbutton.h>
+#include <qtextview.h>
+#include <qwidgetstack.h>
+
+#include <kaction.h>
+#include <kbookmarkmenu.h>
+#include <kcombobox.h>
+#include <kconfig.h>
+#include <kdebug.h>
+#include <kdialog.h>
+#include <kinputdialog.h>
+#include <klineedit.h>
+#include <klistview.h>
+#include <klocale.h>
+#include <kmenubar.h>
+#include <kmessagebox.h>
+#include <kstatusbar.h>
+#include <kstdaction.h>
+#include <kstdguiitem.h>
+#include <kedittoolbar.h>
+
+
+#include "bugcommand.h"
+#include "bugserver.h"
+#include "bugserverconfig.h"
+#include "bugsystem.h"
+#include "centralwidget.h"
+#include "cwbugdetails.h"
+#include "kbbbookmarkmanager.h"
+#include "kbbprefs.h"
+#include "kfinddialog.h"
+#include "packageselectdialog.h"
+#include "preferencesdialog.h"
+
+#define ID_STATUS_MSG 1
+
+using namespace KBugBusterMainWindow;
+
+class TextViewer : public KDialogBase
+{
+ public:
+ TextViewer( const QString &title, QWidget *parent = 0 )
+ : KDialogBase( Plain, title, Ok, Ok, parent, 0,
+ false )
+ {
+ QFrame *topFrame = plainPage();
+
+ QBoxLayout *topLayout = new QVBoxLayout( topFrame );
+
+ mTextView = new QTextEdit( topFrame );
+ mTextView->setReadOnly( true );
+ mTextView->setTextFormat( PlainText );
+ topLayout->addWidget( mTextView );
+
+ resize( 600, 400 );
+ }
+
+ void setText( const QString &text )
+ {
+ mTextView->setText( text );
+ }
+
+ private:
+ QTextEdit *mTextView;
+};
+
+KBookmarkManager* KBBBookmarkManager::s_bookmarkManager;
+
+KBBMainWindow::KBBMainWindow( const QCString &initialPackage,
+ const QCString &initialComponent,
+ const QCString &initialBug,
+ QWidget * , const char * name )
+ : KMainWindow( 0, name ), mPreferencesDialog( 0 ), mResponseViewer( 0 ),
+ mBugSourceViewer( 0 ), mPackageSelectDialog( 0 )
+{
+ BugSystem::self()->setCurrentServer( KBBPrefs::instance()->mCurrentServer );
+
+ m_statusLabel = new QLabel( i18n( "Welcome to <b>KBugBuster</b>." ), statusBar() );
+ m_statusLabel->setMaximumHeight( statusBar()->fontMetrics().height() + 6 );
+ m_statusLabel->setIndent( KDialog::marginHint() / 2 );
+ statusBar()->addWidget( m_statusLabel, 1 );
+
+ m_mainWidget = new CentralWidget( initialPackage, initialComponent,
+ initialBug, this );
+ setCentralWidget( m_mainWidget );
+
+ initActions();
+
+ m_progressBar = new QProgressBar( 100, statusBar() );
+ m_progressBar->setCenterIndicator( true );
+ m_progressBar->setMinimumWidth( 150 );
+ m_progressBar->setMaximumHeight( statusBar()->fontMetrics().height() + 6 );
+ statusBar()->addWidget( m_progressBar );
+ connect( m_mainWidget, SIGNAL( resetProgressBar() ),
+ m_progressBar, SLOT( reset() ) );
+ connect( m_mainWidget, SIGNAL( searchPackage() ),
+ this, SLOT( searchPackage() ) );
+ connect( m_mainWidget, SIGNAL( searchBugNumber() ),
+ this, SLOT( searchBugNumber() ) );
+
+ connect( BugSystem::self(), SIGNAL( infoMessage( const QString & ) ),
+ SLOT( slotStatusMsg( const QString & ) ) );
+
+ connect( BugSystem::self(), SIGNAL( infoMessage( const QString & ) ),
+ SLOT( slotStatusMsg( const QString & ) ) );
+ connect( BugSystem::self(), SIGNAL( infoPercent( unsigned long ) ),
+ SLOT( slotSetPercent( unsigned long ) ) );
+
+ m_mainWidget->readConfig();
+}
+
+KBBMainWindow::~KBBMainWindow()
+{
+// kdDebug() << "KBBMainWindow::~KBBMainWindow()" << endl;
+ delete m_pBookmarkMenu;
+
+ m_mainWidget->writeConfig();
+
+ KBBPrefs::instance()->writeConfig();
+}
+
+void KBBMainWindow::initActions()
+{
+ // Prepare and create XML GUI
+ fileQuit = KStdAction::quit( this,
+ SLOT( close() ), actionCollection() );
+ fileQuit->setToolTip( i18n( "Quit KBugBuster" ) );
+
+ new KAction( i18n("See &Pending Changes"), "contents", 0, this, SLOT( slotListChanges() ),
+ actionCollection(), "file_seechanges" );
+ new KAction( i18n("&Submit Changes"), "mail_send", 0, this, SLOT( slotSubmit() ),
+ actionCollection(), "file_submit" );
+
+ reloadpacklist = new KAction( i18n("Reload &Product List"), "reload", CTRL+Qt::Key_F5, m_mainWidget, SLOT( slotReloadPackageList() ),
+ actionCollection(), "reload_packagelist" );
+ reloadpack= new KAction( i18n("Reload Bug &List (for current product)"), "reload", Qt::Key_F5, m_mainWidget, SLOT( slotReloadPackage() ),
+ actionCollection(), "reload_package" );
+ reloadbug = new KAction( i18n("Reload Bug &Details (for current bug)"), "reload", SHIFT+Qt::Key_F5, m_mainWidget, SLOT( slotReloadBug() ),
+ actionCollection(), "reload_bug" );
+ loadMyBugs = new KAction( i18n( "Load &My Bugs List" ), 0, m_mainWidget, SLOT( slotLoadMyBugs() ),
+ actionCollection(), "load_my_bugs" );
+ reloadall = new KAction( i18n("Load All Bug Details (for current product)"), Qt::Key_F6, m_mainWidget, SLOT( slotRetrieveAllBugDetails() ), actionCollection(), "load_allbugs" );
+ new KAction( i18n("Extract &Attachments"), "filesave", Qt::Key_F4, m_mainWidget, SLOT( slotExtractAttachments() ),
+ actionCollection(), "extract_attachments" );
+
+ new KAction( i18n("Clear Cache"), 0, this, SLOT( clearCache() ),
+ actionCollection(), "clear_cache" );
+
+ new KAction( i18n("&Search by Product..."), "goto", CTRL+Qt::Key_P, this,
+ SLOT( searchPackage() ), actionCollection(), "search_package" );
+ new KAction( i18n("Search by Bug &Number..."), "filefind", CTRL+Qt::Key_N, this,
+ SLOT( searchBugNumber() ), actionCollection(), "search_bugnumber" );
+ // For now "Description" searches by title. Maybe later we can have a
+ // full-text search interfacing bugs.kde.org and rename the current one to "By Title".
+ new KAction( i18n("Search by &Description...") ,"find", CTRL+Qt::Key_D, this,
+ SLOT( searchDescription() ), actionCollection(), "search_description" );
+
+// new KAction( i18n("&Merge"), "view_remove", CTRL+Qt::Key_M, m_mainWidget,
+// SLOT( mergeBugs() ), actionCollection(), "cmd_merge" );
+// new KAction( i18n("&Unmerge"), "view_top_bottom", CTRL+SHIFT+Qt::Key_M, m_mainWidget,
+// SLOT( unmergeBugs() ), actionCollection(), "cmd_unmerge" );
+ new KAction( i18n("C&lose..."), "edittrash", CTRL+Qt::Key_L, m_mainWidget,
+ SLOT( closeBug() ), actionCollection(), "cmd_close" );
+// new KAction( i18n("Clos&e Silently"), "edittrash", CTRL+Qt::Key_E, m_mainWidget,
+// SLOT( closeBugSilently() ), actionCollection(), "cmd_close_silently" );
+ new KAction( i18n("Re&open"), "idea", CTRL+Qt::Key_O, m_mainWidget,
+ SLOT( reopenBug() ), actionCollection(), "cmd_reopen" );
+// new KAction( i18n("Re&assign..."), "folder_new", CTRL+Qt::Key_A, m_mainWidget,
+// SLOT( reassignBug() ), actionCollection(), "cmd_reassign" );
+// new KAction( i18n("Change &Title..."), "text_under", CTRL+Qt::Key_T, m_mainWidget,
+// SLOT( titleBug() ), actionCollection(), "cmd_title" );
+// new KAction( i18n("Change &Severity..."), "edit", CTRL+Qt::Key_S, m_mainWidget,
+// SLOT( severityBug() ), actionCollection(), "cmd_severity" );
+ new KAction( i18n("&Reply..."), "mail_replyall",CTRL+Qt::Key_R , m_mainWidget,
+ SLOT( replyBug() ), actionCollection(), "cmd_reply" );
+ new KAction( i18n("Reply &Privately..."), "mail_reply", CTRL+Qt::Key_I, m_mainWidget,
+ SLOT( replyPrivateBug() ), actionCollection(), "cmd_replyprivate" );
+
+ KStdAction::showMenubar(this, SLOT( slotToggleMenubar() ), actionCollection() );
+#if KDE_IS_VERSION( 3, 1, 90 )
+ createStandardStatusBarAction();
+ setStandardToolBarMenuEnabled(true);
+#endif
+
+ m_disconnectedAction = new KToggleAction( i18n("&Disconnected Mode"), 0,
+ this,
+ SLOT( slotDisconnectedAction() ),
+ actionCollection(),
+ "settings_disconnected" );
+ m_disconnectedAction->setChecked( BugSystem::self()->disconnected() );
+
+ // Bookmarks menu
+ m_pamBookmarks = new KActionMenu( i18n( "&Bookmarks" ), "bookmark", actionCollection(), "bookmarks" );
+ m_pBookmarkMenu = new KBookmarkMenu( KBBBookmarkManager::self(), this, m_pamBookmarks->popupMenu(), actionCollection(), true );
+
+ KStdAction::preferences( this, SLOT(preferences()), actionCollection() );
+
+ KToggleAction *toggleTmp = new KToggleAction( i18n("Show Closed Bugs"), "recycled", 0, this, SLOT( slotToggleDone() ),
+ actionCollection(), "cmd_toggle_done" );
+#if KDE_IS_VERSION( 3, 2, 90 )
+ toggleTmp->setCheckedState(i18n("Hide Closed Bugs"));
+#endif
+ toggleTmp->setChecked( KBBPrefs::instance()->mShowClosedBugs );
+
+ toggleTmp =new KToggleAction( i18n("Show Wishes"), "bookmark", 0, this, SLOT( slotToggleWishes() ),
+ actionCollection(), "cmd_toggle_wishes" );
+#if KDE_IS_VERSION( 3, 2, 90 )
+ toggleTmp->setCheckedState(i18n("Hide Wishes"));
+#endif
+ toggleTmp->setChecked(KBBPrefs::instance()->mShowWishes);
+
+ mSelectServerAction = new KSelectAction( i18n( "Select Server" ), 0, 0,
+ this,
+ SLOT( slotSelectServer() ),
+ actionCollection(),
+ "select_server" );
+
+ setupSelectServerAction();
+
+ if ( KBBPrefs::instance()->mDebugMode ) {
+ new KAction( i18n("Show Last Server Response..."), 0 , this,
+ SLOT( showLastResponse() ), actionCollection(),
+ "debug_lastresponse" );
+ new KAction( i18n("Show Bug HTML Source..."), 0 , this,
+ SLOT( showBugSource() ), actionCollection(),
+ "debug_showbugsource" );
+ }
+
+#if KDE_IS_VERSION( 3, 2, 90 )
+ setupGUI( (ToolBar | Keys | StatusBar | Save | Create ), "kbugbusterui.rc" );
+#else
+ createGUI();
+#endif
+}
+
+void KBBMainWindow::slotToggleMenubar()
+{
+ if ( !hasMenuBar() )
+ return;
+
+ if ( menuBar()->isVisible() )
+ menuBar()->hide();
+ else
+ menuBar()->show();
+}
+
+void KBBMainWindow::setupSelectServerAction()
+{
+ QStringList servers;
+ int current = -1;
+ QValueList<BugServer *> serverList = BugSystem::self()->serverList();
+ QValueList<BugServer *>::ConstIterator it;
+ for ( it = serverList.begin(); it != serverList.end(); ++it ) {
+ QString name = (*it)->serverConfig().name();
+ servers.append( name );
+ if ( name == KBBPrefs::instance()->mCurrentServer ) {
+ current = servers.count() - 1;
+ }
+ }
+ mSelectServerAction->setItems( servers );
+ if ( current >= 0 ) {
+ mSelectServerAction->setCurrentItem( current );
+ }
+}
+
+QString KBBMainWindow::currentURL() const
+{
+ QString number=m_mainWidget->currentNumber();
+
+ if (number.isEmpty())
+ return "";
+ else
+ return "bug:"+number;
+}
+
+QString KBBMainWindow::currentTitle() const
+{
+ return "#"+m_mainWidget->currentNumber()+": "+m_mainWidget->currentTitle();
+}
+
+void KBBMainWindow::openBookmarkURL( const QString & url )
+{
+ if ( url.left(4)=="bug:" ) {
+ QString bugnumber = url.mid(4);
+ m_mainWidget->slotRetrieveBugDetails( Bug::fromNumber( bugnumber ) );
+ }
+}
+
+// --- SLOT IMPLEMENTATIONS -------------------------------------------------
+
+void KBBMainWindow::slotDisconnectedAction()
+{
+ BugSystem::self()->setDisconnected( m_disconnectedAction->isChecked() );
+
+ bool enable = !m_disconnectedAction->isChecked();
+
+ reloadpacklist->setEnabled( enable );
+ reloadpacklist->setEnabled( enable );
+ reloadpack->setEnabled( enable );
+ reloadbug->setEnabled( enable );
+ reloadall->setEnabled( enable );
+ loadMyBugs->setEnabled( enable );
+}
+
+void KBBMainWindow::slotStatusMsg( const QString &text )
+{
+ // Change status message permanently
+ m_statusLabel->setText( text );
+}
+
+void KBBMainWindow::slotSubmit()
+{
+ BugSystem::self()->sendCommands();
+}
+
+void KBBMainWindow::slotListChanges()
+{
+ QStringList list = BugSystem::self()->server()->listCommands();
+
+ if (list.count() > 0)
+ {
+ int ret = KMessageBox::questionYesNoList( this, i18n("List of pending commands:"),
+ list, QString::null, KStdGuiItem::clear(), KStdGuiItem::close() );
+ if ( ret == KMessageBox::Yes )
+ {
+ // Ask for confirmation, it's too easy to click the wrong button in the above dlg box
+ if ( KMessageBox::warningContinueCancel( this, i18n("Do you really want to delete all commands?"),
+ i18n("Confirmation Required"), KGuiItem( i18n("&Delete"), "editdelete"), "clearcommands", true)
+ == KMessageBox::Continue )
+ BugSystem::self()->clearCommands();
+ }
+ }
+ else
+ {
+ KMessageBox::information( this, i18n("There are no pending commands.") );
+ }
+}
+
+void KBBMainWindow::slotSetPercent( unsigned long percent )
+{
+ // KIO::Job::percent() shouldn't return an unsigned long. - Frerich
+ m_progressBar->setProgress( percent );
+}
+
+void KBBMainWindow::searchPackage()
+{
+ if ( !mPackageSelectDialog ) {
+ mPackageSelectDialog = new PackageSelectDialog( this );
+ }
+ mPackageSelectDialog->setPackages( BugSystem::self()->packageList() );
+ BugServerConfig cfg = BugSystem::self()->server()->serverConfig();
+ QStringList recent = cfg.recentPackages();
+ kdDebug() << "MainWindow RECENT: " << recent.join(",") << endl;
+ mPackageSelectDialog->setRecentPackages( recent );
+
+ mPackageSelectDialog->exec();
+ Package package = mPackageSelectDialog->selectedPackage();
+
+ if ( package.isNull() ) {
+ return;
+ }
+
+ QString component = mPackageSelectDialog->selectedComponent();
+ m_mainWidget->slotRetrieveBugList( package.name(), component );
+}
+
+void KBBMainWindow::searchBugNumber()
+{
+ bool ok = false;
+ QString result = KInputDialog::getText( i18n("Search for Bug Number"),
+ i18n("Please enter a bug number:"),
+ QString::null, &ok, this );
+ if ( ok ) {
+ //Strip whitespace and # if needed
+ result = result.stripWhiteSpace();
+ if (result[0]=='#')
+ result = result.mid(1);
+ }
+
+ if ( ok && !result.isEmpty()) {
+ // ### bad way to instantiate a bug! doesn't get us the details!
+ // Right - but do we need the details in this case ? There's no listview entry here... (DF)
+ m_mainWidget->slotRetrieveBugDetails( Bug::fromNumber( result ) );
+ }
+}
+
+void KBBMainWindow::searchDescription()
+{
+ kdDebug() << "KBBMainWindow::searchDescription()." << endl;
+ //KMessageBox::sorry(this,i18n("searchDescription(): to be implemented."),i18n("Not implemented"));
+ KFindDialog dlg( this );
+ if ( dlg.exec() == KDialogBase::Accepted )
+ m_mainWidget->searchBugByTitle( dlg.options(), dlg.pattern() );
+}
+
+bool KBBMainWindow::queryClose()
+{
+ if ( ! BugSystem::self()->server()->commandsPending() ) return true;
+
+ int result = KMessageBox::warningYesNoCancel(this,i18n("There are unsent bug commands."
+ " Do you want to send them now?"), QString::null, i18n("Send"), i18n("Do Not Send"));
+ if ( result == KMessageBox::Cancel ) return false;
+ if ( result == KMessageBox::Yes ) {
+ BugSystem::self()->sendCommands();
+ }
+ return true;
+}
+
+void KBBMainWindow::preferences()
+{
+ if (!mPreferencesDialog) {
+ mPreferencesDialog = new PreferencesDialog(this);
+ connect( mPreferencesDialog, SIGNAL( configChanged() ),
+ SLOT( setupSelectServerAction() ) );
+ connect( mPreferencesDialog, SIGNAL( configChanged() ),
+ m_mainWidget, SLOT( slotReloadPackage() ) );
+ }
+ mPreferencesDialog->show();
+ mPreferencesDialog->raise();
+}
+
+void KBBMainWindow::updatePackage()
+{
+ m_mainWidget->updatePackage();
+}
+
+void KBBMainWindow::slotToggleDone()
+{
+ KBBPrefs::instance()->mShowClosedBugs=!(KBBPrefs::instance()->mShowClosedBugs);
+ updatePackage();
+}
+
+void KBBMainWindow::slotToggleWishes()
+{
+ KBBPrefs::instance()->mShowWishes=!(KBBPrefs::instance()->mShowWishes);
+ updatePackage();
+}
+
+void KBBMainWindow::slotSelectServer()
+{
+ m_mainWidget->writeConfig();
+
+ QString currentServer = mSelectServerAction->currentText();
+
+ BugSystem::self()->setCurrentServer( currentServer );
+
+ m_mainWidget->initialize();
+}
+
+void KBBMainWindow::showLastResponse()
+{
+ if ( !mResponseViewer ) {
+ mResponseViewer = new TextViewer( i18n("Last Server Response"), this );
+ }
+
+ mResponseViewer->setText( BugSystem::lastResponse() );
+
+ mResponseViewer->show();
+ mResponseViewer->raise();
+}
+
+void KBBMainWindow::showBugSource()
+{
+ if ( !mBugSourceViewer ) {
+ mBugSourceViewer = new TextViewer( i18n("Bug HTML Source"), this );
+ }
+
+ mBugSourceViewer->setText( m_mainWidget->bugDetailsWidget()->source() );
+
+ mBugSourceViewer->show();
+ mBugSourceViewer->raise();
+}
+
+void KBBMainWindow::clearCache()
+{
+ BugSystem::self()->server()->cache()->clear();
+}
+
+#include "kbbmainwindow.moc"
+
+/* vim: set et ts=4 sw=4 softtabstop=4: */
+
diff --git a/kbugbuster/gui/kbbmainwindow.h b/kbugbuster/gui/kbbmainwindow.h
new file mode 100644
index 00000000..f139c733
--- /dev/null
+++ b/kbugbuster/gui/kbbmainwindow.h
@@ -0,0 +1,144 @@
+/*
+ kbbmainwindow.h - KBugBuster's main window
+
+ Copyright (c) 2001-2004 by Martijn Klingens <klingens@kde.org>
+
+ *************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the 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 KBBMAINWINDOW_H
+#define KBBMAINWINDOW_H
+
+#include <kapplication.h>
+#include <kbookmarkmanager.h>
+#include <kmainwindow.h>
+#include <qmap.h>
+
+#include "package.h"
+#include "bug.h"
+#include "bugdetails.h"
+
+class KAction;
+class KActionMenu;
+class KBookmarkMenu;
+class KToggleAction;
+class KSelectAction;
+class QLabel;
+class QListViewItem;
+class QProgressBar;
+class PreferencesDialog;
+class TextViewer;
+class PackageSelectDialog;
+
+namespace KBugBusterMainWindow
+{
+ class CentralWidget;
+}
+
+/**
+ * @author Martijn Klingens
+ */
+class KBBMainWindow : public KMainWindow, virtual public KBookmarkOwner
+{
+ Q_OBJECT
+ public:
+ /**
+ * construtor of KBugBusterApp, calls all init functions to create the application.
+ */
+ KBBMainWindow( const QCString &initialPackage = "",
+ const QCString &initialCpomponent = "",
+ const QCString &initialBug = "",
+ QWidget* parent = 0, const char* name = 0 );
+ ~KBBMainWindow();
+
+ /// Overloaded functions of KBookmarkOwner
+ virtual void openBookmarkURL( const QString & _url );
+ virtual QString currentTitle() const;
+ virtual QString currentURL() const;
+
+ public slots:
+ /**
+ * Event handlers for our KActions
+ */
+ void slotStatusMsg( const QString &text );
+ void slotDisconnectedAction();
+ void slotSubmit();
+ void slotListChanges();
+ void slotSetPercent( unsigned long percent );
+ void slotSelectServer();
+
+ void showLastResponse();
+ void showBugSource();
+
+ void clearCache();
+
+ /**
+ * Other event handlers
+ */
+
+ void searchPackage();
+ void searchBugNumber();
+ void searchDescription();
+
+ void preferences();
+ void updatePackage();
+ void slotToggleDone();
+ void slotToggleWishes();
+
+ protected:
+ virtual bool queryClose();
+
+ protected slots:
+ void setupSelectServerAction();
+ void slotToggleMenubar();
+
+ private:
+ void initActions();
+
+ /**
+ * Our main widget
+ */
+ KBugBusterMainWindow::CentralWidget *m_mainWidget;
+
+ /**
+ * Used KActions
+ */
+ KAction *fileQuit;
+ KAction *reloadpacklist;
+ KAction *reloadpack;
+ KAction *reloadbug;
+ KAction *reloadall;
+ KAction *loadMyBugs;
+ KToggleAction *m_disconnectedAction;
+
+ /**
+ * Status bar label. We need this, because the default Qt version doesn't
+ * support rich text in the messages
+ */
+ QLabel *m_statusLabel;
+ QProgressBar *m_progressBar;
+
+ PreferencesDialog *mPreferencesDialog;
+
+ KActionMenu *m_pamBookmarks;
+ KBookmarkMenu* m_pBookmarkMenu;
+
+ KSelectAction *mSelectServerAction;
+
+ TextViewer *mResponseViewer;
+ TextViewer *mBugSourceViewer;
+
+ PackageSelectDialog *mPackageSelectDialog;
+};
+
+#endif
+
+/* vim: set et ts=4 softtabstop=4 sw=4: */
+
diff --git a/kbugbuster/gui/kbugbusterui.rc b/kbugbuster/gui/kbugbusterui.rc
new file mode 100644
index 00000000..f347855c
--- /dev/null
+++ b/kbugbuster/gui/kbugbusterui.rc
@@ -0,0 +1,78 @@
+<!DOCTYPE kpartgui SYSTEM "kpartgui.dtd">
+<kpartgui name="kbugbuster" version="11">
+
+<MenuBar>
+ <Menu name="file" noMerge="1"><text>&amp;File</text>
+ <Action name="file_new_window" />
+ <Action name="file_seechanges" />
+ <Action name="file_submit" />
+ <Separator/>
+ <Action name="file_quit" />
+ </Menu>
+ <Menu name="view"><text>&amp;View</text>
+ <Action name="reload_packagelist" />
+ <Action name="reload_package" />
+ <Action name="reload_bug" />
+ <Separator/>
+ <Action name="load_my_bugs" />
+ <Action name="load_allbugs" />
+ <Separator/>
+ <Action name="extract_attachments" />
+ <Separator/>
+ <Action name="clear_cache" />
+ <Separator/>
+ <Action name="debug_lastresponse" />
+ <Action name="debug_showbugsource" />
+ </Menu>
+ <Menu name="search"><text>S&amp;earch</text>
+ <Action name="search_package" />
+ <Action name="search_bugnumber" />
+ <Action name="search_description" />
+ </Menu>
+ <Action name="bookmarks"/>
+ <Menu name="commands"><text>&amp;Commands</text>
+ <!-- <Action name="cmd_merge" />
+ <Action name="cmd_unmerge" />
+ <Separator/> -->
+ <Action name="cmd_close" />
+ <Action name="cmd_close_silently" />
+ <Action name="cmd_reopen" />
+ <Action name="cmd_reassign" />
+ <Action name="cmd_title" />
+ <Action name="cmd_severity" />
+ <Separator/>
+ <Action name="cmd_reply" />
+ <Action name="cmd_replyprivate" />
+ </Menu>
+ <Menu name="settings"><text>&amp;Settings</text>
+ <Action name="settings_disconnected" append="save_merge"/>
+ <Action name="select_server" append="save_merge"/>
+ </Menu>
+</MenuBar>
+
+<ToolBar name="searchToolBar"><text>Search Toolbar</text>
+ <Action name="search_package" />
+ <Action name="search_bugnumber" />
+ <Action name="search_description" />
+</ToolBar>
+
+<ToolBar name="commandToolBar"><text>Command Toolbar</text>
+ <Action name="cmd_merge" />
+ <Action name="cmd_unmerge" />
+ <Separator/>
+ <Action name="cmd_close" />
+ <Action name="cmd_reopen" />
+ <Action name="cmd_reassign" />
+ <Action name="cmd_title" />
+ <Action name="cmd_severity" />
+ <Separator/>
+ <Action name="cmd_reply" />
+ <Action name="cmd_replyprivate" />
+</ToolBar>
+
+<ToolBar name="settingToolBar"><text>Settings Toolbar</text>
+ <Action name="cmd_toggle_wishes" />
+ <Action name="cmd_toggle_done" />
+</ToolBar>
+
+</kpartgui>
diff --git a/kbugbuster/gui/loadallbugsdlg.cpp b/kbugbuster/gui/loadallbugsdlg.cpp
new file mode 100644
index 00000000..40ecd6d8
--- /dev/null
+++ b/kbugbuster/gui/loadallbugsdlg.cpp
@@ -0,0 +1,92 @@
+/***************************************************************************
+ loadallbugsdlg.cpp - progress dialog while loading all bugs for a package
+ -------------------
+ copyright : (C) 2002 by David Faure
+ email : david@mandrakesoft.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 version 2. *
+ * *
+ ***************************************************************************/
+
+#include "loadallbugsdlg.h"
+#include "bugsystem.h"
+#include "bugcache.h"
+#include <kdebug.h>
+#include <kio/defaultprogress.h>
+#include <qtimer.h>
+
+LoadAllBugsDlg::LoadAllBugsDlg( const Package& pkg, const QString &component )
+ : QDialog( 0L, "progressdlg", TRUE )
+{
+ m_bugLoadingProgress = new KIO::DefaultProgress( this );
+ connect( m_bugLoadingProgress, SIGNAL( stopped() ),
+ this, SLOT( slotStopped() ) );
+ setCaption( i18n( "Loading All Bugs for Product %1" ).arg( pkg.name() ) );
+ connect( BugSystem::self(),
+ SIGNAL( bugDetailsAvailable( const Bug &, const BugDetails & ) ),
+ SLOT( slotBugDetailsAvailable( const Bug &, const BugDetails & ) ) );
+ connect( BugSystem::self(),
+ SIGNAL( bugDetailsLoadingError() ),
+ SLOT( slotBugDetailsLoadingError() ) );
+ // The package (and its buglist) has to be in the cache already...
+ m_bugs = BugSystem::self()->cache()->loadBugList( pkg, component, true );
+ m_count = m_bugs.count();
+ m_bugLoadingProgress->slotTotalSize( 0, m_count );
+ kdDebug() << "LoadAllBugsDlg: " << m_count << " bugs to load" << endl;
+ m_processed = 0;
+ QTimer::singleShot( 0, this, SLOT( loadNextBug() ) );
+}
+
+void LoadAllBugsDlg::slotBugDetailsAvailable( const Bug &bug, const BugDetails & )
+{
+ kdDebug() << "LoadAllBugsDlg::slotBugDetailsAvailable " << bug.number() << endl;
+ m_bugLoadingProgress->slotInfoMessage( 0L, i18n( "Bug %1 loaded" ).arg(bug.number()) );
+ loadNextBug();
+}
+
+void LoadAllBugsDlg::slotBugDetailsLoadingError()
+{
+ // Abort at the first error. Otherwise we get spammed with "no host bugs.kde.org" msg boxes....
+ reject();
+}
+
+void LoadAllBugsDlg::loadNextBug()
+{
+ kdDebug() << "LoadAllBugsDlg::loadNextBug" << endl;
+ if ( m_bugs.isEmpty() )
+ {
+ kdDebug() << "LoadAllBugsDlg::loadNextBug DONE!" << endl;
+ accept();
+ } else {
+ BugCache* cache = BugSystem::self()->cache();
+ Bug bug;
+ do {
+ bug = m_bugs.front();
+ m_bugs.pop_front();
+ m_processed++;
+ m_bugLoadingProgress->slotPercent( 0L, (100 * m_processed) / m_count );
+ kdDebug() << "looking at bug " << bug.number() << " in cache:" << cache->hasBugDetails( bug ) << endl;
+ } while ( cache->hasBugDetails( bug ) && !m_bugs.isEmpty() );
+ if ( !cache->hasBugDetails( bug ) ) {
+ kdDebug() << "LoadAllBugsDlg::loadNextBug loading bug " << bug.number() << endl;
+ BugSystem::self()->retrieveBugDetails( bug );
+ } else {
+ kdDebug() << "LoadAllBugsDlg::loadNextBug DONE!" << endl;
+ accept();
+ }
+ }
+}
+
+void LoadAllBugsDlg::slotStopped()
+{
+ kdDebug() << "LoadAllBugsDlg::slotStopped" << endl;
+ // TODO abort job?
+ reject();
+}
+
+#include "loadallbugsdlg.moc"
diff --git a/kbugbuster/gui/loadallbugsdlg.h b/kbugbuster/gui/loadallbugsdlg.h
new file mode 100644
index 00000000..685abcb0
--- /dev/null
+++ b/kbugbuster/gui/loadallbugsdlg.h
@@ -0,0 +1,43 @@
+/***************************************************************************
+ loadallbugsdlg.h - progress dialog while loading all bugs for a package
+ -------------------
+ copyright : (C) 2002 by David Faure
+ email : david@mandrakesoft.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 version 2. *
+ * *
+ ***************************************************************************/
+#ifndef loadallbugsdlg_h
+#define loadallbugsdlg_h
+
+#include <qdialog.h>
+#include "bug.h"
+class Package;
+class BugDetails;
+
+namespace KIO { class DefaultProgress; }
+
+class LoadAllBugsDlg : public QDialog
+{
+ Q_OBJECT
+public:
+ LoadAllBugsDlg( const Package& pkg, const QString &component );
+
+protected slots:
+ void slotBugDetailsAvailable( const Bug &bug, const BugDetails &bd );
+ void slotBugDetailsLoadingError();
+ void slotStopped();
+ void loadNextBug();
+private:
+ Bug::List m_bugs;
+ unsigned int m_processed;
+ unsigned int m_count;
+ KIO::DefaultProgress* m_bugLoadingProgress;
+};
+
+#endif
diff --git a/kbugbuster/gui/messageeditor.cpp b/kbugbuster/gui/messageeditor.cpp
new file mode 100644
index 00000000..517ef80b
--- /dev/null
+++ b/kbugbuster/gui/messageeditor.cpp
@@ -0,0 +1,117 @@
+#include <qcombobox.h>
+#include <ktextedit.h>
+#include <kinputdialog.h>
+#include <qlayout.h>
+#include <qlabel.h>
+
+#include <klocale.h>
+#include <kmessagebox.h>
+#include <kdebug.h>
+
+#include "kbbprefs.h"
+
+#include "messageeditor.h"
+#include <qpushbutton.h>
+#include "messageeditor.moc"
+
+MessageEditor::MessageEditor( QWidget *parent )
+ : KDialogBase(Plain,i18n("Edit Message Buttons"),Ok|Cancel,Ok,parent,0,
+ true,true)
+{
+ QFrame *topFrame = plainPage();
+ QBoxLayout *topLayout = new QVBoxLayout(topFrame,0,spacingHint());
+
+ QBoxLayout *selectionLayout = new QHBoxLayout;
+ topLayout->addLayout(selectionLayout);
+
+ QLabel *selectionLabel = new QLabel(i18n("Button:"),topFrame);
+ selectionLayout->addWidget(selectionLabel);
+
+ mSelectionCombo = new QComboBox(topFrame);
+ selectionLayout->addWidget(mSelectionCombo);
+ connect(mSelectionCombo,SIGNAL(activated(int)),SLOT(changeMessage()));
+
+ QPushButton *addButton = new QPushButton(i18n("Add Button..."),topFrame);
+ selectionLayout->addWidget(addButton);
+ connect(addButton,SIGNAL(clicked()),SLOT(addButton()));
+
+ QPushButton *removeButton = new QPushButton(i18n("Remove Button"),topFrame);
+ selectionLayout->addWidget(removeButton);
+ connect(removeButton,SIGNAL(clicked()),SLOT(removeButton()));
+
+ mMessageEdit = new KTextEdit(topFrame);
+ topLayout->addWidget(mMessageEdit,1);
+
+ updateConfig();
+}
+
+void MessageEditor::updateConfig()
+{
+ mMessageButtons = KBBPrefs::instance()->mMessageButtons;
+
+ mSelectionCombo->clear();
+
+ QMap<QString,QString>::ConstIterator it;
+ for(it = mMessageButtons.begin();it != mMessageButtons.end();++it) {
+ mSelectionCombo->insertItem(it.key());
+ }
+
+ updateMessage();
+}
+
+void MessageEditor::addButton()
+{
+ QString txt;
+ txt = KInputDialog::getText(i18n("Add Message Button"),
+ i18n("Enter button name:"), QString::null,
+ NULL, this );
+
+ if ( !txt.isNull() ) {
+ saveMessage();
+ mSelectionCombo->insertItem(txt);
+ mMessageButtons.insert(txt,"");
+ mSelectionCombo->setCurrentItem(mSelectionCombo->count()-1);
+ updateMessage();
+ }
+
+}
+
+void MessageEditor::removeButton()
+{
+ int result = KMessageBox::warningContinueCancel(this,
+ i18n("Remove the button %1?").arg(mSelectionCombo->currentText()),
+ i18n("Remove"), KGuiItem( i18n("Delete"), "editdelete") );
+
+ if (result == KMessageBox::Continue) {
+ mMessageButtons.remove(mSelectionCombo->currentText());
+ mSelectionCombo->removeItem(mSelectionCombo->currentItem());
+ mSelectionCombo->setCurrentItem(0);
+ updateMessage();
+ }
+}
+
+void MessageEditor::changeMessage()
+{
+ saveMessage();
+ updateMessage();
+}
+
+void MessageEditor::updateMessage()
+{
+ mCurrentButton = mSelectionCombo->currentText();
+
+ mMessageEdit->setText(mMessageButtons[mCurrentButton]);
+}
+
+void MessageEditor::saveMessage()
+{
+ mMessageButtons.replace(mCurrentButton,mMessageEdit->text());
+}
+
+void MessageEditor::slotOk()
+{
+ saveMessage();
+
+ KBBPrefs::instance()->mMessageButtons = mMessageButtons;
+ accept();
+}
diff --git a/kbugbuster/gui/messageeditor.h b/kbugbuster/gui/messageeditor.h
new file mode 100644
index 00000000..e32e8cec
--- /dev/null
+++ b/kbugbuster/gui/messageeditor.h
@@ -0,0 +1,33 @@
+#ifndef MESSAGEEDITOR_H
+#define MESSAGEEDITOR_H
+
+#include <kdialogbase.h>
+
+class QComboBox;
+class KTextEdit;
+
+class MessageEditor : public KDialogBase {
+ Q_OBJECT
+ public:
+ MessageEditor( QWidget *parent );
+
+ protected slots:
+ void slotOk();
+
+ private slots:
+ void addButton();
+ void removeButton();
+ void changeMessage();
+ void saveMessage();
+ void updateMessage();
+ void updateConfig();
+
+ private:
+ QComboBox *mSelectionCombo;
+ KTextEdit *mMessageEdit;
+
+ QString mCurrentButton;
+ QMap <QString,QString> mMessageButtons;
+};
+
+#endif
diff --git a/kbugbuster/gui/msginputdialog.cpp b/kbugbuster/gui/msginputdialog.cpp
new file mode 100644
index 00000000..a3fc39c7
--- /dev/null
+++ b/kbugbuster/gui/msginputdialog.cpp
@@ -0,0 +1,226 @@
+// $Id$
+// (c) 2001, Cornelius Schumacher
+
+#include <ktextedit.h>
+#include <qlayout.h>
+
+#include <klocale.h>
+#include <kdebug.h>
+#include <qcombobox.h>
+#include <qsplitter.h>
+#include <qlabel.h>
+
+#include "messageeditor.h"
+#include "kbbprefs.h"
+#include "bugsystem.h"
+#include "bugcommand.h"
+
+#include "msginputdialog.h"
+#include "msginputdialog.moc"
+
+MsgInputDialog::MsgInputDialog(MsgInputDialog::MessageType type, const Bug &bug,
+ const Package &package, const QString &quotedMsg,
+ QWidget *parent)
+ : KDialogBase(Plain,QString::null,User1|User2|Ok|Cancel,Ok,parent,0,false,
+ true,KStdGuiItem::clear(),i18n( "&Edit Presets..." )),
+ mBug( bug ),
+ mPackage( package ),
+ mType( type )
+{
+ switch ( mType ) {
+ case Close:
+ setCaption( i18n("Close Bug %1").arg( mBug.number() ) );
+ break;
+ case Reply:
+ setCaption( i18n("Reply to Bug") );
+ break;
+ case ReplyPrivate:
+ setCaption( i18n("Reply Privately to Bug") );
+ break;
+ default:
+ break;
+ }
+
+ QFrame *topFrame = plainPage();
+ ( new QHBoxLayout( topFrame ) )->setAutoAdd( true );
+
+ mSplitter = new QSplitter( QSplitter::Horizontal, topFrame );
+
+ QWidget *w = new QWidget( mSplitter );
+ ( new QVBoxLayout( w, spacingHint(), -1 ) )->setAutoAdd( true );
+
+ if ( mType == Reply ) {
+ QWidget *r = new QWidget( w );
+ QHBoxLayout* rlayout = new QHBoxLayout( r );
+
+ QLabel *rlabel = new QLabel( i18n("&Recipient:"),r );
+ QFont f = r->font();
+ f.setBold( true );
+ r->setFont( f );
+ rlayout->add( rlabel );
+
+ mRecipient = new QComboBox( r );
+ mRecipient->insertItem( i18n("Normal (bugs.kde.org & Maintainer & kde-bugs-dist)"), BugCommand::Normal );
+ mRecipient->insertItem( i18n("Maintonly (bugs.kde.org & Maintainer)"), BugCommand::Maintonly );
+ mRecipient->insertItem( i18n("Quiet (bugs.kde.org only)"), BugCommand::Quiet );
+ rlabel->setBuddy( mRecipient );
+ rlayout->add( mRecipient );
+
+ QSpacerItem *rspacer= new QSpacerItem( 1,1,QSizePolicy::Expanding );
+ rlayout->addItem( rspacer );
+
+ // Reply currently only replies to the bug tracking system
+ r->hide();
+ }
+
+
+ QLabel *l = new QLabel( i18n( "&Message" ), w );
+ QFont f = l->font();
+ f.setBold( true );
+ l->setFont( f );
+
+ mMessageEdit = new KTextEdit( w );
+ mMessageEdit->setMinimumWidth( mMessageEdit->fontMetrics().width('x') * 72 );
+ mMessageEdit->setWordWrap( QTextEdit::FixedColumnWidth );
+ mMessageEdit->setWrapColumnOrWidth( 72 );
+ l->setBuddy( mMessageEdit );
+
+ w = new QWidget( mSplitter );
+ ( new QVBoxLayout( w, spacingHint(), -1 ) )->setAutoAdd( true );
+ l = new QLabel( i18n( "&Preset Messages" ), w );
+ l->setFont( f );
+
+ mPresets = new KListBox( w );
+ updatePresets();
+ l->setBuddy( mPresets );
+
+ connect( mPresets, SIGNAL( executed( QListBoxItem* ) ),
+ SLOT( slotPresetSelected( QListBoxItem * ) ) );
+ connect( this, SIGNAL( user2Clicked() ), SLOT( editPresets() ) );
+ connect( this, SIGNAL( user1Clicked() ), SLOT( clearMessage() ) );
+ mMessageEdit->setFocus();
+
+ if ( !quotedMsg.isEmpty() )
+ insertQuotedMessage( quotedMsg );
+
+ readConfig();
+}
+
+MsgInputDialog::~MsgInputDialog()
+{
+ kdDebug() << "MsgInputDialog::~MsgInputDialog()" << endl;
+ writeConfig();
+}
+
+void MsgInputDialog::readConfig()
+{
+ resize( KBBPrefs::instance()->mMsgDlgWidth,
+ KBBPrefs::instance()->mMsgDlgHeight );
+ QValueList<int> sizes = KBBPrefs::instance()->mMsgDlgSplitter;
+ mSplitter->setSizes( sizes );
+}
+
+void MsgInputDialog::writeConfig()
+{
+ KBBPrefs::instance()->mMsgDlgWidth = width();
+ KBBPrefs::instance()->mMsgDlgHeight = height();
+ KBBPrefs::instance()->mMsgDlgSplitter = mSplitter->sizes();
+}
+
+void MsgInputDialog::updatePresets()
+{
+ mPresets->clear();
+
+ QMap<QString,QString> messageButtons = KBBPrefs::instance()->mMessageButtons;
+
+ int id = 0;
+ QMap<QString,QString>::ConstIterator it;
+ for( it = messageButtons.begin(); it != messageButtons.end(); ++it )
+ mPresets->insertItem( it.key(), id );
+}
+
+QString MsgInputDialog::message() const
+{
+ return mMessageEdit->text();
+}
+
+void MsgInputDialog::editPresets()
+{
+ MessageEditor *dlg = new MessageEditor(this);
+ dlg->exec();
+ delete dlg;
+
+ updatePresets();
+}
+
+void MsgInputDialog::slotPresetSelected( QListBoxItem *lbi )
+{
+ mMessageEdit->setText( KBBPrefs::instance()->mMessageButtons[ lbi->text() ] );
+}
+
+void MsgInputDialog::clearMessage()
+{
+ mMessageEdit->setText("");
+}
+
+void MsgInputDialog::queueCommand()
+{
+ switch ( mType ) {
+ case Close:
+ BugSystem::self()->queueCommand(
+ new BugCommandClose( mBug, message(), mPackage ) );
+ break;
+ case Reply:
+ BugSystem::self()->queueCommand(
+ new BugCommandReply( mBug, message(), mRecipient->currentItem() ) );
+ break;
+ case ReplyPrivate:
+ BugSystem::self()->queueCommand(
+ new BugCommandReplyPrivate( mBug, mBug.submitter().email,
+ message() ) );
+ break;
+ default:
+ break;
+ }
+}
+
+void MsgInputDialog::slotOk()
+{
+ queueCommand();
+ delete this;
+}
+
+void MsgInputDialog::slotCancel()
+{
+ delete this;
+}
+
+void MsgInputDialog::insertQuotedMessage( const QString &msg )
+{
+ Q_ASSERT( mMessageEdit->wordWrap() == QTextEdit::FixedColumnWidth );
+
+ const QString quotationMarker = "> ";
+ const unsigned int wrapColumn = mMessageEdit->wrapColumnOrWidth();
+
+ // ### Needs something more sophisticated than simplifyWhiteSpace to
+ // handle quoting multiple paragraphs properly.
+ QString line = msg.simplifyWhiteSpace();
+
+ QString quotedMsg;
+ while ( line.length() + quotationMarker.length() + 1 > wrapColumn ) {
+ int pos = wrapColumn - quotationMarker.length() - 1;
+ while ( pos > 0 && !line[ pos ].isSpace() )
+ --pos;
+ if ( pos == 0 )
+ pos = wrapColumn;
+ quotedMsg += quotationMarker + line.left( pos ) + "\n";
+ line = line.mid( pos + 1 );
+ }
+ quotedMsg += quotationMarker + line + "\n\n";
+
+ mMessageEdit->setText( quotedMsg );
+
+ const int lastPara = mMessageEdit->paragraphs() - 1;
+ const int lastParaLen = mMessageEdit->paragraphLength( lastPara ) - 1;
+ mMessageEdit->setCursorPosition( lastPara, lastParaLen );
+}
diff --git a/kbugbuster/gui/msginputdialog.h b/kbugbuster/gui/msginputdialog.h
new file mode 100644
index 00000000..9de767e3
--- /dev/null
+++ b/kbugbuster/gui/msginputdialog.h
@@ -0,0 +1,55 @@
+#ifndef MSGINPUTDIALOG_H
+#define MSGINPUTDIALOG_H
+
+#include <kdialogbase.h>
+
+#include "bug.h"
+#include "package.h"
+
+class KTextEdit;
+class QSplitter;
+class KListBox;
+
+class MsgInputDialog : public KDialogBase
+{
+ Q_OBJECT
+ public:
+ enum MessageType{ Close, Reply, ReplyPrivate };
+
+ MsgInputDialog( MessageType, const Bug &, const Package &,
+ const QString &, QWidget *parent=0);
+ virtual ~MsgInputDialog();
+
+ QString message() const;
+
+ protected slots:
+ void slotOk();
+ void slotCancel();
+
+ private slots:
+ void editPresets();
+ void updatePresets();
+ void slotPresetSelected( QListBoxItem * );
+ void clearMessage();
+ void queueCommand();
+
+ private:
+ void createButtons();
+ void createLayout();
+
+ void readConfig();
+ void writeConfig();
+
+ void insertQuotedMessage( const QString &quotedMsg );
+
+ QComboBox *mRecipient;
+ KTextEdit *mMessageEdit;
+ QSplitter *mSplitter;
+ KListBox *mPresets;
+
+ Bug mBug;
+ Package mPackage;
+ MessageType mType;
+};
+
+#endif
diff --git a/kbugbuster/gui/packagelvi.cpp b/kbugbuster/gui/packagelvi.cpp
new file mode 100644
index 00000000..7fe7cfe6
--- /dev/null
+++ b/kbugbuster/gui/packagelvi.cpp
@@ -0,0 +1,38 @@
+/*
+ packagelvi.cpp - Custom QListViewItem that holds a Package object
+
+ copyright : (c) 2001 by Martijn Klingens
+ email : klingens@kde.org
+
+ *************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the 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 "packagelvi.h"
+
+PackageLVI::PackageLVI( QListView *parent , const Package &pkg, const QString &component )
+: QListViewItem( parent, pkg.name(), pkg.description() )
+{
+ m_package = pkg;
+ m_component = component;
+}
+
+PackageLVI::PackageLVI( QListViewItem *parent , const Package &pkg, const QString &component )
+: QListViewItem( parent, component )
+{
+ m_package = pkg;
+ m_component = component;
+}
+
+PackageLVI::~PackageLVI()
+{
+}
+
+/* vim: set et ts=4 sw=4 softtabstop=4: */
+
diff --git a/kbugbuster/gui/packagelvi.h b/kbugbuster/gui/packagelvi.h
new file mode 100644
index 00000000..32f48642
--- /dev/null
+++ b/kbugbuster/gui/packagelvi.h
@@ -0,0 +1,51 @@
+/*
+ packagelvi.h - Custom QListViewItem that holds a Package object
+
+ copyright : (c) 2001 by Martijn Klingens
+ email : klingens@kde.org
+
+ *************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the 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 PACKAGELVI_H
+#define PACKAGELVI_H
+
+#include <qlistview.h>
+
+#include "package.h"
+
+/**
+ * @author Martijn Klingens
+ */
+class PackageLVI : public QListViewItem
+{
+public:
+ // Top-level package
+ PackageLVI( QListView *parent , const Package &pkg, const QString &component );
+ // Child component
+ PackageLVI( QListViewItem *parent , const Package &pkg, const QString &component );
+
+ ~PackageLVI();
+
+ Package& package() { return m_package; }
+ void setPackage( const Package &pkg ) { m_package = pkg; }
+
+ QString component() { return m_component; }
+ void setComponent( const QString &component ) { m_component = component; }
+
+private:
+ Package m_package;
+ QString m_component;
+};
+
+#endif // PACKAGELVI_H
+
+/* vim: set et ts=4 softtabstop=4 sw=4: */
+
diff --git a/kbugbuster/gui/packageselectdialog.cpp b/kbugbuster/gui/packageselectdialog.cpp
new file mode 100644
index 00000000..7b791e9d
--- /dev/null
+++ b/kbugbuster/gui/packageselectdialog.cpp
@@ -0,0 +1,214 @@
+#include <qlistview.h>
+#include <qlayout.h>
+#include <qheader.h>
+
+#include <kdebug.h>
+#include <kcompletion.h>
+#include <klineedit.h>
+
+#include "bugsystem.h"
+#include "kbbprefs.h"
+#include "bugserver.h"
+
+#include "packagelvi.h"
+#include "packageselectdialog.h"
+#include "packageselectdialog.moc"
+
+PackageListView::PackageListView( QWidget *parent ) :
+ QListView( parent )
+{
+ setFocusPolicy( QWidget::StrongFocus );
+}
+
+void PackageListView::resetTyped()
+{
+ mTyped = "";
+}
+
+void PackageListView::keyPressEvent( QKeyEvent *e )
+{
+ // Disable listview text completion for now
+ QListView::keyPressEvent( e );
+ return;
+
+ int k = e->key();
+ if ( k == Key_Return || k == Key_Escape ) e->ignore();
+
+ QString key = e->text();
+ mTyped.append(key);
+ emit typed( mTyped );
+}
+
+PackageSelectDialog::PackageSelectDialog(QWidget *parent,const char *name) :
+ KDialogBase( parent, name, true, i18n("Select Product"), Ok|Cancel )
+{
+ QWidget *topWidget = new QWidget( this );
+ setMainWidget( topWidget );
+
+ QBoxLayout *topLayout = new QVBoxLayout( topWidget );
+ QSplitter *topSplitter = new QSplitter( QSplitter::Vertical, topWidget );
+ topSplitter->setOpaqueResize( true );
+
+ topLayout->addWidget( topSplitter );
+
+ mRecentList = new QListView( topSplitter );
+ mRecentList->addColumn( i18n("Recent") );
+ mRecentList->resize( mRecentList->width(), mRecentList->fontMetrics().height() *
+ KBBPrefs::instance()->mRecentPackagesCount );
+
+ connect( mRecentList, SIGNAL( mouseButtonPressed( int, QListViewItem *, const QPoint &, int) ),
+ SLOT( recentSelected( int, QListViewItem * ) ) );
+ connect( mRecentList, SIGNAL( doubleClicked( QListViewItem * ) ),
+ SLOT( slotOk() ) );
+
+ mCompletion = new KCompletion;
+ mCompletion->setCompletionMode( KGlobalSettings::CompletionAuto );
+
+ mCompleteList = new PackageListView( topSplitter );
+ mCompleteList->addColumn( i18n("Name") );
+ mCompleteList->addColumn( i18n("Description") );
+ mCompleteList->setRootIsDecorated(true);
+ mCompleteList->setAllColumnsShowFocus( true );
+ connect( mCompleteList, SIGNAL( typed( const QString & ) ),
+ SLOT( completeTyped( const QString & ) ) );
+
+
+ connect( mCompleteList, SIGNAL( mouseButtonPressed( int, QListViewItem *, const QPoint &, int) ),
+ SLOT( completeSelected( int, QListViewItem * ) ) );
+ connect( mCompleteList, SIGNAL( doubleClicked( QListViewItem * ) ),
+ SLOT( slotOk() ) );
+
+ mPackageEdit = new KLineEdit( topWidget );
+ mPackageEdit->setFocus();
+
+ topLayout->addWidget( mPackageEdit );
+ connect( mPackageEdit, SIGNAL( textChanged( const QString & ) ),
+ SLOT( completeTyped( const QString & ) ) );
+ enableButtonOK( !mPackageEdit->text().isEmpty() );
+}
+
+PackageSelectDialog::~PackageSelectDialog()
+{
+ delete mCompletion;
+}
+
+void PackageSelectDialog::setRecentPackages( const QStringList &recent )
+{
+ mRecentList->clear();
+ QStringList::ConstIterator it;
+ for( it = recent.begin(); it != recent.end(); ++it ) {
+ new QListViewItem( mRecentList, *it );
+ }
+}
+
+void PackageSelectDialog::setPackages( const Package::List &pkgs )
+{
+ mCompleteList->clear();
+ mCompletion->clear();
+ mCompletionDict.clear();
+ Package::List::ConstIterator it;
+ for( it = pkgs.begin(); it != pkgs.end(); ++it ) {
+ PackageLVI *item = new PackageLVI( mCompleteList, (*it), QString::null );
+ QStringList components = (*it).components();
+
+ if (components.count() > 1) {
+ for( QStringList::ConstIterator cit = components.begin(); cit != components.end(); ++cit ) {
+ PackageLVI *component = new PackageLVI( item, (*it), (*cit) );
+ QString completionName = (*it).name() + "/" + (*cit);
+
+ mCompletion->addItem( completionName );
+ mCompletionDict.insert( completionName, component );
+ }
+ }
+
+ mCompletion->addItem( (*it).name() );
+ mCompletionDict.insert((*it).name(),item);
+ }
+}
+
+void PackageSelectDialog::recentSelected( int, QListViewItem *item )
+{
+ kdDebug() << "PackageSelectDialog::recentSelected()" << endl;
+ if ( item ) {
+ mCompleteList->clearSelection();
+ // Why does a QLineEdit->setText() call emit the textChanged() signal?
+ mPackageEdit->blockSignals( true );
+ mPackageEdit->setText( item->text( 0 ) );
+ enableButtonOK(true);
+ mPackageEdit->blockSignals( false );
+ }
+}
+
+void PackageSelectDialog::completeSelected( int, QListViewItem *item )
+{
+ PackageLVI *lvi = dynamic_cast<PackageLVI*>(item);
+
+ if ( lvi ) {
+ mRecentList->clearSelection();
+ if ( lvi->component().isEmpty() ) {
+ mPackageEdit->setText( lvi->package().name() );
+ }
+ else {
+ mPackageEdit->setText( lvi->package().name() + "/" + lvi->component() );
+ }
+ }
+}
+
+void PackageSelectDialog::slotOk()
+{
+ PackageLVI *item = (PackageLVI *)mCompleteList->selectedItem();
+ if ( item ) {
+ mSelectedPackage = item->package();
+ mSelectedComponent = item->component();
+
+ QString recent_key;
+ if ( item->component().isEmpty() )
+ recent_key = item->package().name();
+ else
+ recent_key = item->package().name() + "/" + item->component();
+
+ BugServer *server = BugSystem::self()->server();
+ QStringList recent = server->serverConfig().recentPackages();
+ if( !recent.contains( recent_key ) ) {
+ recent.prepend( recent_key );
+ if ( int( recent.count() ) > KBBPrefs::instance()->mRecentPackagesCount ) {
+ recent.remove( recent.last() );
+ }
+ kdDebug() << "RECENT: " << recent.join(",") << endl;
+ server->serverConfig().setRecentPackages( recent );
+ }
+ } else {
+ QListViewItem *recentItem = mRecentList->selectedItem();
+ if ( recentItem ) {
+ QStringList tokens = QStringList::split( '/', recentItem->text( 0 ) );
+ mSelectedPackage = BugSystem::self()->package( tokens[0] );
+ mSelectedComponent = tokens[1];
+ }
+ }
+ mCompleteList->resetTyped();
+ accept();
+}
+
+Package PackageSelectDialog::selectedPackage()
+{
+ return mSelectedPackage;
+}
+
+QString PackageSelectDialog::selectedComponent()
+{
+ return mSelectedComponent;
+}
+
+void PackageSelectDialog::completeTyped( const QString &typed )
+{
+ kdDebug() << "completeTyped: " << typed << endl;
+ QString completed = mCompletion->makeCompletion( typed );
+ kdDebug() << "completed: " << completed << endl;
+ if ( !completed.isEmpty() ) {
+ mCompleteList->setSelected( mCompletionDict[ completed ], true );
+ mCompleteList->ensureItemVisible( mCompletionDict[ completed ] );
+ } else {
+ mCompleteList->resetTyped();
+ }
+ enableButtonOK( !typed.isEmpty() );
+}
diff --git a/kbugbuster/gui/packageselectdialog.h b/kbugbuster/gui/packageselectdialog.h
new file mode 100644
index 00000000..1fe596aa
--- /dev/null
+++ b/kbugbuster/gui/packageselectdialog.h
@@ -0,0 +1,64 @@
+#ifndef PACKAGESELECTDIALOG_H
+#define PACKAGESELECTDIALOG_H
+
+#include <qdict.h>
+
+#include <kdialogbase.h>
+
+#include "package.h"
+
+class KCompletion;
+class KLineEdit;
+
+class PackageListView : public QListView
+{
+ Q_OBJECT
+ public:
+ PackageListView( QWidget *parent );
+
+ void resetTyped();
+
+ signals:
+ void typed( const QString & );
+
+ protected:
+ void keyPressEvent( QKeyEvent *e );
+
+ private:
+ QString mTyped;
+};
+
+class PackageSelectDialog : public KDialogBase
+{
+ Q_OBJECT
+ public:
+ PackageSelectDialog(QWidget *parent=0,const char *name=0);
+ ~PackageSelectDialog();
+
+ void setRecentPackages( const QStringList & );
+ void setPackages( const Package::List &pkgs );
+
+ Package selectedPackage();
+ QString selectedComponent();
+
+ protected slots:
+ void slotOk();
+
+ private slots:
+ void recentSelected( int, QListViewItem * );
+ void completeSelected( int, QListViewItem * );
+ void completeTyped( const QString & );
+
+ private:
+ Package::List mPackages;
+ Package mSelectedPackage;
+ QString mSelectedComponent;
+
+ QListView *mRecentList;
+ PackageListView *mCompleteList;
+ KLineEdit *mPackageEdit;
+ KCompletion *mCompletion;
+ QDict<QListViewItem> mCompletionDict;
+};
+
+#endif
diff --git a/kbugbuster/gui/preferencesdialog.cpp b/kbugbuster/gui/preferencesdialog.cpp
new file mode 100644
index 00000000..9cafff28
--- /dev/null
+++ b/kbugbuster/gui/preferencesdialog.cpp
@@ -0,0 +1,306 @@
+#include <qradiobutton.h>
+#include <qcheckbox.h>
+#include <qlineedit.h>
+#include <qpushbutton.h>
+#include <qlayout.h>
+#include <qgroupbox.h>
+#include <qbuttongroup.h>
+#include <qlistview.h>
+#include <qhbox.h>
+
+#include <knuminput.h>
+#include <kurl.h>
+#include <kmessagebox.h>
+#include <kiconloader.h>
+#include <kdebug.h>
+
+#include "mailsender.h"
+#include "kbbprefs.h"
+#include "kbbmainwindow.h"
+#include "serverconfigdialog.h"
+#include "bugsystem.h"
+#include "bugserver.h"
+#include "bugserverconfig.h"
+
+#include "preferencesdialog.h"
+
+class ServerItem : public QListViewItem
+{
+ public:
+ ServerItem( QListView *listView, const BugServerConfig &cfg )
+ : QListViewItem( listView )
+ {
+ setServerConfig( cfg );
+ }
+
+ void setServerConfig( const BugServerConfig &cfg )
+ {
+ mServerConfig = cfg;
+ setText( 0, cfg.name() );
+ setText( 1, cfg.baseUrl().prettyURL() );
+ setText( 2, cfg.user() );
+ setText( 3, cfg.bugzillaVersion() );
+ }
+
+ const BugServerConfig &serverConfig() const { return mServerConfig; }
+
+ private:
+ BugServerConfig mServerConfig;
+};
+
+class ServerListView : public QListView
+{
+ public:
+ ServerListView( QWidget *parent ) : QListView( parent )
+ {
+ addColumn( i18n("Name") );
+ addColumn( i18n("Base URL") );
+ addColumn( i18n("User") );
+ addColumn( i18n("Version") );
+ }
+};
+
+PreferencesDialog::PreferencesDialog( QWidget* parent, const char* name )
+ : KDialogBase ( IconList, i18n("Preferences"), Ok|Apply|Cancel, Ok,
+ parent, name, false, true )
+{
+ setupServerPage();
+ setupAdvancedPage();
+
+ readConfig();
+}
+
+PreferencesDialog::~PreferencesDialog()
+{
+}
+
+void PreferencesDialog::setupServerPage()
+{
+ QFrame *topFrame = addPage( i18n("Servers"), 0,
+ DesktopIcon( "gohome", KIcon::SizeMedium ) );
+
+ QBoxLayout *layout = new QVBoxLayout( topFrame );
+ layout->setSpacing( spacingHint() );
+
+ mServerList = new ServerListView( topFrame );
+ layout->addWidget( mServerList );
+
+ QHBox *buttonBox = new QHBox( topFrame );
+ buttonBox->setSpacing( spacingHint() );
+ layout->addWidget( buttonBox );
+
+ QPushButton *addButton = new QPushButton( i18n("Add Server..."), buttonBox );
+ connect( addButton, SIGNAL( clicked() ), SLOT( addServer() ) );
+
+ QPushButton *editButton = new QPushButton( i18n("Edit Server..."), buttonBox );
+ connect( editButton, SIGNAL( clicked() ), SLOT( editServer() ) );
+
+ QPushButton *removeButton = new QPushButton( i18n("Delete Server"), buttonBox );
+ connect( removeButton, SIGNAL( clicked() ), SLOT( removeServer() ) );
+
+ QPushButton *button = new QPushButton( i18n("Select Server From List..."),
+ topFrame );
+ layout->addWidget( button );
+ connect( button, SIGNAL( clicked() ), SLOT( selectServer() ) );
+ connect( mServerList, SIGNAL( doubleClicked ( QListViewItem *)), this, SLOT( editServer()));
+}
+
+void PreferencesDialog::setupAdvancedPage()
+{
+ QFrame *topFrame = addPage( i18n("Advanced"), 0,
+ DesktopIcon( "misc", KIcon::SizeMedium ) );
+
+ QBoxLayout *layout = new QVBoxLayout( topFrame );
+ layout->setSpacing( spacingHint() );
+
+ QButtonGroup *mailGroup = new QButtonGroup( 1, Horizontal,
+ i18n( "Mail Client" ), topFrame );
+ layout->addWidget( mailGroup );
+
+ mKMailButton = new QRadioButton( i18n( "&KMail" ), mailGroup );
+ mDirectButton = new QRadioButton( i18n( "D&irect" ), mailGroup );
+ mSendmailButton = new QRadioButton( i18n( "&Sendmail" ), mailGroup );
+
+ mShowClosedCheckBox = new QCheckBox( i18n( "Show closed bugs" ), topFrame );
+ layout->addWidget( mShowClosedCheckBox );
+
+ mShowWishesCheckBox = new QCheckBox( i18n( "Show wishes" ), topFrame );
+ layout->addWidget( mShowWishesCheckBox );
+
+ mShowVotedCheckBox = new QCheckBox( i18n( "Show bugs with number of votes greater than:" ), topFrame );
+ layout->addWidget( mShowVotedCheckBox );
+
+ mMinVotesInput = new KIntNumInput( topFrame );
+ mMinVotesInput->setMinValue( 0 );
+ connect( mShowVotedCheckBox, SIGNAL(toggled(bool)),
+ mMinVotesInput, SLOT(setEnabled(bool)) );
+ layout->addWidget( mMinVotesInput );
+
+ mSendBccCheckBox = new QCheckBox( i18n( "Send BCC to myself" ), topFrame );
+ layout->addWidget( mSendBccCheckBox );
+}
+
+void PreferencesDialog::setDefaults()
+{
+ KBBPrefs::instance()->setDefaults();
+ readConfig();
+}
+
+void PreferencesDialog::slotApply()
+{
+ writeConfig();
+}
+
+void PreferencesDialog::slotOk()
+{
+ writeConfig();
+ accept();
+}
+
+void PreferencesDialog::slotCancel()
+{
+ hide();
+}
+
+void PreferencesDialog::addServer()
+{
+ ServerConfigDialog *dlg = new ServerConfigDialog( this );
+ int result = dlg->exec();
+ if ( result == QDialog::Accepted ) {
+ new ServerItem( mServerList, dlg->serverConfig() );
+ }
+}
+
+void PreferencesDialog::editServer()
+{
+ ServerItem *item = static_cast<ServerItem *>( mServerList->currentItem() );
+ if ( !item ) return;
+
+ ServerConfigDialog *dlg = new ServerConfigDialog( this );
+ dlg->setServerConfig( item->serverConfig() );
+
+ int result = dlg->exec();
+ if ( result == QDialog::Accepted ) {
+ item->setServerConfig( dlg->serverConfig() );
+ }
+}
+
+void PreferencesDialog::removeServer()
+{
+ QListViewItem *item = mServerList->currentItem();
+ if ( !item ) return;
+
+ delete item;
+}
+
+void PreferencesDialog::selectServer()
+{
+ SelectServerDlg *dlg =new SelectServerDlg( this, "Select Server" );
+
+ int result = dlg->exec();
+ if ( result == QDialog::Accepted ) {
+ ServerItem *item = dlg->serverSelected();
+ if ( item ) {
+ new ServerItem( mServerList, item->serverConfig() );
+ }
+ }
+ delete dlg;
+}
+
+void PreferencesDialog::createServerItem( ServerListView *listView,
+ const QString &name,
+ const QString &url,
+ const QString &version )
+{
+ BugServerConfig cfg( name, KURL( url ) );
+ cfg.setBugzillaVersion( version );
+ new ServerItem( listView, cfg );
+}
+
+void PreferencesDialog::readConfig()
+{
+ int client = KBBPrefs::instance()->mMailClient;
+ switch(client) {
+ default:
+ case MailSender::KMail:
+ mKMailButton->setChecked(true);
+ break;
+ case MailSender::Sendmail:
+ mSendmailButton->setChecked(true);
+ break;
+ case MailSender::Direct:
+ mDirectButton->setChecked(true);
+ break;
+ }
+ mShowClosedCheckBox->setChecked( KBBPrefs::instance()->mShowClosedBugs );
+ mShowWishesCheckBox->setChecked( KBBPrefs::instance()->mShowWishes );
+ mShowVotedCheckBox->setChecked( KBBPrefs::instance()->mShowVoted );
+ mMinVotesInput->setValue( KBBPrefs::instance()->mMinVotes );
+ mSendBccCheckBox->setChecked( KBBPrefs::instance()->mSendBCC );
+
+ mServerList->clear();
+ QValueList<BugServer *> servers = BugSystem::self()->serverList();
+ QValueList<BugServer *>::ConstIterator it;
+ for( it = servers.begin(); it != servers.end(); ++it ) {
+ new ServerItem( mServerList, (*it)->serverConfig() );
+ }
+}
+
+void PreferencesDialog::writeConfig()
+{
+ MailSender::MailClient client = MailSender::KMail;
+
+ if (mKMailButton->isChecked()) client = MailSender::KMail;
+ if (mSendmailButton->isChecked()) client = MailSender::Sendmail;
+ if (mDirectButton->isChecked()) client = MailSender::Direct;
+
+ KBBPrefs::instance()->mMailClient = client;
+ KBBPrefs::instance()->mShowClosedBugs = mShowClosedCheckBox->isChecked();
+ KBBPrefs::instance()->mShowWishes = mShowWishesCheckBox->isChecked();
+ KBBPrefs::instance()->mShowVoted = mShowVotedCheckBox->isChecked();
+ KBBPrefs::instance()->mMinVotes = mMinVotesInput->value();
+ KBBPrefs::instance()->mSendBCC = mSendBccCheckBox->isChecked();
+ KBBPrefs::instance()->writeConfig();
+
+ QValueList<BugServerConfig> servers;
+ QListViewItem *item;
+ for ( item = mServerList->firstChild(); item;
+ item = item->nextSibling() ) {
+ servers.append( static_cast<ServerItem *>( item )->serverConfig() );
+ }
+
+ BugSystem::self()->setServerList( servers );
+
+ emit configChanged();
+}
+
+SelectServerDlg::SelectServerDlg(PreferencesDialog *parent, const char */*name*/ )
+ :KDialogBase(parent, 0, true, i18n("Select Server"),
+ KDialogBase::Ok | KDialogBase::Cancel)
+{
+ list = new ServerListView(this );
+ setMainWidget( list );
+
+ parent->createServerItem( list, "KDE", "http://bugs.kde.org", "KDE" );
+ parent->createServerItem( list, "GNOME", "http://bugzilla.gnome.org", "2.10" );
+ parent->createServerItem( list, "Mozilla", "http://bugzilla.mozilla.org", "2.17.1" );
+ parent->createServerItem( list, "Apache", "http://nagoya.apache.org/bugzilla/", "2.14.2" );
+ parent->createServerItem( list, "XFree86", "http://bugs.xfree86.org/cgi-bin/bugzilla/", "2.14.2" );
+ parent->createServerItem( list, "Ximian", "http://bugzilla.ximian.com", "2.10" );
+ parent->createServerItem( list, "RedHat", "http://bugzilla.redhat.com/bugzilla/", "2.17.1" );
+ parent->createServerItem( list, "Mandriva", "http://qa.mandriva.com/", "2.17.4" );
+ connect( list, SIGNAL( doubleClicked ( QListViewItem *)), this, SLOT( slotDoubleClicked( QListViewItem *)));
+}
+
+
+ServerItem *SelectServerDlg::serverSelected()
+{
+ return static_cast<ServerItem *>( list->currentItem() );
+}
+
+void SelectServerDlg::slotDoubleClicked( QListViewItem *)
+{
+ accept();
+}
+
+#include "preferencesdialog.moc"
diff --git a/kbugbuster/gui/preferencesdialog.h b/kbugbuster/gui/preferencesdialog.h
new file mode 100644
index 00000000..29c72eaf
--- /dev/null
+++ b/kbugbuster/gui/preferencesdialog.h
@@ -0,0 +1,76 @@
+#ifndef PREFERENCESDIALOG_H
+#define PREFERENCESDIALOG_H
+
+#include <kdialogbase.h>
+
+class QCheckBox;
+class QRadioButton;
+class QLineEdit;
+class QListView;
+class KIntNumInput;
+class ServerListView;
+
+class PreferencesDialog : public KDialogBase
+{
+ Q_OBJECT
+ public:
+ PreferencesDialog( QWidget* parent = 0, const char* name = 0 );
+ ~PreferencesDialog();
+
+ void createServerItem( ServerListView *listView, const QString &name,
+ const QString &url, const QString &version );
+
+ public:
+ void readConfig();
+ void writeConfig();
+
+ signals:
+ void configChanged();
+
+ protected slots:
+ void setDefaults();
+ void slotApply();
+ void slotOk();
+ void slotCancel();
+
+ void addServer();
+ void editServer();
+ void removeServer();
+
+ void selectServer();
+
+ protected:
+ void setupServerPage();
+ void setupAdvancedPage();
+
+
+ private:
+ QCheckBox *mShowClosedCheckBox;
+ QCheckBox *mShowWishesCheckBox;
+ QCheckBox *mShowVotedCheckBox;
+ QCheckBox *mSendBccCheckBox;
+ KIntNumInput *mMinVotesInput;
+ QRadioButton *mKMailButton;
+ QRadioButton *mDirectButton;
+ QRadioButton *mSendmailButton;
+ QListView *mServerList;
+};
+
+class ServerListView;
+class ServerItem;
+
+class SelectServerDlg : public KDialogBase
+{
+ Q_OBJECT
+public:
+ SelectServerDlg(PreferencesDialog *parent, const char */*name*/ );
+ ServerItem *serverSelected();
+protected slots:
+ void slotDoubleClicked( QListViewItem *);
+
+protected:
+ ServerListView *list;
+};
+
+
+#endif
diff --git a/kbugbuster/gui/serverconfigdialog.cpp b/kbugbuster/gui/serverconfigdialog.cpp
new file mode 100644
index 00000000..32c5e241
--- /dev/null
+++ b/kbugbuster/gui/serverconfigdialog.cpp
@@ -0,0 +1,82 @@
+#include "serverconfigdialog.h"
+
+#include "bugserverconfig.h"
+
+#include <kpassdlg.h>
+#include <kdebug.h>
+#include <klocale.h>
+
+#include <qlayout.h>
+#include <qlineedit.h>
+#include <qlabel.h>
+#include <qvbox.h>
+#include <qcombobox.h>
+
+ServerConfigDialog::ServerConfigDialog( QWidget *parent, const char *name ) :
+ KDialogBase( parent, name, true, i18n("Edit Bugzilla Server"), Ok|Cancel )
+{
+ QWidget *topFrame = makeMainWidget();
+
+ QGridLayout *topLayout = new QGridLayout( topFrame );
+ topLayout->setSpacing( spacingHint() );
+
+ QLabel *label;
+
+ mServerName = new QLineEdit( topFrame );
+ label = new QLabel( mServerName, i18n("Name:"), topFrame );
+ topLayout->addWidget( label, 0, 0 );
+ topLayout->addWidget( mServerName, 0, 1 );
+ mServerName->setFocus();
+
+ mServerUrl = new QLineEdit( topFrame );
+ label = new QLabel( mServerUrl, i18n("URL:"), topFrame );
+ topLayout->addWidget( label, 1, 0 );
+ topLayout->addWidget( mServerUrl, 1, 1 );
+
+ mUser = new QLineEdit( topFrame );
+ label = new QLabel( mUser, i18n("User:"), topFrame );
+ topLayout->addWidget( label, 2, 0 );
+ topLayout->addWidget( mUser, 2, 1 );
+
+ mPassword = new KPasswordEdit( topFrame );
+ label = new QLabel( mPassword, i18n("Password:"), topFrame );
+ topLayout->addWidget( label, 3, 0 );
+ topLayout->addWidget( mPassword, 3, 1 );
+
+ mVersion = new QComboBox( topFrame );
+ label = new QLabel( mVersion, i18n("Bugzilla version:"), topFrame );
+ topLayout->addWidget( label, 4, 0 );
+ topLayout->addWidget( mVersion, 4, 1 );
+ mVersion->insertStringList( BugServerConfig::bugzillaVersions() );
+}
+
+void ServerConfigDialog::setServerConfig( const BugServerConfig &cfg )
+{
+ mServerName->setText( cfg.name() );
+ mServerUrl->setText( cfg.baseUrl().url() );
+ mUser->setText( cfg.user() );
+ mPassword->setText( cfg.password() );
+
+ int i;
+ for( i = 0; i < mVersion->count(); ++i ) {
+ if ( mVersion->text( i ) == cfg.bugzillaVersion() ) {
+ mVersion->setCurrentItem( i );
+ break;
+ }
+ }
+}
+
+BugServerConfig ServerConfigDialog::serverConfig()
+{
+ BugServerConfig cfg;
+
+ cfg.setName( mServerName->text() );
+ cfg.setBaseUrl( KURL( mServerUrl->text() ) );
+ cfg.setUser( mUser->text() );
+ cfg.setPassword( mPassword->text() );
+ cfg.setBugzillaVersion( mVersion->currentText() );
+
+ return cfg;
+}
+
+#include "serverconfigdialog.moc"
diff --git a/kbugbuster/gui/serverconfigdialog.h b/kbugbuster/gui/serverconfigdialog.h
new file mode 100644
index 00000000..5764bfdf
--- /dev/null
+++ b/kbugbuster/gui/serverconfigdialog.h
@@ -0,0 +1,28 @@
+#ifndef SERVERCONFIGDIALOG_H
+#define SERVERCONFIGDIALOG_H
+
+#include <kdialogbase.h>
+
+class BugServerConfig;
+class QLineEdit;
+class KPasswordEdit;
+class QComboBox;
+
+class ServerConfigDialog : public KDialogBase
+{
+ Q_OBJECT
+ public:
+ ServerConfigDialog( QWidget *parent = 0 , const char *name = 0 );
+
+ void setServerConfig( const BugServerConfig & );
+ BugServerConfig serverConfig();
+
+ private:
+ QLineEdit *mServerName;
+ QLineEdit *mServerUrl;
+ QLineEdit *mUser;
+ KPasswordEdit *mPassword;
+ QComboBox *mVersion;
+};
+
+#endif
diff --git a/kbugbuster/gui/severityselectdialog.cpp b/kbugbuster/gui/severityselectdialog.cpp
new file mode 100644
index 00000000..714e6f3a
--- /dev/null
+++ b/kbugbuster/gui/severityselectdialog.cpp
@@ -0,0 +1,40 @@
+#include <qlayout.h>
+#include <qbuttongroup.h>
+#include <qradiobutton.h>
+
+#include <kdebug.h>
+
+#include "bugsystem.h"
+#include "kbbprefs.h"
+
+#include "severityselectdialog.h"
+#include "severityselectdialog.moc"
+
+SeveritySelectDialog::SeveritySelectDialog(QWidget *parent,const char *name) :
+ KDialogBase( parent, name, true, i18n("Select Severity"), Ok|Cancel )
+{
+ mButtonGroup = new QButtonGroup( 1, Horizontal, i18n("Severity"), this );
+ setMainWidget( mButtonGroup );
+
+ QValueList<Bug::Severity> severities = Bug::severities();
+ QValueList<Bug::Severity>::ConstIterator it;
+ for( it = severities.begin(); it != severities.end(); ++it ) {
+ mButtonGroup->insert(
+ new QRadioButton( Bug::severityToString( *it ), mButtonGroup ), int(*it) );
+ }
+}
+
+void SeveritySelectDialog::setSeverity( Bug::Severity s )
+{
+ mButtonGroup->setButton( s );
+}
+
+Bug::Severity SeveritySelectDialog::selectedSeverity()
+{
+ return (Bug::Severity)mButtonGroup->id( mButtonGroup->selected() );
+}
+
+QString SeveritySelectDialog::selectedSeverityAsString()
+{
+ return Bug::severityToString( selectedSeverity() );
+}
diff --git a/kbugbuster/gui/severityselectdialog.h b/kbugbuster/gui/severityselectdialog.h
new file mode 100644
index 00000000..12f36fe5
--- /dev/null
+++ b/kbugbuster/gui/severityselectdialog.h
@@ -0,0 +1,23 @@
+#ifndef SEVERITYSELECTDIALOG_H
+#define SEVERITYSELECTDIALOG_H
+
+#include <kdialogbase.h>
+
+#include "bug.h"
+
+class SeveritySelectDialog : public KDialogBase
+{
+ Q_OBJECT
+ public:
+ SeveritySelectDialog(QWidget *parent=0,const char *name=0);
+
+ void setSeverity( Bug::Severity );
+
+ Bug::Severity selectedSeverity();
+ QString selectedSeverityAsString();
+
+ private:
+ QButtonGroup *mButtonGroup;
+};
+
+#endif
diff --git a/kbugbuster/hi128-app-kbugbuster.png b/kbugbuster/hi128-app-kbugbuster.png
new file mode 100644
index 00000000..a39081d9
--- /dev/null
+++ b/kbugbuster/hi128-app-kbugbuster.png
Binary files differ
diff --git a/kbugbuster/hi16-app-kbugbuster.png b/kbugbuster/hi16-app-kbugbuster.png
new file mode 100644
index 00000000..827d5f8e
--- /dev/null
+++ b/kbugbuster/hi16-app-kbugbuster.png
Binary files differ
diff --git a/kbugbuster/hi22-app-kbugbuster.png b/kbugbuster/hi22-app-kbugbuster.png
new file mode 100644
index 00000000..3a3d1ea2
--- /dev/null
+++ b/kbugbuster/hi22-app-kbugbuster.png
Binary files differ
diff --git a/kbugbuster/hi32-app-kbugbuster.png b/kbugbuster/hi32-app-kbugbuster.png
new file mode 100644
index 00000000..59773925
--- /dev/null
+++ b/kbugbuster/hi32-app-kbugbuster.png
Binary files differ
diff --git a/kbugbuster/hi48-app-kbugbuster.png b/kbugbuster/hi48-app-kbugbuster.png
new file mode 100644
index 00000000..2565d767
--- /dev/null
+++ b/kbugbuster/hi48-app-kbugbuster.png
Binary files differ
diff --git a/kbugbuster/hi64-app-kbugbuster.png b/kbugbuster/hi64-app-kbugbuster.png
new file mode 100644
index 00000000..f2f45269
--- /dev/null
+++ b/kbugbuster/hi64-app-kbugbuster.png
Binary files differ
diff --git a/kbugbuster/kbugbuster.desktop b/kbugbuster/kbugbuster.desktop
new file mode 100644
index 00000000..1fa713a9
--- /dev/null
+++ b/kbugbuster/kbugbuster.desktop
@@ -0,0 +1,78 @@
+# KDE Config File
+[Desktop Entry]
+Type=Application
+Exec=kbugbuster -caption "%c" %i %m
+Icon=kbugbuster
+DocPath=kbugbuster/index.html
+GenericName=KDE Bug Management
+GenericName[af]=Kde Fout Bestuuring
+GenericName[bg]=Управление на грешки - KDE
+GenericName[bs]=KDE upravljanje bugovima
+GenericName[ca]=Gestió d'errors a KDE
+GenericName[cs]=Správa chyb KDE
+GenericName[cy]=Rheolaeth Namau KDE
+GenericName[da]=KDE Fejlretningshåndtering
+GenericName[de]=KDE-Programmfehler-Verwaltung
+GenericName[el]=ΔιαχείÏιση σφαλμάτων του KDE
+GenericName[eo]=KDE-Eraroadministrado
+GenericName[es]=Administración de errores de KDE
+GenericName[et]=KDE veahaldusprogramm
+GenericName[eu]=KDE programa-errore kudeaketa
+GenericName[fa]=مدیریت اشکال KDE
+GenericName[fi]=KDE:n vianhallinta
+GenericName[fo]=KDE-villuhandfaring
+GenericName[fr]=Outil de gestion de bogues pour KDE
+GenericName[ga]=Bainisteoireacht Fabhtanna KDE
+GenericName[gl]=Xestión de erros para KDE
+GenericName[he]=ניהול של ב××’×™× ×‘-KDE
+GenericName[hi]=केडीई बग पà¥à¤°à¤¬à¤‚धक
+GenericName[hr]=KDE upravljanje bugovima
+GenericName[hu]=KDE hibakezelő
+GenericName[is]=KDE villustjórnun
+GenericName[it]=Gestione bug di KDE
+GenericName[ja]=KDE ãƒã‚°ãƒžãƒãƒ¼ã‚¸ãƒ¡ãƒ³ãƒˆ
+GenericName[ka]=KDE ბზიკთრმáƒáƒ áƒ—ვáƒ
+GenericName[kk]=KDE қателерді баÑқару
+GenericName[lt]=KDE ydų tvarkymas
+GenericName[lv]=KDE Kļūdu PÄrvalde
+GenericName[ms]=Pengurusan Pepijat KDE
+GenericName[nb]=KDE-feilhåndtering
+GenericName[nds]=KDE-Programmfehler-Pleeg
+GenericName[ne]=केडीई बग पà¥à¤°à¤¬à¤¨à¥à¤§à¤•
+GenericName[nl]=KDE-bugs beheren
+GenericName[nn]=KDE-feilhandtering
+GenericName[pa]=KDE ਬੱਗ ਪਰਬੰਧਨ
+GenericName[pl]=Zarządzanie błędami w KDE
+GenericName[pt]=Gestão de Erros do KDE
+GenericName[pt_BR]=Gerenciamento de Erros do KDE
+GenericName[ro]=Utilitar de administrarea a erorilor din KDE
+GenericName[ru]=ОтÑлеживание ошибок
+GenericName[sk]=Správa chýb KDE
+GenericName[sl]=Upravljanje s hroÅ¡Äi v KDE
+GenericName[sr]=KDE-ово управљање грешкама
+GenericName[sr@Latn]=KDE-ovo upravljanje greškama
+GenericName[sv]=Verktyg för KDE-felhantering
+GenericName[ta]= KDE பக௠மேனேஜà¯à®®à¯†à®©à¯à®Ÿà¯
+GenericName[tg]=Утилитаи идоракунии хатогиҳо
+GenericName[th]=เครื่องมือจัดà¸à¸²à¸£à¸šà¸±à¸à¸ªà¸³à¸«à¸£à¸±à¸š KDE
+GenericName[tr]=KDE Hata Ayıklayıcı
+GenericName[uk]=ÐšÐµÑ€ÑƒÐ²Ð°Ð½Ð½Ñ Ð²Ð°Ð´Ð°Ð¼Ð¸ KDE
+GenericName[ven]=Malangulele a Bug a KDE
+GenericName[vi]=Trình quản lí bug KDE
+GenericName[xh]=Umxholo Wokuxoxwa We KDE
+GenericName[zh_CN]=KDE 除错管ç†
+GenericName[zh_TW]=KDE 臭蟲管ç†
+GenericName[zu]=KDE Ukuphathwa Kwegciwane
+Terminal=false
+Name=KBugBuster
+Name[af]=K-fout-buster
+Name[cy]=KNamWasgydd
+Name[eo]=Eraroĉasilo
+Name[hi]=के-बग-बसà¥à¤Ÿà¤°
+Name[lv]=KKļūduMednieks
+Name[pl]=Przeglądarka bazy błędów
+Name[sv]=Kbugbuster
+Name[ta]= Kபகà¯à®ªà®¸à¯à®Ÿà®°à¯
+Name[th]=บัà¸à¸šà¸±à¸ªà¹€à¸•à¸­à¸£à¹Œ
+Name[ven]=Mupandeli wa Baga wa K
+Categories=Qt;KDE;Development;
diff --git a/kbugbuster/kresources/Makefile.am b/kbugbuster/kresources/Makefile.am
new file mode 100644
index 00000000..ddfde0fa
--- /dev/null
+++ b/kbugbuster/kresources/Makefile.am
@@ -0,0 +1,16 @@
+INCLUDES = -I$(top_srcdir) -I$(top_srcdir)/kbugbuster/backend $(all_includes)
+
+kde_module_LTLIBRARIES = kcal_bugzilla.la
+
+kcal_bugzilla_la_SOURCES = kcalresource.cpp kcalresourceconfig.cpp \
+ kcalresource_plugin.cpp resourceprefs.kcfgc
+kcal_bugzilla_la_LDFLAGS = $(all_libraries) -module $(KDE_PLUGIN)
+kcal_bugzilla_la_LIBADD = ../backend/libkbbbackend.la -lkcal
+
+servicedir = $(kde_servicesdir)/kresources/kcal
+service_DATA = bugzilla.desktop
+
+METASOURCES = AUTO
+
+messages: rc.cpp
+ $(XGETTEXT) *.cpp -o $(podir)/kres_bugzilla.pot
diff --git a/kbugbuster/kresources/bugzilla.desktop b/kbugbuster/kresources/bugzilla.desktop
new file mode 100644
index 00000000..75cbb5a5
--- /dev/null
+++ b/kbugbuster/kresources/bugzilla.desktop
@@ -0,0 +1,48 @@
+[Desktop Entry]
+Name=Bugzilla To-do List
+Name[bg]=Задачи (Bugzilla)
+Name[ca]=Llista de pendents de Bugzilla
+Name[cs]=Seznam úkolů (Bugzilla)
+Name[da]=Bugzilla gøremålsliste
+Name[de]=Bugzilla Todo-Liste
+Name[el]=ΠÏος υλοποίηση λίστα του Bugzilla
+Name[es]=Listado de tareas pendientes de BugZilla
+Name[et]=Bugzilla ülesannete nimekiri
+Name[eu]=Bugzilla-ren egiteke zerrenda
+Name[fa]=Ùهرست کار انجامی Bugzilla
+Name[fi]=Bugzilla-tehtäväluettelo
+Name[fr]=Liste de tâches de Bugzilla
+Name[ga]=Tascliosta Bugzilla
+Name[gl]=Lista de itens por facer de Bugzilla
+Name[he]=רשימת מטלות של Bugzilla
+Name[hu]=Bugzilla feladatlista
+Name[is]=Bugzilla verklisti
+Name[it]=Lista delle cosa da fare di Bugzilla
+Name[ja]=BugzillaToDo リスト
+Name[ka]=Bugzilla-ს დáƒáƒ•áƒáƒšáƒ”ბáƒáƒ—რსიáƒ
+Name[kk]=Bugzilla To-do тізімі
+Name[lt]=Bugzilla darbų sąrašas
+Name[nb]=Bugzilla-huskeliste
+Name[nds]=Bugzilla-Opgavenlist
+Name[ne]=बगजिला गरà¥à¤¨à¥à¤ªà¤°à¥à¤¨à¥‡ कारà¥à¤¯ सूची
+Name[nl]=Bugzilla Todo-lijst
+Name[nn]=Bugzilla-hugseliste
+Name[pa]=ਬੱਗਜੀਲਾ ਕਰਨ ਸੂਚੀ
+Name[pl]=Lista rzeczy do zrobienia w Bugzilli
+Name[pt]=Lista de Itens Por-Fazer do Bugzilla
+Name[pt_BR]=Lista de Itens Por-Fazer do Bugzilla
+Name[ru]=СпиÑок TODO Bugzilla
+Name[sk]=Zoznam úloh v Bugzille
+Name[sl]=Seznam »za-narediti« v Bugzilli
+Name[sr]=ЛиÑта поÑлова Bugzilla-е
+Name[sr@Latn]=Lista poslova Bugzilla-e
+Name[sv]=Bugzilla uppgiftslista
+Name[tr]=Bugzilla To-do Listesi
+Name[uk]=СпиÑок завдань Bugzilla
+Name[zh_CN]=Bugzilla 待办列表
+Name[zh_TW]=Bugzilla 待辦清單
+X-KDE-Library=kcal_bugzilla
+Type=Service
+ServiceTypes=KResources/Plugin
+X-KDE-ResourceFamily=calendar
+X-KDE-ResourceType=bugzilla
diff --git a/kbugbuster/kresources/kcalresource.cpp b/kbugbuster/kresources/kcalresource.cpp
new file mode 100644
index 00000000..fbd91bc1
--- /dev/null
+++ b/kbugbuster/kresources/kcalresource.cpp
@@ -0,0 +1,316 @@
+/*
+ This file is part of KBugBuster.
+
+ Copyright (c) 2003 Cornelius Schumacher <schumacher@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.
+*/
+
+#include <typeinfo>
+#include <stdlib.h>
+
+#include <qdatetime.h>
+#include <qstring.h>
+#include <qptrlist.h>
+
+#include <kdebug.h>
+#include <kurl.h>
+#include <kio/job.h>
+#include <klocale.h>
+#include <kstandarddirs.h>
+
+#include <libkcal/vcaldrag.h>
+#include <libkcal/vcalformat.h>
+#include <libkcal/icalformat.h>
+#include <libkcal/exceptions.h>
+#include <libkcal/incidence.h>
+#include <libkcal/event.h>
+#include <libkcal/todo.h>
+#include <libkcal/journal.h>
+#include <libkcal/filestorage.h>
+
+#include <kabc/locknull.h>
+
+#include <kresources/configwidget.h>
+
+#include "bugsystem.h"
+#include "bugserver.h"
+
+#include "kcalresourceconfig.h"
+#include "resourceprefs.h"
+
+#include "kcalresource.h"
+
+KCalResource::KCalResource( const KConfig* config )
+ : ResourceCached( config ), mLock( 0 )
+{
+ mPrefs = new KBB::ResourcePrefs;
+
+ KConfigSkeletonItem::List items = mPrefs->items();
+ KConfigSkeletonItem::List::Iterator it;
+ for( it = items.begin(); it != items.end(); ++it ) {
+ (*it)->setGroup( identifier() );
+ }
+
+ if ( config ) {
+ readConfig( config );
+ }
+
+ init();
+}
+
+KCalResource::~KCalResource()
+{
+ close();
+
+ if ( mDownloadJob ) mDownloadJob->kill();
+ if ( mUploadJob ) mUploadJob->kill();
+
+ delete mLock;
+}
+
+void KCalResource::init()
+{
+ mDownloadJob = 0;
+ mUploadJob = 0;
+
+ setType( "remote" );
+
+ mOpen = false;
+
+ mLock = new KABC::LockNull( true );
+
+ KConfig config( "kbugbusterrc" );
+
+ BugSystem::self()->readConfig( &config );
+}
+
+KBB::ResourcePrefs *KCalResource::prefs()
+{
+ return mPrefs;
+}
+
+void KCalResource::readConfig( const KConfig * )
+{
+ mPrefs->readConfig();
+}
+
+void KCalResource::writeConfig( KConfig *config )
+{
+ kdDebug() << "KCalResource::writeConfig()" << endl;
+
+ ResourceCalendar::writeConfig( config );
+
+ mPrefs->writeConfig();
+}
+
+QString KCalResource::cacheFile()
+{
+ QString file = locateLocal( "cache", "kcal/kresources/" + identifier() );
+ kdDebug() << "KCalResource::cacheFile(): " << file << endl;
+ return file;
+}
+
+bool KCalResource::doOpen()
+{
+ kdDebug(5800) << "KCalResource::doOpen()" << endl;
+
+ mOpen = true;
+
+ return true;
+}
+
+bool KCalResource::doLoad()
+{
+ kdDebug() << "KCalResource::doLoad()" << endl;
+
+ if ( !mOpen ) return true;
+
+ if ( mDownloadJob ) {
+ kdWarning() << "KCalResource::doLoad(): download still in progress."
+ << endl;
+ return false;
+ }
+ if ( mUploadJob ) {
+ kdWarning() << "KCalResource::doLoad(): upload still in progress."
+ << endl;
+ return false;
+ }
+
+ mCalendar.close();
+
+ mCalendar.load( cacheFile() );
+
+ BugSystem *kbb = BugSystem::self();
+
+ kdDebug() << "KNOWN SERVERS:" << endl;
+ QValueList<BugServer *> servers = kbb->serverList();
+ QValueList<BugServer *>::ConstIterator it;
+ for( it = servers.begin(); it != servers.end(); ++it ) {
+ kdDebug() << " " << (*it)->identifier() << endl;
+ }
+
+ kbb->setCurrentServer( mPrefs->server() );
+ if ( !kbb->server() ) {
+ kdError() << "Server not found." << endl;
+ return false;
+ } else {
+ kdDebug() << "CURRENT SERVER: " << kbb->server()->identifier() << endl;
+ }
+
+ kbb->retrievePackageList();
+
+ Package package = kbb->package( mPrefs->product() );
+
+ connect( kbb, SIGNAL( bugListAvailable( const Package &, const QString &,
+ const Bug::List & ) ),
+ SLOT( slotBugListAvailable( const Package &, const QString &,
+ const Bug::List & ) ) );
+
+ kbb->retrieveBugList( package, mPrefs->component() );
+
+ return true;
+}
+
+void KCalResource::slotBugListAvailable( const Package &, const QString &,
+ const Bug::List &bugs )
+{
+ kdDebug() << "KCalResource::slotBugListAvailable()" << endl;
+
+ if ( bugs.isEmpty() ) return;
+
+ QString masterUid = "kbb_" + BugSystem::self()->server()->identifier();
+ KCal::Todo *masterTodo = mCalendar.todo( masterUid );
+ if ( !masterTodo ) {
+ masterTodo = new KCal::Todo;
+ masterTodo->setUid( masterUid );
+ masterTodo->setSummary( resourceName() );
+ mCalendar.addTodo( masterTodo );
+ }
+
+ Bug::List::ConstIterator it;
+ for( it = bugs.begin(); it != bugs.end(); ++it ) {
+ Bug bug = *it;
+ kdDebug() << " Bug " << bug.number() << ": " << bug.title() << endl;
+ QString uid = "KBugBuster_" + bug.number();
+ KCal::Todo *newTodo = 0;
+ KCal::Todo *todo = mCalendar.todo( uid );
+ if ( !todo ) {
+ newTodo = new KCal::Todo;
+ newTodo->setUid( uid );
+ QString uri = "http://bugs.kde.org/show_bug.cgi?id=%1";
+ newTodo->addAttachment( new KCal::Attachment( uri.arg( bug.number() ) ) );
+ todo = newTodo;
+ }
+
+ todo->setSummary( bug.number() + ": " + bug.title() );
+ todo->setRelatedTo( masterTodo );
+
+ if ( newTodo ) mCalendar.addTodo( newTodo );
+ }
+
+ emit resourceChanged( this );
+}
+
+void KCalResource::slotLoadJobResult( KIO::Job *job )
+{
+ if ( job->error() ) {
+ job->showErrorDialog( 0 );
+ } else {
+ kdDebug() << "KCalResource::slotLoadJobResult() success" << endl;
+
+ mCalendar.close();
+ mCalendar.load( cacheFile() );
+
+ emit resourceChanged( this );
+ }
+
+ mDownloadJob = 0;
+
+ emit resourceLoaded( this );
+}
+
+bool KCalResource::doSave()
+{
+ kdDebug() << "KCalResource::doSave()" << endl;
+
+ if ( !mOpen ) return true;
+
+ if ( readOnly() ) {
+ emit resourceSaved( this );
+ return true;
+ }
+
+ if ( mDownloadJob ) {
+ kdWarning() << "KCalResource::save(): download still in progress."
+ << endl;
+ return false;
+ }
+ if ( mUploadJob ) {
+ kdWarning() << "KCalResource::save(): upload still in progress."
+ << endl;
+ return false;
+ }
+
+ mCalendar.save( cacheFile() );
+
+ mUploadJob = KIO::file_copy( KURL( cacheFile() ), mUploadUrl, -1, true );
+ connect( mUploadJob, SIGNAL( result( KIO::Job * ) ),
+ SLOT( slotSaveJobResult( KIO::Job * ) ) );
+
+ return true;
+}
+
+bool KCalResource::isSaving()
+{
+ return mUploadJob;
+}
+
+void KCalResource::slotSaveJobResult( KIO::Job *job )
+{
+ if ( job->error() ) {
+ job->showErrorDialog( 0 );
+ } else {
+ kdDebug() << "KCalResource::slotSaveJobResult() success" << endl;
+ }
+
+ mUploadJob = 0;
+
+ emit resourceSaved( this );
+}
+
+void KCalResource::doClose()
+{
+ if ( !mOpen ) return;
+
+ mCalendar.close();
+ mOpen = false;
+}
+
+KABC::Lock *KCalResource::lock()
+{
+ return mLock;
+}
+
+void KCalResource::dump() const
+{
+ ResourceCalendar::dump();
+ kdDebug(5800) << " DownloadUrl: " << mDownloadUrl.url() << endl;
+ kdDebug(5800) << " UploadUrl: " << mUploadUrl.url() << endl;
+ kdDebug(5800) << " ReloadPolicy: " << mReloadPolicy << endl;
+}
+
+#include "kcalresource.moc"
diff --git a/kbugbuster/kresources/kcalresource.h b/kbugbuster/kresources/kcalresource.h
new file mode 100644
index 00000000..9970f5e4
--- /dev/null
+++ b/kbugbuster/kresources/kcalresource.h
@@ -0,0 +1,123 @@
+/*
+ This file is part of KBugBuster.
+
+ Copyright (c) 2003 Cornelius Schumacher <schumacher@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 KCALRESOURCE_H
+#define KCALRESOURCE_H
+
+#include <qptrlist.h>
+#include <qstring.h>
+#include <qdatetime.h>
+
+#include <kurl.h>
+#include <kconfig.h>
+#include <kdirwatch.h>
+
+#include <libkcal/incidence.h>
+#include <libkcal/calendarlocal.h>
+#include <libkcal/icalformat.h>
+#include <libkcal/resourcecached.h>
+
+#include <bugsystem.h>
+
+namespace KIO {
+class FileCopyJob;
+class Job;
+}
+
+namespace KBB {
+class ResourcePrefs;
+}
+
+/**
+ This class provides a calendar stored as a remote file.
+*/
+class KCalResource : public KCal::ResourceCached
+{
+ Q_OBJECT
+
+ friend class KCalResourceConfig;
+
+ public:
+ /**
+ Reload policy.
+
+ @see setReloadPolicy(), reloadPolicy()
+ */
+ enum { ReloadNever, ReloadOnStartup, ReloadOnceADay, ReloadAlways };
+
+ /**
+ Create resource from configuration information stored in KConfig object.
+ */
+ KCalResource( const KConfig * );
+ ~KCalResource();
+
+ void readConfig( const KConfig *config );
+ void writeConfig( KConfig *config );
+
+ KBB::ResourcePrefs *prefs();
+
+ /**
+ Return name of file used as cache for remote file.
+ */
+ QString cacheFile();
+
+ KABC::Lock *lock();
+
+ bool isSaving();
+
+ void dump() const;
+
+ protected slots:
+ void slotBugListAvailable( const Package &, const QString &,
+ const Bug::List &bugs );
+
+ void slotLoadJobResult( KIO::Job * );
+ void slotSaveJobResult( KIO::Job * );
+
+ protected:
+ bool doOpen();
+ void doClose();
+ bool doLoad();
+ bool doSave();
+
+ private:
+ void init();
+
+ KBB::ResourcePrefs *mPrefs;
+
+ KURL mDownloadUrl;
+ KURL mUploadUrl;
+
+ int mReloadPolicy;
+
+ KCal::ICalFormat mFormat;
+
+ bool mOpen;
+
+ KIO::FileCopyJob *mDownloadJob;
+ KIO::FileCopyJob *mUploadJob;
+
+ KABC::Lock *mLock;
+
+ class Private;
+ Private *d;
+};
+
+#endif
diff --git a/kbugbuster/kresources/kcalresource_plugin.cpp b/kbugbuster/kresources/kcalresource_plugin.cpp
new file mode 100644
index 00000000..23b5f8ac
--- /dev/null
+++ b/kbugbuster/kresources/kcalresource_plugin.cpp
@@ -0,0 +1,37 @@
+/*
+ This file is part of KBugBuster.
+
+ Copyright (c) 2003 Cornelius Schumacher <schumacher@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.
+*/
+
+#include "kcalresourceconfig.h"
+#include "kcalresource.h"
+
+#include <kglobal.h>
+#include <klocale.h>
+
+using namespace KCal;
+
+extern "C"
+{
+ KDE_EXPORT void *init_kcal_bugzilla()
+ {
+ KGlobal::locale()->insertCatalogue( "kres_bugzilla" );
+ return new KRES::PluginFactory<KCalResource,KCalResourceConfig>();
+ }
+}
diff --git a/kbugbuster/kresources/kcalresourceconfig.cpp b/kbugbuster/kresources/kcalresourceconfig.cpp
new file mode 100644
index 00000000..bb404445
--- /dev/null
+++ b/kbugbuster/kresources/kcalresourceconfig.cpp
@@ -0,0 +1,92 @@
+/*
+ This file is part of KBugBuster.
+
+ Copyright (c) 2003 Cornelius Schumacher <schumacher@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.
+*/
+
+#include <typeinfo>
+
+#include <qlabel.h>
+#include <qlayout.h>
+
+#include <klineedit.h>
+#include <klocale.h>
+#include <kdebug.h>
+#include <kstandarddirs.h>
+#include <kdialog.h>
+
+#include "kcalresource.h"
+#include "resourceprefs.h"
+#include "kcalresourceconfig.h"
+
+KCalResourceConfig::KCalResourceConfig( QWidget* parent, const char* name )
+ : KRES::ConfigWidget( parent, name )
+{
+ resize( 245, 115 );
+
+ QGridLayout *mainLayout = new QGridLayout( this, 2, 2 );
+ mainLayout->setSpacing( KDialog::spacingHint() );
+
+ QLabel *label = new QLabel( i18n("Server:"), this );
+ mainLayout->addWidget( label, 0, 0 );
+
+ mServerEdit = new KLineEdit( this );
+ mainLayout->addWidget( mServerEdit, 0, 1 );
+
+
+ label = new QLabel( i18n("Product:"), this );
+ mainLayout->addWidget( label, 1, 0 );
+
+ mProductEdit = new KLineEdit( this );
+ mainLayout->addWidget( mProductEdit, 1, 1 );
+
+
+ label = new QLabel( i18n("Component:"), this );
+ mainLayout->addWidget( label, 2, 0 );
+
+ mComponentEdit = new KLineEdit( this );
+ mainLayout->addWidget( mComponentEdit, 2, 1 );
+}
+
+void KCalResourceConfig::loadSettings( KRES::Resource *resource )
+{
+ KCalResource *res = static_cast<KCalResource *>( resource );
+ if ( res ) {
+ KBB::ResourcePrefs *p = res->prefs();
+ mServerEdit->setText( p->server() );
+ mProductEdit->setText( p->product() );
+ mComponentEdit->setText( p->component() );
+ } else {
+ kdError(5700) << "KCalResourceConfig::loadSettings(): no KCalResource, cast failed" << endl;
+ }
+}
+
+void KCalResourceConfig::saveSettings( KRES::Resource *resource )
+{
+ KCalResource *res = static_cast<KCalResource*>( resource );
+ if ( res ) {
+ KBB::ResourcePrefs *p = res->prefs();
+ p->setServer( mServerEdit->text() );
+ p->setProduct( mProductEdit->text() );
+ p->setComponent( mComponentEdit->text() );
+ } else {
+ kdError(5700) << "KCalResourceConfig::saveSettings(): no KCalResource, cast failed" << endl;
+ }
+}
+
+#include "kcalresourceconfig.moc"
diff --git a/kbugbuster/kresources/kcalresourceconfig.h b/kbugbuster/kresources/kcalresourceconfig.h
new file mode 100644
index 00000000..43ab60a1
--- /dev/null
+++ b/kbugbuster/kresources/kcalresourceconfig.h
@@ -0,0 +1,53 @@
+/*
+ This file is part of KBugBuster.
+
+ Copyright (c) 2003 Cornelius Schumacher <schumacher@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 KCALRESOURCECONFIG_H
+#define KCALRESOURCECONFIG_H
+
+#include <kresources/resource.h>
+#include <kresources/configwidget.h>
+
+class KLineEdit;
+
+/**
+ Configuration widget for remote resource.
+
+ @see KCalResource
+*/
+class KCalResourceConfig : public KRES::ConfigWidget
+{
+ Q_OBJECT
+ public:
+ KCalResourceConfig( QWidget *parent = 0, const char *name = 0 );
+
+ public slots:
+ virtual void loadSettings( KRES::Resource *resource );
+ virtual void saveSettings( KRES::Resource *resource );
+
+ private:
+ KLineEdit *mServerEdit;
+ KLineEdit *mComponentEdit;
+ KLineEdit *mProductEdit;
+
+ class Private;
+ Private *d;
+};
+
+#endif
diff --git a/kbugbuster/kresources/kresources_kcal_bugzilla.kcfg b/kbugbuster/kresources/kresources_kcal_bugzilla.kcfg
new file mode 100644
index 00000000..ce23c969
--- /dev/null
+++ b/kbugbuster/kresources/kresources_kcal_bugzilla.kcfg
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<kcfg xmlns="http://www.kde.org/standards/kcfg/1.0"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://www.kde.org/standards/kcfg/1.0
+ http://www.kde.org/standards/kcfg/1.0/kcfg.xsd" >
+ <kcfgfile name="kresources_kcal_bugzillarc"/>
+
+ <group name="General">
+ <entry type="String" name="Server">
+ <label>Server</label>
+ </entry>
+ <entry type="String" name="Product">
+ <label>Product</label>
+ </entry>
+ <entry type="String" name="Component">
+ <label>Component</label>
+ </entry>
+ </group>
+
+</kcfg>
diff --git a/kbugbuster/kresources/resourceprefs.kcfgc b/kbugbuster/kresources/resourceprefs.kcfgc
new file mode 100644
index 00000000..0f41bdb1
--- /dev/null
+++ b/kbugbuster/kresources/resourceprefs.kcfgc
@@ -0,0 +1,9 @@
+# Code generation options for kconfig_compiler
+File=kresources_kcal_bugzilla.kcfg
+ClassName=ResourcePrefs
+NameSpace=KBB
+Singleton=false
+Mutators=true
+GlobalEnums=true
+#ItemAccessors=true
+#SetUserTexts=true
diff --git a/kbugbuster/lo16-app-kbugbuster.png b/kbugbuster/lo16-app-kbugbuster.png
new file mode 100644
index 00000000..eb693eb6
--- /dev/null
+++ b/kbugbuster/lo16-app-kbugbuster.png
Binary files differ
diff --git a/kbugbuster/lo32-app-kbugbuster.png b/kbugbuster/lo32-app-kbugbuster.png
new file mode 100644
index 00000000..3ffbba21
--- /dev/null
+++ b/kbugbuster/lo32-app-kbugbuster.png
Binary files differ
diff --git a/kbugbuster/main.cpp b/kbugbuster/main.cpp
new file mode 100644
index 00000000..456d9dc6
--- /dev/null
+++ b/kbugbuster/main.cpp
@@ -0,0 +1,83 @@
+/***************************************************************************
+ main.cpp - description
+ -------------------
+ begin : zo mrt 18 17:12:24 CET 2001
+ copyright : (C) 2001 by Martijn Klingens
+ email : klingens@kde.org
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the 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 <kcmdlineargs.h>
+#include <kaboutdata.h>
+#include <klocale.h>
+#include <dcopclient.h>
+
+#include "gui/kbbmainwindow.h"
+#include "bugsystem.h"
+#include "kbbprefs.h"
+
+static const char description[] =
+ I18N_NOOP("KBugBuster");
+// INSERT A DESCRIPTION FOR YOUR APPLICATION HERE
+
+static const KCmdLineOptions options[] =
+{
+ {"d", 0, 0},
+ {"disconnected", I18N_NOOP("Start in disconnected mode"), 0},
+ {"pkg", 0, 0},
+ {"package <pkg>", I18N_NOOP("Start with the buglist for <package>"), 0},
+ {"bug <br>", I18N_NOOP("Start with bug report <br>"), 0},
+ KCmdLineLastOption
+};
+
+int main(int argc, char *argv[])
+{
+ KAboutData aboutData( "kbugbuster", I18N_NOOP( "KBugBuster" ),
+ VERSION, description, KAboutData::License_GPL,
+ I18N_NOOP("(c) 2001,2002,2003 the KBugBuster authors") );
+ aboutData.addAuthor( "Martijn Klingens", 0, "klingens@kde.org" );
+ aboutData.addAuthor( "Cornelius Schumacher", 0, "schumacher@kde.org" );
+ aboutData.addAuthor( "Simon Hausmann", 0, "hausmann@kde.org" );
+ aboutData.addAuthor( "David Faure", 0, "faure@kde.org" );
+ KCmdLineArgs::init( argc, argv, &aboutData );
+ KCmdLineArgs::addCmdLineOptions( options );
+
+ KApplication app;
+
+ app.dcopClient()->attach();
+
+ KCmdLineArgs *args = KCmdLineArgs::parsedArgs();
+ if (args->isSet("disconnected")) {
+ BugSystem::self()->setDisconnected( true );
+ }
+
+ if ( app.isRestored() )
+ {
+ RESTORE( KBBMainWindow );
+ }
+ else
+ {
+ KBBMainWindow *mainWin = new KBBMainWindow(args->getOption("package"), args->getOption("bug"));
+
+ // Since all background jobs remaing running after closing the
+ // main window we force a quit here
+ QObject::connect( &app, SIGNAL( lastWindowClosed() ),
+ &app, SLOT( quit() ) );
+ mainWin->show();
+ return app.exec();
+ }
+}
+
+/* vim: set et ts=4 sw=4 softtabstop=4: */
diff --git a/kbugbuster/pics/Makefile.am b/kbugbuster/pics/Makefile.am
new file mode 100644
index 00000000..6ce39e37
--- /dev/null
+++ b/kbugbuster/pics/Makefile.am
@@ -0,0 +1,4 @@
+logo_DATA = tools.png logo.png bars.png top-right.png
+logodir = $(kde_datadir)/kbugbuster/pics
+
+EXTRA_DIST = $(logo_DATA)
diff --git a/kbugbuster/pics/bars.png b/kbugbuster/pics/bars.png
new file mode 100644
index 00000000..7d03c72c
--- /dev/null
+++ b/kbugbuster/pics/bars.png
Binary files differ
diff --git a/kbugbuster/pics/logo.png b/kbugbuster/pics/logo.png
new file mode 100644
index 00000000..360d6435
--- /dev/null
+++ b/kbugbuster/pics/logo.png
Binary files differ
diff --git a/kbugbuster/pics/tools.png b/kbugbuster/pics/tools.png
new file mode 100644
index 00000000..7f9584e3
--- /dev/null
+++ b/kbugbuster/pics/tools.png
Binary files differ
diff --git a/kbugbuster/pics/top-right.png b/kbugbuster/pics/top-right.png
new file mode 100644
index 00000000..bad44f08
--- /dev/null
+++ b/kbugbuster/pics/top-right.png
Binary files differ
diff --git a/kcachegrind/AUTHORS b/kcachegrind/AUTHORS
new file mode 100644
index 00000000..ded6005d
--- /dev/null
+++ b/kcachegrind/AUTHORS
@@ -0,0 +1 @@
+Josef Weidendorfer <Josef.Weidendorfer@gmx.de>
diff --git a/kcachegrind/COPYING b/kcachegrind/COPYING
new file mode 100644
index 00000000..5b6e7c66
--- /dev/null
+++ b/kcachegrind/COPYING
@@ -0,0 +1,340 @@
+ GNU GENERAL PUBLIC LICENSE
+ Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+ 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users. This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it. (Some other Free Software Foundation software is covered by
+the GNU Library General Public License instead.) You can apply it to
+your programs, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+ To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have. You must make sure that they, too, receive or can get the
+source code. And you must show them these terms so they know their
+rights.
+
+ We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+ Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software. If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+ Finally, any free program is threatened constantly by software
+patents. We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary. To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ GNU GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License. The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language. (Hereinafter, translation is included without limitation in
+the term "modification".) Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+ 1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+ 2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) You must cause the modified files to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ b) You must cause any work that you distribute or publish, that in
+ whole or in part contains or is derived from the Program or any
+ part thereof, to be licensed as a whole at no charge to all third
+ parties under the terms of this License.
+
+ c) If the modified program normally reads commands interactively
+ when run, you must cause it, when started running for such
+ interactive use in the most ordinary way, to print or display an
+ announcement including an appropriate copyright notice and a
+ notice that there is no warranty (or else, saying that you provide
+ a warranty) and that users may redistribute the program under
+ these conditions, and telling the user how to view a copy of this
+ License. (Exception: if the Program itself is interactive but
+ does not normally print such an announcement, your work based on
+ the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+ a) Accompany it with the complete corresponding machine-readable
+ source code, which must be distributed under the terms of Sections
+ 1 and 2 above on a medium customarily used for software interchange; or,
+
+ b) Accompany it with a written offer, valid for at least three
+ years, to give any third party, for a charge no more than your
+ cost of physically performing source distribution, a complete
+ machine-readable copy of the corresponding source code, to be
+ distributed under the terms of Sections 1 and 2 above on a medium
+ customarily used for software interchange; or,
+
+ c) Accompany it with the information you received as to the offer
+ to distribute corresponding source code. (This alternative is
+ allowed only for noncommercial distribution and only if you
+ received the program in object code or executable form with such
+ an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it. For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable. However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License. Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+ 5. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Program or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+ 6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+ 7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all. For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+ 8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded. In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+ 9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time. Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation. If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+ 10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission. For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this. Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+ NO WARRANTY
+
+ 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+ 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+ END OF TERMS AND CONDITIONS
+
+ How to Apply These Terms to Your New Programs
+
+ If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+ To do so, attach the following notices to the program. It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the program's name and a brief idea of what it does.>
+ Copyright (C) <year> <name of author>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the 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, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+ Gnomovision version 69, Copyright (C) year name of author
+ Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+ This is free software, and you are welcome to redistribute it
+ under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License. Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary. Here is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+ `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+ <signature of Ty Coon>, 1 April 1989
+ Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs. If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library. If this is what you want to do, use the GNU Library General
+Public License instead of this License.
diff --git a/kcachegrind/ChangeLog b/kcachegrind/ChangeLog
new file mode 100644
index 00000000..b19b0fb8
--- /dev/null
+++ b/kcachegrind/ChangeLog
@@ -0,0 +1,89 @@
+2004/06/30
+ * Leak fixes
+ * Crash fixes on reload (make setData() synchroneous)
+ * Some update fixes in the data model (tracedata.cpp)
+ * Fix update problems in Function Profile
+ * Reselect active function on refresh in function profile
+ with grouping on
+
+2004/04/28
+ * toplevel.h/cpp, kcachegrindui.rc
+ - Switching Layouts
+ * multiview.cpp: Removed some qDebug's
+ * Same term fixes
+
+2004/04/26
+ * cachegrindloader.cpp, fixcost.cpp:
+ - Allow Ranges in Subposition Spec, currently not used
+ - Correctly parse "Desc: Trigger:"
+ - Allow Event Spec (Long Name, Formula) with "event:"
+ * listutils.cpp:
+ - make level meters for costs only 1 bar
+ (2 with upper from 0..50%, lower 50%..100% is really confusing)
+ - Besides from Call graph and Tree maps, truncate bars to
+ only use needed size (removes lots of empty rectangles)
+ * CallGraphView:
+ - some fixes when no data is loaded
+ * functionselection.cpp (Function Profile)
+ - activation on mouse release to allow for context menu
+ * tracedata.cpp
+ - more robust parsing of events lists
+ - Introduction of Ranges (not currently used)
+ * utils.cpp:
+ - more robust parsing functions
+
+2004/04/05
+ * CallGraphView:
+ - Add Context menu item "Export as Image"
+ - Hide Birdseye-View if call-graph fits into widget
+ - Error messages in Canvas when something goes wrong
+ * Some Fixes, qDebug->kdDebug
+
+2004/04/02
+ * In most views columns for 2nd Event Type added
+ * Context menus modified to allow quick change of 2nd Event Type
+ * Toolbar simplified (only most used actions)
+ * Terminology fixes ("cost type"->"event type",
+ "trace data"->"profile data", long names of Ir,Dr,...)
+ * Sorting costs in lists is always descending now
+ * New File menu item: "Add..." other profile data to current window
+ * Detect Cachegrind format by "events:" content, not file name
+ Allows for arbitrary names of profile data files.
+
+2004/03/25
+ * New Class Addr as wrapper for memory addresses. Use 64bit
+ to allow loading of data produced on 64bit architectures
+
+2004/03/17
+
+ * costtypeview.cpp, tracedata.h/cpp:
+ Fixed deletion of custom types
+ * cachegrindloader.cpp, tracedata.h/cpp:
+ Moved String compression handling in Cachegrind files
+ to CachegrindLoader
+ * Do not show inclusive cost column in FunctionSelection
+ side bar if not available
+ * Remove "isPartOfTrace" from Loader interface
+ (we allow parts from multiple experiments for comp.)
+ * partview.cpp, partlistitem.h/cpp:
+ Remove Column Callees, add Trigger
+
+2003/05/10
+
+ * Status progress on loading and cycle calculation
+ * Corrected order of trace parts (PID/PartNo/ThreadID)
+ * Allow adding traces (BUGGY...)
+
+2003/02/06
+
+ * Version 0.3a
+ * Bugfixes:
+ - Compiles with KDE 3.0.x
+ - Always select a first cost type
+ - Loading from another directory
+
+
+2002/11/28
+
+ * Version 0.3
+
diff --git a/kcachegrind/INSTALL b/kcachegrind/INSTALL
new file mode 100644
index 00000000..02a4a074
--- /dev/null
+++ b/kcachegrind/INSTALL
@@ -0,0 +1,167 @@
+Basic Installation
+==================
+
+ These are generic installation instructions.
+
+ The `configure' shell script attempts to guess correct values for
+various system-dependent variables used during compilation. It uses
+those values to create a `Makefile' in each directory of the package.
+It may also create one or more `.h' files containing system-dependent
+definitions. Finally, it creates a shell script `config.status' that
+you can run in the future to recreate the current configuration, a file
+`config.cache' that saves the results of its tests to speed up
+reconfiguring, and a file `config.log' containing compiler output
+(useful mainly for debugging `configure').
+
+ If you need to do unusual things to compile the package, please try
+to figure out how `configure' could check whether to do them, and mail
+diffs or instructions to the address given in the `README' so they can
+be considered for the next release. If at some point `config.cache'
+contains results you don't want to keep, you may remove or edit it.
+
+ The file `configure.in' is used to create `configure' by a program
+called `autoconf'. You only need `configure.in' if you want to change
+it or regenerate `configure' using a newer version of `autoconf'.
+
+The simplest way to compile this package is:
+
+ 1. `cd' to the directory containing the package's source code and type
+ `./configure' to configure the package for your system. If you're
+ using `csh' on an old version of System V, you might need to type
+ `sh ./configure' instead to prevent `csh' from trying to execute
+ `configure' itself.
+
+ Running `configure' takes a while. While running, it prints some
+ messages telling which features it is checking for.
+
+ 2. Type `make' to compile the package.
+
+ 3. Type `make install' to install the programs and any data files and
+ documentation.
+
+ 4. You can remove the program binaries and object files from the
+ source code directory by typing `make clean'.
+
+Compilers and Options
+=====================
+
+ Some systems require unusual options for compilation or linking that
+the `configure' script does not know about. You can give `configure'
+initial values for variables by setting them in the environment. Using
+a Bourne-compatible shell, you can do that on the command line like
+this:
+ CC=c89 CFLAGS=-O2 LIBS=-lposix ./configure
+
+Or on systems that have the `env' program, you can do it like this:
+ env CPPFLAGS=-I/usr/local/include LDFLAGS=-s ./configure
+
+Compiling For Multiple Architectures
+====================================
+
+ You can compile the package for more than one kind of computer at the
+same time, by placing the object files for each architecture in their
+own directory. To do this, you must use a version of `make' that
+supports the `VPATH' variable, such as GNU `make'. `cd' to the
+directory where you want the object files and executables to go and run
+the `configure' script. `configure' automatically checks for the
+source code in the directory that `configure' is in and in `..'.
+
+ If you have to use a `make' that does not supports the `VPATH'
+variable, you have to compile the package for one architecture at a time
+in the source code directory. After you have installed the package for
+one architecture, use `make distclean' before reconfiguring for another
+architecture.
+
+Installation Names
+==================
+
+ By default, `make install' will install the package's files in
+`/usr/local/bin', `/usr/local/man', etc. You can specify an
+installation prefix other than `/usr/local' by giving `configure' the
+option `--prefix=PATH'.
+
+ You can specify separate installation prefixes for
+architecture-specific files and architecture-independent files. If you
+give `configure' the option `--exec-prefix=PATH', the package will use
+PATH as the prefix for installing programs and libraries.
+Documentation and other data files will still use the regular prefix.
+
+ If the package supports it, you can cause programs to be installed
+with an extra prefix or suffix on their names by giving `configure' the
+option `--program-prefix=PREFIX' or `--program-suffix=SUFFIX'.
+
+Optional Features
+=================
+
+ Some packages pay attention to `--enable-FEATURE' options to
+`configure', where FEATURE indicates an optional part of the package.
+They may also pay attention to `--with-PACKAGE' options, where PACKAGE
+is something like `gnu-as' or `x' (for the X Window System). The
+`README' should mention any `--enable-' and `--with-' options that the
+package recognizes.
+
+ For packages that use the X Window System, `configure' can usually
+find the X include and library files automatically, but if it doesn't,
+you can use the `configure' options `--x-includes=DIR' and
+`--x-libraries=DIR' to specify their locations.
+
+Specifying the System Type
+==========================
+
+ There may be some features `configure' can not figure out
+automatically, but needs to determine by the type of host the package
+will run on. Usually `configure' can figure that out, but if it prints
+a message saying it can not guess the host type, give it the
+`--host=TYPE' option. TYPE can either be a short name for the system
+type, such as `sun4', or a canonical name with three fields:
+ CPU-COMPANY-SYSTEM
+
+See the file `config.sub' for the possible values of each field. If
+`config.sub' isn't included in this package, then this package doesn't
+need to know the host type.
+
+ If you are building compiler tools for cross-compiling, you can also
+use the `--target=TYPE' option to select the type of system they will
+produce code for and the `--build=TYPE' option to select the type of
+system on which you are compiling the package.
+
+Sharing Defaults
+================
+
+ If you want to set default values for `configure' scripts to share,
+you can create a site shell script called `config.site' that gives
+default values for variables like `CC', `cache_file', and `prefix'.
+`configure' looks for `PREFIX/share/config.site' if it exists, then
+`PREFIX/etc/config.site' if it exists. Or, you can set the
+`CONFIG_SITE' environment variable to the location of the site script.
+A warning: not all `configure' scripts look for a site script.
+
+Operation Controls
+==================
+
+ `configure' recognizes the following options to control how it
+operates.
+
+`--cache-file=FILE'
+ Use and save the results of the tests in FILE instead of
+ `./config.cache'. Set FILE to `/dev/null' to disable caching, for
+ debugging `configure'.
+
+`--help'
+ Print a summary of the options to `configure', and exit.
+
+`--quiet'
+`--silent'
+`-q'
+ Do not print messages saying which checks are being made.
+
+`--srcdir=DIR'
+ Look for the package's source code in directory DIR. Usually
+ `configure' can determine that directory automatically.
+
+`--version'
+ Print the version of Autoconf used to generate the `configure'
+ script, and exit.
+
+`configure' also accepts some other, not widely useful, options.
+
diff --git a/kcachegrind/Makefile.am b/kcachegrind/Makefile.am
new file mode 100644
index 00000000..595471f5
--- /dev/null
+++ b/kcachegrind/Makefile.am
@@ -0,0 +1,6 @@
+SUBDIRS = kcachegrind pics converters
+
+EXTRA_DIST = \
+ AUTHORS COPYING NEWS ChangeLog INSTALL README TODO \
+ kcachegrind.lsm kcachegrind.spec version.h
+
diff --git a/kcachegrind/NEWS b/kcachegrind/NEWS
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/kcachegrind/NEWS
diff --git a/kcachegrind/README b/kcachegrind/README
new file mode 100644
index 00000000..30fee51e
--- /dev/null
+++ b/kcachegrind/README
@@ -0,0 +1,62 @@
+KCachegrind
+===========
+
+
+What is all this about ?
+-------------------------
+
+Profiling, i.e. determinating most time consuming execution parts,
+is an important last step when developing applications.
+KCachegrind visualizes traces, generated by profiling, in various ways;
+most notable is the TreeMap visualization of the calls happening
+and a condensed version of it, the Coverage analysis.
+KCachegrind is designed to allow fast browsing and to provide a quick
+overview of very large programs, such as KDE applications (but not
+limited to!).
+
+At the moment, it uses Cachegrind as profiling backend, which is using
+the excellent CPU simulator in Valgrind. Thus, profiling does not
+need any preparation, can cope with shared libraries and plugin
+architectures, and allows for profile runs to not influence the measuring
+by the profile itself (all in contrast to e.g. GProf). Disadvantage is
+slower profile runs, unfortunately.
+
+For Cachegrind to provide call tree information, a patch is provided.
+This enables the most interesting visualization features of KCachegrind.
+
+
+Requirements
+------------
+
+A call-tree version of Cachegrind:
+ - X86 Linux
+ - Valgrind 1.0.x with call-tree patch from KCachegrind Website
+ - Valgrind 2.0.x with call-tree skin installed
+
+Cachegrind runs on x86 platforms, KCachegrind on all KDE enabled
+platforms (KDE 3.0.x).
+
+
+Compilation and Installation
+----------------------------
+
+Simple do the command sequence
+
+ ./configure --prefix=<KDE base directory>
+ make
+ make install
+
+
+
+KCachegrind features
+--------------------
+
+Most important: TreeMap calltree visualisation.
+For the rest, see the detailed "What's this?" help for
+each part of KCachegrind and the quick starter on the
+WWW page ( http://kcachegrind.sourceforge.net/cgi-bin/show.cgi )
+
+
+
+Happy Profiling,
+ Josef Weidendorfer
diff --git a/kcachegrind/TODO b/kcachegrind/TODO
new file mode 100644
index 00000000..1eca67ed
--- /dev/null
+++ b/kcachegrind/TODO
@@ -0,0 +1,100 @@
+TODO/Wishlist Items
+===================
+
+
+KCachegrind
+-----------
+
+All cost Lists:
+* Show up to a number of items, not down to a threadshold.
+ If more, add a "..." with number of items not shown, and context option
+ to show more
+* "Copy from Top" converts lists into ASCII, puts into clipboard
+
+
+Configuration:
+ Source dirs per ELF object
+
+Layout:
+* 1/2/3/4 vertical/horizontal FunctionInfos
+ with Shift/Wraparound selection mode
+* Inside each FunctionInfo different Layouts
+ - tabbed layout
+ - top: info, bottom left: calls/coverage, bottom right: graph/source
+* Long/short info tab
+
+General:
+* Selected Item can be a object/file/class/function/line
+* Configuration Dlg
+ - Local config (?)
+ - Cost Types
+ - function colors
+ - Try to reload source after config.
+* Session Management
+
+
+
+Annotation Views:
+
+ BUGS:
+ * Draw problem with multiple srcs to one target
+ * REP case...
+
+ TODO:
+ * Selectable Jumps (Arrows)
+ * Tooltip for Jumps (Kind, from/to, jump count)
+ * Show direction (arrows) on jump lines
+
+ Source view TODO:
+ * Implicit jumps (green) [needs support from the tool?]
+
+
+
+Callgraph:
+* Fix Arrows for back-arcs
+* Less "Jumps" for minimap
+* Correct Keyboard navigation (how?)
+
+Types:
+* Ratios
+* Automatic subtypes
+
+WISHS:
+* Support for Data tracing
+ Which variables are touched how often from which function?
+ - Some graphical visualisation...
+
+* GCC -pg (gmon.out) as Profiling Backend
+* Demangler (use c++filt)
+* Calculation of call weights (if not given)
+* OProfile, DynaProf
+
+Support for KCachegrind in Calltree
+-----------------------------------
+
+WISHS:
+- store more details of calltree
+ - for every function call: executed from shared lib
+ (Not needed, if function names are unique in whole app)
+ - adaptive call chain context (Really needed ? MUCH Data!)
+- dump at
+ - breakpoints
+ - watchpoints (with data tracing!)
+ - every xxx BBs (DONE)
+- dump around
+ - function invocation
+ - KAction event
+ - DCOP event
+
+- data accesses from (instr address/count)
+ stack: -> (function, stackframe-offset)
+ dynamic: -> (mem region start, [type], offset)
+ type can be get when a constructor is called for region
+ static: -> (mem region start, type, offset)
+
+* Generate full instr/data access trace for offline analysis.
+
+* Appending mode
+
+
+
diff --git a/kcachegrind/configure.in.in b/kcachegrind/configure.in.in
new file mode 100644
index 00000000..22701fc8
--- /dev/null
+++ b/kcachegrind/configure.in.in
@@ -0,0 +1,8 @@
+KCACHEGRIND_VERSION=0.4.6kde
+AC_SUBST(KCACHEGRIND_VERSION)
+
+AC_FUNC_MMAP
+
+dnl AC_OUTPUT( kcachegrind/version.h )
+dnl AC_OUTPUT( kcachegrind/kcachegrind.spec )
+dnl AC_OUTPUT( kcachegrind/kcachegrind.lsm )
diff --git a/kcachegrind/converters/Makefile.am b/kcachegrind/converters/Makefile.am
new file mode 100644
index 00000000..08b3696b
--- /dev/null
+++ b/kcachegrind/converters/Makefile.am
@@ -0,0 +1,2 @@
+bin_SCRIPTS = hotshot2calltree op2calltree pprof2calltree dprof2calltree \
+ memprof2calltree
diff --git a/kcachegrind/converters/README b/kcachegrind/converters/README
new file mode 100644
index 00000000..6a1c46c5
--- /dev/null
+++ b/kcachegrind/converters/README
@@ -0,0 +1,24 @@
+This directory contains some scripts to convert output of different
+profiling tools into the format which can be loaded by KCachegrind.
+See the comment at start of every script for details.
+
+In the long run, these should be replaced by import filters in
+KCachegrind directly, but I can't promise anything. Partly, this
+is because some scripts are provided as contribution from others.
+
+hotshot2calltree Converter from Python Hotshot Profiler.
+op2calltree Converter from OProfile sampling data.
+dprof2calltree Converter from PERL::DProf Profiler.
+pprof2calltree Converter from APD PHP Profiler.
+
+Thanks go to
+* George Schlossnagle <george@omniti.com> for
+ dprof2calltree and pprof2calltree,
+* Jörg Beyer <job@webde-ag.de> for
+ hotshot2calltree
+
+If you want to write a converter, have a look at the calltree format
+description on the web site (kcachegrind.sf.net).
+
+Josef
+
diff --git a/kcachegrind/converters/dprof2calltree b/kcachegrind/converters/dprof2calltree
new file mode 100644
index 00000000..940457c8
--- /dev/null
+++ b/kcachegrind/converters/dprof2calltree
@@ -0,0 +1,199 @@
+#!/usr/bin/perl
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are met:
+#
+# - Redistributions of source code must retain the above copyright notice,
+# this list of conditions and the following disclaimer.
+#
+# - Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+#
+# - All advertising materials mentioning features or use of this software
+# must display the following acknowledgement: This product includes software
+# developed by OmniTI Computer Consulting.
+#
+# - Neither name of the company nor the names of its contributors may be
+# used to endorse or promote products derived from this software without
+# specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS `AS IS'' AND ANY
+# EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+# DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
+# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+# Copyright (c) 2004 OmniTI Computer Consulting
+# All rights reserved
+# The following code was written by George Schlossnagle <george@omniti.com>
+# and is provided completely free and without any warranty.
+#
+
+#
+# This script is designed to convert the tmon.out output emitted
+# from Perl's Devel::DProf profiling package. To use this:
+#
+# 1) Run your perl script as
+# > perl -d:DProf yoursript.pl
+# This will create a file called tmon.out. If you want to
+# inspect it on the command line, look at the man page
+# for dprofp for details.
+#
+# 2) Run
+# > dprof2calltree -f tmon.out
+# or
+# > dprof2calltree -f tmon.out -o cachegrind.out.foo
+#
+# This creates a cachegrind-style file called cachgrind.out.tmon.out or
+# cachegrind.out.foo, respecitvely.
+#
+# 3) Run kcachegrind cachegrind.out.foo
+#
+# 4) Enjoy!
+
+use strict;
+use Config;
+use Getopt::Std;
+use IO::File;
+
+my @callstack;
+my %function_info;
+my $tree = {};
+my $total_cost = 0;
+my %opts;
+
+getopt('f:o:', \%opts);
+
+my $infd;
+usage() unless ($opts{'f'} && ($infd = IO::File->new($opts{'f'}, "r")));
+
+my $outfd;
+my $outfile = $opts{'o'};
+unless($outfile) {
+ $opts{'f'} =~ m!([^/]+)$!;
+ $outfile = "cachegrind.out.$1";
+}
+$outfd = new IO::File $outfile, "w";
+usage() unless defined $outfd;
+
+while(<$infd>) {
+ last if /^PART2/;
+}
+while(<$infd>) {
+ chomp;
+ my @args = split;
+ if($args[0] eq '@') {
+ # record timing event
+ my $call_element = pop @callstack;
+ if($call_element) {
+ $call_element->{'cost'} += $args[3];
+ $call_element->{'cumm_cost'} += $args[3];
+ $total_cost += $args[3];
+ push @callstack, $call_element;
+ }
+ }
+ elsif($args[0] eq '&') {
+ # declare function
+ $function_info{$args[1]}->{'package'} = $args[2];
+ if($args[2] ne 'main') {
+ $function_info{$args[1]}->{'name'} = $args[2]."::".$args[3];
+ } else {
+ $function_info{$args[1]}->{'name'} = $args[3];
+ }
+ }
+ elsif($args[0] eq '+') {
+ # push myself onto the stack
+ my $call_element = { 'specifier' => $args[1], 'cost' => 0 };
+ push @callstack, $call_element;
+ }
+ elsif($args[0] eq '-') {
+ my $called = pop @callstack;
+ my $called_id = $called->{'specifier'};
+ my $caller = pop @callstack;
+ if (exists $tree->{$called_id}) {
+ $tree->{$called_id}->{'cost'} += $called->{'cost'};
+ }
+ else {
+ $tree->{$called_id} = $called;
+ }
+ if($caller) {
+ $caller->{'child_calls'}++;
+ my $caller_id = $caller->{'specifier'};
+ if(! exists $tree->{$caller_id} ) {
+ $tree->{$caller_id} = { 'specifier' => $caller_id, 'cost' => 0 };
+# $tree->{$caller_id} = $caller;
+ }
+ $caller->{'cumm_cost'} += $called->{'cumm_cost'};
+ $tree->{$caller_id}->{'called_funcs'}->[$tree->{$caller_id}->{'call_counter'}++]->{$called_id} += $called->{'cumm_cost'};
+ push @callstack, $caller;
+ }
+ }
+ elsif($args[0] eq '*') {
+ # goto &func
+ # replace last caller with self
+ my $call_element = pop @callstack;
+ $call_element->{'specifier'} = $args[1];
+ push @callstack, $call_element;
+ }
+ else {print STDERR "Unexpected line: $_\n";}
+}
+
+#
+# Generate output
+#
+my $output = '';
+$output .= "events: Tick\n";
+$output .= "summary: $total_cost\n";
+$output .= "cmd: your script\n\n";
+foreach my $specifier ( keys %$tree ) {
+ my $caller_package = $function_info{$specifier}->{'package'} || '???';
+ my $caller_name = $function_info{$specifier}->{'name'} || '???';
+ my $include = find_include($caller_package);
+ $output .= "ob=\n";
+ $output .= sprintf "fl=%s\n", find_include($caller_package);
+ $output .= sprintf "fn=%s\n", $caller_name;
+ $output .= sprintf "1 %d\n", $tree->{$specifier}->{'cost'};
+ if(exists $tree->{$specifier}->{'called_funcs'}) {
+ foreach my $items (@{$tree->{$specifier}->{'called_funcs'}}) {
+ while(my ($child_specifier, $costs) = each %$items) {
+ $output .= sprintf "cfn=%s\n", $function_info{$child_specifier}->{'name'};
+ $output .= sprintf "cfi=%s\n", find_include($function_info{$child_specifier}->{'package'});
+ $output .= "calls=1\n";
+ $output .= sprintf "1 %d\n", $costs;
+ }
+ }
+ }
+ $output .= "\n";
+}
+print STDERR "Writing kcachegrind output to $outfile\n";
+$outfd->print($output);
+
+
+
+sub find_include {
+ my $module = shift;
+ $module =~ s!::!/!g;
+ for (@INC) {
+ if ( -f "$_/$module.pm" ) {
+ return "$_/$module.pm";
+ }
+ if ( -f "$_/$module.so" ) {
+ return "$_/$module.so";
+ }
+ }
+ return "???";
+}
+
+sub usage() {
+ print STDERR "dprof2calltree -f <tmon.out> [-o outfile]\n";
+ exit -1;
+}
+
+
+# vim: set sts=2 ts=2 bs ai expandtab :
diff --git a/kcachegrind/converters/hotshot2calltree b/kcachegrind/converters/hotshot2calltree
new file mode 100644
index 00000000..176f82f3
--- /dev/null
+++ b/kcachegrind/converters/hotshot2calltree
@@ -0,0 +1,394 @@
+#!/usr/bin/env python
+# _*_ coding: latin1 _*_
+
+#
+# Copyright (c) 2003 by WEB.DE, Karlsruhe
+# Autor: Jörg Beyer <job@webde-ag.de>
+#
+# hotshot2cachegrind is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public
+# License as published by the Free Software Foundation, version 2.
+#
+# 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; see the file COPYING. If not, write to
+# the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+# Boston, MA 02111-1307, USA.
+#
+#
+# This script transforms the pstat output of the hotshot
+# python profiler into the input of kcachegrind.
+#
+# example usage:
+# modify you python script to run this code:
+#
+# import hotshot
+# filename = "pythongrind.prof"
+# prof = hotshot.Profile(filename, lineevents=1)
+# prof.runcall(run) # assuming that "run" should be called.
+# prof.close()
+#
+# it will run the "run"-method under profiling and write
+# the results in a file, called "pythongrind.prof".
+#
+# then call this script:
+# hotshot2cachegrind -o <output> <input>
+# or here:
+# hotshot2cachegrind cachegrind.out.0 pythongrind.prof
+#
+# then call kcachegrind:
+# kcachegrind cachegrind.out.0
+#
+# TODO:
+# * es gibt Probleme mit rekursiven (direkt und indirekt) Aufrufen - dann
+# stimmen die Kosten nicht.
+#
+# * einige Funktionen werden mit "?" als Name angezeigt. Evtl sind
+# das nur die C/C++ extensions.
+#
+# * es fehlt noch ein Funktionsnamen Mangling, dass die Filenamen berücksichtigt,
+# zZ sind alle __init__'s und alle run's schwer unterscheidbar :-(
+#
+version = "$Revision$"
+progname = "hotshot2cachegrind"
+
+import os, sys
+from hotshot import stats,log
+import os.path
+
+file_limit=0
+
+what2text = {
+ log.WHAT_ADD_INFO : "ADD_INFO",
+ log.WHAT_DEFINE_FUNC : "DEFINE_FUNC",
+ log.WHAT_DEFINE_FILE : "DEFINE_FILE",
+ log.WHAT_LINENO : "LINENO",
+ log.WHAT_EXIT : "EXIT",
+ log.WHAT_ENTER : "ENTER"}
+
+# a pseudo caller on the caller stack. This represents
+# the Python interpreter that executes the given python
+# code.
+root_caller = ("PythonInterpreter",0,"execute")
+
+class CallStack:
+ """A tiny Stack implementation, based on python lists"""
+ def __init__(self):
+ self.stack = []
+ self.recursion_counter = {}
+ def push(self, elem):
+ """put something on the stack"""
+ self.stack.append(elem)
+ rc = self.recursion_counter.get(elem, 0)
+ self.recursion_counter[elem] = rc + 1
+
+ def pop(self):
+ """get the head element of the stack and remove it from teh stack"""
+ elem = self.stack[-1:][0]
+ rc = self.recursion_counter.get(elem) - 1
+ if rc>0:
+ self.recursion_counter[elem] = rc
+ else:
+ del self.recursion_counter[elem]
+ return self.stack.pop()
+
+ def top(self):
+ """get the head element of the stack, stack is unchanged."""
+ return self.stack[-1:][0]
+ def handleLineCost(self, tdelta):
+ p, c = self.stack.pop()
+ self.stack.append( (p,c + tdelta) )
+ def size(self):
+ """ return how many elements the stack has"""
+ return len(self.stack)
+
+ def __str__(self):
+ return "[stack: %s]" % self.stack
+
+ def recursion(self, pos):
+ return self.recursion_counter.get(pos, 0)
+ #return self.recursion_dict.has_key((entry[0][0], entry[0][2]))
+
+def return_from_call(caller_stack, call_dict, cost_now):
+ """return from a function call
+ remove the function from the caller stack,
+ add the costs to the calling function.
+ """
+ called, cost_at_enter = caller_stack.pop()
+ caller, caller_cost = caller_stack.top()
+
+ #print "return_from_call: %s ruft %s" % (caller, called,)
+
+ per_file_dict = call_dict.get(called[0], {})
+ per_caller_dict = per_file_dict.get(called[2], {})
+ cost_so_far, call_counter = per_caller_dict.get(caller, (0, 0))
+
+ if caller_stack.recursion(called):
+ per_caller_dict[caller] = (cost_so_far, call_counter + 1)
+ else:
+ per_caller_dict[caller] = (cost_so_far + cost_now - cost_at_enter, call_counter + 1)
+
+ per_file_dict[called[2]] = per_caller_dict
+ call_dict[called[0]] = per_file_dict
+
+
+def updateStatus(filecount):
+ sys.stdout.write("reading File #%d \r" % filecount)
+ sys.stdout.flush()
+def convertProfFiles(output, inputfilenames):
+ """convert all the given input files into one kcachegrind
+ input file.
+ """
+ call_dict = {}
+ cost_per_pos = {}
+ cost_per_function = {}
+ caller_stack = CallStack()
+ caller_stack.push((root_caller, 0))
+
+ total_cost = 0
+ filecount = 1
+ number_of_files = len(inputfilenames)
+ for inputfilename in inputfilenames:
+ updateStatus(filecount)
+ cost, filecount = convertHandleFilename(inputfilename, caller_stack, call_dict, cost_per_pos, cost_per_function, filecount)
+ total_cost += cost
+ if (file_limit > 0) and (filecount > file_limit):
+ break
+
+ print
+ print "total_cost: % d Ticks",total_cost
+ dumpResults(output, call_dict, total_cost, cost_per_pos, cost_per_function)
+
+def convertHandleFilename(inputfilename, caller_stack, call_dict, cost_per_pos, cost_per_function, filecount):
+ updateStatus(filecount)
+ if not ((file_limit > 0) and (filecount > file_limit)):
+ if os.path.isdir(inputfilename):
+ cost, filecount = convertProfDir(inputfilename, caller_stack, call_dict, cost_per_pos, cost_per_function, filecount)
+ elif os.path.isfile(inputfilename):
+ cost = convertProfFile(inputfilename, caller_stack, call_dict, cost_per_pos, cost_per_function)
+ filecount += 1
+ else:
+ sys.stderr.write("warn: ignoring '%s', is no file and no directory\n" % inputfilename)
+ cost = 0
+ return (cost, filecount)
+
+def convertProfDir(start, caller_stack, call_dict, cost_per_pos, cost_per_function, filecount):
+ cost = 0
+ filenames = os.listdir(start)
+ for f in filenames:
+ if (file_limit > 0) and (filecount > file_limit):
+ break
+ full = os.path.join(start, f)
+ c, filecount = convertHandleFilename(full, caller_stack, call_dict, cost_per_pos, cost_per_function, filecount)
+ cost += c;
+ return (cost, filecount)
+
+def handleCostPerPos(cost_per_pos, pos, current_cost):
+ """
+ the cost per source position are managed in a dict in a dict.
+
+ the cost are handled per file and there per function.
+ so, the per-file-dict contains some per-function-dicts
+ which sum up the cost per line (in this function and in
+ this file).
+ """
+ filename = pos[0]
+ lineno = pos[1]
+ funcname = pos[2]
+ file_dict = cost_per_pos.get(filename, {})
+ func_dict = file_dict.get(funcname, {})
+ func_dict.setdefault(lineno, 0)
+ func_dict[lineno] += current_cost
+ file_dict[funcname] = func_dict
+ cost_per_pos[filename] = file_dict
+
+def convertProfFile(inputfilename, caller_stack, call_dict, cost_per_pos, cost_per_function):
+ """convert a single input file into one kcachegrind
+ data.
+
+ this is the most expensive function in this python source :-)
+ """
+
+ total_cost = 0
+ try:
+ logreader = log.LogReader(inputfilename)
+ current_cost = 0
+ hc = handleCostPerPos # shortcut
+ for item in logreader:
+ what, pos ,tdelta = item
+ (file, lineno, func) = pos
+ #line = "%s %s %d %s %d" % (what2text[what], file, lineno, func, tdelta)
+ #print line
+ # most common cases first
+ if what == log.WHAT_LINENO:
+ # add the current cost to the current function
+ hc(cost_per_pos, pos, tdelta)
+ total_cost += tdelta
+ elif what == log.WHAT_ENTER:
+ caller_stack.push((pos, total_cost))
+ hc(cost_per_pos, pos, tdelta)
+ total_cost += tdelta
+ elif what == log.WHAT_EXIT:
+ hc(cost_per_pos, pos, tdelta)
+ total_cost += tdelta
+ return_from_call(caller_stack, call_dict, total_cost)
+ else:
+ assert 0, "duh: %d" % what
+
+
+ # I have no idea, why sometimes the stack is not empty - we
+ # have to rewind the stack to get 100% for the root_caller
+ while caller_stack.size() > 1:
+ return_from_call(caller_stack, call_dict, total_cost)
+
+ except IOError:
+ print "could not open inputfile '%s', ignore this." % inputfilename
+ except EOFError, m:
+ print "EOF: %s" % (m,)
+ return total_cost
+
+def pretty_name(file, function):
+ #pfile = os.path.splitext(os.path.basename(file)) [0]
+ #return "%s_[%s]" % (function, file)
+ return "%s" % function
+ #return "%s::%s" % (file, function)
+ #return "%s_%s" % (pfile, function)
+
+class TagWriter:
+ def __init__(self, output):
+ self.output = output
+ self.last_values = {}
+
+ def clearTag(self, tag):
+ if self.last_values.has_key(tag):
+ del self.last_values[ tag ]
+ def clear(self):
+ self.last_values = {}
+
+ def write(self, tag, value):
+ self.output.write("%s=%s\n" % (tag, value))
+ #if (not self.last_values.has_key(tag)) or self.last_values[tag] != value:
+ # self.last_values[ tag ] = value
+ # self.output.write("%s=%s\n" % (tag, value))
+
+def dumpResults(output, call_dict, total_cost, cost_per_pos, cost_per_function):
+ """write the collected results in the format kcachegrind
+ could read.
+ """
+ # the intro
+ output.write("events: Tick\n")
+ output.write("summary: %d\n" % total_cost)
+ output.write("cmd: your python script\n")
+ output.write("\n")
+ tagwriter = TagWriter(output)
+
+ # now the costs per line
+ for file in cost_per_pos.keys():
+ func_dict = cost_per_pos[file]
+ for func in func_dict.keys():
+ line_dict = func_dict[func]
+ tagwriter.write("ob", file)
+ tagwriter.write("fn", func)# pretty_name(file, func)) ; output.write("# ^--- 2\n")
+ tagwriter.write("fl", file)
+ for line in line_dict:
+ output.write("%d %d\n" %( line, line_dict[line] ))
+
+ output.write("\n\n")
+ # now the function calls. For each caller all the called
+ # functions and their costs are written.
+ for file in call_dict.keys():
+ per_file_dict = call_dict[file]
+ #print "file %s -> %s" % (file, per_file_dict)
+ for called_x in per_file_dict.keys():
+ #print "called_x:",called_x
+ per_caller_dict = per_file_dict[called_x]
+ #print "called_x %s wird gerufen von: %s" % (called_x, per_caller_dict)
+ for caller_x in per_caller_dict.keys():
+ tagwriter.write("ob", caller_x[0])
+ tagwriter.write("fn", caller_x[2])# pretty_name(caller_x[2], caller_x[0])) ; output.write("# ^--- 1\n")
+ tagwriter.write("fl", caller_x[0])
+ tagwriter.write("cob", file)
+ tagwriter.write("cfn", called_x) #pretty_name(file, called_x))
+ tagwriter.write("cfl", file)
+ cost, count = per_caller_dict[caller_x]
+ #print "called_x:",called_x
+ output.write("calls=%d\n%d %d\n" % (count, caller_x[1], cost))
+ tagwriter.clear()
+ #tagwriter.clearTag("cob")
+ # is it a bug in kcachegrind, that the "cob=xxx" line has
+ # to be rewritten after a calls entry with costline ?
+ #assert cost <= total_cost, "caller_x: %s, per_caller_dict: %s " % (caller_x, per_caller_dict, )
+ #output.write("calls=%d\n%d %d\n" % (count, caller_x[1], cost))
+ output.write("\n")
+
+def run_without_optparse():
+ """parse the options without optparse, use sys.argv"""
+ if len(sys.argv) < 4 or sys.argv[1] != "-o" :
+ print "usage: hotshot2cachegrind -o outputfile in1 [in2 [in3 [...]]]"
+ return
+ outputfilename = sys.argv[2]
+ try:
+ output = file(outputfilename, "w")
+ args = sys.argv[3:]
+ convertProfFiles(output, args)
+ output.close()
+ except IOError:
+ print "could not open '%s' for writing." % outputfilename
+
+def run_with_optparse():
+ """parse the options with optparse"""
+
+ global file_limit
+
+ versiontext = "%s version: %s" % ( progname, version.split()[1], )
+ parser = OptionParser(version=versiontext)
+ parser.add_option("-o", "--output",
+ action="store", type="string", dest="outputfilename",
+ help="write output into FILE")
+ parser.add_option("--file-limit",
+ action="store", dest="file_limit", default=0,
+ help="stop after given number of input files")
+ output = sys.stdout
+ close_output = 0
+ (options, args) = parser.parse_args()
+ file_limit = int(options.file_limit)
+ try:
+ if options.outputfilename and options.outputfilename != "-":
+ output = file(options.outputfilename, "w")
+ close_output = 1
+ except IOError:
+ print "could not open '%s' for writing." % options.outputfilename
+ if output:
+ convertProfFiles(output, args)
+ if close_output:
+ output.close()
+
+
+def profile_myself():
+ import hotshot
+ filename = "self.prof"
+ if not os.path.exists(filename):
+ prof = hotshot.Profile(filename, lineevents=1)
+ prof.runcall(run)
+ prof.close()
+ else:
+ print "not profiling myself, since '%s' exists, running normal" % filename
+ run()
+
+# check if optparse is available.
+try:
+ from optparse import OptionParser
+ run = run_with_optparse
+except ImportError:
+ run = run_without_optparse
+
+if __name__ == "__main__":
+ try:
+ run()
+ #profile_myself()
+ except KeyboardInterrupt:
+ sys.exit(1)
diff --git a/kcachegrind/converters/memprof2calltree b/kcachegrind/converters/memprof2calltree
new file mode 100755
index 00000000..e82d6e85
--- /dev/null
+++ b/kcachegrind/converters/memprof2calltree
@@ -0,0 +1,38 @@
+#!/usr/bin/perl
+#
+# Convert the memory profiles of memprof to calltree format,
+# loadable with KCachegrind
+#
+# (C) 2004, Josef Weidendorfer
+
+print "events: Allocated\n";
+
+while(<>) {
+ if (/^(\S.*)$/) {
+ $next = 0;
+ print "\nfn=$1\n";
+ next;
+ }
+ if (/^ children:/) {
+ $next = 1; #children
+ next;
+ }
+ if (/^ inherited:/) {
+ $next = 2; #inherited
+ next;
+ }
+ if (/^ total:/) {
+ # ignore, is calculated
+ next;
+ }
+ if (/^ self:\s*(\d+)/) {
+ if ($1 ne "0") {
+ print "0 $1\n";
+ }
+ next;
+ }
+ if (/^\s+(\S.*?):\s*(\d+)$/) {
+ if ($next < 2) { next; }
+ print "cfn=$1\ncalls=0 0\n0 $2\n";
+ }
+}
diff --git a/kcachegrind/converters/op2calltree b/kcachegrind/converters/op2calltree
new file mode 100755
index 00000000..ff755390
--- /dev/null
+++ b/kcachegrind/converters/op2calltree
@@ -0,0 +1,238 @@
+#!/usr/bin/perl
+#
+# Copyright (c) 2004
+# Author: Josef Weidendorfer <Josef.Weidendorfer@gmx.de>
+#
+# op2calltree is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public
+# License as published by the Free Software Foundation, version 2.
+#
+# 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; see the file COPYING. If not, write to
+# the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+# Boston, MA 02111-1307, USA.
+#
+#
+# Converter from OProfile's output of "opreport -gdf" (v 0.8)
+# into callgrind format.
+#
+# Generate a OProfile report with opreport and flags -gdf
+# and pipe this as standard input into this script.
+# This will generate separate cachegrind files for every application.
+#
+
+
+# parse symbol line. example (with 1 event type, $has_image==0):
+# 308 0.1491 /path/source.c:6 /path/app main
+sub parseSymSpec {
+ $e = 0;
+ while($e < $eventCount) {
+ ($line) = ($line =~ /\d+\s+\S+\s+(.*)/);
+ $e++;
+ }
+ if ($line =~ s/^\(no location information\)\s+//) {
+ $file = "???";
+ $linenr = 0;
+ }
+ else {
+ ($file,$linenr) = ($line =~ s/(\S+?):(\d+)\s+//);
+ }
+ if ($has_image) {
+ if ($line =~ s/^(\S+)\s+//) { $img = $1; }
+ }
+ if ($has_app) {
+ if ($line =~ s/^(\S+)\s+//) { $app = $1; }
+ if (!$has_image) { $img = $app; }
+ }
+ $sym = $line;
+
+ $app =~ s/^.*\///;
+ if ($sym eq "(no symbols)") { $sym = "???"; }
+ $file{$sym} = $file;
+ $linenr{$sym} = $linenr;
+ $app{$sym} = $app;
+ $img{$app,$sym} = $img;
+ $syms{$app}++;
+
+ if ($app ne $oldApp) {
+ $oldApp = $app;
+ print "\n\nApp $app\n";
+ }
+ print " Symbol $sym (Image $img)\n";
+}
+
+
+
+$eventCount = 0;
+$descCount = 0;
+$lnr = 0;
+$has_image = 0;
+$has_app = 0;
+$app = "unnamed";
+$img = "???";
+
+# first loop till first symbol specification
+while(<>) {
+ $lnr++;
+ chomp;
+ if (/^CPU:/) {
+ $desc[$descCount++] = $_;
+ next;
+ }
+ if (/^Counted\s*(\S+)/) {
+ $desc[$descCount++] = $_;
+ $eventCount++;
+ $events[$eventCount] = $1;
+ next;
+ }
+ if (/^(Profiling through timer.*)/) {
+ $desc[$descCount++] = $_;
+ $eventCount++;
+ $events[$eventCount] = "Timer";
+ next;
+ }
+ if (/^vma/) {
+ # title row: adapt to separation options of OProfile
+ if (/image/) { $has_image = 1; }
+ if (/app/) { $has_app = 1; }
+ next;
+ }
+ if (/^([0-9a-fA-F]+)\s*(.*)$/) {
+ $vmaSym = $1;
+ $line = $2;
+ last;
+ }
+}
+
+if ($eventCount == 0) {
+ die "No Events found";
+}
+
+print "Description:\n";
+foreach $d (@desc) { print " $d\n"; }
+print "\n";
+
+print "Events:";
+foreach $e (@events) { print " $e"; }
+print "\n";
+
+parseSymSpec;
+
+while(<>) {
+ $lnr++;
+ if (/^([0-9a-fA-F]+)\s*(.*)$/) {
+ $vmaSym = $1;
+ $line = $2;
+
+ parseSymSpec;
+ next;
+ }
+ if (/^\s+([0-9a-fA-F]+)\s*(.*)$/) {
+
+ $sampleCount{$app,$sym}++;
+ $sc = $sampleCount{$app,$sym};
+
+ $vma{$app,$sym,$sc} = $1;
+ $line = $2;
+
+ $e = 1;
+ while($e <= $eventCount) {
+ ($cost, $line) = ($line =~ /(\d+)\s+\S+\s+(.*)/);
+ $summary{$app,$e} += $cost;
+ $cost{"$app,$sym,$sc,$e"} = $cost;
+ $e++;
+ }
+ if ($line =~ /\(no location information\)/) {
+ $file = "???";
+ $linenr = 0;
+ }
+ else {
+ ($file,$linenr) = ($line =~ /(\S+?):(\d+)/);
+ }
+ $sFile{$app,$sym,$sc} = $file;
+ $linenr{$app,$sym,$sc} = $linenr;
+
+ $file =~ s/^.*\///;
+ print " Sample $sc: $vma{$app,$sym,$sc} ($file:$linenr):";
+ foreach $e (1 .. $eventCount) { $c = $cost{"$app,$sym,$sc,$e"} ; print " $c"; }
+ print "\n";
+ next;
+ }
+ die "ERROR: Reading line $lnr '$_'\n";
+}
+
+foreach $app (keys %syms) {
+ if ($app eq "") { next; }
+ print "Generating dump for App '$app'...\n";
+
+ $out = "# Generated by op2cg, using OProfile with opreport -gdf\n";
+ $out .= "positions: instr line\n";
+
+ $out .= "events:";
+ foreach $e (@events) { $out .= " $e"; }
+ $out .= "\n";
+
+ $out .= "summary:";
+ foreach $e (1 .. $eventCount) { $out .= " $summary{$app,$e}"; }
+ $out .= "\n\n";
+
+ %fileNum = ();
+ $fileNum = 1;
+ $sf = "";
+
+ $img = "";
+
+ foreach $sym (keys %file) {
+ if ($sampleCount{$app,$sym} eq "") { next; }
+
+ if ($img{$app,$sym} ne $img) {
+ $img = $img{$app,$sym};
+ $out .= "ob=$img\n";
+ }
+
+ $file = $file{$sym};
+ if ($sf ne $file) {
+ if ($fileNum{$file} eq "") {
+ $fileNum{$file} = $fileNum;
+ $out .= "fl=($fileNum) $file\n";
+ $fileNum++;
+ }
+ else {
+ $out .= "fl=($fileNum{$file})\n";
+ }
+ $sf = $file;
+ }
+
+ $out .= "fn=$sym\n";
+ foreach $sc (1 .. $sampleCount{$app,$sym}) {
+ if ($sf ne $sFile{$app,$sym,$sc}) {
+ $sf = $sFile{$app,$sym,$sc};
+ if ($sf eq $file) {
+ $out .= "fe=($fileNum{$file})\n";
+ }
+ else {
+ if ($fileNum{$sf} eq "") {
+ $fileNum{$sf} = $fileNum;
+ $out .= "fi=($fileNum) $sf\n";
+ $fileNum++;
+ }
+ else {
+ $out .= "fi=($fileNum{$sf})\n";
+ }
+ }
+ }
+ $out .= "0x$vma{$app,$sym,$sc} $linenr{$app,$sym,$sc}";
+ foreach $e (1 .. $eventCount) { $c = $cost{"$app,$sym,$sc,$e"} ; $out .= " $c"; }
+ $out .= "\n";
+ }
+ }
+
+ open OUT, ">oprof.out.$app";
+ print OUT $out;
+ close OUT;
+}
diff --git a/kcachegrind/converters/pprof2calltree b/kcachegrind/converters/pprof2calltree
new file mode 100644
index 00000000..59f8770d
--- /dev/null
+++ b/kcachegrind/converters/pprof2calltree
@@ -0,0 +1,218 @@
+#!/usr/bin/env php
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are met:
+#
+# - Redistributions of source code must retain the above copyright notice,
+# this list of conditions and the following disclaimer.
+#
+# - Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+#
+# - All advertising materials mentioning features or use of this software
+# must display the following acknowledgement: This product includes software
+# developed by OmniTI Computer Consulting.
+#
+# - Neither name of the company nor the names of its contributors may be
+# used to endorse or promote products derived from this software without
+# specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS `AS IS'' AND ANY
+# EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+# DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
+# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+# Copyright (c) 2004 OmniTI Computer Consulting
+# All rights reserved
+# The following code was written by George Schlossnagle <george@omniti.com>
+# and is provided completely free and without any warranty.
+#
+# This script is designed to convert the pprof output from
+# APD (http://pecl.php.net/apd/) to one readable by kcachegrind. To use
+# this script:
+#
+# 1) Install APD.
+# 2) Profile your script with APD accordingto the directions in it's
+# README file.
+# 3) Take the pprof trace file for your script (pprof.XXXXX.Y) and run it
+# through this script as follows:
+# > pprof2calltree -f pprof.12345.1
+# This creates a new file cachegrind.out.12345.1
+# 4) View your trace with pprof2calltree cachegrind.out.12345.1
+
+<?php
+
+require "Console/Getopt.php";
+
+$con = new Console_Getopt;
+$args = $con->readPHPArgv();
+array_shift($args);
+$shortoptions = 'f:';
+$retval = $con->getopt( $args, $shortoptions);
+if(is_object($retval)) {
+ usage();
+}
+foreach ($retval[0] as $kv_array) {
+ $opt[$kv_array[0]] = $kv_array[1];
+}
+if(!$opt['f']) {
+ usage();
+}
+if(!file_exists($opt['f'])) {
+ print "Trace file ${opt['f']} does not exist\n";
+ exit;
+}
+$IN = fopen($opt['f'], "r");
+if(!$IN) {
+ print "Trace file ${opt['f']} could not be opened\n";
+ exit;
+}
+
+$path_parts = pathinfo($opt['f']);
+$outfile = "cachegrind.out.".$path_parts['basename'];
+$OUT = fopen($outfile, "w");
+if(!$OUT) {
+ print "Destination file $outfile could not be opened.\n";
+ exit;
+}
+
+while(($line = fgets($IN)) !== false) {
+ $line = rtrim($line);
+ if($line == "END_HEADER") {
+ break;
+ }
+}
+$tree = array();
+$callstack = array();
+while(($line = fgets($IN)) !== false) {
+ $line = rtrim($line);
+ $args = explode(" ", $line);
+ if($args[0] == '!') {
+ $file_lookup[$args[1]] = $args[2];
+ }
+ else if($args[0] == '&') {
+ $function_lookup[$args[1]] = $args[2];
+ $function_type[$args[1]] = ($args[3] == 2)?"USER":"INTERNAL";
+ }
+ else if($args[0] == '+') {
+ $val = array(function_id => $args[1],
+ file_id => $args[2],
+ line => $args[3],
+ cost => 0);
+ array_push($callstack, $val);
+ }
+ else if($args[0] == '-') {
+ // retrieve $called to discard
+ $called = array_pop($callstack);
+ // retrieve $caller for reference
+ $caller = array_pop($callstack);
+ $called_id = $called['function_id'];
+
+ // Set meta data if not already set'
+ if(!array_key_exists($called_id, $tree)) {
+ $tree[$called_id] = $called;
+ // initialize these to 0
+ $tree[$called_id]['cost_per_line'] = array();
+ }
+ if($caller !== null) {
+ $caller['child_calls']++;
+ $caller_id = $caller['function_id'];
+ if(!array_key_exists($caller_id, $tree)) {
+ $tree[$caller_id] = $caller;
+ }
+ $caller['cost'] += $called['cost'];
+ $tree[$caller_id]['called_funcs'][$tree[$caller_id]['call_counter']++][$called_id][$called['file_id']][$called['line']] += $called['cost'];
+ array_push($callstack, $caller);
+ }
+ if(is_array($called['cost_per_line'])) {
+ foreach($called[cost_per_line] as $file => $lines) {
+ foreach($lines as $line => $cost) {
+ $tree[$called_id]['cost_per_line'][$file][$line] += $cost;
+ }
+ }
+ }
+ }
+ else if($args[0] == '@') {
+ $called = array_pop($callstack);
+ switch(count($args)) {
+ // support new and old-style pprof data
+ case 6:
+ $file = $args[1];
+ $line = $args[2];
+ $real_tm = $args[5];
+ break;
+ case 4:
+ $file = $called['file_id'];
+ $line = $called['line'];
+ $real_tm = $args[3];
+ break;
+
+ }
+ $called['cost_per_line'][$file][$line] += $real_tm;
+ $called['cost'] += $real_tm;
+ $total_cost += $real_tm;
+ array_push($callstack, $called);
+ }
+}
+
+ob_start();
+print "events: Tick\n";
+print "summary: $total_cost\n";
+printf("cmd: %s\n", $file_lookup[1]);
+print "\n";
+
+foreach($tree as $caller => $data) {
+ $filename = $file_lookup[$data['file_id']]?$file_lookup[$data['file_id']]:"???";
+ printf("ob=%s\n", $function_type[$caller]);
+ printf("fl=%s\n", $filename);
+ printf("fn=%s\n", $function_lookup[$caller]);
+ if(is_array($data['cost_per_line'])) {
+ foreach($data['cost_per_line'] as $file => $lines) {
+ foreach($lines as $line => $cost) {
+ print "$line $cost\n";
+ }
+ }
+ }
+ else if ($data['cost']) {
+ printf("COST %s %s\n", $items['line'], $items['cost']);
+ }
+ else {
+ print_r($items);
+ }
+ if(is_array($data['called_funcs'])) {
+ foreach($data['called_funcs'] as $counter => $items) {
+ foreach($items as $called_id => $costs) {
+ if(is_array($costs)) {
+ printf("cfn=%s\n", $function_lookup[$called_id]);
+ foreach($costs as $file => $lines) {
+ printf("cfi=%s\ncalls=1\n", $file_lookup[$file]);
+ foreach($lines as $line => $cost) {
+ print "$line $cost\n";
+ }
+ }
+ }
+ }
+ }
+ }
+ print "\n";
+}
+print "\ntotals=$total_cost\n";
+$buffer = ob_get_clean();
+print "Writing kcachegrind compatible output to $outfile\n";
+fwrite($OUT, $buffer);
+
+function usage()
+{
+ print <<<EOD
+pprof2calltree -f <tracefile>
+
+EOD;
+ exit(1);
+}
+?>
diff --git a/kcachegrind/kcachegrind.lsm.in b/kcachegrind/kcachegrind.lsm.in
new file mode 100644
index 00000000..fba32141
--- /dev/null
+++ b/kcachegrind/kcachegrind.lsm.in
@@ -0,0 +1,11 @@
+Begin3
+Title: kcachegrind
+Version: @KCACHEGRIND_VERSION@
+Description: KDE Profiling Visualisation Tool
+Keywords: Profiling, Performance Analysis, Visualisation, Development
+Author: Josef Weidendorfer <Josef.Weidendorfer@gmx.de>
+Maintained-by: Josef Weidendorfer <Josef.Weidendorfer@gmx.de>
+Home-page: http://kcachegrind.sourceforge.net
+Platforms: Linux and other Unices
+Copying-policy: GNU Public License
+End
diff --git a/kcachegrind/kcachegrind.spec.in b/kcachegrind/kcachegrind.spec.in
new file mode 100644
index 00000000..060dd28e
--- /dev/null
+++ b/kcachegrind/kcachegrind.spec.in
@@ -0,0 +1,55 @@
+Summary: KDE Profiling Visualisation Tool
+Name: kcachegrind
+Version: @KCACHEGRIND_VERSION@
+Release: 1
+Copyright: GPL
+Group: Development/Tools
+Vendor: (none)
+URL: http://kcachegrind.sourceforge.net
+Packager: Josef Weidendorfer <Josef.Weidendorfer@gmx.de>
+Source: kcachegrind-@KCACHEGRIND_VERSION@.tar.gz
+BuildRoot: /var/tmp/build
+
+%description
+KCachegrind is a GPL'd tool for quick browsing in and visualisation
+of performance data of an application run. This data is produced by
+profiling tools and typically includes distribution of cost events
+to source code ranges (instructions, source lines, functions, C++ classes)
+and call relationship of functions.
+KCachegrind has a list of functions sorted according to different cost
+types, and can provide various performance views for a function like
+direct/indirect callers/callees, TreeMap visualisation of cost distribution
+among callees, call graph sectors centered around the function and
+annotated source/assembler.
+Currently, KCachegrind depends on data delivered by the profiling tool
+calltree, powered by the Valgrind runtime instrumentation framework.
+
+%prep
+%setup
+CFLAGS="$RPM_OPT_FLAGS" CXXFLAGS="$RPM_OPT_FLAGS" ./configure \
+ \
+ $LOCALFLAGS
+%build
+# Setup for parallel builds
+numprocs=`egrep -c ^cpu[0-9]+ /proc/stat || :`
+if [ "$numprocs" = "0" ]; then
+ numprocs=1
+fi
+
+make -j$numprocs
+
+%install
+make install-strip DESTDIR=$RPM_BUILD_ROOT
+
+cd $RPM_BUILD_ROOT
+find . -type d | sed '1,2d;s,^\.,\%attr(-\,root\,root) \%dir ,' > $RPM_BUILD_DIR/file.list.kcachegrind
+find . -type f | sed 's,^\.,\%attr(-\,root\,root) ,' >> $RPM_BUILD_DIR/file.list.kcachegrind
+find . -type l | sed 's,^\.,\%attr(-\,root\,root) ,' >> $RPM_BUILD_DIR/file.list.kcachegrind
+
+%clean
+rm -rf $RPM_BUILD_ROOT/*
+rm -rf $RPM_BUILD_DIR/kcachegrind
+rm -rf ../file.list.kcachegrind
+
+
+%files -f ../file.list.kcachegrind
diff --git a/kcachegrind/kcachegrind/Doxyfile b/kcachegrind/kcachegrind/Doxyfile
new file mode 100644
index 00000000..72db41bc
--- /dev/null
+++ b/kcachegrind/kcachegrind/Doxyfile
@@ -0,0 +1,157 @@
+# Doxygen configuration generated by Doxywizard version 0.1
+#---------------------------------------------------------------------------
+# General configuration options
+#---------------------------------------------------------------------------
+PROJECT_NAME = kcachegrind
+PROJECT_NUMBER =
+OUTPUT_DIRECTORY =
+OUTPUT_LANGUAGE = English
+EXTRACT_ALL = YES
+EXTRACT_PRIVATE = YES
+EXTRACT_STATIC = YES
+HIDE_UNDOC_MEMBERS =
+HIDE_UNDOC_CLASSES =
+BRIEF_MEMBER_DESC =
+REPEAT_BRIEF =
+ALWAYS_DETAILED_SEC =
+FULL_PATH_NAMES =
+STRIP_FROM_PATH =
+INTERNAL_DOCS =
+CLASS_DIAGRAMS =
+SOURCE_BROWSER =
+INLINE_SOURCES =
+STRIP_CODE_COMMENTS =
+CASE_SENSE_NAMES =
+SHORT_NAMES =
+HIDE_SCOPE_NAMES =
+VERBATIM_HEADERS =
+SHOW_INCLUDE_FILES =
+JAVADOC_AUTOBRIEF =
+INHERIT_DOCS =
+INLINE_INFO =
+SORT_MEMBER_DOCS =
+DISTRIBUTE_GROUP_DOC =
+TAB_SIZE =
+ENABLED_SECTIONS =
+GENERATE_TODOLIST =
+GENERATE_TESTLIST =
+GENERATE_BUGLIST =
+ALIASES =
+MAX_INITIALIZER_LINES =
+OPTIMIZE_OUTPUT_FOR_C =
+SHOW_USED_FILES =
+#---------------------------------------------------------------------------
+# configuration options related to warning and progress messages
+#---------------------------------------------------------------------------
+QUIET =
+WARNINGS =
+WARN_IF_UNDOCUMENTED =
+WARN_FORMAT = "$file:$line: $text"
+WARN_LOGFILE =
+#---------------------------------------------------------------------------
+# configuration options related to the input files
+#---------------------------------------------------------------------------
+INPUT = .
+FILE_PATTERNS = *.cpp \
+ *.h
+RECURSIVE = no
+EXCLUDE =
+EXCLUDE_PATTERNS =
+EXAMPLE_PATH =
+EXAMPLE_PATTERNS =
+IMAGE_PATH =
+INPUT_FILTER =
+FILTER_SOURCE_FILES =
+#---------------------------------------------------------------------------
+# configuration options related to the alphabetical class index
+#---------------------------------------------------------------------------
+ALPHABETICAL_INDEX =
+COLS_IN_ALPHA_INDEX =
+IGNORE_PREFIX =
+#---------------------------------------------------------------------------
+# configuration options related to the HTML output
+#---------------------------------------------------------------------------
+GENERATE_HTML =
+HTML_OUTPUT = html
+HTML_HEADER =
+HTML_FOOTER =
+HTML_STYLESHEET =
+HTML_ALIGN_MEMBERS =
+GENERATE_HTMLHELP =
+GENERATE_CHI =
+BINARY_TOC =
+TOC_EXPAND =
+DISABLE_INDEX =
+ENUM_VALUES_PER_LINE =
+GENERATE_TREEVIEW =
+TREEVIEW_WIDTH =
+#---------------------------------------------------------------------------
+# configuration options related to the LaTeX output
+#---------------------------------------------------------------------------
+GENERATE_LATEX = NO
+LATEX_OUTPUT = latex
+COMPACT_LATEX =
+PAPER_TYPE = a4wide
+EXTRA_PACKAGES =
+LATEX_HEADER =
+PDF_HYPERLINKS =
+USE_PDFLATEX =
+LATEX_BATCHMODE =
+#---------------------------------------------------------------------------
+# configuration options related to the RTF output
+#---------------------------------------------------------------------------
+GENERATE_RTF = NO
+RTF_OUTPUT = rtf
+COMPACT_RTF =
+RTF_HYPERLINKS =
+RTF_STYLESHEET_FILE =
+RTF_EXTENSIONS_FILE =
+#---------------------------------------------------------------------------
+# configuration options related to the man page output
+#---------------------------------------------------------------------------
+GENERATE_MAN = NO
+MAN_OUTPUT = man
+MAN_EXTENSION = .3
+MAN_LINKS =
+#---------------------------------------------------------------------------
+# Configuration options related to the preprocessor
+#---------------------------------------------------------------------------
+ENABLE_PREPROCESSING =
+MACRO_EXPANSION =
+EXPAND_ONLY_PREDEF =
+SEARCH_INCLUDES =
+INCLUDE_PATH =
+INCLUDE_FILE_PATTERNS =
+PREDEFINED =
+EXPAND_AS_DEFINED =
+#---------------------------------------------------------------------------
+# Configuration::addtions related to external references
+#---------------------------------------------------------------------------
+TAGFILES =
+GENERATE_TAGFILE =
+ALLEXTERNALS =
+PERL_PATH = /usr/bin/perl
+#---------------------------------------------------------------------------
+# Configuration options related to the dot tool
+#---------------------------------------------------------------------------
+HAVE_DOT =
+CLASS_GRAPH =
+COLLABORATION_GRAPH =
+INCLUDE_GRAPH =
+INCLUDED_BY_GRAPH =
+GRAPHICAL_HIERARCHY =
+DOT_PATH =
+MAX_DOT_GRAPH_WIDTH =
+MAX_DOT_GRAPH_HEIGHT =
+GENERATE_LEGEND =
+DOT_CLEANUP =
+#---------------------------------------------------------------------------
+# Configuration::addtions related to the search engine
+#---------------------------------------------------------------------------
+SEARCHENGINE =
+CGI_NAME = search.cgi
+CGI_URL =
+DOC_URL =
+DOC_ABSPATH =
+BIN_ABSPATH = /usr/local/bin/
+EXT_DOC_PATHS =
diff --git a/kcachegrind/kcachegrind/Makefile.am b/kcachegrind/kcachegrind/Makefile.am
new file mode 100644
index 00000000..3b4871aa
--- /dev/null
+++ b/kcachegrind/kcachegrind/Makefile.am
@@ -0,0 +1,62 @@
+bin_PROGRAMS = kcachegrind
+
+kcachegrind_SOURCES = \
+ functionselectionbase.ui \
+ stackselectionbase.ui \
+ partselectionbase.ui \
+ configdlgbase.ui \
+ loader.cpp cachegrindloader.cpp treemap.cpp pool.cpp \
+ main.cpp configuration.cpp \
+ functionselection.cpp coverage.cpp partgraph.cpp \
+ toplevel.cpp stackselection.cpp stackbrowser.cpp \
+ subcost.cpp tracedata.cpp partselection.cpp configdlg.cpp \
+ utils.cpp fixcost.cpp \
+ traceitemview.cpp instrview.cpp tabview.cpp \
+ sourceview.cpp callmapview.cpp callview.cpp \
+ coverageview.cpp costtypeview.cpp partview.cpp \
+ listutils.cpp costtypeitem.cpp multiview.cpp \
+ callitem.cpp coverageitem.cpp sourceitem.cpp \
+ costlistitem.cpp partlistitem.cpp functionitem.cpp \
+ instritem.cpp stackitem.cpp callgraphview.cpp
+
+kcachegrind_COMPILE_FIRST = ../version.h
+
+kcachegrind_LDADD = $(LIB_KIO)
+
+KDE_ICON = AUTO
+
+xdg_apps_DATA = kcachegrind.desktop
+
+mimeapplicationdir = $(kde_mimedir)/application
+mimeapplication_DATA = x-kcachegrind.desktop
+
+EXTRA_DIST = \
+ kcachegrind.desktop \
+ x-kcachegrind.desktop \
+ hi32-app-kcachegrind.png \
+ hi48-app-kcachegrind.png \
+ Doxyfile \
+ kcachegrindui.rc
+
+# set the include path for X, qt and KDE
+INCLUDES= $(all_includes)
+
+METASOURCES = AUTO
+
+# the library search path.
+kcachegrind_LDFLAGS = $(all_libraries) $(KDE_RPATH)
+
+rcdir = $(kde_datadir)/kcachegrind
+rc_DATA = kcachegrindui.rc
+
+tipdir = $(kde_datadir)/kcachegrind
+tip_DATA = tips
+
+messages: rc.cpp
+ $(PREPARETIPS) > tips.cpp
+ LIST=`find . -name \*.h -o -name \*.cpp`; \
+ if test -n "$$LIST"; then \
+ $(XGETTEXT) $$LIST -o $(podir)/kcachegrind.pot; \
+ fi
+ rm -f tips.cpp
+
diff --git a/kcachegrind/kcachegrind/cachegrindloader.cpp b/kcachegrind/kcachegrind/cachegrindloader.cpp
new file mode 100644
index 00000000..912b3bf6
--- /dev/null
+++ b/kcachegrind/kcachegrind/cachegrindloader.cpp
@@ -0,0 +1,1323 @@
+/* This file is part of KCachegrind.
+ Copyright (C) 2002, 2003 Josef Weidendorfer <Josef.Weidendorfer@gmx.de>
+
+ KCachegrind is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public
+ License as published by the Free Software Foundation, version 2.
+
+ 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; see the file COPYING. If not, write to
+ the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+*/
+
+#include <errno.h>
+
+#include <qfile.h>
+#include <qcstring.h>
+
+#include <klocale.h>
+#include <kdebug.h>
+
+#include "loader.h"
+#include "tracedata.h"
+#include "utils.h"
+#include "fixcost.h"
+
+
+#define TRACE_LOADER 0
+
+/*
+ * Loader for Callgrind Profile data (format based on Cachegrind format).
+ * See Callgrind documentation for the file format.
+ */
+
+class CachegrindLoader: public Loader
+{
+public:
+ CachegrindLoader();
+
+ bool canLoadTrace(QFile* file);
+ bool loadTrace(TracePart*);
+ bool isPartOfTrace(QString file, TraceData*);
+
+private:
+ bool loadTraceInternal(TracePart*);
+
+ enum lineType { SelfCost, CallCost, BoringJump, CondJump };
+
+ bool parsePosition(FixString& s, PositionSpec& newPos);
+
+ // position setters
+ void clearPosition();
+ void ensureObject();
+ void ensureFile();
+ void ensureFunction();
+ void setObject(const QString&);
+ void setCalledObject(const QString&);
+ void setFile(const QString&);
+ void setCalledFile(const QString&);
+ void setFunction(const QString&);
+ void setCalledFunction(const QString&);
+
+ QString _emptyString;
+
+ // current line in file to read in
+ QString _filename;
+ int _lineNo;
+
+ TraceSubMapping* subMapping;
+ TraceData* _data;
+ TracePart* _part;
+
+ // current position
+ lineType nextLineType;
+ bool hasLineInfo, hasAddrInfo;
+ PositionSpec currentPos;
+
+ // current function/line
+ TraceObject* currentObject;
+ TracePartObject* currentPartObject;
+ TraceFile* currentFile;
+ TracePartFile* currentPartFile;
+ TraceFunction* currentFunction;
+ TracePartFunction* currentPartFunction;
+ TraceFunctionSource* currentFunctionSource;
+ TraceInstr* currentInstr;
+ TracePartInstr* currentPartInstr;
+ TraceLine* currentLine;
+ TracePartLine* currentPartLine;
+
+ // current call
+ TraceObject* currentCalledObject;
+ TracePartObject* currentCalledPartObject;
+ TraceFile* currentCalledFile;
+ TracePartFile* currentCalledPartFile;
+ TraceFunction* currentCalledFunction;
+ TracePartFunction* currentCalledPartFunction;
+ SubCost currentCallCount;
+
+ // current jump
+ TraceFile* currentJumpToFile;
+ TraceFunction* currentJumpToFunction;
+ PositionSpec targetPos;
+ SubCost jumpsFollowed, jumpsExecuted;
+
+ /** Support for compressed string format
+ * This uses the following string compression model
+ * for objects, files, functions:
+ * If the name matches
+ * "(<Integer>) Name": this is a compression specification,
+ * mapping the integer number to Name and using Name.
+ * "(<Integer>)" : this is a compression reference.
+ * Assumes previous compression specification of the
+ * integer number to a name, uses this name.
+ * "Name" : Regular name
+ */
+ void clearCompression();
+ const QString& checkUnknown(const QString& n);
+ TraceObject* compressedObject(const QString& name);
+ TraceFile* compressedFile(const QString& name);
+ TraceFunction* compressedFunction(const QString& name,
+ TraceFile*, TraceObject*);
+
+ QPtrVector<TraceCostItem> _objectVector, _fileVector, _functionVector;
+};
+
+
+
+/**********************************************************
+ * Loader
+ */
+
+
+CachegrindLoader::CachegrindLoader()
+ : Loader("Callgrind",
+ i18n( "Import filter for Cachegrind/Callgrind generated profile data files") )
+{
+ _emptyString = QString("");
+}
+
+bool CachegrindLoader::canLoadTrace(QFile* file)
+{
+ if (!file) return false;
+
+ if (!file->isOpen()) {
+ if (!file->open( IO_ReadOnly ) ) {
+ kdDebug() << QFile::encodeName(_filename) << ": "
+ << strerror( errno ) << endl;
+ return false;
+ }
+ }
+
+ /*
+ * We recognize this as cachegrind/callgrind format if in the first
+ * 2047 bytes we see the string "\nevents:"
+ */
+ char buf[2048];
+ int read = file->readBlock(buf,2047);
+ if (read < 0)
+ return false;
+ buf[read] = 0;
+
+ QCString s;
+ s.setRawData(buf, read+1);
+ int pos = s.find("events:");
+ if (pos>0 && buf[pos-1] != '\n') pos = -1;
+ s.resetRawData(buf, read+1);
+ return (pos>=0);
+}
+
+bool CachegrindLoader::loadTrace(TracePart* p)
+{
+ /* do the loading in a new object so parallel load
+ * operations do not interfere each other.
+ */
+ CachegrindLoader l;
+
+ /* emit progress signals via the singleton loader */
+ connect(&l, SIGNAL(updateStatus(QString, int)),
+ this, SIGNAL(updateStatus(QString, int)));
+
+ return l.loadTraceInternal(p);
+}
+
+Loader* createCachegrindLoader()
+{
+ return new CachegrindLoader();
+}
+
+
+
+/**
+ * Return false if this is no position specification
+ */
+bool CachegrindLoader::parsePosition(FixString& line,
+ PositionSpec& newPos)
+{
+ char c;
+ uint diff;
+
+ if (hasAddrInfo) {
+
+ if (!line.first(c)) return false;
+
+ if (c == '*') {
+ // nothing changed
+ line.stripFirst(c);
+ newPos.fromAddr = currentPos.fromAddr;
+ newPos.toAddr = currentPos.toAddr;
+ }
+ else if (c == '+') {
+ line.stripFirst(c);
+ line.stripUInt(diff, false);
+ newPos.fromAddr = currentPos.fromAddr + diff;
+ newPos.toAddr = newPos.fromAddr;
+ }
+ else if (c == '-') {
+ line.stripFirst(c);
+ line.stripUInt(diff, false);
+ newPos.fromAddr = currentPos.fromAddr - diff;
+ newPos.toAddr = newPos.fromAddr;
+ }
+ else if (c >= '0') {
+ uint64 v;
+ line.stripUInt64(v, false);
+ newPos.fromAddr = Addr(v);
+ newPos.toAddr = newPos.fromAddr;
+ }
+ else return false;
+
+ // Range specification
+ if (line.first(c)) {
+ if (c == '+') {
+ line.stripFirst(c);
+ line.stripUInt(diff);
+ newPos.toAddr = newPos.fromAddr + diff;
+ }
+ else if ((c == '-') || (c == ':')) {
+ line.stripFirst(c);
+ uint64 v;
+ line.stripUInt64(v);
+ newPos.toAddr = Addr(v);
+ }
+ }
+ line.stripSpaces();
+
+#if TRACE_LOADER
+ if (newPos.fromAddr == newPos.toAddr)
+ kdDebug() << " Got Addr " << newPos.fromAddr.toString() << endl;
+ else
+ kdDebug() << " Got AddrRange " << newPos.fromAddr.toString()
+ << ":" << newPos.toAddr.toString() << endl;
+#endif
+
+ }
+
+ if (hasLineInfo) {
+
+ if (!line.first(c)) return false;
+
+ if (c > '9') return false;
+ else if (c == '*') {
+ // nothing changed
+ line.stripFirst(c);
+ newPos.fromLine = currentPos.fromLine;
+ newPos.toLine = currentPos.toLine;
+ }
+ else if (c == '+') {
+ line.stripFirst(c);
+ line.stripUInt(diff, false);
+ newPos.fromLine = currentPos.fromLine + diff;
+ newPos.toLine = newPos.fromLine;
+ }
+ else if (c == '-') {
+ line.stripFirst(c);
+ line.stripUInt(diff, false);
+ if (currentPos.fromLine < diff) {
+ kdError() << _filename << ":" << _lineNo
+ << " - Negative line number "
+ << (int)currentPos.fromLine - (int)diff << endl;
+ diff = currentPos.fromLine;
+ }
+ newPos.fromLine = currentPos.fromLine - diff;
+ newPos.toLine = newPos.fromLine;
+ }
+ else if (c >= '0') {
+ line.stripUInt(newPos.fromLine, false);
+ newPos.toLine = newPos.fromLine;
+ }
+ else return false;
+
+ // Range specification
+ if (line.first(c)) {
+ if (c == '+') {
+ line.stripFirst(c);
+ line.stripUInt(diff);
+ newPos.toLine = newPos.fromLine + diff;
+ }
+ else if ((c == '-') || (c == ':')) {
+ line.stripFirst(c);
+ line.stripUInt(newPos.toLine);
+ }
+ }
+ line.stripSpaces();
+
+#if TRACE_LOADER
+ if (newPos.fromLine == newPos.toLine)
+ kdDebug() << " Got Line " << newPos.fromLine << endl;
+ else
+ kdDebug() << " Got LineRange " << newPos.fromLine
+ << ":" << newPos.toLine << endl;
+#endif
+
+ }
+
+ return true;
+}
+
+// Support for compressed strings
+void CachegrindLoader::clearCompression()
+{
+ // this doesn't delete previous contained objects
+ _objectVector.clear();
+ _fileVector.clear();
+ _functionVector.clear();
+
+ // reset to reasonable init size. We double lengths if needed.
+ _objectVector.resize(100);
+ _fileVector.resize(1000);
+ _functionVector.resize(10000);
+}
+
+const QString& CachegrindLoader::checkUnknown(const QString& n)
+{
+ if (n == "???") return _emptyString;
+ return n;
+}
+
+TraceObject* CachegrindLoader::compressedObject(const QString& name)
+{
+ if ((name[0] != '(') || !name[1].isDigit()) return _data->object(checkUnknown(name));
+
+ // compressed format using _objectVector
+ int p = name.find(')');
+ if (p<2) {
+ kdError() << _filename << ":" << _lineNo
+ << " - Invalid compressed ELF object ('"
+ << name << "')" << endl;
+ return 0;
+ }
+ unsigned index = name.mid(1, p-1).toInt();
+ TraceObject* o = 0;
+ p++;
+ if ((int)name.length()>p) {
+ while(name.at(p).isSpace()) p++;
+
+ if (_objectVector.size() <= index) {
+ int newSize = index * 2;
+#if TRACE_LOADER
+ kdDebug() << " CachegrindLoader: objectVector enlarged to "
+ << newSize << endl;
+#endif
+ _objectVector.resize(newSize);
+ }
+
+ QString realName = checkUnknown(name.mid(p));
+ o = (TraceObject*) _objectVector.at(index);
+ if (o && (o->name() != realName)) {
+ kdError() << _filename << ":" << _lineNo
+ << " - Redefinition of compressed ELF object index " << index
+ << " (was '" << o->name()
+ << "') to '" << realName << "'" << endl;
+ }
+
+ o = _data->object(realName);
+ _objectVector.insert(index, o);
+ }
+ else {
+ if ((_objectVector.size() <= index) ||
+ ( (o=(TraceObject*)_objectVector.at(index)) == 0)) {
+ kdError() << _filename << ":" << _lineNo
+ << " - Undefined compressed ELF object index " << index << endl;
+ return 0;
+ }
+ }
+
+ return o;
+}
+
+
+// Note: Callgrind sometimes gives different IDs for same file
+// (when references to same source file come from different ELF objects)
+TraceFile* CachegrindLoader::compressedFile(const QString& name)
+{
+ if ((name[0] != '(') || !name[1].isDigit()) return _data->file(checkUnknown(name));
+
+ // compressed format using _fileVector
+ int p = name.find(')');
+ if (p<2) {
+ kdError() << _filename << ":" << _lineNo
+ << " - Invalid compressed file ('"
+ << name << "')" << endl;
+ return 0;
+ }
+ unsigned int index = name.mid(1, p-1).toUInt();
+ TraceFile* f = 0;
+ p++;
+ if ((int)name.length()>p) {
+ while(name.at(p).isSpace()) p++;
+
+ if (_fileVector.size() <= index) {
+ int newSize = index * 2;
+#if TRACE_LOADER
+ kdDebug() << " CachegrindLoader::fileVector enlarged to "
+ << newSize << endl;
+#endif
+ _fileVector.resize(newSize);
+ }
+
+ QString realName = checkUnknown(name.mid(p));
+ f = (TraceFile*) _fileVector.at(index);
+ if (f && (f->name() != realName)) {
+ kdError() << _filename << ":" << _lineNo
+ << " - Redefinition of compressed file index " << index
+ << " (was '" << f->name()
+ << "') to '" << realName << "'" << endl;
+ }
+
+ f = _data->file(realName);
+ _fileVector.insert(index, f);
+ }
+ else {
+ if ((_fileVector.size() <= index) ||
+ ( (f=(TraceFile*)_fileVector.at(index)) == 0)) {
+ kdError() << _filename << ":" << _lineNo
+ << " - Undefined compressed file index " << index << endl;
+ return 0;
+ }
+ }
+
+ return f;
+}
+
+// Note: Callgrind gives different IDs even for same function
+// when parts of the function are from different source files.
+// Thus, it is no error when multiple indexes map to same function.
+TraceFunction* CachegrindLoader::compressedFunction(const QString& name,
+ TraceFile* file,
+ TraceObject* object)
+{
+ if ((name[0] != '(') || !name[1].isDigit())
+ return _data->function(checkUnknown(name), file, object);
+
+ // compressed format using _functionVector
+ int p = name.find(')');
+ if (p<2) {
+ kdError() << _filename << ":" << _lineNo
+ << " - Invalid compressed function ('"
+ << name << "')" << endl;
+ return 0;
+ }
+
+
+ unsigned int index = name.mid(1, p-1).toUInt();
+ TraceFunction* f = 0;
+ p++;
+ if ((int)name.length()>p) {
+ while(name.at(p).isSpace()) p++;
+
+ if (_functionVector.size() <= index) {
+ int newSize = index * 2;
+#if TRACE_LOADER
+ kdDebug() << " CachegrindLoader::functionVector enlarged to "
+ << newSize << endl;
+#endif
+ _functionVector.resize(newSize);
+ }
+
+ QString realName = checkUnknown(name.mid(p));
+ f = (TraceFunction*) _functionVector.at(index);
+ if (f && (f->name() != realName)) {
+ kdError() << _filename << ":" << _lineNo
+ << " - Redefinition of compressed function index " << index
+ << " (was '" << f->name()
+ << "') to '" << realName << "'" << endl;
+ }
+
+ f = _data->function(realName, file, object);
+ _functionVector.insert(index, f);
+
+#if TRACE_LOADER
+ kdDebug() << "compressedFunction: Inserted at Index " << index
+ << "\n " << f->fullName()
+ << "\n in " << f->cls()->fullName()
+ << "\n in " << f->file()->fullName()
+ << "\n in " << f->object()->fullName() << endl;
+#endif
+ }
+ else {
+ if ((_functionVector.size() <= index) ||
+ ( (f=(TraceFunction*)_functionVector.at(index)) == 0)) {
+ kdError() << _filename << ":" << _lineNo
+ << " - Undefined compressed function index "
+ << index << endl;
+ return 0;
+ }
+
+ // there was a check if the used function (returned from KCachegrinds
+ // model) has the same object and file as here given to us, but that was wrong:
+ // that holds only if we make this assumption on the model...
+ }
+
+ return f;
+}
+
+
+// make sure that a valid object is set, at least dummy with empty name
+void CachegrindLoader::ensureObject()
+{
+ if (currentObject) return;
+
+ currentObject = _data->object(_emptyString);
+ currentPartObject = currentObject->partObject(_part);
+}
+
+void CachegrindLoader::setObject(const QString& name)
+{
+ currentObject = compressedObject(name);
+ if (!currentObject) {
+ kdError() << _filename << ":" << _lineNo
+ << " - Invalid object specification, setting to unknown" << endl;
+
+ currentObject = _data->object(_emptyString);
+ }
+
+ currentPartObject = currentObject->partObject(_part);
+ currentFunction = 0;
+ currentPartFunction = 0;
+}
+
+void CachegrindLoader::setCalledObject(const QString& name)
+{
+ currentCalledObject = compressedObject(name);
+
+ if (!currentCalledObject) {
+ kdError() << _filename << ":" << _lineNo
+ << " - Invalid called specification, setting to unknown" << endl;
+
+ currentCalledObject = _data->object(_emptyString);
+ }
+
+ currentCalledPartObject = currentCalledObject->partObject(_part);
+}
+
+
+// make sure that a valid file is set, at least dummy with empty name
+void CachegrindLoader::ensureFile()
+{
+ if (currentFile) return;
+
+ currentFile = _data->file(_emptyString);
+ currentPartFile = currentFile->partFile(_part);
+}
+
+void CachegrindLoader::setFile(const QString& name)
+{
+ currentFile = compressedFile(name);
+
+ if (!currentFile) {
+ kdWarning() << _filename << ":" << _lineNo
+ << " - Invalid file specification, setting to unknown" << endl;
+
+ currentFile = _data->file(_emptyString);
+ }
+
+ currentPartFile = currentFile->partFile(_part);
+ currentLine = 0;
+ currentPartLine = 0;
+}
+
+void CachegrindLoader::setCalledFile(const QString& name)
+{
+ currentCalledFile = compressedFile(name);
+
+ if (!currentCalledFile) {
+ kdError() << _filename << ":" << _lineNo
+ << " - Invalid called file specification, setting to unknown" << endl;
+
+ currentCalledFile = _data->file(_emptyString);
+ }
+
+ currentCalledPartFile = currentCalledFile->partFile(_part);
+}
+
+// make sure that a valid function is set, at least dummy with empty name
+void CachegrindLoader::ensureFunction()
+{
+ if (currentFunction) return;
+
+ kdWarning() << _filename << ":" << _lineNo
+ << " - Function name not set" << endl;
+
+ ensureFile();
+ ensureObject();
+
+ currentFunction = _data->function(_emptyString,
+ currentFile,
+ currentObject);
+ currentPartFunction = currentFunction->partFunction(_part,
+ currentPartFile,
+ currentPartObject);
+}
+
+void CachegrindLoader::setFunction(const QString& name)
+{
+ ensureFile();
+ ensureObject();
+
+ currentFunction = compressedFunction( name,
+ currentFile,
+ currentObject);
+
+ if (!currentFunction) {
+ kdWarning() << _filename << ":" << _lineNo
+ << " - Invalid function, setting to unknown" << endl;
+
+ currentFunction = _data->function(_emptyString,
+ currentFile,
+ currentObject);
+ }
+
+ currentPartFunction = currentFunction->partFunction(_part,
+ currentPartFile,
+ currentPartObject);
+
+ currentFunctionSource = 0;
+ currentLine = 0;
+ currentPartLine = 0;
+}
+
+void CachegrindLoader::setCalledFunction(const QString& name)
+{
+ // if called object/file not set, use current object/file
+ if (!currentCalledObject) {
+ currentCalledObject = currentObject;
+ currentCalledPartObject = currentPartObject;
+ }
+
+ if (!currentCalledFile) {
+ // !=0 as functions needs file
+ currentCalledFile = currentFile;
+ currentCalledPartFile = currentPartFile;
+ }
+
+ currentCalledFunction = compressedFunction(name,
+ currentCalledFile,
+ currentCalledObject);
+ if (!currentCalledFunction) {
+ kdWarning() << _filename << ":" << _lineNo
+ << " - Invalid called function, setting to unknown" << endl;
+
+ currentCalledFunction = _data->function(_emptyString,
+ currentCalledFile,
+ currentCalledObject);
+ }
+
+ currentCalledPartFunction =
+ currentCalledFunction->partFunction(_part,
+ currentCalledPartFile,
+ currentCalledPartObject);
+}
+
+
+void CachegrindLoader::clearPosition()
+{
+ currentPos = PositionSpec();
+
+ // current function/line
+ currentFunction = 0;
+ currentPartFunction = 0;
+ currentFunctionSource = 0;
+ currentFile = 0;
+ currentPartFile = 0;
+ currentObject = 0;
+ currentPartObject = 0;
+ currentLine = 0;
+ currentPartLine = 0;
+ currentInstr = 0;
+ currentPartInstr = 0;
+
+ // current call
+ currentCalledObject = 0;
+ currentCalledPartObject = 0;
+ currentCalledFile = 0;
+ currentCalledPartFile = 0;
+ currentCalledFunction = 0;
+ currentCalledPartFunction = 0;
+ currentCallCount = 0;
+
+ // current jump
+ currentJumpToFile = 0;
+ currentJumpToFunction = 0;
+ targetPos = PositionSpec();
+ jumpsFollowed = 0;
+ jumpsExecuted = 0;
+
+ subMapping = 0;
+}
+
+
+/**
+ * The main import function...
+ */
+bool CachegrindLoader::loadTraceInternal(TracePart* part)
+{
+ clearCompression();
+ clearPosition();
+
+ _part = part;
+ _data = part->data();
+ QFile* pFile = part->file();
+
+ if (!pFile) return false;
+
+ _filename = pFile->name();
+
+ FixFile file(pFile);
+ if (!file.exists()) {
+ kdError() << "File doesn't exist\n" << endl;
+ return false;
+ }
+ kdDebug() << "Loading " << _filename << " ..." << endl;
+ QString statusMsg = i18n("Loading %1").arg(_filename);
+ int statusProgress = 0;
+ emit updateStatus(statusMsg,statusProgress);
+
+
+#if USE_FIXCOST
+ // FixCost Memory Pool
+ FixPool* pool = _data->fixPool();
+#endif
+
+ _lineNo = 0;
+ FixString line;
+ char c;
+ bool totalsSet = false;
+
+ // current position
+ nextLineType = SelfCost;
+ // default if there's no "positions:" line
+ hasLineInfo = true;
+ hasAddrInfo = false;
+
+ while (file.nextLine(line)) {
+
+ _lineNo++;
+
+#if TRACE_LOADER
+ kdDebug() << "[CachegrindLoader] " << _filename << ":" << _lineNo
+ << " - '" << QString(line) << "'" << endl;
+#endif
+
+ // if we cannot strip a character, this was an empty line
+ if (!line.first(c)) continue;
+
+ if (c <= '9') {
+
+ if (c == '#') continue;
+
+ // parse position(s)
+ if (!parsePosition(line, currentPos)) {
+ kdError() << _filename << ":" << _lineNo
+ << " - Invalid position specification ('"
+ << QString(line) << "')" << endl;
+ continue;
+ }
+
+ // go through after big switch
+ }
+ else { // if (c > '9')
+
+ line.stripFirst(c);
+
+ /* in order of probability */
+ switch(c) {
+
+ case 'f':
+
+ // fl=, fi=, fe=
+ if (line.stripPrefix("l=") ||
+ line.stripPrefix("i=") ||
+ line.stripPrefix("e=")) {
+
+ setFile(line);
+ continue;
+ }
+
+ // fn=
+ if (line.stripPrefix("n=")) {
+
+ setFunction(line);
+
+ // on a new function, update status
+ int progress = (int)(100.0 * file.current() / file.len() +.5);
+ if (progress != statusProgress) {
+ statusProgress = progress;
+
+ /* When this signal is connected, it most probably
+ * should lead to GUI update. Thus, when multiple
+ * "long operations" (like file loading) are in progress,
+ * this can temporarly switch to another operation.
+ */
+ emit updateStatus(statusMsg,statusProgress);
+ }
+
+ continue;
+ }
+
+ break;
+
+ case 'c':
+ // cob=
+ if (line.stripPrefix("ob=")) {
+ setCalledObject(line);
+ continue;
+ }
+
+ // cfi= / cfl=
+ if (line.stripPrefix("fl=") ||
+ line.stripPrefix("fi=")) {
+ setCalledFile(line);
+ continue;
+ }
+
+ // cfn=
+ if (line.stripPrefix("fn=")) {
+
+ setCalledFunction(line);
+ continue;
+ }
+
+ // calls=
+ if (line.stripPrefix("alls=")) {
+ // ignore long lines...
+ line.stripUInt64(currentCallCount);
+ nextLineType = CallCost;
+ continue;
+ }
+
+ // cmd:
+ if (line.stripPrefix("md:")) {
+ QString command = QString(line).stripWhiteSpace();
+ if (!_data->command().isEmpty() &&
+ _data->command() != command) {
+
+ kdWarning() << _filename << ":" << _lineNo
+ << " - Redefined command, was '"
+ << _data->command()
+ << "'" << endl;
+ }
+ _data->setCommand(command);
+ continue;
+ }
+
+ // creator:
+ if (line.stripPrefix("reator:")) {
+ // ignore ...
+ continue;
+ }
+
+ break;
+
+ case 'j':
+
+ // jcnd=
+ if (line.stripPrefix("cnd=")) {
+ bool valid;
+
+ valid = line.stripUInt64(jumpsFollowed) &&
+ line.stripPrefix("/") &&
+ line.stripUInt64(jumpsExecuted) &&
+ parsePosition(line, targetPos);
+
+ if (!valid) {
+ kdError() << _filename << ":" << _lineNo
+ << " - Invalid jcnd line" << endl;
+ }
+ else
+ nextLineType = CondJump;
+ continue;
+ }
+
+ if (line.stripPrefix("ump=")) {
+ bool valid;
+
+ valid = line.stripUInt64(jumpsExecuted) &&
+ parsePosition(line, targetPos);
+
+ if (!valid) {
+ kdError() << _filename << ":" << _lineNo
+ << " - Invalid jump line" << endl;
+ }
+ else
+ nextLineType = BoringJump;
+ continue;
+ }
+
+ // jfi=
+ if (line.stripPrefix("fi=")) {
+ currentJumpToFile = compressedFile(line);
+ continue;
+ }
+
+ // jfn=
+ if (line.stripPrefix("fn=")) {
+
+ if (!currentJumpToFile) {
+ // !=0 as functions needs file
+ currentJumpToFile = currentFile;
+ }
+
+ currentJumpToFunction =
+ compressedFunction(line,
+ currentJumpToFile,
+ currentObject);
+ continue;
+ }
+
+ break;
+
+ case 'o':
+
+ // ob=
+ if (line.stripPrefix("b=")) {
+ setObject(line);
+ continue;
+ }
+
+ break;
+
+ case '#':
+ continue;
+
+ case 't':
+
+ // totals:
+ if (line.stripPrefix("otals:")) continue;
+
+ // thread:
+ if (line.stripPrefix("hread:")) {
+ part->setThreadID(QString(line).toInt());
+ continue;
+ }
+
+ // timeframe (BB):
+ if (line.stripPrefix("imeframe (BB):")) {
+ part->setTimeframe(line);
+ continue;
+ }
+
+ break;
+
+ case 'd':
+
+ // desc:
+ if (line.stripPrefix("esc:")) {
+
+ line.stripSurroundingSpaces();
+
+ // desc: Trigger:
+ if (line.stripPrefix("Trigger:")) {
+ part->setTrigger(line);
+ }
+
+ continue;
+ }
+ break;
+
+ case 'e':
+
+ // events:
+ if (line.stripPrefix("vents:")) {
+ subMapping = _data->mapping()->subMapping(line);
+ part->setFixSubMapping(subMapping);
+ continue;
+ }
+
+ // event:<name>[=<formula>][:<long name>]
+ if (line.stripPrefix("vent:")) {
+ line.stripSurroundingSpaces();
+
+ FixString e, f, l;
+ if (!line.stripName(e)) {
+ kdError() << _filename << ":" << _lineNo
+ << " - Invalid event" << endl;
+ continue;
+ }
+ line.stripSpaces();
+ if (!line.stripFirst(c)) continue;
+
+ if (c=='=') f = line.stripUntil(':');
+ line.stripSpaces();
+
+ // add to known cost types
+ if (line.isEmpty()) line = e;
+ TraceCostType::add(new TraceCostType(e,line,f));
+ continue;
+ }
+ break;
+
+ case 'p':
+
+ // part:
+ if (line.stripPrefix("art:")) {
+ part->setPartNumber(QString(line).toInt());
+ continue;
+ }
+
+ // pid:
+ if (line.stripPrefix("id:")) {
+ part->setProcessID(QString(line).toInt());
+ continue;
+ }
+
+ // positions:
+ if (line.stripPrefix("ositions:")) {
+ QString positions(line);
+ hasLineInfo = (positions.find("line")>=0);
+ hasAddrInfo = (positions.find("instr")>=0);
+ continue;
+ }
+ break;
+
+ case 'v':
+
+ // version:
+ if (line.stripPrefix("ersion:")) {
+ part->setVersion(line);
+ continue;
+ }
+ break;
+
+ case 's':
+
+ // summary:
+ if (line.stripPrefix("ummary:")) {
+ if (!subMapping) {
+ kdError() << "No event line found. Skipping '" << _filename << endl;
+ return false;
+ }
+
+ part->totals()->set(subMapping, line);
+ continue;
+ }
+
+ case 'r':
+
+ // rcalls= (deprecated)
+ if (line.stripPrefix("calls=")) {
+ // handle like normal calls: we need the sum of call count
+ // recursive cost is discarded in cycle detection
+ line.stripUInt64(currentCallCount);
+ nextLineType = CallCost;
+
+ kdDebug() << "WARNING: This trace dump was generated by an old "
+ "version\n of the call-tree skin. Use a new one!" << endl;
+
+ continue;
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ kdError() << _filename << ":" << _lineNo
+ << " - Invalid line '" << c << QString(line) << "'" << endl;
+ continue;
+ }
+
+ if (!subMapping) {
+ kdError() << "No event line found. Skipping '" << _filename << "'" << endl;
+ return false;
+ }
+
+ // for a cost line, we always need a current function
+ ensureFunction();
+
+
+#if USE_FIXCOST
+ if (!currentFunctionSource ||
+ (currentFunctionSource->file() != currentFile))
+ currentFunctionSource = currentFunction->sourceFile(currentFile,
+ true);
+#else
+ if (hasAddrInfo) {
+ if (!currentInstr ||
+ (currentInstr->addr() != currentPos.fromAddr)) {
+ currentInstr = currentFunction->instr(currentPos.fromAddr,
+ true);
+
+ if (!currentInstr) {
+ kdError() << _filename << ":" << _lineNo
+ << " - Invalid address "
+ << currentPos.fromAddr.toString() << endl;
+
+ continue;
+ }
+
+ currentPartInstr = currentInstr->partInstr(part,
+ currentPartFunction);
+ }
+ }
+
+ if (hasLineInfo) {
+ if (!currentLine ||
+ (currentLine->lineno() != currentPos.fromLine)) {
+
+ currentLine = currentFunction->line(currentFile,
+ currentPos.fromLine,
+ true);
+ currentPartLine = currentLine->partLine(part,
+ currentPartFunction);
+ }
+ if (hasAddrInfo && currentInstr)
+ currentInstr->setLine(currentLine);
+ }
+#endif
+
+#if TRACE_LOADER
+ kdDebug() << _filename << ":" << _lineNo
+ << endl << " currentInstr "
+ << (currentInstr ? currentInstr->toString().ascii() : ".")
+ << endl << " currentLine "
+ << (currentLine ? currentLine->toString().ascii() : ".")
+ << "( file " << currentFile->name() << ")"
+ << endl << " currentFunction "
+ << currentFunction->prettyName().ascii()
+ << endl << " currentCalled "
+ << (currentCalledFunction ? currentCalledFunction->prettyName().ascii() : ".")
+ << endl;
+#endif
+
+ // create cost item
+
+ if (nextLineType == SelfCost) {
+
+#if USE_FIXCOST
+ new (pool) FixCost(part, pool,
+ currentFunctionSource,
+ currentPos,
+ currentPartFunction,
+ line);
+#else
+ if (hasAddrInfo) {
+ TracePartInstr* partInstr;
+ partInstr = currentInstr->partInstr(part, currentPartFunction);
+
+ if (hasLineInfo) {
+ // we need to set <line> back after reading for the line
+ int l = line.len();
+ const char* s = line.ascii();
+
+ partInstr->addCost(subMapping, line);
+ line.set(s,l);
+ }
+ else
+ partInstr->addCost(subMapping, line);
+ }
+
+ if (hasLineInfo) {
+ TracePartLine* partLine;
+ partLine = currentLine->partLine(part, currentPartFunction);
+ partLine->addCost(subMapping, line);
+ }
+#endif
+
+ if (!line.isEmpty()) {
+ kdError() << _filename << ":" << _lineNo
+ << " - Garbage at end of cost line ('"
+ << QString(line) << "')" << endl;
+ }
+ }
+ else if (nextLineType == CallCost) {
+ nextLineType = SelfCost;
+
+ TraceCall* calling = currentFunction->calling(currentCalledFunction);
+ TracePartCall* partCalling =
+ calling->partCall(part, currentPartFunction,
+ currentCalledPartFunction);
+
+#if USE_FIXCOST
+ FixCallCost* fcc;
+ fcc = new (pool) FixCallCost(part, pool,
+ currentFunctionSource,
+ hasLineInfo ? currentPos.fromLine : 0,
+ hasAddrInfo ? currentPos.fromAddr : Addr(0),
+ partCalling,
+ currentCallCount, line);
+ fcc->setMax(_data->callMax());
+#else
+ if (hasAddrInfo) {
+ TraceInstrCall* instrCall;
+ TracePartInstrCall* partInstrCall;
+
+ instrCall = calling->instrCall(currentInstr);
+ partInstrCall = instrCall->partInstrCall(part, partCalling);
+ partInstrCall->addCallCount(currentCallCount);
+
+ if (hasLineInfo) {
+ // we need to set <line> back after reading for the line
+ int l = line.len();
+ const char* s = line.ascii();
+
+ partInstrCall->addCost(subMapping, line);
+ line.set(s,l);
+ }
+ else
+ partInstrCall->addCost(subMapping, line);
+
+ // update maximum of call cost
+ _data->callMax()->maxCost(partInstrCall);
+ }
+
+ if (hasLineInfo) {
+ TraceLineCall* lineCall;
+ TracePartLineCall* partLineCall;
+
+ lineCall = calling->lineCall(currentLine);
+ partLineCall = lineCall->partLineCall(part, partCalling);
+
+ partLineCall->addCallCount(currentCallCount);
+ partLineCall->addCost(subMapping, line);
+
+ // update maximum of call cost
+ _data->callMax()->maxCost(partLineCall);
+ }
+#endif
+ currentCalledFile = 0;
+ currentCalledPartFile = 0;
+ currentCalledObject = 0;
+ currentCalledPartObject = 0;
+ currentCallCount = 0;
+
+ if (!line.isEmpty()) {
+ kdError() << _filename << ":" << _lineNo
+ << " - Garbage at end of call cost line ('"
+ << QString(line) << "')" << endl;
+ }
+ }
+ else { // (nextLineType == BoringJump || nextLineType == CondJump)
+
+ TraceFunctionSource* targetSource;
+
+ if (!currentJumpToFunction)
+ currentJumpToFunction = currentFunction;
+
+ targetSource = (currentJumpToFile) ?
+ currentJumpToFunction->sourceFile(currentJumpToFile, true) :
+ currentFunctionSource;
+
+#if USE_FIXCOST
+ new (pool) FixJump(part, pool,
+ /* source */
+ hasLineInfo ? currentPos.fromLine : 0,
+ hasAddrInfo ? currentPos.fromAddr : 0,
+ currentPartFunction,
+ currentFunctionSource,
+ /* target */
+ hasLineInfo ? targetPos.fromLine : 0,
+ hasAddrInfo ? targetPos.fromAddr : Addr(0),
+ currentJumpToFunction,
+ targetSource,
+ (nextLineType == CondJump),
+ jumpsExecuted, jumpsFollowed);
+#endif
+
+ if (0) {
+ kdDebug() << _filename << ":" << _lineNo
+ << " - jump from 0x" << currentPos.fromAddr.toString()
+ << " (line " << currentPos.fromLine
+ << ") to 0x" << targetPos.fromAddr.toString()
+ << " (line " << targetPos.fromLine << ")" << endl;
+
+ if (nextLineType == BoringJump)
+ kdDebug() << " Boring Jump, count " << jumpsExecuted.pretty() << endl;
+ else
+ kdDebug() << " Cond. Jump, followed " << jumpsFollowed.pretty()
+ << ", executed " << jumpsExecuted.pretty() << endl;
+ }
+
+ nextLineType = SelfCost;
+ currentJumpToFunction = 0;
+ currentJumpToFile = 0;
+
+ if (!line.isEmpty()) {
+ kdError() << _filename << ":" << _lineNo
+ << " - Garbage at end of jump cost line ('"
+ << QString(line) << "')" << endl;
+ }
+
+ }
+ }
+
+
+ emit updateStatus(statusMsg,100);
+
+ _part->invalidate();
+ if (!totalsSet) {
+ _part->totals()->clear();
+ _part->totals()->addCost(_part);
+ }
+
+ pFile->close();
+
+ return true;
+}
+
diff --git a/kcachegrind/kcachegrind/callgraphview.cpp b/kcachegrind/kcachegrind/callgraphview.cpp
new file mode 100644
index 00000000..f00efd94
--- /dev/null
+++ b/kcachegrind/kcachegrind/callgraphview.cpp
@@ -0,0 +1,2734 @@
+/* This file is part of KCachegrind.
+ Copyright (C) 2003 Josef Weidendorfer <Josef.Weidendorfer@gmx.de>
+
+ KCachegrind is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public
+ License as published by the Free Software Foundation, version 2.
+
+ 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; see the file COPYING. If not, write to
+ the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+*/
+
+/*
+ * Callgraph View
+ */
+
+#include <stdlib.h>
+#include <math.h>
+
+#include <qtooltip.h>
+#include <qfile.h>
+#include <qtextstream.h>
+#include <qwhatsthis.h>
+#include <qcanvas.h>
+#include <qwmatrix.h>
+#include <qpair.h>
+#include <qpainter.h>
+#include <qpopupmenu.h>
+#include <qstyle.h>
+#include <qprocess.h>
+
+#include <kdebug.h>
+#include <klocale.h>
+#include <kconfig.h>
+#include <ktempfile.h>
+#include <kapplication.h>
+#include <kiconloader.h>
+#include <kfiledialog.h>
+
+#include "configuration.h"
+#include "callgraphview.h"
+#include "toplevel.h"
+#include "listutils.h"
+
+
+/*
+ * TODO:
+ * - Zooming option for work canvas? (e.g. 1:1 - 1:3)
+ */
+
+#define DEBUG_GRAPH 0
+
+// CallGraphView defaults
+
+#define DEFAULT_FUNCLIMIT .05
+#define DEFAULT_CALLLIMIT .05
+#define DEFAULT_MAXCALLER 2
+#define DEFAULT_MAXCALLING -1
+#define DEFAULT_SHOWSKIPPED false
+#define DEFAULT_EXPANDCYCLES false
+#define DEFAULT_CLUSTERGROUPS false
+#define DEFAULT_DETAILLEVEL 1
+#define DEFAULT_LAYOUT GraphOptions::TopDown
+#define DEFAULT_ZOOMPOS Auto
+
+
+//
+// GraphEdgeList
+//
+
+GraphEdgeList::GraphEdgeList()
+ : _sortCallerPos(true)
+{}
+
+int GraphEdgeList::compareItems(Item item1, Item item2)
+{
+ CanvasEdge* e1 = ((GraphEdge*)item1)->canvasEdge();
+ CanvasEdge* e2 = ((GraphEdge*)item2)->canvasEdge();
+
+ // edges without arrow visualisations are sorted as low
+ if (!e1) return -1;
+ if (!e2) return 1;
+
+ int dx1, dy1, dx2, dy2;
+ int x, y;
+ if (_sortCallerPos) {
+ e1->controlPoints().point(0,&x,&y);
+ e2->controlPoints().point(0,&dx1,&dy1);
+ dx1 -= x; dy1 -= y;
+ }
+ else {
+ QPointArray a1 = e1->controlPoints();
+ QPointArray a2 = e2->controlPoints();
+ a1.point(a1.count()-2,&x,&y);
+ a2.point(a2.count()-1,&dx2,&dy2);
+ dx2 -= x; dy2 -= y;
+ }
+ double at1 = atan2(double(dx1), double(dy1));
+ double at2 = atan2(double(dx2), double(dy2));
+
+ return (at1 < at2) ? 1:-1;
+}
+
+
+
+
+//
+// GraphNode
+//
+
+GraphNode::GraphNode()
+{
+ _f=0;
+ self = incl = 0;
+ _cn = 0;
+
+ _visible = false;
+ _lastCallerIndex = _lastCallingIndex = -1;
+
+ callers.setSortCallerPos(false);
+ callings.setSortCallerPos(true);
+ _lastFromCaller = true;
+}
+
+TraceCall* GraphNode::visibleCaller()
+{
+ if (0) qDebug("GraphNode::visibleCaller %s: last %d, count %d",
+ _f->prettyName().ascii(), _lastCallerIndex, callers.count());
+
+ GraphEdge* e = callers.at(_lastCallerIndex);
+ if (e && !e->isVisible()) e = 0;
+ if (!e) {
+ double maxCost = 0.0;
+ GraphEdge* maxEdge = 0;
+ int idx = 0;
+ for(e = callers.first();e; e=callers.next(),idx++)
+ if (e->isVisible() && (e->cost > maxCost)) {
+ maxCost = e->cost;
+ maxEdge = e;
+ _lastCallerIndex = idx;
+ }
+ e = maxEdge;
+ }
+ return e ? e->call() : 0;
+}
+
+TraceCall* GraphNode::visibleCalling()
+{
+ if (0) qDebug("GraphNode::visibleCalling %s: last %d, count %d",
+ _f->prettyName().ascii(), _lastCallingIndex, callings.count());
+
+ GraphEdge* e = callings.at(_lastCallingIndex);
+ if (e && !e->isVisible()) e = 0;
+ if (!e) {
+ double maxCost = 0.0;
+ GraphEdge* maxEdge = 0;
+ int idx = 0;
+ for(e = callings.first();e; e=callings.next(),idx++)
+ if (e->isVisible() && (e->cost > maxCost)) {
+ maxCost = e->cost;
+ maxEdge = e;
+ _lastCallingIndex = idx;
+ }
+ e = maxEdge;
+ }
+ return e ? e->call() : 0;
+}
+
+void GraphNode::setCalling(GraphEdge* e)
+{
+ _lastCallingIndex = callings.findRef(e);
+ _lastFromCaller = false;
+}
+
+void GraphNode::setCaller(GraphEdge* e)
+{
+ _lastCallerIndex = callers.findRef(e);
+ _lastFromCaller = true;
+}
+
+TraceFunction* GraphNode::nextVisible()
+{
+ TraceCall* c;
+ if (_lastFromCaller) {
+ c = nextVisibleCaller(callers.at(_lastCallerIndex));
+ if (c) return c->called(true);
+ c = nextVisibleCalling(callings.at(_lastCallingIndex));
+ if (c) return c->caller(true);
+ }
+ else {
+ c = nextVisibleCalling(callings.at(_lastCallingIndex));
+ if (c) return c->caller(true);
+ c = nextVisibleCaller(callers.at(_lastCallerIndex));
+ if (c) return c->called(true);
+ }
+ return 0;
+}
+
+TraceFunction* GraphNode::priorVisible()
+{
+ TraceCall* c;
+ if (_lastFromCaller) {
+ c = priorVisibleCaller(callers.at(_lastCallerIndex));
+ if (c) return c->called(true);
+ c = priorVisibleCalling(callings.at(_lastCallingIndex));
+ if (c) return c->caller(true);
+ }
+ else {
+ c = priorVisibleCalling(callings.at(_lastCallingIndex));
+ if (c) return c->caller(true);
+ c = priorVisibleCaller(callers.at(_lastCallerIndex));
+ if (c) return c->called(true);
+ }
+ return 0;
+}
+
+TraceCall* GraphNode::nextVisibleCaller(GraphEdge* last)
+{
+ GraphEdge* e;
+ bool found = false;
+ int idx = 0;
+ for(e = callers.first();e; e=callers.next(),idx++) {
+ if (found && e->isVisible()) {
+ _lastCallerIndex = idx;
+ return e->call();
+ }
+ if (e == last) found = true;
+ }
+ return 0;
+}
+
+TraceCall* GraphNode::nextVisibleCalling(GraphEdge* last)
+{
+ GraphEdge* e;
+ bool found = false;
+ int idx = 0;
+ for(e = callings.first();e; e=callings.next(),idx++) {
+ if (found && e->isVisible()) {
+ _lastCallingIndex = idx;
+ return e->call();
+ }
+ if (e == last) found = true;
+ }
+ return 0;
+}
+
+TraceCall* GraphNode::priorVisibleCaller(GraphEdge* last)
+{
+ GraphEdge *e, *prev = 0;
+ int prevIdx = -1, idx = 0;
+ for(e = callers.first(); e; e=callers.next(),idx++) {
+ if (e == last) {
+ _lastCallerIndex = prevIdx;
+ return prev ? prev->call() : 0;
+ }
+ if (e->isVisible()) {
+ prev = e;
+ prevIdx = idx;
+ }
+ }
+ return 0;
+}
+
+TraceCall* GraphNode::priorVisibleCalling(GraphEdge* last)
+{
+ GraphEdge *e, *prev = 0;
+ int prevIdx = -1, idx = 0;
+ for(e = callings.first(); e; e=callings.next(),idx++) {
+ if (e == last) {
+ _lastCallingIndex = prevIdx;
+ return prev ? prev->call() : 0;
+ }
+ if (e->isVisible()) {
+ prev = e;
+ prevIdx = idx;
+ }
+ }
+ return 0;
+}
+
+//
+// GraphEdge
+//
+
+GraphEdge::GraphEdge()
+{
+ _c=0;
+ _from = _to = 0;
+ _fromNode = _toNode = 0;
+ cost = count = 0;
+ _ce = 0;
+
+ _visible = false;
+ _lastFromCaller = true;
+}
+
+QString GraphEdge::prettyName()
+{
+ if (_c) return _c->prettyName();
+ if (_from) return i18n("Call(s) from %1").arg(_from->prettyName());
+ if (_to) return i18n("Call(s) to %1").arg(_to->prettyName());
+ return i18n("(unknown call)");
+}
+
+
+TraceFunction* GraphEdge::visibleCaller()
+{
+ if (_from) {
+ _lastFromCaller = true;
+ if (_fromNode) _fromNode->setCalling(this);
+ return _from;
+ }
+ return 0;
+}
+
+TraceFunction* GraphEdge::visibleCalling()
+{
+ if (_to) {
+ _lastFromCaller = false;
+ if (_toNode) _toNode->setCaller(this);
+ return _to;
+ }
+ return 0;
+}
+
+TraceCall* GraphEdge::nextVisible()
+{
+ TraceCall* res = 0;
+
+ if (_lastFromCaller && _fromNode) {
+ res = _fromNode->nextVisibleCalling(this);
+ if (!res && _toNode)
+ res = _toNode->nextVisibleCaller(this);
+ }
+ else if (_toNode) {
+ res = _toNode->nextVisibleCaller(this);
+ if (!res && _fromNode)
+ res = _fromNode->nextVisibleCalling(this);
+ }
+ return res;
+}
+
+TraceCall* GraphEdge::priorVisible()
+{
+ TraceCall* res = 0;
+
+ if (_lastFromCaller && _fromNode) {
+ res = _fromNode->priorVisibleCalling(this);
+ if (!res && _toNode)
+ res = _toNode->priorVisibleCaller(this);
+ }
+ else if (_toNode) {
+ res = _toNode->priorVisibleCaller(this);
+ if (!res && _fromNode)
+ res = _fromNode->priorVisibleCalling(this);
+ }
+ return res;
+}
+
+
+
+//
+// GraphOptions
+//
+
+QString GraphOptions::layoutString(Layout l)
+{
+ if (l == Circular) return QString("Circular");
+ if (l == LeftRight) return QString("LeftRight");
+ return QString("TopDown");
+}
+
+GraphOptions::Layout GraphOptions::layout(QString s)
+{
+ if (s == QString("Circular")) return Circular;
+ if (s == QString("LeftRight")) return LeftRight;
+ return TopDown;
+}
+
+
+//
+// StorableGraphOptions
+//
+
+StorableGraphOptions::StorableGraphOptions()
+{
+ // default options
+ _funcLimit = DEFAULT_FUNCLIMIT;
+ _callLimit = DEFAULT_CALLLIMIT;
+ _maxCallerDepth = DEFAULT_MAXCALLER;
+ _maxCallingDepth = DEFAULT_MAXCALLING;
+ _showSkipped = DEFAULT_SHOWSKIPPED;
+ _expandCycles = DEFAULT_EXPANDCYCLES;
+ _detailLevel = DEFAULT_DETAILLEVEL;
+ _layout = DEFAULT_LAYOUT;
+}
+
+
+
+
+//
+// GraphExporter
+//
+
+GraphExporter::GraphExporter()
+{
+ _go = this;
+ _tmpFile = 0;
+ _item = 0;
+ reset(0, 0, 0, TraceItem::NoCostType, QString::null);
+}
+
+
+GraphExporter::GraphExporter(TraceData* d, TraceFunction* f, TraceCostType* ct,
+ TraceItem::CostType gt, QString filename)
+{
+ _go = this;
+ _tmpFile = 0;
+ _item = 0;
+ reset(d, f, ct, gt, filename);
+}
+
+
+GraphExporter::~GraphExporter()
+{
+ if (_item && _tmpFile) {
+#if DEBUG_GRAPH
+ _tmpFile->unlink();
+#endif
+ delete _tmpFile;
+ }
+}
+
+
+void GraphExporter::reset(TraceData*, TraceItem* i, TraceCostType* ct,
+ TraceItem::CostType gt, QString filename)
+{
+ _graphCreated = false;
+ _nodeMap.clear();
+ _edgeMap.clear();
+
+ if (_item && _tmpFile) {
+ _tmpFile->unlink();
+ delete _tmpFile;
+ }
+
+ if (i) {
+ switch(i->type()) {
+ case TraceItem::Function:
+ case TraceItem::FunctionCycle:
+ case TraceItem::Call:
+ break;
+ default:
+ i = 0;
+ }
+ }
+
+ _item = i;
+ _costType = ct;
+ _groupType = gt;
+ if (!i) return;
+
+ if (filename.isEmpty()) {
+ _tmpFile = new KTempFile(QString::null, ".dot");
+ _dotName = _tmpFile->name();
+ _useBox = true;
+ }
+ else {
+ _tmpFile = 0;
+ _dotName = filename;
+ _useBox = false;
+ }
+}
+
+
+
+void GraphExporter::setGraphOptions(GraphOptions* go)
+{
+ if (go == 0) go = this;
+ _go = go;
+}
+
+void GraphExporter::createGraph()
+{
+ if (!_item) return;
+ if (_graphCreated) return;
+ _graphCreated = true;
+
+ if ((_item->type() == TraceItem::Function) ||
+ (_item->type() == TraceItem::FunctionCycle)) {
+ TraceFunction* f = (TraceFunction*) _item;
+
+ double incl = f->inclusive()->subCost(_costType);
+ _realFuncLimit = incl * _go->funcLimit();
+ _realCallLimit = incl * _go->callLimit();
+
+ buildGraph(f, 0, true, 1.0); // down to callings
+
+ // set costs of function back to 0, as it will be added again
+ GraphNode& n = _nodeMap[f];
+ n.self = n.incl = 0.0;
+
+ buildGraph(f, 0, false, 1.0); // up to callers
+ }
+ else {
+ TraceCall* c = (TraceCall*) _item;
+
+ double incl = c->subCost(_costType);
+ _realFuncLimit = incl * _go->funcLimit();
+ _realCallLimit = incl * _go->callLimit();
+
+ // create edge
+ TraceFunction *caller, *called;
+ caller = c->caller(false);
+ called = c->called(false);
+ QPair<TraceFunction*,TraceFunction*> p(caller, called);
+ GraphEdge& e = _edgeMap[p];
+ e.setCall(c);
+ e.setCaller(p.first);
+ e.setCalling(p.second);
+ e.cost = c->subCost(_costType);
+ e.count = c->callCount();
+
+ SubCost s = called->inclusive()->subCost(_costType);
+ buildGraph(called, 0, true, e.cost / s); // down to callings
+ s = caller->inclusive()->subCost(_costType);
+ buildGraph(caller, 0, false, e.cost / s); // up to callers
+ }
+}
+
+void GraphExporter::writeDot()
+{
+ if (!_item) return;
+
+ QFile* file = 0;
+ QTextStream* stream = 0;
+
+ if (_tmpFile)
+ stream = _tmpFile->textStream();
+ else {
+ file = new QFile(_dotName);
+ if ( !file->open( IO_WriteOnly ) ) {
+ kdError() << "Can't write dot file '" << _dotName << "'" << endl;
+ return;
+ }
+ stream = new QTextStream(file);
+ }
+
+ if (!_graphCreated) createGraph();
+
+ /* Generate dot format...
+ * When used for the CallGraphView (in contrast to "Export Callgraph..."),
+ * the labels are only dummy placeholders to reserve space for our own
+ * drawings.
+ */
+
+ *stream << "digraph \"callgraph\" {\n";
+
+ if (_go->layout() == LeftRight) {
+ *stream << QString(" rankdir=LR;\n");
+ }
+ else if (_go->layout() == Circular) {
+ TraceFunction *f = 0;
+ switch(_item->type()) {
+ case TraceItem::Function:
+ case TraceItem::FunctionCycle:
+ f = (TraceFunction*) _item;
+ break;
+ case TraceItem::Call:
+ f = ((TraceCall*)_item)->caller(true);
+ break;
+ default:
+ break;
+ }
+ if (f)
+ *stream << QString(" center=F%1;\n").arg((long)f, 0, 16);
+ *stream << QString(" overlap=false;\n splines=true;\n");
+ }
+
+ // for clustering
+ QMap<TraceCostItem*,QPtrList<GraphNode> > nLists;
+
+ GraphNodeMap::Iterator nit;
+ for ( nit = _nodeMap.begin();
+ nit != _nodeMap.end(); ++nit ) {
+ GraphNode& n = *nit;
+
+ if (n.incl <= _realFuncLimit) continue;
+
+ // for clustering: get cost item group of function
+ TraceCostItem* g;
+ TraceFunction* f = n.function();
+ switch(_groupType) {
+ case TraceItem::Object: g = f->object(); break;
+ case TraceItem::Class: g = f->cls(); break;
+ case TraceItem::File: g = f->file(); break;
+ case TraceItem::FunctionCycle: g = f->cycle(); break;
+ default: g = 0; break;
+ }
+ nLists[g].append(&n);
+ }
+
+ QMap<TraceCostItem*,QPtrList<GraphNode> >::Iterator lit;
+ int cluster = 0;
+ for ( lit = nLists.begin();
+ lit != nLists.end(); ++lit, cluster++ ) {
+ QPtrList<GraphNode>& l = lit.data();
+ TraceCostItem* i = lit.key();
+
+ if (_go->clusterGroups() && i) {
+ QString iabr = i->prettyName();
+ if ((int)iabr.length() > Configuration::maxSymbolLength())
+ iabr = iabr.left(Configuration::maxSymbolLength()) + "...";
+
+ *stream << QString("subgraph \"cluster%1\" { label=\"%2\";\n")
+ .arg(cluster).arg(iabr);
+ }
+
+ GraphNode* np;
+ for(np = l.first(); np; np = l.next() ) {
+ TraceFunction* f = np->function();
+
+ QString abr = f->prettyName();
+ if ((int)abr.length() > Configuration::maxSymbolLength())
+ abr = abr.left(Configuration::maxSymbolLength()) + "...";
+
+ *stream << QString(" F%1 [").arg((long)f, 0, 16);
+ if (_useBox) {
+ // make label 3 lines for CallGraphView
+ *stream << QString("shape=box,label=\"** %1 **\\n**\\n%2\"];\n")
+ .arg(abr)
+ .arg(SubCost(np->incl).pretty());
+ }
+ else
+ *stream << QString("label=\"%1\\n%2\"];\n")
+ .arg(abr)
+ .arg(SubCost(np->incl).pretty());
+ }
+
+ if (_go->clusterGroups() && i)
+ *stream << QString("}\n");
+ }
+
+ GraphEdgeMap::Iterator eit;
+ for ( eit = _edgeMap.begin();
+ eit != _edgeMap.end(); ++eit ) {
+ GraphEdge& e = *eit;
+
+ if (e.cost < _realCallLimit) continue;
+ if (!_go->expandCycles()) {
+ // don't show inner cycle calls
+ if (e.call()->inCycle()>0) continue;
+ }
+
+
+ GraphNode& from = _nodeMap[e.from()];
+ GraphNode& to = _nodeMap[e.to()];
+
+ e.setCallerNode(&from);
+ e.setCallingNode(&to);
+
+ if ((from.incl <= _realFuncLimit) ||
+ (to.incl <= _realFuncLimit)) continue;
+
+ // remove dumped edges from n.callers/n.callings
+ from.callings.removeRef(&e);
+ to.callers.removeRef(&e);
+ from.callingSet.remove(&e);
+ to.callerSet.remove(&e);
+
+ *stream << QString(" F%1 -> F%2 [weight=%3")
+ .arg((long)e.from(), 0, 16)
+ .arg((long)e.to(), 0, 16)
+ .arg((long)log(log(e.cost)));
+
+ if (_go->detailLevel() ==1)
+ *stream << QString(",label=\"%1\"")
+ .arg(SubCost(e.cost).pretty());
+ else if (_go->detailLevel() ==2)
+ *stream << QString(",label=\"%3\\n%4 x\"")
+ .arg(SubCost(e.cost).pretty())
+ .arg(SubCost(e.count).pretty());
+
+ *stream << QString("];\n");
+ }
+
+ if (_go->showSkipped()) {
+
+ // Create sum-edges for skipped edges
+ GraphEdge* e;
+ double costSum, countSum;
+ for ( nit = _nodeMap.begin();
+ nit != _nodeMap.end(); ++nit ) {
+ GraphNode& n = *nit;
+ if (n.incl <= _realFuncLimit) continue;
+
+ costSum = countSum = 0.0;
+ for (e=n.callers.first();e;e=n.callers.next()) {
+ costSum += e->cost;
+ countSum += e->count;
+ }
+ if (costSum > _realCallLimit) {
+
+ QPair<TraceFunction*,TraceFunction*> p(0, n.function());
+ e = &(_edgeMap[p]);
+ e->setCalling(p.second);
+ e->cost = costSum;
+ e->count = countSum;
+
+ *stream << QString(" R%1 [shape=point,label=\"\"];\n")
+ .arg((long)n.function(), 0, 16);
+ *stream << QString(" R%1 -> F%2 [label=\"%3\\n%4 x\",weight=%5];\n")
+ .arg((long)n.function(), 0, 16)
+ .arg((long)n.function(), 0, 16)
+ .arg(SubCost(costSum).pretty())
+ .arg(SubCost(countSum).pretty())
+ .arg((int)log(costSum));
+ }
+
+ costSum = countSum = 0.0;
+ for (e=n.callings.first();e;e=n.callings.next()) {
+ costSum += e->cost;
+ countSum += e->count;
+ }
+ if (costSum > _realCallLimit) {
+
+ QPair<TraceFunction*,TraceFunction*> p(n.function(), 0);
+ e = &(_edgeMap[p]);
+ e->setCaller(p.first);
+ e->cost = costSum;
+ e->count = countSum;
+
+ *stream << QString(" S%1 [shape=point,label=\"\"];\n")
+ .arg((long)n.function(), 0, 16);
+ *stream << QString(" F%1 -> S%2 [label=\"%3\\n%4 x\",weight=%5];\n")
+ .arg((long)n.function(), 0, 16)
+ .arg((long)n.function(), 0, 16)
+ .arg(SubCost(costSum).pretty())
+ .arg(SubCost(countSum).pretty())
+ .arg((int)log(costSum));
+ }
+ }
+ }
+
+ // clear edges here completely.
+ // Visible edges are inserted again on parsing in CallGraphView::refresh
+ for ( nit = _nodeMap.begin();
+ nit != _nodeMap.end(); ++nit ) {
+ GraphNode& n = *nit;
+ n.callers.clear();
+ n.callings.clear();
+ n.callerSet.clear();
+ n.callingSet.clear();
+ }
+
+ *stream << "}\n";
+
+ if (_tmpFile) {
+ _tmpFile->close();
+ }
+ else {
+ file->close();
+ delete file;
+ delete stream;
+ }
+}
+
+void GraphExporter::sortEdges()
+{
+ GraphNodeMap::Iterator nit;
+ for ( nit = _nodeMap.begin();
+ nit != _nodeMap.end(); ++nit ) {
+ GraphNode& n = *nit;
+
+ n.callers.sort();
+ n.callings.sort();
+ }
+}
+
+TraceFunction* GraphExporter::toFunc(QString s)
+{
+ if (s[0] != 'F') return 0;
+ bool ok;
+ TraceFunction* f = (TraceFunction*) s.mid(1).toULong(&ok, 16);
+ if (!ok) return 0;
+
+ return f;
+}
+
+GraphNode* GraphExporter::node(TraceFunction* f)
+{
+ if (!f) return 0;
+
+ GraphNodeMap::Iterator it = _nodeMap.find(f);
+ if (it == _nodeMap.end()) return 0;
+
+ return &(*it);
+}
+
+GraphEdge* GraphExporter::edge(TraceFunction* f1, TraceFunction* f2)
+{
+ GraphEdgeMap::Iterator it = _edgeMap.find(qMakePair(f1, f2));
+ if (it == _edgeMap.end()) return 0;
+
+ return &(*it);
+}
+
+
+/**
+ * We do a DFS and don't stop on already visited nodes/edges,
+ * but add up costs. We only stop if limits/max depth is reached.
+ *
+ * For a node/edge, it can happen that the first time visited the
+ * cost will below the limit, so the search is stopped.
+ * If on a further visit of the node/edge the limit is reached,
+ * we use the whole node/edge cost and continue search.
+ */
+void GraphExporter::buildGraph(TraceFunction* f, int d,
+ bool toCallings, double factor)
+{
+#if DEBUG_GRAPH
+ kdDebug() << "buildGraph(" << f->prettyName() << "," << d << "," << factor
+ << ") [to " << (toCallings ? "Callings":"Callers") << "]" << endl;
+#endif
+
+ double oldIncl = 0.0;
+ GraphNode& n = _nodeMap[f];
+ if (n.function() == 0) {
+ n.setFunction(f);
+ }
+ else
+ oldIncl = n.incl;
+
+ double incl = f->inclusive()->subCost(_costType) * factor;
+ n.incl += incl;
+ n.self += f->subCost(_costType) * factor;
+ if (0) qDebug(" Added Incl. %f, now %f", incl, n.incl);
+
+ // A negative depth limit means "unlimited"
+ int maxDepth = toCallings ? _go->maxCallingDepth() : _go->maxCallerDepth();
+ if ((maxDepth>=0) && (d >= maxDepth)) {
+ if (0) qDebug(" Cutoff, max depth reached");
+ return;
+ }
+
+ // if we just reached the limit by summing, do a DFS
+ // from here with full incl. cost because of previous cutoffs
+ if ((n.incl >= _realFuncLimit) && (oldIncl < _realFuncLimit)) incl = n.incl;
+
+ if (f->cycle()) {
+ // for cycles members, we never stop on first visit, but always on 2nd
+ // note: a 2nd visit never should happen, as we don't follow inner-cycle
+ // calls
+ if (oldIncl > 0.0) {
+ if (0) qDebug(" Cutoff, 2nd visit to Cycle Member");
+ // and takeback cost addition, as it's added twice
+ n.incl = oldIncl;
+ n.self -= f->subCost(_costType) * factor;
+ return;
+ }
+ }
+ else if (incl <= _realFuncLimit) {
+ if (0) qDebug(" Cutoff, below limit");
+ return;
+ }
+
+ TraceCall* call;
+ TraceFunction* f2;
+
+
+ // on entering a cycle, only go the FunctionCycle
+ TraceCallList l = toCallings ?
+ f->callings(false) : f->callers(false);
+
+ for (call=l.first();call;call=l.next()) {
+
+ f2 = toCallings ? call->called(false) : call->caller(false);
+
+ double count = call->callCount() * factor;
+ double cost = call->subCost(_costType) * factor;
+
+ // ignore function calls with absolute cost < 3 per call
+ // No: This would skip a lot of functions e.g. with L2 cache misses
+ // if (count>0.0 && (cost/count < 3)) continue;
+
+ double oldCost = 0.0;
+ QPair<TraceFunction*,TraceFunction*> p(toCallings ? f:f2,
+ toCallings ? f2:f);
+ GraphEdge& e = _edgeMap[p];
+ if (e.call() == 0) {
+ e.setCall(call);
+ e.setCaller(p.first);
+ e.setCalling(p.second);
+ }
+ else
+ oldCost = e.cost;
+
+ e.cost += cost;
+ e.count += count;
+ if (0) qDebug(" Edge to %s, added cost %f, now %f",
+ f2->prettyName().ascii(), cost, e.cost);
+
+ // if this call goes into a FunctionCycle, we also show the real call
+ if (f2->cycle() == f2) {
+ TraceFunction* realF;
+ realF = toCallings ? call->called(true) : call->caller(true);
+ QPair<TraceFunction*,TraceFunction*> realP(toCallings ? f:realF,
+ toCallings ? realF:f);
+ GraphEdge& e = _edgeMap[realP];
+ if (e.call() == 0) {
+ e.setCall(call);
+ e.setCaller(realP.first);
+ e.setCalling(realP.second);
+ }
+ e.cost += cost;
+ e.count += count;
+ }
+
+ // - don't do a DFS on calls in recursion/cycle
+ if (call->inCycle()>0) continue;
+ if (call->isRecursion()) continue;
+
+ if (toCallings) {
+ GraphEdgeSet::Iterator it = n.callingSet.find(&e);
+ if (it == n.callingSet.end()) {
+ n.callings.append(&e);
+ n.callingSet.insert(&e, 1 );
+ }
+ }
+ else {
+ GraphEdgeSet::Iterator it = n.callerSet.find(&e);
+ if (it == n.callerSet.end()) {
+ n.callers.append(&e);
+ n.callerSet.insert(&e, 1 );
+ }
+ }
+
+ // if we just reached the call limit (=func limit by summing, do a DFS
+ // from here with full incl. cost because of previous cutoffs
+ if ((e.cost >= _realCallLimit) && (oldCost < _realCallLimit)) cost = e.cost;
+ if (cost < _realCallLimit) {
+ if (0) qDebug(" Edge Cutoff, limit not reached");
+ continue;
+ }
+
+ SubCost s;
+ if (call->inCycle())
+ s = f2->cycle()->inclusive()->subCost(_costType);
+ else
+ s = f2->inclusive()->subCost(_costType);
+ SubCost v = call->subCost(_costType);
+ buildGraph(f2, d+1, toCallings, factor * v / s);
+ }
+}
+
+
+//
+// PannerView
+//
+PannerView::PannerView(QWidget * parent, const char * name)
+ : QCanvasView(parent, name, WNoAutoErase | WStaticContents)
+{
+ _movingZoomRect = false;
+
+ // why doesn't this avoid flicker ?
+ viewport()->setBackgroundMode(Qt::NoBackground);
+ setBackgroundMode(Qt::NoBackground);
+}
+
+void PannerView::setZoomRect(QRect r)
+{
+ QRect oldRect = _zoomRect;
+ _zoomRect = r;
+ updateContents(oldRect);
+ updateContents(_zoomRect);
+}
+
+void PannerView::drawContents(QPainter * p, int clipx, int clipy, int clipw, int cliph)
+{
+ // save/restore around QCanvasView::drawContents seems to be needed
+ // for QT 3.0 to get the red rectangle drawn correct
+ p->save();
+ QCanvasView::drawContents(p,clipx,clipy,clipw,cliph);
+ p->restore();
+ if (_zoomRect.isValid()) {
+ p->setPen(red.dark());
+ p->drawRect(_zoomRect);
+ p->setPen(red);
+ p->drawRect(QRect(_zoomRect.x()+1, _zoomRect.y()+1,
+ _zoomRect.width()-2, _zoomRect.height()-2));
+ }
+}
+
+void PannerView::contentsMousePressEvent(QMouseEvent* e)
+{
+ if (_zoomRect.isValid()) {
+ if (!_zoomRect.contains(e->pos()))
+ emit zoomRectMoved(e->pos().x() - _zoomRect.center().x(),
+ e->pos().y() - _zoomRect.center().y());
+
+ _movingZoomRect = true;
+ _lastPos = e->pos();
+ }
+}
+
+void PannerView::contentsMouseMoveEvent(QMouseEvent* e)
+{
+ if (_movingZoomRect) {
+ emit zoomRectMoved(e->pos().x() - _lastPos.x(), e->pos().y() - _lastPos.y());
+ _lastPos = e->pos();
+ }
+}
+
+void PannerView::contentsMouseReleaseEvent(QMouseEvent*)
+{
+ _movingZoomRect = false;
+ emit zoomRectMoveFinished();
+}
+
+
+
+
+
+//
+// CanvasNode
+//
+
+CanvasNode::CanvasNode(CallGraphView* v, GraphNode* n,
+ int x, int y, int w, int h, QCanvas* c)
+ : QCanvasRectangle(x, y, w, h, c), _node(n), _view(v)
+{
+ setPosition(0, DrawParams::TopCenter);
+ setPosition(1, DrawParams::BottomCenter);
+
+ updateGroup();
+
+ if (!_node || !_view) return;
+
+ if (_node->function())
+ setText(0, _node->function()->prettyName());
+
+ TraceCost* totalCost;
+ if (_view->topLevel()->showExpanded()) {
+ if (_view->activeFunction()) {
+ if (_view->activeFunction()->cycle())
+ totalCost = _view->activeFunction()->cycle()->inclusive();
+ else
+ totalCost = _view->activeFunction()->inclusive();
+ }
+ else
+ totalCost = (TraceCost*) _view->activeItem();
+ }
+ else
+ totalCost = _view->data();
+ double total = totalCost->subCost(_view->costType());
+ double inclP = 100.0 * n->incl / total;
+ if (_view->topLevel()->showPercentage())
+ setText(1, QString("%1 %")
+ .arg(inclP, 0, 'f', Configuration::percentPrecision()));
+ else
+ setText(1, SubCost(n->incl).pretty());
+ setPixmap(1, percentagePixmap(25,10,(int)(inclP+.5), Qt::blue, true));
+}
+
+void CanvasNode::setSelected(bool s)
+{
+ StoredDrawParams::setSelected(s);
+ update();
+}
+
+void CanvasNode::updateGroup()
+{
+ if (!_view || !_node) return;
+
+ QColor c = Configuration::functionColor(_view->groupType(),
+ _node->function());
+ setBackColor(c);
+ update();
+}
+
+void CanvasNode::drawShape(QPainter& p)
+{
+ QRect r = rect(), origRect = r;
+
+ r.setRect(r.x()+1, r.y()+1, r.width()-2, r.height()-2);
+
+ RectDrawing d(r);
+ d.drawBack(&p, this);
+ r.setRect(r.x()+2, r.y()+2, r.width()-4, r.height()-4);
+
+ if (StoredDrawParams::selected() && _view->hasFocus()) {
+ _view->style().drawPrimitive( QStyle::PE_FocusRect, &p, r,
+ _view->colorGroup());
+ }
+
+ // draw afterwards to always get a frame even when zoomed
+ p.setPen(StoredDrawParams::selected() ? red : black);
+ p.drawRect(origRect);
+
+ d.setRect(r);
+ d.drawField(&p, 0, this);
+ d.drawField(&p, 1, this);
+}
+
+
+//
+// CanvasEdgeLabel
+//
+
+CanvasEdgeLabel::CanvasEdgeLabel(CallGraphView* v, CanvasEdge* ce,
+ int x, int y, int w, int h, QCanvas* c)
+ : QCanvasRectangle(x, y, w, h, c), _ce(ce), _view(v)
+{
+ GraphEdge* e = ce->edge();
+ if (!e) return;
+
+ setPosition(1, DrawParams::TopCenter);
+ setText(1, QString("%1 x").arg(SubCost(e->count).pretty()));
+
+ setPosition(0, DrawParams::BottomCenter);
+
+ TraceCost* totalCost;
+ if (_view->topLevel()->showExpanded()) {
+ if (_view->activeFunction()) {
+ if (_view->activeFunction()->cycle())
+ totalCost = _view->activeFunction()->cycle()->inclusive();
+ else
+ totalCost = _view->activeFunction()->inclusive();
+ }
+ else
+ totalCost = (TraceCost*) _view->activeItem();
+ }
+ else
+ totalCost = _view->data();
+ double total = totalCost->subCost(_view->costType());
+ double inclP = 100.0 * e->cost / total;
+ if (_view->topLevel()->showPercentage())
+ setText(0, QString("%1 %")
+ .arg(inclP, 0, 'f', Configuration::percentPrecision()));
+ else
+ setText(0, SubCost(e->cost).pretty());
+ setPixmap(0, percentagePixmap(25,10,(int)(inclP+.5), Qt::blue, true));
+
+ if (e->call() && (e->call()->isRecursion() || e->call()->inCycle())) {
+ QString icon = "undo";
+ KIconLoader* loader = KApplication::kApplication()->iconLoader();
+ QPixmap p= loader->loadIcon(icon, KIcon::Small, 0,
+ KIcon::DefaultState, 0, true);
+ setPixmap(0, p);
+ }
+}
+
+void CanvasEdgeLabel::drawShape(QPainter& p)
+{
+ QRect r = rect();
+ //p.setPen(blue);
+ //p.drawRect(r);
+ RectDrawing d(r);
+ d.drawField(&p, 0, this);
+ d.drawField(&p, 1, this);
+}
+
+//
+// CanvasEdgeArrow
+
+CanvasEdgeArrow::CanvasEdgeArrow(CanvasEdge* ce, QCanvas* c)
+ : QCanvasPolygon(c), _ce(ce)
+{}
+
+void CanvasEdgeArrow::drawShape(QPainter& p)
+{
+ if (_ce->isSelected()) p.setBrush(Qt::red);
+
+ QCanvasPolygon::drawShape(p);
+}
+
+//
+// CanvasEdge
+//
+
+CanvasEdge::CanvasEdge(GraphEdge* e, QCanvas* c)
+ : QCanvasSpline(c), _edge(e)
+{
+ _label = 0;
+ _arrow = 0;
+}
+
+void CanvasEdge::setSelected(bool s)
+{
+ QCanvasItem::setSelected(s);
+ update();
+ if (_arrow) _arrow->setSelected(s);
+}
+
+QPointArray CanvasEdge::areaPoints() const
+{
+ int minX = poly[0].x(), minY = poly[0].y();
+ int maxX = minX, maxY = minY;
+ int i;
+
+ if (0) qDebug("CanvasEdge::areaPoints\n P 0: %d/%d", minX, minY);
+ int len = poly.count();
+ for (i=1;i<len;i++) {
+ if (poly[i].x() < minX) minX = poly[i].x();
+ if (poly[i].y() < minY) minY = poly[i].y();
+ if (poly[i].x() > maxX) maxX = poly[i].x();
+ if (poly[i].y() > maxY) maxY = poly[i].y();
+ if (0) qDebug(" P %d: %d/%d", i, poly[i].x(), poly[i].y());
+ }
+ QPointArray a = poly.copy(), b = poly.copy();
+ if (minX == maxX) {
+ a.translate(-2, 0);
+ b.translate(2, 0);
+ }
+ else {
+ a.translate(0, -2);
+ b.translate(0, 2);
+ }
+ a.resize(2*len);
+ for (i=0;i<len;i++)
+ a[2 * len - 1 -i] = b[i];
+
+ if (0) {
+ qDebug(" Result:");
+ for (i=0;i<2*len;i++)
+ qDebug(" P %d: %d/%d", i, a[i].x(), a[i].y());
+ }
+
+ return a;
+}
+
+void CanvasEdge::drawShape(QPainter& p)
+{
+ if (isSelected()) p.setPen(Qt::red);
+
+ p.drawPolyline(poly);
+}
+
+
+//
+// CanvasFrame
+//
+
+QPixmap* CanvasFrame::_p = 0;
+
+CanvasFrame::CanvasFrame(CanvasNode* n, QCanvas* c)
+ : QCanvasRectangle(c)
+{
+ if (!_p) {
+
+ int d = 5;
+ float v1 = 130.0, v2 = 10.0, v = v1, f = 1.03;
+
+ // calculate pix size
+ QRect r(0, 0, 30, 30);
+ while (v>v2) {
+ r.setRect(r.x()-d, r.y()-d, r.width()+2*d, r.height()+2*d);
+ v /= f;
+ }
+
+ _p = new QPixmap(r.size());
+ _p->fill(Qt::white);
+ QPainter p(_p);
+ p.setPen(Qt::NoPen);
+
+ r.moveBy(-r.x(), -r.y());
+
+ while (v<v1) {
+ v *= f;
+ p.setBrush(QColor(265-(int)v, 265-(int)v, 265-(int)v));
+
+ p.drawRect(QRect(r.x(), r.y(), r.width(), d));
+ p.drawRect(QRect(r.x(), r.bottom()-d, r.width(), d));
+ p.drawRect(QRect(r.x(), r.y()+d, d, r.height()-2*d));
+ p.drawRect(QRect(r.right()-d, r.y()+d, d, r.height()-2*d));
+
+ r.setRect(r.x()+d, r.y()+d, r.width()-2*d, r.height()-2*d);
+ }
+ }
+
+ setSize(_p->width(), _p->height());
+ move(n->rect().center().x()-_p->width()/2,
+ n->rect().center().y()-_p->height()/2);
+}
+
+
+void CanvasFrame::drawShape(QPainter& p)
+{
+ p.drawPixmap( int(x()), int(y()), *_p );
+}
+
+
+
+
+//
+// Tooltips for CallGraphView
+//
+
+class CallGraphTip: public QToolTip
+{
+public:
+ CallGraphTip( QWidget* p ):QToolTip(p) {}
+
+protected:
+ void maybeTip( const QPoint & );
+};
+
+void CallGraphTip::maybeTip( const QPoint& pos )
+{
+ if (!parentWidget()->inherits( "CallGraphView" )) return;
+ CallGraphView* cgv = (CallGraphView*)parentWidget();
+
+ QPoint cPos = cgv->viewportToContents(pos);
+
+ if (0) qDebug("CallGraphTip for (%d/%d) -> (%d/%d) ?",
+ pos.x(), pos.y(), cPos.x(), cPos.y());
+
+ QCanvasItemList l = cgv->canvas()->collisions(cPos);
+ if (l.count() == 0) return;
+ QCanvasItem* i = l.first();
+
+ if (i->rtti() == CANVAS_NODE) {
+ CanvasNode* cn = (CanvasNode*)i;
+ GraphNode* n = cn->node();
+ if (0) qDebug("CallGraphTip: Mouse on Node '%s'",
+ n->function()->prettyName().ascii());
+
+ QString tipStr = QString("%1 (%2)").arg(cn->text(0)).arg(cn->text(1));
+ QPoint vPosTL = cgv->contentsToViewport(i->boundingRect().topLeft());
+ QPoint vPosBR = cgv->contentsToViewport(i->boundingRect().bottomRight());
+ tip(QRect(vPosTL, vPosBR), tipStr);
+
+ return;
+ }
+
+ // redirect from label / arrow to edge
+ if (i->rtti() == CANVAS_EDGELABEL)
+ i = ((CanvasEdgeLabel*)i)->canvasEdge();
+ if (i->rtti() == CANVAS_EDGEARROW)
+ i = ((CanvasEdgeArrow*)i)->canvasEdge();
+
+ if (i->rtti() == CANVAS_EDGE) {
+ CanvasEdge* ce = (CanvasEdge*)i;
+ GraphEdge* e = ce->edge();
+ if (0) qDebug("CallGraphTip: Mouse on Edge '%s'",
+ e->prettyName().ascii());
+
+ QString tipStr;
+ if (!ce->label())
+ tipStr = e->prettyName();
+ else
+ tipStr = QString("%1 (%2)")
+ .arg(ce->label()->text(0)).arg(ce->label()->text(1));
+ tip(QRect(pos.x()-5,pos.y()-5,pos.x()+5,pos.y()+5), tipStr);
+ }
+}
+
+
+
+
+//
+// CallGraphView
+//
+CallGraphView::CallGraphView(TraceItemView* parentView,
+ QWidget* parent, const char* name)
+ : QCanvasView(parent, name), TraceItemView(parentView)
+{
+ _zoomPosition = DEFAULT_ZOOMPOS;
+ _lastAutoPosition = TopLeft;
+
+ _canvas = 0;
+ _xMargin = _yMargin = 0;
+ _completeView = new PannerView(this);
+ _cvZoom = 1;
+ _selectedNode = 0;
+ _selectedEdge = 0;
+
+ _exporter.setGraphOptions(this);
+
+ _completeView->setVScrollBarMode(QScrollView::AlwaysOff);
+ _completeView->setHScrollBarMode(QScrollView::AlwaysOff);
+ _completeView->raise();
+ _completeView->hide();
+
+ setFocusPolicy(QWidget::StrongFocus);
+ setBackgroundMode(Qt::NoBackground);
+
+ connect(this, SIGNAL(contentsMoving(int,int)),
+ this, SLOT(contentsMovingSlot(int,int)));
+ connect(_completeView, SIGNAL(zoomRectMoved(int,int)),
+ this, SLOT(zoomRectMoved(int,int)));
+ connect(_completeView, SIGNAL(zoomRectMoveFinished()),
+ this, SLOT(zoomRectMoveFinished()));
+
+ QWhatsThis::add( this, whatsThis() );
+
+ // tooltips...
+ _tip = new CallGraphTip(this);
+
+ _renderProcess = 0;
+ _prevSelectedNode = 0;
+ connect(&_renderTimer, SIGNAL(timeout()),
+ this, SLOT(showRenderWarning()));
+}
+
+CallGraphView::~CallGraphView()
+{
+ delete _completeView;
+ delete _tip;
+
+ if (_canvas) {
+ setCanvas(0);
+ delete _canvas;
+ }
+}
+
+QString CallGraphView::whatsThis() const
+{
+ return i18n( "<b>Call Graph around active Function</b>"
+ "<p>Depending on configuration, this view shows "
+ "the call graph environment of the active function. "
+ "Note: the shown cost is <b>only</b> the cost which is "
+ "spent while the active function was actually running; "
+ "i.e. the cost shown for main() - if it's visible - should "
+ "be the same as the cost of the active function, as that's "
+ "the part of inclusive cost of main() spent while the active "
+ "function was running.</p>"
+ "<p>For cycles, blue call arrows indicate that this is an "
+ "artificial call added for correct drawing which "
+ "actually never happened.</p>"
+ "<p>If the graph is larger than the widget area, an overview "
+ "panner is shown in one edge. "
+ "There are similar visualization options to the "
+ "Call Treemap; the selected function is highlighted.<p>");
+}
+
+void CallGraphView::updateSizes(QSize s)
+{
+ if (!_canvas) return;
+
+ if (s == QSize(0,0)) s = size();
+
+ // the part of the canvas that should be visible
+ int cWidth = _canvas->width() - 2*_xMargin + 100;
+ int cHeight = _canvas->height() - 2*_yMargin + 100;
+
+ // hide birds eye view if no overview needed
+ if (!_data || !_activeItem ||
+ ((cWidth < s.width()) && cHeight < s.height())) {
+ _completeView->hide();
+ return;
+ }
+ _completeView->show();
+
+ // first, assume use of 1/3 of width/height (possible larger)
+ double zoom = .33 * s.width() / cWidth;
+ if (zoom * cHeight < .33 * s.height()) zoom = .33 * s.height() / cHeight;
+
+ // fit to widget size
+ if (cWidth * zoom > s.width()) zoom = s.width() / (double)cWidth;
+ if (cHeight * zoom > s.height()) zoom = s.height() / (double)cHeight;
+
+ // scale to never use full height/width
+ zoom = zoom * 3/4;
+
+ // at most a zoom of 1/3
+ if (zoom > .33) zoom = .33;
+
+ if (zoom != _cvZoom) {
+ _cvZoom = zoom;
+ if (0) qDebug("Canvas Size: %dx%d, Visible: %dx%d, Zoom: %f",
+ _canvas->width(), _canvas->height(),
+ cWidth, cHeight, zoom);
+
+ QWMatrix wm;
+ wm.scale( zoom, zoom );
+ _completeView->setWorldMatrix(wm);
+
+ // make it a little bigger to compensate for widget frame
+ _completeView->resize(int(cWidth * zoom) + 4,
+ int(cHeight * zoom) + 4);
+
+ // update ZoomRect in completeView
+ contentsMovingSlot(contentsX(), contentsY());
+ }
+
+ _completeView->setContentsPos(int(zoom*(_xMargin-50)),
+ int(zoom*(_yMargin-50)));
+
+ int cvW = _completeView->width();
+ int cvH = _completeView->height();
+ int x = width()- cvW - verticalScrollBar()->width() -2;
+ int y = height()-cvH - horizontalScrollBar()->height() -2;
+ QPoint oldZoomPos = _completeView->pos();
+ QPoint newZoomPos = QPoint(0,0);
+ ZoomPosition zp = _zoomPosition;
+ if (zp == Auto) {
+ QPoint tl1Pos = viewportToContents(QPoint(0,0));
+ QPoint tl2Pos = viewportToContents(QPoint(cvW,cvH));
+ QPoint tr1Pos = viewportToContents(QPoint(x,0));
+ QPoint tr2Pos = viewportToContents(QPoint(x+cvW,cvH));
+ QPoint bl1Pos = viewportToContents(QPoint(0,y));
+ QPoint bl2Pos = viewportToContents(QPoint(cvW,y+cvH));
+ QPoint br1Pos = viewportToContents(QPoint(x,y));
+ QPoint br2Pos = viewportToContents(QPoint(x+cvW,y+cvH));
+ int tlCols = _canvas->collisions(QRect(tl1Pos,tl2Pos)).count();
+ int trCols = _canvas->collisions(QRect(tr1Pos,tr2Pos)).count();
+ int blCols = _canvas->collisions(QRect(bl1Pos,bl2Pos)).count();
+ int brCols = _canvas->collisions(QRect(br1Pos,br2Pos)).count();
+ int minCols = tlCols;
+ zp = _lastAutoPosition;
+ switch(zp) {
+ case TopRight: minCols = trCols; break;
+ case BottomLeft: minCols = blCols; break;
+ case BottomRight: minCols = brCols; break;
+ default:
+ case TopLeft: minCols = tlCols; break;
+ }
+ if (minCols > tlCols) { minCols = tlCols; zp = TopLeft; }
+ if (minCols > trCols) { minCols = trCols; zp = TopRight; }
+ if (minCols > blCols) { minCols = blCols; zp = BottomLeft; }
+ if (minCols > brCols) { minCols = brCols; zp = BottomRight; }
+
+ _lastAutoPosition = zp;
+ }
+
+ switch(zp) {
+ case TopRight:
+ newZoomPos = QPoint(x,0);
+ break;
+ case BottomLeft:
+ newZoomPos = QPoint(0,y);
+ break;
+ case BottomRight:
+ newZoomPos = QPoint(x,y);
+ break;
+ default:
+ break;
+ }
+ if (newZoomPos != oldZoomPos) _completeView->move(newZoomPos);
+}
+
+void CallGraphView::focusInEvent(QFocusEvent*)
+{
+ if (!_canvas) return;
+
+ if (_selectedNode && _selectedNode->canvasNode()) {
+ _selectedNode->canvasNode()->setSelected(true); // requests item update
+ _canvas->update();
+ }
+}
+
+void CallGraphView::focusOutEvent(QFocusEvent* e)
+{
+ // trigger updates as in focusInEvent
+ focusInEvent(e);
+}
+
+void CallGraphView::keyPressEvent(QKeyEvent* e)
+{
+ if (!_canvas) {
+ e->ignore();
+ return;
+ }
+
+ if ((e->key() == Key_Return) ||
+ (e->key() == Key_Space)) {
+ if (_selectedNode)
+ activated(_selectedNode->function());
+ else if (_selectedEdge && _selectedEdge->call())
+ activated(_selectedEdge->call());
+ return;
+ }
+
+ // move selected node/edge
+ if (!(e->state() & (ShiftButton | ControlButton)) &&
+ (_selectedNode || _selectedEdge) &&
+ ((e->key() == Key_Up) ||
+ (e->key() == Key_Down) ||
+ (e->key() == Key_Left) ||
+ (e->key() == Key_Right))) {
+
+ TraceFunction* f = 0;
+ TraceCall* c = 0;
+
+ // rotate arrow key meaning for LeftRight layout
+ int key = e->key();
+ if (_layout == LeftRight) {
+ switch(key) {
+ case Key_Up: key = Key_Left; break;
+ case Key_Down: key = Key_Right; break;
+ case Key_Left: key = Key_Up; break;
+ case Key_Right: key = Key_Down; break;
+ default: break;
+ }
+ }
+
+ if (_selectedNode) {
+ if (key == Key_Up) c = _selectedNode->visibleCaller();
+ if (key == Key_Down) c = _selectedNode->visibleCalling();
+ if (key == Key_Right) f = _selectedNode->nextVisible();
+ if (key == Key_Left) f = _selectedNode->priorVisible();
+ }
+ else if (_selectedEdge) {
+ if (key == Key_Up) f = _selectedEdge->visibleCaller();
+ if (key == Key_Down) f = _selectedEdge->visibleCalling();
+ if (key == Key_Right) c = _selectedEdge->nextVisible();
+ if (key == Key_Left) c = _selectedEdge->priorVisible();
+ }
+
+ if (c) selected(c);
+ if (f) selected(f);
+ return;
+ }
+
+ // move canvas...
+ if (e->key() == Key_Home)
+ scrollBy(-_canvas->width(),0);
+ else if (e->key() == Key_End)
+ scrollBy(_canvas->width(),0);
+ else if (e->key() == Key_Prior)
+ scrollBy(0,-visibleHeight()/2);
+ else if (e->key() == Key_Next)
+ scrollBy(0,visibleHeight()/2);
+ else if (e->key() == Key_Left)
+ scrollBy(-visibleWidth()/10,0);
+ else if (e->key() == Key_Right)
+ scrollBy(visibleWidth()/10,0);
+ else if (e->key() == Key_Down)
+ scrollBy(0,visibleHeight()/10);
+ else if (e->key() == Key_Up)
+ scrollBy(0,-visibleHeight()/10);
+ else e->ignore();
+}
+
+void CallGraphView::resizeEvent(QResizeEvent* e)
+{
+ QCanvasView::resizeEvent(e);
+ if (_canvas) updateSizes(e->size());
+}
+
+TraceItem* CallGraphView::canShow(TraceItem* i)
+{
+ if (i) {
+ switch(i->type()) {
+ case TraceItem::Function:
+ case TraceItem::FunctionCycle:
+ case TraceItem::Call:
+ return i;
+ default:
+ break;
+ }
+ }
+ return 0;
+}
+
+void CallGraphView::doUpdate(int changeType)
+{
+ // Special case ?
+ if (changeType == costType2Changed) return;
+
+ if (changeType == selectedItemChanged) {
+ if (!_canvas) return;
+
+ if (!_selectedItem) return;
+
+ GraphNode* n = 0;
+ GraphEdge* e = 0;
+ if ((_selectedItem->type() == TraceItem::Function) ||
+ (_selectedItem->type() == TraceItem::FunctionCycle)) {
+ n = _exporter.node((TraceFunction*)_selectedItem);
+ if (n == _selectedNode) return;
+ }
+ else if (_selectedItem->type() == TraceItem::Call) {
+ TraceCall* c = (TraceCall*)_selectedItem;
+ e = _exporter.edge(c->caller(false), c->called(false));
+ if (e == _selectedEdge) return;
+ }
+
+ // unselected any selected item
+ if (_selectedNode && _selectedNode->canvasNode()) {
+ _selectedNode->canvasNode()->setSelected(false);
+ }
+ _selectedNode = 0;
+ if (_selectedEdge && _selectedEdge->canvasEdge()) {
+ _selectedEdge->canvasEdge()->setSelected(false);
+ }
+ _selectedEdge = 0;
+
+ // select
+ CanvasNode* sNode = 0;
+ if (n && n->canvasNode()) {
+ _selectedNode = n;
+ _selectedNode->canvasNode()->setSelected(true);
+
+ if (!_isMoving) sNode = _selectedNode->canvasNode();
+ }
+ if (e && e->canvasEdge()) {
+ _selectedEdge = e;
+ _selectedEdge->canvasEdge()->setSelected(true);
+
+#if 0 // don't change position when selecting edge
+ if (!_isMoving) {
+ if (_selectedEdge->fromNode())
+ sNode = _selectedEdge->fromNode()->canvasNode();
+ if (!sNode && _selectedEdge->toNode())
+ sNode = _selectedEdge->toNode()->canvasNode();
+ }
+#endif
+ }
+ if (sNode) {
+ double x = sNode->x() + sNode->width()/2;
+ double y = sNode->y() + sNode->height()/2;
+
+ ensureVisible(int(x),int(y),
+ sNode->width()/2+50, sNode->height()/2+50);
+ }
+
+ _canvas->update();
+ return;
+ }
+
+ if (changeType == groupTypeChanged) {
+ if (!_canvas) return;
+
+ if (_clusterGroups) {
+ refresh();
+ return;
+ }
+
+ QCanvasItemList l = _canvas->allItems();
+ QCanvasItemList::iterator it;
+ for (it = l.begin();it != l.end(); ++it)
+ if ((*it)->rtti() == CANVAS_NODE)
+ ((CanvasNode*) (*it))->updateGroup();
+
+ _canvas->update();
+ return;
+ }
+
+ if (changeType & dataChanged) {
+ // invalidate old selection and graph part
+ _exporter.reset(_data, _activeItem, _costType, _groupType);
+ _selectedNode = 0;
+ _selectedEdge = 0;
+ }
+
+ refresh();
+}
+
+void CallGraphView::clear()
+{
+ if (!_canvas) return;
+
+ delete _canvas;
+ _canvas = 0;
+ _completeView->setCanvas(0);
+ setCanvas(0);
+}
+
+void CallGraphView::showText(QString s)
+{
+ clear();
+ _renderTimer.stop();
+
+ _canvas = new QCanvas(QApplication::desktop()->width(),
+ QApplication::desktop()->height());
+
+ QCanvasText* t = new QCanvasText(s, _canvas);
+ t->move(5, 5);
+ t->show();
+ center(0,0);
+ setCanvas(_canvas);
+ _canvas->update();
+ _completeView->hide();
+}
+
+void CallGraphView::showRenderWarning()
+{
+ QString s;
+
+ if (_renderProcess)
+ s =i18n("Warning: a long lasting graph layouting is in progress.\n"
+ "Reduce node/edge limits for speedup.\n");
+ else
+ s = i18n("Layouting stopped.\n");
+
+ s.append(i18n("The call graph has %1 nodes and %2 edges.\n")
+ .arg(_exporter.nodeCount())
+ .arg(_exporter.edgeCount()));
+
+ showText(s);
+}
+
+void CallGraphView::stopRendering()
+{
+ if (!_renderProcess) return;
+
+ _renderProcess->kill();
+ delete _renderProcess;
+ _renderProcess = 0;
+ _unparsedOutput = QString::null;
+
+ _renderTimer.start(200, true);
+}
+
+void CallGraphView::refresh()
+{
+ // trigger start of background rendering
+ if (_renderProcess) stopRendering();
+
+ // we want to keep a selected node item at the same global position
+ _prevSelectedNode = _selectedNode;
+ _prevSelectedPos = QPoint(-1,-1);
+ if (_selectedNode) {
+ QPoint center = _selectedNode->canvasNode()->boundingRect().center();
+ _prevSelectedPos = contentsToViewport(center);
+ }
+
+ if (!_data || !_activeItem) {
+ showText(i18n("No item activated for which to draw the call graph."));
+ return;
+ }
+
+ TraceItem::CostType t = _activeItem->type();
+ switch(t) {
+ case TraceItem::Function:
+ case TraceItem::FunctionCycle:
+ case TraceItem::Call:
+ break;
+ default:
+ showText(i18n("No call graph can be drawn for the active item."));
+ return;
+ }
+
+ if (1) kdDebug() << "CallGraphView::refresh" << endl;
+
+ _selectedNode = 0;
+ _selectedEdge = 0;
+ _exporter.reset(_data, _activeItem, _costType, _groupType);
+ _exporter.writeDot();
+
+ _renderProcess = new QProcess(this);
+ if (_layout == GraphOptions::Circular)
+ _renderProcess->addArgument( "twopi" );
+ else
+ _renderProcess->addArgument( "dot" );
+ _renderProcess->addArgument(_exporter.filename());
+ _renderProcess->addArgument( "-Tplain" );
+
+ connect( _renderProcess, SIGNAL(readyReadStdout()),
+ this, SLOT(readDotOutput()) );
+ connect( _renderProcess, SIGNAL(processExited()),
+ this, SLOT(dotExited()) );
+
+ if (1) kdDebug() << "Running '"
+ << _renderProcess->arguments().join(" ")
+ << "'..." << endl;
+
+ if ( !_renderProcess->start() ) {
+ QString e = i18n("No call graph is available because the following\n"
+ "command cannot be run:\n'%1'\n")
+ .arg(_renderProcess->arguments().join(" "));
+ e += i18n("Please check that 'dot' is installed (package GraphViz).");
+ showText(e);
+
+ delete _renderProcess;
+ _renderProcess = 0;
+
+ return;
+ }
+
+ _unparsedOutput = QString::null;
+
+ // layouting of more than seconds is dubious
+ _renderTimer.start(1000, true);
+}
+
+void CallGraphView::readDotOutput()
+{
+ _unparsedOutput.append( _renderProcess->readStdout() );
+}
+
+void CallGraphView::dotExited()
+{
+ QString line, cmd;
+ CanvasNode *rItem;
+ QCanvasEllipse* eItem;
+ CanvasEdge* sItem;
+ CanvasEdgeLabel* lItem;
+ QTextStream* dotStream;
+ double scale = 1.0, scaleX = 1.0, scaleY = 1.0;
+ double dotWidth, dotHeight;
+ GraphNode* activeNode = 0;
+ GraphEdge* activeEdge = 0;
+
+ _renderTimer.stop();
+ viewport()->setUpdatesEnabled(false);
+ clear();
+ dotStream = new QTextStream(_unparsedOutput, IO_ReadOnly);
+
+ int lineno = 0;
+ while (1) {
+ line = dotStream->readLine();
+ if (line.isNull()) break;
+ lineno++;
+ if (line.isEmpty()) continue;
+
+ QTextStream lineStream(line, IO_ReadOnly);
+ lineStream >> cmd;
+
+ if (0) qDebug("%s:%d - line '%s', cmd '%s'",
+ _exporter.filename().ascii(), lineno,
+ line.ascii(), cmd.ascii());
+
+ if (cmd == "stop") break;
+
+ if (cmd == "graph") {
+ QString dotWidthString, dotHeightString;
+ lineStream >> scale >> dotWidthString >> dotHeightString;
+ dotWidth = dotWidthString.toDouble();
+ dotHeight = dotHeightString.toDouble();
+
+ if (_detailLevel == 0) { scaleX = scale * 70; scaleY = scale * 40; }
+ else if (_detailLevel == 1) { scaleX = scale * 80; scaleY = scale * 70; }
+ else { scaleX = scale * 60; scaleY = scale * 100; }
+
+ if (!_canvas) {
+ int w = (int)(scaleX * dotWidth);
+ int h = (int)(scaleY * dotHeight);
+
+ // We use as minimum canvas size the desktop size.
+ // Otherwise, the canvas would have to be resized on widget resize.
+ _xMargin = 50;
+ if (w < QApplication::desktop()->width())
+ _xMargin += (QApplication::desktop()->width()-w)/2;
+
+ _yMargin = 50;
+ if (h < QApplication::desktop()->height())
+ _yMargin += (QApplication::desktop()->height()-h)/2;
+
+ _canvas = new QCanvas(int(w+2*_xMargin), int(h+2*_yMargin));
+
+#if DEBUG_GRAPH
+ kdDebug() << _exporter.filename().ascii() << ":" << lineno
+ << " - graph (" << dotWidth << " x " << dotHeight
+ << ") => (" << w << " x " << h << ")" << endl;
+#endif
+ }
+ else
+ kdWarning() << "Ignoring 2nd 'graph' from dot ("
+ << _exporter.filename() << ":" << lineno << ")" << endl;
+ continue;
+ }
+
+ if ((cmd != "node") && (cmd != "edge")) {
+ kdWarning() << "Ignoring unknown command '" << cmd << "' from dot ("
+ << _exporter.filename() << ":" << lineno << ")" << endl;
+ continue;
+ }
+
+ if (_canvas == 0) {
+ kdWarning() << "Ignoring '" << cmd << "' without 'graph' from dot ("
+ << _exporter.filename() << ":" << lineno << ")" << endl;
+ continue;
+ }
+
+ if (cmd == "node") {
+ // x, y are centered in node
+ QString nodeName, label, nodeX, nodeY, nodeWidth, nodeHeight;
+ double x, y, width, height;
+ lineStream >> nodeName >> nodeX >> nodeY >> nodeWidth >> nodeHeight;
+ x = nodeX.toDouble();
+ y = nodeY.toDouble();
+ width = nodeWidth.toDouble();
+ height = nodeHeight.toDouble();
+
+ GraphNode* n = _exporter.node(_exporter.toFunc(nodeName));
+
+ int xx = (int)(scaleX * x + _xMargin);
+ int yy = (int)(scaleY * (dotHeight - y) + _yMargin);
+ int w = (int)(scaleX * width);
+ int h = (int)(scaleY * height);
+
+#if DEBUG_GRAPH
+ kdDebug() << _exporter.filename() << ":" << lineno
+ << " - node '" << nodeName << "' ( "
+ << x << "/" << y << " - "
+ << width << "x" << height << " ) => ("
+ << xx-w/2 << "/" << yy-h/2 << " - "
+ << w << "x" << h << ")" << endl;
+#endif
+
+
+ // Unnamed nodes with collapsed edges (with 'R' and 'S')
+ if (nodeName[0] == 'R' || nodeName[0] == 'S') {
+ w = 10, h = 10;
+ eItem = new QCanvasEllipse(w, h, _canvas);
+ eItem->move(xx, yy);
+ eItem->setBrush(Qt::gray);
+ eItem->setZ(1.0);
+ eItem->show();
+ continue;
+ }
+
+ if (!n) {
+ qDebug("Warning: Unknown function '%s' ?!", nodeName.ascii());
+ continue;
+ }
+ n->setVisible(true);
+
+ rItem = new CanvasNode(this, n, xx-w/2, yy-h/2, w, h, _canvas);
+ n->setCanvasNode(rItem);
+
+ if (n) {
+ if (n->function() == activeItem()) activeNode = n;
+ if (n->function() == selectedItem()) _selectedNode = n;
+ rItem->setSelected(n == _selectedNode);
+ }
+
+ rItem->setZ(1.0);
+ rItem->show();
+
+ continue;
+ }
+
+ // edge
+
+ QString node1Name, node2Name, label, edgeX, edgeY;
+ double x, y;
+ QPointArray pa;
+ int points, i;
+ lineStream >> node1Name >> node2Name >> points;
+
+ GraphEdge* e = _exporter.edge(_exporter.toFunc(node1Name),
+ _exporter.toFunc(node2Name));
+ if (!e) {
+ kdWarning() << "Unknown edge '" << node1Name << "'-'"
+ << node2Name << "' from dot ("
+ << _exporter.filename() << ":" << lineno << ")" << endl;
+ continue;
+ }
+ e->setVisible(true);
+ if (e->fromNode()) e->fromNode()->callings.append(e);
+ if (e->toNode()) e->toNode()->callers.append(e);
+
+ if (0) qDebug(" Edge with %d points:", points);
+
+ pa.resize(points);
+ for (i=0;i<points;i++) {
+ if (lineStream.atEnd()) break;
+ lineStream >> edgeX >> edgeY;
+ x = edgeX.toDouble();
+ y = edgeY.toDouble();
+
+ int xx = (int)(scaleX * x + _xMargin);
+ int yy = (int)(scaleY * (dotHeight - y) + _yMargin);
+
+ if (0) qDebug(" P %d: ( %f / %f ) => ( %d / %d)",
+ i, x, y, xx, yy);
+
+ pa.setPoint(i, xx, yy);
+ }
+ if (i < points) {
+ qDebug("CallGraphView: Can't read %d spline points (%s:%d)",
+ points, _exporter.filename().ascii(), lineno);
+ continue;
+ }
+
+ // calls into/out of cycles are special: make them blue
+ QColor arrowColor = Qt::black;
+ TraceFunction* caller = e->fromNode() ? e->fromNode()->function() : 0;
+ TraceFunction* called = e->toNode() ? e->toNode()->function() : 0;
+ if ( (caller && (caller->cycle() == caller)) ||
+ (called && (called->cycle() == called)) ) arrowColor = Qt::blue;
+
+ sItem = new CanvasEdge(e, _canvas);
+ e->setCanvasEdge(sItem);
+ sItem->setControlPoints(pa, false);
+ sItem->setPen(QPen(arrowColor, 1 /*(int)log(log(e->cost))*/ ));
+ sItem->setZ(0.5);
+ sItem->show();
+
+ if (e->call() == selectedItem()) _selectedEdge = e;
+ if (e->call() == activeItem()) activeEdge = e;
+ sItem->setSelected(e == _selectedEdge);
+
+ // Arrow head
+ QPoint arrowDir;
+ int indexHead = -1;
+
+ // check if head is at start of spline...
+ // this is needed because dot always gives points from top to bottom
+ CanvasNode* fromNode = e->fromNode() ? e->fromNode()->canvasNode() : 0;
+ if (fromNode) {
+ QPoint toCenter = fromNode->rect().center();
+ int dx0 = pa.point(0).x() - toCenter.x();
+ int dy0 = pa.point(0).y() - toCenter.y();
+ int dx1 = pa.point(points-1).x() - toCenter.x();
+ int dy1 = pa.point(points-1).y() - toCenter.y();
+ if (dx0*dx0+dy0*dy0 > dx1*dx1+dy1*dy1) {
+ // start of spline is nearer to call target node
+ indexHead=-1;
+ while(arrowDir.isNull() && (indexHead<points-2)) {
+ indexHead++;
+ arrowDir = pa.point(indexHead) - pa.point(indexHead+1);
+ }
+ }
+ }
+
+ if (arrowDir.isNull()) {
+ indexHead = points;
+ // sometimes the last spline points from dot are the same...
+ while(arrowDir.isNull() && (indexHead>1)) {
+ indexHead--;
+ arrowDir = pa.point(indexHead) - pa.point(indexHead-1);
+ }
+ }
+
+ if (!arrowDir.isNull()) {
+ // arrow around pa.point(indexHead) with direction arrowDir
+ arrowDir *= 10.0/sqrt(double(arrowDir.x()*arrowDir.x() +
+ arrowDir.y()*arrowDir.y()));
+ QPointArray a(3);
+ a.setPoint(0, pa.point(indexHead) + arrowDir);
+ a.setPoint(1, pa.point(indexHead) + QPoint(arrowDir.y()/2,
+ -arrowDir.x()/2));
+ a.setPoint(2, pa.point(indexHead) + QPoint(-arrowDir.y()/2,
+ arrowDir.x()/2));
+
+ if (0) qDebug(" Arrow: ( %d/%d, %d/%d, %d/%d)",
+ a.point(0).x(), a.point(0).y(),
+ a.point(1).x(), a.point(1).y(),
+ a.point(2).x(), a.point(2).y());
+
+ CanvasEdgeArrow* aItem = new CanvasEdgeArrow(sItem,_canvas);
+ aItem->setPoints(a);
+ aItem->setBrush(arrowColor);
+ aItem->setZ(1.5);
+ aItem->show();
+
+ sItem->setArrow(aItem);
+ }
+
+ if (lineStream.atEnd()) continue;
+
+ // parse quoted label
+ QChar c;
+ lineStream >> c;
+ while (c.isSpace()) lineStream >> c;
+ if (c != '\"') {
+ lineStream >> label;
+ label = c + label;
+ }
+ else {
+ lineStream >> c;
+ while(!c.isNull() && (c != '\"')) {
+ //if (c == '\\') lineStream >> c;
+
+ label += c;
+ lineStream >> c;
+ }
+ }
+ lineStream >> edgeX >> edgeY;
+ x = edgeX.toDouble();
+ y = edgeY.toDouble();
+
+ int xx = (int)(scaleX * x + _xMargin);
+ int yy = (int)(scaleY * (dotHeight - y) + _yMargin);
+
+ if (0) qDebug(" Label '%s': ( %f / %f ) => ( %d / %d)",
+ label.ascii(), x, y, xx, yy);
+
+ // Fixed Dimensions for Label: 100 x 40
+ int w = 100;
+ int h = _detailLevel * 20;
+ lItem = new CanvasEdgeLabel(this, sItem, xx-w/2, yy-h/2, w, h, _canvas);
+ // edge labels above nodes
+ lItem->setZ(1.5);
+ sItem->setLabel(lItem);
+ if (h>0) lItem->show();
+
+ }
+ delete dotStream;
+
+ // for keyboard navigation
+ // TODO: Edge sorting. Better keep left-to-right edge order from dot now
+ // _exporter.sortEdges();
+
+ if (!_canvas) {
+ _canvas = new QCanvas(size().width(),size().height());
+ QString s = i18n("Error running the graph layouting tool.\n");
+ s += i18n("Please check that 'dot' is installed (package GraphViz).");
+ QCanvasText* t = new QCanvasText(s, _canvas);
+ t->move(5, 5);
+ t->show();
+ center(0,0);
+ }
+ else if (!activeNode && !activeEdge) {
+ QString s = i18n("There is no call graph available for function\n"
+ "\t'%1'\n"
+ "because it has no cost of the selected event type.");
+ QCanvasText* t = new QCanvasText(s.arg(_activeItem->name()), _canvas);
+ // t->setTextFlags(Qt::AlignHCenter | Qt::AlignVCenter);
+ t->move(5,5);
+ t->show();
+ center(0,0);
+ }
+
+ _completeView->setCanvas(_canvas);
+ setCanvas(_canvas);
+
+ // if we don't have a selection, or the old selection is not
+ // in visible graph, make active function selected for this view
+ if ((!_selectedNode || !_selectedNode->canvasNode()) &&
+ (!_selectedEdge || !_selectedEdge->canvasEdge())) {
+ if (activeNode) {
+ _selectedNode = activeNode;
+ _selectedNode->canvasNode()->setSelected(true);
+ }
+ else if (activeEdge) {
+ _selectedEdge = activeEdge;
+ _selectedEdge->canvasEdge()->setSelected(true);
+ }
+ }
+
+ CanvasNode* sNode = 0;
+ if (_selectedNode)
+ sNode = _selectedNode->canvasNode();
+ else if (_selectedEdge) {
+ if (_selectedEdge->fromNode())
+ sNode = _selectedEdge->fromNode()->canvasNode();
+ if (!sNode && _selectedEdge->toNode())
+ sNode = _selectedEdge->toNode()->canvasNode();
+ }
+ if (sNode) {
+ int x = int(sNode->x() + sNode->width()/2);
+ int y = int(sNode->y() + sNode->height()/2);
+
+ if (_prevSelectedNode) {
+ if (rect().contains(_prevSelectedPos))
+ setContentsPos(x-_prevSelectedPos.x(),
+ y-_prevSelectedPos.y());
+ else
+ ensureVisible(x,y,
+ sNode->width()/2+50, sNode->height()/2+50);
+ }
+ else center(x,y);
+ }
+
+ if (activeNode) {
+ CanvasNode* cn = activeNode->canvasNode();
+ CanvasFrame* f = new CanvasFrame(cn, _canvas);
+ f->setZ(-1);
+ f->show();
+ }
+
+ _cvZoom = 0;
+ updateSizes();
+
+ _canvas->update();
+ viewport()->setUpdatesEnabled(true);
+
+ delete _renderProcess;
+ _renderProcess = 0;
+}
+
+void CallGraphView::contentsMovingSlot(int x, int y)
+{
+ QRect z(int(x * _cvZoom), int(y * _cvZoom),
+ int(visibleWidth() * _cvZoom)-1, int(visibleHeight() * _cvZoom)-1);
+ if (0) qDebug("moving: (%d,%d) => (%d/%d - %dx%d)",
+ x, y, z.x(), z.y(), z.width(), z.height());
+ _completeView->setZoomRect(z);
+}
+
+void CallGraphView::zoomRectMoved(int dx, int dy)
+{
+ if (leftMargin()>0) dx = 0;
+ if (topMargin()>0) dy = 0;
+ scrollBy(int(dx/_cvZoom),int(dy/_cvZoom));
+}
+
+void CallGraphView::zoomRectMoveFinished()
+{
+ if (_zoomPosition == Auto) updateSizes();
+}
+
+void CallGraphView::contentsMousePressEvent(QMouseEvent* e)
+{
+ // clicking on the viewport sets focus
+ setFocus();
+
+ _isMoving = true;
+
+ QCanvasItemList l = canvas()->collisions(e->pos());
+ if (l.count()>0) {
+ QCanvasItem* i = l.first();
+
+ if (i->rtti() == CANVAS_NODE) {
+ GraphNode* n = ((CanvasNode*)i)->node();
+ if (0) qDebug("CallGraphView: Got Node '%s'",
+ n->function()->prettyName().ascii());
+
+ selected(n->function());
+ }
+
+ // redirect from label / arrow to edge
+ if (i->rtti() == CANVAS_EDGELABEL)
+ i = ((CanvasEdgeLabel*)i)->canvasEdge();
+ if (i->rtti() == CANVAS_EDGEARROW)
+ i = ((CanvasEdgeArrow*)i)->canvasEdge();
+
+ if (i->rtti() == CANVAS_EDGE) {
+ GraphEdge* e = ((CanvasEdge*)i)->edge();
+ if (0) qDebug("CallGraphView: Got Edge '%s'",
+ e->prettyName().ascii());
+
+ if (e->call()) selected(e->call());
+ }
+ }
+ _lastPos = e->globalPos();
+}
+
+void CallGraphView::contentsMouseMoveEvent(QMouseEvent* e)
+{
+ if (_isMoving) {
+ int dx = e->globalPos().x() - _lastPos.x();
+ int dy = e->globalPos().y() - _lastPos.y();
+ scrollBy(-dx, -dy);
+ _lastPos = e->globalPos();
+ }
+}
+
+void CallGraphView::contentsMouseReleaseEvent(QMouseEvent*)
+{
+ _isMoving = false;
+ if (_zoomPosition == Auto) updateSizes();
+}
+
+void CallGraphView::contentsMouseDoubleClickEvent(QMouseEvent* e)
+{
+ QCanvasItemList l = canvas()->collisions(e->pos());
+ if (l.count() == 0) return;
+ QCanvasItem* i = l.first();
+
+ if (i->rtti() == CANVAS_NODE) {
+ GraphNode* n = ((CanvasNode*)i)->node();
+ if (0) qDebug("CallGraphView: Double Clicked on Node '%s'",
+ n->function()->prettyName().ascii());
+
+ activated(n->function());
+ }
+
+ // redirect from label / arrow to edge
+ if (i->rtti() == CANVAS_EDGELABEL)
+ i = ((CanvasEdgeLabel*)i)->canvasEdge();
+ if (i->rtti() == CANVAS_EDGEARROW)
+ i = ((CanvasEdgeArrow*)i)->canvasEdge();
+
+ if (i->rtti() == CANVAS_EDGE) {
+ GraphEdge* e = ((CanvasEdge*)i)->edge();
+ if (e->call()) {
+ if (0) qDebug("CallGraphView: Double Clicked On Edge '%s'",
+ e->call()->prettyName().ascii());
+
+ activated(e->call());
+ }
+ }
+}
+
+void CallGraphView::contentsContextMenuEvent(QContextMenuEvent* e)
+{
+ QCanvasItemList l = canvas()->collisions(e->pos());
+ QCanvasItem* i = (l.count() == 0) ? 0 : l.first();
+
+ QPopupMenu popup;
+ TraceFunction *f = 0, *cycle = 0;
+ TraceCall* c = 0;
+
+ if (i) {
+ if (i->rtti() == CANVAS_NODE) {
+ GraphNode* n = ((CanvasNode*)i)->node();
+ if (0) qDebug("CallGraphView: Menu on Node '%s'",
+ n->function()->prettyName().ascii());
+ f = n->function();
+ cycle = f->cycle();
+
+ QString name = f->prettyName();
+ popup.insertItem(i18n("Go to '%1'")
+ .arg(Configuration::shortenSymbol(name)), 93);
+ if (cycle && (cycle != f)) {
+ name = Configuration::shortenSymbol(cycle->prettyName());
+ popup.insertItem(i18n("Go to '%1'").arg(name), 94);
+ }
+ popup.insertSeparator();
+ }
+
+ // redirect from label / arrow to edge
+ if (i->rtti() == CANVAS_EDGELABEL)
+ i = ((CanvasEdgeLabel*)i)->canvasEdge();
+ if (i->rtti() == CANVAS_EDGEARROW)
+ i = ((CanvasEdgeArrow*)i)->canvasEdge();
+
+ if (i->rtti() == CANVAS_EDGE) {
+ GraphEdge* e = ((CanvasEdge*)i)->edge();
+ if (0) qDebug("CallGraphView: Menu on Edge '%s'",
+ e->prettyName().ascii());
+ c = e->call();
+ if (c) {
+ QString name = c->prettyName();
+ popup.insertItem(i18n("Go to '%1'")
+ .arg(Configuration::shortenSymbol(name)), 95);
+
+ popup.insertSeparator();
+ }
+ }
+ }
+
+ if (_renderProcess) {
+ popup.insertItem(i18n("Stop Layouting"), 999);
+ popup.insertSeparator();
+ }
+
+ addGoMenu(&popup);
+ popup.insertSeparator();
+
+ QPopupMenu epopup;
+ epopup.insertItem(i18n("As PostScript"), 201);
+ epopup.insertItem(i18n("As Image ..."), 202);
+
+ popup.insertItem(i18n("Export Graph"), &epopup, 200);
+ popup.insertSeparator();
+
+ QPopupMenu gpopup1;
+ gpopup1.setCheckable(true);
+ gpopup1.insertItem(i18n("Unlimited"), 100);
+ gpopup1.setItemEnabled(100, (_funcLimit>0.005));
+ gpopup1.insertSeparator();
+ gpopup1.insertItem(i18n("None"), 101);
+ gpopup1.insertItem(i18n("max. 2"), 102);
+ gpopup1.insertItem(i18n("max. 5"), 103);
+ gpopup1.insertItem(i18n("max. 10"), 104);
+ gpopup1.insertItem(i18n("max. 15"), 105);
+ if (_maxCallerDepth<-1) _maxCallerDepth=-1;
+ switch(_maxCallerDepth) {
+ case -1: gpopup1.setItemChecked(100,true); break;
+ case 0: gpopup1.setItemChecked(101,true); break;
+ case 2: gpopup1.setItemChecked(102,true); break;
+ case 5: gpopup1.setItemChecked(103,true); break;
+ case 10: gpopup1.setItemChecked(104,true); break;
+ case 15: gpopup1.setItemChecked(105,true); break;
+ default:
+ gpopup1.insertItem(i18n("< %1").arg(_maxCallerDepth), 106);
+ gpopup1.setItemChecked(106,true); break;
+ }
+
+ QPopupMenu gpopup2;
+ gpopup2.setCheckable(true);
+ gpopup2.insertItem(i18n("Unlimited"), 110);
+ gpopup2.setItemEnabled(110, (_funcLimit>0.005));
+ gpopup2.insertSeparator();
+ gpopup2.insertItem(i18n("None"), 111);
+ gpopup2.insertItem(i18n("max. 2"), 112);
+ gpopup2.insertItem(i18n("max. 5"), 113);
+ gpopup2.insertItem(i18n("max. 10"), 114);
+ gpopup2.insertItem(i18n("max. 15"), 115);
+ if (_maxCallingDepth<-1) _maxCallingDepth=-1;
+ switch(_maxCallingDepth) {
+ case -1: gpopup2.setItemChecked(110,true); break;
+ case 0: gpopup2.setItemChecked(111,true); break;
+ case 2: gpopup2.setItemChecked(112,true); break;
+ case 5: gpopup2.setItemChecked(113,true); break;
+ case 10: gpopup2.setItemChecked(114,true); break;
+ case 15: gpopup2.setItemChecked(115,true); break;
+ default:
+ gpopup2.insertItem(i18n("< %1").arg(_maxCallingDepth), 116);
+ gpopup2.setItemChecked(116,true); break;
+ }
+
+ QPopupMenu gpopup3;
+ gpopup3.setCheckable(true);
+ gpopup3.insertItem(i18n("No Minimum"), 120);
+ gpopup3.setItemEnabled(120,
+ (_maxCallerDepth>=0) && (_maxCallingDepth>=0));
+ gpopup3.insertSeparator();
+ gpopup3.insertItem(i18n("50 %"), 121);
+ gpopup3.insertItem(i18n("20 %"), 122);
+ gpopup3.insertItem(i18n("10 %"), 123);
+ gpopup3.insertItem(i18n("5 %"), 124);
+ gpopup3.insertItem(i18n("3 %"), 125);
+ gpopup3.insertItem(i18n("2 %"), 126);
+ gpopup3.insertItem(i18n("1.5 %"), 127);
+ gpopup3.insertItem(i18n("1 %"), 128);
+ if (_funcLimit<0) _funcLimit = DEFAULT_FUNCLIMIT;
+ if (_funcLimit>.5) _funcLimit = .5;
+ if (_funcLimit == 0.0) gpopup3.setItemChecked(120,true);
+ else if (_funcLimit >= 0.5) gpopup3.setItemChecked(121,true);
+ else if (_funcLimit >= 0.2) gpopup3.setItemChecked(122,true);
+ else if (_funcLimit >= 0.1) gpopup3.setItemChecked(123,true);
+ else if (_funcLimit >= 0.05) gpopup3.setItemChecked(124,true);
+ else if (_funcLimit >= 0.03) gpopup3.setItemChecked(125,true);
+ else if (_funcLimit >= 0.02) gpopup3.setItemChecked(126,true);
+ else if (_funcLimit >= 0.015) gpopup3.setItemChecked(127,true);
+ else gpopup3.setItemChecked(128,true);
+ double oldFuncLimit = _funcLimit;
+
+ QPopupMenu gpopup4;
+ gpopup4.setCheckable(true);
+ gpopup4.insertItem(i18n("Same as Node"), 160);
+ gpopup4.insertItem(i18n("50 % of Node"), 161);
+ gpopup4.insertItem(i18n("20 % of Node"), 162);
+ gpopup4.insertItem(i18n("10 % of Node"), 163);
+ if (_callLimit<0) _callLimit = DEFAULT_CALLLIMIT;
+ if (_callLimit >= _funcLimit) _callLimit = _funcLimit;
+ if (_callLimit == _funcLimit) gpopup4.setItemChecked(160,true);
+ else if (_callLimit >= 0.5 * _funcLimit) gpopup4.setItemChecked(161,true);
+ else if (_callLimit >= 0.2 * _funcLimit) gpopup4.setItemChecked(162,true);
+ else gpopup4.setItemChecked(163,true);
+
+ QPopupMenu gpopup;
+ gpopup.setCheckable(true);
+ gpopup.insertItem(i18n("Caller Depth"), &gpopup1, 80);
+ gpopup.insertItem(i18n("Callee Depth"), &gpopup2, 81);
+ gpopup.insertItem(i18n("Min. Node Cost"), &gpopup3, 82);
+ gpopup.insertItem(i18n("Min. Call Cost"), &gpopup4, 83);
+ gpopup.insertSeparator();
+ gpopup.insertItem(i18n("Arrows for Skipped Calls"), 130);
+ gpopup.setItemChecked(130,_showSkipped);
+ gpopup.insertItem(i18n("Inner-cycle Calls"), 131);
+ gpopup.setItemChecked(131,_expandCycles);
+ gpopup.insertItem(i18n("Cluster Groups"), 132);
+ gpopup.setItemChecked(132,_clusterGroups);
+
+ QPopupMenu vpopup;
+ vpopup.setCheckable(true);
+ vpopup.insertItem(i18n("Compact"), 140);
+ vpopup.insertItem(i18n("Normal"), 141);
+ vpopup.insertItem(i18n("Tall"), 142);
+ vpopup.setItemChecked(140,_detailLevel == 0);
+ vpopup.setItemChecked(141,_detailLevel == 1);
+ vpopup.setItemChecked(142,_detailLevel == 2);
+ vpopup.insertSeparator();
+ vpopup.insertItem(i18n("Top to Down"), 150);
+ vpopup.insertItem(i18n("Left to Right"), 151);
+ vpopup.insertItem(i18n("Circular"), 152);
+ vpopup.setItemChecked(150,_layout == TopDown);
+ vpopup.setItemChecked(151,_layout == LeftRight);
+ vpopup.setItemChecked(152,_layout == Circular);
+
+ QPopupMenu opopup;
+ opopup.insertItem(i18n("TopLeft"), 170);
+ opopup.insertItem(i18n("TopRight"), 171);
+ opopup.insertItem(i18n("BottomLeft"), 172);
+ opopup.insertItem(i18n("BottomRight"), 173);
+ opopup.insertItem(i18n("Automatic"), 174);
+ opopup.setItemChecked(170,_zoomPosition == TopLeft);
+ opopup.setItemChecked(171,_zoomPosition == TopRight);
+ opopup.setItemChecked(172,_zoomPosition == BottomLeft);
+ opopup.setItemChecked(173,_zoomPosition == BottomRight);
+ opopup.setItemChecked(174,_zoomPosition == Auto);
+
+ popup.insertItem(i18n("Graph"), &gpopup, 70);
+ popup.insertItem(i18n("Visualization"), &vpopup, 71);
+ popup.insertItem(i18n("Birds-eye View"), &opopup, 72);
+
+ int r = popup.exec(e->globalPos());
+
+ switch(r) {
+ case 93: activated(f); break;
+ case 94: activated(cycle); break;
+ case 95: activated(c); break;
+
+ case 999: stopRendering(); break;
+
+ case 201:
+ {
+ TraceFunction* f = activeFunction();
+ if (!f) break;
+
+ GraphExporter ge(data(), f, costType(), groupType(),
+ QString("callgraph.dot"));
+ ge.setGraphOptions(this);
+ ge.writeDot();
+
+ system("(dot callgraph.dot -Tps > callgraph.ps; kghostview callgraph.ps)&");
+ }
+ break;
+
+ case 202:
+ // write current content of canvas as image to file
+ {
+ if (!_canvas) return;
+
+ QString fn = KFileDialog::getSaveFileName(":","*.png");
+
+ if (!fn.isEmpty()) {
+ QPixmap pix(_canvas->size());
+ QPainter p(&pix);
+ _canvas->drawArea( _canvas->rect(), &p );
+ pix.save(fn,"PNG");
+ }
+ }
+ break;
+
+ case 100: _maxCallerDepth = -1; break;
+ case 101: _maxCallerDepth = 0; break;
+ case 102: _maxCallerDepth = 2; break;
+ case 103: _maxCallerDepth = 5; break;
+ case 104: _maxCallerDepth = 10; break;
+ case 105: _maxCallerDepth = 15; break;
+
+ case 110: _maxCallingDepth = -1; break;
+ case 111: _maxCallingDepth = 0; break;
+ case 112: _maxCallingDepth = 2; break;
+ case 113: _maxCallingDepth = 5; break;
+ case 114: _maxCallingDepth = 10; break;
+ case 115: _maxCallingDepth = 15; break;
+
+ case 120: _funcLimit = 0; break;
+ case 121: _funcLimit = 0.5; break;
+ case 122: _funcLimit = 0.2; break;
+ case 123: _funcLimit = 0.1; break;
+ case 124: _funcLimit = 0.05; break;
+ case 125: _funcLimit = 0.03; break;
+ case 126: _funcLimit = 0.02; break;
+ case 127: _funcLimit = 0.015; break;
+ case 128: _funcLimit = 0.01; break;
+
+ case 130: _showSkipped = !_showSkipped; break;
+ case 131: _expandCycles = !_expandCycles; break;
+ case 132: _clusterGroups = !_clusterGroups; break;
+
+ case 140: _detailLevel = 0; break;
+ case 141: _detailLevel = 1; break;
+ case 142: _detailLevel = 2; break;
+
+ case 150: _layout = TopDown; break;
+ case 151: _layout = LeftRight; break;
+ case 152: _layout = Circular; break;
+
+ case 160: _callLimit = _funcLimit; break;
+ case 161: _callLimit = .5 * _funcLimit; break;
+ case 162: _callLimit = .2 * _funcLimit; break;
+ case 163: _callLimit = .1 * _funcLimit; break;
+
+ case 170: _zoomPosition = TopLeft; break;
+ case 171: _zoomPosition = TopRight; break;
+ case 172: _zoomPosition = BottomLeft; break;
+ case 173: _zoomPosition = BottomRight; break;
+ case 174: _zoomPosition = Auto; break;
+
+ default: break;
+ }
+ if (r>=120 && r<130) _callLimit *= _funcLimit / oldFuncLimit;
+
+ if (r>99 && r<170) refresh();
+ if (r>169 && r<180) updateSizes();
+}
+
+CallGraphView::ZoomPosition CallGraphView::zoomPos(QString s)
+{
+ if (s == QString("TopLeft")) return TopLeft;
+ if (s == QString("TopRight")) return TopRight;
+ if (s == QString("BottomLeft")) return BottomLeft;
+ if (s == QString("BottomRight")) return BottomRight;
+ if (s == QString("Automatic")) return Auto;
+
+ return DEFAULT_ZOOMPOS;
+}
+
+QString CallGraphView::zoomPosString(ZoomPosition p)
+{
+ if (p == TopRight) return QString("TopRight");
+ if (p == BottomLeft) return QString("BottomLeft");
+ if (p == BottomRight) return QString("BottomRight");
+ if (p == Auto) return QString("Automatic");
+
+ return QString("TopLeft");
+}
+
+void CallGraphView::readViewConfig(KConfig* c,
+ QString prefix, QString postfix, bool)
+{
+ KConfigGroup* g = configGroup(c, prefix, postfix);
+
+ if (0) qDebug("CallGraphView::readViewConfig");
+
+ _maxCallerDepth = g->readNumEntry("MaxCaller", DEFAULT_MAXCALLER);
+ _maxCallingDepth = g->readNumEntry("MaxCalling", DEFAULT_MAXCALLING);
+ _funcLimit = g->readDoubleNumEntry("FuncLimit", DEFAULT_FUNCLIMIT);
+ _callLimit = g->readDoubleNumEntry("CallLimit", DEFAULT_CALLLIMIT);
+ _showSkipped = g->readBoolEntry("ShowSkipped", DEFAULT_SHOWSKIPPED);
+ _expandCycles = g->readBoolEntry("ExpandCycles", DEFAULT_EXPANDCYCLES);
+ _clusterGroups = g->readBoolEntry("ClusterGroups",
+ DEFAULT_CLUSTERGROUPS);
+ _detailLevel = g->readNumEntry("DetailLevel", DEFAULT_DETAILLEVEL);
+ _layout = GraphOptions::layout(g->readEntry("Layout",
+ layoutString(DEFAULT_LAYOUT)));
+ _zoomPosition = zoomPos(g->readEntry("ZoomPosition",
+ zoomPosString(DEFAULT_ZOOMPOS)));
+
+ delete g;
+}
+
+void CallGraphView::saveViewConfig(KConfig* c,
+ QString prefix, QString postfix, bool)
+{
+ KConfigGroup g(c, (prefix+postfix).ascii());
+
+ writeConfigEntry(&g, "MaxCaller", _maxCallerDepth, DEFAULT_MAXCALLER);
+ writeConfigEntry(&g, "MaxCalling", _maxCallingDepth, DEFAULT_MAXCALLING);
+ writeConfigEntry(&g, "FuncLimit", _funcLimit, DEFAULT_FUNCLIMIT);
+ writeConfigEntry(&g, "CallLimit", _callLimit, DEFAULT_CALLLIMIT);
+ writeConfigEntry(&g, "ShowSkipped", _showSkipped, DEFAULT_SHOWSKIPPED);
+ writeConfigEntry(&g, "ExpandCycles", _expandCycles, DEFAULT_EXPANDCYCLES);
+ writeConfigEntry(&g, "ClusterGroups", _clusterGroups,
+ DEFAULT_CLUSTERGROUPS);
+ writeConfigEntry(&g, "DetailLevel", _detailLevel, DEFAULT_DETAILLEVEL);
+ writeConfigEntry(&g, "Layout",
+ layoutString(_layout), layoutString(DEFAULT_LAYOUT).utf8().data());
+ writeConfigEntry(&g, "ZoomPosition",
+ zoomPosString(_zoomPosition),
+ zoomPosString(DEFAULT_ZOOMPOS).utf8().data());
+}
+
+#include "callgraphview.moc"
+
diff --git a/kcachegrind/kcachegrind/callgraphview.h b/kcachegrind/kcachegrind/callgraphview.h
new file mode 100644
index 00000000..af861d41
--- /dev/null
+++ b/kcachegrind/kcachegrind/callgraphview.h
@@ -0,0 +1,499 @@
+/* This file is part of KCachegrind.
+ Copyright (C) 2003 Josef Weidendorfer <Josef.Weidendorfer@gmx.de>
+
+ KCachegrind is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public
+ License as published by the Free Software Foundation, version 2.
+
+ 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; see the file COPYING. If not, write to
+ the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+*/
+
+/*
+ * Callgraph View
+ */
+
+#ifndef CALLGRAPHVIEW_H
+#define CALLGRAPHVIEW_H
+
+#include <qcanvas.h>
+#include <qwidget.h>
+#include <qmap.h>
+#include <qtimer.h>
+
+#include "treemap.h" // for DrawParams
+#include "tracedata.h"
+#include "traceitemview.h"
+
+class QProcess;
+
+class KTempFile;
+class CanvasNode;
+class CanvasEdge;
+class GraphEdge;
+class CallGraphView;
+
+// sorts according start/end position of a call arc
+// this depends on attached CanvasEdge's !
+class GraphEdgeList: public QPtrList<GraphEdge>
+{
+ public:
+ GraphEdgeList();
+ void setSortCallerPos(bool b) { _sortCallerPos = b; }
+
+ protected:
+ int compareItems ( Item item1, Item item2 );
+
+ private:
+ bool _sortCallerPos;
+};
+
+
+typedef QMap<GraphEdge*, int> GraphEdgeSet;
+
+// temporary parts of call graph to be shown
+class GraphNode
+{
+public:
+ GraphNode();
+
+ TraceFunction* function() { return _f; }
+ void setFunction(TraceFunction* f) { _f = f; }
+
+ CanvasNode* canvasNode() { return _cn; }
+ void setCanvasNode(CanvasNode* cn) { _cn = cn; }
+
+ bool isVisible() { return _visible; }
+ void setVisible(bool v) { _visible = v; }
+
+ // keyboard navigation
+ TraceCall* visibleCaller();
+ TraceCall* visibleCalling();
+ void setCalling(GraphEdge*);
+ void setCaller(GraphEdge*);
+ TraceFunction* nextVisible();
+ TraceFunction* priorVisible();
+ TraceCall* nextVisibleCaller(GraphEdge*);
+ TraceCall* nextVisibleCalling(GraphEdge*);
+ TraceCall* priorVisibleCaller(GraphEdge*);
+ TraceCall* priorVisibleCalling(GraphEdge*);
+
+ double self, incl;
+ GraphEdgeList callers, callings;
+ // for fast unique insertion of GraphEdges in above lists
+ GraphEdgeSet callerSet, callingSet;
+
+ private:
+ TraceFunction* _f;
+ CanvasNode* _cn;
+ bool _visible;
+
+ // for keyboard navigation
+ int _lastCallerIndex, _lastCallingIndex;
+ bool _lastFromCaller;
+};
+
+class GraphEdge
+{
+public:
+ GraphEdge();
+
+ CanvasEdge* canvasEdge() { return _ce; }
+ void setCanvasEdge(CanvasEdge* ce) { _ce = ce; }
+
+ TraceCall* call() { return _c; }
+ void setCall(TraceCall* c) { _c = c; }
+
+ bool isVisible() { return _visible; }
+ void setVisible(bool v) { _visible = v; }
+
+ GraphNode* fromNode() { return _fromNode; }
+ GraphNode* toNode() { return _toNode; }
+ TraceFunction* from() { return _from; }
+ TraceFunction* to() { return _to; }
+
+ // has special cases for collapsed edges
+ QString prettyName();
+
+ void setCaller(TraceFunction* f) { _from = f; }
+ void setCalling(TraceFunction* f) { _to = f; }
+ void setCallerNode(GraphNode* n) { _fromNode = n; }
+ void setCallingNode(GraphNode* n) { _toNode = n; }
+
+ // keyboard navigation
+ TraceFunction* visibleCaller();
+ TraceFunction* visibleCalling();
+ TraceCall* nextVisible();
+ TraceCall* priorVisible();
+
+ double cost, count;
+
+ private:
+ // we have a _c *and* _from/_to because for collapsed edges,
+ // only _to or _from will be unequal NULL
+ TraceCall* _c;
+ TraceFunction * _from, * _to;
+ GraphNode *_fromNode, *_toNode;
+ CanvasEdge* _ce;
+ bool _visible;
+ // for keyboard navigation: have we last reached this edge via a caller?
+ bool _lastFromCaller;
+
+};
+
+
+typedef QMap<TraceFunction*, GraphNode> GraphNodeMap;
+typedef QMap<QPair<TraceFunction*, TraceFunction*>, GraphEdge> GraphEdgeMap;
+
+
+/* Abstract Interface for graph options */
+class GraphOptions
+{
+ public:
+ enum Layout { TopDown, LeftRight, Circular};
+
+ virtual double funcLimit() = 0;
+ virtual double callLimit() = 0;
+ virtual int maxCallerDepth() = 0;
+ virtual int maxCallingDepth() = 0;
+ virtual bool showSkipped() = 0;
+ virtual bool expandCycles() = 0;
+ virtual bool clusterGroups() = 0;
+ virtual int detailLevel() = 0;
+ virtual Layout layout() = 0;
+
+ static QString layoutString(Layout);
+ static Layout layout(QString);
+};
+
+/* Graph Options Storage */
+class StorableGraphOptions: public GraphOptions
+{
+ public:
+ StorableGraphOptions();
+
+ // implementation of getters
+ virtual double funcLimit() { return _funcLimit; }
+ virtual double callLimit() { return _callLimit; }
+ virtual int maxCallerDepth() { return _maxCallerDepth; }
+ virtual int maxCallingDepth() { return _maxCallingDepth; }
+ virtual bool showSkipped() { return _showSkipped; }
+ virtual bool expandCycles() { return _expandCycles; }
+ virtual bool clusterGroups() { return _clusterGroups; }
+ virtual int detailLevel() { return _detailLevel; }
+ virtual Layout layout() { return _layout; }
+
+ // setters
+ void setMaxCallerDepth(int d) { _maxCallerDepth = d; }
+ void setMaxCallingDepth(int d) { _maxCallingDepth = d; }
+ void setFuncLimit(double l) { _funcLimit = l; }
+ void setCallLimit(double l) { _callLimit = l; }
+ void setShowSkipped(bool b) { _showSkipped = b; }
+ void setExpandCycles(bool b) { _expandCycles = b; }
+ void setClusterGroups(bool b) { _clusterGroups = b; }
+ void setDetailLevel(int l) { _detailLevel = l; }
+ void setLayout(Layout l) { _layout = l; }
+
+ protected:
+ double _funcLimit, _callLimit;
+ int _maxCallerDepth, _maxCallingDepth;
+ bool _showSkipped, _expandCycles, _clusterGroups;
+ int _detailLevel;
+ Layout _layout;
+};
+
+/**
+ * GraphExporter
+ *
+ * Generates a graph file for "dot"
+ * Create an instance and
+ */
+class GraphExporter: public StorableGraphOptions
+{
+public:
+ GraphExporter();
+ GraphExporter(TraceData*, TraceFunction*, TraceCostType*,
+ TraceItem::CostType, QString filename = QString::null);
+ virtual ~GraphExporter();
+
+ void reset(TraceData*, TraceItem*, TraceCostType*,
+ TraceItem::CostType, QString filename = QString::null);
+
+ QString filename() { return _dotName; }
+ int edgeCount() { return _edgeMap.count(); }
+ int nodeCount() { return _nodeMap.count(); }
+
+ // Set the object from which to get graph options for creation.
+ // Default is this object itself (supply 0 for default)
+ void setGraphOptions(GraphOptions* go = 0);
+
+ // Create a subgraph with given limits/maxDepths
+ void createGraph();
+
+ // calls createGraph before dumping of not already created
+ void writeDot();
+
+ // to map back to structures when parsing a layouted graph
+
+ /* <toFunc> is a helper for node() and edge().
+ * Don't use the returned pointer directly, but only with
+ * node() or edge(), because it could be a dangling pointer.
+ */
+ TraceFunction* toFunc(QString);
+ GraphNode* node(TraceFunction*);
+ GraphEdge* edge(TraceFunction*, TraceFunction*);
+
+ /* After CanvasEdges are attached to GraphEdges, we can
+ * sort the incoming and outgoing edges of all nodes
+ * regarding start/end points for keyboard navigation
+ */
+ void sortEdges();
+
+private:
+ void buildGraph(TraceFunction*, int, bool, double);
+
+ QString _dotName;
+ TraceItem* _item;
+ TraceCostType* _costType;
+ TraceItem::CostType _groupType;
+ KTempFile* _tmpFile;
+ double _realFuncLimit, _realCallLimit;
+ int _maxDepth;
+ bool _graphCreated;
+
+ GraphOptions* _go;
+
+ // optional graph attributes
+ bool _useBox;
+
+ // graph parts written to file
+ GraphNodeMap _nodeMap;
+ GraphEdgeMap _edgeMap;
+};
+
+/**
+ * A panner layed over a QCanvas
+ */
+class PannerView: public QCanvasView
+{
+ Q_OBJECT
+
+public:
+ PannerView(QWidget * parent = 0, const char * name = 0);
+
+ void setZoomRect(QRect r);
+
+signals:
+ void zoomRectMoved(int dx, int dy);
+ void zoomRectMoveFinished();
+
+protected:
+ void contentsMousePressEvent(QMouseEvent*);
+ void contentsMouseMoveEvent(QMouseEvent*);
+ void contentsMouseReleaseEvent(QMouseEvent*);
+ void drawContents(QPainter * p, int clipx, int clipy, int clipw, int cliph);
+
+ QRect _zoomRect;
+ bool _movingZoomRect;
+ QPoint _lastPos;
+};
+
+
+/*
+ * Canvas Items:
+ * - CanvasNode (Rectangular Area)
+ * - CanvasEdge (Spline curve)
+ * - CanvasEdgeLabel (Label for edges)
+ * - CanvasEdgeArrow (Arrows at the end of the edge spline)
+ * - CanvasFrame (Grey background blending to show active node)
+ */
+
+enum {
+ CANVAS_NODE = 1122,
+ CANVAS_EDGE, CANVAS_EDGELABEL, CANVAS_EDGEARROW,
+ CANVAS_FRAME
+};
+
+class CanvasNode: public QCanvasRectangle, public StoredDrawParams
+{
+public:
+ CanvasNode(CallGraphView*,GraphNode*, int, int, int, int, QCanvas*);
+
+ void updateGroup();
+ void setSelected(bool);
+ void drawShape(QPainter&);
+
+ GraphNode* node() { return _node; }
+ int rtti() const { return CANVAS_NODE; }
+
+private:
+ GraphNode* _node;
+ CallGraphView* _view;
+};
+
+class CanvasEdgeLabel: public QCanvasRectangle, public StoredDrawParams
+{
+public:
+ CanvasEdgeLabel(CallGraphView*, CanvasEdge*, int, int, int, int, QCanvas*);
+
+ void drawShape(QPainter&);
+
+ CanvasEdge* canvasEdge() { return _ce; }
+ int rtti() const { return CANVAS_EDGELABEL; }
+
+private:
+ CanvasEdge* _ce;
+ CallGraphView* _view;
+};
+
+class CanvasEdgeArrow: public QCanvasPolygon
+{
+public:
+ CanvasEdgeArrow(CanvasEdge*, QCanvas*);
+
+ void drawShape(QPainter&);
+
+ CanvasEdge* canvasEdge() { return _ce; }
+ int rtti() const { return CANVAS_EDGEARROW; }
+
+private:
+ CanvasEdge* _ce;
+};
+
+
+class CanvasEdge: public QCanvasSpline
+{
+public:
+ CanvasEdge(GraphEdge*, QCanvas*);
+
+ void setSelected(bool);
+ void drawShape(QPainter&);
+ QPointArray areaPoints() const;
+
+ CanvasEdgeLabel* label() { return _label; }
+ void setLabel(CanvasEdgeLabel* l) { _label = l; }
+ CanvasEdgeArrow* arrow() { return _arrow; }
+ void setArrow(CanvasEdgeArrow* a) { _arrow = a; }
+
+ GraphEdge* edge() { return _edge; }
+ int rtti() const { return CANVAS_EDGE; }
+
+private:
+ GraphEdge* _edge;
+ CanvasEdgeLabel* _label;
+ CanvasEdgeArrow* _arrow;
+};
+
+
+class CanvasFrame: public QCanvasRectangle
+{
+public:
+ CanvasFrame( CanvasNode*, QCanvas *canvas );
+ int rtti () const { return CANVAS_FRAME; }
+ bool hit( const QPoint&) const { return false; }
+protected:
+ void drawShape( QPainter & );
+private:
+ static QPixmap* _p;
+};
+
+
+class CallGraphTip;
+
+/**
+ * A CanvasView showing a part of the call graph
+ * and another zoomed out CanvasView in a border acting as
+ * a panner to select to visible part (only if needed)
+ */
+class CallGraphView: public QCanvasView, public TraceItemView,
+ public StorableGraphOptions
+{
+ Q_OBJECT
+
+public:
+ enum ZoomPosition { TopLeft, TopRight, BottomLeft, BottomRight, Auto };
+
+ CallGraphView(TraceItemView* parentView,
+ QWidget* parent=0, const char* name=0);
+ ~CallGraphView();
+
+ void readViewConfig(KConfig*, QString prefix, QString postfix, bool);
+ void saveViewConfig(KConfig*, QString prefix, QString postfix, bool);
+
+ QWidget* widget() { return this; }
+ QString whatsThis() const;
+
+ ZoomPosition zoomPos() const { return _zoomPosition; }
+ static ZoomPosition zoomPos(QString);
+ static QString zoomPosString(ZoomPosition);
+
+public slots:
+ void contentsMovingSlot(int,int);
+ void zoomRectMoved(int,int);
+ void zoomRectMoveFinished();
+
+ void showRenderWarning();
+ void stopRendering();
+ void readDotOutput();
+ void dotExited();
+
+protected:
+ void resizeEvent(QResizeEvent*);
+ void contentsMousePressEvent(QMouseEvent*);
+ void contentsMouseMoveEvent(QMouseEvent*);
+ void contentsMouseReleaseEvent(QMouseEvent*);
+ void contentsMouseDoubleClickEvent(QMouseEvent*);
+ void contentsContextMenuEvent(QContextMenuEvent*);
+ void keyPressEvent(QKeyEvent*);
+ void focusInEvent(QFocusEvent*);
+ void focusOutEvent(QFocusEvent*);
+
+private:
+ void updateSizes(QSize s = QSize(0,0));
+ TraceItem* canShow(TraceItem*);
+ void doUpdate(int);
+ void refresh();
+ void makeFrame(CanvasNode*, bool active);
+ void clear();
+ void showText(QString);
+
+ QCanvas *_canvas;
+ int _xMargin, _yMargin;
+ PannerView *_completeView;
+ double _cvZoom;
+
+ CallGraphTip* _tip;
+
+ bool _isMoving;
+ QPoint _lastPos;
+
+ GraphExporter _exporter;
+
+ GraphNode* _selectedNode;
+ GraphEdge* _selectedEdge;
+
+ // widget options
+ ZoomPosition _zoomPosition, _lastAutoPosition;
+
+ // background rendering
+ QProcess* _renderProcess;
+ QTimer _renderTimer;
+ GraphNode* _prevSelectedNode;
+ QPoint _prevSelectedPos;
+ QString _unparsedOutput;
+};
+
+
+
+
+#endif
+
+
+
diff --git a/kcachegrind/kcachegrind/callitem.cpp b/kcachegrind/kcachegrind/callitem.cpp
new file mode 100644
index 00000000..51bc19d2
--- /dev/null
+++ b/kcachegrind/kcachegrind/callitem.cpp
@@ -0,0 +1,185 @@
+/* This file is part of KCachegrind.
+ Copyright (C) 2002, 2003 Josef Weidendorfer <Josef.Weidendorfer@gmx.de>
+
+ KCachegrind is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public
+ License as published by the Free Software Foundation, version 2.
+
+ 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; see the file COPYING. If not, write to
+ the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+*/
+
+/*
+ * Items for caller/callee view.
+ */
+
+#include <qpixmap.h>
+#include <klocale.h>
+#include <kapplication.h>
+#include <kiconloader.h>
+
+#include "configuration.h"
+#include "listutils.h"
+#include "callitem.h"
+#include "callview.h"
+#include "toplevel.h"
+
+// CallItem
+
+
+CallItem::CallItem(CallView* view, QListView* parent, TraceCall* c)
+ : QListViewItem(parent)
+{
+ _call = c;
+ _view = view;
+
+ _active = _view->activeFunction();
+ bool baseIsCycle = (_active && (_active == _active->cycle()));
+
+ QString fName;
+ if (_view->showCallers()) {
+ _shown = _call->caller(true);
+ fName = c->callerName(!baseIsCycle);
+ }
+ else {
+ _shown = _call->called(true);
+ fName = c->calledName(!baseIsCycle);
+ }
+
+ _shown->addPrettyLocation(fName);
+
+ setText(3, fName);
+ updateGroup();
+ updateCost();
+}
+
+void CallItem::updateGroup()
+{
+ QColor c = Configuration::functionColor(_view->groupType(), _shown);
+ setPixmap(3, colorPixmap(10, 10, c));
+}
+
+void CallItem::updateCost()
+{
+ bool sameCycle = _shown->cycle() && (_active->cycle() == _shown->cycle());
+ bool shownIsCycle = (_shown == _shown->cycle());
+ bool selectedIsCycle = (_active == _active->cycle());
+ if (_call->isRecursion()) sameCycle=true;
+
+ QString cStr;
+ if ((selectedIsCycle || shownIsCycle) && sameCycle)
+ cStr = "-";
+ else {
+ _cc = _call->callCount();
+ if (_cc == 0)
+ cStr = i18n("(active)");
+ else
+ cStr = _call->prettyCallCount();
+ }
+ setText(2, cStr);
+
+ TraceCost* totalCost;
+ if (_view->topLevel()->showExpanded()) {
+ if (_active->cycle())
+ totalCost = _active->cycle()->inclusive();
+ else
+ totalCost = _active->inclusive();
+ }
+ else
+ totalCost = _active->data();
+
+ TraceCostType* ct = _view->costType();
+ _sum = _call->subCost(ct);
+ double total = totalCost->subCost(ct);
+
+ if (total == 0.0) {
+ QString str = "-";
+
+ setText(0, str);
+ setPixmap(0, QPixmap());
+ }
+ else {
+ double sum = 100.0 * _sum / total;
+
+ if (_view->topLevel()->showPercentage())
+ setText(0, QString("%1")
+ .arg(sum, 0, 'f', Configuration::percentPrecision()));
+ else
+ setText(0, _call->prettySubCost(ct));
+
+ setPixmap(0, costPixmap(ct, _call, total, false));
+ }
+
+ // Cost Type 2
+ TraceCostType* ct2 = _view->costType2();
+ if (ct2) {
+ _sum2 = _call->subCost(ct2);
+ double total = totalCost->subCost(ct2);
+
+ if (total == 0.0) {
+ QString str = "-";
+
+ setText(1, str);
+ setPixmap(1, QPixmap());
+ }
+ else {
+ double sum = 100.0 * _sum2 / total;
+
+ if (_view->topLevel()->showPercentage())
+ setText(1, QString("%1")
+ .arg(sum, 0, 'f', Configuration::percentPrecision()));
+ else
+ setText(1, _call->prettySubCost(ct2));
+
+ setPixmap(1, costPixmap(ct2, _call, total, false));
+ }
+ }
+
+ QPixmap p;
+ if (sameCycle && !selectedIsCycle && !shownIsCycle) {
+
+ QString icon = "undo";
+ KIconLoader* loader = KApplication::kApplication()->iconLoader();
+ p= loader->loadIcon(icon, KIcon::Small, 0,
+ KIcon::DefaultState, 0, true);
+ }
+ setPixmap(2, p);
+}
+
+
+int CallItem::compare(QListViewItem * i, int col, bool ascending ) const
+{
+ const CallItem* ci1 = this;
+ const CallItem* ci2 = (CallItem*) i;
+
+ // we always want descending order
+ if (ascending) {
+ ci1 = ci2;
+ ci2 = this;
+ }
+
+ if (col==0) {
+ if (ci1->_sum < ci2->_sum) return -1;
+ if (ci1->_sum > ci2->_sum) return 1;
+ return 0;
+ }
+ if (col==1) {
+ if (ci1->_sum2 < ci2->_sum2) return -1;
+ if (ci1->_sum2 > ci2->_sum2) return 1;
+ return 0;
+ }
+ if (col==2) {
+ if (ci1->_cc < ci2->_cc) return -1;
+ if (ci1->_cc > ci2->_cc) return 1;
+ return 0;
+ }
+ return QListViewItem::compare(i, col, ascending);
+}
+
diff --git a/kcachegrind/kcachegrind/callitem.h b/kcachegrind/kcachegrind/callitem.h
new file mode 100644
index 00000000..b3013b0c
--- /dev/null
+++ b/kcachegrind/kcachegrind/callitem.h
@@ -0,0 +1,50 @@
+/* This file is part of KCachegrind.
+ Copyright (C) 2003 Josef Weidendorfer <Josef.Weidendorfer@gmx.de>
+
+ KCachegrind is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public
+ License as published by the Free Software Foundation, version 2.
+
+ 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; see the file COPYING. If not, write to
+ the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+*/
+
+/*
+ * Items of call view.
+ */
+
+#ifndef CALLITEM_H
+#define CALLITEM_H
+
+#include <qlistview.h>
+#include "tracedata.h"
+
+class CallView;
+
+class CallItem: public QListViewItem
+{
+public:
+ CallItem(CallView*, QListView*, TraceCall* c);
+
+ int compare(QListViewItem * i, int col, bool ascending ) const;
+ TraceCall* call() { return _call; }
+ CallView* view() { return _view; }
+ void updateCost();
+ void updateGroup();
+
+private:
+ SubCost _sum, _sum2;
+ SubCost _cc;
+ TraceCall* _call;
+ CallView* _view;
+ TraceFunction *_active, *_shown;
+};
+
+#endif
diff --git a/kcachegrind/kcachegrind/callmapview.cpp b/kcachegrind/kcachegrind/callmapview.cpp
new file mode 100644
index 00000000..8098c6b1
--- /dev/null
+++ b/kcachegrind/kcachegrind/callmapview.cpp
@@ -0,0 +1,999 @@
+/* This file is part of KCachegrind.
+ Copyright (C) 2003 Josef Weidendorfer <Josef.Weidendorfer@gmx.de>
+
+ KCachegrind is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public
+ License as published by the Free Software Foundation, version 2.
+
+ 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; see the file COPYING. If not, write to
+ the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+*/
+
+/*
+ * Call Map View
+ */
+
+#include <qwhatsthis.h>
+#include <qpopupmenu.h>
+
+#include <klocale.h>
+#include <kiconloader.h>
+#include <kapplication.h>
+#include <kconfig.h>
+
+#include "callmapview.h"
+#include "configuration.h"
+#include "listutils.h"
+#include "toplevel.h"
+
+//
+// CallMapView
+//
+
+
+// defaults
+#define DEFAULT_SPLITMODE "Rows"
+#define DEFAULT_DRAWNAME true
+#define DEFAULT_DRAWCOST true
+#define DEFAULT_DRAWLOCATION false
+#define DEFAULT_DRAWCALLS false
+#define DEFAULT_FORCESTRINGS false
+#define DEFAULT_ROTATION true
+#define DEFAULT_SHADING true
+#define DEFAULT_MAXAREA 100
+
+
+CallMapView::CallMapView(bool showCallers, TraceItemView* parentView,
+ QWidget* parent, const char* name)
+ : TreeMapWidget(new CallMapBaseItem(), parent, name), TraceItemView(parentView)
+{
+ _showCallers = showCallers;
+
+ setFieldType(0, i18n( "Name" ));
+ setFieldType(1, i18n( "Cost" ));
+ setFieldType(2, i18n( "Location" ));
+ setFieldPosition(2, TreeMapItem::TopLeft);
+ setFieldType(3, i18n( "Calls" ));
+ setFieldPosition(3, TreeMapItem::TopRight);
+
+ setSplitMode(DEFAULT_SPLITMODE);
+ setFieldVisible(0, DEFAULT_DRAWNAME);
+ setFieldVisible(1, DEFAULT_DRAWCOST);
+ setFieldVisible(2, DEFAULT_DRAWLOCATION);
+ setFieldVisible(3, DEFAULT_DRAWCALLS);
+ setFieldForced(0, DEFAULT_FORCESTRINGS);
+ setFieldForced(1, DEFAULT_FORCESTRINGS);
+ setFieldForced(2, DEFAULT_FORCESTRINGS);
+ setFieldForced(3, DEFAULT_FORCESTRINGS);
+ setAllowRotation(DEFAULT_ROTATION);
+ setShadingEnabled(DEFAULT_SHADING);
+ setMinimalArea(DEFAULT_MAXAREA);
+
+ connect(this,
+ SIGNAL(doubleClicked(TreeMapItem*)),
+ SLOT(activatedSlot(TreeMapItem*)));
+ connect(this,
+ SIGNAL(returnPressed(TreeMapItem*)),
+ SLOT(activatedSlot(TreeMapItem*)));
+ connect(this,
+ SIGNAL(currentChanged(TreeMapItem*, bool)),
+ SLOT(selectedSlot(TreeMapItem*, bool)));
+ connect(this,
+ SIGNAL(contextMenuRequested(TreeMapItem*,const QPoint &)),
+ SLOT(context(TreeMapItem*,const QPoint &)));
+
+ QWhatsThis::add( this, whatsThis());
+}
+
+QString CallMapView::whatsThis() const
+{
+ QString s = _showCallers ?
+ i18n( "<b>Caller Map</b>"
+ "<p>This graph shows the nested hierarchy of "
+ "all callers of the current activated function. "
+ "Each colored rectangle represents a function; "
+ "its size tries to be proportional to the cost spent "
+ "therein while the active function is running "
+ "(however, there are drawing constrains).</p>") :
+ i18n("<b>Call Map</b>"
+ "<p>This graph shows the nested hierarchy of "
+ "all callees of the current activated function. "
+ "Each colored rectangle represents a function; "
+ "its size tries to be proportional to the cost spent "
+ "therein while the active function is running "
+ "(however, there are drawing constrains).</p>");
+
+ s += i18n( "<p>Appearance options can be found in the "
+ "in the context menu. To get exact size proportions, "
+ "choose 'Hide incorrect borders'. As this mode can be "
+ "<em>very</em> time consuming, you may want to limit "
+ "the maximum drawn nesting level before. "
+ "'Best' determinates the split direction for children "
+ "from the aspect ratio of the parent. "
+ "'Always Best' decides on remaining space for each "
+ "sibling. "
+ "'Ignore Proportions' takes space for function name "
+ "drawing <em>before</em> drawing children. Note that "
+ "size proportions can get <em>heavily</em> wrong.</p>"
+
+ "<p>This is a <em>TreeMap</em> widget. "
+ "Keyboard navigation is available with the left/right arrow "
+ "keys for traversing siblings, and up/down arrow keys "
+ "to go a nesting level up/down. "
+ "<em>Return</em> activates the current item.</p>");
+
+ return s;
+}
+
+void CallMapView::setData(TraceData* d)
+{
+ TraceItemView::setData(d);
+
+ ((CallMapBaseItem*)base())->setFunction(0);
+}
+
+void CallMapView::context(TreeMapItem* i,const QPoint & p)
+{
+ if (!i) return;
+
+ QPopupMenu popup;
+ QPopupMenu fpopup; // select function subpopup
+ QPopupMenu vpopup; // visualisation subpopup
+ QPopupMenu dpopup; // split direction
+ QPopupMenu bpopup; // border subpopup
+ QPopupMenu l1popup; // depth limit subpopup
+ QPopupMenu l2popup; // function limit subpopup
+ QPopupMenu l3popup; // area limit subpopup
+
+ TreeMapItem* item = i;
+ int count;
+
+ QString shortCurrentName;
+ if (i) {
+ shortCurrentName = i->text(0);
+ if ((int)shortCurrentName.length() > Configuration::maxSymbolLength())
+ shortCurrentName =
+ shortCurrentName.left(Configuration::maxSymbolLength()) + "...";
+ }
+
+ if (item) {
+ popup.insertItem(i18n("Go To"), &fpopup, 100);
+ count = 0;
+ while (count<Configuration::maxSymbolCount() && item) {
+ QString name = item->text(0);
+ if ((int)name.length()>Configuration::maxSymbolLength())
+ name = name.left(Configuration::maxSymbolLength()) + "...";
+ fpopup.insertItem(name, 101+count);
+ item = item->parent();
+ count++;
+ }
+ popup.insertSeparator();
+ }
+
+ addGoMenu(&popup);
+ popup.insertSeparator();
+
+ l1popup.setCheckable(true);
+ popup.insertItem(i18n("Stop at Depth"), &l1popup, 12);
+
+ int maxDepth = maxDrawingDepth();
+ l1popup.insertItem(i18n("No Depth Limit"), 50);
+ l1popup.setItemChecked(50, maxDepth==-1);
+ l1popup.insertSeparator();
+ l1popup.insertItem(i18n("Depth 10"), 51);
+ l1popup.setItemChecked(51, maxDepth==10);
+ l1popup.insertItem(i18n("Depth 15"), 52);
+ l1popup.setItemChecked(52, maxDepth==15);
+ l1popup.insertItem(i18n("Depth 20"), 53);
+ l1popup.setItemChecked(53, maxDepth==20);
+ if (i) {
+ l1popup.insertSeparator();
+ l1popup.insertItem(i18n("Depth of '%1' (%2)")
+ .arg(shortCurrentName).arg(i->depth()), 55);
+ l1popup.setItemChecked(55, maxDepth == i->depth());
+ }
+ if (maxDepth>0) {
+ l1popup.insertSeparator();
+ l1popup.insertItem(i18n("Decrement Depth (to %1)").arg(maxDepth-1), 56);
+ l1popup.insertItem(i18n("Increment Depth (to %1)").arg(maxDepth+1), 57);
+ }
+
+ l2popup.setCheckable(true);
+ popup.insertItem(i18n("Stop at Function"), &l2popup, 13);
+ l2popup.insertItem(i18n("No Function Limit"), 200);
+ l2popup.setItemChecked(200, fieldStop(0).isEmpty());
+ bool foundStopName = false;
+ item = i;
+ if (i) {
+ l2popup.insertSeparator();
+ count = 0;
+ while (count<Configuration::maxSymbolCount() && item) {
+ QString name = item->text(0);
+ if ((int)name.length()>Configuration::maxSymbolLength())
+ name = name.left(Configuration::maxSymbolLength()) + "...";
+ l2popup.insertItem(name, 201+count);
+ if (item->text(0) == fieldStop(0)) {
+ l2popup.setItemChecked(201+count, true);
+ foundStopName = true;
+ }
+ item = item->parent();
+ count++;
+ }
+ }
+ if (!foundStopName && !fieldStop(0).isEmpty()) {
+ l2popup.insertSeparator();
+ QString name = fieldStop(0);
+ if ((int)name.length()>Configuration::maxSymbolLength())
+ name = name.left(Configuration::maxSymbolLength()) + "...";
+ l2popup.insertItem(name, 199);
+ l2popup.setItemChecked(199, true);
+ }
+
+ l3popup.setCheckable(true);
+ popup.insertItem(i18n("Stop at Area"), &l3popup, 14);
+
+ int mArea = minimalArea();
+ l3popup.insertItem(i18n("No Area Limit"), 60);
+ l3popup.setItemChecked(60, mArea ==-1);
+ l3popup.insertSeparator();
+ l3popup.insertItem(i18n("50 Pixels"), 63);
+ l3popup.setItemChecked(63, mArea==50);
+ l3popup.insertItem(i18n("100 Pixels"), 64);
+ l3popup.setItemChecked(64, mArea==100);
+ l3popup.insertItem(i18n("200 Pixels"), 65);
+ l3popup.setItemChecked(65, mArea==200);
+ l3popup.insertItem(i18n("500 Pixels"), 66);
+ l3popup.setItemChecked(66, mArea==500);
+ int currentArea = 0;
+ if (i) {
+ currentArea = i->width() * i->height();
+ l3popup.insertSeparator();
+ l3popup.insertItem(i18n("Area of '%1' (%2)")
+ .arg(shortCurrentName).arg(currentArea), 67);
+ l3popup.setItemChecked(67, mArea == currentArea);
+ }
+ if (mArea>0) {
+ l3popup.insertSeparator();
+ l3popup.insertItem(i18n("Double Area Limit (to %1)")
+ .arg(mArea*2), 68);
+ l3popup.insertItem(i18n("Half Area Limit (to %1)")
+ .arg(mArea/2), 69);
+ }
+
+ popup.insertSeparator();
+
+ vpopup.setCheckable(true);
+ popup.insertItem(i18n("Visualisation"), &vpopup, 10);
+
+ QPopupMenu splitpopup;
+ addSplitDirectionItems(&splitpopup, 1001);
+ vpopup.insertItem(i18n("Split Direction"), &splitpopup, 1000);
+
+ vpopup.insertItem(i18n("Skip Incorrect Borders"), 40);
+ vpopup.setItemEnabled(40, !_showCallers);
+ vpopup.setItemChecked(40, skipIncorrectBorder());
+
+ bpopup.setCheckable(true);
+ vpopup.insertItem(i18n("Border Width"), &bpopup, 41);
+ bpopup.insertItem(i18n("Border 0"), 42);
+ bpopup.setItemEnabled(42, !_showCallers);
+ bpopup.setItemChecked(42, borderWidth()==0);
+ bpopup.insertItem(i18n("Border 1"), 43);
+ bpopup.setItemChecked(43, borderWidth()==1);
+ bpopup.insertItem(i18n("Border 2"), 44);
+ bpopup.setItemChecked(44, borderWidth()==2);
+ bpopup.insertItem(i18n("Border 3"), 45);
+ bpopup.setItemChecked(45, borderWidth()==3);
+
+ vpopup.insertSeparator();
+
+ vpopup.insertItem(i18n("Draw Symbol Names"), 20);
+ vpopup.insertItem(i18n("Draw Cost"), 21);
+ vpopup.insertItem(i18n("Draw Location"), 22);
+ vpopup.insertItem(i18n("Draw Calls"), 23);
+ vpopup.insertSeparator();
+
+ vpopup.insertItem(i18n("Ignore Proportions"), 24);
+ vpopup.insertItem(i18n("Allow Rotation"), 25);
+ if (!fieldVisible(0) &&
+ !fieldVisible(1) &&
+ !fieldVisible(2) &&
+ !fieldVisible(3)) {
+ vpopup.setItemEnabled(24, false);
+ vpopup.setItemEnabled(25, false);
+ }
+ else {
+ vpopup.setItemChecked(20,fieldVisible(0));
+ vpopup.setItemChecked(21,fieldVisible(1));
+ vpopup.setItemChecked(22,fieldVisible(2));
+ vpopup.setItemChecked(23,fieldVisible(3));
+ vpopup.setItemChecked(24,fieldForced(0));
+ vpopup.setItemChecked(25,allowRotation());
+ }
+
+ vpopup.insertItem(i18n("Shading"), 26);
+ vpopup.setItemChecked(26,isShadingEnabled());
+
+ int r = popup.exec(mapToGlobal(p));
+
+ if (r>100 && r<150) {
+ r -= 100;
+ while (i && (r>1)) {
+ i=i->parent();
+ r--;
+ }
+ activatedSlot(i);
+ return;
+ }
+
+ if (r>200 && r<250) {
+ r -= 200;
+ while (i && (r>1)) {
+ i=i->parent();
+ r--;
+ }
+ if (i)
+ setFieldStop(0, i->text(0));
+
+ return;
+ }
+
+ switch(r) {
+ case 20:
+ setFieldVisible(0, !vpopup.isItemChecked(20));
+ break;
+
+ case 21:
+ setFieldVisible(1, !vpopup.isItemChecked(21));
+ break;
+
+ case 22:
+ setFieldVisible(2, !vpopup.isItemChecked(22));
+ break;
+
+ case 23:
+ setFieldVisible(3, !vpopup.isItemChecked(23));
+ break;
+
+ case 24:
+ setFieldForced(0, !vpopup.isItemChecked(24));
+ setFieldForced(1, !vpopup.isItemChecked(24));
+ setFieldForced(2, !vpopup.isItemChecked(24));
+ setFieldForced(3, !vpopup.isItemChecked(24));
+ break;
+
+ case 25: setAllowRotation(!vpopup.isItemChecked(25)); break;
+ case 26: setShadingEnabled(!vpopup.isItemChecked(26)); break;
+
+ case 40:
+ setSkipIncorrectBorder(!vpopup.isItemChecked(40));
+ break;
+
+ case 42: setBorderWidth(0); break;
+ case 43: setBorderWidth(1); break;
+ case 44: setBorderWidth(2); break;
+ case 45: setBorderWidth(3); break;
+
+ case 50: setMaxDrawingDepth(-1); break;
+ case 51: setMaxDrawingDepth(10); break;
+ case 52: setMaxDrawingDepth(15); break;
+ case 53: setMaxDrawingDepth(20); break;
+ case 55: setMaxDrawingDepth(i->depth()); break;
+ case 56: setMaxDrawingDepth(maxDepth-1); break;
+ case 57: setMaxDrawingDepth(maxDepth+1); break;
+
+ case 200: setFieldStop(0, QString::null); break;
+
+ case 60: setMinimalArea(-1); break;
+ case 61: setMinimalArea(10); break;
+ case 62: setMinimalArea(20); break;
+ case 63: setMinimalArea(50); break;
+ case 64: setMinimalArea(100); break;
+ case 65: setMinimalArea(200); break;
+ case 66: setMinimalArea(500); break;
+ case 67: setMinimalArea(currentArea); break;
+ case 68: setMinimalArea(mArea*2); break;
+ case 69: setMinimalArea(mArea/2); break;
+ }
+}
+
+void CallMapView::activatedSlot(TreeMapItem* item)
+{
+ if (!item) return;
+
+ if (item->rtti() == 1) {
+ CallMapBaseItem* bi = (CallMapBaseItem*)item;
+ activated(bi->function());
+ }
+ else if (item->rtti() == 2) {
+ CallMapCallingItem* ci = (CallMapCallingItem*)item;
+ activated(ci->function());
+ }
+ else if (item->rtti() == 3) {
+ CallMapCallerItem* ci = (CallMapCallerItem*)item;
+ activated(ci->function());
+ }
+}
+
+void CallMapView::selectedSlot(TreeMapItem* item, bool kbd)
+{
+ if (!item) return;
+ if (item->text(0).isEmpty()) return;
+
+ if (kbd) {
+ QString msg = i18n("Call Map: Current is '%1'").arg(item->text(0));
+ if (_topLevel)
+ _topLevel->showMessage(msg, 5000);
+ }
+
+ TraceFunction* f = 0;
+
+ if (item->rtti() == 1) {
+ CallMapBaseItem* bi = (CallMapBaseItem*)item;
+ f = bi->function();
+ }
+ else if (item->rtti() == 2) {
+ CallMapCallingItem* ci = (CallMapCallingItem*)item;
+ f = ci->function();
+ }
+ else if (item->rtti() == 3) {
+ CallMapCallerItem* ci = (CallMapCallerItem*)item;
+ f = ci->function();
+ }
+ if (f) {
+ // this avoids marking
+ _selectedItem = f;
+ selected(f);
+ }
+}
+
+TraceItem* CallMapView::canShow(TraceItem* i)
+{
+ TraceItem::CostType t = i ? i->type() : TraceItem::NoCostType;
+
+ switch(t) {
+ case TraceItem::Function:
+ case TraceItem::FunctionCycle:
+ return i;
+ default:
+ break;
+ }
+ return 0;
+}
+
+void CallMapView::doUpdate(int changeType)
+{
+ if (changeType == costType2Changed) return;
+
+ // if there is a selected item, always draw marking...
+ if (changeType & selectedItemChanged) {
+ TraceFunction* f = 0;
+
+ if (_selectedItem) {
+ switch(_selectedItem->type()) {
+ case TraceItem::Function:
+ case TraceItem::FunctionCycle:
+ f = (TraceFunction*)_selectedItem;
+ break;
+ default:
+ break;
+ }
+ }
+ // if this is the only change...
+ if (changeType == selectedItemChanged) {
+ setMarked(f ? 1:0, true);
+ return;
+ }
+ setMarked(f ? 1:0, false);
+ }
+
+
+ if (changeType & activeItemChanged) {
+ TraceFunction* f = 0;
+
+ if (_activeItem) {
+ switch(_activeItem->type()) {
+ case TraceItem::Function:
+ case TraceItem::FunctionCycle:
+ f = (TraceFunction*)_activeItem;
+ break;
+ default:
+ break;
+ }
+ }
+ ((CallMapBaseItem*)base())->setFunction(f);
+ }
+ else if ( ((changeType & partsChanged) && Configuration::showCycles()) ||
+ (changeType & dataChanged) ||
+ (changeType & configChanged)) {
+ /* regenerates the treemap because traceitems were added/removed */
+ base()->refresh();
+ }
+ else if ((changeType & partsChanged) ||
+ (changeType & costTypeChanged)) {
+ /* we need to do the draw order sorting again as the values change */
+ resort();
+ redraw();
+ }
+ else
+ redraw();
+}
+
+
+
+QColor CallMapView::groupColor(TraceFunction* f) const
+{
+ if (!f)
+ return colorGroup().button();
+
+ return Configuration::functionColor(_groupType, f);
+}
+
+
+QString CallMapView::tipString(TreeMapItem* i) const
+{
+ QString tip, itemTip;
+ int count = 0;
+
+ //qDebug("CallMapView::tipString for '%s'", i->text(0).ascii());
+
+ // first, SubPartItem's
+ while (i && count<Configuration::maxSymbolCount()) {
+ itemTip = i->text(0);
+ if ((int)itemTip.length()>Configuration::maxSymbolLength())
+ itemTip = itemTip.left(Configuration::maxSymbolLength()) + "...";
+
+ if (!i->text(1).isEmpty())
+ itemTip += " (" + i->text(1) + ")";
+
+ if (!tip.isEmpty()) tip += "\n";
+
+ tip += itemTip;
+ i = i->parent();
+ count++;
+ }
+ if (count == Configuration::maxSymbolCount()) tip += "\n...";
+
+ return tip;
+}
+
+
+TraceCost* CallMapView::totalCost()
+{
+ TraceFunction* f = ((CallMapBaseItem*)base())->function();
+ if (!f) return 0;
+
+ return Configuration::showExpanded() ? f->inclusive() : f->data();
+}
+
+
+
+
+// CallMapBaseItem
+
+CallMapBaseItem::CallMapBaseItem()
+{
+ _f = 0;
+}
+
+void CallMapBaseItem::setFunction(TraceFunction* f)
+{
+ if (f == _f) return;
+
+ _f = f;
+ refresh();
+}
+
+
+QString CallMapBaseItem::text(int textNo) const
+{
+ if (textNo == 0) {
+ if (!_f)
+ return i18n("(no function)");
+
+ return _f->prettyName();
+ }
+
+ if (!_f) return QString::null;
+
+ if (textNo == 2) return _f->prettyLocation();
+ if (textNo == 3) return _f->calledCount().pretty();
+ if (textNo != 1) return QString::null;
+
+ TraceCostType* ct = ((CallMapView*)widget())->costType();
+ TraceCost* t = ((CallMapView*)widget())->totalCost();
+
+ if (Configuration::showPercentage()) {
+ double sum, total = t->subCost(ct);
+ if (total == 0.0)
+ sum = 100.0;
+ else
+ sum = 100.0 * _f->inclusive()->subCost(ct) / total;
+
+ return QString("%1 %")
+ .arg(sum, 0, 'f', Configuration::percentPrecision());
+ }
+ return _f->inclusive()->prettySubCost(ct);
+}
+
+QPixmap CallMapBaseItem::pixmap(int i) const
+{
+ if ((i != 1) || !_f) return QPixmap();
+
+ TraceCostType* ct = ((CallMapView*)widget())->costType();
+ TraceCost* t = ((CallMapView*)widget())->totalCost();
+
+ // colored level meter with frame
+ return costPixmap( ct, _f->inclusive(), (double) (t->subCost(ct)), true);
+}
+
+
+double CallMapBaseItem::value() const
+{
+ if (!_f) return 0.0;
+
+ TraceCostType* ct;
+ ct = ((CallMapView*)widget())->costType();
+ return (double) _f->inclusive()->subCost(ct);
+}
+
+
+double CallMapBaseItem::sum() const
+{
+ if (!_f) return 0.0;
+
+ CallMapView* w = (CallMapView*)widget();
+
+ if (w->showCallers())
+ return 0.0;
+ else
+ return (double) _f->inclusive()->subCost(w->costType());
+}
+
+
+bool CallMapBaseItem::isMarked(int) const
+{
+ return ((CallMapView*)widget())->selectedItem() == _f;
+}
+
+TreeMapItemList* CallMapBaseItem::children()
+{
+ if (_f && !initialized()) {
+ CallMapView* w = (CallMapView*)widget();
+
+ if (0) qDebug("Create Function %s (%s)",
+ w->showCallers() ? "Callers":"Callees",
+ text(0).ascii());
+
+ TraceCall* call;
+
+ setSorting(-1);
+ if (w->showCallers()) {
+ TraceCallList l = _f->callers();
+ for (call=l.first();call;call=l.next()) {
+
+ // don't show calls inside of a cycle
+ if (call->inCycle()>0) continue;
+ if (call->isRecursion()) continue;
+
+ addItem(new CallMapCallerItem(1.0, call));
+ }
+
+ setSum(0);
+ }
+ else {
+ TraceCallList l = _f->callings();
+ for (call=l.first();call;call=l.next()) {
+
+ // don't show calls inside of a cycle
+ if (call->inCycle()>0) continue;
+ if (call->isRecursion()) continue;
+
+ CallMapCallingItem* i = new CallMapCallingItem(1.0, call);
+ i->init();
+ addItem(i);
+ }
+
+ setSum(_f->inclusive()->subCost(w->costType()));
+ }
+ setSorting(-2, false);
+ }
+
+ return _children;
+}
+
+QColor CallMapBaseItem::backColor() const
+{
+ return ((CallMapView*)widget())->groupColor(_f);
+}
+
+
+
+// CallMapCallingItems
+
+CallMapCallingItem::CallMapCallingItem(double factor, TraceCall* c)
+{
+ _factor = factor;
+ _c = c;
+}
+
+void CallMapCallingItem::init()
+{
+#if 0
+ // create assoziation: if not possible, i.e. an ass. already exists
+ // for the function, we need to draw the recursive version
+ _recursive = !setFunction(_c->called());
+ _valid = true;
+#endif
+}
+
+QString CallMapCallingItem::text(int textNo) const
+{
+ if (textNo == 0) {
+ if (!_c)
+ return i18n("(no call)");
+
+ return _c->calledName();
+ }
+
+ if (textNo == 2) return _c->called()->prettyLocation();
+ if (textNo == 3) return SubCost(_factor * _c->callCount()).pretty();
+ if (textNo != 1) return QString::null;
+
+ TraceCostType* ct;
+ ct = ((CallMapView*)widget())->costType();
+
+ SubCost val = SubCost(_factor * _c->subCost(ct));
+ if (Configuration::showPercentage()) {
+ // percentage relative to function cost
+ TraceCost* t = ((CallMapView*)widget())->totalCost();
+ double p = 100.0 * _factor * _c->subCost(ct) / t->subCost(ct);
+ return QString("%1 %")
+ .arg(p, 0, 'f', Configuration::percentPrecision());
+ }
+ return val.pretty();
+}
+
+QPixmap CallMapCallingItem::pixmap(int i) const
+{
+ if (i != 1) return QPixmap();
+
+ // Cost pixmap
+ TraceCostType* ct = ((CallMapView*)widget())->costType();
+ TraceCost* t = ((CallMapView*)widget())->totalCost();
+
+ // colored level meter with frame
+ return costPixmap( ct, _c, t->subCost(ct) / _factor, true);
+}
+
+
+double CallMapCallingItem::value() const
+{
+ TraceCostType* ct;
+ ct = ((CallMapView*)widget())->costType();
+ return _factor * _c->subCost(ct);
+}
+
+double CallMapCallingItem::sum() const
+{
+ return value();
+}
+
+bool CallMapCallingItem::isMarked(int) const
+{
+ return ((CallMapView*)widget())->selectedItem() == _c->called();
+}
+
+
+TreeMapItemList* CallMapCallingItem::children()
+{
+ if (!initialized()) {
+ if (0) qDebug("Create Calling subitems (%s)", path(0).join("/").ascii());
+
+ TraceCostType* ct;
+ ct = ((CallMapView*)widget())->costType();
+
+ // same as sum()
+ SubCost s = _c->called()->inclusive()->subCost(ct);
+ SubCost v = _c->subCost(ct);
+ if (v>s) {
+ qDebug("Warning: CallingItem subVal %u > Sum %u (%s)",
+ (unsigned)v, (unsigned)s, _c->called()->prettyName().ascii());
+ v = s;
+ }
+ double newFactor = _factor * v / s;
+
+#if 0
+ qDebug("CallingItem: Subitems of %s => %s, factor %f * %d/%d => %f",
+ _c->caller()->prettyName().ascii(),
+ _c->called()->prettyName().ascii(),
+ _factor, v, s, newFactor);
+#endif
+ setSorting(-1);
+ TraceCall* call;
+ TraceCallList l = _c->called()->callings();
+ for (call=l.first();call;call=l.next()) {
+
+ // don't show calls inside of a cycle
+ if (call->inCycle()>0) continue;
+ if (call->isRecursion()) continue;
+
+ CallMapCallingItem* i = new CallMapCallingItem(newFactor, call);
+ i->init();
+ addItem(i);
+ }
+ setSorting(-2, false);
+ }
+
+ return _children;
+}
+
+
+QColor CallMapCallingItem::backColor() const
+{
+ CallMapView* w = (CallMapView*)widget();
+ return w->groupColor(_c->called());
+}
+
+
+// CallMapCallerItem
+
+CallMapCallerItem::CallMapCallerItem(double factor, TraceCall* c)
+{
+ _factor = factor;
+ _c = c;
+}
+
+QString CallMapCallerItem::text(int textNo) const
+{
+ if (textNo == 0) {
+ if (!_c)
+ return i18n("(no call)");
+
+ return _c->callerName();
+ }
+
+ if (textNo == 2) return _c->caller()->prettyLocation();
+ if (textNo == 3) return SubCost(_factor * _c->callCount()).pretty();
+ if (textNo != 1) return QString::null;
+
+ TraceCostType* ct;
+ ct = ((CallMapView*)widget())->costType();
+
+ SubCost val = SubCost(_factor * _c->subCost(ct));
+ if (Configuration::showPercentage()) {
+ TraceCost* t = ((CallMapView*)widget())->totalCost();
+ double p = 100.0 * _factor * _c->subCost(ct) / t->subCost(ct);
+ return QString("%1 %")
+ .arg(p, 0, 'f', Configuration::percentPrecision());
+ }
+ return val.pretty();
+}
+
+
+QPixmap CallMapCallerItem::pixmap(int i) const
+{
+ if (i != 1) return QPixmap();
+
+ // Cost pixmap
+ TraceCostType* ct = ((CallMapView*)widget())->costType();
+ TraceCost* t = ((CallMapView*)widget())->totalCost();
+
+ // colored level meter with frame
+ return costPixmap( ct, _c, t->subCost(ct) / _factor, true );
+}
+
+
+double CallMapCallerItem::value() const
+{
+ TraceCostType* ct;
+ ct = ((CallMapView*)widget())->costType();
+ return (double) _c->subCost(ct);
+}
+
+bool CallMapCallerItem::isMarked(int) const
+{
+ return ((CallMapView*)widget())->selectedItem() == _c->caller();
+}
+
+
+TreeMapItemList* CallMapCallerItem::children()
+{
+ if (!initialized()) {
+ //qDebug("Create Caller subitems (%s)", name().ascii());
+
+ TraceCostType* ct;
+ ct = ((CallMapView*)widget())->costType();
+
+ SubCost s = _c->caller()->inclusive()->subCost(ct);
+ SubCost v = _c->subCost(ct);
+ double newFactor = _factor * v / s;
+
+
+#if 0
+ qDebug("CallerItem: Subitems of %s => %s, factor %f * %d/%d => %f",
+ _c->caller()->prettyName().ascii(),
+ _c->called()->prettyName().ascii(),
+ _factor, v, s, newFactor);
+#endif
+ setSorting(-1);
+
+ TraceCall* call;
+ TraceCallList l = _c->caller()->callers();
+ for (call=l.first();call;call=l.next()) {
+
+ // don't show calls inside of a cycle
+ if (call->inCycle()>0) continue;
+ if (call->isRecursion()) continue;
+
+ TreeMapItem* i = new CallMapCallerItem(newFactor, call);
+ addItem(i);
+ }
+ setSorting(-2, false);
+ }
+
+ return _children;
+}
+
+QColor CallMapCallerItem::backColor() const
+{
+ CallMapView* w = (CallMapView*)widget();
+ return w->groupColor(_c->caller());
+}
+
+void CallMapView::readViewConfig(KConfig* c,
+ QString prefix, QString postfix, bool)
+{
+ KConfigGroup* g = configGroup(c, prefix, postfix);
+
+ setSplitMode(g->readEntry("SplitMode", DEFAULT_SPLITMODE));
+
+ setFieldVisible(0, g->readBoolEntry("DrawName", DEFAULT_DRAWNAME));
+ setFieldVisible(1, g->readBoolEntry("DrawCost", DEFAULT_DRAWCOST));
+ setFieldVisible(2, g->readBoolEntry("DrawLocation", DEFAULT_DRAWLOCATION));
+ setFieldVisible(3, g->readBoolEntry("DrawCalls", DEFAULT_DRAWCALLS));
+
+ bool enable = g->readBoolEntry("ForceStrings", DEFAULT_FORCESTRINGS);
+ setFieldForced(0, enable);
+ setFieldForced(1, enable);
+ setFieldForced(2, enable);
+ setFieldForced(3, enable);
+
+ setAllowRotation(g->readBoolEntry("AllowRotation", DEFAULT_ROTATION));
+ setShadingEnabled(g->readBoolEntry("Shading", DEFAULT_SHADING));
+ setFieldStop(0, g->readEntry("StopName"));
+ setMaxDrawingDepth(g->readNumEntry("MaxDepth", -1));
+ setMinimalArea(g->readNumEntry("MaxArea", DEFAULT_MAXAREA));
+
+ delete g;
+}
+
+void CallMapView::saveViewConfig(KConfig* c,
+ QString prefix, QString postfix, bool)
+{
+ KConfigGroup g(c, (prefix+postfix).ascii());
+
+ writeConfigEntry(&g, "SplitMode", splitModeString(), DEFAULT_SPLITMODE);
+ writeConfigEntry(&g, "DrawName", fieldVisible(0), DEFAULT_DRAWNAME);
+ writeConfigEntry(&g, "DrawCost", fieldVisible(1), DEFAULT_DRAWCOST);
+ writeConfigEntry(&g, "DrawLocation", fieldVisible(2), DEFAULT_DRAWLOCATION);
+ writeConfigEntry(&g, "DrawCalls", fieldVisible(3), DEFAULT_DRAWCALLS);
+ // when option for all text (0-3)
+ writeConfigEntry(&g, "ForceStrings", fieldForced(0), DEFAULT_FORCESTRINGS);
+
+ writeConfigEntry(&g, "AllowRotation", allowRotation(), DEFAULT_ROTATION);
+ writeConfigEntry(&g, "Shading", isShadingEnabled(), DEFAULT_SHADING);
+
+ writeConfigEntry(&g, "StopName", fieldStop(0), "");
+ writeConfigEntry(&g, "MaxDepth", maxDrawingDepth(), -1);
+ writeConfigEntry(&g, "MaxArea", minimalArea(), DEFAULT_MAXAREA);
+}
+
+#include "callmapview.moc"
diff --git a/kcachegrind/kcachegrind/callmapview.h b/kcachegrind/kcachegrind/callmapview.h
new file mode 100644
index 00000000..8561a0ac
--- /dev/null
+++ b/kcachegrind/kcachegrind/callmapview.h
@@ -0,0 +1,129 @@
+/* This file is part of KCachegrind.
+ Copyright (C) 2003 Josef Weidendorfer <Josef.Weidendorfer@gmx.de>
+
+ KCachegrind is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public
+ License as published by the Free Software Foundation, version 2.
+
+ 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; see the file COPYING. If not, write to
+ the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+*/
+
+/*
+ * Call Map View
+ */
+
+#ifndef CALLMAPVIEW_H
+#define CALLMAPVIEW_H
+
+#include "treemap.h"
+#include "tracedata.h"
+#include "traceitemview.h"
+
+class CallMapView: public TreeMapWidget, public TraceItemView
+{
+ Q_OBJECT
+
+public:
+
+ CallMapView(bool showCallers, TraceItemView* parentView,
+ QWidget* parent=0, const char* name=0);
+
+ QWidget* widget() { return this; }
+ QString whatsThis() const;
+ void setData(TraceData*);
+
+ void readViewConfig(KConfig*, QString prefix, QString postfix, bool);
+ void saveViewConfig(KConfig*, QString prefix, QString postfix, bool);
+
+ bool showCallers() const { return _showCallers; }
+ TraceCost* totalCost();
+ QString tipString(TreeMapItem*) const;
+ QColor groupColor(TraceFunction*) const;
+
+private slots:
+ void context(TreeMapItem*,const QPoint &);
+ void selectedSlot(TreeMapItem*, bool);
+ void activatedSlot(TreeMapItem*);
+
+private:
+ TraceItem* canShow(TraceItem*);
+ void doUpdate(int);
+
+ bool _showCallers;
+};
+
+
+
+// Subitems of CallMap
+
+class CallMapBaseItem: public TreeMapItem
+{
+public:
+ CallMapBaseItem();
+
+ void setFunction(TraceFunction* f);
+ TraceFunction* function() { return _f; }
+ int rtti() const { return 1; }
+ double sum() const;
+ double value() const ;
+ bool isMarked(int) const;
+ QString text(int) const;
+ QPixmap pixmap(int) const;
+ TreeMapItemList* children();
+ QColor backColor() const;
+
+private:
+ TraceFunction* _f;
+};
+
+
+class CallMapCallingItem: public TreeMapItem
+{
+public:
+ CallMapCallingItem(double factor, TraceCall* c);
+ void init();
+ int rtti() const { return 2; }
+ int borderWidth() const { return widget()->borderWidth(); }
+ TraceFunction* function() { return _c->called(); }
+ double value() const;
+ double sum() const;
+ bool isMarked(int) const;
+ QString text(int) const;
+ QPixmap pixmap(int) const;
+ TreeMapItemList* children();
+ QColor backColor() const;
+
+private:
+ TraceCall* _c;
+ double _factor;
+};
+
+class CallMapCallerItem: public TreeMapItem
+{
+public:
+ CallMapCallerItem(double factor, TraceCall* c);
+ int rtti() const { return 3; }
+ int borderWidth() const { return widget()->borderWidth(); }
+ TraceFunction* function() { return _c->caller(); }
+ double value() const;
+ bool isMarked(int) const;
+ QString text(int) const;
+ QPixmap pixmap(int) const;
+ TreeMapItemList* children();
+ QColor backColor() const;
+
+private:
+ TraceCall* _c;
+ double _factor;
+};
+
+
+#endif
diff --git a/kcachegrind/kcachegrind/callview.cpp b/kcachegrind/kcachegrind/callview.cpp
new file mode 100644
index 00000000..edd7ee6a
--- /dev/null
+++ b/kcachegrind/kcachegrind/callview.cpp
@@ -0,0 +1,256 @@
+/* This file is part of KCachegrind.
+ Copyright (C) 2003 Josef Weidendorfer <Josef.Weidendorfer@gmx.de>
+
+ KCachegrind is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public
+ License as published by the Free Software Foundation, version 2.
+
+ 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; see the file COPYING. If not, write to
+ the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+*/
+
+/*
+ * Call Views
+ */
+
+#include <qwhatsthis.h>
+#include <qpopupmenu.h>
+#include <klocale.h>
+
+#include "configuration.h"
+#include "callitem.h"
+#include "callview.h"
+
+
+
+//
+// CallView
+//
+
+
+CallView::CallView(bool showCallers, TraceItemView* parentView,
+ QWidget* parent, const char* name)
+ : QListView(parent, name), TraceItemView(parentView)
+{
+ _showCallers = showCallers;
+
+ addColumn( i18n( "Cost" ) );
+ addColumn( i18n( "Cost 2" ) );
+ if (_showCallers) {
+ addColumn( i18n( "Count" ) );
+ addColumn( i18n( "Caller" ) );
+ }
+ else {
+ addColumn( i18n( "Count" ) );
+ addColumn( i18n( "Callee" ) );
+ }
+
+ setSorting(0,false);
+ setColumnAlignment(0, Qt::AlignRight);
+ setColumnAlignment(1, Qt::AlignRight);
+ setColumnAlignment(2, Qt::AlignRight);
+ setAllColumnsShowFocus(true);
+ setResizeMode(QListView::LastColumn);
+ setMinimumHeight(50);
+
+ connect( this,
+ SIGNAL( selectionChanged(QListViewItem*) ),
+ SLOT( selectedSlot(QListViewItem*) ) );
+
+ connect( this,
+ SIGNAL(contextMenuRequested(QListViewItem*, const QPoint &, int)),
+ SLOT(context(QListViewItem*, const QPoint &, int)));
+
+ connect(this,
+ SIGNAL(doubleClicked(QListViewItem*)),
+ SLOT(activatedSlot(QListViewItem*)));
+
+ connect(this,
+ SIGNAL(returnPressed(QListViewItem*)),
+ SLOT(activatedSlot(QListViewItem*)));
+
+ QWhatsThis::add( this, whatsThis() );
+}
+
+QString CallView::whatsThis() const
+{
+ return _showCallers ?
+ i18n( "<b>List of direct Callers</b>"
+ "<p>This list shows all functions calling the "
+ "current selected one directly, together with "
+ "a call count and the cost spent in the current "
+ "selected function while being called from the "
+ "function from the list.</p>"
+ "<p>An icon instead of an inclusive cost specifies "
+ "that this is a call inside of a recursive cycle. "
+ "An inclusive cost makes no sense here.</p>"
+ "<p>Selecting a function makes it the current selected "
+ "one of this information panel. "
+ "If there are two panels (Split mode), the "
+ "function of the other panel is changed instead.</p>") :
+ i18n( "<b>List of direct Callees</b>"
+ "<p>This list shows all functions called by the "
+ "current selected one directly, together with "
+ "a call count and the cost spent in this function "
+ "while being called from the selected function.</p>"
+ "<p>Selecting a function makes it the current selected "
+ "one of this information panel. "
+ "If there are two panels (Split mode), the "
+ "function of the other panel is changed instead.</p>");
+}
+
+
+void CallView::context(QListViewItem* i, const QPoint & p, int col)
+{
+ QPopupMenu popup;
+
+ // Menu entry:
+ TraceCall* c = i ? ((CallItem*) i)->call() : 0;
+ TraceFunction *f = 0, *cycle = 0;
+
+ if (c) {
+ QString name = _showCallers ? c->callerName(true) : c->calledName(true);
+ f = _showCallers ? c->caller(true) : c->called(true);
+ cycle = f->cycle();
+
+ popup.insertItem(i18n("Go to '%1'")
+ .arg(Configuration::shortenSymbol(name)), 93);
+
+ if (cycle) {
+ name = Configuration::shortenSymbol(cycle->prettyName());
+ popup.insertItem(i18n("Go to '%1'").arg(name), 94);
+ }
+
+ popup.insertSeparator();
+ }
+
+ if ((col == 0) || (col == 1)) {
+ addCostMenu(&popup);
+ popup.insertSeparator();
+ }
+ addGoMenu(&popup);
+
+ int r = popup.exec(p);
+ if (r == 93) activated(f);
+ else if (r == 94) activated(cycle);
+}
+
+void CallView::selectedSlot(QListViewItem * i)
+{
+ if (!i) return;
+ TraceCall* c = ((CallItem*) i)->call();
+ // Should we skip cycles here?
+ TraceItem* f = _showCallers ? c->caller(false) : c->called(false);
+
+ _selectedItem = f;
+ selected(f);
+}
+
+void CallView::activatedSlot(QListViewItem * i)
+{
+ if (!i) return;
+ TraceCall* c = ((CallItem*) i)->call();
+ // skip cycles: use the context menu to get to the cycle...
+ TraceItem* f = _showCallers ? c->caller(true) : c->called(true);
+
+ activated(f);
+}
+
+TraceItem* CallView::canShow(TraceItem* i)
+{
+ TraceItem::CostType t = i ? i->type() : TraceItem::NoCostType;
+
+ switch(t) {
+ case TraceItem::Function:
+ case TraceItem::FunctionCycle:
+ return i;
+ default:
+ break;
+ }
+ return 0;
+}
+
+void CallView::doUpdate(int changeType)
+{
+ // Special case ?
+ if (changeType == selectedItemChanged) {
+
+ if (!_selectedItem) {
+ clearSelection();
+ return;
+ }
+
+ CallItem* ci = (CallItem*) QListView::selectedItem();
+ TraceCall* c;
+ TraceItem* ti;
+ if (ci) {
+ c = ci->call();
+ ti = _showCallers ? c->caller() : c->called();
+ if (ti == _selectedItem) return;
+ }
+
+ QListViewItem *item;
+ for (item = firstChild();item;item = item->nextSibling()) {
+ c = ((CallItem*) item)->call();
+ ti = _showCallers ? c->caller() : c->called();
+ if (ti == _selectedItem) {
+ ensureItemVisible(item);
+ setSelected(item, true);
+ break;
+ }
+ }
+ if (!item && ci) clearSelection();
+ return;
+ }
+
+ if (changeType == groupTypeChanged) {
+ QListViewItem *item;
+ for (item = firstChild();item;item = item->nextSibling())
+ ((CallItem*)item)->updateGroup();
+ return;
+ }
+
+ refresh();
+}
+
+void CallView::refresh()
+{
+ clear();
+ setColumnWidth(0, 50);
+ setColumnWidth(1, _costType2 ? 50:0);
+ setColumnWidth(2, 50);
+ if (_costType)
+ setColumnText(0, _costType->name());
+ if (_costType2)
+ setColumnText(1, _costType2->name());
+
+ if (!_data || !_activeItem) return;
+
+ TraceFunction* f = activeFunction();
+ if (!f) return;
+
+ TraceCall* call;
+ // In the call lists, we skip cycles to show the real call relations
+ TraceCallList l = _showCallers ? f->callers(true) : f->callings(true);
+
+ // Allow resizing of column 1
+ setColumnWidthMode(1, QListView::Maximum);
+
+ for (call=l.first();call;call=l.next())
+ if (call->subCost(_costType)>0)
+ new CallItem(this, this, call);
+
+ if (!_costType2) {
+ setColumnWidthMode(1, QListView::Manual);
+ setColumnWidth(1, 0);
+ }
+}
+
+#include "callview.moc"
diff --git a/kcachegrind/kcachegrind/callview.h b/kcachegrind/kcachegrind/callview.h
new file mode 100644
index 00000000..7b5adc79
--- /dev/null
+++ b/kcachegrind/kcachegrind/callview.h
@@ -0,0 +1,55 @@
+/* This file is part of KCachegrind.
+ Copyright (C) 2003 Josef Weidendorfer <Josef.Weidendorfer@gmx.de>
+
+ KCachegrind is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public
+ License as published by the Free Software Foundation, version 2.
+
+ 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; see the file COPYING. If not, write to
+ the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+*/
+
+/*
+ * Call Views
+ */
+
+#ifndef CALLVIEW_H
+#define CALLVIEW_H
+
+#include <qlistview.h>
+#include "tracedata.h"
+#include "traceitemview.h"
+
+class CallView: public QListView, public TraceItemView
+{
+ Q_OBJECT
+
+public:
+ CallView(bool showCallers, TraceItemView* parentView,
+ QWidget* parent=0, const char* name=0);
+
+ virtual QWidget* widget() { return this; }
+ QString whatsThis() const;
+ bool showCallers() const { return _showCallers; }
+
+private slots:
+ void context(QListViewItem*,const QPoint &, int);
+ void selectedSlot(QListViewItem*);
+ void activatedSlot(QListViewItem*);
+
+private:
+ TraceItem* canShow(TraceItem*);
+ void doUpdate(int);
+ void refresh();
+
+ bool _showCallers;
+};
+
+#endif
diff --git a/kcachegrind/kcachegrind/configdlg.cpp b/kcachegrind/kcachegrind/configdlg.cpp
new file mode 100644
index 00000000..61e85dff
--- /dev/null
+++ b/kcachegrind/kcachegrind/configdlg.cpp
@@ -0,0 +1,398 @@
+/* This file is part of KCachegrind.
+ Copyright (C) 2002, 2003 Josef Weidendorfer <Josef.Weidendorfer@gmx.de>
+
+ KCachegrind is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public
+ License as published by the Free Software Foundation, version 2.
+
+ 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; see the file COPYING. If not, write to
+ the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+*/
+
+/*
+ * Configuration Dialog for KCachegrind
+ */
+
+#include <qcombobox.h>
+#include <qcheckbox.h>
+#include <qlineedit.h>
+#include <qlistview.h>
+#include <qdict.h>
+#include <qmessagebox.h>
+
+#include <kcolorbutton.h>
+#include <kfiledialog.h>
+#include <klocale.h>
+#include <knumvalidator.h>
+
+#include "configdlg.h"
+#include "tracedata.h"
+#include "configuration.h"
+
+
+ConfigDlg::ConfigDlg(Configuration* c, TraceData* data,
+ QWidget* parent, const char* name)
+ :ConfigDlgBase(parent, name)
+{
+ _config = c;
+ _data = data;
+ _objectCS = 0;
+ _classCS = 0;
+ _fileCS = 0;
+ KIntValidator * numValidator = new KIntValidator( this );
+ maxListEdit->setValidator(numValidator );
+ symbolCount->setValidator(numValidator );
+ symbolLength->setValidator(numValidator );
+ precisionEdit->setValidator(numValidator );
+ contextEdit->setValidator(numValidator );
+
+#if 0
+ QListViewItem *oItem, *fItem, *cItem, *fnItem;
+ oItem = new(colorList, i18n("ELF Objects"));
+
+ fItem = new(colorList, i18n("Source Files"));
+ cItem = new(colorList, i18n("C++ Classes"));
+ fnItem = new(colorList, i18n("Function (no Grouping)"));
+#endif
+
+ connect(objectCombo, SIGNAL(activated(const QString &)),
+ this, SLOT(objectActivated(const QString &)));
+ connect(objectCombo, SIGNAL(textChanged(const QString &)),
+ this, SLOT(objectActivated(const QString &)));
+ connect(objectCheck, SIGNAL(toggled(bool)),
+ this, SLOT(objectCheckChanged(bool)));
+ connect(objectColor, SIGNAL(changed(const QColor &)),
+ this, SLOT(objectColorChanged(const QColor &)));
+
+ connect(classCombo, SIGNAL(activated(const QString &)),
+ this, SLOT(classActivated(const QString &)));
+ connect(classCombo, SIGNAL(textChanged(const QString &)),
+ this, SLOT(classActivated(const QString &)));
+ connect(classCheck, SIGNAL(toggled(bool)),
+ this, SLOT(classCheckChanged(bool)));
+ connect(classColor, SIGNAL(changed(const QColor &)),
+ this, SLOT(classColorChanged(const QColor &)));
+
+ connect(fileCombo, SIGNAL(activated(const QString &)),
+ this, SLOT(fileActivated(const QString &)));
+ connect(fileCombo, SIGNAL(textChanged(const QString &)),
+ this, SLOT(fileActivated(const QString &)));
+ connect(fileCheck, SIGNAL(toggled(bool)),
+ this, SLOT(fileCheckChanged(bool)));
+ connect(fileColor, SIGNAL(changed(const QColor &)),
+ this, SLOT(fileColorChanged(const QColor &)));
+
+ QString objectPrefix = TraceCost::typeName(TraceCost::Object);
+ QString classPrefix = TraceCost::typeName(TraceCost::Class);
+ QString filePrefix = TraceCost::typeName(TraceCost::File);
+
+ objectCombo->setDuplicatesEnabled(false);
+ classCombo->setDuplicatesEnabled(false);
+ fileCombo->setDuplicatesEnabled(false);
+ objectCombo->setAutoCompletion(true);
+ classCombo->setAutoCompletion(true);
+ fileCombo->setAutoCompletion(true);
+
+ // first unspecified cost items from data
+ TraceObjectMap::Iterator oit;
+ QStringList oList;
+ for ( oit = data->objectMap().begin();
+ oit != data->objectMap().end(); ++oit )
+ oList.append((*oit).prettyName());
+
+ TraceClassMap::Iterator cit;
+ QStringList cList;
+ for ( cit = data->classMap().begin();
+ cit != data->classMap().end(); ++cit )
+ cList.append((*cit).prettyName());
+
+ TraceFileMap::Iterator fit;
+ QStringList fList;
+ for ( fit = data->fileMap().begin();
+ fit != data->fileMap().end(); ++fit )
+ fList.append((*fit).prettyName());
+
+ // then already defined colors (have to check for duplicates!)
+ QDictIterator<Configuration::ColorSetting> it( c->_colors );
+ for( ; it.current(); ++it ) {
+ if ((*it)->automatic) continue;
+
+ QString n = it.currentKey();
+ if (n.startsWith(objectPrefix)) {
+ n = n.remove(0, objectPrefix.length()+1);
+ if (oList.findIndex(n) == -1) oList.append(n);
+ }
+ else if (n.startsWith(classPrefix)) {
+ n = n.remove(0, classPrefix.length()+1);
+ if (cList.findIndex(n) == -1) cList.append(n);
+ }
+ else if (n.startsWith(filePrefix)) {
+ n = n.remove(0, filePrefix.length()+1);
+ if (fList.findIndex(n) == -1) fList.append(n);
+ }
+ }
+
+ oList.sort();
+ cList.sort();
+ fList.sort();
+ objectCombo->insertStringList(oList);
+ classCombo->insertStringList(cList);
+ fileCombo->insertStringList(fList);
+
+ objectActivated(objectCombo->currentText());
+ classActivated(classCombo->currentText());
+ fileActivated(fileCombo->currentText());
+
+ maxListEdit->setText(QString::number(c->_maxListCount));
+
+ _dirItem = 0;
+
+ QListViewItem* i = new QListViewItem(dirList, i18n("(always)"));
+ i->setOpen(true);
+ QStringList::Iterator sit = c->_generalSourceDirs.begin();
+ for(; sit != c->_generalSourceDirs.end(); ++sit ) {
+ QString d = (*sit);
+ if (d.isEmpty()) d = "/";
+ new QListViewItem(i, d);
+ }
+ for ( oit = data->objectMap().begin();
+ oit != data->objectMap().end(); ++oit ) {
+ QString n = (*oit).name();
+ i = new QListViewItem(dirList, n);
+ i->setOpen(true);
+ QStringList* dirs = c->_objectSourceDirs[n];
+ if (!dirs) continue;
+
+ sit = dirs->begin();
+ for(; sit != dirs->end(); ++sit ) {
+ QString d = (*sit);
+ if (d.isEmpty()) d = "/";
+ new QListViewItem(i, d);
+ }
+ }
+
+ connect(dirList, SIGNAL(selectionChanged(QListViewItem*)),
+ this, SLOT(dirsItemChanged(QListViewItem*)));
+ connect(addDirButton, SIGNAL(clicked()),
+ this, SLOT(dirsAddPressed()));
+ connect(deleteDirButton, SIGNAL(clicked()),
+ this, SLOT(dirsDeletePressed()));
+ dirList->setSelected(dirList->firstChild(), true);
+
+ symbolCount->setText(QString::number(c->_maxSymbolCount));
+ symbolLength->setText(QString::number(c->_maxSymbolLength));
+ precisionEdit->setText(QString::number(c->_percentPrecision));
+ contextEdit->setText(QString::number(c->_context));
+}
+
+ConfigDlg::~ConfigDlg()
+{
+}
+
+bool ConfigDlg::configure(Configuration* c, TraceData* d, QWidget* p)
+{
+ ConfigDlg dlg(c, d, p);
+
+ if (dlg.exec()) {
+
+ bool ok;
+ int newValue = dlg.maxListEdit->text().toUInt(&ok);
+ if (ok && newValue < 500)
+ c->_maxListCount = newValue;
+ else
+ QMessageBox::warning(p, i18n("KCachegrind Configuration"),
+ i18n("The Maximum Number of List Items should be below 500."
+ "The previous set value (%1) will still be used.")
+ .arg(QString::number(c->_maxListCount)),
+ QMessageBox::Ok, 0);
+
+ c->_maxSymbolCount = dlg.symbolCount->text().toInt();
+ c->_maxSymbolLength = dlg.symbolLength->text().toInt();
+ c->_percentPrecision = dlg.precisionEdit->text().toInt();
+ c->_context = dlg.contextEdit->text().toInt();
+ return true;
+ }
+ return false;
+}
+
+void ConfigDlg::objectActivated(const QString & s)
+{
+// qDebug("objectActivated: %s", s.ascii());
+
+ if (s.isEmpty()) { _objectCS=0; return; }
+
+ QString n = TraceCost::typeName(TraceCost::Object) + "-" + s;
+
+ Configuration* c = Configuration::config();
+ Configuration::ColorSetting* cs = c->_colors[n];
+ if (!cs)
+ cs = Configuration::color(n);
+// else
+// qDebug("found color %s", n.ascii());
+
+ _objectCS = cs;
+
+ objectCheck->setChecked(cs->automatic);
+ objectColor->setColor(cs->color);
+
+ /*
+ qDebug("Found Color %s, automatic to %s",
+ _objectCS->name.ascii(),
+ _objectCS->automatic ? "true":"false");
+ */
+}
+
+
+void ConfigDlg::objectCheckChanged(bool b)
+{
+ if (_objectCS) {
+ _objectCS->automatic = b;
+ /*
+ qDebug("Set Color %s automatic to %s",
+ _objectCS->name.ascii(),
+ _objectCS->automatic ? "true":"false");
+ */
+ }
+}
+
+void ConfigDlg::objectColorChanged(const QColor & c)
+{
+ if (_objectCS) _objectCS->color = c;
+}
+
+void ConfigDlg::classActivated(const QString & s)
+{
+// qDebug("classActivated: %s", s.ascii());
+
+ if (s.isEmpty()) { _classCS=0; return; }
+
+ QString n = TraceCost::typeName(TraceCost::Class) + "-" + s;
+
+ Configuration* c = Configuration::config();
+ Configuration::ColorSetting* cs = c->_colors[n];
+ if (!cs)
+ cs = Configuration::color(n);
+
+ _classCS = cs;
+
+ classCheck->setChecked(cs->automatic);
+ classColor->setColor(cs->color);
+
+}
+
+
+void ConfigDlg::classCheckChanged(bool b)
+{
+ if (_classCS) _classCS->automatic = b;
+}
+
+void ConfigDlg::classColorChanged(const QColor & c)
+{
+ if (_classCS) _classCS->color = c;
+}
+
+
+void ConfigDlg::fileActivated(const QString & s)
+{
+// qDebug("fileActivated: %s", s.ascii());
+
+ if (s.isEmpty()) { _fileCS=0; return; }
+
+ QString n = TraceCost::typeName(TraceCost::File) + "-" + s;
+
+ Configuration* c = Configuration::config();
+ Configuration::ColorSetting* cs = c->_colors[n];
+ if (!cs)
+ cs = Configuration::color(n);
+
+ _fileCS = cs;
+
+ fileCheck->setChecked(cs->automatic);
+ fileColor->setColor(cs->color);
+}
+
+
+void ConfigDlg::fileCheckChanged(bool b)
+{
+ if (_fileCS) _fileCS->automatic = b;
+}
+
+void ConfigDlg::fileColorChanged(const QColor & c)
+{
+ if (_fileCS) _fileCS->color = c;
+}
+
+
+void ConfigDlg::dirsItemChanged(QListViewItem* i)
+{
+ _dirItem = i;
+ deleteDirButton->setEnabled(i->depth() == 1);
+ addDirButton->setEnabled(i->depth() == 0);
+}
+
+void ConfigDlg::dirsDeletePressed()
+{
+ if (!_dirItem || (_dirItem->depth() == 0)) return;
+ QListViewItem* p = _dirItem->parent();
+ if (!p) return;
+
+ Configuration* c = Configuration::config();
+ QString objName = p->text(0);
+
+ QStringList* dirs;
+ if (objName == i18n("(always)"))
+ dirs = &(c->_generalSourceDirs);
+ else
+ dirs = c->_objectSourceDirs[objName];
+ if (!dirs) return;
+
+ dirs->remove(_dirItem->text(0));
+ delete _dirItem;
+ _dirItem = 0;
+
+ deleteDirButton->setEnabled(false);
+}
+
+void ConfigDlg::dirsAddPressed()
+{
+ if (!_dirItem || (_dirItem->depth() >0)) return;
+
+ Configuration* c = Configuration::config();
+ QString objName = _dirItem->text(0);
+
+ QStringList* dirs;
+ if (objName == i18n("(always)"))
+ dirs = &(c->_generalSourceDirs);
+ else {
+ dirs = c->_objectSourceDirs[objName];
+ if (!dirs) {
+ dirs = new QStringList;
+ c->_objectSourceDirs.insert(objName, dirs);
+ }
+ }
+
+ QString newDir;
+ newDir = KFileDialog::getExistingDirectory(QString::null,
+ this,
+ i18n("Choose Source Folder"));
+ if (newDir.isEmpty()) return;
+
+ // even for "/", we strip the tailing slash
+ if (newDir.endsWith("/"))
+ newDir = newDir.left(newDir.length()-1);
+
+ if (dirs->findIndex(newDir)>=0) return;
+
+ dirs->append(newDir);
+ if (newDir.isEmpty()) newDir = QString("/");
+ new QListViewItem(_dirItem, newDir);
+}
+
+#include "configdlg.moc"
diff --git a/kcachegrind/kcachegrind/configdlg.h b/kcachegrind/kcachegrind/configdlg.h
new file mode 100644
index 00000000..d8bd2f89
--- /dev/null
+++ b/kcachegrind/kcachegrind/configdlg.h
@@ -0,0 +1,64 @@
+/* This file is part of KCachegrind.
+ Copyright (C) 2002, 2003 Josef Weidendorfer <Josef.Weidendorfer@gmx.de>
+
+ KCachegrind is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public
+ License as published by the Free Software Foundation, version 2.
+
+ 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; see the file COPYING. If not, write to
+ the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+*/
+
+/*
+ * Configuration Dialog for KCachegrind
+ */
+
+#ifndef CONFIGDLG_H
+#define CONFIGDLG_H
+
+#include "configdlgbase.h"
+#include "configuration.h"
+
+class TraceData;
+
+class ConfigDlg : public ConfigDlgBase
+{
+ Q_OBJECT
+
+public:
+ ConfigDlg(Configuration*, TraceData*,
+ QWidget* parent = 0, const char* name = 0);
+ ~ConfigDlg();
+
+ static bool configure(Configuration*, TraceData*, QWidget*);
+
+protected slots:
+ void objectActivated(const QString &);
+ void objectCheckChanged(bool);
+ void objectColorChanged(const QColor &);
+ void classActivated(const QString &);
+ void classCheckChanged(bool);
+ void classColorChanged(const QColor &);
+ void fileActivated(const QString &);
+ void fileCheckChanged(bool);
+ void fileColorChanged(const QColor &);
+ void dirsItemChanged(QListViewItem*);
+ void dirsDeletePressed();
+ void dirsAddPressed();
+
+private:
+ Configuration* _config;
+ TraceData* _data;
+
+ Configuration::ColorSetting *_objectCS, *_classCS, *_fileCS;
+ QListViewItem* _dirItem;
+};
+
+#endif
diff --git a/kcachegrind/kcachegrind/configdlgbase.ui b/kcachegrind/kcachegrind/configdlgbase.ui
new file mode 100644
index 00000000..bf2c1bd8
--- /dev/null
+++ b/kcachegrind/kcachegrind/configdlgbase.ui
@@ -0,0 +1,653 @@
+<!DOCTYPE UI><UI version="3.1" stdsetdef="1">
+<class>ConfigDlgBase</class>
+<widget class="QDialog">
+ <property name="name">
+ <cstring>configDlgBase</cstring>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>447</width>
+ <height>378</height>
+ </rect>
+ </property>
+ <property name="caption">
+ <string>Configuration</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="QTabWidget">
+ <property name="name">
+ <cstring>tabWidget2</cstring>
+ </property>
+ <widget class="QWidget">
+ <property name="name">
+ <cstring>tab</cstring>
+ </property>
+ <attribute name="title">
+ <string>General</string>
+ </attribute>
+ <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="QLineEdit" row="3" column="2" rowspan="1" colspan="2">
+ <property name="name">
+ <cstring>precisionEdit</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>7</hsizetype>
+ <vsizetype>0</vsizetype>
+ <horstretch>2</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ </widget>
+ <widget class="QLabel" row="2" column="1">
+ <property name="name">
+ <cstring>TextLabel2</cstring>
+ </property>
+ <property name="text">
+ <string>Truncated when more/longer than:</string>
+ </property>
+ </widget>
+ <widget class="QLabel" row="3" column="0" rowspan="1" colspan="2">
+ <property name="name">
+ <cstring>TextLabel4_3</cstring>
+ </property>
+ <property name="text">
+ <string>Precision of percentage values:</string>
+ </property>
+ </widget>
+ <widget class="QLabel" row="1" column="0" rowspan="1" colspan="3">
+ <property name="name">
+ <cstring>TextLabel3</cstring>
+ </property>
+ <property name="text">
+ <string>Symbols in tooltips and context menus</string>
+ </property>
+ </widget>
+ <widget class="QLineEdit" row="2" column="3">
+ <property name="name">
+ <cstring>symbolLength</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>4</hsizetype>
+ <vsizetype>0</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ </widget>
+ <spacer row="2" column="0">
+ <property name="name">
+ <cstring>Spacer6_2_2_2</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Fixed</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>16</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ <widget class="QLineEdit" row="0" column="2" rowspan="1" colspan="2">
+ <property name="name">
+ <cstring>maxListEdit</cstring>
+ </property>
+ </widget>
+ <widget class="QLineEdit" row="2" column="2">
+ <property name="name">
+ <cstring>symbolCount</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>4</hsizetype>
+ <vsizetype>0</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ </widget>
+ <widget class="QLabel" row="0" column="0" rowspan="1" colspan="2">
+ <property name="name">
+ <cstring>TextLabel5</cstring>
+ </property>
+ <property name="text">
+ <string>Maximum number of items in lists:</string>
+ </property>
+ </widget>
+ </grid>
+ </widget>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>TextLabel1</cstring>
+ </property>
+ <property name="font">
+ <font>
+ <bold>1</bold>
+ </font>
+ </property>
+ <property name="frameShape">
+ <enum>NoFrame</enum>
+ </property>
+ <property name="frameShadow">
+ <enum>Plain</enum>
+ </property>
+ <property name="text">
+ <string>Cost Item Colors</string>
+ </property>
+ </widget>
+ <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>
+ <spacer row="1" column="1">
+ <property name="name">
+ <cstring>Spacer9</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>
+ <spacer row="0" column="0">
+ <property name="name">
+ <cstring>Spacer6</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Fixed</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>16</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ <widget class="QLayoutWidget" row="0" column="1">
+ <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="QComboBox" row="1" column="1">
+ <property name="name">
+ <cstring>classCombo</cstring>
+ </property>
+ <property name="maximumSize">
+ <size>
+ <width>300</width>
+ <height>32767</height>
+ </size>
+ </property>
+ <property name="editable">
+ <bool>true</bool>
+ </property>
+ </widget>
+ <widget class="QCheckBox" row="2" column="2">
+ <property name="name">
+ <cstring>fileCheck</cstring>
+ </property>
+ <property name="text">
+ <string>Automatic</string>
+ </property>
+ </widget>
+ <widget class="QLabel" row="0" column="0">
+ <property name="name">
+ <cstring>TextLabel4</cstring>
+ </property>
+ <property name="text">
+ <string>Object:</string>
+ </property>
+ </widget>
+ <widget class="QLabel" row="1" column="0">
+ <property name="name">
+ <cstring>TextLabel4_2_2</cstring>
+ </property>
+ <property name="text">
+ <string>Class:</string>
+ </property>
+ </widget>
+ <widget class="KColorButton" row="2" column="3">
+ <property name="name">
+ <cstring>fileColor</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>
+ <widget class="QCheckBox" row="1" column="2">
+ <property name="name">
+ <cstring>classCheck</cstring>
+ </property>
+ <property name="text">
+ <string>Automatic</string>
+ </property>
+ </widget>
+ <widget class="KColorButton" row="0" column="3">
+ <property name="name">
+ <cstring>objectColor</cstring>
+ </property>
+ <property name="text">
+ <string></string>
+ </property>
+ </widget>
+ <widget class="QCheckBox" row="0" column="2">
+ <property name="name">
+ <cstring>objectCheck</cstring>
+ </property>
+ <property name="text">
+ <string>Automatic</string>
+ </property>
+ </widget>
+ <widget class="QLabel" row="2" column="0">
+ <property name="name">
+ <cstring>TextLabel4_2</cstring>
+ </property>
+ <property name="text">
+ <string>File:</string>
+ </property>
+ </widget>
+ <widget class="KColorButton" row="1" column="3">
+ <property name="name">
+ <cstring>classColor</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>
+ <widget class="QComboBox" row="2" column="1">
+ <property name="name">
+ <cstring>fileCombo</cstring>
+ </property>
+ <property name="maximumSize">
+ <size>
+ <width>300</width>
+ <height>32767</height>
+ </size>
+ </property>
+ <property name="editable">
+ <bool>true</bool>
+ </property>
+ </widget>
+ <widget class="QComboBox" row="0" column="1">
+ <property name="name">
+ <cstring>objectCombo</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>3</hsizetype>
+ <vsizetype>0</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="maximumSize">
+ <size>
+ <width>300</width>
+ <height>32767</height>
+ </size>
+ </property>
+ <property name="editable">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </grid>
+ </widget>
+ </grid>
+ </widget>
+ </vbox>
+ </widget>
+ <widget class="QWidget">
+ <property name="name">
+ <cstring>tab</cstring>
+ </property>
+ <attribute name="title">
+ <string>Annotations</string>
+ </attribute>
+ <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="QLabel">
+ <property name="name">
+ <cstring>TextLabel4_3_2</cstring>
+ </property>
+ <property name="text">
+ <string>Context lines in annotations:</string>
+ </property>
+ </widget>
+ <widget class="QLineEdit">
+ <property name="name">
+ <cstring>contextEdit</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>7</hsizetype>
+ <vsizetype>0</vsizetype>
+ <horstretch>2</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ </widget>
+ </hbox>
+ </widget>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>TextLabel1_2</cstring>
+ </property>
+ <property name="font">
+ <font>
+ <bold>1</bold>
+ </font>
+ </property>
+ <property name="text">
+ <string>Source Folders</string>
+ </property>
+ </widget>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>layout11</cstring>
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <spacer row="0" column="0">
+ <property name="name">
+ <cstring>Spacer6_2</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Fixed</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>16</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ <widget class="QListView" row="0" column="1">
+ <column>
+ <property name="text">
+ <string>Object / Related Source Base</string>
+ </property>
+ <property name="clickable">
+ <bool>true</bool>
+ </property>
+ <property name="resizable">
+ <bool>true</bool>
+ </property>
+ </column>
+ <property name="name">
+ <cstring>dirList</cstring>
+ </property>
+ <property name="rootIsDecorated">
+ <bool>true</bool>
+ </property>
+ </widget>
+ <widget class="QLayoutWidget" row="0" column="2">
+ <property name="name">
+ <cstring>layout10</cstring>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QPushButton">
+ <property name="name">
+ <cstring>addDirButton</cstring>
+ </property>
+ <property name="text">
+ <string>Add...</string>
+ </property>
+ </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>49</height>
+ </size>
+ </property>
+ </spacer>
+ <widget class="QPushButton">
+ <property name="name">
+ <cstring>deleteDirButton</cstring>
+ </property>
+ <property name="text">
+ <string>Delete</string>
+ </property>
+ </widget>
+ </vbox>
+ </widget>
+ <spacer row="1" column="1">
+ <property name="name">
+ <cstring>Spacer9_2</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>
+ </grid>
+ </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>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>
+ <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>210</width>
+ <height>0</height>
+ </size>
+ </property>
+ </spacer>
+ <widget class="QPushButton">
+ <property name="name">
+ <cstring>PushButton2</cstring>
+ </property>
+ <property name="text">
+ <string>&amp;OK</string>
+ </property>
+ <property name="default">
+ <bool>true</bool>
+ </property>
+ </widget>
+ <widget class="QPushButton">
+ <property name="name">
+ <cstring>PushButton1</cstring>
+ </property>
+ <property name="text">
+ <string>&amp;Cancel</string>
+ </property>
+ </widget>
+ </hbox>
+ </widget>
+ </vbox>
+</widget>
+<connections>
+ <connection>
+ <sender>PushButton2</sender>
+ <signal>clicked()</signal>
+ <receiver>configDlgBase</receiver>
+ <slot>accept()</slot>
+ </connection>
+ <connection>
+ <sender>PushButton1</sender>
+ <signal>clicked()</signal>
+ <receiver>configDlgBase</receiver>
+ <slot>reject()</slot>
+ </connection>
+ <connection>
+ <sender>classCheck</sender>
+ <signal>toggled(bool)</signal>
+ <receiver>classColor</receiver>
+ <slot>setDisabled(bool)</slot>
+ </connection>
+ <connection>
+ <sender>fileCheck</sender>
+ <signal>toggled(bool)</signal>
+ <receiver>fileColor</receiver>
+ <slot>setDisabled(bool)</slot>
+ </connection>
+ <connection>
+ <sender>objectCheck</sender>
+ <signal>toggled(bool)</signal>
+ <receiver>objectColor</receiver>
+ <slot>setDisabled(bool)</slot>
+ </connection>
+</connections>
+<tabstops>
+ <tabstop>objectCombo</tabstop>
+ <tabstop>objectCheck</tabstop>
+ <tabstop>classCombo</tabstop>
+ <tabstop>classCheck</tabstop>
+ <tabstop>classColor</tabstop>
+ <tabstop>fileCombo</tabstop>
+ <tabstop>fileCheck</tabstop>
+ <tabstop>fileColor</tabstop>
+ <tabstop>maxListEdit</tabstop>
+ <tabstop>PushButton1</tabstop>
+ <tabstop>PushButton2</tabstop>
+</tabstops>
+<includes>
+ <include location="global" impldecl="in implementation">kcolorbutton.h</include>
+</includes>
+<pixmapinproject/>
+<layoutdefaults spacing="6" margin="11"/>
+</UI>
diff --git a/kcachegrind/kcachegrind/configuration.cpp b/kcachegrind/kcachegrind/configuration.cpp
new file mode 100644
index 00000000..f04f434b
--- /dev/null
+++ b/kcachegrind/kcachegrind/configuration.cpp
@@ -0,0 +1,490 @@
+/* This file is part of KCachegrind.
+ Copyright (C) 2002, 2003 Josef Weidendorfer <Josef.Weidendorfer@gmx.de>
+
+ KCachegrind is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public
+ License as published by the Free Software Foundation, version 2.
+
+ 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; see the file COPYING. If not, write to
+ the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+*/
+
+/*
+ * Configuration for KCachegrind
+ */
+
+#include <kconfig.h>
+#include <klocale.h>
+#include <kdebug.h>
+
+#include "configuration.h"
+#include "tracedata.h"
+#include "configdlgbase.h"
+
+#include "traceitemview.h"
+
+//
+// Some predefined cost types...
+//
+
+static QStringList knownTypes()
+{
+ QStringList l;
+
+ l << "Ir" << "Dr" << "Dw"
+ << "I1mr" << "D1mr" << "D1mw"
+ << "I2mr" << "D2mr" << "D2mw"
+
+ << "Smp" << "Sys" << "User"
+ << "L1m" << "L2m" << "CEst";
+
+ return l;
+}
+
+
+static QString knownFormula(QString name)
+{
+ if (name =="L1m") return QString("I1mr + D1mr + D1mw");
+ if (name =="L2m") return QString("I2mr + D2mr + D2mw");
+ if (name =="CEst") return QString("Ir + 10 L1m + 100 L2m");
+
+ return QString::null;
+}
+
+static QString knownLongName(QString name)
+{
+ if (name == "Ir") return i18n("Instruction Fetch");
+ if (name =="Dr") return i18n("Data Read Access");
+ if (name =="Dw") return i18n("Data Write Access");
+ if (name =="I1mr") return i18n("L1 Instr. Fetch Miss");
+ if (name =="D1mr") return i18n("L1 Data Read Miss");
+ if (name =="D1mw") return i18n("L1 Data Write Miss");
+ if (name =="I2mr") return i18n("L2 Instr. Fetch Miss");
+ if (name =="D2mr") return i18n("L2 Data Read Miss");
+ if (name =="D2mw") return i18n("L2 Data Write Miss");
+ if (name =="Smp") return i18n("Samples");
+ if (name =="Sys") return i18n("System Time");
+ if (name =="User") return i18n("User Time");
+ if (name =="L1m") return i18n("L1 Miss Sum");
+ if (name =="L2m") return i18n("L2 Miss Sum");
+ if (name =="CEst") return i18n("Cycle Estimation");
+
+ return QString::null;
+}
+
+
+
+
+//
+// Configuration
+//
+
+Configuration* Configuration::_config = 0;
+
+Configuration::Configuration()
+ :_colors(517)
+{
+ _config = 0;
+
+ _colors.setAutoDelete(true);
+ _objectSourceDirs.setAutoDelete(true);
+
+ // defaults
+ _showPercentage = true;
+ _showExpanded = false;
+ _showCycles = true;
+ _cycleCut = 0.0;
+ _percentPrecision = 2;
+
+ // max symbol count/length in tooltip/popup
+ _maxSymbolLength = 30;
+ _maxSymbolCount = 10;
+ _maxListCount = 100;
+
+ // annotation behaviour
+ _context = 3;
+ _noCostInside = 20;
+}
+
+Configuration* Configuration::config()
+{
+ if (!_config)
+ _config = new Configuration();
+
+ return _config;
+}
+
+
+void Configuration::saveOptions(KConfig* kconfig)
+{
+ Configuration* c = config();
+
+ // color options
+ KConfigGroup colorConfig(kconfig, QCString("CostColors"));
+ QDictIterator<ColorSetting> it( c->_colors );
+ int count = 1;
+ for( ; it.current(); ++it ) {
+ if ( !(*it)->automatic ) {
+ colorConfig.writeEntry( QString("Name%1").arg(count),
+ it.currentKey());
+ colorConfig.writeEntry( QString("Color%1").arg(count),
+ (*it)->color);
+ //qDebug("Written Color %s (%d)", it.currentKey().ascii(), count);
+
+ count++;
+ }
+ }
+ colorConfig.writeEntry( "Count", count-1);
+
+ // source options
+ KConfigGroup sourceConfig(kconfig, QCString("Source"));
+ sourceConfig.writeEntry("Dirs", c->_generalSourceDirs, ':');
+ QDictIterator<QStringList> it2( c->_objectSourceDirs );
+ count = 1;
+ for( ; it2.current(); ++it2 ) {
+ sourceConfig.writeEntry( QString("Object%1").arg(count),
+ it2.currentKey());
+ sourceConfig.writeEntry( QString("Dirs%1").arg(count),
+ *(*it2), ':');
+ count++;
+ }
+ sourceConfig.writeEntry( "Count", count-1);
+
+ // general options
+ KConfigGroup generalConfig(kconfig, QCString("General"));
+ generalConfig.writeEntry("ShowPercentage", c->_showPercentage);
+ generalConfig.writeEntry("ShowExpanded", c->_showExpanded);
+ generalConfig.writeEntry("ShowCycles", c->_showCycles);
+ generalConfig.writeEntry("CycleCut", c->_cycleCut);
+ generalConfig.writeEntry("MaxSymbolCount", c->_maxSymbolCount);
+ generalConfig.writeEntry("MaxListCount", c->_maxListCount);
+ generalConfig.writeEntry("MaxSymbolLength", c->_maxSymbolLength);
+ generalConfig.writeEntry("PercentPrecision", c->_percentPrecision);
+
+ generalConfig.writeEntry("Context", c->_context);
+ generalConfig.writeEntry("NoCostInside", c->_noCostInside);
+
+ KConfigGroup ctConfig(kconfig, QCString("CostTypes"));
+ int ctCount = TraceCostType::knownTypeCount();
+ ctConfig.writeEntry( "Count", ctCount);
+ for (int i=0; i<ctCount; i++) {
+ TraceCostType* t = TraceCostType::knownType(i);
+ ctConfig.writeEntry( QString("Name%1").arg(i+1), t->name());
+
+ // Use localized key
+ TraceItemView::writeConfigEntry(&ctConfig,
+ QString("Longname%1").arg(i+1).ascii(),
+ t->longName(),
+ knownLongName(t->name()).utf8().data() /*, true */ );
+ TraceItemView::writeConfigEntry(&ctConfig,
+ QString("Formula%1").arg(i+1).ascii(),
+ t->formula(), knownFormula(t->name()).utf8().data());
+ }
+}
+
+
+
+
+void Configuration::readOptions(KConfig* kconfig)
+{
+ int i, count;
+ Configuration* c = config();
+
+ // color options
+ c->_colors.clear();
+
+ // colors for default cost types:
+ // red for L2 misses, green for L1 misses, blue for normal accesses
+ c->color("CostType-I2mr")->color = QColor(240, 0, 0);
+ c->color("CostType-D2mr")->color = QColor(180,40,40);
+ c->color("CostType-D2mw")->color = QColor(120,80,80);
+
+ c->color("CostType-I1mr")->color = QColor(0, 240, 0);
+ c->color("CostType-D1mr")->color = QColor(40,180,40);
+ c->color("CostType-D1mw")->color = QColor(80,120,80);
+
+ c->color("CostType-Ir")->color = QColor(0, 0, 240);
+ c->color("CostType-Dr")->color = QColor(40,40,180);
+ c->color("CostType-Dw")->color = QColor(80,80,120);
+
+ KConfigGroup colorConfig(kconfig, QCString("CostColors"));
+ count = colorConfig.readNumEntry("Count", 0);
+ for (i=1;i<=count;i++) {
+ QString n = colorConfig.readEntry(QString("Name%1").arg(i));
+ QColor color = colorConfig.readColorEntry(QString("Color%1").arg(i));
+
+ if (n.isEmpty()) continue;
+
+ ColorSetting* cs = new ColorSetting;
+ cs->name = n;
+ cs->automatic = false;
+ cs->color = color;
+
+ c->_colors.insert(n, cs);
+
+ //qDebug("Read Color %s", n.ascii());
+ }
+
+ // source options
+ KConfigGroup sourceConfig(kconfig, QCString("Source"));
+ QStringList dirs;
+ dirs = sourceConfig.readListEntry("Dirs", ':');
+ if (dirs.count()>0) c->_generalSourceDirs = dirs;
+ count = sourceConfig.readNumEntry("Count", 0);
+ c->_objectSourceDirs.clear();
+ if (count>17) c->_objectSourceDirs.resize(count);
+ for (i=1;i<=count;i++) {
+ QString n = sourceConfig.readEntry(QString("Object%1").arg(i));
+ dirs = sourceConfig.readListEntry(QString("Dirs%1").arg(i), ':');
+
+ if (n.isEmpty() || (dirs.count()==0)) continue;
+
+ c->_objectSourceDirs.insert(n, new QStringList(dirs));
+ }
+
+
+ // general options
+ KConfigGroup generalConfig(kconfig, QCString("General"));
+ c->_showPercentage = generalConfig.readBoolEntry("ShowPercentage", true);
+ c->_showExpanded = generalConfig.readBoolEntry("ShowExpanded", false);
+ c->_showCycles = generalConfig.readBoolEntry("ShowCycles", true);
+ c->_cycleCut = generalConfig.readDoubleNumEntry("CycleCut", 0.0);
+ c->_maxSymbolCount = generalConfig.readNumEntry("MaxSymbolCount", 10);
+ c->_maxListCount = generalConfig.readNumEntry("MaxListCount", 100);
+ c->_maxSymbolLength = generalConfig.readNumEntry("MaxSymbolLength", 30);
+ c->_percentPrecision = generalConfig.readNumEntry("PercentPrecision", 2);
+
+ c->_context = generalConfig.readNumEntry("Context", 3);
+ c->_noCostInside = generalConfig.readNumEntry("NoCostInside", 20);
+
+ // known cost types
+ if (TraceCostType::knownTypeCount()==0) {
+
+ KConfigGroup ctConfig(kconfig, QCString("CostTypes"));
+ int ctCount = ctConfig.readNumEntry("Count", 0);
+ if (ctCount>0) {
+ for (int i=1;i<=ctCount;i++) {
+ QString n = ctConfig.readEntry(QString("Name%1").arg(i));
+ QString l = ctConfig.readEntry(QString("Longname%1").arg(i));
+ if (l.isEmpty()) l = knownLongName(n);
+ QString f = ctConfig.readEntry(QString("Formula%1").arg(i));
+ if (f.isEmpty()) f = knownFormula(n);
+
+ TraceCostType::add(new TraceCostType(n, l, f));
+ }
+ }
+ else {
+ // add default types
+
+ QString longName, formula;
+ TraceCostType* ct;
+ QStringList l = knownTypes();
+ for ( QStringList::Iterator it = l.begin();
+ it != l.end(); ++it ) {
+ longName = knownLongName(*it);
+ formula = knownFormula(*it);
+ ct = new TraceCostType(*it, longName, formula);
+ TraceCostType::add(ct);
+ }
+ }
+ }
+}
+
+QColor Configuration::groupColor(TraceItem* cost)
+{
+ QString n;
+
+ if (!cost)
+ n = QString("default");
+ else
+ n = TraceCost::typeName(cost->type()) + "-" + cost->prettyName();
+
+ return color(n)->color;
+}
+
+QColor Configuration::costTypeColor(TraceCostType* t)
+{
+ QString n;
+
+ if (!t)
+ n = QString("CostType-default");
+ else
+ n = QString("CostType-%1").arg(t->name());
+
+ return color(n)->color;
+}
+
+QColor Configuration::functionColor(TraceCost::CostType gt,
+ TraceFunction* f)
+{
+ TraceCost* group = f;
+ QString n;
+
+ switch(gt) {
+ case TraceCost::Object: group = f->object(); break;
+ case TraceCost::Class: group = f->cls(); break;
+ case TraceCost::File: group = f->file(); break;
+ default:
+ break;
+ }
+
+ if (group != f) {
+ // first look for manual color of a function in a group
+ n = TraceCost::typeName(group->type()) +
+ "-" + group->prettyName() +
+ "-" + f->prettyName();
+
+ ColorSetting* cs = color(n, false);
+ if (cs) return cs->color;
+ }
+ return groupColor(group);
+}
+
+Configuration::ColorSetting* Configuration::color(QString n, bool createNew)
+{
+// qDebug("Color for %s", n.latin1());
+
+ // predefined ?
+ Configuration* c = config();
+ ColorSetting* cs = c->_colors[n];
+ if (cs || !createNew) return cs;
+
+ // automatic colors...
+ int h = 0, s = 100;
+ const char* str = n.ascii();
+ while (*str) {
+ h = (h * 37 + s* (unsigned)*str) % 256;
+ s = (s * 17 + h* (unsigned)*str) % 192;
+ str++;
+ }
+
+ //qDebug("New color for %s: H %d, S %d", n.ascii(), h, 64+s);
+ QColor color = QColor(h, 64+s, 192, QColor::Hsv);
+
+ cs = new ColorSetting;
+ cs->name = n;
+ cs->automatic = true;
+ cs->color = color;
+ c->_colors.insert(n, cs);
+
+ //qDebug("new Color %s", n.ascii());
+
+ return cs;
+}
+
+/* Gives back a list of all Source Base Directories of Objects in
+ * current trace. If a special object is given in 2nd argument,
+ * put its Source Base in front.
+ */
+QStringList Configuration::sourceDirs(TraceData* data, TraceObject* o)
+{
+ QStringList l = config()->_generalSourceDirs, *ol, *ol2 = 0;
+ TraceObjectMap::Iterator oit;
+ for ( oit = data->objectMap().begin();
+ oit != data->objectMap().end(); ++oit ) {
+ ol = config()->_objectSourceDirs[(*oit).name()];
+ if (&(*oit) == o) {
+ ol2 = ol;
+ continue;
+ }
+ if (!ol) continue;
+
+ for(unsigned int i=0;i<ol->count();i++)
+ l.prepend( (*ol)[i] );
+ }
+ if (ol2) {
+ for(unsigned int i=0;i<ol2->count();i++)
+ l.prepend( (*ol2)[i] );
+ }
+ if (0) kdDebug() << "Configuration::sourceDirs: " << l.join(":") << endl;
+
+ return l;
+}
+
+bool Configuration::showPercentage()
+{
+ return config()->_showPercentage;
+}
+
+bool Configuration::showExpanded()
+{
+ return config()->_showExpanded;
+}
+
+bool Configuration::showCycles()
+{
+ return config()->_showCycles;
+}
+
+void Configuration::setShowPercentage(bool s)
+{
+ Configuration* c = config();
+ if (c->_showPercentage == s) return;
+
+ c->_showPercentage = s;
+}
+
+void Configuration::setShowExpanded(bool s)
+{
+ Configuration* c = config();
+ if (c->_showExpanded == s) return;
+
+ c->_showExpanded = s;
+}
+
+void Configuration::setShowCycles(bool s)
+{
+ Configuration* c = config();
+ if (c->_showCycles == s) return;
+
+ c->_showCycles = s;
+}
+
+double Configuration::cycleCut()
+{
+ return config()->_cycleCut;
+}
+
+int Configuration::percentPrecision()
+{
+ return config()->_percentPrecision;
+}
+
+int Configuration::maxSymbolLength()
+{
+ return config()->_maxSymbolLength;
+}
+
+QString Configuration::shortenSymbol(QString s)
+{
+ if ((int)s.length() > maxSymbolLength())
+ s = s.left(maxSymbolLength()) + "...";
+ return s;
+}
+
+int Configuration::maxListCount()
+{
+ return config()->_maxListCount;
+}
+
+int Configuration::maxSymbolCount()
+{
+ return config()->_maxSymbolCount;
+}
+
+int Configuration::context()
+{
+ return config()->_context;
+}
+
+int Configuration::noCostInside()
+{
+ return config()->_noCostInside;
+}
diff --git a/kcachegrind/kcachegrind/configuration.h b/kcachegrind/kcachegrind/configuration.h
new file mode 100644
index 00000000..6c808c0c
--- /dev/null
+++ b/kcachegrind/kcachegrind/configuration.h
@@ -0,0 +1,101 @@
+/* This file is part of KCachegrind.
+ Copyright (C) 2002, 2003 Josef Weidendorfer <Josef.Weidendorfer@gmx.de>
+
+ KCachegrind is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public
+ License as published by the Free Software Foundation, version 2.
+
+ 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; see the file COPYING. If not, write to
+ the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+*/
+
+/*
+ * Configuration for KCachegrind
+ */
+
+#ifndef CONFIGURATION_H
+#define CONFIGURATION_H
+
+#include <qcolor.h>
+#include <qstringlist.h>
+#include <qdict.h>
+
+#include "tracedata.h"
+
+class KConfig;
+
+class Configuration
+{
+ friend class ConfigDlg;
+
+public:
+ Configuration();
+
+ static Configuration* config();
+
+ static void saveOptions(KConfig*);
+ static void readOptions(KConfig*);
+
+ // color for visualisation of an object
+ static QColor functionColor(TraceItem::CostType gt, TraceFunction*);
+ static QColor groupColor(TraceItem*);
+ static QColor costTypeColor(TraceCostType*);
+ static QStringList sourceDirs(TraceData*, TraceObject* o = 0);
+ static bool showPercentage();
+ static bool showExpanded();
+ static bool showCycles();
+
+ // lower percentage limit of cost items filled into lists
+ static int percentPrecision();
+ // max symbol lengths/count in tooltip/popup
+ static int maxSymbolLength();
+ // strip a symbol name according to <maxSymbolLength>
+ static QString shortenSymbol(QString);
+ static int maxSymbolCount();
+ // max. number of items in lists
+ static int maxListCount();
+
+ // how many lines of context to show before/after annotated source/assembler
+ static int context();
+ // how many lines without cost are still regarded as inside a function
+ static int noCostInside();
+
+ static void setShowPercentage(bool);
+ static void setShowExpanded(bool);
+
+ static void setShowCycles(bool);
+ // upper limit for cutting of a call in cycle detection
+ static double cycleCut();
+
+private:
+ struct ColorSetting {
+ QString name;
+ QColor color;
+ bool automatic;
+ };
+
+ static ColorSetting* color(QString, bool createNew = true);
+
+ QDict<ColorSetting> _colors;
+
+ QStringList _generalSourceDirs;
+ QDict<QStringList> _objectSourceDirs;
+
+ bool _showPercentage, _showExpanded, _showCycles;
+ double _cycleCut;
+ int _percentPrecision;
+ int _maxSymbolLength, _maxSymbolCount, _maxListCount;
+ int _context, _noCostInside;
+
+ static Configuration* _config;
+};
+
+
+#endif
diff --git a/kcachegrind/kcachegrind/costlistitem.cpp b/kcachegrind/kcachegrind/costlistitem.cpp
new file mode 100644
index 00000000..bfe22730
--- /dev/null
+++ b/kcachegrind/kcachegrind/costlistitem.cpp
@@ -0,0 +1,136 @@
+/* This file is part of KCachegrind.
+ Copyright (C) 2002, 2003 Josef Weidendorfer <Josef.Weidendorfer@gmx.de>
+
+ KCachegrind is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public
+ License as published by the Free Software Foundation, version 2.
+
+ 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; see the file COPYING. If not, write to
+ the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+*/
+
+#include <math.h>
+
+#include <qpainter.h>
+#include <qregexp.h>
+
+#include <klocale.h>
+#include <kiconloader.h>
+#include <kapplication.h>
+
+#include "listutils.h"
+#include "costlistitem.h"
+#include "coverage.h"
+#include "configuration.h"
+
+// CostListItem
+
+
+CostListItem::CostListItem(QListView* parent, TraceCostItem* costItem,
+ TraceCostType* ct, int size)
+ :QListViewItem(parent)
+{
+ _groupSize = size;
+ _skipped = 0;
+ _costItem = costItem;
+ setCostType(ct);
+
+ if (costItem) {
+ updateName();
+ setPixmap(1, colorPixmap(10, 10,
+ Configuration::groupColor(_costItem)));
+ }
+}
+
+CostListItem::CostListItem(QListView* parent, int skipped,
+ TraceCostItem* costItem, TraceCostType* ct)
+ :QListViewItem(parent)
+{
+ _skipped = skipped;
+ _costItem = costItem;
+ setCostType(ct);
+
+ setText(1, i18n("(%n item skipped)", "(%n items skipped)", _skipped));
+}
+
+void CostListItem::setCostType(TraceCostType* ct)
+{
+ _costType = ct;
+ update();
+}
+
+void CostListItem::updateName()
+{
+ if (!_costItem) return;
+
+ QString n = _costItem->prettyName();
+ if (_groupSize>=0) n += QString(" (%1)").arg(_groupSize);
+
+ setText(1, n);
+}
+
+void CostListItem::setSize(int s)
+{
+ _groupSize = s;
+ updateName();
+}
+
+void CostListItem::update()
+{
+ if (!_costItem) return;
+ TraceData* d = _costItem->data();
+
+ double total = d->subCost(_costType);
+ if (total == 0.0) {
+ setText(0, QString("---"));
+ setPixmap(0, QPixmap());
+ return;
+ }
+
+ _pure = _costItem->subCost(_costType);
+ double pure = 100.0 * _pure / total;
+ QString str;
+ if (Configuration::showPercentage())
+ str = QString("%1").arg(pure, 0, 'f', Configuration::percentPrecision());
+ else
+ str = _costItem->prettySubCost(_costType);
+
+ if (_skipped) {
+ // special handling for skip entries...
+ setText(0, QString("< %1").arg(str));
+ return;
+ }
+
+ setText(0, str);
+ setPixmap(0, costPixmap(_costType, _costItem, total, false));
+}
+
+int CostListItem::compare(QListViewItem * i, int col, bool ascending ) const
+{
+ const CostListItem* fi1 = this;
+ const CostListItem* fi2 = (CostListItem*) i;
+
+ // we always want descending order
+ if (ascending) {
+ fi1 = fi2;
+ fi2 = this;
+ }
+
+ // a skip entry is always sorted last
+ if (fi1->_skipped) return -1;
+ if (fi2->_skipped) return 1;
+
+ if (col==0) {
+ if (fi1->_pure < fi2->_pure) return -1;
+ if (fi1->_pure > fi2->_pure) return 1;
+ return 0;
+ }
+ return QListViewItem::compare(i, col, ascending);
+}
diff --git a/kcachegrind/kcachegrind/costlistitem.h b/kcachegrind/kcachegrind/costlistitem.h
new file mode 100644
index 00000000..28b90248
--- /dev/null
+++ b/kcachegrind/kcachegrind/costlistitem.h
@@ -0,0 +1,52 @@
+/* This file is part of KCachegrind.
+ Copyright (C) 2003 Josef Weidendorfer <Josef.Weidendorfer@gmx.de>
+
+ KCachegrind is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public
+ License as published by the Free Software Foundation, version 2.
+
+ 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; see the file COPYING. If not, write to
+ the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+*/
+
+#ifndef COSTLISTITEM_H
+#define COSTLISTITEM_H
+
+#include <qlistview.h>
+#include "tracedata.h"
+
+class CostListItem: public QListViewItem
+{
+public:
+ CostListItem(QListView* parent, TraceCostItem* cost,
+ TraceCostType* ct, int size = -1);
+ // entry with multiple skipped items
+ CostListItem(QListView* parent, int skipped, TraceCostItem* cost,
+ TraceCostType* ct);
+
+ int compare(QListViewItem * i, int col, bool ascending ) const;
+ TraceCostItem* costItem() { return (_skipped) ? 0 : _costItem; }
+ void setCostType(TraceCostType* ct);
+ void update();
+ void setSize(int s);
+
+private:
+ void updateName();
+
+ SubCost _pure;
+ TraceCostType* _costType;
+ TraceCostItem* _costItem;
+ // >0 only for last item in list, if items are skipped
+ int _skipped;
+ // number of items in group, is put in parenthesis after name
+ int _groupSize;
+};
+
+#endif
diff --git a/kcachegrind/kcachegrind/costtypeitem.cpp b/kcachegrind/kcachegrind/costtypeitem.cpp
new file mode 100644
index 00000000..99d123d8
--- /dev/null
+++ b/kcachegrind/kcachegrind/costtypeitem.cpp
@@ -0,0 +1,149 @@
+/* This file is part of KCachegrind.
+ Copyright (C) 2003 Josef Weidendorfer <Josef.Weidendorfer@gmx.de>
+
+ KCachegrind is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public
+ License as published by the Free Software Foundation, version 2.
+
+ 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; see the file COPYING. If not, write to
+ the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+*/
+
+/*
+ * Items of cost type view.
+ */
+
+#include <qpixmap.h>
+#include <klocale.h>
+
+#include "configuration.h"
+#include "listutils.h"
+#include "costtypeitem.h"
+
+
+// CostTypeItem
+
+
+CostTypeItem::CostTypeItem(QListView* parent, TraceCostItem* costItem,
+ TraceCostType* ct, TraceCost::CostType gt)
+ :QListViewItem(parent)
+{
+ _costItem = costItem;
+ _costType = ct;
+ _groupType = gt;
+
+ if (ct) {
+ setText(0, ct->longName());
+ setText(3, ct->name());
+ QString formula = ct->formula();
+ setText(5, formula);
+ if (!formula.isEmpty()) {
+ setText(4, "=");
+ // we have a virtual type: allow editing
+ setRenameEnabled(0, true);
+ setRenameEnabled(3, true);
+ setRenameEnabled(5, true);
+ }
+ }
+ else {
+ setText(0, i18n("Unknown Type"));
+ }
+ update();
+}
+
+void CostTypeItem::setGroupType(TraceCost::CostType gt)
+{
+ if (_groupType == gt) return;
+
+ _groupType = gt;
+ update();
+}
+
+void CostTypeItem::update()
+{
+ TraceData* d = _costItem ? _costItem->data() : 0;
+ double total = d ? ((double)d->subCost(_costType)) : 0.0;
+
+ if (total == 0.0) {
+ setText(1, "-");
+ setPixmap(1, QPixmap());
+ setText(2, "-");
+ setPixmap(2, QPixmap());
+ return;
+ }
+
+ TraceFunction* f = (_costItem->type()==TraceCost::Function) ?
+ (TraceFunction*)_costItem : 0;
+
+ TraceCost* selfTotalCost = f ? f->data() : d;
+ if (f && Configuration::showExpanded()) {
+ switch(_groupType) {
+ case TraceCost::Object: selfTotalCost = f->object(); break;
+ case TraceCost::Class: selfTotalCost = f->cls(); break;
+ case TraceCost::File: selfTotalCost = f->file(); break;
+ case TraceCost::FunctionCycle: selfTotalCost = f->cycle(); break;
+ default: break;
+ }
+ }
+ if (_costItem->type()==TraceCost::FunctionCycle) {
+ f = (TraceFunction*)_costItem;
+ selfTotalCost = f->data();
+ }
+
+ double selfTotal = selfTotalCost->subCost(_costType);
+
+ // for all cost items there's a self cost
+ _pure = _costItem ? _costItem->subCost(_costType) : SubCost(0);
+ double pure = 100.0 * _pure / selfTotal;
+ if (Configuration::showPercentage()) {
+ setText(2, QString("%1")
+ .arg(pure, 0, 'f', Configuration::percentPrecision()));
+ }
+ else
+ setText(2, _costItem->prettySubCost(_costType));
+
+ setPixmap(2, costPixmap(_costType, _costItem, selfTotal, false));
+
+ if (!f) {
+ setText(1, "-");
+ setPixmap(1, QPixmap());
+ return;
+ }
+
+ _sum = f->inclusive()->subCost(_costType);
+ double sum = 100.0 * _sum / total;
+ if (Configuration::showPercentage()) {
+ setText(1, QString("%1")
+ .arg(sum, 0, 'f', Configuration::percentPrecision()));
+ }
+ else
+ setText(1, _sum.pretty());
+
+ setPixmap(1, costPixmap(_costType, f->inclusive(), total, false));
+}
+
+
+int CostTypeItem::compare(QListViewItem * i, int col, bool ascending ) const
+{
+ CostTypeItem* fi = (CostTypeItem*) i;
+ if (col==0) {
+ if (_sum < fi->_sum) return -1;
+ if (_sum > fi->_sum) return 1;
+ return 0;
+ }
+ if (col==1) {
+ if (_pure < fi->_pure) return -1;
+ if (_pure > fi->_pure) return 1;
+ return 0;
+ }
+ return QListViewItem::compare(i, col, ascending);
+}
+
+
diff --git a/kcachegrind/kcachegrind/costtypeitem.h b/kcachegrind/kcachegrind/costtypeitem.h
new file mode 100644
index 00000000..a9df7d91
--- /dev/null
+++ b/kcachegrind/kcachegrind/costtypeitem.h
@@ -0,0 +1,50 @@
+/* This file is part of KCachegrind.
+ Copyright (C) 2003 Josef Weidendorfer <Josef.Weidendorfer@gmx.de>
+
+ KCachegrind is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public
+ License as published by the Free Software Foundation, version 2.
+
+ 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; see the file COPYING. If not, write to
+ the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+*/
+
+/*
+ * Items of cost type view.
+ */
+
+#ifndef COSTTYEPITEM_H
+#define COSTTYEPITEM_H
+
+#include <qlistview.h>
+#include "tracedata.h"
+
+
+class CostTypeItem: public QListViewItem
+{
+public:
+ CostTypeItem(QListView* parent, TraceCostItem* costItem,
+ TraceCostType* ct, TraceCost::CostType gt);
+
+ int compare(QListViewItem * i, int col, bool ascending ) const;
+ void setGroupType(TraceCost::CostType);
+ TraceCostItem* costItem() { return _costItem; }
+ TraceCostType* costType() { return _costType; }
+ void update();
+
+private:
+ SubCost _sum, _pure;
+ TraceCostType* _costType;
+ TraceCostItem* _costItem;
+ TraceCost::CostType _groupType;
+};
+
+
+#endif
diff --git a/kcachegrind/kcachegrind/costtypeview.cpp b/kcachegrind/kcachegrind/costtypeview.cpp
new file mode 100644
index 00000000..6c08a8c4
--- /dev/null
+++ b/kcachegrind/kcachegrind/costtypeview.cpp
@@ -0,0 +1,310 @@
+/* This file is part of KCachegrind.
+ Copyright (C) 2003 Josef Weidendorfer <Josef.Weidendorfer@gmx.de>
+
+ KCachegrind is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public
+ License as published by the Free Software Foundation, version 2.
+
+ 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; see the file COPYING. If not, write to
+ the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+*/
+
+/*
+ * Cost Type View
+ */
+
+#include <qwhatsthis.h>
+#include <qpopupmenu.h>
+#include <klocale.h>
+
+#include "configuration.h"
+#include "costtypeitem.h"
+#include "costtypeview.h"
+#include "toplevel.h"
+
+
+//
+// CostTypeView
+//
+
+
+CostTypeView::CostTypeView(TraceItemView* parentView,
+ QWidget* parent, const char* name)
+ : QListView(parent, name), TraceItemView(parentView)
+{
+ addColumn( i18n( "Event Type" ) );
+ addColumn( i18n( "Incl." ) );
+ addColumn( i18n( "Self" ) );
+ addColumn( i18n( "Short" ) );
+ addColumn( QString::null );
+ addColumn( i18n( "Formula" ) );
+
+ setSorting(-1);
+ setAllColumnsShowFocus(true);
+ setColumnAlignment(1, Qt::AlignRight);
+ setColumnAlignment(2, Qt::AlignRight);
+ setColumnAlignment(3, Qt::AlignRight);
+ setMinimumHeight(50);
+
+ connect( this,
+ SIGNAL( selectionChanged(QListViewItem*) ),
+ SLOT( selectedSlot(QListViewItem*) ) );
+
+ connect( this,
+ SIGNAL(contextMenuRequested(QListViewItem*, const QPoint &, int)),
+ SLOT(context(QListViewItem*, const QPoint &, int)));
+
+ connect(this,
+ SIGNAL(doubleClicked(QListViewItem*)),
+ SLOT(activatedSlot(QListViewItem*)));
+
+ connect(this,
+ SIGNAL(returnPressed(QListViewItem*)),
+ SLOT(activatedSlot(QListViewItem*)));
+
+ connect(this,
+ SIGNAL(itemRenamed(QListViewItem*,int,const QString&)),
+ SLOT(renamedSlot(QListViewItem*,int,const QString&)));
+
+ QWhatsThis::add( this, whatsThis() );
+}
+
+QString CostTypeView::whatsThis() const
+{
+ return i18n( "<b>Cost Types List</b>"
+ "<p>This list shows all cost types available "
+ "and what the self/inclusive cost of the "
+ "current selected function is for that cost type.</p>"
+ "<p>By choosing a cost type from the list, "
+ "you change the cost type of costs shown "
+ "all over KCachegrind to be the selected one.</p>");
+}
+
+
+void CostTypeView::context(QListViewItem* i, const QPoint & p, int)
+{
+ QPopupMenu popup;
+
+ TraceCostType* ct = i ? ((CostTypeItem*) i)->costType() : 0;
+
+ if (ct)
+ popup.insertItem(i18n("Set Secondary Event Type"), 99);
+ if (_costType2)
+ popup.insertItem(i18n("Remove Secondary Event Type"), 98);
+ if (popup.count()>0)
+ popup.insertSeparator();
+
+ if (ct && !ct->isReal()) {
+ popup.insertItem(i18n("Edit Long Name"), 93);
+ popup.insertItem(i18n("Edit Short Name"), 94);
+ popup.insertItem(i18n("Edit Formula"), 95);
+ popup.insertItem(i18n("Remove"), 96);
+ popup.insertSeparator();
+ }
+
+ addGoMenu(&popup);
+
+ popup.insertSeparator();
+ popup.insertItem(i18n("New Cost Type ..."), 97);
+
+ int r = popup.exec(p);
+ if (r == 98) selectedCostType2(0);
+ else if (r == 99) selectedCostType2(ct);
+ else if (r == 93) i->startRename(0);
+ else if (r == 94) i->startRename(3);
+ else if (r == 95) i->startRename(5);
+ else if (r == 96) {
+
+ // search for a previous type
+ TraceCostType* prev = 0, *ct = 0;
+ TraceCostMapping* m = _data->mapping();
+ for (int i=0;i<m->realCount();i++) {
+ ct = m->realType(i);
+ if (ct) prev = ct;
+ }
+ for (int i=0;i<m->virtualCount();i++) {
+ ct = m->virtualType(i);
+ if (ct == _costType) break;
+ if (ct) prev = ct;
+ }
+
+ if (_data->mapping()->remove(ct)) {
+ // select previous cost type
+ selectedCostType(prev);
+ if (_costType2 == ct)
+ selectedCostType2(prev);
+ refresh();
+ }
+ }
+ else if (r == 97) {
+ int i = 1;
+ while(1) {
+ if (!TraceCostType::knownVirtualType(i18n("New%1").arg(i)))
+ break;
+ i++;
+ }
+ // add same new cost type to this mapping and to known types
+ QString shortName = i18n("New%1").arg(i);
+ QString longName = i18n("New Cost Type %1").arg(i);
+ TraceCostType::add(new TraceCostType(shortName, longName, "0"));
+ _data->mapping()->add(new TraceCostType(shortName, longName, "0"));
+ refresh();
+ }
+}
+
+void CostTypeView::selectedSlot(QListViewItem * i)
+{
+ TraceCostType* ct = i ? ((CostTypeItem*) i)->costType() : 0;
+ if (ct)
+ selectedCostType(ct);
+}
+
+void CostTypeView::activatedSlot(QListViewItem * i)
+{
+ TraceCostType* ct = i ? ((CostTypeItem*) i)->costType() : 0;
+ if (ct)
+ selectedCostType2(ct);
+}
+
+TraceItem* CostTypeView::canShow(TraceItem* i)
+{
+ if (!i) return 0;
+
+ switch(i->type()) {
+ case TraceCost::Object:
+ case TraceCost::Class:
+ case TraceCost::File:
+ case TraceCost::Call:
+ case TraceCost::FunctionCycle:
+ case TraceCost::Function:
+ break;
+ default:
+ return 0;
+ }
+ return i;
+}
+
+void CostTypeView::doUpdate(int changeType)
+{
+ // Special case ?
+ if (changeType == selectedItemChanged) return;
+
+ if (changeType == costType2Changed) return;
+
+ if (changeType == groupTypeChanged) {
+ QListViewItem *item;
+ for (item = firstChild();item;item = item->nextSibling())
+ ((CostTypeItem*)item)->setGroupType(_groupType);
+
+ return;
+ }
+
+ if (changeType == costTypeChanged) {
+ QListViewItem *item;
+ for (item = firstChild();item;item = item->nextSibling())
+ if ( ((CostTypeItem*)item)->costType() == _costType) {
+ setSelected(item, true);
+ ensureItemVisible(item);
+ break;
+ }
+
+ return;
+ }
+
+ if (changeType == partsChanged) {
+ QListViewItem *item;
+ for (item = firstChild();item;item = item->nextSibling())
+ ((CostTypeItem*)item)->update();
+
+ return;
+ }
+
+
+ refresh();
+}
+
+void CostTypeView::refresh()
+{
+ clear();
+ setColumnWidth(1, 50);
+ setColumnWidth(2, 50);
+
+ if (!_data || !_activeItem) return;
+ switch(_activeItem->type()) {
+ case TraceCost::Object:
+ case TraceCost::Class:
+ case TraceCost::File:
+ case TraceCost::FunctionCycle:
+ case TraceCost::Function:
+ break;
+ default:
+ return;
+ }
+ TraceCostItem* c = (TraceCostItem*) _activeItem;
+
+ TraceCostType* ct =0 ;
+ QListViewItem* item = 0;
+ QString sumStr, pureStr;
+ QListViewItem* costItem=0;
+
+ TraceCostMapping* m = _data->mapping();
+ for (int i=m->virtualCount()-1;i>=0;i--) {
+ ct = m->virtualType(i);
+ if (!ct) continue;
+ item = new CostTypeItem(this, c, ct, _groupType);
+ if (ct == _costType) costItem = item;
+ }
+ for (int i=m->realCount()-1;i>=0;i--) {
+ ct = m->realType(i);
+ item = new CostTypeItem(this, c, ct, _groupType);
+ if (ct == _costType) costItem = item;
+ }
+
+ if (costItem) {
+ setSelected(costItem, true);
+ ensureItemVisible(costItem);
+ }
+
+ if (item) setMinimumHeight(3*item->height());
+}
+
+
+void CostTypeView::renamedSlot(QListViewItem* item,int c,const QString& t)
+{
+ TraceCostType* ct = item ? ((CostTypeItem*) item)->costType() : 0;
+ if (!ct || ct->isReal()) return;
+
+ // search for matching known Type
+ int knownCount = TraceCostType::knownTypeCount();
+ TraceCostType* known = 0;
+ for (int i=0; i<knownCount; i++) {
+ known = TraceCostType::knownType(i);
+ if (known->name() == ct->name()) break;
+ }
+
+ if (c == 0) {
+ ct->setLongName(t);
+ if (known) known->setLongName(t);
+ }
+ else if (c == 3) {
+ ct->setName(t);
+ if (known) known->setName(t);
+ }
+ else if (c == 5) {
+ ct->setFormula(t);
+ if (known) known->setFormula(t);
+ }
+ else return;
+
+ if (_topLevel) _topLevel->configChanged();
+ refresh();
+}
+
+#include "costtypeview.moc"
diff --git a/kcachegrind/kcachegrind/costtypeview.h b/kcachegrind/kcachegrind/costtypeview.h
new file mode 100644
index 00000000..c5f51494
--- /dev/null
+++ b/kcachegrind/kcachegrind/costtypeview.h
@@ -0,0 +1,53 @@
+/* This file is part of KCachegrind.
+ Copyright (C) 2003 Josef Weidendorfer <Josef.Weidendorfer@gmx.de>
+
+ KCachegrind is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public
+ License as published by the Free Software Foundation, version 2.
+
+ 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; see the file COPYING. If not, write to
+ the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+*/
+
+/*
+ * Cost Type View
+ */
+
+#ifndef COSTTYPEVIEW_H
+#define COSTTYPEVIEW_H
+
+#include <qlistview.h>
+#include "tracedata.h"
+#include "traceitemview.h"
+
+class CostTypeView: public QListView, public TraceItemView
+{
+ Q_OBJECT
+
+public:
+ CostTypeView(TraceItemView* parentView,
+ QWidget* parent=0, const char* name=0);
+
+ virtual QWidget* widget() { return this; }
+ QString whatsThis() const;
+
+private slots:
+ void context(QListViewItem*,const QPoint &, int);
+ void selectedSlot(QListViewItem*);
+ void activatedSlot(QListViewItem*);
+ void renamedSlot(QListViewItem*,int,const QString&);
+
+private:
+ TraceItem* canShow(TraceItem*);
+ void doUpdate(int);
+ void refresh();
+};
+
+#endif
diff --git a/kcachegrind/kcachegrind/coverage.cpp b/kcachegrind/kcachegrind/coverage.cpp
new file mode 100644
index 00000000..b928fc42
--- /dev/null
+++ b/kcachegrind/kcachegrind/coverage.cpp
@@ -0,0 +1,329 @@
+/* This file is part of KCachegrind.
+ Copyright (C) 2002 Josef Weidendorfer <Josef.Weidendorfer@gmx.de>
+
+ KCachegrind is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public
+ License as published by the Free Software Foundation, version 2.
+
+ 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; see the file COPYING. If not, write to
+ the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+*/
+
+/*
+ * Function Coverage Analysis
+ */
+
+#include "coverage.h"
+
+//#define DEBUG_COVERAGE 1
+
+TraceCostType* Coverage::_costType;
+
+const int Coverage::maxHistogramDepth = maxHistogramDepthValue;
+const int Coverage::Rtti = 1;
+
+Coverage::Coverage()
+{
+}
+
+void Coverage::init()
+{
+ _self = 0.0;
+ _incl = 0.0;
+ _callCount = 0.0;
+ // should always be overwritten before usage
+ _firstPercentage = 1.0;
+ _minDistance = 9999;
+ _maxDistance = 0;
+ _active = false;
+ _inRecursion = false;
+ for (int i = 0;i<maxHistogramDepth;i++) {
+ _selfHisto[i] = 0.0;
+ _inclHisto[i] = 0.0;
+ }
+
+ _valid = true;
+}
+
+int Coverage::inclusiveMedian()
+{
+ double maxP = _inclHisto[0];
+ int medD = 0;
+ for (int i = 1;i<maxHistogramDepth;i++)
+ if (_inclHisto[i]>maxP) {
+ maxP = _inclHisto[i];
+ medD = i;
+ }
+
+ return medD;
+}
+
+int Coverage::selfMedian()
+{
+ double maxP = _selfHisto[0];
+ int medD = 0;
+ for (int i = 1;i<maxHistogramDepth;i++)
+ if (_selfHisto[i]>maxP) {
+ maxP = _selfHisto[i];
+ medD = i;
+ }
+
+ return medD;
+}
+
+TraceFunctionList Coverage::coverage(TraceFunction* f, CoverageMode m,
+ TraceCostType* ct)
+{
+ invalidate(f->data(), Coverage::Rtti);
+
+ _costType = ct;
+
+ // function f takes ownership over c!
+ Coverage* c = new Coverage();
+ c->setFunction(f);
+ c->init();
+
+ TraceFunctionList l;
+
+ if (m == Caller)
+ c->addCallerCoverage(l, 1.0, 0);
+ else
+ c->addCallingCoverage(l, 1.0, 1.0, 0);
+
+ return l;
+}
+
+void Coverage::addCallerCoverage(TraceFunctionList& fList,
+ double pBack, int d)
+{
+ TraceCallList cList;
+ TraceCall* call;
+ Coverage* c;
+
+ if (_inRecursion) return;
+
+ double incl;
+ incl = (double) (_function->inclusive()->subCost(_costType));
+
+ if (_active) {
+#ifdef DEBUG_COVERAGE
+ qDebug("CallerCov: D %d, %s (was active, incl %f, self %f): newP %f", d,
+ _function->prettyName().ascii(), _incl, _self, pBack);
+#endif
+ _inRecursion = true;
+ }
+ else {
+ _active = true;
+
+ // only add cost if this is no recursion
+
+ _incl += pBack;
+ _firstPercentage = pBack;
+
+ if (_minDistance > d) _minDistance = d;
+ if (_maxDistance < d) _maxDistance = d;
+ if (d<maxHistogramDepth) {
+ _inclHisto[d] += pBack;
+ }
+ else {
+ _inclHisto[maxHistogramDepth-1] += pBack;
+ }
+
+#ifdef DEBUG_COVERAGE
+ qDebug("CallerCov: D %d, %s (now active, new incl %f): newP %f",
+ d, _function->prettyName().ascii(), _incl, pBack);
+#endif
+ }
+
+ double callVal, pBackNew;
+
+ cList = _function->callers();
+ for (call=cList.first();call;call=cList.next()) {
+ if (call->inCycle()>0) continue;
+ if (call->isRecursion()) continue;
+
+ if (call->subCost(_costType)>0) {
+ TraceFunction* caller = call->caller();
+
+ c = (Coverage*) caller->assoziation(rtti());
+ if (!c) {
+ c = new Coverage();
+ c->setFunction(caller);
+ }
+ if (!c->isValid()) {
+ c->init();
+ fList.append(caller);
+ }
+
+ if (c->isActive()) continue;
+ if (c->inRecursion()) continue;
+
+ callVal = (double) call->subCost(_costType);
+ pBackNew = pBack * (callVal / incl);
+
+ // FIXME ?!?
+
+ if (!c->isActive()) {
+ if (d>=0)
+ c->callCount() += (double)call->callCount();
+ else
+ c->callCount() += _callCount;
+ }
+ else {
+ // adjust pNew by sum of geometric series of recursion factor.
+ // Thus we can avoid endless recursion here
+ pBackNew *= 1.0 / (1.0 - pBackNew / c->firstPercentage());
+ }
+
+ // Limit depth
+ if (pBackNew > 0.0001)
+ c->addCallerCoverage(fList, pBackNew, d+1);
+ }
+ }
+
+ if (_inRecursion)
+ _inRecursion = false;
+ else if (_active)
+ _active = false;
+}
+
+/**
+ * pForward is time on percent used,
+ * pBack is given to allow for calculation of call counts
+ */
+void Coverage::addCallingCoverage(TraceFunctionList& fList,
+ double pForward, double pBack, int d)
+{
+ TraceCallList cList;
+ TraceCall* call;
+ Coverage* c;
+
+ if (_inRecursion) return;
+
+#ifdef DEBUG_COVERAGE
+ static const char* spaces = " ";
+#endif
+
+ double self, incl;
+ incl = (double) (_function->inclusive()->subCost(_costType));
+
+#ifdef DEBUG_COVERAGE
+ qDebug("CngCov:%s - %s (incl %f, self %f): forward %f, back %f",
+ spaces+strlen(spaces)-d,
+ _function->prettyName().ascii(), _incl, _self, pForward, pBack);
+#endif
+
+
+ if (_active) {
+ _inRecursion = true;
+
+#ifdef DEBUG_COVERAGE
+ qDebug("CngCov:%s < %s: STOP (is active)",
+ spaces+strlen(spaces)-d,
+ _function->prettyName().ascii());
+#endif
+
+ }
+ else {
+ _active = true;
+
+ // only add cost if this is no recursion
+ self = pForward * (_function->subCost(_costType)) / incl;
+ _incl += pForward;
+ _self += self;
+ _firstPercentage = pForward;
+
+ if (_minDistance > d) _minDistance = d;
+ if (_maxDistance < d) _maxDistance = d;
+ if (d<maxHistogramDepth) {
+ _inclHisto[d] += pForward;
+ _selfHisto[d] += self;
+ }
+ else {
+ _inclHisto[maxHistogramDepth-1] += pForward;
+ _selfHisto[maxHistogramDepth-1] += self;
+ }
+
+#ifdef DEBUG_COVERAGE
+ qDebug("CngCov:%s < %s (incl %f, self %f)",
+ spaces+strlen(spaces)-d,
+ _function->prettyName().ascii(), _incl, _self);
+#endif
+ }
+
+ double callVal, pForwardNew, pBackNew;
+
+ cList = _function->callings();
+ for (call=cList.first();call;call=cList.next()) {
+ if (call->inCycle()>0) continue;
+ if (call->isRecursion()) continue;
+
+ if (call->subCost(_costType)>0) {
+ TraceFunction* calling = call->called();
+
+ c = (Coverage*) calling->assoziation(rtti());
+ if (!c) {
+ c = new Coverage();
+ c->setFunction(calling);
+ }
+ if (!c->isValid()) {
+ c->init();
+ fList.append(calling);
+ }
+
+ if (c->isActive()) continue;
+ if (c->inRecursion()) continue;
+
+ callVal = (double) call->subCost(_costType);
+ pForwardNew = pForward * (callVal / incl);
+ pBackNew = pBack * (callVal /
+ calling->inclusive()->subCost(_costType));
+
+ if (!c->isActive()) {
+ c->callCount() += pBack * call->callCount();
+
+#ifdef DEBUG_COVERAGE
+ qDebug("CngCov:%s > %s: forward %f, back %f, calls %f -> %f, now %f",
+ spaces+strlen(spaces)-d,
+ calling->prettyName().ascii(),
+ pForwardNew, pBackNew,
+ (double)call->callCount(),
+ pBack * call->callCount(),
+ c->callCount());
+#endif
+ }
+ else {
+ // adjust pNew by sum of geometric series of recursion factor.
+ // Thus we can avoid endless recursion here
+ double fFactor = 1.0 / (1.0 - pForwardNew / c->firstPercentage());
+ double bFactor = 1.0 / (1.0 - pBackNew);
+#ifdef DEBUG_COVERAGE
+ qDebug("CngCov:%s Recursion - origP %f, actP %f => factor %f, newP %f",
+ spaces+strlen(spaces)-d,
+ c->firstPercentage(), pForwardNew,
+ fFactor, pForwardNew * fFactor);
+#endif
+ pForwardNew *= fFactor;
+ pBackNew *= bFactor;
+
+ }
+
+ // Limit depth
+ if (pForwardNew > 0.0001)
+ c->addCallingCoverage(fList, pForwardNew, pBackNew, d+1);
+ }
+ }
+
+ if (_inRecursion)
+ _inRecursion = false;
+ else if (_active)
+ _active = false;
+}
+
diff --git a/kcachegrind/kcachegrind/coverage.h b/kcachegrind/kcachegrind/coverage.h
new file mode 100644
index 00000000..b6a5107e
--- /dev/null
+++ b/kcachegrind/kcachegrind/coverage.h
@@ -0,0 +1,102 @@
+/* This file is part of KCachegrind.
+ Copyright (C) 2002 Josef Weidendorfer <Josef.Weidendorfer@gmx.de>
+
+ KCachegrind is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public
+ License as published by the Free Software Foundation, version 2.
+
+ 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; see the file COPYING. If not, write to
+ the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+*/
+
+/*
+ * Function Coverage Analysis
+ */
+
+#ifndef COVERAGE_H
+#define COVERAGE_H
+
+#include "tracedata.h"
+
+/**
+ * Coverage of a function.
+ * When analysis is done, every function involved will have a
+ * pointer to an object of this class.
+ *
+ * This function also holds the main routine for coverage analysis,
+ * Coverage::coverage(), as static method.
+ */
+class Coverage : public TraceAssoziation
+{
+public:
+ /* Direction of coverage analysis */
+ enum CoverageMode { Caller, Called };
+
+ // max depth for distance histogram
+#define maxHistogramDepthValue 40
+ static const int maxHistogramDepth;
+
+ static const int Rtti;
+
+ Coverage();
+
+ virtual int rtti() { return Rtti; }
+ void init();
+
+ TraceFunction* function() { return _function; }
+ double self() { return _self; }
+ double inclusive() { return _incl; }
+ double firstPercentage() { return _firstPercentage; }
+ double& callCount() { return _callCount; }
+ int minDistance() { return _minDistance; }
+ int maxDistance() { return _maxDistance; }
+ int inclusiveMedian();
+ int selfMedian();
+ double* selfHistogram() { return _selfHisto; }
+ double* inclusiveHistogram() { return _inclHisto; }
+ bool isActive() { return _active; }
+ bool inRecursion() { return _inRecursion; }
+
+ void setSelf(float p) { _self = p; }
+ void setInclusive(float p) { _incl = p; }
+ void setCallCount(float cc) { _callCount = cc; }
+ void setActive(bool a) { _active = a; }
+ void setInRecursion(bool r) { _inRecursion = r; }
+
+ /**
+ * Calculate coverage of all functions based on function f.
+ * If mode is Called, the coverage of functions called by
+ * f is calculated, otherwise that of functions calling f.
+ * SubCost type ct is used for the analysis.
+ * Self values are undefined for Caller mode.
+ *
+ * Returns list of functions covered.
+ * Coverage degree of returned functions can be get
+ * with function->coverage()->percentage()
+ */
+ static TraceFunctionList coverage(TraceFunction* f, CoverageMode m,
+ TraceCostType* ct);
+
+private:
+ void addCallerCoverage(TraceFunctionList& l, double, int d);
+ void addCallingCoverage(TraceFunctionList& l, double, double, int d);
+
+ double _self, _incl, _firstPercentage, _callCount;
+ int _minDistance, _maxDistance;
+ bool _active, _inRecursion;
+ double _selfHisto[maxHistogramDepthValue];
+ double _inclHisto[maxHistogramDepthValue];
+
+ // temporary set for one coverage analysis
+ static TraceCostType* _costType;
+};
+
+#endif
+
diff --git a/kcachegrind/kcachegrind/coverageitem.cpp b/kcachegrind/kcachegrind/coverageitem.cpp
new file mode 100644
index 00000000..d3542a95
--- /dev/null
+++ b/kcachegrind/kcachegrind/coverageitem.cpp
@@ -0,0 +1,343 @@
+/* This file is part of KCachegrind.
+ Copyright (C) 2003 Josef Weidendorfer <Josef.Weidendorfer@gmx.de>
+
+ KCachegrind is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public
+ License as published by the Free Software Foundation, version 2.
+
+ 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; see the file COPYING. If not, write to
+ the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+*/
+
+/*
+ * Items of coverage view.
+ */
+
+#include <qpixmap.h>
+#include <klocale.h>
+
+#include "configuration.h"
+#include "listutils.h"
+#include "coverage.h"
+#include "coverageitem.h"
+
+
+// CallerCoverageItem
+
+
+CallerCoverageItem::CallerCoverageItem(QListView* parent, Coverage* c,
+ TraceFunction* base,
+ TraceCostType* ct,
+ TraceCost::CostType gt)
+ : QListViewItem(parent)
+{
+ _skipped = 0;
+ _coverage = c;
+ _function = c ? c->function() : 0;
+ _base = base;
+ _groupType = TraceCost::NoCostType;
+
+ setText(3, _function->prettyNameWithLocation());
+
+ setCostType(ct);
+ setGroupType(gt);
+}
+
+CallerCoverageItem::CallerCoverageItem(QListView* parent, int skipped, Coverage* c,
+ TraceFunction* base,
+ TraceCostType* ct,
+ TraceCost::CostType gt)
+ : QListViewItem(parent)
+{
+ _skipped = skipped;
+ _coverage = c;
+ _function = c ? c->function() : 0;
+ _base = base;
+ _groupType = TraceCost::NoCostType;
+
+ setText(3, i18n("(%n function skipped)", "(%n functions skipped)", _skipped));
+
+ setCostType(ct);
+ setGroupType(gt);
+}
+
+void CallerCoverageItem::setGroupType(TraceCost::CostType gt)
+{
+ if (_skipped) return;
+ if (_groupType == gt) return;
+ _groupType = gt;
+
+ QColor c = Configuration::functionColor(_groupType, _function);
+ setPixmap(3, colorPixmap(10, 10, c));
+}
+
+void CallerCoverageItem::setCostType(TraceCostType* ct)
+{
+ _costType = ct;
+ update();
+}
+
+void CallerCoverageItem::update()
+{
+ if (!_coverage) {
+ setText(0, QString::null);
+ setText(1, QString::null);
+ return;
+ }
+
+ _pSum = 100.0 * _coverage->inclusive();
+ SubCost realSum = _base->inclusive()->subCost(_costType);
+ _sum = SubCost(realSum * _coverage->inclusive());
+ QString str;
+ if (Configuration::showPercentage())
+ str = QString("%1").arg(_pSum, 0, 'f', Configuration::percentPrecision());
+ else
+ str = _sum.pretty();
+
+ if (_skipped) {
+ setText(0, QString("< %1").arg(str));
+ return;
+ }
+
+ setText(0, str);
+ setPixmap(0, partitionPixmap(25, 10, _coverage->inclusiveHistogram(), 0,
+ Coverage::maxHistogramDepth, false));
+
+ // call count
+ _cc = SubCost(_coverage->callCount());
+ setText(2, _cc ? _cc.pretty() : QString("(0)"));
+
+ // distance (min/max/median)
+ _distance = _coverage->inclusiveMedian();
+ QString distString;
+ if (_coverage->minDistance() == _coverage->maxDistance())
+ distString = QString::number(_distance);
+ else
+ distString = QString("%1-%2 (%3)")
+ .arg(_coverage->minDistance())
+ .arg(_coverage->maxDistance())
+ .arg(_distance);
+ setText(1, distString);
+}
+
+
+int CallerCoverageItem::compare(QListViewItem * i,
+ int col, bool ascending ) const
+{
+ const CallerCoverageItem* ci1 = this;
+ const CallerCoverageItem* ci2 = (CallerCoverageItem*) i;
+
+ // we always want descending order
+ if (ascending) {
+ ci1 = ci2;
+ ci2 = this;
+ }
+
+ // a skip entry is always sorted last
+ if (ci1->_skipped) return -1;
+ if (ci2->_skipped) return 1;
+
+ if (col==0) {
+ if (ci1->_pSum < ci2->_pSum) return -1;
+ if (ci1->_pSum > ci2->_pSum) return 1;
+
+ // for same percentage (e.g. all 100%), use distance info
+ if (ci1->_distance < ci2->_distance) return -1;
+ if (ci1->_distance > ci2->_distance) return 1;
+ return 0;
+ }
+
+ if (col==1) {
+ if (ci1->_distance < ci2->_distance) return -1;
+ if (ci1->_distance > ci2->_distance) return 1;
+ return 0;
+ }
+
+ if (col==2) {
+ if (ci1->_cc < ci2->_cc) return -1;
+ if (ci1->_cc > ci2->_cc) return 1;
+ return 0;
+ }
+ return QListViewItem::compare(i, col, ascending);
+}
+
+
+// CalleeCoverageItem
+
+
+CalleeCoverageItem::CalleeCoverageItem(QListView* parent, Coverage* c,
+ TraceFunction* base,
+ TraceCostType* ct,
+ TraceCost::CostType gt)
+ : QListViewItem(parent)
+{
+ _skipped = 0;
+ _coverage = c;
+ _function = c ? c->function() : 0;
+ _base = base;
+ _groupType = TraceCost::NoCostType;
+
+ setText(4, _function->prettyNameWithLocation());
+
+ setCostType(ct);
+ setGroupType(gt);
+}
+
+CalleeCoverageItem::CalleeCoverageItem(QListView* parent, int skipped, Coverage* c,
+ TraceFunction* base,
+ TraceCostType* ct,
+ TraceCost::CostType gt)
+ : QListViewItem(parent)
+{
+ _skipped = skipped;
+ _coverage = c;
+ _function = c ? c->function() : 0;
+ _base = base;
+ _groupType = TraceCost::NoCostType;
+
+ setText(4, i18n("(%n function skipped)", "(%n functions skipped)", _skipped));
+
+ setCostType(ct);
+ setGroupType(gt);
+}
+
+void CalleeCoverageItem::setGroupType(TraceCost::CostType gt)
+{
+ if (_skipped) return;
+ if (_groupType == gt) return;
+ _groupType = gt;
+
+ QColor c = Configuration::functionColor(_groupType, _function);
+ setPixmap(4, colorPixmap(10, 10, c));
+}
+
+void CalleeCoverageItem::setCostType(TraceCostType* ct)
+{
+ _costType = ct;
+ update();
+}
+
+void CalleeCoverageItem::update()
+{
+ if (!_coverage) {
+ setText(0, QString::null);
+ setText(1, QString::null);
+ setText(2, QString::null);
+ return;
+ }
+
+ _pSum = 100.0 * _coverage->inclusive();
+
+ // pSum/pSelf are percentages of inclusive cost of base
+ SubCost realSum = _base->inclusive()->subCost(_costType);
+ _sum = SubCost(realSum * _coverage->inclusive());
+
+
+ QString str;
+ if (Configuration::showPercentage())
+ str = QString("%1").arg(_pSum, 0, 'f', Configuration::percentPrecision());
+ else
+ str = _sum.pretty();
+
+ if (_skipped) {
+ str = QString("< %1").arg(str);
+ setText(0, str);
+ setText(1, str);
+ return;
+ }
+ setText(0, str);
+
+ _pSelf = 100.0 * _coverage->self();
+ _self = SubCost(realSum * _coverage->self());
+
+ if (Configuration::showPercentage()) {
+ setText(1, QString("%1")
+ .arg(_pSelf, 0, 'f', Configuration::percentPrecision()));
+ }
+ else {
+ setText(1, _self.pretty());
+ }
+
+ setPixmap(0, partitionPixmap(25, 10, _coverage->inclusiveHistogram(), 0,
+ Coverage::maxHistogramDepth, false));
+ setPixmap(1, partitionPixmap(25, 10, _coverage->selfHistogram(), 0,
+ Coverage::maxHistogramDepth, false));
+
+
+ _cc = SubCost(_coverage->callCount());
+ setText(3, _cc ? _cc.pretty() : QString("(0)"));
+
+ // for comparations
+ _distance = _coverage->inclusiveMedian();
+ QString distString;
+ if (_coverage->minDistance() == _coverage->maxDistance())
+ distString = QString::number(_distance);
+ else {
+ int sMed = _coverage->selfMedian();
+ QString med;
+ if (_distance == sMed)
+ med = QString::number(_distance);
+ else
+ med = QString("%1/%2").arg(_distance).arg(sMed);
+
+ distString = QString("%1-%2 (%3)")
+ .arg(_coverage->minDistance())
+ .arg(_coverage->maxDistance())
+ .arg(med);
+ }
+ setText(2, distString);
+}
+
+
+int CalleeCoverageItem::compare(QListViewItem * i,
+ int col, bool ascending ) const
+{
+ CalleeCoverageItem* ci = (CalleeCoverageItem*) i;
+
+ // a skip entry is always sorted last
+ if (_skipped) return -1;
+ if (ci->_skipped) return 1;
+
+ if (col==0) {
+ if (_pSum < ci->_pSum) return -1;
+ if (_pSum > ci->_pSum) return 1;
+
+ // for same percentage (e.g. all 100%), use distance info
+ if (_distance < ci->_distance) return -1;
+ if (_distance > ci->_distance) return 1;
+ return 0;
+ }
+
+ if (col==1) {
+ if (_pSelf < ci->_pSelf) return -1;
+ if (_pSelf > ci->_pSelf) return 1;
+
+ // for same percentage (e.g. all 100%), use distance info
+ if (_distance < ci->_distance) return -1;
+ if (_distance > ci->_distance) return 1;
+ return 0;
+ }
+
+ if (col==2) {
+ // we want to sort the distance in contra direction to costs
+ if (_distance < ci->_distance) return 1;
+ if (_distance > ci->_distance) return -1;
+ return 0;
+ }
+
+ if (col==3) {
+ if (_cc < ci->_cc) return -1;
+ if (_cc > ci->_cc) return 1;
+ return 0;
+ }
+ return QListViewItem::compare(i, col, ascending);
+}
+
+
diff --git a/kcachegrind/kcachegrind/coverageitem.h b/kcachegrind/kcachegrind/coverageitem.h
new file mode 100644
index 00000000..99d77625
--- /dev/null
+++ b/kcachegrind/kcachegrind/coverageitem.h
@@ -0,0 +1,82 @@
+/* This file is part of KCachegrind.
+ Copyright (C) 2003 Josef Weidendorfer <Josef.Weidendorfer@gmx.de>
+
+ KCachegrind is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public
+ License as published by the Free Software Foundation, version 2.
+
+ 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; see the file COPYING. If not, write to
+ the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+*/
+
+/*
+ * Items of coverage view.
+ */
+
+#ifndef COVERAGEITEM_H
+#define COVERAGEITEM_H
+
+#include <qlistview.h>
+#include "tracedata.h"
+
+class Coverage;
+
+class CallerCoverageItem: public QListViewItem
+{
+public:
+ CallerCoverageItem(QListView* parent, Coverage* c, TraceFunction* base,
+ TraceCostType* ct, TraceCost::CostType gt);
+ CallerCoverageItem(QListView* parent, int skipped, Coverage* c, TraceFunction* base,
+ TraceCostType* ct, TraceCost::CostType gt);
+
+ int compare(QListViewItem * i, int col, bool ascending ) const;
+ TraceFunction* function() { return (_skipped) ? 0 : _function; }
+ void setCostType(TraceCostType* ct);
+ void setGroupType(TraceCost::CostType);
+ void update();
+
+private:
+ float _pSum;
+ SubCost _sum;
+ TraceCostType* _costType;
+ TraceCost::CostType _groupType;
+ SubCost _cc;
+ int _distance, _skipped;
+ TraceFunction *_function, *_base;
+ Coverage* _coverage;
+};
+
+
+class CalleeCoverageItem: public QListViewItem
+{
+public:
+ CalleeCoverageItem(QListView* parent, Coverage* c, TraceFunction* base,
+ TraceCostType* ct, TraceCost::CostType gt);
+ CalleeCoverageItem(QListView* parent, int skipped, Coverage* c, TraceFunction* base,
+ TraceCostType* ct, TraceCost::CostType gt);
+
+ int compare(QListViewItem * i, int col, bool ascending ) const;
+ TraceFunction* function() { return (_skipped) ? 0 : _function; }
+ void setCostType(TraceCostType* ct);
+ void setGroupType(TraceCost::CostType);
+ void update();
+
+private:
+ float _pSum, _pSelf;
+ SubCost _sum, _self;
+ TraceCostType* _costType;
+ TraceCost::CostType _groupType;
+ SubCost _cc;
+ int _distance, _skipped;
+ TraceFunction *_function, *_base;
+ Coverage* _coverage;
+};
+
+#endif
diff --git a/kcachegrind/kcachegrind/coverageview.cpp b/kcachegrind/kcachegrind/coverageview.cpp
new file mode 100644
index 00000000..e6f0a14f
--- /dev/null
+++ b/kcachegrind/kcachegrind/coverageview.cpp
@@ -0,0 +1,321 @@
+/* This file is part of KCachegrind.
+ Copyright (C) 2003 Josef Weidendorfer <Josef.Weidendorfer@gmx.de>
+
+ KCachegrind is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public
+ License as published by the Free Software Foundation, version 2.
+
+ 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; see the file COPYING. If not, write to
+ the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+*/
+
+/*
+ * Coverage Views
+ */
+
+#include <qwhatsthis.h>
+#include <qpopupmenu.h>
+#include <klocale.h>
+
+#include "configuration.h"
+#include "coverageitem.h"
+#include "coverage.h"
+#include "coverageview.h"
+
+
+
+//
+// CoverageView
+//
+
+
+CoverageView::CoverageView(bool showCallers, TraceItemView* parentView,
+ QWidget* parent, const char* name)
+ : QListView(parent, name), TraceItemView(parentView)
+{
+ _showCallers = showCallers;
+
+
+ addColumn( i18n( "Incl." ) );
+ if (_showCallers) {
+ addColumn( i18n( "Distance" ) );
+ addColumn( i18n( "Called" ) );
+ addColumn( i18n( "Caller" ) );
+ }
+ else {
+ addColumn( i18n( "Self" ) );
+ addColumn( i18n( "Distance" ) );
+ addColumn( i18n( "Calling" ) );
+ addColumn( i18n( "Callee" ) );
+ setColumnAlignment(3, Qt::AlignRight);
+ }
+
+ setSorting(0,false);
+ setColumnAlignment(0, Qt::AlignRight);
+ setColumnAlignment(1, Qt::AlignRight);
+ setColumnAlignment(2, Qt::AlignRight);
+ setAllColumnsShowFocus(true);
+ setResizeMode(QListView::LastColumn);
+ setMinimumHeight(50);
+
+ connect( this,
+ SIGNAL( selectionChanged(QListViewItem*) ),
+ SLOT( selectedSlot(QListViewItem*) ) );
+
+ connect( this,
+ SIGNAL(contextMenuRequested(QListViewItem*, const QPoint &, int)),
+ SLOT(context(QListViewItem*, const QPoint &, int)));
+
+ connect(this,
+ SIGNAL(doubleClicked(QListViewItem*)),
+ SLOT(activatedSlot(QListViewItem*)));
+
+ connect(this,
+ SIGNAL(returnPressed(QListViewItem*)),
+ SLOT(activatedSlot(QListViewItem*)));
+
+ QWhatsThis::add( this, whatsThis() );
+}
+
+QString CoverageView::whatsThis() const
+{
+ return _showCallers ?
+ i18n( "<b>List of all Callers</b>"
+ "<p>This list shows all functions calling the "
+ "current selected one, either directly or with "
+ "several functions in-between on the stack; the "
+ "number of functions in-between plus one "
+ "is called the <em>Distance</em> (e.g. "
+ "for function A,B,C there exists a call from "
+ "A to C when A calls B and B calls C, i.e. "
+ "A => B => C. The distance here is 2).</p>"
+
+ "<p>Absolute cost shown is the cost spent in the "
+ "selected function while a listed function is active; "
+ "relative cost is the percentage of all cost spent in "
+ "the selected function while the listed one is "
+ "active. The cost graphic shows logarithmic "
+ "percentage with a different color for each "
+ "distance.</p>"
+
+ "<p>As there can be many calls from the same function, "
+ "the distance column sometimes shows "
+ "the range of distances for all "
+ "calls happening; then, in parentheses, there is the "
+ "medium distance, i.e. the distance where most of the "
+ "call costs happened.</p>"
+
+ "<p>Selecting a function makes it the current selected "
+ "one of this information panel. "
+ "If there are two panels (Split mode), the "
+ "function of the other panel is changed instead.</p>") :
+
+ i18n( "<b>List of all Callees</b>"
+ "<p>This list shows all functions called by the "
+ "current selected one, either directly or with "
+ "several function in-between on the stack; the "
+ "number of function in-between plus one "
+ "is called the <em>Distance</em> (e.g. "
+ "for function A,B,C there exists a call from "
+ "A to C when A calls B and B calls C, i.e. "
+ "A => B => C. The distance here is 2).</p>"
+
+ "<p>Absolute cost shown is the cost spent in the "
+ "listed function while the selected is active; "
+ "relative cost is the percentage of all cost spent in "
+ "the listed function while the selected one is active. "
+ "The cost graphic always shows logarithmic "
+ "percentage with a different color for each "
+ "distance.</p>"
+
+ "<p>As there can be many calls to the same function, "
+ "the distance column sometimes shows "
+ "the range of distances for all "
+ "calls happening; then, in parentheses, there is the "
+ "medium distance, i.e. the distance where most of the "
+ "call costs happened.</p>"
+
+ "<p>Selecting a function makes it the current selected "
+ "one of this information panel. "
+ "If there are two panels (Split mode), the "
+ "function of the other panel is changed instead.</p>");
+}
+
+void CoverageView::context(QListViewItem* i, const QPoint & p, int c)
+{
+ QPopupMenu popup;
+
+ TraceFunction* f = 0;
+ if (i) {
+ f = _showCallers ?
+ ((CallerCoverageItem*)i)->function() :
+ ((CalleeCoverageItem*)i)->function();
+ }
+
+ if (f) {
+ QString name = f->name();
+ if ((int)name.length()>Configuration::maxSymbolLength())
+ name = name.left(Configuration::maxSymbolLength()) + "...";
+ popup.insertItem(i18n("Go to '%1'").arg(name), 93);
+ popup.insertSeparator();
+ }
+
+ if ((c == 0) || (!_showCallers && c == 1)) {
+ addCostMenu(&popup, false);
+ popup.insertSeparator();
+ }
+ addGoMenu(&popup);
+
+ int r = popup.exec(p);
+ if (r == 93) activated(f);
+}
+
+void CoverageView::selectedSlot(QListViewItem * i)
+{
+ TraceFunction* f = 0;
+ if (i) {
+ f = _showCallers ?
+ ((CallerCoverageItem*)i)->function() :
+ ((CalleeCoverageItem*)i)->function();
+ }
+
+ if (f) {
+ _selectedItem = f;
+ selected(f);
+ }
+}
+
+void CoverageView::activatedSlot(QListViewItem * i)
+{
+ TraceFunction* f = 0;
+ if (i) {
+ f = _showCallers ?
+ ((CallerCoverageItem*)i)->function() :
+ ((CalleeCoverageItem*)i)->function();
+ }
+
+ if (f) activated(f);
+}
+
+TraceItem* CoverageView::canShow(TraceItem* i)
+{
+ TraceItem::CostType t = i ? i->type() : TraceItem::NoCostType;
+
+ switch(t) {
+ case TraceItem::Function:
+ case TraceItem::FunctionCycle:
+ return i;
+ default:
+ break;
+ }
+ return 0;
+}
+
+void CoverageView::doUpdate(int changeType)
+{
+ // Special case ?
+ if (changeType == selectedItemChanged) {
+
+ if (!_selectedItem) {
+ clearSelection();
+ return;
+ }
+
+ TraceFunction* f = 0;
+ QListViewItem* i = QListView::selectedItem();
+ if (i) {
+ f = _showCallers ?
+ ((CallerCoverageItem*)i)->function() :
+ ((CalleeCoverageItem*)i)->function();
+ }
+ if (f == _selectedItem) return;
+
+ QListViewItem *item;
+ for (item = firstChild();item;item = item->nextSibling()) {
+ f = _showCallers ?
+ ((CallerCoverageItem*)item)->function() :
+ ((CalleeCoverageItem*)item)->function();
+ if (f == _selectedItem) {
+ ensureItemVisible(item);
+ setCurrentItem(item);
+ break;
+ }
+ }
+ return;
+ }
+
+ if (changeType == groupTypeChanged) {
+ QListViewItem *item;
+ for (item = firstChild();item;item = item->nextSibling()) {
+ if (_showCallers)
+ ((CallerCoverageItem*)item)->setGroupType(_groupType);
+ else
+ ((CalleeCoverageItem*)item)->setGroupType(_groupType);
+ }
+ return;
+ }
+
+ refresh();
+}
+
+void CoverageView::refresh()
+{
+ clear();
+ setColumnWidth(0, 50);
+ if (!_showCallers)
+ setColumnWidth(1, 50);
+
+ if (!_data || !_activeItem) return;
+
+ TraceItem::CostType t = _activeItem->type();
+ TraceFunction* f = 0;
+ if (t == TraceItem::Function) f = (TraceFunction*) _activeItem;
+ if (t == TraceItem::FunctionCycle) f = (TraceFunction*) _activeItem;
+ if (!f) return;
+
+ TraceFunction* ff;
+ TraceFunctionList l;
+
+ _hc.clear(Configuration::maxListCount());
+ SubCost realSum = f->inclusive()->subCost(_costType);
+
+ if (_showCallers)
+ l = Coverage::coverage(f, Coverage::Caller, _costType);
+ else
+ l = Coverage::coverage(f, Coverage::Called, _costType);
+
+ for (ff=l.first();ff;ff=l.next()) {
+ Coverage* c = (Coverage*) ff->assoziation(Coverage::Rtti);
+ if (c && (c->inclusive()>0.0))
+ _hc.addCost(ff, SubCost(realSum * c->inclusive()));
+ }
+
+ for(int i=0;i<_hc.realCount();i++) {
+ ff = (TraceFunction*) _hc[i];
+ Coverage* c = (Coverage*) ff->assoziation(Coverage::Rtti);
+ if (_showCallers)
+ new CallerCoverageItem(this, c, f, _costType, _groupType);
+ else
+ new CalleeCoverageItem(this, c, f, _costType, _groupType);
+ }
+ if (_hc.hasMore()) {
+ // a placeholder for all the functions skipped ...
+ ff = (TraceFunction*) _hc[_hc.maxSize()-1];
+ Coverage* c = (Coverage*) ff->assoziation(Coverage::Rtti);
+ if (_showCallers)
+ new CallerCoverageItem(this, _hc.count() - _hc.maxSize(),
+ c, f, _costType, _groupType);
+ else
+ new CalleeCoverageItem(this, _hc.count() - _hc.maxSize(),
+ c, f, _costType, _groupType);
+ }
+}
+
+#include "coverageview.moc"
diff --git a/kcachegrind/kcachegrind/coverageview.h b/kcachegrind/kcachegrind/coverageview.h
new file mode 100644
index 00000000..ac70ec0e
--- /dev/null
+++ b/kcachegrind/kcachegrind/coverageview.h
@@ -0,0 +1,56 @@
+/* This file is part of KCachegrind.
+ Copyright (C) 2003 Josef Weidendorfer <Josef.Weidendorfer@gmx.de>
+
+ KCachegrind is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public
+ License as published by the Free Software Foundation, version 2.
+
+ 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; see the file COPYING. If not, write to
+ the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+*/
+
+/*
+ * Coverage Views
+ */
+
+#ifndef COVERAGEVIEW_H
+#define COVERAGEVIEW_H
+
+#include <qlistview.h>
+#include "tracedata.h"
+#include "traceitemview.h"
+#include "listutils.h"
+
+class CoverageView: public QListView, public TraceItemView
+{
+ Q_OBJECT
+
+public:
+ CoverageView(bool showCallers, TraceItemView* parentView,
+ QWidget* parent=0, const char* name=0);
+
+ virtual QWidget* widget() { return this; }
+ QString whatsThis() const;
+
+private slots:
+ void context(QListViewItem*,const QPoint &, int);
+ void selectedSlot(QListViewItem*);
+ void activatedSlot(QListViewItem*);
+
+private:
+ TraceItem* canShow(TraceItem*);
+ void doUpdate(int);
+ void refresh();
+
+ HighestCostList _hc;
+ bool _showCallers;
+};
+
+#endif
diff --git a/kcachegrind/kcachegrind/dumpmanager.cpp b/kcachegrind/kcachegrind/dumpmanager.cpp
new file mode 100644
index 00000000..6dda67e6
--- /dev/null
+++ b/kcachegrind/kcachegrind/dumpmanager.cpp
@@ -0,0 +1,50 @@
+/**
+ * DumpManager
+ * Part of KCachegrind
+ * 2003, Josef Weidendorfer (GPL V2)
+ */
+
+#include "dumpmanager.h"
+
+
+//
+// Dump
+//
+
+Dump::Dump(QString file)
+{
+ _filename = file;
+}
+
+
+//
+// DumpManager
+//
+
+DumpManager* DumpManager::_self = 0;
+
+
+DumpManager::DumpManager()
+{
+}
+
+DumpManager* DumpManager::self()
+{
+ if (!_self)
+ _self = new DumpManager();
+
+ return _self;
+}
+
+
+DumpList DumpManager::loadableDumps()
+{
+ DumpList res;
+
+ return res;
+}
+
+TraceData* DumpManager::load(Dump*)
+{
+ return 0;
+}
diff --git a/kcachegrind/kcachegrind/dumpmanager.h b/kcachegrind/kcachegrind/dumpmanager.h
new file mode 100644
index 00000000..3e2ff9e1
--- /dev/null
+++ b/kcachegrind/kcachegrind/dumpmanager.h
@@ -0,0 +1,59 @@
+/**
+ * DumpManager
+ * Part of KCachegrind
+ * 2003, Josef Weidendorfer (GPL V2)
+ *
+ * DumpManager is a Singleton.
+ * - Has List of current loaded dumps / loadable dumps
+ * - Does "communication" with current running profiles
+ * for dump selection dockable
+ */
+
+#ifndef DUMPMANAGER_H
+#define DUMPMANAGER_H
+
+#include <qstring.h>
+#include <qptrlist.h>
+
+class Dump;
+class TraceData;
+
+typedef QPtrList<Dump> DumpList;
+
+
+/**
+ * A loadable profile Dump
+ */
+class Dump
+{
+public:
+ Dump(QString);
+
+ QString filename() { return _filename; }
+
+private:
+ QString _filename;
+};
+
+
+/*
+ * TODO:
+ * - Everything
+ *
+ */
+
+class DumpManager
+{
+public:
+ DumpManager();
+
+ DumpManager* self();
+
+ DumpList loadableDumps();
+ TraceData* load(Dump*);
+
+private:
+ static DumpManager* _self;
+};
+
+#endif
diff --git a/kcachegrind/kcachegrind/dumpselection.cpp b/kcachegrind/kcachegrind/dumpselection.cpp
new file mode 100644
index 00000000..c16470a7
--- /dev/null
+++ b/kcachegrind/kcachegrind/dumpselection.cpp
@@ -0,0 +1,33 @@
+/**
+ * DumpSelection Dockable
+ * Part of KCachegrind
+ * 2003, Josef Weidendorfer (GPL V2)
+ *
+ * - Fast Selection of dumps to load/activate/use for comparing
+ * - Start a profile run from GUI (current supported: Callgrind)
+ * - View state of running profile runs.
+ *
+ */
+
+#include "dumpselection.h"
+
+/*
+ * TODO:
+ * - Everything !!
+ * - Request State info on current function..
+ *
+ */
+
+
+DumpSelection::DumpSelection( TopLevel* top,
+ QWidget* parent, const char* name)
+ : DumpSelectionBase(parent, name), TraceItemView(0, top)
+{
+}
+
+DumpSelection::~DumpSelection()
+{}
+
+
+#include "dumpselection.moc"
+
diff --git a/kcachegrind/kcachegrind/dumpselection.h b/kcachegrind/kcachegrind/dumpselection.h
new file mode 100644
index 00000000..8c59d3e4
--- /dev/null
+++ b/kcachegrind/kcachegrind/dumpselection.h
@@ -0,0 +1,29 @@
+/**
+ * DumpSelection Dockable
+ * Part of KCachegrind
+ * 2003, Josef Weidendorfer (GPL V2)
+ *
+ * - Fast Selection of dumps to load/activate/use for comparing
+ * - Start a profile run from GUI (current supported: Callgrind)
+ * - View state of running profile runs.
+ *
+ */
+
+#ifndef DUMPSELECTION_H
+#define DUMPSELECTION_H
+
+#include "dumpselectionbase.h"
+#include "traceitemview.h"
+
+class DumpSelection : public DumpSelectionBase, public TraceItemView
+{
+ Q_OBJECT
+
+public:
+ DumpSelection( TopLevel*, QWidget* parent = 0, const char* name = 0);
+ virtual ~DumpSelection();
+
+ QWidget* widget() { return this; }
+};
+
+#endif
diff --git a/kcachegrind/kcachegrind/dumpselectionbase.ui b/kcachegrind/kcachegrind/dumpselectionbase.ui
new file mode 100644
index 00000000..37bc1c46
--- /dev/null
+++ b/kcachegrind/kcachegrind/dumpselectionbase.ui
@@ -0,0 +1,1082 @@
+<!DOCTYPE UI><UI version="3.2" stdsetdef="1">
+<class>DumpSelectionBase</class>
+<widget class="QWidget">
+ <property name="name">
+ <cstring>DumpSelectionBase</cstring>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>349</width>
+ <height>832</height>
+ </rect>
+ </property>
+ <property name="caption">
+ <string>Profile Dumps</string>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QSplitter">
+ <property name="name">
+ <cstring>splitter1</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Vertical</enum>
+ </property>
+ <widget class="QListView">
+ <column>
+ <property name="text">
+ <string>Target</string>
+ </property>
+ <property name="clickable">
+ <bool>true</bool>
+ </property>
+ <property name="resizable">
+ <bool>true</bool>
+ </property>
+ </column>
+ <column>
+ <property name="text">
+ <string></string>
+ </property>
+ <property name="clickable">
+ <bool>true</bool>
+ </property>
+ <property name="resizable">
+ <bool>true</bool>
+ </property>
+ </column>
+ <column>
+ <property name="text">
+ <string>Time</string>
+ </property>
+ <property name="clickable">
+ <bool>true</bool>
+ </property>
+ <property name="resizable">
+ <bool>true</bool>
+ </property>
+ </column>
+ <column>
+ <property name="text">
+ <string>Path</string>
+ </property>
+ <property name="clickable">
+ <bool>true</bool>
+ </property>
+ <property name="resizable">
+ <bool>true</bool>
+ </property>
+ </column>
+ <property name="name">
+ <cstring>listView1</cstring>
+ </property>
+ </widget>
+ <widget class="QTabWidget">
+ <property name="name">
+ <cstring>tabWidget2</cstring>
+ </property>
+ <widget class="QWidget">
+ <property name="name">
+ <cstring>tab</cstring>
+ </property>
+ <attribute name="title">
+ <string>Options</string>
+ </attribute>
+ <vbox>
+ <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>1</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="text">
+ <string>Target command:</string>
+ </property>
+ </widget>
+ <widget class="QLineEdit">
+ <property name="name">
+ <cstring>lineEdit1</cstring>
+ </property>
+ </widget>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>textLabel2</cstring>
+ </property>
+ <property name="text">
+ <string>Profiler options:</string>
+ </property>
+ </widget>
+ <widget class="QListView">
+ <column>
+ <property name="text">
+ <string>Option</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>
+ <item>
+ <property name="text">
+ <string>Trace</string>
+ </property>
+ <property name="text">
+ <string></string>
+ </property>
+ <property name="pixmap">
+ <pixmap></pixmap>
+ </property>
+ <property name="pixmap">
+ <pixmap></pixmap>
+ </property>
+ <item>
+ <property name="text">
+ <string>Jumps</string>
+ </property>
+ <property name="text">
+ <string></string>
+ </property>
+ <property name="pixmap">
+ <pixmap></pixmap>
+ </property>
+ <property name="pixmap">
+ <pixmap></pixmap>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>Instructions</string>
+ </property>
+ <property name="text">
+ <string></string>
+ </property>
+ <property name="pixmap">
+ <pixmap></pixmap>
+ </property>
+ <property name="pixmap">
+ <pixmap></pixmap>
+ </property>
+ </item>
+ </item>
+ <item>
+ <property name="text">
+ <string>Events</string>
+ </property>
+ <property name="text">
+ <string></string>
+ </property>
+ <property name="pixmap">
+ <pixmap></pixmap>
+ </property>
+ <property name="pixmap">
+ <pixmap></pixmap>
+ </property>
+ <item>
+ <property name="text">
+ <string>Full Cache</string>
+ </property>
+ <property name="text">
+ <string></string>
+ </property>
+ <property name="pixmap">
+ <pixmap></pixmap>
+ </property>
+ <property name="pixmap">
+ <pixmap></pixmap>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>Custom</string>
+ </property>
+ <property name="text">
+ <string></string>
+ </property>
+ <property name="pixmap">
+ <pixmap></pixmap>
+ </property>
+ <property name="pixmap">
+ <pixmap></pixmap>
+ </property>
+ </item>
+ </item>
+ <item>
+ <property name="text">
+ <string>Collect</string>
+ </property>
+ <property name="text">
+ <string></string>
+ </property>
+ <property name="pixmap">
+ <pixmap></pixmap>
+ </property>
+ <property name="pixmap">
+ <pixmap></pixmap>
+ </property>
+ <item>
+ <property name="text">
+ <string>At Startup</string>
+ </property>
+ <property name="text">
+ <string></string>
+ </property>
+ <property name="pixmap">
+ <pixmap></pixmap>
+ </property>
+ <property name="pixmap">
+ <pixmap></pixmap>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>While In</string>
+ </property>
+ <property name="text">
+ <string></string>
+ </property>
+ <property name="pixmap">
+ <pixmap></pixmap>
+ </property>
+ <property name="pixmap">
+ <pixmap></pixmap>
+ </property>
+ </item>
+ </item>
+ <item>
+ <property name="text">
+ <string>Skip</string>
+ </property>
+ <property name="text">
+ <string></string>
+ </property>
+ <property name="pixmap">
+ <pixmap></pixmap>
+ </property>
+ <property name="pixmap">
+ <pixmap></pixmap>
+ </property>
+ <item>
+ <property name="text">
+ <string>PLT</string>
+ </property>
+ <property name="text">
+ <string></string>
+ </property>
+ <property name="pixmap">
+ <pixmap></pixmap>
+ </property>
+ <property name="pixmap">
+ <pixmap></pixmap>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>Function</string>
+ </property>
+ <property name="text">
+ <string></string>
+ </property>
+ <property name="pixmap">
+ <pixmap></pixmap>
+ </property>
+ <property name="pixmap">
+ <pixmap></pixmap>
+ </property>
+ </item>
+ </item>
+ <item>
+ <property name="text">
+ <string>Dump Profile</string>
+ </property>
+ <property name="text">
+ <string></string>
+ </property>
+ <property name="pixmap">
+ <pixmap></pixmap>
+ </property>
+ <property name="pixmap">
+ <pixmap></pixmap>
+ </property>
+ <item>
+ <property name="text">
+ <string>Every BBs</string>
+ </property>
+ <property name="text">
+ <string></string>
+ </property>
+ <property name="pixmap">
+ <pixmap></pixmap>
+ </property>
+ <property name="pixmap">
+ <pixmap></pixmap>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>On Entering</string>
+ </property>
+ <property name="text">
+ <string></string>
+ </property>
+ <property name="pixmap">
+ <pixmap></pixmap>
+ </property>
+ <property name="pixmap">
+ <pixmap></pixmap>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>On Leaving</string>
+ </property>
+ <property name="text">
+ <string></string>
+ </property>
+ <property name="pixmap">
+ <pixmap></pixmap>
+ </property>
+ <property name="pixmap">
+ <pixmap></pixmap>
+ </property>
+ </item>
+ </item>
+ <item>
+ <property name="text">
+ <string>Zero Events</string>
+ </property>
+ <property name="text">
+ <string></string>
+ </property>
+ <property name="pixmap">
+ <pixmap></pixmap>
+ </property>
+ <property name="pixmap">
+ <pixmap></pixmap>
+ </property>
+ <item>
+ <property name="text">
+ <string>On Entering</string>
+ </property>
+ <property name="text">
+ <string></string>
+ </property>
+ <property name="pixmap">
+ <pixmap></pixmap>
+ </property>
+ <property name="pixmap">
+ <pixmap></pixmap>
+ </property>
+ </item>
+ </item>
+ <item>
+ <property name="text">
+ <string>Separate</string>
+ </property>
+ <property name="text">
+ <string></string>
+ </property>
+ <property name="pixmap">
+ <pixmap></pixmap>
+ </property>
+ <property name="pixmap">
+ <pixmap></pixmap>
+ </property>
+ <item>
+ <property name="text">
+ <string>Threads</string>
+ </property>
+ <property name="text">
+ <string></string>
+ </property>
+ <property name="pixmap">
+ <pixmap></pixmap>
+ </property>
+ <property name="pixmap">
+ <pixmap></pixmap>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>Recursions</string>
+ </property>
+ <property name="text">
+ <string></string>
+ </property>
+ <property name="pixmap">
+ <pixmap></pixmap>
+ </property>
+ <property name="pixmap">
+ <pixmap></pixmap>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>Call Chain</string>
+ </property>
+ <property name="text">
+ <string></string>
+ </property>
+ <property name="pixmap">
+ <pixmap></pixmap>
+ </property>
+ <property name="pixmap">
+ <pixmap></pixmap>
+ </property>
+ </item>
+ </item>
+ <property name="name">
+ <cstring>listView3</cstring>
+ </property>
+ </widget>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>textLabel1_2</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>5</hsizetype>
+ <vsizetype>5</vsizetype>
+ <horstretch>1</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="text">
+ <string>Custom profiler options:</string>
+ </property>
+ </widget>
+ <widget class="QLineEdit">
+ <property name="name">
+ <cstring>lineEdit1_2</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>spacer1</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="QPushButton">
+ <property name="name">
+ <cstring>pushButton2</cstring>
+ </property>
+ <property name="text">
+ <string>Run New Profile</string>
+ </property>
+ </widget>
+ </hbox>
+ </widget>
+ </vbox>
+ </widget>
+ <widget class="QWidget">
+ <property name="name">
+ <cstring>tab</cstring>
+ </property>
+ <attribute name="title">
+ <string>Info</string>
+ </attribute>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>textLabel8</cstring>
+ </property>
+ <property name="text">
+ <string>Dump reason:</string>
+ </property>
+ </widget>
+ <widget class="QLineEdit">
+ <property name="name">
+ <cstring>lineEdit3</cstring>
+ </property>
+ </widget>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>textLabel6</cstring>
+ </property>
+ <property name="text">
+ <string>Event summary:</string>
+ </property>
+ </widget>
+ <widget class="QListView">
+ <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>Sum</string>
+ </property>
+ <property name="clickable">
+ <bool>true</bool>
+ </property>
+ <property name="resizable">
+ <bool>true</bool>
+ </property>
+ </column>
+ <property name="name">
+ <cstring>listView4</cstring>
+ </property>
+ </widget>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>textLabel7</cstring>
+ </property>
+ <property name="text">
+ <string>Miscellaneous:</string>
+ </property>
+ </widget>
+ <widget class="QTextEdit">
+ <property name="name">
+ <cstring>textEdit2</cstring>
+ </property>
+ </widget>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>layout7</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>50</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ <widget class="QPushButton">
+ <property name="name">
+ <cstring>pushButton6</cstring>
+ </property>
+ <property name="text">
+ <string>Show</string>
+ </property>
+ </widget>
+ <widget class="QPushButton">
+ <property name="name">
+ <cstring>pushButton5</cstring>
+ </property>
+ <property name="text">
+ <string>Compare</string>
+ </property>
+ </widget>
+ </hbox>
+ </widget>
+ </vbox>
+ </widget>
+ <widget class="QWidget">
+ <property name="name">
+ <cstring>tab</cstring>
+ </property>
+ <attribute name="title">
+ <string>State</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>
+ <widget class="QPushButton">
+ <property name="name">
+ <cstring>pushButton1</cstring>
+ </property>
+ <property name="text">
+ <string>Update</string>
+ </property>
+ </widget>
+ <widget class="QCheckBox">
+ <property name="name">
+ <cstring>checkBox1</cstring>
+ </property>
+ <property name="text">
+ <string>Every [s]:</string>
+ </property>
+ </widget>
+ <widget class="QLineEdit">
+ <property name="name">
+ <cstring>lineEdit3_2</cstring>
+ </property>
+ </widget>
+ </hbox>
+ </widget>
+ <widget class="QListView">
+ <column>
+ <property name="text">
+ <string>Counter</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>
+ <item>
+ <property name="text">
+ <string>Dumps Done</string>
+ </property>
+ <property name="text">
+ <string></string>
+ </property>
+ <property name="pixmap">
+ <pixmap></pixmap>
+ </property>
+ <property name="pixmap">
+ <pixmap></pixmap>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>Is Collecting</string>
+ </property>
+ <property name="text">
+ <string></string>
+ </property>
+ <property name="pixmap">
+ <pixmap></pixmap>
+ </property>
+ <property name="pixmap">
+ <pixmap></pixmap>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>Executed</string>
+ </property>
+ <property name="text">
+ <string></string>
+ </property>
+ <property name="pixmap">
+ <pixmap></pixmap>
+ </property>
+ <property name="pixmap">
+ <pixmap></pixmap>
+ </property>
+ <item>
+ <property name="text">
+ <string>Basic Blocks</string>
+ </property>
+ <property name="text">
+ <string></string>
+ </property>
+ <property name="pixmap">
+ <pixmap></pixmap>
+ </property>
+ <property name="pixmap">
+ <pixmap></pixmap>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>Calls</string>
+ </property>
+ <property name="text">
+ <string></string>
+ </property>
+ <property name="pixmap">
+ <pixmap></pixmap>
+ </property>
+ <property name="pixmap">
+ <pixmap></pixmap>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>Jumps</string>
+ </property>
+ <property name="text">
+ <string></string>
+ </property>
+ <property name="pixmap">
+ <pixmap></pixmap>
+ </property>
+ <property name="pixmap">
+ <pixmap></pixmap>
+ </property>
+ </item>
+ </item>
+ <item>
+ <property name="text">
+ <string>Events</string>
+ </property>
+ <property name="text">
+ <string></string>
+ </property>
+ <property name="pixmap">
+ <pixmap></pixmap>
+ </property>
+ <property name="pixmap">
+ <pixmap></pixmap>
+ </property>
+ <item>
+ <property name="text">
+ <string>Ir</string>
+ </property>
+ <property name="text">
+ <string></string>
+ </property>
+ <property name="pixmap">
+ <pixmap></pixmap>
+ </property>
+ <property name="pixmap">
+ <pixmap></pixmap>
+ </property>
+ </item>
+ </item>
+ <item>
+ <property name="text">
+ <string>Distinct</string>
+ </property>
+ <property name="text">
+ <string></string>
+ </property>
+ <property name="pixmap">
+ <pixmap></pixmap>
+ </property>
+ <property name="pixmap">
+ <pixmap></pixmap>
+ </property>
+ <item>
+ <property name="text">
+ <string>ELF Objects</string>
+ </property>
+ <property name="text">
+ <string></string>
+ </property>
+ <property name="pixmap">
+ <pixmap></pixmap>
+ </property>
+ <property name="pixmap">
+ <pixmap></pixmap>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>Functions</string>
+ </property>
+ <property name="text">
+ <string></string>
+ </property>
+ <property name="pixmap">
+ <pixmap></pixmap>
+ </property>
+ <property name="pixmap">
+ <pixmap></pixmap>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>Contexts</string>
+ </property>
+ <property name="text">
+ <string></string>
+ </property>
+ <property name="pixmap">
+ <pixmap></pixmap>
+ </property>
+ <property name="pixmap">
+ <pixmap></pixmap>
+ </property>
+ </item>
+ </item>
+ <property name="name">
+ <cstring>listView4_3</cstring>
+ </property>
+ </widget>
+ <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>textLabel4</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>5</hsizetype>
+ <vsizetype>5</vsizetype>
+ <horstretch>1</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="text">
+ <string>Stack trace:</string>
+ </property>
+ </widget>
+ <widget class="QCheckBox">
+ <property name="name">
+ <cstring>checkBox2</cstring>
+ </property>
+ <property name="text">
+ <string>Sync.</string>
+ </property>
+ </widget>
+ </hbox>
+ </widget>
+ <widget class="QListView">
+ <column>
+ <property name="text">
+ <string>#</string>
+ </property>
+ <property name="clickable">
+ <bool>true</bool>
+ </property>
+ <property name="resizable">
+ <bool>true</bool>
+ </property>
+ </column>
+ <column>
+ <property name="text">
+ <string>Incl.</string>
+ </property>
+ <property name="clickable">
+ <bool>true</bool>
+ </property>
+ <property name="resizable">
+ <bool>true</bool>
+ </property>
+ </column>
+ <column>
+ <property name="text">
+ <string>Called</string>
+ </property>
+ <property name="clickable">
+ <bool>true</bool>
+ </property>
+ <property name="resizable">
+ <bool>true</bool>
+ </property>
+ </column>
+ <column>
+ <property name="text">
+ <string>Function</string>
+ </property>
+ <property name="clickable">
+ <bool>true</bool>
+ </property>
+ <property name="resizable">
+ <bool>true</bool>
+ </property>
+ </column>
+ <column>
+ <property name="text">
+ <string>Location</string>
+ </property>
+ <property name="clickable">
+ <bool>true</bool>
+ </property>
+ <property name="resizable">
+ <bool>true</bool>
+ </property>
+ </column>
+ <property name="name">
+ <cstring>listView7</cstring>
+ </property>
+ </widget>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>layout6</cstring>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QPushButton">
+ <property name="name">
+ <cstring>pushButton7</cstring>
+ </property>
+ <property name="text">
+ <string>Start</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>20</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ <widget class="QPushButton">
+ <property name="name">
+ <cstring>pushButton6_2</cstring>
+ </property>
+ <property name="text">
+ <string>Zero</string>
+ </property>
+ </widget>
+ <widget class="QPushButton">
+ <property name="name">
+ <cstring>pushButton4</cstring>
+ </property>
+ <property name="text">
+ <string>Dump</string>
+ </property>
+ </widget>
+ </hbox>
+ </widget>
+ </vbox>
+ </widget>
+ <widget class="QWidget">
+ <property name="name">
+ <cstring>tab</cstring>
+ </property>
+ <attribute name="title">
+ <string>Messages</string>
+ </attribute>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QTextEdit">
+ <property name="name">
+ <cstring>textEdit2_2</cstring>
+ </property>
+ </widget>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>layout6</cstring>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QPushButton">
+ <property name="name">
+ <cstring>pushButton9</cstring>
+ </property>
+ <property name="text">
+ <string>Kill Run</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>21</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ <widget class="QPushButton">
+ <property name="name">
+ <cstring>pushButton8</cstring>
+ </property>
+ <property name="text">
+ <string>Clear</string>
+ </property>
+ </widget>
+ </hbox>
+ </widget>
+ </vbox>
+ </widget>
+ </widget>
+ </widget>
+ </vbox>
+</widget>
+<layoutdefaults spacing="6" margin="11"/>
+</UI>
diff --git a/kcachegrind/kcachegrind/fixcost.cpp b/kcachegrind/kcachegrind/fixcost.cpp
new file mode 100644
index 00000000..41029265
--- /dev/null
+++ b/kcachegrind/kcachegrind/fixcost.cpp
@@ -0,0 +1,174 @@
+/*
+ * Part of KCacheGrind
+ *
+ * 2003, Josef Weidendorfer
+ */
+
+#include "fixcost.h"
+#include "utils.h"
+
+
+// FixCost
+
+FixCost::FixCost(TracePart* part, FixPool* pool,
+ TraceFunctionSource* functionSource,
+ PositionSpec& pos,
+ TracePartFunction* partFunction,
+ FixString& s)
+{
+ int maxCount = part->fixSubMapping()->count();
+
+ _part = part;
+ _functionSource = functionSource;
+ _pos = pos;
+
+ _cost = (SubCost*) pool->reserve(sizeof(SubCost) * maxCount);
+ s.stripSpaces();
+ int i = 0;
+ while(i<maxCount) {
+ if (!s.stripUInt64(_cost[i])) break;
+ i++;
+ }
+ _count = i;
+
+ if (!pool->allocateReserved(sizeof(SubCost) * _count))
+ _count = 0;
+
+ _nextCostOfPartFunction = partFunction ?
+ partFunction->setFirstFixCost(this) : 0;
+}
+
+void* FixCost::operator new(size_t size, FixPool* pool)
+{
+ return pool->allocate(size);
+}
+
+void FixCost::addTo(TraceCost* c)
+{
+ TraceSubMapping* sm = _part->fixSubMapping();
+
+ int i, realIndex;
+
+ for(i=0; i<_count; i++) {
+ realIndex = sm->realIndex(i);
+ c->addCost(realIndex, _cost[i]);
+ }
+}
+
+
+
+// FixCallCost
+
+FixCallCost::FixCallCost(TracePart* part, FixPool* pool,
+ TraceFunctionSource* functionSource,
+ unsigned int line, Addr addr,
+ TracePartCall* partCall,
+ SubCost callCount, FixString& s)
+{
+ if (0) qDebug("Got FixCallCost (addr 0x%s, line %d): calls %s",
+ addr.toString().ascii(), line,
+ callCount.pretty().ascii());
+
+ int maxCount = part->fixSubMapping()->count();
+
+ _part = part;
+ _functionSource = functionSource;
+ _line = line;
+ _addr = addr;
+
+ _cost = (SubCost*) pool->reserve(sizeof(SubCost) * (maxCount+1));
+ s.stripSpaces();
+ int i = 0;
+ while(i<maxCount) {
+ if (!s.stripUInt64(_cost[i])) break;
+ i++;
+ }
+ _count = i;
+
+ if (!pool->allocateReserved(sizeof(SubCost) * (_count+1) ))
+ _count = 0;
+ else
+ _cost[_count] = callCount;
+
+ _nextCostOfPartCall = partCall ? partCall->setFirstFixCallCost(this) : 0;
+}
+
+void* FixCallCost::operator new(size_t size, FixPool* pool)
+{
+ return pool->allocate(size);
+}
+
+void FixCallCost::addTo(TraceCallCost* c)
+{
+ TraceSubMapping* sm = _part->fixSubMapping();
+
+ int i, realIndex;
+
+ for(i=0; i<_count; i++) {
+ realIndex = sm->realIndex(i);
+ c->addCost(realIndex, _cost[i]);
+ }
+ c->addCallCount(_cost[_count]);
+
+ if (0) qDebug("Adding from (addr 0x%s, ln %d): calls %s",
+ _addr.toString().ascii(), _line,
+ _cost[_count].pretty().ascii());
+}
+
+void FixCallCost::setMax(TraceCost* c)
+{
+ TraceSubMapping* sm = _part->fixSubMapping();
+
+ int i, realIndex;
+
+ for(i=0; i<_count; i++) {
+ realIndex = sm->realIndex(i);
+ c->maxCost(realIndex, _cost[i]);
+ }
+}
+
+
+// FixJump
+
+FixJump::FixJump(TracePart* part, FixPool* pool,
+ unsigned int line, Addr addr,
+ TracePartFunction* partFunction,
+ TraceFunctionSource* source,
+ unsigned int targetLine, Addr targetAddr,
+ TraceFunction* targetFunction,
+ TraceFunctionSource* targetSource,
+ bool isCondJump,
+ SubCost executed, SubCost followed)
+{
+ _part = part;
+ _source = source;
+ _line = line;
+ _addr = addr;
+
+ _targetFunction = targetFunction;
+ _targetSource = targetSource;
+ _targetLine = targetLine;
+ _targetAddr = targetAddr;
+
+ _isCondJump = isCondJump;
+
+ int size = (isCondJump ? 2 : 1) * sizeof(SubCost);
+ _cost = (SubCost*) pool->allocate(size);
+ _cost[0] = executed;
+ if (isCondJump) _cost[1] = followed;
+
+ _nextJumpOfPartFunction = partFunction ?
+ partFunction->setFirstFixJump(this) : 0;
+}
+
+void* FixJump::operator new(size_t size, FixPool* pool)
+{
+ return pool->allocate(size);
+}
+
+void FixJump::addTo(TraceJumpCost* jc)
+{
+ jc->addExecutedCount(_cost[0]);
+ if (_isCondJump)
+ jc->addFollowedCount(_cost[1]);
+}
diff --git a/kcachegrind/kcachegrind/fixcost.h b/kcachegrind/kcachegrind/fixcost.h
new file mode 100644
index 00000000..7e90fb40
--- /dev/null
+++ b/kcachegrind/kcachegrind/fixcost.h
@@ -0,0 +1,171 @@
+/*
+ * Part of KCacheGrind
+ *
+ * 2003, Josef Weidendorfer
+ */
+
+#ifndef FIXCOST_H
+#define FIXCOST_H
+
+/**
+ * Setting USE_FIXCOST to 1 enables a memory space hack:
+ * For some data, build up internal data model lazy by using
+ * the Fix*Cost classes, which are simple copies from input data.
+ */
+#define USE_FIXCOST 1
+
+#include "tracedata.h"
+#include "pool.h"
+
+class PositionSpec
+{
+ public:
+ PositionSpec()
+ { fromLine = 0, toLine = 0, fromAddr = 0, toAddr = 0; }
+ PositionSpec(uint l1, uint l2, Addr a1, Addr a2)
+ { fromLine = l1, toLine = l2, fromAddr = a1, toAddr = a2; }
+
+ bool isLineRegion() const { return (fromLine != toLine); }
+ bool isAddrRegion() const { return (fromAddr != toAddr); }
+
+ uint fromLine, toLine;
+ Addr fromAddr, toAddr;
+};
+
+/**
+ * A class holding an unchangable cost item of an input file.
+ *
+ * As there can be a lot of such cost items, we use our own
+ * allocator which uses FixPool
+ */
+class FixCost
+{
+
+ public:
+ FixCost(TracePart*, FixPool*,
+ TraceFunctionSource*,
+ PositionSpec&,
+ TracePartFunction*,
+ FixString&);
+
+ void *operator new(size_t size, FixPool*);
+
+ void addTo(TraceCost*);
+
+ TracePart* part() const { return _part; }
+ bool isLineRegion() const { return _pos.isLineRegion(); }
+ bool isAddrRegion() const { return _pos.isAddrRegion(); }
+ uint fromLine() const { return _pos.fromLine; }
+ uint line() const { return _pos.fromLine; }
+ uint toLine() const { return _pos.toLine; }
+ Addr fromAddr() const { return _pos.fromAddr; }
+ Addr addr() const { return _pos.fromAddr; }
+ Addr toAddr() const { return _pos.toAddr; }
+ TraceFunctionSource* functionSource() const { return _functionSource; }
+
+ FixCost* nextCostOfPartFunction() const
+ { return _nextCostOfPartFunction; }
+
+ private:
+ int _count;
+ SubCost* _cost;
+ PositionSpec _pos;
+
+ TracePart* _part;
+ TraceFunctionSource* _functionSource;
+ FixCost *_nextCostOfPartFunction;
+};
+
+/**
+ * A FixCallCost will be inserted into a
+ * - TracePartCall to keep source/target function info
+ * - TraceFunctionSourceFile to keep file info of call source
+ */
+class FixCallCost
+{
+
+ public:
+ FixCallCost(TracePart*, FixPool*,
+ TraceFunctionSource*,
+ unsigned int line,
+ Addr addr,
+ TracePartCall*,
+ SubCost, FixString&);
+
+ void *operator new(size_t size, FixPool*);
+
+ void addTo(TraceCallCost*);
+ void setMax(TraceCost*);
+
+ TracePart* part() const { return _part; }
+ unsigned int line() const { return _line; }
+ Addr addr() const { return _addr; }
+ SubCost callCount() const { return _cost[_count]; }
+ TraceFunctionSource* functionSource() const { return _functionSource; }
+ FixCallCost* nextCostOfPartCall() const
+ { return _nextCostOfPartCall; }
+
+ private:
+ // we use 1 SubCost more than _count: _cost[_count] is the call count
+ int _count;
+ SubCost* _cost;
+ unsigned int _line;
+ Addr _addr;
+
+ TracePart* _part;
+ TraceFunctionSource* _functionSource;
+ FixCallCost* _nextCostOfPartCall;
+};
+
+/**
+ * A class holding a jump (mostly) inside of a function
+ */
+class FixJump
+{
+
+ public:
+ FixJump(TracePart*, FixPool*,
+ /* source position */
+ unsigned int line, Addr addr,
+ TracePartFunction*, TraceFunctionSource*,
+ /* target position */
+ unsigned int targetLine, Addr targetAddr,
+ TraceFunction*, TraceFunctionSource*,
+ bool isCondJump,
+ SubCost, SubCost);
+
+ void *operator new(size_t size, FixPool*);
+
+ void addTo(TraceJumpCost*);
+
+ TracePart* part() const { return _part; }
+ unsigned int line() const { return _line; }
+ Addr addr() const { return _addr; }
+ TraceFunctionSource* source() const { return _source; }
+ TraceFunction* targetFunction() const { return _targetFunction; }
+ unsigned int targetLine() const { return _targetLine; }
+ Addr targetAddr() const { return _targetAddr; }
+ TraceFunctionSource* targetSource() const { return _targetSource; }
+ bool isCondJump() { return _isCondJump; }
+ SubCost executedCount() const { return _cost[0]; }
+ SubCost followedCount() const
+ { return _isCondJump ? _cost[1] : SubCost(0); }
+
+ FixJump* nextJumpOfPartFunction() const
+ { return _nextJumpOfPartFunction; }
+
+ private:
+ bool _isCondJump;
+ SubCost* _cost;
+ unsigned int _line, _targetLine;
+ Addr _addr, _targetAddr;
+
+ TracePart* _part;
+ TraceFunctionSource *_source, *_targetSource;
+ TraceFunction* _targetFunction;
+ FixJump *_nextJumpOfPartFunction;
+};
+
+#endif
+
+
diff --git a/kcachegrind/kcachegrind/functionitem.cpp b/kcachegrind/kcachegrind/functionitem.cpp
new file mode 100644
index 00000000..9d62b2eb
--- /dev/null
+++ b/kcachegrind/kcachegrind/functionitem.cpp
@@ -0,0 +1,236 @@
+/* This file is part of KCachegrind.
+ Copyright (C) 2003 Josef Weidendorfer <Josef.Weidendorfer@gmx.de>
+
+ KCachegrind is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public
+ License as published by the Free Software Foundation, version 2.
+
+ 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; see the file COPYING. If not, write to
+ the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+*/
+
+/*
+ * List Item for the FunctionSelection list
+ */
+
+
+//#include <math.h>
+
+//#include <qpainter.h>
+//#include <qregexp.h>
+
+#include <klocale.h>
+#include <kiconloader.h>
+#include <kapplication.h>
+
+#include "listutils.h"
+#include "functionitem.h"
+#include "configuration.h"
+
+
+// FunctionItem
+
+FunctionItem::FunctionItem(QListView* parent, TraceFunction* f,
+ TraceCostType* ct, TraceCost::CostType gt)
+ :QListViewItem(parent)
+{
+#if 0
+ _costPixValid = false;
+ _groupPixValid = false;
+#endif
+
+ _function = f;
+ _skipped = 0;
+ _groupType = TraceCost::NoCostType;
+ setGroupType(gt);
+ setCostType(ct);
+
+ setText(3, f->prettyName());
+ setText(4, f->prettyLocation());
+}
+
+FunctionItem::FunctionItem(QListView* parent, int skipped,
+ TraceFunction* f, TraceCostType* ct)
+ :QListViewItem(parent)
+{
+#if 0
+ _costPixValid = false;
+ _groupPixValid = false;
+#endif
+ _skipped = skipped;
+ _function = f;
+ _groupType = TraceCost::NoCostType;
+ setCostType(ct);
+
+ setText(3, i18n("(%n function skipped)", "(%n functions skipped)", skipped));
+}
+
+#if 0
+const QPixmap* FunctionItem::pixmap(int column) const
+{
+ if (column == 3) {
+ if (!_groupPixValid) {
+ QColor c = Configuration::functionColor(_groupType, _function);
+ _groupPix = colorPixmap(10, 10, c);
+ _groupPixValid = true;
+ }
+ return &_groupPix;
+ }
+ if (column == 1) {
+ if (!_costPixValid) {
+ _costPix = colorPixmap(10, 10, c);
+ _costPixValid = true;
+ }
+ return &_costPix;
+ }
+ return 0;
+}
+#endif
+
+void FunctionItem::setGroupType(TraceCost::CostType gt)
+{
+ if (_skipped) return;
+ if (_groupType == gt) return;
+ _groupType = gt;
+
+
+#if 0
+ _groupPixValid = false;
+ viewList()->repaint();
+#else
+ QColor c = Configuration::functionColor(_groupType, _function);
+ setPixmap(3, colorPixmap(10, 10, c));
+#endif
+}
+
+void FunctionItem::setCostType(TraceCostType* c)
+{
+ _costType = c;
+ update();
+}
+
+void FunctionItem::update()
+{
+ double inclTotal = _function->data()->subCost(_costType);
+ QString str;
+
+ TraceCost* selfCost = _function->data();
+ if (Configuration::showExpanded()) {
+ switch(_groupType) {
+ case TraceCost::Object: selfCost = _function->object(); break;
+ case TraceCost::Class: selfCost = _function->cls(); break;
+ case TraceCost::File: selfCost = _function->file(); break;
+ default: break;
+ }
+ }
+ double selfTotal = selfCost->subCost(_costType);
+
+ if (_skipped) {
+ // special handling for skip entries...
+
+ // only text updates of incl./self
+
+ // for all skipped functions, cost is below the given function
+ _sum = _function->inclusive()->subCost(_costType);
+ double incl = 100.0 * _sum / inclTotal;
+ if (Configuration::showPercentage())
+ str = QString("%1").arg(incl, 0, 'f', Configuration::percentPrecision());
+ else
+ str = _function->inclusive()->prettySubCost(_costType);
+ str = "< " + str;
+ setText(0, str);
+ setText(1, str);
+ return;
+ }
+
+ // Call count...
+ if (_function->calledCount() >0)
+ str = _function->prettyCalledCount();
+ else {
+ if (_function == _function->cycle())
+ str = QString("-");
+ else
+ str = QString("(0)");
+ }
+ setText(2, str);
+
+ // Incl. cost
+ _sum = _function->inclusive()->subCost(_costType);
+ if (inclTotal == 0.0) {
+ setPixmap(0, QPixmap());
+ setText(0, "-");
+ }
+ else {
+ double incl = 100.0 * _sum / inclTotal;
+ if (Configuration::showPercentage())
+ setText(0, QString("%1")
+ .arg(incl, 0, 'f', Configuration::percentPrecision()));
+ else
+ setText(0, _function->inclusive()->prettySubCost(_costType));
+
+ setPixmap(0, costPixmap(_costType, _function->inclusive(), inclTotal, false));
+ }
+
+ // self
+ _pure = _function->subCost(_costType);
+ if (selfTotal == 0.0) {
+ setPixmap(1, QPixmap());
+ setText(1, "-");
+ }
+ else {
+ double self = 100.0 * _pure / selfTotal;
+
+ if (Configuration::showPercentage())
+ setText(1, QString("%1")
+ .arg(self, 0, 'f', Configuration::percentPrecision()));
+ else
+ setText(1, _function->prettySubCost(_costType));
+
+ setPixmap(1, costPixmap(_costType, _function, selfTotal, false));
+ }
+}
+
+
+int FunctionItem::compare(QListViewItem * i, int col, bool ascending ) const
+{
+ const FunctionItem* fi1 = this;
+ const FunctionItem* fi2 = (FunctionItem*) i;
+
+ // we always want descending order
+ if (ascending) {
+ fi1 = fi2;
+ fi2 = this;
+ }
+
+ // a skip entry is always sorted last
+ if (fi1->_skipped) return -1;
+ if (fi2->_skipped) return 1;
+
+ if (col==0) {
+ if (fi1->_sum < fi2->_sum) return -1;
+ if (fi1->_sum > fi2->_sum) return 1;
+ return 0;
+ }
+ if (col==1) {
+ if (fi1->_pure < fi2->_pure) return -1;
+ if (fi1->_pure > fi2->_pure) return 1;
+ return 0;
+ }
+ if (col==2) {
+ if (fi1->_function->calledCount() <
+ fi2->_function->calledCount()) return -1;
+ if (fi1->_function->calledCount() >
+ fi2->_function->calledCount()) return 1;
+ return 0;
+ }
+
+ return QListViewItem::compare(i, col, ascending);
+}
+
diff --git a/kcachegrind/kcachegrind/functionitem.h b/kcachegrind/kcachegrind/functionitem.h
new file mode 100644
index 00000000..94545dcb
--- /dev/null
+++ b/kcachegrind/kcachegrind/functionitem.h
@@ -0,0 +1,58 @@
+/* This file is part of KCachegrind.
+ Copyright (C) 2003 Josef Weidendorfer <Josef.Weidendorfer@gmx.de>
+
+ KCachegrind is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public
+ License as published by the Free Software Foundation, version 2.
+
+ 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; see the file COPYING. If not, write to
+ the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+*/
+
+/*
+ * List Item for the FunctionSelection list
+ */
+
+#ifndef FUNCTIONITEM_H
+#define FUNCTIONITEM_H
+
+#include <qlistview.h>
+#include "tracedata.h"
+
+class FunctionItem: public QListViewItem
+{
+public:
+ FunctionItem(QListView* parent, TraceFunction* function,
+ TraceCostType* ct, TraceCost::CostType gt);
+ // constructor for a "Skipped ... " entry
+ FunctionItem(QListView* parent, int skipped,
+ TraceFunction* function, TraceCostType* ct);
+
+ int compare(QListViewItem * i, int col, bool ascending ) const;
+ TraceFunction* function() { return (_skipped) ? 0 : _function; }
+ void setCostType(TraceCostType* ct);
+ void setGroupType(TraceCost::CostType);
+ void update();
+
+#if 0
+ const QPixmap* pixmap (int column) const;
+ bool _costPixValid, _groupPixValid;
+ QPixMap _costPix, _groupPix;
+#endif
+
+private:
+ SubCost _sum, _pure;
+ TraceCostType* _costType;
+ TraceCost::CostType _groupType;
+ TraceFunction* _function;
+ int _skipped;
+};
+
+#endif
diff --git a/kcachegrind/kcachegrind/functionselection.cpp b/kcachegrind/kcachegrind/functionselection.cpp
new file mode 100644
index 00000000..8c4e8a5a
--- /dev/null
+++ b/kcachegrind/kcachegrind/functionselection.cpp
@@ -0,0 +1,871 @@
+/* This file is part of KCachegrind.
+ Copyright (C) 2002, 2003 Josef Weidendorfer <Josef.Weidendorfer@gmx.de>
+
+ KCachegrind is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public
+ License as published by the Free Software Foundation, version 2.
+
+ 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; see the file COPYING. If not, write to
+ the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+*/
+
+/*
+ * For function selection, to be put into a QDockWindow
+ */
+
+#include <qtimer.h>
+#include <qlistview.h>
+#include <qlabel.h>
+#include <qpushbutton.h>
+#include <qcombobox.h>
+#include <qlineedit.h>
+#include <qregexp.h>
+#include <qpopupmenu.h>
+
+#include <klocale.h>
+
+#include "traceitemview.h"
+#include "stackbrowser.h"
+#include "functionselection.h"
+#include "partgraph.h"
+#include "functionitem.h"
+#include "costlistitem.h"
+#include "configuration.h"
+#include "toplevel.h"
+
+FunctionSelection::FunctionSelection( TopLevel* top,
+ QWidget* parent, const char* name)
+ : FunctionSelectionBase(parent, name), TraceItemView(0, top)
+{
+ _group = 0;
+ _inSetGroup = false;
+ _inSetFunction = false;
+
+ QStringList args;
+ args << i18n("(No Grouping)")
+ << TraceCost::i18nTypeName(TraceItem::Object)
+ << TraceCost::i18nTypeName(TraceItem::File)
+ << TraceCost::i18nTypeName(TraceItem::Class)
+ << TraceCost::i18nTypeName(TraceItem::FunctionCycle);
+
+ groupBox->insertStringList(args);
+ // this needs same order of grouptype actionlist!
+ connect(groupBox, SIGNAL(activated(int)),
+ top, SLOT(groupTypeSelected(int)));
+
+ // search while typing...
+ connect(searchEdit, SIGNAL(textChanged(const QString&)),
+ this, SLOT(searchChanged(const QString&)));
+ connect(&_searchTimer, SIGNAL(timeout()),
+ this, SLOT(queryDelayed()));
+ // select first matching group/function on return
+ connect(searchEdit, SIGNAL(returnPressed()),
+ this, SLOT(searchReturnPressed()));
+ searchEdit->setMinimumWidth(50);
+
+ // we start with desending cost sorting
+ functionList->setSorting(0,false);
+ functionList->setColumnAlignment(0, Qt::AlignRight);
+ functionList->setColumnAlignment(1, Qt::AlignRight);
+ functionList->setColumnAlignment(2, Qt::AlignRight);
+ functionList->setAllColumnsShowFocus(true);
+ // functionList->setShowSortIndicator(true);
+ // we can have very long function and location names
+ functionList->setColumnWidthMode(3, QListView::Manual);
+ functionList->setColumnWidth(3, 200);
+ functionList->setColumnWidthMode(4, QListView::Manual);
+ functionList->setColumnWidth(4, 200);
+
+ groupList->setSorting(0,false);
+ groupList->setColumnAlignment(0, Qt::AlignRight);
+ groupList->setAllColumnsShowFocus(true);
+ // groupList->setShowSortIndicator(true);
+ groupList->setResizeMode(QListView::LastColumn);
+
+#if 0
+ // single click press activation
+ connect(functionList, SIGNAL(selectionChanged(QListViewItem*)),
+ this, SLOT(functionActivated(QListViewItem*)));
+ connect(functionList,
+ SIGNAL(contextMenuRequested(QListViewItem*, const QPoint &, int)),
+ this, SLOT(functionContext(QListViewItem*, const QPoint &, int)));
+#else
+ // single click release activation
+ connect(functionList, SIGNAL(selectionChanged(QListViewItem*)),
+ this, SLOT(functionSelected(QListViewItem*)));
+ connect(functionList, SIGNAL(clicked(QListViewItem*)),
+ this, SLOT(functionActivated(QListViewItem*)));
+ connect(functionList, SIGNAL(returnPressed(QListViewItem*)),
+ this, SLOT(functionActivated(QListViewItem*)));
+ connect(functionList,
+ SIGNAL(contextMenuRequested(QListViewItem*, const QPoint &, int)),
+ this, SLOT(functionContext(QListViewItem*, const QPoint &, int)));
+#endif
+
+ connect(groupList, SIGNAL(selectionChanged(QListViewItem*)),
+ this, SLOT(groupSelected(QListViewItem*)));
+ connect(groupList, SIGNAL(doubleClicked(QListViewItem*)),
+ this, SLOT(groupDoubleClicked(QListViewItem*)));
+ connect(groupList, SIGNAL(returnPressed(QListViewItem*)),
+ this, SLOT(groupDoubleClicked(QListViewItem*)));
+ connect(groupList,
+ SIGNAL(contextMenuRequested(QListViewItem*, const QPoint &, int)),
+ this, SLOT(groupContext(QListViewItem*, const QPoint &, int)));
+
+ // start hidden
+ groupList->hide();
+}
+
+FunctionSelection::~FunctionSelection()
+{
+}
+
+void FunctionSelection::searchReturnPressed()
+{
+ query(searchEdit->text());
+
+ QListViewItem* item;
+ if (_groupType != TraceItem::Function) {
+ // if current group not matching, select first matching group
+ item = groupList->currentItem();
+ if (!item || !item->isVisible()) {
+ item = groupList->firstChild();
+ for (;item;item = item->nextSibling())
+ if (item->isVisible()) break;
+ if (!item) return;
+
+ setGroup(((CostListItem*)item)->costItem());
+ return;
+ }
+ }
+
+ functionActivated(functionList->firstChild());
+}
+
+// trigger the query after some delay, dependent on length
+void FunctionSelection::searchChanged(const QString& q)
+{
+ _searchDelayed = q;
+ int ms = 100;
+ if (q.length()<5) ms = 200;
+ if (q.length()<2) ms = 300;
+ _searchTimer.start(ms,true);
+}
+
+void FunctionSelection::queryDelayed()
+{
+ query(_searchDelayed);
+}
+
+void FunctionSelection::functionContext(QListViewItem* i,
+ const QPoint & p, int c)
+{
+ QPopupMenu popup;
+ TraceFunction* f = 0;
+
+ if (i) {
+ f = ((FunctionItem*) i)->function();
+ if (f) {
+ popup.insertItem(i18n("Go to %1").arg(f->prettyName()), 93);
+ popup.insertSeparator();
+ }
+ }
+
+ if ((c == 0) || (c == 1)) {
+ addCostMenu(&popup,false);
+ popup.insertSeparator();
+ }
+ addGroupMenu(&popup);
+ popup.insertSeparator();
+ addGoMenu(&popup);
+
+ int r = popup.exec(p);
+ if (r == 93) activated(f);
+}
+
+void FunctionSelection::groupContext(QListViewItem* /*i*/,
+ const QPoint & p, int c)
+{
+ QPopupMenu popup;
+
+#if 0
+ TraceCostItem* g = 0;
+ if (i) {
+ g = ((CostListItem*) i)->costItem();
+ if (!g) {
+ popup.insertItem(i18n("Show All Items"), 93);
+ popup.insertSeparator();
+ }
+ }
+#endif
+ if (c == 0) {
+ addCostMenu(&popup,false);
+ popup.insertSeparator();
+ }
+ addGroupMenu(&popup);
+ popup.insertSeparator();
+ addGoMenu(&popup);
+
+ popup.exec(p);
+}
+
+
+void FunctionSelection::addGroupMenu(QPopupMenu* popup)
+{
+ QPopupMenu *popup1 = new QPopupMenu(popup);
+ popup1->setCheckable(true);
+
+ if (_groupType != TraceItem::Function) {
+ popup1->insertItem(i18n("No Grouping"),0);
+ popup1->insertSeparator();
+ }
+ popup1->insertItem(TraceCost::i18nTypeName(TraceItem::Object),1);
+ popup1->insertItem(TraceCost::i18nTypeName(TraceItem::File),2);
+ popup1->insertItem(TraceCost::i18nTypeName(TraceItem::Class),3);
+ popup1->insertItem(TraceCost::i18nTypeName(TraceItem::FunctionCycle),4);
+ switch(_groupType) {
+ case TraceItem::Object: popup1->setItemChecked(1, true); break;
+ case TraceItem::File: popup1->setItemChecked(2, true); break;
+ case TraceItem::Class: popup1->setItemChecked(3, true); break;
+ case TraceItem::FunctionCycle: popup1->setItemChecked(4, true); break;
+ default: break;
+ }
+ connect(popup1,SIGNAL(activated(int)),
+ _topLevel,SLOT(groupTypeSelected(int)));
+
+ popup->insertItem(i18n("Grouping"), popup1);
+}
+
+
+TraceItem* FunctionSelection::canShow(TraceItem* i)
+{
+ TraceItem::CostType t = i ? i->type() : TraceItem::NoCostType;
+
+ switch(t) {
+ case TraceItem::Function:
+ case TraceItem::FunctionCycle:
+ case TraceItem::Object:
+ case TraceItem::File:
+ case TraceItem::Class:
+ break;
+
+ case TraceItem::Instr:
+ i = ((TraceInstr*)i)->function();
+ break;
+
+ case TraceItem::Line:
+ i = ((TraceLine*)i)->functionSource()->function();
+ break;
+
+ default:
+ i = 0;
+ break;
+ }
+ return i;
+}
+
+
+void FunctionSelection::doUpdate(int changeType)
+{
+ // Special case ?
+ if (changeType == selectedItemChanged) return;
+
+ // we don't show cost 2 at all...
+ if (changeType == costType2Changed) return;
+
+ if (changeType == activeItemChanged) {
+ if (_activeItem ==0) {
+ functionList->clearSelection();
+ return;
+ }
+ switch(_activeItem->type()) {
+ case TraceItem::Object:
+ case TraceItem::File:
+ case TraceItem::Class:
+ setGroup((TraceCostItem*)_activeItem);
+ return;
+ default: break;
+ }
+
+ // active item is a function
+ TraceFunction* f = (TraceFunction*) _activeItem;
+
+ // if already current, nothing to do
+ QListViewItem* i = functionList->currentItem();
+ if (i && (((FunctionItem*)i)->function() == f)) {
+ functionList->setSelected(i,true);
+ return;
+ }
+
+ // reset searchEdit (as not activated from this view)
+ _searchString = QString::null;
+ query(QString::null);
+
+ // select cost item group of function
+ switch(_groupType) {
+ case TraceItem::Object: setGroup(f->object()); break;
+ case TraceItem::Class: setGroup(f->cls()); break;
+ case TraceItem::File: setGroup(f->file()); break;
+ case TraceItem::FunctionCycle: setGroup(f->cycle()); break;
+ default:
+ break;
+ }
+
+ QListViewItem* item = functionList->firstChild();
+ for (;item;item = item->nextSibling())
+ if (((FunctionItem*)item)->function() == f)
+ break;
+
+ if (!item)
+ item = new FunctionItem(functionList, f, _costType, _groupType);
+
+ functionList->ensureItemVisible(item);
+ // prohibit signalling of a function selection
+ _inSetFunction = true;
+ functionList->setSelected(item, true);
+ _inSetFunction = false;
+
+ return;
+ }
+
+ if (changeType & groupTypeChanged) {
+ if (_activeItem && (_activeItem->type() == TraceItem::Function)) {
+ TraceFunction* f = (TraceFunction*) _activeItem;
+
+ // select cost item group of function
+ switch(_groupType) {
+ case TraceItem::Object: _group = f->object(); break;
+ case TraceItem::Class: _group = f->cls(); break;
+ case TraceItem::File: _group = f->file(); break;
+ case TraceItem::FunctionCycle: _group = f->cycle(); break;
+ default:
+ _group = 0;
+ break;
+ }
+ }
+
+ int id;
+ switch(_groupType) {
+ case TraceItem::Object: id = 1; break;
+ case TraceItem::File: id = 2; break;
+ case TraceItem::Class: id = 3; break;
+ case TraceItem::FunctionCycle: id = 4; break;
+ default: id = 0; break;
+ }
+ groupBox->setCurrentItem(id);
+
+ if (_groupType == TraceItem::Function)
+ groupList->hide();
+ else
+ groupList->show();
+ }
+
+ // reset searchEdit
+ _searchString = QString::null;
+ query(QString::null);
+
+ refresh();
+}
+
+
+/*
+ * This set/selects a group of the set available within the
+ * current group type
+ */
+void FunctionSelection::setGroup(TraceCostItem* g)
+{
+ if (!g) return;
+ if (g->type() != _groupType) return;
+ if (g == _group) return;
+ _group = g;
+
+ QListViewItem* item = groupList->firstChild();
+ for (;item;item = item->nextSibling())
+ if (((CostListItem*)item)->costItem() == g)
+ break;
+
+ if (item) {
+ groupList->ensureItemVisible(item);
+ // prohibit signalling of a group selection
+ _inSetGroup = true;
+ groupList->setSelected(item, true);
+ _inSetGroup = false;
+ }
+ else
+ groupList->clearSelection();
+}
+
+
+void FunctionSelection::refresh()
+{
+ groupList->setUpdatesEnabled(false);
+ groupList->clear();
+
+ // make cost columns as small as possible:
+ // the new functions make them as wide as needed
+ groupList->setColumnWidth(0, 50);
+
+ groupList->setColumnText(1, TraceItem::i18nTypeName(_groupType));
+
+ if (!_data || _data->parts().count()==0) {
+ functionList->clear();
+ groupList->setUpdatesEnabled(true);
+ groupList->repaint();
+
+ // this clears all other lists
+ functionList->setSelected(functionList->firstChild(), true);
+ return;
+ }
+
+ /*
+ qDebug("FunctionSelection::fillLists (%s)",
+ _data->command().ascii());
+ */
+
+ TraceObjectMap::Iterator oit;
+ TraceClassMap::Iterator cit;
+ TraceFileMap::Iterator fit;
+ QListViewItem *i = 0, *item = 0, *fitem = 0;
+
+ // Fill up group list.
+ // Always show group of current function, even if cost below low limit.
+ //
+
+ _hc.clear(Configuration::maxListCount());
+
+ TraceCostItem *group;
+
+ // update group from _activeItem if possible
+ if (_activeItem && (_activeItem->type() == _groupType))
+ _group = (TraceCostItem*) _activeItem;
+
+ switch(_groupType) {
+ case TraceItem::Object:
+
+ for ( oit = _data->objectMap().begin();
+ oit != _data->objectMap().end(); ++oit )
+ _hc.addCost(&(*oit), (*oit).subCost(_costType));
+ break;
+
+ case TraceItem::Class:
+
+ for ( cit = _data->classMap().begin();
+ cit != _data->classMap().end(); ++cit )
+ _hc.addCost(&(*cit), (*cit).subCost(_costType));
+ break;
+
+ case TraceItem::File:
+
+ for ( fit = _data->fileMap().begin();
+ fit != _data->fileMap().end(); ++fit )
+ _hc.addCost(&(*fit), (*fit).subCost(_costType));
+ break;
+
+ case TraceItem::FunctionCycle:
+ {
+ // add all cycles
+ TraceFunctionCycleList l = _data->functionCycles();
+ for (group=l.first();group;group=l.next())
+ _hc.addCost(group, group->subCost(_costType));
+ }
+
+ break;
+
+ default:
+ {
+ QListViewItem* oldItem = functionList->selectedItem();
+ TraceFunction* oldFunction = 0;
+ int oldPos = 0;
+ if (oldItem) {
+ oldFunction = ((FunctionItem*)oldItem)->function();
+ oldPos = oldItem->itemPos();
+ oldPos -= functionList->contentsY();
+ if (oldPos < 0 || oldPos > functionList->height())
+ oldFunction = 0;
+ }
+
+ // switching off QListView updates is buggy with some QT versions...
+ //functionList->setUpdatesEnabled(false);
+ functionList->clear();
+ setCostColumnWidths();
+
+ if (0) qDebug("Function %s at %d, Item %p",
+ oldFunction ? oldFunction->name().ascii() : "-",
+ oldPos, (void*)oldItem);
+
+ TraceFunctionMap::Iterator it;
+ TraceFunction *f;
+ i = 0;
+ fitem = 0;
+ for ( it = _data->functionMap().begin();
+ it != _data->functionMap().end(); ++it )
+ _hc.addCost(&(*it), (*it).inclusive()->subCost(_costType));
+
+ TraceFunctionCycleList l = _data->functionCycles();
+ for (f=l.first();f;f=l.next())
+ _hc.addCost(f, f->inclusive()->subCost(_costType));
+
+ if (_activeItem &&
+ ((_activeItem->type() == TraceItem::Function) ||
+ (_activeItem->type() == TraceItem::FunctionCycle)))
+ fitem = new FunctionItem(functionList, (TraceFunction*)_activeItem,
+ _costType, _groupType);
+
+ for(int i=0;i<_hc.realCount();i++) {
+ f = (TraceFunction*)_hc[i];
+ if (f == _activeItem) continue;
+ new FunctionItem(functionList, f, _costType, _groupType);
+ }
+ if (_hc.hasMore()) {
+ // a placeholder for all the cost items skipped ...
+ new FunctionItem(functionList, _hc.count() - _hc.maxSize(),
+ (TraceFunction*)_hc[_hc.maxSize()-1], _costType);
+ }
+ functionList->sort();
+
+ if (fitem && oldFunction) {
+ _inSetFunction = true;
+ functionList->setSelected(fitem, true);
+ _inSetFunction = false;
+ int newPos = functionList->itemPos(fitem) - functionList->contentsY();
+ functionList->scrollBy(0, newPos-oldPos);
+ }
+ else if (fitem) {
+ functionList->ensureItemVisible(fitem);
+ _inSetFunction = true;
+ functionList->setSelected(fitem, true);
+ _inSetFunction = false;
+ }
+ else
+ functionList->clearSelection();
+
+ //functionList->setUpdatesEnabled(true);
+ //functionList->repaint();
+ groupList->setUpdatesEnabled(true);
+ groupList->repaint();
+ return;
+ }
+ }
+
+ // we always put group of active item in list, even if
+ // it would be skipped because of small costs
+ if (_group)
+ item = new CostListItem(groupList, _group, _costType);
+
+ for(int i=0;i<_hc.realCount();i++) {
+ group = (TraceCostItem*)_hc[i];
+ // don't put group of active item twice into list
+ if (group == _group) continue;
+ new CostListItem(groupList, group, _costType);
+ }
+ if (_hc.hasMore()) {
+ // a placeholder for all the cost items skipped ...
+ new CostListItem(groupList, _hc.count() - _hc.maxSize(),
+ (TraceCostItem*)_hc[_hc.maxSize()-1], _costType);
+ }
+ groupList->sort();
+ if (item) {
+ groupList->ensureItemVisible(item);
+ _inSetGroup = true;
+ groupList->setSelected(item, true);
+ _inSetGroup = false;
+ }
+ else
+ groupList->clearSelection();
+
+ groupList->setUpdatesEnabled(true);
+ groupList->repaint();
+}
+
+
+void FunctionSelection::groupSelected(QListViewItem* i)
+{
+ if (!i) return;
+ if (!_data) return;
+
+ TraceCostItem* g = ((CostListItem*) i)->costItem();
+ if (!g) return;
+
+ _group = g;
+
+ TraceFunctionList list;
+
+ switch(g->type()) {
+ case TraceItem::Object:
+ list = ((TraceObject*)g)->functions();
+ break;
+ case TraceItem::Class:
+ list = ((TraceClass*)g)->functions();
+ break;
+ case TraceItem::File:
+ list = ((TraceFile*)g)->functions();
+ break;
+ case TraceItem::FunctionCycle:
+ list = ((TraceFunctionCycle*)g)->members();
+ break;
+ default:
+ return;
+ }
+
+ // switching off QListView updates is buggy with some QT versions...
+ //functionList->setUpdatesEnabled(false);
+
+ functionList->clear();
+ setCostColumnWidths();
+
+ double total;
+ if (Configuration::showExpanded())
+ total = (double) g->subCost(_costType);
+ else
+ total = (double) _data->subCost(_costType);
+#if 0
+ if (total == 0.0) {
+ functionList->setUpdatesEnabled(true);
+ functionList->repaint();
+ return;
+ }
+#endif
+
+ QRegExp re(_searchString, false, true);
+
+ FunctionItem* fitem = 0;
+ TraceFunction *f;
+ _hc.clear(Configuration::maxListCount());
+ for (f=list.first();f;f=list.next()) {
+ if (re.search(f->prettyName())<0) continue;
+
+ _hc.addCost(f, f->inclusive()->subCost(_costType));
+ if (_activeItem == f)
+ fitem = new FunctionItem(functionList, (TraceFunction*)_activeItem,
+ _costType, _groupType);
+ }
+
+ for(int i=0;i<_hc.realCount();i++) {
+ if (_activeItem == (TraceFunction*)_hc[i]) continue;
+ new FunctionItem(functionList, (TraceFunction*)_hc[i],
+ _costType, _groupType);
+ }
+
+ if (_hc.hasMore()) {
+ // a placeholder for all the functions skipped ...
+ new FunctionItem(functionList, _hc.count() - _hc.maxSize(),
+ (TraceFunction*)_hc[_hc.maxSize()-1], _costType);
+ }
+ functionList->sort();
+
+ if (fitem) {
+ functionList->ensureItemVisible(fitem);
+ _inSetFunction = true;
+ functionList->setSelected(fitem, true);
+ _inSetFunction = false;
+ }
+
+ //functionList->setUpdatesEnabled(true);
+ //functionList->repaint();
+
+ // Don't emit signal if cost item was changed programatically
+ if (!_inSetGroup) {
+ _selectedItem = g;
+ selected(g);
+ }
+}
+
+void FunctionSelection::groupDoubleClicked(QListViewItem* i)
+{
+ if (!i) return;
+ if (!_data) return;
+ TraceCostItem* g = ((CostListItem*) i)->costItem();
+
+ if (!g) return;
+ // group must be selected first
+ if (g != _group) return;
+
+ activated(g);
+}
+
+
+TraceCostItem* FunctionSelection::group(QString s)
+{
+ QListViewItem *item;
+ item = groupList->firstChild();
+ for(;item;item = item->nextSibling())
+ if (((CostListItem*)item)->costItem()->name() == s)
+ return ((CostListItem*)item)->costItem();
+
+ return 0;
+}
+
+
+
+void FunctionSelection::functionSelected(QListViewItem* i)
+{
+ if (!i) return;
+ if (!_data) return;
+
+ TraceFunction* f = ((FunctionItem*) i)->function();
+ if (!f) return;
+
+ //qDebug("FunctionSelection::functionSelected %s", f->name().ascii());
+
+ // Don't emit signal if function was changed programatically
+ if (!_inSetFunction) {
+ _selectedItem = f;
+ selected(f);
+ }
+}
+
+void FunctionSelection::functionActivated(QListViewItem* i)
+{
+ if (!i) return;
+ if (!_data) return;
+ TraceFunction* f = ((FunctionItem*) i)->function();
+
+ if (!f) return;
+
+ if (!_inSetFunction)
+ activated(f);
+}
+
+void FunctionSelection::updateGroupSizes(bool hideEmpty)
+{
+ QListViewItem* item = groupList->firstChild();
+ for (;item;item = item->nextSibling()) {
+ CostListItem* i = (CostListItem*)item;
+ int size = (_groupSize.contains(i->costItem())) ?
+ _groupSize[i->costItem()] : -1;
+ i->setSize(size);
+ i->setVisible(!hideEmpty || (size>0));
+ }
+}
+
+void FunctionSelection::query(QString query)
+{
+ if (searchEdit->text() != query)
+ searchEdit->setText(query);
+ if (_searchString == query) {
+ // when resetting query, get rid of group sizes
+ if (query.isEmpty()) {
+ _groupSize.clear();
+ updateGroupSizes(false);
+ }
+ return;
+ }
+ _searchString = query;
+
+ QRegExp re(query, false, true);
+ _groupSize.clear();
+
+ TraceFunction* f = 0;
+ TraceFunctionList list2;
+
+ _hc.clear(Configuration::maxListCount());
+
+ TraceFunctionMap::Iterator it;
+ for ( it = _data->functionMap().begin();
+ it != _data->functionMap().end(); ++it ) {
+ f = &(*it);
+ if (re.search(f->prettyName())>=0) {
+ if (_group) {
+ if (_groupType==TraceItem::Object) {
+ if (_groupSize.contains(f->object()))
+ _groupSize[f->object()]++;
+ else
+ _groupSize[f->object()] = 1;
+ if (f->object() != _group) continue;
+ }
+ else if (_groupType==TraceItem::Class) {
+ if (_groupSize.contains(f->cls()))
+ _groupSize[f->cls()]++;
+ else
+ _groupSize[f->cls()] = 1;
+ if (f->cls() != _group) continue;
+ }
+ else if (_groupType==TraceItem::File) {
+ if (_groupSize.contains(f->file()))
+ _groupSize[f->file()]++;
+ else
+ _groupSize[f->file()] = 1;
+ if (f->file() != _group) continue;
+ }
+ else if (_groupType==TraceItem::FunctionCycle) {
+ if (_groupSize.contains(f->cycle()))
+ _groupSize[f->cycle()]++;
+ else
+ _groupSize[f->cycle()] = 1;
+ if (f->cycle() != _group) continue;
+ }
+ }
+ _hc.addCost(f, f->inclusive()->subCost(_costType));
+ }
+ }
+
+ updateGroupSizes(true);
+
+ FunctionItem *fi, *item = 0;
+
+ functionList->clear();
+ setCostColumnWidths();
+
+ for(int i=0;i<_hc.realCount();i++) {
+ fi = new FunctionItem(functionList, (TraceFunction*)_hc[i],
+ _costType, _groupType);
+ if (_activeItem == f) item = fi;
+ }
+ if (_hc.hasMore()) {
+ // a placeholder for all the functions skipped ...
+ new FunctionItem(functionList, _hc.count() - _hc.maxSize(),
+ (TraceFunction*)_hc[_hc.maxSize()-1], _costType);
+ }
+
+ functionList->sort();
+
+
+ if (item) {
+ functionList->ensureItemVisible(item);
+ _inSetFunction = true;
+ functionList->setSelected(item, true);
+ _inSetFunction = false;
+ }
+ else {
+ // this emits a function selection
+ functionList->setSelected(functionList->firstChild(), true);
+ }
+}
+
+bool FunctionSelection::setTopFunction()
+{
+ QListViewItem* i = functionList->firstChild();
+ // this emits a function selection
+ functionList->setSelected(i, true);
+ functionActivated(i);
+ return i!=0;
+}
+
+void FunctionSelection::setCostColumnWidths()
+{
+ if (_costType && (_costType->subCost(_data->callMax())>0) ) {
+ functionList->setColumnWidthMode(0, QListView::Maximum);
+ functionList->setColumnWidth(0,50);
+ functionList->setColumnWidthMode(2, QListView::Maximum);
+ functionList->setColumnWidth(2,50);
+ }
+ else {
+ functionList->setColumnWidthMode(0, QListView::Manual);
+ functionList->setColumnWidth(0,0);
+ functionList->setColumnWidthMode(2, QListView::Manual);
+ functionList->setColumnWidth(2,0);
+ }
+
+ functionList->setColumnWidth(1, 50);
+}
+
+
+
+#include "functionselection.moc"
diff --git a/kcachegrind/kcachegrind/functionselection.h b/kcachegrind/kcachegrind/functionselection.h
new file mode 100644
index 00000000..84e637aa
--- /dev/null
+++ b/kcachegrind/kcachegrind/functionselection.h
@@ -0,0 +1,85 @@
+/* This file is part of KCachegrind.
+ Copyright (C) 2002, 2003 Josef Weidendorfer <Josef.Weidendorfer@gmx.de>
+
+ KCachegrind is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public
+ License as published by the Free Software Foundation, version 2.
+
+ 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; see the file COPYING. If not, write to
+ the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+*/
+
+/*
+ * For function selection, to be put into a QDockWindow
+ */
+
+#ifndef FUNCTIONSELECTION_H
+#define FUNCTIONSELECTION_H
+
+#include "functionselectionbase.h"
+#include "traceitemview.h"
+#include "tracedata.h"
+#include "listutils.h"
+
+class QPopupMenu;
+
+class TraceFunction;
+class TraceData;
+class StackBrowser;
+class NestedAreaItem;
+
+class FunctionSelection : public FunctionSelectionBase, public TraceItemView
+{
+ Q_OBJECT
+
+public:
+ FunctionSelection( TopLevel*, QWidget* parent = 0, const char* name = 0);
+ ~FunctionSelection();
+
+ TraceCostItem* group(QString);
+ void setGroup(TraceCostItem*);
+ void query(QString);
+ bool setTopFunction();
+
+ QWidget* widget() { return this; }
+
+ void addGroupMenu(QPopupMenu*);
+
+public slots:
+ void searchReturnPressed();
+ void searchChanged(const QString&);
+ void queryDelayed();
+ void groupDoubleClicked( QListViewItem* );
+ void functionActivated( QListViewItem* );
+ void groupSelected( QListViewItem* );
+ void functionSelected( QListViewItem* );
+ void functionContext(QListViewItem*, const QPoint &, int);
+ void groupContext(QListViewItem*, const QPoint &, int);
+
+private:
+ TraceItem* canShow(TraceItem* i);
+ void doUpdate(int);
+ void selectFunction();
+ void refresh();
+ void setCostColumnWidths();
+ void updateGroupSizes(bool hideEmpty);
+
+ TraceCostItem* _group;
+
+ QString _searchString, _searchDelayed;
+ QTimer _searchTimer;
+ QMap<TraceCostItem*,int> _groupSize;
+
+ HighestCostList _hc;
+ // when setting a
+ bool _inSetGroup, _inSetFunction;
+};
+
+#endif
diff --git a/kcachegrind/kcachegrind/functionselectionbase.ui b/kcachegrind/kcachegrind/functionselectionbase.ui
new file mode 100644
index 00000000..e59dc26c
--- /dev/null
+++ b/kcachegrind/kcachegrind/functionselectionbase.ui
@@ -0,0 +1,163 @@
+<!DOCTYPE UI><UI version="3.1" stdsetdef="1">
+<class>FunctionSelectionBase</class>
+<widget class="QWidget">
+ <property name="name">
+ <cstring>FunctionSelectionBase</cstring>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>223</width>
+ <height>485</height>
+ </rect>
+ </property>
+ <property name="caption">
+ <string>Function Profile</string>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>3</number>
+ </property>
+ <property name="spacing">
+ <number>6</number>
+ </property>
+ <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>searchLabel</cstring>
+ </property>
+ <property name="text">
+ <string>&amp;Search:</string>
+ </property>
+ <property name="buddy" stdset="0">
+ <cstring>searchEdit</cstring>
+ </property>
+ </widget>
+ <widget class="QLineEdit">
+ <property name="name">
+ <cstring>searchEdit</cstring>
+ </property>
+ </widget>
+ <widget class="QComboBox">
+ <property name="name">
+ <cstring>groupBox</cstring>
+ </property>
+ </widget>
+ </hbox>
+ </widget>
+ <widget class="QListView">
+ <column>
+ <property name="text">
+ <string>Self</string>
+ </property>
+ <property name="clickable">
+ <bool>true</bool>
+ </property>
+ <property name="resizable">
+ <bool>true</bool>
+ </property>
+ </column>
+ <column>
+ <property name="text">
+ <string>Group</string>
+ </property>
+ <property name="clickable">
+ <bool>true</bool>
+ </property>
+ <property name="resizable">
+ <bool>true</bool>
+ </property>
+ </column>
+ <property name="name">
+ <cstring>groupList</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>7</hsizetype>
+ <vsizetype>5</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="maximumSize">
+ <size>
+ <width>32767</width>
+ <height>150</height>
+ </size>
+ </property>
+ </widget>
+ <widget class="QListView">
+ <column>
+ <property name="text">
+ <string>Incl.</string>
+ </property>
+ <property name="clickable">
+ <bool>true</bool>
+ </property>
+ <property name="resizable">
+ <bool>true</bool>
+ </property>
+ </column>
+ <column>
+ <property name="text">
+ <string>Self</string>
+ </property>
+ <property name="clickable">
+ <bool>true</bool>
+ </property>
+ <property name="resizable">
+ <bool>true</bool>
+ </property>
+ </column>
+ <column>
+ <property name="text">
+ <string>Called</string>
+ </property>
+ <property name="clickable">
+ <bool>true</bool>
+ </property>
+ <property name="resizable">
+ <bool>true</bool>
+ </property>
+ </column>
+ <column>
+ <property name="text">
+ <string>Function</string>
+ </property>
+ <property name="clickable">
+ <bool>true</bool>
+ </property>
+ <property name="resizable">
+ <bool>true</bool>
+ </property>
+ </column>
+ <column>
+ <property name="text">
+ <string>Location</string>
+ </property>
+ <property name="clickable">
+ <bool>true</bool>
+ </property>
+ <property name="resizable">
+ <bool>true</bool>
+ </property>
+ </column>
+ <property name="name">
+ <cstring>functionList</cstring>
+ </property>
+ </widget>
+ </vbox>
+</widget>
+<layoutdefaults spacing="6" margin="11"/>
+</UI>
diff --git a/kcachegrind/kcachegrind/hi32-app-kcachegrind.png b/kcachegrind/kcachegrind/hi32-app-kcachegrind.png
new file mode 100644
index 00000000..bd41daec
--- /dev/null
+++ b/kcachegrind/kcachegrind/hi32-app-kcachegrind.png
Binary files differ
diff --git a/kcachegrind/kcachegrind/hi48-app-kcachegrind.png b/kcachegrind/kcachegrind/hi48-app-kcachegrind.png
new file mode 100644
index 00000000..58c2efdb
--- /dev/null
+++ b/kcachegrind/kcachegrind/hi48-app-kcachegrind.png
Binary files differ
diff --git a/kcachegrind/kcachegrind/instritem.cpp b/kcachegrind/kcachegrind/instritem.cpp
new file mode 100644
index 00000000..85705f64
--- /dev/null
+++ b/kcachegrind/kcachegrind/instritem.cpp
@@ -0,0 +1,469 @@
+/* This file is part of KCachegrind.
+ Copyright (C) 2003 Josef Weidendorfer <Josef.Weidendorfer@gmx.de>
+
+ KCachegrind is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public
+ License as published by the Free Software Foundation, version 2.
+
+ 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; see the file COPYING. If not, write to
+ the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+*/
+
+/*
+ * Items of instruction view.
+ */
+
+#include <qpixmap.h>
+#include <qpainter.h>
+
+#include <klocale.h>
+#include <kapplication.h>
+#include <kiconloader.h>
+#include <kdebug.h>
+
+#include "configuration.h"
+#include "listutils.h"
+#include "instritem.h"
+#include "instrview.h"
+
+
+// InstrItem
+
+// for messages
+InstrItem::InstrItem(InstrView* iv, QListView* parent,
+ Addr addr, const QString& msg)
+ : QListViewItem(parent)
+{
+ _view = iv;
+ _addr = addr;
+ _instr = 0;
+ _instrCall = 0;
+ _instrJump = 0;
+ _inside = false;
+
+ setText(0, addr.pretty());
+ setText(6, msg);
+
+ updateGroup();
+ updateCost();
+}
+
+// for code lines
+InstrItem::InstrItem(InstrView* iv, QListView* parent,
+ Addr addr, bool inside,
+ const QString& code, const QString& cmd,
+ const QString& args, TraceInstr* instr)
+ : QListViewItem(parent)
+{
+ _view = iv;
+ _addr = addr;
+ _instr = instr;
+ _instrCall = 0;
+ _instrJump = 0;
+ _inside = inside;
+
+ if (args == "...")
+ setText(0, args);
+ else
+ setText(0, addr.pretty());
+ setText(4, code);
+ setText(5, cmd);
+ setText(6, args);
+
+ TraceLine* l;
+ if (instr && (l = instr->line()))
+ setText(7, l->name());
+
+ updateGroup();
+ updateCost();
+}
+
+// for call lines
+InstrItem::InstrItem(InstrView* iv, QListViewItem* parent, Addr addr,
+ TraceInstr* instr, TraceInstrCall* instrCall)
+ : QListViewItem(parent)
+{
+ _view = iv;
+ _addr = addr;
+ _instr = instr;
+ _instrCall = instrCall;
+ _instrJump = 0;
+ _inside = true;
+
+ //qDebug("InstrItem: (file %d, line %d) Linecall to %s",
+ // fileno, lineno, _lineCall->call()->called()->prettyName().ascii());
+
+ SubCost cc = _instrCall->callCount();
+ QString templ = " ";
+ if (cc==0)
+ templ += i18n("Active call to '%1'");
+ else
+ templ += i18n("%n call to '%1'", "%n calls to '%1'", cc);
+
+ QString callStr = templ.arg(_instrCall->call()->calledName());
+ TraceFunction* calledF = _instrCall->call()->called();
+ calledF->addPrettyLocation(callStr);
+
+ setText(6, callStr);
+
+ updateGroup();
+ updateCost();
+}
+
+// for jump lines
+InstrItem::InstrItem(InstrView* iv, QListViewItem* parent, Addr addr,
+ TraceInstr* instr, TraceInstrJump* instrJump)
+ : QListViewItem(parent)
+{
+ _view = iv;
+ _addr = addr;
+ _inside = true;
+ _instr = instr;
+ _instrCall = 0;
+ _instrJump = instrJump;
+
+ //qDebug("SourceItem: (file %d, line %d) Linecall to %s",
+ // fileno, lineno, _lineCall->call()->called()->prettyName().ascii());
+
+ QString jStr;
+ if (_instrJump->isCondJump())
+ jStr = i18n("Jump %1 of %2 times to 0x%3")
+ .arg(_instrJump->followedCount().pretty())
+ .arg(_instrJump->executedCount().pretty())
+ .arg(_instrJump->instrTo()->addr().toString());
+ else
+ jStr = i18n("Jump %1 times to 0x%2")
+ .arg(_instrJump->executedCount().pretty())
+ .arg(_instrJump->instrTo()->addr().toString());
+
+ setText(6, jStr);
+
+ updateGroup();
+ updateCost();
+}
+
+
+void InstrItem::updateGroup()
+{
+ if (!_instrCall) return;
+
+ TraceFunction* f = _instrCall->call()->called();
+ QColor c = Configuration::functionColor(_view->groupType(), f);
+ setPixmap(6, colorPixmap(10, 10, c));
+}
+
+void InstrItem::updateCost()
+{
+ _pure = SubCost(0);
+ _pure2 = SubCost(0);
+
+ if (!_instr) return;
+ if (_instrJump) return;
+
+ TraceCost* instrCost = _instrCall ?
+ (TraceCost*)_instrCall : (TraceCost*)_instr;
+
+ // don't show any cost inside of cycles
+ if (_instrCall &&
+ ((_instrCall->call()->inCycle()>0) ||
+ (_instrCall->call()->isRecursion()>0))) {
+ QString str;
+ QPixmap p;
+
+ QString icon = "undo";
+ KIconLoader* loader = KApplication::kApplication()->iconLoader();
+ p= loader->loadIcon(icon, KIcon::Small, 0,
+ KIcon::DefaultState, 0, true);
+ if (p.isNull())
+ str = i18n("(cycle)");
+
+ setText(1, str);
+ setPixmap(1, p);
+ setText(2, str);
+ setPixmap(2, p);
+ return;
+ }
+
+ TraceCost* totalCost;
+ if (Configuration::showExpanded())
+ totalCost = _instr->function()->inclusive();
+ else
+ totalCost = _instr->function()->data();
+
+ TraceCostType *ct = _view->costType();
+ _pure = ct ? instrCost->subCost(ct) : SubCost(0);
+ if (_pure == 0) {
+ setText(1, QString::null);
+ setPixmap(1, QPixmap());
+ }
+ else {
+ double total = totalCost->subCost(ct);
+ double pure = 100.0 * _pure / total;
+
+ if (Configuration::showPercentage())
+ setText(1, QString("%1")
+ .arg(pure, 0, 'f', Configuration::percentPrecision()));
+ else
+ setText(1, _pure.pretty());
+
+ setPixmap(1, costPixmap(ct, instrCost, total, false));
+ }
+
+ TraceCostType *ct2 = _view->costType2();
+ _pure2 = ct2 ? instrCost->subCost(ct2) : SubCost(0);
+ if (_pure2 == 0) {
+ setText(2, QString::null);
+ setPixmap(2, QPixmap());
+ }
+ else {
+ double total = totalCost->subCost(ct2);
+ double pure = 100.0 * _pure2 / total;
+
+ if (Configuration::showPercentage())
+ setText(2, QString("%1")
+ .arg(pure, 0, 'f', Configuration::percentPrecision()));
+ else
+ setText(2, _pure2.pretty());
+
+ setPixmap(2, costPixmap(ct2, instrCost, total, false));
+ }
+}
+
+
+int InstrItem::compare(QListViewItem * i, int col, bool ascending ) const
+{
+ const InstrItem* ii1 = this;
+ const InstrItem* ii2 = (InstrItem*) i;
+
+ // we always want descending order
+ if (((col>0) && ascending) ||
+ ((col==0) && !ascending) ) {
+ ii1 = ii2;
+ ii2 = this;
+ }
+
+ if (col==1) {
+ if (ii1->_pure < ii2->_pure) return -1;
+ if (ii1->_pure > ii2->_pure) return 1;
+ return 0;
+ }
+ if (col==2) {
+ if (ii1->_pure2 < ii2->_pure2) return -1;
+ if (ii1->_pure2 > ii2->_pure2) return 1;
+ return 0;
+ }
+ if (col==0) {
+ if (ii1->_addr < ii2->_addr) return -1;
+ if (ii1->_addr > ii2->_addr) return 1;
+
+ // Same address: code gets above calls/jumps
+ if (!ii1->_instrCall && !ii1->_instrJump) return -1;
+ if (!ii2->_instrCall && !ii2->_instrJump) return 1;
+
+ // calls above jumps
+ if (ii1->_instrCall && !ii2->_instrCall) return -1;
+ if (ii2->_instrCall && !ii1->_instrCall) return 1;
+
+ if (ii1->_instrCall && ii2->_instrCall) {
+ // Two calls: desending sort according costs
+ if (ii1->_pure < ii2->_pure) return 1;
+ if (ii1->_pure > ii2->_pure) return -1;
+
+ // Two calls: sort according function names
+ TraceFunction* f1 = ii1->_instrCall->call()->called();
+ TraceFunction* f2 = ii2->_instrCall->call()->called();
+ if (f1->prettyName() > f2->prettyName()) return 1;
+ return -1;
+ }
+
+ // Two jumps: descending sort according target address
+ if (ii1->_instrJump->instrTo()->addr() <
+ ii2->_instrJump->instrTo()->addr())
+ return -1;
+ if (ii1->_instrJump->instrTo()->addr() >
+ ii2->_instrJump->instrTo()->addr())
+ return 1;
+ return 0;
+
+ }
+ return QListViewItem::compare(i, col, ascending);
+}
+
+void InstrItem::paintCell( QPainter *p, const QColorGroup &cg,
+ int column, int width, int alignment )
+{
+ QColorGroup _cg( cg );
+
+ if ( !_inside || ((column==1) || column==2))
+ _cg.setColor( QColorGroup::Base, cg.button() );
+ else if ((_instrCall || _instrJump) && column>2)
+ _cg.setColor( QColorGroup::Base, cg.midlight() );
+
+ if (column == 3)
+ paintArrows(p, _cg, width);
+ else
+ QListViewItem::paintCell( p, _cg, column, width, alignment );
+}
+
+void InstrItem::setJumpArray(const QMemArray<TraceInstrJump*>& a)
+{
+ _jump.duplicate(a);
+}
+
+void InstrItem::paintArrows(QPainter *p, const QColorGroup &cg, int width)
+{
+ QListView *lv = listView();
+ if ( !lv ) return;
+ InstrView* iv = (InstrView*) lv;
+
+ const BackgroundMode bgmode = lv->viewport()->backgroundMode();
+ const QColorGroup::ColorRole crole
+ = QPalette::backgroundRoleFromMode( bgmode );
+ if ( cg.brush( crole ) != lv->colorGroup().brush( crole ) )
+ p->fillRect( 0, 0, width, height(), cg.brush( crole ) );
+ else
+ iv->paintEmptyArea( p, QRect( 0, 0, width, height() ) );
+
+ if ( isSelected() && lv->allColumnsShowFocus() )
+ p->fillRect( 0, 0, width, height(), cg.brush( QColorGroup::Highlight ) );
+
+ int marg = lv->itemMargin();
+ int yy = height()/2, y1, y2;
+ QColor c;
+
+ int start = -1, end = -1;
+
+ // draw line borders, detect start/stop of a line
+ for(int i=0;i< (int)_jump.size();i++) {
+ if (_jump[i] == 0) continue;
+
+ y1 = 0;
+ y2 = height();
+ if ((_instrJump == _jump[i]) &&
+ (_jump[i]->instrFrom()->addr() == _addr)) {
+
+ //kdDebug() << "InstrItem " << _addr.toString() << ": start " << i << endl;
+ if (start<0) start = i;
+ if (_jump[i]->instrTo()->addr() <= _addr)
+ y2 = yy;
+ else
+ y1 = yy;
+ }
+ else if (!_instrJump && !_instrCall &&
+ (_jump[i]->instrTo()->addr() == _addr)) {
+
+ //kdDebug() << "InstrItem " << _addr.toString() << ": end " << i << endl;
+ if (end<0) end = i;
+ if (_jump[i]->instrFrom()->addr() < _addr)
+ y2 = yy;
+ else
+ y1 = yy;
+ }
+
+ c = _jump[i]->isCondJump() ? red : blue;
+#if 0
+ if (_jump[i] == ((TraceItemView*)_view)->selectedItem()) {
+ p->fillRect( marg + 6*i-2, (y1==0) ? y1: y1-2,
+ 8, (y2-y1==height())? y2:y2+2,
+ cg.brush( QColorGroup::Highlight ) );
+ c = lv->colorGroup().highlightedText();
+ }
+#endif
+ p->fillRect( marg + 6*i, y1, 4, y2, c);
+ p->setPen(c.light());
+ p->drawLine( marg + 6*i, y1, marg + 6*i, y2);
+ p->setPen(c.dark());
+ p->drawLine( marg + 6*i +3, y1, marg + 6*i +3, y2);
+ }
+
+ // draw start/stop horizontal line
+ int x, y = yy-2, w, h = 4;
+ if (start >= 0) {
+#if 0
+ if (_jump[start] == ((TraceItemView*)_view)->selectedItem()) {
+ c = lv->colorGroup().highlightedText();
+ }
+#endif
+ c = _jump[start]->isCondJump() ? red : blue;
+ x = marg + 6*start;
+ w = 6*(iv->arrowLevels() - start) + 10;
+ p->fillRect( x, y, w, h, c);
+ p->setPen(c.light());
+ p->drawLine(x, y, x+w-1, y);
+ p->drawLine(x, y, x, y+h-1);
+ p->setPen(c.dark());
+ p->drawLine(x+w-1, y, x+w-1, y+h-1);
+ p->drawLine(x+1, y+h-1, x+w-1, y+h-1);
+ }
+ if (end >= 0) {
+ c = _jump[end]->isCondJump() ? red : blue;
+ x = marg + 6*end;
+ w = 6*(iv->arrowLevels() - end) + 10;
+
+ QPointArray a;
+ a.putPoints(0, 7, x, y+h,
+ x,y, x+w-8, y, x+w-8, y-2,
+ x+w, yy,
+ x+w-8, y+h+2, x+w-8, y+h);
+ p->setBrush(c);
+ p->drawConvexPolygon(a);
+
+ p->setPen(c.light());
+ p->drawPolyline(a, 0, 5);
+ p->setPen(c.dark());
+ p->drawPolyline(a, 4, 2);
+ p->setPen(c.light());
+ p->drawPolyline(a, 5, 2);
+ p->setPen(c.dark());
+ p->drawPolyline(a, 6, 2);
+ }
+
+ // draw inner vertical line for start/stop
+ // this overwrites borders of horizontal line
+ for(int i=0;i< (int)_jump.size();i++) {
+ if (_jump[i] == 0) continue;
+
+ c = _jump[i]->isCondJump() ? red : blue;
+
+ if (_jump[i]->instrFrom()->addr() == _addr) {
+ bool drawUp = true;
+ if (_jump[i]->instrTo()->addr() == _addr)
+ if (start<0) drawUp=false;
+ if (_jump[i]->instrTo()->addr() > _addr) drawUp=false;
+ if (drawUp)
+ p->fillRect( marg + 6*i +1, 0, 2, yy, c);
+ else
+ p->fillRect( marg + 6*i +1, yy, 2, height()-yy, c);
+ }
+ else if (_jump[i]->instrTo()->addr() == _addr) {
+ if (end<0) end = i;
+ if (_jump[i]->instrFrom()->addr() < _addr)
+ p->fillRect( marg + 6*i +1, 0, 2, yy, c);
+ else
+ p->fillRect( marg + 6*i +1, yy, 2, height()-yy, c);
+ }
+ }
+
+}
+
+int InstrItem::width( const QFontMetrics& fm,
+ const QListView* lv, int c ) const
+{
+ if (c != 3) return QListViewItem::width(fm, lv, c);
+
+ InstrView* iv = (InstrView*) lv;
+ int levels = iv->arrowLevels();
+
+ if (levels == 0) return 0;
+
+ // 10 pixels for the arrow
+ return 10 + 6*levels + lv->itemMargin() * 2;
+}
+
diff --git a/kcachegrind/kcachegrind/instritem.h b/kcachegrind/kcachegrind/instritem.h
new file mode 100644
index 00000000..50cc26e1
--- /dev/null
+++ b/kcachegrind/kcachegrind/instritem.h
@@ -0,0 +1,86 @@
+/* This file is part of KCachegrind.
+ Copyright (C) 2003 Josef Weidendorfer <Josef.Weidendorfer@gmx.de>
+
+ KCachegrind is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public
+ License as published by the Free Software Foundation, version 2.
+
+ 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; see the file COPYING. If not, write to
+ the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+*/
+
+/*
+ * Items of instruction view.
+ */
+
+#ifndef INSTRITEM_H
+#define INSTRITEM_H
+
+#include <qlistview.h>
+#include "tracedata.h"
+
+class InstrView;
+
+class InstrItem: public QListViewItem
+{
+
+public:
+ // for messages
+ InstrItem(InstrView* iv, QListView* parent,
+ Addr addr, const QString&);
+
+ // for instruction lines
+ InstrItem(InstrView* iv, QListView* parent,
+ Addr addr, bool inside,
+ const QString&, const QString&, const QString&,
+ TraceInstr* instr);
+
+ // for call instr
+ InstrItem(InstrView* iv, QListViewItem* parent, Addr addr,
+ TraceInstr* instr, TraceInstrCall* instrCall);
+
+ // for jump lines
+ InstrItem(InstrView* iv, QListViewItem* parent, Addr addr,
+ TraceInstr* instr, TraceInstrJump* instrJump);
+
+ Addr addr() const { return _addr; }
+ TraceInstr* instr() const { return _instr; }
+ TraceInstrCall* instrCall() const { return _instrCall; }
+ TraceInstrJump* instrJump() const { return _instrJump; }
+
+ int compare(QListViewItem * i, int col, bool ascending ) const;
+
+ void paintCell(QPainter *p, const QColorGroup &cg,
+ int column, int width, int alignment );
+ int width( const QFontMetrics& fm,
+ const QListView* lv, int c ) const;
+
+ void updateGroup();
+ void updateCost();
+
+ // arrow lines
+ void setJumpArray(const QMemArray<TraceInstrJump*>& a);
+
+protected:
+ void paintArrows(QPainter *p, const QColorGroup &cg, int width);
+ QMemArray<TraceInstrJump*> _jump;
+
+private:
+ InstrView* _view;
+ SubCost _pure, _pure2;
+ Addr _addr;
+ TraceInstr* _instr;
+ TraceInstrJump* _instrJump;
+ TraceInstrCall* _instrCall;
+ bool _inside;
+};
+
+
+#endif
diff --git a/kcachegrind/kcachegrind/instrview.cpp b/kcachegrind/kcachegrind/instrview.cpp
new file mode 100644
index 00000000..7bb8c2c1
--- /dev/null
+++ b/kcachegrind/kcachegrind/instrview.cpp
@@ -0,0 +1,949 @@
+/* This file is part of KCachegrind.
+ Copyright (C) 2003 Josef Weidendorfer <Josef.Weidendorfer@gmx.de>
+
+ KCachegrind is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public
+ License as published by the Free Software Foundation, version 2.
+
+ 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; see the file COPYING. If not, write to
+ the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+*/
+
+/*
+ * Instruction View
+ */
+
+#include <qfile.h>
+#include <qregexp.h>
+#include <qwhatsthis.h>
+#include <qpopupmenu.h>
+#include <klocale.h>
+#include <kconfig.h>
+#include <kdebug.h>
+
+#include "configuration.h"
+#include "instritem.h"
+#include "instrview.h"
+
+// InstrView defaults
+
+#define DEFAULT_SHOWHEXCODE true
+
+
+// Helpers for parsing output of 'objdump'
+
+static Addr parseAddr(char* buf)
+{
+ Addr addr;
+ uint pos = 0;
+
+ // check for instruction line: <space>* <hex address> ":" <space>*
+ while(buf[pos]==' ' || buf[pos]=='\t') pos++;
+
+ int digits = addr.set(buf + pos);
+ if ((digits==0) || (buf[pos+digits] != ':')) return Addr(0);
+
+ return addr;
+}
+
+
+static bool parseLine(char* buf, Addr& addr,
+ uint& pos1, uint& pos2, uint& pos3)
+{
+ // check for instruction line: <space>* <hex address> ":" <space>*
+
+ pos1 = 0;
+ while(buf[pos1]==' ' || buf[pos1]=='\t') pos1++;
+
+ int digits = addr.set(buf + pos1);
+ pos1 += digits;
+ if ((digits==0) || (buf[pos1] != ':')) return false;
+
+ // further parsing of objdump output...
+ pos1++;
+ while(buf[pos1]==' ' || buf[pos1]=='\t') pos1++;
+
+ // skip code, pattern "xx "*
+ pos2 = pos1;
+ while(1) {
+ if (! ((buf[pos2]>='0' && buf[pos2]<='9') ||
+ (buf[pos2]>='a' && buf[pos2]<='f')) ) break;
+ if (! ((buf[pos2+1]>='0' && buf[pos2+1]<='9') ||
+ (buf[pos2+1]>='a' && buf[pos2+1]<='f')) ) break;
+ if (buf[pos2+2] != ' ') break;
+ pos2 += 3;
+ }
+ buf[pos2-1]=0;
+ while(buf[pos2]==' '|| buf[pos2]=='\t') pos2++;
+
+ // skip mnemonic
+ pos3 = pos2;
+ while(buf[pos3] && buf[pos3]!=' ' && buf[pos3]!='\t') pos3++;
+ if (buf[pos3] != 0) {
+ buf[pos3] = 0;
+ pos3++;
+ while(buf[pos3]==' '|| buf[pos3]=='\t') pos3++;
+ }
+
+ // maximal 50 chars
+ if (strlen(buf+pos2) > 50)
+ strcpy(buf+pos2+47, "...");
+
+ if (0) qDebug("For 0x%s: Code '%s', Mnc '%s', Args '%s'",
+ addr.toString().ascii(), buf+pos1, buf+pos2, buf+pos3);
+
+ return true;
+}
+
+
+
+
+//
+// InstrView
+//
+
+
+InstrView::InstrView(TraceItemView* parentView,
+ QWidget* parent, const char* name)
+ : QListView(parent, name), TraceItemView(parentView)
+{
+ _showHexCode = DEFAULT_SHOWHEXCODE;
+ _lastHexCodeWidth = 50;
+
+ _inSelectionUpdate = false;
+ _arrowLevels = 0;
+ _lowList.setSortLow(true);
+ _highList.setSortLow(false);
+
+ addColumn( i18n( "#" ) );
+ addColumn( i18n( "Cost" ) );
+ addColumn( i18n( "Cost 2" ) );
+ addColumn( "" );
+ addColumn( i18n( "Hex" ) );
+ addColumn( "" ); // Instruction
+ addColumn( i18n( "Assembler" ) );
+ addColumn( i18n( "Source Position" ) );
+
+ setAllColumnsShowFocus(true);
+ setColumnAlignment(1, Qt::AlignRight);
+ setColumnAlignment(2, Qt::AlignRight);
+
+ connect(this,
+ SIGNAL(contextMenuRequested(QListViewItem*, const QPoint &, int)),
+ SLOT(context(QListViewItem*, const QPoint &, int)));
+
+ connect(this, SIGNAL(selectionChanged(QListViewItem*)),
+ SLOT(selectedSlot(QListViewItem*)));
+
+ connect(this,
+ SIGNAL(doubleClicked(QListViewItem*)),
+ SLOT(activatedSlot(QListViewItem*)));
+
+ connect(this,
+ SIGNAL(returnPressed(QListViewItem*)),
+ SLOT(activatedSlot(QListViewItem*)));
+
+ QWhatsThis::add( this, whatsThis());
+}
+
+void InstrView::paintEmptyArea( QPainter * p, const QRect & r)
+{
+ QListView::paintEmptyArea(p, r);
+}
+
+QString InstrView::whatsThis() const
+{
+ return i18n( "<b>Annotated Assembler</b>"
+ "<p>The annotated assembler list shows the "
+ "machine code instructions of the current selected "
+ "function together with (self) cost spent while "
+ "executing an instruction. If this is a call "
+ "instruction, lines with details on the "
+ "call happening are inserted into the source: "
+ "the cost spent inside of the call, the "
+ "number of calls happening, and the call destination.</p>"
+ "<p>The disassembler output shown is generated with "
+ "the 'objdump' utility from the 'binutils' package.</p>"
+ "<p>Select a line with call information to "
+ "make the destination function of this call current.</p>");
+}
+
+void InstrView::context(QListViewItem* i, const QPoint & p, int c)
+{
+ QPopupMenu popup;
+
+ TraceInstrCall* ic = i ? ((InstrItem*) i)->instrCall() : 0;
+ TraceInstrJump* ij = i ? ((InstrItem*) i)->instrJump() : 0;
+ TraceFunction* f = ic ? ic->call()->called() : 0;
+ TraceInstr* instr = ij ? ij->instrTo() : 0;
+
+ if (f) {
+ QString name = f->name();
+ if ((int)name.length()>Configuration::maxSymbolLength())
+ name = name.left(Configuration::maxSymbolLength()) + "...";
+ popup.insertItem(i18n("Go to '%1'").arg(name), 93);
+ popup.insertSeparator();
+ }
+ else if (instr) {
+ popup.insertItem(i18n("Go to Address %1").arg(instr->name()), 93);
+ popup.insertSeparator();
+ }
+
+ if ((c == 1) || (c == 2)) {
+ addCostMenu(&popup);
+ popup.insertSeparator();
+ }
+ addGoMenu(&popup);
+
+ popup.insertSeparator();
+ popup.setCheckable(true);
+ popup.insertItem(i18n("Hex Code"), 94);
+ if (_showHexCode) popup.setItemChecked(94,true);
+
+ int r = popup.exec(p);
+ if (r == 93) {
+ if (f) activated(f);
+ if (instr) activated(instr);
+ }
+ else if (r == 94) {
+ _showHexCode = !_showHexCode;
+ // remember width when hiding
+ if (!_showHexCode)
+ _lastHexCodeWidth = columnWidth(4);
+ setColumnWidths();
+ }
+}
+
+
+void InstrView::selectedSlot(QListViewItem * i)
+{
+ if (!i) return;
+ // programatically selected items are not signalled
+ if (_inSelectionUpdate) return;
+
+ TraceInstrCall* ic = ((InstrItem*) i)->instrCall();
+ TraceInstrJump* ij = ((InstrItem*) i)->instrJump();
+
+ if (!ic && !ij) {
+ TraceInstr* instr = ((InstrItem*) i)->instr();
+ if (instr) {
+ _selectedItem = instr;
+ selected(instr);
+ }
+ return;
+ }
+
+ if (ic) {
+ _selectedItem = ic;
+ selected(ic);
+ }
+ else if (ij) {
+ _selectedItem = ij;
+ selected(ij);
+ }
+}
+
+void InstrView::activatedSlot(QListViewItem * i)
+{
+ if (!i) return;
+ TraceInstrCall* ic = ((InstrItem*) i)->instrCall();
+ TraceInstrJump* ij = ((InstrItem*) i)->instrJump();
+
+ if (!ic && !ij) {
+ TraceInstr* instr = ((InstrItem*) i)->instr();
+ if (instr) activated(instr);
+ return;
+ }
+
+ if (ic) {
+ TraceFunction* f = ic->call()->called();
+ if (f) activated(f);
+ }
+ else if (ij) {
+ TraceInstr* instr = ij->instrTo();
+ if (instr) activated(instr);
+ }
+}
+
+
+TraceItem* InstrView::canShow(TraceItem* i)
+{
+ TraceItem::CostType t = i ? i->type() : TraceItem::NoCostType;
+ TraceFunction* f = 0;
+
+ switch(t) {
+ case TraceItem::Function:
+ f = (TraceFunction*) i;
+ break;
+
+ case TraceItem::Instr:
+ f = ((TraceInstr*)i)->function();
+ select(i);
+ break;
+
+ case TraceItem::Line:
+ f = ((TraceLine*)i)->functionSource()->function();
+ select(i);
+ break;
+
+ default:
+ break;
+ }
+
+ return f;
+}
+
+
+void InstrView::doUpdate(int changeType)
+{
+ // Special case ?
+ if (changeType == selectedItemChanged) {
+
+ if (!_selectedItem) {
+ clearSelection();
+ return;
+ }
+
+ InstrItem *ii = (InstrItem*)QListView::selectedItem();
+ if (ii) {
+ if ((ii->instr() == _selectedItem) ||
+ (ii->instr() && (ii->instr()->line() == _selectedItem))) return;
+ }
+
+ QListViewItem *item, *item2;
+ for (item = firstChild();item;item = item->nextSibling()) {
+ ii = (InstrItem*)item;
+ if ((ii->instr() == _selectedItem) ||
+ (ii->instr() && (ii->instr()->line() == _selectedItem))) {
+ ensureItemVisible(item);
+ _inSelectionUpdate = true;
+ setCurrentItem(item);
+ _inSelectionUpdate = false;
+ break;
+ }
+ item2 = item->firstChild();
+ for (;item2;item2 = item2->nextSibling()) {
+ ii = (InstrItem*)item2;
+ if (!ii->instrCall()) continue;
+ if (ii->instrCall()->call()->called() == _selectedItem) {
+ ensureItemVisible(item2);
+ _inSelectionUpdate = true;
+ setCurrentItem(item2);
+ _inSelectionUpdate = false;
+ break;
+ }
+ }
+ if (item2) break;
+ }
+ return;
+ }
+
+ if (changeType == groupTypeChanged) {
+ QListViewItem *item, *item2;
+ for (item = firstChild();item;item = item->nextSibling())
+ for (item2 = item->firstChild();item2;item2 = item2->nextSibling())
+ ((InstrItem*)item2)->updateGroup();
+ return;
+ }
+
+ refresh();
+}
+
+void InstrView::setColumnWidths()
+{
+ if (_showHexCode) {
+ setColumnWidthMode(4, QListView::Maximum);
+ setColumnWidth(4, _lastHexCodeWidth);
+ }
+ else {
+ setColumnWidthMode(4, QListView::Manual);
+ setColumnWidth(4, 0);
+ }
+}
+
+void InstrView::refresh()
+{
+ _arrowLevels = 0;
+
+ // reset to automatic sizing to get column width
+ setColumnWidthMode(4, QListView::Maximum);
+
+ clear();
+ setColumnWidth(0, 20);
+ setColumnWidth(1, 50);
+ setColumnWidth(2, _costType2 ? 50:0);
+ setColumnWidth(3, 0); // arrows, defaults to invisible
+ setColumnWidth(4, 0); // hex code column
+ setColumnWidth(5, 20); // command column
+ setColumnWidth(6, 200); // arg column
+ setSorting(0); // always reset to address number sort
+ if (_costType)
+ setColumnText(1, _costType->name());
+ if (_costType2)
+ setColumnText(2, _costType2->name());
+
+ if (!_data || !_activeItem) return;
+
+ TraceItem::CostType t = _activeItem->type();
+ TraceFunction* f = 0;
+ if (t == TraceItem::Function) f = (TraceFunction*) _activeItem;
+ if (t == TraceItem::Instr) {
+ f = ((TraceInstr*)_activeItem)->function();
+ if (!_selectedItem) _selectedItem = _activeItem;
+ }
+ if (t == TraceItem::Line) {
+ f = ((TraceLine*)_activeItem)->functionSource()->function();
+ if (!_selectedItem) _selectedItem = _activeItem;
+ }
+
+ if (!f) return;
+
+ // Allow resizing of column 2
+ setColumnWidthMode(2, QListView::Maximum);
+
+ // check for instruction map
+ TraceInstrMap::Iterator itStart, it, tmpIt, itEnd;
+ TraceInstrMap* instrMap = f->instrMap();
+ if (instrMap) {
+ it = instrMap->begin();
+ itEnd = instrMap->end();
+ // get first instruction with cost of selected type
+ while(it != itEnd) {
+ if ((*it).hasCost(_costType)) break;
+ if (_costType2 && (*it).hasCost(_costType2)) break;
+ ++it;
+ }
+ }
+ if (!instrMap || (it == itEnd)) {
+ new InstrItem(this, this, 1,
+ i18n("There is no instruction info in the profile data file."));
+ new InstrItem(this, this, 2,
+ i18n("For the Valgrind Calltree Skin, rerun with option"));
+ new InstrItem(this, this, 3, i18n(" --dump-instr=yes"));
+ new InstrItem(this, this, 4, i18n("To see (conditional) jumps, additionally specify"));
+ new InstrItem(this, this, 5, i18n(" --trace-jump=yes"));
+ return;
+ }
+
+ // initialisation for arrow drawing
+ // create sorted list of jumps (for jump arrows)
+ _lowList.clear();
+ _highList.clear();
+ itStart = it;
+ while(1) {
+ TraceInstrJumpList jlist = (*it).instrJumps();
+ TraceInstrJump* ij;
+ for (ij=jlist.first();ij;ij=jlist.next()) {
+ if (ij->executedCount()==0) continue;
+ _lowList.append(ij);
+ _highList.append(ij);
+ }
+ ++it;
+ while(it != itEnd) {
+ if ((*it).hasCost(_costType)) break;
+ if (_costType2 && (*it).hasCost(_costType2)) break;
+ ++it;
+ }
+ if (it == itEnd) break;
+ }
+ _lowList.sort();
+ _highList.sort();
+ _lowList.first(); // iterators to list start
+ _highList.first();
+ _arrowLevels = 0;
+ _jump.resize(0);
+
+
+ // do multiple calls to 'objdump' if there are large gaps in addresses
+ it = itStart;
+ while(1) {
+ itStart = it;
+ while(1) {
+ tmpIt = it;
+ ++it;
+ while(it != itEnd) {
+ if ((*it).hasCost(_costType)) break;
+ if (_costType2 && (*it).hasCost(_costType2)) break;
+ ++it;
+ }
+ if (it == itEnd) break;
+ if (!(*it).addr().isInRange( (*tmpIt).addr(),10000) ) break;
+ }
+
+ // tmpIt is always last instruction with cost
+ if (!fillInstrRange(f, itStart, ++tmpIt)) break;
+ if (it == itEnd) break;
+ }
+
+ _lastHexCodeWidth = columnWidth(4);
+ setColumnWidths();
+
+ if (!_costType2) {
+ setColumnWidthMode(2, QListView::Manual);
+ setColumnWidth(2, 0);
+ }
+}
+
+/* This is called after adding instrItems, for each of them in
+ * address order. _jump is the global array of valid jumps
+ * for a line while we iterate downwards.
+ * The existing jumps, sorted in lowList according lower address,
+ * is iterated in the same way.
+ */
+void InstrView::updateJumpArray(Addr addr, InstrItem* ii,
+ bool ignoreFrom, bool ignoreTo)
+{
+ TraceInstrJump* ij;
+ Addr lowAddr, highAddr;
+ int iEnd = -1, iStart = -1;
+
+ if (0) qDebug("updateJumpArray(addr 0x%s, jump to %s)",
+ addr.toString().ascii(),
+ ii->instrJump()
+ ? ii->instrJump()->instrTo()->name().ascii() : "?" );
+
+ // check for new arrows starting from here downwards
+ ij=_lowList.current();
+ while(ij) {
+ lowAddr = ij->instrFrom()->addr();
+ if (ij->instrTo()->addr() < lowAddr)
+ lowAddr = ij->instrTo()->addr();
+
+ if (lowAddr > addr) break;
+
+ // if target is downwards but we draw no source, break
+ if (ignoreFrom && (lowAddr < ij->instrTo()->addr())) break;
+ // if source is downward but we draw no target, break
+ if (ignoreTo && (lowAddr < ij->instrFrom()->addr())) break;
+ // if this is another jump start, break
+ if (ii->instrJump() && (ij != ii->instrJump())) break;
+
+#if 0
+ for(iStart=0;iStart<_arrowLevels;iStart++)
+ if (_jump[iStart] &&
+ (_jump[iStart]->instrTo() == ij->instrTo())) break;
+#else
+ iStart = _arrowLevels;
+#endif
+
+ if (iStart==_arrowLevels) {
+ for(iStart=0;iStart<_arrowLevels;iStart++)
+ if (_jump[iStart] == 0) break;
+ if (iStart==_arrowLevels) {
+ _arrowLevels++;
+ _jump.resize(_arrowLevels);
+ }
+ if (0) qDebug(" new start at %d for %s", iStart, ij->name().ascii());
+ _jump[iStart] = ij;
+ }
+ ij=_lowList.next();
+ }
+
+ ii->setJumpArray(_jump);
+
+ // check for active arrows ending here
+ ij=_highList.current();
+ while(ij) {
+ highAddr = ij->instrFrom()->addr();
+ if (ij->instrTo()->addr() > highAddr) {
+ highAddr = ij->instrTo()->addr();
+ if (ignoreTo) break;
+ }
+ else if (ignoreFrom) break;
+
+ if (highAddr > addr) break;
+
+ for(iEnd=0;iEnd<_arrowLevels;iEnd++)
+ if (_jump[iEnd] == ij) break;
+ if (iEnd==_arrowLevels) {
+ kdDebug() << "InstrView: no jump start for end at 0x"
+ << highAddr.toString() << " ?" << endl;
+ iEnd = -1;
+ }
+
+ if (0 && (iEnd>=0))
+ qDebug(" end %d (%s to %s)",
+ iEnd,
+ _jump[iEnd]->instrFrom()->name().ascii(),
+ _jump[iEnd]->instrTo()->name().ascii());
+
+ if (0 && ij) qDebug("next end: %s to %s",
+ ij->instrFrom()->name().ascii(),
+ ij->instrTo()->name().ascii());
+
+ ij=_highList.next();
+ if (highAddr > addr)
+ break;
+ else {
+ if (iEnd>=0) _jump[iEnd] = 0;
+ iEnd = -1;
+ }
+ }
+ if (iEnd>=0) _jump[iEnd] = 0;
+}
+
+
+
+/**
+ * Fill up with instructions from cost range [it;itEnd[
+ */
+bool InstrView::fillInstrRange(TraceFunction* function,
+ TraceInstrMap::Iterator it,
+ TraceInstrMap::Iterator itEnd)
+{
+ Addr costAddr, nextCostAddr, objAddr, addr;
+ Addr dumpStartAddr, dumpEndAddr;
+ TraceInstrMap::Iterator costIt;
+
+ // shouldn't happen
+ if (it == itEnd) return false;
+
+ // calculate address range for call to objdump
+ TraceInstrMap::Iterator tmpIt = itEnd;
+ --tmpIt;
+ nextCostAddr = (*it).addr();
+ dumpStartAddr = (nextCostAddr<20) ? Addr(0) : nextCostAddr -20;
+ dumpEndAddr = (*tmpIt).addr() +20;
+
+ // generate command
+ QString popencmd, objfile;
+ objfile = function->object()->name();
+ objfile = objfile.replace(QRegExp("[\"']"), ""); // security...
+ popencmd = QString("objdump -C -d "
+ "--start-address=0x%1 --stop-address=0x%2 \"%3\"")
+ .arg(dumpStartAddr.toString()).arg(dumpEndAddr.toString())
+ .arg(objfile);
+ if (1) qDebug("Running '%s'...", popencmd.ascii());
+
+ // and run...
+ FILE* iFILE = popen(QFile::encodeName( popencmd ), "r");
+ if (iFILE == 0) {
+ new InstrItem(this, this, 1,
+ i18n("There is an error trying to execute the command"));
+ new InstrItem(this, this, 2, "");
+ new InstrItem(this, this, 3, popencmd);
+ new InstrItem(this, this, 4, "");
+ new InstrItem(this, this, 5,
+ i18n("Check that you have installed 'objdump'."));
+ new InstrItem(this, this, 6,
+ i18n("This utility can be found in the 'binutils' package."));
+ return false;
+ }
+ QFile file;
+ file.open(IO_ReadOnly, iFILE);
+
+#define BUF_SIZE 256
+
+ char buf[BUF_SIZE];
+ bool inside = false, skipLineWritten = true;
+ int readBytes = -1;
+ int objdumpLineno = 0, dumpedLines = 0, noAssLines = 0;
+ SubCost most = 0;
+ TraceInstr* currInstr;
+ InstrItem *ii, *ii2, *item = 0, *first = 0, *selected = 0;
+ QString code, cmd, args;
+ bool needObjAddr = true, needCostAddr = true;
+
+ costAddr = 0;
+ objAddr = 0;
+
+ while (1) {
+
+ if (needObjAddr) {
+ needObjAddr = false;
+
+ // read next objdump line
+ while (1) {
+ readBytes=file.readLine(buf, BUF_SIZE);
+ if (readBytes<=0) {
+ objAddr = 0;
+ break;
+ }
+
+ objdumpLineno++;
+ if (readBytes == BUF_SIZE) {
+ qDebug("ERROR: Line %d of '%s' too long\n",
+ objdumpLineno, popencmd.ascii());
+ }
+ else if ((readBytes>0) && (buf[readBytes-1] == '\n'))
+ buf[readBytes-1] = 0;
+
+ objAddr = parseAddr(buf);
+ if ((objAddr<dumpStartAddr) || (objAddr>dumpEndAddr))
+ objAddr = 0;
+ if (objAddr != 0) break;
+ }
+
+ if (0) kdDebug() << "Got ObjAddr: 0x" << objAddr.toString() << endl;
+ }
+
+ // try to keep objAddr in [costAddr;nextCostAddr]
+ if (needCostAddr &&
+ (nextCostAddr > 0) &&
+ ((objAddr == Addr(0)) || (objAddr >= nextCostAddr)) ) {
+ needCostAddr = false;
+
+ costIt = it;
+ ++it;
+ while(it != itEnd) {
+ if ((*it).hasCost(_costType)) break;
+ if (_costType2 && (*it).hasCost(_costType2)) break;
+ ++it;
+ }
+ costAddr = nextCostAddr;
+ nextCostAddr = (it == itEnd) ? Addr(0) : (*it).addr();
+
+ if (0) kdDebug() << "Got nextCostAddr: 0x" << nextCostAddr.toString()
+ << ", costAddr 0x" << costAddr.toString() << endl;
+ }
+
+ // if we have no more address from objdump, stop
+ if (objAddr == 0) break;
+
+ if ((nextCostAddr==0) || (costAddr == 0) ||
+ (objAddr < nextCostAddr)) {
+ // next line is objAddr
+
+ uint pos1, pos2, pos3;
+
+ // this sets addr
+ parseLine(buf, addr, pos1, pos2, pos3);
+ code = QString(buf + pos1);
+ cmd = QString(buf + pos2);
+ args = QString(buf + pos3);
+
+ if (costAddr == objAddr) {
+ currInstr = &(*costIt);
+ needCostAddr = true;
+ }
+ else
+ currInstr = 0;
+
+ needObjAddr = true;
+
+ if (0) kdDebug() << "Dump Obj Addr: 0x" << addr.toString()
+ << " [" << cmd << " " << args << "], cost (0x"
+ << costAddr.toString() << ", next 0x"
+ << nextCostAddr.toString() << ")" << endl;
+ }
+ else {
+ addr = costAddr;
+ code = cmd = QString();
+ args = i18n("(No Assembler)");
+
+ currInstr = &(*costIt);
+ needCostAddr = true;
+
+ noAssLines++;
+ if (0) kdDebug() << "Dump Cost Addr: 0x" << addr.toString()
+ << " (no ass), objAddr 0x" << objAddr.toString() << endl;
+ }
+
+ // update inside
+ if (!inside) {
+ if (currInstr) inside = true;
+ }
+ else {
+ if (0) kdDebug() << "Check if 0x" << addr.toString() << " is in ]0x"
+ << costAddr.toString() << ",0x"
+ << (nextCostAddr - 3*Configuration::noCostInside()).toString()
+ << "[" << endl;
+
+ // Suppose a average instruction len of 3 bytes
+ if ( (addr > costAddr) &&
+ ((nextCostAddr==0) ||
+ (addr < nextCostAddr - 3*Configuration::noCostInside()) ))
+ inside = false;
+ }
+
+ int context = Configuration::context();
+
+ if ( ((costAddr==0) || (addr > costAddr + 3*context)) &&
+ ((nextCostAddr==0) || (addr < nextCostAddr - 3*context)) ) {
+
+ // the very last skipLine can be ommitted
+ if ((it == itEnd) &&
+ (itEnd == function->instrMap()->end())) skipLineWritten=true;
+
+ if (!skipLineWritten) {
+ skipLineWritten = true;
+ // a "skipping" line: print "..." instead of a line number
+ code = cmd = QString();
+ args = QString("...");
+ }
+ else
+ continue;
+ }
+ else
+ skipLineWritten = false;
+
+
+ ii = new InstrItem(this, this, addr, inside,
+ code, cmd, args, currInstr);
+ dumpedLines++;
+ if (0) kdDebug() << "Dumped 0x" << addr.toString() << " "
+ << (inside ? "Inside " : "Outside")
+ << (currInstr ? "Cost" : "") << endl;
+
+ // no calls/jumps if we have no cost for this line
+ if (!currInstr) continue;
+
+ if (!selected &&
+ (currInstr == _selectedItem) ||
+ (currInstr->line() == _selectedItem)) selected = ii;
+
+ if (!first) first = ii;
+
+ if (currInstr->subCost(_costType) > most) {
+ item = ii;
+ most = currInstr->subCost(_costType);
+ }
+
+ ii->setOpen(true);
+ TraceInstrCallList list = currInstr->instrCalls();
+ TraceInstrCall* ic;
+ for (ic=list.first();ic;ic=list.next()) {
+ if ((ic->subCost(_costType)==0) &&
+ (ic->subCost(_costType2)==0)) continue;
+
+ if (ic->subCost(_costType) > most) {
+ item = ii;
+ most = ic->subCost(_costType);
+ }
+
+ ii2 = new InstrItem(this, ii, addr, currInstr, ic);
+
+ if (!selected && (ic->call()->called() == _selectedItem))
+ selected = ii2;
+ }
+
+ TraceInstrJumpList jlist = currInstr->instrJumps();
+ TraceInstrJump* ij;
+ for (ij=jlist.first();ij;ij=jlist.next()) {
+ if (ij->executedCount()==0) continue;
+
+ new InstrItem(this, ii, addr, currInstr, ij);
+ }
+ }
+
+ if (selected) item = selected;
+ if (item) first = item;
+ if (first) {
+ ensureItemVisible(first);
+ _inSelectionUpdate = true;
+ setCurrentItem(first);
+ _inSelectionUpdate = false;
+ }
+
+ file.close();
+ pclose(iFILE);
+
+ // for arrows: go down the list according to list sorting
+ sort();
+ QListViewItem *item1, *item2;
+ for (item1=firstChild();item1;item1 = item1->nextSibling()) {
+ ii = (InstrItem*)item1;
+ updateJumpArray(ii->addr(), ii, true, false);
+
+ for (item2=item1->firstChild();item2;item2 = item2->nextSibling()) {
+ ii2 = (InstrItem*)item2;
+ if (ii2->instrJump())
+ updateJumpArray(ii->addr(), ii2, false, true);
+ else
+ ii2->setJumpArray(_jump);
+ }
+ }
+
+ if (arrowLevels())
+ setColumnWidth(3, 10 + 6*arrowLevels() + itemMargin() * 2);
+ else
+ setColumnWidth(3, 0);
+
+
+ if (noAssLines > 1) {
+ // trace cost not machting code
+
+ new InstrItem(this, this, 1,
+ i18n("There is %n cost line without assembler code.",
+ "There are %n cost lines without assembler code.", noAssLines));
+ new InstrItem(this, this, 2,
+ i18n("This happens because the code of"));
+ new InstrItem(this, this, 3, QString(" %1").arg(objfile));
+ new InstrItem(this, this, 4,
+ i18n("does not seem to match the profile data file."));
+ new InstrItem(this, this, 5, "");
+ new InstrItem(this, this, 6,
+ i18n("Are you using an old profile data file or is the above mentioned"));
+ new InstrItem(this, this, 7,
+ i18n("ELF object from an updated installation/another machine?"));
+ new InstrItem(this, this, 8, "");
+ return false;
+ }
+
+ if (dumpedLines == 0) {
+ // no matching line read from popen
+ new InstrItem(this, this, 1,
+ i18n("There seems to be an error trying to execute the command"));
+ new InstrItem(this, this, 2, "");
+ new InstrItem(this, this, 3, popencmd);
+ new InstrItem(this, this, 4, "");
+ new InstrItem(this, this, 5,
+ i18n("Check that the ELF object used in the command exists."));
+ new InstrItem(this, this, 6,
+ i18n("Check that you have installed 'objdump'."));
+ new InstrItem(this, this, 7,
+ i18n("This utility can be found in the 'binutils' package."));
+ return false;
+ }
+
+ return true;
+}
+
+
+void InstrView::updateInstrItems()
+{
+ InstrItem* ii;
+ QListViewItem* item = firstChild();
+ for (;item;item = item->nextSibling()) {
+ ii = (InstrItem*)item;
+ TraceInstr* instr = ii->instr();
+ if (!instr) continue;
+
+ ii->updateCost();
+
+ QListViewItem *next, *i = ii->firstChild();
+ for (;i;i = next) {
+ next = i->nextSibling();
+ ((InstrItem*)i)->updateCost();
+ }
+ }
+}
+
+void InstrView::readViewConfig(KConfig* c,
+ QString prefix, QString postfix, bool)
+{
+ KConfigGroup* g = configGroup(c, prefix, postfix);
+
+ if (0) qDebug("InstrView::readViewConfig");
+
+ _showHexCode = g->readBoolEntry("ShowHexCode", DEFAULT_SHOWHEXCODE);
+
+ delete g;
+}
+
+void InstrView::saveViewConfig(KConfig* c,
+ QString prefix, QString postfix, bool)
+{
+ KConfigGroup g(c, (prefix+postfix).ascii());
+
+ writeConfigEntry(&g, "ShowHexCode", _showHexCode, DEFAULT_SHOWHEXCODE);
+}
+
+#include "instrview.moc"
diff --git a/kcachegrind/kcachegrind/instrview.h b/kcachegrind/kcachegrind/instrview.h
new file mode 100644
index 00000000..9a2f81cf
--- /dev/null
+++ b/kcachegrind/kcachegrind/instrview.h
@@ -0,0 +1,82 @@
+/* This file is part of KCachegrind.
+ Copyright (C) 2003 Josef Weidendorfer <Josef.Weidendorfer@gmx.de>
+
+ KCachegrind is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public
+ License as published by the Free Software Foundation, version 2.
+
+ 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; see the file COPYING. If not, write to
+ the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+*/
+
+/*
+ * Instruction View
+ */
+
+#ifndef INSTRVIEW_H
+#define INSTRVIEW_H
+
+#include <qlistview.h>
+#include "traceitemview.h"
+
+class InstrItem;
+
+class InstrView : public QListView, public TraceItemView
+{
+ friend class InstrItem;
+
+ Q_OBJECT
+
+public:
+ InstrView(TraceItemView* parentView,
+ QWidget* parent = 0, const char* name = 0);
+
+ virtual QWidget* widget() { return this; }
+ QString whatsThis() const;
+
+ void readViewConfig(KConfig*, QString prefix, QString postfix, bool);
+ void saveViewConfig(KConfig*, QString prefix, QString postfix, bool);
+
+protected:
+ int arrowLevels() { return _arrowLevels; }
+ void paintEmptyArea( QPainter *, const QRect & );
+
+private slots:
+ void context(QListViewItem*, const QPoint &, int);
+ void selectedSlot(QListViewItem *);
+ void activatedSlot(QListViewItem *);
+
+private:
+ TraceItem* canShow(TraceItem*);
+ void doUpdate(int);
+ void refresh();
+ void setColumnWidths();
+ void fillInstr();
+ void updateJumpArray(Addr,InstrItem*,bool,bool);
+ bool fillInstrRange(TraceFunction*,
+ TraceInstrMap::Iterator,TraceInstrMap::Iterator);
+ void updateInstrItems();
+
+ bool _inSelectionUpdate;
+
+ // arrows
+ int _arrowLevels;
+ // temporary needed on creation...
+ QMemArray<TraceInstrJump*> _jump;
+ TraceInstrJumpList _lowList, _highList;
+
+ // remember width of hex code column if hidden
+ int _lastHexCodeWidth;
+
+ // widget options
+ bool _showHexCode;
+};
+
+#endif
diff --git a/kcachegrind/kcachegrind/kcachegrind.desktop b/kcachegrind/kcachegrind/kcachegrind.desktop
new file mode 100644
index 00000000..84088653
--- /dev/null
+++ b/kcachegrind/kcachegrind/kcachegrind.desktop
@@ -0,0 +1,103 @@
+# KDE Config File
+[Desktop Entry]
+Type=Application
+Exec=kcachegrind -caption "%c" %i %m %u
+MimeType=application/x-kcachegrind;
+Icon=kcachegrind
+DocPath=kcachegrind/index.html
+Terminal=false
+Name=KCachegrind
+Name[hi]=के-केश-गà¥à¤°à¤¿à¤‚ड
+Name[sv]=Kcachegrind
+Name[ta]= இடைமாறà¯à®±à®•à®Ÿà¯à®Ÿà®®à¯
+GenericName=Profiler Frontend
+GenericName[bs]=Profiler frontend
+GenericName[ca]=Interfície de Profiler
+GenericName[cs]=Rozhraní pro profilaci
+GenericName[cy]=Blaen-wyneb Proffilydd
+GenericName[da]=Grænseflade til profilering
+GenericName[de]=Profiler Oberfläche
+GenericName[el]=ΠÏόγÏαμμα Ï€Ïοφίλ
+GenericName[eo]=Fasado de Profililo
+GenericName[es]=Interfaz para Profiler
+GenericName[et]=Profileerimisrakendus
+GenericName[eu]=Profilatzailearen interfazea
+GenericName[fa]=پایانۀ گزارش‌گیر
+GenericName[fi]=Profiloijan käyttöliittymä
+GenericName[fr]=Interface de profilage
+GenericName[ga]=Comhéadan ar Phróifíleoir
+GenericName[gl]=Interface para o profiler
+GenericName[hi]=पà¥à¤°à¥‹à¤«à¤¼à¤¾à¤‡à¤²à¤° फà¥à¤°à¤¨à¥à¤Ÿà¤à¤£à¥à¤¡
+GenericName[hu]=Profilozó
+GenericName[is]=Myndrænt viðmót á afkastakönnuð
+GenericName[it]=Interfaccia a profiler
+GenericName[ja]=プロファイラフロントエンド
+GenericName[ka]=პრáƒáƒ¤áƒ˜áƒšáƒ”რის Frontend
+GenericName[kk]=Профильдеткіштің интерфейÑÑ–
+GenericName[lt]=Profiliuoklio naudotojo sÄ…saja
+GenericName[nb]=Grensesnitt for profilvisning
+GenericName[nds]=Profiler-Böversiet
+GenericName[ne]=पà¥à¤°à¥‹à¤«à¤¾à¤‡à¤²à¤° फà¥à¤°à¤¨à¥à¤Ÿà¤‡à¤¨à¥à¤¡
+GenericName[nl]=Profiler-hulpprogramma
+GenericName[nn]=Grensesnitt for profilvising
+GenericName[pa]=ਪਰੋਫਾਇਲਰ ਮà©à©±à¨– ਭੂਮੀ
+GenericName[pl]=Interfejs do profilera
+GenericName[pt]=Interface de Profiler
+GenericName[pt_BR]=Interface para o Profiler
+GenericName[ru]=Профилировщик
+GenericName[sk]=Rozhranie pre profiler
+GenericName[sl]=Vmesnik profilnika
+GenericName[sr]=Графички Ð¸Ð½Ñ‚ÐµÑ€Ñ„ÐµÑ˜Ñ Ð·Ð° профајлер
+GenericName[sr@Latn]=GrafiÄki interfejs za profajler
+GenericName[sv]=Profileringsgränssnitt
+GenericName[ta]= விவரகà¯à®•à¯à®±à®¿à®ªà¯à®ªà¯ à®®à¯à®©à¯à®ªà®•à¯à®¤à®¿
+GenericName[tg]=Ð˜Ð½Ñ‚ÐµÑ€Ñ„ÐµÐ¹Ñ Ð±Ð° профилкунанда
+GenericName[tr]=Profil Önyüzü
+GenericName[uk]=Ð†Ð½Ñ‚ÐµÑ€Ñ„ÐµÐ¹Ñ Ð´Ð¾ Profiler
+GenericName[zh_CN]=个性数æ®å‰ç«¯
+GenericName[zh_TW]=分æžå™¨å‰ç«¯
+Comment=Visualization of Performance Profiling Data
+Comment[bg]=Ð’Ð¸Ð·ÑƒÐ°Ð»Ð¸Ð·Ð°Ñ†Ð¸Ñ Ð½Ð° данните за производителноÑÑ‚
+Comment[bs]=Vizualizacija podataka za profiliranje performansi
+Comment[ca]=Visualizació de dades de perfilat de rendiment
+Comment[cs]=Vizualizace profilovacích dat výkonu
+Comment[da]=Visualisering af profileringsdata
+Comment[de]=Visualisierung von Daten des Laufzeitverhaltens eines Programmes
+Comment[el]=ΑναπαÏάσταση δεδομένων ταχÏτητας Ï€Ïοφίλ
+Comment[en_GB]=Visualisation of Performance Profiling Data
+Comment[es]=Visualización de datos de análisis de rendimiento
+Comment[et]=Jõudluse profileerimise andmete visualiseerimise vahend
+Comment[eu]=Errendimendu profil datuen bistaratzea
+Comment[fa]=تجسم کارایی گزارش داده‌ها
+Comment[fi]=Visualisointi tehokkuusprofiloinnin tiedoista
+Comment[fr]=Visualisation des données de performance de profilage
+Comment[gl]=Visualización dos datos da análise de rendimento
+Comment[hi]=परफारà¥à¤®à¥‡à¤¸ पà¥à¤°à¥‹à¤«à¤¾à¤‡à¤²à¤¿à¤‚ग डाटा का विजà¥à¤…लाइज़ेशन
+Comment[hu]=Teljesítményprofil-adatok megjelenítése
+Comment[is]=Sjónræn framsetning gagna úr afkastakönnun
+Comment[it]=Visualizzazione dei dati di profiling delle prestazioni
+Comment[ja]=パフォーマンスプロファイルデータを視覚化
+Comment[ka]=წáƒáƒ áƒ›áƒáƒ“áƒáƒ‘ის მáƒáƒžáƒ áƒáƒ¤áƒ¤áƒ˜áƒšáƒ”ბელი მáƒáƒœáƒáƒªáƒ”მების ვიზუáƒáƒšáƒ˜áƒ–áƒáƒªáƒ˜áƒ
+Comment[kk]=Деректерді профильдеудің визуализациÑÑÑ‹
+Comment[lt]=Veikimo profiliavimo duomenų vizualizacija
+Comment[nb]=Vis informasjon om ytelse.
+Comment[nds]=Visualiseren vun Programmleisten-Looptietdaten
+Comment[ne]=समà¥à¤ªà¤¾à¤¦à¤¨ पà¥à¤°à¥‹à¤«à¤¾à¤‡à¤²à¤¿à¤™ डाटाको दृषà¥à¤Ÿà¤¿à¤•à¤°à¤£
+Comment[nl]=Visualisatie van Performance Profiling Data
+Comment[nn]=Vis informasjon om yting
+Comment[pl]=Wizualizacja danych profilowania wydajności
+Comment[pt]=Visualização dos Dados de Análise de Performance
+Comment[pt_BR]=Visualização de Dados de Perfil de Desempenho
+Comment[ru]=Утилита Ð´Ð»Ñ Ð²Ð¸Ð·ÑƒÐ°Ð»ÑŒÐ½Ð¾Ð³Ð¾ Ð¿Ñ€Ð¾Ñ„Ð¸Ð»Ð¸Ñ€Ð¾Ð²Ð°Ð½Ð¸Ñ Ð¿Ñ€Ð¸Ð»Ð¾Ð¶ÐµÐ½Ð¸Ð¹
+Comment[sk]=Vizualizácia dát o výkone
+Comment[sl]=Vizualizacija podatkov profilnih zmogljivosti
+Comment[sr]=Визуелизација података о профилиÑању перформанÑи
+Comment[sr@Latn]=Vizuelizacija podataka o profilisanju performansi
+Comment[sv]=Åskådliggörande av profileringsdata för prestanda
+Comment[ta]= விவர தகவலை செயலà¯à®ªà®¾à®Ÿà¯à®Ÿà¯ காடà¯à®šà®¿à®¯à®¾à®³à®¿à®ªà¯à®ªà¯
+Comment[tg]=Утилита барои гузориши профили визуалӣ
+Comment[uk]=Ð’Ñ–Ð·ÑƒÐ°Ð»Ñ–Ð·Ð°Ñ†Ñ–Ñ Ð´Ð°Ð½Ð¸Ñ… Ð¿Ñ€Ð¾Ñ„Ñ–Ð»ÑŽÐ²Ð°Ð½Ð½Ñ ÑˆÐ²Ð¸Ð´ÐºÐ¾Ð´Ñ–Ñ—
+Comment[zh_CN]=性能个性数æ®çš„å¯è§†åŒ–表现
+Comment[zh_TW]=效能分æžè³‡æ–™è¦–覺化
+X-DCOP-ServiceType=Multi
+Categories=Qt;KDE;Development;
diff --git a/kcachegrind/kcachegrind/kcachegrindui.rc b/kcachegrind/kcachegrind/kcachegrindui.rc
new file mode 100644
index 00000000..af9b8dcd
--- /dev/null
+++ b/kcachegrind/kcachegrind/kcachegrindui.rc
@@ -0,0 +1,57 @@
+<!DOCTYPE kpartgui>
+<kpartgui name="kcachegrind" version="4">
+ <MenuBar>
+ <Menu name="file"><text>&amp;File</text>
+ <Action name="file_add" append="open_merge"/>
+ <Action name="reload" append="revert_merge"/>
+ <Action name="dump" append="revert_merge"/>
+ <Action name="export"/>
+ </Menu>
+ <Menu name="view"><text>&amp;View</text>
+ <Action name="view_cost_type"/>
+ <Action name="view_cost_type2"/>
+ <Action name="view_group_type"/>
+ <Separator/>
+ <Menu name="layouts"><text>&amp;Layout</text>
+ <Action name="layout_next"/>
+ <Action name="layout_previous"/>
+ <Action name="layout_duplicate"/>
+ <Action name="layout_remove"/>
+ <Separator/>
+ <Action name="layout_restore"/>
+ <Action name="layout_save"/>
+ </Menu>
+ <Action name="view_split"/>
+ <Action name="view_split_dir"/>
+ <Separator/>
+ <Action name="view_percentage"/>
+ <Action name="view_expanded"/>
+ <Action name="view_cycles"/>
+ </Menu>
+ <Menu name="settings">
+ <Menu append="show_toolbar_merge"><text>Sidebars</text>
+ <Action name="settings_show_dumpdock"/>
+ <Action name="settings_show_partdock"/>
+ <Action name="settings_show_stackdock"/>
+ <Action name="settings_show_profiledock"/>
+ </Menu>
+ </Menu>
+ </MenuBar>
+
+ <ToolBar name="mainToolBar" noMerge="1"><text>Main Toolbar</text>
+ <Action name="file_open"/>
+ <Action name="reload"/>
+ <Action name="dump"/>
+ <Separator/>
+ <Action name="go_up"/>
+ <Action name="go_back"/>
+ <Action name="go_forward"/>
+ <Separator/>
+ <Action name="view_percentage"/>
+ <Action name="view_expanded"/>
+ <Action name="view_cycles"/>
+ </ToolBar>
+ <ToolBar name="stateToolBar" noMerge="1"><text>State Toolbar</text>
+ <Action name="view_cost_type"/>
+ </ToolBar>
+</kpartgui>
diff --git a/kcachegrind/kcachegrind/listutils.cpp b/kcachegrind/kcachegrind/listutils.cpp
new file mode 100644
index 00000000..7a14e552
--- /dev/null
+++ b/kcachegrind/kcachegrind/listutils.cpp
@@ -0,0 +1,266 @@
+/* This file is part of KCachegrind.
+ Copyright (C) 2003 Josef Weidendorfer <Josef.Weidendorfer@gmx.de>
+
+ KCachegrind is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public
+ License as published by the Free Software Foundation, version 2.
+
+ 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; see the file COPYING. If not, write to
+ the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+*/
+
+/*
+ * Some helper functions for QListViewItem derivates
+ */
+
+#include <qpainter.h>
+#include "listutils.h"
+
+#define COSTPIX_WIDTH 25
+
+QPixmap colorPixmap(int w, int h, QColor c)
+{
+ static QPixmap* pixs[37];
+ static QColor cols[37];
+ static bool inited = false;
+
+ if (!inited) {
+ for (int i=0;i<37;i++) pixs[i]=0;
+ inited = true;
+ }
+ int hash = (w+h+c.red()+c.green()+c.blue()) % 37;
+ if (pixs[hash]) {
+ if ((pixs[hash]->width() == w) &&
+ (pixs[hash]->height() == h) &&
+ (cols[hash] == c))
+ return *pixs[hash];
+
+ delete pixs[hash];
+ }
+
+
+ QPixmap* pix = new QPixmap(w, h);
+ pix->fill(c);
+ QPainter p(pix);
+ p.setPen(c.light());
+ p.drawLine(0, 0, w-1, 0);
+ p.drawLine(0, 0, 0, h-1);
+ p.setPen(c.dark());
+ p.drawLine(w-1, 0, w-1, h-1);
+ p.drawLine(0, h-1, w-1, h-1);
+
+ pixs[hash] = pix;
+ cols[hash] = c;
+ return *pix;
+}
+
+/**
+ * Create a percentage pixmap with a filling rate of p percent (0-100).
+ * When withFrame==false, the pixmap is truncated to only the filled portion.
+ */
+QPixmap percentagePixmap(int w, int h, int percent, QColor c, bool framed)
+{
+ int iw, ix1, ix2, ih, iy1, iy2;
+
+ // inner rectangle to fill with bar
+ if (framed) {
+ iw = w-2, ix1 = 1, ix2 = w-2;
+ ih = h-2, iy1 = 1, iy2 = h-2;
+ }
+ else {
+ iw = w; ix1 = 0; ix2 = w-1;
+ ih = h; iy1 = 0; iy2 = h-1;
+ }
+
+ /* Limit bar to 100% */
+ int filled = (percent>100) ? iw+1 : iw*percent/100+1;
+ if (!framed) w=filled-1;
+ if (w<3) return QPixmap();
+
+ QPixmap pix(w, h);
+ pix.fill(Qt::white);
+ QPainter p(&pix);
+ p.setPen(Qt::black);
+ if (framed)
+ p.drawRect(0, 0, w, h);
+
+ // inside
+ p.setPen(Qt::NoPen);
+ p.setBrush(c);
+ p.drawRect(ix1, iy1, filled-1,ih);
+
+ // frame
+ ix2 = ix1+filled-2;
+ p.setPen(c.light());
+ p.drawLine(ix1, iy1, ix2, iy1);
+ p.drawLine(ix1, iy1, ix1, iy2);
+ p.setPen(c.dark());
+ p.drawLine(ix1+1, iy2, ix2, iy2);
+ p.drawLine(ix2, iy1, ix2, iy2);
+
+ return pix;
+}
+
+inline QColor partitionColor(int d, int max)
+{
+ return QColor( (720*d/max) % 360,
+ 255-(128*d/max), 192, QColor::Hsv);
+}
+
+
+QPixmap partitionPixmap(int w, int h,
+ double* hist, QColor* cArray, int maxIndex, bool framed)
+{
+ int lastPos = 0, nextPos;
+ double val=0.0, sum=0.0;
+ int d, dmin=maxIndex, dmax=0;
+ for (d = 0;d<maxIndex;d++)
+ if (hist[d]>0.0) {
+ sum += hist[d];
+ if (dmin>d) dmin = d;
+ if (dmax<d) dmax = d;
+ }
+
+ // inner rectangle to fill with bar
+ int iw, ix1, ix2, ih, iy1, iy2;
+ if (framed) {
+ iw = w-2, ix1 = 1, ix2 = w-2;
+ ih = h-2, iy1 = 1, iy2 = h-2;
+ }
+ else {
+ iw = w; ix1 = 0; ix2 = w-1;
+ ih = h; iy1 = 0; iy2 = h-1;
+ }
+
+ int filled = (int)(iw*sum+1);
+ if (!framed && (filled < w)) w=filled;
+ if (w<3) return QPixmap();
+
+ QPixmap pix(w, h);
+ pix.fill(Qt::white);
+ QPainter p(&pix);
+ p.setPen(Qt::black);
+ if (framed)
+ p.drawRect(0, 0, w, h);
+
+ //qDebug("Sum %f, dw %d", sum,dw);
+
+ QColor c, cLast;
+ bool leftDrawn = false;
+ int x1, x2=0;
+ int lastDiff=0, diff;
+ d=dmin;
+ while (d<dmax+1) {
+ val += hist[d];
+ nextPos = (int)(filled * val/sum);
+
+ //qDebug(" hist[%d] %f, val %f, nextPos %d", d, hist[d], val, nextPos);
+
+ diff = nextPos-lastPos;
+ if (diff==0) { d++; continue; }
+
+ c = cArray ? cArray[d] : partitionColor(d,maxIndex);
+
+ x1 = ix1+lastPos;
+ x2 = ix1+nextPos;
+ if (x2>=iw) x2=iw-1;
+
+ // inside
+ p.setPen(Qt::NoPen);
+ p.setBrush(c);
+ p.drawRect(x1, iy1, x2-x1+1, ih);
+
+ // lighter top border
+ p.setPen(c.light());
+ p.drawLine(x1, iy1, x2-1, iy1);
+
+ // when width for last and current distance >2, draw full 3D effect...
+ if (!leftDrawn) {
+ p.drawLine(x1, iy1+1, x1, iy2);
+ leftDrawn = true;
+ }
+
+ // darker bottom border
+ p.setPen(c.dark());
+ p.drawLine(x1, iy2, x2-1, iy2);
+
+ lastPos = nextPos;
+ lastDiff = diff;
+ cLast = c;
+ d++;
+ }
+
+ // right border (in last color)
+ if (x2>0)
+ p.drawLine(x2, iy1, x2, iy2);
+
+ return pix;
+}
+
+
+QPixmap costPixmap(TraceCostType* ct, TraceCost* cost, double total, bool framed)
+{
+ if (ct->isReal()) {
+ QColor color = ct->color();
+ double p = 100.0 * cost->subCost(ct) / total;
+ return percentagePixmap(COSTPIX_WIDTH, 10, (int)(p+.5), color, framed);
+ }
+
+ int maxIndex;
+ double h[MaxRealIndexValue];
+ QColor* cs = ct->mapping()->realColors();
+ maxIndex = ct->histCost(cost, total, h);
+
+ if (maxIndex ==0) return QPixmap();
+ return partitionPixmap(COSTPIX_WIDTH, 10, h, cs, maxIndex, framed);
+}
+
+
+
+// HighestCostList
+
+HighestCostList::HighestCostList()
+{
+ _maxSize = 0;
+ _count = 0;
+ _costType = 0;
+}
+
+void HighestCostList::clear(int maxSize)
+{
+ _maxSize = maxSize;
+ _count = 0;
+ _item.resize(maxSize);
+ _cost.resize(maxSize);
+}
+
+void HighestCostList::addCost(TraceCost* c, SubCost cost)
+{
+ int i;
+
+ _count++;
+ if (_count > _maxSize) {
+ if (_cost[_maxSize-1] >= cost) return;
+ i = _maxSize-1;
+ }
+ else i = _count-1;
+
+ for(; i>0; i--) {
+ if (_cost[i-1] >= cost) break;
+ else {
+ _cost[i] = _cost[i-1];
+ _item[i] = _item[i-1];
+ }
+ }
+ _cost[i] = cost;
+ _item[i] = c;
+}
+
+
diff --git a/kcachegrind/kcachegrind/listutils.h b/kcachegrind/kcachegrind/listutils.h
new file mode 100644
index 00000000..abf7c723
--- /dev/null
+++ b/kcachegrind/kcachegrind/listutils.h
@@ -0,0 +1,65 @@
+/* This file is part of KCachegrind.
+ Copyright (C) 2003 Josef Weidendorfer <Josef.Weidendorfer@gmx.de>
+
+ KCachegrind is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public
+ License as published by the Free Software Foundation, version 2.
+
+ 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; see the file COPYING. If not, write to
+ the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+*/
+
+/*
+ * Some helper functions for QListViewItem derivates
+ */
+
+#ifndef LISTUTILS_H
+#define LISTUTILS_H
+
+#include <qpixmap.h>
+#include <qstring.h>
+#include <qcolor.h>
+#include "tracedata.h"
+
+QString bigNum(SubCost);
+QPixmap colorPixmap(int w, int h, QColor c);
+QPixmap percentagePixmap(int w, int h, int percent, QColor c, bool framed);
+QPixmap partitionPixmap(int w, int h, double* hist, QColor*,
+ int maxIndex, bool framed);
+QPixmap costPixmap(TraceCostType* ct, TraceCost* cost, double total, bool framed);
+
+/**
+ * A class to calculate the <maxSize> TraceCost items
+ * with highest cost.
+ */
+
+class HighestCostList
+{
+ public:
+ HighestCostList();
+
+ void clear(int maxSize);
+ void addCost(TraceCost*, SubCost);
+ int count() { return _count; }
+ int realCount() { return (_count > _maxSize) ? _maxSize:_count; }
+ int maxSize() { return _maxSize; }
+ bool hasMore() { return _count > _maxSize; }
+ TraceCost* operator[] (int i)
+ { return (i>=0 && i<_count && i<_maxSize) ? _item[i] : 0; }
+
+ private:
+ TraceCostList _list;
+ int _maxSize, _count;
+ TraceCostType* _costType;
+ QMemArray<TraceCost*> _item;
+ QMemArray<SubCost> _cost;
+};
+
+#endif
diff --git a/kcachegrind/kcachegrind/lo16-app-kcachegrind.png b/kcachegrind/kcachegrind/lo16-app-kcachegrind.png
new file mode 100644
index 00000000..0985586b
--- /dev/null
+++ b/kcachegrind/kcachegrind/lo16-app-kcachegrind.png
Binary files differ
diff --git a/kcachegrind/kcachegrind/lo32-app-kcachegrind.png b/kcachegrind/kcachegrind/lo32-app-kcachegrind.png
new file mode 100644
index 00000000..12542c8a
--- /dev/null
+++ b/kcachegrind/kcachegrind/lo32-app-kcachegrind.png
Binary files differ
diff --git a/kcachegrind/kcachegrind/loader.cpp b/kcachegrind/kcachegrind/loader.cpp
new file mode 100644
index 00000000..2b373851
--- /dev/null
+++ b/kcachegrind/kcachegrind/loader.cpp
@@ -0,0 +1,85 @@
+/* This file is part of KCachegrind.
+ Copyright (C) 2002 Josef Weidendorfer <Josef.Weidendorfer@gmx.de>
+
+ KCachegrind is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public
+ License as published by the Free Software Foundation, version 2.
+
+ 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; see the file COPYING. If not, write to
+ the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+*/
+
+/*
+ * Base class for loaders of profiling data.
+ */
+
+#include "loader.h"
+
+
+/// Loader
+
+LoaderList Loader::_loaderList;
+
+Loader::Loader(QString name, QString desc)
+{
+ _name = name;
+ _description = desc;
+}
+
+Loader::~Loader()
+{}
+
+bool Loader::canLoadTrace(QFile*)
+{
+ return false;
+}
+
+bool Loader::loadTrace(TracePart*)
+{
+ return false;
+}
+
+Loader* Loader::matchingLoader(QFile* file)
+{
+ Loader* l;
+ for (l=_loaderList.first(); l; l = _loaderList.next())
+ if (l->canLoadTrace(file))
+ return l;
+
+ return 0;
+}
+
+Loader* Loader::loader(QString name)
+{
+ Loader* l;
+ for (l=_loaderList.first(); l; l = _loaderList.next())
+ if (l->name() == name)
+ return l;
+
+ return 0;
+}
+
+// factories of available loaders
+Loader* createCachegrindLoader();
+
+void Loader::initLoaders()
+{
+ _loaderList.append(createCachegrindLoader());
+ //_loaderList.append(GProfLoader::createLoader());
+}
+
+void Loader::deleteLoaders()
+{
+ _loaderList.setAutoDelete(true);
+ _loaderList.clear();
+}
+
+
+#include "loader.moc"
diff --git a/kcachegrind/kcachegrind/loader.h b/kcachegrind/kcachegrind/loader.h
new file mode 100644
index 00000000..70b98c48
--- /dev/null
+++ b/kcachegrind/kcachegrind/loader.h
@@ -0,0 +1,79 @@
+/* This file is part of KCachegrind.
+ Copyright (C) 2002 Josef Weidendorfer <Josef.Weidendorfer@gmx.de>
+
+ KCachegrind is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public
+ License as published by the Free Software Foundation, version 2.
+
+ 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; see the file COPYING. If not, write to
+ the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+*/
+
+/*
+ * Base class for loaders of profiling data.
+ */
+
+#ifndef LOADER_H
+#define LOADER_H
+
+#include <qobject.h>
+#include <qptrlist.h>
+#include <qstring.h>
+
+class QFile;
+class TraceData;
+class TracePart;
+class Loader;
+
+
+typedef QPtrList<Loader> LoaderList;
+
+/**
+ * To implement a new loader, inherit from the Loader class
+ * and implement canLoadTrace(), loadTrace() and if a trace in
+ * this format can consist out of multiple parts, implement
+ * isPartOfTrace(), too.
+ * For registration, put into the static initLoaders() function
+ * of this base class a _loaderList.append(new MyLoader()).
+ *
+ * KCachegrind will use the first matching loader.
+ */
+
+class Loader: public QObject
+{
+ Q_OBJECT
+
+public:
+ Loader(QString name, QString desc);
+ virtual ~Loader();
+
+ virtual bool canLoadTrace(QFile* file);
+ virtual bool loadTrace(TracePart*);
+
+ static Loader* matchingLoader(QFile* file);
+ static Loader* loader(QString name);
+ static void initLoaders();
+ static void deleteLoaders();
+
+ QString name() const { return _name; }
+ QString description() const { return _description; }
+
+signals:
+ void updateStatus(QString, int);
+
+private:
+ QString _name, _description;
+
+ static LoaderList _loaderList;
+};
+
+
+
+#endif
diff --git a/kcachegrind/kcachegrind/main.cpp b/kcachegrind/kcachegrind/main.cpp
new file mode 100644
index 00000000..299d485a
--- /dev/null
+++ b/kcachegrind/kcachegrind/main.cpp
@@ -0,0 +1,95 @@
+/* This file is part of KCachegrind.
+ Copyright (C) 2003 Josef Weidendorfer <Josef.Weidendorfer@gmx.de>
+
+ KCachegrind is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public
+ License as published by the Free Software Foundation, version 2.
+
+ 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; see the file COPYING. If not, write to
+ the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+*/
+
+/*
+ * KCachegrind startup
+ */
+
+// for KCACHEGRIND_VERSION
+#include "../version.h"
+
+#include <qfile.h>
+#include <kapplication.h>
+#include <kcmdlineargs.h>
+#include <kaboutdata.h>
+#include <klocale.h>
+
+#include "toplevel.h"
+#include "tracedata.h"
+#include "loader.h"
+
+static KCmdLineOptions options[] =
+{
+ { "r <exec>", I18N_NOOP("Run <exec> under cachegrind"), 0 },
+ { "+[trace]", I18N_NOOP("Show information of this trace"), 0 },
+ KCmdLineLastOption // End of options.
+};
+
+int main( int argc, char ** argv )
+{
+ KAboutData aboutData("kcachegrind",
+ I18N_NOOP("KCachegrind"),
+ KCACHEGRIND_VERSION,
+ I18N_NOOP("KDE Frontend for Cachegrind"),
+ KAboutData::License_GPL,
+ I18N_NOOP("(C) 2002, 2003, 2004"), 0,
+ "http://kcachegrind.sf.net");
+ aboutData.addAuthor("Josef Weidendorfer",
+ I18N_NOOP("Author/Maintainer"),
+ "Josef.Weidendorfer@gmx.de");
+
+ KCmdLineArgs::init(argc, argv, &aboutData);
+ KCmdLineArgs::addCmdLineOptions( options );
+
+ KApplication a;
+ TopLevel* t;
+ Loader::initLoaders();
+
+ if (a.isRestored()){
+ int n = 1;
+ while (KMainWindow::canBeRestored(n)){
+ (new TopLevel())->restore(n);
+ n++;
+ }
+ }
+ else {
+ KCmdLineArgs *args = KCmdLineArgs::parsedArgs();
+ if (args->count()>0) {
+ for(int i = 0; i < args->count(); i++) {
+ t = new TopLevel();
+ t->show();
+ t->loadDelayed(QFile::decodeName(args->arg(i)));
+ }
+ }
+ else {
+ // load trace in current dir
+ t = new TopLevel();
+ t->show();
+ t->loadDelayed(".");
+ }
+ }
+
+ a.connect( &a, SIGNAL( lastWindowClosed() ), &a, SLOT( quit() ) );
+ int res = a.exec();
+
+ // to make leak checking in valgrind happy...
+ Loader::deleteLoaders();
+ TraceItem::cleanup();
+
+ return res;
+}
diff --git a/kcachegrind/kcachegrind/multiview.cpp b/kcachegrind/kcachegrind/multiview.cpp
new file mode 100644
index 00000000..09dfcd85
--- /dev/null
+++ b/kcachegrind/kcachegrind/multiview.cpp
@@ -0,0 +1,224 @@
+/* This file is part of KCachegrind.
+ Copyright (C) 2003 Josef Weidendorfer <Josef.Weidendorfer@gmx.de>
+
+ KCachegrind is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public
+ License as published by the Free Software Foundation, version 2.
+
+ 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; see the file COPYING. If not, write to
+ the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+*/
+
+/*
+ * MultiView, enclosing multiple TabView's with a user choosable
+ * active view (i.e. focus), separated by a splitter.
+ * Selection of the active view is shown in the next to the right view
+ * (with wrap around).
+ */
+
+#include <qobjectlist.h>
+#include <kconfig.h>
+#include <kdebug.h>
+
+#include "multiview.h"
+#include "tabview.h"
+
+//
+// MultiView
+//
+
+MultiView::MultiView(TopLevel* top, QWidget* parent, const char* name)
+ : QSplitter(parent, name), TraceItemView(0, top)
+{
+ // default
+ setOrientation(Qt::Horizontal);
+
+ appendView();
+ _active = _views.first();
+ _active->setActive(true);
+}
+
+void MultiView::setData(TraceData* d)
+{
+ TraceItemView::setData(d);
+
+ TabView* tv;
+ for(tv=_views.first(); tv; tv=_views.next())
+ tv->setData(d);
+}
+
+void MultiView::setChildCount(int n)
+{
+ while(n< (int)_views.count()) removeView();
+ while(n> (int)_views.count()) appendView();
+}
+
+void MultiView::appendView()
+{
+ int n = _views.count()+1;
+
+ TabView* tv = new TabView(this, this,
+ QString("TabView-%1").arg(n).ascii());
+ connect(tv, SIGNAL(activated(TabView*)),
+ this, SLOT(tabActivated(TabView*)) );
+ _views.append(tv);
+ tv->show();
+
+ // set same attributes as in active view
+ tv->set(0, _data, _costType, _costType2,
+ _groupType, _partList, _activeItem, 0);
+ tv->updateView();
+
+ if (0) kdDebug() << "MultiView::appendView, now "
+ << _views.count() << endl;
+}
+
+void MultiView::removeView()
+{
+ if (_views.count()<=1) return;
+
+ TabView* last = _views.last();
+
+ // if last tab is active, make first active
+ if (last == _active) {
+ TabView* newActive = _views.first();
+ newActive->setActive(true);
+ tabActivated(newActive);
+ }
+
+ _views.removeRef(last);
+ delete last;
+
+ if (0) kdDebug() << "MultiView::removeView, now "
+ << _views.count() << endl;
+}
+
+
+void MultiView::tabActivated(TabView* newActiveTab)
+{
+ if (_active == newActiveTab) return;
+
+ if (0) kdDebug() << "MultiView::tabActivated "
+ << newActiveTab->name() << endl;
+
+ TraceItem* oldActiveItem = 0;
+ if (_active) {
+ oldActiveItem = _active->activeItem();
+ _active->setActive(false);
+ }
+ _active = newActiveTab;
+
+ // make the active item of the new TabView active
+ if (_active && (oldActiveItem != _active->activeItem()))
+ TraceItemView::activated(_active->activeItem());
+}
+
+void MultiView::selected(TraceItemView* sender, TraceItem* i)
+{
+ if (0) kdDebug() << "MultiView::selected " << i->name()
+ << ", sender " << sender->widget()->name() << endl;
+
+ // we react only on selection changes of the active TabView
+ if (sender != (TraceItemView*)_active) return;
+
+ _views.findRef(_active);
+ TabView* next = _views.next();
+ if (!next) next = _views.first();
+
+ // don't change item of active tab
+ if (next == _active) return;
+
+ next->activate(i);
+ next->updateView();
+}
+
+void MultiView::activated(TraceItemView* sender, TraceItem* i)
+{
+ if (0) kdDebug() << "MultiView::activated " << i->name()
+ << ", sender " << sender->widget()->name() << endl;
+
+ // we react only on selection changes of the active TabView
+ if (sender != (TraceItemView*)_active) return;
+
+ TraceItemView::activated(sender,i);
+}
+
+void MultiView::doUpdate(int changeType)
+{
+ TabView* tv;
+ for(tv=_views.first(); tv; tv=_views.next()) {
+ tv->set(changeType, _data, _costType, _costType2,
+ _groupType, _partList,
+ (tv == _active) ? _activeItem : tv->activeItem(),
+ tv->selectedItem());
+ tv->notifyChange(changeType);
+ if (tv->isViewVisible())
+ tv->updateView();
+ }
+}
+
+
+void MultiView::readViewConfig(KConfig* c,
+ QString prefix, QString postfix,
+ bool withOptions)
+{
+ if (0) qDebug("%s::readConfig(%s%s)", name(),
+ prefix.ascii(), postfix.ascii());
+
+ QString active;
+ KConfigGroup* g = configGroup(c, prefix, postfix);
+ int n = g->readNumEntry("Panels", 1);
+ setChildCount(n);
+ setOrientation( (g->readEntry("Orientation") == QString("Horizontal")) ?
+ Qt::Horizontal : Qt::Vertical );
+
+ setSizes(g->readIntListEntry("PanelSizes"));
+
+ active = g->readEntry("ActivePanel", "");
+ delete g;
+
+ TabView* tv, *activeTV = 0;
+ for(tv=_views.first();tv;tv=_views.next()) {
+ if (tv->name() == active) activeTV=tv;
+ tv->readViewConfig(c, QString("%1-%2").arg(prefix).arg(tv->name()),
+ postfix, withOptions);
+ }
+
+ // activate panel after restoring
+ if (!activeTV) activeTV = _views.first();
+
+ if (_active == activeTV)
+ TraceItemView::activated(_active->activeItem());
+ else
+ activeTV->setActive(true);
+}
+
+void MultiView::saveViewConfig(KConfig* c,
+ QString prefix, QString postfix,
+ bool withOptions)
+{
+ KConfigGroup g(c, (prefix+postfix).ascii());
+
+ g.writeEntry("Panels", childCount());
+ g.writeEntry("Orientation",
+ (orientation() == Qt::Horizontal) ?
+ "Horizontal" : "Vertical");
+
+ g.writeEntry("PanelSizes", sizes());
+ g.writeEntry("ActivePanel", _active ? _active->name() : "none");
+
+ TabView* tv;
+ for(tv=_views.first();tv;tv=_views.next())
+ tv->saveViewConfig(c, QString("%1-%2").arg(prefix).arg(tv->name()),
+ postfix, withOptions);
+}
+
+
+#include "multiview.moc"
diff --git a/kcachegrind/kcachegrind/multiview.h b/kcachegrind/kcachegrind/multiview.h
new file mode 100644
index 00000000..d4c56b19
--- /dev/null
+++ b/kcachegrind/kcachegrind/multiview.h
@@ -0,0 +1,66 @@
+/* This file is part of KCachegrind.
+ Copyright (C) 2003 Josef Weidendorfer <Josef.Weidendorfer@gmx.de>
+
+ KCachegrind is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public
+ License as published by the Free Software Foundation, version 2.
+
+ 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; see the file COPYING. If not, write to
+ the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+*/
+
+/*
+ * MultiView, enclosing multiple (default: 2) TabView's with a user
+ * choosable active view (i.e. focus). This is a splitter itself.
+ * Selection of the active view is shown in the next to the right view
+ * (with wrap around).
+ */
+
+#ifndef MULTIVIEW_H
+#define MULTIVIEW_H
+
+#include <qsplitter.h>
+#include <qptrlist.h>
+#include "traceitemview.h"
+#include "tabview.h" // because of QPtrList<TabView>
+
+class MultiView : public QSplitter, public TraceItemView
+{
+ Q_OBJECT
+
+public:
+ MultiView(TopLevel* top, QWidget* parent = 0, const char* name = 0);
+
+ QWidget* widget() { return this; }
+ TabView* activeTabView() const { return _active; }
+ void setData(TraceData*);
+
+ void appendView();
+ void removeView();
+ void setChildCount(int);
+ int childCount() { return _views.count(); }
+
+ void selected(TraceItemView*, TraceItem*);
+ void activated(TraceItemView*, TraceItem*);
+
+ void readViewConfig(KConfig*, QString prefix, QString postfix, bool);
+ void saveViewConfig(KConfig*, QString prefix, QString postfix, bool);
+
+public slots:
+ void tabActivated(TabView*);
+
+ private:
+ void doUpdate(int);
+
+ TabView* _active;
+ QPtrList<TabView> _views;
+};
+
+#endif
diff --git a/kcachegrind/kcachegrind/partgraph.cpp b/kcachegrind/kcachegrind/partgraph.cpp
new file mode 100644
index 00000000..f4fa72a3
--- /dev/null
+++ b/kcachegrind/kcachegrind/partgraph.cpp
@@ -0,0 +1,534 @@
+/* This file is part of KCachegrind.
+ Copyright (C) 2003 Josef Weidendorfer <Josef.Weidendorfer@gmx.de>
+
+ KCachegrind is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public
+ License as published by the Free Software Foundation, version 2.
+
+ 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; see the file COPYING. If not, write to
+ the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+*/
+
+/*
+ * TracePart as Nested Area
+ */
+
+#include <klocale.h>
+
+#include "partgraph.h"
+#include "configuration.h"
+#include "listutils.h"
+
+
+// PartAreaWidget
+
+PartAreaWidget::PartAreaWidget(QWidget* parent, const char* name)
+ : TreeMapWidget(new BasePartItem(), parent, name)
+{
+ _data = 0;
+ _function = 0;
+
+ _costType = 0;
+ _groupType = TraceCost::NoCostType;
+ _visualisation = NoVisualisation;
+ _zoomFunction = false;
+ _callLevels = 1;
+}
+
+void PartAreaWidget::setData(TraceData* data)
+{
+ if (data == _data) return;
+
+ _data = data;
+ _function = 0;
+ _hiddenParts.clear();
+
+ ((BasePartItem*)base())->setData(data);
+}
+
+void PartAreaWidget::changeHidden(const TracePartList& list)
+{
+ _hiddenParts = list;
+ base()->refresh();
+}
+
+
+void PartAreaWidget::setCostType(TraceCostType* ct)
+{
+ _costType = ct;
+
+ // this resizes items
+ base()->redraw();
+}
+
+void PartAreaWidget::setVisualisation(VisualisationMode m)
+{
+ _visualisation = m;
+ refreshParts();
+}
+
+void PartAreaWidget::setZoomFunction(bool zoomFunction)
+{
+ _zoomFunction = zoomFunction;
+ refreshParts();
+}
+
+void PartAreaWidget::setCallLevels(int callLevels)
+{
+ _callLevels = callLevels;
+ refreshParts();
+}
+
+void PartAreaWidget::refreshParts()
+{
+ // rebuild only subparts to keep part selection state
+ TreeMapItem* i;
+ TreeMapItemList* l = base()->children();
+ if (l)
+ for (i=l->first();i;i=l->next())
+ i->refresh();
+
+ // but resize part areas
+ base()->redraw();
+}
+
+
+void PartAreaWidget::setFunction(TraceFunction* f)
+{
+ _function = f;
+
+ if (_visualisation == PartAreaWidget::Inclusive)
+ refreshParts();
+}
+
+void PartAreaWidget::setGroupType(TraceCost::CostType gt)
+{
+ _groupType = gt;
+
+ // rebuild hierarchy below parts.
+ // thus, selected parts stay selected
+ TreeMapItem* i;
+ TreeMapItemList* l = base()->children();
+ if (l)
+ for (i=l->first();i;i=l->next())
+ i->refresh();
+
+ base()->redraw();
+}
+
+bool PartAreaWidget::isHidden(TracePart* part) const
+{
+ return (_hiddenParts.containsRef(part)>0);
+}
+
+QColor PartAreaWidget::groupColor(TraceFunction* f) const
+{
+ if (!f)
+ return colorGroup().button();
+
+ return Configuration::functionColor(_groupType, f);
+}
+
+QString PartAreaWidget::tipString(TreeMapItem* i) const
+{
+ QString tip, itemTip;
+ int count = 0;
+
+ //qDebug("PartAreaWidget::tipString for '%s'", i->name().ascii());
+
+ // first, SubPartItem's
+ while (i && count<Configuration::maxSymbolCount() && i->rtti() == 3) {
+ itemTip = i->text(0);
+ if ((int)itemTip.length()>Configuration::maxSymbolLength())
+ itemTip = itemTip.left(Configuration::maxSymbolLength()) + "...";
+
+ if (!i->text(1).isEmpty())
+ itemTip += " (" + i->text(1) + ")";
+
+ if (!tip.isEmpty())
+ itemTip += "\n";
+
+ tip = itemTip + tip;
+ i = i->parent();
+ count++;
+ }
+
+ // skip to part
+ while (i && i->rtti()==3) i = i->parent();
+
+ if (i && i->rtti()==2) {
+ itemTip = i18n("Profile Part %1").arg(i->text(0));
+ if (!i->text(1).isEmpty())
+ itemTip += " (" + i->text(1) + ")";
+
+ if (!tip.isEmpty())
+ itemTip += "\n";
+
+ tip = itemTip + tip;
+ }
+
+// qDebug("PartAreaWidget:: tip %s, itemTip %s",
+// tip.ascii(), itemTip.ascii());
+
+ return tip;
+}
+
+
+
+
+
+// BasePartItem
+
+BasePartItem::BasePartItem()
+ : TreeMapItem()
+{
+ _data = 0;
+ setSorting(-1);
+}
+
+void BasePartItem::setData(TraceData* data)
+{
+ if (data == _data) return;
+
+ _data = data;
+ refresh();
+}
+
+TreeMapItemList* BasePartItem::children()
+{
+ if (!_data) return _children;
+
+ if (!initialized()) {
+// qDebug("Create Parts (%s)", name().ascii());
+
+ PartAreaWidget* w = (PartAreaWidget*) widget();
+ TracePart* part;
+ TracePartList l = _data->parts();
+ for (part=l.first();part;part=l.next())
+ if (!w->isHidden(part))
+ addItem(new PartItem(part));
+ }
+
+ return _children;
+}
+
+QString BasePartItem::text(int textNo) const
+{
+ if (textNo == 0) {
+ if (!_data)
+ return i18n("(no trace)");
+
+ if (_data->parts().count() == 0)
+ return i18n("(no part)");
+ }
+ return QString::null;
+}
+
+
+QColor BasePartItem::backColor() const
+{
+ return widget()->colorGroup().base();
+}
+
+double BasePartItem::value() const
+{
+ if (!_data) return 0;
+
+ PartAreaWidget* w = (PartAreaWidget*) widget();
+ return (double)_data->subCost(w->costType());
+}
+
+
+
+
+
+// PartItem
+
+PartItem::PartItem(TracePart* p)
+{
+ _p = p;
+ _factor=1;
+}
+
+QString PartItem::text(int textNo) const
+{
+ if (textNo == 0)
+ return _p->prettyName();
+
+ if (textNo != 1)
+ return QString::null;
+
+ TraceCostType* ct;
+ PartAreaWidget* w = (PartAreaWidget*)widget();
+ SubCost v;
+
+ ct = w->costType();
+ v = _p->subCost(ct);
+
+ if (Configuration::showPercentage()) {
+ TraceCost* t = _p->data()->totals();
+ double p = 100.0 * v / t->subCost(ct);
+ return QString("%1 %")
+ .arg(p, 0, 'f', Configuration::percentPrecision());
+ }
+ return v.pretty();
+}
+
+
+QPixmap PartItem::pixmap(int i) const
+{
+ if (i != 1) return QPixmap();
+
+ // Cost pixmap
+
+ TraceCostType* ct = ((PartAreaWidget*)widget())->costType();
+ return costPixmap( ct, _p, (double) (_p->data()->totals()->subCost(ct)), false );
+}
+
+
+double PartItem::value() const
+{
+ PartAreaWidget* w = (PartAreaWidget*)widget();
+ TraceCostType* ct = w->costType();
+ if ((w->visualisation() == PartAreaWidget::Inclusive) &&
+ w->zoomFunction()) {
+
+ // use value of zoomed function
+ TraceFunction* f = w->function();
+ if (f) {
+ TracePartFunction* pf = (TracePartFunction*) f->findDepFromPart(_p);
+ if (pf)
+ return (double) pf->inclusive()->subCost(ct);
+ // when function is not available in part, hide part
+ return 0.0;
+ }
+ }
+ return (double) _p->subCost(ct);
+}
+
+double PartItem::sum() const
+{
+ PartAreaWidget* w = (PartAreaWidget*)widget();
+ if (w->visualisation() == PartAreaWidget::Inclusive) {
+ double s = value();
+ //qDebug("PartItem::sum [part %s]: %d", _p->name().ascii(), s);
+ return s;
+ }
+ return 0.0;
+}
+
+TreeMapItemList* PartItem::children()
+{
+ if (initialized()) return _children;
+
+ TraceCost* c;
+// qDebug("Create Part subitems (%s)", name().ascii());
+
+ PartAreaWidget* w = (PartAreaWidget*)widget();
+ if (w->visualisation() == PartAreaWidget::Inclusive) {
+ TraceFunction* f = w->function();
+ if (f) {
+ c = f->findDepFromPart(_p);
+ if (c) addItem(new SubPartItem(c));
+ }
+
+ return _children;
+ }
+
+
+ switch( ((PartAreaWidget*)widget())->groupType() ) {
+
+ case TraceCost::Object:
+ {
+ TraceObjectMap::Iterator it;
+ for ( it = _p->data()->objectMap().begin();
+ it != _p->data()->objectMap().end(); ++it ) {
+ c = (*it).findDepFromPart(_p);
+ if (c)
+ addItem(new SubPartItem(c));
+ }
+ }
+ break;
+
+ case TraceCost::Class:
+ {
+ TraceClassMap::Iterator it;
+ for ( it = _p->data()->classMap().begin();
+ it != _p->data()->classMap().end(); ++it ) {
+ c = (*it).findDepFromPart(_p);
+ if (c)
+ addItem(new SubPartItem(c));
+ }
+ }
+ break;
+
+ case TraceCost::File:
+ {
+ TraceFileMap::Iterator it;
+ for ( it = _p->data()->fileMap().begin();
+ it != _p->data()->fileMap().end(); ++it ) {
+ c = (*it).findDepFromPart(_p);
+ if (c)
+ addItem(new SubPartItem(c));
+ }
+ }
+ break;
+
+ case TraceCost::Function:
+ {
+ TraceFunctionMap::Iterator it;
+ for ( it = _p->data()->functionMap().begin();
+ it != _p->data()->functionMap().end(); ++it ) {
+ c = (*it).findDepFromPart(_p);
+ if (c)
+ addItem(new SubPartItem(c));
+ }
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ return _children;
+}
+
+
+QColor PartItem::backColor() const
+{
+ PartAreaWidget* w = (PartAreaWidget*)widget();
+ return w->groupColor(0);
+}
+
+
+// SubPartItem
+
+SubPartItem::SubPartItem(TraceCost* c)
+{
+ _partCostItem = c;
+ _factor=1;
+}
+
+QString SubPartItem::text(int textNo) const
+{
+ if (textNo == 0) {
+ if (!_partCostItem)
+ return i18n("(unknown)");
+
+ return _partCostItem->dependant()->prettyName();
+ }
+
+ if (textNo != 1)
+ return QString::null;
+
+ TraceCostType* ct;
+ PartAreaWidget* w = (PartAreaWidget*)widget();
+ SubCost v;
+
+ ct = w->costType();
+ if (w->visualisation() == PartAreaWidget::Inclusive)
+ v = ((TracePartFunction*)_partCostItem)->inclusive()->subCost(ct);
+ else
+ v = _partCostItem->subCost(ct);
+
+ if (Configuration::showPercentage()) {
+ TraceCost* t = Configuration::showExpanded() ?
+ _partCostItem->part() : _partCostItem->part()->data()->totals();
+ double p = 100.0 * v / t->subCost(ct);
+ return QString("%1 %")
+ .arg(p, 0, 'f', Configuration::percentPrecision());
+ }
+ return v.pretty();
+}
+
+QPixmap SubPartItem::pixmap(int i) const
+{
+ if (i != 1) return QPixmap();
+
+ // Cost pixmap
+
+ PartAreaWidget* w = (PartAreaWidget*)widget();
+ TraceCostType* ct = w->costType();
+ TraceCost* t = Configuration::showExpanded() ?
+ _partCostItem->part() : _partCostItem->part()->data()->totals();
+ TraceCost* c;
+ if (w->visualisation() == PartAreaWidget::Inclusive)
+ c = ((TracePartFunction*)_partCostItem)->inclusive();
+ else
+ c = _partCostItem;
+
+ return costPixmap( ct, c, (double) (t->subCost(ct)), false );
+}
+
+double SubPartItem::value() const
+{
+ TraceCostType* ct;
+ PartAreaWidget* w = (PartAreaWidget*)widget();
+
+ ct = w->costType();
+ if (w->visualisation() == PartAreaWidget::Inclusive)
+ return (double)
+ ((TracePartFunction*)_partCostItem)->inclusive()->subCost(ct);
+
+ return (double) _partCostItem->subCost(ct);
+}
+
+double SubPartItem::sum() const
+{
+ PartAreaWidget* w = (PartAreaWidget*)widget();
+ if (w->visualisation() == PartAreaWidget::Inclusive) {
+ double s = value();
+ //qDebug("SubPartItem::sum [Cost %s]: %d", _cost->name().ascii(), s);
+ return s;
+ }
+ return 0.0;
+}
+
+TreeMapItemList* SubPartItem::children()
+{
+ if (!initialized()) {
+// qDebug("Create Part sub-subitems (%s)", name().ascii());
+
+ PartAreaWidget* w = (PartAreaWidget*)widget();
+
+ if (depth()-2 > w->callLevels())
+ return _children;
+
+ if (w->visualisation() == PartAreaWidget::Inclusive) {
+ TracePartCall* call;
+ TracePartCallList l;
+
+ setSum(value());
+
+ l = ((TracePartFunction*)_partCostItem)->partCallings();
+ for (call=l.first();call;call=l.next()) {
+ TraceFunction* called = call->call()->called();
+ TraceCost* partCalled = called->findDepFromPart(call->part());
+ if (partCalled)
+ addItem(new SubPartItem(partCalled));
+ }
+ }
+ }
+
+ return _children;
+}
+
+
+QColor SubPartItem::backColor() const
+{
+ PartAreaWidget* w = (PartAreaWidget*)widget();
+ if (w->visualisation() == PartAreaWidget::Inclusive)
+ return w->groupColor((TraceFunction*)(_partCostItem->dependant()));
+
+ return Configuration::groupColor(_partCostItem->dependant());
+}
+
+
+#include "partgraph.moc"
diff --git a/kcachegrind/kcachegrind/partgraph.h b/kcachegrind/kcachegrind/partgraph.h
new file mode 100644
index 00000000..d4d5b121
--- /dev/null
+++ b/kcachegrind/kcachegrind/partgraph.h
@@ -0,0 +1,131 @@
+/* This file is part of KCachegrind.
+ Copyright (C) 2003 Josef Weidendorfer <Josef.Weidendorfer@gmx.de>
+
+ KCachegrind is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public
+ License as published by the Free Software Foundation, version 2.
+
+ 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; see the file COPYING. If not, write to
+ the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+*/
+
+/*
+ * TracePart Graph
+ */
+
+#ifndef PARTGRAPH_H
+#define PARTGRAPH_H
+
+#include "treemap.h"
+#include "tracedata.h"
+
+class PartAreaWidget: public TreeMapWidget
+{
+ Q_OBJECT
+
+public:
+ // Visualisation inside of trace parts
+ enum VisualisationMode { NoVisualisation, Partitioning, Inclusive };
+
+ PartAreaWidget(QWidget* parent=0, const char* name=0);
+
+ void setData(TraceData* d);
+ void setCostType(TraceCostType* ct);
+ void setGroupType(TraceCost::CostType gt);
+ void setVisualisation(VisualisationMode);
+ void setZoomFunction(bool zoomFunction);
+ void setCallLevels(int callLevels);
+ void setFunction(TraceFunction* f);
+
+ TraceCostType* costType() const { return _costType; }
+ TraceCost::CostType groupType() const { return _groupType; }
+ TraceFunction* function() const { return _function; }
+ VisualisationMode visualisation() const { return _visualisation; }
+ bool zoomFunction() const { return _zoomFunction; }
+ int callLevels() const { return _callLevels; }
+
+ QColor groupColor(TraceFunction*) const;
+ QString tipString(TreeMapItem*) const;
+
+ void changeHidden(const TracePartList& list);
+ bool isHidden(TracePart*) const;
+
+private:
+ void refreshParts();
+
+ TraceData* _data;
+ TraceCostType* _costType;
+ TraceCost::CostType _groupType;
+ TraceFunction* _function;
+ VisualisationMode _visualisation;
+ bool _zoomFunction;
+ int _callLevels;
+
+ TracePartList _hiddenParts;
+};
+
+class BasePartItem: public TreeMapItem
+{
+public:
+ BasePartItem();
+
+ void setData(TraceData* d);
+
+ int rtti() const { return 1; }
+ double value() const;
+ QString text(int) const;
+ int borderWidth() const { return 0; }
+ TreeMapItemList* children();
+ QColor backColor() const;
+
+private:
+ TraceData* _data;
+};
+
+class PartItem: public TreeMapItem
+{
+public:
+ PartItem(TracePart* p);
+ int rtti() const { return 2; }
+ TracePart* part() { return _p; }
+ double value() const;
+ double sum() const;
+ int borderWidth() const { return 0; }
+ QString text(int) const;
+ QPixmap pixmap(int) const;
+ TreeMapItemList* children();
+ QColor backColor() const;
+
+private:
+ TracePart* _p;
+ unsigned int _factor;
+};
+
+class SubPartItem: public TreeMapItem
+{
+public:
+ SubPartItem(TraceCost*);
+ int rtti() const { return 3; }
+ TraceCost* partCostItem() { return _partCostItem; }
+ double value() const;
+ double sum() const;
+ SplitMode splitMode() const { return Vertical; }
+ QString text(int) const;
+ QPixmap pixmap(int) const;
+ TreeMapItemList* children();
+ QColor backColor() const;
+
+private:
+ TraceCost* _partCostItem;
+ unsigned int _factor;
+};
+
+
+#endif
diff --git a/kcachegrind/kcachegrind/partlistitem.cpp b/kcachegrind/kcachegrind/partlistitem.cpp
new file mode 100644
index 00000000..4f60cf1e
--- /dev/null
+++ b/kcachegrind/kcachegrind/partlistitem.cpp
@@ -0,0 +1,189 @@
+/* This file is part of KCachegrind.
+ Copyright (C) 2003 Josef Weidendorfer <Josef.Weidendorfer@gmx.de>
+
+ KCachegrind is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public
+ License as published by the Free Software Foundation, version 2.
+
+ 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; see the file COPYING. If not, write to
+ the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+*/
+
+#include <math.h>
+
+#include <qpainter.h>
+#include <qregexp.h>
+
+#include <klocale.h>
+#include <kiconloader.h>
+#include <kapplication.h>
+
+#include "listutils.h"
+#include "partlistitem.h"
+#include "coverage.h"
+#include "configuration.h"
+
+
+// PartListItem
+
+PartListItem::PartListItem(QListView* parent, TraceCostItem* costItem,
+ TraceCostType* ct, TraceCost::CostType gt,
+ TracePart* part)
+ :QListViewItem(parent)
+{
+ _partCostItem = costItem->findDepFromPart(part);
+ _part = part;
+ _groupType = gt;
+ _costType = ct;
+
+#if 0
+ QString partName = QString::number(part->partNumber());
+ if (part->data()->maxThreadID() >1)
+ partName += i18n(" (Thread %1)").arg(part->threadID());
+ setText(0, partName);
+#else
+ setText(0, _part->prettyName());
+#endif
+
+ if (_part->trigger().isEmpty())
+ setText(4,i18n("(none)"));
+ else
+ setText(4, _part->trigger());
+
+ update();
+}
+
+void PartListItem::setCostType(TraceCostType* ct)
+{
+ if (_costType == ct) return;
+
+ _costType = ct;
+ update();
+}
+
+void PartListItem::setGroupType(TraceCost::CostType gt)
+{
+ if (_groupType == gt) return;
+
+ _groupType = gt;
+ update();
+}
+
+void PartListItem::update()
+{
+ TracePartFunction* pf;
+ pf = !_partCostItem ? 0 :
+ (_partCostItem->type()==TraceCost::PartFunction) ?
+ ((TracePartFunction*)_partCostItem) : 0;
+
+ double total = _part->subCost(_costType);
+
+ TraceCost* selfTotalCost = _part;
+ if (pf && Configuration::showExpanded()) {
+ switch(_groupType) {
+ case TraceCost::Object: selfTotalCost = pf->partObject(); break;
+ case TraceCost::Class: selfTotalCost = pf->partClass(); break;
+ case TraceCost::File: selfTotalCost = pf->partFile(); break;
+ default: break;
+ }
+ }
+ double selfTotal = selfTotalCost->subCost(_costType);
+
+ _pure = _partCostItem ? _partCostItem->subCost(_costType) : SubCost(0);
+ _sum = pf ? pf->inclusive()->subCost(_costType) : SubCost(0);
+
+ if (selfTotal == 0 || !_partCostItem) {
+ setText(2, QString("-"));
+ setPixmap(2, QPixmap());
+ }
+ else {
+ double pure = 100.0 * _pure / selfTotal;
+ if (Configuration::showPercentage()) {
+ setText(2, QString("%1")
+ .arg(pure, 0, 'f', Configuration::percentPrecision()));
+ }
+ else
+ setText(2, _partCostItem->prettySubCost(_costType));
+
+ setPixmap(2, costPixmap(_costType, _partCostItem, selfTotal, false));
+ }
+
+ if (total == 0 || !pf) {
+ setText(1, QString("-"));
+ setPixmap(1, QPixmap());
+ }
+ else {
+ double sum = 100.0 * _sum / total;
+ if (Configuration::showPercentage()) {
+ setText(1, QString("%1")
+ .arg(sum, 0, 'f', Configuration::percentPrecision()));
+ }
+ else
+ setText(1, _sum.pretty());
+
+ setPixmap(1, costPixmap(_costType, pf->inclusive(), total, false));
+ }
+
+ if (!pf) {
+ setText(3, QString("-"));
+ _callers = 0;
+ return;
+ }
+
+ TracePartCall* pc;
+ TracePartCallList pl;
+ SubCost callers, callees;
+ QString str;
+
+ callers = 0;
+ pl = pf->partCallers();
+ for (pc=pl.first();pc;pc=pl.next()) {
+ callers += pc->callCount();
+ }
+
+ if ((callers == 0) && (pf->calledContexts()>0))
+ str = i18n("(active)");
+ else
+ str = callers.pretty();
+
+ _callers = callers;
+ setText(3, str);
+}
+
+
+int PartListItem::compare(QListViewItem * i, int col, bool ascending ) const
+{
+ PartListItem* fi = (PartListItem*) i;
+ if (col==0) {
+ int mTID = _part->data()->maxThreadID()+1;
+ int mNum = _part->data()->maxPartNumber()+1;
+
+ return
+ (_part->processID() - fi->_part->processID()) * mTID * mNum +
+ (_part->partNumber() - fi->_part->partNumber()) * mTID +
+ (_part->threadID() - fi->_part->threadID());
+ }
+ if (col==1) {
+ if (_sum < fi->_sum) return -1;
+ if (_sum > fi->_sum) return 1;
+ return 0;
+ }
+ if (col==2) {
+ if (_pure < fi->_pure) return -1;
+ if (_pure > fi->_pure) return 1;
+ return 0;
+ }
+ if (col==3) {
+ if (_callers < fi->_callers) return -1;
+ if (_callers > fi->_callers) return 1;
+ return 0;
+ }
+ return QListViewItem::compare(i, col, ascending);
+}
diff --git a/kcachegrind/kcachegrind/partlistitem.h b/kcachegrind/kcachegrind/partlistitem.h
new file mode 100644
index 00000000..98a674fe
--- /dev/null
+++ b/kcachegrind/kcachegrind/partlistitem.h
@@ -0,0 +1,54 @@
+/* This file is part of KCachegrind.
+ Copyright (C) 2003 Josef Weidendorfer <Josef.Weidendorfer@gmx.de>
+
+ KCachegrind is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public
+ License as published by the Free Software Foundation, version 2.
+
+ 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; see the file COPYING. If not, write to
+ the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+*/
+
+#ifndef PARTLISTITEM_H
+#define PARTLISTITEM_H
+
+#include <qlistview.h>
+#include "tracedata.h"
+
+/**
+ * For info tab, trace part list.
+ * Needs update on
+ * - cost type change
+ *
+ * Note: on a cost item / percentage change, the list is rebuild
+ */
+class PartListItem: public QListViewItem
+{
+public:
+ PartListItem(QListView* parent, TraceCostItem* costItem,
+ TraceCostType* ct, TraceCost::CostType gt, TracePart* part);
+
+ int compare(QListViewItem * i, int col, bool ascending ) const;
+ TraceCost* partCostItem() { return _partCostItem; }
+ void setCostType(TraceCostType* ct);
+ void setGroupType(TraceCost::CostType);
+ TracePart* part() { return _part; }
+ void update();
+
+private:
+ SubCost _sum, _pure;
+ SubCost _callers;
+ TraceCostType* _costType;
+ TraceCost* _partCostItem;
+ TracePart* _part;
+ TraceCost::CostType _groupType;
+};
+
+#endif
diff --git a/kcachegrind/kcachegrind/partselection.cpp b/kcachegrind/kcachegrind/partselection.cpp
new file mode 100644
index 00000000..85a46c35
--- /dev/null
+++ b/kcachegrind/kcachegrind/partselection.cpp
@@ -0,0 +1,567 @@
+/* This file is part of KCachegrind.
+ Copyright (C) 2003 Josef Weidendorfer <Josef.Weidendorfer@gmx.de>
+
+ KCachegrind is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public
+ License as published by the Free Software Foundation, version 2.
+
+ 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; see the file COPYING. If not, write to
+ the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+*/
+
+/*
+ * For part file selection, to be put into a QDockWindow
+ */
+
+#include <qtimer.h>
+#include <qlistview.h>
+#include <qlabel.h>
+#include <qpushbutton.h>
+#include <qcombobox.h>
+#include <qlineedit.h>
+#include <qpopupmenu.h>
+#include <qlayout.h>
+
+#include <klocale.h>
+#include <kconfig.h>
+#include <kdebug.h>
+
+#include "partselection.h"
+#include "partgraph.h"
+
+PartSelection::PartSelection( QWidget* parent, const char* name)
+ : PartSelectionBase(parent, name)
+{
+ _data = 0;
+ _costType = 0;
+ _costType2 = 0;
+ _groupType = TraceItem::NoCostType;
+ _group = 0;
+ _function = 0;
+ _inSelectionUpdate = false;
+
+ _diagramMode = false;
+ _drawFrames = true;
+
+ partAreaWidget->setAllowRotation(false);
+ partAreaWidget->setMaxSelectDepth(2);
+ partAreaWidget->setSelectionMode(TreeMapWidget::Extended);
+ partAreaWidget->setSplitMode(TreeMapItem::HAlternate);
+ partAreaWidget->setVisibleWidth(2, true);
+ partAreaWidget->setFieldType(0, i18n( "Name" ));
+ partAreaWidget->setFieldType(1, i18n( "Cost" ));
+
+ connect(partAreaWidget, SIGNAL(selectionChanged()),
+ this, SLOT(selectionChanged()));
+ connect(partAreaWidget, SIGNAL(currentChanged(TreeMapItem*, bool)),
+ this, SLOT(currentChangedSlot(TreeMapItem*, bool)));
+ connect(partAreaWidget, SIGNAL(doubleClicked(TreeMapItem*)),
+ this, SLOT(doubleClicked(TreeMapItem*)));
+ connect(partAreaWidget,
+ SIGNAL(contextMenuRequested(TreeMapItem*,const QPoint &)),
+ this,
+ SLOT(contextMenuRequested(TreeMapItem*,const QPoint &)));
+
+ _showInfo = true;
+ showInfo(false);
+}
+
+PartSelection::~PartSelection()
+{
+}
+
+void PartSelection::setData(TraceData* data)
+{
+ if (_data == data) return;
+
+ _data = data;
+ partAreaWidget->setData(data);
+ fillInfo();
+}
+
+
+void PartSelection::refresh()
+{
+ partAreaWidget->redraw();
+ fillInfo();
+}
+
+void PartSelection::setCostType(TraceCostType* ct)
+{
+ if (ct == _costType) return;
+ _costType = ct;
+
+ partAreaWidget->setCostType(ct);
+}
+
+void PartSelection::setCostType2(TraceCostType* ct)
+{
+ if (ct == _costType2) return;
+ _costType2 = ct;
+ if (!_diagramMode) return;
+
+ //TODO: get max cost(type1)/cost(type2) of shown parts
+ //partAreaWidget->setCostType(ct);
+}
+
+void PartSelection::setGroupType(TraceItem::CostType gt)
+{
+ if (gt == _groupType) return;
+ _groupType = gt;
+
+ partAreaWidget->setGroupType(gt);
+}
+
+void PartSelection::setGroup(TraceCostItem*)
+{
+}
+
+void PartSelection::setFunction(TraceFunction* f)
+{
+ if (_function == f) return;
+ _function = f;
+
+ //kdDebug() << "PartSelection::setFunction " << f->name() << endl;
+
+ // FIXME: The TreeMap shouldn't produce spurious selectionChanged events
+ _inSelectionUpdate = true;
+ partAreaWidget->setFunction(_function);
+ _inSelectionUpdate = false;
+}
+
+void PartSelection::setPart(TracePart*)
+{}
+
+void PartSelection::currentChangedSlot(TreeMapItem* i, bool kbd)
+{
+ if (!i) return;
+ if (!kbd) return;
+ if (i->text(0).isEmpty()) return;
+
+ QString str = i->text(0);
+ if (!i->text(1).isEmpty())
+ str += " (" + i->text(1) + ")";
+ QString msg = i18n("Profile Part Overview: Current is '%1'").arg(str);
+ emit showMessage(msg, 5000);
+
+ if (_showInfo) fillInfo();
+}
+
+
+void PartSelection::doubleClicked(TreeMapItem* i)
+{
+ if (!i || i->rtti() != 3) return;
+
+ TraceCost* c = ((SubPartItem*) i)->partCostItem();
+ TraceCostItem* ci = 0;
+
+ switch(c->type()) {
+ case TraceItem::PartFunction:
+ {
+ TraceFunction* f = ((TracePartFunction*)c)->function();
+ if (f)
+ emit functionChanged(f);
+ }
+ return;
+
+ case TraceItem::PartObject:
+ ci = ((TracePartObject*)c)->object();
+ break;
+ case TraceItem::PartClass:
+ ci = ((TracePartClass*)c)->cls();
+ break;
+ case TraceItem::PartFile:
+ ci = ((TracePartFile*)c)->file();
+ break;
+ default:
+ break;
+ }
+
+ if (ci)
+ emit groupChanged(ci);
+}
+
+
+void PartSelection::selectionChanged()
+{
+ if (_inSelectionUpdate) return;
+
+ kdDebug() << "PartSelection::selectionChanged" << endl;
+
+ bool something_changed = false;
+ bool nothingSelected = true;
+
+ TracePartList pList;
+ TreeMapItem* i;
+ TracePart* part;
+
+ // if nothing is selected, activate all parts
+ TreeMapItemList* list = partAreaWidget->base()->children();
+ if (!list) return;
+
+ for (i=list->first();i;i=list->next())
+ if (partAreaWidget->isSelected(i)) {
+ nothingSelected = false;
+ break;
+ }
+
+ for (i=list->first();i;i=list->next()) {
+ part = ((PartItem*)i)->part();
+ bool active = nothingSelected || partAreaWidget->isSelected(i);
+ if (active) {
+ pList.append(part);
+ something_changed = true;
+ }
+ }
+
+ if (something_changed) {
+ //qDebug("PartSelection: Something changed.");
+ emit activePartsChanged(pList);
+ }
+}
+
+/* this makes the graph selection the same to the parts in the list */
+void PartSelection::activePartsChangedSlot(const TracePartList& list)
+{
+ _inSelectionUpdate = true;
+
+ kdDebug() << "Entering PartSelection::activePartsChangedSlot" << endl;
+
+ TreeMapItem* i;
+ TreeMapItemList l = *partAreaWidget->base()->children();
+ // first deselect inactive, then select active (makes current active)
+ for (i=l.first();i;i=l.next()) {
+ TracePart* part = ((PartItem*)i)->part();
+ bool active = (list.containsRef(part)>0);
+ if (!active && partAreaWidget->isSelected(i)) {
+#if 0
+ qDebug("PartSelection::partsChangedSlot: Part %s changed to unselected.",
+ ((PartItem*)i)->part()->shortName().ascii());
+#endif
+
+ partAreaWidget->setSelected(i, false);
+ }
+ }
+ for (i=l.first();i;i=l.next()) {
+ TracePart* part = ((PartItem*)i)->part();
+ bool active = (list.containsRef(part)>0);
+ if (active && !partAreaWidget->isSelected(i)) {
+#if 0
+ qDebug("PartSelection::partsChangedSlot: Part %s changed to selected.",
+ ((PartItem*)i)->part()->shortName().ascii());
+#endif
+ partAreaWidget->setSelected(i, true);
+ }
+ }
+
+ _inSelectionUpdate = false;
+
+ kdDebug() << "Leaving PartSelection::activePartsChangedSlot" << endl;
+
+ fillInfo();
+}
+
+void PartSelection::contextMenuRequested(TreeMapItem* i,
+ const QPoint & p)
+{
+ if (!i) return;
+
+ QPopupMenu popup;
+ QPopupMenu ppopup;
+ QPopupMenu vpopup;
+
+ QString str;
+ TreeMapItem* s = 0;
+
+ if (_data && (_data->parts().count()>1)) {
+ s = partAreaWidget->possibleSelection(i);
+ if (!s->text(0).isEmpty()) {
+ str = (partAreaWidget->isSelected(s)) ?
+ i18n("Deselect") : i18n("Select");
+ str += " '" + s->text(0) + "'";
+ popup.insertItem(str, 1);
+ }
+
+ popup.insertItem(i18n("Select All Parts"), 2);
+
+ popup.insertItem(i18n("Visible Parts"), &ppopup, 10);
+
+ ppopup.insertItem(i18n("Hide Selected Parts"), 3);
+ ppopup.insertItem(i18n("Unhide Hidden Parts"), 4);
+
+ popup.insertSeparator();
+ }
+
+ popup.insertItem(i18n("Go Back"), 99);
+ if (i->rtti() == 3) {
+ TreeMapItem* ni = i;
+ int id = 100;
+ while (ni && ni->rtti() == 3) {
+ TraceCost* c = ((SubPartItem*)ni)->partCostItem();
+ if (c->type() == TraceItem::PartFunction)
+ if ( ((TracePartFunction*)c)->function() == _function) break;
+
+ str = i18n("Select") + " '" + ni->text(0) + "'";
+ popup.insertItem(str, id);
+ ni = ni->parent();
+ id++;
+ }
+ }
+ popup.insertSeparator();
+
+ vpopup.setCheckable(true);
+ popup.insertItem(i18n("Visualization"), &vpopup, 10);
+
+ vpopup.insertItem(i18n("Partitioning Mode"), 30);
+ vpopup.insertItem(i18n("Diagram Mode"), 34);
+ vpopup.insertItem(i18n("Zoom Function"), 31);
+ vpopup.insertItem(i18n("Show Direct Calls"), 32);
+ vpopup.insertItem(i18n("Increment Shown Call Levels"), 33);
+ if (partAreaWidget->visualisation() == PartAreaWidget::Partitioning) {
+ vpopup.setItemChecked(30, true);
+ vpopup.setItemEnabled(31, false);
+ vpopup.setItemEnabled(32, false);
+ vpopup.setItemEnabled(33, false);
+ }
+ else {
+ vpopup.setItemChecked(31, partAreaWidget->zoomFunction());
+ }
+ vpopup.setItemChecked(34, _diagramMode);
+
+ vpopup.insertSeparator();
+
+ vpopup.insertItem(i18n("Draw Names"), 20);
+ vpopup.insertItem(i18n("Draw Costs"), 21);
+ vpopup.insertItem(i18n("Ignore Proportions"), 22);
+ vpopup.insertItem(i18n("Draw Frames"), 24);
+ vpopup.insertItem(i18n("Allow Rotation"), 23);
+ if (!partAreaWidget->fieldVisible(0) &&
+ !partAreaWidget->fieldVisible(1)) {
+ vpopup.setItemEnabled(22, false);
+ vpopup.setItemEnabled(23, false);
+ }
+ else {
+ vpopup.setItemChecked(20,partAreaWidget->fieldVisible(0));
+ vpopup.setItemChecked(21,partAreaWidget->fieldVisible(1));
+ vpopup.setItemChecked(22,partAreaWidget->fieldForced(0));
+ vpopup.setItemChecked(23,partAreaWidget->allowRotation());
+ vpopup.setItemChecked(24,_drawFrames);
+ }
+
+ if (_showInfo)
+ popup.insertItem(i18n("Hide Info"), 40);
+ else
+ popup.insertItem(i18n("Show Info"), 41);
+
+ int r = popup.exec(partAreaWidget->mapToGlobal(p));
+
+ if (r>=100) {
+ TreeMapItem* ci = i;
+ while (ci && r>100) {
+ ci = ci->parent();
+ r--;
+ }
+ doubleClicked(ci);
+ return;
+ }
+
+ switch(r) {
+ case 1:
+ // select/deselect part under mouse
+ partAreaWidget->setSelected(s, !partAreaWidget->isSelected(s));
+ break;
+
+ case 2:
+ // select all parts
+ {
+ TreeMapItemList list = *partAreaWidget->base()->children();
+ partAreaWidget->setRangeSelection(list.first(), list.last(), true);
+ }
+ break;
+
+ case 3:
+ emit partsHideSelected();
+ break;
+
+ case 4:
+ emit partsUnhideAll();
+ break;
+
+ case 99:
+ // last selected function
+ emit goBack();
+ break;
+
+ case 20:
+ partAreaWidget->setFieldVisible(0, !vpopup.isItemChecked(20));
+ break;
+
+ case 21:
+ partAreaWidget->setFieldVisible(1, !vpopup.isItemChecked(21));
+ break;
+
+ case 22:
+ partAreaWidget->setFieldForced(0, !vpopup.isItemChecked(22));
+ partAreaWidget->setFieldForced(1, !vpopup.isItemChecked(22));
+ break;
+
+ case 23: partAreaWidget->setAllowRotation(!vpopup.isItemChecked(23)); break;
+
+ case 24:
+ _drawFrames = !_drawFrames;
+ partAreaWidget->drawFrame(2,_drawFrames);
+ partAreaWidget->drawFrame(3,_drawFrames);
+ break;
+
+ case 30:
+ partAreaWidget->setVisualisation(!vpopup.isItemChecked(30) ?
+ PartAreaWidget::Partitioning :
+ PartAreaWidget::Inclusive);
+ break;
+
+ case 31:
+ // zoom/unzoom function
+ partAreaWidget->setZoomFunction(!vpopup.isItemChecked(31));
+ break;
+
+ case 32:
+ case 33:
+ // change call Levels
+ {
+ int l = (r==32) ? 1 : partAreaWidget->callLevels()+1;
+ partAreaWidget->setCallLevels(l);
+ }
+ break;
+
+ case 34:
+ _diagramMode = !_diagramMode;
+ partAreaWidget->setTransparent(2,_diagramMode);
+ break;
+
+
+ case 40:
+ case 41:
+ showInfo(r==41);
+ break;
+
+ default:
+ break;
+ }
+}
+
+void PartSelection::hiddenPartsChangedSlot(const TracePartList& list)
+{
+ partAreaWidget->changeHidden(list);
+}
+
+void PartSelection::readVisualisationConfig(KConfigGroup* config)
+{
+ bool enable;
+
+ QString mode = config->readEntry("PartitionMode", "Inclusive");
+ if (mode == "Inclusive")
+ partAreaWidget->setVisualisation(PartAreaWidget::Inclusive);
+ else
+ partAreaWidget->setVisualisation(PartAreaWidget::Partitioning);
+
+ _diagramMode = config->readBoolEntry("DiagramMode", false);
+ partAreaWidget->setTransparent(2,_diagramMode);
+
+ _drawFrames = config->readBoolEntry("DrawFrames", true);
+ partAreaWidget->drawFrame(2,_drawFrames);
+ partAreaWidget->drawFrame(3,_drawFrames);
+
+ enable = config->readBoolEntry("GraphZoom", false);
+ partAreaWidget->setZoomFunction(enable);
+
+ int levels = config->readNumEntry("GraphLevels", 1);
+ partAreaWidget->setCallLevels(levels);
+
+ enable = config->readBoolEntry("GraphDrawName", true);
+ partAreaWidget->setFieldVisible(0, enable);
+
+ enable = config->readBoolEntry("GraphDrawCost", true);
+ partAreaWidget->setFieldVisible(1, enable);
+
+ enable = config->readBoolEntry("GraphForceStrings", false);
+ partAreaWidget->setFieldForced(0, enable);
+ partAreaWidget->setFieldForced(1, enable);
+
+ enable = config->readBoolEntry("GraphAllowRotation", true);
+ partAreaWidget->setAllowRotation(enable);
+
+ showInfo(config->readBoolEntry("ShowInfo", false));
+}
+
+void PartSelection::saveVisualisationConfig(KConfigGroup* config)
+{
+ QString mode;
+ if (partAreaWidget->visualisation() == PartAreaWidget::Inclusive)
+ mode = "Inclusive";
+ else
+ mode = "Partitioning";
+ config->writeEntry("PartitionMode", mode);
+
+ config->writeEntry("DiagramMode", _diagramMode);
+ config->writeEntry("DrawFrames", _drawFrames);
+
+ config->writeEntry("GraphZoom", partAreaWidget->zoomFunction());
+ config->writeEntry("GraphLevels", partAreaWidget->callLevels());
+ config->writeEntry("GraphDrawName", partAreaWidget->fieldVisible(0));
+ config->writeEntry("GraphDrawCosts", partAreaWidget->fieldVisible(1));
+ config->writeEntry("GraphForceStrings", partAreaWidget->fieldForced(0));
+ config->writeEntry("GraphAllowRotation", partAreaWidget->allowRotation());
+
+ config->writeEntry("ShowInfo", _showInfo);
+}
+
+void PartSelection::showInfo(bool enable)
+{
+ if (_showInfo == enable) return;
+
+ _showInfo = enable;
+ if (enable) {
+ rangeLabel->show();
+ fillInfo();
+ }
+ else
+ rangeLabel->hide();
+}
+
+void PartSelection::fillInfo()
+{
+ if (!_data) {
+ rangeLabel->setText(i18n("(no trace loaded)"));
+ return;
+ }
+
+ QString info = _data->activePartRange();
+
+ TreeMapItem* i = partAreaWidget->current();
+ while (i && i->rtti()!=2) i = i->parent();
+ if (i) {
+ TracePart* part = ((PartItem*)i)->part();
+
+ //if (!part->trigger().isEmpty()) info += ", " + part->trigger();
+ if (!part->timeframe().isEmpty())
+ info += ", Time " + part->timeframe() + " BBs";
+ }
+ else {
+ TracePart* part = _data->parts().first();
+
+ if (part && !part->version().isEmpty())
+ info += ", Cachegrind " + part->version();
+ }
+
+
+ rangeLabel->setText(info);
+}
+
+#include "partselection.moc"
diff --git a/kcachegrind/kcachegrind/partselection.h b/kcachegrind/kcachegrind/partselection.h
new file mode 100644
index 00000000..168446f1
--- /dev/null
+++ b/kcachegrind/kcachegrind/partselection.h
@@ -0,0 +1,95 @@
+/* This file is part of KCachegrind.
+ Copyright (C) 2003 Josef Weidendorfer <Josef.Weidendorfer@gmx.de>
+
+ KCachegrind is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public
+ License as published by the Free Software Foundation, version 2.
+
+ 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; see the file COPYING. If not, write to
+ the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+*/
+
+/*
+ * PartSelection for KCachegrind
+ * For part file selection, to be put into a QDockWindow
+ */
+
+#ifndef PARTSELECTION_H
+#define PARTSELECTION_H
+
+#include <qobject.h>
+
+#include "partselectionbase.h"
+#include "partgraph.h"
+#include "tracedata.h"
+
+class KConfigGroup;
+class TraceFunction;
+class TraceData;
+class TreeMapItem;
+
+class PartSelection: public PartSelectionBase
+{
+ Q_OBJECT
+
+public:
+ PartSelection( QWidget* parent = 0, const char* name = 0);
+ ~PartSelection();
+
+ TraceData* data() { return _data; }
+ void setData(TraceData*);
+
+ PartAreaWidget* graph() { return partAreaWidget; }
+
+ void readVisualisationConfig(KConfigGroup*);
+ void saveVisualisationConfig(KConfigGroup*);
+
+signals:
+ void activePartsChanged(const TracePartList& list);
+ void partsHideSelected();
+ void partsUnhideAll();
+ void groupChanged(TraceCostItem*);
+ void functionChanged(TraceItem*);
+ void showMessage(const QString&, int);
+ void goBack();
+
+public slots:
+ void selectionChanged();
+ void doubleClicked(TreeMapItem*);
+ void contextMenuRequested(TreeMapItem*, const QPoint &);
+ void currentChangedSlot(TreeMapItem*, bool);
+
+ void setPart(TracePart*);
+ void setCostType(TraceCostType*);
+ void setCostType2(TraceCostType*);
+ void setGroupType(TraceItem::CostType);
+ void setGroup(TraceCostItem*);
+ void setFunction(TraceFunction*);
+ void activePartsChangedSlot(const TracePartList& list);
+ void hiddenPartsChangedSlot(const TracePartList& list);
+ void refresh();
+ void showInfo(bool);
+
+private:
+ void fillInfo();
+
+ TraceData* _data;
+ TraceCostType *_costType, *_costType2;
+ TraceItem::CostType _groupType;
+ TraceCostItem* _group;
+ TraceFunction* _function;
+ bool _showInfo;
+ bool _diagramMode;
+ bool _drawFrames;
+
+ bool _inSelectionUpdate;
+};
+
+#endif
diff --git a/kcachegrind/kcachegrind/partselectionbase.ui b/kcachegrind/kcachegrind/partselectionbase.ui
new file mode 100644
index 00000000..3267f49a
--- /dev/null
+++ b/kcachegrind/kcachegrind/partselectionbase.ui
@@ -0,0 +1,89 @@
+<!DOCTYPE UI><UI version="3.0" stdsetdef="1">
+<class>PartSelectionBase</class>
+<widget class="QWidget">
+ <property name="name">
+ <cstring>PartSelectionBase</cstring>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>460</width>
+ <height>402</height>
+ </rect>
+ </property>
+ <property name="caption">
+ <string>Parts Overview</string>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>6</number>
+ </property>
+ <property name="spacing">
+ <number>6</number>
+ </property>
+ <widget class="PartAreaWidget">
+ <property name="name">
+ <cstring>partAreaWidget</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>5</hsizetype>
+ <vsizetype>7</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="minimumSize">
+ <size>
+ <width>0</width>
+ <height>50</height>
+ </size>
+ </property>
+ </widget>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>rangeLabel</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>7</hsizetype>
+ <vsizetype>5</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="text">
+ <string>(no trace parts)</string>
+ </property>
+ </widget>
+ </vbox>
+</widget>
+<customwidgets>
+ <customwidget>
+ <class>PartAreaWidget</class>
+ <header location="local">partgraph.h</header>
+ <sizehint>
+ <width>-1</width>
+ <height>-1</height>
+ </sizehint>
+ <container>0</container>
+ <sizepolicy>
+ <hordata>5</hordata>
+ <verdata>7</verdata>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ <pixmap>image0</pixmap>
+ </customwidget>
+</customwidgets>
+<images>
+ <image name="image0">
+ <data format="XPM.GZ" length="5230">789c9597db4e1d4b0e86eff31428be8b46b5fb54dd551acd051020211c4320c0682eecaa5e9ccf90005bf3ee53cbbfe9d9c9c548a38ea27c2977b5cbfe6dd7fae3c3c2e1cee6c2873fde3d3cf2e3595a48a77cbff0213f5d5dbdfcf35ffff8f3ddfba65998fff161a179ffb777ef771f17d2c2d6cdf53807c705a889cdac6ee72c47736eebd637b5f2b672d70ecd30e744ca7d9b9a4ad7579587363433e527e5d072abefbb03636978ceb4a31c5bc13a91716ad41f89e0aec2fe74abcc6d6ad5f9e4945357375ef75f997357751dd61d19c71afb61bdef421b951f274ebaffb6716cb3f2b2f230f18d3183dd95b1b441d7d59f2e94757ccf1b27eceff69563618d0f5dcfd9d7beeb7a5dd7f3fac6fb4ee32b87c619f1168d976f7d6ff6df26d6ef4b301e1bac7f54f63e747a5e87f5c173276aff605c22a8fefc540e5e3af5972f956359577bf2c6d978cb78d6697edc9eb2f8b143fed7945359d778b0e6c3e7be81bf7465dce23cf4ac3c16567f19fecefaae53bd081b7baccbb131b7d05f679ca03f27c6b9d1f388c6bbaffab7f80dca4d1fed7bfafdbeedb9533d490f1e2ae8d5693ccacb83d77cd027e3d4416faa97beefa3d7f8f086f168f9d9020f43a3f5c5aa877e28eb88f74fe319becfaa873e0c15de775f95639f3dec37c143d361bf2be3cef4b76bdcb7d84ff5d2cbd0227facf1ecd360fa67d54b9f078ffcd10f636e11ff53e3847853ad3c1b668837e9fe43358c2df45a81430b3db2e6676842d368fd48abdc068b87e0fd2e788bf792b21f861e7afd0e0e5ce37dcdd7d0872218e5d789f57b3218a71ae7bb501eca3af67b510e21c05fd27a1b6218ac3ef17d0ed68fe8cb1be3fc6e5159863ca0bfed824340fe687d62c4838c23f677f0370de380fcdd2be7e03dfab1d6cf300bcd80fa80bfb358dbf9547fa18abe413d68fe421d63ade7737aded094cf63fdcc38f4d0bfee17dac2d08380a3a0dff24cb90bdc23ffaa87e0636c912fed87612e38d4df1e982bc4dbdd29872001f14aca319413eb793e83cbfbe8af27606e4c0f5f8d3bcb7763ec6b8da73b57e69083d61f9d82b9b5fada31f635fcaf8d7b7b5ffb41f16e34ff34fe214dfc0c8e1ef1a22330bfcdc345e31e4c33e3c1e6e181b1609e3ac43f8759803e8cd9f2e7e0ff18ab80ef5d8239e2fc0ef129f90ff0bf0773347fee8d13ce279bc6b34af5c61abf58157bf4b765b05435f4abfec726968c2b67e536fa80fe388279067f680d2c750dff75fe9766da07e44bc02521ba4e1d584c1fb261dcc23fd97f63f8c3af136bfc687362c4e76962ed8fac7a2ecdb7853f7c63ec6bf467bd3fc421c680780c60b6f9275fc045aea84fadaf18a2e0fc04ff0237bd9e8fefc0d236e8ef3f8d83c57fdd38daf94edeb886be74fec618b3ed7f3731e66b0fe67a403e76c0454ef8de9231dbfe9f8dc5fc47be38a6887ad2f950964d2fdc1a27d3c7b6710693f6ef9864b4fdb4ffc6cc5540fea0972c339c87afc1c9f4443a5fe2c84d40bd2f82cb3ae6c7b1716dbc37b1e68bf5be118b7e3dead78125d87d0bfa99bd7d8fb78c1bdb4fcfcfd51bcb9d716bebda3fb8966cf7cf57709103f2e327c6fe5a2fdc4ab4fb01deef5283fa65d50ffb54c13fd67ec37d61e845fb070f8571df7c341eec7e7a691c6ae453fb771937d1fa999ebfa43358bf573d3327c6fdd0a9de59b87414e59f60911ef3ff07380d16bf0b63b6fbb8ce0f4e523a80ee8ff8a5f21fe83f384f2e8cf9d419db7d4bb4bff32cb1dd871ae38c79417962dd9f8f2786bfaa3fa992ddbf68d5d8d6797d62dc27b4bf4a9bdeee5be7c619efbb169c2b9bb7aa67e972857a67d59bf8943cf4a6f5237dae3b9c3f4f8cef5713637e6a3c6548e546a7eb87e0b28e7cf7c68ddd2fb15f28acf166bd2f484c19f921f8cbc57de84ff52c397b8f7e178d7bbb7f7e9f18f743d593ccd210d12f9e8c05fd8417c1e5e704e2afefa7aa5cf850ff4fc6a1473debfc4d7561c4ebd3c48897f69fd4e4d8eb7e4efb736a0b23fe9adfd465bb3f388d6ff22933fa1df6f7597ad483c62371f6e6ff8671b6f89e198fb8cfb0ea3f49619c6f6562cc27d5474a7906e6b589d1df549f29e78479450fe0b1c2fc67d5731a0ba33ffc97a167fd7d92ebb1b1f9a87acdcdd8a23ff2e3c4a81fed0fb91bbb88f8e9f772f9b9c6b8bfac187bd41febbcc8c35831f4bb6edc227eeec8b847bc58ef0f398d91a1179d6f391746bdebfd60ac4716b0180bd8a97e473f8ea2dfdb7d9c3f8e1cff8f8760057b27e57f92cb6e743377e24efff29cb97377e12edd55b190c99eddb5bb71b7eeceddbb07f7e89edc0ff7d33dbb17f7ea16dd925b761fdd8a63d8174f52b15e756bee93fbecd6dd17b7e136dd96db763b6ed77d2dd67bee9bdb77078ed49e8b27b7c5fabb3b7447eed855ae768d6bcbd339ef7a37b8e022392a2734fbd1dd119350a24c23cde8844ee98ccee9c2f9c2977445d77443b793fd8ceee89e1ee8919ee807fdb4e7995ee8b5d82fd252b15ffe8bfd097da4155aa535fa34597fa6f5f2f717da28f69bb445dbb433d99fd22e7da53dfa3659efd3017da7c3f2af233aa68aeadfec1b6aa9236fd63d0d14ca15c0719913737b965fedcbf0c83cc29a677cc2a77cc6e77cc1977cc5d7c5fee637fbdbb2db9d5adff343b17ee427fec1737ee69762fffa9bfd222ff17259fdc82bbcca6bfc893ff33a7fe10ddee42ddee69ddfec77f92beff137dee703fece877cc4c7aee58a6b6ee8b8fc10ed7eb13f635f9a4bc5e54719477152ba671977a505c84845c57222a7bfd89fcb999ccb855cca955cbfc5546ee456ee68b14cf67b799047799aec2fdc92fc28999cef567224cff222afb2c85b32e36d599265f9282bb23ad95fba6559934f2593f3e798b74acc8fd5f6b3accb17d9904dd9926db3a7520d1fdd37d9915df95a72599e1291566df7e49beccb817c974339829eb55e56dc7e51ec0d2dcbb1545297a791563af1c5eff2d3beb4faf8562f568f0744745b9e9d5f1f7992d5e412a186ffef7afff7dfdffd077c99ae99</data>
+ </image>
+</images>
+<layoutdefaults spacing="6" margin="11"/>
+</UI>
diff --git a/kcachegrind/kcachegrind/partview.cpp b/kcachegrind/kcachegrind/partview.cpp
new file mode 100644
index 00000000..ea1db4d7
--- /dev/null
+++ b/kcachegrind/kcachegrind/partview.cpp
@@ -0,0 +1,235 @@
+/* This file is part of KCachegrind.
+ Copyright (C) 2003 Josef Weidendorfer <Josef.Weidendorfer@gmx.de>
+
+ KCachegrind is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public
+ License as published by the Free Software Foundation, version 2.
+
+ 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; see the file COPYING. If not, write to
+ the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+*/
+
+/*
+ * Part View
+ */
+
+#include <qwhatsthis.h>
+#include <qpopupmenu.h>
+#include <qheader.h>
+#include <klocale.h>
+
+#include "configuration.h"
+#include "partlistitem.h"
+#include "toplevel.h"
+#include "partview.h"
+
+
+
+//
+// PartView
+//
+
+
+PartView::PartView(TraceItemView* parentView,
+ QWidget* parent, const char* name)
+ : QListView(parent, name), TraceItemView(parentView)
+{
+ _inSelectionUpdate = false;
+
+ addColumn( i18n( "Profile Part" ) );
+ addColumn( i18n( "Incl." ) );
+ addColumn( i18n( "Self" ) );
+ addColumn( i18n( "Called" ) );
+ //addColumn( i18n( "Fixed" ) );
+ addColumn( i18n( "Comment" ) );
+
+ setAllColumnsShowFocus(true);
+ setColumnAlignment(1, Qt::AlignRight);
+ setColumnAlignment(2, Qt::AlignRight);
+ setColumnAlignment(3, Qt::AlignRight);
+ setMinimumHeight(50);
+ setSelectionMode(Extended);
+
+ connect( this,
+ SIGNAL( selectionChanged() ),
+ SLOT( selectionChangedSlot() ) );
+
+ connect( this,
+ SIGNAL(contextMenuRequested(QListViewItem*, const QPoint &, int)),
+ SLOT(context(QListViewItem*, const QPoint &, int)));
+
+ QWhatsThis::add( this, whatsThis() );
+}
+
+QString PartView::whatsThis() const
+{
+ return i18n( "<b>Trace Part List</b>"
+ "<p>This list shows all trace parts of the loaded "
+ "trace. For each part, the "
+ "self/inclusive cost of the current selected "
+ "function, spent in the part, is shown; "
+ "percentage costs are always relative to the "
+ "total cost <em>of the part</em> (not to the whole "
+ "trace as in the Trace Part Overview). "
+ "Also shown are the calls happening to/from the "
+ "current function inside of the trace part.</p>"
+ "<p>By choosing one or more trace parts from the "
+ "list, the costs shown all over KCachegrind will "
+ "only be the ones spent in the selected part(s). "
+ "If no list selection is shown, in fact all trace "
+ "parts are selected implicitly.</p>"
+ "<p>This is a multi-selection list. You can select "
+ "ranges by dragging the mouse or use SHIFT/CTRL "
+ "modifiers. "
+ "Selection/Deselection of trace parts can also be "
+ "done by using the Trace Part Overview Dockable. "
+ "This one also supports multiple selection.</p>"
+ "<p>Note that the list is hidden if only one trace "
+ "part is loaded.</p>");
+}
+
+
+void PartView::context(QListViewItem* i, const QPoint & pos, int)
+{
+ QPopupMenu popup;
+
+ TracePart* p = i ? ((PartListItem*) i)->part() : 0;
+
+ if (p) {
+ popup.insertItem(i18n("Select '%1'").arg(p->name()), 93);
+ popup.insertItem(i18n("Hide '%1'").arg(p->name()), 94);
+ popup.insertSeparator();
+ }
+
+ popup.insertItem(i18n("Hide Selected"), 95);
+ popup.insertItem(i18n("Show All"), 96);
+ popup.insertSeparator();
+
+ addGoMenu(&popup);
+
+ int r = popup.exec(pos);
+ if (r == 95) {
+ ;
+ }
+
+ // TODO: ...
+}
+
+void PartView::selectionChangedSlot()
+{
+ if (_inSelectionUpdate) return;
+
+ TracePartList l;
+ QListViewItem* item = firstChild();
+ for(;item;item = item->nextSibling())
+ if (item->isSelected())
+ l.append( ((PartListItem*)item)->part() );
+
+ selected(l);
+}
+
+
+TraceItem* PartView::canShow(TraceItem* i)
+{
+ if (!data()) return 0;
+ if (data()->parts().count()>1) return i;
+ return 0;
+}
+
+void PartView::doUpdate(int changeType)
+{
+ // Special case ?
+ if (changeType == costType2Changed) return;
+ if (changeType == selectedItemChanged) return;
+
+ if (changeType == groupTypeChanged) {
+ QListViewItem *item;
+ for (item = firstChild();item;item = item->nextSibling())
+ ((PartListItem*)item)->setGroupType(_groupType);
+
+ return;
+ }
+
+ if (changeType == costTypeChanged) {
+ QListViewItem *item;
+ for (item = firstChild();item;item = item->nextSibling())
+ ((PartListItem*)item)->setCostType(_costType);
+
+ return;
+ }
+
+ if (changeType == partsChanged) {
+
+ TracePart* part;
+
+ QListViewItem* item;
+ _inSelectionUpdate = true;
+ item = firstChild();
+ for(;item;item = item->nextSibling()) {
+ part = ((PartListItem*)item)->part();
+
+ if (_partList.containsRef(part)>0) {
+ setSelected(item, true);
+ ensureItemVisible(item);
+ }
+ else
+ setSelected(item, false);
+ }
+ _inSelectionUpdate = false;
+
+ return;
+ }
+
+ refresh();
+}
+
+void PartView::refresh()
+{
+ clear();
+ setColumnWidth(1, 50);
+ setColumnWidth(2, 50);
+
+ if (!_data || !_activeItem) return;
+
+ TraceItem::CostType t = _activeItem->type();
+ TraceFunction* f = 0;
+ if (t == TraceItem::Function) f = (TraceFunction*) _activeItem;
+ if (!f) return;
+
+ TracePart* part;
+ TracePartList hidden;
+ if (_topLevel)
+ hidden = _topLevel->hiddenParts();
+
+ TracePartList allParts = _data->parts();
+
+ _inSelectionUpdate = true;
+
+ QListViewItem* item = 0;
+ for (part = allParts.first(); part; part = allParts.next()) {
+ if (hidden.findRef(part)>=0) continue;
+ item = new PartListItem(this, f, _costType, _groupType, part);
+
+ if (part->isActive()) {
+ setSelected(item, true);
+ ensureItemVisible(item);
+ }
+ }
+
+ _inSelectionUpdate = false;
+
+ if (item) {
+ int headerHeight = header()->height();
+ int itemHeight = item->height();
+ setMinimumHeight(headerHeight + 2*itemHeight + 2);
+ }
+}
+
+#include "partview.moc"
diff --git a/kcachegrind/kcachegrind/partview.h b/kcachegrind/kcachegrind/partview.h
new file mode 100644
index 00000000..5c6c513b
--- /dev/null
+++ b/kcachegrind/kcachegrind/partview.h
@@ -0,0 +1,54 @@
+/* This file is part of KCachegrind.
+ Copyright (C) 2003 Josef Weidendorfer <Josef.Weidendorfer@gmx.de>
+
+ KCachegrind is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public
+ License as published by the Free Software Foundation, version 2.
+
+ 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; see the file COPYING. If not, write to
+ the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+*/
+
+/*
+ * Part View
+ */
+
+#ifndef PARTVIEW_H
+#define PARTVIEW_H
+
+#include <qlistview.h>
+#include "tracedata.h"
+#include "traceitemview.h"
+
+class PartView: public QListView, public TraceItemView
+{
+ Q_OBJECT
+
+public:
+ PartView(TraceItemView* parentView,
+ QWidget* parent=0, const char* name=0);
+
+ virtual QWidget* widget() { return this; }
+ QString whatsThis() const;
+
+ void refresh();
+
+private slots:
+ void context(QListViewItem*,const QPoint &, int);
+ void selectionChangedSlot();
+
+private:
+ TraceItem* canShow(TraceItem*);
+ void doUpdate(int);
+
+ bool _inSelectionUpdate;
+};
+
+#endif
diff --git a/kcachegrind/kcachegrind/pool.cpp b/kcachegrind/kcachegrind/pool.cpp
new file mode 100644
index 00000000..ec8d4074
--- /dev/null
+++ b/kcachegrind/kcachegrind/pool.cpp
@@ -0,0 +1,258 @@
+/* This file is part of KCachegrind.
+ Copyright (C) 2002-2004 Josef Weidendorfer <Josef.Weidendorfer@gmx.de>
+
+ KCachegrind is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public
+ License as published by the Free Software Foundation, version 2.
+
+ 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; see the file COPYING. If not, write to
+ the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+*/
+
+#include <string.h>
+#include <stdlib.h>
+#include <qglobal.h>
+#include "pool.h"
+
+// FixPool
+
+#define CHUNK_SIZE 100000
+
+struct SpaceChunk
+{
+ struct SpaceChunk* next;
+ unsigned int used;
+ char space[1];
+};
+
+FixPool::FixPool()
+{
+ _first = _last = 0;
+ _reservation = 0;
+ _count = 0;
+ _size = 0;
+}
+
+FixPool::~FixPool()
+{
+ struct SpaceChunk* chunk = _first, *next;
+
+ while(chunk) {
+ next = chunk->next;
+ free(chunk);
+ chunk = next;
+ }
+
+ if (0) qDebug("~FixPool: Had %d objects with total size %d\n",
+ _count, _size);
+}
+
+void* FixPool::allocate(unsigned int size)
+{
+ if (!ensureSpace(size)) return 0;
+
+ _reservation = 0;
+ void* result = _last->space + _last->used;
+ _last->used += size;
+
+ _count++;
+ _size += size;
+
+ return result;
+}
+
+void* FixPool::reserve(unsigned int size)
+{
+ if (!ensureSpace(size)) return 0;
+ _reservation = size;
+
+ return _last->space + _last->used;
+}
+
+
+bool FixPool::allocateReserved(unsigned int size)
+{
+ if (_reservation < size) return false;
+
+ _reservation = 0;
+ _last->used += size;
+
+ _count++;
+ _size += size;
+
+ return true;
+}
+
+bool FixPool::ensureSpace(unsigned int size)
+{
+ if (_last && _last->used + size <= CHUNK_SIZE) return true;
+
+ struct SpaceChunk* newChunk;
+
+ // we don't allow allocation sizes > CHUNK_SIZE
+ if (size > CHUNK_SIZE) return false;
+
+ newChunk = (struct SpaceChunk*) malloc(sizeof(struct SpaceChunk) +
+ CHUNK_SIZE);
+ newChunk->next = 0;
+ newChunk->used = 0;
+
+ if (!_last) {
+ _last = _first = newChunk;
+ }
+ else {
+ _last->next = newChunk;
+ _last = newChunk;
+ }
+ return true;
+}
+
+
+// DynPool
+
+DynPool::DynPool()
+{
+ _data = (char*) malloc(CHUNK_SIZE);
+ _used = 0;
+ _size = CHUNK_SIZE;
+
+ // end marker
+ *(int*)_data = 0;
+}
+
+DynPool::~DynPool()
+{
+ // we could check for correctness by iteration over all objects
+
+ ::free(_data);
+}
+
+bool DynPool::allocate(char** ptr, unsigned int size)
+{
+ // round up to multiple of 4
+ size = (size+3) & ~3;
+
+ /* need 12 bytes more:
+ * - 4 bytes for forward chain
+ * - 4 bytes for pointer to ptr
+ * - 4 bytes as end marker (not used for new object)
+ */
+ if (!ensureSpace(size + 12)) return false;
+
+ char** obj = (char**) (_data+_used);
+ obj[0] = (char*)(_data + _used + size + 8);
+ obj[1] = (char*)ptr;
+ *(int*)(_data+_used+size+8) = 0;
+ *ptr = _data+_used+8;
+
+ _used += size + 8;
+
+ return true;
+}
+
+void DynPool::free(char** ptr)
+{
+ if (!ptr ||
+ !*ptr ||
+ (*(char**)(*ptr - 4)) != (char*)ptr )
+ qFatal("Chaining error in DynPool::free");
+
+ (*(char**)(*ptr - 4)) = 0;
+ *ptr = 0;
+}
+
+bool DynPool::ensureSpace(unsigned int size)
+{
+ if (_used + size <= _size) return true;
+
+ unsigned int newsize = _size *3/2 + CHUNK_SIZE;
+ char* newdata = (char*) malloc(newsize);
+
+ unsigned int freed = 0, len;
+ char **p, **pnext, **pnew;
+
+ qDebug("DynPool::ensureSpace size: %d => %d, used %d. %p => %p",
+ _size, newsize, _used, _data, newdata);
+
+ pnew = (char**) newdata;
+ p = (char**) _data;
+ while(*p) {
+ pnext = (char**) *p;
+ len = (char*)pnext - (char*)p;
+
+ if (0) qDebug(" [%8p] Len %d (ptr %p), freed %d (=> %p)",
+ p, len, p[1], freed, pnew);
+
+ /* skip freed space ? */
+ if (p[1] == 0) {
+ freed += len;
+ p = pnext;
+ continue;
+ }
+
+ // new and old still at same address ?
+ if (pnew == p) {
+ pnew = p = pnext;
+ continue;
+ }
+
+ // copy object
+ pnew[0] = (char*)pnew + len;
+ pnew[1] = p[1];
+ memcpy((char*)pnew + 8, (char*)p + 8, len-8);
+
+ // update pointer to object
+ char** ptr = (char**) p[1];
+ if (*ptr != ((char*)p)+8)
+ qFatal("Chaining error in DynPool::ensureSpace");
+ *ptr = ((char*)pnew)+8;
+
+ pnew = (char**) pnew[0];
+ p = pnext;
+ }
+ pnew[0] = 0;
+
+ unsigned int newused = (char*)pnew - (char*)newdata;
+ qDebug("DynPool::ensureSpace size: %d => %d, used %d => %d (%d freed)",
+ _size, newsize, _used, newused, freed);
+
+ ::free(_data);
+ _data = newdata;
+ _size = newsize;
+ _used = newused;
+
+ return true;
+}
+
+/* Testing the DynPool
+int main()
+{
+ char* bufs[CHUNK_SIZE];
+ int i;
+
+ DynPool p;
+
+ for(i=0;i<CHUNK_SIZE;i++) {
+ p.allocate(bufs+i, 10+i%10);
+ if (((i%3)==0) && (i>20))
+ p.free(bufs+i-20);
+ }
+
+ for(i=0;i<CHUNK_SIZE;i++) {
+ if ((bufs[i]==0) || ((i%7)==0)) continue;
+ p.free(bufs+i);
+ }
+
+ for(i=0;i<CHUNK_SIZE;i++) {
+ if (bufs[i]) continue;
+ p.allocate(bufs+i, 10+i%10);
+ }
+}
+*/
diff --git a/kcachegrind/kcachegrind/pool.h b/kcachegrind/kcachegrind/pool.h
new file mode 100644
index 00000000..ef9a6a07
--- /dev/null
+++ b/kcachegrind/kcachegrind/pool.h
@@ -0,0 +1,107 @@
+/* This file is part of KCachegrind.
+ Copyright (C) 2002-2004 Josef Weidendorfer <Josef.Weidendorfer@gmx.de>
+
+ KCachegrind is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public
+ License as published by the Free Software Foundation, version 2.
+
+ 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; see the file COPYING. If not, write to
+ the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+*/
+
+#ifndef POOL_H
+#define POOL_H
+
+/**
+ * Pool objects: containers for many small objects.
+ */
+
+struct SpaceChunk;
+
+/**
+ * FixPool
+ *
+ * For objects with fixed size and life time
+ * ending with that of the pool.
+ */
+class FixPool
+{
+ public:
+ FixPool();
+ ~FixPool();
+
+ /**
+ * Take <size> bytes from the pool
+ */
+ void* allocate(unsigned int size);
+
+ /**
+ * Reserve space. If you call allocateReservedSpace(realsize)
+ * with realSize < reserved size directly after, you
+ * will get the same memory area.
+ */
+ void* reserve(unsigned int size);
+
+ /**
+ * Before calling this, you have to reserve at least <size> bytes
+ * with reserveSpace().
+ */
+ bool allocateReserved(unsigned int size);
+
+ private:
+ /* Checks that there is enough space in the last chunk.
+ * Returns false if this is not possible.
+ */
+ bool ensureSpace(unsigned int);
+
+ struct SpaceChunk *_first, *_last;
+ unsigned int _reservation;
+ int _count, _size;
+};
+
+/**
+ * DynPool
+ *
+ * For objects which probably need to be resized
+ * in the future. Objects also can be deleted to free up space.
+ * As objects can also be moved in a defragmentation step,
+ * access has to be done via the given pointer object.
+ */
+class DynPool
+{
+ public:
+ DynPool();
+ ~DynPool();
+
+ /**
+ * Take <size> bytes from the pool, changing <*ptr>
+ * to point to this allocated space.
+ * <*ptr> will be changed if the object is moved.
+ * Returns false if no space available.
+ */
+ bool allocate(char** ptr, unsigned int size);
+
+ /**
+ * To resize, first allocate new space, and free old
+ * afterwards.
+ */
+ void free(char** ptr);
+
+ private:
+ /* Checks that there is enough space. If not,
+ * it compactifies, possibly moving objects.
+ */
+ bool ensureSpace(unsigned int);
+
+ char* _data;
+ unsigned int _used, _size;
+};
+
+#endif // POOL_H
diff --git a/kcachegrind/kcachegrind/sourceitem.cpp b/kcachegrind/kcachegrind/sourceitem.cpp
new file mode 100644
index 00000000..dabad043
--- /dev/null
+++ b/kcachegrind/kcachegrind/sourceitem.cpp
@@ -0,0 +1,444 @@
+/* This file is part of KCachegrind.
+ Copyright (C) 2003 Josef Weidendorfer <Josef.Weidendorfer@gmx.de>
+
+ KCachegrind is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public
+ License as published by the Free Software Foundation, version 2.
+
+ 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; see the file COPYING. If not, write to
+ the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+*/
+
+/*
+ * Items of source view.
+ */
+
+#include <qpixmap.h>
+#include <qregexp.h>
+#include <qpainter.h>
+
+#include <klocale.h>
+#include <kiconloader.h>
+#include <kapplication.h>
+
+#include "configuration.h"
+#include "listutils.h"
+#include "sourceview.h"
+#include "sourceitem.h"
+
+
+// SourceItem
+
+// for source lines
+SourceItem::SourceItem(SourceView* sv, QListView* parent,
+ int fileno, unsigned int lineno,
+ bool inside, const QString& src,
+ TraceLine* line)
+ : QListViewItem(parent)
+{
+ _view = sv;
+ _lineno = lineno;
+ _fileno = fileno;
+ _inside = inside;
+ _line = line;
+ _lineCall = 0;
+ _lineJump = 0;
+
+ if (src == "...")
+ setText(0, src);
+ else
+ setText(0, QString::number(lineno));
+
+ QString s = src;
+ setText(4, s.replace( QRegExp("\t"), " " ));
+
+ updateGroup();
+ updateCost();
+}
+
+// for call lines
+SourceItem::SourceItem(SourceView* sv, QListViewItem* parent,
+ int fileno, unsigned int lineno,
+ TraceLine* line, TraceLineCall* lineCall)
+ : QListViewItem(parent)
+{
+ _view = sv;
+ _lineno = lineno;
+ _fileno = fileno;
+ _inside = true;
+ _line = line;
+ _lineCall = lineCall;
+ _lineJump = 0;
+
+ //qDebug("SourceItem: (file %d, line %d) Linecall to %s",
+ // fileno, lineno, _lineCall->call()->called()->prettyName().ascii());
+
+ SubCost cc = _lineCall->callCount();
+ QString templ = " ";
+ if (cc==0)
+ templ += i18n("Active call to '%1'");
+ else
+ templ += i18n("%n call to '%1'", "%n calls to '%1'", cc);
+
+ QString callStr = templ.arg(_lineCall->call()->calledName());
+ TraceFunction* calledF = _lineCall->call()->called();
+ calledF->addPrettyLocation(callStr);
+
+ setText(4, callStr);
+
+ updateGroup();
+ updateCost();
+}
+
+// for jump lines
+SourceItem::SourceItem(SourceView* sv, QListViewItem* parent,
+ int fileno, unsigned int lineno,
+ TraceLine* line, TraceLineJump* lineJump)
+ : QListViewItem(parent)
+{
+ _view = sv;
+ _lineno = lineno;
+ _fileno = fileno;
+ _inside = true;
+ _line = line;
+ _lineCall = 0;
+ _lineJump = lineJump;
+
+ //qDebug("SourceItem: (file %d, line %d) Linecall to %s",
+ // fileno, lineno, _lineCall->call()->called()->prettyName().ascii());
+
+ QString to;
+ if (_lineJump->lineTo()->functionSource() == _line->functionSource())
+ to = _lineJump->lineTo()->name();
+ else
+ to = _lineJump->lineTo()->prettyName();
+
+ QString jStr;
+ if (_lineJump->isCondJump())
+ jStr = i18n("Jump %1 of %2 times to %3")
+ .arg(_lineJump->followedCount().pretty())
+ .arg(_lineJump->executedCount().pretty())
+ .arg(to);
+ else
+ jStr = i18n("Jump %1 times to %2")
+ .arg(_lineJump->executedCount().pretty())
+ .arg(to);
+
+ setText(4, jStr);
+}
+
+
+void SourceItem::updateGroup()
+{
+ if (!_lineCall) return;
+
+ TraceFunction* f = _lineCall->call()->called();
+ QColor c = Configuration::functionColor(_view->groupType(), f);
+ setPixmap(4, colorPixmap(10, 10, c));
+}
+
+void SourceItem::updateCost()
+{
+ _pure = SubCost(0);
+ _pure2 = SubCost(0);
+
+ if (!_line) return;
+ if (_lineJump) return;
+
+ TraceCost* lineCost = _lineCall ? (TraceCost*)_lineCall : (TraceCost*)_line;
+
+ // don't show any cost inside of cycles
+ if (_lineCall &&
+ ((_lineCall->call()->inCycle()>0) ||
+ (_lineCall->call()->isRecursion()>0))) {
+ QString str;
+ QPixmap p;
+
+ QString icon = "undo";
+ KIconLoader* loader = KApplication::kApplication()->iconLoader();
+ p= loader->loadIcon(icon, KIcon::Small, 0,
+ KIcon::DefaultState, 0, true);
+ if (p.isNull())
+ str = i18n("(cycle)");
+
+ setText(1, str);
+ setPixmap(1, p);
+ setText(2, str);
+ setPixmap(2, p);
+ return;
+ }
+
+ TraceCost* totalCost;
+ if (Configuration::showExpanded())
+ totalCost = _line->functionSource()->function()->inclusive();
+ else
+ totalCost = _line->functionSource()->function()->data();
+
+ TraceCostType* ct = _view->costType();
+ _pure = ct ? lineCost->subCost(ct) : SubCost(0);
+ if (_pure == 0) {
+ setText(1, QString::null);
+ setPixmap(1, QPixmap());
+ }
+ else {
+ double total = totalCost->subCost(ct);
+ double pure = 100.0 * _pure / total;
+
+ if (Configuration::showPercentage())
+ setText(1, QString("%1")
+ .arg(pure, 0, 'f', Configuration::percentPrecision()));
+ else
+ setText(1, _pure.pretty());
+
+ setPixmap(1, costPixmap(ct, lineCost, total, false));
+ }
+
+ TraceCostType* ct2 = _view->costType2();
+ _pure2 = ct2 ? lineCost->subCost(ct2) : SubCost(0);
+ if (_pure2 == 0) {
+ setText(2, QString::null);
+ setPixmap(2, QPixmap());
+ }
+ else {
+ double total = totalCost->subCost(ct2);
+ double pure2 = 100.0 * _pure2 / total;
+
+ if (Configuration::showPercentage())
+ setText(2, QString("%1")
+ .arg(pure2, 0, 'f', Configuration::percentPrecision()));
+ else
+ setText(2, _pure2.pretty());
+
+ setPixmap(2, costPixmap(ct2, lineCost, total, false));
+ }
+}
+
+
+int SourceItem::compare(QListViewItem * i, int col, bool ascending ) const
+{
+ const SourceItem* si1 = this;
+ const SourceItem* si2 = (SourceItem*) i;
+
+ // we always want descending order
+ if (((col>0) && ascending) ||
+ ((col==0) && !ascending) ) {
+ si1 = si2;
+ si2 = this;
+ }
+
+ if (col==1) {
+ if (si1->_pure < si2->_pure) return -1;
+ if (si1->_pure > si2->_pure) return 1;
+ return 0;
+ }
+ if (col==2) {
+ if (si1->_pure2 < si2->_pure2) return -1;
+ if (si1->_pure2 > si2->_pure2) return 1;
+ return 0;
+ }
+ if (col==0) {
+ // Sort file numbers
+ if (si1->_fileno < si2->_fileno) return -1;
+ if (si1->_fileno > si2->_fileno) return 1;
+
+ // Sort line numbers
+ if (si1->_lineno < si2->_lineno) return -1;
+ if (si1->_lineno > si2->_lineno) return 1;
+
+ // Same line: code gets above calls/jumps
+ if (!si1->_lineCall && !si1->_lineJump) return -1;
+ if (!si2->_lineCall && !si2->_lineJump) return 1;
+
+ // calls above jumps
+ if (si1->_lineCall && !si2->_lineCall) return -1;
+ if (si2->_lineCall && !si1->_lineCall) return 1;
+
+ if (si1->_lineCall && si2->_lineCall) {
+ // Two calls: desending sort according costs
+ if (si1->_pure < si2->_pure) return 1;
+ if (si1->_pure > si2->_pure) return -1;
+
+ // Two calls: sort according function names
+ TraceFunction* f1 = si1->_lineCall->call()->called();
+ TraceFunction* f2 = si2->_lineCall->call()->called();
+ if (f1->prettyName() > f2->prettyName()) return 1;
+ return -1;
+ }
+
+ // Two jumps: descending sort according target line
+ if (si1->_lineJump->lineTo()->lineno() <
+ si2->_lineJump->lineTo()->lineno())
+ return -1;
+ if (si1->_lineJump->lineTo()->lineno() >
+ si2->_lineJump->lineTo()->lineno())
+ return 1;
+ return 0;
+ }
+ return QListViewItem::compare(i, col, ascending);
+}
+
+void SourceItem::paintCell( QPainter *p, const QColorGroup &cg,
+ int column, int width, int alignment )
+{
+ QColorGroup _cg( cg );
+
+ if ( !_inside || ((column==1) || (column==2)))
+ _cg.setColor( QColorGroup::Base, cg.button() );
+ else if ((_lineCall || _lineJump) && column>2)
+ _cg.setColor( QColorGroup::Base, cg.midlight() );
+
+ if (column == 3)
+ paintArrows(p, _cg, width);
+ else
+ QListViewItem::paintCell( p, _cg, column, width, alignment );
+}
+
+void SourceItem::setJumpArray(const QMemArray<TraceLineJump*>& a)
+{
+ _jump.duplicate(a);
+}
+
+void SourceItem::paintArrows(QPainter *p, const QColorGroup &cg, int width)
+{
+ QListView *lv = listView();
+ if ( !lv ) return;
+ SourceView* sv = (SourceView*) lv;
+
+ const BackgroundMode bgmode = lv->viewport()->backgroundMode();
+ const QColorGroup::ColorRole crole
+ = QPalette::backgroundRoleFromMode( bgmode );
+ if ( cg.brush( crole ) != lv->colorGroup().brush( crole ) )
+ p->fillRect( 0, 0, width, height(), cg.brush( crole ) );
+ else
+ sv->paintEmptyArea( p, QRect( 0, 0, width, height() ) );
+
+ if ( isSelected() && lv->allColumnsShowFocus() )
+ p->fillRect( 0, 0, width, height(), cg.brush( QColorGroup::Highlight ) );
+
+ int marg = lv->itemMargin();
+ int yy = height()/2, y1, y2;
+ QColor c;
+
+ int start = -1, end = -1;
+
+ // draw line borders, detect start/stop of a line
+ for(int i=0;i< (int)_jump.size();i++) {
+ if (_jump[i] == 0) continue;
+
+ y1 = 0;
+ y2 = height();
+ if (_lineJump &&
+ (_lineJump->lineTo() == _jump[i]->lineTo()) &&
+ (_jump[i]->lineFrom()->lineno() == _lineno)) {
+
+ if (start<0) start = i;
+ if (_lineJump == _jump[i]) {
+ if (_jump[i]->lineTo()->lineno() <= _lineno)
+ y2 = yy;
+ else
+ y1 = yy;
+ }
+ }
+ else if (!_lineJump && !_lineCall &&
+ (_jump[i]->lineTo()->lineno() == _lineno)) {
+ if (end<0) end = i;
+ if (_jump[i]->lineFrom()->lineno() < _lineno)
+ y2 = yy;
+ else
+ y1 = yy;
+ }
+
+ c = _jump[i]->isCondJump() ? red : blue;
+ p->fillRect( marg + 6*i, y1, 4, y2, c);
+ p->setPen(c.light());
+ p->drawLine( marg + 6*i, y1, marg + 6*i, y2);
+ p->setPen(c.dark());
+ p->drawLine( marg + 6*i +3, y1, marg + 6*i +3, y2);
+ }
+
+ // draw start/stop horizontal line
+ int x, y = yy-2, w, h = 4;
+ if (start >= 0) {
+ c = _jump[start]->isCondJump() ? red : blue;
+ x = marg + 6*start;
+ w = 6*(sv->arrowLevels() - start) + 10;
+ p->fillRect( x, y, w, h, c);
+ p->setPen(c.light());
+ p->drawLine(x, y, x+w-1, y);
+ p->drawLine(x, y, x, y+h-1);
+ p->setPen(c.dark());
+ p->drawLine(x+w-1, y, x+w-1, y+h-1);
+ p->drawLine(x+1, y+h-1, x+w-1, y+h-1);
+ }
+ if (end >= 0) {
+ c = _jump[end]->isCondJump() ? red : blue;
+ x = marg + 6*end;
+ w = 6*(sv->arrowLevels() - end) + 10;
+
+ QPointArray a;
+ a.putPoints(0, 7, x, y+h,
+ x,y, x+w-8, y, x+w-8, y-2,
+ x+w, yy,
+ x+w-8, y+h+2, x+w-8, y+h);
+ p->setBrush(c);
+ p->drawConvexPolygon(a);
+
+ p->setPen(c.light());
+ p->drawPolyline(a, 0, 5);
+ p->setPen(c.dark());
+ p->drawPolyline(a, 4, 2);
+ p->setPen(c.light());
+ p->drawPolyline(a, 5, 2);
+ p->setPen(c.dark());
+ p->drawPolyline(a, 6, 2);
+ }
+
+ // draw inner vertical line for start/stop
+ // this overwrites borders of horizontal line
+ for(int i=0;i< (int)_jump.size();i++) {
+ if (_jump[i] == 0) continue;
+
+ c = _jump[i]->isCondJump() ? red : blue;
+
+ if (_jump[i]->lineFrom()->lineno() == _lineno) {
+ bool drawUp = true;
+ if (_jump[i]->lineTo()->lineno() == _lineno)
+ if (start<0) drawUp = false;
+ if (_jump[i]->lineTo()->lineno() > _lineno) drawUp = false;
+ if (drawUp)
+ p->fillRect( marg + 6*i +1, 0, 2, yy, c);
+ else
+ p->fillRect( marg + 6*i +1, yy, 2, height()-yy, c);
+ }
+ else if (_jump[i]->lineTo()->lineno() == _lineno) {
+ if (end<0) end = i;
+ if (_jump[i]->lineFrom()->lineno() < _lineno)
+ p->fillRect( marg + 6*i +1, 0, 2, yy, c);
+ else
+ p->fillRect( marg + 6*i +1, yy, 2, height()-yy, c);
+ }
+ }
+
+}
+
+int SourceItem::width( const QFontMetrics& fm,
+ const QListView* lv, int c ) const
+{
+ if (c != 3) return QListViewItem::width(fm, lv, c);
+
+ SourceView* sv = (SourceView*) lv;
+ int levels = sv->arrowLevels();
+
+ if (levels == 0) return 0;
+
+ // 10 pixels for the arrow
+ return 10 + 6*levels + lv->itemMargin() * 2;
+}
+
diff --git a/kcachegrind/kcachegrind/sourceitem.h b/kcachegrind/kcachegrind/sourceitem.h
new file mode 100644
index 00000000..b1a3aec4
--- /dev/null
+++ b/kcachegrind/kcachegrind/sourceitem.h
@@ -0,0 +1,84 @@
+/* This file is part of KCachegrind.
+ Copyright (C) 2003 Josef Weidendorfer <Josef.Weidendorfer@gmx.de>
+
+ KCachegrind is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public
+ License as published by the Free Software Foundation, version 2.
+
+ 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; see the file COPYING. If not, write to
+ the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+*/
+
+/*
+ * Items of source view.
+ */
+
+#ifndef SOURCEITEM_H
+#define SOURCEITEM_H
+
+#include <qlistview.h>
+#include "tracedata.h"
+
+class SourceView;
+
+class SourceItem: public QListViewItem
+{
+public:
+ // for source lines
+ SourceItem(SourceView* sv, QListView* parent,
+ int fileno, unsigned int lineno,
+ bool inside, const QString& src,
+ TraceLine* line = 0);
+
+ // for call lines
+ SourceItem(SourceView* sv, QListViewItem* parent,
+ int fileno, unsigned int lineno,
+ TraceLine* line, TraceLineCall* lineCall);
+
+ // for jump lines
+ SourceItem(SourceView* sv, QListViewItem* parent,
+ int fileno, unsigned int lineno,
+ TraceLine* line, TraceLineJump* lineJump);
+
+ uint lineno() const { return _lineno; }
+ int fileNumber() const { return _fileno; }
+ bool inside() const { return _inside; }
+ TraceLine* line() const { return _line; }
+ TraceLineCall* lineCall() const { return _lineCall; }
+ TraceLineJump* lineJump() const { return _lineJump; }
+
+ int compare(QListViewItem * i, int col, bool ascending ) const;
+
+ void paintCell( QPainter *p, const QColorGroup &cg,
+ int column, int width, int alignment );
+ int width( const QFontMetrics& fm,
+ const QListView* lv, int c ) const;
+ void updateGroup();
+ void updateCost();
+
+ // arrow lines
+ void setJumpArray(const QMemArray<TraceLineJump*>& a);
+
+protected:
+ void paintArrows(QPainter *p, const QColorGroup &cg, int width);
+ QMemArray<TraceLineJump*> _jump;
+
+private:
+ SourceView* _view;
+ SubCost _pure, _pure2;
+ uint _lineno;
+ int _fileno; // for line sorting (even with multiple files)
+ bool _inside;
+ TraceLine* _line;
+ TraceLineJump* _lineJump;
+ TraceLineCall* _lineCall;
+};
+
+#endif
diff --git a/kcachegrind/kcachegrind/sourceview.cpp b/kcachegrind/kcachegrind/sourceview.cpp
new file mode 100644
index 00000000..e5102828
--- /dev/null
+++ b/kcachegrind/kcachegrind/sourceview.cpp
@@ -0,0 +1,813 @@
+/* This file is part of KCachegrind.
+ Copyright (C) 2003 Josef Weidendorfer <Josef.Weidendorfer@gmx.de>
+
+ KCachegrind is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public
+ License as published by the Free Software Foundation, version 2.
+
+ 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; see the file COPYING. If not, write to
+ the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+*/
+
+/*
+ * Source View
+ */
+
+#include <qdir.h>
+#include <qfile.h>
+#include <qwhatsthis.h>
+#include <qpopupmenu.h>
+#include <klocale.h>
+#include <kdebug.h>
+
+#include "configuration.h"
+#include "sourceitem.h"
+#include "sourceview.h"
+
+
+//
+// SourceView
+//
+
+
+SourceView::SourceView(TraceItemView* parentView,
+ QWidget* parent, const char* name)
+ : QListView(parent, name), TraceItemView(parentView)
+{
+ _inSelectionUpdate = false;
+
+ _arrowLevels = 0;
+ _lowList.setSortLow(true);
+ _highList.setSortLow(false);
+
+ addColumn( i18n( "#" ) );
+ addColumn( i18n( "Cost" ) );
+ addColumn( i18n( "Cost 2" ) );
+ addColumn( "" );
+ addColumn( i18n( "Source (unknown)" ) );
+
+ setAllColumnsShowFocus(true);
+ setColumnAlignment(0, Qt::AlignRight);
+ setColumnAlignment(1, Qt::AlignRight);
+ setColumnAlignment(2, Qt::AlignRight);
+ setResizeMode(QListView::LastColumn);
+
+ connect(this,
+ SIGNAL(contextMenuRequested(QListViewItem*, const QPoint &, int)),
+ SLOT(context(QListViewItem*, const QPoint &, int)));
+
+ connect(this,
+ SIGNAL(selectionChanged(QListViewItem*)),
+ SLOT(selectedSlot(QListViewItem*)));
+
+ connect(this,
+ SIGNAL(doubleClicked(QListViewItem*)),
+ SLOT(activatedSlot(QListViewItem*)));
+
+ connect(this,
+ SIGNAL(returnPressed(QListViewItem*)),
+ SLOT(activatedSlot(QListViewItem*)));
+
+ QWhatsThis::add( this, whatsThis());
+}
+
+void SourceView::paintEmptyArea( QPainter * p, const QRect & r)
+{
+ QListView::paintEmptyArea(p, r);
+}
+
+
+QString SourceView::whatsThis() const
+{
+ return i18n( "<b>Annotated Source</b>"
+ "<p>The annotated source list shows the "
+ "source lines of the current selected function "
+ "together with (self) cost spent while executing the "
+ "code of this source line. If there was a call "
+ "in a source line, lines with details on the "
+ "call happening are inserted into the source: "
+ "the cost spent inside of the call, the "
+ "number of calls happening, and the call destination.</p>"
+ "<p>Select a inserted call information line to "
+ "make the destination function current.</p>");
+}
+
+void SourceView::context(QListViewItem* i, const QPoint & p, int c)
+{
+ QPopupMenu popup;
+
+ // Menu entry:
+ TraceLineCall* lc = i ? ((SourceItem*) i)->lineCall() : 0;
+ TraceLineJump* lj = i ? ((SourceItem*) i)->lineJump() : 0;
+ TraceFunction* f = lc ? lc->call()->called() : 0;
+ TraceLine* line = lj ? lj->lineTo() : 0;
+
+ if (f) {
+ QString name = f->name();
+ if ((int)name.length()>Configuration::maxSymbolLength())
+ name = name.left(Configuration::maxSymbolLength()) + "...";
+ popup.insertItem(i18n("Go to '%1'").arg(name), 93);
+ popup.insertSeparator();
+ }
+ else if (line) {
+ popup.insertItem(i18n("Go to Line %1").arg(line->name()), 93);
+ popup.insertSeparator();
+ }
+
+ if ((c == 1) || (c == 2)) {
+ addCostMenu(&popup);
+ popup.insertSeparator();
+ }
+ addGoMenu(&popup);
+
+ int r = popup.exec(p);
+ if (r == 93) {
+ if (f) activated(f);
+ if (line) activated(line);
+ }
+}
+
+
+void SourceView::selectedSlot(QListViewItem * i)
+{
+ if (!i) return;
+ // programatically selected items are not signalled
+ if (_inSelectionUpdate) return;
+
+ TraceLineCall* lc = ((SourceItem*) i)->lineCall();
+ TraceLineJump* lj = ((SourceItem*) i)->lineJump();
+
+ if (!lc && !lj) {
+ TraceLine* l = ((SourceItem*) i)->line();
+ if (l) {
+ _selectedItem = l;
+ selected(l);
+ }
+ return;
+ }
+
+ TraceFunction* f = lc ? lc->call()->called() : 0;
+ if (f) {
+ _selectedItem = f;
+ selected(f);
+ }
+ else {
+ TraceLine* line = lj ? lj->lineTo() : 0;
+ if (line) {
+ _selectedItem = line;
+ selected(line);
+ }
+ }
+}
+
+void SourceView::activatedSlot(QListViewItem * i)
+{
+ if (!i) return;
+ TraceLineCall* lc = ((SourceItem*) i)->lineCall();
+ TraceLineJump* lj = ((SourceItem*) i)->lineJump();
+
+ if (!lc && !lj) {
+ TraceLine* l = ((SourceItem*) i)->line();
+ if (l) activated(l);
+ return;
+ }
+
+ TraceFunction* f = lc ? lc->call()->called() : 0;
+ if (f) activated(f);
+ else {
+ TraceLine* line = lj ? lj->lineTo() : 0;
+ if (line) activated(line);
+ }
+}
+
+TraceItem* SourceView::canShow(TraceItem* i)
+{
+ TraceItem::CostType t = i ? i->type() : TraceItem::NoCostType;
+ TraceFunction* f = 0;
+
+ switch(t) {
+ case TraceItem::Function:
+ f = (TraceFunction*) i;
+ break;
+
+ case TraceItem::Instr:
+ f = ((TraceInstr*)i)->function();
+ select(i);
+ break;
+
+ case TraceItem::Line:
+ f = ((TraceLine*)i)->functionSource()->function();
+ select(i);
+ break;
+
+ default:
+ break;
+ }
+
+ return f;
+}
+
+void SourceView::doUpdate(int changeType)
+{
+ // Special case ?
+ if (changeType == selectedItemChanged) {
+
+ if (!_selectedItem) {
+ clearSelection();
+ return;
+ }
+
+ TraceLine* sLine = 0;
+ if (_selectedItem->type() == TraceItem::Line)
+ sLine = (TraceLine*) _selectedItem;
+ if (_selectedItem->type() == TraceItem::Instr)
+ sLine = ((TraceInstr*)_selectedItem)->line();
+
+ SourceItem* si = (SourceItem*)QListView::selectedItem();
+ if (si) {
+ if (si->line() == sLine) return;
+ if (si->lineCall() &&
+ (si->lineCall()->call()->called() == _selectedItem)) return;
+ }
+
+ QListViewItem *item, *item2;
+ for (item = firstChild();item;item = item->nextSibling()) {
+ si = (SourceItem*)item;
+ if (si->line() == sLine) {
+ ensureItemVisible(item);
+ _inSelectionUpdate = true;
+ setCurrentItem(item);
+ _inSelectionUpdate = false;
+ break;
+ }
+ item2 = item->firstChild();
+ for (;item2;item2 = item2->nextSibling()) {
+ si = (SourceItem*)item2;
+ if (!si->lineCall()) continue;
+ if (si->lineCall()->call()->called() == _selectedItem) {
+ ensureItemVisible(item2);
+ _inSelectionUpdate = true;
+ setCurrentItem(item2);
+ _inSelectionUpdate = false;
+ break;
+ }
+ }
+ if (item2) break;
+ }
+ return;
+ }
+
+ if (changeType == groupTypeChanged) {
+ QListViewItem *item, *item2;
+ for (item = firstChild();item;item = item->nextSibling())
+ for (item2 = item->firstChild();item2;item2 = item2->nextSibling())
+ ((SourceItem*)item2)->updateGroup();
+ }
+
+ refresh();
+}
+
+void SourceView::refresh()
+{
+ clear();
+ setColumnWidth(0, 20);
+ setColumnWidth(1, 50);
+ setColumnWidth(2, _costType2 ? 50:0);
+ setColumnWidth(3, 0); // arrows, defaults to invisible
+ setSorting(0); // always reset to line number sort
+ if (_costType)
+ setColumnText(1, _costType->name());
+ if (_costType2)
+ setColumnText(2, _costType2->name());
+
+ _arrowLevels = 0;
+
+ if (!_data || !_activeItem) {
+ setColumnText(4, i18n("(No Source)"));
+ return;
+ }
+
+ TraceItem::CostType t = _activeItem->type();
+ TraceFunction* f = 0;
+ if (t == TraceItem::Function) f = (TraceFunction*) _activeItem;
+ if (t == TraceItem::Instr) {
+ f = ((TraceInstr*)_activeItem)->function();
+ if (!_selectedItem) _selectedItem = _activeItem;
+ }
+ if (t == TraceItem::Line) {
+ f = ((TraceLine*)_activeItem)->functionSource()->function();
+ if (!_selectedItem) _selectedItem = _activeItem;
+ }
+
+ if (!f) return;
+
+ // Allow resizing of column 2
+ setColumnWidthMode(2, QListView::Maximum);
+
+ TraceFunctionSource* mainSF = f->sourceFile();
+
+ // skip first source if there's no debug info and there are more sources
+ // (this is for a bug in GCC 2.95.x giving unknown source for prologs)
+ if (mainSF &&
+ (mainSF->firstLineno() == 0) &&
+ (mainSF->lastLineno() == 0) &&
+ (f->sourceFiles().count()>1) ) {
+ // skip
+ }
+ else
+ fillSourceFile(mainSF, 0);
+
+ TraceFunctionSource* sf;
+ int fileno = 1;
+ TraceFunctionSourceList l = f->sourceFiles();
+ for (sf=l.first();sf;sf=l.next(), fileno++)
+ if (sf != mainSF)
+ fillSourceFile(sf, fileno);
+
+ if (!_costType2) {
+ setColumnWidthMode(2, QListView::Manual);
+ setColumnWidth(2, 0);
+ }
+}
+
+
+// helper for fillSourceList:
+// search recursive for a file, starting from a base dir
+static bool checkFileExistance(QString& dir, const QString& name)
+{
+ // we leave this in...
+ qDebug("Checking %s/%s", dir.ascii(), name.ascii());
+
+ if (QFile::exists(dir + "/" + name)) return true;
+
+ // check in subdirectories
+ QDir d(dir);
+ d.setFilter( QDir::Dirs | QDir::NoSymLinks );
+ d.setSorting( QDir::Unsorted );
+ QStringList subdirs = d.entryList();
+ QStringList::Iterator it =subdirs.begin();
+ for(; it != subdirs.end(); ++it ) {
+ if (*it == "." || *it == ".." || *it == "CVS") continue;
+
+ dir = d.filePath(*it);
+ if (checkFileExistance(dir, name)) return true;
+ }
+ return false;
+}
+
+
+void SourceView::updateJumpArray(uint lineno, SourceItem* si,
+ bool ignoreFrom, bool ignoreTo)
+{
+ TraceLineJump* lj;
+ uint lowLineno, highLineno;
+ int iEnd = -1, iStart = -1;
+
+ if (0) qDebug("updateJumpArray(line %d, jump to %s)",
+ lineno,
+ si->lineJump()
+ ? si->lineJump()->lineTo()->name().ascii() : "?" );
+
+
+ lj=_lowList.current();
+ while(lj) {
+ lowLineno = lj->lineFrom()->lineno();
+ if (lj->lineTo()->lineno() < lowLineno)
+ lowLineno = lj->lineTo()->lineno();
+
+ if (lowLineno > lineno) break;
+
+ if (ignoreFrom && (lowLineno < lj->lineTo()->lineno())) break;
+ if (ignoreTo && (lowLineno < lj->lineFrom()->lineno())) break;
+
+ if (si->lineJump() && (lj != si->lineJump())) break;
+
+ int asize = (int)_jump.size();
+#if 0
+ for(iStart=0;iStart<asize;iStart++)
+ if (_jump[iStart] &&
+ (_jump[iStart]->lineTo() == lj->lineTo())) break;
+#else
+ iStart = asize;
+#endif
+
+ if (iStart == asize) {
+ for(iStart=0;iStart<asize;iStart++)
+ if (_jump[iStart] == 0) break;
+
+ if (iStart== asize) {
+ asize++;
+ _jump.resize(asize);
+ if (asize > _arrowLevels) _arrowLevels = asize;
+ }
+
+ if (0) qDebug(" start %d (%s to %s)",
+ iStart,
+ lj->lineFrom()->name().ascii(),
+ lj->lineTo()->name().ascii());
+
+ _jump[iStart] = lj;
+ }
+ lj=_lowList.next();
+ }
+
+ si->setJumpArray(_jump);
+
+ lj=_highList.current();
+ while(lj) {
+ highLineno = lj->lineFrom()->lineno();
+ if (lj->lineTo()->lineno() > highLineno) {
+ highLineno = lj->lineTo()->lineno();
+ if (ignoreTo) break;
+ }
+ else if (ignoreFrom) break;
+
+ if (highLineno > lineno) break;
+
+ for(iEnd=0;iEnd< (int)_jump.size();iEnd++)
+ if (_jump[iEnd] == lj) break;
+ if (iEnd == (int)_jump.size()) {
+ qDebug("LineView: no jump start for end at %x ?", highLineno);
+ iEnd = -1;
+ }
+ lj=_highList.next();
+
+ if (0 && (iEnd>=0))
+ qDebug(" end %d (%s to %s)",
+ iEnd,
+ _jump[iEnd]->lineFrom()->name().ascii(),
+ _jump[iEnd]->lineTo()->name().ascii());
+
+ if (0 && lj) qDebug("next end: %s to %s",
+ lj->lineFrom()->name().ascii(),
+ lj->lineTo()->name().ascii());
+
+ if (highLineno > lineno)
+ break;
+ else {
+ if (iEnd>=0) _jump[iEnd] = 0;
+ iEnd = -1;
+ }
+ }
+ if (iEnd>=0) _jump[iEnd] = 0;
+}
+
+
+/* If sourceList is empty we set the source file name into the header,
+ * else this code is of a inlined function, and we add "inlined from..."
+ */
+void SourceView::fillSourceFile(TraceFunctionSource* sf, int fileno)
+{
+ if (!sf) return;
+
+ if (0) qDebug("Selected Item %s",
+ _selectedItem ? _selectedItem->name().ascii() : "(none)");
+
+ TraceLineMap::Iterator lineIt, lineItEnd;
+ int nextCostLineno = 0, lastCostLineno = 0;
+
+ bool validSourceFile = (!sf->file()->name().isEmpty());
+
+ TraceLine* sLine = 0;
+ if (_selectedItem) {
+ if (_selectedItem->type() == TraceItem::Line)
+ sLine = (TraceLine*) _selectedItem;
+ if (_selectedItem->type() == TraceItem::Instr)
+ sLine = ((TraceInstr*)_selectedItem)->line();
+ }
+
+ if (validSourceFile) {
+ TraceLineMap* lineMap = sf->lineMap();
+ if (lineMap) {
+ lineIt = lineMap->begin();
+ lineItEnd = lineMap->end();
+ // get first line with cost of selected type
+ while(lineIt != lineItEnd) {
+ if (&(*lineIt) == sLine) break;
+ if ((*lineIt).hasCost(_costType)) break;
+ if (_costType2 && (*lineIt).hasCost(_costType2)) break;
+ ++lineIt;
+ }
+
+ nextCostLineno = (lineIt == lineItEnd) ? 0 : (*lineIt).lineno();
+ if (nextCostLineno<0) {
+ kdError() << "SourceView::fillSourceFile: Negative line number "
+ << nextCostLineno << endl
+ << " Function '" << sf->function()->name() << "'" << endl
+ << " File '" << sf->file()->name() << "'" << endl;
+ nextCostLineno = 0;
+ }
+
+ }
+
+ if (nextCostLineno == 0) {
+ new SourceItem(this, this, fileno, 0, false,
+ i18n("There is no cost of current selected type associated"));
+ new SourceItem(this, this, fileno, 1, false,
+ i18n("with any source line of this function in file"));
+ new SourceItem(this, this, fileno, 2, false,
+ QString(" '%1'").arg(sf->function()->prettyName()));
+ new SourceItem(this, this, fileno, 3, false,
+ i18n("Thus, no annotated source can be shown."));
+ return;
+ }
+ }
+
+ QString filename = sf->file()->shortName();
+ QString dir = sf->file()->directory();
+ if (!dir.isEmpty())
+ filename = dir + "/" + filename;
+
+ if (nextCostLineno>0) {
+ // we have debug info... search for source file
+ if (!QFile::exists(filename)) {
+ QStringList list = Configuration::sourceDirs(_data,
+ sf->function()->object());
+ QStringList::Iterator it;
+
+ for ( it = list.begin(); it != list.end(); ++it ) {
+ dir = *it;
+ if (checkFileExistance(dir, sf->file()->shortName())) break;
+ }
+
+ if (it == list.end())
+ nextCostLineno = 0;
+ else {
+ filename = dir + "/" + sf->file()->shortName();
+ // no need to search again
+ sf->file()->setDirectory(dir);
+ }
+ }
+ }
+
+ // do it here, because the source directory could have been set before
+ if (childCount()==0) {
+ setColumnText(4, validSourceFile ?
+ i18n("Source ('%1')").arg(filename) :
+ i18n("Source (unknown)"));
+ }
+ else {
+ new SourceItem(this, this, fileno, 0, true,
+ validSourceFile ?
+ i18n("--- Inlined from '%1' ---").arg(filename) :
+ i18n("--- Inlined from unknown source ---"));
+ }
+
+ if (nextCostLineno == 0) {
+ new SourceItem(this, this, fileno, 0, false,
+ i18n("There is no source available for the following function:"));
+ new SourceItem(this, this, fileno, 1, false,
+ QString(" '%1'").arg(sf->function()->prettyName()));
+ if (sf->file()->name().isEmpty()) {
+ new SourceItem(this, this, fileno, 2, false,
+ i18n("This is because no debug information is present."));
+ new SourceItem(this, this, fileno, 3, false,
+ i18n("Recompile source and redo the profile run."));
+ if (sf->function()->object()) {
+ new SourceItem(this, this, fileno, 4, false,
+ i18n("The function is located in this ELF object:"));
+ new SourceItem(this, this, fileno, 5, false,
+ QString(" '%1'")
+ .arg(sf->function()->object()->prettyName()));
+ }
+ }
+ else {
+ new SourceItem(this, this, fileno, 2, false,
+ i18n("This is because its source file cannot be found:"));
+ new SourceItem(this, this, fileno, 3, false,
+ QString(" '%1'").arg(sf->file()->name()));
+ new SourceItem(this, this, fileno, 4, false,
+ i18n("Add the folder of this file to the source folder list."));
+ new SourceItem(this, this, fileno, 5, false,
+ i18n("The list can be found in the configuration dialog."));
+ }
+ return;
+ }
+
+
+ // initialisation for arrow drawing
+ // create sorted list of jumps (for jump arrows)
+ TraceLineMap::Iterator it = lineIt, nextIt;
+ _lowList.clear();
+ _highList.clear();
+ while(1) {
+
+ nextIt = it;
+ ++nextIt;
+ while(nextIt != lineItEnd) {
+ if (&(*nextIt) == sLine) break;
+ if ((*nextIt).hasCost(_costType)) break;
+ if (_costType2 && (*nextIt).hasCost(_costType2)) break;
+ ++nextIt;
+ }
+
+ TraceLineJumpList jlist = (*it).lineJumps();
+ TraceLineJump* lj;
+ for (lj=jlist.first();lj;lj=jlist.next()) {
+ if (lj->executedCount()==0) continue;
+ // skip jumps to next source line with cost
+ //if (lj->lineTo() == &(*nextIt)) continue;
+
+ _lowList.append(lj);
+ _highList.append(lj);
+ }
+ it = nextIt;
+ if (it == lineItEnd) break;
+ }
+ _lowList.sort();
+ _highList.sort();
+ _lowList.first(); // iterators to list start
+ _highList.first();
+ _jump.resize(0);
+
+
+ char buf[256];
+ bool inside = false, skipLineWritten = true;
+ int readBytes;
+ int fileLineno = 0;
+ SubCost most = 0;
+
+ TraceLine* currLine;
+ SourceItem *si, *si2, *item = 0, *first = 0, *selected = 0;
+ QFile file(filename);
+ if (!file.open(IO_ReadOnly)) return;
+ while (1) {
+ readBytes=file.readLine(buf, sizeof( buf ));
+ if (readBytes<=0) {
+ // for nice empty 4 lines after function with EOF
+ buf[0] = 0;
+ }
+
+ if (readBytes >= (int) sizeof( buf )) {
+ qDebug("%s:%d Line too long\n",
+ sf->file()->name().ascii(), fileLineno);
+ }
+ else if ((readBytes>0) && (buf[readBytes-1] == '\n'))
+ buf[readBytes-1] = 0;
+
+
+ // keep fileLineno inside [lastCostLineno;nextCostLineno]
+ fileLineno++;
+ if (fileLineno == nextCostLineno) {
+ currLine = &(*lineIt);
+
+ // get next line with cost of selected type
+ ++lineIt;
+ while(lineIt != lineItEnd) {
+ if (&(*lineIt) == sLine) break;
+ if ((*lineIt).hasCost(_costType)) break;
+ if (_costType2 && (*lineIt).hasCost(_costType2)) break;
+ ++lineIt;
+ }
+
+ lastCostLineno = nextCostLineno;
+ nextCostLineno = (lineIt == lineItEnd) ? 0 : (*lineIt).lineno();
+ }
+ else
+ currLine = 0;
+
+ // update inside
+ if (!inside) {
+ if (currLine) inside = true;
+ }
+ else {
+ if ( (fileLineno > lastCostLineno) &&
+ ((nextCostLineno == 0) ||
+ (fileLineno < nextCostLineno - Configuration::noCostInside()) ))
+ inside = false;
+ }
+
+ int context = Configuration::context();
+
+ if ( ((lastCostLineno==0) || (fileLineno > lastCostLineno + context)) &&
+ ((nextCostLineno==0) || (fileLineno < nextCostLineno - context))) {
+ if (lineIt == lineItEnd) break;
+
+ if (!skipLineWritten) {
+ skipLineWritten = true;
+ // a "skipping" line: print "..." instead of a line number
+ strcpy(buf,"...");
+ }
+ else
+ continue;
+ }
+ else
+ skipLineWritten = false;
+
+ si = new SourceItem(this, this,
+ fileno, fileLineno, inside, QString(buf),
+ currLine);
+
+ if (!currLine) continue;
+
+ if (!selected && (currLine == sLine)) selected = si;
+ if (!first) first = si;
+
+ if (currLine->subCost(_costType) > most) {
+ item = si;
+ most = currLine->subCost(_costType);
+ }
+
+ si->setOpen(true);
+ TraceLineCallList list = currLine->lineCalls();
+ TraceLineCall* lc;
+ for (lc=list.first();lc;lc=list.next()) {
+ if ((lc->subCost(_costType)==0) &&
+ (lc->subCost(_costType2)==0)) continue;
+
+ if (lc->subCost(_costType) > most) {
+ item = si;
+ most = lc->subCost(_costType);
+ }
+
+ si2 = new SourceItem(this, si, fileno, fileLineno, currLine, lc);
+
+ if (!selected && (lc->call()->called() == _selectedItem))
+ selected = si2;
+ }
+
+ TraceLineJumpList jlist = currLine->lineJumps();
+ TraceLineJump* lj;
+ for (lj=jlist.first();lj;lj=jlist.next()) {
+ if (lj->executedCount()==0) continue;
+
+ new SourceItem(this, si, fileno, fileLineno, currLine, lj);
+ }
+ }
+
+ if (selected) item = selected;
+ if (item) first = item;
+ if (first) {
+ ensureItemVisible(first);
+ _inSelectionUpdate = true;
+ setCurrentItem(first);
+ _inSelectionUpdate = false;
+ }
+
+ file.close();
+
+ // for arrows: go down the list according to list sorting
+ sort();
+ QListViewItem *item1, *item2;
+ for (item1=firstChild();item1;item1 = item1->nextSibling()) {
+ si = (SourceItem*)item1;
+ updateJumpArray(si->lineno(), si, true, false);
+
+ for (item2=item1->firstChild();item2;item2 = item2->nextSibling()) {
+ si2 = (SourceItem*)item2;
+ if (si2->lineJump())
+ updateJumpArray(si->lineno(), si2, false, true);
+ else
+ si2->setJumpArray(_jump);
+ }
+ }
+
+ if (arrowLevels())
+ setColumnWidth(3, 10 + 6*arrowLevels() + itemMargin() * 2);
+ else
+ setColumnWidth(3, 0);
+}
+
+
+void SourceView::updateSourceItems()
+{
+ setColumnWidth(1, 50);
+ setColumnWidth(2, _costType2 ? 50:0);
+ // Allow resizing of column 2
+ setColumnWidthMode(2, QListView::Maximum);
+
+ if (_costType)
+ setColumnText(1, _costType->name());
+ if (_costType2)
+ setColumnText(2, _costType2->name());
+
+ SourceItem* si;
+ QListViewItem* item = firstChild();
+ for (;item;item = item->nextSibling()) {
+ si = (SourceItem*)item;
+ TraceLine* l = si->line();
+ if (!l) continue;
+
+ si->updateCost();
+
+ QListViewItem *next, *i = si->firstChild();
+ for (;i;i = next) {
+ next = i->nextSibling();
+ ((SourceItem*)i)->updateCost();
+ }
+ }
+
+ if (!_costType2) {
+ setColumnWidthMode(2, QListView::Manual);
+ setColumnWidth(2, 0);
+ }
+}
+
+#include "sourceview.moc"
diff --git a/kcachegrind/kcachegrind/sourceview.h b/kcachegrind/kcachegrind/sourceview.h
new file mode 100644
index 00000000..4836032a
--- /dev/null
+++ b/kcachegrind/kcachegrind/sourceview.h
@@ -0,0 +1,70 @@
+/* This file is part of KCachegrind.
+ Copyright (C) 2003 Josef Weidendorfer <Josef.Weidendorfer@gmx.de>
+
+ KCachegrind is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public
+ License as published by the Free Software Foundation, version 2.
+
+ 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; see the file COPYING. If not, write to
+ the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+*/
+
+/*
+ * Source View
+ */
+
+#ifndef SOURCEVIEW_H
+#define SOURCEVIEW_H
+
+#include <qlistview.h>
+#include "traceitemview.h"
+
+class SourceItem;
+
+class SourceView : public QListView, public TraceItemView
+{
+ friend class SourceItem;
+
+ Q_OBJECT
+
+public:
+ SourceView(TraceItemView* parentView,
+ QWidget* parent = 0, const char* name = 0);
+
+ QWidget* widget() { return this; }
+ QString whatsThis() const;
+
+protected:
+ int arrowLevels() { return _arrowLevels; }
+ void paintEmptyArea( QPainter *, const QRect & );
+
+private slots:
+ void context(QListViewItem*, const QPoint &, int);
+ void selectedSlot(QListViewItem *);
+ void activatedSlot(QListViewItem *);
+
+private:
+ TraceItem* canShow(TraceItem*);
+ void doUpdate(int);
+ void refresh();
+ void updateJumpArray(uint,SourceItem*,bool,bool);
+ void fillSourceFile(TraceFunctionSource*, int);
+ void updateSourceItems();
+
+ bool _inSelectionUpdate;
+
+ // arrows
+ int _arrowLevels;
+ // temporary needed on creation...
+ QMemArray<TraceLineJump*> _jump;
+ TraceLineJumpList _lowList, _highList;
+};
+
+#endif
diff --git a/kcachegrind/kcachegrind/stackbrowser.cpp b/kcachegrind/kcachegrind/stackbrowser.cpp
new file mode 100644
index 00000000..783edf99
--- /dev/null
+++ b/kcachegrind/kcachegrind/stackbrowser.cpp
@@ -0,0 +1,417 @@
+/* This file is part of KCachegrind.
+ Copyright (C) 2003 Josef Weidendorfer <Josef.Weidendorfer@gmx.de>
+
+ KCachegrind is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public
+ License as published by the Free Software Foundation, version 2.
+
+ 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; see the file COPYING. If not, write to
+ the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+*/
+
+#include <qlistview.h>
+
+#include "stackbrowser.h"
+
+// Stack
+
+Stack::Stack(TraceFunction* top, TraceCallList calls)
+{
+ _refCount = 0;
+ _top = top;
+ _calls = calls;
+
+ extendBottom();
+}
+
+Stack::Stack(TraceFunction* f)
+{
+ _refCount = 0;
+ _top = f;
+
+ extendBottom();
+ extendTop();
+}
+
+void Stack::extendBottom()
+{
+ TraceCallList l;
+ TraceCall *c, *call;
+ SubCost most;
+ TraceFunction* f;
+
+ if (_calls.last())
+ f = _calls.last()->called();
+ else
+ f = _top;
+
+ if (!f) return;
+ // don't follow calls from cycles
+ if (f->cycle() == f) return;
+
+
+ int max = 30;
+
+ // try to extend to lower stack frames
+ while (f && (max-- >0)) {
+ l = f->callings();
+ call = 0;
+ most = 0;
+ for (c=l.first();c;c=l.next()) {
+ // no cycle calls in stack: could be deleted without notice
+ if (c->called()->cycle() == c->called()) continue;
+ // no simple recursions
+ if (c->called() == _top) continue;
+
+ if (c->called()->name().isEmpty()) continue;
+ SubCost sc = c->subCost(0); // FIXME
+ if (sc == 0) continue;
+
+ if (sc > most) {
+ most = sc;
+ call = c;
+ }
+ }
+ if (!call)
+ break;
+
+ _calls.append(call);
+ f = call->called();
+ }
+}
+
+
+void Stack::extendTop()
+{
+ TraceCallList l;
+ TraceCall *c, *call;
+ SubCost most;
+
+ int max = 10;
+
+ // don't follow calls from cycles
+ if (_top->cycle() == _top) return;
+
+ // try to extend to upper stack frames
+ while (_top && (max-- >0)) {
+ l = _top->callers();
+ call = 0;
+ most = 0;
+ for (c=l.first();c;c=l.next()) {
+ // no cycle calls in stack: could be deleted without notice
+ if (c->caller()->cycle() == c->caller()) continue;
+ // no simple recursions
+ if (c->caller() == _top) continue;
+
+ if (c->caller()->name().isEmpty()) continue;
+ SubCost sc = c->subCost(0); // FIXME
+ if (sc == 0) continue;
+
+ if (sc > most) {
+ most = sc;
+ call = c;
+ }
+ }
+ if (!call)
+ break;
+
+ _calls.prepend(call);
+ _top = call->caller();
+ }
+}
+
+TraceFunction* Stack::caller(TraceFunction* fn, bool extend)
+{
+ TraceFunction* f;
+ TraceCall* c;
+
+ if (extend && (_top == fn)) {
+ // extend at top
+ extendTop();
+ f = _top;
+ }
+
+ for (c=_calls.first();c;c=_calls.next()) {
+ f = c->called();
+ if (f == fn)
+ return c->caller();
+ }
+ return 0;
+}
+
+TraceFunction* Stack::called(TraceFunction* fn, bool extend)
+{
+ TraceFunction* f;
+ TraceCall* c;
+
+ for (c=_calls.first();c;c=_calls.next()) {
+ f = c->caller();
+ if (f == fn)
+ return c->called();
+ }
+
+ if (extend && (c->called() == fn)) {
+ // extend at bottom
+ extendBottom();
+
+ // and search again
+ for (c=_calls.first();c;c=_calls.next()) {
+ f = c->caller();
+ if (f == fn)
+ return c->called();
+ }
+ }
+
+ return 0;
+}
+
+bool Stack::contains(TraceFunction* fn)
+{
+ // cycles are listed on there own
+ if (fn->cycle() == fn) return false;
+ if (_top->cycle() == _top) return false;
+
+ if (fn == _top)
+ return true;
+
+ TraceFunction* f = _top;
+ TraceCall* c;
+
+ for (c=_calls.first();c;c=_calls.next()) {
+ f = c->called();
+ if (f == fn)
+ return true;
+ }
+
+ TraceCallList l;
+
+ // try to extend at bottom (even if callCount 0)
+ l = f->callings();
+ for (c=l.first();c;c=l.next()) {
+ f = c->called();
+ if (f == fn)
+ break;
+ }
+
+ if (c) {
+ _calls.append(c);
+
+ // extend at bottom after found one
+ extendBottom();
+ return true;
+ }
+
+ // try to extend at top (even if callCount 0)
+ l = _top->callers();
+ for (c=l.first();c;c=l.next()) {
+ f = c->caller();
+ if (f == fn)
+ break;
+ }
+
+ if (c) {
+ _calls.prepend(c);
+
+ // extend at top after found one
+ extendTop();
+ return true;
+ }
+
+ return false;
+}
+
+Stack* Stack::split(TraceFunction* f)
+{
+ TraceCallList calls = _calls;
+ TraceCall *c, *c2;
+
+ // cycles are listed on there own
+ if (f->cycle() == f) return 0;
+ if (_top->cycle() == _top) return false;
+
+ for (c=calls.first();c;c=calls.next()) {
+ TraceCallList l = c->called()->callings();
+ for (c2=l.first();c2;c2=l.next()) {
+ if (c2 == c) continue;
+ if (c2->called() == f)
+ break;
+ }
+ if (c2)
+ break;
+ }
+
+ if (!c)
+ return 0;
+
+ // remove bottom part
+ calls.last();
+ while (calls.current() && calls.current()!=c)
+ calls.removeLast();
+
+ calls.append(c2);
+ return new Stack(_top, calls );
+}
+
+QString Stack::toString()
+{
+ QString res = _top->name();
+ TraceCall *c;
+ for (c=_calls.first();c;c=_calls.next())
+ res += "\n > " + c->called()->name();
+
+ return res;
+}
+
+
+// HistoryItem
+
+HistoryItem::HistoryItem(Stack* stack, TraceFunction* function)
+{
+ _stack = stack;
+ _function = function;
+ if (_stack)
+ _stack->ref();
+
+ _last = 0;
+ _next = 0;
+
+/*
+ qDebug("New Stack History Item (sRef %d): %s\n %s",
+ _stack->refCount(), _function->name().ascii(),
+ _stack->toString().ascii());
+*/
+}
+
+HistoryItem::~HistoryItem()
+{
+ if (0) qDebug("Deleting Stack History Item (sRef %d): %s",
+ _stack->refCount(),
+ _function->name().ascii());
+
+ if (_last)
+ _last->_next = _next;
+ if (_stack) {
+ if (_stack->deref() == 0)
+ delete _stack;
+ }
+}
+
+
+// StackBrowser
+
+StackBrowser::StackBrowser()
+{
+ _current = 0;
+}
+
+StackBrowser::~StackBrowser()
+{
+ delete _current;
+}
+
+HistoryItem* StackBrowser::select(TraceFunction* f)
+{
+ if (!_current) {
+ Stack* s = new Stack(f);
+ _current = new HistoryItem(s, f);
+ }
+ else if (_current->function() != f) {
+ // make current item the last one
+ HistoryItem* item = _current;
+ if (item->next()) {
+ item = item->next();
+ item->last()->setNext(0);
+
+ while (item->next()) {
+ item = item->next();
+ delete item->last();
+ }
+ delete item;
+ }
+
+ Stack* s = _current->stack();
+ if (!s->contains(f)) {
+ s = s->split(f);
+ if (!s)
+ s = new Stack(f);
+ }
+
+ item = _current;
+ _current = new HistoryItem(s, f);
+ item->setNext(_current);
+ _current->setLast(item);
+ }
+
+ // qDebug("Selected %s in StackBrowser", f->name().ascii());
+
+ return _current;
+}
+
+HistoryItem* StackBrowser::goBack()
+{
+ if (_current && _current->last())
+ _current = _current->last();
+
+ return _current;
+}
+
+HistoryItem* StackBrowser::goForward()
+{
+ if (_current && _current->next())
+ _current = _current->next();
+
+ return _current;
+}
+
+HistoryItem* StackBrowser::goUp()
+{
+ if (_current) {
+ TraceFunction* f = _current->stack()->caller(_current->function(), true);
+ if (f)
+ _current = select(f);
+ }
+
+ return _current;
+}
+
+HistoryItem* StackBrowser::goDown()
+{
+ if (_current) {
+ TraceFunction* f = _current->stack()->called(_current->function(), true);
+ if (f)
+ _current = select(f);
+ }
+
+ return _current;
+}
+
+bool StackBrowser::canGoBack()
+{
+ return _current && _current->last();
+}
+
+bool StackBrowser::canGoForward()
+{
+ return _current && _current->next();
+}
+
+bool StackBrowser::canGoUp()
+{
+ if (!_current) return false;
+
+ return _current->stack()->caller(_current->function(), false);
+}
+
+bool StackBrowser::canGoDown()
+ {
+ if (!_current) return false;
+
+ return _current->stack()->called(_current->function(), false);
+}
diff --git a/kcachegrind/kcachegrind/stackbrowser.h b/kcachegrind/kcachegrind/stackbrowser.h
new file mode 100644
index 00000000..a533f426
--- /dev/null
+++ b/kcachegrind/kcachegrind/stackbrowser.h
@@ -0,0 +1,109 @@
+/* This file is part of KCachegrind.
+ Copyright (C) 2003 Josef Weidendorfer <Josef.Weidendorfer@gmx.de>
+
+ KCachegrind is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public
+ License as published by the Free Software Foundation, version 2.
+
+ 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; see the file COPYING. If not, write to
+ the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+*/
+
+#ifndef STACKBROWSER_H
+#define STACKBROWSER_H
+
+#include "tracedata.h"
+
+// A history of selected functions within stacks
+
+class Stack
+{
+public:
+ Stack(TraceFunction*);
+
+ // extend the stack at top/bottom if possible
+ bool contains(TraceFunction*);
+
+ void extendBottom();
+ void extendTop();
+
+ // search for a function on stack calling specified function.
+ // if found, return upper part with new function call
+ Stack* split(TraceFunction*);
+
+ // increment reference count
+ void ref() { _refCount++; }
+ // decrement reference count
+ bool deref() { return --_refCount; }
+ int refCount() { return _refCount; }
+
+ TraceFunction* top() { return _top; }
+ TraceCallList calls() { return _calls; }
+ TraceFunction* caller(TraceFunction*, bool extend);
+ TraceFunction* called(TraceFunction*, bool extend);
+
+ QString toString();
+
+private:
+ Stack(TraceFunction* top, TraceCallList list);
+
+ // at the top of the stack we have a function...
+ TraceFunction* _top;
+ // list ordered from top to bottom
+ TraceCallList _calls;
+ int _refCount;
+};
+
+class HistoryItem
+{
+public:
+ HistoryItem(Stack*, TraceFunction*);
+ ~HistoryItem();
+
+ Stack* stack() { return _stack; }
+ TraceFunction* function() { return _function; }
+ HistoryItem* last() { return _last; }
+ HistoryItem* next() { return _next; }
+ void setLast(HistoryItem* h) { _last = h; }
+ void setNext(HistoryItem* h) { _next = h; }
+
+private:
+
+ HistoryItem *_last, *_next;
+ Stack* _stack;
+ TraceFunction* _function;
+};
+
+
+class StackBrowser
+{
+public:
+ StackBrowser();
+ ~StackBrowser();
+
+ // A function was selected. This creates a new history entry
+ HistoryItem* select(TraceFunction*);
+
+ HistoryItem* current() { return _current; }
+ bool canGoBack();
+ bool canGoForward();
+ bool canGoUp();
+ bool canGoDown();
+ HistoryItem* goBack();
+ HistoryItem* goForward();
+ HistoryItem* goUp();
+ HistoryItem* goDown();
+
+private:
+ HistoryItem* _current;
+};
+
+
+#endif
diff --git a/kcachegrind/kcachegrind/stackitem.cpp b/kcachegrind/kcachegrind/stackitem.cpp
new file mode 100644
index 00000000..7ffdd2d3
--- /dev/null
+++ b/kcachegrind/kcachegrind/stackitem.cpp
@@ -0,0 +1,116 @@
+/* This file is part of KCachegrind.
+ Copyright (C) 2003 Josef Weidendorfer <Josef.Weidendorfer@gmx.de>
+
+ KCachegrind is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public
+ License as published by the Free Software Foundation, version 2.
+
+ 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; see the file COPYING. If not, write to
+ the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+*/
+
+/*
+ * Items of stack dockable.
+ */
+
+#include <qpixmap.h>
+#include <klocale.h>
+
+#include "configuration.h"
+#include "listutils.h"
+#include "stackitem.h"
+#include "stackselection.h"
+
+// StackItem
+
+StackItem::StackItem(StackSelection* ss,
+ QListView* parent, TraceFunction* f)
+ :QListViewItem(parent)
+{
+ _view = ss;
+ _function = f;
+ _call = 0;
+
+ updateGroup();
+ updateCost();
+
+ setText(2, QString("-- "));
+ setText(3, f->prettyName());
+}
+
+StackItem::StackItem(StackSelection* ss,
+ QListView* parent, TraceCall* call)
+ :QListViewItem(parent)
+{
+ _view = ss;
+ _call = call;
+ _function = call->called();
+
+ updateGroup();
+ updateCost();
+
+ setText(3, _function->prettyName());
+}
+
+
+void StackItem::updateGroup()
+{
+ QColor c = Configuration::functionColor(_view->groupType(),
+ _function);
+ setPixmap(3, colorPixmap(10, 10, c));
+}
+
+void StackItem::updateCost()
+{
+ if (!_call) return;
+
+ setText(2, _call->prettyCallCount());
+
+ TraceCostType* ct = _view->costType();
+ _sum = _call->subCost(ct);
+ double total = _call->called()->data()->subCost(ct);
+ if (total == 0.0) {
+ setText(0, "-");
+ setPixmap(0, QPixmap());
+ }
+ else {
+ double sum = 100.0 * _sum / total;
+
+ if (Configuration::showPercentage())
+ setText(0, QString("%1")
+ .arg(sum, 0, 'f', Configuration::percentPrecision()));
+ else
+ setText(0, _call->prettySubCost(ct));
+
+ setPixmap(0, costPixmap(ct, _call, total, false));
+ }
+
+ // if _costType2 is 0, column1 is hidden, no change needed
+ TraceCostType* ct2 = _view->costType2();
+ if (!ct2) return;
+
+ _sum = _call->subCost(ct2);
+ total = _call->called()->data()->subCost(ct2);
+ if (total == 0.0) {
+ setText(1, "-");
+ setPixmap(1, QPixmap());
+ }
+ else {
+ double sum = 100.0 * _sum / total;
+
+ if (Configuration::showPercentage())
+ setText(1, QString("%1")
+ .arg(sum, 0, 'f', Configuration::percentPrecision()));
+ else
+ setText(1, _call->prettySubCost(ct2));
+
+ setPixmap(1, costPixmap(ct2, _call, total, false));
+ }
+}
diff --git a/kcachegrind/kcachegrind/stackitem.h b/kcachegrind/kcachegrind/stackitem.h
new file mode 100644
index 00000000..a3a3a4c8
--- /dev/null
+++ b/kcachegrind/kcachegrind/stackitem.h
@@ -0,0 +1,56 @@
+/* This file is part of KCachegrind.
+ Copyright (C) 2003, 2004
+ Josef Weidendorfer <Josef.Weidendorfer@gmx.de>
+
+ KCachegrind is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public
+ License as published by the Free Software Foundation, version 2.
+
+ 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; see the file COPYING. If not, write to
+ the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+*/
+
+/*
+ * Items of stack dockable.
+ */
+
+#ifndef STACKITEM_H
+#define STACKITEM_H
+
+#include <qlistview.h>
+#include "tracedata.h"
+
+class StackSelection;
+
+
+// for the stack browser
+
+class StackItem: public QListViewItem
+{
+public:
+ // for top
+ StackItem(StackSelection* ss, QListView* parent, TraceFunction* f);
+ StackItem(StackSelection* ss, QListView* parent, TraceCall* c);
+
+ TraceFunction* function() { return _function; }
+ TraceCall* call() { return _call; }
+ void updateGroup();
+ void updateCost();
+
+private:
+ StackSelection* _view;
+ SubCost _sum;
+ TraceFunction* _function;
+ TraceCall* _call;
+};
+
+
+
+#endif
diff --git a/kcachegrind/kcachegrind/stackselection.cpp b/kcachegrind/kcachegrind/stackselection.cpp
new file mode 100644
index 00000000..c01098e0
--- /dev/null
+++ b/kcachegrind/kcachegrind/stackselection.cpp
@@ -0,0 +1,230 @@
+/* This file is part of KCachegrind.
+ Copyright (C) 2003 Josef Weidendorfer <Josef.Weidendorfer@gmx.de>
+
+ KCachegrind is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public
+ License as published by the Free Software Foundation, version 2.
+
+ 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; see the file COPYING. If not, write to
+ the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+*/
+
+/*
+ * StackSelection for KCachegrind
+ * For function selection of a most expected stack,
+ * to be put into a QDockWindow
+ */
+
+#include <qtimer.h>
+#include <qlistview.h>
+#include <qlabel.h>
+#include <qpushbutton.h>
+#include <qcombobox.h>
+#include <qlineedit.h>
+
+#include <kdebug.h>
+
+#include "stackbrowser.h"
+#include "stackselection.h"
+#include "stackitem.h"
+
+StackSelection::StackSelection( QWidget* parent, const char* name)
+ : StackSelectionBase(parent, name)
+{
+ _data = 0;
+ _browser = new StackBrowser();
+ _item = 0;
+ _function = 0;
+ _costType = 0;
+ _costType2 = 0;
+ _groupType = TraceItem::Function;
+
+ stackList->setSorting(-1);
+ stackList->setAllColumnsShowFocus(true);
+ stackList->setResizeMode(QListView::LastColumn);
+ stackList->setColumnAlignment(0, Qt::AlignRight);
+ stackList->setColumnAlignment(1, Qt::AlignRight);
+ stackList->setColumnAlignment(2, Qt::AlignRight);
+ stackList->setColumnWidth(0, 50);
+ // 2nd cost column hidden at first (_costType2 == 0)
+ stackList->setColumnWidth(1, 0);
+ stackList->setColumnWidth(2, 50);
+
+ connect(stackList, SIGNAL(selectionChanged(QListViewItem*)),
+ this, SLOT(stackSelected(QListViewItem*)));
+}
+
+StackSelection::~StackSelection()
+{
+ delete _browser;
+}
+
+void StackSelection::setData(TraceData* data)
+{
+ if (_data == data) return;
+
+ _data = data;
+
+ stackList->clear();
+ delete _browser;
+ _browser = new StackBrowser();
+ _function = 0;
+}
+
+
+void StackSelection::setFunction(TraceFunction* f)
+{
+ if (_function == f) return;
+ _function = f;
+
+ if (!_data || !_function) return;
+
+ //kdDebug() << "StackSelection::setFunction " << f->name() << endl;
+
+ HistoryItem* item = _browser->current();
+ if (!item || item->function() != f) {
+ _browser->select(f);
+ rebuildStackList();
+ }
+}
+
+
+void StackSelection::rebuildStackList()
+{
+ HistoryItem* item = _browser->current();
+ stackList->clear();
+ stackList->setColumnWidth(0, 50);
+ stackList->setColumnWidth(1, _costType2 ? 50:0);
+ stackList->setColumnWidth(2, 50);
+ if (!item || !item->stack()) return;
+
+ TraceFunction* top = item->stack()->top();
+ if (!top) return;
+
+ stackList->setColumnWidthMode(1, QListView::Maximum);
+
+ TraceCallList l = item->stack()->calls();
+ TraceCall* call;
+ for (call=l.last();call;call=l.prev())
+ new StackItem(this, stackList, call);
+
+ new StackItem(this, stackList, top);
+
+ // select current function
+ QListViewItem* i = stackList->firstChild();
+ for (;i;i=i->nextSibling())
+ if (((StackItem*)i)->function() == item->function())
+ break;
+
+ if (i) {
+ // this calls stackFunctionSelected()
+ stackList->setCurrentItem(i);
+ stackList->ensureItemVisible(i);
+ }
+
+ if (!_costType2) {
+ stackList->setColumnWidthMode(1, QListView::Manual);
+ stackList->setColumnWidth(1, 0);
+ }
+}
+
+void StackSelection::stackSelected(QListViewItem* i)
+{
+ if (!i) return;
+
+ TraceFunction* f = ((StackItem*)i)->function();
+ emit functionSelected(f);
+}
+
+
+void StackSelection::browserBack()
+{
+ if (_browser && _browser->canGoBack()) {
+ _browser->goBack();
+ rebuildStackList();
+ }
+}
+
+void StackSelection::browserForward()
+{
+ if (_browser && _browser->canGoForward()) {
+ _browser->goForward();
+ rebuildStackList();
+ }
+}
+
+void StackSelection::browserUp()
+{
+ if (_browser) {
+ _browser->goUp();
+ rebuildStackList();
+ }
+}
+
+void StackSelection::browserDown()
+{
+ if (_browser) {
+ _browser->goDown();
+ rebuildStackList();
+ }
+}
+
+void StackSelection::refresh()
+{
+ QListViewItem* item = stackList->firstChild();
+ for(;item;item = item->nextSibling())
+ ((StackItem*)item)->updateCost();
+}
+
+void StackSelection::setCostType(TraceCostType* ct)
+{
+ if (ct == _costType) return;
+ _costType = ct;
+
+ stackList->setColumnWidth(0, 50);
+ if (_costType)
+ stackList->setColumnText(0, _costType->name());
+
+ QListViewItem* item = stackList->firstChild();
+ for(;item;item = item->nextSibling())
+ ((StackItem*)item)->updateCost();
+}
+
+void StackSelection::setCostType2(TraceCostType* ct)
+{
+ if (ct == _costType2) return;
+ _costType2 = ct;
+
+ stackList->setColumnWidth(1, 50);
+ stackList->setColumnWidthMode(1, QListView::Maximum);
+ if (_costType2)
+ stackList->setColumnText(1, _costType2->name());
+
+ QListViewItem* item = stackList->firstChild();
+ for(;item;item = item->nextSibling())
+ ((StackItem*)item)->updateCost();
+
+ if (!_costType2) {
+ stackList->setColumnWidthMode(1, QListView::Manual);
+ stackList->setColumnWidth(1, 0);
+ }
+}
+
+void StackSelection::setGroupType(TraceItem::CostType gt)
+{
+ if (_groupType == gt) return;
+ _groupType = gt;
+
+ QListViewItem* item = stackList->firstChild();
+ for(;item;item = item->nextSibling())
+ ((StackItem*)item)->updateGroup();
+}
+
+#include "stackselection.moc"
diff --git a/kcachegrind/kcachegrind/stackselection.h b/kcachegrind/kcachegrind/stackselection.h
new file mode 100644
index 00000000..80c7ed0e
--- /dev/null
+++ b/kcachegrind/kcachegrind/stackselection.h
@@ -0,0 +1,80 @@
+/* This file is part of KCachegrind.
+ Copyright (C) 2003 Josef Weidendorfer <Josef.Weidendorfer@gmx.de>
+
+ KCachegrind is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public
+ License as published by the Free Software Foundation, version 2.
+
+ 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; see the file COPYING. If not, write to
+ the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+*/
+
+/*
+ * StackSelection for KCachegrind
+ * For function selection of a most expected stack,
+ * to be put into a QDockWindow
+ */
+
+#ifndef STACKSELECTION_H
+#define STACKSELECTION_H
+
+#include "stackselectionbase.h"
+#include "tracedata.h"
+
+class TraceFunction;
+class TraceData;
+class StackBrowser;
+class NestedAreaItem;
+
+class StackSelection : public StackSelectionBase
+{
+ Q_OBJECT
+
+public:
+ StackSelection( QWidget* parent = 0, const char* name = 0);
+ ~StackSelection();
+
+ TraceData* data() const { return _data; }
+ void setData(TraceData*);
+ StackBrowser* browser() const { return _browser; }
+ TraceCostType* costType() { return _costType; }
+ TraceCostType* costType2() { return _costType2; }
+ TraceItem::CostType groupType() { return _groupType; }
+
+signals:
+ void functionSelected(TraceItem*);
+
+public slots:
+ void setFunction(TraceFunction*);
+ void setCostType(TraceCostType*);
+ void setCostType2(TraceCostType*);
+ void setGroupType(TraceItem::CostType);
+
+ void stackSelected( QListViewItem* );
+ void browserBack();
+ void browserForward();
+ void browserUp();
+ void browserDown();
+ void refresh();
+ void rebuildStackList();
+
+private:
+ void selectFunction();
+
+ TraceData* _data;
+ StackBrowser* _browser;
+ QListViewItem* _item;
+ TraceFunction* _function;
+ TraceCostType* _costType;
+ TraceCostType* _costType2;
+ TraceItem::CostType _groupType;
+};
+
+#endif
diff --git a/kcachegrind/kcachegrind/stackselectionbase.ui b/kcachegrind/kcachegrind/stackselectionbase.ui
new file mode 100644
index 00000000..291153bc
--- /dev/null
+++ b/kcachegrind/kcachegrind/stackselectionbase.ui
@@ -0,0 +1,80 @@
+<!DOCTYPE UI><UI version="3.0" stdsetdef="1">
+<class>StackSelectionBase</class>
+<widget class="QWidget">
+ <property name="name">
+ <cstring>StackSelectionBase</cstring>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>168</width>
+ <height>108</height>
+ </rect>
+ </property>
+ <property name="caption">
+ <string>Stack Selection</string>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>3</number>
+ </property>
+ <property name="spacing">
+ <number>6</number>
+ </property>
+ <widget class="QListView">
+ <column>
+ <property name="text">
+ <string>Cost</string>
+ </property>
+ <property name="clickable">
+ <bool>true</bool>
+ </property>
+ <property name="resizeable">
+ <bool>true</bool>
+ </property>
+ </column>
+ <column>
+ <property name="text">
+ <string>Cost2</string>
+ </property>
+ <property name="clickable">
+ <bool>true</bool>
+ </property>
+ <property name="resizeable">
+ <bool>true</bool>
+ </property>
+ </column>
+ <column>
+ <property name="text">
+ <string>Calls</string>
+ </property>
+ <property name="clickable">
+ <bool>true</bool>
+ </property>
+ <property name="resizeable">
+ <bool>true</bool>
+ </property>
+ </column>
+ <column>
+ <property name="text">
+ <string>Function</string>
+ </property>
+ <property name="clickable">
+ <bool>true</bool>
+ </property>
+ <property name="resizeable">
+ <bool>true</bool>
+ </property>
+ </column>
+ <property name="name">
+ <cstring>stackList</cstring>
+ </property>
+ </widget>
+ </vbox>
+</widget>
+<layoutdefaults spacing="6" margin="11"/>
+</UI>
diff --git a/kcachegrind/kcachegrind/subcost.cpp b/kcachegrind/kcachegrind/subcost.cpp
new file mode 100644
index 00000000..5352fe25
--- /dev/null
+++ b/kcachegrind/kcachegrind/subcost.cpp
@@ -0,0 +1,62 @@
+/* This file is part of KCachegrind.
+ Copyright (C) 2004 Josef Weidendorfer <Josef.Weidendorfer@gmx.de>
+
+ KCachegrind is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public
+ License as published by the Free Software Foundation, version 2.
+
+ 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; see the file COPYING. If not, write to
+ the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+*/
+
+#include <qstring.h>
+
+#include "subcost.h"
+
+//---------------------------------------------------
+// SubCost
+
+bool SubCost::set(const char** ps)
+{
+ const char* s = *ps;
+ if (!s || (*s < '0') || (*s > '9')) return false;
+
+ v = *s - '0';
+ s++;
+ while(*s >= '0' && *s <= '9') {
+ v = 10* v + (*s-'0');
+ s++;
+ }
+ while(*s == ' ') s++;
+ *ps = s;
+
+ return true;
+}
+
+QString SubCost::pretty()
+{
+ unsigned long long n = v;
+
+ if (n==0) return QString(" 0");
+
+ int i = 0;
+ QString res = "";
+
+ while (n) {
+ if ((i>0) && !(i%3)) res = " " + res;
+ i++;
+ res = QChar('0'+int(n%10)) + res;
+ n /= 10;
+ }
+ res = " " + res;
+ return res;
+}
+
+
diff --git a/kcachegrind/kcachegrind/subcost.h b/kcachegrind/kcachegrind/subcost.h
new file mode 100644
index 00000000..5f24a733
--- /dev/null
+++ b/kcachegrind/kcachegrind/subcost.h
@@ -0,0 +1,66 @@
+/* This file is part of KCachegrind.
+ Copyright (C) 2002-2004 Josef Weidendorfer <Josef.Weidendorfer@gmx.de>
+
+ KCachegrind is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public
+ License as published by the Free Software Foundation, version 2.
+
+ 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; see the file COPYING. If not, write to
+ the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+*/
+
+#ifndef SUBCOST_H
+#define SUBCOST_H
+
+#include "utils.h"
+
+typedef unsigned long long uint64;
+
+/**
+ * Cost event counter, simple wrapper around a 64bit entity
+ */
+class SubCost
+{
+ public:
+ SubCost() {}
+ SubCost(uint64 i) { v=i; }
+ SubCost(unsigned i) { v=i; }
+ SubCost(int i) { v=(unsigned)i; }
+ SubCost(double d) { v= (uint64)(d + .5); }
+
+ SubCost& operator=(uint64 i) { v = i; return *this; }
+ SubCost& operator=(unsigned i) { v = i; return *this; }
+ SubCost& operator=(int i) { v = i; return *this; }
+ SubCost& operator=(double d) { v = (uint64)(d + .5); return *this; }
+
+ bool set(const char** s);
+ bool set(FixString& s) { return s.stripUInt64(v); }
+
+ operator uint64&() { return v; }
+
+ bool operator==(unsigned i) const { return v == i; }
+ bool operator==(int i) const { return v == (unsigned)i; }
+ bool operator<(unsigned i) const { return v < i; }
+ bool operator<(int i) const { return v < (unsigned)i; }
+ bool operator<(const SubCost& s) const { return v < s.v; }
+ bool operator>(unsigned i) const { return v > i; }
+ bool operator>(int i) const { return v > (unsigned)i; }
+ bool operator>(const SubCost& s) const { return v > s.v; }
+
+ /**
+ * Convert SubCost value into a QString,
+ * spaced every 3 digits.
+ */
+ QString pretty();
+
+ uint64 v;
+};
+
+#endif
diff --git a/kcachegrind/kcachegrind/tabview.cpp b/kcachegrind/kcachegrind/tabview.cpp
new file mode 100644
index 00000000..3a644a15
--- /dev/null
+++ b/kcachegrind/kcachegrind/tabview.cpp
@@ -0,0 +1,890 @@
+/* This file is part of KCachegrind.
+ Copyright (C) 2003 Josef Weidendorfer <Josef.Weidendorfer@gmx.de>
+
+ KCachegrind is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public
+ License as published by the Free Software Foundation, version 2.
+
+ 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; see the file COPYING. If not, write to
+ the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+*/
+
+/*
+ * Tab View, enclosing detailed views for one trace item in
+ * two tab widgets, separated by a splitter
+ */
+
+#include <qobjectlist.h>
+#include <qsplitter.h>
+#include <qtabwidget.h>
+#include <qlayout.h>
+#include <qwhatsthis.h>
+#include <qpopupmenu.h>
+
+#include <klocale.h>
+#include <kconfig.h>
+
+#include "tabview.h"
+#include "costtypeview.h"
+#include "partview.h"
+#include "callview.h"
+#include "coverageview.h"
+#include "callmapview.h"
+#include "instrview.h"
+#include "sourceview.h"
+#include "callgraphview.h"
+
+// TabBar
+
+TabBar::TabBar(TabView* v, QTabWidget* parent, const char *name)
+ : QTabBar(parent, name)
+{
+ _tabWidget = parent;
+ _tabView = v;
+}
+
+void TabBar::mousePressEvent(QMouseEvent *e)
+{
+ if (e->button() == RightButton) {
+ QTab *tab = selectTab( e->pos() );
+ QWidget* page;
+ page = tab ? _tabWidget->page( indexOf( tab->identifier() ) ) :0;
+
+ QPopupMenu popup, popup1, popup2, popup3;
+ if (page) {
+ TraceItemView::Position p = _tabView->tabPosition(page);
+ if (p != TraceItemView::Top) {
+ popup.insertItem(i18n("Move to Top"), 81);
+ popup2.insertItem(i18n("Top"), 91);
+ }
+ if (p != TraceItemView::Right) {
+ popup.insertItem(i18n("Move to Right"), 82);
+ popup2.insertItem(i18n("Right"), 92);
+ }
+ if (p != TraceItemView::Bottom) {
+ popup.insertItem(i18n("Move to Bottom"), 83);
+ popup2.insertItem(i18n("Bottom"), 93);
+ }
+ if (p != TraceItemView::Left) {
+ popup.insertItem(i18n("Move to Bottom Left"), 84);
+ popup2.insertItem(i18n("Bottom Left"), 94);
+ }
+ popup.insertItem(i18n("Move Area To"), &popup2, 2);
+ popup.insertSeparator();
+ popup.insertItem(i18n("Hide This Tab"), 80);
+ popup.insertItem(i18n("Hide Area"), 90);
+
+ if (_tabView->visibleTabs() <2) {
+ popup.setItemEnabled(80, false);
+ popup.setItemEnabled(90, false);
+ }
+ else if (_tabView->visibleAreas() <2)
+ popup.setItemEnabled(90, false);
+ }
+ popup3.insertItem(i18n("Top"), 101);
+ popup3.insertItem(i18n("Right"), 102);
+ popup3.insertItem(i18n("Bottom"), 103);
+ popup3.insertItem(i18n("Bottom Left"), 104);
+ popup.insertItem(i18n("Show Hidden On"), &popup3, 3);
+
+ int r = popup.exec( mapToGlobal( e->pos() ) );
+
+ TraceItemView::Position p = TraceItemView::Hidden;
+ if ((r % 10) == 1) p = TraceItemView::Top;
+ if ((r % 10) == 2) p = TraceItemView::Right;
+ if ((r % 10) == 3) p = TraceItemView::Bottom;
+ if ((r % 10) == 4) p = TraceItemView::Left;
+
+ if (r>=80 && r<100) _tabView->moveTab(page, p, r>=90);
+ if (r>=100 && r<110) _tabView->moveTab(0, p, true);
+ }
+
+ QTabBar::mousePressEvent( e );
+}
+
+
+//
+// Splitter
+//
+
+Splitter::Splitter(Orientation o, QWidget* parent, const char* name)
+ : QSplitter(o, parent, name)
+{}
+
+void Splitter::moveEvent(QMoveEvent* e)
+{
+ QSplitter::moveEvent(e);
+
+ if (0) qDebug("Splitter %s: Move", name());
+ checkVisiblity();
+}
+
+void Splitter::checkVisiblity()
+{
+ const QObjectList *l = children();
+ QObjectListIt it( *l );
+ QObject *obj;
+ while ( (obj = it.current()) != 0 ) {
+ ++it;
+ if (obj->isA("Splitter")) ((Splitter*)obj)->checkVisiblity();
+ else if (obj->isA("TabWidget")) ((TabWidget*)obj)->checkVisibility();
+ }
+}
+
+
+
+
+//
+// TabWidget
+//
+
+TabWidget::TabWidget(TabView* v, QWidget* parent,
+ const char* name, WFlags f)
+ : QTabWidget(parent, name, f)
+{
+ _hasVisibleRect = false;
+ setTabBar(new TabBar(v, this));
+}
+
+void TabWidget::checkVisibility()
+{
+ bool hasVisibleRect = (visibleRect().width()>1) &&
+ (visibleRect().height()>1);
+
+ if (0) qDebug("TabWidget %s: VR (%dx%d) HasVisibleRect: %s => %s",
+ name(),
+ visibleRect().width(), visibleRect().height(),
+ _hasVisibleRect ? "Yes":"No",
+ hasVisibleRect ? "Yes":"No");
+
+ if (hasVisibleRect != _hasVisibleRect) {
+ _hasVisibleRect = hasVisibleRect;
+ emit visibleRectChanged(this);
+ }
+}
+
+void TabWidget::resizeEvent(QResizeEvent *e)
+{
+ QTabWidget::resizeEvent(e);
+ if (0) qDebug("TabWidget %s:\n Resize from (%d/%d) to (%d/%d)",
+ name(),
+ e->oldSize().width(), e->oldSize().height(),
+ e->size().width(), e->size().height());
+ checkVisibility();
+}
+
+void TabWidget::showEvent(QShowEvent* e)
+{
+ QTabWidget::showEvent(e);
+
+ if (0) qDebug("TabWidget %s: Show", name());
+ checkVisibility();
+}
+
+void TabWidget::hideEvent(QHideEvent* e)
+{
+ QTabWidget::hideEvent(e);
+
+ if (0) qDebug("TabWidget %s: Hide", name());
+ checkVisibility();
+}
+
+void TabWidget::moveEvent(QMoveEvent* e)
+{
+ QTabWidget::moveEvent(e);
+
+ if (0) qDebug("TabWidget %s: Move", name());
+ checkVisibility();
+}
+
+
+
+//
+// TabView
+//
+
+/*
+ * Areas for child views
+ *
+ * leftSplitter
+ * |
+ * | ----- -----
+ * | _/ \_______________/ \____
+ * | | Top | TopRight |
+ * | | | |
+ * -> |---------------------| |
+ * | BottomLeft | Bottom | |
+ * | | | |
+ * -\_____/------\____/--------------
+ *
+ * ^ ^
+ * bottomSplitter mainSplitter
+ */
+
+TabView::TabView(TraceItemView* parentView,
+ QWidget* parent, const char* name)
+ : QWidget(parent, name), TraceItemView(parentView)
+{
+ setFocusPolicy(QWidget::StrongFocus);
+
+ _isCollapsed = true;
+
+ QVBoxLayout* vbox = new QVBoxLayout( this, 6, 6);
+
+ _nameLabel = new KSqueezedTextLabel( this, "nameLabel" );
+ _nameLabel->setText(i18n("(No profile data file loaded)"));
+ vbox->addWidget( _nameLabel );
+
+ _mainSplitter = new QSplitter(Qt::Horizontal, this);
+ _leftSplitter = new Splitter(Qt::Vertical, _mainSplitter, "Left");
+ vbox->addWidget( _mainSplitter );
+
+ _rightTW = new TabWidget(this, _mainSplitter, "Right");
+ connect(_rightTW, SIGNAL(currentChanged(QWidget*)),
+ this, SLOT(tabChanged(QWidget*)));
+ connect(_rightTW, SIGNAL(visibleRectChanged(TabWidget*)),
+ this, SLOT(visibleRectChangedSlot(TabWidget*)));
+
+ _topTW = new TabWidget(this, _leftSplitter, "Top");
+ connect(_topTW, SIGNAL(currentChanged(QWidget*)),
+ this, SLOT(tabChanged(QWidget*)));
+ connect(_topTW, SIGNAL(visibleRectChanged(TabWidget*)),
+ this, SLOT(visibleRectChangedSlot(TabWidget*)));
+
+ _bottomSplitter = new Splitter(Qt::Horizontal,
+ _leftSplitter, "Bottom");
+
+ _leftTW = new TabWidget(this, _bottomSplitter, "Left");
+ _leftTW->setTabPosition(QTabWidget::Bottom);
+ connect(_leftTW, SIGNAL(currentChanged(QWidget*)),
+ this, SLOT(tabChanged(QWidget*)));
+ connect(_leftTW, SIGNAL(visibleRectChanged(TabWidget*)),
+ this, SLOT(visibleRectChangedSlot(TabWidget*)));
+
+ _bottomTW = new TabWidget(this, _bottomSplitter, "Bottom");
+ _bottomTW->setTabPosition(QTabWidget::Bottom);
+ connect(_bottomTW, SIGNAL(currentChanged(QWidget*)),
+ this, SLOT(tabChanged(QWidget*)));
+ connect(_bottomTW, SIGNAL(visibleRectChanged(TabWidget*)),
+ this, SLOT(visibleRectChangedSlot(TabWidget*)));
+
+
+ // default positions...
+
+ addTop( addTab( i18n("Types"),
+ new CostTypeView(this, _topTW,
+ "CostTypeView")));
+ addTop( addTab( i18n("Callers"),
+ new CallView(true, this, _topTW,
+ "CallerView")));
+ addTop( addTab( i18n("All Callers"),
+ new CoverageView(true, this, _topTW,
+ "AllCallerView")));
+ addTop( addTab( i18n("Caller Map"),
+ new CallMapView(true, this, _bottomTW,
+ "CallerMapView")));
+ addTop( addTab( i18n("Source"),
+ new SourceView(this, _topTW,
+ "SourceView")));
+
+ addBottom( addTab( i18n("Parts"),
+ new PartView(this, _bottomTW,
+ "PartView")));
+ addBottom( addTab( i18n("Call Graph"),
+ new CallGraphView(this, _bottomTW,
+ "CallGraphView")));
+ addBottom( addTab( i18n("Callees"),
+ new CallView(false, this, _bottomTW,
+ "CalleeView")));
+ addBottom( addTab( i18n("All Callees"),
+ new CoverageView(false, this, _bottomTW,
+ "AllCalleeView")));
+
+ addBottom( addTab( i18n("Callee Map"),
+ new CallMapView(false, this, _topTW,
+ "CalleeMapView")));
+ addBottom( addTab( i18n("Assembler"),
+ new InstrView(this, _bottomTW,
+ "InstrView")));
+
+ // after all child widgets are created...
+ _lastFocus = 0;
+ _active = false;
+ installFocusFilters();
+
+ updateVisibility();
+
+ QWhatsThis::add( this, whatsThis() );
+}
+
+void TabView::setData(TraceData* d)
+{
+ TraceItemView::setData(d);
+
+ TraceItemView* v;
+ for (v=_tabs.first();v;v=_tabs.next())
+ v->setData(d);
+}
+
+TraceItemView* TabView::addTab(QString label, TraceItemView* view)
+{
+ view->setTitle(label);
+ _tabs.append(view);
+ return view;
+}
+
+void TabView::addTop(TraceItemView* view)
+{
+ view->setPosition(TraceItemView::Top);
+ _topTW->insertTab(view->widget(), view->title());
+}
+
+void TabView::addBottom(TraceItemView* view)
+{
+ view->setPosition(TraceItemView::Bottom);
+ _bottomTW->insertTab(view->widget(), view->title());
+}
+
+TraceItemView::Position TabView::tabPosition(QWidget* w)
+{
+ TraceItemView* v;
+ for (v=_tabs.first();v;v=_tabs.next())
+ if (v->widget() == w) return v->position();
+
+ return Hidden;
+}
+
+int TabView::visibleTabs()
+{
+ int c = 0;
+ TraceItemView* v;
+ for (v=_tabs.first();v;v=_tabs.next()) {
+ if (v->position() == Hidden) continue;
+ c++;
+ }
+ return c;
+}
+
+
+int TabView::visibleAreas()
+{
+ int c = 0, t = 0, b = 0, r = 0, l = 0;
+ TraceItemView* v;
+ for (v=_tabs.first();v;v=_tabs.next()) {
+ switch(v->position()) {
+ case TraceItemView::Top: t++; break;
+ case TraceItemView::Bottom: b++; break;
+ case TraceItemView::Left: l++; break;
+ case TraceItemView::Right: r++; break;
+ default: break;
+ }
+ }
+ if (t>0) c++;
+ if (b>0) c++;
+ if (l>0) c++;
+ if (r>0) c++;
+
+ return c;
+}
+
+
+
+// This hides/shows splitters and tabwidgets according to tab childs
+void TabView::updateVisibility()
+{
+ // calculate count of tabs in areas
+ int t = 0, b = 0, r = 0, l = 0;
+ TraceItemView* v;
+ for (v=_tabs.first();v;v=_tabs.next()) {
+ switch(v->position()) {
+ case TraceItemView::Top: t++; break;
+ case TraceItemView::Bottom: b++; break;
+ case TraceItemView::Left: l++; break;
+ case TraceItemView::Right: r++; break;
+ default: break;
+ }
+ }
+
+ if (0) qDebug("TabView::updateVisiblity t %d, b %d, l %d, r %d",
+ t, b, l, r);
+
+ QValueList<int> s;
+ s.append(100);
+
+
+ // children of mainSplitter
+ if (_rightTW->isHidden() != (r == 0)) {
+ if (r == 0) {
+ _rightTW->hide();
+
+ if (!_topTW->hasVisibleRect() &&
+ !_bottomTW->hasVisibleRect() &&
+ !_leftTW->hasVisibleRect()) _mainSplitter->setSizes(s);
+ }
+ else
+ _rightTW->show();
+ }
+ if (_leftSplitter->isHidden() != (t+b+l == 0)) {
+ if (t+b+l == 0) {
+ _leftSplitter->hide();
+
+ if (!_rightTW->hasVisibleRect()) _mainSplitter->setSizes(s);
+ }
+ else
+ _leftSplitter->show();
+ }
+
+ // children of leftSplitter
+ if (_topTW->isHidden() != (t == 0)) {
+ if (t == 0) {
+ _topTW->hide();
+
+ if (!_bottomTW->hasVisibleRect() &&
+ !_leftTW->hasVisibleRect()) _leftSplitter->setSizes(s);
+ }
+ else
+ _topTW->show();
+ }
+
+ if (_bottomSplitter->isHidden() != (b+l == 0)) {
+ if (b+l == 0) {
+ _bottomSplitter->hide();
+
+ if (!_topTW->hasVisibleRect()) _leftSplitter->setSizes(s);
+ }
+ else
+ _bottomSplitter->show();
+ }
+
+ // children of bottomSplitter
+ if (_bottomTW->isHidden() != (b == 0)) {
+ if (b == 0) {
+ _bottomTW->hide();
+
+ if (!_leftTW->hasVisibleRect()) _bottomSplitter->setSizes(s);
+ }
+ else
+ _bottomTW->show();
+ }
+ if (_leftTW->isHidden() != (l == 0)) {
+ if (l == 0) {
+ _leftTW->hide();
+
+ if (!_bottomTW->hasVisibleRect()) _bottomSplitter->setSizes(s);
+ }
+ else
+ _leftTW->show();
+ }
+}
+
+TabWidget* TabView::tabWidget(Position p)
+{
+ switch(p) {
+ case TraceItemView::Top: return _topTW;
+ case TraceItemView::Bottom: return _bottomTW;
+ case TraceItemView::Left: return _leftTW;
+ case TraceItemView::Right: return _rightTW;
+ default: break;
+ }
+ return 0;
+}
+
+void TabView::moveTab(QWidget* w, Position p, bool wholeArea)
+{
+ TraceItemView *v;
+ Position origPos = Hidden;
+ if (w) {
+ for (v=_tabs.first();v;v=_tabs.next())
+ if (v->widget() == w) break;
+
+ if (!v) return;
+ origPos = v->position();
+ }
+ if (origPos == p) return;
+
+ TabWidget *from, *to;
+ from = tabWidget(origPos);
+ to = tabWidget(p);
+
+ QPtrList<TraceItemView> tabs;
+ for (v=_tabs.first();v;v=_tabs.next())
+ if ((v->position() == origPos) &&
+ (wholeArea || (v->widget() == w))) tabs.append(v);
+
+ bool isEnabled;
+ for (v=tabs.first();v;v=tabs.next()) {
+ v->setPosition(p);
+ w = v->widget();
+
+ if (from) {
+ isEnabled = from->isTabEnabled(w);
+ from->removePage(w);
+ }
+ else isEnabled = (v->canShow(_activeItem)!=0);
+
+ if (to) {
+ TraceItemView *vv;
+ int idx = -1, i;
+ for(vv = _tabs.first(); vv && (vv!=v); vv = _tabs.next()) {
+ i = to->indexOf(vv->widget());
+ if (i>=0) idx = i;
+ }
+ to->insertTab(w, v->title(), idx+1);
+ to->setTabEnabled(w, isEnabled);
+ if (isEnabled) {
+ to->showPage(w);
+ v->updateView();
+ }
+ }
+ }
+ updateVisibility();
+}
+
+
+QString TabView::whatsThis() const
+{
+ return i18n( "<b>Information Tabs</b>"
+ "<p>This widget shows information for the "
+ "current selected function in different tabs: "
+ "<ul>"
+ "<li>The Costs tab shows a list of available event types "
+ "and the inclusive and self costs regarding to these types.</li>"
+ "<li>The Parts tab shows a list of trace parts "
+ "if the trace consists of more than one part (otherwise, "
+ "this tab is hided). "
+ "The cost of the selected function spent in the different "
+ "parts together with the calls happening is shown.</li>"
+ "<li>The Call Lists tab shows direct callers and "
+ "callees of the function in more detail.</li>"
+ "<li>The Coverage tab shows the same is the Call "
+ "Lists tab, but not only direct callers and callees "
+ "but also indirect ones.</li>"
+ "<li>The Call Graph tab shows a graphical "
+ "visualization of the calls done by this function.</li>"
+ "<li>The Source tab presents annotated source code "
+ "if debugging information and the source file "
+ "is available.</li>"
+ "<li>The Assembler tab presents annotated assembler code "
+ "if trace information on instruction level "
+ "is available.</li></ul>"
+ "For more information, see the <em>What's This?</em> "
+ "help of the corresponding tab widget</p>");
+}
+
+void TabView::installFocusFilters()
+{
+ QObjectList *l = queryList("QWidget");
+ QObjectListIt it( *l );
+ QObject *obj;
+
+ while ( (obj = it.current()) != 0 ) {
+ ++it;
+ if ( ((QWidget*)obj)->isFocusEnabled() )
+ obj->installEventFilter(this);
+ }
+ delete l;
+}
+
+
+bool TabView::eventFilter(QObject* o, QEvent* e)
+{
+ if (e->type() == QEvent::FocusIn) {
+ _lastFocus = o->isWidgetType() ? (QWidget*) o : 0;
+ setActive(_lastFocus != 0);
+ }
+ return QWidget::eventFilter(o,e);
+}
+
+void TabView::mousePressEvent(QMouseEvent*)
+{
+ if (_lastFocus)
+ _lastFocus->setFocus();
+ setActive(true);
+}
+
+void TabView::setActive(bool a)
+{
+ if (a == _active) return;
+ _active = a;
+
+ QFont nameLabel_font( _nameLabel->font() );
+ nameLabel_font.setBold(a);
+ _nameLabel->setFont( nameLabel_font );
+
+ if (0) qDebug("%s::setActive(%s)", name(), a ? "true":"false");
+
+ if (a) emit activated(this);
+}
+
+void TabView::doUpdate(int changeType)
+{
+ if (changeType & (activeItemChanged | configChanged | dataChanged))
+
+ _nameLabel->setText( !_data ? i18n("(No Data loaded)") :
+ !_activeItem ? i18n("(No function selected)") :
+ _activeItem->prettyName());
+
+
+ // we use our own list iterators because setTabEnabled can
+ // invoke tabChanged, which mangles with the lists, too
+ bool canShow;
+ TraceItemView *v;
+ QPtrListIterator<TraceItemView> it( _tabs );
+ while ( (v=it.current()) != 0) {
+ ++it;
+
+ TabWidget *tw = 0;
+ switch(v->position()) {
+ case TraceItemView::Top: tw = _topTW; break;
+ case TraceItemView::Bottom: tw = _bottomTW; break;
+ case TraceItemView::Left: tw = _leftTW; break;
+ case TraceItemView::Right: tw = _rightTW; break;
+ default: break;
+ }
+
+ // update even if hidden
+ if (tw) {
+ if (!tw->hasVisibleRect()) continue;
+ }
+ canShow = v->set(changeType, _data, _costType, _costType2,
+ _groupType, _partList,
+ _activeItem, _selectedItem);
+ v->notifyChange(changeType);
+
+ if (!tw) continue;
+ if (tw->isTabEnabled(v->widget()) != canShow)
+ tw->setTabEnabled(v->widget(), canShow);
+
+ if (v->widget() == tw->currentPage())
+ v->updateView();
+ }
+}
+
+
+void TabView::tabChanged(QWidget* w)
+{
+ TraceItemView *v;
+ for (v=_tabs.first();v;v=_tabs.next())
+ if (v->widget() == w) v->updateView();
+}
+
+void TabView::visibleRectChangedSlot(TabWidget* tw)
+{
+ if (0) qDebug("%s: %svisible !",
+ tw->name(), tw->hasVisibleRect() ? "":"un");
+
+ if (tw->hasVisibleRect()) doUpdate(0);
+}
+
+void TabView::resizeEvent(QResizeEvent* e)
+{
+ QWidget::resizeEvent(e);
+
+ bool collapsed = (e->size().width()<=1) || (e->size().height()<=1);
+ if (_isCollapsed != collapsed) {
+ _isCollapsed = collapsed;
+ updateView();
+ }
+
+ if (0) qDebug("TabView::Resize from (%d/%d) to (%d/%d)",
+ e->oldSize().width(), e->oldSize().height(),
+ e->size().width(), e->size().height());
+}
+
+void TabView::selected(TraceItemView*, TraceItem* s)
+{
+ // we set selected item for our own children
+ select(s);
+ updateView();
+
+ // still forward to parent
+ if (_parentView) _parentView->selected(this, s);
+}
+
+
+void TabView::readViewConfig(KConfig* c,
+ QString prefix, QString postfix,
+ bool withOptions)
+{
+ if (0) qDebug("%s::readConfig(%s%s)", name(),
+ prefix.ascii(), postfix.ascii());
+
+ KConfigGroup* g = configGroup(c, prefix, postfix);
+
+ _mainSplitter->setSizes(g->readIntListEntry("MainSizes"));
+ _leftSplitter->setSizes(g->readIntListEntry("LeftSizes"));
+ _bottomSplitter->setSizes(g->readIntListEntry("BottomSizes"));
+
+ QString activeT = g->readEntry("ActiveTop", "CallerView");
+ QString activeB = g->readEntry("ActiveBottom", "CalleeView");
+ QString activeL = g->readEntry("ActiveLeft", "");
+ QString activeR = g->readEntry("ActiveRight", "");
+
+ QStringList topTabs = g->readListEntry("TopTabs");
+ QStringList bottomTabs = g->readListEntry("BottomTabs");
+ QStringList leftTabs = g->readListEntry("LeftTabs");
+ QStringList rightTabs = g->readListEntry("RightTabs");
+
+ if (topTabs.isEmpty() && bottomTabs.isEmpty() &&
+ rightTabs.isEmpty() && leftTabs.isEmpty()) {
+ // no tabs visible ?! Reset to default
+ topTabs << "CostTypeView" << "CallerView" << "AllCallerView"
+ << "CalleeMapView" << "SourceView";
+ bottomTabs << "PartView" << "CalleeView" << "CallGraphView"
+ << "AllCalleeView" << "CallerMapView" << "InstrView";
+ }
+
+ TraceItemView *activeTop = 0, *activeBottom = 0;
+ TraceItemView *activeLeft = 0, *activeRight = 0;
+
+ moveTab(0, TraceItemView::Top, true);
+ TraceItemView *v;
+ QPtrListIterator<TraceItemView> it( _tabs );
+ while ( (v=it.current()) != 0) {
+ ++it;
+
+ QString n = QString(v->widget()->name());
+ if (topTabs.contains(n)) {
+ moveTab(v->widget(), TraceItemView::Top);
+ if (n == activeT) activeTop = v;
+ }
+ else if (bottomTabs.contains(n)) {
+ moveTab(v->widget(), TraceItemView::Bottom);
+ if (n == activeB) activeBottom = v;
+ }
+ else if (leftTabs.contains(n)) {
+ moveTab(v->widget(), TraceItemView::Left);
+ if (n == activeL) activeLeft = v;
+ }
+ else if (rightTabs.contains(n)) {
+ moveTab(v->widget(), TraceItemView::Right);
+ if (n == activeR) activeRight = v;
+ }
+ else moveTab(v->widget(), Hidden);
+
+ if (withOptions)
+ v->readViewConfig(c, QString("%1-%2")
+ .arg(prefix).arg(v->widget()->name()),
+ postfix, true);
+ }
+ if (activeTop) _topTW->showPage(activeTop->widget());
+ if (activeBottom)_bottomTW->showPage(activeBottom->widget());
+ if (activeLeft) _leftTW->showPage(activeLeft->widget());
+ if (activeRight) _rightTW->showPage(activeRight->widget());
+
+ QString activeType = g->readEntry("ActiveItemType", "");
+ QString activeName = g->readEntry("ActiveItemName", "");
+ QString selectedType = g->readEntry("SelectedItemType", "");
+ QString selectedName = g->readEntry("SelectedItemName", "");
+ delete g;
+
+ if (!_data) return;
+
+ if (withOptions) {
+ // restore active item
+ TraceItem::CostType t = TraceItem::costType(activeType);
+ if (t==TraceItem::NoCostType) t = TraceItem::Function;
+ TraceCost* activeItem = _data->search(t, activeName, _costType);
+ if (!activeItem) return;
+ activate(activeItem);
+
+ // restore selected item
+ t = TraceItem::costType(selectedType);
+ if (t==TraceItem::NoCostType) t = TraceItem::Function;
+ TraceCost* selectedItem = _data->search(t, selectedName,
+ _costType, activeItem);
+ if (selectedItem) select(selectedItem);
+ }
+
+ updateView();
+}
+
+void TabView::saveViewConfig(KConfig* c,
+ QString prefix, QString postfix,
+ bool withOptions)
+{
+ KConfigGroup g(c, (prefix+postfix).ascii());
+
+ g.writeEntry("MainSizes", _mainSplitter->sizes());
+ g.writeEntry("LeftSizes", _leftSplitter->sizes());
+ g.writeEntry("BottomSizes", _bottomSplitter->sizes());
+
+ QString a;
+ if ((_topTW->count()>0) &&
+ (_topTW->isTabEnabled(_topTW->currentPage())))
+ a = QString(_topTW->currentPage()->name());
+ g.writeEntry("ActiveTop", a);
+
+ a.setLength(0);
+ if ((_bottomTW->count()>0) &&
+ (_bottomTW->isTabEnabled(_bottomTW->currentPage())))
+ a = QString(_bottomTW->currentPage()->name());
+ g.writeEntry("ActiveBottom", a);
+
+ a.setLength(0);
+ if ((_leftTW->count()>0) &&
+ (_leftTW->isTabEnabled(_leftTW->currentPage())))
+ a = QString(_leftTW->currentPage()->name());
+ g.writeEntry("ActiveLeft", a);
+
+ a.setLength(0);
+ if ((_rightTW->count()>0) &&
+ (_rightTW->isTabEnabled(_rightTW->currentPage())))
+ a = QString(_rightTW->currentPage()->name());
+ g.writeEntry("ActiveRight", a);
+
+ if (withOptions)
+ if (_activeItem) {
+ g.writeEntry("ActiveItemType",
+ TraceItem::typeName(_activeItem->type()));
+ g.writeEntry("ActiveItemName", _activeItem->name());
+ if (_selectedItem) {
+ g.writeEntry("SelectedItemType",
+ TraceItem::typeName(_selectedItem->type()));
+ g.writeEntry("SelectedItemName", _selectedItem->name());
+ }
+ }
+
+ QStringList topList, bottomList, leftList, rightList;
+ TraceItemView *v;
+ for (v=_tabs.first();v;v=_tabs.next()) {
+ switch(v->position()) {
+ case TraceItemView::Top:
+ topList << QString(v->widget()->name());
+ break;
+
+ case TraceItemView::Bottom:
+ bottomList << QString(v->widget()->name());
+ break;
+
+ case TraceItemView::Left:
+ leftList << QString(v->widget()->name());
+ break;
+
+ case TraceItemView::Right:
+ rightList << QString(v->widget()->name());
+ break;
+
+ default: break;
+ }
+ }
+
+ g.writeEntry("TopTabs", topList);
+ g.writeEntry("BottomTabs", bottomList);
+ g.writeEntry("LeftTabs", leftList);
+ g.writeEntry("RightTabs", rightList);
+
+ if (withOptions)
+ for (v=_tabs.first();v;v=_tabs.next())
+ v->saveViewConfig(c, QString("%1-%2").arg(prefix)
+ .arg(v->widget()->name()), postfix, true);
+}
+
+#include "tabview.moc"
diff --git a/kcachegrind/kcachegrind/tabview.h b/kcachegrind/kcachegrind/tabview.h
new file mode 100644
index 00000000..946f9225
--- /dev/null
+++ b/kcachegrind/kcachegrind/tabview.h
@@ -0,0 +1,170 @@
+/* This file is part of KCachegrind.
+ Copyright (C) 2003 Josef Weidendorfer <Josef.Weidendorfer@gmx.de>
+
+ KCachegrind is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public
+ License as published by the Free Software Foundation, version 2.
+
+ 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; see the file COPYING. If not, write to
+ the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+*/
+
+/*
+ * Tab View, enclosing detailed views for one trace item in
+ * two tab widgets, separated by a splitter
+ */
+
+#ifndef TABVIEW_H
+#define TABVIEW_H
+
+#include <qptrlist.h>
+#include <qwidget.h>
+#include <qtabwidget.h>
+#include <qtabbar.h>
+#include <ksqueezedtextlabel.h>
+#include "traceitemview.h"
+
+class QSplitter;
+class TabView;
+
+/**
+ * Subclass of QTabBar to enable context menu on tabs
+ */
+class TabBar : public QTabBar
+{
+ Q_OBJECT
+
+ public:
+ TabBar(TabView*, QTabWidget* parent, const char *name = 0);
+ protected:
+ void mousePressEvent(QMouseEvent *e);
+
+ private:
+ QTabWidget* _tabWidget;
+ TabView* _tabView;
+};
+
+
+/**
+ * Own Splitter:
+ * Call checkVisiblity for all TabWidget children of the splitter
+ * on a MoveEvent. This typically is produced when collapsing the widget
+ * inside of another splitter.
+ */
+class Splitter: public QSplitter
+{
+ Q_OBJECT
+
+public:
+ Splitter(Orientation o, QWidget* parent = 0, const char* name = 0);
+ void checkVisiblity();
+
+protected:
+ void moveEvent(QMoveEvent *);
+};
+
+
+/**
+ * Own TabView:
+ * - A QTabWidget able to track its visible rect via resizeEvents.
+ * This is needed to track if this widget is collapsed in a QSplitter.
+ * - Use own TabBar for context menu
+ */
+class TabWidget: public QTabWidget
+{
+ Q_OBJECT
+
+public:
+
+ TabWidget(TabView*, QWidget* parent = 0,
+ const char* name = 0, WFlags f = 0);
+
+ bool hasVisibleRect() { return _hasVisibleRect; }
+ void checkVisibility();
+
+signals:
+ void visibleRectChanged(TabWidget*);
+
+protected:
+ void resizeEvent(QResizeEvent *);
+ void showEvent(QShowEvent *);
+ void hideEvent(QHideEvent *);
+ void moveEvent(QMoveEvent *);
+
+private:
+ bool _hasVisibleRect;
+};
+
+
+
+class TabView : public QWidget, public TraceItemView
+{
+ Q_OBJECT
+
+public:
+
+ TabView(TraceItemView* parentView,
+ QWidget* parent = 0, const char* name = 0);
+
+ virtual QWidget* widget() { return this; }
+ QString whatsThis() const ;
+ void setData(TraceData*);
+ bool isViewVisible() const { return !_isCollapsed; }
+ void selected(TraceItemView*, TraceItem*);
+ bool active() const { return _active; }
+ void setActive(bool);
+
+ /**
+ * Rearrange tabs
+ * if <w> == 0, move hidden tabs
+ */
+ void moveTab(QWidget* w, Position, bool wholeArea = false);
+
+ Position tabPosition(QWidget*);
+ int visibleTabs();
+ int visibleAreas();
+
+ void readViewConfig(KConfig*, QString prefix, QString postfix, bool);
+ void saveViewConfig(KConfig*, QString prefix, QString postfix, bool);
+
+public slots:
+ void tabChanged(QWidget*);
+ void visibleRectChangedSlot(TabWidget*);
+
+signals:
+ void activated(TabView*);
+
+protected:
+ void resizeEvent(QResizeEvent *);
+ bool eventFilter(QObject*, QEvent*);
+ void mousePressEvent(QMouseEvent*);
+
+private:
+ TraceItemView* addTab(QString, TraceItemView*);
+ void addTop(TraceItemView*);
+ void addBottom(TraceItemView*);
+ TabWidget* tabWidget(Position);
+ void updateVisibility();
+ void doUpdate(int);
+ void installFocusFilters();
+
+ // this is true if width or height <= 1, and no child updates are done
+ bool _isCollapsed;
+
+ KSqueezedTextLabel* _nameLabel;
+ QSplitter *_mainSplitter, *_leftSplitter, *_bottomSplitter;
+ TabWidget *_topTW, *_leftTW, *_bottomTW, *_rightTW;
+ QPtrList<TraceItemView> _tabs;
+
+ QWidget* _lastFocus;
+ bool _active;
+};
+
+#endif
diff --git a/kcachegrind/kcachegrind/tips b/kcachegrind/kcachegrind/tips
new file mode 100644
index 00000000..1f555c0e
--- /dev/null
+++ b/kcachegrind/kcachegrind/tips
@@ -0,0 +1,141 @@
+<tip category="KCachegrind|Help">
+<html>
+<p>...that the <em>What's This?</em> help for every GUI widget
+in KCachegrind contains detailed usage information for this widget?
+It is highly recommended to read at least these help texts on first
+use. Request <em>What's This?</em> help by pressing
+Shift+F1 and clicking on the widget.</p>
+</html>
+</tip>
+
+<tip category="KCachegrind|Explanation">
+<html>
+<p>...that you can get profile information at instruction level
+with Calltree when you provide the option <em>--dump-instr=yes</em>?
+Use the Assembler View for the instruction annotations.
+</p>
+</html>
+</tip>
+
+<tip category="KCachegrind|Keyboard">
+<html>
+<p>...that you can use Alt-Left/Right keys of your keyboard to go
+back/forward in the active object history ?</p>
+</html>
+</tip>
+
+<tip category="KCachegrind|Keyboard">
+<html>
+<p>...that you can navigate in the Callee/Caller Map View using
+arrow keys? Use Left/Right to change to siblings of the current
+item; use Up/Down to go one nesting level up/down. To select
+the current item, press Space, and to activate it, press Return.
+</p>
+</html>
+</tip>
+
+<tip category="KCachegrind|Keyboard">
+<html>
+<p>...that you can navigate in the Call Graph View using
+arrow keys? Use Up/Down to go one calling level up/down, alternating
+between calls and functions. Use Left/Right to change to siblings of a current
+selected call. To activate the current item, press Return.
+</p>
+</html>
+</tip>
+
+<tip category="KCachegrind|Filters">
+<html>
+<p>...that you can rapidly locate a function by entering part of its
+name (case-insensitive) into the edit line of the toolbar
+and hit return?</p>
+</html>
+</tip>
+
+<tip category="KCachegrind|Appearance">
+<html>
+<p>...that you can assign custom colors to
+ELF objects/C++ Classes/Source Files for graph coloring
+in <em>Settings->Configure KCachegrind...</em>?</p>
+</html>
+</tip>
+
+<tip category="KCachegrind|Configuration">
+<html>
+<p>...that you can see if debug info is available for a selected
+function by looking at the location label in the Info tab or
+the source listing header in the source tab?</p>
+<p>There must be the name of the source file (with extension).
+If KCachegrind still doesn't show the source, make sure that you
+have added the directory of the source file to the
+<em>Source Directories</em> list in the configuration.
+</html>
+</tip>
+
+<tip category="KCachegrind|Appearance">
+<html>
+<p>...that you can configure whether KCachgrind should
+show absolute event counts or relative ones (percentage display)?</p>
+</html>
+</tip>
+
+<tip category="KCachegrind|Appearance">
+<html>
+<p>...that you can configure the maximum number of items
+for all function lists in KCachegrind? Limiting the number
+of items is done to get a fast reacting GUI. The last item in
+the list will show you the number of skipped functions, together
+with a cost condition for these skipped functions.</p>
+<p>To activate a function with small costs, search for it and select
+it in the flat profile. Selecting functions with small cost will
+temporarily add them to the flat profile list.</p>
+</html>
+</tip>
+
+<tip category="KCachegrind|Explanation">
+<html>
+<p>...that the Coverage tab - in contrast to the Call Lists tab -
+shows <em>all</em> functions that are calling the selected function
+(upper part) / are called by the selected function (bottom part),
+no matter how many function are between them on the stack?</p>
+<p>Examples:</p>
+<p>An entry in the upper list for function foo1() with a value of 50%
+with function bar() selected means that 50% of all the cost of function
+bar() happened while called from function foo1().</p>
+<p>An entry in the bottom list for function foo2() with a value of 50%
+with function bar() selected means that 50% of all the cost of function
+bar() happened while calling foo2() from bar().</p>
+</html>
+</tip>
+
+<tip category="KCachegrind|Explanation">
+<html>
+<p>...that waiting for the tool tip inside of a tree map
+shows the list of names of the nested rectangles the mouse
+pointer is over?</p>
+<p>Items from this list can be selected by pressing the right
+mouse button.</p>
+</html>
+</tip>
+
+<tip category="KCachegrind|Explanation">
+<html>
+<p>...that you can constrain the cost counts shown to only a
+few parts of the whole trace by selecting these parts in the
+"Trace Selection" Dockable?</p>
+<p>To generate multiple parts in a profiling run with
+cachegrind, use e.g. option --cachedumps=xxx for parts
+of a length of xxx basic blocks (A basic block is a run
+of not-branching assembler statements inside of your program
+code).</p>
+</html>
+</tip>
+
+<tip category="KCachegrind|Explanation">
+<p>...that by splitting the view to show information of
+two functions simultaniously, selecting a function in
+one panel shows the information for that function
+in the other panel?</p>
+</html>
+</tip>
+
diff --git a/kcachegrind/kcachegrind/toplevel.cpp b/kcachegrind/kcachegrind/toplevel.cpp
new file mode 100644
index 00000000..328a6bdb
--- /dev/null
+++ b/kcachegrind/kcachegrind/toplevel.cpp
@@ -0,0 +1,2399 @@
+/* This file is part of KCachegrind.
+ Copyright (C) 2002, 2003 Josef Weidendorfer <Josef.Weidendorfer@gmx.de>
+
+ KCachegrind is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public
+ License as published by the Free Software Foundation, version 2.
+
+ 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; see the file COPYING. If not, write to
+ the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+*/
+
+/*
+ * KCachegrind top level window
+ */
+
+#define TRACE_UPDATES 0
+#define ENABLE_DUMPDOCK 0
+
+#include <stdlib.h> // for system()
+
+#include <qvbox.h>
+#include <qtimer.h>
+#include <qwhatsthis.h>
+#include <qlineedit.h>
+#include <qtextstream.h>
+#include <qsizepolicy.h>
+#include <qprogressbar.h>
+#include <qfile.h>
+
+// With Qt 3.1, we can disallow user interaction with long tasks.
+// This needs QEventLoop. Otherwise, QApplication::processEvents is used.
+#if (QT_VERSION-0 >= 0x030100)
+#include <qeventloop.h>
+#endif
+
+#include <kapplication.h>
+#include <klocale.h>
+#include <kstatusbar.h>
+#include <kstdaccel.h>
+#include <kstdaction.h>
+#include <kaction.h>
+#include <kurl.h>
+#include <kfiledialog.h>
+#include <kio/netaccess.h>
+#include <kedittoolbar.h>
+#include <kkeydialog.h>
+#include <ktip.h>
+#include <kpopupmenu.h>
+#include <kdebug.h>
+
+#if ENABLE_DUMPDOCK
+#include "dumpselection.h"
+#endif
+
+#include "toplevel.h"
+#include "partselection.h"
+#include "functionselection.h"
+#include "stackselection.h"
+#include "stackbrowser.h"
+#include "tracedata.h"
+#include "configuration.h"
+#include "configdlg.h"
+#include "multiview.h"
+#include "callgraphview.h"
+
+
+TopLevel::TopLevel(const char *name)
+ : KMainWindow(0, name), DCOPObject("KCachegrindIface")
+{
+ init();
+
+ createDocks();
+
+ _multiView = new MultiView(this, this, "MultiView");
+ setCentralWidget(_multiView);
+
+ createActions();
+
+ _partDockShown->setChecked(!_partDock->isHidden());
+ _stackDockShown->setChecked(!_stackDock->isHidden());
+ _functionDockShown->setChecked(!_functionDock->isHidden());
+
+ connect(_partDock, SIGNAL(visibilityChanged(bool)),
+ this, SLOT(partVisibilityChanged(bool)));
+ connect(_stackDock, SIGNAL(visibilityChanged(bool)),
+ this, SLOT(stackVisibilityChanged(bool)));
+ connect(_functionDock, SIGNAL(visibilityChanged(bool)),
+ this, SLOT(functionVisibilityChanged(bool)));
+
+#if ENABLE_DUMPDOCK
+ _dumpDockShown->setChecked(!_dumpDock->isHidden());
+ connect(_dumpDock, SIGNAL(visibilityChanged(bool)),
+ this, SLOT(dumpVisibilityChanged(bool)));
+#endif
+
+ _statusbar = statusBar();
+ _statusLabel = new QLabel(_statusbar);
+#if 0
+ // how to do avoid main window resizing on large statusbar label?
+ QSizePolicy p(QSizePolicy::Fixed, QSizePolicy::Expanding);
+ _statusLabel->setSizePolicy(p);
+ _statusbar->setSizePolicy(p);
+#endif
+ _statusbar->addWidget(_statusLabel, 1);
+
+ KConfig* kconfig = KGlobal::config();
+ Configuration::readOptions( kconfig );
+ _openRecent->loadEntries( kconfig );
+
+ // set toggle after reading configuration
+ _showPercentage = Configuration::showPercentage();
+ _showExpanded = Configuration::showExpanded();
+ _showCycles = Configuration::showCycles();
+ _taPercentage->setChecked(_showPercentage);
+ _taExpanded->setChecked(_showExpanded);
+ _taCycles->setChecked(_showCycles);
+
+ setupPartSelection(_partSelection);
+
+ // KCachegrind for KDE 3.0.x does not allow to hide toolbars...
+#if KDE_VERSION >= 308 // KDE 3.1
+ setStandardToolBarMenuEnabled(true);
+#endif
+
+ // QT dock windows are created before (using QT position restoring)
+ createGUI();
+
+ setAutoSaveSettings();
+
+ // restore current state settings (not configuration options)
+ restoreCurrentState(QString::null);
+
+ // if this is the first toplevel, show tip of day
+ if (memberList->count() == 1)
+ QTimer::singleShot( 200, this, SLOT(slotShowTipOnStart()) );
+}
+
+void TopLevel::init()
+{
+ _activeParts.clear();
+ _hiddenParts.clear();
+
+ _progressBar = 0;
+
+ _data = 0;
+ _function = 0;
+ _costType = 0;
+ _costType2 = 0;
+ _groupType = TraceCost::NoCostType;
+ _group = 0;
+
+ _layoutCurrent = 0;
+ _layoutCount = 1;
+
+ // for delayed slots
+ _traceItemDelayed = 0;
+ _costTypeDelayed = 0;
+ _costType2Delayed = 0;
+ _groupTypeDelayed = TraceCost::NoCostType;
+ _groupDelayed = 0;
+ _directionDelayed = TraceItemView::None;
+ _lastSender = 0;
+}
+
+
+/**
+ * Setup the part selection widget.
+ * Statusbar has to be created before.
+ */
+void TopLevel::setupPartSelection(PartSelection* ps)
+{
+ // setup connections from the part selection widget
+
+ connect(ps, SIGNAL(activePartsChanged(const TracePartList&)),
+ this, SLOT(activePartsChangedSlot(const TracePartList&)));
+ connect(ps, SIGNAL(groupChanged(TraceCostItem*)),
+ this, SLOT(setGroupDelayed(TraceCostItem*)));
+ connect(ps, SIGNAL(functionChanged(TraceItem*)),
+ this, SLOT(setTraceItemDelayed(TraceItem*)));
+
+ connect(ps, SIGNAL(goBack()),
+ _stackSelection, SLOT(browserBack()));
+
+ connect(ps, SIGNAL(partsHideSelected()),
+ this, SLOT(partsHideSelectedSlotDelayed()));
+ connect(ps, SIGNAL(partsUnhideAll()),
+ this, SLOT(partsUnhideAllSlotDelayed()));
+
+ connect(ps, SIGNAL(showMessage(const QString&, int)),
+ _statusbar, SLOT(message(const QString&, int)));
+}
+
+/**
+ * This saves the current state of the main window and
+ * sub widgets.
+ *
+ * No positions are saved. These is done automatically for
+ * KToolbar, and manually in queryExit() for QT docks.
+ */
+void TopLevel::saveCurrentState(QString postfix)
+{
+ KConfig* kconfig = KGlobal::config();
+ QCString pf = postfix.ascii();
+
+ KConfigGroup psConfig(kconfig, QCString("PartOverview")+pf);
+ _partSelection->saveVisualisationConfig(&psConfig);
+
+ KConfigGroup stateConfig(kconfig, QCString("CurrentState")+pf);
+ stateConfig.writeEntry("CostType",
+ _costType ? _costType->name() : QString("?"));
+ stateConfig.writeEntry("CostType2",
+ _costType2 ? _costType2->name() : QString("?"));
+ stateConfig.writeEntry("GroupType", TraceItem::typeName(_groupType));
+
+ _multiView->saveViewConfig(kconfig, QString("MainView"), postfix, true);
+}
+
+/**
+ * This function is called when a trace is closed.
+ * Save browsing position for later restoring
+ */
+void TopLevel::saveTraceSettings()
+{
+ QString key = traceKey();
+
+ KConfigGroup pConfig(KGlobal::config(), QCString("TracePositions"));
+ pConfig.writeEntry(QString("CostType%1").arg(key),
+ _costType ? _costType->name() : QString("?"));
+ pConfig.writeEntry(QString("CostType2%1").arg(key),
+ _costType2 ? _costType2->name() : QString("?"));
+ pConfig.writeEntry(QString("GroupType%1").arg(key),
+ TraceItem::typeName(_groupType));
+
+ if (!_data) return;
+
+ KConfigGroup aConfig(KGlobal::config(), QCString("Layouts"));
+ aConfig.writeEntry(QString("Count%1").arg(key), _layoutCount);
+ aConfig.writeEntry(QString("Current%1").arg(key), _layoutCurrent);
+
+ saveCurrentState(key);
+ pConfig.writeEntry(QString("Group%1").arg(key),
+ _group ? _group->name() : QString::null);
+}
+
+/**
+ * This restores the current state of the main window and
+ * sub widgets.
+ *
+ * This does NOT restore any positions. This is done automatically for
+ * KToolbar, and manually in the createDocks() for QT docks..
+ */
+void TopLevel::restoreCurrentState(QString postfix)
+{
+ KConfig* kconfig = KGlobal::config();
+ QStringList gList = kconfig->groupList();
+ QCString pf = postfix.ascii();
+
+ // dock properties (not position, this should be have done before)
+ QCString group = QCString("PartOverview");
+ if (gList.contains(group+pf)) group += pf;
+ KConfigGroup psConfig(kconfig, group);
+ _partSelection->readVisualisationConfig(&psConfig);
+
+ _multiView->readViewConfig(kconfig, QString("MainView"), postfix, true);
+ _taSplit->setChecked(_multiView->childCount()>1);
+ _taSplitDir->setEnabled(_multiView->childCount()>1);
+ _taSplitDir->setChecked(_multiView->orientation() == Qt::Horizontal);
+}
+
+
+void TopLevel::createDocks()
+{
+ _partDock = new QDockWindow(QDockWindow::InDock, this);
+ _partDock->setCaption(i18n("Parts Overview"));
+ _partDock->setCloseMode( QDockWindow::Always );
+ _partSelection = new PartSelection(_partDock, "partSelection");
+ _partDock->setWidget(_partSelection);
+ _partDock->setResizeEnabled(true);
+ _partDock->setFixedExtentWidth(200);
+ QWhatsThis::add( _partSelection, i18n(
+ "<b>The Parts Overview</b>"
+ "<p>A trace consists of multiple trace parts when "
+ "there are several profile data files from one profile run. "
+ "The Trace Part Overview dockable shows these, "
+ "horizontally ordered in execution time; "
+ "the rectangle sizes are proportional to the total "
+ "cost spent in the parts. You can select one or several "
+ "parts to constrain all costs shown to these parts only."
+ "</p>"
+ "<p>The parts are further subdivided: there is a "
+ "partitioning and an callee split mode: "
+ "<ul><li>Partitioning: You see the "
+ "partitioning into groups for a trace part, according to "
+ "the group type selected. E.g. if ELF object groups are "
+ "selected, you see colored rectangles for each "
+ "used ELF object (shared library or executable), sized "
+ "according to the cost spent therein.</li>"
+ "<li>Callee: A rectangle showing the inclusive "
+ "cost of the current selected function in the trace part "
+ "is shown. "
+ "This is split up into smaller rectangles to show the costs of its "
+ "callees.</li></ul></p>"));
+
+ _stackDock = new QDockWindow(QDockWindow::InDock, this);
+ _stackDock->setResizeEnabled(true);
+ // Why is the caption only correct with a close button?
+ _stackDock->setCloseMode( QDockWindow::Always );
+ _stackSelection = new StackSelection(_stackDock, "stackSelection");
+ _stackDock->setWidget(_stackSelection);
+ _stackDock->setFixedExtentWidth(200);
+ _stackDock->setCaption(i18n("Top Cost Call Stack"));
+ QWhatsThis::add( _stackSelection, i18n(
+ "<b>The Top Cost Call Stack</b>"
+ "<p>This is a purely fictional 'most probable' call stack. "
+ "It is built up by starting with the current selected "
+ "function and adds the callers/callees with highest cost "
+ "at the top and to bottom.</p>"
+ "<p>The <b>Cost</b> and <b>Calls</b> columns show the "
+ "cost used for all calls from the function in the line "
+ "above.</p>"));
+
+ connect(_stackSelection, SIGNAL(functionSelected(TraceItem*)),
+ this, SLOT(setTraceItemDelayed(TraceItem*)));
+
+ _functionDock = new QDockWindow(QDockWindow::InDock, this);
+ _functionDock->setCaption(i18n("Flat Profile"));
+ _functionDock->setCloseMode( QDockWindow::Always );
+ _functionSelection = new FunctionSelection(this, _functionDock,
+ "functionSelection");
+ _functionSelection->setTopLevel(this);
+
+ _functionDock->setWidget(_functionSelection);
+ _functionDock->setResizeEnabled(true);
+ _functionDock->setFixedExtentWidth(200);
+ QWhatsThis::add( _functionSelection, i18n(
+ "<b>The Flat Profile</b>"
+ "<p>The flat profile contains a group and a function "
+ "selection list. The group list contains all groups "
+ "where costs "
+ "are spent in, depending on the chosen group type. "
+ "The group list is hidden when group type 'Function' "
+ "is selected.<p>"
+ "<p>The function list contains the functions of the "
+ "selected group (or all for 'Function' group type), "
+ "ordered by the costs spent therein. Functions with "
+ "costs less than 1% are hidden on default.</p>"));
+
+#if ENABLE_DUMPDOCK
+ _dumpDock = new QDockWindow(QDockWindow::InDock, this);
+ _dumpDock->setCaption(i18n("Profile Dumps"));
+ _dumpDock->setCloseMode( QDockWindow::Always );
+ _dumpSelection = new DumpSelection(this, _dumpDock,
+ "dumpSelection");
+ _dumpSelection->setTopLevel(this);
+
+ _dumpDock->setWidget(_dumpSelection);
+ _dumpDock->setResizeEnabled(true);
+ _dumpDock->setFixedExtentWidth(200);
+ QWhatsThis::add( _dumpSelection, i18n(
+ "<b>Profile Dumps</b>"
+ "<p>This dockable shows in the top part the list of "
+ "loadable profile dumps in all subdirectories of: "
+ "<ul><li>current working directory of KCachegrind, "
+ "i.e. where it was started from, and "
+ "<li>the default profile dump directory given in the "
+ "configuration.</ul> "
+ "The list is sorted according the the target command "
+ "profiled in the corresponding dump.</p>"
+ "<p>On selecting a profile dump, information for it "
+ "is shown in the bottom area of the dockable: "
+ "<ul><li><b>Options</b> allows you to view the profiled "
+ "command and profile options of this dump. By changing "
+ "any item, a new (yet unexisting) profile template "
+ "is created. Press <b>Run Profile</b> to start a"
+ "profile run with these options in the background. "
+ "<li><b>Info</b> gives detailed info on the selected "
+ "dump like event cost summary and properties of the "
+ "simulated cache. "
+ "<li><b>State</b> is only available for current happening "
+ "profiles runs. Press <b>Update</b> to see different "
+ "counters of the run, and a stack trace of the current "
+ "position in the program profiled. Check the <b>Every</b> "
+ "option to let KCachegrind regularly poll these data. "
+ "Check the <b>Sync</b> option to let the dockable activate "
+ "the top function in the current loaded dump.</ul></p>"));
+#endif
+
+ // Restore QT Dock positions...
+ KConfigGroup dockConfig(KGlobal::config(), QCString("Docks"));
+ QString str = dockConfig.readEntry("Position", QString::null);
+ if (0) qDebug("Docks/Position: '%s'", str.ascii());
+ if (str.isEmpty()) {
+ // default positions
+ addDockWindow(_partDock, DockLeft);
+ addDockWindow(_stackDock, DockLeft);
+ addDockWindow(_functionDock, DockLeft);
+ _stackDock->hide();
+#if ENABLE_DUMPDOCK
+ addDockWindow(_dumpDock, DockLeft);
+ _dumpDock->hide();
+#endif
+ }
+ else {
+ QTextStream ts( &str, IO_ReadOnly );
+ ts >> *this;
+ }
+ _forcePartDock = dockConfig.readBoolEntry("ForcePartDockVisible", false);
+
+#if 0
+ // dock context menu
+ setAppropriate(_partDock, true);
+ setAppropriate(_stackDock, true);
+ setAppropriate(_dumpDock, true);
+ setAppropriate(_functionDock, true);
+
+ connect( _partDock, SIGNAL(contextMenuRequested(const QPoint &)),
+ this, SLOT(showDockMenu(const QPoint &)));
+#endif
+}
+
+
+TopLevel::~TopLevel()
+{
+ delete _data;
+}
+
+
+void TopLevel::saveProperties(KConfig* c)
+{
+ c->writeEntry("TraceName", _data->traceName());
+}
+
+void TopLevel::readProperties(KConfig* c)
+{
+ QString traceName = c->readEntry("TraceName");
+ if (!traceName.isEmpty()) {
+ TraceData* d = new TraceData(this);
+ d->load(traceName);
+ setData(d);
+ }
+}
+
+void TopLevel::createLayoutActions()
+{
+ QString hint;
+ KAction* action;
+
+ action = new KAction( i18n( "&Duplicate" ),
+ KShortcut(KKey("Ctrl+Plus")),
+ this, SLOT(layoutDuplicate()),
+ actionCollection(), "layout_duplicate" );
+ hint = i18n("<b>Duplicate Current Layout</b>"
+ "<p>Make a copy of the current layout.</p>");
+ action->setWhatsThis( hint );
+
+ action = new KAction( i18n( "&Remove" ), KShortcut(),
+ this, SLOT(layoutRemove()),
+ actionCollection(), "layout_remove" );
+ hint = i18n("<b>Remove Current Layout</b>"
+ "<p>Delete current layout and make the previous active.</p>");
+ action->setWhatsThis( hint );
+
+ action = new KAction( i18n( "&Go to Next" ),
+ KShortcut(KKey("Ctrl+Right")),
+ this, SLOT(layoutNext()),
+ actionCollection(), "layout_next" );
+ hint = i18n("Go to Next Layout");
+ action->setWhatsThis( hint );
+
+ action = new KAction( i18n( "&Go to Previous" ),
+ KShortcut(KKey("Ctrl+Left")),
+ this, SLOT(layoutPrevious()),
+ actionCollection(), "layout_previous" );
+ hint = i18n("Go to Previous Layout");
+ action->setWhatsThis( hint );
+
+ action = new KAction( i18n( "&Restore to Default" ), KShortcut(),
+ this, SLOT(layoutRestore()),
+ actionCollection(), "layout_restore" );
+ hint = i18n("Restore Layouts to Default");
+ action->setWhatsThis( hint );
+
+ action = new KAction( i18n( "&Save as Default" ), KShortcut(),
+ this, SLOT(layoutSave()),
+ actionCollection(), "layout_save" );
+ hint = i18n("Save Layouts as Default");
+ action->setWhatsThis( hint );
+}
+
+// TODO: split this up...
+void TopLevel::createMiscActions()
+{
+ QString hint;
+ KAction* action;
+
+ action = KStdAction::openNew(this, SLOT(newWindow()), actionCollection());
+ hint = i18n("<b>New</b><p>Open new empty KCachegrind window.</p>");
+ action->setWhatsThis( hint );
+
+ action = new KAction( i18n( "&Add..." ), KShortcut(),
+ this, SLOT(addTrace()),
+ actionCollection(), "file_add" );
+ hint = i18n("<b>Add Profile Data</b>"
+ "<p>This opens an additional profile data file in the current window.</p>");
+ action->setWhatsThis( hint );
+
+ action = new KAction( i18n( "&Reload" ), "reload",
+#if KDE_VERSION > 0x030190
+ // for KDE 3.2: KStdAccel::key is deprecated
+ KStdAccel::shortcut(KStdAccel::Reload),
+#else
+ KStdAccel::key(KStdAccel::Reload),
+#endif
+ this, SLOT( reload() ), actionCollection(), "reload" );
+ hint = i18n("<b>Reload Profile Data</b>"
+ "<p>This loads any new created parts, too.</p>");
+ action->setWhatsThis( hint );
+
+ action = new KAction( i18n( "&Export Graph" ), KShortcut(),
+ this, SLOT(exportGraph()),
+ actionCollection(), "export" );
+
+ hint = i18n("<b>Export Call Graph</b>"
+ "<p>Generates a file with extension .dot for the tools "
+ "of the GraphViz package.</p>");
+ action->setWhatsThis( hint );
+
+
+ _taDump = new KToggleAction( i18n( "&Force Dump" ), "redo",
+#if KDE_VERSION > 0x030190
+ // for KDE 3.2: KStdAccel::key is deprecated
+ KStdAccel::shortcut(KStdAccel::Redo),
+#else
+ KStdAccel::key(KStdAccel::Redo),
+#endif
+ this, SLOT( forceTrace() ),
+ actionCollection(), "dump" );
+ hint = i18n("<b>Force Dump</b>"
+ "<p>This forces a dump for a Callgrind profile run "
+ "in the current directory. This action is checked while "
+ "KCachegrind looks for the dump. If the dump is "
+ "finished, it automatically reloads the current trace. "
+ "If this is the one from the running Callgrind, the new "
+ "created trace part will be loaded, too.</p>"
+ "<p>Force dump creates a file 'callgrind.cmd', and "
+ "checks every second for its existence. A running "
+ "Callgrind will detect this file, dump a trace part, "
+ "and delete 'callgrind.cmd'. "
+ "The deletion is detected by KCachegrind, "
+ "and it does a Reload. If there's <em>no</em> Callgrind "
+ "running, press 'Force Dump' again to cancel the dump "
+ "request. This deletes 'callgrind.cmd' itself and "
+ "stops polling for a new dump.</p>"
+ "<p>Note: A Callgrind run <em>only</em> detects "
+ "existence of 'callgrind.cmd' when actively running "
+ "a few milliseconds, i.e. "
+ "<em>not</em> sleeping. Tip: For a profiled GUI program, "
+ "you can awake Callgrind e.g. by resizing a window "
+ "of the program.</p>");
+ _taDump->setWhatsThis( hint );
+
+ action = KStdAction::open(this, SLOT(loadTrace()), actionCollection());
+ hint = i18n("<b>Open Profile Data</b>"
+ "<p>This opens a profile data file, with possible multiple parts</p>");
+ action->setToolTip( hint );
+ action->setWhatsThis( hint );
+
+ _openRecent = KStdAction::openRecent(this, SLOT(loadTrace(const KURL&)),
+ actionCollection());
+
+ KStdAction::showStatusbar(this,
+ SLOT(toggleStatusBar()), actionCollection());
+
+ _partDockShown = new KToggleAction(i18n("Parts Overview"), KShortcut(),
+ this, SLOT(togglePartDock()),
+ actionCollection(),
+ "settings_show_partdock");
+
+ hint = i18n("Show/Hide the Parts Overview Dockable");
+ _partDockShown->setToolTip( hint );
+ _partDockShown->setWhatsThis( hint );
+
+ _stackDockShown = new KToggleAction(i18n("Call Stack"), KShortcut(),
+ this, SLOT(toggleStackDock()),
+ actionCollection(),
+ "settings_show_stackdock");
+
+ hint = i18n("Show/Hide the Call Stack Dockable");
+ _stackDockShown->setToolTip( hint );
+ _stackDockShown->setWhatsThis( hint );
+
+ _functionDockShown = new KToggleAction(i18n("Function Profile"), KShortcut(),
+ this, SLOT(toggleFunctionDock()),
+ actionCollection(),
+ "settings_show_profiledock");
+
+ hint = i18n("Show/Hide the Function Profile Dockable");
+ _functionDockShown->setToolTip( hint );
+ _functionDockShown->setWhatsThis( hint );
+
+#if ENABLE_DUMPDOCK
+ _dumpDockShown = new KToggleAction(i18n("Profile Dumps"), KShortcut(),
+ this, SLOT(toggleDumpDock()),
+ actionCollection(),
+ "settings_show_dumpdock");
+
+ hint = i18n("Show/Hide the Profile Dumps Dockable");
+ _dumpDockShown->setToolTip( hint );
+ _dumpDockShown->setWhatsThis( hint );
+#endif
+
+ _taPercentage = new KToggleAction(i18n("Show Relative Costs"), "percent",
+ KShortcut(),
+ this, SLOT(togglePercentage()),
+ actionCollection(),
+ "view_percentage");
+#if KDE_VERSION >= 0x030290
+ // for KDE 3.3: show another text instead of a checkmark
+ _taPercentage->setCheckedState(i18n("Show Absolute Costs"));
+#endif
+
+ hint = i18n("Show relative instead of absolute costs");
+ _taPercentage->setToolTip( hint );
+ _taPercentage->setWhatsThis( hint );
+
+ _taExpanded = new KToggleAction(i18n("Percentage Relative to Parent"), "move",
+ KShortcut(),
+ this, SLOT(toggleExpanded()),
+ actionCollection(),
+ "view_expanded");
+
+ hint = i18n("Show percentage costs relative to parent");
+ _taExpanded->setToolTip( hint );
+ _taExpanded->setWhatsThis( hint );
+
+ hint = i18n("<b>Show percentage costs relative to parent</b>"
+ "<p>If this is switched off, percentage costs are always shown "
+ "relative to the total cost of the profile part(s) that are "
+ "currently browsed. By turning on this option, percentage cost "
+ "of shown cost items will be relative to the parent cost item."
+ "<ul><table>"
+ "<tr><td><b>Cost Type</td><td><b>Parent Cost</td></tr>"
+ "<tr><td>Function Cumulative</td><td>Total</td></tr>"
+ "<tr><td>Function Self</td><td>Function Group (*) / Total</td></tr>"
+ "<tr><td>Call</td><td>Function Cumulative</td></tr>"
+ "<tr><td>Source Line</td><td>Function Cumulative</td></tr>"
+ "</table>"
+ "<p>(*) Only if function grouping is switched on (e.g. ELF object grouping).");
+ _taExpanded->setWhatsThis( hint );
+
+ _taCycles = new KToggleAction( i18n( "Do Cycle Detection" ), "undo",
+ KShortcut(),
+ this, SLOT( toggleCycles() ), actionCollection(),
+ "view_cycles" );
+#if KDE_VERSION >= 0x030290
+ // for KDE 3.3: show another text instead of a checkmark
+ _taCycles->setCheckedState(i18n("Skip Cycle Detection"));
+#endif
+
+ hint = i18n("<b>Detect recursive cycles</b>"
+ "<p>If this is switched off, the treemap drawing will show "
+ "black areas when a recursive call is made instead of drawing the "
+ "recursion ad infinitum. Note that "
+ "the size of black areas often will be wrong, as inside recursive "
+ "cycles the cost of calls cannot be determined; the error is small, "
+ "however, for false cycles (see documentation)."
+ "<p>The correct handling for cycles is to detect them and collapse all "
+ "functions of a cycle into a virtual function, which is done when this "
+ "option is selected. Unfortunately, with GUI applications, this often will "
+ "lead to huge false cycles, making the analysis impossible; therefore, there "
+ "is the option to switch this off.");
+ _taCycles->setWhatsThis( hint );
+
+ KStdAction::quit(this, SLOT(close()), actionCollection());
+ KStdAction::preferences(this, SLOT(configure()), actionCollection());
+ KStdAction::keyBindings(this, SLOT(configureKeys()), actionCollection());
+ KStdAction::configureToolbars(this,SLOT(configureToolbars()),
+ actionCollection());
+#if 0
+ action = KStdAction::back(_stackSelection, SLOT(browserBack()),
+ actionCollection());
+ hint = i18n("Go back in function selection history");
+ action->setToolTip( hint );
+ action->setWhatsThis( hint );
+
+ action = KStdAction::forward(_stackSelection, SLOT(browserForward()),
+ actionCollection());
+ hint = i18n("Go forward in function selection history");
+ action->setToolTip( hint );
+ action->setWhatsThis( hint );
+
+ action = KStdAction::up(_stackSelection, SLOT(browserUp()),
+ actionCollection());
+ hint = i18n("<b>Go Up</b>"
+ "<p>Go to last selected caller of current function. "
+ "If no caller was visited, use that with highest cost.</p>");
+ action->setToolTip( hint );
+ action->setWhatsThis( hint );
+#else
+ _paUp = new KToolBarPopupAction( i18n( "&Up" ), "up",
+ ALT+Key_Up,
+ _stackSelection, SLOT( browserUp() ),
+ actionCollection(), "go_up" );
+ connect( _paUp->popupMenu(), SIGNAL( aboutToShow() ),
+ this, SLOT( upAboutToShow() ) );
+ connect( _paUp->popupMenu(), SIGNAL( activated( int ) ),
+ this, SLOT( upActivated( int ) ) );
+ hint = i18n("<b>Go Up</b>"
+ "<p>Go to last selected caller of current function. "
+ "If no caller was visited, use that with highest cost.</p>");
+ _paUp->setToolTip( hint );
+ _paUp->setWhatsThis( hint );
+
+ QPair< KGuiItem, KGuiItem > backForward = KStdGuiItem::backAndForward();
+ _paBack = new KToolBarPopupAction( backForward.first, ALT+Key_Left,
+ _stackSelection, SLOT(browserBack()),
+ actionCollection(), "go_back" );
+ connect( _paBack->popupMenu(), SIGNAL( aboutToShow() ),
+ this, SLOT( backAboutToShow() ) );
+ connect( _paBack->popupMenu(), SIGNAL( activated( int ) ),
+ this, SLOT( backActivated( int ) ) );
+ hint = i18n("Go back in function selection history");
+ _paBack->setToolTip( hint );
+ _paBack->setWhatsThis( hint );
+
+ _paForward = new KToolBarPopupAction( backForward.second, ALT+Key_Right,
+ _stackSelection,
+ SLOT(browserForward()),
+ actionCollection(), "go_forward" );
+ connect( _paForward->popupMenu(), SIGNAL( aboutToShow() ),
+ this, SLOT( forwardAboutToShow() ) );
+ connect( _paForward->popupMenu(), SIGNAL( activated( int ) ),
+ this, SLOT( forwardActivated( int ) ) );
+ hint = i18n("Go forward in function selection history");
+ _paForward->setToolTip( hint );
+ _paForward->setWhatsThis( hint );
+#endif
+
+ _saCost = new KSelectAction( i18n("Primary Event Type"), KShortcut(),
+ actionCollection(), "view_cost_type");
+ hint = i18n("Select primary event type of costs");
+ _saCost->setComboWidth(300);
+ _saCost->setToolTip( hint );
+ _saCost->setWhatsThis( hint );
+
+ // cost types are dependent on loaded data, thus KSelectAction
+ // is filled in setData()
+ connect( _saCost, SIGNAL(activated(const QString&)),
+ this, SLOT(costTypeSelected(const QString&)));
+
+ _saCost2 = new KSelectAction( i18n("Secondary Event Type"), KShortcut(),
+ actionCollection(), "view_cost_type2");
+ hint = i18n("Select secondary event type for cost e.g. shown in annotations");
+ _saCost2->setComboWidth(300);
+ _saCost2->setToolTip( hint );
+ _saCost2->setWhatsThis( hint );
+
+ connect( _saCost2, SIGNAL(activated(const QString&)),
+ this, SLOT(costType2Selected(const QString&)));
+
+ saGroup = new KSelectAction( i18n("Grouping"), KShortcut(),
+ actionCollection(), "view_group_type");
+
+ hint = i18n("Select how functions are grouped into higher level cost items");
+ saGroup->setToolTip( hint );
+ saGroup->setWhatsThis( hint );
+
+ QStringList args;
+
+ args << i18n("(No Grouping)")
+ << TraceCost::i18nTypeName(TraceItem::Object)
+ << TraceCost::i18nTypeName(TraceItem::File)
+ << TraceCost::i18nTypeName(TraceItem::Class)
+ << TraceCost::i18nTypeName(TraceItem::FunctionCycle);
+
+ saGroup->setItems(args);
+ connect( saGroup, SIGNAL(activated(int)),
+ this, SLOT(groupTypeSelected(int)));
+
+ _taSplit = new KToggleAction(i18n("Split"), "view_left_right", KShortcut(),
+ this, SLOT(splitSlot()),
+ actionCollection(), "view_split");
+
+ hint = i18n("Show two information panels");
+ _taSplit->setToolTip( hint );
+ _taSplit->setWhatsThis( hint );
+
+ _taSplitDir = new KToggleAction(i18n("Split Horizontal"),
+ "view_left_right", KShortcut(),
+ this, SLOT(splitDirSlot()),
+ actionCollection(), "view_split_dir");
+
+ hint = i18n("Change Split Orientation when main window is split.");
+ _taSplitDir->setToolTip( hint );
+ _taSplitDir->setWhatsThis( hint );
+
+ // copied from KMail...
+#if KDE_VERSION >= 308 // KDE 3.1
+ KStdAction::tipOfDay( this, SLOT( slotShowTip() ), actionCollection() );
+#else
+ (void) new KAction( KGuiItem( i18n("Tip of the &Day..."), "idea",
+ i18n("Show \"Tip of the Day\"") ),
+ 0, this, SLOT(slotShowTip()),
+ actionCollection(), "help_show_tip" );
+#endif
+}
+
+void TopLevel::createActions()
+{
+ createMiscActions();
+ createLayoutActions();
+}
+
+void TopLevel::toggleStatusBar()
+{
+ if (statusBar()->isVisible())
+ statusBar()->hide();
+ else
+ statusBar()->show();
+}
+
+void TopLevel::togglePartDock()
+{
+ if (!_partDock->isVisible())
+ _partDock->show();
+ else
+ _partDock->hide();
+}
+
+void TopLevel::toggleStackDock()
+{
+ if (!_stackDock->isVisible())
+ _stackDock->show();
+ else
+ _stackDock->hide();
+}
+
+void TopLevel::toggleDumpDock()
+{
+#if ENABLE_DUMPDOCK
+ if (!_dumpDock->isVisible())
+ _dumpDock->show();
+ else
+ _dumpDock->hide();
+#endif
+}
+
+void TopLevel::toggleFunctionDock()
+{
+ if (!_functionDock->isVisible())
+ _functionDock->show();
+ else
+ _functionDock->hide();
+}
+
+void TopLevel::togglePercentage()
+{
+ setPercentage(_taPercentage->isChecked());
+}
+
+void TopLevel::setAbsoluteCost()
+{
+ setPercentage(false);
+}
+
+void TopLevel::setRelativeCost()
+{
+ setPercentage(true);
+}
+
+void TopLevel::setPercentage(bool show)
+{
+ if (_showPercentage == show) return;
+ _showPercentage = show;
+ if (_taPercentage->isChecked() != show)
+ _taPercentage->setChecked(show);
+
+ // FIXME: Delete when no view gets this config from Configuration
+ Configuration::setShowPercentage(_showPercentage);
+
+ _partSelection->refresh();
+ _stackSelection->refresh();
+
+ _functionSelection->notifyChange(TraceItemView::configChanged);
+ _functionSelection->updateView();
+
+ _multiView->notifyChange(TraceItemView::configChanged);
+ _multiView->updateView();
+}
+
+void TopLevel::toggleExpanded()
+{
+ bool show = _taExpanded->isChecked();
+ if (_showExpanded == show) return;
+ _showExpanded = show;
+
+ // FIXME: Delete when no view gets this config from Configuration
+ Configuration::setShowExpanded(_showExpanded);
+
+ _partSelection->refresh();
+ _stackSelection->refresh();
+
+ _functionSelection->notifyChange(TraceItemView::configChanged);
+ _functionSelection->updateView();
+
+ _multiView->notifyChange(TraceItemView::configChanged);
+ _multiView->updateView();
+}
+
+void TopLevel::toggleCycles()
+{
+ bool show = _taCycles->isChecked();
+ if (_showCycles == show) return;
+ _showCycles = show;
+
+ // FIXME: Delete when no view gets this config from Configuration
+ Configuration::setShowCycles(_showCycles);
+
+ if (!_data) return;
+
+ _data->invalidateDynamicCost();
+ _data->updateFunctionCycles();
+
+ _partSelection->refresh();
+ _stackSelection->rebuildStackList();
+
+ _functionSelection->notifyChange(TraceItemView::configChanged);
+ _functionSelection->updateView();
+
+ _multiView->notifyChange(TraceItemView::configChanged);
+ _multiView->updateView();
+}
+
+void TopLevel::partVisibilityChanged(bool v)
+{
+ _partDockShown->setChecked(v);
+}
+
+void TopLevel::stackVisibilityChanged(bool v)
+{
+ _stackDockShown->setChecked(v);
+}
+
+#if ENABLE_DUMPDOCK
+void TopLevel::dumpVisibilityChanged(bool v)
+#else
+void TopLevel::dumpVisibilityChanged(bool)
+#endif
+{
+#if ENABLE_DUMPDOCK
+ _dumpDockShown->setChecked(v);
+#endif
+}
+
+void TopLevel::functionVisibilityChanged(bool v)
+{
+ _functionDockShown->setChecked(v);
+ if (v)
+ _functionSelection->updateView();
+}
+
+
+void TopLevel::querySlot()
+{
+ _functionSelection->query(queryLineEdit->text());
+}
+
+void TopLevel::configureKeys()
+{
+#if KDE_VERSION > 0x030190
+ // for KDE 3.2: KKeyDialog::configureKeys is deprecated
+ KKeyDialog::configure(actionCollection(), this, true);
+#else
+ KKeyDialog::configureKeys(actionCollection(), xmlFile(), true, this);
+#endif
+}
+
+
+void TopLevel::configureToolbars()
+{
+ KEditToolbar *dlg = new KEditToolbar(guiFactory(),this);
+
+ if (dlg->exec())
+ createGUI();
+
+ delete dlg;
+}
+
+
+void TopLevel::newTrace()
+{
+ // start cachegrind on command...
+}
+
+void TopLevel::newWindow()
+{
+ TopLevel* t = new TopLevel(0);
+ t->show();
+}
+
+
+void TopLevel::loadTrace()
+{
+ KURL url = KFileDialog::getOpenURL(":",
+ i18n("cachegrind.out* callgrind.out*|Callgrind Profile Data\n*|All Files"),
+ this,
+ i18n("Select Callgrind Profile Data"));
+ loadTrace(url);
+}
+
+void TopLevel::loadTrace(const KURL& url)
+{
+ if (url.isEmpty()) return;
+
+ // network transparancy
+ QString tmpFile;
+#if KDE_VERSION > 0x030190
+ // for KDE 3.2: KIO::NetAccess::download with 2 args is deprecated
+ if(KIO::NetAccess::download( url, tmpFile, this )) {
+#else
+ if(KIO::NetAccess::download( url, tmpFile )) {
+#endif
+ _openRecent->addURL(url);
+ _openRecent->saveEntries( KGlobal::config() );
+
+ loadTrace(tmpFile);
+ KIO::NetAccess::removeTempFile( tmpFile );
+ }
+}
+
+void TopLevel::loadTrace(QString file)
+{
+ if (file.isEmpty()) return;
+
+ if (_data && _data->parts().count()>0) {
+
+ // In new window
+ TopLevel* t = new TopLevel();
+ t->show();
+ t->loadDelayed(file);
+ return;
+ }
+
+ // this constructor enables progress bar callbacks
+ TraceData* d = new TraceData(this);
+ d->load(file);
+ setData(d);
+}
+
+
+void TopLevel::addTrace()
+{
+ KURL url = KFileDialog::getOpenURL(QString::null,
+ i18n("cachegrind.out* callgrind.out*|Callgrind Profile Data\n*|All Files"),
+ this,
+ i18n("Add Callgrind Profile Data"));
+ addTrace(url);
+}
+
+void TopLevel::addTrace(const KURL& url)
+{
+ if (url.isEmpty()) return;
+
+ // network transparancy
+ QString tmpFile;
+#if KDE_VERSION > 0x030190
+ // for KDE 3.2: KIO::NetAccess::download with 2 args is deprecated
+ if(KIO::NetAccess::download( url, tmpFile, this )) {
+#else
+ if(KIO::NetAccess::download( url, tmpFile )) {
+#endif
+ _openRecent->addURL(url);
+ _openRecent->saveEntries( KGlobal::config() );
+
+ addTrace(tmpFile);
+ KIO::NetAccess::removeTempFile( tmpFile );
+ }
+}
+
+void TopLevel::addTrace(QString file)
+{
+ if (file.isEmpty()) return;
+
+ if (_data) {
+ _data->load(file);
+
+ // GUI update for added data
+ configChanged();
+ return;
+ }
+
+ // this constructor enables progress bar callbacks
+ TraceData* d = new TraceData(this);
+ d->load(file);
+ setData(d);
+}
+
+
+
+void TopLevel::loadDelayed(QString file)
+{
+ _loadTraceDelayed = file;
+ QTimer::singleShot(0, this, SLOT(loadTraceDelayed()));
+}
+
+void TopLevel::loadTraceDelayed()
+{
+ if (_loadTraceDelayed.isEmpty()) return;
+
+ loadTrace(_loadTraceDelayed);
+ _loadTraceDelayed = QString::null;
+}
+
+
+void TopLevel::reload()
+{
+ QString trace;
+ if (!_data || _data->parts().count()==0)
+ trace = "."; // open first trace found in dir
+ else
+ trace = _data->traceName();
+
+ // this also keeps sure we have the same browsing position...
+ TraceData* d = new TraceData(this);
+ d->load(trace);
+ setData(d);
+}
+
+void TopLevel::exportGraph()
+{
+ if (!_data || !_function) return;
+
+ QString n = QString("callgraph.dot");
+ GraphExporter ge(_data, _function, _costType, _groupType, n);
+ ge.writeDot();
+
+ QString cmd = QString("(dot %1 -Tps > %2.ps; kghostview %3.ps)&")
+ .arg(n).arg(n).arg(n);
+ system(QFile::encodeName( cmd ));
+}
+
+
+bool TopLevel::setCostType(QString s)
+{
+ TraceCostType* ct;
+
+ ct = (_data) ? _data->mapping()->type(s) : 0;
+
+ // if costtype with given name not found, use first available
+ if (!ct && _data) ct = _data->mapping()->type(0);
+
+ return setCostType(ct);
+}
+
+bool TopLevel::setCostType2(QString s)
+{
+ TraceCostType* ct;
+
+ // Special type i18n("(Hidden)") gives 0
+ ct = (_data) ? _data->mapping()->type(s) : 0;
+
+ return setCostType2(ct);
+}
+
+void TopLevel::costTypeSelected(const QString& s)
+{
+ TraceCostType* ct;
+
+ ct = (_data) ? _data->mapping()->typeForLong(s) : 0;
+ setCostType(ct);
+}
+
+void TopLevel::costType2Selected(const QString& s)
+{
+ TraceCostType* ct;
+
+ ct = (_data) ? _data->mapping()->typeForLong(s) : 0;
+ setCostType2(ct);
+}
+
+bool TopLevel::setCostType(TraceCostType* ct)
+{
+ if (_costType == ct) return false;
+ _costType = ct;
+
+ if (ct) {
+ int idx=0;
+ QStringList l = _saCost->items();
+ for (QStringList::Iterator it = l.begin(); it != l.end(); ++it, ++idx ) {
+ if (*it == ct->longName())
+ _saCost->setCurrentItem(idx);
+ }
+ }
+
+ _partSelection->setCostType(_costType);
+ _stackSelection->setCostType(_costType);
+
+ _functionSelection->setCostType(_costType);
+ _functionSelection->updateView();
+
+ _multiView->setCostType(_costType);
+ _multiView->updateView();
+
+ updateStatusBar();
+
+ return true;
+}
+
+bool TopLevel::setCostType2(TraceCostType* ct)
+{
+ if (_costType2 == ct) return false;
+ _costType2 = ct;
+
+ QString longName = ct ? ct->longName() : i18n("(Hidden)");
+
+ int idx=0;
+ QStringList l = _saCost2->items();
+ for (QStringList::Iterator it = l.begin(); it != l.end(); ++it, ++idx ) {
+ if (*it == longName)
+ _saCost2->setCurrentItem(idx);
+ }
+
+ _partSelection->setCostType2(_costType2);
+ _stackSelection->setCostType2(_costType2);
+
+ _functionSelection->setCostType2(_costType2);
+ _functionSelection->updateView();
+
+ _multiView->setCostType2(_costType2);
+ _multiView->updateView();
+
+ updateStatusBar();
+
+ return true;
+}
+
+
+void TopLevel::groupTypeSelected(int cg)
+{
+ switch(cg) {
+ case 0: setGroupType( TraceItem::Function ); break;
+ case 1: setGroupType( TraceItem::Object ); break;
+ case 2: setGroupType( TraceItem::File ); break;
+ case 3: setGroupType( TraceItem::Class ); break;
+ case 4: setGroupType( TraceItem::FunctionCycle ); break;
+ default: break;
+ }
+}
+
+bool TopLevel::setGroupType(QString s)
+{
+ TraceItem::CostType gt;
+
+ gt = (_data) ? _data->costType(s) : TraceData::costType(s);
+ // only allow Function/Object/File/Class as grouptype
+ switch(gt) {
+ case TraceItem::Object:
+ case TraceItem::File:
+ case TraceItem::Class:
+ case TraceItem::FunctionCycle:
+ break;
+ default:
+ gt = TraceItem::Function;
+ }
+
+ return setGroupType(gt);
+}
+
+bool TopLevel::setGroupType(TraceItem::CostType gt)
+{
+ if (_groupType == gt) return false;
+ _groupType = gt;
+
+ int idx = -1;
+ switch(gt) {
+ case TraceItem::Function: idx = 0; break;
+ case TraceItem::Object: idx = 1; break;
+ case TraceItem::File: idx = 2; break;
+ case TraceItem::Class: idx = 3; break;
+ case TraceItem::FunctionCycle: idx = 4; break;
+ default:
+ break;
+ }
+
+ if (idx==-1) return false;
+
+ if (saGroup->currentItem() != idx)
+ saGroup->setCurrentItem(idx);
+
+ _stackSelection->setGroupType(_groupType);
+ _partSelection->setGroupType(_groupType);
+
+ _functionSelection->set(_groupType);
+ _functionSelection->updateView();
+
+ _multiView->set(_groupType);
+ _multiView->updateView();
+
+ updateStatusBar();
+
+ return true;
+}
+
+bool TopLevel::setGroup(QString s)
+{
+ return true;
+ TraceCostItem* ci = _functionSelection->group(s);
+ if (!ci)
+ return false;
+
+ return setGroup(ci);
+}
+
+
+bool TopLevel::setGroup(TraceCostItem* g)
+{
+ _multiView->activate(g);
+ _multiView->updateView();
+ _functionSelection->activate(g);
+ _functionSelection->updateView();
+
+ if (_group == g) return false;
+ _group = g;
+
+
+ updateStatusBar();
+
+ return true;
+}
+
+bool TopLevel::setFunction(QString s)
+{
+ if (!_data) return false;
+
+ TraceCost* f = _data->search(TraceItem::Function, s, _costType);
+ if (!f) return false;
+
+ return setFunction((TraceFunction*)f);
+}
+
+bool TopLevel::setFunction(TraceFunction* f)
+{
+ _multiView->activate(f);
+ _multiView->updateView();
+
+ _functionSelection->activate(f);
+ _functionSelection->updateView();
+
+ if (_function == f) return false;
+ _function = f;
+
+ _partSelection->setFunction(_function);
+ _stackSelection->setFunction(_function);
+
+ StackBrowser* b = _stackSelection->browser();
+ if (b) {
+ // don't disable up: a press forces stack-up extending...
+ _paForward->setEnabled(b->canGoForward());
+ _paBack->setEnabled(b->canGoBack());
+ }
+
+#if TRACE_UPDATES
+ qDebug("TopLevel::setFunction(%s), lastSender %s",
+ f ? f->prettyName().ascii() : "0",
+ _lastSender ? _lastSender->name() :"0" );
+#endif
+
+ return true;
+}
+
+
+/**
+ * Delayed versions.
+ * We always have a pair of slots: One receiver to start the
+ * delay with a singleShot Timer. It stores the parameter into a
+ * temporary variable. And one parameterless slot for
+ * forwarding, using this temporary.
+ */
+void TopLevel::setCostTypeDelayed(TraceCostType* ct)
+{
+ _costTypeDelayed = ct;
+ QTimer::singleShot (0, this, SLOT(setCostTypeDelayed()));
+}
+
+void TopLevel::setCostType2Delayed(TraceCostType* ct)
+{
+ _costType2Delayed = ct;
+ QTimer::singleShot (0, this, SLOT(setCostType2Delayed()));
+}
+
+void TopLevel::setCostTypeDelayed()
+{
+ setCostType(_costTypeDelayed);
+}
+
+void TopLevel::setCostType2Delayed()
+{
+ setCostType2(_costType2Delayed);
+}
+
+void TopLevel::setGroupTypeDelayed(TraceItem::CostType gt)
+{
+ _groupTypeDelayed = gt;
+ QTimer::singleShot (0, this, SLOT(setGroupTypeDelayed()));
+}
+
+void TopLevel::setGroupTypeDelayed()
+{
+ setGroupType(_groupTypeDelayed);
+}
+
+void TopLevel::setGroupDelayed(TraceCostItem* g)
+{
+#if TRACE_UPDATES
+ qDebug("TopLevel::setGroupDelayed(%s), sender %s",
+ g ? g->prettyName().ascii() : "0",
+ _lastSender ? _lastSender->name() :"0" );
+#endif
+
+ _groupDelayed = g;
+ QTimer::singleShot (0, this, SLOT(setGroupDelayed()));
+}
+
+void TopLevel::setGroupDelayed()
+{
+ setGroup(_groupDelayed);
+}
+
+void TopLevel::setDirectionDelayed(TraceItemView::Direction d)
+{
+ _directionDelayed = d;
+ QTimer::singleShot (0, this, SLOT(setDirectionDelayed()));
+}
+
+void TopLevel::setDirectionDelayed()
+{
+ switch(_directionDelayed) {
+ case TraceItemView::Back:
+ _stackSelection->browserBack();
+ break;
+
+ case TraceItemView::Forward:
+ _stackSelection->browserForward();
+ break;
+
+ case TraceItemView::Up:
+ {
+ StackBrowser* b = _stackSelection ? _stackSelection->browser() : 0;
+ HistoryItem* hi = b ? b->current() : 0;
+ TraceFunction* f = hi ? hi->function() : 0;
+
+ if (!f) break;
+ f = hi->stack()->caller(f, false);
+ if (f) setFunction(f);
+ }
+ break;
+
+ default: break;
+ }
+
+ _directionDelayed = TraceItemView::None;
+}
+
+
+void TopLevel::setTraceItemDelayed(TraceItem* i)
+{
+ // no need to select same item a 2nd time...
+ if (_traceItemDelayed == i) return;
+ _traceItemDelayed = i;
+ _lastSender = sender();
+
+ kdDebug() << "Selected " << (i ? i->prettyName() : "(none)") << endl;
+
+#if TRACE_UPDATES
+ qDebug("TopLevel::setTraceItemDelayed(%s), sender %s",
+ i ? i->prettyName().ascii() : "0",
+ _lastSender ? _lastSender->name() :"0" );
+#endif
+
+ QTimer::singleShot (0, this, SLOT(setTraceItemDelayed()));
+}
+
+void TopLevel::setTraceItemDelayed()
+{
+ if (!_traceItemDelayed) return;
+
+ switch(_traceItemDelayed->type()) {
+ case TraceItem::Function:
+ case TraceItem::FunctionCycle:
+ setFunction((TraceFunction*)_traceItemDelayed);
+ break;
+
+ case TraceItem::Object:
+ case TraceItem::File:
+ case TraceItem::Class:
+ setGroup((TraceCostItem*)_traceItemDelayed);
+ break;
+
+#if 0
+ // this conflicts with the selection policy of InstrView ?!?
+ case TraceItem::Instr:
+ case TraceItem::Line:
+ // only for multiview
+ _multiView->activate(_traceItemDelayed);
+ _multiView->updateView();
+ break;
+#endif
+
+ default: break;
+ }
+
+ _traceItemDelayed = 0;
+ _lastSender = 0;
+}
+
+/**
+ * A TraceData object cannot be viewed many times in different
+ * toplevel windows. Thus, this toplevel window takes ownership
+ * of the TraceData object: on closing the window or opening
+ * another trace, the object is destroyed.
+ */
+void TopLevel::setData(TraceData* data)
+{
+ if (data == _data) return;
+
+ _lastSender = 0;
+
+ saveTraceSettings();
+
+ if (_data) {
+ _partSelection->setData(0);
+ _stackSelection->setData(0);
+
+ _functionSelection->setData(0);
+ _functionSelection->updateView();
+ _multiView->setData(0);
+ _multiView->updateView();
+
+ // we are the owner...
+ delete _data;
+ }
+
+ // reset members
+ init();
+
+ _data = data;
+
+ // fill cost type list
+ QStringList types;
+
+ if (_data) {
+ /* add all supported virtual types */
+ TraceCostMapping* m = _data->mapping();
+ m->addKnownVirtualTypes();
+
+ /* first, fill selection list with available cost types */
+ for (int i=0;i<m->realCount();i++)
+ types << m->realType(i)->longName();
+ for (int i=0;i<m->virtualCount();i++)
+ types << m->virtualType(i)->longName();
+ }
+ _saCost->setItems(types);
+ _saCost->setComboWidth(300);
+
+ if (types.count()>0) {
+ // second type list gets an additional "(Hidden)"
+ types.prepend(i18n("(Hidden)"));
+ }
+ _saCost2->setItems(types);
+ _saCost2->setComboWidth(300);
+ // default is hidden
+ if (types.count()>0)
+ _saCost2->setCurrentItem(0);
+
+ _partSelection->setData(_data);
+ _stackSelection->setData(_data);
+ _functionSelection->setData(_data);
+ _functionSelection->updateView();
+ _multiView->setData(_data);
+ _multiView->updateView();
+
+ /* this is needed to let the other widgets know the types */
+ restoreTraceTypes();
+
+ restoreTraceSettings();
+
+ QString caption;
+ if (_data) {
+ caption = _data->traceName();
+ if (!_data->command().isEmpty())
+ caption += " [" + _data->command() + "]";
+ }
+ setCaption(caption);
+
+ if (!_data || (!_forcePartDock && _data->parts().count()<2)) {
+ _partDock->hide();
+ _partDockShown->setChecked(false);
+ }
+ else {
+ _partDock->show();
+ _partDockShown->setChecked(true);
+ }
+
+ updateStatusBar();
+}
+
+void TopLevel::addCostMenu(QPopupMenu* popup, bool withCost2)
+{
+ if (_data) {
+ QPopupMenu *popup1 = new QPopupMenu(popup);
+ QPopupMenu *popup2 = 0;
+ popup1->setCheckable(true);
+
+ if (withCost2) {
+ popup2 = new QPopupMenu(popup);
+ popup2->setCheckable(true);
+
+ if (_costType2) {
+ popup2->insertItem(i18n("Hide"),199);
+ popup2->insertSeparator();
+ }
+ }
+
+ TraceCostMapping* m = _data->mapping();
+ TraceCostType* ct;
+ for (int i=0;i<m->realCount();i++) {
+ ct = m->realType(i);
+ popup1->insertItem(ct->longName(), 100+i);
+ if (_costType == ct) popup1->setItemChecked(100+i,true);
+ if (popup2) {
+ popup2->insertItem(ct->longName(), 100+i);
+ if (_costType2 == ct) popup2->setItemChecked(100+i,true);
+ }
+ }
+ for (int i=0;i<m->virtualCount();i++) {
+ ct = m->virtualType(i);
+ popup1->insertItem(ct->longName(), 200+i);
+ if (_costType == ct) popup1->setItemChecked(200+i,true);
+ if (popup2) {
+ popup2->insertItem(ct->longName(), 200+i);
+ if (_costType2 == ct) popup2->setItemChecked(200+i,true);
+ }
+ }
+ popup->insertItem(i18n("Primary Event Type"), popup1);
+ connect(popup1,SIGNAL(activated(int)),this,SLOT(setCostType(int)));
+ if (popup2) {
+ popup->insertItem(i18n("Secondary Event Type"), popup2);
+ connect(popup2,SIGNAL(activated(int)),this,SLOT(setCostType2(int)));
+ }
+ }
+ if (_showPercentage)
+ popup->insertItem(i18n("Show Absolute Cost"),
+ this, SLOT(setAbsoluteCost()));
+ else
+ popup->insertItem(i18n("Show Relative Cost"),
+ this, SLOT(setRelativeCost()));
+}
+
+bool TopLevel::setCostType(int id)
+{
+ if (!_data) return false;
+
+ TraceCostMapping* m = _data->mapping();
+ TraceCostType* ct=0;
+ if (id >=100 && id<199) ct = m->realType(id-100);
+ if (id >=200 && id<299) ct = m->virtualType(id-200);
+
+ return ct ? setCostType(ct) : false;
+}
+
+bool TopLevel::setCostType2(int id)
+{
+ if (!_data) return false;
+
+ TraceCostMapping* m = _data->mapping();
+ TraceCostType* ct=0;
+ if (id >=100 && id<199) ct = m->realType(id-100);
+ if (id >=200 && id<299) ct = m->virtualType(id-200);
+
+ return setCostType2(ct);
+}
+
+void TopLevel::addGoMenu(QPopupMenu* popup)
+{
+ popup->insertItem(i18n("Go Back"), this, SLOT(goBack()));
+ popup->insertItem(i18n("Go Forward"), this, SLOT(goForward()));
+ popup->insertItem(i18n("Go Up"), this, SLOT(goUp()));
+}
+
+void TopLevel::goBack()
+{
+ setDirectionDelayed(TraceItemView::Back);
+}
+
+void TopLevel::goForward()
+{
+ setDirectionDelayed(TraceItemView::Forward);
+}
+
+void TopLevel::goUp()
+{
+ setDirectionDelayed(TraceItemView::Up);
+}
+
+QString TopLevel::traceKey()
+{
+ if (!_data || _data->command().isEmpty()) return QString::null;
+
+ QString name = _data->command();
+ QString key;
+ for (unsigned int l=0;l<name.length();l++)
+ if (name[l].isLetterOrNumber()) key += name[l];
+
+ return QString("-") + key;
+}
+
+
+void TopLevel::restoreTraceTypes()
+{
+ QString key = traceKey();
+
+ KConfigGroup cConfig(KGlobal::config(), QCString("CurrentState"));
+ KConfigGroup pConfig(KGlobal::config(), QCString("TracePositions"));
+
+ QString groupType, costType, costType2;
+ groupType = pConfig.readEntry(QString("GroupType%1").arg(key));
+ costType = pConfig.readEntry(QString("CostType%1").arg(key));
+ costType2 = pConfig.readEntry(QString("CostType2%1").arg(key));
+
+ if (groupType.isEmpty()) groupType = cConfig.readEntry("GroupType");
+ if (costType.isEmpty()) costType = cConfig.readEntry("CostType");
+ if (costType2.isEmpty()) costType2 = cConfig.readEntry("CostType2");
+
+ setGroupType(groupType);
+ setCostType(costType);
+ setCostType2(costType2);
+
+ // if still no cost type set, use first available
+ if (!_costType && !_saCost->items().isEmpty())
+ costTypeSelected(_saCost->items().first());
+
+ KConfigGroup aConfig(KGlobal::config(), QCString("Layouts"));
+ _layoutCount = aConfig.readNumEntry(QString("Count%1").arg(key), 0);
+ _layoutCurrent = aConfig.readNumEntry(QString("Current%1").arg(key), 0);
+ if (_layoutCount == 0) layoutRestore();
+ updateLayoutActions();
+}
+
+
+/**
+ * This must be called after setting group/cost types in the function
+ * selection widget, because the group/function choosing depends on
+ * filled lists in the function selection widget
+ */
+void TopLevel::restoreTraceSettings()
+{
+ if (!_data) return;
+
+ QString key = traceKey();
+
+ KConfigGroup pConfig(KGlobal::config(), QCString("TracePositions"));
+ QString group = pConfig.readEntry(QString("Group%1").arg(key));
+ if (!group.isEmpty()) setGroup(group);
+
+ restoreCurrentState(key);
+
+ // restoreCurrentState() usually leads to a call to setTraceItemDelayed()
+ // to restore last active item...
+ if (!_traceItemDelayed) {
+ // function not available any more.. try with "main"
+ if (!setFunction("main"))
+ _functionSelection->setTopFunction();
+ }
+}
+
+
+/* Layout */
+
+void TopLevel::layoutDuplicate()
+{
+ // save current and allocate a new slot
+ _multiView->saveViewConfig(KGlobal::config(),
+ QString("Layout%1-MainView").arg(_layoutCurrent),
+ traceKey(), false);
+ _layoutCurrent = _layoutCount;
+ _layoutCount++;
+
+ updateLayoutActions();
+
+ kdDebug() << "TopLevel::layoutDuplicate: count " << _layoutCount << endl;
+}
+
+void TopLevel::layoutRemove()
+{
+ if (_layoutCount <2) return;
+
+ int from = _layoutCount-1;
+ if (_layoutCurrent == from) { _layoutCurrent--; from--; }
+ // restore from last and decrement count
+ _multiView->readViewConfig(KGlobal::config(),
+ QString("Layout%1-MainView").arg(from),
+ traceKey(), false);
+ _layoutCount--;
+
+ updateLayoutActions();
+}
+
+void TopLevel::layoutNext()
+{
+ if (_layoutCount <2) return;
+
+ KConfig* config = KGlobal::config();
+ QString key = traceKey();
+
+ _multiView->saveViewConfig(config,
+ QString("Layout%1-MainView").arg(_layoutCurrent),
+ key, false);
+ _layoutCurrent++;
+ if (_layoutCurrent == _layoutCount) _layoutCurrent = 0;
+
+ _multiView->readViewConfig(config,
+ QString("Layout%1-MainView").arg(_layoutCurrent),
+ key, false);
+
+ if (0) kdDebug() << "TopLevel::layoutNext: current "
+ << _layoutCurrent << endl;
+}
+
+void TopLevel::layoutPrevious()
+{
+ if (_layoutCount <2) return;
+
+ KConfig* config = KGlobal::config();
+ QString key = traceKey();
+
+ _multiView->saveViewConfig(config,
+ QString("Layout%1-MainView").arg(_layoutCurrent),
+ key, false);
+ _layoutCurrent--;
+ if (_layoutCurrent <0) _layoutCurrent = _layoutCount-1;
+
+ _multiView->readViewConfig(config,
+ QString("Layout%1-MainView").arg(_layoutCurrent),
+ key, false);
+
+ if (0) kdDebug() << "TopLevel::layoutPrevious: current "
+ << _layoutCurrent << endl;
+}
+
+void TopLevel::layoutSave()
+{
+ KConfig* config = KGlobal::config();
+ QString key = traceKey();
+
+ _multiView->saveViewConfig(config,
+ QString("Layout%1-MainView").arg(_layoutCurrent),
+ key, false);
+
+ for(int i=0;i<_layoutCount;i++) {
+ _multiView->readViewConfig(config,
+ QString("Layout%1-MainView").arg(i),
+ key, false);
+ _multiView->saveViewConfig(config,
+ QString("Layout%1-MainView").arg(i),
+ QString(), false);
+ }
+
+ _multiView->readViewConfig(config,
+ QString("Layout%1-MainView").arg(_layoutCurrent),
+ key, false);
+
+ KConfigGroup aConfig(config, QCString("Layouts"));
+ aConfig.writeEntry("DefaultCount", _layoutCount);
+ aConfig.writeEntry("DefaultCurrent", _layoutCurrent);
+}
+
+void TopLevel::layoutRestore()
+{
+ KConfig* config = KGlobal::config();
+ KConfigGroup aConfig(config, QCString("Layouts"));
+ _layoutCount = aConfig.readNumEntry("DefaultCount", 0);
+ _layoutCurrent = aConfig.readNumEntry("DefaultCurrent", 0);
+ if (_layoutCount == 0) {
+ _layoutCount++;
+ return;
+ }
+
+ QString key = traceKey();
+ for(int i=0;i<_layoutCount;i++) {
+ _multiView->readViewConfig(config,
+ QString("Layout%1-MainView").arg(i),
+ QString(), false);
+ _multiView->saveViewConfig(config,
+ QString("Layout%1-MainView").arg(i),
+ key, false);
+ }
+
+ _multiView->readViewConfig(config,
+ QString("Layout%1-MainView").arg(_layoutCurrent),
+ key, false);
+
+ updateLayoutActions();
+}
+
+
+void TopLevel::updateLayoutActions()
+{
+ KAction* ka;
+
+ ka = actionCollection()->action("layout_next");
+ if (ka) ka->setEnabled(_layoutCount>1);
+
+ ka = actionCollection()->action("layout_previous");
+ if (ka) ka->setEnabled(_layoutCount>1);
+
+ ka = actionCollection()->action("layout_remove");
+ if (ka) ka->setEnabled(_layoutCount>1);
+
+ _statusbar->message(i18n("Layout Count: %1").arg(_layoutCount), 1000);
+}
+
+
+void TopLevel::updateStatusBar()
+{
+ if (!_data || _data->parts().count()==0) {
+ _statusLabel->setText(i18n("No profile data file loaded."));
+ return;
+ }
+
+ QString status = QString("%1 [%2] - ")
+ .arg(_data->shortTraceName())
+ .arg(_data->activePartRange());
+
+ if (_costType) {
+ status += i18n("Total %1 Cost: %2")
+ .arg(_costType->longName())
+ .arg(_data->prettySubCost(_costType));
+
+ /* this gets too long...
+ if (_costType2 && (_costType2 != _costType))
+ status += i18n(", %1 Cost: %2")
+ .arg(_costType2->longName())
+ .arg(_data->prettySubCost(_costType2));
+ */
+ }
+ else
+ status += i18n("No event type selected");
+
+ /* Not working... should give group of selected function
+
+ if (_groupType != TraceItem::Function) {
+ status += QString(" - %1 '%2'")
+ .arg(TraceItem::i18nTypeName(_groupType))
+ .arg(_group ? _group->prettyName() : i18n("(None)"));
+ }
+ */
+
+ _statusLabel->setText(status);
+}
+
+void TopLevel::configure()
+{
+ if (ConfigDlg::configure(Configuration::config(), _data, this)) {
+ Configuration::saveOptions(KGlobal::config());
+
+ configChanged();
+ }
+ else
+ Configuration::readOptions(KGlobal::config());
+}
+
+bool TopLevel::queryClose()
+{
+ saveTraceSettings();
+
+ return true;
+}
+
+bool TopLevel::queryExit()
+{
+ // save current toplevel options as defaults...
+ Configuration::setShowPercentage(_showPercentage);
+ Configuration::setShowExpanded(_showExpanded);
+ Configuration::setShowCycles(_showCycles);
+ Configuration::saveOptions(KGlobal::config());
+
+ saveCurrentState(QString::null);
+
+ // save QT dock positions...
+
+ // We don't want to save the KToolbar position here.
+ // Its already stored.
+ delete toolBar();
+
+ KConfigGroup dockConfig(KGlobal::config(), QCString("Docks"));
+ QString str;
+ QTextStream ts( &str, IO_WriteOnly );
+ ts << *this;
+#if 1
+ dockConfig.writeEntry("Position", str);
+#else
+ /* We store this with a localized key because for dock positions,
+ * QT uses the localized captions of docks.
+ * This way, when changing languages, you don't loose dock position
+ * settings.
+ * For the retrieval to work, we need to store a non-localized.
+ */
+ dockConfig.writeEntry("Position", str, true, false, true);
+#endif
+
+ // if part dock was chosen visible even for only 1 part loaded,
+ // keep this choice...
+ _forcePartDock = false;
+ if (_data && (_data->parts().count()<2) && _partDock->isVisible())
+ _forcePartDock=true;
+ dockConfig.writeEntry("ForcePartDockVisible", _forcePartDock);
+
+ return true;
+}
+
+
+void TopLevel::splitSlot()
+{
+ int count = _multiView->childCount();
+ if (count<1) count = 1;
+ if (count>2) count = 2;
+ count = 3-count;
+ _multiView->setChildCount(count);
+
+ _taSplit->setChecked(count>1);
+ _taSplitDir->setEnabled(count>1);
+ _taSplitDir->setChecked(_multiView->orientation() == Qt::Horizontal);
+}
+
+void TopLevel::splitDirSlot()
+{
+ _multiView->setOrientation( _taSplitDir->isChecked() ?
+ Qt::Horizontal : Qt::Vertical );
+}
+
+
+
+// this is called after a config change in the dialog
+void TopLevel::configChanged()
+{
+ //qDebug("TopLevel::configChanged");
+ //_showPercentage->setChecked(Configuration::showPercentage());
+
+ // invalidate found/cached dirs of source files
+ _data->resetSourceDirs();
+
+ _partSelection->refresh();
+ _stackSelection->refresh();
+
+ _functionSelection->notifyChange(TraceItemView::configChanged);
+ _functionSelection->updateView();
+
+ _multiView->notifyChange(TraceItemView::configChanged);
+ _multiView->updateView();
+}
+
+void TopLevel::slotShowTipOnStart() {
+ KTipDialog::showTip(this);
+}
+
+void TopLevel::slotShowTip() {
+ KTipDialog::showTip( this, QString::null, true );
+}
+
+void TopLevel::dummySlot()
+{
+}
+
+void TopLevel::activePartsChangedSlot(const TracePartList& list)
+{
+ if (!_data) return;
+
+ if (!_data->activateParts(list)) {
+// qDebug("TopLevel::activePartsChangedSlot: No Change!");
+ return;
+ }
+ _activeParts = list;
+
+ _partSelection->activePartsChangedSlot(list);
+
+ _multiView->set(list);
+ _multiView->updateView();
+
+ _functionSelection->set(list);
+ _functionSelection->updateView();
+
+ _stackSelection->refresh();
+
+ updateStatusBar();
+}
+
+void TopLevel::partsHideSelectedSlotDelayed()
+{
+ QTimer::singleShot( 0, this, SLOT(partsHideSelectedSlot()) );
+}
+
+// this puts selected parts into hidden list,
+// deselects them and makes the remaining parts selected
+void TopLevel::partsHideSelectedSlot()
+{
+ if (!_data) return;
+
+ TracePart* part;
+ TracePartList newHidden, newActive;
+ TracePartList l = _data->parts();
+ for (part=l.first();part;part=l.next()) {
+ if ((_activeParts.findRef(part)>=0) ||
+ (_hiddenParts.findRef(part)>=0))
+ newHidden.append(part);
+ else
+ newActive.append(part);
+ }
+
+ _hiddenParts = newHidden;
+ _partSelection->hiddenPartsChangedSlot(_hiddenParts);
+
+#if 0
+ _mainWidget1->hiddenPartsChangedSlot(_hiddenParts);
+ _mainWidget2->hiddenPartsChangedSlot(_hiddenParts);
+#endif
+
+ activePartsChangedSlot(newActive);
+}
+
+void TopLevel::partsUnhideAllSlotDelayed()
+{
+ QTimer::singleShot( 0, this, SLOT(partsUnhideAllSlot()) );
+}
+
+// this unhides all hidden parts. Does NOT change selection
+void TopLevel::partsUnhideAllSlot()
+{
+ if (!_data) return;
+
+ _hiddenParts.clear();
+ _partSelection->hiddenPartsChangedSlot(_hiddenParts);
+#if 0
+ _mainWidget1->hiddenPartsChangedSlot(_hiddenParts);
+ _mainWidget2->hiddenPartsChangedSlot(_hiddenParts);
+#endif
+}
+
+void TopLevel::forceTrace()
+{
+// qDebug("forceTrace");
+
+ // Needs Callgrind now...
+ QFile cmd("callgrind.cmd");
+ if (!cmd.exists()) {
+ cmd.open(IO_WriteOnly);
+ cmd.writeBlock("DUMP\n", 5);
+ cmd.close();
+ }
+ if (_taDump->isChecked())
+ QTimer::singleShot( 1000, this, SLOT(forceTraceReload()) );
+ else {
+ // cancel request
+ cmd.remove();
+ }
+
+}
+
+void TopLevel::forceTraceReload()
+{
+// qDebug("forceTraceReload");
+
+ QFile cmd("callgrind.cmd");
+ if (cmd.exists()) {
+ if (_taDump->isChecked())
+ QTimer::singleShot( 1000, this, SLOT(forceTraceReload()) );
+ return;
+ }
+ _taDump->setChecked(false);
+ reload();
+}
+
+void TopLevel::forwardAboutToShow()
+{
+ QPopupMenu *popup = _paForward->popupMenu();
+
+ popup->clear();
+ StackBrowser* b = _stackSelection ? _stackSelection->browser() : 0;
+ HistoryItem* hi = b ? b->current() : 0;
+ TraceFunction* f;
+
+ if (!hi) {
+ popup->insertItem(i18n("(No Stack)"));
+ return;
+ }
+
+ hi = hi->next();
+ if (!hi) {
+ popup->insertItem(i18n("(No next function)"));
+ return;
+ }
+
+ int count = 1;
+ while (count<Configuration::maxSymbolCount() && hi) {
+ f = hi->function();
+ if (!f) break;
+
+ QString name = f->prettyName();
+ if ((int)name.length()>Configuration::maxSymbolLength())
+ name = name.left(Configuration::maxSymbolLength()) + "...";
+
+ //qDebug("forward: Adding %s", name.ascii());
+ popup->insertItem(name, count);
+ hi = hi->next();
+ count++;
+ }
+}
+
+void TopLevel::backAboutToShow()
+{
+ QPopupMenu *popup = _paBack->popupMenu();
+
+ popup->clear();
+ StackBrowser* b = _stackSelection ? _stackSelection->browser() : 0;
+ HistoryItem* hi = b ? b->current() : 0;
+ TraceFunction* f;
+
+ if (!hi) {
+ popup->insertItem(i18n("(No Stack)"));
+ return;
+ }
+
+ hi = hi->last();
+ if (!hi) {
+ popup->insertItem(i18n("(No previous function)"));
+ return;
+ }
+
+ int count = 1;
+ while (count<Configuration::maxSymbolCount() && hi) {
+ f = hi->function();
+ if (!f) break;
+
+ QString name = f->prettyName();
+ if ((int)name.length()>Configuration::maxSymbolLength())
+ name = name.left(Configuration::maxSymbolLength()) + "...";
+
+ //qDebug("back: Adding %s", name.ascii());
+ popup->insertItem(name, count);
+ hi = hi->last();
+ count++;
+ }
+}
+
+void TopLevel::upAboutToShow()
+{
+ QPopupMenu *popup = _paUp->popupMenu();
+
+ popup->clear();
+ StackBrowser* b = _stackSelection ? _stackSelection->browser() : 0;
+ HistoryItem* hi = b ? b->current() : 0;
+ TraceFunction* f = hi ? hi->function() : 0;
+
+ if (!f) {
+ popup->insertItem(i18n("(No Stack)"));
+ return;
+ }
+ f = hi->stack()->caller(f, false);
+ if (!f) {
+ popup->insertItem(i18n("(No Function Up)"));
+ return;
+ }
+
+ int count = 1;
+ while (count<Configuration::maxSymbolCount() && f) {
+ QString name = f->prettyName();
+ if ((int)name.length()>Configuration::maxSymbolLength())
+ name = name.left(Configuration::maxSymbolLength()) + "...";
+
+ popup->insertItem(name, count);
+ f = hi->stack()->caller(f, false);
+ count++;
+ }
+
+}
+
+void TopLevel::forwardActivated(int id)
+{
+ //qDebug("forwardActivated: %d", id);
+
+ StackBrowser* b = _stackSelection ? _stackSelection->browser() : 0;
+ if (!b) return;
+
+ while (id>1) {
+ b->goForward();
+ id--;
+ }
+ _stackSelection->browserForward();
+}
+
+void TopLevel::backActivated(int id)
+{
+ //qDebug("backActivated: %d", id);
+
+ StackBrowser* b = _stackSelection ? _stackSelection->browser() : 0;
+ if (!b) return;
+
+ while (id>1) {
+ b->goBack();
+ id--;
+ }
+ _stackSelection->browserBack();
+}
+
+void TopLevel::upActivated(int id)
+{
+ //qDebug("upActivated: %d", id);
+
+ StackBrowser* b = _stackSelection ? _stackSelection->browser() : 0;
+ HistoryItem* hi = b ? b->current() : 0;
+ if (!hi) return;
+
+ TraceFunction* f = hi->function();
+
+ while (id>0 && f) {
+ f = hi->stack()->caller(f, false);
+ id--;
+ }
+
+ //qDebug("upActivated: %s", f ? f->prettyName().ascii() : "??" );
+ if (f)
+ setFunction(f);
+
+}
+
+void TopLevel::showMessage(const QString& msg, int ms)
+{
+ if (_statusbar)
+ _statusbar->message(msg, ms);
+}
+
+void TopLevel::showStatus(QString msg, int progress)
+{
+ static bool msgUpdateNeeded = true;
+
+ if (msg.isEmpty()) {
+ if (_progressBar) {
+ _statusbar->removeWidget(_progressBar);
+ delete _progressBar;
+ _progressBar = 0;
+ }
+ _statusbar->clear();
+ _progressMsg = msg;
+ return;
+ }
+
+ if (_progressMsg.isEmpty()) _progressStart.start();
+
+ if (msg != _progressMsg) {
+ _progressMsg = msg;
+ msgUpdateNeeded = true;
+ }
+
+ // do nothing if last change was less than 0.5 seconds ago
+ if (_progressStart.elapsed() < 500) return;
+
+ if (!_progressBar) {
+ _progressBar = new QProgressBar(_statusbar);
+ _progressBar->setMaximumSize(200, _statusbar->height()-4);
+ _statusbar->addWidget(_progressBar, 1, true);
+ _progressBar->show();
+ msgUpdateNeeded = true;
+ }
+
+ _progressStart.restart();
+
+ if (msgUpdateNeeded) {
+ _statusbar->message(msg);
+ msgUpdateNeeded = false;
+ }
+ _progressBar->setProgress(progress);
+
+ // let the progress bar update itself
+#if (QT_VERSION-0 >= 0x030100)
+ QEventLoop* l = qApp->eventLoop();
+ if (l) l->processEvents(QEventLoop::ExcludeUserInput);
+#else
+ // for Qt 3.0.x. This allows user input and thus potentially races
+ qApp->processEvents();
+#endif
+}
+
+#include "toplevel.moc"
diff --git a/kcachegrind/kcachegrind/toplevel.h b/kcachegrind/kcachegrind/toplevel.h
new file mode 100644
index 00000000..8662768e
--- /dev/null
+++ b/kcachegrind/kcachegrind/toplevel.h
@@ -0,0 +1,274 @@
+/* This file is part of KCachegrind.
+ Copyright (C) 2002, 2003 Josef Weidendorfer <Josef.Weidendorfer@gmx.de>
+
+ KCachegrind is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public
+ License as published by the Free Software Foundation, version 2.
+
+ 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; see the file COPYING. If not, write to
+ the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+*/
+
+/*
+ * KCachegrind top level window
+ */
+
+#ifndef TOPLEVEL_H
+#define TOPLEVEL_H
+
+#include <qdatetime.h>
+
+#include <dcopobject.h>
+#include <kmainwindow.h>
+
+#include "traceitemview.h"
+#include "tracedata.h"
+
+class MultiView;
+class QLineEdit;
+class QDockWidget;
+class QLabel;
+class QProgressBar;
+class QPopupMenu;
+
+class KURL;
+class KSelectAction;
+class KToggleAction;
+class KToolBarPopupAction;
+
+class TraceData;
+class KRecentFilesAction;
+class MainWidget;
+class PartSelection;
+class FunctionSelection;
+class DumpSelection;
+class StackSelection;
+class TraceFunction;
+
+class TopLevel : public KMainWindow, public DCOPObject
+{
+ Q_OBJECT
+
+public:
+ TopLevel(const char *name = 0);
+ ~TopLevel();
+
+ TraceData* data() { return _data; }
+ void setData(TraceData*);
+
+ virtual void saveProperties(KConfig*);
+ virtual void readProperties(KConfig*);
+
+ void createActions();
+ void createDocks();
+
+ TraceItem::CostType groupType() { return _groupType; }
+ TraceCostType* costType() { return _costType; }
+ TraceCostType* costType2() { return _costType2; }
+ TracePartList activeParts() { return _activeParts; }
+ TracePartList hiddenParts() { return _hiddenParts; }
+
+ // current config
+ bool showPercentage() const { return _showPercentage; }
+ bool showExpanded() const { return _showExpanded; }
+ bool showCycles() const { return _showCycles; }
+
+ /* convenience functions for often used context menu items */
+ void addCostMenu(QPopupMenu*,bool);
+ void addGoMenu(QPopupMenu*);
+
+public slots:
+ void newTrace();
+ void loadTrace();
+ void loadTrace(const KURL&);
+ void loadTrace(QString);
+ void addTrace();
+ void addTrace(const KURL&);
+ void addTrace(QString);
+
+ // for quick showing the main window...
+ void loadDelayed(QString);
+
+ void reload();
+ void exportGraph();
+ void newWindow();
+ void configure();
+ void querySlot();
+ void dummySlot();
+
+ // layouts
+ void layoutDuplicate();
+ void layoutRemove();
+ void layoutNext();
+ void layoutPrevious();
+ void layoutSave();
+ void layoutRestore();
+ void updateLayoutActions();
+
+ void updateStatusBar();
+ void costTypeSelected(const QString&);
+ void costType2Selected(const QString&);
+ void groupTypeSelected(int);
+ void splitSlot();
+ void splitDirSlot();
+ void configureToolbars();
+ void configureKeys();
+ bool queryExit();
+ bool queryClose();
+ void togglePartDock();
+ void toggleStackDock();
+ void toggleFunctionDock();
+ void toggleDumpDock();
+ void toggleStatusBar();
+ void partVisibilityChanged(bool);
+ void dumpVisibilityChanged(bool);
+ void stackVisibilityChanged(bool);
+ void functionVisibilityChanged(bool);
+ void togglePercentage();
+ void setPercentage(bool);
+ void setAbsoluteCost();
+ void setRelativeCost();
+ void toggleExpanded();
+ void toggleCycles();
+ void forceTrace();
+ void forceTraceReload();
+ void forwardAboutToShow();
+ void backAboutToShow();
+ void upAboutToShow();
+ void forwardActivated(int);
+ void backActivated(int);
+ void upActivated(int);
+
+ bool setCostType(TraceCostType*);
+ bool setCostType2(TraceCostType*);
+ bool setCostType(QString);
+ bool setCostType2(QString);
+ bool setCostType(int);
+ bool setCostType2(int);
+ bool setGroupType(TraceItem::CostType);
+ bool setGroupType(QString);
+ bool setGroup(TraceCostItem*);
+ bool setGroup(QString);
+ bool setFunction(TraceFunction*);
+ bool setFunction(QString);
+ void activePartsChangedSlot(const TracePartList& list);
+ void partsHideSelectedSlot();
+ void partsUnhideAllSlot();
+
+ /* These go back to mainloop first by using a timer.
+ * So they can be called from event handlers that
+ * aren't allowed to delete list entries.
+ */
+ void setCostTypeDelayed(TraceCostType*);
+ void setCostType2Delayed(TraceCostType*);
+ void setGroupTypeDelayed(TraceItem::CostType);
+ void setGroupDelayed(TraceCostItem*);
+ void setTraceItemDelayed(TraceItem*);
+ void partsHideSelectedSlotDelayed();
+ void partsUnhideAllSlotDelayed();
+ void goBack();
+ void goForward();
+ void goUp();
+ void setDirectionDelayed(TraceItemView::Direction);
+
+ /* SingleShot Slots (without parameters) for the delayed versions */
+ void setCostTypeDelayed();
+ void setCostType2Delayed();
+ void setGroupTypeDelayed();
+ void setGroupDelayed();
+ void setTraceItemDelayed();
+ void loadTraceDelayed();
+ void setDirectionDelayed();
+
+ // configuration has changed
+ void configChanged();
+
+ //void refresh();
+ void slotShowTipOnStart();
+ void slotShowTip();
+
+ // progress in status bar, empty message disables progress display
+ void showStatus(QString msg, int progress);
+ void showMessage(const QString&, int msec);
+
+private:
+ void init();
+ void createLayoutActions();
+ void createMiscActions();
+ void setupMainWidget(MainWidget*);
+ void setupPartSelection(PartSelection*);
+ void restoreCurrentState(QString postfix);
+ void saveCurrentState(QString postfix);
+ void saveTraceSettings();
+ QString traceKey();
+ void restoreTraceTypes();
+ void restoreTraceSettings();
+
+ KStatusBar* _statusbar;
+ QLabel* _statusLabel;
+ KRecentFilesAction* _openRecent;
+ bool _twoMainWidgets;
+ Orientation _spOrientation;
+
+ MultiView* _multiView;
+ FunctionSelection* _functionSelection;
+ DumpSelection* _dumpSelection;
+ PartSelection* _partSelection;
+ StackSelection* _stackSelection;
+ QLineEdit* queryLineEdit;
+
+ QDockWindow *_partDock, *_stackDock, *_functionDock, *_dumpDock;
+ bool _forcePartDock;
+
+ KSelectAction *_saCost, *_saCost2, *saGroup;
+ KToggleAction *_partDockShown, *_stackDockShown;
+ KToggleAction *_functionDockShown, *_dumpDockShown;
+ KToggleAction *_taPercentage, *_taExpanded, *_taCycles;
+ KToggleAction *_taDump, *_taSplit, *_taSplitDir;
+ KToolBarPopupAction *_paForward, *_paBack, *_paUp;
+
+ TraceFunction* _function;
+ const QObject* _lastSender;
+
+ // trace data shown in this window
+ TraceData* _data;
+ // subcost types used for visualisation
+ TraceCostType* _costType;
+ TraceCostType* _costType2;
+ // grouping of function list
+ TraceItem::CostType _groupType;
+ // selected group
+ TraceCostItem* _group;
+ // selected parts
+ TracePartList _activeParts;
+ // hidden parts
+ TracePartList _hiddenParts;
+ // layouts
+ int _layoutCurrent, _layoutCount;
+
+ // for delayed slots
+ TraceCostType* _costTypeDelayed;
+ TraceCostType* _costType2Delayed;
+ TraceItem::CostType _groupTypeDelayed;
+ TraceCostItem* _groupDelayed;
+ TraceItem* _traceItemDelayed;
+ QString _loadTraceDelayed;
+ TraceItemView::Direction _directionDelayed;
+
+ // for status progress display
+ QString _progressMsg;
+ QTime _progressStart;
+ QProgressBar* _progressBar;
+
+ // toplevel configuration options
+ bool _showPercentage, _showExpanded, _showCycles;
+};
+
+#endif
diff --git a/kcachegrind/kcachegrind/tracedata.cpp b/kcachegrind/kcachegrind/tracedata.cpp
new file mode 100644
index 00000000..85f4f2e1
--- /dev/null
+++ b/kcachegrind/kcachegrind/tracedata.cpp
@@ -0,0 +1,5072 @@
+/* This file is part of KCachegrind.
+ Copyright (C) 2002, 2003 Josef Weidendorfer <Josef.Weidendorfer@gmx.de>
+
+ KCachegrind is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public
+ License as published by the Free Software Foundation, version 2.
+
+ 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; see the file COPYING. If not, write to
+ the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+*/
+
+
+#include <stdlib.h>
+
+#include <qfile.h>
+#include <qdir.h>
+#include <qfileinfo.h>
+#include <qregexp.h>
+
+#include <klocale.h>
+#include <kdebug.h>
+
+#include "tracedata.h"
+#include "toplevel.h"
+#include "loader.h"
+#include "configuration.h"
+#include "utils.h"
+#include "fixcost.h"
+
+
+#define TRACE_DEBUG 0
+#define TRACE_ASSERTIONS 0
+
+const int TraceCost::MaxRealIndex = MaxRealIndexValue;
+const int TraceCost::InvalidIndex = -1;
+
+//---------------------------------------------------
+// Addr
+
+bool Addr::set(FixString& s)
+{
+ return s.stripUInt64(_v);
+}
+
+int Addr::set(const char *s)
+{
+ int n = 0;
+ _v = 0;
+
+ while((n<16) && *s) {
+ if ((*s>='0') && (*s<='9'))
+ _v = 16*_v + (*s-'0');
+ else if ((*s>='a') && (*s<='f'))
+ _v = 16*_v + 10 + (*s-'a');
+ else if ((*s>='A') && (*s<='F'))
+ _v = 16*_v + 10 + (*s-'A');
+ else break;
+ s++;
+ n++;
+ }
+
+ return n;
+}
+
+
+QString Addr::toString() const
+{
+ if (_v == 0) return QString("0");
+
+ uint64 n = _v;
+ QString hex;
+#if (QT_VERSION-0 >= 0x030200)
+ hex.reserve(16);
+#endif
+
+ while(n>0) {
+ int d = (n & 15);
+ hex = QChar((d<10) ? ('0'+d) : ('A'-10+d)) + hex;
+ n /= 16;
+ }
+
+ return hex;
+}
+
+QString Addr::pretty() const
+{
+ if (_v == 0) return QString("0");
+
+ uint64 n = _v;
+ int p = 0;
+ QString hex;
+#if (QT_VERSION-0 >= 0x030200)
+ hex.reserve(20);
+#endif
+
+ while(n>0) {
+ int d = (n & 15);
+ if ((p>0) && ((p%4)==0)) hex = " " + hex;
+ hex = QChar((d<10) ? ('0'+d) : ('A'-10+d)) + hex;
+ n /= 16;
+ p++;
+ }
+
+ return hex;
+}
+
+bool Addr::isInRange(Addr a, int distance)
+{
+ uint64 diff = (a._v > _v) ? (a._v - _v) : (_v - a._v);
+ uint64 dist = (distance<0) ? distance : -distance;
+ return (diff < dist);
+}
+
+//---------------------------------------------------
+// TraceItem
+
+QString* TraceItem::_typeName = 0;
+QString* TraceItem::_i18nTypeName = 0;
+
+TraceItem::TraceItem()
+{
+ _position = 0;
+ _dep = 0;
+ _dirty = true;
+}
+
+TraceItem::~TraceItem()
+{}
+
+void TraceItem::cleanup()
+{
+ if (_typeName) {
+ delete [] _typeName;
+ _typeName = 0;
+ }
+ if (_i18nTypeName) {
+ delete [] _i18nTypeName;
+ _i18nTypeName = 0;
+ }
+}
+
+QString TraceItem::typeName(CostType t)
+{
+ if (!_typeName) {
+ _typeName = new QString [MaxCostType+1];
+ QString* strs = _typeName;
+ for(int i=0;i<=MaxCostType;i++)
+ strs[i] = QString("?");
+
+ strs[Item] = I18N_NOOP("Abstract Item");
+ strs[Cost] = I18N_NOOP("Cost Item");
+ strs[PartLine] = I18N_NOOP("Part Source Line");
+ strs[Line] = I18N_NOOP("Source Line");
+ strs[PartLineCall] = I18N_NOOP("Part Line Call");
+ strs[LineCall] = I18N_NOOP("Line Call");
+ strs[PartLineJump] = I18N_NOOP("Part Jump");
+ strs[LineJump] = I18N_NOOP("Jump");
+ strs[PartInstr] = I18N_NOOP("Part Instruction");
+ strs[Instr] = I18N_NOOP("Instruction");
+ strs[PartInstrJump] = I18N_NOOP("Part Instruction Jump");
+ strs[InstrJump] = I18N_NOOP("Instruction Jump");
+ strs[PartInstrCall] = I18N_NOOP("Part Instruction Call");
+ strs[InstrCall] = I18N_NOOP("Instruction Call");
+ strs[PartCall] = I18N_NOOP("Part Call");
+ strs[Call] = I18N_NOOP("Call");
+ strs[PartFunction] = I18N_NOOP("Part Function");
+ strs[FunctionSource] = I18N_NOOP("Function Source File");
+ strs[Function] = I18N_NOOP("Function");
+ strs[FunctionCycle] = I18N_NOOP("Function Cycle");
+ strs[PartClass] = I18N_NOOP("Part Class");
+ strs[Class] = I18N_NOOP("Class");
+ strs[PartFile] = I18N_NOOP("Part Source File");
+ strs[File] = I18N_NOOP("Source File");
+ strs[PartObject] = I18N_NOOP("Part ELF Object");
+ strs[Object] = I18N_NOOP("ELF Object");
+ strs[Part] = I18N_NOOP("Profile Part");
+ strs[Data] = I18N_NOOP("Program Trace");
+ }
+ if (t<0 || t> MaxCostType) t = MaxCostType;
+ return _typeName[t];
+}
+
+TraceItem::CostType TraceItem::costType(QString s)
+{
+ // This is the default cost Type
+ if (s.isEmpty()) return Function;
+
+ CostType type;
+ for (int i=0; i<MaxCostType;i++) {
+ type = (CostType) i;
+ if (typeName(type) == s)
+ return type;
+ }
+ return NoCostType;
+}
+
+// all strings of typeName() are translatable because of I18N_NOOP there
+QString TraceItem::i18nTypeName(CostType t)
+{
+ if (!_i18nTypeName) {
+ _i18nTypeName = new QString [MaxCostType+1];
+ for(int i=0;i<=MaxCostType;i++)
+ _i18nTypeName[i] = i18n(typeName((CostType)i).utf8().data());
+ }
+ if (t<0 || t> MaxCostType) t = MaxCostType;
+ return _i18nTypeName[t];
+}
+
+TraceItem::CostType TraceItem::i18nCostType(QString s)
+{
+ // This is the default cost Type
+ if (s.isEmpty()) return Function;
+
+ CostType type;
+ for (int i=0; i<MaxCostType;i++) {
+ type = (CostType) i;
+ if (i18nTypeName(type) == s)
+ return type;
+ }
+ return NoCostType;
+}
+
+
+void TraceItem::clear()
+{
+ invalidate();
+}
+
+
+QString TraceItem::costString(TraceCostMapping*)
+{
+ return QString("(no cost)");
+}
+
+QString TraceItem::name() const
+{
+ if (part()) {
+ return i18n("%1 from %2")
+ .arg(_dep->name())
+ .arg(part()->name());
+ }
+
+ if (_dep)
+ return _dep->name();
+
+ return i18n("(unknown)");
+}
+
+QString TraceItem::prettyName() const
+{
+ if (name().isEmpty()) return i18n("(unknown)");
+ return name();
+}
+
+
+QString TraceItem::fullName() const
+{
+ return QString("%1 %2")
+ .arg(typeName(type())).arg(prettyName());
+}
+
+QString TraceItem::toString()
+{
+ return QString("%1\n [%3]").arg(fullName()).arg(costString(0));
+}
+
+void TraceItem::invalidate()
+{
+ if (_dirty) return;
+ _dirty = true;
+
+ if (_dep)
+ _dep->invalidate();
+}
+
+void TraceItem::update()
+{
+ _dirty = false;
+}
+
+TracePart* TraceItem::part()
+{
+ return _position ? _position->part() : 0;
+}
+
+const TracePart* TraceItem::part() const
+{
+ return _position ? _position->part() : 0;
+}
+
+TraceData* TraceItem::data()
+{
+ return _position ? _position->data() : 0;
+}
+
+const TraceData* TraceItem::data() const
+{
+ return _position ? _position->data() : 0;
+}
+
+
+//---------------------------------------------------
+// TraceCost
+
+TraceCost::TraceCost()
+ : TraceItem()
+{
+ _cachedType = 0; // no virtual value cached
+
+ TraceCost::clear();
+}
+
+TraceCost::~TraceCost()
+{}
+
+
+void TraceCost::clear()
+{
+ // simple set usage count to 0
+ _count = 0;
+
+ TraceItem::clear();
+}
+
+
+
+void TraceCost::set(TraceSubMapping* sm, const char* s)
+{
+ if (!sm) return;
+ if (!s) {
+ if (_count>0) clear();
+ return;
+ }
+
+ while(*s == ' ') s++;
+
+ if (sm->isIdentity()) {
+ int i = 0;
+ while(i<sm->count()) {
+ if (!_cost[i].set(&s)) break;
+ i++;
+ }
+ _count = i;
+ }
+ else {
+ int i = 0, maxIndex = 0, index;
+ while(1) {
+ index = sm->realIndex(i);
+ if (maxIndex<index) maxIndex=index;
+ if (index == TraceCost::InvalidIndex) break;
+ if (!_cost[index].set(&s)) break;
+ i++;
+ }
+ // we have to set all costs of unused indexes till maxIndex to zero
+ for(i=sm->firstUnused(); i<=maxIndex; i=sm->nextUnused(i))
+ _cost[i] = 0;
+ _count = maxIndex;
+ }
+ // a cost change has to be propagated (esp. in subclasses)
+ invalidate();
+}
+
+void TraceCost::set(TraceSubMapping* sm, FixString & s)
+{
+ if (!sm) return;
+
+ s.stripSpaces();
+
+ if (sm->isIdentity()) {
+ int i = 0;
+ while(i<sm->count()) {
+ if (!s.stripUInt64(_cost[i])) break;
+ i++;
+ }
+ _count = i;
+ }
+ else {
+ int i = 0, maxIndex = 0, index;
+ while(1) {
+ index = sm->realIndex(i);
+ if (maxIndex<index) maxIndex=index;
+ if (index == TraceCost::InvalidIndex) break;
+ if (!s.stripUInt64(_cost[index])) break;
+ i++;
+ }
+ // we have to set all costs of unused indexes till maxIndex to zero
+ for(i=sm->firstUnused(); i<=maxIndex; i=sm->nextUnused(i))
+ _cost[i] = 0;
+ _count = maxIndex+1;
+ }
+ invalidate();
+}
+
+
+void TraceCost::addCost(TraceSubMapping* sm, const char* s)
+{
+ if (!sm || !s) return;
+
+ SubCost v;
+
+ if (sm->isIdentity()) {
+ int i = 0;
+ while(i<sm->count()) {
+ if (!v.set(&s)) break;
+ if (i<_count)
+ _cost[i] += v;
+ else
+ _cost[i] = v;
+ i++;
+ }
+ if (i > _count) _count = i;
+ }
+ else {
+ int i = 0, maxIndex = 0, index;
+ while(1) {
+ if (!v.set(&s)) break;
+ index = sm->realIndex(i);
+ if (maxIndex<index) maxIndex=index;
+ if (index == TraceCost::InvalidIndex) break;
+ if (index<_count)
+ _cost[index] += v;
+ else
+ _cost[index] = v;
+ i++;
+ }
+ if (maxIndex >= _count) {
+ /* we have to set all costs of unused indexes in the interval
+ * [_count;maxIndex] to zero */
+ for(i=sm->nextUnused(_count-1); i<=maxIndex; i=sm->nextUnused(i))
+ _cost[i] = 0;
+ _count = maxIndex+1;
+ }
+ }
+
+ // a cost change has to be propagated (esp. in subclasses)
+ invalidate();
+
+#if TRACE_DEBUG
+ _dirty = false; // don't recurse !
+ qDebug("%s\n now %s", fullName().ascii(),
+ TraceCost::costString(0).ascii());
+ _dirty = true; // because of invalidate()
+#endif
+}
+
+void TraceCost::addCost(TraceSubMapping* sm, FixString & s)
+{
+ if (!sm) return;
+
+ s.stripSpaces();
+
+ SubCost v;
+
+ if (sm->isIdentity()) {
+ int i = 0;
+ while(i<sm->count()) {
+ if (!s.stripUInt64(v)) break;
+ if (i<_count)
+ _cost[i] += v;
+ else
+ _cost[i] = v;
+ i++;
+ }
+ if (i > _count) _count = i;
+ }
+ else {
+ int i = 0, maxIndex = 0, index;
+ while(1) {
+ if (!s.stripUInt64(v)) break;
+ index = sm->realIndex(i);
+ if (maxIndex<index) maxIndex=index;
+ if (index == TraceCost::InvalidIndex) break;
+ if (index<_count)
+ _cost[index] += v;
+ else
+ _cost[index] = v;
+ i++;
+ }
+ if (maxIndex >= _count) {
+ /* we have to set all costs of unused indexes in the interval
+ * [_count;maxIndex] to zero */
+ for(i=sm->nextUnused(_count-1); i<=maxIndex; i=sm->nextUnused(i))
+ _cost[i] = 0;
+ _count = maxIndex+1;
+ }
+ }
+
+ invalidate();
+
+#if TRACE_DEBUG
+ _dirty = false; // don't recurse !
+ qDebug("%s\n now %s", fullName().ascii(),
+ TraceCost::costString(0).ascii());
+ _dirty = true; // because of invalidate()
+#endif
+}
+
+
+// update each subcost to be maximum of old and given costs
+void TraceCost::maxCost(TraceSubMapping* sm, FixString & s)
+{
+ if (!sm) return;
+
+ s.stripSpaces();
+
+ SubCost v;
+
+ if (sm->isIdentity()) {
+ int i = 0;
+ while(i<sm->count()) {
+ if (!s.stripUInt64(v)) break;
+ if (i<_count) {
+ if (v>_cost[i]) _cost[i] = v;
+ }
+ else
+ _cost[i] = v;
+ i++;
+ }
+ if (i > _count) _count = i;
+ }
+ else {
+ int i = 0, maxIndex = 0, index;
+ while(1) {
+ if (!s.stripUInt64(v)) break;
+ index = sm->realIndex(i);
+ if (maxIndex<index) maxIndex=index;
+ if (index == TraceCost::InvalidIndex) break;
+ if (index<_count) {
+ if (v>_cost[index]) _cost[index] = v;
+ }
+ else
+ _cost[index] = v;
+ i++;
+ }
+ if (maxIndex >= _count) {
+ /* we have to set all costs of unused indexes in the interval
+ * [_count;maxIndex] to zero */
+ for(i=sm->nextUnused(_count-1); i<=maxIndex; i=sm->nextUnused(i))
+ _cost[i] = 0;
+ _count = maxIndex+1;
+ }
+ }
+
+ invalidate();
+
+#if TRACE_DEBUG
+ _dirty = false; // don't recurse !
+ qDebug("%s\n now %s", fullName().ascii(),
+ TraceCost::costString(0).ascii());
+ _dirty = true; // because of invalidate()
+#endif
+}
+
+
+void TraceCost::addCost(TraceCost* item)
+{
+ int i;
+
+ if (!item) return;
+
+ // we have to update the other item if needed
+ // because we access the item costs directly
+ if (item->_dirty) item->update();
+
+ if (item->_count < _count) {
+ for (i = 0; i<item->_count; i++)
+ _cost[i] += item->_cost[i];
+ }
+ else {
+ for (i = 0; i<_count; i++)
+ _cost[i] += item->_cost[i];
+ for (; i<item->_count; i++)
+ _cost[i] = item->_cost[i];
+ _count = item->_count;
+ }
+
+ // a cost change has to be propagated (esp. in subclasses)
+ invalidate();
+
+#if TRACE_DEBUG
+ _dirty = false; // don't recurse !
+ qDebug("%s added cost item\n %s\n now %s",
+ fullName().ascii(), item->fullName().ascii(),
+ TraceCost::costString(0).ascii());
+ _dirty = true; // because of invalidate()
+#endif
+}
+
+void TraceCost::maxCost(TraceCost* item)
+{
+ int i;
+
+ if (!item) return;
+
+ // we have to update the other item if needed
+ // because we access the item costs directly
+ if (item->_dirty) item->update();
+
+ if (item->_count < _count) {
+ for (i = 0; i<item->_count; i++)
+ if (_cost[i] < item->_cost[i]) _cost[i] = item->_cost[i];
+ }
+ else {
+ for (i = 0; i<_count; i++)
+ if (_cost[i] < item->_cost[i]) _cost[i] = item->_cost[i];
+ for (; i<item->_count; i++)
+ _cost[i] = item->_cost[i];
+ _count = item->_count;
+ }
+
+ // a cost change has to be propagated (esp. in subclasses)
+ invalidate();
+
+#if TRACE_DEBUG
+ _dirty = false; // don't recurse !
+ qDebug("%s added cost item\n %s\n now %s",
+ fullName().ascii(), item->fullName().ascii(),
+ TraceCost::costString(0).ascii());
+ _dirty = true; // because of invalidate()
+#endif
+}
+
+void TraceCost::addCost(int type, SubCost value)
+{
+ if (type<0 || type>=MaxRealIndex) return;
+ if (type<_count)
+ _cost[type] += value;
+ else {
+ for(int i=_count;i<type;i++)
+ _cost[i] = 0;
+ _cost[type] = value;
+ _count = type+1;
+ }
+
+ // a cost change has to be propagated (esp. in subclasses)
+ invalidate();
+}
+
+void TraceCost::maxCost(int type, SubCost value)
+{
+ if (type<0 || type>=MaxRealIndex) return;
+ if (type<_count) {
+ if (value>_cost[type]) _cost[type] = value;
+ }
+ else {
+ for(int i=_count;i<type;i++)
+ _cost[i] = 0;
+ _cost[type] = value;
+ _count = type+1;
+ }
+
+ // a cost change has to be propagated (esp. in subclasses)
+ invalidate();
+}
+
+
+TraceCost TraceCost::diff(TraceCost* item)
+{
+ TraceCost res;
+
+ // we have to update the other item if needed
+ // because we access the item costs directly
+ if (item->_dirty) item->update();
+
+ int maxCount = (item->_count > _count) ? item->_count : _count;
+
+ res._count = maxCount;
+ for (int i=0; i<maxCount;i++)
+ res._cost[i] = item->subCost(i) - subCost(i);
+
+ return res;
+}
+
+QString TraceCost::costString(TraceCostMapping* m)
+{
+ QString res;
+
+ if (_dirty) update();
+
+ int maxIndex = m ? m->realCount() : TraceCost::MaxRealIndex;
+ for (int i = 0; i<maxIndex; i++) {
+ if (!res.isEmpty()) res += ", ";
+ if (m) res += m->type(i)->name() + " ";
+
+ res += subCost(i).pretty();
+ }
+ return res;
+}
+
+
+void TraceCost::invalidate()
+{
+ if (_dirty) return;
+ _dirty = true;
+ _cachedType = 0; // cached value is invalid, too
+
+ if (_dep)
+ _dep->invalidate();
+}
+
+void TraceCost::update()
+{
+ _dirty = false;
+}
+
+// this is only for real types
+SubCost TraceCost::subCost(int idx)
+{
+ if (idx<0) return 0;
+
+ /* update if needed as cost could be calculated dynamically in subclasses
+ * this can change _count !! */
+ if (_dirty) update();
+ if (idx>=_count) return 0;
+
+ return _cost[idx];
+}
+
+SubCost TraceCost::subCost(TraceCostType* t)
+{
+ if (!t) return 0;
+ if (_cachedType != t) {
+ _cachedType = t;
+ _cachedCost = t->subCost(this);
+ }
+ return _cachedCost;
+}
+
+QString TraceCost::prettySubCost(TraceCostType* t)
+{
+ return subCost(t).pretty();
+}
+
+
+
+//---------------------------------------------------
+// TraceJumpCost
+
+TraceJumpCost::TraceJumpCost()
+ :TraceItem()
+{
+ TraceJumpCost::clear();
+}
+
+TraceJumpCost::~TraceJumpCost()
+{}
+
+SubCost TraceJumpCost::executedCount()
+{
+ if (_dirty) update();
+
+ return _executedCount;
+}
+
+SubCost TraceJumpCost::followedCount()
+{
+ if (_dirty) update();
+
+ return _followedCount;
+}
+
+QString TraceJumpCost::costString(TraceCostMapping*)
+{
+ if (_dirty) update();
+
+ return QString("%1/%2")
+ .arg(_followedCount.pretty())
+ .arg(_executedCount.pretty());
+}
+
+void TraceJumpCost::clear()
+{
+ _followedCount = 0;
+ _executedCount = 0;
+}
+
+void TraceJumpCost::addCost(TraceJumpCost* item)
+{
+ if (item->_dirty) item->update();
+
+ _followedCount += item->followedCount();
+ _executedCount += item->executedCount();
+}
+
+
+//---------------------------------------------------
+// TraceCostType
+
+QPtrList<TraceCostType>* TraceCostType::_knownTypes = 0;
+
+TraceCostType::TraceCostType(QString name, QString longName, QString formula)
+{
+ _name = name;
+ _longName = longName;
+ _formula = formula;
+ _mapping = 0;
+ _realIndex = TraceCost::InvalidIndex;
+ _parsed = false;
+ _inParsing = false;
+
+ for (int i=0; i<TraceCost::MaxRealIndex;i++)
+ _coefficient[i] = 0;
+}
+
+void TraceCostType::setFormula(QString formula)
+{
+ _formula = formula;
+ _realIndex = TraceCost::InvalidIndex;
+ _parsed = false;
+}
+
+void TraceCostType::setMapping(TraceCostMapping* m)
+{
+ _parsed = false;
+ _mapping = m;
+}
+
+// setting the index to TraceCost::MaxRealIndex makes it a
+// real type with unspecified index
+void TraceCostType::setRealIndex(int i)
+{
+ if (i<0 || i>TraceCost::MaxRealIndex)
+ i=TraceCost::InvalidIndex;
+
+ _realIndex = i;
+ _formula = QString::null;
+}
+
+// checks for existing types and sets coefficients
+bool TraceCostType::parseFormula()
+{
+ if (_parsed) return true;
+ if (_inParsing) {
+ qDebug("TraceCostType::parseFormula: Recursion detected.");
+ return false;
+ }
+
+ if (!_mapping) {
+ qDebug("TraceCostType::parseFormula: No mapping set!");
+ return false;
+ }
+
+ _inParsing = true;
+
+ for (int i=0; i<TraceCost::MaxRealIndex;i++)
+ _coefficient[i] = 0;
+
+ QRegExp rx( "((?:\\+|\\-)?)\\s*(\\d*)\\s*\\*?\\s*(\\w+)" );
+
+ int factor, pos;
+ QString costName;
+ TraceCostType* costType;
+
+ pos = 0;
+ while (1) {
+ pos = rx.search(_formula, pos);
+ if (pos<0) break;
+ pos += rx.matchedLength();
+ if (rx.cap(0).isEmpty()) break;
+
+ //qDebug("parseFormula: matched '%s','%s','%s'",
+ // rx.cap(1).ascii(), rx.cap(2).ascii(), rx.cap(3).ascii());
+
+ costName = rx.cap(3);
+ costType = _mapping->type(costName);
+ if (!costType) {
+ // qDebug("Cost type '%s': In formula cost '%s' unknown.",
+ // _name.ascii(), costName.ascii());
+
+ _inParsing = false;
+ return false;
+ }
+
+ factor = (rx.cap(2).isEmpty()) ? 1 : rx.cap(2).toInt();
+ if (rx.cap(1) == "-") factor = -factor;
+
+ if (costType->isReal())
+ _coefficient[costType->realIndex()] += factor;
+ else {
+ costType->parseFormula();
+ for (int i=0; i<TraceCost::MaxRealIndex;i++)
+ _coefficient[i] += factor * costType->_coefficient[i];
+ }
+ }
+
+ _inParsing = false;
+ _parsed = true;
+
+ return true;
+}
+
+QString TraceCostType::parsedFormula()
+{
+ QString res;
+
+ if (!parseFormula()) return res;
+
+ for (int i=0; i<TraceCost::MaxRealIndex;i++) {
+ int c = _coefficient[i];
+ if (c == 0) continue;
+
+ if (!res.isEmpty()) {
+ res += " ";
+ if (c>0) res += "+ ";
+ }
+ if (c<0) { res += "- "; c = -c; }
+ res += QString::number(c);
+
+ TraceCostType* t = _mapping->type(i);
+ if (!t) continue;
+
+ if (!t->name().isEmpty())
+ res += QString(" * %1").arg(t->name());
+ }
+
+ return res;
+}
+
+SubCost TraceCostType::subCost(TraceCost* c)
+{
+ if (_realIndex != TraceCost::InvalidIndex)
+ return c->subCost(_realIndex);
+
+ if (!_parsed) {
+ if (!parseFormula()) return 0;
+ }
+ SubCost res = 0;
+
+ int rc = _mapping->realCount();
+ for (int i = 0;i<rc;i++)
+ if (_coefficient[i] != 0)
+ res += _coefficient[i] * c->subCost(i);
+
+ return res;
+}
+
+int TraceCostType::histCost(TraceCost* c, double total, double* hist)
+{
+ if (total == 0.0) return 0;
+
+ if (!_parsed) {
+ if (!parseFormula()) return 0;
+ }
+
+ int rc = _mapping->realCount();
+ for (int i = 0;i<rc;i++) {
+ if (_coefficient[i] != 0)
+ hist[i] = _coefficient[i] * c->subCost(i) / total;
+ else
+ hist[i] = 0.0;
+ }
+
+ return rc;
+}
+
+
+
+
+TraceCostType* TraceCostType::knownRealType(QString n)
+{
+ if (!_knownTypes) return 0;
+
+ TraceCostType* t;
+ for (t=_knownTypes->first();t;t=_knownTypes->next())
+ if (t->isReal() && (t->name() == n)) {
+ TraceCostType* type = new TraceCostType(*t);
+ return type;
+ }
+
+ return 0;
+}
+
+TraceCostType* TraceCostType::knownVirtualType(QString n)
+{
+ if (!_knownTypes) return 0;
+
+ TraceCostType* t;
+ for (t=_knownTypes->first();t;t=_knownTypes->next())
+ if (!t->isReal() && (t->name() == n)) {
+ TraceCostType* type = new TraceCostType(*t);
+ return type;
+ }
+
+ return 0;
+}
+
+// we take ownership
+void TraceCostType::add(TraceCostType* t)
+{
+ if (!t) return;
+
+ t->setMapping(0);
+
+ if (!_knownTypes)
+ _knownTypes = new QPtrList<TraceCostType>;
+
+ /* Already known? */
+ TraceCostType* kt;
+ for (kt=_knownTypes->first();kt;kt=_knownTypes->next())
+ if (kt->name() == t->name()) break;
+
+ if (kt) {
+ // Overwrite old type
+ if (!t->longName().isEmpty() &&
+ (t->longName() != t->name())) kt->setLongName(t->longName());
+ if (!t->formula().isEmpty()) kt->setFormula(t->formula());
+
+ delete t;
+ }
+ else {
+ if (t->longName().isEmpty()) t->setLongName(t->name());
+ _knownTypes->append(t);
+ }
+}
+
+
+int TraceCostType::knownTypeCount()
+{
+ if (!_knownTypes) return 0;
+
+ return _knownTypes->count();
+}
+
+bool TraceCostType::remove(QString n)
+{
+ if (!_knownTypes) return false;
+
+ TraceCostType* t;
+ for (t=_knownTypes->first();t;t=_knownTypes->next())
+ if (!t->isReal() && (t->name() == n)) {
+ _knownTypes->removeRef(t);
+ delete t;
+ return true;
+ }
+
+ return false;
+}
+
+TraceCostType* TraceCostType::knownType(int i)
+{
+ if (!_knownTypes) return 0;
+ if (i<0 || i>=(int)_knownTypes->count()) return 0;
+
+ return _knownTypes->at(i);
+}
+
+QColor TraceCostType::color()
+{
+ if (!_mapping) return QColor();
+ return _mapping->realColors()[_realIndex];
+}
+
+
+//---------------------------------------------------
+// TraceCostMapping
+
+TraceCostMapping::TraceCostMapping()
+{
+ _realCount = 0;
+ _virtualCount = 0;
+ for (int i=0;i<TraceCost::MaxRealIndex;i++) _real[i] = 0;
+ for (int i=0;i<TraceCost::MaxRealIndex;i++) _virtual[i] = 0;
+}
+
+TraceCostMapping::~TraceCostMapping()
+{
+ for (int i=0;i<TraceCost::MaxRealIndex;i++)
+ if (_real[i]) delete _real[i];
+
+ for (int i=0;i<TraceCost::MaxRealIndex;i++)
+ if (_virtual[i]) delete _virtual[i];
+}
+
+TraceSubMapping* TraceCostMapping::subMapping(QString types, bool create)
+{
+ // first check if there's enough space in the mapping
+ int newCount = 0;
+ int pos = 0, pos2, len = types.length();
+
+ while (1) {
+ // skip space
+ while((pos<len) && types[pos].isSpace()) pos++;
+
+ pos2 = pos;
+ while((pos2<len) && !types[pos2].isSpace()) pos2++;
+ if (pos2 == pos) break;
+
+ if (realIndex(types.mid(pos,pos2-pos)) == TraceCost::InvalidIndex)
+ newCount++;
+
+ pos = pos2;
+ }
+
+ if (!create && (newCount>0)) return 0;
+
+ if (newCount+_realCount > TraceCost::MaxRealIndex) {
+ kdDebug() << "TraceCostMapping::subMapping: No space for "
+ << newCount << " sub costs." << endl;
+ return 0;
+ }
+
+ TraceSubMapping* sm = new TraceSubMapping(this);
+
+ pos = 0;
+ while (1) {
+ // skip space
+ while((pos<len) && types[pos].isSpace()) pos++;
+
+ pos2 = pos;
+ while((pos2<len) && !types[pos2].isSpace()) pos2++;
+ if (pos2 == pos) break;
+
+ sm->append(addReal(types.mid(pos,pos2-pos)));
+
+ pos = pos2;
+ }
+
+ return sm;
+}
+
+
+int TraceCostMapping::addReal(QString t)
+{
+ int index = realIndex(t);
+ if (index>=0) return index;
+
+ TraceCostType* ct = TraceCostType::knownRealType(t);
+ if (!ct) ct = new TraceCostType(t, t);
+
+ // make it real
+ ct->setRealIndex();
+
+ return add(ct);
+}
+
+// add a cost type to a mapping
+// this transfers ownership of the type!
+int TraceCostMapping::add(TraceCostType* ct)
+{
+ if (!ct) return TraceCost::InvalidIndex;
+
+ ct->setMapping(this);
+
+ if (ct->isReal()) {
+ if (_realCount >= TraceCost::MaxRealIndex) {
+ qDebug("WARNING: Maximum for real cost types reached (on adding '%s')",
+ ct->name().ascii());
+ return TraceCost::InvalidIndex;
+ }
+ _real[_realCount] = ct;
+ ct->setRealIndex(_realCount);
+ _realColor[_realCount] = Configuration::costTypeColor(ct);
+
+ _realCount++;
+ return _realCount-1;
+ }
+
+ if (_virtualCount >= TraceCost::MaxRealIndex) {
+ qDebug("WARNING: Maximum for virtual cost types reached (on adding '%s')",
+ ct->name().ascii());
+ return TraceCost::InvalidIndex;
+ }
+ _virtual[_virtualCount] = ct;
+ _virtualCount++;
+ return _virtualCount-1;
+}
+
+// we delete the type: t is invalid when returning true!
+bool TraceCostMapping::remove(TraceCostType* t)
+{
+ if (!t) return false;
+ if (t->mapping() != this) return false;
+
+ // don't delete real types
+ if (t->isReal()) return false;
+
+ int i;
+ for(i=0;i<_virtualCount;i++)
+ if (_virtual[i] == t) break;
+
+ // not found?
+ if (i == _virtualCount) return false;
+
+ // delete known type with same name
+ TraceCostType::remove(t->name());
+
+ // delete this type
+ _virtual[i] = 0;
+ delete t;
+ if (i+1 == _virtualCount) {
+ // we can reuse the last index
+ _virtualCount--;
+ }
+ return true;
+}
+
+
+TraceCostType* TraceCostMapping::realType(int t)
+{
+ if (t<0 || t>=_realCount) return 0;
+ return _real[t];
+}
+
+TraceCostType* TraceCostMapping::virtualType(int t)
+{
+ if (t<0 || t>=_virtualCount) return 0;
+ return _virtual[t];
+}
+
+
+TraceCostType* TraceCostMapping::type(int t)
+{
+ if (t<0) return 0;
+ if (t<_realCount) return _real[t];
+
+ t -= TraceCost::MaxRealIndex;
+ if (t<0) return 0;
+ if (t<_virtualCount) return _virtual[t];
+
+ return 0;
+}
+
+TraceCostType* TraceCostMapping::type(QString name)
+{
+ for (int i=0;i<_realCount;i++)
+ if (_real[i] && (_real[i]->name() == name))
+ return _real[i];
+
+ for (int i=0;i<_virtualCount;i++)
+ if (_virtual[i] && (_virtual[i]->name() == name))
+ return _virtual[i];
+
+ return 0;
+}
+
+TraceCostType* TraceCostMapping::typeForLong(QString name)
+{
+ for (int i=0;i<_realCount;i++)
+ if (_real[i] && (_real[i]->longName() == name))
+ return _real[i];
+
+ for (int i=0;i<_virtualCount;i++)
+ if (_virtual[i] && (_virtual[i]->longName() == name))
+ return _virtual[i];
+
+ return 0;
+}
+
+
+int TraceCostMapping::realIndex(QString name)
+{
+ for (int i=0;i<_realCount;i++)
+ if (_real[i] && (_real[i]->name() == name))
+ return i;
+
+ return TraceCost::InvalidIndex;
+}
+
+int TraceCostMapping::index(QString name)
+{
+ for (int i=0;i<_realCount;i++)
+ if (_real[i] && (_real[i]->name() == name))
+ return i;
+
+ for (int i=0;i<_virtualCount;i++)
+ if (_virtual[i] && (_virtual[i]->name() == name))
+ return TraceCost::MaxRealIndex + 1 + i;
+
+ return TraceCost::InvalidIndex;
+}
+
+int TraceCostMapping::addKnownVirtualTypes()
+{
+ int addCount = 0;
+ int addDiff, i;
+ int knownCount = TraceCostType::knownTypeCount();
+
+ while (1) {
+ addDiff = 0;
+ for (i=0; i<knownCount; i++) {
+ TraceCostType* t = TraceCostType::knownType(i);
+ if (t->isReal()) continue;
+ if (index(t->name()) != TraceCost::InvalidIndex) continue;
+ t->setMapping(this);
+ if (t->parseFormula()) {
+ addDiff++;
+ add(new TraceCostType(t->name(), t->longName(), t->formula()));
+ }
+ t->setMapping(0);
+ }
+ if (addDiff == 0) break;
+ addCount += addDiff;
+ }
+ return addCount;
+}
+
+
+//---------------------------------------------------
+// TraceSubMapping
+
+TraceSubMapping::TraceSubMapping(TraceCostMapping* mapping)
+{
+ _mapping = mapping;
+ clear();
+}
+
+void TraceSubMapping::clear()
+{
+ _count = 0;
+ _isIdentity = true;
+ _firstUnused = 0;
+ for(int i=0;i<TraceCost::MaxRealIndex;i++) {
+ _realIndex[i] = TraceCost::InvalidIndex;
+ _nextUnused[i] = i+1;
+ }
+}
+
+bool TraceSubMapping::append(QString type, bool create)
+{
+ if (!_mapping) return false;
+ int index = create ? _mapping->addReal(type) : _mapping->realIndex(type);
+
+ return append(index);
+}
+
+bool TraceSubMapping::append(int type)
+{
+ if (!_mapping) return false;
+ if ((type<0) || (type >= _mapping->realCount())) return false;
+
+ if ( _count >= TraceCost::MaxRealIndex) return false;
+
+ _realIndex[_count] = type;
+
+ if (_isIdentity && (_count != type)) _isIdentity = false;
+ if (type == _firstUnused)
+ _firstUnused = _nextUnused[type];
+ for(int i=0;i<type;i++)
+ if (_nextUnused[i] == type)
+ _nextUnused[i]=_nextUnused[type];
+
+ _count++;
+ return true;
+}
+
+
+//---------------------------------------------------
+// TraceCallCost
+
+TraceCallCost::TraceCallCost()
+{
+ _callCount = 0;
+}
+
+TraceCallCost::~TraceCallCost()
+{}
+
+
+QString TraceCallCost::costString(TraceCostMapping* m)
+{
+ return QString("%1, Calls %2")
+ .arg(TraceCost::costString(m))
+ .arg(_callCount.pretty());
+}
+
+QString TraceCallCost::prettyCallCount()
+{
+ return _callCount.pretty();
+}
+
+void TraceCallCost::clear()
+{
+ _callCount = 0;
+ TraceCost::clear();
+}
+
+SubCost TraceCallCost::callCount()
+{
+ if (_dirty) update();
+
+ return _callCount;
+}
+
+void TraceCallCost::addCallCount(SubCost c)
+{
+ _callCount += c;
+
+ invalidate();
+}
+
+
+//---------------------------------------------------
+// TraceInclusiveCost
+
+TraceInclusiveCost::TraceInclusiveCost()
+{}
+
+TraceInclusiveCost::~TraceInclusiveCost()
+{}
+
+QString TraceInclusiveCost::costString(TraceCostMapping* m)
+{
+ return QString("%1, Inclusive %2")
+ .arg(TraceCost::costString(m))
+ .arg(_inclusive.costString(m));
+}
+
+void TraceInclusiveCost::clear()
+{
+ _inclusive.clear();
+ TraceCost::clear();
+}
+
+TraceCost* TraceInclusiveCost::inclusive()
+{
+ if (_dirty) update();
+
+ return &_inclusive;
+}
+
+void TraceInclusiveCost::addInclusive(TraceCost* c)
+{
+ _inclusive.addCost(c);
+
+ invalidate();
+}
+
+
+//---------------------------------------------------
+// TraceListCost
+
+TraceListCost::TraceListCost()
+{
+ _lastDep = 0;
+}
+
+TraceListCost::~TraceListCost()
+{}
+
+void TraceListCost::addDep(TraceCost* dep)
+{
+#if TRACE_ASSERTIONS
+ if (_deps.findRef(dep)>=0) {
+ qDebug("addDep: %s already in list!",
+ dep->fullName().ascii());
+ return;
+ }
+#endif
+
+ _deps.append(dep);
+ _lastDep = dep;
+ invalidate();
+
+#if TRACE_DEBUG
+ qDebug("%s added\n %s (now %d)",
+ fullName().ascii(), dep->fullName().ascii(),
+ _deps.count());
+#endif
+}
+
+TraceCost* TraceListCost::findDepFromPart(TracePart* part)
+{
+ if (_lastDep && _lastDep->part() == part)
+ return _lastDep;
+
+ TraceCost* dep;
+ for (dep = _deps.first(); dep; dep = _deps.next())
+ if (dep->part() == part) {
+ _lastDep = dep;
+ return dep;
+ }
+ return 0;
+}
+
+
+void TraceListCost::update()
+{
+ if (!_dirty) return;
+
+#if TRACE_DEBUG
+ qDebug("update %s (count %d)",
+ fullName().ascii(), _deps.count());
+#endif
+
+ clear();
+ TraceCost* item;
+ for (item = _deps.first(); item; item = _deps.next()) {
+ if (onlyActiveParts())
+ if (!item->part() || !item->part()->isActive()) continue;
+
+ addCost(item);
+ }
+
+ _dirty = false;
+
+#if TRACE_DEBUG
+ qDebug(" > %s", costString(0).ascii());
+#endif
+}
+
+
+
+//---------------------------------------------------
+// TraceJumpListCost
+
+TraceJumpListCost::TraceJumpListCost()
+{
+ _lastDep = 0;
+}
+
+TraceJumpListCost::~TraceJumpListCost()
+{}
+
+void TraceJumpListCost::addDep(TraceJumpCost* dep)
+{
+#if TRACE_ASSERTIONS
+ if (_deps.findRef(dep)>=0) {
+ qDebug("addDep: %s already in list!",
+ dep->fullName().ascii());
+ return;
+ }
+#endif
+
+ _deps.append(dep);
+ _lastDep = dep;
+ invalidate();
+
+#if TRACE_DEBUG
+ qDebug("%s added\n %s (now %d)",
+ fullName().ascii(), dep->fullName().ascii(),
+ _deps.count());
+#endif
+}
+
+TraceJumpCost* TraceJumpListCost::findDepFromPart(TracePart* part)
+{
+ if (_lastDep && _lastDep->part() == part)
+ return _lastDep;
+
+ TraceJumpCost* dep;
+ for (dep = _deps.first(); dep; dep = _deps.next())
+ if (dep->part() == part) {
+ _lastDep = dep;
+ return dep;
+ }
+ return 0;
+}
+
+
+void TraceJumpListCost::update()
+{
+ if (!_dirty) return;
+
+#if TRACE_DEBUG
+ qDebug("update %s (count %d)",
+ fullName().ascii(), _deps.count());
+#endif
+
+ clear();
+ TraceJumpCost* item;
+ for (item = _deps.first(); item; item = _deps.next()) {
+ if (onlyActiveParts())
+ if (!item->part() || !item->part()->isActive()) continue;
+
+ addCost(item);
+ }
+
+ _dirty = false;
+
+#if TRACE_DEBUG
+ qDebug(" > %s", costString(0).ascii());
+#endif
+}
+
+
+
+//---------------------------------------------------
+// TraceCallListCost
+
+TraceCallListCost::TraceCallListCost()
+{
+ _lastDep = 0;
+}
+
+TraceCallListCost::~TraceCallListCost()
+{}
+
+void TraceCallListCost::addDep(TraceCallCost* dep)
+{
+#if TRACE_ASSERTIONS
+ if (_deps.findRef(dep)>=0) {
+ qDebug("addDep: %s already in list!",
+ dep->fullName().ascii());
+ return;
+ }
+#endif
+
+ _deps.append(dep);
+ _lastDep = dep;
+ invalidate();
+
+#if TRACE_DEBUG
+ qDebug("%s added\n %s (now %d)",
+ fullName().ascii(), dep->fullName().ascii(),
+ _deps.count());
+#endif
+}
+
+TraceCallCost* TraceCallListCost::findDepFromPart(TracePart* part)
+{
+ if (_lastDep && _lastDep->part() == part)
+ return _lastDep;
+
+ TraceCallCost* dep;
+ for (dep = _deps.first(); dep; dep = _deps.next())
+ if (dep->part() == part) {
+ _lastDep = dep;
+ return dep;
+ }
+ return 0;
+}
+
+
+void TraceCallListCost::update()
+{
+ if (!_dirty) return;
+
+#if TRACE_DEBUG
+ qDebug("update %s (count %d)",
+ fullName().ascii(), _deps.count());
+#endif
+
+ /* Without dependent cost items, assume fixed costs,
+ * i.e. don't change cost */
+ if (_deps.count()>0) {
+ clear();
+ TraceCallCost* item;
+ for (item = _deps.first(); item; item = _deps.next()) {
+ if (onlyActiveParts())
+ if (!item->part() || !item->part()->isActive()) continue;
+
+ addCost(item);
+ addCallCount(item->callCount());
+ }
+ }
+
+ _dirty = false;
+
+#if TRACE_DEBUG
+ qDebug(" > %s", costString(0).ascii());
+#endif
+}
+
+
+//---------------------------------------------------
+// TraceInclusiveListCost
+
+TraceInclusiveListCost::TraceInclusiveListCost()
+{
+ _lastDep = 0;
+}
+
+TraceInclusiveListCost::~TraceInclusiveListCost()
+{}
+
+
+void TraceInclusiveListCost::addDep(TraceInclusiveCost* dep)
+{
+#if TRACE_ASSERTIONS
+ if (_deps.findRef(dep)>=0) {
+ qDebug("addDep: %s already in list!",
+ dep->fullName().ascii());
+ return;
+ }
+#endif
+
+ _deps.append(dep);
+ _lastDep = dep;
+ invalidate();
+
+#if TRACE_DEBUG
+ qDebug("%s added\n %s (now %d)",
+ fullName().ascii(), dep->fullName().ascii(),
+ _deps.count());
+#endif
+}
+
+TraceInclusiveCost* TraceInclusiveListCost::findDepFromPart(TracePart* part)
+{
+ if (_lastDep && _lastDep->part() == part)
+ return _lastDep;
+
+ TraceInclusiveCost* dep;
+ for (dep = _deps.first(); dep; dep = _deps.next())
+ if (dep->part() == part) {
+ _lastDep = dep;
+ return dep;
+ }
+ return 0;
+}
+
+void TraceInclusiveListCost::update()
+{
+ if (!_dirty) return;
+
+#if TRACE_DEBUG
+ qDebug("update %s (count %d)",
+ fullName().ascii(), _deps.count());
+#endif
+
+ clear();
+ TraceInclusiveCost* item;
+ for (item = _deps.first(); item; item = _deps.next()) {
+ if (onlyActiveParts())
+ if (!item->part() || !item->part()->isActive()) continue;
+
+ addCost(item);
+ addInclusive(item->inclusive());
+ }
+
+ _dirty = false;
+
+#if TRACE_DEBUG
+ qDebug(" > %s", costString(0).ascii());
+#endif
+}
+
+
+
+//---------------------------------------------------
+// TracePartInstrJump
+
+TracePartInstrJump::TracePartInstrJump(TraceInstrJump* instrJump,
+ TracePartInstrJump* next)
+{
+ _dep = instrJump;
+ _next = next;
+}
+
+TracePartInstrJump::~TracePartInstrJump()
+{}
+
+
+//---------------------------------------------------
+// TracePartInstrCall
+
+TracePartInstrCall::TracePartInstrCall(TraceInstrCall* instrCall)
+{
+ _dep = instrCall;
+}
+
+TracePartInstrCall::~TracePartInstrCall()
+{}
+
+
+
+//---------------------------------------------------
+// TracePartInstr
+
+TracePartInstr::TracePartInstr(TraceInstr* instr)
+{
+ _dep = instr;
+}
+
+TracePartInstr::~TracePartInstr()
+{}
+
+
+
+//---------------------------------------------------
+// TracePartLineJump
+
+TracePartLineJump::TracePartLineJump(TraceLineJump* lineJump)
+{
+ _dep = lineJump;
+}
+
+TracePartLineJump::~TracePartLineJump()
+{}
+
+
+//---------------------------------------------------
+// TracePartLineCall
+
+TracePartLineCall::TracePartLineCall(TraceLineCall* lineCall)
+{
+ _dep = lineCall;
+}
+
+TracePartLineCall::~TracePartLineCall()
+{}
+
+
+//---------------------------------------------------
+// TracePartLine
+
+TracePartLine::TracePartLine(TraceLine* line)
+{
+ _dep = line;
+}
+
+TracePartLine::~TracePartLine()
+{}
+
+
+
+
+//---------------------------------------------------
+// TracePartCall
+
+TracePartCall::TracePartCall(TraceCall* call)
+{
+ _dep = call;
+
+ _firstFixCallCost = 0;
+}
+
+TracePartCall::~TracePartCall()
+{}
+
+bool TracePartCall::isRecursion()
+{
+ return call()->isRecursion();
+}
+
+void TracePartCall::update()
+{
+#if !USE_FIXCOST
+ TraceCallListCost::update();
+#else
+
+ if (!_dirty) return;
+
+#if TRACE_DEBUG
+ qDebug("update %s", fullName().ascii());
+#endif
+
+ /* Without dependent cost items, assume fixed costs,
+ * i.e. don't change cost */
+ if (_firstFixCallCost) {
+ clear();
+ FixCallCost* item;
+ for (item = _firstFixCallCost; item; item = item->nextCostOfPartCall())
+ item->addTo(this);
+ }
+
+ _dirty = false;
+
+#if TRACE_DEBUG
+ qDebug(" > %s", costString(0).ascii());
+#endif
+
+#endif // USE_FIXCOST
+}
+
+
+//---------------------------------------------------
+// TracePartFunction
+
+TracePartFunction::TracePartFunction(TraceFunction* function,
+ TracePartObject* partObject,
+ TracePartFile *partFile)
+{
+ _dep = function;
+ _partObject = partObject;
+ _partFile = partFile;
+ _partClass = 0;
+
+ _calledCount = 0;
+ _callingCount = 0;
+ _calledContexts = 0;
+ _callingContexts = 0;
+
+ _firstFixCost = 0;
+ _firstFixJump = 0;
+}
+
+TracePartFunction::~TracePartFunction()
+{}
+
+QString TracePartFunction::prettyCalledCount()
+{
+ return _calledCount.pretty();
+}
+
+QString TracePartFunction::prettyCallingCount()
+{
+ return _callingCount.pretty();
+}
+
+QString TracePartFunction::costString(TraceCostMapping* m)
+{
+ update();
+
+ QString res = TraceInclusiveCost::costString(m);
+ res += QString(", called from %1: %2")
+ .arg(_calledContexts).arg(prettyCalledCount());
+ res += QString(", calling from %1: %2")
+ .arg(_callingContexts).arg(prettyCallingCount());
+
+ return res;
+}
+
+
+void TracePartFunction::addPartInstr(TracePartInstr* ref)
+{
+#if TRACE_ASSERTIONS
+ if (_partInstr.findRef(ref)>=0) {
+ qDebug("TracePartFunction::addPartInstr: %s already in list!",
+ ref->name().ascii());
+ return;
+ }
+#endif
+
+ _partInstr.append(ref);
+ invalidate();
+
+#if TRACE_DEBUG
+ qDebug("%s added\n %s (now %d)",
+ fullName().ascii(), ref->fullName().ascii(),
+ _partInstr.count());
+#endif
+}
+
+
+void TracePartFunction::addPartLine(TracePartLine* ref)
+{
+#if TRACE_ASSERTIONS
+ if (_partLines.findRef(ref)>=0) {
+ qDebug("TracePartFunction::addPartLine: %s already in list!",
+ ref->name().ascii());
+ return;
+ }
+#endif
+
+ _partLines.append(ref);
+ invalidate();
+
+#if TRACE_DEBUG
+ qDebug("%s added\n %s (now %d)",
+ fullName().ascii(), ref->fullName().ascii(),
+ _partLines.count());
+#endif
+}
+
+
+void TracePartFunction::addPartCaller(TracePartCall* ref)
+{
+#if TRACE_ASSERTIONS
+ if (_partCallers.findRef(ref)>=0) {
+ qDebug("TracePartFunction::addPartCaller: %s already in list!",
+ ref->name().ascii());
+ return;
+ }
+#endif
+
+ _partCallers.append(ref);
+ invalidate();
+
+#if TRACE_DEBUG
+ qDebug("%s added Caller\n %s (now %d)",
+ fullName().ascii(), ref->fullName().ascii(),
+ _partCallers.count());
+#endif
+}
+
+
+void TracePartFunction::addPartCalling(TracePartCall* ref)
+{
+#if TRACE_ASSERTIONS
+ if (_partCallings.findRef(ref)>=0) {
+ qDebug("TracePartFunction::addPartCalling: %s already in list!",
+ ref->name().ascii());
+ return;
+ }
+#endif
+
+ _partCallings.append(ref);
+ invalidate();
+
+#if TRACE_DEBUG
+ qDebug("%s added Calling\n %s (now %d)",
+ fullName().ascii(), ref->fullName().ascii(),
+ _partCallings.count());
+#endif
+}
+
+SubCost TracePartFunction::calledCount()
+{
+ if (_dirty) update();
+
+ return _calledCount;
+}
+
+int TracePartFunction::calledContexts()
+{
+ if (_dirty) update();
+
+ return _calledContexts;
+}
+
+SubCost TracePartFunction::callingCount()
+{
+ if (_dirty) update();
+
+ return _callingCount;
+}
+
+
+int TracePartFunction::callingContexts()
+{
+ if (_dirty) update();
+
+ return _callingContexts;
+}
+
+
+void TracePartFunction::update()
+{
+ if (!_dirty) return;
+
+#if TRACE_DEBUG
+ qDebug("TracePartFunction::update %s (Callers %d, Callings %d, lines %d)",
+ name().ascii(), _partCallers.count(), _partCallings.count(),
+ _partLines.count());
+#endif
+
+ _calledCount = 0;
+ _callingCount = 0;
+ _calledContexts = 0;
+ _callingContexts = 0;
+
+ // calculate additional cost metrics
+ TracePartCall *caller, *calling;
+ for (caller=_partCallers.first();caller;caller=_partCallers.next()) {
+
+ // FIXME
+ if (caller->subCost(0)>0)
+ _calledContexts++;
+
+ SubCost c = caller->callCount();
+ if (c>0) {
+ _calledCount += c;
+ }
+ }
+ for (calling=_partCallings.first();calling;calling=_partCallings.next()) {
+ // FIXME
+ if (calling->subCost(0)>0)
+ _callingContexts++;
+
+ SubCost c = calling->callCount();
+ if (c>0) {
+ _callingCount += c;
+ }
+ }
+
+ // self cost
+#if !USE_FIXCOST
+ if (_partLines.count()>0) {
+ TraceCost::clear();
+
+ TracePartLine* line;
+ for (line = _partLines.first(); line; line = _partLines.next())
+ addCost(line);
+ }
+#else
+ if (_firstFixCost) {
+ TraceCost::clear();
+
+ FixCost* item;
+ for (item = _firstFixCost; item; item = item->nextCostOfPartFunction())
+ item->addTo(this);
+ }
+#endif
+
+
+ /* There are two possibilities to calculate inclusive cost:
+ * 1) sum of call costs to this function
+ * 2) sum of call costs from this function + self cost
+ *
+ * 1) is wrong if a function was called spontaneous, but also by a call.
+ * This eventually can happen with thread/process startup functions,
+ * and signal handlers.
+ *
+ * 2) is wrong with "skipped PLT" and the calltree skin, because
+ * cost of PLT is attributed to called function (?)
+ *
+ * For now, do 1) if there are callers, otherwise 2).
+ * Should this be fixed to take the maximum of 1) and 2) ?
+ */
+ _inclusive.clear();
+ if (_calledCount>0) {
+ // inclusive cost: if possible, use caller sums
+ for (caller=_partCallers.first();caller;caller=_partCallers.next()) {
+ // detect simple recursion (no cycle)
+ if (caller->isRecursion()) continue;
+
+ addInclusive(caller);
+ }
+ }
+ else {
+ // without caller info, use calling sum + line costs
+ for (calling=_partCallings.first();calling;calling=_partCallings.next()) {
+ // detect simple recursion (no cycle)
+ if (calling->isRecursion()) continue;
+
+ addInclusive(calling);
+ }
+ _dirty = false; // don't recurse!
+ addInclusive(this);
+ }
+
+ _dirty = false;
+
+#if TRACE_DEBUG
+ qDebug(" > %s", costString(0).ascii());
+#endif
+}
+
+
+
+//---------------------------------------------------
+// TracePartClass
+
+TracePartClass::TracePartClass(TraceClass* cls)
+{
+ _dep = cls;
+}
+
+TracePartClass::~TracePartClass()
+{}
+
+QString TracePartClass::prettyName() const
+{
+ return QString("%1 from %2")
+ .arg( _dep->name().isEmpty() ? QString("(global)") : _dep->name())
+ .arg(part()->name());
+}
+
+//---------------------------------------------------
+// TracePartFile
+
+TracePartFile::TracePartFile(TraceFile* file)
+{
+ _dep = file;
+}
+
+TracePartFile::~TracePartFile()
+{}
+
+
+//---------------------------------------------------
+// TracePartObject
+
+TracePartObject::TracePartObject(TraceObject* object)
+{
+ _dep = object;
+}
+
+TracePartObject::~TracePartObject()
+{}
+
+
+
+
+//---------------------------------------------------
+// TraceInstrJump
+
+TraceInstrJump::TraceInstrJump(TraceInstr* instrFrom, TraceInstr* instrTo,
+ bool isCondJump)
+{
+ _first = 0;
+
+ _instrFrom = instrFrom;
+ _instrTo = instrTo;
+ _isCondJump = isCondJump;
+}
+
+TraceInstrJump::~TraceInstrJump()
+{
+ // we are the owner of the TracePartInstrJump's generated in our factory
+ TracePartInstrJump* item = _first, *next;
+ while(item) {
+ next = item->next();
+ delete item;
+ item = next;
+ }
+}
+
+TracePartInstrJump* TraceInstrJump::partInstrJump(TracePart* part)
+{
+ static TracePartInstrJump* item = 0;
+
+ // shortcut
+ if (item && (item->instrJump()==this) && (item->part() == part)) return item;
+
+ for(item = _first; item; item = item->next())
+ if (item->part() == part) break;
+
+ if (!item) {
+ item = new TracePartInstrJump(this, _first);
+ item->setPosition(part);
+ _first = item;
+ }
+ return item;
+}
+
+void TraceInstrJump::update()
+{
+ if (!_dirty) return;
+
+ clear();
+ TracePartInstrJump* item;
+ for (item = _first; item; item = item->next()) {
+ if (!item->part() || !item->part()->isActive()) continue;
+
+ addCost(item);
+ }
+ _dirty = false;
+
+#if TRACE_DEBUG
+ qDebug("updated %s", fullName().ascii());
+#endif
+
+#if TRACE_DEBUG
+ qDebug(" > %s", costString(0).ascii());
+#endif
+}
+
+QString TraceInstrJump::name() const
+{
+ return QString("jump at 0x%1 to 0x%2")
+ .arg(_instrFrom->addr().toString())
+ .arg(_instrTo->addr().toString());
+}
+
+
+//---------------------------------------------------
+// TraceInstrJumpList
+
+
+int TraceInstrJumpList::compareItems ( Item item1, Item item2 )
+{
+ TraceInstrJump* ij1 = (TraceInstrJump*) item1;
+ TraceInstrJump* ij2 = (TraceInstrJump*) item2;
+
+ Addr addr1Low = ij1->instrFrom()->addr();
+ Addr addr2Low = ij2->instrFrom()->addr();
+ Addr addr1High = ij1->instrTo()->addr();
+ Addr addr2High = ij2->instrTo()->addr();
+ Addr t;
+
+ if (addr1Low > addr1High) {
+ t = addr1Low;
+ addr1Low = addr1High;
+ addr1High = t;
+ }
+
+ if (addr2Low > addr2High) {
+ t = addr2Low;
+ addr2Low = addr2High;
+ addr2High = t;
+ }
+
+ if (_sortLow) {
+ // we sort according to smallest instruction address
+ if (addr1Low != addr2Low) return (addr1Low > addr2Low) ? 1:-1;
+ // jump ends come before jump starts
+ if (addr1Low == ij1->instrTo()->addr()) return -1;
+ if (addr2Low == ij2->instrTo()->addr()) return 1;
+ return (addr1High > addr2High) ? 1:-1;
+ }
+
+ // we sort according to highest instruction address
+ if (addr1High != addr2High) return (addr1High > addr2High) ? 1:-1;
+ // jump ends come before jump starts
+ if (addr1High == ij1->instrTo()->addr()) return -1;
+ if (addr2High == ij2->instrTo()->addr()) return 1;
+ return (addr1Low > addr2Low) ? 1:-1;
+}
+
+
+//---------------------------------------------------
+// TraceLineJump
+
+TraceLineJump::TraceLineJump(TraceLine* lineFrom, TraceLine* lineTo,
+ bool isCondJump)
+{
+ // we are the owner of TracePartLineJump's generated in our factory
+ _deps.setAutoDelete(true);
+
+ _lineFrom = lineFrom;
+ _lineTo = lineTo;
+ _isCondJump = isCondJump;
+}
+
+TraceLineJump::~TraceLineJump()
+{}
+
+
+TracePartLineJump* TraceLineJump::partLineJump(TracePart* part)
+{
+ TracePartLineJump* item = (TracePartLineJump*) findDepFromPart(part);
+ if (!item) {
+ item = new TracePartLineJump(this);
+ item->setPosition(part);
+ addDep(item);
+ }
+ return item;
+}
+
+
+QString TraceLineJump::name() const
+{
+ return QString("jump at %1 to %2")
+ .arg(_lineFrom->prettyName())
+ .arg(_lineTo->prettyName());
+}
+
+
+//---------------------------------------------------
+// TraceLineJumpList
+
+
+int TraceLineJumpList::compareItems ( Item item1, Item item2 )
+{
+ TraceLineJump* lj1 = (TraceLineJump*) item1;
+ TraceLineJump* lj2 = (TraceLineJump*) item2;
+
+ uint line1Low = lj1->lineFrom()->lineno();
+ uint line2Low = lj2->lineFrom()->lineno();
+ uint line1High = lj1->lineTo()->lineno();
+ uint line2High = lj2->lineTo()->lineno();
+ uint t;
+
+ if (line1Low > line1High) {
+ t = line1Low; line1Low = line1High; line1High = t;
+ }
+ if (line2Low > line2High) {
+ t = line2Low; line2Low = line2High; line2High = t;
+ }
+
+ if (_sortLow) {
+ // we sort according to smallest line number
+ if (line1Low != line2Low) return line1Low - line2Low;
+ // jump ends come before jump starts
+ if (line1Low == lj1->lineTo()->lineno()) return -1;
+ if (line2Low == lj2->lineTo()->lineno()) return 1;
+ return line1High - line2High;
+ }
+
+ // we sort according to highest line number
+ if (line1High != line2High) return line1High - line2High;
+ // jump ends come before jump starts
+ if (line1High == lj1->lineTo()->lineno()) return -1;
+ if (line2High == lj2->lineTo()->lineno()) return 1;
+ return line1Low - line2Low;
+}
+
+
+//---------------------------------------------------
+// TraceInstrCall
+
+TraceInstrCall::TraceInstrCall(TraceCall* call, TraceInstr* instr)
+{
+ // we are the owner of TracePartInstrCall's generated in our factory
+ _deps.setAutoDelete(true);
+
+ _call = call;
+ _instr = instr;
+}
+
+TraceInstrCall::~TraceInstrCall()
+{}
+
+
+TracePartInstrCall* TraceInstrCall::partInstrCall(TracePart* part,
+ TracePartCall*)
+{
+ TracePartInstrCall* item = (TracePartInstrCall*) findDepFromPart(part);
+ if (!item) {
+ item = new TracePartInstrCall(this);
+ item->setPosition(part);
+ addDep(item);
+ // instruction calls are not registered in function calls
+ // as together with line calls calls are duplicated
+ //partCall->addDep(item);
+ }
+ return item;
+}
+
+
+QString TraceInstrCall::name() const
+{
+ return QString("%1 at %2").arg(_call->name()).arg(_instr->name());
+}
+
+
+//---------------------------------------------------
+// TraceLineCall
+
+TraceLineCall::TraceLineCall(TraceCall* call, TraceLine* line)
+{
+ // we are the owner of TracePartLineCall's generated in our factory
+ _deps.setAutoDelete(true);
+
+ _call = call;
+ _line = line;
+}
+
+TraceLineCall::~TraceLineCall()
+{}
+
+
+TracePartLineCall* TraceLineCall::partLineCall(TracePart* part,
+ TracePartCall* partCall)
+{
+ TracePartLineCall* item = (TracePartLineCall*) findDepFromPart(part);
+ if (!item) {
+ item = new TracePartLineCall(this);
+ item->setPosition(part);
+ addDep(item);
+ partCall->addDep(item);
+ }
+ return item;
+}
+
+
+QString TraceLineCall::name() const
+{
+ return QString("%1 at %2").arg(_call->name()).arg(_line->name());
+}
+
+
+//---------------------------------------------------
+// TraceCall
+
+TraceCall::TraceCall(TraceFunction* caller, TraceFunction* called)
+{
+ // we are the owner of all items generated in our factory
+ _deps.setAutoDelete(true);
+ _lineCalls.setAutoDelete(true);
+
+ _caller = caller;
+ _called = called;
+}
+
+
+TraceCall::~TraceCall()
+{}
+
+TracePartCall* TraceCall::partCall(TracePart* part,
+ TracePartFunction* partCaller,
+ TracePartFunction* partCalling)
+{
+ TracePartCall* item = (TracePartCall*) findDepFromPart(part);
+ if (!item) {
+ item = new TracePartCall(this);
+ item->setPosition(part);
+ addDep(item);
+ partCaller->addPartCalling(item);
+ partCalling->addPartCaller(item);
+ }
+ return item;
+}
+
+TraceInstrCall* TraceCall::instrCall(TraceInstr* i)
+{
+ TraceInstrCall* icall;
+ for (icall=_instrCalls.first();icall;icall=_instrCalls.next())
+ if (icall->instr() == i)
+ break;
+
+ if (!icall) {
+ icall = new TraceInstrCall(this, i);
+
+ _instrCalls.append(icall);
+ invalidate();
+
+#if TRACE_DEBUG
+ qDebug("Created %s [TraceCall::instrCall]", icall->fullName().ascii());
+#endif
+ i->addInstrCall(icall);
+ }
+ return icall;
+}
+
+
+TraceLineCall* TraceCall::lineCall(TraceLine* l)
+{
+ TraceLineCall* lcall;
+ for (lcall=_lineCalls.first();lcall;lcall=_lineCalls.next())
+ if (lcall->line() == l)
+ break;
+
+ if (!lcall) {
+ lcall = new TraceLineCall(this, l);
+
+ _lineCalls.append(lcall);
+ invalidate();
+
+#if TRACE_DEBUG
+ qDebug("Created %s [TraceCall::lineCall]", lcall->fullName().ascii());
+#endif
+ l->addLineCall(lcall);
+ }
+ return lcall;
+}
+
+
+void TraceCall::invalidateDynamicCost()
+{
+ TraceLineCall* lc;
+ for (lc=_lineCalls.first();lc;lc=_lineCalls.next())
+ lc->invalidate();
+
+ TraceInstrCall* ic;
+ for (ic=_instrCalls.first();ic;ic=_instrCalls.next())
+ ic->invalidate();
+
+ invalidate();
+}
+
+
+QString TraceCall::name() const
+{
+ return QString("%1 => %2")
+ .arg(_caller->name())
+ .arg(_called->name());
+}
+
+int TraceCall::inCycle()
+{
+ if (!_caller || !_called) return 0;
+ if (!_caller->cycle()) return 0;
+ if (_caller == _caller->cycle()) return 0;
+ if (_caller->cycle() != _called->cycle()) return 0;
+
+ return _caller->cycle()->cycleNo();
+}
+
+void TraceCall::update()
+{
+ if (!_dirty) return;
+
+ // special handling for cycles
+ if (_caller && _caller->cycle() && _caller==_caller->cycle()) {
+
+ // we have no part calls: use inclusive cost of called function
+ clear();
+ if (_called)
+ addCost(_called->inclusive());
+ _dirty = false;
+ return;
+ }
+
+ TraceCallListCost::update();
+}
+
+TraceFunction* TraceCall::caller(bool /*skipCycle*/) const
+{
+ return _caller;
+}
+
+TraceFunction* TraceCall::called(bool skipCycle) const
+{
+ if (!skipCycle && _called) {
+ // if this is a call to a cycle member from outside of the cycle,
+ // fake it to be a call to the whole cycle
+ if (_called->cycle() && _caller &&
+ (_caller->cycle() != _called->cycle()))
+ return _called->cycle();
+ }
+
+ return _called;
+}
+
+QString TraceCall::callerName(bool skipCycle) const
+{
+ if (!_caller) return i18n("(no caller)");
+
+ if (!skipCycle) {
+ // if this call goes into a cycle, add the entry function
+ TraceFunctionCycle* c = _called->cycle();
+ if (c && _caller && (_caller->cycle() != c)) {
+ QString via = _called->prettyName();
+ return i18n("%1 via %2").arg(_caller->prettyName()).arg(via);
+ }
+ }
+
+ return _caller->prettyName();
+}
+
+QString TraceCall::calledName(bool skipCycle) const
+{
+ if (!_called) return i18n("(no callee)");
+
+ if (!skipCycle) {
+ // if this call goes into a cycle, add the entry function
+ TraceFunctionCycle* c = _called->cycle();
+ if (c && _caller && (_caller->cycle() != c)) {
+ // HACK to get rid of cycle postfix...
+ _called->setCycle(0);
+ QString via = _called->prettyName();
+ _called->setCycle(c);
+ return i18n("%1 via %2").arg(c->name()).arg(via);
+ }
+ }
+ return _called->prettyName();
+}
+
+
+//---------------------------------------------------
+// TraceInstr
+
+TraceInstr::TraceInstr()
+{
+ // we are the owner of TracePartInstr's generated in our factory
+ _deps.setAutoDelete(true);
+ _instrJumps.setAutoDelete(true);
+
+ _addr = 0;
+ _line = 0;
+ _function = 0;
+}
+
+TraceInstr::~TraceInstr()
+{}
+
+bool TraceInstr::hasCost(TraceCostType* ct)
+{
+ bool res = subCost(ct) > 0;
+ if (!res) {
+ TraceInstrCall* ic;
+ for(ic=_instrCalls.first();ic;ic=_instrCalls.next())
+ if (ic->subCost(ct) > 0) break;
+ res = (ic != 0);
+ if (!res) {
+ TraceInstrJump* ij;
+ for(ij=_instrJumps.first();ij;ij=_instrJumps.next())
+ if (ij->executedCount() > 0) break;
+ res = (ij != 0);
+ }
+ }
+
+ return res;
+}
+
+TracePartInstr* TraceInstr::partInstr(TracePart* part,
+ TracePartFunction* partFunction)
+{
+ TracePartInstr* item = (TracePartInstr*) findDepFromPart(part);
+ if (!item) {
+ item = new TracePartInstr(this);
+ item->setPosition(part);
+ addDep(item);
+ //part->addDep(item);
+ partFunction->addPartInstr(item);
+ }
+ return item;
+}
+
+TraceInstrJump* TraceInstr::instrJump(TraceInstr* to, bool isJmpCond)
+{
+ TraceInstrJump* jump;
+ for (jump=_instrJumps.first();jump;jump=_instrJumps.next())
+ if (jump->instrTo() == to)
+ break;
+
+ if (!jump) {
+ jump = new TraceInstrJump(this, to, isJmpCond);
+
+ _instrJumps.append(jump);
+ }
+ return jump;
+}
+
+
+
+void TraceInstr::addInstrCall(TraceInstrCall* instrCall)
+{
+#if TRACE_ASSERTIONS
+ if (_instrCalls.findRef(instrCall)>=0) return;
+
+ if (instrCall->instr() != this) {
+ qDebug("Can't add instruction call to another instruction!");
+ return;
+ }
+#endif
+
+ _instrCalls.append(instrCall);
+ invalidate();
+
+#if TRACE_DEBUG
+ qDebug("%s added\n %s (now %d)",
+ fullName().ascii(),
+ instrCall->fullName().ascii(), _instrCalls.count());
+#endif
+}
+
+
+QString TraceInstr::name() const
+{
+ return QString("0x%1").arg(_addr.toString());
+}
+
+QString TraceInstr::prettyName() const
+{
+ return QString("0x%1").arg(_addr.toString());
+}
+
+
+//---------------------------------------------------
+// TraceLine
+
+TraceLine::TraceLine()
+{
+ // we are the owner of TracePartLine's generated in our factory
+ _deps.setAutoDelete(true);
+ _lineJumps.setAutoDelete(true);
+
+ _lineno = 0;
+ _sourceFile = 0;
+}
+
+TraceLine::~TraceLine()
+{}
+
+bool TraceLine::hasCost(TraceCostType* ct)
+{
+ bool res = subCost(ct) > 0;
+ if (!res) {
+ TraceLineCall* lc;
+ for(lc=_lineCalls.first();lc;lc=_lineCalls.next())
+ if (lc->subCost(ct) > 0) break;
+ res = (lc != 0);
+ if (!res) {
+ TraceLineJump* lj;
+ for(lj=_lineJumps.first();lj;lj=_lineJumps.next())
+ if (lj->executedCount() > 0) break;
+ res = (lj != 0);
+ }
+ }
+
+ return res;
+}
+
+TracePartLine* TraceLine::partLine(TracePart* part,
+ TracePartFunction* partFunction)
+{
+ TracePartLine* item = (TracePartLine*) findDepFromPart(part);
+ if (!item) {
+ item = new TracePartLine(this);
+ item->setPosition(part);
+ addDep(item);
+#if !USE_FIXCOST
+ part->addDep(item);
+#endif
+ partFunction->addPartLine(item);
+ }
+ return item;
+}
+
+TraceLineJump* TraceLine::lineJump(TraceLine* to, bool isJmpCond)
+{
+ TraceLineJump* jump;
+ for (jump=_lineJumps.first();jump;jump=_lineJumps.next())
+ if (jump->lineTo() == to)
+ break;
+
+ if (!jump) {
+ jump = new TraceLineJump(this, to, isJmpCond);
+
+ _lineJumps.append(jump);
+ }
+ return jump;
+}
+
+
+void TraceLine::addLineCall(TraceLineCall* lineCall)
+{
+#if TRACE_ASSERTIONS
+ if (_lineCalls.findRef(lineCall)>=0) return;
+
+ if (lineCall->line() != this) {
+ qDebug("Can't add line call to another line!");
+ return;
+ }
+#endif
+
+ TraceFunction* caller = lineCall->call()->caller();
+ TraceFunction* function = _sourceFile->function();
+ if (caller != function) {
+ // We regard 2 functions as the same if they have
+ // same class, name, object
+ if ((caller->cls() != function->cls()) ||
+ (caller->name() != function->name()) ||
+ (caller->object() != function->object())) {
+
+ qDebug("ERROR: Adding line call, line %d\n of %s to\n %s ?!",
+ lineCall->line()->lineno(),
+ caller->info().ascii(), function->info().ascii());
+ }
+ }
+
+ _lineCalls.append(lineCall);
+ invalidate();
+
+#if TRACE_DEBUG
+ qDebug("%s added\n %s (now %d)",
+ fullName().ascii(),
+ lineCall->fullName().ascii(), _lineCalls.count());
+#endif
+}
+
+
+QString TraceLine::name() const
+{
+ QString fileShortName = _sourceFile->file()->shortName();
+ if (fileShortName.isEmpty())
+ return i18n("(unknown)");
+
+ return QString("%1:%2")
+ .arg(fileShortName).arg(_lineno);
+}
+
+QString TraceLine::prettyName() const
+{
+ return QString("%1 [%2]")
+ .arg(name()).arg(_sourceFile->function()->prettyName());
+}
+
+//---------------------------------------------------
+// TraceCostItem
+
+TraceCostItem::TraceCostItem()
+{
+}
+
+TraceCostItem::~TraceCostItem()
+{}
+
+
+//---------------------------------------------------
+// TraceFunctionSource
+
+TraceFunctionSource::TraceFunctionSource(TraceFunction* function,
+ TraceFile* file)
+{
+ _file = file;
+ _function = function;
+
+ // the function is dependent from our cost sum
+ _dep = _function;
+
+ _lineMap = 0;
+ _lineMapFilled = false;
+ _line0 = 0;
+}
+
+TraceFunctionSource::~TraceFunctionSource()
+{
+ if (_lineMap) delete _lineMap;
+ if (_line0) delete _line0;
+}
+
+QString TraceFunctionSource::name() const
+{
+ return QString("%1 for %2").arg(_file->name()).arg(_function->name());
+}
+
+uint TraceFunctionSource::firstLineno()
+{
+ // lazy generate the map if not done up to now
+ TraceLineMap* map = lineMap();
+ // ignore line 0 here
+ if (!map || map->count() == 0) return 0;
+ TraceLineMap::Iterator it = map->begin();
+ return (*it).lineno();
+}
+
+uint TraceFunctionSource::lastLineno()
+{
+ // lazy generate the map if not done up to now
+ TraceLineMap* map = lineMap();
+ // ignore line 0 here
+ if (!map || map->count() == 0) return 0;
+ TraceLineMap::Iterator it = map->end();
+ --it;
+ return (*it).lineno();
+}
+
+/* factory */
+TraceLine* TraceFunctionSource::line(uint lineno, bool createNew)
+{
+ if (lineno == 0) {
+ if (!_line0) {
+ if (!createNew) return 0;
+ _line0 = new TraceLine;
+ _line0->setSourceFile(this);
+ _line0->setLineno(0);
+ }
+ return _line0;
+ }
+
+ if (!createNew) {
+ if (!_lineMap) return 0;
+ TraceLineMap::Iterator it = _lineMap->find(lineno);
+ if (it == _lineMap->end()) return 0;
+ return &(it.data());
+ }
+
+ if (!_lineMap) _lineMap = new TraceLineMap;
+
+ TraceLine& l = (*_lineMap)[lineno];
+ if (!l.isValid()) {
+ l.setSourceFile(this);
+ l.setLineno(lineno);
+
+#if TRACE_DEBUG
+ qDebug("Created %s [TraceFunctionSource::line]",
+ l.fullName().ascii());
+#endif
+ }
+ return &l;
+}
+
+void TraceFunctionSource::update()
+{
+ if (!_dirty) return;
+
+ clear();
+
+ // no need to create lineMap if not already created
+ if (_lineMap) {
+ TraceLineMap::Iterator lit;
+ for ( lit = _lineMap->begin();
+ lit != _lineMap->end(); ++lit )
+ addCost( &(*lit) );
+ }
+
+ _dirty = false;
+}
+
+void TraceFunctionSource::invalidateDynamicCost()
+{
+ // no need to create lineMap if not already created
+ if (_lineMap) {
+ TraceLineMap::Iterator lit;
+ for ( lit = _lineMap->begin();
+ lit != _lineMap->end(); ++lit )
+ (*lit).invalidate();
+ }
+
+ invalidate();
+}
+
+TraceLineMap* TraceFunctionSource::lineMap()
+{
+#if USE_FIXCOST
+
+ if (_lineMapFilled) return _lineMap;
+ _lineMapFilled = true;
+ if (!_lineMap)
+ _lineMap = new TraceLineMap;
+
+ TraceLine* l = 0;
+ TracePartLine* pl = 0;
+ TraceLineCall* lc = 0;
+ TracePartLineCall* plc = 0;
+
+ /* go over all part objects for this function, and
+ * - build TraceLines (the line map) using FixCost objects
+ * - build TraceJumpLines using FixJump objects
+ */
+ TraceInclusiveCostList pfList = _function->deps();
+ TracePartFunction* pf = (TracePartFunction*) pfList.first();
+ for(; pf; pf = (TracePartFunction*) pfList.next()) {
+
+ if (0) qDebug("PartFunction %s:%d",
+ pf->function()->name().ascii(), pf->part()->partNumber());
+
+ FixCost* fc = pf->firstFixCost();
+ for(; fc; fc = fc->nextCostOfPartFunction()) {
+ if (fc->line() == 0) continue;
+ if (fc->functionSource() != this) continue;
+
+ if (!l || l->lineno() != fc->line()) {
+ l = &(*_lineMap)[fc->line()];
+ if (!l->isValid()) {
+ l->setSourceFile(this);
+ l->setLineno(fc->line());
+ }
+ pl = 0;
+ }
+ if (!pl || pl->part() != fc->part())
+ pl = l->partLine(fc->part(), pf);
+ fc->addTo(pl);
+ }
+
+ TraceLine* to = 0;
+ TraceLineJump* lj;
+ TracePartLineJump* plj;
+ FixJump* fj = pf->firstFixJump();
+ for(; fj; fj = fj->nextJumpOfPartFunction()) {
+ if (fj->line() == 0) continue;
+ if (fj->source() != this) continue;
+ if (!fj->targetSource()) {
+ // be robust against buggy loaders
+ continue;
+ }
+
+ // don't display jumps to same or following line
+ if ((fj->line() == fj->targetLine()) ||
+ (fj->line()+1 == fj->targetLine())) continue;
+
+ if (!l || l->lineno() != fj->line()) {
+ l = &(*_lineMap)[fj->line()];
+ if (!l->isValid()) {
+ l->setSourceFile(this);
+ l->setLineno(fj->line());
+ }
+ }
+
+ to = fj->targetSource()->line(fj->targetLine(), true);
+
+ lj = l->lineJump(to, fj->isCondJump());
+ plj = lj->partLineJump(fj->part());
+
+ fj->addTo(plj);
+ }
+
+
+ TracePartCallList pcList = pf->partCallings();
+ TracePartCall* pc = pcList.first();
+ for(; pc; pc = pcList.next()) {
+
+ if (0) qDebug("PartCall %s:%d",
+ pc->call()->name().ascii(),
+ pf->part()->partNumber());
+
+ FixCallCost* fcc = pc->firstFixCallCost();
+ for(; fcc; fcc = fcc->nextCostOfPartCall()) {
+ if (fcc->line() == 0) continue;
+ if (fcc->functionSource() != this) continue;
+
+ if (!l || l->lineno() != fcc->line()) {
+ l = &(*_lineMap)[fcc->line()];
+ if (!l->isValid()) {
+ l->setSourceFile(this);
+ l->setLineno(fcc->line());
+ }
+ }
+ if (!lc || lc->call() != pc->call() || lc->line() != l) {
+ lc = pc->call()->lineCall(l);
+ plc = 0;
+ }
+ if (!plc || plc->part() != fcc->part())
+ plc = lc->partLineCall(fcc->part(), pc);
+
+ fcc->addTo(plc);
+ if (0) qDebug("Add FixCallCost %s:%d/0x%s, CallCount %s",
+ fcc->functionSource()->file()->shortName().ascii(),
+ fcc->line(), fcc->addr().toString().ascii(),
+ fcc->callCount().pretty().ascii());
+ }
+ }
+ }
+
+#endif
+
+ return _lineMap;
+}
+
+
+
+//---------------------------------------------------
+// TraceAssoziation
+
+TraceAssoziation::TraceAssoziation()
+{
+ _function = 0;
+ _valid = false;
+}
+
+TraceAssoziation::~TraceAssoziation()
+{
+ // don't delete from TraceFunction
+ if (_function) _function->removeAssoziation(this);
+}
+
+bool TraceAssoziation::isAssoziated()
+{
+ if (!_function) return false;
+
+ return _function->assoziation(rtti())==this;
+}
+
+bool TraceAssoziation::setFunction(TraceFunction* f)
+{
+ if (_function == f)
+ return isAssoziated();
+
+ if (_function) {
+ // don't delete ourself
+ _function->removeAssoziation(this);
+ }
+
+ _function = f;
+ if (f && f->assoziation(rtti()) == 0) {
+ f->addAssoziation(this);
+ return true;
+ }
+ return false;
+}
+
+void TraceAssoziation::clear(TraceData* d, int rtti)
+{
+ TraceFunctionMap::Iterator it;
+ for ( it = d->functionMap().begin();
+ it != d->functionMap().end(); ++it )
+ (*it).removeAssoziation(rtti);
+}
+
+void TraceAssoziation::invalidate(TraceData* d, int rtti)
+{
+ TraceFunctionMap::Iterator it;
+ for ( it = d->functionMap().begin();
+ it != d->functionMap().end(); ++it )
+ (*it).invalidateAssoziation(rtti);
+}
+
+
+//---------------------------------------------------
+// TraceFunction
+
+TraceFunction::TraceFunction()
+{
+ _object = 0;
+ _file = 0;
+ _cls = 0;
+ _cycle = 0;
+
+ // we are the owner of items generated in our factory
+ _deps.setAutoDelete(true);
+ _callings.setAutoDelete(true);
+ _sourceFiles.setAutoDelete(true);
+
+ _calledCount = 0;
+ _callingCount = 0;
+ _calledContexts = 0;
+ _callingContexts = 0;
+
+ _instrMap = 0;
+ _instrMapFilled = false;
+}
+
+
+TraceFunction::~TraceFunction()
+{
+ _assoziations.setAutoDelete(true);
+ _assoziations.clear();
+
+ if (_instrMap) delete _instrMap;
+}
+
+// no unique check is done!
+void TraceFunction::addAssoziation(TraceAssoziation* a)
+{
+ if (!a) return;
+ _assoziations.append(a);
+}
+
+void TraceFunction::removeAssoziation(TraceAssoziation* a)
+{
+ _assoziations.removeRef(a);
+}
+
+void TraceFunction::removeAssoziation(int rtti, bool reallyDelete)
+{
+ if (rtti==0) {
+ if (reallyDelete)
+ _assoziations.setAutoDelete(true);
+ _assoziations.clear();
+ _assoziations.setAutoDelete(false);
+ return;
+ }
+
+ TraceAssoziation* a;
+ for (a=_assoziations.first();a;a=_assoziations.next())
+ if (a->rtti() == rtti) {
+ if (reallyDelete) delete a;
+ _assoziations.remove();
+ return;
+ }
+}
+
+void TraceFunction::invalidateAssoziation(int rtti)
+{
+ TraceAssoziation* a;
+ for (a=_assoziations.first();a;a=_assoziations.next())
+ if ((rtti==0) || (a->rtti() == rtti))
+ a->invalidate();
+}
+
+TraceAssoziation* TraceFunction::assoziation(int rtti)
+{
+ TraceAssoziation* a;
+ for (a=_assoziations.first();a;a=_assoziations.next())
+ if (a->rtti() == rtti)
+ return a;
+ return 0;
+}
+
+
+// helper for prettyName
+bool TraceFunction::isUniquePrefix(QString prefix) const
+{
+ TraceFunctionMap::ConstIterator it, it2;
+ it = it2 = _myMapIterator;
+ if (it != data()->functionBeginIterator()) {
+ it2--;
+ if ((*it2).name().startsWith(prefix)) return false;
+ }
+ if (it != data()->functionEndIterator()) {
+ it++;
+ if ((*it).name().startsWith(prefix)) return false;
+ }
+ return true;
+}
+
+
+QString TraceFunction::prettyName() const
+{
+ QString res = _name;
+
+ if (_name.isEmpty())
+ return i18n("(unknown)");
+
+ int p = _name.find('(');
+ if (p>0) {
+ // handle C++ "operator()" correct
+ if ((_name[p+1] == ')') && (_name[p+2] == '(')) p+=2;
+
+ // we have a C++ symbol with argument types:
+ // check for unique function name (inclusive '(' !)
+ if (isUniquePrefix(_name.left(p+1)))
+ res = _name.left(p);
+ }
+
+ // cycle members
+ if (_cycle) {
+ if (_cycle != this)
+ res = QString("%1 <cycle %2>").arg(res).arg(_cycle->cycleNo());
+ else
+ res = QString("<cycle %2>").arg(_cycle->cycleNo());
+ }
+
+
+ return res;
+}
+
+/*
+ * Returns location string: ELF object and source file(s).
+ */
+QString TraceFunction::location(int maxFiles) const
+{
+ QString loc;
+
+ // add object file with address range
+ if (_object) {
+ loc = _object->shortName();
+
+#if 0
+ uint from = firstAddress();
+ uint to = lastAddress();
+ if (from != 0 && to != 0) {
+ if (from == to)
+ loc += QString(" (0x%1)").arg(to, 0, 16);
+ else
+ loc += QString(" (0x%1-0x%2)").arg(from, 0, 16).arg(to, 0, 16);
+ }
+#endif
+ }
+
+ // add all source files
+ int filesAdded = 0;
+ TraceFunctionSourceList list = _sourceFiles;
+ TraceFunctionSource* sourceFile = list.first();
+ for (;sourceFile;sourceFile=list.next()) {
+ if (!sourceFile->file() ||
+ (sourceFile->file()->name().isEmpty()) )
+ continue;
+
+ if (!loc.isEmpty())
+ loc += (filesAdded>0) ? ", " : ": ";
+ filesAdded++;
+
+ if ((maxFiles>0) && (filesAdded>maxFiles)) {
+ loc += "...";
+ break;
+ }
+ loc += sourceFile->file()->shortName();
+
+#if 0
+ from = sourceFile->firstLineno();
+ to = sourceFile->lastLineno();
+ if (from != 0 && to != 0) {
+ if (from == to)
+ loc += QString(" (%1)").arg(to);
+ else
+ loc += QString(" (%1-%2)").arg(from).arg(to);
+ }
+#endif
+ }
+
+ return loc;
+}
+
+// pretty version is allowed to mangle the string...
+QString TraceFunction::prettyLocation(int maxFiles) const
+{
+ QString l = location(maxFiles);
+ if (l.isEmpty()) return i18n("(unknown)");
+
+ return l;
+}
+
+void TraceFunction::addPrettyLocation(QString& s, int maxFiles) const
+{
+ QString l = location(maxFiles);
+ if (l.isEmpty()) return;
+
+ s += QString(" (%1)").arg(l);
+}
+
+QString TraceFunction::prettyNameWithLocation(int maxFiles) const
+{
+ QString l = location(maxFiles);
+ if (l.isEmpty()) return prettyName();
+
+ return QString("%1 (%2)").arg(prettyName()).arg(l);
+}
+
+QString TraceFunction::info() const
+{
+ QString l = location();
+ if (l.isEmpty())
+ return QString("Function %1").arg(name());
+
+ return QString("Function %1 (location %2)")
+ .arg(name()).arg(l);
+}
+
+
+Addr TraceFunction::firstAddress() const
+{
+ // ignore address 0 here
+ if (!_instrMap || _instrMap->count() == 0) return 0;
+ TraceInstrMap::ConstIterator it = _instrMap->begin();
+ return (*it).addr();
+}
+
+Addr TraceFunction::lastAddress() const
+{
+ // ignore address 0 here
+ if (!_instrMap || _instrMap->count() == 0) return 0;
+ TraceInstrMap::ConstIterator it = _instrMap->end();
+ --it;
+ return (*it).addr();
+}
+
+/* factory */
+TraceInstr* TraceFunction::instr(Addr addr, bool createNew)
+{
+ // address 0 not allowed
+ if (addr == Addr(0)) return 0;
+
+ if (!createNew) {
+ if (!_instrMap) return 0;
+ TraceInstrMap::Iterator it = _instrMap->find(addr);
+ if (it == _instrMap->end())
+ return 0;
+ return &(it.data());
+ }
+
+ if (!_instrMap) _instrMap = new TraceInstrMap;
+
+ TraceInstr& i = (*_instrMap)[addr];
+ if (!i.isValid()) {
+ i.setAddr(addr);
+ i.setFunction(this);
+
+#if TRACE_DEBUG
+ qDebug("Created %s [TraceFunction::instr]",
+ i.fullName().ascii());
+#endif
+ }
+ return &i;
+}
+
+void TraceFunction::addCaller(TraceCall* caller)
+{
+#if TRACE_ASSERTIONS
+ if (caller->called() != this) {
+ qDebug("Can't add call to another line!\n");
+ return;
+ }
+
+ if (_callers.findRef(caller)>=0) return;
+#endif
+
+ _callers.append(caller);
+ invalidate();
+
+#if TRACE_DEBUG
+ qDebug("%s added Caller\n %s (now %d)",
+ fullName().ascii(), caller->fullName().ascii(), _callers.count());
+#endif
+}
+
+
+
+TraceCall* TraceFunction::calling(TraceFunction* called)
+{
+ TraceCallMap::Iterator it = _callingMap.find(called);
+ TraceCall* calling = (it == _callingMap.end()) ? 0 : it.data();
+
+ if (!calling) {
+ calling = new TraceCall(this, called);
+
+ _callingMap.insert(called, calling);
+ _callings.append(calling);
+
+ // we have to invalidate ourself so invalidations from item propagate up
+ invalidate();
+
+#if TRACE_DEBUG
+ qDebug("Created %s [TraceFunction::calling]", calling->fullName().ascii());
+#endif
+ called->addCaller(calling);
+ }
+ return calling;
+}
+
+TraceFunctionSource* TraceFunction::sourceFile(TraceFile* file,
+ bool createNew)
+{
+ if (!file) file = _file;
+
+ TraceFunctionSource* sourceFile = _sourceFiles.first();
+ for (;sourceFile;sourceFile=_sourceFiles.next())
+ if (sourceFile->file() == file) break;
+
+ if (!sourceFile && createNew) {
+ sourceFile = new TraceFunctionSource(this, file);
+
+ _sourceFiles.append(sourceFile);
+
+ // we have to invalidate ourself so invalidations from item propagate up
+ invalidate();
+
+#if TRACE_DEBUG
+ qDebug("Created SourceFile %s [TraceFunction::line]",
+ file->name().ascii());
+#endif
+ file->addSourceFile(sourceFile);
+ }
+ return sourceFile;
+}
+
+TraceLine* TraceFunction::line(TraceFile* file, uint lineno,
+ bool createNew)
+{
+ Q_ASSERT(file!=0);
+
+ TraceFunctionSource* sf = sourceFile(file, createNew);
+ if (!sf)
+ return 0;
+ else
+ return sf->line(lineno, createNew);
+}
+
+
+TracePartFunction* TraceFunction::partFunction(TracePart* part,
+ TracePartFile* partFile,
+ TracePartObject* partObject)
+{
+ TracePartFunction* item = (TracePartFunction*) findDepFromPart(part);
+ if (!item) {
+ item = new TracePartFunction(this, partObject, partFile);
+ item->setPosition(part);
+ addDep(item);
+#if USE_FIXCOST
+ part->addDep(item);
+#endif
+
+ if (_cls) {
+ TracePartClass* partClass = _cls->partClass(part);
+ partClass->addPartFunction(item);
+ item->setPartClass(partClass);
+ }
+
+ partFile->addPartFunction(item);
+ if (partObject)
+ partObject->addPartFunction(item);
+ }
+ else if (item->partObject()==0 && partObject) {
+ item->setPartObject(partObject);
+ partObject->addPartFunction(item);
+ }
+
+ return item;
+}
+
+
+SubCost TraceFunction::calledCount()
+{
+ if (_dirty) update();
+
+ return _calledCount;
+}
+
+int TraceFunction::calledContexts()
+{
+ if (_dirty) update();
+
+ return _calledContexts;
+}
+
+SubCost TraceFunction::callingCount()
+{
+ if (_dirty) update();
+
+ return _callingCount;
+}
+
+int TraceFunction::callingContexts()
+{
+ if (_dirty) update();
+
+ return _callingContexts;
+}
+
+QString TraceFunction::prettyCalledCount()
+{
+ return _calledCount.pretty();
+}
+
+QString TraceFunction::prettyCallingCount()
+{
+ return _callingCount.pretty();
+}
+
+
+TraceCallList TraceFunction::callers(bool skipCycle) const
+{
+ if (skipCycle) return _callers;
+
+ // fake the callers for cycle members
+ if (_cycle && (_cycle != this)) {
+ TraceCallList l;
+ TraceCall* c;
+
+ // inner-cycle-callers
+ TraceCallList list=_callers;
+ for (c=list.first();c;c=list.next())
+ if (c->caller()->cycle() == _cycle)
+ l.append(c);
+
+ // call from cycle itself
+ for (c=_cycle->_callings.first();c;c=_cycle->_callings.next())
+ if (c->called() == this) {
+ l.append(c);
+ return l;
+ }
+ }
+
+ return _callers;
+}
+
+const TraceCallList& TraceFunction::callings(bool /* skipCycle */) const
+{
+ return _callings;
+}
+
+void TraceFunction::invalidateDynamicCost()
+{
+ TraceCall* c;
+ for (c=_callings.first();c;c=_callings.next())
+ c->invalidateDynamicCost();
+
+ TraceFunctionSource* sf;
+ for (sf=_sourceFiles.first();sf;sf=_sourceFiles.next())
+ sf->invalidateDynamicCost();
+
+ if (_instrMap) {
+ TraceInstrMap::Iterator iit;
+ for ( iit = _instrMap->begin();
+ iit != _instrMap->end(); ++iit )
+ (*iit).invalidate();
+ }
+
+ invalidate();
+}
+
+void TraceFunction::update()
+{
+ if (!_dirty) return;
+
+#if TRACE_DEBUG
+ qDebug("Update %s (Callers %d, sourceFiles %d, instrs %d)",
+ _name.ascii(), _callers.count(),
+ _sourceFiles.count(), _instrMap ? _instrMap->count():0);
+#endif
+
+ _calledCount = 0;
+ _callingCount = 0;
+ _calledContexts = 0;
+ _callingContexts = 0;
+ clear();
+
+ // context count is NOT the sum of part contexts
+ TraceCall *caller, *calling;
+ for (caller=_callers.first();caller;caller=_callers.next()) {
+ // FIXME
+ if (caller->subCost(0)>0)
+ _calledContexts++;
+ _calledCount += caller->callCount();
+ }
+
+ for (calling=_callings.first();calling;calling=_callings.next()) {
+ // FIXME
+ if (calling->subCost(0)>0) _callingContexts++;
+ _callingCount += calling->callCount();
+ }
+
+ if (data()->inFunctionCycleUpdate() || !_cycle) {
+ // usual case (no cycle member)
+ TraceInclusiveCost* item;
+ for (item=_deps.first();item;item=_deps.next()) {
+ if (!item->part() || !item->part()->isActive()) continue;
+
+ addCost(item);
+ addInclusive(item->inclusive());
+ }
+ }
+ else {
+ // this is a cycle or cycle member
+ for (calling=_callings.first();calling;calling=_callings.next()) {
+
+ // ignore inner-cycle member calls for inclusive cost
+ if ((_cycle != this) &&
+ (calling->inCycle()>0)) continue;
+
+ addInclusive(calling);
+ }
+
+ // self cost
+ if (type() == FunctionCycle) {
+ // cycle: self cost is sum of cycle member self costs, but
+ // doesn't add to inclusive cost
+ TraceFunctionList mList = ((TraceFunctionCycle*)this)->members();
+ TraceFunction* m;
+ for (m=mList.first();m;m=mList.next())
+ addCost(m);
+ }
+ else {
+ // cycle member
+ TraceInclusiveCost* item;
+ for (item=_deps.first();item;item=_deps.next()) {
+ if (!item->part() || !item->part()->isActive()) continue;
+
+ addCost(item);
+ }
+ _dirty = false; // don't recurse
+ addInclusive(this);
+ }
+ }
+ _dirty = false;
+
+#if TRACE_DEBUG
+ qDebug("> %s", costString(0).ascii());
+#endif
+}
+
+bool TraceFunction::isCycle()
+{
+ return _cycle == this;
+}
+
+bool TraceFunction::isCycleMember()
+{
+ return _cycle && (_cycle != this);
+}
+
+void TraceFunction::cycleReset()
+{
+ _cycle = 0;
+ _cycleStackDown = 0;
+ _cycleLow = 0;
+}
+
+// this doesn't mark functions calling themself !
+void TraceFunction::cycleDFS(int d, int& pNo, TraceFunction** pTop)
+{
+ if (_cycleLow != 0) return;
+
+ if (0)
+ qDebug("%s D%02d > %s (%d)",
+ QString().fill(' ', d).ascii(), d, prettyName().ascii(), pNo+1);
+
+
+
+ // initialize with prefix order
+ pNo++;
+ int prefixNo = pNo;
+ _cycleLow = prefixNo;
+
+ // put myself on stack
+ _cycleStackDown = *pTop;
+ *pTop = this;
+
+ /* cycle cut heuristic:
+ * skip calls for cycle detection if they make less than _cycleCut
+ * percent of the cost of the function.
+ * FIXME: Which cost type to use for this heuristic ?!
+ */
+
+ SubCost base = 0;
+ if (_callers.count()>0) {
+ TraceCallList l = _callers;
+ TraceCall *caller;
+
+ for (caller=l.first();caller;caller=l.next())
+ if (caller->subCost(0) > base)
+ base = caller->subCost(0);
+ }
+ else base = inclusive()->subCost(0);
+
+ SubCost cutLimit = SubCost(base * Configuration::cycleCut());
+
+ if (0)
+ qDebug("%s Cum. %s, Max Caller %s, cut limit %s",
+ QString().fill(' ', d).ascii(),
+ inclusive()->subCost(0).pretty().ascii(),
+ base.pretty().ascii(),
+ cutLimit.pretty().ascii());
+
+ TraceCall *calling;
+ TraceCallList l = _callings;
+ for (calling=l.first();calling;calling=l.next()) {
+ TraceFunction* called = calling->called();
+
+ // cycle cut heuristic
+ if (calling->subCost(0) < cutLimit) {
+ if (0) qDebug("%s Cut call to %s (cum. %s)",
+ QString().fill(' ', d).ascii(),
+ called->prettyName().ascii(),
+ calling->subCost(0).pretty().ascii());
+
+ continue;
+ }
+
+ if (called->_cycleLow==0) {
+ // not visited yet
+ called->cycleDFS(d+1, pNo, pTop);
+ if (called->_cycleLow < _cycleLow)
+ _cycleLow = called->_cycleLow;
+ }
+ else if (called->_cycleStackDown) {
+ // backlink to same SCC (still in stack)
+ if (called->_cycleLow < _cycleLow)
+ _cycleLow = called->_cycleLow;
+
+ if (0)
+ qDebug("%s D%02d - %s (%d)",
+ QString().fill(' ', d+1).ascii(), d+1,
+ called->prettyName().ascii(), called->_cycleLow);
+ }
+ else {
+ if (0)
+ qDebug("%s D%02d - %s (%d) [Not on stack]",
+ QString().fill(' ', d+1).ascii(), d+1,
+ called->prettyName().ascii(), called->_cycleLow);
+ }
+ }
+
+ if (prefixNo == _cycleLow) {
+ // this is the base of a SCC.
+
+ if (*pTop == this) {
+ *pTop = _cycleStackDown;
+ _cycleStackDown = 0;
+ }
+ else {
+ // a SCC with >1 members
+
+ TraceFunctionCycle* cycle = data()->functionCycle(this);
+ if (0) qDebug("BASE CYC %d %s",
+ cycle->cycleNo(), prettyName().ascii());
+ while(*pTop) {
+ TraceFunction* top = *pTop;
+ cycle->add(top);
+
+ // remove from stack
+ *pTop = top->_cycleStackDown;
+ top->_cycleStackDown = 0;
+
+ if (0) qDebug("CYC %s", top->prettyName().ascii());
+ if (top == this) break;
+ }
+ }
+ }
+ if (0)
+ qDebug("%s D%02d < %s (%d)",
+ QString().fill(' ', d).ascii(), d,
+ prettyName().ascii(), _cycleLow);
+}
+
+
+TraceInstrMap* TraceFunction::instrMap()
+{
+#if USE_FIXCOST
+
+ if (_instrMapFilled) return _instrMap;
+ _instrMapFilled = true;
+ if (!_instrMap)
+ _instrMap = new TraceInstrMap;
+
+ TraceLine* l = 0;
+ TraceInstr* i = 0;
+ TracePartInstr* pi = 0;
+ TraceInstrCall* ic = 0;
+ TracePartInstrCall* pic = 0;
+
+ TraceInclusiveCostList pfList = deps();
+ TracePartFunction* pf = (TracePartFunction*) pfList.first();
+ for(; pf; pf = (TracePartFunction*) pfList.next()) {
+
+ if (0) qDebug("PartFunction %s:%d",
+ pf->function()->name().ascii(), pf->part()->partNumber());
+
+ FixCost* fc = pf->firstFixCost();
+ for(; fc; fc = fc->nextCostOfPartFunction()) {
+ if (fc->addr() == 0) continue;
+
+ if (!l || (l->lineno() != fc->line()) ||
+ (l->functionSource() != fc->functionSource()))
+ l = fc->functionSource()->line(fc->line(),true);
+
+ if (!i || i->addr() != fc->addr()) {
+ i = &(*_instrMap)[fc->addr()];
+ if (!i->isValid()) {
+ i->setFunction(this);
+ i->setAddr(fc->addr());
+ i->setLine(l);
+ }
+ pi = 0;
+ }
+ if (!pi || pi->part() != fc->part())
+ pi = i->partInstr(fc->part(), pf);
+ fc->addTo(pi);
+ }
+
+ TraceInstr* to = 0;
+ TraceInstrJump* ij;
+ TracePartInstrJump* pij;
+ FixJump* fj = pf->firstFixJump();
+ for(; fj; fj = fj->nextJumpOfPartFunction()) {
+ if (fj->addr() == 0) continue;
+
+ if (!l || (l->lineno() != fj->line()) ||
+ (l->functionSource() != fj->source()))
+ l = fj->source()->line(fj->line(),true);
+
+ if (!i || i->addr() != fj->addr()) {
+ i = &(*_instrMap)[fj->addr()];
+ if (!i->isValid()) {
+ i->setFunction(this);
+ i->setAddr(fj->addr());
+ i->setLine(l);
+ }
+ }
+
+ to = fj->targetFunction()->instr(fj->targetAddr(), true);
+
+ ij = i->instrJump(to, fj->isCondJump());
+ pij = ij->partInstrJump(fj->part());
+
+ fj->addTo(pij);
+ }
+
+ TracePartCallList pcList = pf->partCallings();
+ TracePartCall* pc = pcList.first();
+ for(; pc; pc = pcList.next()) {
+
+ if (0) qDebug("PartCall %s:%d",
+ pc->call()->name().ascii(),
+ pf->part()->partNumber());
+
+ FixCallCost* fcc = pc->firstFixCallCost();
+ for(; fcc; fcc = fcc->nextCostOfPartCall()) {
+ if (fcc->addr() == 0) continue;
+
+ if (!l || (l->lineno() != fcc->line()) ||
+ (l->functionSource() != fcc->functionSource()))
+ l = fcc->functionSource()->line(fcc->line(),true);
+
+ if (!i || i->addr() != fcc->addr()) {
+ i = &(*_instrMap)[fcc->addr()];
+ if (!i->isValid()) {
+ i->setFunction(this);
+ i->setAddr(fcc->addr());
+ i->setLine(l);
+ }
+ }
+ if (!ic || ic->call() != pc->call() || ic->instr() != i) {
+ ic = pc->call()->instrCall(i);
+ pic = 0;
+ }
+ if (!pic || pic->part() != fcc->part())
+ pic = ic->partInstrCall(fcc->part(), pc);
+
+ fcc->addTo(pic);
+ if (0) qDebug("Add FixCallCost %s:%d/0x%s, CallCount %s",
+ fcc->functionSource()->file()->shortName().ascii(),
+ fcc->line(), fcc->addr().toString().ascii(),
+ fcc->callCount().pretty().ascii());
+ }
+ }
+ }
+
+#endif
+
+ return _instrMap;
+}
+
+
+
+//---------------------------------------------------
+// TraceFunctionCycle
+
+TraceFunctionCycle::TraceFunctionCycle(TraceFunction* f, int n)
+{
+ _base = f;
+ _cycleNo = n;
+ _cycle = this;
+
+ setPosition(f->data());
+ setName(QString("<cycle %1>").arg(n));
+
+ // reset to attributes of base function
+ setFile(_base->file());
+ setClass(_base->cls());
+ setObject(_base->object());
+}
+
+void TraceFunctionCycle::init()
+{
+ _members.clear();
+ _memberSet.clear();
+ _callers.clear();
+ // this deletes all TraceCall's to members
+ _callings.clear();
+
+ invalidate();
+}
+
+void TraceFunctionCycle::add(TraceFunction* f)
+{
+ _members.append(f);
+ _memberSet.insert(f,1);
+}
+
+void TraceFunctionCycle::setup()
+{
+ if (_members.count()==0) return;
+
+ TraceFunction* f;
+ for (f=_members.first();f;f=_members.next()) {
+
+ // the cycle takes all outside callers from its members
+ TraceCall *call;
+ TraceCallList l = f->callers();
+ for (call=l.first();call;call=l.next()) {
+ if ( _memberSet.contains(call->caller()) ) continue;
+ _callers.append(call);
+ }
+
+ // the cycle has a call to each member
+ call = new TraceCall(this, f);
+ call->invalidate();
+ _callings.append(call);
+
+ // now do some faking...
+ f->setCycle(this);
+ }
+ invalidate();
+}
+
+
+//---------------------------------------------------
+// TraceClass
+
+TraceClass::TraceClass()
+{
+ // we are the owner of items generated in our factory
+ _deps.setAutoDelete(true);
+}
+
+TraceClass::~TraceClass()
+{}
+
+QString TraceClass::prettyName() const
+{
+ if (_name.isEmpty())
+ return QString("(global)");
+ return _name;
+}
+
+TracePartClass* TraceClass::partClass(TracePart* part)
+{
+ TracePartClass* item = (TracePartClass*) findDepFromPart(part);
+ if (!item) {
+ item = new TracePartClass(this);
+ item->setPosition(part);
+ addDep(item);
+ }
+ return item;
+}
+
+void TraceClass::addFunction(TraceFunction* function)
+{
+#if TRACE_ASSERTIONS
+ if (function->cls() != this) {
+ qDebug("Can't add function to a class not enclosing this function\n");
+ return;
+ }
+
+ if (_functions.findRef(function)>=0) return;
+#endif
+
+ _functions.append(function);
+
+ invalidate();
+
+#if TRACE_DEBUG
+ qDebug("%s added\n %s (now %d)",
+ fullName().ascii(),
+ function->fullName().ascii(), _functions.count());
+#endif
+}
+
+
+
+//---------------------------------------------------
+// TraceFile
+
+TraceFile::TraceFile()
+{
+ // we are the owner of items generated in our factory
+ _deps.setAutoDelete(true);
+}
+
+TraceFile::~TraceFile()
+{}
+
+TracePartFile* TraceFile::partFile(TracePart* part)
+{
+ TracePartFile* item = (TracePartFile*) findDepFromPart(part);
+ if (!item) {
+ item = new TracePartFile(this);
+ item->setPosition(part);
+ addDep(item);
+ }
+ return item;
+}
+
+void TraceFile::addFunction(TraceFunction* function)
+{
+#if TRACE_ASSERTIONS
+ if (function->file() != this) {
+ qDebug("Can't add function to a file not enclosing this function\n");
+ return;
+ }
+
+ if (_functions.findRef(function)>=0) return;
+#endif
+
+ _functions.append(function);
+
+ invalidate();
+
+#if TRACE_DEBUG
+ qDebug("%s added\n %s (now %d)",
+ fullName().ascii(),
+ function->fullName().ascii(), _functions.count());
+#endif
+}
+
+
+void TraceFile::addSourceFile(TraceFunctionSource* sourceFile)
+{
+#if TRACE_ASSERTIONS
+ if (sourceFile->file() != this) {
+ qDebug("Can't add sourceFile to a file not having lines for it\n");
+ return;
+ }
+#endif
+
+ _sourceFiles.append(sourceFile);
+ // not truely needed, as we don't use the sourceFiles for cost update
+ invalidate();
+
+#if TRACE_DEBUG
+ qDebug("%s \n added SourceFile %s (now %d)",
+ fullName().ascii(), sourceFile->fullName().ascii(),
+ _sourceFiles.count());
+#endif
+}
+
+
+
+void TraceFile::setDirectory(const QString& dir)
+{
+ if (dir.endsWith("/"))
+ _dir = dir.left(dir.length()-1);
+ else
+ _dir = dir;
+}
+
+QString TraceFile::directory()
+{
+ if (!_dir.isEmpty()) return _dir;
+
+ int lastIndex = 0, index;
+ while ( (index=_name.find("/", lastIndex)) >=0)
+ lastIndex = index+1;
+
+ if (lastIndex==0) return QString::null;
+
+ // without ending "/"
+ return _name.left(lastIndex-1);
+}
+
+
+QString TraceFile::shortName() const
+{
+ int lastIndex = 0, index;
+ while ( (index=_name.find("/", lastIndex)) >=0)
+ lastIndex = index+1;
+
+ return _name.mid(lastIndex);
+}
+
+QString TraceFile::prettyName() const
+{
+ QString sn = shortName();
+
+ if (sn.isEmpty())
+ return i18n("(unknown)");
+
+ return sn;
+}
+
+QString TraceFile::prettyLongName() const
+{
+ if (_name.isEmpty())
+ return i18n("(unknown)");
+ return _name;
+}
+
+
+//---------------------------------------------------
+// TraceObject
+
+TraceObject::TraceObject()
+{
+ // we are the owner of items generated in our factory
+ _deps.setAutoDelete(true);
+}
+
+TraceObject::~TraceObject()
+{}
+
+TracePartObject* TraceObject::partObject(TracePart* part)
+{
+ TracePartObject* item = (TracePartObject*) findDepFromPart(part);
+ if (!item) {
+ item = new TracePartObject(this);
+ item->setPosition(part);
+ addDep(item);
+ }
+ return item;
+}
+
+void TraceObject::addFunction(TraceFunction* function)
+{
+#if TRACE_ASSERTIONS
+ if (function->object() != this) {
+ qDebug("Can't add function to an object not enclosing this function\n");
+ return;
+ }
+
+ if (_functions.findRef(function)>=0) return;
+#endif
+
+ _functions.append(function);
+
+ invalidate();
+
+#if TRACE_DEBUG
+ qDebug("%s added\n %s (now %d)",
+ fullName().ascii(),
+ function->fullName().ascii(), _functions.count());
+#endif
+}
+
+// strip path
+void TraceObject::setName(const QString& name)
+{
+ _name = name;
+
+ int lastIndex = 0, index;
+ while ( (index=_name.find("/", lastIndex)) >=0)
+ lastIndex = index+1;
+
+ _shortName = _name.mid(lastIndex);
+}
+
+QString TraceObject::prettyName() const
+{
+ if (_shortName.isEmpty())
+ return i18n("(unknown)");
+
+ return _shortName;
+}
+
+//---------------------------------------------------
+// TracePart
+
+TracePart::TracePart(TraceData* data, QFile* file)
+{
+ setPosition(data);
+
+ _dep = data;
+ _file = file;
+ if (_file)
+ _name = _file->name();
+ _active = true;
+
+ _number = 0;
+ _tid = 0;
+ _pid = 0;
+
+ _fixSubMapping = 0;
+}
+
+TracePart::~TracePart()
+{
+ delete _file;
+
+ delete _fixSubMapping;
+}
+
+void TracePart::setPartNumber(int n)
+{
+ if (data()->maxPartNumber() <n) data()->setMaxPartNumber(n);
+ _number = n;
+}
+
+void TracePart::setThreadID(int tid)
+{
+ if (data()->maxThreadID() <tid) data()->setMaxThreadID(tid);
+ _tid = tid;
+}
+
+void TracePart::setProcessID(int pid)
+{
+ _pid = pid;
+}
+
+
+
+// strip path
+QString TracePart::shortName() const
+{
+ int lastIndex = 0, index;
+ while ( (index=_name.find("/", lastIndex)) >=0)
+ lastIndex = index+1;
+
+ return _name.mid(lastIndex);
+}
+
+QString TracePart::prettyName() const
+{
+ QString name = QString("%1.%2").arg(_pid).arg(_number);
+ if (data()->maxThreadID()>1)
+ name += QString("-%3").arg(_tid);
+ return name;
+}
+
+bool TracePart::activate(bool active)
+{
+ if (_active == active) return false;
+ _active = active;
+
+ // to be done by the client of this function
+ // data()->invalidateDynamicCost();
+ // So better use the TraceData functions...
+
+ return true;
+}
+
+
+
+//---------------------------------------------------
+// TracePartList
+
+int TracePartList::compareItems ( Item item1, Item item2 )
+{
+ TracePart* p1 = (TracePart*) item1;
+ TracePart* p2 = (TracePart*) item2;
+ int mTID = p1->data()->maxThreadID()+1;
+ int mNum = p1->data()->maxPartNumber()+1;
+
+ return
+ (p1->processID() - p2->processID()) * mTID * mNum +
+ (p1->partNumber() - p2->partNumber()) * mTID +
+ (p1->threadID() - p2->threadID());
+}
+
+QString TracePartList::names() const
+{
+ QString res;
+ TracePart* p;
+ TracePartList l = *this;
+ for (p=l.first();p;p=l.next()) {
+ if (!res.isEmpty()) res += ", ";
+ res += p->shortName();
+ }
+
+ return res;
+}
+
+
+
+//---------------------------------------------------
+// TraceData
+
+
+// create vectors with reasonable default sizes, but not wasting memory
+TraceData::TraceData(TopLevel* top)
+{
+ _topLevel = top;
+ init();
+}
+
+TraceData::TraceData(const QString& base)
+{
+ _topLevel = 0;
+ init();
+ load(base);
+}
+
+void TraceData::init()
+{
+ _parts.setAutoDelete(true);
+
+ _functionCycleCount = 0;
+ _inFunctionCycleUpdate = false;
+
+ _maxThreadID = 0;
+ _maxPartNumber = 0;
+ _fixPool = 0;
+ _dynPool = 0;
+}
+
+TraceData::~TraceData()
+{
+ if (_fixPool) delete _fixPool;
+ if (_dynPool) delete _dynPool;
+}
+
+QString TraceData::shortTraceName() const
+{
+ int lastIndex = 0, index;
+ while ( (index=_traceName.find("/", lastIndex)) >=0)
+ lastIndex = index+1;
+
+ return _traceName.mid(lastIndex);
+}
+
+FixPool* TraceData::fixPool()
+{
+ if (!_fixPool)
+ _fixPool = new FixPool();
+
+ return _fixPool;
+}
+
+DynPool* TraceData::dynPool()
+{
+ if (!_dynPool)
+ _dynPool = new DynPool();
+
+ return _dynPool;
+}
+
+
+/**
+ * Two cases:
+ *
+ * - <base> is a directory: Load first profile data file available
+ * - <base> is a file name without part/thread suffixes
+ */
+void TraceData::load(const QString& base)
+{
+ bool baseExisting = true;
+
+ _traceName = base;
+ QFileInfo finfo(base);
+ QString file = finfo.fileName();
+ QDir dir = finfo.dir();
+
+ if (!finfo.exists()) {
+ baseExisting = false;
+ }
+ else if (finfo.isDir()) {
+ // search for first profile data file in directory
+ dir = QDir(base);
+
+ QStringList prefixList;
+ prefixList << "callgrind.out" << "cachegrind.out";
+ for ( QStringList::Iterator it = prefixList.begin();
+ it != prefixList.end(); ++it ) {
+ file = *it;
+
+ // search for ".pid"
+ QStringList strList = dir.entryList(file+".*", QDir::Files);
+ if (strList.count()>0) {
+ int l = file.length();
+ file = strList.first();
+ l++;
+ while(file[l] >= '0' && file[l] <= '9') l++;
+ file = file.left(l);
+ break;
+ }
+ }
+
+ _traceName = dir.path() + "/" + file;
+ }
+
+ QStringList strList;
+ strList += dir.entryList(file+".*", QDir::Files);
+ strList += dir.entryList(file+"-*", QDir::Files);
+
+ baseExisting = QFile::exists(_traceName);
+ if (baseExisting)
+ strList << file;
+
+ if (strList.count() == 0) {
+ _traceName = base + "/" + file + " " + i18n("(not found)");
+ return;
+ }
+
+
+ // try to guess pid from file name
+ unsigned int pos = file.length();
+ unsigned int pid = 0, f=1;
+ pos--;
+ while(pos>0) {
+ if (file[pos] < '0' || file[pos] > '9') break;
+ pid += f * (file[pos].latin1() - '0');
+ pos--;
+ f *= 10;
+ }
+
+ QStringList::Iterator it;
+ unsigned int maxNumber = 0;
+ for (it = strList.begin(); it != strList.end(); ++it ) {
+ TracePart* p = addPart( dir.path(), *it );
+
+ if (!p) {
+ kdDebug() << "Error loading " << *it << endl;
+ continue;
+ }
+
+ const QString& str = *it;
+ unsigned int pos = file.length();
+
+ // try to guess part number from file name
+ unsigned int n = 0;
+ if ((str.length() > pos) && (str[pos] == '.')) {
+ pos++;
+ while(str.length()>pos) {
+ if (str[pos] < '0' || str[pos] > '9') break;
+ n = 10*n + (str[pos++] - '0');
+ }
+ }
+
+ // try to guess thread number from file name
+ unsigned int t = 0;
+ if ((str.length() > pos) && (str[pos] == '-')) {
+ pos++;
+ while(str.length()>pos) {
+ if (str[pos] < '0' || str[pos] > '9') break;
+ t = 10*t + (str[pos++] - '0');
+ }
+ }
+
+ //qDebug("File %s: Part %d, Thread %d", (*it).ascii(), n, t);
+
+ if (p->partNumber()>0) n = p->partNumber();
+ if (n>maxNumber) maxNumber = n;
+ if (n==0) n = maxNumber+1;
+ p->setPartNumber(n);
+
+ if (p->threadID()==0) p->setThreadID(t);
+ if (p->processID()==0) p->setProcessID(pid);
+
+ _parts.append(p);
+ }
+ _parts.sort();
+
+ invalidateDynamicCost();
+ updateFunctionCycles();
+
+ // clear loading messages from status bar
+ if (_topLevel) _topLevel->showStatus(QString::null, 0);
+}
+
+TracePart* TraceData::addPart(const QString& dir, const QString& name)
+{
+ QString filename = QString("%1/%2").arg(dir).arg(name);
+#if TRACE_DEBUG
+ qDebug("TraceData::addPart('%s')", filename.ascii());
+#endif
+
+ QFile* file = new QFile(filename);
+
+ Loader* l = Loader::matchingLoader(file);
+ if (!l) return 0;
+
+ if (_topLevel)
+ _topLevel->connect(l, SIGNAL(updateStatus(QString, int)),
+ SLOT(showStatus(QString, int)));
+
+ TracePart* part = new TracePart(this, file);
+
+ if (! l->loadTrace(part)) {
+ delete part;
+ part = 0;
+ }
+
+ if (_topLevel) l->disconnect(_topLevel);
+
+ return part;
+}
+
+bool TraceData::activateParts(const TracePartList& l)
+{
+ bool changed = false;
+
+ TracePart* part;
+ for (part=_parts.first();part;part=_parts.next())
+ if (part->activate(l.containsRef(part)>0))
+ changed = true;
+
+ if (changed) {
+ // because active parts have changed, throw away calculated
+ // costs...
+ invalidateDynamicCost();
+ updateFunctionCycles();
+ }
+
+ return changed;
+}
+
+
+bool TraceData::activateParts(TracePartList l, bool active)
+{
+ bool changed = false;
+
+ TracePart* part;
+ for (part=l.first();part;part=l.next())
+ if (_parts.findRef(part)>=0)
+ if (part->activate(active))
+ changed = true;
+
+ if (changed) {
+ invalidateDynamicCost();
+ updateFunctionCycles();
+ }
+
+ return changed;
+}
+
+bool TraceData::activatePart(TracePart* p, bool active)
+{
+ return p->activate(active);
+}
+
+bool TraceData::activateAll(bool active)
+{
+ return activateParts(_parts, active);
+}
+
+
+TracePart* TraceData::part(QString& name)
+{
+ TracePart* part;
+ for (part=_parts.first();part;part=_parts.next())
+ if (part->name() == name)
+ return part;
+ return 0;
+}
+
+QString TraceData::activePartRange()
+{
+ QString res;
+ int r1=-1, r2=-1, count=1;
+ TracePart* part;
+ for (part=_parts.first();part;part=_parts.next(), count++)
+ if (part->isActive()) {
+ if (r1<0) { r1 = r2 = count; }
+ else if (r2 == count-1) { r2 = count; }
+ else {
+ if (!res.isEmpty()) res += ";";
+ if (r1==r2) res += QString::number(r1);
+ else res += QString("%1-%2").arg(r1).arg(r2);
+ r1 = r2 = count;
+ }
+ }
+ if (r1>=0) {
+ if (!res.isEmpty()) res += ";";
+ if (r1==r2) res += QString::number(r1);
+ else res += QString("%1-%2").arg(r1).arg(r2);
+ }
+
+ return res;
+}
+
+void TraceData::invalidateDynamicCost()
+{
+ // invalidate all dynamic costs
+
+ TraceObjectMap::Iterator oit;
+ for ( oit = _objectMap.begin();
+ oit != _objectMap.end(); ++oit )
+ (*oit).invalidate();
+
+ TraceClassMap::Iterator cit;
+ for ( cit = _classMap.begin();
+ cit != _classMap.end(); ++cit )
+ (*cit).invalidate();
+
+ TraceFileMap::Iterator fit;
+ for ( fit = _fileMap.begin();
+ fit != _fileMap.end(); ++fit )
+ (*fit).invalidate();
+
+ TraceFunctionMap::Iterator it;
+ for ( it = _functionMap.begin();
+ it != _functionMap.end(); ++it ) {
+ (*it).invalidateDynamicCost();
+ }
+
+ invalidate();
+
+}
+
+
+TraceObject* TraceData::object(const QString& name)
+{
+ TraceObject& o = _objectMap[name];
+ if (!o.data()) {
+ // was created
+ o.setPosition(this);
+ o.setName(name);
+
+#if TRACE_DEBUG
+ qDebug("Created %s [TraceData::object]",
+ o.fullName().ascii());
+#endif
+ }
+ return &o;
+}
+
+
+TraceFile* TraceData::file(const QString& name)
+{
+ TraceFile& f = _fileMap[name];
+ if (!f.data()) {
+ // was created
+ f.setPosition(this);
+ f.setName(name);
+
+#if TRACE_DEBUG
+ qDebug("Created %s [TraceData::file]",
+ f.fullName().ascii());
+#endif
+ }
+ return &f;
+}
+
+
+// usually only called by function()
+TraceClass* TraceData::cls(const QString& fnName, QString& shortName)
+{
+ int lastIndex = 0, index, pIndex;
+
+ // we ignore any "::" after a '(' or a space
+ pIndex=fnName.find("(", 0);
+
+#if 0
+ int sIndex=fnName.find(" ", 0);
+ if (sIndex>=0)
+ if ((pIndex == -1) || (sIndex < pIndex))
+ pIndex = sIndex;
+#endif
+
+ while ((index=fnName.find("::", lastIndex)) >=0) {
+ if (pIndex>=0 && pIndex<index) break;
+ lastIndex = index+2;
+ }
+
+ QString clsName = (lastIndex < 3) ? QString::null :
+ fnName.left(lastIndex-2);
+ shortName = fnName.mid(lastIndex);
+
+ TraceClass& c = _classMap[clsName];
+ if (!c.data()) {
+ // was created
+ c.setPosition(this);
+ c.setName(clsName);
+
+#if TRACE_DEBUG
+ qDebug("Created %s [TraceData::cls]",
+ c.fullName().ascii());
+#endif
+ }
+ return &c;
+}
+
+
+// name is inclusive class/namespace prefix
+TraceFunction* TraceData::function(const QString& name,
+ TraceFile* file, TraceObject* object)
+{
+ // strip class name
+ QString shortName;
+ TraceClass* c = cls(name, shortName);
+
+ if (!file || !object || !c) {
+ qDebug("ERROR - no file/object/class for %s ?!", name.ascii());
+ return 0;
+ }
+
+ // Don't use file in key: A function can go over many files
+ // (inlined parts), but still is ONE function.
+ QString key = name + object->shortName();
+
+ TraceFunctionMap::Iterator it;
+ it = _functionMap.find(key);
+ if (it == _functionMap.end()) {
+ it = _functionMap.insert(key, TraceFunction());
+ TraceFunction& f = it.data();
+
+ f.setPosition(this);
+ f.setName(name);
+ f.setClass(c);
+ f.setObject(object);
+ f.setFile(file);
+ f.setMapIterator(it);
+
+#if TRACE_DEBUG
+ qDebug("Created %s [TraceData::function]\n for %s, %s, %s",
+ f.fullName().ascii(),
+ c->fullName().ascii(), file->fullName().ascii(),
+ object ? object->fullName().ascii() : "(unknown object)");
+#endif
+
+ c->addFunction(&f);
+ object->addFunction(&f);
+ file->addFunction(&f);
+ }
+
+ return &(it.data());
+}
+
+TraceFunctionMap::Iterator TraceData::functionIterator(TraceFunction* f)
+{
+
+ // IMPORTANT: build as SAME key as used in function() above !!
+ QString key;
+
+ if (f->cls()) key = f->cls()->name() + "::";
+ key += f->name();
+ key += f->object()->shortName();
+
+ return _functionMap.find(key);
+}
+
+TraceFunctionMap::ConstIterator TraceData::functionBeginIterator() const
+{
+ return _functionMap.begin();
+}
+
+TraceFunctionMap::ConstIterator TraceData::functionEndIterator() const
+{
+ return _functionMap.end();
+}
+
+
+void TraceData::resetSourceDirs()
+{
+ TraceFileMap::Iterator fit;
+ for ( fit = _fileMap.begin();
+ fit != _fileMap.end(); ++fit )
+ (*fit).resetDirectory();
+}
+
+void TraceData::update()
+{
+ if (!_dirty) return;
+
+ clear();
+ _totals.clear();
+
+ TracePart* part;
+ for (part=_parts.first();part;part=_parts.next()) {
+ _totals.addCost(part->totals());
+ if (part->isActive())
+ addCost(part->totals());
+ }
+
+ _dirty = false;
+}
+
+TraceCost* TraceData::search(TraceItem::CostType t, QString name,
+ TraceCostType* ct, TraceCost* parent)
+{
+ TraceCost* result = 0;
+ TraceItem::CostType pt = parent ? parent->type() : NoCostType;
+ SubCost sc, scTop = 0;
+
+ switch(t) {
+ case Function:
+ {
+ TraceFunction *f;
+ TraceFunctionMap::Iterator it;
+ for ( it = _functionMap.begin();
+ it != _functionMap.end(); ++it ) {
+ f = &(*it);
+
+ if (f->name() != name) continue;
+
+ if ((pt == Class) && (parent != f->cls())) continue;
+ if ((pt == File) && (parent != f->file())) continue;
+ if ((pt == Object) && (parent != f->object())) continue;
+
+ if (ct) {
+ sc = f->inclusive()->subCost(ct);
+ if (sc <= scTop) continue;
+ scTop = sc;
+ }
+
+ result = f;
+ }
+ }
+ break;
+
+ case File:
+ {
+ TraceFile *f;
+ TraceFileMap::Iterator it;
+ for ( it = _fileMap.begin();
+ it != _fileMap.end(); ++it ) {
+ f = &(*it);
+ if (f->name() != name) continue;
+ if (ct) {
+ sc = f->subCost(ct);
+ if (sc <= scTop) continue;
+ scTop = sc;
+ }
+ result = f;
+ }
+ }
+ break;
+
+ case Class:
+ {
+ TraceClass *c;
+ TraceClassMap::Iterator it;
+ for ( it = _classMap.begin();
+ it != _classMap.end(); ++it ) {
+ c = &(*it);
+ if (c->name() != name) continue;
+ if (ct) {
+ sc = c->subCost(ct);
+ if (sc <= scTop) continue;
+ scTop = sc;
+ }
+ result = c;
+ }
+ }
+ break;
+
+ case Object:
+ {
+ TraceObject *o;
+ TraceObjectMap::Iterator it;
+ for ( it = _objectMap.begin();
+ it != _objectMap.end(); ++it ) {
+ o = &(*it);
+ if (o->name() != name) continue;
+ if (ct) {
+ sc = o->subCost(ct);
+ if (sc <= scTop) continue;
+ scTop = sc;
+ }
+ result = o;
+ }
+ }
+ break;
+
+ case Instr:
+ if (pt == Function) {
+ TraceInstrMap* instrMap = ((TraceFunction*)parent)->instrMap();
+ if (!instrMap) break;
+
+ TraceInstr *instr;
+ TraceInstrMap::Iterator it;
+ for ( it = instrMap->begin();
+ it != instrMap->end(); ++it ) {
+ instr = &(*it);
+ if (instr->name() != name) continue;
+ result = instr;
+ }
+ }
+ break;
+
+ case Line:
+ {
+ TraceFunctionSourceList sList;
+ if (pt == Function)
+ sList = ((TraceFunction*)parent)->sourceFiles();
+ else if (pt == FunctionSource)
+ sList.append((TraceFunctionSource*) parent);
+ else break;
+
+ TraceLineMap* lineMap;
+ TraceLine* line;
+ TraceLineMap::Iterator it;
+ TraceFunctionSource* fs;
+ for(fs = sList.first(); fs; fs = sList.next()) {
+ lineMap = fs->lineMap();
+ if (!lineMap) continue;
+
+ for ( it = lineMap->begin();
+ it != lineMap->end(); ++it ) {
+ line = &(*it);
+ if (line->name() != name) continue;
+ result = line;
+ }
+ }
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ return result;
+}
+
+
+TraceFunctionCycle* TraceData::functionCycle(TraceFunction* f)
+{
+ TraceFunctionCycle* cycle;
+ for (cycle=_functionCycles.first();cycle;cycle=_functionCycles.next())
+ if (cycle->base() == f) return cycle;
+
+ _functionCycleCount++;
+ cycle = new TraceFunctionCycle(f, _functionCycleCount);
+
+ _functionCycles.append(cycle);
+ return cycle;
+}
+
+
+void TraceData::updateFunctionCycles()
+{
+ //qDebug("Updating cycles...");
+
+ // init cycle info
+ TraceFunctionCycle* cycle;
+ for (cycle=_functionCycles.first();cycle;cycle=_functionCycles.next())
+ cycle->init();
+
+ TraceFunctionMap::Iterator it;
+ for ( it = _functionMap.begin(); it != _functionMap.end(); ++it )
+ (*it).cycleReset();
+
+ if (!Configuration::showCycles()) return;
+
+ _inFunctionCycleUpdate = true;
+
+
+#if 0
+ int fCount = _functionMap.size(), fNo = 0, progress=0, p;
+ QString msg = i18n("Recalculating Function Cycles...");
+ if (_topLevel) _topLevel->showStatus(msg,0);
+#endif
+
+ // DFS and collapse strong connected components (Tarjan)
+ int pNo = 0;
+ TraceFunction* stackTop;
+ for ( it = _functionMap.begin(); it != _functionMap.end(); ++it ) {
+
+#if 0
+ if (_topLevel) {
+ fNo++;
+ p = 100*fNo/fCount;
+ if (p> progress) {
+ progress = p;
+ _topLevel->showStatus(msg, p);
+ }
+ }
+#endif
+
+ stackTop = 0;
+ (*it).cycleDFS(1, pNo, &stackTop);
+ }
+
+ // postprocess cycles
+ for (cycle=_functionCycles.first();cycle;cycle=_functionCycles.next())
+ cycle->setup();
+
+ _inFunctionCycleUpdate = false;
+ // we have to invalidate costs because cycles are now taken into account
+ invalidateDynamicCost();
+
+#if 0
+ if (0) if (_topLevel) _topLevel->showStatus(QString::null,0);
+#endif
+}
+
+void TraceData::updateObjectCycles()
+{
+}
+
+
+void TraceData::updateClassCycles()
+{
+}
+
+
+void TraceData::updateFileCycles()
+{
+}
+
+
diff --git a/kcachegrind/kcachegrind/tracedata.h b/kcachegrind/kcachegrind/tracedata.h
new file mode 100644
index 00000000..21922a05
--- /dev/null
+++ b/kcachegrind/kcachegrind/tracedata.h
@@ -0,0 +1,1967 @@
+/* This file is part of KCachegrind.
+ Copyright (C) 2002, 2003 Josef Weidendorfer <Josef.Weidendorfer@gmx.de>
+
+ KCachegrind is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public
+ License as published by the Free Software Foundation, version 2.
+
+ 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; see the file COPYING. If not, write to
+ the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+*/
+
+/*
+ * Classes holding profiling data for
+ * multiple tracefiles for one command.
+ * See class TraceData first.
+ */
+
+#ifndef TRACEDATA_H
+#define TRACEDATA_H
+
+#include <qstring.h>
+#include <qstringlist.h>
+#include <qptrlist.h>
+#include <qmap.h>
+#include <qptrvector.h>
+#include <qcolor.h>
+
+#include "subcost.h"
+#include "utils.h"
+
+class QFile;
+
+/**
+ * All cost items are classes prefixed with "Trace".
+ * "TraceCost" holds basic cost metrics for the simplest, smallest
+ * trace entity: These are events counted for an instruction at
+ * a specific memory address of the traced program.
+ * All other cost items are derived from TraceCost, and add needed
+ * cost metrics, e.g. for a call the number of calls that happened.
+ *
+ * Abstract, i.e. never instantiated cost items are
+ * - TraceCost: Basic cost metrics (instr/read/write access + cache events)
+ * - TraceCallCost: Additional call count cost metric.
+ * - TraceInclusiveCost: Additional TraceCost aggregated.
+ * - TraceListCost: Adds dependency to a list of TraceCost's
+ * - TraceCallListCost: same for list of TraceCallCost's
+ * - TraceInclusiveListCost: same for list of TraceInclusiveCost's
+ * - TraceCostItem: Base for cost items for "interesting" costs:
+ * TraceFunction, TraceClass, TraceFile, TraceObject
+ *
+ * The smallest Cachegrind output is trace data indexed by a source
+ * line number, a TracePartLine. Another one is a call from one
+ * source line of a function to another function, a TracePartLineCall.
+ * All other cost items derive the value by summation of cost metrics
+ * from TraceLineItem and TracePartLineCall costs; their cost is
+ * calculated lazy on demand and cached afterwards.
+ *
+ * For cost items, which are sums over all trace files read in, the
+ * summed cost metrics change when e.g. a new trace file is read.
+ * Thus, their cached costs are invalidated, and again recalculated
+ * only on demand. In the following list, theses cost items are called
+ * "dynamic", the other "fixed" (but neverless calculated lazy).
+ *
+ * Cost Item Type Summation of ...
+ *
+ * TracePartLineCall fixed Read from trace file
+ * TracePartLine fixed Read from trace file
+ * TracePartCall fixed TracePartLineCall's
+ * TraceLineCall dynamic TracePartLineCall's
+ * TraceCall dynamic TraceLineCall's
+ * TraceLine dynamic TracePartLine's and TraceLineCall's
+ * TracePartFunction fixed TracePartLine's / TracePartCall's
+ * TraceFunction dynamic TraceLine's / TraceCall's (called from)
+ * TracePartClass fixed TracePartFunction's
+ * TraceClass dynamic TraceFunction's
+ * TracePartFile fixed TracePartFunction's
+ * TraceFile dynamic TraceFunction's
+ * TracePartObject fixed TracePartFunction's
+ * TraceObject dynamic TraceFunction's
+ * TracePart fixed TracePartLine's
+ * TraceData dynamic TracePart's
+ *
+ * As there exists only one TraceData object for a traced program, its the
+ * owner of some "high level" cost items. The following shows the owner
+ * relationship of the cost item classes, together with references.
+ *
+ * Cost Item Owner (& back ref) Other References to
+ *
+ * TracePartLineCall TraceLineCall
+ * TracePartCall TraceCall TracePartLineCall's
+ * TracePartLine TraceLine TracePartLineCall's
+ * TracePartFunction TraceFunction
+ * TracePartClass TraceClass TracePart
+ * TracePartFile TraceFile TracePart
+ * TracePartObject TraceObject TracePart
+ * TraceLineCall TraceCall TracePartLineCall's
+ * TraceCall TraceFunction TracePartCall's
+ * TraceLine TraceData TraceLineCall's
+ * TraceFunction TraceData TraceCall's (calling)
+ * TraceClass TraceData
+ * TraceFile TraceData
+ * TraceObject TraceData
+ * TracePart TraceData
+ * TraceData Main Application
+ *
+ * Convention:
+ * - The owner has a factory method for owned objects,
+ * and calls addXXX() to install references in other objects
+ * - The owner is first arg in a constructor.
+ */
+
+
+class FixString;
+class FixCost;
+class FixCallCost;
+class FixJump;
+class FixPool;
+class DynPool;
+class TopLevel;
+
+class TraceCost;
+class TraceCostType;
+class TraceCostMapping;
+class TraceSubMapping;
+class TraceJumpCost;
+class TraceCallCost;
+class TraceInclusiveCost;
+
+class TracePartInstr;
+class TracePartInstrCall;
+class TracePartLine;
+class TracePartLineCall;
+class TracePartCall;
+class TracePartLineRegion;
+class TracePartFunction;
+class TracePartClass;
+class TracePartObject;
+class TracePartFile;
+
+class TraceInstr;
+class TraceInstrJump;
+class TraceInstrCall;
+class TraceLine;
+class TraceLineJump;
+class TraceLineCall;
+class TraceCall;
+class TraceLineRegion;
+class TraceFunctionSource;
+class TraceFunction;
+class TraceFunctionCycle;
+class TraceClass;
+class TraceObject;
+class TraceFile;
+class TracePart;
+class TraceData;
+
+typedef QPtrList<TraceCost> TraceCostList;
+typedef QPtrList<TraceJumpCost> TraceJumpCostList;
+typedef QPtrList<TraceCallCost> TraceCallCostList;
+typedef QPtrList<TraceInclusiveCost> TraceInclusiveCostList;
+
+typedef QPtrList<TracePartCall> TracePartCallList;
+typedef QPtrList<TracePartInstr> TracePartInstrList;
+typedef QPtrList<TracePartLine> TracePartLineList;
+typedef QPtrList<TracePartLineRegion> TracePartLineRegionList;
+typedef QPtrList<TracePartFunction> TracePartFunctionList;
+typedef QPtrList<TracePartInstrCall> TracePartInstrCallList;
+typedef QPtrList<TracePartLineCall> TracePartLineCallList;
+
+
+typedef QPtrList<TraceInstr> TraceInstrList;
+typedef QPtrList<TraceLine> TraceLineList;
+typedef QPtrList<TraceInstrCall> TraceInstrCallList;
+typedef QPtrList<TraceLineCall> TraceLineCallList;
+typedef QPtrList<TraceCall> TraceCallList;
+typedef QPtrList<TraceFile> TraceFileList;
+typedef QPtrList<TraceLineRegion> TraceLineRegionList;
+typedef QPtrList<TraceFunctionSource> TraceFunctionSourceList;
+typedef QPtrList<TraceFunction> TraceFunctionList;
+typedef QPtrList<TraceFunctionCycle> TraceFunctionCycleList;
+typedef QMap<QString, TraceObject> TraceObjectMap;
+typedef QMap<QString, TraceClass> TraceClassMap;
+typedef QMap<QString, TraceFile> TraceFileMap;
+typedef QMap<QString, TraceFunction> TraceFunctionMap;
+typedef QMap<uint, TraceLine> TraceLineMap;
+
+
+/**
+ * Addresses are 64bit values like costs to be able
+ * to always load profile data produced on 64bit
+ * architectures.
+ */
+class Addr
+{
+ public:
+ Addr() { _v=0; }
+ Addr(uint64 v) { _v = v; }
+
+ // Interpretes char data at s as hex (without "0x" prefix)
+ // and return number of interpreted chars.
+ int set(const char *s);
+ bool set(FixString& s);
+ QString toString() const;
+ // similar to toString(), but adds a space every 4 digits
+ QString pretty() const;
+
+ // returns true if this address is in [a-distance;a+distance]
+ bool isInRange(Addr a, int distance);
+
+ bool operator==(const Addr& a) const { return (_v == a._v); }
+ bool operator!=(const Addr& a) const { return (_v != a._v); }
+ bool operator>(const Addr& a) const { return _v > a._v; }
+ bool operator>=(const Addr& a) const { return _v >= a._v; }
+ bool operator<(const Addr& a) const { return _v < a._v; }
+ bool operator<=(const Addr& a) const { return _v <= a._v; }
+
+ Addr operator+(int d) const { return Addr(_v + d); }
+ Addr operator-(int d) const { return Addr(_v - d); }
+
+ private:
+ uint64 _v;
+};
+
+typedef QMap<Addr, TraceInstr> TraceInstrMap;
+
+
+/**
+ * Base class for cost items.
+ */
+class TraceItem
+{
+public:
+
+ // RTTI for trace item classes, using type() method
+ enum CostType { Item, Cost,
+ PartInstr, Instr,
+ PartLine, Line,
+ PartInstrJump, InstrJump,
+ PartLineJump, LineJump,
+ PartInstrCall, InstrCall,
+ PartLineCall, LineCall,
+ PartCall, Call,
+ PartLineRegion, LineRegion,
+ PartFunction, FunctionSource, Function, FunctionCycle,
+ PartClass, Class, ClassCycle,
+ PartFile, File, FileCycle,
+ PartObject, Object, ObjectCycle,
+ Part, Data,
+ MaxCostType, NoCostType };
+
+ TraceItem();
+ virtual ~TraceItem();
+
+ virtual CostType type() const { return Item; }
+
+ // conversion of item type to locale independent string (e.g. for config)
+ static QString typeName(CostType);
+ static CostType costType(QString);
+ // the versions below should be used for user visible strings, as
+ // these use localisation settings
+ static QString i18nTypeName(CostType);
+ static CostType i18nCostType(QString);
+ // clean up some static data
+ static void cleanup();
+
+ /**
+ * Returns dynamic name info (without type)
+ */
+ virtual QString name() const;
+
+ /**
+ * Same as name, but sometimes nicer for humans :-)
+ */
+ virtual QString prettyName() const;
+
+ /**
+ * Returns text of all cost metrics
+ */
+ virtual QString costString(TraceCostMapping*);
+
+ /**
+ * Returns type name + dynamic name
+ */
+ QString fullName() const;
+
+ /**
+ * Returns full name + cost text
+ */
+ QString toString();
+
+ /**
+ * Set all cost counters to zero
+ */
+ virtual void clear();
+
+ /** Invalidate the cost attributes.
+ * An invalidated object needs to be recalculated when a cost
+ * attribute is requested (e.g. by subCost()).
+ * Has to be overwritten by subclasses when the cost influences costs of
+ * other cost items. If only one item depends on the cost of this item,
+ * it can by set with setDependant() without a need for overwriting.
+ */
+ virtual void invalidate();
+
+ /**
+ * Sets a dependant to be invalidated when this cost is invalidated.
+ * Call this function directly after the constructor.
+ */
+ void setDependant(TraceItem* d) { _dep = d; }
+
+ TraceItem* dependant() { return _dep; }
+
+ /**
+ * If this item is from a single profile data file, position
+ * points to a TracePart, otherwise to a TraceData object.
+ */
+ void setPosition(TraceItem* p) { _position = p; }
+
+ // getters for specific positions, to be overwritten
+ virtual TracePart* part();
+ virtual const TracePart* part() const;
+ virtual TraceData* data();
+ virtual const TraceData* data() const;
+
+ protected:
+ /** Updates cost attributes.
+ * This has to be called by subclasses that access cost attributes
+ * directly
+ */
+ virtual void update();
+
+ bool _dirty;
+
+ TraceItem* _position;
+ TraceItem* _dep;
+
+ private:
+ static QString *_typeName, *_i18nTypeName;
+};
+
+
+
+/**
+ * An array of basic cost metrics for a trace item.
+ *
+ * The semantic of specific indexes is stored in the
+ * TraceCostMapping of the TraceData object holding this TraceCost.
+ */
+class TraceCost: public TraceItem
+{
+public:
+ /**
+ * The maximal number of subcosts a TraceCost can have.
+ */
+ static const int MaxRealIndex;
+#define MaxRealIndexValue 13
+ static const int InvalidIndex;
+
+
+ TraceCost();
+ virtual ~TraceCost();
+
+ virtual CostType type() const { return Cost; }
+ virtual QString costString(TraceCostMapping*);
+
+ virtual void clear();
+
+ // set the cost according to a submapping and a list of ASCII numbers
+ void set(TraceSubMapping*, const char*);
+ void set(TraceSubMapping*, FixString&);
+ // add a cost according to a submapping and a list of ASCII numbers
+ void addCost(TraceSubMapping*, const char*);
+ void addCost(TraceSubMapping*, FixString&);
+ // add the cost of another item
+ void addCost(TraceCost* item);
+ void addCost(int index, SubCost value);
+
+ // maximal cost
+ void maxCost(TraceSubMapping*, FixString&);
+ void maxCost(TraceCost* item);
+ void maxCost(int index, SubCost value);
+ TraceCost diff(TraceCost* item);
+
+ virtual void invalidate();
+
+ /** Returns a sub cost. This automatically triggers
+ * a call to update() if needed.
+ */
+ SubCost subCost(TraceCostType*);
+
+ /**
+ * Same as above, but only for real types
+ */
+ SubCost subCost(int);
+
+ /** Returns a cost attribute converted to a string
+ * (with space after every 3 digits)
+ */
+ QString prettySubCost(TraceCostType*);
+
+ protected:
+ virtual void update();
+
+ SubCost _cost[MaxRealIndexValue];
+ int _count; // only _count first indexes of _cost are used
+
+ // cache last virtual subcost for faster access
+ SubCost _cachedCost;
+ TraceCostType* _cachedType;
+};
+
+
+
+/**
+ * A cost type, e.g. "L1 Read Miss", short "l1rm".
+ *
+ * We distinguish "real" cost types, where the values come
+ * from the trace file, and "virtual" cost types, which
+ * are calculated from the real ones.
+ *
+ * For a virtual cost type, set a formula to calculate it:
+ * e.g. for "Read Misses" : "l1rm + l2rm".
+ * To allow for parsing, you must specify a TraceCostMapping
+ * with according cost types (e.g. "l1rm" and "l2rm" for above formula).
+ *
+ * The cost type with empty name is the "const" cost type.
+ */
+class TraceCostType
+{
+public:
+
+ /**
+ * <name> is a short (non-localized) identifier for the cost type,
+ * e.g. "l1rm".
+ * <longName> is a long localized string, e.g. "L1 Read Miss"
+ * <formula> uses short names to reference other types
+ */
+ TraceCostType(QString name,
+ QString longName = QString::null,
+ QString formula = QString::null);
+
+ void setName(QString n) { _name = n; }
+ void setLongName(QString n) { _longName = n; }
+ void setMapping(TraceCostMapping* m);
+ void setFormula(QString);
+ // default arg is for specifying a real type, but index unknown
+ void setRealIndex(int r = TraceCost::MaxRealIndex);
+
+ const QString& name() { return _name; }
+ const QString& longName() { return _longName; }
+ const QString& formula() { return _formula; }
+ TraceCostMapping* mapping() { return _mapping; }
+ int realIndex() { return _realIndex; }
+ bool isReal() { return _formula.isEmpty(); }
+ QColor color();
+
+ /*
+ * returns true if all cost type names can be resolved in formula
+ */
+ bool parseFormula();
+ QString parsedFormula();
+
+ SubCost subCost(TraceCost*);
+
+ /*
+ * For virtual costs, returns a histogram for use with
+ * partitionPixmap().
+ * Returns maximal real index.
+ */
+ int histCost(TraceCost* c, double total, double* hist);
+
+ // application wide known types, referenced by short name
+ // next 2 functions return a new type object instance
+ static TraceCostType* knownRealType(QString);
+ static TraceCostType* knownVirtualType(QString);
+ static void add(TraceCostType*);
+ static bool remove(QString);
+ static int knownTypeCount();
+ static TraceCostType* knownType(int);
+
+private:
+
+ QString _name, _longName, _formula;
+ TraceCostMapping* _mapping;
+ bool _parsed, _inParsing;
+ // index MaxRealIndex is for constant addition
+ int _coefficient[MaxRealIndexValue];
+ int _realIndex;
+
+ static QPtrList<TraceCostType>* _knownTypes;
+};
+
+
+/**
+ * A class for managing a set of cost types.
+ *
+ * Each cost type has an index:
+ * - Real costs are in range [0 .. TraceCost:MaxRealIndex[
+ * - Virtual costs are in range [MaxRealIndex, ...]
+ */
+class TraceCostMapping
+{
+public:
+ TraceCostMapping();
+ ~TraceCostMapping();
+
+ /**
+ * Defines a sub mapping with a list of real types
+ * If <create> is false, checks if this is a existing sub mapping.
+ */
+ TraceSubMapping* subMapping(QString types, bool create = true);
+
+ // "knows" about some real types
+ int addReal(QString);
+ int add(TraceCostType*);
+ bool remove(TraceCostType*);
+ int realCount() { return _realCount; }
+ int virtualCount() { return _virtualCount; }
+ int minVirtualIndex() { return TraceCost::MaxRealIndex; }
+ TraceCostType* type(int);
+ TraceCostType* realType(int);
+ TraceCostType* virtualType(int);
+ TraceCostType* type(QString);
+ TraceCostType* typeForLong(QString);
+ int realIndex(QString);
+ int index(QString);
+ QColor* realColors() { return _realColor; }
+
+ /**
+ * Adds all known virtual types that can be parsed
+ */
+ int addKnownVirtualTypes();
+
+private:
+ // we support only a fixed number of real and virtual types
+ TraceCostType* _real[MaxRealIndexValue];
+ QColor _realColor[MaxRealIndexValue];
+ TraceCostType* _virtual[MaxRealIndexValue];
+ int _realCount, _virtualCount;
+};
+
+/**
+ * A submapping of a TraceCostMapping
+ *
+ * This is a fixed ordered list of indexes for real cost types
+ * in a mapping.
+ *
+ * You can define a mapping by requesting submappings. Undefined cost
+ * types will get a new real type index.
+ * TraceCostMapping m;
+ * sm1 = m.subMapping("Event1 Cost1 Cost2"); // returns submap [0,1,2]
+ * sm2 = m.subMapping("Event2 Cost3 Event1"); // returns submap [3,4,0]
+ * Real types of m will be:
+ * (0:Event1, 1:Cost1, 2:Cost2, 3:Event2, 4:Cost3)
+ */
+class TraceSubMapping
+{
+public:
+ TraceSubMapping(TraceCostMapping*);
+
+ bool append(QString, bool create=true);
+ bool append(int);
+ void clear();
+
+ /**
+ * Get number of used indexes
+ */
+ int count() { return _count; }
+
+ /**
+ * Is this submapping the identity( i.e. realIndex(i)=i ) ?
+ * This often allows for optimizations.
+ */
+ bool isIdentity() { return _isIdentity; }
+ int realIndex(int i)
+ { return (i<0 || i>=_count) ? TraceCost::InvalidIndex : _realIndex[i]; }
+
+ /*
+ * Allows an iteration over the sorted list of all real indexes not used in
+ * this submapping, up to topIndex (use TraceCost::MaxRealIndex for all).
+ * Usage: for(i = firstUnused(); i < topIndex; i = nextUnused(i)) { LOOP }
+ */
+ int firstUnused() { return _firstUnused; }
+ int nextUnused(int i) {
+ if (i<0 || i>=TraceCost::MaxRealIndex) return TraceCost::InvalidIndex;
+ return _nextUnused[i]; }
+
+private:
+ TraceCostMapping* _mapping;
+ int _count, _firstUnused;
+ bool _isIdentity;
+ int _realIndex[MaxRealIndexValue];
+ int _nextUnused[MaxRealIndexValue];
+};
+
+
+/**
+ * Cost of a (conditional) jump.
+ */
+class TraceJumpCost: public TraceItem
+{
+ public:
+ TraceJumpCost();
+ virtual ~TraceJumpCost();
+
+ // reimplementations for cost addition
+ virtual QString costString(TraceCostMapping* m);
+ virtual void clear();
+
+ void addCost(TraceJumpCost*);
+
+ // additional cost metrics
+ SubCost followedCount();
+ SubCost executedCount();
+ void addFollowedCount(SubCost c) { _followedCount += c; }
+ void addExecutedCount(SubCost c) { _executedCount += c; }
+
+ protected:
+ SubCost _executedCount, _followedCount;
+};
+
+
+
+/**
+ * Cost item with additional call count metric.
+ */
+class TraceCallCost: public TraceCost
+{
+ public:
+ TraceCallCost();
+ virtual ~TraceCallCost();
+
+ // reimplementations for cost addition
+ virtual QString costString(TraceCostMapping* m);
+ virtual void clear();
+
+ // additional cost metric
+ SubCost callCount();
+ QString prettyCallCount();
+ void addCallCount(SubCost c);
+
+ protected:
+ SubCost _callCount;
+};
+
+
+/**
+ * Cost item with additional inclusive metric
+ */
+class TraceInclusiveCost: public TraceCost
+{
+ public:
+ TraceInclusiveCost();
+ virtual ~TraceInclusiveCost();
+
+ // reimplementations for cost addition
+ virtual QString costString(TraceCostMapping* m);
+ virtual void clear();
+
+ // additional cost metric
+ TraceCost* inclusive();
+ void addInclusive(TraceCost*);
+
+ protected:
+ TraceCost _inclusive;
+};
+
+
+/**
+ * Cost Item
+ * dependend on a list of cost items.
+ */
+class TraceListCost: public TraceCost
+{
+ public:
+ TraceListCost();
+ virtual ~TraceListCost();
+
+ // reimplementation for dependency list
+ virtual void update();
+
+ TraceCostList& deps() { return _deps; }
+ void addDep(TraceCost*);
+ TraceCost* findDepFromPart(TracePart*);
+
+ protected:
+ // overwrite in subclass to change update behaviour
+ virtual bool onlyActiveParts() { return false; }
+
+ TraceCostList _deps;
+
+ private:
+ // very temporary: cached
+ TraceCost* _lastDep;
+};
+
+
+/**
+ * Jump Cost Item
+ * dependend on a list of Jump cost items.
+ */
+class TraceJumpListCost: public TraceJumpCost
+{
+ public:
+ TraceJumpListCost();
+ virtual ~TraceJumpListCost();
+
+ // reimplementation for dependency list
+ virtual void update();
+
+ TraceJumpCostList deps() { return _deps; }
+ void addDep(TraceJumpCost*);
+ TraceJumpCost* findDepFromPart(TracePart*);
+
+ protected:
+ // overwrite in subclass to change update behaviour
+ virtual bool onlyActiveParts() { return false; }
+
+ TraceJumpCostList _deps;
+
+ private:
+ // very temporary: cached
+ TraceJumpCost* _lastDep;
+};
+
+
+
+
+/**
+ * Call Cost Item
+ * dependend on a list of Call cost items.
+ */
+class TraceCallListCost: public TraceCallCost
+{
+ public:
+ TraceCallListCost();
+ virtual ~TraceCallListCost();
+
+ // reimplementation for dependency list
+ virtual void update();
+
+ TraceCallCostList deps() { return _deps; }
+ void addDep(TraceCallCost*);
+ TraceCallCost* findDepFromPart(TracePart*);
+
+ protected:
+ // overwrite in subclass to change update behaviour
+ virtual bool onlyActiveParts() { return false; }
+
+ TraceCallCostList _deps;
+
+ private:
+ // very temporary: cached
+ TraceCallCost* _lastDep;
+};
+
+
+/**
+ * Inclusive Cost Item dependend on a list of inclusive cost items.
+ */
+class TraceInclusiveListCost: public TraceInclusiveCost
+{
+ public:
+ TraceInclusiveListCost();
+ virtual ~TraceInclusiveListCost();
+
+ // reimplementation for dependency
+ virtual void update();
+
+ TraceInclusiveCostList deps() { return _deps; }
+ void addDep(TraceInclusiveCost*);
+ TraceInclusiveCost* findDepFromPart(TracePart*);
+
+ protected:
+ // overwrite in subclass to change update behaviour
+ virtual bool onlyActiveParts() { return false; }
+
+ TraceInclusiveCostList _deps;
+
+ private:
+ // very temporary: cached
+ TraceInclusiveCost* _lastDep;
+};
+
+
+
+
+
+/*-----------------------------------------------------------------
+ * Classes for cost items of one trace file, i.e. a "trace part"
+ *-----------------------------------------------------------------
+ */
+
+/**
+ * Cost of jump at a instruction code address from a trace file.
+ */
+class TracePartInstrJump: public TraceJumpCost
+{
+ public:
+ TracePartInstrJump(TraceInstrJump*, TracePartInstrJump*);
+ virtual ~TracePartInstrJump();
+
+ virtual CostType type() const { return PartInstrJump; }
+ // fix cost item
+ virtual void update() {}
+ TraceInstrJump* instrJump() const { return (TraceInstrJump*) _dep; }
+ TracePartInstrJump* next() const { return _next; }
+
+ private:
+ // chaining all parts for InstrJump
+ TracePartInstrJump* _next;
+};
+
+
+/**
+ * Cost of a call at a instruction code address from a trace file.
+ * Cost is always up to date, no lazy update needed.
+ */
+class TracePartInstrCall: public TraceCallCost
+{
+public:
+ TracePartInstrCall(TraceInstrCall*);
+ virtual ~TracePartInstrCall();
+
+ virtual CostType type() const { return PartInstrCall; }
+ // fix cost item
+ virtual void update() {}
+ TraceInstrCall* instrCall() const { return (TraceInstrCall*) _dep; }
+};
+
+
+/**
+ * Cost of a code instruction address from a trace file.
+ * Cost is always up to date, no lazy update needed.
+ */
+class TracePartInstr: public TraceCost
+{
+public:
+ TracePartInstr(TraceInstr*);
+ virtual ~TracePartInstr();
+
+ virtual CostType type() const { return PartInstr; }
+ // fix cost item
+ virtual void update() {}
+
+ TraceInstr* instr() const { return (TraceInstr*)_dep; }
+};
+
+
+/**
+ * Cost of jump at a source line from a trace file.
+ */
+class TracePartLineJump: public TraceJumpCost
+{
+ public:
+ TracePartLineJump(TraceLineJump*);
+ virtual ~TracePartLineJump();
+
+ virtual CostType type() const { return PartLineJump; }
+ // fix cost item
+ virtual void update() {}
+ TraceLineJump* lineJump() const { return (TraceLineJump*) _dep; }
+};
+
+
+/**
+ * Cost of a call at a line from a trace file.
+ * Cost is always up to date, no lazy update needed.
+ */
+class TracePartLineCall: public TraceCallCost
+{
+public:
+ TracePartLineCall(TraceLineCall*);
+ virtual ~TracePartLineCall();
+
+ virtual CostType type() const { return PartLineCall; }
+ // fix cost item
+ virtual void update() {}
+ TraceLineCall* lineCall() const { return (TraceLineCall*) _dep; }
+};
+
+
+
+/**
+ * Cost of a line from a trace file.
+ * Cost is always up to date, no lazy update needed.
+ */
+class TracePartLine: public TraceCost
+{
+public:
+ TracePartLine(TraceLine*);
+ virtual ~TracePartLine();
+
+ virtual CostType type() const { return PartLine; }
+ // fix cost item
+ virtual void update() {}
+
+ TraceLine* line() const { return (TraceLine*)_dep; }
+};
+
+
+/**
+ * Cost of a source region.
+ */
+class TracePartLineRegion: public TraceInclusiveCost
+{
+public:
+ TracePartLineRegion(TraceLineRegion*);
+ virtual ~TracePartLineRegion();
+
+ virtual CostType type() const { return PartLineRegion; }
+ virtual void update();
+
+ TraceLineRegion* region() const { return (TraceLineRegion*)_dep; }
+};
+
+
+/**
+ * Cost of a call at a function to another function,
+ * from a single trace file.
+ */
+class TracePartCall: public TraceCallListCost
+{
+public:
+ TracePartCall(TraceCall* call);
+ virtual ~TracePartCall();
+
+ virtual CostType type() const { return PartCall; }
+ // calls a function itself?
+ bool isRecursion();
+
+ // reimplementation for dependency list
+ virtual void update();
+
+ TraceCall* call() const { return (TraceCall*)_dep; }
+
+ FixCallCost* setFirstFixCallCost(FixCallCost* fc)
+ { FixCallCost* t = _firstFixCallCost; _firstFixCallCost = fc; return t; }
+ FixCallCost* firstFixCallCost() const { return _firstFixCallCost; }
+
+private:
+ FixCallCost* _firstFixCallCost;
+};
+
+
+/**
+ * Cost of a function,
+ * from a single trace file.
+ */
+class TracePartFunction: public TraceInclusiveCost
+{
+public:
+ TracePartFunction(TraceFunction*,
+ TracePartObject*, TracePartFile*);
+ virtual ~TracePartFunction();
+
+ virtual CostType type() const { return PartFunction; }
+ virtual void update();
+ virtual QString costString(TraceCostMapping* m);
+
+ void addPartInstr(TracePartInstr*);
+ void addPartLine(TracePartLine*);
+ void addPartCaller(TracePartCall*);
+ void addPartCalling(TracePartCall*);
+
+ TraceFunction* function() { return (TraceFunction*) _dep; }
+ TracePartObject* partObject() { return _partObject; }
+ TracePartClass* partClass() { return _partClass; }
+ TracePartFile* partFile() { return _partFile; }
+ const TracePartCallList& partCallers() { return _partCallers; }
+ const TracePartCallList& partCallings() { return _partCallings; }
+ void setPartObject(TracePartObject* o) { _partObject = o; }
+ void setPartClass(TracePartClass* c) { _partClass = c; }
+ void setPartFile(TracePartFile* f) { _partFile = f; }
+
+ /* for linked list of FixXXX objects */
+ FixCost* setFirstFixCost(FixCost* fc)
+ { FixCost* t = _firstFixCost; _firstFixCost = fc; return t; }
+ FixCost* firstFixCost() const { return _firstFixCost; }
+ FixJump* setFirstFixJump(FixJump* fj)
+ { FixJump* t = _firstFixJump; _firstFixJump = fj; return t; }
+ FixJump* firstFixJump() const { return _firstFixJump; }
+
+ // additional cost metrics
+ SubCost calledCount();
+ SubCost callingCount();
+ QString prettyCalledCount();
+ QString prettyCallingCount();
+ int calledContexts();
+ int callingContexts();
+
+private:
+ TracePartObject* _partObject;
+ TracePartClass* _partClass;
+ TracePartFile* _partFile;
+
+ TracePartCallList _partCallings;
+ TracePartCallList _partCallers;
+ TracePartInstrList _partInstr;
+ TracePartLineList _partLines;
+
+ // cached
+ SubCost _calledCount, _callingCount;
+ int _calledContexts, _callingContexts;
+
+ FixCost* _firstFixCost;
+ FixJump* _firstFixJump;
+};
+
+
+/**
+ * Cost of a class,
+ * from a single trace file.
+ */
+class TracePartClass: public TraceInclusiveListCost
+{
+public:
+ TracePartClass(TraceClass*);
+ virtual ~TracePartClass();
+
+ virtual CostType type() const { return PartClass; }
+ QString prettyName() const;
+
+ TraceClass* cls() { return (TraceClass*)_dep; }
+ void addPartFunction(TracePartFunction* f) { addDep(f); }
+};
+
+
+/**
+ * Cost of a source file,
+ * from a single trace file.
+ */
+class TracePartFile: public TraceInclusiveListCost
+{
+public:
+ TracePartFile(TraceFile*);
+ virtual ~TracePartFile();
+
+ virtual CostType type() const { return PartFile; }
+ TraceFile* file() { return (TraceFile*)_dep; }
+ void addPartFunction(TracePartFunction* f) { addDep(f); }
+};
+
+
+/**
+ * Cost of a object,
+ * from a single trace file.
+ */
+class TracePartObject: public TraceInclusiveListCost
+{
+public:
+ TracePartObject(TraceObject*);
+ virtual ~TracePartObject();
+
+ virtual CostType type() const { return PartObject; }
+ TraceObject* object() const { return (TraceObject*)_dep; }
+ void addPartFunction(TracePartFunction* f) { addDep(f); }
+};
+
+
+
+/**
+ * A Trace Part: All data read from a trace file, containing all costs
+ * that happened in a specified time interval of the executed command.
+ */
+class TracePart: public TraceListCost
+{
+public:
+ TracePart(TraceData*, QFile* file);
+ virtual ~TracePart();
+
+ virtual CostType type() const { return Part; }
+ virtual TracePart* part() { return this; }
+ virtual const TracePart* part() const { return this; }
+
+ QString shortName() const;
+ QString prettyName() const;
+ QFile* file() const { return _file; }
+ QString name() const { return _name; }
+ QString description() const { return _descr; }
+ QString trigger() const { return _trigger; }
+ QString timeframe() const { return _timeframe; }
+ QString version() const { return _version; }
+ int partNumber() { return _number; }
+ int threadID() { return _tid; }
+ int processID() { return _pid; }
+ void setDescription(const QString& d) { _descr = d; }
+ void setTrigger(const QString& t) { _trigger = t; }
+ void setTimeframe(const QString& t) { _timeframe = t; }
+ void setVersion(const QString& v) { _version = v; }
+ void setPartNumber(int n);
+ void setThreadID(int t);
+ void setProcessID(int p);
+ TraceCost* totals() { return &_totals; }
+ /* we get owner of the submapping */
+ void setFixSubMapping(TraceSubMapping* sm) { _fixSubMapping = sm; }
+ TraceSubMapping* fixSubMapping() { return _fixSubMapping; }
+
+ // returns true if something changed
+ bool activate(bool);
+ bool isActive() { return _active; }
+
+private:
+ QFile* _file;
+ QString _name;
+ QString _descr;
+ QString _trigger;
+ QString _timeframe;
+ QString _version;
+
+ int _number, _tid, _pid;
+
+ bool _active;
+
+ // the totals line
+ TraceCost _totals;
+
+ // submapping for all fix costs of this part
+ TraceSubMapping* _fixSubMapping;
+};
+
+
+class TracePartList: public QPtrList<TracePart>
+{
+ public:
+ QString names() const;
+ protected:
+ int compareItems ( Item item1, Item item2 );
+};
+
+
+/*-----------------------------------------------------------------
+ * Classes for cost items summed up from multiple trace parts
+ *-----------------------------------------------------------------
+ */
+
+
+/**
+ * A jump from an instruction to another inside of a function
+ */
+class TraceInstrJump: public TraceJumpCost
+{
+public:
+ TraceInstrJump(TraceInstr* instrFrom, TraceInstr* instrTo,
+ bool isCondJump);
+ virtual ~TraceInstrJump();
+
+ virtual CostType type() const { return InstrJump; }
+ virtual QString name() const;
+
+ virtual void update();
+
+ TraceInstr* instrFrom() const { return _instrFrom; }
+ TraceInstr* instrTo() const { return _instrTo; }
+ bool isCondJump() const { return _isCondJump; }
+
+ // part factory
+ TracePartInstrJump* partInstrJump(TracePart*);
+
+ private:
+ TraceInstr *_instrFrom, *_instrTo;
+ bool _isCondJump;
+ // list of parts for this InstrJump
+ TracePartInstrJump* _first;
+};
+
+class TraceInstrJumpList: public QPtrList<TraceInstrJump>
+{
+ public:
+ TraceInstrJumpList() { _sortLow = true; }
+ void setSortLow(bool s) { _sortLow = s; }
+
+ protected:
+ int compareItems ( Item item1, Item item2 );
+
+ private:
+ bool _sortLow;
+};
+
+
+/**
+ * A jump from one line to another inside of a function.
+ */
+class TraceLineJump: public TraceJumpListCost
+{
+ public:
+ TraceLineJump(TraceLine* lineFrom, TraceLine* lineTo,
+ bool isCondJump);
+ virtual ~TraceLineJump();
+
+ virtual CostType type() const { return LineJump; }
+ virtual QString name() const;
+
+ TraceLine* lineFrom() const { return _lineFrom; }
+ TraceLine* lineTo() const { return _lineTo; }
+ bool isCondJump() { return _isCondJump; }
+
+ // part factory
+ TracePartLineJump* partLineJump(TracePart*);
+
+ protected:
+ bool onlyActiveParts() { return true; }
+
+ private:
+ TraceLine *_lineFrom, *_lineTo;
+ bool _isCondJump;
+};
+
+
+class TraceLineJumpList: public QPtrList<TraceLineJump>
+{
+ public:
+ TraceLineJumpList() { _sortLow = true; }
+ void setSortLow(bool s) { _sortLow = s; }
+
+ protected:
+ int compareItems ( Item item1, Item item2 );
+
+ private:
+ bool _sortLow;
+};
+
+
+/**
+ * A call from an instruction of one function to another function
+ */
+class TraceInstrCall: public TraceCallListCost
+{
+ public:
+ TraceInstrCall(TraceCall* call, TraceInstr* instr);
+ virtual ~TraceInstrCall();
+
+ virtual CostType type() const { return InstrCall; }
+ virtual QString name() const;
+
+ TraceInstr* instr() const { return _instr; }
+ TraceCall* call() const { return _call; }
+
+ // part factory
+ TracePartInstrCall* partInstrCall(TracePart*, TracePartCall*);
+
+ protected:
+ bool onlyActiveParts() { return true; }
+
+ private:
+ TraceInstr* _instr;
+ TraceCall* _call;
+};
+
+
+/**
+ * A call from a line of one function to another function.
+ */
+class TraceLineCall: public TraceCallListCost
+{
+ public:
+ TraceLineCall(TraceCall* call, TraceLine* line);
+ virtual ~TraceLineCall();
+
+ virtual CostType type() const { return LineCall; }
+ virtual QString name() const;
+
+ TraceLine* line() const { return _line; }
+ TraceCall* call() const { return _call; }
+
+ // part factory
+ TracePartLineCall* partLineCall(TracePart*, TracePartCall*);
+
+ protected:
+ bool onlyActiveParts() { return true; }
+
+ private:
+ TraceLine* _line;
+ TraceCall* _call;
+};
+
+
+/**
+ * A call from one to another function.
+ * Consists of a list a TraceLineCalls
+ */
+class TraceCall: public TraceCallListCost
+{
+ public:
+ TraceCall(TraceFunction* caller, TraceFunction* called);
+ virtual ~TraceCall();
+
+ virtual CostType type() const { return Call; }
+ virtual QString name() const;
+
+ // calls a function itself?
+ bool isRecursion() { return _caller == _called; }
+
+ // return cycle number >0 if call is inside of a cycle
+ int inCycle();
+ // we need some special handling for cycle calls
+ void update();
+
+ void invalidateDynamicCost();
+
+ // factories
+ TracePartCall* partCall(TracePart*,
+ TracePartFunction*, TracePartFunction*);
+ TraceLineCall* lineCall(TraceLine*);
+ TraceInstrCall* instrCall(TraceInstr*);
+
+ TraceFunction* caller(bool skipCycle=false) const;
+ TraceFunction* called(bool skipCycle=false) const;
+ QString callerName(bool skipCycle=false) const;
+ QString calledName(bool skipCycle=false) const;
+ const TraceLineCallList& lineCalls() const { return _lineCalls; }
+ const TraceInstrCallList& instrCalls() const { return _instrCalls; }
+
+ FixCallCost* setFirstFixCost(FixCallCost* fc)
+ { FixCallCost* t = _firstFixCost; _firstFixCost = fc; return t; }
+
+ protected:
+ bool onlyActiveParts() { return true; }
+
+ private:
+ TraceInstrCallList _instrCalls;
+ TraceLineCallList _lineCalls;
+ TraceFunction* _caller;
+ TraceFunction* _called;
+
+ FixCallCost* _firstFixCost;
+};
+
+
+/**
+ * A code instruction address of the program.
+ * Consists of a list a TracePartInstr from different trace files
+ * and a list of TraceInstrCalls if there are calls from this address.
+ */
+class TraceInstr: public TraceListCost
+{
+ public:
+ TraceInstr();
+ virtual ~TraceInstr();
+
+ virtual CostType type() const { return Instr; }
+ virtual QString name() const;
+ QString prettyName() const;
+
+ bool isValid() { return _addr != Addr(0); }
+
+ // factories
+ TracePartInstr* partInstr(TracePart* part,
+ TracePartFunction* partFunction);
+ TraceInstrJump* instrJump(TraceInstr* to, bool isCondJump);
+
+ void addInstrCall(TraceInstrCall*);
+
+ Addr addr() const { return _addr; }
+ TraceFunction* function() const { return _function; }
+ TraceLine* line() const { return _line; }
+ const TraceInstrJumpList& instrJumps() const { return _instrJumps; }
+ const TraceInstrCallList& instrCalls() const { return _instrCalls; }
+ bool hasCost(TraceCostType*);
+
+ // only to be called after default constructor
+ void setAddr(const Addr addr) { _addr = addr; }
+ void setFunction(TraceFunction* f) { _function = f; }
+ void setLine(TraceLine* l) { _line = l; }
+
+ protected:
+ bool onlyActiveParts() { return true; }
+
+ private:
+ Addr _addr;
+ TraceFunction* _function;
+ TraceLine* _line;
+
+ TraceInstrJumpList _instrJumps;
+ TraceInstrCallList _instrCalls;
+};
+
+
+/**
+ * A source line of the program.
+ * Consists of a list a TracePartLines from different trace files
+ * and a list of TraceLineCalls if there are calls from this line.
+ */
+class TraceLine: public TraceListCost
+{
+public:
+ TraceLine();
+ virtual ~TraceLine();
+
+ virtual CostType type() const { return Line; }
+ virtual QString name() const;
+ QString prettyName() const;
+
+ // factories
+ TracePartLine* partLine(TracePart* part,
+ TracePartFunction* partFunction);
+ TraceLineJump* lineJump(TraceLine* to, bool isCondJump);
+
+ void addLineCall(TraceLineCall*);
+
+
+ bool isValid() { return _sourceFile != 0; }
+ bool hasCost(TraceCostType*);
+ TraceFunctionSource* functionSource() const { return _sourceFile; }
+ uint lineno() const { return _lineno; }
+ const TraceLineCallList& lineCalls() const { return _lineCalls; }
+ const TraceLineJumpList& lineJumps() const { return _lineJumps; }
+
+ // only to be called after default constructor
+ void setSourceFile(TraceFunctionSource* sf) { _sourceFile = sf; }
+ void setLineno(uint lineno) { _lineno = lineno; }
+
+ protected:
+ bool onlyActiveParts() { return true; }
+
+ private:
+ TraceFunctionSource* _sourceFile;
+ uint _lineno;
+
+ TraceLineJumpList _lineJumps;
+ TraceLineCallList _lineCalls;
+};
+
+
+/*
+ * Base class for all costs which
+ * represent "interesting" items or group of items
+ * with settable name and inclusive cost
+ */
+class TraceCostItem: public TraceInclusiveListCost
+{
+ public:
+ TraceCostItem();
+ virtual ~TraceCostItem();
+
+ virtual QString name() const { return _name; }
+ virtual void setName(const QString& name) { _name = name; }
+
+ protected:
+ bool onlyActiveParts() { return true; }
+
+ protected:
+ QString _name;
+};
+
+
+/**
+ * Cost of a source region.
+ */
+class TraceLineRegion: public TraceInclusiveListCost
+{
+public:
+ TraceLineRegion(uint from, uint to, QString name);
+ virtual ~TraceLineRegion();
+
+ virtual CostType type() const { return LineRegion; }
+ virtual void update();
+
+ uint from() const { return _from; }
+ uint to() const { return _to; }
+ QString name() const { return _name; }
+
+ // factories
+ TracePartLine* partLineRegion(TracePart* part,
+ TracePartFunction* partFunction);
+ private:
+ uint _from, _to;
+ QString _name;
+};
+
+
+/**
+ * A container helper class for TraceFunction for source lines
+ * where a function is implemented in.
+ * With inlining, lines of the same function can come from
+ * different source files.
+ * An instance of this class holds all lines of one source file
+ * for a function in a map
+ */
+class TraceFunctionSource: public TraceCost
+{
+public:
+ TraceFunctionSource(TraceFunction*, TraceFile*);
+ virtual ~TraceFunctionSource();
+
+ virtual CostType type() const { return FunctionSource; }
+ virtual QString name() const;
+
+ // reimplementation for dependency map
+ virtual void update();
+
+ TraceFile* file() const { return _file; }
+ TraceFunction* function() const { return _function; }
+ uint firstLineno();
+ uint lastLineno();
+ TraceLineMap* lineMap();
+
+ void invalidateDynamicCost();
+
+ /* factories */
+ TraceLine* line(uint lineno, bool createNew = true);
+ TraceLineRegion* region(uint from, uint to, QString name,
+ bool createNew = true);
+
+ private:
+ TraceFile* _file;
+ TraceFunction* _function;
+ TraceLineMap* _lineMap;
+ TraceLine* _line0;
+ TraceLineRegionList* _regions;
+
+ bool _lineMapFilled;
+};
+
+
+/**
+ * For temporary assoziation of objects with TraceFunctions.
+ * Used in coverage analysis and TreeMap drawing.
+ */
+class TraceAssoziation
+{
+ public:
+ /**
+ * Creates an invalid assoziation.
+ */
+ TraceAssoziation();
+ virtual ~TraceAssoziation();
+
+ // for runtime detection
+ virtual int rtti() { return 0; }
+
+ /**
+ * Could we set the function assoziation to ourself?
+ * This only can return false if this is a unique assoziation.
+ */
+ bool isAssoziated();
+
+ /**
+ * reset function to assoziate this object to.
+ * returns true if assoziation could be established
+ */
+ bool setFunction(TraceFunction*);
+ TraceFunction* function() { return _function; }
+
+ void invalidate() { _valid = false; }
+ bool isValid() { return _valid; }
+
+ /**
+ * Delete all assoziations in TraceFunctions of data with
+ * rtti runtime info. rtti = 0: delete ALL assoziations.
+ */
+ static void clear(TraceData* data, int rtti);
+
+ /**
+ * Invalidate all assoziations in TraceFunctions of data with
+ * rtti runtime info. rtti = 0: Invalidate ALL assoziations.
+ */
+ static void invalidate(TraceData* data, int rtti);
+
+ protected:
+ TraceFunction* _function;
+ bool _valid;
+};
+
+typedef QPtrList<TraceAssoziation> TraceAssoziationList;
+typedef QMap<TraceFunction*, TraceCall*> TraceCallMap;
+
+/**
+ * A traced function
+ *
+ * References to functions are stored in
+ * (1) a function map in TraceData (by value)
+ * (2) a TraceClass
+ */
+class TraceFunction: public TraceCostItem
+{
+ public:
+ TraceFunction();
+ TraceFunction(TraceData* data, const QString& name,
+ TraceClass* cls, TraceFile* file, TraceObject* object);
+ virtual ~TraceFunction();
+
+ virtual CostType type() const { return Function; }
+ virtual void update();
+
+ // this invalidate all subcosts of function depending on
+ // active status of parts
+ void invalidateDynamicCost();
+
+ void addCaller(TraceCall*);
+
+ // factories
+ TraceCall* calling(TraceFunction* called);
+ TraceLine* line(TraceFile*, uint lineno, bool createNew = true);
+ TraceInstr* instr(Addr addr, bool createNew = true);
+ TracePartFunction* partFunction(TracePart*,
+ TracePartFile*, TracePartObject*);
+
+ /**
+ * Returns empty string if location is fully unknown.
+ * Use prettyLocation for single user-visible string.
+ * A function can have a lot of code from different sources (inlined);
+ * maxItems limits this list. Default is full list
+ */
+ QString location(int maxFiles = 0) const;
+
+ QString prettyName() const;
+ QString prettyLocation(int maxFiles = 0) const;
+ QString prettyNameWithLocation(int maxFiles = 1) const;
+ void addPrettyLocation(QString&, int maxFiles = 1) const;
+ // type + name + location
+ QString info() const;
+
+ TraceClass* cls() const { return _cls; }
+ TraceFile* file() const { return _file; }
+ TraceObject* object() const { return _object; }
+ // get the source file with lines from function declaration (not inlined)
+ TraceFunctionSource* sourceFile(TraceFile* file = 0,
+ bool createNew = false);
+ const TraceFunctionSourceList& sourceFiles() const
+ { return _sourceFiles; }
+ TraceCallList callers(bool skipCycle=false) const;
+ const TraceCallList& callings(bool skipCycle=false) const;
+
+ Addr firstAddress() const;
+ Addr lastAddress() const;
+ TraceInstrMap* instrMap();
+
+ // cost metrics
+ SubCost calledCount();
+ SubCost callingCount();
+ QString prettyCalledCount();
+ QString prettyCallingCount();
+ int calledContexts();
+ int callingContexts();
+
+ // only to be called after default constructor
+ void setFile(TraceFile* file) { _file = file; }
+ void setObject(TraceObject* object) { _object = object; }
+ void setClass(TraceClass* cls) { _cls = cls; }
+ void setMapIterator(TraceFunctionMap::Iterator it) { _myMapIterator = it; }
+
+ // see TraceFunctionAssoziation
+ void addAssoziation(TraceAssoziation* a);
+ void removeAssoziation(TraceAssoziation* a);
+ void removeAssoziation(int rtti, bool reallyDelete = true);
+ void invalidateAssoziation(int rtti);
+ TraceAssoziation* assoziation(int rtti);
+
+ // cycles
+ void setCycle(TraceFunctionCycle* c) { _cycle = c; }
+ TraceFunctionCycle* cycle() { return _cycle; }
+ bool isCycle();
+ bool isCycleMember();
+ void cycleReset();
+ void cycleDFS(int d, int& pNo, TraceFunction** pTop);
+
+ protected:
+ TraceCallList _callers; // list of calls we are called from
+ TraceCallList _callings; // list of calls we are calling (we are owner)
+ TraceCallMap _callingMap; // contains the same as _callings in a map
+ TraceFunctionCycle* _cycle;
+
+ private:
+ bool isUniquePrefix(QString) const;
+ TraceFunctionMap::Iterator _myMapIterator;
+
+ TraceClass* _cls;
+ TraceObject* _object;
+ TraceFile* _file;
+
+ TraceFunctionSourceList _sourceFiles; // we are owner
+ TraceInstrMap* _instrMap; // we are owner
+ bool _instrMapFilled;
+
+ // see TraceAssoziation
+ TraceAssoziationList _assoziations;
+
+ // for cycle detection
+ int _cycleLow;
+ TraceFunction* _cycleStackDown;
+
+ // cached
+ SubCost _calledCount, _callingCount;
+ int _calledContexts, _callingContexts;
+};
+
+typedef QMap<TraceFunction*,int> TraceFunctionSet;
+
+/**
+ * A cycle of recursive calling functions.
+ *
+ * This is itself shown as a function
+ */
+class TraceFunctionCycle: public TraceFunction
+{
+ public:
+ TraceFunctionCycle(TraceFunction*, int n);
+
+ virtual CostType type() const { return FunctionCycle; }
+
+ // this removes all members from this cycle
+ void init();
+ void add(TraceFunction*);
+ // this sets up the cycle once members are added
+ void setup();
+
+ TraceFunction* base() const { return _base; }
+ int cycleNo() const { return _cycleNo; }
+ const TraceFunctionList& members() const { return _members; }
+
+ private:
+ TraceFunction* _base;
+ int _cycleNo;
+
+ TraceFunctionList _members;
+ TraceFunctionSet _memberSet;
+};
+
+
+/**
+ * A C++ Class / Namespace
+ *
+ * If a function symbol has a prefix ending in "::",
+ * the prefix is supposed to be a class/namespace specifier.
+ * Without such a prefix, we put a symbol in the "(global)" namespace.
+ */
+class TraceClass: public TraceCostItem
+{
+ public:
+ TraceClass();
+ virtual ~TraceClass();
+
+ virtual CostType type() const { return Class; }
+ virtual QString prettyName() const;
+
+ void addFunction(TraceFunction*);
+ const TraceFunctionList& functions() const { return _functions; }
+
+ // part factory
+ TracePartClass* partClass(TracePart*);
+
+ private:
+ TraceFunctionList _functions;
+};
+
+
+
+/**
+ * A source file containing function definitions
+ */
+class TraceFile: public TraceCostItem
+{
+ public:
+ TraceFile();
+ virtual ~TraceFile();
+
+ virtual CostType type() const { return File; }
+ void setDirectory(const QString& dir);
+ void resetDirectory() { _dir = QString::null; }
+ QString directory();
+
+ void addFunction(TraceFunction*);
+ void addSourceFile(TraceFunctionSource*);
+
+ // without path
+ QString shortName() const;
+ QString prettyName() const;
+ QString prettyLongName() const;
+ const TraceFunctionList& functions() const { return _functions; }
+ const TraceFunctionSourceList& sourceFiles() const
+ { return _sourceFiles; }
+
+ // part factory
+ TracePartFile* partFile(TracePart*);
+
+ private:
+ TraceFunctionList _functions;
+ TraceFunctionSourceList _sourceFiles;
+ QString _dir;
+};
+
+
+/**
+ * A object containing a text segment (shared lib/executable)
+ * with defined functions
+ */
+class TraceObject: public TraceCostItem
+{
+ public:
+ TraceObject();
+ virtual ~TraceObject();
+
+ virtual CostType type() const { return Object; }
+
+ void addFunction(TraceFunction*);
+
+ virtual void setName(const QString& name);
+ QString shortName() const { return _shortName; }
+ QString prettyName() const;
+ const TraceFunctionList& functions() const { return _functions; }
+
+ // part factory
+ TracePartObject* partObject(TracePart*);
+
+ private:
+ TraceFunctionList _functions;
+ QString _shortName;
+};
+
+
+
+/**
+ * This class holds profiling data of multiple tracefiles
+ * generated with cachegrind on one command.
+ *
+ */
+class TraceData: public TraceCost
+{
+ public:
+ TraceData(TopLevel* top = 0);
+ TraceData(const QString& base);
+ virtual ~TraceData();
+
+ virtual CostType type() const { return Data; }
+ virtual TraceData* data() { return this; }
+ virtual const TraceData* data() const { return this; }
+
+ /**
+ * Loads a trace file.
+ *
+ * This adjusts the TraceCostMapping according to given cost types
+ */
+ void load(const QString&);
+
+ /** returns true if something changed. These do NOT
+ * invalidate the dynamic costs on a activation change,
+ * i.e. all cost items dependend on active parts.
+ * This has to be done by the caller when true is returned by
+ * calling invalidateDynamicCost().
+ */
+ bool activateParts(const TracePartList&);
+ bool activateParts(TracePartList, bool active);
+ bool activatePart(TracePart*, bool active);
+ bool activateAll(bool active=true);
+
+ TracePartList parts() const { return _parts; }
+ TracePart* part(QString& name);
+
+ // with path
+ QString traceName() const { return _traceName; }
+
+ // without path
+ QString shortTraceName() const;
+ QString activePartRange();
+
+ TraceCostMapping* mapping() { return &_mapping; }
+
+ // memory pools
+ FixPool* fixPool();
+ DynPool* dynPool();
+
+ // factories for object/file/class/function/line instances
+ TraceObject* object(const QString& name);
+ TraceFile* file(const QString& name);
+ TraceClass* cls(const QString& fnName, QString& shortName);
+ // function creation involves class creation if needed
+ TraceFunction* function(const QString& name, TraceFile*, TraceObject*);
+ // factory for function cycles
+ TraceFunctionCycle* functionCycle(TraceFunction*);
+
+ /**
+ * Search for item with given name and highest subcost of given cost type.
+ *
+ * For some items, they will only be found if the parent cost is given:
+ * Instr, Line, Call => need parent of type Function
+ * For Function, a parent of type Obj/File/Class can be given, but
+ * isn't needed.
+ */
+ TraceCost* search(TraceItem::CostType, QString,
+ TraceCostType* ct = 0, TraceCost* parent = 0);
+
+ // for pretty function names without signature if unique...
+ TraceFunctionMap::Iterator functionIterator(TraceFunction*);
+ TraceFunctionMap::ConstIterator functionBeginIterator() const;
+ TraceFunctionMap::ConstIterator functionEndIterator() const;
+
+ TraceObjectMap& objectMap() { return _objectMap; }
+ TraceFileMap& fileMap() { return _fileMap; }
+ TraceClassMap& classMap() { return _classMap; }
+ TraceFunctionMap& functionMap() { return _functionMap; }
+
+ const TraceFunctionCycleList& functionCycles() { return _functionCycles; }
+
+ TraceCost* callMax() { return &_callMax; }
+
+ void setCommand(const QString& command) { _command = command; }
+ QString command() const { return _command; }
+ TraceCost* totals() { return &_totals; }
+ void setMaxThreadID(int tid) { _maxThreadID = tid; }
+ int maxThreadID() const { return _maxThreadID; }
+ void setMaxPartNumber(int n) { _maxPartNumber = n; }
+ int maxPartNumber() const { return _maxPartNumber; }
+
+ // reset all manually set directories for source files
+ void resetSourceDirs();
+
+ virtual void update();
+
+ // invalidates all cost items dependant on active state of parts
+ void invalidateDynamicCost();
+
+ // cycle detection
+ void updateFunctionCycles();
+ void updateObjectCycles();
+ void updateClassCycles();
+ void updateFileCycles();
+ bool inFunctionCycleUpdate() { return _inFunctionCycleUpdate; }
+
+ private:
+ void init();
+ // add trace part: events from one trace file
+ TracePart* addPart(const QString& dir, const QString& file);
+
+ // for progress bar callbacks
+ TopLevel* _topLevel;
+
+ TracePartList _parts;
+
+ // The mapping for all costs
+ TraceCostMapping _mapping;
+
+ FixPool* _fixPool;
+ DynPool* _dynPool;
+
+ // always the trace totals (not dependent on active parts)
+ TraceCost _totals;
+ int _maxThreadID;
+ int _maxPartNumber;
+
+ TraceObjectMap _objectMap;
+ TraceClassMap _classMap;
+ TraceFileMap _fileMap;
+ TraceFunctionMap _functionMap;
+ QString _command;
+ QString _traceName;
+
+ // Max of all costs of calls: This allows to see if the incl. cost can
+ // be hidden for a cost type, as it's always the same as self cost
+ TraceCost _callMax;
+
+ // cycles
+ TraceFunctionCycleList _functionCycles;
+ int _functionCycleCount;
+ bool _inFunctionCycleUpdate;
+};
+
+
+
+#endif
diff --git a/kcachegrind/kcachegrind/traceitemview.cpp b/kcachegrind/kcachegrind/traceitemview.cpp
new file mode 100644
index 00000000..8ee2faac
--- /dev/null
+++ b/kcachegrind/kcachegrind/traceitemview.cpp
@@ -0,0 +1,443 @@
+/* This file is part of KCachegrind.
+ Copyright (C) 2003 Josef Weidendorfer <Josef.Weidendorfer@gmx.de>
+
+ KCachegrind is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public
+ License as published by the Free Software Foundation, version 2.
+
+ 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; see the file COPYING. If not, write to
+ the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+*/
+
+/*
+ * Trace Item View
+ */
+
+#include <qwidget.h>
+#include <kconfig.h>
+#include <klocale.h>
+#include <kdebug.h>
+
+#include "traceitemview.h"
+#include "toplevel.h"
+
+#define TRACE_UPDATES 0
+
+TraceItemView::TraceItemView(TraceItemView* parentView, TopLevel* top)
+{
+ _parentView = parentView;
+ _topLevel = top ? top : parentView->topLevel();
+
+ _data = _newData = 0;
+ // _partList and _newPartList is empty
+ _activeItem = _newActiveItem = 0;
+ _selectedItem = _newSelectedItem = 0;
+ _costType = _newCostType = 0;
+ _costType2 = _newCostType2 = 0;
+ _groupType = _newGroupType = TraceItem::NoCostType;
+
+ _status = nothingChanged;
+ _inUpdate = false;
+ _pos = Hidden;
+}
+
+QString TraceItemView::whatsThis() const
+{
+ return i18n("No description available");
+}
+
+void TraceItemView::select(TraceItem* i)
+{
+ _newSelectedItem = i;
+}
+
+KConfigGroup* TraceItemView::configGroup(KConfig* c,
+ QString group, QString post)
+{
+ QStringList gList = c->groupList();
+ if (gList.contains((group+post).ascii()) ) group += post;
+ return new KConfigGroup(c, group);
+}
+
+void TraceItemView::writeConfigEntry(KConfigBase* c, const char* pKey,
+ QString value, const char* def, bool bNLS)
+{
+ if (!c) return;
+ if ((value.isEmpty() && ((def == 0) || (*def == 0))) ||
+ (value == QString(def)))
+ c->deleteEntry(pKey);
+ else
+ c->writeEntry(pKey, value, true, false, bNLS);
+}
+
+void TraceItemView::writeConfigEntry(KConfigBase* c, const char* pKey,
+ int value, int def)
+{
+ if (!c) return;
+ if (value == def)
+ c->deleteEntry(pKey);
+ else
+ c->writeEntry(pKey, value);
+}
+
+void TraceItemView::writeConfigEntry(KConfigBase* c, const char* pKey,
+ double value, double def)
+{
+ if (!c) return;
+ if (value == def)
+ c->deleteEntry(pKey);
+ else
+ c->writeEntry(pKey, value);
+}
+
+void TraceItemView::writeConfigEntry(KConfigBase* c, const char* pKey,
+ bool value, bool def)
+{
+ if (!c) return;
+ if (value == def)
+ c->deleteEntry(pKey);
+ else
+ c->writeEntry(pKey, value);
+}
+
+void TraceItemView::readViewConfig(KConfig*, QString, QString, bool)
+{}
+
+#if 1
+void TraceItemView::saveViewConfig(KConfig*, QString, QString, bool)
+{}
+#else
+void TraceItemView::saveViewConfig(KConfig* c,
+ QString prefix, QString postfix, bool)
+{
+ // write a dummy config entry to see missing virtual functions
+ KConfigGroup g(c, (prefix+postfix).ascii());
+ g.writeEntry("SaveNotImplemented", true);
+}
+#endif
+
+bool TraceItemView::activate(TraceItem* i)
+{
+ i = canShow(i);
+ _newActiveItem = i;
+
+ return (i != 0);
+}
+
+TraceFunction* TraceItemView::activeFunction()
+{
+ TraceItem::CostType t = _activeItem->type();
+ switch(t) {
+ case TraceItem::Function:
+ case TraceItem::FunctionCycle:
+ return (TraceFunction*) _activeItem;
+ default:
+ break;
+ }
+ return 0;
+}
+
+bool TraceItemView::set(int changeType, TraceData* d,
+ TraceCostType* t1, TraceCostType* t2,
+ TraceItem::CostType g, const TracePartList& l,
+ TraceItem* a, TraceItem* s)
+{
+ _status |= changeType;
+ _newData = d;
+ _newGroupType = g;
+ _newCostType = t1;
+ _newCostType2 = t2;
+ _newPartList = l;
+ _newSelectedItem = s;
+ _newActiveItem = canShow(a);
+ if (!_newActiveItem) {
+ _newSelectedItem = 0;
+ return false;
+ }
+
+ return true;
+}
+
+
+bool TraceItemView::isViewVisible()
+{
+ QWidget* w = widget();
+ if (w)
+ return w->isVisible();
+ return false;
+}
+
+void TraceItemView::setData(TraceData* d)
+{
+ _newData = d;
+
+ // invalidate all pointers to old data
+ _activeItem = _newActiveItem = 0;
+ _selectedItem = _newSelectedItem = 0;
+ _costType = _newCostType = 0;
+ _costType2 = _newCostType2 = 0;
+ _groupType = _newGroupType = TraceItem::NoCostType;
+ _partList.clear();
+ _newPartList.clear();
+
+ // updateView will change this to dataChanged
+ _status = nothingChanged;
+}
+
+void TraceItemView::updateView(bool force)
+{
+ if (!force && !isViewVisible()) return;
+
+ if (_newData != _data) {
+ _status |= dataChanged;
+ _data = _newData;
+ }
+ else {
+ _status &= ~dataChanged;
+
+ // if there's no data change and data is 0, no update needed
+ if (!_data) return;
+ }
+
+ if (!(_newPartList == _partList)) {
+ _status |= partsChanged;
+ _partList = _newPartList;
+ }
+ else
+ _status &= ~partsChanged;
+
+ if (_newActiveItem != _activeItem) {
+
+ // when setting a new active item, there's no selection
+ _selectedItem = 0;
+
+ _status |= activeItemChanged;
+ _activeItem = _newActiveItem;
+ }
+ else
+ _status &= ~activeItemChanged;
+
+ if (_newCostType != _costType) {
+ _status |= costTypeChanged;
+ _costType = _newCostType;
+ }
+ else
+ _status &= ~costTypeChanged;
+
+ if (_newCostType2 != _costType2) {
+ _status |= costType2Changed;
+ _costType2 = _newCostType2;
+ }
+ else
+ _status &= ~costType2Changed;
+
+ if (_newGroupType != _groupType) {
+ _status |= groupTypeChanged;
+ _groupType = _newGroupType;
+ }
+ else
+ _status &= ~groupTypeChanged;
+
+
+ if (_newSelectedItem != _selectedItem) {
+ _status |= selectedItemChanged;
+ _selectedItem = _newSelectedItem;
+ }
+ else
+ _status &= ~selectedItemChanged;
+
+
+ if (!force && (_status == nothingChanged)) return;
+
+#if TRACE_UPDATES
+ kdDebug() << (widget() ? widget()->name() : "TraceItemView")
+ << "::doUpdate ( "
+ << ((_status & dataChanged) ? "data ":"")
+ << ((_status & configChanged) ? "config ":"")
+ << ")" << endl;
+
+ if (_status & partsChanged)
+ kdDebug() << " Part List "
+ << _partList.names()
+ << endl;
+
+ if (_status & costTypeChanged)
+ kdDebug() << " Cost type "
+ << (_costType ? _costType->name().ascii() : "?")
+ << endl;
+
+ if (_status & costType2Changed)
+ kdDebug() << " Cost type 2 "
+ << (_costType2 ? _costType2->name().ascii() : "?")
+ << endl;
+
+ if (_status & groupTypeChanged)
+ kdDebug() << " Group type "
+ << TraceItem::typeName(_groupType)
+ << endl;
+
+ if (_status & activeItemChanged)
+ kdDebug() << " Active: "
+ << (_activeItem ? _activeItem->fullName().ascii() : "?")
+ << endl;
+
+ if (_status & selectedItemChanged)
+ kdDebug() << " Selected: "
+ << (_selectedItem ? _selectedItem->fullName().ascii() : "?")
+ << endl;
+#endif
+
+ int st = _status;
+ _status = nothingChanged;
+ doUpdate(st);
+ return;
+
+ if (_inUpdate) return;
+ _inUpdate = true;
+ doUpdate(_status);
+ _inUpdate = false;
+}
+
+
+void TraceItemView::selected(TraceItemView* /*sender*/, TraceItem* i)
+{
+#if TRACE_UPDATES
+ kdDebug() << (widget() ? widget()->name() : "TraceItemView")
+ << "::selected "
+ << (i ? i->name().ascii(): "(nil)")
+ << ", sender "
+ << sender->widget()->name() << endl;
+#endif
+
+ if (_parentView) _parentView->selected(this, i);
+}
+
+void TraceItemView::selected(TraceItemView* /*sender*/, const TracePartList& l)
+{
+#if TRACE_UPDATES
+ kdDebug() << (widget() ? widget()->name() : "TraceItemView")
+ << "::selected "
+ << l.names()
+ << ", sender "
+ << sender->widget()->name() << endl;
+#endif
+
+ if (_parentView)
+ _parentView->selected(this, l);
+ else
+ if (_topLevel) _topLevel->activePartsChangedSlot(l);
+}
+
+void TraceItemView::activated(TraceItemView* /*sender*/, TraceItem* i)
+{
+#if TRACE_UPDATES
+ kdDebug() << (widget() ? widget()->name() : "TraceItemView")
+ << "::activated "
+ << (i ? i->name().ascii(): "(nil)")
+ << ", sender "
+ << sender->widget()->name() << endl;
+#endif
+
+ if (_parentView)
+ _parentView->activated(this, i);
+ else
+ if (_topLevel) _topLevel->setTraceItemDelayed(i);
+}
+
+void TraceItemView::selectedCostType(TraceItemView*, TraceCostType* t)
+{
+ if (_parentView)
+ _parentView->selectedCostType(this, t);
+ else
+ if (_topLevel) _topLevel->setCostTypeDelayed(t);
+}
+
+void TraceItemView::selectedCostType2(TraceItemView*, TraceCostType* t)
+{
+ if (_parentView)
+ _parentView->selectedCostType2(this, t);
+ else
+ if (_topLevel) _topLevel->setCostType2Delayed(t);
+}
+
+void TraceItemView::activated(TraceItemView*, Direction d)
+{
+ if (_parentView)
+ _parentView->activated(this, d);
+ else
+ if (_topLevel) _topLevel->setDirectionDelayed(d);
+}
+
+void TraceItemView::doUpdate(int)
+{
+}
+
+void TraceItemView::selected(TraceItem* i)
+{
+ if (_parentView)
+ _parentView->selected(this, i);
+
+}
+
+void TraceItemView::selected(const TracePartList& l)
+{
+ if (_parentView)
+ _parentView->selected(this, l);
+ else
+ if (_topLevel) _topLevel->activePartsChangedSlot(l);
+}
+
+void TraceItemView::activated(TraceItem* i)
+{
+#if TRACE_UPDATES
+ kdDebug() << (widget() ? widget()->name() : "TraceItemView")
+ << "::activated "
+ << (i ? i->name().ascii(): "(nil)") << endl;
+#endif
+
+ if (_parentView)
+ _parentView->activated(this, i);
+ else
+ if (_topLevel) _topLevel->setTraceItemDelayed(i);
+}
+
+void TraceItemView::selectedCostType(TraceCostType* t)
+{
+ if (_parentView)
+ _parentView->selectedCostType(this, t);
+ else
+ if (_topLevel) _topLevel->setCostTypeDelayed(t);
+}
+
+void TraceItemView::selectedCostType2(TraceCostType* t)
+{
+ if (_parentView)
+ _parentView->selectedCostType2(this, t);
+ else
+ if (_topLevel) _topLevel->setCostType2Delayed(t);
+}
+
+void TraceItemView::activated(Direction d)
+{
+ if (_parentView)
+ _parentView->activated(this, d);
+ else
+ if (_topLevel) _topLevel->setDirectionDelayed(d);
+}
+
+void TraceItemView::addCostMenu(QPopupMenu* p, bool withCost2)
+{
+ if (_topLevel) _topLevel->addCostMenu(p, withCost2);
+}
+
+void TraceItemView::addGoMenu(QPopupMenu* p)
+{
+ if (_topLevel) _topLevel->addGoMenu(p);
+}
diff --git a/kcachegrind/kcachegrind/traceitemview.h b/kcachegrind/kcachegrind/traceitemview.h
new file mode 100644
index 00000000..e74a009c
--- /dev/null
+++ b/kcachegrind/kcachegrind/traceitemview.h
@@ -0,0 +1,206 @@
+/* This file is part of KCachegrind.
+ Copyright (C) 2003 Josef Weidendorfer <Josef.Weidendorfer@gmx.de>
+
+ KCachegrind is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public
+ License as published by the Free Software Foundation, version 2.
+
+ 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; see the file COPYING. If not, write to
+ the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+*/
+
+/*
+ * Trace Item View
+ */
+
+#ifndef TRACEITEMVIEW_H
+#define TRACEITEMVIEW_H
+
+#include "tracedata.h"
+
+class QWidget;
+class QPopupMenu;
+
+class KConfig;
+class KConfigGroup;
+class KConfigBase;
+
+class TopLevel;
+
+/**
+ * Abstract Base Class for KCachegrind Views
+ *
+ * This class delivers the shared functionality of all KCachegrind
+ * Views for one TraceItem (like Function, Object...), the "active"
+ * item. Additional view attributes are current primary cost type,
+ * an optional secondary cost type, group type,
+ * and possibly a selected costitem in this view.
+ * Note that there is a difference in changing the selected item of
+ * a view (this usually changes selection in other views, too), and
+ * activating that item.
+ */
+class TraceItemView
+{
+public:
+
+ /**
+ * Change type for update functions
+ * - <dataChanged> is used if e.g. cycles are recalculated
+ */
+ enum { nothingChanged = 0,
+ costTypeChanged = 1,
+ costType2Changed = 2,
+ groupTypeChanged = 4,
+ partsChanged = 8,
+ activeItemChanged = 16,
+ selectedItemChanged = 32,
+ dataChanged = 64,
+ configChanged = 128 };
+
+ enum Direction { None, Back, Forward, Up };
+
+ // a TraceItemView can have a position in a parent container
+ enum Position { Hidden, Top, Right, Left, Bottom };
+
+ TraceItemView(TraceItemView* parentView, TopLevel* top = 0);
+ virtual ~TraceItemView() {}
+
+ virtual QString whatsThis() const;
+
+ static KConfigGroup* configGroup(KConfig*, QString prefix, QString postfix);
+ static void writeConfigEntry(KConfigBase*, const char* pKey, QString value,
+ const char* def, bool bNLS = false);
+ static void writeConfigEntry(KConfigBase*, const char* pKey,
+ int value, int def);
+ static void writeConfigEntry(KConfigBase*, const char* pKey,
+ bool value, bool def);
+ static void writeConfigEntry(KConfigBase*, const char* pKey,
+ double value, double def);
+ virtual void readViewConfig(KConfig*, QString prefix, QString postfix,
+ bool withOptions);
+ virtual void saveViewConfig(KConfig*, QString prefix, QString postfix,
+ bool withOptions);
+
+ // Immediate remove all references to old data, and set the new.
+ // This resets the visualization state.
+ // A GUI update has to be triggered with updateView().
+ // Overwrite in container views to also set new data for all members.
+ virtual void setData(TraceData* d);
+
+ // change from parent, call updateView() to update lazily (only if visible)
+ void setCostType(TraceCostType* t) { _newCostType = t; }
+ void setCostType2(TraceCostType* t) { _newCostType2 = t; }
+ void set(TraceItem::CostType g) { _newGroupType = g; }
+ void set(const TracePartList& l) { _newPartList = l; }
+ // returns false if nothing can be shown for this trace item
+ bool activate(TraceItem* i);
+ void select(TraceItem* i);
+ void notifyChange(int changeType) { _status |= changeType; }
+ // all in one
+ bool set(int, TraceData*, TraceCostType*, TraceCostType*,
+ TraceItem::CostType, const TracePartList&,
+ TraceItem*, TraceItem*);
+
+ // general update request, call if view is/gets visible
+ void updateView(bool force = false);
+
+ /**
+ * Notification from child views.
+ * Default implementation notifies parent
+ */
+ virtual void selected(TraceItemView* sender, TraceItem*);
+ virtual void selected(TraceItemView* sender, const TracePartList&);
+ virtual void activated(TraceItemView* sender, Direction);
+ virtual void selectedCostType(TraceItemView* sender, TraceCostType*);
+ virtual void selectedCostType2(TraceItemView* sender, TraceCostType*);
+ virtual void activated(TraceItemView* sender, TraceItem*);
+
+ // getters...
+ // always get the newest values
+ TraceData* data() const { return _newData; }
+ TraceItem* activeItem() const { return _newActiveItem; }
+ TraceItem* selectedItem() const { return _newSelectedItem; }
+ TraceCostType* costType() const { return _newCostType; }
+ TraceCostType* costType2() const { return _newCostType2; }
+ TraceItem::CostType groupType() const { return _newGroupType; }
+ const TracePartList& partList() const { return _newPartList; }
+
+ TraceFunction* activeFunction();
+ int status() const { return _status; }
+
+ // pointer to top level window to e.g. show status messages
+ void setTopLevel(TopLevel* t) { _topLevel = t; }
+ TopLevel* topLevel() const { return _topLevel; }
+
+ void setPosition(Position p) { _pos = p; }
+ Position position() const { return _pos; }
+
+ void setTitle(QString t) { _title = t; }
+ QString title() const { return _title; }
+
+ // We depend on derived class to be a widget.
+ // Force overiding by making this abstract.
+ virtual QWidget* widget() = 0;
+
+ /**
+ * This function is called when a new item should become active.
+ * Reimplement this in subclasses.
+ *
+ * Returns the real item to become active. You can call select() here.
+ * Return 0 if nothing can be shown.
+ * Use the methods like data() instead of _data here, as
+ * _data possibly will give old/wrong information.
+ */
+ virtual TraceItem* canShow(TraceItem* i) { return i; }
+
+ /* convenience functions for often used context menu items */
+ void addCostMenu(QPopupMenu*,bool withCost2 = true);
+ void addGoMenu(QPopupMenu*);
+
+protected:
+ // helpers to call selected()/activated() of parentView
+ void selected(TraceItem*);
+ void selected(const TracePartList&);
+ void activated(TraceItem*);
+ void selectedCostType(TraceCostType*);
+ void selectedCostType2(TraceCostType*);
+ void activated(Direction);
+
+ /* Is this view visible?
+ * if not, doUpdate() won't be called by updateView()
+ */
+ virtual bool isViewVisible();
+
+ // update handler (to be reimplemented)
+ virtual void doUpdate(int changeType);
+
+ TraceItemView* _parentView;
+ TopLevel* _topLevel;
+
+ TraceData* _data;
+ TracePartList _partList;
+ TraceItem *_activeItem, *_selectedItem;
+ TraceCostType *_costType, *_costType2;
+ TraceItem::CostType _groupType;
+
+private:
+ TraceData* _newData;
+ TracePartList _newPartList;
+ TraceItem *_newActiveItem, *_newSelectedItem;
+ TraceCostType *_newCostType, *_newCostType2;
+ TraceItem::CostType _newGroupType;
+
+ QString _title;
+ int _status;
+ bool _inUpdate;
+ Position _pos;
+};
+
+#endif
diff --git a/kcachegrind/kcachegrind/treemap.cpp b/kcachegrind/kcachegrind/treemap.cpp
new file mode 100644
index 00000000..3ccc34f9
--- /dev/null
+++ b/kcachegrind/kcachegrind/treemap.cpp
@@ -0,0 +1,3214 @@
+/* This file is part of KCachegrind.
+ Copyright (C) 2002, 2003 Josef Weidendorfer <Josef.Weidendorfer@gmx.de>
+
+ KCachegrind is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public
+ License as published by the Free Software Foundation, version 2.
+
+ 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; see the file COPYING. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+/*
+ * A Widget for visualizing hierarchical metrics as areas.
+ * The API is similar to QListView.
+ */
+
+#include <math.h>
+
+#include <qpainter.h>
+#include <qtooltip.h>
+#include <qregexp.h>
+#include <qstyle.h>
+#include <qpopupmenu.h>
+
+#include <klocale.h>
+#include <kconfig.h>
+#include <kdebug.h>
+
+#include "treemap.h"
+
+
+// set this to 1 to enable debug output
+#define DEBUG_DRAWING 0
+#define MAX_FIELD 12
+
+
+//
+// StoredDrawParams
+//
+StoredDrawParams::StoredDrawParams()
+{
+ _selected = false;
+ _current = false;
+ _shaded = true;
+ _rotated = false;
+
+ _backColor = Qt::white;
+
+ // field array has size 0
+}
+
+StoredDrawParams::StoredDrawParams(QColor c,
+ bool selected, bool current)
+{
+ _backColor = c;
+
+ _selected = selected;
+ _current = current;
+ _shaded = true;
+ _rotated = false;
+ _drawFrame = true;
+
+ // field array has size 0
+}
+
+QString StoredDrawParams::text(int f) const
+{
+ if ((f<0) || (f >= (int)_field.size()))
+ return QString::null;
+
+ return _field[f].text;
+}
+
+QPixmap StoredDrawParams::pixmap(int f) const
+{
+ if ((f<0) || (f >= (int)_field.size()))
+ return QPixmap();
+
+ return _field[f].pix;
+}
+
+DrawParams::Position StoredDrawParams::position(int f) const
+{
+ if ((f<0) || (f >= (int)_field.size()))
+ return Default;
+
+ return _field[f].pos;
+}
+
+int StoredDrawParams::maxLines(int f) const
+{
+ if ((f<0) || (f >= (int)_field.size()))
+ return 0;
+
+ return _field[f].maxLines;
+}
+
+const QFont& StoredDrawParams::font() const
+{
+ static QFont* f = 0;
+ if (!f) f = new QFont(QApplication::font());
+
+ return *f;
+}
+
+void StoredDrawParams::ensureField(int f)
+{
+ static Field* def = 0;
+ if (!def) {
+ def = new Field();
+ def->pos = Default;
+ def->maxLines = 0;
+ }
+
+ if (f<0 || f>=MAX_FIELD) return;
+
+ if ((int)_field.size() < f+1) _field.resize(f+1, *def);
+}
+
+
+void StoredDrawParams::setField(int f, const QString& t, QPixmap pm,
+ Position p, int maxLines)
+{
+ if (f<0 || f>=MAX_FIELD) return;
+ ensureField(f);
+
+ _field[f].text = t;
+ _field[f].pix = pm;
+ _field[f].pos = p;
+ _field[f].maxLines = maxLines;
+}
+
+void StoredDrawParams::setText(int f, const QString& t)
+{
+ if (f<0 || f>=MAX_FIELD) return;
+ ensureField(f);
+
+ _field[f].text = t;
+}
+
+void StoredDrawParams::setPixmap(int f, const QPixmap& pm)
+{
+ if (f<0 || f>=MAX_FIELD) return;
+ ensureField(f);
+
+ _field[f].pix = pm;
+}
+
+void StoredDrawParams::setPosition(int f, Position p)
+{
+ if (f<0 || f>=MAX_FIELD) return;
+ ensureField(f);
+
+ _field[f].pos = p;
+}
+
+void StoredDrawParams::setMaxLines(int f, int m)
+{
+ if (f<0 || f>=MAX_FIELD) return;
+ ensureField(f);
+
+ _field[f].maxLines = m;
+}
+
+
+
+//
+// RectDrawing
+//
+
+RectDrawing::RectDrawing(QRect r)
+{
+ _fm = 0;
+ _dp = 0;
+ setRect(r);
+}
+
+
+RectDrawing::~RectDrawing()
+{
+ delete _fm;
+ delete _dp;
+}
+
+DrawParams* RectDrawing::drawParams()
+{
+ if (!_dp)
+ _dp = new StoredDrawParams();
+
+ return _dp;
+}
+
+
+void RectDrawing::setDrawParams(DrawParams* dp)
+{
+ if (_dp) delete _dp;
+ _dp = dp;
+}
+
+void RectDrawing::setRect(QRect r)
+{
+ _rect = r;
+
+ _usedTopLeft = 0;
+ _usedTopCenter = 0;
+ _usedTopRight = 0;
+ _usedBottomLeft = 0;
+ _usedBottomCenter = 0;
+ _usedBottomRight = 0;
+
+ _fontHeight = 0;
+}
+
+QRect RectDrawing::remainingRect(DrawParams* dp)
+{
+ if (!dp) dp = drawParams();
+
+ if ((_usedTopLeft >0) ||
+ (_usedTopCenter >0) ||
+ (_usedTopRight >0)) {
+ if (dp->rotated())
+ _rect.setLeft(_rect.left() + _fontHeight);
+ else
+ _rect.setTop(_rect.top() + _fontHeight);
+ }
+
+ if ((_usedBottomLeft >0) ||
+ (_usedBottomCenter >0) ||
+ (_usedBottomRight >0)) {
+ if (dp->rotated())
+ _rect.setRight(_rect.right() - _fontHeight);
+ else
+ _rect.setBottom(_rect.bottom() - _fontHeight);
+ }
+ return _rect;
+}
+
+
+void RectDrawing::drawBack(QPainter* p, DrawParams* dp)
+{
+ if (!dp) dp = drawParams();
+ if (_rect.width()<=0 || _rect.height()<=0) return;
+
+ QRect r = _rect;
+ QColor normal = dp->backColor();
+ if (dp->selected()) normal = normal.light();
+ bool isCurrent = dp->current();
+
+ if (dp->drawFrame() || isCurrent) {
+ // 3D raised/sunken frame effect...
+ QColor high = normal.light();
+ QColor low = normal.dark();
+ p->setPen( isCurrent ? low:high);
+ p->drawLine(r.left(), r.top(), r.right(), r.top());
+ p->drawLine(r.left(), r.top(), r.left(), r.bottom());
+ p->setPen( isCurrent ? high:low);
+ p->drawLine(r.right(), r.top(), r.right(), r.bottom());
+ p->drawLine(r.left(), r.bottom(), r.right(), r.bottom());
+ r.setRect(r.x()+1, r.y()+1, r.width()-2, r.height()-2);
+ }
+ if (r.width()<=0 || r.height()<=0) return;
+
+ if (dp->shaded()) {
+ // some shading
+ bool goDark = qGray(normal.rgb())>128;
+ int rBase, gBase, bBase;
+ normal.rgb(&rBase, &gBase, &bBase);
+ p->setBrush(QBrush::NoBrush);
+
+ // shade parameters:
+ int d = 7;
+ float factor = 0.1, forth=0.7, back1 =0.9, toBack2 = .7, back2 = 0.97;
+
+ // coefficient corrections because of rectangle size
+ int s = r.width();
+ if (s > r.height()) s = r.height();
+ if (s<100) {
+ forth -= .3 * (100-s)/100;
+ back1 -= .2 * (100-s)/100;
+ back2 -= .02 * (100-s)/100;
+ }
+
+
+ // maximal color difference
+ int rDiff = goDark ? -rBase/d : (255-rBase)/d;
+ int gDiff = goDark ? -gBase/d : (255-gBase)/d;
+ int bDiff = goDark ? -bBase/d : (255-bBase)/d;
+
+ QColor shadeColor;
+ while (factor<.95) {
+ shadeColor.setRgb((int)(rBase+factor*rDiff+.5),
+ (int)(gBase+factor*gDiff+.5),
+ (int)(bBase+factor*bDiff+.5));
+ p->setPen(shadeColor);
+ p->drawRect(r);
+ r.setRect(r.x()+1, r.y()+1, r.width()-2, r.height()-2);
+ if (r.width()<=0 || r.height()<=0) return;
+ factor = 1.0 - ((1.0 - factor) * forth);
+ }
+
+ // and back (1st half)
+ while (factor>toBack2) {
+ shadeColor.setRgb((int)(rBase+factor*rDiff+.5),
+ (int)(gBase+factor*gDiff+.5),
+ (int)(bBase+factor*bDiff+.5));
+ p->setPen(shadeColor);
+ p->drawRect(r);
+ r.setRect(r.x()+1, r.y()+1, r.width()-2, r.height()-2);
+ if (r.width()<=0 || r.height()<=0) return;
+ factor = 1.0 - ((1.0 - factor) / back1);
+ }
+
+ // and back (2nd half)
+ while ( factor>.01) {
+ shadeColor.setRgb((int)(rBase+factor*rDiff+.5),
+ (int)(gBase+factor*gDiff+.5),
+ (int)(bBase+factor*bDiff+.5));
+ p->setPen(shadeColor);
+ p->drawRect(r);
+ r.setRect(r.x()+1, r.y()+1, r.width()-2, r.height()-2);
+ if (r.width()<=0 || r.height()<=0) return;
+
+ factor = factor * back2;
+ }
+ }
+
+ // fill inside
+ p->setPen(QPen::NoPen);
+ p->setBrush(normal);
+ p->drawRect(r);
+}
+
+
+bool RectDrawing::drawField(QPainter* p, int f, DrawParams* dp)
+{
+ if (!dp) dp = drawParams();
+
+ if (!_fm) {
+ _fm = new QFontMetrics(dp->font());
+ _fontHeight = _fm->height();
+ }
+
+ QRect r = _rect;
+
+ if (0) kdDebug(90100) << "DrawField: Rect " << r.x() << "/" << r.y()
+ << " - " << r.width() << "x" << r.height() << endl;
+
+ int h = _fontHeight;
+ bool rotate = dp->rotated();
+ int width = (rotate ? r.height() : r.width()) -4;
+ int height = (rotate ? r.width() : r.height());
+ int lines = height / h;
+
+ // stop if we have no space available
+ if (lines<1) return false;
+
+ // calculate free space in first line (<unused>)
+ int pos = dp->position(f);
+ if (pos == DrawParams::Default) {
+ switch(f%4) {
+ case 0: pos = DrawParams::TopLeft; break;
+ case 1: pos = DrawParams::TopRight; break;
+ case 2: pos = DrawParams::BottomRight; break;
+ case 3: pos = DrawParams::BottomLeft; break;
+ }
+ }
+
+ int unused = 0;
+ bool isBottom = false;
+ bool isCenter = false;
+ bool isRight = false;
+ int* used = 0;
+ switch(pos) {
+ case DrawParams::TopLeft:
+ used = &_usedTopLeft;
+ if (_usedTopLeft == 0) {
+ if (_usedTopCenter)
+ unused = (width - _usedTopCenter)/2;
+ else
+ unused = width - _usedTopRight;
+ }
+ break;
+
+ case DrawParams::TopCenter:
+ isCenter = true;
+ used = &_usedTopCenter;
+ if (_usedTopCenter == 0) {
+ if (_usedTopLeft > _usedTopRight)
+ unused = width - 2 * _usedTopLeft;
+ else
+ unused = width - 2 * _usedTopRight;
+ }
+ break;
+
+ case DrawParams::TopRight:
+ isRight = true;
+ used = &_usedTopRight;
+ if (_usedTopRight == 0) {
+ if (_usedTopCenter)
+ unused = (width - _usedTopCenter)/2;
+ else
+ unused = width - _usedTopLeft;
+ }
+ break;
+
+ case DrawParams::BottomLeft:
+ isBottom = true;
+ used = &_usedBottomLeft;
+ if (_usedBottomLeft == 0) {
+ if (_usedBottomCenter)
+ unused = (width - _usedBottomCenter)/2;
+ else
+ unused = width - _usedBottomRight;
+ }
+ break;
+
+ case DrawParams::BottomCenter:
+ isCenter = true;
+ isBottom = true;
+ used = &_usedBottomCenter;
+ if (_usedBottomCenter == 0) {
+ if (_usedBottomLeft > _usedBottomRight)
+ unused = width - 2 * _usedBottomLeft;
+ else
+ unused = width - 2 * _usedBottomRight;
+ }
+ break;
+
+ case DrawParams::BottomRight:
+ isRight = true;
+ isBottom = true;
+ used = &_usedBottomRight;
+ if (_usedBottomRight == 0) {
+ if (_usedBottomCenter)
+ unused = (width - _usedBottomCenter)/2;
+ else
+ unused = width - _usedBottomLeft;
+ }
+ break;
+ }
+
+ if (isBottom) {
+ if ((_usedTopLeft >0) ||
+ (_usedTopCenter >0) ||
+ (_usedTopRight >0))
+ lines--;
+ }
+ else if (!isBottom) {
+ if ((_usedBottomLeft >0) ||
+ (_usedBottomCenter >0) ||
+ (_usedBottomRight >0))
+ lines--;
+ }
+ if (lines<1) return false;
+
+
+ int y = isBottom ? height - h : 0;
+
+ if (unused < 0) unused = 0;
+ if (unused == 0) {
+ // no space available in last line at this position
+ y = isBottom ? (y-h) : (y+h);
+ lines--;
+
+ if (lines<1) return false;
+
+ // new line: reset used space
+ if (isBottom)
+ _usedBottomLeft = _usedBottomCenter = _usedBottomRight = 0;
+ else
+ _usedTopLeft = _usedTopCenter = _usedTopRight = 0;
+
+ unused = width;
+ }
+
+ // stop as soon as possible when there's no space for "..."
+ static int dotW = 0;
+ if (!dotW) dotW = _fm->width("...");
+ if (width < dotW) return false;
+
+ // get text and pixmap now, only if we need to, because it is possible
+ // that they are calculated on demand (and this can take some time)
+ QString name = dp->text(f);
+ if (name.isEmpty()) return 0;
+ QPixmap pix = dp->pixmap(f);
+
+ // check if pixmap can be drawn
+ int pixW = pix.width();
+ int pixH = pix.height();
+ int pixY = 0;
+ bool pixDrawn = true;
+ if (pixW>0) {
+ pixW += 2; // X distance from pix
+ if ((width < pixW + dotW) || (height < pixH)) {
+ // don't draw
+ pixW = 0;
+ }
+ else
+ pixDrawn = false;
+ }
+
+ // width of text and pixmap to be drawn
+ int w = pixW + _fm->width(name);
+
+ if (0) kdDebug(90100) << " For '" << name << "': Unused " << unused
+ << ", StrW " << w << ", Width " << width << endl;
+
+ // if we have limited space at 1st line:
+ // use it only if whole name does fit in last line...
+ if ((unused < width) && (w > unused)) {
+ y = isBottom ? (y-h) : (y+h);
+ lines--;
+
+ if (lines<1) return false;
+
+ // new line: reset used space
+ if (isBottom)
+ _usedBottomLeft = _usedBottomCenter = _usedBottomRight = 0;
+ else
+ _usedTopLeft = _usedTopCenter = _usedTopRight = 0;
+ }
+
+ p->save();
+ p->setPen( (qGray(dp->backColor().rgb())>100) ? Qt::black : Qt::white);
+ p->setFont(dp->font());
+ if (rotate) {
+ //p->translate(r.x()+2, r.y()+r.height());
+ p->translate(r.x(), r.y()+r.height()-2);
+ p->rotate(270);
+ }
+ else
+ p->translate(r.x()+2, r.y());
+
+
+ // adjust available lines according to maxLines
+ int max = dp->maxLines(f);
+ if ((max > 0) && (lines>max)) lines = max;
+
+ /* loop over name parts to break up string depending on available width.
+ * every char category change is supposed a possible break,
+ * with the exception Uppercase=>Lowercase.
+ * It's good enough for numbers, Symbols...
+ *
+ * If the text is to be written at the bottom, we start with the
+ * end of the string (so everything is reverted)
+ */
+ QString remaining;
+ int origLines = lines;
+ while (lines>0) {
+
+ if (w>width && lines>1) {
+ int lastBreakPos = name.length(), lastWidth = w;
+ int len = name.length();
+ QChar::Category caOld, ca;
+
+ if (!isBottom) {
+ // start with comparing categories of last 2 chars
+ caOld = name[len-1].category();
+ while (len>2) {
+ len--;
+ ca = name[len-1].category();
+ if (ca != caOld) {
+ // "Aa" has no break between...
+ if (ca == QChar::Letter_Uppercase &&
+ caOld == QChar::Letter_Lowercase) {
+ caOld = ca;
+ continue;
+ }
+ caOld = ca;
+ lastBreakPos = len;
+ w = pixW + _fm->width(name, len);
+ lastWidth = w;
+ if (w <= width) break;
+ }
+ }
+ w = lastWidth;
+ remaining = name.mid(lastBreakPos);
+ // remove space on break point
+ if (name[lastBreakPos-1].category() == QChar::Separator_Space)
+ name = name.left(lastBreakPos-1);
+ else
+ name = name.left(lastBreakPos);
+ }
+ else { // bottom
+ int l = len;
+ caOld = name[l-len].category();
+ while (len>2) {
+ len--;
+ ca = name[l-len].category();
+
+ if (ca != caOld) {
+ // "Aa" has no break between...
+ if (caOld == QChar::Letter_Uppercase &&
+ ca == QChar::Letter_Lowercase) {
+ caOld = ca;
+ continue;
+ }
+ caOld = ca;
+ lastBreakPos = len;
+ w = pixW + _fm->width(name.right(len));
+ lastWidth = w;
+ if (w <= width) break;
+ }
+ }
+ w = lastWidth;
+ remaining = name.left(l-lastBreakPos);
+ // remove space on break point
+ if (name[l-lastBreakPos].category() == QChar::Separator_Space)
+ name = name.right(lastBreakPos-1);
+ else
+ name = name.right(lastBreakPos);
+ }
+ }
+ else
+ remaining = QString::null;
+
+ /* truncate and add ... if needed */
+ if (w>width) {
+ int len = name.length();
+ w += dotW;
+ while (len>2 && (w > width)) {
+ len--;
+ w = pixW + _fm->width(name, len) + dotW;
+ }
+ // stop drawing: we cannot draw 2 chars + "..."
+ if (w>width) break;
+
+ name = name.left(len) + "...";
+ }
+
+ int x = 0;
+ if (isCenter)
+ x = (width - w)/2;
+ else if (isRight)
+ x = width - w;
+
+ if (!pixDrawn) {
+ pixY = y+(h-pixH)/2; // default: center vertically
+ if (pixH > h) pixY = isBottom ? y-(pixH-h) : y;
+
+ p->drawPixmap( x, pixY, pix);
+
+ // for distance to next text
+ pixY = isBottom ? (pixY - h - 2) : (pixY + pixH + 2);
+ pixDrawn = true;
+ }
+
+
+ if (0) kdDebug(90100) << " Drawing '" << name << "' at "
+ << x+pixW << "/" << y << endl;
+
+ p->drawText( x+pixW, y,
+ width - pixW, h,
+ Qt::AlignLeft, name);
+ y = isBottom ? (y-h) : (y+h);
+ lines--;
+
+ if (remaining.isEmpty()) break;
+ name = remaining;
+ w = pixW + _fm->width(name);
+ }
+
+ // make sure the pix stays visible
+ if (pixDrawn && (pixY>0)) {
+ if (isBottom && (pixY<y)) y = pixY;
+ if (!isBottom && (pixY>y)) y = pixY;
+ }
+
+ if (origLines > lines) {
+ // if only 1 line written, don't reset _used* vars
+ if (lines - origLines >1) {
+ if (isBottom)
+ _usedBottomLeft = _usedBottomCenter = _usedBottomRight = 0;
+ else
+ _usedTopLeft = _usedTopCenter = _usedTopRight = 0;
+ }
+
+ // take back one line
+ y = isBottom ? (y+h) : (y-h);
+ if (used) *used = w;
+ }
+
+ // update free space
+ if (!isBottom) {
+ if (rotate)
+ _rect.setRect(r.x()+y, r.y(), r.width()-y, r.height());
+ else
+ _rect.setRect(r.x(), r.y()+y, r.width(), r.height()-y);
+ }
+ else {
+ if (rotate)
+ _rect.setRect(r.x(), r.y(), y+h, r.height());
+ else
+ _rect.setRect(r.x(), r.y(), r.width(), y+h);
+ }
+
+ p->restore();
+
+ return true;
+}
+
+
+
+
+
+
+//
+// TreeMapItemList
+//
+
+int TreeMapItemList::compareItems ( Item item1, Item item2 )
+{
+ bool ascending;
+ int result;
+
+ TreeMapItem* parent = ((TreeMapItem*)item1)->parent();
+ // shouldn't happen
+ if (!parent) return 0;
+
+ int textNo = parent->sorting(&ascending);
+
+ if (textNo < 0) {
+ double diff = ((TreeMapItem*)item1)->value() -
+ ((TreeMapItem*)item2)->value();
+ result = (diff < -.9) ? -1 : (diff > .9) ? 1 : 0;
+ }
+ else
+ result = (((TreeMapItem*)item1)->text(textNo) <
+ ((TreeMapItem*)item2)->text(textNo)) ? -1 : 1;
+
+ return ascending ? result : -result;
+}
+
+
+TreeMapItem* TreeMapItemList::commonParent()
+{
+ TreeMapItem* parent, *item;
+ parent = first();
+ if (parent)
+ while( (item = next()) != 0)
+ parent = parent->commonParent(item);
+
+ return parent;
+}
+
+
+// TreeMapItem
+
+TreeMapItem::TreeMapItem(TreeMapItem* parent, double value)
+{
+ _value = value;
+ _parent = parent;
+
+ _sum = 0;
+ _children = 0;
+ _widget = 0;
+ _index = -1;
+ _depth = -1; // not set
+ _unused_self = 0;
+ _freeRects = 0;
+
+ if (_parent) {
+ // take sorting from parent
+ _sortTextNo = _parent->sorting(&_sortAscending);
+ _parent->addItem(this);
+ }
+ else {
+ _sortAscending = false;
+ _sortTextNo = -1; // default: no sorting
+ }
+}
+
+
+TreeMapItem::TreeMapItem(TreeMapItem* parent, double value,
+ QString text1, QString text2,
+ QString text3, QString text4)
+{
+ _value = value;
+ _parent = parent;
+
+ // this resizes the text vector only if needed
+ if (!text4.isEmpty()) setText(3, text4);
+ if (!text3.isEmpty()) setText(2, text3);
+ if (!text2.isEmpty()) setText(1, text2);
+ setText(0, text1);
+
+ _sum = 0;
+ _children = 0;
+ _widget = 0;
+ _index = -1;
+ _depth = -1; // not set
+ _unused_self = 0;
+ _freeRects = 0;
+
+ if (_parent) _parent->addItem(this);
+}
+
+TreeMapItem::~TreeMapItem()
+{
+ if (_children) delete _children;
+ if (_freeRects) delete _freeRects;
+
+ // finally, notify widget about deletion
+ if (_widget) _widget->deletingItem(this);
+}
+
+void TreeMapItem::setParent(TreeMapItem* p)
+{
+ _parent = p;
+ if (p) _widget = p->_widget;
+}
+
+bool TreeMapItem::isChildOf(TreeMapItem* item)
+{
+ if (!item) return false;
+
+ TreeMapItem* i = this;
+ while (i) {
+ if (item == i) return true;
+ i = i->_parent;
+ }
+ return false;
+}
+
+TreeMapItem* TreeMapItem::commonParent(TreeMapItem* item)
+{
+ while (item && !isChildOf(item)) {
+ item = item->parent();
+ }
+ return item;
+}
+
+void TreeMapItem::redraw()
+{
+ if (_widget)
+ _widget->redraw(this);
+}
+
+void TreeMapItem::clear()
+{
+ if (_children) {
+ // delete selected items below this item from selection
+ if (_widget) _widget->clearSelection(this);
+
+ delete _children;
+ _children = 0;
+ }
+}
+
+
+// invalidates current children and forces redraw
+// this is only usefull when children are created on demand in items()
+void TreeMapItem::refresh()
+{
+ clear();
+ redraw();
+}
+
+
+QStringList TreeMapItem::path(int textNo) const
+{
+ QStringList list(text(textNo));
+
+ TreeMapItem* i = _parent;
+ while (i) {
+ QString text = i->text(textNo);
+ if (!text.isEmpty())
+ list.prepend(i->text(textNo));
+ i = i->_parent;
+ }
+ return list;
+}
+
+int TreeMapItem::depth() const
+{
+ if (_depth>0) return _depth;
+
+ if (_parent)
+ return _parent->depth() + 1;
+ return 1;
+}
+
+
+bool TreeMapItem::initialized()
+{
+ if (!_children) {
+ _children = new TreeMapItemList;
+ _children->setAutoDelete(true);
+ return false;
+ }
+ return true;
+}
+
+void TreeMapItem::addItem(TreeMapItem* i)
+{
+ if (!i) return;
+
+ if (!_children) {
+ _children = new TreeMapItemList;
+ _children->setAutoDelete(true);
+ }
+ i->setParent(this);
+
+ if (sorting(0) == -1)
+ _children->append(i); // preserve insertion order
+ else
+ _children->inSort(i);
+}
+
+
+// default implementations of virtual functions
+
+double TreeMapItem::value() const
+{
+ return _value;
+}
+
+double TreeMapItem::sum() const
+{
+ return _sum;
+}
+
+DrawParams::Position TreeMapItem::position(int f) const
+{
+ Position p = StoredDrawParams::position(f);
+ if (_widget && (p == Default))
+ p = _widget->fieldPosition(f);
+
+ return p;
+}
+
+// use widget font
+const QFont& TreeMapItem::font() const
+{
+ return _widget->currentFont();
+}
+
+
+bool TreeMapItem::isMarked(int) const
+{
+ return false;
+}
+
+
+int TreeMapItem::borderWidth() const
+{
+ if (_widget)
+ return _widget->borderWidth();
+
+ return 2;
+}
+
+int TreeMapItem::sorting(bool* ascending) const
+{
+ if (ascending) *ascending = _sortAscending;
+ return _sortTextNo;
+}
+
+// do *not* set sorting recursively
+void TreeMapItem::setSorting(int textNo, bool ascending)
+{
+ if (_sortTextNo == textNo) {
+ if(_sortAscending == ascending) return;
+ if (textNo == -1) {
+ // when no sorting is done, order change doesn't do anything
+ _sortAscending = ascending;
+ return;
+ }
+ }
+ _sortAscending = ascending;
+ _sortTextNo = textNo;
+
+ if (_children && _sortTextNo != -1) _children->sort();
+}
+
+void TreeMapItem::resort(bool recursive)
+{
+ if (!_children) return;
+
+ if (_sortTextNo != -1) _children->sort();
+
+ if (recursive)
+ for (TreeMapItem* i=_children->first(); i; i=_children->next())
+ i->resort(recursive);
+}
+
+
+TreeMapItem::SplitMode TreeMapItem::splitMode() const
+{
+ if (_widget)
+ return _widget->splitMode();
+
+ return Best;
+}
+
+int TreeMapItem::rtti() const
+{
+ return 0;
+}
+
+TreeMapItemList* TreeMapItem::children()
+{
+ if (!_children) {
+ _children = new TreeMapItemList;
+ _children->setAutoDelete(true);
+ }
+ return _children;
+}
+
+void TreeMapItem::clearItemRect()
+{
+ _rect = QRect();
+ clearFreeRects();
+}
+
+void TreeMapItem::clearFreeRects()
+{
+ if (_freeRects) _freeRects->clear();
+}
+
+void TreeMapItem::addFreeRect(const QRect& r)
+{
+ // don't add invalid rects
+ if ((r.width() < 1) || (r.height() < 1)) return;
+
+ if (!_freeRects) {
+ _freeRects = new QPtrList<QRect>;
+ _freeRects->setAutoDelete(true);
+ }
+
+ if (0) kdDebug(90100) << "addFree(" << path(0).join("/") << ", "
+ << r.x() << "/" << r.y() << "-"
+ << r.width() << "x" << r.height() << ")" << endl;
+
+ QRect* last = _freeRects->last();
+ if (!last) {
+ _freeRects->append(new QRect(r));
+ return;
+ }
+
+ // join rect with last rect if possible
+ // this saves memory and doesn't make the tooltip flicker
+
+ bool replaced = false;
+ if ((last->left() == r.left()) && (last->width() == r.width())) {
+ if ((last->bottom()+1 == r.top()) || (r.bottom()+1 == last->top())) {
+ *last |= r;
+ replaced = true;
+ }
+ }
+ else if ((last->top() == r.top()) && (last->height() == r.height())) {
+ if ((last->right()+1 == r.left()) || (r.right()+1 == last->left())) {
+ *last |= r;
+ replaced = true;
+ }
+ }
+
+ if (!replaced) {
+ _freeRects->append(new QRect(r));
+ return;
+ }
+
+ if (0) kdDebug(90100) << " united with last to ("
+ << last->x() << "/" << last->y() << "-"
+ << last->width() << "x" << last->height() << ")" << endl;
+}
+
+
+// Tooltips for TreeMapWidget
+
+class TreeMapTip: public QToolTip
+{
+public:
+ TreeMapTip( QWidget* p ):QToolTip(p) {}
+
+protected:
+ void maybeTip( const QPoint & );
+};
+
+void TreeMapTip::maybeTip( const QPoint& pos )
+{
+ if ( !parentWidget()->inherits( "TreeMapWidget" ) )
+ return;
+
+ TreeMapWidget* p = (TreeMapWidget*)parentWidget();
+ TreeMapItem* i;
+ i = p->item(pos.x(), pos.y());
+ QPtrList<QRect>* rList = i ? i->freeRects() : 0;
+ if (rList) {
+ QRect* r;
+ for(r=rList->first();r;r=rList->next())
+ if (r->contains(pos))
+ tip(*r, p->tipString(i));
+ }
+}
+
+
+
+// TreeMapWidget
+
+TreeMapWidget::TreeMapWidget(TreeMapItem* base,
+ QWidget* parent, const char* name)
+ : QWidget(parent, name)
+{
+ _base = base;
+ _base->setWidget(this);
+
+ _font = font();
+ _fontHeight = fontMetrics().height();
+
+
+ // default behaviour
+ _selectionMode = Single;
+ _splitMode = TreeMapItem::AlwaysBest;
+ _visibleWidth = 2;
+ _reuseSpace = false;
+ _skipIncorrectBorder = false;
+ _drawSeparators = false;
+ _allowRotation = true;
+ _borderWidth = 2;
+ _shading = true; // beautiful is default!
+ _maxSelectDepth = -1; // unlimited
+ _maxDrawingDepth = -1; // unlimited
+ _minimalArea = -1; // unlimited
+ _markNo = 0;
+
+ for(int i=0;i<4;i++) {
+ _drawFrame[i] = true;
+ _transparent[i] = false;
+ }
+
+ // _stopAtText will be unset on resizing (per default)
+ // _textVisible will be true on resizing (per default)
+ // _forceText will be false on resizing (per default)
+
+ // start state: _selection is an empty list
+ _current = 0;
+ _oldCurrent = 0;
+ _pressed = 0;
+ _lastOver = 0;
+ _needsRefresh = _base;
+
+ setBackgroundMode(Qt::NoBackground);
+ setFocusPolicy(QWidget::StrongFocus);
+ _tip = new TreeMapTip(this);
+}
+
+TreeMapWidget::~TreeMapWidget()
+{
+ delete _base;
+ delete _tip;
+}
+
+const QFont& TreeMapWidget::currentFont() const
+{
+ return _font;
+}
+
+void TreeMapWidget::setSplitMode(TreeMapItem::SplitMode m)
+{
+ if (_splitMode == m) return;
+
+ _splitMode = m;
+ redraw();
+}
+
+TreeMapItem::SplitMode TreeMapWidget::splitMode() const
+{
+ return _splitMode;
+}
+
+bool TreeMapWidget::setSplitMode(QString mode)
+{
+ if (mode == "Bisection") setSplitMode(TreeMapItem::Bisection);
+ else if (mode == "Columns") setSplitMode(TreeMapItem::Columns);
+ else if (mode == "Rows") setSplitMode(TreeMapItem::Rows);
+ else if (mode == "AlwaysBest") setSplitMode(TreeMapItem::AlwaysBest);
+ else if (mode == "Best") setSplitMode(TreeMapItem::Best);
+ else if (mode == "HAlternate") setSplitMode(TreeMapItem::HAlternate);
+ else if (mode == "VAlternate") setSplitMode(TreeMapItem::VAlternate);
+ else if (mode == "Horizontal") setSplitMode(TreeMapItem::Horizontal);
+ else if (mode == "Vertical") setSplitMode(TreeMapItem::Vertical);
+ else return false;
+
+ return true;
+}
+
+QString TreeMapWidget::splitModeString() const
+{
+ QString mode;
+ switch(splitMode()) {
+ case TreeMapItem::Bisection: mode = "Bisection"; break;
+ case TreeMapItem::Columns: mode = "Columns"; break;
+ case TreeMapItem::Rows: mode = "Rows"; break;
+ case TreeMapItem::AlwaysBest: mode = "AlwaysBest"; break;
+ case TreeMapItem::Best: mode = "Best"; break;
+ case TreeMapItem::HAlternate: mode = "HAlternate"; break;
+ case TreeMapItem::VAlternate: mode = "VAlternate"; break;
+ case TreeMapItem::Horizontal: mode = "Horizontal"; break;
+ case TreeMapItem::Vertical: mode = "Vertical"; break;
+ default: mode = "Unknown"; break;
+ }
+ return mode;
+}
+
+
+void TreeMapWidget::setShadingEnabled(bool s)
+{
+ if (_shading == s) return;
+
+ _shading = s;
+ redraw();
+}
+
+void TreeMapWidget::drawFrame(int d, bool b)
+{
+ if ((d<0) || (d>=4) || (_drawFrame[d]==b)) return;
+
+ _drawFrame[d] = b;
+ redraw();
+}
+
+void TreeMapWidget::setTransparent(int d, bool b)
+{
+ if ((d<0) || (d>=4) || (_transparent[d]==b)) return;
+
+ _transparent[d] = b;
+ redraw();
+}
+
+void TreeMapWidget::setAllowRotation(bool enable)
+{
+ if (_allowRotation == enable) return;
+
+ _allowRotation = enable;
+ redraw();
+}
+
+void TreeMapWidget::setVisibleWidth(int width, bool reuseSpace)
+{
+ if (_visibleWidth == width && _reuseSpace == reuseSpace) return;
+
+ _visibleWidth = width;
+ _reuseSpace = reuseSpace;
+ redraw();
+}
+
+void TreeMapWidget::setSkipIncorrectBorder(bool enable)
+{
+ if (_skipIncorrectBorder == enable) return;
+
+ _skipIncorrectBorder = enable;
+ redraw();
+}
+
+void TreeMapWidget::setBorderWidth(int w)
+{
+ if (_borderWidth == w) return;
+
+ _borderWidth = w;
+ redraw();
+}
+
+void TreeMapWidget::setMaxDrawingDepth(int d)
+{
+ if (_maxDrawingDepth == d) return;
+
+ _maxDrawingDepth = d;
+ redraw();
+}
+
+QString TreeMapWidget::defaultFieldType(int f) const
+{
+ return i18n("Text %1").arg(f+1);
+}
+
+QString TreeMapWidget::defaultFieldStop(int) const
+{
+ return QString();
+}
+
+bool TreeMapWidget::defaultFieldVisible(int f) const
+{
+ return (f<2);
+}
+
+bool TreeMapWidget::defaultFieldForced(int) const
+{
+ return false;
+}
+
+DrawParams::Position TreeMapWidget::defaultFieldPosition(int f) const
+{
+ switch(f%4) {
+ case 0: return DrawParams::TopLeft;
+ case 1: return DrawParams::TopRight;
+ case 2: return DrawParams::BottomRight;
+ case 3: return DrawParams::BottomLeft;
+ default:break;
+ }
+ return DrawParams::TopLeft;
+}
+
+bool TreeMapWidget::resizeAttr(int size)
+{
+ if (size<0 || size>=MAX_FIELD) return false;
+
+ if (size>(int)_attr.size()) {
+ struct FieldAttr a;
+ int oldSize = _attr.size();
+ _attr.resize(size, a);
+ while (oldSize<size) {
+ _attr[oldSize].type = defaultFieldType(oldSize);
+ _attr[oldSize].stop = defaultFieldStop(oldSize);
+ _attr[oldSize].visible = defaultFieldVisible(oldSize);
+ _attr[oldSize].forced = defaultFieldForced(oldSize);
+ _attr[oldSize].pos = defaultFieldPosition(oldSize);
+ oldSize++;
+ }
+ }
+ return true;
+}
+
+void TreeMapWidget::setFieldType(int f, QString type)
+{
+ if (((int)_attr.size() < f+1) &&
+ (type == defaultFieldType(f))) return;
+ if (resizeAttr(f+1)) _attr[f].type = type;
+
+ // no need to redraw: the type string is not visible in the TreeMap
+}
+
+QString TreeMapWidget::fieldType(int f) const
+{
+ if (f<0 || (int)_attr.size()<f+1) return defaultFieldType(f);
+ return _attr[f].type;
+}
+
+void TreeMapWidget::setFieldStop(int f, QString stop)
+{
+ if (((int)_attr.size() < f+1) &&
+ (stop == defaultFieldStop(f))) return;
+ if (resizeAttr(f+1)) {
+ _attr[f].stop = stop;
+ redraw();
+ }
+}
+
+QString TreeMapWidget::fieldStop(int f) const
+{
+ if (f<0 || (int)_attr.size()<f+1) return defaultFieldStop(f);
+ return _attr[f].stop;
+}
+
+void TreeMapWidget::setFieldVisible(int f, bool enable)
+{
+ if (((int)_attr.size() < f+1) &&
+ (enable == defaultFieldVisible(f))) return;
+
+ if (resizeAttr(f+1)) {
+ _attr[f].visible = enable;
+ redraw();
+ }
+}
+
+bool TreeMapWidget::fieldVisible(int f) const
+{
+ if (f<0 || (int)_attr.size()<f+1)
+ return defaultFieldVisible(f);
+
+ return _attr[f].visible;
+}
+
+void TreeMapWidget::setFieldForced(int f, bool enable)
+{
+ if (((int)_attr.size() < f+1) &&
+ (enable == defaultFieldForced(f))) return;
+
+ if (resizeAttr(f+1)) {
+ _attr[f].forced = enable;
+ if (_attr[f].visible) redraw();
+ }
+}
+
+bool TreeMapWidget::fieldForced(int f) const
+{
+ if (f<0 || (int)_attr.size()<f+1)
+ return defaultFieldForced(f);
+
+ return _attr[f].forced;
+}
+
+void TreeMapWidget::setFieldPosition(int f, TreeMapItem::Position pos)
+{
+ if (((int)_attr.size() < f+1) &&
+ (pos == defaultFieldPosition(f))) return;
+
+ if (resizeAttr(f+1)) {
+ _attr[f].pos = pos;
+ if (_attr[f].visible) redraw();
+ }
+}
+
+DrawParams::Position TreeMapWidget::fieldPosition(int f) const
+{
+ if (f<0 || (int)_attr.size()<f+1)
+ return defaultFieldPosition(f);
+
+ return _attr[f].pos;
+}
+
+void TreeMapWidget::setFieldPosition(int f, QString pos)
+{
+ if (pos == "TopLeft")
+ setFieldPosition(f, DrawParams::TopLeft);
+ else if (pos == "TopCenter")
+ setFieldPosition(f, DrawParams::TopCenter);
+ else if (pos == "TopRight")
+ setFieldPosition(f, DrawParams::TopRight);
+ else if (pos == "BottomLeft")
+ setFieldPosition(f, DrawParams::BottomLeft);
+ else if (pos == "BottomCenter")
+ setFieldPosition(f, DrawParams::BottomCenter);
+ else if (pos == "BottomRight")
+ setFieldPosition(f, DrawParams::BottomRight);
+ else if (pos == "Default")
+ setFieldPosition(f, DrawParams::Default);
+}
+
+QString TreeMapWidget::fieldPositionString(int f) const
+{
+ TreeMapItem::Position pos = fieldPosition(f);
+ if (pos == DrawParams::TopLeft) return QString("TopLeft");
+ if (pos == DrawParams::TopCenter) return QString("TopCenter");
+ if (pos == DrawParams::TopRight) return QString("TopRight");
+ if (pos == DrawParams::BottomLeft) return QString("BottomLeft");
+ if (pos == DrawParams::BottomCenter) return QString("BottomCenter");
+ if (pos == DrawParams::BottomRight) return QString("BottomRight");
+ if (pos == DrawParams::Default) return QString("Default");
+ return QString("unknown");
+}
+
+void TreeMapWidget::setMinimalArea(int area)
+{
+ if (_minimalArea == area) return;
+
+ _minimalArea = area;
+ redraw();
+}
+
+
+void TreeMapWidget::deletingItem(TreeMapItem* i)
+{
+ // remove any references to the item to be deleted
+ while(_selection.findRef(i) > -1)
+ _selection.remove();
+
+ while(_tmpSelection.findRef(i) > -1)
+ _tmpSelection.remove();
+
+ if (_current == i) _current = 0;
+ if (_oldCurrent == i) _oldCurrent = 0;
+ if (_pressed == i) _pressed = 0;
+ if (_lastOver == i) _lastOver = 0;
+
+ // don't redraw a deleted item
+ if (_needsRefresh == i) {
+ // we can savely redraw the parent, as deleting order is
+ // from child to parent; i.e. i->parent() is existing.
+ _needsRefresh = i->parent();
+ }
+}
+
+
+QString TreeMapWidget::tipString(TreeMapItem* i) const
+{
+ QString tip, itemTip;
+
+ while (i) {
+ if (!i->text(0).isEmpty()) {
+ itemTip = i->text(0);
+ if (!i->text(1).isEmpty())
+ itemTip += " (" + i->text(1) + ")";
+
+ if (!tip.isEmpty())
+ tip += "\n";
+
+ tip += itemTip;
+ }
+ i = i->parent();
+ }
+ return tip;
+}
+
+TreeMapItem* TreeMapWidget::item(int x, int y) const
+{
+ TreeMapItem* p = _base;
+ TreeMapItem* i;
+
+ if (!rect().contains(x, y)) return 0;
+ if (DEBUG_DRAWING) kdDebug(90100) << "item(" << x << "," << y << "):" << endl;
+
+ while (1) {
+ TreeMapItemList* list = p->children();
+ if (!list)
+ i = 0;
+ else {
+ int idx=0;
+ for (i=list->first();i;i=list->next(),idx++) {
+
+ if (DEBUG_DRAWING)
+ kdDebug(90100) << " Checking " << i->path(0).join("/") << " ("
+ << i->itemRect().x() << "/" << i->itemRect().y()
+ << "-" << i->itemRect().width()
+ << "x" << i->itemRect().height() << ")" << endl;
+
+ if (i->itemRect().contains(x, y)) {
+
+ if (DEBUG_DRAWING) kdDebug(90100) << " .. Got. Index " << idx << endl;
+
+ p->setIndex(idx);
+ break;
+ }
+ }
+ }
+
+ if (!i) {
+ static TreeMapItem* last = 0;
+ if (p != last) {
+ last = p;
+
+ if (DEBUG_DRAWING)
+ kdDebug(90100) << "item(" << x << "," << y << "): Got "
+ << p->path(0).join("/") << " (Size "
+ << p->itemRect().width() << "x" << p->itemRect().height()
+ << ", Val " << p->value() << ")" << endl;
+ }
+
+ return p;
+ }
+ p = i;
+ }
+ return 0;
+}
+
+TreeMapItem* TreeMapWidget::possibleSelection(TreeMapItem* i) const
+{
+ if (i) {
+ if (_maxSelectDepth>=0) {
+ int depth = i->depth();
+ while(i && depth > _maxSelectDepth) {
+ i = i->parent();
+ depth--;
+ }
+ }
+ }
+ return i;
+}
+
+TreeMapItem* TreeMapWidget::visibleItem(TreeMapItem* i) const
+{
+ if (i) {
+ /* Must have a visible area */
+ while(i && ((i->itemRect().width() <1) ||
+ (i->itemRect().height() <1))) {
+ TreeMapItem* p = i->parent();
+ if (!p) break;
+ int idx = p->children()->findRef(i);
+ idx--;
+ if (idx<0)
+ i = p;
+ else
+ i = p->children()->at(idx);
+ }
+ }
+ return i;
+}
+
+void TreeMapWidget::setSelected(TreeMapItem* item, bool selected)
+{
+ item = possibleSelection(item);
+ setCurrent(item);
+
+ TreeMapItem* changed = setTmpSelected(item, selected);
+ if (!changed) return;
+
+ _selection = _tmpSelection;
+ if (_selectionMode == Single)
+ emit selectionChanged(item);
+ emit selectionChanged();
+ redraw(changed);
+
+ if (0) kdDebug(90100) << (selected ? "S":"Des") << "elected Item "
+ << (item ? item->path(0).join("") : QString("(null)"))
+ << " (depth " << (item ? item->depth() : -1)
+ << ")" << endl;
+}
+
+void TreeMapWidget::setMarked(int markNo, bool redrawWidget)
+{
+ // if there's no marking, return
+ if ((_markNo == 0) && (markNo == 0)) return;
+
+ _markNo = markNo;
+ if (!clearSelection() && redrawWidget) redraw();
+}
+
+/* Returns all items which appear only in one of the given lists */
+TreeMapItemList TreeMapWidget::diff(TreeMapItemList& l1,
+ TreeMapItemList& l2)
+{
+ TreeMapItemList l;
+ TreeMapItemListIterator it1(l1), it2(l2);
+
+ TreeMapItem* item;
+ while ( (item = it1.current()) != 0 ) {
+ ++it1;
+ if (l2.containsRef(item) > 0) continue;
+ l.append(item);
+ }
+ while ( (item = it2.current()) != 0 ) {
+ ++it2;
+ if (l1.containsRef(item) > 0) continue;
+ l.append(item);
+ }
+
+ return l;
+}
+
+/* Only modifies _tmpSelection.
+ * Returns 0 when no change happened, otherwise the TreeMapItem that has
+ * to be redrawn for all changes.
+ */
+TreeMapItem* TreeMapWidget::setTmpSelected(TreeMapItem* item, bool selected)
+{
+ if (!item) return 0;
+ if (_selectionMode == NoSelection) return 0;
+
+ TreeMapItemList old = _tmpSelection;
+
+ if (_selectionMode == Single) {
+ _tmpSelection.clear();
+ if (selected) _tmpSelection.append(item);
+ }
+ else {
+ if (selected) {
+ TreeMapItem* i=_tmpSelection.first();
+ while (i) {
+ if (i->isChildOf(item) || item->isChildOf(i)) {
+ _tmpSelection.remove();
+ i = _tmpSelection.current();
+ }
+ else
+ i = _tmpSelection.next();
+ }
+ _tmpSelection.append(item);
+ }
+ else
+ _tmpSelection.removeRef(item);
+ }
+
+ return diff(old, _tmpSelection).commonParent();
+}
+
+
+bool TreeMapWidget::clearSelection(TreeMapItem* parent)
+{
+ TreeMapItemList old = _selection;
+
+ TreeMapItem* i=_selection.first();
+ while (i) {
+ if (i->isChildOf(parent)) {
+ _selection.remove();
+ i = _selection.current();
+ }
+ else
+ i = _selection.next();
+ }
+
+ TreeMapItem* changed = diff(old, _selection).commonParent();
+ if (changed) {
+ changed->redraw();
+ emit selectionChanged();
+ }
+ return (changed != 0);
+}
+
+bool TreeMapWidget::isSelected(TreeMapItem* i) const
+{
+ return _selection.containsRef(i)>0;
+}
+
+bool TreeMapWidget::isTmpSelected(TreeMapItem* i)
+{
+ return _tmpSelection.containsRef(i)>0;
+}
+
+
+void TreeMapWidget::setCurrent(TreeMapItem* i, bool kbd)
+{
+ TreeMapItem* old = _current;
+ _current = i;
+
+ if (_markNo >0) {
+ // remove mark
+ _markNo = 0;
+
+ if (1) kdDebug(90100) << "setCurrent(" << i->path(0).join("/")
+ << ") - mark removed" << endl;
+
+ // always complete redraw needed to remove mark
+ redraw();
+
+ if (old == _current) return;
+ }
+ else {
+ if (old == _current) return;
+
+ if (old) old->redraw();
+ if (i) i->redraw();
+ }
+
+ //kdDebug(90100) << "Current Item " << (i ? i->path().ascii() : "(null)") << endl;
+
+ emit currentChanged(i, kbd);
+}
+
+void TreeMapWidget::setRangeSelection(TreeMapItem* i1,
+ TreeMapItem* i2, bool selected)
+{
+ i1 = possibleSelection(i1);
+ i2 = possibleSelection(i2);
+ setCurrent(i2);
+
+ TreeMapItem* changed = setTmpRangeSelection(i1, i2, selected);
+ if (!changed) return;
+
+ _selection = _tmpSelection;
+ if (_selectionMode == Single)
+ emit selectionChanged(i2);
+ emit selectionChanged();
+ redraw(changed);
+}
+
+TreeMapItem* TreeMapWidget::setTmpRangeSelection(TreeMapItem* i1,
+ TreeMapItem* i2,
+ bool selected)
+{
+ if ((i1 == 0) && (i2 == 0)) return 0;
+ if ((i1 == 0) || i1->isChildOf(i2)) return setTmpSelected(i2, selected);
+ if ((i2 == 0) || i2->isChildOf(i1)) return setTmpSelected(i1, selected);
+
+ TreeMapItem* changed = setTmpSelected(i1, selected);
+ TreeMapItem* changed2 = setTmpSelected(i2, selected);
+ if (changed2) changed = changed2->commonParent(changed);
+
+ TreeMapItem* commonParent = i1;
+ while (commonParent && !i2->isChildOf(commonParent)) {
+ i1 = commonParent;
+ commonParent = commonParent->parent();
+ }
+ if (!commonParent) return changed;
+ while (i2 && i2->parent() != commonParent)
+ i2 = i2->parent();
+ if (!i2) return changed;
+
+ TreeMapItemList* list = commonParent->children();
+ if (!list) return changed;
+
+ TreeMapItem* i = list->first();
+ bool between = false;
+ while (i) {
+ if (between) {
+ if (i==i1 || i==i2) break;
+ changed2 = setTmpSelected(i, selected);
+ if (changed2) changed = changed2->commonParent(changed);
+ }
+ else if (i==i1 || i==i2)
+ between = true;
+ i = list->next();
+ }
+
+ return changed;
+}
+
+void TreeMapWidget::contextMenuEvent( QContextMenuEvent* e )
+{
+ //kdDebug(90100) << "TreeMapWidget::contextMenuEvent" << endl;
+
+ if ( receivers( SIGNAL(contextMenuRequested(TreeMapItem*, const QPoint &)) ) )
+ e->accept();
+
+ if ( e->reason() == QContextMenuEvent::Keyboard ) {
+ QRect r = (_current) ? _current->itemRect() : _base->itemRect();
+ QPoint p = QPoint(r.left() + r.width()/2, r.top() + r.height()/2);
+ emit contextMenuRequested(_current, p);
+ }
+ else {
+ TreeMapItem* i = item(e->x(), e->y());
+ emit contextMenuRequested(i, e->pos());
+ }
+}
+
+
+void TreeMapWidget::mousePressEvent( QMouseEvent* e )
+{
+ //kdDebug(90100) << "TreeMapWidget::mousePressEvent" << endl;
+
+ _oldCurrent = _current;
+
+ TreeMapItem* i = item(e->x(), e->y());
+
+ _pressed = i;
+
+ _inShiftDrag = e->state() & ShiftButton;
+ _inControlDrag = e->state() & ControlButton;
+ _lastOver = _pressed;
+
+ TreeMapItem* changed = 0;
+ TreeMapItem* item = possibleSelection(_pressed);
+
+ switch(_selectionMode) {
+ case Single:
+ changed = setTmpSelected(item, true);
+ break;
+ case Multi:
+ changed = setTmpSelected(item, !isTmpSelected(item));
+ break;
+ case Extended:
+ if (_inControlDrag)
+ changed = setTmpSelected(item, !isTmpSelected(item));
+ else if (_inShiftDrag) {
+ TreeMapItem* sCurrent = possibleSelection(_current);
+ changed = setTmpRangeSelection(sCurrent, item,
+ !isTmpSelected(item));
+ }
+ else {
+ _selectionMode = Single;
+ changed = setTmpSelected(item, true);
+ _selectionMode = Extended;
+ }
+ break;
+ default:
+ break;
+ }
+
+ // item under mouse always selected on right button press
+ if (e->button() == RightButton) {
+ TreeMapItem* changed2 = setTmpSelected(item, true);
+ if (changed2) changed = changed2->commonParent(changed);
+ }
+
+ setCurrent(_pressed);
+
+ if (changed)
+ redraw(changed);
+
+ if (e->button() == RightButton) {
+
+ // emit selection change
+ if (! (_tmpSelection == _selection)) {
+ _selection = _tmpSelection;
+ if (_selectionMode == Single)
+ emit selectionChanged(_lastOver);
+ emit selectionChanged();
+ }
+ _pressed = 0;
+ _lastOver = 0;
+ emit rightButtonPressed(i, e->pos());
+ }
+}
+
+void TreeMapWidget::mouseMoveEvent( QMouseEvent* e )
+{
+ //kdDebug(90100) << "TreeMapWidget::mouseMoveEvent" << endl;
+
+ if (!_pressed) return;
+ TreeMapItem* over = item(e->x(), e->y());
+ if (_lastOver == over) return;
+
+ setCurrent(over);
+ if (over == 0) {
+ _lastOver = 0;
+ return;
+ }
+
+ TreeMapItem* changed = 0;
+ TreeMapItem* item = possibleSelection(over);
+
+ switch(_selectionMode) {
+ case Single:
+ changed = setTmpSelected(item, true);
+ break;
+ case Multi:
+ changed = setTmpSelected(item, !isTmpSelected(item));
+ break;
+ case Extended:
+ if (_inControlDrag)
+ changed = setTmpSelected(item, !isTmpSelected(item));
+ else {
+ TreeMapItem* sLast = possibleSelection(_lastOver);
+ changed = setTmpRangeSelection(sLast, item, true);
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ _lastOver = over;
+
+ if (changed)
+ redraw(changed);
+}
+
+void TreeMapWidget::mouseReleaseEvent( QMouseEvent* )
+{
+ //kdDebug(90100) << "TreeMapWidget::mouseReleaseEvent" << endl;
+
+ if (!_pressed) return;
+
+ if (!_lastOver) {
+ // take back
+ setCurrent(_oldCurrent);
+ TreeMapItem* changed = diff(_tmpSelection, _selection).commonParent();
+ _tmpSelection = _selection;
+ if (changed)
+ redraw(changed);
+ }
+ else {
+ if (! (_tmpSelection == _selection)) {
+ _selection = _tmpSelection;
+ if (_selectionMode == Single)
+ emit selectionChanged(_lastOver);
+ emit selectionChanged();
+ }
+ if (!_inControlDrag && !_inShiftDrag && (_pressed == _lastOver))
+ emit clicked(_lastOver);
+ }
+
+ _pressed = 0;
+ _lastOver = 0;
+}
+
+
+void TreeMapWidget::mouseDoubleClickEvent( QMouseEvent* e )
+{
+ TreeMapItem* over = item(e->x(), e->y());
+
+ emit doubleClicked(over);
+}
+
+
+/* returns -1 if nothing visible found */
+int nextVisible(TreeMapItem* i)
+{
+ TreeMapItem* p = i->parent();
+ if (!p || p->itemRect().isEmpty()) return -1;
+
+ int idx = p->children()->findRef(i);
+ if (idx<0) return -1;
+
+ while (idx < (int)p->children()->count()-1) {
+ idx++;
+ QRect r = p->children()->at(idx)->itemRect();
+ if (r.width()>1 && r.height()>1)
+ return idx;
+ }
+ return -1;
+}
+
+/* returns -1 if nothing visible found */
+int prevVisible(TreeMapItem* i)
+{
+ TreeMapItem* p = i->parent();
+ if (!p || p->itemRect().isEmpty()) return -1;
+
+ int idx = p->children()->findRef(i);
+ if (idx<0) return -1;
+
+ while (idx > 0) {
+ idx--;
+ QRect r = p->children()->at(idx)->itemRect();
+ if (r.width()>1 && r.height()>1)
+ return idx;
+ }
+ return -1;
+}
+
+
+
+
+void TreeMapWidget::keyPressEvent( QKeyEvent* e )
+{
+ if (e->key() == Key_Escape && _pressed) {
+
+ // take back
+ if (_oldCurrent != _lastOver)
+ setCurrent(_oldCurrent);
+ if (! (_tmpSelection == _selection)) {
+ TreeMapItem* changed = diff(_tmpSelection, _selection).commonParent();
+ _tmpSelection = _selection;
+ if (changed)
+ redraw(changed);
+ }
+ _pressed = 0;
+ _lastOver = 0;
+ }
+
+ if ((e->key() == Key_Space) ||
+ (e->key() == Key_Return)) {
+
+ switch(_selectionMode) {
+ case NoSelection:
+ break;
+ case Single:
+ setSelected(_current, true);
+ break;
+ case Multi:
+ setSelected(_current, !isSelected(_current));
+ break;
+ case Extended:
+ if ((e->state() & ControlButton) || (e->state() & ShiftButton))
+ setSelected(_current, !isSelected(_current));
+ else {
+ _selectionMode = Single;
+ setSelected(_current, true);
+ _selectionMode = Extended;
+ }
+ }
+
+ if (_current && (e->key() == Key_Return))
+ emit returnPressed(_current);
+
+ return;
+ }
+
+ if (!_current) {
+ if (e->key() == Key_Down) {
+ setCurrent(_base, true);
+ }
+ return;
+ }
+
+ TreeMapItem* old = _current, *newItem;
+ TreeMapItem* p = _current->parent();
+
+ bool goBack;
+ if (_current->sorting(&goBack) == -1) {
+ // noSorting
+ goBack = false;
+ }
+
+
+ if ((e->key() == Key_Backspace) ||
+ (e->key() == Key_Up)) {
+ newItem = visibleItem(p);
+ setCurrent(newItem, true);
+ }
+ else if (e->key() == Key_Left) {
+ int newIdx = goBack ? nextVisible(_current) : prevVisible(_current);
+ if (p && newIdx>=0) {
+ p->setIndex(newIdx);
+ setCurrent(p->children()->at(newIdx), true);
+ }
+ }
+ else if (e->key() == Key_Right) {
+ int newIdx = goBack ? prevVisible(_current) : nextVisible(_current);
+ if (p && newIdx>=0) {
+ p->setIndex(newIdx);
+ setCurrent(p->children()->at(newIdx), true);
+ }
+ }
+ else if (e->key() == Key_Down) {
+ if (_current->children() && _current->children()->count()>0) {
+ int newIdx = _current->index();
+ if (newIdx<0)
+ newIdx = goBack ? (_current->children()->count()-1) : 0;
+ if (newIdx>=(int)_current->children()->count())
+ newIdx = _current->children()->count()-1;
+ newItem = visibleItem(_current->children()->at(newIdx));
+ setCurrent(newItem, true);
+ }
+ }
+
+ if (old == _current) return;
+ if (! (e->state() & ControlButton)) return;
+ if (! (e->state() & ShiftButton)) return;
+
+ switch(_selectionMode) {
+ case NoSelection:
+ break;
+ case Single:
+ setSelected(_current, true);
+ break;
+ case Multi:
+ setSelected(_current, !isSelected(_current));
+ break;
+ case Extended:
+ if (e->state() & ControlButton)
+ setSelected(_current, !isSelected(_current));
+ else
+ setSelected(_current, isSelected(old));
+ }
+}
+
+void TreeMapWidget::fontChange( const QFont& )
+{
+ redraw();
+}
+
+
+void TreeMapWidget::resizeEvent( QResizeEvent * )
+{
+ // this automatically redraws (as size is changed)
+ drawTreeMap();
+}
+
+void TreeMapWidget::paintEvent( QPaintEvent * )
+{
+ drawTreeMap();
+}
+
+void TreeMapWidget::showEvent( QShowEvent * )
+{
+ // refresh only if needed
+ drawTreeMap();
+}
+
+// Updates screen from shadow buffer,
+// but redraws before if needed
+void TreeMapWidget::drawTreeMap()
+{
+ // no need to draw if hidden
+ if (!isVisible()) return;
+
+ if (_pixmap.size() != size())
+ _needsRefresh = _base;
+
+ if (_needsRefresh) {
+
+ if (DEBUG_DRAWING)
+ kdDebug(90100) << "Redrawing " << _needsRefresh->path(0).join("/") << endl;
+
+ if (_needsRefresh == _base) {
+ // redraw whole widget
+ _pixmap = QPixmap(size());
+ _pixmap.fill(backgroundColor());
+ }
+ QPainter p(&_pixmap);
+ if (_needsRefresh == _base) {
+ p.setPen(black);
+ p.drawRect(QRect(2, 2, QWidget::width()-4, QWidget::height()-4));
+ _base->setItemRect(QRect(3, 3, QWidget::width()-6, QWidget::height()-6));
+ }
+ else {
+ // only subitem
+ if (!_needsRefresh->itemRect().isValid()) return;
+ }
+
+ // reset cached font object; it could have been changed
+ _font = font();
+ _fontHeight = fontMetrics().height();
+
+ drawItems(&p, _needsRefresh);
+ _needsRefresh = 0;
+ }
+
+ bitBlt( this, 0, 0, &_pixmap, 0, 0,
+ QWidget::width(), QWidget::height(), CopyROP, true);
+
+ if (hasFocus()) {
+ QPainter p(this);
+ style().drawPrimitive( QStyle::PE_FocusRect, &p,
+ QRect(0, 0, QWidget::width(), QWidget::height()),
+ colorGroup() );
+ }
+}
+
+
+
+void TreeMapWidget::redraw(TreeMapItem* i)
+{
+ if (!i) return;
+
+ if (!_needsRefresh)
+ _needsRefresh = i;
+ else {
+ if (!i->isChildOf(_needsRefresh))
+ _needsRefresh = _needsRefresh->commonParent(i);
+ }
+
+ if (isVisible()) {
+ // delayed drawing if we have multiple redraw requests
+ update();
+ }
+}
+
+void TreeMapWidget::drawItem(QPainter* p,
+ TreeMapItem* item)
+{
+ bool isSelected = false;
+ TreeMapItem* i;
+
+ if (_markNo>0) {
+ for(i = item;i;i=i->parent())
+ if (i->isMarked(_markNo)) break;
+
+ isSelected = (i!=0);
+ }
+ else {
+ for (i=_tmpSelection.first();i;i=_tmpSelection.next())
+ if (item->isChildOf(i)) break;
+
+ isSelected = (i!=0);
+ }
+
+ bool isCurrent = _current && item->isChildOf(_current);
+ int dd = item->depth();
+ if (isTransparent(dd)) return;
+
+ RectDrawing d(item->itemRect());
+ item->setSelected(isSelected);
+ item->setCurrent(isCurrent);
+ item->setShaded(_shading);
+ item->drawFrame(drawFrame(dd));
+ d.drawBack(p, item);
+}
+
+
+bool TreeMapWidget::horizontal(TreeMapItem* i, const QRect& r)
+{
+ switch(i->splitMode()) {
+ case TreeMapItem::HAlternate:
+ return (i->depth()%2)==1;
+ case TreeMapItem::VAlternate:
+ return (i->depth()%2)==0;
+ case TreeMapItem::Horizontal:
+ return true;
+ case TreeMapItem::Vertical:
+ return false;
+ default:
+ return r.width() > r.height();
+ }
+ return false;
+}
+
+
+/**
+ * Draw TreeMapItems recursive, starting from item
+ */
+void TreeMapWidget::drawItems(QPainter* p,
+ TreeMapItem* item)
+{
+ if (DEBUG_DRAWING)
+ kdDebug(90100) << "+drawItems(" << item->path(0).join("/") << ", "
+ << item->itemRect().x() << "/" << item->itemRect().y()
+ << "-" << item->itemRect().width() << "x"
+ << item->itemRect().height() << "), Val " << item->value()
+ << ", Sum " << item->sum() << endl;
+
+ drawItem(p, item);
+ item->clearFreeRects();
+
+ QRect origRect = item->itemRect();
+ int bw = item->borderWidth();
+ QRect r = QRect(origRect.x()+bw, origRect.y()+bw,
+ origRect.width()-2*bw, origRect.height()-2*bw);
+
+ TreeMapItemList* list = item->children();
+ TreeMapItem* i;
+
+ bool stopDrawing = false;
+
+ // only subdivide if there are children
+ if (!list || list->count()==0)
+ stopDrawing = true;
+
+ // only subdivide if there is enough space
+ if (!stopDrawing && (r.width()<=0 || r.height()<=0))
+ stopDrawing = true;
+
+ // stop drawing if maximum depth is reached
+ if (!stopDrawing &&
+ (_maxDrawingDepth>=0 && item->depth()>=_maxDrawingDepth))
+ stopDrawing = true;
+
+ // stop drawing if stopAtText is reached
+ if (!stopDrawing)
+ for (int no=0;no<(int)_attr.size();no++) {
+ QString stopAt = fieldStop(no);
+ if (!stopAt.isEmpty() && (item->text(no) == stopAt)) {
+ stopDrawing = true;
+ break;
+ }
+ }
+
+ // area size is checked later...
+#if 0
+ // stop drawing if minimal area size is reached
+ if (!stopDrawing &&
+ (_minimalArea > 0) &&
+ (r.width() * r.height() < _minimalArea)) stopDrawing = true;
+#endif
+
+ if (stopDrawing) {
+ if (list) {
+ // invalidate rects
+ for (i=list->first();i;i=list->next())
+ i->clearItemRect();
+ }
+ // tooltip apears on whole item rect
+ item->addFreeRect(item->itemRect());
+
+ // if we have space for text...
+ if ((r.height() < _fontHeight) || (r.width() < _fontHeight)) return;
+
+ RectDrawing d(r);
+ item->setRotated(_allowRotation && (r.height() > r.width()));
+ for (int no=0;no<(int)_attr.size();no++) {
+ if (!fieldVisible(no)) continue;
+ d.drawField(p, no, item);
+ }
+ r = d.remainingRect(item);
+
+ if (DEBUG_DRAWING)
+ kdDebug(90100) << "-drawItems(" << item->path(0).join("/") << ")" << endl;
+ return;
+ }
+
+ double user_sum, child_sum, self;
+
+ // user supplied sum
+ user_sum = item->sum();
+
+ // own sum
+ child_sum = 0;
+ for (i=list->first();i;i=list->next()) {
+ child_sum += i->value();
+ if (DEBUG_DRAWING)
+ kdDebug(90100) << " child: " << i->text(0) << ", value "
+ << i->value() << endl;
+ }
+
+ QRect orig = r;
+
+ // if we have space for text...
+ if ((r.height() >= _fontHeight) && (r.width() >= _fontHeight)) {
+
+ RectDrawing d(r);
+ item->setRotated(_allowRotation && (r.height() > r.width()));
+ for (int no=0;no<(int)_attr.size();no++) {
+ if (!fieldVisible(no)) continue;
+ if (!fieldForced(no)) continue;
+ d.drawField(p, no, item);
+ }
+ r = d.remainingRect(item);
+ }
+
+ if (orig.x() == r.x()) {
+ // Strings on top
+ item->addFreeRect(QRect(orig.x(), orig.y(),
+ orig.width(), orig.height()-r.height()));
+ }
+ else {
+ // Strings on the left
+ item->addFreeRect(QRect(orig.x(), orig.y(),
+ orig.width()-r.width(), orig.height()));
+ }
+
+ if (user_sum == 0) {
+ // user didn't supply any sum
+ user_sum = child_sum;
+ self = 0;
+ }
+ else {
+ self = user_sum - child_sum;
+
+ if (user_sum < child_sum) {
+ //kdDebug(90100) << "TreeMWidget " <<
+ // item->path() << ": User sum " << user_sum << " < Child Items sum " << child_sum << endl;
+
+ // invalid user supplied sum: ignore and use calculate sum
+ user_sum = child_sum;
+ self = 0.0;
+ }
+ else {
+ // Try to put the border waste in self
+ // percent of wasted space on border...
+ float borderArea = origRect.width() * origRect.height();
+ borderArea = (borderArea - r.width()*r.height())/borderArea;
+ unsigned borderValue = (unsigned)(borderArea * user_sum);
+
+ if (borderValue > self) {
+ if (_skipIncorrectBorder) {
+ r = origRect;
+ // should add my self to nested self and set my self =0
+ }
+ else
+ self = 0.0;
+ }
+ else
+ self -= borderValue;
+
+ user_sum = child_sum + self;
+ }
+ }
+
+ bool rotate = (_allowRotation && (r.height() > r.width()));
+ int self_length = (int)( ((rotate) ? r.width() : r.height()) *
+ self / user_sum + .5);
+ if (self_length > 0) {
+ // take space for self cost
+ QRect sr = r;
+ if (rotate) {
+ sr.setWidth( self_length );
+ r.setRect(r.x()+sr.width(), r.y(), r.width()-sr.width(), r.height());
+ }
+ else {
+ sr.setHeight( self_length );
+ r.setRect(r.x(), r.y()+sr.height(), r.width(), r.height()-sr.height());
+ }
+
+ // set selfRect (not occupied by children) for tooltip
+ item->addFreeRect(sr);
+
+ if (0) kdDebug(90100) << "Item " << item->path(0).join("/") << ": SelfR "
+ << sr.x() << "/" << sr.y() << "-" << sr.width()
+ << "/" << sr.height() << ", self " << self << "/"
+ << user_sum << endl;
+
+ if ((sr.height() >= _fontHeight) && (sr.width() >= _fontHeight)) {
+
+ RectDrawing d(sr);
+ item->setRotated(_allowRotation && (r.height() > r.width()));
+ for (int no=0;no<(int)_attr.size();no++) {
+ if (!fieldVisible(no)) continue;
+ if (fieldForced(no)) continue;
+ d.drawField(p, no, item);
+ }
+ }
+
+ user_sum -= self;
+ }
+
+ bool goBack;
+ if (item->sorting(&goBack) == -1) {
+ // noSorting
+ goBack = false;
+ }
+
+ TreeMapItemListIterator it(*list);
+ if (goBack) it.toLast();
+
+ if (item->splitMode() == TreeMapItem::Columns) {
+ int len = list->count();
+ bool drawDetails = true;
+
+ while (len>0 && user_sum>0) {
+ TreeMapItemListIterator first = it;
+ double valSum = 0;
+ int lenLeft = len;
+ int columns = (int)(sqrt((double)len * r.width()/r.height())+.5);
+ if (columns==0) columns = 1; //should never be needed
+
+ while (lenLeft>0 && ((double)valSum*(len-lenLeft) <
+ (double)len*user_sum/columns/columns)) {
+ valSum += it.current()->value();
+ if (goBack) --it; else ++it;
+ lenLeft--;
+ }
+
+ // we always split horizontally
+ int nextPos = (int)((double)r.width() * valSum / user_sum);
+ QRect firstRect = QRect(r.x(), r.y(), nextPos, r.height());
+
+ if (nextPos < _visibleWidth) {
+ if (item->sorting(0) == -1) {
+ // fill current rect with hash pattern
+ drawFill(item, p, firstRect);
+ }
+ else {
+ // fill rest with hash pattern
+ drawFill(item, p, r, first, len, goBack);
+ break;
+ }
+ }
+ else {
+ drawDetails = drawItemArray(p, item, firstRect,
+ valSum, first, len-lenLeft, goBack);
+ }
+ r.setRect(r.x()+nextPos, r.y(), r.width()-nextPos, r.height());
+ user_sum -= valSum;
+ len = lenLeft;
+
+ if (!drawDetails) {
+ if (item->sorting(0) == -1)
+ drawDetails = true;
+ else {
+ drawFill(item, p, r, it, len, goBack);
+ break;
+ }
+ }
+ }
+ }
+ else if (item->splitMode() == TreeMapItem::Rows) {
+ int len = list->count();
+ bool drawDetails = true;
+
+ while (len>0 && user_sum>0) {
+ TreeMapItemListIterator first = it;
+ double valSum = 0;
+ int lenLeft = len;
+ int rows = (int)(sqrt((double)len * r.height()/r.width())+.5);
+ if (rows==0) rows = 1; //should never be needed
+
+ while (lenLeft>0 && ((double)valSum*(len-lenLeft) <
+ (double)len*user_sum/rows/rows)) {
+ valSum += it.current()->value();
+ if (goBack) --it; else ++it;
+ lenLeft--;
+ }
+
+ // we always split horizontally
+ int nextPos = (int)((double)r.height() * valSum / user_sum);
+ QRect firstRect = QRect(r.x(), r.y(), r.width(), nextPos);
+
+ if (nextPos < _visibleWidth) {
+ if (item->sorting(0) == -1) {
+ drawFill(item, p, firstRect);
+ }
+ else {
+ drawFill(item, p, r, first, len, goBack);
+ break;
+ }
+ }
+ else {
+ drawDetails = drawItemArray(p, item, firstRect,
+ valSum, first, len-lenLeft, goBack);
+ }
+ r.setRect(r.x(), r.y()+nextPos, r.width(), r.height()-nextPos);
+ user_sum -= valSum;
+ len = lenLeft;
+
+ if (!drawDetails) {
+ if (item->sorting(0) == -1)
+ drawDetails = true;
+ else {
+ drawFill(item, p, r, it, len, goBack);
+ break;
+ }
+ }
+ }
+ }
+ else
+ drawItemArray(p, item, r, user_sum, it, list->count(), goBack);
+
+ if (DEBUG_DRAWING)
+ kdDebug(90100) << "-drawItems(" << item->path(0).join("/") << ")" << endl;
+}
+
+// fills area with a pattern if to small to draw children
+void TreeMapWidget::drawFill(TreeMapItem* i, QPainter* p, QRect& r)
+{
+ p->setBrush(Qt::Dense4Pattern);
+ p->setPen(Qt::NoPen);
+ p->drawRect(r);
+ i->addFreeRect(r);
+}
+
+// fills area with a pattern if to small to draw children
+void TreeMapWidget::drawFill(TreeMapItem* i, QPainter* p, QRect& r,
+ TreeMapItemListIterator it, int len, bool goBack)
+{
+ if (DEBUG_DRAWING)
+ kdDebug(90100) << " +drawFill(" << r.x() << "/" << r.y()
+ << "-" << r.width() << "x" << r.height()
+ << ", len " << len << ")" << endl;
+
+ p->setBrush(Qt::Dense4Pattern);
+ p->setPen(Qt::NoPen);
+ p->drawRect(r);
+ i->addFreeRect(r);
+
+ // reset rects
+ while (len>0 && it.current()) {
+
+ if (DEBUG_DRAWING)
+ kdDebug(90100) << " Reset Rect " << (*it)->path(0).join("/") << endl;
+
+ (*it)->clearItemRect();
+ if (goBack) --it; else ++it;
+ len--;
+ }
+ if (DEBUG_DRAWING)
+ kdDebug(90100) << " -drawFill(" << r.x() << "/" << r.y()
+ << "-" << r.width() << "x" << r.height()
+ << ", len " << len << ")" << endl;
+}
+
+// returns false if rect gets to small
+bool TreeMapWidget::drawItemArray(QPainter* p, TreeMapItem* item,
+ QRect& r, double user_sum,
+ TreeMapItemListIterator it, int len,
+ bool goBack)
+{
+ if (user_sum == 0) return false;
+
+ static bool b2t = true;
+
+ // stop recursive bisection for small rectangles
+ if (((r.height() < _visibleWidth) &&
+ (r.width() < _visibleWidth)) ||
+ ((_minimalArea > 0) &&
+ (r.width() * r.height() < _minimalArea))) {
+
+ drawFill(item, p, r, it, len, goBack);
+ return false;
+ }
+
+ if (DEBUG_DRAWING)
+ kdDebug(90100) << " +drawItemArray(" << item->path(0).join("/")
+ << ", " << r.x() << "/" << r.y() << "-" << r.width()
+ << "x" << r.height() << ")" << endl;
+
+ if (len>2 && (item->splitMode() == TreeMapItem::Bisection)) {
+
+ TreeMapItemListIterator first = it;
+ double valSum = 0;
+ int lenLeft = len;
+ //while (lenLeft>0 && valSum<user_sum/2) {
+ while (lenLeft>len/2) {
+ valSum += it.current()->value();
+ if (goBack) --it; else ++it;
+ lenLeft--;
+ }
+
+ // draw first half...
+ bool drawOn;
+
+ if (r.width() > r.height()) {
+ int halfPos = (int)((double)r.width() * valSum / user_sum);
+ QRect firstRect = QRect(r.x(), r.y(), halfPos, r.height());
+ drawOn = drawItemArray(p, item, firstRect,
+ valSum, first, len-lenLeft, goBack);
+ r.setRect(r.x()+halfPos, r.y(), r.width()-halfPos, r.height());
+ }
+ else {
+ int halfPos = (int)((double)r.height() * valSum / user_sum);
+ QRect firstRect = QRect(r.x(), r.y(), r.width(), halfPos);
+ drawOn = drawItemArray(p, item, firstRect,
+ valSum, first, len-lenLeft, goBack);
+ r.setRect(r.x(), r.y()+halfPos, r.width(), r.height()-halfPos);
+ }
+
+ // if no sorting, don't stop drawing
+ if (item->sorting(0) == -1) drawOn = true;
+
+ // second half
+ if (drawOn)
+ drawOn = drawItemArray(p, item, r, user_sum - valSum,
+ it, lenLeft, goBack);
+ else {
+ drawFill(item, p, r, it, len, goBack);
+ }
+
+ if (DEBUG_DRAWING)
+ kdDebug(90100) << " -drawItemArray(" << item->path(0).join("/")
+ << ")" << endl;
+
+ return drawOn;
+ }
+
+ bool hor = horizontal(item,r);
+
+ TreeMapItem* i;
+ while (len>0) {
+ i = it.current();
+ if (user_sum <= 0) {
+
+ if (DEBUG_DRAWING)
+ kdDebug(90100) << "drawItemArray: Reset " << i->path(0).join("/") << endl;
+
+ i->clearItemRect();
+ if (goBack) --it; else ++it;
+ len--;
+ continue;
+ }
+
+ // stop drawing for small rectangles
+ if (((r.height() < _visibleWidth) &&
+ (r.width() < _visibleWidth)) ||
+ ((_minimalArea > 0) &&
+ (r.width() * r.height() < _minimalArea))) {
+
+ drawFill(item, p, r, it, len, goBack);
+ if (DEBUG_DRAWING)
+ kdDebug(90100) << " -drawItemArray(" << item->path(0).join("/")
+ << "): Stop" << endl;
+ return false;
+ }
+
+ if (i->splitMode() == TreeMapItem::AlwaysBest)
+ hor = r.width() > r.height();
+
+ int lastPos = hor ? r.width() : r.height();
+ double val = i->value();
+ int nextPos = (user_sum <= 0.0) ? 0: (int)(lastPos * val / user_sum +.5);
+ if (nextPos>lastPos) nextPos = lastPos;
+
+ if ((item->sorting(0) != -1) && (nextPos < _visibleWidth)) {
+ drawFill(item, p, r, it, len, goBack);
+ if (DEBUG_DRAWING)
+ kdDebug(90100) << " -drawItemArray(" << item->path(0).join("/")
+ << "): Stop" << endl;
+ return false;
+ }
+
+ QRect currRect = r;
+
+ if (hor)
+ currRect.setWidth(nextPos);
+ else {
+ if (b2t)
+ currRect.setRect(r.x(), r.bottom()-nextPos+1, r.width(), nextPos);
+ else
+ currRect.setHeight(nextPos);
+ }
+
+ // don't draw very small rectangles:
+ if (nextPos >= _visibleWidth) {
+ i->setItemRect(currRect);
+ drawItems(p, i);
+ }
+ else {
+ i->clearItemRect();
+ drawFill(item, p, currRect);
+ }
+
+ // draw Separator
+ if (_drawSeparators && (nextPos<lastPos)) {
+ p->setPen(black);
+ if (hor) {
+ if (r.top()<=r.bottom())
+ p->drawLine(r.x() + nextPos, r.top(), r.x() + nextPos, r.bottom());
+ }
+ else {
+ if (r.left()<=r.right())
+ p->drawLine(r.left(), r.y() + nextPos, r.right(), r.y() + nextPos);
+ }
+ nextPos++;
+ }
+
+ if (hor)
+ r.setRect(r.x() + nextPos, r.y(), lastPos-nextPos, r.height());
+ else {
+ if (b2t)
+ r.setRect(r.x(), r.y(), r.width(), lastPos-nextPos);
+ else
+ r.setRect(r.x(), r.y() + nextPos, r.width(), lastPos-nextPos);
+ }
+
+ user_sum -= val;
+ if (goBack) --it; else ++it;
+ len--;
+ }
+
+ if (DEBUG_DRAWING)
+ kdDebug(90100) << " -drawItemArray(" << item->path(0).join("/")
+ << "): Continue" << endl;
+
+ return true;
+}
+
+
+/*----------------------------------------------------------------
+ * Popup menus for option setting
+ */
+
+void TreeMapWidget::splitActivated(int id)
+{
+ if (id == _splitID) setSplitMode(TreeMapItem::Bisection);
+ else if (id == _splitID+1) setSplitMode(TreeMapItem::Columns);
+ else if (id == _splitID+2) setSplitMode(TreeMapItem::Rows);
+ else if (id == _splitID+3) setSplitMode(TreeMapItem::AlwaysBest);
+ else if (id == _splitID+4) setSplitMode(TreeMapItem::Best);
+ else if (id == _splitID+5) setSplitMode(TreeMapItem::VAlternate);
+ else if (id == _splitID+6) setSplitMode(TreeMapItem::HAlternate);
+ else if (id == _splitID+7) setSplitMode(TreeMapItem::Horizontal);
+ else if (id == _splitID+8) setSplitMode(TreeMapItem::Vertical);
+}
+
+
+void TreeMapWidget::addSplitDirectionItems(QPopupMenu* popup, int id)
+{
+ _splitID = id;
+ popup->setCheckable(true);
+
+ connect(popup, SIGNAL(activated(int)),
+ this, SLOT(splitActivated(int)));
+
+ popup->insertItem(i18n("Recursive Bisection"), id);
+ popup->insertItem(i18n("Columns"), id+1);
+ popup->insertItem(i18n("Rows"), id+2);
+ popup->insertItem(i18n("Always Best"), id+3);
+ popup->insertItem(i18n("Best"), id+4);
+ popup->insertItem(i18n("Alternate (V)"), id+5);
+ popup->insertItem(i18n("Alternate (H)"), id+6);
+ popup->insertItem(i18n("Horizontal"), id+7);
+ popup->insertItem(i18n("Vertical"), id+8);
+
+ switch(splitMode()) {
+ case TreeMapItem::Bisection: popup->setItemChecked(id,true); break;
+ case TreeMapItem::Columns: popup->setItemChecked(id+1,true); break;
+ case TreeMapItem::Rows: popup->setItemChecked(id+2,true); break;
+ case TreeMapItem::AlwaysBest: popup->setItemChecked(id+3,true); break;
+ case TreeMapItem::Best: popup->setItemChecked(id+4,true); break;
+ case TreeMapItem::VAlternate: popup->setItemChecked(id+5,true); break;
+ case TreeMapItem::HAlternate: popup->setItemChecked(id+6,true); break;
+ case TreeMapItem::Horizontal: popup->setItemChecked(id+7,true); break;
+ case TreeMapItem::Vertical: popup->setItemChecked(id+8,true); break;
+ default: break;
+ }
+}
+
+void TreeMapWidget::visualizationActivated(int id)
+{
+ if (id == _visID+2) setSkipIncorrectBorder(!skipIncorrectBorder());
+ else if (id == _visID+3) setBorderWidth(0);
+ else if (id == _visID+4) setBorderWidth(1);
+ else if (id == _visID+5) setBorderWidth(2);
+ else if (id == _visID+6) setBorderWidth(3);
+ else if (id == _visID+10) setAllowRotation(!allowRotation());
+ else if (id == _visID+11) setShadingEnabled(!isShadingEnabled());
+ else if (id<_visID+19 || id>_visID+100) return;
+
+ id -= 20+_visID;
+ int f = id/10;
+ if ((id%10) == 1) setFieldVisible(f, !fieldVisible(f));
+ else if ((id%10) == 2) setFieldForced(f, !fieldForced(f));
+ else if ((id%10) == 3) setFieldPosition(f, DrawParams::TopLeft);
+ else if ((id%10) == 4) setFieldPosition(f, DrawParams::TopCenter);
+ else if ((id%10) == 5) setFieldPosition(f, DrawParams::TopRight);
+ else if ((id%10) == 6) setFieldPosition(f, DrawParams::BottomLeft);
+ else if ((id%10) == 7) setFieldPosition(f, DrawParams::BottomCenter);
+ else if ((id%10) == 8) setFieldPosition(f, DrawParams::BottomRight);
+}
+
+void TreeMapWidget::addVisualizationItems(QPopupMenu* popup, int id)
+{
+ _visID = id;
+
+ popup->setCheckable(true);
+
+ QPopupMenu* bpopup = new QPopupMenu();
+ bpopup->setCheckable(true);
+
+ connect(popup, SIGNAL(activated(int)),
+ this, SLOT(visualizationActivated(int)));
+ connect(bpopup, SIGNAL(activated(int)),
+ this, SLOT(visualizationActivated(int)));
+
+ QPopupMenu* spopup = new QPopupMenu();
+ addSplitDirectionItems(spopup, id+100);
+ popup->insertItem(i18n("Nesting"), spopup, id);
+
+ popup->insertItem(i18n("Border"), bpopup, id+1);
+ bpopup->insertItem(i18n("Correct Borders Only"), id+2);
+ bpopup->insertSeparator();
+ bpopup->insertItem(i18n("Width %1").arg(0), id+3);
+ bpopup->insertItem(i18n("Width %1").arg(1), id+4);
+ bpopup->insertItem(i18n("Width %1").arg(2), id+5);
+ bpopup->insertItem(i18n("Width %1").arg(3), id+6);
+ bpopup->setItemChecked(id+2, skipIncorrectBorder());
+ bpopup->setItemChecked(id+3, borderWidth()==0);
+ bpopup->setItemChecked(id+4, borderWidth()==1);
+ bpopup->setItemChecked(id+5, borderWidth()==2);
+ bpopup->setItemChecked(id+6, borderWidth()==3);
+
+ popup->insertItem(i18n("Allow Rotation"), id+10);
+ popup->setItemChecked(id+10,allowRotation());
+ popup->insertItem(i18n("Shading"), id+11);
+ popup->setItemChecked(id+11,isShadingEnabled());
+
+ if (_attr.size() ==0) return;
+
+ popup->insertSeparator();
+ int f;
+ QPopupMenu* tpopup;
+ id += 20;
+ for (f=0;f<(int)_attr.size();f++, id+=10) {
+ tpopup = new QPopupMenu();
+ tpopup->setCheckable(true);
+ popup->insertItem(_attr[f].type, tpopup, id);
+ tpopup->insertItem(i18n("Visible"), id+1);
+ tpopup->insertItem(i18n("Take Space From Children"), id+2);
+ tpopup->insertSeparator();
+ tpopup->insertItem(i18n("Top Left"), id+3);
+ tpopup->insertItem(i18n("Top Center"), id+4);
+ tpopup->insertItem(i18n("Top Right"), id+5);
+ tpopup->insertItem(i18n("Bottom Left"), id+6);
+ tpopup->insertItem(i18n("Bottom Center"), id+7);
+ tpopup->insertItem(i18n("Bottom Right"), id+8);
+
+ tpopup->setItemChecked(id+1,_attr[f].visible);
+ tpopup->setItemEnabled(id+2,_attr[f].visible);
+ tpopup->setItemEnabled(id+3,_attr[f].visible);
+ tpopup->setItemEnabled(id+4,_attr[f].visible);
+ tpopup->setItemEnabled(id+5,_attr[f].visible);
+ tpopup->setItemEnabled(id+6,_attr[f].visible);
+ tpopup->setItemEnabled(id+7,_attr[f].visible);
+ tpopup->setItemEnabled(id+8,_attr[f].visible);
+ tpopup->setItemChecked(id+2,_attr[f].forced);
+ tpopup->setItemChecked(id+3,_attr[f].pos == DrawParams::TopLeft);
+ tpopup->setItemChecked(id+4,_attr[f].pos == DrawParams::TopCenter);
+ tpopup->setItemChecked(id+5,_attr[f].pos == DrawParams::TopRight);
+ tpopup->setItemChecked(id+6,_attr[f].pos == DrawParams::BottomLeft);
+ tpopup->setItemChecked(id+7,_attr[f].pos == DrawParams::BottomCenter);
+ tpopup->setItemChecked(id+8,_attr[f].pos == DrawParams::BottomRight);
+
+ connect(tpopup, SIGNAL(activated(int)),
+ this, SLOT(visualizationActivated(int)));
+ }
+}
+
+void TreeMapWidget::selectionActivated(int id)
+{
+ TreeMapItem* i = _menuItem;
+ id -= _selectionID;
+ while (id>0 && i) {
+ i=i->parent();
+ id--;
+ }
+ if (i)
+ setSelected(i, true);
+}
+
+void TreeMapWidget::addSelectionItems(QPopupMenu* popup,
+ int id, TreeMapItem* i)
+{
+ if (!i) return;
+
+ _selectionID = id;
+ _menuItem = i;
+
+ connect(popup, SIGNAL(activated(int)),
+ this, SLOT(selectionActivated(int)));
+
+ while (i) {
+ QString name = i->text(0);
+ if (name.isEmpty()) break;
+ popup->insertItem(i->text(0), id++);
+ i = i->parent();
+ }
+}
+
+void TreeMapWidget::fieldStopActivated(int id)
+{
+ if (id == _fieldStopID) setFieldStop(0, QString::null);
+ else {
+ TreeMapItem* i = _menuItem;
+ id -= _fieldStopID+1;
+ while (id>0 && i) {
+ i=i->parent();
+ id--;
+ }
+ if (i)
+ setFieldStop(0, i->text(0));
+ }
+}
+
+void TreeMapWidget::addFieldStopItems(QPopupMenu* popup,
+ int id, TreeMapItem* i)
+{
+ _fieldStopID = id;
+
+ connect(popup, SIGNAL(activated(int)),
+ this, SLOT(fieldStopActivated(int)));
+
+ popup->insertItem(i18n("No %1 Limit").arg(fieldType(0)), id);
+ popup->setItemChecked(id, fieldStop(0).isEmpty());
+ _menuItem = i;
+ bool foundFieldStop = false;
+ if (i) {
+ popup->insertSeparator();
+
+ while (i) {
+ id++;
+ QString name = i->text(0);
+ if (name.isEmpty()) break;
+ popup->insertItem(i->text(0), id);
+ if (fieldStop(0) == i->text(0)) {
+ popup->setItemChecked(id, true);
+ foundFieldStop = true;
+ }
+ i = i->parent();
+ }
+ }
+
+ if (!foundFieldStop && !fieldStop(0).isEmpty()) {
+ popup->insertSeparator();
+ popup->insertItem(fieldStop(0), id+1);
+ popup->setItemChecked(id+1, true);
+ }
+}
+
+void TreeMapWidget::areaStopActivated(int id)
+{
+ if (id == _areaStopID) setMinimalArea(-1);
+ else if (id == _areaStopID+1) {
+ int area = _menuItem ? (_menuItem->width() * _menuItem->height()) : -1;
+ setMinimalArea(area);
+ }
+ else if (id == _areaStopID+2) setMinimalArea(100);
+ else if (id == _areaStopID+3) setMinimalArea(400);
+ else if (id == _areaStopID+4) setMinimalArea(1000);
+ else if (id == _areaStopID+5) setMinimalArea(minimalArea()*2);
+ else if (id == _areaStopID+6) setMinimalArea(minimalArea()/2);
+}
+
+void TreeMapWidget::addAreaStopItems(QPopupMenu* popup,
+ int id, TreeMapItem* i)
+{
+ _areaStopID = id;
+ _menuItem = i;
+
+ connect(popup, SIGNAL(activated(int)),
+ this, SLOT(areaStopActivated(int)));
+
+ bool foundArea = false;
+
+ popup->insertItem(i18n("No Area Limit"), id);
+ popup->setItemChecked(id, minimalArea() == -1);
+
+ if (i) {
+ int area = i->width() * i->height();
+ popup->insertSeparator();
+ popup->insertItem(i18n("Area of '%1' (%2)")
+ .arg(i->text(0)).arg(area), id+1);
+ if (area == minimalArea()) {
+ popup->setItemChecked(id+1, true);
+ foundArea = true;
+ }
+ }
+
+ popup->insertSeparator();
+ int area = 100, count;
+ for (count=0;count<3;count++) {
+ popup->insertItem(i18n("1 Pixel", "%n Pixels", area), id+2+count);
+ if (area == minimalArea()) {
+ popup->setItemChecked(id+2+count, true);
+ foundArea = true;
+ }
+ area = (area==100) ? 400 : (area==400) ? 1000 : 4000;
+ }
+
+ if (minimalArea()>0) {
+ popup->insertSeparator();
+ if (!foundArea) {
+ popup->insertItem(i18n("1 Pixel", "%n Pixels", minimalArea()), id+10);
+ popup->setItemChecked(id+10, true);
+ }
+
+ popup->insertItem(i18n("Double Area Limit (to %1)")
+ .arg(minimalArea()*2), id+5);
+ popup->insertItem(i18n("Halve Area Limit (to %1)")
+ .arg(minimalArea()/2), id+6);
+ }
+}
+
+
+void TreeMapWidget::depthStopActivated(int id)
+{
+ if (id == _depthStopID) setMaxDrawingDepth(-1);
+ else if (id == _depthStopID+1) {
+ int d = _menuItem ? _menuItem->depth() : -1;
+ setMaxDrawingDepth(d);
+ }
+ else if (id == _depthStopID+2) setMaxDrawingDepth(maxDrawingDepth()-1);
+ else if (id == _depthStopID+3) setMaxDrawingDepth(maxDrawingDepth()+1);
+}
+
+void TreeMapWidget::addDepthStopItems(QPopupMenu* popup,
+ int id, TreeMapItem* i)
+{
+ _depthStopID = id;
+ _menuItem = i;
+
+ connect(popup, SIGNAL(activated(int)),
+ this, SLOT(depthStopActivated(int)));
+
+ bool foundDepth = false;
+
+ popup->insertItem(i18n("No Depth Limit"), id);
+ popup->setItemChecked(id, maxDrawingDepth() == -1);
+
+ if (i) {
+ int d = i->depth();
+ popup->insertSeparator();
+ popup->insertItem(i18n("Depth of '%1' (%2)")
+ .arg(i->text(0)).arg(d), id+1);
+ if (d == maxDrawingDepth()) {
+ popup->setItemChecked(id+1, true);
+ foundDepth = true;
+ }
+ }
+
+ if (maxDrawingDepth()>1) {
+ popup->insertSeparator();
+ if (!foundDepth) {
+ popup->insertItem(i18n("Depth %1").arg(maxDrawingDepth()), id+10);
+ popup->setItemChecked(id+10, true);
+ }
+
+ popup->insertItem(i18n("Decrement (to %1)")
+ .arg(maxDrawingDepth()-1), id+2);
+ popup->insertItem(i18n("Increment (to %1)")
+ .arg(maxDrawingDepth()+1), id+3);
+ }
+}
+
+
+
+/*----------------------------------------------------------------
+ * Option saving/restoring
+ */
+
+void TreeMapWidget::saveOptions(KConfigGroup* config, QString prefix)
+{
+ config->writeEntry(prefix+"Nesting", splitModeString());
+ config->writeEntry(prefix+"AllowRotation", allowRotation());
+ config->writeEntry(prefix+"ShadingEnabled", isShadingEnabled());
+ config->writeEntry(prefix+"OnlyCorrectBorder", skipIncorrectBorder());
+ config->writeEntry(prefix+"BorderWidth", borderWidth());
+ config->writeEntry(prefix+"MaxDepth", maxDrawingDepth());
+ config->writeEntry(prefix+"MinimalArea", minimalArea());
+
+ int f, fCount = _attr.size();
+ config->writeEntry(prefix+"FieldCount", fCount);
+ for (f=0;f<fCount;f++) {
+ config->writeEntry(QString(prefix+"FieldVisible%1").arg(f),
+ _attr[f].visible);
+ config->writeEntry(QString(prefix+"FieldForced%1").arg(f),
+ _attr[f].forced);
+ config->writeEntry(QString(prefix+"FieldStop%1").arg(f),
+ _attr[f].stop);
+ config->writeEntry(QString(prefix+"FieldPosition%1").arg(f),
+ fieldPositionString(f));
+ }
+}
+
+
+void TreeMapWidget::restoreOptions(KConfigGroup* config, QString prefix)
+{
+ bool enabled;
+ int num;
+ QString str;
+
+ str = config->readEntry(prefix+"Nesting");
+ if (!str.isEmpty()) setSplitMode(str);
+
+ if (config->hasKey(prefix+"AllowRotation")) {
+ enabled = config->readBoolEntry(prefix+"AllowRotation", true);
+ setAllowRotation(enabled);
+ }
+
+ if (config->hasKey(prefix+"ShadingEnabled")) {
+ enabled = config->readBoolEntry(prefix+"ShadingEnabled", true);
+ setShadingEnabled(enabled);
+ }
+
+ if (config->hasKey(prefix+"OnlyCorrectBorder")) {
+ enabled = config->readBoolEntry(prefix+"OnlyCorrectBorder", false);
+ setSkipIncorrectBorder(enabled);
+ }
+
+ num = config->readNumEntry(prefix+"BorderWidth", -2);
+ if (num!=-2) setBorderWidth(num);
+
+ num = config->readNumEntry(prefix+"MaxDepth", -2);
+ if (num!=-2) setMaxDrawingDepth(num);
+
+ num = config->readNumEntry(prefix+"MinimalArea", -2);
+ if (num!=-2) setMinimalArea(num);
+
+ num = config->readNumEntry(prefix+"FieldCount", -2);
+ if (num<=0 || num>MAX_FIELD) return;
+
+ int f;
+ for (f=0;f<num;f++) {
+ str = QString(prefix+"FieldVisible%1").arg(f);
+ if (config->hasKey(str))
+ setFieldVisible(f, config->readBoolEntry(str));
+
+ str = QString(prefix+"FieldForced%1").arg(f);
+ if (config->hasKey(str))
+ setFieldForced(f, config->readBoolEntry(str));
+
+ str = config->readEntry(QString(prefix+"FieldStop%1").arg(f));
+ setFieldStop(f, str);
+
+ str = config->readEntry(QString(prefix+"FieldPosition%1").arg(f));
+ if (!str.isEmpty()) setFieldPosition(f, str);
+ }
+}
+
+#include "treemap.moc"
diff --git a/kcachegrind/kcachegrind/treemap.h b/kcachegrind/kcachegrind/treemap.h
new file mode 100644
index 00000000..4bb0b4cd
--- /dev/null
+++ b/kcachegrind/kcachegrind/treemap.h
@@ -0,0 +1,758 @@
+/* This file is part of KCachegrind.
+ Copyright (C) 2002, 2003 Josef Weidendorfer <Josef.Weidendorfer@gmx.de>
+
+ KCachegrind is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public
+ License as published by the Free Software Foundation, version 2.
+
+ 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; see the file COPYING. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+/**
+ * A Widget for visualizing hierarchical metrics as areas.
+ * The API is similar to QListView.
+ *
+ * This file defines the following classes:
+ * DrawParams, RectDrawing, TreeMapItem, TreeMapWidget
+ *
+ * DrawParams/RectDrawing allows reusing of TreeMap drawing
+ * functions in other widgets.
+ */
+
+#ifndef TREEMAP_H
+#define TREEMAP_H
+
+#include <qstring.h>
+#include <qwidget.h>
+#include <qpixmap.h>
+#include <qptrlist.h>
+#include <qvaluevector.h>
+#include <qcolor.h>
+#include <qapplication.h>
+#include <qstringlist.h>
+
+class QPopupMenu;
+class TreeMapTip;
+class TreeMapWidget;
+class TreeMapItem;
+class TreeMapItemList;
+class QString;
+
+class KConfigGroup;
+
+
+/**
+ * Drawing parameters for an object.
+ * A Helper Interface for RectDrawing.
+ */
+class DrawParams
+{
+public:
+ /**
+ * Positions for drawing into a rectangle.
+ *
+ * The specified position assumes no rotation.
+ * If there is more than one text for one position, it is put
+ * nearer to the center of the item.
+ *
+ * Drawing at top positions cuts free space from top,
+ * drawing at bottom positions cuts from bottom.
+ * Default usually gives positions clockwise according to field number.
+ */
+ enum Position { TopLeft, TopCenter, TopRight,
+ BottomLeft, BottomCenter, BottomRight,
+ Default, Unknown};
+
+ // no constructor as this is an abstract class
+ virtual ~DrawParams() {}
+
+ virtual QString text(int) const = 0;
+ virtual QPixmap pixmap(int) const = 0;
+ virtual Position position(int) const = 0;
+ // 0: no limit, negative: leave at least -maxLines() free
+ virtual int maxLines(int) const { return 0; }
+ virtual int fieldCount() const { return 0; }
+
+ virtual QColor backColor() const { return Qt::white; }
+ virtual const QFont& font() const = 0;
+
+ virtual bool selected() const { return false; }
+ virtual bool current() const { return false; }
+ virtual bool shaded() const { return true; }
+ virtual bool rotated() const { return false; }
+ virtual bool drawFrame() const { return true; }
+};
+
+
+/*
+ * DrawParam with attributes stored
+ */
+class StoredDrawParams: public DrawParams
+{
+public:
+ StoredDrawParams();
+ StoredDrawParams(QColor c,
+ bool selected = false, bool current = false);
+
+ // getters
+ QString text(int) const;
+ QPixmap pixmap(int) const;
+ Position position(int) const;
+ int maxLines(int) const;
+ int fieldCount() const { return _field.size(); }
+
+ QColor backColor() const { return _backColor; }
+ bool selected() const { return _selected; }
+ bool current() const { return _current; }
+ bool shaded() const { return _shaded; }
+ bool rotated() const { return _rotated; }
+ bool drawFrame() const { return _drawFrame; }
+
+ const QFont& font() const;
+
+ // attribute setters
+ void setField(int f, const QString& t, QPixmap pm = QPixmap(),
+ Position p = Default, int maxLines = 0);
+ void setText(int f, const QString&);
+ void setPixmap(int f, const QPixmap&);
+ void setPosition(int f, Position);
+ void setMaxLines(int f, int);
+ void setBackColor(const QColor& c) { _backColor = c; }
+ void setSelected(bool b) { _selected = b; }
+ void setCurrent(bool b) { _current = b; }
+ void setShaded(bool b) { _shaded = b; }
+ void setRotated(bool b) { _rotated = b; }
+ void drawFrame(bool b) { _drawFrame = b; }
+
+protected:
+ QColor _backColor;
+ bool _selected :1;
+ bool _current :1;
+ bool _shaded :1;
+ bool _rotated :1;
+ bool _drawFrame :1;
+
+private:
+ // resize field array if needed to allow to access field <f>
+ void ensureField(int f);
+
+ struct Field {
+ QString text;
+ QPixmap pix;
+ Position pos;
+ int maxLines;
+ };
+
+ QValueVector<Field> _field;
+};
+
+
+/* State for drawing on a rectangle.
+ *
+ * Following drawing functions are provided:
+ * - background drawing with shading and 3D frame
+ * - successive pixmap/text drawing at various positions with wrap-around
+ * optimized for minimal space usage (e.g. if a text is drawn at top right
+ * after text on top left, the same line is used if space allows)
+ *
+ */
+class RectDrawing
+{
+public:
+ RectDrawing(QRect);
+ ~RectDrawing();
+
+ // The default DrawParams object used.
+ DrawParams* drawParams();
+ // we take control over the given object (i.e. delete at destruction)
+ void setDrawParams(DrawParams*);
+
+ // draw on a given QPainter, use this class as info provider per default
+ void drawBack(QPainter*, DrawParams* dp = 0);
+ /* Draw field at position() from pixmap()/text() with maxLines().
+ * Returns true if something was drawn
+ */
+ bool drawField(QPainter*, int f, DrawParams* dp = 0);
+
+ // resets rectangle for free space
+ void setRect(QRect);
+
+ // Returns the rectangle area still free of text/pixmaps after
+ // a number of drawText() calls.
+ QRect remainingRect(DrawParams* dp = 0);
+
+private:
+ int _usedTopLeft, _usedTopCenter, _usedTopRight;
+ int _usedBottomLeft, _usedBottomCenter, _usedBottomRight;
+ QRect _rect;
+
+ // temporary
+ int _fontHeight;
+ QFontMetrics* _fm;
+ DrawParams* _dp;
+};
+
+
+class TreeMapItemList: public QPtrList<TreeMapItem>
+{
+public:
+ TreeMapItem* commonParent();
+protected:
+ int compareItems ( Item item1, Item item2 );
+};
+
+typedef QPtrListIterator<TreeMapItem> TreeMapItemListIterator;
+
+
+/**
+ * Base class of items in TreeMap.
+ *
+ * This class supports an arbitrary number of text() strings
+ * positioned counterclock-wise starting at TopLeft. Each item
+ * has its own static value(), sum() and sorting(). The
+ * splitMode() and borderWidth() is taken from a TreeMapWidget.
+ *
+ * If you want more flexibility, reimplement TreeMapItem and
+ * override the corresponding methods. For dynamic creation of child
+ * items on demand, reimplement children().
+ */
+class TreeMapItem: public StoredDrawParams
+{
+public:
+
+ /**
+ * Split direction for nested areas:
+ * AlwaysBest: Choose split direction for every subitem according to
+ * longest side of rectangle left for drawing
+ * Best: Choose split direction for all subitems of an area
+ * depending on longest side
+ * HAlternate: Horizontal at top; alternate direction on depth step
+ * VAlternate: Vertical at top; alternate direction on depth step
+ * Horizontal: Always horizontal split direction
+ * Vertical: Always vertical split direction
+ */
+ enum SplitMode { Bisection, Columns, Rows,
+ AlwaysBest, Best,
+ HAlternate, VAlternate,
+ Horizontal, Vertical };
+
+ TreeMapItem(TreeMapItem* parent = 0, double value = 1.0 );
+ TreeMapItem(TreeMapItem* parent, double value,
+ QString text1, QString text2 = QString::null,
+ QString text3 = QString::null, QString text4 = QString::null);
+ virtual ~TreeMapItem();
+
+ bool isChildOf(TreeMapItem*);
+
+ TreeMapItem* commonParent(TreeMapItem* item);
+
+ // force a redraw of this item
+ void redraw();
+
+ // delete all children
+ void clear();
+
+ // force new child generation & refresh
+ void refresh();
+
+ // call in a reimplemented items() method to check if already called
+ // after a clear(), this will return false
+ bool initialized();
+
+ /**
+ * Adds an item to a parent.
+ * When no sorting is used, the item is appended (drawn at bottom).
+ * This is only needed if the parent was not already specified in the
+ * construction of the item.
+ */
+ void addItem(TreeMapItem*);
+
+ /**
+ * Returns a list of text strings of specified text number,
+ * from root up to this item.
+ */
+ QStringList path(int) const;
+
+ /**
+ * Depth of this item. This is the distance to root.
+ */
+ int depth() const;
+
+ /**
+ * Parent Item
+ */
+ TreeMapItem* parent() const { return _parent; }
+
+ /**
+ * Temporary rectangle used for drawing this item the last time.
+ * This is internally used to map from a point to an item.
+ */
+ void setItemRect(const QRect& r) { _rect = r; }
+ void clearItemRect();
+ const QRect& itemRect() const { return _rect; }
+ int width() const { return _rect.width(); }
+ int height() const { return _rect.height(); }
+
+ /**
+ * Temporary rectangle list of free space of this item.
+ * Used internally to enable tooltip.
+ */
+ void clearFreeRects();
+ QPtrList<QRect>* freeRects() const { return _freeRects; }
+ void addFreeRect(const QRect& r);
+
+ /**
+ * Temporary child item index of the child that was current() recently.
+ */
+ int index() const { return _index; }
+ void setIndex(int i) { _index = i; }
+
+
+ /**
+ * TreeMap widget this item is put in.
+ */
+ TreeMapWidget* widget() const { return _widget; }
+
+ void setParent(TreeMapItem* p);
+ void setWidget(TreeMapWidget* w) { _widget = w; }
+ void setSum(double s) { _sum = s; }
+ void setValue(double s) { _value = s; }
+
+ virtual double sum() const;
+ virtual double value() const;
+ // replace "Default" position with setting from TreeMapWidget
+ virtual Position position(int) const;
+ virtual const QFont& font() const;
+ virtual bool isMarked(int) const;
+
+ virtual int borderWidth() const;
+
+ /**
+ * Returns the text number after that sorting is done or
+ * -1 for no sorting, -2 for value() sorting (default).
+ * If ascending != 0, a bool value is written at that location
+ * to indicate if sorting should be ascending.
+ */
+ virtual int sorting(bool* ascending) const;
+
+ /**
+ * Set the sorting for child drawing.
+ *
+ * Default is no sorting: <textNo> = -1
+ * For value() sorting, use <textNo> = -2
+ *
+ * For fast sorting, set this to -1 before child insertions and call
+ * again after inserting all children.
+ */
+ void setSorting(int textNo, bool ascending = true);
+
+ /**
+ * Resort according to the already set sorting.
+ *
+ * This has to be done if the sorting base changes (e.g. text or values
+ * change). If this is only true for the children of this item, you can
+ * set the recursive parameter to false.
+ */
+ void resort(bool recursive = true);
+
+ virtual SplitMode splitMode() const;
+ virtual int rtti() const;
+ // not const as this can create children on demand
+ virtual TreeMapItemList* children();
+
+protected:
+ TreeMapItemList* _children;
+ double _sum, _value;
+
+private:
+ TreeMapWidget* _widget;
+ TreeMapItem* _parent;
+
+ int _sortTextNo;
+ bool _sortAscending;
+
+ // temporary layout
+ QRect _rect;
+ QPtrList<QRect>* _freeRects;
+ int _depth;
+
+ // temporary self value (when using level skipping)
+ double _unused_self;
+
+ // index of last active subitem
+ int _index;
+};
+
+
+/**
+ * Class for visualization of a metric of hierarchically
+ * nested items as 2D areas.
+ */
+class TreeMapWidget: public QWidget
+{
+ Q_OBJECT
+
+public:
+
+ /**
+ * Same as in QListBox/QListView
+ */
+ enum SelectionMode { Single, Multi, Extended, NoSelection };
+
+ /* The widget becomes owner of the base item */
+ TreeMapWidget(TreeMapItem* base, QWidget* parent=0, const char* name=0);
+ ~TreeMapWidget();
+
+ /**
+ * Returns the TreeMapItem filling out the widget space
+ */
+ TreeMapItem* base() const { return _base; }
+
+ /**
+ * Returns a reference to the current widget font.
+ */
+ const QFont& currentFont() const;
+
+ /**
+ * Returns the area item at position x/y, independent from any
+ * maxSelectDepth setting.
+ */
+ TreeMapItem* item(int x, int y) const;
+
+ /**
+ * Returns the nearest item with a visible area; this
+ * can be the given item itself.
+ */
+ TreeMapItem* visibleItem(TreeMapItem*) const;
+
+ /**
+ * Returns the item possible for selection. this returns the
+ * given item itself or a parent thereof,
+ * depending on setting of maxSelectDepth().
+ */
+ TreeMapItem* possibleSelection(TreeMapItem*) const;
+
+ /**
+ * Selects or unselects an item.
+ * In multiselection mode, the constrain that a selected item
+ * has no selected children or parents stays true.
+ */
+ void setSelected(TreeMapItem*, bool selected = true);
+
+ /**
+ * Switches on the marking <markNo>. Marking 0 switches off marking.
+ * This is mutually exclusive to selection, and is automatically
+ * switched off when selection is changed (also by the user).
+ * Marking is visually the same as selection, and is based on
+ * TreeMapItem::isMarked(<markNo>).
+ * This enables to programmatically show multiple selected items
+ * at once even in single selection mode.
+ */
+ void setMarked(int markNo = 1, bool redraw = true);
+
+ /**
+ * Clear selection of all selected items which are children of
+ * parent. When parent == 0, clears whole selection
+ * Returns true if selection changed.
+ */
+ bool clearSelection(TreeMapItem* parent = 0);
+
+ /**
+ * Selects or unselects items in a range.
+ * This is needed internally for Shift-Click in Extented mode.
+ * Range means for a hierarchical widget:
+ * - select/unselect i1 and i2 according selected
+ * - search common parent of i1 and i2, and select/unselect the
+ * range of direct children between but excluding the child
+ * leading to i1 and the child leading to i2.
+ */
+ void setRangeSelection(TreeMapItem* i1,
+ TreeMapItem* i2, bool selected);
+
+ /**
+ * Sets the current item.
+ * The current item is mainly used for keyboard navigation.
+ */
+ void setCurrent(TreeMapItem*, bool kbd=false);
+
+ /**
+ * Set the maximal depth a selected item can have.
+ * If you try to select a item with higher depth, the ancestor holding
+ * this condition is used.
+ *
+ * See also possibleSelection().
+ */
+ void setMaxSelectDepth(int d) { _maxSelectDepth = d; }
+
+
+ void setSelectionMode(SelectionMode m) { _selectionMode = m; }
+
+ /**
+ * for setting/getting global split direction
+ */
+ void setSplitMode(TreeMapItem::SplitMode m);
+ TreeMapItem::SplitMode splitMode() const;
+ // returns true if string was recognized
+ bool setSplitMode(QString);
+ QString splitModeString() const;
+
+
+ /*
+ * Shading of rectangles enabled ?
+ */
+ void setShadingEnabled(bool s);
+ bool isShadingEnabled() const { return _shading; }
+
+ /* Setting for a whole depth level: draw 3D frame (default) or solid */
+ void drawFrame(int d, bool b);
+ bool drawFrame(int d) const { return (d<4)?_drawFrame[d]:true; }
+
+ /* Setting for a whole depth level: draw items (default) or transparent */
+ void setTransparent(int d, bool b);
+ bool isTransparent(int d) const { return (d<4)?_transparent[d]:false; }
+
+ /**
+ * Items usually have a size proportional to their value().
+ * With <width>, you can give the minimum width
+ * of the resulting rectangle to still be drawn.
+ * For space not used because of to small items, you can specify
+ * with <reuseSpace> if the background should shine through or
+ * the space will be used to enlarge the next item to be drawn
+ * at this level.
+ */
+ void setVisibleWidth(int width, bool reuseSpace = false);
+
+ /**
+ * If a children value() is almost the parents sum(),
+ * it can happen that the border to be drawn for visibilty of
+ * nesting relations takes to much space, and the
+ * parent/child size relation can not be mapped to a correct
+ * area size relation.
+ *
+ * Either
+ * (1) Ignore the incorrect drawing, or
+ * (2) Skip drawing of the parent level alltogether.
+ */
+ void setSkipIncorrectBorder(bool enable = true);
+ bool skipIncorrectBorder() const { return _skipIncorrectBorder; }
+
+ /**
+ * Maximal nesting depth
+ */
+ void setMaxDrawingDepth(int d);
+ int maxDrawingDepth() const { return _maxDrawingDepth; }
+
+ /**
+ * Minimal area for rectangles to draw
+ */
+ void setMinimalArea(int area);
+ int minimalArea() const { return _minimalArea; }
+
+ /* defaults for text attributes */
+ QString defaultFieldType(int) const;
+ QString defaultFieldStop(int) const;
+ bool defaultFieldVisible(int) const;
+ bool defaultFieldForced(int) const;
+ DrawParams::Position defaultFieldPosition(int) const;
+
+ /**
+ * Set the type name of a field.
+ * This is important for the visualization menu generated
+ * with visualizationMenu()
+ */
+ void setFieldType(int, QString);
+ QString fieldType(int) const;
+
+ /**
+ * Stop drawing at item with name
+ */
+ void setFieldStop(int, QString);
+ QString fieldStop(int) const;
+
+ /**
+ * Should the text with number textNo be visible?
+ * This is only done if remaining space is enough to allow for
+ * proportional size constrains.
+ */
+ void setFieldVisible(int, bool);
+ bool fieldVisible(int) const;
+
+ /**
+ * Should the drawing of the name into the rectangle be forced?
+ * This enables drawing of the name before drawing subitems, and
+ * thus destroys proportional constrains.
+ */
+ void setFieldForced(int, bool);
+ bool fieldForced(int) const;
+
+ /**
+ * Set the field position in the area. See TreeMapItem::Position
+ */
+ void setFieldPosition(int, DrawParams::Position);
+ DrawParams::Position fieldPosition(int) const;
+ void setFieldPosition(int, QString);
+ QString fieldPositionString(int) const;
+
+ /**
+ * Do we allow the texts to be rotated by 90 degrees for better fitting?
+ */
+ void setAllowRotation(bool);
+ bool allowRotation() const { return _allowRotation; }
+
+ void setBorderWidth(int w);
+ int borderWidth() const { return _borderWidth; }
+
+ /**
+ * Save/restore options.
+ */
+ void saveOptions(KConfigGroup*, QString prefix = QString::null);
+ void restoreOptions(KConfigGroup*, QString prefix = QString::null);
+
+ /**
+ * These functions populate given popup menus.
+ * The added items are already connected to handlers.
+ *
+ * The int is the menu id where to start for the items (100 IDs reserved).
+ */
+ void addSplitDirectionItems(QPopupMenu*, int);
+ void addSelectionItems(QPopupMenu*, int, TreeMapItem*);
+ void addFieldStopItems(QPopupMenu*, int, TreeMapItem*);
+ void addAreaStopItems(QPopupMenu*, int, TreeMapItem*);
+ void addDepthStopItems(QPopupMenu*, int, TreeMapItem*);
+ void addVisualizationItems(QPopupMenu*, int);
+
+ TreeMapWidget* widget() { return this; }
+ TreeMapItem* current() const { return _current; }
+ TreeMapItemList selection() const { return _selection; }
+ bool isSelected(TreeMapItem* i) const;
+ int maxSelectDepth() const { return _maxSelectDepth; }
+ SelectionMode selectionMode() const { return _selectionMode; }
+
+ /**
+ * Return tooltip string to show for a item (can be rich text)
+ * Default implementation gives lines with "text0 (text1)" going to root.
+ */
+ virtual QString tipString(TreeMapItem* i) const;
+
+ /**
+ * Redraws an item with all children.
+ * This takes changed values(), sums(), colors() and text() into account.
+ */
+ void redraw(TreeMapItem*);
+ void redraw() { redraw(_base); }
+
+ /**
+ * Resort all TreeMapItems. See TreeMapItem::resort().
+ */
+ void resort() { _base->resort(true); }
+
+ // internal
+ void drawTreeMap();
+
+ // used internally when items are destroyed
+ void deletingItem(TreeMapItem*);
+
+protected slots:
+ void splitActivated(int);
+ void selectionActivated(int);
+ void fieldStopActivated(int);
+ void areaStopActivated(int);
+ void depthStopActivated(int);
+ void visualizationActivated(int);
+
+signals:
+ void selectionChanged();
+ void selectionChanged(TreeMapItem*);
+
+ /**
+ * This signal is emitted if the current item changes.
+ * If the change is done because of keyboard navigation,
+ * the <kbd> is set to true
+ */
+ void currentChanged(TreeMapItem*, bool keyboard);
+ void clicked(TreeMapItem*);
+ void returnPressed(TreeMapItem*);
+ void doubleClicked(TreeMapItem*);
+ void rightButtonPressed(TreeMapItem*, const QPoint &);
+ void contextMenuRequested(TreeMapItem*, const QPoint &);
+
+protected:
+ void mousePressEvent( QMouseEvent * );
+ void contextMenuEvent( QContextMenuEvent * );
+ void mouseReleaseEvent( QMouseEvent * );
+ void mouseMoveEvent( QMouseEvent * );
+ void mouseDoubleClickEvent( QMouseEvent * );
+ void keyPressEvent( QKeyEvent* );
+ void paintEvent( QPaintEvent * );
+ void resizeEvent( QResizeEvent * );
+ void showEvent( QShowEvent * );
+ void fontChange( const QFont& );
+
+private:
+ TreeMapItemList diff(TreeMapItemList&, TreeMapItemList&);
+ // returns true if selection changed
+ TreeMapItem* setTmpSelected(TreeMapItem*, bool selected = true);
+ TreeMapItem* setTmpRangeSelection(TreeMapItem* i1,
+ TreeMapItem* i2, bool selected);
+ bool isTmpSelected(TreeMapItem* i);
+
+ void drawItem(QPainter* p, TreeMapItem*);
+ void drawItems(QPainter* p, TreeMapItem*);
+ bool horizontal(TreeMapItem* i, const QRect& r);
+ void drawFill(TreeMapItem*,QPainter* p, QRect& r);
+ void drawFill(TreeMapItem*,QPainter* p, QRect& r,
+ TreeMapItemListIterator it, int len, bool goBack);
+ bool drawItemArray(QPainter* p, TreeMapItem*, QRect& r, double,
+ TreeMapItemListIterator it, int len, bool);
+ bool resizeAttr(int);
+
+ TreeMapItem* _base;
+ TreeMapItem *_current, *_pressed, *_lastOver, *_oldCurrent;
+ TreeMapTip* _tip;
+ int _maxSelectDepth, _maxDrawingDepth;
+
+ // attributes for field, per textNo
+ struct FieldAttr {
+ QString type, stop;
+ bool visible, forced;
+ DrawParams::Position pos;
+ };
+ QValueVector<FieldAttr> _attr;
+
+ SelectionMode _selectionMode;
+ TreeMapItem::SplitMode _splitMode;
+ int _visibleWidth, _stopArea, _minimalArea, _borderWidth;
+ bool _reuseSpace, _skipIncorrectBorder, _drawSeparators, _shading;
+ bool _allowRotation;
+ bool _transparent[4], _drawFrame[4];
+ TreeMapItem * _needsRefresh;
+ TreeMapItemList _selection;
+ int _markNo;
+
+ // for the context menus: start IDs
+ int _splitID, _selectionID, _visID;
+ int _fieldStopID, _areaStopID, _depthStopID;
+ TreeMapItem* _menuItem;
+
+ // temporary selection while dragging, used for drawing
+ // most of the time, _selection == _tmpSelection
+ TreeMapItemList _tmpSelection;
+ bool _inShiftDrag, _inControlDrag;
+
+ // temporary widget font metrics while drawing
+ QFont _font;
+ int _fontHeight;
+
+ // back buffer pixmap
+ QPixmap _pixmap;
+};
+
+#endif
diff --git a/kcachegrind/kcachegrind/utils.cpp b/kcachegrind/kcachegrind/utils.cpp
new file mode 100644
index 00000000..618fce7b
--- /dev/null
+++ b/kcachegrind/kcachegrind/utils.cpp
@@ -0,0 +1,483 @@
+/* This file is part of KCachegrind.
+ Copyright (C) 2003 Josef Weidendorfer <Josef.Weidendorfer@gmx.de>
+
+ KCachegrind is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public
+ License as published by the Free Software Foundation, version 2.
+
+ 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; see the file COPYING. If not, write to
+ the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+*/
+
+/*
+ * Utility classes for KCachegrind
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#ifdef HAVE_MMAP
+#include <unistd.h>
+#include <sys/mman.h>
+#endif
+
+#include <qfile.h>
+#include <errno.h>
+
+#include "utils.h"
+
+
+// class FixString
+
+FixString::FixString(const char* str, int len)
+{
+ _str = str;
+ _len = len;
+}
+
+bool FixString::stripFirst(char& c)
+{
+ if (!_len) {
+ c = 0;
+ return false;
+ }
+
+ c = *_str;
+ _str++;
+ _len--;
+ return true;
+ }
+
+bool FixString::stripPrefix(const char* p)
+{
+ if (_len == 0) return false;
+ if (!p || (*p != *_str)) return false;
+
+ const char* s = _str+1;
+ int l = _len-1;
+ p++;
+ while(*p) {
+ if (l==0) return false;
+ if (*s != *p) return false;
+ p++;
+ s++;
+ l--;
+ }
+ _str = s;
+ _len = l;
+ return true;
+}
+
+
+// this parses hexadecimal (with prefix '0x' too)
+bool FixString::stripUInt(unsigned int& v, bool stripSpaces)
+{
+ if (_len==0) {
+ v = 0;
+ return false;
+ }
+
+ char c = *_str;
+ if (c<'0' || c>'9') {
+ v = 0;
+ return false;
+ }
+
+ v = c-'0';
+ const char* s = _str+1;
+ int l = _len-1;
+ c = *s;
+
+ if ((l>0) && (c == 'x') && (v==0)) {
+ // hexadecimal
+ s++;
+ c = *s;
+ l--;
+
+ while(l>0) {
+ if (c>='0' && c<='9')
+ v = 16*v + (c-'0');
+ else if (c>='a' && c<='f')
+ v = 16*v + 10 + (c-'a');
+ else if (c>='A' && c<='F')
+ v = 16*v + 10 + (c-'A');
+ else
+ break;
+ s++;
+ c = *s;
+ l--;
+ }
+ }
+ else {
+ // decimal
+
+ while(l>0) {
+ if (c<'0' || c>'9') break;
+ v = 10*v + (c-'0');
+ s++;
+ c = *s;
+ l--;
+ }
+ }
+
+ if (stripSpaces)
+ while(l>0) {
+ if (c != ' ') break;
+ s++;
+ c = *s;
+ l--;
+ }
+
+ _str = s;
+ _len = l;
+ return true;
+}
+
+
+void FixString::stripSurroundingSpaces()
+{
+ if (_len==0) return;
+
+ // leading spaces
+ while((_len>0) && (*_str==' ')) {
+ _len--;
+ _str++;
+ }
+
+ // trailing spaces
+ while((_len>0) && (_str[_len-1]==' ')) {
+ _len--;
+ }
+}
+
+void FixString::stripSpaces()
+{
+ while((_len>0) && (*_str==' ')) {
+ _len--;
+ _str++;
+ }
+}
+
+bool FixString::stripName(FixString& s)
+{
+ if (_len==0) return false;
+
+ // first char has to be a letter or "_"
+ if (!QChar(*_str).isLetter() && (*_str != '_')) return false;
+
+ int newLen = 1;
+ const char* newStr = _str;
+
+ _str++;
+ _len--;
+
+ while(_len>0) {
+ if (!QChar(*_str).isLetterOrNumber()
+ && (*_str != '_')) break;
+
+ newLen++;
+ _str++;
+ _len--;
+ }
+
+ s.set(newStr, newLen);
+ return true;
+}
+
+FixString FixString::stripUntil(char c)
+{
+ if (_len == 0) return FixString();
+
+ const char* newStr = _str;
+ int newLen = 0;
+
+ while(_len>0) {
+ if (*_str == c) {
+ _str++;
+ _len--;
+ break;
+ }
+
+ _str++;
+ _len--;
+ newLen++;
+ }
+ return FixString(newStr, newLen);
+}
+
+bool FixString::stripUInt64(uint64& v, bool stripSpaces)
+{
+ if (_len==0) {
+ v = 0;
+ return false;
+ }
+
+ char c = *_str;
+ if (c<'0' || c>'9') {
+ v = 0;
+ return false;
+ }
+
+ v = c-'0';
+ const char* s = _str+1;
+ int l = _len-1;
+ c = *s;
+
+ if ((l>0) && (c == 'x') && (v==0)) {
+ // hexadecimal
+ s++;
+ c = *s;
+ l--;
+
+ while(l>0) {
+ if (c>='0' && c<='9')
+ v = 16*v + (c-'0');
+ else if (c>='a' && c<='f')
+ v = 16*v + 10 + (c-'a');
+ else if (c>='A' && c<='F')
+ v = 16*v + 10 + (c-'A');
+ else
+ break;
+ s++;
+ c = *s;
+ l--;
+ }
+ }
+ else {
+ // decimal
+ while(l>0) {
+ if (c<'0' || c>'9') break;
+ v = 10*v + (c-'0');
+ s++;
+ c = *s;
+ l--;
+ }
+ }
+
+ if (stripSpaces)
+ while(l>0) {
+ if (c != ' ') break;
+ s++;
+ c = *s;
+ l--;
+ }
+
+ _str = s;
+ _len = l;
+ return true;
+}
+
+
+bool FixString::stripInt64(int64& v, bool stripSpaces)
+{
+ if (_len==0) {
+ v = 0;
+ return false;
+ }
+
+ char c = *_str;
+ if (c<'0' || c>'9') {
+ v = 0;
+ return false;
+ }
+
+ v = c-'0';
+ const char* s = _str+1;
+ int l = _len-1;
+ c = *s;
+
+ if ((l>0) && (c == 'x') && (v==0)) {
+ // hexadecimal
+ s++;
+ c = *s;
+ l--;
+
+ while(l>0) {
+ if (c>='0' && c<='9')
+ v = 16*v + (c-'0');
+ else if (c>='a' && c<='f')
+ v = 16*v + 10 + (c-'a');
+ else if (c>='A' && c<='F')
+ v = 16*v + 10 + (c-'A');
+ else
+ break;
+ s++;
+ c = *s;
+ l--;
+ }
+ }
+ else {
+ // decimal
+
+ while(l>0) {
+ if (c<'0' || c>'9') break;
+ v = 10*v + (c-'0');
+ s++;
+ c = *s;
+ l--;
+ }
+ }
+
+ if (stripSpaces)
+ while(l>0) {
+ if (c != ' ') break;
+ s++;
+ c = *s;
+ l--;
+ }
+
+ _str = s;
+ _len = l;
+ return true;
+}
+
+
+
+// class FixFile
+
+FixFile::FixFile(QFile* file)
+{
+ if (!file) {
+ _len = 0;
+ _currentLeft = 0;
+ _openError = true;
+ return;
+ }
+
+ _filename = file->name();
+ if (!file->isOpen() && !file->open( IO_ReadOnly ) ) {
+ qWarning( "%s: %s", (const char*) QFile::encodeName(_filename),
+ strerror( errno ) );
+ _len = 0;
+ _currentLeft = 0;
+ _openError = true;
+ return;
+ }
+
+ _openError = false;
+ _used_mmap = false;
+
+#ifdef HAVE_MMAP
+ char *addr = 0;
+ size_t len = file->size();
+ if (len>0) addr = (char *) mmap( addr, len,
+ PROT_READ, MAP_PRIVATE,
+ file->handle(), 0 );
+ if (addr && (addr != MAP_FAILED)) {
+ // mmap succeeded
+ _base = addr;
+ _len = len;
+ _used_mmap = true;
+
+ if (0) qDebug("Mapped '%s'", _filename.ascii());
+ } else {
+#endif // HAVE_MMAP
+ // try reading the data into memory instead
+ _data = file->readAll();
+ _base = _data.data();
+ _len = _data.size();
+#ifdef HAVE_MMAP
+ }
+#endif // HAVE_MMAP
+
+ _current = _base;
+ _currentLeft = _len;
+}
+
+FixFile::~FixFile()
+{
+ // if the file was read into _data, it will be deleted automatically
+
+#ifdef HAVE_MMAP
+ if (_used_mmap) {
+ if (0) qDebug("Unmapping '%s'", _filename.ascii());
+ if (munmap(_base, _len) != 0)
+ qWarning( "munmap: %s", strerror( errno ) );
+ }
+#endif // HAVE_MMAP
+}
+
+bool FixFile::nextLine(FixString& str)
+{
+ if (_currentLeft == 0) return false;
+
+ unsigned left = _currentLeft;
+ char* current = _current;
+
+ while(left>0) {
+ if (*current == 0 || *current == '\n') break;
+ current++;
+ left--;
+ }
+
+ if (0) {
+ char tmp[200];
+ int l = _currentLeft-left;
+ if (l>199) l = 199;
+ strncpy(tmp, _current, l);
+ tmp[l] = 0;
+ qDebug("[FixFile::nextLine] At %d, len %d: '%s'",
+ _current - _base, _currentLeft-left, tmp);
+ }
+
+ str.set(_current, _currentLeft-left);
+
+ if (*current == '\n') {
+ current++;
+ left--;
+ }
+ _current = current;
+ _currentLeft = left;
+
+ return true;
+}
+
+bool FixFile::setCurrent(unsigned pos)
+{
+ if (pos > _len) return false;
+
+ _current = _base + pos;
+ _currentLeft = _len - pos;
+ return true;
+}
+
+
+#if 0
+
+// class AppendList
+
+
+AppendList::AppendList()
+{
+ _next = 0;
+ _current = 0;
+ _last = 0;
+
+ _count = 0;
+ _currentIndex = 0;
+ _lastIndex = 0;
+ _autoDelete = false;
+}
+
+
+void AppendList::clear()
+{
+ int count = _count;
+ int i;
+
+ if (count <= firstLen) {
+ if (_autoDelete)
+ for (i=0;i<count;i++)
+ delete _first[i];
+ }
+}
+
+#endif
diff --git a/kcachegrind/kcachegrind/utils.h b/kcachegrind/kcachegrind/utils.h
new file mode 100644
index 00000000..2831c1ce
--- /dev/null
+++ b/kcachegrind/kcachegrind/utils.h
@@ -0,0 +1,164 @@
+/* This file is part of KCachegrind.
+ Copyright (C) 2003 Josef Weidendorfer <Josef.Weidendorfer@gmx.de>
+
+ KCachegrind is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public
+ License as published by the Free Software Foundation, version 2.
+
+ 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; see the file COPYING. If not, write to
+ the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+*/
+
+/*
+ * Utility classes for KCachegrind
+ */
+
+#ifndef UTILS_H
+#define UTILS_H
+
+#include <qstring.h>
+
+class QFile;
+
+typedef unsigned long long uint64;
+typedef long long int64;
+
+/**
+ * A simple, constant string class
+ *
+ * For use with zero-copy strings from mapped files.
+ */
+class FixString {
+
+ public:
+ // constructor for an invalid string
+ FixString() { _len = 0; _str = 0; }
+
+ /**
+ * FixString never does a deep copy! You have to make sure that
+ * the string starting at the char pointer is valid trough the
+ * lifetime of FixString.
+ */
+ FixString(const char*, int len);
+
+ int len() { return _len; }
+ const char* ascii() { return _str; }
+ bool isEmpty() { return _len == 0; }
+ bool isValid() { return _str != 0; }
+
+ // sets <c> to first character and returns true if length >0
+ bool first(char& c)
+ { if (_len==0) return false; c=_str[0]; return true; }
+
+ void set(const char* s, int l) { _str=s; _len=l; }
+ bool stripFirst(char&);
+ bool stripPrefix(const char*);
+
+ /**
+ * Strip leading and trailing spaces
+ */
+ void stripSurroundingSpaces();
+
+ /**
+ * Strip leading spaces
+ */
+ void stripSpaces();
+
+ /**
+ * Strip name: [A-Za-z_][0-9A_Za-z_]*
+ */
+ bool stripName(FixString&);
+
+ /**
+ * Strip string until char appears or end. Strips char, too.
+ */
+ FixString stripUntil(char);
+
+ bool stripUInt(uint&, bool stripSpaces = true);
+ bool stripUInt64(uint64&, bool stripSpaces = true);
+ bool stripInt64(int64&, bool stripSpaces = true);
+
+ operator QString() const
+ { return QString::fromLatin1(_str,_len); }
+
+ private:
+ const char* _str;
+ int _len;
+};
+
+
+/**
+ * A class for fast line by line reading of a read-only ASCII file
+ */
+class FixFile {
+
+ public:
+ FixFile(QFile*);
+ ~FixFile();
+
+ /**
+ * Read next line into <str>. Returns false on error or EOF.
+ */
+ bool nextLine(FixString& str);
+ bool exists() { return !_openError; }
+ unsigned len() { return _len; }
+ unsigned current() { return _current - _base; }
+ bool setCurrent(unsigned pos);
+ void rewind() { setCurrent(0); }
+
+ private:
+ char *_base, *_current;
+ QByteArray _data;
+ unsigned _len, _currentLeft;
+ bool _used_mmap, _openError;
+ QString _filename;
+};
+
+
+/**
+ * A list of pointers, only able to append items.
+ * Optimized for speed, not space.
+ */
+template<class type>
+class AppendList {
+
+ public:
+ AppendList();
+ ~AppendList() { clear(); }
+
+ void setAutoDelete(bool);
+ void clear();
+ void append(const type*);
+
+ unsigned count() const { return _count; }
+ unsigned containsRef(const type*) const;
+
+ type* current();
+ type* first();
+ type* next();
+
+ private:
+ static const int firstLen = 8;
+ static const int maxLen = 256;
+
+ struct AppendListChunk {
+ int size;
+ struct AppendListChunk* next;
+ type* data[1];
+ };
+
+ struct AppendListChunk *_next, *_current, *_last;
+ int _count, _currentIndex, _lastIndex;
+ bool _autoDelete;
+ type* _first[firstLen];
+};
+
+
+#endif
diff --git a/kcachegrind/kcachegrind/x-kcachegrind.desktop b/kcachegrind/kcachegrind/x-kcachegrind.desktop
new file mode 100644
index 00000000..671f89ac
--- /dev/null
+++ b/kcachegrind/kcachegrind/x-kcachegrind.desktop
@@ -0,0 +1,44 @@
+[Desktop Entry]
+Comment=Cachegrind/Callgrind Profile Dump
+Comment[ca]=Resultat del anàlisis de Cachegrind/Callgring
+Comment[cs]=Data profilace Cachegrind/Callgrind
+Comment[cy]=Tomen Proffil Cachegrind/Callgrind
+Comment[da]=Cachegrind/Callgrind profile-dump
+Comment[de]=Cachegrind/Callgrind Profil-Ausgabe
+Comment[el]=ΑποτÏπωση Ï€Ïοφίλ Cachegrind/Callgrind
+Comment[es]=Resultado de análisis de Cachegrind/Callgring
+Comment[et]=Cachegrind/Callgrind profileerimistõmmis
+Comment[eu]=Cachegrind/Callgrind profil iraulketa
+Comment[fa]=تخلیۀ Profile Cachegrind/Callgrind
+Comment[fi]=Cachegrind/Callgrind-profiilivedos
+Comment[fr]=Dépôt de profil Cachegrind / Callgrind
+Comment[gl]=Resultado da análise de Cachegrind/Callgrind
+Comment[hi]=केश-गà¥à¤°à¤¿à¤‚ड/काल-गà¥à¤°à¤¿à¤‚ड पà¥à¤°à¥‹à¤«à¤¼à¤¾à¤‡à¤² डमà¥à¤ª
+Comment[hu]=Cachegrind/Callgrind teljesítményprofil-fájl
+Comment[is]=Niðurstaða afkastakönnunar á Cachegrind/Callgrind
+Comment[it]=Dump del profilo di Cachegrind/Callgrind
+Comment[ja]=Callgrind/Callgrind プロファイルダンプ
+Comment[ka]=Cachegrind/Callgrind პრáƒáƒ¤áƒ˜áƒšáƒ˜áƒ¡ დáƒáƒ›áƒžáƒ˜
+Comment[kk]=Cachegrind/Callgrind профилінің дампы
+Comment[nds]=Cachegrind/Callgrind-Profilutgaav
+Comment[ne]=Cachegrind/Callgrind पà¥à¤°à¥‹à¤«à¤¾à¤‡à¤² डमà¥à¤ª
+Comment[nl]=Cachegrind/Callgrind Profieldump
+Comment[nn]=Cachegrind/Callgrind-profildump
+Comment[pl]=Zrzut profilowania Cachegrind/Callgrind
+Comment[pt]=Resultado da Análise do Cachegrind/Callgrind
+Comment[pt_BR]=Depósito de Perfil Cachegrind/Callgrind
+Comment[ru]=Дамп Ð¿Ñ€Ð¾Ñ„Ð¸Ð»Ð¸Ñ€Ð¾Ð²Ð°Ð½Ð¸Ñ Cachegrind/Callgrind
+Comment[sk]=Výpis volaní Cachegrind/Callgrind
+Comment[sr]=Cachegrind-ов/Callgrind-ов избачај профила
+Comment[sr@Latn]=Cachegrind-ov/Callgrind-ov izbaÄaj profila
+Comment[sv]=Profileringsdump från Cachegrind/Callgrind
+Comment[ta]=இடைமாறà¯à®±à®•à®Ÿà¯à®Ÿà®®à¯/ அழைபà¯à®ªà¯ கடà¯à®Ÿà®®à¯ விவரகà¯à®•à¯à®±à®¿ திணிபà¯à®ªà¯
+Comment[tg]=Дампи профилкунии Cachegrind/Callgrind
+Comment[uk]=Ð—Ð²Ð°Ð»ÑŽÐ²Ð°Ð½Ð½Ñ Ð¿Ñ€Ð¾Ñ„Ñ–Ð»ÑŽÐ²Ð°Ð½Ð½Ñ Cachegrind/Callgrind
+Comment[zh_CN]=Cachegrind/Callgrind é…置文件转存
+Comment[zh_TW]=Cachegrind/Callgrind 分æžè³‡æ–™å‚¾å°
+DefaultApp=kcachegrind
+Icon=kcachegrind
+Type=MimeType
+MimeType=application/x-kcachegrind
+Patterns=cachegrind.out*;callgrind.out*
diff --git a/kcachegrind/pics/Makefile.am b/kcachegrind/pics/Makefile.am
new file mode 100644
index 00000000..a899c7b2
--- /dev/null
+++ b/kcachegrind/pics/Makefile.am
@@ -0,0 +1,3 @@
+kcachegrindicondir = $(kde_datadir)/kcachegrind/icons
+kcachegrindicon_ICON = AUTO
+SUBDIRS = hicolor
diff --git a/kcachegrind/pics/hicolor/Makefile.am b/kcachegrind/pics/hicolor/Makefile.am
new file mode 100644
index 00000000..be8b0c26
--- /dev/null
+++ b/kcachegrind/pics/hicolor/Makefile.am
@@ -0,0 +1,2 @@
+kcachegrindicondir = $(kde_datadir)/kcachegrind/icons
+kcachegrindicon_ICON = AUTO
diff --git a/kcachegrind/pics/hicolor/hi16-action-fromrec.png b/kcachegrind/pics/hicolor/hi16-action-fromrec.png
new file mode 100644
index 00000000..a5cb430d
--- /dev/null
+++ b/kcachegrind/pics/hicolor/hi16-action-fromrec.png
Binary files differ
diff --git a/kcachegrind/pics/hicolor/hi16-action-percent.png b/kcachegrind/pics/hicolor/hi16-action-percent.png
new file mode 100644
index 00000000..7a4ba47e
--- /dev/null
+++ b/kcachegrind/pics/hicolor/hi16-action-percent.png
Binary files differ
diff --git a/kcachegrind/pics/hicolor/hi16-action-recrec.png b/kcachegrind/pics/hicolor/hi16-action-recrec.png
new file mode 100644
index 00000000..ec11bfa4
--- /dev/null
+++ b/kcachegrind/pics/hicolor/hi16-action-recrec.png
Binary files differ
diff --git a/kcachegrind/pics/hicolor/hi16-action-torec.png b/kcachegrind/pics/hicolor/hi16-action-torec.png
new file mode 100644
index 00000000..c092c018
--- /dev/null
+++ b/kcachegrind/pics/hicolor/hi16-action-torec.png
Binary files differ
diff --git a/kcachegrind/pics/hicolor/hi22-action-percent.png b/kcachegrind/pics/hicolor/hi22-action-percent.png
new file mode 100644
index 00000000..c64a3785
--- /dev/null
+++ b/kcachegrind/pics/hicolor/hi22-action-percent.png
Binary files differ
diff --git a/kcachegrind/pics/hicolor/hi32-action-percent.png b/kcachegrind/pics/hicolor/hi32-action-percent.png
new file mode 100644
index 00000000..e876c30d
--- /dev/null
+++ b/kcachegrind/pics/hicolor/hi32-action-percent.png
Binary files differ
diff --git a/kcachegrind/tests/cg-badcompression1 b/kcachegrind/tests/cg-badcompression1
new file mode 100644
index 00000000..6076bf92
--- /dev/null
+++ b/kcachegrind/tests/cg-badcompression1
@@ -0,0 +1,17 @@
+# Test with bad callgrind format
+# Expected:
+# :13 - Redefinition of compressed file index 2 (was 'file1.c') to ''
+# :14 - Redefinition of compressed function index 1 (was 'main') to 'main2'
+# :16 - Undefined compressed function index 2
+# :16 - Invalid function, setting to unknown
+
+events: Ir
+
+fl=(2) file1.c
+fn=(1) main
+10 9
+fl=(2 )
+fn=(1) main2
+11 1
+fn=(2)
+12 1
diff --git a/kcachegrind/tests/cg-badcostline1 b/kcachegrind/tests/cg-badcostline1
new file mode 100644
index 00000000..224ff670
--- /dev/null
+++ b/kcachegrind/tests/cg-badcostline1
@@ -0,0 +1,11 @@
+# Test with bad callgrind format
+# Expected:
+# :10 - ignored garbage at end of cost line ('30')
+# :11 - ignored garbage at end of cost line ('hello')
+
+events: Ir
+
+fn=main
+10 20 30
+11 hello
+12 10
diff --git a/kcachegrind/tests/cg-badposition b/kcachegrind/tests/cg-badposition
new file mode 100644
index 00000000..1be582c7
--- /dev/null
+++ b/kcachegrind/tests/cg-badposition
@@ -0,0 +1,15 @@
+# Test with bad callgrind format
+# Expected:
+# :11 - Negative line number -20
+# :12 - Garbage at end of cost line ('a 21')
+# :13 - Negative line number -91
+# :15 - Invalid line 'aa 40'
+
+events: Ir
+
+fn=main
+-20 1
+9a 21
+-100 20
+0x9a 30
+aa 40
diff --git a/kcachegrind/version.h.in b/kcachegrind/version.h.in
new file mode 100644
index 00000000..21f758c7
--- /dev/null
+++ b/kcachegrind/version.h.in
@@ -0,0 +1 @@
+#define KCACHEGRIND_VERSION "@KCACHEGRIND_VERSION@"
diff --git a/kdeaccounts-plugin/Makefile.am b/kdeaccounts-plugin/Makefile.am
new file mode 100644
index 00000000..7be8cea3
--- /dev/null
+++ b/kdeaccounts-plugin/Makefile.am
@@ -0,0 +1,17 @@
+INCLUDES = $(all_includes)
+
+noinst_HEADERS = kdeaccountsformat.h
+kde_module_LTLIBRARIES = kabcformat_kdeaccounts.la
+kabcformat_kdeaccounts_la_SOURCES = kdeaccountsformat.cpp
+kabcformat_kdeaccounts_la_LDFLAGS = $(all_libraries) -module $(KDE_PLUGIN)
+kabcformat_kdeaccounts_la_LIBADD = -lkabc
+
+# let automoc handle all of the meta source files (moc)
+METASOURCES = AUTO
+
+messages: rc.cpp
+ $(XGETTEXT) *.cpp -o $(podir)/kabcformat_kdeaccounts.pot
+
+linkdir = $(kde_datadir)/kabc/formats
+link_DATA = kdeaccountsplugin.desktop
+EXTRA_DIST = $(link_DATA) README
diff --git a/kdeaccounts-plugin/README b/kdeaccounts-plugin/README
new file mode 100644
index 00000000..1319ab18
--- /dev/null
+++ b/kdeaccounts-plugin/README
@@ -0,0 +1,15 @@
+This is a KDE Addressbook Plugin, that is able to parse the file containing
+names and email addresses of all KDE CVS accounts and puts them into your
+addressbook. Very handy being able to auto-complete all those KDE developers
+in KMail :)
+
+After installing, fire up kcontrol, open the Addressbook configuration,
+select Add -> "file", enter a descriptive name like "KDE CVS Accounts",
+check the "Read-only" option and select "KDE CVS Accounts" from the
+dropdown list. Finally, enter the full path to the "accounts" file
+(in CVS, it's in the "kde-common" module).
+
+That should be all :)
+
+Carsten Pfeiffer <pfeiffer@kde.org>
+
diff --git a/kdeaccounts-plugin/kdeaccountsformat.cpp b/kdeaccounts-plugin/kdeaccountsformat.cpp
new file mode 100644
index 00000000..d445e311
--- /dev/null
+++ b/kdeaccounts-plugin/kdeaccountsformat.cpp
@@ -0,0 +1,90 @@
+#include "kdeaccountsformat.h"
+
+#include <qcstring.h>
+#include <qfile.h>
+
+#include <kabc/addressbook.h>
+#include <kabc/addressee.h>
+#include <kabc/resourcefile.h>
+
+extern "C"
+{
+ KDE_EXPORT KABC::FormatPlugin *format()
+ {
+ return new KDEAccountsFormat();
+ }
+}
+
+/**
+ * Loads addresses of the kde-common/accounts file-> The format is
+ * pfeiffer Carsten Pfeiffer pfeiffer@kde.org
+ */
+
+bool KDEAccountsFormat::loadAll( KABC::AddressBook *book,
+ KABC::Resource *resource,
+ QFile *file )
+{
+ if ( !book || !file ) // eh?
+ return false;
+
+ QString uuid = "KDEAccountsEntry.";
+ int id = 0;
+
+ QByteArray array = file->readAll();
+ file->close();
+
+ QByteArray::ConstIterator it = array.begin();
+ QByteArray::ConstIterator end = array.end();
+ QByteArray::ConstIterator startLine;
+ QString line;
+ char eol = '\n';
+ char delim = ' ';
+
+ for ( ; it < end; it++ )
+ {
+ startLine = it;
+
+ for ( ; it && it < end && *it != eol; it++ )
+ { } // find eol
+
+ uint length = it - startLine;
+ line = QString::fromUtf8( startLine, length ).simplifyWhiteSpace();
+
+ QString nickName;
+ QString name;
+ QString email;
+
+ int firstSpace = line.find( delim );
+ if ( firstSpace > 0 )
+ {
+ nickName = line.left( firstSpace );
+
+ int lastSpace = line.findRev( delim );
+ if ( lastSpace > firstSpace )
+ {
+ email = line.mid( lastSpace +1 );
+
+ int start = firstSpace + 1;
+ int length = lastSpace - start;
+ name = line.mid( start, length );
+
+ if ( !email.isEmpty() )
+ {
+ KABC::Addressee address;
+ address.setNickName( nickName );
+ address.setNameFromString( name );
+ address.setOrganization("KDE Project");
+ address.insertCategory("KDE Developer");
+ address.insertEmail( email );
+ address.setUid( uuid + QString::number( id++ ));
+
+ address.setResource( resource );
+ book->insertAddressee( address );
+ }
+ }
+ }
+ }
+
+ return true;
+}
+
diff --git a/kdeaccounts-plugin/kdeaccountsformat.h b/kdeaccounts-plugin/kdeaccountsformat.h
new file mode 100644
index 00000000..6eb07c7c
--- /dev/null
+++ b/kdeaccounts-plugin/kdeaccountsformat.h
@@ -0,0 +1,51 @@
+/****************************************************************************
+** $Id$
+**
+** Created : 2001
+**
+** Copyright (C) 2001 Carsten Pfeiffer <pfeiffer@kde.org>
+**
+****************************************************************************/
+
+#ifndef KDEACCOUNTSPARSER_H
+#define KDEACCOUNTSPARSER_H
+
+#include <kabc/formatplugin.h>
+
+namespace KABC {
+ class AddressBook;
+}
+
+class KDEAccountsFormat : public KABC::FormatPlugin
+{
+public:
+ KDEAccountsFormat() {}
+ ~KDEAccountsFormat() {}
+
+ virtual bool loadAll( KABC::AddressBook *,
+ KABC::Resource *resource, QFile *file );
+
+ virtual bool load( KABC::Addressee&, QFile *)
+ {
+ qDebug("*** KDE Accounts format: load single entry not supported.");
+ return false;
+ }
+ virtual void save( const KABC::Addressee&, QFile *)
+ {
+ qDebug("*** KDE Accounts format: save not supported.");
+ }
+ virtual void saveAll( KABC::AddressBook *, KABC::Resource *, QFile *)
+ {
+ qDebug("*** KDE Accounts format: save not supported.");
+ }
+ virtual bool checkFormat( QFile *file ) const
+ {
+ if ( file->name().endsWith( "/accounts" ) )
+ return true; // lame, but works for me :)
+
+ return false;
+ }
+
+};
+
+#endif // KDEACCOUNTSPARSER_H
diff --git a/kdeaccounts-plugin/kdeaccountsplugin.desktop b/kdeaccounts-plugin/kdeaccountsplugin.desktop
new file mode 100644
index 00000000..03abf9a2
--- /dev/null
+++ b/kdeaccounts-plugin/kdeaccountsplugin.desktop
@@ -0,0 +1,44 @@
+[Misc]
+Name=KDE Repository Accounts
+Name[bg]=Сметки в хранилището на KDE
+Name[ca]=Comptes del repositori de KDE
+Name[cs]=ÚÄty z KDE repository
+Name[da]=KDE lager-konti
+Name[de]=KDE Repositorium-Zugänge
+Name[el]=ΛογαÏιασμοί χώÏου αποθήκευσης του KDE
+Name[es]=Cuentas del repositorio de KDE
+Name[et]=KDE hoidla kontod
+Name[eu]=KDE-ren biltegiaren kontuak
+Name[fa]=حسابهای مخزن KDE
+Name[fi]=KDE:n versionhallinnan käyttäjätunnukset
+Name[fr]=Comptes du référentiel de KDE
+Name[gl]=Contas no repositorio de KDE
+Name[hu]=KDE SVN-azonosítók
+Name[is]=KDE geymslu aðgangur
+Name[it]=Account del deposito di KDE
+Name[ja]=KDE リãƒã‚¸ãƒˆãƒªã‚¢ã‚«ã‚¦ãƒ³ãƒˆ
+Name[ka]=KDE რეპáƒáƒ–იტáƒáƒ áƒ˜áƒ˜áƒ¡ áƒáƒœáƒ’áƒáƒ áƒ˜áƒ¨áƒ˜
+Name[kk]=KDE қоймаÑының тіркелгілері
+Name[lt]=KDE saugyklos paskyros
+Name[nb]=KDE-lagerkontoer
+Name[nds]=KDE-Archivkontos
+Name[ne]=केडीई भणà¥à¤¡à¤¾à¤° खाता
+Name[nl]=KDE Repository gebruikersnamen
+Name[nn]=KDE-lagerkontoar
+Name[pa]=KDE ਰਿਪੋਜ਼ਟਰੀ ਖਾਤੇ
+Name[pl]=Konta w repozytorium KDE
+Name[pt]=Contas do Repositório do KDE
+Name[pt_BR]=Contas do Repositório do KDE
+Name[ru]=Учётные запиÑи Ñ€ÐµÐ¿Ð¾Ð·Ð¸Ñ‚Ð¾Ñ€Ð¸Ñ KDE
+Name[sk]=ÚÄty KDE archívu
+Name[sl]=RaÄuni za skladiÅ¡Äe KDE
+Name[sr]=Ðалози KDE Ñкладишта
+Name[sr@Latn]=Nalozi KDE skladišta
+Name[sv]=KDE-arkivkonton
+Name[uk]=Рахунки Ñховища KDE
+Name[zh_CN]=KDE 仓库账å·
+Name[zh_TW]=KDE 主目錄帳號
+
+[Plugin]
+Type=text
+X-KDE-Library=kabcformat_kdeaccounts
diff --git a/kdepalettes/KDE_Gimp b/kdepalettes/KDE_Gimp
new file mode 100644
index 00000000..796420c1
--- /dev/null
+++ b/kdepalettes/KDE_Gimp
@@ -0,0 +1,44 @@
+GIMP Palette
+# KDE Standard -- GIMP Palette file
+0 0 0 Black
+48 48 48 Untitled
+88 88 88 Untitled
+128 128 128 Untitled
+160 160 160 Untitled
+195 195 195 Untitled
+220 220 220 Untitled
+64 0 0 Untitled
+128 0 0 Untitled
+192 0 0 Untitled
+255 0 0 Untitled
+255 192 192 Untitled
+0 64 0 Untitled
+0 128 0 Untitled
+0 192 0 Untitled
+0 255 0 Untitled
+192 255 192 Untitled
+0 0 0 Untitled
+0 0 128 Untitled
+0 0 192 Untitled
+0 0 255 Untitled
+192 192 255 Untitled
+64 64 0 Untitled
+128 128 0 Untitled
+192 192 0 Untitled
+255 255 0 Untitled
+255 255 192 Untitled
+0 64 64 Untitled
+0 128 128 Untitled
+0 192 192 Untitled
+0 255 255 Untitled
+192 255 255 Untitled
+0 0 0 Untitled
+128 0 128 Untitled
+192 0 192 Untitled
+255 0 255 Untitled
+255 192 255 Untitled
+255 128 0 Untitled
+192 88 0 Untitled
+255 168 88 Untitled
+255 220 168 Untitled
+255 255 255 Untitled
diff --git a/kdepalettes/README b/kdepalettes/README
new file mode 100644
index 00000000..2f9f1336
--- /dev/null
+++ b/kdepalettes/README
@@ -0,0 +1,16 @@
+These are palettes for both the Gimp and Xpaint that match the KDE
+standard color palette. I thought they maybe useful to others designing
+themes and icons.
+
+INSTALLATION:
+Gimp
+ Copy the file KDE_Gimp to ~/.gimp/palettes/. You can now access the
+ palette by selecting File->Dialogs->Palette.
+XPaint
+ To make the KDE palette the default palette copy kde_xpaintrc to
+ ~/.XPaintrc. Otherwise you can load it by selecting File->
+ Load Palette from the image's file menu.
+
+Daniel M. Duley
+<mosfet@jorsm.com>
+
diff --git a/kdepalettes/kde_xpaintrc b/kdepalettes/kde_xpaintrc
new file mode 100644
index 00000000..b4ab0b32
--- /dev/null
+++ b/kdepalettes/kde_xpaintrc
@@ -0,0 +1,128 @@
+reset
+
+pattern BeginData
+P1
+2 2
+01
+10
+
+EndData
+pattern BeginData
+P1
+4 4
+1000
+0001
+0010
+0100
+
+EndData
+pattern BeginData
+P1
+4 4
+0001
+1000
+0100
+0010
+
+EndData
+pattern BeginData
+P1
+2 2
+00
+01
+
+EndData
+pattern BeginData
+P1
+4 4
+1000
+0000
+0000
+0000
+
+EndData
+pattern BeginData
+P1
+4 6
+1000
+0100
+0010
+0001
+0010
+0100
+
+EndData
+pattern BeginData
+P1
+8 8
+10000000
+10000000
+10000000
+11111111
+00001000
+00001000
+00001000
+11111111
+
+EndData
+pattern BeginData
+P1
+8 16
+00111000
+01000100
+10000010
+10000010
+10000010
+01000100
+00111000
+00000000
+10000011
+01000100
+00101000
+00101000
+00101000
+01000100
+10000011
+00000000
+
+EndData
+solid #303030
+solid #585858
+solid #808080
+solid #a0a0a0
+solid #c3c3c3
+solid #dcdcdc
+solid #400000
+solid #800000
+solid #c00000
+solid #ff0000
+solid #ffc0c0
+solid #004000
+solid #008000
+solid #00c000
+solid #00ff00
+solid #c0ffc0
+solid #000000
+solid #000080
+solid #0000c0
+solid #0000ff
+solid #c0c0ff
+solid #404000
+solid #808000
+solid #c0c000
+solid #ffff00
+solid #ffffc0
+solid #004040
+solid #008080
+solid #00c0c0
+solid #00ffff
+solid #c0ffff
+solid #800080
+solid #c000c0
+solid #ff00ff
+solid #ffc0ff
+solid #ff8000
+solid #c05800
+solid #ffa858
+solid #ffdca8
+solid #ffffff
diff --git a/kdesdk.lsm b/kdesdk.lsm
new file mode 100644
index 00000000..ecb2a710
--- /dev/null
+++ b/kdesdk.lsm
@@ -0,0 +1,11 @@
+Begin4
+Title: kdesdk
+Version: 3.5.10
+Entered-date: 2008-08-26
+Description: K Desktop Environment (KDE) SDK
+Keywords: KDE X11 desktop Qt
+Author: http://bugs.kde.org/ (KDE Bugtracking System)
+Primary-site: http://www.kde.org/download/
+Platforms: Unix, Qt
+Copying-policy: GPL, Artistic
+End
diff --git a/kfile-plugins/Makefile.am b/kfile-plugins/Makefile.am
new file mode 100644
index 00000000..aa4d2f43
--- /dev/null
+++ b/kfile-plugins/Makefile.am
@@ -0,0 +1 @@
+SUBDIRS=diff c++ ts
diff --git a/kfile-plugins/c++/Makefile.am b/kfile-plugins/c++/Makefile.am
new file mode 100644
index 00000000..4770b509
--- /dev/null
+++ b/kfile-plugins/c++/Makefile.am
@@ -0,0 +1,22 @@
+## Makefile.am for c++ file meta info plugin
+
+# set the include path for X, qt and KDE
+INCLUDES = $(all_includes)
+
+# these are the headers for your project
+noinst_HEADERS = kfile_cpp.h
+
+kde_module_LTLIBRARIES = kfile_cpp.la
+
+kfile_cpp_la_SOURCES = kfile_cpp.cpp
+kfile_cpp_la_LDFLAGS = $(all_libraries) -module $(KDE_PLUGIN)
+kfile_cpp_la_LIBADD = $(LIB_KIO)
+
+# let automoc handle all of the meta source files (moc)
+METASOURCES = AUTO
+
+messages:
+ $(XGETTEXT) *.cpp -o $(podir)/kfile_cpp.pot
+
+services_DATA = kfile_cpp.desktop kfile_h.desktop
+servicesdir = $(kde_servicesdir)
diff --git a/kfile-plugins/c++/kfile_cpp.cpp b/kfile-plugins/c++/kfile_cpp.cpp
new file mode 100644
index 00000000..6c854a00
--- /dev/null
+++ b/kfile-plugins/c++/kfile_cpp.cpp
@@ -0,0 +1,130 @@
+/* This file is part of the KDE project
+ * Copyright (C) 2002 Rolf Magnus <ramagnus@kde.org>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public
+ * License as published by the Free Software Foundation version 2.
+ *
+ * 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; see the file COPYING. If not, write to
+ * the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ */
+
+#include "kfile_cpp.h"
+
+#include <kurl.h>
+#include <klocale.h>
+#include <kgenericfactory.h>
+#include <kdebug.h>
+
+#include <qfile.h>
+#include <qregexp.h>
+
+typedef KGenericFactory<KCppPlugin> CppFactory;
+
+K_EXPORT_COMPONENT_FACTORY(kfile_cpp, CppFactory("kfile_cpp"))
+
+KCppPlugin::KCppPlugin(QObject *parent, const char *name,
+ const QStringList &args)
+ : KFilePlugin(parent, name, args)
+{
+ kdDebug(7034) << "c++ plugin\n";
+ makeMimeTypeInfo("text/x-c++src");
+ makeMimeTypeInfo("text/x-chdr");
+}
+
+void KCppPlugin::makeMimeTypeInfo(const QString& mimetype)
+{
+ KFileMimeTypeInfo* info = addMimeTypeInfo( mimetype );
+
+ KFileMimeTypeInfo::GroupInfo* group =
+ addGroupInfo(info, "General", i18n("General"));
+
+ KFileMimeTypeInfo::ItemInfo* item;
+ item = addItemInfo(group, "Lines", i18n("Lines"), QVariant::Int);
+ setAttributes(item, KFileMimeTypeInfo::Averaged);
+ item = addItemInfo(group, "Code", i18n("Code"), QVariant::Int);
+ setAttributes(item, KFileMimeTypeInfo::Averaged);
+ item = addItemInfo(group, "Comment", i18n("Comment"), QVariant::Int);
+ setAttributes(item, KFileMimeTypeInfo::Averaged);
+ item = addItemInfo(group, "Blank", i18n("Blank"), QVariant::Int);
+ setAttributes(item, KFileMimeTypeInfo::Averaged);
+ item = addItemInfo(group, "Strings", i18n("Strings"), QVariant::Int);
+ setAttributes(item, KFileMimeTypeInfo::Averaged);
+ item = addItemInfo(group, "i18n Strings", i18n("i18n Strings"), QVariant::Int);
+ setAttributes(item, KFileMimeTypeInfo::Averaged);
+ item = addItemInfo(group, "Included Files", i18n("Included Files"), QVariant::Int);
+ setAttributes(item, KFileMimeTypeInfo::Averaged);
+}
+
+bool KCppPlugin::readInfo( KFileMetaInfo& info, uint )
+{
+ QFile f(info.path());
+ if (!f.open(IO_ReadOnly))
+ return false;
+
+ int codeLines = 0;
+ int commentLines = 0;
+ int totalLines = 0;
+ int emptyLines = 0;
+ int Strings = 0;
+ int Stringsi18n = 0;
+ int Includes = 0;
+
+ bool inComment = false;
+
+ QString line;
+
+ QTextStream stream( &f );
+ while (!stream.eof())
+ {
+ line = stream.readLine();
+ totalLines++;
+
+ if (line.stripWhiteSpace().isEmpty())
+ {
+ emptyLines++;
+ continue;
+ }
+
+ if (line.contains("/*")) inComment = true;
+
+ if (!inComment)
+ {
+ codeLines++;
+ if (line.contains(QRegExp("^\\s*#\\s*include"))) Includes++;
+
+ int pos = line.find("//");
+ if (pos>=0) commentLines++;
+ // truncate the comment - we don't want to count strings in it
+ line.truncate(pos);
+
+ Strings+=line.contains(QRegExp("\".*\""));
+ Stringsi18n+=line.contains(QRegExp("(?:i18n|I18N_NOOP)\\s*\\("));
+ }
+ else
+ commentLines++;
+
+ if (line.contains("*/")) inComment = false;
+ }
+
+ KFileMetaInfoGroup group = appendGroup(info, "General");
+
+ appendItem(group, "Lines", int(totalLines));
+ appendItem(group, "Code", int(codeLines));
+ appendItem(group, "Comment", int(commentLines));
+ appendItem(group, "Blank", int(emptyLines));
+ appendItem(group, "Strings", int(Strings));
+ appendItem(group, "i18n Strings", int(Stringsi18n));
+ appendItem(group, "Included Files", int(Includes));
+ return true;
+}
+
+#include "kfile_cpp.moc"
diff --git a/kfile-plugins/c++/kfile_cpp.desktop b/kfile-plugins/c++/kfile_cpp.desktop
new file mode 100644
index 00000000..2792aa9f
--- /dev/null
+++ b/kfile-plugins/c++/kfile_cpp.desktop
@@ -0,0 +1,60 @@
+[Desktop Entry]
+Type=Service
+Name=C++ Info
+Name[af]=C++ Inligting
+Name[bg]=Изходен код на C++
+Name[br]=Titouroù C++
+Name[ca]=Informació C++
+Name[cs]=C++ info
+Name[cy]=Gwybodaeth C++
+Name[da]=C++-info
+Name[de]=C++-Info
+Name[el]=ΠληÏοφοÏίες C++
+Name[eo]=C++-informo
+Name[es]=Info de C++
+Name[et]=C++ info
+Name[eu]=C++ informazioa
+Name[fa]=اطلاعات C++
+Name[fi]=C++-tiedot
+Name[fo]=C++-upplýsingar
+Name[fr]=Informations C++
+Name[ga]=Eolas C++
+Name[gl]=Información de C++
+Name[he]=מידע ++C
+Name[hi]=C++ जानकारी
+Name[hr]=C++ informacije
+Name[hu]=C++-jellemzők
+Name[is]=C++ upplýsingar
+Name[it]=Informazioni C++
+Name[ja]=C++ 情報
+Name[ka]=C++ ინფáƒáƒ áƒ›áƒáƒªáƒ˜áƒ
+Name[kk]=C++ мәліметі
+Name[lt]=C++ Informacija
+Name[ms]=Info C++
+Name[nds]=C++-Datei-Info
+Name[nl]=C++-info
+Name[nn]=C++-info
+Name[pa]=C++ ਜਾਣਕਾਰੀ
+Name[pl]=Informacja z C++
+Name[pt]=Informação de C++
+Name[pt_BR]=Informações C++
+Name[ro]=Informaţii C++
+Name[ru]=Ð˜Ð½Ñ„Ð¾Ñ€Ð¼Ð°Ñ†Ð¸Ñ C++
+Name[sk]=Informácie o C++
+Name[sl]=Informacije o C++
+Name[sr]=C++ информације
+Name[sr@Latn]=C++ informacije
+Name[sv]=C++-information
+Name[ta]= =C/C++ தகவலà¯
+Name[tg]=Ðхбороти C++
+Name[th]=ข้อมูล C++
+Name[tr]=C++ Bilgisi
+Name[uk]=Ð†Ð½Ñ„Ð¾Ñ€Ð¼Ð°Ñ†Ñ–Ñ Ð¿Ñ€Ð¾ C++
+Name[xh]=C++ Ulwazi
+Name[zh_CN]=C++ ä¿¡æ¯
+Name[zh_TW]=C++ 資訊
+ServiceTypes=KFilePlugin
+X-KDE-Library=kfile_cpp
+MimeType=text/x-c++src;text/x-chdr
+PreferredGroups=General
+PreferredItems=Lines,Code,Comment,Blank,Strings,i18n Strings,Included Files
diff --git a/kfile-plugins/c++/kfile_cpp.h b/kfile-plugins/c++/kfile_cpp.h
new file mode 100644
index 00000000..d238858d
--- /dev/null
+++ b/kfile-plugins/c++/kfile_cpp.h
@@ -0,0 +1,40 @@
+/* This file is part of the KDE project
+ * Copyright (C) 2002 Rolf Magnus <ramagnus@kde.org>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public
+ * License as published by the Free Software Foundation version 2.
+ *
+ * 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; see the file COPYING. If not, write to
+ * the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ */
+
+#ifndef __KFILE_CPP_H__
+#define __KFILE_CPP_H__
+
+#include <kfilemetainfo.h>
+#include <kurl.h>
+
+class QStringList;
+
+class KCppPlugin: public KFilePlugin
+{
+ Q_OBJECT
+
+public:
+ KCppPlugin(QObject *parent, const char *name, const QStringList& args);
+ virtual bool readInfo(KFileMetaInfo& info, uint what);
+
+private:
+ void makeMimeTypeInfo(const QString& mimetype);
+};
+
+#endif
diff --git a/kfile-plugins/c++/kfile_h.desktop b/kfile-plugins/c++/kfile_h.desktop
new file mode 100644
index 00000000..b0766114
--- /dev/null
+++ b/kfile-plugins/c++/kfile_h.desktop
@@ -0,0 +1,58 @@
+[Desktop Entry]
+Type=Service
+Name=C/C++ Header Info
+Name[af]=C/C++ Opskrif Inligting
+Name[bg]=Ð˜Ð½Ñ„Ð¾Ñ€Ð¼Ð°Ñ†Ð¸Ñ Ð·Ð° заглавната чаÑÑ‚ на C/C++
+Name[br]=Titouriñ diwar-benn ar reollin C/C++
+Name[ca]=Informació de capçaleres C/C++
+Name[cs]=Informace o C/C++ hlaviÄce
+Name[cy]=Gwybodaeth Pennawd C/C++
+Name[da]=C/C++-headerinfo
+Name[de]=C++-Header-Info
+Name[el]=ΠληÏοφοÏίες κεφαλίδων C/C++
+Name[es]=Info de cabecera C/C++
+Name[et]=C/C++ päise info
+Name[eu]=C/C++ goiburuen informazioa
+Name[fa]=اطلاعات سرآیند C/C++
+Name[fi]=C/C++-otsikkotiedot
+Name[fr]=Informations d'en-tête C/C++
+Name[gl]=Información da cabeceira de C/C++
+Name[he]=מידע כותרות ++C/C
+Name[hi]=C/C++ हेडर जानकारी
+Name[hr]=Informacije o C++ zaglavljima
+Name[hu]=C/C++ header fájl jellemzői
+Name[is]=C/C++ haus upplýsingar
+Name[it]=Informazioni intestazioni C/C++
+Name[ja]=C/C++ ヘッダ情報
+Name[ka]=C/C++ ზედრკáƒáƒšáƒáƒœáƒ¢áƒ˜áƒ¢áƒ£áƒšáƒ˜áƒ¡ ინფáƒáƒ áƒ›áƒáƒªáƒ˜áƒ
+Name[kk]=C/C++ айдар мәліметі
+Name[lt]=C/C++ antraÅ¡Äių informacija
+Name[ms]=Info Pengepala C/C++
+Name[nb]=C++-deklarasjonsfilinfo
+Name[nds]=C/C++-Koppdatei-Info
+Name[ne]=C/C++ Header info
+Name[nl]=C/C++ Header-info
+Name[nn]=C/C++-deklarasjonsinfo
+Name[pa]=C/C++ Header ਜਾਣਕਾਰੀ
+Name[pl]=Informacja z nagłówka C/C++
+Name[pt]=Informações do Cabeçalho de C/C++
+Name[pt_BR]=Informações sobre Cabeçalhos C/C++
+Name[ro]=Informaţii antet C/C++
+Name[ru]=Ð˜Ð½Ñ„Ð¾Ñ€Ð¼Ð°Ñ†Ð¸Ñ Ð¾ файлах заголовков C/C++
+Name[sk]=Informácie o hlaviÄkách C/C++
+Name[sl]=Informacije o glavi C/C++
+Name[sr]=Информације о C/C++ заглављу
+Name[sr@Latn]=Informacije o C/C++ zaglavlju
+Name[sv]=Information om C/C++-deklarationsfiler
+Name[ta]= =C/C++ தலைபà¯à®ªà¯ தகவலà¯
+Name[tg]=Ðхборот дар бораи Ñарлавҳаи файлҳои C/C++
+Name[th]=ข้อมูลà¹à¸Ÿà¹‰à¸¡à¸ªà¹ˆà¸§à¸™à¸«à¸±à¸§ C/C++
+Name[tr]=C/C++ Başlık Bilgisi
+Name[uk]=Ð†Ð½Ñ„Ð¾Ñ€Ð¼Ð°Ñ†Ñ–Ñ Ð¿Ð¾ заголовкам C++
+Name[xh]=C/C++ Ulwazi lokubhaliweyo okuphezulu
+Name[zh_CN]=C/C++ 头文件信æ¯
+Name[zh_TW]=C/C++ 檔頭資訊
+ServiceTypes=KFilePlugin
+X-KDE-Library=kfile_cpp
+MimeType=text/x-chdr
+PreferredItems=Lines,Code,Comment,Blank,Strings,i18n Strings,Included Files
diff --git a/kfile-plugins/diff/Makefile.am b/kfile-plugins/diff/Makefile.am
new file mode 100644
index 00000000..ea6cccc0
--- /dev/null
+++ b/kfile-plugins/diff/Makefile.am
@@ -0,0 +1,22 @@
+## Makefile.am for diff file meta info plugin
+
+# set the include path for X, qt and KDE
+INCLUDES = $(all_includes)
+
+# these are the headers for your project
+noinst_HEADERS = kfile_diff.h
+
+kde_module_LTLIBRARIES = kfile_diff.la
+
+kfile_diff_la_SOURCES = kfile_diff.cpp
+kfile_diff_la_LDFLAGS = $(all_libraries) -module $(KDE_PLUGIN)
+kfile_diff_la_LIBADD = $(LIB_KSYCOCA)
+
+# let automoc handle all of the meta source files (moc)
+METASOURCES = AUTO
+
+messages:
+ $(XGETTEXT) *.cpp *.h -o $(podir)/kfile_diff.pot
+
+services_DATA = kfile_diff.desktop
+servicesdir = $(kde_servicesdir)
diff --git a/kfile-plugins/diff/kfile_diff.cpp b/kfile-plugins/diff/kfile_diff.cpp
new file mode 100644
index 00000000..0f2fa02d
--- /dev/null
+++ b/kfile-plugins/diff/kfile_diff.cpp
@@ -0,0 +1,610 @@
+/**************************************************************************
+** kfile_diff.cpp
+** -------------------
+** begin : Sun Jan 20 23:25:44 2002
+** copyright : (C) 2002-2003 by Otto Bruggeman
+** email : otto.bruggeman@home.nl
+**
+***************************************************************************/
+/***************************************************************************
+**
+** This program is free software; you can redistribute it and/or modify
+** it under the terms of the GNU General Public License as published by
+** the Free Software Foundation; either version 2 of the License, or
+** (at your option) any later version.
+**
+***************************************************************************/
+
+/*
+** Patch by Volker Augustin for empty diff files. Februari 8, 2002
+**
+** Patched to work with CVS from after February 26, 2002 Otto
+**
+** Patched to work with CVS from after March 24, 2002 Otto
+**
+** Added support for Perforce diffs, April 26, 2003 Otto Bruggeman
+**
+** Added support for Subversion diffs, September 11, 2003 Otto Bruggeman
+*/
+
+#include <qcstring.h>
+#include <qdatetime.h>
+#include <qdict.h>
+#include <qfile.h>
+#include <qregexp.h>
+#include <qvalidator.h>
+
+#include <kdebug.h>
+#include <kgenericfactory.h>
+#include <klocale.h>
+#include <kprocess.h>
+#include <kurl.h>
+
+#include "kfile_diff.h"
+
+K_EXPORT_COMPONENT_FACTORY(kfile_diff, KGenericFactory<KDiffPlugin>("kfile_diff"))
+
+KDiffPlugin::KDiffPlugin(QObject *parent, const char *name,
+ const QStringList &preferredItems)
+ : KFilePlugin(parent, name, preferredItems)
+{
+ kdDebug(7034) << "diff plugin" << endl;
+
+ KFileMimeTypeInfo* info = addMimeTypeInfo( "text/x-diff" );
+
+ KFileMimeTypeInfo::GroupInfo* group;
+ group = addGroupInfo( info, "General", i18n( "General" ) );
+ addItemInfo( group, "Files", i18n( "Files" ), QVariant::UInt );
+ addItemInfo( group, "First", i18n( "First File" ), QVariant::String );
+ addItemInfo( group, "Format", i18n( "Format" ), QVariant::String );
+ addItemInfo( group, "DiffProgram", i18n( "Diff Program" ), QVariant::String );
+ addItemInfo( group, "Hunks", i18n( "Hunks" ), QVariant::UInt );
+ group = addGroupInfo( info, "Statistics", i18n( "Statistics" ) );
+ addItemInfo( group, "Insert", i18n( "Insertions" ), QVariant::UInt );
+ addItemInfo( group, "Modify", i18n( "Changes" ), QVariant::UInt );
+ addItemInfo( group, "Delete", i18n( "Deletions" ), QVariant::UInt );
+}
+
+bool KDiffPlugin::readInfo( KFileMetaInfo& info, uint what )
+{
+ // This is a hack to avoid using the what stuff, since it is not yet implemented
+ what = 0;
+
+ // Used to determine if false or true should be returned
+ bool dataSet = false;
+
+ KFileMetaInfoGroup group;
+
+ QFile file( info.path() );
+ QStringList lines;
+
+ if( file.open( IO_ReadOnly ) )
+ {
+ QTextStream stream( &file );
+ while (!stream.eof())
+ {
+ lines.append( stream.readLine() );
+ }
+ file.close();
+ }
+
+ QString format;
+ QString program;
+
+ enum KDiffPlugin::Format diffFormat;
+ enum KDiffPlugin::DiffProgram diffProgram;
+
+ diffFormat = determineDiffFormat ( lines );
+
+ format = determineI18nedFormat( diffFormat );
+
+ diffProgram = determineDiffProgram( lines );
+
+ program = determineI18nedProgram( diffProgram );
+
+ int numberOfAdditions = 0;
+ int numberOfDeletions = 0;
+ int numberOfChanges = 0;
+ int numberOfHunks = 0;
+ int numberOfFiles = 0;
+
+
+ if ( what != KFileMetaInfo::Fastest )
+ {
+ determineDiffInfo( lines, diffFormat, &numberOfFiles, &numberOfHunks, &numberOfAdditions, &numberOfChanges, &numberOfDeletions );
+ }
+
+ QString filename;
+ QRegExp firstFile( "^Index: (.*)" );
+ QStringList::ConstIterator it = lines.begin();
+
+ it = lines.begin();
+ while ( it != lines.end() )
+ {
+ if ( firstFile.exactMatch( (*it) ) )
+ {
+ filename = firstFile.cap(1);
+ // only interested in the first filename
+ break;
+ }
+ ++it;
+ }
+
+ kdDebug(7034) << "Diff Format : " << format << endl; // i18n-ed but that is not a problem unless i get i18n-ed debug output ah well, we'll figure something out when then happens
+
+ if (what != KFileMetaInfo::Fastest )
+ {
+ // These dont get calculated in fastest mode...
+ kdDebug(7034) << "Number of additions : " << numberOfAdditions << endl;
+ kdDebug(7034) << "Number of deletions : " << numberOfDeletions << endl;
+ kdDebug(7034) << "Number of changes : " << numberOfChanges << endl;
+ kdDebug(7034) << "Number of hunks : " << numberOfHunks << endl;
+ }
+
+ group = appendGroup( info, "General" );
+
+ if ( numberOfFiles != 0 && what != KFileMetaInfo::Fastest )
+ {
+ appendItem( group, "Files", numberOfFiles );
+ dataSet = true;
+ }
+
+ if ( !filename.isEmpty() )
+ {
+ appendItem( group, "First", filename );
+ dataSet = true;
+ }
+
+ if ( !format.isEmpty() )
+ {
+ appendItem( group, "Format", format );
+ dataSet = true;
+ }
+
+ if ( !program.isEmpty() )
+ {
+ appendItem( group, "DiffProgram", program );
+ dataSet = true;
+ }
+
+ if ( numberOfHunks != 0 && what != KFileMetaInfo::Fastest )
+ {
+ appendItem( group, "Hunks", numberOfHunks );
+ dataSet = true;
+ }
+
+ group = appendGroup( info, "Statistics" );
+
+ if ( numberOfAdditions != 0 && what != KFileMetaInfo::Fastest )
+ {
+ appendItem( group, "Insert", numberOfAdditions );
+ dataSet = true;
+ }
+
+ if ( numberOfChanges != 0 && what != KFileMetaInfo::Fastest )
+ {
+ appendItem( group, "Modify", numberOfChanges );
+ dataSet = true;
+ }
+
+ if ( numberOfDeletions != 0 && what != KFileMetaInfo::Fastest )
+ {
+ appendItem( group, "Delete", numberOfDeletions );
+ dataSet = true;
+ }
+
+ return dataSet;
+}
+
+enum KDiffPlugin::Format KDiffPlugin::determineDiffFormat( const QStringList lines ) const
+{
+ QString line;
+
+ if ( lines.count() == 0 )
+ {
+ return KDiffPlugin::Empty;
+ }
+
+ QStringList::ConstIterator it = lines.begin();
+
+ while ( it != lines.end() )
+ {
+ line = (*it);
+ if ( line.find( QRegExp( "^[0-9]+[0-9,]*[acd][0-9]+[0-9,]*$" ), 0 ) == 0 )
+ {
+ return KDiffPlugin::Normal;
+ }
+ else if ( line.find( QRegExp( "^--- " ), 0 ) == 0 )
+ {
+ // unified has first a '^--- ' line, then a '^+++ ' line
+ return KDiffPlugin::Unified;
+ }
+ else if ( line.find( QRegExp( "^\\*\\*\\* [^\\t]+\\t" ), 0 ) == 0 )
+ {
+ // context has first a '^*** ' line, then a '^--- ' line
+ return KDiffPlugin::Context;
+ }
+ else if ( line.find( QRegExp( "^[acd][0-9]+ [0-9]+" ), 0 ) == 0 )
+ {
+ return KDiffPlugin::RCS;
+ }
+ else if ( line.find( QRegExp( "^[0-9]+[0-9,]*[acd]" ), 0 ) == 0 )
+ {
+ return KDiffPlugin::Ed;
+ }
+ ++it;
+ }
+ return KDiffPlugin::Unknown;
+}
+
+enum KDiffPlugin::DiffProgram KDiffPlugin::determineDiffProgram( const QStringList lines ) const
+{
+ if ( lines.count() == 0 )
+ {
+ return KDiffPlugin::Undeterminable;
+ }
+
+ QStringList::ConstIterator it = lines.begin();
+ // very crude, might need some more refining
+ QRegExp diffRE( "^diff .*" );
+ QRegExp p4sRE("^==== ");
+
+ bool indexFound = false;
+
+ while ( it != lines.end() )
+ {
+ if ( (*it).startsWith( "Index:" ) )
+ indexFound = true;
+ else if ( (*it).startsWith( "retrieving revision") )
+ return KDiffPlugin::CVSDiff;
+ else if ( diffRE.exactMatch( *it ) )
+ return KDiffPlugin::Diff;
+ else if ( p4sRE.exactMatch( *it ) )
+ return KDiffPlugin::Perforce;
+
+ ++it;
+ }
+
+ if ( indexFound ) // but no "retrieving revision" found like only cvs diff adds.
+ return KDiffPlugin::SubVersion;
+
+ return KDiffPlugin::Undeterminable;
+}
+
+const QString KDiffPlugin::determineI18nedFormat( enum KDiffPlugin::Format diffFormat ) const
+{
+ QString format;
+ switch( diffFormat )
+ {
+ case KDiffPlugin::Context:
+ format = i18n( "Context" );
+ break;
+ case KDiffPlugin::Ed:
+ format = i18n( "Ed" );
+ break;
+ case KDiffPlugin::Normal:
+ format = i18n( "Normal" );
+ break;
+ case KDiffPlugin::RCS:
+ format = i18n( "RCS" );
+ break;
+ case KDiffPlugin::Unified:
+ format = i18n( "Unified" );
+ break;
+ case KDiffPlugin::Empty:
+ format = i18n( "Not Available (file empty)" );
+ break;
+ case KDiffPlugin::Unknown:
+ format = i18n( "Unknown" );
+ break;
+ case KDiffPlugin::SideBySide:
+ format = i18n( "Side by Side" );
+ }
+ return format;
+}
+
+const QString KDiffPlugin::determineI18nedProgram( enum KDiffPlugin::DiffProgram diffProgram ) const
+{
+ QString program;
+
+ switch( diffProgram )
+ {
+ case KDiffPlugin::CVSDiff:
+ program = i18n( "CVSDiff" );
+ break;
+ case KDiffPlugin::Diff:
+ program = i18n( "Diff" );
+ break;
+ case KDiffPlugin::Diff3:
+ program = i18n( "Diff3" );
+ break;
+ case KDiffPlugin::Perforce:
+ program = i18n( "Perforce" );
+ break;
+ case KDiffPlugin::SubVersion:
+ program = i18n( "SubVersion" );
+ break;
+ case KDiffPlugin::Undeterminable:
+ program = i18n( "Unknown" );
+ break;
+ }
+ return program;
+}
+
+void KDiffPlugin::determineDiffInfo( const QStringList lines,
+ enum KDiffPlugin::Format diffFormat,
+ int* numberOfFiles,
+ int* numberOfHunks,
+ int* numberOfAdditions,
+ int* numberOfChanges,
+ int* numberOfDeletions )
+{
+ QString line;
+
+ QRegExp edAdd( "([0-9]+)(|,([0-9]+))a" );
+ QRegExp edDel( "([0-9]+)(|,([0-9]+))d" );
+ QRegExp edMod( "([0-9]+)(|,([0-9]+))c" );
+
+ QRegExp normalAdd( "[0-9]+a([0-9]+)(|,([0-9]+))" );
+ QRegExp normalDel( "([0-9]+)(|,([0-9]+))d(|[0-9]+)" );
+ QRegExp normalMod( "([0-9]+)(|,([0-9]+))c([0-9]+)(|,([0-9]+))" );
+
+ QRegExp rcsAdd( "a[0-9]+ ([0-9]+)" );
+ QRegExp rcsDel( "d[0-9]+ ([0-9]+)" );
+
+ QStringList::ConstIterator it = lines.begin();
+
+ switch( diffFormat )
+ {
+ case KDiffPlugin::Context:
+ while ( it != lines.end() )
+ {
+ if ( (*it).startsWith("***************") )
+ {
+ (*numberOfHunks)++;
+// kdDebug(7034) << "Context Hunk : " << (*it) << endl;
+ }
+ else if ( (*it).startsWith("***") )
+ {
+ (*numberOfFiles)++;
+// kdDebug(7034) << "Context File : " << (*it) << endl;
+ }
+ else if ( (*it).startsWith("---") ) {} // ignore
+ else if ( (*it).startsWith("+") )
+ {
+ (*numberOfAdditions)++;
+// kdDebug(7034) << "Context Insertion : " << (*it) << endl;
+ }
+ else if ( (*it).startsWith("-") )
+ {
+ (*numberOfDeletions)++;
+// kdDebug(7034) << "Context Deletion : " << (*it) << endl;
+ }
+ else if ( (*it).startsWith("!") )
+ {
+ (*numberOfChanges)++;
+// kdDebug(7034) << "Context Modified : " << (*it) << endl;
+ }
+ else if ( (*it).startsWith(" ") )
+ {
+// kdDebug(7034) << "Context Context : " << (*it) << endl;
+ }
+ else
+ {
+// kdDebug(7034) << "Context Unknown : " << (*it) << endl;
+ }
+
+ ++it;
+ }
+ (*numberOfChanges) /= 2; // changes are in both parts of the hunks
+ (*numberOfFiles) -= (*numberOfHunks); // it counts old parts of a hunk as files :(
+ break;
+ case KDiffPlugin::Ed:
+ while ( it != lines.end() )
+ {
+ if ( (*it).startsWith( "diff" ) )
+ {
+ (*numberOfFiles)++;
+// kdDebug(7034) << "Ed File : " << (*it) << endl;
+ }
+ else if ( edAdd.exactMatch( (*it) ) )
+ {
+// kdDebug(7034) << "Ed Insertion : " << (*it) << endl;
+ (*numberOfHunks)++;
+ ++it;
+ while( it != lines.end() && !(*it).startsWith(".") )
+ {
+ (*numberOfAdditions)++;
+// kdDebug(7034) << "Ed Insertion : " << (*it) << endl;
+ ++it;
+ }
+ }
+ else if ( edDel.exactMatch( (*it) ) )
+ {
+// kdDebug(7034) << "Ed Deletion : " << (*it) << endl;
+ (*numberOfHunks)++;
+ (*numberOfDeletions) += (edDel.cap(3).isEmpty() ? 1 : edDel.cap(3).toInt() - edDel.cap(1).toInt() + 1);
+// kdDebug(7034) << "Ed noOfLines : " << (edDel.cap(3).isEmpty() ? 1 : edDel.cap(3).toInt() - edDel.cap(1).toInt() + 1) << endl;
+ }
+ else if ( edMod.exactMatch( (*it) ) )
+ {
+// kdDebug(7034) << "Ed Modification : " << (*it) << endl;
+ if ( edMod.cap(3).isEmpty() )
+ (*numberOfDeletions)++;
+ else
+ (*numberOfDeletions) += edMod.cap(3).toInt() - edMod.cap(1).toInt() + 1;
+ (*numberOfHunks)++;
+ ++it;
+ while( it != lines.end() && !(*it).startsWith(".") )
+ {
+ (*numberOfAdditions)++;
+// kdDebug(7034) << "Ed Modification : " << (*it) << endl;
+ ++it;
+ }
+ }
+ else
+ {
+// kdDebug(7034) << "Ed Unknown : " << (*it) << endl;
+ }
+
+ ++it;
+ }
+ break;
+ case KDiffPlugin::Normal:
+ while ( it != lines.end() )
+ {
+ if ( (*it).startsWith( "diff" ) )
+ {
+ (*numberOfFiles)++;
+// kdDebug(7034) << "Normal File : " << (*it) << endl;
+ }
+ else if ( normalAdd.exactMatch( *it ) )
+ {
+// kdDebug(7034) << "Normal Insertion : " << (*it) << endl;
+ (*numberOfHunks)++;
+ if ( normalAdd.cap(3).isEmpty() )
+ {
+ (*numberOfAdditions)++;
+// kdDebug(7034) << "Normal Addition : " << 1 << endl;
+ }
+ else
+ {
+ (*numberOfAdditions) += normalAdd.cap(3).toInt() - normalAdd.cap(1).toInt() + 1;
+// kdDebug(7034) << "Normal Addition : " << normalAdd.cap(3).toInt() - normalAdd.cap(1).toInt() + 1 << endl;
+ }
+ }
+ else if ( normalDel.exactMatch( *it ) )
+ {
+// kdDebug(7034) << "Normal Deletion : " << (*it) << endl;
+ (*numberOfHunks)++;
+ if ( normalDel.cap(3).isEmpty() )
+ {
+ (*numberOfDeletions)++;
+// kdDebug(7034) << "Normal Deletion : " << 1 << endl;
+ }
+ else
+ {
+ (*numberOfDeletions) += normalDel.cap(3).toInt() - normalDel.cap(1).toInt() + 1;
+// kdDebug(7034) << "Normal Deletion : " << normalDel.cap(3).toInt() - normalDel.cap(1).toInt() + 1 << endl;
+ }
+ }
+ else if ( normalMod.exactMatch( *it ) )
+ {
+// kdDebug(7034) << "Normal Modification : " << (*it) << endl;
+ (*numberOfHunks)++;
+ if ( normalMod.cap(3).isEmpty() )
+ {
+ (*numberOfDeletions)++;
+// kdDebug(7034) << "Normal Deletion : " << 1 << endl;
+ }
+ else
+ {
+ (*numberOfDeletions) += normalMod.cap(3).toInt() - normalMod.cap(1).toInt() + 1;
+// kdDebug(7034) << "Normal Deletion : " << normalMod.cap(3).toInt() - normalMod.cap(1).toInt() + 1 << endl;
+ }
+ if ( normalMod.cap(6).isEmpty() )
+ {
+ (*numberOfAdditions)++;
+// kdDebug(7034) << "Normal Addition : " << 1 << endl;
+ }
+ else
+ {
+ (*numberOfAdditions) += normalMod.cap(6).toInt() - normalMod.cap(4).toInt() + 1;
+// kdDebug(7034) << "Normal Addition : " << normalMod.cap(6).toInt() - normalMod.cap(4).toInt() + 1 << endl;
+ }
+ }
+ else if ( (*it).startsWith(">") )
+ {
+// numberOfAdditions++;
+// kdDebug(7034) << "Normal Insertion : " << (*it) << endl;
+ }
+ else if ( (*it).startsWith("<") )
+ {
+// numberOfDeletions++;
+// kdDebug(7034) << "Normal Deletion : " << (*it) << endl;
+ }
+ else
+ {
+// kdDebug(7034) << "Normal Unknown : " << (*it) << endl;
+ }
+
+ ++it;
+ }
+ break;
+ case KDiffPlugin::RCS:
+ while ( it != lines.end() )
+ {
+ if ( (*it).startsWith( "diff" ) ) // works for cvs diff, have to test for normal diff
+ {
+// kdDebug(7034) << "RCS File : " << (*it) << endl;
+ (*numberOfFiles)++;
+ }
+ else if ( rcsAdd.exactMatch( *it ) )
+ {
+// kdDebug(7034) << "RCS Insertion : " << (*it) << endl;
+ (*numberOfHunks)++;
+ (*numberOfAdditions) += rcsAdd.cap(1).toInt();
+// kdDebug(7034) << "RCS noOfLines : " << rcsAdd.cap(1).toInt() << endl;
+ }
+ else if ( rcsDel.exactMatch( *it ) )
+ {
+// kdDebug(7034) << "RCS Deletion : " << (*it) << endl;
+ (*numberOfHunks)++;
+ (*numberOfDeletions) += rcsDel.cap(1).toInt();
+// kdDebug(7034) << "RCS noOfLines : " << rcsDel.cap(1).toInt() << endl;
+ }
+ else
+ {
+// kdDebug(7034) << "RCS Unknown : " << (*it) << endl;
+ }
+
+ ++it;
+ }
+ break;
+ case KDiffPlugin::Unified:
+ while ( it != lines.end() )
+ {
+ if ( (*it).startsWith("@@ ") )
+ {
+ (*numberOfHunks)++;
+// kdDebug(7034) << "Unified Hunk : " << (*it) << endl;
+ }
+ else if ( (*it).startsWith("---") )
+ {
+ (*numberOfFiles)++;
+// kdDebug(7034) << "Unified File : " << (*it) << endl;
+ }
+ else if ( (*it).startsWith("+++") ) {} // ignore (dont count as insertion)
+ else if ( (*it).startsWith("+") )
+ {
+ (*numberOfAdditions)++;
+// kdDebug(7034) << "Unified Insertion : " << (*it) << endl;
+ }
+ else if ( (*it).startsWith("-") )
+ {
+ (*numberOfDeletions)++;
+// kdDebug(7034) << "Unified Deletion : " << (*it) << endl;
+ }
+ else if ( (*it).startsWith(" ") )
+ {
+// kdDebug(7034) << "Unified Context : " << (*it) << endl;
+ }
+ else
+ {
+// kdDebug(7034) << "Unified Unknown : " << (*it) << endl;
+ }
+
+ ++it;
+ }
+ break;
+ case KDiffPlugin::Empty:
+ case KDiffPlugin::Unknown:
+ case KDiffPlugin::SideBySide:
+ break;
+ }
+}
+
+#include "kfile_diff.moc"
+
+/* vim: set ts=4 sw=4 noet: */
+
diff --git a/kfile-plugins/diff/kfile_diff.desktop b/kfile-plugins/diff/kfile_diff.desktop
new file mode 100644
index 00000000..95b0bb78
--- /dev/null
+++ b/kfile-plugins/diff/kfile_diff.desktop
@@ -0,0 +1,57 @@
+[Desktop Entry]
+Type=Service
+Name=Diff Stats
+Name[af]=Diff Statistiek
+Name[bg]=СтатиÑтика за разлики
+Name[br]=Stadegoù Diff
+Name[bs]=Diff statistika
+Name[ca]=Estadístiques de diff
+Name[cs]=Statistika rozdílů
+Name[cy]=Ystadegau Gwahaniaethau
+Name[da]=Diff-stats
+Name[de]=Diff-Statistiken
+Name[el]=Στατιστικά diff
+Name[es]=Estadísticas Diff
+Name[et]=Võrdlemise tulemused
+Name[eu]=Desberdintasun estatistikak
+Name[fa]=آمارهای Diff
+Name[fi]=Diff-tilastot
+Name[fr]=Statistiques de diff
+Name[ga]=Staitistic Diff
+Name[gl]=Estatísticas de diff
+Name[he]=סטטיסטיקת Diff
+Name[hi]=डिफ सà¥à¤Ÿà¥‡à¤Ÿà¥à¤¸
+Name[hr]=Diff statistike
+Name[hu]=Diff statisztika
+Name[it]=Statistiche di confronto
+Name[ja]=Diff 統計
+Name[kk]=Diff ÑтатиÑтикаÑÑ‹
+Name[lt]=Skirtumų statistika
+Name[ms]=Stat Diff
+Name[nb]=Diff-statistikk
+Name[nds]=Verscheelstatistiken
+Name[ne]=भिनà¥à¤¨ तथà¥à¤¯à¤¾à¤™à¥à¤•
+Name[nl]=Diff-statistieken
+Name[nn]=Diff-statistikk
+Name[pa]=ਅੰਤਰ ਹਾਲਤ
+Name[pl]=Statystyka różnic
+Name[pt]=Estatísticas do diff
+Name[pt_BR]=Estados do Diff
+Name[ro]=Statistici Diff
+Name[ru]=СтатиÑтика различий
+Name[sk]=Å tatistiky Diff
+Name[sl]=Statistike diff
+Name[sr]=СтатиÑтика разликовања
+Name[sr@Latn]=Statistika razlikovanja
+Name[sv]=Diff-statistik
+Name[ta]=டிப௠ஸà¯à®Ÿà®Ÿà¯à®¸à¯
+Name[tg]=СтатиÑтикаи фарқиÑÑ‚
+Name[th]=สถานะà¹à¸•à¸à¸•à¹ˆà¸²à¸‡
+Name[tr]=Diff Ä°statistikleri
+Name[uk]=СтатиÑтика відмінноÑтей
+Name[zh_CN]=Diff 统计
+Name[zh_TW]=Diff 狀態
+ServiceTypes=KFilePlugin
+X-KDE-Library=kfile_diff
+MimeType=text/x-diff
+PreferredItems=Files,First,Format,Hunks,Insert,Modify,Delete
diff --git a/kfile-plugins/diff/kfile_diff.h b/kfile-plugins/diff/kfile_diff.h
new file mode 100644
index 00000000..d32e176c
--- /dev/null
+++ b/kfile-plugins/diff/kfile_diff.h
@@ -0,0 +1,52 @@
+/**************************************************************************
+** kfile_diff.h
+** -------------------
+** begin : Sun Jan 20 23:25:29 2002
+** copyright : (C) 2002 by Otto Bruggeman
+** email : otto.bruggeman@home.nl
+**
+***************************************************************************/
+/***************************************************************************
+**
+** This program is free software; you can redistribute it and/or modify
+** it under the terms of the 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 __KFILE_PDF_H__
+#define __KFILE_PDF_H__
+
+#include <kfilemetainfo.h>
+
+class QStringList;
+
+class KDiffPlugin: public KFilePlugin
+{
+ Q_OBJECT
+
+public:
+ KDiffPlugin( QObject *parent, const char *name,
+ const QStringList& preferredItems );
+
+
+ virtual bool readInfo( KFileMetaInfo& info, uint what );
+
+public:
+ enum Format { Context, Ed, Normal, RCS, Unified, Empty, SideBySide, Unknown };
+ enum DiffProgram { CVSDiff, Diff, Diff3, Perforce, SubVersion, Undeterminable }; // cant use Unknown again :(
+
+private:
+ enum Format determineDiffFormat ( const QStringList lines ) const;
+ enum DiffProgram determineDiffProgram ( const QStringList lines ) const;
+ const QString determineI18nedFormat ( enum KDiffPlugin::Format diffFormat ) const;
+ const QString determineI18nedProgram( enum KDiffPlugin::DiffProgram diffProgram ) const;
+ // yes ugly, it's better to use a struct or classmembers to pass these parameters around
+ void determineDiffInfo ( const QStringList lines,
+ enum KDiffPlugin::Format diffFormat, int* numberOfFiles,
+ int* numberOfHunks, int* numberOfAdditions,
+ int* numberOfChanges, int* numberOfDeletions );
+};
+
+#endif
diff --git a/kfile-plugins/ts/Makefile.am b/kfile-plugins/ts/Makefile.am
new file mode 100644
index 00000000..dd64ec48
--- /dev/null
+++ b/kfile-plugins/ts/Makefile.am
@@ -0,0 +1,21 @@
+## Makefile.am for text file meta info plugin
+
+# set the include path for X, qt and KDE
+INCLUDES = $(all_includes)
+
+noinst_HEADERS = kfile_ts.h
+
+kde_module_LTLIBRARIES = kfile_ts.la
+
+kfile_ts_la_SOURCES = kfile_ts.cpp
+kfile_ts_la_LDFLAGS = $(all_libraries) -module $(KDE_PLUGIN)
+kfile_ts_la_LIBADD = $(LIB_KIO)
+
+# let automoc handle all of the meta source files (moc)
+METASOURCES = AUTO
+
+messages:
+ $(XGETTEXT) *.cpp -o $(podir)/kfile_ts.pot
+
+services_DATA = kfile_ts.desktop
+servicesdir = $(kde_servicesdir)
diff --git a/kfile-plugins/ts/kfile_ts.cpp b/kfile-plugins/ts/kfile_ts.cpp
new file mode 100644
index 00000000..d6783fd7
--- /dev/null
+++ b/kfile-plugins/ts/kfile_ts.cpp
@@ -0,0 +1,93 @@
+/* This file is part of the KDE project
+ * Copyright (C) 2002 Carsten Niehaus <cniehaus@kde.org>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public
+ * License as published by the Free Software Foundation version 2.
+ *
+ * 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; see the file COPYING. If not, write to
+ * the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ */
+
+#include "kfile_ts.h"
+
+#include <kgenericfactory.h>
+#include <kdebug.h>
+
+#include <qfile.h>
+#include <qstringlist.h>
+
+typedef KGenericFactory<KTsPlugin> TsFactory;
+
+K_EXPORT_COMPONENT_FACTORY(kfile_ts, TsFactory("kfile_ts"))
+
+KTsPlugin::KTsPlugin(QObject *parent, const char *name,
+ const QStringList &args) : KFilePlugin(parent, name, args)
+{
+ makeMimeTypeInfo( "application/x-linguist" );
+}
+
+void KTsPlugin::makeMimeTypeInfo(const QString& mimeType)
+{
+ KFileMimeTypeInfo* info = addMimeTypeInfo(mimeType);
+
+ KFileMimeTypeInfo::GroupInfo* group =
+ addGroupInfo(info, "General", i18n("General"));
+
+ KFileMimeTypeInfo::ItemInfo* item;
+ item = addItemInfo(group, "Messages", i18n("Messages"), QVariant::Int);
+ setAttributes(item, KFileMimeTypeInfo::Averaged);
+ item = addItemInfo(group, "Translated", i18n("Translated"), QVariant::Int);
+ setAttributes(item, KFileMimeTypeInfo::Averaged);
+ item = addItemInfo(group, "Untranslated", i18n("Untranslated"), QVariant::Int);
+ setAttributes(item, KFileMimeTypeInfo::Averaged);
+ item = addItemInfo(group, "Obsolete", i18n("Obsolete"), QVariant::Int);
+}
+
+bool KTsPlugin::readInfo(KFileMetaInfo& info, uint)
+{
+ QFile f(info.path());
+ if (!f.open(IO_ReadOnly))
+ return false;
+
+ int messages = 0;
+ int untranslated = 0;
+ int obsolete = 0;
+
+ QTextStream stream( &f );
+ QString line = stream.readLine();
+
+ // is it really a linguist file?
+ if (!line.contains("<!DOCTYPE TS>", false))
+ return false;
+
+ while (!stream.eof())
+ {
+ line = stream.readLine();
+
+ if (line.contains("type=\"obsolete\"")) obsolete++;
+
+ if (line.contains("<source>")) messages++;
+
+ if (line.contains("type=\"unfinished\"")) untranslated++;
+
+ }
+
+ KFileMetaInfoGroup group = appendGroup(info, "General");
+ appendItem(group, "Messages", messages);
+ appendItem(group, "Translated", messages-untranslated-obsolete);
+ appendItem(group, "Untranslated", untranslated);
+ appendItem(group, "Obsolete", obsolete);
+
+ return true;
+}
+
+#include "kfile_ts.moc"
diff --git a/kfile-plugins/ts/kfile_ts.desktop b/kfile-plugins/ts/kfile_ts.desktop
new file mode 100644
index 00000000..09c3ae7d
--- /dev/null
+++ b/kfile-plugins/ts/kfile_ts.desktop
@@ -0,0 +1,54 @@
+[Desktop Entry]
+Type=Service
+Name=Qt Linguist File Info
+Name[bg]=Ð˜Ð½Ñ„Ð¾Ñ€Ð¼Ð°Ñ†Ð¸Ñ Ð·Ð° файла Qt Linguist
+Name[br]=Restr titouroù Qt Linguist
+Name[bs]=Qt Linguist informacije o datoteci
+Name[ca]=Informació fitxer de Qt Linguist
+Name[cs]=Info o souboru Qt Linguist
+Name[cy]=Gwybodaeth Ffeil Qt Linguist
+Name[da]=Qt Linguist Fil-info
+Name[de]=Qt Linguist-Dateiinfo
+Name[el]=ΠληÏοφοÏίες αÏχείου Qt Linguist
+Name[es]=Información de archivo de Qt Linguist
+Name[et]=Qt Linguisti faili info
+Name[eu]=Qt Linguist fitxategi informazioa
+Name[fa]=اطلاعات پروندۀ زبان‌شناسQt
+Name[fi]=Qt Linquist -tiedoston tiedot
+Name[fr]=Fichier d'informations Qt Linguist
+Name[ga]=Eolas faoi Chomhad Qt Linguist
+Name[gl]=Información do Ficheiro de Qt Linguist
+Name[hi]=कà¥à¤¯à¥‚टी लिंगà¥à¤µà¤¿à¤¸à¥à¤Ÿ फ़ाइल जानकारी
+Name[hu]=Qt Linguist fájljellemzők
+Name[is]=Qt Linguist skráarupplýsingar
+Name[it]=Informazioni file per Qt Linguist
+Name[ja]=Qt Linguist ファイル情報
+Name[ka]=Qt Linguist ფáƒáƒ˜áƒšáƒ˜áƒ¡ ინფáƒáƒ áƒ›áƒáƒªáƒ˜áƒ
+Name[kk]=Qt Linguist файл мәліметі
+Name[lt]=Qt Linguist bylos informacija
+Name[nb]=Informasjon om Qt Linguist-fil
+Name[nds]=QtLinguist-Datei-Info
+Name[ne]=Qt बहà¥à¤­à¤¾à¤·à¥€ फाइल सूचना
+Name[nl]=Qt Linquïst-bestandsinformatie
+Name[nn]=Informasjon om Qt Linguist-fil
+Name[pa]=Qt Linguist ਫਾਇਲ ਜਾਣਕਾਰੀ
+Name[pl]=Informacja pliku Qt Linguist
+Name[pt]=Informação do Ficheiro do Qt Linguist
+Name[pt_BR]=Arquivo de Informações de Lingüística do Qt
+Name[ru]=Ð˜Ð½Ñ„Ð¾Ñ€Ð¼Ð°Ñ†Ð¸Ñ Ð¾ файле в формате Qt Linguist
+Name[sk]=Informácie pre Qt Linguist
+Name[sl]=Informacije o Qt Linguist
+Name[sr]=Информације о фајлу Qt Linguist-а
+Name[sr@Latn]=Informacije o fajlu Qt Linguist-a
+Name[sv]=Qt Linguist-filinformation
+Name[ta]=Qt மொழியியல௠கோபà¯à®ªà¯à®•à®³à¯ தகவலà¯
+Name[tg]=Ðхборот дар бораи файл дар формати Qt Linguist
+Name[tr]=Qt Dilbilimci Dosya Bilgisi
+Name[uk]=Ñ–Ð½Ñ„Ð¾Ñ€Ð¼Ð°Ñ†Ñ–Ñ Ð¿Ñ€Ð¾ файл формату Qt Linguist
+Name[zh_CN]=Qt 语言大师文件信æ¯
+Name[zh_TW]=Qt 語言檔資訊
+ServiceTypes=KFilePlugin
+X-KDE-Library=kfile_ts
+MimeType=application/x-linguist
+PreferredGroups=General
+PreferredItems=Messages,Translated,Untranslated,Fuzzi
diff --git a/kfile-plugins/ts/kfile_ts.h b/kfile-plugins/ts/kfile_ts.h
new file mode 100644
index 00000000..0f976bbf
--- /dev/null
+++ b/kfile-plugins/ts/kfile_ts.h
@@ -0,0 +1,39 @@
+/* This file is part of the KDE project
+ * Copyright (C) 2002 Carsten Niehaus <cniehaus@kde.org>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public
+ * License as published by the Free Software Foundation version 2.
+ *
+ * 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; see the file COPYING. If not, write to
+ * the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ */
+
+#ifndef __KFILE_TS_H_
+#define __KFILE_TS_H_
+
+#include <kfilemetainfo.h>
+
+class QStringList;
+
+class KTsPlugin: public KFilePlugin
+{
+ Q_OBJECT
+
+public:
+ KTsPlugin(QObject *parent, const char *name, const QStringList& args);
+ virtual bool readInfo(KFileMetaInfo& info, uint what);
+
+private:
+ void makeMimeTypeInfo(const QString& mimeType);
+};
+
+#endif
diff --git a/kioslave/Makefile.am b/kioslave/Makefile.am
new file mode 100644
index 00000000..93c6570c
--- /dev/null
+++ b/kioslave/Makefile.am
@@ -0,0 +1,6 @@
+if include_kioslave_svn
+SVN_SUBDIR = svn
+endif
+
+SUBDIRS= $(SVN_SUBDIR)
+
diff --git a/kioslave/svn/AUTHORS b/kioslave/svn/AUTHORS
new file mode 100644
index 00000000..75a6fbc9
--- /dev/null
+++ b/kioslave/svn/AUTHORS
@@ -0,0 +1 @@
+Mickael Marchand <marchand@kde.org>
diff --git a/kioslave/svn/COPYING b/kioslave/svn/COPYING
new file mode 100644
index 00000000..f5030495
--- /dev/null
+++ b/kioslave/svn/COPYING
@@ -0,0 +1,481 @@
+ GNU LIBRARY GENERAL PUBLIC LICENSE
+ Version 2, June 1991
+
+ Copyright (C) 1991 Free Software Foundation, Inc.
+ 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+[This is the first released version of the library GPL. It is
+ numbered 2 because it goes with version 2 of the ordinary GPL.]
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+Licenses are intended to guarantee your freedom to share and change
+free software--to make sure the software is free for all its users.
+
+ This license, the Library General Public License, applies to some
+specially designated Free Software Foundation software, and to any
+other libraries whose authors decide to use it. You can use it for
+your libraries, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+ To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if
+you distribute copies of the library, or if you modify it.
+
+ For example, if you distribute copies of the library, whether gratis
+or for a fee, you must give the recipients all the rights that we gave
+you. You must make sure that they, too, receive or can get the source
+code. If you link a program with the library, you must provide
+complete object files to the recipients so that they can relink them
+with the library, after making changes to the library and recompiling
+it. And you must show them these terms so they know their rights.
+
+ Our method of protecting your rights has two steps: (1) copyright
+the library, and (2) offer you this license which gives you legal
+permission to copy, distribute and/or modify the library.
+
+ Also, for each distributor's protection, we want to make certain
+that everyone understands that there is no warranty for this free
+library. If the library is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original
+version, so that any problems introduced by others will not reflect on
+the original authors' reputations.
+
+ Finally, any free program is threatened constantly by software
+patents. We wish to avoid the danger that companies distributing free
+software will individually obtain patent licenses, thus in effect
+transforming the program into proprietary software. To prevent this,
+we have made it clear that any patent must be licensed for everyone's
+free use or not licensed at all.
+
+ Most GNU software, including some libraries, is covered by the ordinary
+GNU General Public License, which was designed for utility programs. This
+license, the GNU Library General Public License, applies to certain
+designated libraries. This license is quite different from the ordinary
+one; be sure to read it in full, and don't assume that anything in it is
+the same as in the ordinary license.
+
+ The reason we have a separate public license for some libraries is that
+they blur the distinction we usually make between modifying or adding to a
+program and simply using it. Linking a program with a library, without
+changing the library, is in some sense simply using the library, and is
+analogous to running a utility program or application program. However, in
+a textual and legal sense, the linked executable is a combined work, a
+derivative of the original library, and the ordinary General Public License
+treats it as such.
+
+ Because of this blurred distinction, using the ordinary General
+Public License for libraries did not effectively promote software
+sharing, because most developers did not use the libraries. We
+concluded that weaker conditions might promote sharing better.
+
+ However, unrestricted linking of non-free programs would deprive the
+users of those programs of all benefit from the free status of the
+libraries themselves. This Library General Public License is intended to
+permit developers of non-free programs to use free libraries, while
+preserving your freedom as a user of such programs to change the free
+libraries that are incorporated in them. (We have not seen how to achieve
+this as regards changes in header files, but we have achieved it as regards
+changes in the actual functions of the Library.) The hope is that this
+will lead to faster development of free libraries.
+
+ The precise terms and conditions for copying, distribution and
+modification follow. Pay close attention to the difference between a
+"work based on the library" and a "work that uses the library". The
+former contains code derived from the library, while the latter only
+works together with the library.
+
+ Note that it is possible for a library to be covered by the ordinary
+General Public License rather than by this special one.
+
+ GNU LIBRARY GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License Agreement applies to any software library which
+contains a notice placed by the copyright holder or other authorized
+party saying it may be distributed under the terms of this Library
+General Public License (also called "this License"). Each licensee is
+addressed as "you".
+
+ A "library" means a collection of software functions and/or data
+prepared so as to be conveniently linked with application programs
+(which use some of those functions and data) to form executables.
+
+ The "Library", below, refers to any such software library or work
+which has been distributed under these terms. A "work based on the
+Library" means either the Library or any derivative work under
+copyright law: that is to say, a work containing the Library or a
+portion of it, either verbatim or with modifications and/or translated
+straightforwardly into another language. (Hereinafter, translation is
+included without limitation in the term "modification".)
+
+ "Source code" for a work means the preferred form of the work for
+making modifications to it. For a library, complete source code means
+all the source code for all modules it contains, plus any associated
+interface definition files, plus the scripts used to control compilation
+and installation of the library.
+
+ Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running a program using the Library is not restricted, and output from
+such a program is covered only if its contents constitute a work based
+on the Library (independent of the use of the Library in a tool for
+writing it). Whether that is true depends on what the Library does
+and what the program that uses the Library does.
+
+ 1. You may copy and distribute verbatim copies of the Library's
+complete source code as you receive it, in any medium, provided that
+you conspicuously and appropriately publish on each copy an
+appropriate copyright notice and disclaimer of warranty; keep intact
+all the notices that refer to this License and to the absence of any
+warranty; and distribute a copy of this License along with the
+Library.
+
+ You may charge a fee for the physical act of transferring a copy,
+and you may at your option offer warranty protection in exchange for a
+fee.
+
+ 2. You may modify your copy or copies of the Library or any portion
+of it, thus forming a work based on the Library, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) The modified work must itself be a software library.
+
+ b) You must cause the files modified to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ c) You must cause the whole of the work to be licensed at no
+ charge to all third parties under the terms of this License.
+
+ d) If a facility in the modified Library refers to a function or a
+ table of data to be supplied by an application program that uses
+ the facility, other than as an argument passed when the facility
+ is invoked, then you must make a good faith effort to ensure that,
+ in the event an application does not supply such function or
+ table, the facility still operates, and performs whatever part of
+ its purpose remains meaningful.
+
+ (For example, a function in a library to compute square roots has
+ a purpose that is entirely well-defined independent of the
+ application. Therefore, Subsection 2d requires that any
+ application-supplied function or table used by this function must
+ be optional: if the application does not supply it, the square
+ root function must still compute square roots.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Library,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Library, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote
+it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Library.
+
+In addition, mere aggregation of another work not based on the Library
+with the Library (or with a work based on the Library) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may opt to apply the terms of the ordinary GNU General Public
+License instead of this License to a given copy of the Library. To do
+this, you must alter all the notices that refer to this License, so
+that they refer to the ordinary GNU General Public License, version 2,
+instead of to this License. (If a newer version than version 2 of the
+ordinary GNU General Public License has appeared, then you can specify
+that version instead if you wish.) Do not make any other change in
+these notices.
+
+ Once this change is made in a given copy, it is irreversible for
+that copy, so the ordinary GNU General Public License applies to all
+subsequent copies and derivative works made from that copy.
+
+ This option is useful when you wish to copy part of the code of
+the Library into a program that is not a library.
+
+ 4. You may copy and distribute the Library (or a portion or
+derivative of it, under Section 2) in object code or executable form
+under the terms of Sections 1 and 2 above provided that you accompany
+it with the complete corresponding machine-readable source code, which
+must be distributed under the terms of Sections 1 and 2 above on a
+medium customarily used for software interchange.
+
+ If distribution of object code is made by offering access to copy
+from a designated place, then offering equivalent access to copy the
+source code from the same place satisfies the requirement to
+distribute the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 5. A program that contains no derivative of any portion of the
+Library, but is designed to work with the Library by being compiled or
+linked with it, is called a "work that uses the Library". Such a
+work, in isolation, is not a derivative work of the Library, and
+therefore falls outside the scope of this License.
+
+ However, linking a "work that uses the Library" with the Library
+creates an executable that is a derivative of the Library (because it
+contains portions of the Library), rather than a "work that uses the
+library". The executable is therefore covered by this License.
+Section 6 states terms for distribution of such executables.
+
+ When a "work that uses the Library" uses material from a header file
+that is part of the Library, the object code for the work may be a
+derivative work of the Library even though the source code is not.
+Whether this is true is especially significant if the work can be
+linked without the Library, or if the work is itself a library. The
+threshold for this to be true is not precisely defined by law.
+
+ If such an object file uses only numerical parameters, data
+structure layouts and accessors, and small macros and small inline
+functions (ten lines or less in length), then the use of the object
+file is unrestricted, regardless of whether it is legally a derivative
+work. (Executables containing this object code plus portions of the
+Library will still fall under Section 6.)
+
+ Otherwise, if the work is a derivative of the Library, you may
+distribute the object code for the work under the terms of Section 6.
+Any executables containing that work also fall under Section 6,
+whether or not they are linked directly with the Library itself.
+
+ 6. As an exception to the Sections above, you may also compile or
+link a "work that uses the Library" with the Library to produce a
+work containing portions of the Library, and distribute that work
+under terms of your choice, provided that the terms permit
+modification of the work for the customer's own use and reverse
+engineering for debugging such modifications.
+
+ You must give prominent notice with each copy of the work that the
+Library is used in it and that the Library and its use are covered by
+this License. You must supply a copy of this License. If the work
+during execution displays copyright notices, you must include the
+copyright notice for the Library among them, as well as a reference
+directing the user to the copy of this License. Also, you must do one
+of these things:
+
+ a) Accompany the work with the complete corresponding
+ machine-readable source code for the Library including whatever
+ changes were used in the work (which must be distributed under
+ Sections 1 and 2 above); and, if the work is an executable linked
+ with the Library, with the complete machine-readable "work that
+ uses the Library", as object code and/or source code, so that the
+ user can modify the Library and then relink to produce a modified
+ executable containing the modified Library. (It is understood
+ that the user who changes the contents of definitions files in the
+ Library will not necessarily be able to recompile the application
+ to use the modified definitions.)
+
+ b) Accompany the work with a written offer, valid for at
+ least three years, to give the same user the materials
+ specified in Subsection 6a, above, for a charge no more
+ than the cost of performing this distribution.
+
+ c) If distribution of the work is made by offering access to copy
+ from a designated place, offer equivalent access to copy the above
+ specified materials from the same place.
+
+ d) Verify that the user has already received a copy of these
+ materials or that you have already sent this user a copy.
+
+ For an executable, the required form of the "work that uses the
+Library" must include any data and utility programs needed for
+reproducing the executable from it. However, as a special exception,
+the source code distributed need not include anything that is normally
+distributed (in either source or binary form) with the major
+components (compiler, kernel, and so on) of the operating system on
+which the executable runs, unless that component itself accompanies
+the executable.
+
+ It may happen that this requirement contradicts the license
+restrictions of other proprietary libraries that do not normally
+accompany the operating system. Such a contradiction means you cannot
+use both them and the Library together in an executable that you
+distribute.
+
+ 7. You may place library facilities that are a work based on the
+Library side-by-side in a single library together with other library
+facilities not covered by this License, and distribute such a combined
+library, provided that the separate distribution of the work based on
+the Library and of the other library facilities is otherwise
+permitted, and provided that you do these two things:
+
+ a) Accompany the combined library with a copy of the same work
+ based on the Library, uncombined with any other library
+ facilities. This must be distributed under the terms of the
+ Sections above.
+
+ b) Give prominent notice with the combined library of the fact
+ that part of it is a work based on the Library, and explaining
+ where to find the accompanying uncombined form of the same work.
+
+ 8. You may not copy, modify, sublicense, link with, or distribute
+the Library except as expressly provided under this License. Any
+attempt otherwise to copy, modify, sublicense, link with, or
+distribute the Library is void, and will automatically terminate your
+rights under this License. However, parties who have received copies,
+or rights, from you under this License will not have their licenses
+terminated so long as such parties remain in full compliance.
+
+ 9. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Library or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Library (or any work based on the
+Library), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Library or works based on it.
+
+ 10. Each time you redistribute the Library (or any work based on the
+Library), the recipient automatically receives a license from the
+original licensor to copy, distribute, link with or modify the Library
+subject to these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+ 11. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Library at all. For example, if a patent
+license would not permit royalty-free redistribution of the Library by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Library.
+
+If any portion of this section is held invalid or unenforceable under any
+particular circumstance, the balance of the section is intended to apply,
+and the section as a whole is intended to apply in other circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+ 12. If the distribution and/or use of the Library is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Library under this License may add
+an explicit geographical distribution limitation excluding those countries,
+so that distribution is permitted only in or among countries not thus
+excluded. In such case, this License incorporates the limitation as if
+written in the body of this License.
+
+ 13. The Free Software Foundation may publish revised and/or new
+versions of the Library General Public License from time to time.
+Such new versions will be similar in spirit to the present version,
+but may differ in detail to address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Library
+specifies a version number of this License which applies to it and
+"any later version", you have the option of following the terms and
+conditions either of that version or of any later version published by
+the Free Software Foundation. If the Library does not specify a
+license version number, you may choose any version ever published by
+the Free Software Foundation.
+
+ 14. If you wish to incorporate parts of the Library into other free
+programs whose distribution conditions are incompatible with these,
+write to the author to ask for permission. For software which is
+copyrighted by the Free Software Foundation, write to the Free
+Software Foundation; we sometimes make exceptions for this. Our
+decision will be guided by the two goals of preserving the free status
+of all derivatives of our free software and of promoting the sharing
+and reuse of software generally.
+
+ NO WARRANTY
+
+ 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
+WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
+EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
+OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
+KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
+LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
+THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+ 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
+WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
+AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
+FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
+CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
+LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
+RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
+FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
+SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+DAMAGES.
+
+ END OF TERMS AND CONDITIONS
+
+ How to Apply These Terms to Your New Libraries
+
+ If you develop a new library, and you want it to be of the greatest
+possible use to the public, we recommend making it free software that
+everyone can redistribute and change. You can do so by permitting
+redistribution under these terms (or, alternatively, under the terms of the
+ordinary General Public License).
+
+ To apply these terms, attach the following notices to the library. It is
+safest to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least the
+"copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the library's name and a brief idea of what it does.>
+ Copyright (C) <year> <name of author>
+
+ 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; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+Also add information on how to contact you by electronic and paper mail.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the library, if
+necessary. Here is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the
+ library `Frob' (a library for tweaking knobs) written by James Random Hacker.
+
+ <signature of Ty Coon>, 1 April 1990
+ Ty Coon, President of Vice
+
+That's all there is to it!
diff --git a/kioslave/svn/Makefile.am b/kioslave/svn/Makefile.am
new file mode 100644
index 00000000..1253820d
--- /dev/null
+++ b/kioslave/svn/Makefile.am
@@ -0,0 +1,15 @@
+SUBDIRS = ksvnd svnhelper icons
+
+INCLUDES = $(SVN_INCLUDE) $(all_includes)
+
+kde_module_LTLIBRARIES = kio_svn.la
+
+kio_svn_la_SOURCES = svn.cpp
+kio_svn_la_LIBADD = -lkio
+kio_svn_la_LDFLAGS = -avoid-version -module $(all_libraries) $(KDE_PLUGIN) $(SVNLD) $(SVN_LIB)
+
+protocol_DATA = svn+http.protocol svn+https.protocol svn+file.protocol svn+ssh.protocol svn.protocol
+protocoldir = $(kde_servicesdir)
+
+messages: rc.cpp
+ $(XGETTEXT) *.cpp -o $(podir)/kio_svn.pot
diff --git a/kioslave/svn/README b/kioslave/svn/README
new file mode 100644
index 00000000..6d851afa
--- /dev/null
+++ b/kioslave/svn/README
@@ -0,0 +1,40 @@
+This is a kio_subversion. It allows you to browse a (remote) Subversion repository.
+The expected URLs are something like : svn+http://svn.collab.net/repos/svn
+This will show you the current HEAD version of the repository (just like the one you would get
+with http://svn.collab.net/repos/svn).
+You can also try : svn+http://svn.collab.net/repos/svn?rev=500 so that it displays the revision 500.
+
+REQUIREMENTS:
+------------
+Subversion libraries >= 0.37.0 (http://subversion.tigris.org)
+
+FEATURES:
+---------
+Supported protocols :
+svn+http://hostname/path?rev=revision_number
+svn+https://hostname/path?rev=revision_number
+svn+ssh://hostname/path?rev=revision_number
+svn://hostname/path?rev=revision_number
+svn+file://repository/path?rev=revision_number
+
+INSTALL:
+--------
+you need the svn client library which is distributed by subversion.
+on Debian : apt-get install libsvn0-dev will do everything you need.
+
+you can pass the following arguments to configure to help it find your
+subversion/apr installations :
+
+--with-apr-config=FILE Use the given path to apr-config when determining APR configuration; defaults to "apr-config"
+--with-apu-config=FILE Use the given path to apu-config when determining APR util configuration; defaults to "apu-config"
+--with-subversion-dir=DIR where Subversion is installed
+--with-svn-include=DIR Use the given path to the subversion headers.
+--with-svn-lib=DIR Use the given path to the subversion libraries.
+
+BUGS:
+-----
+- file modifications time are wrong in konqui
+- kio_svn crashes often with subversion 1.2-rc2, needs investigation
+any other ?
+please report
+
diff --git a/kioslave/svn/TODO b/kioslave/svn/TODO
new file mode 100644
index 00000000..b5bbe683
--- /dev/null
+++ b/kioslave/svn/TODO
@@ -0,0 +1,74 @@
+For the menu options, tortoise SVN has something like below.
+We can follow this to some extent:
+
+Folder not in SVN at all:
+
+SVN Checkout
+Svn:
+ Export
+ Create Repository here
+ Import
+ ----
+ Settings...
+ Help
+
+A folder and a file in an SVN folder and in the SVN repository
+
+SVN Update
+SVN Commit....
+Svn:
+ Show Log
+ Check for modifications
+ Revision Graph
+ ----
+ Update to revision...
+ Rename...
+ Delete
+ Revert
+ Cleanup
+ ----
+ Branch/tag...
+ Switch...
+ Merge...
+ Export...
+ Relocate...
+ ----
+ Add (?)
+ ----
+ Create Patch...
+ Apply Patch...
+ ----
+ Settings...
+ Help
+
+A file in an SVN folder and in SVN repository
+
+SVN Update
+SVN Commit....
+Svn:
+ Show Log
+ Check for modifications
+ Revision Graph
+ ----
+ Update to revision...
+ Rename...
+ Delete
+ Revert
+ Cleanup
+ ----
+ Branch/tag...
+ Switch...
+ Merge...
+ Blame...
+ ----
+ Settings...
+ Help
+
+
+A file in SVN folder, but not in repos
+
+Svn:
+ Add
+ Add to ignore list
+
+
diff --git a/kioslave/svn/configure.in.bot b/kioslave/svn/configure.in.bot
new file mode 100644
index 00000000..ccab94db
--- /dev/null
+++ b/kioslave/svn/configure.in.bot
@@ -0,0 +1,9 @@
+if test "x$with_subversion" = xcheck && test -z "$SVN_SUBDIR"; then
+ echo ""
+ echo "You're missing Subversion libraries (1.x)"
+ echo "KDE will not be able to browse Subversion repositories without it,"
+ echo "consider installing it."
+ echo "Look at kioslave/svn/README for more information"
+ echo ""
+ all_tests=bad
+fi
diff --git a/kioslave/svn/configure.in.in b/kioslave/svn/configure.in.in
new file mode 100644
index 00000000..9e962c08
--- /dev/null
+++ b/kioslave/svn/configure.in.in
@@ -0,0 +1,157 @@
+AC_ARG_WITH(subversion,
+ [AC_HELP_STRING(--with-subversion,
+ [enable support for subversion @<:@default=check@:>@])],
+ [], with_subversion=check)
+
+SVN_SUBDIR=""
+if test "x$with_subversion" != xno; then
+
+APR_CONFIGS="apr-config apr-1-config /usr/local/apr/bin/apr-config"
+SVN_SUBDIR="svn"
+AC_ARG_WITH(apr-config,
+[[ --with-apr-config=FILE Use the given path to apr-config when determining
+ APR configuration; defaults to "apr-config"]],
+[
+ if test "$withval" != "yes" -a "$withval" != ""; then
+ APR_CONFIGS=$withval
+ fi
+])
+AC_MSG_CHECKING([for APR])
+APR_CONFIG=""
+for VALUE in $APR_CONFIGS ; do
+ if $VALUE --cflags > /dev/null; then
+ APR_CONFIG=$VALUE
+ break
+ fi
+done
+test $VALUE && APR_CONFIG=$VALUE
+if test $APR_CONFIG ; then
+ AC_MSG_RESULT([found])
+else
+ AC_MSG_RESULT([not found])
+ SVN_SUBDIR=
+dnl AC_MSG_ERROR([APR is required. Try --with-apr-config.])
+fi
+
+APR_CPPFLAGS="`$APR_CONFIG --cppflags`"
+APR_INCLUDE="`$APR_CONFIG --includes`"
+APR_LIBS="`$APR_CONFIG --link-ld --libs`"
+
+dnl
+dnl APR util
+dnl
+
+APU_CONFIGS="apu-config apu-1-config /usr/local/apr/bin/apu-config"
+AC_ARG_WITH(apu-config,
+[[ --with-apu-config=FILE Use the given path to apu-config when determining
+ APR util configuration; defaults to "apu-config"]],
+[
+ if test "$withval" != "yes" -a "$withval" != ""; then
+ APU_CONFIGS=$withval
+ fi
+])
+AC_MSG_CHECKING([for APR util])
+APU_CONFIG=""
+for VALUE in $APU_CONFIGS ; do
+ if $VALUE --includes > /dev/null; then
+ APU_CONFIG=$VALUE
+ break
+ fi
+done
+if test $APU_CONFIG ; then
+ AC_MSG_RESULT([found])
+else
+ AC_MSG_RESULT([not found])
+ SVN_SUBDIR=
+dnl AC_MSG_ERROR([APR util is required. Try --with-apu-config.])
+fi
+dnl APR_CPPFLAGS="$APR_CPPFLAGS `$APU_CONFIG --includes`"
+APR_INCLUDE="$APR_INCLUDE `$APU_CONFIG --includes`"
+APR_LIBS="$APR_LIBS `$APU_CONFIG --link-ld --libs`"
+
+AC_MSG_CHECKING(for Subversion svn-config)
+AC_ARG_WITH(subversion-dir,
+ [ --with-subversion-dir=DIR where Subversion is installed ],
+ [
+ SVNCONFIG="$withval/bin/svn-config"
+ ])
+
+if test -z "$SVNCONFIG"; then
+ _SVNCONFIG="`svn-config --prefix 2> /dev/null`"
+ if test -n "$_SVNCONFIG"; then
+ SVNCONFIG="$_SVNCONFIG/bin/svn-config"
+ fi
+fi
+
+AC_SUBST(SVNCONFIG)
+if test -x "$SVNCONFIG"; then
+ SVNLD="`$SVNCONFIG --ldflags`"
+ SVN_LIB="`$SVNCONFIG --libs` -lsvn_client-1"
+ SVN_CPPFLAGS="`$SVNCONFIG --cppflags`"
+ dnl ugly hack for subversion svn-config problems in 0.14.x, to be removed when svn-config is fixed
+ SVN_INCLUDE="`$SVNCONFIG --includes` -I$_SVNCONFIG/include/subversion-1/"
+ AC_MSG_RESULT(yes)
+else
+ AC_MSG_RESULT(not found)
+ SVNLD=""
+ dnl just a fallback to debian's config so that it works for me :)
+ SVN_INCLUDES="/usr/local/include /usr/include"
+ AC_ARG_WITH(svn-include,
+ [[ --with-svn-include=DIR Use the given path to the subversion headers.]],
+ [
+ if test "$withval" != "yes" -a "$withval" != ""; then
+ SVN_INCLUDES=$withval
+ fi
+ ])
+ AC_MSG_CHECKING([for Subversion headers])
+ SVN_INCLUDE=""
+ for VALUE in $SVN_INCLUDES ; do
+ if test -f $VALUE/subversion-1/svn_types.h ; then
+ SVN_INCLUDE="-I$VALUE"
+ break
+ fi
+ done
+ if test $SVN_INCLUDE ; then
+ AC_MSG_RESULT([found])
+ else
+ AC_MSG_RESULT([not found])
+ SVN_SUBDIR=
+dnl AC_MSG_ERROR([Subversion headers are required. Try --with-svn-include.])
+ fi
+ SVN_LIBS="/usr/local/lib /usr/lib /usr/lib64"
+ AC_ARG_WITH(svn-lib,
+ [[ --with-svn-lib=DIR Use the given path to the subversion libraries.]],
+ [
+ if test "$withval" != "yes" -a "$withval" != ""; then
+ SVN_LIBS=$withval
+ fi
+ ])
+ AC_MSG_CHECKING([for Subversion libraries])
+ SVN_LIB=""
+ for VALUE in $SVN_LIBS ; do
+ if ls $VALUE/libsvn_client-1.* 1>/dev/null 2>&1; then
+ SVN_LIB="-L$VALUE"
+ break
+ fi
+ done
+ if test $SVN_LIB ; then
+ AC_MSG_RESULT([found])
+ else
+ AC_MSG_RESULT([not found])
+ SVN_SUBDIR=
+ fi
+fi
+SVN_LIB="$SVN_LIB $APR_LIBS -lsvn_client-1"
+SVN_INCLUDE="$SVN_INCLUDE $APR_INCLUDE"
+SVN_CPPFLAGS="$APR_CPPFLAGS $SVN_CPPFLAGS"
+
+if test "x$with_subversion" != xcheck && test -z "$SVN_SUBDIR"; then
+ AC_MSG_ERROR([--with-subversion was given, but test for subversion failed])
+fi
+fi
+
+AC_SUBST(SVN_INCLUDE)
+AC_SUBST(SVN_LIB)
+AC_SUBST(SVN_CPPFLAGS)
+AC_SUBST(SVNLD)
+AM_CONDITIONAL(include_kioslave_svn, test -n "$SVN_SUBDIR")
diff --git a/kioslave/svn/icons/Makefile.am b/kioslave/svn/icons/Makefile.am
new file mode 100644
index 00000000..a4b97f06
--- /dev/null
+++ b/kioslave/svn/icons/Makefile.am
@@ -0,0 +1 @@
+KDE_ICON=AUTO
diff --git a/kioslave/svn/icons/cr128-action-svn_add.png b/kioslave/svn/icons/cr128-action-svn_add.png
new file mode 100644
index 00000000..0b26fdbc
--- /dev/null
+++ b/kioslave/svn/icons/cr128-action-svn_add.png
Binary files differ
diff --git a/kioslave/svn/icons/cr128-action-svn_branch.png b/kioslave/svn/icons/cr128-action-svn_branch.png
new file mode 100644
index 00000000..9fafce71
--- /dev/null
+++ b/kioslave/svn/icons/cr128-action-svn_branch.png
Binary files differ
diff --git a/kioslave/svn/icons/cr128-action-svn_merge.png b/kioslave/svn/icons/cr128-action-svn_merge.png
new file mode 100644
index 00000000..8d534b3a
--- /dev/null
+++ b/kioslave/svn/icons/cr128-action-svn_merge.png
Binary files differ
diff --git a/kioslave/svn/icons/cr128-action-svn_remove.png b/kioslave/svn/icons/cr128-action-svn_remove.png
new file mode 100644
index 00000000..2af59d2f
--- /dev/null
+++ b/kioslave/svn/icons/cr128-action-svn_remove.png
Binary files differ
diff --git a/kioslave/svn/icons/cr128-action-svn_status.png b/kioslave/svn/icons/cr128-action-svn_status.png
new file mode 100644
index 00000000..bcbfaaa3
--- /dev/null
+++ b/kioslave/svn/icons/cr128-action-svn_status.png
Binary files differ
diff --git a/kioslave/svn/icons/cr128-action-svn_switch.png b/kioslave/svn/icons/cr128-action-svn_switch.png
new file mode 100644
index 00000000..74fbded1
--- /dev/null
+++ b/kioslave/svn/icons/cr128-action-svn_switch.png
Binary files differ
diff --git a/kioslave/svn/icons/cr16-action-svn_add.png b/kioslave/svn/icons/cr16-action-svn_add.png
new file mode 100644
index 00000000..70769a36
--- /dev/null
+++ b/kioslave/svn/icons/cr16-action-svn_add.png
Binary files differ
diff --git a/kioslave/svn/icons/cr16-action-svn_branch.png b/kioslave/svn/icons/cr16-action-svn_branch.png
new file mode 100644
index 00000000..f8c701f0
--- /dev/null
+++ b/kioslave/svn/icons/cr16-action-svn_branch.png
Binary files differ
diff --git a/kioslave/svn/icons/cr16-action-svn_merge.png b/kioslave/svn/icons/cr16-action-svn_merge.png
new file mode 100644
index 00000000..1321a5fd
--- /dev/null
+++ b/kioslave/svn/icons/cr16-action-svn_merge.png
Binary files differ
diff --git a/kioslave/svn/icons/cr16-action-svn_remove.png b/kioslave/svn/icons/cr16-action-svn_remove.png
new file mode 100644
index 00000000..8f6f3040
--- /dev/null
+++ b/kioslave/svn/icons/cr16-action-svn_remove.png
Binary files differ
diff --git a/kioslave/svn/icons/cr16-action-svn_status.png b/kioslave/svn/icons/cr16-action-svn_status.png
new file mode 100644
index 00000000..8ad00fd7
--- /dev/null
+++ b/kioslave/svn/icons/cr16-action-svn_status.png
Binary files differ
diff --git a/kioslave/svn/icons/cr16-action-svn_switch.png b/kioslave/svn/icons/cr16-action-svn_switch.png
new file mode 100644
index 00000000..c28b3b98
--- /dev/null
+++ b/kioslave/svn/icons/cr16-action-svn_switch.png
Binary files differ
diff --git a/kioslave/svn/icons/cr22-action-svn_add.png b/kioslave/svn/icons/cr22-action-svn_add.png
new file mode 100644
index 00000000..249005eb
--- /dev/null
+++ b/kioslave/svn/icons/cr22-action-svn_add.png
Binary files differ
diff --git a/kioslave/svn/icons/cr22-action-svn_branch.png b/kioslave/svn/icons/cr22-action-svn_branch.png
new file mode 100644
index 00000000..db729c2a
--- /dev/null
+++ b/kioslave/svn/icons/cr22-action-svn_branch.png
Binary files differ
diff --git a/kioslave/svn/icons/cr22-action-svn_merge.png b/kioslave/svn/icons/cr22-action-svn_merge.png
new file mode 100644
index 00000000..08b1a53f
--- /dev/null
+++ b/kioslave/svn/icons/cr22-action-svn_merge.png
Binary files differ
diff --git a/kioslave/svn/icons/cr22-action-svn_remove.png b/kioslave/svn/icons/cr22-action-svn_remove.png
new file mode 100644
index 00000000..3005c2ac
--- /dev/null
+++ b/kioslave/svn/icons/cr22-action-svn_remove.png
Binary files differ
diff --git a/kioslave/svn/icons/cr22-action-svn_status.png b/kioslave/svn/icons/cr22-action-svn_status.png
new file mode 100644
index 00000000..5561af4b
--- /dev/null
+++ b/kioslave/svn/icons/cr22-action-svn_status.png
Binary files differ
diff --git a/kioslave/svn/icons/cr22-action-svn_switch.png b/kioslave/svn/icons/cr22-action-svn_switch.png
new file mode 100644
index 00000000..e6a92dcc
--- /dev/null
+++ b/kioslave/svn/icons/cr22-action-svn_switch.png
Binary files differ
diff --git a/kioslave/svn/icons/cr32-action-svn_add.png b/kioslave/svn/icons/cr32-action-svn_add.png
new file mode 100644
index 00000000..63b987bd
--- /dev/null
+++ b/kioslave/svn/icons/cr32-action-svn_add.png
Binary files differ
diff --git a/kioslave/svn/icons/cr32-action-svn_branch.png b/kioslave/svn/icons/cr32-action-svn_branch.png
new file mode 100644
index 00000000..4fbd9c3f
--- /dev/null
+++ b/kioslave/svn/icons/cr32-action-svn_branch.png
Binary files differ
diff --git a/kioslave/svn/icons/cr32-action-svn_merge.png b/kioslave/svn/icons/cr32-action-svn_merge.png
new file mode 100644
index 00000000..0b2b42e2
--- /dev/null
+++ b/kioslave/svn/icons/cr32-action-svn_merge.png
Binary files differ
diff --git a/kioslave/svn/icons/cr32-action-svn_remove.png b/kioslave/svn/icons/cr32-action-svn_remove.png
new file mode 100644
index 00000000..5a213d57
--- /dev/null
+++ b/kioslave/svn/icons/cr32-action-svn_remove.png
Binary files differ
diff --git a/kioslave/svn/icons/cr32-action-svn_status.png b/kioslave/svn/icons/cr32-action-svn_status.png
new file mode 100644
index 00000000..5fb3df96
--- /dev/null
+++ b/kioslave/svn/icons/cr32-action-svn_status.png
Binary files differ
diff --git a/kioslave/svn/icons/cr32-action-svn_switch.png b/kioslave/svn/icons/cr32-action-svn_switch.png
new file mode 100644
index 00000000..28724155
--- /dev/null
+++ b/kioslave/svn/icons/cr32-action-svn_switch.png
Binary files differ
diff --git a/kioslave/svn/icons/cr48-action-svn_add.png b/kioslave/svn/icons/cr48-action-svn_add.png
new file mode 100644
index 00000000..4f4f7f34
--- /dev/null
+++ b/kioslave/svn/icons/cr48-action-svn_add.png
Binary files differ
diff --git a/kioslave/svn/icons/cr48-action-svn_branch.png b/kioslave/svn/icons/cr48-action-svn_branch.png
new file mode 100644
index 00000000..d7fe093e
--- /dev/null
+++ b/kioslave/svn/icons/cr48-action-svn_branch.png
Binary files differ
diff --git a/kioslave/svn/icons/cr48-action-svn_merge.png b/kioslave/svn/icons/cr48-action-svn_merge.png
new file mode 100644
index 00000000..a052acb1
--- /dev/null
+++ b/kioslave/svn/icons/cr48-action-svn_merge.png
Binary files differ
diff --git a/kioslave/svn/icons/cr48-action-svn_remove.png b/kioslave/svn/icons/cr48-action-svn_remove.png
new file mode 100644
index 00000000..df562606
--- /dev/null
+++ b/kioslave/svn/icons/cr48-action-svn_remove.png
Binary files differ
diff --git a/kioslave/svn/icons/cr48-action-svn_status.png b/kioslave/svn/icons/cr48-action-svn_status.png
new file mode 100644
index 00000000..f98d11eb
--- /dev/null
+++ b/kioslave/svn/icons/cr48-action-svn_status.png
Binary files differ
diff --git a/kioslave/svn/icons/cr48-action-svn_switch.png b/kioslave/svn/icons/cr48-action-svn_switch.png
new file mode 100644
index 00000000..131d897d
--- /dev/null
+++ b/kioslave/svn/icons/cr48-action-svn_switch.png
Binary files differ
diff --git a/kioslave/svn/icons/cr64-action-svn_add.png b/kioslave/svn/icons/cr64-action-svn_add.png
new file mode 100644
index 00000000..54091c32
--- /dev/null
+++ b/kioslave/svn/icons/cr64-action-svn_add.png
Binary files differ
diff --git a/kioslave/svn/icons/cr64-action-svn_branch.png b/kioslave/svn/icons/cr64-action-svn_branch.png
new file mode 100644
index 00000000..74deadc6
--- /dev/null
+++ b/kioslave/svn/icons/cr64-action-svn_branch.png
Binary files differ
diff --git a/kioslave/svn/icons/cr64-action-svn_merge.png b/kioslave/svn/icons/cr64-action-svn_merge.png
new file mode 100644
index 00000000..b73ec742
--- /dev/null
+++ b/kioslave/svn/icons/cr64-action-svn_merge.png
Binary files differ
diff --git a/kioslave/svn/icons/cr64-action-svn_remove.png b/kioslave/svn/icons/cr64-action-svn_remove.png
new file mode 100644
index 00000000..db521dc3
--- /dev/null
+++ b/kioslave/svn/icons/cr64-action-svn_remove.png
Binary files differ
diff --git a/kioslave/svn/icons/cr64-action-svn_status.png b/kioslave/svn/icons/cr64-action-svn_status.png
new file mode 100644
index 00000000..fba134bc
--- /dev/null
+++ b/kioslave/svn/icons/cr64-action-svn_status.png
Binary files differ
diff --git a/kioslave/svn/icons/cr64-action-svn_switch.png b/kioslave/svn/icons/cr64-action-svn_switch.png
new file mode 100644
index 00000000..84fd6ee5
--- /dev/null
+++ b/kioslave/svn/icons/cr64-action-svn_switch.png
Binary files differ
diff --git a/kioslave/svn/icons/crsc-action-svn_add.svgz b/kioslave/svn/icons/crsc-action-svn_add.svgz
new file mode 100644
index 00000000..8092028e
--- /dev/null
+++ b/kioslave/svn/icons/crsc-action-svn_add.svgz
Binary files differ
diff --git a/kioslave/svn/icons/crsc-action-svn_branch.svgz b/kioslave/svn/icons/crsc-action-svn_branch.svgz
new file mode 100644
index 00000000..1622c9f6
--- /dev/null
+++ b/kioslave/svn/icons/crsc-action-svn_branch.svgz
Binary files differ
diff --git a/kioslave/svn/icons/crsc-action-svn_merge.svgz b/kioslave/svn/icons/crsc-action-svn_merge.svgz
new file mode 100644
index 00000000..56f18c44
--- /dev/null
+++ b/kioslave/svn/icons/crsc-action-svn_merge.svgz
Binary files differ
diff --git a/kioslave/svn/icons/crsc-action-svn_remove.svgz b/kioslave/svn/icons/crsc-action-svn_remove.svgz
new file mode 100644
index 00000000..cf0db832
--- /dev/null
+++ b/kioslave/svn/icons/crsc-action-svn_remove.svgz
Binary files differ
diff --git a/kioslave/svn/icons/crsc-action-svn_status.svgz b/kioslave/svn/icons/crsc-action-svn_status.svgz
new file mode 100644
index 00000000..1a6ba518
--- /dev/null
+++ b/kioslave/svn/icons/crsc-action-svn_status.svgz
Binary files differ
diff --git a/kioslave/svn/icons/crsc-action-svn_switch.svgz b/kioslave/svn/icons/crsc-action-svn_switch.svgz
new file mode 100644
index 00000000..4717aac2
--- /dev/null
+++ b/kioslave/svn/icons/crsc-action-svn_switch.svgz
Binary files differ
diff --git a/kioslave/svn/ksvnd/Makefile.am b/kioslave/svn/ksvnd/Makefile.am
new file mode 100644
index 00000000..a466be08
--- /dev/null
+++ b/kioslave/svn/ksvnd/Makefile.am
@@ -0,0 +1,13 @@
+#INCLUDES= -I$(top_srcdir)/kwallet/client $(all_includes)
+INCLUDES= $(all_includes)
+
+kde_module_LTLIBRARIES = kded_ksvnd.la
+
+kded_ksvnd_la_SOURCES = commitdlg.ui ksvnd.cpp ksvnd.skel
+kded_ksvnd_la_METASOURCES = AUTO
+kded_ksvnd_la_LDFLAGS = $(all_libraries) -module -avoid-version
+#kded_ksvnd_la_LIBADD = $(top_builddir)/kwallet/client/libkwalletclient.la $(LIB_KIO)
+kded_ksvnd_la_LIBADD = $(LIB_KIO)
+
+kded_DATA = ksvnd.desktop
+kdeddir = $(kde_servicesdir)/kded
diff --git a/kioslave/svn/ksvnd/commitdlg.ui b/kioslave/svn/ksvnd/commitdlg.ui
new file mode 100644
index 00000000..7425e5c9
--- /dev/null
+++ b/kioslave/svn/ksvnd/commitdlg.ui
@@ -0,0 +1,116 @@
+<!DOCTYPE UI><UI version="3.2" stdsetdef="1">
+<class>CommitDlg</class>
+<widget class="QDialog">
+ <property name="name">
+ <cstring>CommitDlg</cstring>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>451</width>
+ <height>337</height>
+ </rect>
+ </property>
+ <property name="caption">
+ <string>Log Message</string>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>layout2</cstring>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="KTextEdit">
+ <property name="name">
+ <cstring>textMessage</cstring>
+ </property>
+ </widget>
+ <widget class="KTextEdit">
+ <property name="name">
+ <cstring>listMessage</cstring>
+ </property>
+ <property name="readOnly">
+ <bool>true</bool>
+ </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>220</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ <widget class="QPushButton">
+ <property name="name">
+ <cstring>pushButton1</cstring>
+ </property>
+ <property name="text">
+ <string>&amp;OK</string>
+ </property>
+ </widget>
+ <widget class="QPushButton">
+ <property name="name">
+ <cstring>pushButton2</cstring>
+ </property>
+ <property name="text">
+ <string>&amp;Cancel</string>
+ </property>
+ </widget>
+ </hbox>
+ </widget>
+ </vbox>
+ </widget>
+ </vbox>
+</widget>
+<connections>
+ <connection>
+ <sender>pushButton1</sender>
+ <signal>clicked()</signal>
+ <receiver>CommitDlg</receiver>
+ <slot>accept()</slot>
+ </connection>
+ <connection>
+ <sender>pushButton2</sender>
+ <signal>clicked()</signal>
+ <receiver>CommitDlg</receiver>
+ <slot>reject()</slot>
+ </connection>
+</connections>
+<includes>
+ <include location="local" impldecl="in implementation">commitdlg.ui.h</include>
+</includes>
+<functions>
+ <function>setLog( const QString &amp; comment )</function>
+ <function returnType="QString">logMessage() const</function>
+</functions>
+<layoutdefaults spacing="6" margin="11"/>
+<includehints>
+ <includehint>ktextedit.h</includehint>
+ <includehint>ktextedit.h</includehint>
+</includehints>
+</UI>
diff --git a/kioslave/svn/ksvnd/commitdlg.ui.h b/kioslave/svn/ksvnd/commitdlg.ui.h
new file mode 100644
index 00000000..296d55c0
--- /dev/null
+++ b/kioslave/svn/ksvnd/commitdlg.ui.h
@@ -0,0 +1,30 @@
+/* This file is part of the KDE project
+ Copyright (C) 2004 Mickael Marchand <marchand@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.
+*/
+
+
+void CommitDlg::setLog( const QString & comment )
+{
+listMessage->setText(comment);
+}
+
+
+QString CommitDlg::logMessage() const
+{
+return textMessage->text();
+}
diff --git a/kioslave/svn/ksvnd/ksvnd.cpp b/kioslave/svn/ksvnd/ksvnd.cpp
new file mode 100644
index 00000000..c9701647
--- /dev/null
+++ b/kioslave/svn/ksvnd/ksvnd.cpp
@@ -0,0 +1,351 @@
+/*
+ This file is part of the KDE Project
+
+ Copyright (C) 2003, 2004 Mickael Marchand <marchand@kde.org>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License
+ version 2 as published by the Free Software Foundation.
+
+ This software 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 library; see the file COPYING. If not, write to
+ the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+*/
+
+#include <kapplication.h>
+#include <klocale.h>
+#include <kdebug.h>
+#include <kmessagebox.h>
+#include <qdir.h>
+#include <qfile.h>
+
+#include "config.h"
+
+#include "ksvnd.h"
+#include "commitdlg.h"
+
+extern "C" {
+ KDE_EXPORT KDEDModule *create_ksvnd(const QCString &name) {
+ return new KSvnd(name);
+ }
+}
+
+KSvnd::KSvnd(const QCString &name)
+ : KDEDModule(name) {
+}
+
+KSvnd::~KSvnd() {
+}
+
+QString KSvnd::commitDialog(QString modifiedFiles) {
+ CommitDlg commitDlg;
+ commitDlg.setLog( modifiedFiles );
+ int result = commitDlg.exec();
+ if ( result == QDialog::Accepted ) {
+ return commitDlg.logMessage();
+ } else
+ return QString::null;
+}
+
+bool KSvnd::AreAnyFilesInSvn( const KURL::List& wclist ) {
+ for ( QValueListConstIterator<KURL> it = wclist.begin(); it != wclist.end() ; ++it ) {
+ kdDebug( 7128 ) << "Checking file " << ( *it ) << endl;
+ QDir bdir ( ( *it ).path() );
+ if ( bdir.exists() && QFile::exists( ( *it ).path() + "/.svn/entries" ) ) {
+ return true;
+ } else if ( !bdir.exists() ) {
+ if ( isFileInSvnEntries( ( *it ).fileName(), ( *it ).directory() + "/.svn/entries" ) || isFileInExternals ( ( *it ).fileName(), ( *it ).directory()+"/.svn/dir-props" ) )
+ return true;
+ }
+ }
+ return false;
+}
+
+bool KSvnd::AreAnyFilesNotInSvn( const KURL::List& wclist ) {
+ for ( QValueListConstIterator<KURL> it = wclist.begin(); it != wclist.end() ; ++it ) {
+ kdDebug( 7128 ) << "Checking file " << ( *it ) << endl;
+ QDir bdir ( ( *it ).path() );
+ if ( bdir.exists() && !QFile::exists( ( *it ).path() + "/.svn/entries" ) ) {
+ return true;
+ } else if ( !bdir.exists() ) {
+ if ( !isFileInSvnEntries( ( *it ).fileName(),( *it ).directory() + "/.svn/entries" ) && !isFileInExternals ( ( *it ).fileName(), ( *it ).directory()+"/.svn/dir-props" ) )
+ return true;
+ }
+ }
+ return false;
+}
+
+bool KSvnd::AreAllFilesInSvn( const KURL::List& wclist ) {
+ for ( QValueListConstIterator<KURL> it = wclist.begin(); it != wclist.end() ; ++it ) {
+ kdDebug( 7128 ) << "Checking file " << ( *it ) << endl;
+ QDir bdir ( ( *it ).path() );
+ if ( bdir.exists() && !QFile::exists( ( *it ).path() + "/.svn/entries" ) ) {
+ return false;
+ } else if ( !bdir.exists() ) {
+ if ( !isFileInSvnEntries( ( *it ).fileName(),( *it ).directory() + "/.svn/entries" ) && !isFileInExternals ( ( *it ).fileName(), ( *it ).directory()+"/.svn/dir-props" ) )
+ return false;
+ }
+ }
+ return true;
+}
+
+bool KSvnd::AreAllFilesNotInSvn( const KURL::List& wclist ) {
+ for ( QValueListConstIterator<KURL> it = wclist.begin(); it != wclist.end() ; ++it ) {
+ kdDebug( 7128 ) << "Checking file " << ( *it ) << endl;
+ QDir bdir ( ( *it ).path() );
+ if ( bdir.exists() && QFile::exists( ( *it ).path() + "/.svn/entries" ) ) {
+ return false;
+ } else if ( !bdir.exists() ) {
+ if ( isFileInSvnEntries( ( *it ).fileName(),( *it ).directory() + "/.svn/entries" ) || isFileInExternals ( ( *it ).fileName(), ( *it ).directory()+"/.svn/dir-props" ) )
+ return false;
+ }
+ }
+ return true;
+}
+
+bool KSvnd::isFileInSvnEntries ( const QString filename, const QString entfile ) {
+ QFile file( entfile );
+ if ( file.open( IO_ReadOnly ) ) {
+ QTextStream stream( &file );
+ QString line;
+ while ( !stream.atEnd() ) {
+ line = stream.readLine().simplifyWhiteSpace();
+ if ( line == "name=\""+ filename + "\"" ) {
+ file.close();
+ return true;
+ }
+ }
+ file.close();
+ }
+ return false;
+}
+
+bool KSvnd::isFileInExternals ( const QString filename, const QString propfile ) {
+ QFile file( propfile );
+ if ( file.open( IO_ReadOnly ) ) {
+ QTextStream stream( &file );
+ QStringList line;
+ while ( !stream.atEnd() )
+ line << stream.readLine().simplifyWhiteSpace();
+ for ( uint i = 0 ; i < line.count(); i++ ) {
+ if ( line[ i ] == "K 13" && line[ i+1 ] == "svn:externals" ) { //Key 13 : svn:externals
+ //next line should be "V xx"
+ if ( line [ i+2 ].startsWith( "V " ) ) {
+ //ok browse the values now
+ i+=2;
+ while ( i < line.count() ) {
+ if ( line[ i ].startsWith( filename+" " ) ) { //found it !
+ file.close( );
+ return true;
+ } else if ( line[ i ].isEmpty() ) {
+ file.close( );
+ return false; //we are out of svn:externals now...
+ }
+ i++;
+ }
+ }
+ }
+ }
+ file.close();
+ }
+ return false;
+}
+
+bool KSvnd::anyNotValidWorkingCopy( const KURL::List& wclist ) {
+ bool result = true; //one negative match is enough
+ for ( QValueListConstIterator<KURL> it = wclist.begin(); it != wclist.end() ; ++it ) {
+ //exception for .svn dirs
+ if ( ( *it ).path(-1).endsWith( "/.svn" ) )
+ return true;
+ //if is a directory check whether it contains a .svn/entries file
+ QDir dir( ( *it ).path() );
+ if ( dir.exists() ) { //it's a dir
+ if ( !QFile::exists( ( *it ).path() + "/.svn/entries" ) )
+ result = false;
+ }
+
+ //else check if ./.svn/entries exists
+ if ( !QFile::exists( ( *it ).directory() + "/.svn/entries" ) )
+ result = false;
+ }
+ return result;
+}
+
+bool KSvnd::anyValidWorkingCopy( const KURL::List& wclist ) {
+ for ( QValueListConstIterator<KURL> it = wclist.begin(); it != wclist.end() ; ++it ) {
+ //skip .svn dirs
+ if ( ( *it ).path(-1).endsWith( "/.svn" ) )
+ continue;
+ //if is a directory check whether it contains a .svn/entries file
+ QDir dir( ( *it ).path() );
+ if ( dir.exists() ) { //it's a dir
+ if ( QFile::exists( ( *it ).path() + "/.svn/entries" ) )
+ return true;
+ }
+
+ //else check if ./.svn/entries exists
+ if ( QFile::exists( ( *it ).directory() + "/.svn/entries" ) )
+ return true;
+ }
+ return false;
+}
+
+int KSvnd::getStatus( const KURL::List& list ) {
+ int result = 0;
+ uint files = 0, folders = 0, parentsentries = 0, parentshavesvn = 0, subdirhavesvn = 0, external = 0;
+ for ( QValueListConstIterator<KURL> it = list.begin(); it != list.end() ; ++it ) {
+ if ( isFolder ( ( *it ) ) ) {
+ folders++;
+ } else {
+ files++;
+ }
+ if ( isFileInSvnEntries ( (*it).filename(),( *it ).directory() + "/.svn/entries" ) ) { // normal subdir known in the working copy
+ parentsentries++;
+ } else if ( isFolder( *it ) ) { // other subfolders (either another module checkouted or an external, or something not known at all)
+ if ( QFile::exists( ( *it ).path() + "/.svn/entries" ) )
+ subdirhavesvn++;
+ if ( isFileInExternals( (*it).filename(), ( *it ).directory() + "/.svn/dir-props" ) ) {
+ external++;
+ }
+ }
+ if ( ( isFolder( ( *it ) ) && QFile::exists( ( *it ).directory() + "../.svn/entries" ) ) || QFile::exists( ( *it ).directory() + "/.svn/entries" ) ) //parent has a .svn ?
+ parentshavesvn++;
+ }
+ if ( files > 0 )
+ result |= SomeAreFiles;
+ if ( folders == list.count() ) {
+ result |= AllAreFolders;
+ result |= SomeAreFolders;
+ }
+ if ( folders > 0 )
+ result |= SomeAreFolders;
+ if ( parentsentries == list.count() ) {
+ result |= AllAreInParentsEntries;
+ result |= SomeAreInParentsEntries;
+ } else if ( parentsentries != 0 )
+ result |= SomeAreInParentsEntries;
+ if ( parentshavesvn == list.count() ) {
+ result |= AllParentsHaveSvn;
+ result |= SomeParentsHaveSvn;
+ } else if ( parentshavesvn > 0 )
+ result |= SomeParentsHaveSvn;
+ if ( subdirhavesvn == list.count() ) {
+ result |= AllHaveSvn;
+ result |= SomeHaveSvn;
+ } else if ( subdirhavesvn > 0 )
+ result |= SomeHaveSvn;
+ if ( external == list.count() ) {
+ result |= AllAreExternalToParent;
+ result |= SomeAreExternalToParent;
+ } else if ( external > 0 )
+ result |= SomeAreExternalToParent;
+
+ return result;
+}
+
+bool KSvnd::isFolder( const KURL& url ) {
+ QDir d( url.path() );
+ return d.exists();
+}
+
+QStringList KSvnd::getActionMenu ( const KURL::List &list ) {
+ QStringList result;
+ int listStatus = getStatus( list );
+
+ if ( !(listStatus & SomeAreInParentsEntries) &&
+ !(listStatus & SomeAreExternalToParent) &&
+ !(listStatus & SomeHaveSvn)) {
+ if( list.size() == 1 && listStatus & SomeAreFolders) {
+ result << "Checkout";
+ result << "Export";
+// result << "CreateRepository";
+ result << "Import";
+ }
+ } else if ( (listStatus & AllAreInParentsEntries) ) {
+ result << "Diff";
+ //In SVN
+// result << "ShowLog";
+// result << "CheckForModifications";
+// result << "RevisionGraph";
+// result << "_SEPARATOR_";
+// result << "Update to revision..."
+ result << "Rename";
+ result << "Delete";
+ if( listStatus & SomeAreFolders && !(listStatus & SomeAreFiles)) {
+ result << "Revert";
+// result << "Cleanup";
+ }
+ result << "_SEPARATOR_";
+// result << "BranchTag";
+ result << "Switch";
+ result << "Merge";
+ if( listStatus & SomeAreFolders && !(listStatus & SomeAreFiles)) {
+// result << "Export";
+// result << "Relocate";
+ result << "_SEPARATOR_";
+ result << "Add";
+ }
+ result << "_SEPARATOR_";
+ if( listStatus & SomeAreFiles && !(listStatus & SomeAreFolders)) {
+ result << "Blame";
+ }
+ result << "CreatePatch";
+
+ if( list.size() == 1 && listStatus & SomeAreFolders) {
+// result << "ApplyPatchToFolder";
+ }
+ }
+ return result;
+}
+
+QStringList KSvnd::getTopLevelActionMenu ( const KURL::List &list ) {
+ QStringList result;
+ int listStatus = getStatus( list );
+
+
+ if ( ( listStatus & AllParentsHaveSvn &&
+ ( ( listStatus & SomeAreExternalToParent ) || ( listStatus & SomeAreInParentsEntries ) )
+ || ( listStatus & SomeHaveSvn ) )
+ ) {
+ result << "Update";
+ result << "Commit";
+ }
+
+ return result;
+}
+
+#if 0
+void KSvnd::notify(const QString& path, int action, int kind, const QString& mime_type, int content_state, int prop_state, long int revision, const QString& userstring) {
+ kdDebug(7128) << "KDED/Subversion : notify " << path << " action : " << action << " mime_type : " << mime_type << " content_state : " << content_state << " prop_state : " << prop_state << " revision : " << revision << " userstring : " << userstring << endl;
+ QByteArray params;
+
+ QDataStream stream(params, IO_WriteOnly);
+ stream << path << action << kind << mime_type << content_state << prop_state << revision << userstring;
+
+ emitDCOPSignal( "subversionNotify(QString,int,int,QString,int,int,long int,QString)", params );
+}
+
+void KSvnd::status(const QString& path, int text_status, int prop_status, int repos_text_status, int repos_prop_status, long int rev ) {
+ kdDebug(7128) << "KDED/Subversion : status " << path << " " << text_status << " " << prop_status << " "
+ << repos_text_status << " " << repos_prop_status << " " << rev << endl;
+ QByteArray params;
+
+ QDataStream stream(params, IO_WriteOnly);
+ stream << path << text_status << prop_status << repos_text_status << repos_prop_status << rev;
+
+ emitDCOPSignal( "subversionStatus(QString,int,int,int,int,long int)", params );
+}
+
+void KSvnd::popupMessage( const QString& message ) {
+ kdDebug(7128) << "KDED/Subversion : popupMessage" << message << endl;
+ KMessageBox::information(0, message, i18n( "Subversion" ) );
+}
+#endif
+
+#include "ksvnd.moc"
diff --git a/kioslave/svn/ksvnd/ksvnd.desktop b/kioslave/svn/ksvnd/ksvnd.desktop
new file mode 100644
index 00000000..d2c942d4
--- /dev/null
+++ b/kioslave/svn/ksvnd/ksvnd.desktop
@@ -0,0 +1,50 @@
+[Desktop Entry]
+Type=Service
+Name=KDED Subversion Module
+Name[bg]=Модул KDED Subversion
+Name[br]=Mollad Subversion KDED
+Name[ca]=Mòdul KDED de Subversion
+Name[cs]=KDED Subversion modul
+Name[da]=KDED Subversion modul
+Name[de]=Subversion-Unterstützung
+Name[el]=ΆÏθÏωμα KDED Subversion
+Name[es]=Módulo de Subversion de KDED
+Name[et]=KDED Subversioni moodul
+Name[eu]=KDED Subversion modulua
+Name[fa]=پیمانۀ زیرنسخۀ KDED
+Name[fi]=KDED Subversion -moduuli
+Name[fr]=Module KDED Subversion
+Name[ga]=Modúl Subversion KDED
+Name[gl]=Módulo KDED Subversion
+Name[hu]=KDED Subversion modul
+Name[is]=KDED Subversion eining
+Name[it]=Modulo Subversion di KDED
+Name[ja]=KDED Subversion モジュール
+Name[ka]=KDED Subversion მáƒáƒ“ული
+Name[kk]=KDED Subversion қызмет модулі
+Name[lt]=KDED Subversion modulis
+Name[nb]=KDED Subversion-modul
+Name[nds]=KDED Subversion-Moduul
+Name[ne]=केडीईडी उप संसà¥à¤•à¤°à¤£ मोडà¥à¤¯à¥à¤²
+Name[nl]=KDED Subversion-module
+Name[nn]=KDED Subversion-modul
+Name[pa]=KDED ਸਬ-ਵਰਜਨ ਮੈਡੀਊਲ
+Name[pl]=Moduł Subversion dla KDED
+Name[pt]=Módulo KDED Subversion
+Name[pt_BR]=Módulo de Sub-versão KDED
+Name[ru]=Служба Subversion
+Name[sk]=KDED Subversion modul
+Name[sl]=Modul Subversion za KDED
+Name[sr]=KDED модул за Subversion
+Name[sr@Latn]=KDED modul za Subversion
+Name[sv]=KDED Subversion-modul
+Name[tr]=KDED Alt Versiyon Modülü
+Name[uk]=Модуль KDED Subversion
+Name[zh_CN]=KDED Subversion 模å—
+Name[zh_TW]=KDED Subversion 模組
+ServiceTypes=KDEDModule
+X-KDE-ModuleType=Library
+X-KDE-Library=ksvnd
+X-KDE-FactoryName=ksvnd
+X-KDE-Kded-autoload=true
+X-KDE-Kded-load-on-demand=true
diff --git a/kioslave/svn/ksvnd/ksvnd.h b/kioslave/svn/ksvnd/ksvnd.h
new file mode 100644
index 00000000..20bb7e9a
--- /dev/null
+++ b/kioslave/svn/ksvnd/ksvnd.h
@@ -0,0 +1,69 @@
+/*
+ This file is part of the KDE Project
+
+ Copyright (C) 2003-2005 Mickael Marchand <marchand@kde.org>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License
+ version 2 as published by the Free Software Foundation.
+
+ This software 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 library; see the file COPYING. If not, write to
+ the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+*/
+
+#ifndef KSVND_H
+#define KSVND_H
+
+#include <dcopclient.h>
+#include <kdedmodule.h>
+#include <kurl.h>
+#include <qstringlist.h>
+
+class KSvnd : public KDEDModule
+{
+ Q_OBJECT
+ K_DCOP
+
+ //note: InSVN means parent is added. InRepos means itself is added
+ enum { SomeAreFiles = 1, SomeAreFolders = 2, SomeAreInParentsEntries = 4, SomeParentsHaveSvn = 8, SomeHaveSvn = 16, SomeAreExternalToParent = 32, AllAreInParentsEntries = 64, AllParentsHaveSvn = 128, AllHaveSvn = 256, AllAreExternalToParent = 512, AllAreFolders = 1024 };
+public:
+ KSvnd(const QCString &);
+ ~KSvnd();
+
+k_dcop:
+// void addAuthInfo(KIO::AuthInfo, long);
+ QString commitDialog(QString);
+ bool anyNotValidWorkingCopy( const KURL::List& wclist );
+ bool anyValidWorkingCopy( const KURL::List& wclist );
+ bool AreAnyFilesNotInSvn( const KURL::List& wclist );
+ bool AreAnyFilesInSvn( const KURL::List& wclist );
+ bool AreAllFilesNotInSvn( const KURL::List& wclist );
+ bool AreAllFilesInSvn( const KURL::List& wclist );
+ QStringList getActionMenu ( const KURL::List& list );
+ QStringList getTopLevelActionMenu ( const KURL::List &list );
+// void notify(const QString&, int ,int, const QString& , int , int, long int, const QString&);
+// void status(const QString& path, int text_status, int prop_status, int repos_text_status, int repos_prop_status ,long int rev);
+// void popupMessage( const QString& message );
+
+k_dcop_signals:
+ //emitted whenever something happens using subversion ;)
+// void subversionNotify(const QString&, int ,int, const QString& , int , int, long int, const QString&);
+// void subversionStatus(const QString&,int,int,int,int,long int);
+
+public slots:
+
+protected:
+ bool isFileInSvnEntries ( const QString filename, const QString entfile );
+ bool isFileInExternals ( const QString filename, const QString propfile );
+ bool isFolder( const KURL& url );
+ int getStatus( const KURL::List& list );
+};
+
+#endif
diff --git a/kioslave/svn/svn+file.protocol b/kioslave/svn/svn+file.protocol
new file mode 100644
index 00000000..ff8edc5e
--- /dev/null
+++ b/kioslave/svn/svn+file.protocol
@@ -0,0 +1,43 @@
+[Protocol]
+exec=kio_svn
+protocol=svn+file
+input=none
+output=filesystem
+reading=true
+writing=true
+deleting=true
+makedir=true
+linking=false
+moving=true
+listing=Name,Size,Date,Owner
+defaultMimetype=application/octet-stream
+Icon=remote
+Description=Subversion ioslave
+Description[br]=Sklav E/D Subversion
+Description[ca]=Ioslave de Subversion
+Description[cs]=Subversion protokol
+Description[de]=Ein-/Ausgabemodul für Subversion
+Description[es]=El ioslave de Subversion
+Description[et]=Subversioni IO-moodul
+Description[fr]=ioslave subversion
+Description[ga]=ioslave Subversion
+Description[gl]=Ioslave para Subversíon
+Description[hu]=Subversion KDE-protokoll
+Description[it]=Slave I/O di Subversion
+Description[lt]=Subversion įvesties-išvesties priedas
+Description[nb]=Subversion-iu-slave
+Description[nds]=In-/Utgaavmoduul för Subversion
+Description[ne]=उप संसà¥à¤•à¤°à¤£ ioslave
+Description[nn]=Subversion-iu-slave
+Description[pl]=Wtyczka protokołu Subversion
+Description[pt]='Ioslave' para Subversion
+Description[pt_BR]=ioslave de Subversão
+Description[ru]=ДоÑтуп к хранилищу Subversion
+Description[sl]=ioslave za Subversion
+Description[sr]=IOSlave за Subversion
+Description[sr@Latn]=IOSlave za Subversion
+Description[sv]=Subversion I/O-slav
+Description[tr]=Alt Version ioslave
+Description[uk]=Підлеглий В/В Subversion
+maxInstances=5
+class=:internet
diff --git a/kioslave/svn/svn+http.protocol b/kioslave/svn/svn+http.protocol
new file mode 100644
index 00000000..656fa217
--- /dev/null
+++ b/kioslave/svn/svn+http.protocol
@@ -0,0 +1,43 @@
+[Protocol]
+exec=kio_svn
+protocol=svn+http
+input=none
+output=filesystem
+reading=true
+writing=true
+deleting=true
+makedir=true
+linking=false
+moving=true
+listing=Name,Size,Date,Owner
+defaultMimetype=application/octet-stream
+Icon=remote
+Description=Subversion ioslave
+Description[br]=Sklav E/D Subversion
+Description[ca]=Ioslave de Subversion
+Description[cs]=Subversion protokol
+Description[de]=Ein-/Ausgabemodul für Subversion
+Description[es]=El ioslave de Subversion
+Description[et]=Subversioni IO-moodul
+Description[fr]=ioslave subversion
+Description[ga]=ioslave Subversion
+Description[gl]=Ioslave para Subversíon
+Description[hu]=Subversion KDE-protokoll
+Description[it]=Slave I/O di Subversion
+Description[lt]=Subversion įvesties-išvesties priedas
+Description[nb]=Subversion-iu-slave
+Description[nds]=In-/Utgaavmoduul för Subversion
+Description[ne]=उप संसà¥à¤•à¤°à¤£ ioslave
+Description[nn]=Subversion-iu-slave
+Description[pl]=Wtyczka protokołu Subversion
+Description[pt]='Ioslave' para Subversion
+Description[pt_BR]=ioslave de Subversão
+Description[ru]=ДоÑтуп к хранилищу Subversion
+Description[sl]=ioslave za Subversion
+Description[sr]=IOSlave за Subversion
+Description[sr@Latn]=IOSlave za Subversion
+Description[sv]=Subversion I/O-slav
+Description[tr]=Alt Version ioslave
+Description[uk]=Підлеглий В/В Subversion
+maxInstances=5
+class=:internet
diff --git a/kioslave/svn/svn+https.protocol b/kioslave/svn/svn+https.protocol
new file mode 100644
index 00000000..e299958c
--- /dev/null
+++ b/kioslave/svn/svn+https.protocol
@@ -0,0 +1,43 @@
+[Protocol]
+exec=kio_svn
+protocol=svn+https
+input=none
+output=filesystem
+reading=true
+writing=true
+deleting=true
+makedir=true
+linking=false
+moving=true
+listing=Name,Size,Date,Owner
+defaultMimetype=application/octet-stream
+Icon=remote
+Description=Subversion ioslave
+Description[br]=Sklav E/D Subversion
+Description[ca]=Ioslave de Subversion
+Description[cs]=Subversion protokol
+Description[de]=Ein-/Ausgabemodul für Subversion
+Description[es]=El ioslave de Subversion
+Description[et]=Subversioni IO-moodul
+Description[fr]=ioslave subversion
+Description[ga]=ioslave Subversion
+Description[gl]=Ioslave para Subversíon
+Description[hu]=Subversion KDE-protokoll
+Description[it]=Slave I/O di Subversion
+Description[lt]=Subversion įvesties-išvesties priedas
+Description[nb]=Subversion-iu-slave
+Description[nds]=In-/Utgaavmoduul för Subversion
+Description[ne]=उप संसà¥à¤•à¤°à¤£ ioslave
+Description[nn]=Subversion-iu-slave
+Description[pl]=Wtyczka protokołu Subversion
+Description[pt]='Ioslave' para Subversion
+Description[pt_BR]=ioslave de Subversão
+Description[ru]=ДоÑтуп к хранилищу Subversion
+Description[sl]=ioslave za Subversion
+Description[sr]=IOSlave за Subversion
+Description[sr@Latn]=IOSlave za Subversion
+Description[sv]=Subversion I/O-slav
+Description[tr]=Alt Version ioslave
+Description[uk]=Підлеглий В/В Subversion
+maxInstances=5
+class=:internet
diff --git a/kioslave/svn/svn+ssh.protocol b/kioslave/svn/svn+ssh.protocol
new file mode 100644
index 00000000..7c985da9
--- /dev/null
+++ b/kioslave/svn/svn+ssh.protocol
@@ -0,0 +1,43 @@
+[Protocol]
+exec=kio_svn
+protocol=svn+ssh
+input=none
+output=filesystem
+reading=true
+writing=true
+deleting=true
+makedir=true
+linking=false
+moving=true
+listing=Name,Size,Date,Owner
+defaultMimetype=application/octet-stream
+Icon=remote
+Description=Subversion ioslave
+Description[br]=Sklav E/D Subversion
+Description[ca]=Ioslave de Subversion
+Description[cs]=Subversion protokol
+Description[de]=Ein-/Ausgabemodul für Subversion
+Description[es]=El ioslave de Subversion
+Description[et]=Subversioni IO-moodul
+Description[fr]=ioslave subversion
+Description[ga]=ioslave Subversion
+Description[gl]=Ioslave para Subversíon
+Description[hu]=Subversion KDE-protokoll
+Description[it]=Slave I/O di Subversion
+Description[lt]=Subversion įvesties-išvesties priedas
+Description[nb]=Subversion-iu-slave
+Description[nds]=In-/Utgaavmoduul för Subversion
+Description[ne]=उप संसà¥à¤•à¤°à¤£ ioslave
+Description[nn]=Subversion-iu-slave
+Description[pl]=Wtyczka protokołu Subversion
+Description[pt]='Ioslave' para Subversion
+Description[pt_BR]=ioslave de Subversão
+Description[ru]=ДоÑтуп к хранилищу Subversion
+Description[sl]=ioslave za Subversion
+Description[sr]=IOSlave за Subversion
+Description[sr@Latn]=IOSlave za Subversion
+Description[sv]=Subversion I/O-slav
+Description[tr]=Alt Version ioslave
+Description[uk]=Підлеглий В/В Subversion
+maxInstances=5
+class=:internet
diff --git a/kioslave/svn/svn.cpp b/kioslave/svn/svn.cpp
new file mode 100644
index 00000000..8ff9496e
--- /dev/null
+++ b/kioslave/svn/svn.cpp
@@ -0,0 +1,1593 @@
+/* This file is part of the KDE project
+ Copyright (C) 2003 Mickael Marchand <marchand@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.
+*/
+
+#include <qcstring.h>
+#include <qsocket.h>
+#include <qdatetime.h>
+#include <qbitarray.h>
+
+#include <stdlib.h>
+#include <math.h>
+#include <unistd.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <netdb.h>
+
+#include <kapplication.h>
+#include <kdebug.h>
+#include <kmessagebox.h>
+#include <kinstance.h>
+#include <kglobal.h>
+#include <kstandarddirs.h>
+#include <klocale.h>
+#include <kurl.h>
+#include <ksock.h>
+#include <dcopclient.h>
+#include <qcstring.h>
+
+#include <subversion-1/svn_sorts.h>
+#include <subversion-1/svn_path.h>
+#include <subversion-1/svn_utf.h>
+#include <subversion-1/svn_ra.h>
+#include <subversion-1/svn_time.h>
+
+#include <kmimetype.h>
+#include <qfile.h>
+
+#include "svn.h"
+#include <apr_portable.h>
+
+using namespace KIO;
+
+typedef struct
+{
+ /* Holds the directory that corresponds to the REPOS_URL at RA->open()
+ * time. When callbacks specify a relative path, they are joined with
+ * this base directory. */
+ const char *base_dir;
+ svn_wc_adm_access_t *base_access;
+
+ /* An array of svn_client_commit_item_t * structures, present only
+ * during working copy commits. */
+ apr_array_header_t *commit_items;
+
+ /* A hash of svn_config_t's, keyed off file name (i.e. the contents of
+ * ~/.subversion/config end up keyed off of 'config'). */
+ apr_hash_t *config;
+
+ /* The pool to use for session-related items. */
+ apr_pool_t *pool;
+
+} svn_client__callback_baton_t;
+
+static svn_error_t *
+open_tmp_file (apr_file_t **fp,
+ void *callback_baton,
+ apr_pool_t *pool)
+{
+ svn_client__callback_baton_t *cb = (svn_client__callback_baton_t *) callback_baton;
+ const char *truepath;
+ const char *ignored_filename;
+
+ if (cb->base_dir)
+ truepath = apr_pstrdup (pool, cb->base_dir);
+ else
+ truepath = "";
+
+ /* Tack on a made-up filename. */
+ truepath = svn_path_join (truepath, "tempfile", pool);
+
+ /* Open a unique file; use APR_DELONCLOSE. */
+ SVN_ERR (svn_io_open_unique_file (fp, &ignored_filename,
+ truepath, ".tmp", TRUE, pool));
+
+ return SVN_NO_ERROR;
+}
+
+static svn_error_t *write_to_string(void *baton, const char *data, apr_size_t *len) {
+ kbaton *tb = ( kbaton* )baton;
+ svn_stringbuf_appendbytes(tb->target_string, data, *len);
+ return SVN_NO_ERROR;
+}
+
+static int
+compare_items_as_paths (const svn_sort__item_t*a, const svn_sort__item_t*b) {
+ return svn_path_compare_paths ((const char *)a->key, (const char *)b->key);
+}
+
+kio_svnProtocol::kio_svnProtocol(const QCString &pool_socket, const QCString &app_socket)
+ : SlaveBase("kio_svn", pool_socket, app_socket) {
+ kdDebug(7128) << "kio_svnProtocol::kio_svnProtocol()" << endl;
+
+ m_counter = 0;
+
+ apr_initialize();
+ // CleanUP ctx preventing crash in svn_client_update and other
+ memset(&ctx, 0, sizeof(ctx));
+ pool = svn_pool_create (NULL);
+
+ svn_error_t *err = svn_client_create_context(&ctx, pool);
+ if ( err ) {
+ kdDebug(7128) << "kio_svnProtocol::kio_svnProtocol() create_context ERROR" << endl;
+ error( KIO::ERR_SLAVE_DEFINED, err->message );
+ return;
+ }
+
+ err = svn_config_ensure (NULL,pool);
+ if ( err ) {
+ kdDebug(7128) << "kio_svnProtocol::kio_svnProtocol() configensure ERROR" << endl;
+ error( KIO::ERR_SLAVE_DEFINED, err->message );
+ return;
+ }
+ svn_config_get_config (&ctx->config, NULL, pool);
+
+ ctx->log_msg_func = kio_svnProtocol::commitLogPrompt;
+ ctx->log_msg_baton = this; //pass this so that we can get a dcopClient from it
+ //TODO
+ ctx->cancel_func = NULL;
+
+ apr_array_header_t *providers = apr_array_make(pool, 9, sizeof(svn_auth_provider_object_t *));
+
+ svn_auth_provider_object_t *provider;
+
+ //disk cache
+ svn_client_get_simple_provider(&provider,pool);
+ APR_ARRAY_PUSH(providers, svn_auth_provider_object_t*) = provider;
+ svn_client_get_username_provider(&provider,pool);
+ APR_ARRAY_PUSH(providers, svn_auth_provider_object_t*) = provider;
+
+ //interactive prompt
+ svn_client_get_simple_prompt_provider (&provider,kio_svnProtocol::checkAuth,this,2,pool);
+ APR_ARRAY_PUSH(providers, svn_auth_provider_object_t*) = provider;
+ //we always ask user+pass, no need for a user only question
+/* svn_client_get_username_prompt_provider
+ * (&provider,kio_svnProtocol::checkAuth,this,2,pool);
+ APR_ARRAY_PUSH(providers, svn_auth_provider_object_t*) = provider;*/
+
+ //SSL disk cache, keep that one, because it does nothing bad :)
+ svn_client_get_ssl_server_trust_file_provider (&provider, pool);
+ APR_ARRAY_PUSH (providers, svn_auth_provider_object_t *) = provider;
+ svn_client_get_ssl_client_cert_file_provider (&provider, pool);
+ APR_ARRAY_PUSH (providers, svn_auth_provider_object_t *) = provider;
+ svn_client_get_ssl_client_cert_pw_file_provider (&provider, pool);
+ APR_ARRAY_PUSH (providers, svn_auth_provider_object_t *) = provider;
+
+ //SSL interactive prompt, where things get hard
+ svn_client_get_ssl_server_trust_prompt_provider (&provider, kio_svnProtocol::trustSSLPrompt, NULL, pool);
+ APR_ARRAY_PUSH (providers, svn_auth_provider_object_t *) = provider;
+ svn_client_get_ssl_client_cert_prompt_provider (&provider, kio_svnProtocol::clientCertSSLPrompt, NULL, 2, pool);
+ APR_ARRAY_PUSH (providers, svn_auth_provider_object_t *) = provider;
+ svn_client_get_ssl_client_cert_pw_prompt_provider (&provider, kio_svnProtocol::clientCertPasswdPrompt, NULL, 2, pool);
+ APR_ARRAY_PUSH (providers, svn_auth_provider_object_t *) = provider;
+
+ svn_auth_open(&ctx->auth_baton, providers, pool);
+}
+
+kio_svnProtocol::~kio_svnProtocol(){
+ kdDebug(7128) << "kio_svnProtocol::~kio_svnProtocol()" << endl;
+ svn_pool_destroy(pool);
+ apr_terminate();
+}
+
+void kio_svnProtocol::initNotifier(bool is_checkout, bool is_export, bool suppress_final_line, apr_pool_t *spool) {
+ m_counter=0;//reset counter
+ ctx->notify_func = kio_svnProtocol::notify;
+ struct notify_baton *nb = ( struct notify_baton* )apr_palloc(spool, sizeof( *nb ) );
+ nb->master = this;
+ nb->received_some_change = FALSE;
+ nb->sent_first_txdelta = FALSE;
+ nb->is_checkout = is_checkout;
+ nb->is_export = is_export;
+ nb->suppress_final_line = suppress_final_line;
+ nb->in_external = FALSE;
+ nb->had_print_error = FALSE;
+ nb->pool = svn_pool_create (spool);
+
+ ctx->notify_baton = nb;
+}
+
+svn_error_t* kio_svnProtocol::checkAuth(svn_auth_cred_simple_t **cred, void *baton, const char *realm, const char *username, svn_boolean_t /*may_save*/, apr_pool_t *pool) {
+ kdDebug(7128) << "kio_svnProtocol::checkAuth() for " << realm << endl;
+ kio_svnProtocol *p = ( kio_svnProtocol* )baton;
+ svn_auth_cred_simple_t *ret = (svn_auth_cred_simple_t*)apr_pcalloc (pool, sizeof (*ret));
+
+// p->info.keepPassword = true;
+ p->info.verifyPath=true;
+ kdDebug(7128 ) << "auth current URL : " << p->myURL.url() << endl;
+ p->info.url = p->myURL;
+ p->info.username = username; //( const char* )svn_auth_get_parameter( p->ctx->auth_baton, SVN_AUTH_PARAM_DEFAULT_USERNAME );
+// if ( !p->checkCachedAuthentication( p->info ) ){
+ p->openPassDlg( p->info );
+// }
+ ret->username = apr_pstrdup(pool, p->info.username.utf8());
+ ret->password = apr_pstrdup(pool, p->info.password.utf8());
+ ret->may_save = true;
+ *cred = ret;
+ return SVN_NO_ERROR;
+}
+
+void kio_svnProtocol::recordCurrentURL(const KURL& url) {
+ myURL = url;
+}
+
+//don't implement mimeType() until we don't need to download the whole file
+
+void kio_svnProtocol::get(const KURL& url ){
+ kdDebug(7128) << "kio_svn::get(const KURL& url)" << endl ;
+
+ QString remoteServer = url.host();
+ infoMessage(i18n("Looking for %1...").arg( remoteServer ) );
+
+ apr_pool_t *subpool = svn_pool_create (pool);
+ kbaton *bt = (kbaton*)apr_pcalloc(subpool, sizeof(*bt));
+ bt->target_string = svn_stringbuf_create("", subpool);
+ bt->string_stream = svn_stream_create(bt,subpool);
+ svn_stream_set_write(bt->string_stream,write_to_string);
+
+ QString target = makeSvnURL( url );
+ kdDebug(7128) << "SvnURL: " << target << endl;
+ recordCurrentURL( KURL( target ) );
+
+ //find the requested revision
+ svn_opt_revision_t rev;
+ svn_opt_revision_t endrev;
+ int idx = target.findRev( "?rev=" );
+ if ( idx != -1 ) {
+ QString revstr = target.mid( idx+5 );
+#if 0
+ kdDebug(7128) << "revision string found " << revstr << endl;
+ if ( revstr == "HEAD" ) {
+ rev.kind = svn_opt_revision_head;
+ kdDebug(7128) << "revision searched : HEAD" << endl;
+ } else {
+ rev.kind = svn_opt_revision_number;
+ rev.value.number = revstr.toLong();
+ kdDebug(7128) << "revision searched : " << rev.value.number << endl;
+ }
+#endif
+ svn_opt_parse_revision( &rev, &endrev, revstr.utf8(), subpool );
+ target = target.left( idx );
+ kdDebug(7128) << "new target : " << target << endl;
+ } else {
+ kdDebug(7128) << "no revision given. searching HEAD " << endl;
+ rev.kind = svn_opt_revision_head;
+ }
+ initNotifier(false, false, false, subpool);
+
+ svn_error_t *err = svn_client_cat (bt->string_stream, svn_path_canonicalize( target.utf8(),subpool ),&rev,ctx, subpool);
+ if ( err ) {
+ error( KIO::ERR_SLAVE_DEFINED, err->message );
+ svn_pool_destroy( subpool );
+ return;
+ }
+
+ // Send the mimeType as soon as it is known
+ QByteArray *cp = new QByteArray();
+ cp->setRawData( bt->target_string->data, bt->target_string->len );
+ KMimeType::Ptr mt = KMimeType::findByContent(*cp);
+ kdDebug(7128) << "KMimeType returned : " << mt->name() << endl;
+ mimeType( mt->name() );
+
+ totalSize(bt->target_string->len);
+
+ //send data
+ data(*cp);
+
+ data(QByteArray()); // empty array means we're done sending the data
+ finished();
+ svn_pool_destroy (subpool);
+}
+
+void kio_svnProtocol::stat(const KURL & url){
+ kdDebug(7128) << "kio_svn::stat(const KURL& url) : " << url.url() << endl ;
+
+ void *ra_baton, *session;
+ svn_ra_plugin_t *ra_lib;
+ svn_node_kind_t kind;
+ apr_pool_t *subpool = svn_pool_create (pool);
+
+ QString target = makeSvnURL( url);
+ kdDebug(7128) << "SvnURL: " << target << endl;
+ recordCurrentURL( KURL( target ) );
+
+ //find the requested revision
+ svn_opt_revision_t rev;
+ svn_opt_revision_t endrev;
+ int idx = target.findRev( "?rev=" );
+ if ( idx != -1 ) {
+ QString revstr = target.mid( idx+5 );
+#if 0
+ kdDebug(7128) << "revision string found " << revstr << endl;
+ if ( revstr == "HEAD" ) {
+ rev.kind = svn_opt_revision_head;
+ kdDebug(7128) << "revision searched : HEAD" << endl;
+ } else {
+ rev.kind = svn_opt_revision_number;
+ rev.value.number = revstr.toLong();
+ kdDebug(7128) << "revision searched : " << rev.value.number << endl;
+ }
+#endif
+ svn_opt_parse_revision( &rev, &endrev, revstr.utf8( ), subpool );
+ target = target.left( idx );
+ kdDebug(7128) << "new target : " << target << endl;
+ } else {
+ kdDebug(7128) << "no revision given. searching HEAD " << endl;
+ rev.kind = svn_opt_revision_head;
+ }
+
+ //init
+ svn_error_t *err = svn_ra_init_ra_libs(&ra_baton,subpool);
+ if ( err ) {
+ kdDebug(7128) << "init RA libs failed : " << err->message << endl;
+ return;
+ }
+ //find RA libs
+ err = svn_ra_get_ra_library(&ra_lib,ra_baton,svn_path_canonicalize( target.utf8(), subpool ),subpool);
+ if ( err ) {
+ kdDebug(7128) << "RA get libs failed : " << err->message << endl;
+ return;
+ }
+ kdDebug(7128) << "RA init completed" << endl;
+
+ //start session
+ svn_ra_callbacks_t *cbtable = (svn_ra_callbacks_t*)apr_pcalloc(subpool, sizeof(*cbtable));
+ kio_svn_callback_baton_t *callbackbt = (kio_svn_callback_baton_t*)apr_pcalloc(subpool, sizeof( *callbackbt ));
+
+ cbtable->open_tmp_file = open_tmp_file;
+ cbtable->get_wc_prop = NULL;
+ cbtable->set_wc_prop = NULL;
+ cbtable->push_wc_prop = NULL;
+ cbtable->auth_baton = ctx->auth_baton;
+
+ callbackbt->base_dir = target.utf8();
+ callbackbt->pool = subpool;
+ callbackbt->config = ctx->config;
+
+ err = ra_lib->open(&session,svn_path_canonicalize( target.utf8(), subpool ),cbtable,callbackbt,ctx->config,subpool);
+ if ( err ) {
+ kdDebug(7128)<< "Open session " << err->message << endl;
+ return;
+ }
+ kdDebug(7128) << "Session opened to " << target << endl;
+ //find number for HEAD
+ if (rev.kind == svn_opt_revision_head) {
+ err = ra_lib->get_latest_revnum(session,&rev.value.number,subpool);
+ if ( err ) {
+ kdDebug(7128)<< "Latest RevNum " << err->message << endl;
+ return;
+ }
+ kdDebug(7128) << "Got rev " << rev.value.number << endl;
+ }
+
+ //get it
+ ra_lib->check_path(session,"",rev.value.number,&kind,subpool);
+ kdDebug(7128) << "Checked Path" << endl;
+ UDSEntry entry;
+ switch ( kind ) {
+ case svn_node_file:
+ kdDebug(7128) << "::stat result : file" << endl;
+ createUDSEntry(url.filename(),"",0,false,0,entry);
+ statEntry( entry );
+ break;
+ case svn_node_dir:
+ kdDebug(7128) << "::stat result : directory" << endl;
+ createUDSEntry(url.filename(),"",0,true,0,entry);
+ statEntry( entry );
+ break;
+ case svn_node_unknown:
+ case svn_node_none:
+ //error XXX
+ default:
+ kdDebug(7128) << "::stat result : UNKNOWN ==> WOW :)" << endl;
+ ;
+ }
+ finished();
+ svn_pool_destroy( subpool );
+}
+
+void kio_svnProtocol::listDir(const KURL& url){
+ kdDebug(7128) << "kio_svn::listDir(const KURL& url) : " << url.url() << endl ;
+
+ apr_pool_t *subpool = svn_pool_create (pool);
+ apr_hash_t *dirents;
+
+ QString target = makeSvnURL( url);
+ kdDebug(7128) << "SvnURL: " << target << endl;
+ recordCurrentURL( KURL( target ) );
+
+ //find the requested revision
+ svn_opt_revision_t rev;
+ svn_opt_revision_t endrev;
+ int idx = target.findRev( "?rev=" );
+ if ( idx != -1 ) {
+ QString revstr = target.mid( idx+5 );
+ svn_opt_parse_revision( &rev, &endrev, revstr.utf8(), subpool );
+#if 0
+ kdDebug(7128) << "revision string found " << revstr << endl;
+ if ( revstr == "HEAD" ) {
+ rev.kind = svn_opt_revision_head;
+ kdDebug(7128) << "revision searched : HEAD" << endl;
+ } else {
+ rev.kind = svn_opt_revision_number;
+ rev.value.number = revstr.toLong();
+ kdDebug(7128) << "revision searched : " << rev.value.number << endl;
+ }
+#endif
+ target = target.left( idx );
+ kdDebug(7128) << "new target : " << target << endl;
+ } else {
+ kdDebug(7128) << "no revision given. searching HEAD " << endl;
+ rev.kind = svn_opt_revision_head;
+ }
+
+ initNotifier(false, false, false, subpool);
+ svn_error_t *err = svn_client_ls (&dirents, svn_path_canonicalize( target.utf8(), subpool ), &rev, false, ctx, subpool);
+ if ( err ) {
+ error( KIO::ERR_SLAVE_DEFINED, err->message );
+ svn_pool_destroy( subpool );
+ return;
+ }
+
+ apr_array_header_t *array;
+ int i;
+
+ array = svn_sort__hash (dirents, compare_items_as_paths, subpool);
+
+ UDSEntry entry;
+ for (i = 0; i < array->nelts; ++i) {
+ entry.clear();
+ const char *utf8_entryname, *native_entryname;
+ svn_dirent_t *dirent;
+ svn_sort__item_t *item;
+
+ item = &APR_ARRAY_IDX (array, i, svn_sort__item_t);
+
+ utf8_entryname = (const char*)item->key;
+
+ dirent = (svn_dirent_t*)apr_hash_get (dirents, utf8_entryname, item->klen);
+
+ svn_utf_cstring_from_utf8 (&native_entryname, utf8_entryname, subpool);
+ const char *native_author = NULL;
+
+ //XXX BUGGY
+/* apr_time_exp_t timexp;
+ apr_time_exp_lt(&timexp, dirent->time);
+ apr_os_exp_time_t *ostime;
+ apr_os_exp_time_get( &ostime, &timexp);
+
+ time_t mtime = mktime( ostime );*/
+
+ if (dirent->last_author)
+ svn_utf_cstring_from_utf8 (&native_author, dirent->last_author, subpool);
+
+ if ( createUDSEntry(QString( native_entryname ), QString( native_author ), dirent->size,
+ dirent->kind==svn_node_dir ? true : false, 0, entry) )
+ listEntry( entry, false );
+ }
+ listEntry( entry, true );
+
+ finished();
+ svn_pool_destroy (subpool);
+}
+
+bool kio_svnProtocol::createUDSEntry( const QString& filename, const QString& user, long long int size, bool isdir, time_t mtime, UDSEntry& entry) {
+ kdDebug(7128) << "MTime : " << ( long )mtime << endl;
+ kdDebug(7128) << "UDS filename : " << filename << endl;
+ UDSAtom atom;
+ atom.m_uds = KIO::UDS_NAME;
+ atom.m_str = filename;
+ entry.append( atom );
+
+ atom.m_uds = KIO::UDS_FILE_TYPE;
+ atom.m_long = isdir ? S_IFDIR : S_IFREG;
+ entry.append( atom );
+
+ atom.m_uds = KIO::UDS_SIZE;
+ atom.m_long = size;
+ entry.append( atom );
+
+ atom.m_uds = KIO::UDS_MODIFICATION_TIME;
+ atom.m_long = mtime;
+ entry.append( atom );
+
+ atom.m_uds = KIO::UDS_USER;
+ atom.m_str = user;
+ entry.append( atom );
+
+ return true;
+}
+
+void kio_svnProtocol::copy(const KURL & src, const KURL& dest, int /*permissions*/, bool /*overwrite*/) {
+ kdDebug(7128) << "kio_svnProtocol::copy() Source : " << src.url() << " Dest : " << dest.url() << endl;
+
+ apr_pool_t *subpool = svn_pool_create (pool);
+ svn_client_commit_info_t *commit_info = NULL;
+
+ KURL nsrc = src;
+ KURL ndest = dest;
+ nsrc.setProtocol( chooseProtocol( src.protocol() ) );
+ ndest.setProtocol( chooseProtocol( dest.protocol() ) );
+ QString srcsvn = nsrc.url();
+ QString destsvn = ndest.url();
+
+ recordCurrentURL( nsrc );
+
+ //find the requested revision
+ svn_opt_revision_t rev;
+ int idx = srcsvn.findRev( "?rev=" );
+ if ( idx != -1 ) {
+ QString revstr = srcsvn.mid( idx+5 );
+ kdDebug(7128) << "revision string found " << revstr << endl;
+ if ( revstr == "HEAD" ) {
+ rev.kind = svn_opt_revision_head;
+ kdDebug(7128) << "revision searched : HEAD" << endl;
+ } else {
+ rev.kind = svn_opt_revision_number;
+ rev.value.number = revstr.toLong();
+ kdDebug(7128) << "revision searched : " << rev.value.number << endl;
+ }
+ srcsvn = srcsvn.left( idx );
+ kdDebug(7128) << "new src : " << srcsvn << endl;
+ } else {
+ kdDebug(7128) << "no revision given. searching HEAD " << endl;
+ rev.kind = svn_opt_revision_head;
+ }
+
+ initNotifier(false, false, false, subpool);
+ svn_error_t *err = svn_client_copy(&commit_info, srcsvn.utf8(), &rev, destsvn.utf8(), ctx, subpool);
+ if ( err ) {
+ error( KIO::ERR_SLAVE_DEFINED, err->message );
+ }
+
+ finished();
+ svn_pool_destroy (subpool);
+}
+
+void kio_svnProtocol::mkdir( const KURL::List& list, int /*permissions*/ ) {
+ kdDebug(7128) << "kio_svnProtocol::mkdir(LIST) : " << list << endl;
+
+ apr_pool_t *subpool = svn_pool_create (pool);
+ svn_client_commit_info_t *commit_info = NULL;
+
+ recordCurrentURL( list[ 0 ] );
+
+ apr_array_header_t *targets = apr_array_make(subpool, list.count()+1, sizeof(const char *));
+
+ KURL::List::const_iterator it = list.begin(), end = list.end();
+ for ( ; it != end; ++it ) {
+ QString cur = makeSvnURL( *it );
+ kdDebug( 7128 ) << "kio_svnProtocol::mkdir raw url for subversion : " << cur << endl;
+ const char *_target = apr_pstrdup( subpool, svn_path_canonicalize( apr_pstrdup( subpool, cur.utf8() ), subpool ) );
+ (*(( const char ** )apr_array_push(( apr_array_header_t* )targets)) ) = _target;
+ }
+
+ initNotifier(false, false, false, subpool);
+ svn_error_t *err = svn_client_mkdir(&commit_info,targets,ctx,subpool);
+ if ( err ) {
+ error( KIO::ERR_COULD_NOT_MKDIR, err->message );
+ }
+
+ finished();
+ svn_pool_destroy (subpool);
+}
+
+void kio_svnProtocol::mkdir( const KURL& url, int /*permissions*/ ) {
+ kdDebug(7128) << "kio_svnProtocol::mkdir() : " << url.url() << endl;
+
+ apr_pool_t *subpool = svn_pool_create (pool);
+ svn_client_commit_info_t *commit_info = NULL;
+
+ QString target = makeSvnURL( url);
+ kdDebug(7128) << "SvnURL: " << target << endl;
+ recordCurrentURL( KURL( target ) );
+
+ apr_array_header_t *targets = apr_array_make(subpool, 2, sizeof(const char *));
+ (*(( const char ** )apr_array_push(( apr_array_header_t* )targets)) ) = apr_pstrdup( subpool, target.utf8() );
+
+ initNotifier(false, false, false, subpool);
+ svn_error_t *err = svn_client_mkdir(&commit_info,targets,ctx,subpool);
+ if ( err ) {
+ error( KIO::ERR_COULD_NOT_MKDIR, err->message );
+ }
+
+ finished();
+ svn_pool_destroy (subpool);
+}
+
+void kio_svnProtocol::del( const KURL& url, bool /*isfile*/ ) {
+ kdDebug(7128) << "kio_svnProtocol::del() : " << url.url() << endl;
+
+ apr_pool_t *subpool = svn_pool_create (pool);
+ svn_client_commit_info_t *commit_info = NULL;
+
+ QString target = makeSvnURL(url);
+ kdDebug(7128) << "SvnURL: " << target << endl;
+ recordCurrentURL( KURL( target ) );
+
+ apr_array_header_t *targets = apr_array_make(subpool, 2, sizeof(const char *));
+ (*(( const char ** )apr_array_push(( apr_array_header_t* )targets)) ) = apr_pstrdup( subpool, target.utf8() );
+
+ initNotifier(false, false, false, subpool);
+ svn_error_t *err = svn_client_delete(&commit_info,targets,false/*force remove locally modified files in wc*/,ctx,subpool);
+ if ( err ) {
+ error( KIO::ERR_CANNOT_DELETE, err->message );
+ }
+
+ finished();
+ svn_pool_destroy (subpool);
+}
+
+void kio_svnProtocol::rename(const KURL& src, const KURL& dest, bool /*overwrite*/) {
+ kdDebug(7128) << "kio_svnProtocol::rename() Source : " << src.url() << " Dest : " << dest.url() << endl;
+
+ apr_pool_t *subpool = svn_pool_create (pool);
+ svn_client_commit_info_t *commit_info = NULL;
+
+ KURL nsrc = src;
+ KURL ndest = dest;
+ nsrc.setProtocol( chooseProtocol( src.protocol() ) );
+ ndest.setProtocol( chooseProtocol( dest.protocol() ) );
+ QString srcsvn = nsrc.url();
+ QString destsvn = ndest.url();
+
+ recordCurrentURL( nsrc );
+
+ //find the requested revision
+ svn_opt_revision_t rev;
+ int idx = srcsvn.findRev( "?rev=" );
+ if ( idx != -1 ) {
+ QString revstr = srcsvn.mid( idx+5 );
+ kdDebug(7128) << "revision string found " << revstr << endl;
+ if ( revstr == "HEAD" ) {
+ rev.kind = svn_opt_revision_head;
+ kdDebug(7128) << "revision searched : HEAD" << endl;
+ } else {
+ rev.kind = svn_opt_revision_number;
+ rev.value.number = revstr.toLong();
+ kdDebug(7128) << "revision searched : " << rev.value.number << endl;
+ }
+ srcsvn = srcsvn.left( idx );
+ kdDebug(7128) << "new src : " << srcsvn << endl;
+ } else {
+ kdDebug(7128) << "no revision given. searching HEAD " << endl;
+ rev.kind = svn_opt_revision_head;
+ }
+
+ initNotifier(false, false, false, subpool);
+ svn_error_t *err = svn_client_move(&commit_info, srcsvn.utf8(), &rev, destsvn.utf8(), false/*force remove locally modified files in wc*/, ctx, subpool);
+ if ( err ) {
+ error( KIO::ERR_CANNOT_RENAME, err->message );
+ }
+
+ finished();
+ svn_pool_destroy (subpool);
+}
+
+void kio_svnProtocol::special( const QByteArray& data ) {
+ kdDebug(7128) << "kio_svnProtocol::special" << endl;
+
+ QDataStream stream(data, IO_ReadOnly);
+ int tmp;
+
+ stream >> tmp;
+ kdDebug(7128) << "kio_svnProtocol::special " << tmp << endl;
+
+ switch ( tmp ) {
+ case SVN_CHECKOUT:
+ {
+ KURL repository, wc;
+ int revnumber;
+ QString revkind;
+ stream >> repository;
+ stream >> wc;
+ stream >> revnumber;
+ stream >> revkind;
+ kdDebug(7128) << "kio_svnProtocol CHECKOUT from " << repository.url() << " to " << wc.url() << " at " << revnumber << " or " << revkind << endl;
+ checkout( repository, wc, revnumber, revkind );
+ break;
+ }
+ case SVN_UPDATE:
+ {
+ KURL wc;
+ int revnumber;
+ QString revkind;
+ stream >> wc;
+ stream >> revnumber;
+ stream >> revkind;
+ kdDebug(7128) << "kio_svnProtocol UPDATE " << wc.url() << " at " << revnumber << " or " << revkind << endl;
+ update(wc, revnumber, revkind );
+ break;
+ }
+ case SVN_COMMIT:
+ {
+ KURL::List wclist;
+ while ( !stream.atEnd() ) {
+ KURL tmp;
+ stream >> tmp;
+ wclist << tmp;
+ }
+ kdDebug(7128) << "kio_svnProtocol COMMIT" << endl;
+ commit( wclist );
+ break;
+ }
+ case SVN_LOG:
+ {
+ kdDebug(7128) << "kio_svnProtocol LOG" << endl;
+ int revstart, revend;
+ QString revkindstart, revkindend;
+ KURL::List targets;
+ stream >> revstart;
+ stream >> revkindstart;
+ stream >> revend;
+ stream >> revkindend;
+ while ( !stream.atEnd() ) {
+ KURL tmp;
+ stream >> tmp;
+ targets << tmp;
+ }
+ svn_log( revstart, revkindstart, revend, revkindend, targets );
+ break;
+ }
+ case SVN_IMPORT:
+ {
+ KURL wc,repos;
+ stream >> repos;
+ stream >> wc;
+ kdDebug(7128) << "kio_svnProtocol IMPORT" << endl;
+ import(repos,wc);
+ break;
+ }
+ case SVN_ADD:
+ {
+ KURL wc;
+ stream >> wc;
+ kdDebug(7128) << "kio_svnProtocol ADD" << endl;
+ add(wc);
+ break;
+ }
+ case SVN_DEL:
+ {
+ KURL::List wclist;
+ while ( !stream.atEnd() ) {
+ KURL tmp;
+ stream >> tmp;
+ wclist << tmp;
+ }
+ kdDebug(7128) << "kio_svnProtocol DEL" << endl;
+ wc_delete(wclist);
+ break;
+ }
+ case SVN_REVERT:
+ {
+ KURL::List wclist;
+ while ( !stream.atEnd() ) {
+ KURL tmp;
+ stream >> tmp;
+ wclist << tmp;
+ }
+ kdDebug(7128) << "kio_svnProtocol REVERT" << endl;
+ wc_revert(wclist);
+ break;
+ }
+ case SVN_STATUS:
+ {
+ KURL wc;
+ int checkRepos=false;
+ int fullRecurse=false;
+ stream >> wc;
+ stream >> checkRepos;
+ stream >> fullRecurse;
+ kdDebug(7128) << "kio_svnProtocol STATUS" << endl;
+ wc_status(wc,checkRepos,fullRecurse);
+ break;
+ }
+ case SVN_MKDIR:
+ {
+ KURL::List list;
+ stream >> list;
+ kdDebug(7128) << "kio_svnProtocol MKDIR" << endl;
+ mkdir(list,0);
+ break;
+ }
+ case SVN_RESOLVE:
+ {
+ KURL url;
+ bool recurse;
+ stream >> url;
+ stream >> recurse;
+ kdDebug(7128) << "kio_svnProtocol RESOLVE" << endl;
+ wc_resolve(url,recurse);
+ break;
+ }
+ case SVN_SWITCH:
+ {
+ KURL wc,url;
+ bool recurse;
+ int revnumber;
+ QString revkind;
+ stream >> wc;
+ stream >> url;
+ stream >> recurse;
+ stream >> revnumber;
+ stream >> revkind;
+ kdDebug(7128) << "kio_svnProtocol SWITCH" << endl;
+ svn_switch(wc,url,revnumber,revkind,recurse);
+ break;
+ }
+ case SVN_DIFF:
+ {
+ KURL url1,url2;
+ int rev1, rev2;
+ bool recurse;
+ QString revkind1, revkind2;
+ stream >> url1;
+ stream >> url2;
+ stream >> rev1;
+ stream >> revkind1;
+ stream >> rev2;
+ stream >> revkind2;
+ stream >> recurse;
+ kdDebug(7128) << "kio_svnProtocol DIFF" << endl;
+ svn_diff(url1,url2,rev1,rev2,revkind1,revkind2,recurse);
+ break;
+ }
+ default:
+ {
+ kdDebug(7128) << "kio_svnProtocol DEFAULT" << endl;
+ break;
+ }
+ }
+}
+
+void kio_svnProtocol::popupMessage( const QString& message ) {
+ QByteArray params;
+ QDataStream stream(params, IO_WriteOnly);
+ stream << message;
+
+ if ( !dcopClient()->send( "kded","ksvnd","popupMessage(QString)", params ) )
+ kdWarning() << "Communication with KDED:KSvnd failed" << endl;
+}
+
+void kio_svnProtocol::svn_log( int revstart, const QString& revkindstart, int revend, const QString& revkindend, const KURL::List& targets ) {
+ kdDebug(7128) << "kio_svn::log : " << targets << " from revision " << revstart << " or " << revkindstart << " to "
+ " revision " << revend << " or " << revkindend
+ << endl;
+
+ apr_pool_t *subpool = svn_pool_create (pool);
+
+ svn_opt_revision_t rev1 = createRevision( revstart, revkindstart, subpool );
+ svn_opt_revision_t rev2 = createRevision( revend, revkindend, subpool );
+
+ //TODO
+
+ finished();
+ svn_pool_destroy (subpool);
+}
+
+svn_opt_revision_t kio_svnProtocol::createRevision( int revision, const QString& revkind, apr_pool_t *pool ) {
+ svn_opt_revision_t result,endrev;
+
+ if ( revision != -1 ) {
+ result.value.number = revision;
+ result.kind = svn_opt_revision_number;
+ } else if ( revkind == "WORKING" ) {
+ result.kind = svn_opt_revision_working;
+ } else if ( revkind == "BASE" ) {
+ result.kind = svn_opt_revision_base;
+ } else if ( !revkind.isNull() ) {
+ svn_opt_parse_revision(&result,&endrev,revkind.utf8(),pool);
+ }
+ return result;
+}
+
+void kio_svnProtocol::svn_diff(const KURL & url1, const KURL& url2,int rev1, int rev2,const QString& revkind1,const QString& revkind2,bool recurse) {
+ kdDebug(7128) << "kio_svn::diff : " << url1.path() << " at revision " << rev1 << " or " << revkind1 << " with "
+ << url2.path() << " at revision " << rev2 << " or " << revkind2
+ << endl ;
+
+ apr_pool_t *subpool = svn_pool_create (pool);
+ apr_array_header_t *options = svn_cstring_split( "", "\t\r\n", TRUE, subpool );
+
+ KURL nurl1 = url1;
+ KURL nurl2 = url2;
+ nurl1.setProtocol( chooseProtocol( url1.protocol() ) ); //svn+https -> https for eg
+ nurl2.setProtocol( chooseProtocol( url2.protocol() ) );
+ recordCurrentURL( nurl1 );
+ QString source = makeSvnURL( nurl1 );
+ QString target = makeSvnURL( nurl2 );
+
+ const char *path1 = svn_path_canonicalize( apr_pstrdup( subpool, source.utf8() ), subpool );
+ const char *path2 = svn_path_canonicalize( apr_pstrdup( subpool, target.utf8() ), subpool );
+ //remove file:/// so we can diff for working copies, needs a better check (so we support URL for file:/// _repositories_ )
+ if ( nurl1.protocol() == "file" ) {
+ path1 = svn_path_canonicalize( apr_pstrdup( subpool, nurl1.path().utf8() ), subpool );
+ }
+ if ( nurl2.protocol() == "file" ) {
+ path2 = svn_path_canonicalize( apr_pstrdup( subpool, nurl2.path().utf8() ), subpool );
+ }
+ kdDebug( 7128 ) << "1 : " << path1 << " 2: " << path2 << endl;
+
+ svn_opt_revision_t revision1,revision2;
+ revision1 = createRevision(rev1, revkind1, subpool);
+ revision2 = createRevision(rev2, revkind2, subpool);
+
+ char *templ;
+ templ = apr_pstrdup ( subpool, "/tmp/tmpfile_XXXXXX" );
+ apr_file_t *outfile = NULL;
+ apr_file_mktemp( &outfile, templ , APR_READ|APR_WRITE|APR_CREATE|APR_TRUNCATE, subpool );
+
+ initNotifier(false, false, false, subpool);
+ svn_error_t *err = svn_client_diff (options, path1, &revision1, path2, &revision2, recurse, false, true, outfile, NULL, ctx, subpool);
+ if ( err )
+ error( KIO::ERR_SLAVE_DEFINED, err->message );
+ //read the content of the outfile now
+ QStringList tmp;
+ apr_file_close(outfile);
+ QFile file(templ);
+ if ( file.open( IO_ReadOnly ) ) {
+ QTextStream stream( &file );
+ QString line;
+ while ( !stream.atEnd() ) {
+ line = stream.readLine();
+ tmp << line;
+ }
+ file.close();
+ }
+ for ( QStringList::Iterator itt = tmp.begin(); itt != tmp.end(); itt++ ) {
+ setMetaData(QString::number( m_counter ).rightJustify( 10,'0' )+ "diffresult", ( *itt ) );
+ m_counter++;
+ }
+ //delete temp file
+ file.remove();
+
+ finished();
+ svn_pool_destroy (subpool);
+}
+
+void kio_svnProtocol::svn_switch( const KURL& wc, const KURL& repos, int revnumber, const QString& revkind, bool recurse) {
+ kdDebug(7128) << "kio_svn::switch : " << wc.path() << " at revision " << revnumber << " or " << revkind << endl ;
+
+ apr_pool_t *subpool = svn_pool_create (pool);
+
+ KURL nurl = repos;
+ KURL dest = wc;
+ nurl.setProtocol( chooseProtocol( repos.protocol() ) );
+ dest.setProtocol( "file" );
+ recordCurrentURL( nurl );
+ QString source = dest.path();
+ QString target = makeSvnURL( repos );
+
+ const char *path = svn_path_canonicalize( apr_pstrdup( subpool, source.utf8() ), subpool );
+ const char *url = svn_path_canonicalize( apr_pstrdup( subpool, target.utf8() ), subpool );
+
+ svn_opt_revision_t rev = createRevision( revnumber, revkind, subpool );
+
+ initNotifier(false, false, false, subpool);
+ svn_error_t *err = svn_client_switch (NULL/*result revision*/, path, url, &rev, recurse, ctx, subpool);
+ if ( err )
+ error( KIO::ERR_SLAVE_DEFINED, err->message );
+
+ finished();
+ svn_pool_destroy (subpool);
+}
+
+void kio_svnProtocol::update( const KURL& wc, int revnumber, const QString& revkind ) {
+ kdDebug(7128) << "kio_svn::update : " << wc.path() << " at revision " << revnumber << " or " << revkind << endl ;
+
+ apr_pool_t *subpool = svn_pool_create (pool);
+ KURL dest = wc;
+ dest.setProtocol( "file" );
+ QString target = dest.path();
+ recordCurrentURL( dest );
+
+ svn_opt_revision_t rev = createRevision( revnumber, revkind, subpool );
+
+ initNotifier(false, false, false, subpool);
+ svn_error_t *err = svn_client_update (NULL, svn_path_canonicalize( target.utf8(), subpool ), &rev, true, ctx, subpool);
+ if ( err )
+ error( KIO::ERR_SLAVE_DEFINED, err->message );
+
+ finished();
+ svn_pool_destroy (subpool);
+}
+
+void kio_svnProtocol::import( const KURL& repos, const KURL& wc ) {
+ kdDebug(7128) << "kio_svnProtocol::import() : " << wc.url() << " into " << repos.url() << endl;
+
+ apr_pool_t *subpool = svn_pool_create (pool);
+ svn_client_commit_info_t *commit_info = NULL;
+ bool nonrecursive = false;
+
+ KURL nurl = repos;
+ KURL dest = wc;
+ nurl.setProtocol( chooseProtocol( repos.protocol() ) );
+ dest.setProtocol( "file" );
+ recordCurrentURL( nurl );
+ dest.cleanPath( true ); // remove doubled '/'
+ QString source = dest.path(-1);
+ QString target = makeSvnURL( repos );
+
+ const char *path = svn_path_canonicalize( apr_pstrdup( subpool, source.utf8() ), subpool );
+ const char *url = svn_path_canonicalize( apr_pstrdup( subpool, target.utf8() ), subpool );
+
+ initNotifier(false, false, false, subpool);
+ svn_error_t *err = svn_client_import(&commit_info,path,url,nonrecursive,ctx,subpool);
+ if ( err )
+ error( KIO::ERR_SLAVE_DEFINED, err->message );
+
+ finished();
+ svn_pool_destroy (subpool);
+}
+
+void kio_svnProtocol::checkout( const KURL& repos, const KURL& wc, int revnumber, const QString& revkind ) {
+ kdDebug(7128) << "kio_svn::checkout : " << repos.url() << " into " << wc.path() << " at revision " << revnumber << " or " << revkind << endl ;
+
+ apr_pool_t *subpool = svn_pool_create (pool);
+ KURL nurl = repos;
+ KURL dest = wc;
+ nurl.setProtocol( chooseProtocol( repos.protocol() ) );
+ dest.setProtocol( "file" );
+ QString target = makeSvnURL( repos );
+ recordCurrentURL( nurl );
+ QString dpath = dest.path();
+
+ //find the requested revision
+ svn_opt_revision_t rev = createRevision( revnumber, revkind, subpool );
+
+ initNotifier(true, false, false, subpool);
+ svn_error_t *err = svn_client_checkout (NULL/* rev actually checkedout */, svn_path_canonicalize( target.utf8(), subpool ), svn_path_canonicalize ( dpath.utf8(), subpool ), &rev, true, ctx, subpool);
+ if ( err )
+ error( KIO::ERR_SLAVE_DEFINED, err->message );
+
+ finished();
+ svn_pool_destroy (subpool);
+}
+
+void kio_svnProtocol::commit(const KURL::List& wc) {
+ kdDebug(7128) << "kio_svnProtocol::commit() : " << wc << endl;
+
+ apr_pool_t *subpool = svn_pool_create (pool);
+ svn_client_commit_info_t *commit_info = NULL;
+ bool nonrecursive = false;
+
+ apr_array_header_t *targets = apr_array_make(subpool, 1+wc.count(), sizeof(const char *));
+
+ for ( QValueListConstIterator<KURL> it = wc.begin(); it != wc.end() ; ++it ) {
+ KURL nurl = *it;
+ nurl.setProtocol( "file" );
+ recordCurrentURL( nurl );
+ (*(( const char ** )apr_array_push(( apr_array_header_t* )targets)) ) = svn_path_canonicalize( nurl.path().utf8(), subpool );
+ }
+
+ initNotifier(false, false, false, subpool);
+ svn_error_t *err = svn_client_commit(&commit_info,targets,nonrecursive,ctx,subpool);
+ if ( err )
+ error( KIO::ERR_SLAVE_DEFINED, err->message );
+
+ if ( commit_info ) {
+ for ( QValueListConstIterator<KURL> it = wc.begin(); it != wc.end() ; ++it ) {
+ KURL nurl = *it;
+ nurl.setProtocol( "file" );
+
+ QString userstring = i18n ( "Nothing to commit." );
+ if ( SVN_IS_VALID_REVNUM( commit_info->revision ) )
+ userstring = i18n( "Committed revision %1." ).arg(commit_info->revision);
+ setMetaData(QString::number( m_counter ).rightJustify( 10,'0' )+ "path", nurl.path() );
+ setMetaData(QString::number( m_counter ).rightJustify( 10,'0' )+ "action", "0" );
+ setMetaData(QString::number( m_counter ).rightJustify( 10,'0' )+ "kind", "0" );
+ setMetaData(QString::number( m_counter ).rightJustify( 10,'0' )+ "mime_t", "" );
+ setMetaData(QString::number( m_counter ).rightJustify( 10,'0' )+ "content", "0" );
+ setMetaData(QString::number( m_counter ).rightJustify( 10,'0' )+ "prop", "0" );
+ setMetaData(QString::number( m_counter ).rightJustify( 10,'0' )+ "rev" , QString::number( commit_info->revision ) );
+ setMetaData(QString::number( m_counter ).rightJustify( 10,'0' )+ "string", userstring );
+ m_counter++;
+ }
+ }
+
+ finished();
+ svn_pool_destroy (subpool);
+}
+
+void kio_svnProtocol::add(const KURL& wc) {
+ kdDebug(7128) << "kio_svnProtocol::add() : " << wc.url() << endl;
+
+ apr_pool_t *subpool = svn_pool_create (pool);
+ bool nonrecursive = false;
+
+ KURL nurl = wc;
+ nurl.setProtocol( "file" );
+ QString target = nurl.url();
+ recordCurrentURL( nurl );
+
+ initNotifier(false, false, false, subpool);
+ svn_error_t *err = svn_client_add(svn_path_canonicalize( nurl.path().utf8(), subpool ),nonrecursive,ctx,subpool);
+ if ( err )
+ error( KIO::ERR_SLAVE_DEFINED, err->message );
+
+ finished();
+ svn_pool_destroy (subpool);
+}
+
+void kio_svnProtocol::wc_delete(const KURL::List& wc) {
+ kdDebug(7128) << "kio_svnProtocol::wc_delete() : " << wc << endl;
+
+ apr_pool_t *subpool = svn_pool_create (pool);
+ svn_client_commit_info_t *commit_info = NULL;
+ bool nonrecursive = false;
+
+ apr_array_header_t *targets = apr_array_make(subpool, 1+wc.count(), sizeof(const char *));
+
+ for ( QValueListConstIterator<KURL> it = wc.begin(); it != wc.end() ; ++it ) {
+ KURL nurl = *it;
+ nurl.setProtocol( "file" );
+ recordCurrentURL( nurl );
+ (*(( const char ** )apr_array_push(( apr_array_header_t* )targets)) ) = svn_path_canonicalize( nurl.path().utf8(), subpool );
+ }
+
+ initNotifier(false, false, false, subpool);
+ svn_error_t *err = svn_client_delete(&commit_info,targets,nonrecursive,ctx,subpool);
+
+ if ( err )
+ error( KIO::ERR_SLAVE_DEFINED, err->message );
+
+ finished();
+ svn_pool_destroy (subpool);
+}
+
+void kio_svnProtocol::wc_revert(const KURL::List& wc) {
+ kdDebug(7128) << "kio_svnProtocol::revert() : " << wc << endl;
+
+ apr_pool_t *subpool = svn_pool_create (pool);
+ bool nonrecursive = false;
+
+ apr_array_header_t *targets = apr_array_make(subpool, 1 + wc.count(), sizeof(const char *));
+
+ for ( QValueListConstIterator<KURL> it = wc.begin(); it != wc.end() ; ++it ) {
+ KURL nurl = *it;
+ nurl.setProtocol( "file" );
+ recordCurrentURL( nurl );
+ (*(( const char ** )apr_array_push(( apr_array_header_t* )targets)) ) = svn_path_canonicalize( nurl.path().utf8(), subpool );
+ }
+
+ initNotifier(false, false, false, subpool);
+ svn_error_t *err = svn_client_revert(targets,nonrecursive,ctx,subpool);
+ if ( err )
+ error( KIO::ERR_SLAVE_DEFINED, err->message );
+
+ finished();
+ svn_pool_destroy (subpool);
+}
+
+void kio_svnProtocol::wc_status(const KURL& wc, bool checkRepos, bool fullRecurse, bool getAll, int revnumber, const QString& revkind) {
+ kdDebug(7128) << "kio_svnProtocol::status() : " << wc.url() << endl;
+
+ apr_pool_t *subpool = svn_pool_create (pool);
+ svn_revnum_t result_rev;
+ bool no_ignore = FALSE;
+
+ KURL nurl = wc;
+ nurl.setProtocol( "file" );
+ recordCurrentURL( nurl );
+
+ svn_opt_revision_t rev = createRevision( revnumber, revkind, subpool );
+
+ initNotifier(false, false, false, subpool);
+
+ svn_error_t *err = svn_client_status(&result_rev, svn_path_canonicalize( nurl.path().utf8(), subpool ), &rev, kio_svnProtocol::status, this, fullRecurse, getAll, checkRepos, no_ignore, ctx, subpool);
+
+ if ( err )
+ error( KIO::ERR_SLAVE_DEFINED, err->message );
+
+ finished();
+ svn_pool_destroy (subpool);
+}
+
+//change the proto and remove trailing /
+//remove double / also
+QString kio_svnProtocol::makeSvnURL ( const KURL& url ) const {
+ QString kproto = url.protocol();
+ KURL tpURL = url;
+ tpURL.cleanPath( true );
+ QString svnUrl;
+ if ( kproto == "svn+http" ) {
+ kdDebug(7128) << "http:/ " << url.url() << endl;
+ tpURL.setProtocol("http");
+ svnUrl = tpURL.url(-1);
+ return svnUrl;
+ }
+ else if ( kproto == "svn+https" ) {
+ kdDebug(7128) << "https:/ " << url.url() << endl;
+ tpURL.setProtocol("https");
+ svnUrl = tpURL.url(-1);
+ return svnUrl;
+ }
+ else if ( kproto == "svn+ssh" ) {
+ kdDebug(7128) << "svn+ssh:/ " << url.url() << endl;
+ tpURL.setProtocol("svn+ssh");
+ svnUrl = tpURL.url(-1);
+ return svnUrl;
+ }
+ else if ( kproto == "svn" ) {
+ kdDebug(7128) << "svn:/ " << url.url() << endl;
+ tpURL.setProtocol("svn");
+ svnUrl = tpURL.url(-1);
+ return svnUrl;
+ }
+ else if ( kproto == "svn+file" ) {
+ kdDebug(7128) << "file:/ " << url.url() << endl;
+ tpURL.setProtocol("file");
+ svnUrl = tpURL.url(-1);
+ //hack : add one more / after file:/
+ int idx = svnUrl.find("/");
+ svnUrl.insert( idx, "//" );
+ return svnUrl;
+ }
+ return tpURL.url(-1);
+}
+
+QString kio_svnProtocol::chooseProtocol ( const QString& kproto ) const {
+ if ( kproto == "svn+http" ) return QString( "http" );
+ else if ( kproto == "svn+https" ) return QString( "https" );
+ else if ( kproto == "svn+ssh" ) return QString( "svn+ssh" );
+ else if ( kproto == "svn" ) return QString( "svn" );
+ else if ( kproto == "svn+file" ) return QString( "file" );
+ return kproto;
+}
+
+svn_error_t *kio_svnProtocol::trustSSLPrompt(svn_auth_cred_ssl_server_trust_t **cred_p, void *, const char */*realm*/, apr_uint32_t /*failures*/, const svn_auth_ssl_server_cert_info_t */*cert_info*/, svn_boolean_t /*may_save*/, apr_pool_t *pool) {
+ //when ksvnd is ready make it prompt for the SSL certificate ... XXX
+ *cred_p = (svn_auth_cred_ssl_server_trust_t*)apr_pcalloc (pool, sizeof (**cred_p));
+ (*cred_p)->may_save = FALSE;
+ return SVN_NO_ERROR;
+}
+
+svn_error_t *kio_svnProtocol::clientCertSSLPrompt(svn_auth_cred_ssl_client_cert_t **/*cred_p*/, void *, const char */*realm*/, svn_boolean_t /*may_save*/, apr_pool_t */*pool*/) {
+ //when ksvnd is ready make it prompt for the SSL certificate ... XXX
+/* *cred_p = apr_palloc (pool, sizeof(**cred_p));
+ (*cred_p)->cert_file = cert_file;*/
+ return SVN_NO_ERROR;
+}
+
+svn_error_t *kio_svnProtocol::clientCertPasswdPrompt(svn_auth_cred_ssl_client_cert_pw_t **/*cred_p*/, void *, const char */*realm*/, svn_boolean_t /*may_save*/, apr_pool_t */*pool*/) {
+ //when ksvnd is ready make it prompt for the SSL certificate password ... XXX
+ return SVN_NO_ERROR;
+}
+
+svn_error_t *kio_svnProtocol::commitLogPrompt( const char **log_msg, const char **/*file*/, apr_array_header_t *commit_items, void *baton, apr_pool_t *pool ) {
+ QCString replyType;
+ QByteArray params;
+ QByteArray reply;
+ QString result;
+ QStringList slist;
+ kio_svnProtocol *p = ( kio_svnProtocol* )baton;
+ svn_stringbuf_t *message = NULL;
+
+ for (int i = 0; i < commit_items->nelts; i++) {
+ QString list;
+ svn_client_commit_item_t *item = ((svn_client_commit_item_t **) commit_items->elts)[i];
+ const char *path = item->path;
+ char text_mod = '_', prop_mod = ' ';
+
+ if (! path)
+ path = item->url;
+ else if (! *path)
+ path = ".";
+
+ if (! path)
+ path = ".";
+
+ if ((item->state_flags & SVN_CLIENT_COMMIT_ITEM_DELETE) && (item->state_flags & SVN_CLIENT_COMMIT_ITEM_ADD))
+ text_mod = 'R';
+ else if (item->state_flags & SVN_CLIENT_COMMIT_ITEM_ADD)
+ text_mod = 'A';
+ else if (item->state_flags & SVN_CLIENT_COMMIT_ITEM_DELETE)
+ text_mod = 'D';
+ else if (item->state_flags & SVN_CLIENT_COMMIT_ITEM_TEXT_MODS)
+ text_mod = 'M';
+ if (item->state_flags & SVN_CLIENT_COMMIT_ITEM_PROP_MODS)
+ prop_mod = 'M';
+
+ list += text_mod;
+ list += " ";
+ list += prop_mod;
+ list += " ";
+ list += path;
+ kdDebug(7128) << " Commiting items : " << list << endl;
+ slist << list;
+ }
+
+ QDataStream stream(params, IO_WriteOnly);
+ stream << slist.join("\n");
+
+ if ( !p->dcopClient()->call( "kded","ksvnd","commitDialog(QString)", params, replyType, reply ) ) {
+ kdWarning() << "Communication with KDED:KSvnd failed" << endl;
+ return SVN_NO_ERROR;
+ }
+
+ if ( replyType != "QString" ) {
+ kdWarning() << "Unexpected reply type" << endl;
+ return SVN_NO_ERROR;
+ }
+
+ QDataStream stream2 ( reply, IO_ReadOnly );
+ stream2 >> result;
+
+ if ( result.isNull() ) { //cancelled
+ *log_msg = NULL;
+ return SVN_NO_ERROR;
+ }
+
+ message = svn_stringbuf_create( result.utf8(), pool );
+ *log_msg = message->data;
+
+ return SVN_NO_ERROR;
+}
+
+void kio_svnProtocol::notify(void *baton, const char *path, svn_wc_notify_action_t action, svn_node_kind_t kind, const char *mime_type, svn_wc_notify_state_t content_state, svn_wc_notify_state_t prop_state, svn_revnum_t revision) {
+ kdDebug(7128) << "NOTIFY : " << path << " updated at revision " << revision << " action : " << action << ", kind : " << kind << " , content_state : " << content_state << ", prop_state : " << prop_state << endl;
+
+ QString userstring;
+ struct notify_baton *nb = ( struct notify_baton* ) baton;
+
+ //// Convert notification to a user readable string
+ switch ( action ) {
+ case svn_wc_notify_add : //add
+ if (mime_type && (svn_mime_type_is_binary (mime_type)))
+ userstring = i18n( "A (bin) %1" ).arg( path );
+ else
+ userstring = i18n( "A %1" ).arg( path );
+ break;
+ case svn_wc_notify_copy: //copy
+ break;
+ case svn_wc_notify_delete: //delete
+ nb->received_some_change = TRUE;
+ userstring = i18n( "D %1" ).arg( path );
+ break;
+ case svn_wc_notify_restore : //restore
+ userstring=i18n( "Restored %1." ).arg( path );
+ break;
+ case svn_wc_notify_revert : //revert
+ userstring=i18n( "Reverted %1." ).arg( path );
+ break;
+ case svn_wc_notify_failed_revert: //failed revert
+ userstring=i18n( "Failed to revert %1.\nTry updating instead." ).arg( path );
+ break;
+ case svn_wc_notify_resolved: //resolved
+ userstring=i18n( "Resolved conflicted state of %1." ).arg( path );
+ break;
+ case svn_wc_notify_skip: //skip
+ if ( content_state == svn_wc_notify_state_missing )
+ userstring=i18n("Skipped missing target %1.").arg( path );
+ else
+ userstring=i18n("Skipped %1.").arg( path );
+ break;
+ case svn_wc_notify_update_delete: //update_delete
+ nb->received_some_change = TRUE;
+ userstring=i18n( "D %1" ).arg( path );
+ break;
+ case svn_wc_notify_update_add: //update_add
+ nb->received_some_change = TRUE;
+ userstring=i18n( "A %1" ).arg( path );
+ break;
+ case svn_wc_notify_update_update: //update_update
+ {
+ /* If this is an inoperative dir change, do no notification.
+ An inoperative dir change is when a directory gets closed
+ without any props having been changed. */
+ if (! ((kind == svn_node_dir)
+ && ((prop_state == svn_wc_notify_state_inapplicable)
+ || (prop_state == svn_wc_notify_state_unknown)
+ || (prop_state == svn_wc_notify_state_unchanged)))) {
+ nb->received_some_change = TRUE;
+
+ if (kind == svn_node_file) {
+ if (content_state == svn_wc_notify_state_conflicted)
+ userstring = "C";
+ else if (content_state == svn_wc_notify_state_merged)
+ userstring = "G";
+ else if (content_state == svn_wc_notify_state_changed)
+ userstring = "U";
+ }
+
+ if (prop_state == svn_wc_notify_state_conflicted)
+ userstring += "C";
+ else if (prop_state == svn_wc_notify_state_merged)
+ userstring += "G";
+ else if (prop_state == svn_wc_notify_state_changed)
+ userstring += "U";
+ else
+ userstring += " ";
+
+ if (! ((content_state == svn_wc_notify_state_unchanged
+ || content_state == svn_wc_notify_state_unknown)
+ && (prop_state == svn_wc_notify_state_unchanged
+ || prop_state == svn_wc_notify_state_unknown)))
+ userstring += QString( " " ) + path;
+ }
+ break;
+ }
+ case svn_wc_notify_update_completed: //update_completed
+ {
+ if (! nb->suppress_final_line) {
+ if (SVN_IS_VALID_REVNUM (revision)) {
+ if (nb->is_export) {
+ if ( nb->in_external )
+ userstring = i18n("Exported external at revision %1.").arg( revision );
+ else
+ userstring = i18n("Exported revision %1.").arg( revision );
+ } else if (nb->is_checkout) {
+ if ( nb->in_external )
+ userstring = i18n("Checked out external at revision %1.").arg( revision );
+ else
+ userstring = i18n("Checked out revision %1.").arg( revision);
+ } else {
+ if (nb->received_some_change) {
+ if ( nb->in_external )
+ userstring=i18n("Updated external to revision %1.").arg( revision );
+ else
+ userstring = i18n("Updated to revision %1.").arg( revision);
+ } else {
+ if ( nb->in_external )
+ userstring = i18n("External at revision %1.").arg( revision );
+ else
+ userstring = i18n("At revision %1.").arg( revision);
+ }
+ }
+ } else /* no revision */ {
+ if (nb->is_export) {
+ if ( nb->in_external )
+ userstring = i18n("External export complete.");
+ else
+ userstring = i18n("Export complete.");
+ } else if (nb->is_checkout) {
+ if ( nb->in_external )
+ userstring = i18n("External checkout complete.");
+ else
+ userstring = i18n("Checkout complete.");
+ } else {
+ if ( nb->in_external )
+ userstring = i18n("External update complete.");
+ else
+ userstring = i18n("Update complete.");
+ }
+ }
+ }
+ }
+ if (nb->in_external)
+ nb->in_external = FALSE;
+ break;
+ case svn_wc_notify_update_external: //update_external
+ nb->in_external = TRUE;
+ userstring = i18n("Fetching external item into %1." ).arg( path );
+ break;
+ case svn_wc_notify_status_completed: //status_completed
+ if (SVN_IS_VALID_REVNUM (revision))
+ userstring = i18n( "Status against revision: %1.").arg( revision );
+ break;
+ case svn_wc_notify_status_external: //status_external
+ userstring = i18n("Performing status on external item at %1.").arg( path );
+ break;
+ case svn_wc_notify_commit_modified: //commit_modified
+ userstring = i18n( "Sending %1").arg( path );
+ break;
+ case svn_wc_notify_commit_added: //commit_added
+ if (mime_type && svn_mime_type_is_binary (mime_type)) {
+ userstring = i18n( "Adding (bin) %1.").arg( path );
+ } else {
+ userstring = i18n( "Adding %1.").arg( path );
+ }
+ break;
+ case svn_wc_notify_commit_deleted: //commit_deleted
+ userstring = i18n( "Deleting %1.").arg( path );
+ break;
+ case svn_wc_notify_commit_replaced: //commit_replaced
+ userstring = i18n( "Replacing %1.").arg( path );
+ break;
+ case svn_wc_notify_commit_postfix_txdelta: //commit_postfix_txdelta
+ if (! nb->sent_first_txdelta) {
+ nb->sent_first_txdelta = TRUE;
+ userstring=i18n("Transmitting file data ");
+ } else {
+ userstring=".";
+ }
+ break;
+
+ break;
+ case svn_wc_notify_blame_revision: //blame_revision
+ break;
+ default:
+ break;
+ }
+ //// End convert
+
+ kio_svnProtocol *p = ( kio_svnProtocol* )nb->master;
+
+ p->setMetaData(QString::number( p->counter() ).rightJustify( 10,'0' )+ "path" , QString::fromUtf8( path ));
+ p->setMetaData(QString::number( p->counter() ).rightJustify( 10,'0' )+ "action", QString::number( action ));
+ p->setMetaData(QString::number( p->counter() ).rightJustify( 10,'0' )+ "kind", QString::number( kind ));
+ p->setMetaData(QString::number( p->counter() ).rightJustify( 10,'0' )+ "mime_t", QString::fromUtf8( mime_type ));
+ p->setMetaData(QString::number( p->counter() ).rightJustify( 10,'0' )+ "content", QString::number( content_state ));
+ p->setMetaData(QString::number( p->counter() ).rightJustify( 10,'0' )+ "prop", QString::number( prop_state ));
+ p->setMetaData(QString::number( p->counter() ).rightJustify( 10,'0' )+ "rev", QString::number( revision ));
+ p->setMetaData(QString::number( p->counter() ).rightJustify( 10,'0' )+ "string", userstring );
+ p->incCounter();
+}
+
+void kio_svnProtocol::status(void *baton, const char *path, svn_wc_status_t *status) {
+ kdDebug(7128) << "STATUS : " << path << ", wc text status : " << status->text_status
+ << ", wc prop status : " << status->prop_status
+ << ", repos text status : " << status->repos_text_status
+ << ", repos prop status : " << status->repos_prop_status
+ << endl;
+
+ QByteArray params;
+ kio_svnProtocol *p = ( kio_svnProtocol* )baton;
+
+ QDataStream stream(params, IO_WriteOnly);
+ long int rev = status->entry ? status->entry->revision : 0;
+ stream << QString::fromUtf8( path ) << status->text_status << status->prop_status << status->repos_text_status << status->repos_prop_status << rev;
+
+ p->setMetaData(QString::number( p->counter() ).rightJustify( 10,'0' )+ "path", QString::fromUtf8( path ));
+ p->setMetaData(QString::number( p->counter() ).rightJustify( 10,'0' )+ "text", QString::number( status->text_status ));
+ p->setMetaData(QString::number( p->counter() ).rightJustify( 10,'0' )+ "prop", QString::number( status->prop_status ));
+ p->setMetaData(QString::number( p->counter() ).rightJustify( 10,'0' )+ "reptxt", QString::number( status->repos_text_status ));
+ p->setMetaData(QString::number( p->counter() ).rightJustify( 10,'0' )+ "repprop", QString::number( status->repos_prop_status ));
+ p->setMetaData(QString::number( p->counter() ).rightJustify( 10,'0' )+ "rev", QString::number( rev ));
+ p->incCounter();
+}
+
+
+void kio_svnProtocol::wc_resolve( const KURL& wc, bool recurse ) {
+ kdDebug(7128) << "kio_svnProtocol::wc_resolve() : " << wc.url() << endl;
+
+ apr_pool_t *subpool = svn_pool_create (pool);
+
+ KURL nurl = wc;
+ nurl.setProtocol( "file" );
+ recordCurrentURL( nurl );
+
+ initNotifier(false, false, false, subpool);
+ svn_error_t *err = svn_client_resolved(svn_path_canonicalize( nurl.path().utf8(), subpool ), recurse,ctx,subpool);
+ if ( err )
+ error( KIO::ERR_SLAVE_DEFINED, err->message );
+
+ finished();
+ svn_pool_destroy (subpool);
+}
+
+extern "C"
+{
+ KDE_EXPORT int kdemain(int argc, char **argv) {
+ KInstance instance( "kio_svn" );
+
+ kdDebug(7128) << "*** Starting kio_svn " << endl;
+
+ if (argc != 4) {
+ kdDebug(7128) << "Usage: kio_svn protocol domain-socket1 domain-socket2" << endl;
+ exit(-1);
+ }
+
+ kio_svnProtocol slave(argv[2], argv[3]);
+ slave.dispatchLoop();
+
+ kdDebug(7128) << "*** kio_svn Done" << endl;
+ return 0;
+ }
+}
+
diff --git a/kioslave/svn/svn.h b/kioslave/svn/svn.h
new file mode 100644
index 00000000..50c92d1c
--- /dev/null
+++ b/kioslave/svn/svn.h
@@ -0,0 +1,140 @@
+/* This file is part of the KDE project
+ Copyright (C) 2003 Mickael Marchand <marchand@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 _svn_H_
+#define _svn_H_
+
+#include <qstring.h>
+#include <qcstring.h>
+
+#include <kurl.h>
+#include <kio/global.h>
+#include <kio/slavebase.h>
+#include <subversion-1/svn_pools.h>
+#include <subversion-1/svn_auth.h>
+#include <subversion-1/svn_client.h>
+#include <subversion-1/svn_config.h>
+#include <sys/stat.h>
+#include <qvaluelist.h>
+#include <subversion-1/svn_wc.h>
+
+class QCString;
+class kio_svnProtocol;
+
+typedef struct kbaton {
+ svn_stream_t *target_stream;
+ svn_stringbuf_t *target_string;
+ svn_stream_t *string_stream;
+} kbaton;
+
+typedef struct kio_svn_callback_baton_t {
+ const char* base_dir;
+ apr_hash_t *config;
+ apr_pool_t *pool;
+} kio_svn_callback_baton_t;
+
+typedef struct notify_baton {
+ svn_boolean_t received_some_change;
+ svn_boolean_t is_checkout;
+ svn_boolean_t is_export;
+ svn_boolean_t suppress_final_line;
+ svn_boolean_t sent_first_txdelta;
+ svn_boolean_t in_external;
+ svn_boolean_t had_print_error; /* Used to not keep printing error messages
+ when we've already had one print error. */
+ apr_pool_t *pool; /* this pool is cleared after every notification,
+ so don't keep anything here! */
+ kio_svnProtocol *master;
+} notify_baton;
+
+
+class kio_svnProtocol : public KIO::SlaveBase
+{
+ public:
+ kio_svnProtocol(const QCString &pool_socket, const QCString &app_socket);
+ virtual ~kio_svnProtocol();
+ virtual void special( const QByteArray& data );
+ virtual void get(const KURL& url);
+ virtual void listDir(const KURL& url);
+ virtual void stat(const KURL& url);
+ virtual void mkdir(const KURL& url, int permissions);
+ virtual void mkdir(const KURL::List& list, int permissions);
+ virtual void del( const KURL& url, bool isfile );
+ virtual void copy(const KURL & src, const KURL& dest, int permissions, bool overwrite);
+ virtual void rename(const KURL& src, const KURL& dest, bool overwrite);
+ void checkout( const KURL& repos, const KURL& wc, int revnumber, const QString& revkind );
+ void import( const KURL& repos, const KURL& wc );
+ void svn_switch( const KURL& wc, const KURL& url, int revnumber, const QString& revkind, bool recurse);
+ void svn_log( int revstart, const QString& revkindstart, int revend, const QString& revkindend, const KURL::List& targets );
+ void svn_diff( const KURL& url1, const KURL& url2, int rev1, int rev2, const QString& revkind1, const QString& revkind2, bool recurse);
+ //TODO fix with svn 1.2 : support a KURL::List -> svn_client_update2()
+ void update( const KURL& wc, int revnumber, const QString& revkind );
+ void commit( const KURL::List& wc );
+ void add( const KURL& wc );
+ //these work using the working copy
+ void wc_resolve( const KURL& wc, bool recurse = true );
+ void wc_delete( const KURL::List& wc );
+ void wc_revert( const KURL::List& wc );
+ void wc_status(const KURL& wc, bool checkRepos=false, bool fullRecurse=true, bool getAll=true, int revnumber=-1, const QString& revkind="HEAD");
+
+ static svn_error_t* checkAuth(svn_auth_cred_simple_t **cred, void *baton, const char *realm, const char *username, svn_boolean_t may_save, apr_pool_t *pool);
+ static svn_error_t *trustSSLPrompt(svn_auth_cred_ssl_server_trust_t **cred_p, void *, const char *realm, apr_uint32_t failures, const svn_auth_ssl_server_cert_info_t *cert_info, svn_boolean_t may_save, apr_pool_t *pool);
+ static svn_error_t *clientCertSSLPrompt(svn_auth_cred_ssl_client_cert_t **cred_p, void *, const char *realm, svn_boolean_t may_save, apr_pool_t *pool);
+ static svn_error_t *clientCertPasswdPrompt(svn_auth_cred_ssl_client_cert_pw_t **cred_p, void *, const char *realm, svn_boolean_t may_save, apr_pool_t *pool);
+ static svn_error_t *commitLogPrompt( const char **log_msg, const char **tmp_file, apr_array_header_t *commit_items, void *baton, apr_pool_t *pool );
+ static void notify(void *baton, const char *path, svn_wc_notify_action_t action, svn_node_kind_t kind, const char *mime_type, svn_wc_notify_state_t content_state, svn_wc_notify_state_t prop_state, svn_revnum_t revision);
+ static void status(void *baton, const char *path, svn_wc_status_t *status);
+
+ QString chooseProtocol ( const QString& kproto ) const;
+ QString makeSvnURL ( const KURL& url ) const;
+ void initNotifier(bool is_checkout, bool is_export, bool suppress_final_line, apr_pool_t *spool);
+
+ void recordCurrentURL(const KURL& url);
+ void popupMessage( const QString& message );
+ int counter() { return m_counter; }
+ void incCounter() { m_counter++; }
+ svn_opt_revision_t createRevision( int revision, const QString& revkind, apr_pool_t *pool );
+
+ KURL myURL;
+ svn_client_ctx_t *ctx;
+ KIO::AuthInfo info;
+
+ enum SVN_METHOD {
+ SVN_CHECKOUT=1, //KURL repository, KURL workingcopy, int revnumber=-1, QString revkind(HEAD, ...) //revnumber==-1 => use of revkind
+ SVN_UPDATE=2, // KURL wc (svn:///tmp/test, int revnumber=-1, QString revkind(HEAD, ...) // revnumber==-1 => use of revkind
+ SVN_COMMIT=3,
+ SVN_LOG=4,
+ SVN_IMPORT=5,
+ SVN_ADD=6,
+ SVN_DEL=7,
+ SVN_REVERT=8,
+ SVN_STATUS=9,
+ SVN_MKDIR=10,
+ SVN_RESOLVE=11,
+ SVN_SWITCH=12,
+ SVN_DIFF=13
+ };
+
+ private:
+ bool createUDSEntry( const QString& filename, const QString& user, long long int size, bool isdir, time_t mtime, KIO::UDSEntry& entry);
+ apr_pool_t *pool;
+ int m_counter;
+};
+
+#endif
diff --git a/kioslave/svn/svn.protocol b/kioslave/svn/svn.protocol
new file mode 100644
index 00000000..abd77fb3
--- /dev/null
+++ b/kioslave/svn/svn.protocol
@@ -0,0 +1,43 @@
+[Protocol]
+exec=kio_svn
+protocol=svn
+input=none
+output=filesystem
+reading=true
+writing=true
+deleting=true
+makedir=true
+linking=false
+moving=true
+listing=Name,Size,Date,Owner
+defaultMimetype=application/octet-stream
+Icon=remote
+Description=Subversion ioslave
+Description[br]=Sklav E/D Subversion
+Description[ca]=Ioslave de Subversion
+Description[cs]=Subversion protokol
+Description[de]=Ein-/Ausgabemodul für Subversion
+Description[es]=El ioslave de Subversion
+Description[et]=Subversioni IO-moodul
+Description[fr]=ioslave subversion
+Description[ga]=ioslave Subversion
+Description[gl]=Ioslave para Subversíon
+Description[hu]=Subversion KDE-protokoll
+Description[it]=Slave I/O di Subversion
+Description[lt]=Subversion įvesties-išvesties priedas
+Description[nb]=Subversion-iu-slave
+Description[nds]=In-/Utgaavmoduul för Subversion
+Description[ne]=उप संसà¥à¤•à¤°à¤£ ioslave
+Description[nn]=Subversion-iu-slave
+Description[pl]=Wtyczka protokołu Subversion
+Description[pt]='Ioslave' para Subversion
+Description[pt_BR]=ioslave de Subversão
+Description[ru]=ДоÑтуп к хранилищу Subversion
+Description[sl]=ioslave za Subversion
+Description[sr]=IOSlave за Subversion
+Description[sr@Latn]=IOSlave za Subversion
+Description[sv]=Subversion I/O-slav
+Description[tr]=Alt Version ioslave
+Description[uk]=Підлеглий В/В Subversion
+maxInstances=5
+class=:internet
diff --git a/kioslave/svn/svnhelper/Makefile.am b/kioslave/svn/svnhelper/Makefile.am
new file mode 100644
index 00000000..bb5afe46
--- /dev/null
+++ b/kioslave/svn/svnhelper/Makefile.am
@@ -0,0 +1,18 @@
+bin_PROGRAMS = kio_svn_helper
+
+INCLUDES = $(all_includes)
+AM_LDFLAGS = $(all_libraries)
+
+kio_svn_helper_SOURCES = kio_svn_helper.cpp subversioncheckout.ui subversionswitch.ui subversionlog.ui subversiondiff.ui
+
+kio_svn_helper_LDFLAGS = $(KDE_RPATH) $(LIB_KDECORE) $(LIB_KDEUI) $(LIB_KSYCOCA) $(LIB_KIO) $(all_libraries)
+
+servicemenudir = \
+ $(kde_datadir)/konqueror/servicemenus
+
+servicemenu_DATA = \
+ subversion.desktop subversion_toplevel.desktop
+
+
+METASOURCES = AUTO
+
diff --git a/kioslave/svn/svnhelper/apply_patch.desktop b/kioslave/svn/svnhelper/apply_patch.desktop
new file mode 100644
index 00000000..0c010a5d
--- /dev/null
+++ b/kioslave/svn/svnhelper/apply_patch.desktop
@@ -0,0 +1,94 @@
+[Desktop Entry]
+ServiceTypes=text/x-diff
+#uncomment when Exec is implemented
+#Actions=Apply
+X-KDE-Priority=TopLevel
+
+[Desktop Action Apply]
+Name=Apply Patch...
+Name[bg]=Прилагане на кръпка...
+Name[ca]=Aplica pedaç...
+Name[cs]=Aplikovat záplatu...
+Name[da]=Anvend rettelse...
+Name[de]=Patch einspielen ...
+Name[el]=ΕφαÏμογή επιδιόÏθωσης...
+Name[eo]=Apliki Flikon...
+Name[es]=Aplicar parche...
+Name[et]=Paiga rakendamine...
+Name[eu]=Aplikatu adabakia...
+Name[fa]=اعمال کژنه...
+Name[fi]=Toteuta korjaus...
+Name[fr]=Appliquer le correctif...
+Name[ga]=Cuir Paiste i bhFeidhm...
+Name[gl]=Aplicar un parche...
+Name[he]=החל ×ת הטל××™...
+Name[hu]=Folt alkalmazása...
+Name[is]=Virkja plástur...
+Name[it]=Applica correzione...
+Name[ja]=パッãƒã‚’é©ç”¨...
+Name[ka]=ბებკის გáƒáƒáƒ¥áƒ¢áƒ˜áƒ£áƒ áƒ”ბáƒ...
+Name[kk]=Жамауды қолдану...
+Name[lt]=Pritaikyti pataisymÄ…...
+Name[nb]=Bruk lapp …
+Name[nds]=Kodeplaster inspelen...
+Name[ne]=लागू पà¥à¤¯à¤¾à¤š...
+Name[nl]=Patch toepassen...
+Name[nn]=Bruk lapp …
+Name[pa]=ਪੈਂਚ ਲਾਗੂ...
+Name[pl]=Nałóż łatę...
+Name[pt]=Aplicar um 'Patch'...
+Name[pt_BR]=Aplicar um 'Patch'...
+Name[ru]=Применить заплатку...
+Name[sk]=Aplikovať záplatu...
+Name[sl]=Uveljavi popravek ...
+Name[sr]=Примени закрпу...
+Name[sr@Latn]=Primeni zakrpu...
+Name[sv]=Utför programfix...
+Name[tr]=Yamayı Uygula...
+Name[uk]=ЗаÑтоÑувати латку...
+Name[zh_CN]=应用补ä¸...
+Name[zh_TW]=套用修補...
+Icon=apply
+Exec=
+Comment=Apply the patch to another folder/file
+Comment[bg]=Прилагане на кръпка към друга директориÑ/файл
+Comment[ca]=Aplica el pedaç a una altra carpeta o fitxer
+Comment[cs]=Aplikovat záplatu na jiný soubor/složku
+Comment[da]=Anvend rettelsen på en anden mappe/fil
+Comment[de]=Spielt den Patch in einen/eine andere(n) Ordner/Datei ein
+Comment[el]=ΕφαÏμογή της επιδιόÏθωσης σε άλλο φάκελο/αÏχείο
+Comment[es]=Aplicar el parche a otra carpeta o archivo
+Comment[et]=Paiga rakendamine teisele kataloogile/failile
+Comment[eu]=Aplikatu adabakia beste karpeta/fitxategi bati
+Comment[fa]=اعمال کژنه به پوشه/پروندۀ دیگر
+Comment[fi]=Toteuta korjaus toiseen kansioon/tiedostoon
+Comment[fr]=Appliquer le correctif sur un autre dossier / fichier
+Comment[ga]=Cuir an paiste i bhfeidhm ar fhillteán/chomhad eile
+Comment[gl]=Aplicar o parche noutro cartafol/ficheiro
+Comment[hu]=A folt alkalmazása másik könyvtárra vagy fájlra
+Comment[is]=Virkja plásturinn á aðra möppu/skrá
+Comment[it]=Applica la correzione a un'altra cartella o file
+Comment[ja]=ä»–ã®ãƒ•ã‚©ãƒ«ãƒ€ã‚„ファイルã¸ãƒ‘ッãƒã‚’é©ç”¨ã—ã¾ã™ã€‚
+Comment[ka]=ბებკის სხვრსáƒáƒ¥áƒáƒ¦áƒáƒšáƒ“ეზე/ფáƒáƒ˜áƒšáƒ–ე გáƒáƒáƒ¥áƒ¢áƒ˜áƒ£áƒ áƒ”ბáƒ
+Comment[kk]=БаÑқа қапшық/файлға жамауды қолдану
+Comment[lt]=Pritaikyti pataisymÄ… kitam aplankui/bylai
+Comment[nb]=Bruk lappen på en annen mappe/fil
+Comment[nds]=Kodeplaster op en anner Orner/Datei anwennen
+Comment[ne]=अनà¥à¤¯ फोलà¥à¤¡à¤°/फाइलमा पà¥à¤¯à¤¾à¤š लागू गरà¥à¤¨à¥à¤¹à¥‹à¤¸à¥
+Comment[nl]=Patch toepassen op een andere map of een ander bestand
+Comment[nn]=Bruk lappen på ei anna mappe/fil
+Comment[pa]=ਹੋਰ ਫੋਲਡਰ/ਫਾਇਲ ਲਈ ਪੈਂਚ ਲਾਗੂ
+Comment[pl]=Nałożenie łaty na inny plik/katalog
+Comment[pt]=Aplicar o 'patch' (actualização) noutra pasta/ficheiro
+Comment[pt_BR]=Aplicar o 'patch' (atualização) noutra pasta/arquivo
+Comment[ru]=Применить заплатку к другой папке или файлу
+Comment[sk]=AplikovaÅ¥ záplatu na iný prieÄinok/súbor
+Comment[sl]=Uveljavi popravek za drugo mapo/datoteko
+Comment[sr]=Примени закрпу на другу фаÑциклу/фајл
+Comment[sr@Latn]=Primeni zakrpu na drugu fasciklu/fajl
+Comment[sv]=Utför en programfix för en annan katalog eller fil
+Comment[tr]=Yamayı diğer dizine/dosyaya uygula
+Comment[uk]=ЗаÑтоÑувати латку до іншої теки файла
+Comment[zh_CN]=将补ä¸åº”用到其它文件夹/文件
+Comment[zh_TW]=套用修補到å¦ä¸€å€‹è³‡æ–™å¤¾/檔案
+
diff --git a/kioslave/svn/svnhelper/kio_svn_helper.cpp b/kioslave/svn/svnhelper/kio_svn_helper.cpp
new file mode 100644
index 00000000..1b66033b
--- /dev/null
+++ b/kioslave/svn/svnhelper/kio_svn_helper.cpp
@@ -0,0 +1,292 @@
+/* This file is part of the KDE project
+ Copyright (c) 2005 Mickael Marchand <marchand@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.
+*/
+
+#include <kcmdlineargs.h>
+#include <klocale.h>
+#include <kapplication.h>
+#include <kurl.h>
+#include <kmessagebox.h>
+#include <dcopclient.h>
+#include <kdebug.h>
+#include <kglobal.h>
+#include <qtimer.h>
+#include <kio/job.h>
+#include <kio/jobclasses.h>
+#include <kio/netaccess.h>
+#include <qpixmap.h>
+#include <kmessagebox.h>
+
+#include "kio_svn_helper.h"
+#include "subversioncheckout.h"
+#include "subversionswitch.h"
+#include "subversiondiff.h"
+#include <kurlrequester.h>
+#include <qspinbox.h>
+#include <kprocess.h>
+#include <ktempfile.h>
+#include <qtextstream.h>
+#include <qtextedit.h>
+#include <kstandarddirs.h>
+#include <qtextbrowser.h>
+#include <qtextcodec.h>
+
+SvnHelper::SvnHelper():KApplication() {
+ KCmdLineArgs *args = KCmdLineArgs::parsedArgs();
+ KWinModule wm ( this );
+ m_id = wm.activeWindow();
+
+ KURL::List list;
+ for ( int i = 0 ; i < args->count() ; i++ )
+ list << args->url(i);
+
+ if (args->isSet("u")) {
+ kdDebug(7128) << "update " << list << endl;
+ KURL servURL = "svn+http://this_is_a_fake_URL_and_this_is_normal/";
+ //FIXME when 1.2 is out (move the loop inside kio_svn's ::update)
+ for ( QValueListConstIterator<KURL> it = list.begin(); it != list.end() ; ++it ) {
+ QByteArray parms;
+ QDataStream s( parms, IO_WriteOnly );
+ int cmd = 2;
+ int rev = -1;
+ kdDebug(7128) << "updating : " << (*it).prettyURL() << endl;
+ s << cmd << *it << rev << QString( "HEAD" );
+ KIO::SimpleJob * job = KIO::special(servURL, parms, true);
+ connect( job, SIGNAL( result( KIO::Job * ) ), this, SLOT( slotResult( KIO::Job * ) ) );
+ KIO::NetAccess::synchronousRun( job, 0 );
+ }
+ } else if (args->isSet("c")) {
+ kdDebug(7128) << "commit " << list << endl;
+ KURL servURL = "svn+http://this_is_a_fake_URL_and_this_is_normal/";
+ QByteArray parms;
+ QDataStream s( parms, IO_WriteOnly );
+ int cmd = 3;
+ s<<cmd;
+ for ( QValueListConstIterator<KURL> it = list.begin(); it != list.end() ; ++it ) {
+ kdDebug(7128) << "commiting : " << (*it).prettyURL() << endl;
+ s << *it;
+ }
+ KIO::SimpleJob * job = KIO::special(servURL, parms, true);
+ connect( job, SIGNAL( result( KIO::Job * ) ), this, SLOT( slotResult( KIO::Job * ) ) );
+ KIO::NetAccess::synchronousRun( job, 0 );
+ } else if (args->isSet("a")) {
+ kdDebug(7128) << "add " << list << endl;
+ KURL servURL = "svn+http://this_is_a_fake_URL_and_this_is_normal/";
+ for ( QValueListConstIterator<KURL> it = list.begin(); it != list.end() ; ++it ) {
+ QByteArray parms;
+ QDataStream s( parms, IO_WriteOnly );
+ int cmd = 6;
+ kdDebug(7128) << "adding : " << (*it).prettyURL() << endl;
+ s << cmd << *it;
+ KIO::SimpleJob * job = KIO::special(servURL, parms, true);
+ connect( job, SIGNAL( result( KIO::Job * ) ), this, SLOT( slotResult( KIO::Job * ) ) );
+ KIO::NetAccess::synchronousRun( job, 0 );
+ }
+ } else if (args->isSet("D")) {
+ kdDebug(7128) << "diff " << list << endl;
+ KURL servURL = "svn+http://this_is_a_fake_URL_and_this_is_normal/";
+ for ( QValueListConstIterator<KURL> it = list.begin(); it != list.end() ; ++it ) {
+ QByteArray parms;
+ QDataStream s( parms, IO_WriteOnly );
+ int cmd = 13;
+ kdDebug(7128) << "diffing : " << (*it).prettyURL() << endl;
+ int rev1=-1;
+ int rev2=-1;
+ QString revkind1 = "BASE";
+ QString revkind2 = "WORKING";
+ s << cmd << *it << *it << rev1 << revkind1 << rev2 << revkind2 << true ;
+ KIO::SimpleJob * job = KIO::special(servURL, parms, true);
+ connect( job, SIGNAL( result( KIO::Job * ) ), this, SLOT( slotResult( KIO::Job * ) ) );
+ KIO::NetAccess::synchronousRun( job, 0 );
+ if ( diffresult.count() > 0 ) {
+ //check kompare is available
+ if ( !KStandardDirs::findExe( "kompare" ).isNull() ) {
+ KTempFile *tmp = new KTempFile;
+ tmp->setAutoDelete(true);
+ QTextStream *stream = tmp->textStream();
+ stream->setCodec( QTextCodec::codecForName( "utf8" ) );
+ for ( QStringList::Iterator it2 = diffresult.begin();it2 != diffresult.end() ; ++it2 ) {
+ ( *stream ) << ( *it2 ) << "\n";
+ }
+ tmp->close();
+ KProcess *p = new KProcess;
+ *p << "kompare" << "-n" << "-o" << tmp->name();
+ p->start();
+ } else { //else do it with message box
+ Subversion_Diff df;
+ for ( QStringList::Iterator it2 = diffresult.begin();it2 != diffresult.end() ; ++it2 ) {
+ df.text->append( *it2 );
+ }
+ QFont f = df.font();
+ f.setFixedPitch( true );
+ df.text->setFont( f );
+ df.exec();
+ }
+ }
+ diffresult.clear();
+ }
+ } else if (args->isSet("d")) {
+ kdDebug(7128) << "delete " << list << endl;
+ KURL servURL = "svn+http://this_is_a_fake_URL_and_this_is_normal/";
+ QByteArray parms;
+ QDataStream s( parms, IO_WriteOnly );
+ int cmd = 7;
+ s<<cmd;
+ for ( QValueListConstIterator<KURL> it = list.begin(); it != list.end() ; ++it ) {
+ kdDebug(7128) << "deleting : " << (*it).prettyURL() << endl;
+ s << *it;
+ }
+ KIO::SimpleJob * job = KIO::special(servURL, parms, true);
+ connect( job, SIGNAL( result( KIO::Job * ) ), this, SLOT( slotResult( KIO::Job * ) ) );
+ KIO::NetAccess::synchronousRun( job, 0 );
+ } else if (args->isSet("s")) {
+ kdDebug(7128) << "switch " << list << endl;
+ SubversionSwitch d;
+ int result = d.exec();
+ if ( result == QDialog::Accepted ) {
+ for ( QValueListConstIterator<KURL> it = list.begin(); it != list.end() ; ++it ) {
+ kdDebug(7128) << "switching : " << (*it).prettyURL() << endl;
+ KURL servURL = "svn+http://this_is_a_fake_URL_and_this_is_normal/";
+ QByteArray parms;
+ QDataStream s( parms, IO_WriteOnly );
+ int revnumber = -1;
+ QString revkind = "HEAD";
+ if ( d.revision->value() != 0 ) {
+ revnumber = d.revision->value();
+ revkind = "";
+ }
+ bool recurse=true;
+ int cmd = 12;
+ s << cmd;
+ s << *it;
+ s << KURL( d.url->url() );
+ s << recurse;
+ s << revnumber;
+ s << revkind;
+ KIO::SimpleJob * job = KIO::special(servURL, parms, true);
+ connect( job, SIGNAL( result( KIO::Job * ) ), this, SLOT( slotResult( KIO::Job * ) ) );
+ KIO::NetAccess::synchronousRun( job, 0 );
+ }
+ }
+ } else if (args->isSet("r")) {
+ kdDebug(7128) << "revert " << list << endl;
+ KURL servURL = "svn+http://this_is_a_fake_URL_and_this_is_normal/";
+ QByteArray parms;
+ QDataStream s( parms, IO_WriteOnly );
+ int cmd = 8;
+ s<<cmd;
+ for ( QValueListConstIterator<KURL> it = list.begin(); it != list.end() ; ++it ) {
+ kdDebug(7128) << "reverting : " << (*it).prettyURL() << endl;
+ s << *it;
+ }
+ KIO::SimpleJob * job = KIO::special(servURL, parms, true);
+ connect( job, SIGNAL( result( KIO::Job * ) ), this, SLOT( slotResult( KIO::Job * ) ) );
+ KIO::NetAccess::synchronousRun( job, 0 );
+ } else if (args->isSet("C")) {
+ kdDebug(7128) << "checkout " << list << endl;
+ SubversionCheckout d;
+ int result = d.exec();
+ if ( result == QDialog::Accepted ) {
+ for ( QValueListConstIterator<KURL> it = list.begin(); it != list.end() ; ++it ) {
+ KURL servURL = "svn+http://this_is_a_fake_URL_and_this_is_normal/";
+ QByteArray parms;
+ QDataStream s( parms, IO_WriteOnly );
+ int cmd = 1;
+ int rev = -1;
+ QString revkind = "HEAD";
+ if ( d.revision->value() != 0 ) {
+ rev = d.revision->value();
+ revkind = "";
+ }
+ s<<cmd;
+ s << KURL( d.url->url() );
+ s << ( *it );
+ s << rev;
+ s << revkind;
+ kdDebug(7128) << "checkouting : " << d.url->url() << " into " << (*it).prettyURL() << " at rev : " << rev << " or " << revkind << endl;
+ KIO::SimpleJob * job = KIO::special(servURL, parms, true);
+ connect( job, SIGNAL( result( KIO::Job * ) ), this, SLOT( slotResult( KIO::Job * ) ) );
+ KIO::NetAccess::synchronousRun( job, 0 );
+ }
+ }
+ } else {
+ KMessageBox::sorry(0, "Sorry, request not recognised. Perhaps not implemented yet?", "Feature Not Implemented");
+ }
+ QTimer::singleShot( 0, this, SLOT( finished() ) );
+}
+
+void SvnHelper::slotResult( KIO::Job* job ) {
+ if ( job->error() )
+ job->showErrorDialog( );
+
+ KIO::MetaData ma = job->metaData();
+ QValueList<QString> keys = ma.keys();
+ qHeapSort( keys );
+ QValueList<QString>::Iterator begin = keys.begin(), end = keys.end(), it;
+
+ QStringList message;
+ for ( it = begin; it != end; ++it ) {
+ // kdDebug(7128) << "METADATA helper : " << *it << ":" << ma[ *it ] << endl;
+ if ( ( *it ).endsWith( "string" ) ) {
+ if ( ma[ *it ].length() > 2 ) {
+ message << ma[ *it ];
+ }
+ }
+ //extra check to retrieve the diff output in case with run a diff command
+ if ( ( *it ).endsWith( "diffresult" ) ) {
+ diffresult << ma[ *it ];
+ }
+ }
+ if ( message.count() > 0 )
+ KMessageBox::informationListWId(m_id, "", message, "Subversion");
+}
+
+void SvnHelper::finished() {
+ kapp->quit();
+}
+
+static KCmdLineOptions options[] = {
+ { "u", I18N_NOOP("Update given URL"), 0 },
+ { "c", I18N_NOOP("Commit given URL"), 0 },
+ { "C", I18N_NOOP("Checkout in given directory"), 0 },
+ { "a", I18N_NOOP("Add given URL to the working copy"), 0 },
+ { "d", I18N_NOOP("Delete given URL from the working copy"), 0 },
+ { "s", I18N_NOOP("Switch given working copy to another branch"), 0 },
+ { "r", I18N_NOOP("Revert local changes"), 0 },
+ { "m", I18N_NOOP("Merge changes between two branches"), 0 },
+ { "D", I18N_NOOP("Show locally made changements with diff"), 0 },
+ {"!+URL", I18N_NOOP("URL to update/commit/add/delete from Subversion"), 0 },
+ KCmdLineLastOption
+};
+
+int main(int argc, char **argv) {
+ KCmdLineArgs::init(argc, argv, "kio_svn_helper", I18N_NOOP("Subversion Helper"), "KDE frontend for SVN", "0.1");
+
+ KCmdLineArgs::addCmdLineOptions( options );
+ KGlobal::locale()->setMainCatalogue("kio_svn");
+ KApplication::addCmdLineOptions();
+
+ if ( KCmdLineArgs::parsedArgs()->count()==0 )
+ KCmdLineArgs::usage();
+ KApplication *app = new SvnHelper();
+
+// app->dcopClient()->attach();
+ app->exec();
+}
+
+#include "kio_svn_helper.moc"
diff --git a/kioslave/svn/svnhelper/kio_svn_helper.h b/kioslave/svn/svnhelper/kio_svn_helper.h
new file mode 100644
index 00000000..519577f2
--- /dev/null
+++ b/kioslave/svn/svnhelper/kio_svn_helper.h
@@ -0,0 +1,41 @@
+/* This file is part of the KDE project
+ Copyright (c) 2005 Mickael Marchand <marchand@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 _KIO_SVN_HELPER_H_
+#define _KIO_SVN_HELPER_H_
+
+#include <kapplication.h>
+#include <kio/job.h>
+#include <kwinmodule.h>
+#include <qstringlist.h>
+
+class SvnHelper:public KApplication {
+ Q_OBJECT
+
+public:
+ SvnHelper();
+private slots:
+ void finished();
+ void slotResult( KIO::Job *);
+private:
+ WId m_id;
+ QStringList diffresult; //for diff commands ;)
+};
+
+#endif
diff --git a/kioslave/svn/svnhelper/subversion.desktop b/kioslave/svn/svnhelper/subversion.desktop
new file mode 100644
index 00000000..00d206d0
--- /dev/null
+++ b/kioslave/svn/svnhelper/subversion.desktop
@@ -0,0 +1,919 @@
+[Desktop Entry]
+ServiceTypes=inode/directory,all/all
+X-KDE-Submenu=Subversion
+X-KDE-Submenu[fa]=زیرنسخه
+X-KDE-Submenu[ne]=उप संसà¥à¤•à¤°à¤£
+X-KDE-Submenu[pa]=ਸਬ-ਵਰਜਨ
+X-KDE-Submenu[pt_BR]=Subversão
+#X-KDE-ShowIfDcopCall=kded ksvnd anyValidWorkingCopy(KURL::List)
+
+#Return type of below is a QStringList with a list of Actions which is appended to the Actions above
+X-KDE-GetActionMenu=kded ksvnd getActionMenu(KURL::List)
+
+[Desktop Action Add]
+Name=Add to Repository
+Name[bg]=ДобавÑне в хранилището
+Name[br]=Ouzhpennañ d'an daveiñ
+Name[ca]=Afegeix al repositori
+Name[cs]=Přidat do repository
+Name[da]=Tilføj til lager
+Name[de]=Zum SVN-Archiv hinzufügen
+Name[el]=ΠÏοσθήκη στο χώÏο αποθήκευσης
+Name[es]=Añadir al repositorio
+Name[et]=Hoidlasse lisamine
+Name[eu]=Gehitu biltegira
+Name[fa]=اÙزودن به مخزن
+Name[fi]=Lisää versionhallintaan
+Name[fr]=Ajouter au référentiel
+Name[ga]=Cuir leis an Stór
+Name[gl]=Engadir ao repositorio
+Name[he]=הוסף למ×גר
+Name[hu]=Hozzáadás az adattárhoz
+Name[is]=Bæta við geymslu
+Name[it]=Aggiungi al deposito
+Name[ja]=リãƒã‚¸ãƒˆãƒªã¸è¿½åŠ 
+Name[ka]=რეპáƒáƒ–იტáƒáƒ áƒ˜áƒ˜áƒ¡áƒ—ვის დმáƒáƒ¢áƒ”ბáƒ
+Name[kk]=ҚоймаÑына қоÑу
+Name[lt]=Įdėti į saugyklą
+Name[nb]=Legg til lager
+Name[nds]=Na't Archiv tofögen
+Name[ne]=भणà¥à¤¡à¤¾à¤°à¤®à¤¾ थपà¥à¤¨à¥à¤¹à¥‹à¤¸à¥
+Name[nl]=Toevoegen aan repository
+Name[nn]=Legg til lager
+Name[pa]=ਰਿਪੋਜ਼ਟਰੀ 'ਚ ਸ਼ਾਮਲ
+Name[pl]=Dodaj do repozytorium
+Name[pt]=Adicionar ao Repositório
+Name[pt_BR]=Adicionar ao Repositório
+Name[ru]=Добавить в хранилище
+Name[sk]=Pridať do archívu
+Name[sl]=Dodaj v skladiÅ¡Äe
+Name[sr]=Додај у Ñкладиште
+Name[sr@Latn]=Dodaj u skladište
+Name[sv]=Lägg till i arkiv
+Name[tr]=Depoya Ekle
+Name[uk]=Додати до Ñховища
+Name[zh_CN]=添加到仓库
+Name[zh_TW]=新增到主目錄
+Icon=svn_add
+Exec=kio_svn_helper -a %U
+
+[Desktop Action Delete]
+Name=Delete From Repository
+Name[bg]=Изтриване от хранилището
+Name[br]=Lemel eus an daveiñ
+Name[ca]=Elimina del repositori
+Name[cs]=Smazat z repository
+Name[da]=Slet fra lager
+Name[de]=Aus dem SVN-Archiv löschen
+Name[el]=ΔιαγÏαφή από το χώÏο αποθήκευσης
+Name[es]=Eliminar del repositorio
+Name[et]=Hoidlast kustutamine
+Name[eu]=Ezabatu biltegitik
+Name[fa]=حذ٠از مخزن
+Name[fi]=Poista versionhallinnasta
+Name[fr]=Supprimer du référentiel
+Name[ga]=Scrios ón Stór
+Name[gl]=Eliminar do repositorio
+Name[he]=מחק ממ×גר
+Name[hu]=Törlés az adattárból
+Name[is]=Eyða frá geymslu
+Name[it]=Elimina dal deposito
+Name[ja]=リãƒã‚¸ãƒˆãƒªã‹ã‚‰å‰Šé™¤
+Name[ka]=რეპáƒáƒ–ირტáƒáƒ áƒ˜áƒ˜áƒ“áƒáƒœ წáƒáƒ¨áƒšáƒ
+Name[kk]=ҚоймаÑынан өшіру
+Name[lt]=Pašalinti iš saugyklos
+Name[nb]=Slett fra lager
+Name[nds]=Ut Archiv wegdoon
+Name[ne]=भणà¥à¤¡à¤¾à¤°à¤¬à¤¾à¤Ÿ मेटà¥à¤¨à¥à¤¹à¥‹à¤¸à¥
+Name[nl]=Verwijderen uit repository
+Name[nn]=Slett frå lager
+Name[pa]=ਰਿਪੋਜ਼ਟਰੀ ਤੋਂ ਹਟਾਓ
+Name[pl]=Usuń z repozytorium
+Name[pt]=Remover do Repositório
+Name[pt_BR]=Remover do Repositório
+Name[ru]=Удалить из хранилища
+Name[sk]=Odstrániť z archívu
+Name[sl]=IzbriÅ¡i iz skladiÅ¡Äa
+Name[sr]=Обриши из Ñкладишта
+Name[sr@Latn]=Obriši iz skladišta
+Name[sv]=Ta bort från arkiv
+Name[tr]=Depodan Sil
+Name[uk]=Видалити зі Ñховища
+Name[zh_CN]=从仓库删除
+Name[zh_TW]=從主目錄刪除
+Icon=svn_remove
+Exec=kio_svn_helper -d %U
+
+[Desktop Action Revert]
+Name=Revert Local Changes
+Name[bg]=Връщане на локалните промени
+Name[ca]=Reverteix els canvis locals
+Name[cs]=Vrátit místní změny
+Name[da]=Vend lokale ændringer om
+Name[de]=Lokale Änderungen zurücknehmen
+Name[el]=ΕπαναφοÏά τοπικών αλλαγών
+Name[es]=Revertir cambios locales
+Name[et]=Kohalike muudatuste tühistamine
+Name[eu]=Leheneratu aldaketa lokalak
+Name[fa]=بازگشت تغییرات محلی
+Name[fi]=Palauta paikalliset muutokset
+Name[fr]=Annuler les modifications locales
+Name[gl]=Anular as modificacións locais
+Name[he]=נקה ×©×™× ×•×™×™× ×ž×§×•×ž×™×™×
+Name[hu]=A helyi módosítások visszavonása
+Name[is]=Afturkalla staðbundnar breytingar
+Name[it]=Annulla i cambiamenti locali
+Name[ja]=ローカルã§ã®å¤‰æ›´ã‚’å…ƒã«æˆ»ã™
+Name[ka]=ლáƒáƒ™áƒáƒšáƒ£áƒ áƒ˜ ცვლილებების შებრუნებáƒ
+Name[kk]=Жергілікті өзгеріÑтерінен қайту
+Name[lt]=Atšaukti vietinius pakeitimus
+Name[nb]=Tilbakestill lokale endringer
+Name[nds]=Lokaal Ännern torüchnehmen
+Name[ne]=उलà¥à¤Ÿà¥‹ सà¥à¤¥à¤¾à¤¨à¥€à¤¯ परिवरà¥à¤¤à¤¨
+Name[nl]=Lokale wijzigingen ongedaan maken
+Name[nn]=Tilbakestill lokale endringar
+Name[pa]=ਉਲਟ ਸਥਾਨਕ ਤਬਦੀਲੀਆਂ
+Name[pl]=Cofnij lokalne zmiany
+Name[pt]=Reverter as Modificações Locais
+Name[pt_BR]=Reverter as Modificações Locais
+Name[ru]=Отменить локальные изменениÑ
+Name[sk]=Vrátiť lokálne zmeny
+Name[sl]=Povrni krajevne spremembe
+Name[sr]=Одбаци локалне измене
+Name[sr@Latn]=Odbaci lokalne izmene
+Name[sv]=Återställ lokal ändring
+Name[tr]=Yerel Değişiklikleri Ters Çevir
+Name[uk]=Повернути локальні зміни
+Name[zh_CN]=æ¢å¤æœ¬åœ°æ›´æ”¹
+Name[zh_TW]=回復本地端變更
+Icon=undo
+Exec=kio_svn_helper -r %U
+Comment=Remove any changes made locally. Warning - this cannot be undone.
+Comment[bg]=Премахване на направените локални промени. Предупреждение - данните ще Ñе загубÑÑ‚ безвъзвратно.
+Comment[ca]=Elimina qualsevol canvi local. Avís: No es pot desfer.
+Comment[cs]=Odstraní změny provedené lokálně; nelze vrátit, pozor.
+Comment[da]=Fjern alle ændringer der er lavet lokalt. Advarsel - dette kan ikke fortrydes.
+Comment[de]=Nimmt alle lokal durchgeführten Änderungen zurück. Warnung: Dieser Vorgang kann nicht rückgängig gemacht werden.
+Comment[el]=ΑφαίÏεση κάθε Ï„Ïοποποίησης που έγινε τοπικά. ΠÏοειδοποίηση ότι αυτό δε μποÏεί να αναιÏεθεί.
+Comment[es]=Eliminar cualquier cambio local. Atención: esto no se puede deshacer.
+Comment[et]=Eemaldab kõik kohalikud muudatused. Hoiatus: seda ei saa tagasi võtta.
+Comment[eu]=Kendu lokalki egindako aldaketak. Abisua: ekintza hau ezin da desegin.
+Comment[fa]=حذ٠همۀ تغییرات ایجادشدۀ محلی. اخطار - این نمی‌تواند انجام نشود.
+Comment[fi]=Poista kaikki paikallisesti tehdyt muutokset. Varoitus - muutosta ei voi perua.
+Comment[fr]=Annuler toutes les modifications effectuées localement. Attention, cela ne peut pas être annulé.
+Comment[gl]=Borra as alteracións feitas a nível local. Atención - isto non pode ser anulado.
+Comment[hu]=A helyi módosítások visszavonása. Ez a művelet nem vonható vissza!
+Comment[is]=Fjarlægja allar breytingar sem voru gerðar hér. Athugið - það er ekki hægt að afturkalla þetta.
+Comment[it]=Rimuovi ogni cambiamento fatto localmente. Attenzione: non si può tornare indietro.
+Comment[ja]=ローカルã§è¡Œã‚ã‚ŒãŸå¤‰æ›´ã‚’削除ã—ã¾ã™ã€‚注æ„: ã“ã®æ“作ã¯å…ƒã«æˆ»ã›ã¾ã›ã‚“。
+Comment[ka]=ნებისმიერი ლáƒáƒ™áƒáƒšáƒ£áƒ áƒáƒ“ გáƒáƒ™áƒ”თებული ცვლილებების წáƒáƒ¨áƒšáƒ. გáƒáƒ¤áƒ áƒ—ხილებრ- áƒáƒ›áƒ˜áƒ¡ უკუქცევრშეუძლებელიáƒ.
+Comment[kk]=Жергілікті (Ñғни тапÑырылмаған) өзгеріÑтерден айну. Ðбайлаңыз - бұл амалдан қайта алмайÑыз.
+Comment[lt]=Panaikinti visus vietoje atliktus pakeitimus. Perspėjimas: to nebebus galima atšaukti.
+Comment[nb]=Fjern alle endringer som er gjort lokalt. MERK – dette kan ikke angres.
+Comment[nds]=All lokaal Ännern wegdoon. Wohrschoen - Dit lett sik nich torüchnehmen.
+Comment[ne]=कà¥à¤¨à¥ˆ पनि सà¥à¤¥à¤¾à¤¨à¥€à¤¯ परिवरà¥à¤¤à¤¨ हटाउनà¥à¤¹à¥‹à¤¸à¥ । चेतावनी - यसलाई पूरà¥à¤µà¤¾à¤µà¤¸à¥à¤¥à¤¾à¤®à¤¾ फरà¥à¤•à¤¾à¤‰à¤¨ सकिने छैन ।
+Comment[nl]=Lokale wijzigingen ongedaan maken. Let op: dit kan niet teruggedraaid worden.
+Comment[nn]=Fjern alle endringar som er gjorde lokalt. MERK – dette kan ikkje angrast.
+Comment[pl]=Usuwa wszystkie zmiany dokonane lokalnie. Uwaga - tej operacji nie można cofnąć.
+Comment[pt]=Remover as alterações que tenham sido feitas a nível local. Atenção - isto não pode ser anulado.
+Comment[pt_BR]=Remover as alterações que tenham sido feitas localmente. Atenção - isto não pode ser desfeito.
+Comment[ru]=Отменить вÑе не опубликованные изменениÑ. Эта Ð¾Ð¿ÐµÑ€Ð°Ñ†Ð¸Ñ Ð½Ðµ подлежит отмене.
+Comment[sk]=Odstráni lokálne zmeny. Upozornenie - toto sa nedá už vrátiť.
+Comment[sl]=Odstrani vse spremembe, opravljene krajevno. Opozorilo - tega ni mogoÄe razveljaviti.
+Comment[sr]=Уклони Ñве локално направљене измене. Упозорење: ово Ñе не може опозвати.
+Comment[sr@Latn]=Ukloni sve lokalno napravljene izmene. Upozorenje: ovo se ne može opozvati.
+Comment[sv]=Tar bort alla ändringar som gjorts lokalt. Varning: detta kan inte ångras.
+Comment[tr]=Yerel olarak yapılan değişiklikleri kaldır. Dikkat - bu işlem geri alınamaz.
+Comment[uk]=Вилучити вÑÑ– зміни, Ñкі було зроблено локально. ÐŸÐ¾Ð¿ÐµÑ€ÐµÐ´Ð¶ÐµÐ½Ð½Ñ - зміни буде вилучено назавжди.
+Comment[zh_CN]=删除本地进行的任何更改。警告 - æ­¤æ“作无法撤消。
+Comment[zh_TW]=移除任何已åšçš„變更。警告:無法å†å¾©åŽŸã€‚
+
+[Desktop Action Rename]
+Name=Rename...
+Name[bg]=Преименуване...
+Name[br]=Adenvel ...
+Name[ca]=Reanomena...
+Name[cs]=Přejmenovat...
+Name[cy]=Ail-enwi...
+Name[da]=Omdøb...
+Name[de]=Umbenennen ...
+Name[el]=Μετονομασία...
+Name[eo]=Alinomigi...
+Name[es]=Cambiar nombre...
+Name[et]=Ãœmbernimetamine...
+Name[eu]=Berrizendatu...
+Name[fa]=تغییر نام...
+Name[fi]=Nimeä uudelleen...
+Name[fr]=Renommer...
+Name[ga]=Athainmnigh...
+Name[gl]=Mudar o nome...
+Name[he]=שנה ש×...
+Name[hu]=Ãtnevezés...
+Name[is]=Endurnefna...
+Name[it]=Rinomina...
+Name[ja]=åå‰å¤‰æ›´...
+Name[ka]=სáƒáƒ®áƒ”ლის გáƒáƒ“áƒáƒ áƒ¥áƒ›áƒ”ვáƒ...
+Name[kk]=Қайта атау...
+Name[lt]=Pervadinti...
+Name[nb]=Endre navn …
+Name[nds]=Ümnömen...
+Name[ne]=पà¥à¤¨: नामकरण गरà¥à¤¨à¥à¤¹à¥‹à¤¸à¥...
+Name[nl]=Hernoemen...
+Name[nn]=Endra namn …
+Name[pa]=ਨਾਂ-ਤਬਦੀਲ...
+Name[pl]=Zmień nazwę...
+Name[pt]=Mudar o Nome...
+Name[pt_BR]=Renomear...
+Name[ru]=Переименовать...
+Name[sk]=Premenovať...
+Name[sl]=Preimenuj ...
+Name[sr]=Преименуј...
+Name[sr@Latn]=Preimenuj...
+Name[sv]=Byt namn...
+Name[tr]=Yeniden Adlandır...
+Name[uk]=Перейменувати...
+Name[zh_CN]=é‡å‘½å...
+Name[zh_TW]=é‡æ–°å‘½å...
+Icon=pencil
+Exec=kio_svn_helper -r %U
+Comment=Rename a file locally and in the repository. Use this rather than adding and deleting to rename a file.
+Comment[bg]=Преименуване на файл локално и в хранилището. За предпочитане е да използвате този метод вмеÑто изтриване и добавÑне.
+Comment[ca]=Reanomena un fitxer localment i en el repositori. Use-ho en comptes d'afegir i eliminar per a reanomenar un fitxer.
+Comment[cs]=Přejmenovat soubor lokálně a v repository. Použijte raději než přidání a smazání souboru k docílení jeho přejmenování.
+Comment[da]=Omdøb en fil lokalt og i lageret. Brug dette i stedet for at tilføje og slette for at omdøbe en fil.
+Comment[de]=Benennt eine Datei lokal und im SVN-Archiv um. Verwenden Sie besser diese Funktion zum Umbenennen einer Datei als Hinzufügen und Löschen.
+Comment[el]=Μετονομασία ενός αÏχείου τοπικά και στο χώÏο αποθήκευσης. ΧÏησιμοποιήστε αυτό αντί της Ï€Ïοσθήκης και αφαίÏεσης για τη μετονομασία ενός αÏχείου.
+Comment[es]=Cambiar el nombre de un archivo localmente y en el repositorio. Use esto en lugar de añadir y eliminar para cambiar el nombre de un archivo.
+Comment[et]=Faili ümbernimetamine nii kohalikult kui hoidlas. See on eelistatud viis faili ümbernimetamisel lisamise ja kustutamise asemel.
+Comment[eu]=Berrizendatu fitxategi bat lokalki eta biltegian. Erabili hau fitxategia ezabatu eta berriro gehitu ordez.
+Comment[fa]=تغییر نام پروندۀ محلی Ùˆ در مخزن. به جای اÙزودن Ùˆ حذÙØŒ برای تغییر نام پرونده از این استÙاده کنید.
+Comment[fi]=Nimeä uudelleen paikallinen ja versionhallinnassa oleva tiedosto. Nimeä tiedosto uudelleen mieluummin näin kuin lisäämällä ja poistamalla.
+Comment[fr]=Renommer un fichier localement et dans le référentiel. Utilisez cette option pour renommer un fichier, au lieu de le supprimer puis l'ajouter sous le nouveau nom.
+Comment[gl]=Muda o nome dun ficheiro tanto localmente como no repositorio. Use isto en vez de engadir e eliminar o ficheiro para mudar o nome.
+Comment[hu]=Fájl átnevezése helyben és az adattárban. Ezt érdemes használni hozzáadás és törlés helyett.
+Comment[is]=Endurnefna skrá hér og í geymslunni. Notist heldur við þetta í stað þess að bæta við og eyða til að endurnefna skrá.
+Comment[it]=Rinomina un file localmente e nel deposito. Usa questo invece di aggiungere e rimuovere un file per rinominarlo.
+Comment[ja]=ローカルã¨ãƒªãƒã‚¸ãƒˆãƒªã®ãƒ•ã‚¡ã‚¤ãƒ«ã‚’改åã—ã¾ã™ã€‚åå‰ã®å¤‰æ›´ã®éš›ã«è¿½åŠ ã¨å‰Šé™¤ã‚’ã—ãªã„ã§ã€ã“ã®æ–¹æ³•ã‚’使用ã—ã¦ãã ã•ã„。
+Comment[ka]=ფáƒáƒ˜áƒšáƒ˜áƒ¡ სáƒáƒ®áƒ”ლის გáƒáƒ“áƒáƒ áƒ¥áƒ›áƒ”ვრლáƒáƒ™áƒáƒšáƒ£áƒ áƒáƒ“ დრრეპáƒáƒ–იტáƒáƒ áƒ˜áƒáƒ¡áƒ˜. დáƒáƒ›áƒáƒ¢áƒ”ბის დრწáƒáƒ¨áƒšáƒ˜áƒ¡ ნáƒáƒªáƒ•áƒšáƒáƒ“ ეს გáƒáƒ›áƒáƒ˜áƒ§áƒ”ნეთ.
+Comment[kk]=Файлдың жергілікті де, қоймаÑындағы да атауын өзгерту. Өшіріп қайта қоÑудан гөрі оÑыны қолданған дұрыÑ.
+Comment[lt]=Pervadinti bylą vietoje ir saugykloje. Naudokite šią parinktį užuot ištrindami ir įrašydami nauju vardu norimą pervadinti bylą.
+Comment[nb]=Gi en fil nytt navn lokalt og i arkivet. Bruk dette heller enn å slette og legge inn på nytt for å endre navn på en fil.
+Comment[nds]=En Datei lokaal un in't Archiv ümnömen. Bruuk beter dit, as "Tofögen" un "Wegdoon".
+Comment[ne]=फाइलालाई सà¥à¤¥à¤¾à¤¨à¥€à¤¯ रà¥à¤ªà¤®à¤¾ र भणà¥à¤¡à¤¾à¤°à¤®à¤¾ पà¥à¤¨: नामकरण गरà¥à¤¨à¥à¤¹à¥‹à¤¸à¥ । फाइललाई पà¥à¤¨: नामकरण गरà¥à¤¨ थपà¥à¤¨à¥‡ र मेटà¥à¤¨à¥‡ भनà¥à¤¦à¤¾ यसलाई पà¥à¤°à¤¯à¥‹à¤— गरà¥à¤¨à¥à¤¹à¥‹à¤¸à¥ ।
+Comment[nl]=Hernoem een bestand lokaal en in de repository. Gebruik dit bij voorkeur boven het verwijderen van een bestand en het toevoegen onder een andere naam.
+Comment[nn]=Gi ei fil nytt namn lokalt og i arkivet. Bruk dette heller enn å sletta og leggja inn på nytt for å endra namn på ei fil.
+Comment[pl]=Zmienia nazwę pliku lokalnie i w repozytorium. Należy tego używać zamiast dodawania i usuwania pliku.
+Comment[pt]=Muda o nome de um ficheiro a nível local e no repositório. Use isto em vez de adicionar e remover o ficheiro para mudar o nome.
+Comment[pt_BR]=Muda o nome de um arquivo localmente e no repositório. Use isto em vez de adicionar e remover o arquivo para mudar o nome.
+Comment[ru]=Переименовать файл Ñ Ð¾Ñ‚Ñ€Ð°Ð¶ÐµÐ½Ð¸ÐµÐ¼ Ñтого в хранилище.
+Comment[sk]=Premenuje súbor lokálne aj v archíve. Použite radšej toto ako pridanie a odstránenie súboru.
+Comment[sl]=Preimenuj datoteko krajevno in v skladiÅ¡Äu. Uporabite to namesto brisanja in dodajanja datoteke.
+Comment[sr]=Преименуј фајл локално и у Ñкладишту. КориÑтите ово умеÑто трика Ñа додавањем и бриÑањем фајла.
+Comment[sr@Latn]=Preimenuj fajl lokalno i u skladištu. Koristite ovo umesto trika sa dodavanjem i brisanjem fajla.
+Comment[sv]=Byt namn på en fil lokalt och i arkivet. Använd detta istället för att lägga till och ta bort för att byta namn på en fil.
+Comment[uk]=Перейменувати файл локально Ñ– в Ñховищі. Вживайте заміÑÑ‚ÑŒ Ð´Ð¾Ð´Ð°Ð²Ð°Ð½Ð½Ñ Ñ– Ð²Ð¸Ð´Ð°Ð»ÐµÐ½Ð½Ñ Ñ„Ð°Ð¹Ð»Ð°, щоб його перейменувати.
+Comment[zh_CN]=在本地和仓库中é‡å‘½å文件。使用此功能æ¥å–代对文件的添加和删除。
+Comment[zh_TW]=在本地端與主目錄中é‡æ–°å‘½å檔案。ä¸å¿…先新增å†åˆªé™¤æª”案。
+
+[Desktop Action Import]
+Name=Import Repository
+Name[bg]=Импортиране на директориÑ
+Name[br]=Enporzh an daveiñ
+Name[ca]=Importa repositori
+Name[cs]=Importovat repository
+Name[da]=Importér lager
+Name[de]=SVN-Archiv importieren
+Name[el]=Εισαγωγή χώÏου αποθήκευσης
+Name[eo]=Importi Deponejon
+Name[es]=Importar repositorio
+Name[et]=Hoidla import
+Name[eu]=Inportatu biltegia
+Name[fa]=مخزن واردات
+Name[fi]=Tuo versionhallinta
+Name[fr]=Importer dans un référentiel
+Name[ga]=Iompórtáil Stór
+Name[gl]=Importar un repositorio
+Name[hu]=Adattár importálása
+Name[is]=Flytja inn geymslu
+Name[it]=Importa deposito
+Name[ja]=リãƒã‚¸ãƒˆãƒªã®ã‚¤ãƒ³ãƒãƒ¼ãƒˆ
+Name[ka]=რეპáƒáƒ–იტáƒáƒ áƒ˜áƒ˜áƒ¡ იმპáƒáƒ áƒ¢áƒ˜
+Name[kk]=ҚоймаÑына импорттау
+Name[lt]=Importuoti saugyklÄ…
+Name[nb]=Importer lager
+Name[nds]=Archiv importeren
+Name[ne]=आयात भणà¥à¤¡à¤¾à¤°
+Name[nl]=Repository importeren
+Name[nn]=Importer lager
+Name[pa]=ਰਿਪੋਜ਼ਟਰੀ ਅਯਾਤ
+Name[pl]=Importuj repozytorium
+Name[pt]=Importar um Repositório
+Name[pt_BR]=Importar um Repositório
+Name[ru]=Импортировать в хранилище
+Name[sk]=Importovať archív
+Name[sl]=Uvozi skladiÅ¡Äe
+Name[sr]=Увези Ñкладиште
+Name[sr@Latn]=Uvezi skladište
+Name[sv]=Importera arkiv
+Name[tr]=Depoyu İçe Aktar
+Name[uk]=Імпортувати Ñховище
+Name[zh_CN]=导入仓库
+Name[zh_TW]=匯入主目錄
+Icon=svn_import
+Exec=kio_svn_helper -i %U
+Comment=Put folder into an existing repository to put it under revision control.
+Comment[bg]=ПоÑтавÑне на Ð´Ð¸Ñ€ÐµÐºÑ‚Ð¾Ñ€Ð¸Ñ Ð² ÑъщеÑтвуващо хранилище.
+Comment[ca]=Situa la carpeta en un repositori existent per a posar-la sota el control de revisions.
+Comment[cs]=Zařadit složku do repository a správy verzí
+Comment[da]=Put mappe ind i et eksisterende lager for at få den ind under revisionskontrol.
+Comment[de]=Schiebt den Ordner in ein existierendes SVN-Archiv, um ihn in die Versionsverwaltung aufzunehmen.
+Comment[el]=Εισαγωγή φακέλου σε έναν υπάÏχον χώÏο αποθήκευσης για τον έλεγχο εκδόσεων.
+Comment[es]=Situar la carpeta en un repositorio existente para ponerla bajo control de revisión.
+Comment[et]=Kataloogi lisamine olemasolevasse versioonikontrolli süsteemi hoidlasse.
+Comment[eu]=Jarri karpeta biltegi batean errebisio kontrolpean edukitzeko.
+Comment[fa]=گذاشتن پوشه در مخزن موجود جهت قراردادن آن تحت کنترل بازبینی.
+Comment[fi]=Laita kansio versionhallintaan viemällä se olemassa olevaan versionhallintavarastoon.
+Comment[fr]=Place le dossier dans un référentiel existant afin de le mettre sous contrôle de version.
+Comment[gl]=Pon o cartafol nun repositorio existente para pólo baixo control de versións.
+Comment[hu]=Könyvtár felvétele a verziókövető rendszer felügyelete alá.
+Comment[is]=Setja möppu í geymslu sem finnst fyrir til að setja hana undir breytingarstjórn.
+Comment[it]=Metti una cartella in un deposito esistente per metterla sotto controllo di revisione.
+Comment[ja]=既存ã®ãƒªãƒã‚¸ãƒˆãƒªã«ãƒ•ã‚©ãƒ«ãƒ€ã‚’ç½®ãã€ãƒªãƒ“ジョン管ç†ã®å¯¾è±¡ã¨ã—ã¾ã™ã€‚
+Comment[ka]=რევიზიის კáƒáƒœáƒ¢áƒ áƒáƒšáƒ˜áƒ¡áƒ—ვის ჩáƒáƒ“ეთ სáƒáƒ¥áƒáƒ¦áƒáƒšáƒ“ე áƒáƒ áƒ¡áƒ”ბულ რეპáƒáƒ–იტáƒáƒ áƒ˜áƒáƒ¨áƒ˜.
+Comment[kk]=Қапшықты қоймаÑына, нұÑқалар еÑебін қадағалап, көшіру.
+Comment[lt]=Ä®dÄ—ti aplankÄ… į egzistuojanÄiÄ… saugyklÄ… ir įjungti jį į keitimų sekimo sistemÄ….
+Comment[nb]=Legg mappe inn i et eksisterende arkiv slik at det får revisjonskontroll.
+Comment[nds]=Verschufft en Orner na en vörhannen Archiv, so dat he ünner Verschoonkuntrull kummt
+Comment[ne]=फोलà¥à¤¡à¤²à¤¾à¤ˆ पà¥à¤¨à¤°à¤¾à¤µà¥‹à¤²à¤•à¤¨ नियनà¥à¤¤à¥à¤°à¤£ गरà¥à¤¨ अवसà¥à¤¥à¤¿à¤¤ भणà¥à¤¡à¤¾à¤°à¤®à¤¾ राखà¥à¤¨à¥à¤¹à¥‹à¤¸à¥ ।
+Comment[nl]=Plaats een map in een bestaande repository zodat het onder het versiebeheer system valt.
+Comment[nn]=Legg ei mappe inn i eit eksisterande lager slik at det får revisjonskontroll.
+Comment[pl]=Dodaje katalog do istniejącego repozytorium, aby umieścić go w systemie kontrolowania wersji.
+Comment[pt]=Coloca a pasta num repositório existente para a colocar sob controlo de versões.
+Comment[pt_BR]=Coloca a pasta num repositório existente para colocá-lo sob controle de versões.
+Comment[ru]=ПомеÑтить папку в ÑущеÑтвующее хранилище Ð´Ð»Ñ Ð´Ð¾Ð±Ð°Ð²Ð»ÐµÐ½Ð¸Ñ Ñтой папки в ÑиÑтему ÐºÐ¾Ð½Ñ‚Ñ€Ð¾Ð»Ñ Ñ€ÐµÐ²Ð¸Ð·Ð¸Ð¹
+Comment[sk]=Vloží prieÄinok do existujúceho archívu ako novú revíziu.
+Comment[sl]=Uvozi mapo v obstojeÄe skladiÅ¡Äe. Mapa tako postane del revizijskega nadzora.
+Comment[sr]=Стави фаÑциклу у поÑтојеће Ñкладиште, ради Ñтављања под контролу ревизија.
+Comment[sr@Latn]=Stavi fasciklu u postojeće skladište, radi stavljanja pod kontrolu revizija.
+Comment[sv]=Lägg till katalog i ett befintligt arkiv för att få den under versionskontroll
+Comment[tr]=Dizini başka bie alt düzeltme controlünde var olan bir depo içine koy.
+Comment[uk]=Ð’Ñтавити теку в Ñ–Ñнуюче Ñховище, щоб уможливити Ð´Ð»Ñ Ð½ÐµÑ— ÐºÐµÑ€ÑƒÐ²Ð°Ð½Ð½Ñ Ð²ÐµÑ€ÑÑ–Ñми.
+Comment[zh_CN]=将文件夹放入现有仓库,以便让其å—到版本控制。
+Comment[zh_TW]=將資料夾放進ç¾å­˜çš„主目錄,並開始åšç‰ˆæœ¬æŽ§åˆ¶ã€‚
+
+[Desktop Action Checkout]
+Name=Checkout From Repository...
+Name[bg]=ИзтеглÑне от хранилището...
+Name[ca]=Obtenir del repositori...
+Name[cs]=Získat z repository...
+Name[da]=Tjek ud fra lager...
+Name[de]=Aus SVN-Archiv herausholen ...
+Name[el]=Έλεγχος εξόδου από το χώÏο αποθήκευσης...
+Name[eo]=Ekpreni el Deponejo...
+Name[es]=Obtener del repositorio...
+Name[et]=Hoidla väljavõte...
+Name[eu]=Deskargatu biltegitik...
+Name[fa]=وارسی از مخزن...
+Name[fi]=Nouda versionhallinnasta...
+Name[fr]=Extraire depuis un référentiel...
+Name[gl]=Obter do repositorio...
+Name[hu]=Kimásolás az adattárból...
+Name[is]=Ná í frá geymslu...
+Name[it]=Ritira dal deposito...
+Name[ja]=リãƒã‚¸ãƒˆãƒªã‹ã‚‰ãƒã‚§ãƒƒã‚¯ã‚¢ã‚¦ãƒˆ...
+Name[ka]=რეპáƒáƒ–იტáƒáƒ áƒ˜áƒ˜áƒ“áƒáƒœ áƒáƒ›áƒáƒœáƒ˜áƒ¨áƒ•áƒœáƒ...
+Name[kk]=ҚоймаÑынан көшіріп алу...
+Name[lt]=Atsisiųsti iš saugyklos...
+Name[nb]=Sjekk ut fra lager …
+Name[nds]=Ut Archiv daalladen...
+Name[ne]=भणà¥à¤¡à¤¾à¤°à¤¬à¤¾à¤Ÿ जाà¤à¤š...
+Name[nl]=Repository uitchecken...
+Name[nn]=Sjekk ut frå lager …
+Name[pa]=ਰਿਪੋਜ਼ਟਰੀ ਤੋਂ ਚੈਕਆਉਟ...
+Name[pl]=Pobierz z repozytorium...
+Name[pt]=Obter do Repositório...
+Name[pt_BR]=Obter do Repositório...
+Name[ru]=Загрузить из хранилища...
+Name[sk]=Získať z archívu...
+Name[sl]=Prevzemi iz skladiÅ¡Äa ...
+Name[sr]=Довуци из Ñкладишта...
+Name[sr@Latn]=Dovuci iz skladišta...
+Name[sv]=Checka ut från ett arkiv...
+Name[tr]=Depodan Kontrol Et...
+Name[uk]=ВзÑти зі Ñховища...
+Name[zh_CN]=从仓库中检出...
+Name[zh_TW]=從主目錄å–出...
+Icon=svn_checkout
+Exec=kio_svn_helper -C %U
+Comment=Checkout out files from an existing repository into this folder.
+Comment[bg]=ИзтеглÑне на файлове от хранилището в текущата директориÑ.
+Comment[ca]=Obté fitxers des d'un repositori existent cap aquesta carpeta.
+Comment[cs]=Získat soubory z existující repository do této složky.
+Comment[da]=Tjek filer ud fra et eksisterende lager til denne mappe.
+Comment[de]=Legt Dateien aus einem existierenden SVN-Archiv in diesem Ordner ab.
+Comment[el]=΄Έλεγχος εξόδου των αÏχείων από έναν υπάÏχον χώÏο αποθήκευσης σε αυτόν τον φάκελο.
+Comment[es]=Descargar archivos de un repositorio existente en esta carpeta.
+Comment[et]=Olemasoleva hoidla failide väljavõte sellesse kataloogi.
+Comment[eu]=Deskargatu fitxategiak biltegi batetik karpeta honetara.
+Comment[fa]=وارسی پرونده‌های بیرونی از مخزن موجود در این پوشه
+Comment[fi]=Nouda tiedostot olemassa olevasta versionhallinnasta tähän kansioon.
+Comment[fr]=Extraire dans ce dossier les fichiers d'un référentiel existant
+Comment[gl]=Obtén todos os ficheiros dun repositorio existente para este cartafol.
+Comment[hu]=Fájlok kimásolása az adattárból ebbe a könyvtárba.
+Comment[is]=Ná í skrár frá geymslu og setja í þessa möppu.
+Comment[it]=Ritira i file da un deposito esistente in questa cartella.
+Comment[ja]=既存ã®ãƒªãƒã‚¸ãƒˆãƒªã‹ã‚‰ã€ã“ã®ãƒ‡ã‚£ãƒ¬ã‚¯ãƒˆãƒªã¸ãƒ•ã‚¡ã‚¤ãƒ«ã‚’ãƒã‚§ãƒƒã‚¯ã‚¢ã‚¦ãƒˆã—ã¾ã™ã€‚
+Comment[ka]=áƒáƒ áƒ¡áƒ”ბული რეპáƒáƒ–იტáƒáƒ áƒ˜áƒ˜áƒ“áƒáƒœ ფáƒáƒ˜áƒšáƒ”ბი áƒáƒ› სáƒáƒ¥áƒáƒ¦áƒáƒšáƒ“ეში áƒáƒ›áƒáƒœáƒ˜áƒ¨áƒœáƒ”თ.
+Comment[kk]=Файлдарды қоймаÑынан көрÑетілген қапшыққа көшіріп алу.
+Comment[lt]=Atsisiųsti bylas iÅ¡ egzistuojanÄios saugyklos į šį aplankÄ….
+Comment[nb]=Sjekk ut filer fra et arkiv inn i denne mappa
+Comment[nds]=Laadt Dateien ut en vörhannen Archiv na dissen Orner daal.
+Comment[ne]=यो फोलà¥à¤¡à¤°à¤®à¤¾ अवसà¥à¤¥à¤¿à¤¤ भणà¥à¤¡à¤¾à¤° बाहिरका फाइललाई जाà¤à¤š गरà¥à¤¨à¥à¤¹à¥‹à¤¸à¥ ।
+Comment[nl]=Bestanden van een bestaande repository uitchecken in deze map.
+Comment[nn]=Sjekk ut filer frå eit arkiv inn i denne mappa.
+Comment[pl]=Pobranie plików z istniejącego repozytorium do tego katalogu.
+Comment[pt]=Obtém todos os ficheiros de um repositório existente para esta pasta.
+Comment[pt_BR]=Obtém todos os arquivos de um repositório existente para esta pasta.
+Comment[ru]=Загрузить файлы из ÑущеÑтвующего хранилища в указанную папку
+Comment[sk]=Získa súbory z existujúceho archívu do tohoto prieÄinku.
+Comment[sl]=Prevzemi datoteke iz obstojeÄega skladiÅ¡Äa v to mapo.
+Comment[sr]=Довуци фајлове из поÑтојећег Ñкладишта у ову фаÑциклу.
+Comment[sr@Latn]=Dovuci fajlove iz postojećeg skladišta u ovu fasciklu.
+Comment[sv]=Checka ut filer från ett befintligt arkiv till katalogen.
+Comment[tr]=Bu dizinde var olan bir depodan hatalı dosyaları kontrol et.
+Comment[uk]=ВзÑти файли з Ñ–Ñнуючого Ñховища Ñ– поклаÑти в цю теку.
+Comment[zh_CN]=从已有仓库中检出文件并存放至此文件夹。
+Comment[zh_TW]=從ç¾å­˜çš„主目錄å–出檔案到此資料夾。
+
+[Desktop Action Switch]
+Name=Switch...
+Name[bg]=Превключване...
+Name[br]=Gwintañ ...
+Name[ca]=Canvia...
+Name[cs]=Přepnout...
+Name[de]=Wechseln (switch)
+Name[el]=Εναλλαγή...
+Name[eo]=Åœalti...
+Name[es]=Cambiar...
+Name[et]=Lülitumine...
+Name[eu]=Aldatu...
+Name[fa]=سودهی...
+Name[fi]=Vaihda...
+Name[fr]=Basculer...
+Name[gl]=Mudar...
+Name[he]=החלף...
+Name[hu]=Váltás...
+Name[is]=Skipta...
+Name[it]=Passa...
+Name[ja]=スイッãƒ...
+Name[ka]=გáƒáƒ“რთვáƒ...
+Name[kk]=ÐуыÑу...
+Name[lt]=Perjungti...
+Name[nb]=Bytt …
+Name[nds]=Telg wesseln...
+Name[ne]=सà¥à¤µà¤¿à¤š...
+Name[nl]=Omzetten (switch)...
+Name[nn]=Byt …
+Name[pa]=ਤਬਦੀਲ...
+Name[pl]=Przełącz...
+Name[pt]=Mudar...
+Name[pt_BR]=Mudar...
+Name[ru]=Сменить Ð°Ð´Ñ€ÐµÑ Ñ…Ñ€Ð°Ð½Ð¸Ð»Ð¸Ñ‰Ð°...
+Name[sk]=Vymeniť...
+Name[sl]=Preklopi ...
+Name[sr]=Пребаци...
+Name[sr@Latn]=Prebaci...
+Name[sv]=Byt...
+Name[tr]=DeÄŸiÅŸtir...
+Name[uk]=Перемкнути...
+Name[zh_CN]=切æ¢...
+Name[zh_TW]=切æ›...
+Icon=svn_switch
+Comment=Switch given working copy to another branch
+Comment[bg]=Превключване на работното копие към друго разклонение.
+Comment[ca]=Canvia una còpia de treball indicada a una altra branca
+Comment[cs]=Přepnout danou pracovní kopii na jinou větev
+Comment[da]=Skift given arbejdskopi til en anden gren.
+Comment[de]=Wechselt von der vorhandenen Arbeitskopie zu einer anderen Verzweigung (branch).
+Comment[el]=Εναλλαγή του δοσμένου αντιγÏάφου εÏγασίας σε άλλον κλάδο
+Comment[es]=Cambiar una determinada copia de trabajo a otra rama
+Comment[et]=Antud töökoopia lülitamine teise harru
+Comment[eu]=aldatu laneko kopia bat beste adar batekin
+Comment[fa]=سودهی رونوشت کار داده‌شده به شاخۀ دیگر
+Comment[fi]=Vaihda annettu työkopio toiseen haaraan
+Comment[fr]=Basculer la copie de travail vers une autre branche
+Comment[gl]=Muda a copia de traballo actual para outra ramificación
+Comment[hu]=A munkamásolat átváltása másik ágra
+Comment[is]=Skipta núverandi vinnuafriti yfir í aðra grein
+Comment[it]=Passa la copia di lavoro a un altro ramo
+Comment[ja]=作業中ã®ã‚³ãƒ”ーを他ã®ãƒ–ランãƒã¸åˆ‡ã‚Šæ›ãˆã¾ã™ã€‚
+Comment[ka]=მიმდინáƒáƒ áƒ” სáƒáƒ›áƒ£áƒ¨áƒáƒ áƒáƒ¡áƒšáƒ˜áƒ¡ სხვრტáƒáƒ¢áƒ–ე გáƒáƒ™áƒ”თებáƒ
+Comment[kk]=Ð–Ò±Ð¼Ñ‹Ñ ÐºÓ©ÑˆÑ–Ñ€Ð¼ÐµÐ½Ñ– жобаның баÑқа ÑалаÑына (Ñғни қоймаÑына) ауыÑтыру
+Comment[lt]=Perjungti esamą vietinį saugyklos aplanką į kitą atšaką
+Comment[nb]=Byt arbeidskopien til en annen gren
+Comment[nds]=Arbeitkopie na en annern Telg verschuven
+Comment[ne]=दिइà¤à¤•à¥‹ कारà¥à¤¯ पà¥à¤°à¤¤à¤¿à¤²à¤¾à¤ˆ अनà¥à¤¯ शाखामा सà¥à¤µà¤¿à¤š गरà¥à¤¨à¥à¤¹à¥‹à¤¸à¥
+Comment[nl]=Zet een bestaande copy om naar een andere branch
+Comment[nn]=Byt arbeidskopien til ei anna grein
+Comment[pl]=Przełącza katalog roboczy na inną gałąź
+Comment[pt]=Muda a cópia de trabalho actual para outra ramificação
+Comment[pt_BR]=Muda a cópia de trabalho atual para outra ramificação
+Comment[ru]=Сменить Ð°Ð´Ñ€ÐµÑ Ñ…Ñ€Ð°Ð½Ð¸Ð»Ð¸Ñ‰Ð°, например перейти от Ñтабильной ветки к ветке разработки
+Comment[sk]=Vymení danú pracovnú kópiu zo inú vetvu
+Comment[sl]=Preklopi dano delovno kopijo na drugo vejo
+Comment[sr]=Пребаци дату радну копију на другу грану
+Comment[sr@Latn]=Prebaci datu radnu kopiju na drugu granu
+Comment[sv]=Byt angiven arbetskopia till en annan gren
+Comment[tr]=Çalışan belirli bir kopyayı başka bölüme değiştir
+Comment[uk]=Перемкнути поточну робочу копію на іншу гілку
+Comment[zh_CN]=将工作副本切æ¢åˆ°å¦å¤–一个分支
+Comment[zh_TW]=將指定的工作複本切æ›åˆ°å¦ä¸€å€‹åˆ†æ”¯
+Exec=kio_svn_helper -s %U
+
+[Desktop Action Merge]
+Name=Merge...
+Name[bg]=СмеÑване...
+Name[br]=D&astum ...
+Name[ca]=Fusiona...
+Name[cs]=SlouÄit...
+Name[da]=Indflet...
+Name[de]=Zusammenführen ...
+Name[el]=Συγχώνευση...
+Name[eo]=Kunfandi...
+Name[es]=Mezclar...
+Name[et]=Ãœhendamine...
+Name[eu]=Bateratu...
+Name[fa]=ادغام...
+Name[fi]=Yhdistä...
+Name[fr]=Fusionner...
+Name[ga]=Cumaisc...
+Name[gl]=Fusionar...
+Name[he]=מזג...
+Name[hu]=Összeolvasztás...
+Name[is]=Bræða saman...
+Name[it]=Fondi...
+Name[ja]=マージ...
+Name[ka]=შერწყმáƒ...
+Name[kk]=Біріктіру...
+Name[lt]=Sulieti...
+Name[nb]=Flett …
+Name[nds]=Tosamenföhren...
+Name[ne]=गाभिनà¥...
+Name[nl]=Samenvoegen...
+Name[nn]=Flett …
+Name[pa]=ਮਿਲਾਨ...
+Name[pl]=Połącz...
+Name[pt]=Reunir...
+Name[pt_BR]=Mesclar...
+Name[ru]=Объединить...
+Name[sk]=Spojiť...
+Name[sl]=Združi ...
+Name[sr]=Стопи...
+Name[sr@Latn]=Stopi...
+Name[sv]=Sammanfoga...
+Name[tr]=BirleÅŸtir...
+Name[uk]=Об'єднати...
+Name[zh_CN]=åˆå¹¶...
+Name[zh_TW]=åˆä½µ...
+Icon=svn_merge
+Comment=Merge changes between this and another branch
+Comment[bg]=СмеÑване на промените от това разклонение Ñ Ð´Ñ€ÑƒÐ³Ð¾ разклонение.
+Comment[ca]=Fusiona els canvis entre aquesta i una altra branca
+Comment[cs]=SlouÄit zmÄ›ny mezi touto a jinou vÄ›tví
+Comment[da]=Indflet ændringer mellem denne og en anden gren
+Comment[de]=Führt Änderungen aus dieser und einer anderen Verzweigung zusammen
+Comment[el]=Συγχώνευση αλλαγών Î¼ÎµÏ„Î±Î¾Ï Ï„Î¿Ï… Ï„Ïέχοντος και κάποιου άλλου κλάδου
+Comment[es]=Mezclar los cambios entre esta y otra rama
+Comment[et]=Selle ja teise haru muudatuste ühendamine
+Comment[eu]=Bateratu hau eta beste adar baten arteko aldaketak
+Comment[fa]=تغییرات بین این شاخه و شاخۀ دیگر را ادغام می‌کند
+Comment[fi]=Yhdistä tämän ja toisen haaran väliset muutokset
+Comment[fr]=Fusionner les modifications entre cette branche et une autre
+Comment[gl]=Fusiona as modificacións entre esta ramificación e outra
+Comment[hu]=A módosítások összefésülése egy másik ággal
+Comment[is]=Bræða saman breytingar milli þessarar og annarar greinar
+Comment[it]=Fondi i cambiamenti tra questo e un altro ramo
+Comment[ja]=ã“ã®ãƒ–ランãƒã¨ä»–ã®ãƒ–ランãƒã®é–“ã§ã€å¤‰æ›´ã‚’マージã—ã¾ã™ã€‚
+Comment[ka]=áƒáƒ› დრსხვრტáƒáƒ¢áƒ”ბის ცვლილებების შერწყმáƒ
+Comment[kk]=ОÑÑ‹ және өзге Ñалалардағы өзгеріÑтерін біріктіру
+Comment[lt]=Sulieti pakeitimus tarp šios ir kitos atšakos
+Comment[nb]=Flett sammen endringer mellom denne og en annen gren
+Comment[nds]=Ännern twischen dissen un en annern Telg tosamenföhren
+Comment[ne]=यो र अनà¥à¤¯ शाखा बीचका परिवरà¥à¤¤à¤¨ गाभà¥à¤¨à¥à¤¹à¥‹à¤¸à¥
+Comment[nl]=Deze en een andere tak samenvoegen
+Comment[nn]=Flett saman endringar mellom denne og ei anna grein
+Comment[pl]=ÅÄ…czy zmiany miÄ™dzy tÄ… i innÄ… gaÅ‚Ä™ziÄ…
+Comment[pt]=Junta as modificações entre esta ramificação e outra
+Comment[pt_BR]=Mescla as modificações entre esta ramificação e outra
+Comment[ru]=Объеденить Ð¸Ð·Ð¼ÐµÐ½ÐµÐ½Ð¸Ñ Ð¼ÐµÐ¶Ð´Ñƒ Ñтой и другой ветками
+Comment[sk]=Spojí zmeny medzi touto a inou vetvou
+Comment[sl]=Združi spremembe med to in drugo vejo
+Comment[sr]=Стопи измене између ове и друге гране
+Comment[sr@Latn]=Stopi izmene između ove i druge grane
+Comment[sv]=Sammanfoga ändringar mellan den här och en annan gren
+Comment[tr]=Bu ve başka bölüm arasındaki değişiklikleri birleştir
+Comment[uk]=Об'єднати зміни в цій та іншій гілках
+Comment[zh_CN]=åˆå¹¶æœ¬åœ°å’Œå¦å¤–一个分支的更改
+Comment[zh_TW]=將這個與å¦ä¸€å€‹åˆ†æ”¯åˆä½µ
+Exec=kio_svn_helper -m %U
+
+[Desktop Action Blame]
+Name=Blame...
+Name[bg]=ИнформациÑ...
+Name[ca]=Responsabilitza...
+Name[cs]=Obvinit...
+Name[de]=Blame ...
+Name[el]=Συσχέτιση...
+Name[eo]=Kulpigi...
+Name[es]=Responsabilizar...
+Name[et]=Autorsus...
+Name[eu]=Erruduna...
+Name[fa]=...سرزنش کردن
+Name[fr]=Blâmer...
+Name[gl]=Autorías...
+Name[he]=×”×ש×...
+Name[hu]=Ki tette ezt...
+Name[is]=Kenna um...
+Name[it]=Traccia...
+Name[ja]=ブレイム...
+Name[ka]=ბრáƒáƒšáƒ˜...
+Name[kk]=Кім екен...
+Name[lt]=Nustatyti...
+Name[nb]=Skyld på …
+Name[nds]=Naspören...
+Name[ne]=दोष...
+Name[nl]=Annotatie...
+Name[nn]=Skuld på …
+Name[pa]=ਬਲਾਮੀ...
+Name[pl]=Obwiń...
+Name[pt]=Culpar...
+Name[pt_BR]=Culpar...
+Name[ru]=Определить авторов...
+Name[sk]=Žalovať...
+Name[sl]=Odgovornost ...
+Name[sr]=Окриви...
+Name[sr@Latn]=Okrivi...
+Name[sv]=Klandra...
+Name[uk]=Вина...
+Name[zh_CN]=历å²...
+Name[zh_TW]=最後狀態註記...
+Icon=svn_blame
+Comment=See who wrote each line of the file and in what revision
+Comment[bg]=Ð˜Ð½Ñ„Ð¾Ñ€Ð¼Ð°Ñ†Ð¸Ñ Ð·Ð° това кой е напиÑал файла и в ÐºÐ¾Ñ Ð²ÐµÑ€ÑиÑ
+Comment[ca]=Veu qui va escriure cada línia del fitxer i en qui l'ha revisat
+Comment[cs]=Zobrazit, kdo napsal kterou řádku souboru spolu s revizí
+Comment[da]=Se hvem der skrev hver linje i filen og i hvilken revision
+Comment[de]=Zeigt an, wer die Zeilen einer Datei wann geändert hat.
+Comment[el]=Δείτε ποιος έγÏαψε κάθε γÏαμμή του αÏχείου και σε ποια αναθεώÏηση
+Comment[es]=Ver quién escribió cada línea del archivo y en qué revisión
+Comment[et]=Vaatamine, kes ja millises versioonis mingi faili rea kirjutas
+Comment[eu]=Ikusi nork idatzi duen lerro bakoitza eta zer errebisiotan
+Comment[fa]=ببینید چه کسی هر خط پرونده را و در چه بازبینی نوشته است
+Comment[fi]=Tarkista kuka on kirjoittanut tiedoston rivit missäkin versiossa
+Comment[fr]=Voir qui a écrit chacune des lignes du fichier, et dans quelle version.
+Comment[gl]=Consulta quen escribiu unha liña dada no ficheiro e en que versión
+Comment[hu]=A fájlok készítőinek megtekintése soronként, verzió szerint
+Comment[is]=Sjá hver skrifaði hvaða línu og í hvaða útgáfu
+Comment[it]=Vedi chi ha scritto ogni riga del file e in quale revisione
+Comment[ja]=誰ãŒã©ã®ãƒªãƒ“ジョンã®ã€ã©ã®ãƒ•ã‚¡ã‚¤ãƒ«ã®ã€ã©ã®è¡Œã‚’書ã„ãŸã®ã‹ã‚’見ã¾ã™ã€‚
+Comment[ka]=ნáƒáƒ®áƒ”თ თუ ვინ ჩáƒáƒ¬áƒ”რრფáƒáƒ˜áƒšáƒ˜áƒ¡ ყáƒáƒ•áƒ”ლი ხáƒáƒ–ი დრრáƒáƒ›áƒ”ლ რევიზიáƒáƒ¨áƒ˜
+Comment[kk]=Файлдағы жолды кім және қай нұÑқаÑында жазғанын білу
+Comment[lt]=Patikrinti, kas parašė kiekvieną eilutę ir kurio keitimo metu tai buvo atlikta
+Comment[nb]=Se hvem som skrev hver linje i fila og i hvilken revisjon
+Comment[nds]=Wiest, wokeen wannehr welke Dateiregen ännert hett
+Comment[ne]=पà¥à¤°à¤¤à¥à¤¯à¥‡à¤• फाइल कसले लेखेको छ र के दोहोरिà¤à¤•à¥‹ छ हेरà¥à¤¨à¥à¤¹à¥‹à¤¸à¥
+Comment[nl]=Bekijk wie welke regel van het bestand geschreven heeft en in welke revisie
+Comment[nn]=Sjå kven som skreiv kvar linje i fila og i kva revisjon
+Comment[pl]=Pokazuje, kto ostatni zmienił każdą linię w pliku i w której wersji
+Comment[pt]=Vê quem escreveu uma dada linha no ficheiro e em que versão
+Comment[pt_BR]=Vê quem escreveu uma determinada linha no arquivo e em que versão
+Comment[ru]=ПроÑмотреть авторов каждой Ñтроки в файле и в выбранной ревизии
+Comment[sk]=Pozrite sa, kto a v ktorej revízii napísal každý riadok súboru
+Comment[sl]=Prikaži, kdo je napisal katero vrstico in v kateri reviziji
+Comment[sr]=Прикажи за Ñваку линију фајла ко ју је напиÑао и у којој ревизији
+Comment[sr@Latn]=Prikaži za svaku liniju fajla ko ju je napisao i u kojoj reviziji
+Comment[sv]=Se vem som skrev varje rad i filen och för vilken version
+Comment[uk]=ПодивитиÑÑŒ хто напиÑав кожний Ñ€Ñдок файла Ñ– в Ñкій модифікації
+Comment[zh_CN]=查看è°åœ¨å“ªæ¬¡ä¿®è®¢ä¸­å†™äº†æ–‡ä»¶çš„哪一行
+Comment[zh_TW]=看檔案中的æ¯ä¸€è¡Œæ˜¯èª°å¯«çš„,其版本為何
+Exec=kio_svn_helper -b %U
+
+[Desktop Action CreatePatch]
+Name=Create Patch...
+Name[bg]=Създаване на кръпка...
+Name[ca]=Crea pedaç...
+Name[cs]=Vytvořit záplatu...
+Name[da]=Lav rettelse...
+Name[de]=Patch erstellen ...
+Name[el]=ΔημιουÏγία διόÏθωσης...
+Name[eo]=Krei Flikon...
+Name[es]=Crear parche...
+Name[et]=Paiga loomine...
+Name[eu]=Sortu adabakia...
+Name[fa]=ایجاد کژنه...
+Name[fi]=Luo korjaus...
+Name[fr]=Créer un correctif...
+Name[ga]=Cruthaigh Paiste...
+Name[gl]=Criar un parche...
+Name[he]=צור טל××™...
+Name[hu]=Folt készítése...
+Name[is]=Búa til plástur...
+Name[it]=Crea correzione...
+Name[ja]=パッãƒã®ä½œæˆ...
+Name[ka]=ბებკის შექმნáƒ...
+Name[kk]=Жамауды құру...
+Name[lt]=Kurti pataisymÄ…...
+Name[nb]=Lag lapp …
+Name[nds]=Kodeplaster opstellen...
+Name[ne]=पà¥à¤¯à¤¾à¤š सिरà¥à¤œà¤¨à¤¾...
+Name[nl]=Patch aanmaken...
+Name[nn]=Lag lapp …
+Name[pa]=ਪੈਂਚ ਬਣਾਓ...
+Name[pl]=Stwórz łatę...
+Name[pt]=Criar um 'Patch'...
+Name[pt_BR]=Criar um 'Patch'...
+Name[ru]=Создать заплатку...
+Name[sk]=Vytvoriť záplatu...
+Name[sl]=Ustvari popravek ...
+Name[sr]=Ðаправи закрпу...
+Name[sr@Latn]=Napravi zakrpu...
+Name[sv]=Skapa programfix...
+Name[tr]=Yama OluÅŸtur...
+Name[uk]=Створити латку...
+Name[zh_CN]=创建补ä¸...
+Name[zh_TW]=建立修補檔...
+Exec=kio_svn_helper -p %U
+
+[Desktop Action Export]
+Name=Export...
+Name[bg]=ЕкÑпортиране...
+Name[br]=Ezporzh ...
+Name[ca]=Exporta...
+Name[cs]=Exportovat...
+Name[cy]=Allforio...
+Name[da]=Eksportér...
+Name[de]=Exportieren ...
+Name[el]=Εξαγωγή...
+Name[eo]=Eksporti...
+Name[es]=Exportar...
+Name[et]=Eksport...
+Name[eu]=Esportatu...
+Name[fa]=صادرات...
+Name[fi]=Vie...
+Name[fr]=Exporter...
+Name[ga]=Easpórtáil...
+Name[gl]=Exportar...
+Name[he]=ייצ×....
+Name[hu]=Exportálás...
+Name[is]=Flytja út...
+Name[it]=Esporta...
+Name[ja]=エクスãƒãƒ¼ãƒˆ...
+Name[ka]=ექსპáƒáƒ áƒ¢áƒ˜...
+Name[kk]=ЭкÑпорттау...
+Name[lt]=Eksportuoti...
+Name[nb]=Eksporter …
+Name[nds]=Exporteren...
+Name[ne]=निरà¥à¤¯à¤¾à¤¤...
+Name[nl]=Exporteren...
+Name[nn]=Eksporter …
+Name[pa]=ਨਿਰਯਾਤ...
+Name[pl]=Eksportuj...
+Name[pt]=Exportar...
+Name[pt_BR]=Exportar...
+Name[ru]=ЭкÑпорт...
+Name[sk]=Exportovať...
+Name[sl]=Izvozi ...
+Name[sr]=Извези...
+Name[sr@Latn]=Izvezi...
+Name[sv]=Exportera...
+Name[tr]=Dışa Aktar...
+Name[uk]=ЕкÑпортувати...
+Name[zh_CN]=导出...
+Name[zh_TW]=匯出...
+Icon=svn_export
+Exec=kio_svn_helper -e %U
+Comment=Checkout out an unversioned copy of a tree from a repository
+Comment[bg]=ИзтеглÑне на копие на дървото от хранилището.
+Comment[ca]=Exporta una còpia sense versió d'un arbre del repositori
+Comment[cs]=Získat z repository kopii stromu bez verze
+Comment[da]=Tjek en kopi uden version ud af et træ fra et lager
+Comment[de]=Herausholen eines Baums aus dem SVN-Archiv ohne Versionsinformationen
+Comment[el]=Έλεγχος εξόδου ενός αντιγÏάφου χωÏίς έκδοση από ένα δέντÏο του χώÏου αποθήκευσης
+Comment[es]=Exporta una copia no versionada de un árbol de un repositorio
+Comment[et]=Hoidla failipuu versioonita koopia väljavõte
+Comment[eu]=Deskargatu bertsio-gabeko zuhaitz baten kopia bat biltegitik
+Comment[fa]=وارسی یک رونوشت کلی درخت از مخزن
+Comment[fi]=Nouda versioimaton kopio versionhallinnan puusta
+Comment[fr]=Extraire une copie sans contrôle de version d'une arborescence depuis un référentiel
+Comment[gl]=Obtén unha copia sen control de versións dunha árbore do repositorio
+Comment[hu]=Verzió nélküli másolat készítése az adattárból
+Comment[is]=Ná í afrit af tré án útgáfunúmers frá geymslu
+Comment[it]=Ritira una copia senza versione di un albero da un deposito
+Comment[ja]=リãƒã‚¸ãƒˆãƒªã‹ã‚‰éžãƒãƒ¼ã‚¸ãƒ§ãƒ³ç®¡ç†ãƒ„リーã¨ã—ã¦ãƒã‚§ãƒƒã‚¯ã‚¢ã‚¦ãƒˆã—ã¾ã™ã€‚
+Comment[ka]=რეპáƒáƒ–იტტáƒáƒ áƒ˜áƒ˜áƒ“áƒáƒœ ხის უვერსირáƒáƒ¡áƒšáƒ˜áƒ¡ შემáƒáƒ¬áƒ›áƒ”ბáƒ
+Comment[kk]=Жоба бұтағын қоймаÑынан, нұÑқалар еÑебін қадағалауынан Ñ‚Ñ‹Ñ ÐºÓ©ÑˆÑ–Ñ€Ñ–Ð¿ алу
+Comment[lt]=Atsisiųsti bylas iÅ¡ egzistuojanÄios saugyklos be keitimų sekimo.
+Comment[nb]=Sjekk ut en kopi av et tre uten versjon fra et lager
+Comment[nds]=En Boomkopie ahn Verschooninformatschoon ut en Archiv daalladen
+Comment[ne]=भणà¥à¤¡à¤¾à¤°à¤¬à¤¾à¤Ÿ संसà¥à¤•à¤°à¤£ ननिकालिà¤à¤•à¥‹ टà¥à¤°à¥€ बाहिरको पà¥à¤°à¤¤à¤¿ जाà¤à¤š गरà¥à¤¨à¥à¤¹à¥‹à¤¸à¥
+Comment[nl]=Een niet onder versiebeheer vallende kopie uitchecken van een tak uit de repository
+Comment[nn]=Sjekk ut ein kopi av eit tre utan versjon frå eit lager
+Comment[pl]=Pobiera kopiÄ™ drzewa z repozytorium bez informacji do kontroli wersji
+Comment[pt]=Obtém uma cópia sem controlo de versões de uma árvore do repositório
+Comment[pt_BR]=Obtém uma cópia sem controle de versões de uma árvore do repositório
+Comment[ru]=Загрузить копию дерева без Ñлужебной информации ÑиÑтемы ÑƒÐ¿Ñ€Ð°Ð²Ð»ÐµÐ½Ð¸Ñ Ð²ÐµÑ€ÑиÑми
+Comment[sk]=Získa neverzionovanú kópiu stromu z archívu
+Comment[sl]=Iz skladiÅ¡Äa prevzemi kopijo drevesa brez razliÄice
+Comment[sr]=Довуци неверзирану копију Ñтабла из Ñкладишта
+Comment[sr@Latn]=Dovuci neverziranu kopiju stabla iz skladišta
+Comment[sv]=Checka ut en kopia utan versionskontroll från ett arkiv
+Comment[tr]=Depodaki bir ağaçtan kusurlu bir versionsuz kopyayı kontrol et
+Comment[uk]=ВзÑти зі Ñховища копію дерева без верÑій
+Comment[zh_CN]=从仓库中检出无版本副本
+Comment[zh_TW]=從主目錄中å–出ä¸å«ç‰ˆæœ¬è³‡è¨Šçš„工作複本
+
+[Desktop Action Diff]
+Name=Diff (local)
+Name[bg]=Разлика (локално)
+Name[cs]=Rozdíl (místní)
+Name[da]=Diff (lokal)
+Name[de]=Diff (lokal)
+Name[el]=ΔιαφοÏές (τοπικά)
+Name[es]=Diferencias (locales)
+Name[et]=Võrdlemine (kohalik)
+Name[eu]=Desberdintasunak (lokala)
+Name[fa]=Diff (محلی)
+Name[fi]=Diff (paikallinen)
+Name[fr]=Différences (locales)
+Name[ga]=Diff (logánta)
+Name[gl]=Diferenzas (local)
+Name[he]=Diff (מקומי)
+Name[hu]=Diff (helyi)
+Name[is]=Bera saman (staðbundið)
+Name[it]=Differenza (locale)
+Name[ja]=Diff (ローカル)
+Name[ka]=Diff (ლáƒáƒ™áƒáƒšáƒ£áƒ áƒ˜)
+Name[kk]=Жергілікті өзгеріÑтер
+Name[lt]=Diff (vietinis)
+Name[ms]=Diff (tempatan)
+Name[nb]=Diff (lokal)
+Name[nds]=Verscheel (lokaal)
+Name[ne]=Diff (सà¥à¤¥à¤¾à¤¨à¥€à¤¯)
+Name[nl]=Diff (lokaal)
+Name[nn]=Diff (lokal)
+Name[pa]=ਅੰਤਰ (ਸਥਾਨਕ)
+Name[pl]=Różnice (lokalne)
+Name[pt]=Diferenças (local)
+Name[pt_BR]=Diferenças (local)
+Name[ru]=Локальные изменениÑ
+Name[sk]=Rozdiel (lokálne)
+Name[sl]=Diff (krajevno)
+Name[sr]=Разликуј (локално)
+Name[sr@Latn]=Razlikuj (lokalno)
+Name[sv]=Jämför (lokalt)
+Name[tr]=Diff (yerel)
+Name[uk]=РозбіжноÑÑ‚Ñ– (локальні)
+Name[zh_CN]=Diff (本地)
+Name[zh_TW]=比較(本地端)
+Icon=svn_diff
+Exec=kio_svn_helper -D %U
+Comment=Show local changes since last update
+Comment[bg]=Показване на локалните промени Ñлед поÑледното обновÑване.
+Comment[ca]=Mostra els canvis locals des de l'última actualització
+Comment[cs]=Zobrazit lokální změny od poslední aktualizace
+Comment[da]=Vis lokale ændringer siden sidste opdatering
+Comment[de]=Zeigt die lokal durchgeführten Änderungen seit der letzten Aktualisierung
+Comment[el]=Εμφάνιση τοπικών αλλαγών από την τελευταία ενημέÏωση
+Comment[es]=Mostrar los cambios locales desde la última actualización
+Comment[et]=Kohalike muudatuste näitamine pärast viimast uuendamist
+Comment[eu]=Erakutsi azken aldaketatik gertatu diren aldaketa lokalak
+Comment[fa]=نمایش تغییرات محلی از آخرین به‌روزرسانی
+Comment[fi]=Näytä viimeisen päivityksen jälkeen tehdyt paikalliset muutokset
+Comment[fr]=Afficher les changements locaux effectués depuis la dernière mise à jour
+Comment[gl]=Mostra as modificacións locais desde a última actualización
+Comment[hu]=A helyi módosítások mutatása (az utolsó frissítés óta)
+Comment[is]=Sýna staðbundnar breytingar frá seinustu uppfærslu
+Comment[it]=Mostra i cambiamenti locali dall'ultimo aggiornamento
+Comment[ja]=最終アップデートã‹ã‚‰ãƒ­ãƒ¼ã‚«ãƒ«ã«ã©ã®ã‚ˆã†ãªå¤‰æ›´ãŒã‚ã£ãŸã®ã‹ã‚’表示ã—ã¾ã™ã€‚
+Comment[ka]=უკáƒáƒœáƒáƒ¡áƒ™áƒœáƒ”ლი გáƒáƒœáƒáƒ®áƒšáƒ”ბის შემდეგ ლáƒáƒ™áƒáƒšáƒ£áƒ áƒ˜ ცვლილებების ჩვენებáƒ
+Comment[kk]=ҚоймаÑына әлі тапÑырылмаған жергілікті өзгеріÑтерді көрÑету
+Comment[lt]=Rodyti vietinius pakeitimus nuo paskutinio atnaujinimo
+Comment[nb]=Vis lokale endringer siden siste oppdatering
+Comment[nds]=Lokaal Ännern na de verleden Opfrischen wiesen
+Comment[ne]=अनà¥à¤¤à¤¿à¤® अदà¥à¤¯à¤¾à¤µà¤§à¤¿à¤• पछिका सà¥à¤¥à¤¾à¤¨à¥€à¤¯ परिवरà¥à¤¤à¤¨ देखाउनà¥à¤¹à¥‹à¤¸à¥
+Comment[nl]=Lokale wijzigingen sinds de laatste update tonen
+Comment[nn]=Vis lokale endringar sidan siste oppdatering
+Comment[pl]=Pokazuje lokalne zmiany od ostatniego uaktualnienia
+Comment[pt]=Mostra as modificações locais desde a última actualização
+Comment[pt_BR]=Mostra as modificações locais desde a última atualização
+Comment[ru]=Определить изменениÑ, не внеÑенные в общее хранилище
+Comment[sk]=Zobrazí lokálne zmeny od poslednej aktualizácie
+Comment[sl]=Prikaži krajevne spremembe od zadnje posodobitve
+Comment[sr]=Прикажи локалне измене од поÑледњег ажурирања
+Comment[sr@Latn]=Prikaži lokalne izmene od poslednjeg ažuriranja
+Comment[sv]=Visa lokala ändringar sedan senaste uppdateringen
+Comment[tr]=Son güncellemeden sonraki yerel değişiklikleri göster
+Comment[uk]=Показати локальні зміни з чаÑу оÑтаннього оновленнÑ
+Comment[zh_CN]=显示上次更新åŽæœ¬åœ°çš„更改
+Comment[zh_TW]=顯示最後一次更新之後於本地端所åšçš„改變
+
diff --git a/kioslave/svn/svnhelper/subversion_toplevel.desktop b/kioslave/svn/svnhelper/subversion_toplevel.desktop
new file mode 100644
index 00000000..bf38f02c
--- /dev/null
+++ b/kioslave/svn/svnhelper/subversion_toplevel.desktop
@@ -0,0 +1,97 @@
+[Desktop Entry]
+ServiceTypes=inode/directory,all/all
+X-KDE-Priority=TopLevel
+
+X-KDE-GetActionMenu=kded ksvnd getTopLevelActionMenu(KURL::List)
+
+[Desktop Action Update]
+Name=SVN Update
+Name[bg]=ОбновÑване SVN
+Name[ca]=Actualitza SVN
+Name[cs]=SVN update
+Name[da]=SVN Opdatér
+Name[de]=Aktualisieren (SVN)
+Name[el]=ΕνημέÏωση SVN
+Name[es]=Actualizar SVN
+Name[et]=SVN uuendamine
+Name[eu]=SVN eguneratu
+Name[fa]=به‌روزرسانی SVN
+Name[fi]=SVN-päivitys (Update)
+Name[fr]=Mise à jour SVN
+Name[gl]=Actualización SVN
+Name[he]=עדכון SVN
+Name[hu]=SVN frissítés
+Name[is]=Uppfæra SVN
+Name[it]=Aggiornamento SVN
+Name[ja]=SVN アップデート
+Name[ka]=SVN გáƒáƒœáƒáƒ®áƒšáƒ”ბáƒ
+Name[kk]=SVN жаңарту
+Name[lt]=SVN atnaujinti
+Name[ms]=Kemaskini SVN
+Name[nb]=SVN oppdater
+Name[nds]=SVN-Archiv opfrischen
+Name[ne]=à¤à¤¸à¤­à¥€à¤à¤¨ अदà¥à¤¯à¤¾à¤µà¤§à¤¿à¤•
+Name[nl]=SVN bijwerken
+Name[nn]=SVN oppdater
+Name[pa]=SVN ਅੱਪਡੇਟ
+Name[pl]=Uaktualnij
+Name[pt]=Actualização do SVN
+Name[pt_BR]=Atualização a partir do SVN
+Name[ru]=Обновить
+Name[sk]=SVN aktualizácia
+Name[sl]=Posodobitev SVN
+Name[sr]=SVN ажурирање
+Name[sr@Latn]=SVN ažuriranje
+Name[sv]=SVN-uppdatera
+Name[tr]=SVN Güncelleme
+Name[uk]=SVN-оновленнÑ
+Name[zh_CN]=SVN æ›´æ–°
+Name[zh_TW]=SVN æ›´æ–°
+Icon=redo
+Exec=kio_svn_helper -u %U
+
+[Desktop Action Commit]
+Name=SVN Commit
+Name[bg]=Изпращане SVN
+Name[ca]=Entrega SVN
+Name[cs]=SVN commit
+Name[de]=Einspielen (SVN)
+Name[el]=ΚαταχώÏηση SVN
+Name[es]=Entrega SVN
+Name[et]=SVN sissekanne
+Name[eu]=SVN entregatu
+Name[fa]=تصدیق SVN
+Name[fi]=SVN-toimitus (Commit)
+Name[fr]=Validation SVN
+Name[ga]=SVN Cur i bhFeidhm
+Name[gl]=Entrega SVN
+Name[he]=שליחת ×©×™× ×•×™×™× ×©×œ ×”Ö¾SVN
+Name[hu]=SVN eltárolás
+Name[is]=Setja inn í SVN
+Name[it]=Deposito SVN
+Name[ja]=SVN コミット
+Name[ka]=SVN შესრულებáƒ
+Name[kk]=SVN тапÑыру
+Name[lt]=SVN išsiųsti
+Name[nb]=SVN meld inn
+Name[nds]=Na SVN-Archiv inspelen
+Name[ne]=à¤à¤¸à¤­à¥€à¤à¤¨ कमिट
+Name[nl]=SVN vastleggen
+Name[nn]=SVN meld inn
+Name[pa]=SVN ਕਮਿਟ
+Name[pl]=Wyślij
+Name[pt]=Envio do SVN
+Name[pt_BR]=Envio para o SVN
+Name[ru]=Опубликовать
+Name[sk]=SVN potvrdenie
+Name[sl]=Udejanjanje SVN
+Name[sr]=SVN предаја
+Name[sr@Latn]=SVN predaja
+Name[sv]=SVN-arkivera
+Name[tr]=SVN Teslim Etme
+Name[uk]=SVN-переданнÑ
+Name[zh_CN]=SVN æ交
+Name[zh_TW]=SVN æ交
+Icon=undo
+Exec=kio_svn_helper -c %U
+
diff --git a/kioslave/svn/svnhelper/subversioncheckout.ui b/kioslave/svn/svnhelper/subversioncheckout.ui
new file mode 100644
index 00000000..5b320eee
--- /dev/null
+++ b/kioslave/svn/svnhelper/subversioncheckout.ui
@@ -0,0 +1,204 @@
+<!DOCTYPE UI><UI version="3.3" stdsetdef="1">
+<class>SubversionCheckout</class>
+<widget class="QDialog">
+ <property name="name">
+ <cstring>SubversionCheckout</cstring>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>498</width>
+ <height>133</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>Subversion Checkout</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>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLayoutWidget" row="2" column="0">
+ <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="text">
+ <string>&amp;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>&amp;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>&amp;Cancel</string>
+ </property>
+ <property name="accel">
+ <string></string>
+ </property>
+ <property name="autoDefault">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </hbox>
+ </widget>
+ <widget class="KURLRequester" row="0" column="0">
+ <property name="name">
+ <cstring>url</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>7</hsizetype>
+ <vsizetype>5</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ </widget>
+ <widget class="QLayoutWidget" row="1" column="0">
+ <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="text">
+ <string>Revision (0 for HEAD):</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>121</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ <widget class="QSpinBox">
+ <property name="name">
+ <cstring>revision</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>3</hsizetype>
+ <vsizetype>0</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ </widget>
+ </hbox>
+ </widget>
+ </grid>
+ </widget>
+ </vbox>
+</widget>
+<connections>
+ <connection>
+ <sender>buttonOk</sender>
+ <signal>clicked()</signal>
+ <receiver>SubversionCheckout</receiver>
+ <slot>accept()</slot>
+ </connection>
+ <connection>
+ <sender>buttonCancel</sender>
+ <signal>clicked()</signal>
+ <receiver>SubversionCheckout</receiver>
+ <slot>reject()</slot>
+ </connection>
+</connections>
+<layoutdefaults spacing="6" margin="11"/>
+<includehints>
+ <includehint>kurlrequester.h</includehint>
+ <includehint>klineedit.h</includehint>
+ <includehint>kpushbutton.h</includehint>
+</includehints>
+</UI>
diff --git a/kioslave/svn/svnhelper/subversiondiff.ui b/kioslave/svn/svnhelper/subversiondiff.ui
new file mode 100644
index 00000000..dab4ca0e
--- /dev/null
+++ b/kioslave/svn/svnhelper/subversiondiff.ui
@@ -0,0 +1,100 @@
+<!DOCTYPE UI><UI version="3.3" stdsetdef="1">
+<class>Subversion_Diff</class>
+<widget class="QDialog">
+ <property name="name">
+ <cstring>Subversion_Diff</cstring>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>511</width>
+ <height>282</height>
+ </rect>
+ </property>
+ <property name="caption">
+ <string>Subversion Diff</string>
+ </property>
+ <property name="sizeGripEnabled">
+ <bool>true</bool>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QTextBrowser">
+ <property name="name">
+ <cstring>text</cstring>
+ </property>
+ <property name="textFormat">
+ <enum>PlainText</enum>
+ </property>
+ <property name="wordWrap">
+ <enum>NoWrap</enum>
+ </property>
+ <property name="autoFormatting">
+ <set>AutoAll</set>
+ </property>
+ </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>
+ <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>&amp;OK</string>
+ </property>
+ <property name="accel">
+ <string></string>
+ </property>
+ <property name="autoDefault">
+ <bool>true</bool>
+ </property>
+ <property name="default">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </hbox>
+ </widget>
+ </vbox>
+</widget>
+<connections>
+ <connection>
+ <sender>buttonOk</sender>
+ <signal>clicked()</signal>
+ <receiver>Subversion_Diff</receiver>
+ <slot>accept()</slot>
+ </connection>
+</connections>
+<layoutdefaults spacing="6" margin="11"/>
+</UI>
diff --git a/kioslave/svn/svnhelper/subversionlog.ui b/kioslave/svn/svnhelper/subversionlog.ui
new file mode 100644
index 00000000..2c167d5b
--- /dev/null
+++ b/kioslave/svn/svnhelper/subversionlog.ui
@@ -0,0 +1,100 @@
+<!DOCTYPE UI><UI version="3.3" stdsetdef="1">
+<class>Subversion_Log</class>
+<widget class="QDialog">
+ <property name="name">
+ <cstring>Subversion_Log</cstring>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>511</width>
+ <height>282</height>
+ </rect>
+ </property>
+ <property name="caption">
+ <string>Subversion Log</string>
+ </property>
+ <property name="sizeGripEnabled">
+ <bool>true</bool>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QTextBrowser">
+ <property name="name">
+ <cstring>text</cstring>
+ </property>
+ <property name="textFormat">
+ <enum>PlainText</enum>
+ </property>
+ <property name="wordWrap">
+ <enum>NoWrap</enum>
+ </property>
+ <property name="autoFormatting">
+ <set>AutoAll</set>
+ </property>
+ </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>
+ <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>&amp;OK</string>
+ </property>
+ <property name="accel">
+ <string></string>
+ </property>
+ <property name="autoDefault">
+ <bool>true</bool>
+ </property>
+ <property name="default">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </hbox>
+ </widget>
+ </vbox>
+</widget>
+<connections>
+ <connection>
+ <sender>buttonOk</sender>
+ <signal>clicked()</signal>
+ <receiver>Subversion_Log</receiver>
+ <slot>accept()</slot>
+ </connection>
+</connections>
+<layoutdefaults spacing="6" margin="11"/>
+</UI>
diff --git a/kioslave/svn/svnhelper/subversionswitch.ui b/kioslave/svn/svnhelper/subversionswitch.ui
new file mode 100644
index 00000000..8ee1a37c
--- /dev/null
+++ b/kioslave/svn/svnhelper/subversionswitch.ui
@@ -0,0 +1,204 @@
+<!DOCTYPE UI><UI version="3.3" stdsetdef="1">
+<class>SubversionSwitch</class>
+<widget class="QDialog">
+ <property name="name">
+ <cstring>SubversionSwitch</cstring>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>498</width>
+ <height>133</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>Subversion Switch</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>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLayoutWidget" row="2" column="0">
+ <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="text">
+ <string>&amp;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>&amp;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>&amp;Cancel</string>
+ </property>
+ <property name="accel">
+ <string></string>
+ </property>
+ <property name="autoDefault">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </hbox>
+ </widget>
+ <widget class="KURLRequester" row="0" column="0">
+ <property name="name">
+ <cstring>url</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>7</hsizetype>
+ <vsizetype>5</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ </widget>
+ <widget class="QLayoutWidget" row="1" column="0">
+ <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="text">
+ <string>Revision (0 for HEAD) :</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>121</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ <widget class="QSpinBox">
+ <property name="name">
+ <cstring>revision</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>3</hsizetype>
+ <vsizetype>0</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ </widget>
+ </hbox>
+ </widget>
+ </grid>
+ </widget>
+ </vbox>
+</widget>
+<connections>
+ <connection>
+ <sender>buttonOk</sender>
+ <signal>clicked()</signal>
+ <receiver>SubversionSwitch</receiver>
+ <slot>accept()</slot>
+ </connection>
+ <connection>
+ <sender>buttonCancel</sender>
+ <signal>clicked()</signal>
+ <receiver>SubversionSwitch</receiver>
+ <slot>reject()</slot>
+ </connection>
+</connections>
+<layoutdefaults spacing="6" margin="11"/>
+<includehints>
+ <includehint>kurlrequester.h</includehint>
+ <includehint>klineedit.h</includehint>
+ <includehint>kpushbutton.h</includehint>
+</includehints>
+</UI>
diff --git a/kmtrace/Makefile.am b/kmtrace/Makefile.am
new file mode 100644
index 00000000..68fce88d
--- /dev/null
+++ b/kmtrace/Makefile.am
@@ -0,0 +1,50 @@
+# This file is part of the KDE libraries
+# Copyright (C) 1996-1997 Matthias Kalle Dalheimer (kalle@kde.org)
+# (C) 1997-1998 Stephan Kulow (coolo@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.
+
+AM_CPPFLAGS = -DQT_NO_ASCII_CAST -UQT_NO_COMPAT -O3
+LDADD = $(LIB_KDECORE) -liberty
+INCLUDES = $(all_includes)
+
+bin_PROGRAMS = kmtrace demangle kmmatch
+kmtrace_SOURCES = kmtrace.cpp
+kmtrace_LDFLAGS = $(all_libraries)
+
+demangle_SOURCES = demangle.cpp
+demangle_LDFLAGS = $(all_libraries)
+
+kmmatch_SOURCES = match.cpp
+kmmatch_LDFLAGS = $(all_libraries)
+
+bin_SCRIPTS = kminspector
+
+lib_LIBRARIES = libktrace_s.a
+libktrace_s_a_SOURCES = ktrace_s.c
+
+ktrace_s.c: $(srcdir)/ktrace.c
+ $(LN_S) $(srcdir)/ktrace.c $@
+
+lib_LTLIBRARIES = libktrace.la
+libktrace_la_LDFLAGS = -avoid-version
+libktrace_la_SOURCES = ksotrace.cpp ktrace.c
+libktrace_la_LIBADD = $(LIBDL)
+
+exclude_DATA = kde.excludes
+excludedir = $(kde_datadir)/kmtrace
+
+include_HEADERS = ktrace.h
diff --git a/kmtrace/README b/kmtrace/README
new file mode 100644
index 00000000..63e35228
--- /dev/null
+++ b/kmtrace/README
@@ -0,0 +1,110 @@
+This is a KDE tool to assist with malloc debugging using glibc's "mtrace"
+functionality. Unfortunately the mtrace that is part of current (9/9/2000)
+glibc versions only logs the return-address of the malloc/free call.
+The file mtrace.c in this directory logs a complete backtrace upon malloc/
+free.
+
+THIS PROGRAM DEPENDS ON GLIBC! It does not pretend to be portable.
+
+Howto use:
+
+Install the libktrace.so shared library, the ktrace.h header file, the
+and kde.excludes file and the kmtrace processing tool with:
+
+ make install
+
+There are two ways to activate memory usage loggings by ktrace :
+
+1) The LD_PRELOAD way
+
+This way, you can debug any application without having to recompile it,
+but you'll have to debug also the memory allocated by KApplication and
+friends.
+
+You can activate malloc logging by starting yourApplication as:
+
+ MALLOC_TRACE=/tmp/ktrace.out LD_PRELOAD=$KDEDIR/lib/libktrace.so yourApplication
+
+2) The manual way
+
+Take the KDE application that you want to investigate and add
+
+ #include <ktrace.h>
+
+Add as first statement in main():
+
+ ktrace();
+
+Add ktrace_s.a to the LDADD line in your Makefile.am like:
+
+ kicker_LDADD = kicker.la /opt/kde/lib/libktrace_s.a
+
+Note that the static library is used.
+You can now activate malloc logging by starting yourApplication as:
+
+ MALLOC_TRACE=/tmp/ktrace.out yourApplication
+
+This will generate a huge log in /tmp/ktrace.out.
+
+You can process this log with:
+
+ kmtrace /tmp/ktrace.out > ktrace.parsed
+
+By default the trace-output is stored in the current directory
+as "ktrace.out". kmtrace also searches it there, so you don't need
+to add any commandline options.
+
+TIPS
+====
+
+* If you can't be bothered with the stuff that KApplication allocates for you
+you might want to put the ktrace() call after the KApplication constructor.
+This will lead to a lot of warnings like:
+
+ Freeing unalloacted memory: 0x08056108
+
+Which are harmless, it just means that the memory was allocated before you
+turned the tracing on. Note that you cannot use this if you're using
+LD_PRELOAD to use ktrace.
+
+* To filter out harmless allocations out of the output file you can specify
+with the --exclude option a file with symbols to exclude from output. If a
+backtrace contains a symbol that starts with any of the symbols in this file,
+this backtrace / leaked block is not shown in the output.
+
+In the file kde.exclude some example symbols are listed. Usage example:
+
+ kmtrace /tmp/malloc.trace > /tmp/malloc.parsed
+
+* Be aware that the reported symbols may not be accurate under all
+circumstances. E.g. consider the following backtrace:
+
+ 0x405879c1 /lib/libdl.so.2(dlerror+0x1b1)
+ 0x405873b3 /lib/libdl.so.2(dlopen+0x33)
+ 0x4053c0b2 /ext/kde2.0/lib/libkdecore.so.3(QXmlSimpleReader::reportParseErro
+ 0x4053c74b /ext/kde2.0/lib/libkdecore.so.3(lt_dlexit+0x24b)
+ 0x4053c894 /ext/kde2.0/lib/libkdecore.so.3(lt_dlexit+0x394)
+ 0x4053dd49 /ext/kde2.0/lib/libkdecore.so.3(lt_dlopen+0x899)
+
+The QXmlSimpleReader is obviously wrong here.
+
+* You can use the --tree option to kmtrace to specify a file to print a tree
+of the allocations. You can also use --treedepth and --treethreshold options
+to hide subtrees that are deeper than the specified depth or allocated less
+than the given memory amount.
+
+* The advantage of using libktrace_s.a (the static library) is that you can
+put calls to ktrace() and kuntrace() around a block of code that
+interests you. Only allocations and deallocations between the first call
+to ktrace() and the first call to kuntrace() will be logged.
+
+
+Have fun.
+
+Waldo Bastian
+bastian@kde.org
+
+kmtrace.cpp by Waldo Bastian <bastian@kde.org>
+ktrace.c by Waldo Bastian <bastian@kde.org> based on mtrace.c
+mtrace.c by Mike Haertel <mike@ai.mit.edu>
+mtrace.c patched by Andi Kleen <ak@suse.de>
diff --git a/kmtrace/configure.in.in b/kmtrace/configure.in.in
new file mode 100644
index 00000000..5df3711e
--- /dev/null
+++ b/kmtrace/configure.in.in
@@ -0,0 +1,18 @@
+dnl AC_OUTPUT( kmtrace/kminspector )
+
+case "$host" in
+ *-gnu)
+ saved_LIBS="$LIBS"
+ LIBS="$LIBS -Wl,-Bstatic -liberty -Wl,-Bdynamic"
+ AC_TRY_LINK([], [], [kde_compile_kmtrace=$GCC], [kde_compile_kmtrace=no])
+ AC_SUBST(KMTRACE_LIBS, [$LIBS])
+ LIBS="$saved_LIBS"
+ ;;
+ *)
+ kde_compile_kmtrace=no
+ ;;
+esac
+
+if test ! "x$kde_compile_kmtrace" = "xyes"; then
+ DO_NOT_COMPILE="$DO_NOT_COMPILE kmtrace"
+fi
diff --git a/kmtrace/demangle.cpp b/kmtrace/demangle.cpp
new file mode 100644
index 00000000..81bcff90
--- /dev/null
+++ b/kmtrace/demangle.cpp
@@ -0,0 +1,60 @@
+#include <qintdict.h>
+#include <stdio.h>
+#include <qstringlist.h>
+#include <qstrlist.h>
+#include <qtextstream.h>
+#include <qsortedlist.h>
+#include <qfile.h>
+#include <qtl.h>
+#include <qvaluelist.h>
+#include <stdlib.h>
+#include <ktempfile.h>
+#include <kinstance.h>
+#include <kstandarddirs.h>
+#include <kcmdlineargs.h>
+
+extern "C" {
+/* Options passed to cplus_demangle (in 2nd parameter). */
+
+#define DMGL_NO_OPTS 0 /* For readability... */
+#define DMGL_PARAMS (1 << 0) /* Include function args */
+#define DMGL_ANSI (1 << 1) /* Include const, volatile, etc */
+#define DMGL_JAVA (1 << 2) /* Demangle as Java rather than C++. */
+
+#define DMGL_AUTO (1 << 8)
+#define DMGL_GNU (1 << 9)
+#define DMGL_LUCID (1 << 10)
+#define DMGL_ARM (1 << 11)
+#define DMGL_HP (1 << 12) /* For the HP aCC compiler; same as ARM
+ except for template arguments, etc. */
+#define DMGL_EDG (1 << 13)
+#define DMGL_GNU_V3 (1 << 14)
+#define DMGL_GNAT (1 << 15)
+
+
+extern char *cplus_demangle(const char *mangled, int options);
+}
+
+
+int main(int argc, char **argv)
+{
+ char buf[1024];
+
+ while(!feof(stdin))
+ {
+ fgets(buf, 1024, stdin);
+ QCString line = buf;
+ line = line.stripWhiteSpace();
+ char *res = cplus_demangle(line.data(), DMGL_PARAMS | DMGL_AUTO | DMGL_ANSI );
+ if (res)
+ {
+ printf("%s\n", res);
+ free(res);
+ }
+ else
+ {
+ printf("%s\n", line.data());
+ }
+ }
+}
+
diff --git a/kmtrace/kde.excludes b/kmtrace/kde.excludes
new file mode 100644
index 00000000..9e77eb5a
--- /dev/null
+++ b/kmtrace/kde.excludes
@@ -0,0 +1,49 @@
+# We don't care about initialisation done by X11.
+XLoadQueryFont
+_XInitKeysymDB
+IceRegisterForProtocolSetup
+KDE_IceRegisterForProtocolSetup
+IceOpenConnection
+KDE_IceOpenConnection
+KDE_IceProtocolSetup
+#and we don't care about Xim memleaks
+qt_init_internal
+QApplication::create_xim
+# workaround for Qt 2.2.0 bug
+QFontDatabase::QFontDatabase
+QFontDatabase::charSets
+
+#QRexExp does caching(?)
+QRegExpEngine::QRegExpEngine
+QRegExpEngine::parseExpression
+
+QStyleSheet::defaultSheet
+
+QTimer::singleShot
+QTextCodec::codecForLocale
+# Yeah, yeah we know that this metaobject stuff is never free'ed.
+QMetaObject::new_meta
+QObject::initMetaObject
+QObject::staticMetaObject
+QString::sprintf
+QWidget::createTLExtra
+# static KDE stuff
+kdbgstream::flush
+KCmdLineArgs::addCmdLineOptions
+k_bindtextdomain
+_nl_find_domain
+KIconTheme::list
+KIconTheme::current
+KGlobalSettings::toolBarFont
+KGlobalSettings::menuFont
+KGlobalSettings::fixedFont
+KGlobalSettings::generalFont
+KGlobalSettings::toolBarFont
+KImageIOFactory::self
+objMap
+# Some C functions that allocate data for initialisation
+getpwuid
+adjtime
+getservbyname
+# nothing created by static objects can be a memory leak
+__static_initialization_and_destruction_0
diff --git a/kmtrace/kminspector.in b/kmtrace/kminspector.in
new file mode 100755
index 00000000..572ed200
--- /dev/null
+++ b/kmtrace/kminspector.in
@@ -0,0 +1,9 @@
+#! /bin/sh
+
+export MALLOC_TREE=kminspector.tree
+export MALLOC_THRESHOLD=2000
+export LD_PRELOAD=@kde_libraries@/libktrace.so
+
+$*
+
+cat kminspector.tree | less
diff --git a/kmtrace/kmtrace.cpp b/kmtrace/kmtrace.cpp
new file mode 100644
index 00000000..82055e43
--- /dev/null
+++ b/kmtrace/kmtrace.cpp
@@ -0,0 +1,721 @@
+#include <qintdict.h>
+#include <stdio.h>
+#include <qstringlist.h>
+#include <qstrlist.h>
+#include <qtextstream.h>
+#include <qsortedlist.h>
+#include <qfile.h>
+#include <qtl.h>
+#include <qvaluelist.h>
+#include <stdlib.h>
+#include <ktempfile.h>
+#include <kinstance.h>
+#include <kstandarddirs.h>
+#include <kcmdlineargs.h>
+#include <kprocess.h>
+
+extern "C" {
+/* Options passed to cplus_demangle (in 2nd parameter). */
+
+#define DMGL_NO_OPTS 0 /* For readability... */
+#define DMGL_PARAMS (1 << 0) /* Include function args */
+#define DMGL_ANSI (1 << 1) /* Include const, volatile, etc */
+#define DMGL_JAVA (1 << 2) /* Demangle as Java rather than C++. */
+
+#define DMGL_AUTO (1 << 8)
+#define DMGL_GNU (1 << 9)
+#define DMGL_LUCID (1 << 10)
+#define DMGL_ARM (1 << 11)
+#define DMGL_HP (1 << 12) /* For the HP aCC compiler; same as ARM
+ except for template arguments, etc. */
+#define DMGL_EDG (1 << 13)
+#define DMGL_GNU_V3 (1 << 14)
+#define DMGL_GNAT (1 << 15)
+
+
+extern char *cplus_demangle(const char *mangled, int options);
+}
+
+struct Entry {
+ int base;
+ int size;
+ int signature;
+ int count;
+ int total_size;
+ int backtrace[1];
+
+ bool operator==(const Entry &e) { return total_size == e.total_size; }
+ bool operator<(const Entry &e) { return total_size > e.total_size; }
+};
+
+QIntDict<Entry> *entryDict = 0;
+QIntDict<char> *symbolDict = 0;
+QIntDict<char> *formatDict = 0;
+QSortedList<Entry> *entryList = 0;
+QStrList *excludes = 0;
+
+const char * const unknown = "<unknown>";
+const char * const excluded = "<excluded>";
+int allocCount = 0;
+int leakedCount = 0;
+int count = 0;
+int maxCount;
+int totalBytesAlloced = 0;
+int totalBytesLeaked = 0;
+int totalBytes = 0;
+int maxBytes;
+
+int fromHex(const char *str);
+void parseLine(const QCString &_line, char operation);
+void dumpBlocks();
+
+int fromHex(const char *str)
+{
+ if (*str == '[') str++;
+ str += 2; // SKip "0x"
+ return strtoll(str, NULL, 16);
+}
+
+// [address0][address1] .... [address] + base size
+void parseLine(const QCString &_line, char operation)
+{
+ char *line= (char *) _line.data();
+ const char *cols[200];
+ int i = 0;
+ cols[i++] = line;
+ while(*line)
+ {
+ if (*line == ' ')
+ {
+ *line = 0;
+ line++;
+ while (*line && (*line==' ')) line++;
+ if (*line) cols[i++] = line;
+ }
+ else line++;
+ }
+ int cols_count = i;
+ if (cols_count > 199) fprintf(stderr, "Error cols_count = %d\n", cols_count);
+ if (cols_count < 4) return;
+ switch (operation)
+ {
+ case '+':
+ {
+ Entry *entry = (Entry *) malloc((cols_count+3) *sizeof(int));
+ entry->base = fromHex(cols[cols_count-2]);
+ entry->size = fromHex(cols[cols_count-1]);
+ int signature = 0;
+ for(int i = cols_count-3; i--;)
+ {
+ signature += (entry->backtrace[i-1] = fromHex(cols[i]));
+ }
+ entry->signature = (signature / 4)+cols_count;
+ entry->count = 1;
+ entry->total_size = entry->size;
+ entry->backtrace[cols_count-4] = 0;
+ totalBytesAlloced += entry->size;
+ totalBytes += entry->size;
+ count++;
+ if (totalBytes > maxBytes)
+ maxBytes = totalBytes;
+ if (count > maxCount)
+ maxCount = count;
+ if (entryDict->find(entry->base))
+ fprintf(stderr, "\rAllocated twice: 0x%08x \n", entry->base);
+ entryDict->replace(entry->base, entry);
+ } break;
+ case '-':
+ {
+ int base = fromHex(cols[cols_count-1]);
+ Entry *entry = entryDict->take(base);
+ if (!entry)
+ {
+ if (base)
+ fprintf(stderr, "\rFreeing unalloacted memory: 0x%08x \n", base);
+ }
+ else
+ {
+ totalBytes -= entry->size;
+ count--;
+ free(entry);
+ }
+ } break;
+ default:
+ break;
+ }
+}
+
+void sortBlocks()
+{
+ QIntDictIterator<Entry> it(*entryDict);
+ for(;it.current(); ++it)
+ {
+ Entry *entry = it.current();
+ totalBytesLeaked += entry->total_size;
+ entryList->append(entry);
+ for(int i = 0; entry->backtrace[i]; i++)
+ {
+ if (!symbolDict->find(entry->backtrace[i]))
+ symbolDict->insert(entry->backtrace[i], unknown);
+ }
+ }
+ entryList->sort();
+}
+
+void collectDupes()
+{
+ QIntDict<Entry> dupeDict;
+ QIntDictIterator<Entry> it(*entryDict);
+ for(;it.current();)
+ {
+ Entry *entry = it.current();
+ ++it;
+ Entry *entry2 = dupeDict.find(entry->signature);
+ if (entry2)
+ {
+ entry2->count++;
+ entry2->total_size += entry->size;
+ entryDict->remove(entry->base);
+ }
+ else
+ {
+ dupeDict.insert(entry->signature, entry);
+ }
+ }
+}
+
+int lookupSymbols(FILE *stream)
+{
+ int i = 0;
+ int symbols = 0;
+ char line2[1024];
+ while(!feof(stream))
+ {
+ fgets(line2, 1023, stream);
+ if (line2[0] == '=' )
+ {
+ if(strcmp(line2,"= End") == 0 )
+ break;
+ }
+ else if (line2[0] == '#')
+ ;
+ else if (line2[0] == '@')
+ ;
+ else if (line2[0] == '[')
+ ;
+ else if (line2[0] == '-')
+ ;
+ else if (line2[0] == '<')
+ ;
+ else if (line2[0] == '>')
+ ;
+ else if (line2[0] == '+')
+ {
+ i++;
+ if (i & 1024)
+ {
+ fprintf(stderr, "\rLooking up symbols: %d found %d of %d symbols", i, symbols, symbolDict->count());
+ }
+ }
+ else
+ {
+ char *addr = index(line2, '[');
+ if (addr)
+ {
+ long i_addr = fromHex(addr);
+ const char* str = symbolDict->find(i_addr);
+ if (str == unknown)
+ {
+ *addr = 0;
+ char* str;
+ if( rindex(line2, '/') != NULL )
+ str = qstrdup(rindex(line2, '/')+1);
+ else
+ str = qstrdup(line2);
+ symbolDict->replace(i_addr, str);
+ symbols++;
+ }
+ }
+ }
+ }
+ fprintf(stderr, "\rLooking up symbols: %d found %d of %d symbols\n", i, symbols, symbolDict->count());
+ return symbolDict->count()-symbols;
+}
+
+void lookupUnknownSymbols(const char *appname)
+{
+ KTempFile inputFile;
+ KTempFile outputFile;
+ inputFile.setAutoDelete(true);
+ outputFile.setAutoDelete(true);
+ FILE *fInputFile = inputFile.fstream();
+ QIntDict<char> oldDict = *symbolDict;
+ QIntDictIterator<char> it(oldDict);
+ for(;it.current(); ++it)
+ {
+ fprintf(fInputFile, "%08lx\n", it.currentKey());
+ }
+ inputFile.close();
+ QCString command;
+ command.sprintf("addr2line -e %s -f -C -s < %s > %s", appname,
+ QFile::encodeName(KProcess::quote(inputFile.name())).data(),
+ QFile::encodeName(KProcess::quote(outputFile.name())).data());
+ system(command.data());
+ fInputFile = fopen(QFile::encodeName(outputFile.name()), "r");
+ if (!fInputFile)
+ {
+ fprintf(stderr, "Error opening temp file.\n");
+ return;
+ }
+ QIntDictIterator<char> it2(oldDict);
+ char buffer1[1024];
+ char buffer2[1024];
+ for(;it2.current(); ++it2)
+ {
+ if (feof(fInputFile))
+ {
+ fprintf(stderr, "Premature end of symbol output.\n");
+ fclose(fInputFile);
+ return;
+ }
+ if (!fgets(buffer1, 1023, fInputFile)) continue;
+ if (!fgets(buffer2, 1023, fInputFile)) continue;
+ buffer1[strlen(buffer1)-1]=0;
+ buffer2[strlen(buffer2)-1]=0;
+ QCString symbol;
+ symbol.sprintf("%s(%s)", buffer2, buffer1);
+ if(*buffer1 != '?')
+ symbolDict->replace(it2.currentKey(),qstrdup(symbol.data()));
+ }
+ fclose(fInputFile);
+}
+
+int match(const char *s1, const char *s2)
+{
+ register int result;
+ while(true)
+ {
+ result = *s1 - *s2;
+ if (result)
+ return result;
+ s1++;
+ s2++;
+ if (!*s2) return 0;
+ if (!*s1) return -1;
+ }
+ return 0;
+}
+
+const char *lookupAddress(int addr)
+{
+ char *str = formatDict->find(addr);
+ if (str) return str;
+ QCString s = symbolDict->find(addr);
+ if (s.isEmpty())
+ {
+fprintf(stderr, "Error!\n");
+ exit(1);
+ }
+ else
+ {
+ int start = s.find('(');
+ int end = s.findRev('+');
+ if (end < 0)
+ end = s.findRev(')');
+ if ((start > 0) && (end > start))
+ {
+ QCString symbol = s.mid(start+1, end-start-1);
+ char *res = 0;
+ if (symbol.find(')') == -1)
+ res = cplus_demangle(symbol.data(), DMGL_PARAMS | DMGL_AUTO | DMGL_ANSI );
+
+ if (res)
+ {
+ symbol = res;
+ free(res);
+ }
+ res = (char *) symbol.data();
+ for(const char *it = excludes->first();it;it = excludes->next())
+ {
+ int i = match(res, it);
+ if (i == 0)
+ {
+ formatDict->insert(addr,excluded);
+ return excluded;
+ }
+ }
+ s.replace(start+1, end-start-1, symbol);
+ }
+ }
+ str = qstrdup(s.data());
+ formatDict->insert(addr,str);
+ return str;
+}
+
+void dumpBlocks()
+{
+ int filterBytes = 0;
+ int filterCount = 0;
+ for(Entry *entry = entryList->first();entry; entry = entryList->next())
+ {
+ for(int i = 0; entry->backtrace[i]; i++)
+ {
+ const char *str = lookupAddress(entry->backtrace[i]);
+ if (str == excluded)
+ {
+ entry->total_size = 0;
+ continue;
+ }
+ }
+ if (!entry->total_size) continue;
+ filterBytes += entry->total_size;
+ filterCount++;
+ }
+ printf("Leaked memory after filtering: %d bytes in %d blocks.\n", filterBytes, filterCount);
+ for(Entry *entry = entryList->first();entry; entry = entryList->next())
+ {
+ if (!entry->total_size) continue;
+ printf("[%d bytes in %d blocks, 1st. block is %d bytes at 0x%08x] ", entry->total_size, entry->count, entry->size, entry->base);
+ printf("\n");
+ for(int i = 0; entry->backtrace[i]; i++)
+ {
+ const char *str = lookupAddress(entry->backtrace[i]);
+ printf(" 0x%08x %s\n", entry->backtrace[i], str);
+ }
+ }
+}
+
+struct TreeEntry
+{
+ int address; // backtrace
+ int total_size;
+ int total_count;
+ typedef QValueList < TreeEntry > TreeList;
+ TreeList *subentries () const;
+ mutable TreeList *_subentries;
+ TreeEntry (int adr = 0, int size = 0, int count = 0, TreeList * sub = NULL );
+ bool operator == (const TreeEntry &) const;
+ bool operator < (const TreeEntry &) const;
+};
+
+typedef QValueList < TreeEntry > TreeList;
+
+inline TreeEntry::TreeEntry (int adr, int size, int count, TreeList * sub)
+ : address (adr), total_size (size), total_count (count), _subentries (sub)
+{
+}
+
+inline bool TreeEntry::operator == (const TreeEntry & r) const
+{ // this one is for QValueList
+ return address == r.address;
+}
+
+inline
+bool TreeEntry::operator < (const TreeEntry & r) const
+{ // this one is for qBubbleSort() ... yes, ugly hack
+ // the result is also reversed to get descending order
+ return total_size > r.total_size;
+}
+
+inline TreeList * TreeEntry::subentries () const
+{ // must be allocated only on-demand
+ if (_subentries == NULL)
+ _subentries = new TreeList; // this leaks memory, but oh well
+ return _subentries;
+}
+
+TreeList * treeList = 0;
+
+void buildTree ()
+{
+ for (Entry * entry = entryList->first ();
+ entry != NULL; entry = entryList->next ())
+ {
+ if (!entry->total_size)
+ continue;
+ TreeList * list = treeList;
+ int i;
+ for (i = 0; entry->backtrace[i]; ++i)
+ ; // find last (topmost) backtrace entry
+ for (--i; i >= 0; --i)
+ {
+ TreeList::Iterator pos = list->find (entry->backtrace[i]);
+ if (pos == list->end ())
+ {
+ list->prepend (TreeEntry (entry->backtrace[i], entry->total_size,
+ entry->count));
+ pos = list->find (entry->backtrace[i]);
+ }
+ else
+ *pos = TreeEntry (entry->backtrace[i],
+ entry->total_size + (*pos).total_size,
+ entry->count + (*pos).total_count,
+ (*pos)._subentries);
+ list = (*pos).subentries ();
+ }
+ }
+}
+
+void processTree (TreeList * list, int threshold, int maxdepth, int depth)
+{
+ if (++depth > maxdepth && maxdepth > 0) // maxdepth <= 0 means no limit
+ return;
+ for (TreeList::Iterator it = list->begin (); it != list->end ();)
+ {
+ if ((*it).subentries ()->count () > 0)
+ processTree ((*it).subentries (), threshold, maxdepth, depth);
+ if ((*it).total_size < threshold || (depth > maxdepth && maxdepth > 0))
+ {
+ it = list->remove (it);
+ continue;
+ }
+ ++it;
+ }
+ qBubbleSort (*list);
+}
+
+void
+dumpTree (const TreeEntry & entry, int level, char *indent, FILE * file)
+{
+ bool extra_ind = (entry.subentries ()->count () > 0);
+ if(extra_ind)
+ indent[level++] = '+';
+ indent[level] = '\0';
+ char savindent[2];
+ const char * str = lookupAddress (entry.address);
+ fprintf (file, "%s- %d/%d %s[0x%08x]\n", indent,
+ entry.total_size, entry.total_count, str, entry.address);
+ if (level > 1)
+ {
+ savindent[0] = indent[level - 2];
+ savindent[1] = indent[level - 1];
+ if (indent[level - 2] == '+')
+ indent[level - 2] = '|';
+ else if (indent[level - 2] == '\\')
+ indent[level - 2] = ' ';
+ }
+ int pos = 0;
+ int last = entry.subentries ()->count() - 1;
+ for (TreeList::ConstIterator it = entry.subentries ()->begin ();
+ it != entry.subentries ()->end (); ++it)
+ {
+ if (pos == last)
+ indent[level - 1] = '\\';
+ dumpTree ((*it), level, indent, file);
+ ++pos;
+ }
+ if (level > 1)
+ {
+ indent[level - 2] = savindent[0];
+ indent[level - 1] = savindent[1];
+ }
+ if (extra_ind)
+ --level;
+ indent[level] = '\0';
+}
+
+void dumpTree (FILE * file)
+{
+ char indent[1024];
+ indent[0] = '\0';
+ for (TreeList::ConstIterator it = treeList->begin ();
+ it != treeList->end (); ++it)
+ dumpTree (*it, 0, indent, file);
+}
+
+void createTree (const QCString & treefile, int threshold, int maxdepth)
+{
+ FILE * file = fopen (treefile, "w");
+ if (file == NULL)
+ {
+ fprintf (stderr, "Can't write tree file.\n");
+ return;
+ }
+ treeList = new TreeList;
+ buildTree ();
+ processTree (treeList, threshold, maxdepth, 0);
+ dumpTree (file);
+ fclose (file);
+}
+
+void readExcludeFile(const char *name)
+{
+ FILE *stream = fopen(name, "r");
+ if (!stream)
+ {
+ fprintf(stderr, "Error: Can't open %s.\n", name);
+ exit(1);
+ }
+ char line[1024];
+ while(!feof(stream))
+ {
+ if (!fgets(line, 1023, stream)) break;
+ if ((line[0] == 0) || (line[0] == '#')) continue;
+ line[strlen(line)-1] = 0;
+ excludes->append(line);
+ }
+ fclose(stream);
+ excludes->sort();
+}
+
+static KCmdLineOptions options[] =
+{
+ { "x", 0, 0 },
+ { "exclude <file>", "File containing symbols to exclude from output", 0},
+ { "e", 0, 0 },
+ { "exe <file>", "Executable to use for looking up unknown symbols", 0},
+ { "+<trace-log>", "Log file to investigate", 0},
+ {"t", 0, 0},
+ {"tree <file>", "File to write allocations tree", 0},
+ {"th", 0, 0},
+ {"treethreshold <value>",
+ "Don't print subtrees which allocated less than <value> memory", 0},
+ {"td", 0, 0},
+ {"treedepth <value>",
+ "Don't print subtrees that are deeper than <value>", 0},
+ KCmdLineLastOption
+};
+
+int main(int argc, char *argv[])
+{
+ KInstance instance("kmtrace");
+
+ KCmdLineArgs::init(argc, argv, "kmtrace", "KDE Memory leak tracer", "v1.0");
+
+ KCmdLineArgs::addCmdLineOptions(options);
+
+ KCmdLineArgs *args = KCmdLineArgs::parsedArgs();
+
+ (void) args->count();
+ const char *logfile;
+ if(args->count())
+ logfile = args->arg(0);
+ else
+ logfile = "ktrace.out";
+
+ QCString exe = args->getOption("exe");
+ QCString exclude;
+
+ excludes = new QStrList;
+
+ exclude = QFile::encodeName(locate("data", "kmtrace/kde.excludes"));
+ if(!exclude.isEmpty())
+ readExcludeFile(exclude);
+
+ exclude = args->getOption("exclude");
+ if (!exclude.isEmpty())
+ {
+ fprintf(stderr, "Reading %s\n", exclude.data());
+ readExcludeFile(exclude);
+ }
+
+ FILE *stream = fopen(logfile, "r");
+ if (!stream)
+ {
+ fprintf(stderr, "Can't open %s\n", logfile);
+ exit(1);
+ }
+
+ entryDict = new QIntDict<Entry>(9973);
+ symbolDict = new QIntDict<char>(9973);
+ formatDict = new QIntDict<char>(9973);
+ entryList = new QSortedList<Entry>;
+
+ fprintf(stderr, "Running\n");
+ QCString line;
+ char line2[1024];
+ while(!feof(stream))
+ {
+ fgets(line2, 1023, stream);
+ line2[strlen(line2)-1] = 0;
+ if (line2[0] == '=')
+ {
+ printf("%s\n", line2);
+ if( strcmp( line2, "= End" ) == 0 )
+ break;
+ }
+ else if (line2[0] == '#')
+ {
+ QCString app(line2+1);
+ if(exe.isEmpty())
+ {
+ exe = app.stripWhiteSpace();
+ fprintf(stderr, "ktrace.out: malloc trace of %s\n", exe.data());
+ }
+ else if(!app.contains(exe.data()))
+ {
+ fprintf(stderr, "trace file was for application '%s', not '%s'\n", app.data(), exe.data());
+ exit(1);
+ }
+ }
+ else if (line2[0] == '@')
+ line = 0;
+ else if (line2[0] == '[')
+ line = line + ' ' + line2;
+ else if (line2[0] == '+')
+ {
+ allocCount++;
+ line = line + ' ' + line2;
+ parseLine(line, '+');
+ line = 0;
+ if (allocCount & 128)
+ {
+ fprintf(stderr, "\rTotal long term allocs: %d still allocated: %d ", allocCount, entryDict->count());
+ }
+ }
+ else if (line2[0] == '-')
+ {
+ line = line + ' ' + line2;
+ parseLine(line, '-');
+ line = 0;
+ }
+ else if (line2[0] == '<')
+ {
+ line2[0] = '-';
+ // First part of realloc (free)
+ QCString reline = line + ' ' + line2;
+ parseLine(reline, '-');
+ }
+ else if (line2[0] == '>')
+ {
+ line2[0] = '+';
+ // Second part of realloc (alloc)
+ line = line + ' ' + line2;
+ parseLine(line, '+');
+ line = 0;
+ }
+ else
+ {
+ char *addr = index(line2,'[');
+ if (addr)
+ {
+ line = line + ' ' + addr;
+ }
+ }
+ }
+ leakedCount = count;
+ fprintf(stderr, "\rTotal long term allocs: %d still allocated: %d(%d) \n", allocCount, leakedCount, entryDict->count());
+ printf("Totals allocated: %d bytes in %d blocks.\n", totalBytesAlloced, allocCount);
+ printf("Maximum allocated: %d bytes / %d blocks.\n", maxBytes, maxCount);
+ fprintf(stderr, "Collecting duplicates...\n");
+ collectDupes();
+ fprintf(stderr, "Sorting...\n");
+ sortBlocks();
+ printf("Totals leaked: %d bytes in %d blocks.\n", totalBytesLeaked, leakedCount);
+ fprintf(stderr, "Looking up symbols...\n");
+ rewind(stream);
+ lookupSymbols(stream);
+ fprintf(stderr, "Looking up unknown symbols...\n");
+ lookupUnknownSymbols(exe);
+ fprintf(stderr, "Printing...\n");
+ dumpBlocks();
+ QCString treeFile = args->getOption ("tree");
+ if (!treeFile.isEmpty ())
+ {
+ fprintf (stderr, "Creating allocation tree...\n");
+ createTree (treeFile, args->getOption ("treethreshold").toInt (),
+ args->getOption ("treedepth").toInt ());
+ }
+ fprintf(stderr, "Done.\n");
+ return 0;
+}
diff --git a/kmtrace/ksotrace.cpp b/kmtrace/ksotrace.cpp
new file mode 100644
index 00000000..9f379414
--- /dev/null
+++ b/kmtrace/ksotrace.cpp
@@ -0,0 +1,11 @@
+#include "ktrace.h"
+#include <stdlib.h>
+
+class KTraceActivate
+{
+public:
+ KTraceActivate() { setenv("LD_PRELOAD","",1); ktrace(); }
+ ~KTraceActivate() { kuntrace(); }
+} kTraceActivateInstance;
+
+
diff --git a/kmtrace/ktrace.c b/kmtrace/ktrace.c
new file mode 100644
index 00000000..044a1d24
--- /dev/null
+++ b/kmtrace/ktrace.c
@@ -0,0 +1,840 @@
+/* More debugging hooks for `malloc'.
+ Copyright (C) 1991,92,93,94,96,97,98,99,2000 Free Software Foundation, Inc.
+ Written April 2, 1991 by John Gilmore of Cygnus Support.
+ Based on mcheck.c by Mike Haertel.
+ Hacked by AK
+ Cleanup and performance improvements by
+ Chris Schlaeger <cs@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.
+
+ The author may be reached (Email) at the address mike@ai.mit.edu,
+ or (US mail) as Mike Haertel c/o Free Software Foundation.
+*/
+
+#define MALLOC_HOOKS
+#define _GNU_SOURCE
+
+#include <pthread.h>
+#include <malloc.h>
+
+#include <dlfcn.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <execinfo.h>
+#include <unistd.h>
+
+#ifdef USE_IN_LIBIO
+# include <libio/iolibio.h>
+# define setvbuf(s, b, f, l) _IO_setvbuf (s, b, f, l)
+#endif
+
+/* This is the most important parameter. It should be set to two times
+ * the maximum number of mallocs the application uses at a time. Prime
+ * numbers are very good candidates for this value. I added a list of
+ * some prime numbers for conveniance.
+ *
+ * 10007, 20011, 30013, 40031, 50033, 60037, 70039, 80051, 90053,
+ * 100057, 110059, 120067, 130069, 140071, 150077, 160079, 170081,
+ * 180097, 190121, 200131, 210139, 220141, 230143, 240151, 250153,
+ * 260171, 270191, 280199, 290201, 300221, 310223, 320237, 330241,
+ * 340261, 350281, 360287, 370373, 380377, 390389 */
+#define TR_CACHE_SIZE 100057
+
+/* The DELTA value is also a value for the maximum
+ * number of iterations during a positive free/realloc
+ * search. It must NOT divide TR_CACHE_SIZE without
+ * remainder! */
+#define DELTA 23
+
+/* The high and low mark control the flushing algorithm. Whenever the
+ * hashtable reaches the high mark every DELTAth entry is written to
+ * disk until the low filling mark is reached. A hash table becomes
+ * very inefficient when it becomes filled to 50% or more. */
+#define TR_HIGH_MARK ((int) (TR_CACHE_SIZE * 0.5))
+#define TR_LOW_MARK ((int) (TR_HIGH_MARK - (TR_CACHE_SIZE / DELTA)))
+
+/* Maximum call stack depth. No checking for overflows
+ * is done. Adjust this value with care! */
+#define TR_BT_SIZE 100
+
+#define PROFILE 1
+
+/* The hash function. Since the smallest allocated block is probably
+ * not smaller than 8 bytes we ignore the last 3 LSBs. */
+#define HASHFUNC(a) (((((unsigned long) a) << 1) ^ \
+ (((unsigned long) a) >> 3)) % \
+ TR_CACHE_SIZE)
+
+#define TR_HASHTABLE_SIZE 9973
+
+#define TR_NONE 0
+#define TR_MALLOC 1
+#define TR_REALLOC 2
+#define TR_FREE 3
+
+#define TRACE_BUFFER_SIZE 512
+
+typedef struct
+{
+ void* ptr;
+ size_t size;
+ int bt_size;
+ void** bt;
+} tr_entry;
+
+typedef struct CallerNode
+{
+ void* funcAdr;
+ unsigned long mallocs;
+ unsigned long mallocsSum;
+ unsigned int noCallees;
+ unsigned int maxCallees;
+ struct CallerNode** callees;
+} CallerNode;
+
+void ktrace(void);
+void kuntrace(void);
+
+static void addAllocationToTree(void);
+
+static void tr_freehook __P ((void*, const void*));
+static void* tr_reallochook __P ((void*, size_t,
+ const void*));
+static void* tr_mallochook __P ((size_t, const void*));
+/* Old hook values. */
+static void (*tr_old_free_hook) __P ((void* ptr, const void*));
+static void* (*tr_old_malloc_hook) __P ((size_t size,
+ const void*));
+static void* (*tr_old_realloc_hook) __P ((void* ptr,
+ size_t size,
+ const void*));
+
+static FILE* mallstream;
+static char malloc_trace_buffer[TRACE_BUFFER_SIZE];
+
+
+/* Address to breakpoint on accesses to... */
+void* mallwatch;
+
+static pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;
+
+
+static int bt_size;
+static void *bt[TR_BT_SIZE + 1];
+static char tr_offsetbuf[20];
+static tr_entry tr_cache[TR_CACHE_SIZE];
+static int tr_cache_level;
+static int tr_cache_pos;
+static int tr_max_offset = 0;
+static void *tr_hashtable[TR_HASHTABLE_SIZE];
+#ifdef PROFILE
+static unsigned long tr_mallocs = 0;
+static unsigned long tr_logged_mallocs = 0;
+static unsigned long tr_frees = 0;
+static unsigned long tr_logged_frees = 0;
+static unsigned long tr_current_mallocs = 0;
+static unsigned long tr_max_mallocs = 0;
+static unsigned long tr_flashes = 0;
+static unsigned long tr_failed_free_lookups = 0;
+static unsigned long tr_malloc_collisions = 0;
+#endif
+
+static CallerNode* CallTree = NULL;
+static char* mallTreeFile = NULL;
+static FILE* mallTreeStream = NULL;
+static long mallThreshold = 2000;
+
+/* This function is called when the block being alloc'd, realloc'd, or
+ * freed has an address matching the variable "mallwatch". In a
+ * debugger, set "mallwatch" to the address of interest, then put a
+ * breakpoint on tr_break. */
+void tr_break __P ((void));
+void
+tr_break()
+{
+}
+
+__inline__ static void
+tr_backtrace(void **_bt, int size)
+{
+ int i;
+ Dl_info info;
+ for (i = 0; i < size; i++)
+ {
+ long hash = (((unsigned long)_bt[i]) / 4) % TR_HASHTABLE_SIZE;
+ if ((tr_hashtable[hash]!= _bt[i]) && dladdr(_bt[i], &info) &&
+ info.dli_fname && *info.dli_fname)
+ {
+ if (_bt[i] >= (void *) info.dli_saddr)
+ sprintf(tr_offsetbuf, "+%#lx", (unsigned long)
+ (_bt[i] - info.dli_saddr));
+ else
+ sprintf(tr_offsetbuf, "-%#lx", (unsigned long)
+ (info.dli_saddr - _bt[i]));
+ fprintf(mallstream, "%s%s%s%s%s[%p]\n",
+ info.dli_fname ?: "",
+ info.dli_sname ? "(" : "",
+ info.dli_sname ?: "",
+ info.dli_sname ? tr_offsetbuf : "",
+ info.dli_sname ? ")" : "",
+ _bt[i]);
+ tr_hashtable[hash] = _bt[i];
+ }
+ else
+ {
+ fprintf(mallstream, "[%p]\n", _bt[i]);
+ }
+ }
+}
+
+__inline__ static void
+tr_log(const void* caller, void* ptr, void* old,
+ size_t size, int op)
+{
+ int i, offset;
+
+ switch (op)
+ {
+ case TR_FREE:
+ i = HASHFUNC(ptr);
+ if ((offset = (i + tr_max_offset + 1)) >= TR_CACHE_SIZE)
+ offset -= TR_CACHE_SIZE;
+ do
+ {
+ if (tr_cache[i].ptr == ptr)
+ {
+ tr_cache[i].ptr = NULL;
+ free(tr_cache[i].bt);
+ tr_cache_level--;
+ return;
+ }
+ if (++i >= TR_CACHE_SIZE)
+ i = 0;
+#ifdef PROFILE
+ tr_failed_free_lookups++;
+#endif
+ } while (i != offset);
+
+ /* We don't know this allocation, so it has been flushed to disk
+ * already. So flush free as well. */
+ fprintf(mallstream, "@\n");
+ bt_size = backtrace(bt, TR_BT_SIZE);
+ tr_backtrace(&(bt[1]), bt_size - 2);
+ fprintf(mallstream, "- %p\n", ptr);
+#ifdef PROFILE
+ tr_logged_frees++;
+#endif
+ return;
+
+ case TR_REALLOC:
+ /* If old is 0 it's actually a malloc. */
+ if (old)
+ {
+ i = HASHFUNC(old);
+ if ((offset = (i + tr_max_offset + 1)) >= TR_CACHE_SIZE)
+ offset -= TR_CACHE_SIZE;
+ do
+ {
+ if (tr_cache[i].ptr == old)
+ {
+ int j = HASHFUNC(ptr);
+ /* We move the entry otherwise the free will be
+ * fairly expensive due to the wrong place in the
+ * hash table. */
+ tr_cache[i].ptr = NULL;
+ for ( ; ; )
+ {
+ if (tr_cache[j].ptr == NULL)
+ break;
+
+ if (++j >= TR_CACHE_SIZE)
+ i = 0;
+ }
+ tr_cache[j].ptr = ptr;
+ if (ptr)
+ {
+ tr_cache[j].size = tr_cache[i].size;
+ tr_cache[j].bt_size = tr_cache[i].bt_size;
+ tr_cache[j].bt = tr_cache[i].bt;
+ }
+ else
+ tr_cache_level--;
+ tr_cache[i].size = size;
+ return;
+ }
+ if (++i >= TR_CACHE_SIZE)
+ i = 0;
+ } while (i != offset);
+
+ fprintf(mallstream, "@\n");
+ bt_size = backtrace(bt, TR_BT_SIZE);
+ tr_backtrace(&(bt[1]), bt_size - 2);
+ fprintf(mallstream, "< %p\n", old);
+ fprintf(mallstream, "> %p %#lx\n", ptr,
+ (unsigned long) size);
+ return;
+ }
+
+ case TR_MALLOC:
+ if (tr_cache_level >= TR_HIGH_MARK)
+ {
+ /* The hash table becomes ineffective when the high mark has
+ * been reached. We still need some more experience with
+ * the low mark. It's unclear what reasonable values are. */
+#ifdef PROFILE
+ tr_flashes++;
+#endif
+ i = HASHFUNC(ptr);
+ do
+ {
+ if (tr_cache[i].ptr)
+ {
+#ifdef PROFILE
+ tr_logged_mallocs++;
+#endif
+ fprintf(mallstream, "@\n");
+ tr_backtrace(&(tr_cache[i].bt[1]),
+ tr_cache[i].bt_size - 2);
+ fprintf(mallstream, "+ %p %#lx\n",
+ tr_cache[i].ptr,
+ (unsigned long int)
+ tr_cache[i].size);
+ tr_cache[i].ptr = NULL;
+ tr_cache_level--;
+ }
+ if ((i += DELTA) >= TR_CACHE_SIZE)
+ i -= TR_CACHE_SIZE;
+ } while (tr_cache_level > TR_LOW_MARK);
+ }
+
+ i = HASHFUNC(ptr);
+ for ( ; ; )
+ {
+ if (tr_cache[i].ptr == NULL)
+ break;
+
+ if (++i >= TR_CACHE_SIZE)
+ i = 0;
+#ifdef PROFILE
+ tr_malloc_collisions++;
+#endif
+ }
+ if ((offset = (i - HASHFUNC(ptr))) < 0)
+ offset += TR_CACHE_SIZE;
+ if (offset > tr_max_offset)
+ tr_max_offset = offset;
+
+ tr_cache[i].ptr = ptr;
+ tr_cache[i].size = size;
+ tr_cache[i].bt = (void**) malloc(TR_BT_SIZE * sizeof(void*));
+ tr_cache[i].bt_size = backtrace(
+ tr_cache[i].bt, TR_BT_SIZE);
+ tr_cache[i].bt = realloc(tr_cache[i].bt, tr_cache[i].bt_size * sizeof(void*));
+ tr_cache_level++;
+
+ return;
+
+ case TR_NONE:
+ if (tr_cache[tr_cache_pos].ptr)
+ {
+#ifdef PROFILE
+ tr_logged_mallocs++;
+#endif
+ fprintf(mallstream, "@\n");
+ tr_backtrace(&(tr_cache[tr_cache_pos].bt[1]),
+ tr_cache[tr_cache_pos].bt_size - 2);
+ fprintf(mallstream, "+ %p %#lx\n",
+ tr_cache[tr_cache_pos].ptr,
+ (unsigned long int)
+ tr_cache[tr_cache_pos].size);
+ tr_cache[tr_cache_pos].ptr = NULL;
+ free(tr_cache[tr_cache_pos].bt);
+ tr_cache_level--;
+ }
+
+ if (++tr_cache_pos >= TR_CACHE_SIZE)
+ tr_cache_pos = 0;
+ break;
+ }
+}
+
+static void
+tr_freehook (ptr, caller)
+ void* ptr;
+ const void* caller;
+{
+ if (ptr == NULL)
+ return;
+ if (ptr == mallwatch)
+ tr_break ();
+
+ pthread_mutex_lock(&lock);
+#ifdef PROFILE
+ tr_frees++;
+ tr_current_mallocs--;
+#endif
+
+ __free_hook = tr_old_free_hook;
+
+ if (tr_old_free_hook != NULL)
+ (*tr_old_free_hook) (ptr, caller);
+ else
+ free(ptr);
+ tr_log(caller, ptr, 0, 0, TR_FREE);
+
+ __free_hook = tr_freehook;
+ pthread_mutex_unlock(&lock);
+}
+
+static void*
+tr_mallochook (size, caller)
+ size_t size;
+ const void* caller;
+{
+ void* hdr;
+
+ pthread_mutex_lock(&lock);
+
+ __malloc_hook = tr_old_malloc_hook;
+ __realloc_hook = tr_old_realloc_hook;
+ __free_hook = tr_old_free_hook;
+
+ if (tr_old_malloc_hook != NULL)
+ hdr = (void*) (*tr_old_malloc_hook) (size, caller);
+ else
+ hdr = (void*) malloc(size);
+ tr_log(caller, hdr, 0, size, TR_MALLOC);
+ /* We only build the allocation tree if mallTreeFile has been set. */
+ if (mallTreeFile)
+ addAllocationToTree();
+
+ __malloc_hook = tr_mallochook;
+ __realloc_hook = tr_reallochook;
+ __free_hook = tr_freehook;
+
+#ifdef PROFILE
+ tr_mallocs++;
+ tr_current_mallocs++;
+ if (tr_current_mallocs > tr_max_mallocs)
+ tr_max_mallocs = tr_current_mallocs;
+#endif
+ pthread_mutex_unlock(&lock);
+
+ if (hdr == mallwatch)
+ tr_break ();
+
+ return hdr;
+}
+
+static void*
+tr_reallochook (ptr, size, caller)
+ void* ptr;
+ size_t size;
+ const void* caller;
+{
+ void* hdr;
+
+ if (ptr == mallwatch)
+ tr_break ();
+
+ pthread_mutex_lock(&lock);
+
+ __free_hook = tr_old_free_hook;
+ __malloc_hook = tr_old_malloc_hook;
+ __realloc_hook = tr_old_realloc_hook;
+
+ if (tr_old_realloc_hook != NULL)
+ hdr = (void*) (*tr_old_realloc_hook) (ptr, size, caller);
+ else
+ hdr = (void*) realloc (ptr, size);
+
+ tr_log(caller, hdr, ptr, size, TR_REALLOC);
+
+ __free_hook = tr_freehook;
+ __malloc_hook = tr_mallochook;
+ __realloc_hook = tr_reallochook;
+
+#ifdef PROFILE
+ /* If ptr is 0 there was no previos malloc of this location */
+ if (ptr == NULL)
+ {
+ tr_mallocs++;
+ tr_current_mallocs++;
+ if (tr_current_mallocs > tr_max_mallocs)
+ tr_max_mallocs = tr_current_mallocs;
+ }
+#endif
+
+ pthread_mutex_unlock(&lock);
+
+ if (hdr == mallwatch)
+ tr_break ();
+
+ return hdr;
+}
+
+void
+addAllocationToTree(void)
+{
+ int bt_size;
+ int i, j;
+ void *bt[TR_BT_SIZE + 1];
+ CallerNode* cn = CallTree;
+ CallerNode** parent = &CallTree;
+
+ bt_size = backtrace(bt, TR_BT_SIZE);
+ for (i = bt_size - 1; i >= 4; i--)
+ {
+ if (cn == NULL)
+ {
+ *parent = cn = (CallerNode*) malloc(sizeof(CallerNode));
+ cn->funcAdr = bt[i];
+ cn->mallocs = 0;
+ cn->noCallees = 0;
+ cn->maxCallees = 0;
+ cn->callees = NULL;
+ }
+ if (i == 4)
+ cn->mallocs++;
+ else
+ {
+ int knownCallee = 0;
+ for (j = 0; j < cn->noCallees; j++)
+ if (bt[i - 1] == cn->callees[j]->funcAdr)
+ {
+ parent = &cn->callees[j];
+ cn = cn->callees[j];
+ knownCallee = 1;
+ break;
+ }
+ if (!knownCallee)
+ {
+ if (cn->noCallees == cn->maxCallees)
+ {
+ /* Copy callees into new, larger array. */
+ CallerNode** tmp;
+ int newSize = 2 * cn->maxCallees;
+ if (newSize == 0)
+ newSize = 4;
+ tmp = (CallerNode**) malloc(newSize * sizeof(CallerNode*));
+ memcpy(tmp, cn->callees,
+ cn->maxCallees * sizeof(CallerNode*));
+ if (cn->callees)
+ free(cn->callees);
+ cn->callees = tmp;
+ memset(&cn->callees[cn->maxCallees], 0,
+ (newSize - cn->maxCallees) * sizeof(CallerNode*));
+ cn->maxCallees = newSize;
+ }
+ parent = &cn->callees[cn->noCallees++];
+ cn = 0;
+ }
+ }
+ }
+}
+
+static int
+removeBranchesBelowThreshold(CallerNode* root)
+{
+ int i;
+ int max;
+
+ if (!root)
+ return (0);
+ for (i = 0; i < root->noCallees; i++)
+ {
+ if (removeBranchesBelowThreshold(root->callees[i]))
+ {
+ free(root->callees[i]);
+ if (root->noCallees > 1)
+ {
+ root->callees[i] = root->callees[root->noCallees - 1];
+ root->callees[root->noCallees - 1] = 0;
+ }
+ else if (root->noCallees == 1)
+ root->callees[i] = 0;
+
+ root->noCallees--;
+ i--;
+ }
+ }
+ if (root->noCallees == 0 && root->mallocs < mallThreshold )
+ return (1);
+
+ return (0);
+}
+
+static void
+dumpCallTree(CallerNode* root, char* indentStr, int rawMode)
+{
+ int i;
+ Dl_info info;
+ char* newIndentStr;
+ size_t indDepth;
+
+ if (!root || !mallTreeStream)
+ return;
+
+ if (rawMode)
+ {
+ fprintf(mallTreeStream, "-");
+ }
+ else
+ {
+ newIndentStr = (char*) malloc(strlen(indentStr) + 2);
+ strcpy(newIndentStr, indentStr);
+ if (root->noCallees > 0)
+ strcat(newIndentStr, "+");
+ indDepth = strlen(newIndentStr);
+ fprintf(mallTreeStream, "%s- ", newIndentStr);
+ }
+
+ if (dladdr(root->funcAdr, &info) && info.dli_fname && *info.dli_fname)
+ {
+ if (root->funcAdr >= (void *) info.dli_saddr)
+ sprintf(tr_offsetbuf, "+%#lx", (unsigned long)
+ (root->funcAdr - info.dli_saddr));
+ else
+ sprintf(tr_offsetbuf, "-%#lx", (unsigned long)
+ (info.dli_saddr - root->funcAdr));
+ fprintf(mallTreeStream, "%s%s%s%s%s[%p]",
+ info.dli_fname ?: "",
+ info.dli_sname ? "(" : "",
+ info.dli_sname ?: "",
+ info.dli_sname ? tr_offsetbuf : "",
+ info.dli_sname ? ")" : "",
+ root->funcAdr);
+ }
+ else
+ {
+ fprintf(mallTreeStream, "[%p]", root->funcAdr);
+ }
+ fprintf(mallTreeStream, ": %lu\n", root->mallocs);
+ if (indDepth > 1 && !rawMode)
+ {
+ if (newIndentStr[indDepth - 2] == '+')
+ newIndentStr[indDepth - 2] = '|';
+ else if (newIndentStr[indDepth - 2] == '\\')
+ newIndentStr[indDepth - 2] = ' ';
+ }
+
+ for (i = 0; i < root->noCallees; i++)
+ {
+ if (rawMode)
+ dumpCallTree(root->callees[i], "", 1);
+ else
+ {
+ if (i == root->noCallees - 1)
+ newIndentStr[indDepth - 1] = '\\';
+ dumpCallTree(root->callees[i], newIndentStr, rawMode);
+ }
+ }
+ if (rawMode)
+ fprintf(mallTreeStream, ".\n");
+ else
+ free(newIndentStr);
+
+}
+
+#ifdef _LIBC
+extern void __libc_freeres (void);
+
+/* This function gets called to make sure all memory the library
+ * allocates get freed and so does not irritate the user when studying
+ * the mtrace output. */
+static void
+release_libc_mem (void)
+{
+ /* Only call the free function if we still are running in mtrace
+ * mode. */
+ /*if (mallstream != NULL)
+ __libc_freeres ();*/
+
+ kuntrace();
+ write(2, "kuntrace()\n", 11);
+}
+#endif
+
+/* We enable tracing if either the environment variable MALLOC_TRACE
+ * or the variable MALLOC_TREE are set, or if the variable mallwatch
+ * has been patched to an address that the debugging user wants us to
+ * stop on. When patching mallwatch, don't forget to set a breakpoint
+ * on tr_break! */
+void
+ktrace()
+{
+#ifdef _LIBC
+ static int added_atexit_handler;
+#endif
+ char* mallfile;
+
+ /* Don't panic if we're called more than once. */
+ if (mallstream != NULL)
+ return;
+
+#ifdef _LIBC
+ /* When compiling the GNU libc we use the secure getenv function
+ * which prevents the misuse in case of SUID or SGID enabled
+ * programs. */
+ mallfile = __secure_getenv("MALLOC_TRACE");
+ mallTreeFile = __secure_getenv("MALLOC_TREE");
+ if( __secure_getenv("MALLOC_THRESHOLD") != NULL )
+ mallThreshold = atol(__secure_getenv("MALLOC_THRESHOLD"));
+#else
+ mallfile = getenv("MALLOC_TRACE");
+ mallTreeFile = getenv("MALLOC_TREE");
+ if( getenv("MALLOC_THRESHOLD") != NULL )
+ mallThreshold = atol(getenv("MALLOC_THRESHOLD"));
+#endif
+ if (mallfile != NULL || mallTreeFile != NULL || mallwatch != NULL)
+ {
+ mallstream = fopen (mallfile != NULL ? mallfile : "/dev/null", "w");
+ if (mallstream != NULL)
+ {
+ char buf[512];
+
+ /* Be sure it doesn't malloc its buffer! */
+ setvbuf (mallstream, malloc_trace_buffer, _IOFBF,
+ TRACE_BUFFER_SIZE);
+ fprintf (mallstream, "= Start\n");
+ memset(buf, 0, sizeof(buf));
+ readlink("/proc/self/exe", buf, sizeof(buf));
+ if(*buf)
+ fprintf (mallstream, "#%s\n", buf);
+
+ /* Save old hooks and hook in our own functions for all
+ * malloc, realloc and free calls */
+ tr_old_free_hook = __free_hook;
+ __free_hook = tr_freehook;
+ tr_old_malloc_hook = __malloc_hook;
+ __malloc_hook = tr_mallochook;
+ tr_old_realloc_hook = __realloc_hook;
+ __realloc_hook = tr_reallochook;
+
+ tr_cache_pos = TR_CACHE_SIZE;
+ do
+ {
+ tr_cache[--tr_cache_pos].ptr = NULL;
+ } while (tr_cache_pos);
+ tr_cache_level = 0;
+
+ memset(tr_hashtable, 0, sizeof(void*) * TR_HASHTABLE_SIZE);
+#ifdef _LIBC
+ if (!added_atexit_handler)
+ {
+ added_atexit_handler = 1;
+ atexit (release_libc_mem);
+ }
+#endif
+ }
+ }
+}
+
+void
+kuntrace()
+{
+ if (mallstream == NULL)
+ return;
+
+ /* restore hooks to original values */
+ __free_hook = tr_old_free_hook;
+ __malloc_hook = tr_old_malloc_hook;
+ __realloc_hook = tr_old_realloc_hook;
+
+ if (removeBranchesBelowThreshold(CallTree))
+ CallTree = 0;
+ if (mallTreeFile)
+ {
+ if (mallTreeStream = fopen(mallTreeFile, "w"))
+ {
+ dumpCallTree(CallTree, "", 0);
+ fclose(mallTreeStream);
+ }
+ }
+
+ /* Flush cache. */
+ while (tr_cache_level)
+ tr_log(NULL, 0, 0, 0, TR_NONE);
+
+ fprintf (mallstream, "= End\n");
+#ifdef PROFILE
+ fprintf(mallstream, "\nMax Mallocs: %8ld Cache Size: %8ld"
+ " Flashes: %8ld\n"
+ "Mallocs: %8ld Frees: %8ld Leaks: %8ld\n"
+ "Logged Mallocs: %8ld Logged Frees: %8ld Logged Leaks: %8ld\n"
+ "Avg. Free lookups: %ld Malloc collisions: %ld Max offset: %ld\n",
+ tr_max_mallocs, TR_CACHE_SIZE, tr_flashes,
+ tr_mallocs, tr_frees, tr_current_mallocs,
+ tr_logged_mallocs, tr_logged_frees,
+ tr_logged_mallocs - tr_logged_frees,
+ tr_frees > 0 ? ( tr_failed_free_lookups / tr_frees ) : 0,
+ tr_malloc_collisions, tr_max_offset);
+#endif
+ fclose (mallstream);
+ mallstream = NULL;
+ write(2, "kuntrace()\n", 11);
+}
+
+int fork()
+{
+ int result;
+ if (mallstream)
+ fflush(mallstream);
+ result = __fork();
+ if (result == 0)
+ {
+ if (mallstream)
+ {
+ close(fileno(mallstream));
+ mallstream = NULL;
+ __free_hook = tr_old_free_hook;
+ __malloc_hook = tr_old_malloc_hook;
+ __realloc_hook = tr_old_realloc_hook;
+ }
+ }
+ return result;
+}
+
+
+static int my_mcount_lock = 0;
+void mcount()
+{
+ Dl_info info;
+ int i = 1;
+ if (my_mcount_lock) return;
+ my_mcount_lock = 1;
+ bt_size = backtrace(bt, TR_BT_SIZE);
+#if 0
+for(i = 1; (i < 5) && (i < bt_size); i++)
+{
+#endif
+ if (dladdr(bt[i], &info) && info.dli_fname && *info.dli_fname)
+ {
+ fprintf(stdout, "%s\n", info.dli_sname ? info.dli_sname : "");
+ }
+ else
+ {
+ fprintf(stdout, "[%p]\n", bt[i]);
+ }
+#if 0
+}
+ fprintf(stdout, "\n");
+#endif
+ my_mcount_lock = 0;
+}
+
diff --git a/kmtrace/ktrace.h b/kmtrace/ktrace.h
new file mode 100644
index 00000000..366f2148
--- /dev/null
+++ b/kmtrace/ktrace.h
@@ -0,0 +1,10 @@
+#ifndef _KTRACE_H
+#define _KTRACE_H
+
+extern "C" {
+/* Activate a standard collection of tracing hooks. */
+extern void ktrace (void);
+extern void kuntrace (void);
+}
+
+#endif /* ktrace.h */
diff --git a/kmtrace/match.cpp b/kmtrace/match.cpp
new file mode 100644
index 00000000..2a9c74b4
--- /dev/null
+++ b/kmtrace/match.cpp
@@ -0,0 +1,73 @@
+#include <qintdict.h>
+#include <stdio.h>
+#include <qstringlist.h>
+#include <qstrlist.h>
+#include <qtextstream.h>
+#include <qsortedlist.h>
+#include <qfile.h>
+#include <qtl.h>
+#include <qvaluelist.h>
+#include <stdlib.h>
+#include <ktempfile.h>
+#include <kinstance.h>
+#include <kstandarddirs.h>
+#include <kcmdlineargs.h>
+
+int main(int argc, char **argv)
+{
+ char buf[1024];
+ if (argc != 3)
+ {
+ fprintf(stderr, "Usage: kmmatch <map-file> <call-file>\n");
+ fprintf(stderr, "\n<map-file> is a file as output by 'nm'.\n");
+ fprintf(stderr, "<call-file> is a file that contains symbols, e.g. a list of all\n"
+ "function calls made by a program.\n");
+ fprintf(stderr, "The program will print all symbols from <call-file> that are present\n"
+ "in <map-file>, in the same order as they appear in <call-file>.\n");
+ return 1;
+ }
+
+ int i = 1;
+ QDict<int> dict(20011);
+
+ FILE *map_file = fopen(argv[1], "r");
+ if (!map_file)
+ {
+ fprintf(stderr, "Error opening '%s'\n", argv[1]);
+ return 1;
+ }
+ while(!feof(map_file))
+ {
+ fgets(buf, 1024, map_file);
+ QString line = QString::fromLatin1(buf).stripWhiteSpace();
+ QStringList split = QStringList::split(' ', line);
+ if (split.count() <= 1)
+ return 1;
+
+ if (split[1] == "T")
+ {
+ dict.insert(split[2], &i);
+ }
+ }
+ fclose(map_file);
+
+ FILE *call_file = fopen(argv[2], "r");
+ if (!call_file)
+ {
+ fprintf(stderr, "Error opening '%s'\n", argv[2]);
+ return 1;
+ }
+
+ while(!feof(call_file))
+ {
+ fgets(buf, 1024, call_file);
+ QString line = QString::fromLatin1(buf).stripWhiteSpace();
+ if (dict.find(line))
+ {
+ qWarning("%s", line.latin1());
+ }
+ }
+ fclose(call_file);
+ return 0;
+}
+
diff --git a/kmtrace/mtrace.c b/kmtrace/mtrace.c
new file mode 100644
index 00000000..26c08ae6
--- /dev/null
+++ b/kmtrace/mtrace.c
@@ -0,0 +1,383 @@
+/* More debugging hooks for `malloc'.
+ Copyright (C) 1991,92,93,94,96,97,98,99,2000 Free Software Foundation, Inc.
+ Written April 2, 1991 by John Gilmore of Cygnus Support.
+ Based on mcheck.c by Mike Haertel.
+ Hacked by AK
+
+ 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.
+
+ The author may be reached (Email) at the address mike@ai.mit.edu,
+ or (US mail) as Mike Haertel c/o Free Software Foundation. */
+
+#define _LIBC
+#define MALLOC_HOOKS
+
+#ifndef _MALLOC_INTERNAL
+#define _MALLOC_INTERNAL
+#include <malloc.h>
+#include <mcheck.h>
+#include <bits/libc-lock.h>
+#endif
+
+#include <dlfcn.h>
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+
+#include <stdio-common/_itoa.h>
+#include <elf/ldsodefs.h>
+
+#ifdef USE_IN_LIBIO
+# include <libio/iolibio.h>
+# define setvbuf(s, b, f, l) _IO_setvbuf (s, b, f, l)
+#endif
+
+#define TRACE_BUFFER_SIZE 512
+
+static FILE *mallstream;
+static const char mallenv[]= "MALLOC_TRACE";
+static char malloc_trace_buffer[TRACE_BUFFER_SIZE];
+
+__libc_lock_define_initialized (static, lock)
+
+/* Address to breakpoint on accesses to... */
+__ptr_t mallwatch;
+
+/* File name and line number information, for callers that had
+ the foresight to call through a macro. */
+char *_mtrace_file;
+int _mtrace_line;
+
+/* Old hook values. */
+static void (*tr_old_free_hook) __P ((__ptr_t ptr, const __ptr_t));
+static __ptr_t (*tr_old_malloc_hook) __P ((__malloc_size_t size,
+ const __ptr_t));
+static __ptr_t (*tr_old_realloc_hook) __P ((__ptr_t ptr,
+ __malloc_size_t size,
+ const __ptr_t));
+
+#define TR_PIPELINE_SIZE 16
+#define TR_BT_SIZE 80
+#define TR_HASHTABLE_SIZE 9973
+
+#define TR_NONE 0
+#define TR_MALLOC 1
+#define TR_REALLOC 2
+#define TR_FREE 3
+
+typedef struct {
+ int op;
+ __ptr_t ptr;
+ __ptr_t old;
+ __malloc_size_t size;
+ int bt_size;
+ void *bt[TR_BT_SIZE+1];
+} tr_entry;
+
+static tr_entry tr_pipeline[TR_PIPELINE_SIZE];
+static int tr_pipeline_pos;
+static void *tr_hashtable[TR_HASHTABLE_SIZE];
+
+
+/* This function is called when the block being alloc'd, realloc'd, or
+ freed has an address matching the variable "mallwatch". In a debugger,
+ set "mallwatch" to the address of interest, then put a breakpoint on
+ tr_break. */
+
+void tr_break __P ((void));
+void
+tr_break ()
+{
+}
+
+static void
+tr_backtrace(void **bt, int size)
+{
+ char buf[20];
+ int i;
+ Dl_info info;
+ for(i = 0; i < size; i++)
+ {
+ long hash = (((unsigned long)bt[i]) / 4) % TR_HASHTABLE_SIZE;
+ if ((tr_hashtable[hash]!= bt[i]) && _dl_addr(bt[i], &info) && info.dli_fname && *info.dli_fname)
+ {
+ if (bt[i] >= (void *) info.dli_saddr)
+ sprintf(buf, "+%#lx", (unsigned long)(bt[i] - info.dli_saddr));
+ else
+ sprintf(buf, "-%#lx", (unsigned long)(info.dli_saddr - bt[i]));
+ fprintf(mallstream, "%s%s%s%s%s[%p]\n",
+ info.dli_fname ?: "",
+ info.dli_sname ? "(" : "",
+ info.dli_sname ?: "",
+ info.dli_sname ? buf : "",
+ info.dli_sname ? ")" : "",
+ bt[i]);
+ tr_hashtable[hash] = bt[i];
+ }
+ else {
+ fprintf(mallstream, "[%p]\n", bt[i]);
+ }
+ }
+}
+
+static void
+inline
+tr_log(const __ptr_t caller, __ptr_t ptr, __ptr_t old, __malloc_size_t size, int op)
+{
+ switch(op)
+ {
+ case TR_REALLOC:
+ break;
+ case TR_MALLOC:
+ break;
+ case TR_FREE:
+ {
+ int i = tr_pipeline_pos;
+ do {
+ if (i) i--; else i = TR_PIPELINE_SIZE-1;
+ if (tr_pipeline[i].ptr == ptr)
+ {
+ if (tr_pipeline[i].op == TR_MALLOC)
+ {
+ tr_pipeline[i].op = TR_NONE;
+ tr_pipeline[i].ptr = NULL;
+ return;
+ }
+ break;
+ }
+ } while (i != tr_pipeline_pos);
+ }
+ }
+
+ if (tr_pipeline[tr_pipeline_pos].op)
+ {
+ putc('@', mallstream);
+ putc('\n', mallstream);
+ /* Generate backtrace...
+ * We throw out the first frame (tr_mallochook)
+ * end the last one (_start)
+ */
+ tr_backtrace(&(tr_pipeline[tr_pipeline_pos].bt[1]),
+ tr_pipeline[tr_pipeline_pos].bt_size-2);
+
+ switch(tr_pipeline[tr_pipeline_pos].op)
+ {
+ case TR_MALLOC:
+ fprintf (mallstream, "+ %p %#lx\n",
+ tr_pipeline[tr_pipeline_pos].ptr,
+ (unsigned long int) tr_pipeline[tr_pipeline_pos].size);
+ break;
+ case TR_FREE:
+ fprintf (mallstream, "- %p\n",
+ tr_pipeline[tr_pipeline_pos].ptr);
+ break;
+ case TR_REALLOC:
+ fprintf (mallstream, "< %p\n",
+ tr_pipeline[tr_pipeline_pos].old);
+ fprintf (mallstream, "> %p %#lx\n",
+ tr_pipeline[tr_pipeline_pos].ptr,
+ (unsigned long int) tr_pipeline[tr_pipeline_pos].size);
+ break;
+ }
+ }
+
+ tr_pipeline[tr_pipeline_pos].op = op;
+ tr_pipeline[tr_pipeline_pos].ptr = ptr;
+ tr_pipeline[tr_pipeline_pos].old = old;
+ tr_pipeline[tr_pipeline_pos].size = size;
+ tr_pipeline[tr_pipeline_pos].bt_size = backtrace(
+ tr_pipeline[tr_pipeline_pos].bt, TR_BT_SIZE);
+ tr_pipeline_pos++;
+ if (tr_pipeline_pos == TR_PIPELINE_SIZE)
+ tr_pipeline_pos = 0;
+}
+
+static void tr_freehook __P ((__ptr_t, const __ptr_t));
+static void
+tr_freehook (ptr, caller)
+ __ptr_t ptr;
+ const __ptr_t caller;
+{
+ if (ptr == NULL)
+ return;
+ __libc_lock_lock (lock);
+ tr_log(caller, ptr, 0, 0, TR_FREE );
+ __libc_lock_unlock (lock);
+ if (ptr == mallwatch)
+ tr_break ();
+ __libc_lock_lock (lock);
+ __free_hook = tr_old_free_hook;
+ if (tr_old_free_hook != NULL)
+ (*tr_old_free_hook) (ptr, caller);
+ else
+ free (ptr);
+ __free_hook = tr_freehook;
+ __libc_lock_unlock (lock);
+}
+
+static __ptr_t tr_mallochook __P ((__malloc_size_t, const __ptr_t));
+static __ptr_t
+tr_mallochook (size, caller)
+ __malloc_size_t size;
+ const __ptr_t caller;
+{
+ __ptr_t hdr;
+
+ __libc_lock_lock (lock);
+
+ __malloc_hook = tr_old_malloc_hook;
+ if (tr_old_malloc_hook != NULL)
+ hdr = (__ptr_t) (*tr_old_malloc_hook) (size, caller);
+ else
+ hdr = (__ptr_t) malloc (size);
+ __malloc_hook = tr_mallochook;
+
+ tr_log(caller, hdr, 0, size, TR_MALLOC);
+
+ __libc_lock_unlock (lock);
+
+ if (hdr == mallwatch)
+ tr_break ();
+
+ return hdr;
+}
+
+static __ptr_t tr_reallochook __P ((__ptr_t, __malloc_size_t, const __ptr_t));
+static __ptr_t
+tr_reallochook (ptr, size, caller)
+ __ptr_t ptr;
+ __malloc_size_t size;
+ const __ptr_t caller;
+{
+ __ptr_t hdr;
+
+ if (ptr == mallwatch)
+ tr_break ();
+
+ __libc_lock_lock (lock);
+
+ __free_hook = tr_old_free_hook;
+ __malloc_hook = tr_old_malloc_hook;
+ __realloc_hook = tr_old_realloc_hook;
+ if (tr_old_realloc_hook != NULL)
+ hdr = (__ptr_t) (*tr_old_realloc_hook) (ptr, size, caller);
+ else
+ hdr = (__ptr_t) realloc (ptr, size);
+ __free_hook = tr_freehook;
+ __malloc_hook = tr_mallochook;
+ __realloc_hook = tr_reallochook;
+
+ tr_log(caller, hdr, ptr, size, TR_REALLOC);
+
+ __libc_lock_unlock (lock);
+
+ if (hdr == mallwatch)
+ tr_break ();
+
+ return hdr;
+}
+
+
+#ifdef _LIBC
+extern void __libc_freeres (void);
+
+/* This function gets called to make sure all memory the library
+ allocates get freed and so does not irritate the user when studying
+ the mtrace output. */
+static void
+release_libc_mem (void)
+{
+ /* Only call the free function if we still are running in mtrace mode. */
+ if (mallstream != NULL)
+ __libc_freeres ();
+}
+#endif
+
+
+/* We enable tracing if either the environment variable MALLOC_TRACE
+ is set, or if the variable mallwatch has been patched to an address
+ that the debugging user wants us to stop on. When patching mallwatch,
+ don't forget to set a breakpoint on tr_break! */
+
+void
+mtrace ()
+{
+#ifdef _LIBC
+ static int added_atexit_handler;
+#endif
+ char *mallfile;
+
+ /* Don't panic if we're called more than once. */
+ if (mallstream != NULL)
+ return;
+
+#ifdef _LIBC
+ /* When compiling the GNU libc we use the secure getenv function
+ which prevents the misuse in case of SUID or SGID enabled
+ programs. */
+ mallfile = __secure_getenv (mallenv);
+#else
+ mallfile = getenv (mallenv);
+#endif
+ if (mallfile != NULL || mallwatch != NULL)
+ {
+ mallstream = fopen (mallfile != NULL ? mallfile : "/dev/null", "w");
+ if (mallstream != NULL)
+ {
+ /* Be sure it doesn't malloc its buffer! */
+ setvbuf (mallstream, malloc_trace_buffer, _IOFBF, TRACE_BUFFER_SIZE);
+ fprintf (mallstream, "= Start\n");
+ tr_old_free_hook = __free_hook;
+ __free_hook = tr_freehook;
+ tr_old_malloc_hook = __malloc_hook;
+ __malloc_hook = tr_mallochook;
+ tr_old_realloc_hook = __realloc_hook;
+ __realloc_hook = tr_reallochook;
+
+ tr_pipeline_pos = TR_PIPELINE_SIZE;
+ for(;tr_pipeline_pos--;)
+ {
+ tr_pipeline[tr_pipeline_pos].op = TR_NONE;
+ tr_pipeline[tr_pipeline_pos].ptr = NULL;
+ }
+ memset(tr_hashtable, 0, sizeof(void *)*TR_HASHTABLE_SIZE);
+#ifdef _LIBC
+ if (!added_atexit_handler)
+ {
+ added_atexit_handler = 1;
+ atexit (release_libc_mem);
+ }
+#endif
+ }
+ }
+}
+
+void
+muntrace ()
+{
+ if (mallstream == NULL)
+ return;
+
+ fprintf (mallstream, "= End\n");
+ fclose (mallstream);
+ mallstream = NULL;
+ __free_hook = tr_old_free_hook;
+ __malloc_hook = tr_old_malloc_hook;
+ __realloc_hook = tr_old_realloc_hook;
+}
+
+
diff --git a/kompare/AUTHORS b/kompare/AUTHORS
new file mode 100644
index 00000000..72381951
--- /dev/null
+++ b/kompare/AUTHORS
@@ -0,0 +1,2 @@
+Otto Bruggeman <otto.bruggeman@home.nl>
+John Firebaugh <jfirebaugh@kde.org>
diff --git a/kompare/COPYING b/kompare/COPYING
new file mode 100644
index 00000000..8832c184
--- /dev/null
+++ b/kompare/COPYING
@@ -0,0 +1,340 @@
+ GNU GENERAL PUBLIC LICENSE
+ Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+ 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users. This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it. (Some other Free Software Foundation software is covered by
+the GNU Library General Public License instead.) You can apply it to
+your programs, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+ To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have. You must make sure that they, too, receive or can get the
+source code. And you must show them these terms so they know their
+rights.
+
+ We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+ Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software. If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+ Finally, any free program is threatened constantly by software
+patents. We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary. To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ GNU GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License. The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language. (Hereinafter, translation is included without limitation in
+the term "modification".) Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+ 1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+ 2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) You must cause the modified files to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ b) You must cause any work that you distribute or publish, that in
+ whole or in part contains or is derived from the Program or any
+ part thereof, to be licensed as a whole at no charge to all third
+ parties under the terms of this License.
+
+ c) If the modified program normally reads commands interactively
+ when run, you must cause it, when started running for such
+ interactive use in the most ordinary way, to print or display an
+ announcement including an appropriate copyright notice and a
+ notice that there is no warranty (or else, saying that you provide
+ a warranty) and that users may redistribute the program under
+ these conditions, and telling the user how to view a copy of this
+ License. (Exception: if the Program itself is interactive but
+ does not normally print such an announcement, your work based on
+ the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+ a) Accompany it with the complete corresponding machine-readable
+ source code, which must be distributed under the terms of Sections
+ 1 and 2 above on a medium customarily used for software interchange; or,
+
+ b) Accompany it with a written offer, valid for at least three
+ years, to give any third party, for a charge no more than your
+ cost of physically performing source distribution, a complete
+ machine-readable copy of the corresponding source code, to be
+ distributed under the terms of Sections 1 and 2 above on a medium
+ customarily used for software interchange; or,
+
+ c) Accompany it with the information you received as to the offer
+ to distribute corresponding source code. (This alternative is
+ allowed only for noncommercial distribution and only if you
+ received the program in object code or executable form with such
+ an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it. For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable. However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License. Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+ 5. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Program or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+ 6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+ 7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all. For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+ 8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded. In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+ 9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time. Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation. If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+ 10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission. For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this. Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+ NO WARRANTY
+
+ 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+ 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+ END OF TERMS AND CONDITIONS
+
+ How to Apply These Terms to Your New Programs
+
+ If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+ To do so, attach the following notices to the program. It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the program's name and a brief idea of what it does.>
+ Copyright (C) 19yy <name of author>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the 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, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+ Gnomovision version 69, Copyright (C) 19yy name of author
+ Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+ This is free software, and you are welcome to redistribute it
+ under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License. Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary. Here is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+ `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+ <signature of Ty Coon>, 1 April 1989
+ Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs. If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library. If this is what you want to do, use the GNU Library General
+Public License instead of this License.
diff --git a/kompare/ChangeLog b/kompare/ChangeLog
new file mode 100644
index 00000000..d9db63b5
--- /dev/null
+++ b/kompare/ChangeLog
@@ -0,0 +1,423 @@
+Dec 27, 2004 : Jeff Snyder
+ * Fix for bug 95640 (nothing displayed when kompare is embedded in Ark
+ fixed by forcing the delivery of childEvents to komparesplitter at
+ the end of its constructor
+
+Dec 20, 2004 : Jeff Snyder
+ * Things that have happened since 3.3:
+ (this list is not complete)
+ * Look & feel changed
+
+Dec 20, 2004 : Jeff Snyder
+ * Things that were changed sometime between Nov 25, 2003 and KDE 3.3:
+ (this list is not complete)
+ * KompareConnectWidget became draggable, by replacing KompareViewFrame
+ with KompareSplitter.
+
+Dec 20, 2004 : Jeff Snyder
+ * This changelog seems to have been neglected for over a year now. I'll
+ try to retroactively fix this as and when I remember things that have
+ been fixed - but it'll probably never be complete and accurate for the
+ Dec 2003 - Nov 2004 period. I'll be making entries concering what i'm
+ doing with kompare from now onwards.
+
+Nov 25, 2003 : Otto Bruggeman
+ * Fix nasty looping to the end of the file when hitting previous difference on the first difference in the first file
+
+Nov 25, 2003 : Laurent Montel
+ * Fix memleak, QStringList is implicitly shared so no need for a reference, it is already a pointer to data thing
+
+Nov 23, 2003 : Otto Bruggeman
+ * Fixed version string (bug 68872)
+ * Fix for 68871 (added slotNextDifference to slotApplyDifference())
+ * Fix for a crash: dont call blendOriginalIntoModelList with Kompare::ShowingDiff
+
+Nov 22, 2003 : Otto Bruggeman
+ * Fix to make the bugs.kde.org dialog pop up instead of sending a mail to John when pressing
+ Help->Report bug... Also added my homepage since it has always been kompare's home imo.
+
+Nov 22, 2003 : Otto Bruggeman
+ * Rework the blendFile method so it actually works and as a bonus is a bit faster
+ This introduces a new form of show entire file when comparing, one that works
+ And because of it, it saves files properly now because the entire file is now available even if
+ you have a single line change in a million line file with only 2 context lines in the diff.
+
+Nov 22, 2003 : Otto Bruggeman
+ * Remove the Show entire file option. It only causes problems at the moment
+ Fixes bug 68729
+
+Nov 22, 2003 : Otto Bruggeman
+ * Commenting out a lot of debug output, it has served it's purpose well in levenshteintable.cpp
+
+Nov 21, 2003 : Otto Bruggeman
+ * Also expand tabs to spaces in strings without or after Commands (in the INLINE_DIFFERENCES
+ code path and yes commands is a shitty name for them but i cant think of something decent)
+
+Nov 21, 2003 : Otto Bruggeman
+ * Real Fix (tm) for activating the Swap source with destination action
+
+Nov 21, 2003 : Otto Bruggeman
+ * Fix empty line drawing in the INLINE_DIFFERENCES code path
+
+Nov 20, 2003 : Otto Bruggeman
+ * When swapping source with destination also change the windows caption and the statusbar text
+ * Make sure that when swapping and when there are changes, all changes that were made can be
+ saved, discarded or cancel the whole swap (strings are recycled from the queryClose method)
+ * Give a better parent to the KIO::NetAccess::download in komparemodellist.cpp
+ * Added some FIXME's for after the branching to make the urls appear in bold in the error message
+ * Make queryClose not use the isModified from the part but from the modellist
+
+Nov 20, 2003 : Otto Bruggeman
+ * Fix for activating the Swap Source with Destination action.
+
+Nov 19, 2003 : Otto Bruggeman
+ * Fixed bug 68570, it needed temp vars otherwise it was overwriting source with destination and then
+ overwriting that destination with source which was just changed into destination
+
+Nov 17, 2003 : Otto Bruggeman
+ * Fix for empty -x and -X arguments.
+ * Fix bugs 58858 and 58531 by using Kompare::Custom instead of Kompare::Default
+ * Fix last selected url in the kurlcomboboxes
+ * Fix for inline differences when there is only 1 char left that still needs to be drawn
+ * Remove support for the -a Treat all files as text diff option. This caused all sorts of weird crashes
+ when parsing the diff output now with the custom options.
+ * Move the per preference page code in the diffprefs constructor into seperate methods per page
+
+Nov 14, 2003 : Otto Bruggeman
+ * Fix to make Kompare listen to the kdisplayFontChanged signal and set the font properly and redraw with the new font.
+ Found by David Faure.
+
+Nov 09, 2003 : Otto Bruggeman
+ * Implemented inline differences (deactivated until KDE3.2 has been branched)
+ * added support for the -x and -X options to diff (deactivated until KDE3.2 has been branched)
+ * Various other code cleanups/reindenting
+
+Nov 09, 2003 : Otto Bruggeman
+ * Code cleanups
+
+Nov 02, 2003 : Otto Bruggeman
+ * Fixed some more scrolling problems
+ lastItem->scrollId(), add lastItem->maxHeight() and substract the minScrollId()
+ That is the maxScrollId i need in the QScrollBar, took me long enough...
+
+Oct 05, 2003 : Otto Bruggeman
+ * Fixed the scrolling problems, a stupid regression i introduced, i cant simplify mathematic expressions apparently
+ * Added an implementation for double clicking a difference in the view, but it is not properly connected yet
+ void contentsMouseDoubleClickEvent ( QMouseEvent* );
+ * Fixed embedding in Konqueror by implementing openURL()
+ * Removed m_maxScrollId, it is not necessary and only costs time, QScrollView::contentsHeight() does the same
+ * Fixed some more warnings about unused variables
+ * Fixed the initial drawing of the vertical and horizontal scrollbar
+
+Oct 04, 2003 : Otto Bruggeman
+ * Added a call to m_modelList->openDirAndDiff to openDirAndDiff
+ * Fixed some error strings by swapping the %# thingies
+ * Added some useless debug output
+ * Fixed KompareModelList::openDirAndDiff to use the right models variable (m_models instead of models)
+
+Oct 03, 2003 : Otto Bruggeman
+ * Fixed ApplyAll and UnApplyAll, stupid copy and paste error
+ * Fixed some warnings about signed and unsigned
+ * Fixed some warnings about unused variables
+ * Fixed some redrawing issues in the connection widget
+
+Sep 27, 2003 : Otto Bruggeman
+ * Fixed the redrawing problems in the connect widget with a QTimer::singleShot()
+ * Undid a stupid commit that changed the keyboard shortcuts for next and previous difference
+ * Fixed another bug in the navigation part that made it emit a signal twice
+ * Fixed a bug in the listview drawing, still one left that i cant seem to solve :(
+
+Sep 27, 2003 : Otto Bruggeman
+ * Moved the apply and navigation actions into the komparemodellist
+ * Fixed Ingo's problem with the next and prev difference KActions
+
+Sep 26, 2003 : Otto Bruggeman
+ * Added a struct Info in the Kompare namespace. This one contains all the info about what kompare is doing
+ * Fixed splitting the path string in diffmodel
+ * Fixed showing the path in komparenavtreepart in the directory listviews
+
+Sep 24, 2003 : Otto Bruggeman
+ * Fixes opening diffs, comparing files after moving all that code around
+
+Sep 23, 2003 : Otto Bruggeman
+ * Moved a lot of url downloading to the kompare part and moved the opening and reading of the downloads to komparemodellist
+
+Sep 22, 2003 : Otto Bruggeman
+ * Added openStdin() to KompareShell
+ * Fixed stupid implicit conversion from QString to QStringList in kompare_part.cpp
+ * Added openDiff( QStringList ) to the interface and to the part
+
+Sep 14, 2003 : Otto Bruggeman
+ * Fixed exit status of the kompare process
+
+Sep 13, 2003 : Otto Bruggeman
+ * Removed some files that apparently came back after the merge
+
+Sep 07, 2003 : Otto Bruggeman
+ * Some changes to the interface. Made the copy ctor and assignment operator
+ and added a private d-pointer
+ * Removed the use of all deprecated methods and replaced them with undeprecated ones :)
+
+Sep 02, 2003 : Scott Wheeler
+ * Made the interface pure virtual
+
+Sep 01, 2003 : Scott Wheeler
+ * Fixed constness of the KompareModelList constructor
+ * Fixed another 2 warnings about comapring signed with unsigned ints
+ * Fixed the initialization of the difault var
+
+Aug 27, 2003 : Otto Bruggeman
+ * After shitloads of trouble here finally some fixes for the stupid desktop
+ file stuff
+ * Fixes for when there are not enough args for a certain commandline option.
+
+Aug 22, 2003 : Otto Bruggeman
+ * Fixed converting tabs to spaces in the view, i totally screwed up
+ * View settings now get applied to the view after pressing ok.
+ (Maybe i should make them apply on APlly instead of OK)
+
+Aug 13, 2003 : Otto Bruggeman
+ * Komkommertijd :) InitialPreference=10 for kompare.desktop as
+ requested
+
+Aug 10, 2003 : Otto Bruggeman
+ * Backported Helge Deller's changes from head to make_it_cool
+ (kompare_shell.cpp 1.33 -> 1.34). This is about roaming user fixes.
+ Thanks Helge !
+
+Jul 19, 2003 : Otto Bruggeman
+ * Backported Ingo Klocker's changes from head to make_it_cool
+ (kompare_shell.cpp 1.34 -> 1.35). This is about being able to
+ configure the shortcuts from kompare_part as well. Thanks Ingo !
+
+Jun 29, 2003 : Otto Bruggeman
+ * Fixed bug 58144 by adding a check for comparing dirs, in that case
+ destinationURL is a directory and not a file name so we need to
+ recreate the filename. This involved changing some code to use a
+ different enum value, so i hope i did it the right way, session
+ management may be broken now when the session was stored with 3.1.2
+ and restarted with 3.1.3. But that is unfortunately unfixable with a
+ kconf_update script.
+
+Jun 29, 2003 : Otto Bruggeman
+ * Removed a lot of commented code since it is no longer used and will
+ never be used again.
+ * Added 2 methods to the interface: openDiff3(KURL) and
+ openDiff3(QStringList)
+ * Fixed context diff parsing as indicated in bugreport 57774
+ (the example works now, hope there are no regressions)
+ * Removed all references to MiscSettings and MiscPrefs.
+ These classes will disappear RSN.
+ * Fixed the history saving of the urls in the kompare dialog
+ * Parser is no longer a static class but one that needs to be
+ instanciated
+ * Added ViewSettings to KompareProcess, maybe it is better to merge the
+ diff and view settings into one class.
+
+May 3, 2003 : Otto Bruggeman
+ * Implemented support for -I in the regular diff options (the one in
+ the kompare options dialog)
+ * Fixed the braindamage i created in main.cpp so that kompare no
+ longer stalls because of a missing mainwindow
+ * Made the kcomparedialog more generic and renamed it to
+ kompareurldialog so i can reuse it for blending too
+ * Removed some braindamage in the kompare/Makefile.am
+ * Some compile fixes because of changes to the CXXFLAGS
+ (QRegExp::match cant be used anymore, and some other old style stuff)
+ * Added an action to the menu for blending
+ * moved Open file (or in this case Open Diff) to the top of the file
+ menu
+ * Fixed the accel conflict in the file menu between open diff and
+ compare files
+
+Apr 30, 2003 : Otto Bruggeman
+ * Implemented blending of a diff file with the original file
+ * Renamed General* View* (more appropriate)
+ * Renamed m_models into m_modelList since it is more appropriate in komparepart
+ * Small fixes to the view, but they break more than they fix :(
+ * Added commandline options for comparing, opening a diff file and
+ blending
+
+Apr 20, 2003 : Otto Bruggeman
+ * Fixed bug 54264 with a statusbar that gets too wide when long
+ filenames are used
+ * Fixed the missing endline problem in the parser (bug 56552)
+ * Fixed all copyright years (probably too many but hey i'll change
+ those files some time this year so it will be valid :P)
+ * Added support for using a different diff program (Bug 55573)
+ * Added support for using a different tabsize in the viewer (Bug 38776)
+ * The interface is now final i guess so this fixes bug 42849, not
+ every method is implemented but i'll get to them eventually.
+
+Apr 19, 2003 : Otto Bruggeman
+ * Fixed bug 56322 where openURL did not clear the models when called
+ again with a new diff
+
+Aug 9, 2002 : Otto Bruggeman
+ * Fixed the whatsthis text for the compare button in the compare dialog
+ * Fixed the history of the comboboxes in the compare dialog
+ * Put the komparemodellist and all needed classes in a Diff2 namespace
+ * Implemented a better parser design (see parser.cpp/h)
+ * Removed the need to directly link to the komparepart for the shellapp
+ * Removed the need to link directly to the komparepart for the navigationpart
+ * Added support for perforce diffs in the new Parser classes
+ * Added a push design for the modified status instead of a pull design
+ * Added an interface to the Komparepart so people can use that to
+ reuse the komparepart
+
+Jul 15, 2002 : Otto Bruggeman
+ * Fixed normal diff a bit more, filenames dont work yet
+ * Removed some code duplication
+ * Fixed diff output parsing with Common subdirectories in it
+ * Fixed Copyright years in the about box (thanks Carsten Niehaus)
+ * Removed the KShellProcess and replaced it with a KProcess
+
+Feb 18, 2002 : Otto Bruggeman
+ * Fixed scrolling with a wheel mouse in the kompare(list)view and
+ connectwidget and added a config option for the number of lines
+ that is scrolled per wheelscroll.
+ * Fixed the history somehow in the compare dialog.
+ * Implemented the separate directory/file widget.
+ * Implemented reading from stdin by using - as file on the commandline.
+ * Partly implemented a better way for ed and rcs parsing, i'll
+ improve this before KDE 3.0 is released
+
+Jan 10, 2002 : Otto Bruggeman
+ Comparing directories works now :) You can select them from the begin
+ dialog, and select a directory and then press ok. It will enter the
+ directory but dont select a file so it keeps the directory.
+ Known bug here is that directories need a trailing slash :(
+
+Oct 07, 2001 : Otto Bruggeman
+ Fix crash when part is not found, basically dont use kapp->quit()
+ but use exit(int). Would be interested to know why it crashes though,
+ the bt gave nothing meaningful here. I should have compiled kompare with
+ debug code.
+
+Sep 17/18, 2001 : Otto Bruggeman
+ Fixed some stuff dont know what anymore (writing this on oct 7)
+ Probably some more fixes for the klibloader.
+
+Sep 17, 2001 : Otto Bruggeman
+ Moved to kdesdk and renamed to kompare with preservation of history.
+ Changed almost every occurence of kdiff to kompare (not in this file).
+
+Sep 08, 2001 : Otto Bruggeman
+ Removed the qt3back dir, changed everything over to qt3,
+ qlist->qptrlist, qlistconstiterator->qptrlistconstiterator
+
+Jul 29, 2001 : John Firebaugh
+ Add some tests.
+ Add the qregexp3 backport.
+ Use qregexp3 for diff parsing -- soooo much cleaner.
+ All the diff options work.
+
+Jul 28, 2001 : John Firebaugh
+ Directories can be selected in the compare dialog
+ New base clase KDiff, holds some common stuff
+ Use an enum for format in preferences
+ Implement a save options dialog, displayed at "Save .diff"
+ The diff can be run in any directory, the paths to source
+ and destination will be automatically determined from this.
+ Save all.
+
+Jul 25, 2001 : John Firebaugh
+ Prompt to save changes on close
+ Show [modified] caption
+ Clean up internal save mechanism
+
+Jul 14, 2001 : John Firebaugh
+ New menu item "Swap source and destination".
+ Make empty selection work.
+
+Jul 13, 2001 : John Firebaugh
+ Text view now works in compare mode.
+ Fix clicking difference to select it.
+ Don't scroll to difference when clicking to select it.
+ Give the diff view a nice frame.
+
+Jul 12, 2001 : Otto Bruggeman
+ Stats work now, maybe they need more info but i dont know what yet.
+ Will think some more about it.
+
+Jul 12, 2001 : John Firebaugh
+ When comparing files, you can apply or unapply changes and save
+ the result.
+ New menu item "Show Text View" (loads the diff in embedded text viewer).
+ Better status notification.
+ Set the window caption when comparing.
+
+Jun 27, 2001 : John Firebaugh
+ Ported main view to QListView
+ Remove obsolete files
+ Clicking a difference in the main view selects it
+ Better scrolling
+
+Jun 24, 2001 : John Firebaugh
+ Coverted to dock window and added navigation tree in a dock.
+ Multiple file diffs are now supported. Each file will show up
+ as an item in the tree, with differences as children.
+
+Jun 22, 2001 : Otto Bruggeman
+ Tried implementing rcs and ed but they dont work atm, same for show
+ diffstats, will fix that asap.
+
+May 22, 2001 : John Firebaugh
+ Reworking of most of the view code. Looks pretty.
+
+May 18, 2001 : Otto Bruggeman
+ Context seems to work, implemented saving... might have some problems
+ left (saving that is)
+
+May 15, 2001 : John Firebaugh
+ Make the settings work for all windows. Probably some more changes :)
+
+May 14, 2001 : Otto Bruggeman
+ context diff does not work atm, there is some problem with the separa-
+ tion of old and new. Maybe the old and new needs to be reintegrated.
+ I fixed some functions and now diffmodel does no longer need static
+ functions. All loading is done from the kdiffpart and that is where
+ save should go as well. Removed determineDiffFormat because it is not
+ needed anymore.
+
+May 13, 2001 : Otto Bruggeman
+ contextdiff is better implemented it finds all stuff in the diff atm
+ but it does not work.
+
+May 04, 2001 : Otto Bruggeman
+ cleaned up the code by moving the part to a subdir
+ halfassed implementation of contextdiff, will update later today
+
+Apr 10, 2001 : John Firebaugh
+ use new model/view architecture (not completely implemented yet)
+ NOTE: it will (should) compile, but you won't see any differences... a
+ work in progress
+
+Apr 05, 2001 : Otto Bruggeman
+ Implemented the ability to move from chuck to chunk in the htmlview
+ Cleaned up the preferences, squashed a few bugs
+
+Apr 04, 2001 : Otto Bruggeman
+ Normal format works as well
+
+Apr 04, 2001 : Otto Bruggeman
+ Finally implemented the preferences menu... i still lack some nice
+ icons for it but that will be solved in the near future...
+
+Mar 25, 2001 : Otto Bruggeman
+ Moved the application icons to the pics dir
+
+Mar 20, 2001 : Otto Bruggeman
+ Fixed a stupid bug that caused the last line in the rightview not
+ to be colored.
+ Implemented slots for using the KHistoryCombo in the views to select
+ files with.
+ Still a nasty bug with regard to the initial directory in the
+ KFileDialog, needs to be fixed asap but i dont know the cause.
+ Still an error in the historylist and completionlist items. They are
+ not shown correctly.
+
+Mar 19, 2001 : Otto Bruggeman
+ Added most of the preferences dialog
+ Some speed improvements
+ Some fixes to use the last used directory in KFileDialog
diff --git a/kompare/DESIGN b/kompare/DESIGN
new file mode 100644
index 00000000..fde8a5c9
--- /dev/null
+++ b/kompare/DESIGN
@@ -0,0 +1,35 @@
+Kompare General design:
+
+Kompare is split up into 4 parts:
+- A shell around the parts
+- A library with the modellist and the parser
+- The navigation tree which uses the library
+- The view part that also uses the library
+
+The diffmodel is comparable to a document and the view part is comparable
+to the view and the komparemodellist is comparable to a documentmanager.
+The navtree can be viewed as a document view manager.
+The model is fully separated from the view and all communication goes
+through signals and slots. The view gets a model that contains all differences
+for the compared files A and B. The view gets this model from the modellist,
+the central entity in the part.
+
+There is an interface to the komparepart that can be used in other programs,
+simply link to the libkompareinterface.la and call its methods after you have
+instanciated a komparepart. There is also a "hidden" signal and slot interface
+that can be connected to from the shell app to get some information, and an
+interface for communication between the navigation part and the komparepart.
+
+There is no need to use the interface for the communication between the
+navigation and kompare parts in the shell app.
+
+Kompare has some debug areas:
+
+8100 kompare
+8101 kompare (libs)
+8102 kompare (shell)
+8103 kompare (part)
+8104 kompare (list view)
+8105 kompare (nav view)
+8106 kompare (connect widget)
+
diff --git a/kompare/Makefile.am b/kompare/Makefile.am
new file mode 100644
index 00000000..bf5297b5
--- /dev/null
+++ b/kompare/Makefile.am
@@ -0,0 +1,43 @@
+SUBDIRS = interfaces libdiff2 libdialogpages komparenavtreepart komparepart pics
+
+INCLUDES = \
+ -I$(srcdir)/libdiff2 \
+ -I$(srcdir)/libdialogpages \
+ -I$(srcdir)/komparenavtreepart \
+ -I$(srcdir)/komparepart \
+ -I$(srcdir)/interfaces \
+ $(all_includes)
+
+noinst_HEADERS = kompare_shell.h kompareurldialog.h
+
+# let automoc handle all of the meta source files (moc)
+METASOURCES = AUTO
+
+messages: rc.cpp
+ $(EXTRACTRC) */*.rc */*.ui >> rc.cpp
+ $(XGETTEXT) `find . -name "*.cpp" -o -name "*.h"` -o $(podir)/kompare.pot
+
+#########################################################################
+# APPLICATION SECTION
+#########################################################################
+# this is the program that gets installed. it's name is used for all
+# of the other Makefile.am variables
+bin_PROGRAMS = kompare
+
+# the application source, library search path, and link libraries
+kompare_SOURCES = main.cpp kompare_shell.cpp kompareurldialog.cpp
+kompare_LDFLAGS = $(all_libraries)
+kompare_LDADD = $(LIB_KPARTS) \
+ $(top_builddir)/kompare/interfaces/libkompareinterface.la \
+ $(top_builddir)/kompare/libdialogpages/libdialogpages.la \
+ -lktexteditor
+
+# this is where the desktop file will go
+xdg_apps_DATA = kompare.desktop
+
+# this is where the shell's XML-GUI resource file goes
+shellrcdir = $(kde_datadir)/kompare
+shellrc_DATA = kompareui.rc
+
+kompareservicedir = $(kde_servicetypesdir)
+kompareservice_DATA = komparenavigationpart.desktop kompareviewpart.desktop
diff --git a/kompare/README b/kompare/README
new file mode 100644
index 00000000..af036f57
--- /dev/null
+++ b/kompare/README
@@ -0,0 +1,16 @@
+Kompare 2.0
+
+Kompare is a program to view the differences between files. Features include:
+
+ * comparison of files or directories via a graphical interface
+ * bezier-based connection widget lets you see both source and destination
+ as they really appear
+ * graphical viewing of patch files in normal, context, unified and
+ diff formats
+ * interactive application of differences
+ * full network transparency
+ * ability to view plain-text diff output in embedded viewer
+ * easy navigation of multiple-file diffs with dockable navigation tree
+ * graphical interface to commonly used diff command line options
+ * switch source and destination with one command
+ * diff statistics
diff --git a/kompare/TODO b/kompare/TODO
new file mode 100644
index 00000000..e87a574f
--- /dev/null
+++ b/kompare/TODO
@@ -0,0 +1,34 @@
+!!! Must do before a merge back into HEAD !!!
+* Write a kconfupdate script to convert the kconfigfile
+ * the diff options now have their own group
+ * the view options now have their own group
+ * the Recent Files group has been renamed to Recent Compare Files
+
+Very important:
+* Make sure unified and context actually work again !
+* Implement the rest of the interface (compare3 etc.)
+* Make sure the rest works too ! Still some problems parsing some files
+* Other various things that need to be fixed asap (before 3.2 is released)
+
+In descending order of importance:
+* Add a kompare manual/document
+* add support for handediting conflicts
+* session management (should almost work)
+* implement normal, ed and rcs format (normal got busted)
+* merge text view GUI
+* clicking in the connect widget should select a difference (tricky!)
+* add support for incremental patch saving (i'll explain if anyone wants to know)
+* Add support for diff3 (that is comparing 3 files at once)
+
+Special requests:
+Puetzk:
+* Editing the TO pane
+Falk:
+* Allow only part of a change to be applied to the other file
+Harlekin:
+* Add search functionality, either in source, dest or both at the same time
+HarryF:
+* emit clicked() signal when on a diff with line number
+aseigo:
+* merge from dest to source instead of only from source to dest
+(Workaround: swap source with destination and then apply the differences)
diff --git a/kompare/interfaces/Makefile.am b/kompare/interfaces/Makefile.am
new file mode 100644
index 00000000..ab8f9b93
--- /dev/null
+++ b/kompare/interfaces/Makefile.am
@@ -0,0 +1,8 @@
+INCLUDES = $(all_includes)
+
+lib_LTLIBRARIES = libkompareinterface.la
+
+libkompareinterface_la_LDFLAGS = -no-undefined $(all_libraries)
+libkompareinterface_la_SOURCES = kompareinterface.cpp
+libkompareinterface_la_LIBADD = $(LIB_QT)
+
diff --git a/kompare/interfaces/kompareinterface.cpp b/kompare/interfaces/kompareinterface.cpp
new file mode 100644
index 00000000..1522bad0
--- /dev/null
+++ b/kompare/interfaces/kompareinterface.cpp
@@ -0,0 +1,60 @@
+// Blah blah standard LGPL license
+// Copyright 2002-2004, Otto Bruggeman <otto.bruggeman@home.nl>
+
+#include "kompareinterface.h"
+
+class KompareInterfacePrivate
+{
+public:
+ KompareInterfacePrivate();
+ ~KompareInterfacePrivate();
+ KompareInterfacePrivate( const KompareInterfacePrivate& );
+ KompareInterfacePrivate& operator=( const KompareInterfacePrivate& );
+
+protected:
+ // Add all variables for the KompareInterface class here and access them through the kip pointer
+};
+
+KompareInterfacePrivate::KompareInterfacePrivate()
+{
+}
+
+KompareInterfacePrivate::~KompareInterfacePrivate()
+{
+}
+
+KompareInterfacePrivate::KompareInterfacePrivate( const KompareInterfacePrivate& /*kip*/ )
+{
+}
+
+KompareInterfacePrivate& KompareInterfacePrivate::operator=(const KompareInterfacePrivate& /*kip*/ )
+{
+ return *this;
+}
+
+KompareInterface::KompareInterface()
+{
+ kip = new KompareInterfacePrivate();
+}
+
+KompareInterface::~KompareInterface()
+{
+ delete kip;
+}
+
+KompareInterface::KompareInterface( const KompareInterface& ki )
+{
+ kip = new KompareInterfacePrivate( *(ki.kip) );
+}
+
+KompareInterface& KompareInterface::operator=( const KompareInterface& ki )
+{
+ kip = ki.kip;
+ return *this;
+}
+
+void KompareInterface::setEncoding( const QString& encoding )
+{
+ m_encoding = encoding;
+}
+
diff --git a/kompare/interfaces/kompareinterface.h b/kompare/interfaces/kompareinterface.h
new file mode 100644
index 00000000..b9c0fcda
--- /dev/null
+++ b/kompare/interfaces/kompareinterface.h
@@ -0,0 +1,105 @@
+// blah blah standard LGPL license
+// Copyright 2002-2003, Otto Bruggeman <otto.bruggeman@home.nl>
+
+#ifndef _KOMPARE_INTERFACE_H
+#define _KOMPARE_INTERFACE_H
+
+#include <qstring.h>
+#include <qstringlist.h>
+#include <kdemacros.h>
+
+class KConfig;
+class KURL;
+
+class KompareInterfacePrivate;
+
+class KDE_EXPORT KompareInterface
+{
+public:
+ KompareInterface();
+ virtual ~KompareInterface();
+
+protected:
+ KompareInterface( const KompareInterface& );
+ KompareInterface& operator=(const KompareInterface& );
+
+public:
+ /**
+ * Open and parse the diff file at url.
+ */
+ virtual bool openDiff( const KURL& diffUrl ) = 0;
+
+ /**
+ * Open and parse the supplied diff output
+ */
+ virtual bool openDiff( const QString& diffOutput ) = 0;
+
+ /**
+ * Open and parse the diff3 file at url.
+ */
+ virtual bool openDiff3( const KURL& diff3Url ) = 0;
+
+ /**
+ * Open and parse the supplied diff3 output
+ */
+ virtual bool openDiff3( const QString& diff3Output ) = 0;
+
+ /**
+ * Compare, with diff, source with destination, can also be used if you dont
+ * know what source and destination are. The part will try to figure out what
+ * they are (directory, file, diff output file) and call the
+ * appropriate method(s)
+ */
+ virtual void compare( const KURL& sourceFile, const KURL& destinationFile ) = 0;
+
+ /**
+ * Compare, with diff, source with destination files
+ */
+ virtual void compareFiles( const KURL& sourceFile, const KURL& destinationFile ) = 0;
+
+ /**
+ * Compare, with diff, source with destination directories
+ */
+ virtual void compareDirs ( const KURL& sourceDir, const KURL& destinationDir ) = 0;
+
+ /**
+ * Compare, with diff3, originalFile with changedFile1 and changedFile2
+ */
+ virtual void compare3Files( const KURL& originalFile, const KURL& changedFile1, const KURL& changedFile2 ) = 0;
+
+ /**
+ * This will show the file and the file with the diff applied
+ */
+ virtual void openFileAndDiff( const KURL& file, const KURL& diffFile ) = 0;
+
+ /**
+ * This will show the directory and the directory with the diff applied
+ */
+ virtual void openDirAndDiff ( const KURL& dir, const KURL& diffFile ) = 0;
+
+ /**
+ * This will set the encoding to use for all files that are read or for the diffoutput
+ */
+ virtual void setEncoding( const QString& encoding );
+
+public:
+ /**
+ * Warning this should be in class Part in KDE 4.0, not here !
+ * Around that time the methods will disappear here
+ */
+ virtual int readProperties( KConfig* config ) = 0;
+ virtual int saveProperties( KConfig* config ) = 0;
+
+ /**
+ * Warning this should be in class ReadWritePart in KDE 4.0, not here !
+ * Around that time the method will disappear here
+ */
+ virtual bool queryClose() = 0;
+
+protected:
+ // Add all variables to the KompareInterfacePrivate class and access them through the kip pointer
+ KompareInterfacePrivate* kip;
+ QString m_encoding;
+};
+
+#endif /* _KOMPARE_INTERFACE_H */
diff --git a/kompare/kompare.desktop b/kompare/kompare.desktop
new file mode 100644
index 00000000..88b7fcc4
--- /dev/null
+++ b/kompare/kompare.desktop
@@ -0,0 +1,74 @@
+# KDE Config File
+[Desktop Entry]
+Type=Application
+Name=Kompare
+Name[af]=K-vergelyk
+Name[eo]=Komparilo
+Name[hi]=कामà¥à¤ªà¥‡à¤¯à¤°
+Name[lv]=SalÄ«dzinÄt
+Name[ne]=तà¥à¤²à¤¨à¤¾
+Name[pa]=ਕੇ-ਤà©à¨²à¨¨à¨¾
+Name[ta]=கோமà¯à®ªà¯†à®°à¯
+Name[th]=เปรียบเทียบ
+Name[tr]=Karşılaştır
+GenericName=Diff/Patch Frontend
+GenericName[af]=Diff/Lap Voorprogram
+GenericName[bs]=Frontend za Diff/Patch
+GenericName[ca]=Interfície per a diff/patch
+GenericName[cs]=Rozhraní pro Diff/Patch
+GenericName[cy]=Blaen Gwahaniaethau/Clytiau
+GenericName[da]=Diff/patch-grænseflade
+GenericName[de]=Oberfläche für Diff und Patch
+GenericName[el]=ΠÏόγÏαμμα Diff/Patch
+GenericName[eo]=Fasado por la programoj "diff" kaj "patch"
+GenericName[es]=Interfaz Diff/Patch
+GenericName[et]=Diff/patch kasutajaliides
+GenericName[eu]=Desberdintasun/Adabaki interfazea
+GenericName[fa]=پایانۀ Diff/کژنه
+GenericName[fi]=Diff/Patch-käyttöliittymä
+GenericName[fr]=Interface graphique pour Diff et Patch
+GenericName[ga]=Comhéadan Diff/Patch
+GenericName[gl]=Interface para Diff/Patch
+GenericName[he]=ממשק ל-Diff/Patch
+GenericName[hi]=डिफ/पैच फà¥à¤°à¤¨à¥à¤Ÿà¤à¤£à¥à¤¡
+GenericName[hr]=SuÄelje za Diff/Patch
+GenericName[hu]=Grafikus diff/patch
+GenericName[is]=Myndrænt viðmót á Diff/Patch
+GenericName[it]=Interfaccia per diff e patch
+GenericName[ja]=Diff/Patch フロントエンド
+GenericName[kk]=Diff/Patch интерфейÑÑ–
+GenericName[lt]=Diff/Patch naudotojo sÄ…saja
+GenericName[lv]=Diff/Patch Frontends
+GenericName[ms]=Bahagian Depan Beza/Tampal
+GenericName[nb]=Diff-/Patch-grensesnitt
+GenericName[nds]=Böversiet för "diff" un "patch"
+GenericName[ne]=Diff/Patch फà¥à¤°à¤¨à¥à¤Ÿà¤‡à¤¨à¥à¤¡
+GenericName[nl]=Diff/Patch-hulpprogramma
+GenericName[nn]=Diff-/Patch-grensesnitt
+GenericName[pa]=Diff/Patch ਮà©à©±à¨–
+GenericName[pl]=Interfejs dla programów diff i patch
+GenericName[pt]=Interface do Diff/Patch
+GenericName[pt_BR]=Interface para Diferenças (diff)/Correções
+GenericName[ro]=Interfaţă grafică pentru "diff" şi "patch"
+GenericName[ru]=Сравнение файлов
+GenericName[sk]=Rozhranie Diff/Patch
+GenericName[sl]=Vmesnik za diff/patch
+GenericName[sr]=Ð˜Ð½Ñ‚ÐµÑ€Ñ„ÐµÑ˜Ñ Ð·Ð° Diff/Patch
+GenericName[sr@Latn]=Interfejs za Diff/Patch
+GenericName[sv]=Gränssnitt för Diff/Patch
+GenericName[ta]=டிபà¯/ஒடà¯à®Ÿà¯ à®®à¯à®©à¯à®ªà®•à¯à®¤à®¿
+GenericName[tg]=Утилитаи баробаркунии файлҳо
+GenericName[th]=ฟรอนต์เอนด์ของ Diff/Patch
+GenericName[tr]=Diff/Yama Önyüzü
+GenericName[uk]=Ð†Ð½Ñ‚ÐµÑ€Ñ„ÐµÐ¹Ñ Ð´Ð¾ diff/patch
+GenericName[zh_CN]=Diff/Patch å‰ç«¯
+GenericName[zh_TW]=Diff/Patch å‰ç«¯
+GenericName[zu]=Diff/PatchIsiqalo sokugcina
+MimeType=text/x-diff;
+Exec=kompare -caption "%c" %i %m -o %U
+Icon=kompare
+DocPath=kompare/index.html
+Terminal=false
+X-DCOP-ServiceType=Multi
+Categories=Qt;KDE;Development;
+InitialPreference=10
diff --git a/kompare/kompare_shell.cpp b/kompare/kompare_shell.cpp
new file mode 100644
index 00000000..3840e272
--- /dev/null
+++ b/kompare/kompare_shell.cpp
@@ -0,0 +1,487 @@
+/***************************************************************************
+ kompare_shell.cpp - description
+ -------------------
+ begin : Sun Mar 4 2001
+ copyright : (C) 2001-2004 Otto Bruggeman
+ (C) 2001-2003 John Firebaugh
+ email : otto.bruggeman@home.nl
+ jfirebaugh@kde.org
+****************************************************************************/
+
+/***************************************************************************
+**
+** This program is free software; you can redistribute it and/or modify
+** it under the terms of the 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 <ktexteditor/document.h>
+#include <ktexteditor/editinterface.h>
+#include <ktexteditor/view.h>
+#include <kdebug.h>
+#include <kedittoolbar.h>
+#include <kencodingfiledialog.h>
+#include <kiconloader.h>
+#include <kkeydialog.h>
+#include <klibloader.h>
+#include <klocale.h>
+#include <kmessagebox.h>
+#include <kparts/componentfactory.h>
+#include <ksqueezedtextlabel.h>
+#include <kstatusbar.h>
+#include <kstdaction.h>
+#include <ktrader.h>
+#include <kuserprofile.h>
+
+#include "kompare_part.h"
+#include "komparenavtreepart.h"
+#include "kompareurldialog.h"
+
+#include "kompare_shell.h"
+
+#define ID_N_OF_N_DIFFERENCES 1
+#define ID_N_OF_N_FILES 2
+#define ID_GENERAL 3
+
+KompareShell::KompareShell()
+ : KParts::DockMainWindow( 0L, "KompareShell" ),
+ m_textViewPart( 0 ),
+ m_textViewWidget( 0 )
+{
+ if ( !initialGeometrySet() )
+ resize( 800, 480 );
+
+ // set the shell's ui resource file
+ setXMLFile("kompareui.rc");
+
+ // then, setup our actions
+ setupActions();
+ setupStatusBar();
+
+ KTrader::OfferList offers = KTrader::self()->query( "text/x-diff",
+ "Kompare/ViewPart", QString::null, QString::null );
+#ifdef NDEBUG
+ for( int i = 0; i < offers.count(); i++ )
+ {
+ kdDebug(8102) << "One kservicetype checked..." << endl;
+ KService::Ptr ptr2 = *(offers.at( i ));
+ QStringList list = ptr2->serviceTypes();
+ for ( QStringList::Iterator it2 = list.begin(); it2 != list.end(); ++it2 )
+ kdDebug(8102) << *it2 << endl;
+ }
+#endif
+ if ( offers.count() == 0 )
+ {
+ KMessageBox::error(this, i18n( "Could not find our KompareViewPart." ) );
+ exit(1);
+ }
+
+ KService::Ptr ptr = offers.first();
+
+ KLibFactory *mainViewFactory = KLibLoader::self()->factory( ptr->library().ascii() );
+ if (mainViewFactory)
+ {
+ m_mainViewDock = createDockWidget( "View", kapp->icon() );
+ // now that the Part is loaded, we cast it to a KomparePart to get
+ // our hands on it
+ m_viewPart = static_cast<KomparePart*>(mainViewFactory->create(m_mainViewDock,
+ "kompare_part", "KParts::ReadWritePart" ));
+
+ if ( m_viewPart )
+ {
+ m_mainViewDock->setWidget( m_viewPart->widget() );
+ setView( m_mainViewDock );
+ setMainDockWidget( m_mainViewDock );
+
+ // and integrate the part's GUI with the shell's
+ createGUI(m_viewPart);
+ }
+ }
+ else
+ {
+ // if we couldn't load our Part, we exit since the Shell by
+ // itself can't do anything useful
+ KMessageBox::error(this, i18n( "Could not load our KompareViewPart." ) );
+ exit(2);
+ }
+
+ offers.clear();
+ offers = KTrader::self()->query( "text/x-diff", "KParts/ReadOnlyPart", "'Kompare/NavigationPart' in ServiceTypes", QString::null );
+ if ( offers.count() == 0 )
+ {
+ KMessageBox::error(this, i18n( "Could not find our KompareNavigationPart." ) );
+ exit(3);
+ }
+
+ ptr = offers.first();
+
+ KLibFactory *navTreeFactory = KLibLoader::self()->factory( ptr->library().ascii() );
+ if (navTreeFactory)
+ {
+ m_navTreeDock = createDockWidget( "Navigation", kapp->icon() );
+
+ m_navTreePart = static_cast<KompareNavTreePart*>(navTreeFactory->create(m_navTreeDock,
+ "komparenavtreepart", "KParts::ReadOnlyPart" ));
+
+ if ( m_navTreePart )
+ {
+ m_navTreeDock->setWidget( m_navTreePart->widget() );
+ m_navTreeDock->manualDock( m_mainViewDock, KDockWidget::DockTop, 20 );
+ }
+ }
+ else
+ {
+ // if we couldn't load our Part, we exit since the Shell by
+ // itself can't do anything useful
+ KMessageBox::error(this, i18n( "Could not load our KompareNavigationPart." ) );
+ exit(4);
+ }
+
+ // Hook up the inter part communication
+ connect( m_viewPart, SIGNAL( modelsChanged(const Diff2::DiffModelList*) ),
+ m_navTreePart, SLOT( slotModelsChanged( const Diff2::DiffModelList*) ) );
+
+ connect( m_viewPart, SIGNAL( kompareInfo(Kompare::Info*) ),
+ m_navTreePart, SLOT( slotKompareInfo(Kompare::Info*) ) );
+
+ connect( m_navTreePart, SIGNAL( selectionChanged(const Diff2::DiffModel*, const Diff2::Difference*) ),
+ m_viewPart, SIGNAL( selectionChanged(const Diff2::DiffModel*, const Diff2::Difference*) ) );
+ connect( m_viewPart, SIGNAL( setSelection(const Diff2::DiffModel*, const Diff2::Difference*) ),
+ m_navTreePart, SLOT( slotSetSelection(const Diff2::DiffModel*, const Diff2::Difference*) ) );
+
+ connect( m_navTreePart, SIGNAL( selectionChanged(const Diff2::Difference*) ),
+ m_viewPart, SIGNAL( selectionChanged(const Diff2::Difference*) ) );
+ connect( m_viewPart, SIGNAL( setSelection(const Diff2::Difference*) ),
+ m_navTreePart, SLOT( slotSetSelection(const Diff2::Difference*) ) );
+
+ // This is the interpart interface, it is signal and slot based so no "real" nterface here
+ // All you have to do is connect the parts from your application.
+ // These just point to the method with the same name in the KompareModelList or get called
+ // from the method with the same name in KompareModelList.
+
+ // There is currently no applying possible from the navtreepart to the viewpart
+ connect( m_viewPart, SIGNAL(applyDifference(bool)),
+ m_navTreePart, SLOT(slotApplyDifference(bool)) );
+ connect( m_viewPart, SIGNAL(applyAllDifferences(bool)),
+ m_navTreePart, SLOT(slotApplyAllDifferences(bool)) );
+ connect( m_viewPart, SIGNAL(applyDifference(const Diff2::Difference*, bool)),
+ m_navTreePart, SLOT(slotApplyDifference(const Diff2::Difference*, bool)) );
+
+ // Hook up the KomparePart -> KompareShell communication
+ connect( m_viewPart, SIGNAL( setStatusBarModelInfo( int, int, int, int, int ) ),
+ this, SLOT( slotUpdateStatusBar( int, int, int, int, int ) ) );
+ connect( m_viewPart, SIGNAL( setStatusBarText(const QString&) ),
+ this, SLOT( slotSetStatusBarText(const QString&) ) );
+
+ // Read basic main-view settings, and set to autosave
+ setAutoSaveSettings( "General Options" );
+}
+
+KompareShell::~KompareShell()
+{
+}
+
+bool KompareShell::queryClose()
+{
+ return m_viewPart->queryClose();
+}
+
+void KompareShell::openDiff(const KURL& url)
+{
+ kdDebug(8102) << "Url = " << url.prettyURL() << endl;
+ m_diffURL = url;
+ m_viewPart->openDiff( url );
+}
+
+void KompareShell::openStdin()
+{
+ kdDebug(8102) << "Using stdin to read the diff" << endl;
+ QFile file;
+ file.open( IO_ReadOnly, stdin );
+ QTextStream stream( &file );
+
+ QString diff = stream.read();
+
+ file.close();
+
+ m_viewPart->openDiff( diff );
+
+}
+
+void KompareShell::compare(const KURL& source,const KURL& destination )
+{
+ m_sourceURL = source;
+ m_destinationURL = destination;
+
+ m_viewPart->compare( source, destination );
+}
+
+void KompareShell::blend( const KURL& url1, const KURL& diff )
+{
+ m_sourceURL = url1;
+ m_destinationURL = diff;
+
+ m_viewPart->openDirAndDiff( url1, diff );
+}
+
+void KompareShell::setupActions()
+{
+ KAction* open = KStdAction::open(this, SLOT(slotFileOpen()), actionCollection());
+ open->setText( i18n( "&Open Diff..." ) );
+ new KAction( i18n("&Compare Files..."), "fileopen", Qt::CTRL + Qt::Key_C,
+ this, SLOT(slotFileCompareFiles()),
+ actionCollection(), "file_compare_files" );
+ new KAction( i18n("&Blend URL with Diff..."), "fileblend", Qt::CTRL + Qt::Key_B,
+ this, SLOT(slotFileBlendURLAndDiff()),
+ actionCollection(), "file_blend_url" );
+ KStdAction::quit( this, SLOT( slotFileClose() ), actionCollection() );
+
+#if KDE_VERSION >= KDE_MAKE_VERSION(3,1,90)
+ createStandardStatusBarAction();
+#endif
+ setStandardToolBarMenuEnabled(true);
+ m_showTextView = new KToggleAction( i18n("Show T&ext View"), 0, this, SLOT(slotShowTextView()),
+ actionCollection(), "options_show_text_view" );
+ m_showTextView->setCheckedState(i18n("Hide T&ext View"));
+
+ KStdAction::keyBindings(this, SLOT(optionsConfigureKeys()), actionCollection());
+ KStdAction::configureToolbars(this, SLOT(optionsConfigureToolbars()), actionCollection());
+}
+
+void KompareShell::setupStatusBar()
+{
+ // Made these entries permanent so they will appear on the right side
+ statusBar()->insertItem( i18n(" 0 of 0 differences "), ID_N_OF_N_DIFFERENCES, 0, true );
+ statusBar()->insertItem( i18n(" 0 of 0 files "), ID_N_OF_N_FILES, 0, true );
+
+ m_generalLabel = new KSqueezedTextLabel( "", 0, "general_statusbar_label" );
+ statusBar()->addWidget( m_generalLabel, 1, false );
+ m_generalLabel->setAlignment( Qt::AlignLeft );
+}
+
+void KompareShell::slotUpdateStatusBar( int modelIndex, int differenceIndex, int modelCount, int differenceCount, int appliedCount )
+{
+ kdDebug(8102) << "KompareShell::updateStatusBar()" << endl;
+
+ QString fileStr;
+ QString diffStr;
+
+ if ( modelIndex >= 0 )
+ fileStr = i18n( " %1 of %n file ", " %1 of %n files ", modelCount ).arg( modelIndex + 1 );
+ else
+ fileStr = i18n( " %n file ", " %n files ", modelCount );
+
+ if ( differenceIndex >= 0 )
+ diffStr = i18n( " %1 of %n difference, %2 applied ", " %1 of %n differences, %2 applied ", differenceCount )
+ .arg( differenceIndex + 1 ).arg( appliedCount );
+ else
+ diffStr = i18n( " %n difference ", " %n differences ", differenceCount );
+
+ statusBar()->changeItem( fileStr, ID_N_OF_N_FILES );
+ statusBar()->changeItem( diffStr, ID_N_OF_N_DIFFERENCES );
+}
+
+void KompareShell::slotSetStatusBarText( const QString& text )
+{
+ m_generalLabel->setText( text );
+}
+
+void KompareShell::setCaption( const QString& caption )
+{
+// kdDebug() << kdBacktrace();
+ KParts::DockMainWindow::setCaption( caption, m_viewPart->isModified() );
+}
+
+void KompareShell::saveProperties(KConfig* config)
+{
+ // The 'config' object points to the session managed
+ // config file. Anything you write here will be available
+ // later when this app is restored
+ if ( m_mode == Kompare::ComparingFiles )
+ {
+ config->writeEntry( "Mode", "ComparingFiles" );
+ config->writePathEntry( "SourceUrl", m_sourceURL.url() );
+ config->writePathEntry( "DestinationUrl", m_destinationURL.url() );
+ }
+ else if ( m_mode == Kompare::ShowingDiff )
+ {
+ config->writeEntry( "Mode", "ShowingDiff" );
+ config->writePathEntry( "DiffUrl", m_diffURL.url() );
+ }
+
+ m_viewPart->saveProperties( config );
+}
+
+void KompareShell::readProperties(KConfig* config)
+{
+ // The 'config' object points to the session managed
+ // config file. This function is automatically called whenever
+ // the app is being restored. Read in here whatever you wrote
+ // in 'saveProperties'
+
+ QString mode = config->readEntry( "Mode", "ComparingFiles" );
+ if ( mode == "ComparingFiles" )
+ {
+ m_mode = Kompare::ComparingFiles;
+ m_sourceURL = config->readPathEntry( "SourceUrl", "" );
+ m_destinationURL = config->readPathEntry( "DestinationFile", "" );
+
+ m_viewPart->readProperties( config );
+
+ m_viewPart->compareFiles( m_sourceURL, m_destinationURL );
+ }
+ else if ( mode == "ShowingDiff" )
+ {
+ m_mode = Kompare::ShowingDiff;
+ m_diffURL = config->readPathEntry( "DiffUrl", "" );
+
+ m_viewPart->readProperties( config );
+
+ m_viewPart->openURL( m_diffURL );
+ }
+ else
+ { // just in case something weird has happened, dont restore the diff then
+ // Bruggie: or when some idiot like me changes the possible values for mode
+ // IOW, a nice candidate for a kconf_update thingy :)
+ m_viewPart->readProperties( config );
+ }
+}
+
+void KompareShell::slotFileOpen()
+{
+ // FIXME: use different filedialog which gets encoding
+ KURL url = KFileDialog::getOpenURL( QString::null, "text/x-diff", this );
+ if( !url.isEmpty() ) {
+ KompareShell* shell = new KompareShell();
+ kapp->ref();
+ shell->show();
+ shell->openDiff( url );
+ }
+}
+
+void KompareShell::slotFileBlendURLAndDiff()
+{
+ KompareURLDialog* dialog = new KompareURLDialog( this );
+
+ dialog->setCaption( i18n( "Blend File/Folder with diff Output" ) );
+ dialog->setFirstGroupBoxTitle( i18n( "File/Folder" ) );
+ dialog->setSecondGroupBoxTitle( i18n( "Diff Output" ) );
+
+ KGuiItem blendGuiItem( i18n( "Blend" ), QString::null, i18n( "Blend this file or folder with the diff output" ), i18n( "If you have entered a file or folder name and a file that contains diff output in the fields in this dialog then this button will be enabled and pressing it will open kompare's main view where the output of the entered file or files from the folder are mixed with the diff output so you can then apply the difference(s) to a file or to the files. " ) );
+ dialog->setButtonOK( blendGuiItem );
+
+ dialog->setGroup( "Recent Blend Files" );
+
+ dialog->setFirstURLRequesterMode( KFile::File|KFile::Directory|KFile::ExistingOnly );
+ // diff output can not be a directory
+ dialog->setSecondURLRequesterMode( KFile::File|KFile::ExistingOnly );
+ if ( dialog->exec() == QDialog::Accepted )
+ {
+ m_sourceURL = dialog->getFirstURL();
+ m_destinationURL = dialog->getSecondURL();
+ KompareShell* shell = new KompareShell();
+ kapp->ref();
+ shell->show();
+ shell->m_viewPart->setEncoding( dialog->encoding() );
+ shell->blend( m_sourceURL, m_destinationURL );
+ }
+ delete dialog;
+}
+
+void KompareShell::slotFileCompareFiles()
+{
+ KompareURLDialog* dialog = new KompareURLDialog( this );
+
+ dialog->setCaption( i18n( "Compare Files or Folders" ) );
+ dialog->setFirstGroupBoxTitle( i18n( "Source" ) );
+ dialog->setSecondGroupBoxTitle( i18n( "Destination" ) );
+
+ KGuiItem compareGuiItem( i18n( "Compare" ), QString::null, i18n( "Compare these files or folders" ), i18n( "If you have entered 2 filenames or 2 folders in the fields in this dialog then this button will be enabled and pressing it will start a comparison of the entered files or folders. " ) );
+ dialog->setButtonOK( compareGuiItem );
+
+ dialog->setGroup( "Recent Compare Files" );
+
+ dialog->setFirstURLRequesterMode( KFile::File|KFile::Directory|KFile::ExistingOnly );
+ dialog->setSecondURLRequesterMode( KFile::File|KFile::Directory|KFile::ExistingOnly );
+
+ if ( dialog->exec() == QDialog::Accepted )
+ {
+ m_sourceURL = dialog->getFirstURL();
+ m_destinationURL = dialog->getSecondURL();
+ KompareShell* shell = new KompareShell();
+ kapp->ref();
+ shell->show();
+ kdDebug() << "Damn it, i should be called !!! Oh and encoding is: " << dialog->encoding() << endl;
+ shell->m_viewPart->setEncoding( dialog->encoding() );
+ shell->compare( m_sourceURL, m_destinationURL );
+ }
+ delete dialog;
+}
+
+void KompareShell::slotFileClose()
+{
+ if ( m_viewPart->queryClose() )
+ {
+ delete this;
+ kapp->deref();
+ }
+}
+
+void KompareShell::slotShowTextView()
+{
+ if ( !m_textViewWidget )
+ {
+ int errCode;
+
+ // FIXME: proper error checking
+ m_textViewWidget = createDockWidget( i18n("Text View"), SmallIcon( "text") );
+ m_textViewPart = KParts::ComponentFactory::createPartInstanceFromQuery<KTextEditor::Document>(
+ QString::fromLatin1("KTextEditor/Document"),
+ QString::null, (QWidget*)this, 0, (QWidget*)this, 0, QStringList(), &errCode );
+ if ( m_textViewPart )
+ {
+ m_textView = m_textViewPart->createView( this, 0 );
+ m_textViewWidget->setWidget( static_cast<QWidget*>(m_textView) );
+ m_textEditIface = editInterface( m_textViewPart );
+ connect( m_viewPart, SIGNAL(diffString(const QString&)),
+ this, SLOT(slotSetDiffString(const QString&)) );
+ }
+ }
+
+ m_textViewWidget->manualDock( m_mainViewDock, KDockWidget:: DockCenter );
+}
+
+void KompareShell::slotSetDiffString( const QString& diffString )
+{
+ if ( m_textEditIface )
+ m_textEditIface->setText( diffString );
+}
+
+void KompareShell::optionsConfigureKeys()
+{
+ KKeyDialog dlg( true, this );
+
+ dlg.insert( actionCollection() );
+ if ( m_viewPart )
+ dlg.insert( m_viewPart->actionCollection() );
+
+ dlg.configure();
+}
+
+void KompareShell::optionsConfigureToolbars()
+{
+ saveMainWindowSettings( KGlobal::config(), autoSaveGroup() );
+ // use the standard toolbar editor
+ KEditToolbar dlg(factory());
+ connect(&dlg,SIGNAL(newToolbarConfig()),this,SLOT(newToolbarConfig()));
+ dlg.exec();
+}
+
+void KompareShell::newToolbarConfig()
+{
+ applyMainWindowSettings( KGlobal::config(), autoSaveGroup() );
+}
+
+#include "kompare_shell.moc"
diff --git a/kompare/kompare_shell.h b/kompare/kompare_shell.h
new file mode 100644
index 00000000..be3bb150
--- /dev/null
+++ b/kompare/kompare_shell.h
@@ -0,0 +1,149 @@
+/***************************************************************************
+ kompare_shell.h - description
+ -------------------
+ begin : Sun Mar 4 2001
+ copyright : (C) 2001-2003 by Otto Bruggeman
+ and John Firebaugh
+ email : otto.bruggeman@home.nl
+ jfirebaugh@kde.org
+****************************************************************************/
+
+/***************************************************************************
+**
+** This program is free software; you can redistribute it and/or modify
+** it under the terms of the 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 KOMPARESHELL_H
+#define KOMPARESHELL_H
+
+#include <kapplication.h>
+#include <kparts/dockmainwindow.h>
+
+#include "kompare.h"
+
+class KToggleAction;
+
+class KSqueezedTextLabel;
+class KomparePart;
+class KompareNavTreePart;
+
+namespace KTextEditor {
+ class Document;
+ class EditInterface;
+ class View;
+}
+
+/**
+* This is the application "Shell". It has a menubar, toolbar, and
+* statusbar but relies on the "Part" to do all the real work.
+*
+* Adapted the shell a bit so it now handles seperate view and navigation parts
+*
+* @short Application Shell
+* @author John Firebaugh <jfirebaugh@kde.org>
+* @author Otto Bruggeman <bruggie@home.nl>
+* @version 3.2.90
+*/
+class KompareShell : public KParts::DockMainWindow
+{
+ Q_OBJECT
+public:
+ /**
+ * Default Constructor
+ */
+ KompareShell();
+
+ /**
+ * Default Destructor
+ */
+ virtual ~KompareShell();
+
+ /**
+ * Use this method to load whatever file/URL you have
+ */
+ void openDiff( const KURL& url );
+
+ /**
+ * Use this method to load the diff from stdin
+ */
+ void openStdin();
+
+ /**
+ * Use this method to compare 2 URLs (files or directories)
+ */
+ void compare( const KURL& source, const KURL& destination );
+
+ /**
+ * Use this method to blend diff into url1 (file or directory)
+ */
+ void blend( const KURL& url1, const KURL& diff );
+
+public slots:
+ void slotUpdateStatusBar( int modelIndex, int differenceIndex, int modelCount, int differenceCount, int appliedCount );
+ void setCaption( const QString& caption );
+
+ /**
+ * This method only exists because i cant make main a frined of this class
+ */
+ KomparePart* viewPart() const { return m_viewPart; }
+
+protected:
+ virtual bool queryClose();
+
+ /**
+ * This method is called when it is time for the app to save its
+ * properties for session management purposes.
+ */
+ void saveProperties(KConfig *);
+
+ /**
+ * This method is called when this app is restored. The KConfig
+ * object points to the session management config file that was saved
+ * with @ref saveProperties
+ */
+ void readProperties(KConfig *);
+
+private slots:
+ void slotSetStatusBarText( const QString& text );
+ void slotFileOpen();
+ void slotFileCompareFiles();
+ void slotFileBlendURLAndDiff();
+ void slotShowTextView();
+ void slotFileClose();
+ void optionsConfigureKeys();
+ void optionsConfigureToolbars();
+ void slotSetDiffString( const QString& diffString );
+ void newToolbarConfig();
+
+private:
+ void setupAccel();
+ void setupActions();
+ void setupStatusBar();
+
+private:
+ KURL m_sourceURL;
+ KURL m_destinationURL;
+ KURL m_diffURL;
+
+ KomparePart* m_viewPart;
+ KompareNavTreePart* m_navTreePart;
+ KTextEditor::Document* m_textViewPart;
+ KTextEditor::View* m_textView;
+ KTextEditor::EditInterface* m_textEditIface;
+
+ KDockWidget* m_textViewWidget;
+ KDockWidget* m_mainViewDock;
+ KDockWidget* m_navTreeDock;
+
+ KToggleAction* m_showTextView;
+
+ enum Kompare::Mode m_mode;
+ // This is the statusbarwidget for displaying the general stuff
+ KSqueezedTextLabel* m_generalLabel;
+};
+
+#endif // KOMPARE_H
diff --git a/kompare/komparenavigationpart.desktop b/kompare/komparenavigationpart.desktop
new file mode 100644
index 00000000..1e7f7669
--- /dev/null
+++ b/kompare/komparenavigationpart.desktop
@@ -0,0 +1,4 @@
+[Desktop Entry]
+Type=ServiceType
+X-KDE-ServiceType=Kompare/NavigationPart
+X-KDE-Derived=KParts/ReadOnlyPart
diff --git a/kompare/komparenavtreepart/Makefile.am b/kompare/komparenavtreepart/Makefile.am
new file mode 100644
index 00000000..cac18964
--- /dev/null
+++ b/kompare/komparenavtreepart/Makefile.am
@@ -0,0 +1,29 @@
+#########################################################################
+# KPART SECTION
+#########################################################################
+
+INCLUDES = \
+ -I$(top_srcdir)/kompare/libdiff2 \
+ -I$(top_srcdir)/kompare/komparepart \
+ $(all_includes)
+
+noinst_HEADERS = \
+ komparenavtreepart.h
+
+# let automoc handle all of the meta source files (moc)
+METASOURCES = AUTO
+
+kde_module_LTLIBRARIES = libkomparenavtreepart.la
+
+# the Part's source, library search path, and link libraries
+libkomparenavtreepart_la_SOURCES = \
+ komparenavtreepart.cpp
+
+libkomparenavtreepart_la_LDFLAGS = $(KDE_PLUGIN) $(all_libraries)
+libkomparenavtreepart_la_LIBADD = $(LIB_KPARTS) ../libdiff2/libdiff2.la
+
+# this is where the desktop file will go
+partdesktopdir = $(kde_servicesdir)
+partdesktop_DATA = komparenavtreepart.desktop
+
+
diff --git a/kompare/komparenavtreepart/komparenavtreepart.cpp b/kompare/komparenavtreepart/komparenavtreepart.cpp
new file mode 100644
index 00000000..f2e10759
--- /dev/null
+++ b/kompare/komparenavtreepart/komparenavtreepart.cpp
@@ -0,0 +1,710 @@
+/***************************************************************************
+ KompareNavTreePart.cpp - description
+ -------------------
+ begin : Sun Mar 4 2001
+ copyright : (C) 2001-2004 Otto Bruggeman
+ (C) 2001-2003 John Firebaugh
+ email : otto.bruggeman@home.nl
+ jfirebaugh@kde.org
+****************************************************************************/
+
+/***************************************************************************
+**
+** This program is free software; you can redistribute it and/or modify
+** it under the terms of the 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 <kdebug.h>
+#include <klocale.h>
+#include <kiconloader.h>
+#include <kmimetype.h>
+#include <klistview.h>
+#include <kaboutdata.h>
+
+#include "difference.h"
+#include "diffmodel.h"
+#include "diffmodellist.h"
+#include "komparemodellist.h"
+
+#include "komparenavtreepart.h"
+
+#define COL_SOURCE 0
+#define COL_DESTINATION 1
+#define COL_DIFFERENCE 2
+
+using namespace Diff2;
+
+KompareNavTreePart::KompareNavTreePart( QWidget* parent, const char* name )
+ : KParts::ReadOnlyPart( parent, name ),
+ m_splitter( 0 ),
+ m_modelList( 0 ),
+ m_srcDirTree( 0 ),
+ m_destDirTree( 0 ),
+ m_fileList( 0 ),
+ m_changesList( 0 ),
+ m_srcRootItem( 0 ),
+ m_destRootItem( 0 ),
+ m_selectedModel( 0 ),
+ m_selectedDifference( 0 ),
+ m_source( "" ),
+ m_destination( "" ),
+ m_info( 0 )
+{
+ m_splitter = new QSplitter( Qt::Horizontal );
+
+ setWidget( m_splitter );
+
+ m_srcDirTree = new KListView( m_splitter );
+ m_srcDirTree->addColumn( i18n("Source Folder") );
+ m_srcDirTree->setRootIsDecorated( false );
+ m_srcDirTree->setSorting( 0, true );
+
+ m_destDirTree = new KListView( m_splitter );
+ m_destDirTree->addColumn( i18n("Destination Folder") );
+ m_destDirTree->setRootIsDecorated( false );
+ m_destDirTree->setSorting( 0, true );
+
+ m_fileList = new KListView( m_splitter );
+ m_fileList->addColumn( i18n("Source File") );
+ m_fileList->addColumn( i18n("Destination File") );
+ m_fileList->setAllColumnsShowFocus( true );
+ m_fileList->setRootIsDecorated( false );
+ m_fileList->setSorting( 0, true );
+
+ m_changesList = new KListView( m_splitter );
+ m_changesList->addColumn( i18n("Source Line") );
+ m_changesList->addColumn( i18n("Destination Line") );
+ m_changesList->addColumn( i18n("Difference") );
+ m_changesList->setAllColumnsShowFocus( true );
+ m_changesList->setRootIsDecorated( false );
+ m_changesList->setSorting( 0, true );
+
+ connect( m_srcDirTree, SIGNAL(selectionChanged( QListViewItem* )),
+ this, SLOT(slotSrcDirTreeSelectionChanged( QListViewItem* )) );
+ connect( m_destDirTree, SIGNAL(selectionChanged( QListViewItem* )),
+ this, SLOT(slotDestDirTreeSelectionChanged( QListViewItem* )) );
+ connect( m_fileList, SIGNAL(selectionChanged( QListViewItem* )),
+ this, SLOT(slotFileListSelectionChanged( QListViewItem* )) );
+ connect( m_changesList, SIGNAL(selectionChanged( QListViewItem* )),
+ this, SLOT(slotChangesListSelectionChanged( QListViewItem* )) );
+}
+
+KompareNavTreePart::~KompareNavTreePart()
+{
+}
+
+void KompareNavTreePart::slotKompareInfo( struct Kompare::Info* info )
+{
+ m_info = info;
+}
+
+void KompareNavTreePart::slotModelsChanged( const DiffModelList* modelList )
+{
+ kdDebug(8105) << "Models (" << modelList << ") have changed... scanning the models... " << endl;
+
+ if ( modelList )
+ {
+ m_modelList = modelList;
+ m_srcDirTree->clear();
+ m_destDirTree->clear();
+ m_fileList->clear();
+ m_changesList->clear();
+ buildTreeInMemory();
+ }
+ else
+ {
+ m_modelList = modelList;
+ m_srcDirTree->clear();
+ m_destDirTree->clear();
+ m_fileList->clear();
+ m_changesList->clear();
+ }
+}
+
+void KompareNavTreePart::buildTreeInMemory()
+{
+ kdDebug(8105) << "BuildTreeInMemory called" << endl;
+
+ if ( m_modelList->count() == 0 )
+ {
+ kdDebug() << "No models... weird shit..." << endl;
+ return; // avoids a crash on clear()
+ }
+
+ if ( m_info == 0 )
+ {
+ kdDebug() << "No Info... weird shit..." << endl;
+ return;
+ }
+
+ QString srcBase;
+ QString destBase;
+
+ DiffModel* model;
+ model = m_modelList->first();
+ m_selectedModel = 0L;
+
+ switch ( m_info->mode )
+ {
+ case Kompare::ShowingDiff:
+ srcBase = model->sourcePath();
+ destBase = model->destinationPath();
+ break;
+ case Kompare::ComparingFiles:
+ srcBase = model->sourcePath();
+ destBase = model->destinationPath();
+ break;
+ case Kompare::ComparingDirs:
+ srcBase = m_info->localSource;
+ if ( !srcBase.endsWith( "/" ) )
+ srcBase += "/";
+ destBase = m_info->localDestination;
+ if ( !destBase.endsWith( "/" ) )
+ destBase += "/";
+ break;
+ case Kompare::BlendingFile:
+ case Kompare::BlendingDir:
+ default:
+ kdDebug(8105) << "Oops needs to implement this..." << endl;
+ }
+
+// kdDebug(8105) << "srcBase = " << srcBase << endl;
+// kdDebug(8105) << "destBase = " << destBase << endl;
+
+ m_srcRootItem = new KDirLVI( m_srcDirTree, srcBase );
+ m_destRootItem = new KDirLVI( m_destDirTree, destBase );
+
+ QString srcPath;
+ QString destPath;
+
+ // Create the tree from the models
+ DiffModelListConstIterator modelIt = m_modelList->begin();
+ DiffModelListConstIterator mEnd = m_modelList->end();
+
+ for ( ; modelIt != mEnd; ++modelIt )
+ {
+ model = *modelIt;
+ srcPath = model->sourcePath();
+ destPath = model->destinationPath();
+
+ kdDebug(8105) << "srcPath = " << srcPath << endl;
+ kdDebug(8105) << "destPath = " << destPath << endl;
+ m_srcRootItem->addModel( srcPath, model, &m_modelToSrcDirItemDict );
+ m_destRootItem->addModel( destPath, model, &m_modelToDestDirItemDict );
+ }
+// m_srcDirTree->setSelected( m_srcDirTree->firstChild(), true );
+}
+
+void KompareNavTreePart::buildDirectoryTree()
+{
+// FIXME: afaict this can be deleted
+// kdDebug(8105) << "BuildDirTree called" << endl;
+}
+
+QString KompareNavTreePart::compareFromEndAndReturnSame(
+ const QString& string1,
+ const QString& string2 )
+{
+ QString result;
+
+ int srcLen = string1.length();
+ int destLen = string2.length();
+
+ while ( srcLen != 0 && destLen != 0 )
+ {
+ if ( string1[--srcLen] == string2[--destLen] )
+ result.prepend( string1[srcLen] );
+ else
+ break;
+ }
+
+ if ( srcLen != 0 && destLen != 0 && result.startsWith( "/" ) )
+ result = result.remove( 0, 1 ); // strip leading /, we need it later
+
+ return result;
+}
+
+void KompareNavTreePart::slotSetSelection( const DiffModel* model, const Difference* diff )
+{
+ kdDebug(8105) << "KompareNavTreePart::slotSetSelection model = " << model << ", diff = " << diff << endl;
+ if ( model == m_selectedModel )
+ {
+ // model is the same, so no need to update that...
+ if ( diff != m_selectedDifference )
+ {
+ m_selectedDifference = diff;
+ setSelectedDifference( diff );
+ }
+ return;
+ }
+
+ // model is different so we need to find the right dirs, file and changeitems to select
+ // if m_selectedModel == NULL then everything needs to be done as well
+ if ( !m_selectedModel || model->sourcePath() != m_selectedModel->sourcePath() )
+ { // dirs are different, so we need to update the dirviews as well
+ m_selectedModel = model;
+ m_selectedDifference = diff;
+
+ setSelectedDir( model );
+ setSelectedFile( model );
+ setSelectedDifference( diff );
+ return;
+ }
+
+ if ( !m_selectedModel || model->sourceFile() != m_selectedModel->sourceFile() )
+ {
+ m_selectedModel = model;
+ setSelectedFile( model );
+
+ m_selectedDifference = diff;
+ setSelectedDifference( diff );
+ }
+}
+
+void KompareNavTreePart::setSelectedDir( const DiffModel* model )
+{
+ KDirLVI* currentDir;
+ currentDir = m_modelToSrcDirItemDict[ (void*)model ];
+ kdDebug(8105) << "Manually setting selection in srcdirtree with currentDir = " << currentDir << endl;
+ m_srcDirTree->blockSignals( true );
+ m_srcDirTree->setSelected( currentDir, true );
+ m_srcDirTree->ensureItemVisible( currentDir );
+ m_srcDirTree->blockSignals( false );
+
+ currentDir = m_modelToDestDirItemDict[ (void*)model ];
+ kdDebug(8105) << "Manually setting selection in destdirtree with currentDir = " << currentDir << endl;
+ m_destDirTree->blockSignals( true );
+ m_destDirTree->setSelected( currentDir, true );
+ m_destDirTree->ensureItemVisible( currentDir );
+ m_destDirTree->blockSignals( false );
+
+ m_fileList->blockSignals( true );
+ currentDir->fillFileList( m_fileList, &m_modelToFileItemDict );
+ m_fileList->blockSignals( false );
+}
+
+void KompareNavTreePart::setSelectedFile( const DiffModel* model )
+{
+ KFileLVI* currentFile;
+ currentFile = m_modelToFileItemDict[ (void*)model ];
+ kdDebug(8105) << "Manually setting selection in filelist" << endl;
+ m_fileList->blockSignals( true );
+ m_fileList->setSelected( currentFile, true );
+ m_fileList->ensureItemVisible( currentFile );
+ m_fileList->blockSignals( false );
+
+ m_changesList->blockSignals( true );
+ currentFile->fillChangesList( m_changesList, &m_diffToChangeItemDict );
+ m_changesList->blockSignals( false );
+}
+
+void KompareNavTreePart::setSelectedDifference( const Difference* diff )
+{
+ KChangeLVI* currentDiff;
+ currentDiff = m_diffToChangeItemDict[ (void*)diff ];
+ kdDebug(8105) << "Manually setting selection in changeslist to " << currentDiff << endl;
+ m_changesList->blockSignals( true );
+ m_changesList->setSelected( currentDiff, true );
+ m_changesList->ensureItemVisible( currentDiff );
+ m_changesList->blockSignals( false );
+}
+
+void KompareNavTreePart::slotSetSelection( const Difference* diff )
+{
+// kdDebug(8105) << "Scotty i need more power !!" << endl;
+ if ( m_selectedDifference != diff )
+ {
+// kdDebug(8105) << "But sir, i am giving you all she's got" << endl;
+ m_selectedDifference = diff;
+ setSelectedDifference( diff );
+ }
+}
+
+void KompareNavTreePart::slotSrcDirTreeSelectionChanged( QListViewItem* item )
+{
+ kdDebug(8105) << "Sent by the sourceDirectoryTree with item = " << item << endl;
+ m_srcDirTree->ensureItemVisible( item );
+ KDirLVI* dir = static_cast<KDirLVI*>(item);
+ // order the dest tree view to set its selected item to the same as here
+ QString path;
+ // We start with an empty path and after the call path contains the full path
+ path = dir->fullPath( path );
+ KDirLVI* selItem = m_destRootItem->setSelected( path );
+ m_destDirTree->blockSignals( true );
+ m_destDirTree->setSelected( selItem, true );
+ m_destDirTree->ensureItemVisible( selItem );
+ m_destDirTree->blockSignals( false );
+ // fill the changes list
+ dir->fillFileList( m_fileList, &m_modelToFileItemDict );
+}
+
+void KompareNavTreePart::slotDestDirTreeSelectionChanged( QListViewItem* item )
+{
+ kdDebug(8105) << "Sent by the destinationDirectoryTree with item = " << item << endl;
+ m_destDirTree->ensureItemVisible( item );
+ KDirLVI* dir = static_cast<KDirLVI*>(item);
+ // order the src tree view to set its selected item to the same as here
+ QString path;
+ // We start with an empty path and after the call path contains the full path
+ path = dir->fullPath( path );
+ KDirLVI* selItem = m_srcRootItem->setSelected( path );
+ m_srcDirTree->blockSignals( true );
+ m_srcDirTree->setSelected( selItem, true );
+ m_srcDirTree->ensureItemVisible( selItem );
+ m_srcDirTree->blockSignals( false );
+ // fill the changes list
+ dir->fillFileList( m_fileList, &m_modelToFileItemDict );
+}
+
+void KompareNavTreePart::slotFileListSelectionChanged( QListViewItem* item )
+{
+ kdDebug(8105) << "Sent by the fileList with item = " << item << endl;
+
+ KFileLVI* file = static_cast<KFileLVI*>(item);
+ m_selectedModel = file->model();
+ m_changesList->blockSignals( true );
+ file->fillChangesList( m_changesList, &m_diffToChangeItemDict );
+ m_changesList->blockSignals( false );
+
+ if ( m_changesList->selectedItem() )
+ {
+ // FIXME: This is ugly...
+ m_selectedDifference = (static_cast<KChangeLVI*>(m_changesList->selectedItem()))->difference();
+ }
+
+ emit selectionChanged( m_selectedModel, m_selectedDifference );
+}
+
+void KompareNavTreePart::slotChangesListSelectionChanged( QListViewItem* item )
+{
+ kdDebug(8105) << "Sent by the changesList" << endl;
+
+ KChangeLVI* change = static_cast<KChangeLVI*>(item);
+ m_selectedDifference = change->difference();
+
+ emit selectionChanged( m_selectedDifference );
+}
+
+void KompareNavTreePart::slotApplyDifference( bool /*apply*/ )
+{
+ KChangeLVI* clvi = m_diffToChangeItemDict[(void*)m_selectedDifference];
+ if ( clvi )
+ clvi->setDifferenceText();
+}
+
+void KompareNavTreePart::slotApplyAllDifferences( bool /*apply*/ )
+{
+ QPtrDictIterator<KChangeLVI> it( m_diffToChangeItemDict );
+
+ kdDebug() << "m_diffToChangeItemDict.count() = " << m_diffToChangeItemDict.count() << endl;
+
+ for ( ; it.current(); ++it )
+ {
+ it.current()->setDifferenceText();
+ }
+}
+
+void KompareNavTreePart::slotApplyDifference( const Difference* diff, bool /*apply*/ )
+{
+ // this applies to the currently selected difference
+ KChangeLVI* clvi = m_diffToChangeItemDict[(void*)diff];
+ if ( clvi )
+ clvi->setDifferenceText();
+}
+
+void KChangeLVI::setDifferenceText()
+{
+ QString text;
+ switch( m_difference->type() ) {
+ case Difference::Change:
+ // Shouldn't this simply be diff->sourceLineCount() ?
+ // because you change the _number of lines_ lines in source, not in dest
+ if( m_difference->applied() )
+ text = i18n( "Applied: Changes made to %n line undone", "Applied: Changes made to %n lines undone",
+ m_difference->sourceLineCount() );
+ else
+ text = i18n( "Changed %n line", "Changed %n lines",
+ m_difference->sourceLineCount() );
+ break;
+ case Difference::Insert:
+ if( m_difference->applied() )
+ text = i18n( "Applied: Insertion of %n line undone", "Applied: Insertion of %n lines undone",
+ m_difference->destinationLineCount() );
+ else
+ text = i18n( "Inserted %n line", "Inserted %n lines",
+ m_difference->destinationLineCount() );
+ break;
+ case Difference::Delete:
+ if( m_difference->applied() )
+ text = i18n( "Applied: Deletion of %n line undone", "Applied: Deletion of %n lines undone",
+ m_difference->sourceLineCount() );
+ else
+ text = i18n( "Deleted %n line", "Deleted %n lines",
+ m_difference->sourceLineCount() );
+ break;
+ default:
+ kdDebug(8105) << "Unknown or Unchanged enum value when checking for diff->type() in KChangeLVI's constructor" << endl;
+ text = "";
+ }
+
+ setText( 2, text );
+}
+
+KChangeLVI::KChangeLVI( KListView* parent, Difference* diff ) : KListViewItem( parent )
+{
+ m_difference = diff;
+
+ setText( 0, QString::number( diff->sourceLineNumber() ) );
+ setText( 1, QString::number( diff->destinationLineNumber() ) );
+
+ setDifferenceText();
+}
+
+int KChangeLVI::compare( QListViewItem* item, int column, bool ascending ) const
+{
+ if ( ascending )
+ {
+ if ( this->text(column).length() < item->text(column).length() )
+ return -1;
+ if ( this->text(column).length() > item->text(column).length() )
+ return 1;
+ }
+ else
+ {
+ if ( this->text(column).length() > item->text(column).length() )
+ return -1;
+ if ( this->text(column).length() < item->text(column).length() )
+ return 1;
+ }
+
+ return key( column, ascending ).compare( item->key( column, ascending ) );
+}
+
+KChangeLVI::~KChangeLVI()
+{
+}
+
+KFileLVI::KFileLVI( KListView* parent, DiffModel* model ) : KListViewItem( parent )
+{
+ m_model = model;
+
+ setText( 0, model->sourceFile() );
+ setText( 1, model->destinationFile() );
+ setPixmap( 0, SmallIcon( "txt" ) );
+ setPixmap( 1, SmallIcon( "txt" ) );
+ setSelectable( true );
+}
+
+void KFileLVI::fillChangesList( KListView* changesList, QPtrDict<KChangeLVI>* diffToChangeItemDict )
+{
+ changesList->clear();
+ diffToChangeItemDict->clear();
+
+ DifferenceListConstIterator diffIt = m_model->differences()->begin();
+ DifferenceListConstIterator dEnd = m_model->differences()->end();
+
+ for ( ; diffIt != dEnd; ++diffIt )
+ {
+ KChangeLVI* change = new KChangeLVI( changesList, *diffIt );
+ diffToChangeItemDict->insert( *diffIt, change );
+ }
+
+ changesList->setSelected( changesList->firstChild(), true );
+}
+
+KFileLVI::~KFileLVI()
+{
+}
+
+KDirLVI::KDirLVI( KListView* parent, QString& dir ) : KListViewItem( parent )
+{
+// kdDebug(8105) << "KDirLVI (KListView) constructor called with dir = " << dir << endl;
+ m_rootItem = true;
+ m_dirName = dir;
+ setPixmap( 0, SmallIcon( "folder" ) );
+ setOpen( true );
+ setSelectable( true );
+ if ( m_dirName.isEmpty() )
+ setText( 0, i18n( "Unknown" ) );
+ else
+ setText( 0, m_dirName );
+}
+
+KDirLVI::KDirLVI( KDirLVI* parent, QString& dir ) : KListViewItem( parent )
+{
+// kdDebug(8105) << "KDirLVI (KDirLVI) constructor called with dir = " << dir << endl;
+ m_rootItem = false;
+ m_dirName = dir;
+ setPixmap( 0, SmallIcon( "folder" ) );
+ setOpen( true );
+ setSelectable( true );
+ setText( 0, m_dirName );
+}
+
+// addModel always removes it own path from the beginning
+void KDirLVI::addModel( QString& path, DiffModel* model, QPtrDict<KDirLVI>* modelToDirItemDict )
+{
+// kdDebug(8105) << "KDirLVI::addModel called with path = " << path << " from KDirLVI with m_dirName = " << m_dirName << endl;
+
+ if ( !m_dirName.isEmpty() )
+ {
+ if ( path.find( m_dirName ) > -1 )
+ path = path.replace( path.find( m_dirName ), m_dirName.length(), "" );
+ }
+
+// kdDebug(8105) << "Path after removal of own dir (\"" << m_dirName << "\") = " << path << endl;
+
+ if ( path.isEmpty() ) {
+ m_modelList.append( model );
+ modelToDirItemDict->insert( model, this );
+ return;
+ }
+
+ KDirLVI* child;
+
+ QString dir = path.mid( 0, path.find( "/", 0 ) + 1 );
+ child = findChild( dir );
+ if ( !child )
+ {
+ // does not exist yet so make it
+// kdDebug(8105) << "KDirLVI::addModel creating new KDirLVI because not found" << endl;
+ child = new KDirLVI( this, dir );
+ }
+
+ child->addModel( path, model, modelToDirItemDict );
+}
+
+KDirLVI* KDirLVI::findChild( QString dir )
+{
+// kdDebug(8105) << "KDirLVI::findChild called with dir = " << dir << endl;
+ KDirLVI* child;
+ if ( ( child = static_cast<KDirLVI*>(this->firstChild()) ) != 0L )
+ { // has children, check if dir already exists, if so addModel
+ do {
+ if ( dir == child->dirName() )
+ return child;
+ } while ( ( child = static_cast<KDirLVI*>(child->nextSibling()) ) != 0L );
+ }
+
+ return 0L;
+}
+
+void KDirLVI::fillFileList( KListView* fileList, QPtrDict<KFileLVI>* modelToFileItemDict )
+{
+ fileList->clear();
+
+ DiffModelListIterator modelIt = m_modelList.begin();
+ DiffModelListIterator mEnd = m_modelList.end();
+ for ( ;modelIt != mEnd; ++modelIt )
+ {
+ KFileLVI* file = new KFileLVI( fileList, *modelIt );
+ modelToFileItemDict->insert( *modelIt, file );
+ }
+
+ fileList->setSelected( fileList->firstChild(), true );
+}
+
+QString KDirLVI::fullPath( QString& path )
+{
+// if ( !path.isEmpty() )
+// kdDebug(8105) << "KDirLVI::fullPath called with path = " << path << endl;
+// else
+// kdDebug(8105) << "KDirLVI::fullPath called with empty path..." << endl;
+
+ if ( m_rootItem ) // dont bother adding rootItem's dir...
+ return path;
+
+ path = path.prepend( m_dirName );
+
+ KDirLVI* lviParent = dynamic_cast<KDirLVI*>( parent() );
+ if ( lviParent )
+ {
+ path = lviParent->fullPath( path );
+ }
+
+ return path;
+}
+
+KDirLVI* KDirLVI::setSelected( QString dir )
+{
+// kdDebug(8105) << "KDirLVI::setSelected called with dir = " << dir << endl;
+
+ // root item's dirName is never taken into account... remember that
+ if ( !m_rootItem )
+ {
+ dir = dir.remove( 0, m_dirName.length() );
+ }
+
+ if ( dir.isEmpty() )
+ {
+ return this;
+ }
+ KDirLVI* child = static_cast<KDirLVI*>(firstChild());
+ if ( !child )
+ return 0L;
+
+ do {
+ if ( dir.startsWith( child->dirName() ) )
+ return child->setSelected( dir );
+ } while ( ( child = static_cast<KDirLVI*>(child->nextSibling()) ) != 0L );
+
+ return 0L;
+}
+
+KDirLVI::~KDirLVI()
+{
+}
+
+// part stuff
+KInstance* KompareNavTreePartFactory::s_instance = 0L;
+KAboutData* KompareNavTreePartFactory::s_about = 0L;
+
+KompareNavTreePartFactory::KompareNavTreePartFactory()
+ : KParts::Factory()
+{
+}
+
+KompareNavTreePartFactory::~KompareNavTreePartFactory()
+{
+ delete s_instance;
+ delete s_about;
+
+ s_instance = 0L;
+}
+
+KParts::Part* KompareNavTreePartFactory::createPartObject( QWidget* parentWidget, const char* widgetName,
+ QObject* /*parent*/, const char* /*name*/,
+ const char* /*classname*/, const QStringList & /*args*/ )
+{
+ // Create an instance of our Part
+ KompareNavTreePart* obj = new KompareNavTreePart( parentWidget, widgetName );
+
+ KGlobal::locale()->insertCatalogue("kompare");
+
+ return obj;
+}
+
+KInstance* KompareNavTreePartFactory::instance()
+{
+ if( !s_instance )
+ {
+ s_about = new KAboutData("komparenavtreepart", I18N_NOOP("KompareNavTreePart"), "1.1");
+ s_about->addAuthor("John Firebaugh", "Author", "jfirebaugh@kde.org");
+ s_about->addAuthor("Otto Bruggeman", "Author", "otto.bruggeman@home.nl" );
+ s_instance = new KInstance(s_about);
+ }
+ return s_instance;
+}
+
+extern "C"
+{
+ KDE_EXPORT void* init_libkomparenavtreepart()
+ {
+ return new KompareNavTreePartFactory;
+ }
+}
+
+#include "komparenavtreepart.moc"
diff --git a/kompare/komparenavtreepart/komparenavtreepart.desktop b/kompare/komparenavtreepart/komparenavtreepart.desktop
new file mode 100644
index 00000000..eb5ce686
--- /dev/null
+++ b/kompare/komparenavtreepart/komparenavtreepart.desktop
@@ -0,0 +1,11 @@
+[Desktop Entry]
+Name=KompareNavTreePart
+Name[pl]=Komponent drzewa nawigacyjnego Kompare
+Name[pt_BR]=Componente da árvore do Kompare
+Name[sv]=Kompare-navigeringsträdsdel
+Name[ta]=கோமà¯à®ªà¯†à®°à¯ மரம௠பாகமà¯
+MimeType=text/x-diff
+ServiceTypes=Kompare/NavigationPart
+X-KDE-Library=libkomparenavtreepart
+Type=Service
+Icon=kompare
diff --git a/kompare/komparenavtreepart/komparenavtreepart.h b/kompare/komparenavtreepart/komparenavtreepart.h
new file mode 100644
index 00000000..e2563d63
--- /dev/null
+++ b/kompare/komparenavtreepart/komparenavtreepart.h
@@ -0,0 +1,191 @@
+/***************************************************************************
+ komparenavtreepart.h - description
+ -------------------
+ begin : Mon Feb 26 2002
+ copyright : (C) 2001-2004 Otto Bruggeman
+ (C) 2001-2003 John Firebaugh
+ email : otto.bruggeman@home.nl
+ jfirebaugh@kde.org
+****************************************************************************/
+
+/***************************************************************************
+**
+** This program is free software; you can redistribute it and/or modify
+** it under the terms of the 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 KOMPARENAVTREEPART_H
+#define KOMPARENAVTREEPART_H
+
+#include <qptrdict.h>
+#include <qptrlist.h>
+#include <qsplitter.h>
+#include <qlistview.h>
+
+#include <kparts/factory.h>
+#include <kparts/part.h>
+
+#include "kompare.h"
+#include "diffmodellist.h"
+
+class KompareModelList;
+class KomparePart;
+class KListView;
+
+namespace Diff2 {
+class DiffModel;
+class Difference;
+}
+
+class KDirLVI;
+class KFileLVI;
+class KChangeLVI;
+
+class KompareNavTreePart : public KParts::ReadOnlyPart
+{
+ Q_OBJECT
+
+public:
+ KompareNavTreePart( QWidget* parent = 0L, const char* name = 0L );
+ virtual ~KompareNavTreePart();
+
+public:
+ virtual bool openFile() { return false; };
+
+public slots:
+ void slotSetSelection( const Diff2::DiffModel* model, const Diff2::Difference* diff );
+ void slotSetSelection( const Diff2::Difference* diff );
+ void slotModelsChanged( const Diff2::DiffModelList* modelList );
+ void slotKompareInfo( Kompare::Info* info );
+
+signals:
+ void selectionChanged( const Diff2::DiffModel* model, const Diff2::Difference* diff );
+ void selectionChanged( const Diff2::Difference* diff );
+
+private slots:
+ void slotSrcDirTreeSelectionChanged ( QListViewItem* item );
+ void slotDestDirTreeSelectionChanged( QListViewItem* item );
+ void slotFileListSelectionChanged ( QListViewItem* item );
+ void slotChangesListSelectionChanged( QListViewItem* item );
+
+ void slotApplyDifference( bool apply );
+ void slotApplyAllDifferences( bool apply );
+ void slotApplyDifference( const Diff2::Difference* diff, bool apply );
+
+ void buildTreeInMemory();
+
+private:
+ void setSelectedDir( const Diff2::DiffModel* model );
+ void setSelectedFile( const Diff2::DiffModel* model );
+ void setSelectedDifference( const Diff2::Difference* diff );
+
+ void buildDirectoryTree();
+
+ QString compareFromEndAndReturnSame( const QString& string1, const QString& string2 );
+ void addDirToTreeView( enum Kompare::Target, const QString& filename );
+
+ KListViewItem* findDirInDirTree( const KListViewItem* parent, const QString& dir );
+
+// KListViewItem* firstItem();
+// KListViewItem* lastItem();
+
+private:
+ QSplitter* m_splitter;
+ const Diff2::DiffModelList* m_modelList;
+
+ QPtrDict<KChangeLVI> m_diffToChangeItemDict;
+ QPtrDict<KFileLVI> m_modelToFileItemDict;
+ QPtrDict<KDirLVI> m_modelToSrcDirItemDict;
+ QPtrDict<KDirLVI> m_modelToDestDirItemDict;
+
+ KListView* m_srcDirTree;
+ KListView* m_destDirTree;
+ KListView* m_fileList;
+ KListView* m_changesList;
+
+ KDirLVI* m_srcRootItem;
+ KDirLVI* m_destRootItem;
+
+ const Diff2::DiffModel* m_selectedModel;
+ const Diff2::Difference* m_selectedDifference;
+
+ QString m_source;
+ QString m_destination;
+
+ struct Kompare::Info* m_info;
+};
+
+// These 3 classes are need to store the models into a tree so it is easier
+// to extract the info we need for the navigation widgets
+
+class KChangeLVI : public KListViewItem
+{
+public:
+ KChangeLVI( KListView* parent, Diff2::Difference* diff );
+ ~KChangeLVI();
+public:
+ Diff2::Difference* difference() { return m_difference; };
+ virtual int compare( QListViewItem* item, int column, bool ascending ) const;
+
+ void setDifferenceText();
+private:
+ Diff2::Difference* m_difference;
+};
+
+class KFileLVI : public KListViewItem
+{
+public:
+ KFileLVI( KListView* parent, Diff2::DiffModel* model );
+ ~KFileLVI();
+public:
+ Diff2::DiffModel* model() { return m_model; };
+ void fillChangesList( KListView* changesList, QPtrDict<KChangeLVI>* diffToChangeItemDict );
+private:
+ Diff2::DiffModel* m_model;
+};
+
+class KDirLVI : public KListViewItem
+{
+public:
+ KDirLVI( KDirLVI* parent, QString& dir );
+ KDirLVI( KListView* parent, QString& dir );
+ ~KDirLVI();
+public:
+ void addModel( QString& dir, Diff2::DiffModel* model, QPtrDict<KDirLVI>* modelToDirItemDict );
+ QString& dirName() { return m_dirName; };
+ QString fullPath( QString& path );
+ KDirLVI* setSelected( QString dir );
+ void fillFileList( KListView* fileList, QPtrDict<KFileLVI>* modelToFileItemDict );
+ bool isRootItem() { return m_rootItem; };
+private:
+ KDirLVI* findChild( QString dir );
+private:
+ Diff2::DiffModelList m_modelList;
+ QString m_dirName;
+ bool m_rootItem;
+};
+
+// part stuff
+class KInstance;
+class KAboutData;
+
+class KompareNavTreePartFactory : public KParts::Factory
+{
+ Q_OBJECT
+public:
+ KompareNavTreePartFactory();
+ virtual ~KompareNavTreePartFactory();
+ virtual KParts::Part* createPartObject( QWidget *parentWidget, const char *widgetName,
+ QObject *parent, const char *name,
+ const char *classname, const QStringList &args );
+ static KInstance* instance();
+
+private:
+ static KInstance* s_instance;
+ static KAboutData* s_about;
+};
+
+#endif
diff --git a/kompare/komparepart/Makefile.am b/kompare/komparepart/Makefile.am
new file mode 100644
index 00000000..f076448b
--- /dev/null
+++ b/kompare/komparepart/Makefile.am
@@ -0,0 +1,49 @@
+#########################################################################
+# KPART SECTION
+#########################################################################
+
+INCLUDES = \
+ -I$(top_srcdir)/kompare/libdialogpages \
+ -I$(top_srcdir)/kompare/libdiff2 \
+ -I$(top_srcdir)/kompare/interfaces \
+ $(all_includes)
+
+noinst_HEADERS = \
+ kompare_part.h \
+ komparesplitter.h \
+ kompareprefdlg.h \
+ komparelistview.h \
+ kompareconnectwidget.h \
+ komparesaveoptionsbase.h \
+ komparesaveoptionswidget.h \
+ kompare_qsplitter.h
+
+# let automoc handle all of the meta source files (moc)
+METASOURCES = AUTO
+
+kde_module_LTLIBRARIES = libkomparepart.la
+
+# the Part's source, library search path, and link libraries
+libkomparepart_la_SOURCES = \
+ kompare_part.cpp \
+ kompareconnectwidget.cpp \
+ komparesplitter.cpp \
+ komparelistview.cpp \
+ kompareprefdlg.cpp \
+ komparesaveoptionsbase.ui \
+ komparesaveoptionswidget.cpp
+
+libkomparepart_la_LDFLAGS = $(KDE_PLUGIN) $(all_libraries)
+libkomparepart_la_LIBADD = $(LIB_KPARTS) $(LIB_KFILE) \
+ ../libdialogpages/libdialogpages.la \
+ ../libdiff2/libdiff2.la \
+ ../interfaces/libkompareinterface.la
+
+# this is where the desktop file will go
+partdesktopdir = $(kde_servicesdir)
+partdesktop_DATA = komparepart.desktop
+
+# this is where the part's XML-GUI resource file goes
+partrcdir = $(kde_datadir)/kompare
+partrc_DATA = komparepartui.rc
+
diff --git a/kompare/komparepart/kompare_part.cpp b/kompare/komparepart/kompare_part.cpp
new file mode 100644
index 00000000..d74945e6
--- /dev/null
+++ b/kompare/komparepart/kompare_part.cpp
@@ -0,0 +1,759 @@
+/***************************************************************************
+ kompare_part.cpp - description
+ -------------------
+ begin : Sun Mar 4 2001
+ copyright : (C) 2001-2004 Otto Bruggeman
+ (C) 2001-2003 John Firebaugh
+ (C) 2004 Jeff Snyder
+ email : otto.bruggeman@home.nl
+ jfirebaugh@kde.org
+ jeff@caffeinated.me.uk
+****************************************************************************/
+
+/***************************************************************************
+**
+** This program is free software; you can redistribute it and/or modify
+** it under the terms of the 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 "kompare_qsplitter.h" // make sure we get there first
+
+#include <qlayout.h>
+#include <qwidget.h>
+
+#include <kaction.h>
+#include <kapplication.h>
+#include <kdebug.h>
+#include <kfiletreeview.h>
+#include <kfiledialog.h>
+#include <klocale.h>
+#include <kmessagebox.h>
+#include <kstdaction.h>
+#include <kinstance.h>
+#include <ktempfile.h>
+#include <kparts/genericfactory.h>
+//#include <ktempdir.h>
+
+#include <kio/netaccess.h>
+
+#include "diffmodel.h"
+#include "komparelistview.h"
+#include "kompareconnectwidget.h"
+#include "diffsettings.h"
+#include "viewsettings.h"
+#include "kompareprefdlg.h"
+#include "komparesaveoptionswidget.h"
+#include "komparesplitter.h"
+
+#include "kompare_part.h"
+
+typedef KParts::GenericFactory<KomparePart> KomparePartFactory;
+K_EXPORT_COMPONENT_FACTORY( libkomparepart, KomparePartFactory )
+
+ViewSettings* KomparePart::m_viewSettings = 0L;
+DiffSettings* KomparePart::m_diffSettings = 0L;
+
+KomparePart::KomparePart( QWidget *parentWidget, const char *widgetName,
+ QObject *parent, const char *name, const QStringList & /*args*/ ) :
+ KParts::ReadWritePart(parent, name),
+ m_tempDiff( 0 ),
+ m_info()
+{
+ // we need an instance
+ setInstance( KomparePartFactory::instance() );
+
+ if( !m_viewSettings ) {
+ m_viewSettings = new ViewSettings( 0 );
+ }
+ if( !m_diffSettings ) {
+ m_diffSettings = new DiffSettings( 0 );
+ }
+
+ readProperties( kapp->config() );
+
+ // This creates the "Model creator" and connects the signals and slots
+ m_modelList = new Diff2::KompareModelList( m_diffSettings, m_info, this, "komparemodellist" );
+ connect( m_modelList, SIGNAL(status( Kompare::Status )),
+ this, SLOT(slotSetStatus( Kompare::Status )) );
+ connect( m_modelList, SIGNAL(setStatusBarModelInfo( int, int, int, int, int )),
+ this, SIGNAL(setStatusBarModelInfo( int, int, int, int, int )) );
+ connect( m_modelList, SIGNAL(error( QString )),
+ this, SLOT(slotShowError( QString )) );
+ connect( m_modelList, SIGNAL(applyAllDifferences( bool )),
+ this, SLOT(updateActions()) );
+ connect( m_modelList, SIGNAL(applyDifference( bool )),
+ this, SLOT(updateActions()) );
+ connect( m_modelList, SIGNAL(applyAllDifferences( bool )),
+ this, SIGNAL(appliedChanged()) );
+ connect( m_modelList, SIGNAL(applyDifference( bool )),
+ this, SIGNAL(appliedChanged()) );
+
+ connect( m_modelList, SIGNAL( setModified( bool ) ),
+ this, SLOT( slotSetModified( bool ) ) );
+
+ // This is the stuff to connect the "interface" of the kompare part to the model inside
+ connect( m_modelList, SIGNAL(modelsChanged(const Diff2::DiffModelList*)),
+ this, SIGNAL(modelsChanged(const Diff2::DiffModelList*)) );
+
+ connect( m_modelList, SIGNAL(setSelection(const Diff2::DiffModel*, const Diff2::Difference*)),
+ this, SIGNAL(setSelection(const Diff2::DiffModel*, const Diff2::Difference*)) );
+ connect( this, SIGNAL(selectionChanged(const Diff2::DiffModel*, const Diff2::Difference*)),
+ m_modelList, SLOT(slotSelectionChanged(const Diff2::DiffModel*, const Diff2::Difference*)) );
+
+ connect( m_modelList, SIGNAL(setSelection(const Diff2::Difference*)),
+ this, SIGNAL(setSelection(const Diff2::Difference*)) );
+ connect( this, SIGNAL(selectionChanged(const Diff2::Difference*)),
+ m_modelList, SLOT(slotSelectionChanged(const Diff2::Difference*)) );
+
+ connect( m_modelList, SIGNAL(applyDifference(bool)),
+ this, SIGNAL(applyDifference(bool)) );
+ connect( m_modelList, SIGNAL(applyAllDifferences(bool)),
+ this, SIGNAL(applyAllDifferences(bool)) );
+ connect( m_modelList, SIGNAL(applyDifference(const Diff2::Difference*, bool)),
+ this, SIGNAL(applyDifference(const Diff2::Difference*, bool)) );
+
+ // This creates the splitterwidget and connects the signals and slots
+ m_splitter = new KompareSplitter ( m_viewSettings, parentWidget, widgetName );
+
+ connect( m_modelList, SIGNAL(setSelection(const Diff2::DiffModel*, const Diff2::Difference*)),
+ m_splitter, SLOT(slotSetSelection(const Diff2::DiffModel*, const Diff2::Difference*)) );
+// connect( m_splitter, SIGNAL(selectionChanged(const Diff2::Difference*, const Diff2::Difference*)),
+// m_modelList, SLOT(slotSelectionChanged(const Diff2::Difference*, const Diff2::Difference*)) );
+ connect( m_modelList, SIGNAL(setSelection(const Diff2::Difference*)),
+ m_splitter, SLOT(slotSetSelection(const Diff2::Difference*)) );
+ connect( m_splitter, SIGNAL(selectionChanged(const Diff2::Difference*)),
+ m_modelList, SLOT(slotSelectionChanged(const Diff2::Difference*)) );
+
+ connect( m_modelList, SIGNAL(applyDifference(bool)),
+ m_splitter, SLOT(slotApplyDifference(bool)) );
+ connect( m_modelList, SIGNAL(applyAllDifferences(bool)),
+ m_splitter, SLOT(slotApplyAllDifferences(bool)) );
+ connect( m_modelList, SIGNAL(applyDifference(const Diff2::Difference*, bool)),
+ m_splitter, SLOT(slotApplyDifference(const Diff2::Difference*, bool)) );
+ connect( this, SIGNAL(configChanged()), m_splitter, SIGNAL(configChanged()) );
+
+ // notify the part that this is our internal widget
+ setWidget( m_splitter->parentWidget() );
+
+ setupActions();
+
+ // set our XML-UI resource file
+ setXMLFile( "komparepartui.rc" );
+
+ // we are read-write by default -> uhm what if we are opened by lets say konq in RO mode ?
+ // Then we should not be doing this...
+ setReadWrite( true );
+
+ // we are not modified since we haven't done anything yet
+ setModified( false );
+}
+
+KomparePart::~KomparePart()
+{
+ // This is the only place allowed to call cleanUpTemporaryFiles
+ // because before there might still be a use for them (when swapping)
+ cleanUpTemporaryFiles();
+}
+
+void KomparePart::setupActions()
+{
+ // create our actions
+
+ m_saveAll = new KAction( i18n("Save &All"), "save_all", 0,
+ this, SLOT(saveAll()),
+ actionCollection(), "file_save_all" );
+ m_saveDiff = new KAction( i18n("Save .&diff..."), 0,
+ this, SLOT(saveDiff()),
+ actionCollection(), "file_save_diff" );
+ m_swap = new KAction( i18n( "Swap Source with Destination" ), 0,
+ this, SLOT(slotSwap()),
+ actionCollection(), "file_swap" );
+ m_diffStats = new KAction( i18n( "Show Statistics" ), 0,
+ this, SLOT(slotShowDiffstats()),
+ actionCollection(), "file_diffstats" );
+
+ KStdAction::preferences(this, SLOT(optionsPreferences()), actionCollection());
+}
+
+void KomparePart::updateActions()
+{
+ m_saveAll->setEnabled ( m_modelList->isModified() );
+ m_saveDiff->setEnabled ( m_modelList->mode() == Kompare::ComparingFiles || m_modelList->mode() == Kompare::ComparingDirs );
+ m_swap->setEnabled ( m_modelList->mode() == Kompare::ComparingFiles || m_modelList->mode() == Kompare::ComparingDirs );
+ m_diffStats->setEnabled( m_modelList->modelCount() > 0 );
+}
+
+void KomparePart::setEncoding( const QString& encoding )
+{
+ kdDebug() << "Encoding: " << encoding << endl;
+ m_modelList->setEncoding( encoding );
+}
+
+bool KomparePart::openDiff( const KURL& url )
+{
+ kdDebug(8103) << "Url = " << url.url() << endl;
+
+ emit kompareInfo( &m_info );
+
+ m_info.mode = Kompare::ShowingDiff;
+ m_info.source = url;
+ bool result = false;
+ m_info.localSource = fetchURL( url );
+ if ( !m_info.localSource.isEmpty() )
+ {
+ kdDebug(8103) << "Download succeeded " << endl;
+ result = m_modelList->openDiff( m_info.localSource );
+ updateActions();
+ updateCaption();
+ updateStatus();
+ }
+ else
+ {
+ kdDebug(8103) << "Download failed !" << endl;
+ }
+
+ return result;
+}
+
+bool KomparePart::openDiff( const QString& diffOutput )
+{
+ bool value = false;
+
+ emit kompareInfo( &m_info );
+
+ m_info.mode = Kompare::ShowingDiff;
+
+ if ( m_modelList->parseDiffOutput( diffOutput ) == 0 )
+ {
+ value = true;
+ m_modelList->show();
+ updateActions();
+ updateCaption();
+ updateStatus();
+ }
+
+ return value;
+}
+
+bool KomparePart::openDiff3( const KURL& diff3Url )
+{
+ // FIXME: Implement this !!!
+ kdDebug(8103) << "Not implemented yet. Filename is: " << diff3Url.url() << endl;
+ return false;
+}
+
+bool KomparePart::openDiff3( const QString& diff3Output )
+{
+ // FIXME: Implement this !!!
+ kdDebug(8103) << "Not implemented yet. diff3 output is: " << endl;
+ kdDebug(8103) << diff3Output << endl;
+ return false;
+}
+
+bool KomparePart::exists( const QString& url )
+{
+ QFileInfo fi( url );
+ return fi.exists();
+}
+
+const QString KomparePart::fetchURL( const KURL& url )
+{
+ QString tempFileName( "" );
+ if ( !url.isLocalFile() )
+ {
+ if ( ! KIO::NetAccess::download( url, tempFileName, widget() ) )
+ {
+ slotShowError( i18n( "<qt>The URL <b>%1</b> cannot be downloaded.</qt>" ).arg( url.prettyURL() ) );
+ tempFileName = "";
+ }
+ return tempFileName;
+ }
+ else
+ {
+ // is Local already, check if exists
+ if ( exists( url.path() ) )
+ return url.path();
+ else
+ {
+ slotShowError( i18n( "<qt>The URL <b>%1</b> does not exist on your system.</qt>" ).arg( url.prettyURL() ) );
+ return tempFileName;
+ }
+ }
+}
+
+void KomparePart::cleanUpTemporaryFiles()
+{
+ // i hope a local file will not be removed if it was not downloaded...
+ if ( !m_info.localSource.isEmpty() )
+ KIO::NetAccess::removeTempFile( m_info.localSource );
+ if ( !m_info.localDestination.isEmpty() )
+ KIO::NetAccess::removeTempFile( m_info.localDestination );
+}
+
+void KomparePart::compare( const KURL& source, const KURL& destination )
+{
+ m_info.source = source;
+ m_info.destination = destination;
+
+ m_info.localSource = fetchURL( source );
+ m_info.localDestination = fetchURL( destination );
+
+ emit kompareInfo( &m_info );
+
+ if ( !m_info.localSource.isEmpty() && !m_info.localDestination.isEmpty() )
+ {
+ m_modelList->compare( m_info.localSource, m_info.localDestination );
+ updateActions();
+ updateCaption();
+ updateStatus();
+ }
+}
+
+void KomparePart::compareFiles( const KURL& sourceFile, const KURL& destinationFile )
+{
+ emit kompareInfo( &m_info );
+
+ m_info.mode = Kompare::ComparingFiles;
+
+ m_info.source = sourceFile;
+ m_info.destination = destinationFile;
+
+ m_info.localSource = fetchURL( sourceFile );
+ m_info.localDestination = fetchURL( destinationFile );
+
+ if ( !m_info.localSource.isEmpty() && !m_info.localDestination.isEmpty() )
+ {
+ m_modelList->compareFiles( m_info.localSource, m_info.localDestination );
+ updateActions();
+ updateCaption();
+ updateStatus();
+ }
+}
+
+void KomparePart::compareDirs( const KURL& sourceDirectory, const KURL& destinationDirectory )
+{
+ emit kompareInfo( &m_info );
+
+ m_info.mode = Kompare::ComparingDirs;
+
+ m_info.source = sourceDirectory;
+ m_info.destination = destinationDirectory;
+
+ m_info.localSource = fetchURL( sourceDirectory );
+ m_info.localDestination = fetchURL( destinationDirectory );
+
+ if ( !m_info.localSource.isEmpty() && !m_info.localDestination.isEmpty() )
+ {
+ m_modelList->compareDirs( m_info.localSource, m_info.localDestination );
+ updateActions();
+ updateCaption();
+ updateStatus();
+ }
+}
+
+void KomparePart::compare3Files( const KURL& /*originalFile*/, const KURL& /*changedFile1*/, const KURL& /*changedFile2*/ )
+{
+ // FIXME: actually implement this some day :)
+ updateActions();
+ updateCaption();
+ updateStatus();
+}
+
+void KomparePart::openFileAndDiff( const KURL& file, const KURL& diffFile )
+{
+ emit kompareInfo( &m_info );
+
+ m_info.source = file;
+ m_info.destination = diffFile;
+
+ m_info.localSource = fetchURL( file );
+ m_info.localDestination = fetchURL( diffFile );
+ m_info.mode = Kompare::BlendingFile;
+
+ if ( !m_info.localSource.isEmpty() && !m_info.localDestination.isEmpty() )
+ {
+ m_modelList->openFileAndDiff( m_info.localSource, m_info.localDestination );
+ updateActions();
+ updateCaption();
+ updateStatus();
+ }
+}
+
+void KomparePart::openDirAndDiff ( const KURL& dir, const KURL& diffFile )
+{
+ emit kompareInfo( &m_info );
+
+ m_info.source = dir;
+ m_info.destination = diffFile;
+
+ m_info.localSource = fetchURL( dir );
+ m_info.localDestination = fetchURL( diffFile );
+ m_info.mode = Kompare::BlendingDir;
+
+ if ( !m_info.localSource.isEmpty() && !m_info.localDestination.isEmpty() )
+ {
+ m_modelList->openDirAndDiff( m_info.localSource, m_info.localDestination );
+ updateActions();
+ updateCaption();
+ updateStatus();
+ }
+}
+
+bool KomparePart::openFile()
+{
+ // This is called from openURL
+ // This is a little inefficient but i will do it anyway
+ openDiff( m_url );
+ return true;
+}
+
+bool KomparePart::saveAll()
+{
+ bool result = m_modelList->saveAll();
+ updateActions();
+ updateCaption();
+ updateStatus();
+ return result;
+}
+
+void KomparePart::saveDiff()
+{
+ KDialogBase* dlg = new KDialogBase( widget(), "save_options",
+ true /* modal */, i18n("Diff Options"),
+ KDialogBase::Ok|KDialogBase::Cancel );
+ KompareSaveOptionsWidget* w = new KompareSaveOptionsWidget(
+ m_info.localSource,
+ m_info.localDestination,
+ m_diffSettings, dlg );
+ dlg->setMainWidget( w );
+ dlg->setButtonOK( KStdGuiItem::save() );
+
+ if( dlg->exec() ) {
+ w->saveOptions();
+ KConfig* config = instance()->config();
+ saveProperties( config );
+ config->sync();
+
+ while ( 1 )
+ {
+ KURL url = KFileDialog::getSaveURL( m_info.destination.url(),
+ i18n("*.diff *.dif *.patch|Patch Files"), widget(), i18n( "Save .diff" ) );
+ if ( KIO::NetAccess::exists( url, false, widget() ) )
+ {
+ int result = KMessageBox::warningYesNoCancel( widget(), i18n("The file exists or is write-protected; do you want to overwrite it?"), i18n("File Exists"), i18n("Overwrite"), i18n("Do Not Overwrite") );
+ if ( result == KMessageBox::Cancel )
+ {
+ break;
+ }
+ else if ( result == KMessageBox::No )
+ {
+ continue;
+ }
+ else
+ {
+ kdDebug(8103) << "URL = " << url.prettyURL() << endl;
+ kdDebug(8103) << "Directory = " << w->directory() << endl;
+ kdDebug(8103) << "DiffSettings = " << m_diffSettings << endl;
+
+ m_modelList->saveDiff( url.url(), w->directory(), m_diffSettings );
+ break;
+ }
+ }
+ else
+ {
+ kdDebug(8103) << "URL = " << url.prettyURL() << endl;
+ kdDebug(8103) << "Directory = " << w->directory() << endl;
+ kdDebug(8103) << "DiffSettings = " << m_diffSettings << endl;
+
+ m_modelList->saveDiff( url.url(), w->directory(), m_diffSettings );
+ break;
+ }
+ }
+ }
+ delete dlg;
+}
+
+KAboutData *KomparePart::createAboutData()
+{
+ KAboutData *about = new KAboutData("kompare", I18N_NOOP("KomparePart"), "3.2");
+ about->addAuthor("John Firebaugh", "Author", "jfirebaugh@kde.org");
+ about->addAuthor("Otto Bruggeman", "Author", "otto.bruggeman@home.nl" );
+ return about;
+}
+
+void KomparePart::slotSetStatus( enum Kompare::Status status )
+{
+ updateActions();
+
+ switch( status ) {
+ case Kompare::RunningDiff:
+ emit setStatusBarText( i18n( "Running diff..." ) );
+ break;
+ case Kompare::Parsing:
+ emit setStatusBarText( i18n( "Parsing diff output..." ) );
+ break;
+ case Kompare::FinishedParsing:
+ updateStatus();
+ break;
+ case Kompare::FinishedWritingDiff:
+ updateStatus();
+ emit diffURLChanged();
+ break;
+ default:
+ break;
+ }
+}
+
+void KomparePart::updateCaption()
+{
+ QString source = m_info.source.prettyURL();
+ QString destination = m_info.destination.prettyURL();
+
+ QString text;
+
+ switch ( m_info.mode )
+ {
+ case Kompare::ComparingFiles :
+ case Kompare::ComparingDirs :
+ case Kompare::BlendingFile :
+ case Kompare::BlendingDir :
+ text = source + ":" + destination;
+ break;
+ case Kompare::ShowingDiff :
+ text = source;
+ break;
+ default:
+ break;
+ }
+
+ emit setWindowCaption( text );
+}
+
+void KomparePart::updateStatus()
+{
+ QString source = m_info.source.prettyURL();
+ QString destination = m_info.destination.prettyURL();
+
+ QString text;
+
+ switch ( m_info.mode )
+ {
+ case Kompare::ComparingFiles :
+ text = i18n( "Comparing file %1 with file %2" )
+ .arg( source )
+ .arg( destination );
+ break;
+ case Kompare::ComparingDirs :
+ text = i18n( "Comparing files in %1 with files in %2" )
+ .arg( source )
+ .arg( destination );
+ break;
+ case Kompare::ShowingDiff :
+ text = i18n( "Viewing diff output from %1" ).arg( source );
+ break;
+ case Kompare::BlendingFile :
+ text = i18n( "Blending diff output from %1 into file %2" )
+ .arg( source )
+ .arg( destination );
+ break;
+ case Kompare::BlendingDir :
+ text = i18n( "Blending diff output from %1 into folder %2" )
+ .arg( m_info.source.prettyURL() )
+ .arg( m_info.destination.prettyURL() );
+ break;
+ default:
+ break;
+ }
+
+ emit setStatusBarText( text );
+}
+
+void KomparePart::slotShowError( QString error )
+{
+ KMessageBox::error( widget(), error );
+}
+
+void KomparePart::slotSwap()
+{
+ if ( isModified() )
+ {
+ int query = KMessageBox::warningYesNoCancel
+ (
+ widget(),
+ i18n( "You have made changes to the destination file(s).\n"
+ "Would you like to save them?" ),
+ i18n( "Save Changes?" ),
+ KStdGuiItem::save(),
+ KStdGuiItem::discard()
+ );
+
+ if ( query == KMessageBox::Yes )
+ m_modelList->saveAll();
+
+ if ( query == KMessageBox::Cancel )
+ return; // Abort prematurely so no swapping
+ }
+
+ // Swap the info in the Kompare::Info struct
+ KURL url = m_info.source;
+ m_info.source = m_info.destination;
+ m_info.destination = url;
+
+ QString string = m_info.localSource;
+ m_info.localSource = m_info.localDestination;
+ m_info.localDestination = string;
+
+ // Update window caption and statusbar text
+ updateCaption();
+ updateStatus();
+
+ m_modelList->swap();
+}
+
+void KomparePart::slotShowDiffstats( void )
+{
+ // Fetch all the args needed for komparestatsmessagebox
+ // oldfile, newfile, diffformat, noofhunks, noofdiffs
+
+ QString oldFile;
+ QString newFile;
+ QString diffFormat;
+ int filesInDiff;
+ int noOfHunks;
+ int noOfDiffs;
+
+ oldFile = m_modelList->selectedModel() ? m_modelList->selectedModel()->sourceFile() : QString( "" );
+ newFile = m_modelList->selectedModel() ? m_modelList->selectedModel()->destinationFile() : QString( "" );
+
+ if ( m_modelList->selectedModel() )
+ {
+ switch( m_info.format ) {
+ case Kompare::Unified :
+ diffFormat = i18n( "Unified" );
+ break;
+ case Kompare::Context :
+ diffFormat = i18n( "Context" );
+ break;
+ case Kompare::RCS :
+ diffFormat = i18n( "RCS" );
+ break;
+ case Kompare::Ed :
+ diffFormat = i18n( "Ed" );
+ break;
+ case Kompare::Normal :
+ diffFormat = i18n( "Normal" );
+ break;
+ case Kompare::UnknownFormat :
+ default:
+ diffFormat = i18n( "Unknown" );
+ break;
+ }
+ }
+ else
+ {
+ diffFormat = "";
+ }
+
+ filesInDiff = m_modelList->modelCount();
+
+ noOfHunks = m_modelList->selectedModel() ? m_modelList->selectedModel()->hunkCount() : 0;
+ noOfDiffs = m_modelList->selectedModel() ? m_modelList->selectedModel()->differenceCount() : 0;
+
+ if ( m_modelList->modelCount() == 0 ) { // no diff loaded yet
+ KMessageBox::information( 0L, i18n(
+ "No diff file, or no 2 files have been diffed. "
+ "Therefore no stats are available."),
+ i18n("Diff Statistics"), QString::null, false );
+ }
+ else if ( m_modelList->modelCount() == 1 ) { // 1 file in diff, or 2 files compared
+ KMessageBox::information( 0L, i18n(
+ "Statistics:\n"
+ "\n"
+ "Old file: %1\n"
+ "New file: %2\n"
+ "\n"
+ "Format: %3\n"
+ "Number of hunks: %4\n"
+ "Number of differences: %5")
+ .arg(oldFile).arg(newFile).arg(diffFormat)
+ .arg(noOfHunks).arg(noOfDiffs),
+ i18n("Diff Statistics"), QString::null, false );
+ } else { // more than 1 file in diff, or 2 directories compared
+ KMessageBox::information( 0L, i18n(
+ "Statistics:\n"
+ "\n"
+ "Number of files in diff file: %1\n"
+ "Format: %2\n"
+ "\n"
+ "Current old file: %3\n"
+ "Current new file: %4\n"
+ "\n"
+ "Number of hunks: %5\n"
+ "Number of differences: %6")
+ .arg(filesInDiff).arg(diffFormat).arg(oldFile)
+ .arg(newFile).arg(noOfHunks).arg(noOfDiffs),
+ i18n("Diff Statistics"), QString::null, false );
+ }
+}
+
+bool KomparePart::queryClose()
+{
+ if( !isModified() ) return true;
+
+ int query = KMessageBox::warningYesNoCancel
+ (
+ widget(),
+ i18n("You have made changes to the destination file(s).\n"
+ "Would you like to save them?" ),
+ i18n( "Save Changes?" ),
+ KStdGuiItem::save(),
+ KStdGuiItem::discard()
+ );
+
+ if( query == KMessageBox::Cancel )
+ return false;
+
+ if( query == KMessageBox::Yes )
+ return m_modelList->saveAll();
+
+ return true;
+}
+
+int KomparePart::readProperties( KConfig *config )
+{
+ m_viewSettings->loadSettings( config );
+ m_diffSettings->loadSettings( config );
+ emit configChanged();
+ return 0;
+}
+
+int KomparePart::saveProperties( KConfig *config )
+{
+ m_viewSettings->saveSettings( config );
+ m_diffSettings->saveSettings( config );
+ return 0;
+}
+
+void KomparePart::optionsPreferences()
+{
+ // show preferences
+ KomparePrefDlg* pref = new KomparePrefDlg( m_viewSettings, m_diffSettings );
+
+ connect( pref, SIGNAL(applyClicked()), this, SIGNAL(configChanged()) );
+
+ if ( pref->exec() )
+ emit configChanged();
+}
+
+void KomparePart::slotSetModified( bool modified )
+{
+ kdDebug() << "KomparePart::slotSetModified( " << modified << " );" << endl;
+ setModified( modified );
+ updateActions();
+ updateCaption();
+}
+
+#include "kompare_part.moc"
diff --git a/kompare/komparepart/kompare_part.h b/kompare/komparepart/kompare_part.h
new file mode 100644
index 00000000..0a9716c3
--- /dev/null
+++ b/kompare/komparepart/kompare_part.h
@@ -0,0 +1,223 @@
+/***************************************************************************
+ kompare_part.h - description
+ -------------------
+ begin : Sun Mar 4 2001
+ copyright : (C) 2001-2004 Otto Bruggeman
+ (C) 2001-2003 John Firebaugh
+ (C) 2004 Jeff Snyder
+ email : otto.bruggeman@home.nl
+ jfirebaugh@kde.org
+ jeff@caffeinated.me.uk
+****************************************************************************/
+
+/***************************************************************************
+**
+** This program is free software; you can redistribute it and/or modify
+** it under the terms of the 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 KOMPAREPART_H
+#define KOMPAREPART_H
+
+#include <kparts/factory.h>
+#include <kparts/part.h>
+
+#include "kompare.h"
+
+#include "kompareinterface.h"
+
+class QWidget;
+
+class KTempFile;
+class KToggleAction;
+class KURL;
+
+namespace Diff2 {
+class Difference;
+class DiffModel;
+class DiffModelList;
+class KompareModelList;
+}
+class DiffSettings;
+class ViewSettings;
+class KFileTreeView;
+class KompareSplitter;
+class KompareProcess;
+
+/**
+ * This is a "Part". It does all the real work in a KPart
+ * application.
+ *
+ * @short Main Part
+ * @author John Firebaugh <jfirebaugh@kde.org>
+ * @author Otto Bruggeman <bruggie@home.nl>
+ * @version 0.3
+ */
+class KomparePart : public KParts::ReadWritePart,
+ public KompareInterface
+{
+ Q_OBJECT
+public:
+ /**
+ * Default constructor
+ */
+ KomparePart( QWidget *parentWidget, const char *widgetName,
+ QObject *parent, const char *name, const QStringList & /*args*/);
+
+ /**
+ * Destructor
+ */
+ virtual ~KomparePart();
+
+ // Sessionmanagement stuff, added to the kompare iface
+ // because they are not in the Part class where they belong
+ // Should be added when bic changes are allowed again (kde 4.0)
+ virtual int readProperties( KConfig *config );
+ virtual int saveProperties( KConfig *config );
+ // this one is called when the shell_app is about to close.
+ // we need it now to save the properties of the part when apps dont (can't)
+ // use the readProperties and saveProperties methods
+ virtual bool queryClose();
+
+ // bool isModified() const { return m_modelList->isModified(); }
+ // Do we really want to expose this ???
+ const Diff2::KompareModelList* model() const { return m_modelList; };
+
+ static KAboutData *createAboutData();
+
+public:
+ // Reimplemented from the KompareInterface
+ /**
+ * Open and parse the diff file at diffUrl.
+ */
+ virtual bool openDiff( const KURL& diffUrl );
+
+ /** Added on request of Harald Fernengel */
+ virtual bool openDiff( const QString& diffOutput );
+
+ /** Open and parse the diff3 file at diff3Url */
+ virtual bool openDiff3( const KURL& diff3URL );
+
+ /** Open and parse the file diff3Output with the output of diff3 */
+ virtual bool openDiff3( const QString& diff3Output );
+
+ /** Compare, with diff, source with destination */
+ virtual void compare( const KURL& sourceFile, const KURL& destinationFile );
+
+ /** Compare, with diff, source with destination */
+ virtual void compareFiles( const KURL& sourceFile, const KURL& destinationFile );
+
+ /** Compare, with diff, source with destination */
+ virtual void compareDirs ( const KURL& sourceDir, const KURL& destinationDir );
+
+ /** Compare, with diff3, originalFile with changedFile1 and changedFile2 */
+ virtual void compare3Files( const KURL& originalFile, const KURL& changedFile1, const KURL& changedFile2 );
+
+ /** This will show the file and the file with the diff applied */
+ virtual void openFileAndDiff( const KURL& file, const KURL& diffFile );
+
+ /** This will show the directory and the directory with the diff applied */
+ virtual void openDirAndDiff ( const KURL& dir, const KURL& diffFile );
+
+ /** Reimplementing this because this one knows more about the real part then the interface */
+ virtual void setEncoding( const QString& encoding );
+
+ // This is the interpart interface, it is signal and slot based so no "real" interface here
+ // All you have to do is connect the parts from your application.
+ // These just point to their counterpart in the KompareModelList or get called from their
+ // counterpart in KompareModelList.
+signals:
+ void modelsChanged( const Diff2::DiffModelList* models );
+
+ void setSelection( const Diff2::DiffModel* model, const Diff2::Difference* diff );
+ void setSelection( const Diff2::Difference* diff );
+
+ void selectionChanged( const Diff2::DiffModel* model, const Diff2::Difference* diff );
+ void selectionChanged( const Diff2::Difference* diff );
+
+ void applyDifference( bool apply );
+ void applyAllDifferences( bool apply );
+ void applyDifference( const Diff2::Difference*, bool apply );
+
+ void configChanged();
+
+ /*
+ ** This is emitted when a difference is clicked in the kompare view. You can connect to
+ ** it so you can use it to jump to this particular line in the editor in your app.
+ */
+ void differenceClicked( int lineNumber );
+
+ // Stuff that can probably be removed by putting it in the part where it belongs in my opinion
+public slots:
+ /** Save all destinations. */
+ bool saveAll();
+
+ /** Save the results of a comparison as a diff file. */
+ void saveDiff();
+
+ /** This slot is connected to the setModifed( bool ) signal from the KompareModelList */
+ void slotSetModified( bool modified );
+
+signals:
+ void appliedChanged();
+ void diffURLChanged();
+ void kompareInfo( Kompare::Info* info );
+ void setStatusBarModelInfo( int modelIndex, int differenceIndex, int modelCount, int differenceCount, int appliedCount );
+// void setStatusBarText( const QString& text );
+
+protected:
+ /**
+ * This is the method that gets called when the file is opened,
+ * when using openURL( const KURL& ) or in our case also openDiff( const KURL& );
+ * return true when everything went ok, false if there were problems
+ */
+ virtual bool openFile();
+ virtual bool saveFile() { return true; };
+
+ // patchFile
+ bool patchFile(KURL&);
+ bool patchDir();
+
+protected slots:
+ void slotSetStatus( Kompare::Status status );
+ void slotShowError( QString error );
+
+ void slotSwap();
+ void slotShowDiffstats();
+ void optionsPreferences();
+ void updateActions();
+ void updateCaption();
+ void updateStatus();
+
+private:
+ void cleanUpTemporaryFiles();
+ void setupActions();
+ bool exists( const QString& url );
+ bool isDirectory( const KURL& url );
+ const QString fetchURL( const KURL& url );
+
+private:
+ // Uhm why were these static again ???
+ // Ah yes, so multiple instances of kompare use the
+ // same settings after one of them changes them
+ static ViewSettings* m_viewSettings;
+ static DiffSettings* m_diffSettings;
+
+ Diff2::KompareModelList* m_modelList;
+
+ KompareSplitter* m_splitter;
+
+ KAction* m_saveAll;
+ KAction* m_saveDiff;
+ KAction* m_swap;
+ KAction* m_diffStats;
+
+ KTempFile* m_tempDiff;
+
+ struct Kompare::Info m_info;
+};
+
+#endif // KOMPAREPART_H
diff --git a/kompare/komparepart/kompare_qsplitter.h b/kompare/komparepart/kompare_qsplitter.h
new file mode 100644
index 00000000..1f1be49d
--- /dev/null
+++ b/kompare/komparepart/kompare_qsplitter.h
@@ -0,0 +1,213 @@
+/****************************************************************************
+**
+**
+** Definition of QSplitter class
+**
+** Created : 980105
+**
+** Copyright (C) 1992-2000 Trolltech AS. All rights reserved.
+**
+** This file is part of the widgets module of the Qt GUI Toolkit.
+**
+** This file may be distributed and/or modified under the terms of the
+** GNU General Public License version 2 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file.
+**
+** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+**
+** See http://www.trolltech.com/gpl/ for GPL licensing information.
+**
+**********************************************************************/
+
+#ifndef QSPLITTER_H
+#define QSPLITTER_H
+
+#ifndef QT_H
+#include "qframe.h"
+#include "qvaluelist.h"
+#endif // QT_H
+
+#ifndef QT_NO_SPLITTER
+
+
+//class QSplitterHandle;
+class QSplitterLayoutStruct;
+class QTextStream;
+
+class QSplitterPrivate
+{
+public:
+ QSplitterPrivate()
+ : opaque( FALSE ), firstShow( TRUE ), childrenCollapsible( TRUE ),
+ handleWidth( 0 ) { }
+
+ QPtrList<QSplitterLayoutStruct> list;
+ bool opaque : 8;
+ bool firstShow : 8;
+ bool childrenCollapsible : 8;
+ int handleWidth;
+};
+
+class Q_EXPORT QSplitter : public QFrame
+{
+ Q_OBJECT
+ Q_PROPERTY( Orientation orientation READ orientation WRITE setOrientation )
+ Q_PROPERTY( bool opaqueResize READ opaqueResize WRITE setOpaqueResize )
+ Q_PROPERTY( int handleWidth READ handleWidth WRITE setHandleWidth )
+ Q_PROPERTY( bool childrenCollapsible READ childrenCollapsible WRITE setChildrenCollapsible )
+
+public:
+ // ### Qt 4.0: remove Auto from public API
+ enum ResizeMode { Stretch, KeepSize, FollowSizeHint, Auto };
+
+ QSplitter( QWidget* parent = 0, const char* name = 0 );
+ QSplitter( Orientation, QWidget* parent = 0, const char* name = 0 );
+ ~QSplitter();
+
+ virtual void setOrientation( Orientation );
+ Orientation orientation() const { return orient; }
+
+ // ### Qt 4.0: make setChildrenCollapsible() and setCollapsible() virtual
+
+ void setChildrenCollapsible( bool );
+ bool childrenCollapsible() const;
+
+ void setCollapsible( QWidget *w, bool );
+ virtual void setResizeMode( QWidget *w, ResizeMode );
+ virtual void setOpaqueResize( bool = TRUE );
+ bool opaqueResize() const;
+
+ void moveToFirst( QWidget * );
+ void moveToLast( QWidget * );
+
+ void refresh() { recalc( TRUE ); }
+ QSize sizeHint() const;
+ QSize minimumSizeHint() const;
+
+ QValueList<int> sizes() const;
+ void setSizes( QValueList<int> );
+
+ int handleWidth() const;
+ void setHandleWidth( int );
+
+protected:
+ void childEvent( QChildEvent * );
+
+ bool event( QEvent * );
+ void resizeEvent( QResizeEvent * );
+
+ int idAfter( QWidget* ) const;
+
+ void moveSplitter( QCOORD pos, int id );
+ virtual void drawSplitter( QPainter*, QCOORD x, QCOORD y,
+ QCOORD w, QCOORD h );
+ void styleChange( QStyle& );
+ int adjustPos( int, int );
+ virtual void setRubberband( int );
+ void getRange( int id, int *, int * );
+
+public: // private (:
+ enum { DefaultResizeMode = 3 };
+
+ void init();
+ void recalc( bool update = FALSE );
+ void doResize();
+ void storeSizes();
+ void getRange( int id, int *, int *, int *, int * );
+ void addContribution( int, int *, int *, bool );
+ int adjustPos( int, int, int *, int *, int *, int * );
+ bool collapsible( QSplitterLayoutStruct * );
+ void processChildEvents();
+ QSplitterLayoutStruct *findWidget( QWidget * );
+ QSplitterLayoutStruct *addWidget( QWidget *, bool prepend = FALSE );
+ void recalcId();
+ void doMove( bool backwards, int pos, int id, int delta, bool upLeft,
+ bool mayCollapse );
+ void setGeo( QWidget *w, int pos, int size, bool splitterMoved );
+ int findWidgetJustBeforeOrJustAfter( int id, int delta, int &collapsibleSize );
+ void updateHandles();
+
+ inline QCOORD pick( const QPoint &p ) const
+ { return orient == Horizontal ? p.x() : p.y(); }
+ inline QCOORD pick( const QSize &s ) const
+ { return orient == Horizontal ? s.width() : s.height(); }
+
+ inline QCOORD trans( const QPoint &p ) const
+ { return orient == Vertical ? p.x() : p.y(); }
+ inline QCOORD trans( const QSize &s ) const
+ { return orient == Vertical ? s.width() : s.height(); }
+
+ QSplitterPrivate *d;
+
+ Orientation orient;
+ friend class QSplitterHandle;
+
+#ifndef QT_NO_TEXTSTREAM
+// moc doesn't like these.
+// friend Q_EXPORT QTextStream& operator<<( QTextStream&, const QSplitter& );
+// friend Q_EXPORT QTextStream& operator>>( QTextStream&, QSplitter& );
+#endif
+
+public:
+#if defined(Q_DISABLE_COPY)
+ QSplitter( const QSplitter & );
+ QSplitter& operator=( const QSplitter & );
+#endif
+};
+
+#ifndef QT_NO_TEXTSTREAM
+Q_EXPORT QTextStream& operator<<( QTextStream&, const QSplitter& );
+Q_EXPORT QTextStream& operator>>( QTextStream&, QSplitter& );
+#endif
+
+class QSplitterHandle : public QWidget
+{
+ Q_OBJECT
+public:
+ QSplitterHandle( Orientation o,
+ QSplitter *parent, const char* name=0 );
+ void setOrientation( Orientation o );
+ Orientation orientation() const { return orient; }
+
+ bool opaque() const { return s->opaqueResize(); }
+
+ QSize sizeHint() const;
+
+ int id() const { return myId; } // d->list.at(id())->wid == this
+ void setId( int i ) { myId = i; }
+
+protected:
+ void paintEvent( QPaintEvent * );
+ void mouseMoveEvent( QMouseEvent * );
+ void mousePressEvent( QMouseEvent * );
+ void mouseReleaseEvent( QMouseEvent * );
+
+public: // private (:
+ Orientation orient;
+ bool opaq;
+ int myId;
+
+ QSplitter *s;
+};
+
+const uint Default = 2;
+
+class QSplitterLayoutStruct : public Qt
+{
+public:
+ QCOORD sizer;
+ uint isHandle : 1;
+ uint collapsible : 2;
+ uint resizeMode : 2;
+ QWidget *wid;
+
+ QSplitterLayoutStruct()
+ : sizer( -1 ), collapsible( Default ) { }
+ QCOORD getSizer( Orientation orient );
+};
+
+#endif // QT_NO_SPLITTER
+
+#endif // QSPLITTER_H
diff --git a/kompare/komparepart/kompareconnectwidget.cpp b/kompare/komparepart/kompareconnectwidget.cpp
new file mode 100644
index 00000000..eed8e99c
--- /dev/null
+++ b/kompare/komparepart/kompareconnectwidget.cpp
@@ -0,0 +1,285 @@
+/***************************************************************************
+ kompareconnectwidget.cpp - description
+ -------------------
+ begin : Tue Jun 26 2001
+ copyright : (C) 2001-2003 John Firebaugh
+ (C) 2001-2004 Otto Bruggeman
+ (C) 2004 Jeff Snyder
+ email : jfirebaugh@kde.org
+ otto.bruggeman@home.nl
+ jeff@caffeinated.me.uk
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the 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 <qapplication.h>
+#include <qpainter.h>
+#include <qpixmap.h>
+#include <qstyle.h>
+#include <qtimer.h>
+
+#include <kdebug.h>
+
+#include "viewsettings.h"
+#include "komparemodellist.h"
+#include "komparelistview.h"
+#include "komparesplitter.h"
+
+#include "kompareconnectwidget.h"
+
+using namespace Diff2;
+
+KompareConnectWidgetFrame::KompareConnectWidgetFrame( KompareListView* left,
+ KompareListView* right,
+ ViewSettings* settings,
+ KompareSplitter* parent,
+ const char* name ) :
+ QSplitterHandle(Horizontal, (QSplitter *)parent, name),
+ m_wid ( left, right, settings, this, name ),
+ m_label ( "", this ),
+ m_layout ( this )
+{
+ setSizePolicy ( QSizePolicy(QSizePolicy::Fixed, QSizePolicy::Ignored) );
+ m_wid.setSizePolicy ( QSizePolicy(QSizePolicy::Ignored, QSizePolicy::Ignored) );
+ m_label.setSizePolicy ( QSizePolicy(QSizePolicy::Ignored, QSizePolicy::Fixed) );
+ m_label.setMargin(3);
+ QFrame* bottomLine = new QFrame(this);
+ bottomLine->setFrameShape(QFrame::HLine);
+ bottomLine->setFrameShadow ( QFrame::Plain );
+ bottomLine->setSizePolicy ( QSizePolicy(QSizePolicy::Ignored, QSizePolicy::Fixed) );
+ bottomLine->setFixedHeight(1);
+ m_layout.setSpacing(0);
+ m_layout.setMargin(0);
+ m_layout.addWidget(&m_label);
+ m_layout.addWidget(bottomLine);
+ m_layout.addWidget(&m_wid);
+}
+
+KompareConnectWidgetFrame::~KompareConnectWidgetFrame()
+{
+}
+
+QSize KompareConnectWidgetFrame::sizeHint() const
+{
+ return QSize(50, style().pixelMetric( QStyle::PM_ScrollBarExtent ) );
+}
+
+static int kMouseOffset;
+
+void KompareConnectWidgetFrame::mouseMoveEvent( QMouseEvent *e )
+{
+ if ( !(e->state()&LeftButton) )
+ return;
+
+ QCOORD pos = s->pick( parentWidget()->mapFromGlobal(e->globalPos()) )
+ - kMouseOffset;
+
+ ((KompareSplitter*)s)->moveSplitter( pos, id() );
+}
+
+void KompareConnectWidgetFrame::mousePressEvent( QMouseEvent *e )
+{
+ if ( e->button() == LeftButton )
+ kMouseOffset = s->pick( e->pos() );
+ QSplitterHandle::mousePressEvent(e);
+}
+
+void KompareConnectWidgetFrame::mouseReleaseEvent( QMouseEvent *e )
+{
+ if ( !opaque() && e->button() == LeftButton ) {
+ QCOORD pos = s->pick( parentWidget()->mapFromGlobal(e->globalPos()) )
+ - kMouseOffset;
+ ((KompareSplitter*)s)->moveSplitter( pos, id() );
+ }
+}
+
+KompareConnectWidget::KompareConnectWidget( KompareListView* left, KompareListView* right,
+ ViewSettings* settings, QWidget* parent, const char* name )
+ : QWidget(parent, name),
+ m_settings( settings ),
+ m_leftView( left ),
+ m_rightView( right ),
+ m_selectedModel( 0 ),
+ m_selectedDifference( 0 )
+{
+// connect( m_settings, SIGNAL( settingsChanged() ), this, SLOT( slotDelayedRepaint() ) );
+ setBackgroundMode( NoBackground );
+ setSizePolicy( QSizePolicy( QSizePolicy::Fixed, QSizePolicy::Minimum ) );
+ setFocusProxy( parent->parentWidget() );
+}
+
+KompareConnectWidget::~KompareConnectWidget()
+{
+}
+
+void KompareConnectWidget::slotSetSelection( const DiffModel* model, const Difference* diff )
+{
+ if( m_selectedModel == model && m_selectedDifference == diff )
+ return;
+
+ if ( m_selectedModel == model && m_selectedDifference != diff )
+ {
+ m_selectedDifference = diff;
+ slotDelayedRepaint();
+ return;
+ }
+
+ m_selectedModel = model;
+ m_selectedDifference = diff;
+
+ slotDelayedRepaint();
+}
+
+void KompareConnectWidget::slotDelayedRepaint()
+{
+ QTimer::singleShot( 0, this, SLOT( repaint() ) );
+}
+
+void KompareConnectWidget::slotSetSelection( const Difference* diff )
+{
+ if ( m_selectedDifference == diff )
+ return;
+
+ m_selectedDifference = diff;
+
+ slotDelayedRepaint();
+}
+
+void KompareConnectWidget::paintEvent( QPaintEvent* /* e */ )
+{
+// kdDebug(8106) << "KompareConnectWidget::paintEvent()" << endl;
+
+ QPixmap pixbuf(size());
+ QPainter paint(&pixbuf, this);
+ QPainter* p = &paint;
+
+ p->fillRect( 0, 0, pixbuf.width(), pixbuf.height(), white.dark(110) );
+
+ if ( m_selectedModel )
+ {
+ int firstL = m_leftView->firstVisibleDifference();
+ int firstR = m_rightView->firstVisibleDifference();
+ int lastL = m_leftView->lastVisibleDifference();
+ int lastR = m_rightView->lastVisibleDifference();
+
+ int first = firstL < 0 ? firstR : QMIN( firstL, firstR );
+ int last = lastL < 0 ? lastR : QMAX( lastL, lastR );
+
+// kdDebug(8106) << " left: " << firstL << " - " << lastL << endl;
+// kdDebug(8106) << " right: " << firstR << " - " << lastR << endl;
+// kdDebug(8106) << " drawing: " << first << " - " << last << endl;
+ if ( first >= 0 && last >= 0 && first <= last )
+ {
+ const DifferenceList* differences = const_cast<DiffModel*>(m_selectedModel)->differences();
+ DifferenceListConstIterator diffIt = differences->at( first );
+ DifferenceListConstIterator dEnd = differences->at( last + 1 );
+
+ QRect leftRect, rightRect;
+
+ for ( int i = first; i <= last; ++diffIt, ++i )
+ {
+ Difference* diff = *diffIt;
+ bool selected = ( diff == m_selectedDifference );
+
+ if ( QApplication::reverseLayout() )
+ {
+ leftRect = m_rightView->itemRect( i );
+ rightRect = m_leftView->itemRect( i );
+ }
+ else
+ {
+ leftRect = m_leftView->itemRect( i );
+ rightRect = m_rightView->itemRect( i );
+ }
+
+ int tl = leftRect.top();
+ int tr = rightRect.top();
+ int bl = leftRect.bottom();
+ int br = rightRect.bottom();
+
+ // Bah, stupid 16-bit signed shorts in that crappy X stuff...
+ tl = tl >= -32768 ? tl : -32768;
+ tr = tr >= -32768 ? tr : -32768;
+ bl = bl <= 32767 ? bl : 32767;
+ br = br <= 32767 ? br : 32767;
+
+// kdDebug(8106) << "drawing: " << tl << " " << tr << " " << bl << " " << br << endl;
+ QPointArray topBezier = makeTopBezier( tl, tr );
+ QPointArray bottomBezier = makeBottomBezier( bl, br );
+
+ QColor color = m_settings->colorForDifferenceType( diff->type(), selected, diff->applied() ).dark(110);
+ p->setPen( color );
+ p->setBrush( color );
+ p->drawPolygon ( makeConnectPoly( topBezier, bottomBezier ) );
+
+ if ( selected )
+ {
+ p->setPen( color.dark(135) );
+ p->drawPolyline( topBezier );
+ p->drawPolyline( bottomBezier );
+ }
+ }
+ }
+ }
+
+ p->flush();
+ bitBlt(this, 0, 0, &pixbuf);
+}
+
+QPointArray KompareConnectWidget::makeTopBezier( int tl, int tr )
+{
+ int l = 0;
+ int r = width();
+ int o = (int)((double)r*0.4); // 40% of width
+ QPointArray controlPoints;
+
+ if ( tl != tr )
+ {
+ controlPoints.setPoints( 4, l,tl, o,tl, r-o,tr, r,tr );
+ return controlPoints.cubicBezier();
+ }
+ else
+ {
+ controlPoints.setPoints( 2, l,tl, r,tr );
+ return controlPoints;
+ }
+}
+
+QPointArray KompareConnectWidget::makeBottomBezier( int bl, int br )
+{
+ int l = 0;
+ int r = width();
+ int o = (int)((double)r*0.4); // 40% of width
+ QPointArray controlPoints;
+
+ if ( bl != br )
+ {
+ controlPoints.setPoints( 4, r,br, r-o,br, o,bl, l,bl );
+ return controlPoints.cubicBezier();
+ }
+ else
+ {
+ controlPoints.setPoints( 2, r,br, l,bl );
+ return controlPoints;
+ }
+}
+
+QPointArray KompareConnectWidget::makeConnectPoly( const QPointArray& topBezier, const QPointArray& bottomBezier )
+{
+ QPointArray poly( topBezier.size() + bottomBezier.size() );
+ for( uint i = 0; i < topBezier.size(); i++ )
+ poly.setPoint( i, topBezier.point( i ) );
+ for( uint i = 0; i < bottomBezier.size(); i++ )
+ poly.setPoint( i + topBezier.size(), bottomBezier.point( i ) );
+
+ return poly;
+}
+
+#include "kompareconnectwidget.moc"
diff --git a/kompare/komparepart/kompareconnectwidget.h b/kompare/komparepart/kompareconnectwidget.h
new file mode 100644
index 00000000..96160c97
--- /dev/null
+++ b/kompare/komparepart/kompareconnectwidget.h
@@ -0,0 +1,95 @@
+/***************************************************************************
+ kompareconnectwidget.h - description
+ -------------------
+ begin : Tue Jun 26 2001
+ copyright : (C) 2001-2003 John Firebaugh
+ (C) 2001-2004 Otto Bruggeman
+ (C) 2004 Jeff Snyder
+ email : jfirebaugh@kde.org
+ otto.bruggeman@home.nl
+ jeff@caffeinated.me.uk
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the 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 KOMPARECONNECTWIDGET_H
+#define KOMPARECONNECTWIDGET_H
+
+#include "kompare_qsplitter.h"
+#include <qwidget.h>
+
+namespace Diff2 {
+class DiffModel;
+}
+class ViewSettings;
+class KompareListView;
+class KompareSplitter;
+
+class KompareConnectWidget : public QWidget
+{
+ Q_OBJECT
+
+public:
+ KompareConnectWidget( KompareListView* left, KompareListView* right,
+ ViewSettings* settings, QWidget* parent, const char* name = 0 );
+ ~KompareConnectWidget();
+
+public slots:
+ void slotSetSelection( const Diff2::DiffModel* model, const Diff2::Difference* diff );
+ void slotSetSelection( const Diff2::Difference* diff );
+
+ void slotDelayedRepaint();
+
+signals:
+ void selectionChanged(const Diff2::Difference* diff);
+
+protected:
+ void paintEvent( QPaintEvent* e );
+ QPointArray makeTopBezier( int tl, int tr );
+ QPointArray makeBottomBezier( int bl, int br );
+ QPointArray makeConnectPoly( const QPointArray& topBezier, const QPointArray& bottomBezier );
+
+private:
+ ViewSettings* m_settings;
+
+ KompareListView* m_leftView;
+ KompareListView* m_rightView;
+
+ const Diff2::DiffModel* m_selectedModel;
+ const Diff2::Difference* m_selectedDifference;
+};
+
+class KompareConnectWidgetFrame : public QSplitterHandle
+{
+ Q_OBJECT
+public:
+ KompareConnectWidgetFrame( KompareListView* left, KompareListView* right,
+ ViewSettings* settings, KompareSplitter* parent, const char* name = 0 );
+ ~KompareConnectWidgetFrame();
+
+ QSize sizeHint() const;
+
+ KompareConnectWidget* wid() { return &m_wid; }
+
+protected:
+ // stop the parent QSplitterHandle painting
+ void paintEvent( QPaintEvent* /* e */ ) { }
+
+ void mouseMoveEvent( QMouseEvent * );
+ void mousePressEvent( QMouseEvent * );
+ void mouseReleaseEvent( QMouseEvent * );
+
+private:
+ KompareConnectWidget m_wid;
+ QLabel m_label;
+ QVBoxLayout m_layout;
+};
+
+#endif
diff --git a/kompare/komparepart/komparelistview.cpp b/kompare/komparepart/komparelistview.cpp
new file mode 100644
index 00000000..b86bdef9
--- /dev/null
+++ b/kompare/komparepart/komparelistview.cpp
@@ -0,0 +1,783 @@
+/***************************************************************************
+ komparelistview.h - description
+ -------------------
+ begin : Sun Mar 4 2001
+ copyright : (C) 2001-2004 Otto Bruggeman
+ (C) 2001-2003 John Firebaugh
+ (C) 2004 Jeff Snyder
+ email : otto.bruggeman@home.nl
+ jfirebaugh@kde.org
+ jeff@caffeinated.me.uk
+****************************************************************************/
+
+/***************************************************************************
+**
+** This program is free software; you can redistribute it and/or modify
+** it under the terms of the 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 <qheader.h>
+#include <qpainter.h>
+#include <qregexp.h>
+#include <qtimer.h>
+
+#include <kdebug.h>
+#include <kglobal.h>
+#include <kglobalsettings.h>
+
+#include "diffmodel.h"
+#include "diffhunk.h"
+#include "difference.h"
+#include "viewsettings.h"
+#include "komparemodellist.h"
+#include "komparesplitter.h"
+
+#include "komparelistview.h"
+
+#define COL_LINE_NO 0
+#define COL_MAIN 1
+
+#define BLANK_LINE_HEIGHT 3
+#define HUNK_LINE_HEIGHT 5
+
+using namespace Diff2;
+
+KompareListViewFrame::KompareListViewFrame( bool isSource,
+ ViewSettings* settings,
+ KompareSplitter* parent,
+ const char* name ):
+ QFrame ( parent, name ),
+ m_view ( isSource, settings, this, name ),
+ m_label ( isSource?"Source":"Dest", this ),
+ m_layout ( this )
+{
+ setSizePolicy ( QSizePolicy(QSizePolicy::Ignored, QSizePolicy::Ignored) );
+ m_label.setSizePolicy ( QSizePolicy(QSizePolicy::Ignored, QSizePolicy::Fixed) );
+ QFrame *bottomLine = new QFrame(this);
+ bottomLine->setFrameShape(QFrame::HLine);
+ bottomLine->setFrameShadow ( QFrame::Plain );
+ bottomLine->setSizePolicy ( QSizePolicy(QSizePolicy::Ignored, QSizePolicy::Fixed) );
+ bottomLine->setFixedHeight(1);
+ m_label.setMargin(3);
+ m_layout.setSpacing(0);
+ m_layout.setMargin(0);
+ m_layout.addWidget(&m_label);
+ m_layout.addWidget(bottomLine);
+ m_layout.addWidget(&m_view);
+
+ connect( &m_view, SIGNAL(differenceClicked(const Diff2::Difference*)),
+ parent, SLOT(slotDifferenceClicked(const Diff2::Difference*)) );
+
+ connect( parent, SIGNAL(scrollViewsToId(int)), &m_view, SLOT(scrollToId(int)) );
+ connect( parent, SIGNAL(setXOffset(int)), &m_view, SLOT(setXOffset(int)) );
+ connect( &m_view, SIGNAL(resized()), parent, SLOT(slotUpdateScrollBars()) );
+}
+
+void KompareListViewFrame::slotSetModel( const DiffModel* model )
+{
+ if( model )
+ {
+ if( view()->isSource() ) {
+ if( !model->sourceRevision().isEmpty() )
+ m_label.setText( model->sourceFile() + " (" + model->sourceRevision() + ")" );
+ else
+ m_label.setText( model->sourceFile() );
+ } else {
+ if( !model->destinationRevision().isEmpty() )
+ m_label.setText( model->destinationFile() + " (" + model->destinationRevision() + ")" );
+ else
+ m_label.setText( model->destinationFile() );
+ }
+ } else {
+ m_label.setText( QString::null );
+ }
+}
+
+KompareListView::KompareListView( bool isSource,
+ ViewSettings* settings,
+ QWidget* parent, const char* name ) :
+ KListView( parent, name ),
+ m_isSource( isSource ),
+ m_settings( settings ),
+ m_scrollId( -1 ),
+ m_selectedModel( 0 ),
+ m_selectedDifference( 0 )
+{
+ header()->hide();
+ addColumn( "Line Number", 0 );
+ addColumn( "Main" );
+ addColumn( "Blank" );
+ setColumnAlignment( COL_LINE_NO, AlignRight );
+ setAllColumnsShowFocus( true );
+ setRootIsDecorated( false );
+ setSorting( -1 );
+ setItemMargin( 3 );
+ setTreeStepSize( 0 );
+ setColumnWidthMode( COL_LINE_NO, Maximum );
+ setColumnWidthMode( COL_MAIN, Maximum );
+ setResizeMode( LastColumn );
+ setFrameStyle( QFrame::NoFrame );
+ setVScrollBarMode( QScrollView::AlwaysOff );
+ setHScrollBarMode( QScrollView::AlwaysOff );
+ setFocusPolicy( QWidget::NoFocus );
+ setFont( m_settings->m_font );
+ setSpaces( m_settings->m_tabToNumberOfSpaces );
+ setFocusProxy( parent->parentWidget() );
+}
+
+KompareListView::~KompareListView()
+{
+}
+
+KompareListViewItem* KompareListView::itemAtIndex( int i )
+{
+ return m_items[ i ];
+}
+
+int KompareListView::firstVisibleDifference()
+{
+ QListViewItem* item = itemAt( QPoint( 0, 0 ) );
+
+ if( item == 0 )
+ {
+ kdDebug(8104) << "no item at viewport coordinates (0,0)" << endl;
+ }
+
+ while( item ) {
+ KompareListViewLineItem* lineItem = dynamic_cast<KompareListViewLineItem*>(item);
+ if( lineItem && lineItem->diffItemParent()->difference()->type() != Difference::Unchanged )
+ break;
+ item = item->itemBelow();
+ }
+
+ if( item )
+ return m_items.findIndex( ((KompareListViewLineItem*)item)->diffItemParent() );
+
+ return -1;
+}
+
+int KompareListView::lastVisibleDifference()
+{
+ QListViewItem* item = itemAt( QPoint( 0, visibleHeight() - 1 ) );
+
+ if( item == 0 )
+ {
+ kdDebug(8104) << "no item at viewport coordinates (0," << visibleHeight() - 1 << ")" << endl;
+ item = lastItem();
+ }
+
+ while( item ) {
+ KompareListViewLineItem* lineItem = dynamic_cast<KompareListViewLineItem*>(item);
+ if( lineItem && lineItem->diffItemParent()->difference()->type() != Difference::Unchanged )
+ break;
+ item = item->itemAbove();
+ }
+
+ if( item )
+ return m_items.findIndex( ((KompareListViewLineItem*)item)->diffItemParent() );
+
+ return -1;
+}
+
+QRect KompareListView::itemRect( int i )
+{
+ QListViewItem* item = itemAtIndex( i );
+ int x = 0;
+ int y = itemPos( item );
+ int vx, vy;
+ contentsToViewport( x, y, vx, vy );
+ return QRect( vx, vy, 0, item->totalHeight() );
+}
+
+int KompareListView::minScrollId()
+{
+ return visibleHeight() / 2;
+}
+
+int KompareListView::maxScrollId()
+{
+ KompareListViewItem* item = (KompareListViewItem*)firstChild();
+ if(!item) return 0;
+ while( item && item->nextSibling() ) {
+ item = (KompareListViewItem*)item->nextSibling();
+ }
+ int maxId = item->scrollId() + item->maxHeight() - minScrollId();
+ kdDebug(8104) << "Max ID = " << maxId << endl;
+ return maxId;
+}
+
+int KompareListView::contentsWidth()
+{
+ return ( columnWidth(COL_LINE_NO) + columnWidth(COL_MAIN) );
+}
+
+void KompareListView::setXOffset( int x )
+{
+ kdDebug(8104) << "SetXOffset : Scroll to x position: " << x << endl;
+ setContentsPos( x, contentsY() );
+}
+
+void KompareListView::scrollToId( int id )
+{
+// kdDebug(8104) << "ScrollToID : Scroll to id : " << id << endl;
+ KompareListViewItem* item = (KompareListViewItem*)firstChild();
+ while( item && item->nextSibling() ) {
+ if( ((KompareListViewItem*)item->nextSibling())->scrollId() > id )
+ break;
+ item = (KompareListViewItem*)item->nextSibling();
+ }
+
+ if( item ) {
+ int pos = item->itemPos();
+ int itemId = item->scrollId();
+ int height = item->totalHeight();
+ double r = (double)( id - itemId ) / (double)item->maxHeight();
+ int y = pos + (int)( r * (double)height ) - minScrollId();
+// kdDebug(8104) << "scrollToID: " << endl;
+// kdDebug(8104) << " id = " << id << endl;
+// kdDebug(8104) << " id after = " << ( item->nextSibling() ? QString::number( ((KompareListViewItem*)item->nextSibling())->scrollId() ) : "no such sibling..." ) << endl;
+// kdDebug(8104) << " pos = " << pos << endl;
+// kdDebug(8104) << " itemId = " << itemId << endl;
+// kdDebug(8104) << " r = " << r << endl;
+// kdDebug(8104) << " height = " << height << endl;
+// kdDebug(8104) << " minID = " << minScrollId() << endl;
+// kdDebug(8104) << " y = " << y << endl;
+// kdDebug(8104) << "contentsHeight = " << contentsHeight() << endl;
+// kdDebug(8104) << " c - y = " << contentsHeight() - y << endl;
+ setContentsPos( contentsX(), y );
+ }
+
+ m_scrollId = id;
+}
+
+int KompareListView::scrollId()
+{
+ if( m_scrollId < 0 )
+ m_scrollId = minScrollId();
+ return m_scrollId;
+}
+
+void KompareListView::setSelectedDifference( const Difference* diff, bool scroll )
+{
+ kdDebug(8104) << "KompareListView::setSelectedDifference(" << diff << ", " << scroll << ")" << endl;
+
+ // When something other than a click causes this function to be called,
+ // it'll only get called once, and all is simple.
+ //
+ // When the user clicks on a diff, this function will get called once when
+ // komparesplitter::slotDifferenceClicked runs, and again when the
+ // setSelection signal from the modelcontroller arrives.
+ //
+ // the first call (which will always be from the splitter) will have
+ // scroll==false, and the the second call will bail out here.
+ // Which is why clicking on a difference does not cause the listviews to
+ // scroll.
+ if ( m_selectedDifference == diff )
+ return;
+
+ m_selectedDifference = diff;
+
+ KompareListViewItem* item = m_itemDict[ (void*)diff ];
+ if( !item ) {
+ kdDebug(8104) << "KompareListView::slotSetSelection(): couldn't find our selection!" << endl;
+ return;
+ }
+
+ // why does this not happen when the user clicks on a diff? see the comment above.
+ if( scroll )
+ scrollToId(item->scrollId());
+ setSelected( item, true );
+}
+
+void KompareListView::slotSetSelection( const Difference* diff )
+{
+ kdDebug(8104) << "KompareListView::slotSetSelection( const Difference* diff )" << endl;
+
+ setSelectedDifference( diff, true );
+}
+
+void KompareListView::slotSetSelection( const DiffModel* model, const Difference* diff )
+{
+ kdDebug(8104) << "KompareListView::slotSetSelection( const DiffModel* model, const Difference* diff )" << endl;
+
+ if( m_selectedModel && m_selectedModel == model ) {
+ slotSetSelection( diff );
+ return;
+ }
+
+ clear();
+ m_items.clear();
+ m_itemDict.clear();
+ m_selectedModel = model;
+
+ m_itemDict.resize(model->differenceCount());
+
+ DiffHunkListConstIterator hunkIt = model->hunks()->begin();
+ DiffHunkListConstIterator hEnd = model->hunks()->end();
+
+ KompareListViewItem* item = 0;
+ Difference* tmpdiff = 0;
+ DiffHunk* hunk = 0;
+
+
+ for ( ; hunkIt != hEnd; ++hunkIt )
+ {
+ hunk = *hunkIt;
+
+ if( item )
+ item = new KompareListViewHunkItem( this, item, hunk, model->isBlended() );
+ else
+ item = new KompareListViewHunkItem( this, hunk, model->isBlended() );
+
+ DifferenceListConstIterator diffIt = hunk->differences().begin();
+ DifferenceListConstIterator dEnd = hunk->differences().end();
+
+ for ( ; diffIt != dEnd; ++diffIt )
+ {
+ tmpdiff = *diffIt;
+
+ item = new KompareListViewDiffItem( this, item, tmpdiff );
+
+ int type = tmpdiff->type();
+
+ if ( type != Difference::Unchanged )
+ {
+ m_items.append( (KompareListViewDiffItem*)item );
+ m_itemDict.insert( tmpdiff, (KompareListViewDiffItem*)item );
+ }
+ }
+ }
+
+ slotSetSelection( diff );
+}
+
+void KompareListView::contentsMousePressEvent( QMouseEvent* e )
+{
+ QPoint vp = contentsToViewport( e->pos() );
+ KompareListViewLineItem* lineItem = dynamic_cast<KompareListViewLineItem*>( itemAt( vp ) );
+ if( !lineItem )
+ return;
+ KompareListViewDiffItem* diffItem = lineItem->diffItemParent();
+ if( diffItem->difference()->type() != Difference::Unchanged ) {
+ emit differenceClicked( diffItem->difference() );
+ }
+}
+
+void KompareListView::contentsMouseDoubleClickEvent( QMouseEvent* e )
+{
+ QPoint vp = contentsToViewport( e->pos() );
+ KompareListViewLineItem* lineItem = dynamic_cast<KompareListViewLineItem*>( itemAt( vp ) );
+ if ( !lineItem )
+ return;
+ KompareListViewDiffItem* diffItem = lineItem->diffItemParent();
+ if ( diffItem->difference()->type() != Difference::Unchanged ) {
+ // FIXME: make a new signal that does both
+ emit differenceClicked( diffItem->difference() );
+ emit applyDifference( !diffItem->difference()->applied() );
+ }
+}
+
+void KompareListView::slotApplyDifference( bool apply )
+{
+ m_itemDict[ (void*)m_selectedDifference ]->applyDifference( apply );
+}
+
+void KompareListView::slotApplyAllDifferences( bool apply )
+{
+ QPtrDictIterator<KompareListViewDiffItem> it ( m_itemDict );
+ for( ; it.current(); ++it )
+ it.current()->applyDifference( apply );
+ repaint();
+}
+
+void KompareListView::slotApplyDifference( const Difference* diff, bool apply )
+{
+ m_itemDict[ (void*)diff ]->applyDifference( apply );
+}
+
+void KompareListView::setSpaces( int spaces )
+{
+ m_spaces.truncate( 0 );
+ kdDebug( 8104 ) << "tabToNumberOfSpaces: " << spaces << endl;
+ for ( int i = 0; i < spaces; i++ )
+ m_spaces += " ";
+
+ triggerUpdate();
+}
+
+void KompareListView::wheelEvent( QWheelEvent* e )
+{
+ e->ignore(); // we want the parent to catch wheel events
+}
+
+void KompareListView::resizeEvent( QResizeEvent* e )
+{
+ KListView::resizeEvent(e);
+ emit resized();
+ kdDebug() << "resizeEvent " << endl;
+}
+
+KompareListViewItem::KompareListViewItem( KompareListView* parent )
+ : QListViewItem( parent ),
+ m_scrollId( 0 )
+{
+// kdDebug(8104) << "Created KompareListViewItem with scroll id " << m_scrollId << endl;
+}
+
+KompareListViewItem::KompareListViewItem( KompareListView* parent, KompareListViewItem* after )
+ : QListViewItem( parent, after ),
+ m_scrollId( after->scrollId() + after->maxHeight() )
+{
+// kdDebug(8104) << "Created KompareListViewItem with scroll id " << m_scrollId << endl;
+}
+
+KompareListViewItem::KompareListViewItem( KompareListViewItem* parent )
+ : QListViewItem( parent ),
+ m_scrollId( 0 )
+{
+}
+
+KompareListViewItem::KompareListViewItem( KompareListViewItem* parent, KompareListViewItem* /*after*/ )
+ : QListViewItem( parent ),
+ m_scrollId( 0 )
+{
+}
+
+KompareListView* KompareListViewItem::kompareListView() const
+{
+ return (KompareListView*)listView();
+}
+
+void KompareListViewItem::paintFocus( QPainter* /* p */, const QColorGroup& /* cg */, const QRect& /* r */ )
+{
+ // Don't paint anything
+}
+
+KompareListViewDiffItem::KompareListViewDiffItem( KompareListView* parent, Difference* difference )
+ : KompareListViewItem( parent ),
+ m_difference( difference ),
+ m_sourceItem( 0L ),
+ m_destItem( 0L )
+{
+ init();
+}
+
+KompareListViewDiffItem::KompareListViewDiffItem( KompareListView* parent, KompareListViewItem* after, Difference* difference )
+ : KompareListViewItem( parent, after ),
+ m_difference( difference ),
+ m_sourceItem( 0L ),
+ m_destItem( 0L )
+{
+ init();
+}
+
+void KompareListViewDiffItem::init()
+{
+ setExpandable( true );
+ setOpen( true );
+ m_destItem = new KompareListViewLineContainerItem( this, false );
+ m_sourceItem = new KompareListViewLineContainerItem( this, true );
+ setVisibility();
+}
+
+void KompareListViewDiffItem::setup()
+{
+ KompareListViewItem::setup();
+ setHeight( 0 );
+}
+
+void KompareListViewDiffItem::setVisibility()
+{
+ m_sourceItem->setVisible( kompareListView()->isSource() || m_difference->applied() );
+ m_destItem->setVisible( !m_sourceItem->isVisible() );
+}
+
+void KompareListViewDiffItem::applyDifference( bool apply )
+{
+ kdDebug(8104) << "KompareListViewDiffItem::applyDifference( " << apply << " )" << endl;
+ setVisibility();
+ setup();
+ repaint();
+}
+
+int KompareListViewDiffItem::maxHeight()
+{
+ int lines = QMAX( m_difference->sourceLineCount(), m_difference->destinationLineCount() );
+ if( lines == 0 )
+ return BLANK_LINE_HEIGHT;
+ else
+ return lines * listView()->fontMetrics().lineSpacing();
+}
+
+void KompareListViewDiffItem::setSelected( bool b )
+{
+ kdDebug(8104) << "KompareListViewDiffItem::setSelected( " << b << " )" << endl;
+ KompareListViewItem::setSelected( b );
+ QListViewItem* item = m_sourceItem->isVisible() ?
+ m_sourceItem->firstChild() :
+ m_destItem->firstChild();
+ while( item && item->isVisible() ) {
+ item->repaint();
+ item = item->nextSibling();
+ }
+}
+
+KompareListViewLineContainerItem::KompareListViewLineContainerItem( KompareListViewDiffItem* parent, bool isSource )
+ : KompareListViewItem( parent ),
+ m_isSource( isSource )
+{
+// kdDebug(8104) << "isSource ? " << (isSource ? " Yes!" : " No!") << endl;
+ setExpandable( true );
+ setOpen( true );
+
+ int lines = lineCount();
+ int line = lineNumber() + lines - 1;
+// kdDebug(8104) << "LineNumber : " << lineNumber() << endl;
+ if( lines == 0 ) {
+ new KompareListViewBlankLineItem( this );
+ return;
+ }
+
+ for( int i = lines - 1; i >= 0; i--, line-- ) {
+ new KompareListViewLineItem( this, line, lineAt( i ) );
+ }
+}
+
+void KompareListViewLineContainerItem::setup()
+{
+ KompareListViewItem::setup();
+ setHeight( 0 );
+}
+
+KompareListViewDiffItem* KompareListViewLineContainerItem::diffItemParent() const
+{
+ return (KompareListViewDiffItem*)parent();
+}
+
+int KompareListViewLineContainerItem::lineCount() const
+{
+ return m_isSource ? diffItemParent()->difference()->sourceLineCount() :
+ diffItemParent()->difference()->destinationLineCount();
+}
+
+int KompareListViewLineContainerItem::lineNumber() const
+{
+ return m_isSource ? diffItemParent()->difference()->sourceLineNumber() :
+ diffItemParent()->difference()->destinationLineNumber();
+}
+
+DifferenceString* KompareListViewLineContainerItem::lineAt( int i ) const
+{
+ return m_isSource ? diffItemParent()->difference()->sourceLineAt( i ) :
+ diffItemParent()->difference()->destinationLineAt( i );
+}
+
+KompareListViewLineItem::KompareListViewLineItem( KompareListViewLineContainerItem* parent, int line, DifferenceString* text )
+ : KompareListViewItem( parent )
+{
+ setText( COL_LINE_NO, QString::number( line ) );
+ setText( COL_MAIN, text->string() );
+ m_text = text;
+}
+
+void KompareListViewLineItem::setup()
+{
+ KompareListViewItem::setup();
+ setHeight( listView()->fontMetrics().lineSpacing() );
+}
+
+void KompareListViewLineItem::paintCell( QPainter * p, const QColorGroup & cg, int column, int width, int align )
+{
+ QColor bg = cg.base();
+ p->fillRect( 0, 0, width, height(), bg );
+ if ( diffItemParent()->difference()->type() == Difference::Unchanged )
+ {
+ if ( column == COL_LINE_NO )
+ {
+ bg = cg.background();
+ p->fillRect( 0, 0, width, height(), bg );
+ }
+ }
+ else
+ {
+ bg = kompareListView()->settings()->colorForDifferenceType(
+ diffItemParent()->difference()->type(),
+ diffItemParent()->isSelected(),
+ diffItemParent()->difference()->applied() );
+ if ( column != COL_MAIN )
+ p->fillRect( 0, 0, width, height(), bg );
+ }
+
+ p->setPen( cg.foreground() );
+
+ paintText( p, bg, column, width, align );
+
+ if ( diffItemParent()->isSelected() )
+ {
+ p->setPen( bg.dark(135) );
+ if ( this == parent()->firstChild() )
+ p->drawLine( 0, 0, width, 0 );
+ if ( nextSibling() == 0 )
+ p->drawLine( 0, height() - 1, width, height() - 1 );
+ }
+}
+
+void KompareListViewLineItem::paintText( QPainter* p, const QColor& bg, int column, int width, int align )
+{
+ if ( column == COL_MAIN )
+ {
+ QString textChunk;
+ int offset = listView()->itemMargin();
+ unsigned int prevValue = 0;
+ int chunkWidth;
+ QBrush changeBrush( bg, Dense3Pattern );
+ QBrush normalBrush( bg, SolidPattern );
+ QBrush brush;
+
+ if ( m_text->string().isEmpty() )
+ {
+ p->fillRect( 0, 0, width, height(), normalBrush );
+ return;
+ }
+
+ p->fillRect( 0, 0, offset, height(), normalBrush );
+
+ if ( !m_text->markerList().isEmpty() )
+ {
+ MarkerListConstIterator markerIt = m_text->markerList().begin();
+ MarkerListConstIterator mEnd = m_text->markerList().end();
+ Marker* m = *markerIt;
+
+ for ( ; markerIt != mEnd; ++markerIt )
+ {
+ m = *markerIt;
+ textChunk = m_text->string().mid( prevValue, m->offset() - prevValue );
+// kdDebug(8104) << "TextChunk = \"" << textChunk << "\"" << endl;
+// kdDebug(8104) << "c->offset() = " << c->offset() << endl;
+// kdDebug(8104) << "prevValue = " << prevValue << endl;
+ textChunk.replace( QChar('\t'), kompareListView()->spaces() );
+ prevValue = m->offset();
+ if ( m->type() == Marker::End )
+ {
+ QFont font( p->font() );
+ font.setBold( true );
+ p->setFont( font );
+// p->setPen( Qt::blue );
+ brush = changeBrush;
+ }
+ else
+ {
+ QFont font( p->font() );
+ font.setBold( false );
+ p->setFont( font );
+// p->setPen( Qt::black );
+ brush = normalBrush;
+ }
+ chunkWidth = p->fontMetrics().width( textChunk );
+ p->fillRect( offset, 0, chunkWidth, height(), brush );
+ p->drawText( offset, 0,
+ chunkWidth, height(),
+ align, textChunk );
+ offset += chunkWidth;
+ }
+ }
+ if ( prevValue < m_text->string().length() )
+ {
+ // Still have to draw some string without changes
+ textChunk = m_text->string().mid( prevValue, kMax( ( unsigned int )1, m_text->string().length() - prevValue ) );
+ textChunk.replace( QChar('\t'), kompareListView()->spaces() );
+// kdDebug(8104) << "TextChunk = \"" << textChunk << "\"" << endl;
+ QFont font( p->font() );
+ font.setBold( false );
+ p->setFont( font );
+ chunkWidth = p->fontMetrics().width( textChunk );
+ p->fillRect( offset, 0, chunkWidth, height(), normalBrush );
+ p->drawText( offset, 0,
+ chunkWidth, height(),
+ align, textChunk );
+ offset += chunkWidth;
+ }
+ p->fillRect( offset, 0, width - offset, height(), normalBrush );
+ }
+ else
+ {
+ p->fillRect( 0, 0, width, height(), bg );
+ p->drawText( listView()->itemMargin(), 0,
+ width - listView()->itemMargin(), height(),
+ align, text( column ) );
+ }
+}
+
+KompareListViewDiffItem* KompareListViewLineItem::diffItemParent() const
+{
+ KompareListViewLineContainerItem* p = (KompareListViewLineContainerItem*)parent();
+ return p->diffItemParent();
+}
+
+KompareListViewBlankLineItem::KompareListViewBlankLineItem( KompareListViewLineContainerItem* parent )
+ : KompareListViewLineItem( parent, 0, new DifferenceString() )
+{
+}
+
+void KompareListViewBlankLineItem::setup()
+{
+ KompareListViewLineItem::setup();
+ setHeight( BLANK_LINE_HEIGHT );
+}
+
+void KompareListViewBlankLineItem::paintText( QPainter* p, const QColor& bg, int column, int width, int )
+{
+ if ( column == COL_MAIN )
+ {
+ QBrush normalBrush( bg, SolidPattern );
+ p->fillRect( 0, 0, width, height(), normalBrush );
+ }
+}
+
+KompareListViewHunkItem::KompareListViewHunkItem( KompareListView* parent, DiffHunk* hunk, bool zeroHeight )
+ : KompareListViewItem( parent ),
+ m_zeroHeight( zeroHeight ),
+ m_hunk( hunk )
+{
+ setSelectable( false );
+}
+
+KompareListViewHunkItem::KompareListViewHunkItem( KompareListView* parent, KompareListViewItem* after, DiffHunk* hunk, bool zeroHeight )
+ : KompareListViewItem( parent, after ),
+ m_zeroHeight( zeroHeight ),
+ m_hunk( hunk )
+{
+ setSelectable( false );
+}
+
+int KompareListViewHunkItem::maxHeight()
+{
+ if( m_zeroHeight ) {
+ return 0;
+ } else if( m_hunk->function().isEmpty() ) {
+ return HUNK_LINE_HEIGHT;
+ } else {
+ return listView()->fontMetrics().lineSpacing();
+ }
+}
+
+void KompareListViewHunkItem::setup()
+{
+ KompareListViewItem::setup();
+
+ setHeight( maxHeight() );
+}
+
+void KompareListViewHunkItem::paintCell( QPainter * p, const QColorGroup & cg, int column, int width, int align )
+{
+ p->fillRect( 0, 0, width, height(), cg.mid() );
+ if( column == COL_MAIN ) {
+ p->drawText( listView()->itemMargin(), 0, width - listView()->itemMargin(), height(),
+ align, m_hunk->function() );
+ }
+}
+
+#include "komparelistview.moc"
diff --git a/kompare/komparepart/komparelistview.h b/kompare/komparepart/komparelistview.h
new file mode 100644
index 00000000..26a6dacb
--- /dev/null
+++ b/kompare/komparepart/komparelistview.h
@@ -0,0 +1,225 @@
+/***************************************************************************
+ komparelistview.h - description
+ -------------------
+ begin : Sun Mar 4 2001
+ copyright : (C) 2001-2004 Otto Bruggeman
+ (C) 2001-2003 John Firebaugh
+ (C) 2004 Jeff Snyder
+ email : otto.bruggeman@home.nl
+ jfirebaugh@kde.org
+ jeff@caffeinated.me.uk
+****************************************************************************/
+
+/***************************************************************************
+**
+** This program is free software; you can redistribute it and/or modify
+** it under the terms of the 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 KOMPARELISTVIEW_H
+#define KOMPARELISTVIEW_H
+
+#include <qptrlist.h>
+#include <qptrdict.h>
+#include <qlabel.h>
+#include <qlayout.h>
+
+#include <klistview.h>
+
+namespace Diff2 {
+class DiffModel;
+class DiffHunk;
+class Difference;
+class DifferenceString;
+class KompareModelList;
+}
+class ViewSettings;
+class KompareSplitter;
+class KompareListView;
+class KompareListViewItem;
+class KompareListViewDiffItem;
+class KompareListViewLineContainerItem;
+
+class KompareListView : public KListView
+{
+ Q_OBJECT
+
+public:
+ KompareListView( bool isSource, ViewSettings* settings, QWidget* parent, const char* name = 0 );
+ virtual ~KompareListView();
+
+ KompareListViewItem* itemAtIndex( int i );
+ int firstVisibleDifference();
+ int lastVisibleDifference();
+ QRect itemRect( int i );
+ int minScrollId();
+ int maxScrollId();
+ int contentsWidth();
+
+ bool isSource() const { return m_isSource; };
+ ViewSettings* settings() const { return m_settings; };
+
+ void setSelectedDifference( const Diff2::Difference* diff, bool scroll );
+
+ const QString& spaces() const { return m_spaces; };
+ void setSpaces( int spaces );
+
+public slots:
+ void slotSetSelection( const Diff2::DiffModel* model, const Diff2::Difference* diff );
+ void slotSetSelection( const Diff2::Difference* diff );
+ void setXOffset( int x );
+ void scrollToId( int id );
+ int scrollId();
+ void slotApplyDifference( bool apply );
+ void slotApplyAllDifferences( bool apply );
+ void slotApplyDifference( const Diff2::Difference* diff, bool apply );
+
+signals:
+ void differenceClicked( const Diff2::Difference* diff );
+ void applyDifference( bool apply );
+ void resized();
+
+protected:
+ void wheelEvent( QWheelEvent* e );
+ void resizeEvent( QResizeEvent* e );
+ void contentsMousePressEvent ( QMouseEvent * e );
+ void contentsMouseDoubleClickEvent ( QMouseEvent* );
+ void contentsMouseReleaseEvent ( QMouseEvent * ) {};
+ void contentsMouseMoveEvent ( QMouseEvent * ) {};
+
+private:
+ QValueList<KompareListViewDiffItem*> m_items;
+ QPtrDict<KompareListViewDiffItem> m_itemDict;
+ bool m_isSource;
+ ViewSettings* m_settings;
+ int m_scrollId;
+ int m_maxMainWidth;
+ const Diff2::DiffModel* m_selectedModel;
+ const Diff2::Difference* m_selectedDifference;
+ QString m_spaces;
+};
+
+class KompareListViewFrame : public QFrame
+{
+ Q_OBJECT
+
+public:
+ KompareListViewFrame( bool isSource, ViewSettings* settings, KompareSplitter* parent, const char* name = 0 );
+ virtual ~KompareListViewFrame() {};
+ KompareListView* view() { return &m_view; };
+
+public slots:
+ void slotSetModel( const Diff2::DiffModel* model );
+
+private:
+ KompareListView m_view;
+ QLabel m_label;
+ QVBoxLayout m_layout;
+};
+
+class KompareListViewItem : public QListViewItem
+{
+public:
+ KompareListViewItem( KompareListView* parent );
+ KompareListViewItem( KompareListView* parent, KompareListViewItem* after );
+ KompareListViewItem( KompareListViewItem* parent );
+ KompareListViewItem( KompareListViewItem* parent, KompareListViewItem* after );
+
+ void paintFocus( QPainter* p, const QColorGroup& cg, const QRect& r );
+ int scrollId() { return m_scrollId; };
+
+ virtual int maxHeight() = 0;
+
+ KompareListView* kompareListView() const;
+
+private:
+ int m_scrollId;
+};
+
+class KompareListViewDiffItem : public KompareListViewItem
+{
+public:
+ KompareListViewDiffItem( KompareListView* parent, Diff2::Difference* difference );
+ KompareListViewDiffItem( KompareListView* parent, KompareListViewItem* after, Diff2::Difference* difference );
+
+ void setup();
+ void setSelected( bool b );
+ void applyDifference( bool apply );
+
+ Diff2::Difference* difference() { return m_difference; };
+
+ int maxHeight();
+
+private:
+ void init();
+ void setVisibility();
+
+ Diff2::Difference* m_difference;
+ KompareListViewLineContainerItem* m_sourceItem;
+ KompareListViewLineContainerItem* m_destItem;
+};
+
+class KompareListViewLineContainerItem : public KompareListViewItem
+{
+public:
+ KompareListViewLineContainerItem( KompareListViewDiffItem* parent, bool isSource );
+
+ void setup();
+ int maxHeight() { return 0; }
+ KompareListViewDiffItem* diffItemParent() const;
+
+private:
+ int lineCount() const;
+ int lineNumber() const;
+ Diff2::DifferenceString* lineAt( int i ) const;
+
+ bool m_isSource;
+};
+
+class KompareListViewLineItem : public KompareListViewItem
+{
+public:
+ KompareListViewLineItem( KompareListViewLineContainerItem* parent, int line, Diff2::DifferenceString* text );
+
+ virtual void setup();
+ int maxHeight() { return 0; }
+
+ virtual void paintCell( QPainter* p, const QColorGroup& cg, int column, int width, int align );
+ virtual void paintText( QPainter* p, const QColor& bg, int column, int width, int align );
+
+ KompareListViewDiffItem* diffItemParent() const;
+
+private:
+ Diff2::DifferenceString* m_text;
+};
+
+class KompareListViewBlankLineItem : public KompareListViewLineItem
+{
+public:
+ KompareListViewBlankLineItem( KompareListViewLineContainerItem* parent );
+
+ void setup();
+
+ void paintText( QPainter* p, const QColor& bg, int column, int width, int align );
+};
+
+class KompareListViewHunkItem : public KompareListViewItem
+{
+public:
+ KompareListViewHunkItem( KompareListView* parent, Diff2::DiffHunk* hunk, bool zeroHeight = false );
+ KompareListViewHunkItem( KompareListView* parent, KompareListViewItem* after, Diff2::DiffHunk* hunk, bool zeroHeight= false );
+
+ void setup();
+ void paintCell( QPainter* p, const QColorGroup& cg, int column, int width, int align );
+
+ int maxHeight();
+
+private:
+ bool m_zeroHeight;
+ Diff2::DiffHunk* m_hunk;
+};
+
+#endif
diff --git a/kompare/komparepart/komparepart.desktop b/kompare/komparepart/komparepart.desktop
new file mode 100644
index 00000000..3d075d62
--- /dev/null
+++ b/kompare/komparepart/komparepart.desktop
@@ -0,0 +1,24 @@
+[Desktop Entry]
+GenericComment=A part to graphically show the difference between 2 files
+Name=KomparePart
+Name[af]=K-vergelyk-deel
+Name[de]=Einbettungsfähige Komponente von Kompare
+Name[eo]=Komparo-parto
+Name[he]=רכיב Kompare
+Name[hi]=कामà¥à¤ªà¥‡à¤¯à¤°-पारà¥à¤Ÿ
+Name[lv]=SalÄ«dzinÄtDaļu
+Name[pl]=Moduł Kompare
+Name[pt_BR]=Parte do Kompare
+Name[ro]=Componentă Kompare
+Name[ru]=Компонент утилиты ÑÑ€Ð°Ð²Ð½ÐµÐ½Ð¸Ñ Ñ„Ð°Ð¹Ð»Ð¾Ð²
+Name[sv]=Kompare-del
+Name[ta]=கோமà¯à®ªà¯†à®°à¯ உறà¯à®ªà¯à®ªà¯
+Name[tg]=ҚиÑмати утилитҳои баробаркунии файлҳо
+Name[th]=ส่วนเปรียบเทียบ
+Name[zu]=Ingxenye yeKompare
+MimeType=text/x-diff
+ServiceTypes=Kompare/ViewPart,KParts/ReadWritePart,KParts/ReadOnlyPart
+X-KDE-Library=libkomparepart
+Type=Service
+Icon=kompare
+InitialPreference=10
diff --git a/kompare/komparepart/komparepartui.rc b/kompare/komparepart/komparepartui.rc
new file mode 100644
index 00000000..c7140325
--- /dev/null
+++ b/kompare/komparepart/komparepartui.rc
@@ -0,0 +1,44 @@
+<!DOCTYPE kpartgui SYSTEM "kpartgui.dtd">
+<kpartgui name="kompare_part" version="5">
+<MenuBar>
+ <Menu name="file"><text>&amp;File</text>
+ <Action name="file_save"/>
+ <Action name="file_save_all"/>
+ <Action name="file_save_as"/>
+ <Action name="file_save_diff"/>
+ <Separator/>
+ <Action name="file_swap"/>
+ <Action name="file_diffstats"/>
+ </Menu>
+ <Menu name="difference"><text>&amp;Difference</text>
+ <Action name="difference_unapplyall"/>
+ <Action name="difference_unapply"/>
+ <Action name="difference_apply"/>
+ <Action name="difference_applyall"/>
+ <Separator/>
+ <Action name="difference_previousfile"/>
+ <Action name="difference_nextfile"/>
+ <Separator/>
+ <Action name="difference_previous"/>
+ <Action name="difference_next"/>
+ </Menu>
+ <Menu name="settings"><text>&amp;Settings</text>
+ <Action name="options_configure"/>
+ </Menu>
+</MenuBar>
+<ToolBar name="mainToolBar">
+ <Action name="file_save"/>
+ <Action name="file_save_all"/>
+ <Separator/>
+ <Action name="difference_previousfile"/>
+ <Action name="difference_nextfile"/>
+ <Separator/>
+ <Action name="difference_previous"/>
+ <Action name="difference_next"/>
+ <Separator/>
+ <Action name="difference_unapplyall"/>
+ <Action name="difference_unapply"/>
+ <Action name="difference_apply"/>
+ <Action name="difference_applyall"/>
+</ToolBar>
+</kpartgui>
diff --git a/kompare/komparepart/kompareprefdlg.cpp b/kompare/komparepart/kompareprefdlg.cpp
new file mode 100644
index 00000000..2d731af3
--- /dev/null
+++ b/kompare/komparepart/kompareprefdlg.cpp
@@ -0,0 +1,106 @@
+/***************************************************************************
+ kompareprefdlg.cpp - description
+ -------------------
+ begin : Sun Mar 4 2001
+ copyright : (C) 2001-2003 by Otto Bruggeman
+ and John Firebaugh
+ email : otto.bruggeman@home.nl
+ jfirebaugh@kde.org
+****************************************************************************/
+
+/***************************************************************************
+**
+** This program is free software; you can redistribute it and/or modify
+** it under the terms of the 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 <qvbox.h>
+
+#include <kdebug.h>
+#include <kiconloader.h>
+#include <klocale.h>
+
+#include "diffpage.h"
+#include "viewpage.h"
+
+#include "kompareprefdlg.h"
+
+// implementation
+
+KomparePrefDlg::KomparePrefDlg( ViewSettings* viewSets, DiffSettings* diffSets ) : KDialogBase( IconList, i18n( "Preferences" ), Help|Default|Ok|Apply|Cancel, Ok, 0, 0, true, true )
+{
+ // ok i need some stuff in that pref dlg...
+ setIconListAllVisible(true);
+
+ QVBox* frame;
+ frame = addVBoxPage( i18n( "View" ), i18n( "View Settings" ), UserIcon( "diff_view" ) );
+ m_viewPage = new ViewPage( frame );
+ m_viewPage->setSettings( viewSets );
+
+ frame = addVBoxPage( i18n( "Diff" ), i18n( "Diff Settings" ), UserIcon( "diff_specific" ) );
+ m_diffPage = new DiffPage( frame );
+ m_diffPage->setSettings( diffSets );
+
+// frame = addVBoxPage( i18n( "" ), i18n( "" ), UserIcon( "" ) );
+
+ adjustSize();
+}
+
+KomparePrefDlg::~KomparePrefDlg()
+{
+
+}
+
+/** No descriptions */
+void KomparePrefDlg::slotDefault()
+{
+ kdDebug(8103) << "SlotDefault called -> Settings should be restored to defaults..." << endl;
+ // restore all defaults in the options...
+ m_viewPage->setDefaults();
+ m_diffPage->setDefaults();
+}
+
+/** No descriptions */
+void KomparePrefDlg::slotHelp()
+{
+ // show some help...
+ // figure out the current active page
+ // and give help for that page
+}
+
+/** No descriptions */
+void KomparePrefDlg::slotApply()
+{
+ kdDebug(8103) << "SlotApply called -> Settings should be applied..." << endl;
+ // well apply the settings that are currently selected
+ m_viewPage->apply();
+ m_diffPage->apply();
+
+ emit applyClicked();
+}
+
+/** No descriptions */
+void KomparePrefDlg::slotOk()
+{
+ kdDebug(8103) << "SlotOk called -> Settings should be applied..." << endl;
+ // Apply the settings that are currently selected
+ m_viewPage->apply();
+ m_diffPage->apply();
+
+ KDialogBase::slotOk();
+}
+
+/** No descriptions */
+void KomparePrefDlg::slotCancel()
+{
+ // discard the current settings and use the present ones
+ m_viewPage->restore();
+ m_diffPage->restore();
+
+ KDialogBase::slotCancel();
+}
+
+#include "kompareprefdlg.moc"
diff --git a/kompare/komparepart/kompareprefdlg.h b/kompare/komparepart/kompareprefdlg.h
new file mode 100644
index 00000000..e81da90c
--- /dev/null
+++ b/kompare/komparepart/kompareprefdlg.h
@@ -0,0 +1,54 @@
+/***************************************************************************
+ kompareprefdlg.h - description
+ -------------------
+ begin : Sun Mar 4 2001
+ copyright : (C) 2001-2003 by Otto Bruggeman
+ and John Firebaugh
+ email : otto.bruggeman@home.nl
+ jfirebaugh@kde.org
+****************************************************************************/
+
+/***************************************************************************
+**
+** This program is free software; you can redistribute it and/or modify
+** it under the terms of the 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 KOMPAREPREFDLG_H
+#define KOMPAREPREFDLG_H
+
+#include <kdialogbase.h>
+
+class DiffPage;
+class DiffSettings;
+class ViewPage;
+class ViewSettings;
+
+class KomparePrefDlg : public KDialogBase
+{
+Q_OBJECT
+public:
+ KomparePrefDlg( ViewSettings*, DiffSettings* );
+ ~KomparePrefDlg();
+
+protected slots:
+ /** No descriptions */
+ virtual void slotOk();
+ /** No descriptions */
+ virtual void slotApply();
+ /** No descriptions */
+ virtual void slotHelp();
+ /** No descriptions */
+ virtual void slotDefault();
+ /** No descriptions */
+ virtual void slotCancel();
+
+private:
+ ViewPage* m_viewPage;
+ DiffPage* m_diffPage;
+};
+
+#endif
diff --git a/kompare/komparepart/komparesaveoptionsbase.ui b/kompare/komparepart/komparesaveoptionsbase.ui
new file mode 100644
index 00000000..4c49b018
--- /dev/null
+++ b/kompare/komparepart/komparesaveoptionsbase.ui
@@ -0,0 +1,336 @@
+<!DOCTYPE UI><UI version="3.0" stdsetdef="1">
+<class>KompareSaveOptionsBase</class>
+<widget class="QWidget">
+ <property name="name">
+ <cstring>KompareSaveOptionsBase</cstring>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>558</width>
+ <height>399</height>
+ </rect>
+ </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="QGroupBox" row="1" column="0" rowspan="1" colspan="2">
+ <property name="name">
+ <cstring>GroupBox2</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>1</hsizetype>
+ <vsizetype>1</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="frameShape">
+ <enum>Panel</enum>
+ </property>
+ <property name="title">
+ <string>Run Diff In</string>
+ </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="KURLRequester">
+ <property name="name">
+ <cstring>m_directoryRequester</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>7</hsizetype>
+ <vsizetype>5</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ </widget>
+ </hbox>
+ </widget>
+ <widget class="QGroupBox" row="2" column="0" rowspan="1" colspan="2">
+ <property name="name">
+ <cstring>m_CommandLineGB</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>3</hsizetype>
+ <vsizetype>3</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="frameShape">
+ <enum>Panel</enum>
+ </property>
+ <property name="title">
+ <string>Command Line</string>
+ </property>
+ <property name="alignment">
+ <set>AlignVCenter|AlignLeft</set>
+ </property>
+ <property name="hAlign" stdset="0">
+ </property>
+ <property name="vAlign" stdset="0">
+ </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="QLabel">
+ <property name="name">
+ <cstring>m_CommandLineLabel</cstring>
+ </property>
+ <property name="text">
+ <string>cd dir &amp;&amp; diff -udHprNa -- source destination</string>
+ </property>
+ </widget>
+ </hbox>
+ </widget>
+ <widget class="QButtonGroup" row="0" column="1">
+ <property name="name">
+ <cstring>m_OptionsGB</cstring>
+ </property>
+ <property name="title">
+ <string>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="QCheckBox">
+ <property name="name">
+ <cstring>m_SmallerChangesCB</cstring>
+ </property>
+ <property name="text">
+ <string>Look for smaller changes</string>
+ </property>
+ <property name="checked">
+ <bool>true</bool>
+ </property>
+ </widget>
+ <widget class="QCheckBox">
+ <property name="name">
+ <cstring>m_LargeFilesCB</cstring>
+ </property>
+ <property name="text">
+ <string>Optimize for large files</string>
+ </property>
+ <property name="checked">
+ <bool>true</bool>
+ </property>
+ </widget>
+ <widget class="QCheckBox">
+ <property name="name">
+ <cstring>m_IgnoreCaseCB</cstring>
+ </property>
+ <property name="text">
+ <string>Ignore changes in case</string>
+ </property>
+ </widget>
+ <widget class="QCheckBox">
+ <property name="name">
+ <cstring>m_ExpandTabsCB</cstring>
+ </property>
+ <property name="text">
+ <string>Expand tabs to spaces</string>
+ </property>
+ </widget>
+ <widget class="QCheckBox">
+ <property name="name">
+ <cstring>m_IgnoreEmptyLinesCB</cstring>
+ </property>
+ <property name="text">
+ <string>Ignore added or removed empty lines</string>
+ </property>
+ </widget>
+ <widget class="QCheckBox">
+ <property name="name">
+ <cstring>m_IgnoreWhiteSpaceCB</cstring>
+ </property>
+ <property name="text">
+ <string>Ignore changes in whitespace</string>
+ </property>
+ </widget>
+ <widget class="QCheckBox">
+ <property name="name">
+ <cstring>m_FunctionNamesCB</cstring>
+ </property>
+ <property name="text">
+ <string>Show function names</string>
+ </property>
+ <property name="checked">
+ <bool>true</bool>
+ </property>
+ </widget>
+ <widget class="QCheckBox">
+ <property name="name">
+ <cstring>m_RecursiveCB</cstring>
+ </property>
+ <property name="text">
+ <string>Compare folders recursively</string>
+ </property>
+ <property name="checked">
+ <bool>true</bool>
+ </property>
+ </widget>
+ <widget class="QCheckBox">
+ <property name="name">
+ <cstring>m_NewFilesCB</cstring>
+ </property>
+ <property name="text">
+ <string>Treat new files as empty</string>
+ </property>
+ <property name="checked">
+ <bool>true</bool>
+ </property>
+ <property name="tristate">
+ <bool>false</bool>
+ </property>
+ </widget>
+ </vbox>
+ </widget>
+ <widget class="QButtonGroup" row="0" column="0">
+ <property name="name">
+ <cstring>m_FormatBG</cstring>
+ </property>
+ <property name="title">
+ <string>Format</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>m_ContextRB</cstring>
+ </property>
+ <property name="text">
+ <string>Context</string>
+ </property>
+ </widget>
+ <widget class="QRadioButton">
+ <property name="name">
+ <cstring>m_EdRB</cstring>
+ </property>
+ <property name="text">
+ <string>Ed</string>
+ </property>
+ </widget>
+ <widget class="QRadioButton">
+ <property name="name">
+ <cstring>m_NormalRB</cstring>
+ </property>
+ <property name="text">
+ <string>Normal</string>
+ </property>
+ </widget>
+ <widget class="QRadioButton">
+ <property name="name">
+ <cstring>m_RCSRB</cstring>
+ </property>
+ <property name="text">
+ <string>RCS</string>
+ </property>
+ </widget>
+ <widget class="QRadioButton">
+ <property name="name">
+ <cstring>m_UnifiedRB</cstring>
+ </property>
+ <property name="text">
+ <string>Unified</string>
+ </property>
+ <property name="checked">
+ <bool>true</bool>
+ </property>
+ </widget>
+ <widget class="QRadioButton">
+ <property name="name">
+ <cstring>m_SideBySideRB</cstring>
+ </property>
+ <property name="text">
+ <string>Side-by-side</string>
+ </property>
+ <property name="checked">
+ <bool>false</bool>
+ </property>
+ </widget>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>m_ContextLinesLayout</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>m_ContextLinesLabel</cstring>
+ </property>
+ <property name="text">
+ <string>Number of context lines:</string>
+ </property>
+ </widget>
+ <widget class="QSpinBox">
+ <property name="name">
+ <cstring>m_ContextLinesSB</cstring>
+ </property>
+ <property name="enabled">
+ <bool>true</bool>
+ </property>
+ <property name="maxValue">
+ <number>65535</number>
+ </property>
+ <property name="value">
+ <number>3</number>
+ </property>
+ </widget>
+ </hbox>
+ </widget>
+ </vbox>
+ </widget>
+ </grid>
+</widget>
+<layoutdefaults spacing="6" margin="11"/>
+</UI>
diff --git a/kompare/komparepart/komparesaveoptionswidget.cpp b/kompare/komparepart/komparesaveoptionswidget.cpp
new file mode 100644
index 00000000..866ecc0d
--- /dev/null
+++ b/kompare/komparepart/komparesaveoptionswidget.cpp
@@ -0,0 +1,215 @@
+/***************************************************************************
+ komparesaveoptionswidget.cpp - description
+ -------------------
+ begin : Sun Mar 4 2001
+ copyright : (C) 2001-2003 by Otto Bruggeman
+ and John Firebaugh
+ email : otto.bruggeman@home.nl
+ jfirebaugh@kde.org
+****************************************************************************/
+
+/***************************************************************************
+**
+** This program is free software; you can redistribute it and/or modify
+** it under the terms of the 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 <qbuttongroup.h>
+#include <qcheckbox.h>
+#include <qlabel.h>
+#include <qradiobutton.h>
+#include <qspinbox.h>
+
+#include <kdebug.h>
+#include <kfiledialog.h>
+#include <kurlrequester.h>
+
+#include "diffsettings.h"
+#include "komparesaveoptionswidget.h"
+
+KompareSaveOptionsWidget::KompareSaveOptionsWidget( QString source, QString destination,
+ DiffSettings * settings, QWidget * parent )
+ : KompareSaveOptionsBase( parent, "save options" )
+ , m_source( source )
+ , m_destination( destination )
+{
+ m_settings = settings;
+
+ m_directoryRequester->setMode( static_cast<KFile::Mode>(
+ KFile::ExistingOnly | KFile::Directory | KFile::LocalOnly ) );
+
+ KURL sourceURL;
+ KURL destinationURL;
+ sourceURL.setPath( source );
+ destinationURL.setPath( destination );
+
+ // Find a common root.
+ KURL root( sourceURL );
+ while( root.isValid() && !root.isParentOf( destinationURL ) ) {
+ root = root.upURL();
+ }
+
+ // If we found a common root, change to that directory and
+ // strip the common part from source and destination.
+ if( root.isValid() ) {
+ m_directoryRequester->setURL( root.url() );
+ }
+
+ connect( m_SmallerChangesCB, SIGNAL(toggled(bool)), SLOT(updateCommandLine()) );
+ connect( m_LargeFilesCB, SIGNAL(toggled(bool)), SLOT(updateCommandLine()) );
+ connect( m_IgnoreCaseCB, SIGNAL(toggled(bool)), SLOT(updateCommandLine()) );
+ connect( m_ExpandTabsCB, SIGNAL(toggled(bool)), SLOT(updateCommandLine()) );
+ connect( m_IgnoreEmptyLinesCB, SIGNAL(toggled(bool)), SLOT(updateCommandLine()) );
+ connect( m_IgnoreWhiteSpaceCB, SIGNAL(toggled(bool)), SLOT(updateCommandLine()) );
+ connect( m_FunctionNamesCB, SIGNAL(toggled(bool)), SLOT(updateCommandLine()) );
+ connect( m_RecursiveCB, SIGNAL(toggled(bool)), SLOT(updateCommandLine()) );
+ connect( m_NewFilesCB, SIGNAL(toggled(bool)), SLOT(updateCommandLine()) );
+ connect( m_ContextRB, SIGNAL(toggled(bool)), SLOT(updateCommandLine()) );
+ connect( m_EdRB, SIGNAL(toggled(bool)), SLOT(updateCommandLine()) );
+ connect( m_NormalRB, SIGNAL(toggled(bool)), SLOT(updateCommandLine()) );
+ connect( m_RCSRB, SIGNAL(toggled(bool)), SLOT(updateCommandLine()) );
+ connect( m_UnifiedRB, SIGNAL(toggled(bool)), SLOT(updateCommandLine()) );
+ connect( m_SideBySideRB, SIGNAL(toggled(bool)), SLOT(updateCommandLine()) );
+ connect( m_ContextLinesSB, SIGNAL(valueChanged(int)), SLOT(updateCommandLine()) );
+ connect( m_directoryRequester, SIGNAL(textChanged(const QString&)), SLOT(updateCommandLine()) );
+
+ loadOptions();
+}
+
+KompareSaveOptionsWidget::~KompareSaveOptionsWidget()
+{
+
+}
+
+QString KompareSaveOptionsWidget::directory() const
+{
+ return KURL( m_directoryRequester->url() ).path();
+}
+
+void KompareSaveOptionsWidget::updateCommandLine()
+{
+ QString cmdLine = "diff";
+
+ QString options = "";
+
+ switch( static_cast<Kompare::Format>( m_FormatBG->id( m_FormatBG->selected() ) ) ) {
+ case Kompare::Unified :
+ cmdLine += " -U " + QString::number( m_ContextLinesSB->value() );
+ break;
+ case Kompare::Context :
+ cmdLine += " -C " + QString::number( m_ContextLinesSB->value() );
+ break;
+ case Kompare::RCS :
+ options += "n";
+ break;
+ case Kompare::Ed :
+ options += "e";
+ break;
+ case Kompare::SideBySide:
+ options += "y";
+ break;
+ case Kompare::Normal :
+ case Kompare::UnknownFormat :
+ default:
+ break;
+ }
+
+ if ( m_SmallerChangesCB->isChecked() ) {
+ options += "d";
+ }
+
+ if ( m_LargeFilesCB->isChecked() ) {
+ options += "H";
+ }
+
+ if ( m_IgnoreCaseCB->isChecked() ){
+ options += "i";
+ }
+
+ if ( m_ExpandTabsCB->isChecked() ) {
+ options += "t";
+ }
+
+ if ( m_IgnoreEmptyLinesCB->isChecked() ) {
+ options += "B";
+ }
+
+ if ( m_IgnoreWhiteSpaceCB->isChecked() ) {
+ options += "b";
+ }
+
+ if ( m_FunctionNamesCB->isChecked() ) {
+ options += "p";
+ }
+
+// if ( ) {
+// cmdLine += " -w";
+// }
+
+ if ( m_RecursiveCB->isChecked() ) {
+ options += "r";
+ }
+
+ if( m_NewFilesCB->isChecked() ) {
+ options += "N";
+ }
+
+// if( m_AllTextCB->isChecked() ) {
+// options += "a";
+// }
+
+ if( options.length() > 0 ) {
+ cmdLine += " -" + options;
+ }
+
+ cmdLine += " -- ";
+ cmdLine += constructRelativePath( m_directoryRequester->url(), m_source );
+ cmdLine += " ";
+ cmdLine += constructRelativePath( m_directoryRequester->url(), m_destination );
+
+ m_CommandLineLabel->setText( cmdLine );
+}
+
+void KompareSaveOptionsWidget::loadOptions()
+{
+ m_SmallerChangesCB->setChecked ( m_settings->m_createSmallerDiff );
+ m_LargeFilesCB->setChecked ( m_settings->m_largeFiles );
+ m_IgnoreCaseCB->setChecked ( m_settings->m_ignoreChangesInCase );
+ m_ExpandTabsCB->setChecked ( m_settings->m_convertTabsToSpaces );
+ m_IgnoreEmptyLinesCB->setChecked( m_settings->m_ignoreEmptyLines );
+ m_IgnoreWhiteSpaceCB->setChecked( m_settings->m_ignoreWhiteSpace );
+ m_FunctionNamesCB->setChecked ( m_settings->m_showCFunctionChange );
+ m_RecursiveCB->setChecked ( m_settings->m_recursive );
+ m_NewFilesCB->setChecked ( m_settings->m_newFiles );
+// m_AllTextCB->setChecked ( m_settings->m_allText );
+
+ m_ContextLinesSB->setValue ( m_settings->m_linesOfContext );
+
+ m_FormatBG->setButton ( m_settings->m_format );
+
+ updateCommandLine();
+}
+
+void KompareSaveOptionsWidget::saveOptions()
+{
+ m_settings->m_createSmallerDiff = m_SmallerChangesCB->isChecked();
+ m_settings->m_largeFiles = m_LargeFilesCB->isChecked();
+ m_settings->m_ignoreChangesInCase = m_IgnoreCaseCB->isChecked();
+ m_settings->m_convertTabsToSpaces = m_ExpandTabsCB->isChecked();
+ m_settings->m_ignoreEmptyLines = m_IgnoreEmptyLinesCB->isChecked();
+ m_settings->m_ignoreWhiteSpace = m_IgnoreWhiteSpaceCB->isChecked();
+ m_settings->m_showCFunctionChange = m_FunctionNamesCB->isChecked();
+ m_settings->m_recursive = m_RecursiveCB->isChecked();
+ m_settings->m_newFiles = m_NewFilesCB->isChecked();
+// m_settings->m_allText = m_AllTextCB->isChecked();
+
+ m_settings->m_linesOfContext = m_ContextLinesSB->value();
+
+ m_settings->m_format = static_cast<Kompare::Format>( m_FormatBG->id( m_FormatBG->selected() ) );
+
+}
+
+#include "komparesaveoptionswidget.moc"
diff --git a/kompare/komparepart/komparesaveoptionswidget.h b/kompare/komparepart/komparesaveoptionswidget.h
new file mode 100644
index 00000000..6361ca77
--- /dev/null
+++ b/kompare/komparepart/komparesaveoptionswidget.h
@@ -0,0 +1,51 @@
+/***************************************************************************
+ komparesaveoptionswidget.h - description
+ -------------------
+ begin : Sun Mar 4 2001
+ copyright : (C) 2001-2003 by Otto Bruggeman
+ and John Firebaugh
+ email : otto.bruggeman@home.nl
+ jfirebaugh@kde.org
+****************************************************************************/
+
+/***************************************************************************
+**
+** This program is free software; you can redistribute it and/or modify
+** it under the terms of the 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 KOMPARESAVEOPTIONSWIDGET_H
+#define KOMPARESAVEOPTIONSWIDGET_H
+
+#include <kurl.h>
+
+#include "komparesaveoptionsbase.h"
+#include "kompare.h"
+
+class DiffSettings;
+
+class KompareSaveOptionsWidget : public KompareSaveOptionsBase, public KompareFunctions
+{
+Q_OBJECT
+public:
+ KompareSaveOptionsWidget( QString source, QString destination, DiffSettings* settings, QWidget* parent );
+ ~KompareSaveOptionsWidget();
+
+ void saveOptions();
+ QString directory() const;
+
+protected slots:
+ void updateCommandLine();
+
+private:
+ void loadOptions();
+
+ DiffSettings* m_settings;
+ QString m_source;
+ QString m_destination;
+};
+
+#endif
diff --git a/kompare/komparepart/komparesplitter.cpp b/kompare/komparepart/komparesplitter.cpp
new file mode 100644
index 00000000..fcf014cb
--- /dev/null
+++ b/kompare/komparepart/komparesplitter.cpp
@@ -0,0 +1,712 @@
+/***************************************************************************
+ komparesplitter.cpp - description
+ -------------------
+ begin : Wed Jan 14 2004
+ copyright : (C) 2004 by Jeff Snyder
+ email : jeff@caffeinated.me.uk
+****************************************************************************/
+
+/***************************************************************************
+**
+** This program is free software; you can redistribute it and/or modify
+** it under the terms of the 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 "komparesplitter.h"
+
+#include <qstyle.h>
+#include <qstring.h>
+#include <qtimer.h>
+
+#include <kdebug.h>
+#include <kapplication.h>
+#include <kglobalsettings.h>
+
+#include "diffmodel.h"
+#include "difference.h"
+#include "viewsettings.h"
+#include "kompare_part.h"
+#include "komparelistview.h"
+#include "kompareconnectwidget.h"
+
+using namespace Diff2;
+
+KompareSplitter::KompareSplitter( ViewSettings *settings, QWidget * parent,
+ const char *name) :
+ QSplitter( Horizontal, parent, name ),
+ m_settings( settings )
+{
+ QFrame *scrollFrame = new QFrame( parent, "scrollFrame" );
+ reparent( scrollFrame, *(new QPoint()), false );
+
+ // Set up the scrollFrame
+ scrollFrame->setFrameStyle( QFrame::NoFrame | QFrame::Plain );
+ scrollFrame->setLineWidth(scrollFrame->style().pixelMetric(QStyle::PM_DefaultFrameWidth));
+ QGridLayout *pairlayout = new QGridLayout(scrollFrame, 2, 2, 0);
+ m_vScroll = new QScrollBar( QScrollBar::Vertical, scrollFrame );
+ pairlayout->addWidget( m_vScroll, 0, 1 );
+ m_hScroll = new QScrollBar( QScrollBar::Horizontal, scrollFrame );
+ pairlayout->addWidget( m_hScroll, 1, 0 );
+
+ new KompareListViewFrame(true, m_settings, this, "source");
+ new KompareListViewFrame(false, m_settings, this, "destination");
+ pairlayout->addWidget( this, 0, 0 );
+
+ // set up our looks
+ setFrameStyle( QFrame::StyledPanel | QFrame::Sunken );
+ setLineWidth( style().pixelMetric( QStyle::PM_DefaultFrameWidth ) );
+
+ setHandleWidth(50);
+ setChildrenCollapsible( false );
+ setFrameStyle( QFrame::NoFrame );
+ setSizePolicy( QSizePolicy (QSizePolicy::Ignored, QSizePolicy::Ignored ));
+ setOpaqueResize( true );
+ setFocusPolicy( QWidget::WheelFocus );
+
+ connect( this, SIGNAL(configChanged()), SLOT(slotConfigChanged()) );
+ connect( this, SIGNAL(configChanged()), SLOT(slotDelayedRepaintHandles()) );
+ connect( this, SIGNAL(configChanged()), SLOT(slotDelayedUpdateScrollBars()) );
+
+ // scrolling
+ connect( m_vScroll, SIGNAL(valueChanged(int)), SLOT(scrollToId(int)) );
+ connect( m_vScroll, SIGNAL(sliderMoved(int)), SLOT(scrollToId(int)) );
+ connect( m_hScroll, SIGNAL(valueChanged(int)), SIGNAL(setXOffset(int)) );
+ connect( m_hScroll, SIGNAL(sliderMoved(int)), SIGNAL(setXOffset(int)) );
+
+ m_scrollTimer=new QTimer();
+ restartTimer = false;
+ connect (m_scrollTimer, SIGNAL(timeout()), SLOT(timerTimeout()) );
+
+ // we need to receive childEvents now so that d->list is ready for when
+ // slotSetSelection(...) arrives
+ kapp->sendPostedEvents(this, QEvent::ChildInserted);
+
+ // init stuff
+ slotUpdateScrollBars();
+}
+
+KompareSplitter::~KompareSplitter(){}
+
+/*
+ Inserts the widget \a w at the end (or at the beginning if \a
+ prepend is TRUE) of the splitter's list of widgets.
+
+ It is the responsibility of the caller to make sure that \a w is
+ not already in the splitter and to call recalcId() if needed. (If
+ \a prepend is TRUE, then recalcId() is very probably needed.)
+*/
+
+QSplitterLayoutStruct *KompareSplitter::addWidget( KompareListViewFrame *w, bool prepend )
+{
+ /* This function is *not* a good place to make connections to and from
+ * the KompareListView. Make them in the KompareListViewFrame constructor
+ * instad - that way the connections get made upon creation, not upon the
+ * next processing of the event queue. */
+
+ QSplitterLayoutStruct *s;
+ KompareConnectWidgetFrame *newHandle = 0;
+ if ( d->list.count() > 0 ) {
+ s = new QSplitterLayoutStruct;
+ s->resizeMode = KeepSize;
+ QString tmp = "qt_splithandle_";
+ tmp += w->name();
+ KompareListView *lw =
+ ((KompareListViewFrame*)(prepend?w:d->list.last()->wid))->view();
+ KompareListView *rw =
+ ((KompareListViewFrame*)(prepend?d->list.first()->wid:w))->view();
+ newHandle = new KompareConnectWidgetFrame(lw, rw, m_settings, this, tmp.latin1());
+ s->wid = newHandle;
+ newHandle->setId( d->list.count() );
+ s->isHandle = TRUE;
+ s->sizer = pick( newHandle->sizeHint() );
+ if ( prepend )
+ d->list.prepend( s );
+ else
+ d->list.append( s );
+ }
+ s = new QSplitterLayoutStruct;
+ s->resizeMode = DefaultResizeMode;
+ s->wid = w;
+ s->isHandle = FALSE;
+ if ( prepend ) d->list.prepend( s );
+ else d->list.append( s );
+ if ( newHandle && isVisible() )
+ newHandle->show(); // will trigger sending of post events
+ return s;
+}
+
+
+/*!
+ Tells the splitter that the child widget described by \a c has
+ been inserted or removed.
+*/
+
+void KompareSplitter::childEvent( QChildEvent *c )
+{
+ if ( c->type() == QEvent::ChildInserted ) {
+ if ( !c->child()->isWidgetType() )
+ return;
+
+ if ( ((QWidget*)c->child())->testWFlags( WType_TopLevel ) )
+ return;
+
+ QSplitterLayoutStruct *s = d->list.first();
+ while ( s ) {
+ if ( s->wid == c->child() )
+ return;
+ s = d->list.next();
+ }
+ addWidget( (KompareListViewFrame*)c->child() );
+ recalc( isVisible() );
+ } else if ( c->type() == QEvent::ChildRemoved ) {
+ QSplitterLayoutStruct *prev = 0;
+ if ( d->list.count() > 1 )
+ prev = d->list.at( 1 ); // yes, this is correct
+ QSplitterLayoutStruct *curr = d->list.first();
+ while ( curr ) {
+ if ( curr->wid == c->child() ) {
+ d->list.removeRef( curr );
+ if ( prev && prev->isHandle ) {
+ QWidget *w = prev->wid;
+ d->list.removeRef( prev );
+ delete w; // will call childEvent()
+ }
+ recalcId();
+ doResize();
+ return;
+ }
+ prev = curr;
+ curr = d->list.next();
+ }
+ }
+}
+
+// This is from a private qt header (kernel/qlayoutengine_p.h). sorry.
+QSize qSmartMinSize( QWidget *w );
+
+static QPoint toggle( QWidget *w, QPoint pos )
+{
+ QSize minS = qSmartMinSize( w );
+ return -pos - QPoint( minS.width(), minS.height() );
+}
+
+static bool isCollapsed( QWidget *w )
+{
+ return w->x() < 0 || w->y() < 0;
+}
+
+static QPoint topLeft( QWidget *w )
+{
+ if ( isCollapsed(w) ) {
+ return toggle( w, w->pos() );
+ } else {
+ return w->pos();
+ }
+}
+
+static QPoint bottomRight( QWidget *w )
+{
+ if ( isCollapsed(w) ) {
+ return toggle( w, w->pos() ) - QPoint( 1, 1 );
+ } else {
+ return w->geometry().bottomRight();
+ }
+}
+
+void KompareSplitter::moveSplitter( QCOORD p, int id )
+{
+ QSplitterLayoutStruct *s = d->list.at( id );
+ int farMin;
+ int min;
+ int max;
+ int farMax;
+ p = adjustPos( p, id, &farMin, &min, &max, &farMax );
+ int oldP = pick( s->wid->pos() );
+ int* poss = new int[d->list.count()];
+ int* ws = new int[d->list.count()];
+ QWidget *w = 0;
+ bool upLeft;
+ if ( QApplication::reverseLayout() && orient == Horizontal ) {
+ int q = p + s->wid->width();
+ doMove( FALSE, q, id - 1, -1, (p > max), poss, ws );
+ doMove( TRUE, q, id, -1, (p < min), poss, ws );
+ upLeft = (q > oldP);
+ } else {
+ doMove( FALSE, p, id, +1, (p > max), poss, ws );
+ doMove( TRUE, p, id - 1, +1, (p < min), poss, ws );
+ upLeft = (p < oldP);
+ }
+ if ( upLeft ) {
+ int count = d->list.count();
+ for ( int id = 0; id < count; ++id ) {
+ w = d->list.at( id )->wid;
+ if( !w->isHidden() )
+ setGeo( w, poss[id], ws[id], TRUE );
+ }
+ } else {
+ for ( int id = d->list.count() - 1; id >= 0; --id ) {
+ w = d->list.at( id )->wid;
+ if( !w->isHidden() )
+ setGeo( w, poss[id], ws[id], TRUE );
+ }
+ }
+ storeSizes();
+}
+
+void KompareSplitter::doMove( bool backwards, int pos, int id, int delta,
+ bool mayCollapse, int* positions, int* widths )
+{
+ QSplitterLayoutStruct *s;
+ QWidget *w;
+ for ( ; id >= 0 && id < (int)d->list.count();
+ id = backwards ? id - delta : id + delta ) {
+ s = d->list.at( id );
+ w = s->wid;
+ if ( w->isHidden() ) {
+ mayCollapse = TRUE;
+ } else {
+ if ( s->isHandle ) {
+ int dd = s->getSizer( orient );
+ int nextPos = backwards ? pos - dd : pos + dd;
+ positions[id] = pos;
+ widths[id] = dd;
+ pos = nextPos;
+ } else {
+ int dd = backwards ? pos - pick( topLeft(w) )
+ : pick( bottomRight(w) ) - pos + 1;
+ if ( dd > 0 || (!isCollapsed(w) && !mayCollapse) ) {
+ dd = QMAX( pick(qSmartMinSize(w)),
+ QMIN(dd, pick(w->maximumSize())) );
+ } else {
+ dd = 0;
+ }
+ positions[id] = backwards ? pos - dd : pos;
+ widths[id] = dd;
+ pos = backwards ? pos - dd : pos + dd;
+ mayCollapse = TRUE;
+ }
+ }
+ }
+}
+
+void KompareSplitter::slotSetSelection( const DiffModel* model, const Difference* diff )
+{
+ QSplitterLayoutStruct *curr;
+ for ( curr = d->list.first(); curr; curr = d->list.next() )
+ {
+ if ( curr->isHandle )
+ ((KompareConnectWidgetFrame*)
+ curr->wid)->wid()->slotSetSelection( model, diff );
+ else
+ {
+ ((KompareListViewFrame*)
+ curr->wid)->view()->slotSetSelection( model, diff );
+ ((KompareListViewFrame*)
+ curr->wid)->slotSetModel( model );
+ }
+ }
+ slotDelayedRepaintHandles();
+ slotDelayedUpdateScrollBars();
+}
+
+void KompareSplitter::slotSetSelection( const Difference* diff )
+{
+ QSplitterLayoutStruct *curr;
+ for ( curr = d->list.first(); curr; curr = d->list.next() )
+ if ( curr->isHandle )
+ ((KompareConnectWidgetFrame*)
+ curr->wid)->wid()->slotSetSelection( diff );
+ else
+ ((KompareListViewFrame*)
+ curr->wid)->view()->slotSetSelection( diff );
+ slotDelayedRepaintHandles();
+ slotDelayedUpdateScrollBars();
+}
+
+void KompareSplitter::slotApplyDifference( bool apply )
+{
+ QSplitterLayoutStruct *curr;
+ for ( curr = d->list.first(); curr; curr = d->list.next() )
+ if ( !curr->isHandle )
+ ((KompareListViewFrame*)
+ curr->wid)->view()->slotApplyDifference( apply );
+ slotDelayedRepaintHandles();
+}
+
+void KompareSplitter::slotApplyAllDifferences( bool apply )
+{
+ QSplitterLayoutStruct *curr;
+ for ( curr = d->list.first(); curr; curr = d->list.next() )
+ if ( !curr->isHandle )
+ ((KompareListViewFrame*)
+ curr->wid)->view()->slotApplyAllDifferences( apply );
+ slotDelayedRepaintHandles();
+ scrollToId( scrollTo ); // FIXME!
+}
+
+void KompareSplitter::slotApplyDifference( const Difference* diff, bool apply )
+{
+ QSplitterLayoutStruct *curr;
+ for ( curr = d->list.first(); curr; curr = d->list.next() )
+ if ( !curr->isHandle )
+ ((KompareListViewFrame*)
+ curr->wid)->view()->slotApplyDifference( diff, apply );
+ slotDelayedRepaintHandles();
+}
+
+void KompareSplitter::slotDifferenceClicked( const Difference* diff )
+{
+ QSplitterLayoutStruct *curr;
+ for ( curr = d->list.first(); curr; curr = d->list.next() )
+ if ( !curr->isHandle )
+ ((KompareListViewFrame*)
+ curr->wid)->view()->setSelectedDifference( diff, false );
+ emit selectionChanged( diff );
+}
+
+void KompareSplitter::slotConfigChanged()
+{
+ QSplitterLayoutStruct *curr;
+ for ( curr = d->list.first(); curr; curr = d->list.next() ) {
+ if ( !curr->isHandle )
+ {
+ ((KompareListViewFrame*)
+ curr->wid)->view()->setSpaces( m_settings->m_tabToNumberOfSpaces );
+ ((KompareListViewFrame*)
+ curr->wid)->view()->setFont( m_settings->m_font );
+ ((KompareListViewFrame*)
+ curr->wid)->view()->update();
+ }
+ }
+}
+
+void KompareSplitter::slotDelayedRepaintHandles()
+{
+ QSplitterLayoutStruct *curr;
+ for ( curr = d->list.first(); curr; curr = d->list.next() )
+ if ( curr->isHandle )
+ ((KompareConnectWidgetFrame*)curr->wid)->wid()->slotDelayedRepaint();
+}
+
+void KompareSplitter::repaintHandles()
+{
+ QSplitterLayoutStruct *curr;
+ for ( curr = d->list.first(); curr; curr = d->list.next() )
+ if ( curr->isHandle )
+ ((KompareConnectWidgetFrame*)curr->wid)->wid()->repaint();
+}
+
+// Scrolling stuff
+/*
+ * limit updating to once every 50 msec with a qtimer
+ * FIXME: i'm a nasty hack
+ */
+
+void KompareSplitter::wheelEvent( QWheelEvent* e )
+{
+ // scroll lines...
+ if ( e->orientation() == Qt::Vertical )
+ {
+ if ( e->state() & Qt::ControlButton )
+ if ( e->delta() < 0 ) // scroll down one page
+ m_vScroll->addPage();
+ else // scroll up one page
+ m_vScroll->subtractPage();
+ else
+ if ( e->delta() < 0 ) // scroll down
+ m_vScroll->addLine();
+ else // scroll up
+ m_vScroll->subtractLine();
+ }
+ else
+ {
+ if ( e->state() & Qt::ControlButton )
+ if ( e->delta() < 0 ) // scroll right one page
+ m_hScroll->addPage();
+ else // scroll left one page
+ m_hScroll->subtractPage();
+ else
+ if ( e->delta() < 0 ) // scroll to the right
+ m_hScroll->addLine();
+ else // scroll to the left
+ m_hScroll->subtractLine();
+ }
+ e->accept();
+ repaintHandles();
+}
+
+void KompareSplitter::keyPressEvent( QKeyEvent* e )
+{
+ //keyboard scrolling
+ switch ( e->key() ) {
+ case Key_Right:
+ case Key_L:
+ m_hScroll->addLine();
+ break;
+ case Key_Left:
+ case Key_H:
+ m_hScroll->subtractLine();
+ break;
+ case Key_Up:
+ case Key_K:
+ m_vScroll->subtractLine();
+ break;
+ case Key_Down:
+ case Key_J:
+ m_vScroll->addLine();
+ break;
+ case Key_PageDown:
+ m_vScroll->addPage();
+ break;
+ case Key_PageUp:
+ m_vScroll->subtractPage();
+ break;
+ }
+ e->accept();
+ repaintHandles();
+}
+
+void KompareSplitter::timerTimeout()
+{
+ if ( restartTimer )
+ restartTimer = false;
+ else
+ m_scrollTimer->stop();
+
+ slotDelayedRepaintHandles();
+
+ emit scrollViewsToId( scrollTo );
+}
+
+void KompareSplitter::scrollToId( int id )
+{
+ scrollTo = id;
+
+ if( restartTimer )
+ return;
+
+ if( m_scrollTimer->isActive() )
+ {
+ restartTimer = true;
+ }
+ else
+ {
+ emit scrollViewsToId( id );
+ slotDelayedRepaintHandles();
+ m_scrollTimer->start(30, false);
+ }
+}
+
+void KompareSplitter::slotDelayedUpdateScrollBars()
+{
+ QTimer::singleShot( 0, this, SLOT( slotUpdateScrollBars() ) );
+}
+
+void KompareSplitter::slotUpdateScrollBars()
+{
+ int m_scrollDistance = m_settings->m_scrollNoOfLines * lineSpacing();
+ int m_pageSize = pageSize();
+
+ if( needVScrollBar() )
+ {
+ m_vScroll->show();
+
+ m_vScroll->blockSignals( true );
+ m_vScroll->setRange( minVScrollId(),
+ maxVScrollId() );
+ m_vScroll->setValue( scrollId() );
+ m_vScroll->setSteps( m_scrollDistance, m_pageSize );
+ m_vScroll->blockSignals( false );
+ }
+ else
+ {
+ m_vScroll->hide();
+ }
+
+ if( needHScrollBar() )
+ {
+ m_hScroll->show();
+ m_hScroll->blockSignals( true );
+ m_hScroll->setRange( 0, maxHScrollId() );
+ m_hScroll->setValue( maxContentsX() );
+ m_hScroll->setSteps( 10, minVisibleWidth() - 10 );
+ m_hScroll->blockSignals( false );
+ }
+ else
+ {
+ m_hScroll->hide();
+ }
+}
+
+void KompareSplitter::slotDelayedUpdateVScrollValue()
+{
+ QTimer::singleShot( 0, this, SLOT( slotUpdateVScrollValue() ) );
+}
+
+void KompareSplitter::slotUpdateVScrollValue()
+{
+ m_vScroll->setValue( scrollId() );
+}
+
+/* FIXME: this should return the scrollId() from the listview containing the
+ * /base/ of the diff. but there's bigger issues with that atm.
+ */
+
+int KompareSplitter::scrollId()
+{
+ QSplitterLayoutStruct *curr = d->list.first();
+ for ( curr = d->list.first(); curr; curr = d->list.next() )
+ if ( !curr->isHandle )
+ return ((KompareListViewFrame*) curr->wid)->view()->scrollId();
+ return minVScrollId();
+}
+
+int KompareSplitter::lineSpacing()
+{
+ QSplitterLayoutStruct *curr = d->list.first();
+ for ( curr = d->list.first(); curr; curr = d->list.next() )
+ if ( !curr->isHandle )
+ return ((KompareListViewFrame*)
+ curr->wid)->view()->fontMetrics().lineSpacing();
+ return 1;
+}
+
+int KompareSplitter::pageSize()
+{
+ QSplitterLayoutStruct *curr;
+ for ( curr = d->list.first(); curr; curr = d->list.next() )
+ {
+ if ( !curr->isHandle )
+ {
+ KompareListView *view = ((KompareListViewFrame*) curr->wid)->view();
+ return view->visibleHeight() - QStyle::PM_ScrollBarExtent;
+ }
+ }
+ return 1;
+}
+
+bool KompareSplitter::needVScrollBar()
+{
+ QSplitterLayoutStruct *curr;
+ int pagesize = pageSize();
+ for ( curr = d->list.first(); curr; curr = d->list.next() )
+ {
+ if( !curr->isHandle )
+ {
+ KompareListView *view = ((KompareListViewFrame*) curr->wid)->view();
+ if( view ->contentsHeight() > pagesize)
+ return true;
+ }
+ }
+ return false;
+}
+
+int KompareSplitter::minVScrollId()
+{
+
+ QSplitterLayoutStruct *curr;
+ int min = -1;
+ int mSId;
+ for ( curr = d->list.first(); curr; curr = d->list.next() )
+ {
+ if(!curr->isHandle) {
+ KompareListView* view = ((KompareListViewFrame*)curr->wid)->view();
+ mSId = view->minScrollId();
+ if (mSId < min || min == -1) min = mSId;
+ }
+ }
+ return ( min == -1 ) ? 0 : min;
+}
+
+int KompareSplitter::maxVScrollId()
+{
+ QSplitterLayoutStruct *curr;
+ int max = 0;
+ int mSId;
+ for ( curr = d->list.first(); curr; curr = d->list.next() )
+ {
+ if ( !curr->isHandle )
+ {
+ mSId = ((KompareListViewFrame*)curr->wid)->view()->maxScrollId();
+ if ( mSId > max )
+ max = mSId;
+ }
+ }
+ return max;
+}
+
+bool KompareSplitter::needHScrollBar()
+{
+ QSplitterLayoutStruct *curr;
+ for ( curr = d->list.first(); curr; curr = d->list.next() )
+ {
+ if( !curr->isHandle )
+ {
+ KompareListView *view = ((KompareListViewFrame*) curr->wid)->view();
+ if ( view->contentsWidth() > view->visibleWidth() )
+ return true;
+ }
+ }
+ return false;
+}
+
+int KompareSplitter::maxHScrollId()
+{
+ QSplitterLayoutStruct *curr;
+ int max = 0;
+ int mHSId;
+ for ( curr = d->list.first(); curr; curr = d->list.next() )
+ {
+ if( !curr->isHandle )
+ {
+ KompareListView *view = ((KompareListViewFrame*) curr->wid)->view();
+ mHSId = view->contentsWidth() - view->visibleWidth();
+ if ( mHSId > max )
+ max = mHSId;
+ }
+ }
+ return max;
+}
+
+int KompareSplitter::maxContentsX()
+{
+ QSplitterLayoutStruct *curr;
+ int max = 0;
+ int mCX;
+ for ( curr = d->list.first(); curr; curr = d->list.next() )
+ {
+ if ( !curr->isHandle )
+ {
+ mCX = ((KompareListViewFrame*) curr->wid)->view()->contentsX();
+ if ( mCX > max )
+ max = mCX;
+ }
+ }
+ return max;
+}
+
+int KompareSplitter::minVisibleWidth()
+{
+ // Why the hell do we want to know this?
+ // ah yes, its because we use it to set the "page size" for horiz. scrolling.
+ // despite the fact that *noone* has a pgright and pgleft key :P
+ // But we do have mousewheels with horizontal scrolling functionality,
+ // pressing shift and scrolling then goes left and right one page at the time
+ QSplitterLayoutStruct *curr;
+ int min = -1;
+ int vW;
+ for( curr = d->list.first(); curr; curr = d->list.next() )
+ {
+ if ( !curr->isHandle ) {
+ vW = ((KompareListViewFrame*)curr->wid)->view()->visibleWidth();
+ if ( vW < min || min == -1 )
+ min = vW;
+ }
+ }
+ return ( min == -1 ) ? 0 : min;
+}
+
+#include "komparesplitter.moc"
diff --git a/kompare/komparepart/komparesplitter.h b/kompare/komparepart/komparesplitter.h
new file mode 100644
index 00000000..47eee6bf
--- /dev/null
+++ b/kompare/komparepart/komparesplitter.h
@@ -0,0 +1,115 @@
+/***************************************************************************
+ kompareview.cpp - description
+ -------------------
+ begin : Wed Jan 14 2004
+ copyright : (C) 2004 by Jeff Snyder
+ email : jeff@caffeinated.me.uk
+****************************************************************************/
+
+/***************************************************************************
+**
+** This program is free software; you can redistribute it and/or modify
+** it under the terms of the 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 _KOMPARESPLITTER_H_
+#define _KOMPARESPLITTER_H_
+
+#include "kompare_qsplitter.h"
+
+#include <qtimer.h>
+
+#include "komparelistview.h"
+#include "komparemodellist.h"
+
+class QSplitterLayoutStruct;
+class QTextStream;
+class QSplitterHandle;
+
+namespace Diff2 {
+class DiffModel;
+class Difference;
+}
+class ViewSettings;
+
+class KompareSplitter : public QSplitter
+{
+ Q_OBJECT
+
+public:
+ KompareSplitter(ViewSettings *settings, QWidget *parent=0, const char *name = 0);
+ ~KompareSplitter();
+
+signals:
+ void selectionChanged( const Diff2::Difference* diff );
+
+ void configChanged();
+
+ void scrollViewsToId( int id );
+ void setXOffset( int x );
+
+public slots:
+ void slotApplyDifference( bool apply );
+ void slotApplyAllDifferences( bool apply );
+ void slotApplyDifference( const Diff2::Difference* diff, bool apply );
+
+ // to update the list views
+ void slotSetSelection( const Diff2::DiffModel* model, const Diff2::Difference* diff );
+ void slotSetSelection( const Diff2::Difference* diff );
+
+ void slotDifferenceClicked( const Diff2::Difference* diff );
+
+ void slotConfigChanged();
+
+ void scrollToId( int id );
+ void slotDelayedUpdateScrollBars();
+ void slotUpdateScrollBars();
+ void slotDelayedUpdateVScrollValue();
+ void slotUpdateVScrollValue();
+
+protected:
+ void childEvent( QChildEvent * );
+ void wheelEvent( QWheelEvent* e );
+ void keyPressEvent( QKeyEvent* e );
+
+ void moveSplitter( QCOORD pos, int id );
+
+private slots:
+ void slotDelayedRepaintHandles();
+ void timerTimeout();
+
+private:
+ QSplitterLayoutStruct *addWidget(KompareListViewFrame *w,
+ bool prepend = FALSE );
+
+ void doMove( bool backwards, int pos, int id, int delta,
+ bool mayCollapse, int* positions, int* widths );
+
+ void repaintHandles();
+
+ QTimer* m_scrollTimer;
+ bool restartTimer;
+ int scrollTo;
+
+ // Scrollbars. all this just for the goddamn scrollbars. i hate them.
+ int scrollId();
+ int lineSpacing();
+ int pageSize();
+ bool needVScrollBar();
+ int minVScrollId();
+ int maxVScrollId();
+ bool needHScrollBar();
+ int maxHScrollId();
+ int maxContentsX();
+ int minVisibleWidth();
+
+ ViewSettings* m_settings;
+ QScrollBar* m_vScroll;
+ QScrollBar* m_hScroll;
+
+ friend class KompareConnectWidgetFrame;
+};
+#endif //_KOMPARESPLITTER_H_
diff --git a/kompare/kompareui.rc b/kompare/kompareui.rc
new file mode 100644
index 00000000..cfcf64c8
--- /dev/null
+++ b/kompare/kompareui.rc
@@ -0,0 +1,33 @@
+<!DOCTYPE kpartgui SYSTEM "kpartgui.dtd">
+<kpartgui name="kompare_shell" version="9">
+<MenuBar>
+ <Menu noMerge="1" name="file"><text>&amp;File</text>
+ <Action name="file_open"/>
+ <Action name="file_compare_files"/>
+ <Action name="file_blend_url"/>
+ <Separator/>
+ <Merge/>
+ <Separator/>
+ <Action name="file_quit"/>
+ </Menu>
+ <Merge/>
+ <Menu noMerge="1" name="settings"><text>&amp;Settings</text>
+ <Merge name="StandardToolBarMenuHandler" />
+ <Action name="options_show_toolbar"/>
+ <Action name="options_show_statusbar"/>
+ <Action name="options_show_text_view"/>
+ <Merge name="show_merge"/>
+ <Separator/>
+ <Action name="options_configure_keybinding"/>
+ <Action name="options_configure_toolbars"/>
+ <Merge name="configure_merge"/>
+ <Merge/>
+ </Menu>
+</MenuBar>
+<ToolBar noMerge="1" name="mainToolBar"><text>Main Toolbar</text>
+ <Action name="file_compare_files"/>
+ <Separator/>
+ <Merge/>
+ <Action name="help"/>
+</ToolBar>
+</kpartgui>
diff --git a/kompare/kompareurldialog.cpp b/kompare/kompareurldialog.cpp
new file mode 100644
index 00000000..4630cd18
--- /dev/null
+++ b/kompare/kompareurldialog.cpp
@@ -0,0 +1,143 @@
+/***************************************************************************
+ comparedialog.cpp - description
+ -------------------
+ begin : Sun Mar 4 2001
+ copyright : (C) 2001-2004 Otto Bruggeman
+ (C) 2001-2003 John Firebaugh
+ email : otto.bruggeman@home.nl
+ jfirebaugh@kde.org
+****************************************************************************/
+
+/***************************************************************************
+**
+** This program is free software; you can redistribute it and/or modify
+** it under the terms of the 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 <qvbox.h>
+
+#include <kapplication.h>
+#include <klocale.h>
+#include <kurlrequester.h>
+
+#include "diffpage.h"
+#include "diffsettings.h"
+#include "filespage.h"
+#include "filessettings.h"
+#include "viewpage.h"
+#include "viewsettings.h"
+
+#include "kompareurldialog.h"
+
+KompareURLDialog::KompareURLDialog( QWidget *parent, const char *name )
+ : KDialogBase( IconList, "", Ok|Cancel, Ok, parent, name )
+{
+ setIconListAllVisible(true);
+
+ KConfig* cfg = kapp->config();
+ QVBox* filesBox = addVBoxPage( i18n( "Files" ), i18n( "Here you can enter the files you want to compare." ) );
+ m_filesPage = new FilesPage( filesBox );
+ m_filesSettings = new FilesSettings( this );
+ m_filesSettings->loadSettings( cfg );
+ m_filesPage->setSettings( m_filesSettings );
+
+ QVBox* diffBox = addVBoxPage( i18n( "Diff" ), i18n( "Here you can change the options for comparing the files." ) );
+ m_diffPage = new DiffPage( diffBox );
+ m_diffSettings = new DiffSettings( this );
+ m_diffSettings->loadSettings( cfg );
+ m_diffPage->setSettings( m_diffSettings );
+
+ QVBox* viewBox = addVBoxPage( i18n( "Appearance" ), i18n( "Here you can change the options for the view." ) );
+ m_viewPage = new ViewPage( viewBox );
+ m_viewSettings = new ViewSettings( this );
+ m_viewSettings->loadSettings( cfg );
+ m_viewPage->setSettings( m_viewSettings );
+
+ adjustSize();
+
+ enableButtonSeparator( true );
+
+ connect( m_filesPage->firstURLRequester(), SIGNAL( textChanged( const QString& ) ),
+ this, SLOT( slotEnableOk() ) );
+ connect( m_filesPage->secondURLRequester(), SIGNAL( textChanged( const QString& ) ),
+ this, SLOT( slotEnableOk() ) );
+
+ slotEnableOk();
+}
+
+KompareURLDialog::~KompareURLDialog()
+{
+}
+
+void KompareURLDialog::slotOk()
+{
+ m_filesPage->setURLsInComboBoxes();
+
+ KConfig* cfg = kapp->config();
+
+ m_filesPage->apply();
+ m_diffPage->apply();
+ m_viewPage->apply();
+
+ m_filesSettings->saveSettings( cfg );
+ m_diffSettings->saveSettings( cfg );
+ m_viewSettings->saveSettings( cfg );
+
+ cfg->sync();
+
+ KDialogBase::slotOk();
+}
+
+void KompareURLDialog::slotEnableOk()
+{
+ enableButtonOK( !m_filesPage->firstURLRequester()->url().isEmpty() &&
+ !m_filesPage->secondURLRequester()->url().isEmpty() );
+}
+
+KURL KompareURLDialog::getFirstURL() const
+{
+ return KURL( m_filesPage->firstURLRequester()->url() );
+}
+
+KURL KompareURLDialog::getSecondURL() const
+{
+ return KURL( m_filesPage->secondURLRequester()->url() );
+}
+
+QString KompareURLDialog::encoding() const
+{
+ return m_filesPage->encoding();
+}
+
+void KompareURLDialog::setFirstGroupBoxTitle( const QString& title )
+{
+ m_filesPage->setFirstGroupBoxTitle( title );
+}
+
+void KompareURLDialog::setSecondGroupBoxTitle( const QString& title )
+{
+ m_filesPage->setSecondGroupBoxTitle( title );
+}
+
+void KompareURLDialog::setGroup( const QString& groupName )
+{
+ m_filesSettings->setGroup( groupName );
+ m_filesSettings->loadSettings( kapp->config() );
+ m_filesPage->setSettings( m_filesSettings );
+}
+
+void KompareURLDialog::setFirstURLRequesterMode( unsigned int mode )
+{
+ m_filesPage->setFirstURLRequesterMode( mode );
+}
+
+void KompareURLDialog::setSecondURLRequesterMode( unsigned int mode )
+{
+ m_filesPage->setSecondURLRequesterMode( mode );
+}
+
+#include "kompareurldialog.moc"
+
diff --git a/kompare/kompareurldialog.h b/kompare/kompareurldialog.h
new file mode 100644
index 00000000..61db9974
--- /dev/null
+++ b/kompare/kompareurldialog.h
@@ -0,0 +1,76 @@
+/***************************************************************************
+ kcompareurldialog.h - description
+ -------------------
+ begin : Sun Mar 4 2001
+ copyright : (C) 2001-2004 Otto Bruggeman
+ (C) 2001-2003 John Firebaugh
+ email : otto.bruggeman@home.nl
+ jfirebaugh@kde.org
+****************************************************************************/
+
+/***************************************************************************
+**
+** This program is free software; you can redistribute it and/or modify
+** it under the terms of the 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 KOMPAREURLDIALOG_H
+#define KOMPAREURLDIALOG_H
+
+#include <kdialogbase.h>
+#include <kurl.h>
+
+class QGroupBox;
+
+class KComboBox;
+class KConfig;
+class KFileDialog;
+class KURLComboBox;
+class KURLRequester;
+
+class FilesPage;
+class FilesSettings;
+class DiffPage;
+class DiffSettings;
+class ViewPage;
+class ViewSettings;
+
+class KompareURLDialog : public KDialogBase
+{
+ Q_OBJECT
+
+public:
+ KompareURLDialog( QWidget* parent = 0, const char* name = 0 );
+ ~KompareURLDialog();
+
+ KURL getFirstURL() const;
+ KURL getSecondURL() const;
+ QString encoding() const;
+
+ void setFirstGroupBoxTitle ( const QString& title );
+ void setSecondGroupBoxTitle( const QString& title );
+
+ void setGroup( const QString& groupName );
+
+ void setFirstURLRequesterMode ( unsigned int mode );
+ void setSecondURLRequesterMode( unsigned int mode );
+
+protected slots:
+ virtual void slotOk();
+
+private slots:
+ void slotEnableOk();
+
+private:
+ FilesPage* m_filesPage;
+ FilesSettings* m_filesSettings;
+ DiffPage* m_diffPage;
+ DiffSettings* m_diffSettings;
+ ViewPage* m_viewPage;
+ ViewSettings* m_viewSettings;
+};
+
+#endif
diff --git a/kompare/kompareviewpart.desktop b/kompare/kompareviewpart.desktop
new file mode 100644
index 00000000..5af4da28
--- /dev/null
+++ b/kompare/kompareviewpart.desktop
@@ -0,0 +1,4 @@
+[Desktop Entry]
+Type=ServiceType
+X-KDE-ServiceType=Kompare/ViewPart
+X-KDE-Derived=KParts/ReadOnlyPart
diff --git a/kompare/libdialogpages/Makefile.am b/kompare/libdialogpages/Makefile.am
new file mode 100644
index 00000000..e13405eb
--- /dev/null
+++ b/kompare/libdialogpages/Makefile.am
@@ -0,0 +1,32 @@
+INCLUDES = \
+ -I$(top_srcdir)/kompare/libdiff2 \
+ $(all_includes)
+
+noinst_HEADERS = \
+ settingsbase.h \
+ diffsettings.h \
+ filessettings.h \
+ viewsettings.h \
+ pagebase.h \
+ diffpage.h \
+ filespage.h \
+ viewpage.h
+
+# let automoc handle all of the meta source files (moc)
+METASOURCES = AUTO
+
+noinst_LTLIBRARIES = libdialogpages.la
+
+# the library's source, library search path, and link libraries
+libdialogpages_la_SOURCES = \
+ settingsbase.cpp \
+ diffsettings.cpp \
+ filessettings.cpp \
+ viewsettings.cpp \
+ pagebase.cpp \
+ diffpage.cpp \
+ filespage.cpp \
+ viewpage.cpp
+
+libdialogpages_la_LDFLAGS = $(all_libraries)
+libdialogpages_la_LIBADD = $(LIB_KFILE)
diff --git a/kompare/libdialogpages/diffpage.cpp b/kompare/libdialogpages/diffpage.cpp
new file mode 100644
index 00000000..7f805c5b
--- /dev/null
+++ b/kompare/libdialogpages/diffpage.cpp
@@ -0,0 +1,355 @@
+/***************************************************************************
+ diffprefs.cpp - description
+ -------------------
+ begin : Sun Mar 4 2001
+ copyright : (C) 2001-2004 Otto Bruggeman
+ email : otto.bruggeman@home.nl
+****************************************************************************/
+
+/***************************************************************************
+**
+** This program is free software; you can redistribute it and/or modify
+** it under the terms of the 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 <qcheckbox.h>
+#include <qhgroupbox.h>
+#include <qlabel.h>
+#include <qlayout.h>
+#include <qradiobutton.h>
+#include <qspinbox.h>
+#include <qtooltip.h>
+#include <qvbuttongroup.h>
+#include <qwhatsthis.h>
+
+#include <kapplication.h>
+#include <kcombobox.h>
+#include <kdialog.h>
+#include <keditlistbox.h>
+#include <klineedit.h>
+#include <klocale.h>
+#include <ktrader.h>
+#include <kurlcombobox.h>
+#include <kurlrequester.h>
+
+#include <kparts/componentfactory.h>
+#include <kregexpeditorinterface.h>
+
+#include "diffsettings.h"
+
+#include "diffpage.h"
+
+DiffPage::DiffPage( QWidget* parent ) : PageBase( parent ),
+ m_ignoreRegExpDialog( 0 )
+{
+ addDiffTab();
+
+ addFormatTab();
+
+ addOptionsTab();
+
+ addExcludeTab();
+}
+
+DiffPage::~DiffPage()
+{
+ m_settings = 0;
+}
+
+void DiffPage::setSettings( DiffSettings* setts )
+{
+ m_settings = setts;
+
+ m_diffURLRequester->setURL( m_settings->m_diffProgram );
+
+ m_smallerCheckBox->setChecked ( m_settings->m_createSmallerDiff );
+ m_largerCheckBox->setChecked ( m_settings->m_largeFiles );
+ m_tabsCheckBox->setChecked ( m_settings->m_convertTabsToSpaces );
+ m_caseCheckBox->setChecked ( m_settings->m_ignoreChangesInCase );
+ m_linesCheckBox->setChecked ( m_settings->m_ignoreEmptyLines );
+ m_whitespaceCheckBox->setChecked ( m_settings->m_ignoreWhiteSpace );
+ m_allWhitespaceCheckBox->setChecked ( m_settings->m_ignoreAllWhiteSpace );
+ m_ignoreTabExpansionCheckBox->setChecked( m_settings->m_ignoreChangesDueToTabExpansion );
+
+ m_ignoreRegExpCheckBox->setChecked ( m_settings->m_ignoreRegExp );
+ m_ignoreRegExpEdit->setCompletedItems( m_settings->m_ignoreRegExpTextHistory );
+ m_ignoreRegExpEdit->setText ( m_settings->m_ignoreRegExpText );
+
+ m_locSpinBox->setValue( m_settings->m_linesOfContext );
+
+ m_modeButtonGroup->setButton( m_settings->m_format );
+
+ m_excludeFilePatternCheckBox->setChecked ( m_settings->m_excludeFilePattern );
+ slotExcludeFilePatternToggled ( m_settings->m_excludeFilePattern );
+ m_excludeFilePatternEditListBox->insertStringList( m_settings->m_excludeFilePatternList );
+
+ m_excludeFileCheckBox->setChecked( m_settings->m_excludeFilesFile );
+ slotExcludeFileToggled ( m_settings->m_excludeFilesFile );
+ m_excludeFileURLComboBox->setURLs( m_settings->m_excludeFilesFileHistoryList );
+ m_excludeFileURLComboBox->setURL ( KURL( m_settings->m_excludeFilesFileURL ) );
+}
+
+DiffSettings* DiffPage::settings( void )
+{
+ return m_settings;
+}
+
+void DiffPage::restore()
+{
+ // this shouldn't do a thing...
+}
+
+void DiffPage::apply()
+{
+ m_settings->m_diffProgram = m_diffURLRequester->url();
+
+ m_settings->m_largeFiles = m_largerCheckBox->isChecked();
+ m_settings->m_createSmallerDiff = m_smallerCheckBox->isChecked();
+ m_settings->m_convertTabsToSpaces = m_tabsCheckBox->isChecked();
+ m_settings->m_ignoreChangesInCase = m_caseCheckBox->isChecked();
+ m_settings->m_ignoreEmptyLines = m_linesCheckBox->isChecked();
+ m_settings->m_ignoreWhiteSpace = m_whitespaceCheckBox->isChecked();
+ m_settings->m_ignoreAllWhiteSpace = m_allWhitespaceCheckBox->isChecked();
+ m_settings->m_ignoreChangesDueToTabExpansion = m_ignoreTabExpansionCheckBox->isChecked();
+
+ m_settings->m_ignoreRegExp = m_ignoreRegExpCheckBox->isChecked();
+ m_settings->m_ignoreRegExpText = m_ignoreRegExpEdit->text();
+ m_settings->m_ignoreRegExpTextHistory = m_ignoreRegExpEdit->completionObject()->items();
+
+ m_settings->m_linesOfContext = m_locSpinBox->value();
+
+ m_settings->m_format = static_cast<Kompare::Format>( m_modeButtonGroup->selectedId() );
+
+ m_settings->m_excludeFilePattern = m_excludeFilePatternCheckBox->isChecked();
+ m_settings->m_excludeFilePatternList = m_excludeFilePatternEditListBox->items();
+
+ m_settings->m_excludeFilesFile = m_excludeFileCheckBox->isChecked();
+ m_settings->m_excludeFilesFileURL = m_excludeFileURLComboBox->currentText();
+ m_settings->m_excludeFilesFileHistoryList = m_excludeFileURLComboBox->urls();
+
+ m_settings->saveSettings( kapp->config() );
+}
+
+void DiffPage::setDefaults()
+{
+ m_diffURLRequester->setURL( "diff" );
+ m_smallerCheckBox->setChecked( true );
+ m_largerCheckBox->setChecked( true );
+ m_tabsCheckBox->setChecked( false );
+ m_caseCheckBox->setChecked( false );
+ m_linesCheckBox->setChecked( false );
+ m_whitespaceCheckBox->setChecked( false );
+ m_allWhitespaceCheckBox->setChecked( false );
+ m_ignoreTabExpansionCheckBox->setChecked( false );
+ m_ignoreRegExpCheckBox->setChecked( false );
+
+ m_ignoreRegExpEdit->setText( QString::null );
+
+ m_locSpinBox->setValue( 3 );
+
+ m_modeButtonGroup->setButton( Kompare::Unified );
+
+ m_excludeFilePatternCheckBox->setChecked( false );
+
+ m_excludeFileCheckBox->setChecked( false );
+}
+
+void DiffPage::slotShowRegExpEditor()
+{
+ if ( ! m_ignoreRegExpDialog )
+ m_ignoreRegExpDialog = KParts::ComponentFactory::createInstanceFromQuery<QDialog>( "KRegExpEditor/KRegExpEditor", QString::null, this );
+
+ KRegExpEditorInterface *iface = static_cast<KRegExpEditorInterface *>( m_ignoreRegExpDialog->qt_cast( "KRegExpEditorInterface" ) );
+
+ if ( !iface )
+ return;
+
+ iface->setRegExp( m_ignoreRegExpEdit->text() );
+ bool ok = m_ignoreRegExpDialog->exec();
+
+ if ( ok )
+ m_ignoreRegExpEdit->setText( iface->regExp() );
+}
+
+void DiffPage::slotExcludeFilePatternToggled( bool on )
+{
+ if ( !on )
+ {
+ m_excludeFilePatternEditListBox->setEnabled( false );
+ }
+ else
+ {
+ m_excludeFilePatternEditListBox->setEnabled( true );
+ }
+}
+
+void DiffPage::slotExcludeFileToggled( bool on )
+{
+ if ( !on )
+ {
+ m_excludeFileURLComboBox->setEnabled( false );
+ m_excludeFileURLRequester->setEnabled( false );
+ }
+ else
+ {
+ m_excludeFileURLComboBox->setEnabled( true );
+ m_excludeFileURLRequester->setEnabled( true );
+ }
+}
+
+void DiffPage::addDiffTab()
+{
+ QWidget* page = new QWidget( this );
+ QVBoxLayout* layout = new QVBoxLayout( page );
+ layout->setSpacing( KDialog::spacingHint() );
+ layout->setMargin( KDialog::marginHint() );
+
+ // add diff program selector
+ m_diffProgramGroup = new QVButtonGroup( i18n( "Diff Program" ), page );
+ layout->addWidget( m_diffProgramGroup );
+ m_diffProgramGroup->setMargin( KDialog::marginHint() );
+
+ m_diffURLRequester = new KURLRequester( m_diffProgramGroup, "diffURLRequester" );
+ QWhatsThis::add( m_diffURLRequester, i18n( "You can select a different diff program here. On Solaris the standard diff program does not support all the options that the GNU version does. This way you can select that version." ) );
+
+ layout->addStretch( 1 );
+ page->setMinimumSize( sizeHintForWidget( page ) );
+
+ addTab( page, i18n( "&Diff" ) );
+}
+
+void DiffPage::addFormatTab()
+{
+ QWidget* page = new QWidget( this );
+ QVBoxLayout* layout = new QVBoxLayout( page );
+ layout->setSpacing( KDialog::spacingHint() );
+ layout->setMargin( KDialog::marginHint() );
+
+ // add diff modes
+ m_modeButtonGroup = new QVButtonGroup( i18n( "Output Format" ), page );
+ QWhatsThis::add( m_modeButtonGroup, i18n( "Select the format of the output generated by diff. Unified is the one that is used most frequently because it is very readable. The KDE developers like this format the best so use it for sending patches." ) );
+ layout->addWidget( m_modeButtonGroup );
+ m_modeButtonGroup->setMargin( KDialog::marginHint() );
+
+ QRadioButton* radioButton;
+ radioButton = new QRadioButton( i18n( "Context" ), m_modeButtonGroup );
+ radioButton = new QRadioButton( i18n( "Ed" ), m_modeButtonGroup );
+ radioButton->setEnabled( false );
+ radioButton = new QRadioButton( i18n( "Normal" ), m_modeButtonGroup );
+ radioButton = new QRadioButton( i18n( "RCS" ), m_modeButtonGroup );
+ radioButton->setEnabled( false );
+ radioButton = new QRadioButton( i18n( "Unified" ), m_modeButtonGroup );
+
+ // #lines of context (loc)
+ QHGroupBox* groupBox = new QHGroupBox( i18n( "Lines of Context" ), page );
+ layout->addWidget( groupBox );
+ groupBox->setMargin( KDialog::marginHint() );
+
+ QLabel* label = new QLabel( i18n( "Number of context lines:" ), groupBox );
+ m_locSpinBox = new QSpinBox( 0, 100, 1, groupBox );
+ QWhatsThis::add( m_locSpinBox, i18n( "The number of context lines is normally 2 or 3. This makes the diff readable and applicable in most cases. More than 3 lines will only bloat the diff unnecessarily." ) );
+ label->setBuddy( m_locSpinBox );
+
+ layout->addStretch( 1 );
+ page->setMinimumSize( sizeHintForWidget( page ) );
+
+ addTab( page, i18n( "&Format" ) );
+}
+
+void DiffPage::addOptionsTab()
+{
+ QWidget* page = new QWidget( this );
+ QVBoxLayout* layout = new QVBoxLayout( page );
+ layout->setSpacing( KDialog::spacingHint() );
+ layout->setMargin( KDialog::marginHint() );
+
+ // add diff options
+ QVButtonGroup* optionButtonGroup = new QVButtonGroup( i18n( "General" ), page );
+ layout->addWidget( optionButtonGroup );
+ optionButtonGroup->setMargin( KDialog::marginHint() );
+
+ m_smallerCheckBox = new QCheckBox( i18n( "&Look for smaller changes" ), optionButtonGroup );
+ QToolTip::add( m_smallerCheckBox, i18n( "This corresponds to the -d diff option." ) );
+ m_largerCheckBox = new QCheckBox( i18n( "O&ptimize for large files" ), optionButtonGroup );
+ QToolTip::add( m_largerCheckBox, i18n( "This corresponds to the -H diff option." ) );
+ m_caseCheckBox = new QCheckBox( i18n( "&Ignore changes in case" ), optionButtonGroup );
+ QToolTip::add( m_caseCheckBox, i18n( "This corresponds to the -i diff option." ) );
+
+ QHBoxLayout* groupLayout = new QHBoxLayout( layout, -1, "regexp_horizontal_layout" );
+ groupLayout->setMargin( KDialog::marginHint() );
+
+ m_ignoreRegExpCheckBox = new QCheckBox( i18n( "Ignore regexp:" ), page );
+ QToolTip::add( m_ignoreRegExpCheckBox, i18n( "This option corresponds to the -I diff option." ) );
+ groupLayout->addWidget( m_ignoreRegExpCheckBox );
+ m_ignoreRegExpEdit = new KLineEdit( QString::null, page, "regexplineedit" );
+ QToolTip::add( m_ignoreRegExpEdit, i18n( "Add the regular expression here that you want to use\nto ignore lines that match it." ) );
+ groupLayout->addWidget( m_ignoreRegExpEdit );
+
+ if ( !KTrader::self()->query("KRegExpEditor/KRegExpEditor").isEmpty() )
+ {
+ // Ok editor is available, use it
+ QButton* ignoreRegExpEditButton = new QPushButton( i18n( "&Edit..." ), page, "regexp_editor_button" );
+ QToolTip::add( ignoreRegExpEditButton, i18n( "Clicking this will open a regular expression dialog where\nyou can graphically create regular expressions." ) );
+ groupLayout->addWidget( ignoreRegExpEditButton );
+ connect( ignoreRegExpEditButton, SIGNAL( clicked() ), this, SLOT( slotShowRegExpEditor() ) );
+ }
+
+ QVButtonGroup* moreOptionButtonGroup = new QVButtonGroup( i18n( "Whitespace" ), page );
+ layout->addWidget( moreOptionButtonGroup );
+ moreOptionButtonGroup->setMargin( KDialog::marginHint() );
+
+ m_tabsCheckBox = new QCheckBox( i18n( "E&xpand tabs to spaces in output" ), moreOptionButtonGroup );
+ QToolTip::add( m_tabsCheckBox, i18n( "This option corresponds to the -t diff option." ) );
+ m_linesCheckBox = new QCheckBox( i18n( "I&gnore added or removed empty lines" ), moreOptionButtonGroup );
+ QToolTip::add( m_linesCheckBox, i18n( "This option corresponds to the -B diff option." ) );
+ m_whitespaceCheckBox = new QCheckBox( i18n( "Ig&nore changes in the amount of whitespace" ), moreOptionButtonGroup );
+ QToolTip::add( m_whitespaceCheckBox, i18n( "This option corresponds to the -b diff option." ) );
+ m_allWhitespaceCheckBox = new QCheckBox( i18n( "Ign&ore all whitespace" ), moreOptionButtonGroup );
+ QToolTip::add( m_allWhitespaceCheckBox, i18n( "This option corresponds to the -w diff option." ) );
+ m_ignoreTabExpansionCheckBox = new QCheckBox( i18n( "Igno&re changes due to tab expansion" ), moreOptionButtonGroup );
+ QToolTip::add( m_ignoreTabExpansionCheckBox, i18n( "This option corresponds to the -E diff option." ) );
+
+ layout->addStretch( 1 );
+ page->setMinimumSize( sizeHintForWidget( page ) );
+
+ addTab( page, i18n( "O&ptions" ) );
+}
+
+void DiffPage::addExcludeTab()
+{
+ QWidget* page = new QWidget( this );
+ QVBoxLayout* layout = new QVBoxLayout( page );
+ layout->setSpacing( KDialog::spacingHint() );
+ layout->setMargin( KDialog::marginHint() );
+
+ QHGroupBox* excludeFilePatternGroupBox = new QHGroupBox( i18n( "File Pattern to Exclude" ), page );
+ m_excludeFilePatternCheckBox = new QCheckBox( "", excludeFilePatternGroupBox );
+ QToolTip::add( m_excludeFilePatternCheckBox, i18n( "If this is checked you can enter a shell pattern in the text box on the right or select entries from the list." ) );
+ m_excludeFilePatternEditListBox = new KEditListBox( excludeFilePatternGroupBox, "exclude_file_pattern_editlistbox", false, KEditListBox::Add|KEditListBox::Remove );
+ QToolTip::add( m_excludeFilePatternEditListBox, i18n( "Here you can enter or remove a shell pattern or select one or more entries from the list." ) );
+ layout->addWidget( excludeFilePatternGroupBox );
+
+
+ connect( m_excludeFilePatternCheckBox, SIGNAL(toggled(bool)), this, SLOT(slotExcludeFilePatternToggled(bool)));
+
+ QHGroupBox* excludeFileNameGroupBox = new QHGroupBox( i18n( "File with Filenames to Exclude" ), page );
+ m_excludeFileCheckBox = new QCheckBox( "", excludeFileNameGroupBox );
+ QToolTip::add( m_excludeFileCheckBox, i18n( "If this is checked you can enter a filename in the combo box on the right." ) );
+ m_excludeFileURLComboBox = new KURLComboBox( KURLComboBox::Files, true, excludeFileNameGroupBox, "exclude_file_urlcombo" );
+ QToolTip::add( m_excludeFileURLComboBox, i18n( "Here you can enter the URL of a file with shell patterns to ignore during the comparison of the folders." ) );
+ m_excludeFileURLRequester = new KURLRequester( m_excludeFileURLComboBox, excludeFileNameGroupBox, "exclude_file_name_urlrequester" );
+ QToolTip::add( m_excludeFileURLRequester, i18n( "Any file you select in the dialog that pops up when you click it will be put in the dialog to the left of this button." ) );
+ layout->addWidget( excludeFileNameGroupBox );
+
+ connect( m_excludeFileCheckBox, SIGNAL(toggled(bool)), this, SLOT(slotExcludeFileToggled(bool)));
+
+ layout->addStretch( 1 );
+ page->setMinimumSize( sizeHintForWidget( page ) );
+
+ addTab( page, i18n( "&Exclude" ) );
+}
+
+#include "diffpage.moc"
diff --git a/kompare/libdialogpages/diffpage.h b/kompare/libdialogpages/diffpage.h
new file mode 100644
index 00000000..dee23989
--- /dev/null
+++ b/kompare/libdialogpages/diffpage.h
@@ -0,0 +1,100 @@
+/***************************************************************************
+ diffprefs.h - description
+ -------------------
+ begin : Sun Mar 4 2001
+ copyright : (C) 2001-2004 Otto Bruggeman
+ (C) 2001-2003 John Firebaugh
+ email : otto.bruggeman@home.nl
+ jfirebaugh@kde.org
+****************************************************************************/
+
+/***************************************************************************
+**
+** This program is free software; you can redistribute it and/or modify
+** it under the terms of the 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 DIFFPAGE_H
+#define DIFFPAGE_H
+
+#include "pagebase.h"
+
+class QCheckBox;
+class QDialog;
+class QSpinBox;
+class QStringList;
+class QVButtonGroup;
+class QWidget;
+
+class KLineEdit;
+class KComboBox;
+class KEditListBox;
+class KURLComboBox;
+class KURLRequester;
+
+class DiffSettings;
+
+class DiffPage : public PageBase
+{
+Q_OBJECT
+public:
+ DiffPage( QWidget* );
+ ~DiffPage();
+
+public:
+ void setSettings( DiffSettings* );
+ DiffSettings* settings( void );
+
+public:
+ virtual void restore();
+ virtual void apply();
+ virtual void setDefaults();
+
+protected slots:
+ void slotShowRegExpEditor();
+ void slotExcludeFilePatternToggled( bool );
+ void slotExcludeFileToggled( bool );
+
+private:
+ void addDiffTab();
+ void addFormatTab();
+ void addOptionsTab();
+ void addExcludeTab();
+
+public:
+ DiffSettings* m_settings;
+
+ KURLRequester* m_diffURLRequester;
+
+ QCheckBox* m_smallerCheckBox;
+ QCheckBox* m_largerCheckBox;
+ QCheckBox* m_tabsCheckBox;
+ QCheckBox* m_caseCheckBox;
+ QCheckBox* m_linesCheckBox;
+ QCheckBox* m_whitespaceCheckBox;
+ QCheckBox* m_allWhitespaceCheckBox;
+ QCheckBox* m_ignoreTabExpansionCheckBox;
+
+ QCheckBox* m_ignoreRegExpCheckBox;
+ KLineEdit* m_ignoreRegExpEdit;
+ QStringList* m_ignoreRegExpEditHistory;
+ QDialog* m_ignoreRegExpDialog;
+
+ QCheckBox* m_excludeFilePatternCheckBox;
+ KEditListBox* m_excludeFilePatternEditListBox;
+
+ QCheckBox* m_excludeFileCheckBox;
+ KURLComboBox* m_excludeFileURLComboBox;
+ KURLRequester* m_excludeFileURLRequester;
+
+ // loc == lines of context
+ QSpinBox* m_locSpinBox;
+
+ QVButtonGroup* m_modeButtonGroup;
+ QVButtonGroup* m_diffProgramGroup;
+};
+
+#endif
diff --git a/kompare/libdialogpages/diffsettings.cpp b/kompare/libdialogpages/diffsettings.cpp
new file mode 100644
index 00000000..20504ffe
--- /dev/null
+++ b/kompare/libdialogpages/diffsettings.cpp
@@ -0,0 +1,108 @@
+/***************************************************************************
+ diffsettings.cpp - description
+ -------------------
+ begin : Sun Mar 4 2001
+ copyright : (C) 2001-2004 Otto Bruggeman
+ email : otto.bruggeman@home.nl
+****************************************************************************/
+
+/***************************************************************************
+**
+** This program is free software; you can redistribute it and/or modify
+** it under the terms of the 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 <kconfig.h>
+
+#include "diffsettings.h"
+
+DiffSettings::DiffSettings( QWidget* parent )
+ : SettingsBase( parent ),
+ m_linesOfContext( 0 ),
+ m_format( Kompare::Unified ),
+ m_largeFiles( false ),
+ m_ignoreWhiteSpace( false ),
+ m_ignoreAllWhiteSpace( false ),
+ m_ignoreEmptyLines( false ),
+ m_ignoreChangesDueToTabExpansion( false ),
+ m_createSmallerDiff( false ),
+ m_ignoreChangesInCase( false ),
+ m_showCFunctionChange( false ),
+ m_convertTabsToSpaces( false ),
+ m_ignoreRegExp( false ),
+ m_recursive( false ),
+ m_newFiles( false ),
+ m_excludeFilePattern( false ),
+ m_excludeFilesFile( false )
+{
+}
+
+DiffSettings::~DiffSettings()
+{
+}
+
+void DiffSettings::loadSettings( KConfig* config )
+{
+ KConfigGroup group( config, "Diff Options" );
+ m_diffProgram = group.readEntry ( "DiffProgram", "" );
+ m_linesOfContext = group.readNumEntry ( "LinesOfContext", 3 );
+ m_largeFiles = group.readBoolEntry( "LargeFiles", true );
+ m_ignoreWhiteSpace = group.readBoolEntry( "IgnoreWhiteSpace", false );
+ m_ignoreAllWhiteSpace = group.readBoolEntry( "IgnoreAllWhiteSpace", false );
+ m_ignoreEmptyLines = group.readBoolEntry( "IgnoreEmptyLines", false );
+ m_ignoreChangesDueToTabExpansion = group.readBoolEntry( "IgnoreChangesDueToTabExpansion", false );
+ m_ignoreChangesInCase = group.readBoolEntry( "IgnoreChangesInCase", false );
+ m_ignoreRegExp = group.readBoolEntry( "IgnoreRegExp", false );
+ m_ignoreRegExpText = group.readEntry ( "IgnoreRegExpText", "" );
+ m_ignoreRegExpTextHistory = group.readListEntry( "IgnoreRegExpTextHistory" );
+ m_createSmallerDiff = group.readBoolEntry( "CreateSmallerDiff", true );
+ m_convertTabsToSpaces = group.readBoolEntry( "ConvertTabsToSpaces", false );
+ m_showCFunctionChange = group.readBoolEntry( "ShowCFunctionChange", false );
+ m_recursive = group.readBoolEntry( "CompareRecursively", true );
+ m_newFiles = group.readBoolEntry( "NewFiles", true );
+
+ m_format = static_cast<Kompare::Format>( group.readNumEntry( "Format", Kompare::Unified ) );
+
+ KConfigGroup group2 ( config, "Exclude File Options" );
+ m_excludeFilePattern = group2.readBoolEntry( "Pattern", false );
+ m_excludeFilePatternList = group2.readListEntry( "PatternList" );
+ m_excludeFilesFile = group2.readBoolEntry( "File", false );
+ m_excludeFilesFileURL = group2.readEntry ( "FileURL", "" );
+ m_excludeFilesFileHistoryList = group2.readListEntry( "FileHistoryList" );
+}
+
+void DiffSettings::saveSettings( KConfig* config )
+{
+ KConfigGroup group( config, "Diff Options" );
+ group.writeEntry( "DiffProgram", m_diffProgram );
+ group.writeEntry( "LinesOfContext", m_linesOfContext );
+ group.writeEntry( "Format", m_format );
+ group.writeEntry( "LargeFiles", m_largeFiles );
+ group.writeEntry( "IgnoreWhiteSpace", m_ignoreWhiteSpace );
+ group.writeEntry( "IgnoreAllWhiteSpace", m_ignoreAllWhiteSpace );
+ group.writeEntry( "IgnoreEmptyLines", m_ignoreEmptyLines );
+ group.writeEntry( "IgnoreChangesInCase", m_ignoreChangesInCase );
+ group.writeEntry( "IgnoreChangesDueToTabExpansion", m_ignoreChangesDueToTabExpansion );
+ group.writeEntry( "IgnoreRegExp", m_ignoreRegExp );
+ group.writeEntry( "IgnoreRegExpText", m_ignoreRegExpText );
+ group.writeEntry( "IgnoreRegExpTextHistory", m_ignoreRegExpTextHistory );
+ group.writeEntry( "CreateSmallerDiff", m_createSmallerDiff );
+ group.writeEntry( "ConvertTabsToSpaces", m_convertTabsToSpaces );
+ group.writeEntry( "ShowCFunctionChange", m_showCFunctionChange );
+ group.writeEntry( "CompareRecursively", m_recursive );
+ group.writeEntry( "NewFiles", m_newFiles );
+ group.setDirty( true );
+
+ KConfigGroup group2( config, "Exclude File Options" );
+ group2.writeEntry( "Pattern", m_excludeFilePattern );
+ group2.writeEntry( "PatternList", m_excludeFilePatternList );
+ group2.writeEntry( "File", m_excludeFilesFile );
+ group2.writeEntry( "FileURL", m_excludeFilesFileURL );
+ group2.writeEntry( "FileHistoryList", m_excludeFilesFileHistoryList );
+ group2.setDirty( true );
+}
+
+#include "diffsettings.moc"
diff --git a/kompare/libdialogpages/diffsettings.h b/kompare/libdialogpages/diffsettings.h
new file mode 100644
index 00000000..46962cb8
--- /dev/null
+++ b/kompare/libdialogpages/diffsettings.h
@@ -0,0 +1,66 @@
+/***************************************************************************
+ diffsettings.h - description
+ -------------------
+ begin : Sun Mar 4 2001
+ copyright : (C) 2001-2003 by Otto Bruggeman
+ and John Firebaugh
+ email : otto.bruggeman@home.nl
+ jfirebaugh@kde.org
+****************************************************************************/
+
+/***************************************************************************
+**
+** This program is free software; you can redistribute it and/or modify
+** it under the terms of the 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 DIFFSETTINGS_H
+#define DIFFSETTINGS_H
+
+#include <qstringlist.h>
+#include <qwidget.h>
+
+#include "kompare.h"
+#include "settingsbase.h"
+
+class DiffSettings : public SettingsBase
+{
+Q_OBJECT
+public:
+ DiffSettings( QWidget* parent );
+ virtual ~DiffSettings();
+public:
+ // some virtual functions that will be overloaded from the base class
+ virtual void loadSettings( KConfig* config );
+ virtual void saveSettings( KConfig* config );
+
+public:
+ QString m_diffProgram;
+ int m_linesOfContext;
+ Kompare::Format m_format;
+ bool m_largeFiles; // -H
+ bool m_ignoreWhiteSpace; // -b
+ bool m_ignoreAllWhiteSpace; // -w
+ bool m_ignoreEmptyLines; // -B
+ bool m_ignoreChangesDueToTabExpansion; // -E
+ bool m_createSmallerDiff; // -d
+ bool m_ignoreChangesInCase; // -i
+ bool m_showCFunctionChange; // -p
+ bool m_convertTabsToSpaces; // -t
+ bool m_ignoreRegExp; // -I
+ QString m_ignoreRegExpText; // the RE for -I
+ QStringList m_ignoreRegExpTextHistory;
+ bool m_recursive; // -r
+ bool m_newFiles; // -N
+// bool m_allText; // -a
+ bool m_excludeFilePattern; // -x
+ QStringList m_excludeFilePatternList; // The list of patterns for -x
+ bool m_excludeFilesFile; // -X
+ QString m_excludeFilesFileURL; // The filename to -X
+ QStringList m_excludeFilesFileHistoryList; // The history list of filenames
+};
+
+#endif
diff --git a/kompare/libdialogpages/filespage.cpp b/kompare/libdialogpages/filespage.cpp
new file mode 100644
index 00000000..9e15a129
--- /dev/null
+++ b/kompare/libdialogpages/filespage.cpp
@@ -0,0 +1,170 @@
+/***************************************************************************
+ filespage.cpp
+ -------------------
+ begin : Sun Apr 18 2004
+ copyright : (C) 2004 Otto Bruggeman
+ email : otto.bruggeman@home.nl
+
+****************************************************************************/
+
+/***************************************************************************
+**
+** This program is free software; you can redistribute it and/or modify
+** it under the terms of the 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 <qlayout.h>
+#include <qgroupbox.h>
+
+#include <kapplication.h>
+#include <kcharsets.h>
+#include <kconfig.h>
+#include <kdebug.h>
+#include <kdialog.h>
+#include <klocale.h>
+#include <kurlcombobox.h>
+#include <kurlrequester.h>
+
+#include "filessettings.h"
+#include "filespage.h"
+
+FilesPage::FilesPage( QWidget* parent ) : PageBase( parent ), m_URLChanged( false )
+{
+ QWidget* page = new QWidget( this );
+ QVBoxLayout* layout = new QVBoxLayout( page );
+ layout->setSpacing( KDialog::spacingHint() );
+ layout->setMargin( KDialog::marginHint() );
+
+ m_firstGB = new QGroupBox( 1, Qt::Vertical, "You have to set this moron :)", page );
+ m_firstURLComboBox = new KURLComboBox( KURLComboBox::Both, true, m_firstGB, "SourceURLComboBox" );
+ m_firstURLRequester = new KURLRequester( m_firstURLComboBox, m_firstGB );
+ m_firstURLRequester->setFocus();
+
+ m_secondGB = new QGroupBox( 1, Qt::Vertical, "This too moron !", page );
+ m_secondURLComboBox = new KURLComboBox( KURLComboBox::Both, true, m_secondGB, "DestURLComboBox" );
+ m_secondURLRequester = new KURLRequester( m_secondURLComboBox, m_secondGB );
+
+ connect( m_firstURLRequester, SIGNAL( urlSelected( const QString & ) ), SLOT( setSecondURL( const QString & ) ) );
+ connect( m_secondURLRequester, SIGNAL( urlSelected( const QString & ) ), SLOT( setFirstURL( const QString & ) ) );
+
+ m_thirdGB = new QGroupBox( 1, Qt::Vertical, i18n( "Encoding" ), page );
+ m_encodingComboBox = new QComboBox( false, m_thirdGB, "encoding_combobox" );
+ m_encodingComboBox->insertStringList( KGlobal::charsets()->availableEncodingNames() );
+
+ layout->addWidget( m_firstGB );
+ layout->addWidget( m_secondGB );
+ layout->addWidget( m_thirdGB );
+
+ layout->addStretch( 1 );
+ page->setMinimumSize( sizeHintForWidget( page ) );
+
+ addTab( page, i18n( "&Files" ) );
+}
+
+FilesPage::~FilesPage()
+{
+ m_settings = 0;
+}
+
+KURLRequester* FilesPage::firstURLRequester() const
+{
+ return m_firstURLRequester;
+}
+
+KURLRequester* FilesPage::secondURLRequester() const
+{
+ return m_secondURLRequester;
+}
+
+QString FilesPage::encoding() const
+{
+ return m_encodingComboBox->currentText();
+}
+
+void FilesPage::setFirstGroupBoxTitle( const QString& title )
+{
+ m_firstGB->setTitle( title );
+}
+
+void FilesPage::setSecondGroupBoxTitle( const QString& title )
+{
+ m_secondGB->setTitle( title );
+}
+
+void FilesPage::setURLsInComboBoxes()
+{
+// kdDebug() << "first : " << m_firstURLComboBox->currentText() << endl;
+// kdDebug() << "second: " << m_secondURLComboBox->currentText() << endl;
+ m_firstURLComboBox->setURL( KURL( m_firstURLComboBox->currentText() ) );
+ m_secondURLComboBox->setURL( KURL( m_secondURLComboBox->currentText() ) );
+}
+
+
+void FilesPage::setFirstURLRequesterMode( unsigned int mode )
+{
+ m_firstURLRequester->setMode( mode );
+}
+
+void FilesPage::setSecondURLRequesterMode( unsigned int mode )
+{
+ m_secondURLRequester->setMode( mode );
+}
+
+void FilesPage::setSettings( FilesSettings* settings )
+{
+ m_settings = settings;
+
+ m_firstURLComboBox->setURLs( m_settings->m_recentSources );
+ m_firstURLComboBox->setURL( KURL( m_settings->m_lastChosenSourceURL ) );
+ m_secondURLComboBox->setURLs( m_settings->m_recentDestinations );
+ m_secondURLComboBox->setURL( KURL( m_settings->m_lastChosenDestinationURL ) );
+ m_encodingComboBox->setCurrentText( m_settings->m_encoding );
+}
+
+void FilesPage::restore()
+{
+ // this shouldn't do a thing...
+}
+
+void FilesPage::apply()
+{
+ m_settings->m_recentSources = m_firstURLComboBox->urls();
+ m_settings->m_lastChosenSourceURL = m_firstURLComboBox->currentText();
+ m_settings->m_recentDestinations = m_secondURLComboBox->urls();
+ m_settings->m_lastChosenDestinationURL = m_secondURLComboBox->currentText();
+ m_settings->m_encoding = m_encodingComboBox->currentText();
+}
+
+void FilesPage::setDefaults()
+{
+ m_firstURLComboBox->setURLs( "" );
+ m_firstURLComboBox->setURL( KURL( "" ) );
+ m_secondURLComboBox->setURLs( "" );
+ m_secondURLComboBox->setURL( KURL( "" ) );
+ m_encodingComboBox->setCurrentText( "Default" );
+}
+
+void FilesPage::setFirstURL( const QString &url )
+{
+ QString _url = url;
+ if ( !m_URLChanged )
+ {
+ m_firstURLRequester->setURL( _url.remove( url.section( '/', -1 ) ) );
+ m_URLChanged = true;
+ }
+}
+
+void FilesPage::setSecondURL( const QString &url )
+{
+ QString _url = url;
+ if ( !m_URLChanged )
+ {
+ m_secondURLRequester->setURL( _url.remove( url.section( '/', -1 ) ) );
+ m_URLChanged = true;
+ }
+}
+
+#include "filespage.moc"
diff --git a/kompare/libdialogpages/filespage.h b/kompare/libdialogpages/filespage.h
new file mode 100644
index 00000000..145c4614
--- /dev/null
+++ b/kompare/libdialogpages/filespage.h
@@ -0,0 +1,83 @@
+/***************************************************************************
+ kcompareurldialog.h - description
+ -------------------
+ begin : Sun Mar 4 2001
+ copyright : (C) 2001-2004 Otto Bruggeman
+ (C) 2001-2003 John Firebaugh
+ email : otto.bruggeman@home.nl
+ jfirebaugh@kde.org
+****************************************************************************/
+
+/***************************************************************************
+**
+** This program is free software; you can redistribute it and/or modify
+** it under the terms of the 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 FILESPAGE_H
+#define FILESPAGE_H
+
+#include "pagebase.h"
+
+class QGroupBox;
+
+class QComboBox;
+class KComboBox;
+class KConfig;
+class KFileDialog;
+class KURLComboBox;
+class KURLRequester;
+
+class FilesSettings;
+
+class FilesPage : PageBase
+{
+Q_OBJECT
+public:
+ FilesPage( QWidget* parent );
+ virtual ~FilesPage();
+
+public:
+ KURLRequester* firstURLRequester() const;
+ KURLRequester* secondURLRequester() const;
+
+ QString encoding() const;
+
+ void setFirstGroupBoxTitle ( const QString& title );
+ void setSecondGroupBoxTitle( const QString& title );
+
+ void setURLsInComboBoxes();
+
+ void setFirstURLRequesterMode( unsigned int mode );
+ void setSecondURLRequesterMode( unsigned int mode );
+
+public:
+ virtual void setSettings( FilesSettings* settings );
+ virtual void restore();
+ virtual void apply();
+ virtual void setDefaults();
+
+protected slots:
+ void setFirstURL( const QString & );
+ void setSecondURL( const QString & );
+
+private:
+ QGroupBox* m_firstGB;
+ QGroupBox* m_secondGB;
+ QGroupBox* m_thirdGB;
+ KURLComboBox* m_firstURLComboBox;
+ KURLComboBox* m_secondURLComboBox;
+ KURLRequester* m_firstURLRequester;
+ KURLRequester* m_secondURLRequester;
+ // Use this bool to lock the connection between both KURLRequesters.
+ // This prevents annoying behaviour
+ bool m_URLChanged;
+ QComboBox* m_encodingComboBox;
+
+ FilesSettings* m_settings;
+};
+
+#endif
diff --git a/kompare/libdialogpages/filessettings.cpp b/kompare/libdialogpages/filessettings.cpp
new file mode 100644
index 00000000..d5a94a66
--- /dev/null
+++ b/kompare/libdialogpages/filessettings.cpp
@@ -0,0 +1,60 @@
+/***************************************************************************
+ filessettings.cpp - description
+ -------------------
+ begin : Sun Apr 18 2004
+ copyright : (C) 2004 Otto Bruggeman
+ email : otto.bruggeman@home.nl
+
+****************************************************************************/
+
+/***************************************************************************
+**
+** This program is free software; you can redistribute it and/or modify
+** it under the terms of the 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 <kapplication.h>
+#include <kconfig.h>
+
+#include "filessettings.h"
+
+FilesSettings::FilesSettings( QWidget* parent )
+ : SettingsBase( parent )
+{
+}
+
+FilesSettings::~FilesSettings()
+{
+}
+
+void FilesSettings::loadSettings( KConfig* config )
+{
+ config->setGroup( m_configGroupName );
+
+ m_recentSources = config->readListEntry( "Recent Sources" );
+ m_lastChosenSourceURL = config->readEntry ( "LastChosenSourceListEntry", "" );
+ m_recentDestinations = config->readListEntry( "Recent Destinations" );
+ m_lastChosenDestinationURL = config->readEntry ( "LastChosenDestinationListEntry", "" );
+ m_encoding = config->readEntry ( "Encoding", "default" );
+}
+
+void FilesSettings::saveSettings( KConfig* config )
+{
+ config->setGroup( m_configGroupName );
+ config->writeEntry( "Recent Sources", m_recentSources );
+ config->writeEntry( "Recent Destinations", m_recentDestinations );
+ config->writeEntry( "LastChosenSourceListEntry", m_lastChosenSourceURL );
+ config->writeEntry( "LastChosenDestinationListEntry", m_lastChosenDestinationURL );
+ config->writeEntry( "Encoding", m_encoding );
+ config->sync();
+}
+
+void FilesSettings::setGroup( const QString& groupName )
+{
+ m_configGroupName = groupName;
+}
+
+#include "filessettings.moc"
diff --git a/kompare/libdialogpages/filessettings.h b/kompare/libdialogpages/filessettings.h
new file mode 100644
index 00000000..3c394dbb
--- /dev/null
+++ b/kompare/libdialogpages/filessettings.h
@@ -0,0 +1,53 @@
+/***************************************************************************
+ filessettings.h - description
+ -------------------
+ begin : Sun Apr 18 2004
+ copyright : (C) 2004 Otto Bruggeman
+ email : otto.bruggeman@home.nl
+
+****************************************************************************/
+
+/***************************************************************************
+**
+** This program is free software; you can redistribute it and/or modify
+** it under the terms of the 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 FILESSETTINGS_H
+#define FILESSETTINGS_H
+
+#include <qstring.h>
+
+#include "settingsbase.h"
+
+class KConfig;
+
+class FilesSettings : public SettingsBase
+{
+Q_OBJECT
+public:
+ FilesSettings( QWidget* parent );
+ virtual ~FilesSettings();
+
+public:
+ // some virtual functions that will be overloaded from the base class
+ virtual void loadSettings( KConfig* config );
+ virtual void saveSettings( KConfig* config );
+
+ void setGroup( const QString& groupName );
+
+public:
+ QString m_configGroupName;
+
+ QStringList m_recentSources;
+ QString m_lastChosenSourceURL;
+ QStringList m_recentDestinations;
+ QString m_lastChosenDestinationURL;
+ QString m_encoding;
+};
+
+#endif // FILESSETTINGS_H
+
diff --git a/kompare/libdialogpages/pagebase.cpp b/kompare/libdialogpages/pagebase.cpp
new file mode 100644
index 00000000..de062634
--- /dev/null
+++ b/kompare/libdialogpages/pagebase.cpp
@@ -0,0 +1,104 @@
+/***************************************************************************
+ prefsbase.cpp - description
+ -------------------
+ begin : Sun Mar 4 2001
+ copyright : (C) 2001 by Otto Bruggeman
+ and John Firebaugh
+ email : otto.bruggeman@home.nl
+ jfirebaugh@kde.org
+****************************************************************************/
+
+/***************************************************************************
+**
+** This program is free software; you can redistribute it and/or modify
+** it under the terms of the 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 <qlayout.h>
+#include <qobjectlist.h>
+
+#include "pagebase.h"
+
+PageBase::PageBase( QWidget* parent ) : KTabCtl( parent )
+{
+
+}
+
+PageBase::~PageBase()
+{
+
+}
+
+/** No descriptions */
+QSize PageBase::sizeHintForWidget( QWidget* widget )
+{
+ //
+ // The size is computed by adding the sizeHint().height() of all
+ // widget children and taking the width of the widest child and adding
+ // layout()->margin() and layout()->spacing()
+ //
+
+ // this code in this method has been ripped out of a file in kbabel
+ // so copyright goes to the kbabel authors.
+
+ QSize size;
+
+ int numChild = 0;
+ QObjectList *l = (QObjectList*)(widget->children());
+
+ for( uint i=0; i < l->count(); i++ )
+ {
+ QObject *o = l->at(i);
+ if( o->isWidgetType() )
+ {
+ numChild += 1;
+ QWidget *w=((QWidget*)o);
+
+ QSize s = w->sizeHint();
+ if( s.isEmpty() == true )
+ {
+ s = QSize( 50, 100 ); // Default size
+ }
+ size.setHeight( size.height() + s.height() );
+ if( s.width() > size.width() )
+ {
+ size.setWidth( s.width() );
+ }
+ }
+ }
+
+ if( numChild > 0 )
+ {
+ size.setHeight( size.height() + widget->layout()->spacing()*(numChild-1) );
+ size += QSize( widget->layout()->margin()*2, widget->layout()->margin()*2 + 1 );
+ }
+ else
+ {
+ size = QSize( 1, 1 );
+ }
+
+ return( size );
+}
+
+/** No descriptions */
+void PageBase::apply()
+{
+
+}
+
+/** No descriptions */
+void PageBase::restore()
+{
+
+}
+
+/** No descriptions */
+void PageBase::setDefaults()
+{
+
+}
+
+#include "pagebase.moc"
diff --git a/kompare/libdialogpages/pagebase.h b/kompare/libdialogpages/pagebase.h
new file mode 100644
index 00000000..7aab7b81
--- /dev/null
+++ b/kompare/libdialogpages/pagebase.h
@@ -0,0 +1,49 @@
+/***************************************************************************
+ prefsbase.h - description
+ -------------------
+ begin : Sun Mar 4 2001
+ copyright : (C) 2001 by Otto Bruggeman
+ and John Firebaugh
+ email : otto.bruggeman@home.nl
+ jfirebaugh@kde.org
+****************************************************************************/
+
+/***************************************************************************
+**
+** This program is free software; you can redistribute it and/or modify
+** it under the terms of the 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 PAGEBASE_H
+#define PAGEBASE_H
+
+#include <qsize.h>
+#include <qwidget.h>
+
+#include <kconfig.h>
+#include <ktabctl.h>
+
+#include "kompare.h"
+
+class PageBase : public KTabCtl
+{
+Q_OBJECT
+public:
+ PageBase( QWidget* );
+ ~PageBase();
+
+public:
+ /** No descriptions */
+ QSize sizeHintForWidget( QWidget* widget );
+ /** No descriptions */
+ virtual void restore();
+ /** No descriptions */
+ virtual void apply();
+ /** No descriptions */
+ virtual void setDefaults();
+};
+
+#endif
diff --git a/kompare/libdialogpages/settingsbase.cpp b/kompare/libdialogpages/settingsbase.cpp
new file mode 100644
index 00000000..dc7b64d6
--- /dev/null
+++ b/kompare/libdialogpages/settingsbase.cpp
@@ -0,0 +1,42 @@
+/***************************************************************************
+ settingsbase.cpp - description
+ -------------------
+ begin : Sun Mar 4 2001
+ copyright : (C) 2001 by Otto Bruggeman
+ and John Firebaugh
+ email : otto.bruggeman@home.nl
+ jfirebaugh@kde.org
+****************************************************************************/
+
+/***************************************************************************
+**
+** This program is free software; you can redistribute it and/or modify
+** it under the terms of the 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 <qwidget.h>
+
+#include "settingsbase.h"
+
+SettingsBase::SettingsBase( QWidget* parent ) : QObject( parent )
+{
+
+}
+
+SettingsBase::~SettingsBase()
+{
+
+}
+
+void SettingsBase::loadSettings( KConfig* /* config */ )
+{
+}
+
+void SettingsBase::saveSettings( KConfig* /* config */ )
+{
+}
+
+#include "settingsbase.moc"
diff --git a/kompare/libdialogpages/settingsbase.h b/kompare/libdialogpages/settingsbase.h
new file mode 100644
index 00000000..5ec035ba
--- /dev/null
+++ b/kompare/libdialogpages/settingsbase.h
@@ -0,0 +1,42 @@
+/***************************************************************************
+ settingsbase.h - description
+ -------------------
+ begin : Sun Mar 4 2001
+ copyright : (C) 2001 by Otto Bruggeman
+ and John Firebaugh
+ email : otto.bruggeman@home.nl
+ jfirebaugh@kde.org
+****************************************************************************/
+
+/***************************************************************************
+**
+** This program is free software; you can redistribute it and/or modify
+** it under the terms of the 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 SETTINGSBASE_H
+#define SETTINGSBASE_H
+
+#include <qobject.h>
+
+#include "kompare.h"
+
+class QWidget;
+class KConfig;
+
+class SettingsBase : public QObject
+{
+Q_OBJECT
+public:
+ SettingsBase( QWidget* parent );
+ ~SettingsBase();
+
+public:
+ virtual void loadSettings( KConfig* config );
+ virtual void saveSettings( KConfig* config );
+};
+
+#endif
diff --git a/kompare/libdialogpages/viewpage.cpp b/kompare/libdialogpages/viewpage.cpp
new file mode 100644
index 00000000..c4e61e8d
--- /dev/null
+++ b/kompare/libdialogpages/viewpage.cpp
@@ -0,0 +1,179 @@
+/***************************************************************************
+ viewprefs.cpp - description
+ -------------------
+ begin : Sun Mar 4 2001
+ copyright : (C) 2001-2002 by Otto Bruggeman
+ and John Firebaugh
+ email : otto.bruggeman@home.nl
+ jfirebaugh@kde.org
+****************************************************************************/
+
+/***************************************************************************
+**
+** This program is free software; you can redistribute it and/or modify
+** it under the terms of the 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 <qcheckbox.h>
+#include <qgroupbox.h>
+#include <qhgroupbox.h>
+#include <qlabel.h>
+#include <qlayout.h>
+#include <qspinbox.h>
+
+#include <kapplication.h>
+#include <kcolorbutton.h>
+#include <kdialog.h>
+#include <kfontcombo.h>
+#include <klocale.h>
+
+#include "viewpage.h"
+#include "viewsettings.h"
+
+ViewPage::ViewPage( QWidget* parent ) : PageBase( parent )
+{
+ QWidget* page;
+ QVBoxLayout* layout;
+ QGroupBox* colorGroupBox;
+ QHGroupBox* snolGroupBox;
+ QHGroupBox* tabGroupBox;
+ QLabel* label;
+
+ page = new QWidget( this );
+ layout = new QVBoxLayout( page );
+ layout->setSpacing( KDialog::spacingHint() );
+ layout->setMargin( KDialog::marginHint() );
+
+ // add a groupbox
+ colorGroupBox = new QGroupBox( 2, Qt::Horizontal, i18n( "Colors" ), page );
+ layout->addWidget( colorGroupBox );
+ colorGroupBox->setMargin( KDialog::marginHint() );
+
+ // add the removeColor
+ label = new QLabel( i18n( "Removed color:" ), colorGroupBox );
+ m_removedColorButton = new KColorButton( colorGroupBox );
+ label->setBuddy( m_removedColorButton );
+
+ // add the changeColor
+ label = new QLabel( i18n( "Changed color:" ), colorGroupBox );
+ m_changedColorButton = new KColorButton( colorGroupBox );
+ label->setBuddy( m_changedColorButton );
+
+ // add the addColor
+ label = new QLabel( i18n( "Added color:" ), colorGroupBox );
+ m_addedColorButton = new KColorButton( colorGroupBox );
+ label->setBuddy( m_addedColorButton );
+
+ // add the appliedColor
+ label = new QLabel( i18n( "Applied color:" ), colorGroupBox );
+ m_appliedColorButton = new KColorButton( colorGroupBox );
+ label->setBuddy( m_appliedColorButton );
+
+ // scroll number of lines (snol)
+ snolGroupBox = new QHGroupBox( i18n( "Mouse Wheel" ), page );
+ layout->addWidget( snolGroupBox );
+ snolGroupBox->setMargin( KDialog::marginHint() );
+
+ label = new QLabel( i18n( "Number of lines:" ), snolGroupBox );
+ m_snolSpinBox = new QSpinBox( 0, 50, 1, snolGroupBox );
+ label->setBuddy( m_snolSpinBox );
+
+ // Temporarily here for testing...
+ // number of spaces for a tab character stuff
+ tabGroupBox = new QHGroupBox( i18n( "Tabs to Spaces" ), page );
+ layout->addWidget( tabGroupBox );
+ tabGroupBox->setMargin( KDialog::marginHint() );
+
+ label = new QLabel( i18n( "Number of spaces to convert a tab character to:" ), tabGroupBox );
+ m_tabSpinBox = new QSpinBox( 1, 16, 1, tabGroupBox );
+ label->setBuddy( m_tabSpinBox );
+
+ layout->addStretch( 1 );
+ page->setMinimumSize( sizeHintForWidget( page ) );
+
+ addTab( page, i18n( "A&ppearance" ) );
+
+ page = new QWidget( this );
+ layout = new QVBoxLayout( page );
+ layout->setSpacing( KDialog::spacingHint() );
+ layout->setMargin( KDialog::marginHint() );
+
+ QHGroupBox* gb = new QHGroupBox( i18n( "Text Font" ), page );
+ layout->addWidget( gb );
+ gb->setMargin( KDialog::marginHint() );
+
+ label = new QLabel( i18n( "Font:" ), gb );
+ m_fontCombo = new KFontCombo( gb, "fontcombo" );
+ label->setBuddy( m_fontCombo );
+
+ label = new QLabel( i18n( "Size:" ), gb );
+ m_fontSizeSpinBox = new QSpinBox( 6, 24, 1, gb, "fontsize" );
+ label->setBuddy( m_fontSizeSpinBox );
+
+ layout->addStretch( 1 );
+ page->setMinimumSize( sizeHintForWidget( page ) );
+
+ addTab( page, i18n( "&Fonts" ) );
+}
+
+ViewPage::~ViewPage()
+{
+
+}
+
+void ViewPage::setSettings( ViewSettings* setts )
+{
+ m_settings = setts;
+
+ m_addedColorButton->setColor ( m_settings->m_addColor );
+ m_changedColorButton->setColor( m_settings->m_changeColor );
+ m_removedColorButton->setColor( m_settings->m_removeColor );
+ m_appliedColorButton->setColor( m_settings->m_appliedColor );
+ m_snolSpinBox->setValue ( m_settings->m_scrollNoOfLines );
+ m_tabSpinBox->setValue ( m_settings->m_tabToNumberOfSpaces );
+
+ m_fontCombo->setCurrentFont ( m_settings->m_font.family() );
+ m_fontSizeSpinBox->setValue ( m_settings->m_font.pointSize() );
+}
+
+ViewSettings* ViewPage::settings( void )
+{
+ return m_settings;
+}
+
+void ViewPage::restore()
+{
+}
+
+void ViewPage::apply()
+{
+ m_settings->m_addColor = m_addedColorButton->color();
+ m_settings->m_changeColor = m_changedColorButton->color();
+ m_settings->m_removeColor = m_removedColorButton->color();
+ m_settings->m_appliedColor = m_appliedColorButton->color();
+ m_settings->m_scrollNoOfLines = m_snolSpinBox->value();
+ m_settings->m_tabToNumberOfSpaces = m_tabSpinBox->value();
+
+ m_settings->m_font = QFont( m_fontCombo->currentFont() );
+ m_settings->m_font.setPointSize( m_fontSizeSpinBox->value() );
+
+ m_settings->saveSettings( kapp->config() );
+}
+
+void ViewPage::setDefaults()
+{
+ m_addedColorButton->setColor ( ViewSettings::default_addColor );
+ m_changedColorButton->setColor( ViewSettings::default_changeColor );
+ m_removedColorButton->setColor( ViewSettings::default_removeColor );
+ m_appliedColorButton->setColor( ViewSettings::default_appliedColor );
+ m_snolSpinBox->setValue ( 3 );
+ m_tabSpinBox->setValue ( 4 );
+
+ m_fontCombo->setCurrentFont ( KGlobalSettings::fixedFont().family() );
+ m_fontSizeSpinBox->setValue ( 10 );
+}
+
+#include "viewpage.moc"
diff --git a/kompare/libdialogpages/viewpage.h b/kompare/libdialogpages/viewpage.h
new file mode 100644
index 00000000..30591f4b
--- /dev/null
+++ b/kompare/libdialogpages/viewpage.h
@@ -0,0 +1,64 @@
+/***************************************************************************
+ generalprefs.h - description
+ -------------------
+ begin : Sun Mar 4 2001
+ copyright : (C) 2001-2003 by Otto Bruggeman
+ and John Firebaugh
+ email : otto.bruggeman@home.nl
+ jfirebaugh@kde.org
+****************************************************************************/
+
+/***************************************************************************
+**
+** This program is free software; you can redistribute it and/or modify
+** it under the terms of the 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 VIEWPAGE_H
+#define VIEWPAGE_H
+
+#include "pagebase.h"
+
+class QCheckBox;
+class QSpinBox;
+
+class KColorButton;
+class KFontCombo;
+
+class ViewSettings;
+
+class ViewPage : public PageBase
+{
+Q_OBJECT
+public:
+ ViewPage( QWidget* );
+ ~ViewPage();
+
+public:
+ void setSettings( ViewSettings* );
+ ViewSettings* settings( void );
+
+public:
+ ViewSettings* m_settings;
+
+public:
+ virtual void restore();
+ virtual void apply();
+ virtual void setDefaults();
+
+public:
+ KColorButton* m_removedColorButton;
+ KColorButton* m_changedColorButton;
+ KColorButton* m_addedColorButton;
+ KColorButton* m_appliedColorButton;
+ // snol == scroll number of lines
+ QSpinBox* m_snolSpinBox;
+ QSpinBox* m_tabSpinBox;
+ KFontCombo* m_fontCombo;
+ QSpinBox* m_fontSizeSpinBox;
+};
+
+#endif
diff --git a/kompare/libdialogpages/viewsettings.cpp b/kompare/libdialogpages/viewsettings.cpp
new file mode 100644
index 00000000..c55dd40e
--- /dev/null
+++ b/kompare/libdialogpages/viewsettings.cpp
@@ -0,0 +1,101 @@
+/***************************************************************************
+ generalsettings.cpp - description
+ -------------------
+ begin : Sun Mar 4 2001
+ copyright : (C) 2001-2003 by Otto Bruggeman
+ and John Firebaugh
+ email : otto.bruggeman@home.nl
+ jfirebaugh@kde.org
+****************************************************************************/
+
+/***************************************************************************
+**
+** This program is free software; you can redistribute it and/or modify
+** it under the terms of the 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 <qfont.h>
+
+#include <kconfig.h>
+#include <kglobalsettings.h>
+
+#include "viewsettings.h"
+
+using namespace Diff2;
+
+const QColor ViewSettings::default_removeColor (190, 237, 190);
+const QColor ViewSettings::default_changeColor (237, 190, 190);
+const QColor ViewSettings::default_addColor (190, 190, 237);
+const QColor ViewSettings::default_appliedColor(237, 237, 190);
+
+ViewSettings::ViewSettings( QWidget* parent )
+ : SettingsBase( parent ),
+ m_removeColor( 0, 0, 0 ),
+ m_changeColor( 0, 0, 0),
+ m_addColor( 0, 0, 0),
+ m_appliedColor( 0, 0, 0),
+ m_scrollNoOfLines( 0 ),
+ m_tabToNumberOfSpaces( 0 )
+{
+}
+
+ViewSettings::~ViewSettings()
+{
+}
+
+void ViewSettings::loadSettings( KConfig* config )
+{
+ KConfigGroup cfg( config, "View Options" );
+ m_removeColor = cfg.readColorEntry( "RemoveColor", &default_removeColor );
+ m_changeColor = cfg.readColorEntry( "ChangeColor", &default_changeColor );
+ m_addColor = cfg.readColorEntry( "AddColor", &default_addColor );
+ m_appliedColor = cfg.readColorEntry( "AppliedColor", &default_appliedColor );
+ m_scrollNoOfLines = cfg.readNumEntry ( "ScrollNoOfLines", 3 );
+ m_tabToNumberOfSpaces = cfg.readNumEntry ( "TabToNumberOfSpaces", 4 );
+
+ QFont stdFixed = KGlobalSettings::fixedFont();
+ stdFixed.setPointSize( 10 );
+ m_font = cfg.readFontEntry ( "TextFont", &stdFixed );
+}
+
+void ViewSettings::saveSettings( KConfig* config )
+{
+ KConfigGroup cfg( config, "View Options" );
+ cfg.writeEntry( "RemoveColor", m_removeColor );
+ cfg.writeEntry( "ChangeColor", m_changeColor );
+ cfg.writeEntry( "AddColor", m_addColor );
+ cfg.writeEntry( "AppliedColor", m_appliedColor );
+ cfg.writeEntry( "ScrollNoOfLines", m_scrollNoOfLines );
+ cfg.writeEntry( "TabToNumberOfSpaces", m_tabToNumberOfSpaces );
+
+ cfg.writeEntry( "TextFont", m_font );
+}
+
+QColor ViewSettings::colorForDifferenceType( int type, bool selected, bool applied )
+{
+ // FIXME: does not belong here
+ QColor color;
+ if( applied )
+ color = m_appliedColor;
+ else
+ {
+ type = type & 0xFFFFFFEF; // remove the AppliedByBlend
+ switch( type ) {
+ case Difference::Unchanged: color = white; break;
+ case Difference::Change: color = m_changeColor; break;
+ case Difference::Insert: color = m_addColor; break;
+ case Difference::Delete: color = m_removeColor; break;
+ default: break;
+ }
+ }
+
+ if( selected )
+ color = color.light( 110 );
+
+ return color;
+}
+
+#include "viewsettings.moc"
diff --git a/kompare/libdialogpages/viewsettings.h b/kompare/libdialogpages/viewsettings.h
new file mode 100644
index 00000000..ab0f4d5f
--- /dev/null
+++ b/kompare/libdialogpages/viewsettings.h
@@ -0,0 +1,61 @@
+/***************************************************************************
+ generalsettings.h - description
+ -------------------
+ begin : Sun Mar 4 2001
+ copyright : (C) 2001-2003 by Otto Bruggeman
+ and John Firebaugh
+ email : otto.bruggeman@home.nl
+ jfirebaugh@kde.org
+****************************************************************************/
+
+/***************************************************************************
+**
+** This program is free software; you can redistribute it and/or modify
+** it under the terms of the 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 VIEWSETTINGS_H
+#define VIEWSETTINGS_H
+
+#include <qcolor.h>
+#include <qwidget.h>
+
+#include "difference.h"
+#include "settingsbase.h"
+
+class ViewSettings : public SettingsBase
+{
+Q_OBJECT
+public:
+ static const QColor default_removeColor;
+ static const QColor default_changeColor;
+ static const QColor default_addColor;
+ static const QColor default_appliedColor;
+
+ ViewSettings( QWidget* parent );
+ ~ViewSettings();
+public:
+ // some virtual functions that will be overloaded from the base class
+ virtual void loadSettings( KConfig* config );
+ virtual void saveSettings( KConfig* config );
+ QColor colorForDifferenceType( int type, bool selected = false, bool applied = false );
+
+public:
+ QColor m_removeColor;
+ QColor m_changeColor;
+ QColor m_addColor;
+ QColor m_appliedColor;
+ QColor m_selectedRemoveColor;
+ QColor m_selectedChangeColor;
+ QColor m_selectedAddColor;
+ QColor m_selectedAppliedColor;
+ int m_scrollNoOfLines;
+ int m_tabToNumberOfSpaces;
+
+ QFont m_font;
+};
+
+#endif // VIEWSETTINGS_H
diff --git a/kompare/libdiff2/Makefile.am b/kompare/libdiff2/Makefile.am
new file mode 100644
index 00000000..6f9048d8
--- /dev/null
+++ b/kompare/libdiff2/Makefile.am
@@ -0,0 +1,37 @@
+INCLUDES = \
+ -I$(top_srcdir)/kompare/libdialogpages \
+ -I$(top_srcdir)/kompare/komparepart \
+ -I$(top_srcdir)/kompare/interfaces $(all_includes)
+
+noinst_HEADERS = \
+ levenshteintable.h \
+ kompare.h \
+ kompareprocess.h \
+ komparemodellist.h \
+ diffmodel.h \
+ difference.h \
+ diffhunk.h
+
+# let automoc handle all of the meta source files (moc)
+METASOURCES = AUTO
+
+noinst_LTLIBRARIES = libdiff2.la
+
+# the Part's source, library search path, and link libraries
+libdiff2_la_SOURCES = \
+ kompareprocess.cpp \
+ komparemodellist.cpp \
+ diffmodellist.cpp \
+ diffmodel.cpp \
+ difference.cpp \
+ diffhunk.cpp \
+ levenshteintable.cpp \
+ parser.cpp \
+ parserbase.cpp \
+ cvsdiffparser.cpp \
+ diffparser.cpp \
+ perforceparser.cpp
+
+libdiff2_la_LDFLAGS = $(all_libraries)
+libdiff2_la_LIBADD = $(LIB_KFILE)
+
diff --git a/kompare/libdiff2/cvsdiffparser.cpp b/kompare/libdiff2/cvsdiffparser.cpp
new file mode 100644
index 00000000..d210eb66
--- /dev/null
+++ b/kompare/libdiff2/cvsdiffparser.cpp
@@ -0,0 +1,160 @@
+/**************************************************************************
+** cvsdiffparser.cpp
+** -----------------
+** begin : Sun Aug 4 15:05:35 2002
+** copyright : (C) 2002-2004 Otto Bruggeman
+** email : otto.bruggeman@home.nl
+**
+***************************************************************************/
+/***************************************************************************
+**
+** This program is free software; you can redistribute it and/or modify
+** it under the terms of the 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 <qregexp.h>
+
+#include <kdebug.h>
+
+#include "cvsdiffparser.h"
+#include "komparemodellist.h"
+
+
+using namespace Diff2;
+
+CVSDiffParser::CVSDiffParser( const KompareModelList* list, const QStringList& diff ) : ParserBase( list, diff )
+{
+ // The regexps needed for context cvs diff parsing, the rest is the same as in parserbase.cpp
+ // third capture in header1 is non optional for cvs diff, it is the revision
+ m_contextDiffHeader1.setPattern( "\\*\\*\\* ([^\\t]+)\\t([^\\t]+)\\t(.*)\\n" );
+ m_contextDiffHeader2.setPattern( "--- ([^\\t]+)\\t([^\\t]+)(|\\t(.*))\\n" );
+
+ m_normalDiffHeader.setPattern( "Index: (.*)\\n" );
+}
+
+CVSDiffParser::~CVSDiffParser()
+{
+}
+
+enum Kompare::Format CVSDiffParser::determineFormat()
+{
+// kdDebug(8101) << "Determining the format of the CVSDiff" << endl;
+
+ QRegExp normalRE ( "[0-9]+[0-9,]*[acd][0-9]+[0-9,]*" );
+ QRegExp unifiedRE( "^--- [^\\t]+\\t" );
+ QRegExp contextRE( "^\\*\\*\\* [^\\t]+\\t" );
+ QRegExp rcsRE ( "^[acd][0-9]+ [0-9]+" );
+ QRegExp edRE ( "^[0-9]+[0-9,]*[acd]" );
+
+ QStringList::ConstIterator it = m_diffLines.begin();
+
+ while( it != m_diffLines.end() )
+ {
+ if( (*it).find( normalRE, 0 ) == 0 )
+ {
+// kdDebug(8101) << "Difflines are from a Normal diff..." << endl;
+ return Kompare::Normal;
+ }
+ else if( (*it).find( unifiedRE, 0 ) == 0 )
+ {
+// kdDebug(8101) << "Difflines are from a Unified diff..." << endl;
+ return Kompare::Unified;
+ }
+ else if( (*it).find( contextRE, 0 ) == 0 )
+ {
+// kdDebug(8101) << "Difflines are from a Context diff..." << endl;
+ return Kompare::Context;
+ }
+ else if( (*it).find( rcsRE, 0 ) == 0 )
+ {
+// kdDebug(8101) << "Difflines are from a RCS diff..." << endl;
+ return Kompare::RCS;
+ }
+ else if( (*it).find( edRE, 0 ) == 0 )
+ {
+// kdDebug(8101) << "Difflines are from an ED diff..." << endl;
+ return Kompare::Ed;
+ }
+ ++it;
+ }
+// kdDebug(8101) << "Difflines are from an unknown diff..." << endl;
+ return Kompare::UnknownFormat;
+}
+
+bool CVSDiffParser::parseNormalDiffHeader()
+{
+ kdDebug(8101) << "CVSDiffParser::parseNormalDiffHeader()" << endl;
+ bool result = false;
+
+ QStringList::ConstIterator diffEnd = m_diffLines.end();
+
+ while ( m_diffIterator != diffEnd )
+ {
+ if ( m_normalDiffHeader.exactMatch( *m_diffIterator ) )
+ {
+ kdDebug(8101) << "Matched length Header = " << m_normalDiffHeader.matchedLength() << endl;
+ kdDebug(8101) << "Matched string Header = " << m_normalDiffHeader.cap( 0 ) << endl;
+
+ m_currentModel = new DiffModel();
+ QObject::connect( m_currentModel, SIGNAL( setModified( bool ) ), m_list, SLOT( slotSetModified( bool ) ) );
+ m_currentModel->setSourceFile ( m_normalDiffHeader.cap( 1 ) );
+ m_currentModel->setDestinationFile ( m_normalDiffHeader.cap( 1 ) );
+
+ result = true;
+
+ ++m_diffIterator;
+ break;
+ }
+ else
+ {
+ kdDebug(8101) << "No match for: " << ( *m_diffIterator ) << endl;
+ }
+ ++m_diffIterator;
+ }
+
+ if ( result == false )
+ {
+ // Set this to the first line again and hope it is a single file diff
+ m_diffIterator = m_diffLines.begin();
+ m_currentModel = new DiffModel();
+ QObject::connect( m_currentModel, SIGNAL( setModified( bool ) ), m_list, SLOT( slotSetModified( bool ) ) );
+ m_singleFileDiff = true;
+ }
+
+ return result;
+}
+
+
+bool CVSDiffParser::parseEdDiffHeader()
+{
+ return false;
+}
+
+bool CVSDiffParser::parseRCSDiffHeader()
+{
+ return false;
+}
+
+bool CVSDiffParser::parseEdHunkHeader()
+{
+ return false;
+}
+
+bool CVSDiffParser::parseRCSHunkHeader()
+{
+ return false;
+}
+
+bool CVSDiffParser::parseEdHunkBody()
+{
+ return false;
+}
+
+bool CVSDiffParser::parseRCSHunkBody()
+{
+ return false;
+}
+
diff --git a/kompare/libdiff2/cvsdiffparser.h b/kompare/libdiff2/cvsdiffparser.h
new file mode 100644
index 00000000..88fef485
--- /dev/null
+++ b/kompare/libdiff2/cvsdiffparser.h
@@ -0,0 +1,61 @@
+/**************************************************************************
+** cvsdiffparser.h
+** -----------------
+** begin : Sun Aug 4 15:05:35 2002
+** copyright : (C) 2002-2004 Otto Bruggeman
+** email : otto.bruggeman@home.nl
+**
+***************************************************************************/
+/***************************************************************************
+**
+** This program is free software; you can redistribute it and/or modify
+** it under the terms of the 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 _CVSDIFF_PARSER_H
+#define _CVSDIFF_PARSER_H
+
+#include <qregexp.h>
+
+#include "parserbase.h"
+
+namespace Diff2
+{
+
+class KompareModelList;
+
+class CVSDiffParser : public ParserBase
+{
+public:
+ CVSDiffParser( const KompareModelList* list, const QStringList& diff );
+ virtual ~CVSDiffParser();
+
+protected:
+ virtual enum Kompare::Format determineFormat();
+
+protected:
+// virtual bool parseContextDiffHeader();
+ virtual bool parseEdDiffHeader();
+ virtual bool parseNormalDiffHeader();
+ virtual bool parseRCSDiffHeader();
+// virtual bool parseUnifiedDiffHeader();
+
+// virtual bool parseContextHunkHeader();
+ virtual bool parseEdHunkHeader();
+// virtual bool parseNormalHunkHeader();
+ virtual bool parseRCSHunkHeader();
+// virtual bool parseUnifiedHunkHeader();
+
+// virtual bool parseContextHunkBody();
+ virtual bool parseEdHunkBody();
+// virtual bool parseNormalHunkBody();
+ virtual bool parseRCSHunkBody();
+// virtual bool parseUnifiedHunkBody();
+};
+
+} // End of namespace Diff2
+
+#endif
diff --git a/kompare/libdiff2/difference.cpp b/kompare/libdiff2/difference.cpp
new file mode 100644
index 00000000..8cbb4093
--- /dev/null
+++ b/kompare/libdiff2/difference.cpp
@@ -0,0 +1,137 @@
+/***************************************************************************
+ difference.cpp - description
+ -------------------
+ begin : Sun Mar 4 2001
+ copyright : (C) 2001-2003 by Otto Bruggeman
+ and John Firebaugh
+ email : otto.bruggeman@home.nl
+ jfirebaugh@kde.org
+****************************************************************************/
+
+/***************************************************************************
+**
+** This program is free software; you can redistribute it and/or modify
+** it under the terms of the 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 "difference.h"
+#include "levenshteintable.h"
+
+using namespace Diff2;
+
+Difference::Difference( int sourceLineNo, int destinationLineNo, int type ) :
+ m_type( type ),
+ m_sourceLineNo( sourceLineNo ),
+ m_destinationLineNo( destinationLineNo ),
+ m_applied( false )
+{
+}
+
+Difference::~Difference()
+{
+}
+
+void Difference::addSourceLine( QString line )
+{
+ m_sourceLines.append( new DifferenceString( line ) );
+}
+
+void Difference::addDestinationLine( QString line )
+{
+ m_destinationLines.append( new DifferenceString( line ) );
+}
+
+int Difference::sourceLineCount() const
+{
+ return m_sourceLines.count();
+}
+
+int Difference::destinationLineCount() const
+{
+ return m_destinationLines.count();
+}
+
+void Difference::apply( bool apply )
+{
+ m_applied = apply;
+}
+
+void Difference::determineInlineDifferences()
+{
+ LevenshteinTable table;
+ if ( m_type != Difference::Change )
+ return;
+
+ // Do nothing for now when the slc != dlc
+ // One could try to find the closest matching destination string for any
+ // of the source strings but this is compute intensive
+ if ( sourceLineCount() != destinationLineCount() )
+ return;
+
+ int slc = sourceLineCount();
+
+ for ( int i = 0; i < slc; ++i )
+ {
+ DifferenceString* sl = sourceLineAt( i );
+ DifferenceString* dl = destinationLineAt( i );
+
+ // FIXME: If the table cant be created dont do the rest
+ table.createTable( sl, dl );
+
+ table.createListsOfMarkers();
+ }
+}
+
+QString Difference::recreateDifference() const
+{
+ QString difference;
+
+ // source
+ DifferenceStringListConstIterator stringIt = m_sourceLines.begin();
+ DifferenceStringListConstIterator sEnd = m_sourceLines.end();
+
+ for ( ; stringIt != sEnd; ++stringIt )
+ {
+ switch ( m_type )
+ {
+ case Change:
+ case Delete:
+ difference += "-";
+ break;
+ default:
+ // Insert but this is not possible in source
+ // Unchanged will be handled in destination
+ // since they are the same
+// kdDebug( 8101 ) << "Go away, nothing to do for you in source..." << endl;
+ continue;
+ }
+ difference += (*stringIt)->string();
+ }
+
+ //destination
+ stringIt = m_destinationLines.begin();
+ sEnd = m_destinationLines.end();
+
+ for ( ; stringIt != sEnd; ++stringIt )
+ {
+ switch ( m_type )
+ {
+ case Change:
+ case Insert:
+ difference += "+";
+ break;
+ case Unchanged:
+ difference += " ";
+ break;
+ default: // Delete but this is not possible in destination
+// kdDebug( 8101 ) << "Go away, nothing to do for you in destination..." << endl;
+ continue;
+ }
+ difference += (*stringIt)->string();
+ }
+
+ return difference;
+}
diff --git a/kompare/libdiff2/difference.h b/kompare/libdiff2/difference.h
new file mode 100644
index 00000000..91065891
--- /dev/null
+++ b/kompare/libdiff2/difference.h
@@ -0,0 +1,223 @@
+/***************************************************************************
+ difference.h - description
+ -------------------
+ begin : Sun Mar 4 2001
+ copyright : (C) 2001-2003 by Otto Bruggeman
+ and John Firebaugh
+ email : otto.bruggeman@home.nl
+ jfirebaugh@kde.org
+****************************************************************************/
+
+/***************************************************************************
+**
+** This program is free software; you can redistribute it and/or modify
+** it under the terms of the 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 DIFFERENCE_H
+#define DIFFERENCE_H
+
+#include <qvaluelist.h>
+#include <qvaluevector.h>
+
+#include <kdebug.h>
+
+class QString;
+
+namespace Diff2
+{
+
+class LevenshteinTable;
+
+class Marker
+{
+public:
+ enum Type { Start = 0, End = 1 };
+
+public:
+ Marker()
+ {
+ m_type = Marker::Start;
+ m_offset = 0;
+ }
+ Marker( enum Marker::Type type, unsigned int offset )
+ {
+ m_type = type;
+ m_offset = offset;
+ }
+ ~Marker() {}
+
+public:
+ enum Marker::Type type() const { return m_type; }
+ unsigned int offset() const { return m_offset; }
+
+ void setType ( enum Marker::Type type ) { m_type = type; }
+ void setOffset( unsigned int offset ) { m_offset = offset; }
+
+private:
+ enum Marker::Type m_type;
+ unsigned int m_offset;
+};
+
+typedef QValueList<Marker*> MarkerList;
+typedef QValueList<Marker*>::iterator MarkerListIterator;
+typedef QValueList<Marker*>::const_iterator MarkerListConstIterator;
+
+class DifferenceString
+{
+public:
+ DifferenceString()
+ {
+// kdDebug(8101) << "DifferenceString::DifferenceString()" << endl;
+ }
+ DifferenceString( const QString& string, const MarkerList& markerList = MarkerList() ) :
+ m_string( string ),
+ m_markerList( markerList )
+ {
+// kdDebug(8101) << "DifferenceString::DifferenceString( " << string << ", " << markerList << " )" << endl;
+ calculateHash();
+ }
+ DifferenceString( const DifferenceString& ds ) :
+ m_string( ds.m_string ),
+ m_conflict( ds.m_conflict ),
+ m_hash( ds.m_hash ),
+ m_markerList( ds.m_markerList )
+ {
+// kdDebug(8101) << "DifferenceString::DifferenceString( const DifferenceString& " << ds << " )" << endl;
+ }
+ ~DifferenceString() {}
+
+public:
+ const QString& string() const
+ {
+ return m_string;
+ }
+ const QString& conflictString() const
+ {
+ return m_conflict;
+ }
+ const MarkerList& markerList()
+ {
+ return m_markerList;
+ }
+ void setString( const QString& string )
+ {
+ m_string = string;
+ calculateHash();
+ }
+ void setConflictString( const QString& conflict )
+ {
+ m_conflict = conflict;
+ }
+ void setMarkerList( const MarkerList& markerList )
+ {
+ m_markerList = markerList;
+ }
+ void prepend( Marker* marker )
+ {
+ m_markerList.prepend( marker );
+ }
+ bool operator==( const DifferenceString& ks )
+ {
+ if ( m_hash != ks.m_hash )
+ return false;
+ return m_string == ks.m_string;
+ }
+
+protected:
+ void calculateHash()
+ {
+ unsigned short const* str = reinterpret_cast<unsigned short const*>( m_string.unicode() );
+ const unsigned int len = m_string.length();
+
+ m_hash = 1315423911;
+
+ for ( unsigned int i = 0; i < len; i++ )
+ {
+ m_hash ^= ( m_hash << 5 ) + str[i] + ( m_hash >> 2 );
+ }
+ }
+
+private:
+ QString m_string;
+ QString m_conflict;
+ unsigned int m_hash;
+ MarkerList m_markerList;
+};
+
+typedef QValueVector<DifferenceString*> DifferenceStringList;
+typedef QValueVector<DifferenceString*>::iterator DifferenceStringListIterator;
+typedef QValueVector<DifferenceString*>::const_iterator DifferenceStringListConstIterator;
+
+class Difference
+{
+public:
+ enum Type { Change, Insert, Delete, Unchanged };
+
+public:
+ Difference( int sourceLineNo, int destinationLineNo, int type = Difference::Unchanged );
+ ~Difference();
+
+public:
+ int type() const { return m_type; };
+
+ int sourceLineNumber() const { return m_sourceLineNo; }
+ int destinationLineNumber() const { return m_destinationLineNo; }
+
+ int sourceLineCount() const;
+ int destinationLineCount() const;
+
+ DifferenceString* sourceLineAt( int i ) { return m_sourceLines[ i ]; }
+ DifferenceString* destinationLineAt( int i ) { return m_destinationLines[ i ]; }
+
+ const DifferenceStringList sourceLines() const { return m_sourceLines; }
+ const DifferenceStringList destinationLines() const { return m_destinationLines; }
+
+ bool hasConflict() const
+ {
+ return m_conflicts;
+ }
+ void setConflict( bool conflicts )
+ {
+ m_conflicts = conflicts;
+ }
+
+ void apply( bool apply );
+ bool applied() const { return m_applied; }
+
+ void setType( int type ) { m_type = type; }
+
+ void addSourceLine( QString line );
+ void addDestinationLine( QString line );
+
+ /** This method will calculate the differences between the individual strings and store them as Markers */
+ void determineInlineDifferences();
+
+ QString recreateDifference() const;
+
+private:
+ int m_type;
+
+ int m_sourceLineNo;
+ int m_destinationLineNo;
+
+ DifferenceStringList m_sourceLines;
+ DifferenceStringList m_destinationLines;
+
+ bool m_applied;
+ bool m_conflicts;
+
+ LevenshteinTable* m_tableXXX; // now unused
+};
+
+typedef QValueList<Difference*> DifferenceList;
+typedef QValueList<Difference*>::iterator DifferenceListIterator;
+typedef QValueList<Difference*>::const_iterator DifferenceListConstIterator;
+
+} // End of namespace Diff2
+
+#endif
+
diff --git a/kompare/libdiff2/diffhunk.cpp b/kompare/libdiff2/diffhunk.cpp
new file mode 100644
index 00000000..f980dd93
--- /dev/null
+++ b/kompare/libdiff2/diffhunk.cpp
@@ -0,0 +1,115 @@
+/***************************************************************************
+ diffhunk.cpp - description
+ -------------------
+ begin : Sun Mar 4 2001
+ copyright : (C) 2001-2003 by Otto Bruggeman
+ and John Firebaugh
+ email : otto.bruggeman@home.nl
+ jfirebaugh@kde.org
+****************************************************************************/
+
+/***************************************************************************
+**
+** This program is free software; you can redistribute it and/or modify
+** it under the terms of the 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 "difference.h"
+#include "diffhunk.h"
+
+using namespace Diff2;
+
+DiffHunk::DiffHunk( int sourceLine, int destinationLine, QString function, Type type ) :
+ m_sourceLine( sourceLine ),
+ m_destinationLine( destinationLine ),
+ m_function( function ),
+ m_type( type )
+{
+}
+
+DiffHunk::~DiffHunk()
+{
+}
+
+void DiffHunk::add( Difference* diff )
+{
+ m_differences.append( diff );
+}
+
+int DiffHunk::sourceLineCount() const
+{
+ DifferenceListConstIterator diffIt = m_differences.begin();
+ DifferenceListConstIterator dEnd = m_differences.end();
+
+ int lineCount = 0;
+
+ for ( ; diffIt != dEnd; ++diffIt )
+ lineCount += (*diffIt)->sourceLineCount();
+
+ return lineCount;
+}
+
+int DiffHunk::destinationLineCount() const
+{
+ DifferenceListConstIterator diffIt = m_differences.begin();
+ DifferenceListConstIterator dEnd = m_differences.end();
+
+ int lineCount = 0;
+
+ for ( ; diffIt != dEnd; ++diffIt )
+ lineCount += (*diffIt)->destinationLineCount();
+
+ return lineCount;
+}
+
+QString DiffHunk::recreateHunk() const
+{
+ QString hunk;
+ QString differences;
+
+ // recreate body
+ DifferenceListConstIterator diffIt = m_differences.begin();
+ DifferenceListConstIterator dEnd = m_differences.end();
+
+ int slc = 0; // source line count
+ int dlc = 0; // destination line count
+ for ( ; diffIt != dEnd; ++diffIt )
+ {
+ switch ( (*diffIt)->type() )
+ {
+ case Difference::Unchanged:
+ case Difference::Change:
+ slc += (*diffIt)->sourceLineCount();
+ dlc += (*diffIt)->destinationLineCount();
+ break;
+ case Difference::Insert:
+ dlc += (*diffIt)->destinationLineCount();
+ break;
+ case Difference::Delete:
+ slc += (*diffIt)->sourceLineCount();
+ break;
+ }
+ differences += (*diffIt)->recreateDifference();
+ }
+
+ // recreate header
+ hunk += QString::fromLatin1( "@@ -%1,%3 +%2,%4 @@" )
+ .arg( m_sourceLine )
+ .arg( m_destinationLine )
+ .arg( slc )
+ .arg( dlc );
+
+ if ( !m_function.isEmpty() )
+ hunk += " " + m_function;
+
+ hunk += QString::fromLatin1( "\n" );
+
+ hunk += differences;
+
+ kdDebug( 8101 ) << hunk << endl;
+ return hunk;
+}
diff --git a/kompare/libdiff2/diffhunk.h b/kompare/libdiff2/diffhunk.h
new file mode 100644
index 00000000..8a76babb
--- /dev/null
+++ b/kompare/libdiff2/diffhunk.h
@@ -0,0 +1,69 @@
+/***************************************************************************
+ diffhunk.h - description
+ -------------------
+ begin : Sun Mar 4 2001
+ copyright : (C) 2001-2003 by Otto Bruggeman
+ and John Firebaugh
+ email : otto.bruggeman@home.nl
+ jfirebaugh@kde.org
+****************************************************************************/
+
+/***************************************************************************
+**
+** This program is free software; you can redistribute it and/or modify
+** it under the terms of the 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 DIFFHUNK_H
+#define DIFFHUNK_H
+
+#include "difference.h"
+
+namespace Diff2
+{
+
+class Difference;
+
+class DiffHunk
+{
+public:
+ enum Type { Normal, AddedByBlend };
+
+public:
+ DiffHunk( int sourceLine, int destinationLine, QString function = QString::null, Type type = Normal );
+ ~DiffHunk();
+
+ const DifferenceList& differences() const { return m_differences; };
+ const QString& function() const { return m_function; };
+
+ int sourceLineNumber() const { return m_sourceLine; };
+ int destinationLineNumber() const { return m_destinationLine; };
+
+ int sourceLineCount() const;
+ int destinationLineCount() const;
+
+ const Type type() const { return m_type; }
+ void setType( Type type ) { m_type = type; }
+
+ void add( Difference* diff );
+
+ QString recreateHunk() const;
+
+private:
+ int m_sourceLine;
+ int m_destinationLine;
+ DifferenceList m_differences;
+ QString m_function;
+ Type m_type;
+};
+
+typedef QValueList<DiffHunk*> DiffHunkList;
+typedef QValueList<DiffHunk*>::iterator DiffHunkListIterator;
+typedef QValueList<DiffHunk*>::const_iterator DiffHunkListConstIterator;
+
+} // End of namespace Diff2
+
+#endif
diff --git a/kompare/libdiff2/diffmodel.cpp b/kompare/libdiff2/diffmodel.cpp
new file mode 100644
index 00000000..54c33457
--- /dev/null
+++ b/kompare/libdiff2/diffmodel.cpp
@@ -0,0 +1,409 @@
+/***************************************************************************
+ diffmodel.cpp - description
+ -------------------
+ begin : Sun Mar 4 2001
+ copyright : (C) 2001-2004 Otto Bruggeman
+ (C) 2001-2003 John Firebaugh
+ email : otto.bruggeman@home.nl
+ jfirebaugh@kde.org
+****************************************************************************/
+
+/***************************************************************************
+**
+** This program is free software; you can redistribute it and/or modify
+** it under the terms of the 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 <qregexp.h>
+#include <qvaluelist.h>
+
+#include <kdebug.h>
+#include <klocale.h>
+
+#include "difference.h"
+#include "diffhunk.h"
+#include "diffmodel.h"
+
+using namespace Diff2;
+
+/** */
+DiffModel::DiffModel( const QString& source, const QString& destination ) :
+ m_source( source ),
+ m_destination( destination ),
+ m_sourcePath( "" ),
+ m_destinationPath( "" ),
+ m_sourceFile( "" ),
+ m_destinationFile( "" ),
+ m_sourceTimestamp( "" ),
+ m_destinationTimestamp( "" ),
+ m_sourceRevision( "" ),
+ m_destinationRevision( "" ),
+ m_appliedCount( 0 ),
+ m_modified( false ),
+ m_diffIndex( 0 ),
+ m_selectedDifference( 0 ),
+ m_blended( false )
+{
+ splitSourceInPathAndFileName();
+ splitDestinationInPathAndFileName();
+}
+
+DiffModel::DiffModel() :
+ m_source( "" ),
+ m_destination( "" ),
+ m_sourcePath( "" ),
+ m_destinationPath( "" ),
+ m_sourceFile( "" ),
+ m_destinationFile( "" ),
+ m_sourceTimestamp( "" ),
+ m_destinationTimestamp( "" ),
+ m_sourceRevision( "" ),
+ m_destinationRevision( "" ),
+ m_appliedCount( 0 ),
+ m_modified( false ),
+ m_diffIndex( 0 ),
+ m_selectedDifference( 0 ),
+ m_blended( false )
+{
+}
+
+/** */
+DiffModel::~DiffModel()
+{
+}
+
+void DiffModel::splitSourceInPathAndFileName()
+{
+ int pos;
+
+ if( ( pos = m_source.findRev( "/" ) ) >= 0 )
+ m_sourcePath = m_source.mid( 0, pos+1 );
+
+ if( ( pos = m_source.findRev( "/" ) ) >= 0 )
+ m_sourceFile = m_source.mid( pos+1, m_source.length() - pos );
+ else
+ m_sourceFile = m_source;
+
+ kdDebug(8101) << m_source << " was split into " << m_sourcePath << " and " << m_sourceFile << endl;
+}
+
+void DiffModel::splitDestinationInPathAndFileName()
+{
+ int pos;
+
+ if( ( pos = m_destination.findRev( "/" ) )>= 0 )
+ m_destinationPath = m_destination.mid( 0, pos+1 );
+
+ if( ( pos = m_destination.findRev( "/" ) ) >= 0 )
+ m_destinationFile = m_destination.mid( pos+1, m_destination.length() - pos );
+ else
+ m_destinationFile = m_source;
+
+ kdDebug(8101) << m_destination << " was split into " << m_destinationPath << " and " << m_destinationFile << endl;
+}
+
+DiffModel& DiffModel::operator=( const DiffModel& model )
+{
+ if ( &model != this ) // Guard from self-assignment
+ {
+ m_source = model.m_source;
+ m_destination = model.m_destination;
+ m_sourcePath = model.m_sourcePath;
+ m_sourceFile = model.m_sourceFile;
+ m_sourceTimestamp = model.m_sourceTimestamp;
+ m_sourceRevision = model.m_sourceRevision;
+ m_destinationPath = model.m_destinationPath;
+ m_destinationFile = model.m_destinationFile;
+ m_destinationTimestamp = model.m_destinationTimestamp;
+ m_destinationRevision = model.m_destinationRevision;
+ m_appliedCount = model.m_appliedCount;
+ m_modified = model.m_modified;
+
+ m_diffIndex = model.m_diffIndex;
+ m_selectedDifference = model.m_selectedDifference;
+ }
+
+ return *this;
+}
+
+bool DiffModel::operator<( const DiffModel& model )
+{
+ if ( localeAwareCompareSource( model ) < 0 )
+ return true;
+ return false;
+}
+
+int DiffModel::localeAwareCompareSource( const DiffModel& model )
+{
+ int result = m_sourcePath.localeAwareCompare( model.m_sourcePath );
+
+ if ( result == 0 )
+ return m_sourceFile.localeAwareCompare( model.m_sourceFile );
+
+ return result;
+}
+
+QString DiffModel::recreateDiff() const
+{
+ // For now we'll always return a diff in the diff format
+ QString diff;
+
+ // recreate header
+ QString tab = QString::fromLatin1( "\t" );
+ QString nl = QString::fromLatin1( "\n" );
+ diff += QString::fromLatin1( "--- %1\t%2" ).arg( m_source ).arg( m_sourceTimestamp );
+ if ( !m_sourceRevision.isEmpty() )
+ diff += tab + m_sourceRevision;
+ diff += nl;
+ diff += QString::fromLatin1( "+++ %1\t%2" ).arg( m_destination ).arg( m_destinationTimestamp );
+ if ( !m_destinationRevision.isEmpty() )
+ diff += tab + m_destinationRevision;
+ diff += nl;
+
+ // recreate body by iterating over the hunks
+ DiffHunkListConstIterator hunkIt = m_hunks.begin();
+ DiffHunkListConstIterator hEnd = m_hunks.end();
+
+ for ( ; hunkIt != hEnd; ++hunkIt )
+ {
+ if ((*hunkIt)->type() != DiffHunk::AddedByBlend)
+ diff += (*hunkIt)->recreateHunk();
+ }
+
+ return diff;
+}
+
+DifferenceList* DiffModel::allDifferences()
+{
+ if ( m_hunks.count() != 0 )
+ {
+ DiffHunkListConstIterator hunkIt = m_hunks.begin();
+ DiffHunkListConstIterator hEnd = m_hunks.end();
+
+ for ( ; hunkIt != hEnd; ++hunkIt )
+ {
+ DiffHunk* hunk = *hunkIt;
+
+ DifferenceListConstIterator diffIt = hunk->differences().begin();
+ DifferenceListConstIterator dEnd = hunk->differences().end();
+
+ for ( ; diffIt != dEnd; ++diffIt )
+ {
+ m_allDifferences.append( *diffIt );
+ }
+ }
+ return &m_allDifferences;
+ }
+ else
+ {
+ DifferenceList *diffList = new DifferenceList;
+ return diffList;
+ }
+}
+
+Difference* DiffModel::firstDifference()
+{
+ kdDebug( 8101 ) << "DiffModel::firstDifference()" << endl;
+ m_diffIndex = 0;
+ kdDebug( 8101 ) << "m_diffIndex = " << m_diffIndex << endl;
+
+ m_selectedDifference = m_differences[ m_diffIndex ];
+
+ return m_selectedDifference;
+}
+
+Difference* DiffModel::lastDifference()
+{
+ kdDebug( 8101 ) << "DiffModel::lastDifference()" << endl;
+ m_diffIndex = m_differences.count() - 1;
+ kdDebug( 8101 ) << "m_diffIndex = " << m_diffIndex << endl;
+
+ m_selectedDifference = m_differences[ m_diffIndex ];
+
+ return m_selectedDifference;
+}
+
+Difference* DiffModel::prevDifference()
+{
+ kdDebug( 8101 ) << "DiffModel::prevDifference()" << endl;
+ if ( --m_diffIndex < m_differences.count() )
+ {
+ kdDebug( 8101 ) << "m_diffIndex = " << m_diffIndex << endl;
+ m_selectedDifference = m_differences[ m_diffIndex ];
+ }
+ else
+ {
+ m_selectedDifference = 0;
+ m_diffIndex = 0;
+ kdDebug( 8101 ) << "m_diffIndex = " << m_diffIndex << endl;
+ }
+
+ return m_selectedDifference;
+}
+
+Difference* DiffModel::nextDifference()
+{
+ kdDebug( 8101 ) << "DiffModel::nextDifference()" << endl;
+ if ( ++m_diffIndex < m_differences.count() )
+ {
+ kdDebug( 8101 ) << "m_diffIndex = " << m_diffIndex << endl;
+ m_selectedDifference = m_differences[ m_diffIndex ];
+ }
+ else
+ {
+ m_selectedDifference = 0;
+ m_diffIndex = 0; // just for safety...
+ kdDebug( 8101 ) << "m_diffIndex = " << m_diffIndex << endl;
+ }
+
+ return m_selectedDifference;
+}
+
+const QString DiffModel::sourceFile() const
+{
+ return m_sourceFile;
+}
+
+const QString DiffModel::destinationFile() const
+{
+ return m_destinationFile;
+}
+
+const QString DiffModel::sourcePath() const
+{
+ return m_sourcePath;
+}
+
+const QString DiffModel::destinationPath() const
+{
+ return m_destinationPath;
+}
+
+void DiffModel::setSourceFile( QString path )
+{
+ m_source = path;
+ splitSourceInPathAndFileName();
+}
+
+void DiffModel::setDestinationFile( QString path )
+{
+ m_destination = path;
+ splitDestinationInPathAndFileName();
+}
+
+void DiffModel::setSourceTimestamp( QString timestamp )
+{
+ m_sourceTimestamp = timestamp;
+}
+
+void DiffModel::setDestinationTimestamp( QString timestamp )
+{
+ m_destinationTimestamp = timestamp;
+}
+
+void DiffModel::setSourceRevision( QString revision )
+{
+ m_destinationRevision = revision;
+}
+
+void DiffModel::setDestinationRevision( QString revision )
+{
+ m_destinationRevision = revision;
+}
+
+void DiffModel::addHunk( DiffHunk* hunk )
+{
+ m_hunks.append( hunk );
+}
+
+void DiffModel::addDiff( Difference* diff )
+{
+ m_differences.append( diff );
+}
+
+void DiffModel::applyDifference( bool apply )
+{
+ if ( apply && !m_selectedDifference->applied() )
+ m_appliedCount++;
+ else if ( !apply && m_selectedDifference->applied() )
+ m_appliedCount--;
+
+ bool modified;
+
+ // Not setting the m_modified yet so i can still query the current
+ // modified status from the slot that is connected to the signal
+ if ( m_appliedCount == 0 )
+ modified = false;
+ else
+ modified = true;
+
+ emit setModified( modified );
+
+ m_modified = modified;
+
+ m_selectedDifference->apply( apply );
+}
+
+void DiffModel::applyAllDifferences( bool apply )
+{
+ bool modified;
+
+ // Not setting the m_modified yet so i can still query the current
+ // modified status from the slot that is connected to the signal
+ if ( apply )
+ {
+ m_appliedCount = m_differences.count();
+ modified = true;
+ }
+ else
+ {
+ m_appliedCount = 0;
+ modified = false;
+ }
+
+ emit setModified( modified );
+
+ m_modified = modified;
+
+ DifferenceListIterator diffIt = m_differences.begin();
+ DifferenceListIterator dEnd = m_differences.end();
+
+ for ( ; diffIt != dEnd; ++diffIt )
+ {
+ (*diffIt)->apply( apply );
+ }
+}
+
+void DiffModel::slotSetModified( bool modified )
+{
+ // Not setting the m_modified yet so i can still query the current
+ // modified status from the slot that is connected to the signal
+ emit setModified( modified );
+
+ m_modified = modified;
+}
+
+bool DiffModel::setSelectedDifference( Difference* diff )
+{
+ kdDebug(8101) << "diff = " << diff << endl;
+ kdDebug(8101) << "m_selectedDifference = " << m_selectedDifference << endl;
+
+ if ( diff != m_selectedDifference )
+ {
+ if ( ( m_differences.findIndex( diff ) ) == -1 )
+ return false;
+ // Dont set m_diffIndex if it cant be found
+ m_diffIndex = m_differences.findIndex( diff );
+ kdDebug( 8101 ) << "m_diffIndex = " << m_diffIndex << endl;
+ m_selectedDifference = diff;
+ }
+
+ return true;
+}
+
+#include "diffmodel.moc"
+
+/* vim: set ts=4 sw=4 noet: */
diff --git a/kompare/libdiff2/diffmodel.h b/kompare/libdiff2/diffmodel.h
new file mode 100644
index 00000000..11c424b5
--- /dev/null
+++ b/kompare/libdiff2/diffmodel.h
@@ -0,0 +1,150 @@
+/***************************************************************************
+ diffmodel.h - description
+ -------------------
+ begin : Sun Mar 4 2001
+ copyright : (C) 2001-2004 Otto Bruggeman
+ (C) 2001-2003 John Firebaugh
+ email : otto.bruggeman@home.nl
+ jfirebaugh@kde.org
+****************************************************************************/
+
+/***************************************************************************
+**
+** This program is free software; you can redistribute it and/or modify
+** it under the terms of the 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 DIFFMODEL_H
+#define DIFFMODEL_H
+
+#include <qobject.h>
+#include <qstringlist.h>
+
+#include "diffhunk.h"
+#include "kompare.h"
+
+namespace Diff2
+{
+
+class DiffHunk;
+class Difference;
+
+class DiffModel : public QObject
+{
+Q_OBJECT
+public:
+
+ DiffModel( const QString& srcBaseURL, const QString& destBaseURL );
+ DiffModel();
+ DiffModel( const DiffModel& ) : QObject() {};
+ ~DiffModel();
+
+ int parseDiff( enum Kompare::Format format, const QStringList& list );
+
+ QString recreateDiff() const;
+
+ int hunkCount() const { return m_hunks.count(); }
+ int differenceCount() const { return m_differences.count(); }
+ int appliedCount() const { return m_appliedCount; }
+
+ DiffHunk* hunkAt( int i ) { return *( m_hunks.at( i ) ); }
+ const Difference* differenceAt( int i ) { return *( m_differences.at( i ) ); }
+
+ DiffHunkList* hunks() { return &m_hunks; }
+ const DiffHunkList* hunks() const { return &m_hunks; }
+ DifferenceList* differences() { return &m_differences; }
+ const DifferenceList* differences() const { return &m_differences; }
+
+ DifferenceList* allDifferences();
+
+ int findDifference( Difference* diff ) const { return m_differences.findIndex( diff ); }
+
+ Difference* firstDifference();
+ Difference* lastDifference();
+ Difference* prevDifference();
+ Difference* nextDifference();
+
+ const QString source() const { return m_source; }
+ const QString destination() const { return m_destination; }
+ const QString sourceFile() const;
+ const QString destinationFile() const;
+ const QString sourcePath() const;
+ const QString destinationPath() const;
+ const QString sourceTimestamp() const { return m_sourceTimestamp; }
+ const QString destinationTimestamp() const { return m_destinationTimestamp; }
+ const QString sourceRevision() const { return m_sourceRevision; }
+ const QString destinationRevision() const { return m_destinationRevision; }
+
+ void setSourceFile( QString path );
+ void setDestinationFile( QString path );
+ void setSourceTimestamp( QString timestamp );
+ void setDestinationTimestamp( QString timestamp );
+ void setSourceRevision( QString revision );
+ void setDestinationRevision( QString revision );
+
+ void addHunk( DiffHunk* hunk );
+ void addDiff( Difference* diff );
+ bool isModified() const { return m_modified; }
+
+ const int diffIndex( void ) const { return m_diffIndex; }
+ void setDiffIndex( int diffIndex ) { m_diffIndex = diffIndex; }
+
+ void applyDifference( bool apply );
+ void applyAllDifferences( bool apply );
+
+ bool setSelectedDifference( Difference* diff );
+
+ DiffModel& operator=( const DiffModel& model );
+ bool operator<( const DiffModel& model );
+
+ int localeAwareCompareSource( const DiffModel& model );
+
+ bool isBlended() const { return m_blended; }
+ void setBlended( bool blended ) { m_blended = blended; }
+
+signals:
+ void setModified( bool modified );
+
+public slots:
+ void slotSetModified( bool modified );
+
+private:
+ void splitSourceInPathAndFileName();
+ void splitDestinationInPathAndFileName();
+
+private:
+ QString m_source;
+ QString m_destination;
+
+ QString m_sourcePath;
+ QString m_destinationPath;
+
+ QString m_sourceFile;
+ QString m_destinationFile;
+
+ QString m_sourceTimestamp;
+ QString m_destinationTimestamp;
+
+ QString m_sourceRevision;
+ QString m_destinationRevision;
+
+ DiffHunkList m_hunks;
+ DifferenceList m_differences;
+ DifferenceList m_allDifferences;
+
+ int m_appliedCount;
+ bool m_modified;
+
+ unsigned int m_diffIndex;
+ Difference* m_selectedDifference;
+
+ bool m_blended;
+};
+
+} // End of namespace Diff2
+
+#endif
+
diff --git a/kompare/libdiff2/diffmodellist.cpp b/kompare/libdiff2/diffmodellist.cpp
new file mode 100644
index 00000000..200e8108
--- /dev/null
+++ b/kompare/libdiff2/diffmodellist.cpp
@@ -0,0 +1,29 @@
+/*******************************************************************************
+**
+** Filename : diffmodellist.cpp
+** Created on : 26 march, 2004
+** Copyright : (c) 2004 Otto Bruggeman
+** Email : bruggie@home.nl
+**
+*******************************************************************************/
+
+/*******************************************************************************
+**
+** This program is free software; you can redistribute it and/or modify
+** it under the terms of the 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 <kdebug.h>
+
+#include "diffmodellist.h"
+
+using namespace Diff2;
+
+void DiffModelList::sort()
+{
+ qHeapSort(*this);
+}
+
diff --git a/kompare/libdiff2/diffmodellist.h b/kompare/libdiff2/diffmodellist.h
new file mode 100644
index 00000000..9c4f9807
--- /dev/null
+++ b/kompare/libdiff2/diffmodellist.h
@@ -0,0 +1,49 @@
+/*******************************************************************************
+**
+** Filename : diffmodellist.h
+** Created on : 24 januari, 2004
+** Copyright : (c) 2004 Otto Bruggeman
+** Email : bruggie@home.nl
+**
+*******************************************************************************/
+
+/*******************************************************************************
+**
+** This program is free software; you can redistribute it and/or modify
+** it under the terms of the 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 DIFFMODELLIST_H
+#define DIFFMODELLIST_H
+
+#include <qvaluelist.h> // include for the base class
+
+#include "diffmodel.h"
+
+namespace Diff2
+{
+
+typedef QValueListIterator<DiffModel*> DiffModelListIterator;
+typedef QValueListConstIterator<DiffModel*> DiffModelListConstIterator;
+
+class DiffModelList : public QValueList<DiffModel*>
+{
+public:
+ DiffModelList() {}
+ DiffModelList( const DiffModelList &list ) : QValueList<DiffModel*>( list ) {}
+ virtual ~DiffModelList()
+ {
+ clear();
+ }
+
+public:
+ virtual void sort();
+
+}; // End of class DiffModelList
+
+} // End of Namespace Diff2
+
+#endif // DIFFMODELLIST_H
diff --git a/kompare/libdiff2/diffparser.cpp b/kompare/libdiff2/diffparser.cpp
new file mode 100644
index 00000000..f98fbde5
--- /dev/null
+++ b/kompare/libdiff2/diffparser.cpp
@@ -0,0 +1,81 @@
+/**************************************************************************
+** diffparser.cpp
+** --------------
+** begin : Sun Aug 4 15:05:35 2002
+** copyright : (C) 2002-2004 Otto Bruggeman
+** email : otto.bruggeman@home.nl
+**
+***************************************************************************/
+/***************************************************************************
+**
+** This program is free software; you can redistribute it and/or modify
+** it under the terms of the 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 <qregexp.h>
+
+#include <kdebug.h>
+
+#include "diffparser.h"
+
+using namespace Diff2;
+
+DiffParser::DiffParser( const KompareModelList* list, const QStringList& diff ) : ParserBase( list, diff )
+{
+ // The regexps needed for context diff parsing, the rest is the same as in parserbase.cpp
+ m_contextDiffHeader1.setPattern( "\\*\\*\\* ([^\\t]+)\\t([^\\t]+)\\n" );
+ m_contextDiffHeader2.setPattern( "--- ([^\\t]+)\\t([^\\t]+)\\n" );
+}
+
+DiffParser::~DiffParser()
+{
+}
+
+enum Kompare::Format DiffParser::determineFormat()
+{
+ kdDebug(8101) << "Determining the format of the diff Diff" << endl;
+
+ QRegExp normalRE ( "[0-9]+[0-9,]*[acd][0-9]+[0-9,]*" );
+ QRegExp unifiedRE( "^--- " );
+ QRegExp contextRE( "^\\*\\*\\* " );
+ QRegExp rcsRE ( "^[acd][0-9]+ [0-9]+" );
+ QRegExp edRE ( "^[0-9]+[0-9,]*[acd]" );
+
+ QStringList::ConstIterator it = m_diffLines.begin();
+
+ while( it != m_diffLines.end() )
+ {
+ kdDebug(8101) << (*it) << endl;
+ if( (*it).find( normalRE, 0 ) == 0 )
+ {
+ kdDebug(8101) << "Difflines are from a Normal diff..." << endl;
+ return Kompare::Normal;
+ }
+ else if( (*it).find( unifiedRE, 0 ) == 0 )
+ {
+ kdDebug(8101) << "Difflines are from a Unified diff..." << endl;
+ return Kompare::Unified;
+ }
+ else if( (*it).find( contextRE, 0 ) == 0 )
+ {
+ kdDebug(8101) << "Difflines are from a Context diff..." << endl;
+ return Kompare::Context;
+ }
+ else if( (*it).find( rcsRE, 0 ) == 0 )
+ {
+ kdDebug(8101) << "Difflines are from an RCS diff..." << endl;
+ return Kompare::RCS;
+ }
+ else if( (*it).find( edRE, 0 ) == 0 )
+ {
+ kdDebug(8101) << "Difflines are from an ED diff..." << endl;
+ return Kompare::Ed;
+ }
+ ++it;
+ }
+ kdDebug(8101) << "Difflines are from an unknown diff..." << endl;
+ return Kompare::UnknownFormat;
+}
diff --git a/kompare/libdiff2/diffparser.h b/kompare/libdiff2/diffparser.h
new file mode 100644
index 00000000..72905e3f
--- /dev/null
+++ b/kompare/libdiff2/diffparser.h
@@ -0,0 +1,38 @@
+/**************************************************************************
+** diffparser.h
+** -----------------
+** begin : Sun Aug 4 15:05:35 2002
+** copyright : (C) 2002-2004 Otto Bruggeman
+** email : otto.bruggeman@home.nl
+**
+***************************************************************************/
+/***************************************************************************
+**
+** This program is free software; you can redistribute it and/or modify
+** it under the terms of the 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 _DIFF_PARSER_H
+#define _DIFF_PARSER_H
+
+#include "parserbase.h"
+
+namespace Diff2
+{
+
+class DiffParser : public ParserBase
+{
+public:
+ DiffParser( const KompareModelList* list, const QStringList& diff );
+ virtual ~DiffParser();
+
+protected:
+ virtual enum Kompare::Format determineFormat();
+};
+
+} // End of namespace Diff2
+
+#endif
diff --git a/kompare/libdiff2/kompare.h b/kompare/libdiff2/kompare.h
new file mode 100644
index 00000000..1ed5c4c7
--- /dev/null
+++ b/kompare/libdiff2/kompare.h
@@ -0,0 +1,144 @@
+/***************************************************************************
+ kompare.h - description
+ -------------------
+ begin : Sun Mar 4 2001
+ copyright : (C) 2001-2003 by Otto Bruggeman
+ and John Firebaugh
+ email : otto.bruggeman@home.nl
+ jfirebaugh@kde.org
+****************************************************************************/
+
+/***************************************************************************
+**
+** This program is free software; you can redistribute it and/or modify
+** it under the terms of the 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 KOMPARE_H
+#define KOMPARE_H
+
+#include <kurl.h>
+
+namespace Kompare
+{
+ enum Format {
+ Context = 0,
+ Ed = 1,
+ Normal = 2,
+ RCS = 3,
+ Unified = 4,
+ SideBySide = 5,
+ UnknownFormat = -1
+ };
+
+ enum Generator {
+ CVSDiff = 0,
+ Diff = 1,
+ Perforce = 2,
+ SubVersion = 3,
+ Reserved2 = 4,
+ Reserved3 = 5,
+ Reserved4 = 6,
+ Reserved5 = 7,
+ Reserved6 = 8,
+ Reserved7 = 9,
+ UnknownGenerator = -1
+ };
+
+ enum Mode {
+ ComparingFiles, // compareFiles
+ ComparingDirs, // compareDirs
+ ShowingDiff, // openDiff
+ BlendingDir, // openDirAnfDiff
+ BlendingFile, // openFileAndDiff
+ UnknownMode // Used to initialize the Infoi struct
+ };
+
+ enum DiffMode {
+ Default,
+ Custom,
+ UnknownDiffMode // Use to initialize the Info struct
+ };
+
+ enum Status {
+ RunningDiff,
+ Parsing,
+ FinishedParsing,
+ FinishedWritingDiff,
+ ReRunningDiff // When a change has been detected after diff has run
+ };
+
+ enum Target {
+ Source,
+ Destination
+ };
+
+ struct Info {
+ Info (
+ enum Mode _mode = UnknownMode,
+ enum DiffMode _diffMode = UnknownDiffMode,
+ enum Format _format = UnknownFormat,
+ enum Generator _generator = UnknownGenerator,
+ KURL _source = KURL(),
+ KURL _destination = KURL(),
+ QString _localSource = "",
+ QString _localDestination = ""
+ )
+ {
+ mode = _mode;
+ diffMode = _diffMode;
+ format = _format;
+ generator = _generator;
+ source = _source;
+ destination = _destination;
+ localSource = _localSource;
+ localDestination = _localDestination;
+ }
+ enum Mode mode;
+ enum DiffMode diffMode;
+ enum Format format;
+ enum Generator generator;
+ KURL source;
+ KURL destination;
+ QString localSource;
+ QString localDestination;
+ };
+} // End of namespace Kompare
+
+/*
+** This should be removed and put somewhere else
+*/
+class KompareFunctions
+{
+public:
+ static QString constructRelativePath( const QString& from, const QString& to )
+ {
+ KURL fromURL( from );
+ KURL toURL( to );
+ KURL root;
+ int upLevels = 0;
+
+ // Find a common root.
+ root = from;
+ while( root.isValid() && !root.isParentOf( toURL ) ) {
+ root = root.upURL();
+ upLevels++;
+ }
+
+ if( !root.isValid() ) return to;
+
+ QString relative;
+ for( ; upLevels > 0; upLevels-- ) {
+ relative += "../";
+ }
+
+ relative += QString( to ).replace( 0, root.path(1).length(), "" );
+
+ return relative;
+ }
+};
+
+#endif
diff --git a/kompare/libdiff2/komparemodellist.cpp b/kompare/libdiff2/komparemodellist.cpp
new file mode 100644
index 00000000..ac3c725a
--- /dev/null
+++ b/kompare/libdiff2/komparemodellist.cpp
@@ -0,0 +1,1423 @@
+/***************************************************************************
+ komparemodellist.cpp - description
+ -------------------
+ begin : Tue Jun 26 2001
+ copyright : (C) 2001-2004 Otto Bruggeman
+ (C) 2001-2003 John Firebaugh
+ (C) 2007 Kevin Kofler
+ email : jfirebaugh@kde.org
+ otto.bruggeman@home.nl
+ kevin.kofler@chello.at
+***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the 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 <qfile.h>
+#include <qdir.h>
+#include <qregexp.h>
+#include <qtextcodec.h>
+#include <qvaluelist.h>
+
+#include <kaction.h>
+#include <kcharsets.h>
+#include <kdebug.h>
+#include <kdirwatch.h>
+#include <kio/netaccess.h>
+#include <klocale.h>
+#include <kmimetype.h>
+#include <ktempfile.h>
+
+#include "difference.h"
+#include "diffhunk.h"
+#include "diffmodel.h"
+#include "diffmodellist.h"
+#include "kompareprocess.h"
+#include "komparemodellist.h"
+#include "parser.h"
+
+#include "kompare_part.h"
+
+using namespace Diff2;
+
+KompareModelList::KompareModelList( DiffSettings* diffSettings, struct Kompare::Info& info, QObject* parent, const char* name )
+ : QObject( parent, name ),
+ m_diffProcess( 0 ),
+ m_diffSettings( diffSettings ),
+ m_models( 0 ),
+ m_selectedModel( 0 ),
+ m_selectedDifference( 0 ),
+ m_noOfModified( 0 ),
+ m_modelIndex( 0 ),
+ m_info( info ),
+ m_textCodec( 0 )
+{
+ m_applyDifference = new KAction( i18n("&Apply Difference"), "1rightarrow", Qt::Key_Space,
+ this, SLOT(slotActionApplyDifference()),
+ (( KomparePart* )parent)->actionCollection(), "difference_apply" );
+ m_unApplyDifference = new KAction( i18n("Un&apply Difference"), "1leftarrow", Qt::Key_BackSpace,
+ this, SLOT(slotActionUnApplyDifference()),
+ (( KomparePart* )parent)->actionCollection(), "difference_unapply" );
+ m_applyAll = new KAction( i18n("App&ly All"), "2rightarrow", Qt::CTRL + Qt::Key_A,
+ this, SLOT(slotActionApplyAllDifferences()),
+ (( KomparePart* )parent)->actionCollection(), "difference_applyall" );
+ m_unapplyAll = new KAction( i18n("&Unapply All"), "2leftarrow", Qt::CTRL + Qt::Key_U,
+ this, SLOT(slotActionUnapplyAllDifferences()),
+ (( KomparePart* )parent)->actionCollection(), "difference_unapplyall" );
+ m_previousFile = new KAction( i18n("P&revious File"), "2uparrow", Qt::CTRL + Qt::Key_PageUp,
+ this, SLOT(slotPreviousModel()),
+ (( KomparePart* )parent)->actionCollection(), "difference_previousfile" );
+ m_nextFile = new KAction( i18n("N&ext File"), "2downarrow", Qt::CTRL + Qt::Key_PageDown,
+ this, SLOT(slotNextModel()),
+ (( KomparePart* )parent)->actionCollection(), "difference_nextfile" );
+ m_previousDifference = new KAction( i18n("&Previous Difference"), "1uparrow", Qt::CTRL + Qt::Key_Up,
+ this, SLOT(slotPreviousDifference()),
+ (( KomparePart* )parent)->actionCollection(), "difference_previous" );
+ m_nextDifference = new KAction( i18n("&Next Difference"), "1downarrow", Qt::CTRL + Qt::Key_Down,
+ this, SLOT(slotNextDifference()),
+ (( KomparePart* )parent)->actionCollection(), "difference_next" );
+ m_previousDifference->setEnabled( false );
+ m_nextDifference->setEnabled( false );
+
+ m_save = KStdAction::save( this, SLOT(slotSaveDestination()), ((KomparePart*)parent)->actionCollection() );
+ m_save->setEnabled( false );
+
+ updateModelListActions();
+}
+
+KompareModelList::~KompareModelList()
+{
+}
+
+bool KompareModelList::isDirectory( const QString& url ) const
+{
+ QFileInfo fi( url );
+ if ( fi.isDir() )
+ return true;
+ else
+ return false;
+}
+
+bool KompareModelList::isDiff( const QString& mimeType ) const
+{
+ if ( mimeType == "text/x-diff" )
+ return true;
+ else
+ return false;
+}
+
+bool KompareModelList::compare( const QString& source, const QString& destination )
+{
+ bool result = false;
+
+ bool sourceIsDirectory = isDirectory( source );
+ bool destinationIsDirectory = isDirectory( source );
+
+ if ( sourceIsDirectory && destinationIsDirectory )
+ {
+ m_info.mode = Kompare::ComparingDirs;
+ result = compareDirs( source, destination );
+ }
+ else if ( !sourceIsDirectory && !destinationIsDirectory )
+ {
+ QFile sourceFile( source );
+ sourceFile.open( IO_ReadOnly );
+ QString sourceMimeType = ( KMimeType::findByContent( sourceFile.readAll() ) )->name();
+ sourceFile.close();
+ kdDebug(8101) << "Mimetype source : " << sourceMimeType << endl;
+
+ QFile destinationFile( destination );
+ destinationFile.open( IO_ReadOnly );
+ QString destinationMimeType = ( KMimeType::findByContent( destinationFile.readAll() ) )->name();
+ destinationFile.close();
+ kdDebug(8101) << "Mimetype destination: " << destinationMimeType << endl;
+
+ // Not checking if it is a text file/something diff can even compare, we'll let diff handle that
+ if ( !isDiff( sourceMimeType ) && isDiff( destinationMimeType ) )
+ {
+ kdDebug(8101) << "Blending destination into source..." << endl;
+ m_info.mode = Kompare::BlendingFile;
+ result = openFileAndDiff( source, destination );
+ }
+ else if ( isDiff( sourceMimeType ) && !isDiff( destinationMimeType ) )
+ {
+ kdDebug(8101) << "Blending source into destination..." << endl;
+ m_info.mode = Kompare::BlendingFile;
+ result = openFileAndDiff( destination, source );
+ }
+ else
+ {
+ kdDebug(8101) << "Comparing source with destination" << endl;
+ m_info.mode = Kompare::ComparingFiles;
+ result = compareFiles( source, destination );
+ }
+ }
+ else if ( sourceIsDirectory && !destinationIsDirectory )
+ {
+ m_info.mode = Kompare::BlendingDir;
+ result = openDirAndDiff( source, destination );
+ }
+ else
+ {
+ m_info.mode = Kompare::BlendingDir;
+ result = openDirAndDiff( destination, source );
+ }
+
+ return result;
+}
+
+bool KompareModelList::compareFiles( const QString& source, const QString& destination )
+{
+ m_source = source;
+ m_destination = destination;
+
+ clear(); // Destroy the old models...
+
+// m_fileWatch = new KDirWatch( this, "filewatch" );
+// m_fileWatch->addFile( m_source );
+// m_fileWatch->addFile( m_destination );
+
+// connect( m_fileWatch, SIGNAL( dirty( const QString& ) ), this, SLOT( slotFileChanged( const QString& ) ) );
+// connect( m_fileWatch, SIGNAL( created( const QString& ) ), this, SLOT( slotFileChanged( const QString& ) ) );
+// connect( m_fileWatch, SIGNAL( deleted( const QString& ) ), this, SLOT( slotFileChanged( const QString& ) ) );
+
+// m_fileWatch->startScan();
+ m_diffProcess = new KompareProcess( m_diffSettings, Kompare::Custom, m_source, m_destination );
+ m_diffProcess->setEncoding( m_encoding );
+
+ connect( m_diffProcess, SIGNAL(diffHasFinished( bool )),
+ this, SLOT(slotDiffProcessFinished( bool )) );
+
+ emit status( Kompare::RunningDiff );
+ m_diffProcess->start();
+
+ return true;
+}
+
+bool KompareModelList::compareDirs( const QString& source, const QString& destination )
+{
+ m_source = source;
+ m_destination = destination;
+
+ clear(); // Destroy the old models...
+
+// m_dirWatch = new KDirWatch( this, "dirwatch" );
+ // Watch files in the dirs and watch the dirs recursively
+// m_dirWatch->addDir( m_source, true, true );
+// m_dirWatch->addDir( m_destination, true, true );
+
+// connect( m_dirWatch, SIGNAL( dirty ( const QString& ) ), this, SLOT( slotDirectoryChanged( const QString& ) ) );
+// connect( m_dirWatch, SIGNAL( created( const QString& ) ), this, SLOT( slotDirectoryChanged( const QString& ) ) );
+// connect( m_dirWatch, SIGNAL( deleted( const QString& ) ), this, SLOT( slotDirectoryChanged( const QString& ) ) );
+
+// m_dirWatch->startScan();
+ m_diffProcess = new KompareProcess( m_diffSettings, Kompare::Custom, m_source, m_destination );
+ m_diffProcess->setEncoding( m_encoding );
+
+ connect( m_diffProcess, SIGNAL(diffHasFinished( bool )),
+ this, SLOT(slotDiffProcessFinished( bool )) );
+
+ emit status( Kompare::RunningDiff );
+ m_diffProcess->start();
+
+ return true;
+}
+
+bool KompareModelList::openFileAndDiff( const QString& file, const QString& diff )
+{
+ clear();
+
+ if ( parseDiffOutput( readFile( diff ) ) != 0 )
+ {
+ emit error( i18n( "<qt>No models or no differences, this file: <b>%1</b>, is not a valid diff file.</qt>" ).arg( diff ) );
+ return false;
+ }
+
+ // Do our thing :)
+ if ( !blendOriginalIntoModelList( file ) )
+ {
+ kdDebug(8101) << "Oops cant blend original file into modellist : " << file << endl;
+ emit( i18n( "<qt>There were problems applying the diff <b>%1</b> to the file <b>%2</b>.</qt>" ).arg( diff ).arg( file ) );
+ return false;
+ }
+
+ updateModelListActions();
+ show();
+
+ return true;
+}
+
+bool KompareModelList::openDirAndDiff( const QString& dir, const QString& diff )
+{
+ clear();
+
+ if ( parseDiffOutput( readFile( diff ) ) != 0 )
+ {
+ emit error( i18n( "<qt>No models or no differences, this file: <b>%1</b>, is not a valid diff file.</qt>" ).arg( diff ) );
+ return false;
+ }
+
+ // Do our thing :)
+ if ( !blendOriginalIntoModelList( dir ) )
+ {
+ // Trouble blending the original into the model
+ kdDebug(8101) << "Oops cant blend original dir into modellist : " << dir << endl;
+ emit error( i18n( "<qt>There were problems applying the diff <b>%1</b> to the folder <b>%2</b>.</qt>" ).arg( diff ).arg( dir ) );
+ return false;
+ }
+
+ updateModelListActions();
+ show();
+
+ return true;
+}
+
+void KompareModelList::slotSaveDestination()
+{
+ if ( m_selectedModel )
+ {
+ saveDestination( m_selectedModel );
+ }
+}
+
+bool KompareModelList::saveDestination( DiffModel* model )
+{
+ kdDebug() << "KompareModelList::saveDestination: " << endl;
+
+ if( !model->isModified() )
+ return true;
+
+ KTempFile* temp = new KTempFile();
+
+ if( temp->status() != 0 ) {
+ emit error( i18n( "Could not open a temporary file." ) );
+ temp->unlink();
+ delete temp;
+ return false;
+ }
+
+ QTextStream* stream = temp->textStream();
+ QStringList list;
+
+ DiffHunkListConstIterator hunkIt = model->hunks()->begin();
+ DiffHunkListConstIterator hEnd = model->hunks()->end();
+
+ for( ; hunkIt != hEnd; ++hunkIt )
+ {
+ DiffHunk* hunk = *hunkIt;
+
+ DifferenceListConstIterator diffIt = hunk->differences().begin();
+ DifferenceListConstIterator dEnd = hunk->differences().end();
+
+ Difference* diff;
+ for( ; diffIt != dEnd; ++diffIt )
+ {
+ diff = *diffIt;
+ if( !diff->applied() )
+ {
+ DifferenceStringListConstIterator stringIt = diff->destinationLines().begin();
+ DifferenceStringListConstIterator sEnd = diff->destinationLines().end();
+ for ( ; stringIt != sEnd; ++stringIt )
+ {
+ list.append( ( *stringIt )->string() );
+ }
+ }
+ else
+ {
+ DifferenceStringListConstIterator stringIt = diff->sourceLines().begin();
+ DifferenceStringListConstIterator sEnd = diff->sourceLines().end();
+ for ( ; stringIt != sEnd; ++stringIt )
+ {
+ list.append( ( *stringIt )->string() );
+ }
+ }
+ }
+ }
+
+ // kdDebug( 8101 ) << "Everything: " << endl << list.join( "\n" ) << endl;
+
+ if( list.count() > 0 )
+ *stream << list.join( "" );
+
+ temp->close();
+ if( temp->status() != 0 ) {
+ emit error( i18n( "<qt>Could not write to the temporary file <b>%1</b>, deleting it.</qt>" ).arg( temp->name() ) );
+ temp->unlink();
+ delete temp;
+ return false;
+ }
+
+ bool result = false;
+
+ if ( m_info.mode == Kompare::ComparingDirs )
+ {
+ QString destination = model->destinationPath() + model->destinationFile();
+ kdDebug(8101) << "Tempfilename : " << temp->name() << endl;
+ kdDebug(8101) << "DestinationURL : " << destination << endl;
+ KIO::UDSEntry entry;
+ if ( !KIO::NetAccess::stat( KURL( destination ).path(), entry, (QWidget*)parent() ) )
+ {
+ if ( !KIO::NetAccess::mkdir( KURL( destination ).path(), (QWidget*)parent() ) )
+ {
+ emit error( i18n( "<qt>Could not create destination directory <b>%1</b>.\nThe file has not been saved.</qt>" ) );
+ return false;
+ }
+ }
+ result = KIO::NetAccess::upload( temp->name(), KURL( destination ), (QWidget*)parent() );
+ }
+ else
+ {
+ kdDebug(8101) << "Tempfilename : " << temp->name() << endl;
+ kdDebug(8101) << "DestinationURL : " << m_destination << endl;
+ result = KIO::NetAccess::upload( temp->name(), KURL( m_destination ), (QWidget*)parent() );
+ }
+
+ if ( !result )
+ {
+ emit error( i18n( "<qt>Could not upload the temporary file to the destination location <b>%1</b>. The temporary file is still available under: <b>%2</b>. You can manually copy it to the right place.</qt>" ).arg( m_destination ).arg( temp->name() ) );
+ }
+ else
+ {
+ //model->slotSetModified( false );
+ temp->unlink();
+ delete temp;
+ }
+
+ return true;
+}
+
+bool KompareModelList::saveAll()
+{
+ if ( !m_models )
+ return false;
+
+ DiffModelListIterator it = m_models->begin();
+ DiffModelListIterator end = m_models->end();
+ for ( ; it != end; ++it )
+ {
+ if( !saveDestination( *it ) )
+ return false;
+ }
+ return true;
+}
+
+void KompareModelList::setEncoding( const QString& encoding )
+{
+ m_encoding = encoding;
+ if ( encoding.lower() == "default" )
+ {
+ m_textCodec = QTextCodec::codecForLocale();
+ }
+ else
+ {
+ kdDebug() << "Encoding : " << encoding << endl;
+ m_textCodec = KGlobal::charsets()->codecForName( encoding.latin1() );
+ kdDebug() << "TextCodec: " << m_textCodec << endl;
+ if ( !m_textCodec )
+ m_textCodec = QTextCodec::codecForLocale();
+ }
+ kdDebug() << "TextCodec: " << m_textCodec << endl;
+}
+
+void KompareModelList::slotDiffProcessFinished( bool success )
+{
+ if ( success )
+ {
+ emit status( Kompare::Parsing );
+ if ( parseDiffOutput( m_diffProcess->diffOutput() ) != 0 )
+ {
+ emit error( i18n( "Could not parse diff output." ) );
+ }
+ else
+ {
+ if ( m_info.mode != Kompare::ShowingDiff )
+ {
+ kdDebug() << "Blend this crap please and dont gimme any conflicts..." << endl;
+ blendOriginalIntoModelList( m_info.localSource );
+ }
+ updateModelListActions();
+ show();
+ }
+ emit status( Kompare::FinishedParsing );
+ }
+ else if ( m_diffProcess->exitStatus() == 0 )
+ {
+ emit error( i18n( "The files are identical." ) );
+ }
+ else
+ {
+ emit error( m_diffProcess->stdErr() );
+ }
+
+ delete m_diffProcess;
+ m_diffProcess = 0;
+}
+
+void KompareModelList::slotDirectoryChanged( const QString& /*dir*/ )
+{
+ // some debug output to see if watching works properly
+ kdDebug(8101) << "Yippie directories are being watched !!! :)" << endl;
+ if ( m_diffProcess )
+ {
+ emit status( Kompare::ReRunningDiff );
+ m_diffProcess->start();
+ }
+}
+
+void KompareModelList::slotFileChanged( const QString& /*file*/ )
+{
+ // some debug output to see if watching works properly
+ kdDebug(8101) << "Yippie files are being watched !!! :)" << endl;
+ if ( m_diffProcess )
+ {
+ emit status( Kompare::ReRunningDiff );
+ m_diffProcess->start();
+ }
+}
+
+QStringList KompareModelList::split( const QString& fileContents )
+{
+ QString contents = fileContents;
+ QStringList list;
+
+ int pos = 0;
+ unsigned int oldpos = 0;
+ // split that does not strip the split char
+#ifdef QT_OS_MAC
+ const char split = '\r';
+#else
+ const char split = '\n';
+#endif
+ while ( ( pos = contents.find( split, oldpos ) ) >= 0 )
+ {
+ list.append( contents.mid( oldpos, pos - oldpos + 1 ) );
+ oldpos = pos + 1;
+ }
+
+ if ( contents.length() > oldpos )
+ {
+ list.append( contents.right( contents.length() - oldpos ) );
+ }
+
+ return list;
+}
+
+QString KompareModelList::readFile( const QString& fileName )
+{
+ QStringList list;
+
+ QFile file( fileName );
+ file.open( IO_ReadOnly );
+
+ QTextStream stream( &file );
+ kdDebug() << "Codec = " << m_textCodec << endl;
+
+ if ( !m_textCodec )
+ m_textCodec = QTextCodec::codecForLocale();
+
+ stream.setCodec( m_textCodec );
+
+ QString contents = stream.read();
+
+ file.close();
+
+ return contents;
+}
+
+bool KompareModelList::openDiff( const QString& diffFile )
+{
+ kdDebug(8101) << "Stupid :) Url = " << diffFile << endl;
+
+ if ( diffFile.isEmpty() )
+ return false;
+
+ QString diff = readFile( diffFile );
+
+ clear(); // Clear the current models
+
+ emit status( Kompare::Parsing );
+
+ if ( parseDiffOutput( diff ) != 0 )
+ {
+ emit error( i18n( "Could not parse diff output." ) );
+ return false;
+ }
+
+ updateModelListActions();
+ show();
+
+ emit status( Kompare::FinishedParsing );
+
+ return true;
+}
+
+QString KompareModelList::recreateDiff() const
+{
+ QString diff;
+
+ DiffModelListConstIterator modelIt = m_models->begin();
+ DiffModelListConstIterator mEnd = m_models->end();
+
+ for ( ; modelIt != mEnd; ++modelIt )
+ {
+ diff += (*modelIt)->recreateDiff();
+ }
+ return diff;
+}
+
+bool KompareModelList::saveDiff( const QString& url, QString directory, DiffSettings* diffSettings )
+{
+ kdDebug() << "KompareModelList::saveDiff: " << endl;
+
+ m_diffTemp = new KTempFile();
+ m_diffURL = url;
+
+ if( m_diffTemp->status() != 0 ) {
+ emit error( i18n( "Could not open a temporary file." ) );
+ m_diffTemp->unlink();
+ delete m_diffTemp;
+ m_diffTemp = 0;
+ return false;
+ }
+
+ m_diffProcess = new KompareProcess( diffSettings, Kompare::Custom, m_source, m_destination, directory );
+ m_diffProcess->setEncoding( m_encoding );
+
+ connect( m_diffProcess, SIGNAL(diffHasFinished( bool )),
+ this, SLOT(slotWriteDiffOutput( bool )) );
+
+ emit status( Kompare::RunningDiff );
+ return m_diffProcess->start();
+}
+
+void KompareModelList::slotWriteDiffOutput( bool success )
+{
+ kdDebug(8101) << "Success = " << success << endl;
+
+ if( success )
+ {
+ QTextStream* stream = m_diffTemp->textStream();
+
+ *stream << m_diffProcess->diffOutput();
+
+ m_diffTemp->close();
+
+ if( m_diffTemp->status() != 0 )
+ {
+ emit error( i18n( "Could not write to the temporary file." ) );
+ }
+
+ KIO::NetAccess::upload( m_diffTemp->name(), KURL( m_diffURL ), (QWidget*)parent() );
+
+ emit status( Kompare::FinishedWritingDiff );
+ }
+
+ m_diffURL.truncate( 0 );
+ m_diffTemp->unlink();
+
+ delete m_diffTemp;
+ m_diffTemp = 0;
+
+ delete m_diffProcess;
+ m_diffProcess = 0;
+}
+
+void KompareModelList::slotSelectionChanged( const Diff2::DiffModel* model, const Diff2::Difference* diff )
+{
+// This method will signal all the other objects about a change in selection,
+// it will emit setSelection( const DiffModel*, const Difference* ) to all who are connected
+ kdDebug(8101) << "KompareModelList::slotSelectionChanged( " << model << ", " << diff << " )" << endl;
+ kdDebug(8101) << "Sender is : " << sender()->className() << endl;
+// kdDebug(8101) << kdBacktrace() << endl;
+
+ m_selectedModel = const_cast<DiffModel*>(model);
+ m_modelIndex = m_models->findIndex( m_selectedModel );
+ kdDebug( 8101 ) << "m_modelIndex = " << m_modelIndex << endl;
+ m_selectedDifference = const_cast<Difference*>(diff);
+
+ m_selectedModel->setSelectedDifference( m_selectedDifference );
+
+ // setSelected* search for the argument in the lists and return false if not found
+ // if found they return true and set the m_selected*
+ if ( !setSelectedModel( m_selectedModel ) )
+ {
+ // Backup plan
+ m_selectedModel = firstModel();
+ m_selectedDifference = m_selectedModel->firstDifference();
+ }
+ else if ( !m_selectedModel->setSelectedDifference( m_selectedDifference ) )
+ {
+ // Another backup plan
+ m_selectedDifference = m_selectedModel->firstDifference();
+ }
+
+ emit setSelection( model, diff );
+ emit setStatusBarModelInfo( findModel( m_selectedModel ), m_selectedModel->findDifference( m_selectedDifference ), modelCount(), differenceCount(), m_selectedModel->appliedCount() );
+
+ updateModelListActions();
+}
+
+void KompareModelList::slotSelectionChanged( const Diff2::Difference* diff )
+{
+// This method will emit setSelection( const Difference* ) to whomever is listening
+// when for instance in kompareview the selection has changed
+ kdDebug(8101) << "KompareModelList::slotSelectionChanged( " << diff << " )" << endl;
+ kdDebug(8101) << "Sender is : " << sender()->className() << endl;
+
+ m_selectedDifference = const_cast<Difference*>(diff);
+
+ if ( !m_selectedModel->setSelectedDifference( m_selectedDifference ) )
+ {
+ // Backup plan
+ m_selectedDifference = m_selectedModel->firstDifference();
+ }
+
+ emit setSelection( diff );
+ emit setStatusBarModelInfo( findModel( m_selectedModel ), m_selectedModel->findDifference( m_selectedDifference ), modelCount(), differenceCount(), m_selectedModel->appliedCount() );
+
+ updateModelListActions();
+}
+
+void KompareModelList::slotPreviousModel()
+{
+ if ( ( m_selectedModel = prevModel() ) != 0 )
+ {
+ m_selectedDifference = m_selectedModel->firstDifference();
+ }
+ else
+ {
+ m_selectedModel = firstModel();
+ m_selectedDifference = m_selectedModel->firstDifference();
+ }
+
+ emit setSelection( m_selectedModel, m_selectedDifference );
+ emit setStatusBarModelInfo( findModel( m_selectedModel ), m_selectedModel->findDifference( m_selectedDifference ), modelCount(), differenceCount(), m_selectedModel->appliedCount() );
+ updateModelListActions();
+}
+
+void KompareModelList::slotNextModel()
+{
+ if ( ( m_selectedModel = nextModel() ) != 0 )
+ {
+ m_selectedDifference = m_selectedModel->firstDifference();
+ }
+ else
+ {
+ m_selectedModel = lastModel();
+ m_selectedDifference = m_selectedModel->firstDifference();
+ }
+
+ emit setSelection( m_selectedModel, m_selectedDifference );
+ emit setStatusBarModelInfo( findModel( m_selectedModel ), m_selectedModel->findDifference( m_selectedDifference ), modelCount(), differenceCount(), m_selectedModel->appliedCount() );
+ updateModelListActions();
+}
+
+DiffModel* KompareModelList::firstModel()
+{
+ kdDebug( 8101 ) << "KompareModelList::firstModel()" << endl;
+ m_modelIndex = 0;
+ kdDebug( 8101 ) << "m_modelIndex = " << m_modelIndex << endl;
+
+ m_selectedModel = m_models->first();
+
+ return m_selectedModel;
+}
+
+DiffModel* KompareModelList::lastModel()
+{
+ kdDebug( 8101 ) << "KompareModelList::lastModel()" << endl;
+ m_modelIndex = m_models->count() - 1;
+ kdDebug( 8101 ) << "m_modelIndex = " << m_modelIndex << endl;
+
+ m_selectedModel = m_models->last();
+
+ return m_selectedModel;
+}
+
+DiffModel* KompareModelList::prevModel()
+{
+ kdDebug( 8101 ) << "KompareModelList::prevModel()" << endl;
+ if ( --m_modelIndex < m_models->count() )
+ {
+ kdDebug( 8101 ) << "m_modelIndex = " << m_modelIndex << endl;
+ m_selectedModel = (*m_models)[ m_modelIndex ];
+ }
+ else
+ {
+ m_selectedModel = 0;
+ m_modelIndex = 0;
+ kdDebug( 8101 ) << "m_modelIndex = " << m_modelIndex << endl;
+ }
+
+ return m_selectedModel;
+}
+
+DiffModel* KompareModelList::nextModel()
+{
+ kdDebug( 8101 ) << "KompareModelList::nextModel()" << endl;
+ if ( ++m_modelIndex < m_models->count() )
+ {
+ kdDebug( 8101 ) << "m_modelIndex = " << m_modelIndex << endl;
+ m_selectedModel = (*m_models)[ m_modelIndex ];
+ }
+ else
+ {
+ m_selectedModel = 0;
+ m_modelIndex = 0;
+ kdDebug( 8101 ) << "m_modelIndex = " << m_modelIndex << endl;
+ }
+
+ return m_selectedModel;
+}
+
+void KompareModelList::slotPreviousDifference()
+{
+ kdDebug(8101) << "slotPreviousDifference called" << endl;
+ if ( ( m_selectedDifference = m_selectedModel->prevDifference() ) != 0 )
+ {
+ emit setSelection( m_selectedDifference );
+ emit setStatusBarModelInfo( findModel( m_selectedModel ), m_selectedModel->findDifference( m_selectedDifference ), modelCount(), differenceCount(), m_selectedModel->appliedCount() );
+ updateModelListActions();
+ return;
+ }
+
+ kdDebug(8101) << "**** no previous difference... ok lets find the previous model..." << endl;
+
+ if ( ( m_selectedModel = prevModel() ) != 0 )
+ {
+ m_selectedDifference = m_selectedModel->lastDifference();
+
+ emit setSelection( m_selectedModel, m_selectedDifference );
+ emit setStatusBarModelInfo( findModel( m_selectedModel ), m_selectedModel->findDifference( m_selectedDifference ), modelCount(), differenceCount(), m_selectedModel->appliedCount() );
+ updateModelListActions();
+ return;
+ }
+
+
+ kdDebug(8101) << "**** !!! No previous model, ok backup plan activated..." << endl;
+
+ // Backup plan
+ m_selectedModel = firstModel();
+ m_selectedDifference = m_selectedModel->firstDifference();
+
+ emit setSelection( m_selectedModel, m_selectedDifference );
+ emit setStatusBarModelInfo( findModel( m_selectedModel ), m_selectedModel->findDifference( m_selectedDifference ), modelCount(), differenceCount(), m_selectedModel->appliedCount() );
+ updateModelListActions();
+}
+
+void KompareModelList::slotNextDifference()
+{
+ kdDebug(8101) << "slotNextDifference called" << endl;
+ if ( ( m_selectedDifference = m_selectedModel->nextDifference() ) != 0 )
+ {
+ emit setSelection( m_selectedDifference );
+ emit setStatusBarModelInfo( findModel( m_selectedModel ), m_selectedModel->findDifference( m_selectedDifference ), modelCount(), differenceCount(), m_selectedModel->appliedCount() );
+ updateModelListActions();
+ return;
+ }
+
+ kdDebug(8101) << "**** no next difference... ok lets find the next model..." << endl;
+
+ if ( ( m_selectedModel = nextModel() ) != 0 )
+ {
+ m_selectedDifference = m_selectedModel->firstDifference();
+
+ emit setSelection( m_selectedModel, m_selectedDifference );
+ emit setStatusBarModelInfo( findModel( m_selectedModel ), m_selectedModel->findDifference( m_selectedDifference ), modelCount(), differenceCount(), m_selectedModel->appliedCount() );
+ updateModelListActions();
+ return;
+ }
+
+ kdDebug(8101) << "**** !!! No next model, ok backup plan activated..." << endl;
+
+ // Backup plan
+ m_selectedModel = lastModel();
+ m_selectedDifference = m_selectedModel->lastDifference();
+
+ emit setSelection( m_selectedModel, m_selectedDifference );
+ emit setStatusBarModelInfo( findModel( m_selectedModel ), m_selectedModel->findDifference( m_selectedDifference ), modelCount(), differenceCount(), m_selectedModel->appliedCount() );
+ updateModelListActions();
+}
+
+void KompareModelList::slotApplyDifference( bool apply )
+{
+ m_selectedModel->applyDifference( apply );
+ emit applyDifference( apply );
+}
+
+void KompareModelList::slotApplyAllDifferences( bool apply )
+{
+ m_selectedModel->applyAllDifferences( apply );
+ emit applyAllDifferences( apply );
+}
+
+int KompareModelList::parseDiffOutput( const QString& diff )
+{
+ kdDebug(8101) << "KompareModelList::parseDiffOutput" << endl;
+
+ QStringList diffLines = split( diff );
+
+ Parser* parser = new Parser( this );
+ m_models = parser->parse( diffLines );
+
+ m_info.generator = parser->generator();
+ m_info.format = parser->format();
+
+ delete parser;
+
+ if ( m_models )
+ {
+ m_selectedModel = firstModel();
+ kdDebug(8101) << "Ok there are differences..." << endl;
+ m_selectedDifference = m_selectedModel->firstDifference();
+ emit setStatusBarModelInfo( 0, 0, modelCount(), differenceCount(), 0);
+ }
+ else
+ {
+ // Wow trouble, no models, so no differences...
+ kdDebug(8101) << "Now i'll be damned, there should be models here !!!" << endl;
+ return -1;
+ }
+
+ return 0;
+}
+
+bool KompareModelList::blendOriginalIntoModelList( const QString& localURL )
+{
+ kdDebug() << "Hurrah we are blending..." << endl;
+ QFileInfo fi( localURL );
+
+ bool result = false;
+ DiffModel* model;
+
+ QString fileContents;
+
+ if ( fi.isDir() )
+ { // is a dir
+ kdDebug() << "Blend Dir" << endl;
+// QDir dir( localURL, QString::null, QDir::Name|QDir::DirsFirst, QDir::All );
+ DiffModelListIterator modelIt = m_models->begin();
+ DiffModelListIterator mEnd = m_models->end();
+ for ( ; modelIt != mEnd; ++modelIt )
+ {
+ model = *modelIt;
+ kdDebug(8101) << "Model : " << model << endl;
+ QString filename = model->sourcePath() + model->sourceFile();
+ if ( !filename.startsWith( localURL ) )
+ filename.prepend( localURL );
+ QFileInfo fi2( filename );
+ if ( fi2.exists() )
+ {
+ kdDebug(8101) << "Reading from: " << filename << endl;
+ fileContents = readFile( filename );
+ result = blendFile( model, fileContents );
+ }
+ else
+ {
+ kdDebug(8101) << "File " << filename << " does not exist !" << endl;
+ kdDebug(8101) << "Assume empty file !" << endl;
+ fileContents.truncate( 0 );
+ result = blendFile( model, fileContents );
+ }
+ }
+ kdDebug() << "End of Blend Dir" << endl;
+ }
+ else if ( fi.isFile() )
+ { // is a file
+ kdDebug() << "Blend File" << endl;
+ kdDebug(8101) << "Reading from: " << localURL << endl;
+ fileContents = readFile( localURL );
+
+ result = blendFile( (*m_models)[ 0 ], fileContents );
+ kdDebug() << "End of Blend File" << endl;
+ }
+
+ return result;
+}
+
+bool KompareModelList::blendFile( DiffModel* model, const QString& fileContents )
+{
+ if ( !model )
+ {
+ kdDebug() << "**** model is null :(" << endl;
+ return false;
+ }
+
+ model->setBlended( true );
+
+ int srcLineNo = 1, destLineNo = 1;
+
+ QStringList lines = split( fileContents );
+
+ QStringList::ConstIterator linesIt = lines.begin();
+ QStringList::ConstIterator lEnd = lines.end();
+
+ DiffHunkList* hunks = model->hunks();
+ kdDebug(8101) << "Hunks in hunklist: " << hunks->count() << endl;
+ DiffHunkListIterator hunkIt = hunks->begin();
+
+ DiffHunk* newHunk = 0;
+ Difference* newDiff = 0;
+
+ // FIXME: this approach is not very good, we should first check if the hunk applies cleanly
+ // and without offset and if not use that new linenumber with offset to compare against
+ // This will only work for files we just diffed with kompare but not for blending where
+ // file(s) to patch has/have potentially changed
+
+ for ( ; hunkIt != hunks->end(); ++hunkIt )
+ {
+ // Do we need to insert a new hunk before this one ?
+ DiffHunk* hunk = *hunkIt;
+ if ( srcLineNo < hunk->sourceLineNumber() )
+ {
+ newHunk = new DiffHunk( srcLineNo, destLineNo, "", DiffHunk::AddedByBlend );
+
+ hunks->insert( hunkIt, newHunk );
+
+ newDiff = new Difference( srcLineNo, destLineNo,
+ Difference::Unchanged );
+
+ newHunk->add( newDiff );
+
+ while ( srcLineNo < hunk->sourceLineNumber() && linesIt != lEnd )
+ {
+ newDiff->addSourceLine( *linesIt );
+ newDiff->addDestinationLine( *linesIt );
+ srcLineNo++;
+ destLineNo++;
+ ++linesIt;
+ }
+ }
+
+ // Now we add the linecount difference for the hunk that follows
+ int size = hunk->sourceLineCount();
+
+ for ( int i = 0; i < size; ++i )
+ {
+ ++linesIt;
+ }
+
+ srcLineNo += size;
+ destLineNo += (*hunkIt)->destinationLineCount();
+ }
+
+ if ( linesIt != lEnd )
+ {
+ newHunk = new DiffHunk( srcLineNo, destLineNo, "", DiffHunk::AddedByBlend );
+
+ model->addHunk( newHunk );
+
+ newDiff = new Difference( srcLineNo, destLineNo, Difference::Unchanged );
+
+ newHunk->add( newDiff );
+
+ while ( linesIt != lEnd )
+ {
+ newDiff->addSourceLine( *linesIt );
+ newDiff->addDestinationLine( *linesIt );
+ ++linesIt;
+ }
+ }
+#if 0
+ DifferenceList hunkDiffList = (*hunkIt)->differences();
+ DifferenceListIterator diffIt = hunkDiffList.begin();
+ DifferenceListIterator dEnd = hunkDiffList.end();
+ kdDebug() << "Number of differences in hunkDiffList = " << diffList.count() << endl;
+
+ DifferenceListIterator tempIt;
+ Difference* diff;
+
+ for ( ; diffIt != dEnd; ++diffIt )
+ {
+ diff = *diffIt;
+ kdDebug() << "*(Diff it) = " << diff << endl;
+ // Check if there are lines in the original file before the difference
+ // that are not yet in the diff. If so create new Unchanged diff
+ if ( srcLineNo < diff->sourceLineNumber() )
+ {
+ newDiff = new Difference( srcLineNo, destLineNo,
+ Difference::Unchanged | Difference::AddedByBlend );
+ newHunk->add( newDiff );
+ while ( srcLineNo < diff->sourceLineNumber() && linesIt != lEnd )
+ {
+// kdDebug(8101) << "SourceLine = " << srcLineNo << ": " << *linesIt << endl;
+ newDiff->addSourceLine( *linesIt );
+ newDiff->addDestinationLine( *linesIt );
+ srcLineNo++;
+ destLineNo++;
+ ++linesIt;
+ }
+ }
+ // Now i've got to add that diff
+ switch ( diff->type() )
+ {
+ case Difference::Unchanged:
+ kdDebug(8101) << "Unchanged" << endl;
+ for ( int i = 0; i < diff->sourceLineCount(); i++ )
+ {
+ if ( linesIt != lEnd && *linesIt != diff->sourceLineAt( i )->string() )
+ {
+ kdDebug(8101) << "Conflict: SourceLine = " << srcLineNo << ": " << *linesIt << endl;
+ kdDebug(8101) << "Conflict: DiffLine = " << diff->sourceLineNumber() + i << ": " << diff->sourceLineAt( i )->string() << endl;
+
+ // Do conflict resolution (well sort of)
+ diff->sourceLineAt( i )->setConflictString( *linesIt );
+ diff->setConflict( true );
+ }
+// kdDebug(8101) << "SourceLine = " << srcLineNo << ": " << *linesIt << endl;
+// kdDebug(8101) << "DiffLine = " << diff->sourceLineNumber() + i << ": " << diff->sourceLineAt( i )->string() << endl;
+ srcLineNo++;
+ destLineNo++;
+ ++linesIt;
+ }
+
+ tempIt = diffIt;
+ --diffIt;
+ diffList.remove( tempIt );
+ newHunk->add( diff );
+
+ break;
+ case Difference::Change:
+ kdDebug(8101) << "Change" << endl;
+
+ //QStringListConstIterator saveIt = linesIt;
+
+ for ( int i = 0; i < diff->sourceLineCount(); i++ )
+ {
+ if ( linesIt != lEnd && *linesIt != diff->sourceLineAt( i )->string() )
+ {
+ kdDebug(8101) << "Conflict: SourceLine = " << srcLineNo << ": " << *linesIt << endl;
+ kdDebug(8101) << "Conflict: DiffLine = " << diff->sourceLineNumber() + i << ": " << diff->sourceLineAt( i )->string() << endl;
+
+ // Do conflict resolution (well sort of)
+ diff->sourceLineAt( i )->setConflictString( *linesIt );
+ diff->setConflict( true );
+ }
+ srcLineNo++;
+ destLineNo++;
+ ++linesIt;
+ }
+
+ destLineNo += diff->destinationLineCount();
+
+ tempIt = diffIt;
+ --diffIt;
+ diffList.remove( tempIt );
+ newHunk->add( diff );
+ newModel->addDiff( diff );
+
+ break;
+ case Difference::Insert:
+ kdDebug(8101) << "Insert" << endl;
+ destLineNo += diff->destinationLineCount();
+ tempIt = diffIt;
+ --diffIt;
+ diffList.remove( tempIt );
+ newHunk->add( diff );
+ newModel->addDiff( diff );
+ break;
+ case Difference::Delete:
+ kdDebug(8101) << "Delete" << endl;
+ kdDebug(8101) << "Number of lines in Delete: " << diff->sourceLineCount() << endl;
+ for ( int i = 0; i < diff->sourceLineCount(); i++ )
+ {
+ if ( linesIt != lEnd && *linesIt != diff->sourceLineAt( i )->string() )
+ {
+ kdDebug(8101) << "Conflict: SourceLine = " << srcLineNo << ": " << *linesIt << endl;
+ kdDebug(8101) << "Conflict: DiffLine = " << diff->sourceLineNumber() + i << ": " << diff->sourceLineAt( i )->string() << endl;
+
+ // Do conflict resolution (well sort of)
+ diff->sourceLineAt( i )->setConflictString( *linesIt );
+ diff->setConflict( true );
+ }
+
+// kdDebug(8101) << "SourceLine = " << srcLineNo << ": " << *it << endl;
+// kdDebug(8101) << "DiffLine = " << diff->sourceLineNumber() + i << ": " << diff->sourceLineAt( i )->string() << endl;
+ srcLineNo++;
+ ++linesIt;
+ }
+
+ tempIt = diffIt;
+ --diffIt;
+ diffList.remove( tempIt );
+ newHunk->add( diff );
+ newModel->addDiff( diff );
+ break;
+ default:
+ kdDebug(8101) << "****, some diff type we dont know about ???" << endl;
+ }
+ }
+ }
+#endif
+
+/*
+ diffList = newModel->differences();
+
+ diff = diffList.first();
+ kdDebug(8101) << "Count = " << diffList.count() << endl;
+ for ( diff = diffList.first(); diff; diff = diffList.next() )
+ {
+ kdDebug(8101) << "sourcelinenumber = " << diff->sourceLineNumber() << endl;
+ }
+*/
+
+ m_selectedModel = firstModel();
+
+ m_selectedDifference = m_selectedModel->firstDifference();
+
+ return true;
+}
+
+void KompareModelList::show()
+{
+ kdDebug() << "KompareModelList::Show Number of models = " << m_models->count() << endl;
+ emit modelsChanged( m_models );
+ emit setSelection( m_selectedModel, m_selectedDifference );
+}
+
+void KompareModelList::clear()
+{
+ if ( m_models )
+ m_models->clear();
+
+ emit modelsChanged( m_models );
+}
+
+void KompareModelList::swap()
+{
+ QString source = m_source;
+ QString destination = m_destination;
+ if ( m_info.mode == Kompare::ComparingFiles )
+ compareFiles( destination, source );
+ else if ( m_info.mode == Kompare::ComparingDirs )
+ compareDirs( destination, source );
+}
+
+bool KompareModelList::isModified() const
+{
+ if ( m_noOfModified > 0 )
+ return true;
+ return false;
+}
+
+int KompareModelList::modelCount() const
+{
+ return m_models ? m_models->count() : 0;
+}
+
+int KompareModelList::differenceCount() const
+{
+ return m_selectedModel ? m_selectedModel->differenceCount() : -1;
+}
+
+int KompareModelList::appliedCount() const
+{
+ return m_selectedModel ? m_selectedModel->appliedCount() : -1;
+}
+
+void KompareModelList::slotSetModified( bool modified )
+{
+ kdDebug(8101) << "KompareModelList::slotSetModified( " << modified << " );" << endl;
+ kdDebug(8101) << "Before: m_noOfModified = " << m_noOfModified << endl;
+
+ // If selectedModel emits its signal setModified it does not set the model
+ // internal m_modified bool yet, it only does that after the emit.
+ if ( modified && !m_selectedModel->isModified() )
+ m_noOfModified++;
+ else if ( !modified && m_selectedModel->isModified() )
+ m_noOfModified--;
+
+ kdDebug(8101) << "After : m_noOfModified = " << m_noOfModified << endl;
+
+ if ( m_noOfModified < 0 )
+ {
+ kdDebug(8101) << "Wow something is ****ed up..." << endl;
+ }
+ else if ( m_noOfModified == 0 )
+ {
+ emit setModified( false );
+ }
+ else // > 0 :-)
+ {
+ emit setModified( true );
+ }
+}
+
+bool KompareModelList::setSelectedModel( DiffModel* model )
+{
+ kdDebug(8101) << "KompareModelList::setSelectedModel( " << model << " )" << endl;
+
+ if ( model != m_selectedModel )
+ {
+ if ( m_models->findIndex( model ) == -1 )
+ return false;
+ kdDebug(8101) << "m_selectedModel (was) = " << m_selectedModel << endl;
+ m_modelIndex = m_models->findIndex( model );
+ kdDebug(8101) << "m_selectedModel (is) = " << m_selectedModel << endl;
+ m_selectedModel = model;
+ }
+
+ updateModelListActions();
+
+ return true;
+}
+
+void KompareModelList::updateModelListActions()
+{
+ if ( m_models && m_selectedModel && m_selectedDifference )
+ {
+ if ( ( ( KomparePart* )parent() )->isReadWrite() )
+ {
+ if ( m_selectedModel->appliedCount() != m_selectedModel->differenceCount() )
+ m_applyAll->setEnabled( true );
+ else
+ m_applyAll->setEnabled( false );
+
+ if ( m_selectedModel->appliedCount() != 0 )
+ m_unapplyAll->setEnabled( true );
+ else
+ m_unapplyAll->setEnabled( false );
+
+ m_applyDifference->setEnabled( true );
+ m_unApplyDifference->setEnabled( true );
+ m_save->setEnabled( m_selectedModel->isModified() );
+ }
+ else
+ {
+ m_applyDifference->setEnabled ( false );
+ m_unApplyDifference->setEnabled( false );
+ m_applyAll->setEnabled ( false );
+ m_unapplyAll->setEnabled ( false );
+ m_save->setEnabled ( false );
+ }
+
+ m_previousFile->setEnabled ( hasPrevModel() );
+ m_nextFile->setEnabled ( hasNextModel() );
+ m_previousDifference->setEnabled( hasPrevDiff() );
+ m_nextDifference->setEnabled ( hasNextDiff() );
+ }
+ else
+ {
+ m_applyDifference->setEnabled ( false );
+ m_unApplyDifference->setEnabled ( false );
+ m_applyAll->setEnabled ( false );
+ m_unapplyAll->setEnabled ( false );
+
+ m_previousFile->setEnabled ( false );
+ m_nextFile->setEnabled ( false );
+ m_previousDifference->setEnabled( false );
+ m_nextDifference->setEnabled ( false );
+ m_save->setEnabled ( false );
+ }
+}
+
+bool KompareModelList::hasPrevModel() const
+{
+ kdDebug(8101) << "KompareModelList::hasPrevModel()" << endl;
+
+ if ( m_modelIndex > 0 )
+ {
+// kdDebug(8101) << "has prev model" << endl;
+ return true;
+ }
+
+// kdDebug(8101) << "doesn't have a prev model, this is the first one..." << endl;
+
+ return false;
+}
+
+bool KompareModelList::hasNextModel() const
+{
+ kdDebug(8101) << "KompareModelList::hasNextModel()" << endl;
+
+ if ( ( unsigned int )m_modelIndex < ( m_models->count() - 1 ) )
+ {
+// kdDebug(8101) << "has next model" << endl;
+ return true;
+ }
+
+// kdDebug(8101) << "doesn't have a next model, this is the last one..." << endl;
+ return false;
+}
+
+bool KompareModelList::hasPrevDiff() const
+{
+// kdDebug(8101) << "KompareModelList::hasPrevDiff()" << endl;
+ int index = m_selectedModel->diffIndex();
+
+ if ( index > 0 )
+ {
+// kdDebug(8101) << "has prev difference in same model" << endl;
+ return true;
+ }
+
+ if ( hasPrevModel() )
+ {
+// kdDebug(8101) << "has prev difference but in prev model" << endl;
+ return true;
+ }
+
+// kdDebug(8101) << "doesn't have a prev difference, not even in the previous model because there is no previous model" << endl;
+
+ return false;
+}
+
+bool KompareModelList::hasNextDiff() const
+{
+// kdDebug(8101) << "KompareModelList::hasNextDiff()" << endl;
+ int index = m_selectedModel->diffIndex();
+
+ if ( index < ( m_selectedModel->differenceCount() - 1 ) )
+ {
+// kdDebug(8101) << "has next difference in same model" << endl;
+ return true;
+ }
+
+ if ( hasNextModel() )
+ {
+// kdDebug(8101) << "has next difference but in next model" << endl;
+ return true;
+ }
+
+// kdDebug(8101) << "doesn't have a next difference, not even in next model because there is no next model" << endl;
+
+ return false;
+}
+
+void KompareModelList::slotActionApplyDifference()
+{
+ if ( !m_selectedDifference->applied() )
+ slotApplyDifference( true );
+ slotNextDifference();
+ updateModelListActions();
+}
+
+void KompareModelList::slotActionUnApplyDifference()
+{
+ if ( m_selectedDifference->applied() )
+ slotApplyDifference( false );
+ slotPreviousDifference();
+ updateModelListActions();
+}
+
+void KompareModelList::slotActionApplyAllDifferences()
+{
+ slotApplyAllDifferences( true );
+ updateModelListActions();
+}
+
+void KompareModelList::slotActionUnapplyAllDifferences()
+{
+ slotApplyAllDifferences( false );
+ updateModelListActions();
+}
+
+#include "komparemodellist.moc"
+
+/* vim: set ts=4 sw=4 noet: */
diff --git a/kompare/libdiff2/komparemodellist.h b/kompare/libdiff2/komparemodellist.h
new file mode 100644
index 00000000..8ba264fb
--- /dev/null
+++ b/kompare/libdiff2/komparemodellist.h
@@ -0,0 +1,213 @@
+/***************************************************************************
+ komparemodellist.h - description
+ -------------------
+ begin : Tue Jun 26 2001
+ copyright : (C) 2001-2003 by John Firebaugh
+ and Otto Bruggeman
+ email : jfirebaugh@kde.org
+ otto.bruggeman@home.nl
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the 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 KOMPAREMODELLIST_H
+#define KOMPAREMODELLIST_H
+
+#include <qobject.h>
+
+#include "diffmodel.h"
+#include "diffmodellist.h"
+#include "kompare.h"
+
+class QFile;
+
+class KAction;
+class KDirWatch;
+class KTempFile;
+
+class DiffSettings;
+class KompareProcess;
+
+namespace Diff2
+{
+
+class KompareModelList : public QObject
+{
+ Q_OBJECT
+public:
+ KompareModelList( DiffSettings* diffSettings, struct Kompare::Info& info, QObject* parent = 0, const char* name = 0 );
+ ~KompareModelList();
+
+public:
+ // Swap source with destination and show differences
+ void swap();
+
+ /* Comparing methods */
+ bool compare( const QString& source, const QString& destination );
+
+ bool compareFiles( const QString& source, const QString& destination );
+ bool compareDirs( const QString& source, const QString& destination );
+
+ bool openDiff( const QString& diff );
+
+ bool openFileAndDiff( const QString& file, const QString& diff );
+ bool openDirAndDiff( const QString& dir, const QString& diff );
+
+ bool saveDiff( const QString& url, QString directory, DiffSettings* diffSettings );
+ bool saveAll();
+
+ bool saveDestination( DiffModel* model );
+
+ void setEncoding( const QString& encoding );
+
+ QString recreateDiff() const;
+
+ // This parses the difflines and creates new models
+ int parseDiffOutput( const QString& diff );
+
+ // Call this to emit the signals to the rest of the "world" to show the diff
+ void show();
+
+ // This will blend the original URL (dir or file) into the diffmodel,
+ // this is like patching but with a twist
+ bool blendOriginalIntoModelList( const QString& localURL );
+
+ enum Kompare::Mode mode() const { return m_info.mode; };
+ const DiffModelList* models() const { return m_models; };
+
+ int modelCount() const;
+ int differenceCount() const;
+ int appliedCount() const;
+
+ const DiffModel* modelAt( int i ) const { return *( m_models->at( i ) ); };
+ int findModel( DiffModel* model ) const { return m_models->findIndex( model ); };
+
+ bool isModified() const;
+
+ int currentModel() const { return m_models->findIndex( m_selectedModel ); };
+ int currentDifference() const { return m_selectedModel ? m_selectedModel->findDifference( m_selectedDifference ) : -1; };
+
+ const DiffModel* selectedModel() const { return m_selectedModel; };
+ const Difference* selectedDifference() const { return m_selectedDifference; };
+
+ void clear();
+
+private:
+ Diff2::DiffModel* firstModel();
+ Diff2::DiffModel* lastModel();
+ Diff2::DiffModel* prevModel();
+ Diff2::DiffModel* nextModel();
+
+ bool setSelectedModel( Diff2::DiffModel* model );
+
+ void updateModelListActions();
+
+protected:
+ bool blendFile( DiffModel* model, const QString& lines );
+
+signals:
+ void status( Kompare::Status status );
+ void setStatusBarModelInfo( int modelIndex, int differenceIndex, int modelCount, int differenceCount, int appliedCount );
+ void error( QString error );
+ void modelsChanged( const Diff2::DiffModelList* models );
+ void setSelection( const Diff2::DiffModel* model, const Diff2::Difference* diff );
+ void setSelection( const Diff2::Difference* diff );
+ void applyDifference( bool apply );
+ void applyAllDifferences( bool apply );
+ void applyDifference( const Diff2::Difference* diff, bool apply );
+
+ // Emits true when m_noOfModified > 0, false when m_noOfModified == 0
+ void setModified( bool modified );
+
+public slots:
+ void slotSelectionChanged( const Diff2::DiffModel* model, const Diff2::Difference* diff );
+ void slotSelectionChanged( const Diff2::Difference* diff );
+
+ void slotApplyDifference( bool apply );
+ void slotApplyAllDifferences( bool apply );
+ void slotPreviousModel();
+ void slotNextModel();
+ void slotPreviousDifference();
+ void slotNextDifference();
+
+ // This slot is called by the diffmodels whenever their status changes to modified or unmodified
+ void slotSetModified( bool modified );
+
+protected slots:
+ void slotDiffProcessFinished( bool success );
+ void slotWriteDiffOutput( bool success );
+
+ void slotActionApplyDifference();
+ void slotActionUnApplyDifference();
+ void slotActionApplyAllDifferences();
+ void slotActionUnapplyAllDifferences();
+
+ /** Save the currently selected destination in a multi-file diff,
+ or the single destination if a single file diff. */
+ void slotSaveDestination();
+
+private slots:
+ void slotDirectoryChanged( const QString& );
+ void slotFileChanged( const QString& );
+
+private: // Helper methods
+ bool isDirectory( const QString& url ) const;
+ bool isDiff( const QString& mimetype ) const;
+ QString readFile( const QString& fileName );
+
+ bool hasPrevModel() const;
+ bool hasNextModel() const;
+ bool hasPrevDiff() const;
+ bool hasNextDiff() const;
+
+ QStringList split( const QString& diff );
+
+private:
+ KTempFile* m_diffTemp;
+ QString m_diffURL;
+
+ KompareProcess* m_diffProcess;
+
+ DiffSettings* m_diffSettings;
+
+ DiffModelList* m_models;
+
+ QString m_source;
+ QString m_destination;
+
+ DiffModel* m_selectedModel;
+ Difference* m_selectedDifference;
+
+ KDirWatch* m_dirWatch;
+ KDirWatch* m_fileWatch;
+
+ int m_noOfModified;
+ unsigned int m_modelIndex;
+
+ struct Kompare::Info& m_info;
+
+ KAction* m_applyDifference;
+ KAction* m_unApplyDifference;
+ KAction* m_applyAll;
+ KAction* m_unapplyAll;
+ KAction* m_previousFile;
+ KAction* m_nextFile;
+ KAction* m_previousDifference;
+ KAction* m_nextDifference;
+
+ KAction* m_save;
+
+ QString m_encoding;
+ QTextCodec* m_textCodec;
+};
+
+} // End of namespace Diff2
+
+#endif
diff --git a/kompare/libdiff2/kompareprocess.cpp b/kompare/libdiff2/kompareprocess.cpp
new file mode 100644
index 00000000..2d5eac00
--- /dev/null
+++ b/kompare/libdiff2/kompareprocess.cpp
@@ -0,0 +1,269 @@
+/***************************************************************************
+ kompareprocess.cpp - description
+ -------------------
+ begin : Sun Mar 4 2001
+ copyright : (C) 2001-2003 by Otto Bruggeman
+ and John Firebaugh
+ (C) 2007 Kevin Kofler
+ email : otto.bruggeman@home.nl
+ jfirebaugh@kde.org
+ kevin.kofler@chello.at
+****************************************************************************/
+
+/***************************************************************************
+**
+** This program is free software; you can redistribute it and/or modify
+** it under the terms of the 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 <qdir.h>
+#include <qstringlist.h>
+#include <qtextcodec.h>
+
+#include <kcharsets.h>
+#include <kdebug.h>
+#include <kglobal.h>
+
+#include "diffsettings.h"
+#include "kompareprocess.h"
+
+KompareProcess::KompareProcess( DiffSettings* diffSettings, enum Kompare::DiffMode mode, QString source, QString destination, QString dir )
+ : KProcess(),
+ m_diffSettings( diffSettings ),
+ m_mode( mode ),
+ m_textDecoder( 0 )
+{
+ setUseShell( true );
+
+ // connect the stdout and stderr signals
+ connect( this, SIGNAL( receivedStdout( KProcess*, char*, int ) ),
+ SLOT ( slotReceivedStdout( KProcess*, char*, int ) ) );
+ connect( this, SIGNAL( receivedStderr( KProcess*, char*, int ) ),
+ SLOT ( slotReceivedStderr( KProcess*, char*, int ) ) );
+
+ // connect the signal that indicates that the proces has exited
+ connect( this, SIGNAL( processExited( KProcess* ) ),
+ SLOT ( slotProcessExited( KProcess* ) ) );
+
+ *this << "LANG=C";
+
+ // Write command and options
+ if( m_mode == Kompare::Default )
+ {
+ writeDefaultCommandLine();
+ }
+ else
+ {
+ writeCommandLine();
+ }
+
+ if( !dir.isEmpty() ) {
+ QDir::setCurrent( dir );
+ }
+
+ // Write file names
+ *this << "--";
+ *this << KProcess::quote( constructRelativePath( dir, source ) );
+ *this << KProcess::quote( constructRelativePath( dir, destination ) );
+}
+
+void KompareProcess::writeDefaultCommandLine()
+{
+ if ( !m_diffSettings || m_diffSettings->m_diffProgram.isEmpty() )
+ {
+ *this << "diff" << "-dr";
+ }
+ else
+ {
+ *this << m_diffSettings->m_diffProgram << "-dr";
+ }
+
+ *this << "-U" << QString::number( m_diffSettings->m_linesOfContext );
+}
+
+void KompareProcess::writeCommandLine()
+{
+ // load the executable into the KProcess
+ if ( m_diffSettings->m_diffProgram.isEmpty() )
+ {
+ kdDebug(8101) << "Using the first diff in the path..." << endl;
+ *this << "diff";
+ }
+ else
+ {
+ kdDebug(8101) << "Using a user specified diff, namely: " << m_diffSettings->m_diffProgram << endl;
+ *this << m_diffSettings->m_diffProgram;
+ }
+
+ switch( m_diffSettings->m_format ) {
+ case Kompare::Unified :
+ *this << "-U" << QString::number( m_diffSettings->m_linesOfContext );
+ break;
+ case Kompare::Context :
+ *this << "-C" << QString::number( m_diffSettings->m_linesOfContext );
+ break;
+ case Kompare::RCS :
+ *this << "-n";
+ break;
+ case Kompare::Ed :
+ *this << "-e";
+ break;
+ case Kompare::SideBySide:
+ *this << "-y";
+ break;
+ case Kompare::Normal :
+ case Kompare::UnknownFormat :
+ default:
+ break;
+ }
+
+ if ( m_diffSettings->m_largeFiles )
+ {
+ *this << "-H";
+ }
+
+ if ( m_diffSettings->m_ignoreWhiteSpace )
+ {
+ *this << "-b";
+ }
+
+ if ( m_diffSettings->m_ignoreAllWhiteSpace )
+ {
+ *this << "-w";
+ }
+
+ if ( m_diffSettings->m_ignoreEmptyLines )
+ {
+ *this << "-B";
+ }
+
+ if ( m_diffSettings->m_ignoreChangesDueToTabExpansion )
+ {
+ *this << "-E";
+ }
+
+ if ( m_diffSettings->m_createSmallerDiff )
+ {
+ *this << "-d";
+ }
+
+ if ( m_diffSettings->m_ignoreChangesInCase )
+ {
+ *this << "-i";
+ }
+
+ if ( m_diffSettings->m_ignoreRegExp && !m_diffSettings->m_ignoreRegExpText.isEmpty() )
+ {
+ *this << "-I " << KProcess::quote( m_diffSettings->m_ignoreRegExpText );
+ }
+
+ if ( m_diffSettings->m_showCFunctionChange )
+ {
+ *this << "-p";
+ }
+
+ if ( m_diffSettings->m_convertTabsToSpaces )
+ {
+ *this << "-t";
+ }
+
+ if ( m_diffSettings->m_recursive )
+ {
+ *this << "-r";
+ }
+
+ if ( m_diffSettings->m_newFiles )
+ {
+ *this << "-N";
+ }
+
+// This option is more trouble than it is worth... please do not ever enable it unless you want really weird crashes
+// if ( m_diffSettings->m_allText )
+// {
+// *this << "-a";
+// }
+
+ if ( m_diffSettings->m_excludeFilePattern )
+ {
+ QStringList::ConstIterator it = m_diffSettings->m_excludeFilePatternList.begin();
+ QStringList::ConstIterator end = m_diffSettings->m_excludeFilePatternList.end();
+ for ( ; it != end; ++it )
+ {
+ *this << "-x" << KProcess::quote( *it );
+ }
+ }
+
+ if ( m_diffSettings->m_excludeFilesFile && !m_diffSettings->m_excludeFilesFileURL.isEmpty() )
+ {
+ *this << "-X" << KProcess::quote( m_diffSettings->m_excludeFilesFileURL );
+ }
+}
+
+KompareProcess::~KompareProcess()
+{
+}
+
+void KompareProcess::setEncoding( const QString& encoding )
+{
+ if ( encoding.lower() == "default" )
+ {
+ m_textDecoder = QTextCodec::codecForLocale()->makeDecoder();
+ }
+ else
+ {
+ QTextCodec* textCodec = KGlobal::charsets()->codecForName( encoding.latin1() );
+ if ( textCodec )
+ m_textDecoder = textCodec->makeDecoder();
+ else
+ {
+ kdDebug(8101) << "Using locale codec as backup..." << endl;
+ textCodec = QTextCodec::codecForLocale();
+ m_textDecoder = textCodec->makeDecoder();
+ }
+ }
+}
+
+void KompareProcess::slotReceivedStdout( KProcess* /* process */, char* buffer, int length )
+{
+ // add all output to m_stdout
+ if ( m_textDecoder )
+ m_stdout += m_textDecoder->toUnicode( buffer, length );
+ else
+ kdDebug(8101) << "KompareProcess::slotReceivedStdout : No decoder !!!" << endl;
+}
+
+void KompareProcess::slotReceivedStderr( KProcess* /* process */, char* buffer, int length )
+{
+ // add all output to m_stderr
+ if ( m_textDecoder )
+ m_stderr += m_textDecoder->toUnicode( buffer, length );
+ else
+ kdDebug(8101) << "KompareProcess::slotReceivedStderr : No decoder !!!" << endl;
+}
+
+bool KompareProcess::start()
+{
+#ifndef NDEBUG
+ QString cmdLine;
+ QValueList<QCString>::ConstIterator it = arguments.begin();
+ for (; it != arguments.end(); ++it )
+ cmdLine += "\"" + (*it) + "\" ";
+ kdDebug(8101) << cmdLine << endl;
+#endif
+ return( KProcess::start( KProcess::NotifyOnExit, KProcess::AllOutput ) );
+}
+
+void KompareProcess::slotProcessExited( KProcess* /* proc */ )
+{
+ // exit status of 0: no differences
+ // 1: some differences
+ // 2: error but there may be differences !
+ kdDebug(8101) << "Exited with exit status : " << exitStatus() << endl;
+ emit diffHasFinished( normalExit() && exitStatus() != 0 );
+}
+
+#include "kompareprocess.moc"
+
diff --git a/kompare/libdiff2/kompareprocess.h b/kompare/libdiff2/kompareprocess.h
new file mode 100644
index 00000000..06a4a5ce
--- /dev/null
+++ b/kompare/libdiff2/kompareprocess.h
@@ -0,0 +1,67 @@
+/***************************************************************************
+ kompareprocess.h - description
+ -------------------
+ begin : Sun Mar 4 2001
+ copyright : (C) 2001-2003 by Otto Bruggeman
+ and John Firebaugh
+ email : otto.bruggeman@home.nl
+ jfirebaugh@kde.org
+****************************************************************************/
+
+/***************************************************************************
+**
+** This program is free software; you can redistribute it and/or modify
+** it under the terms of the 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 KOMPAREPROCESS_H
+#define KOMPAREPROCESS_H
+
+#include <kprocess.h>
+
+#include "kompare.h"
+
+class QTextCodec;
+
+class DiffSettings;
+
+class KompareProcess : public KProcess, public KompareFunctions
+{
+ Q_OBJECT
+
+public:
+ KompareProcess( DiffSettings* diffSettings, enum Kompare::DiffMode mode, QString source, QString destination, QString directory = QString::null );
+ ~KompareProcess();
+
+ bool start();
+
+ QString diffOutput() { return m_stdout; }
+ QString stdOut() { return m_stdout; }
+ QString stdErr() { return m_stderr; }
+
+ void setEncoding( const QString& encoding );
+
+signals:
+ void diffHasFinished( bool finishedNormally );
+
+protected:
+ void writeDefaultCommandLine();
+ void writeCommandLine();
+
+protected slots:
+ void slotReceivedStdout( KProcess*, char*, int );
+ void slotReceivedStderr( KProcess*, char*, int );
+ void slotProcessExited( KProcess* proc );
+
+private:
+ DiffSettings* m_diffSettings;
+ enum Kompare::DiffMode m_mode;
+ QString m_stdout;
+ QString m_stderr;
+ QTextDecoder* m_textDecoder;
+};
+
+#endif
diff --git a/kompare/libdiff2/levenshteintable.cpp b/kompare/libdiff2/levenshteintable.cpp
new file mode 100644
index 00000000..54525aef
--- /dev/null
+++ b/kompare/libdiff2/levenshteintable.cpp
@@ -0,0 +1,332 @@
+/*******************************************************************************
+**
+** Filename : levenshteintable.cpp
+** Created on : 08 november, 2003
+** Copyright : (c) 2003 Otto Bruggeman
+** Email : bruggie@home.nl
+**
+*******************************************************************************/
+
+/*******************************************************************************
+**
+** This program is free software; you can redistribute it and/or modify
+** it under the terms of the 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 <qstring.h>
+
+#include <kdebug.h>
+#include <kglobal.h>
+
+#include "levenshteintable.h"
+
+#include "difference.h"
+
+using namespace Diff2;
+
+LevenshteinTable::LevenshteinTable()
+ : m_width( 256 ),
+ m_height( 256 ),
+ m_size( m_height * m_width ),
+ m_table( new unsigned int[ m_size ] ),
+ m_source( 0 ),
+ m_destination( 0 )
+{
+}
+
+LevenshteinTable::LevenshteinTable( unsigned int width, unsigned int height )
+ : m_width( width ),
+ m_height( height ),
+ m_size( m_width * m_height ),
+ m_table( new unsigned int[ m_size ] ),
+ m_source( 0 ),
+ m_destination( 0 )
+{
+}
+
+LevenshteinTable::~LevenshteinTable()
+{
+ delete[] m_table;
+ m_source = 0;
+ m_destination = 0;
+}
+
+int LevenshteinTable::getContent( unsigned int posX, unsigned int posY ) const
+{
+// kdDebug(8101) << "Width = " << m_width << ", height = " << m_height << ", posX = " << posX << ", posY = " << posY << endl;
+ return m_table[ posY * m_width + posX ];
+}
+
+int LevenshteinTable::setContent( unsigned int posX, unsigned int posY, int value )
+{
+ m_table[ posY * m_width + posX ] = value;
+
+ return 0;
+}
+
+bool LevenshteinTable::setSize( unsigned int width, unsigned int height )
+{
+ // Set a limit of 16.7 million entries, will be about 64 MB of ram, that should be plenty
+ if ( ( ( width ) * ( height ) ) > ( 256 * 256 * 256 ) )
+ return false;
+
+ if ( ( ( width ) * ( height ) ) > m_size )
+ {
+ delete[] m_table;
+
+ m_size = width * height;
+ m_table = new unsigned int[ m_size ];
+ }
+
+ m_width = width;
+ m_height = height;
+
+ return true;
+}
+
+void LevenshteinTable::dumpLevenshteinTable()
+{
+ for ( unsigned int i = 0; i < m_height; ++i )
+ {
+ for ( unsigned int j = 0; j < m_width; ++j )
+ {
+ std::cout.width( 3 );
+ std::cout << getContent( j, i );
+ }
+ std::cout << std::endl;
+ }
+}
+
+unsigned int LevenshteinTable::createTable( DifferenceString* source, DifferenceString* destination )
+{
+ m_source = source;
+ m_destination = destination;
+
+ QString s = ' ' + source->string(); // Optimization, so i dont have to subtract 1 from the indexes every
+ QString d = ' ' + destination->string(); // single time and add 1 to the width and height of the table
+
+ unsigned int m = s.length();
+ unsigned int n = d.length();
+
+ const QChar* sq = s.unicode();
+ const QChar* dq = d.unicode();
+
+ if ( m == 1 )
+ return --n;
+
+ if ( n == 1 )
+ return --m;
+
+ if ( !setSize( m, n ) )
+ return 0;
+
+ unsigned int i;
+ unsigned int j;
+
+ // initialize first row
+ for ( i = 0; i < m; ++i )
+ setContent( i, 0, i );
+ // initialize first column
+ for ( j = 0; j < n; ++j )
+ setContent( 0, j, j );
+
+ int cost = 0, north = 0, west = 0, northwest = 0;
+
+ ushort si, dj;
+ // Optimization, calculate row wise instead of column wise, wont trash the cache so much with large strings
+ for ( j = 1; j < n; ++j )
+ {
+ dj = dq[ j ];
+
+ for ( i = 1; i < m; ++i )
+ {
+ si = sq[ i ];
+ if ( si == dj )
+ cost = 0;
+ else
+ cost = 1;
+
+ north = getContent( i, j-1 ) + 1;
+ west = getContent( i-1, j ) + 1;
+ northwest = getContent( i-1, j-1 ) + cost;
+
+ setContent( i, j, kMin( north, kMin( west, northwest ) ) );
+ }
+ }
+
+ return getContent( m-1, n-1 );
+}
+
+int LevenshteinTable::chooseRoute( int c1, int c2, int c3 )
+{
+// kdDebug(8101) << "c1 = " << c1 << ", c2 = " << c2 << ", c3 = " << c3 << endl;
+ // preference order: c2, c3, c1, hopefully this will work out for me
+ if ( c2 <= c1 && c2 <= c3 )
+ return 1;
+
+ if ( c3 <= c2 && c3 <= c1 )
+ return 2;
+
+ return 0;
+}
+
+void LevenshteinTable::createListsOfMarkers()
+{
+// std::cout << source.latin1() << std::endl;
+// std::cout << destination.latin1() << std::endl;
+// dumpLevenshteinTable();
+
+ unsigned int x = m_width-1;
+ unsigned int y = m_height-1;
+
+ Marker* c = 0;
+
+ int n, nw, w, direction, currentValue;
+ while ( x > 0 && y > 0 )
+ {
+ currentValue = getContent( x, y );
+
+ nw = getContent( x - 1, y - 1 );
+ n = getContent( x, y - 1 );
+ w = getContent( x - 1, y );
+
+ direction = chooseRoute( n, nw, w );
+
+ switch ( direction )
+ {
+ case 0: // north
+// kdDebug(8101) << "Picking north" << endl;
+// kdDebug(8101) << "Source[" << ( x - 1 ) << "] = " << QString( source[ x-1 ] ) << ", destination[" << ( y - 1 ) << "] = " << QString( destination[ y-1 ] ) << endl;
+
+ if ( !m_destination->markerList().isEmpty() )
+ c = m_destination->markerList().first();
+ else
+ c = 0;
+
+ if ( c && c->type() == Marker::End )
+ {
+// kdDebug(8101) << "CurrentValue: " << currentValue << endl;
+ if ( n == currentValue )
+ m_destination->prepend( new Marker( Marker::Start, y ) );
+ // else: the change continues, dont do anything
+ }
+ else
+ {
+// kdDebug(8101) << "CurrentValue: " << currentValue << endl;
+ if ( n < currentValue )
+ m_destination->prepend( new Marker( Marker::End, y ) );
+ }
+
+ --y;
+ break;
+ case 1: // northwest
+// kdDebug(8101) << "Picking northwest" << endl;
+// kdDebug(8101) << "Source[" << ( x - 1 ) << "] = " << QString( source[ x-1 ] ) << ", destination[" << ( y - 1 ) << "] = " << QString( destination[ y-1 ] ) << endl;
+
+ if ( !m_destination->markerList().isEmpty() )
+ c = m_destination->markerList().first();
+ else
+ c = 0;
+
+ if ( c && c->type() == Marker::End )
+ {
+// kdDebug(8101) << "End found: CurrentValue: " << currentValue << endl;
+ if ( nw == currentValue )
+ m_destination->prepend( new Marker( Marker::Start, y ) );
+ // else: the change continues, dont do anything
+ }
+ else
+ {
+// kdDebug(8101) << "CurrentValue: " << currentValue << endl;
+ if ( nw < currentValue )
+ m_destination->prepend( new Marker( Marker::End, y ) );
+ }
+
+ if ( !m_source->markerList().isEmpty() )
+ c = m_source->markerList().first();
+ else
+ c = 0;
+
+ if ( c && c->type() == Marker::End )
+ {
+// kdDebug(8101) << "End found: CurrentValue: " << currentValue << endl;
+ if ( nw == currentValue )
+ m_source->prepend( new Marker( Marker::Start, x ) );
+ // else: the change continues, dont do anything
+ }
+ else
+ {
+// kdDebug(8101) << "CurrentValue: " << currentValue << endl;
+ if ( nw < currentValue )
+ m_source->prepend( new Marker( Marker::End, x ) );
+ }
+
+ --y;
+ --x;
+ break;
+ case 2: // west
+// kdDebug(8101) << "Picking west" << endl;
+// kdDebug(8101) << "Source[" << ( x - 1 ) << "] = " << QString( source[ x-1 ] ) << ", destination[" << ( y - 1 ) << "] = " << QString( destination[ y-1 ] ) << endl;
+
+ if ( !m_source->markerList().isEmpty() )
+ c = m_source->markerList().first();
+ else
+ c = 0;
+
+ if ( c && c->type() == Marker::End )
+ {
+// kdDebug(8101) << "End found: CurrentValue: " << currentValue << endl;
+ if ( w == currentValue )
+ m_source->prepend( new Marker( Marker::Start, x ) );
+ // else: the change continues, dont do anything
+ }
+ else
+ {
+// kdDebug(8101) << "CurrentValue: " << currentValue << endl;
+ if ( w < currentValue )
+ m_source->prepend( new Marker( Marker::End, x ) );
+ }
+
+ --x;
+ break;
+ }
+ }
+
+// kdDebug(8101) << "Source string: " << m_source->string() << endl;
+// c = m_source->markerList()->first();
+// QStringList list;
+// unsigned int prevValue = 0;
+// for ( ; c; c = m_source->markerList()->next() )
+// {
+// kdDebug(8101) << "Source Marker Entry : Type: " << c->type() << ", Offset: " << c->offset() << endl;
+// list.append( m_source->string().mid( prevValue, c->offset() - prevValue ) );
+// prevValue = c->offset();
+// }
+// if ( prevValue < m_source->string().length() - 1 )
+// {
+// list.append( m_source->string().mid( prevValue, m_source->string().length() - prevValue ) );
+// }
+// kdDebug(8101) << "Source Resulting stringlist : " << list.join("\n") << endl;
+
+// list.clear();
+// prevValue = 0;
+
+// kdDebug(8101) << "Destination string: " << m_destination->string() << endl;
+// for ( ; c; c = m_destination->markerList()->next() )
+// {
+// kdDebug(8101) << "Destination Marker Entry : Type: " << c->type() << ", Offset: " << c->offset() << endl;
+// list.append( m_destination->string().mid( prevValue, c->offset() - prevValue ) );
+// prevValue = c->offset();
+// }
+// if ( prevValue < m_destination->string().length() - 1 )
+// {
+// list.append( m_destination->string().mid( prevValue, m_destination->string().length() - prevValue ) );
+// }
+// kdDebug(8101) << "Destination Resulting string : " << list.join("\n") << endl;
+}
+
diff --git a/kompare/libdiff2/levenshteintable.h b/kompare/libdiff2/levenshteintable.h
new file mode 100644
index 00000000..201d1c10
--- /dev/null
+++ b/kompare/libdiff2/levenshteintable.h
@@ -0,0 +1,69 @@
+/*******************************************************************************
+**
+** Filename : levenshteintable.h
+** Created on : 08 november, 2003
+** Copyright : (c) 2003 Otto Bruggeman
+** Email : bruggie@home.nl
+**
+*******************************************************************************/
+
+/*******************************************************************************
+**
+** This program is free software; you can redistribute it and/or modify
+** it under the terms of the 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 _LEVENSHTEIN_H
+#define _LEVENSHTEIN_H
+
+#include "difference.h"
+
+class QString;
+
+namespace Diff2 {
+
+class Marker;
+
+class LevenshteinTable
+{
+public:
+ LevenshteinTable();
+ LevenshteinTable( unsigned int width, unsigned int height );
+ ~LevenshteinTable();
+
+public:
+ int getContent( unsigned int posX, unsigned int posY ) const;
+ int setContent( unsigned int posX, unsigned int posY, int value );
+ bool setSize ( unsigned int width, unsigned int height );
+
+ unsigned int width() const { return m_width; };
+ unsigned int height() const { return m_height; };
+
+ /** Debug method to check if the table is properly filled */
+ void dumpLevenshteinTable( void );
+
+ /** This will calculate the levenshtein distance of 2 strings */
+ unsigned int createTable( DifferenceString* s, DifferenceString* d );
+
+ void createListsOfMarkers( void );
+ int chooseRoute( int c1, int c2, int c3 );
+
+protected:
+ LevenshteinTable( const LevenshteinTable& table );
+ const LevenshteinTable& operator = ( const LevenshteinTable& table );
+
+private:
+ unsigned int m_width;
+ unsigned int m_height;
+ unsigned int m_size;
+ unsigned int* m_table;
+ DifferenceString* m_source;
+ DifferenceString* m_destination;
+};
+
+} // namespace Diff2
+
+#endif // _LEVENSHTEIN_H
diff --git a/kompare/libdiff2/parser.cpp b/kompare/libdiff2/parser.cpp
new file mode 100644
index 00000000..04ff7a4a
--- /dev/null
+++ b/kompare/libdiff2/parser.cpp
@@ -0,0 +1,139 @@
+/**************************************************************************
+** parser.cpp
+** -------------------
+** begin : Sun Aug 4 15:05:35 2002
+** copyright : (C) 2002-2004 Otto Bruggeman
+** email : otto.bruggeman@home.nl
+**
+***************************************************************************/
+/***************************************************************************
+**
+** This program is free software; you can redistribute it and/or modify
+** it under the terms of the 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 <kdebug.h>
+
+#include "parser.h"
+#include "cvsdiffparser.h"
+#include "diffparser.h"
+#include "perforceparser.h"
+#include "diffmodel.h"
+
+using namespace Diff2;
+
+Parser::Parser( const KompareModelList* list ) :
+ m_list( list )
+{
+}
+
+Parser::~Parser()
+{
+}
+
+int Parser::cleanUpCrap( QStringList& diffLines )
+{
+ QStringList::Iterator it = diffLines.begin();
+
+ int nol = 0;
+
+ QString noNewLine( "\\ No newline" );
+
+ for ( ; it != diffLines.end(); ++it )
+ {
+ if ( (*it).startsWith( noNewLine ) )
+ {
+ it = diffLines.remove( it );
+ // correcting the advance of the iterator because of the remove
+ --it;
+ QString temp( *it );
+ temp.truncate( temp.find( '\n' ) );
+ *it = temp;
+ ++nol;
+ }
+ }
+
+ return nol;
+}
+
+DiffModelList* Parser::parse( QStringList& diffLines )
+{
+ /* Basically determine the generator then call the parse method */
+ ParserBase* parser;
+
+ m_generator = determineGenerator( diffLines );
+
+ int nol = cleanUpCrap( diffLines );
+ kdDebug(8101) << "Cleaned up " << nol << " line(s) of crap from the diff..." << endl;
+
+ switch( m_generator )
+ {
+ case Kompare::CVSDiff :
+ kdDebug(8101) << "It is a CVS generated diff..." << endl;
+ parser = new CVSDiffParser( m_list, diffLines );
+ break;
+ case Kompare::Diff :
+ kdDebug(8101) << "It is a diff generated diff..." << endl;
+ parser = new DiffParser( m_list, diffLines );
+ break;
+ case Kompare::Perforce :
+ kdDebug(8101) << "It is a Perforce generated diff..." << endl;
+ parser = new PerforceParser( m_list, diffLines );
+ break;
+ default:
+ // Nothing to delete, just leave...
+ return 0L;
+ }
+
+ m_format = parser->format();
+ DiffModelList* modelList = parser->parse();
+ if ( modelList )
+ {
+ kdDebug(8101) << "Modelcount: " << modelList->count() << endl;
+ DiffModelListIterator modelIt = modelList->begin();
+ DiffModelListIterator mEnd = modelList->end();
+ for ( ; modelIt != mEnd; ++modelIt )
+ {
+ kdDebug(8101) << "Hunkcount: " << (*modelIt)->hunkCount() << endl;
+ kdDebug(8101) << "Diffcount: " << (*modelIt)->differenceCount() << endl;
+ }
+ }
+
+ delete parser;
+
+ return modelList;
+}
+
+enum Kompare::Generator Parser::determineGenerator( const QStringList& diffLines )
+{
+ // Shit have to duplicate some code with this method and the ParserBase derived classes
+ QString cvsDiff ( "Index: " );
+ QString perforceDiff( "==== " );
+
+ QStringList::ConstIterator it = diffLines.begin();
+ QStringList::ConstIterator linesEnd = diffLines.end();
+
+ while ( it != linesEnd )
+ {
+ if ( ( *it ).startsWith( cvsDiff ) )
+ {
+ kdDebug(8101) << "Diff is a CVSDiff" << endl;
+ return Kompare::CVSDiff;
+ }
+ else if ( ( *it ).startsWith( perforceDiff ) )
+ {
+ kdDebug(8101) << "Diff is a Perforce Diff" << endl;
+ return Kompare::Perforce;
+ }
+ ++it;
+ }
+
+ kdDebug(8101) << "We'll assume it is a diff Diff" << endl;
+
+ // For now we'll assume it is a diff file diff, later we might
+ // try to really determine if it is a diff file diff.
+ return Kompare::Diff;
+}
diff --git a/kompare/libdiff2/parser.h b/kompare/libdiff2/parser.h
new file mode 100644
index 00000000..0ffae23a
--- /dev/null
+++ b/kompare/libdiff2/parser.h
@@ -0,0 +1,58 @@
+/**************************************************************************
+** parser.h
+** --------
+** begin : Tue Jul 30 23:53:52 2002
+** copyright : (C) 2002-2004 Otto Bruggeman
+** email : otto.bruggeman@home.nl
+**
+***************************************************************************/
+/***************************************************************************
+**
+** This program is free software; you can redistribute it and/or modify
+** it under the terms of the 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 _DIFF2_PARSER_H
+#define _DIFF2_PARSER_H
+
+#include "diffmodellist.h"
+#include "kompare.h"
+
+namespace Diff2
+{
+
+class DiffModel;
+class KompareModelList;
+
+class Parser
+{
+public:
+ Parser( const KompareModelList* list );
+ ~Parser();
+
+public:
+ DiffModelList* parse( QStringList& diffLines );
+
+ enum Kompare::Generator generator() const { return m_generator; };
+ enum Kompare::Format format() const { return m_format; };
+
+private:
+ /** Which program was used to generate the output */
+ enum Kompare::Generator determineGenerator( const QStringList& diffLines );
+
+ int cleanUpCrap( QStringList& diffLines );
+
+private:
+ enum Kompare::Generator m_generator;
+ enum Kompare::Format m_format;
+
+ const KompareModelList* m_list;
+};
+
+} // End of namespace Diff2
+
+#endif
+
diff --git a/kompare/libdiff2/parserbase.cpp b/kompare/libdiff2/parserbase.cpp
new file mode 100644
index 00000000..303f7b22
--- /dev/null
+++ b/kompare/libdiff2/parserbase.cpp
@@ -0,0 +1,739 @@
+/**************************************************************************
+** parserbase.cpp
+** -------------------
+** begin : Sun Aug 4 15:05:35 2002
+** copyright : (C) 2002-2004 Otto Bruggeman
+** email : otto.bruggeman@home.nl
+**
+***************************************************************************/
+/***************************************************************************
+**
+** This program is free software; you can redistribute it and/or modify
+** it under the terms of the 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 <qobject.h>
+
+#include <kdebug.h>
+
+#include "diffmodel.h"
+#include "diffhunk.h"
+#include "difference.h"
+#include "komparemodellist.h"
+
+#include "parserbase.h"
+
+using namespace Diff2;
+
+ParserBase::ParserBase( const KompareModelList* list, const QStringList& diff ) :
+ m_diffLines( diff ),
+ m_currentModel( 0 ),
+ m_models( 0 ),
+ m_diffIterator( m_diffLines.begin() ),
+ m_singleFileDiff( false ),
+ m_list( list )
+{
+// kdDebug(8101) << diff << endl;
+// kdDebug(8101) << m_diffLines << endl;
+ m_models = new DiffModelList();
+
+ // used in contexthunkheader
+ m_contextHunkHeader1.setPattern( "\\*{15} ?(.*)\\n" ); // capture is for function name
+ m_contextHunkHeader2.setPattern( "\\*\\*\\* ([0-9]+),([0-9]+) \\*\\*\\*\\*\\n" );
+ // used in contexthunkbody
+ m_contextHunkHeader3.setPattern( "--- ([0-9]+),([0-9]+) ----\\n" );
+
+ m_contextHunkBodyRemoved.setPattern( "- (.*)" );
+ m_contextHunkBodyAdded.setPattern ( "\\+ (.*)" );
+ m_contextHunkBodyChanged.setPattern( "! (.*)" );
+ m_contextHunkBodyContext.setPattern( " (.*)" );
+ m_contextHunkBodyLine.setPattern ( "[-\\+! ] (.*)" );
+
+ // This regexp sucks... i'll see what happens
+ m_normalDiffHeader.setPattern( "diff (?:(?:-|--)[a-zA-Z0-9=\\\"]+ )*(?:|-- +)(.*) +(.*)\\n" );
+
+ m_normalHunkHeaderAdded.setPattern ( "([0-9]+)a([0-9]+)(|,[0-9]+)(.*)\\n" );
+ m_normalHunkHeaderRemoved.setPattern( "([0-9]+)(|,[0-9]+)d([0-9]+)(.*)\\n" );
+ m_normalHunkHeaderChanged.setPattern( "([0-9]+)(|,[0-9]+)c([0-9]+)(|,[0-9]+)(.*)\\n" );
+
+ m_normalHunkBodyRemoved.setPattern ( "< (.*)" );
+ m_normalHunkBodyAdded.setPattern ( "> (.*)" );
+ m_normalHunkBodyDivider.setPattern ( "---" );
+
+ m_unifiedDiffHeader1.setPattern ( "--- ([^\\t]+)(?:\\t([^\\t]+)(?:\\t?)(.*))?\\n" );
+ m_unifiedDiffHeader2.setPattern ( "\\+\\+\\+ ([^\\t]+)(?:\\t([^\\t]+)(?:\\t?)(.*))?\\n" );
+ m_unifiedHunkHeader.setPattern ( "@@ -([0-9]+)(|,([0-9]+)) \\+([0-9]+)(|,([0-9]+)) @@(?: ?)(.*)\\n" );
+ m_unifiedHunkBodyAdded.setPattern ( "\\+(.*)" );
+ m_unifiedHunkBodyRemoved.setPattern( "-(.*)" );
+ m_unifiedHunkBodyContext.setPattern( " (.*)" );
+ m_unifiedHunkBodyLine.setPattern ( "([-+ ])(.*)" );
+}
+
+ParserBase::~ParserBase()
+{
+ if ( m_models )
+ m_models = 0; // dont delete this, i pass it around...
+}
+
+enum Kompare::Format ParserBase::determineFormat()
+{
+ // Write your own format detection routine damn it :)
+ return Kompare::UnknownFormat;
+}
+
+DiffModelList* ParserBase::parse()
+{
+ switch( determineFormat() )
+ {
+ case Kompare::Context :
+ return parseContext();
+ case Kompare::Ed :
+ return parseEd();
+ case Kompare::Normal :
+ return parseNormal();
+ case Kompare::RCS :
+ return parseRCS();
+ case Kompare::Unified :
+ return parseUnified();
+ default: // Unknown and SideBySide for now
+ return 0L;
+ }
+}
+
+bool ParserBase::parseContextDiffHeader()
+{
+// kdDebug(8101) << "ParserBase::parseContextDiffHeader()" << endl;
+ bool result = false;
+
+ while ( m_diffIterator != m_diffLines.end() )
+ {
+ if ( !m_contextDiffHeader1.exactMatch( *(m_diffIterator)++ ) )
+ {
+ continue;
+ }
+// kdDebug(8101) << "Matched length Header1 = " << m_contextDiffHeader1.matchedLength() << endl;
+// kdDebug(8101) << "Matched string Header1 = " << m_contextDiffHeader1.cap( 0 ) << endl;
+ if ( m_diffIterator != m_diffLines.end() && m_contextDiffHeader2.exactMatch( *m_diffIterator ) )
+ {
+// kdDebug(8101) << "Matched length Header2 = " << m_contextDiffHeader2.matchedLength() << endl;
+// kdDebug(8101) << "Matched string Header2 = " << m_contextDiffHeader2.cap( 0 ) << endl;
+
+ m_currentModel = new DiffModel( m_contextDiffHeader1.cap( 1 ), m_contextDiffHeader2.cap( 1 ) );
+ QObject::connect( m_currentModel, SIGNAL( setModified( bool ) ), m_list, SLOT( slotSetModified( bool ) ) );
+ m_currentModel->setSourceTimestamp ( m_contextDiffHeader1.cap( 2 ) );
+ m_currentModel->setSourceRevision ( m_contextDiffHeader1.cap( 4 ) );
+ m_currentModel->setDestinationTimestamp( m_contextDiffHeader2.cap( 2 ) );
+ m_currentModel->setDestinationRevision ( m_contextDiffHeader2.cap( 4 ) );
+
+ ++m_diffIterator;
+ result = true;
+
+ break;
+ }
+ else
+ {
+ // We're screwed, second line does not match or is not there...
+ break;
+ }
+ // Dont inc the Iterator because the second line might be the first line of
+ // the context header and the first hit was a fluke (impossible imo)
+ // maybe we should return false here because the diff is broken ?
+ }
+
+ return result;
+}
+
+bool ParserBase::parseEdDiffHeader()
+{
+ return false;
+}
+
+bool ParserBase::parseNormalDiffHeader()
+{
+// kdDebug(8101) << "ParserBase::parseNormalDiffHeader()" << endl;
+ bool result = false;
+
+ while ( m_diffIterator != m_diffLines.end() )
+ {
+ if ( m_normalDiffHeader.exactMatch( *m_diffIterator ) )
+ {
+// kdDebug(8101) << "Matched length Header = " << m_normalDiffHeader.matchedLength() << endl;
+// kdDebug(8101) << "Matched string Header = " << m_normalDiffHeader.cap( 0 ) << endl;
+
+ m_currentModel = new DiffModel();
+ QObject::connect( m_currentModel, SIGNAL( setModified( bool ) ), m_list, SLOT( slotSetModified( bool ) ) );
+ m_currentModel->setSourceFile ( m_normalDiffHeader.cap( 1 ) );
+ m_currentModel->setDestinationFile ( m_normalDiffHeader.cap( 2 ) );
+
+ result = true;
+
+ ++m_diffIterator;
+ break;
+ }
+ else
+ {
+ kdDebug(8101) << "No match for: " << ( *m_diffIterator ) << endl;
+ }
+ ++m_diffIterator;
+ }
+
+ if ( result == false )
+ {
+ // Set this to the first line again and hope it is a single file diff
+ m_diffIterator = m_diffLines.begin();
+ m_currentModel = new DiffModel();
+ QObject::connect( m_currentModel, SIGNAL( setModified( bool ) ), m_list, SLOT( slotSetModified( bool ) ) );
+ m_singleFileDiff = true;
+ }
+
+ return result;
+}
+
+bool ParserBase::parseRCSDiffHeader()
+{
+ return false;
+}
+
+bool ParserBase::parseUnifiedDiffHeader()
+{
+// kdDebug(8101) << "ParserBase::parseUnifiedDiffHeader()" << endl;
+ bool result = false;
+
+ while ( m_diffIterator != m_diffLines.end() ) // dont assume we start with the diffheader1 line
+ {
+ if ( !m_unifiedDiffHeader1.exactMatch( *m_diffIterator ) )
+ {
+ ++m_diffIterator;
+ continue;
+ }
+// kdDebug(8101) << "Matched length Header1 = " << m_unifiedDiffHeader1.matchedLength() << endl;
+// kdDebug(8101) << "Matched string Header1 = " << m_unifiedDiffHeader1.cap( 0 ) << endl;
+ ++m_diffIterator;
+ if ( m_diffIterator != m_diffLines.end() && m_unifiedDiffHeader2.exactMatch( *m_diffIterator ) )
+ {
+ m_currentModel = new DiffModel( m_unifiedDiffHeader1.cap( 1 ), m_unifiedDiffHeader2.cap( 1 ) );
+ QObject::connect( m_currentModel, SIGNAL( setModified( bool ) ), m_list, SLOT( slotSetModified( bool ) ) );
+ m_currentModel->setSourceTimestamp( m_unifiedDiffHeader1.cap( 2 ) );
+ m_currentModel->setSourceRevision( m_unifiedDiffHeader1.cap( 4 ) );
+ m_currentModel->setDestinationTimestamp( m_unifiedDiffHeader2.cap( 2 ) );
+ m_currentModel->setDestinationRevision( m_unifiedDiffHeader2.cap( 4 ) );
+
+ ++m_diffIterator;
+ result = true;
+
+ break;
+ }
+ else
+ {
+ // We're screwed, second line does not match or is not there...
+ break;
+ }
+ }
+
+ return result;
+}
+
+bool ParserBase::parseContextHunkHeader()
+{
+// kdDebug(8101) << "ParserBase::parseContextHunkHeader()" << endl;
+
+ if ( m_diffIterator == m_diffLines.end() )
+ return false;
+
+ if ( !m_contextHunkHeader1.exactMatch( *(m_diffIterator) ) )
+ return false; // big fat trouble, aborting...
+
+ ++m_diffIterator;
+
+ if ( m_diffIterator == m_diffLines.end() )
+ return false;
+
+ if ( !m_contextHunkHeader2.exactMatch( *(m_diffIterator) ) )
+ return false; // big fat trouble, aborting...
+
+ ++m_diffIterator;
+
+ return true;
+}
+
+bool ParserBase::parseEdHunkHeader()
+{
+ return false;
+}
+
+bool ParserBase::parseNormalHunkHeader()
+{
+// kdDebug(8101) << "ParserBase::parseNormalHunkHeader()" << endl;
+ if ( m_diffIterator != m_diffLines.end() )
+ {
+// kdDebug(8101) << "Header = " << *m_diffIterator << endl;
+ if ( m_normalHunkHeaderAdded.exactMatch( *m_diffIterator ) )
+ {
+ m_normalDiffType = Difference::Insert;
+ }
+ else if ( m_normalHunkHeaderRemoved.exactMatch( *m_diffIterator ) )
+ {
+ m_normalDiffType = Difference::Delete;
+ }
+ else if ( m_normalHunkHeaderChanged.exactMatch( *m_diffIterator ) )
+ {
+ m_normalDiffType = Difference::Change;
+ }
+ else
+ return false;
+
+ ++m_diffIterator;
+ return true;
+ }
+
+ return false;
+}
+
+bool ParserBase::parseRCSHunkHeader()
+{
+ return false;
+}
+
+bool ParserBase::parseUnifiedHunkHeader()
+{
+// kdDebug(8101) << "ParserBase::parseUnifiedHunkHeader()" << endl;
+
+ if ( m_unifiedHunkHeader.exactMatch( *m_diffIterator ) )
+ {
+ ++m_diffIterator;
+ return true;
+ }
+ else
+ {
+// kdDebug(8101) << "This is not a unified hunk header : " << (*m_diffIterator) << endl;
+ return false;
+ }
+
+}
+
+bool ParserBase::parseContextHunkBody()
+{
+// kdDebug(8101) << "ParserBase::parseContextHunkBody()" << endl;
+
+ // Storing the src part of the hunk for later use
+ QStringList oldLines;
+ for( ; m_diffIterator != m_diffLines.end() && m_contextHunkBodyLine.exactMatch( *m_diffIterator ); ++m_diffIterator ) {
+// kdDebug(8101) << "Added old line: " << *m_diffIterator << endl;
+ oldLines.append( *m_diffIterator );
+ }
+
+ if( !m_contextHunkHeader3.exactMatch( *m_diffIterator ) )
+ return false;
+
+ ++m_diffIterator;
+
+ // Storing the dest part of the hunk for later use
+ QStringList newLines;
+ for( ; m_diffIterator != m_diffLines.end() && m_contextHunkBodyLine.exactMatch( *m_diffIterator ); ++m_diffIterator ) {
+// kdDebug(8101) << "Added new line: " << *m_diffIterator << endl;
+ newLines.append( *m_diffIterator );
+ }
+
+ QString function = m_contextHunkHeader1.cap( 1 );
+// kdDebug(8101) << "Captured function: " << function << endl;
+ int linenoA = m_contextHunkHeader2.cap( 1 ).toInt();
+// kdDebug(8101) << "Source line number: " << linenoA << endl;
+ int linenoB = m_contextHunkHeader3.cap( 1 ).toInt();
+// kdDebug(8101) << "Dest line number: " << linenoB << endl;
+
+ DiffHunk* hunk = new DiffHunk( linenoA, linenoB, function );
+
+ m_currentModel->addHunk( hunk );
+
+ QStringList::Iterator oldIt = oldLines.begin();
+ QStringList::Iterator newIt = newLines.begin();
+
+ Difference* diff;
+ while( oldIt != oldLines.end() || newIt != newLines.end() )
+ {
+ if( oldIt != oldLines.end() && m_contextHunkBodyRemoved.exactMatch( *oldIt ) )
+ {
+// kdDebug(8101) << "Delete: " << endl;
+ diff = new Difference( linenoA, linenoB );
+ diff->setType( Difference::Delete );
+ m_currentModel->addDiff( diff );
+// kdDebug(8101) << "Difference added" << endl;
+ hunk->add( diff );
+ for( ; oldIt != oldLines.end() && m_contextHunkBodyRemoved.exactMatch( *oldIt ); ++oldIt )
+ {
+// kdDebug(8101) << " " << m_contextHunkBodyRemoved.cap( 1 ) << endl;
+ diff->addSourceLine( m_contextHunkBodyRemoved.cap( 1 ) );
+ linenoA++;
+ }
+ }
+ else if( newIt != newLines.end() && m_contextHunkBodyAdded.exactMatch( *newIt ) )
+ {
+// kdDebug(8101) << "Insert: " << endl;
+ diff = new Difference( linenoA, linenoB );
+ diff->setType( Difference::Insert );
+ m_currentModel->addDiff( diff );
+// kdDebug(8101) << "Difference added" << endl;
+ hunk->add( diff );
+ for( ; newIt != newLines.end() && m_contextHunkBodyAdded.exactMatch( *newIt ); ++newIt )
+ {
+// kdDebug(8101) << " " << m_contextHunkBodyAdded.cap( 1 ) << endl;
+ diff->addDestinationLine( m_contextHunkBodyAdded.cap( 1 ) );
+ linenoB++;
+ }
+ }
+ else if( ( oldIt == oldLines.end() || m_contextHunkBodyContext.exactMatch( *oldIt ) ) &&
+ ( newIt == newLines.end() || m_contextHunkBodyContext.exactMatch( *newIt ) ) )
+ {
+// kdDebug(8101) << "Unchanged: " << endl;
+ diff = new Difference( linenoA, linenoB );
+ // Dont add this diff with addDiff to the model... no unchanged differences allowed in there...
+ diff->setType( Difference::Unchanged );
+ hunk->add( diff );
+ while( ( oldIt == oldLines.end() || m_contextHunkBodyContext.exactMatch( *oldIt ) ) &&
+ ( newIt == newLines.end() || m_contextHunkBodyContext.exactMatch( *newIt ) ) &&
+ ( oldIt != oldLines.end() || newIt != newLines.end() ) )
+ {
+ QString l;
+ if( oldIt != oldLines.end() )
+ {
+ l = m_contextHunkBodyContext.cap( 1 );
+// kdDebug(8101) << "old: " << l << endl;
+ ++oldIt;
+ }
+ if( newIt != newLines.end() )
+ {
+ l = m_contextHunkBodyContext.cap( 1 );
+// kdDebug(8101) << "new: " << l << endl;
+ ++newIt;
+ }
+ diff->addSourceLine( l );
+ diff->addDestinationLine( l );
+ linenoA++;
+ linenoB++;
+ }
+ }
+ else if( ( oldIt != oldLines.end() && m_contextHunkBodyChanged.exactMatch( *oldIt ) ) ||
+ ( newIt != newLines.end() && m_contextHunkBodyChanged.exactMatch( *newIt ) ) )
+ {
+// kdDebug(8101) << "Changed: " << endl;
+ diff = new Difference( linenoA, linenoB );
+ diff->setType( Difference::Change );
+ m_currentModel->addDiff( diff );
+// kdDebug(8101) << "Difference added" << endl;
+ hunk->add( diff );
+ while( oldIt != oldLines.end() && m_contextHunkBodyChanged.exactMatch( *oldIt ) )
+ {
+// kdDebug(8101) << " " << m_contextHunkBodyChanged.cap( 1 ) << endl;
+ diff->addSourceLine( m_contextHunkBodyChanged.cap( 1 ) );
+ linenoA++;
+ ++oldIt;
+ }
+ while( newIt != newLines.end() && m_contextHunkBodyChanged.exactMatch( *newIt ) )
+ {
+// kdDebug(8101) << " " << m_contextHunkBodyChanged.cap( 1 ) << endl;
+ diff->addDestinationLine( m_contextHunkBodyChanged.cap( 1 ) );
+ linenoB++;
+ ++newIt;
+ }
+ }
+ else
+ return false;
+ diff->determineInlineDifferences();
+ }
+
+ return true;
+}
+
+bool ParserBase::parseEdHunkBody()
+{
+ return false;
+}
+
+bool ParserBase::parseNormalHunkBody()
+{
+// kdDebug(8101) << "ParserBase::parseNormalHunkBody" << endl;
+
+ QString type = QString::null;
+
+ int linenoA = 0, linenoB = 0;
+
+ if ( m_normalDiffType == Difference::Insert )
+ {
+ linenoA = m_normalHunkHeaderAdded.cap( 1 ).toInt();
+ linenoB = m_normalHunkHeaderAdded.cap( 2 ).toInt();
+ }
+ else if ( m_normalDiffType == Difference::Delete )
+ {
+ linenoA = m_normalHunkHeaderRemoved.cap( 1 ).toInt();
+ linenoB = m_normalHunkHeaderRemoved.cap( 3 ).toInt();
+ }
+ else if ( m_normalDiffType == Difference::Change )
+ {
+ linenoA = m_normalHunkHeaderChanged.cap( 1 ).toInt();
+ linenoB = m_normalHunkHeaderChanged.cap( 3 ).toInt();
+ }
+
+ DiffHunk* hunk = new DiffHunk( linenoA, linenoB );
+ m_currentModel->addHunk( hunk );
+ Difference* diff = new Difference( linenoA, linenoB );
+ hunk->add( diff );
+ m_currentModel->addDiff( diff );
+
+ diff->setType( m_normalDiffType );
+
+ if ( m_normalDiffType == Difference::Change || m_normalDiffType == Difference::Delete )
+ for( ; m_diffIterator != m_diffLines.end() && m_normalHunkBodyRemoved.exactMatch( *m_diffIterator ); ++m_diffIterator )
+ {
+// kdDebug(8101) << "Line = " << *m_diffIterator << endl;
+ diff->addSourceLine( m_normalHunkBodyRemoved.cap( 1 ) );
+ }
+ if ( m_normalDiffType == Difference::Change )
+ if( m_diffIterator != m_diffLines.end() && m_normalHunkBodyDivider.exactMatch( *m_diffIterator ) )
+ {
+// kdDebug(8101) << "Line = " << *m_diffIterator << endl;
+ ++m_diffIterator;
+ }
+ else
+ return false;
+ if ( m_normalDiffType == Difference::Insert || m_normalDiffType == Difference::Change )
+ for( ; m_diffIterator != m_diffLines.end() && m_normalHunkBodyAdded.exactMatch( *m_diffIterator ); ++m_diffIterator )
+ {
+// kdDebug(8101) << "Line = " << *m_diffIterator << endl;
+ diff->addDestinationLine( m_normalHunkBodyAdded.cap( 1 ) );
+ }
+
+ return true;
+}
+
+bool ParserBase::parseRCSHunkBody()
+{
+ return false;
+}
+
+bool ParserBase::matchesUnifiedHunkLine( QString line ) const
+{
+ static const QChar context( ' ' );
+ static const QChar added ( '+' );
+ static const QChar removed( '-' );
+
+ QChar first = line[0];
+
+ return ( first == context || first == added || first == removed );
+}
+
+bool ParserBase::parseUnifiedHunkBody()
+{
+// kdDebug(8101) << "ParserBase::parseUnifiedHunkBody" << endl;
+
+ int linenoA = 0, linenoB = 0;
+ bool wasNum;
+
+ // Fetching the stuff we need from the hunkheader regexp that was parsed in parseUnifiedHunkHeader();
+ linenoA = m_unifiedHunkHeader.cap( 1 ).toInt();
+ if( !m_unifiedHunkHeader.cap( 3 ).isEmpty() && m_unifiedHunkHeader.cap( 3 ).toInt(&wasNum) == 0 ) {
+ // If a hunk is an insertion or deletion with no context, the line number given
+ // is the one before the hunk. this isn't what we want, so increment it to fix this.
+ if( wasNum == false )
+ return false;
+ linenoA++;
+ }
+ linenoB = m_unifiedHunkHeader.cap( 4 ).toInt();
+ if( !m_unifiedHunkHeader.cap( 6 ).isEmpty() && m_unifiedHunkHeader.cap( 6 ).toInt(&wasNum) == 0 ) {
+ // see above
+ if( wasNum == false )
+ return false;
+ linenoB++;
+ }
+ QString function = m_unifiedHunkHeader.cap( 7 );
+ for ( int i = 0; i < 9; i++ )
+ {
+// kdDebug(8101) << "Capture " << i << ": " << m_unifiedHunkHeader.cap( i ) << endl;
+ }
+
+ DiffHunk* hunk = new DiffHunk( linenoA, linenoB, function );
+ m_currentModel->addHunk( hunk );
+
+ const QStringList::ConstIterator m_diffLinesEnd = m_diffLines.end();
+
+ const QString context = QString( " " );
+ const QString added = QString( "+" );
+ const QString removed = QString( "-" );
+
+ while( m_diffIterator != m_diffLinesEnd && matchesUnifiedHunkLine( *m_diffIterator ) )
+ {
+ Difference* diff = new Difference( linenoA, linenoB );
+ hunk->add( diff );
+
+ if( (*m_diffIterator).startsWith( context ) )
+ { // context
+ for( ; m_diffIterator != m_diffLinesEnd && (*m_diffIterator).startsWith( context ); ++m_diffIterator )
+ {
+ diff->addSourceLine( QString( *m_diffIterator ).remove( 0, 1 ) );
+ diff->addDestinationLine( QString( *m_diffIterator ).remove( 0, 1 ) );
+ linenoA++;
+ linenoB++;
+ }
+ }
+ else
+ { // This is a real difference, not context
+ for( ; m_diffIterator != m_diffLinesEnd && (*m_diffIterator).startsWith( removed ); ++m_diffIterator )
+ {
+ diff->addSourceLine( QString( *m_diffIterator ).remove( 0, 1 ) );
+ linenoA++;
+ }
+ for( ; m_diffIterator != m_diffLinesEnd && (*m_diffIterator).startsWith( added ); ++m_diffIterator )
+ {
+ diff->addDestinationLine( QString( *m_diffIterator ).remove( 0, 1 ) );
+ linenoB++;
+ }
+ if ( diff->sourceLineCount() == 0 )
+ {
+ diff->setType( Difference::Insert );
+// kdDebug(8101) << "Insert difference" << endl;
+ }
+ else if ( diff->destinationLineCount() == 0 )
+ {
+ diff->setType( Difference::Delete );
+// kdDebug(8101) << "Delete difference" << endl;
+ }
+ else
+ {
+ diff->setType( Difference::Change );
+// kdDebug(8101) << "Change difference" << endl;
+ }
+ diff->determineInlineDifferences();
+ m_currentModel->addDiff( diff );
+ }
+ }
+
+ return true;
+}
+
+DiffModelList* ParserBase::parseContext()
+{
+ while ( parseContextDiffHeader() )
+ {
+ while ( parseContextHunkHeader() )
+ parseContextHunkBody();
+ if ( m_currentModel->differenceCount() > 0 )
+ m_models->append( m_currentModel );
+ }
+
+ m_models->sort();
+
+ if ( m_models->count() > 0 )
+ {
+ return m_models;
+ }
+ else
+ {
+ delete m_models;
+ return 0L;
+ }
+}
+
+DiffModelList* ParserBase::parseEd()
+{
+ while ( parseEdDiffHeader() )
+ {
+ while ( parseEdHunkHeader() )
+ parseEdHunkBody();
+ if ( m_currentModel->differenceCount() > 0 )
+ m_models->append( m_currentModel );
+ }
+
+ m_models->sort();
+
+ if ( m_models->count() > 0 )
+ {
+ return m_models;
+ }
+ else
+ {
+ delete m_models;
+ return 0L;
+ }
+}
+
+DiffModelList* ParserBase::parseNormal()
+{
+ while ( parseNormalDiffHeader() )
+ {
+ while ( parseNormalHunkHeader() )
+ parseNormalHunkBody();
+ if ( m_currentModel->differenceCount() > 0 )
+ m_models->append( m_currentModel );
+ }
+
+ if ( m_singleFileDiff )
+ {
+ while ( parseNormalHunkHeader() )
+ parseNormalHunkBody();
+ if ( m_currentModel->differenceCount() > 0 )
+ m_models->append( m_currentModel );
+ }
+
+ m_models->sort();
+
+ if ( m_models->count() > 0 )
+ {
+ return m_models;
+ }
+ else
+ {
+ delete m_models;
+ return 0L;
+ }
+}
+
+DiffModelList* ParserBase::parseRCS()
+{
+ while ( parseRCSDiffHeader() )
+ {
+ while ( parseRCSHunkHeader() )
+ parseRCSHunkBody();
+ if ( m_currentModel->differenceCount() > 0 )
+ m_models->append( m_currentModel );
+ }
+
+ m_models->sort();
+
+ if ( m_models->count() > 0 )
+ {
+ return m_models;
+ }
+ else
+ {
+ delete m_models;
+ return 0L;
+ }
+}
+
+DiffModelList* ParserBase::parseUnified()
+{
+ while ( parseUnifiedDiffHeader() )
+ {
+ while ( parseUnifiedHunkHeader() )
+ parseUnifiedHunkBody();
+// kdDebug(8101) << "New model ready to be analyzed..." << endl;
+// kdDebug(8101) << " differenceCount() == " << m_currentModel->differenceCount() << endl;
+ if ( m_currentModel->differenceCount() > 0 )
+ m_models->append( m_currentModel );
+ }
+
+ m_models->sort();
+
+ if ( m_models->count() > 0 )
+ {
+ return m_models;
+ }
+ else
+ {
+ delete m_models;
+ return 0L;
+ }
+}
+
diff --git a/kompare/libdiff2/parserbase.h b/kompare/libdiff2/parserbase.h
new file mode 100644
index 00000000..5e08803e
--- /dev/null
+++ b/kompare/libdiff2/parserbase.h
@@ -0,0 +1,133 @@
+/**************************************************************************
+** parserbase.h
+** -------------------
+** begin : Tue Jul 30 23:53:52 2002
+** copyright : (C) 2002-2004 Otto Bruggeman
+** email : otto.bruggeman@home.nl
+**
+***************************************************************************/
+/***************************************************************************
+**
+** This program is free software; you can redistribute it and/or modify
+** it under the terms of the 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 _DIFF2_PARSERBASE_H
+#define _DIFF2_PARSERBASE_H
+
+#include <qregexp.h>
+
+#include "kompare.h"
+#include "difference.h"
+#include "diffmodellist.h"
+
+class QStringList;
+class QString;
+
+namespace Diff2
+{
+
+class KompareModelList;
+
+class ParserBase
+{
+public:
+ ParserBase( const KompareModelList* list, const QStringList& diff );
+ virtual ~ParserBase();
+
+public:
+ enum Kompare::Format format() { return determineFormat(); };
+ DiffModelList* parse();
+
+protected:
+ virtual bool parseContextDiffHeader();
+ virtual bool parseEdDiffHeader();
+ virtual bool parseNormalDiffHeader();
+ virtual bool parseRCSDiffHeader();
+ virtual bool parseUnifiedDiffHeader();
+
+ virtual bool parseContextHunkHeader();
+ virtual bool parseEdHunkHeader();
+ virtual bool parseNormalHunkHeader();
+ virtual bool parseRCSHunkHeader();
+ virtual bool parseUnifiedHunkHeader();
+
+ virtual bool parseContextHunkBody();
+ virtual bool parseEdHunkBody();
+ virtual bool parseNormalHunkBody();
+ virtual bool parseRCSHunkBody();
+ virtual bool parseUnifiedHunkBody();
+
+ virtual DiffModelList* parseContext();
+ virtual DiffModelList* parseEd();
+ virtual DiffModelList* parseNormal();
+ virtual DiffModelList* parseRCS();
+ virtual DiffModelList* parseUnified();
+
+protected: // Helper methods to speed things up
+ bool matchesUnifiedHunkLine( QString line ) const;
+
+protected:
+ /** What is format of the diff */
+ virtual enum Kompare::Format determineFormat();
+
+protected:
+ // Regexps for context parsing
+ QRegExp m_contextDiffHeader1;
+ QRegExp m_contextDiffHeader2;
+
+ QRegExp m_contextHunkHeader1;
+ QRegExp m_contextHunkHeader2;
+ QRegExp m_contextHunkHeader3;
+
+ QRegExp m_contextHunkBodyRemoved;
+ QRegExp m_contextHunkBodyAdded;
+ QRegExp m_contextHunkBodyChanged;
+ QRegExp m_contextHunkBodyContext;
+ QRegExp m_contextHunkBodyLine; // Added for convenience
+
+ // Regexps for normal parsing
+ QRegExp m_normalDiffHeader;
+
+ QRegExp m_normalHunkHeaderAdded;
+ QRegExp m_normalHunkHeaderRemoved;
+ QRegExp m_normalHunkHeaderChanged;
+
+ QRegExp m_normalHunkBodyRemoved;
+ QRegExp m_normalHunkBodyAdded;
+ QRegExp m_normalHunkBodyDivider;
+
+ enum Difference::Type m_normalDiffType;
+
+ // RegExps for rcs parsing
+ QRegExp m_rcsDiffHeader;
+
+ // Regexps for unified parsing
+ QRegExp m_unifiedDiffHeader1;
+ QRegExp m_unifiedDiffHeader2;
+
+ QRegExp m_unifiedHunkHeader;
+
+ QRegExp m_unifiedHunkBodyAdded;
+ QRegExp m_unifiedHunkBodyRemoved;
+ QRegExp m_unifiedHunkBodyContext;
+ QRegExp m_unifiedHunkBodyLine; // Added for convenience
+
+protected:
+ const QStringList& m_diffLines;
+ DiffModel* m_currentModel;
+ DiffModelList* m_models;
+ QStringList::ConstIterator m_diffIterator;
+
+ bool m_singleFileDiff;
+
+protected:
+ const KompareModelList* m_list;
+};
+
+} // End of namespace Diff2
+
+#endif
diff --git a/kompare/libdiff2/perforceparser.cpp b/kompare/libdiff2/perforceparser.cpp
new file mode 100644
index 00000000..907d88ff
--- /dev/null
+++ b/kompare/libdiff2/perforceparser.cpp
@@ -0,0 +1,223 @@
+/**************************************************************************
+** perforceparser.cpp
+** ------------------
+** begin : Sun Aug 4 15:05:35 2002
+** copyright : (C) 2002-2004 Otto Bruggeman
+** email : otto.bruggeman@home.nl
+**
+***************************************************************************/
+/***************************************************************************
+**
+** This program is free software; you can redistribute it and/or modify
+** it under the terms of the 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 <qregexp.h>
+
+#include <kdebug.h>
+
+#include "perforceparser.h"
+
+using namespace Diff2;
+
+PerforceParser::PerforceParser( const KompareModelList* list, const QStringList& diff ) : ParserBase( list, diff )
+{
+ m_contextDiffHeader1.setPattern( "==== (.*) - (.*) ====\\n" );
+ m_contextDiffHeader1.setMinimal( true );
+ m_normalDiffHeader.setPattern ( "==== (.*) - (.*) ====\\n" );
+ m_normalDiffHeader.setMinimal ( true );
+ m_rcsDiffHeader.setPattern ( "==== (.*) - (.*) ====\\n" );
+ m_rcsDiffHeader.setMinimal ( true );
+ m_unifiedDiffHeader1.setPattern( "==== (.*) - (.*) ====\\n" );
+ m_unifiedDiffHeader1.setMinimal( true );
+}
+
+PerforceParser::~PerforceParser()
+{
+}
+
+enum Kompare::Format PerforceParser::determineFormat()
+{
+ kdDebug(8101) << "Determining the format of the Perforce Diff" << endl;
+
+ QRegExp unifiedRE( "^@@" );
+ QRegExp contextRE( "^\\*{15}" );
+ QRegExp normalRE ( "^\\d+(|,\\d+)[acd]\\d+(|,\\d+)" );
+ QRegExp rcsRE ( "^[acd]\\d+ \\d+" );
+ // Summary is not supported since it gives no useful parsable info
+
+ QStringList::ConstIterator it = m_diffLines.begin();
+
+ while( it != m_diffLines.end() )
+ {
+ if( (*it).find( unifiedRE, 0 ) == 0 )
+ {
+ kdDebug(8101) << "Difflines are from a Unified diff..." << endl;
+ return Kompare::Unified;
+ }
+ else if( (*it).find( contextRE, 0 ) == 0 )
+ {
+ kdDebug(8101) << "Difflines are from a Context diff..." << endl;
+ return Kompare::Context;
+ }
+ else if( (*it).find( normalRE, 0 ) == 0 )
+ {
+ kdDebug(8101) << "Difflines are from a Normal diff..." << endl;
+ return Kompare::Normal;
+ }
+ else if( (*it).find( rcsRE, 0 ) == 0 )
+ {
+ kdDebug(8101) << "Difflines are from a RCS diff..." << endl;
+ return Kompare::RCS;
+ }
+ ++it;
+ }
+ kdDebug(8101) << "Difflines are from an unknown diff..." << endl;
+ return Kompare::UnknownFormat;
+}
+
+bool PerforceParser::parseContextDiffHeader()
+{
+// kdDebug(8101) << "ParserBase::parseContextDiffHeader()" << endl;
+ bool result = false;
+
+ QStringList::ConstIterator itEnd = m_diffLines.end();
+
+ QRegExp sourceFileRE ( "([^\\#]+)#(\\d+)" );
+ QRegExp destinationFileRE( "([^\\#]+)#(|\\d+)" );
+
+ while ( m_diffIterator != itEnd )
+ {
+ if ( m_contextDiffHeader1.exactMatch( *(m_diffIterator)++ ) )
+ {
+// kdDebug(8101) << "Matched length Header1 = " << m_contextDiffHeader1.matchedLength() << endl;
+// kdDebug(8101) << "Matched string Header1 = " << m_contextDiffHeader1.cap( 0 ) << endl;
+// kdDebug(8101) << "First capture Header1 = " << m_contextDiffHeader1.cap( 1 ) << endl;
+// kdDebug(8101) << "Second capture Header1 = " << m_contextDiffHeader1.cap( 2 ) << endl;
+
+ m_currentModel = new DiffModel();
+ sourceFileRE.exactMatch( m_contextDiffHeader1.cap( 1 ) );
+ destinationFileRE.exactMatch( m_contextDiffHeader1.cap( 2 ) );
+ kdDebug(8101) << "Matched length = " << sourceFileRE.matchedLength() << endl;
+ kdDebug(8101) << "Matched length = " << destinationFileRE.matchedLength() << endl;
+ kdDebug(8101) << "Captured texts = " << sourceFileRE.capturedTexts() << endl;
+ kdDebug(8101) << "Captured texts = " << destinationFileRE.capturedTexts() << endl;
+ kdDebug(8101) << "Source File : " << sourceFileRE.cap( 1 ) << endl;
+ kdDebug(8101) << "Destination File : " << destinationFileRE.cap( 1 ) << endl;
+ m_currentModel->setSourceFile ( sourceFileRE.cap( 1 ) );
+ m_currentModel->setDestinationFile( destinationFileRE.cap( 1 ) );
+
+ result = true;
+
+ break;
+ }
+ else
+ {
+ kdDebug(8101) << "Matched length = " << m_contextDiffHeader1.matchedLength() << endl;
+ kdDebug(8101) << "Captured texts = " << m_contextDiffHeader1.capturedTexts() << endl;
+ }
+ }
+
+ return result;
+}
+
+bool PerforceParser::parseNormalDiffHeader()
+{
+ bool result = false;
+
+ QStringList::ConstIterator itEnd = m_diffLines.end();
+
+ QRegExp sourceFileRE ( "([^\\#]+)#(\\d+)" );
+ QRegExp destinationFileRE( "([^\\#]+)#(|\\d+)" );
+
+ while ( m_diffIterator != itEnd )
+ {
+ kdDebug(8101) << "Line = " << *m_diffIterator << endl;
+ kdDebug(8101) << "String length = " << (*m_diffIterator).length() << endl;
+ if ( m_normalDiffHeader.exactMatch( *(m_diffIterator)++ ) )
+ {
+ kdDebug(8101) << "Matched length Header1 = " << m_normalDiffHeader.matchedLength() << endl;
+ kdDebug(8101) << "Matched string Header1 = " << m_normalDiffHeader.cap( 0 ) << endl;
+ kdDebug(8101) << "First capture Header1 = \"" << m_normalDiffHeader.cap( 1 ) << "\"" << endl;
+ kdDebug(8101) << "Second capture Header1 = \"" << m_normalDiffHeader.cap( 2 ) << "\"" << endl;
+
+ m_currentModel = new DiffModel();
+ sourceFileRE.exactMatch( m_normalDiffHeader.cap( 1 ) );
+ destinationFileRE.exactMatch( m_normalDiffHeader.cap( 2 ) );
+ kdDebug(8101) << "Matched length = " << sourceFileRE.matchedLength() << endl;
+ kdDebug(8101) << "Matched length = " << destinationFileRE.matchedLength() << endl;
+ kdDebug(8101) << "Captured texts = " << sourceFileRE.capturedTexts() << endl;
+ kdDebug(8101) << "Captured texts = " << destinationFileRE.capturedTexts() << endl;
+ kdDebug(8101) << "Source File : " << sourceFileRE.cap( 1 ) << endl;
+ kdDebug(8101) << "Destination File : " << destinationFileRE.cap( 1 ) << endl;
+ m_currentModel->setSourceFile ( sourceFileRE.cap( 1 ) );
+ m_currentModel->setDestinationFile( destinationFileRE.cap( 1 ) );
+
+ result = true;
+
+ break;
+ }
+ else
+ {
+ kdDebug(8101) << "Matched length = " << m_normalDiffHeader.matchedLength() << endl;
+ kdDebug(8101) << "Captured texts = " << m_normalDiffHeader.capturedTexts() << endl;
+ }
+ }
+
+ return result;
+}
+
+bool PerforceParser::parseRCSDiffHeader()
+{
+ return false;
+}
+
+bool PerforceParser::parseUnifiedDiffHeader()
+{
+ bool result = false;
+
+ QStringList::ConstIterator itEnd = m_diffLines.end();
+
+ QRegExp sourceFileRE ( "([^\\#]+)#(\\d+)" );
+ QRegExp destinationFileRE( "([^\\#]+)#(|\\d+)" );
+
+ while ( m_diffIterator != itEnd )
+ {
+// kdDebug(8101) << "Line = " << *m_diffIterator << endl;
+// kdDebug(8101) << "String length = " << (*m_diffIterator).length() << endl;
+ if ( m_unifiedDiffHeader1.exactMatch( *(m_diffIterator)++ ) )
+ {
+// kdDebug(8101) << "Matched length Header1 = " << m_unifiedDiffHeader1.matchedLength() << endl;
+// kdDebug(8101) << "Matched string Header1 = " << m_unifiedDiffHeader1.cap( 0 ) << endl;
+// kdDebug(8101) << "First capture Header1 = \"" << m_unifiedDiffHeader1.cap( 1 ) << "\"" << endl;
+// kdDebug(8101) << "Second capture Header1 = \"" << m_unifiedDiffHeader1.cap( 2 ) << "\"" << endl;
+
+ m_currentModel = new DiffModel();
+ sourceFileRE.exactMatch( m_unifiedDiffHeader1.cap( 1 ) );
+ destinationFileRE.exactMatch( m_unifiedDiffHeader1.cap( 2 ) );
+// kdDebug(8101) << "Matched length = " << sourceFileRE.matchedLength() << endl;
+// kdDebug(8101) << "Matched length = " << destinationFileRE.matchedLength() << endl;
+// kdDebug(8101) << "Captured texts = " << sourceFileRE.capturedTexts() << endl;
+// kdDebug(8101) << "Captured texts = " << destinationFileRE.capturedTexts() << endl;
+// kdDebug(8101) << "Source File : " << sourceFileRE.cap( 1 ) << endl;
+// kdDebug(8101) << "Destination File : " << destinationFileRE.cap( 1 ) << endl;
+ m_currentModel->setSourceFile ( sourceFileRE.cap( 1 ) );
+ m_currentModel->setDestinationFile( destinationFileRE.cap( 1 ) );
+
+ result = true;
+
+ break;
+ }
+ else
+ {
+// kdDebug(8101) << "Matched length = " << m_unifiedDiffHeader1.matchedLength() << endl;
+// kdDebug(8101) << "Captured texts = " << m_unifiedDiffHeader1.capturedTexts() << endl;
+ }
+ }
+
+ return result;
+}
+
diff --git a/kompare/libdiff2/perforceparser.h b/kompare/libdiff2/perforceparser.h
new file mode 100644
index 00000000..99973167
--- /dev/null
+++ b/kompare/libdiff2/perforceparser.h
@@ -0,0 +1,44 @@
+/**************************************************************************
+** perforceparser.h
+** -------------------
+** begin : Sun Sep 8 20:58:59 2002
+** copyright : (c) 2002-2004 Otto Bruggeman
+** email : otto.bruggeman@home.nl
+**
+***************************************************************************/
+/***************************************************************************
+**
+** This program is free software; you can redistribute it and/or modify
+** it under the terms of the 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 _PERFORCE_PARSER_H
+#define _PERFORCE_PARSER_H
+
+#include "parserbase.h"
+
+namespace Diff2
+{
+
+class PerforceParser : public ParserBase
+{
+public:
+ PerforceParser( const KompareModelList* list, const QStringList& diff );
+ virtual ~PerforceParser();
+
+protected:
+ virtual bool parseContextDiffHeader();
+ virtual bool parseNormalDiffHeader();
+ virtual bool parseRCSDiffHeader();
+ virtual bool parseUnifiedDiffHeader();
+
+protected:
+ virtual enum Kompare::Format determineFormat();
+};
+
+} // End of namespace Diff2
+
+#endif
diff --git a/kompare/main.cpp b/kompare/main.cpp
new file mode 100644
index 00000000..00827c4d
--- /dev/null
+++ b/kompare/main.cpp
@@ -0,0 +1,217 @@
+/***************************************************************************
+ main.cpp - description
+ -------------------
+ begin : Sun Mar 4 2001
+ copyright : (C) 2001-2004 Otto Bruggeman
+ (C) 2001-2003 John Firebaugh
+ email : otto.bruggeman@home.nl
+ jfirebaugh@kde.org
+****************************************************************************/
+
+/***************************************************************************
+**
+** This program is free software; you can redistribute it and/or modify
+** it under the terms of the 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 <kaboutdata.h>
+#include <kcmdlineargs.h>
+#include <kdebug.h>
+#include <kfile.h>
+#include <klocale.h>
+#include <kmessagebox.h>
+
+#include "kompare_part.h"
+#include "kompare_shell.h"
+#include "kompareurldialog.h"
+
+static const char description[] =
+ I18N_NOOP("A program to view the differences between files and optionally generate a diff" );
+
+static const char version[] = "3.4";
+
+static KCmdLineOptions options[] =
+{
+ { "c", I18N_NOOP( "This will compare URL1 with URL2" ), 0 },
+ { "o", I18N_NOOP( "This will open URL1 and expect it to be diff output. URL1 can also be a '-' and then it will read from standard input. Can be used for instance for cvs diff | kompare -o -. Kompare will do a check to see if it can find the original file(s) and then blend the original file(s) into the diffoutput and show that in the viewer. -n disables the check." ), 0 },
+ { "b", I18N_NOOP( "This will blend URL2 into URL1, URL2 is expected to be diff output and URL1 the file or folder that the diffoutput needs to be blended into. " ), 0 },
+ { "n", I18N_NOOP( "Disables the check for automatically finding the original file(s) when using '-' as URL with the -o option." ), 0 },
+ { "e <encoding>", I18N_NOOP( "Use this to specify the encoding when calling it from the command line. It will default to the local encoding if not specified." ), 0 },
+ { "+[URL1 [URL2]]",0 , 0 },
+ { "+-", 0, 0 },
+// { "", I18N_NOOP( "" ), 0 },
+ KCmdLineLastOption
+};
+
+int main(int argc, char *argv[])
+{
+ KAboutData aboutData( "kompare", I18N_NOOP("Kompare"), version, description,
+ KAboutData::License_GPL,
+ I18N_NOOP("(c) 2001-2004, John Firebaugh and Otto Bruggeman"), 0, "http://bruggie.dnsalias.org/kompare/" );
+ aboutData.addAuthor( "John Firebaugh", I18N_NOOP("Author"), "jfirebaugh@kde.org" );
+ aboutData.addAuthor( "Otto Bruggeman", I18N_NOOP("Author"), "otto.bruggeman@home.nl" );
+ aboutData.addCredit( "Chris Luetchford", I18N_NOOP("Kompare icon artist"), "chris@os11.com" );
+ aboutData.addCredit( "Malte Starostik", I18N_NOOP("A lot of good advice"), "malte@kde.org" );
+ aboutData.addCredit( "Bernd Gehrmann", I18N_NOOP("Cervisia diff viewer"), "bernd@physik.hu-berlin.de" );
+
+ KCmdLineArgs::init(argc, argv, &aboutData);
+ KCmdLineArgs::addCmdLineOptions( options );
+ KApplication app;
+ bool difault = false;
+
+ // see if we are starting with session management
+ if (app.isRestored())
+ {
+ RESTORE(KompareShell)
+ }
+ else
+ {
+ KCmdLineArgs *args = KCmdLineArgs::parsedArgs();
+
+ KompareShell* ks;
+
+ kdDebug( 8100 ) << "Arg Count = " << args->count() << endl;
+ for ( int i=0; i < args->count(); i++ )
+ {
+ kdDebug( 8100 ) << "Argument " << (i+1) << ": " << args->arg( i ) << endl;
+ }
+
+ if ( args->isSet( "e" ) )
+ {
+ // Encoding given...
+ // FIXME: Need to implement this...
+ }
+
+ if ( args->isSet( "o" ) )
+ {
+ kdDebug( 8100 ) << "Option -o is set" << endl;
+ if ( args->count() != 1 )
+ {
+ difault = true;
+ }
+ else
+ {
+ ks = new KompareShell();
+ ks->show();
+ kdDebug( 8100 ) << "OpenDiff..." << endl;
+ if ( ( strlen( args->arg(0) ) == 1 ) && ( *(args->arg(0)) == '-' ) )
+ ks->openStdin();
+ else
+ ks->openDiff( args->url( 0 ) );
+ difault = false;
+ }
+ }
+ else if ( args->isSet( "c" ) )
+ {
+ kdDebug( 8100 ) << "Option -c is set" << endl;
+ if ( args->count() != 2 )
+ {
+ KCmdLineArgs::usage( "kompare" );
+ difault = true;
+ }
+ else
+ {
+ ks = new KompareShell();
+ ks->show();
+ KURL url0 = args->url( 0 );
+ kdDebug( 8100 ) << "URL0 = " << url0.url() << endl;
+ KURL url1 = args->url( 1 );
+ kdDebug( 8100 ) << "URL1 = " << url1.url() << endl;
+ ks->compare( url0, url1 );
+ difault = false;
+ }
+ }
+ else if ( args->isSet( "b" ) )
+ {
+ kdDebug( 8100 ) << "Option -b is set" << endl;
+ if ( args->count() != 2 )
+ {
+ KCmdLineArgs::usage( "kompare" );
+ difault = true;
+ }
+ else
+ {
+ ks = new KompareShell();
+ ks->show();
+ kdDebug( 8100 ) << "blend..." << endl;
+ KURL url0 = args->url( 0 );
+ kdDebug( 8100 ) << "URL0 = " << url0.url() << endl;
+ KURL url1 = args->url( 1 );
+ kdDebug( 8100 ) << "URL1 = " << url1.url() << endl;
+ ks->blend( url0, url1 );
+ difault = false;
+ }
+ }
+ else if ( args->count() == 1 )
+ {
+ ks = new KompareShell();
+ ks->show();
+
+ kdDebug( 8100 ) << "Single file. so openDiff/openStdin is only possible..." << endl;
+ if ( ( strlen( args->arg(0) ) == 1 && *(args->arg(0)) == '-' ) )
+ ks->openStdin();
+ else
+ ks->openDiff( args->url( 0 ) );
+
+ difault = false;
+ }
+ else if ( args->count() == 2 )
+ {
+ // In this case we are assuming you want to compare files/dirs
+ // and not blending because that is almost impossible to detect
+ ks = new KompareShell();
+ ks->show();
+ kdDebug( 8100 ) << "Dunno, we'll have to figure it out later, trying compare for now..." << endl;
+ KURL url0 = args->url( 0 );
+ kdDebug( 8100 ) << "URL0 = " << url0.url() << endl;
+ KURL url1 = args->url( 1 );
+ kdDebug( 8100 ) << "URL1 = " << url1.url() << endl;
+ ks->compare( url0, url1 );
+ difault = false;
+ }
+ else if ( args->count() == 0 ) // no options and no args
+ {
+ difault = true;
+ }
+
+ if ( difault )
+ {
+ KompareURLDialog* dialog = new KompareURLDialog();
+
+ dialog->setCaption( i18n("Compare Files or Folders") );
+ dialog->setFirstGroupBoxTitle( i18n( "Source" ) );
+ dialog->setSecondGroupBoxTitle( i18n( "Destination" ) );
+
+ KGuiItem compareGuiItem( i18n( "Compare" ), QString::null, i18n( "Compare these files or folder" ), i18n( "If you have entered 2 filenames or 2 folders in the fields in this dialog then this button will be enabled and pressing it will start a comparison of the entered files or folders. " ) );
+ dialog->setButtonOK( compareGuiItem );
+
+ dialog->setGroup( "Recent Compare Files" );
+
+ dialog->setFirstURLRequesterMode( KFile::File|KFile::Directory|KFile::ExistingOnly );
+ dialog->setSecondURLRequesterMode( KFile::File|KFile::Directory|KFile::ExistingOnly );
+
+ if( dialog->exec() == QDialog::Accepted )
+ {
+ ks = new KompareShell();
+ ks->show();
+ ks->viewPart()->setEncoding( dialog->encoding() );
+ ks->compare( dialog->getFirstURL(), dialog->getSecondURL() );
+ }
+ else
+ return -1;
+
+ delete dialog;
+ }
+
+ args->clear();
+ }
+
+ return kapp->exec();
+}
+
+/* vim: set ts=4 sw=4 noet: */
+
diff --git a/kompare/pics/Makefile.am b/kompare/pics/Makefile.am
new file mode 100644
index 00000000..f8961b29
--- /dev/null
+++ b/kompare/pics/Makefile.am
@@ -0,0 +1,3 @@
+KDE_ICON = AUTO
+
+
diff --git a/kompare/pics/hi128-app-kompare.png b/kompare/pics/hi128-app-kompare.png
new file mode 100644
index 00000000..27d8e576
--- /dev/null
+++ b/kompare/pics/hi128-app-kompare.png
Binary files differ
diff --git a/kompare/pics/hi16-app-kompare.png b/kompare/pics/hi16-app-kompare.png
new file mode 100644
index 00000000..6dbccf11
--- /dev/null
+++ b/kompare/pics/hi16-app-kompare.png
Binary files differ
diff --git a/kompare/pics/hi22-app-kompare.png b/kompare/pics/hi22-app-kompare.png
new file mode 100644
index 00000000..55c53514
--- /dev/null
+++ b/kompare/pics/hi22-app-kompare.png
Binary files differ
diff --git a/kompare/pics/hi32-app-kompare.png b/kompare/pics/hi32-app-kompare.png
new file mode 100644
index 00000000..68011ccf
--- /dev/null
+++ b/kompare/pics/hi32-app-kompare.png
Binary files differ
diff --git a/kompare/pics/hi48-app-kompare.png b/kompare/pics/hi48-app-kompare.png
new file mode 100644
index 00000000..fb04abca
--- /dev/null
+++ b/kompare/pics/hi48-app-kompare.png
Binary files differ
diff --git a/kompare/pics/hisc-app-kompare.svgz b/kompare/pics/hisc-app-kompare.svgz
new file mode 100644
index 00000000..35b0fb6c
--- /dev/null
+++ b/kompare/pics/hisc-app-kompare.svgz
Binary files differ
diff --git a/kompare/tests/cvsdiff/context.diff b/kompare/tests/cvsdiff/context.diff
new file mode 100644
index 00000000..c9a7f855
--- /dev/null
+++ b/kompare/tests/cvsdiff/context.diff
@@ -0,0 +1,83 @@
+Index: client/dcopfind.cpp
+===================================================================
+RCS file: /home/kde/kdelibs/dcop/client/dcopfind.cpp,v
+retrieving revision 1.2
+diff -c -r1.2 dcopfind.cpp
+*** client/dcopfind.cpp 2001/10/31 01:17:39 1.2
+--- client/dcopfind.cpp 2002/01/16 18:07:13
+***************
+*** 36,42 ****
+ static bool bAppIdOnly = 0;
+ static bool bLaunchApp = 0;
+
+! bool findObject( const char* app, const char* obj, const char* func, int argc, char** args )
+ {
+ QString f = func; // Qt is better with unicode strings, so use one.
+ int left = f.find( '(' );
+--- 36,42 ----
+ static bool bAppIdOnly = 0;
+ static bool bLaunchApp = 0;
+
+! bool findObject( const char* app, const char* obj, const char* func, QCStringList args )
+ {
+ QString f = func; // Qt is better with unicode strings, so use one.
+ int left = f.find( '(' );
+***************
+*** 118,124 ****
+ f = fc;
+ }
+
+! if ( (int) types.count() != argc ) {
+ qWarning( "arguments do not match" );
+ exit(1);
+ }
+--- 118,124 ----
+ f = fc;
+ }
+
+! if ( types.count() != args.count() ) {
+ qWarning( "arguments do not match" );
+ exit(1);
+ }
+***************
+*** 128,136 ****
+
+ int i = 0;
+ for ( QStringList::Iterator it = types.begin(); it != types.end(); ++it ) {
+! marshall(arg, argc, args, i, *it);
+ }
+! if ( (int) i != argc ) {
+ qWarning( "arguments do not match" );
+ exit(1);
+ }
+--- 128,136 ----
+
+ int i = 0;
+ for ( QStringList::Iterator it = types.begin(); it != types.end(); ++it ) {
+! marshall(arg, args, i, *it);
+ }
+! if ( (uint) i != args.count() ) {
+ qWarning( "arguments do not match" );
+ exit(1);
+ }
+***************
+*** 221,227 ****
+ argc = 0;
+ }
+
+! findObject( app, objid, function, argc, args );
+
+ return 0;
+ }
+--- 221,231 ----
+ argc = 0;
+ }
+
+! QCStringList params;
+! for( int i = 0; i < argc; i++ )
+! params.append( args[ i ] );
+!
+! findObject( app, objid, function, params );
+
+ return 0;
+ }
diff --git a/kompare/tests/cvsdiff/contextm.diff b/kompare/tests/cvsdiff/contextm.diff
new file mode 100644
index 00000000..ef20ec4c
--- /dev/null
+++ b/kompare/tests/cvsdiff/contextm.diff
@@ -0,0 +1,1046 @@
+Index: client/dcop.cpp
+===================================================================
+RCS file: /home/kde/kdelibs/dcop/client/dcop.cpp,v
+retrieving revision 1.26
+diff -c -r1.26 dcop.cpp
+*** client/dcop.cpp 2001/10/31 01:17:39 1.26
+--- client/dcop.cpp 2002/01/16 18:06:24
+***************
+*** 20,38 ****
+
+ ******************************************************************/
+
+! #include <qvariant.h>
+ #include <qcolor.h>
+! #include "../kdatastream.h"
+ #include "../dcopclient.h"
+ #include "../dcopref.h"
+! #include <stdlib.h>
+! #include <stdio.h>
+! #include <ctype.h>
+
+ #include "marshall.cpp"
+
+ static DCOPClient* dcop = 0;
+
+ bool startsWith(const QCString &id, const char *str, int n)
+ {
+ return !n || (strncmp(id.data(), str, n) == 0);
+--- 20,66 ----
+
+ ******************************************************************/
+
+! #include <ctype.h>
+! #include <stdio.h>
+! #include <stdlib.h>
+!
+ #include <qcolor.h>
+! #include <qdir.h>
+! #include <qfile.h>
+! #include <qfileinfo.h>
+! #include <qmap.h>
+! #include <qstringlist.h>
+! #include <qtextstream.h>
+! #include <qvariant.h>
+!
+! // putenv() is not available on all platforms, so make sure the emulation
+! // wrapper is available in those cases by loading config.h!
+! #include <config.h>
+!
+ #include "../dcopclient.h"
+ #include "../dcopref.h"
+! #include "../kdatastream.h"
+
+ #include "marshall.cpp"
+
++ typedef QMap<QString, QString> UserList;
++
+ static DCOPClient* dcop = 0;
+
++ static QTextStream cout( stdout, IO_WriteOnly );
++ static QTextStream cerr( stderr, IO_WriteOnly );
++
++ /**
++ * Session to send call to
++ * DefaultSession - current session. Current KDE session when called without
++ * --user or --all-users option. Otherwise this value ignores
++ * all users with more than one active session.
++ * AllSessions - Send to all sessions found. requires --user or --all-users.
++ * QuerySessions - Don't call DCOP, return a list of available sessions.
++ * CustomSession - Use the specified session
++ */
++ enum Session { DefaultSession = 0, AllSessions, QuerySessions, CustomSession };
++
+ bool startsWith(const QCString &id, const char *str, int n)
+ {
+ return !n || (strncmp(id.data(), str, n) == 0);
+***************
+*** 118,126 ****
+ }
+ }
+
+! void callFunction( const char* app, const char* obj, const char* func, int argc, char** args )
+ {
+-
+ QString f = func; // Qt is better with unicode strings, so use one.
+ int left = f.find( '(' );
+ int right = f.find( ')' );
+--- 146,153 ----
+ }
+ }
+
+! void callFunction( const char* app, const char* obj, const char* func, const QCStringList args )
+ {
+ QString f = func; // Qt is better with unicode strings, so use one.
+ int left = f.find( '(' );
+ int right = f.find( ')' );
+***************
+*** 136,142 ****
+ bool ok = false;
+ QCStringList funcs = dcop->remoteFunctions( app, obj, &ok );
+ QCString realfunc;
+! if ( !ok && argc == 0 )
+ goto doit;
+ if ( !ok )
+ {
+--- 163,169 ----
+ bool ok = false;
+ QCStringList funcs = dcop->remoteFunctions( app, obj, &ok );
+ QCString realfunc;
+! if ( !ok && args.isEmpty() )
+ goto doit;
+ if ( !ok )
+ {
+***************
+*** 153,167 ****
+
+ if ( l > 0 && (*it).mid( s, l - s ) == func ) {
+ realfunc = (*it).mid( s );
+! int a = (*it).contains(',');
+! if ( ( a == 0 && argc == 0) || ( a > 0 && a + 1 == argc ) )
+ break;
+ }
+ }
+ if ( realfunc.isEmpty() )
+ {
+ qWarning("no such function");
+! exit(1);
+ }
+ f = realfunc;
+ left = f.find( '(' );
+--- 180,195 ----
+
+ if ( l > 0 && (*it).mid( s, l - s ) == func ) {
+ realfunc = (*it).mid( s );
+! uint a = (*it).contains(',');
+! if ( ( a == 0 && args.isEmpty() ) || ( a > 0 && a + 1 == args.count() ) )
+ break;
+ }
+ }
+ if ( realfunc.isEmpty() )
+ {
+ qWarning("no such function");
+! // exit(1);
+! return;
+ }
+ f = realfunc;
+ left = f.find( '(' );
+***************
+*** 243,253 ****
+ QCString replyType;
+ QDataStream arg(data, IO_WriteOnly);
+
+! int i = 0;
+! for ( QStringList::Iterator it = types.begin(); it != types.end(); ++it ) {
+! marshall(arg, argc, args, i, *it);
+! }
+! if ( i != argc ) {
+ qWarning( "arguments do not match" );
+ exit(1);
+ }
+--- 271,282 ----
+ QCString replyType;
+ QDataStream arg(data, IO_WriteOnly);
+
+! uint i = 0;
+! for( QStringList::Iterator it = types.begin(); it != types.end(); ++it )
+! marshall( arg, args, i, *it );
+!
+! if ( i != args.count() )
+! {
+ qWarning( "arguments do not match" );
+ exit(1);
+ }
+***************
+*** 265,343 ****
+ }
+ }
+ }
+-
+
+
+! int main( int argc, char** argv )
+ {
+
+! if ( argc > 1 && argv[1][0] == '-' ) {
+! fprintf( stderr, "Usage: dcop [ application [object [function [arg1] [arg2] [arg3] ... ] ] ] \n" );
+! exit(0);
+ }
+
+! DCOPClient client;
+! client.attach();
+! dcop = &client;
+
+ QCString app;
+ QCString objid;
+ QCString function;
+! char **args = 0;
+! if ((argc > 1) && (strncmp(argv[1], "DCOPRef(", 8)) == 0)
+ {
+! char *delim = strchr(argv[1], ',');
+! if (!delim)
+! {
+! fprintf(stderr, "Error: '%s' is not a valid DCOP reference.\n", argv[1]);
+! return 1;
+! }
+! *delim = 0;
+! app = argv[1] + 8;
+! delim++;
+! delim[strlen(delim)-1] = 0;
+! objid = delim;
+! if (argc > 2)
+! function = argv[2];
+! if (argc > 3)
+! args = &argv[3];
+! argc++;
+ }
+ else
+ {
+! if (argc > 1)
+! app = argv[1];
+! if (argc > 2)
+! objid = argv[2];
+! if (argc > 3)
+! function = argv[3];
+! if (argc > 4)
+! args = &argv[4];
+! }
+!
+! switch ( argc ) {
+! case 0:
+! case 1:
+! queryApplications("");
+! break;
+! case 2:
+! if (endsWith(app, '*'))
+! queryApplications(app);
+! else
+! queryObjects( app, "" );
+! break;
+! case 3:
+! if (endsWith(objid, '*'))
+! queryObjects(app, objid);
+! else
+! queryFunctions( app, objid );
+! break;
+! case 4:
+! default:
+! callFunction( app, objid, function, argc - 4, args );
+! break;
+
+ }
+
+ return 0;
+ }
+--- 294,773 ----
+ }
+ }
+ }
+
++ /**
++ * Show command-line help and exit
++ */
++ void showHelp( int exitCode = 0 )
++ {
++ cout << "Usage: dcop [options] [application [object [function [arg1] [arg2] ... ] ] ]" << endl
++ << "" << endl
++ << "Console DCOP client" << endl
++ << "" << endl
++ << "Generic options:" << endl
++ << " --help Show help about options" << endl
++ << "" << endl
++ << "Options:" << endl
++ << " --pipe Call DCOP for each line read from stdin" << endl
++ << " --user <user> Connect to the given user's DCOP server. This option will" << endl
++ << " ignore the values of the environment vars $DCOPSERVER and" << endl
++ << " $ICEAUTHORITY, even if they are set." << endl
++ << " If the user has more than one open session, you must also" << endl
++ << " use one of the --list-sessions, --session or --als-sessions" << endl
++ << " command-line options." << endl
++ << " --all-users Send the same DCOP call to all users with a running DCOP" << endl
++ << " server. Only failed calls to existing DCOP servers will"
++ << " generate an error message. If no DCOP server is available" << endl
++ << " at all, no error will be generated." << endl;
++
++ exit( exitCode );
++ }
+
+! /**
+! * Return a list of all users and their home directories.
+! * Returns an empty list if /etc/passwd cannot be read for some reason.
+! */
+! static UserList userList()
+ {
++ UserList result;
++
++ QFile f( "/etc/passwd" );
++
++ if( !f.open( IO_ReadOnly ) )
++ {
++ cerr << "Can't open /etc/passwd for reading!" << endl;
++ return result;
++ }
+
+! QStringList l( QStringList::split( '\n', f.readAll() ) );
+!
+! for( QStringList::ConstIterator it( l.begin() ); it != l.end(); ++it )
+! {
+! QStringList userInfo( QStringList::split( ':', *it, true ) );
+! result[ userInfo[ 0 ] ] = userInfo[ 5 ];
+ }
+
+! return result;
+! }
+!
+! /**
+! * Return a list of available DCOP sessions for the specified user
+! * An empty list means no sessions are available, or an error occurred.
+! */
+! QStringList dcopSessionList( const QString &user, const QString &home )
+! {
+! if( home.isEmpty() )
+! {
+! cerr << "WARNING: Cannot determine home directory for user "
+! << user << "!" << endl
+! << "Please check permissions or set the $DCOPSERVER variable manually before" << endl
+! << "calling dcop." << endl;
+! return QStringList();
+! }
+!
+! QStringList result;
+! QFileInfo dirInfo( home );
+! if( !dirInfo.exists() || !dirInfo.isReadable() )
+! return result;
+!
+! QDir d( home );
+! d.setFilter( QDir::Files | QDir::Hidden | QDir::NoSymLinks );
+! d.setNameFilter( ".DCOPserver*" );
+!
+! const QFileInfoList *list = d.entryInfoList();
+! if( !list )
+! return result;
+!
+! QFileInfoListIterator it( *list );
+! QFileInfo *fi;
+!
+! while ( ( fi = it.current() ) != 0 )
+! {
+! if( fi->isReadable() )
+! result.append( fi->fileName() );
+! ++it;
+! }
+! return result;
+! }
+
++ /**
++ * Do the actual DCOP call
++ */
++ void runDCOP( QCStringList args, UserList users, Session session,
++ const QString sessionName, bool readStdin )
++ {
+ QCString app;
+ QCString objid;
+ QCString function;
+! QCStringList params;
+! DCOPClient *client = 0L;
+! if ( !args.isEmpty() && args[ 0 ].find( "DCOPRef(" ) == 0 )
+ {
+! // WARNING: This part (until the closing '}') could very
+! // well be broken now. As I don't know how to trigger and test
+! // dcoprefs this code is *not* tested. It compiles and it looks
+! // ok to me, but that's all I can say - Martijn (2001/12/24)
+! int delimPos = args[ 0 ].findRev( ',' );
+! if( delimPos == -1 )
+! {
+! cerr << "Error: '" << args[ 0 ]
+! << "' is not a valid DCOP reference." << endl;
+! exit( -1 );
+! }
+! args[ 0 ][ delimPos ] = 0;
+! app = args[ 0 ].mid( 8 );
+! delimPos++;
+! args[ 0 ][ args[ 0 ].length() - 1 ] = 0;
+! objid = args[ 0 ].mid( delimPos );
+! if( args.count() > 1 )
+! function = args[ 1 ];
+! if( args.count() > 2 )
+! {
+! params = args;
+! params.remove( params.begin() );
+! params.remove( params.begin() );
+! }
+ }
+ else
+ {
+! if( !args.isEmpty() )
+! app = args[ 0 ];
+! if( args.count() > 1 )
+! objid = args[ 1 ];
+! if( args.count() > 2 )
+! function = args[ 2 ];
+! if( args.count() > 3)
+! {
+! params = args;
+! params.remove( params.begin() );
+! params.remove( params.begin() );
+! params.remove( params.begin() );
+! }
+! }
+!
+! bool firstRun = true;
+! UserList::Iterator it;
+! QStringList sessions;
+! bool presetDCOPServer = false;
+! // char *dcopStr = 0L;
+! QString dcopServer;
+!
+! for( it = users.begin(); it != users.end() || firstRun; it++ )
+! {
+! firstRun = false;
+!
+! //cout << "Iterating '" << it.key() << "'" << endl;
+!
+! if( session == QuerySessions )
+! {
+! QStringList sessions = dcopSessionList( it.key(), it.data() );
+! if( sessions.isEmpty() )
+! {
+! cout << "No active sessions";
+! if( !( *it ).isEmpty() )
+! cout << " for user " << *it;
+! cout << endl;
+! }
+! else
+! {
+! cout << "Active sessions ";
+! if( !( *it ).isEmpty() )
+! cout << "for user " << *it << " ";
+! cout << ":" << endl;
+!
+! QStringList::Iterator sIt;
+! for( sIt = sessions.begin(); sIt != sessions.end(); sIt++ )
+! cout << " " << *sIt << endl;
+!
+! cout << endl;
+! }
+! continue;
+! }
+!
+! if( getenv( "DCOPSERVER" ) )
+! {
+! sessions.append( getenv( "DCOPSERVER" ) );
+! presetDCOPServer = true;
+! }
+!
+! if( users.count() > 1 || ( users.count() == 1 &&
+! ( getenv( "DCOPSERVER" ) == 0 /*&& getenv( "DISPLAY" ) == 0*/ ) ) )
+! {
+! sessions = dcopSessionList( it.key(), it.data() );
+! if( sessions.isEmpty() )
+! {
+! if( users.count() > 1 )
+! continue;
+! else
+! {
+! cerr << "ERROR: No active KDE sessions!" << endl
+! << "If you are sure there is one, please set the $DCOPSERVER variable manually" << endl
+! << "before calling dcop." << endl;
+! exit( -1 );
+! }
+! }
+! else if( sessions.count() > 1 && session != AllSessions )
+! {
+! cerr << "ERROR: Multiple available KDE sessions!" << endl
+! << "Please specify the correct session to use with --session or use the" << endl
+! << "--all-sessions option to broadcast to all sessions." << endl;
+! exit( -1 );
+! }
+! }
+
++ if( users.count() > 1 || ( users.count() == 1 &&
++ ( getenv( "ICEAUTHORITY" ) == 0 || getenv( "DISPLAY" ) == 0 ) ) )
++ {
++ // Check for ICE authority file and if the file can be read by us
++ QString home = it.data();
++ QString iceFile = it.data() + "/.ICEauthority";
++ QFileInfo fi( iceFile );
++ if( iceFile.isEmpty() )
++ {
++ cerr << "WARNING: Cannot determine home directory for user "
++ << it.key() << "!" << endl
++ << "Please check permissions or set the $ICEAUTHORITY variable manually before" << endl
++ << "calling dcop." << endl;
++ }
++ else if( fi.exists() )
++ {
++ if( fi.isReadable() )
++ {
++ char *envStr = strdup( ( "ICEAUTHORITY=" + iceFile ).ascii() );
++ putenv( envStr );
++ //cerr << "ice: " << envStr << endl;
++ }
++ else
++ {
++ cerr << "WARNING: ICE authority file " << iceFile
++ << "is not readable by you!" << endl
++ << "Please check permissions or set the $ICEAUTHORITY variable manually before" << endl
++ << "calling dcop." << endl;
++ }
++ }
++ else
++ {
++ if( users.count() > 1 )
++ continue;
++ else
++ {
++ cerr << "WARNING: Cannot find ICE authority file "
++ << iceFile << "!" << endl
++ << "Please check permissions or set the $ICEAUTHORITY"
++ << " variable manually before" << endl
++ << "calling dcop." << endl;
++ }
++ }
++ }
++
++ // Main loop
++ // If users is an empty list we're calling for the currently logged
++ // in user. In this case we don't have a session, but still want
++ // to iterate the loop once.
++ QStringList::Iterator sIt = sessions.begin();
++ for( ; sIt != sessions.end() || users.isEmpty(); sIt++ )
++ {
++ if( !presetDCOPServer && !users.isEmpty() )
++ {
++ QString dcopFile = it.data() + "/" + *sIt;
++ QFile f( dcopFile );
++ if( !f.open( IO_ReadOnly ) )
++ {
++ cerr << "Can't open " << dcopFile << " for reading!" << endl;
++ exit( -1 );
++ }
++
++ QStringList l( QStringList::split( '\n', f.readAll() ) );
++ dcopServer = l.first();
++
++ if( dcopServer.isEmpty() )
++ {
++ cerr << "WARNING: Unable to determine DCOP server for session "
++ << *sIt << "!" << endl
++ << "Please check permissions or set the $DCOPSERVER variable manually before" << endl
++ << "calling dcop." << endl;
++ exit( -1 );
++ }
++ }
++
++ delete client;
++ client = new DCOPClient;
++ if( !dcopServer.isEmpty() )
++ client->setServerAddress( dcopServer.ascii() );
++ bool success = client->attach();
++ if( !success )
++ {
++ cerr << "ERROR: Couldn't attach to DCOP server!" << endl;
++ continue;
++ }
++ dcop = client;
++
++ switch ( args.count() )
++ {
++ case 0:
++ queryApplications("");
++ break;
++ case 1:
++ if (endsWith(app, '*'))
++ queryApplications(app);
++ else
++ queryObjects( app, "" );
++ break;
++ case 2:
++ if (endsWith(objid, '*'))
++ queryObjects(app, objid);
++ else
++ queryFunctions( app, objid );
++ break;
++ case 3:
++ default:
++ if( readStdin )
++ {
++ QCStringList::Iterator replaceArg = args.end();
++
++ QCStringList::Iterator it;
++ for( it = args.begin(); it != args.end(); it++ )
++ if( *it == "%1" )
++ replaceArg = it;
++
++ // Read from stdin until EOF and call function for each line read
++ char *buf = new char[ 1000 ];
++ while ( !feof( stdin ) )
++ {
++ fgets( buf, 1000, stdin );
++
++ if( replaceArg != args.end() )
++ *replaceArg = buf;
++
++ callFunction( app, objid, function, params );
++ }
++ }
++ else
++ {
++ // Just call function
++ // cout << "call " << app << ", " << objid << ", " << function << ", (params)" << endl;
++ callFunction( app, objid, function, params );
++ }
++ break;
++ }
++ // Another sIt++ would make the loop infinite...
++ if( users.isEmpty() )
++ break;
++ }
++
++ // Another it++ would make the loop infinite...
++ if( it == users.end() )
++ break;
+ }
++ }
++
+
++ int main( int argc, char** argv )
++ {
++ bool readStdin = false;
++ int numOptions = 0;
++ QString user;
++ Session session = DefaultSession;
++ QString sessionName;
++
++ // Scan for command-line options first
++ for( int pos = 1 ; pos <= argc - 1 ; pos++ )
++ {
++ if( strcmp( argv[ pos ], "--help" ) == 0 )
++ showHelp( 0 );
++ else if( strcmp( argv[ pos ], "--pipe" ) == 0 )
++ {
++ readStdin = true;
++ numOptions++;
++ }
++ else if( strcmp( argv[ pos ], "--user" ) == 0 )
++ {
++ if( pos <= argc - 2 )
++ {
++ user = QString::fromLocal8Bit( argv[ pos + 1] );
++ numOptions +=2;
++ pos++;
++ }
++ else
++ {
++ cerr << "Missing username for '--user' option!" << endl << endl;
++ showHelp( -1 );
++ }
++ }
++ else if( strcmp( argv[ pos ], "--all-users" ) == 0 )
++ {
++ user = "*";
++ numOptions ++;
++ }
++ else if( strcmp( argv[ pos ], "--list-sessions" ) == 0 )
++ {
++ session = QuerySessions;
++ numOptions ++;
++ }
++ else if( strcmp( argv[ pos ], "--all-sessions" ) == 0 )
++ {
++ session = AllSessions;
++ numOptions ++;
++ }
++ else if( argv[ pos ][ 0 ] == '-' )
++ {
++ cerr << "Unknown command-line option '" << argv[ pos ]
++ << "'." << endl << endl;
++ showHelp( -1 );
++ }
++ else
++ break; // End of options
++ }
++
++ argc -= numOptions;
++
++ QCStringList args;
++ for( int i = numOptions; i < argc + numOptions - 1; i++ )
++ args.append( argv[ i + 1 ] );
++
++ if( readStdin && args.count() < 3 )
++ {
++ cerr << "--pipe option only supported for function calls!" << endl << endl;
++ showHelp( -1 );
++ }
++
++ if( user == "*" && args.count() < 3 && session != QuerySessions )
++ {
++ cerr << "ERROR: The --all-users option is only supported for function calls!" << endl << endl;
++ showHelp( -1 );
++ }
++
++ if( session == QuerySessions && !args.isEmpty() )
++ {
++ cerr << "ERROR: The --list-sessions option cannot be used for actual DCOP calls!" << endl << endl;
++ showHelp( -1 );
++ }
++
++ if( session == QuerySessions && user.isEmpty() )
++ {
++ cerr << "ERROR: The --list-sessions option can only be used with the --user or" << endl
++ << "--all-users options!" << endl << endl;
++ showHelp( -1 );
++ }
++
++ if( session != DefaultSession && session != QuerySessions &&
++ args.count() < 3 )
++ {
++ cerr << "ERROR: The --session and --all-sessions options are only supported for function" << endl
++ << "calls!" << endl << endl;
++ showHelp( -1 );
++ }
++
++ UserList users;
++ if( user == "*" )
++ users = userList();
++ else if( !user.isEmpty() )
++ users[ user ] = userList()[ user ];
++
++ runDCOP( args, users, session, sessionName, readStdin );
++
+ return 0;
+ }
++
++ // vim: set ts=8 sts=4 sw=4 noet:
++
+Index: client/dcopfind.cpp
+===================================================================
+RCS file: /home/kde/kdelibs/dcop/client/dcopfind.cpp,v
+retrieving revision 1.2
+diff -c -r1.2 dcopfind.cpp
+*** client/dcopfind.cpp 2001/10/31 01:17:39 1.2
+--- client/dcopfind.cpp 2002/01/16 18:06:24
+***************
+*** 36,42 ****
+ static bool bAppIdOnly = 0;
+ static bool bLaunchApp = 0;
+
+! bool findObject( const char* app, const char* obj, const char* func, int argc, char** args )
+ {
+ QString f = func; // Qt is better with unicode strings, so use one.
+ int left = f.find( '(' );
+--- 36,42 ----
+ static bool bAppIdOnly = 0;
+ static bool bLaunchApp = 0;
+
+! bool findObject( const char* app, const char* obj, const char* func, QCStringList args )
+ {
+ QString f = func; // Qt is better with unicode strings, so use one.
+ int left = f.find( '(' );
+***************
+*** 118,124 ****
+ f = fc;
+ }
+
+! if ( (int) types.count() != argc ) {
+ qWarning( "arguments do not match" );
+ exit(1);
+ }
+--- 118,124 ----
+ f = fc;
+ }
+
+! if ( types.count() != args.count() ) {
+ qWarning( "arguments do not match" );
+ exit(1);
+ }
+***************
+*** 128,136 ****
+
+ int i = 0;
+ for ( QStringList::Iterator it = types.begin(); it != types.end(); ++it ) {
+! marshall(arg, argc, args, i, *it);
+ }
+! if ( (int) i != argc ) {
+ qWarning( "arguments do not match" );
+ exit(1);
+ }
+--- 128,136 ----
+
+ int i = 0;
+ for ( QStringList::Iterator it = types.begin(); it != types.end(); ++it ) {
+! marshall(arg, args, i, *it);
+ }
+! if ( (uint) i != args.count() ) {
+ qWarning( "arguments do not match" );
+ exit(1);
+ }
+***************
+*** 221,227 ****
+ argc = 0;
+ }
+
+! findObject( app, objid, function, argc, args );
+
+ return 0;
+ }
+--- 221,231 ----
+ argc = 0;
+ }
+
+! QCStringList params;
+! for( int i = 0; i < argc; i++ )
+! params.append( args[ i ] );
+!
+! findObject( app, objid, function, params );
+
+ return 0;
+ }
+Index: client/marshall.cpp
+===================================================================
+RCS file: /home/kde/kdelibs/dcop/client/marshall.cpp,v
+retrieving revision 1.3
+diff -c -r1.3 marshall.cpp
+*** client/marshall.cpp 2001/10/31 01:17:39 1.3
+--- client/marshall.cpp 2002/01/16 18:06:24
+***************
+*** 242,349 ****
+
+ }
+
+! void marshall(QDataStream &arg, int argc, char **argv, int &i, QString type)
+ {
+! if (type == "QStringList")
+! type = "QValueList<QString>";
+! if (type == "QCStringList")
+! type = "QValueList<QCString>";
+! if (i >= argc)
+! {
+! qWarning("Not enough arguments.");
+! exit(1);
+! }
+! QString s = QString::fromLocal8Bit(argv[i]);
+!
+! if ( type == "int" )
+! arg << s.toInt();
+! else if ( type == "uint" )
+! arg << s.toUInt();
+! else if ( type == "unsigned" )
+! arg << s.toUInt();
+! else if ( type == "unsigned int" )
+! arg << s.toUInt();
+! else if ( type == "long" )
+! arg << s.toLong();
+! else if ( type == "long int" )
+! arg << s.toLong();
+! else if ( type == "unsigned long" )
+! arg << s.toULong();
+! else if ( type == "unsigned long int" )
+! arg << s.toULong();
+! else if ( type == "float" )
+! arg << s.toFloat();
+! else if ( type == "double" )
+! arg << s.toDouble();
+! else if ( type == "bool" )
+! arg << mkBool( s );
+! else if ( type == "QString" )
+! arg << s;
+! else if ( type == "QCString" )
+! arg << QCString( argv[i] );
+! else if ( type == "QColor" )
+! arg << mkColor( s );
+! else if ( type == "QPoint" )
+! arg << mkPoint( s );
+! else if ( type == "QSize" )
+! arg << mkSize( s );
+! else if ( type == "QRect" )
+! arg << mkRect( s );
+! else if ( type == "QVariant" ) {
+! if ( s == "true" || s == "false" )
+! arg << QVariant( mkBool( s ), 42 );
+! else if ( s.left( 4 ) == "int(" )
+! arg << QVariant( s.mid(4, s.length()-5).toInt() );
+! else if ( s.left( 7 ) == "QPoint(" )
+! arg << QVariant( mkPoint( s.mid(7, s.length()-8) ) );
+! else if ( s.left( 6 ) == "QSize(" )
+! arg << QVariant( mkSize( s.mid(6, s.length()-7) ) );
+! else if ( s.left( 6 ) == "QRect(" )
+! arg << QVariant( mkRect( s.mid(6, s.length()-7) ) );
+! else if ( s.left( 7 ) == "QColor(" )
+! arg << QVariant( mkColor( s.mid(7, s.length()-8) ) );
+! else
+! arg << QVariant( s );
+! } else if ( type.startsWith("QValueList<")) {
+! type = type.mid(11, type.length() - 12);
+! QStringList list;
+! QString delim = s;
+! if (delim == "[")
+! delim = "]";
+! if (delim == "(")
+! delim = ")";
+! i++;
+! QByteArray dummy_data;
+! QDataStream dummy_arg(dummy_data, IO_WriteOnly);
+
+! int j = i;
+! int count = 0;
+! // Parse list to get the count
+! while (true) {
+! if (j >= argc)
+! {
+! qWarning("List end-delimiter '%s' not found.", delim.latin1());
+! exit(1);
+! }
+! if (argv[j] == delim) break;
+! marshall(dummy_arg, argc, argv, j, type);
+! count++;
+! }
+! arg << (Q_UINT32) count;
+! // Parse the list for real
+! while (true) {
+! if (i >= argc)
+! {
+! qWarning("List end-delimiter '%s' not found.", delim.latin1());
+! exit(1);
+! }
+! if (argv[i] == delim) break;
+! marshall(arg, argc, argv, i, type);
+! }
+! } else {
+! qWarning( "cannot handle datatype '%s'", type.latin1() );
+! exit(1);
+! }
+ i++;
+ }
+
+--- 242,351 ----
+
+ }
+
+! void marshall( QDataStream &arg, QCStringList args, uint &i, QString type )
+ {
+! if (type == "QStringList")
+! type = "QValueList<QString>";
+! if (type == "QCStringList")
+! type = "QValueList<QCString>";
+! if( i > args.count() )
+! {
+! qWarning("Not enough arguments.");
+! exit(1);
+! }
+! QString s = QString::fromLocal8Bit( args[ i ] );
+
+! if ( type == "int" )
+! arg << s.toInt();
+! else if ( type == "uint" )
+! arg << s.toUInt();
+! else if ( type == "unsigned" )
+! arg << s.toUInt();
+! else if ( type == "unsigned int" )
+! arg << s.toUInt();
+! else if ( type == "long" )
+! arg << s.toLong();
+! else if ( type == "long int" )
+! arg << s.toLong();
+! else if ( type == "unsigned long" )
+! arg << s.toULong();
+! else if ( type == "unsigned long int" )
+! arg << s.toULong();
+! else if ( type == "float" )
+! arg << s.toFloat();
+! else if ( type == "double" )
+! arg << s.toDouble();
+! else if ( type == "bool" )
+! arg << mkBool( s );
+! else if ( type == "QString" )
+! arg << s;
+! else if ( type == "QCString" )
+! arg << QCString( args[ i ] );
+! else if ( type == "QColor" )
+! arg << mkColor( s );
+! else if ( type == "QPoint" )
+! arg << mkPoint( s );
+! else if ( type == "QSize" )
+! arg << mkSize( s );
+! else if ( type == "QRect" )
+! arg << mkRect( s );
+! else if ( type == "QVariant" ) {
+! if ( s == "true" || s == "false" )
+! arg << QVariant( mkBool( s ), 42 );
+! else if ( s.left( 4 ) == "int(" )
+! arg << QVariant( s.mid(4, s.length()-5).toInt() );
+! else if ( s.left( 7 ) == "QPoint(" )
+! arg << QVariant( mkPoint( s.mid(7, s.length()-8) ) );
+! else if ( s.left( 6 ) == "QSize(" )
+! arg << QVariant( mkSize( s.mid(6, s.length()-7) ) );
+! else if ( s.left( 6 ) == "QRect(" )
+! arg << QVariant( mkRect( s.mid(6, s.length()-7) ) );
+! else if ( s.left( 7 ) == "QColor(" )
+! arg << QVariant( mkColor( s.mid(7, s.length()-8) ) );
+! else
+! arg << QVariant( s );
+! } else if ( type.startsWith("QValueList<")) {
+! type = type.mid(11, type.length() - 12);
+! QStringList list;
+! QString delim = s;
+! if (delim == "[")
+! delim = "]";
+! if (delim == "(")
+! delim = ")";
+ i++;
++ QByteArray dummy_data;
++ QDataStream dummy_arg(dummy_data, IO_WriteOnly);
++
++ uint j = i;
++ uint count = 0;
++ // Parse list to get the count
++ while (true) {
++ if( j > args.count() )
++ {
++ qWarning("List end-delimiter '%s' not found.", delim.latin1());
++ exit(1);
++ }
++ if( QString::fromLocal8Bit( args[ j ] ) == delim )
++ break;
++ marshall( dummy_arg, args, j, type );
++ count++;
++ }
++ arg << (Q_UINT32) count;
++ // Parse the list for real
++ while (true) {
++ if( i > args.count() )
++ {
++ qWarning("List end-delimiter '%s' not found.", delim.latin1());
++ exit(1);
++ }
++ if( QString::fromLocal8Bit( args[ i ] ) == delim )
++ break;
++ marshall( arg, args, i, type );
++ }
++ } else {
++ qWarning( "cannot handle datatype '%s'", type.latin1() );
++ exit(1);
++ }
++ i++;
+ }
+
diff --git a/kompare/tests/cvsdiff/ed.diff b/kompare/tests/cvsdiff/ed.diff
new file mode 100644
index 00000000..2c859e61
--- /dev/null
+++ b/kompare/tests/cvsdiff/ed.diff
@@ -0,0 +1,24 @@
+Index: client/dcopfind.cpp
+===================================================================
+RCS file: /home/kde/kdelibs/dcop/client/dcopfind.cpp,v
+retrieving revision 1.2
+diff -e -r1.2 dcopfind.cpp
+224c
+ QCStringList params;
+ for( int i = 0; i < argc; i++ )
+ params.append( args[ i ] );
+
+ findObject( app, objid, function, params );
+.
+133c
+ if ( (uint) i != args.count() ) {
+.
+131c
+ marshall(arg, args, i, *it);
+.
+121c
+ if ( types.count() != args.count() ) {
+.
+39c
+bool findObject( const char* app, const char* obj, const char* func, QCStringList args )
+.
diff --git a/kompare/tests/cvsdiff/edm.diff b/kompare/tests/cvsdiff/edm.diff
new file mode 100644
index 00000000..0fb04575
--- /dev/null
+++ b/kompare/tests/cvsdiff/edm.diff
@@ -0,0 +1,692 @@
+Index: client/dcop.cpp
+===================================================================
+RCS file: /home/kde/kdelibs/dcop/client/dcop.cpp,v
+retrieving revision 1.26
+diff -e -r1.26 dcop.cpp
+343a
+
+// vim: set ts=8 sts=4 sw=4 noet:
+
+.
+340a
+}
+
+
+int main( int argc, char** argv )
+{
+ bool readStdin = false;
+ int numOptions = 0;
+ QString user;
+ Session session = DefaultSession;
+ QString sessionName;
+
+ // Scan for command-line options first
+ for( int pos = 1 ; pos <= argc - 1 ; pos++ )
+ {
+ if( strcmp( argv[ pos ], "--help" ) == 0 )
+ showHelp( 0 );
+ else if( strcmp( argv[ pos ], "--pipe" ) == 0 )
+ {
+ readStdin = true;
+ numOptions++;
+ }
+ else if( strcmp( argv[ pos ], "--user" ) == 0 )
+ {
+ if( pos <= argc - 2 )
+ {
+ user = QString::fromLocal8Bit( argv[ pos + 1] );
+ numOptions +=2;
+ pos++;
+ }
+ else
+ {
+ cerr << "Missing username for '--user' option!" << endl << endl;
+ showHelp( -1 );
+ }
+ }
+ else if( strcmp( argv[ pos ], "--all-users" ) == 0 )
+ {
+ user = "*";
+ numOptions ++;
+ }
+ else if( strcmp( argv[ pos ], "--list-sessions" ) == 0 )
+ {
+ session = QuerySessions;
+ numOptions ++;
+ }
+ else if( strcmp( argv[ pos ], "--all-sessions" ) == 0 )
+ {
+ session = AllSessions;
+ numOptions ++;
+ }
+ else if( argv[ pos ][ 0 ] == '-' )
+ {
+ cerr << "Unknown command-line option '" << argv[ pos ]
+ << "'." << endl << endl;
+ showHelp( -1 );
+ }
+ else
+ break; // End of options
+ }
+
+ argc -= numOptions;
+
+ QCStringList args;
+ for( int i = numOptions; i < argc + numOptions - 1; i++ )
+ args.append( argv[ i + 1 ] );
+
+ if( readStdin && args.count() < 3 )
+ {
+ cerr << "--pipe option only supported for function calls!" << endl << endl;
+ showHelp( -1 );
+ }
+
+ if( user == "*" && args.count() < 3 && session != QuerySessions )
+ {
+ cerr << "ERROR: The --all-users option is only supported for function calls!" << endl << endl;
+ showHelp( -1 );
+ }
+
+ if( session == QuerySessions && !args.isEmpty() )
+ {
+ cerr << "ERROR: The --list-sessions option cannot be used for actual DCOP calls!" << endl << endl;
+ showHelp( -1 );
+ }
+
+ if( session == QuerySessions && user.isEmpty() )
+ {
+ cerr << "ERROR: The --list-sessions option can only be used with the --user or" << endl
+ << "--all-users options!" << endl << endl;
+ showHelp( -1 );
+ }
+
+ if( session != DefaultSession && session != QuerySessions &&
+ args.count() < 3 )
+ {
+ cerr << "ERROR: The --session and --all-sessions options are only supported for function" << endl
+ << "calls!" << endl << endl;
+ showHelp( -1 );
+ }
+
+ UserList users;
+ if( user == "*" )
+ users = userList();
+ else if( !user.isEmpty() )
+ users[ user ] = userList()[ user ];
+
+ runDCOP( args, users, session, sessionName, readStdin );
+.
+339a
+ if( users.count() > 1 || ( users.count() == 1 &&
+ ( getenv( "ICEAUTHORITY" ) == 0 || getenv( "DISPLAY" ) == 0 ) ) )
+ {
+ // Check for ICE authority file and if the file can be read by us
+ QString home = it.data();
+ QString iceFile = it.data() + "/.ICEauthority";
+ QFileInfo fi( iceFile );
+ if( iceFile.isEmpty() )
+ {
+ cerr << "WARNING: Cannot determine home directory for user "
+ << it.key() << "!" << endl
+ << "Please check permissions or set the $ICEAUTHORITY variable manually before" << endl
+ << "calling dcop." << endl;
+ }
+ else if( fi.exists() )
+ {
+ if( fi.isReadable() )
+ {
+ char *envStr = strdup( ( "ICEAUTHORITY=" + iceFile ).ascii() );
+ putenv( envStr );
+ //cerr << "ice: " << envStr << endl;
+ }
+ else
+ {
+ cerr << "WARNING: ICE authority file " << iceFile
+ << "is not readable by you!" << endl
+ << "Please check permissions or set the $ICEAUTHORITY variable manually before" << endl
+ << "calling dcop." << endl;
+ }
+ }
+ else
+ {
+ if( users.count() > 1 )
+ continue;
+ else
+ {
+ cerr << "WARNING: Cannot find ICE authority file "
+ << iceFile << "!" << endl
+ << "Please check permissions or set the $ICEAUTHORITY"
+ << " variable manually before" << endl
+ << "calling dcop." << endl;
+ }
+ }
+ }
+
+ // Main loop
+ // If users is an empty list we're calling for the currently logged
+ // in user. In this case we don't have a session, but still want
+ // to iterate the loop once.
+ QStringList::Iterator sIt = sessions.begin();
+ for( ; sIt != sessions.end() || users.isEmpty(); sIt++ )
+ {
+ if( !presetDCOPServer && !users.isEmpty() )
+ {
+ QString dcopFile = it.data() + "/" + *sIt;
+ QFile f( dcopFile );
+ if( !f.open( IO_ReadOnly ) )
+ {
+ cerr << "Can't open " << dcopFile << " for reading!" << endl;
+ exit( -1 );
+ }
+
+ QStringList l( QStringList::split( '\n', f.readAll() ) );
+ dcopServer = l.first();
+
+ if( dcopServer.isEmpty() )
+ {
+ cerr << "WARNING: Unable to determine DCOP server for session "
+ << *sIt << "!" << endl
+ << "Please check permissions or set the $DCOPSERVER variable manually before" << endl
+ << "calling dcop." << endl;
+ exit( -1 );
+ }
+ }
+
+ delete client;
+ client = new DCOPClient;
+ if( !dcopServer.isEmpty() )
+ client->setServerAddress( dcopServer.ascii() );
+ bool success = client->attach();
+ if( !success )
+ {
+ cerr << "ERROR: Couldn't attach to DCOP server!" << endl;
+ continue;
+ }
+ dcop = client;
+
+ switch ( args.count() )
+ {
+ case 0:
+ queryApplications("");
+ break;
+ case 1:
+ if (endsWith(app, '*'))
+ queryApplications(app);
+ else
+ queryObjects( app, "" );
+ break;
+ case 2:
+ if (endsWith(objid, '*'))
+ queryObjects(app, objid);
+ else
+ queryFunctions( app, objid );
+ break;
+ case 3:
+ default:
+ if( readStdin )
+ {
+ QCStringList::Iterator replaceArg = args.end();
+
+ QCStringList::Iterator it;
+ for( it = args.begin(); it != args.end(); it++ )
+ if( *it == "%1" )
+ replaceArg = it;
+
+ // Read from stdin until EOF and call function for each line read
+ char *buf = new char[ 1000 ];
+ while ( !feof( stdin ) )
+ {
+ fgets( buf, 1000, stdin );
+
+ if( replaceArg != args.end() )
+ *replaceArg = buf;
+
+ callFunction( app, objid, function, params );
+ }
+ }
+ else
+ {
+ // Just call function
+// cout << "call " << app << ", " << objid << ", " << function << ", (params)" << endl;
+ callFunction( app, objid, function, params );
+ }
+ break;
+ }
+ // Another sIt++ would make the loop infinite...
+ if( users.isEmpty() )
+ break;
+ }
+
+ // Another it++ would make the loop infinite...
+ if( it == users.end() )
+ break;
+.
+308,338c
+ if( !args.isEmpty() )
+ app = args[ 0 ];
+ if( args.count() > 1 )
+ objid = args[ 1 ];
+ if( args.count() > 2 )
+ function = args[ 2 ];
+ if( args.count() > 3)
+ {
+ params = args;
+ params.remove( params.begin() );
+ params.remove( params.begin() );
+ params.remove( params.begin() );
+ }
+ }
+
+ bool firstRun = true;
+ UserList::Iterator it;
+ QStringList sessions;
+ bool presetDCOPServer = false;
+// char *dcopStr = 0L;
+ QString dcopServer;
+
+ for( it = users.begin(); it != users.end() || firstRun; it++ )
+ {
+ firstRun = false;
+
+ //cout << "Iterating '" << it.key() << "'" << endl;
+
+ if( session == QuerySessions )
+ {
+ QStringList sessions = dcopSessionList( it.key(), it.data() );
+ if( sessions.isEmpty() )
+ {
+ cout << "No active sessions";
+ if( !( *it ).isEmpty() )
+ cout << " for user " << *it;
+ cout << endl;
+ }
+ else
+ {
+ cout << "Active sessions ";
+ if( !( *it ).isEmpty() )
+ cout << "for user " << *it << " ";
+ cout << ":" << endl;
+
+ QStringList::Iterator sIt;
+ for( sIt = sessions.begin(); sIt != sessions.end(); sIt++ )
+ cout << " " << *sIt << endl;
+
+ cout << endl;
+ }
+ continue;
+ }
+
+ if( getenv( "DCOPSERVER" ) )
+ {
+ sessions.append( getenv( "DCOPSERVER" ) );
+ presetDCOPServer = true;
+ }
+
+ if( users.count() > 1 || ( users.count() == 1 &&
+ ( getenv( "DCOPSERVER" ) == 0 /*&& getenv( "DISPLAY" ) == 0*/ ) ) )
+ {
+ sessions = dcopSessionList( it.key(), it.data() );
+ if( sessions.isEmpty() )
+ {
+ if( users.count() > 1 )
+ continue;
+ else
+ {
+ cerr << "ERROR: No active KDE sessions!" << endl
+ << "If you are sure there is one, please set the $DCOPSERVER variable manually" << endl
+ << "before calling dcop." << endl;
+ exit( -1 );
+ }
+ }
+ else if( sessions.count() > 1 && session != AllSessions )
+ {
+ cerr << "ERROR: Multiple available KDE sessions!" << endl
+ << "Please specify the correct session to use with --session or use the" << endl
+ << "--all-sessions option to broadcast to all sessions." << endl;
+ exit( -1 );
+ }
+ }
+.
+289,304c
+ // WARNING: This part (until the closing '}') could very
+ // well be broken now. As I don't know how to trigger and test
+ // dcoprefs this code is *not* tested. It compiles and it looks
+ // ok to me, but that's all I can say - Martijn (2001/12/24)
+ int delimPos = args[ 0 ].findRev( ',' );
+ if( delimPos == -1 )
+ {
+ cerr << "Error: '" << args[ 0 ]
+ << "' is not a valid DCOP reference." << endl;
+ exit( -1 );
+ }
+ args[ 0 ][ delimPos ] = 0;
+ app = args[ 0 ].mid( 8 );
+ delimPos++;
+ args[ 0 ][ args[ 0 ].length() - 1 ] = 0;
+ objid = args[ 0 ].mid( delimPos );
+ if( args.count() > 1 )
+ function = args[ 1 ];
+ if( args.count() > 2 )
+ {
+ params = args;
+ params.remove( params.begin() );
+ params.remove( params.begin() );
+ }
+.
+286,287c
+ QCStringList params;
+ DCOPClient *client = 0L;
+ if ( !args.isEmpty() && args[ 0 ].find( "DCOPRef(" ) == 0 )
+.
+282a
+/**
+ * Do the actual DCOP call
+ */
+void runDCOP( QCStringList args, UserList users, Session session,
+ const QString sessionName, bool readStdin )
+{
+.
+279,281c
+ return result;
+}
+
+/**
+ * Return a list of available DCOP sessions for the specified user
+ * An empty list means no sessions are available, or an error occurred.
+ */
+QStringList dcopSessionList( const QString &user, const QString &home )
+{
+ if( home.isEmpty() )
+ {
+ cerr << "WARNING: Cannot determine home directory for user "
+ << user << "!" << endl
+ << "Please check permissions or set the $DCOPSERVER variable manually before" << endl
+ << "calling dcop." << endl;
+ return QStringList();
+ }
+
+ QStringList result;
+ QFileInfo dirInfo( home );
+ if( !dirInfo.exists() || !dirInfo.isReadable() )
+ return result;
+
+ QDir d( home );
+ d.setFilter( QDir::Files | QDir::Hidden | QDir::NoSymLinks );
+ d.setNameFilter( ".DCOPserver*" );
+
+ const QFileInfoList *list = d.entryInfoList();
+ if( !list )
+ return result;
+
+ QFileInfoListIterator it( *list );
+ QFileInfo *fi;
+
+ while ( ( fi = it.current() ) != 0 )
+ {
+ if( fi->isReadable() )
+ result.append( fi->fileName() );
+ ++it;
+ }
+ return result;
+}
+.
+274,276c
+ QStringList l( QStringList::split( '\n', f.readAll() ) );
+
+ for( QStringList::ConstIterator it( l.begin() ); it != l.end(); ++it )
+ {
+ QStringList userInfo( QStringList::split( ':', *it, true ) );
+ result[ userInfo[ 0 ] ] = userInfo[ 5 ];
+.
+272a
+ UserList result;
+
+ QFile f( "/etc/passwd" );
+
+ if( !f.open( IO_ReadOnly ) )
+ {
+ cerr << "Can't open /etc/passwd for reading!" << endl;
+ return result;
+ }
+.
+270,271c
+/**
+ * Return a list of all users and their home directories.
+ * Returns an empty list if /etc/passwd cannot be read for some reason.
+ */
+static UserList userList()
+.
+268a
+/**
+ * Show command-line help and exit
+ */
+void showHelp( int exitCode = 0 )
+{
+ cout << "Usage: dcop [options] [application [object [function [arg1] [arg2] ... ] ] ]" << endl
+ << "" << endl
+ << "Console DCOP client" << endl
+ << "" << endl
+ << "Generic options:" << endl
+ << " --help Show help about options" << endl
+ << "" << endl
+ << "Options:" << endl
+ << " --pipe Call DCOP for each line read from stdin" << endl
+ << " --user <user> Connect to the given user's DCOP server. This option will" << endl
+ << " ignore the values of the environment vars $DCOPSERVER and" << endl
+ << " $ICEAUTHORITY, even if they are set." << endl
+ << " If the user has more than one open session, you must also" << endl
+ << " use one of the --list-sessions, --session or --als-sessions" << endl
+ << " command-line options." << endl
+ << " --all-users Send the same DCOP call to all users with a running DCOP" << endl
+ << " server. Only failed calls to existing DCOP servers will"
+ << " generate an error message. If no DCOP server is available" << endl
+ << " at all, no error will be generated." << endl;
+
+ exit( exitCode );
+}
+.
+246,250c
+ uint i = 0;
+ for( QStringList::Iterator it = types.begin(); it != types.end(); ++it )
+ marshall( arg, args, i, *it );
+
+ if ( i != args.count() )
+ {
+.
+164c
+// exit(1);
+ return;
+.
+156,157c
+ uint a = (*it).contains(',');
+ if ( ( a == 0 && args.isEmpty() ) || ( a > 0 && a + 1 == args.count() ) )
+.
+139c
+ if ( !ok && args.isEmpty() )
+.
+123d
+121c
+void callFunction( const char* app, const char* obj, const char* func, const QCStringList args )
+.
+35a
+static QTextStream cout( stdout, IO_WriteOnly );
+static QTextStream cerr( stderr, IO_WriteOnly );
+
+/**
+ * Session to send call to
+ * DefaultSession - current session. Current KDE session when called without
+ * --user or --all-users option. Otherwise this value ignores
+ * all users with more than one active session.
+ * AllSessions - Send to all sessions found. requires --user or --all-users.
+ * QuerySessions - Don't call DCOP, return a list of available sessions.
+ * CustomSession - Use the specified session
+ */
+enum Session { DefaultSession = 0, AllSessions, QuerySessions, CustomSession };
+
+.
+33a
+typedef QMap<QString, QString> UserList;
+
+.
+28,30c
+#include "../kdatastream.h"
+.
+25c
+#include <qdir.h>
+#include <qfile.h>
+#include <qfileinfo.h>
+#include <qmap.h>
+#include <qstringlist.h>
+#include <qtextstream.h>
+#include <qvariant.h>
+
+// putenv() is not available on all platforms, so make sure the emulation
+// wrapper is available in those cases by loading config.h!
+#include <config.h>
+
+.
+23c
+#include <ctype.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+.
+Index: client/dcopfind.cpp
+===================================================================
+RCS file: /home/kde/kdelibs/dcop/client/dcopfind.cpp,v
+retrieving revision 1.2
+diff -e -r1.2 dcopfind.cpp
+224c
+ QCStringList params;
+ for( int i = 0; i < argc; i++ )
+ params.append( args[ i ] );
+
+ findObject( app, objid, function, params );
+.
+133c
+ if ( (uint) i != args.count() ) {
+.
+131c
+ marshall(arg, args, i, *it);
+.
+121c
+ if ( types.count() != args.count() ) {
+.
+39c
+bool findObject( const char* app, const char* obj, const char* func, QCStringList args )
+.
+Index: client/marshall.cpp
+===================================================================
+RCS file: /home/kde/kdelibs/dcop/client/marshall.cpp,v
+retrieving revision 1.3
+diff -e -r1.3 marshall.cpp
+347a
+ QByteArray dummy_data;
+ QDataStream dummy_arg(dummy_data, IO_WriteOnly);
+
+ uint j = i;
+ uint count = 0;
+ // Parse list to get the count
+ while (true) {
+ if( j > args.count() )
+ {
+ qWarning("List end-delimiter '%s' not found.", delim.latin1());
+ exit(1);
+ }
+ if( QString::fromLocal8Bit( args[ j ] ) == delim )
+ break;
+ marshall( dummy_arg, args, j, type );
+ count++;
+ }
+ arg << (Q_UINT32) count;
+ // Parse the list for real
+ while (true) {
+ if( i > args.count() )
+ {
+ qWarning("List end-delimiter '%s' not found.", delim.latin1());
+ exit(1);
+ }
+ if( QString::fromLocal8Bit( args[ i ] ) == delim )
+ break;
+ marshall( arg, args, i, type );
+ }
+ } else {
+ qWarning( "cannot handle datatype '%s'", type.latin1() );
+ exit(1);
+ }
+ i++;
+.
+319,346c
+ if ( type == "int" )
+ arg << s.toInt();
+ else if ( type == "uint" )
+ arg << s.toUInt();
+ else if ( type == "unsigned" )
+ arg << s.toUInt();
+ else if ( type == "unsigned int" )
+ arg << s.toUInt();
+ else if ( type == "long" )
+ arg << s.toLong();
+ else if ( type == "long int" )
+ arg << s.toLong();
+ else if ( type == "unsigned long" )
+ arg << s.toULong();
+ else if ( type == "unsigned long int" )
+ arg << s.toULong();
+ else if ( type == "float" )
+ arg << s.toFloat();
+ else if ( type == "double" )
+ arg << s.toDouble();
+ else if ( type == "bool" )
+ arg << mkBool( s );
+ else if ( type == "QString" )
+ arg << s;
+ else if ( type == "QCString" )
+ arg << QCString( args[ i ] );
+ else if ( type == "QColor" )
+ arg << mkColor( s );
+ else if ( type == "QPoint" )
+ arg << mkPoint( s );
+ else if ( type == "QSize" )
+ arg << mkSize( s );
+ else if ( type == "QRect" )
+ arg << mkRect( s );
+ else if ( type == "QVariant" ) {
+ if ( s == "true" || s == "false" )
+ arg << QVariant( mkBool( s ), 42 );
+ else if ( s.left( 4 ) == "int(" )
+ arg << QVariant( s.mid(4, s.length()-5).toInt() );
+ else if ( s.left( 7 ) == "QPoint(" )
+ arg << QVariant( mkPoint( s.mid(7, s.length()-8) ) );
+ else if ( s.left( 6 ) == "QSize(" )
+ arg << QVariant( mkSize( s.mid(6, s.length()-7) ) );
+ else if ( s.left( 6 ) == "QRect(" )
+ arg << QVariant( mkRect( s.mid(6, s.length()-7) ) );
+ else if ( s.left( 7 ) == "QColor(" )
+ arg << QVariant( mkColor( s.mid(7, s.length()-8) ) );
+ else
+ arg << QVariant( s );
+ } else if ( type.startsWith("QValueList<")) {
+ type = type.mid(11, type.length() - 12);
+ QStringList list;
+ QString delim = s;
+ if (delim == "[")
+ delim = "]";
+ if (delim == "(")
+ delim = ")";
+.
+247,317c
+ if (type == "QStringList")
+ type = "QValueList<QString>";
+ if (type == "QCStringList")
+ type = "QValueList<QCString>";
+ if( i > args.count() )
+ {
+ qWarning("Not enough arguments.");
+ exit(1);
+ }
+ QString s = QString::fromLocal8Bit( args[ i ] );
+.
+245c
+void marshall( QDataStream &arg, QCStringList args, uint &i, QString type )
+.
diff --git a/kompare/tests/cvsdiff/normal.diff b/kompare/tests/cvsdiff/normal.diff
new file mode 100644
index 00000000..3becb815
--- /dev/null
+++ b/kompare/tests/cvsdiff/normal.diff
@@ -0,0 +1,29 @@
+Index: client/dcopfind.cpp
+===================================================================
+RCS file: /home/kde/kdelibs/dcop/client/dcopfind.cpp,v
+retrieving revision 1.2
+diff -r1.2 dcopfind.cpp
+39c39
+< bool findObject( const char* app, const char* obj, const char* func, int argc, char** args )
+---
+> bool findObject( const char* app, const char* obj, const char* func, QCStringList args )
+121c121
+< if ( (int) types.count() != argc ) {
+---
+> if ( types.count() != args.count() ) {
+131c131
+< marshall(arg, argc, args, i, *it);
+---
+> marshall(arg, args, i, *it);
+133c133
+< if ( (int) i != argc ) {
+---
+> if ( (uint) i != args.count() ) {
+224c224,228
+< findObject( app, objid, function, argc, args );
+---
+> QCStringList params;
+> for( int i = 0; i < argc; i++ )
+> params.append( args[ i ] );
+>
+> findObject( app, objid, function, params );
diff --git a/kompare/tests/cvsdiff/normalm.diff b/kompare/tests/cvsdiff/normalm.diff
new file mode 100644
index 00000000..935763a0
--- /dev/null
+++ b/kompare/tests/cvsdiff/normalm.diff
@@ -0,0 +1,861 @@
+Index: client/dcop.cpp
+===================================================================
+RCS file: /home/kde/kdelibs/dcop/client/dcop.cpp,v
+retrieving revision 1.26
+diff -r1.26 dcop.cpp
+23c23,26
+< #include <qvariant.h>
+---
+> #include <ctype.h>
+> #include <stdio.h>
+> #include <stdlib.h>
+>
+25c28,39
+< #include "../kdatastream.h"
+---
+> #include <qdir.h>
+> #include <qfile.h>
+> #include <qfileinfo.h>
+> #include <qmap.h>
+> #include <qstringlist.h>
+> #include <qtextstream.h>
+> #include <qvariant.h>
+>
+> // putenv() is not available on all platforms, so make sure the emulation
+> // wrapper is available in those cases by loading config.h!
+> #include <config.h>
+>
+28,30c42
+< #include <stdlib.h>
+< #include <stdio.h>
+< #include <ctype.h>
+---
+> #include "../kdatastream.h"
+33a46,47
+> typedef QMap<QString, QString> UserList;
+>
+35a50,63
+> static QTextStream cout( stdout, IO_WriteOnly );
+> static QTextStream cerr( stderr, IO_WriteOnly );
+>
+> /**
+> * Session to send call to
+> * DefaultSession - current session. Current KDE session when called without
+> * --user or --all-users option. Otherwise this value ignores
+> * all users with more than one active session.
+> * AllSessions - Send to all sessions found. requires --user or --all-users.
+> * QuerySessions - Don't call DCOP, return a list of available sessions.
+> * CustomSession - Use the specified session
+> */
+> enum Session { DefaultSession = 0, AllSessions, QuerySessions, CustomSession };
+>
+121c149
+< void callFunction( const char* app, const char* obj, const char* func, int argc, char** args )
+---
+> void callFunction( const char* app, const char* obj, const char* func, const QCStringList args )
+123d150
+<
+139c166
+< if ( !ok && argc == 0 )
+---
+> if ( !ok && args.isEmpty() )
+156,157c183,184
+< int a = (*it).contains(',');
+< if ( ( a == 0 && argc == 0) || ( a > 0 && a + 1 == argc ) )
+---
+> uint a = (*it).contains(',');
+> if ( ( a == 0 && args.isEmpty() ) || ( a > 0 && a + 1 == args.count() ) )
+164c191,192
+< exit(1);
+---
+> // exit(1);
+> return;
+246,250c274,279
+< int i = 0;
+< for ( QStringList::Iterator it = types.begin(); it != types.end(); ++it ) {
+< marshall(arg, argc, args, i, *it);
+< }
+< if ( i != argc ) {
+---
+> uint i = 0;
+> for( QStringList::Iterator it = types.begin(); it != types.end(); ++it )
+> marshall( arg, args, i, *it );
+>
+> if ( i != args.count() )
+> {
+268a298,324
+> /**
+> * Show command-line help and exit
+> */
+> void showHelp( int exitCode = 0 )
+> {
+> cout << "Usage: dcop [options] [application [object [function [arg1] [arg2] ... ] ] ]" << endl
+> << "" << endl
+> << "Console DCOP client" << endl
+> << "" << endl
+> << "Generic options:" << endl
+> << " --help Show help about options" << endl
+> << "" << endl
+> << "Options:" << endl
+> << " --pipe Call DCOP for each line read from stdin" << endl
+> << " --user <user> Connect to the given user's DCOP server. This option will" << endl
+> << " ignore the values of the environment vars $DCOPSERVER and" << endl
+> << " $ICEAUTHORITY, even if they are set." << endl
+> << " If the user has more than one open session, you must also" << endl
+> << " use one of the --list-sessions, --session or --als-sessions" << endl
+> << " command-line options." << endl
+> << " --all-users Send the same DCOP call to all users with a running DCOP" << endl
+> << " server. Only failed calls to existing DCOP servers will"
+> << " generate an error message. If no DCOP server is available" << endl
+> << " at all, no error will be generated." << endl;
+>
+> exit( exitCode );
+> }
+270,271c326,330
+<
+< int main( int argc, char** argv )
+---
+> /**
+> * Return a list of all users and their home directories.
+> * Returns an empty list if /etc/passwd cannot be read for some reason.
+> */
+> static UserList userList()
+272a332,340
+> UserList result;
+>
+> QFile f( "/etc/passwd" );
+>
+> if( !f.open( IO_ReadOnly ) )
+> {
+> cerr << "Can't open /etc/passwd for reading!" << endl;
+> return result;
+> }
+274,276c342,347
+< if ( argc > 1 && argv[1][0] == '-' ) {
+< fprintf( stderr, "Usage: dcop [ application [object [function [arg1] [arg2] [arg3] ... ] ] ] \n" );
+< exit(0);
+---
+> QStringList l( QStringList::split( '\n', f.readAll() ) );
+>
+> for( QStringList::ConstIterator it( l.begin() ); it != l.end(); ++it )
+> {
+> QStringList userInfo( QStringList::split( ':', *it, true ) );
+> result[ userInfo[ 0 ] ] = userInfo[ 5 ];
+279,281c350,391
+< DCOPClient client;
+< client.attach();
+< dcop = &client;
+---
+> return result;
+> }
+>
+> /**
+> * Return a list of available DCOP sessions for the specified user
+> * An empty list means no sessions are available, or an error occurred.
+> */
+> QStringList dcopSessionList( const QString &user, const QString &home )
+> {
+> if( home.isEmpty() )
+> {
+> cerr << "WARNING: Cannot determine home directory for user "
+> << user << "!" << endl
+> << "Please check permissions or set the $DCOPSERVER variable manually before" << endl
+> << "calling dcop." << endl;
+> return QStringList();
+> }
+>
+> QStringList result;
+> QFileInfo dirInfo( home );
+> if( !dirInfo.exists() || !dirInfo.isReadable() )
+> return result;
+>
+> QDir d( home );
+> d.setFilter( QDir::Files | QDir::Hidden | QDir::NoSymLinks );
+> d.setNameFilter( ".DCOPserver*" );
+>
+> const QFileInfoList *list = d.entryInfoList();
+> if( !list )
+> return result;
+>
+> QFileInfoListIterator it( *list );
+> QFileInfo *fi;
+>
+> while ( ( fi = it.current() ) != 0 )
+> {
+> if( fi->isReadable() )
+> result.append( fi->fileName() );
+> ++it;
+> }
+> return result;
+> }
+282a393,398
+> /**
+> * Do the actual DCOP call
+> */
+> void runDCOP( QCStringList args, UserList users, Session session,
+> const QString sessionName, bool readStdin )
+> {
+286,287c402,404
+< char **args = 0;
+< if ((argc > 1) && (strncmp(argv[1], "DCOPRef(", 8)) == 0)
+---
+> QCStringList params;
+> DCOPClient *client = 0L;
+> if ( !args.isEmpty() && args[ 0 ].find( "DCOPRef(" ) == 0 )
+289,304c406,429
+< char *delim = strchr(argv[1], ',');
+< if (!delim)
+< {
+< fprintf(stderr, "Error: '%s' is not a valid DCOP reference.\n", argv[1]);
+< return 1;
+< }
+< *delim = 0;
+< app = argv[1] + 8;
+< delim++;
+< delim[strlen(delim)-1] = 0;
+< objid = delim;
+< if (argc > 2)
+< function = argv[2];
+< if (argc > 3)
+< args = &argv[3];
+< argc++;
+---
+> // WARNING: This part (until the closing '}') could very
+> // well be broken now. As I don't know how to trigger and test
+> // dcoprefs this code is *not* tested. It compiles and it looks
+> // ok to me, but that's all I can say - Martijn (2001/12/24)
+> int delimPos = args[ 0 ].findRev( ',' );
+> if( delimPos == -1 )
+> {
+> cerr << "Error: '" << args[ 0 ]
+> << "' is not a valid DCOP reference." << endl;
+> exit( -1 );
+> }
+> args[ 0 ][ delimPos ] = 0;
+> app = args[ 0 ].mid( 8 );
+> delimPos++;
+> args[ 0 ][ args[ 0 ].length() - 1 ] = 0;
+> objid = args[ 0 ].mid( delimPos );
+> if( args.count() > 1 )
+> function = args[ 1 ];
+> if( args.count() > 2 )
+> {
+> params = args;
+> params.remove( params.begin() );
+> params.remove( params.begin() );
+> }
+308,338c433,516
+< if (argc > 1)
+< app = argv[1];
+< if (argc > 2)
+< objid = argv[2];
+< if (argc > 3)
+< function = argv[3];
+< if (argc > 4)
+< args = &argv[4];
+< }
+<
+< switch ( argc ) {
+< case 0:
+< case 1:
+< queryApplications("");
+< break;
+< case 2:
+< if (endsWith(app, '*'))
+< queryApplications(app);
+< else
+< queryObjects( app, "" );
+< break;
+< case 3:
+< if (endsWith(objid, '*'))
+< queryObjects(app, objid);
+< else
+< queryFunctions( app, objid );
+< break;
+< case 4:
+< default:
+< callFunction( app, objid, function, argc - 4, args );
+< break;
+---
+> if( !args.isEmpty() )
+> app = args[ 0 ];
+> if( args.count() > 1 )
+> objid = args[ 1 ];
+> if( args.count() > 2 )
+> function = args[ 2 ];
+> if( args.count() > 3)
+> {
+> params = args;
+> params.remove( params.begin() );
+> params.remove( params.begin() );
+> params.remove( params.begin() );
+> }
+> }
+>
+> bool firstRun = true;
+> UserList::Iterator it;
+> QStringList sessions;
+> bool presetDCOPServer = false;
+> // char *dcopStr = 0L;
+> QString dcopServer;
+>
+> for( it = users.begin(); it != users.end() || firstRun; it++ )
+> {
+> firstRun = false;
+>
+> //cout << "Iterating '" << it.key() << "'" << endl;
+>
+> if( session == QuerySessions )
+> {
+> QStringList sessions = dcopSessionList( it.key(), it.data() );
+> if( sessions.isEmpty() )
+> {
+> cout << "No active sessions";
+> if( !( *it ).isEmpty() )
+> cout << " for user " << *it;
+> cout << endl;
+> }
+> else
+> {
+> cout << "Active sessions ";
+> if( !( *it ).isEmpty() )
+> cout << "for user " << *it << " ";
+> cout << ":" << endl;
+>
+> QStringList::Iterator sIt;
+> for( sIt = sessions.begin(); sIt != sessions.end(); sIt++ )
+> cout << " " << *sIt << endl;
+>
+> cout << endl;
+> }
+> continue;
+> }
+>
+> if( getenv( "DCOPSERVER" ) )
+> {
+> sessions.append( getenv( "DCOPSERVER" ) );
+> presetDCOPServer = true;
+> }
+>
+> if( users.count() > 1 || ( users.count() == 1 &&
+> ( getenv( "DCOPSERVER" ) == 0 /*&& getenv( "DISPLAY" ) == 0*/ ) ) )
+> {
+> sessions = dcopSessionList( it.key(), it.data() );
+> if( sessions.isEmpty() )
+> {
+> if( users.count() > 1 )
+> continue;
+> else
+> {
+> cerr << "ERROR: No active KDE sessions!" << endl
+> << "If you are sure there is one, please set the $DCOPSERVER variable manually" << endl
+> << "before calling dcop." << endl;
+> exit( -1 );
+> }
+> }
+> else if( sessions.count() > 1 && session != AllSessions )
+> {
+> cerr << "ERROR: Multiple available KDE sessions!" << endl
+> << "Please specify the correct session to use with --session or use the" << endl
+> << "--all-sessions option to broadcast to all sessions." << endl;
+> exit( -1 );
+> }
+> }
+339a518,660
+> if( users.count() > 1 || ( users.count() == 1 &&
+> ( getenv( "ICEAUTHORITY" ) == 0 || getenv( "DISPLAY" ) == 0 ) ) )
+> {
+> // Check for ICE authority file and if the file can be read by us
+> QString home = it.data();
+> QString iceFile = it.data() + "/.ICEauthority";
+> QFileInfo fi( iceFile );
+> if( iceFile.isEmpty() )
+> {
+> cerr << "WARNING: Cannot determine home directory for user "
+> << it.key() << "!" << endl
+> << "Please check permissions or set the $ICEAUTHORITY variable manually before" << endl
+> << "calling dcop." << endl;
+> }
+> else if( fi.exists() )
+> {
+> if( fi.isReadable() )
+> {
+> char *envStr = strdup( ( "ICEAUTHORITY=" + iceFile ).ascii() );
+> putenv( envStr );
+> //cerr << "ice: " << envStr << endl;
+> }
+> else
+> {
+> cerr << "WARNING: ICE authority file " << iceFile
+> << "is not readable by you!" << endl
+> << "Please check permissions or set the $ICEAUTHORITY variable manually before" << endl
+> << "calling dcop." << endl;
+> }
+> }
+> else
+> {
+> if( users.count() > 1 )
+> continue;
+> else
+> {
+> cerr << "WARNING: Cannot find ICE authority file "
+> << iceFile << "!" << endl
+> << "Please check permissions or set the $ICEAUTHORITY"
+> << " variable manually before" << endl
+> << "calling dcop." << endl;
+> }
+> }
+> }
+>
+> // Main loop
+> // If users is an empty list we're calling for the currently logged
+> // in user. In this case we don't have a session, but still want
+> // to iterate the loop once.
+> QStringList::Iterator sIt = sessions.begin();
+> for( ; sIt != sessions.end() || users.isEmpty(); sIt++ )
+> {
+> if( !presetDCOPServer && !users.isEmpty() )
+> {
+> QString dcopFile = it.data() + "/" + *sIt;
+> QFile f( dcopFile );
+> if( !f.open( IO_ReadOnly ) )
+> {
+> cerr << "Can't open " << dcopFile << " for reading!" << endl;
+> exit( -1 );
+> }
+>
+> QStringList l( QStringList::split( '\n', f.readAll() ) );
+> dcopServer = l.first();
+>
+> if( dcopServer.isEmpty() )
+> {
+> cerr << "WARNING: Unable to determine DCOP server for session "
+> << *sIt << "!" << endl
+> << "Please check permissions or set the $DCOPSERVER variable manually before" << endl
+> << "calling dcop." << endl;
+> exit( -1 );
+> }
+> }
+>
+> delete client;
+> client = new DCOPClient;
+> if( !dcopServer.isEmpty() )
+> client->setServerAddress( dcopServer.ascii() );
+> bool success = client->attach();
+> if( !success )
+> {
+> cerr << "ERROR: Couldn't attach to DCOP server!" << endl;
+> continue;
+> }
+> dcop = client;
+>
+> switch ( args.count() )
+> {
+> case 0:
+> queryApplications("");
+> break;
+> case 1:
+> if (endsWith(app, '*'))
+> queryApplications(app);
+> else
+> queryObjects( app, "" );
+> break;
+> case 2:
+> if (endsWith(objid, '*'))
+> queryObjects(app, objid);
+> else
+> queryFunctions( app, objid );
+> break;
+> case 3:
+> default:
+> if( readStdin )
+> {
+> QCStringList::Iterator replaceArg = args.end();
+>
+> QCStringList::Iterator it;
+> for( it = args.begin(); it != args.end(); it++ )
+> if( *it == "%1" )
+> replaceArg = it;
+>
+> // Read from stdin until EOF and call function for each line read
+> char *buf = new char[ 1000 ];
+> while ( !feof( stdin ) )
+> {
+> fgets( buf, 1000, stdin );
+>
+> if( replaceArg != args.end() )
+> *replaceArg = buf;
+>
+> callFunction( app, objid, function, params );
+> }
+> }
+> else
+> {
+> // Just call function
+> // cout << "call " << app << ", " << objid << ", " << function << ", (params)" << endl;
+> callFunction( app, objid, function, params );
+> }
+> break;
+> }
+> // Another sIt++ would make the loop infinite...
+> if( users.isEmpty() )
+> break;
+> }
+>
+> // Another it++ would make the loop infinite...
+> if( it == users.end() )
+> break;
+340a662,767
+> }
+>
+>
+> int main( int argc, char** argv )
+> {
+> bool readStdin = false;
+> int numOptions = 0;
+> QString user;
+> Session session = DefaultSession;
+> QString sessionName;
+>
+> // Scan for command-line options first
+> for( int pos = 1 ; pos <= argc - 1 ; pos++ )
+> {
+> if( strcmp( argv[ pos ], "--help" ) == 0 )
+> showHelp( 0 );
+> else if( strcmp( argv[ pos ], "--pipe" ) == 0 )
+> {
+> readStdin = true;
+> numOptions++;
+> }
+> else if( strcmp( argv[ pos ], "--user" ) == 0 )
+> {
+> if( pos <= argc - 2 )
+> {
+> user = QString::fromLocal8Bit( argv[ pos + 1] );
+> numOptions +=2;
+> pos++;
+> }
+> else
+> {
+> cerr << "Missing username for '--user' option!" << endl << endl;
+> showHelp( -1 );
+> }
+> }
+> else if( strcmp( argv[ pos ], "--all-users" ) == 0 )
+> {
+> user = "*";
+> numOptions ++;
+> }
+> else if( strcmp( argv[ pos ], "--list-sessions" ) == 0 )
+> {
+> session = QuerySessions;
+> numOptions ++;
+> }
+> else if( strcmp( argv[ pos ], "--all-sessions" ) == 0 )
+> {
+> session = AllSessions;
+> numOptions ++;
+> }
+> else if( argv[ pos ][ 0 ] == '-' )
+> {
+> cerr << "Unknown command-line option '" << argv[ pos ]
+> << "'." << endl << endl;
+> showHelp( -1 );
+> }
+> else
+> break; // End of options
+> }
+>
+> argc -= numOptions;
+>
+> QCStringList args;
+> for( int i = numOptions; i < argc + numOptions - 1; i++ )
+> args.append( argv[ i + 1 ] );
+>
+> if( readStdin && args.count() < 3 )
+> {
+> cerr << "--pipe option only supported for function calls!" << endl << endl;
+> showHelp( -1 );
+> }
+>
+> if( user == "*" && args.count() < 3 && session != QuerySessions )
+> {
+> cerr << "ERROR: The --all-users option is only supported for function calls!" << endl << endl;
+> showHelp( -1 );
+> }
+>
+> if( session == QuerySessions && !args.isEmpty() )
+> {
+> cerr << "ERROR: The --list-sessions option cannot be used for actual DCOP calls!" << endl << endl;
+> showHelp( -1 );
+> }
+>
+> if( session == QuerySessions && user.isEmpty() )
+> {
+> cerr << "ERROR: The --list-sessions option can only be used with the --user or" << endl
+> << "--all-users options!" << endl << endl;
+> showHelp( -1 );
+> }
+>
+> if( session != DefaultSession && session != QuerySessions &&
+> args.count() < 3 )
+> {
+> cerr << "ERROR: The --session and --all-sessions options are only supported for function" << endl
+> << "calls!" << endl << endl;
+> showHelp( -1 );
+> }
+>
+> UserList users;
+> if( user == "*" )
+> users = userList();
+> else if( !user.isEmpty() )
+> users[ user ] = userList()[ user ];
+>
+> runDCOP( args, users, session, sessionName, readStdin );
+343a771,773
+>
+> // vim: set ts=8 sts=4 sw=4 noet:
+>
+Index: client/dcopfind.cpp
+===================================================================
+RCS file: /home/kde/kdelibs/dcop/client/dcopfind.cpp,v
+retrieving revision 1.2
+diff -r1.2 dcopfind.cpp
+39c39
+< bool findObject( const char* app, const char* obj, const char* func, int argc, char** args )
+---
+> bool findObject( const char* app, const char* obj, const char* func, QCStringList args )
+121c121
+< if ( (int) types.count() != argc ) {
+---
+> if ( types.count() != args.count() ) {
+131c131
+< marshall(arg, argc, args, i, *it);
+---
+> marshall(arg, args, i, *it);
+133c133
+< if ( (int) i != argc ) {
+---
+> if ( (uint) i != args.count() ) {
+224c224,228
+< findObject( app, objid, function, argc, args );
+---
+> QCStringList params;
+> for( int i = 0; i < argc; i++ )
+> params.append( args[ i ] );
+>
+> findObject( app, objid, function, params );
+Index: client/marshall.cpp
+===================================================================
+RCS file: /home/kde/kdelibs/dcop/client/marshall.cpp,v
+retrieving revision 1.3
+diff -r1.3 marshall.cpp
+245c245
+< void marshall(QDataStream &arg, int argc, char **argv, int &i, QString type)
+---
+> void marshall( QDataStream &arg, QCStringList args, uint &i, QString type )
+247,317c247,256
+< if (type == "QStringList")
+< type = "QValueList<QString>";
+< if (type == "QCStringList")
+< type = "QValueList<QCString>";
+< if (i >= argc)
+< {
+< qWarning("Not enough arguments.");
+< exit(1);
+< }
+< QString s = QString::fromLocal8Bit(argv[i]);
+<
+< if ( type == "int" )
+< arg << s.toInt();
+< else if ( type == "uint" )
+< arg << s.toUInt();
+< else if ( type == "unsigned" )
+< arg << s.toUInt();
+< else if ( type == "unsigned int" )
+< arg << s.toUInt();
+< else if ( type == "long" )
+< arg << s.toLong();
+< else if ( type == "long int" )
+< arg << s.toLong();
+< else if ( type == "unsigned long" )
+< arg << s.toULong();
+< else if ( type == "unsigned long int" )
+< arg << s.toULong();
+< else if ( type == "float" )
+< arg << s.toFloat();
+< else if ( type == "double" )
+< arg << s.toDouble();
+< else if ( type == "bool" )
+< arg << mkBool( s );
+< else if ( type == "QString" )
+< arg << s;
+< else if ( type == "QCString" )
+< arg << QCString( argv[i] );
+< else if ( type == "QColor" )
+< arg << mkColor( s );
+< else if ( type == "QPoint" )
+< arg << mkPoint( s );
+< else if ( type == "QSize" )
+< arg << mkSize( s );
+< else if ( type == "QRect" )
+< arg << mkRect( s );
+< else if ( type == "QVariant" ) {
+< if ( s == "true" || s == "false" )
+< arg << QVariant( mkBool( s ), 42 );
+< else if ( s.left( 4 ) == "int(" )
+< arg << QVariant( s.mid(4, s.length()-5).toInt() );
+< else if ( s.left( 7 ) == "QPoint(" )
+< arg << QVariant( mkPoint( s.mid(7, s.length()-8) ) );
+< else if ( s.left( 6 ) == "QSize(" )
+< arg << QVariant( mkSize( s.mid(6, s.length()-7) ) );
+< else if ( s.left( 6 ) == "QRect(" )
+< arg << QVariant( mkRect( s.mid(6, s.length()-7) ) );
+< else if ( s.left( 7 ) == "QColor(" )
+< arg << QVariant( mkColor( s.mid(7, s.length()-8) ) );
+< else
+< arg << QVariant( s );
+< } else if ( type.startsWith("QValueList<")) {
+< type = type.mid(11, type.length() - 12);
+< QStringList list;
+< QString delim = s;
+< if (delim == "[")
+< delim = "]";
+< if (delim == "(")
+< delim = ")";
+< i++;
+< QByteArray dummy_data;
+< QDataStream dummy_arg(dummy_data, IO_WriteOnly);
+---
+> if (type == "QStringList")
+> type = "QValueList<QString>";
+> if (type == "QCStringList")
+> type = "QValueList<QCString>";
+> if( i > args.count() )
+> {
+> qWarning("Not enough arguments.");
+> exit(1);
+> }
+> QString s = QString::fromLocal8Bit( args[ i ] );
+319,346c258,314
+< int j = i;
+< int count = 0;
+< // Parse list to get the count
+< while (true) {
+< if (j >= argc)
+< {
+< qWarning("List end-delimiter '%s' not found.", delim.latin1());
+< exit(1);
+< }
+< if (argv[j] == delim) break;
+< marshall(dummy_arg, argc, argv, j, type);
+< count++;
+< }
+< arg << (Q_UINT32) count;
+< // Parse the list for real
+< while (true) {
+< if (i >= argc)
+< {
+< qWarning("List end-delimiter '%s' not found.", delim.latin1());
+< exit(1);
+< }
+< if (argv[i] == delim) break;
+< marshall(arg, argc, argv, i, type);
+< }
+< } else {
+< qWarning( "cannot handle datatype '%s'", type.latin1() );
+< exit(1);
+< }
+---
+> if ( type == "int" )
+> arg << s.toInt();
+> else if ( type == "uint" )
+> arg << s.toUInt();
+> else if ( type == "unsigned" )
+> arg << s.toUInt();
+> else if ( type == "unsigned int" )
+> arg << s.toUInt();
+> else if ( type == "long" )
+> arg << s.toLong();
+> else if ( type == "long int" )
+> arg << s.toLong();
+> else if ( type == "unsigned long" )
+> arg << s.toULong();
+> else if ( type == "unsigned long int" )
+> arg << s.toULong();
+> else if ( type == "float" )
+> arg << s.toFloat();
+> else if ( type == "double" )
+> arg << s.toDouble();
+> else if ( type == "bool" )
+> arg << mkBool( s );
+> else if ( type == "QString" )
+> arg << s;
+> else if ( type == "QCString" )
+> arg << QCString( args[ i ] );
+> else if ( type == "QColor" )
+> arg << mkColor( s );
+> else if ( type == "QPoint" )
+> arg << mkPoint( s );
+> else if ( type == "QSize" )
+> arg << mkSize( s );
+> else if ( type == "QRect" )
+> arg << mkRect( s );
+> else if ( type == "QVariant" ) {
+> if ( s == "true" || s == "false" )
+> arg << QVariant( mkBool( s ), 42 );
+> else if ( s.left( 4 ) == "int(" )
+> arg << QVariant( s.mid(4, s.length()-5).toInt() );
+> else if ( s.left( 7 ) == "QPoint(" )
+> arg << QVariant( mkPoint( s.mid(7, s.length()-8) ) );
+> else if ( s.left( 6 ) == "QSize(" )
+> arg << QVariant( mkSize( s.mid(6, s.length()-7) ) );
+> else if ( s.left( 6 ) == "QRect(" )
+> arg << QVariant( mkRect( s.mid(6, s.length()-7) ) );
+> else if ( s.left( 7 ) == "QColor(" )
+> arg << QVariant( mkColor( s.mid(7, s.length()-8) ) );
+> else
+> arg << QVariant( s );
+> } else if ( type.startsWith("QValueList<")) {
+> type = type.mid(11, type.length() - 12);
+> QStringList list;
+> QString delim = s;
+> if (delim == "[")
+> delim = "]";
+> if (delim == "(")
+> delim = ")";
+347a316,349
+> QByteArray dummy_data;
+> QDataStream dummy_arg(dummy_data, IO_WriteOnly);
+>
+> uint j = i;
+> uint count = 0;
+> // Parse list to get the count
+> while (true) {
+> if( j > args.count() )
+> {
+> qWarning("List end-delimiter '%s' not found.", delim.latin1());
+> exit(1);
+> }
+> if( QString::fromLocal8Bit( args[ j ] ) == delim )
+> break;
+> marshall( dummy_arg, args, j, type );
+> count++;
+> }
+> arg << (Q_UINT32) count;
+> // Parse the list for real
+> while (true) {
+> if( i > args.count() )
+> {
+> qWarning("List end-delimiter '%s' not found.", delim.latin1());
+> exit(1);
+> }
+> if( QString::fromLocal8Bit( args[ i ] ) == delim )
+> break;
+> marshall( arg, args, i, type );
+> }
+> } else {
+> qWarning( "cannot handle datatype '%s'", type.latin1() );
+> exit(1);
+> }
+> i++;
diff --git a/kompare/tests/cvsdiff/rcs.diff b/kompare/tests/cvsdiff/rcs.diff
new file mode 100644
index 00000000..da42d91a
--- /dev/null
+++ b/kompare/tests/cvsdiff/rcs.diff
@@ -0,0 +1,24 @@
+Index: client/dcopfind.cpp
+===================================================================
+RCS file: /home/kde/kdelibs/dcop/client/dcopfind.cpp,v
+retrieving revision 1.2
+diff -n -r1.2 dcopfind.cpp
+d39 1
+a39 1
+bool findObject( const char* app, const char* obj, const char* func, QCStringList args )
+d121 1
+a121 1
+ if ( types.count() != args.count() ) {
+d131 1
+a131 1
+ marshall(arg, args, i, *it);
+d133 1
+a133 1
+ if ( (uint) i != args.count() ) {
+d224 1
+a224 5
+ QCStringList params;
+ for( int i = 0; i < argc; i++ )
+ params.append( args[ i ] );
+
+ findObject( app, objid, function, params );
diff --git a/kompare/tests/cvsdiff/rcsm.diff b/kompare/tests/cvsdiff/rcsm.diff
new file mode 100644
index 00000000..c690b2a7
--- /dev/null
+++ b/kompare/tests/cvsdiff/rcsm.diff
@@ -0,0 +1,683 @@
+Index: client/dcop.cpp
+===================================================================
+RCS file: /home/kde/kdelibs/dcop/client/dcop.cpp,v
+retrieving revision 1.26
+diff -n -r1.26 dcop.cpp
+d23 1
+a23 4
+#include <ctype.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+d25 1
+a25 12
+#include <qdir.h>
+#include <qfile.h>
+#include <qfileinfo.h>
+#include <qmap.h>
+#include <qstringlist.h>
+#include <qtextstream.h>
+#include <qvariant.h>
+
+// putenv() is not available on all platforms, so make sure the emulation
+// wrapper is available in those cases by loading config.h!
+#include <config.h>
+
+d28 3
+a30 1
+#include "../kdatastream.h"
+a33 2
+typedef QMap<QString, QString> UserList;
+
+a35 14
+static QTextStream cout( stdout, IO_WriteOnly );
+static QTextStream cerr( stderr, IO_WriteOnly );
+
+/**
+ * Session to send call to
+ * DefaultSession - current session. Current KDE session when called without
+ * --user or --all-users option. Otherwise this value ignores
+ * all users with more than one active session.
+ * AllSessions - Send to all sessions found. requires --user or --all-users.
+ * QuerySessions - Don't call DCOP, return a list of available sessions.
+ * CustomSession - Use the specified session
+ */
+enum Session { DefaultSession = 0, AllSessions, QuerySessions, CustomSession };
+
+d121 1
+a121 1
+void callFunction( const char* app, const char* obj, const char* func, const QCStringList args )
+d123 1
+d139 1
+a139 1
+ if ( !ok && args.isEmpty() )
+d156 2
+a157 2
+ uint a = (*it).contains(',');
+ if ( ( a == 0 && args.isEmpty() ) || ( a > 0 && a + 1 == args.count() ) )
+d164 1
+a164 2
+// exit(1);
+ return;
+d246 5
+a250 6
+ uint i = 0;
+ for( QStringList::Iterator it = types.begin(); it != types.end(); ++it )
+ marshall( arg, args, i, *it );
+
+ if ( i != args.count() )
+ {
+a268 27
+/**
+ * Show command-line help and exit
+ */
+void showHelp( int exitCode = 0 )
+{
+ cout << "Usage: dcop [options] [application [object [function [arg1] [arg2] ... ] ] ]" << endl
+ << "" << endl
+ << "Console DCOP client" << endl
+ << "" << endl
+ << "Generic options:" << endl
+ << " --help Show help about options" << endl
+ << "" << endl
+ << "Options:" << endl
+ << " --pipe Call DCOP for each line read from stdin" << endl
+ << " --user <user> Connect to the given user's DCOP server. This option will" << endl
+ << " ignore the values of the environment vars $DCOPSERVER and" << endl
+ << " $ICEAUTHORITY, even if they are set." << endl
+ << " If the user has more than one open session, you must also" << endl
+ << " use one of the --list-sessions, --session or --als-sessions" << endl
+ << " command-line options." << endl
+ << " --all-users Send the same DCOP call to all users with a running DCOP" << endl
+ << " server. Only failed calls to existing DCOP servers will"
+ << " generate an error message. If no DCOP server is available" << endl
+ << " at all, no error will be generated." << endl;
+
+ exit( exitCode );
+}
+d270 2
+a271 5
+/**
+ * Return a list of all users and their home directories.
+ * Returns an empty list if /etc/passwd cannot be read for some reason.
+ */
+static UserList userList()
+a272 9
+ UserList result;
+
+ QFile f( "/etc/passwd" );
+
+ if( !f.open( IO_ReadOnly ) )
+ {
+ cerr << "Can't open /etc/passwd for reading!" << endl;
+ return result;
+ }
+d274 3
+a276 6
+ QStringList l( QStringList::split( '\n', f.readAll() ) );
+
+ for( QStringList::ConstIterator it( l.begin() ); it != l.end(); ++it )
+ {
+ QStringList userInfo( QStringList::split( ':', *it, true ) );
+ result[ userInfo[ 0 ] ] = userInfo[ 5 ];
+d279 3
+a281 42
+ return result;
+}
+
+/**
+ * Return a list of available DCOP sessions for the specified user
+ * An empty list means no sessions are available, or an error occurred.
+ */
+QStringList dcopSessionList( const QString &user, const QString &home )
+{
+ if( home.isEmpty() )
+ {
+ cerr << "WARNING: Cannot determine home directory for user "
+ << user << "!" << endl
+ << "Please check permissions or set the $DCOPSERVER variable manually before" << endl
+ << "calling dcop." << endl;
+ return QStringList();
+ }
+
+ QStringList result;
+ QFileInfo dirInfo( home );
+ if( !dirInfo.exists() || !dirInfo.isReadable() )
+ return result;
+
+ QDir d( home );
+ d.setFilter( QDir::Files | QDir::Hidden | QDir::NoSymLinks );
+ d.setNameFilter( ".DCOPserver*" );
+
+ const QFileInfoList *list = d.entryInfoList();
+ if( !list )
+ return result;
+
+ QFileInfoListIterator it( *list );
+ QFileInfo *fi;
+
+ while ( ( fi = it.current() ) != 0 )
+ {
+ if( fi->isReadable() )
+ result.append( fi->fileName() );
+ ++it;
+ }
+ return result;
+}
+a282 6
+/**
+ * Do the actual DCOP call
+ */
+void runDCOP( QCStringList args, UserList users, Session session,
+ const QString sessionName, bool readStdin )
+{
+d286 2
+a287 3
+ QCStringList params;
+ DCOPClient *client = 0L;
+ if ( !args.isEmpty() && args[ 0 ].find( "DCOPRef(" ) == 0 )
+d289 16
+a304 24
+ // WARNING: This part (until the closing '}') could very
+ // well be broken now. As I don't know how to trigger and test
+ // dcoprefs this code is *not* tested. It compiles and it looks
+ // ok to me, but that's all I can say - Martijn (2001/12/24)
+ int delimPos = args[ 0 ].findRev( ',' );
+ if( delimPos == -1 )
+ {
+ cerr << "Error: '" << args[ 0 ]
+ << "' is not a valid DCOP reference." << endl;
+ exit( -1 );
+ }
+ args[ 0 ][ delimPos ] = 0;
+ app = args[ 0 ].mid( 8 );
+ delimPos++;
+ args[ 0 ][ args[ 0 ].length() - 1 ] = 0;
+ objid = args[ 0 ].mid( delimPos );
+ if( args.count() > 1 )
+ function = args[ 1 ];
+ if( args.count() > 2 )
+ {
+ params = args;
+ params.remove( params.begin() );
+ params.remove( params.begin() );
+ }
+d308 31
+a338 84
+ if( !args.isEmpty() )
+ app = args[ 0 ];
+ if( args.count() > 1 )
+ objid = args[ 1 ];
+ if( args.count() > 2 )
+ function = args[ 2 ];
+ if( args.count() > 3)
+ {
+ params = args;
+ params.remove( params.begin() );
+ params.remove( params.begin() );
+ params.remove( params.begin() );
+ }
+ }
+
+ bool firstRun = true;
+ UserList::Iterator it;
+ QStringList sessions;
+ bool presetDCOPServer = false;
+// char *dcopStr = 0L;
+ QString dcopServer;
+
+ for( it = users.begin(); it != users.end() || firstRun; it++ )
+ {
+ firstRun = false;
+
+ //cout << "Iterating '" << it.key() << "'" << endl;
+
+ if( session == QuerySessions )
+ {
+ QStringList sessions = dcopSessionList( it.key(), it.data() );
+ if( sessions.isEmpty() )
+ {
+ cout << "No active sessions";
+ if( !( *it ).isEmpty() )
+ cout << " for user " << *it;
+ cout << endl;
+ }
+ else
+ {
+ cout << "Active sessions ";
+ if( !( *it ).isEmpty() )
+ cout << "for user " << *it << " ";
+ cout << ":" << endl;
+
+ QStringList::Iterator sIt;
+ for( sIt = sessions.begin(); sIt != sessions.end(); sIt++ )
+ cout << " " << *sIt << endl;
+
+ cout << endl;
+ }
+ continue;
+ }
+
+ if( getenv( "DCOPSERVER" ) )
+ {
+ sessions.append( getenv( "DCOPSERVER" ) );
+ presetDCOPServer = true;
+ }
+
+ if( users.count() > 1 || ( users.count() == 1 &&
+ ( getenv( "DCOPSERVER" ) == 0 /*&& getenv( "DISPLAY" ) == 0*/ ) ) )
+ {
+ sessions = dcopSessionList( it.key(), it.data() );
+ if( sessions.isEmpty() )
+ {
+ if( users.count() > 1 )
+ continue;
+ else
+ {
+ cerr << "ERROR: No active KDE sessions!" << endl
+ << "If you are sure there is one, please set the $DCOPSERVER variable manually" << endl
+ << "before calling dcop." << endl;
+ exit( -1 );
+ }
+ }
+ else if( sessions.count() > 1 && session != AllSessions )
+ {
+ cerr << "ERROR: Multiple available KDE sessions!" << endl
+ << "Please specify the correct session to use with --session or use the" << endl
+ << "--all-sessions option to broadcast to all sessions." << endl;
+ exit( -1 );
+ }
+ }
+a339 143
+ if( users.count() > 1 || ( users.count() == 1 &&
+ ( getenv( "ICEAUTHORITY" ) == 0 || getenv( "DISPLAY" ) == 0 ) ) )
+ {
+ // Check for ICE authority file and if the file can be read by us
+ QString home = it.data();
+ QString iceFile = it.data() + "/.ICEauthority";
+ QFileInfo fi( iceFile );
+ if( iceFile.isEmpty() )
+ {
+ cerr << "WARNING: Cannot determine home directory for user "
+ << it.key() << "!" << endl
+ << "Please check permissions or set the $ICEAUTHORITY variable manually before" << endl
+ << "calling dcop." << endl;
+ }
+ else if( fi.exists() )
+ {
+ if( fi.isReadable() )
+ {
+ char *envStr = strdup( ( "ICEAUTHORITY=" + iceFile ).ascii() );
+ putenv( envStr );
+ //cerr << "ice: " << envStr << endl;
+ }
+ else
+ {
+ cerr << "WARNING: ICE authority file " << iceFile
+ << "is not readable by you!" << endl
+ << "Please check permissions or set the $ICEAUTHORITY variable manually before" << endl
+ << "calling dcop." << endl;
+ }
+ }
+ else
+ {
+ if( users.count() > 1 )
+ continue;
+ else
+ {
+ cerr << "WARNING: Cannot find ICE authority file "
+ << iceFile << "!" << endl
+ << "Please check permissions or set the $ICEAUTHORITY"
+ << " variable manually before" << endl
+ << "calling dcop." << endl;
+ }
+ }
+ }
+
+ // Main loop
+ // If users is an empty list we're calling for the currently logged
+ // in user. In this case we don't have a session, but still want
+ // to iterate the loop once.
+ QStringList::Iterator sIt = sessions.begin();
+ for( ; sIt != sessions.end() || users.isEmpty(); sIt++ )
+ {
+ if( !presetDCOPServer && !users.isEmpty() )
+ {
+ QString dcopFile = it.data() + "/" + *sIt;
+ QFile f( dcopFile );
+ if( !f.open( IO_ReadOnly ) )
+ {
+ cerr << "Can't open " << dcopFile << " for reading!" << endl;
+ exit( -1 );
+ }
+
+ QStringList l( QStringList::split( '\n', f.readAll() ) );
+ dcopServer = l.first();
+
+ if( dcopServer.isEmpty() )
+ {
+ cerr << "WARNING: Unable to determine DCOP server for session "
+ << *sIt << "!" << endl
+ << "Please check permissions or set the $DCOPSERVER variable manually before" << endl
+ << "calling dcop." << endl;
+ exit( -1 );
+ }
+ }
+
+ delete client;
+ client = new DCOPClient;
+ if( !dcopServer.isEmpty() )
+ client->setServerAddress( dcopServer.ascii() );
+ bool success = client->attach();
+ if( !success )
+ {
+ cerr << "ERROR: Couldn't attach to DCOP server!" << endl;
+ continue;
+ }
+ dcop = client;
+
+ switch ( args.count() )
+ {
+ case 0:
+ queryApplications("");
+ break;
+ case 1:
+ if (endsWith(app, '*'))
+ queryApplications(app);
+ else
+ queryObjects( app, "" );
+ break;
+ case 2:
+ if (endsWith(objid, '*'))
+ queryObjects(app, objid);
+ else
+ queryFunctions( app, objid );
+ break;
+ case 3:
+ default:
+ if( readStdin )
+ {
+ QCStringList::Iterator replaceArg = args.end();
+
+ QCStringList::Iterator it;
+ for( it = args.begin(); it != args.end(); it++ )
+ if( *it == "%1" )
+ replaceArg = it;
+
+ // Read from stdin until EOF and call function for each line read
+ char *buf = new char[ 1000 ];
+ while ( !feof( stdin ) )
+ {
+ fgets( buf, 1000, stdin );
+
+ if( replaceArg != args.end() )
+ *replaceArg = buf;
+
+ callFunction( app, objid, function, params );
+ }
+ }
+ else
+ {
+ // Just call function
+// cout << "call " << app << ", " << objid << ", " << function << ", (params)" << endl;
+ callFunction( app, objid, function, params );
+ }
+ break;
+ }
+ // Another sIt++ would make the loop infinite...
+ if( users.isEmpty() )
+ break;
+ }
+
+ // Another it++ would make the loop infinite...
+ if( it == users.end() )
+ break;
+a340 106
+}
+
+
+int main( int argc, char** argv )
+{
+ bool readStdin = false;
+ int numOptions = 0;
+ QString user;
+ Session session = DefaultSession;
+ QString sessionName;
+
+ // Scan for command-line options first
+ for( int pos = 1 ; pos <= argc - 1 ; pos++ )
+ {
+ if( strcmp( argv[ pos ], "--help" ) == 0 )
+ showHelp( 0 );
+ else if( strcmp( argv[ pos ], "--pipe" ) == 0 )
+ {
+ readStdin = true;
+ numOptions++;
+ }
+ else if( strcmp( argv[ pos ], "--user" ) == 0 )
+ {
+ if( pos <= argc - 2 )
+ {
+ user = QString::fromLocal8Bit( argv[ pos + 1] );
+ numOptions +=2;
+ pos++;
+ }
+ else
+ {
+ cerr << "Missing username for '--user' option!" << endl << endl;
+ showHelp( -1 );
+ }
+ }
+ else if( strcmp( argv[ pos ], "--all-users" ) == 0 )
+ {
+ user = "*";
+ numOptions ++;
+ }
+ else if( strcmp( argv[ pos ], "--list-sessions" ) == 0 )
+ {
+ session = QuerySessions;
+ numOptions ++;
+ }
+ else if( strcmp( argv[ pos ], "--all-sessions" ) == 0 )
+ {
+ session = AllSessions;
+ numOptions ++;
+ }
+ else if( argv[ pos ][ 0 ] == '-' )
+ {
+ cerr << "Unknown command-line option '" << argv[ pos ]
+ << "'." << endl << endl;
+ showHelp( -1 );
+ }
+ else
+ break; // End of options
+ }
+
+ argc -= numOptions;
+
+ QCStringList args;
+ for( int i = numOptions; i < argc + numOptions - 1; i++ )
+ args.append( argv[ i + 1 ] );
+
+ if( readStdin && args.count() < 3 )
+ {
+ cerr << "--pipe option only supported for function calls!" << endl << endl;
+ showHelp( -1 );
+ }
+
+ if( user == "*" && args.count() < 3 && session != QuerySessions )
+ {
+ cerr << "ERROR: The --all-users option is only supported for function calls!" << endl << endl;
+ showHelp( -1 );
+ }
+
+ if( session == QuerySessions && !args.isEmpty() )
+ {
+ cerr << "ERROR: The --list-sessions option cannot be used for actual DCOP calls!" << endl << endl;
+ showHelp( -1 );
+ }
+
+ if( session == QuerySessions && user.isEmpty() )
+ {
+ cerr << "ERROR: The --list-sessions option can only be used with the --user or" << endl
+ << "--all-users options!" << endl << endl;
+ showHelp( -1 );
+ }
+
+ if( session != DefaultSession && session != QuerySessions &&
+ args.count() < 3 )
+ {
+ cerr << "ERROR: The --session and --all-sessions options are only supported for function" << endl
+ << "calls!" << endl << endl;
+ showHelp( -1 );
+ }
+
+ UserList users;
+ if( user == "*" )
+ users = userList();
+ else if( !user.isEmpty() )
+ users[ user ] = userList()[ user ];
+
+ runDCOP( args, users, session, sessionName, readStdin );
+a343 3
+
+// vim: set ts=8 sts=4 sw=4 noet:
+
+Index: client/dcopfind.cpp
+===================================================================
+RCS file: /home/kde/kdelibs/dcop/client/dcopfind.cpp,v
+retrieving revision 1.2
+diff -n -r1.2 dcopfind.cpp
+d39 1
+a39 1
+bool findObject( const char* app, const char* obj, const char* func, QCStringList args )
+d121 1
+a121 1
+ if ( types.count() != args.count() ) {
+d131 1
+a131 1
+ marshall(arg, args, i, *it);
+d133 1
+a133 1
+ if ( (uint) i != args.count() ) {
+d224 1
+a224 5
+ QCStringList params;
+ for( int i = 0; i < argc; i++ )
+ params.append( args[ i ] );
+
+ findObject( app, objid, function, params );
+Index: client/marshall.cpp
+===================================================================
+RCS file: /home/kde/kdelibs/dcop/client/marshall.cpp,v
+retrieving revision 1.3
+diff -n -r1.3 marshall.cpp
+d245 1
+a245 1
+void marshall( QDataStream &arg, QCStringList args, uint &i, QString type )
+d247 71
+a317 10
+ if (type == "QStringList")
+ type = "QValueList<QString>";
+ if (type == "QCStringList")
+ type = "QValueList<QCString>";
+ if( i > args.count() )
+ {
+ qWarning("Not enough arguments.");
+ exit(1);
+ }
+ QString s = QString::fromLocal8Bit( args[ i ] );
+d319 28
+a346 57
+ if ( type == "int" )
+ arg << s.toInt();
+ else if ( type == "uint" )
+ arg << s.toUInt();
+ else if ( type == "unsigned" )
+ arg << s.toUInt();
+ else if ( type == "unsigned int" )
+ arg << s.toUInt();
+ else if ( type == "long" )
+ arg << s.toLong();
+ else if ( type == "long int" )
+ arg << s.toLong();
+ else if ( type == "unsigned long" )
+ arg << s.toULong();
+ else if ( type == "unsigned long int" )
+ arg << s.toULong();
+ else if ( type == "float" )
+ arg << s.toFloat();
+ else if ( type == "double" )
+ arg << s.toDouble();
+ else if ( type == "bool" )
+ arg << mkBool( s );
+ else if ( type == "QString" )
+ arg << s;
+ else if ( type == "QCString" )
+ arg << QCString( args[ i ] );
+ else if ( type == "QColor" )
+ arg << mkColor( s );
+ else if ( type == "QPoint" )
+ arg << mkPoint( s );
+ else if ( type == "QSize" )
+ arg << mkSize( s );
+ else if ( type == "QRect" )
+ arg << mkRect( s );
+ else if ( type == "QVariant" ) {
+ if ( s == "true" || s == "false" )
+ arg << QVariant( mkBool( s ), 42 );
+ else if ( s.left( 4 ) == "int(" )
+ arg << QVariant( s.mid(4, s.length()-5).toInt() );
+ else if ( s.left( 7 ) == "QPoint(" )
+ arg << QVariant( mkPoint( s.mid(7, s.length()-8) ) );
+ else if ( s.left( 6 ) == "QSize(" )
+ arg << QVariant( mkSize( s.mid(6, s.length()-7) ) );
+ else if ( s.left( 6 ) == "QRect(" )
+ arg << QVariant( mkRect( s.mid(6, s.length()-7) ) );
+ else if ( s.left( 7 ) == "QColor(" )
+ arg << QVariant( mkColor( s.mid(7, s.length()-8) ) );
+ else
+ arg << QVariant( s );
+ } else if ( type.startsWith("QValueList<")) {
+ type = type.mid(11, type.length() - 12);
+ QStringList list;
+ QString delim = s;
+ if (delim == "[")
+ delim = "]";
+ if (delim == "(")
+ delim = ")";
+a347 34
+ QByteArray dummy_data;
+ QDataStream dummy_arg(dummy_data, IO_WriteOnly);
+
+ uint j = i;
+ uint count = 0;
+ // Parse list to get the count
+ while (true) {
+ if( j > args.count() )
+ {
+ qWarning("List end-delimiter '%s' not found.", delim.latin1());
+ exit(1);
+ }
+ if( QString::fromLocal8Bit( args[ j ] ) == delim )
+ break;
+ marshall( dummy_arg, args, j, type );
+ count++;
+ }
+ arg << (Q_UINT32) count;
+ // Parse the list for real
+ while (true) {
+ if( i > args.count() )
+ {
+ qWarning("List end-delimiter '%s' not found.", delim.latin1());
+ exit(1);
+ }
+ if( QString::fromLocal8Bit( args[ i ] ) == delim )
+ break;
+ marshall( arg, args, i, type );
+ }
+ } else {
+ qWarning( "cannot handle datatype '%s'", type.latin1() );
+ exit(1);
+ }
+ i++;
diff --git a/kompare/tests/cvsdiff/unified.diff b/kompare/tests/cvsdiff/unified.diff
new file mode 100644
index 00000000..562dee43
--- /dev/null
+++ b/kompare/tests/cvsdiff/unified.diff
@@ -0,0 +1,50 @@
+Index: client/dcopfind.cpp
+===================================================================
+RCS file: /home/kde/kdelibs/dcop/client/dcopfind.cpp,v
+retrieving revision 1.2
+diff -u -r1.2 dcopfind.cpp
+--- client/dcopfind.cpp 2001/10/31 01:17:39 1.2
++++ client/dcopfind.cpp 2002/01/16 18:07:51
+@@ -36,7 +36,7 @@
+ static bool bAppIdOnly = 0;
+ static bool bLaunchApp = 0;
+
+-bool findObject( const char* app, const char* obj, const char* func, int argc, char** args )
++bool findObject( const char* app, const char* obj, const char* func, QCStringList args )
+ {
+ QString f = func; // Qt is better with unicode strings, so use one.
+ int left = f.find( '(' );
+@@ -118,7 +118,7 @@
+ f = fc;
+ }
+
+- if ( (int) types.count() != argc ) {
++ if ( types.count() != args.count() ) {
+ qWarning( "arguments do not match" );
+ exit(1);
+ }
+@@ -128,9 +128,9 @@
+
+ int i = 0;
+ for ( QStringList::Iterator it = types.begin(); it != types.end(); ++it ) {
+- marshall(arg, argc, args, i, *it);
++ marshall(arg, args, i, *it);
+ }
+- if ( (int) i != argc ) {
++ if ( (uint) i != args.count() ) {
+ qWarning( "arguments do not match" );
+ exit(1);
+ }
+@@ -221,7 +221,11 @@
+ argc = 0;
+ }
+
+- findObject( app, objid, function, argc, args );
++ QCStringList params;
++ for( int i = 0; i < argc; i++ )
++ params.append( args[ i ] );
++
++ findObject( app, objid, function, params );
+
+ return 0;
+ }
diff --git a/kompare/tests/cvsdiff/unifiedm.diff b/kompare/tests/cvsdiff/unifiedm.diff
new file mode 100644
index 00000000..1de79f8f
--- /dev/null
+++ b/kompare/tests/cvsdiff/unifiedm.diff
@@ -0,0 +1,924 @@
+Index: client/dcop.cpp
+===================================================================
+RCS file: /home/kde/kdelibs/dcop/client/dcop.cpp,v
+retrieving revision 1.26
+diff -u -r1.26 dcop.cpp
+--- client/dcop.cpp 2001/10/31 01:17:39 1.26
++++ client/dcop.cpp 2002/01/16 18:06:14
+@@ -20,19 +20,47 @@
+
+ ******************************************************************/
+
+-#include <qvariant.h>
++#include <ctype.h>
++#include <stdio.h>
++#include <stdlib.h>
++
+ #include <qcolor.h>
+-#include "../kdatastream.h"
++#include <qdir.h>
++#include <qfile.h>
++#include <qfileinfo.h>
++#include <qmap.h>
++#include <qstringlist.h>
++#include <qtextstream.h>
++#include <qvariant.h>
++
++// putenv() is not available on all platforms, so make sure the emulation
++// wrapper is available in those cases by loading config.h!
++#include <config.h>
++
+ #include "../dcopclient.h"
+ #include "../dcopref.h"
+-#include <stdlib.h>
+-#include <stdio.h>
+-#include <ctype.h>
++#include "../kdatastream.h"
+
+ #include "marshall.cpp"
+
++typedef QMap<QString, QString> UserList;
++
+ static DCOPClient* dcop = 0;
+
++static QTextStream cout( stdout, IO_WriteOnly );
++static QTextStream cerr( stderr, IO_WriteOnly );
++
++/**
++ * Session to send call to
++ * DefaultSession - current session. Current KDE session when called without
++ * --user or --all-users option. Otherwise this value ignores
++ * all users with more than one active session.
++ * AllSessions - Send to all sessions found. requires --user or --all-users.
++ * QuerySessions - Don't call DCOP, return a list of available sessions.
++ * CustomSession - Use the specified session
++ */
++enum Session { DefaultSession = 0, AllSessions, QuerySessions, CustomSession };
++
+ bool startsWith(const QCString &id, const char *str, int n)
+ {
+ return !n || (strncmp(id.data(), str, n) == 0);
+@@ -118,9 +146,8 @@
+ }
+ }
+
+-void callFunction( const char* app, const char* obj, const char* func, int argc, char** args )
++void callFunction( const char* app, const char* obj, const char* func, const QCStringList args )
+ {
+-
+ QString f = func; // Qt is better with unicode strings, so use one.
+ int left = f.find( '(' );
+ int right = f.find( ')' );
+@@ -136,7 +163,7 @@
+ bool ok = false;
+ QCStringList funcs = dcop->remoteFunctions( app, obj, &ok );
+ QCString realfunc;
+- if ( !ok && argc == 0 )
++ if ( !ok && args.isEmpty() )
+ goto doit;
+ if ( !ok )
+ {
+@@ -153,15 +180,16 @@
+
+ if ( l > 0 && (*it).mid( s, l - s ) == func ) {
+ realfunc = (*it).mid( s );
+- int a = (*it).contains(',');
+- if ( ( a == 0 && argc == 0) || ( a > 0 && a + 1 == argc ) )
++ uint a = (*it).contains(',');
++ if ( ( a == 0 && args.isEmpty() ) || ( a > 0 && a + 1 == args.count() ) )
+ break;
+ }
+ }
+ if ( realfunc.isEmpty() )
+ {
+ qWarning("no such function");
+- exit(1);
++// exit(1);
++ return;
+ }
+ f = realfunc;
+ left = f.find( '(' );
+@@ -243,11 +271,12 @@
+ QCString replyType;
+ QDataStream arg(data, IO_WriteOnly);
+
+- int i = 0;
+- for ( QStringList::Iterator it = types.begin(); it != types.end(); ++it ) {
+- marshall(arg, argc, args, i, *it);
+- }
+- if ( i != argc ) {
++ uint i = 0;
++ for( QStringList::Iterator it = types.begin(); it != types.end(); ++it )
++ marshall( arg, args, i, *it );
++
++ if ( i != args.count() )
++ {
+ qWarning( "arguments do not match" );
+ exit(1);
+ }
+@@ -265,79 +294,480 @@
+ }
+ }
+ }
+-
+
++/**
++ * Show command-line help and exit
++ */
++void showHelp( int exitCode = 0 )
++{
++ cout << "Usage: dcop [options] [application [object [function [arg1] [arg2] ... ] ] ]" << endl
++ << "" << endl
++ << "Console DCOP client" << endl
++ << "" << endl
++ << "Generic options:" << endl
++ << " --help Show help about options" << endl
++ << "" << endl
++ << "Options:" << endl
++ << " --pipe Call DCOP for each line read from stdin" << endl
++ << " --user <user> Connect to the given user's DCOP server. This option will" << endl
++ << " ignore the values of the environment vars $DCOPSERVER and" << endl
++ << " $ICEAUTHORITY, even if they are set." << endl
++ << " If the user has more than one open session, you must also" << endl
++ << " use one of the --list-sessions, --session or --als-sessions" << endl
++ << " command-line options." << endl
++ << " --all-users Send the same DCOP call to all users with a running DCOP" << endl
++ << " server. Only failed calls to existing DCOP servers will"
++ << " generate an error message. If no DCOP server is available" << endl
++ << " at all, no error will be generated." << endl;
++
++ exit( exitCode );
++}
+
+-int main( int argc, char** argv )
++/**
++ * Return a list of all users and their home directories.
++ * Returns an empty list if /etc/passwd cannot be read for some reason.
++ */
++static UserList userList()
+ {
++ UserList result;
++
++ QFile f( "/etc/passwd" );
++
++ if( !f.open( IO_ReadOnly ) )
++ {
++ cerr << "Can't open /etc/passwd for reading!" << endl;
++ return result;
++ }
+
+- if ( argc > 1 && argv[1][0] == '-' ) {
+- fprintf( stderr, "Usage: dcop [ application [object [function [arg1] [arg2] [arg3] ... ] ] ] \n" );
+- exit(0);
++ QStringList l( QStringList::split( '\n', f.readAll() ) );
++
++ for( QStringList::ConstIterator it( l.begin() ); it != l.end(); ++it )
++ {
++ QStringList userInfo( QStringList::split( ':', *it, true ) );
++ result[ userInfo[ 0 ] ] = userInfo[ 5 ];
+ }
+
+- DCOPClient client;
+- client.attach();
+- dcop = &client;
++ return result;
++}
++
++/**
++ * Return a list of available DCOP sessions for the specified user
++ * An empty list means no sessions are available, or an error occurred.
++ */
++QStringList dcopSessionList( const QString &user, const QString &home )
++{
++ if( home.isEmpty() )
++ {
++ cerr << "WARNING: Cannot determine home directory for user "
++ << user << "!" << endl
++ << "Please check permissions or set the $DCOPSERVER variable manually before" << endl
++ << "calling dcop." << endl;
++ return QStringList();
++ }
++
++ QStringList result;
++ QFileInfo dirInfo( home );
++ if( !dirInfo.exists() || !dirInfo.isReadable() )
++ return result;
++
++ QDir d( home );
++ d.setFilter( QDir::Files | QDir::Hidden | QDir::NoSymLinks );
++ d.setNameFilter( ".DCOPserver*" );
++
++ const QFileInfoList *list = d.entryInfoList();
++ if( !list )
++ return result;
++
++ QFileInfoListIterator it( *list );
++ QFileInfo *fi;
++
++ while ( ( fi = it.current() ) != 0 )
++ {
++ if( fi->isReadable() )
++ result.append( fi->fileName() );
++ ++it;
++ }
++ return result;
++}
+
++/**
++ * Do the actual DCOP call
++ */
++void runDCOP( QCStringList args, UserList users, Session session,
++ const QString sessionName, bool readStdin )
++{
+ QCString app;
+ QCString objid;
+ QCString function;
+- char **args = 0;
+- if ((argc > 1) && (strncmp(argv[1], "DCOPRef(", 8)) == 0)
++ QCStringList params;
++ DCOPClient *client = 0L;
++ if ( !args.isEmpty() && args[ 0 ].find( "DCOPRef(" ) == 0 )
+ {
+- char *delim = strchr(argv[1], ',');
+- if (!delim)
+- {
+- fprintf(stderr, "Error: '%s' is not a valid DCOP reference.\n", argv[1]);
+- return 1;
+- }
+- *delim = 0;
+- app = argv[1] + 8;
+- delim++;
+- delim[strlen(delim)-1] = 0;
+- objid = delim;
+- if (argc > 2)
+- function = argv[2];
+- if (argc > 3)
+- args = &argv[3];
+- argc++;
++ // WARNING: This part (until the closing '}') could very
++ // well be broken now. As I don't know how to trigger and test
++ // dcoprefs this code is *not* tested. It compiles and it looks
++ // ok to me, but that's all I can say - Martijn (2001/12/24)
++ int delimPos = args[ 0 ].findRev( ',' );
++ if( delimPos == -1 )
++ {
++ cerr << "Error: '" << args[ 0 ]
++ << "' is not a valid DCOP reference." << endl;
++ exit( -1 );
++ }
++ args[ 0 ][ delimPos ] = 0;
++ app = args[ 0 ].mid( 8 );
++ delimPos++;
++ args[ 0 ][ args[ 0 ].length() - 1 ] = 0;
++ objid = args[ 0 ].mid( delimPos );
++ if( args.count() > 1 )
++ function = args[ 1 ];
++ if( args.count() > 2 )
++ {
++ params = args;
++ params.remove( params.begin() );
++ params.remove( params.begin() );
++ }
+ }
+ else
+ {
+- if (argc > 1)
+- app = argv[1];
+- if (argc > 2)
+- objid = argv[2];
+- if (argc > 3)
+- function = argv[3];
+- if (argc > 4)
+- args = &argv[4];
+- }
+-
+- switch ( argc ) {
+- case 0:
+- case 1:
+- queryApplications("");
+- break;
+- case 2:
+- if (endsWith(app, '*'))
+- queryApplications(app);
+- else
+- queryObjects( app, "" );
+- break;
+- case 3:
+- if (endsWith(objid, '*'))
+- queryObjects(app, objid);
+- else
+- queryFunctions( app, objid );
+- break;
+- case 4:
+- default:
+- callFunction( app, objid, function, argc - 4, args );
+- break;
++ if( !args.isEmpty() )
++ app = args[ 0 ];
++ if( args.count() > 1 )
++ objid = args[ 1 ];
++ if( args.count() > 2 )
++ function = args[ 2 ];
++ if( args.count() > 3)
++ {
++ params = args;
++ params.remove( params.begin() );
++ params.remove( params.begin() );
++ params.remove( params.begin() );
++ }
++ }
++
++ bool firstRun = true;
++ UserList::Iterator it;
++ QStringList sessions;
++ bool presetDCOPServer = false;
++// char *dcopStr = 0L;
++ QString dcopServer;
++
++ for( it = users.begin(); it != users.end() || firstRun; it++ )
++ {
++ firstRun = false;
++
++ //cout << "Iterating '" << it.key() << "'" << endl;
++
++ if( session == QuerySessions )
++ {
++ QStringList sessions = dcopSessionList( it.key(), it.data() );
++ if( sessions.isEmpty() )
++ {
++ cout << "No active sessions";
++ if( !( *it ).isEmpty() )
++ cout << " for user " << *it;
++ cout << endl;
++ }
++ else
++ {
++ cout << "Active sessions ";
++ if( !( *it ).isEmpty() )
++ cout << "for user " << *it << " ";
++ cout << ":" << endl;
++
++ QStringList::Iterator sIt;
++ for( sIt = sessions.begin(); sIt != sessions.end(); sIt++ )
++ cout << " " << *sIt << endl;
++
++ cout << endl;
++ }
++ continue;
++ }
++
++ if( getenv( "DCOPSERVER" ) )
++ {
++ sessions.append( getenv( "DCOPSERVER" ) );
++ presetDCOPServer = true;
++ }
++
++ if( users.count() > 1 || ( users.count() == 1 &&
++ ( getenv( "DCOPSERVER" ) == 0 /*&& getenv( "DISPLAY" ) == 0*/ ) ) )
++ {
++ sessions = dcopSessionList( it.key(), it.data() );
++ if( sessions.isEmpty() )
++ {
++ if( users.count() > 1 )
++ continue;
++ else
++ {
++ cerr << "ERROR: No active KDE sessions!" << endl
++ << "If you are sure there is one, please set the $DCOPSERVER variable manually" << endl
++ << "before calling dcop." << endl;
++ exit( -1 );
++ }
++ }
++ else if( sessions.count() > 1 && session != AllSessions )
++ {
++ cerr << "ERROR: Multiple available KDE sessions!" << endl
++ << "Please specify the correct session to use with --session or use the" << endl
++ << "--all-sessions option to broadcast to all sessions." << endl;
++ exit( -1 );
++ }
++ }
+
++ if( users.count() > 1 || ( users.count() == 1 &&
++ ( getenv( "ICEAUTHORITY" ) == 0 || getenv( "DISPLAY" ) == 0 ) ) )
++ {
++ // Check for ICE authority file and if the file can be read by us
++ QString home = it.data();
++ QString iceFile = it.data() + "/.ICEauthority";
++ QFileInfo fi( iceFile );
++ if( iceFile.isEmpty() )
++ {
++ cerr << "WARNING: Cannot determine home directory for user "
++ << it.key() << "!" << endl
++ << "Please check permissions or set the $ICEAUTHORITY variable manually before" << endl
++ << "calling dcop." << endl;
++ }
++ else if( fi.exists() )
++ {
++ if( fi.isReadable() )
++ {
++ char *envStr = strdup( ( "ICEAUTHORITY=" + iceFile ).ascii() );
++ putenv( envStr );
++ //cerr << "ice: " << envStr << endl;
++ }
++ else
++ {
++ cerr << "WARNING: ICE authority file " << iceFile
++ << "is not readable by you!" << endl
++ << "Please check permissions or set the $ICEAUTHORITY variable manually before" << endl
++ << "calling dcop." << endl;
++ }
++ }
++ else
++ {
++ if( users.count() > 1 )
++ continue;
++ else
++ {
++ cerr << "WARNING: Cannot find ICE authority file "
++ << iceFile << "!" << endl
++ << "Please check permissions or set the $ICEAUTHORITY"
++ << " variable manually before" << endl
++ << "calling dcop." << endl;
++ }
++ }
++ }
++
++ // Main loop
++ // If users is an empty list we're calling for the currently logged
++ // in user. In this case we don't have a session, but still want
++ // to iterate the loop once.
++ QStringList::Iterator sIt = sessions.begin();
++ for( ; sIt != sessions.end() || users.isEmpty(); sIt++ )
++ {
++ if( !presetDCOPServer && !users.isEmpty() )
++ {
++ QString dcopFile = it.data() + "/" + *sIt;
++ QFile f( dcopFile );
++ if( !f.open( IO_ReadOnly ) )
++ {
++ cerr << "Can't open " << dcopFile << " for reading!" << endl;
++ exit( -1 );
++ }
++
++ QStringList l( QStringList::split( '\n', f.readAll() ) );
++ dcopServer = l.first();
++
++ if( dcopServer.isEmpty() )
++ {
++ cerr << "WARNING: Unable to determine DCOP server for session "
++ << *sIt << "!" << endl
++ << "Please check permissions or set the $DCOPSERVER variable manually before" << endl
++ << "calling dcop." << endl;
++ exit( -1 );
++ }
++ }
++
++ delete client;
++ client = new DCOPClient;
++ if( !dcopServer.isEmpty() )
++ client->setServerAddress( dcopServer.ascii() );
++ bool success = client->attach();
++ if( !success )
++ {
++ cerr << "ERROR: Couldn't attach to DCOP server!" << endl;
++ continue;
++ }
++ dcop = client;
++
++ switch ( args.count() )
++ {
++ case 0:
++ queryApplications("");
++ break;
++ case 1:
++ if (endsWith(app, '*'))
++ queryApplications(app);
++ else
++ queryObjects( app, "" );
++ break;
++ case 2:
++ if (endsWith(objid, '*'))
++ queryObjects(app, objid);
++ else
++ queryFunctions( app, objid );
++ break;
++ case 3:
++ default:
++ if( readStdin )
++ {
++ QCStringList::Iterator replaceArg = args.end();
++
++ QCStringList::Iterator it;
++ for( it = args.begin(); it != args.end(); it++ )
++ if( *it == "%1" )
++ replaceArg = it;
++
++ // Read from stdin until EOF and call function for each line read
++ char *buf = new char[ 1000 ];
++ while ( !feof( stdin ) )
++ {
++ fgets( buf, 1000, stdin );
++
++ if( replaceArg != args.end() )
++ *replaceArg = buf;
++
++ callFunction( app, objid, function, params );
++ }
++ }
++ else
++ {
++ // Just call function
++// cout << "call " << app << ", " << objid << ", " << function << ", (params)" << endl;
++ callFunction( app, objid, function, params );
++ }
++ break;
++ }
++ // Another sIt++ would make the loop infinite...
++ if( users.isEmpty() )
++ break;
++ }
++
++ // Another it++ would make the loop infinite...
++ if( it == users.end() )
++ break;
+ }
++}
++
+
++int main( int argc, char** argv )
++{
++ bool readStdin = false;
++ int numOptions = 0;
++ QString user;
++ Session session = DefaultSession;
++ QString sessionName;
++
++ // Scan for command-line options first
++ for( int pos = 1 ; pos <= argc - 1 ; pos++ )
++ {
++ if( strcmp( argv[ pos ], "--help" ) == 0 )
++ showHelp( 0 );
++ else if( strcmp( argv[ pos ], "--pipe" ) == 0 )
++ {
++ readStdin = true;
++ numOptions++;
++ }
++ else if( strcmp( argv[ pos ], "--user" ) == 0 )
++ {
++ if( pos <= argc - 2 )
++ {
++ user = QString::fromLocal8Bit( argv[ pos + 1] );
++ numOptions +=2;
++ pos++;
++ }
++ else
++ {
++ cerr << "Missing username for '--user' option!" << endl << endl;
++ showHelp( -1 );
++ }
++ }
++ else if( strcmp( argv[ pos ], "--all-users" ) == 0 )
++ {
++ user = "*";
++ numOptions ++;
++ }
++ else if( strcmp( argv[ pos ], "--list-sessions" ) == 0 )
++ {
++ session = QuerySessions;
++ numOptions ++;
++ }
++ else if( strcmp( argv[ pos ], "--all-sessions" ) == 0 )
++ {
++ session = AllSessions;
++ numOptions ++;
++ }
++ else if( argv[ pos ][ 0 ] == '-' )
++ {
++ cerr << "Unknown command-line option '" << argv[ pos ]
++ << "'." << endl << endl;
++ showHelp( -1 );
++ }
++ else
++ break; // End of options
++ }
++
++ argc -= numOptions;
++
++ QCStringList args;
++ for( int i = numOptions; i < argc + numOptions - 1; i++ )
++ args.append( argv[ i + 1 ] );
++
++ if( readStdin && args.count() < 3 )
++ {
++ cerr << "--pipe option only supported for function calls!" << endl << endl;
++ showHelp( -1 );
++ }
++
++ if( user == "*" && args.count() < 3 && session != QuerySessions )
++ {
++ cerr << "ERROR: The --all-users option is only supported for function calls!" << endl << endl;
++ showHelp( -1 );
++ }
++
++ if( session == QuerySessions && !args.isEmpty() )
++ {
++ cerr << "ERROR: The --list-sessions option cannot be used for actual DCOP calls!" << endl << endl;
++ showHelp( -1 );
++ }
++
++ if( session == QuerySessions && user.isEmpty() )
++ {
++ cerr << "ERROR: The --list-sessions option can only be used with the --user or" << endl
++ << "--all-users options!" << endl << endl;
++ showHelp( -1 );
++ }
++
++ if( session != DefaultSession && session != QuerySessions &&
++ args.count() < 3 )
++ {
++ cerr << "ERROR: The --session and --all-sessions options are only supported for function" << endl
++ << "calls!" << endl << endl;
++ showHelp( -1 );
++ }
++
++ UserList users;
++ if( user == "*" )
++ users = userList();
++ else if( !user.isEmpty() )
++ users[ user ] = userList()[ user ];
++
++ runDCOP( args, users, session, sessionName, readStdin );
++
+ return 0;
+ }
++
++// vim: set ts=8 sts=4 sw=4 noet:
++
+Index: client/dcopfind.cpp
+===================================================================
+RCS file: /home/kde/kdelibs/dcop/client/dcopfind.cpp,v
+retrieving revision 1.2
+diff -u -r1.2 dcopfind.cpp
+--- client/dcopfind.cpp 2001/10/31 01:17:39 1.2
++++ client/dcopfind.cpp 2002/01/16 18:06:14
+@@ -36,7 +36,7 @@
+ static bool bAppIdOnly = 0;
+ static bool bLaunchApp = 0;
+
+-bool findObject( const char* app, const char* obj, const char* func, int argc, char** args )
++bool findObject( const char* app, const char* obj, const char* func, QCStringList args )
+ {
+ QString f = func; // Qt is better with unicode strings, so use one.
+ int left = f.find( '(' );
+@@ -118,7 +118,7 @@
+ f = fc;
+ }
+
+- if ( (int) types.count() != argc ) {
++ if ( types.count() != args.count() ) {
+ qWarning( "arguments do not match" );
+ exit(1);
+ }
+@@ -128,9 +128,9 @@
+
+ int i = 0;
+ for ( QStringList::Iterator it = types.begin(); it != types.end(); ++it ) {
+- marshall(arg, argc, args, i, *it);
++ marshall(arg, args, i, *it);
+ }
+- if ( (int) i != argc ) {
++ if ( (uint) i != args.count() ) {
+ qWarning( "arguments do not match" );
+ exit(1);
+ }
+@@ -221,7 +221,11 @@
+ argc = 0;
+ }
+
+- findObject( app, objid, function, argc, args );
++ QCStringList params;
++ for( int i = 0; i < argc; i++ )
++ params.append( args[ i ] );
++
++ findObject( app, objid, function, params );
+
+ return 0;
+ }
+Index: client/marshall.cpp
+===================================================================
+RCS file: /home/kde/kdelibs/dcop/client/marshall.cpp,v
+retrieving revision 1.3
+diff -u -r1.3 marshall.cpp
+--- client/marshall.cpp 2001/10/31 01:17:39 1.3
++++ client/marshall.cpp 2002/01/16 18:06:14
+@@ -242,108 +242,110 @@
+
+ }
+
+-void marshall(QDataStream &arg, int argc, char **argv, int &i, QString type)
++void marshall( QDataStream &arg, QCStringList args, uint &i, QString type )
+ {
+- if (type == "QStringList")
+- type = "QValueList<QString>";
+- if (type == "QCStringList")
+- type = "QValueList<QCString>";
+- if (i >= argc)
+- {
+- qWarning("Not enough arguments.");
+- exit(1);
+- }
+- QString s = QString::fromLocal8Bit(argv[i]);
+-
+- if ( type == "int" )
+- arg << s.toInt();
+- else if ( type == "uint" )
+- arg << s.toUInt();
+- else if ( type == "unsigned" )
+- arg << s.toUInt();
+- else if ( type == "unsigned int" )
+- arg << s.toUInt();
+- else if ( type == "long" )
+- arg << s.toLong();
+- else if ( type == "long int" )
+- arg << s.toLong();
+- else if ( type == "unsigned long" )
+- arg << s.toULong();
+- else if ( type == "unsigned long int" )
+- arg << s.toULong();
+- else if ( type == "float" )
+- arg << s.toFloat();
+- else if ( type == "double" )
+- arg << s.toDouble();
+- else if ( type == "bool" )
+- arg << mkBool( s );
+- else if ( type == "QString" )
+- arg << s;
+- else if ( type == "QCString" )
+- arg << QCString( argv[i] );
+- else if ( type == "QColor" )
+- arg << mkColor( s );
+- else if ( type == "QPoint" )
+- arg << mkPoint( s );
+- else if ( type == "QSize" )
+- arg << mkSize( s );
+- else if ( type == "QRect" )
+- arg << mkRect( s );
+- else if ( type == "QVariant" ) {
+- if ( s == "true" || s == "false" )
+- arg << QVariant( mkBool( s ), 42 );
+- else if ( s.left( 4 ) == "int(" )
+- arg << QVariant( s.mid(4, s.length()-5).toInt() );
+- else if ( s.left( 7 ) == "QPoint(" )
+- arg << QVariant( mkPoint( s.mid(7, s.length()-8) ) );
+- else if ( s.left( 6 ) == "QSize(" )
+- arg << QVariant( mkSize( s.mid(6, s.length()-7) ) );
+- else if ( s.left( 6 ) == "QRect(" )
+- arg << QVariant( mkRect( s.mid(6, s.length()-7) ) );
+- else if ( s.left( 7 ) == "QColor(" )
+- arg << QVariant( mkColor( s.mid(7, s.length()-8) ) );
+- else
+- arg << QVariant( s );
+- } else if ( type.startsWith("QValueList<")) {
+- type = type.mid(11, type.length() - 12);
+- QStringList list;
+- QString delim = s;
+- if (delim == "[")
+- delim = "]";
+- if (delim == "(")
+- delim = ")";
+- i++;
+- QByteArray dummy_data;
+- QDataStream dummy_arg(dummy_data, IO_WriteOnly);
++ if (type == "QStringList")
++ type = "QValueList<QString>";
++ if (type == "QCStringList")
++ type = "QValueList<QCString>";
++ if( i > args.count() )
++ {
++ qWarning("Not enough arguments.");
++ exit(1);
++ }
++ QString s = QString::fromLocal8Bit( args[ i ] );
+
+- int j = i;
+- int count = 0;
+- // Parse list to get the count
+- while (true) {
+- if (j >= argc)
+- {
+- qWarning("List end-delimiter '%s' not found.", delim.latin1());
+- exit(1);
+- }
+- if (argv[j] == delim) break;
+- marshall(dummy_arg, argc, argv, j, type);
+- count++;
+- }
+- arg << (Q_UINT32) count;
+- // Parse the list for real
+- while (true) {
+- if (i >= argc)
+- {
+- qWarning("List end-delimiter '%s' not found.", delim.latin1());
+- exit(1);
+- }
+- if (argv[i] == delim) break;
+- marshall(arg, argc, argv, i, type);
+- }
+- } else {
+- qWarning( "cannot handle datatype '%s'", type.latin1() );
+- exit(1);
+- }
++ if ( type == "int" )
++ arg << s.toInt();
++ else if ( type == "uint" )
++ arg << s.toUInt();
++ else if ( type == "unsigned" )
++ arg << s.toUInt();
++ else if ( type == "unsigned int" )
++ arg << s.toUInt();
++ else if ( type == "long" )
++ arg << s.toLong();
++ else if ( type == "long int" )
++ arg << s.toLong();
++ else if ( type == "unsigned long" )
++ arg << s.toULong();
++ else if ( type == "unsigned long int" )
++ arg << s.toULong();
++ else if ( type == "float" )
++ arg << s.toFloat();
++ else if ( type == "double" )
++ arg << s.toDouble();
++ else if ( type == "bool" )
++ arg << mkBool( s );
++ else if ( type == "QString" )
++ arg << s;
++ else if ( type == "QCString" )
++ arg << QCString( args[ i ] );
++ else if ( type == "QColor" )
++ arg << mkColor( s );
++ else if ( type == "QPoint" )
++ arg << mkPoint( s );
++ else if ( type == "QSize" )
++ arg << mkSize( s );
++ else if ( type == "QRect" )
++ arg << mkRect( s );
++ else if ( type == "QVariant" ) {
++ if ( s == "true" || s == "false" )
++ arg << QVariant( mkBool( s ), 42 );
++ else if ( s.left( 4 ) == "int(" )
++ arg << QVariant( s.mid(4, s.length()-5).toInt() );
++ else if ( s.left( 7 ) == "QPoint(" )
++ arg << QVariant( mkPoint( s.mid(7, s.length()-8) ) );
++ else if ( s.left( 6 ) == "QSize(" )
++ arg << QVariant( mkSize( s.mid(6, s.length()-7) ) );
++ else if ( s.left( 6 ) == "QRect(" )
++ arg << QVariant( mkRect( s.mid(6, s.length()-7) ) );
++ else if ( s.left( 7 ) == "QColor(" )
++ arg << QVariant( mkColor( s.mid(7, s.length()-8) ) );
++ else
++ arg << QVariant( s );
++ } else if ( type.startsWith("QValueList<")) {
++ type = type.mid(11, type.length() - 12);
++ QStringList list;
++ QString delim = s;
++ if (delim == "[")
++ delim = "]";
++ if (delim == "(")
++ delim = ")";
+ i++;
++ QByteArray dummy_data;
++ QDataStream dummy_arg(dummy_data, IO_WriteOnly);
++
++ uint j = i;
++ uint count = 0;
++ // Parse list to get the count
++ while (true) {
++ if( j > args.count() )
++ {
++ qWarning("List end-delimiter '%s' not found.", delim.latin1());
++ exit(1);
++ }
++ if( QString::fromLocal8Bit( args[ j ] ) == delim )
++ break;
++ marshall( dummy_arg, args, j, type );
++ count++;
++ }
++ arg << (Q_UINT32) count;
++ // Parse the list for real
++ while (true) {
++ if( i > args.count() )
++ {
++ qWarning("List end-delimiter '%s' not found.", delim.latin1());
++ exit(1);
++ }
++ if( QString::fromLocal8Bit( args[ i ] ) == delim )
++ break;
++ marshall( arg, args, i, type );
++ }
++ } else {
++ qWarning( "cannot handle datatype '%s'", type.latin1() );
++ exit(1);
++ }
++ i++;
+ }
+
diff --git a/kompare/tests/diff/context.diff b/kompare/tests/diff/context.diff
new file mode 100644
index 00000000..e17df000
--- /dev/null
+++ b/kompare/tests/diff/context.diff
@@ -0,0 +1,27 @@
+*** /home/John/lao Thu Apr 12 11:09:30 2001
+--- /home/John/tzu Sat Jul 28 13:23:25 2001
+***************
+*** 1,7 ****
+- The Way that can be told of is not the eternal Way;
+- The name that can be named is not the eternal name.
+ The Nameless is the origin of Heaven and Earth;
+! The Named is the mother of all things.
+ Therefore let there always be non-being,
+ so we may see their subtlety,
+ And let there always be being,
+--- 1,6 ----
+ The Nameless is the origin of Heaven and Earth;
+! The named is the mother of all things.
+!
+ Therefore let there always be non-being,
+ so we may see their subtlety,
+ And let there always be being,
+***************
+*** 9,11 ****
+--- 8,13 ----
+ The two are the same,
+ But after they are produced,
+ they have different names.
++ They both may be called deep and profound.
++ Deeper and more profound,
++ The door of all subtleties!
diff --git a/kompare/tests/diff/contextm.diff b/kompare/tests/diff/contextm.diff
new file mode 100644
index 00000000..0b1bba5a
--- /dev/null
+++ b/kompare/tests/diff/contextm.diff
@@ -0,0 +1,1032 @@
+diff -cr dcop/client/dcop.cpp dcop2/client/dcop.cpp
+*** dcop/client/dcop.cpp Wed Jan 30 22:38:07 2002
+--- dcop2/client/dcop.cpp Wed Jan 30 22:37:04 2002
+***************
+*** 20,38 ****
+
+ ******************************************************************/
+
+! #include <qvariant.h>
+ #include <qcolor.h>
+! #include "../kdatastream.h"
+ #include "../dcopclient.h"
+ #include "../dcopref.h"
+! #include <stdlib.h>
+! #include <stdio.h>
+! #include <ctype.h>
+
+ #include "marshall.cpp"
+
+ static DCOPClient* dcop = 0;
+
+ bool startsWith(const QCString &id, const char *str, int n)
+ {
+ return !n || (strncmp(id.data(), str, n) == 0);
+--- 20,66 ----
+
+ ******************************************************************/
+
+! #include <ctype.h>
+! #include <stdio.h>
+! #include <stdlib.h>
+!
+ #include <qcolor.h>
+! #include <qdir.h>
+! #include <qfile.h>
+! #include <qfileinfo.h>
+! #include <qmap.h>
+! #include <qstringlist.h>
+! #include <qtextstream.h>
+! #include <qvariant.h>
+!
+! // putenv() is not available on all platforms, so make sure the emulation
+! // wrapper is available in those cases by loading config.h!
+! #include <config.h>
+!
+ #include "../dcopclient.h"
+ #include "../dcopref.h"
+! #include "../kdatastream.h"
+
+ #include "marshall.cpp"
+
++ typedef QMap<QString, QString> UserList;
++
+ static DCOPClient* dcop = 0;
+
++ static QTextStream cout( stdout, IO_WriteOnly );
++ static QTextStream cerr( stderr, IO_WriteOnly );
++
++ /**
++ * Session to send call to
++ * DefaultSession - current session. Current KDE session when called without
++ * --user or --all-users option. Otherwise this value ignores
++ * all users with more than one active session.
++ * AllSessions - Send to all sessions found. requires --user or --all-users.
++ * QuerySessions - Don't call DCOP, return a list of available sessions.
++ * CustomSession - Use the specified session
++ */
++ enum Session { DefaultSession = 0, AllSessions, QuerySessions, CustomSession };
++
+ bool startsWith(const QCString &id, const char *str, int n)
+ {
+ return !n || (strncmp(id.data(), str, n) == 0);
+***************
+*** 118,126 ****
+ }
+ }
+
+! void callFunction( const char* app, const char* obj, const char* func, int argc, char** args )
+ {
+-
+ QString f = func; // Qt is better with unicode strings, so use one.
+ int left = f.find( '(' );
+ int right = f.find( ')' );
+--- 146,153 ----
+ }
+ }
+
+! void callFunction( const char* app, const char* obj, const char* func, const QCStringList args )
+ {
+ QString f = func; // Qt is better with unicode strings, so use one.
+ int left = f.find( '(' );
+ int right = f.find( ')' );
+***************
+*** 136,142 ****
+ bool ok = false;
+ QCStringList funcs = dcop->remoteFunctions( app, obj, &ok );
+ QCString realfunc;
+! if ( !ok && argc == 0 )
+ goto doit;
+ if ( !ok )
+ {
+--- 163,169 ----
+ bool ok = false;
+ QCStringList funcs = dcop->remoteFunctions( app, obj, &ok );
+ QCString realfunc;
+! if ( !ok && args.isEmpty() )
+ goto doit;
+ if ( !ok )
+ {
+***************
+*** 153,167 ****
+
+ if ( l > 0 && (*it).mid( s, l - s ) == func ) {
+ realfunc = (*it).mid( s );
+! int a = (*it).contains(',');
+! if ( ( a == 0 && argc == 0) || ( a > 0 && a + 1 == argc ) )
+ break;
+ }
+ }
+ if ( realfunc.isEmpty() )
+ {
+ qWarning("no such function");
+! exit(1);
+ }
+ f = realfunc;
+ left = f.find( '(' );
+--- 180,195 ----
+
+ if ( l > 0 && (*it).mid( s, l - s ) == func ) {
+ realfunc = (*it).mid( s );
+! uint a = (*it).contains(',');
+! if ( ( a == 0 && args.isEmpty() ) || ( a > 0 && a + 1 == args.count() ) )
+ break;
+ }
+ }
+ if ( realfunc.isEmpty() )
+ {
+ qWarning("no such function");
+! // exit(1);
+! return;
+ }
+ f = realfunc;
+ left = f.find( '(' );
+***************
+*** 243,253 ****
+ QCString replyType;
+ QDataStream arg(data, IO_WriteOnly);
+
+! int i = 0;
+! for ( QStringList::Iterator it = types.begin(); it != types.end(); ++it ) {
+! marshall(arg, argc, args, i, *it);
+! }
+! if ( i != argc ) {
+ qWarning( "arguments do not match" );
+ exit(1);
+ }
+--- 271,282 ----
+ QCString replyType;
+ QDataStream arg(data, IO_WriteOnly);
+
+! uint i = 0;
+! for( QStringList::Iterator it = types.begin(); it != types.end(); ++it )
+! marshall( arg, args, i, *it );
+!
+! if ( i != args.count() )
+! {
+ qWarning( "arguments do not match" );
+ exit(1);
+ }
+***************
+*** 266,343 ****
+ }
+ }
+
+
+!
+! int main( int argc, char** argv )
+ {
+
+! if ( argc > 1 && argv[1][0] == '-' ) {
+! fprintf( stderr, "Usage: dcop [ application [object [function [arg1] [arg2] [arg3] ... ] ] ] \n" );
+! exit(0);
+ }
+
+! DCOPClient client;
+! client.attach();
+! dcop = &client;
+
+ QCString app;
+ QCString objid;
+ QCString function;
+! char **args = 0;
+! if ((argc > 1) && (strncmp(argv[1], "DCOPRef(", 8)) == 0)
+ {
+! char *delim = strchr(argv[1], ',');
+! if (!delim)
+! {
+! fprintf(stderr, "Error: '%s' is not a valid DCOP reference.\n", argv[1]);
+! return 1;
+! }
+! *delim = 0;
+! app = argv[1] + 8;
+! delim++;
+! delim[strlen(delim)-1] = 0;
+! objid = delim;
+! if (argc > 2)
+! function = argv[2];
+! if (argc > 3)
+! args = &argv[3];
+! argc++;
+ }
+ else
+ {
+! if (argc > 1)
+! app = argv[1];
+! if (argc > 2)
+! objid = argv[2];
+! if (argc > 3)
+! function = argv[3];
+! if (argc > 4)
+! args = &argv[4];
+! }
+!
+! switch ( argc ) {
+! case 0:
+! case 1:
+! queryApplications("");
+! break;
+! case 2:
+! if (endsWith(app, '*'))
+! queryApplications(app);
+! else
+! queryObjects( app, "" );
+! break;
+! case 3:
+! if (endsWith(objid, '*'))
+! queryObjects(app, objid);
+! else
+! queryFunctions( app, objid );
+! break;
+! case 4:
+! default:
+! callFunction( app, objid, function, argc - 4, args );
+! break;
+
+ }
+
+ return 0;
+ }
+--- 295,773 ----
+ }
+ }
+
++ /**
++ * Show command-line help and exit
++ */
++ void showHelp( int exitCode = 0 )
++ {
++ cout << "Usage: dcop [options] [application [object [function [arg1] [arg2] ... ] ] ]" << endl
++ << "" << endl
++ << "Console DCOP client" << endl
++ << "" << endl
++ << "Generic options:" << endl
++ << " --help Show help about options" << endl
++ << "" << endl
++ << "Options:" << endl
++ << " --pipe Call DCOP for each line read from stdin" << endl
++ << " --user <user> Connect to the given user's DCOP server. This option will" << endl
++ << " ignore the values of the environment vars $DCOPSERVER and" << endl
++ << " $ICEAUTHORITY, even if they are set." << endl
++ << " If the user has more than one open session, you must also" << endl
++ << " use one of the --list-sessions, --session or --als-sessions" << endl
++ << " command-line options." << endl
++ << " --all-users Send the same DCOP call to all users with a running DCOP" << endl
++ << " server. Only failed calls to existing DCOP servers will"
++ << " generate an error message. If no DCOP server is available" << endl
++ << " at all, no error will be generated." << endl;
++
++ exit( exitCode );
++ }
+
+! /**
+! * Return a list of all users and their home directories.
+! * Returns an empty list if /etc/passwd cannot be read for some reason.
+! */
+! static UserList userList()
+ {
++ UserList result;
++
++ QFile f( "/etc/passwd" );
++
++ if( !f.open( IO_ReadOnly ) )
++ {
++ cerr << "Can't open /etc/passwd for reading!" << endl;
++ return result;
++ }
+
+! QStringList l( QStringList::split( '\n', f.readAll() ) );
+!
+! for( QStringList::ConstIterator it( l.begin() ); it != l.end(); ++it )
+! {
+! QStringList userInfo( QStringList::split( ':', *it, true ) );
+! result[ userInfo[ 0 ] ] = userInfo[ 5 ];
+ }
+
+! return result;
+! }
+!
+! /**
+! * Return a list of available DCOP sessions for the specified user
+! * An empty list means no sessions are available, or an error occurred.
+! */
+! QStringList dcopSessionList( const QString &user, const QString &home )
+! {
+! if( home.isEmpty() )
+! {
+! cerr << "WARNING: Cannot determine home directory for user "
+! << user << "!" << endl
+! << "Please check permissions or set the $DCOPSERVER variable manually before" << endl
+! << "calling dcop." << endl;
+! return QStringList();
+! }
+!
+! QStringList result;
+! QFileInfo dirInfo( home );
+! if( !dirInfo.exists() || !dirInfo.isReadable() )
+! return result;
+!
+! QDir d( home );
+! d.setFilter( QDir::Files | QDir::Hidden | QDir::NoSymLinks );
+! d.setNameFilter( ".DCOPserver*" );
+!
+! const QFileInfoList *list = d.entryInfoList();
+! if( !list )
+! return result;
+!
+! QFileInfoListIterator it( *list );
+! QFileInfo *fi;
+!
+! while ( ( fi = it.current() ) != 0 )
+! {
+! if( fi->isReadable() )
+! result.append( fi->fileName() );
+! ++it;
+! }
+! return result;
+! }
+
++ /**
++ * Do the actual DCOP call
++ */
++ void runDCOP( QCStringList args, UserList users, Session session,
++ const QString sessionName, bool readStdin )
++ {
+ QCString app;
+ QCString objid;
+ QCString function;
+! QCStringList params;
+! DCOPClient *client = 0L;
+! if ( !args.isEmpty() && args[ 0 ].find( "DCOPRef(" ) == 0 )
+ {
+! // WARNING: This part (until the closing '}') could very
+! // well be broken now. As I don't know how to trigger and test
+! // dcoprefs this code is *not* tested. It compiles and it looks
+! // ok to me, but that's all I can say - Martijn (2001/12/24)
+! int delimPos = args[ 0 ].findRev( ',' );
+! if( delimPos == -1 )
+! {
+! cerr << "Error: '" << args[ 0 ]
+! << "' is not a valid DCOP reference." << endl;
+! exit( -1 );
+! }
+! args[ 0 ][ delimPos ] = 0;
+! app = args[ 0 ].mid( 8 );
+! delimPos++;
+! args[ 0 ][ args[ 0 ].length() - 1 ] = 0;
+! objid = args[ 0 ].mid( delimPos );
+! if( args.count() > 1 )
+! function = args[ 1 ];
+! if( args.count() > 2 )
+! {
+! params = args;
+! params.remove( params.begin() );
+! params.remove( params.begin() );
+! }
+ }
+ else
+ {
+! if( !args.isEmpty() )
+! app = args[ 0 ];
+! if( args.count() > 1 )
+! objid = args[ 1 ];
+! if( args.count() > 2 )
+! function = args[ 2 ];
+! if( args.count() > 3)
+! {
+! params = args;
+! params.remove( params.begin() );
+! params.remove( params.begin() );
+! params.remove( params.begin() );
+! }
+! }
+!
+! bool firstRun = true;
+! UserList::Iterator it;
+! QStringList sessions;
+! bool presetDCOPServer = false;
+! // char *dcopStr = 0L;
+! QString dcopServer;
+!
+! for( it = users.begin(); it != users.end() || firstRun; it++ )
+! {
+! firstRun = false;
+!
+! //cout << "Iterating '" << it.key() << "'" << endl;
+!
+! if( session == QuerySessions )
+! {
+! QStringList sessions = dcopSessionList( it.key(), it.data() );
+! if( sessions.isEmpty() )
+! {
+! cout << "No active sessions";
+! if( !( *it ).isEmpty() )
+! cout << " for user " << *it;
+! cout << endl;
+! }
+! else
+! {
+! cout << "Active sessions ";
+! if( !( *it ).isEmpty() )
+! cout << "for user " << *it << " ";
+! cout << ":" << endl;
+!
+! QStringList::Iterator sIt;
+! for( sIt = sessions.begin(); sIt != sessions.end(); sIt++ )
+! cout << " " << *sIt << endl;
+!
+! cout << endl;
+! }
+! continue;
+! }
+!
+! if( getenv( "DCOPSERVER" ) )
+! {
+! sessions.append( getenv( "DCOPSERVER" ) );
+! presetDCOPServer = true;
+! }
+!
+! if( users.count() > 1 || ( users.count() == 1 &&
+! ( getenv( "DCOPSERVER" ) == 0 /*&& getenv( "DISPLAY" ) == 0*/ ) ) )
+! {
+! sessions = dcopSessionList( it.key(), it.data() );
+! if( sessions.isEmpty() )
+! {
+! if( users.count() > 1 )
+! continue;
+! else
+! {
+! cerr << "ERROR: No active KDE sessions!" << endl
+! << "If you are sure there is one, please set the $DCOPSERVER variable manually" << endl
+! << "before calling dcop." << endl;
+! exit( -1 );
+! }
+! }
+! else if( sessions.count() > 1 && session != AllSessions )
+! {
+! cerr << "ERROR: Multiple available KDE sessions!" << endl
+! << "Please specify the correct session to use with --session or use the" << endl
+! << "--all-sessions option to broadcast to all sessions." << endl;
+! exit( -1 );
+! }
+! }
+
++ if( users.count() > 1 || ( users.count() == 1 &&
++ ( getenv( "ICEAUTHORITY" ) == 0 || getenv( "DISPLAY" ) == 0 ) ) )
++ {
++ // Check for ICE authority file and if the file can be read by us
++ QString home = it.data();
++ QString iceFile = it.data() + "/.ICEauthority";
++ QFileInfo fi( iceFile );
++ if( iceFile.isEmpty() )
++ {
++ cerr << "WARNING: Cannot determine home directory for user "
++ << it.key() << "!" << endl
++ << "Please check permissions or set the $ICEAUTHORITY variable manually before" << endl
++ << "calling dcop." << endl;
++ }
++ else if( fi.exists() )
++ {
++ if( fi.isReadable() )
++ {
++ char *envStr = strdup( ( "ICEAUTHORITY=" + iceFile ).ascii() );
++ putenv( envStr );
++ //cerr << "ice: " << envStr << endl;
++ }
++ else
++ {
++ cerr << "WARNING: ICE authority file " << iceFile
++ << "is not readable by you!" << endl
++ << "Please check permissions or set the $ICEAUTHORITY variable manually before" << endl
++ << "calling dcop." << endl;
++ }
++ }
++ else
++ {
++ if( users.count() > 1 )
++ continue;
++ else
++ {
++ cerr << "WARNING: Cannot find ICE authority file "
++ << iceFile << "!" << endl
++ << "Please check permissions or set the $ICEAUTHORITY"
++ << " variable manually before" << endl
++ << "calling dcop." << endl;
++ }
++ }
++ }
++
++ // Main loop
++ // If users is an empty list we're calling for the currently logged
++ // in user. In this case we don't have a session, but still want
++ // to iterate the loop once.
++ QStringList::Iterator sIt = sessions.begin();
++ for( ; sIt != sessions.end() || users.isEmpty(); sIt++ )
++ {
++ if( !presetDCOPServer && !users.isEmpty() )
++ {
++ QString dcopFile = it.data() + "/" + *sIt;
++ QFile f( dcopFile );
++ if( !f.open( IO_ReadOnly ) )
++ {
++ cerr << "Can't open " << dcopFile << " for reading!" << endl;
++ exit( -1 );
++ }
++
++ QStringList l( QStringList::split( '\n', f.readAll() ) );
++ dcopServer = l.first();
++
++ if( dcopServer.isEmpty() )
++ {
++ cerr << "WARNING: Unable to determine DCOP server for session "
++ << *sIt << "!" << endl
++ << "Please check permissions or set the $DCOPSERVER variable manually before" << endl
++ << "calling dcop." << endl;
++ exit( -1 );
++ }
++ }
++
++ delete client;
++ client = new DCOPClient;
++ if( !dcopServer.isEmpty() )
++ client->setServerAddress( dcopServer.ascii() );
++ bool success = client->attach();
++ if( !success )
++ {
++ cerr << "ERROR: Couldn't attach to DCOP server!" << endl;
++ continue;
++ }
++ dcop = client;
++
++ switch ( args.count() )
++ {
++ case 0:
++ queryApplications("");
++ break;
++ case 1:
++ if (endsWith(app, '*'))
++ queryApplications(app);
++ else
++ queryObjects( app, "" );
++ break;
++ case 2:
++ if (endsWith(objid, '*'))
++ queryObjects(app, objid);
++ else
++ queryFunctions( app, objid );
++ break;
++ case 3:
++ default:
++ if( readStdin )
++ {
++ QCStringList::Iterator replaceArg = args.end();
++
++ QCStringList::Iterator it;
++ for( it = args.begin(); it != args.end(); it++ )
++ if( *it == "%1" )
++ replaceArg = it;
++
++ // Read from stdin until EOF and call function for each line read
++ char *buf = new char[ 1000 ];
++ while ( !feof( stdin ) )
++ {
++ fgets( buf, 1000, stdin );
++
++ if( replaceArg != args.end() )
++ *replaceArg = buf;
++
++ callFunction( app, objid, function, params );
++ }
++ }
++ else
++ {
++ // Just call function
++ // cout << "call " << app << ", " << objid << ", " << function << ", (params)" << endl;
++ callFunction( app, objid, function, params );
++ }
++ break;
++ }
++ // Another sIt++ would make the loop infinite...
++ if( users.isEmpty() )
++ break;
++ }
++
++ // Another it++ would make the loop infinite...
++ if( it == users.end() )
++ break;
+ }
++ }
++
++
++ int main( int argc, char** argv )
++ {
++ bool readStdin = false;
++ int numOptions = 0;
++ QString user;
++ Session session = DefaultSession;
++ QString sessionName;
++
++ // Scan for command-line options first
++ for( int pos = 1 ; pos <= argc - 1 ; pos++ )
++ {
++ if( strcmp( argv[ pos ], "--help" ) == 0 )
++ showHelp( 0 );
++ else if( strcmp( argv[ pos ], "--pipe" ) == 0 )
++ {
++ readStdin = true;
++ numOptions++;
++ }
++ else if( strcmp( argv[ pos ], "--user" ) == 0 )
++ {
++ if( pos <= argc - 2 )
++ {
++ user = QString::fromLocal8Bit( argv[ pos + 1] );
++ numOptions +=2;
++ pos++;
++ }
++ else
++ {
++ cerr << "Missing username for '--user' option!" << endl << endl;
++ showHelp( -1 );
++ }
++ }
++ else if( strcmp( argv[ pos ], "--all-users" ) == 0 )
++ {
++ user = "*";
++ numOptions ++;
++ }
++ else if( strcmp( argv[ pos ], "--list-sessions" ) == 0 )
++ {
++ session = QuerySessions;
++ numOptions ++;
++ }
++ else if( strcmp( argv[ pos ], "--all-sessions" ) == 0 )
++ {
++ session = AllSessions;
++ numOptions ++;
++ }
++ else if( argv[ pos ][ 0 ] == '-' )
++ {
++ cerr << "Unknown command-line option '" << argv[ pos ]
++ << "'." << endl << endl;
++ showHelp( -1 );
++ }
++ else
++ break; // End of options
++ }
++
++ argc -= numOptions;
++
++ QCStringList args;
++ for( int i = numOptions; i < argc + numOptions - 1; i++ )
++ args.append( argv[ i + 1 ] );
++
++ if( readStdin && args.count() < 3 )
++ {
++ cerr << "--pipe option only supported for function calls!" << endl << endl;
++ showHelp( -1 );
++ }
++
++ if( user == "*" && args.count() < 3 && session != QuerySessions )
++ {
++ cerr << "ERROR: The --all-users option is only supported for function calls!" << endl << endl;
++ showHelp( -1 );
++ }
++
++ if( session == QuerySessions && !args.isEmpty() )
++ {
++ cerr << "ERROR: The --list-sessions option cannot be used for actual DCOP calls!" << endl << endl;
++ showHelp( -1 );
++ }
++
++ if( session == QuerySessions && user.isEmpty() )
++ {
++ cerr << "ERROR: The --list-sessions option can only be used with the --user or" << endl
++ << "--all-users options!" << endl << endl;
++ showHelp( -1 );
++ }
++
++ if( session != DefaultSession && session != QuerySessions &&
++ args.count() < 3 )
++ {
++ cerr << "ERROR: The --session and --all-sessions options are only supported for function" << endl
++ << "calls!" << endl << endl;
++ showHelp( -1 );
++ }
++
++ UserList users;
++ if( user == "*" )
++ users = userList();
++ else if( !user.isEmpty() )
++ users[ user ] = userList()[ user ];
++
++ runDCOP( args, users, session, sessionName, readStdin );
+
+ return 0;
+ }
++
++ // vim: set ts=8 sts=4 sw=4 noet:
++
+diff -cr dcop/client/dcopfind.cpp dcop2/client/dcopfind.cpp
+*** dcop/client/dcopfind.cpp Wed Jan 30 22:38:07 2002
+--- dcop2/client/dcopfind.cpp Wed Jan 30 22:37:04 2002
+***************
+*** 36,42 ****
+ static bool bAppIdOnly = 0;
+ static bool bLaunchApp = 0;
+
+! bool findObject( const char* app, const char* obj, const char* func, int argc, char** args )
+ {
+ QString f = func; // Qt is better with unicode strings, so use one.
+ int left = f.find( '(' );
+--- 36,42 ----
+ static bool bAppIdOnly = 0;
+ static bool bLaunchApp = 0;
+
+! bool findObject( const char* app, const char* obj, const char* func, QCStringList args )
+ {
+ QString f = func; // Qt is better with unicode strings, so use one.
+ int left = f.find( '(' );
+***************
+*** 118,124 ****
+ f = fc;
+ }
+
+! if ( (int) types.count() != argc ) {
+ qWarning( "arguments do not match" );
+ exit(1);
+ }
+--- 118,124 ----
+ f = fc;
+ }
+
+! if ( types.count() != args.count() ) {
+ qWarning( "arguments do not match" );
+ exit(1);
+ }
+***************
+*** 128,136 ****
+
+ int i = 0;
+ for ( QStringList::Iterator it = types.begin(); it != types.end(); ++it ) {
+! marshall(arg, argc, args, i, *it);
+ }
+! if ( (int) i != argc ) {
+ qWarning( "arguments do not match" );
+ exit(1);
+ }
+--- 128,136 ----
+
+ int i = 0;
+ for ( QStringList::Iterator it = types.begin(); it != types.end(); ++it ) {
+! marshall(arg, args, i, *it);
+ }
+! if ( (uint) i != args.count() ) {
+ qWarning( "arguments do not match" );
+ exit(1);
+ }
+***************
+*** 221,227 ****
+ argc = 0;
+ }
+
+! findObject( app, objid, function, argc, args );
+
+ return 0;
+ }
+--- 221,231 ----
+ argc = 0;
+ }
+
+! QCStringList params;
+! for( int i = 0; i < argc; i++ )
+! params.append( args[ i ] );
+!
+! findObject( app, objid, function, params );
+
+ return 0;
+ }
+diff -cr dcop/client/marshall.cpp dcop2/client/marshall.cpp
+*** dcop/client/marshall.cpp Wed Jan 30 22:38:07 2002
+--- dcop2/client/marshall.cpp Wed Jan 30 22:37:04 2002
+***************
+*** 242,349 ****
+
+ }
+
+! void marshall(QDataStream &arg, int argc, char **argv, int &i, QString type)
+ {
+! if (type == "QStringList")
+! type = "QValueList<QString>";
+! if (type == "QCStringList")
+! type = "QValueList<QCString>";
+! if (i >= argc)
+! {
+! qWarning("Not enough arguments.");
+! exit(1);
+! }
+! QString s = QString::fromLocal8Bit(argv[i]);
+!
+! if ( type == "int" )
+! arg << s.toInt();
+! else if ( type == "uint" )
+! arg << s.toUInt();
+! else if ( type == "unsigned" )
+! arg << s.toUInt();
+! else if ( type == "unsigned int" )
+! arg << s.toUInt();
+! else if ( type == "long" )
+! arg << s.toLong();
+! else if ( type == "long int" )
+! arg << s.toLong();
+! else if ( type == "unsigned long" )
+! arg << s.toULong();
+! else if ( type == "unsigned long int" )
+! arg << s.toULong();
+! else if ( type == "float" )
+! arg << s.toFloat();
+! else if ( type == "double" )
+! arg << s.toDouble();
+! else if ( type == "bool" )
+! arg << mkBool( s );
+! else if ( type == "QString" )
+! arg << s;
+! else if ( type == "QCString" )
+! arg << QCString( argv[i] );
+! else if ( type == "QColor" )
+! arg << mkColor( s );
+! else if ( type == "QPoint" )
+! arg << mkPoint( s );
+! else if ( type == "QSize" )
+! arg << mkSize( s );
+! else if ( type == "QRect" )
+! arg << mkRect( s );
+! else if ( type == "QVariant" ) {
+! if ( s == "true" || s == "false" )
+! arg << QVariant( mkBool( s ), 42 );
+! else if ( s.left( 4 ) == "int(" )
+! arg << QVariant( s.mid(4, s.length()-5).toInt() );
+! else if ( s.left( 7 ) == "QPoint(" )
+! arg << QVariant( mkPoint( s.mid(7, s.length()-8) ) );
+! else if ( s.left( 6 ) == "QSize(" )
+! arg << QVariant( mkSize( s.mid(6, s.length()-7) ) );
+! else if ( s.left( 6 ) == "QRect(" )
+! arg << QVariant( mkRect( s.mid(6, s.length()-7) ) );
+! else if ( s.left( 7 ) == "QColor(" )
+! arg << QVariant( mkColor( s.mid(7, s.length()-8) ) );
+! else
+! arg << QVariant( s );
+! } else if ( type.startsWith("QValueList<")) {
+! type = type.mid(11, type.length() - 12);
+! QStringList list;
+! QString delim = s;
+! if (delim == "[")
+! delim = "]";
+! if (delim == "(")
+! delim = ")";
+! i++;
+! QByteArray dummy_data;
+! QDataStream dummy_arg(dummy_data, IO_WriteOnly);
+
+! int j = i;
+! int count = 0;
+! // Parse list to get the count
+! while (true) {
+! if (j >= argc)
+! {
+! qWarning("List end-delimiter '%s' not found.", delim.latin1());
+! exit(1);
+! }
+! if (argv[j] == delim) break;
+! marshall(dummy_arg, argc, argv, j, type);
+! count++;
+! }
+! arg << (Q_UINT32) count;
+! // Parse the list for real
+! while (true) {
+! if (i >= argc)
+! {
+! qWarning("List end-delimiter '%s' not found.", delim.latin1());
+! exit(1);
+! }
+! if (argv[i] == delim) break;
+! marshall(arg, argc, argv, i, type);
+! }
+! } else {
+! qWarning( "cannot handle datatype '%s'", type.latin1() );
+! exit(1);
+! }
+ i++;
+ }
+
+--- 242,351 ----
+
+ }
+
+! void marshall( QDataStream &arg, QCStringList args, uint &i, QString type )
+ {
+! if (type == "QStringList")
+! type = "QValueList<QString>";
+! if (type == "QCStringList")
+! type = "QValueList<QCString>";
+! if( i > args.count() )
+! {
+! qWarning("Not enough arguments.");
+! exit(1);
+! }
+! QString s = QString::fromLocal8Bit( args[ i ] );
+
+! if ( type == "int" )
+! arg << s.toInt();
+! else if ( type == "uint" )
+! arg << s.toUInt();
+! else if ( type == "unsigned" )
+! arg << s.toUInt();
+! else if ( type == "unsigned int" )
+! arg << s.toUInt();
+! else if ( type == "long" )
+! arg << s.toLong();
+! else if ( type == "long int" )
+! arg << s.toLong();
+! else if ( type == "unsigned long" )
+! arg << s.toULong();
+! else if ( type == "unsigned long int" )
+! arg << s.toULong();
+! else if ( type == "float" )
+! arg << s.toFloat();
+! else if ( type == "double" )
+! arg << s.toDouble();
+! else if ( type == "bool" )
+! arg << mkBool( s );
+! else if ( type == "QString" )
+! arg << s;
+! else if ( type == "QCString" )
+! arg << QCString( args[ i ] );
+! else if ( type == "QColor" )
+! arg << mkColor( s );
+! else if ( type == "QPoint" )
+! arg << mkPoint( s );
+! else if ( type == "QSize" )
+! arg << mkSize( s );
+! else if ( type == "QRect" )
+! arg << mkRect( s );
+! else if ( type == "QVariant" ) {
+! if ( s == "true" || s == "false" )
+! arg << QVariant( mkBool( s ), 42 );
+! else if ( s.left( 4 ) == "int(" )
+! arg << QVariant( s.mid(4, s.length()-5).toInt() );
+! else if ( s.left( 7 ) == "QPoint(" )
+! arg << QVariant( mkPoint( s.mid(7, s.length()-8) ) );
+! else if ( s.left( 6 ) == "QSize(" )
+! arg << QVariant( mkSize( s.mid(6, s.length()-7) ) );
+! else if ( s.left( 6 ) == "QRect(" )
+! arg << QVariant( mkRect( s.mid(6, s.length()-7) ) );
+! else if ( s.left( 7 ) == "QColor(" )
+! arg << QVariant( mkColor( s.mid(7, s.length()-8) ) );
+! else
+! arg << QVariant( s );
+! } else if ( type.startsWith("QValueList<")) {
+! type = type.mid(11, type.length() - 12);
+! QStringList list;
+! QString delim = s;
+! if (delim == "[")
+! delim = "]";
+! if (delim == "(")
+! delim = ")";
+ i++;
++ QByteArray dummy_data;
++ QDataStream dummy_arg(dummy_data, IO_WriteOnly);
++
++ uint j = i;
++ uint count = 0;
++ // Parse list to get the count
++ while (true) {
++ if( j > args.count() )
++ {
++ qWarning("List end-delimiter '%s' not found.", delim.latin1());
++ exit(1);
++ }
++ if( QString::fromLocal8Bit( args[ j ] ) == delim )
++ break;
++ marshall( dummy_arg, args, j, type );
++ count++;
++ }
++ arg << (Q_UINT32) count;
++ // Parse the list for real
++ while (true) {
++ if( i > args.count() )
++ {
++ qWarning("List end-delimiter '%s' not found.", delim.latin1());
++ exit(1);
++ }
++ if( QString::fromLocal8Bit( args[ i ] ) == delim )
++ break;
++ marshall( arg, args, i, type );
++ }
++ } else {
++ qWarning( "cannot handle datatype '%s'", type.latin1() );
++ exit(1);
++ }
++ i++;
+ }
+
diff --git a/kompare/tests/diff/contextp.diff b/kompare/tests/diff/contextp.diff
new file mode 100644
index 00000000..ed9319bc
--- /dev/null
+++ b/kompare/tests/diff/contextp.diff
@@ -0,0 +1,27 @@
+*** /home/John/lao Thu Apr 12 11:09:30 2001
+--- /home/John/tzu Sat Jul 28 13:23:25 2001
+***************
+*** 1,7 ****
+- The Way that can be told of is not the eternal Way;
+- The name that can be named is not the eternal name.
+ The Nameless is the origin of Heaven and Earth;
+! The Named is the mother of all things.
+ Therefore let there always be non-being,
+ so we may see their subtlety,
+ And let there always be being,
+--- 1,6 ----
+ The Nameless is the origin of Heaven and Earth;
+! The named is the mother of all things.
+!
+ Therefore let there always be non-being,
+ so we may see their subtlety,
+ And let there always be being,
+*************** And let there always be being,
+*** 9,11 ****
+--- 8,13 ----
+ The two are the same,
+ But after they are produced,
+ they have different names.
++ They both may be called deep and profound.
++ Deeper and more profound,
++ The door of all subtleties!
diff --git a/kompare/tests/diff/ed.diff b/kompare/tests/diff/ed.diff
new file mode 100644
index 00000000..43c2b2f1
--- /dev/null
+++ b/kompare/tests/diff/ed.diff
@@ -0,0 +1,10 @@
+11a
+They both may be called deep and profound.
+Deeper and more profound,
+The door of all subtleties!
+.
+4c
+The named is the mother of all things.
+
+.
+1,2d
diff --git a/kompare/tests/diff/edm.diff b/kompare/tests/diff/edm.diff
new file mode 100644
index 00000000..0df2abc1
--- /dev/null
+++ b/kompare/tests/diff/edm.diff
@@ -0,0 +1,680 @@
+diff -er dcop/client/dcop.cpp dcop2/client/dcop.cpp
+343a
+
+// vim: set ts=8 sts=4 sw=4 noet:
+
+.
+340a
+}
+
+
+int main( int argc, char** argv )
+{
+ bool readStdin = false;
+ int numOptions = 0;
+ QString user;
+ Session session = DefaultSession;
+ QString sessionName;
+
+ // Scan for command-line options first
+ for( int pos = 1 ; pos <= argc - 1 ; pos++ )
+ {
+ if( strcmp( argv[ pos ], "--help" ) == 0 )
+ showHelp( 0 );
+ else if( strcmp( argv[ pos ], "--pipe" ) == 0 )
+ {
+ readStdin = true;
+ numOptions++;
+ }
+ else if( strcmp( argv[ pos ], "--user" ) == 0 )
+ {
+ if( pos <= argc - 2 )
+ {
+ user = QString::fromLocal8Bit( argv[ pos + 1] );
+ numOptions +=2;
+ pos++;
+ }
+ else
+ {
+ cerr << "Missing username for '--user' option!" << endl << endl;
+ showHelp( -1 );
+ }
+ }
+ else if( strcmp( argv[ pos ], "--all-users" ) == 0 )
+ {
+ user = "*";
+ numOptions ++;
+ }
+ else if( strcmp( argv[ pos ], "--list-sessions" ) == 0 )
+ {
+ session = QuerySessions;
+ numOptions ++;
+ }
+ else if( strcmp( argv[ pos ], "--all-sessions" ) == 0 )
+ {
+ session = AllSessions;
+ numOptions ++;
+ }
+ else if( argv[ pos ][ 0 ] == '-' )
+ {
+ cerr << "Unknown command-line option '" << argv[ pos ]
+ << "'." << endl << endl;
+ showHelp( -1 );
+ }
+ else
+ break; // End of options
+ }
+
+ argc -= numOptions;
+
+ QCStringList args;
+ for( int i = numOptions; i < argc + numOptions - 1; i++ )
+ args.append( argv[ i + 1 ] );
+
+ if( readStdin && args.count() < 3 )
+ {
+ cerr << "--pipe option only supported for function calls!" << endl << endl;
+ showHelp( -1 );
+ }
+
+ if( user == "*" && args.count() < 3 && session != QuerySessions )
+ {
+ cerr << "ERROR: The --all-users option is only supported for function calls!" << endl << endl;
+ showHelp( -1 );
+ }
+
+ if( session == QuerySessions && !args.isEmpty() )
+ {
+ cerr << "ERROR: The --list-sessions option cannot be used for actual DCOP calls!" << endl << endl;
+ showHelp( -1 );
+ }
+
+ if( session == QuerySessions && user.isEmpty() )
+ {
+ cerr << "ERROR: The --list-sessions option can only be used with the --user or" << endl
+ << "--all-users options!" << endl << endl;
+ showHelp( -1 );
+ }
+
+ if( session != DefaultSession && session != QuerySessions &&
+ args.count() < 3 )
+ {
+ cerr << "ERROR: The --session and --all-sessions options are only supported for function" << endl
+ << "calls!" << endl << endl;
+ showHelp( -1 );
+ }
+
+ UserList users;
+ if( user == "*" )
+ users = userList();
+ else if( !user.isEmpty() )
+ users[ user ] = userList()[ user ];
+
+ runDCOP( args, users, session, sessionName, readStdin );
+.
+339a
+ if( users.count() > 1 || ( users.count() == 1 &&
+ ( getenv( "ICEAUTHORITY" ) == 0 || getenv( "DISPLAY" ) == 0 ) ) )
+ {
+ // Check for ICE authority file and if the file can be read by us
+ QString home = it.data();
+ QString iceFile = it.data() + "/.ICEauthority";
+ QFileInfo fi( iceFile );
+ if( iceFile.isEmpty() )
+ {
+ cerr << "WARNING: Cannot determine home directory for user "
+ << it.key() << "!" << endl
+ << "Please check permissions or set the $ICEAUTHORITY variable manually before" << endl
+ << "calling dcop." << endl;
+ }
+ else if( fi.exists() )
+ {
+ if( fi.isReadable() )
+ {
+ char *envStr = strdup( ( "ICEAUTHORITY=" + iceFile ).ascii() );
+ putenv( envStr );
+ //cerr << "ice: " << envStr << endl;
+ }
+ else
+ {
+ cerr << "WARNING: ICE authority file " << iceFile
+ << "is not readable by you!" << endl
+ << "Please check permissions or set the $ICEAUTHORITY variable manually before" << endl
+ << "calling dcop." << endl;
+ }
+ }
+ else
+ {
+ if( users.count() > 1 )
+ continue;
+ else
+ {
+ cerr << "WARNING: Cannot find ICE authority file "
+ << iceFile << "!" << endl
+ << "Please check permissions or set the $ICEAUTHORITY"
+ << " variable manually before" << endl
+ << "calling dcop." << endl;
+ }
+ }
+ }
+
+ // Main loop
+ // If users is an empty list we're calling for the currently logged
+ // in user. In this case we don't have a session, but still want
+ // to iterate the loop once.
+ QStringList::Iterator sIt = sessions.begin();
+ for( ; sIt != sessions.end() || users.isEmpty(); sIt++ )
+ {
+ if( !presetDCOPServer && !users.isEmpty() )
+ {
+ QString dcopFile = it.data() + "/" + *sIt;
+ QFile f( dcopFile );
+ if( !f.open( IO_ReadOnly ) )
+ {
+ cerr << "Can't open " << dcopFile << " for reading!" << endl;
+ exit( -1 );
+ }
+
+ QStringList l( QStringList::split( '\n', f.readAll() ) );
+ dcopServer = l.first();
+
+ if( dcopServer.isEmpty() )
+ {
+ cerr << "WARNING: Unable to determine DCOP server for session "
+ << *sIt << "!" << endl
+ << "Please check permissions or set the $DCOPSERVER variable manually before" << endl
+ << "calling dcop." << endl;
+ exit( -1 );
+ }
+ }
+
+ delete client;
+ client = new DCOPClient;
+ if( !dcopServer.isEmpty() )
+ client->setServerAddress( dcopServer.ascii() );
+ bool success = client->attach();
+ if( !success )
+ {
+ cerr << "ERROR: Couldn't attach to DCOP server!" << endl;
+ continue;
+ }
+ dcop = client;
+
+ switch ( args.count() )
+ {
+ case 0:
+ queryApplications("");
+ break;
+ case 1:
+ if (endsWith(app, '*'))
+ queryApplications(app);
+ else
+ queryObjects( app, "" );
+ break;
+ case 2:
+ if (endsWith(objid, '*'))
+ queryObjects(app, objid);
+ else
+ queryFunctions( app, objid );
+ break;
+ case 3:
+ default:
+ if( readStdin )
+ {
+ QCStringList::Iterator replaceArg = args.end();
+
+ QCStringList::Iterator it;
+ for( it = args.begin(); it != args.end(); it++ )
+ if( *it == "%1" )
+ replaceArg = it;
+
+ // Read from stdin until EOF and call function for each line read
+ char *buf = new char[ 1000 ];
+ while ( !feof( stdin ) )
+ {
+ fgets( buf, 1000, stdin );
+
+ if( replaceArg != args.end() )
+ *replaceArg = buf;
+
+ callFunction( app, objid, function, params );
+ }
+ }
+ else
+ {
+ // Just call function
+// cout << "call " << app << ", " << objid << ", " << function << ", (params)" << endl;
+ callFunction( app, objid, function, params );
+ }
+ break;
+ }
+ // Another sIt++ would make the loop infinite...
+ if( users.isEmpty() )
+ break;
+ }
+
+ // Another it++ would make the loop infinite...
+ if( it == users.end() )
+ break;
+.
+308,338c
+ if( !args.isEmpty() )
+ app = args[ 0 ];
+ if( args.count() > 1 )
+ objid = args[ 1 ];
+ if( args.count() > 2 )
+ function = args[ 2 ];
+ if( args.count() > 3)
+ {
+ params = args;
+ params.remove( params.begin() );
+ params.remove( params.begin() );
+ params.remove( params.begin() );
+ }
+ }
+
+ bool firstRun = true;
+ UserList::Iterator it;
+ QStringList sessions;
+ bool presetDCOPServer = false;
+// char *dcopStr = 0L;
+ QString dcopServer;
+
+ for( it = users.begin(); it != users.end() || firstRun; it++ )
+ {
+ firstRun = false;
+
+ //cout << "Iterating '" << it.key() << "'" << endl;
+
+ if( session == QuerySessions )
+ {
+ QStringList sessions = dcopSessionList( it.key(), it.data() );
+ if( sessions.isEmpty() )
+ {
+ cout << "No active sessions";
+ if( !( *it ).isEmpty() )
+ cout << " for user " << *it;
+ cout << endl;
+ }
+ else
+ {
+ cout << "Active sessions ";
+ if( !( *it ).isEmpty() )
+ cout << "for user " << *it << " ";
+ cout << ":" << endl;
+
+ QStringList::Iterator sIt;
+ for( sIt = sessions.begin(); sIt != sessions.end(); sIt++ )
+ cout << " " << *sIt << endl;
+
+ cout << endl;
+ }
+ continue;
+ }
+
+ if( getenv( "DCOPSERVER" ) )
+ {
+ sessions.append( getenv( "DCOPSERVER" ) );
+ presetDCOPServer = true;
+ }
+
+ if( users.count() > 1 || ( users.count() == 1 &&
+ ( getenv( "DCOPSERVER" ) == 0 /*&& getenv( "DISPLAY" ) == 0*/ ) ) )
+ {
+ sessions = dcopSessionList( it.key(), it.data() );
+ if( sessions.isEmpty() )
+ {
+ if( users.count() > 1 )
+ continue;
+ else
+ {
+ cerr << "ERROR: No active KDE sessions!" << endl
+ << "If you are sure there is one, please set the $DCOPSERVER variable manually" << endl
+ << "before calling dcop." << endl;
+ exit( -1 );
+ }
+ }
+ else if( sessions.count() > 1 && session != AllSessions )
+ {
+ cerr << "ERROR: Multiple available KDE sessions!" << endl
+ << "Please specify the correct session to use with --session or use the" << endl
+ << "--all-sessions option to broadcast to all sessions." << endl;
+ exit( -1 );
+ }
+ }
+.
+289,304c
+ // WARNING: This part (until the closing '}') could very
+ // well be broken now. As I don't know how to trigger and test
+ // dcoprefs this code is *not* tested. It compiles and it looks
+ // ok to me, but that's all I can say - Martijn (2001/12/24)
+ int delimPos = args[ 0 ].findRev( ',' );
+ if( delimPos == -1 )
+ {
+ cerr << "Error: '" << args[ 0 ]
+ << "' is not a valid DCOP reference." << endl;
+ exit( -1 );
+ }
+ args[ 0 ][ delimPos ] = 0;
+ app = args[ 0 ].mid( 8 );
+ delimPos++;
+ args[ 0 ][ args[ 0 ].length() - 1 ] = 0;
+ objid = args[ 0 ].mid( delimPos );
+ if( args.count() > 1 )
+ function = args[ 1 ];
+ if( args.count() > 2 )
+ {
+ params = args;
+ params.remove( params.begin() );
+ params.remove( params.begin() );
+ }
+.
+286,287c
+ QCStringList params;
+ DCOPClient *client = 0L;
+ if ( !args.isEmpty() && args[ 0 ].find( "DCOPRef(" ) == 0 )
+.
+282a
+/**
+ * Do the actual DCOP call
+ */
+void runDCOP( QCStringList args, UserList users, Session session,
+ const QString sessionName, bool readStdin )
+{
+.
+279,281c
+ return result;
+}
+
+/**
+ * Return a list of available DCOP sessions for the specified user
+ * An empty list means no sessions are available, or an error occurred.
+ */
+QStringList dcopSessionList( const QString &user, const QString &home )
+{
+ if( home.isEmpty() )
+ {
+ cerr << "WARNING: Cannot determine home directory for user "
+ << user << "!" << endl
+ << "Please check permissions or set the $DCOPSERVER variable manually before" << endl
+ << "calling dcop." << endl;
+ return QStringList();
+ }
+
+ QStringList result;
+ QFileInfo dirInfo( home );
+ if( !dirInfo.exists() || !dirInfo.isReadable() )
+ return result;
+
+ QDir d( home );
+ d.setFilter( QDir::Files | QDir::Hidden | QDir::NoSymLinks );
+ d.setNameFilter( ".DCOPserver*" );
+
+ const QFileInfoList *list = d.entryInfoList();
+ if( !list )
+ return result;
+
+ QFileInfoListIterator it( *list );
+ QFileInfo *fi;
+
+ while ( ( fi = it.current() ) != 0 )
+ {
+ if( fi->isReadable() )
+ result.append( fi->fileName() );
+ ++it;
+ }
+ return result;
+}
+.
+274,276c
+ QStringList l( QStringList::split( '\n', f.readAll() ) );
+
+ for( QStringList::ConstIterator it( l.begin() ); it != l.end(); ++it )
+ {
+ QStringList userInfo( QStringList::split( ':', *it, true ) );
+ result[ userInfo[ 0 ] ] = userInfo[ 5 ];
+.
+272a
+ UserList result;
+
+ QFile f( "/etc/passwd" );
+
+ if( !f.open( IO_ReadOnly ) )
+ {
+ cerr << "Can't open /etc/passwd for reading!" << endl;
+ return result;
+ }
+.
+270,271c
+/**
+ * Return a list of all users and their home directories.
+ * Returns an empty list if /etc/passwd cannot be read for some reason.
+ */
+static UserList userList()
+.
+268a
+/**
+ * Show command-line help and exit
+ */
+void showHelp( int exitCode = 0 )
+{
+ cout << "Usage: dcop [options] [application [object [function [arg1] [arg2] ... ] ] ]" << endl
+ << "" << endl
+ << "Console DCOP client" << endl
+ << "" << endl
+ << "Generic options:" << endl
+ << " --help Show help about options" << endl
+ << "" << endl
+ << "Options:" << endl
+ << " --pipe Call DCOP for each line read from stdin" << endl
+ << " --user <user> Connect to the given user's DCOP server. This option will" << endl
+ << " ignore the values of the environment vars $DCOPSERVER and" << endl
+ << " $ICEAUTHORITY, even if they are set." << endl
+ << " If the user has more than one open session, you must also" << endl
+ << " use one of the --list-sessions, --session or --als-sessions" << endl
+ << " command-line options." << endl
+ << " --all-users Send the same DCOP call to all users with a running DCOP" << endl
+ << " server. Only failed calls to existing DCOP servers will"
+ << " generate an error message. If no DCOP server is available" << endl
+ << " at all, no error will be generated." << endl;
+
+ exit( exitCode );
+}
+.
+246,250c
+ uint i = 0;
+ for( QStringList::Iterator it = types.begin(); it != types.end(); ++it )
+ marshall( arg, args, i, *it );
+
+ if ( i != args.count() )
+ {
+.
+164c
+// exit(1);
+ return;
+.
+156,157c
+ uint a = (*it).contains(',');
+ if ( ( a == 0 && args.isEmpty() ) || ( a > 0 && a + 1 == args.count() ) )
+.
+139c
+ if ( !ok && args.isEmpty() )
+.
+123d
+121c
+void callFunction( const char* app, const char* obj, const char* func, const QCStringList args )
+.
+35a
+static QTextStream cout( stdout, IO_WriteOnly );
+static QTextStream cerr( stderr, IO_WriteOnly );
+
+/**
+ * Session to send call to
+ * DefaultSession - current session. Current KDE session when called without
+ * --user or --all-users option. Otherwise this value ignores
+ * all users with more than one active session.
+ * AllSessions - Send to all sessions found. requires --user or --all-users.
+ * QuerySessions - Don't call DCOP, return a list of available sessions.
+ * CustomSession - Use the specified session
+ */
+enum Session { DefaultSession = 0, AllSessions, QuerySessions, CustomSession };
+
+.
+33a
+typedef QMap<QString, QString> UserList;
+
+.
+28,30c
+#include "../kdatastream.h"
+.
+25c
+#include <qdir.h>
+#include <qfile.h>
+#include <qfileinfo.h>
+#include <qmap.h>
+#include <qstringlist.h>
+#include <qtextstream.h>
+#include <qvariant.h>
+
+// putenv() is not available on all platforms, so make sure the emulation
+// wrapper is available in those cases by loading config.h!
+#include <config.h>
+
+.
+23c
+#include <ctype.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+.
+diff -er dcop/client/dcopfind.cpp dcop2/client/dcopfind.cpp
+224c
+ QCStringList params;
+ for( int i = 0; i < argc; i++ )
+ params.append( args[ i ] );
+
+ findObject( app, objid, function, params );
+.
+133c
+ if ( (uint) i != args.count() ) {
+.
+131c
+ marshall(arg, args, i, *it);
+.
+121c
+ if ( types.count() != args.count() ) {
+.
+39c
+bool findObject( const char* app, const char* obj, const char* func, QCStringList args )
+.
+diff -er dcop/client/marshall.cpp dcop2/client/marshall.cpp
+347a
+ QByteArray dummy_data;
+ QDataStream dummy_arg(dummy_data, IO_WriteOnly);
+
+ uint j = i;
+ uint count = 0;
+ // Parse list to get the count
+ while (true) {
+ if( j > args.count() )
+ {
+ qWarning("List end-delimiter '%s' not found.", delim.latin1());
+ exit(1);
+ }
+ if( QString::fromLocal8Bit( args[ j ] ) == delim )
+ break;
+ marshall( dummy_arg, args, j, type );
+ count++;
+ }
+ arg << (Q_UINT32) count;
+ // Parse the list for real
+ while (true) {
+ if( i > args.count() )
+ {
+ qWarning("List end-delimiter '%s' not found.", delim.latin1());
+ exit(1);
+ }
+ if( QString::fromLocal8Bit( args[ i ] ) == delim )
+ break;
+ marshall( arg, args, i, type );
+ }
+ } else {
+ qWarning( "cannot handle datatype '%s'", type.latin1() );
+ exit(1);
+ }
+ i++;
+.
+319,346c
+ if ( type == "int" )
+ arg << s.toInt();
+ else if ( type == "uint" )
+ arg << s.toUInt();
+ else if ( type == "unsigned" )
+ arg << s.toUInt();
+ else if ( type == "unsigned int" )
+ arg << s.toUInt();
+ else if ( type == "long" )
+ arg << s.toLong();
+ else if ( type == "long int" )
+ arg << s.toLong();
+ else if ( type == "unsigned long" )
+ arg << s.toULong();
+ else if ( type == "unsigned long int" )
+ arg << s.toULong();
+ else if ( type == "float" )
+ arg << s.toFloat();
+ else if ( type == "double" )
+ arg << s.toDouble();
+ else if ( type == "bool" )
+ arg << mkBool( s );
+ else if ( type == "QString" )
+ arg << s;
+ else if ( type == "QCString" )
+ arg << QCString( args[ i ] );
+ else if ( type == "QColor" )
+ arg << mkColor( s );
+ else if ( type == "QPoint" )
+ arg << mkPoint( s );
+ else if ( type == "QSize" )
+ arg << mkSize( s );
+ else if ( type == "QRect" )
+ arg << mkRect( s );
+ else if ( type == "QVariant" ) {
+ if ( s == "true" || s == "false" )
+ arg << QVariant( mkBool( s ), 42 );
+ else if ( s.left( 4 ) == "int(" )
+ arg << QVariant( s.mid(4, s.length()-5).toInt() );
+ else if ( s.left( 7 ) == "QPoint(" )
+ arg << QVariant( mkPoint( s.mid(7, s.length()-8) ) );
+ else if ( s.left( 6 ) == "QSize(" )
+ arg << QVariant( mkSize( s.mid(6, s.length()-7) ) );
+ else if ( s.left( 6 ) == "QRect(" )
+ arg << QVariant( mkRect( s.mid(6, s.length()-7) ) );
+ else if ( s.left( 7 ) == "QColor(" )
+ arg << QVariant( mkColor( s.mid(7, s.length()-8) ) );
+ else
+ arg << QVariant( s );
+ } else if ( type.startsWith("QValueList<")) {
+ type = type.mid(11, type.length() - 12);
+ QStringList list;
+ QString delim = s;
+ if (delim == "[")
+ delim = "]";
+ if (delim == "(")
+ delim = ")";
+.
+247,317c
+ if (type == "QStringList")
+ type = "QValueList<QString>";
+ if (type == "QCStringList")
+ type = "QValueList<QCString>";
+ if( i > args.count() )
+ {
+ qWarning("Not enough arguments.");
+ exit(1);
+ }
+ QString s = QString::fromLocal8Bit( args[ i ] );
+.
+245c
+void marshall( QDataStream &arg, QCStringList args, uint &i, QString type )
+.
diff --git a/kompare/tests/diff/normal.diff b/kompare/tests/diff/normal.diff
new file mode 100644
index 00000000..6f82a1c4
--- /dev/null
+++ b/kompare/tests/diff/normal.diff
@@ -0,0 +1,12 @@
+1,2d0
+< The Way that can be told of is not the eternal Way;
+< The name that can be named is not the eternal name.
+4c2,3
+< The Named is the mother of all things.
+---
+> The named is the mother of all things.
+>
+11a11,13
+> They both may be called deep and profound.
+> Deeper and more profound,
+> The door of all subtleties!
diff --git a/kompare/tests/diff/normalm.diff b/kompare/tests/diff/normalm.diff
new file mode 100644
index 00000000..3db667ba
--- /dev/null
+++ b/kompare/tests/diff/normalm.diff
@@ -0,0 +1,849 @@
+diff -r dcop/client/dcop.cpp dcop2/client/dcop.cpp
+23c23,26
+< #include <qvariant.h>
+---
+> #include <ctype.h>
+> #include <stdio.h>
+> #include <stdlib.h>
+>
+25c28,39
+< #include "../kdatastream.h"
+---
+> #include <qdir.h>
+> #include <qfile.h>
+> #include <qfileinfo.h>
+> #include <qmap.h>
+> #include <qstringlist.h>
+> #include <qtextstream.h>
+> #include <qvariant.h>
+>
+> // putenv() is not available on all platforms, so make sure the emulation
+> // wrapper is available in those cases by loading config.h!
+> #include <config.h>
+>
+28,30c42
+< #include <stdlib.h>
+< #include <stdio.h>
+< #include <ctype.h>
+---
+> #include "../kdatastream.h"
+33a46,47
+> typedef QMap<QString, QString> UserList;
+>
+35a50,63
+> static QTextStream cout( stdout, IO_WriteOnly );
+> static QTextStream cerr( stderr, IO_WriteOnly );
+>
+> /**
+> * Session to send call to
+> * DefaultSession - current session. Current KDE session when called without
+> * --user or --all-users option. Otherwise this value ignores
+> * all users with more than one active session.
+> * AllSessions - Send to all sessions found. requires --user or --all-users.
+> * QuerySessions - Don't call DCOP, return a list of available sessions.
+> * CustomSession - Use the specified session
+> */
+> enum Session { DefaultSession = 0, AllSessions, QuerySessions, CustomSession };
+>
+121c149
+< void callFunction( const char* app, const char* obj, const char* func, int argc, char** args )
+---
+> void callFunction( const char* app, const char* obj, const char* func, const QCStringList args )
+123d150
+<
+139c166
+< if ( !ok && argc == 0 )
+---
+> if ( !ok && args.isEmpty() )
+156,157c183,184
+< int a = (*it).contains(',');
+< if ( ( a == 0 && argc == 0) || ( a > 0 && a + 1 == argc ) )
+---
+> uint a = (*it).contains(',');
+> if ( ( a == 0 && args.isEmpty() ) || ( a > 0 && a + 1 == args.count() ) )
+164c191,192
+< exit(1);
+---
+> // exit(1);
+> return;
+246,250c274,279
+< int i = 0;
+< for ( QStringList::Iterator it = types.begin(); it != types.end(); ++it ) {
+< marshall(arg, argc, args, i, *it);
+< }
+< if ( i != argc ) {
+---
+> uint i = 0;
+> for( QStringList::Iterator it = types.begin(); it != types.end(); ++it )
+> marshall( arg, args, i, *it );
+>
+> if ( i != args.count() )
+> {
+268a298,324
+> /**
+> * Show command-line help and exit
+> */
+> void showHelp( int exitCode = 0 )
+> {
+> cout << "Usage: dcop [options] [application [object [function [arg1] [arg2] ... ] ] ]" << endl
+> << "" << endl
+> << "Console DCOP client" << endl
+> << "" << endl
+> << "Generic options:" << endl
+> << " --help Show help about options" << endl
+> << "" << endl
+> << "Options:" << endl
+> << " --pipe Call DCOP for each line read from stdin" << endl
+> << " --user <user> Connect to the given user's DCOP server. This option will" << endl
+> << " ignore the values of the environment vars $DCOPSERVER and" << endl
+> << " $ICEAUTHORITY, even if they are set." << endl
+> << " If the user has more than one open session, you must also" << endl
+> << " use one of the --list-sessions, --session or --als-sessions" << endl
+> << " command-line options." << endl
+> << " --all-users Send the same DCOP call to all users with a running DCOP" << endl
+> << " server. Only failed calls to existing DCOP servers will"
+> << " generate an error message. If no DCOP server is available" << endl
+> << " at all, no error will be generated." << endl;
+>
+> exit( exitCode );
+> }
+270,271c326,330
+<
+< int main( int argc, char** argv )
+---
+> /**
+> * Return a list of all users and their home directories.
+> * Returns an empty list if /etc/passwd cannot be read for some reason.
+> */
+> static UserList userList()
+272a332,340
+> UserList result;
+>
+> QFile f( "/etc/passwd" );
+>
+> if( !f.open( IO_ReadOnly ) )
+> {
+> cerr << "Can't open /etc/passwd for reading!" << endl;
+> return result;
+> }
+274,276c342,347
+< if ( argc > 1 && argv[1][0] == '-' ) {
+< fprintf( stderr, "Usage: dcop [ application [object [function [arg1] [arg2] [arg3] ... ] ] ] \n" );
+< exit(0);
+---
+> QStringList l( QStringList::split( '\n', f.readAll() ) );
+>
+> for( QStringList::ConstIterator it( l.begin() ); it != l.end(); ++it )
+> {
+> QStringList userInfo( QStringList::split( ':', *it, true ) );
+> result[ userInfo[ 0 ] ] = userInfo[ 5 ];
+279,281c350,391
+< DCOPClient client;
+< client.attach();
+< dcop = &client;
+---
+> return result;
+> }
+>
+> /**
+> * Return a list of available DCOP sessions for the specified user
+> * An empty list means no sessions are available, or an error occurred.
+> */
+> QStringList dcopSessionList( const QString &user, const QString &home )
+> {
+> if( home.isEmpty() )
+> {
+> cerr << "WARNING: Cannot determine home directory for user "
+> << user << "!" << endl
+> << "Please check permissions or set the $DCOPSERVER variable manually before" << endl
+> << "calling dcop." << endl;
+> return QStringList();
+> }
+>
+> QStringList result;
+> QFileInfo dirInfo( home );
+> if( !dirInfo.exists() || !dirInfo.isReadable() )
+> return result;
+>
+> QDir d( home );
+> d.setFilter( QDir::Files | QDir::Hidden | QDir::NoSymLinks );
+> d.setNameFilter( ".DCOPserver*" );
+>
+> const QFileInfoList *list = d.entryInfoList();
+> if( !list )
+> return result;
+>
+> QFileInfoListIterator it( *list );
+> QFileInfo *fi;
+>
+> while ( ( fi = it.current() ) != 0 )
+> {
+> if( fi->isReadable() )
+> result.append( fi->fileName() );
+> ++it;
+> }
+> return result;
+> }
+282a393,398
+> /**
+> * Do the actual DCOP call
+> */
+> void runDCOP( QCStringList args, UserList users, Session session,
+> const QString sessionName, bool readStdin )
+> {
+286,287c402,404
+< char **args = 0;
+< if ((argc > 1) && (strncmp(argv[1], "DCOPRef(", 8)) == 0)
+---
+> QCStringList params;
+> DCOPClient *client = 0L;
+> if ( !args.isEmpty() && args[ 0 ].find( "DCOPRef(" ) == 0 )
+289,304c406,429
+< char *delim = strchr(argv[1], ',');
+< if (!delim)
+< {
+< fprintf(stderr, "Error: '%s' is not a valid DCOP reference.\n", argv[1]);
+< return 1;
+< }
+< *delim = 0;
+< app = argv[1] + 8;
+< delim++;
+< delim[strlen(delim)-1] = 0;
+< objid = delim;
+< if (argc > 2)
+< function = argv[2];
+< if (argc > 3)
+< args = &argv[3];
+< argc++;
+---
+> // WARNING: This part (until the closing '}') could very
+> // well be broken now. As I don't know how to trigger and test
+> // dcoprefs this code is *not* tested. It compiles and it looks
+> // ok to me, but that's all I can say - Martijn (2001/12/24)
+> int delimPos = args[ 0 ].findRev( ',' );
+> if( delimPos == -1 )
+> {
+> cerr << "Error: '" << args[ 0 ]
+> << "' is not a valid DCOP reference." << endl;
+> exit( -1 );
+> }
+> args[ 0 ][ delimPos ] = 0;
+> app = args[ 0 ].mid( 8 );
+> delimPos++;
+> args[ 0 ][ args[ 0 ].length() - 1 ] = 0;
+> objid = args[ 0 ].mid( delimPos );
+> if( args.count() > 1 )
+> function = args[ 1 ];
+> if( args.count() > 2 )
+> {
+> params = args;
+> params.remove( params.begin() );
+> params.remove( params.begin() );
+> }
+308,338c433,516
+< if (argc > 1)
+< app = argv[1];
+< if (argc > 2)
+< objid = argv[2];
+< if (argc > 3)
+< function = argv[3];
+< if (argc > 4)
+< args = &argv[4];
+< }
+<
+< switch ( argc ) {
+< case 0:
+< case 1:
+< queryApplications("");
+< break;
+< case 2:
+< if (endsWith(app, '*'))
+< queryApplications(app);
+< else
+< queryObjects( app, "" );
+< break;
+< case 3:
+< if (endsWith(objid, '*'))
+< queryObjects(app, objid);
+< else
+< queryFunctions( app, objid );
+< break;
+< case 4:
+< default:
+< callFunction( app, objid, function, argc - 4, args );
+< break;
+---
+> if( !args.isEmpty() )
+> app = args[ 0 ];
+> if( args.count() > 1 )
+> objid = args[ 1 ];
+> if( args.count() > 2 )
+> function = args[ 2 ];
+> if( args.count() > 3)
+> {
+> params = args;
+> params.remove( params.begin() );
+> params.remove( params.begin() );
+> params.remove( params.begin() );
+> }
+> }
+>
+> bool firstRun = true;
+> UserList::Iterator it;
+> QStringList sessions;
+> bool presetDCOPServer = false;
+> // char *dcopStr = 0L;
+> QString dcopServer;
+>
+> for( it = users.begin(); it != users.end() || firstRun; it++ )
+> {
+> firstRun = false;
+>
+> //cout << "Iterating '" << it.key() << "'" << endl;
+>
+> if( session == QuerySessions )
+> {
+> QStringList sessions = dcopSessionList( it.key(), it.data() );
+> if( sessions.isEmpty() )
+> {
+> cout << "No active sessions";
+> if( !( *it ).isEmpty() )
+> cout << " for user " << *it;
+> cout << endl;
+> }
+> else
+> {
+> cout << "Active sessions ";
+> if( !( *it ).isEmpty() )
+> cout << "for user " << *it << " ";
+> cout << ":" << endl;
+>
+> QStringList::Iterator sIt;
+> for( sIt = sessions.begin(); sIt != sessions.end(); sIt++ )
+> cout << " " << *sIt << endl;
+>
+> cout << endl;
+> }
+> continue;
+> }
+>
+> if( getenv( "DCOPSERVER" ) )
+> {
+> sessions.append( getenv( "DCOPSERVER" ) );
+> presetDCOPServer = true;
+> }
+>
+> if( users.count() > 1 || ( users.count() == 1 &&
+> ( getenv( "DCOPSERVER" ) == 0 /*&& getenv( "DISPLAY" ) == 0*/ ) ) )
+> {
+> sessions = dcopSessionList( it.key(), it.data() );
+> if( sessions.isEmpty() )
+> {
+> if( users.count() > 1 )
+> continue;
+> else
+> {
+> cerr << "ERROR: No active KDE sessions!" << endl
+> << "If you are sure there is one, please set the $DCOPSERVER variable manually" << endl
+> << "before calling dcop." << endl;
+> exit( -1 );
+> }
+> }
+> else if( sessions.count() > 1 && session != AllSessions )
+> {
+> cerr << "ERROR: Multiple available KDE sessions!" << endl
+> << "Please specify the correct session to use with --session or use the" << endl
+> << "--all-sessions option to broadcast to all sessions." << endl;
+> exit( -1 );
+> }
+> }
+339a518,660
+> if( users.count() > 1 || ( users.count() == 1 &&
+> ( getenv( "ICEAUTHORITY" ) == 0 || getenv( "DISPLAY" ) == 0 ) ) )
+> {
+> // Check for ICE authority file and if the file can be read by us
+> QString home = it.data();
+> QString iceFile = it.data() + "/.ICEauthority";
+> QFileInfo fi( iceFile );
+> if( iceFile.isEmpty() )
+> {
+> cerr << "WARNING: Cannot determine home directory for user "
+> << it.key() << "!" << endl
+> << "Please check permissions or set the $ICEAUTHORITY variable manually before" << endl
+> << "calling dcop." << endl;
+> }
+> else if( fi.exists() )
+> {
+> if( fi.isReadable() )
+> {
+> char *envStr = strdup( ( "ICEAUTHORITY=" + iceFile ).ascii() );
+> putenv( envStr );
+> //cerr << "ice: " << envStr << endl;
+> }
+> else
+> {
+> cerr << "WARNING: ICE authority file " << iceFile
+> << "is not readable by you!" << endl
+> << "Please check permissions or set the $ICEAUTHORITY variable manually before" << endl
+> << "calling dcop." << endl;
+> }
+> }
+> else
+> {
+> if( users.count() > 1 )
+> continue;
+> else
+> {
+> cerr << "WARNING: Cannot find ICE authority file "
+> << iceFile << "!" << endl
+> << "Please check permissions or set the $ICEAUTHORITY"
+> << " variable manually before" << endl
+> << "calling dcop." << endl;
+> }
+> }
+> }
+>
+> // Main loop
+> // If users is an empty list we're calling for the currently logged
+> // in user. In this case we don't have a session, but still want
+> // to iterate the loop once.
+> QStringList::Iterator sIt = sessions.begin();
+> for( ; sIt != sessions.end() || users.isEmpty(); sIt++ )
+> {
+> if( !presetDCOPServer && !users.isEmpty() )
+> {
+> QString dcopFile = it.data() + "/" + *sIt;
+> QFile f( dcopFile );
+> if( !f.open( IO_ReadOnly ) )
+> {
+> cerr << "Can't open " << dcopFile << " for reading!" << endl;
+> exit( -1 );
+> }
+>
+> QStringList l( QStringList::split( '\n', f.readAll() ) );
+> dcopServer = l.first();
+>
+> if( dcopServer.isEmpty() )
+> {
+> cerr << "WARNING: Unable to determine DCOP server for session "
+> << *sIt << "!" << endl
+> << "Please check permissions or set the $DCOPSERVER variable manually before" << endl
+> << "calling dcop." << endl;
+> exit( -1 );
+> }
+> }
+>
+> delete client;
+> client = new DCOPClient;
+> if( !dcopServer.isEmpty() )
+> client->setServerAddress( dcopServer.ascii() );
+> bool success = client->attach();
+> if( !success )
+> {
+> cerr << "ERROR: Couldn't attach to DCOP server!" << endl;
+> continue;
+> }
+> dcop = client;
+>
+> switch ( args.count() )
+> {
+> case 0:
+> queryApplications("");
+> break;
+> case 1:
+> if (endsWith(app, '*'))
+> queryApplications(app);
+> else
+> queryObjects( app, "" );
+> break;
+> case 2:
+> if (endsWith(objid, '*'))
+> queryObjects(app, objid);
+> else
+> queryFunctions( app, objid );
+> break;
+> case 3:
+> default:
+> if( readStdin )
+> {
+> QCStringList::Iterator replaceArg = args.end();
+>
+> QCStringList::Iterator it;
+> for( it = args.begin(); it != args.end(); it++ )
+> if( *it == "%1" )
+> replaceArg = it;
+>
+> // Read from stdin until EOF and call function for each line read
+> char *buf = new char[ 1000 ];
+> while ( !feof( stdin ) )
+> {
+> fgets( buf, 1000, stdin );
+>
+> if( replaceArg != args.end() )
+> *replaceArg = buf;
+>
+> callFunction( app, objid, function, params );
+> }
+> }
+> else
+> {
+> // Just call function
+> // cout << "call " << app << ", " << objid << ", " << function << ", (params)" << endl;
+> callFunction( app, objid, function, params );
+> }
+> break;
+> }
+> // Another sIt++ would make the loop infinite...
+> if( users.isEmpty() )
+> break;
+> }
+>
+> // Another it++ would make the loop infinite...
+> if( it == users.end() )
+> break;
+340a662,767
+> }
+>
+>
+> int main( int argc, char** argv )
+> {
+> bool readStdin = false;
+> int numOptions = 0;
+> QString user;
+> Session session = DefaultSession;
+> QString sessionName;
+>
+> // Scan for command-line options first
+> for( int pos = 1 ; pos <= argc - 1 ; pos++ )
+> {
+> if( strcmp( argv[ pos ], "--help" ) == 0 )
+> showHelp( 0 );
+> else if( strcmp( argv[ pos ], "--pipe" ) == 0 )
+> {
+> readStdin = true;
+> numOptions++;
+> }
+> else if( strcmp( argv[ pos ], "--user" ) == 0 )
+> {
+> if( pos <= argc - 2 )
+> {
+> user = QString::fromLocal8Bit( argv[ pos + 1] );
+> numOptions +=2;
+> pos++;
+> }
+> else
+> {
+> cerr << "Missing username for '--user' option!" << endl << endl;
+> showHelp( -1 );
+> }
+> }
+> else if( strcmp( argv[ pos ], "--all-users" ) == 0 )
+> {
+> user = "*";
+> numOptions ++;
+> }
+> else if( strcmp( argv[ pos ], "--list-sessions" ) == 0 )
+> {
+> session = QuerySessions;
+> numOptions ++;
+> }
+> else if( strcmp( argv[ pos ], "--all-sessions" ) == 0 )
+> {
+> session = AllSessions;
+> numOptions ++;
+> }
+> else if( argv[ pos ][ 0 ] == '-' )
+> {
+> cerr << "Unknown command-line option '" << argv[ pos ]
+> << "'." << endl << endl;
+> showHelp( -1 );
+> }
+> else
+> break; // End of options
+> }
+>
+> argc -= numOptions;
+>
+> QCStringList args;
+> for( int i = numOptions; i < argc + numOptions - 1; i++ )
+> args.append( argv[ i + 1 ] );
+>
+> if( readStdin && args.count() < 3 )
+> {
+> cerr << "--pipe option only supported for function calls!" << endl << endl;
+> showHelp( -1 );
+> }
+>
+> if( user == "*" && args.count() < 3 && session != QuerySessions )
+> {
+> cerr << "ERROR: The --all-users option is only supported for function calls!" << endl << endl;
+> showHelp( -1 );
+> }
+>
+> if( session == QuerySessions && !args.isEmpty() )
+> {
+> cerr << "ERROR: The --list-sessions option cannot be used for actual DCOP calls!" << endl << endl;
+> showHelp( -1 );
+> }
+>
+> if( session == QuerySessions && user.isEmpty() )
+> {
+> cerr << "ERROR: The --list-sessions option can only be used with the --user or" << endl
+> << "--all-users options!" << endl << endl;
+> showHelp( -1 );
+> }
+>
+> if( session != DefaultSession && session != QuerySessions &&
+> args.count() < 3 )
+> {
+> cerr << "ERROR: The --session and --all-sessions options are only supported for function" << endl
+> << "calls!" << endl << endl;
+> showHelp( -1 );
+> }
+>
+> UserList users;
+> if( user == "*" )
+> users = userList();
+> else if( !user.isEmpty() )
+> users[ user ] = userList()[ user ];
+>
+> runDCOP( args, users, session, sessionName, readStdin );
+343a771,773
+>
+> // vim: set ts=8 sts=4 sw=4 noet:
+>
+diff -r dcop/client/dcopfind.cpp dcop2/client/dcopfind.cpp
+39c39
+< bool findObject( const char* app, const char* obj, const char* func, int argc, char** args )
+---
+> bool findObject( const char* app, const char* obj, const char* func, QCStringList args )
+121c121
+< if ( (int) types.count() != argc ) {
+---
+> if ( types.count() != args.count() ) {
+131c131
+< marshall(arg, argc, args, i, *it);
+---
+> marshall(arg, args, i, *it);
+133c133
+< if ( (int) i != argc ) {
+---
+> if ( (uint) i != args.count() ) {
+224c224,228
+< findObject( app, objid, function, argc, args );
+---
+> QCStringList params;
+> for( int i = 0; i < argc; i++ )
+> params.append( args[ i ] );
+>
+> findObject( app, objid, function, params );
+diff -r dcop/client/marshall.cpp dcop2/client/marshall.cpp
+245c245
+< void marshall(QDataStream &arg, int argc, char **argv, int &i, QString type)
+---
+> void marshall( QDataStream &arg, QCStringList args, uint &i, QString type )
+247,317c247,256
+< if (type == "QStringList")
+< type = "QValueList<QString>";
+< if (type == "QCStringList")
+< type = "QValueList<QCString>";
+< if (i >= argc)
+< {
+< qWarning("Not enough arguments.");
+< exit(1);
+< }
+< QString s = QString::fromLocal8Bit(argv[i]);
+<
+< if ( type == "int" )
+< arg << s.toInt();
+< else if ( type == "uint" )
+< arg << s.toUInt();
+< else if ( type == "unsigned" )
+< arg << s.toUInt();
+< else if ( type == "unsigned int" )
+< arg << s.toUInt();
+< else if ( type == "long" )
+< arg << s.toLong();
+< else if ( type == "long int" )
+< arg << s.toLong();
+< else if ( type == "unsigned long" )
+< arg << s.toULong();
+< else if ( type == "unsigned long int" )
+< arg << s.toULong();
+< else if ( type == "float" )
+< arg << s.toFloat();
+< else if ( type == "double" )
+< arg << s.toDouble();
+< else if ( type == "bool" )
+< arg << mkBool( s );
+< else if ( type == "QString" )
+< arg << s;
+< else if ( type == "QCString" )
+< arg << QCString( argv[i] );
+< else if ( type == "QColor" )
+< arg << mkColor( s );
+< else if ( type == "QPoint" )
+< arg << mkPoint( s );
+< else if ( type == "QSize" )
+< arg << mkSize( s );
+< else if ( type == "QRect" )
+< arg << mkRect( s );
+< else if ( type == "QVariant" ) {
+< if ( s == "true" || s == "false" )
+< arg << QVariant( mkBool( s ), 42 );
+< else if ( s.left( 4 ) == "int(" )
+< arg << QVariant( s.mid(4, s.length()-5).toInt() );
+< else if ( s.left( 7 ) == "QPoint(" )
+< arg << QVariant( mkPoint( s.mid(7, s.length()-8) ) );
+< else if ( s.left( 6 ) == "QSize(" )
+< arg << QVariant( mkSize( s.mid(6, s.length()-7) ) );
+< else if ( s.left( 6 ) == "QRect(" )
+< arg << QVariant( mkRect( s.mid(6, s.length()-7) ) );
+< else if ( s.left( 7 ) == "QColor(" )
+< arg << QVariant( mkColor( s.mid(7, s.length()-8) ) );
+< else
+< arg << QVariant( s );
+< } else if ( type.startsWith("QValueList<")) {
+< type = type.mid(11, type.length() - 12);
+< QStringList list;
+< QString delim = s;
+< if (delim == "[")
+< delim = "]";
+< if (delim == "(")
+< delim = ")";
+< i++;
+< QByteArray dummy_data;
+< QDataStream dummy_arg(dummy_data, IO_WriteOnly);
+---
+> if (type == "QStringList")
+> type = "QValueList<QString>";
+> if (type == "QCStringList")
+> type = "QValueList<QCString>";
+> if( i > args.count() )
+> {
+> qWarning("Not enough arguments.");
+> exit(1);
+> }
+> QString s = QString::fromLocal8Bit( args[ i ] );
+319,346c258,314
+< int j = i;
+< int count = 0;
+< // Parse list to get the count
+< while (true) {
+< if (j >= argc)
+< {
+< qWarning("List end-delimiter '%s' not found.", delim.latin1());
+< exit(1);
+< }
+< if (argv[j] == delim) break;
+< marshall(dummy_arg, argc, argv, j, type);
+< count++;
+< }
+< arg << (Q_UINT32) count;
+< // Parse the list for real
+< while (true) {
+< if (i >= argc)
+< {
+< qWarning("List end-delimiter '%s' not found.", delim.latin1());
+< exit(1);
+< }
+< if (argv[i] == delim) break;
+< marshall(arg, argc, argv, i, type);
+< }
+< } else {
+< qWarning( "cannot handle datatype '%s'", type.latin1() );
+< exit(1);
+< }
+---
+> if ( type == "int" )
+> arg << s.toInt();
+> else if ( type == "uint" )
+> arg << s.toUInt();
+> else if ( type == "unsigned" )
+> arg << s.toUInt();
+> else if ( type == "unsigned int" )
+> arg << s.toUInt();
+> else if ( type == "long" )
+> arg << s.toLong();
+> else if ( type == "long int" )
+> arg << s.toLong();
+> else if ( type == "unsigned long" )
+> arg << s.toULong();
+> else if ( type == "unsigned long int" )
+> arg << s.toULong();
+> else if ( type == "float" )
+> arg << s.toFloat();
+> else if ( type == "double" )
+> arg << s.toDouble();
+> else if ( type == "bool" )
+> arg << mkBool( s );
+> else if ( type == "QString" )
+> arg << s;
+> else if ( type == "QCString" )
+> arg << QCString( args[ i ] );
+> else if ( type == "QColor" )
+> arg << mkColor( s );
+> else if ( type == "QPoint" )
+> arg << mkPoint( s );
+> else if ( type == "QSize" )
+> arg << mkSize( s );
+> else if ( type == "QRect" )
+> arg << mkRect( s );
+> else if ( type == "QVariant" ) {
+> if ( s == "true" || s == "false" )
+> arg << QVariant( mkBool( s ), 42 );
+> else if ( s.left( 4 ) == "int(" )
+> arg << QVariant( s.mid(4, s.length()-5).toInt() );
+> else if ( s.left( 7 ) == "QPoint(" )
+> arg << QVariant( mkPoint( s.mid(7, s.length()-8) ) );
+> else if ( s.left( 6 ) == "QSize(" )
+> arg << QVariant( mkSize( s.mid(6, s.length()-7) ) );
+> else if ( s.left( 6 ) == "QRect(" )
+> arg << QVariant( mkRect( s.mid(6, s.length()-7) ) );
+> else if ( s.left( 7 ) == "QColor(" )
+> arg << QVariant( mkColor( s.mid(7, s.length()-8) ) );
+> else
+> arg << QVariant( s );
+> } else if ( type.startsWith("QValueList<")) {
+> type = type.mid(11, type.length() - 12);
+> QStringList list;
+> QString delim = s;
+> if (delim == "[")
+> delim = "]";
+> if (delim == "(")
+> delim = ")";
+347a316,349
+> QByteArray dummy_data;
+> QDataStream dummy_arg(dummy_data, IO_WriteOnly);
+>
+> uint j = i;
+> uint count = 0;
+> // Parse list to get the count
+> while (true) {
+> if( j > args.count() )
+> {
+> qWarning("List end-delimiter '%s' not found.", delim.latin1());
+> exit(1);
+> }
+> if( QString::fromLocal8Bit( args[ j ] ) == delim )
+> break;
+> marshall( dummy_arg, args, j, type );
+> count++;
+> }
+> arg << (Q_UINT32) count;
+> // Parse the list for real
+> while (true) {
+> if( i > args.count() )
+> {
+> qWarning("List end-delimiter '%s' not found.", delim.latin1());
+> exit(1);
+> }
+> if( QString::fromLocal8Bit( args[ i ] ) == delim )
+> break;
+> marshall( arg, args, i, type );
+> }
+> } else {
+> qWarning( "cannot handle datatype '%s'", type.latin1() );
+> exit(1);
+> }
+> i++;
diff --git a/kompare/tests/diff/rcs.diff b/kompare/tests/diff/rcs.diff
new file mode 100644
index 00000000..08069790
--- /dev/null
+++ b/kompare/tests/diff/rcs.diff
@@ -0,0 +1,9 @@
+d1 2
+d4 1
+a4 2
+The named is the mother of all things.
+
+a11 3
+They both may be called deep and profound.
+Deeper and more profound,
+The door of all subtleties!
diff --git a/kompare/tests/diff/rcsm.diff b/kompare/tests/diff/rcsm.diff
new file mode 100644
index 00000000..0c4222f9
--- /dev/null
+++ b/kompare/tests/diff/rcsm.diff
@@ -0,0 +1,671 @@
+diff -nr dcop/client/dcop.cpp dcop2/client/dcop.cpp
+d23 1
+a23 4
+#include <ctype.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+d25 1
+a25 12
+#include <qdir.h>
+#include <qfile.h>
+#include <qfileinfo.h>
+#include <qmap.h>
+#include <qstringlist.h>
+#include <qtextstream.h>
+#include <qvariant.h>
+
+// putenv() is not available on all platforms, so make sure the emulation
+// wrapper is available in those cases by loading config.h!
+#include <config.h>
+
+d28 3
+a30 1
+#include "../kdatastream.h"
+a33 2
+typedef QMap<QString, QString> UserList;
+
+a35 14
+static QTextStream cout( stdout, IO_WriteOnly );
+static QTextStream cerr( stderr, IO_WriteOnly );
+
+/**
+ * Session to send call to
+ * DefaultSession - current session. Current KDE session when called without
+ * --user or --all-users option. Otherwise this value ignores
+ * all users with more than one active session.
+ * AllSessions - Send to all sessions found. requires --user or --all-users.
+ * QuerySessions - Don't call DCOP, return a list of available sessions.
+ * CustomSession - Use the specified session
+ */
+enum Session { DefaultSession = 0, AllSessions, QuerySessions, CustomSession };
+
+d121 1
+a121 1
+void callFunction( const char* app, const char* obj, const char* func, const QCStringList args )
+d123 1
+d139 1
+a139 1
+ if ( !ok && args.isEmpty() )
+d156 2
+a157 2
+ uint a = (*it).contains(',');
+ if ( ( a == 0 && args.isEmpty() ) || ( a > 0 && a + 1 == args.count() ) )
+d164 1
+a164 2
+// exit(1);
+ return;
+d246 5
+a250 6
+ uint i = 0;
+ for( QStringList::Iterator it = types.begin(); it != types.end(); ++it )
+ marshall( arg, args, i, *it );
+
+ if ( i != args.count() )
+ {
+a268 27
+/**
+ * Show command-line help and exit
+ */
+void showHelp( int exitCode = 0 )
+{
+ cout << "Usage: dcop [options] [application [object [function [arg1] [arg2] ... ] ] ]" << endl
+ << "" << endl
+ << "Console DCOP client" << endl
+ << "" << endl
+ << "Generic options:" << endl
+ << " --help Show help about options" << endl
+ << "" << endl
+ << "Options:" << endl
+ << " --pipe Call DCOP for each line read from stdin" << endl
+ << " --user <user> Connect to the given user's DCOP server. This option will" << endl
+ << " ignore the values of the environment vars $DCOPSERVER and" << endl
+ << " $ICEAUTHORITY, even if they are set." << endl
+ << " If the user has more than one open session, you must also" << endl
+ << " use one of the --list-sessions, --session or --als-sessions" << endl
+ << " command-line options." << endl
+ << " --all-users Send the same DCOP call to all users with a running DCOP" << endl
+ << " server. Only failed calls to existing DCOP servers will"
+ << " generate an error message. If no DCOP server is available" << endl
+ << " at all, no error will be generated." << endl;
+
+ exit( exitCode );
+}
+d270 2
+a271 5
+/**
+ * Return a list of all users and their home directories.
+ * Returns an empty list if /etc/passwd cannot be read for some reason.
+ */
+static UserList userList()
+a272 9
+ UserList result;
+
+ QFile f( "/etc/passwd" );
+
+ if( !f.open( IO_ReadOnly ) )
+ {
+ cerr << "Can't open /etc/passwd for reading!" << endl;
+ return result;
+ }
+d274 3
+a276 6
+ QStringList l( QStringList::split( '\n', f.readAll() ) );
+
+ for( QStringList::ConstIterator it( l.begin() ); it != l.end(); ++it )
+ {
+ QStringList userInfo( QStringList::split( ':', *it, true ) );
+ result[ userInfo[ 0 ] ] = userInfo[ 5 ];
+d279 3
+a281 42
+ return result;
+}
+
+/**
+ * Return a list of available DCOP sessions for the specified user
+ * An empty list means no sessions are available, or an error occurred.
+ */
+QStringList dcopSessionList( const QString &user, const QString &home )
+{
+ if( home.isEmpty() )
+ {
+ cerr << "WARNING: Cannot determine home directory for user "
+ << user << "!" << endl
+ << "Please check permissions or set the $DCOPSERVER variable manually before" << endl
+ << "calling dcop." << endl;
+ return QStringList();
+ }
+
+ QStringList result;
+ QFileInfo dirInfo( home );
+ if( !dirInfo.exists() || !dirInfo.isReadable() )
+ return result;
+
+ QDir d( home );
+ d.setFilter( QDir::Files | QDir::Hidden | QDir::NoSymLinks );
+ d.setNameFilter( ".DCOPserver*" );
+
+ const QFileInfoList *list = d.entryInfoList();
+ if( !list )
+ return result;
+
+ QFileInfoListIterator it( *list );
+ QFileInfo *fi;
+
+ while ( ( fi = it.current() ) != 0 )
+ {
+ if( fi->isReadable() )
+ result.append( fi->fileName() );
+ ++it;
+ }
+ return result;
+}
+a282 6
+/**
+ * Do the actual DCOP call
+ */
+void runDCOP( QCStringList args, UserList users, Session session,
+ const QString sessionName, bool readStdin )
+{
+d286 2
+a287 3
+ QCStringList params;
+ DCOPClient *client = 0L;
+ if ( !args.isEmpty() && args[ 0 ].find( "DCOPRef(" ) == 0 )
+d289 16
+a304 24
+ // WARNING: This part (until the closing '}') could very
+ // well be broken now. As I don't know how to trigger and test
+ // dcoprefs this code is *not* tested. It compiles and it looks
+ // ok to me, but that's all I can say - Martijn (2001/12/24)
+ int delimPos = args[ 0 ].findRev( ',' );
+ if( delimPos == -1 )
+ {
+ cerr << "Error: '" << args[ 0 ]
+ << "' is not a valid DCOP reference." << endl;
+ exit( -1 );
+ }
+ args[ 0 ][ delimPos ] = 0;
+ app = args[ 0 ].mid( 8 );
+ delimPos++;
+ args[ 0 ][ args[ 0 ].length() - 1 ] = 0;
+ objid = args[ 0 ].mid( delimPos );
+ if( args.count() > 1 )
+ function = args[ 1 ];
+ if( args.count() > 2 )
+ {
+ params = args;
+ params.remove( params.begin() );
+ params.remove( params.begin() );
+ }
+d308 31
+a338 84
+ if( !args.isEmpty() )
+ app = args[ 0 ];
+ if( args.count() > 1 )
+ objid = args[ 1 ];
+ if( args.count() > 2 )
+ function = args[ 2 ];
+ if( args.count() > 3)
+ {
+ params = args;
+ params.remove( params.begin() );
+ params.remove( params.begin() );
+ params.remove( params.begin() );
+ }
+ }
+
+ bool firstRun = true;
+ UserList::Iterator it;
+ QStringList sessions;
+ bool presetDCOPServer = false;
+// char *dcopStr = 0L;
+ QString dcopServer;
+
+ for( it = users.begin(); it != users.end() || firstRun; it++ )
+ {
+ firstRun = false;
+
+ //cout << "Iterating '" << it.key() << "'" << endl;
+
+ if( session == QuerySessions )
+ {
+ QStringList sessions = dcopSessionList( it.key(), it.data() );
+ if( sessions.isEmpty() )
+ {
+ cout << "No active sessions";
+ if( !( *it ).isEmpty() )
+ cout << " for user " << *it;
+ cout << endl;
+ }
+ else
+ {
+ cout << "Active sessions ";
+ if( !( *it ).isEmpty() )
+ cout << "for user " << *it << " ";
+ cout << ":" << endl;
+
+ QStringList::Iterator sIt;
+ for( sIt = sessions.begin(); sIt != sessions.end(); sIt++ )
+ cout << " " << *sIt << endl;
+
+ cout << endl;
+ }
+ continue;
+ }
+
+ if( getenv( "DCOPSERVER" ) )
+ {
+ sessions.append( getenv( "DCOPSERVER" ) );
+ presetDCOPServer = true;
+ }
+
+ if( users.count() > 1 || ( users.count() == 1 &&
+ ( getenv( "DCOPSERVER" ) == 0 /*&& getenv( "DISPLAY" ) == 0*/ ) ) )
+ {
+ sessions = dcopSessionList( it.key(), it.data() );
+ if( sessions.isEmpty() )
+ {
+ if( users.count() > 1 )
+ continue;
+ else
+ {
+ cerr << "ERROR: No active KDE sessions!" << endl
+ << "If you are sure there is one, please set the $DCOPSERVER variable manually" << endl
+ << "before calling dcop." << endl;
+ exit( -1 );
+ }
+ }
+ else if( sessions.count() > 1 && session != AllSessions )
+ {
+ cerr << "ERROR: Multiple available KDE sessions!" << endl
+ << "Please specify the correct session to use with --session or use the" << endl
+ << "--all-sessions option to broadcast to all sessions." << endl;
+ exit( -1 );
+ }
+ }
+a339 143
+ if( users.count() > 1 || ( users.count() == 1 &&
+ ( getenv( "ICEAUTHORITY" ) == 0 || getenv( "DISPLAY" ) == 0 ) ) )
+ {
+ // Check for ICE authority file and if the file can be read by us
+ QString home = it.data();
+ QString iceFile = it.data() + "/.ICEauthority";
+ QFileInfo fi( iceFile );
+ if( iceFile.isEmpty() )
+ {
+ cerr << "WARNING: Cannot determine home directory for user "
+ << it.key() << "!" << endl
+ << "Please check permissions or set the $ICEAUTHORITY variable manually before" << endl
+ << "calling dcop." << endl;
+ }
+ else if( fi.exists() )
+ {
+ if( fi.isReadable() )
+ {
+ char *envStr = strdup( ( "ICEAUTHORITY=" + iceFile ).ascii() );
+ putenv( envStr );
+ //cerr << "ice: " << envStr << endl;
+ }
+ else
+ {
+ cerr << "WARNING: ICE authority file " << iceFile
+ << "is not readable by you!" << endl
+ << "Please check permissions or set the $ICEAUTHORITY variable manually before" << endl
+ << "calling dcop." << endl;
+ }
+ }
+ else
+ {
+ if( users.count() > 1 )
+ continue;
+ else
+ {
+ cerr << "WARNING: Cannot find ICE authority file "
+ << iceFile << "!" << endl
+ << "Please check permissions or set the $ICEAUTHORITY"
+ << " variable manually before" << endl
+ << "calling dcop." << endl;
+ }
+ }
+ }
+
+ // Main loop
+ // If users is an empty list we're calling for the currently logged
+ // in user. In this case we don't have a session, but still want
+ // to iterate the loop once.
+ QStringList::Iterator sIt = sessions.begin();
+ for( ; sIt != sessions.end() || users.isEmpty(); sIt++ )
+ {
+ if( !presetDCOPServer && !users.isEmpty() )
+ {
+ QString dcopFile = it.data() + "/" + *sIt;
+ QFile f( dcopFile );
+ if( !f.open( IO_ReadOnly ) )
+ {
+ cerr << "Can't open " << dcopFile << " for reading!" << endl;
+ exit( -1 );
+ }
+
+ QStringList l( QStringList::split( '\n', f.readAll() ) );
+ dcopServer = l.first();
+
+ if( dcopServer.isEmpty() )
+ {
+ cerr << "WARNING: Unable to determine DCOP server for session "
+ << *sIt << "!" << endl
+ << "Please check permissions or set the $DCOPSERVER variable manually before" << endl
+ << "calling dcop." << endl;
+ exit( -1 );
+ }
+ }
+
+ delete client;
+ client = new DCOPClient;
+ if( !dcopServer.isEmpty() )
+ client->setServerAddress( dcopServer.ascii() );
+ bool success = client->attach();
+ if( !success )
+ {
+ cerr << "ERROR: Couldn't attach to DCOP server!" << endl;
+ continue;
+ }
+ dcop = client;
+
+ switch ( args.count() )
+ {
+ case 0:
+ queryApplications("");
+ break;
+ case 1:
+ if (endsWith(app, '*'))
+ queryApplications(app);
+ else
+ queryObjects( app, "" );
+ break;
+ case 2:
+ if (endsWith(objid, '*'))
+ queryObjects(app, objid);
+ else
+ queryFunctions( app, objid );
+ break;
+ case 3:
+ default:
+ if( readStdin )
+ {
+ QCStringList::Iterator replaceArg = args.end();
+
+ QCStringList::Iterator it;
+ for( it = args.begin(); it != args.end(); it++ )
+ if( *it == "%1" )
+ replaceArg = it;
+
+ // Read from stdin until EOF and call function for each line read
+ char *buf = new char[ 1000 ];
+ while ( !feof( stdin ) )
+ {
+ fgets( buf, 1000, stdin );
+
+ if( replaceArg != args.end() )
+ *replaceArg = buf;
+
+ callFunction( app, objid, function, params );
+ }
+ }
+ else
+ {
+ // Just call function
+// cout << "call " << app << ", " << objid << ", " << function << ", (params)" << endl;
+ callFunction( app, objid, function, params );
+ }
+ break;
+ }
+ // Another sIt++ would make the loop infinite...
+ if( users.isEmpty() )
+ break;
+ }
+
+ // Another it++ would make the loop infinite...
+ if( it == users.end() )
+ break;
+a340 106
+}
+
+
+int main( int argc, char** argv )
+{
+ bool readStdin = false;
+ int numOptions = 0;
+ QString user;
+ Session session = DefaultSession;
+ QString sessionName;
+
+ // Scan for command-line options first
+ for( int pos = 1 ; pos <= argc - 1 ; pos++ )
+ {
+ if( strcmp( argv[ pos ], "--help" ) == 0 )
+ showHelp( 0 );
+ else if( strcmp( argv[ pos ], "--pipe" ) == 0 )
+ {
+ readStdin = true;
+ numOptions++;
+ }
+ else if( strcmp( argv[ pos ], "--user" ) == 0 )
+ {
+ if( pos <= argc - 2 )
+ {
+ user = QString::fromLocal8Bit( argv[ pos + 1] );
+ numOptions +=2;
+ pos++;
+ }
+ else
+ {
+ cerr << "Missing username for '--user' option!" << endl << endl;
+ showHelp( -1 );
+ }
+ }
+ else if( strcmp( argv[ pos ], "--all-users" ) == 0 )
+ {
+ user = "*";
+ numOptions ++;
+ }
+ else if( strcmp( argv[ pos ], "--list-sessions" ) == 0 )
+ {
+ session = QuerySessions;
+ numOptions ++;
+ }
+ else if( strcmp( argv[ pos ], "--all-sessions" ) == 0 )
+ {
+ session = AllSessions;
+ numOptions ++;
+ }
+ else if( argv[ pos ][ 0 ] == '-' )
+ {
+ cerr << "Unknown command-line option '" << argv[ pos ]
+ << "'." << endl << endl;
+ showHelp( -1 );
+ }
+ else
+ break; // End of options
+ }
+
+ argc -= numOptions;
+
+ QCStringList args;
+ for( int i = numOptions; i < argc + numOptions - 1; i++ )
+ args.append( argv[ i + 1 ] );
+
+ if( readStdin && args.count() < 3 )
+ {
+ cerr << "--pipe option only supported for function calls!" << endl << endl;
+ showHelp( -1 );
+ }
+
+ if( user == "*" && args.count() < 3 && session != QuerySessions )
+ {
+ cerr << "ERROR: The --all-users option is only supported for function calls!" << endl << endl;
+ showHelp( -1 );
+ }
+
+ if( session == QuerySessions && !args.isEmpty() )
+ {
+ cerr << "ERROR: The --list-sessions option cannot be used for actual DCOP calls!" << endl << endl;
+ showHelp( -1 );
+ }
+
+ if( session == QuerySessions && user.isEmpty() )
+ {
+ cerr << "ERROR: The --list-sessions option can only be used with the --user or" << endl
+ << "--all-users options!" << endl << endl;
+ showHelp( -1 );
+ }
+
+ if( session != DefaultSession && session != QuerySessions &&
+ args.count() < 3 )
+ {
+ cerr << "ERROR: The --session and --all-sessions options are only supported for function" << endl
+ << "calls!" << endl << endl;
+ showHelp( -1 );
+ }
+
+ UserList users;
+ if( user == "*" )
+ users = userList();
+ else if( !user.isEmpty() )
+ users[ user ] = userList()[ user ];
+
+ runDCOP( args, users, session, sessionName, readStdin );
+a343 3
+
+// vim: set ts=8 sts=4 sw=4 noet:
+
+diff -nr dcop/client/dcopfind.cpp dcop2/client/dcopfind.cpp
+d39 1
+a39 1
+bool findObject( const char* app, const char* obj, const char* func, QCStringList args )
+d121 1
+a121 1
+ if ( types.count() != args.count() ) {
+d131 1
+a131 1
+ marshall(arg, args, i, *it);
+d133 1
+a133 1
+ if ( (uint) i != args.count() ) {
+d224 1
+a224 5
+ QCStringList params;
+ for( int i = 0; i < argc; i++ )
+ params.append( args[ i ] );
+
+ findObject( app, objid, function, params );
+diff -nr dcop/client/marshall.cpp dcop2/client/marshall.cpp
+d245 1
+a245 1
+void marshall( QDataStream &arg, QCStringList args, uint &i, QString type )
+d247 71
+a317 10
+ if (type == "QStringList")
+ type = "QValueList<QString>";
+ if (type == "QCStringList")
+ type = "QValueList<QCString>";
+ if( i > args.count() )
+ {
+ qWarning("Not enough arguments.");
+ exit(1);
+ }
+ QString s = QString::fromLocal8Bit( args[ i ] );
+d319 28
+a346 57
+ if ( type == "int" )
+ arg << s.toInt();
+ else if ( type == "uint" )
+ arg << s.toUInt();
+ else if ( type == "unsigned" )
+ arg << s.toUInt();
+ else if ( type == "unsigned int" )
+ arg << s.toUInt();
+ else if ( type == "long" )
+ arg << s.toLong();
+ else if ( type == "long int" )
+ arg << s.toLong();
+ else if ( type == "unsigned long" )
+ arg << s.toULong();
+ else if ( type == "unsigned long int" )
+ arg << s.toULong();
+ else if ( type == "float" )
+ arg << s.toFloat();
+ else if ( type == "double" )
+ arg << s.toDouble();
+ else if ( type == "bool" )
+ arg << mkBool( s );
+ else if ( type == "QString" )
+ arg << s;
+ else if ( type == "QCString" )
+ arg << QCString( args[ i ] );
+ else if ( type == "QColor" )
+ arg << mkColor( s );
+ else if ( type == "QPoint" )
+ arg << mkPoint( s );
+ else if ( type == "QSize" )
+ arg << mkSize( s );
+ else if ( type == "QRect" )
+ arg << mkRect( s );
+ else if ( type == "QVariant" ) {
+ if ( s == "true" || s == "false" )
+ arg << QVariant( mkBool( s ), 42 );
+ else if ( s.left( 4 ) == "int(" )
+ arg << QVariant( s.mid(4, s.length()-5).toInt() );
+ else if ( s.left( 7 ) == "QPoint(" )
+ arg << QVariant( mkPoint( s.mid(7, s.length()-8) ) );
+ else if ( s.left( 6 ) == "QSize(" )
+ arg << QVariant( mkSize( s.mid(6, s.length()-7) ) );
+ else if ( s.left( 6 ) == "QRect(" )
+ arg << QVariant( mkRect( s.mid(6, s.length()-7) ) );
+ else if ( s.left( 7 ) == "QColor(" )
+ arg << QVariant( mkColor( s.mid(7, s.length()-8) ) );
+ else
+ arg << QVariant( s );
+ } else if ( type.startsWith("QValueList<")) {
+ type = type.mid(11, type.length() - 12);
+ QStringList list;
+ QString delim = s;
+ if (delim == "[")
+ delim = "]";
+ if (delim == "(")
+ delim = ")";
+a347 34
+ QByteArray dummy_data;
+ QDataStream dummy_arg(dummy_data, IO_WriteOnly);
+
+ uint j = i;
+ uint count = 0;
+ // Parse list to get the count
+ while (true) {
+ if( j > args.count() )
+ {
+ qWarning("List end-delimiter '%s' not found.", delim.latin1());
+ exit(1);
+ }
+ if( QString::fromLocal8Bit( args[ j ] ) == delim )
+ break;
+ marshall( dummy_arg, args, j, type );
+ count++;
+ }
+ arg << (Q_UINT32) count;
+ // Parse the list for real
+ while (true) {
+ if( i > args.count() )
+ {
+ qWarning("List end-delimiter '%s' not found.", delim.latin1());
+ exit(1);
+ }
+ if( QString::fromLocal8Bit( args[ i ] ) == delim )
+ break;
+ marshall( arg, args, i, type );
+ }
+ } else {
+ qWarning( "cannot handle datatype '%s'", type.latin1() );
+ exit(1);
+ }
+ i++;
diff --git a/kompare/tests/diff/unified.diff b/kompare/tests/diff/unified.diff
new file mode 100644
index 00000000..952e648c
--- /dev/null
+++ b/kompare/tests/diff/unified.diff
@@ -0,0 +1,19 @@
+--- /home/John/lao Thu Apr 12 11:09:30 2001
++++ /home/John/tzu Sat Jul 28 13:23:25 2001
+@@ -1,7 +1,6 @@
+-The Way that can be told of is not the eternal Way;
+-The name that can be named is not the eternal name.
+ The Nameless is the origin of Heaven and Earth;
+-The Named is the mother of all things.
++The named is the mother of all things.
++
+ Therefore let there always be non-being,
+ so we may see their subtlety,
+ And let there always be being,
+@@ -9,3 +8,6 @@
+ The two are the same,
+ But after they are produced,
+ they have different names.
++They both may be called deep and profound.
++Deeper and more profound,
++The door of all subtleties!
diff --git a/kompare/tests/diff/unifiedm.diff b/kompare/tests/diff/unifiedm.diff
new file mode 100644
index 00000000..4a30c6b4
--- /dev/null
+++ b/kompare/tests/diff/unifiedm.diff
@@ -0,0 +1,911 @@
+diff -aur dcop/client/dcop.cpp dcop2/client/dcop.cpp
+--- dcop/client/dcop.cpp Wed Jan 30 22:38:07 2002
++++ dcop2/client/dcop.cpp Wed Jan 30 22:37:04 2002
+@@ -20,19 +20,47 @@
+
+ ******************************************************************/
+
+-#include <qvariant.h>
++#include <ctype.h>
++#include <stdio.h>
++#include <stdlib.h>
++
+ #include <qcolor.h>
+-#include "../kdatastream.h"
++#include <qdir.h>
++#include <qfile.h>
++#include <qfileinfo.h>
++#include <qmap.h>
++#include <qstringlist.h>
++#include <qtextstream.h>
++#include <qvariant.h>
++
++// putenv() is not available on all platforms, so make sure the emulation
++// wrapper is available in those cases by loading config.h!
++#include <config.h>
++
+ #include "../dcopclient.h"
+ #include "../dcopref.h"
+-#include <stdlib.h>
+-#include <stdio.h>
+-#include <ctype.h>
++#include "../kdatastream.h"
+
+ #include "marshall.cpp"
+
++typedef QMap<QString, QString> UserList;
++
+ static DCOPClient* dcop = 0;
+
++static QTextStream cout( stdout, IO_WriteOnly );
++static QTextStream cerr( stderr, IO_WriteOnly );
++
++/**
++ * Session to send call to
++ * DefaultSession - current session. Current KDE session when called without
++ * --user or --all-users option. Otherwise this value ignores
++ * all users with more than one active session.
++ * AllSessions - Send to all sessions found. requires --user or --all-users.
++ * QuerySessions - Don't call DCOP, return a list of available sessions.
++ * CustomSession - Use the specified session
++ */
++enum Session { DefaultSession = 0, AllSessions, QuerySessions, CustomSession };
++
+ bool startsWith(const QCString &id, const char *str, int n)
+ {
+ return !n || (strncmp(id.data(), str, n) == 0);
+@@ -118,9 +146,8 @@
+ }
+ }
+
+-void callFunction( const char* app, const char* obj, const char* func, int argc, char** args )
++void callFunction( const char* app, const char* obj, const char* func, const QCStringList args )
+ {
+-
+ QString f = func; // Qt is better with unicode strings, so use one.
+ int left = f.find( '(' );
+ int right = f.find( ')' );
+@@ -136,7 +163,7 @@
+ bool ok = false;
+ QCStringList funcs = dcop->remoteFunctions( app, obj, &ok );
+ QCString realfunc;
+- if ( !ok && argc == 0 )
++ if ( !ok && args.isEmpty() )
+ goto doit;
+ if ( !ok )
+ {
+@@ -153,15 +180,16 @@
+
+ if ( l > 0 && (*it).mid( s, l - s ) == func ) {
+ realfunc = (*it).mid( s );
+- int a = (*it).contains(',');
+- if ( ( a == 0 && argc == 0) || ( a > 0 && a + 1 == argc ) )
++ uint a = (*it).contains(',');
++ if ( ( a == 0 && args.isEmpty() ) || ( a > 0 && a + 1 == args.count() ) )
+ break;
+ }
+ }
+ if ( realfunc.isEmpty() )
+ {
+ qWarning("no such function");
+- exit(1);
++// exit(1);
++ return;
+ }
+ f = realfunc;
+ left = f.find( '(' );
+@@ -243,11 +271,12 @@
+ QCString replyType;
+ QDataStream arg(data, IO_WriteOnly);
+
+- int i = 0;
+- for ( QStringList::Iterator it = types.begin(); it != types.end(); ++it ) {
+- marshall(arg, argc, args, i, *it);
+- }
+- if ( i != argc ) {
++ uint i = 0;
++ for( QStringList::Iterator it = types.begin(); it != types.end(); ++it )
++ marshall( arg, args, i, *it );
++
++ if ( i != args.count() )
++ {
+ qWarning( "arguments do not match" );
+ exit(1);
+ }
+@@ -266,78 +295,479 @@
+ }
+ }
+
++/**
++ * Show command-line help and exit
++ */
++void showHelp( int exitCode = 0 )
++{
++ cout << "Usage: dcop [options] [application [object [function [arg1] [arg2] ... ] ] ]" << endl
++ << "" << endl
++ << "Console DCOP client" << endl
++ << "" << endl
++ << "Generic options:" << endl
++ << " --help Show help about options" << endl
++ << "" << endl
++ << "Options:" << endl
++ << " --pipe Call DCOP for each line read from stdin" << endl
++ << " --user <user> Connect to the given user's DCOP server. This option will" << endl
++ << " ignore the values of the environment vars $DCOPSERVER and" << endl
++ << " $ICEAUTHORITY, even if they are set." << endl
++ << " If the user has more than one open session, you must also" << endl
++ << " use one of the --list-sessions, --session or --als-sessions" << endl
++ << " command-line options." << endl
++ << " --all-users Send the same DCOP call to all users with a running DCOP" << endl
++ << " server. Only failed calls to existing DCOP servers will"
++ << " generate an error message. If no DCOP server is available" << endl
++ << " at all, no error will be generated." << endl;
++
++ exit( exitCode );
++}
+
+-
+-int main( int argc, char** argv )
++/**
++ * Return a list of all users and their home directories.
++ * Returns an empty list if /etc/passwd cannot be read for some reason.
++ */
++static UserList userList()
+ {
++ UserList result;
++
++ QFile f( "/etc/passwd" );
++
++ if( !f.open( IO_ReadOnly ) )
++ {
++ cerr << "Can't open /etc/passwd for reading!" << endl;
++ return result;
++ }
+
+- if ( argc > 1 && argv[1][0] == '-' ) {
+- fprintf( stderr, "Usage: dcop [ application [object [function [arg1] [arg2] [arg3] ... ] ] ] \n" );
+- exit(0);
++ QStringList l( QStringList::split( '\n', f.readAll() ) );
++
++ for( QStringList::ConstIterator it( l.begin() ); it != l.end(); ++it )
++ {
++ QStringList userInfo( QStringList::split( ':', *it, true ) );
++ result[ userInfo[ 0 ] ] = userInfo[ 5 ];
+ }
+
+- DCOPClient client;
+- client.attach();
+- dcop = &client;
++ return result;
++}
++
++/**
++ * Return a list of available DCOP sessions for the specified user
++ * An empty list means no sessions are available, or an error occurred.
++ */
++QStringList dcopSessionList( const QString &user, const QString &home )
++{
++ if( home.isEmpty() )
++ {
++ cerr << "WARNING: Cannot determine home directory for user "
++ << user << "!" << endl
++ << "Please check permissions or set the $DCOPSERVER variable manually before" << endl
++ << "calling dcop." << endl;
++ return QStringList();
++ }
++
++ QStringList result;
++ QFileInfo dirInfo( home );
++ if( !dirInfo.exists() || !dirInfo.isReadable() )
++ return result;
++
++ QDir d( home );
++ d.setFilter( QDir::Files | QDir::Hidden | QDir::NoSymLinks );
++ d.setNameFilter( ".DCOPserver*" );
++
++ const QFileInfoList *list = d.entryInfoList();
++ if( !list )
++ return result;
++
++ QFileInfoListIterator it( *list );
++ QFileInfo *fi;
++
++ while ( ( fi = it.current() ) != 0 )
++ {
++ if( fi->isReadable() )
++ result.append( fi->fileName() );
++ ++it;
++ }
++ return result;
++}
+
++/**
++ * Do the actual DCOP call
++ */
++void runDCOP( QCStringList args, UserList users, Session session,
++ const QString sessionName, bool readStdin )
++{
+ QCString app;
+ QCString objid;
+ QCString function;
+- char **args = 0;
+- if ((argc > 1) && (strncmp(argv[1], "DCOPRef(", 8)) == 0)
++ QCStringList params;
++ DCOPClient *client = 0L;
++ if ( !args.isEmpty() && args[ 0 ].find( "DCOPRef(" ) == 0 )
+ {
+- char *delim = strchr(argv[1], ',');
+- if (!delim)
+- {
+- fprintf(stderr, "Error: '%s' is not a valid DCOP reference.\n", argv[1]);
+- return 1;
+- }
+- *delim = 0;
+- app = argv[1] + 8;
+- delim++;
+- delim[strlen(delim)-1] = 0;
+- objid = delim;
+- if (argc > 2)
+- function = argv[2];
+- if (argc > 3)
+- args = &argv[3];
+- argc++;
++ // WARNING: This part (until the closing '}') could very
++ // well be broken now. As I don't know how to trigger and test
++ // dcoprefs this code is *not* tested. It compiles and it looks
++ // ok to me, but that's all I can say - Martijn (2001/12/24)
++ int delimPos = args[ 0 ].findRev( ',' );
++ if( delimPos == -1 )
++ {
++ cerr << "Error: '" << args[ 0 ]
++ << "' is not a valid DCOP reference." << endl;
++ exit( -1 );
++ }
++ args[ 0 ][ delimPos ] = 0;
++ app = args[ 0 ].mid( 8 );
++ delimPos++;
++ args[ 0 ][ args[ 0 ].length() - 1 ] = 0;
++ objid = args[ 0 ].mid( delimPos );
++ if( args.count() > 1 )
++ function = args[ 1 ];
++ if( args.count() > 2 )
++ {
++ params = args;
++ params.remove( params.begin() );
++ params.remove( params.begin() );
++ }
+ }
+ else
+ {
+- if (argc > 1)
+- app = argv[1];
+- if (argc > 2)
+- objid = argv[2];
+- if (argc > 3)
+- function = argv[3];
+- if (argc > 4)
+- args = &argv[4];
+- }
+-
+- switch ( argc ) {
+- case 0:
+- case 1:
+- queryApplications("");
+- break;
+- case 2:
+- if (endsWith(app, '*'))
+- queryApplications(app);
+- else
+- queryObjects( app, "" );
+- break;
+- case 3:
+- if (endsWith(objid, '*'))
+- queryObjects(app, objid);
+- else
+- queryFunctions( app, objid );
+- break;
+- case 4:
+- default:
+- callFunction( app, objid, function, argc - 4, args );
+- break;
++ if( !args.isEmpty() )
++ app = args[ 0 ];
++ if( args.count() > 1 )
++ objid = args[ 1 ];
++ if( args.count() > 2 )
++ function = args[ 2 ];
++ if( args.count() > 3)
++ {
++ params = args;
++ params.remove( params.begin() );
++ params.remove( params.begin() );
++ params.remove( params.begin() );
++ }
++ }
++
++ bool firstRun = true;
++ UserList::Iterator it;
++ QStringList sessions;
++ bool presetDCOPServer = false;
++// char *dcopStr = 0L;
++ QString dcopServer;
++
++ for( it = users.begin(); it != users.end() || firstRun; it++ )
++ {
++ firstRun = false;
++
++ //cout << "Iterating '" << it.key() << "'" << endl;
++
++ if( session == QuerySessions )
++ {
++ QStringList sessions = dcopSessionList( it.key(), it.data() );
++ if( sessions.isEmpty() )
++ {
++ cout << "No active sessions";
++ if( !( *it ).isEmpty() )
++ cout << " for user " << *it;
++ cout << endl;
++ }
++ else
++ {
++ cout << "Active sessions ";
++ if( !( *it ).isEmpty() )
++ cout << "for user " << *it << " ";
++ cout << ":" << endl;
++
++ QStringList::Iterator sIt;
++ for( sIt = sessions.begin(); sIt != sessions.end(); sIt++ )
++ cout << " " << *sIt << endl;
++
++ cout << endl;
++ }
++ continue;
++ }
++
++ if( getenv( "DCOPSERVER" ) )
++ {
++ sessions.append( getenv( "DCOPSERVER" ) );
++ presetDCOPServer = true;
++ }
++
++ if( users.count() > 1 || ( users.count() == 1 &&
++ ( getenv( "DCOPSERVER" ) == 0 /*&& getenv( "DISPLAY" ) == 0*/ ) ) )
++ {
++ sessions = dcopSessionList( it.key(), it.data() );
++ if( sessions.isEmpty() )
++ {
++ if( users.count() > 1 )
++ continue;
++ else
++ {
++ cerr << "ERROR: No active KDE sessions!" << endl
++ << "If you are sure there is one, please set the $DCOPSERVER variable manually" << endl
++ << "before calling dcop." << endl;
++ exit( -1 );
++ }
++ }
++ else if( sessions.count() > 1 && session != AllSessions )
++ {
++ cerr << "ERROR: Multiple available KDE sessions!" << endl
++ << "Please specify the correct session to use with --session or use the" << endl
++ << "--all-sessions option to broadcast to all sessions." << endl;
++ exit( -1 );
++ }
++ }
+
++ if( users.count() > 1 || ( users.count() == 1 &&
++ ( getenv( "ICEAUTHORITY" ) == 0 || getenv( "DISPLAY" ) == 0 ) ) )
++ {
++ // Check for ICE authority file and if the file can be read by us
++ QString home = it.data();
++ QString iceFile = it.data() + "/.ICEauthority";
++ QFileInfo fi( iceFile );
++ if( iceFile.isEmpty() )
++ {
++ cerr << "WARNING: Cannot determine home directory for user "
++ << it.key() << "!" << endl
++ << "Please check permissions or set the $ICEAUTHORITY variable manually before" << endl
++ << "calling dcop." << endl;
++ }
++ else if( fi.exists() )
++ {
++ if( fi.isReadable() )
++ {
++ char *envStr = strdup( ( "ICEAUTHORITY=" + iceFile ).ascii() );
++ putenv( envStr );
++ //cerr << "ice: " << envStr << endl;
++ }
++ else
++ {
++ cerr << "WARNING: ICE authority file " << iceFile
++ << "is not readable by you!" << endl
++ << "Please check permissions or set the $ICEAUTHORITY variable manually before" << endl
++ << "calling dcop." << endl;
++ }
++ }
++ else
++ {
++ if( users.count() > 1 )
++ continue;
++ else
++ {
++ cerr << "WARNING: Cannot find ICE authority file "
++ << iceFile << "!" << endl
++ << "Please check permissions or set the $ICEAUTHORITY"
++ << " variable manually before" << endl
++ << "calling dcop." << endl;
++ }
++ }
++ }
++
++ // Main loop
++ // If users is an empty list we're calling for the currently logged
++ // in user. In this case we don't have a session, but still want
++ // to iterate the loop once.
++ QStringList::Iterator sIt = sessions.begin();
++ for( ; sIt != sessions.end() || users.isEmpty(); sIt++ )
++ {
++ if( !presetDCOPServer && !users.isEmpty() )
++ {
++ QString dcopFile = it.data() + "/" + *sIt;
++ QFile f( dcopFile );
++ if( !f.open( IO_ReadOnly ) )
++ {
++ cerr << "Can't open " << dcopFile << " for reading!" << endl;
++ exit( -1 );
++ }
++
++ QStringList l( QStringList::split( '\n', f.readAll() ) );
++ dcopServer = l.first();
++
++ if( dcopServer.isEmpty() )
++ {
++ cerr << "WARNING: Unable to determine DCOP server for session "
++ << *sIt << "!" << endl
++ << "Please check permissions or set the $DCOPSERVER variable manually before" << endl
++ << "calling dcop." << endl;
++ exit( -1 );
++ }
++ }
++
++ delete client;
++ client = new DCOPClient;
++ if( !dcopServer.isEmpty() )
++ client->setServerAddress( dcopServer.ascii() );
++ bool success = client->attach();
++ if( !success )
++ {
++ cerr << "ERROR: Couldn't attach to DCOP server!" << endl;
++ continue;
++ }
++ dcop = client;
++
++ switch ( args.count() )
++ {
++ case 0:
++ queryApplications("");
++ break;
++ case 1:
++ if (endsWith(app, '*'))
++ queryApplications(app);
++ else
++ queryObjects( app, "" );
++ break;
++ case 2:
++ if (endsWith(objid, '*'))
++ queryObjects(app, objid);
++ else
++ queryFunctions( app, objid );
++ break;
++ case 3:
++ default:
++ if( readStdin )
++ {
++ QCStringList::Iterator replaceArg = args.end();
++
++ QCStringList::Iterator it;
++ for( it = args.begin(); it != args.end(); it++ )
++ if( *it == "%1" )
++ replaceArg = it;
++
++ // Read from stdin until EOF and call function for each line read
++ char *buf = new char[ 1000 ];
++ while ( !feof( stdin ) )
++ {
++ fgets( buf, 1000, stdin );
++
++ if( replaceArg != args.end() )
++ *replaceArg = buf;
++
++ callFunction( app, objid, function, params );
++ }
++ }
++ else
++ {
++ // Just call function
++// cout << "call " << app << ", " << objid << ", " << function << ", (params)" << endl;
++ callFunction( app, objid, function, params );
++ }
++ break;
++ }
++ // Another sIt++ would make the loop infinite...
++ if( users.isEmpty() )
++ break;
++ }
++
++ // Another it++ would make the loop infinite...
++ if( it == users.end() )
++ break;
+ }
++}
++
++
++int main( int argc, char** argv )
++{
++ bool readStdin = false;
++ int numOptions = 0;
++ QString user;
++ Session session = DefaultSession;
++ QString sessionName;
++
++ // Scan for command-line options first
++ for( int pos = 1 ; pos <= argc - 1 ; pos++ )
++ {
++ if( strcmp( argv[ pos ], "--help" ) == 0 )
++ showHelp( 0 );
++ else if( strcmp( argv[ pos ], "--pipe" ) == 0 )
++ {
++ readStdin = true;
++ numOptions++;
++ }
++ else if( strcmp( argv[ pos ], "--user" ) == 0 )
++ {
++ if( pos <= argc - 2 )
++ {
++ user = QString::fromLocal8Bit( argv[ pos + 1] );
++ numOptions +=2;
++ pos++;
++ }
++ else
++ {
++ cerr << "Missing username for '--user' option!" << endl << endl;
++ showHelp( -1 );
++ }
++ }
++ else if( strcmp( argv[ pos ], "--all-users" ) == 0 )
++ {
++ user = "*";
++ numOptions ++;
++ }
++ else if( strcmp( argv[ pos ], "--list-sessions" ) == 0 )
++ {
++ session = QuerySessions;
++ numOptions ++;
++ }
++ else if( strcmp( argv[ pos ], "--all-sessions" ) == 0 )
++ {
++ session = AllSessions;
++ numOptions ++;
++ }
++ else if( argv[ pos ][ 0 ] == '-' )
++ {
++ cerr << "Unknown command-line option '" << argv[ pos ]
++ << "'." << endl << endl;
++ showHelp( -1 );
++ }
++ else
++ break; // End of options
++ }
++
++ argc -= numOptions;
++
++ QCStringList args;
++ for( int i = numOptions; i < argc + numOptions - 1; i++ )
++ args.append( argv[ i + 1 ] );
++
++ if( readStdin && args.count() < 3 )
++ {
++ cerr << "--pipe option only supported for function calls!" << endl << endl;
++ showHelp( -1 );
++ }
++
++ if( user == "*" && args.count() < 3 && session != QuerySessions )
++ {
++ cerr << "ERROR: The --all-users option is only supported for function calls!" << endl << endl;
++ showHelp( -1 );
++ }
++
++ if( session == QuerySessions && !args.isEmpty() )
++ {
++ cerr << "ERROR: The --list-sessions option cannot be used for actual DCOP calls!" << endl << endl;
++ showHelp( -1 );
++ }
++
++ if( session == QuerySessions && user.isEmpty() )
++ {
++ cerr << "ERROR: The --list-sessions option can only be used with the --user or" << endl
++ << "--all-users options!" << endl << endl;
++ showHelp( -1 );
++ }
++
++ if( session != DefaultSession && session != QuerySessions &&
++ args.count() < 3 )
++ {
++ cerr << "ERROR: The --session and --all-sessions options are only supported for function" << endl
++ << "calls!" << endl << endl;
++ showHelp( -1 );
++ }
++
++ UserList users;
++ if( user == "*" )
++ users = userList();
++ else if( !user.isEmpty() )
++ users[ user ] = userList()[ user ];
++
++ runDCOP( args, users, session, sessionName, readStdin );
+
+ return 0;
+ }
++
++// vim: set ts=8 sts=4 sw=4 noet:
++
+diff -aur dcop/client/dcopfind.cpp dcop2/client/dcopfind.cpp
+--- dcop/client/dcopfind.cpp Wed Jan 30 22:38:07 2002
++++ dcop2/client/dcopfind.cpp Wed Jan 30 22:37:04 2002
+@@ -36,7 +36,7 @@
+ static bool bAppIdOnly = 0;
+ static bool bLaunchApp = 0;
+
+-bool findObject( const char* app, const char* obj, const char* func, int argc, char** args )
++bool findObject( const char* app, const char* obj, const char* func, QCStringList args )
+ {
+ QString f = func; // Qt is better with unicode strings, so use one.
+ int left = f.find( '(' );
+@@ -118,7 +118,7 @@
+ f = fc;
+ }
+
+- if ( (int) types.count() != argc ) {
++ if ( types.count() != args.count() ) {
+ qWarning( "arguments do not match" );
+ exit(1);
+ }
+@@ -128,9 +128,9 @@
+
+ int i = 0;
+ for ( QStringList::Iterator it = types.begin(); it != types.end(); ++it ) {
+- marshall(arg, argc, args, i, *it);
++ marshall(arg, args, i, *it);
+ }
+- if ( (int) i != argc ) {
++ if ( (uint) i != args.count() ) {
+ qWarning( "arguments do not match" );
+ exit(1);
+ }
+@@ -221,7 +221,11 @@
+ argc = 0;
+ }
+
+- findObject( app, objid, function, argc, args );
++ QCStringList params;
++ for( int i = 0; i < argc; i++ )
++ params.append( args[ i ] );
++
++ findObject( app, objid, function, params );
+
+ return 0;
+ }
+diff -aur dcop/client/marshall.cpp dcop2/client/marshall.cpp
+--- dcop/client/marshall.cpp Wed Jan 30 22:38:07 2002
++++ dcop2/client/marshall.cpp Wed Jan 30 22:37:04 2002
+@@ -242,108 +242,110 @@
+
+ }
+
+-void marshall(QDataStream &arg, int argc, char **argv, int &i, QString type)
++void marshall( QDataStream &arg, QCStringList args, uint &i, QString type )
+ {
+- if (type == "QStringList")
+- type = "QValueList<QString>";
+- if (type == "QCStringList")
+- type = "QValueList<QCString>";
+- if (i >= argc)
+- {
+- qWarning("Not enough arguments.");
+- exit(1);
+- }
+- QString s = QString::fromLocal8Bit(argv[i]);
+-
+- if ( type == "int" )
+- arg << s.toInt();
+- else if ( type == "uint" )
+- arg << s.toUInt();
+- else if ( type == "unsigned" )
+- arg << s.toUInt();
+- else if ( type == "unsigned int" )
+- arg << s.toUInt();
+- else if ( type == "long" )
+- arg << s.toLong();
+- else if ( type == "long int" )
+- arg << s.toLong();
+- else if ( type == "unsigned long" )
+- arg << s.toULong();
+- else if ( type == "unsigned long int" )
+- arg << s.toULong();
+- else if ( type == "float" )
+- arg << s.toFloat();
+- else if ( type == "double" )
+- arg << s.toDouble();
+- else if ( type == "bool" )
+- arg << mkBool( s );
+- else if ( type == "QString" )
+- arg << s;
+- else if ( type == "QCString" )
+- arg << QCString( argv[i] );
+- else if ( type == "QColor" )
+- arg << mkColor( s );
+- else if ( type == "QPoint" )
+- arg << mkPoint( s );
+- else if ( type == "QSize" )
+- arg << mkSize( s );
+- else if ( type == "QRect" )
+- arg << mkRect( s );
+- else if ( type == "QVariant" ) {
+- if ( s == "true" || s == "false" )
+- arg << QVariant( mkBool( s ), 42 );
+- else if ( s.left( 4 ) == "int(" )
+- arg << QVariant( s.mid(4, s.length()-5).toInt() );
+- else if ( s.left( 7 ) == "QPoint(" )
+- arg << QVariant( mkPoint( s.mid(7, s.length()-8) ) );
+- else if ( s.left( 6 ) == "QSize(" )
+- arg << QVariant( mkSize( s.mid(6, s.length()-7) ) );
+- else if ( s.left( 6 ) == "QRect(" )
+- arg << QVariant( mkRect( s.mid(6, s.length()-7) ) );
+- else if ( s.left( 7 ) == "QColor(" )
+- arg << QVariant( mkColor( s.mid(7, s.length()-8) ) );
+- else
+- arg << QVariant( s );
+- } else if ( type.startsWith("QValueList<")) {
+- type = type.mid(11, type.length() - 12);
+- QStringList list;
+- QString delim = s;
+- if (delim == "[")
+- delim = "]";
+- if (delim == "(")
+- delim = ")";
+- i++;
+- QByteArray dummy_data;
+- QDataStream dummy_arg(dummy_data, IO_WriteOnly);
++ if (type == "QStringList")
++ type = "QValueList<QString>";
++ if (type == "QCStringList")
++ type = "QValueList<QCString>";
++ if( i > args.count() )
++ {
++ qWarning("Not enough arguments.");
++ exit(1);
++ }
++ QString s = QString::fromLocal8Bit( args[ i ] );
+
+- int j = i;
+- int count = 0;
+- // Parse list to get the count
+- while (true) {
+- if (j >= argc)
+- {
+- qWarning("List end-delimiter '%s' not found.", delim.latin1());
+- exit(1);
+- }
+- if (argv[j] == delim) break;
+- marshall(dummy_arg, argc, argv, j, type);
+- count++;
+- }
+- arg << (Q_UINT32) count;
+- // Parse the list for real
+- while (true) {
+- if (i >= argc)
+- {
+- qWarning("List end-delimiter '%s' not found.", delim.latin1());
+- exit(1);
+- }
+- if (argv[i] == delim) break;
+- marshall(arg, argc, argv, i, type);
+- }
+- } else {
+- qWarning( "cannot handle datatype '%s'", type.latin1() );
+- exit(1);
+- }
++ if ( type == "int" )
++ arg << s.toInt();
++ else if ( type == "uint" )
++ arg << s.toUInt();
++ else if ( type == "unsigned" )
++ arg << s.toUInt();
++ else if ( type == "unsigned int" )
++ arg << s.toUInt();
++ else if ( type == "long" )
++ arg << s.toLong();
++ else if ( type == "long int" )
++ arg << s.toLong();
++ else if ( type == "unsigned long" )
++ arg << s.toULong();
++ else if ( type == "unsigned long int" )
++ arg << s.toULong();
++ else if ( type == "float" )
++ arg << s.toFloat();
++ else if ( type == "double" )
++ arg << s.toDouble();
++ else if ( type == "bool" )
++ arg << mkBool( s );
++ else if ( type == "QString" )
++ arg << s;
++ else if ( type == "QCString" )
++ arg << QCString( args[ i ] );
++ else if ( type == "QColor" )
++ arg << mkColor( s );
++ else if ( type == "QPoint" )
++ arg << mkPoint( s );
++ else if ( type == "QSize" )
++ arg << mkSize( s );
++ else if ( type == "QRect" )
++ arg << mkRect( s );
++ else if ( type == "QVariant" ) {
++ if ( s == "true" || s == "false" )
++ arg << QVariant( mkBool( s ), 42 );
++ else if ( s.left( 4 ) == "int(" )
++ arg << QVariant( s.mid(4, s.length()-5).toInt() );
++ else if ( s.left( 7 ) == "QPoint(" )
++ arg << QVariant( mkPoint( s.mid(7, s.length()-8) ) );
++ else if ( s.left( 6 ) == "QSize(" )
++ arg << QVariant( mkSize( s.mid(6, s.length()-7) ) );
++ else if ( s.left( 6 ) == "QRect(" )
++ arg << QVariant( mkRect( s.mid(6, s.length()-7) ) );
++ else if ( s.left( 7 ) == "QColor(" )
++ arg << QVariant( mkColor( s.mid(7, s.length()-8) ) );
++ else
++ arg << QVariant( s );
++ } else if ( type.startsWith("QValueList<")) {
++ type = type.mid(11, type.length() - 12);
++ QStringList list;
++ QString delim = s;
++ if (delim == "[")
++ delim = "]";
++ if (delim == "(")
++ delim = ")";
+ i++;
++ QByteArray dummy_data;
++ QDataStream dummy_arg(dummy_data, IO_WriteOnly);
++
++ uint j = i;
++ uint count = 0;
++ // Parse list to get the count
++ while (true) {
++ if( j > args.count() )
++ {
++ qWarning("List end-delimiter '%s' not found.", delim.latin1());
++ exit(1);
++ }
++ if( QString::fromLocal8Bit( args[ j ] ) == delim )
++ break;
++ marshall( dummy_arg, args, j, type );
++ count++;
++ }
++ arg << (Q_UINT32) count;
++ // Parse the list for real
++ while (true) {
++ if( i > args.count() )
++ {
++ qWarning("List end-delimiter '%s' not found.", delim.latin1());
++ exit(1);
++ }
++ if( QString::fromLocal8Bit( args[ i ] ) == delim )
++ break;
++ marshall( arg, args, i, type );
++ }
++ } else {
++ qWarning( "cannot handle datatype '%s'", type.latin1() );
++ exit(1);
++ }
++ i++;
+ }
+
diff --git a/kompare/tests/diff/unifiedp.diff b/kompare/tests/diff/unifiedp.diff
new file mode 100644
index 00000000..891b8b8d
--- /dev/null
+++ b/kompare/tests/diff/unifiedp.diff
@@ -0,0 +1,19 @@
+--- /home/John/lao Thu Apr 12 11:09:30 2001
++++ /home/John/tzu Sat Jul 28 13:23:25 2001
+@@ -1,7 +1,6 @@
+-The Way that can be told of is not the eternal Way;
+-The name that can be named is not the eternal name.
+ The Nameless is the origin of Heaven and Earth;
+-The Named is the mother of all things.
++The named is the mother of all things.
++
+ Therefore let there always be non-being,
+ so we may see their subtlety,
+ And let there always be being,
+@@ -9,3 +8,6 @@ And let there always be being,
+ The two are the same,
+ But after they are produced,
+ they have different names.
++They both may be called deep and profound.
++Deeper and more profound,
++The door of all subtleties!
diff --git a/kompare/tests/perforce/context.diff b/kompare/tests/perforce/context.diff
new file mode 100644
index 00000000..a25c2461
--- /dev/null
+++ b/kompare/tests/perforce/context.diff
@@ -0,0 +1,8 @@
+==== //depot/testje#2 - /home/bruggie/perforce-repo/testje ====
+***************
+*** 3,5 ****
+--- 3,6 ----
+
+ but i
+ 'll see what this is all about later on
++ More lines for #3 to see what happens in a multifile diff
diff --git a/kompare/tests/perforce/contextm.diff b/kompare/tests/perforce/contextm.diff
new file mode 100644
index 00000000..07380b31
--- /dev/null
+++ b/kompare/tests/perforce/contextm.diff
@@ -0,0 +1,23 @@
+==== //depot/craphola#1 - /home/bruggie/perforce-repo/craphola ====
+***************
+*** 2,4 ****
+--- 2,11 ----
+ I'm just adding this file to see what it does with multiple file that have differences
+
+ Now i'll add some text more later in the #2 revision but that has to wait a bit
++
++ This will be a copy and paste of the previous lines just to have some changes for revision 2 of this file
++
++ This is another t4extfile used to test the perforce diff stuff
++ I'm just adding this file to see what it does with multiple file that have differences
++
++ Now i'll add some text more later in the #2 revision but that has to wait a bit
+==== //depot/testje#2 - /home/bruggie/perforce-repo/testje ====
+***************
+*** 3,5 ****
+--- 3,7 ----
+
+ but i
+ 'll see what this is all about later on
++
++ More lines for #3 to see what happens in a multifile diff
diff --git a/kompare/tests/perforce/rcs.diff b/kompare/tests/perforce/rcs.diff
new file mode 100644
index 00000000..ce99087d
--- /dev/null
+++ b/kompare/tests/perforce/rcs.diff
@@ -0,0 +1,3 @@
+==== //depot/testje#2 - /home/bruggie/perforce-repo/testje ====
+a5 1
+More lines for #3 to see what happens in a multifile diff
diff --git a/kompare/tests/perforce/rcsm.diff b/kompare/tests/perforce/rcsm.diff
new file mode 100644
index 00000000..bee028a0
--- /dev/null
+++ b/kompare/tests/perforce/rcsm.diff
@@ -0,0 +1,12 @@
+==== //depot/craphola#1 - /home/bruggie/perforce-repo/craphola ====
+a4 7
+
+This will be a copy and paste of the previous lines just to have some changes for revision 2 of this file
+
+This is another t4extfile used to test the perforce diff stuff
+I'm just adding this file to see what it does with multiple file that have differences
+
+Now i'll add some text more later in the #2 revision but that has to wait a bit
+==== //depot/testje#2 - /home/bruggie/perforce-repo/testje ====
+a5 2
+More lines for #3 to see what happens in a multifile diff
diff --git a/kompare/tests/perforce/unified.diff b/kompare/tests/perforce/unified.diff
new file mode 100644
index 00000000..f9235ba9
--- /dev/null
+++ b/kompare/tests/perforce/unified.diff
@@ -0,0 +1,6 @@
+==== //depot/testje#2 - /home/bruggie/perforce-repo/testje ====
+@@ -3,3 +3,4 @@
+
+ but i
+ 'll see what this is all about later on
++More lines for #3 to see what happens in a multifile diff
diff --git a/kompare/tests/perforce/unifiedm.diff b/kompare/tests/perforce/unifiedm.diff
new file mode 100644
index 00000000..6aa832e7
--- /dev/null
+++ b/kompare/tests/perforce/unifiedm.diff
@@ -0,0 +1,19 @@
+==== //depot/craphola#1 - /home/bruggie/perforce-repo/craphola ====
+@@ -2,3 +2,10 @@
+ I'm just adding this file to see what it does with multiple file that have differences
+
+ Now i'll add some text more later in the #2 revision but that has to wait a bit
++
++This will be a copy and paste of the previous lines just to have some changes for revision 2 of this file
++
++This is another t4extfile used to test the perforce diff stuff
++I'm just adding this file to see what it does with multiple file that have differences
++
++Now i'll add some text more later in the #2 revision but that has to wait a bit
+==== //depot/testje#2 - /home/bruggie/perforce-repo/testje ====
+@@ -3,3 +3,5 @@
+
+ but i
+ 'll see what this is all about later on
++
++More lines for #3 to see what happens in a multifile diff
diff --git a/kompare/tests/subversion/context.diff b/kompare/tests/subversion/context.diff
new file mode 100644
index 00000000..b8380037
--- /dev/null
+++ b/kompare/tests/subversion/context.diff
@@ -0,0 +1,9 @@
+Index: NEWS
+===================================================================
+*** NEWS
+--- NEWS Sun Sep 22 14:34:37 2002
+***************
+*** 1 ****
+!
+--- 1 ----
+! just a fake modif for kompare tests
diff --git a/kompare/tests/subversion/contextm.diff b/kompare/tests/subversion/contextm.diff
new file mode 100644
index 00000000..fbb61263
--- /dev/null
+++ b/kompare/tests/subversion/contextm.diff
@@ -0,0 +1,180 @@
+Index: NEWS
+===================================================================
+*** NEWS
+--- NEWS Sun Sep 22 14:34:37 2002
+***************
+*** 1 ****
+!
+--- 1 ----
+! just a fake modif for kompare tests
+Index: README
+===================================================================
+*** README
+--- README Fri Sep 13 23:05:48 2002
+***************
+*** 1,117 ****
+! Vim KPart
+!
+!
+! by Philippe Fremy <pfremy@kde.com>
+!
+!
+! Okay, I made it : a Vim KPart!
+!
+! This means that you can have Vim embedded inside Konqueror, and everywhere a
+! text ReadWrite or ReadOnly KPart is requested. Actually, there is almost no
+! place right now where this is the case in KDE. KMail uses its own editor,
+! KDEvelop uses its own editor, Kate uses some more powerful Kate component.
+!
+! But this only the beginning. Enabling a part in those programs shouldn't be
+! much hassle and you can probably help me do it. My hope is really to get
+! KDevelop use Vim.
+!
+!
+! ======= OBSOLETE ===========
+! Requirements:
+! -------------
+! To make this KPart work, you need a graphicial Vim version 6 with the client-server stuff feature activated and with the vim60-vimpart-patch.diff applied. The patch is in this dir. I hope to get it into the main Vim tree. KVim has already the patch but is slightly less stable that the original GVim. A big advantage of KVim is that you get the native KDE dialogs when vim asks a question.
+!
+!
+! ======= OBSOLETE ===========
+! Installation:
+! -------------
+! To make your vimpart work, you'll have to go into the vimpart directory and run "testVim your_patched_vim". If the test does work, a file goodVim will be created. You will be able to install and use the component. Else, the test will report why it fails (features missing in vim).
+!
+!
+!
+! ======= OBSOLETE ===========
+! Testing:
+! --------
+! If you want to see your component without installing it, you can do the
+! following:
+!
+! 1. configure, build. Then go into the Vimpart subdirectory.
+!
+! 2. Include the current Vimpart directory in your KDEDIRS:
+! export KDEDIRS=`pwd`:$KDEDIR
+!
+! 3. Symlink .libs to lib
+! ln -s .libs lib
+!
+! 4. Create pseudo share/services dir:
+! mkdir share; mkdir share/services;
+!
+! 5. Symlink to Vimpart.desktop:
+! ln -s Vimpart.desktop share/services/Vimpart.desktop
+!
+! 6. Create a pseudo share/config dir
+! mkdir share/config;
+!
+! 7. Symlink to vimwidgetrc
+! ln -s vimwidgetrc share/config/vimwidgetrc
+!
+! 8. Update the desktop mimetype database:
+! kbuildsycoca
+!
+! To test it, run VimPartShell. Or run konqueror from this dir and click on a
+! text file.
+!
+!
+! ======= OBSOLETE ===========
+! Remarks:
+! --------
+! The initial preference of the Vim KPart is 10. Kate uses 8, so if you install the part, it will override Kate for all the mimetypes. You can always change that by manually editing the initial preference in the desktop file or by simply selecting which editor you prefer for which mimetype in the control center.
+!
+! If you find some mimetype not handled by the Vim KPart although they should be, send me a patch!
+!
+!
+!
+! How it works:
+! -------------
+! At the beginning, we started to write KVim, a port of GVim to KDE to make
+! it possible to embed Vim inside KDE. But with the latest version of Vim, it
+! turns out that it is not necessary to have a native Vim.
+!
+!
+! I use QXembed, a widget which can embed any X application if it knows its X Window Id, using some X feature. The patch I provide will make vim displays its window id on stdout when the window is mapped. GVim 6.0 then provides a way to send commands to a Vim window from another process. If you look at the VimWidget source, you will see that 70% of the code is there to handle the communication process. The rest uses the communication channel to send the vim commands needed by kpart and ktexteditor.
+!
+! As far as I can tell, the part is race-condition free. If you issue many sendNormalCmd and many evalExpr, they are guaranted to be executed sequentially. This has caused me enough problems when it wasn't the case!
+!
+!
+! Qt, KDE2 and KDE3:
+! ------------------
+! The VimWidget itself depends very litle on KDE. It is quite easy to port remove the KDE specific stuff, to use it in a Qt only program. In fact, at the beginning, it was only Qt-based.
+!
+!
+!
+! ======= OBSOLETE ===========
+! Features & TODO:
+! ----------------
+! I think most basic features required by an editor widget or part are supported. There are some possible improvement but I would like more feedback to know what really needs to be done. So don't hesitate to write me about your feelings using this.
+!
+! My TODO list is:
+! - restore the editing mode after sendCmd
+! - implement KTextEditor interface
+! - add some useful actions to the part (like search, ...)
+!
+!
+!
+! Feedback:
+! ---------
+! For the Vim KPart : pfremy@kde.com
+! For KVim: pfremy@kde.org, mikmak@freenux.org, orzel@kde.org
+!
+!
+!
+!
+!
+!
+!
+
+
+
+--- 1,47 ----
+! Yes, that's really a Vim Komponent :)
+! Yes, you can have Vim inside KDE apps, you guessed it :)
+
++ So, it's designed for KDE 3.x (if someone wants to port it to KDE 2 that
++ should be easy), it uses GVim or KVim (even Motif Vim works) 6.x.
++ It can be used in different apps :
++ - KDevelop (version 3)
++ - Konqueror (as a file viewer)
++ - KWrite
++ - KMail (coming in KDE 3.2)
++ - Kompare, KBabel ........ ;)
++
++ CONFIGURATION
++ =============
++ once you compiled and installed it as any other app,
++ start your KDE Control Center, go to the file manager section
++ and open the Vim Component configuration module.
++ Here, you have to select a Vim executable which may be found on
++ your computer (generally /usr/bin/vim) will do it fine for most
++ linux distributions. All you need is that it's a GUI-enabled Vim 6.0 or
++ better.
++ Push the test button, if that's okay then that's should be enough to start
++ using it :)
++
++ FUNCTIONMENT
++ ============
++ Philippe Fremy (pfremy@kde.com) wrote the initial version of this kpart.
++ The concept is to start a normal GUI Vim (like gvim), then "embeds" the Vim
++ window into a KDE Widget.
++ It used to be based on the ClientServer feature of Vim (type :help
++ clientserver in Vim for more info) using external processus to control the
++ embedded Vim. That was running quite fine, but was slow :/
++ We changed that :)
++ Now we communicate directly from the kpart to the embedded Vim thanks to X11
++ without using externals processus. That's much faster and reliable ;)
++ KVim has also another remote control system using KDE's DCOP communication
++ backend.
++ Currently I would advice people to use DCOP when running KVim and using X11
++ communication with GVim (DCOP won't work with GVim anyway).
++ There may be some differences in speed, though I have not noticed it here.
++ The most important difference is that DCOP provides a signal system and that can
++ make a difference to improve the interaction between KVim and the hosting
++ application (KDevelop for example). But it's not yet used.
+
++ Hope you'll enjoy Vim inside KDE :)
++ Mickael "Mikmak" Marchand (marchand@kde.org)
+
diff --git a/kompare/tests/subversion/ed.diff b/kompare/tests/subversion/ed.diff
new file mode 100644
index 00000000..512b3880
--- /dev/null
+++ b/kompare/tests/subversion/ed.diff
@@ -0,0 +1,5 @@
+Index: NEWS
+===================================================================
+1c
+just a fake modif for kompare tests
+.
diff --git a/kompare/tests/subversion/edm.diff b/kompare/tests/subversion/edm.diff
new file mode 100644
index 00000000..dc51b21f
--- /dev/null
+++ b/kompare/tests/subversion/edm.diff
@@ -0,0 +1,57 @@
+Index: NEWS
+===================================================================
+1c
+just a fake modif for kompare tests
+.
+Index: README
+===================================================================
+116a
+Hope you'll enjoy Vim inside KDE :)
+Mickael "Mikmak" Marchand (marchand@kde.org)
+.
+115a
+So, it's designed for KDE 3.x (if someone wants to port it to KDE 2 that
+should be easy), it uses GVim or KVim (even Motif Vim works) 6.x.
+It can be used in different apps :
+ - KDevelop (version 3)
+ - Konqueror (as a file viewer)
+ - KWrite
+ - KMail (coming in KDE 3.2)
+ - Kompare, KBabel ........ ;)
+
+CONFIGURATION
+=============
+once you compiled and installed it as any other app,
+start your KDE Control Center, go to the file manager section
+and open the Vim Component configuration module.
+Here, you have to select a Vim executable which may be found on
+your computer (generally /usr/bin/vim) will do it fine for most
+linux distributions. All you need is that it's a GUI-enabled Vim 6.0 or
+better.
+Push the test button, if that's okay then that's should be enough to start
+using it :)
+
+FUNCTIONMENT
+============
+Philippe Fremy (pfremy@kde.com) wrote the initial version of this kpart.
+The concept is to start a normal GUI Vim (like gvim), then "embeds" the Vim
+window into a KDE Widget.
+It used to be based on the ClientServer feature of Vim (type :help
+clientserver in Vim for more info) using external processus to control the
+embedded Vim. That was running quite fine, but was slow :/
+We changed that :)
+Now we communicate directly from the kpart to the embedded Vim thanks to X11
+without using externals processus. That's much faster and reliable ;)
+KVim has also another remote control system using KDE's DCOP communication
+backend.
+Currently I would advice people to use DCOP when running KVim and using X11
+communication with GVim (DCOP won't work with GVim anyway).
+There may be some differences in speed, though I have not noticed it here.
+The most important difference is that DCOP provides a signal system and that can
+make a difference to improve the interaction between KVim and the hosting
+application (KDevelop for example). But it's not yet used.
+.
+1,114c
+Yes, that's really a Vim Komponent :)
+Yes, you can have Vim inside KDE apps, you guessed it :)
+.
diff --git a/kompare/tests/subversion/normal.diff b/kompare/tests/subversion/normal.diff
new file mode 100644
index 00000000..853cc219
--- /dev/null
+++ b/kompare/tests/subversion/normal.diff
@@ -0,0 +1,6 @@
+Index: NEWS
+===================================================================
+1c1
+<
+---
+> just a fake modif for kompare tests
diff --git a/kompare/tests/subversion/normalm.diff b/kompare/tests/subversion/normalm.diff
new file mode 100644
index 00000000..f526a3b0
--- /dev/null
+++ b/kompare/tests/subversion/normalm.diff
@@ -0,0 +1,170 @@
+Index: NEWS
+===================================================================
+1c1
+<
+---
+> just a fake modif for kompare tests
+Index: README
+===================================================================
+1,114c1,2
+< Vim KPart
+<
+<
+< by Philippe Fremy <pfremy@kde.com>
+<
+<
+< Okay, I made it : a Vim KPart!
+<
+< This means that you can have Vim embedded inside Konqueror, and everywhere a
+< text ReadWrite or ReadOnly KPart is requested. Actually, there is almost no
+< place right now where this is the case in KDE. KMail uses its own editor,
+< KDEvelop uses its own editor, Kate uses some more powerful Kate component.
+<
+< But this only the beginning. Enabling a part in those programs shouldn't be
+< much hassle and you can probably help me do it. My hope is really to get
+< KDevelop use Vim.
+<
+<
+< ======= OBSOLETE ===========
+< Requirements:
+< -------------
+< To make this KPart work, you need a graphicial Vim version 6 with the client-server stuff feature activated and with the vim60-vimpart-patch.diff applied. The patch is in this dir. I hope to get it into the main Vim tree. KVim has already the patch but is slightly less stable that the original GVim. A big advantage of KVim is that you get the native KDE dialogs when vim asks a question.
+<
+<
+< ======= OBSOLETE ===========
+< Installation:
+< -------------
+< To make your vimpart work, you'll have to go into the vimpart directory and run "testVim your_patched_vim". If the test does work, a file goodVim will be created. You will be able to install and use the component. Else, the test will report why it fails (features missing in vim).
+<
+<
+<
+< ======= OBSOLETE ===========
+< Testing:
+< --------
+< If you want to see your component without installing it, you can do the
+< following:
+<
+< 1. configure, build. Then go into the Vimpart subdirectory.
+<
+< 2. Include the current Vimpart directory in your KDEDIRS:
+< export KDEDIRS=`pwd`:$KDEDIR
+<
+< 3. Symlink .libs to lib
+< ln -s .libs lib
+<
+< 4. Create pseudo share/services dir:
+< mkdir share; mkdir share/services;
+<
+< 5. Symlink to Vimpart.desktop:
+< ln -s Vimpart.desktop share/services/Vimpart.desktop
+<
+< 6. Create a pseudo share/config dir
+< mkdir share/config;
+<
+< 7. Symlink to vimwidgetrc
+< ln -s vimwidgetrc share/config/vimwidgetrc
+<
+< 8. Update the desktop mimetype database:
+< kbuildsycoca
+<
+< To test it, run VimPartShell. Or run konqueror from this dir and click on a
+< text file.
+<
+<
+< ======= OBSOLETE ===========
+< Remarks:
+< --------
+< The initial preference of the Vim KPart is 10. Kate uses 8, so if you install the part, it will override Kate for all the mimetypes. You can always change that by manually editing the initial preference in the desktop file or by simply selecting which editor you prefer for which mimetype in the control center.
+<
+< If you find some mimetype not handled by the Vim KPart although they should be, send me a patch!
+<
+<
+<
+< How it works:
+< -------------
+< At the beginning, we started to write KVim, a port of GVim to KDE to make
+< it possible to embed Vim inside KDE. But with the latest version of Vim, it
+< turns out that it is not necessary to have a native Vim.
+<
+<
+< I use QXembed, a widget which can embed any X application if it knows its X Window Id, using some X feature. The patch I provide will make vim displays its window id on stdout when the window is mapped. GVim 6.0 then provides a way to send commands to a Vim window from another process. If you look at the VimWidget source, you will see that 70% of the code is there to handle the communication process. The rest uses the communication channel to send the vim commands needed by kpart and ktexteditor.
+<
+< As far as I can tell, the part is race-condition free. If you issue many sendNormalCmd and many evalExpr, they are guaranted to be executed sequentially. This has caused me enough problems when it wasn't the case!
+<
+<
+< Qt, KDE2 and KDE3:
+< ------------------
+< The VimWidget itself depends very litle on KDE. It is quite easy to port remove the KDE specific stuff, to use it in a Qt only program. In fact, at the beginning, it was only Qt-based.
+<
+<
+<
+< ======= OBSOLETE ===========
+< Features & TODO:
+< ----------------
+< I think most basic features required by an editor widget or part are supported. There are some possible improvement but I would like more feedback to know what really needs to be done. So don't hesitate to write me about your feelings using this.
+<
+< My TODO list is:
+< - restore the editing mode after sendCmd
+< - implement KTextEditor interface
+< - add some useful actions to the part (like search, ...)
+<
+<
+<
+< Feedback:
+< ---------
+< For the Vim KPart : pfremy@kde.com
+< For KVim: pfremy@kde.org, mikmak@freenux.org, orzel@kde.org
+<
+<
+<
+<
+<
+<
+<
+---
+> Yes, that's really a Vim Komponent :)
+> Yes, you can have Vim inside KDE apps, you guessed it :)
+115a4,43
+> So, it's designed for KDE 3.x (if someone wants to port it to KDE 2 that
+> should be easy), it uses GVim or KVim (even Motif Vim works) 6.x.
+> It can be used in different apps :
+> - KDevelop (version 3)
+> - Konqueror (as a file viewer)
+> - KWrite
+> - KMail (coming in KDE 3.2)
+> - Kompare, KBabel ........ ;)
+>
+> CONFIGURATION
+> =============
+> once you compiled and installed it as any other app,
+> start your KDE Control Center, go to the file manager section
+> and open the Vim Component configuration module.
+> Here, you have to select a Vim executable which may be found on
+> your computer (generally /usr/bin/vim) will do it fine for most
+> linux distributions. All you need is that it's a GUI-enabled Vim 6.0 or
+> better.
+> Push the test button, if that's okay then that's should be enough to start
+> using it :)
+>
+> FUNCTIONMENT
+> ============
+> Philippe Fremy (pfremy@kde.com) wrote the initial version of this kpart.
+> The concept is to start a normal GUI Vim (like gvim), then "embeds" the Vim
+> window into a KDE Widget.
+> It used to be based on the ClientServer feature of Vim (type :help
+> clientserver in Vim for more info) using external processus to control the
+> embedded Vim. That was running quite fine, but was slow :/
+> We changed that :)
+> Now we communicate directly from the kpart to the embedded Vim thanks to X11
+> without using externals processus. That's much faster and reliable ;)
+> KVim has also another remote control system using KDE's DCOP communication
+> backend.
+> Currently I would advice people to use DCOP when running KVim and using X11
+> communication with GVim (DCOP won't work with GVim anyway).
+> There may be some differences in speed, though I have not noticed it here.
+> The most important difference is that DCOP provides a signal system and that can
+> make a difference to improve the interaction between KVim and the hosting
+> application (KDevelop for example). But it's not yet used.
+116a45,46
+> Hope you'll enjoy Vim inside KDE :)
+> Mickael "Mikmak" Marchand (marchand@kde.org)
diff --git a/kompare/tests/subversion/rcs.diff b/kompare/tests/subversion/rcs.diff
new file mode 100644
index 00000000..1633c3a3
--- /dev/null
+++ b/kompare/tests/subversion/rcs.diff
@@ -0,0 +1,5 @@
+Index: NEWS
+===================================================================
+d1 1
+a1 1
+just a fake modif for kompare tests
diff --git a/kompare/tests/subversion/rcsm.diff b/kompare/tests/subversion/rcsm.diff
new file mode 100644
index 00000000..a409cd54
--- /dev/null
+++ b/kompare/tests/subversion/rcsm.diff
@@ -0,0 +1,55 @@
+Index: NEWS
+===================================================================
+d1 1
+a1 1
+just a fake modif for kompare tests
+Index: README
+===================================================================
+d1 114
+a114 2
+Yes, that's really a Vim Komponent :)
+Yes, you can have Vim inside KDE apps, you guessed it :)
+a115 40
+So, it's designed for KDE 3.x (if someone wants to port it to KDE 2 that
+should be easy), it uses GVim or KVim (even Motif Vim works) 6.x.
+It can be used in different apps :
+ - KDevelop (version 3)
+ - Konqueror (as a file viewer)
+ - KWrite
+ - KMail (coming in KDE 3.2)
+ - Kompare, KBabel ........ ;)
+
+CONFIGURATION
+=============
+once you compiled and installed it as any other app,
+start your KDE Control Center, go to the file manager section
+and open the Vim Component configuration module.
+Here, you have to select a Vim executable which may be found on
+your computer (generally /usr/bin/vim) will do it fine for most
+linux distributions. All you need is that it's a GUI-enabled Vim 6.0 or
+better.
+Push the test button, if that's okay then that's should be enough to start
+using it :)
+
+FUNCTIONMENT
+============
+Philippe Fremy (pfremy@kde.com) wrote the initial version of this kpart.
+The concept is to start a normal GUI Vim (like gvim), then "embeds" the Vim
+window into a KDE Widget.
+It used to be based on the ClientServer feature of Vim (type :help
+clientserver in Vim for more info) using external processus to control the
+embedded Vim. That was running quite fine, but was slow :/
+We changed that :)
+Now we communicate directly from the kpart to the embedded Vim thanks to X11
+without using externals processus. That's much faster and reliable ;)
+KVim has also another remote control system using KDE's DCOP communication
+backend.
+Currently I would advice people to use DCOP when running KVim and using X11
+communication with GVim (DCOP won't work with GVim anyway).
+There may be some differences in speed, though I have not noticed it here.
+The most important difference is that DCOP provides a signal system and that can
+make a difference to improve the interaction between KVim and the hosting
+application (KDevelop for example). But it's not yet used.
+a116 2
+Hope you'll enjoy Vim inside KDE :)
+Mickael "Mikmak" Marchand (marchand@kde.org)
diff --git a/kompare/tests/subversion/unified.diff b/kompare/tests/subversion/unified.diff
new file mode 100644
index 00000000..fca49ace
--- /dev/null
+++ b/kompare/tests/subversion/unified.diff
@@ -0,0 +1,7 @@
+Index: NEWS
+===================================================================
+--- NEWS
++++ NEWS 2002-09-22 14:34:37.000000000 +0200
+@@ -1 +1 @@
+-
++just a fake modif for kompare tests
diff --git a/kompare/tests/subversion/unifiedm.diff b/kompare/tests/subversion/unifiedm.diff
new file mode 100644
index 00000000..29a07705
--- /dev/null
+++ b/kompare/tests/subversion/unifiedm.diff
@@ -0,0 +1,173 @@
+Index: NEWS
+===================================================================
+--- NEWS
++++ NEWS 2002-09-22 14:34:37.000000000 +0200
+@@ -1 +1 @@
+-
++just a fake modif for kompare tests
+Index: README
+===================================================================
+--- README
++++ README 2002-09-13 23:05:48.000000000 +0200
+@@ -1,117 +1,47 @@
+- Vim KPart
+-
+-
+- by Philippe Fremy <pfremy@kde.com>
+-
+-
+-Okay, I made it : a Vim KPart!
+-
+-This means that you can have Vim embedded inside Konqueror, and everywhere a
+-text ReadWrite or ReadOnly KPart is requested. Actually, there is almost no
+-place right now where this is the case in KDE. KMail uses its own editor,
+-KDEvelop uses its own editor, Kate uses some more powerful Kate component.
+-
+-But this only the beginning. Enabling a part in those programs shouldn't be
+-much hassle and you can probably help me do it. My hope is really to get
+-KDevelop use Vim.
+-
+-
+-======= OBSOLETE ===========
+-Requirements:
+--------------
+-To make this KPart work, you need a graphicial Vim version 6 with the client-server stuff feature activated and with the vim60-vimpart-patch.diff applied. The patch is in this dir. I hope to get it into the main Vim tree. KVim has already the patch but is slightly less stable that the original GVim. A big advantage of KVim is that you get the native KDE dialogs when vim asks a question.
+-
+-
+-======= OBSOLETE ===========
+-Installation:
+--------------
+-To make your vimpart work, you'll have to go into the vimpart directory and run "testVim your_patched_vim". If the test does work, a file goodVim will be created. You will be able to install and use the component. Else, the test will report why it fails (features missing in vim).
+-
+-
+-
+-======= OBSOLETE ===========
+-Testing:
+---------
+-If you want to see your component without installing it, you can do the
+-following:
+-
+-1. configure, build. Then go into the Vimpart subdirectory.
+-
+-2. Include the current Vimpart directory in your KDEDIRS:
+-export KDEDIRS=`pwd`:$KDEDIR
+-
+-3. Symlink .libs to lib
+-ln -s .libs lib
+-
+-4. Create pseudo share/services dir:
+-mkdir share; mkdir share/services;
+-
+-5. Symlink to Vimpart.desktop:
+-ln -s Vimpart.desktop share/services/Vimpart.desktop
+-
+-6. Create a pseudo share/config dir
+-mkdir share/config;
+-
+-7. Symlink to vimwidgetrc
+-ln -s vimwidgetrc share/config/vimwidgetrc
+-
+-8. Update the desktop mimetype database:
+-kbuildsycoca
+-
+-To test it, run VimPartShell. Or run konqueror from this dir and click on a
+-text file.
+-
+-
+-======= OBSOLETE ===========
+-Remarks:
+---------
+-The initial preference of the Vim KPart is 10. Kate uses 8, so if you install the part, it will override Kate for all the mimetypes. You can always change that by manually editing the initial preference in the desktop file or by simply selecting which editor you prefer for which mimetype in the control center.
+-
+-If you find some mimetype not handled by the Vim KPart although they should be, send me a patch!
+-
+-
+-
+-How it works:
+--------------
+-At the beginning, we started to write KVim, a port of GVim to KDE to make
+-it possible to embed Vim inside KDE. But with the latest version of Vim, it
+-turns out that it is not necessary to have a native Vim.
+-
+-
+-I use QXembed, a widget which can embed any X application if it knows its X Window Id, using some X feature. The patch I provide will make vim displays its window id on stdout when the window is mapped. GVim 6.0 then provides a way to send commands to a Vim window from another process. If you look at the VimWidget source, you will see that 70% of the code is there to handle the communication process. The rest uses the communication channel to send the vim commands needed by kpart and ktexteditor.
+-
+-As far as I can tell, the part is race-condition free. If you issue many sendNormalCmd and many evalExpr, they are guaranted to be executed sequentially. This has caused me enough problems when it wasn't the case!
+-
+-
+-Qt, KDE2 and KDE3:
+-------------------
+-The VimWidget itself depends very litle on KDE. It is quite easy to port remove the KDE specific stuff, to use it in a Qt only program. In fact, at the beginning, it was only Qt-based.
+-
+-
+-
+-======= OBSOLETE ===========
+-Features & TODO:
+-----------------
+-I think most basic features required by an editor widget or part are supported. There are some possible improvement but I would like more feedback to know what really needs to be done. So don't hesitate to write me about your feelings using this.
+-
+-My TODO list is:
+-- restore the editing mode after sendCmd
+-- implement KTextEditor interface
+-- add some useful actions to the part (like search, ...)
+-
+-
+-
+-Feedback:
+----------
+-For the Vim KPart : pfremy@kde.com
+-For KVim: pfremy@kde.org, mikmak@freenux.org, orzel@kde.org
+-
+-
+-
+-
+-
+-
+-
++Yes, that's really a Vim Komponent :)
++Yes, you can have Vim inside KDE apps, you guessed it :)
+
++So, it's designed for KDE 3.x (if someone wants to port it to KDE 2 that
++should be easy), it uses GVim or KVim (even Motif Vim works) 6.x.
++It can be used in different apps :
++ - KDevelop (version 3)
++ - Konqueror (as a file viewer)
++ - KWrite
++ - KMail (coming in KDE 3.2)
++ - Kompare, KBabel ........ ;)
++
++CONFIGURATION
++=============
++once you compiled and installed it as any other app,
++start your KDE Control Center, go to the file manager section
++and open the Vim Component configuration module.
++Here, you have to select a Vim executable which may be found on
++your computer (generally /usr/bin/vim) will do it fine for most
++linux distributions. All you need is that it's a GUI-enabled Vim 6.0 or
++better.
++Push the test button, if that's okay then that's should be enough to start
++using it :)
++
++FUNCTIONMENT
++============
++Philippe Fremy (pfremy@kde.com) wrote the initial version of this kpart.
++The concept is to start a normal GUI Vim (like gvim), then "embeds" the Vim
++window into a KDE Widget.
++It used to be based on the ClientServer feature of Vim (type :help
++clientserver in Vim for more info) using external processus to control the
++embedded Vim. That was running quite fine, but was slow :/
++We changed that :)
++Now we communicate directly from the kpart to the embedded Vim thanks to X11
++without using externals processus. That's much faster and reliable ;)
++KVim has also another remote control system using KDE's DCOP communication
++backend.
++Currently I would advice people to use DCOP when running KVim and using X11
++communication with GVim (DCOP won't work with GVim anyway).
++There may be some differences in speed, though I have not noticed it here.
++The most important difference is that DCOP provides a signal system and that can
++make a difference to improve the interaction between KVim and the hosting
++application (KDevelop for example). But it's not yet used.
+
++Hope you'll enjoy Vim inside KDE :)
++Mickael "Mikmak" Marchand (marchand@kde.org)
+
diff --git a/kprofilemethod/Makefile.am b/kprofilemethod/Makefile.am
new file mode 100644
index 00000000..0d2aa3f6
--- /dev/null
+++ b/kprofilemethod/Makefile.am
@@ -0,0 +1,2 @@
+include_HEADERS = kprofilemethod.h
+
diff --git a/kprofilemethod/README b/kprofilemethod/README
new file mode 100644
index 00000000..543e841c
--- /dev/null
+++ b/kprofilemethod/README
@@ -0,0 +1,21 @@
+As the docu in kprofilemethod.h says:
+
+ Those macros help profiling using QTime.
+ They allow to sum up the time taken by a given bit of code
+ in a method called several times.
+ This way one can find out which low-level method used by a high-level
+ method is taking most of its time.
+
+WARNING:
+
+ Please do not commit code that uses kprofilemethod.h
+ Since not everyone has kdesdk installed, it won't build for everyone.
+ This is a tool to be used for a one-time profiling, and then you need
+ to remove all its traces before committing.
+
+TODO:
+
+ KDevelop, XEmacs and vi shortcuts to insert begin/end macros around a block
+ of code (e.g. after selecting it) - this macro would also insert the
+ int variable, and another shortcut for inserting the print macro.
+
diff --git a/kprofilemethod/kprofilemethod.h b/kprofilemethod/kprofilemethod.h
new file mode 100644
index 00000000..fc5ecbe1
--- /dev/null
+++ b/kprofilemethod/kprofilemethod.h
@@ -0,0 +1,51 @@
+/* This file is part of the KDE project
+ Copyright (C) 2002 David Faure <faure@kde.org>
+
+ This program 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 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this program; see the file COPYING. If not, write to
+ the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+*/
+
+#ifndef KPROFILE_METHOD_H
+#define KPROFILE_METHOD_H
+
+#include <qdatetime.h>
+#include <kdebug.h>
+
+/**
+ * Those macros help profiling using QTime.
+ * They allow to sum up the time taken by a given bit of code
+ * in a method called several times.
+ * This way one can find out which low-level method used by a high-level
+ * method is taking most of its time
+ *
+ *
+ * Declare the var somewhere, out of any method:
+ * int pr_theMethod = 0;
+ * (the name pr_* helps finding and removing all of this before committing)
+ *
+ * Then in the method, around the code to be timed:
+ * PROFILE_METHOD_BEGIN( pr_theMethod );
+ * ...
+ * PROFILE_METHOD_END( pr_theMethod );
+ *
+ * And finally, to see the result, put this call in a method
+ * called after all that (destructor, program exit...)
+ * PROFILE_METHOD_PRINT( pr_theMethod, "theMethod" );
+ *
+ */
+#define PROFILE_METHOD_BEGIN(sym) extern int sym; QTime profile_dt##sym; profile_dt##sym.start();
+#define PROFILE_METHOD_END(sym) extern int sym; sym += profile_dt##sym.elapsed();
+#define PROFILE_METHOD_PRINT(sym, name) extern int sym; kdDebug() << name << " took " << sym << " milliseconds" << endl;
+
+#endif // KPROFILE_METHOD_H
diff --git a/kspy/Makefile.am b/kspy/Makefile.am
new file mode 100644
index 00000000..37af3c20
--- /dev/null
+++ b/kspy/Makefile.am
@@ -0,0 +1,30 @@
+
+lib_LTLIBRARIES = libkspy.la
+libkspy_la_SOURCES = navviewitem.cpp propsview.cpp navview.cpp spy.cpp sigslotview.cpp \
+ receiversview.cpp classinfoview.cpp
+
+include_HEADERS = kspy.h
+
+noinst_HEADERS = spy.h navview.h propsview.h navviewitem.h receiversview.h classinfoview.h
+
+libkspy_la_LIBADD = $(LIB_QT) $(LIB_KDECORE) $(LIB_KDEUI) $(LIBSOCKET)
+
+# set the include path for X, qt and KDE
+INCLUDES= $(all_includes)
+
+libkspy_la_LDFLAGS = $(all_libraries) -version-info 3:0:2 -no-undefined $(USER_LDFLAGS)
+
+EXTRA_DIST = main.cpp spy.cpp spy.h navview.cpp navview.h propsview.cpp \
+ propsview.h navviewitem.cpp navviewitem.h sigslotview.h receiversview.h classinfoview.h
+
+METASOURCES = AUTO
+
+messages:
+ 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`; \
+ if test -n "$$LIST"; then \
+ $(XGETTEXT) $$LIST -o $(podir)/spy.pot; \
+ fi
+
+check_PROGRAMS = testkspy
+testkspy_SOURCES = main.cpp
+testkspy_LDADD = libkspy.la
diff --git a/kspy/README b/kspy/README
new file mode 100644
index 00000000..ad810112
--- /dev/null
+++ b/kspy/README
@@ -0,0 +1,12 @@
+KSpy
+====
+
+KSpy is a utility intended to help developers examine the internal
+state of a Qt/KDE application. KSpy graphically displays all the
+QObjects in use, and allows you to browse their properties. Using KSpy
+is very simple, include kspy.h and call KSpy::invoke() when you want
+to looks inside your app. The KSpy function is inline and the main
+part of KSpy is dynamically loaded, so you may even want to leave this
+in the release build of an application.
+
+Richard Moore, <rich@kde.org>
diff --git a/kspy/classinfoview.cpp b/kspy/classinfoview.cpp
new file mode 100644
index 00000000..1b976cfa
--- /dev/null
+++ b/kspy/classinfoview.cpp
@@ -0,0 +1,58 @@
+/***************************************************************************
+ classinfoview.cpp - description
+ -------------------
+ begin : Tue Jan 11 2005
+ copyright : (C) 2005 by Richard Dale
+ email : Richard_Dale@tipitina.demon.co.uk
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the 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 <qobjectdict.h>
+#include <qobjectlist.h>
+#include <qmetaobject.h>
+#include <qstrlist.h>
+#include <qvariant.h>
+
+#include <klocale.h>
+
+#include "classinfoview.h"
+
+ClassInfoView::ClassInfoView(QWidget *parent, const char *name ) : KListView(parent,name)
+{
+ addColumn( i18n( "Name" ) );
+ addColumn( i18n( "Value" ) );
+
+ setRootIsDecorated( true );
+ setAllColumnsShowFocus( true );
+ setFullWidth( true );
+}
+
+ClassInfoView::~ClassInfoView()
+{
+}
+
+void ClassInfoView::buildList( QObject *o )
+{
+ QMetaObject *mo = o->metaObject();
+
+ for (int index = 0; index < mo->numClassInfo(true); index++) {
+ const QClassInfo * classInfo = mo->classInfo(index, true);
+ new KListViewItem( this, classInfo->name, classInfo->value );
+ }
+}
+
+void ClassInfoView::setTarget( QObject *o )
+{
+ clear();
+ buildList( o );
+}
+
+#include "classinfoview.moc"
diff --git a/kspy/classinfoview.h b/kspy/classinfoview.h
new file mode 100644
index 00000000..e8b4440b
--- /dev/null
+++ b/kspy/classinfoview.h
@@ -0,0 +1,40 @@
+/***************************************************************************
+ classinfoview.h - description
+ -------------------
+ begin : Tue Jan 11 2005
+ copyright : (C) 2005 by Richard Dale
+ email : Richard_Dale@tipitina.demon.co.uk
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the 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 CLASSINFOVIEW_H
+#define CLASSINFOVIEW_H
+
+#include <qwidget.h>
+#include <klistview.h>
+
+/**
+ *@author Richard Dale
+ */
+
+class ClassInfoView : public KListView {
+ Q_OBJECT
+public:
+ ClassInfoView(QWidget *parent=0, const char *name=0);
+ ~ClassInfoView();
+
+ void buildList( QObject *o );
+
+public slots:
+ void setTarget( QObject * );
+};
+
+#endif
diff --git a/kspy/kspy.h b/kspy/kspy.h
new file mode 100644
index 00000000..e2878125
--- /dev/null
+++ b/kspy/kspy.h
@@ -0,0 +1,44 @@
+// -*- c++ -*-
+
+#ifndef KSPY_H
+#define KSPY_H
+
+#include <klibloader.h>
+
+/**
+ * Loader for the QObject debugging tool. The usage is simple, just call
+ * KSpy::invoke(), then use the spy window to examine the state of your
+ * QObjects.
+ *
+ * @author Richard Moore, rich@kde.org
+ * @version $Id$
+ */
+class KSpy
+{
+public:
+ /**
+ * Loads and invokes the KSpy utility.
+ */
+ static void invoke() {
+ KLibLoader *loader = KLibLoader::self();
+ KLibrary *lib = loader->library( "libkspy" );
+
+ if ( !lib ) {
+ qWarning( "Unable to load KSpy library\n" );
+ return;
+ }
+
+ lib->factory(); // Ensure the factory is loaded
+
+ // We don't need to do any more, KSpy is fired up by the loader hook
+ // in the shared library.
+ }
+
+private:
+ // Prevent instantiation.
+ KSpy() {}
+ ~KSpy() {}
+};
+
+#endif // KSPY_H
+
diff --git a/kspy/main.cpp b/kspy/main.cpp
new file mode 100644
index 00000000..ab8a3594
--- /dev/null
+++ b/kspy/main.cpp
@@ -0,0 +1,52 @@
+/***************************************************************************
+ main.cpp - description
+ -------------------
+ begin : Tue May 1 02:59:33 BST 2001
+ copyright : (C) 2001 by Richard Moore
+ email : rich@kde.org
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the 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 <kcmdlineargs.h>
+#include <kaboutdata.h>
+#include <klocale.h>
+
+#include "spy.h"
+
+static const char description[] =
+ I18N_NOOP("Spy");
+// INSERT A DESCRIPTION FOR YOUR APPLICATION HERE
+
+
+static KCmdLineOptions options[] =
+{
+ KCmdLineLastOption
+ // INSERT YOUR COMMANDLINE OPTIONS HERE
+};
+
+int main(int argc, char *argv[])
+{
+
+ KAboutData aboutData( "spy", I18N_NOOP("Spy"),
+ VERSION, description, KAboutData::License_GPL,
+ "(c) 2001, Richard Moore", 0, 0, "rich@kde.org");
+ aboutData.addAuthor("Richard Moore",0, "rich@kde.org");
+ KCmdLineArgs::init( argc, argv, &aboutData );
+ KCmdLineArgs::addCmdLineOptions( options ); // Add our own options.
+
+ KApplication a;
+ Spy *spy = new Spy();
+ a.setMainWidget(spy);
+
+ spy->show();
+
+ return a.exec();
+}
diff --git a/kspy/navview.cpp b/kspy/navview.cpp
new file mode 100644
index 00000000..8f6afc8e
--- /dev/null
+++ b/kspy/navview.cpp
@@ -0,0 +1,88 @@
+/***************************************************************************
+ navview.cpp - description
+ -------------------
+ begin : Tue May 1 2001
+ copyright : (C) 2001 by Richard Moore
+ email : rich@kde.org
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the 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 <qobjectlist.h>
+#include <qobjectdict.h>
+
+#include <klocale.h>
+
+#include "navview.h"
+#include "navviewitem.h"
+
+NavView::NavView(QWidget *parent, const char *name ) : KListView(parent,name)
+{
+ addColumn( i18n( "Name" ) );
+ addColumn( i18n( "Type" ) );
+
+ setRootIsDecorated( true );
+ setAllColumnsShowFocus( true );
+ setFullWidth( true );
+
+ connect( this, SIGNAL( selectionChanged( QListViewItem * ) ),
+ this, SLOT( selectItem( QListViewItem * ) ) );
+}
+
+NavView::~NavView(){
+}
+
+void NavView::buildTree()
+{
+ const QObjectList *roots = QObject::objectTrees();
+ QObjectListIt it( *roots );
+
+ QObject * obj;
+ while ( (obj = it.current()) != 0 ) {
+ ++it;
+ NavViewItem *item = new NavViewItem( this, obj );
+ createSubTree( item );
+ }
+}
+
+void NavView::expandVisibleTree()
+{
+ QListViewItemIterator it( this, QListViewItemIterator::Visible |
+ QListViewItemIterator::Expandable );
+
+ while ( it.current() ) {
+ setOpen( *it, true );
+ ++it;
+ }
+}
+
+void NavView::selectItem( QListViewItem *item )
+{
+ NavViewItem *navItem = static_cast<NavViewItem*>( item );
+
+ emit selected( navItem->data );
+}
+
+void NavView::createSubTree( NavViewItem *parent )
+{
+ const QObjectList *kids = parent->data->children();
+ if ( !kids )
+ return;
+
+ QObject * obj;
+ QObjectListIt it( *kids );
+ while ( (obj=it.current()) != 0 ) {
+ ++it;
+ NavViewItem *item = new NavViewItem( parent, obj );
+ createSubTree( item );
+ }
+}
+
+#include "navview.moc"
diff --git a/kspy/navview.h b/kspy/navview.h
new file mode 100644
index 00000000..326f7790
--- /dev/null
+++ b/kspy/navview.h
@@ -0,0 +1,57 @@
+/***************************************************************************
+ navview.h - description
+ -------------------
+ begin : Tue May 1 2001
+ copyright : (C) 2001 by Richard Moore
+ email : rich@kde.org
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the 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 NAVVIEW_H
+#define NAVVIEW_H
+
+#include <qwidget.h>
+#include <klistview.h>
+
+class NavViewItem;
+
+/**
+ * @author Richard Moore
+ */
+class NavView : public KListView
+{
+ Q_OBJECT
+
+ public:
+ NavView( QWidget *parent = 0, const char *name = 0 );
+ ~NavView();
+
+ /**
+ Builds the complete tree.
+ */
+ void buildTree();
+
+ /**
+ Expands all currently visible items.
+ */
+ void expandVisibleTree();
+
+ signals:
+ void selected( QObject *object );
+
+ protected slots:
+ void selectItem( QListViewItem *item );
+
+ private:
+ void createSubTree( NavViewItem* );
+};
+
+#endif
diff --git a/kspy/navviewitem.cpp b/kspy/navviewitem.cpp
new file mode 100644
index 00000000..de372b4f
--- /dev/null
+++ b/kspy/navviewitem.cpp
@@ -0,0 +1,40 @@
+/***************************************************************************
+ navviewitem.cpp - description
+ -------------------
+ begin : Tue May 1 2001
+ copyright : (C) 2001 by Richard Moore
+ email : rich@kde.org
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the 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 <qobject.h>
+
+#include "navview.h"
+#include "navviewitem.h"
+
+NavViewItem::NavViewItem(NavView *parent, QObject *obj )
+ : KListViewItem(parent, obj->name(), obj->className() )
+{
+ data = obj;
+ setExpandable( true );
+}
+
+NavViewItem::NavViewItem(NavViewItem *parent, QObject *obj )
+ : KListViewItem(parent, obj->name(), obj->className() )
+{
+ data = obj;
+ setExpandable( true );
+}
+
+NavViewItem::~NavViewItem()
+{
+}
+
diff --git a/kspy/navviewitem.h b/kspy/navviewitem.h
new file mode 100644
index 00000000..35a66c07
--- /dev/null
+++ b/kspy/navviewitem.h
@@ -0,0 +1,38 @@
+/***************************************************************************
+ navviewitem.h - description
+ -------------------
+ begin : Tue May 1 2001
+ copyright : (C) 2001 by Richard Moore
+ email : rich@kde.org
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the 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 NAVVIEWITEM_H
+#define NAVVIEWITEM_H
+
+#include <qlistview.h>
+
+class NavView;
+
+/**
+ *@author Richard Moore
+ */
+
+class NavViewItem : public KListViewItem {
+public:
+ NavViewItem(NavView *parent, QObject *item );
+ NavViewItem(NavViewItem *parent, QObject *item );
+ ~NavViewItem();
+
+ QObject *data;
+};
+
+#endif
diff --git a/kspy/propsview.cpp b/kspy/propsview.cpp
new file mode 100644
index 00000000..12b855c0
--- /dev/null
+++ b/kspy/propsview.cpp
@@ -0,0 +1,196 @@
+/***************************************************************************
+ propsview.cpp - description
+ -------------------
+ begin : Tue May 1 2001
+ copyright : (C) 2001 by Richard Moore
+ email : rich@kde.org
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the 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 <qobjectdict.h>
+#include <qobjectlist.h>
+#include <qmetaobject.h>
+#include <qstrlist.h>
+#include <qvariant.h>
+#include <qcursor.h>
+
+#include <klocale.h>
+
+#include "propsview.h"
+
+class KSpyItem : KListViewItem
+{
+public:
+ KSpyItem( QListView * parent, QString label1, QString label2 = QString::null, QString label3 = QString::null, QString label4 = QString::null, QString label5 = QString::null, QString label6 = QString::null )
+ : KListViewItem(parent, label1, label2, label3, label4, label5, label6)
+ {
+ }
+protected:
+ void paintCell( QPainter * p, const QColorGroup & cg,
+ int column, int width, int alignment )
+ {
+ if (column == 1 && text(2) == "QColor") {
+ QColorGroup color_cg( cg.foreground(), cg.background(),
+ cg.light(), cg.dark(), cg.mid(),
+ QColor(text(1)), QColor(text(1)) );
+ QListViewItem::paintCell(p, color_cg, column, width, alignment);
+ } else {
+ KListViewItem::paintCell(p, cg, column, width, alignment);
+ }
+ }
+};
+
+PropsView::PropsView(QWidget *parent, const char *name ) : KListView(parent,name)
+{
+ addColumn( i18n( "Name" ) );
+ addColumn( i18n( "Value" ) );
+ addColumn( i18n( "Type" ) );
+ addColumn( i18n( "Access" ) );
+ addColumn( i18n( "Designable" ) );
+ addColumn( i18n( "Type Flags" ) );
+
+ setAllColumnsShowFocus( true );
+ setColumnAlignment( 3, AlignCenter );
+ setColumnAlignment( 4, AlignCenter );
+ setFullWidth( true );
+}
+
+PropsView::~PropsView()
+{
+}
+
+void PropsView::buildList( QObject *o )
+{
+ QMetaObject *mo = o->metaObject();
+ QStrList names = mo->propertyNames( true );
+
+ for ( uint i = 0; i < names.count(); i++ ) {
+ char *prop = names.at( i );
+ QVariant v = o->property( prop );
+ const QMetaProperty *mp = mo->property( mo->findProperty(prop, true), true );
+
+ QString val( "????" );
+ switch( v.type() ) {
+ case QVariant::String:
+ case QVariant::CString:
+ val = v.toString();
+ break;
+ case QVariant::Bool:
+ val = ( v.toBool() ? "True" : "False" );
+ break;
+ case QVariant::Color:
+ {
+ QColor c = v.toColor();
+ val = c.name();
+ break;
+ }
+ case QVariant::Cursor:
+ {
+ QCursor c = v.toCursor();
+ val = QString("shape=%1").arg(c.shape());
+ break;
+ }
+ case QVariant::Font:
+ {
+ QFont f = v.toFont();
+ val = QString("family=%1, pointSize=%2, weight=%3, italic=%4, bold=%5, underline=%6, strikeOut=%7")
+ .arg(f.family())
+ .arg(f.pointSize())
+ .arg(f.weight())
+ .arg(f.italic())
+ .arg(f.bold())
+ .arg(f.underline())
+ .arg(f.strikeOut());
+ break;
+ }
+ case QVariant::Int:
+ val.setNum( v.toInt() );
+ if (mp->isEnumType()) {
+ QMetaObject * metaObject = *(mp->meta);
+ val = QString("%1::%2").arg(metaObject->className()).arg(mp->valueToKey(val.toInt()));
+ }
+ break;
+ case QVariant::Point:
+ {
+ QPoint p = v.toPoint();
+ val = QString("x=%1, y=%2").arg(p.x()).arg(p.y());
+ break;
+ }
+ case QVariant::Rect:
+ {
+ QRect r = v.toRect();
+ val = QString("left=%1, right=%2, top=%3, bottom=%4")
+ .arg(r.left())
+ .arg(r.right())
+ .arg(r.top())
+ .arg(r.bottom());
+ break;
+ }
+ case QVariant::Size:
+ {
+ QSize s = v.toSize();
+ val = QString("width=%1, height=%2").arg(s.width()).arg(s.height());
+ break;
+ }
+ case QVariant::SizePolicy:
+ {
+ QSizePolicy s = v.toSizePolicy();
+ val = QString("horData=%1, verData=%2").arg(s.horData()).arg(s.verData());
+ break;
+ }
+ case QVariant::Double:
+ val.setNum( v.toDouble() );
+ break;
+ default:
+ break;
+ }
+
+ QString ro("R/O");
+ QString rw("R/W");
+ QString st("Set");
+ QString et("Enum");
+ QString yes("Yes");
+ QString no("No");
+
+ QString writable = ( mp->writable() ? rw : ro );
+ QString setType = ( mp->isSetType() ? st : QString::null );
+ QString enumType = ( mp->isEnumType() ? et : QString::null );
+ QString designable = ( mp->designable(o) ? yes : no );
+
+ QString flags;
+ bool first = true;
+ if ( !setType.isNull() ) {
+ if ( first )
+ first = false;
+ else
+ flags += " | ";
+
+ flags += setType;
+ }
+ if ( !enumType.isNull() ) {
+ if ( first )
+ first = false;
+ else
+ flags += " | ";
+
+ flags += enumType;
+ }
+
+ new KSpyItem( this, prop, val, v.typeName(), writable, designable, flags );
+ }
+}
+
+void PropsView::setTarget( QObject *o )
+{
+ clear();
+ buildList( o );
+}
+#include "propsview.moc"
diff --git a/kspy/propsview.h b/kspy/propsview.h
new file mode 100644
index 00000000..62eb5e8d
--- /dev/null
+++ b/kspy/propsview.h
@@ -0,0 +1,40 @@
+/***************************************************************************
+ propsview.h - description
+ -------------------
+ begin : Tue May 1 2001
+ copyright : (C) 2001 by Richard Moore
+ email : rich@kde.org
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the 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 PROPSVIEW_H
+#define PROPSVIEW_H
+
+#include <qwidget.h>
+#include <klistview.h>
+
+/**
+ *@author Richard Moore
+ */
+
+class PropsView : public KListView {
+ Q_OBJECT
+public:
+ PropsView(QWidget *parent=0, const char *name=0);
+ ~PropsView();
+
+ void buildList( QObject *o );
+
+public slots:
+ void setTarget( QObject * );
+};
+
+#endif
diff --git a/kspy/receiversview.cpp b/kspy/receiversview.cpp
new file mode 100644
index 00000000..e1da1127
--- /dev/null
+++ b/kspy/receiversview.cpp
@@ -0,0 +1,80 @@
+/***************************************************************************
+ receiversview.cpp - description
+ -------------------
+ begin : Tue Jan 11 2005
+ copyright : (C) 2005 by Richard Dale
+ email : Richard_Dale@tipitina.demon.co.uk
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the 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 <qobjectdict.h>
+#include <qobjectlist.h>
+#include <qmetaobject.h>
+#include <qstrlist.h>
+#include <qvariant.h>
+#include <qsignalslotimp.h>
+
+#include <klocale.h>
+
+#include "receiversview.h"
+
+class UnencapsulatedQObject : public QObject {
+public:
+ QConnectionList *public_receivers(int signal) const { return receivers(signal); }
+};
+
+ReceiversView::ReceiversView(QWidget *parent, const char *name ) : KListView(parent,name)
+{
+ addColumn( i18n( "Object" ) );
+ addColumn( i18n( "Type" ) );
+ addColumn( i18n( "Member Name" ) );
+
+ setRootIsDecorated( true );
+ setAllColumnsShowFocus( true );
+ setFullWidth( true );
+}
+
+ReceiversView::~ReceiversView()
+{
+}
+
+void ReceiversView::buildList( QObject *o )
+{
+ QMetaObject *mo = o->metaObject();
+
+ UnencapsulatedQObject * qobject = (UnencapsulatedQObject *) o;
+ QStrList signalNames = mo->signalNames(true);
+
+ for (int sig = 0; sig < mo->numSignals(true); sig++) {
+ QConnectionList * clist = qobject->public_receivers(sig);
+ if (clist != 0) {
+ KListViewItem *conn = new KListViewItem( this, signalNames.at(sig) );
+
+ for ( QConnection * connection = clist->first();
+ connection != 0;
+ connection = clist->next() )
+ {
+ new KListViewItem( conn,
+ connection->object()->name(),
+ connection->memberType() == 1 ? "SLOT" : "SIGNAL",
+ connection->memberName() );
+ }
+ }
+ }
+}
+
+void ReceiversView::setTarget( QObject *o )
+{
+ clear();
+ buildList( o );
+}
+
+#include "receiversview.moc"
diff --git a/kspy/receiversview.h b/kspy/receiversview.h
new file mode 100644
index 00000000..31768883
--- /dev/null
+++ b/kspy/receiversview.h
@@ -0,0 +1,40 @@
+/***************************************************************************
+ receiversview.h - description
+ -------------------
+ begin : Tue Jan 11 2005
+ copyright : (C) 2005 by Richard Dale
+ email : Richard_Dale@tipitina.demon.co.uk
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the 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 RECEIVERSVIEW_H
+#define RECEIVERSVIEW_H
+
+#include <qwidget.h>
+#include <klistview.h>
+
+/**
+ *@author Richard Dale
+ */
+
+class ReceiversView : public KListView {
+ Q_OBJECT
+public:
+ ReceiversView(QWidget *parent=0, const char *name=0);
+ ~ReceiversView();
+
+ void buildList( QObject *o );
+
+public slots:
+ void setTarget( QObject * );
+};
+
+#endif
diff --git a/kspy/sigslotview.cpp b/kspy/sigslotview.cpp
new file mode 100644
index 00000000..2e04cfa7
--- /dev/null
+++ b/kspy/sigslotview.cpp
@@ -0,0 +1,73 @@
+/***************************************************************************
+ sigslotview.cpp - description
+ -------------------
+ begin : Tue May 1 2001
+ copyright : (C) 2001 by Richard Moore
+ email : rich@kde.org
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the 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 <qobjectdict.h>
+#include <qobjectlist.h>
+#include <qmetaobject.h>
+#include <qstrlist.h>
+#include <qvariant.h>
+
+#include <klocale.h>
+
+#include "sigslotview.h"
+
+SigSlotView::SigSlotView(QWidget *parent, const char *name ) : KListView(parent,name)
+{
+ addColumn( i18n( "Signals/Slots" ) );
+
+ setRootIsDecorated( true );
+ setAllColumnsShowFocus( true );
+ setFullWidth( true );
+}
+
+SigSlotView::~SigSlotView()
+{
+}
+
+void SigSlotView::buildList( QObject *o )
+{
+ QMetaObject *mo = o->metaObject();
+
+ KListViewItem *sigs = new KListViewItem( this, "Signals" );
+ QStrList sigList = mo->signalNames( true );
+ QStrListIterator sigIt( sigList );
+ char *si;
+ while ( (si=sigIt.current()) != 0 ) {
+ ++sigIt;
+ new KListViewItem( sigs, si /*, "someSignal()"*/ );
+ }
+
+ KListViewItem *slts = new KListViewItem( this, "Slots" );
+ QStrList sltList = mo->slotNames( true );
+ QStrListIterator sltIt( sltList );
+ char *sl;
+ while ( (sl=sltIt.current()) != 0 ) {
+ ++sltIt;
+ new KListViewItem( slts, sl/*, "someSlot()"*/ );
+ }
+
+ setOpen( sigs, false );
+ setOpen( slts, false );
+}
+
+void SigSlotView::setTarget( QObject *o )
+{
+ clear();
+ buildList( o );
+}
+
+#include "sigslotview.moc"
diff --git a/kspy/sigslotview.h b/kspy/sigslotview.h
new file mode 100644
index 00000000..86138fd1
--- /dev/null
+++ b/kspy/sigslotview.h
@@ -0,0 +1,40 @@
+/***************************************************************************
+ sigslotview.h - description
+ -------------------
+ begin : Tue May 1 2001
+ copyright : (C) 2001 by Richard Moore
+ email : rich@kde.org
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the 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 SIGSLOTVIEW_H
+#define SIGSLOTVIEW_H
+
+#include <qwidget.h>
+#include <klistview.h>
+
+/**
+ *@author Richard Moore
+ */
+
+class SigSlotView : public KListView {
+ Q_OBJECT
+public:
+ SigSlotView(QWidget *parent=0, const char *name=0);
+ ~SigSlotView();
+
+ void buildList( QObject *o );
+
+public slots:
+ void setTarget( QObject * );
+};
+
+#endif
diff --git a/kspy/spy.cpp b/kspy/spy.cpp
new file mode 100644
index 00000000..341f5b62
--- /dev/null
+++ b/kspy/spy.cpp
@@ -0,0 +1,115 @@
+/***************************************************************************
+ spy.cpp - description
+ -------------------
+ begin : Tue May 1 02:59:33 BST 2001
+ copyright : (C) 2001 by Richard Moore
+ email : rich@kde.org
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the 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 <klistviewsearchline.h>
+#include <klocale.h>
+
+#include <qlabel.h>
+#include <qlayout.h>
+#include <qlistview.h>
+#include <qsplitter.h>
+#include <ktabwidget.h>
+#include <qvbox.h>
+
+#include "navview.h"
+#include "propsview.h"
+#include "sigslotview.h"
+#include "receiversview.h"
+#include "classinfoview.h"
+#include "spy.h"
+
+extern "C"
+{
+ KDE_EXPORT void* init_libkspy()
+ {
+ qWarning( "KSpy: Initialising...\n" );
+ Spy *s = new Spy();
+ s->show();
+
+ return 0;
+ }
+}
+
+Spy::Spy( QWidget *parent, const char *name )
+ : QWidget( parent, name )
+{
+ QVBoxLayout *layout = new QVBoxLayout( this, 11, 6 );
+
+ QSplitter *div = new QSplitter( this );
+ layout->addWidget( div );
+
+ QVBox *leftPane = new QVBox( div );
+
+ KListViewSearchLine *searchLine = new KListViewSearchLine( leftPane, "search line" );
+ mNavView = new NavView( leftPane, "navigation view" );
+ searchLine->setListView( mNavView );
+
+ KTabWidget *tabs = new KTabWidget( div );
+
+ mPropsView = new PropsView( tabs, "properties view" );
+ tabs->addTab( mPropsView, i18n( "Properties" ) );
+
+ mSigSlotView = new SigSlotView( tabs, "signals and slots view" );
+ tabs->addTab( mSigSlotView, i18n( "Signals && Slots" ) );
+
+ mReceiversView = new ReceiversView( tabs, "receivers view" );
+ tabs->addTab( mReceiversView, i18n( "Receivers" ) );
+
+ mClassInfoView = new ClassInfoView( tabs, "class info view" );
+ tabs->addTab( mClassInfoView, i18n( "Class Info" ) );
+
+ mNavView->buildTree();
+
+ connect( mNavView, SIGNAL( selected( QObject * ) ),
+ mPropsView, SLOT( setTarget( QObject * ) ) );
+ connect( mNavView, SIGNAL( selected( QObject * ) ),
+ mSigSlotView, SLOT( setTarget( QObject * ) ) );
+ connect( mNavView, SIGNAL( selected( QObject * ) ),
+ mReceiversView, SLOT( setTarget( QObject * ) ) );
+ connect( mNavView, SIGNAL( selected( QObject * ) ),
+ mClassInfoView, SLOT( setTarget( QObject * ) ) );
+}
+
+Spy::~Spy()
+{
+}
+
+
+void Spy::setTarget( QWidget *target )
+{
+ mTarget = target;
+ mPropsView->buildList( mTarget );
+ mSigSlotView->buildList( mTarget );
+ mReceiversView->buildList( mTarget );
+ mClassInfoView->buildList( mTarget );
+}
+
+void Spy::keyPressEvent( QKeyEvent *event )
+{
+ if ( event->key() == Qt::Key_Up ) {
+ event->accept();
+ QApplication::postEvent( mNavView, new QKeyEvent( QEvent::KeyPress, Qt::Key_Up, 0, 0 ) );
+ } else if ( event->key() == Qt::Key_Down ) {
+ event->accept();
+ QApplication::postEvent( mNavView, new QKeyEvent( QEvent::KeyPress, Qt::Key_Down, 0, 0 ) );
+ } else if ( event->key() == Qt::Key_Return ) {
+ event->accept();
+ mNavView->expandVisibleTree();
+ }
+}
+
+#include "spy.moc"
diff --git a/kspy/spy.h b/kspy/spy.h
new file mode 100644
index 00000000..61d80162
--- /dev/null
+++ b/kspy/spy.h
@@ -0,0 +1,59 @@
+/***************************************************************************
+ spy.h - description
+ -------------------
+ begin : Tue May 1 02:59:33 BST 2001
+ copyright : (C) 2001 by Richard Moore
+ email : rich@kde.org
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the 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 SPY_H
+#define SPY_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <kapplication.h>
+#include <qwidget.h>
+
+class NavView;
+class PropsView;
+class SigSlotView;
+class ReceiversView;
+class ClassInfoView;
+
+/**
+ Spy is the main window class of the project.
+ */
+class Spy : public QWidget
+{
+ Q_OBJECT
+
+ public:
+ Spy( QWidget *parent = 0, const char *name = 0 );
+ ~Spy();
+
+ void setTarget( QWidget *target );
+
+ protected:
+ virtual void keyPressEvent( QKeyEvent* );
+
+ private:
+ QWidget *mTarget;
+ PropsView *mPropsView;
+ SigSlotView *mSigSlotView;
+ ReceiversView *mReceiversView;
+ ClassInfoView *mClassInfoView;
+ NavView *mNavView;
+};
+
+#endif
diff --git a/kstartperf/Makefile.am b/kstartperf/Makefile.am
new file mode 100644
index 00000000..9214d389
--- /dev/null
+++ b/kstartperf/Makefile.am
@@ -0,0 +1,14 @@
+INCLUDES = $(all_includes)
+
+lib_LTLIBRARIES = libkstartperf.la
+libkstartperf_la_LDFLAGS = $(all_libraries) -version-info 1:0 -no-undefined
+# libkstartperf_la_LIBADD = ../libltdl/libltdlc.la
+libkstartperf_la_SOURCES = libkstartperf.c
+
+bin_PROGRAMS = kstartperf
+kstartperf_LDFLAGS = $(all_libraries)
+kstartperf_LDADD = $(LIB_KDECORE)
+kstartperf_SOURCES = kstartperf.cpp
+
+messages:
+ $(XGETTEXT) $(kstartperf_SOURCES) -o $(podir)/kstartperf.pot
diff --git a/kstartperf/README b/kstartperf/README
new file mode 100644
index 00000000..ff986444
--- /dev/null
+++ b/kstartperf/README
@@ -0,0 +1,31 @@
+
+** kstartperf: startup time measurement for KDE apps **
+
+** Usage:
+
+kstartperf measures startup time for KDE applications. Usage is simple:
+
+ $ kstartperf konsole
+
+will show you the startup time of konsole in milliseconds.
+
+
+** How does it work?
+
+1. Kstartperf stores the current time with microsecond resolution in an
+ environment variable ($KSTARTPERF).
+2. Kstartperf executes the requested application, but with a LD_PRELOAD
+ library that overrides the X11 XMapWindow() function.
+3. As soon as the app calls XMapWindow (this is the point where we assume
+ that the app has "started up"), our function is called instead of the
+ original XMapWindow(). This function calculates the time difference
+ between the current time and the time stored in the environment variable
+ and prints this information to standard error.
+4. Our function disables itself and calls the original XMapWindow().
+
+** Notes
+
+The appliation that is being profiled, needs to be linked against kdecore.
+
+Geert Jansen <jansen@kde.org>,
+20 July 2000
diff --git a/kstartperf/kstartperf.cpp b/kstartperf/kstartperf.cpp
new file mode 100644
index 00000000..3f029b62
--- /dev/null
+++ b/kstartperf/kstartperf.cpp
@@ -0,0 +1,124 @@
+/* vi: ts=8 sts=4 sw=4
+ *
+ * $Id$
+ *
+ * This file is part of the KDE project, module kstartperf.
+ * Copyright (C) 2000 Geert Jansen <jansen@kde.org>
+ *
+ * You can freely redistribute this program under the "Artistic License".
+ * See the file "LICENSE.readme" for the exact terms.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <errno.h>
+#include <sys/time.h>
+
+#include <qstring.h>
+#include <qtextstream.h>
+#include <qfile.h>
+
+#include <kapplication.h>
+#include <kaboutdata.h>
+#include <kcmdlineargs.h>
+#include <klocale.h>
+#include <kstandarddirs.h>
+
+
+static KCmdLineOptions options[] =
+{
+ { "+command", I18N_NOOP("Specifies the command to run"), 0 },
+ KCmdLineLastOption
+};
+
+
+QString libkstartperf()
+{
+ QString lib = QString::null;
+ QString la_file = locate("lib", "libkstartperf.la");
+
+ if (la_file.isEmpty())
+ return lib;
+
+ // Find the name of the .so file by reading the .la file
+ QFile la(la_file);
+ if (la.open(IO_ReadOnly))
+ {
+ QTextStream is(&la);
+ QString line;
+
+ while (!is.atEnd())
+ {
+ line = is.readLine();
+ if (line.left(15) == "library_names='")
+ {
+ lib = line.mid(15);
+ int pos = lib.find(" ");
+ if (pos > 0)
+ lib = lib.left(pos);
+ }
+ }
+
+ la.close();
+ }
+
+ // Look up the actual .so file.
+ lib = locate("lib", lib);
+ return lib;
+}
+
+
+int main(int argc, char **argv)
+{
+ KAboutData aboutData("kstartperf", I18N_NOOP("KStartPerf"),
+ "1.0", I18N_NOOP("Measures start up time of a KDE application"),
+ KAboutData::License_Artistic,
+ "Copyright (c) 2000 Geert Jansen and libkmapnotify authors");
+ aboutData.addAuthor("Geert Jansen", I18N_NOOP("Maintainer"),
+ "jansen@kde.org", "http://www.stack.nl/~geertj/");
+
+ KCmdLineArgs::init(argc, argv, &aboutData);
+ KCmdLineArgs::addCmdLineOptions(options);
+ KCmdLineArgs *args = KCmdLineArgs::parsedArgs();
+
+ KApplication *app = new KApplication(false, false);
+
+ // Check arguments
+
+ if (args->count() == 0)
+ {
+ fprintf(stderr, "No command specified!\n");
+ fprintf(stderr, "usage: kstartperf command [arguments]\n");
+ exit(1);
+ }
+
+ // Build command
+
+ char cmd[1024];
+ sprintf(cmd, "LD_PRELOAD=%s %s", libkstartperf().latin1(), args->arg(0));
+ for (int i=1; i<args->count(); i++)
+ {
+ strcat(cmd, " ");
+ strcat(cmd, args->arg(i));
+ }
+
+ // Put the current time in the environment variable `KSTARTPERF'
+
+ struct timeval tv;
+ if (gettimeofday(&tv, 0L) != 0)
+ {
+ perror("gettimeofday()");
+ exit(1);
+ }
+ char env[100];
+ sprintf(env, "KSTARTPERF=%ld:%ld", tv.tv_sec, tv.tv_usec);
+ putenv(env);
+
+ // And exec() the command
+
+ execl("/bin/sh", "sh", "-c", cmd, (void *)0);
+
+ perror("execl()");
+ exit(1);
+}
diff --git a/kstartperf/libkstartperf.c b/kstartperf/libkstartperf.c
new file mode 100644
index 00000000..3c8deae0
--- /dev/null
+++ b/kstartperf/libkstartperf.c
@@ -0,0 +1,122 @@
+/* vi: ts=8 sts=4 sw=4
+ *
+ * $Id$
+ *
+ * libkstartperf.c: LD_PRELOAD library for startup time measurements.
+ *
+ * Copyright (C) 2000 Geert Jansen <jansen@kde.org>
+ *
+ * Based heavily on kmapnotify.c:
+ *
+ * (C) 2000 Rik Hemsley <rik@kde.org>
+ * (C) 2000 Simon Hausmann <hausmann@kde.org>
+ * (C) 2000 Bill Soudan <soudan@kde.org>
+ */
+
+#include <sys/time.h>
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <X11/X.h>
+#include <X11/Xlib.h>
+
+#include <ltdl.h>
+
+
+/* Prototypes */
+
+int XMapWindow(Display *, Window);
+int XMapRaised(Display *, Window);
+void KDE_InterceptXMapRequest(Display *, Window);
+void KDE_ShowPerformance();
+
+/* Globals */
+
+typedef Window (*KDE_XMapRequestSignature)(Display *, Window);
+KDE_XMapRequestSignature KDE_RealXMapWindow = 0L;
+KDE_XMapRequestSignature KDE_RealXMapRaised = 0L;
+
+
+/* Functions */
+
+int XMapWindow(Display * d, Window w)
+{
+ if (KDE_RealXMapWindow == 0L)
+ {
+ KDE_InterceptXMapRequest(d, w);
+ KDE_ShowPerformance();
+ }
+ return KDE_RealXMapWindow(d, w);
+}
+
+int XMapRaised(Display * d, Window w)
+{
+ if (KDE_RealXMapRaised == 0L)
+ {
+ KDE_InterceptXMapRequest(d, w);
+ KDE_ShowPerformance();
+ }
+ return KDE_RealXMapRaised(d, w);
+}
+
+void KDE_InterceptXMapRequest(Display * d, Window w)
+{
+ lt_dlhandle handle;
+
+ handle = lt_dlopen("libX11.so");
+ if (handle == 0L)
+ handle = lt_dlopen("libX11.so.6");
+
+ if (handle == 0L)
+ {
+ fprintf(stderr, "kstartperf: Could not dlopen libX11\n");
+ exit(1);
+ }
+
+ KDE_RealXMapWindow = (KDE_XMapRequestSignature)lt_dlsym(handle, "XMapWindow");
+ if (KDE_RealXMapWindow == 0L)
+ {
+ fprintf(stderr, "kstartperf: Could not find symbol XMapWindow in libX11\n");
+ exit(1);
+ }
+
+ KDE_RealXMapRaised = (KDE_XMapRequestSignature)lt_dlsym(handle, "XMapRaised");
+ if (KDE_RealXMapRaised == 0L)
+ {
+ fprintf(stderr, "kstartperf: Could not find symbol XMapRaised in libX11\n");
+ exit(1);
+ }
+}
+
+void KDE_ShowPerformance()
+{
+ char *env;
+ long l1, l2;
+ float dt;
+ struct timeval tv;
+
+ env = getenv("KSTARTPERF");
+ if (env == 0L)
+ {
+ fprintf(stderr, "kstartperf: $KSTARTPERF not set!\n");
+ exit(1);
+ }
+ if (sscanf(env, "%ld:%ld", &l1, &l2) != 2)
+ {
+ fprintf(stderr, "kstartperf: $KSTARTPERF illegal format\n");
+ exit(1);
+ }
+
+ if (gettimeofday(&tv, 0L) != 0)
+ {
+ fprintf(stderr, "kstartperf: gettimeofday() failed.\n");
+ exit(1);
+ }
+
+ dt = 1e3*(tv.tv_sec - l1) + 1e-3*(tv.tv_usec - l2);
+ fprintf(stderr, "\nkstartperf: measured startup time at %7.2f ms\n\n", dt);
+}
+
diff --git a/kuiviewer/Makefile.am b/kuiviewer/Makefile.am
new file mode 100644
index 00000000..e5713689
--- /dev/null
+++ b/kuiviewer/Makefile.am
@@ -0,0 +1,70 @@
+# this has all of the subdirectories that make will recurse into. if
+# there are none, comment this out
+
+# set the include path for X, qt and KDE
+INCLUDES = $(all_includes)
+
+# these are the headers for your project
+noinst_HEADERS = kuiviewer.h kuiviewer_part.h
+
+# let automoc handle all of the meta source files (moc)
+METASOURCES = AUTO
+
+messages: rc.cpp
+ $(XGETTEXT) *.cpp -o $(podir)/kuiviewer.pot
+
+KDE_ICON = kuiviewer
+
+# this Makefile creates both a KPart application and a KPart
+#########################################################################
+# APPLICATION SECTION
+#########################################################################
+# this is the program that gets installed. it's name is used for all
+# of the other Makefile.am variables
+bin_PROGRAMS = kuiviewer
+
+# the application source, library search path, and link libraries
+kuiviewer_SOURCES = main.cpp kuiviewer.cpp
+kuiviewer_LDFLAGS = $(KDE_RPATH) $(all_libraries)
+kuiviewer_LDADD = $(LIB_KPARTS)
+
+xdg_apps_DATA =kuiviewer.desktop
+
+# this is where the shell's XML-GUI resource file goes
+shellrcdir = $(kde_datadir)/kuiviewer
+shellrc_DATA = kuiviewerui.rc
+
+#########################################################################
+# KPART SECTION
+#########################################################################
+kde_module_LTLIBRARIES = libkuiviewerpart.la quithumbnail.la
+
+# the Part's source, library search path, and link libraries
+libkuiviewerpart_la_SOURCES = kuiviewer_part.cpp
+libkuiviewerpart_la_LDFLAGS = -module $(KDE_PLUGIN) $(all_libraries)
+libkuiviewerpart_la_LIBADD = $(LIB_KPARTS) $(LIB_KFILE) -lqui
+
+# this is where the desktop file will go
+partdesktopdir = $(kde_servicesdir)
+partdesktop_DATA = kuiviewer_part.desktop
+
+# this is where the part's XML-GUI resource file goes
+partrcdir = $(kde_datadir)/kuiviewerpart
+partrc_DATA = kuiviewer_part.rc
+
+
+#########################################################################
+# THUMBNAIL SECTION
+#########################################################################
+quithumbnail_la_SOURCES = quicreator.cpp
+quithumbnail_la_LIBADD = $(LIB_KDECORE) -lqui
+quithumbnail_la_LDFLAGS = $(all_libraries) -module $(KDE_PLUGIN)
+services_DATA = designerthumbnail.desktop
+servicesdir = $(kde_servicesdir)
+
+#########################################################################
+# UTILS SECTION
+#########################################################################
+.PHONY: changes
+changes:
+ cvs2cl.pl --window 3600 -w --hide-filenames -I '.desktop'
diff --git a/kuiviewer/designerthumbnail.desktop b/kuiviewer/designerthumbnail.desktop
new file mode 100644
index 00000000..ec98ccfd
--- /dev/null
+++ b/kuiviewer/designerthumbnail.desktop
@@ -0,0 +1,53 @@
+[Desktop Entry]
+Type=Service
+Name=Qt Designer Files
+Name[bg]=Файлове на дизайнера Qt
+Name[br]=Restroù Ergrafer Qt
+Name[bs]=Qt Designer datoteke
+Name[ca]=Fitxers de Qt Designer
+Name[cs]=Soubory Qt designeru
+Name[cy]=Ffeiliau Qt Designer
+Name[da]=Qt Designer-filer
+Name[de]=Qt-Designer Dateien
+Name[el]=ΑÏχεία Qt Designer
+Name[es]=Archivos de Qt Designer
+Name[et]=Qt Designeri failid
+Name[eu]=Qt Designer fitxategiak
+Name[fa]=پرونده‌های طراح Qt
+Name[fi]=Qt Designer -tiedostot
+Name[fr]=Fichiers Qt Designer
+Name[ga]=Comhaid Qt Designer
+Name[gl]=Ficheiros de Qt Designer
+Name[hi]=कà¥à¤¯à¥‚-टी डिजाइनर फ़ाइलें
+Name[hu]=Qt Designer fájlok
+Name[is]=Qt Designer skrár
+Name[it]=File di Qt Designer
+Name[ja]=Qt デザイナーファイル
+Name[ka]=Qt დიზáƒáƒ˜áƒœáƒ”რის ფáƒáƒ˜áƒšáƒ”ბი
+Name[kk]=Qt Designer файлы
+Name[lt]=Qt Designer bylos
+Name[nb]=Qt Designer-filer
+Name[nds]=Qt-Designer-Dateien
+Name[ne]=Qt डिजाइनर फाइल
+Name[nl]=Qt Designer-bestanden
+Name[nn]=Qt Designer-filer
+Name[pa]=Qt Designer ਫਾਇਲ
+Name[pl]=Pliki Qt Designer
+Name[pt]=Ficheiros do Qt Designer
+Name[pt_BR]=Arquivos do Qt Designer
+Name[ru]=Файлы Qt Designer
+Name[sk]=Súbory Qt Designer
+Name[sl]=Datoteke za Qt Designer
+Name[sr]=Фајлови Qt Designer-а
+Name[sr@Latn]=Fajlovi Qt Designer-a
+Name[sv]=Qt-designer-filer
+Name[ta]=Qt வடிவமை கோபà¯à®ªà¯à®•à®³à¯
+Name[tg]=Файлҳои Qt Designer
+Name[tr]=Qt Designer Dosyaları
+Name[uk]=Файли Qt Designer
+Name[zh_CN]=Qt 设计师文件
+Name[zh_TW]=Qt Designer 檔案
+ServiceTypes=ThumbCreator
+MimeTypes=application/x-designer
+X-KDE-Library=quithumbnail
+CacheThumbnail=true
diff --git a/kuiviewer/hi16-app-kuiviewer.png b/kuiviewer/hi16-app-kuiviewer.png
new file mode 100644
index 00000000..43eab761
--- /dev/null
+++ b/kuiviewer/hi16-app-kuiviewer.png
Binary files differ
diff --git a/kuiviewer/hi32-app-kuiviewer.png b/kuiviewer/hi32-app-kuiviewer.png
new file mode 100644
index 00000000..ce9df987
--- /dev/null
+++ b/kuiviewer/hi32-app-kuiviewer.png
Binary files differ
diff --git a/kuiviewer/hi48-app-kuiviewer.png b/kuiviewer/hi48-app-kuiviewer.png
new file mode 100644
index 00000000..6464fb39
--- /dev/null
+++ b/kuiviewer/hi48-app-kuiviewer.png
Binary files differ
diff --git a/kuiviewer/kuiviewer.cpp b/kuiviewer/kuiviewer.cpp
new file mode 100644
index 00000000..f56b0985
--- /dev/null
+++ b/kuiviewer/kuiviewer.cpp
@@ -0,0 +1,165 @@
+/*
+ *
+ * This file is part of the kuiviewer package
+ * Copyright (c) 2003 Richard Moore <rich@kde.org>
+ * Copyright (c) 2003 Ian Reinhart Geiser <geiseri@kde.org>
+ * Copyright (c) 2004 Benjamin C. Meyer <ben+kuiviewer@meyerhome.net>
+ *
+ * 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., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ **/
+
+#include "kuiviewer.h"
+#include "kuiviewer.moc"
+#include "kuiviewer_part.h"
+
+#include <kdebug.h>
+
+#include <qobjectlist.h>
+#include <qdockwindow.h>
+#include <qpixmap.h>
+
+#include <kurl.h>
+
+#include <kaction.h>
+#include <kstdaction.h>
+
+#include <kiconloader.h>
+#include <klibloader.h>
+#include <klocale.h>
+#include <kmessagebox.h>
+#include <kfiledialog.h>
+
+KUIViewer::KUIViewer()
+ : KParts::MainWindow( 0L, "KUIViewer" )
+{
+ // setup our actions
+ setupActions();
+
+ setMinimumSize(300, 200);
+
+ // Bring up the gui
+ setupGUI();
+
+ // this routine will find and load our Part. it finds the Part by
+ // name which is a bad idea usually.. but it's alright in this
+ // case since our Part is made for this Shell
+ KLibFactory *factory = KLibLoader::self()->factory("libkuiviewerpart");
+ if (factory)
+ {
+ // now that the Part is loaded, we cast it to a Part to get
+ // our hands on it
+ m_part = static_cast<KParts::ReadOnlyPart *>(factory->create(this,
+ "kuiviewer_part", "KParts::ReadOnlyPart" ));
+
+ if (m_part)
+ {
+ // tell the KParts::MainWindow that this is indeed the main widget
+ setCentralWidget(m_part->widget());
+
+ // and integrate the part's GUI with the shell's
+ createGUI(m_part);
+ }
+ }
+ else
+ {
+ // if we couldn't find our Part, we exit since the Shell by
+ // itself can't do anything useful
+ //FIXME improve message, which Part is this referring to?
+ KMessageBox::error(this, i18n("Unable to locate Kuiviewer kpart."));
+ kapp->quit();
+ // we return here, cause kapp->quit() only means "exit the
+ // next time we enter the event loop...
+ return;
+ }
+}
+
+KUIViewer::~KUIViewer()
+{
+}
+
+void KUIViewer::load(const KURL& url)
+{
+ m_part->openURL( url );
+ adjustSize();
+}
+
+void KUIViewer::setupActions()
+{
+ KStdAction::open(this, SLOT(fileOpen()), actionCollection());
+ KStdAction::quit(kapp, SLOT(quit()), actionCollection());
+}
+
+void KUIViewer::saveProperties(KConfig* /*config*/)
+{
+ // the 'config' object points to the session managed
+ // config file. anything you write here will be available
+ // later when this app is restored
+}
+
+void KUIViewer::readProperties(KConfig* /*config*/)
+{
+ // the 'config' object points to the session managed
+ // config file. this function is automatically called whenever
+ // the app is being restored. read in here whatever you wrote
+ // in 'saveProperties'
+}
+
+void KUIViewer::fileOpen()
+{
+ // this slot is called whenever the File->Open menu is selected,
+ // the Open shortcut is pressed (usually CTRL+O) or the Open toolbar
+ // button is clicked
+ KURL file_name =
+ KFileDialog::getOpenURL( QString::null, i18n("*.ui *.UI|User Interface Files"), this );
+
+ if (file_name.isEmpty() == false)
+ {
+ // About this function, the style guide (
+ // http://developer.kde.org/documentation/standards/kde/style/basics/index.html )
+ // says that it should open a new window if the document is _not_
+ // in its initial state. This is what we do here..
+ if ( m_part->url().isEmpty() )
+ {
+ // we open the file in this window...
+ load( file_name );
+ }
+ else
+ {
+ // we open the file in a new window...
+ KUIViewer* newWin = new KUIViewer;
+ newWin->load( file_name );
+ newWin->show();
+ }
+ }
+}
+
+void KUIViewer::takeScreenshot(const QCString &filename, int w, int h){
+ if(!m_part)
+ return;
+ showMinimized();
+ if(w!=-1 && h!=-1){
+ // resize widget to the desired size
+ m_part->widget()->setMinimumSize(w, h);
+ m_part->widget()->setMaximumSize(w, h);
+ m_part->widget()->repaint();
+ // resize app to be as large as desired size
+ adjustSize();
+ // Disable the saving of the size
+ setAutoSaveSettings(QString::fromLatin1("MainWindow"), false);
+ }
+ QPixmap pixmap = QPixmap::grabWidget( m_part->widget() );
+ pixmap.save( filename, "PNG" );
+}
+
diff --git a/kuiviewer/kuiviewer.desktop b/kuiviewer/kuiviewer.desktop
new file mode 100644
index 00000000..e1e62263
--- /dev/null
+++ b/kuiviewer/kuiviewer.desktop
@@ -0,0 +1,58 @@
+[Desktop Entry]
+Name=KUIViewer
+Name[cy]=KUIGwelydd
+Name[hi]=के-यूआई-वà¥à¤¯à¥‚अर
+Name[ja]=KUI ビューア
+Name[sv]=KUIviewer
+Name[ta]=KUIவியூவரà¯
+Exec=kuiviewer %i %m -caption "%c"
+Icon=kuiviewer
+Type=Application
+GenericName=Qt Designer UI File Viewer
+GenericName[br]=Ur gweler restr UI Ergrafer Qt
+GenericName[bs]=Preglednik Qt Designer UI datoteka
+GenericName[ca]=Visor de fitxer UI de Qt Designer
+GenericName[cs]=ProhlížeÄ UI souborů z Qt Designeru
+GenericName[cy]=Gwelydd Ffeiliau UI Qt Designer
+GenericName[da]=Qt Designer UI filviser
+GenericName[de]=Betrachter für UI-Dateien des Qt-Designer
+GenericName[el]=ΠÏοβολέας αÏχείων Qt Designer UI
+GenericName[es]=Visor de archivos UI de Qt Designer
+GenericName[et]=Qt Designeri UI-failide näitaja
+GenericName[eu]=Qt Designer UI fitxartegi ikusgailua
+GenericName[fa]=مشاهده‌گر پروندۀ واسط نگاره‌ای طراح Qt
+GenericName[fi]=Qt Designerin UI-tiedostojen katselin
+GenericName[fr]=Afficheur de fichiers UI de QT Designer
+GenericName[gl]=Visor de ficheiros de Qt Designer
+GenericName[hu]=Qt Designer UI-fájlnézegető
+GenericName[is]=Qt Designer UI skráaskoðari
+GenericName[it]=Visualizzatore per file UI di Qt Designer
+GenericName[ja]=Qt デザイナー UI ファイルビューア
+GenericName[ka]=Qt დიზáƒáƒ˜áƒœáƒ”რის UI ფáƒáƒ˜áƒšáƒ—რმხილველი
+GenericName[kk]=Qt Designer пайдаланушы интерфейÑінің файлдарын қарау құралы
+GenericName[lt]=Qt Designer naudotojo sąsajos bylų žiūryklė
+GenericName[nb]=Qt Designer UI-filviser
+GenericName[nds]=Kieker för Qt-Designer sien UI-Dateien
+GenericName[ne]=Qt डिजाइनर यूआई फाइल दरà¥à¤¶à¤•
+GenericName[nl]=Weergave van QT Designer UI-bestanden
+GenericName[nn]=Qt Designer UI-filvisar
+GenericName[pl]=Przeglądarka plików interfejsu użytkownika Qt Designera
+GenericName[pt]=Visualizador de Ficheiros UI do Qt Designer
+GenericName[pt_BR]=Visualizador de Arquivos e Interface do Qt Designer
+GenericName[ru]=ПроÑмотрщик UI-файлов Qt Designer
+GenericName[sk]=PrehliadaÄ súborov UI pre Qt Designer
+GenericName[sl]=Pregledovalnik datotek UI za Qt Designer
+GenericName[sr]=Приказивач UI фајлова Qt Designer-а
+GenericName[sr@Latn]=PrikazivaÄ UI fajlova Qt Designer-a
+GenericName[sv]=Qt-designer UI-filvisning
+GenericName[ta]=Qt வடிவமைபà¯à®ªà®µà®°à¯ UI கோபà¯à®ªà¯à®•à®³à¯ காடà¯à®šà®¿à®¯à®•à®®à¯
+GenericName[tg]=Ðамоишгари UI-файлҳо Qt Designer
+GenericName[tr]=Qt Designer UI Dosya Görüntüleyici
+GenericName[uk]=ПереглÑдач UI-файлів Qt Designer
+GenericName[zh_CN]=Qt 设计师 UI 文件查看器
+GenericName[zh_TW]=Qt Designer UI 檔案檢視器
+MimeType=application/x-designer;
+Terminal=false
+X-DCOP-ServiceType=Multi
+Categories=Qt;KDE;Development;
+InitialPreference=10
diff --git a/kuiviewer/kuiviewer.h b/kuiviewer/kuiviewer.h
new file mode 100644
index 00000000..c6194b4e
--- /dev/null
+++ b/kuiviewer/kuiviewer.h
@@ -0,0 +1,103 @@
+/*
+ *
+ * This file is part of the kuiviewer package
+ * Copyright (c) 2003 Richard Moore <rich@kde.org>
+ * Copyright (c) 2003 Ian Reinhart Geiser <geiseri@kde.org>
+ * Copyright (c) 2004 Benjamin C. Meyer <ben+kuiviewer@meyerhome.net>
+ *
+ * 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., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ **/
+
+#ifndef KUIVIEWER_H
+#define KUIVIEWER_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <kapplication.h>
+#include <kparts/mainwindow.h>
+
+class KToggleAction;
+class KListView;
+
+namespace KParts {
+class ReadOnlyPart;
+}
+
+/**
+ * This is the application "Shell". It has a menubar, toolbar, and
+ * statusbar but relies on the "Part" to do all the real work.
+ *
+ * @short KUI Viewer Shell
+ * @author Richard Moore <rich@kde.org>
+ * @author Ian Reinhart Geiser <geiser@kde.org>
+ * @version 1.0
+ */
+class KUIViewer : public KParts::MainWindow
+{
+ Q_OBJECT
+public:
+ /**
+ * Default Constructor
+ */
+ KUIViewer();
+
+ /**
+ * Default Destructor
+ */
+ virtual ~KUIViewer();
+
+ /**
+ * Use this method to load whatever file/URL you have
+ */
+ void load(const KURL& url);
+
+ /**
+ * Take screenshot of current ui file
+ * @param filename to save image in
+ * @param h height of image
+ * @param w width of image
+ */
+ void takeScreenshot(const QCString &filename, int h=-1, int w=-1);
+
+protected:
+ /**
+ * This method is called when it is time for the app to save its
+ * properties for session management purposes.
+ */
+ void saveProperties(KConfig *);
+
+ /**
+ * This method is called when this app is restored. The KConfig
+ * object points to the session management config file that was saved
+ * with @ref saveProperties
+ */
+ void readProperties(KConfig *);
+
+private slots:
+ void fileOpen();
+
+private:
+ void setupActions();
+
+private:
+ KParts::ReadOnlyPart *m_part;
+ KToggleAction *m_toolbarAction;
+ KToggleAction *m_statusbarAction;
+};
+
+#endif // KUIVIEWER_H
+
diff --git a/kuiviewer/kuiviewer_part.cpp b/kuiviewer/kuiviewer_part.cpp
new file mode 100644
index 00000000..25ef1b2d
--- /dev/null
+++ b/kuiviewer/kuiviewer_part.cpp
@@ -0,0 +1,211 @@
+/**
+ *
+ * This file is part of the kuiviewer package
+ * Copyright (c) 2003 Richard Moore <rich@kde.org>
+ * Copyright (c) 2003 Ian Reinhart Geiser <geiseri@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., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ **/
+
+#include "kuiviewer_part.h"
+#include "kuiviewer_part.moc"
+
+#include <kaction.h>
+#include <kapplication.h>
+#include <kconfig.h>
+#include <kdebug.h>
+#include <kdialogbase.h>
+#include <kiconloader.h>
+#include <kinstance.h>
+#include <kio/netaccess.h>
+#include <klistview.h>
+#include <kparts/genericfactory.h>
+#include <kstdaction.h>
+#include <kstyle.h>
+#include <qmetaobject.h>
+
+#include <qclipboard.h>
+#include <qcursor.h>
+#include <qfile.h>
+#include <qobjectlist.h>
+#include <qpixmap.h>
+#include <qstyle.h>
+#include <qstylefactory.h>
+#include <qvariant.h>
+#include <qvbox.h>
+#include <qvariant.h>
+#include <qwidgetfactory.h>
+
+typedef KParts::GenericFactory<KUIViewerPart> KUIViewerPartFactory;
+K_EXPORT_COMPONENT_FACTORY( libkuiviewerpart, KUIViewerPartFactory )
+
+KUIViewerPart::KUIViewerPart( QWidget *parentWidget, const char *widgetName,
+ QObject *parent, const char *name,
+ const QStringList & /*args*/ )
+ : KParts::ReadOnlyPart(parent, name)
+{
+ // we need an instance
+ setInstance( KUIViewerPartFactory::instance() );
+
+ KGlobal::locale()->insertCatalogue("kuiviewer");
+
+ // this should be your custom internal widget
+ m_widget = new QVBox( parentWidget, widgetName );
+
+ // notify the part that this is our internal widget
+ setWidget(m_widget);
+
+ // set our XML-UI resource file
+ setXMLFile("kuiviewer_part.rc");
+
+ m_style = new KListAction( i18n("Style"),
+ CTRL + Key_S,
+ this,
+ SLOT(slotStyle(int)),
+ actionCollection(),
+ "change_style");
+ m_style->setEditable(false);
+
+ kapp->config()->setGroup("General");
+ const QString currentStyle = kapp->config()->readEntry("currentWidgetStyle", KStyle::defaultStyle());
+
+ const QStringList styles = QStyleFactory::keys();
+ m_style->setItems(styles);
+ m_style->setCurrentItem(0);
+
+ QStringList::ConstIterator it = styles.begin();
+ QStringList::ConstIterator end = styles.end();
+ int idx = 0;
+ for (; it != end; ++it, ++idx) {
+ if ((*it).lower() == currentStyle.lower()) {
+ m_style->setCurrentItem(idx);
+ break;
+ }
+ }
+ m_style->setToolTip(i18n("Set the current style to view."));
+ m_style->setMenuAccelsEnabled(true);
+
+ m_copy = KStdAction::copy(this, SLOT(slotGrab()), actionCollection());
+
+ updateActions();
+
+// Commented out to fix warning (rich)
+// slot should probably be called saveAs() for consistency with
+// KParts::ReadWritePart BTW.
+// KStdAction::saveAs(this, SLOT(slotSave()), actionCollection());
+}
+
+KUIViewerPart::~KUIViewerPart()
+{
+}
+
+KAboutData *KUIViewerPart::createAboutData()
+{
+ // the non-i18n name here must be the same as the directory in
+ // which the part's rc file is installed ('partrcdir' in the
+ // Makefile)
+ KAboutData *aboutData = new KAboutData("kuiviewerpart", I18N_NOOP("KUIViewerPart"), "0.1",
+ I18N_NOOP("Displays Designer's UI files"),
+ KAboutData::License_LGPL );
+ aboutData->addAuthor("Richard Moore", 0, "rich@kde.org");
+ aboutData->addAuthor("Ian Reinhart Geiser", 0, "geiseri@kde.org");
+ return aboutData;
+}
+
+bool KUIViewerPart::openFile()
+{
+ // m_file is always local so we can use QFile on it
+ QFile file( m_file );
+ if ( !file.open(IO_ReadOnly) )
+ return false;
+
+ delete m_view;
+ m_view = QWidgetFactory::create( &file, 0, m_widget );
+
+ file.close();
+ updateActions();
+
+ if ( !m_view )
+ return false;
+
+ m_view->show();
+ slotStyle(0);
+ return true;
+}
+
+bool KUIViewerPart::openURL( const KURL& url)
+{
+ // just for fun, set the status bar
+ emit setStatusBarText( url.prettyURL() );
+ emit setWindowCaption( url.prettyURL() );
+
+ m_url = url;
+ m_file = QString::null;
+ if (KIO::NetAccess::download(url, m_file))
+ return openFile();
+ else
+ return false;
+}
+
+void KUIViewerPart::updateActions()
+{
+ if ( !m_view.isNull() ) {
+ m_style->setEnabled( true );
+ m_copy->setEnabled( true );
+ }
+ else {
+ m_style->setEnabled( false );
+ m_copy->setEnabled( false );
+ }
+}
+
+void KUIViewerPart::slotStyle(int)
+{
+ if ( m_view.isNull() ) {
+ updateActions();
+ return;
+ }
+
+ QString styleName = m_style->currentText();
+ QStyle* style = QStyleFactory::create(styleName);
+ kdDebug() << "Change style..." << endl;
+ m_widget->hide();
+ QApplication::setOverrideCursor( WaitCursor );
+ m_widget->setStyle( style);
+
+ QObjectList *l = m_widget->queryList( "QWidget" );
+ for ( QObject *o = l->first(); o; o = l->next() )
+ ( static_cast<QWidget *>(o) )->setStyle( style );
+ delete l;
+
+ m_widget->show();
+ QApplication::restoreOverrideCursor();
+
+ kapp->config()->setGroup("General");
+ kapp->config()->writeEntry("currentWidgetStyle", m_style->currentText());
+ kapp->config()->sync();
+}
+
+void KUIViewerPart::slotGrab()
+{
+ if ( m_view.isNull() ) {
+ updateActions();
+ return;
+ }
+
+ QClipboard *clipboard = QApplication::clipboard();
+ clipboard->setPixmap(QPixmap::grabWidget(m_widget));
+}
+
diff --git a/kuiviewer/kuiviewer_part.desktop b/kuiviewer/kuiviewer_part.desktop
new file mode 100644
index 00000000..704eaf5d
--- /dev/null
+++ b/kuiviewer/kuiviewer_part.desktop
@@ -0,0 +1,9 @@
+[Desktop Entry]
+Name=KUIViewerPart
+Name[hi]=के-यूआई-वà¥à¤¯à¥‚अर-पारà¥à¤Ÿ
+Name[sv]=KUIviewer-del
+Name[ta]=KUIவியூவர௠உறà¯à®ªà¯à®ªà¯
+MimeType=application/x-designer;
+ServiceTypes=KParts/ReadOnlyPart
+X-KDE-Library=libkuiviewerpart
+Type=Service
diff --git a/kuiviewer/kuiviewer_part.h b/kuiviewer/kuiviewer_part.h
new file mode 100644
index 00000000..e34f1f35
--- /dev/null
+++ b/kuiviewer/kuiviewer_part.h
@@ -0,0 +1,80 @@
+/**
+ *
+ * This file is part of the kuiviewer package
+ * Copyright (c) 2003 Richard Moore <rich@kde.org>
+ * Copyright (c) 2003 Ian Reinhart Geiser <geiseri@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., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ **/
+
+#ifndef KUIVIEWERPART_H
+#define KUIVIEWERPART_H
+
+#include <qguardedptr.h>
+#include <kparts/part.h>
+
+class QWidget;
+class KURL;
+class QVBox;
+class KAboutData;
+class KListAction;
+class KListView;
+
+/**
+ * This is a "Part". It that does all the real work in a KPart
+ * application.
+ *
+ * @short Main Part
+ * @author Richard Moore <rich@kde.org>
+ * @version 0.1
+ */
+class KUIViewerPart : public KParts::ReadOnlyPart
+{
+ Q_OBJECT
+public:
+ /**
+ * Default constructor
+ */
+ KUIViewerPart(QWidget *parentWidget, const char *widgetName,
+ QObject *parent, const char *name, const QStringList &args);
+
+ /**
+ * Destructor
+ */
+ virtual ~KUIViewerPart();
+
+ static KAboutData *createAboutData();
+
+public slots:
+ bool openURL( const KURL& );
+ void slotStyle(int);
+ void slotGrab();
+ void updateActions();
+
+protected:
+ /**
+ * This must be implemented by each part
+ */
+ virtual bool openFile();
+
+private:
+ QVBox *m_widget;
+ QGuardedPtr<QWidget> m_view;
+ KListAction *m_style;
+ KAction *m_copy;
+};
+
+#endif // KUIVIEWERPART_H
+
diff --git a/kuiviewer/kuiviewer_part.rc b/kuiviewer/kuiviewer_part.rc
new file mode 100644
index 00000000..26fead68
--- /dev/null
+++ b/kuiviewer/kuiviewer_part.rc
@@ -0,0 +1,17 @@
+<!DOCTYPE kpartgui SYSTEM "kpartgui.dtd">
+<kpartgui name="kuiviewer_part" version="5">
+<MenuBar>
+ <Menu name="file"><Text>&amp;File</Text>
+ <Action name="file_save_as"/>
+ </Menu>
+ <Menu name="edit"><Text>&amp;Edit</Text>
+ <Action name="edit_copy"/>
+ </Menu>
+ <Menu name="view"><Text>&amp;View</Text>
+ <Action name="change_style"/>
+ </Menu>
+</MenuBar>
+<ToolBar name="styleBar"><Text>Style</Text>
+ <Action name="change_style"/>
+</ToolBar>
+</kpartgui>
diff --git a/kuiviewer/kuiviewerui.rc b/kuiviewer/kuiviewerui.rc
new file mode 100644
index 00000000..296367af
--- /dev/null
+++ b/kuiviewer/kuiviewerui.rc
@@ -0,0 +1,8 @@
+<!DOCTYPE kpartgui SYSTEM "kpartgui.dtd">
+<kpartgui name="shell" version="1">
+<MenuBar>
+ <Menu name="file"><Text>&amp;File</Text></Menu>
+ <Menu name="edit"><Text>&amp;Edit</Text></Menu>
+ <Menu name="view"><Text>&amp;View</Text></Menu>
+</MenuBar>
+</kpartgui>
diff --git a/kuiviewer/lo16-app-kuiviewer.png b/kuiviewer/lo16-app-kuiviewer.png
new file mode 100644
index 00000000..6983b6ab
--- /dev/null
+++ b/kuiviewer/lo16-app-kuiviewer.png
Binary files differ
diff --git a/kuiviewer/lo32-app-kuiviewer.png b/kuiviewer/lo32-app-kuiviewer.png
new file mode 100644
index 00000000..8a55a122
--- /dev/null
+++ b/kuiviewer/lo32-app-kuiviewer.png
Binary files differ
diff --git a/kuiviewer/main.cpp b/kuiviewer/main.cpp
new file mode 100644
index 00000000..0ab53d0f
--- /dev/null
+++ b/kuiviewer/main.cpp
@@ -0,0 +1,88 @@
+/**
+ *
+ * This file is part of the kuiviewer package
+ * Copyright (c) 2003 Richard Moore <rich@kde.org>
+ * Copyright (c) 2003 Ian Reinhart Geiser <geiseri@kde.org>
+ * Copyright (c) 2004 Benjamin C. Meyer <ben+kuiviewer@meyerhome.net>
+ *
+ * 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., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ **/
+
+#include "kuiviewer.h"
+#include <kapplication.h>
+#include <kaboutdata.h>
+#include <kcmdlineargs.h>
+#include <klocale.h>
+
+static KCmdLineOptions options[] =
+{
+ { "+[URL]", I18N_NOOP( "Document to open" ), 0 },
+ { "s",0,0 },
+ { "takescreenshot <filename>", I18N_NOOP( "Save screenshot to file and exit" ), 0 },
+ { "w",0,0 },
+ { "screenshotwidth <int>", I18N_NOOP( "Screenshot width" ), "-1" },
+ { "h",0,0 },
+ { "screenshotheight <int>", I18N_NOOP( "Screenshot height" ), "-1" },
+ KCmdLineLastOption
+};
+
+int main(int argc, char **argv)
+{
+ KAboutData about("kuiviewer", I18N_NOOP("KUIViewer"), "0.1",
+ I18N_NOOP("Displays Designer's UI files"),
+ KAboutData::License_LGPL );
+ about.addAuthor("Richard Moore", 0, "rich@kde.org");
+ about.addAuthor("Ian Reinhart Geiser", 0, "geiseri@kde.org");
+ // Screenshot capability
+ about.addAuthor("Benjamin C. Meyer", 0, "ben+kuiviewer@meyerhome.net");
+
+ KCmdLineArgs::init(argc, argv, &about);
+ KCmdLineArgs::addCmdLineOptions( options );
+ KApplication app;
+
+ // see if we are starting with session management
+ if (app.isRestored())
+ RESTORE(KUIViewer)
+ else
+ {
+ // no session.. just start up normally
+ KCmdLineArgs *args = KCmdLineArgs::parsedArgs();
+
+ if ( args->count() == 0 )
+ {
+ KUIViewer *widget = new KUIViewer;
+ widget->show();
+ }
+ else
+ {
+ int i = 0;
+ for (; i < args->count(); i++ ) {
+ KUIViewer *widget = new KUIViewer;
+ widget->load( args->url(i) );
+
+ if (args->isSet("takescreenshot")){
+ widget->takeScreenshot(args->getOption("takescreenshot"),
+ QString(args->getOption("screenshotwidth")).toInt(),
+ QString(args->getOption("screenshotheight")).toInt());
+ return 0;
+ }
+ widget->show();
+ }
+ }
+ args->clear();
+ }
+
+ return app.exec();
+}
diff --git a/kuiviewer/quicreator.cpp b/kuiviewer/quicreator.cpp
new file mode 100644
index 00000000..0bf47e71
--- /dev/null
+++ b/kuiviewer/quicreator.cpp
@@ -0,0 +1,61 @@
+/**
+ *
+ * This file is part of the kuiviewer package
+ * Copyright (c) 2003 Richard Moore <rich@kde.org>
+ * Copyright (c) 2003 Ian Reinhart Geiser <geiseri@kde.org>
+ * Copyright (c) 2004 Benjamin C. Meyer <ben+kuiviewer@meyerhome.net>
+ *
+ * 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., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ **/
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <qpixmap.h>
+#include <qimage.h>
+#include <qwidgetfactory.h>
+
+#include "quicreator.h"
+
+#include <kdemacros.h>
+
+extern "C"
+{
+ KDE_EXPORT ThumbCreator *new_creator()
+ {
+ return new QUICreator;
+ }
+}
+
+bool QUICreator::create(const QString &path, int width, int height, QImage &
+img)
+{
+ QWidget *w = QWidgetFactory::create(path, 0, 0);
+ if ( w )
+ {
+ QPixmap p = QPixmap::grabWidget(w);
+ img = p.convertToImage().smoothScale(width,height,QImage::ScaleMin);
+ return true;
+ }
+ else
+ return false;
+}
+
+ThumbCreator::Flags QUICreator::flags() const
+{
+ return static_cast<Flags>(DrawFrame);
+}
+
diff --git a/kuiviewer/quicreator.h b/kuiviewer/quicreator.h
new file mode 100644
index 00000000..7127ecc7
--- /dev/null
+++ b/kuiviewer/quicreator.h
@@ -0,0 +1,36 @@
+/*
+ *
+ * This file is part of the kuiviewer package
+ * Copyright (c) 2003 Richard Moore <rich@kde.org>
+ * Copyright (c) 2003 Ian Reinhart Geiser <geiseri@kde.org>
+ * Copyright (c) 2004 Benjamin C. Meyer <ben+kuiviewer@meyerhome.net>
+ *
+ * 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., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ **/
+#ifndef UICREATOR_H
+#define UICREATOR_H
+
+#include <kio/thumbcreator.h>
+
+class QUICreator : public ThumbCreator
+{
+public:
+ QUICreator() {};
+ virtual bool create(const QString &path, int, int, QImage &img);
+ virtual Flags flags() const;
+};
+
+#endif // UICREATOR_H
+
diff --git a/kunittest/Makefile.am b/kunittest/Makefile.am
new file mode 100644
index 00000000..2e5d3d0b
--- /dev/null
+++ b/kunittest/Makefile.am
@@ -0,0 +1,21 @@
+SUBDIRS = example
+INCLUDES = $(all_includes)
+METASOURCES = AUTO
+
+lib_LTLIBRARIES = libkunittestgui.la
+libkunittestgui_la_SOURCES = testerwidget.ui runnergui.cpp dcopinterface.skel
+libkunittestgui_la_LDFLAGS = $(all_libraries) $(KDE_RPATH)
+libkunittestgui_la_LIBADD = -lkunittest $(LIB_KDECORE)
+
+runnergui.lo : testerwidget.h
+
+bin_PROGRAMS = kunittestguimodrunner
+kunittestguimodrunner_SOURCES = guimodrunner.cpp
+kunittestguimodrunner_LDFLAGS = $(all_libraries) $(KDE_RPATH)
+kunittestguimodrunner_LDADD = libkunittestgui.la $(LIB_KDECORE) $(LIB_KIO)
+
+noinst_HEADERS = dcopinterface.h
+libkunittestinclude_HEADERS = runnergui.h
+libkunittestincludedir = $(includedir)/kunittest
+
+bin_SCRIPTS = kunittest kunittestmod kunittest_debughelper
diff --git a/kunittest/dcopinterface.h b/kunittest/dcopinterface.h
new file mode 100644
index 00000000..046753d2
--- /dev/null
+++ b/kunittest/dcopinterface.h
@@ -0,0 +1,38 @@
+/***************************************************************************
+ * Copyright (C) 2005 by Jeroen Wijnhout *
+ * Jeroen.Wijnhout@kdemail.net *
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the 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, write to the *
+ * Free Software Foundation, Inc., *
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
+ ***************************************************************************/
+#ifndef KUNITTEST_DCOPINTERFACE_H
+#define KUNITTEST_DCOPINTERFACE_H
+
+#include <dcopobject.h>
+#include <qstring.h>
+
+namespace KUnitTest
+{
+ class DCOPInterface : public DCOPObject
+ {
+ K_DCOP
+
+ k_dcop:
+ virtual bool addDebugInfo(const QString &name, const QString &info) = 0;
+ virtual bool addSlotDebugInfo(const QString &name, const QString &slt, const QString &info) = 0;
+ };
+}
+
+#endif
diff --git a/kunittest/example/Makefile.am b/kunittest/example/Makefile.am
new file mode 100644
index 00000000..d008ca22
--- /dev/null
+++ b/kunittest/example/Makefile.am
@@ -0,0 +1 @@
+SUBDIRS = simple module
diff --git a/kunittest/example/module/Makefile.am b/kunittest/example/module/Makefile.am
new file mode 100644
index 00000000..17404d06
--- /dev/null
+++ b/kunittest/example/module/Makefile.am
@@ -0,0 +1,20 @@
+INCLUDES = -I$(top_srcdir)/include $(all_includes)
+METASOURCES = AUTO
+
+noinst_HEADERS = samplemodule.h sampleextra.h sampletests.h
+
+check_LTLIBRARIES = kunittest_samplemodule.la kunittest_samplemodule2.la
+
+kunittest_samplemodule_la_SOURCES = samplemodule.cpp sampletests.cpp sampleextra.cpp
+kunittest_samplemodule_la_LIBADD = -lkunittest
+kunittest_samplemodule_la_LDFLAGS = -module $(KDE_CHECK_PLUGIN) $(all_libraries)
+
+kunittest_samplemodule2_la_SOURCES = samplemodule2.cpp
+kunittest_samplemodule2_la_LIBADD = -lkunittest
+kunittest_samplemodule2_la_LDFLAGS = -module $(KDE_CHECK_PLUGIN) $(all_libraries)
+
+check-local:
+ kunittestmodrunner
+
+guicheck:
+ $(srcdir)/../../kunittestmod $(PWD)
diff --git a/kunittest/example/module/sampleextra.cpp b/kunittest/example/module/sampleextra.cpp
new file mode 100644
index 00000000..38c49448
--- /dev/null
+++ b/kunittest/example/module/sampleextra.cpp
@@ -0,0 +1,37 @@
+/**
+ * Copyright (C) 2005 Jeroen Wijnhout <Jeroen.Wijnhout@kdemail.net>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <kdebug.h>
+#include <kunittest/tester.h>
+
+#include "sampleextra.h"
+
+
+void SomeExtraTester::allTests()
+{
+ kdDebug() << "Debug output belonging to SomeExtraTester." << endl;
+
+ CHECK( QString("Extra") , QString("Extra") );
+}
diff --git a/kunittest/example/module/sampleextra.h b/kunittest/example/module/sampleextra.h
new file mode 100644
index 00000000..f27a6bd9
--- /dev/null
+++ b/kunittest/example/module/sampleextra.h
@@ -0,0 +1,36 @@
+/**
+ * Copyright (C) 2005 Jeroen Wijnhout <Jeroen.Wijnhout@kdemail.net>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _SAMPLEEXTRA_H_
+#define _SAMPLEEXTRA_H_
+
+#include <kunittest/tester.h>
+
+class SomeExtraTester : public KUnitTest::Tester
+{
+ void allTests();
+};
+
+#endif
diff --git a/kunittest/example/module/samplemodule.cpp b/kunittest/example/module/samplemodule.cpp
new file mode 100644
index 00000000..3b6665fd
--- /dev/null
+++ b/kunittest/example/module/samplemodule.cpp
@@ -0,0 +1,37 @@
+/**
+ * Copyright (C) 2005 Jeroen Wijnhout <Jeroen.Wijnhout@kdemail.net>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <kunittest/runner.h>
+#include <kunittest/module.h>
+
+#include "sampletests.h"
+#include "sampleextra.h"
+
+using namespace KUnitTest;
+
+KUNITTEST_MODULE( kunittest_samplemodule, "Suite1" )
+KUNITTEST_MODULE_REGISTER_TESTER( SlotSampleTester )
+KUNITTEST_MODULE_REGISTER_TESTER( SomeSampleTester )
+KUNITTEST_MODULE_REGISTER_TESTER( SomeExtraTester )
diff --git a/kunittest/example/module/samplemodule.h b/kunittest/example/module/samplemodule.h
new file mode 100644
index 00000000..b09002c6
--- /dev/null
+++ b/kunittest/example/module/samplemodule.h
@@ -0,0 +1,43 @@
+/**
+ * Copyright (C) 2005 Jeroen Wijnhout <Jeroen.Wijnhout@kdemail.net>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef SAMPLETESTMODULE_H
+#define SAMPLETESTMODULE_H
+
+#include <kunittest/tester.h>
+
+class SimpleSampleTester : public KUnitTest::Tester
+{
+public:
+ void allTests();
+};
+
+class SomeSampleTester : public KUnitTest::Tester
+{
+public:
+ void allTests();
+};
+
+#endif
diff --git a/kunittest/example/module/samplemodule2.cpp b/kunittest/example/module/samplemodule2.cpp
new file mode 100644
index 00000000..87efde28
--- /dev/null
+++ b/kunittest/example/module/samplemodule2.cpp
@@ -0,0 +1,61 @@
+/**
+ * Copyright (C) 2005 Jeroen Wijnhout <Jeroen.Wijnhout@kdemail.net>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <qstringlist.h>
+
+#include <kdebug.h>
+#include <kunittest/runner.h>
+#include <kunittest/module.h>
+
+#include "samplemodule.h"
+
+using namespace KUnitTest;
+
+KUNITTEST_MODULE( kunittest_samplemodule2, "Suite2::Sub" )
+KUNITTEST_MODULE_REGISTER_TESTER( SimpleSampleTester )
+KUNITTEST_MODULE_REGISTER_TESTER( SomeSampleTester )
+
+void SimpleSampleTester::allTests()
+{
+ kdDebug() << "Debug output belonging to SimpleSampleTester." << endl;
+ CHECK( QString("SimpleSample") , QString("SimpleSample") );
+
+ // operator == is used, so this can't work...
+ //XFAIL( "SimpleSample" , "SampleSimple" );
+
+ kdDebug() << "Do some math." << endl;
+ //XFAIL( 2*2 , 4 ); // to test unexpected passes
+ SKIP("Just curious how this 'skipping' works.");
+}
+
+void SomeSampleTester::allTests()
+{
+ kdDebug() << "Checking operator precedences." << endl;
+ CHECK( 2.0 * 3.0 / 2.0 * 4.0 / 2.0 , 6.0 );
+
+ QStringList testList;
+ testList << "one" << "two";
+ CHECK( testList.count() , (QStringList::size_type) 2 );
+}
diff --git a/kunittest/example/module/samplemodule2.h b/kunittest/example/module/samplemodule2.h
new file mode 100644
index 00000000..b09002c6
--- /dev/null
+++ b/kunittest/example/module/samplemodule2.h
@@ -0,0 +1,43 @@
+/**
+ * Copyright (C) 2005 Jeroen Wijnhout <Jeroen.Wijnhout@kdemail.net>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef SAMPLETESTMODULE_H
+#define SAMPLETESTMODULE_H
+
+#include <kunittest/tester.h>
+
+class SimpleSampleTester : public KUnitTest::Tester
+{
+public:
+ void allTests();
+};
+
+class SomeSampleTester : public KUnitTest::Tester
+{
+public:
+ void allTests();
+};
+
+#endif
diff --git a/kunittest/example/module/sampletests.cpp b/kunittest/example/module/sampletests.cpp
new file mode 100644
index 00000000..3b253e55
--- /dev/null
+++ b/kunittest/example/module/sampletests.cpp
@@ -0,0 +1,82 @@
+/**
+ * Copyright (C) 2005 Jeroen Wijnhout <Jeroen.Wijnhout@kdemail.net>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <qstringlist.h>
+
+#include <kdebug.h>
+#include <kunittest/runner.h>
+#include <kunittest/module.h>
+
+#include "sampletests.h"
+#include "sampleextra.h"
+
+void SlotSampleTester::setUp()
+{
+ kdDebug() << "setUp" << endl;
+ m_str = new QString("setUp str");
+}
+
+void SlotSampleTester::tearDown()
+{
+ kdDebug() << "tearDown" << endl;
+ delete m_str;
+}
+
+bool SlotSampleTester::test()
+{
+ kdDebug() << "SlotSampleTester::test()" << endl;
+ return true;
+}
+
+void SlotSampleTester::testSlot()
+{
+ kdDebug() << "Debug output belonging to SlotSampleTester slot 1." << endl;
+ CHECK( test() , true);
+ CHECK( "test" , "test");
+ kdDebug() << "Checking if m_str is initialized correctly." << endl;
+ CHECK( *m_str , QString("setUp str") );
+}
+
+void SlotSampleTester::testSlot2()
+{
+ kdDebug() << "Debug output belonging to SlotSampleTester slot 2." << endl;
+ CHECK("testSlot2","testSlot2");
+ CHECK(1,1);
+ CHECK(2,2);
+}
+
+void SomeSampleTester::allTests()
+{
+ kdDebug() << "Checking operator precedences." << endl;
+ CHECK( 2.0 * 3.0 / 2.0 * 4.0 / 2.0 , 6.0 );
+
+ QStringList testList;
+ testList << "one" << "two";
+ CHECK( testList.count() , (QStringList::size_type) 2 );
+ CHECK( testList.count()*2 , (QStringList::size_type) 4 );
+}
+
+#include "sampletests.moc"
+
diff --git a/kunittest/example/module/sampletests.h b/kunittest/example/module/sampletests.h
new file mode 100644
index 00000000..63ff6e44
--- /dev/null
+++ b/kunittest/example/module/sampletests.h
@@ -0,0 +1,53 @@
+/**
+ * Copyright (C) 2005 Jeroen Wijnhout <Jeroen.Wijnhout@kdemail.net>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef SAMPLETESTMODULE_H
+#define SAMPLETESTMODULE_H
+
+#include <kunittest/tester.h>
+
+class SlotSampleTester : public KUnitTest::SlotTester
+{
+ Q_OBJECT
+
+public slots:
+ void setUp();
+ void tearDown();
+ void testSlot();
+ void testSlot2();
+
+private:
+ bool test();
+
+ QString *m_str;
+};
+
+class SomeSampleTester : public KUnitTest::Tester
+{
+public:
+ void allTests();
+};
+
+#endif
diff --git a/kunittest/example/simple/Makefile.am b/kunittest/example/simple/Makefile.am
new file mode 100644
index 00000000..f35b8228
--- /dev/null
+++ b/kunittest/example/simple/Makefile.am
@@ -0,0 +1,22 @@
+INCLUDES = -I$(top_srcdir) $(all_includes)
+METASOURCES = AUTO
+
+check_PROGRAMS = sampletests sampletestsgui
+
+sampletests_SOURCES = main.cpp sampletest.cpp
+sampletests_LDFLAGS = $(KDE_RPATH) $(all_libraries)
+sampletests_LDADD = -lkunittest
+
+sampletestsgui_SOURCES = maingui.cpp sampletest.cpp
+sampletestsgui_LDFLAGS = $(KDE_RPATH) $(all_libraries)
+# Normally you would write -lkunittestgui here, but since the examples
+# are bundled with the library source code itself we don't want to
+# have you install the libraries before you can compile the examples.
+sampletestsgui_LDADD = ../../libkunittestgui.la
+
+noinst_HEADERS = sampletest.h
+
+TESTS = sampletests
+
+guicheck: sampletestsgui
+ kunittest ./sampletestsgui SampleTests
diff --git a/kunittest/example/simple/main.cpp b/kunittest/example/simple/main.cpp
new file mode 100644
index 00000000..a750587c
--- /dev/null
+++ b/kunittest/example/simple/main.cpp
@@ -0,0 +1,32 @@
+/**
+ * Copyright (C) 2005 Jeroen Wijnhout <Jeroen.Wijnhout@kdemail.net>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "kunittest/runner.h"
+
+int main( int /*argc*/, char** /*argv*/ )
+{
+ KUnitTest::Runner::self()->runTests();
+ return KUnitTest::Runner::self()->numberOfFailedTests();
+}
diff --git a/kunittest/example/simple/maingui.cpp b/kunittest/example/simple/maingui.cpp
new file mode 100644
index 00000000..63e8cfd9
--- /dev/null
+++ b/kunittest/example/simple/maingui.cpp
@@ -0,0 +1,60 @@
+/**
+ * Copyright (C) 2005 Jeroen Wijnhout <Jeroen.Wijnhout@kdemail.net>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <kaboutdata.h>
+#include <kapplication.h>
+#include <kcmdlineargs.h>
+#include <klocale.h>
+
+#include "kunittest/runnergui.h"
+
+static const char description[] =
+ I18N_NOOP("A simple sample.");
+
+static const char version[] = "0.1";
+
+static KCmdLineOptions options[] =
+{
+// { "+[URL]", I18N_NOOP( "Document to open" ), 0 },
+ KCmdLineLastOption
+};
+
+int main( int argc, char** argv )
+{
+ KAboutData about("SampleTests", I18N_NOOP("SampleTests"), version, description,
+ KAboutData::License_BSD, "(C) 2005 Jeroen Wijnhout", 0, 0,
+ "Jeroen.Wijnhout@kdemail.net");
+
+ KCmdLineArgs::init(argc, argv, &about);
+ KCmdLineArgs::addCmdLineOptions( options );
+
+ KApplication app;
+
+ KUnitTest::RunnerGUI runner(0);
+ runner.show();
+ app.setMainWidget(&runner);
+
+ return app.exec();
+}
diff --git a/kunittest/example/simple/sampletest.cpp b/kunittest/example/simple/sampletest.cpp
new file mode 100644
index 00000000..32d97703
--- /dev/null
+++ b/kunittest/example/simple/sampletest.cpp
@@ -0,0 +1,55 @@
+/**
+ * Copyright (C) 2005 Jeroen Wijnhout <Jeroen.Wijnhout@kdemail.net>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <qstringlist.h>
+
+#include <kdebug.h>
+#include <kunittest/runner.h>
+
+#include "sampletest.h"
+
+using namespace KUnitTest;
+
+KUNITTEST_SUITE("SampleSuite");
+KUNITTEST_REGISTER_TESTER(SimpleSampleTester);
+KUNITTEST_REGISTER_TESTER(SomeSampleTester);
+
+void SimpleSampleTester::allTests()
+{
+ kdDebug() << "Debug output belonging to SimpleSampleTester." << endl;
+ CHECK( QString("SimpleSample") , QString("SimpleSample") );
+
+ SKIP("Just curious how this 'skipping' works.");
+}
+
+void SomeSampleTester::allTests()
+{
+ kdDebug() << "Checking operator precedences." << endl;
+ CHECK( 2.0 * 3.0 / 2.0 * 4.0 / 2.0 , 6.0 );
+
+ QStringList testList;
+ testList << "one" << "two";
+ CHECK( testList.count() , (QStringList::size_type) 2 );
+}
diff --git a/kunittest/example/simple/sampletest.h b/kunittest/example/simple/sampletest.h
new file mode 100644
index 00000000..a4d85266
--- /dev/null
+++ b/kunittest/example/simple/sampletest.h
@@ -0,0 +1,42 @@
+/**
+ * Copyright (C) 2005 Jeroen Wijnhout <Jeroen.Wijnhout@kdemail.net>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef SAMPLETEST_H
+#define SAMPLETEST_H
+
+#include <kunittest/tester.h>
+
+class SimpleSampleTester : public KUnitTest::Tester
+{
+public:
+ void allTests();
+};
+
+class SomeSampleTester : public KUnitTest::Tester
+{
+public:
+ void allTests();
+};
+#endif
diff --git a/kunittest/guimodrunner.cpp b/kunittest/guimodrunner.cpp
new file mode 100644
index 00000000..08f47734
--- /dev/null
+++ b/kunittest/guimodrunner.cpp
@@ -0,0 +1,72 @@
+/**
+ * Copyright (C) 2005 Jeroen Wijnhout <Jeroen.Wijnhout@kdemail.net>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <kdebug.h>
+#include <kapplication.h>
+#include <kglobal.h>
+#include <kinstance.h>
+#include <kaboutdata.h>
+#include <kcmdlineargs.h>
+#include <klocale.h>
+
+#include "runnergui.h"
+
+static const char description[] =
+ I18N_NOOP("A command-line application that can be used to run KUnitTest modules.");
+
+static const char version[] = "0.1";
+
+static KCmdLineOptions options[] =
+{
+ {"query [regexp]", I18N_NOOP("Only run modules which filename match the regexp."), "^kunittest_.*\\.la$"},
+ {"folder [folder]", I18N_NOOP("Only run tests modules which are found in the folder. Use the query option to select modules."), "."},
+ { "enable-dbgcap", I18N_NOOP("Enables debug capturing. You typically use this option when you use the GUI."), 0},
+ KCmdLineLastOption
+};
+
+
+int main( int argc, char **argv )
+{
+ KInstance instance("modrunner");
+
+ KAboutData about("KUnitTestModRunner", I18N_NOOP("KUnitTestModRunner"), version, description,
+ KAboutData::License_BSD, "(C) 2005 Jeroen Wijnhout", 0, 0,
+ "Jeroen.Wijnhout@kdemail.net");
+
+ KCmdLineArgs::init(argc, argv, &about);
+ KCmdLineArgs::addCmdLineOptions( options );
+ KCmdLineArgs *args = KCmdLineArgs::parsedArgs();
+
+ KUnitTest::Runner::loadModules(args->getOption("folder"), args->getOption("query"));
+ KUnitTest::Runner::setDebugCapturingEnabled(args->isSet("enable-dbgcap"));
+
+ KApplication app;
+
+ KUnitTest::RunnerGUI runner(0);
+ runner.show();
+ app.setMainWidget(&runner);
+
+ return app.exec();
+}
diff --git a/kunittest/kunittest b/kunittest/kunittest
new file mode 100755
index 00000000..fbb8424f
--- /dev/null
+++ b/kunittest/kunittest
@@ -0,0 +1,19 @@
+#!/bin/bash
+
+export APP=$1
+export DCOPNAME=$2
+
+if [ ! -x $APP ]
+then
+ kdialog --error "Sorry, $APP is not a valid executable file."
+ exit 1;
+fi
+
+DEBUGHELPER=`which kunittest_debughelper`
+if [ -z $DEBUGHELPER ]
+then
+ kdialog --error "Sorry, couldn't find the kunittest_debughelper script."
+ exit 3
+fi
+
+$APP 2>&1 | perl $DEBUGHELPER "$DCOPNAME-*"
diff --git a/kunittest/kunittest_debughelper b/kunittest/kunittest_debughelper
new file mode 100755
index 00000000..66dfacf2
--- /dev/null
+++ b/kunittest/kunittest_debughelper
@@ -0,0 +1,107 @@
+#!/usr/bin/perl
+# Copyright (C) 2005 Jeroen Wijnhout <Jeroen.Wijnhout@kdemail.net>
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+#
+# 1. Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+#
+# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+# OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+# IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+# NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+use DCOP;
+
+my $app = $ARGV[0]; shift @ARGV;
+my $dcopid = "";
+my $testername = "";
+my $reading_debug = 0;
+my $debug="";
+my $runnergui;
+
+my $client = new DCOP;
+$client->attach();
+
+while (<>)
+{
+ $runnergui = getDCOPObject();
+ my $line = $_;
+
+ print $_;
+
+ if ( $line =~ /KUnitTest_Debug_End\[.*\]/ )
+ {
+ $ret = $runnergui->addDebugInfo($testername, $debug);
+
+ $debug = "";
+
+ # stop reading
+ $reading_debug = 0;
+ }
+ elsif ( $line =~ /KUnitTest_Debug_EndSlot\[.*\]/ )
+ {
+ $ret = $runnergui->addSlotDebugInfo($testername, $slotname, $debug);
+
+ $line = "";
+ $debug = "";
+ $slotname = "";
+ }
+ elsif ( $line =~ /KUnitTest_Debug_BeginSlot\[(.*)\]/ )
+ {
+ $slotname = $1;
+ $line = "";
+ }
+
+ if ( $reading_debug )
+ {
+ if ( $line =~ /^check:(.*\[[0-9]+\])/ )
+ {
+ $line = $1.":\n";
+ }
+
+ $debug = $debug.$line;
+ }
+
+ if ( $line =~ /KUnitTest_Debug_Start\[(.*)\]/ )
+ {
+ $testername = $1;
+ $reading_debug = 1;
+ $debug="";
+ }
+}
+
+sub getDCOPObject
+{
+ if ( $dcopid eq "" )
+ {
+ $allapps = $client->registeredApplications();
+ my $i = 0;
+ while ( ! ($allapps->[$i] eq "") )
+ {
+ if ( $allapps->[$i] =~ /$app/ )
+ {
+ print "found: ".$allapps->[$i]."\n";
+ $dcopid = $allapps->[$i];
+ break;
+ }
+
+ $i = $i + 1;
+ }
+
+ $object = $client->createObject($dcopid, "Runner");
+ }
+
+ return $object;
+} \ No newline at end of file
diff --git a/kunittest/kunittestmod b/kunittest/kunittestmod
new file mode 100755
index 00000000..ba039844
--- /dev/null
+++ b/kunittest/kunittestmod
@@ -0,0 +1,37 @@
+#!/bin/bash
+
+FOLDER="--folder $PWD"
+QUERY=""
+
+while [ "$#" -gt 0 ]
+do
+ case $1 in
+ -f|--folder)
+ FOLDER="--folder $2"
+ shift
+ ;;
+ -q|--query)
+ QUERY="--query $2"
+ shift
+ ;;
+ esac
+ # to process the next parameter
+ shift
+done
+
+APP=`which kunittestguimodrunner`
+if [ ! -x $APP ]
+then
+ kdialog --error "Sorry, $APP is not a valid executable file."
+ exit 1;
+fi
+
+DEBUGHELPER=`which kunittest_debughelper`
+if [ -z $DEBUGHELPER ]
+then
+ kdialog --error "Sorry, couldn't find the kunittest_debughelper script."
+ exit 3
+fi
+
+DCOPNAME="KUnitTestModRunner"
+$APP --enable-dbgcap $FOLDER $QUERY 2>&1 | perl $DEBUGHELPER "$DCOPNAME-*"
diff --git a/kunittest/runnergui.cpp b/kunittest/runnergui.cpp
new file mode 100644
index 00000000..ef5afe98
--- /dev/null
+++ b/kunittest/runnergui.cpp
@@ -0,0 +1,433 @@
+/**
+ * Copyright (C) 2005 Jeroen Wijnhout <Jeroen.Wijnhout@kdemail.net>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <qmetaobject.h>
+#include <qregexp.h>
+#include <qpushbutton.h>
+#include <qtextedit.h>
+#include <qlabel.h>
+#include <qprogressbar.h>
+#include <qcombobox.h>
+
+#include <dcopclient.h>
+#include <dcopobject.h>
+#include <kiconloader.h>
+#include <kdebug.h>
+#include <kmessagebox.h>
+
+#include <kunittest/tester.h>
+
+#include "dcopinterface.h"
+#include "runnergui.h"
+#include "testerwidget.h"
+
+namespace KUnitTest
+{
+ const int g_nameColumn = 0;
+ const int g_finishedColumn = 1;
+ const int g_skippedColumn = 2;
+ const int g_failedColumn = 3;
+ const int g_xfailedColumn = 4;
+ const int g_passedColumn = 5;
+ const int g_xpassedColumn = 6;
+
+ /*! The DCOP implementation for the RunnerGUI.
+ */
+ class RunnerGUIDCOPImpl : virtual public DCOPInterface
+ {
+ public:
+ RunnerGUIDCOPImpl(RunnerGUI *rg) : m_rg(rg)
+ {
+ // set the DCOP object id
+ setObjId("Runner");
+ }
+
+ /*! This DCOP method adds debug info to a given test case.
+ * @param name The name of the test.
+ * @param info The debug info.
+ */
+ bool addDebugInfo(const QString &name, const QString &info)
+ {
+ Tester *tester = Runner::self()->registry().find(name.local8Bit());
+ if ( tester == 0L ) return false;
+
+ tester->results()->addDebugInfo(info);
+
+ return true;
+ }
+
+ bool addSlotDebugInfo(const QString &name, const QString &slt, const QString &info)
+ {
+ Tester *tester = Runner::self()->registry().find(name.local8Bit());
+
+ if ( tester == 0L ) return false;
+ if ( ! tester->inherits("KUnitTest::SlotTester") ) return false;
+
+ SlotTester *sltester = static_cast<SlotTester*>(tester);
+ sltester->results(slt.local8Bit())->addDebugInfo(info);
+
+ return true;
+ }
+
+ private:
+ RunnerGUI *m_rg;
+ };
+
+ RunnerGUI::RunnerGUI(QWidget *parent) : QHBox(parent)
+ {
+ m_dcop = new RunnerGUIDCOPImpl(this);
+
+ m_testerWidget = new TesterWidget(this);
+ setGeometry(0, 0, 700, 500);
+
+ // file the combo box
+ m_testerWidget->selectCombo()->insertItem("All suites/modules . . .");
+ m_testerWidget->selectCombo()->insertItem("Selected tests . . .");
+
+ RegistryIteratorType it(Runner::self()->registry());
+ QStringList suites;
+ for ( ; it.current(); ++it )
+ {
+ addTester(it.currentKey(), it.current());
+
+ QString test = it.currentKey();
+ int index = test.find("::");
+ if ( index != -1 ) test = test.left(index);
+
+ if ( suites.contains(test) == 0 )
+ suites.append(test);
+ }
+
+ for ( uint i = 0; i < suites.count(); ++i )
+ m_testerWidget->selectCombo()->insertItem(suites[i]);
+
+ // configure the resultslist
+ m_testerWidget->resultList()->setAllColumnsShowFocus(true);
+ m_testerWidget->resultList()->setSelectionMode(QListView::Extended);
+ m_testerWidget->resultList()->setRootIsDecorated(true);
+ m_testerWidget->resultList()->setColumnAlignment(g_finishedColumn, Qt::AlignHCenter);
+ m_testerWidget->resultList()->setColumnAlignment(g_skippedColumn, Qt::AlignHCenter);
+ m_testerWidget->resultList()->setColumnAlignment(g_failedColumn, Qt::AlignHCenter);
+ m_testerWidget->resultList()->setColumnAlignment(g_xfailedColumn, Qt::AlignHCenter);
+ m_testerWidget->resultList()->setColumnAlignment(g_passedColumn, Qt::AlignHCenter);
+ m_testerWidget->resultList()->setColumnAlignment(g_xpassedColumn, Qt::AlignHCenter);
+
+ // set the text in the results label
+ fillResultsLabel();
+
+ // init the progress bar
+ configureProgressBar(Runner::self()->numberOfTestCases(), 0);
+
+ connect(Runner::self(), SIGNAL(finished(const char *, Tester *)), this, SLOT(addTestResult(const char *, Tester *)));
+ connect(m_testerWidget->resultList(), SIGNAL(clicked(QListViewItem *)), this, SLOT(showDetails(QListViewItem *)));
+ connect(m_testerWidget, SIGNAL(run()), this, SLOT(runSuite()));
+ connect(m_testerWidget->details(), SIGNAL(doubleClicked(int, int)), this, SLOT(doubleClickedOnDetails(int, int)));
+ }
+
+ RunnerGUI::~RunnerGUI()
+ {
+ delete m_dcop;
+ }
+
+ void RunnerGUI::configureProgressBar(int steps, int progress)
+ {
+ m_testerWidget->progressBar()->setTotalSteps(steps);
+ m_testerWidget->progressBar()->setProgress(progress);
+ }
+
+ void RunnerGUI::fillResultsLabel()
+ {
+ if ( Runner::self()->numberOfTests() > 0 )
+ m_testerWidget->resultsLabel()->setText(
+ QString("Test cases: %1 | Tests performed: %5, Skipped: <font color=\"#f7a300\">%4</font> | Passed: <font color=\"#009900\">%2</font>, Failed: <font color=\"#990000\">%3</font>")
+ .arg(Runner::self()->numberOfTestCases())
+ .arg(Runner::self()->numberOfPassedTests())
+ .arg(Runner::self()->numberOfFailedTests())
+ .arg(Runner::self()->numberOfSkippedTests())
+ .arg(Runner::self()->numberOfTests()) );
+ else
+ m_testerWidget->resultsLabel()->setText(QString("Test cases: %1").arg(Runner::self()->numberOfTestCases()));
+ }
+
+ void RunnerGUI::addTestResult(const char *name, Tester *test)
+ {
+ QStringList scopes = QStringList::split("::", name);
+ QString suite = scopes[0];
+
+ // find the suite item
+ QListViewItem *item = 0L;
+ for ( uint i = 0; i < scopes.count(); ++i )
+ item = getItem(scopes[i], item);
+
+ if ( test->inherits("KUnitTest::SlotTester") )
+ {
+ SlotTester *sltest = static_cast<SlotTester*>(test);
+ TestResultsListIteratorType it(sltest->resultsList());
+ QListViewItem *slotItem = 0L;
+ for ( ; it.current(); ++it)
+ {
+ slotItem = getItem(it.currentKey(), item);
+ setSummary(slotItem, it.current());
+ }
+ }
+ else
+ setSummary(item, test->results());
+
+ fillResultsLabel();
+ m_testerWidget->progressBar()->setProgress(m_testerWidget->progressBar()->progress() + 1);
+ }
+
+ void RunnerGUI::addTester(const char *name, Tester *test)
+ {
+ QStringList scopes = QStringList::split("::", name);
+ QString suite = scopes[0];
+
+ // find the suite item
+ QListViewItem *item = 0L;
+ for ( uint i = 0; i < scopes.count(); ++i )
+ item = getItem(scopes[i], item);
+
+ if ( test->inherits("KUnitTest::SlotTester") )
+ {
+ QStrList allSlots = test->metaObject()->slotNames();
+ for ( char *sl = allSlots.first(); sl; sl = allSlots.next() )
+ {
+ if ( QString(sl).startsWith("test") )
+ getItem(sl, item);
+ }
+ }
+ }
+
+ QListViewItem *RunnerGUI::getItem(const QString &name, QListViewItem *item /*= 0L*/)
+ {
+ QListViewItem *parent = item;
+
+ if ( item == 0L ) item = m_testerWidget->resultList()->firstChild();
+ else item = item->firstChild();
+
+ while ( item && (item->text(g_nameColumn) != name) )
+ item = item->nextSibling();
+
+ // item not found, create it
+ if ( item == 0L )
+ {
+ if ( parent == 0L )
+ item = new QListViewItem(m_testerWidget->resultList());
+ else
+ item = new QListViewItem(parent);
+
+ item->setText(g_nameColumn, name);
+ }
+
+ return item;
+ }
+
+ void RunnerGUI::reset()
+ {
+ QListViewItemIterator it( m_testerWidget->resultList() );
+ while ( it.current() )
+ {
+ QListViewItem *item = it.current();
+ item->setText(g_finishedColumn, "0");
+ item->setText(g_skippedColumn, "0");
+ item->setText(g_failedColumn, "0");
+ item->setText(g_xfailedColumn, "0");
+ item->setText(g_passedColumn, "0");
+ item->setText(g_xpassedColumn, "0");
+ item->setPixmap(g_nameColumn, QPixmap());
+ ++it;
+ }
+ }
+
+ void RunnerGUI::setSummary(QListViewItem *item, TestResults *res)
+ {
+ if ( item == 0L ) return;
+
+ bool ok;
+
+ int val = item->text(g_finishedColumn).toInt(&ok); if (!ok) val = 0;
+ item->setText(g_finishedColumn, QString::number(val + res->testsFinished()));
+
+ val = item->text(g_skippedColumn).toInt(&ok); if (!ok) val = 0;
+ item->setText(g_skippedColumn, QString::number(val + res->skipped()));
+
+ val = item->text(g_passedColumn).toInt(&ok); if (!ok) val = 0;
+ item->setText(g_passedColumn, QString::number(val + res->passed()));
+
+ val = item->text(g_failedColumn).toInt(&ok); if (!ok) val = 0;
+ item->setText(g_failedColumn, QString::number(val + res->errors()));
+
+ val = item->text(g_xfailedColumn).toInt(&ok); if (!ok) val = 0;
+ item->setText(g_xfailedColumn, QString::number(val + res->xfails()));
+
+ val = item->text(g_xpassedColumn).toInt(&ok); if (!ok) val = 0;
+ item->setText(g_xpassedColumn, QString::number(val + res->xpasses()));
+
+ bool passed = (item->text(g_failedColumn).toInt(&ok) + item->text(g_xfailedColumn).toInt(&ok)) == 0;
+ item->setPixmap(g_nameColumn, passed ? SmallIcon("button_ok") : SmallIcon("button_cancel") );
+
+ setSummary(item->parent(), res);
+ }
+
+ QString RunnerGUI::fullName(QListViewItem *item)
+ {
+ QString name = item->text(g_nameColumn);
+ while ( (item = item->parent()) != 0L )
+ name = item->text(g_nameColumn) + "::" + name;
+
+ return name;
+ }
+
+ void RunnerGUI::runSuite()
+ {
+ Runner::self()->reset();
+ reset();
+
+ if ( m_testerWidget->selectCombo()->currentItem() == 0 )
+ {
+ configureProgressBar(Runner::self()->numberOfTestCases(), 0);
+ Runner::self()->runTests();
+ }
+ else if ( m_testerWidget->selectCombo()->currentItem() == 1 )
+ {
+ QListViewItemIterator it( m_testerWidget->resultList() );
+ QStringList prefixes;
+ while ( it.current() )
+ {
+ QListViewItem *item = it.current();
+ if ( item->isSelected() )
+ {
+ QString prefix = fullName(item);
+ if ( prefix.endsWith("()") )
+ {
+ int index = prefix.findRev("::");
+ prefix = prefix.left(index);
+ }
+ prefixes << prefix;
+ }
+
+ ++it;
+ }
+
+ configureProgressBar(prefixes.count(), 0);
+ for ( uint i = 0; i < prefixes.count(); ++i )
+ Runner::self()->runMatchingTests(prefixes[i]);
+ }
+ else
+ {
+ QString suite = m_testerWidget->selectCombo()->currentText();
+ QStringList tests;
+ RegistryIteratorType it(Runner::self()->registry());
+ for ( ; it.current(); ++it )
+ if ( QString(it.currentKey()).startsWith(suite) )
+ tests.append(it.currentKey());
+
+ configureProgressBar(tests.count(), 0);
+
+ for ( uint i = 0; i < tests.count(); ++i )
+ Runner::self()->runTest(tests[i].local8Bit());
+ }
+
+ showDetails(m_testerWidget->resultList()->currentItem());
+ }
+
+ void RunnerGUI::showDetails(QListViewItem *item)
+ {
+ if ( item == 0L ) return;
+
+ QString name = fullName(item);
+ if ( name.endsWith("()") ) name = fullName(item->parent());
+
+ Tester *tester = Runner::self()->registry().find(name.local8Bit());
+
+ if ( tester == 0L ) return;
+
+ TestResults *res = 0L;
+ if ( tester->inherits("KUnitTest::SlotTester") )
+ res = static_cast<SlotTester*>(tester)->results(item->text(g_nameColumn).local8Bit());
+ else
+ res = tester->results();
+
+ if ( tester == 0L )
+ m_testerWidget->details()->setText("No test found with name: " + fullName(item));
+ else
+ {
+ QTextEdit *te = m_testerWidget->details();
+
+ te->clear();
+
+ te->append("<qt><a name=\"errors\"><font color=\"#990000\">Errors</font></a>:<br></qt>");
+ appendList(te, res->errorList());
+
+ te->append("<qt><br><hr><font color=\"#c2c939\">Expected to fail</font>:<br></qt>");
+ appendList(te, res->xfailList());
+
+ te->append("<qt><br><hr><font color=\"#BF00B5\">Unexpected Success</font>:<br></qt>");
+ appendList(te, res->xpassList());
+
+ te->append("<qt><br><hr><font color=\"#009900\">Success</font>:<br></qt>");
+ appendList(te, res->successList());
+
+ te->append("<qt><br><hr><font color=\"#F7A300\">Skipped</font>:<br></qt>");
+ appendList(te, res->skipList());
+
+ te->append("<qt><br><hr><font color=\"#000099\">Debug</font>:<br></qt>");
+
+ te->append(res->debugInfo());
+
+ te->scrollToAnchor("errors");
+ }
+ }
+
+ void RunnerGUI::appendList(QTextEdit *te, const QStringList &list)
+ {
+ for ( uint i = 0; i < list.count(); ++i )
+ te->append(list[i]);
+ }
+
+ void RunnerGUI::doubleClickedOnDetails(int para, int /*pos*/)
+ {
+ static QRegExp reFileAndLine("^(.*)\\[([0-9]+)\\]:");
+
+ QString line = m_testerWidget->details()->text(para);
+ m_testerWidget->details()->setSelection(para, 0, para, line.length()-1);
+
+ if ( reFileAndLine.search(line) != -1 )
+ {
+ DCOPClient client;
+ client.attach();
+ QByteArray data;
+ QDataStream arg(data, IO_WriteOnly);
+ bool ok;
+ arg << QString(reFileAndLine.cap(1)) << (reFileAndLine.cap(2).toInt(&ok) - 1);
+ client.send("kdevelop-*", "KDevPartController", "editDocument(QString,int)", data);
+ client.send("kdevelop-*", "MainWindow", "raise()", "");
+
+ client.detach();
+ }
+ }
+}
+
+#include "runnergui.moc"
diff --git a/kunittest/runnergui.h b/kunittest/runnergui.h
new file mode 100644
index 00000000..dbd03666
--- /dev/null
+++ b/kunittest/runnergui.h
@@ -0,0 +1,78 @@
+/**
+ * Copyright (C) 2005 Jeroen Wijnhout <Jeroen.Wijnhout@kdemail.net>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _KUNITTEST_TESTER_H_
+#define _KUNITTEST_TESTER_H_
+
+#include <qlistview.h>
+#include <qhbox.h>
+
+#include <kunittest/runner.h>
+#include <kunittest/tester.h>
+
+#include <kdemacros.h>
+
+class TesterWidget;
+class QTextEdit;
+
+namespace KUnitTest
+{
+ class RunnerGUIDCOPImpl;
+
+ class KDE_EXPORT RunnerGUI : public QHBox
+ {
+ Q_OBJECT
+
+ public:
+ RunnerGUI(QWidget *parent);
+ ~RunnerGUI();
+
+ private slots:
+ void addTestResult(const char *name, Tester *test);
+ void addTester(const char *name, Tester *test);
+ void showDetails(QListViewItem *item);
+ void runSuite();
+ void doubleClickedOnDetails(int para, int pos);
+
+ private:
+ void reset();
+ void configureProgressBar(int steps, int progress);
+ void fillResultsLabel();
+ void appendList(QTextEdit *te, const QStringList &list);
+
+ QListViewItem *getItem(const QString &name, QListViewItem *item = 0L);
+ void setItem(QListViewItem *item, const TestResults *res);
+ QString fullName(QListViewItem *item);
+
+ void setSummary(QListViewItem *item, TestResults *res);
+
+ TesterWidget *m_testerWidget;
+
+ friend class RunnerGUIDCOPImpl;
+ RunnerGUIDCOPImpl *m_dcop;
+ };
+}
+
+#endif
diff --git a/kunittest/testerwidget.ui b/kunittest/testerwidget.ui
new file mode 100644
index 00000000..61f74337
--- /dev/null
+++ b/kunittest/testerwidget.ui
@@ -0,0 +1,197 @@
+<!DOCTYPE UI><UI version="3.3" stdsetdef="1">
+<class>TesterWidget</class>
+<widget class="QWidget">
+ <property name="name">
+ <cstring>TesterWidget</cstring>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>622</width>
+ <height>773</height>
+ </rect>
+ </property>
+ <property name="baseSize">
+ <size>
+ <width>500</width>
+ <height>500</height>
+ </size>
+ </property>
+ <property name="caption">
+ <string>KUnitTester</string>
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QPushButton" row="0" column="2">
+ <property name="name">
+ <cstring>m_pshRun</cstring>
+ </property>
+ <property name="text">
+ <string>Run</string>
+ </property>
+ </widget>
+ <widget class="QProgressBar" row="1" column="0" rowspan="1" colspan="3">
+ <property name="name">
+ <cstring>m_pbProgress</cstring>
+ </property>
+ </widget>
+ <widget class="QComboBox" row="0" column="1">
+ <property name="name">
+ <cstring>m_cbSelect</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>7</hsizetype>
+ <vsizetype>0</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ </widget>
+ <widget class="QLabel" row="0" column="0">
+ <property name="name">
+ <cstring>m_lbSelect</cstring>
+ </property>
+ <property name="text">
+ <string>Select a suite or module:</string>
+ </property>
+ </widget>
+ <widget class="QLabel" row="2" column="0" rowspan="1" colspan="3">
+ <property name="name">
+ <cstring>m_lbResults</cstring>
+ </property>
+ <property name="text">
+ <string></string>
+ </property>
+ </widget>
+ <widget class="QListView" row="3" column="0" rowspan="1" colspan="3">
+ <column>
+ <property name="text">
+ <string>Test</string>
+ </property>
+ <property name="clickable">
+ <bool>true</bool>
+ </property>
+ <property name="resizable">
+ <bool>true</bool>
+ </property>
+ </column>
+ <column>
+ <property name="text">
+ <string>Finished</string>
+ </property>
+ <property name="clickable">
+ <bool>true</bool>
+ </property>
+ <property name="resizable">
+ <bool>true</bool>
+ </property>
+ </column>
+ <column>
+ <property name="text">
+ <string>Skipped</string>
+ </property>
+ <property name="clickable">
+ <bool>true</bool>
+ </property>
+ <property name="resizable">
+ <bool>true</bool>
+ </property>
+ </column>
+ <column>
+ <property name="text">
+ <string>Failed</string>
+ </property>
+ <property name="clickable">
+ <bool>true</bool>
+ </property>
+ <property name="resizable">
+ <bool>true</bool>
+ </property>
+ </column>
+ <column>
+ <property name="text">
+ <string>xFailed</string>
+ </property>
+ <property name="clickable">
+ <bool>true</bool>
+ </property>
+ <property name="resizable">
+ <bool>true</bool>
+ </property>
+ </column>
+ <column>
+ <property name="text">
+ <string>Passed</string>
+ </property>
+ <property name="clickable">
+ <bool>true</bool>
+ </property>
+ <property name="resizable">
+ <bool>true</bool>
+ </property>
+ </column>
+ <column>
+ <property name="text">
+ <string>xPassed</string>
+ </property>
+ <property name="clickable">
+ <bool>true</bool>
+ </property>
+ <property name="resizable">
+ <bool>true</bool>
+ </property>
+ </column>
+ <property name="name">
+ <cstring>m_lvResults</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>7</hsizetype>
+ <vsizetype>1</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="minimumSize">
+ <size>
+ <width>0</width>
+ <height>200</height>
+ </size>
+ </property>
+ </widget>
+ <widget class="QTextEdit" row="4" column="0" rowspan="1" colspan="3">
+ <property name="name">
+ <cstring>m_teDetails</cstring>
+ </property>
+ <property name="minimumSize">
+ <size>
+ <width>600</width>
+ <height>200</height>
+ </size>
+ </property>
+ <property name="readOnly">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </grid>
+</widget>
+<includes>
+ <include location="local" impldecl="in implementation">testerwidget.ui.h</include>
+</includes>
+<signals>
+ <signal>run()</signal>
+</signals>
+<functions>
+ <function access="private" specifier="non virtual">init()</function>
+ <function returnType="QListView *">resultList()</function>
+ <function returnType="QTextEdit *">details()</function>
+ <function returnType="QProgressBar *">progressBar()</function>
+ <function returnType="QLabel *">resultsLabel()</function>
+ <function returnType="QComboBox *">selectCombo()</function>
+</functions>
+<layoutdefaults spacing="6" margin="11"/>
+</UI>
diff --git a/kunittest/testerwidget.ui.h b/kunittest/testerwidget.ui.h
new file mode 100644
index 00000000..b895a357
--- /dev/null
+++ b/kunittest/testerwidget.ui.h
@@ -0,0 +1,46 @@
+/****************************************************************************
+** ui.h extension file, included from the uic-generated form implementation.
+**
+** If you want to add, delete, or rename functions or slots, use
+** Qt Designer to update this file, preserving your code.
+**
+** You should not define a constructor or destructor in this file.
+** Instead, write your code in functions called init() and destroy().
+** These will automatically be called by the form's constructor and
+** destructor.
+*****************************************************************************/
+
+
+void TesterWidget::init()
+{
+ connect(m_pshRun, SIGNAL(clicked()), this, SIGNAL(run()));
+}
+
+QListView * TesterWidget::resultList()
+{
+ return m_lvResults;
+}
+
+
+QTextEdit * TesterWidget::details()
+{
+ return m_teDetails;
+}
+
+
+QProgressBar * TesterWidget::progressBar()
+{
+ return m_pbProgress;
+}
+
+
+QLabel * TesterWidget::resultsLabel()
+{
+ return m_lbResults;
+}
+
+
+QComboBox * TesterWidget::selectCombo()
+{
+ return m_cbSelect;
+}
diff --git a/poxml/GettextLexer.cpp b/poxml/GettextLexer.cpp
new file mode 100644
index 00000000..cc768114
--- /dev/null
+++ b/poxml/GettextLexer.cpp
@@ -0,0 +1,550 @@
+/* $ANTLR 2.7.1: "gettext.g" -> "GettextLexer.cpp"$ */
+#include "GettextLexer.hpp"
+#include "antlr/CharBuffer.hpp"
+#include "antlr/TokenStreamException.hpp"
+#include "antlr/TokenStreamIOException.hpp"
+#include "antlr/TokenStreamRecognitionException.hpp"
+#include "antlr/CharStreamException.hpp"
+#include "antlr/CharStreamIOException.hpp"
+#include "antlr/NoViableAltForCharException.hpp"
+
+#line 1 "gettext.g"
+
+#line 14 "GettextLexer.cpp"
+GettextLexer::GettextLexer(ANTLR_USE_NAMESPACE(std)istream& in)
+ : ANTLR_USE_NAMESPACE(antlr)CharScanner(new ANTLR_USE_NAMESPACE(antlr)CharBuffer(in))
+{
+ setCaseSensitive(true);
+ initLiterals();
+}
+
+GettextLexer::GettextLexer(ANTLR_USE_NAMESPACE(antlr)InputBuffer& ib)
+ : ANTLR_USE_NAMESPACE(antlr)CharScanner(ib)
+{
+ setCaseSensitive(true);
+ initLiterals();
+}
+
+GettextLexer::GettextLexer(const ANTLR_USE_NAMESPACE(antlr)LexerSharedInputState& state)
+ : ANTLR_USE_NAMESPACE(antlr)CharScanner(state)
+{
+ setCaseSensitive(true);
+ initLiterals();
+}
+
+void GettextLexer::initLiterals()
+{
+}
+bool GettextLexer::getCaseSensitiveLiterals() const
+{
+ return true;
+}
+
+ANTLR_USE_NAMESPACE(antlr)RefToken GettextLexer::nextToken()
+{
+ ANTLR_USE_NAMESPACE(antlr)RefToken theRetToken;
+ for (;;) {
+ ANTLR_USE_NAMESPACE(antlr)RefToken theRetToken;
+ int _ttype = ANTLR_USE_NAMESPACE(antlr)Token::INVALID_TYPE;
+ resetText();
+ try { // for char stream error handling
+ try { // for lexical error handling
+ switch ( LA(1)) {
+ case static_cast<unsigned char>('\t'):
+ case static_cast<unsigned char>('\n'):
+ case static_cast<unsigned char>('\r'):
+ case static_cast<unsigned char>(' '):
+ {
+ mWS(true);
+ theRetToken=_returnToken;
+ break;
+ }
+ case static_cast<unsigned char>('['):
+ {
+ mL_BRACKET(true);
+ theRetToken=_returnToken;
+ break;
+ }
+ case static_cast<unsigned char>(']'):
+ {
+ mR_BRACKET(true);
+ theRetToken=_returnToken;
+ break;
+ }
+ case static_cast<unsigned char>('0'):
+ case static_cast<unsigned char>('1'):
+ case static_cast<unsigned char>('2'):
+ case static_cast<unsigned char>('3'):
+ case static_cast<unsigned char>('4'):
+ case static_cast<unsigned char>('5'):
+ case static_cast<unsigned char>('6'):
+ case static_cast<unsigned char>('7'):
+ case static_cast<unsigned char>('8'):
+ case static_cast<unsigned char>('9'):
+ {
+ mT_INT(true);
+ theRetToken=_returnToken;
+ break;
+ }
+ case static_cast<unsigned char>('#'):
+ {
+ mT_COMMENT(true);
+ theRetToken=_returnToken;
+ break;
+ }
+ case static_cast<unsigned char>('m'):
+ {
+ mMSG_TAG(true);
+ theRetToken=_returnToken;
+ break;
+ }
+ case static_cast<unsigned char>('"'):
+ {
+ mT_STRING(true);
+ theRetToken=_returnToken;
+ break;
+ }
+ default:
+ {
+ if (LA(1)==EOF_CHAR) {uponEOF(); _returnToken = makeToken(ANTLR_USE_NAMESPACE(antlr)Token::EOF_TYPE);}
+ else {throw ANTLR_USE_NAMESPACE(antlr)NoViableAltForCharException(LA(1), getFilename(), getLine());}
+ }
+ }
+ if ( !_returnToken ) goto tryAgain; // found SKIP token
+ _ttype = _returnToken->getType();
+ _returnToken->setType(_ttype);
+ return _returnToken;
+ }
+ catch (ANTLR_USE_NAMESPACE(antlr)RecognitionException& e) {
+ throw ANTLR_USE_NAMESPACE(antlr)TokenStreamRecognitionException(e);
+ }
+ }
+ catch (ANTLR_USE_NAMESPACE(antlr)CharStreamIOException& csie) {
+ throw ANTLR_USE_NAMESPACE(antlr)TokenStreamIOException(csie.io);
+ }
+ catch (ANTLR_USE_NAMESPACE(antlr)CharStreamException& cse) {
+ throw ANTLR_USE_NAMESPACE(antlr)TokenStreamException(cse.getMessage());
+ }
+tryAgain:;
+ }
+}
+
+void GettextLexer::mWS(bool _createToken) {
+ int _ttype; ANTLR_USE_NAMESPACE(antlr)RefToken _token; int _begin=text.length();
+ _ttype = WS;
+ int _saveIndex;
+
+ {
+ switch ( LA(1)) {
+ case static_cast<unsigned char>(' '):
+ {
+ match(static_cast<unsigned char>(' '));
+ break;
+ }
+ case static_cast<unsigned char>('\t'):
+ {
+ match(static_cast<unsigned char>('\t'));
+ break;
+ }
+ case static_cast<unsigned char>('\n'):
+ case static_cast<unsigned char>('\r'):
+ {
+ {
+ switch ( LA(1)) {
+ case static_cast<unsigned char>('\n'):
+ {
+ match(static_cast<unsigned char>('\n'));
+ break;
+ }
+ case static_cast<unsigned char>('\r'):
+ {
+ match("\r\n");
+ break;
+ }
+ default:
+ {
+ throw ANTLR_USE_NAMESPACE(antlr)NoViableAltForCharException(LA(1), getFilename(), getLine());
+ }
+ }
+ }
+#line 110 "gettext.g"
+ newline();
+#line 173 "GettextLexer.cpp"
+ break;
+ }
+ default:
+ {
+ throw ANTLR_USE_NAMESPACE(antlr)NoViableAltForCharException(LA(1), getFilename(), getLine());
+ }
+ }
+ }
+#line 111 "gettext.g"
+ _ttype = ANTLR_USE_NAMESPACE(antlr)Token::SKIP;
+#line 184 "GettextLexer.cpp"
+ if ( _createToken && _token==ANTLR_USE_NAMESPACE(antlr)nullToken && _ttype!=ANTLR_USE_NAMESPACE(antlr)Token::SKIP ) {
+ _token = makeToken(_ttype);
+ _token->setText(text.substr(_begin, text.length()-_begin));
+ }
+ _returnToken = _token;
+ _saveIndex=0;
+}
+
+void GettextLexer::mL_BRACKET(bool _createToken) {
+ int _ttype; ANTLR_USE_NAMESPACE(antlr)RefToken _token; int _begin=text.length();
+ _ttype = L_BRACKET;
+ int _saveIndex;
+
+ match(static_cast<unsigned char>('['));
+ if ( _createToken && _token==ANTLR_USE_NAMESPACE(antlr)nullToken && _ttype!=ANTLR_USE_NAMESPACE(antlr)Token::SKIP ) {
+ _token = makeToken(_ttype);
+ _token->setText(text.substr(_begin, text.length()-_begin));
+ }
+ _returnToken = _token;
+ _saveIndex=0;
+}
+
+void GettextLexer::mR_BRACKET(bool _createToken) {
+ int _ttype; ANTLR_USE_NAMESPACE(antlr)RefToken _token; int _begin=text.length();
+ _ttype = R_BRACKET;
+ int _saveIndex;
+
+ match(static_cast<unsigned char>(']'));
+ if ( _createToken && _token==ANTLR_USE_NAMESPACE(antlr)nullToken && _ttype!=ANTLR_USE_NAMESPACE(antlr)Token::SKIP ) {
+ _token = makeToken(_ttype);
+ _token->setText(text.substr(_begin, text.length()-_begin));
+ }
+ _returnToken = _token;
+ _saveIndex=0;
+}
+
+void GettextLexer::mT_INT(bool _createToken) {
+ int _ttype; ANTLR_USE_NAMESPACE(antlr)RefToken _token; int _begin=text.length();
+ _ttype = T_INT;
+ int _saveIndex;
+
+ {
+ int _cnt26=0;
+ for (;;) {
+ if (((LA(1) >= static_cast<unsigned char>('0') && LA(1) <= static_cast<unsigned char>('9')))) {
+ matchRange(static_cast<unsigned char>('0'),static_cast<unsigned char>('9'));
+ }
+ else {
+ if ( _cnt26>=1 ) { goto _loop26; } else {throw ANTLR_USE_NAMESPACE(antlr)NoViableAltForCharException(LA(1), getFilename(), getLine());}
+ }
+
+ _cnt26++;
+ }
+ _loop26:;
+ }
+ if ( _createToken && _token==ANTLR_USE_NAMESPACE(antlr)nullToken && _ttype!=ANTLR_USE_NAMESPACE(antlr)Token::SKIP ) {
+ _token = makeToken(_ttype);
+ _token->setText(text.substr(_begin, text.length()-_begin));
+ }
+ _returnToken = _token;
+ _saveIndex=0;
+}
+
+void GettextLexer::mT_COMMENT(bool _createToken) {
+ int _ttype; ANTLR_USE_NAMESPACE(antlr)RefToken _token; int _begin=text.length();
+ _ttype = T_COMMENT;
+ int _saveIndex;
+
+ match(static_cast<unsigned char>('#'));
+ {
+ for (;;) {
+ if ((_tokenSet_0.member(LA(1)))) {
+ matchNot(static_cast<unsigned char>('\n'));
+ }
+ else {
+ goto _loop29;
+ }
+
+ }
+ _loop29:;
+ }
+ if ( _createToken && _token==ANTLR_USE_NAMESPACE(antlr)nullToken && _ttype!=ANTLR_USE_NAMESPACE(antlr)Token::SKIP ) {
+ _token = makeToken(_ttype);
+ _token->setText(text.substr(_begin, text.length()-_begin));
+ }
+ _returnToken = _token;
+ _saveIndex=0;
+}
+
+void GettextLexer::mMSG_TAG(bool _createToken) {
+ int _ttype; ANTLR_USE_NAMESPACE(antlr)RefToken _token; int _begin=text.length();
+ _ttype = MSG_TAG;
+ int _saveIndex;
+
+ match("msg");
+ {
+ switch ( LA(1)) {
+ case static_cast<unsigned char>('i'):
+ {
+ {
+ match("id");
+ }
+ {
+ if ((LA(1)==static_cast<unsigned char>('_'))) {
+ match("_plural");
+#line 126 "gettext.g"
+ _ttype = T_MSGID_PLURAL;
+#line 292 "GettextLexer.cpp"
+ }
+ else {
+ match("");
+#line 125 "gettext.g"
+ _ttype = T_MSGID;
+#line 298 "GettextLexer.cpp"
+ }
+
+ }
+ break;
+ }
+ case static_cast<unsigned char>('s'):
+ {
+ match("str");
+#line 128 "gettext.g"
+ _ttype = T_MSGSTR;
+#line 309 "GettextLexer.cpp"
+ break;
+ }
+ default:
+ {
+ throw ANTLR_USE_NAMESPACE(antlr)NoViableAltForCharException(LA(1), getFilename(), getLine());
+ }
+ }
+ }
+ if ( _createToken && _token==ANTLR_USE_NAMESPACE(antlr)nullToken && _ttype!=ANTLR_USE_NAMESPACE(antlr)Token::SKIP ) {
+ _token = makeToken(_ttype);
+ _token->setText(text.substr(_begin, text.length()-_begin));
+ }
+ _returnToken = _token;
+ _saveIndex=0;
+}
+
+void GettextLexer::mT_STRING(bool _createToken) {
+ int _ttype; ANTLR_USE_NAMESPACE(antlr)RefToken _token; int _begin=text.length();
+ _ttype = T_STRING;
+ int _saveIndex;
+
+ {
+ int _cnt43=0;
+ for (;;) {
+ if ((LA(1)==static_cast<unsigned char>('"'))) {
+ _saveIndex=text.length();
+ match(static_cast<unsigned char>('"'));
+ text.erase(_saveIndex);
+ {
+ for (;;) {
+ if ((LA(1)==static_cast<unsigned char>('\\'))) {
+ mESC(false);
+ }
+ else if ((_tokenSet_1.member(LA(1)))) {
+ matchNot(static_cast<unsigned char>('"'));
+ }
+ else {
+ goto _loop37;
+ }
+
+ }
+ _loop37:;
+ }
+ {
+ _saveIndex=text.length();
+ match(static_cast<unsigned char>('"'));
+ text.erase(_saveIndex);
+ {
+ for (;;) {
+ switch ( LA(1)) {
+ case static_cast<unsigned char>(' '):
+ {
+ match(static_cast<unsigned char>(' '));
+ break;
+ }
+ case static_cast<unsigned char>('t'):
+ {
+ match(static_cast<unsigned char>('t'));
+ break;
+ }
+ default:
+ {
+ goto _loop40;
+ }
+ }
+ }
+ _loop40:;
+ }
+ _saveIndex=text.length();
+ match(static_cast<unsigned char>('\n'));
+ text.erase(_saveIndex);
+#line 133 "gettext.g"
+ newline();
+#line 383 "GettextLexer.cpp"
+ {
+ for (;;) {
+ switch ( LA(1)) {
+ case static_cast<unsigned char>(' '):
+ {
+ _saveIndex=text.length();
+ match(static_cast<unsigned char>(' '));
+ text.erase(_saveIndex);
+ break;
+ }
+ case static_cast<unsigned char>('\t'):
+ {
+ _saveIndex=text.length();
+ match(static_cast<unsigned char>('\t'));
+ text.erase(_saveIndex);
+ break;
+ }
+ default:
+ {
+ goto _loop42;
+ }
+ }
+ }
+ _loop42:;
+ }
+ }
+ }
+ else {
+ if ( _cnt43>=1 ) { goto _loop43; } else {throw ANTLR_USE_NAMESPACE(antlr)NoViableAltForCharException(LA(1), getFilename(), getLine());}
+ }
+
+ _cnt43++;
+ }
+ _loop43:;
+ }
+ if ( _createToken && _token==ANTLR_USE_NAMESPACE(antlr)nullToken && _ttype!=ANTLR_USE_NAMESPACE(antlr)Token::SKIP ) {
+ _token = makeToken(_ttype);
+ _token->setText(text.substr(_begin, text.length()-_begin));
+ }
+ _returnToken = _token;
+ _saveIndex=0;
+}
+
+void GettextLexer::mESC(bool _createToken) {
+ int _ttype; ANTLR_USE_NAMESPACE(antlr)RefToken _token; int _begin=text.length();
+ _ttype = ESC;
+ int _saveIndex;
+
+ match(static_cast<unsigned char>('\\'));
+ {
+ switch ( LA(1)) {
+ case static_cast<unsigned char>('n'):
+ {
+ match(static_cast<unsigned char>('n'));
+ break;
+ }
+ case static_cast<unsigned char>('r'):
+ {
+ match(static_cast<unsigned char>('r'));
+ break;
+ }
+ case static_cast<unsigned char>('t'):
+ {
+ match(static_cast<unsigned char>('t'));
+ break;
+ }
+ case static_cast<unsigned char>('b'):
+ {
+ match(static_cast<unsigned char>('b'));
+ break;
+ }
+ case static_cast<unsigned char>('f'):
+ {
+ match(static_cast<unsigned char>('f'));
+ break;
+ }
+ case static_cast<unsigned char>('"'):
+ {
+ match(static_cast<unsigned char>('"'));
+ break;
+ }
+ case static_cast<unsigned char>('\''):
+ {
+ match(static_cast<unsigned char>('\''));
+ break;
+ }
+ case static_cast<unsigned char>('\\'):
+ {
+ match(static_cast<unsigned char>('\\'));
+ break;
+ }
+ case static_cast<unsigned char>('0'):
+ case static_cast<unsigned char>('1'):
+ case static_cast<unsigned char>('2'):
+ case static_cast<unsigned char>('3'):
+ {
+ {
+ matchRange(static_cast<unsigned char>('0'),static_cast<unsigned char>('3'));
+ }
+ {
+ if (((LA(1) >= static_cast<unsigned char>('0') && LA(1) <= static_cast<unsigned char>('9')))) {
+ {
+ matchRange(static_cast<unsigned char>('0'),static_cast<unsigned char>('9'));
+ }
+ {
+ if (((LA(1) >= static_cast<unsigned char>('0') && LA(1) <= static_cast<unsigned char>('9')))) {
+ matchRange(static_cast<unsigned char>('0'),static_cast<unsigned char>('9'));
+ }
+ else if (((LA(1) >= static_cast<unsigned char>('\0') && LA(1) <= static_cast<unsigned char>('\377')))) {
+ }
+ else {
+ throw ANTLR_USE_NAMESPACE(antlr)NoViableAltForCharException(LA(1), getFilename(), getLine());
+ }
+
+ }
+ }
+ else if (((LA(1) >= static_cast<unsigned char>('\0') && LA(1) <= static_cast<unsigned char>('\377')))) {
+ }
+ else {
+ throw ANTLR_USE_NAMESPACE(antlr)NoViableAltForCharException(LA(1), getFilename(), getLine());
+ }
+
+ }
+ break;
+ }
+ case static_cast<unsigned char>('4'):
+ case static_cast<unsigned char>('5'):
+ case static_cast<unsigned char>('6'):
+ case static_cast<unsigned char>('7'):
+ {
+ {
+ matchRange(static_cast<unsigned char>('4'),static_cast<unsigned char>('7'));
+ }
+ {
+ if (((LA(1) >= static_cast<unsigned char>('0') && LA(1) <= static_cast<unsigned char>('9')))) {
+ {
+ matchRange(static_cast<unsigned char>('0'),static_cast<unsigned char>('9'));
+ }
+ }
+ else if (((LA(1) >= static_cast<unsigned char>('\0') && LA(1) <= static_cast<unsigned char>('\377')))) {
+ }
+ else {
+ throw ANTLR_USE_NAMESPACE(antlr)NoViableAltForCharException(LA(1), getFilename(), getLine());
+ }
+
+ }
+ break;
+ }
+ default:
+ {
+ throw ANTLR_USE_NAMESPACE(antlr)NoViableAltForCharException(LA(1), getFilename(), getLine());
+ }
+ }
+ }
+ if ( _createToken && _token==ANTLR_USE_NAMESPACE(antlr)nullToken && _ttype!=ANTLR_USE_NAMESPACE(antlr)Token::SKIP ) {
+ _token = makeToken(_ttype);
+ _token->setText(text.substr(_begin, text.length()-_begin));
+ }
+ _returnToken = _token;
+ _saveIndex=0;
+}
+
+
+const unsigned long GettextLexer::_tokenSet_0_data_[] = { 4294966271UL, 4294967295UL, 4294967295UL, 4294967295UL, 4294967295UL, 4294967295UL, 4294967295UL, 4294967295UL, 0UL, 0UL, 0UL, 0UL, 0UL, 0UL, 0UL, 0UL };
+const ANTLR_USE_NAMESPACE(antlr)BitSet GettextLexer::_tokenSet_0(_tokenSet_0_data_,16);
+const unsigned long GettextLexer::_tokenSet_1_data_[] = { 4294967295UL, 4294967291UL, 4026531839UL, 4294967295UL, 4294967295UL, 4294967295UL, 4294967295UL, 4294967295UL, 0UL, 0UL, 0UL, 0UL, 0UL, 0UL, 0UL, 0UL };
+const ANTLR_USE_NAMESPACE(antlr)BitSet GettextLexer::_tokenSet_1(_tokenSet_1_data_,16);
+
diff --git a/poxml/GettextLexer.hpp b/poxml/GettextLexer.hpp
new file mode 100644
index 00000000..951ad423
--- /dev/null
+++ b/poxml/GettextLexer.hpp
@@ -0,0 +1,47 @@
+#ifndef INC_GettextLexer_hpp_
+#define INC_GettextLexer_hpp_
+
+#line 2 "gettext.g"
+
+#include <string>
+using namespace std;
+#include "parser.h"
+
+#line 11 "GettextLexer.hpp"
+#include "antlr/config.hpp"
+/* $ANTLR 2.7.1: "gettext.g" -> "GettextLexer.hpp"$ */
+#include "antlr/CommonToken.hpp"
+#include "antlr/InputBuffer.hpp"
+#include "antlr/BitSet.hpp"
+#include "GettextParserTokenTypes.hpp"
+#include "antlr/CharScanner.hpp"
+class GettextLexer : public ANTLR_USE_NAMESPACE(antlr)CharScanner, public GettextParserTokenTypes
+ {
+#line 1 "gettext.g"
+#line 22 "GettextLexer.hpp"
+private:
+ void initLiterals();
+public:
+ bool getCaseSensitiveLiterals() const;
+public:
+ GettextLexer(ANTLR_USE_NAMESPACE(std)istream& in);
+ GettextLexer(ANTLR_USE_NAMESPACE(antlr)InputBuffer& ib);
+ GettextLexer(const ANTLR_USE_NAMESPACE(antlr)LexerSharedInputState& state);
+ ANTLR_USE_NAMESPACE(antlr)RefToken nextToken();
+ public: void mWS(bool _createToken);
+ public: void mL_BRACKET(bool _createToken);
+ public: void mR_BRACKET(bool _createToken);
+ public: void mT_INT(bool _createToken);
+ public: void mT_COMMENT(bool _createToken);
+ public: void mMSG_TAG(bool _createToken);
+ public: void mT_STRING(bool _createToken);
+ protected: void mESC(bool _createToken);
+private:
+
+ static const unsigned long _tokenSet_0_data_[];
+ static const ANTLR_USE_NAMESPACE(antlr)BitSet _tokenSet_0;
+ static const unsigned long _tokenSet_1_data_[];
+ static const ANTLR_USE_NAMESPACE(antlr)BitSet _tokenSet_1;
+};
+
+#endif /*INC_GettextLexer_hpp_*/
diff --git a/poxml/GettextParser.cpp b/poxml/GettextParser.cpp
new file mode 100644
index 00000000..90651eaa
--- /dev/null
+++ b/poxml/GettextParser.cpp
@@ -0,0 +1,414 @@
+/* $ANTLR 2.7.1: "gettext.g" -> "GettextParser.cpp"$ */
+#include "GettextParser.hpp"
+#include "antlr/NoViableAltException.hpp"
+#include "antlr/SemanticException.hpp"
+#line 12 "gettext.g"
+
+#include <iostream>
+#include "GettextLexer.hpp"
+#include "GettextParser.hpp"
+#include "antlr/AST.hpp"
+#include "antlr/CommonAST.hpp"
+
+/*
+int main()
+{
+ ANTLR_USING_NAMESPACE(std)
+ ANTLR_USING_NAMESPACE(antlr)
+ try {
+ GettextLexer lexer(cin);
+ GettextParser parser(lexer);
+ parser.file();
+
+ } catch(exception& e) {
+ cerr << "exception: " << e.what() << endl;
+ }
+}
+*/
+
+#line 30 "GettextParser.cpp"
+GettextParser::GettextParser(ANTLR_USE_NAMESPACE(antlr)TokenBuffer& tokenBuf, int k)
+: ANTLR_USE_NAMESPACE(antlr)LLkParser(tokenBuf,k)
+{
+ setTokenNames(_tokenNames);
+}
+
+GettextParser::GettextParser(ANTLR_USE_NAMESPACE(antlr)TokenBuffer& tokenBuf)
+: ANTLR_USE_NAMESPACE(antlr)LLkParser(tokenBuf,1)
+{
+ setTokenNames(_tokenNames);
+}
+
+GettextParser::GettextParser(ANTLR_USE_NAMESPACE(antlr)TokenStream& lexer, int k)
+: ANTLR_USE_NAMESPACE(antlr)LLkParser(lexer,k)
+{
+ setTokenNames(_tokenNames);
+}
+
+GettextParser::GettextParser(ANTLR_USE_NAMESPACE(antlr)TokenStream& lexer)
+: ANTLR_USE_NAMESPACE(antlr)LLkParser(lexer,1)
+{
+ setTokenNames(_tokenNames);
+}
+
+GettextParser::GettextParser(const ANTLR_USE_NAMESPACE(antlr)ParserSharedInputState& state)
+: ANTLR_USE_NAMESPACE(antlr)LLkParser(state,1)
+{
+ setTokenNames(_tokenNames);
+}
+
+ MsgList GettextParser::file() {
+#line 43 "gettext.g"
+ MsgList ml ;
+#line 64 "GettextParser.cpp"
+#line 43 "gettext.g"
+
+ string c, mi, ms;
+ MsgBlock mb;
+ MsgList ml2;
+
+#line 71 "GettextParser.cpp"
+
+ try { // for error handling
+ bool synPredMatched3 = false;
+ if (((LA(1)==T_MSGID||LA(1)==T_COMMENT))) {
+ int _m3 = mark();
+ synPredMatched3 = true;
+ inputState->guessing++;
+ try {
+ {
+ comment();
+ match(T_MSGID);
+ }
+ }
+ catch (ANTLR_USE_NAMESPACE(antlr)RecognitionException& pe) {
+ synPredMatched3 = false;
+ }
+ rewind(_m3);
+ inputState->guessing--;
+ }
+ if ( synPredMatched3 ) {
+ {
+ mb=file_block();
+ ml2=file();
+ if ( inputState->guessing==0 ) {
+#line 49 "gettext.g"
+ ml = ml2; ml.append(mb);
+#line 98 "GettextParser.cpp"
+ }
+ }
+ }
+ else {
+ bool synPredMatched6 = false;
+ if (((LA(1)==ANTLR_USE_NAMESPACE(antlr)Token::EOF_TYPE||LA(1)==T_COMMENT))) {
+ int _m6 = mark();
+ synPredMatched6 = true;
+ inputState->guessing++;
+ try {
+ {
+ comment();
+ match(ANTLR_USE_NAMESPACE(antlr)Token::EOF_TYPE);
+ }
+ }
+ catch (ANTLR_USE_NAMESPACE(antlr)RecognitionException& pe) {
+ synPredMatched6 = false;
+ }
+ rewind(_m6);
+ inputState->guessing--;
+ }
+ if ( synPredMatched6 ) {
+ c=comment();
+ if ( inputState->guessing==0 ) {
+#line 50 "gettext.g"
+ (void)c;
+#line 125 "GettextParser.cpp"
+ }
+ }
+ else {
+ throw ANTLR_USE_NAMESPACE(antlr)NoViableAltException(LT(1), getFilename());
+ }
+ }
+ }
+ catch (ANTLR_USE_NAMESPACE(antlr)RecognitionException& ex) {
+ if( inputState->guessing == 0 ) {
+ reportError(ex);
+ consume();
+ consumeUntil(_tokenSet_0);
+ } else {
+ throw ex;
+ }
+ }
+ return ml ;
+}
+
+string GettextParser::comment() {
+#line 76 "gettext.g"
+ string s;
+#line 148 "GettextParser.cpp"
+ ANTLR_USE_NAMESPACE(antlr)RefToken c = ANTLR_USE_NAMESPACE(antlr)nullToken;
+#line 76 "gettext.g"
+
+ string r;
+
+#line 154 "GettextParser.cpp"
+
+ try { // for error handling
+ if ((LA(1)==T_COMMENT)) {
+ {
+ c = LT(1);
+ match(T_COMMENT);
+ r=comment();
+ if ( inputState->guessing==0 ) {
+#line 80 "gettext.g"
+ s = c->getText() + r;
+#line 165 "GettextParser.cpp"
+ }
+ }
+ }
+ else if ((LA(1)==ANTLR_USE_NAMESPACE(antlr)Token::EOF_TYPE||LA(1)==T_MSGID)) {
+ }
+ else {
+ throw ANTLR_USE_NAMESPACE(antlr)NoViableAltException(LT(1), getFilename());
+ }
+
+ }
+ catch (ANTLR_USE_NAMESPACE(antlr)RecognitionException& ex) {
+ if( inputState->guessing == 0 ) {
+ reportError(ex);
+ consume();
+ consumeUntil(_tokenSet_1);
+ } else {
+ throw ex;
+ }
+ }
+ return s;
+}
+
+ MsgBlock GettextParser::file_block() {
+#line 53 "gettext.g"
+ MsgBlock mb ;
+#line 191 "GettextParser.cpp"
+#line 53 "gettext.g"
+
+ string c, mi, mip, ms;
+
+#line 196 "GettextParser.cpp"
+
+ try { // for error handling
+ c=comment();
+ mi=msgid();
+ {
+ if ((LA(1)==T_MSGSTR)) {
+ {
+ ms=msgstr();
+ if ( inputState->guessing==0 ) {
+#line 59 "gettext.g"
+
+ mb.comment = QString::fromUtf8(c.c_str());
+ mb.msgid = QString::fromUtf8(mi.c_str());
+ mb.msgstr = QString::fromUtf8(ms.c_str());
+
+#line 212 "GettextParser.cpp"
+ }
+ }
+ }
+ else if ((LA(1)==T_MSGID_PLURAL)) {
+ {
+ mip=msgid_plural();
+ ms=msgstr_plural();
+ if ( inputState->guessing==0 ) {
+#line 66 "gettext.g"
+
+ mb.comment = QString::fromUtf8(c.c_str());
+ mb.msgid = QString::fromUtf8(mi.c_str());
+ mb.msgid_plural = QString::fromUtf8(mip.c_str());
+ mb.msgstr = QString::fromUtf8(ms.c_str());
+
+#line 228 "GettextParser.cpp"
+ }
+ }
+ }
+ else {
+ throw ANTLR_USE_NAMESPACE(antlr)NoViableAltException(LT(1), getFilename());
+ }
+
+ }
+ }
+ catch (ANTLR_USE_NAMESPACE(antlr)RecognitionException& ex) {
+ if( inputState->guessing == 0 ) {
+ reportError(ex);
+ consume();
+ consumeUntil(_tokenSet_2);
+ } else {
+ throw ex;
+ }
+ }
+ return mb ;
+}
+
+string GettextParser::msgid() {
+#line 84 "gettext.g"
+ string s;
+#line 253 "GettextParser.cpp"
+ ANTLR_USE_NAMESPACE(antlr)RefToken t = ANTLR_USE_NAMESPACE(antlr)nullToken;
+
+ try { // for error handling
+ match(T_MSGID);
+ t = LT(1);
+ match(T_STRING);
+ if ( inputState->guessing==0 ) {
+#line 85 "gettext.g"
+ s = t->getText();
+#line 263 "GettextParser.cpp"
+ }
+ }
+ catch (ANTLR_USE_NAMESPACE(antlr)RecognitionException& ex) {
+ if( inputState->guessing == 0 ) {
+ reportError(ex);
+ consume();
+ consumeUntil(_tokenSet_3);
+ } else {
+ throw ex;
+ }
+ }
+ return s;
+}
+
+string GettextParser::msgstr() {
+#line 92 "gettext.g"
+ string s;
+#line 281 "GettextParser.cpp"
+ ANTLR_USE_NAMESPACE(antlr)RefToken t = ANTLR_USE_NAMESPACE(antlr)nullToken;
+
+ try { // for error handling
+ match(T_MSGSTR);
+ t = LT(1);
+ match(T_STRING);
+ if ( inputState->guessing==0 ) {
+#line 93 "gettext.g"
+ s = t->getText();
+#line 291 "GettextParser.cpp"
+ }
+ }
+ catch (ANTLR_USE_NAMESPACE(antlr)RecognitionException& ex) {
+ if( inputState->guessing == 0 ) {
+ reportError(ex);
+ consume();
+ consumeUntil(_tokenSet_2);
+ } else {
+ throw ex;
+ }
+ }
+ return s;
+}
+
+string GettextParser::msgid_plural() {
+#line 88 "gettext.g"
+ string s;
+#line 309 "GettextParser.cpp"
+ ANTLR_USE_NAMESPACE(antlr)RefToken t = ANTLR_USE_NAMESPACE(antlr)nullToken;
+
+ try { // for error handling
+ match(T_MSGID_PLURAL);
+ t = LT(1);
+ match(T_STRING);
+ if ( inputState->guessing==0 ) {
+#line 89 "gettext.g"
+ s = t->getText();
+#line 319 "GettextParser.cpp"
+ }
+ }
+ catch (ANTLR_USE_NAMESPACE(antlr)RecognitionException& ex) {
+ if( inputState->guessing == 0 ) {
+ reportError(ex);
+ consume();
+ consumeUntil(_tokenSet_4);
+ } else {
+ throw ex;
+ }
+ }
+ return s;
+}
+
+string GettextParser::msgstr_plural() {
+#line 96 "gettext.g"
+ string s;
+#line 337 "GettextParser.cpp"
+ ANTLR_USE_NAMESPACE(antlr)RefToken n = ANTLR_USE_NAMESPACE(antlr)nullToken;
+ ANTLR_USE_NAMESPACE(antlr)RefToken t = ANTLR_USE_NAMESPACE(antlr)nullToken;
+
+ try { // for error handling
+ {
+ int _cnt18=0;
+ for (;;) {
+ if ((LA(1)==T_MSGSTR)) {
+ match(T_MSGSTR);
+ match(L_BRACKET);
+ n = LT(1);
+ match(T_INT);
+ match(R_BRACKET);
+ t = LT(1);
+ match(T_STRING);
+ if ( inputState->guessing==0 ) {
+#line 98 "gettext.g"
+ s = t->getText();
+#line 356 "GettextParser.cpp"
+ }
+ }
+ else {
+ if ( _cnt18>=1 ) { goto _loop18; } else {throw ANTLR_USE_NAMESPACE(antlr)NoViableAltException(LT(1), getFilename());}
+ }
+
+ _cnt18++;
+ }
+ _loop18:;
+ }
+ }
+ catch (ANTLR_USE_NAMESPACE(antlr)RecognitionException& ex) {
+ if( inputState->guessing == 0 ) {
+ reportError(ex);
+ consume();
+ consumeUntil(_tokenSet_2);
+ } else {
+ throw ex;
+ }
+ }
+ return s;
+}
+
+const char* GettextParser::_tokenNames[] = {
+ "<0>",
+ "EOF",
+ "<2>",
+ "NULL_TREE_LOOKAHEAD",
+ "T_MSGID",
+ "T_COMMENT",
+ "T_STRING",
+ "T_MSGID_PLURAL",
+ "T_MSGSTR",
+ "L_BRACKET",
+ "T_INT",
+ "R_BRACKET",
+ "WS",
+ "MSG_TAG",
+ "ESC",
+ 0
+};
+
+const unsigned long GettextParser::_tokenSet_0_data_[] = { 2UL, 0UL, 0UL, 0UL };
+// EOF
+const ANTLR_USE_NAMESPACE(antlr)BitSet GettextParser::_tokenSet_0(_tokenSet_0_data_,4);
+const unsigned long GettextParser::_tokenSet_1_data_[] = { 18UL, 0UL, 0UL, 0UL };
+// EOF T_MSGID
+const ANTLR_USE_NAMESPACE(antlr)BitSet GettextParser::_tokenSet_1(_tokenSet_1_data_,4);
+const unsigned long GettextParser::_tokenSet_2_data_[] = { 50UL, 0UL, 0UL, 0UL };
+// EOF T_MSGID T_COMMENT
+const ANTLR_USE_NAMESPACE(antlr)BitSet GettextParser::_tokenSet_2(_tokenSet_2_data_,4);
+const unsigned long GettextParser::_tokenSet_3_data_[] = { 384UL, 0UL, 0UL, 0UL };
+// T_MSGID_PLURAL T_MSGSTR
+const ANTLR_USE_NAMESPACE(antlr)BitSet GettextParser::_tokenSet_3(_tokenSet_3_data_,4);
+const unsigned long GettextParser::_tokenSet_4_data_[] = { 256UL, 0UL, 0UL, 0UL };
+// T_MSGSTR
+const ANTLR_USE_NAMESPACE(antlr)BitSet GettextParser::_tokenSet_4(_tokenSet_4_data_,4);
+
+
diff --git a/poxml/GettextParser.hpp b/poxml/GettextParser.hpp
new file mode 100644
index 00000000..46b2b137
--- /dev/null
+++ b/poxml/GettextParser.hpp
@@ -0,0 +1,53 @@
+#ifndef INC_GettextParser_hpp_
+#define INC_GettextParser_hpp_
+
+#line 2 "gettext.g"
+
+#include <string>
+using namespace std;
+#include "parser.h"
+
+#line 11 "GettextParser.hpp"
+#include "antlr/config.hpp"
+/* $ANTLR 2.7.1: "gettext.g" -> "GettextParser.hpp"$ */
+#include "antlr/TokenStream.hpp"
+#include "antlr/TokenBuffer.hpp"
+#include "GettextParserTokenTypes.hpp"
+#include "antlr/LLkParser.hpp"
+
+class GettextParser : public ANTLR_USE_NAMESPACE(antlr)LLkParser, public GettextParserTokenTypes
+ {
+#line 1 "gettext.g"
+#line 22 "GettextParser.hpp"
+protected:
+ GettextParser(ANTLR_USE_NAMESPACE(antlr)TokenBuffer& tokenBuf, int k);
+public:
+ GettextParser(ANTLR_USE_NAMESPACE(antlr)TokenBuffer& tokenBuf);
+protected:
+ GettextParser(ANTLR_USE_NAMESPACE(antlr)TokenStream& lexer, int k);
+public:
+ GettextParser(ANTLR_USE_NAMESPACE(antlr)TokenStream& lexer);
+ GettextParser(const ANTLR_USE_NAMESPACE(antlr)ParserSharedInputState& state);
+ public: MsgList file();
+ public: string comment();
+ public: MsgBlock file_block();
+ public: string msgid();
+ public: string msgstr();
+ public: string msgid_plural();
+ public: string msgstr_plural();
+private:
+ static const char* _tokenNames[];
+
+ static const unsigned long _tokenSet_0_data_[];
+ static const ANTLR_USE_NAMESPACE(antlr)BitSet _tokenSet_0;
+ static const unsigned long _tokenSet_1_data_[];
+ static const ANTLR_USE_NAMESPACE(antlr)BitSet _tokenSet_1;
+ static const unsigned long _tokenSet_2_data_[];
+ static const ANTLR_USE_NAMESPACE(antlr)BitSet _tokenSet_2;
+ static const unsigned long _tokenSet_3_data_[];
+ static const ANTLR_USE_NAMESPACE(antlr)BitSet _tokenSet_3;
+ static const unsigned long _tokenSet_4_data_[];
+ static const ANTLR_USE_NAMESPACE(antlr)BitSet _tokenSet_4;
+};
+
+#endif /*INC_GettextParser_hpp_*/
diff --git a/poxml/GettextParserTokenTypes.hpp b/poxml/GettextParserTokenTypes.hpp
new file mode 100644
index 00000000..05fd7408
--- /dev/null
+++ b/poxml/GettextParserTokenTypes.hpp
@@ -0,0 +1,22 @@
+#ifndef INC_GettextParserTokenTypes_hpp_
+#define INC_GettextParserTokenTypes_hpp_
+
+/* $ANTLR 2.7.1: "gettext.g" -> "GettextParserTokenTypes.hpp"$ */
+struct GettextParserTokenTypes {
+ enum {
+ EOF_ = 1,
+ T_MSGID = 4,
+ T_COMMENT = 5,
+ T_STRING = 6,
+ T_MSGID_PLURAL = 7,
+ T_MSGSTR = 8,
+ L_BRACKET = 9,
+ T_INT = 10,
+ R_BRACKET = 11,
+ WS = 12,
+ MSG_TAG = 13,
+ ESC = 14,
+ NULL_TREE_LOOKAHEAD = 3
+ };
+};
+#endif /*INC_GettextParserTokenTypes_hpp_*/
diff --git a/poxml/GettextParserTokenTypes.txt b/poxml/GettextParserTokenTypes.txt
new file mode 100644
index 00000000..083e90e3
--- /dev/null
+++ b/poxml/GettextParserTokenTypes.txt
@@ -0,0 +1,13 @@
+// $ANTLR 2.7.1: gettext.g -> GettextParserTokenTypes.txt$
+GettextParser // output token vocab name
+T_MSGID=4
+T_COMMENT=5
+T_STRING=6
+T_MSGID_PLURAL=7
+T_MSGSTR=8
+L_BRACKET=9
+T_INT=10
+R_BRACKET=11
+WS=12
+MSG_TAG=13
+ESC=14
diff --git a/poxml/Makefile.am b/poxml/Makefile.am
new file mode 100644
index 00000000..bef54179
--- /dev/null
+++ b/poxml/Makefile.am
@@ -0,0 +1,48 @@
+
+bin_PROGRAMS = split2po xml2pot po2xml swappo transxx
+
+INCLUDES = -I$(srcdir)/antlr $(all_includes)
+KDE_CXXFLAGS = $(USE_EXCEPTIONS)
+
+SUBDIRS = antlr
+
+split2po_SOURCES = split.cpp parser.cpp
+split2po_LDFLAGS = $(all_libraries) $(KDE_RPATH)
+split2po_LDADD = $(LIB_QT)
+
+xml2pot_SOURCES = xml2pot.cpp parser.cpp
+xml2pot_LDFLAGS = $(all_libraries) $(KDE_RPATH)
+xml2pot_LDADD = $(LIB_QT)
+
+po2xml_SOURCES = GettextLexer.cpp GettextParser.cpp po2xml.cpp parser.cpp
+po2xml_LDFLAGS = $(all_libraries) $(KDE_RPATH)
+po2xml_LDADD = antlr/src/libantlr.la $(LIB_QT)
+
+swappo_SOURCES = GettextLexer.cpp GettextParser.cpp swappo.cpp parser.cpp
+swappo_LDFLAGS = $(all_libraries) $(KDE_RPATH)
+swappo_LDADD = antlr/src/libantlr.la $(LIB_QT)
+
+transxx_SOURCES = GettextLexer.cpp GettextParser.cpp transxx.cpp parser.cpp
+transxx_LDFLAGS = $(all_libraries) $(KDE_RPATH)
+transxx_LDADD = antlr/src/libantlr.la $(LIB_QT)
+
+parser:
+ cd $(srcdir) && java antlr.Tool gettext.g
+
+SUFFIXES = .pot .po .xml .txml
+
+lauri.pot: xml2pot lauri.xml
+ checkXML $(srcdir)/lauri.xml
+ ./xml2pot $(srcdir)/lauri.xml > lauri.pot
+ msgmerge -o lauri.pot lauri.pot lauri.pot
+
+$(srcdir)/lauri.po: lauri.pot
+ msgmerge -o $(srcdir)/lauri.po $(srcdir)/lauri.po lauri.pot
+ msgfmt --statistics $(srcdir)/lauri.po -o /dev/null
+
+lauri_de.xml: po2xml $(srcdir)/lauri.po $(srcdir)/lauri.xml
+ ./po2xml $(srcdir)/lauri.xml $(srcdir)/lauri.po | \
+ sed -e "s,<!ENTITY % English,<!ENTITY % German," > lauri_de.xml
+
+test: lauri_de.xml
+ checkXML lauri_de.xml
diff --git a/poxml/antlr/AUTHORS b/poxml/antlr/AUTHORS
new file mode 100644
index 00000000..7bdc4852
--- /dev/null
+++ b/poxml/antlr/AUTHORS
@@ -0,0 +1,2 @@
+Author:
+ Peter Wells <pete@yamuna.demon.co.uk>
diff --git a/poxml/antlr/COPYING b/poxml/antlr/COPYING
new file mode 100644
index 00000000..ce9ec595
--- /dev/null
+++ b/poxml/antlr/COPYING
@@ -0,0 +1,32 @@
+
+SOFTWARE RIGHTS
+
+ANTLR MageLang Institute, 1989-1999
+http://www.ANTLR.org
+
+We reserve no legal rights to the ANTLR--it is fully in the
+public domain. An individual or company may do whatever
+they wish with source code distributed with ANTLR or the
+code generated by ANTLR, including the incorporation of
+ANTLR, or its output, into commerical software.
+
+We encourage users to develop software with ANTLR. However,
+we do ask that credit is given to us for developing
+ANTLR. By "credit", we mean that if you use ANTLR or
+incorporate any source code into one of your programs
+(commercial product, research project, or otherwise) that
+you acknowledge this fact somewhere in the documentation,
+research report, etc... If you like ANTLR and have
+developed a nice tool with the output, please mention that
+you developed it using ANTLR. In addition, we ask that the
+headers remain intact in our source code. As long as these
+guidelines are kept, we expect to continue enhancing this
+system and expect to make other tools available as they are
+completed.
+
+The primary ANTLR guy:
+
+Terence Parr
+MageLang Institute; http://www.MageLang.com
+parrt@jguru.com
+parrt@magelang.com
diff --git a/poxml/antlr/ChangeLog b/poxml/antlr/ChangeLog
new file mode 100644
index 00000000..735046e5
--- /dev/null
+++ b/poxml/antlr/ChangeLog
@@ -0,0 +1,293 @@
+Not 100% complete. Changes from develtree are not listed yet.
+
+Change 400 on 2000/09/27 by klaren@klaren.hawking.main
+
+ Made little TCL script to pretty print a ChangeLog with C++ stuff.
+
+
+Change 399 on 2000/09/27 by klaren@klaren.hawking.main
+
+ Fixed generating too many ASTNULL checks in wrong places.
+
+
+Change 397 on 2000/09/27 by klaren@klaren.hawking.main
+
+ Some *UGLY* fixes for the last typecasting problems in Cpp codegen. It
+ now works. In 2.7.2 or later I'll fix this in a nice way.
+
+
+Change 397 on 2000/09/27 by klaren@klaren.hawking.main
+
+ Some *UGLY* fixes for the last typecasting problems in Cpp codegen. It
+ now works. In 2.7.2 or later I'll fix this in a nice way.
+
+
+Change 394 on 2000/09/26 by klaren@klaren.hawking.main
+
+ Prefixed Unicode optimization checks with a ASTNULL check.
+
+
+Change 393 on 2000/09/25 by klaren@klaren.hawking.main
+
+ Bumped up the version no from 2.7.1a4 to 2.7.1.
+
+
+Change 380 on 2000/09/24 by parrt@parrt.foggy
+
+ integrating ric's stuff into main
+
+
+Change 380 on 2000/09/24 by parrt@parrt.foggy
+
+ integrating ric's stuff into main
+
+
+Change 380 on 2000/09/24 by parrt@parrt.foggy
+
+ integrating ric's stuff into main
+
+
+Change 348 on 2000/09/07 by klaren@klaren.hawking.main
+
+ Small improvement in constructor of CommonAST.
+
+
+Change 344 on 2000/09/06 by klaren@klaren.hawking.main
+
+ Fixed missing namespace in generated TreeParsers as reported by Ross
+ Bencina.
+
+
+Change 341 on 2000/09/06 by klaren@klaren.hawking.main
+
+ Miniscule fix for Borland C++Builder 4.0/C++ 5.4. (extra parens)
+
+
+Change 317 on 2000/08/22 by klaren@klaren.hawking.main
+
+ Updated changelog for a5 (or was it 2.7.1) release..
+
+
+Change 316 on 2000/08/22 by klaren@klaren.hawking.main
+
+ All kinds of small Makefile/configure tweaks. All gcc-isms should be
+ gone now.
+
+
+Change 309 on 2000/08/15 by klaren@klaren.hawking.main
+
+ Integrate bugfixes from klaren.dev to MismatchedChar/TokenException.
+
+
+Change 297 on 2000/08/07 by klaren@klaren.kronecker.main
+
+ Fixes for namespace/namespaceAntlr/namespaceStd/genHashLines options.
+
+
+Change 296 on 2000/08/07 by klaren@klaren.kronecker.main
+
+ Virtualized all functions that someone should want to override. Probably
+ necessary for heteroAST stuff.
+
+
+Change 291 on 2000/08/07 by klaren@klaren.kronecker.main
+
+ Some tweaks to configure.in and Makefile.am's. Fix for CXXFLAGS being
+ set incorrectly when not using gcc.
+
+
+Change 290 on 2000/08/05 by klaren@klaren.kronecker.main
+
+ Updated prototype of toLower to definition in cpp file. It seems I
+ messed them up a while back.
+
+
+Change 289 on 2000/08/05 by klaren@klaren.kronecker.main
+
+ Added namespace macro to out_of_range exception.
+
+
+Change 288 on 2000/07/28 by parrt@parrt.foggy
+
+ re-added toLower return type fix
+
+
+Change 285 on 2000/07/19 by klaren@klaren.kronecker.main
+
+ Fixed thinko.
+
+
+Change 284 on 2000/07/19 by klaren@klaren.kronecker.main
+
+ Dumped output of p4 changes -l into it...
+
+
+Change 283 on 2000/07/19 by klaren@klaren.kronecker.main
+
+ Fix for bug found by Michael Ebner. Bitset size was not increased in add
+ method.
+
+
+Change 280 on 2000/07/19 by klaren@klaren.kronecker.main
+
+ Made namespaceAntlr, namespaceStd and genHashlines options file-level
+ options. Removed nameSpace member from Tool class all is now handled in
+ CppCodegenerator.java.
+
+
+Change 276 on 2000/07/18 by klaren@klaren.kronecker.main
+
+ C++ Changes for the indented traceXXXX output as invented by Monty Zukowski
+
+
+Change 275 on 2000/07/18 by klaren@klaren.kronecker.main
+
+ Added missing initializer in generated code for TreeParser
+
+
+Change 272 on 2000/07/17 by klaren@klaren.kronecker.main
+
+ Another workspace for MSVC6 has support for dll's (for version 2.6.1).
+
+
+Change 271 on 2000/07/17 by klaren@klaren.kronecker.main
+
+ New autoconf/automake stuff for the C++ support library.
+
+
+Change 270 on 2000/07/17 by klaren@klaren.kronecker.main
+
+ Fixed error within the NO_STATIC_CONSTS #ifdef
+
+
+Change 269 on 2000/07/17 by klaren@klaren.kronecker.main
+
+ Move C++ files to lib/cpp/src as first step for autoconf setup
+
+
+Change 268 on 2000/07/17 by klaren@klaren.kronecker.main
+
+ Add contrib dir and Microsoft Visual C++ 6.0 projects supplied by John
+ Millaway
+
+
+Change 260 on 2000/07/14 by klaren@klaren.kronecker.main
+
+ Fixed crashbugs/typos in constructors of Mismatched[Token|Char]Exception
+
+
+Change 258 on 2000/07/10 by parrt@parrt.foggy
+
+ fixes per klaren
+
+
+Change 258 on 2000/07/10 by parrt@parrt.foggy
+
+ fixes per klaren
+
+
+Change 248 on 2000/07/04 by parrt@parrt.foggy
+
+ Ric Klaren's changes to C++ lib
+
+
+Change 247 on 2000/07/04 by parrt@parrt.foggy
+
+ Ric Klaren's changes for namespaces
+
+
+Change 239 on 2000/06/03 by parrt@parrt.foggy
+
+ adjusted so it works; header actions got converted to Token objects from
+ Strings; lots of cast problems and then null ptr exceptions.
+
+Change 235 on 2000/05/31 by pete@pete.linux
+
+ More changes to support #line generation in C++ (from Ric Klaren)
+
+Change 220 on 2000/05/29 by parrt@parrt.foggy
+
+ changed char to int for toLower
+
+
+Change 219 on 2000/05/28 by pete@pete.linux
+
+ Mirroring Java changes
+
+
+Change 218 on 2000/05/28 by pete@pete.linux
+
+ Cleaned up the #line generator a little.
+
+
+Change 211 on 2000/05/27 by parrt@parrt.foggy
+
+ had same bug as JavaCodeGenerator related to ~(A|B)
+
+
+Change 205 on 2000/05/24 by pete@pete.linux
+
+ Add support for Metrowerks Codewarrior
+
+
+Change 203 on 2000/05/22 by pete@pete.linux
+
+ Fix for multithreading from Jan Mikkelsen
+
+
+Change 202 on 2000/05/21 by pete@pete.linux
+
+ Merged in some fixes from Ric Klaren for tracing TreeParsers, cleaner
+ namespace code, and #line generation.
+
+
+Change 202 on 2000/05/21 by pete@pete.linux
+
+ Merged in some fixes from Ric Klaren for tracing TreeParsers, cleaner
+ namespace code, and #line generation.
+
+Change 201 on 2000/05/21 by pete@pete.linux
+
+ Added destructors with empty throw specs, as suggested by Dan Field.
+
+
+Change 200 on 2000/05/21 by pete@pete.linux
+
+ Various performance improvements, mostly from Eric Dumas.
+
+
+Change 183 on 2000/02/08 by pete@pete.linux
+
+ Added support for Sun CC 5.0 (from Michael Schmitt)
+
+
+Change 182 on 2000/02/08 by pete@pete.linux
+
+ Fix a couple of minor problems with C++ generation (noted by Michael
+ Schmitt)
+
+Change 132 on 2000/01/18 by parrt@parrt.foggy
+
+ setting type to ktext for everything
+
+
+Change 132 on 2000/01/18 by parrt@parrt.foggy
+
+ setting type to ktext for everything
+
+
+Change 131 on 2000/01/18 by parrt@parrt.foggy
+
+ from dev back to main
+
+
+Change 131 on 2000/01/18 by parrt@parrt.foggy
+
+ from dev back to main
+
+
+Change 1 on 1999/12/13 by parrt@parrt.foggy
+
+ adding 2.6.0 from antlr site as initial main line
+
+
diff --git a/poxml/antlr/INSTALL b/poxml/antlr/INSTALL
new file mode 100644
index 00000000..30dd4d49
--- /dev/null
+++ b/poxml/antlr/INSTALL
@@ -0,0 +1,183 @@
+Basic Installation
+==================
+
+ These are generic installation instructions. Check out the README for
+additional info.
+
+ The `configure' shell script attempts to guess correct values for
+various system-dependent variables used during compilation. It uses
+those values to create a `Makefile' in each directory of the package.
+It may also create one or more `.h' files containing system-dependent
+definitions. Finally, it creates a shell script `config.status' that
+you can run in the future to recreate the current configuration, a file
+`config.cache' that saves the results of its tests to speed up
+reconfiguring, and a file `config.log' containing compiler output
+(useful mainly for debugging `configure').
+
+ If you need to do unusual things to compile the package, please try
+to figure out how `configure' could check whether to do them, and mail
+diffs or instructions to the address given in the `README' so they can
+be considered for the next release. If at some point `config.cache'
+contains results you don't want to keep, you may remove or edit it.
+
+ The file `configure.in' is used to create `configure' by a program
+called `autoconf'. You only need `configure.in' if you want to change
+it or regenerate `configure' using a newer version of `autoconf'.
+
+The simplest way to compile this package is:
+
+ 1. `cd' to the directory containing the package's source code and type
+ `./configure' to configure the package for your system. If you're
+ using `csh' on an old version of System V, you might need to type
+ `sh ./configure' instead to prevent `csh' from trying to execute
+ `configure' itself.
+
+ Running `configure' takes awhile. While running, it prints some
+ messages telling which features it is checking for.
+
+ 2. Type `make' to compile the package.
+
+ 3. Optionally, type `make check' to run any self-tests that come with
+ the package.
+
+ 4. Type `make install' to install the programs and any data files and
+ documentation.
+
+ 5. You can remove the program binaries and object files from the
+ source code directory by typing `make clean'. To also remove the
+ files that `configure' created (so you can compile the package for
+ a different kind of computer), type `make distclean'. There is
+ also a `make maintainer-clean' target, but that is intended mainly
+ for the package's developers. If you use it, you may have to get
+ all sorts of other programs in order to regenerate files that came
+ with the distribution.
+
+Compilers and Options
+=====================
+
+ Some systems require unusual options for compilation or linking that
+the `configure' script does not know about. You can give `configure'
+initial values for variables by setting them in the environment. Using
+a Bourne-compatible shell, you can do that on the command line like
+this:
+ CC=c89 CFLAGS=-O2 LIBS=-lposix ./configure
+
+Or on systems that have the `env' program, you can do it like this:
+ env CPPFLAGS=-I/usr/local/include LDFLAGS=-s ./configure
+
+Compiling For Multiple Architectures
+====================================
+
+ You can compile the package for more than one kind of computer at the
+same time, by placing the object files for each architecture in their
+own directory. To do this, you must use a version of `make' that
+supports the `VPATH' variable, such as GNU `make'. `cd' to the
+directory where you want the object files and executables to go and run
+the `configure' script. `configure' automatically checks for the
+source code in the directory that `configure' is in and in `..'.
+
+ If you have to use a `make' that does not supports the `VPATH'
+variable, you have to compile the package for one architecture at a time
+in the source code directory. After you have installed the package for
+one architecture, use `make distclean' before reconfiguring for another
+architecture.
+
+Installation Names
+==================
+
+ By default, `make install' will install the package's files in
+`/usr/local/bin', `/usr/local/man', etc. You can specify an
+installation prefix other than `/usr/local' by giving `configure' the
+option `--prefix=PATH'.
+
+ You can specify separate installation prefixes for
+architecture-specific files and architecture-independent files. If you
+give `configure' the option `--exec-prefix=PATH', the package will use
+PATH as the prefix for installing programs and libraries.
+Documentation and other data files will still use the regular prefix.
+
+ In addition, if you use an unusual directory layout you can give
+options like `--bindir=PATH' to specify different values for particular
+kinds of files. Run `configure --help' for a list of the directories
+you can set and what kinds of files go in them.
+
+ If the package supports it, you can cause programs to be installed
+with an extra prefix or suffix on their names by giving `configure' the
+option `--program-prefix=PREFIX' or `--program-suffix=SUFFIX'.
+
+Optional Features
+=================
+
+ Some packages pay attention to `--enable-FEATURE' options to
+`configure', where FEATURE indicates an optional part of the package.
+They may also pay attention to `--with-PACKAGE' options, where PACKAGE
+is something like `gnu-as' or `x' (for the X Window System). The
+`README' should mention any `--enable-' and `--with-' options that the
+package recognizes.
+
+ For packages that use the X Window System, `configure' can usually
+find the X include and library files automatically, but if it doesn't,
+you can use the `configure' options `--x-includes=DIR' and
+`--x-libraries=DIR' to specify their locations.
+
+Specifying the System Type
+==========================
+
+ There may be some features `configure' can not figure out
+automatically, but needs to determine by the type of host the package
+will run on. Usually `configure' can figure that out, but if it prints
+a message saying it can not guess the host type, give it the
+`--host=TYPE' option. TYPE can either be a short name for the system
+type, such as `sun4', or a canonical name with three fields:
+ CPU-COMPANY-SYSTEM
+
+See the file `config.sub' for the possible values of each field. If
+`config.sub' isn't included in this package, then this package doesn't
+need to know the host type.
+
+ If you are building compiler tools for cross-compiling, you can also
+use the `--target=TYPE' option to select the type of system they will
+produce code for and the `--build=TYPE' option to select the type of
+system on which you are compiling the package.
+
+Sharing Defaults
+================
+
+ If you want to set default values for `configure' scripts to share,
+you can create a site shell script called `config.site' that gives
+default values for variables like `CC', `cache_file', and `prefix'.
+`configure' looks for `PREFIX/share/config.site' if it exists, then
+`PREFIX/etc/config.site' if it exists. Or, you can set the
+`CONFIG_SITE' environment variable to the location of the site script.
+A warning: not all `configure' scripts look for a site script.
+
+Operation Controls
+==================
+
+ `configure' recognizes the following options to control how it
+operates.
+
+`--cache-file=FILE'
+ Use and save the results of the tests in FILE instead of
+ `./config.cache'. Set FILE to `/dev/null' to disable caching, for
+ debugging `configure'.
+
+`--help'
+ Print a summary of the options to `configure', and exit.
+
+`--quiet'
+`--silent'
+`-q'
+ Do not print messages saying which checks are being made. To
+ suppress all normal output, redirect it to `/dev/null' (any error
+ messages will still be shown).
+
+`--srcdir=DIR'
+ Look for the package's source code in directory DIR. Usually
+ `configure' can determine that directory automatically.
+
+`--version'
+ Print the version of Autoconf used to generate the `configure'
+ script, and exit.
+
+`configure' also accepts some other, not widely useful, options.
diff --git a/poxml/antlr/Makefile.am b/poxml/antlr/Makefile.am
new file mode 100644
index 00000000..be459d64
--- /dev/null
+++ b/poxml/antlr/Makefile.am
@@ -0,0 +1,2 @@
+SUBDIRS = src antlr
+
diff --git a/poxml/antlr/README b/poxml/antlr/README
new file mode 100644
index 00000000..6ca0913b
--- /dev/null
+++ b/poxml/antlr/README
@@ -0,0 +1,72 @@
+C++ support libraries
+
+Original GNU autconf stuff contributed by Braden N. McDaniel. Slightly
+hacked up by me (Ric Klaren (klaren@cs.utwente.nl)) for who it's the first
+autoconf/automake/aclocal stuff ever, so suggestions additions welcome.
+
+HOW TO INSTALL
+
+In theory do:
+
+./configure --prefix=<basedirectory where you want it installed>
+make
+make install
+
+Now libantlr.a should reside under <basedir>/lib/libantlr.a and the
+includes should be at <basedir>/include/antlr.
+
+NOTE: this only installs the C++ library and header files.
+
+In the contrib directory a dsp/dsw project for Microsoft Visual C++ can be
+found.
+
+In general this library needs runtime typing information (RTTI) make sure
+you enable this in whatever compiler you are using.
+
+SUPPORTED COMPILERS
+
+Pasted from the FAQ entry on: http://www.jguru.com/jguru/faq/view.jsp?EID=121
+
+Compiler OS Version
+------------------ --------------------- ----------
+Sun Workshop 4.2 Solaris 2.6, 7 2.7.1a2
+Sun Workshop 5.0 Solaris 2.7 2.7.1a2
+Sun Workshop 6.0 Solaris 2.7 2.7.1a2
+egcs-1.1.2 Solaris 2.6,7 2.7.1a2
+egcs-1.1.2 Linux 2.2, Solaris 2.6 2.7.1a2
+gcc-2.95.2 Linux 2.2, Solaris 2.6,7 2.7.1a2
+gcc-2.96 (20000527) Solaris 2.6 2.7.1a2
+aCC A.01.21 HP-UX 10.20 2.7.0 no!
+Visual C++ 6.0 PC 2.7.1a2 (warnings)
+Intel C++ 4.0 NT 4.0 2.7.0
+Borland 5.0 NT 4.0 2.7.0
+
+IT DOESN'T WORK!?
+
+Check out the faq: http://www.jguru.com/jguru/faq/view.jsp?EID=120
+
+The text of that entry (by Peter Wells):
+
+The ANTLR code uses some relatively new features of C++ which not all
+compilers support yet (such as namespaces, and new style standard headers).
+
+There is work currently in progress to provide a compatibility mode for
+ANTLR, to enable older compilers to handle this.
+
+At the moment, you may be able to work around the problem with a few nasty
+tricks:
+
+Try creating some header files like 'iostream' just containing:
+
+#include <iostream.h>
+
+and compile with an option to define away the word 'std', such as
+
+CC .... -Dstd= ....
+
+Also in the antlr subdirectory there's a file config.hpp. Tweak this one to
+enable/disable the different bells and whistles used in the rest of the code.
+Don't forget to submit those changes back to us (along with compiler info)
+so we can incorporate them in our next release!
+
+Thanks!
diff --git a/poxml/antlr/TODO b/poxml/antlr/TODO
new file mode 100644
index 00000000..51d104c3
--- /dev/null
+++ b/poxml/antlr/TODO
@@ -0,0 +1,34 @@
+* Improve configure scripts => KICK OUT automake!
+
+* Add allocators to the objects
+
+* Look more at exception handling
+
+* TreeParser.cpp around line 76 the MismatchedTokenException here does not
+ use ttype to improve it's errormessage. Would require changing a bit in
+ MismatchedTokenException.cpp
+
+* On Thu, Sep 21, 2000 at 12:33:48AM -0700, John Lambert <JohnL@jBASE.com> wrote:
+ > 1) The literal EOF is not defined and causes the define of EOF_CHAR in
+ > CharScanner.hpp to fail.
+
+ ANTLR with STL Port. Changing the EOF define to char_traits<char>::eof()
+ breaks things for gcc-2.95.2. Fix this in next release portably.
+ http://www.egroups.com/message/antlr-interest/2520
+
+* John Millaway requested some mechanism to add code to the constructor
+ of the parser/lexer/treewalker. This can be usefull.
+ http://www.egroups.com/message/antlr-interest/2501
+
+* Fix heterogeneous AST stuff. It boils down to adding a method to AST
+ types that knows how to duplicate the sucker. Atm duptree cannot work
+ because of this. Knowing one factory is not enough. Also look at having
+ to set the astfactory by hand (this is not 100% necessary).
+ http://www.egroups.com/message/antlr-interest/2496
+
+* Look at messageLog stuff Ross Bencina proposed. Looks good at first glance.
+ http://www.egroups.com/message/antlr-interest/2555
+
+* Add RW_STL & CC 4.2 patch from Ulrich Teichert:
+ See my mailbox.. and these comments from Ross Bencina:
+ http://www.egroups.com/message/antlr-interest/2494
diff --git a/poxml/antlr/antlr/ANTLRException.hpp b/poxml/antlr/antlr/ANTLRException.hpp
new file mode 100644
index 00000000..efbe0d7f
--- /dev/null
+++ b/poxml/antlr/antlr/ANTLRException.hpp
@@ -0,0 +1,60 @@
+#ifndef INC_ANTLRException_hpp__
+#define INC_ANTLRException_hpp__
+
+/**
+ * <b>SOFTWARE RIGHTS</b>
+ * <p>
+ * ANTLR 2.6.0 MageLang Insitute, 1999
+ * <p>
+ * We reserve no legal rights to the ANTLR--it is fully in the
+ * public domain. An individual or company may do whatever
+ * they wish with source code distributed with ANTLR or the
+ * code generated by ANTLR, including the incorporation of
+ * ANTLR, or its output, into commerical software.
+ * <p>
+ * We encourage users to develop software with ANTLR. However,
+ * we do ask that credit is given to us for developing
+ * ANTLR. By "credit", we mean that if you use ANTLR or
+ * incorporate any source code into one of your programs
+ * (commercial product, research project, or otherwise) that
+ * you acknowledge this fact somewhere in the documentation,
+ * research report, etc... If you like ANTLR and have
+ * developed a nice tool with the output, please mention that
+ * you developed it using ANTLR. In addition, we ask that the
+ * headers remain intact in our source code. As long as these
+ * guidelines are kept, we expect to continue enhancing this
+ * system and expect to make other tools available as they are
+ * completed.
+ * <p>
+ * The ANTLR gang:
+ * @version ANTLR 2.6.0 MageLang Insitute, 1999
+ * @author Terence Parr, <a href=http://www.MageLang.com>MageLang Institute</a>
+ * @author <br>John Lilley, <a href=http://www.Empathy.com>Empathy Software</a>
+ * @author <br><a href="mailto:pete@yamuna.demon.co.uk">Pete Wells</a>
+ */
+
+#include "antlr/config.hpp"
+#include <exception>
+#include <string>
+
+ANTLR_BEGIN_NAMESPACE(antlr)
+
+class ANTLRException : public ANTLR_USE_NAMESPACE(std)exception {
+private:
+ ANTLR_USE_NAMESPACE(std)string text;
+
+public:
+ ANTLRException();
+ ANTLRException(const ANTLR_USE_NAMESPACE(std)string& s);
+ virtual ~ANTLRException() throw();
+
+ virtual ANTLR_USE_NAMESPACE(std)string toString() const;
+
+ virtual ANTLR_USE_NAMESPACE(std)string getMessage() const;
+
+ virtual const char* what() const throw();
+};
+
+ANTLR_END_NAMESPACE
+
+#endif //INC_ANTLRException_hpp__
diff --git a/poxml/antlr/antlr/AST.hpp b/poxml/antlr/antlr/AST.hpp
new file mode 100644
index 00000000..a36ffd15
--- /dev/null
+++ b/poxml/antlr/antlr/AST.hpp
@@ -0,0 +1,108 @@
+#ifndef INC_AST_hpp__
+#define INC_AST_hpp__
+
+/**
+ * <b>SOFTWARE RIGHTS</b>
+ * <p>
+ * ANTLR 2.6.0 MageLang Insitute, 1999
+ * <p>
+ * We reserve no legal rights to the ANTLR--it is fully in the
+ * public domain. An individual or company may do whatever
+ * they wish with source code distributed with ANTLR or the
+ * code generated by ANTLR, including the incorporation of
+ * ANTLR, or its output, into commerical software.
+ * <p>
+ * We encourage users to develop software with ANTLR. However,
+ * we do ask that credit is given to us for developing
+ * ANTLR. By "credit", we mean that if you use ANTLR or
+ * incorporate any source code into one of your programs
+ * (commercial product, research project, or otherwise) that
+ * you acknowledge this fact somewhere in the documentation,
+ * research report, etc... If you like ANTLR and have
+ * developed a nice tool with the output, please mention that
+ * you developed it using ANTLR. In addition, we ask that the
+ * headers remain intact in our source code. As long as these
+ * guidelines are kept, we expect to continue enhancing this
+ * system and expect to make other tools available as they are
+ * completed.
+ * <p>
+ * The ANTLR gang:
+ * @version ANTLR 2.6.0 MageLang Insitute, 1999
+ * @author Terence Parr, <a href=http://www.MageLang.com>MageLang Institute</a>
+ * @author <br>John Lilley, <a href=http://www.Empathy.com>Empathy Software</a>
+ * @author <br><a href="mailto:pete@yamuna.demon.co.uk">Pete Wells</a>
+ */
+
+#include "antlr/config.hpp"
+#include "antlr/ASTRefCount.hpp"
+#include "antlr/Token.hpp"
+#include <vector>
+#include <string>
+
+ANTLR_BEGIN_NAMESPACE(antlr)
+
+struct ASTRef;
+
+class AST {
+public:
+ AST() : ref(0) {}
+ virtual ~AST() {}
+
+ virtual void addChild(RefAST c)=0;
+
+ virtual bool equals(RefAST t) const=0;
+ virtual bool equalsList(RefAST t) const=0;
+ virtual bool equalsListPartial(RefAST t) const=0;
+ virtual bool equalsTree(RefAST t) const=0;
+ virtual bool equalsTreePartial(RefAST t) const=0;
+
+ virtual ANTLR_USE_NAMESPACE(std)vector<RefAST> findAll(RefAST t)=0;
+ virtual ANTLR_USE_NAMESPACE(std)vector<RefAST> findAllPartial(RefAST t)=0;
+
+ /** Get the first child of this node; null if no children */
+ virtual RefAST getFirstChild() const=0;
+ /** Get the next sibling in line after this one */
+ virtual RefAST getNextSibling() const=0;
+
+ /** Get the token text for this node */
+ virtual ANTLR_USE_NAMESPACE(std)string getText() const=0;
+ /** Get the token type for this node */
+ virtual int getType() const=0;
+
+ virtual void initialize(int t,const ANTLR_USE_NAMESPACE(std)string& txt)=0;
+ virtual void initialize(RefAST t)=0;
+ virtual void initialize(RefToken t)=0;
+
+ /** Set the first child of a node. */
+ virtual void setFirstChild(RefAST c)=0;
+ /** Set the next sibling after this one. */
+ virtual void setNextSibling(RefAST n)=0;
+
+ /** Set the token text for this node */
+ virtual void setText(const ANTLR_USE_NAMESPACE(std)string& txt)=0;
+ /** Set the token type for this node */
+ virtual void setType(int type)=0;
+
+ virtual ANTLR_USE_NAMESPACE(std)string toString() const=0;
+ virtual ANTLR_USE_NAMESPACE(std)string toStringList() const=0;
+ virtual ANTLR_USE_NAMESPACE(std)string toStringTree() const=0;
+private:
+ friend struct ASTRef;
+ ASTRef* ref;
+
+ AST(const AST& other);
+ AST(RefAST other);
+ AST& operator=(const AST& other);
+ AST& operator=(RefAST other);
+};
+
+extern RefAST nullAST;
+extern AST* const nullASTptr;
+
+#ifdef NEEDS_OPERATOR_LESS_THAN
+inline operator<(RefAST l,RefAST r); // {return true;}
+#endif
+
+ANTLR_END_NAMESPACE
+
+#endif //INC_AST_hpp__
diff --git a/poxml/antlr/antlr/ASTArray.hpp b/poxml/antlr/antlr/ASTArray.hpp
new file mode 100644
index 00000000..5203acf0
--- /dev/null
+++ b/poxml/antlr/antlr/ASTArray.hpp
@@ -0,0 +1,63 @@
+#ifndef INC_ASTArray_hpp__
+#define INC_ASTArray_hpp__
+
+/**
+ * <b>SOFTWARE RIGHTS</b>
+ * <p>
+ * ANTLR 2.6.0 MageLang Insitute, 1999
+ * <p>
+ * We reserve no legal rights to the ANTLR--it is fully in the
+ * public domain. An individual or company may do whatever
+ * they wish with source code distributed with ANTLR or the
+ * code generated by ANTLR, including the incorporation of
+ * ANTLR, or its output, into commerical software.
+ * <p>
+ * We encourage users to develop software with ANTLR. However,
+ * we do ask that credit is given to us for developing
+ * ANTLR. By "credit", we mean that if you use ANTLR or
+ * incorporate any source code into one of your programs
+ * (commercial product, research project, or otherwise) that
+ * you acknowledge this fact somewhere in the documentation,
+ * research report, etc... If you like ANTLR and have
+ * developed a nice tool with the output, please mention that
+ * you developed it using ANTLR. In addition, we ask that the
+ * headers remain intact in our source code. As long as these
+ * guidelines are kept, we expect to continue enhancing this
+ * system and expect to make other tools available as they are
+ * completed.
+ * <p>
+ * The ANTLR gang:
+ * @version ANTLR 2.6.0 MageLang Insitute, 1999
+ * @author Terence Parr, <a href=http://www.MageLang.com>MageLang Institute</a>
+ * @author <br>John Lilley, <a href=http://www.Empathy.com>Empathy Software</a>
+ * @author <br><a href="mailto:pete@yamuna.demon.co.uk">Pete Wells</a>
+ */
+
+#include "antlr/config.hpp"
+#include "antlr/AST.hpp"
+
+ANTLR_BEGIN_NAMESPACE(antlr)
+
+/** ASTArray is a class that allows ANTLR to
+ * generate code that can create and initialize an array
+ * in one expression, like:
+ * (new ASTArray(3))->add(x)->add(y)->add(z)
+ */
+class ASTArray {
+public:
+ int size; // = 0;
+ ANTLR_USE_NAMESPACE(std)vector<RefAST> array;
+
+ ASTArray(int capacity)
+ : size(0)
+ , array(capacity)
+ {}
+ ASTArray* add(RefAST node) {
+ array[size++] = node;
+ return this;
+ }
+};
+
+ANTLR_END_NAMESPACE
+
+#endif //INC_ASTArray_hpp__
diff --git a/poxml/antlr/antlr/ASTFactory.hpp b/poxml/antlr/antlr/ASTFactory.hpp
new file mode 100644
index 00000000..584cee6d
--- /dev/null
+++ b/poxml/antlr/antlr/ASTFactory.hpp
@@ -0,0 +1,113 @@
+#ifndef INC_ASTFactory_hpp__
+#define INC_ASTFactory_hpp__
+
+/**
+ * <b>SOFTWARE RIGHTS</b>
+ * <p>
+ * ANTLR 2.6.0 MageLang Insitute, 1999
+ * <p>
+ * We reserve no legal rights to the ANTLR--it is fully in the
+ * public domain. An individual or company may do whatever
+ * they wish with source code distributed with ANTLR or the
+ * code generated by ANTLR, including the incorporation of
+ * ANTLR, or its output, into commerical software.
+ * <p>
+ * We encourage users to develop software with ANTLR. However,
+ * we do ask that credit is given to us for developing
+ * ANTLR. By "credit", we mean that if you use ANTLR or
+ * incorporate any source code into one of your programs
+ * (commercial product, research project, or otherwise) that
+ * you acknowledge this fact somewhere in the documentation,
+ * research report, etc... If you like ANTLR and have
+ * developed a nice tool with the output, please mention that
+ * you developed it using ANTLR. In addition, we ask that the
+ * headers remain intact in our source code. As long as these
+ * guidelines are kept, we expect to continue enhancing this
+ * system and expect to make other tools available as they are
+ * completed.
+ * <p>
+ * The ANTLR gang:
+ * @version ANTLR 2.6.0 MageLang Insitute, 1999
+ * @author Terence Parr, <a href=http://www.MageLang.com>MageLang Institute</a>
+ * @author <br>John Lilley, <a href=http://www.Empathy.com>Empathy Software</a>
+ * @author <br><a href="mailto:pete@yamuna.demon.co.uk">Pete Wells</a>
+ */
+
+#include "antlr/config.hpp"
+#include "antlr/AST.hpp"
+#include "antlr/ASTArray.hpp"
+#include "antlr/ASTPair.hpp"
+
+ANTLR_BEGIN_NAMESPACE(antlr)
+
+/** AST Support code shared by TreeParser and Parser.
+ * We use delegation to share code (and have only one
+ * bit of code to maintain) rather than subclassing
+ * or superclassing (forces AST support code to be
+ * loaded even when you don't want to do AST stuff).
+ *
+ * Typically, setASTNodeType is used to specify the
+ * type of node to create, but you can override
+ * create to make heterogeneous nodes etc...
+ */
+class ASTFactory {
+public:
+ typedef RefAST (*factory_type)();
+protected:
+ /** Name of AST class to create during tree construction.
+ * Null implies that the create method should create
+ * a default AST type such as CommonAST.
+ */
+ factory_type nodeFactory;
+
+public:
+ ASTFactory();
+ /** Add a child to the current AST */
+ void addASTChild(ASTPair& currentAST, RefAST child);
+ /** Create a new empty AST node; if the user did not specify
+ * an AST node type, then create a default one: CommonAST.
+ */
+ virtual RefAST create();
+ RefAST create(int type);
+ RefAST create(int type, const ANTLR_USE_NAMESPACE(std)string& txt);
+ /** Create a new empty AST node; if the user did not specify
+ * an AST node type, then create a default one: CommonAST.
+ */
+ RefAST create(RefAST tr);
+ RefAST create(RefToken tok);
+ /** Copy a single node. clone() is not used because
+ * we want to return an AST not a plain object...a type
+ * safety issue. Further, we want to have all AST node
+ * creation go through the factory so creation can be
+ * tracked. Returns null if t is null.
+ */
+ RefAST dup(RefAST t);
+ /** Duplicate tree including siblings of root. */
+ RefAST dupList(RefAST t);
+ /**Duplicate a tree, assuming this is a root node of a tree--
+ * duplicate that node and what's below; ignore siblings of root node.
+ */
+ RefAST dupTree(RefAST t);
+ /** Make a tree from a list of nodes. The first element in the
+ * array is the root. If the root is null, then the tree is
+ * a simple list not a tree. Handles null children nodes correctly.
+ * For example, build(a, b, null, c) yields tree (a b c). build(null,a,b)
+ * yields tree (nil a b).
+ */
+ RefAST make(ANTLR_USE_NAMESPACE(std)vector<RefAST> nodes);
+ /** Make a tree from a list of nodes, where the nodes are contained
+ * in an ASTArray object
+ */
+ RefAST make(ASTArray* nodes);
+ /** Make an AST the root of current AST */
+ void makeASTRoot(ASTPair& currentAST, RefAST root);
+ void setASTNodeFactory(factory_type factory);
+ virtual ~ASTFactory() {}
+private:
+ ASTFactory( const ASTFactory& );
+ ASTFactory& operator=( const ASTFactory& );
+};
+
+ANTLR_END_NAMESPACE
+
+#endif //INC_ASTFactory_hpp__
diff --git a/poxml/antlr/antlr/ASTNULLType.hpp b/poxml/antlr/antlr/ASTNULLType.hpp
new file mode 100644
index 00000000..8f3faa46
--- /dev/null
+++ b/poxml/antlr/antlr/ASTNULLType.hpp
@@ -0,0 +1,72 @@
+#ifndef INC_ASTNULLType_hpp__
+#define INC_ASTNULLType_hpp__
+
+/**
+ * <b>SOFTWARE RIGHTS</b>
+ * <p>
+ * ANTLR 2.6.0 MageLang Insitute, 1999
+ * <p>
+ * We reserve no legal rights to the ANTLR--it is fully in the
+ * public domain. An individual or company may do whatever
+ * they wish with source code distributed with ANTLR or the
+ * code generated by ANTLR, including the incorporation of
+ * ANTLR, or its output, into commerical software.
+ * <p>
+ * We encourage users to develop software with ANTLR. However,
+ * we do ask that credit is given to us for developing
+ * ANTLR. By "credit", we mean that if you use ANTLR or
+ * incorporate any source code into one of your programs
+ * (commercial product, research project, or otherwise) that
+ * you acknowledge this fact somewhere in the documentation,
+ * research report, etc... If you like ANTLR and have
+ * developed a nice tool with the output, please mention that
+ * you developed it using ANTLR. In addition, we ask that the
+ * headers remain intact in our source code. As long as these
+ * guidelines are kept, we expect to continue enhancing this
+ * system and expect to make other tools available as they are
+ * completed.
+ * <p>
+ * The ANTLR gang:
+ * @version ANTLR 2.6.0 MageLang Insitute, 1999
+ * @author Terence Parr, <a href=http://www.MageLang.com>MageLang Institute</a>
+ * @author <br>John Lilley, <a href=http://www.Empathy.com>Empathy Software</a>
+ * @author <br><a href="mailto:pete@yamuna.demon.co.uk">Pete Wells</a>
+ */
+
+#include "antlr/config.hpp"
+#include "antlr/AST.hpp"
+
+ANTLR_BEGIN_NAMESPACE(antlr)
+
+/** There is only one instance of this class **/
+class ASTNULLType : public AST {
+public:
+ void addChild(RefAST c) {;}
+ bool equals(RefAST t) const {return false;}
+ bool equalsList(RefAST t) const {return false;}
+ bool equalsListPartial(RefAST t) const {return false;}
+ bool equalsTree(RefAST t) const {return false;}
+ bool equalsTreePartial(RefAST t) const {return false;}
+ ANTLR_USE_NAMESPACE(std)vector<RefAST> findAll(RefAST tree)
+ {return ANTLR_USE_NAMESPACE(std)vector<RefAST>();}
+ ANTLR_USE_NAMESPACE(std)vector<RefAST> findAllPartial(RefAST subtree)
+ {return ANTLR_USE_NAMESPACE(std)vector<RefAST>();}
+ RefAST getFirstChild() const { return this; }
+ RefAST getNextSibling() const { return this; }
+ ANTLR_USE_NAMESPACE(std)string getText() const { return "<ASTNULL>"; }
+ int getType() const { return Token::NULL_TREE_LOOKAHEAD; }
+ void initialize(int t, const ANTLR_USE_NAMESPACE(std)string& txt) {}
+ void initialize(RefAST t) {}
+ void initialize(RefToken t) {}
+ void setFirstChild(RefAST c) {;}
+ void setNextSibling(RefAST n) {;}
+ void setText(const ANTLR_USE_NAMESPACE(std)string& text) {;}
+ void setType(int ttype) {;}
+ ANTLR_USE_NAMESPACE(std)string toString() const {return getText();}
+ ANTLR_USE_NAMESPACE(std)string toStringList() const {return getText();}
+ ANTLR_USE_NAMESPACE(std)string toStringTree() const {return getText();}
+};
+
+ANTLR_END_NAMESPACE
+
+#endif //INC_ASTNULLType_hpp__
diff --git a/poxml/antlr/antlr/ASTPair.hpp b/poxml/antlr/antlr/ASTPair.hpp
new file mode 100644
index 00000000..eb7629ba
--- /dev/null
+++ b/poxml/antlr/antlr/ASTPair.hpp
@@ -0,0 +1,77 @@
+#ifndef INC_ASTPair_hpp__
+#define INC_ASTPair_hpp__
+
+/**
+ * <b>SOFTWARE RIGHTS</b>
+ * <p>
+ * ANTLR 2.6.0 MageLang Insitute, 1999
+ * <p>
+ * We reserve no legal rights to the ANTLR--it is fully in the
+ * public domain. An individual or company may do whatever
+ * they wish with source code distributed with ANTLR or the
+ * code generated by ANTLR, including the incorporation of
+ * ANTLR, or its output, into commerical software.
+ * <p>
+ * We encourage users to develop software with ANTLR. However,
+ * we do ask that credit is given to us for developing
+ * ANTLR. By "credit", we mean that if you use ANTLR or
+ * incorporate any source code into one of your programs
+ * (commercial product, research project, or otherwise) that
+ * you acknowledge this fact somewhere in the documentation,
+ * research report, etc... If you like ANTLR and have
+ * developed a nice tool with the output, please mention that
+ * you developed it using ANTLR. In addition, we ask that the
+ * headers remain intact in our source code. As long as these
+ * guidelines are kept, we expect to continue enhancing this
+ * system and expect to make other tools available as they are
+ * completed.
+ * <p>
+ * The ANTLR gang:
+ * @version ANTLR 2.6.0 MageLang Insitute, 1999
+ * @author Terence Parr, <a href=http://www.MageLang.com>MageLang Institute</a>
+ * @author <br>John Lilley, <a href=http://www.Empathy.com>Empathy Software</a>
+ * @author <br><a href="mailto:pete@yamuna.demon.co.uk">Pete Wells</a>
+ */
+#include "antlr/config.hpp"
+#include "antlr/AST.hpp"
+
+ANTLR_BEGIN_NAMESPACE(antlr)
+
+/** ASTPair: utility class used for manipulating a pair of ASTs
+ * representing the current AST root and current AST sibling.
+ * This exists to compensate for the lack of pointers or 'var'
+ * arguments in Java.
+ *
+ * OK, so we can do those things in C++, but it seems easier
+ * to stick with the Java way for now.
+ */
+class ASTPair {
+public:
+ RefAST root; // current root of tree
+ RefAST child; // current child to which siblings are added
+
+ /** Make sure that child is the last sibling */
+ void advanceChildToEnd() {
+ if (child) {
+ while (child->getNextSibling()) {
+ child = child->getNextSibling();
+ }
+ }
+ }
+// /** Copy an ASTPair. Don't call it clone() because we want type-safety */
+// ASTPair copy() {
+// ASTPair tmp = new ASTPair();
+// tmp.root = root;
+// tmp.child = child;
+// return tmp;
+// }
+ ANTLR_USE_NAMESPACE(std)string toString() const {
+ ANTLR_USE_NAMESPACE(std)string r = !root ? ANTLR_USE_NAMESPACE(std)string("null") : root->getText();
+ ANTLR_USE_NAMESPACE(std)string c = !child ? ANTLR_USE_NAMESPACE(std)string("null") : child->getText();
+ return "["+r+","+c+"]";
+ }
+};
+
+ANTLR_END_NAMESPACE
+
+#endif //INC_ASTPair_hpp__
diff --git a/poxml/antlr/antlr/ASTRefCount.hpp b/poxml/antlr/antlr/ASTRefCount.hpp
new file mode 100644
index 00000000..cb44128b
--- /dev/null
+++ b/poxml/antlr/antlr/ASTRefCount.hpp
@@ -0,0 +1,104 @@
+#ifndef INC_ASTRefCount_hpp__
+# define INC_ASTRefCount_hpp__
+
+/**
+ * <b>SOFTWARE RIGHTS</b>
+ * <p>
+ * ANTLR 2.6.0 MageLang Insitute, 1999
+ * <p>
+ * We reserve no legal rights to the ANTLR--it is fully in the
+ * public domain. An individual or company may do whatever
+ * they wish with source code distributed with ANTLR or the
+ * code generated by ANTLR, including the incorporation of
+ * ANTLR, or its output, into commerical software.
+ * <p>
+ * We encourage users to develop software with ANTLR. However,
+ * we do ask that credit is given to us for developing
+ * ANTLR. By "credit", we mean that if you use ANTLR or
+ * incorporate any source code into one of your programs
+ * (commercial product, research project, or otherwise) that
+ * you acknowledge this fact somewhere in the documentation,
+ * research report, etc... If you like ANTLR and have
+ * developed a nice tool with the output, please mention that
+ * you developed it using ANTLR. In addition, we ask that the
+ * headers remain intact in our source code. As long as these
+ * guidelines are kept, we expect to continue enhancing this
+ * system and expect to make other tools available as they are
+ * completed.
+ * <p>
+ * The ANTLR gang:
+ * @version ANTLR 2.6.0 MageLang Insitute, 1999
+ * @author Terence Parr, <a href=http://www.MageLang.com>MageLang Institute</a>
+ * @author <br>John Lilley, <a href=http://www.Empathy.com>Empathy Software</a>
+ * @author <br><a href="mailto:pete@yamuna.demon.co.uk">Pete Wells</a>
+ */
+
+# include "antlr/config.hpp"
+
+ANTLR_BEGIN_NAMESPACE(antlr)
+
+ class AST;
+
+struct ASTRef
+{
+ AST* const ptr;
+ unsigned int count;
+
+ ASTRef(AST* p);
+ ~ASTRef();
+ ASTRef* increment();
+ bool decrement();
+
+ static ASTRef* getRef(const AST* p);
+private:
+ ASTRef( const ASTRef& );
+ ASTRef& operator=( const ASTRef& );
+};
+
+template<class T>
+ class ASTRefCount
+{
+private:
+ ASTRef* ref;
+
+public:
+ ASTRefCount(const AST* p=0)
+ : ref(p ? ASTRef::getRef(p) : 0)
+ {
+ }
+ ASTRefCount(const ASTRefCount<T>& other)
+ : ref(other.ref ? other.ref->increment() : 0)
+ {
+ }
+ ~ASTRefCount()
+ {
+ if (ref && ref->decrement()) delete ref;
+ }
+ ASTRefCount<T>& operator=(AST* other)
+ {
+ ASTRef* tmp=ASTRef::getRef(other);
+ if (ref && ref->decrement()) delete ref;
+ ref=tmp;
+ return *this;
+ }
+ ASTRefCount<T>& operator=(const ASTRefCount<T>& other)
+ {
+ ASTRef* tmp=other.ref ? other.ref->increment() : 0;
+ if (ref && ref->decrement()) delete ref;
+ ref=tmp;
+ return *this;
+ }
+
+ operator T* () const
+ { return ref ? static_cast<T*>(ref->ptr) : 0; }
+ T* operator->() const
+ { return ref ? static_cast<T*>(ref->ptr) : 0; }
+ T* get() const
+ { return ref ? static_cast<T*>(ref->ptr) : 0; }
+};
+
+typedef ASTRefCount<AST> RefAST;
+
+ANTLR_END_NAMESPACE
+
+#endif //INC_ASTRefCount_hpp__
diff --git a/poxml/antlr/antlr/BaseAST.hpp b/poxml/antlr/antlr/BaseAST.hpp
new file mode 100644
index 00000000..7b93c1ef
--- /dev/null
+++ b/poxml/antlr/antlr/BaseAST.hpp
@@ -0,0 +1,106 @@
+#ifndef INC_BaseAST_hpp__
+#define INC_BaseAST_hpp__
+
+/**
+ * <b>SOFTWARE RIGHTS</b>
+ * <p>
+ * ANTLR 2.6.0 MageLang Insitute, 1999
+ * <p>
+ * We reserve no legal rights to the ANTLR--it is fully in the
+ * public domain. An individual or company may do whatever
+ * they wish with source code distributed with ANTLR or the
+ * code generated by ANTLR, including the incorporation of
+ * ANTLR, or its output, into commerical software.
+ * <p>
+ * We encourage users to develop software with ANTLR. However,
+ * we do ask that credit is given to us for developing
+ * ANTLR. By "credit", we mean that if you use ANTLR or
+ * incorporate any source code into one of your programs
+ * (commercial product, research project, or otherwise) that
+ * you acknowledge this fact somewhere in the documentation,
+ * research report, etc... If you like ANTLR and have
+ * developed a nice tool with the output, please mention that
+ * you developed it using ANTLR. In addition, we ask that the
+ * headers remain intact in our source code. As long as these
+ * guidelines are kept, we expect to continue enhancing this
+ * system and expect to make other tools available as they are
+ * completed.
+ * <p>
+ * The ANTLR gang:
+ * @version ANTLR 2.6.0 MageLang Insitute, 1999
+ * @author Terence Parr, <a href=http://www.MageLang.com>MageLang Institute</a>
+ * @author <br>John Lilley, <a href=http://www.Empathy.com>Empathy Software</a>
+ * @author <br><a href="mailto:pete@yamuna.demon.co.uk">Pete Wells</a>
+ */
+
+#include "antlr/config.hpp"
+#include "antlr/AST.hpp"
+
+ANTLR_BEGIN_NAMESPACE(antlr)
+
+class BaseAST;
+typedef ASTRefCount<BaseAST> RefBaseAST;
+
+class BaseAST : public AST {
+public:
+ BaseAST() : AST() {}
+ virtual ~BaseAST() {}
+protected:
+ RefBaseAST down;
+ RefBaseAST right;
+
+//private:
+// static bool verboseStringConversion;
+// static ANTLR_USE_NAMESPACE(std)vector<ANTLR_USE_NAMESPACE(std)string> tokenNames;
+
+public:
+ virtual void addChild(RefAST c);
+
+private:
+ void doWorkForFindAll(ANTLR_USE_NAMESPACE(std)vector<RefAST>& v,
+ RefAST target,bool partialMatch);
+
+public:
+ virtual bool equals(RefAST t) const;
+ virtual bool equalsList(RefAST t) const;
+ virtual bool equalsListPartial(RefAST t) const;
+ virtual bool equalsTree(RefAST t) const;
+ virtual bool equalsTreePartial(RefAST t) const;
+
+ virtual ANTLR_USE_NAMESPACE(std)vector<RefAST> findAll(RefAST t);
+ virtual ANTLR_USE_NAMESPACE(std)vector<RefAST> findAllPartial(RefAST t);
+
+ /** Get the first child of this node; null if no children */
+ virtual RefAST getFirstChild() const;
+ /** Get the next sibling in line after this one */
+ virtual RefAST getNextSibling() const;
+
+ /** Get the token text for this node */
+ virtual ANTLR_USE_NAMESPACE(std)string getText() const;
+ /** Get the token type for this node */
+ virtual int getType() const;
+
+ /** Remove all children */
+ virtual void removeChildren();
+
+ /** Set the first child of a node. */
+ virtual void setFirstChild(RefAST c);
+ /** Set the next sibling after this one. */
+ void setNextSibling(RefAST n);
+
+ /** Set the token text for this node */
+ virtual void setText(const ANTLR_USE_NAMESPACE(std)string& txt);
+ /** Set the token type for this node */
+ virtual void setType(int type);
+
+// static void setVerboseStringConversion(bool verbose,
+// const ANTLR_USE_NAMESPACE(std)vector<ANTLR_USE_NAMESPACE(std)string>& names);
+
+ virtual ANTLR_USE_NAMESPACE(std)string toString() const;
+ virtual ANTLR_USE_NAMESPACE(std)string toStringList() const;
+ virtual ANTLR_USE_NAMESPACE(std)string toStringTree() const;
+};
+
+ANTLR_END_NAMESPACE
+
+#endif //INC_BaseAST_hpp__
diff --git a/poxml/antlr/antlr/BitSet.hpp b/poxml/antlr/antlr/BitSet.hpp
new file mode 100644
index 00000000..4eb400c7
--- /dev/null
+++ b/poxml/antlr/antlr/BitSet.hpp
@@ -0,0 +1,50 @@
+#ifndef INC_BitSet_hpp__
+#define INC_BitSet_hpp__
+
+#include "antlr/config.hpp"
+#include <vector>
+#include <stdexcept>
+
+ANTLR_BEGIN_NAMESPACE(antlr)
+
+/**A BitSet to replace java.util.BitSet.
+ * Primary differences are that most set operators return new sets
+ * as opposed to oring and anding "in place". Further, a number of
+ * operations were added. I cannot contain a BitSet because there
+ * is no way to access the internal bits (which I need for speed)
+ * and, because it is final, I cannot subclass to add functionality.
+ * Consider defining set degree. Without access to the bits, I must
+ * call a method n times to test the ith bit...ack!
+ *
+ * Also seems like or() from util is wrong when size of incoming set is bigger
+ * than this.length.
+ *
+ *
+ * This is a C++ version of the Java class described above, with only
+ * a handful of the methods implemented, because we don't need the
+ * others at runtime. It's really just a wrapper around vector<bool>,
+ * which should probably be changed to a wrapper around bitset, once
+ * bitset is more widely available.
+ *
+ * @author Terence Parr, MageLang Institute
+ * @author <br><a href="mailto:pete@yamuna.demon.co.uk">Pete Wells</a>
+ */
+class BitSet {
+private:
+ ANTLR_USE_NAMESPACE(std)vector<bool> storage;
+
+public:
+ BitSet(int nbits=64);
+ BitSet(const unsigned long* bits_,int nlongs);
+ ~BitSet();
+
+ void add(int el);
+
+ bool member(int el) const;
+
+ ANTLR_USE_NAMESPACE(std)vector<int> toArray() const;
+};
+
+ANTLR_END_NAMESPACE
+
+#endif //INC_BitSet_hpp__
diff --git a/poxml/antlr/antlr/CharBuffer.hpp b/poxml/antlr/antlr/CharBuffer.hpp
new file mode 100644
index 00000000..45d467bb
--- /dev/null
+++ b/poxml/antlr/antlr/CharBuffer.hpp
@@ -0,0 +1,75 @@
+#ifndef INC_CharBuffer_hpp__
+#define INC_CharBuffer_hpp__
+
+/**
+ * <b>SOFTWARE RIGHTS</b>
+ * <p>
+ * ANTLR 2.6.0 MageLang Insitute, 1999
+ * <p>
+ * We reserve no legal rights to the ANTLR--it is fully in the
+ * public domain. An individual or company may do whatever
+ * they wish with source code distributed with ANTLR or the
+ * code generated by ANTLR, including the incorporation of
+ * ANTLR, or its output, into commerical software.
+ * <p>
+ * We encourage users to develop software with ANTLR. However,
+ * we do ask that credit is given to us for developing
+ * ANTLR. By "credit", we mean that if you use ANTLR or
+ * incorporate any source code into one of your programs
+ * (commercial product, research project, or otherwise) that
+ * you acknowledge this fact somewhere in the documentation,
+ * research report, etc... If you like ANTLR and have
+ * developed a nice tool with the output, please mention that
+ * you developed it using ANTLR. In addition, we ask that the
+ * headers remain intact in our source code. As long as these
+ * guidelines are kept, we expect to continue enhancing this
+ * system and expect to make other tools available as they are
+ * completed.
+ * <p>
+ * The ANTLR gang:
+ * @version ANTLR 2.6.0 MageLang Insitute, 1999
+ * @author Terence Parr, <a href=http://www.MageLang.com>MageLang Institute</a>
+ * @author <br>John Lilley, <a href=http://www.Empathy.com>Empathy Software</a>
+ * @author <br><a href="mailto:pete@yamuna.demon.co.uk">Pete Wells</a>
+ */
+
+/**A Stream of characters fed to the lexer from a InputStream that can
+ * be rewound via mark()/rewind() methods.
+ * <p>
+ * A dynamic array is used to buffer up all the input characters. Normally,
+ * "k" characters are stored in the buffer. More characters may be stored during
+ * guess mode (testing syntactic predicate), or when LT(i>k) is referenced.
+ * Consumption of characters is deferred. In other words, reading the next
+ * character is not done by conume(), but deferred until needed by LA or LT.
+ * <p>
+ *
+ * @see antlr.CharQueue
+ */
+
+#include "antlr/config.hpp"
+#include "antlr/InputBuffer.hpp"
+#include <iostream>
+
+ANTLR_BEGIN_NAMESPACE(antlr)
+
+class CharBuffer : public InputBuffer {
+private:
+ // char source
+ ANTLR_USE_NAMESPACE(std)istream& input;
+
+public:
+ /** Create a character buffer */
+ CharBuffer(ANTLR_USE_NAMESPACE(std)istream& input_);
+
+ /** Get the next character from the stream */
+ int getChar();
+
+private:
+// Not implemented.
+// CharBuffer(const CharBuffer& other);
+// CharBuffer& operator=(const CharBuffer& other);
+};
+
+ANTLR_END_NAMESPACE
+
+#endif //INC_CharBuffer_hpp__
diff --git a/poxml/antlr/antlr/CharScanner.hpp b/poxml/antlr/antlr/CharScanner.hpp
new file mode 100644
index 00000000..b0ab9276
--- /dev/null
+++ b/poxml/antlr/antlr/CharScanner.hpp
@@ -0,0 +1,265 @@
+#ifndef INC_CharScanner_hpp__
+#define INC_CharScanner_hpp__
+
+/**
+ * <b>SOFTWARE RIGHTS</b>
+ * <p>
+ * ANTLR 2.6.0 MageLang Insitute, 1999
+ * <p>
+ * $Id$
+ * <p>
+ * We reserve no legal rights to the ANTLR--it is fully in the
+ * public domain. An individual or company may do whatever
+ * they wish with source code distributed with ANTLR or the
+ * code generated by ANTLR, including the incorporation of
+ * ANTLR, or its output, into commerical software.
+ * <p>
+ * We encourage users to develop software with ANTLR. However,
+ * we do ask that credit is given to us for developing
+ * ANTLR. By "credit", we mean that if you use ANTLR or
+ * incorporate any source code into one of your programs
+ * (commercial product, research project, or otherwise) that
+ * you acknowledge this fact somewhere in the documentation,
+ * research report, etc... If you like ANTLR and have
+ * developed a nice tool with the output, please mention that
+ * you developed it using ANTLR. In addition, we ask that the
+ * headers remain intact in our source code. As long as these
+ * guidelines are kept, we expect to continue enhancing this
+ * system and expect to make other tools available as they are
+ * completed.
+ * <p>
+ * The ANTLR gang:
+ * @version ANTLR 2.6.0 MageLang Insitute, 1999
+ * @author Terence Parr, <a href=http://www.MageLang.com>MageLang Institute</a>
+ * @author <br>John Lilley, <a href=http://www.Empathy.com>Empathy Software</a>
+ * @author <br><a href="mailto:pete@yamuna.demon.co.uk">Pete Wells</a>
+ */
+
+#include "antlr/config.hpp"
+#include "antlr/TokenStream.hpp"
+#include "antlr/RecognitionException.hpp"
+#include "antlr/InputBuffer.hpp"
+#include "antlr/BitSet.hpp"
+#include "antlr/LexerSharedInputState.hpp"
+#include <map>
+#include <cstdio>
+
+ANTLR_BEGIN_NAMESPACE(antlr)
+
+class CharScanner;
+
+class CharScannerLiteralsLess : public ANTLR_USE_NAMESPACE(std)binary_function<ANTLR_USE_NAMESPACE(std)string,ANTLR_USE_NAMESPACE(std)string,bool> {
+private:
+ const CharScanner* scanner;
+public:
+#ifdef NO_TEMPLATE_PARTS
+ CharScannerLiteralsLess(); // not really used
+#endif
+ CharScannerLiteralsLess(const CharScanner* theScanner);
+ bool operator() (const ANTLR_USE_NAMESPACE(std)string& x,const ANTLR_USE_NAMESPACE(std)string& y) const;
+private:
+// CharScannerLiteralsLess(const CharScannerLiteralsLess&);
+// CharScannerLiteralsLess& operator=(const CharScannerLiteralsLess&);
+};
+
+class CharScanner : public TokenStream {
+private:
+#ifndef NO_STATIC_CONSTS
+ static const int NO_CHAR = 0;
+#else
+ enum {
+ NO_CHAR = 0
+ };
+#endif
+
+public:
+#ifndef NO_STATIC_CONSTS
+ static const int EOF_CHAR = EOF;
+#else
+ enum {
+ EOF_CHAR = EOF
+ };
+#endif
+
+protected:
+ ANTLR_USE_NAMESPACE(std)string text; // text of current token
+
+ bool saveConsumedInput; // does consume() save characters?
+
+ typedef RefToken (*factory_type)();
+ factory_type tokenFactory; // what kind of tokens to create?
+
+ bool caseSensitive;
+ ANTLR_USE_NAMESPACE(std)map<ANTLR_USE_NAMESPACE(std)string,int,CharScannerLiteralsLess> literals; // set by subclass
+
+ RefToken _returnToken; // used to return tokens w/o using return val
+
+ // Input chars
+ LexerSharedInputState inputState;
+
+ /** Used during filter mode to indicate that path is desired.
+ * A subsequent scan error will report an error as usual if acceptPath=true;
+ */
+ bool commitToPath;
+
+public:
+ CharScanner();
+
+ CharScanner(InputBuffer& cb);
+ CharScanner(InputBuffer* cb);
+
+ CharScanner(const LexerSharedInputState& state);
+
+ virtual ~CharScanner();
+
+ virtual void append(char c);
+
+ virtual void append(const ANTLR_USE_NAMESPACE(std)string& s);
+
+ virtual void commit();
+
+ virtual void consume();
+
+ /** Consume chars until one matches the given char */
+ virtual void consumeUntil(int c);
+
+ /** Consume chars until one matches the given set */
+ virtual void consumeUntil(const BitSet& set);
+
+ virtual bool getCaseSensitive() const;
+
+ virtual bool getCaseSensitiveLiterals() const=0;
+
+ virtual int getColumn() const;
+
+ virtual void setColumn(int c);
+
+ virtual bool getCommitToPath() const;
+
+ virtual const ANTLR_USE_NAMESPACE(std)string& getFilename() const;
+
+ virtual InputBuffer& getInputBuffer();
+
+ virtual LexerSharedInputState getInputState();
+
+ virtual int getLine() const;
+
+ /** return a copy of the current text buffer */
+ virtual const ANTLR_USE_NAMESPACE(std)string& getText() const;
+
+ virtual RefToken getTokenObject() const;
+
+ virtual int LA(int i);
+
+protected:
+ virtual RefToken makeToken(int t);
+
+public:
+ virtual int mark();
+
+ virtual void match(int c);
+
+ virtual void match(const BitSet& b);
+
+ virtual void match(const ANTLR_USE_NAMESPACE(std)string& s);
+
+ virtual void matchNot(int c);
+
+ virtual void matchRange(int c1, int c2);
+
+ virtual void newline();
+
+ virtual void tab();
+
+ void panic();
+
+ void panic(const ANTLR_USE_NAMESPACE(std)string& s);
+
+ /** Report exception errors caught in nextToken() */
+ virtual void reportError(const RecognitionException& e);
+
+ /** Parser error-reporting function can be overridden in subclass */
+ virtual void reportError(const ANTLR_USE_NAMESPACE(std)string& s);
+
+ /** Parser warning-reporting function can be overridden in subclass */
+ virtual void reportWarning(const ANTLR_USE_NAMESPACE(std)string& s);
+
+ virtual void resetText();
+
+ virtual void rewind(int pos);
+
+ virtual void setCaseSensitive(bool t);
+
+ virtual void setCommitToPath(bool commit);
+
+ virtual void setFilename(const ANTLR_USE_NAMESPACE(std)string& f);
+
+ virtual void setInputState(LexerSharedInputState state);
+
+ virtual void setLine(int l);
+
+ virtual void setText(const ANTLR_USE_NAMESPACE(std)string& s);
+
+ virtual void setTokenObjectFactory(factory_type factory);
+
+ // Test the token text against the literals table
+ // Override this method to perform a different literals test
+ virtual int testLiteralsTable(int ttype) const;
+
+ // Test the text passed in against the literals table
+ // Override this method to perform a different literals test
+ // This is used primarily when you want to test a portion of
+ // a token
+ virtual int testLiteralsTable(const ANTLR_USE_NAMESPACE(std)string& text,int ttype) const;
+
+ // Override this method to get more specific case handling
+ virtual int toLower(int c) const;
+
+protected:
+ class Tracer {
+ private:
+ CharScanner* parser;
+ ANTLR_USE_NAMESPACE(std)string text;
+ public:
+ Tracer(CharScanner* p,const ANTLR_USE_NAMESPACE(std)string& t)
+ : parser(p), text(t) { parser->traceIn(text); }
+ ~Tracer()
+ { parser->traceOut(text); }
+ };
+
+ int traceDepth;
+public:
+ virtual void traceIndent();
+ virtual void traceIn(const ANTLR_USE_NAMESPACE(std)string& rname);
+ virtual void traceOut(const ANTLR_USE_NAMESPACE(std)string& rname);
+
+ /* This method is called by YourLexer::nextToken() when the lexer has
+ * hit EOF condition. EOF is NOT a character.
+ * This method is not called if EOF is reached during
+ * syntactic predicate evaluation or during evaluation
+ * of normal lexical rules, which presumably would be
+ * an IOException. This traps the "normal" EOF condition.
+ *
+ * uponEOF() is called after the complete evaluation of
+ * the previous token and only if your parser asks
+ * for another token beyond that last non-EOF token.
+ *
+ * You might want to throw token or char stream exceptions
+ * like: "Heh, premature eof" or a retry stream exception
+ * ("I found the end of this file, go back to referencing file").
+ */
+ virtual void uponEOF();
+};
+
+inline int CharScanner::LA(int i)
+{
+ if ( caseSensitive ) {
+ return inputState->getInput().LA(i);
+ } else {
+ return toLower(inputState->getInput().LA(i));
+ }
+}
+
+ANTLR_END_NAMESPACE
+
+#endif //INC_CharScanner_hpp__
diff --git a/poxml/antlr/antlr/CharStreamException.hpp b/poxml/antlr/antlr/CharStreamException.hpp
new file mode 100644
index 00000000..33f52061
--- /dev/null
+++ b/poxml/antlr/antlr/CharStreamException.hpp
@@ -0,0 +1,18 @@
+#ifndef INC_CharStreamException_hpp__
+#define INC_CharStreamException_hpp__
+
+#include "antlr/config.hpp"
+#include "antlr/ANTLRException.hpp"
+
+ANTLR_BEGIN_NAMESPACE(antlr)
+
+class CharStreamException : public ANTLRException {
+public:
+ CharStreamException(const ANTLR_USE_NAMESPACE(std)string& s)
+ : ANTLRException(s) {}
+ ~CharStreamException() throw() {}
+};
+
+ANTLR_END_NAMESPACE
+
+#endif //INC_CharStreamException_hpp__
diff --git a/poxml/antlr/antlr/CharStreamIOException.hpp b/poxml/antlr/antlr/CharStreamIOException.hpp
new file mode 100644
index 00000000..1a8b1d1e
--- /dev/null
+++ b/poxml/antlr/antlr/CharStreamIOException.hpp
@@ -0,0 +1,20 @@
+#ifndef INC_CharStreamIOException_hpp__
+#define INC_CharStreamIOException_hpp__
+
+#include "antlr/config.hpp"
+#include "antlr/CharStreamException.hpp"
+
+ANTLR_BEGIN_NAMESPACE(antlr)
+
+class CharStreamIOException : public CharStreamException {
+public:
+ ANTLR_USE_NAMESPACE(std)exception io;
+
+ CharStreamIOException(ANTLR_USE_NAMESPACE(std)exception& e)
+ : CharStreamException(e.what()), io(e) {}
+ ~CharStreamIOException() throw() {}
+};
+
+ANTLR_END_NAMESPACE
+
+#endif //INC_CharStreamIOException_hpp__
diff --git a/poxml/antlr/antlr/CircularQueue.hpp b/poxml/antlr/antlr/CircularQueue.hpp
new file mode 100644
index 00000000..eadf8d42
--- /dev/null
+++ b/poxml/antlr/antlr/CircularQueue.hpp
@@ -0,0 +1,88 @@
+#ifndef INC_CircularQueue_hpp__
+#define INC_CircularQueue_hpp__
+
+/**
+ * <b>SOFTWARE RIGHTS</b>
+ * <p>
+ * ANTLR 2.6.0 MageLang Insitute, 1999
+ * <p>
+ * We reserve no legal rights to the ANTLR--it is fully in the
+ * public domain. An individual or company may do whatever
+ * they wish with source code distributed with ANTLR or the
+ * code generated by ANTLR, including the incorporation of
+ * ANTLR, or its output, into commerical software.
+ * <p>
+ * We encourage users to develop software with ANTLR. However,
+ * we do ask that credit is given to us for developing
+ * ANTLR. By "credit", we mean that if you use ANTLR or
+ * incorporate any source code into one of your programs
+ * (commercial product, research project, or otherwise) that
+ * you acknowledge this fact somewhere in the documentation,
+ * research report, etc... If you like ANTLR and have
+ * developed a nice tool with the output, please mention that
+ * you developed it using ANTLR. In addition, we ask that the
+ * headers remain intact in our source code. As long as these
+ * guidelines are kept, we expect to continue enhancing this
+ * system and expect to make other tools available as they are
+ * completed.
+ * <p>
+ * The ANTLR gang:
+ * @version ANTLR 2.6.0 MageLang Insitute, 1999
+ * @author Terence Parr, <a href=http://www.MageLang.com>MageLang Institute</a>
+ * @author <br>John Lilley, <a href=http://www.Empathy.com>Empathy Software</a>
+ * @author <br><a href="mailto:pete@yamuna.demon.co.uk">Pete Wells</a>
+ */
+
+#include "antlr/config.hpp"
+#include <vector>
+
+ANTLR_BEGIN_NAMESPACE(antlr)
+
+// Resize every 5000 items
+#define OFFSET_MAX_RESIZE 5000
+
+template <class T>
+class CircularQueue {
+private:
+ ANTLR_USE_NAMESPACE(std)vector<T> storage;
+
+public:
+ CircularQueue()
+ : storage(), m_offset(0) {}
+ ~CircularQueue()
+ {}
+
+ T elementAt(int idx) const
+ { return storage[idx+m_offset]; } //Is this safe?
+ void removeFirst()
+ {
+ if (m_offset >= OFFSET_MAX_RESIZE) {
+ storage.erase( storage.begin(), storage.begin() + m_offset + 1 );
+ m_offset = 0;
+ } else {
+ ++m_offset;
+ }
+ }
+ inline void removeItems( int nb )
+ {
+ if (m_offset >= OFFSET_MAX_RESIZE) {
+ storage.erase( storage.begin(), storage.begin() + m_offset + nb );
+ m_offset = 0;
+ } else {
+ m_offset+=nb;
+ }
+ }
+ void append(const T& t)
+ { storage.push_back(t); }
+ int entries() const
+ { return storage.size()-m_offset; }
+
+private:
+ int m_offset;
+ CircularQueue(const CircularQueue&);
+ const CircularQueue& operator=(const CircularQueue&);
+};
+
+ANTLR_END_NAMESPACE
+
+#endif //INC_CircularQueue_hpp__
diff --git a/poxml/antlr/antlr/CommonAST.hpp b/poxml/antlr/antlr/CommonAST.hpp
new file mode 100644
index 00000000..c7ab7313
--- /dev/null
+++ b/poxml/antlr/antlr/CommonAST.hpp
@@ -0,0 +1,68 @@
+#ifndef INC_CommonAST_hpp__
+#define INC_CommonAST_hpp__
+
+/**
+ * <b>SOFTWARE RIGHTS</b>
+ * <p>
+ * ANTLR 2.6.0 MageLang Insitute, 1999
+ * <p>
+ * We reserve no legal rights to the ANTLR--it is fully in the
+ * public domain. An individual or company may do whatever
+ * they wish with source code distributed with ANTLR or the
+ * code generated by ANTLR, including the incorporation of
+ * ANTLR, or its output, into commerical software.
+ * <p>
+ * We encourage users to develop software with ANTLR. However,
+ * we do ask that credit is given to us for developing
+ * ANTLR. By "credit", we mean that if you use ANTLR or
+ * incorporate any source code into one of your programs
+ * (commercial product, research project, or otherwise) that
+ * you acknowledge this fact somewhere in the documentation,
+ * research report, etc... If you like ANTLR and have
+ * developed a nice tool with the output, please mention that
+ * you developed it using ANTLR. In addition, we ask that the
+ * headers remain intact in our source code. As long as these
+ * guidelines are kept, we expect to continue enhancing this
+ * system and expect to make other tools available as they are
+ * completed.
+ * <p>
+ * The ANTLR gang:
+ * @version ANTLR 2.6.0 MageLang Insitute, 1999
+ * @author Terence Parr, <a href=http://www.MageLang.com>MageLang Institute</a>
+ * @author <br>John Lilley, <a href=http://www.Empathy.com>Empathy Software</a>
+ * @author <br><a href="mailto:pete@yamuna.demon.co.uk">Pete Wells</a>
+ */
+
+#include "antlr/config.hpp"
+#include "antlr/BaseAST.hpp"
+
+ANTLR_BEGIN_NAMESPACE(antlr)
+
+class CommonAST : public BaseAST {
+public:
+ CommonAST();
+ CommonAST(RefToken t);
+ virtual ~CommonAST();
+
+ virtual ANTLR_USE_NAMESPACE(std)string getText() const;
+ virtual int getType() const;
+
+ virtual void initialize(int t,const ANTLR_USE_NAMESPACE(std)string& txt);
+ virtual void initialize(RefAST t);
+ virtual void initialize(RefToken t);
+
+ virtual void setText(const ANTLR_USE_NAMESPACE(std)string& txt);
+ virtual void setType(int type);
+
+ static RefAST factory();
+
+protected:
+ int ttype;
+ ANTLR_USE_NAMESPACE(std)string text;
+};
+
+typedef ASTRefCount<CommonAST> RefCommonAST;
+
+ANTLR_END_NAMESPACE
+
+#endif //INC_CommonAST_hpp__
diff --git a/poxml/antlr/antlr/CommonASTWithHiddenTokens.hpp b/poxml/antlr/antlr/CommonASTWithHiddenTokens.hpp
new file mode 100644
index 00000000..11e030e7
--- /dev/null
+++ b/poxml/antlr/antlr/CommonASTWithHiddenTokens.hpp
@@ -0,0 +1,41 @@
+#ifndef INC_CommonASTWithHiddenTokens_hpp__
+#define INC_CommonASTWithHiddenTokens_hpp__
+
+/** A CommonAST whose initialization copies hidden token
+ * information from the Token used to create a node.
+ */
+
+#include "antlr/config.hpp"
+#include "antlr/CommonAST.hpp"
+
+ANTLR_BEGIN_NAMESPACE(antlr)
+
+class CommonASTWithHiddenTokens : public CommonAST {
+public:
+ CommonASTWithHiddenTokens() : CommonAST()
+ {
+ }
+ virtual ~CommonASTWithHiddenTokens()
+ {
+ }
+protected:
+ RefToken hiddenBefore,hiddenAfter; // references to hidden tokens
+public:
+ virtual RefToken getHiddenAfter() const
+ { return hiddenAfter; }
+ virtual RefToken getHiddenBefore() const
+ { return hiddenBefore; }
+
+ // Borland C++ builder seems to need the decl's of the first two...
+ virtual void initialize(int t,const ANTLR_USE_NAMESPACE(std)string& txt);
+ virtual void initialize(RefAST t);
+ virtual void initialize(RefToken t);
+
+ static RefAST factory();
+};
+
+typedef ASTRefCount<CommonASTWithHiddenTokens> RefCommonASTWithHiddenTokens;
+
+ANTLR_END_NAMESPACE
+
+#endif //INC_CommonASTWithHiddenTokens_hpp__
diff --git a/poxml/antlr/antlr/CommonHiddenStreamToken.hpp b/poxml/antlr/antlr/CommonHiddenStreamToken.hpp
new file mode 100644
index 00000000..50ff2354
--- /dev/null
+++ b/poxml/antlr/antlr/CommonHiddenStreamToken.hpp
@@ -0,0 +1,30 @@
+#ifndef INC_CommonHiddenStreamToken_hpp__
+#define INC_CommonHiddenStreamToken_hpp__
+
+#include "antlr/config.hpp"
+#include "antlr/CommonToken.hpp"
+
+ANTLR_BEGIN_NAMESPACE(antlr)
+
+class CommonHiddenStreamToken : public CommonToken {
+protected:
+ RefToken hiddenBefore;
+ RefToken hiddenAfter;
+
+public:
+ CommonHiddenStreamToken();
+ CommonHiddenStreamToken(int t, const ANTLR_USE_NAMESPACE(std)string& txt);
+ CommonHiddenStreamToken(const ANTLR_USE_NAMESPACE(std)string& s);
+
+ RefToken getHiddenAfter();
+ RefToken getHiddenBefore();
+
+ static RefToken factory();
+
+ void setHiddenAfter(RefToken t);
+ void setHiddenBefore(RefToken t);
+};
+
+ANTLR_END_NAMESPACE
+
+#endif //INC_CommonHiddenStreamToken_hpp__
diff --git a/poxml/antlr/antlr/CommonToken.hpp b/poxml/antlr/antlr/CommonToken.hpp
new file mode 100644
index 00000000..669aa535
--- /dev/null
+++ b/poxml/antlr/antlr/CommonToken.hpp
@@ -0,0 +1,77 @@
+#ifndef INC_CommonToken_hpp__
+#define INC_CommonToken_hpp__
+
+/**
+ * <b>SOFTWARE RIGHTS</b>
+ * <p>
+ * ANTLR 2.6.0 MageLang Insitute, 1999
+ * <p>
+ * We reserve no legal rights to the ANTLR--it is fully in the
+ * public domain. An individual or company may do whatever
+ * they wish with source code distributed with ANTLR or the
+ * code generated by ANTLR, including the incorporation of
+ * ANTLR, or its output, into commerical software.
+ * <p>
+ * We encourage users to develop software with ANTLR. However,
+ * we do ask that credit is given to us for developing
+ * ANTLR. By "credit", we mean that if you use ANTLR or
+ * incorporate any source code into one of your programs
+ * (commercial product, research project, or otherwise) that
+ * you acknowledge this fact somewhere in the documentation,
+ * research report, etc... If you like ANTLR and have
+ * developed a nice tool with the output, please mention that
+ * you developed it using ANTLR. In addition, we ask that the
+ * headers remain intact in our source code. As long as these
+ * guidelines are kept, we expect to continue enhancing this
+ * system and expect to make other tools available as they are
+ * completed.
+ * <p>
+ * The ANTLR gang:
+ * @version ANTLR 2.6.0 MageLang Insitute, 1999
+ * @author Terence Parr, <a href=http://www.MageLang.com>MageLang Institute</a>
+ * @author <br>John Lilley, <a href=http://www.Empathy.com>Empathy Software</a>
+ * @author <br><a href="mailto:pete@yamuna.demon.co.uk">Pete Wells</a>
+ */
+
+#include "antlr/config.hpp"
+#include "antlr/Token.hpp"
+#include <string>
+
+ANTLR_BEGIN_NAMESPACE(antlr)
+
+class CommonToken : public Token {
+protected:
+ // most tokens will want line and text information
+ int line;
+ int col;
+ ANTLR_USE_NAMESPACE(std)string text;
+
+public:
+ CommonToken();
+ CommonToken(int t, const ANTLR_USE_NAMESPACE(std)string& txt);
+ CommonToken(const ANTLR_USE_NAMESPACE(std)string& s);
+
+ int getLine() const;
+ ANTLR_USE_NAMESPACE(std)string getText() const;
+ void setLine(int l);
+ void setText(const ANTLR_USE_NAMESPACE(std)string& s);
+
+ ANTLR_USE_NAMESPACE(std)string toString() const;
+
+ /** Return token's start column */
+ int getColumn() const;
+
+ void setColumn(int c);
+
+ bool isInvalid() const;
+
+ static RefToken factory();
+
+private:
+ CommonToken(const CommonToken&);
+ const CommonToken& operator=(const CommonToken&);
+};
+
+ANTLR_END_NAMESPACE
+
+#endif //INC_CommonToken_hpp__
diff --git a/poxml/antlr/antlr/InputBuffer.hpp b/poxml/antlr/antlr/InputBuffer.hpp
new file mode 100644
index 00000000..96e62191
--- /dev/null
+++ b/poxml/antlr/antlr/InputBuffer.hpp
@@ -0,0 +1,158 @@
+#ifndef INC_InputBuffer_hpp__
+#define INC_InputBuffer_hpp__
+
+/**
+ * <b>SOFTWARE RIGHTS</b>
+ * <p>
+ * ANTLR 2.6.0 MageLang Insitute, 1999
+ * <p>
+ * We reserve no legal rights to the ANTLR--it is fully in the
+ * public domain. An individual or company may do whatever
+ * they wish with source code distributed with ANTLR or the
+ * code generated by ANTLR, including the incorporation of
+ * ANTLR, or its output, into commerical software.
+ * <p>
+ * We encourage users to develop software with ANTLR. However,
+ * we do ask that credit is given to us for developing
+ * ANTLR. By "credit", we mean that if you use ANTLR or
+ * incorporate any source code into one of your programs
+ * (commercial product, research project, or otherwise) that
+ * you acknowledge this fact somewhere in the documentation,
+ * research report, etc... If you like ANTLR and have
+ * developed a nice tool with the output, please mention that
+ * you developed it using ANTLR. In addition, we ask that the
+ * headers remain intact in our source code. As long as these
+ * guidelines are kept, we expect to continue enhancing this
+ * system and expect to make other tools available as they are
+ * completed.
+ * <p>
+ * The ANTLR gang:
+ * @version ANTLR 2.6.0 MageLang Insitute, 1999
+ * @author Terence Parr, <a href=http://www.MageLang.com>MageLang Institute</a>
+ * @author <br>John Lilley, <a href=http://www.Empathy.com>Empathy Software</a>
+ * @author <br><a href="mailto:pete@yamuna.demon.co.uk">Pete Wells</a>
+ */
+
+/**A Stream of characters fed to the lexer from a InputStream that can
+ * be rewound via mark()/rewind() methods.
+ * <p>
+ * A dynamic array is used to buffer up all the input characters. Normally,
+ * "k" characters are stored in the buffer. More characters may be stored during
+ * guess mode (testing syntactic predicate), or when LT(i>k) is referenced.
+ * Consumption of characters is deferred. In other words, reading the next
+ * character is not done by conume(), but deferred until needed by LA or LT.
+ * <p>
+ *
+ * @see antlr.CharQueue
+ */
+
+#include "antlr/config.hpp"
+#include "antlr/CircularQueue.hpp"
+#include <string>
+
+ANTLR_BEGIN_NAMESPACE(antlr)
+
+class InputBuffer {
+protected:
+ // char source
+ // leave to subclasses
+
+ // Number of active markers
+ int nMarkers; // = 0;
+
+ // Additional offset used when markers are active
+ int markerOffset; // = 0;
+
+ // Number of calls to consume() since last LA() or LT() call
+ int numToConsume; // = 0;
+
+ // Circular queue
+ CircularQueue<int> queue;
+
+public:
+ /** Create a character buffer */
+ InputBuffer();
+
+ virtual ~InputBuffer() {}
+
+ /** This method updates the state of the input buffer so that
+ * the text matched since the most recent mark() is no longer
+ * held by the buffer. So, you either do a mark/rewind for
+ * failed predicate or mark/commit to keep on parsing without
+ * rewinding the input.
+ */
+ void commit();
+
+ /** Mark another character for deferred consumption */
+ virtual void consume();
+
+ /** Ensure that the character buffer is sufficiently full */
+ virtual void fill(int amount);
+
+ /** Override this in subclasses to get the next character */
+ virtual int getChar()=0;
+
+ ANTLR_USE_NAMESPACE(std)string getLAChars() const;
+
+ ANTLR_USE_NAMESPACE(std)string getMarkedChars() const;
+
+ virtual bool isMarked() const;
+
+ /** Get a lookahead character */
+ virtual int LA(int i);
+
+ /**Return an integer marker that can be used to rewind the buffer to
+ * its current state.
+ */
+ virtual int mark();
+
+ /**Rewind the character buffer to a marker.
+ * @param mark Marker returned previously from mark()
+ */
+ virtual void rewind(int mark);
+
+protected:
+ /** Sync up deferred consumption */
+ void syncConsume();
+
+private:
+ InputBuffer(const InputBuffer& other);
+ InputBuffer& operator=(const InputBuffer& other);
+};
+
+/** Sync up deferred consumption */
+inline void InputBuffer::syncConsume() {
+#ifdef OLD_CODE
+ while (numToConsume > 0) {
+ if (nMarkers > 0)
+ {
+ // guess mode -- leave leading characters and bump offset.
+ markerOffset++;
+ } else {
+ // normal mode -- remove first character
+ queue.removeFirst();
+ }
+ numToConsume--;
+ }
+#endif
+
+ if (numToConsume > 0) {
+ if (nMarkers > 0) {
+ markerOffset += numToConsume;
+ } else {
+ queue.removeItems( numToConsume );
+ }
+ numToConsume = 0;
+ }
+}
+
+/** Get a lookahead character */
+inline int InputBuffer::LA(int i)
+{
+ fill(i);
+ return queue.elementAt(markerOffset + i - 1);
+}
+
+ANTLR_END_NAMESPACE
+
+#endif //INC_InputBuffer_hpp__
diff --git a/poxml/antlr/antlr/LLkParser.hpp b/poxml/antlr/antlr/LLkParser.hpp
new file mode 100644
index 00000000..8b8db188
--- /dev/null
+++ b/poxml/antlr/antlr/LLkParser.hpp
@@ -0,0 +1,82 @@
+#ifndef INC_LLkParser_hpp__
+#define INC_LLkParser_hpp__
+
+/**
+ * <b>SOFTWARE RIGHTS</b>
+ * <p>
+ * ANTLR 2.6.0 MageLang Insitute, 1999
+ * <p>
+ * We reserve no legal rights to the ANTLR--it is fully in the
+ * public domain. An individual or company may do whatever
+ * they wish with source code distributed with ANTLR or the
+ * code generated by ANTLR, including the incorporation of
+ * ANTLR, or its output, into commerical software.
+ * <p>
+ * We encourage users to develop software with ANTLR. However,
+ * we do ask that credit is given to us for developing
+ * ANTLR. By "credit", we mean that if you use ANTLR or
+ * incorporate any source code into one of your programs
+ * (commercial product, research project, or otherwise) that
+ * you acknowledge this fact somewhere in the documentation,
+ * research report, etc... If you like ANTLR and have
+ * developed a nice tool with the output, please mention that
+ * you developed it using ANTLR. In addition, we ask that the
+ * headers remain intact in our source code. As long as these
+ * guidelines are kept, we expect to continue enhancing this
+ * system and expect to make other tools available as they are
+ * completed.
+ * <p>
+ * The ANTLR gang:
+ * @version ANTLR 2.6.0 MageLang Insitute, 1999
+ * @author Terence Parr, <a href=http://www.MageLang.com>MageLang Institute</a>
+ * @author <br>John Lilley, <a href=http://www.Empathy.com>Empathy Software</a>
+ * @author <br><a href="mailto:pete@yamuna.demon.co.uk">Pete Wells</a>
+ */
+
+#include "antlr/config.hpp"
+#include "antlr/Parser.hpp"
+
+ANTLR_BEGIN_NAMESPACE(antlr)
+
+/**An LL(k) parser.
+ *
+ * @see antlr.Token
+ * @see antlr.TokenBuffer
+ * @see antlr.LL1Parser
+ */
+class LLkParser : public Parser {
+protected:
+ int k;
+
+public:
+// LLkParser(int k_);
+
+ LLkParser(const ParserSharedInputState& lexer, int k_);
+
+ LLkParser(TokenBuffer& tokenBuf, int k_);
+
+ LLkParser(TokenStream& lexer, int k_);
+
+ /**Consume another token from the input stream. Can only write sequentially!
+ * If you need 3 tokens ahead, you must consume() 3 times.
+ * <p>
+ * Note that it is possible to overwrite tokens that have not been matched.
+ * For example, calling consume() 3 times when k=2, means that the first token
+ * consumed will be overwritten with the 3rd.
+ */
+ void consume();
+
+ int LA(int i);
+
+ RefToken LT(int i);
+
+private:
+ void trace(const ANTLR_USE_NAMESPACE(std)string& ee, const ANTLR_USE_NAMESPACE(std)string& rname);
+public:
+ void traceIn(const ANTLR_USE_NAMESPACE(std)string& rname);
+ void traceOut(const ANTLR_USE_NAMESPACE(std)string& rname);
+};
+
+ANTLR_END_NAMESPACE
+
+#endif //INC_LLkParser_hpp__
diff --git a/poxml/antlr/antlr/LexerSharedInputState.hpp b/poxml/antlr/antlr/LexerSharedInputState.hpp
new file mode 100644
index 00000000..dba2a5f4
--- /dev/null
+++ b/poxml/antlr/antlr/LexerSharedInputState.hpp
@@ -0,0 +1,49 @@
+#ifndef INC_LexerSharedInputState_hpp__
+#define INC_LexerSharedInputState_hpp__
+
+#include "antlr/config.hpp"
+#include "antlr/InputBuffer.hpp"
+#include "antlr/RefCount.hpp"
+#include <string>
+
+ANTLR_BEGIN_NAMESPACE(antlr)
+
+/** This object contains the data associated with an
+ * input stream of characters. Multiple lexers
+ * share a single LexerSharedInputState to lex
+ * the same input stream.
+ */
+class LexerInputState {
+public:
+ LexerInputState(InputBuffer* inbuf);
+ LexerInputState(InputBuffer& inbuf);
+ LexerInputState(ANTLR_USE_NAMESPACE(std)istream& in);
+ ~LexerInputState();
+
+ int column;
+ int line;
+ int tokenStartColumn;
+ int tokenStartLine;
+ int guessing;
+ /** What file (if known) caused the problem? */
+ ANTLR_USE_NAMESPACE(std)string filename;
+ InputBuffer& getInput();
+private:
+ InputBuffer* input;
+ bool inputResponsible;
+
+ // we don't want these:
+ LexerInputState(const LexerInputState&);
+ LexerInputState& operator=(const LexerInputState&);
+};
+
+typedef RefCount<LexerInputState> LexerSharedInputState;
+
+inline InputBuffer& LexerInputState::getInput()
+{
+ return *input;
+}
+
+ANTLR_END_NAMESPACE
+
+#endif //INC_LexerSharedInputState_hpp__
diff --git a/poxml/antlr/antlr/Makefile.am b/poxml/antlr/antlr/Makefile.am
new file mode 100644
index 00000000..bafa1347
--- /dev/null
+++ b/poxml/antlr/antlr/Makefile.am
@@ -0,0 +1,45 @@
+noinst_HEADERS = \
+ ANTLRException.hpp \
+ AST.hpp \
+ ASTArray.hpp \
+ ASTFactory.hpp \
+ ASTNULLType.hpp \
+ ASTPair.hpp \
+ ASTRefCount.hpp \
+ BaseAST.hpp \
+ BitSet.hpp \
+ CharBuffer.hpp \
+ CharScanner.hpp \
+ CharStreamException.hpp \
+ CharStreamIOException.hpp \
+ CircularQueue.hpp \
+ CommonAST.hpp \
+ CommonASTWithHiddenTokens.hpp \
+ CommonHiddenStreamToken.hpp \
+ CommonToken.hpp \
+ InputBuffer.hpp \
+ LLkParser.hpp \
+ LexerSharedInputState.hpp \
+ MismatchedCharException.hpp \
+ MismatchedTokenException.hpp \
+ NoViableAltException.hpp \
+ NoViableAltForCharException.hpp \
+ Parser.hpp \
+ ParserSharedInputState.hpp \
+ RecognitionException.hpp \
+ RefCount.hpp \
+ SemanticException.hpp \
+ String.hpp \
+ Token.hpp \
+ TokenBuffer.hpp \
+ TokenStream.hpp \
+ TokenStreamBasicFilter.hpp \
+ TokenStreamException.hpp \
+ TokenStreamHiddenTokenFilter.hpp \
+ TokenStreamIOException.hpp \
+ TokenStreamRecognitionException.hpp \
+ TokenStreamRetryException.hpp \
+ TokenStreamSelector.hpp \
+ TreeParser.hpp \
+ TreeParserSharedInputState.hpp \
+ config.hpp
diff --git a/poxml/antlr/antlr/MismatchedCharException.hpp b/poxml/antlr/antlr/MismatchedCharException.hpp
new file mode 100644
index 00000000..ea923a9d
--- /dev/null
+++ b/poxml/antlr/antlr/MismatchedCharException.hpp
@@ -0,0 +1,127 @@
+#ifndef INC_MismatchedCharException_hpp__
+#define INC_MismatchedCharException_hpp__
+
+/**
+ * <b>SOFTWARE RIGHTS</b>
+ * <p>
+ * ANTLR 2.6.0 MageLang Insitute, 1999
+ * <p>
+ * We reserve no legal rights to the ANTLR--it is fully in the
+ * public domain. An individual or company may do whatever
+ * they wish with source code distributed with ANTLR or the
+ * code generated by ANTLR, including the incorporation of
+ * ANTLR, or its output, into commerical software.
+ * <p>
+ * We encourage users to develop software with ANTLR. However,
+ * we do ask that credit is given to us for developing
+ * ANTLR. By "credit", we mean that if you use ANTLR or
+ * incorporate any source code into one of your programs
+ * (commercial product, research project, or otherwise) that
+ * you acknowledge this fact somewhere in the documentation,
+ * research report, etc... If you like ANTLR and have
+ * developed a nice tool with the output, please mention that
+ * you developed it using ANTLR. In addition, we ask that the
+ * headers remain intact in our source code. As long as these
+ * guidelines are kept, we expect to continue enhancing this
+ * system and expect to make other tools available as they are
+ * completed.
+ * <p>
+ * The ANTLR gang:
+ * @version ANTLR 2.6.0 MageLang Insitute, 1999
+ * @author Terence Parr, <a href=http://www.MageLang.com>MageLang Institute</a>
+ * @author <br>John Lilley, <a href=http://www.Empathy.com>Empathy Software</a>
+ * @author <br><a href="mailto:pete@yamuna.demon.co.uk">Pete Wells</a>
+ */
+
+#include "antlr/config.hpp"
+#include "antlr/RecognitionException.hpp"
+#include "antlr/BitSet.hpp"
+#include "antlr/CharScanner.hpp"
+
+ANTLR_BEGIN_NAMESPACE(antlr)
+
+class MismatchedCharException : public RecognitionException {
+public:
+ // Types of chars
+#ifndef NO_STATIC_CONSTS
+ static const int CHAR = 1;
+ static const int NOT_CHAR = 2;
+ static const int RANGE = 3;
+ static const int NOT_RANGE = 4;
+ static const int SET = 5;
+ static const int NOT_SET = 6;
+#else
+ enum {
+ CHAR = 1,
+ NOT_CHAR = 2,
+ RANGE = 3,
+ NOT_RANGE = 4,
+ SET = 5,
+ NOT_SET = 6
+ };
+#endif
+
+public:
+ // One of the above
+ int mismatchType;
+
+ // what was found on the input stream
+ int foundChar;
+
+ // For CHAR/NOT_CHAR and RANGE/NOT_RANGE
+ int expecting;
+
+ // For RANGE/NOT_RANGE (expecting is lower bound of range)
+ int upper;
+
+ // For SET/NOT_SET
+ BitSet set;
+
+protected:
+ // who knows...they may want to ask scanner questions
+ CharScanner* scanner;
+
+public:
+ MismatchedCharException();
+
+ // Expected range / not range
+ MismatchedCharException(
+ int c,
+ int lower,
+ int upper_,
+ bool matchNot,
+ CharScanner* scanner_
+ );
+
+ // Expected token / not token
+ MismatchedCharException(
+ int c,
+ int expecting_,
+ bool matchNot,
+ CharScanner* scanner_
+ );
+
+ // Expected BitSet / not BitSet
+ MismatchedCharException(
+ int c,
+ BitSet set_,
+ bool matchNot,
+ CharScanner* scanner_
+ );
+
+ MismatchedCharException(
+ const ANTLR_USE_NAMESPACE(std)string& s,
+ int line
+ );
+ ~MismatchedCharException() throw() {}
+
+ /**
+ * Returns the error message that happened on the line/col given.
+ * Copied from toString().
+ */
+ ANTLR_USE_NAMESPACE(std)string getMessage() const;
+};
+
+ANTLR_END_NAMESPACE
+
+#endif //INC_MismatchedCharException_hpp__
diff --git a/poxml/antlr/antlr/MismatchedTokenException.hpp b/poxml/antlr/antlr/MismatchedTokenException.hpp
new file mode 100644
index 00000000..ae4a82cd
--- /dev/null
+++ b/poxml/antlr/antlr/MismatchedTokenException.hpp
@@ -0,0 +1,167 @@
+#ifndef INC_MismatchedTokenException_hpp__
+#define INC_MismatchedTokenException_hpp__
+
+/**
+ * <b>SOFTWARE RIGHTS</b>
+ * <p>
+ * ANTLR 2.6.0 MageLang Insitute, 1999
+ * <p>
+ * We reserve no legal rights to the ANTLR--it is fully in the
+ * public domain. An individual or company may do whatever
+ * they wish with source code distributed with ANTLR or the
+ * code generated by ANTLR, including the incorporation of
+ * ANTLR, or its output, into commerical software.
+ * <p>
+ * We encourage users to develop software with ANTLR. However,
+ * we do ask that credit is given to us for developing
+ * ANTLR. By "credit", we mean that if you use ANTLR or
+ * incorporate any source code into one of your programs
+ * (commercial product, research project, or otherwise) that
+ * you acknowledge this fact somewhere in the documentation,
+ * research report, etc... If you like ANTLR and have
+ * developed a nice tool with the output, please mention that
+ * you developed it using ANTLR. In addition, we ask that the
+ * headers remain intact in our source code. As long as these
+ * guidelines are kept, we expect to continue enhancing this
+ * system and expect to make other tools available as they are
+ * completed.
+ * <p>
+ * The ANTLR gang:
+ * @version ANTLR 2.6.0 MageLang Insitute, 1999
+ * @author Terence Parr, <a href=http://www.MageLang.com>MageLang Institute</a>
+ * @author <br>John Lilley, <a href=http://www.Empathy.com>Empathy Software</a>
+ * @author <br><a href="mailto:pete@yamuna.demon.co.uk">Pete Wells</a>
+ */
+
+#include "antlr/config.hpp"
+#include "antlr/RecognitionException.hpp"
+#include "antlr/BitSet.hpp"
+#include "antlr/Token.hpp"
+#include "antlr/AST.hpp"
+#include <vector>
+
+ANTLR_BEGIN_NAMESPACE(antlr)
+
+class MismatchedTokenException : public RecognitionException {
+private:
+ // Token names array for formatting
+ ANTLR_USE_NAMESPACE(std)vector<ANTLR_USE_NAMESPACE(std)string> tokenNames;
+
+public:
+ // The token that was encountered
+ const RefToken token;
+ // The offending AST node if tree walking
+ const RefAST node;
+
+ ANTLR_USE_NAMESPACE(std)string tokenText; // taken from node or token object
+
+ // Types of tokens
+#ifndef NO_STATIC_CONSTS
+ static const int TOKEN = 1;
+ static const int NOT_TOKEN = 2;
+ static const int RANGE = 3;
+ static const int NOT_RANGE = 4;
+ static const int SET = 5;
+ static const int NOT_SET = 6;
+#else
+ enum {
+ TOKEN = 1,
+ NOT_TOKEN = 2,
+ RANGE = 3,
+ NOT_RANGE = 4,
+ SET = 5,
+ NOT_SET = 6
+ };
+#endif
+
+public:
+ // One of the above
+ int mismatchType;
+
+ // For TOKEN/NOT_TOKEN and RANGE/NOT_RANGE
+ int expecting;
+
+ // For RANGE/NOT_RANGE (expecting is lower bound of range)
+ int upper;
+
+ // For SET/NOT_SET
+ BitSet set;
+
+ MismatchedTokenException();
+
+ // Expected range / not range
+ MismatchedTokenException(
+ const ANTLR_USE_NAMESPACE(std)vector<ANTLR_USE_NAMESPACE(std)string>& tokenNames_,
+ RefAST node_,
+ int lower,
+ int upper_,
+ bool matchNot
+ );
+
+ // Expected token / not token
+ MismatchedTokenException(
+ const ANTLR_USE_NAMESPACE(std)vector<ANTLR_USE_NAMESPACE(std)string>& tokenNames_,
+ RefAST node_,
+ int expecting_,
+ bool matchNot
+ );
+
+ // Expected BitSet / not BitSet
+ MismatchedTokenException(
+ const ANTLR_USE_NAMESPACE(std)vector<ANTLR_USE_NAMESPACE(std)string>& tokenNames_,
+ RefAST node_,
+ BitSet set_,
+ bool matchNot
+ );
+
+ // Expected range / not range
+ MismatchedTokenException(
+ const ANTLR_USE_NAMESPACE(std)vector<ANTLR_USE_NAMESPACE(std)string>& tokenNames_,
+ RefToken token_,
+ int lower,
+ int upper_,
+ bool matchNot,
+ const ANTLR_USE_NAMESPACE(std)string& fileName_
+ );
+
+ // Expected token / not token
+ MismatchedTokenException(
+ const ANTLR_USE_NAMESPACE(std)vector<ANTLR_USE_NAMESPACE(std)string>& tokenNames_,
+ RefToken token_,
+ int expecting_,
+ bool matchNot,
+ const ANTLR_USE_NAMESPACE(std)string& fileName_
+ );
+
+ // Expected BitSet / not BitSet
+ MismatchedTokenException(
+ const ANTLR_USE_NAMESPACE(std)vector<ANTLR_USE_NAMESPACE(std)string>& tokenNames_,
+ RefToken token_,
+ BitSet set_,
+ bool matchNot,
+ const ANTLR_USE_NAMESPACE(std)string& fileName_
+ );
+ ~MismatchedTokenException() throw() {}
+
+ /**
+ * @deprecated As of ANTLR 2.7.0
+ */
+ ANTLR_USE_NAMESPACE(std)string getErrorMessage() const;
+
+ /**
+ * Returns the error message that happened on the line/col given.
+ * Copied from toString().
+ */
+ ANTLR_USE_NAMESPACE(std)string getMessage() const;
+
+private:
+ ANTLR_USE_NAMESPACE(std)string tokenName(int tokenType) const;
+
+public:
+ ANTLR_USE_NAMESPACE(std)string toString() const;
+
+};
+
+ANTLR_END_NAMESPACE
+
+#endif //INC_MismatchedTokenException_hpp__
diff --git a/poxml/antlr/antlr/NoViableAltException.hpp b/poxml/antlr/antlr/NoViableAltException.hpp
new file mode 100644
index 00000000..f85bcf96
--- /dev/null
+++ b/poxml/antlr/antlr/NoViableAltException.hpp
@@ -0,0 +1,71 @@
+#ifndef INC_NoViableAltException_hpp__
+#define INC_NoViableAltException_hpp__
+
+/**
+ * <b>SOFTWARE RIGHTS</b>
+ * <p>
+ * ANTLR 2.6.0 MageLang Insitute, 1999
+ * <p>
+ * We reserve no legal rights to the ANTLR--it is fully in the
+ * public domain. An individual or company may do whatever
+ * they wish with source code distributed with ANTLR or the
+ * code generated by ANTLR, including the incorporation of
+ * ANTLR, or its output, into commerical software.
+ * <p>
+ * We encourage users to develop software with ANTLR. However,
+ * we do ask that credit is given to us for developing
+ * ANTLR. By "credit", we mean that if you use ANTLR or
+ * incorporate any source code into one of your programs
+ * (commercial product, research project, or otherwise) that
+ * you acknowledge this fact somewhere in the documentation,
+ * research report, etc... If you like ANTLR and have
+ * developed a nice tool with the output, please mention that
+ * you developed it using ANTLR. In addition, we ask that the
+ * headers remain intact in our source code. As long as these
+ * guidelines are kept, we expect to continue enhancing this
+ * system and expect to make other tools available as they are
+ * completed.
+ * <p>
+ * The ANTLR gang:
+ * @version ANTLR 2.6.0 MageLang Insitute, 1999
+ * @author Terence Parr, <a href=http://www.MageLang.com>MageLang Institute</a>
+ * @author <br>John Lilley, <a href=http://www.Empathy.com>Empathy Software</a>
+ * @author <br><a href="mailto:pete@yamuna.demon.co.uk">Pete Wells</a>
+ */
+
+#include "antlr/config.hpp"
+#include "antlr/RecognitionException.hpp"
+#include "antlr/Token.hpp"
+#include "antlr/AST.hpp"
+
+ANTLR_BEGIN_NAMESPACE(antlr)
+
+class NoViableAltException : public RecognitionException {
+public:
+ const RefToken token;
+ const RefAST node; // handles parsing and treeparsing
+
+ NoViableAltException(RefAST t);
+
+ NoViableAltException(RefToken t,const ANTLR_USE_NAMESPACE(std)string& fileName_);
+ ~NoViableAltException() throw() {}
+
+ /**
+ * @deprecated As of ANTLR 2.7.0
+ */
+ ANTLR_USE_NAMESPACE(std)string getErrorMessage() const;
+
+ /**
+ * Returns a clean error message (no line number/column information)
+ */
+ ANTLR_USE_NAMESPACE(std)string getMessage() const;
+
+ /**
+ * Returns a string representation of this exception.
+ */
+ virtual ANTLR_USE_NAMESPACE(std)string toString() const;
+};
+
+ANTLR_END_NAMESPACE
+
+#endif //INC_NoViableAltException_hpp__
diff --git a/poxml/antlr/antlr/NoViableAltForCharException.hpp b/poxml/antlr/antlr/NoViableAltForCharException.hpp
new file mode 100644
index 00000000..756e9c7f
--- /dev/null
+++ b/poxml/antlr/antlr/NoViableAltForCharException.hpp
@@ -0,0 +1,64 @@
+#ifndef INC_NoViableAltForCharException_hpp__
+#define INC_NoViableAltForCharException_hpp__
+
+/**
+ * <b>SOFTWARE RIGHTS</b>
+ * <p>
+ * ANTLR 2.6.0 MageLang Institute
+ * <p>
+ * We reserve no legal rights to the ANTLR--it is fully in the
+ * public domain. An individual or company may do whatever
+ * they wish with source code distributed with ANTLR or the
+ * code generated by ANTLR, including the incorporation of
+ * ANTLR, or its output, into commerical software.
+ * <p>
+ * We encourage users to develop software with ANTLR. However,
+ * we do ask that credit is given to us for developing
+ * ANTLR. By "credit", we mean that if you use ANTLR or
+ * incorporate any source code into one of your programs
+ * (commercial product, research project, or otherwise) that
+ * you acknowledge this fact somewhere in the documentation,
+ * research report, etc... If you like ANTLR and have
+ * developed a nice tool with the output, please mention that
+ * you developed it using ANTLR. In addition, we ask that the
+ * headers remain intact in our source code. As long as these
+ * guidelines are kept, we expect to continue enhancing this
+ * system and expect to make other tools available as they are
+ * completed.
+ * <p>
+ * The ANTLR gang:
+ * @version ANTLR 2.6.0 MageLang Institute
+ * @author Terence Parr, <a href=http://www.MageLang.com>MageLang Institute</a>
+ * @author <br>John Lilley, <a href=http://www.Empathy.com>Empathy Software</a>
+ * @author <br><a href="mailto:pete@yamuna.demon.co.uk">Pete Wells</a>
+ */
+
+#include "antlr/config.hpp"
+#include "antlr/RecognitionException.hpp"
+#include "antlr/CharScanner.hpp"
+
+ANTLR_BEGIN_NAMESPACE(antlr)
+
+class NoViableAltForCharException : public RecognitionException {
+public:
+ int foundChar;
+
+ NoViableAltForCharException(int c, CharScanner* scanner);
+
+ NoViableAltForCharException(int c, const ANTLR_USE_NAMESPACE(std)string& fileName_, int line_);
+ ~NoViableAltForCharException() throw() {}
+
+ /**
+ * @deprecated As of ANTLR 2.7.0
+ */
+ virtual ANTLR_USE_NAMESPACE(std)string getErrorMessage() const;
+
+ /**
+ * Returns a clean error message (no line number/column information)
+ */
+ virtual ANTLR_USE_NAMESPACE(std)string getMessage() const;
+};
+
+ANTLR_END_NAMESPACE
+
+#endif //INC_NoViableAltForCharException_hpp__
diff --git a/poxml/antlr/antlr/Parser.hpp b/poxml/antlr/antlr/Parser.hpp
new file mode 100644
index 00000000..767953d3
--- /dev/null
+++ b/poxml/antlr/antlr/Parser.hpp
@@ -0,0 +1,213 @@
+#ifndef INC_Parser_hpp__
+#define INC_Parser_hpp__
+
+/**
+ * <b>SOFTWARE RIGHTS</b>
+ * <p>
+ * ANTLR 2.6.0 MageLang Insitute, 1999
+ * <p>
+ * We reserve no legal rights to the ANTLR--it is fully in the
+ * public domain. An individual or company may do whatever
+ * they wish with source code distributed with ANTLR or the
+ * code generated by ANTLR, including the incorporation of
+ * ANTLR, or its output, into commerical software.
+ * <p>
+ * We encourage users to develop software with ANTLR. However,
+ * we do ask that credit is given to us for developing
+ * ANTLR. By "credit", we mean that if you use ANTLR or
+ * incorporate any source code into one of your programs
+ * (commercial product, research project, or otherwise) that
+ * you acknowledge this fact somewhere in the documentation,
+ * research report, etc... If you like ANTLR and have
+ * developed a nice tool with the output, please mention that
+ * you developed it using ANTLR. In addition, we ask that the
+ * headers remain intact in our source code. As long as these
+ * guidelines are kept, we expect to continue enhancing this
+ * system and expect to make other tools available as they are
+ * completed.
+ * <p>
+ * The ANTLR gang:
+ * @version ANTLR 2.6.0 MageLang Insitute, 1999
+ * @author Terence Parr, <a href=http://www.MageLang.com>MageLang Institute</a>
+ * @author <br>John Lilley, <a href=http://www.Empathy.com>Empathy Software</a>
+ * @author <br><a href="mailto:pete@yamuna.demon.co.uk">Pete Wells</a>
+ */
+
+#include "antlr/config.hpp"
+#include "antlr/BitSet.hpp"
+#include "antlr/TokenBuffer.hpp"
+#include "antlr/RecognitionException.hpp"
+#include "antlr/ASTFactory.hpp"
+#include "antlr/ParserSharedInputState.hpp"
+
+ANTLR_BEGIN_NAMESPACE(antlr)
+
+/**A generic ANTLR parser (LL(k) for k>=1) containing a bunch of
+ * utility routines useful at any lookahead depth. We distinguish between
+ * the LL(1) and LL(k) parsers because of efficiency. This may not be
+ * necessary in the near future.
+ *
+ * Each parser object contains the state of the parse including a lookahead
+ * cache (the form of which is determined by the subclass), whether or
+ * not the parser is in guess mode, where tokens come from, etc...
+ *
+ * <p>
+ * During <b>guess</b> mode, the current lookahead token(s) and token type(s)
+ * cache must be saved because the token stream may not have been informed
+ * to save the token (via <tt>mark</tt>) before the <tt>try</tt> block.
+ * Guessing is started by:
+ * <ol>
+ * <li>saving the lookahead cache.
+ * <li>marking the current position in the TokenBuffer.
+ * <li>increasing the guessing level.
+ * </ol>
+ *
+ * After guessing, the parser state is restored by:
+ * <ol>
+ * <li>restoring the lookahead cache.
+ * <li>rewinding the TokenBuffer.
+ * <li>decreasing the guessing level.
+ * </ol>
+ *
+ * @see antlr.Token
+ * @see antlr.TokenBuffer
+ * @see antlr.TokenStream
+ * @see antlr.LL1Parser
+ * @see antlr.LLkParser
+ */
+
+extern bool DEBUG_PARSER;
+
+class Parser {
+protected:
+ ParserSharedInputState inputState;
+
+ /** Nesting level of registered handlers */
+ // int exceptionLevel;
+
+ /** Table of token type to token names */
+ ANTLR_USE_NAMESPACE(std)vector<ANTLR_USE_NAMESPACE(std)string> tokenNames;
+ /** AST return value for a rule is squirreled away here */
+ RefAST returnAST;
+ /** AST support code; parser and treeparser delegate to this object */
+ ASTFactory astFactory;
+
+// Parser();
+
+ Parser(TokenBuffer& input_);
+ Parser(TokenBuffer* input_);
+
+ Parser(const ParserSharedInputState& state);
+
+public:
+ virtual ~Parser();
+
+protected:
+ void setTokenNames(const char** tokenNames_);
+
+public:
+ /**Get another token object from the token stream */
+ virtual void consume()=0;
+
+ /** Consume tokens until one matches the given token */
+ void consumeUntil(int tokenType);
+
+ /** Consume tokens until one matches the given token set */
+ void consumeUntil(const BitSet& set);
+
+ /** Get the AST return value squirreled away in the parser */
+ RefAST getAST();
+
+ ASTFactory& getASTFactory();
+
+ ANTLR_USE_NAMESPACE(std)string getFilename() const;
+
+ virtual ParserSharedInputState getInputState() const;
+
+ ANTLR_USE_NAMESPACE(std)string getTokenName(int num) const;
+ ANTLR_USE_NAMESPACE(std)vector<ANTLR_USE_NAMESPACE(std)string> getTokenNames() const;
+
+ /** Return the token type of the ith token of lookahead where i=1
+ * is the current token being examined by the parser (i.e., it
+ * has not been matched yet).
+ */
+ virtual int LA(int i)=0;
+
+ /**Return the ith token of lookahead */
+ virtual RefToken LT(int i)=0;
+
+ // Forwarded to TokenBuffer
+ virtual int mark();
+
+ /**Make sure current lookahead symbol matches token type <tt>t</tt>.
+ * Throw an exception upon mismatch, which is catch by either the
+ * error handler or by the syntactic predicate.
+ */
+ void match(int t);
+
+ /**Make sure current lookahead symbol matches the given set
+ * Throw an exception upon mismatch, which is catch by either the
+ * error handler or by the syntactic predicate.
+ */
+ void match(const BitSet& b);
+
+ void matchNot(int t);
+
+ static void panic();
+
+ /** Parser error-reporting function can be overridden in subclass */
+ virtual void reportError(const RecognitionException& ex);
+
+ /** Parser error-reporting function can be overridden in subclass */
+ virtual void reportError(const ANTLR_USE_NAMESPACE(std)string& s);
+
+ /** Parser warning-reporting function can be overridden in subclass */
+ virtual void reportWarning(const ANTLR_USE_NAMESPACE(std)string& s);
+
+ virtual void rewind(int pos);
+
+ /** Set the object used to generate ASTs */
+// void setASTFactory(ASTFactory astFactory_);
+
+ /** Specify the type of node to create during tree building */
+ void setASTNodeFactory(ASTFactory::factory_type factory);
+
+ void setFilename(const ANTLR_USE_NAMESPACE(std)string& f);
+
+ void setInputState(ParserSharedInputState state);
+
+ /** Set or change the input token buffer */
+// void setTokenBuffer(TokenBuffer<Token>* t);
+
+ virtual void traceIndent();
+ virtual void traceIn(const ANTLR_USE_NAMESPACE(std)string& rname);
+ virtual void traceOut(const ANTLR_USE_NAMESPACE(std)string& rname);
+protected:
+ int traceDepth; // used to keep track of the indentation for the trace
+
+protected:
+ /** Utility class which allows tracing to work even when exceptions are
+ * thrown.
+ */
+ class Tracer {
+ private:
+ Parser* parser;
+ ANTLR_USE_NAMESPACE(std)string text;
+ public:
+ Tracer(Parser* p,const ANTLR_USE_NAMESPACE(std)string& t)
+ : parser(p), text(t) { parser->traceIn(text); }
+ ~Tracer()
+ { parser->traceOut(text); }
+ private:
+ Tracer(const Tracer&); // undefined
+ const Tracer& operator=(const Tracer&); // undefined
+ };
+
+private:
+ Parser(const Parser&); // undefined
+ const Parser& operator=(const Parser&); // undefined
+};
+
+ANTLR_END_NAMESPACE
+
+#endif //INC_Parser_hpp__
diff --git a/poxml/antlr/antlr/ParserSharedInputState.hpp b/poxml/antlr/antlr/ParserSharedInputState.hpp
new file mode 100644
index 00000000..b5599954
--- /dev/null
+++ b/poxml/antlr/antlr/ParserSharedInputState.hpp
@@ -0,0 +1,42 @@
+#ifndef INC_ParserSharedInputState_hpp__
+#define INC_ParserSharedInputState_hpp__
+
+#include "antlr/config.hpp"
+#include "antlr/TokenBuffer.hpp"
+#include "antlr/RefCount.hpp"
+#include <string>
+
+ANTLR_BEGIN_NAMESPACE(antlr)
+
+/** This object contains the data associated with an
+ * input stream of tokens. Multiple parsers
+ * share a single ParserSharedInputState to parse
+ * the same stream of tokens.
+ */
+class ParserInputState {
+public:
+ ParserInputState(TokenBuffer* input_);
+ ParserInputState(TokenBuffer& input_);
+ ~ParserInputState();
+
+public:
+ /** Are we guessing (guessing>0)? */
+ int guessing; //= 0;
+ /** What file (if known) caused the problem? */
+ ANTLR_USE_NAMESPACE(std)string filename;
+ TokenBuffer& getInput();
+private:
+ /** Where to get token objects */
+ TokenBuffer* input;
+ bool inputResponsible;
+
+ // we don't want these:
+ ParserInputState(const ParserInputState&);
+ ParserInputState& operator=(const ParserInputState&);
+};
+
+typedef RefCount<ParserInputState> ParserSharedInputState;
+
+ANTLR_END_NAMESPACE
+
+#endif //INC_ParserSharedInputState_hpp__
diff --git a/poxml/antlr/antlr/RecognitionException.hpp b/poxml/antlr/antlr/RecognitionException.hpp
new file mode 100644
index 00000000..c6439111
--- /dev/null
+++ b/poxml/antlr/antlr/RecognitionException.hpp
@@ -0,0 +1,78 @@
+#ifndef INC_RecognitionException_hpp__
+#define INC_RecognitionException_hpp__
+
+/**
+ * <b>SOFTWARE RIGHTS</b>
+ * <p>
+ * ANTLR 2.6.0 MageLang Insitute, 1999
+ * <p>
+ * We reserve no legal rights to the ANTLR--it is fully in the
+ * public domain. An individual or company may do whatever
+ * they wish with source code distributed with ANTLR or the
+ * code generated by ANTLR, including the incorporation of
+ * ANTLR, or its output, into commerical software.
+ * <p>
+ * We encourage users to develop software with ANTLR. However,
+ * we do ask that credit is given to us for developing
+ * ANTLR. By "credit", we mean that if you use ANTLR or
+ * incorporate any source code into one of your programs
+ * (commercial product, research project, or otherwise) that
+ * you acknowledge this fact somewhere in the documentation,
+ * research report, etc... If you like ANTLR and have
+ * developed a nice tool with the output, please mention that
+ * you developed it using ANTLR. In addition, we ask that the
+ * headers remain intact in our source code. As long as these
+ * guidelines are kept, we expect to continue enhancing this
+ * system and expect to make other tools available as they are
+ * completed.
+ * <p>
+ * The ANTLR gang:
+ * @version ANTLR 2.6.0 MageLang Insitute, 1999
+ * @author Terence Parr, <a href=http://www.MageLang.com>MageLang Institute</a>
+ * @author <br>John Lilley, <a href=http://www.Empathy.com>Empathy Software</a>
+ * @author <br><a href="mailto:pete@yamuna.demon.co.uk">Pete Wells</a>
+ */
+
+#include "antlr/config.hpp"
+#include "antlr/ANTLRException.hpp"
+
+ANTLR_BEGIN_NAMESPACE(antlr)
+
+class RecognitionException : public ANTLRException {
+public:
+ ANTLR_USE_NAMESPACE(std)string fileName; // not used by treeparsers
+ int line; // not used by treeparsers
+ int column; // not used by treeparsers
+
+ RecognitionException();
+
+ RecognitionException(const ANTLR_USE_NAMESPACE(std)string& s);
+
+ RecognitionException(const ANTLR_USE_NAMESPACE(std)string& s,const ANTLR_USE_NAMESPACE(std)string& fileName_,int line);
+ RecognitionException(const ANTLR_USE_NAMESPACE(std)string& s,const ANTLR_USE_NAMESPACE(std)string& fileName_,int line,int column);
+ ~RecognitionException() throw() {}
+
+ /**
+ * @return the column number that this exception happened on.
+ * @author Shawn P. Vincent (svincent@svincent.com)
+ */
+ virtual int getColumn() const;
+ /**
+ * @deprecated As of ANTLR 2.7.0
+ */
+ virtual ANTLR_USE_NAMESPACE(std)string getErrorMessage() const;
+protected:
+ virtual ANTLR_USE_NAMESPACE(std)string getFileLineString() const;
+public:
+ virtual ANTLR_USE_NAMESPACE(std)string getFilename() const;
+ /**
+ * @return the line number that this exception happened on.
+ * @author Shawn P. Vincent (svincent@svincent.com)
+ */
+ virtual int getLine() const;
+ virtual ANTLR_USE_NAMESPACE(std)string toString() const;
+};
+
+ANTLR_END_NAMESPACE
+
+#endif //INC_RecognitionException_hpp__
diff --git a/poxml/antlr/antlr/RefCount.hpp b/poxml/antlr/antlr/RefCount.hpp
new file mode 100644
index 00000000..9306576b
--- /dev/null
+++ b/poxml/antlr/antlr/RefCount.hpp
@@ -0,0 +1,87 @@
+#ifndef INC_RefCount_hpp__
+#define INC_RefCount_hpp__
+
+/**
+ * <b>SOFTWARE RIGHTS</b>
+ * <p>
+ * ANTLR 2.6.0 MageLang Insitute, 1999
+ * <p>
+ * We reserve no legal rights to the ANTLR--it is fully in the
+ * public domain. An individual or company may do whatever
+ * they wish with source code distributed with ANTLR or the
+ * code generated by ANTLR, including the incorporation of
+ * ANTLR, or its output, into commerical software.
+ * <p>
+ * We encourage users to develop software with ANTLR. However,
+ * we do ask that credit is given to us for developing
+ * ANTLR. By "credit", we mean that if you use ANTLR or
+ * incorporate any source code into one of your programs
+ * (commercial product, research project, or otherwise) that
+ * you acknowledge this fact somewhere in the documentation,
+ * research report, etc... If you like ANTLR and have
+ * developed a nice tool with the output, please mention that
+ * you developed it using ANTLR. In addition, we ask that the
+ * headers remain intact in our source code. As long as these
+ * guidelines are kept, we expect to continue enhancing this
+ * system and expect to make other tools available as they are
+ * completed.
+ * <p>
+ * The ANTLR gang:
+ * @version ANTLR 2.6.0 MageLang Insitute, 1999
+ * @author Terence Parr, <a href=http://www.MageLang.com>MageLang Institute</a>
+ * @author <br>John Lilley, <a href=http://www.Empathy.com>Empathy Software</a>
+ * @author <br><a href="mailto:pete@yamuna.demon.co.uk">Pete Wells</a>
+ */
+
+#include "antlr/config.hpp"
+
+ANTLR_BEGIN_NAMESPACE(antlr)
+
+template<class T>
+class RefCount {
+private:
+ struct Ref {
+ T* const ptr;
+ unsigned int count;
+
+ Ref(T* p) : ptr(p), count(1) {}
+ ~Ref() {delete ptr;}
+ Ref* increment() {++count;return this;}
+ bool decrement() {return (--count==0);}
+ private:
+ Ref(const Ref&);
+ Ref& operator=(const Ref&);
+ }* ref;
+
+public:
+ explicit RefCount(T* p=0)
+ : ref(p ? new Ref(p) : 0)
+ {
+ }
+ RefCount(const RefCount<T>& other)
+ : ref(other.ref ? other.ref->increment() : 0)
+ {
+ }
+ ~RefCount()
+ {
+ if (ref && ref->decrement()) delete ref;
+ }
+ RefCount<T>& operator=(const RefCount<T>& other)
+ {
+ Ref* tmp=other.ref ? other.ref->increment() : 0;
+ if (ref && ref->decrement()) delete ref;
+ ref=tmp;
+ return *this;
+ }
+
+ operator T* () const
+ { return ref ? ref->ptr : 0; }
+ T* operator->() const
+ { return ref ? ref->ptr : 0; }
+ T* get() const
+ { return ref ? ref->ptr : 0; }
+};
+
+ANTLR_END_NAMESPACE
+
+#endif //INC_RefCount_hpp__
diff --git a/poxml/antlr/antlr/SemanticException.hpp b/poxml/antlr/antlr/SemanticException.hpp
new file mode 100644
index 00000000..3f1a9447
--- /dev/null
+++ b/poxml/antlr/antlr/SemanticException.hpp
@@ -0,0 +1,52 @@
+#ifndef INC_SemanticException_hpp__
+#define INC_SemanticException_hpp__
+
+/**
+ * <b>SOFTWARE RIGHTS</b>
+ * <p>
+ * ANTLR 2.6.0 MageLang Insitute, 1999
+ * <p>
+ * We reserve no legal rights to the ANTLR--it is fully in the
+ * public domain. An individual or company may do whatever
+ * they wish with source code distributed with ANTLR or the
+ * code generated by ANTLR, including the incorporation of
+ * ANTLR, or its output, into commerical software.
+ * <p>
+ * We encourage users to develop software with ANTLR. However,
+ * we do ask that credit is given to us for developing
+ * ANTLR. By "credit", we mean that if you use ANTLR or
+ * incorporate any source code into one of your programs
+ * (commercial product, research project, or otherwise) that
+ * you acknowledge this fact somewhere in the documentation,
+ * research report, etc... If you like ANTLR and have
+ * developed a nice tool with the output, please mention that
+ * you developed it using ANTLR. In addition, we ask that the
+ * headers remain intact in our source code. As long as these
+ * guidelines are kept, we expect to continue enhancing this
+ * system and expect to make other tools available as they are
+ * completed.
+ * <p>
+ * The ANTLR gang:
+ * @version ANTLR 2.6.0 MageLang Insitute, 1999
+ * @author Terence Parr, <a href=http://www.MageLang.com>MageLang Institute</a>
+ * @author <br>John Lilley, <a href=http://www.Empathy.com>Empathy Software</a>
+ * @author <br><a href="mailto:pete@yamuna.demon.co.uk">Pete Wells</a>
+ */
+
+#include "antlr/config.hpp"
+#include "antlr/RecognitionException.hpp"
+
+ANTLR_BEGIN_NAMESPACE(antlr)
+
+class SemanticException : public RecognitionException {
+public:
+ SemanticException(const ANTLR_USE_NAMESPACE(std)string& s)
+ : RecognitionException(s) {}
+ SemanticException(const ANTLR_USE_NAMESPACE(std)string& s,const ANTLR_USE_NAMESPACE(std)string& fileName_,int line_)
+ : RecognitionException(s,fileName_,line_) {}
+ ~SemanticException() throw() {}
+};
+
+ANTLR_END_NAMESPACE
+
+#endif //INC_SemanticException_hpp__
diff --git a/poxml/antlr/antlr/String.hpp b/poxml/antlr/antlr/String.hpp
new file mode 100644
index 00000000..5fac82d6
--- /dev/null
+++ b/poxml/antlr/antlr/String.hpp
@@ -0,0 +1,47 @@
+#ifndef INC_String_hpp__
+#define INC_String_hpp__
+
+/**
+ * <b>SOFTWARE RIGHTS</b>
+ * <p>
+ * ANTLR 2.6.0 MageLang Insitute, 1999
+ * <p>
+ * We reserve no legal rights to the ANTLR--it is fully in the
+ * public domain. An individual or company may do whatever
+ * they wish with source code distributed with ANTLR or the
+ * code generated by ANTLR, including the incorporation of
+ * ANTLR, or its output, into commerical software.
+ * <p>
+ * We encourage users to develop software with ANTLR. However,
+ * we do ask that credit is given to us for developing
+ * ANTLR. By "credit", we mean that if you use ANTLR or
+ * incorporate any source code into one of your programs
+ * (commercial product, research project, or otherwise) that
+ * you acknowledge this fact somewhere in the documentation,
+ * research report, etc... If you like ANTLR and have
+ * developed a nice tool with the output, please mention that
+ * you developed it using ANTLR. In addition, we ask that the
+ * headers remain intact in our source code. As long as these
+ * guidelines are kept, we expect to continue enhancing this
+ * system and expect to make other tools available as they are
+ * completed.
+ * <p>
+ * The ANTLR gang:
+ * @version ANTLR 2.6.0 MageLang Insitute, 1999
+ * @author Terence Parr, <a href=http://www.MageLang.com>MageLang Institute</a>
+ * @author <br>John Lilley, <a href=http://www.Empathy.com>Empathy Software</a>
+ * @author <br><a href="mailto:pete@yamuna.demon.co.uk">Pete Wells</a>
+ */
+
+#include "antlr/config.hpp"
+#include <string>
+
+ANTLR_BEGIN_NAMESPACE(antlr)
+
+ANTLR_USE_NAMESPACE(std)string operator+(const ANTLR_USE_NAMESPACE(std)string& lhs,int rhs);
+
+ANTLR_USE_NAMESPACE(std)string charName(int ch);
+
+ANTLR_END_NAMESPACE
+
+#endif //INC_String_hpp__
diff --git a/poxml/antlr/antlr/Token.hpp b/poxml/antlr/antlr/Token.hpp
new file mode 100644
index 00000000..b85551c3
--- /dev/null
+++ b/poxml/antlr/antlr/Token.hpp
@@ -0,0 +1,106 @@
+#ifndef INC_Token_hpp__
+#define INC_Token_hpp__
+
+/**
+ * <b>SOFTWARE RIGHTS</b>
+ * <p>
+ * ANTLR 2.6.0 MageLang Insitute, 1999
+ * <p>
+ * We reserve no legal rights to the ANTLR--it is fully in the
+ * public domain. An individual or company may do whatever
+ * they wish with source code distributed with ANTLR or the
+ * code generated by ANTLR, including the incorporation of
+ * ANTLR, or its output, into commerical software.
+ * <p>
+ * We encourage users to develop software with ANTLR. However,
+ * we do ask that credit is given to us for developing
+ * ANTLR. By "credit", we mean that if you use ANTLR or
+ * incorporate any source code into one of your programs
+ * (commercial product, research project, or otherwise) that
+ * you acknowledge this fact somewhere in the documentation,
+ * research report, etc... If you like ANTLR and have
+ * developed a nice tool with the output, please mention that
+ * you developed it using ANTLR. In addition, we ask that the
+ * headers remain intact in our source code. As long as these
+ * guidelines are kept, we expect to continue enhancing this
+ * system and expect to make other tools available as they are
+ * completed.
+ * <p>
+ * The ANTLR gang:
+ * @version ANTLR 2.6.0 MageLang Insitute, 1999
+ * @author Terence Parr, <a href=http://www.MageLang.com>MageLang Institute</a>
+ * @author <br>John Lilley, <a href=http://www.Empathy.com>Empathy Software</a>
+ * @author <br><a href="mailto:pete@yamuna.demon.co.uk">Pete Wells</a>
+ */
+
+#include "antlr/config.hpp"
+#include "antlr/RefCount.hpp"
+#include <string>
+
+ANTLR_BEGIN_NAMESPACE(antlr)
+
+/** A token is minimally a token type. Subclasses can add the text matched
+ * for the token and line info.
+ */
+
+class Token;
+typedef RefCount<Token> RefToken;
+
+class Token {
+public:
+ // constants
+#ifndef NO_STATIC_CONSTS
+ static const int MIN_USER_TYPE = 4;
+ static const int NULL_TREE_LOOKAHEAD = 3;
+ static const int INVALID_TYPE = 0;
+ static const int EOF_TYPE = 1;
+ static const int SKIP = -1;
+#else
+ enum {
+ MIN_USER_TYPE = 4,
+ NULL_TREE_LOOKAHEAD = 3,
+ INVALID_TYPE = 0,
+ EOF_TYPE = 1,
+ SKIP = -1
+ };
+#endif
+
+ // each Token has at least a token type
+ int type; //=INVALID_TYPE;
+
+public:
+ // the illegal token object
+ static RefToken badToken; // = new Token(INVALID_TYPE, "<no text>");
+
+ Token();
+ Token(int t);
+ Token(int t, const ANTLR_USE_NAMESPACE(std)string& txt);
+
+ virtual int getColumn() const;
+ virtual int getLine() const;
+ virtual ANTLR_USE_NAMESPACE(std)string getText() const;
+ virtual int getType() const;
+
+ virtual void setColumn(int c);
+
+ virtual void setLine(int l);
+ virtual void setText(const ANTLR_USE_NAMESPACE(std)string& t);
+ virtual void setType(int t);
+
+ virtual ANTLR_USE_NAMESPACE(std)string toString() const;
+
+ virtual ~Token();
+private:
+ Token(const Token&);
+ const Token& operator=(const Token&);
+};
+
+#ifdef NEEDS_OPERATOR_LESS_THAN
+inline operator<(RefToken l,RefToken r); //{return true;}
+#endif
+
+extern RefToken nullToken;
+
+ANTLR_END_NAMESPACE
+
+#endif //INC_Token_hpp__
diff --git a/poxml/antlr/antlr/TokenBuffer.hpp b/poxml/antlr/antlr/TokenBuffer.hpp
new file mode 100644
index 00000000..b7c1b25f
--- /dev/null
+++ b/poxml/antlr/antlr/TokenBuffer.hpp
@@ -0,0 +1,141 @@
+#ifndef INC_TokenBuffer_hpp__
+#define INC_TokenBuffer_hpp__
+
+/**
+ * <b>SOFTWARE RIGHTS</b>
+ * <p>
+ * ANTLR 2.6.0 MageLang Insitute, 1999
+ * <p>
+ * We reserve no legal rights to the ANTLR--it is fully in the
+ * public domain. An individual or company may do whatever
+ * they wish with source code distributed with ANTLR or the
+ * code generated by ANTLR, including the incorporation of
+ * ANTLR, or its output, into commerical software.
+ * <p>
+ * We encourage users to develop software with ANTLR. However,
+ * we do ask that credit is given to us for developing
+ * ANTLR. By "credit", we mean that if you use ANTLR or
+ * incorporate any source code into one of your programs
+ * (commercial product, research project, or otherwise) that
+ * you acknowledge this fact somewhere in the documentation,
+ * research report, etc... If you like ANTLR and have
+ * developed a nice tool with the output, please mention that
+ * you developed it using ANTLR. In addition, we ask that the
+ * headers remain intact in our source code. As long as these
+ * guidelines are kept, we expect to continue enhancing this
+ * system and expect to make other tools available as they are
+ * completed.
+ * <p>
+ * The ANTLR gang:
+ * @version ANTLR 2.6.0 MageLang Insitute, 1999
+ * @author Terence Parr, <a href=http://www.MageLang.com>MageLang Institute</a>
+ * @author <br>John Lilley, <a href=http://www.Empathy.com>Empathy Software</a>
+ * @author <br><a href="mailto:pete@yamuna.demon.co.uk">Pete Wells</a>
+ */
+
+#include "antlr/config.hpp"
+#include "antlr/TokenStream.hpp"
+#include "antlr/CircularQueue.hpp"
+
+ANTLR_BEGIN_NAMESPACE(antlr)
+
+/**A Stream of Token objects fed to the parser from a TokenStream that can
+ * be rewound via mark()/rewind() methods.
+ * <p>
+ * A dynamic array is used to buffer up all the input tokens. Normally,
+ * "k" tokens are stored in the buffer. More tokens may be stored during
+ * guess mode (testing syntactic predicate), or when LT(i>k) is referenced.
+ * Consumption of tokens is deferred. In other words, reading the next
+ * token is not done by conume(), but deferred until needed by LA or LT.
+ * <p>
+ *
+ * @see antlr.Token
+ * @see antlr.TokenStream
+ * @see antlr.TokenQueue
+ */
+class TokenBuffer {
+protected:
+ // Token source
+ TokenStream& input;
+
+private:
+ // Number of active markers
+ int nMarkers;
+
+ // Additional offset used when markers are active
+ int markerOffset;
+
+ // Number of calls to consume() since last LA() or LT() call
+ int numToConsume;
+
+ // Circular queue
+ CircularQueue<RefToken> queue;
+
+public:
+ /** Create a token buffer */
+ TokenBuffer(TokenStream& input_);
+
+ /** Mark another token for deferred consumption */
+ void consume();
+
+private:
+ /** Ensure that the token buffer is sufficiently full */
+ void fill(int amount);
+
+public:
+ /** Get a lookahead token value */
+ int LA(int i);
+
+ /** Get a lookahead token */
+ RefToken LT(int i);
+
+ /**Return an integer marker that can be used to rewind the buffer to
+ * its current state.
+ */
+ int mark();
+
+ /**Rewind the token buffer to a marker.
+ * @param mark Marker returned previously from mark()
+ */
+ void rewind(int mark);
+
+private:
+ /** Sync up deferred consumption */
+ void syncConsume();
+
+private:
+ TokenBuffer(const TokenBuffer& other);
+ const TokenBuffer& operator=(const TokenBuffer& other);
+public:
+// virtual ~TokenBuffer() {}
+};
+
+/** Sync up deferred consumption */
+inline void TokenBuffer::syncConsume()
+{
+#ifdef OLD_CODE
+ while (numToConsume > 0) {
+ if (nMarkers > 0) {
+ // guess mode -- leave leading tokens and bump offset.
+ markerOffset++;
+ } else {
+ // normal mode -- remove first token
+ queue.removeFirst();
+ }
+ numToConsume--;
+ }
+#endif
+
+ if (numToConsume > 0) {
+ if (nMarkers > 0) {
+ markerOffset += numToConsume;
+ } else {
+ queue.removeItems( numToConsume );
+ }
+ numToConsume = 0;
+ }
+}
+
+ANTLR_END_NAMESPACE
+
+#endif //INC_TokenBuffer_hpp__
diff --git a/poxml/antlr/antlr/TokenStream.hpp b/poxml/antlr/antlr/TokenStream.hpp
new file mode 100644
index 00000000..e8436419
--- /dev/null
+++ b/poxml/antlr/antlr/TokenStream.hpp
@@ -0,0 +1,54 @@
+#ifndef INC_TokenStream_hpp__
+#define INC_TokenStream_hpp__
+
+/**
+ * <b>SOFTWARE RIGHTS</b>
+ * <p>
+ * ANTLR 2.6.0 MageLang Insitute, 1999
+ * <p>
+ * We reserve no legal rights to the ANTLR--it is fully in the
+ * public domain. An individual or company may do whatever
+ * they wish with source code distributed with ANTLR or the
+ * code generated by ANTLR, including the incorporation of
+ * ANTLR, or its output, into commerical software.
+ * <p>
+ * We encourage users to develop software with ANTLR. However,
+ * we do ask that credit is given to us for developing
+ * ANTLR. By "credit", we mean that if you use ANTLR or
+ * incorporate any source code into one of your programs
+ * (commercial product, research project, or otherwise) that
+ * you acknowledge this fact somewhere in the documentation,
+ * research report, etc... If you like ANTLR and have
+ * developed a nice tool with the output, please mention that
+ * you developed it using ANTLR. In addition, we ask that the
+ * headers remain intact in our source code. As long as these
+ * guidelines are kept, we expect to continue enhancing this
+ * system and expect to make other tools available as they are
+ * completed.
+ * <p>
+ * The ANTLR gang:
+ * @version ANTLR 2.6.0 MageLang Insitute, 1999
+ * @author Terence Parr, <a href=http://www.MageLang.com>MageLang Institute</a>
+ * @author <br>John Lilley, <a href=http://www.Empathy.com>Empathy Software</a>
+ * @author <br><a href="mailto:pete@yamuna.demon.co.uk">Pete Wells</a>
+ */
+
+/**This interface allows any object to pretend it is a stream
+ * of tokens.
+ * @author Terence Parr, MageLang Institute
+ */
+
+#include "antlr/config.hpp"
+#include "antlr/Token.hpp"
+
+ANTLR_BEGIN_NAMESPACE(antlr)
+
+class TokenStream {
+public:
+ virtual RefToken nextToken()=0;
+ virtual ~TokenStream() {}
+};
+
+ANTLR_END_NAMESPACE
+
+#endif //INC_TokenStream_hpp__
diff --git a/poxml/antlr/antlr/TokenStreamBasicFilter.hpp b/poxml/antlr/antlr/TokenStreamBasicFilter.hpp
new file mode 100644
index 00000000..5438878b
--- /dev/null
+++ b/poxml/antlr/antlr/TokenStreamBasicFilter.hpp
@@ -0,0 +1,35 @@
+#ifndef INC_TokenStreamBasicFilter_hpp__
+#define INC_TokenStreamBasicFilter_hpp__
+
+#include "antlr/config.hpp"
+#include "antlr/BitSet.hpp"
+#include "antlr/TokenStream.hpp"
+
+ANTLR_BEGIN_NAMESPACE(antlr)
+
+/** This object is a TokenStream that passes through all
+ * tokens except for those that you tell it to discard.
+ * There is no buffering of the tokens.
+ */
+class TokenStreamBasicFilter : public TokenStream {
+ /** The set of token types to discard */
+protected:
+ BitSet discardMask;
+
+ /** The input stream */
+protected:
+ TokenStream* input;
+
+public:
+ TokenStreamBasicFilter(TokenStream& input_);
+
+ void discard(int ttype);
+
+ void discard(const BitSet& mask);
+
+ RefToken nextToken();
+};
+
+ANTLR_END_NAMESPACE
+
+#endif //INC_TokenStreamBasicFilter_hpp__
diff --git a/poxml/antlr/antlr/TokenStreamException.hpp b/poxml/antlr/antlr/TokenStreamException.hpp
new file mode 100644
index 00000000..2dc96776
--- /dev/null
+++ b/poxml/antlr/antlr/TokenStreamException.hpp
@@ -0,0 +1,19 @@
+#ifndef INC_TokenStreamException_hpp__
+#define INC_TokenStreamException_hpp__
+
+#include "antlr/config.hpp"
+#include "antlr/ANTLRException.hpp"
+
+ANTLR_BEGIN_NAMESPACE(antlr)
+
+class TokenStreamException : public ANTLRException {
+public:
+ TokenStreamException() {}
+ TokenStreamException(const ANTLR_USE_NAMESPACE(std)string& s)
+ : ANTLRException(s) {}
+ virtual ~TokenStreamException() throw() {}
+};
+
+ANTLR_END_NAMESPACE
+
+#endif //INC_TokenStreamException_hpp__
diff --git a/poxml/antlr/antlr/TokenStreamHiddenTokenFilter.hpp b/poxml/antlr/antlr/TokenStreamHiddenTokenFilter.hpp
new file mode 100644
index 00000000..47aad001
--- /dev/null
+++ b/poxml/antlr/antlr/TokenStreamHiddenTokenFilter.hpp
@@ -0,0 +1,84 @@
+#ifndef INC_TokenStreamHiddenTokenFilter_hpp__
+#define INC_TokenStreamHiddenTokenFilter_hpp__
+
+#include "antlr/config.hpp"
+#include "antlr/TokenStreamBasicFilter.hpp"
+
+ANTLR_BEGIN_NAMESPACE(antlr)
+
+/**This object filters a token stream coming from a lexer
+ * or another TokenStream so that only certain token channels
+ * get transmitted to the parser.
+ *
+ * Any of the channels can be filtered off as "hidden" channels whose
+ * tokens can be accessed from the parser.
+ */
+class TokenStreamHiddenTokenFilter : public TokenStreamBasicFilter {
+ // protected BitSet discardMask;
+protected:
+ BitSet hideMask;
+
+private:
+ RefToken nextMonitoredToken;
+
+protected:
+ /** track tail of hidden list emanating from previous
+ * monitored token
+ */
+ RefToken lastHiddenToken;
+
+ RefToken firstHidden; // = null;
+
+public:
+ TokenStreamHiddenTokenFilter(TokenStream& input);
+
+protected:
+ void consume();
+
+private:
+ void consumeFirst();
+
+public:
+ BitSet getDiscardMask() const;
+
+ /** Return a ptr to the hidden token appearing immediately after
+ * token t in the input stream.
+ */
+ RefToken getHiddenAfter(RefToken t);
+
+ /** Return a ptr to the hidden token appearing immediately before
+ * token t in the input stream.
+ */
+ RefToken getHiddenBefore(RefToken t);
+
+ BitSet getHideMask() const;
+
+ /** Return the first hidden token if one appears
+ * before any monitored token.
+ */
+ RefToken getInitialHiddenToken();
+
+ void hide(int m);
+
+ void hide(const BitSet& mask);
+
+protected:
+ RefToken LA(int i);
+
+public:
+/** Return the next monitored token.
+ * Test the token following the monitored token.
+ * If following is another monitored token, save it
+ * for the next invocation of nextToken (like a single
+ * lookahead token) and return it then.
+ * If following is unmonitored, nondiscarded (hidden)
+ * channel token, add it to the monitored token.
+ *
+ * Note: EOF must be a monitored Token.
+ */
+ RefToken nextToken();
+};
+
+ANTLR_END_NAMESPACE
+
+#endif //INC_TokenStreamHiddenTokenFilter_hpp__
diff --git a/poxml/antlr/antlr/TokenStreamIOException.hpp b/poxml/antlr/antlr/TokenStreamIOException.hpp
new file mode 100644
index 00000000..9ac6d759
--- /dev/null
+++ b/poxml/antlr/antlr/TokenStreamIOException.hpp
@@ -0,0 +1,22 @@
+#ifndef INC_TokenStreamIOException_hpp__
+#define INC_TokenStreamIOException_hpp__
+
+#include "antlr/config.hpp"
+#include "antlr/TokenStreamException.hpp"
+#include <exception>
+
+ANTLR_BEGIN_NAMESPACE(antlr)
+
+class TokenStreamIOException : public TokenStreamException {
+public:
+ ANTLR_USE_NAMESPACE(std)exception io;
+
+ TokenStreamIOException() {}
+ TokenStreamIOException(const ANTLR_USE_NAMESPACE(std)exception& e)
+ : TokenStreamException(e.what()), io(e) {}
+ ~TokenStreamIOException() throw() {}
+};
+
+ANTLR_END_NAMESPACE
+
+#endif //INC_TokenStreamIOException_hpp__
diff --git a/poxml/antlr/antlr/TokenStreamRecognitionException.hpp b/poxml/antlr/antlr/TokenStreamRecognitionException.hpp
new file mode 100644
index 00000000..4aa4609f
--- /dev/null
+++ b/poxml/antlr/antlr/TokenStreamRecognitionException.hpp
@@ -0,0 +1,21 @@
+#ifndef INC_TokenStreamRecognitionException_hpp__
+#define INC_TokenStreamRecognitionException_hpp__
+
+#include "antlr/config.hpp"
+#include "antlr/TokenStreamException.hpp"
+#include <exception>
+
+ANTLR_BEGIN_NAMESPACE(antlr)
+
+class TokenStreamRecognitionException : public TokenStreamException {
+public:
+ RecognitionException recog;
+
+ TokenStreamRecognitionException(RecognitionException& re)
+ : TokenStreamException(re.getMessage()), recog(re) {}
+ ~TokenStreamRecognitionException() throw() {}
+};
+
+ANTLR_END_NAMESPACE
+
+#endif //INC_TokenStreamRecognitionException_hpp__
diff --git a/poxml/antlr/antlr/TokenStreamRetryException.hpp b/poxml/antlr/antlr/TokenStreamRetryException.hpp
new file mode 100644
index 00000000..a940d8c4
--- /dev/null
+++ b/poxml/antlr/antlr/TokenStreamRetryException.hpp
@@ -0,0 +1,17 @@
+#ifndef INC_TokenStreamRetryException_hpp__
+#define INC_TokenStreamRetryException_hpp__
+
+#include "antlr/config.hpp"
+#include "antlr/TokenStreamException.hpp"
+
+ANTLR_BEGIN_NAMESPACE(antlr)
+
+class TokenStreamRetryException : public TokenStreamException {
+public:
+ TokenStreamRetryException() {}
+ ~TokenStreamRetryException() throw() {}
+};
+
+ANTLR_END_NAMESPACE
+
+#endif //INC_TokenStreamRetryException_hpp__
diff --git a/poxml/antlr/antlr/TokenStreamSelector.hpp b/poxml/antlr/antlr/TokenStreamSelector.hpp
new file mode 100644
index 00000000..7e7d7398
--- /dev/null
+++ b/poxml/antlr/antlr/TokenStreamSelector.hpp
@@ -0,0 +1,78 @@
+#ifndef INC_TokenStreamSelector_hpp__
+#define INC_TokenStreamSelector_hpp__
+
+#include "antlr/config.hpp"
+#include "antlr/TokenStream.hpp"
+#include <map>
+#include <stack>
+
+ANTLR_BEGIN_NAMESPACE(antlr)
+
+/** A token stream MUX (multiplexor) knows about n token streams
+ * and can multiplex them onto the same channel for use by token
+ * stream consumer like a parser. This is a way to have multiple
+ * lexers break up the same input stream for a single parser.
+ * Or, you can have multiple instances of the same lexer handle
+ * multiple input streams; this works great for includes.
+ */
+class TokenStreamSelector : public TokenStream {
+protected:
+ /** The set of inputs to the MUX */
+#ifdef OS_NO_ALLOCATOR
+ typedef ANTLR_USE_NAMESPACE(std)less<ANTLR_USE_NAMESPACE(std)string> lessp;
+ typedef ANTLR_USE_NAMESPACE(std)map<ANTLR_USE_NAMESPACE(std)string,TokenStream*,lessp> inputStreamNames_coll;
+#else
+ typedef ANTLR_USE_NAMESPACE(std)map<ANTLR_USE_NAMESPACE(std)string,TokenStream*> inputStreamNames_coll;
+#endif
+ inputStreamNames_coll inputStreamNames;
+
+ /** The currently-selected token stream input */
+ TokenStream* input;
+
+ /** Used to track stack of input streams */
+#ifdef OS_NO_ALLOCATOR
+ typedef ANTLR_USE_NAMESPACE(std)stack<TokenStream*, ANTLR_USE_NAMESPACE(std)deque<TokenStream*> > streamStack_coll;
+#else
+ typedef ANTLR_USE_NAMESPACE(std)stack<TokenStream*> streamStack_coll;
+#endif
+ streamStack_coll streamStack;
+
+public:
+ TokenStreamSelector();
+ ~TokenStreamSelector();
+
+ void addInputStream(TokenStream* stream, const ANTLR_USE_NAMESPACE(std)string& key);
+
+ /** Return the stream from which tokens are being pulled at
+ * the moment.
+ */
+ TokenStream* getCurrentStream() const;
+
+ TokenStream* getStream(const ANTLR_USE_NAMESPACE(std)string& sname) const;
+
+ RefToken nextToken();
+
+ TokenStream* pop();
+
+ void push(TokenStream* stream);
+
+ void push(const ANTLR_USE_NAMESPACE(std)string& sname);
+
+ /** Abort recognition of current Token and try again.
+ * A stream can push a new stream (for include files
+ * for example, and then retry(), which will cause
+ * the current stream to abort back to this.nextToken().
+ * this.nextToken() then asks for a token from the
+ * current stream, which is the new "substream."
+ */
+ void retry();
+
+/** Set the stream without pushing old stream */
+ void select(TokenStream* stream);
+
+ void select(const ANTLR_USE_NAMESPACE(std)string& sname);
+};
+
+ANTLR_END_NAMESPACE
+
+#endif //INC_TokenStreamSelector_hpp__
diff --git a/poxml/antlr/antlr/TreeParser.hpp b/poxml/antlr/antlr/TreeParser.hpp
new file mode 100644
index 00000000..ed474bd1
--- /dev/null
+++ b/poxml/antlr/antlr/TreeParser.hpp
@@ -0,0 +1,159 @@
+#ifndef INC_TreeParser_hpp__
+#define INC_TreeParser_hpp__
+
+/**
+ * <b>SOFTWARE RIGHTS</b>
+ * <p>
+ * ANTLR 2.6.0 MageLang Insitute, 1999
+ * <p>
+ * We reserve no legal rights to the ANTLR--it is fully in the
+ * public domain. An individual or company may do whatever
+ * they wish with source code distributed with ANTLR or the
+ * code generated by ANTLR, including the incorporation of
+ * ANTLR, or its output, into commerical software.
+ * <p>
+ * We encourage users to develop software with ANTLR. However,
+ * we do ask that credit is given to us for developing
+ * ANTLR. By "credit", we mean that if you use ANTLR or
+ * incorporate any source code into one of your programs
+ * (commercial product, research project, or otherwise) that
+ * you acknowledge this fact somewhere in the documentation,
+ * research report, etc... If you like ANTLR and have
+ * developed a nice tool with the output, please mention that
+ * you developed it using ANTLR. In addition, we ask that the
+ * headers remain intact in our source code. As long as these
+ * guidelines are kept, we expect to continue enhancing this
+ * system and expect to make other tools available as they are
+ * completed.
+ * <p>
+ * The ANTLR gang:
+ * @version ANTLR 2.6.0 MageLang Insitute, 1999
+ * @author Terence Parr, <a href=http://www.MageLang.com>MageLang Institute</a>
+ * @author <br>John Lilley, <a href=http://www.Empathy.com>Empathy Software</a>
+ * @author <br><a href="mailto:pete@yamuna.demon.co.uk">Pete Wells</a>
+ */
+#include "antlr/config.hpp"
+#include "antlr/AST.hpp"
+#include "antlr/ASTFactory.hpp"
+#include "antlr/BitSet.hpp"
+#include "antlr/RecognitionException.hpp"
+#include "antlr/TreeParserSharedInputState.hpp"
+
+ANTLR_BEGIN_NAMESPACE(antlr)
+
+class TreeParser {
+public:
+ TreeParser();
+ TreeParser(const TreeParserSharedInputState& state);
+ virtual ~TreeParser();
+
+protected:
+ void setTokenNames(const char** tokenNames_);
+
+public:
+ /** The AST Null object; the parsing cursor is set to this when
+ * it is found to be null. This way, we can test the
+ * token type of a node without having to have tests for null
+ * everywhere.
+ */
+ static RefAST ASTNULL;
+
+protected:
+ /** Where did this rule leave off parsing; avoids a return parameter */
+ RefAST _retTree;
+
+ /** guessing nesting level; guessing==0 implies not guessing */
+ // int guessing; // = 0;
+
+ /** Nesting level of registered handlers */
+ // int exceptionLevel; // = 0;
+
+ TreeParserSharedInputState inputState;
+
+ /** Table of token type to token names */
+ ANTLR_USE_NAMESPACE(std)vector<ANTLR_USE_NAMESPACE(std)string> tokenNames;
+
+ /** AST return value for a rule is squirreled away here */
+ RefAST returnAST;
+
+ /** AST support code; parser and treeparser delegate to this object */
+ ASTFactory astFactory; // = new ASTFactory();
+
+ /** Used to keep track of indent depth with -traceTreeParser */
+ int traceDepth;
+
+public:
+ /** Get the AST return value squirreled away in the parser */
+ RefAST getAST() const {
+ return returnAST;
+ }
+
+ ANTLR_USE_NAMESPACE(std)string getTokenName(int num) const;
+ ANTLR_USE_NAMESPACE(std)vector<ANTLR_USE_NAMESPACE(std)string> getTokenNames() const;
+
+protected:
+ void match(RefAST t, int ttype);
+
+public:
+ /**Make sure current lookahead symbol matches the given set
+ * Throw an exception upon mismatch, which is catch by either the
+ * error handler or by the syntactic predicate.
+ */
+ void match(RefAST t, const BitSet& b);
+
+protected:
+ void matchNot(RefAST t, int ttype);
+
+public:
+ static void panic();
+
+ /** Parser error-reporting function can be overridden in subclass */
+ virtual void reportError(const RecognitionException& ex);
+
+ /** Parser error-reporting function can be overridden in subclass */
+ virtual void reportError(const ANTLR_USE_NAMESPACE(std)string& s);
+
+ /** Parser warning-reporting function can be overridden in subclass */
+ virtual void reportWarning(const ANTLR_USE_NAMESPACE(std)string& s);
+
+ /** Specify an object with support code (shared by
+ * Parser and TreeParser. Normally, the programmer
+ * does not play with this, using setASTNodeType instead.
+ */
+// void setASTFactory(ASTFactory f);
+
+ /** Specify the type of node to create during tree building */
+ void setASTNodeFactory(ASTFactory::factory_type factory);
+
+protected:
+ /** Utility class which allows tracing to work even when exceptions are
+ * thrown.
+ */
+ class Tracer {
+ private:
+ TreeParser* parser;
+ ANTLR_USE_NAMESPACE(std)string text;
+ RefAST tree;
+ public:
+ Tracer(TreeParser* p,const ANTLR_USE_NAMESPACE(std)string& t, RefAST a)
+ : parser(p), text(t), tree(a) { parser->traceIn(text,tree); }
+ ~Tracer()
+ { parser->traceOut(text,tree); }
+ private:
+ Tracer(const Tracer&); // undefined
+ const Tracer& operator=(const Tracer&); // undefined
+ };
+
+public:
+ void traceIndent();
+ void traceIn(const ANTLR_USE_NAMESPACE(std)string& rname, RefAST t);
+ void traceOut(const ANTLR_USE_NAMESPACE(std)string& rname, RefAST t);
+
+private:
+ TreeParser(const TreeParser& other);
+ TreeParser& operator=(const TreeParser& other);
+};
+
+ANTLR_END_NAMESPACE
+
+#endif //INC_TreeParser_hpp__
diff --git a/poxml/antlr/antlr/TreeParserSharedInputState.hpp b/poxml/antlr/antlr/TreeParserSharedInputState.hpp
new file mode 100644
index 00000000..8f7b0922
--- /dev/null
+++ b/poxml/antlr/antlr/TreeParserSharedInputState.hpp
@@ -0,0 +1,34 @@
+#ifndef INC_TreeParserSharedInputState_hpp__
+#define INC_TreeParserSharedInputState_hpp__
+
+#include "antlr/config.hpp"
+#include "antlr/RefCount.hpp"
+
+ANTLR_BEGIN_NAMESPACE(antlr)
+
+/** This object contains the data associated with an
+ * input AST. Multiple parsers
+ * share a single TreeParserSharedInputState to parse
+ * the same tree or to have the parser walk multiple
+ * trees.
+ */
+class TreeParserInputState {
+public:
+ TreeParserInputState();
+ ~TreeParserInputState();
+
+public:
+ /** Are we guessing (guessing>0)? */
+ int guessing; //= 0;
+
+private:
+ // we don't want these:
+ TreeParserInputState(const TreeParserInputState&);
+ TreeParserInputState& operator=(const TreeParserInputState&);
+};
+
+typedef RefCount<TreeParserInputState> TreeParserSharedInputState;
+
+ANTLR_END_NAMESPACE
+
+#endif //INC_TreeParserSharedInputState_hpp__
diff --git a/poxml/antlr/antlr/config.hpp b/poxml/antlr/antlr/config.hpp
new file mode 100644
index 00000000..8ac94a3a
--- /dev/null
+++ b/poxml/antlr/antlr/config.hpp
@@ -0,0 +1,168 @@
+#ifndef INC_config_hpp__
+#define INC_config_hpp__
+
+/**
+ * <b>SOFTWARE RIGHTS</b>
+ * <p>
+ * ANTLR 2.6.0 MageLang Insitute, 1999
+ * <p>
+ * We reserve no legal rights to the ANTLR--it is fully in the
+ * public domain. An individual or company may do whatever
+ * they wish with source code distributed with ANTLR or the
+ * code generated by ANTLR, including the incorporation of
+ * ANTLR, or its output, into commerical software.
+ * <p>
+ * We encourage users to develop software with ANTLR. However,
+ * we do ask that credit is given to us for developing
+ * ANTLR. By "credit", we mean that if you use ANTLR or
+ * incorporate any source code into one of your programs
+ * (commercial product, research project, or otherwise) that
+ * you acknowledge this fact somewhere in the documentation,
+ * research report, etc... If you like ANTLR and have
+ * developed a nice tool with the output, please mention that
+ * you developed it using ANTLR. In addition, we ask that the
+ * headers remain intact in our source code. As long as these
+ * guidelines are kept, we expect to continue enhancing this
+ * system and expect to make other tools available as they are
+ * completed.
+ * <p>
+ * The ANTLR gang:
+ * @version ANTLR 2.6.0 MageLang Insitute, 1999
+ * @author Terence Parr, <a href=http://www.MageLang.com>MageLang Institute</a>
+ * @author <br>John Lilley, <a href=http://www.Empathy.com>Empathy Software</a>
+ * @author <br><a href="mailto:pete@yamuna.demon.co.uk">Pete Wells</a>
+ */
+
+/*
+ * Just a simple configuration file to differentiate between the
+ * various compilers used.
+ */
+
+/*
+ Some compilers do not accept namespaces std:: for example.
+ In this case, just define #define ANTLR_USE_NAMESPACE(_x_).
+
+ See SunWorkShop 4.2 for example.
+ */
+#define ANTLR_USE_NAMESPACE(_x_) _x_::
+#define ANTLR_USING_NAMESPACE(_x_) using namespace _x_;
+#define ANTLR_BEGIN_NAMESPACE(_x_) namespace _x_ {
+#define ANTLR_END_NAMESPACE }
+#define ANTLR_C_USING(_x_)
+
+#if defined(_MSC_VER) && !defined(__ICL) // Microsoft Visual C++
+
+// This warning really gets on my nerves.
+// It's the one about symbol longer than 256 chars, and it happens
+// all the time with STL.
+#pragma warning( disable : 4786 )
+
+// Now, some defines for shortcomings in the MS compiler:
+
+// Not allowed to put 'static const int XXX=20;' in a class definition
+#define NO_STATIC_CONSTS
+// Using vector<XXX> requires operator<(X,X) to be defined
+#define NEEDS_OPERATOR_LESS_THAN
+// No strcasecmp in the C library (so use stricmp instead)
+// - Anyone know which is in which standard?
+#define NO_STRCASECMP
+
+#endif
+
+#if defined(__ICL)
+#define NO_STRCASECMP
+#endif
+
+//
+// SunPro Compiler (Using OBJECTSPACE STL)
+//
+#ifdef __SUNPRO_CC
+
+#if (__SUNPRO_CC >= 0x500)
+
+#define NEEDS_OPERATOR_LESS_THAN
+#define NO_TEMPLATE_PARTS
+
+#else
+
+#undef namespace
+#define namespace
+
+
+#if (__SUNPRO_CC == 0x420)
+
+/* This code is specif to SunWspro Compiler 4.2, and will compile with
+ the objectspace 2.1 toolkit for Solaris2.6 */
+#define HAS_NOT_CASSERT_H
+#define HAS_NOT_CSTRING_H
+#define HAS_NOT_CCTYPE_H
+#define HAS_NOT_CSTDIO_H
+#define HAS_OSTREAM_H
+
+/* #define OS_SOLARIS_2_6
+#define OS_NO_WSTRING
+#define OS_NO_ALLOCATORS
+#define OS_MULTI_THREADED
+#define OS_SOLARIS_NATIVE
+#define OS_REALTIME
+#define __OSVERSION__=5
+#define SVR4
+*/
+
+// ObjectSpace + some specific templates constructions with stl.
+/* #define OS_NO_ALLOCATOR */
+
+// This great compiler does not have the namespace feature.
+#undef ANTLR_USE_NAMESPACE
+#define ANTLR_USE_NAMESPACE(_x_)
+#undef ANTLR_USING_NAMESPACE
+#define ANTLR_USING_NAMESPACE(_x_)
+#undef ANTLR_BEGIN_NAMESPACE
+#define ANTLR_BEGIN_NAMESPACE(_x_)
+#undef ANTLR_END_NAMESPACE
+#define ANTLR_END_NAMESPACE
+
+#endif
+
+#undef explicit
+#define explicit
+
+#define exception os_exception
+#define bad_exception os_bad_exception
+
+// Not allowed to put 'static const int XXX=20;' in a class definition
+#define NO_STATIC_CONSTS
+// Using vector<XXX> requires operator<(X,X) to be defined
+#define NEEDS_OPERATOR_LESS_THAN
+
+#endif
+
+#endif
+
+//
+// Inprise C++ Builder 3.0
+//
+#ifdef __BCPLUSPLUS__
+
+#define NO_TEMPLATE_PARTS
+#define NO_STRCASECMP
+#endif
+
+#ifdef _AIX
+#include <strings.h>
+#endif
+
+//
+// Metrowerks Codewarrior
+//
+#ifdef __MWERKS__
+#if (__MWERKS__ <= 0x2201)
+#define NO_TEMPLATE_PARTS
+#define ANTLR_REALLY_NO_STRCASECMP
+#endif
+
+#undef ANTLR_C_USING
+#define ANTLR_C_USING(_x_) using std:: ## _x_;
+#endif
+
+#endif //INC_config_hpp__
diff --git a/poxml/antlr/configure.in b/poxml/antlr/configure.in
new file mode 100644
index 00000000..66f8cf15
--- /dev/null
+++ b/poxml/antlr/configure.in
@@ -0,0 +1,22 @@
+AC_INIT(src/Parser.cpp)
+
+PACKAGE=libantlr
+VERSION="2.7.1"
+LIBANTLR_SO_VERSION=0:0:0
+
+AM_INIT_AUTOMAKE($PACKAGE, $VERSION)
+
+AM_DISABLE_SHARED
+AM_PROG_LIBTOOL
+AC_PROG_CXX
+AC_PROG_CXXCPP
+AC_PROG_RANLIB
+
+test "$ac_cv_prog_gxx" = 'yes' && CXXFLAGS="$CXXFLAGS -W -Wall -pipe"
+
+AC_SUBST(LIBANTLR_SO_VERSION)
+AC_SUBST(LIBTOOL_DEPS)
+
+AC_OUTPUT(Makefile \
+ src/Makefile \
+ antlr/Makefile)
diff --git a/poxml/antlr/src/ANTLRException.cpp b/poxml/antlr/src/ANTLRException.cpp
new file mode 100644
index 00000000..42632e71
--- /dev/null
+++ b/poxml/antlr/src/ANTLRException.cpp
@@ -0,0 +1,57 @@
+/**
+ * <b>SOFTWARE RIGHTS</b>
+ * <p>
+ * ANTLR 2.6.0 MageLang Insitute, 1998
+ * <p>
+ * We reserve no legal rights to the ANTLR--it is fully in the
+ * public domain. An individual or company may do whatever
+ * they wish with source code distributed with ANTLR or the
+ * code generated by ANTLR, including the incorporation of
+ * ANTLR, or its output, into commerical software.
+ * <p>
+ * We encourage users to develop software with ANTLR. However,
+ * we do ask that credit is given to us for developing
+ * ANTLR. By "credit", we mean that if you use ANTLR or
+ * incorporate any source code into one of your programs
+ * (commercial product, research project, or otherwise) that
+ * you acknowledge this fact somewhere in the documentation,
+ * research report, etc... If you like ANTLR and have
+ * developed a nice tool with the output, please mention that
+ * you developed it using ANTLR. In addition, we ask that the
+ * headers remain intact in our source code. As long as these
+ * guidelines are kept, we expect to continue enhancing this
+ * system and expect to make other tools available as they are
+ * completed.
+ * <p>
+ * The ANTLR gang:
+ * @version ANTLR 2.6.0 MageLang Insitute, 1998
+ * @author Terence Parr, <a href=http://www.MageLang.com>MageLang Institute</a>
+ * @author <br>John Lilley, <a href=http://www.Empathy.com>Empathy Software</a>
+ * @author <br><a href="mailto:pete@yamuna.demon.co.uk">Pete Wells</a>
+ */
+
+#include "antlr/ANTLRException.hpp"
+
+ANTLR_BEGIN_NAMESPACE(antlr)
+
+ANTLRException::ANTLRException() : text("")
+{}
+
+ANTLRException::ANTLRException(const ANTLR_USE_NAMESPACE(std)string& s)
+: text(s)
+{}
+
+ANTLRException::~ANTLRException() throw()
+{}
+
+ANTLR_USE_NAMESPACE(std)string ANTLRException::toString() const
+{ return text; }
+
+ANTLR_USE_NAMESPACE(std)string ANTLRException::getMessage() const
+{ return text; }
+
+const char* ANTLRException::what() const throw()
+{ return text.c_str(); }
+
+ANTLR_END_NAMESPACE
+
diff --git a/poxml/antlr/src/ASTFactory.cpp b/poxml/antlr/src/ASTFactory.cpp
new file mode 100644
index 00000000..e44386f7
--- /dev/null
+++ b/poxml/antlr/src/ASTFactory.cpp
@@ -0,0 +1,218 @@
+/**
+ * <b>SOFTWARE RIGHTS</b>
+ * <p>
+ * ANTLR 2.6.0 MageLang Insitute, 1998
+ * <p>
+ * We reserve no legal rights to the ANTLR--it is fully in the
+ * public domain. An individual or company may do whatever
+ * they wish with source code distributed with ANTLR or the
+ * code generated by ANTLR, including the incorporation of
+ * ANTLR, or its output, into commerical software.
+ * <p>
+ * We encourage users to develop software with ANTLR. However,
+ * we do ask that credit is given to us for developing
+ * ANTLR. By "credit", we mean that if you use ANTLR or
+ * incorporate any source code into one of your programs
+ * (commercial product, research project, or otherwise) that
+ * you acknowledge this fact somewhere in the documentation,
+ * research report, etc... If you like ANTLR and have
+ * developed a nice tool with the output, please mention that
+ * you developed it using ANTLR. In addition, we ask that the
+ * headers remain intact in our source code. As long as these
+ * guidelines are kept, we expect to continue enhancing this
+ * system and expect to make other tools available as they are
+ * completed.
+ * <p>
+ * The ANTLR gang:
+ * @version ANTLR 2.6.0 MageLang Insitute, 1998
+ * @author Terence Parr, <a href=http://www.MageLang.com>MageLang Institute</a>
+ * @author <br>John Lilley, <a href=http://www.Empathy.com>Empathy Software</a>
+ * @author <br><a href="mailto:pete@yamuna.demon.co.uk">Pete Wells</a>
+ */
+
+#include "antlr/ASTFactory.hpp"
+#include "antlr/CommonAST.hpp"
+
+ANTLR_BEGIN_NAMESPACE(antlr)
+
+/** AST Support code shared by TreeParser and Parser.
+ * We use delegation to share code (and have only one
+ * bit of code to maintain) rather than subclassing
+ * or superclassing (forces AST support code to be
+ * loaded even when you don't want to do AST stuff).
+ *
+ * Typically, setASTNodeType is used to specify the
+ * type of node to create, but you can override
+ * create to make heterogeneous nodes etc...
+ */
+
+ASTFactory::ASTFactory() : nodeFactory(&CommonAST::factory)
+{
+}
+
+/** Add a child to the current AST */
+void ASTFactory::addASTChild(ASTPair& currentAST, RefAST child)
+{
+ if (child) {
+ if (!currentAST.root) {
+ // Make new child the current root
+ currentAST.root = child;
+ }
+ else {
+ if (!currentAST.child) {
+ // Add new child to current root
+ currentAST.root->setFirstChild(child);
+ }
+ else {
+ currentAST.child->setNextSibling(child);
+ }
+ }
+ // Make new child the current child
+ currentAST.child = child;
+ currentAST.advanceChildToEnd();
+ }
+}
+/** Create a new empty AST node; if the user did not specify
+ * an AST node type, then create a default one: CommonAST.
+ */
+RefAST ASTFactory::create()
+{
+ RefAST node = nodeFactory();
+ node->setType(Token::INVALID_TYPE);
+ return node;
+}
+
+RefAST ASTFactory::create(int type)
+{
+ RefAST t = nodeFactory();
+ t->initialize(type,"");
+ return t;
+}
+
+RefAST ASTFactory::create(int type, const ANTLR_USE_NAMESPACE(std)string& txt)
+{
+ RefAST t = nodeFactory();
+ t->initialize(type,txt);
+ return t;
+}
+
+/** Create a new empty AST node; if the user did not specify
+ * an AST node type, then create a default one: CommonAST.
+ */
+RefAST ASTFactory::create(RefAST tr)
+{
+ if (!tr)
+ return nullAST;
+
+ RefAST t = nodeFactory();
+ t->initialize(tr);
+ return t;
+}
+
+RefAST ASTFactory::create(RefToken tok)
+{
+ RefAST t = nodeFactory();
+ t->initialize(tok);
+ return t;
+}
+/** Copy a single node. clone() is not used because
+ * we want to return an AST not a plain object...a type
+ * safety issue. Further, we want to have all AST node
+ * creation go through the factory so creation can be
+ * tracked. Returns null if t is null.
+ */
+RefAST ASTFactory::dup(RefAST t)
+{
+ return create(t); // if t==null, create returns null
+}
+
+/** Duplicate tree including siblings of root. */
+RefAST ASTFactory::dupList(RefAST t)
+{
+ RefAST result = dupTree(t); // if t == null, then result==null
+ RefAST nt = result;
+ while (t) { // for each sibling of the root
+ t = t->getNextSibling();
+ nt->setNextSibling(dupTree(t)); // dup each subtree, building new tree
+ nt = nt->getNextSibling();
+ }
+ return result;
+}
+/**Duplicate a tree, assuming this is a root node of a tree--
+ * duplicate that node and what's below; ignore siblings of root node.
+ */
+RefAST ASTFactory::dupTree(RefAST t)
+{
+ RefAST result = dup(t); // make copy of root
+ // copy all children of root.
+ if (t) {
+ result->setFirstChild( dupList(t->getFirstChild()) );
+ }
+ return result;
+}
+/** Make a tree from a list of nodes. The first element in the
+ * array is the root. If the root is null, then the tree is
+ * a simple list not a tree. Handles null children nodes correctly.
+ * For example, build(a, b, null, c) yields tree (a b c). build(null,a,b)
+ * yields tree (nil a b).
+ */
+RefAST ASTFactory::make(ANTLR_USE_NAMESPACE(std)vector<RefAST> nodes)
+{
+ if ( nodes.size()==0 )
+ return RefAST(nullASTptr);
+ RefAST root = nodes[0];
+ RefAST tail = RefAST(nullASTptr);
+ if (root) {
+ root->setFirstChild(RefAST(nullASTptr)); // don't leave any old pointers set
+ }
+ // link in children;
+ for (unsigned int i=1; i<nodes.size(); i++) {
+ if ( !nodes[i] ) continue; // ignore null nodes
+ if ( !root ) {
+ // Set the root and set it up for a flat list
+ root = tail = nodes[i];
+ }
+ else if ( !tail ) {
+ root->setFirstChild(nodes[i]);
+ tail = root->getFirstChild();
+ }
+ else {
+ tail->setNextSibling(nodes[i]);
+ tail = tail->getNextSibling();
+ }
+ // Chase tail to last sibling
+ while (tail->getNextSibling()) {
+ tail = tail->getNextSibling();
+ }
+ }
+ return root;
+}
+/** Make a tree from a list of nodes, where the nodes are contained
+ * in an ASTArray object
+ */
+RefAST ASTFactory::make(ASTArray* nodes)
+{
+ RefAST ret = make(nodes->array);
+ delete nodes;
+ return ret;
+}
+/** Make an AST the root of current AST */
+void ASTFactory::makeASTRoot(ASTPair& currentAST, RefAST root)
+{
+ if (root) {
+ // Add the current root as a child of new root
+ root->addChild(currentAST.root);
+ // The new current child is the last sibling of the old root
+ currentAST.child = currentAST.root;
+ currentAST.advanceChildToEnd();
+ // Set the new root
+ currentAST.root = root;
+ }
+}
+void ASTFactory::setASTNodeFactory(factory_type factory)
+{
+ nodeFactory = factory;
+}
+
+ANTLR_END_NAMESPACE
+
diff --git a/poxml/antlr/src/ASTRefCount.cpp b/poxml/antlr/src/ASTRefCount.cpp
new file mode 100644
index 00000000..1da98306
--- /dev/null
+++ b/poxml/antlr/src/ASTRefCount.cpp
@@ -0,0 +1,74 @@
+#include "antlr/ASTRefCount.hpp"
+#include "antlr/AST.hpp"
+
+ANTLR_BEGIN_NAMESPACE(antlr)
+
+/**
+ * <b>SOFTWARE RIGHTS</b>
+ * <p>
+ * ANTLR 2.6.0 MageLang Insitute, 1999
+ * <p>
+ * We reserve no legal rights to the ANTLR--it is fully in the
+ * public domain. An individual or company may do whatever
+ * they wish with source code distributed with ANTLR or the
+ * code generated by ANTLR, including the incorporation of
+ * ANTLR, or its output, into commerical software.
+ * <p>
+ * We encourage users to develop software with ANTLR. However,
+ * we do ask that credit is given to us for developing
+ * ANTLR. By "credit", we mean that if you use ANTLR or
+ * incorporate any source code into one of your programs
+ * (commercial product, research project, or otherwise) that
+ * you acknowledge this fact somewhere in the documentation,
+ * research report, etc... If you like ANTLR and have
+ * developed a nice tool with the output, please mention that
+ * you developed it using ANTLR. In addition, we ask that the
+ * headers remain intact in our source code. As long as these
+ * guidelines are kept, we expect to continue enhancing this
+ * system and expect to make other tools available as they are
+ * completed.
+ * <p>
+ * The ANTLR gang:
+ * @version ANTLR 2.6.0 MageLang Insitute, 1999
+ * @author Terence Parr, <a href=http://www.MageLang.com>MageLang Institute</a>
+ * @author <br>John Lilley, <a href=http://www.Empathy.com>Empathy Software</a>
+ * @author <br><a href="mailto:pete@yamuna.demon.co.uk">Pete Wells</a>
+ */
+
+ASTRef::ASTRef(AST* p)
+ : ptr(p), count(1)
+{
+ if (p && !p->ref)
+ p->ref = this;
+}
+
+ASTRef::~ASTRef()
+{
+ delete ptr;
+}
+
+ASTRef* ASTRef::increment()
+{
+ ++count;
+ return this;
+}
+
+bool ASTRef::decrement()
+{
+ return (--count==0);
+}
+
+ASTRef* ASTRef::getRef(const AST* p)
+{
+ if (p) {
+ AST* pp = const_cast<AST*>(p);
+ if (pp->ref)
+ return pp->ref->increment();
+ else
+ return new ASTRef(pp);
+ } else
+ return 0;
+}
+
+ANTLR_END_NAMESPACE
+
diff --git a/poxml/antlr/src/BaseAST.cpp b/poxml/antlr/src/BaseAST.cpp
new file mode 100644
index 00000000..4080e0e8
--- /dev/null
+++ b/poxml/antlr/src/BaseAST.cpp
@@ -0,0 +1,320 @@
+/**
+ * <b>SOFTWARE RIGHTS</b>
+ * <p>
+ * ANTLR 2.6.0 MageLang Insitute, 1998
+ * <p>
+ * We reserve no legal rights to the ANTLR--it is fully in the
+ * public domain. An individual or company may do whatever
+ * they wish with source code distributed with ANTLR or the
+ * code generated by ANTLR, including the incorporation of
+ * ANTLR, or its output, into commerical software.
+ * <p>
+ * We encourage users to develop software with ANTLR. However,
+ * we do ask that credit is given to us for developing
+ * ANTLR. By "credit", we mean that if you use ANTLR or
+ * incorporate any source code into one of your programs
+ * (commercial product, research project, or otherwise) that
+ * you acknowledge this fact somewhere in the documentation,
+ * research report, etc... If you like ANTLR and have
+ * developed a nice tool with the output, please mention that
+ * you developed it using ANTLR. In addition, we ask that the
+ * headers remain intact in our source code. As long as these
+ * guidelines are kept, we expect to continue enhancing this
+ * system and expect to make other tools available as they are
+ * completed.
+ * <p>
+ * The ANTLR gang:
+ * @version ANTLR 2.6.0 MageLang Insitute, 1998
+ * @author Terence Parr, <a href=http://www.MageLang.com>MageLang Institute</a>
+ * @author <br>John Lilley, <a href=http://www.Empathy.com>Empathy Software</a>
+ * @author <br><a href="mailto:pete@yamuna.demon.co.uk">Pete Wells</a>
+ */
+
+#include "antlr/BaseAST.hpp"
+
+ANTLR_BEGIN_NAMESPACE(antlr)
+
+//bool BaseAST::verboseStringConversion;
+//ANTLR_USE_NAMESPACE(std)vector<ANTLR_USE_NAMESPACE(std)string> BaseAST::tokenNames;
+
+void BaseAST::addChild(RefAST c)
+{
+ if (!c)
+ return;
+ RefBaseAST tmp=down;
+ if (tmp) {
+ while (tmp->right)
+ tmp=tmp->right;
+ tmp->right=c;
+ } else {
+ down=c;
+ }
+}
+
+void BaseAST::doWorkForFindAll(
+ ANTLR_USE_NAMESPACE(std)vector<RefAST>& v,
+ RefAST target,bool partialMatch)
+{
+ // Start walking sibling lists, looking for matches.
+ for (RefAST sibling=this;
+ sibling;
+ sibling=sibling->getNextSibling())
+ {
+ if ( (partialMatch && sibling->equalsTreePartial(target)) ||
+ (!partialMatch && sibling->equalsTree(target)) ) {
+ v.push_back(sibling);
+ }
+ // regardless of match or not, check any children for matches
+ if ( sibling->getFirstChild() ) {
+ RefBaseAST(sibling->getFirstChild())->doWorkForFindAll(v, target, partialMatch);
+ }
+ }
+
+}
+
+/** Is node t equal to this in terms of token type and text? */
+bool BaseAST::equals(RefAST t) const
+{
+ if (!t)
+ return false;
+ return (getText() == t->getText()) && (getType() == t->getType());
+}
+
+/** Is t an exact structural and equals() match of this tree. The
+ * 'this' reference is considered the start of a sibling list.
+ */
+bool BaseAST::equalsList(RefAST t) const
+{
+ // the empty tree is not a match of any non-null tree.
+ if (!t)
+ return false;
+
+ // Otherwise, start walking sibling lists. First mismatch, return false.
+ RefAST sibling=this;
+ for (;sibling && t;
+ sibling=sibling->getNextSibling(), t=t->getNextSibling()) {
+ // as a quick optimization, check roots first.
+ if (!sibling->equals(t))
+ return false;
+ // if roots match, do full list match test on children.
+ if (sibling->getFirstChild()) {
+ if (!sibling->getFirstChild()->equalsList(t->getFirstChild()))
+ return false;
+ }
+ // sibling has no kids, make sure t doesn't either
+ else if (t->getFirstChild())
+ return false;
+ }
+
+ if (!sibling && !t)
+ return true;
+
+ // one sibling list has more than the other
+ return false;
+}
+
+/** Is 'sub' a subtree of this list?
+ * The siblings of the root are NOT ignored.
+ */
+bool BaseAST::equalsListPartial(RefAST sub) const
+{
+ // the empty tree is always a subset of any tree.
+ if (!sub)
+ return true;
+
+ // Otherwise, start walking sibling lists. First mismatch, return false.
+ RefAST sibling=this;
+ for (;sibling && sub;
+ sibling=sibling->getNextSibling(), sub=sub->getNextSibling()) {
+ // as a quick optimization, check roots first.
+ if (!sibling->equals(sub))
+ return false;
+ // if roots match, do partial list match test on children.
+ if (sibling->getFirstChild())
+ if (!sibling->getFirstChild()->equalsListPartial(sub->getFirstChild()))
+ return false;
+ }
+
+ if (!sibling && sub)
+ // nothing left to match in this tree, but subtree has more
+ return false;
+
+ // either both are null or sibling has more, but subtree doesn't
+ return true;
+}
+
+/** Is tree rooted at 'this' equal to 't'? The siblings
+ * of 'this' are ignored.
+ */
+bool BaseAST::equalsTree(RefAST t) const
+{
+ // check roots first
+ if (!equals(t))
+ return false;
+ // if roots match, do full list match test on children.
+ if (getFirstChild()) {
+ if (!getFirstChild()->equalsList(t->getFirstChild()))
+ return false;
+ }
+ // sibling has no kids, make sure t doesn't either
+ else if (t->getFirstChild())
+ return false;
+
+ return true;
+}
+
+/** Is 'sub' a subtree of the tree rooted at 'this'? The siblings
+ * of 'this' are ignored.
+ */
+bool BaseAST::equalsTreePartial(RefAST sub) const
+{
+ // the empty tree is always a subset of any tree.
+ if (!sub)
+ return true;
+
+ // check roots first
+ if (!equals(sub))
+ return false;
+ // if roots match, do full list partial match test on children.
+ if (getFirstChild())
+ if (!getFirstChild()->equalsListPartial(sub->getFirstChild()))
+ return false;
+
+ return true;
+}
+
+/** Walk the tree looking for all exact subtree matches. Return
+ * an ASTEnumerator that lets the caller walk the list
+ * of subtree roots found herein.
+ */
+ANTLR_USE_NAMESPACE(std)vector<RefAST> BaseAST::findAll(RefAST target)
+{
+ ANTLR_USE_NAMESPACE(std)vector<RefAST> roots;
+
+ // the empty tree cannot result in an enumeration
+ if (target) {
+ doWorkForFindAll(roots,target,false); // find all matches recursively
+ }
+
+ return roots;
+}
+
+/** Walk the tree looking for all subtrees. Return
+ * an ASTEnumerator that lets the caller walk the list
+ * of subtree roots found herein.
+ */
+ANTLR_USE_NAMESPACE(std)vector<RefAST> BaseAST::findAllPartial(RefAST target)
+{
+ ANTLR_USE_NAMESPACE(std)vector<RefAST> roots;
+
+ // the empty tree cannot result in an enumeration
+ if (target) {
+ doWorkForFindAll(roots,target,true); // find all matches recursively
+ }
+
+ return roots;
+}
+
+RefAST BaseAST::getFirstChild() const
+{
+ return RefAST(down);
+}
+
+RefAST BaseAST::getNextSibling() const
+{
+ return RefAST(right);
+}
+
+ANTLR_USE_NAMESPACE(std)string BaseAST::getText() const
+{
+ return "";
+}
+
+int BaseAST::getType() const
+{
+ return 0;
+}
+
+void BaseAST::removeChildren()
+{
+ down=nullAST;
+}
+
+void BaseAST::setFirstChild(RefAST c)
+{
+ down=c;
+}
+
+void BaseAST::setNextSibling(RefAST n)
+{
+ right=n;
+}
+
+void BaseAST::setText(const ANTLR_USE_NAMESPACE(std)string& txt)
+{
+}
+
+void BaseAST::setType(int type)
+{
+}
+
+//void BaseAST::setVerboseStringConversion(bool verbose,
+// const ANTLR_USE_NAMESPACE(std)vector<ANTLR_USE_NAMESPACE(std)string>& names)
+//{
+// verboseStringConversion = verbose;
+// tokenNames = names;
+//}
+
+ANTLR_USE_NAMESPACE(std)string BaseAST::toString() const
+{
+// if ( verboseStringConversion &&
+// !getText().equalsIgnoreCase(tokenNames[getType()]) &&
+// !getText().equalsIgnoreCase(Tool.stripFrontBack(tokenNames[getType()],"\"","\"")) ) {
+// b.append('[');
+// b.append(getText());
+// b.append(",<");
+// b.append(tokenNames[getType()]);
+// b.append(">]");
+// return b.toString();
+// }
+ return getText();
+}
+
+ANTLR_USE_NAMESPACE(std)string BaseAST::toStringList() const
+{
+ ANTLR_USE_NAMESPACE(std)string ts="";
+ if (getFirstChild()) {
+ ts+=" ( ";
+ ts+=toString();
+ ts+=getFirstChild()->toStringList();
+ ts+=" )";
+ } else {
+ ts+=" ";
+ ts+=toString();
+ }
+ if (getNextSibling())
+ ts+=getNextSibling()->toStringList();
+ return ts;
+}
+
+ANTLR_USE_NAMESPACE(std)string BaseAST::toStringTree() const
+{
+ ANTLR_USE_NAMESPACE(std)string ts="";
+ if (getFirstChild()) {
+ ts+=" ( ";
+ ts+=toString();
+ ts+=getFirstChild()->toStringList();
+ ts+=" )";
+ } else {
+ ts+=" ";
+ ts+=toString();
+ }
+ return ts;
+}
+
+// this is nasty, but it makes the code generation easier
+RefAST nullAST;
+AST* const nullASTptr=0;
+
+ANTLR_END_NAMESPACE
+
diff --git a/poxml/antlr/src/BitSet.cpp b/poxml/antlr/src/BitSet.cpp
new file mode 100644
index 00000000..a0a1b110
--- /dev/null
+++ b/poxml/antlr/src/BitSet.cpp
@@ -0,0 +1,76 @@
+#include "antlr/BitSet.hpp"
+
+ANTLR_BEGIN_NAMESPACE(antlr)
+
+/** A BitSet to replace java.util.BitSet.
+ * Primary differences are that most set operators return new sets
+ * as opposed to oring and anding "in place". Further, a number of
+ * operations were added. I cannot contain a BitSet because there
+ * is no way to access the internal bits (which I need for speed)
+ * and, because it is final, I cannot subclass to add functionality.
+ * Consider defining set degree. Without access to the bits, I must
+ * call a method n times to test the ith bit...ack!
+ *
+ * Also seems like or() from util is wrong when size of incoming set is bigger
+ * than this.length.
+ *
+ * This is a C++ version of the Java class described above, with only
+ * a handful of the methods implemented, because we don't need the
+ * others at runtime. It's really just a wrapper around vector<bool>,
+ * which should probably be changed to a wrapper around bitset, once
+ * bitset is more widely available.
+ *
+ * @author Terence Parr, MageLang Institute
+ * @author <br><a href="mailto:pete@yamuna.demon.co.uk">Pete Wells</a>
+ */
+BitSet::BitSet(int nbits)
+ : storage(nbits)
+{
+ for (int i=0;i<nbits;i++) {
+ storage[i] = false;
+ }
+}
+
+BitSet::BitSet(const unsigned long* bits_,int nlongs)
+ : storage(nlongs*32)
+{
+ for ( int i = 0 ; i < nlongs*32; i++) {
+ storage[i] = (bits_[i>>5] & (1UL << (i&31))) ? true : false;
+ }
+}
+
+BitSet::~BitSet()
+{
+}
+
+void BitSet::add(int el)
+{
+ if ( el < 0 )
+ throw ANTLR_USE_NAMESPACE(std)out_of_range(ANTLR_USE_NAMESPACE(std)string("antlr::BitSet.cpp line 49"));
+
+ if( static_cast<unsigned int>(el) >= storage.size() )
+ storage.resize( el+1, false );
+
+ storage[el] = true;
+}
+
+bool BitSet::member(int el) const
+{
+ if ( el < 0 || static_cast<unsigned int>(el) >= storage.size())
+ return false;
+
+ return storage[el];
+}
+
+ANTLR_USE_NAMESPACE(std)vector<int> BitSet::toArray() const
+{
+ ANTLR_USE_NAMESPACE(std)vector<int> elems;
+ for (unsigned int i=0;i<storage.size();i++) {
+ if (storage[i])
+ elems.push_back(i);
+ }
+
+ return elems;
+}
+
+ANTLR_END_NAMESPACE
diff --git a/poxml/antlr/src/CharBuffer.cpp b/poxml/antlr/src/CharBuffer.cpp
new file mode 100644
index 00000000..a43eb153
--- /dev/null
+++ b/poxml/antlr/src/CharBuffer.cpp
@@ -0,0 +1,67 @@
+/**
+ * <b>SOFTWARE RIGHTS</b>
+ * <p>
+ * ANTLR 2.6.0 MageLang Insitute, 1998
+ * <p>
+ * We reserve no legal rights to the ANTLR--it is fully in the
+ * public domain. An individual or company may do whatever
+ * they wish with source code distributed with ANTLR or the
+ * code generated by ANTLR, including the incorporation of
+ * ANTLR, or its output, into commerical software.
+ * <p>
+ * We encourage users to develop software with ANTLR. However,
+ * we do ask that credit is given to us for developing
+ * ANTLR. By "credit", we mean that if you use ANTLR or
+ * incorporate any source code into one of your programs
+ * (commercial product, research project, or otherwise) that
+ * you acknowledge this fact somewhere in the documentation,
+ * research report, etc... If you like ANTLR and have
+ * developed a nice tool with the output, please mention that
+ * you developed it using ANTLR. In addition, we ask that the
+ * headers remain intact in our source code. As long as these
+ * guidelines are kept, we expect to continue enhancing this
+ * system and expect to make other tools available as they are
+ * completed.
+ * <p>
+ * The ANTLR gang:
+ * @version ANTLR 2.6.0 MageLang Insitute, 1998
+ * @author Terence Parr, <a href=http://www.MageLang.com>MageLang Institute</a>
+ * @author <br>John Lilley, <a href=http://www.Empathy.com>Empathy Software</a>
+ * @author <br><a href="mailto:pete@yamuna.demon.co.uk">Pete Wells</a>
+ */
+
+/**A Stream of characters fed to the lexer from a InputStream that can
+ * be rewound via mark()/rewind() methods.
+ * <p>
+ * A dynamic array is used to buffer up all the input characters. Normally,
+ * "k" characters are stored in the buffer. More characters may be stored during
+ * guess mode (testing syntactic predicate), or when LT(i>k) is referenced.
+ * Consumption of characters is deferred. In other words, reading the next
+ * character is not done by conume(), but deferred until needed by LA or LT.
+ * <p>
+ *
+ * @see antlr.CharQueue
+ */
+
+#include "antlr/CharBuffer.hpp"
+
+ANTLR_BEGIN_NAMESPACE(antlr)
+
+/** Create a character buffer */
+CharBuffer::CharBuffer(ANTLR_USE_NAMESPACE(std)istream& input_)
+: input(input_)
+{}
+
+/** Get the next character from the stream */
+int CharBuffer::getChar()
+{
+// try {
+ return input.get();
+// }
+// catch (???& e) {
+// throw CharStreamIOException(e);
+// }
+}
+
+ANTLR_END_NAMESPACE
+
diff --git a/poxml/antlr/src/CharScanner.cpp b/poxml/antlr/src/CharScanner.cpp
new file mode 100644
index 00000000..ff40138d
--- /dev/null
+++ b/poxml/antlr/src/CharScanner.cpp
@@ -0,0 +1,430 @@
+/**
+ * <b>SOFTWARE RIGHTS</b>
+ * <p>
+ * ANTLR 2.6.0 MageLang Insitute, 1998
+ * <p>
+ * We reserve no legal rights to the ANTLR--it is fully in the
+ * public domain. An individual or company may do whatever
+ * they wish with source code distributed with ANTLR or the
+ * code generated by ANTLR, including the incorporation of
+ * ANTLR, or its output, into commerical software.
+ * <p>
+ * We encourage users to develop software with ANTLR. However,
+ * we do ask that credit is given to us for developing
+ * ANTLR. By "credit", we mean that if you use ANTLR or
+ * incorporate any source code into one of your programs
+ * (commercial product, research project, or otherwise) that
+ * you acknowledge this fact somewhere in the documentation,
+ * research report, etc... If you like ANTLR and have
+ * developed a nice tool with the output, please mention that
+ * you developed it using ANTLR. In addition, we ask that the
+ * headers remain intact in our source code. As long as these
+ * guidelines are kept, we expect to continue enhancing this
+ * system and expect to make other tools available as they are
+ * completed.
+ * <p>
+ * The ANTLR gang:
+ * @version ANTLR 2.6.0 MageLang Insitute, 1998
+ * @author Terence Parr, <a href=http://www.MageLang.com>MageLang Institute</a>
+ * @author <br>John Lilley, <a href=http://www.Empathy.com>Empathy Software</a>
+ * @author <br><a href="mailto:pete@yamuna.demon.co.uk">Pete Wells</a>
+ */
+
+#include "antlr/CharScanner.hpp"
+#include "antlr/CommonToken.hpp"
+#include "antlr/MismatchedCharException.hpp"
+#include <map>
+
+#ifdef HAS_NOT_CCTYPE_H
+#include <ctype.h>
+#else
+#include <cctype>
+#endif
+
+#include <iostream>
+
+#ifdef HAS_NOT_CSTRING_H
+#include <string>
+#else
+#include <cstring>
+#endif
+#include <stdlib.h>
+
+ANTLR_BEGIN_NAMESPACE(antlr)
+ANTLR_C_USING(exit)
+ANTLR_C_USING(tolower)
+
+#ifdef ANTLR_REALLY_NO_STRCASECMP
+// Apparently, neither strcasecmp nor stricmp is standard, and Codewarrior
+// on the mac has neither...
+inline int strcasecmp(const char *s1, const char *s2)
+{
+ while (true)
+ {
+ char c1 = tolower(*s1++),
+ c2 = tolower(*s2++);
+ if (c1 < c2) return -1;
+ if (c1 > c2) return 1;
+ if (c1 == 0) return 0;
+ }
+}
+#else
+#ifdef NO_STRCASECMP
+ANTLR_C_USING(stricmp)
+#else
+ANTLR_C_USING(strcasecmp)
+#endif
+#endif
+
+CharScannerLiteralsLess::CharScannerLiteralsLess(const CharScanner* theScanner)
+: scanner(theScanner)
+{}
+
+bool CharScannerLiteralsLess::operator() (const ANTLR_USE_NAMESPACE(std)string& x,const ANTLR_USE_NAMESPACE(std)string& y) const
+{
+ if (scanner->getCaseSensitiveLiterals()) {
+ return ANTLR_USE_NAMESPACE(std)less<ANTLR_USE_NAMESPACE(std)string>()(x,y);
+ } else {
+#ifdef NO_STRCASECMP
+ return (stricmp(x.c_str(),y.c_str())<0);
+#else
+ return (strcasecmp(x.c_str(),y.c_str())<0);
+#endif
+ }
+}
+
+CharScanner::CharScanner(InputBuffer& cb)
+ : saveConsumedInput(true) //, caseSensitiveLiterals(true)
+ , literals(CharScannerLiteralsLess(this))
+ , inputState(new LexerInputState(cb))
+ , commitToPath(false)
+ , traceDepth(0)
+{
+ setTokenObjectFactory(&CommonToken::factory);
+}
+
+CharScanner::CharScanner(InputBuffer* cb)
+ : saveConsumedInput(true) //, caseSensitiveLiterals(true)
+ , literals(CharScannerLiteralsLess(this))
+ , inputState(new LexerInputState(cb))
+ , commitToPath(false)
+ , traceDepth(0)
+{
+ setTokenObjectFactory(&CommonToken::factory);
+}
+
+CharScanner::CharScanner(const LexerSharedInputState& state)
+ : saveConsumedInput(true) //, caseSensitiveLiterals(true)
+ , literals(CharScannerLiteralsLess(this))
+ , inputState(state)
+ , commitToPath(false)
+ , traceDepth(0)
+{
+ setTokenObjectFactory(&CommonToken::factory);
+}
+
+CharScanner::~CharScanner()
+{
+}
+
+void CharScanner::append(char c)
+{
+ if (saveConsumedInput) {
+ int l = text.length();
+ if ((l%256) == 0) text.reserve(l+256);
+ text.replace(l,0,&c,1);
+ }
+}
+
+void CharScanner::append(const ANTLR_USE_NAMESPACE(std)string& s)
+{
+ if (saveConsumedInput)
+ text+=s;
+}
+
+void CharScanner::commit()
+{
+ inputState->getInput().commit();
+}
+
+void CharScanner::consume()
+{
+ if (inputState->guessing == 0) {
+ int c = LA(1);
+ if (caseSensitive) {
+ append(c);
+ } else {
+ // use input.LA(), not LA(), to get original case
+ // CharScanner.LA() would toLower it.
+ append(inputState->getInput().LA(1));
+ }
+ if (c == '\t') {
+ tab();
+ }
+ else {
+ inputState->column++;
+ }
+ }
+ inputState->getInput().consume();
+}
+
+/** Consume chars until one matches the given char */
+void CharScanner::consumeUntil(int c)
+{
+ while (LA(1) != EOF_CHAR && LA(1) != c)
+ {
+ consume();
+ }
+}
+
+/** Consume chars until one matches the given set */
+void CharScanner::consumeUntil(const BitSet& set)
+{
+ while (LA(1) != EOF_CHAR && !set.member(LA(1))) {
+ consume();
+ }
+}
+
+bool CharScanner::getCaseSensitive() const
+{ return caseSensitive; }
+
+//bool CharScanner::getCaseSensitiveLiterals() const
+//{ return caseSensitiveLiterals; }
+
+int CharScanner::getColumn() const
+{ return inputState->column; }
+
+void CharScanner::setColumn(int c)
+{ inputState->column = c; }
+
+bool CharScanner::getCommitToPath() const
+{ return commitToPath; }
+
+const ANTLR_USE_NAMESPACE(std)string& CharScanner::getFilename() const
+{ return inputState->filename; }
+
+InputBuffer& CharScanner::getInputBuffer()
+{ return inputState->getInput(); }
+
+LexerSharedInputState CharScanner::getInputState()
+{ return inputState; }
+
+int CharScanner::getLine() const
+{ return inputState->line; }
+
+/** return a copy of the current text buffer */
+const ANTLR_USE_NAMESPACE(std)string& CharScanner::getText() const
+{ return text; }
+
+RefToken CharScanner::getTokenObject() const
+{ return _returnToken; }
+
+RefToken CharScanner::makeToken(int t)
+{
+ RefToken tok=tokenFactory();
+ tok->setType(t);
+ tok->setColumn(inputState->tokenStartColumn);
+ tok->setLine(inputState->tokenStartLine);
+ return tok;
+}
+
+int CharScanner::mark()
+{
+ return inputState->getInput().mark();
+}
+
+void CharScanner::match(int c)
+{
+ if ( LA(1) != c ) {
+ throw MismatchedCharException(LA(1),c,false,this);
+ }
+ consume();
+}
+
+void CharScanner::match(const BitSet& b)
+{
+ if (!b.member(LA(1))) {
+ throw MismatchedCharException(LA(1),b,false,this);
+ }
+ consume();
+}
+
+void CharScanner::match(const ANTLR_USE_NAMESPACE(std)string& s)
+{
+ int len = s.length();
+ for (int i=0; i<len; i++) {
+ if ( LA(1) != s[i] ) {
+ throw MismatchedCharException(LA(1),s[i],false,this);
+ }
+ consume();
+ }
+}
+
+void CharScanner::matchNot(int c)
+{
+ if ( LA(1) == c ) {
+ throw MismatchedCharException(LA(1),c,true,this);
+ }
+ consume();
+}
+
+void CharScanner::matchRange(int c1, int c2)
+{
+ if (LA(1)<c1 || LA(1)>c2) {
+ throw MismatchedCharException(LA(1),c1,c2,false,this);
+ }
+ consume();
+}
+
+void CharScanner::newline()
+{
+ ++inputState->line;
+ inputState->column=1;
+}
+
+/** advance the current column number by an appropriate amount.
+ * If you do not override this to specify how much to jump for
+ * a tab, then tabs are counted as one char. This method is
+ * called from consume().
+ */
+void CharScanner::tab() {
+ // update inputState->column as function of
+ // inputState->column and tab stops.
+ // For example, if tab stops are columns 1 and 5 etc...
+ // and column is 3, then add 2 to column.
+ ++inputState->column;
+}
+
+void CharScanner::panic()
+{
+ ANTLR_USE_NAMESPACE(std)cerr << "CharScanner: panic" << ANTLR_USE_NAMESPACE(std)endl;
+ exit(1);
+}
+
+void CharScanner::panic(const ANTLR_USE_NAMESPACE(std)string& s)
+{
+ ANTLR_USE_NAMESPACE(std)cerr << "CharScanner: panic: " << s.c_str() << ANTLR_USE_NAMESPACE(std)endl;
+ exit(1);
+}
+
+/** Report exception errors caught in nextToken() */
+void CharScanner::reportError(const RecognitionException& ex)
+{
+ ANTLR_USE_NAMESPACE(std)cerr << ex.toString().c_str() << ANTLR_USE_NAMESPACE(std)endl;
+}
+
+/** Parser error-reporting function can be overridden in subclass */
+void CharScanner::reportError(const ANTLR_USE_NAMESPACE(std)string& s)
+{
+ if (getFilename().empty())
+ ANTLR_USE_NAMESPACE(std)cerr << "error: " << s.c_str() << ANTLR_USE_NAMESPACE(std)endl;
+ else
+ ANTLR_USE_NAMESPACE(std)cerr << getFilename().c_str() << ": error: " << s.c_str() << ANTLR_USE_NAMESPACE(std)endl;
+}
+
+/** Parser warning-reporting function can be overridden in subclass */
+void CharScanner::reportWarning(const ANTLR_USE_NAMESPACE(std)string& s)
+{
+ if (getFilename().empty())
+ ANTLR_USE_NAMESPACE(std)cerr << "warning: " << s.c_str() << ANTLR_USE_NAMESPACE(std)endl;
+ else
+ ANTLR_USE_NAMESPACE(std)cerr << getFilename().c_str() << ": warning: " << s.c_str() << ANTLR_USE_NAMESPACE(std)endl;
+}
+
+void CharScanner::resetText()
+{
+ text="";
+ inputState->tokenStartColumn = inputState->column;
+ inputState->tokenStartLine = inputState->line;
+}
+
+void CharScanner::rewind(int pos)
+{
+ inputState->getInput().rewind(pos);
+}
+
+void CharScanner::setCaseSensitive(bool t)
+{
+ caseSensitive = t;
+}
+
+void CharScanner::setCommitToPath(bool commit)
+{
+ commitToPath = commit;
+}
+
+void CharScanner::setFilename(const ANTLR_USE_NAMESPACE(std)string& f)
+{ inputState->filename=f; }
+
+void CharScanner::setInputState(LexerSharedInputState state)
+{ inputState = state; }
+
+void CharScanner::setLine(int l)
+{ inputState->line=l; }
+
+void CharScanner::setText(const ANTLR_USE_NAMESPACE(std)string& s)
+{ text=s; }
+
+void CharScanner::setTokenObjectFactory(factory_type factory)
+{ tokenFactory=factory; }
+
+/** Test the token text against the literals table
+ * Override this method to perform a different literals test */
+int CharScanner::testLiteralsTable(int ttype) const
+{
+ ANTLR_USE_NAMESPACE(std)map<ANTLR_USE_NAMESPACE(std)string,int,CharScannerLiteralsLess>::const_iterator i = literals.find(text);
+ if (i != literals.end())
+ ttype = (*i).second;
+ return ttype;
+}
+
+/** Test the text passed in against the literals table
+ * Override this method to perform a different literals test
+ * This is used primarily when you want to test a portion of
+ * a token.
+ */
+int CharScanner::testLiteralsTable(const ANTLR_USE_NAMESPACE(std)string& text_, int ttype) const
+{
+ ANTLR_USE_NAMESPACE(std)map<ANTLR_USE_NAMESPACE(std)string,int,CharScannerLiteralsLess>::const_iterator i = literals.find(text_);
+ if (i != literals.end())
+ ttype = (*i).second;
+ return ttype;
+}
+
+/** Override this method to get more specific case handling */
+int CharScanner::toLower(int c) const
+{
+ return tolower(c);
+}
+
+void CharScanner::traceIndent()
+{
+ for( int i = 0; i < traceDepth; i++ )
+ ANTLR_USE_NAMESPACE(std)cout << " ";
+}
+
+void CharScanner::traceIn(const ANTLR_USE_NAMESPACE(std)string& rname)
+{
+ traceDepth++;
+ traceIndent();
+ ANTLR_USE_NAMESPACE(std)cout << "> lexer " << rname.c_str() << "; c==" << LA(1) << ANTLR_USE_NAMESPACE(std)endl;
+}
+
+void CharScanner::traceOut(const ANTLR_USE_NAMESPACE(std)string& rname)
+{
+ traceIndent();
+ ANTLR_USE_NAMESPACE(std)cout << "< lexer " << rname.c_str() << "; c==" << LA(1) << ANTLR_USE_NAMESPACE(std)endl;
+ traceDepth--;
+}
+
+void CharScanner::uponEOF()
+{
+}
+
+#ifndef NO_STATIC_CONSTS
+const int CharScanner::NO_CHAR;
+const int CharScanner::EOF_CHAR;
+#endif
+
+ANTLR_END_NAMESPACE
+
diff --git a/poxml/antlr/src/CommonAST.cpp b/poxml/antlr/src/CommonAST.cpp
new file mode 100644
index 00000000..3a4067e3
--- /dev/null
+++ b/poxml/antlr/src/CommonAST.cpp
@@ -0,0 +1,100 @@
+/**
+ * <b>SOFTWARE RIGHTS</b>
+ * <p>
+ * ANTLR 2.6.0 MageLang Insitute, 1998
+ * <p>
+ * We reserve no legal rights to the ANTLR--it is fully in the
+ * public domain. An individual or company may do whatever
+ * they wish with source code distributed with ANTLR or the
+ * code generated by ANTLR, including the incorporation of
+ * ANTLR, or its output, into commerical software.
+ * <p>
+ * We encourage users to develop software with ANTLR. However,
+ * we do ask that credit is given to us for developing
+ * ANTLR. By "credit", we mean that if you use ANTLR or
+ * incorporate any source code into one of your programs
+ * (commercial product, research project, or otherwise) that
+ * you acknowledge this fact somewhere in the documentation,
+ * research report, etc... If you like ANTLR and have
+ * developed a nice tool with the output, please mention that
+ * you developed it using ANTLR. In addition, we ask that the
+ * headers remain intact in our source code. As long as these
+ * guidelines are kept, we expect to continue enhancing this
+ * system and expect to make other tools available as they are
+ * completed.
+ * <p>
+ * The ANTLR gang:
+ * @version ANTLR 2.6.0 MageLang Insitute, 1998
+ * @author Terence Parr, <a href=http://www.MageLang.com>MageLang Institute</a>
+ * @author <br>John Lilley, <a href=http://www.Empathy.com>Empathy Software</a>
+ * @author <br><a href="mailto:pete@yamuna.demon.co.uk">Pete Wells</a>
+ */
+
+#include "antlr/config.hpp"
+#include "antlr/CommonAST.hpp"
+
+ANTLR_BEGIN_NAMESPACE(antlr)
+
+CommonAST::CommonAST()
+: BaseAST(),
+ ttype( Token::INVALID_TYPE ),
+ text("")
+{
+}
+
+CommonAST::CommonAST(RefToken t)
+: BaseAST(),
+ ttype( t->getType() ),
+ text( t->getText() )
+{
+}
+
+CommonAST::~CommonAST()
+{
+}
+
+ANTLR_USE_NAMESPACE(std)string CommonAST::getText() const
+{
+ return text;
+}
+
+int CommonAST::getType() const
+{
+ return ttype;
+}
+
+void CommonAST::initialize(int t,const ANTLR_USE_NAMESPACE(std)string& txt)
+{
+ setType(t);
+ setText(txt);
+}
+
+void CommonAST::initialize(RefAST t)
+{
+ setType(t->getType());
+ setText(t->getText());
+}
+
+void CommonAST::initialize(RefToken t)
+{
+ setType(t->getType());
+ setText(t->getText());
+}
+
+void CommonAST::setText(const ANTLR_USE_NAMESPACE(std)string& txt)
+{
+ text = txt;
+}
+
+void CommonAST::setType(int type)
+{
+ ttype = type;
+}
+
+RefAST CommonAST::factory()
+{
+ return RefAST(new CommonAST);
+}
+
+ANTLR_END_NAMESPACE
+
diff --git a/poxml/antlr/src/CommonASTWithHiddenTokens.cpp b/poxml/antlr/src/CommonASTWithHiddenTokens.cpp
new file mode 100644
index 00000000..d6c242d2
--- /dev/null
+++ b/poxml/antlr/src/CommonASTWithHiddenTokens.cpp
@@ -0,0 +1,29 @@
+#include "antlr/config.hpp"
+#include "antlr/CommonASTWithHiddenTokens.hpp"
+#include "antlr/CommonHiddenStreamToken.hpp"
+
+ANTLR_BEGIN_NAMESPACE(antlr)
+
+void CommonASTWithHiddenTokens::initialize(int t,const ANTLR_USE_NAMESPACE(std)string& txt)
+{
+ CommonAST::initialize(t,txt);
+}
+
+void CommonASTWithHiddenTokens::initialize(RefAST t)
+{
+ CommonAST::initialize(t);
+}
+
+void CommonASTWithHiddenTokens::initialize(RefToken t)
+{
+ CommonAST::initialize(t);
+ hiddenBefore = static_cast<CommonHiddenStreamToken*>(t.get())->getHiddenBefore();
+ hiddenAfter = static_cast<CommonHiddenStreamToken*>(t.get())->getHiddenAfter();
+}
+
+RefAST CommonASTWithHiddenTokens::factory()
+{
+ return RefAST(new CommonASTWithHiddenTokens);
+}
+
+ANTLR_END_NAMESPACE
diff --git a/poxml/antlr/src/CommonHiddenStreamToken.cpp b/poxml/antlr/src/CommonHiddenStreamToken.cpp
new file mode 100644
index 00000000..d33927cc
--- /dev/null
+++ b/poxml/antlr/src/CommonHiddenStreamToken.cpp
@@ -0,0 +1,46 @@
+#include "antlr/CommonHiddenStreamToken.hpp"
+
+ANTLR_BEGIN_NAMESPACE(antlr)
+
+CommonHiddenStreamToken::CommonHiddenStreamToken()
+: CommonToken()
+{
+}
+
+CommonHiddenStreamToken::CommonHiddenStreamToken(int t, const ANTLR_USE_NAMESPACE(std)string& txt)
+: CommonToken(t,txt)
+{
+}
+
+CommonHiddenStreamToken::CommonHiddenStreamToken(const ANTLR_USE_NAMESPACE(std)string& s)
+: CommonToken(s)
+{
+}
+
+RefToken CommonHiddenStreamToken::getHiddenAfter()
+{
+ return hiddenAfter;
+}
+
+RefToken CommonHiddenStreamToken::getHiddenBefore()
+{
+ return hiddenBefore;
+}
+
+RefToken CommonHiddenStreamToken::factory()
+{
+ return RefToken(new CommonHiddenStreamToken);
+}
+
+void CommonHiddenStreamToken::setHiddenAfter(RefToken t)
+{
+ hiddenAfter = t;
+}
+
+void CommonHiddenStreamToken::setHiddenBefore(RefToken t)
+{
+ hiddenBefore = t;
+}
+
+ANTLR_END_NAMESPACE
+
diff --git a/poxml/antlr/src/CommonToken.cpp b/poxml/antlr/src/CommonToken.cpp
new file mode 100644
index 00000000..ff60bd79
--- /dev/null
+++ b/poxml/antlr/src/CommonToken.cpp
@@ -0,0 +1,81 @@
+/**
+ * <b>SOFTWARE RIGHTS</b>
+ * <p>
+ * ANTLR 2.6.0 MageLang Insitute, 1998
+ * <p>
+ * We reserve no legal rights to the ANTLR--it is fully in the
+ * public domain. An individual or company may do whatever
+ * they wish with source code distributed with ANTLR or the
+ * code generated by ANTLR, including the incorporation of
+ * ANTLR, or its output, into commerical software.
+ * <p>
+ * We encourage users to develop software with ANTLR. However,
+ * we do ask that credit is given to us for developing
+ * ANTLR. By "credit", we mean that if you use ANTLR or
+ * incorporate any source code into one of your programs
+ * (commercial product, research project, or otherwise) that
+ * you acknowledge this fact somewhere in the documentation,
+ * research report, etc... If you like ANTLR and have
+ * developed a nice tool with the output, please mention that
+ * you developed it using ANTLR. In addition, we ask that the
+ * headers remain intact in our source code. As long as these
+ * guidelines are kept, we expect to continue enhancing this
+ * system and expect to make other tools available as they are
+ * completed.
+ * <p>
+ * The ANTLR gang:
+ * @version ANTLR 2.6.0 MageLang Insitute, 1998
+ * @author Terence Parr, <a href=http://www.MageLang.com>MageLang Institute</a>
+ * @author <br>John Lilley, <a href=http://www.Empathy.com>Empathy Software</a>
+ * @author <br><a href="mailto:pete@yamuna.demon.co.uk">Pete Wells</a>
+ */
+
+#include "antlr/CommonToken.hpp"
+#include "antlr/String.hpp"
+
+ANTLR_BEGIN_NAMESPACE(antlr)
+
+CommonToken::CommonToken() : Token(), line(1), col(1), text("")
+{}
+
+CommonToken::CommonToken(int t, const ANTLR_USE_NAMESPACE(std)string& txt)
+ : Token(t), line(1), col(1), text(txt)
+{}
+
+CommonToken::CommonToken(const ANTLR_USE_NAMESPACE(std)string& s)
+ : Token(), line(1), col(1), text(s)
+{}
+
+int CommonToken::getLine() const
+{ return line; }
+
+ANTLR_USE_NAMESPACE(std)string CommonToken::getText() const
+{ return text; }
+
+void CommonToken::setLine(int l)
+{ line=l; }
+
+void CommonToken::setText(const ANTLR_USE_NAMESPACE(std)string& s)
+{ text=s; }
+
+ANTLR_USE_NAMESPACE(std)string CommonToken::toString() const
+{
+ return "[\""+getText()+"\",<"+type+">,line="+line+"]";
+}
+
+int CommonToken::getColumn() const
+{ return col; }
+
+void CommonToken::setColumn(int c)
+{ col=c; }
+
+bool CommonToken::isInvalid() const
+{ return type==INVALID_TYPE; }
+
+RefToken CommonToken::factory()
+{
+ return RefToken(new CommonToken);
+}
+
+ANTLR_END_NAMESPACE
+
diff --git a/poxml/antlr/src/InputBuffer.cpp b/poxml/antlr/src/InputBuffer.cpp
new file mode 100644
index 00000000..058c32ab
--- /dev/null
+++ b/poxml/antlr/src/InputBuffer.cpp
@@ -0,0 +1,109 @@
+/**
+ * <b>SOFTWARE RIGHTS</b>
+ * <p>
+ * ANTLR 2.6.0 MageLang Insitute, 1998
+ * <p>
+ * We reserve no legal rights to the ANTLR--it is fully in the
+ * public domain. An individual or company may do whatever
+ * they wish with source code distributed with ANTLR or the
+ * code generated by ANTLR, including the incorporation of
+ * ANTLR, or its output, into commerical software.
+ * <p>
+ * We encourage users to develop software with ANTLR. However,
+ * we do ask that credit is given to us for developing
+ * ANTLR. By "credit", we mean that if you use ANTLR or
+ * incorporate any source code into one of your programs
+ * (commercial product, research project, or otherwise) that
+ * you acknowledge this fact somewhere in the documentation,
+ * research report, etc... If you like ANTLR and have
+ * developed a nice tool with the output, please mention that
+ * you developed it using ANTLR. In addition, we ask that the
+ * headers remain intact in our source code. As long as these
+ * guidelines are kept, we expect to continue enhancing this
+ * system and expect to make other tools available as they are
+ * completed.
+ * <p>
+ * The ANTLR gang:
+ * @version ANTLR 2.6.0 MageLang Insitute, 1998
+ * @author Terence Parr, <a href=http://www.MageLang.com>MageLang Institute</a>
+ * @author <br>John Lilley, <a href=http://www.Empathy.com>Empathy Software</a>
+ * @author <br><a href="mailto:pete@yamuna.demon.co.uk">Pete Wells</a>
+ */
+
+/**A Stream of characters fed to the lexer from a InputStream that can
+ * be rewound via mark()/rewind() methods.
+ * <p>
+ * A dynamic array is used to buffer up all the input characters. Normally,
+ * "k" characters are stored in the buffer. More characters may be stored during
+ * guess mode (testing syntactic predicate), or when LT(i>k) is referenced.
+ * Consumption of characters is deferred. In other words, reading the next
+ * character is not done by conume(), but deferred until needed by LA or LT.
+ * <p>
+ *
+ * @see antlr.CharQueue
+ */
+
+#include "antlr/InputBuffer.hpp"
+
+ANTLR_BEGIN_NAMESPACE(antlr)
+
+/** Create a character buffer */
+InputBuffer::InputBuffer()
+: nMarkers(0), markerOffset(0), numToConsume(0)
+{}
+
+/** This method updates the state of the input buffer so that
+ * the text matched since the most recent mark() is no longer
+ * held by the buffer. So, you either do a mark/rewind for
+ * failed predicate or mark/commit to keep on parsing without
+ * rewinding the input.
+ */
+void InputBuffer::commit()
+{
+ nMarkers--;
+}
+
+/** Mark another character for deferred consumption */
+void InputBuffer::consume()
+{
+ numToConsume++;
+}
+
+/** Ensure that the character buffer is sufficiently full */
+void InputBuffer::fill(int amount)
+{
+ syncConsume();
+ // Fill the buffer sufficiently to hold needed characters
+ while (queue.entries() < amount + markerOffset) {
+ // Append the next character
+ queue.append(getChar());
+ }
+}
+
+bool InputBuffer::isMarked() const
+{
+ return (nMarkers != 0);
+}
+
+/**Return an integer marker that can be used to rewind the buffer to
+ * its current state.
+ */
+int InputBuffer::mark()
+{
+ syncConsume();
+ nMarkers++;
+ return markerOffset;
+}
+
+/**Rewind the character buffer to a marker.
+ * @param mark Marker returned previously from mark()
+ */
+void InputBuffer::rewind(int mark)
+{
+ syncConsume();
+ markerOffset = mark;
+ nMarkers--;
+}
+
+ANTLR_END_NAMESPACE
+
diff --git a/poxml/antlr/src/LLkParser.cpp b/poxml/antlr/src/LLkParser.cpp
new file mode 100644
index 00000000..2f21cd8b
--- /dev/null
+++ b/poxml/antlr/src/LLkParser.cpp
@@ -0,0 +1,105 @@
+/**
+ * <b>SOFTWARE RIGHTS</b>
+ * <p>
+ * ANTLR 2.6.0 MageLang Insitute, 1998
+ * <p>
+ * We reserve no legal rights to the ANTLR--it is fully in the
+ * public domain. An individual or company may do whatever
+ * they wish with source code distributed with ANTLR or the
+ * code generated by ANTLR, including the incorporation of
+ * ANTLR, or its output, into commerical software.
+ * <p>
+ * We encourage users to develop software with ANTLR. However,
+ * we do ask that credit is given to us for developing
+ * ANTLR. By "credit", we mean that if you use ANTLR or
+ * incorporate any source code into one of your programs
+ * (commercial product, research project, or otherwise) that
+ * you acknowledge this fact somewhere in the documentation,
+ * research report, etc... If you like ANTLR and have
+ * developed a nice tool with the output, please mention that
+ * you developed it using ANTLR. In addition, we ask that the
+ * headers remain intact in our source code. As long as these
+ * guidelines are kept, we expect to continue enhancing this
+ * system and expect to make other tools available as they are
+ * completed.
+ * <p>
+ * The ANTLR gang:
+ * @version ANTLR 2.6.0 MageLang Insitute, 1998
+ * @author Terence Parr, <a href=http://www.MageLang.com>MageLang Institute</a>
+ * @author <br>John Lilley, <a href=http://www.Empathy.com>Empathy Software</a>
+ * @author <br><a href="mailto:pete@yamuna.demon.co.uk">Pete Wells</a>
+ */
+
+#include "antlr/LLkParser.hpp"
+#include <iostream>
+
+ANTLR_BEGIN_NAMESPACE(antlr)
+
+/**An LL(k) parser.
+ *
+ * @see antlr.Token
+ * @see antlr.TokenBuffer
+ * @see antlr.LL1Parser
+ */
+
+// LLkParser(int k_);
+
+LLkParser::LLkParser(const ParserSharedInputState& state, int k_)
+: Parser(state), k(k_)
+{}
+
+LLkParser::LLkParser(TokenBuffer& tokenBuf, int k_)
+: Parser(tokenBuf), k(k_)
+{}
+
+LLkParser::LLkParser(TokenStream& lexer, int k_)
+: Parser(new TokenBuffer(lexer)), k(k_)
+{
+}
+
+/**Consume another token from the input stream. Can only write sequentially!
+ * If you need 3 tokens ahead, you must consume() 3 times.
+ * <p>
+ * Note that it is possible to overwrite tokens that have not been matched.
+ * For example, calling consume() 3 times when k=2, means that the first token
+ * consumed will be overwritten with the 3rd.
+ */
+void LLkParser::consume()
+{ inputState->getInput().consume(); }
+
+int LLkParser::LA(int i)
+{ return inputState->getInput().LA(i); }
+
+RefToken LLkParser::LT(int i)
+{ return inputState->getInput().LT(i); }
+
+void LLkParser::trace(const ANTLR_USE_NAMESPACE(std)string& ee, const ANTLR_USE_NAMESPACE(std)string& rname)
+{
+ traceIndent();
+
+ ANTLR_USE_NAMESPACE(std)cout << ee.c_str() << rname.c_str() << ((inputState->guessing>0)?"; [guessing]":"; ");
+
+ for (int i = 1; i <= k; i++)
+ {
+ if (i != 1) {
+ ANTLR_USE_NAMESPACE(std)cout << ", ";
+ }
+ ANTLR_USE_NAMESPACE(std)cout << "LA(" << i << ")==" << LT(i)->getText().c_str();
+ }
+
+ ANTLR_USE_NAMESPACE(std)cout << ANTLR_USE_NAMESPACE(std)endl;
+}
+
+void LLkParser::traceIn(const ANTLR_USE_NAMESPACE(std)string& rname)
+{
+ traceDepth++;
+ trace("> ",rname);
+}
+
+void LLkParser::traceOut(const ANTLR_USE_NAMESPACE(std)string& rname)
+{
+ trace("< ",rname);
+ traceDepth--;
+}
+
+ANTLR_END_NAMESPACE
diff --git a/poxml/antlr/src/LexerSharedInputState.cpp b/poxml/antlr/src/LexerSharedInputState.cpp
new file mode 100644
index 00000000..a95f33a8
--- /dev/null
+++ b/poxml/antlr/src/LexerSharedInputState.cpp
@@ -0,0 +1,55 @@
+#include "antlr/LexerSharedInputState.hpp"
+#include "antlr/CharBuffer.hpp"
+
+ANTLR_BEGIN_NAMESPACE(antlr)
+
+/** This object contains the data associated with an
+ * input stream of characters. Multiple lexers
+ * share a single LexerSharedInputState to lex
+ * the same input stream.
+ */
+
+LexerInputState::LexerInputState(InputBuffer* inbuf)
+: column(1)
+, line(1)
+, tokenStartColumn(1)
+, tokenStartLine(1)
+, guessing(0)
+, filename("")
+, input(inbuf)
+, inputResponsible(true)
+{
+}
+
+LexerInputState::LexerInputState(InputBuffer& inbuf)
+: column(1)
+, line(1)
+, tokenStartColumn(1)
+, tokenStartLine(1)
+, guessing(0)
+, filename("")
+, input(&inbuf)
+, inputResponsible(false)
+{
+}
+
+LexerInputState::LexerInputState(ANTLR_USE_NAMESPACE(std)istream& in)
+: column(1)
+, line(1)
+, tokenStartColumn(1)
+, tokenStartLine(1)
+, guessing(0)
+, filename("")
+, input(new CharBuffer(in))
+, inputResponsible(true)
+{
+}
+
+LexerInputState::~LexerInputState()
+{
+ if (inputResponsible)
+ delete input;
+}
+
+ANTLR_END_NAMESPACE
+
diff --git a/poxml/antlr/src/Makefile.am b/poxml/antlr/src/Makefile.am
new file mode 100644
index 00000000..7a5d2426
--- /dev/null
+++ b/poxml/antlr/src/Makefile.am
@@ -0,0 +1,39 @@
+
+# Make #include <antlr/xxx> work..
+INCLUDES=-I$(srcdir)/..
+KDE_CXXFLAGS = $(USE_EXCEPTIONS)
+
+noinst_LTLIBRARIES = libantlr.la
+
+libantlr_la_LDFLAGS = -no-undefined
+
+libantlr_la_SOURCES = \
+ ANTLRException.cpp \
+ ASTFactory.cpp \
+ ASTRefCount.cpp \
+ BaseAST.cpp \
+ BitSet.cpp \
+ CharBuffer.cpp \
+ CharScanner.cpp \
+ CommonAST.cpp \
+ CommonASTWithHiddenTokens.cpp \
+ CommonHiddenStreamToken.cpp \
+ CommonToken.cpp \
+ InputBuffer.cpp \
+ LLkParser.cpp \
+ LexerSharedInputState.cpp \
+ MismatchedCharException.cpp \
+ MismatchedTokenException.cpp \
+ NoViableAltException.cpp \
+ NoViableAltForCharException.cpp \
+ Parser.cpp \
+ ParserSharedInputState.cpp \
+ RecognitionException.cpp \
+ String.cpp \
+ Token.cpp \
+ TokenBuffer.cpp \
+ TokenStreamBasicFilter.cpp \
+ TokenStreamHiddenTokenFilter.cpp \
+ TokenStreamSelector.cpp \
+ TreeParser.cpp \
+ TreeParserSharedInputState.cpp
diff --git a/poxml/antlr/src/MismatchedCharException.cpp b/poxml/antlr/src/MismatchedCharException.cpp
new file mode 100644
index 00000000..4dede0e8
--- /dev/null
+++ b/poxml/antlr/src/MismatchedCharException.cpp
@@ -0,0 +1,153 @@
+/**
+ * <b>SOFTWARE RIGHTS</b>
+ * <p>
+ * ANTLR 2.6.0 MageLang Insitute, 1999
+ * <p>
+ * We reserve no legal rights to the ANTLR--it is fully in the
+ * public domain. An individual or company may do whatever
+ * they wish with source code distributed with ANTLR or the
+ * code generated by ANTLR, including the incorporation of
+ * ANTLR, or its output, into commerical software.
+ * <p>
+ * We encourage users to develop software with ANTLR. However,
+ * we do ask that credit is given to us for developing
+ * ANTLR. By "credit", we mean that if you use ANTLR or
+ * incorporate any source code into one of your programs
+ * (commercial product, research project, or otherwise) that
+ * you acknowledge this fact somewhere in the documentation,
+ * research report, etc... If you like ANTLR and have
+ * developed a nice tool with the output, please mention that
+ * you developed it using ANTLR. In addition, we ask that the
+ * headers remain intact in our source code. As long as these
+ * guidelines are kept, we expect to continue enhancing this
+ * system and expect to make other tools available as they are
+ * completed.
+ * <p>
+ * The ANTLR gang:
+ * @version ANTLR 2.6.0 MageLang Insitute, 1999
+ * @author Terence Parr, <a href=http://www.MageLang.com>MageLang Institute</a>
+ * @author <br>John Lilley, <a href=http://www.Empathy.com>Empathy Software</a>
+ * @author <br><a href="mailto:pete@yamuna.demon.co.uk">Pete Wells</a>
+ */
+
+#include "antlr/MismatchedCharException.hpp"
+#include "antlr/String.hpp"
+
+ANTLR_BEGIN_NAMESPACE(antlr)
+
+MismatchedCharException::MismatchedCharException()
+: RecognitionException("Mismatched char")
+{}
+
+// Expected range / not range
+MismatchedCharException::MismatchedCharException(
+ int c,
+ int lower,
+ int upper_,
+ bool matchNot,
+ CharScanner* scanner_
+) : RecognitionException("Mismatched char",
+ scanner_->getFilename(),
+ scanner_->getLine(),
+ scanner_->getColumn())
+ , mismatchType(matchNot ? NOT_RANGE : RANGE)
+ , foundChar(c)
+ , expecting(lower)
+ , upper(upper_)
+ , scanner(scanner_)
+{
+}
+
+// Expected token / not token
+MismatchedCharException::MismatchedCharException(
+ int c,
+ int expecting_,
+ bool matchNot,
+ CharScanner* scanner_
+) : RecognitionException("Mismatched char",
+ scanner_->getFilename(),
+ scanner_->getLine(),
+ scanner_->getColumn())
+ , mismatchType(matchNot ? NOT_CHAR : CHAR)
+ , foundChar(c)
+ , expecting(expecting_)
+ , scanner(scanner_)
+{
+}
+
+// Expected BitSet / not BitSet
+MismatchedCharException::MismatchedCharException(
+ int c,
+ BitSet set_,
+ bool matchNot,
+ CharScanner* scanner_
+) : RecognitionException("Mismatched char",
+ scanner_->getFilename(),
+ scanner_->getLine(),
+ scanner_->getColumn())
+ , mismatchType(matchNot ? NOT_SET : SET)
+ , foundChar(c)
+ , set(set_)
+ , scanner(scanner_)
+{
+}
+
+MismatchedCharException::MismatchedCharException(
+ const ANTLR_USE_NAMESPACE(std)string& s,
+ int line
+) : RecognitionException(s)
+{
+}
+
+/**
+ * Returns the error message that happened on the line/col given.
+ * Copied from toString().
+ */
+ANTLR_USE_NAMESPACE(std)string MismatchedCharException::getMessage() const
+{
+ ANTLR_USE_NAMESPACE(std)string s;
+
+ switch (mismatchType) {
+ case CHAR :
+ s += "expecting '" + charName(expecting) + "', found '" + charName(foundChar) + "'";
+ break;
+ case NOT_CHAR :
+ s += "expecting anything but '" + charName(expecting) + "'; got it anyway";
+ break;
+ case RANGE :
+ s += "expecting token in range: '" + charName(expecting) + "'..'" + charName(upper) + "', found '" + charName(foundChar) + "'";
+ break;
+ case NOT_RANGE :
+ s += "expecting token NOT in range: " + charName(expecting) + "'..'" + charName(upper) + "', found '" + charName(foundChar) + "'";
+ break;
+ case SET :
+ case NOT_SET :
+ {
+ s += ANTLR_USE_NAMESPACE(std)string("expecting ") + (mismatchType == NOT_SET ? "NOT " : "") + "one of (";
+ ANTLR_USE_NAMESPACE(std)vector<int> elems = set.toArray();
+ for (int i = 0; i < (int) elems.size(); i++) {
+ s += " '";
+ s += charName(elems[i]);
+ s += "'";
+ }
+ s += "), found '" + charName(foundChar) + "'";
+ }
+ break;
+ default :
+ s += RecognitionException::getMessage();
+ break;
+ }
+
+ return s;
+}
+
+#ifndef NO_STATIC_CONSTS
+const int MismatchedCharException::CHAR;
+const int MismatchedCharException::NOT_CHAR;
+const int MismatchedCharException::RANGE;
+const int MismatchedCharException::NOT_RANGE;
+const int MismatchedCharException::SET;
+const int MismatchedCharException::NOT_SET;
+#endif
+
+ANTLR_END_NAMESPACE
diff --git a/poxml/antlr/src/MismatchedTokenException.cpp b/poxml/antlr/src/MismatchedTokenException.cpp
new file mode 100644
index 00000000..b8b10808
--- /dev/null
+++ b/poxml/antlr/src/MismatchedTokenException.cpp
@@ -0,0 +1,223 @@
+/**
+ * <b>SOFTWARE RIGHTS</b>
+ * <p>
+ * ANTLR 2.6.0 MageLang Insitute, 1998
+ * <p>
+ * We reserve no legal rights to the ANTLR--it is fully in the
+ * public domain. An individual or company may do whatever
+ * they wish with source code distributed with ANTLR or the
+ * code generated by ANTLR, including the incorporation of
+ * ANTLR, or its output, into commerical software.
+ * <p>
+ * We encourage users to develop software with ANTLR. However,
+ * we do ask that credit is given to us for developing
+ * ANTLR. By "credit", we mean that if you use ANTLR or
+ * incorporate any source code into one of your programs
+ * (commercial product, research project, or otherwise) that
+ * you acknowledge this fact somewhere in the documentation,
+ * research report, etc... If you like ANTLR and have
+ * developed a nice tool with the output, please mention that
+ * you developed it using ANTLR. In addition, we ask that the
+ * headers remain intact in our source code. As long as these
+ * guidelines are kept, we expect to continue enhancing this
+ * system and expect to make other tools available as they are
+ * completed.
+ * <p>
+ * The ANTLR gang:
+ * @version ANTLR 2.6.0 MageLang Insitute, 1998
+ * @author Terence Parr, <a href=http://www.MageLang.com>MageLang Institute</a>
+ * @author <br>John Lilley, <a href=http://www.Empathy.com>Empathy Software</a>
+ * @author <br><a href="mailto:pete@yamuna.demon.co.uk">Pete Wells</a>
+ */
+
+#include "antlr/MismatchedTokenException.hpp"
+#include "antlr/String.hpp"
+
+ANTLR_BEGIN_NAMESPACE(antlr)
+
+MismatchedTokenException::MismatchedTokenException()
+: RecognitionException("Mismatched Token: expecting any AST node","<AST>",1)
+, token(0)
+, node(nullASTptr)
+{
+}
+
+// Expected range / not range
+MismatchedTokenException::MismatchedTokenException(
+ const ANTLR_USE_NAMESPACE(std)vector<ANTLR_USE_NAMESPACE(std)string>& tokenNames_,
+ RefAST node_,
+ int lower,
+ int upper_,
+ bool matchNot
+) : RecognitionException("Mismatched Token")
+ , tokenNames(tokenNames_)
+ , token(0)
+ , node(node_)
+ , tokenText( (node_ ? node_->toString(): ANTLR_USE_NAMESPACE(std)string("<empty tree>")) )
+ , mismatchType(matchNot ? NOT_RANGE : RANGE)
+ , expecting(lower)
+ , upper(upper_)
+{
+ fileName = "<AST>";
+}
+
+// Expected token / not token
+MismatchedTokenException::MismatchedTokenException(
+ const ANTLR_USE_NAMESPACE(std)vector<ANTLR_USE_NAMESPACE(std)string>& tokenNames_,
+ RefAST node_,
+ int expecting_,
+ bool matchNot
+) : RecognitionException("Mismatched Token")
+ , tokenNames(tokenNames_)
+ , token(0)
+ , node(node_)
+ , tokenText( (node_ ? node_->toString(): ANTLR_USE_NAMESPACE(std)string("<empty tree>")) )
+ , mismatchType(matchNot ? NOT_TOKEN : TOKEN)
+ , expecting(expecting_)
+{
+ fileName = "<AST>";
+}
+
+// Expected BitSet / not BitSet
+MismatchedTokenException::MismatchedTokenException(
+ const ANTLR_USE_NAMESPACE(std)vector<ANTLR_USE_NAMESPACE(std)string>& tokenNames_,
+ RefAST node_,
+ BitSet set_,
+ bool matchNot
+) : RecognitionException("Mismatched Token")
+ , tokenNames(tokenNames_)
+ , token(0)
+ , node(node_)
+ , tokenText( (node_ ? node_->toString(): ANTLR_USE_NAMESPACE(std)string("<empty tree>")) )
+ , mismatchType(matchNot ? NOT_SET : SET)
+ , set(set_)
+{
+ fileName = "<AST>";
+}
+
+// Expected range / not range
+MismatchedTokenException::MismatchedTokenException(
+ const ANTLR_USE_NAMESPACE(std)vector<ANTLR_USE_NAMESPACE(std)string>& tokenNames_,
+ RefToken token_,
+ int lower,
+ int upper_,
+ bool matchNot,
+ const ANTLR_USE_NAMESPACE(std)string& fileName_
+) : RecognitionException("Mismatched Token",fileName_,token_->getLine(),token_->getColumn())
+ , tokenNames(tokenNames_)
+ , token(token_)
+ , node(nullASTptr)
+ , tokenText(token_->getText())
+ , mismatchType(matchNot ? NOT_RANGE : RANGE)
+ , expecting(lower)
+ , upper(upper_)
+{
+}
+
+// Expected token / not token
+MismatchedTokenException::MismatchedTokenException(
+ const ANTLR_USE_NAMESPACE(std)vector<ANTLR_USE_NAMESPACE(std)string>& tokenNames_,
+ RefToken token_,
+ int expecting_,
+ bool matchNot,
+ const ANTLR_USE_NAMESPACE(std)string& fileName_
+) : RecognitionException("Mismatched Token",fileName_,token_->getLine(),token_->getColumn())
+ , tokenNames(tokenNames_)
+ , token(token_)
+ , node(nullASTptr)
+ , tokenText(token_->getText())
+ , mismatchType(matchNot ? NOT_TOKEN : TOKEN)
+ , expecting(expecting_)
+{
+}
+
+// Expected BitSet / not BitSet
+MismatchedTokenException::MismatchedTokenException(
+ const ANTLR_USE_NAMESPACE(std)vector<ANTLR_USE_NAMESPACE(std)string>& tokenNames_,
+ RefToken token_,
+ BitSet set_,
+ bool matchNot,
+ const ANTLR_USE_NAMESPACE(std)string& fileName_
+) : RecognitionException("Mismatched Token",fileName_,token_->getLine(),token_->getColumn())
+ , tokenNames(tokenNames_)
+ , token(token_)
+ , node(nullASTptr)
+ , tokenText(token_->getText())
+ , mismatchType(matchNot ? NOT_SET : SET)
+ , set(set_)
+{
+}
+
+// deprecated As of ANTLR 2.7.0
+ANTLR_USE_NAMESPACE(std)string MismatchedTokenException::getErrorMessage() const
+{
+ return getMessage();
+}
+
+ANTLR_USE_NAMESPACE(std)string MismatchedTokenException::getMessage() const
+{
+ ANTLR_USE_NAMESPACE(std)string s;
+ switch (mismatchType) {
+ case TOKEN:
+ s += "expecting " + tokenName(expecting) + ", found '" + tokenText + "'";
+ break;
+ case NOT_TOKEN:
+ s += "expecting anything but " + tokenName(expecting) + "; got it anyway";
+ break;
+ case RANGE:
+ s += "expecting token in range: " + tokenName(expecting) + ".." + tokenName(upper) + ", found '" + tokenText + "'";
+ break;
+ case NOT_RANGE:
+ s += "expecting token NOT in range: " + tokenName(expecting) + ".." + tokenName(upper) + ", found '" + tokenText + "'";
+ break;
+ case SET:
+ case NOT_SET:
+ {
+ s += ANTLR_USE_NAMESPACE(std)string("expecting ") + (mismatchType == NOT_SET ? "NOT " : "") + "one of (";
+ ANTLR_USE_NAMESPACE(std)vector<int> elems = set.toArray();
+ for (int i = 0; i < (int) elems.size(); i++)
+ {
+ s += " ";
+ s += tokenName(elems[i]);
+ }
+ s += "), found '" + tokenText + "'";
+ }
+ break;
+ default:
+ s = RecognitionException::getMessage();
+ break;
+ }
+ return s;
+}
+
+ANTLR_USE_NAMESPACE(std)string MismatchedTokenException::tokenName(int tokenType) const
+{
+ if (tokenType == Token::INVALID_TYPE) {
+ return "<Set of tokens>";
+ }
+ else if (tokenType < 0 || tokenType >= (int) tokenNames.size()) {
+ return ANTLR_USE_NAMESPACE(std)string("<") + tokenType + ">";
+ }
+ else {
+ return tokenNames[tokenType];
+ }
+}
+
+ANTLR_USE_NAMESPACE(std)string MismatchedTokenException::toString() const {
+ if (token) {
+ return getFileLineString() + getMessage();
+ }
+ return getMessage();
+}
+
+#ifndef NO_STATIC_CONSTS
+const int MismatchedTokenException::TOKEN;
+const int MismatchedTokenException::NOT_TOKEN;
+const int MismatchedTokenException::RANGE;
+const int MismatchedTokenException::NOT_RANGE;
+const int MismatchedTokenException::SET;
+const int MismatchedTokenException::NOT_SET;
+#endif
+
+ANTLR_END_NAMESPACE
+
diff --git a/poxml/antlr/src/NoViableAltException.cpp b/poxml/antlr/src/NoViableAltException.cpp
new file mode 100644
index 00000000..433f4325
--- /dev/null
+++ b/poxml/antlr/src/NoViableAltException.cpp
@@ -0,0 +1,82 @@
+/**
+ * <b>SOFTWARE RIGHTS</b>
+ * <p>
+ * ANTLR 2.6.0 MageLang Insitute, 1998
+ * <p>
+ * We reserve no legal rights to the ANTLR--it is fully in the
+ * public domain. An individual or company may do whatever
+ * they wish with source code distributed with ANTLR or the
+ * code generated by ANTLR, including the incorporation of
+ * ANTLR, or its output, into commerical software.
+ * <p>
+ * We encourage users to develop software with ANTLR. However,
+ * we do ask that credit is given to us for developing
+ * ANTLR. By "credit", we mean that if you use ANTLR or
+ * incorporate any source code into one of your programs
+ * (commercial product, research project, or otherwise) that
+ * you acknowledge this fact somewhere in the documentation,
+ * research report, etc... If you like ANTLR and have
+ * developed a nice tool with the output, please mention that
+ * you developed it using ANTLR. In addition, we ask that the
+ * headers remain intact in our source code. As long as these
+ * guidelines are kept, we expect to continue enhancing this
+ * system and expect to make other tools available as they are
+ * completed.
+ * <p>
+ * The ANTLR gang:
+ * @version ANTLR 2.6.0 MageLang Insitute, 1998
+ * @author Terence Parr, <a href=http://www.MageLang.com>MageLang Institute</a>
+ * @author <br>John Lilley, <a href=http://www.Empathy.com>Empathy Software</a>
+ * @author <br><a href="mailto:pete@yamuna.demon.co.uk">Pete Wells</a>
+ */
+
+#include "antlr/NoViableAltException.hpp"
+#include "antlr/String.hpp"
+
+ANTLR_BEGIN_NAMESPACE(antlr)
+
+NoViableAltException::NoViableAltException(RefAST t)
+: RecognitionException("NoViableAlt")
+, token(0)
+, node(t)
+{
+ fileName = "<AST>";
+}
+
+NoViableAltException::NoViableAltException(RefToken t,const ANTLR_USE_NAMESPACE(std)string& fileName_)
+: RecognitionException("NoViableAlt") // line ")+t.getLine()+" token is "+t.getText())
+, token(t)
+, node(nullASTptr)
+{
+ line = t->getLine();
+ column = t->getColumn();
+ fileName = fileName_;
+}
+
+ANTLR_USE_NAMESPACE(std)string NoViableAltException::getErrorMessage() const
+{
+ return getMessage();
+}
+
+ANTLR_USE_NAMESPACE(std)string NoViableAltException::getMessage() const
+{
+ if (token)
+ return ANTLR_USE_NAMESPACE(std)string("unexpected token: ")+token->getText();
+
+ // must a tree parser error if token==null
+ if (!node) {
+ return "unexpected end of subtree";
+ }
+ return ANTLR_USE_NAMESPACE(std)string("unexpected AST node: ")+node->toString();
+}
+
+ANTLR_USE_NAMESPACE(std)string NoViableAltException::toString() const
+{
+ if (token)
+ return getFileLineString()+getMessage();
+ else
+ return getMessage();
+}
+
+ANTLR_END_NAMESPACE
+
diff --git a/poxml/antlr/src/NoViableAltForCharException.cpp b/poxml/antlr/src/NoViableAltForCharException.cpp
new file mode 100644
index 00000000..2ff9120f
--- /dev/null
+++ b/poxml/antlr/src/NoViableAltForCharException.cpp
@@ -0,0 +1,71 @@
+/**
+ * <b>SOFTWARE RIGHTS</b>
+ * <p>
+ * ANTLR 2.6.0 MageLang Institute
+ * <p>
+ * We reserve no legal rights to the ANTLR--it is fully in the
+ * public domain. An individual or company may do whatever
+ * they wish with source code distributed with ANTLR or the
+ * code generated by ANTLR, including the incorporation of
+ * ANTLR, or its output, into commerical software.
+ * <p>
+ * We encourage users to develop software with ANTLR. However,
+ * we do ask that credit is given to us for developing
+ * ANTLR. By "credit", we mean that if you use ANTLR or
+ * incorporate any source code into one of your programs
+ * (commercial product, research project, or otherwise) that
+ * you acknowledge this fact somewhere in the documentation,
+ * research report, etc... If you like ANTLR and have
+ * developed a nice tool with the output, please mention that
+ * you developed it using ANTLR. In addition, we ask that the
+ * headers remain intact in our source code. As long as these
+ * guidelines are kept, we expect to continue enhancing this
+ * system and expect to make other tools available as they are
+ * completed.
+ * <p>
+ * The ANTLR gang:
+ * @version ANTLR 2.6.0 MageLang Institute
+ * @author Terence Parr, <a href=http://www.MageLang.com>MageLang Institute</a>
+ * @author <br>John Lilley, <a href=http://www.Empathy.com>Empathy Software</a>
+ * @author <br><a href="mailto:pete@yamuna.demon.co.uk">Pete Wells</a>
+ */
+
+#include "antlr/NoViableAltForCharException.hpp"
+#include "antlr/String.hpp"
+
+ANTLR_BEGIN_NAMESPACE(antlr)
+
+NoViableAltForCharException::NoViableAltForCharException(int c, CharScanner* scanner)
+: RecognitionException("NoViableAlt")
+, foundChar(c)
+{
+ line = scanner->getLine();
+ fileName = scanner->getFilename();
+}
+
+NoViableAltForCharException::NoViableAltForCharException(int c, const ANTLR_USE_NAMESPACE(std)string& fileName_, int line_)
+: RecognitionException("NoViableAlt")
+, foundChar(c)
+{
+ line = line_;
+ fileName = fileName_;
+}
+
+/**
+ * @deprecated As of ANTLR 2.7.0
+ */
+ANTLR_USE_NAMESPACE(std)string NoViableAltForCharException::getErrorMessage() const
+{
+ return getMessage();
+}
+
+/**
+ * Returns a clean error message (no line number/column information)
+ */
+ANTLR_USE_NAMESPACE(std)string NoViableAltForCharException::getMessage() const
+{
+ return ANTLR_USE_NAMESPACE(std)string("unexpected char: ")+charName(foundChar);
+}
+
+ANTLR_END_NAMESPACE
+
diff --git a/poxml/antlr/src/Parser.cpp b/poxml/antlr/src/Parser.cpp
new file mode 100644
index 00000000..5a0388d4
--- /dev/null
+++ b/poxml/antlr/src/Parser.cpp
@@ -0,0 +1,304 @@
+/**
+ * <b>SOFTWARE RIGHTS</b>
+ * <p>
+ * ANTLR 2.6.0 MageLang Insitute, 1998
+ * <p>
+ * We reserve no legal rights to the ANTLR--it is fully in the
+ * public domain. An individual or company may do whatever
+ * they wish with source code distributed with ANTLR or the
+ * code generated by ANTLR, including the incorporation of
+ * ANTLR, or its output, into commerical software.
+ * <p>
+ * We encourage users to develop software with ANTLR. However,
+ * we do ask that credit is given to us for developing
+ * ANTLR. By "credit", we mean that if you use ANTLR or
+ * incorporate any source code into one of your programs
+ * (commercial product, research project, or otherwise) that
+ * you acknowledge this fact somewhere in the documentation,
+ * research report, etc... If you like ANTLR and have
+ * developed a nice tool with the output, please mention that
+ * you developed it using ANTLR. In addition, we ask that the
+ * headers remain intact in our source code. As long as these
+ * guidelines are kept, we expect to continue enhancing this
+ * system and expect to make other tools available as they are
+ * completed.
+ * <p>
+ * The ANTLR gang:
+ * @version ANTLR 2.6.0 MageLang Insitute, 1998
+ * @author Terence Parr, <a href=http://www.MageLang.com>MageLang Institute</a>
+ * @author <br>John Lilley, <a href=http://www.Empathy.com>Empathy Software</a>
+ * @author <br><a href="mailto:pete@yamuna.demon.co.uk">Pete Wells</a>
+ */
+
+#include "antlr/Parser.hpp"
+
+#include "antlr/BitSet.hpp"
+#include "antlr/TokenBuffer.hpp"
+#include "antlr/MismatchedTokenException.hpp"
+//#include "antlr/ASTFactory.hpp"
+#include <iostream>
+#include <stdlib.h>
+
+ANTLR_BEGIN_NAMESPACE(antlr)
+ANTLR_C_USING(exit)
+
+/**A generic ANTLR parser (LL(k) for k>=1) containing a bunch of
+ * utility routines useful at any lookahead depth. We distinguish between
+ * the LL(1) and LL(k) parsers because of efficiency. This may not be
+ * necessary in the near future.
+ *
+ * Each parser object contains the state of the parse including a lookahead
+ * cache (the form of which is determined by the subclass), whether or
+ * not the parser is in guess mode, where tokens come from, etc...
+ *
+ * <p>
+ * During <b>guess</b> mode, the current lookahead token(s) and token type(s)
+ * cache must be saved because the token stream may not have been informed
+ * to save the token (via <tt>mark</tt>) before the <tt>try</tt> block.
+ * Guessing is started by:
+ * <ol>
+ * <li>saving the lookahead cache.
+ * <li>marking the current position in the TokenBuffer.
+ * <li>increasing the guessing level.
+ * </ol>
+ *
+ * After guessing, the parser state is restored by:
+ * <ol>
+ * <li>restoring the lookahead cache.
+ * <li>rewinding the TokenBuffer.
+ * <li>decreasing the guessing level.
+ * </ol>
+ *
+ * @see antlr.Token
+ * @see antlr.TokenBuffer
+ * @see antlr.TokenStream
+ * @see antlr.LL1Parser
+ * @see antlr.LLkParser
+ */
+
+bool DEBUG_PARSER=false;
+
+Parser::Parser(TokenBuffer& input)
+: inputState(new ParserInputState(input)), traceDepth(0)
+{
+}
+
+Parser::Parser(TokenBuffer* input)
+: inputState(new ParserInputState(input)), traceDepth(0)
+{
+}
+
+Parser::Parser(const ParserSharedInputState& state)
+: inputState(state), traceDepth(0)
+{
+}
+
+Parser::~Parser()
+{
+}
+
+void Parser::setTokenNames(const char** tokenNames_)
+{
+ while (*tokenNames_) {
+ tokenNames.push_back(*(tokenNames_++));
+ }
+}
+
+/** Consume tokens until one matches the given token */
+void Parser::consumeUntil(int tokenType)
+{
+ while (LA(1) != Token::EOF_TYPE && LA(1) != tokenType)
+ consume();
+}
+
+/** Consume tokens until one matches the given token set */
+void Parser::consumeUntil(const BitSet& set)
+{
+ while (LA(1) != Token::EOF_TYPE && !set.member(LA(1)))
+ consume();
+}
+
+/** Get the AST return value squirreled away in the parser */
+RefAST Parser::getAST()
+{
+ return returnAST;
+}
+
+ASTFactory& Parser::getASTFactory()
+{
+ return astFactory;
+}
+
+ANTLR_USE_NAMESPACE(std)string Parser::getFilename() const
+{
+ return inputState->filename;
+}
+
+ParserSharedInputState Parser::getInputState() const
+{
+ return inputState;
+}
+
+ANTLR_USE_NAMESPACE(std)string Parser::getTokenName(int num) const
+{
+ return tokenNames[num];
+}
+
+ANTLR_USE_NAMESPACE(std)vector<ANTLR_USE_NAMESPACE(std)string> Parser::getTokenNames() const
+{
+ return tokenNames;
+}
+
+// Forwarded to TokenBuffer
+int Parser::mark()
+{
+ return inputState->getInput().mark();
+}
+
+/**Make sure current lookahead symbol matches token type <tt>t</tt>.
+ * Throw an exception upon mismatch, which is catch by either the
+ * error handler or by the syntactic predicate.
+ */
+void Parser::match(int t)
+{
+ if ( DEBUG_PARSER )
+ {
+ traceIndent();
+ ANTLR_USE_NAMESPACE(std)cout << "enter match(" << t << ") with LA(1)=" << LA(1) << ANTLR_USE_NAMESPACE(std)endl;
+ }
+ if ( LA(1)!=t ) {
+ if ( DEBUG_PARSER )
+ {
+ traceIndent();
+ ANTLR_USE_NAMESPACE(std)cout << "token mismatch: " << LA(1) << "!=" << t << ANTLR_USE_NAMESPACE(std)endl;
+ }
+ throw MismatchedTokenException(tokenNames, LT(1), t, false, getFilename());
+ } else {
+ // mark token as consumed -- fetch next token deferred until LA/LT
+ consume();
+ }
+}
+
+/**Make sure current lookahead symbol matches the given set
+ * Throw an exception upon mismatch, which is catch by either the
+ * error handler or by the syntactic predicate.
+ */
+void Parser::match(const BitSet& b)
+{
+ if ( DEBUG_PARSER )
+ {
+ traceIndent();
+ ANTLR_USE_NAMESPACE(std)cout << "enter match(" << "bitset" /*b.toString()*/
+ << ") with LA(1)=" << LA(1) << ANTLR_USE_NAMESPACE(std)endl;
+ }
+ if ( !b.member(LA(1)) ) {
+ if ( DEBUG_PARSER )
+ {
+ traceIndent();
+ ANTLR_USE_NAMESPACE(std)cout << "token mismatch: " << LA(1) << " not member of "
+ << "bitset" /*b.toString()*/ << ANTLR_USE_NAMESPACE(std)endl;
+ }
+ throw MismatchedTokenException(tokenNames, LT(1), b, false, getFilename());
+ } else {
+ // mark token as consumed -- fetch next token deferred until LA/LT
+ consume();
+ }
+}
+
+void Parser::matchNot(int t)
+{
+ if ( LA(1)==t ) {
+ // Throws inverted-sense exception
+ throw MismatchedTokenException(tokenNames, LT(1), t, true, getFilename());
+ } else {
+ // mark token as consumed -- fetch next token deferred until LA/LT
+ consume();
+ }
+}
+
+void Parser::panic()
+{
+ ANTLR_USE_NAMESPACE(std)cerr << "Parser: panic" << ANTLR_USE_NAMESPACE(std)endl;
+ exit(1);
+}
+
+/** Parser error-reporting function can be overridden in subclass */
+void Parser::reportError(const RecognitionException& ex)
+{
+ ANTLR_USE_NAMESPACE(std)cerr << ex.toString().c_str() << ANTLR_USE_NAMESPACE(std)endl;
+}
+
+/** Parser error-reporting function can be overridden in subclass */
+void Parser::reportError(const ANTLR_USE_NAMESPACE(std)string& s)
+{
+ if ( getFilename().empty() )
+ ANTLR_USE_NAMESPACE(std)cerr << "error: " << s.c_str() << ANTLR_USE_NAMESPACE(std)endl;
+ else
+ ANTLR_USE_NAMESPACE(std)cerr << getFilename().c_str() << ": error: " << s.c_str() << ANTLR_USE_NAMESPACE(std)endl;
+}
+
+/** Parser warning-reporting function can be overridden in subclass */
+void Parser::reportWarning(const ANTLR_USE_NAMESPACE(std)string& s)
+{
+ if ( getFilename().empty() )
+ ANTLR_USE_NAMESPACE(std)cerr << "warning: " << s.c_str() << ANTLR_USE_NAMESPACE(std)endl;
+ else
+ ANTLR_USE_NAMESPACE(std)cerr << getFilename().c_str() << ": warning: " << s.c_str() << ANTLR_USE_NAMESPACE(std)endl;
+}
+
+void Parser::rewind(int pos)
+{
+ inputState->getInput().rewind(pos);
+}
+
+/** Set the object used to generate ASTs */
+// void setASTFactory(ASTFactory astFactory_);
+
+/** Specify the type of node to create during tree building */
+void Parser::setASTNodeFactory(ASTFactory::factory_type factory)
+{
+ astFactory.setASTNodeFactory(factory);
+}
+
+void Parser::setFilename(const ANTLR_USE_NAMESPACE(std)string& f)
+{
+ inputState->filename = f;
+}
+
+void Parser::setInputState(ParserSharedInputState state)
+{
+ inputState = state;
+}
+
+/** Set or change the input token buffer */
+// void setTokenBuffer(TokenBuffer<Token>* t);
+
+void Parser::traceIndent()
+{
+ for( int i = 0; i < traceDepth; i++ )
+ ANTLR_USE_NAMESPACE(std)cout << " ";
+}
+
+void Parser::traceIn(const ANTLR_USE_NAMESPACE(std)string& rname)
+{
+ traceDepth++;
+
+ for( int i = 0; i < traceDepth; i++ )
+ ANTLR_USE_NAMESPACE(std)cout << " ";
+
+ ANTLR_USE_NAMESPACE(std)cout << "> " << rname.c_str() << "; LA(1)==" << LT(1)->getText().c_str() <<
+ ((inputState->guessing>0)?" [guessing]":"") << ANTLR_USE_NAMESPACE(std)endl;
+}
+
+void Parser::traceOut(const ANTLR_USE_NAMESPACE(std)string& rname)
+{
+ for( int i = 0; i < traceDepth; i++ )
+ ANTLR_USE_NAMESPACE(std)cout << " ";
+
+ ANTLR_USE_NAMESPACE(std)cout << "< " << rname.c_str() << "; LA(1)==" << LT(1)->getText().c_str() <<
+ ((inputState->guessing>0)?" [guessing]":"") << ANTLR_USE_NAMESPACE(std)endl;
+
+ traceDepth--;
+}
+
+ANTLR_END_NAMESPACE
diff --git a/poxml/antlr/src/ParserSharedInputState.cpp b/poxml/antlr/src/ParserSharedInputState.cpp
new file mode 100644
index 00000000..102aba87
--- /dev/null
+++ b/poxml/antlr/src/ParserSharedInputState.cpp
@@ -0,0 +1,37 @@
+#include "antlr/ParserSharedInputState.hpp"
+
+ANTLR_BEGIN_NAMESPACE(antlr)
+
+/** This object contains the data associated with an
+ * input stream of tokens. Multiple parsers
+ * share a single ParserSharedInputState to parse
+ * the same stream of tokens.
+ */
+
+ParserInputState::ParserInputState(TokenBuffer* input_)
+: guessing(0)
+, input(input_)
+, inputResponsible(true)
+{
+}
+
+ParserInputState::ParserInputState(TokenBuffer& input_)
+: guessing(0)
+, input(&input_)
+, inputResponsible(false)
+{
+}
+
+ParserInputState::~ParserInputState()
+{
+ if (inputResponsible)
+ delete input;
+}
+
+TokenBuffer& ParserInputState::getInput()
+{
+ return *input;
+}
+
+ANTLR_END_NAMESPACE
+
diff --git a/poxml/antlr/src/RecognitionException.cpp b/poxml/antlr/src/RecognitionException.cpp
new file mode 100644
index 00000000..1d1bd53d
--- /dev/null
+++ b/poxml/antlr/src/RecognitionException.cpp
@@ -0,0 +1,87 @@
+/**
+ * <b>SOFTWARE RIGHTS</b>
+ * <p>
+ * ANTLR 2.6.0 MageLang Insitute, 1998
+ * <p>
+ * We reserve no legal rights to the ANTLR--it is fully in the
+ * public domain. An individual or company may do whatever
+ * they wish with source code distributed with ANTLR or the
+ * code generated by ANTLR, including the incorporation of
+ * ANTLR, or its output, into commerical software.
+ * <p>
+ * We encourage users to develop software with ANTLR. However,
+ * we do ask that credit is given to us for developing
+ * ANTLR. By "credit", we mean that if you use ANTLR or
+ * incorporate any source code into one of your programs
+ * (commercial product, research project, or otherwise) that
+ * you acknowledge this fact somewhere in the documentation,
+ * research report, etc... If you like ANTLR and have
+ * developed a nice tool with the output, please mention that
+ * you developed it using ANTLR. In addition, we ask that the
+ * headers remain intact in our source code. As long as these
+ * guidelines are kept, we expect to continue enhancing this
+ * system and expect to make other tools available as they are
+ * completed.
+ * <p>
+ * The ANTLR gang:
+ * @version ANTLR 2.6.0 MageLang Insitute, 1998
+ * @author Terence Parr, <a href=http://www.MageLang.com>MageLang Institute</a>
+ * @author <br>John Lilley, <a href=http://www.Empathy.com>Empathy Software</a>
+ * @author <br><a href="mailto:pete@yamuna.demon.co.uk">Pete Wells</a>
+ */
+
+#include "antlr/RecognitionException.hpp"
+#include "antlr/String.hpp"
+
+ANTLR_BEGIN_NAMESPACE(antlr)
+
+RecognitionException::RecognitionException()
+: ANTLRException("parsing error"), line(1), column(1)
+{}
+
+RecognitionException::RecognitionException(const ANTLR_USE_NAMESPACE(std)string& s)
+: ANTLRException(s)
+{}
+
+RecognitionException::RecognitionException(const ANTLR_USE_NAMESPACE(std)string& s,const ANTLR_USE_NAMESPACE(std)string& fileName_,int line_)
+: ANTLRException(s), fileName(fileName_), line(line_)
+{}
+
+RecognitionException::RecognitionException(const ANTLR_USE_NAMESPACE(std)string& s,const ANTLR_USE_NAMESPACE(std)string& fileName_,int line_,int column_)
+: ANTLRException(s), fileName(fileName_), line(line_), column(column_)
+{}
+
+int RecognitionException::getColumn() const
+{
+ return column;
+}
+
+ANTLR_USE_NAMESPACE(std)string RecognitionException::getErrorMessage() const
+{
+ return getMessage();
+}
+
+ANTLR_USE_NAMESPACE(std)string RecognitionException::getFileLineString() const
+{
+ if ( fileName.length() )
+ return fileName+": "+line+": ";
+ else
+ return ANTLR_USE_NAMESPACE(std)string("line ")+line+": ";
+}
+
+ANTLR_USE_NAMESPACE(std)string RecognitionException::getFilename() const
+{
+ return fileName;
+}
+
+int RecognitionException::getLine() const
+{
+ return line;
+}
+
+ANTLR_USE_NAMESPACE(std)string RecognitionException::toString() const
+{
+ return getFileLineString()+getMessage();
+}
+
+ANTLR_END_NAMESPACE
diff --git a/poxml/antlr/src/String.cpp b/poxml/antlr/src/String.cpp
new file mode 100644
index 00000000..6d9df7a5
--- /dev/null
+++ b/poxml/antlr/src/String.cpp
@@ -0,0 +1,61 @@
+/**
+ * <b>SOFTWARE RIGHTS</b>
+ * <p>
+ * ANTLR 2.6.0 MageLang Insitute, 1998
+ * <p>
+ * We reserve no legal rights to the ANTLR--it is fully in the
+ * public domain. An individual or company may do whatever
+ * they wish with source code distributed with ANTLR or the
+ * code generated by ANTLR, including the incorporation of
+ * ANTLR, or its output, into commerical software.
+ * <p>
+ * We encourage users to develop software with ANTLR. However,
+ * we do ask that credit is given to us for developing
+ * ANTLR. By "credit", we mean that if you use ANTLR or
+ * incorporate any source code into one of your programs
+ * (commercial product, research project, or otherwise) that
+ * you acknowledge this fact somewhere in the documentation,
+ * research report, etc... If you like ANTLR and have
+ * developed a nice tool with the output, please mention that
+ * you developed it using ANTLR. In addition, we ask that the
+ * headers remain intact in our source code. As long as these
+ * guidelines are kept, we expect to continue enhancing this
+ * system and expect to make other tools available as they are
+ * completed.
+ * <p>
+ * The ANTLR gang:
+ * @version ANTLR 2.6.0 MageLang Insitute, 1998
+ * @author Terence Parr, <a href=http://www.MageLang.com>MageLang Institute</a>
+ * @author <br>John Lilley, <a href=http://www.Empathy.com>Empathy Software</a>
+ * @author <br><a href="mailto:pete@yamuna.demon.co.uk">Pete Wells</a>
+ */
+
+#include "antlr/String.hpp"
+
+#ifdef HAS_NOT_CSTDIO_H
+#include <stdio.h>
+#else
+#include <cstdio>
+#endif
+
+ANTLR_BEGIN_NAMESPACE(antlr)
+ANTLR_C_USING(sprintf)
+
+ANTLR_USE_NAMESPACE(std)string operator+(const ANTLR_USE_NAMESPACE(std)string& lhs,int rhs)
+{
+ char tmp[100];
+ sprintf(tmp,"%d",rhs);
+ return lhs+tmp;
+}
+
+ANTLR_USE_NAMESPACE(std)string charName(int ch)
+{
+ if (ch == EOF)
+ return "EOF";
+ else {
+ return ANTLR_USE_NAMESPACE(std)string(1, static_cast<char>(ch));
+ }
+}
+
+ANTLR_END_NAMESPACE
+
diff --git a/poxml/antlr/src/Token.cpp b/poxml/antlr/src/Token.cpp
new file mode 100644
index 00000000..f307774f
--- /dev/null
+++ b/poxml/antlr/src/Token.cpp
@@ -0,0 +1,108 @@
+/**
+ * <b>SOFTWARE RIGHTS</b>
+ * <p>
+ * ANTLR 2.6.0 MageLang Insitute, 1998
+ * <p>
+ * We reserve no legal rights to the ANTLR--it is fully in the
+ * public domain. An individual or company may do whatever
+ * they wish with source code distributed with ANTLR or the
+ * code generated by ANTLR, including the incorporation of
+ * ANTLR, or its output, into commerical software.
+ * <p>
+ * We encourage users to develop software with ANTLR. However,
+ * we do ask that credit is given to us for developing
+ * ANTLR. By "credit", we mean that if you use ANTLR or
+ * incorporate any source code into one of your programs
+ * (commercial product, research project, or otherwise) that
+ * you acknowledge this fact somewhere in the documentation,
+ * research report, etc... If you like ANTLR and have
+ * developed a nice tool with the output, please mention that
+ * you developed it using ANTLR. In addition, we ask that the
+ * headers remain intact in our source code. As long as these
+ * guidelines are kept, we expect to continue enhancing this
+ * system and expect to make other tools available as they are
+ * completed.
+ * <p>
+ * The ANTLR gang:
+ * @version ANTLR 2.6.0 MageLang Insitute, 1998
+ * @author Terence Parr, <a href=http://www.MageLang.com>MageLang Institute</a>
+ * @author <br>John Lilley, <a href=http://www.Empathy.com>Empathy Software</a>
+ * @author <br><a href="mailto:pete@yamuna.demon.co.uk">Pete Wells</a>
+ */
+
+#include "antlr/Token.hpp"
+#include "antlr/String.hpp"
+
+ANTLR_BEGIN_NAMESPACE(antlr)
+
+RefToken Token::badToken(new Token(Token::INVALID_TYPE, "<no text>"));
+
+Token::Token() : type(INVALID_TYPE)
+{
+}
+
+Token::Token(int t) : type(t)
+{
+}
+
+Token::Token(int t, const ANTLR_USE_NAMESPACE(std)string& txt)
+ : type(t)
+{
+ type=t;
+ setText(txt);
+}
+
+int Token::getColumn() const
+{
+ return 0;
+}
+
+int Token::getLine() const
+{
+ return 0;
+}
+
+ANTLR_USE_NAMESPACE(std)string Token::getText() const
+{
+ return "<no text>";
+}
+
+int Token::getType() const
+{
+ return type;
+}
+
+void Token::setColumn(int c)
+{}
+
+void Token::setLine(int l)
+{}
+
+void Token::setText(const ANTLR_USE_NAMESPACE(std)string& t)
+{}
+
+void Token::setType(int t)
+{
+ type=t;
+}
+
+ANTLR_USE_NAMESPACE(std)string Token::toString() const
+{
+ return "[\""+getText()+"\",<"+type+">]";
+}
+
+Token::~Token()
+{}
+
+RefToken nullToken;
+
+#ifndef NO_STATIC_CONSTS
+const int Token::MIN_USER_TYPE;
+const int Token::NULL_TREE_LOOKAHEAD;
+const int Token::INVALID_TYPE;
+const int Token::EOF_TYPE;
+const int Token::SKIP;
+#endif
+
+ANTLR_END_NAMESPACE
+
diff --git a/poxml/antlr/src/TokenBuffer.cpp b/poxml/antlr/src/TokenBuffer.cpp
new file mode 100644
index 00000000..ded5df9b
--- /dev/null
+++ b/poxml/antlr/src/TokenBuffer.cpp
@@ -0,0 +1,107 @@
+/**
+ * <b>SOFTWARE RIGHTS</b>
+ * <p>
+ * ANTLR 2.6.0 MageLang Insitute, 1998
+ * <p>
+ * We reserve no legal rights to the ANTLR--it is fully in the
+ * public domain. An individual or company may do whatever
+ * they wish with source code distributed with ANTLR or the
+ * code generated by ANTLR, including the incorporation of
+ * ANTLR, or its output, into commerical software.
+ * <p>
+ * We encourage users to develop software with ANTLR. However,
+ * we do ask that credit is given to us for developing
+ * ANTLR. By "credit", we mean that if you use ANTLR or
+ * incorporate any source code into one of your programs
+ * (commercial product, research project, or otherwise) that
+ * you acknowledge this fact somewhere in the documentation,
+ * research report, etc... If you like ANTLR and have
+ * developed a nice tool with the output, please mention that
+ * you developed it using ANTLR. In addition, we ask that the
+ * headers remain intact in our source code. As long as these
+ * guidelines are kept, we expect to continue enhancing this
+ * system and expect to make other tools available as they are
+ * completed.
+ * <p>
+ * The ANTLR gang:
+ * @version ANTLR 2.6.0 MageLang Insitute, 1998
+ * @author Terence Parr, <a href=http://www.MageLang.com>MageLang Institute</a>
+ * @author <br>John Lilley, <a href=http://www.Empathy.com>Empathy Software</a>
+ * @author <br><a href="mailto:pete@yamuna.demon.co.uk">Pete Wells</a>
+ */
+
+#include "antlr/TokenBuffer.hpp"
+
+ANTLR_BEGIN_NAMESPACE(antlr)
+
+/**A Stream of Token objects fed to the parser from a TokenStream that can
+ * be rewound via mark()/rewind() methods.
+ * <p>
+ * A dynamic array is used to buffer up all the input tokens. Normally,
+ * "k" tokens are stored in the buffer. More tokens may be stored during
+ * guess mode (testing syntactic predicate), or when LT(i>k) is referenced.
+ * Consumption of tokens is deferred. In other words, reading the next
+ * token is not done by conume(), but deferred until needed by LA or LT.
+ * <p>
+ *
+ * @see antlr.Token
+ * @see antlr.TokenStream
+ * @see antlr.TokenQueue
+ */
+
+/** Create a token buffer */
+TokenBuffer::TokenBuffer(TokenStream& input_)
+: input(input_)
+{ nMarkers=0; markerOffset=0; numToConsume=0; }
+
+/** Mark another token for deferred consumption */
+void TokenBuffer::consume()
+{ numToConsume++; }
+
+/** Ensure that the token buffer is sufficiently full */
+void TokenBuffer::fill(int amount)
+{
+ syncConsume();
+ // Fill the buffer sufficiently to hold needed tokens
+ while (queue.entries() < amount + markerOffset) {
+ // Append the next token
+ queue.append(input.nextToken());
+ }
+}
+
+/** Get a lookahead token value */
+int TokenBuffer::LA(int i)
+{
+ fill(i);
+ return queue.elementAt(markerOffset+i-1)->type;
+}
+
+/** Get a lookahead token */
+RefToken TokenBuffer::LT(int i)
+{
+ fill(i);
+ return queue.elementAt(markerOffset+i-1);
+}
+
+/**Return an integer marker that can be used to rewind the buffer to
+ * its current state.
+ */
+int TokenBuffer::mark()
+{
+ syncConsume();
+ nMarkers++;
+ return markerOffset;
+}
+
+/**Rewind the token buffer to a marker.
+ * @param mark Marker returned previously from mark()
+ */
+void TokenBuffer::rewind(int mark)
+{
+ syncConsume();
+ markerOffset=mark;
+ nMarkers--;
+}
+
+ANTLR_END_NAMESPACE
+
diff --git a/poxml/antlr/src/TokenStreamBasicFilter.cpp b/poxml/antlr/src/TokenStreamBasicFilter.cpp
new file mode 100644
index 00000000..71257f46
--- /dev/null
+++ b/poxml/antlr/src/TokenStreamBasicFilter.cpp
@@ -0,0 +1,34 @@
+#include "antlr/TokenStreamBasicFilter.hpp"
+
+ANTLR_BEGIN_NAMESPACE(antlr)
+
+/** This object is a TokenStream that passes through all
+ * tokens except for those that you tell it to discard.
+ * There is no buffering of the tokens.
+ */
+TokenStreamBasicFilter::TokenStreamBasicFilter(TokenStream& input_)
+: input(&input_)
+{
+}
+
+void TokenStreamBasicFilter::discard(int ttype)
+{
+ discardMask.add(ttype);
+}
+
+void TokenStreamBasicFilter::discard(const BitSet& mask)
+{
+ discardMask = mask;
+}
+
+RefToken TokenStreamBasicFilter::nextToken()
+{
+ RefToken tok = input->nextToken();
+ while ( tok && discardMask.member(tok->getType()) ) {
+ tok = input->nextToken();
+ }
+ return tok;
+}
+
+ANTLR_END_NAMESPACE
+
diff --git a/poxml/antlr/src/TokenStreamHiddenTokenFilter.cpp b/poxml/antlr/src/TokenStreamHiddenTokenFilter.cpp
new file mode 100644
index 00000000..827ca382
--- /dev/null
+++ b/poxml/antlr/src/TokenStreamHiddenTokenFilter.cpp
@@ -0,0 +1,146 @@
+#include "antlr/TokenStreamHiddenTokenFilter.hpp"
+#include "antlr/CommonHiddenStreamToken.hpp"
+
+ANTLR_BEGIN_NAMESPACE(antlr)
+
+/**This object filters a token stream coming from a lexer
+ * or another TokenStream so that only certain token channels
+ * get transmitted to the parser.
+ *
+ * Any of the channels can be filtered off as "hidden" channels whose
+ * tokens can be accessed from the parser.
+ */
+
+TokenStreamHiddenTokenFilter::TokenStreamHiddenTokenFilter(TokenStream& input)
+: TokenStreamBasicFilter(input)
+{
+}
+
+void TokenStreamHiddenTokenFilter::consume()
+{
+ nextMonitoredToken = input->nextToken();
+}
+
+void TokenStreamHiddenTokenFilter::consumeFirst()
+{
+ consume();
+
+ // Handle situation where hidden or discarded tokens
+ // appear first in input stream
+ RefToken p;
+ // while hidden or discarded scarf tokens
+ while ( hideMask.member(LA(1)->getType()) || discardMask.member(LA(1)->getType()) ) {
+ if ( hideMask.member(LA(1)->getType()) ) {
+ if ( !p ) {
+ p = LA(1);
+ }
+ else {
+ static_cast<CommonHiddenStreamToken*>(p.get())->setHiddenAfter(LA(1));
+ static_cast<CommonHiddenStreamToken*>(LA(1).get())->setHiddenBefore(p); // double-link
+ p = LA(1);
+ }
+ lastHiddenToken = p;
+ if (!firstHidden)
+ firstHidden = p; // record hidden token if first
+ }
+ consume();
+ }
+}
+
+BitSet TokenStreamHiddenTokenFilter::getDiscardMask() const
+{
+ return discardMask;
+}
+
+/** Return a ptr to the hidden token appearing immediately after
+ * token t in the input stream.
+ */
+RefToken TokenStreamHiddenTokenFilter::getHiddenAfter(RefToken t)
+{
+ return static_cast<CommonHiddenStreamToken*>(t.get())->getHiddenAfter();
+}
+
+/** Return a ptr to the hidden token appearing immediately before
+ * token t in the input stream.
+ */
+RefToken TokenStreamHiddenTokenFilter::getHiddenBefore(RefToken t)
+{
+ return static_cast<CommonHiddenStreamToken*>(t.get())->getHiddenBefore();
+}
+
+BitSet TokenStreamHiddenTokenFilter::getHideMask() const
+{
+ return hideMask;
+}
+
+/** Return the first hidden token if one appears
+ * before any monitored token.
+ */
+RefToken TokenStreamHiddenTokenFilter::getInitialHiddenToken()
+{
+ return firstHidden;
+}
+
+void TokenStreamHiddenTokenFilter::hide(int m)
+{
+ hideMask.add(m);
+}
+
+void TokenStreamHiddenTokenFilter::hide(const BitSet& mask)
+{
+ hideMask = mask;
+}
+
+RefToken TokenStreamHiddenTokenFilter::LA(int i)
+{
+ return nextMonitoredToken;
+}
+
+/** Return the next monitored token.
+* Test the token following the monitored token.
+* If following is another monitored token, save it
+* for the next invocation of nextToken (like a single
+* lookahead token) and return it then.
+* If following is unmonitored, nondiscarded (hidden)
+* channel token, add it to the monitored token.
+*
+* Note: EOF must be a monitored Token.
+*/
+RefToken TokenStreamHiddenTokenFilter::nextToken()
+{
+ // handle an initial condition; don't want to get lookahead
+ // token of this splitter until first call to nextToken
+ if ( !LA(1) ) {
+ consumeFirst();
+ }
+
+ // we always consume hidden tokens after monitored, thus,
+ // upon entry LA(1) is a monitored token.
+ RefToken monitored = LA(1);
+ // point to hidden tokens found during last invocation
+ static_cast<CommonHiddenStreamToken*>(monitored.get())->setHiddenBefore(lastHiddenToken);
+ lastHiddenToken = nullToken;
+
+ // Look for hidden tokens, hook them into list emanating
+ // from the monitored tokens.
+ consume();
+ RefToken p = monitored;
+ // while hidden or discarded scarf tokens
+ while ( hideMask.member(LA(1)->getType()) || discardMask.member(LA(1)->getType()) ) {
+ if ( hideMask.member(LA(1)->getType()) ) {
+ // attach the hidden token to the monitored in a chain
+ // link forwards
+ static_cast<CommonHiddenStreamToken*>(p.get())->setHiddenAfter(LA(1));
+ // link backwards
+ if (p != monitored) { //hidden cannot point to monitored tokens
+ static_cast<CommonHiddenStreamToken*>(LA(1).get())->setHiddenBefore(p);
+ }
+ p = lastHiddenToken = LA(1);
+ }
+ consume();
+ }
+ return monitored;
+}
+
+ANTLR_END_NAMESPACE
+
diff --git a/poxml/antlr/src/TokenStreamSelector.cpp b/poxml/antlr/src/TokenStreamSelector.cpp
new file mode 100644
index 00000000..2e6527a8
--- /dev/null
+++ b/poxml/antlr/src/TokenStreamSelector.cpp
@@ -0,0 +1,97 @@
+#include "antlr/TokenStreamSelector.hpp"
+#include "antlr/TokenStreamRetryException.hpp"
+
+ANTLR_BEGIN_NAMESPACE(antlr)
+
+/** A token stream MUX (multiplexor) knows about n token streams
+ * and can multiplex them onto the same channel for use by token
+ * stream consumer like a parser. This is a way to have multiple
+ * lexers break up the same input stream for a single parser.
+ * Or, you can have multiple instances of the same lexer handle
+ * multiple input streams; this works great for includes.
+ */
+
+TokenStreamSelector::TokenStreamSelector()
+: input(0)
+{
+}
+
+TokenStreamSelector::~TokenStreamSelector()
+{
+}
+
+void TokenStreamSelector::addInputStream(TokenStream* stream, const ANTLR_USE_NAMESPACE(std)string& key)
+{
+ inputStreamNames[key] = stream;
+}
+
+TokenStream* TokenStreamSelector::getCurrentStream() const
+{
+ return input;
+}
+
+TokenStream* TokenStreamSelector::getStream(const ANTLR_USE_NAMESPACE(std)string& sname) const
+{
+ inputStreamNames_coll::const_iterator i = inputStreamNames.find(sname);
+ if (i == inputStreamNames.end()) {
+ throw ANTLR_USE_NAMESPACE(std)string("TokenStream ")+sname+" not found";
+ }
+ return (*i).second;
+}
+
+RefToken TokenStreamSelector::nextToken()
+{
+ // keep looking for a token until you don't
+ // get a retry exception
+ for (;;) {
+ try {
+ return input->nextToken();
+ }
+ catch (TokenStreamRetryException& r) {
+ // just retry "forever"
+ }
+ }
+}
+
+TokenStream* TokenStreamSelector::pop()
+{
+ TokenStream* stream = streamStack.top();
+ streamStack.pop();
+ select(stream);
+ return stream;
+}
+
+void TokenStreamSelector::push(TokenStream* stream)
+{
+ streamStack.push(input);
+ select(stream);
+}
+
+void TokenStreamSelector::push(const ANTLR_USE_NAMESPACE(std)string& sname)
+{
+ streamStack.push(input);
+ select(sname);
+}
+
+void TokenStreamSelector::retry()
+{
+ throw TokenStreamRetryException();
+}
+
+/** Set the stream without pushing old stream */
+void TokenStreamSelector::select(TokenStream* stream)
+{
+ input = stream;
+}
+
+void TokenStreamSelector::select(const ANTLR_USE_NAMESPACE(std)string& sname)
+{
+ inputStreamNames_coll::const_iterator i = inputStreamNames.find(sname);
+ if (i == inputStreamNames.end()) {
+ throw ANTLR_USE_NAMESPACE(std)string("TokenStream ")+sname+" not found";
+ }
+ input = (*i).second;
+}
+
+ANTLR_END_NAMESPACE
+
diff --git a/poxml/antlr/src/TreeParser.cpp b/poxml/antlr/src/TreeParser.cpp
new file mode 100644
index 00000000..6d302737
--- /dev/null
+++ b/poxml/antlr/src/TreeParser.cpp
@@ -0,0 +1,165 @@
+/**
+ * <b>SOFTWARE RIGHTS</b>
+ * <p>
+ * ANTLR 2.6.0 MageLang Insitute, 1998
+ * <p>
+ * We reserve no legal rights to the ANTLR--it is fully in the
+ * public domain. An individual or company may do whatever
+ * they wish with source code distributed with ANTLR or the
+ * code generated by ANTLR, including the incorporation of
+ * ANTLR, or its output, into commerical software.
+ * <p>
+ * We encourage users to develop software with ANTLR. However,
+ * we do ask that credit is given to us for developing
+ * ANTLR. By "credit", we mean that if you use ANTLR or
+ * incorporate any source code into one of your programs
+ * (commercial product, research project, or otherwise) that
+ * you acknowledge this fact somewhere in the documentation,
+ * research report, etc... If you like ANTLR and have
+ * developed a nice tool with the output, please mention that
+ * you developed it using ANTLR. In addition, we ask that the
+ * headers remain intact in our source code. As long as these
+ * guidelines are kept, we expect to continue enhancing this
+ * system and expect to make other tools available as they are
+ * completed.
+ * <p>
+ * The ANTLR gang:
+ * @version ANTLR 2.6.0 MageLang Insitute, 1998
+ * @author Terence Parr, <a href=http://www.MageLang.com>MageLang Institute</a>
+ * @author <br>John Lilley, <a href=http://www.Empathy.com>Empathy Software</a>
+ * @author <br><a href="mailto:pete@yamuna.demon.co.uk">Pete Wells</a>
+ */
+#include "antlr/TreeParser.hpp"
+#include "antlr/ASTNULLType.hpp"
+#include "antlr/MismatchedTokenException.hpp"
+#include <iostream>
+#include <stdlib.h>
+
+ANTLR_BEGIN_NAMESPACE(antlr)
+ANTLR_C_USING(exit)
+
+TreeParser::TreeParser()
+: inputState(new TreeParserInputState()), traceDepth(0)
+{
+}
+
+TreeParser::TreeParser(const TreeParserSharedInputState& state)
+: inputState(state), traceDepth(0)
+{
+}
+
+TreeParser::~TreeParser()
+{
+}
+
+void TreeParser::setTokenNames(const char** tokenNames_)
+{
+ while (*tokenNames_) {
+ tokenNames.push_back(*(tokenNames_++));
+ }
+}
+
+/** The AST Null object; the parsing cursor is set to this when
+ * it is found to be null. This way, we can test the
+ * token type of a node without having to have tests for null
+ * everywhere.
+ */
+RefAST TreeParser::ASTNULL(new ASTNULLType);
+
+/** Get the AST return value squirreled away in the parser */
+//RefAST getAST() const {
+// return returnAST;
+//}
+
+void TreeParser::match(RefAST t, int ttype)
+{
+ if (!t || t==ASTNULL || t->getType()!=ttype)
+ throw MismatchedTokenException();
+}
+
+/**Make sure current lookahead symbol matches the given set
+ * Throw an exception upon mismatch, which is caught by either the
+ * error handler or by the syntactic predicate.
+ */
+void TreeParser::match(RefAST t, const BitSet& b)
+{
+ if ( !t || t==ASTNULL || !b.member(t->getType()) ) {
+ throw MismatchedTokenException();
+ }
+}
+
+void TreeParser::matchNot(RefAST t, int ttype)
+{
+ //ANTLR_USE_NAMESPACE(std)cout << "match(" << ttype << "); cursor is " << t.toString() << ANTLR_USE_NAMESPACE(std)endl;
+ if ( !t || t==ASTNULL || t->getType()==ttype ) {
+ throw MismatchedTokenException();
+ }
+}
+
+void TreeParser::panic()
+{
+ ANTLR_USE_NAMESPACE(std)cerr << "TreeWalker: panic" << ANTLR_USE_NAMESPACE(std)endl;
+ exit(1);
+}
+
+/** Parser error-reporting function can be overridden in subclass */
+void TreeParser::reportError(const RecognitionException& ex)
+{
+ ANTLR_USE_NAMESPACE(std)cerr << ex.toString().c_str() << ANTLR_USE_NAMESPACE(std)endl;
+}
+
+/** Parser error-reporting function can be overridden in subclass */
+void TreeParser::reportError(const ANTLR_USE_NAMESPACE(std)string& s)
+{
+ ANTLR_USE_NAMESPACE(std)cerr << "error: " << s.c_str() << ANTLR_USE_NAMESPACE(std)endl;
+}
+
+/** Parser warning-reporting function can be overridden in subclass */
+void TreeParser::reportWarning(const ANTLR_USE_NAMESPACE(std)string& s)
+{
+ ANTLR_USE_NAMESPACE(std)cerr << "warning: " << s.c_str() << ANTLR_USE_NAMESPACE(std)endl;
+}
+
+/** Specify an object with support code (shared by
+ * Parser and TreeParser. Normally, the programmer
+ * does not play with this, using setASTNodeType instead.
+ */
+// void TreeParser::setASTFactory(ASTFactory f);
+
+/** Specify the type of node to create during tree building */
+void TreeParser::setASTNodeFactory(ASTFactory::factory_type factory)
+{
+ astFactory.setASTNodeFactory(factory);
+}
+
+/** Procedure to write out an indent for traceIn and traceOut */
+void TreeParser::traceIndent()
+{
+ for( int i = 0; i < traceDepth; i++ )
+ ANTLR_USE_NAMESPACE(std)cout << " ";
+}
+
+void TreeParser::traceIn(const ANTLR_USE_NAMESPACE(std)string& rname, RefAST t)
+{
+ traceDepth++;
+ traceIndent();
+
+ ANTLR_USE_NAMESPACE(std)cout << "> " << rname.c_str()
+ << "(" << (t ? t->toString().c_str() : "null") << ")"
+ << ((inputState->guessing>0)?" [guessing]":"")
+ << ANTLR_USE_NAMESPACE(std)endl;
+}
+
+void TreeParser::traceOut(const ANTLR_USE_NAMESPACE(std)string& rname, RefAST t)
+{
+ traceIndent();
+
+ ANTLR_USE_NAMESPACE(std)cout << "< " << rname.c_str()
+ << "(" << (t ? t->toString().c_str() : "null") << ")"
+ << ((inputState->guessing>0)?" [guessing]":"")
+ << ANTLR_USE_NAMESPACE(std)endl;
+
+ traceDepth--;
+}
+
+ANTLR_END_NAMESPACE
diff --git a/poxml/antlr/src/TreeParserSharedInputState.cpp b/poxml/antlr/src/TreeParserSharedInputState.cpp
new file mode 100644
index 00000000..89f1d5dc
--- /dev/null
+++ b/poxml/antlr/src/TreeParserSharedInputState.cpp
@@ -0,0 +1,22 @@
+#include "antlr/TreeParserSharedInputState.hpp"
+
+ANTLR_BEGIN_NAMESPACE(antlr)
+
+/** This object contains the data associated with an
+ * input AST. Multiple parsers
+ * share a single TreeParserSharedInputState to parse
+ * the same tree or to have the parser walk multiple
+ * trees.
+ */
+
+TreeParserInputState::TreeParserInputState()
+: guessing(0)
+{
+}
+
+TreeParserInputState::~TreeParserInputState()
+{
+}
+
+ANTLR_END_NAMESPACE
+
diff --git a/poxml/gettext.g b/poxml/gettext.g
new file mode 100644
index 00000000..8da92334
--- /dev/null
+++ b/poxml/gettext.g
@@ -0,0 +1,168 @@
+
+header "pre_include_hpp" {
+#include <string>
+using namespace std;
+#include "parser.h"
+}
+
+options {
+ language="Cpp";
+}
+
+{
+#include <iostream>
+#include "GettextLexer.hpp"
+#include "GettextParser.hpp"
+#include "antlr/AST.hpp"
+#include "antlr/CommonAST.hpp"
+
+/*
+int main()
+{
+ ANTLR_USING_NAMESPACE(std)
+ ANTLR_USING_NAMESPACE(antlr)
+ try {
+ GettextLexer lexer(cin);
+ GettextParser parser(lexer);
+ parser.file();
+
+ } catch(exception& e) {
+ cerr << "exception: " << e.what() << endl;
+ }
+}
+*/
+}
+
+class GettextParser extends Parser;
+
+options {
+ codeGenMakeSwitchThreshold = 3;
+ codeGenBitsetTestThreshold = 4;
+}
+
+file returns [ MsgList ml ]
+{
+string c, mi, ms;
+MsgBlock mb;
+MsgList ml2;
+}
+ : (comment T_MSGID) => (mb=file_block ml2=file { ml = ml2; ml.append(mb); } )
+ | (comment EOF) => c=comment { (void)c; }
+ ;
+
+file_block returns [ MsgBlock mb ]
+{
+string c, mi, mip, ms;
+}
+ : c=comment mi=msgid
+ (
+ ( ms=msgstr {
+ mb.comment = QString::fromUtf8(c.c_str());
+ mb.msgid = QString::fromUtf8(mi.c_str());
+ mb.msgstr = QString::fromUtf8(ms.c_str());
+ }
+ )
+ |
+ ( mip=msgid_plural ms=msgstr_plural {
+ mb.comment = QString::fromUtf8(c.c_str());
+ mb.msgid = QString::fromUtf8(mi.c_str());
+ mb.msgid_plural = QString::fromUtf8(mip.c_str());
+ mb.msgstr = QString::fromUtf8(ms.c_str());
+ }
+ )
+ )
+ ;
+
+comment returns [string s]
+{
+string r;
+}
+ : (c:T_COMMENT r=comment { s = c->getText() + r; } )
+ | /* nothing */
+ ;
+
+msgid returns [string s]
+ : T_MSGID t:T_STRING { s = t->getText(); }
+ ;
+
+msgid_plural returns [string s]
+ : T_MSGID_PLURAL t:T_STRING { s = t->getText(); }
+ ;
+
+msgstr returns [string s]
+ : T_MSGSTR t:T_STRING { s = t->getText(); }
+ ;
+
+msgstr_plural returns [string s]
+ : (
+ T_MSGSTR L_BRACKET n:T_INT R_BRACKET t:T_STRING { s = t->getText(); }
+ )+
+ ;
+
+class GettextLexer extends Lexer;
+options {
+ charVocabulary = '\u0000'..'\u00FF';
+ testLiterals=false; // don't automatically test for literals
+}
+
+WS
+ : (' ' | '\t'
+ | ('\n' | "\r\n") { newline(); }
+ ) { $setType(ANTLR_USE_NAMESPACE(antlr)Token::SKIP); }
+ ;
+
+L_BRACKET: '[' ;
+
+R_BRACKET: ']' ;
+
+T_INT : ( '0'..'9' )+
+ ;
+
+T_COMMENT : '#' (~'\n')*
+ ;
+
+MSG_TAG : "msg" ( ("id") (
+ "" { $setType(T_MSGID); }
+ | "_plural" { $setType(T_MSGID_PLURAL); }
+ )
+ | "str" { $setType(T_MSGSTR); }
+ )
+ ;
+
+T_STRING
+ : ('"'! (ESC|~'"')* ('"'! (' ' | 't')*! '\n'! { newline(); } (' '! | '\t'!)*))+
+ ;
+
+// copied from example
+protected
+ESC : '\\'
+ ( 'n'
+ | 'r'
+ | 't'
+ | 'b'
+ | 'f'
+ | '"'
+ | '\''
+ | '\\'
+ | ('0'..'3')
+ (
+ options {
+ warnWhenFollowAmbig = false;
+ }
+ : ('0'..'9')
+ (
+ options {
+ warnWhenFollowAmbig = false;
+ }
+ : '0'..'9'
+ )?
+ )?
+ | ('4'..'7')
+ (
+ options {
+ warnWhenFollowAmbig = false;
+ }
+ : ('0'..'9')
+ )?
+ )
+ ;
diff --git a/poxml/lauri.po b/poxml/lauri.po
new file mode 100644
index 00000000..9dd0d025
--- /dev/null
+++ b/poxml/lauri.po
@@ -0,0 +1,442 @@
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR Free Software Foundation, Inc.
+# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\n"
+"POT-Creation-Date: 2001-02-09 01:25+0100\n"
+"PO-Revision-Date: 2001-07-02 20:31MET\n"
+"Last-Translator: Stephan Kulow <coolo@kde.org>\n"
+"Language-Team: german <kde-i18n-de@kde.org>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"X-Generator: KBabel 0.9.2\n"
+
+#. Tag: title
+#: lauri.xml:16
+#, no-c-format
+msgid "test document"
+msgstr "Testtext"
+
+#. Tag: author
+#: lauri.xml:17
+#, no-c-format
+msgid "<firstname>Stephan</firstname><surname>Kulow</surname>"
+msgstr "<firstname>Stephan</firstname><surname>Kulow</surname>"
+
+#. Tag: para
+#: lauri.xml:19
+#, no-c-format
+msgid "This is nonsense"
+msgstr "Dies ist Schwachsinn"
+
+#. Tag: keyword
+#: lauri.xml:20
+#, no-c-format
+msgid "<keyword>KDE</keyword>"
+msgstr "<keyword>KDE.de</keyword>"
+
+#. Tag: title
+#: lauri.xml:25
+#, no-c-format
+msgid "&quot;Text&quot; for &lauri;"
+msgstr "&quot;Text&quot; für &lauri;"
+
+#. Tag: title
+#: lauri.xml:27
+#, no-c-format
+msgid "Section 1"
+msgstr "Abschnitt 1"
+
+#. Tag: title
+#: lauri.xml:29
+#, no-c-format
+msgid "Section 1.1"
+msgstr "Abschnitt 1.1"
+
+#. Tag: para
+#: lauri.xml:31
+#, no-c-format
+msgid ""
+"<emphasis><emphasis role=\"blah\">Warum kann ich meinem Rechner nicht "
+"einfach ausschalten?</emphasis></emphasis>Hier noch"
+msgstr ""
+"<emphasis><emphasis role=\"blah\">Warum kann ich meinem Rechner nicht "
+"einfach ausschalten?</emphasis></emphasis>Hier noch"
+
+#. Tag: para
+#: lauri.xml:34
+#, no-c-format
+msgid "<application>me</application> can't be turned off."
+msgstr "Das <application>me</application> kann nicht ausgemacht werden."
+
+#. Tag: para
+#: lauri.xml:36
+#, no-c-format
+msgid "Leading &quot;Text&quot; for &lauri;"
+msgstr "&quot;Starttext&quot; f&uuml;r &lauri;"
+
+#. Tag: para
+#: lauri.xml:39
+#, no-c-format
+msgid ""
+"we pretend her name was Höpfner, but that <anchor id=\"help\"/> is a good "
+"name too"
+msgstr ""
+"sagen wir mal sie heisst Höpfner, aber <anchor id=\"help\"/> ist auch gut"
+
+#. Tag: para
+#: lauri.xml:39
+#, no-c-format
+msgid "<keycap> Shift </keycap> <keycap> help </keycap>"
+msgstr "<keycap> Schieber </keycap> <keycap> Hilfe </keycap>"
+
+#. Tag: primary
+#: lauri.xml:45
+#, no-c-format
+msgid "<primary>kde</primary>"
+msgstr "<primary>kde.de</primary>"
+
+#. Tag: para
+#: lauri.xml:46
+#, no-c-format
+msgid ""
+"an archive of the developer's mailing list is at <ulink url=\"http://lists."
+"kde.org/?l=kde-kmail&amp;r=1&amp;w=2\">lists.kde.org</ulink>."
+msgstr ""
+"Es gibt ein Archiv <ulink url=\"http://lists.kde.org/?l=kde-kmail&amp;"
+"r=1&amp;w=2\">lists.kde.org</ulink>."
+
+#. Tag: trans_comment
+#: lauri.xml:51
+#, no-c-format
+msgid "GIVE_ME_CREDIT"
+msgstr "<para>Habe ich gemacht - toll ne?</para>"
+
+#. Tag: term
+#: lauri.xml:56
+#, no-c-format
+msgid "Text 1"
+msgstr "Schrift 1"
+
+#. Tag: para
+#: lauri.xml:60
+#, no-c-format
+msgid "Text 2"
+msgstr "Schrift 2"
+
+#. Tag: para
+#: lauri.xml:63
+#, no-c-format
+msgid "Text 3 \"everything\""
+msgstr "Text 3 \"alles\""
+
+#. Tag: term
+#: lauri.xml:65
+#, no-c-format
+msgid "Everything"
+msgstr "Alles"
+
+#. Tag: para
+#: lauri.xml:65
+#, no-c-format
+msgid "Is correct"
+msgstr "Ist klar"
+
+#. Tag: term
+#: lauri.xml:66
+#, no-c-format
+msgid "Nothing"
+msgstr "Nichts"
+
+#. Tag: para
+#: lauri.xml:66
+#, no-c-format
+msgid "Is wrong"
+msgstr "ist falsch"
+
+#. Tag: para
+#: lauri.xml:68
+#, no-c-format
+msgid "Text 4 \\\"even more\\\""
+msgstr "Text 4 \\\"noch mehr\\\""
+
+#. Tag: para
+#: lauri.xml:73
+#, no-c-format
+msgid "Text 4 \\\"even less\\\""
+msgstr "Text 4 \\\"noch weniger\\\""
+
+#. Tag: menuchoice
+#: lauri.xml:85
+#, no-c-format
+msgid ""
+"<shortcut><keycombo><keycap>Ctrl</keycap><keycap>N</keycap></keycombo></"
+"shortcut> <guimenu><accel>F</accel>ile</guimenu><guimenuitem><accel>N</"
+"accel>ew</guimenuitem>"
+msgstr ""
+"<shortcut><keycombo><keycap>Ctrl</keycap><keycap>N</keycap></keycombo></"
+"shortcut> <guimenu><accel>D</accel>atei</guimenu><guimenuitem><accel>N</"
+"accel>eu</guimenuitem>"
+
+#. Tag: action
+#: lauri.xml:88
+#, no-c-format
+msgid "This starts a new Document in a new instance of the editor."
+msgstr "Dies macht alles neu."
+
+#. Tag: title
+#: lauri.xml:96
+#, no-c-format
+msgid "What XML looks like"
+msgstr "Wie XML aussieht"
+
+#. Tag: para
+#: lauri.xml:98
+#, no-c-format
+msgid ""
+"Here is an example of an XML file used by <application>Columbo</application> "
+"to describe a search site on the Internet:"
+msgstr "Dies ist <application>Columbo</application>:"
+
+#. Tag: programlisting
+#: lauri.xml:110
+#, no-c-format
+msgid ""
+"<![CDATA[<!DOCTYPE search>\n"
+"<search \n"
+" name=\"Altavista\" \n"
+" channel=\"web\"\n"
+" method=\"get\"\n"
+" action=\"http://www.altavista.com/cgi-bin/query\"\n"
+">\n"
+"\n"
+" <input name=\"pg\" value=\"q\"/>\n"
+" <input name=\"sc\" value=\"on\"/>\n"
+" <input name=\"hl\" value=\"on\"/>\n"
+" <input name=\"kl\" value=\"XX\"/>\n"
+" <input name=\"stype\" value=\"stext\"/>\n"
+" <input name=\"q\" user=\"true\"/>\n"
+"\n"
+" <interpret\n"
+" resultListStart=\"&lt;dl&gt;\"\n"
+" resultItemStart=\"&lt;dt&gt;\"\n"
+" relevanceStart=\"\"\n"
+" resultListEnd=\"&lt;/td&gt;\"\n"
+" resultItemEnd=\"&lt;/dl&gt;\"\n"
+" relevanceEnd=\"\"\n"
+" />\n"
+"</search>]]>"
+msgstr ""
+"\n"
+"<![CDATA[<!DOCTYPE search>\n"
+"<search \n"
+" name=\"Altawista\" \n"
+" channel=\"Netz\"\n"
+" method=\"krieg\"\n"
+" action=\"http://www.altawista.com/cgi-bin/query\"\n"
+">\n"
+"\n"
+" <input name=\"pg\" value=\"q\"/>\n"
+" <input name=\"sc\" value=\"on\"/>\n"
+" <input name=\"hl\" value=\"on\"/>\n"
+" <input name=\"kl\" value=\"XX\"/>\n"
+" <input name=\"stype\" value=\"stext\"/>\n"
+" <input name=\"q\" user=\"wahr\"/>\n"
+"\n"
+" <interpret\n"
+" resultListAnfang=\"&lt;dl&gt;\"\n"
+" resultItemAnfang=\"&lt;dt&gt;\"\n"
+" relevanceAnfang=\"\"\n"
+" resultListEnde=\"&lt;/td&gt;\"\n"
+" resultItemEnd=\"&lt;/dl&gt;\"\n"
+" relevanceEnd=\"\"\n"
+" />\n"
+"</search>]]>"
+
+#. Tag: para
+#: lauri.xml:113
+#, no-c-format
+msgid ""
+"This instruction is normally used to declare the DTD of the document. Here "
+"no DTD is used, and only the name of the root element (<varname>search</"
+"varname>) appears."
+msgstr "Das ist normalerweise DTD"
+
+#. Tag: para
+#: lauri.xml:120
+#, no-c-format
+msgid ""
+"<sgmltag class=\"starttag\">search</sgmltag> begins the root element. Here, "
+"it extends to the end of the document (<sgmltag class=\"endtag\">search</"
+"sgmltag>)."
+msgstr ""
+"<sgmltag class=\"starttag\">search</sgmltag> begins the root element. Here, "
+"it extends to the end of the document (<sgmltag class=\"endtag\">search</"
+"sgmltag>)."
+
+#. Tag: para
+#: lauri.xml:127
+#, no-c-format
+msgid ""
+"This is an example of an empty element. Empty elements do not need a closing "
+"tag (which would be <varname>&lt;/input&gt;</varname> in this case)."
+msgstr ""
+"This is an example of an empty element. Empty elements do not need a closing "
+"tag (which would be <varname>&lt;/input&gt;</varname> in this case)."
+
+#. Tag: title
+#: lauri.xml:139
+#, no-c-format
+msgid "The ugly part"
+msgstr "Der schlimme Teil"
+
+#. Tag: para
+#: lauri.xml:140
+#, no-c-format
+msgid "Ending Text:"
+msgstr "Ende:"
+
+#. Tag: literallayout
+#: lauri.xml:143
+#, no-c-format
+msgid ""
+"Matthias Hoelzer\n"
+"KDE-Verein i.G.\n"
+"Account-Nr. 2798296\n"
+"\n"
+"Staedtische Sparkasse Wuerzburg\n"
+"Hofstrasse 9\n"
+"97070 Wuerzburg\n"
+"Germany\n"
+"BLZ 790 500 00\n"
+"SWIFT-Address: BYLA DE 77\n"
+"\n"
+"print \"$b4 /path/to/KDE/libs/libpng.a $af\\n\"; \\\n"
+"you see it here\n"
+"whereever"
+msgstr ""
+"\n"
+"Matthias Hoelzer\n"
+"KDE-Verein i.G.\n"
+"Account-Nr. 2798296\n"
+"\n"
+"FrankenSWIFT-Address: BYLA DE 77\n"
+"hallo Du"
+
+#. Tag: screen
+#: lauri.xml:146
+#, no-c-format
+msgid ""
+"Expect ogin: <lineannotation># remember, we do ordinary "
+"terminal login</lineannotation>\n"
+"ID \"\" <lineannotation># kppp sends the id you "
+"configured in the main dialog</lineannotation>\n"
+"Expect for userxyz: <lineannotation># a list of available numbers "
+"is shown, the user should choose one</lineannotation> \n"
+"Send userxyz-home <lineannotation># the user wants to be called "
+"back on their home number</lineannotation>\n"
+"Expect ogin: <lineannotation># The callback process is now "
+"running, a new connection, and so a new login.</lineannotation>\n"
+"ID\n"
+"Expect assword: <lineannotation># Now send your password</"
+"lineannotation>\n"
+"Expect &gt; <lineannotation># Wait for the command "
+"prompt (the prompt may vary)</lineannotation>\n"
+"Send start_ppp <lineannotation># this command starts the pppd</"
+"lineannotation>"
+msgstr ""
+"\n"
+"Expect ogin: <lineannotation># Dies ist alles nicht so "
+"schlimm!</lineannotation>\n"
+"ID \"\" <lineannotation># kppp sends the id you "
+"configured in the main dialog</lineannotation>\n"
+"Expect for userxyz: <lineannotation># a list of available numbers "
+"is shown, the user should choose one</lineannotation> \n"
+"Send userxyz-home <lineannotation># the user wants to be called "
+"back on their home number</lineannotation>\n"
+"Expect ogin: <lineannotation># The callback process is now "
+"running, a new connection, and so a new login.</lineannotation>\n"
+"ID\n"
+"Expect assword: <lineannotation># Now send your password</"
+"lineannotation>\n"
+"Expect &gt; <lineannotation># Wait for the command "
+"prompt (the prompt may vary)</lineannotation>\n"
+"Send start_ppp <lineannotation># this command starts the pppd</"
+"lineannotation>"
+
+#. Tag: screen
+#: lauri.xml:150
+#, no-c-format
+msgid ""
+"Send <lineannotation># send an empty string</"
+"lineannotation>\n"
+"Expect ID:\n"
+"Send itsme\n"
+"Expect word:\n"
+"Send forgot\n"
+"Expect granted\n"
+"Send ppp"
+msgstr ""
+"\n"
+"Send <lineannotation># send einen leerenstring</"
+"lineannotation>\n"
+"Expect ID:\n"
+"Send ichbins\n"
+"Expect word:\n"
+"Send forgot\n"
+"Expect granted\n"
+"Send ppp"
+
+#. Tag: programlisting
+#: lauri.xml:152
+#, no-c-format
+msgid ""
+"-&gt; #include &lt;qpixmap.h&gt;\n"
+"-&gt; #include &lt;qpen.h&gt;\n"
+"\n"
+" class KScribbleDoc\n"
+" {\n"
+"\n"
+"-&gt; protected:\n"
+"\n"
+"-&gt; QPen currentPen(){ return pen;}; \n"
+" \n"
+"-&gt; int penWidth()\n"
+"-&gt; { return pen.width(); }\n"
+"\n"
+" public slots:\n"
+" void updateAllViews(KScribbleView *sender);\n"
+" \n"
+" protected:\n"
+" \n"
+"-&gt; QPixmap buffer;\n"
+" \n"
+" private:\n"
+"-&gt; QPen pen;\n"
+" /** the modified flag of the current document */\n"
+" bool modified;"
+msgstr ""
+"\n"
+"-&gt; #include &lt;qpixmap.h&gt;\n"
+"-&gt; #include &lt;qpen.h&gt;\n"
+" class KScribbleDoc\n"
+" {\n"
+"-&gt; protected:\n"
+"-&gt; QPen currentPen(){ return pen;}; \n"
+" \n"
+"-&gt; int penWidth()\n"
+"-&gt; { return pen.width(); }\n"
+" public slots:\n"
+" void updateAllViews(KScribbleView *sender);\n"
+" \n"
+" protected:\n"
+" \n"
+"-&gt; QPixmap buffer;\n"
+" \n"
+" private:\n"
+"-&gt; QPen pen;\n"
+" /** das veraenderte flag of the current document */\n"
+" bool modified;"
diff --git a/poxml/lauri.xml b/poxml/lauri.xml
new file mode 100644
index 00000000..27715981
--- /dev/null
+++ b/poxml/lauri.xml
@@ -0,0 +1,241 @@
+<?xml version="1.0" ?>
+<!DOCTYPE book PUBLIC "-//KDE//DTD DocBook XML V4.2-Based Variant V1.1//EN" "dtd/kdex.dtd" [
+ <!ENTITY % English "INCLUDE" > <!-- change language only here -->
+ <!ENTITY lauri "<emphasis>Lauri</emphasis>" >
+]>
+
+<book>
+
+
+<bookinfo>
+<date>06/08/2000</date>
+<releaseinfo>0.05.00</releaseinfo>
+
+<!-- *********************** Test **************** -->
+
+<title>test document</title>
+<author><firstname>Stephan</firstname><surname>Kulow</surname></author>
+
+<abstract><para>This is nonsense</para></abstract>
+<keywordset><keyword>KDE</keyword></keywordset>
+
+</bookinfo>
+
+<chapter id="hello">
+<title>&quot;Text&quot; for &lauri;</title>
+<sect1>
+<title>Section 1</title>
+<sect2>
+<title>Section 1.1</title>
+ <anchor id="try"/>
+ <para><emphasis><emphasis role="blah">Warum kann ich
+ meinem Rechner nicht einfach
+ ausschalten?</emphasis></emphasis>Hier noch</para>
+ <para><application>me</application> can't be turned off.</para>
+<para>
+ <note><para>
+ Leading &quot;Text&quot; for &lauri;
+ </para></note>
+ <caution><para>we pretend her name was Höpfner, but that <anchor id="help"/> is a good name too</para></caution>
+ <keycap>
+ Shift
+ </keycap>
+ <keycap>
+ help
+ </keycap><indexterm><primary>kde</primary></indexterm>
+ <tip><para>an archive of the
+developer's mailing list is at <ulink
+url="http://lists.kde.org/?l=kde-kmail&amp;r=1&amp;w=2">lists.kde.org</ulink>.
+ </para></tip>
+</para>
+<!-- TRANS:GIVE_ME_CREDIT -->
+
+<para>
+ <variablelist>
+ <varlistentry>
+ <term>
+ Text 1
+ </term>
+ <listitem>
+ <para id="blah">
+ Text 2
+ <note>
+ <para>
+ Text 3 "everything"
+ <variablelist><varlistentry><term>Everything</term><listitem><para>Is correct</para></listitem></varlistentry></variablelist>
+ <variablelist><varlistentry><term>Nothing</term><listitem><para>Is wrong</para></listitem></varlistentry></variablelist>
+ <footnote>
+ <para>
+ Text 4 \"even more\"
+ </para>
+ <para>
+ <note>
+ <para>
+ Text 4 \"even less\"
+ </para>
+ </note>
+ </para>
+ </footnote>
+ </para>
+ </note>
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><anchor id="new"/><menuchoice>
+<shortcut><keycombo><keycap>Ctrl</keycap><keycap>N</keycap></keycombo></shortcut>
+<guimenu><accel>F</accel>ile</guimenu><guimenuitem><accel>N</accel>ew</guimenuitem></menuchoice></term>
+ <listitem><para><action>This starts a new Document in a new instance of the
+editor.</action></para>
+</listitem>
+ </varlistentry>
+ </variablelist>
+</para>
+</sect2>
+ <sect2 id="xml-format">
+ <title>What XML looks like</title>
+
+ <para>
+ Here is an example of an XML file used
+ by <application>Columbo</application> to describe a search site on the
+ Internet:
+ </para>
+ <para>
+ <programlistingco>
+ <areaspec>
+ <area id="xml.doctype" coords="1"/>
+ <area id="xml.rootel" coords="2"/>
+ <area id="xml.nestedel" coords="9"/>
+ </areaspec>
+ <programlisting>
+<![CDATA[<!DOCTYPE search>
+<search
+ name="Altavista"
+ channel="web"
+ method="get"
+ action="http://www.altavista.com/cgi-bin/query"
+>
+
+ <input name="pg" value="q"/>
+ <input name="sc" value="on"/>
+ <input name="hl" value="on"/>
+ <input name="kl" value="XX"/>
+ <input name="stype" value="stext"/>
+ <input name="q" user="true"/>
+
+ <interpret
+ resultListStart="&lt;dl&gt;"
+ resultItemStart="&lt;dt&gt;"
+ relevanceStart=""
+ resultListEnd="&lt;/td&gt;"
+ resultItemEnd="&lt;/dl&gt;"
+ relevanceEnd=""
+ />
+</search>]]>
+ </programlisting>
+ <calloutlist>
+ <callout arearefs="xml.doctype">
+ <para>
+ This instruction is normally used to declare the DTD of the
+ document. Here no DTD is used, and only the name of the root
+ element (<varname>search</varname>) appears.
+ </para>
+ </callout>
+ <callout arearefs="xml.rootel">
+ <para>
+ <sgmltag class="starttag">search</sgmltag> begins the root
+ element. Here, it extends to the end of the document
+ (<sgmltag class="endtag">search</sgmltag>).
+ </para>
+ </callout>
+ <callout arearefs="xml.nestedel">
+ <para>
+ This is an example of an empty element. Empty elements do not
+ need a closing tag (which would be
+ <varname>&lt;/input&gt;</varname> in this case).
+ </para>
+ </callout>
+ </calloutlist>
+ </programlistingco>
+ </para>
+
+ </sect2>
+<sect2>
+<title>The ugly part</title>
+<para>
+ Ending Text:
+
+<literallayout>
+Matthias Hoelzer
+KDE-Verein i.G.
+Account-Nr. 2798296
+
+Staedtische Sparkasse Wuerzburg
+Hofstrasse 9
+97070 Wuerzburg
+Germany
+BLZ 790 500 00
+SWIFT-Address: BYLA DE 77
+
+print "$b4 /path/to/KDE/libs/libpng.a $af\n"; \
+you see it here
+whereever
+</literallayout>
+</para>
+<para>
+<screen>
+Expect ogin: <lineannotation># remember, we do ordinary terminal login</lineannotation>
+ID "" <lineannotation># kppp sends the id you configured in the main dialog</lineannotation>
+Expect for userxyz: <lineannotation># a list of available numbers is shown, the user should choose one</lineannotation>
+Send userxyz-home <lineannotation># the user wants to be called back on their home number</lineannotation>
+Expect ogin: <lineannotation># The callback process is now running, a new connection, and so a new login.</lineannotation>
+ID
+Expect assword: <lineannotation># Now send your password</lineannotation>
+Expect &gt; <lineannotation># Wait for the command prompt (the prompt may vary)</lineannotation>
+Send start_ppp <lineannotation># this command starts the pppd</lineannotation>
+</screen>
+</para>
+
+<para>
+<screen>
+Send <lineannotation># send an empty string</lineannotation>
+Expect ID:
+Send itsme
+Expect word:
+Send forgot
+Expect granted
+Send ppp
+</screen>
+
+<programlisting>
+-&gt; #include &lt;qpixmap.h&gt;
+-&gt; #include &lt;qpen.h&gt;
+
+ class KScribbleDoc
+ {
+
+-&gt; protected:
+
+-&gt; QPen currentPen(){ return pen;};
+
+-&gt; int penWidth()
+-&gt; { return pen.width(); }
+
+ public slots:
+ void updateAllViews(KScribbleView *sender);
+
+ protected:
+
+-&gt; QPixmap buffer;
+
+ private:
+-&gt; QPen pen;
+ /** the modified flag of the current document */
+ bool modified;
+</programlisting>
+</para>
+</sect2>
+</sect1>
+</chapter>
+</book>
+
diff --git a/poxml/parser.cpp b/poxml/parser.cpp
new file mode 100644
index 00000000..c34976bf
--- /dev/null
+++ b/poxml/parser.cpp
@@ -0,0 +1,1008 @@
+// #define POXML_DEBUG
+
+#include "parser.h"
+#include <iostream>
+#include <stdlib.h>
+#include <assert.h>
+#include <qregexp.h>
+
+using namespace std;
+
+static const char *singletags[] = {"beginpage","imagedata", "colspec", "spanspec",
+ "anchor", "xref", "area",
+ "footnoteref", "void", "inlinegraphic",
+ "glosssee", "graphic", "xi:include",
+ 0};
+static const char *cuttingtags[] = {"bridgehead", "trans_comment", "para", "title", "term",
+ "entry", "contrib", "keyword", "example",
+ "note", "footnote", "caution",
+ "informalexample", "remark", "comment",
+ "imageobject", "varlistentry", "thead",
+ "tbody", "tgroup", "row", "screenshot", "screeninfo",
+ "variablelist", "step", "procedure",
+ "step", "holder", "listitem", "important",
+ "author", "itemizedlist", "orderedlist",
+ "caption", "textobject", "mediaobject",
+ "tip", "glossdef", "inlinemediaobject",
+ "simplelist", "member", "glossentry",
+ "areaspec", "corpauthor", "indexterm",
+ "calloutlist", "callout", "subtitle",
+ "table", "part", "xi:fallback", "primary",
+ "secondary", "chapter", "sect1", "sect2",
+ "figure", "abstract", "sect3", "sect", "sect4",
+ "warning", "preface", "authorgroup", "keywordset",
+ "informaltable", "qandaentry", "question", "answer",
+ "othercredit", "affiliation", "qandaset",
+ "cmdsynopsis", "funcsynopsis", "funcsynopsisinfo" ,
+ "epigraph", "attribution", "glossary", "chapterinfo",
+ "glossdiv", "blockingquote", "simplesect", "section",
+ "qandadiv", "refsect1", "refmeta", "formalpara",
+ "refentry", "refnamediv", "refpurpose", "refentrytitle",
+ "refmiscinfo", "refsect2", "refsect3", "refsect1info",
+ "refsect2info", "refsect3info", "refsection", "refsectioninfo",
+ "refsynopsisdiv", "refsysnopsisdivinfo", "remark",
+ "revdescription", "glossentry", "partinfo",
+ "segmentedlist", "segtitle", "seg", "seglistitem", "screenco",
+ 0};
+static const char *literaltags[] = {"literallayout", "synopsis", "screen",
+ "programlisting", 0};
+
+bool StructureParser::fatalError ( const QXmlParseException &e )
+{
+ cerr << "fatalError " << e.message().latin1() << " " << e.lineNumber() << " "
+ << e.columnNumber() << endl;
+ return false;
+}
+
+bool StructureParser::startDocument()
+{
+ infos_reg = QRegExp("\\s*poxml_line=\"(\\d+)\" poxml_col=\"(\\d+)\"");
+ do_not_split_reg = QRegExp("\\s*condition=\"do-not-split\"");
+ message = "";
+ inside = 0;
+ return true;
+}
+
+bool StructureParser::isCuttingTag(const QString &qName)
+{
+ int index = 0;
+ while (cuttingtags[index]) {
+ if (cuttingtags[index] == qName)
+ return true;
+ index++;
+ }
+ return isLiteralTag(qName);
+}
+
+bool StructureParser::isSingleTag(const QString &qName)
+{
+ int index = 0;
+ while (singletags[index]) {
+ if (singletags[index] == qName)
+ return true;
+ index++;
+ }
+ return false;
+}
+
+bool StructureParser::isLiteralTag(const QString &qName)
+{
+ int index = 0;
+ while (literaltags[index]) {
+ if (literaltags[index] == qName)
+ return true;
+ index++;
+ }
+ return false;
+}
+
+bool StructureParser::skippedEntity ( const QString & name )
+{
+ if (inside)
+ message += QString("&%1;").arg(name);
+ return true;
+}
+
+bool StructureParser::startElement( const QString& , const QString& ,
+ const QString& qName,
+ const QXmlAttributes & attr )
+{
+ QString tname = qName.lower();
+
+ bool first = false;
+
+ if (isCuttingTag(tname)) {
+ if (!inside) {
+ message = QString::null;
+ list.pc.increasePara();
+ startline = locator->lineNumber();
+ startcol = locator->columnNumber();
+ first = true;
+ }
+ inside++;
+ }
+
+ if (inside)
+ {
+ QString tmp = "<" + tname;
+ for (int i = 0; i < attr.length(); i++) {
+ tmp += QString(" %1=\"%2\"").arg(attr.qName(i)).arg(attr.value(i));
+ }
+ tmp += QString(" poxml_line=\"%1\"").arg(locator->lineNumber());
+ tmp += QString(" poxml_col=\"%1\"").arg(locator->columnNumber());
+
+ if (isSingleTag(qName))
+ tmp += "/>";
+ else
+ tmp += ">";
+ message += tmp;
+ if (first)
+ startcol -= message.length();
+ }
+
+ if (tname == "anchor" || tname.left(4) == "sect" || tname == "chapter")
+ if (!attr.value("id").isEmpty()) list.pc.addAnchor(attr.value("id"));
+
+ return true;
+}
+
+bool StructureParser::startCDATA()
+{
+ if ( inside )
+ message += "<![CDATA[";
+ return true;
+}
+
+bool StructureParser::endCDATA()
+{
+ if ( inside )
+ message += "]]>";
+ return true;
+}
+
+bool StructureParser::isClosure(const QString &message)
+{
+ assert(message.at(0) == '<');
+ int endindex = 1;
+ while (!message.at(endindex).isSpace() && message.at(endindex) != '>')
+ endindex++;
+ QString tag = message.mid(1, endindex - 1);
+ return closureTag(message, tag);
+}
+
+bool StructureParser::closureTag(const QString& message, const QString &tag)
+{
+#ifdef POXML_DEBUG
+ qDebug("closureTag %s %s", message.latin1(), tag.latin1());
+#endif
+
+ int inside = 0;
+ uint index = 0;
+ while (true)
+ {
+ int nextclose = message.find(QRegExp(QString::fromLatin1("</%1[\\s>]").arg(tag)), index);
+ int nextstart = message.find(QRegExp(QString::fromLatin1("<%1[>\\s]").arg(tag)), index);
+ // qDebug("finding %d %d %d %d", nextstart, nextclose, index, inside);
+ if (nextclose == -1) {
+#ifdef POXML_DEBUG
+ qDebug("ending on no close anymore %d %d %d %d", (!inside && index >= message.length()), inside, index, message.length());
+#endif
+ return !inside && index >= message.length();
+ }
+ if (nextstart == -1)
+ nextstart = message.length() + 1;
+
+ if (nextstart < nextclose) {
+ inside++;
+ index = nextstart + 1;
+ while (message.at(index) != '>')
+ index++;
+ index++;
+ } else {
+ inside--;
+ index = nextclose + 1;
+ while (message.at(index) != '>')
+ index++;
+ index++;
+ if (!inside) {
+#ifdef POXML_DEBUG
+ qDebug("ending on exit %d", index >= message.length());
+#endif
+ return index >= message.length();
+ }
+ }
+ }
+}
+
+void StructureParser::descape(QString &message)
+{
+ uint index = 0;
+ stripWhiteSpace( message );
+
+ int inside = 0;
+ bool lastws = false;
+
+ while (index < message.length()) {
+ switch (message.at(index).latin1()) {
+ case '\n':
+ case '\t':
+ case '\r':
+ if (!inside)
+ message[index] = ' ';
+ case ' ':
+ if (!inside && lastws)
+ message[index] = '\010';
+ lastws = true;
+ break;
+ case '<': {
+ uint endindex = index+1;
+ while (endindex < message.length() && !message.at(endindex).isSpace() &&
+ message.at(endindex) != '>')
+ endindex++;
+ QString tag = message.mid(index + 1, endindex - index - 1);
+ if (tag.at(0) == '/') {
+ if (isLiteralTag(tag.mid(1)))
+ inside--;
+ } else
+ if (isLiteralTag(tag))
+ inside++;
+ break;
+ }
+ default:
+ lastws = false;
+ }
+
+ index++;
+ }
+ message.replace(QRegExp("\010"), "");
+}
+
+bool StructureParser::formatMessage(MsgBlock &msg) const
+{
+#ifdef POXML_DEBUG
+ qDebug("formatMessage %s", msg.msgid.latin1());
+#endif
+
+ int offset = 0;
+ bool changed = false;
+ bool recurse = true;
+
+ if (msg.msgid.isEmpty())
+ return true;
+
+ for (int index = 0; msg.msgid.at(index) == ' '; index++, offset++);
+ stripWhiteSpace( msg.msgid );
+
+ // removing starting single tags
+ for (int index = 0; singletags[index]; index++)
+ {
+ int slen = strlen(singletags[index]);
+
+ if (msg.msgid.left(slen + 1) == QString::fromLatin1("<%1").arg(singletags[index]) &&
+ !msg.msgid.at( slen + 1 ).isLetterOrNumber() )
+ {
+#ifdef POXML_DEBUG
+ qDebug("removing single tag %s", singletags[index]);
+#endif
+ int strindex = strlen(singletags[index]) + 1;
+ while (msg.msgid.at(strindex) != '>')
+ strindex++;
+ msg.msgid = msg.msgid.mid(strindex + 1);
+ changed = true;
+ offset += strindex + 1;
+ for (int index = 0; msg.msgid.at(index) == ' '; index++, offset++) ;
+ stripWhiteSpace( msg.msgid );
+ }
+ }
+
+ while (msg.msgid.right(2) == "/>")
+ {
+ int strindex = msg.msgid.length() - 2;
+ while (msg.msgid.at(strindex) != '<')
+ strindex--;
+ msg.msgid = msg.msgid.left(strindex);
+ stripWhiteSpace( msg.msgid ); // only removed space at the end
+ changed = true;
+ }
+
+ for (int index = 0; msg.msgid.at(index) == ' '; index++, offset++) ;
+ stripWhiteSpace( msg.msgid );
+
+ while (true) {
+ if (msg.msgid.at(0) != '<')
+ break;
+ if (msg.msgid.at(msg.msgid.length() - 1) != '>')
+ break;
+ int strindex = 1;
+ while (msg.msgid.at(strindex) != ' ' && msg.msgid.at(strindex) != '>')
+ strindex++;
+ QString starttag = msg.msgid.mid(1, strindex - 1);
+ int endindex = msg.msgid.length() - 2;
+ while (msg.msgid.at(endindex) != '<' && msg.msgid.at(endindex + 1) != '/')
+ endindex--;
+#ifdef POXML_DEBUG
+ qDebug("endIndex %d", endindex);
+#endif
+ strindex = endindex;
+ QString orig = msg.msgid;
+
+ QString endtag = msg.msgid.mid(endindex + 2, msg.msgid.length() - (endindex + 2) - 1);
+ QString endtag_attr = endtag.mid(endtag.find(' '), endtag.length());
+ endtag.replace(infos_reg, "");
+ if (endtag == starttag) {
+ if (!closureTag(msg.msgid, starttag))
+ break;
+
+ // removing start/end tags
+ msg.msgid = msg.msgid.left(endindex);
+ strindex = 0;
+ while (msg.msgid.at(strindex) != '>')
+ strindex++;
+ QString attr = msg.msgid.left(strindex);
+ msg.msgid = msg.msgid.mid(strindex + 1);
+ offset += strindex + 1;
+ for (int index = 0; msg.msgid.at(index) == ' '; index++, offset++) ;
+ stripWhiteSpace( msg.msgid );
+ msg.tag = starttag;
+
+ if (infos_reg.search(attr) >= 0) {
+ msg.lines.first().start_line = infos_reg.cap(1).toInt();
+ msg.lines.first().start_col = infos_reg.cap(2).toInt();
+#ifdef POXML_DEBUG
+ qDebug("col %s %s %d", attr.latin1(), msg.msgid.latin1(), msg.lines.first().start_col);
+#endif
+ offset = 0;
+
+ if (infos_reg.search(endtag_attr) >= 0) {
+ msg.lines.first().end_line = infos_reg.cap(1).toInt();
+ msg.lines.first().end_col = infos_reg.cap(2).toInt() + 1;
+ }
+ }
+ if (do_not_split_reg.search(attr) >= 0) {
+ msg.do_not_split = true;
+ break;
+ }
+
+ changed = true;
+ } else
+ break;
+ }
+
+#ifdef POXML_DEBUG
+ qDebug("formatMessage result %s %d %d", msg.msgid.latin1(), changed && recurse, msg.lines.first().start_col);
+#endif
+
+ msg.lines.first().offset += offset;
+ if (msg.do_not_split)
+ recurse = false;
+
+ if (changed && recurse)
+ formatMessage(msg);
+
+ return !recurse; // indicates an abort
+}
+
+MsgList StructureParser::splitMessage(const MsgBlock &mb)
+{
+ MsgList result;
+
+ MsgBlock msg1 = mb;
+ MsgBlock msg2 = mb;
+
+ QString message = mb.msgid;
+
+#ifdef POXML_DEBUG
+ qDebug("splitMessage %s", message.latin1());
+#endif
+
+ if (message.at(0) == '<') {
+ int endindex = 1;
+ while (!message.at(endindex).isSpace() && message.at(endindex) != '>')
+ endindex++;
+ QString tag = message.mid(1, endindex - 1);
+
+ if (closureTag(message, tag))
+ goto error;
+
+ if (isCuttingTag(tag))
+ {
+ // if the message starts with a cutting tag, this tag has to
+ // end in between. We split both messages and format them
+ int strindex = endindex;
+ strindex++;
+
+ int inside = 1;
+ while (true) {
+#ifdef POXML_DEBUG
+ qDebug("inside %s %d", message.mid(strindex, 35).latin1(), inside);
+#endif
+
+ // the exception for poxml_* attributes is made in the closing tag
+ int closing_index = message.find(QRegExp(QString::fromLatin1("</%1[\\s>]").arg(tag)),
+ strindex);
+ int starting_index = message.find(QRegExp(QString::fromLatin1("<%1[\\s>]").arg(tag)),
+ strindex);
+
+#ifdef POXML_DEBUG
+ qDebug("index1 %d %d %d", closing_index, starting_index, strindex);
+#endif
+
+ // when a new start was found, we set the start_index after the next match
+ // (and set strindex to it later - increasing inside)
+ if (starting_index != -1) {
+ starting_index += tag.length() + 1;
+ while (message.at(starting_index) != '>')
+ starting_index++;
+ starting_index++;
+ }
+
+#ifdef POXML_DEBUG
+ qDebug("index %d %d %d", closing_index, starting_index, strindex);
+#endif
+
+ assert(closing_index != -1);
+ closing_index += 3 + tag.length();
+ while (message.at(closing_index - 1) != '>')
+ closing_index++;
+
+ if (starting_index == -1) {
+ strindex = closing_index;
+#ifdef POXML_DEBUG
+ qDebug("set strindex %d", strindex);
+#endif
+ inside--;
+ if (!inside)
+ break;
+ continue;
+ }
+ if (closing_index < starting_index)
+ {
+ strindex = closing_index;
+ inside--;
+ } else {
+ strindex = starting_index;
+ inside++;
+ }
+
+ if (!inside)
+ break;
+ }
+
+#ifdef POXML_DEBUG
+ qDebug("split into %s -AAAAAANNNNNNDDDDDD- %s", message.left(strindex).latin1(), message.mid(strindex).latin1());
+#endif
+ msg1.msgid = message.left(strindex);
+ bool leave = formatMessage(msg1);
+
+ msg2.msgid = message.mid(strindex);
+ msg2.lines.first().offset += strindex;
+ leave = leave & formatMessage(msg2);
+
+ if (msg1.lines.first().end_line > msg2.lines.first().start_line ||
+ (msg1.lines.first().end_line == msg2.lines.first().start_line &&
+ msg1.lines.first().end_col > msg2.lines.first().start_col))
+ {
+ msg2.lines.first().start_line = msg1.lines.first().end_line;
+ msg2.lines.first().start_col = msg1.lines.first().end_col;
+ }
+
+#ifdef POXML_DEBUG
+ qDebug("splited %d-%d(%s) and %d-%d(%s)", msg1.lines.first().end_line,msg1.lines.first().end_col,
+ msg1.msgid.latin1(),
+ msg2.lines.first().start_line,msg2.lines.first().start_col, msg2.msgid.latin1());
+#endif
+
+ if (leave) {
+ result.append(msg1);
+ result.append(msg2);
+ return result;
+ }
+ result = splitMessage(msg1);
+ result += splitMessage(msg2);
+ return result;
+ }
+
+ }
+
+ if (message.at(message.length() - 1 ) == '>')
+ {
+ int endindex = message.length() - 1;
+ while (endindex >= 0 && (message.at(endindex) != '<' || message.at(endindex + 1) != '/'))
+ endindex--;
+ QString tag = message.mid(endindex + 2, message.length() - endindex - 3);
+ if (tag.find(' ') > 0 ) {
+ tag = tag.left(tag.find(' '));
+ }
+#ifdef POXML_DEBUG
+ qDebug("behind tag %s", tag.latin1());
+#endif
+
+ if (isCuttingTag(tag))
+ {
+ // if the message ends with a cutting tag, this tag has to
+ // start in between. We split both messages and format them
+ int strindex = endindex;
+
+ int inside = 1;
+ while (true) {
+#ifdef POXML_DEBUG
+ qDebug("inside %s %d", message.mid(strindex, 35).latin1(), inside);
+#endif
+
+ int closing_index = message.findRev(QRegExp(QString::fromLatin1("</%1[\\s>]").arg(tag)),
+ strindex - 1);
+ int starting_index = message.findRev(QRegExp(QString::fromLatin1("<%1[\\s>]").arg(tag)),
+ strindex - 1);
+
+#ifdef POXML_DEBUG
+ qDebug("index1 %d %d %d", closing_index, starting_index, strindex);
+#endif
+
+ if (starting_index == -1) {
+ assert(inside == 1);
+ break;
+ }
+
+ if (closing_index > starting_index)
+ {
+ strindex = closing_index;
+ inside++;
+ } else {
+ strindex = starting_index;
+ inside--;
+ }
+
+ if (!inside)
+ break;
+ }
+
+
+#ifdef POXML_DEBUG
+ qDebug("split2 into \"%s\" -AAAAAANNNNNNNNNDDDDDDDDDDD- \"%s\"", message.left(strindex).latin1(), message.mid(strindex).latin1());
+#endif
+
+ msg1.msgid = message.left(strindex);
+ formatMessage(msg1);
+
+ msg2.msgid = message.mid(strindex);
+ msg2.lines.first().offset += strindex;
+ formatMessage(msg2);
+
+ if (msg1.lines.first().end_line > msg2.lines.first().start_line ||
+ (msg1.lines.first().end_line == msg2.lines.first().start_line &&
+ msg1.lines.first().end_col > msg2.lines.first().start_col))
+ {
+ msg1.lines.first().end_line = msg2.lines.first().start_line;
+ msg1.lines.first().end_col = msg2.lines.first().start_col - 1;
+ }
+
+#ifdef POXML_DEBUG
+ qDebug("splited %d-%d(%s) and %d-%d(%s)", msg1.lines.first().end_line,msg1.lines.first().end_col,
+ msg1.msgid.latin1(),
+ msg2.lines.first().start_line,msg2.lines.first().start_col, msg2.msgid.latin1());
+#endif
+
+ result = splitMessage(msg1);
+ result += splitMessage(msg2);
+
+ return result;
+ }
+ }
+error:
+ result.append(mb);
+ return result;
+}
+
+bool StructureParser::endElement( const QString& , const QString&, const QString& qName)
+{
+ QString tname = qName.lower();
+
+ // qDebug("endElement %s - %s %d", tname.latin1(), message.latin1(), inside);
+
+ if (inside) {
+ if (!isSingleTag(qName)) {
+ message += QString("</%1").arg(tname);
+ message += QString(" poxml_line=\"%1\"").arg(locator->lineNumber());
+ message += QString(" poxml_col=\"%1\"").arg(locator->columnNumber());
+ message += ">";
+ }
+ }
+
+ if (isCuttingTag(tname)) {
+ inside--;
+ if (!inside) {
+ MsgBlock m;
+ descape(message);
+ m.msgid = message;
+
+ BlockInfo bi;
+ bi.start_line = startline;
+ bi.start_col = startcol;
+ bi.end_line = locator->lineNumber();
+ bi.end_col = locator->columnNumber() + 1;
+ bi.offset = m.lines.first().offset;
+ m.lines.append(bi);
+ formatMessage(m);
+
+ MsgList messages = splitMessage(m);
+ for (MsgList::Iterator it = messages.begin();
+ it != messages.end(); ++it)
+ {
+#ifdef POXML_DEBUG
+ qDebug("parser '%s' %d '%s' %d:%d", (*it).msgid.latin1(), (*it).lines.first().offset, message.mid((*it).lines.first().offset, 15).latin1(), (*it).lines.first().start_line, (*it).lines.first().start_col);
+#endif
+ // if the remaining text still starts with a tag, the poxml_ info
+ // is most probably more correct
+ if ((*it).msgid.at(0) == '<' && isClosure((*it).msgid)) {
+ if (infos_reg.search((*it).msgid) >= 0) {
+ (*it).lines.first().start_line = infos_reg.cap(1).toInt();
+ (*it).lines.first().start_col = infos_reg.cap(2).toInt();;
+ (*it).lines.first().offset = 0;
+ }
+ }
+ (*it).msgid.replace(infos_reg, QString::null);
+
+ if (!(*it).msgid.isEmpty())
+ list.append(*it);
+ }
+ }
+ }
+
+ return true;
+}
+
+bool StructureParser::comment ( const QString &c )
+{
+ if (c.left(7) != " TRANS:")
+ return true;
+
+ assert(false);
+ return true;
+}
+
+QString StructureParser::escapeLiterals( const QString &_contents) {
+ QString contents = _contents;
+
+ contents.replace(QRegExp("\n"), "&POXML_LINEFEED;");
+ contents.replace(QRegExp("<"), "&POXML_LT;");
+ contents.replace(QRegExp(">"), "&POXML_GT;");
+ contents.replace(QRegExp("\t"), " ");
+ contents.replace(QRegExp(" "), "&POXML_SPACE;");
+
+ return contents;
+}
+
+QString StructureParser::descapeLiterals( const QString &_contents) {
+ QString contents = _contents;
+
+ contents.replace(QRegExp("&POXML_LINEFEED;"), "\n");
+ contents.replace(QRegExp("&POXML_LT;"), "<");
+ contents.replace(QRegExp("&POXML_GT;"), ">");
+ contents.replace(QRegExp("&POXML_SPACE;"), " ");
+ contents.replace(QRegExp("!POXML_AMP!"), "&");
+ return contents;
+}
+
+void StructureParser::stripWhiteSpace( QString &contents)
+{
+ contents = contents.stripWhiteSpace();
+ bool changed;
+ do {
+ changed = false;
+ if (contents.startsWith("&POXML_LINEFEED;")) {
+ contents = contents.mid(strlen("&POXML_LINEFEED;"), contents.length());
+ changed = true;
+ }
+ if (contents.startsWith("&POXML_SPACE;")) {
+ contents = contents.mid(strlen("&POXML_SPACE;"), contents.length());
+ changed = true;
+ }
+ if (contents.endsWith("&POXML_LINEFEED;")) {
+ contents = contents.left(contents.length() - strlen("&POXML_LINEFEED;"));
+ changed = true;
+ }
+ if (contents.endsWith("&POXML_SPACE;")) {
+ contents = contents.left( contents.length() - strlen("&POXML_SPACE;"));
+ changed = true;
+ }
+ } while (changed);
+}
+
+void StructureParser::cleanupTags( QString &contents )
+{
+ contents.replace(QRegExp("&"), "!POXML_AMP!");
+
+ for (int index = 0; literaltags[index]; index++) {
+ QRegExp start(QString("<%1[\\s>]").arg(literaltags[index]));
+ QRegExp end(QString("</%1[\\s>]").arg(literaltags[index]));
+ int strindex = 0;
+ while (true) {
+ strindex = contents.find(start, strindex);
+ if (strindex < 0)
+ break;
+ while (contents.at(strindex) != '>')
+ strindex++;
+ strindex++; // one more
+ int endindex = contents.find(end, strindex);
+ QString part = contents.mid(strindex, endindex - strindex);
+ QString newpart = escapeLiterals(part);
+ contents.replace(strindex, part.length(), newpart);
+ // this assumes that literal tags to not overlap
+ strindex = strindex + newpart.length();
+ }
+ }
+
+ QRegExp unclosed("</(\\w*)\\s\\s*>");
+ int index = -1;
+ while (true) {
+ index = unclosed.search(contents, index + 1);
+ if (index < 0)
+ break;
+ QString tag = unclosed.cap(1);
+ contents.replace(index, unclosed.matchedLength(), QString("</%1>").arg(tag));
+ }
+
+ QRegExp start("<((\\s*[^<>\\s])*)\\s\\s*(/*)>");
+ start.setMinimal(true);
+
+ index = -1;
+ while (true) {
+ index = start.search(contents, index + 1);
+ if (index < 0)
+ break;
+ QString tag = start.cap(1);
+ QString cut = start.capturedTexts().last();
+ // qDebug("UNCLO %s %d -%s- -%s-", start.cap(0).latin1(), index, tag.latin1(), cut.latin1());
+ contents.replace(index, start.matchedLength(), QString("<%1%2>").arg(tag).arg(cut));
+ }
+ QRegExp singletag("<(\\w*)\\s([^><]*)/>");
+
+ index = -1;
+ while (true) {
+ index = singletag.search(contents, index + 1);
+ if (index < 0)
+ break;
+ QString tag = singletag.cap(1);
+ if (!StructureParser::isSingleTag(tag)) {
+ contents.replace(index, singletag.matchedLength(), QString("<%1 %2></%3>").arg(tag).arg(singletag.cap(2)).arg(tag));
+ }
+ }
+
+ QRegExp trans_comment("<!-- TRANS:([^<>]*)-->");
+ index = -1;
+ while (true) {
+ index = trans_comment.search(contents, index + 1);
+ if (index < 0)
+ break;
+ QString msgid = trans_comment.cap(1);
+ contents.replace(index, trans_comment.matchedLength(), QString("<trans_comment>%1</trans_comment>").arg(msgid));
+ }
+
+#ifdef POXML_DEBUG
+ qDebug("final %s", contents.latin1());
+#endif
+
+}
+
+static bool removeEmptyTag( QString &contents, const QString & tag)
+{
+// qDebug("cont %s %s", contents.latin1(), tag.latin1());
+
+ QRegExp empty(QString("<%1[^>]*>[\\s\n][\\s\n]*</%2\\s*>").arg(tag).arg(tag));
+ int strindex = 0;
+ while (true) {
+ strindex = contents.find(empty, strindex);
+ if (strindex < 0)
+ break;
+ qDebug("found empty tag %s", tag.latin1());
+ contents.replace(strindex, empty.matchedLength(), " ");
+ strindex++;
+ return true;
+ }
+ return false;
+}
+
+void StructureParser::removeEmptyTags( QString &contents )
+{
+ bool removed;
+ do {
+ removed = false;
+
+ for (int index = 0; cuttingtags[index]; index++) {
+ if (removeEmptyTag(contents, cuttingtags[index])) {
+ removed = true;
+ break;
+ }
+ }
+ // as glossterm has two different semantics, it's likely
+ // to break something when it's cuttingtag
+ if (removeEmptyTag(contents, "glossterm"))
+ removed = true;
+
+ } while (removed);
+}
+
+bool StructureParser::characters(const QString &ch)
+{
+ if (inside && !ch.isEmpty())
+ message += ch;
+ return true;
+}
+
+QString escape(QString message)
+{
+ message.replace(QRegExp("\\\\"), "\\\\");
+ message.replace(QRegExp("\""), "\\\"");
+ return message;
+}
+
+void outputMsg(const char *prefix, const QString &message)
+{
+ QStringList list = QStringList::split('\n', message, true);
+ QString line;
+
+ if (list.count() == 1) {
+ line = list.first();
+ if (line.isEmpty())
+ cout << prefix << " \"\"\n";
+ else
+ cout << prefix << " \"" << escape(line).utf8().data() << "\"\n";
+ } else {
+ cout << prefix << " \"\"\n";
+ for (QStringList::ConstIterator it = list.begin(); it != list.end(); it++) {
+ line = *it;
+ if (!line.isEmpty()) {
+ cout << " \"" << escape(line).utf8().data();
+ if (it == list.fromLast())
+ cout << "\"\n";
+ else
+ cout << "\\n\"\n";
+ } else {
+ cout << " \"";
+ if (it != list.fromLast())
+ cout << "\\n";
+ cout << "\"\n";
+ }
+ }
+ }
+}
+
+QString escapePO(QString msgid)
+{
+ int index = 0;
+ while (true) {
+ index = msgid.find("\\n", index);
+ if (index == -1)
+ break;
+ if (index >= 1 && msgid.at(index - 1) == '\\' && msgid.at(index - 2) != '\\') {
+ msgid.replace(index - 1, 3, "&POXML_LITERALLINEFEED;");
+ index += 3;
+ } else
+ msgid.replace(index, 2, "\n");
+ }
+ index = 0;
+ while (true) {
+ index = msgid.find("\\\"", index);
+ if (index == -1)
+ break;
+ if (index > 1 && msgid.at(index - 1) == '\\' && msgid.at(index - 2) != '\\')
+ msgid.replace(index - 1, 3, "&POXML_LITERALQUOTE;");
+ else
+ msgid.replace(index, 2, "\"");
+ }
+ index = 0;
+ while (true) {
+ index = msgid.find("\\t", index);
+ if (index == -1)
+ break;
+ if (msgid.at(index - 1) == '\\')
+ msgid.replace(index - 1, 3, "\\t");
+ else
+ msgid.replace(index, 2, "\t");
+ }
+ index = 0;
+ while (true) {
+ index = msgid.find("\\\\", index);
+ if (index == -1)
+ break;
+ msgid.replace(index, 2, "\\");
+ index += 1;
+ }
+
+ msgid.replace(QRegExp("&POXML_LITERALLINEFEED;"), "\\n");
+ msgid.replace(QRegExp("&POXML_LITERALQUOTE;"), "\\");
+ return msgid;
+}
+
+
+MsgList parseXML(const char *filename)
+{
+ StructureParser handler;
+ QFile xmlFile( filename );
+ xmlFile.open(IO_ReadOnly);
+
+ QCString ccontents;
+ ccontents.fill(0, xmlFile.size() + 1);
+ memcpy(ccontents.data(), xmlFile.readAll().data(), xmlFile.size());
+ xmlFile.close();
+
+ QString contents = QString::fromUtf8( ccontents );
+ StructureParser::cleanupTags(contents);
+
+ while (true) {
+ int index = contents.find("<!ENTITY");
+ if (index < 0)
+ break;
+ int inside = 0;
+ int endindex = index + 1;
+ QString replacement = "";
+ while (contents.at(endindex) != '>' || inside)
+ {
+ switch (contents.at(endindex).latin1()) {
+ case '<':
+ inside++; break;
+ case '>':
+ inside--; break;
+ case '\n':
+ replacement += '\n';
+ break;
+ default:
+ break;
+ }
+ endindex++;
+ }
+ endindex++;
+ contents.replace(index, endindex - index, replacement);
+ }
+
+ QTextStream ts(contents.utf8(), IO_ReadOnly);
+ QXmlInputSource source( ts );
+ QXmlSimpleReader reader;
+ reader.setFeature( "http://trolltech.com/xml/features/report-start-end-entity", true);
+ reader.setContentHandler( &handler );
+ reader.setLexicalHandler( &handler );
+ reader.setDTDHandler( &handler );
+ // reader.setErrorHandler( &handler );
+ reader.parse( source );
+ MsgList english = handler.getList();
+
+ bool changed = false;
+
+ do {
+ changed = false;
+ QMap<QString, QString> msgids;
+
+ for (MsgList::Iterator it = english.begin();
+ it != english.end(); it++)
+ {
+ QMap<QString,QString>::Iterator found = msgids.find((*it).msgid);
+ if ((*it).msgid.length() < 4) {
+ (*it).msgid = QString("<%1>").arg((*it).tag) + (*it).msgid +
+ QString("</%1>").arg((*it).tag);
+ changed = true;
+ break;
+ }
+ if (found != msgids.end()) {
+ if (found.data() != (*it).tag) {
+#ifdef POXML_DEBUG
+ qDebug("same msgid for '%s' and '%s'", found.data().latin1(), (*it).tag.latin1());
+#endif
+ changed = true;
+ QString msgid = (*it).msgid;
+ for (MsgList::Iterator it2 = english.begin();
+ it2 != english.end(); it2++)
+ {
+ if ((*it2).msgid == msgid)
+ (*it2).msgid = QString("<%1>").arg((*it2).tag) + msgid + QString("</%1>").arg((*it2).tag);
+ }
+ break;
+ }
+ } else {
+ msgids.insert((*it).msgid, (*it).tag);
+ }
+ }
+ } while (changed);
+
+ return english;
+}
+
diff --git a/poxml/parser.h b/poxml/parser.h
new file mode 100644
index 00000000..f63f6cef
--- /dev/null
+++ b/poxml/parser.h
@@ -0,0 +1,124 @@
+#ifndef PARSER_H
+#define PARSER_H
+
+#include <qxml.h>
+#include <qmap.h>
+#include <qregexp.h>
+
+struct BlockInfo {
+ int start_line;
+ int start_col;
+ int end_line;
+ int end_col;
+
+ // used to detect sub-messages
+ int offset;
+
+ BlockInfo() {
+ start_line = 0;
+ start_col = 0;
+ end_line = 0;
+ end_col = 0;
+
+ // used to detect sub-messages
+ offset = 0;
+ }
+};
+
+class MsgBlock {
+ public:
+ MsgBlock() { start = end = 0; do_not_split = false; }
+ MsgBlock(const MsgBlock &rhs ) {
+ *this = rhs;
+ }
+ QValueList<BlockInfo> lines;
+ QString tag;
+ QString comment;
+ QString msgid;
+ QString msgid_plural;
+ QString msgstr;
+ QStringList msgstr_plurals;
+ int start, end;
+ bool do_not_split;
+
+ void operator=(const MsgBlock& rhs) {
+ lines = rhs.lines;
+ tag = rhs.tag;
+ comment = rhs.comment;
+ msgid = rhs.msgid;
+ msgid_plural = rhs.msgid_plural;
+ msgstr = rhs.msgstr;
+ msgstr_plurals = rhs.msgstr_plurals;
+ start = rhs.start;
+ end = rhs.end;
+ do_not_split = rhs.do_not_split;
+ }
+};
+
+class ParaCounter
+{
+public:
+ ParaCounter() { current = 0; }
+ void addAnchor(QString anchor) { anchors.insert(anchor, current); }
+ void increasePara() { current++; }
+
+ QMap<QString, int> anchors;
+ int current;
+};
+
+class MsgList : public QValueList<MsgBlock>
+{
+public:
+ MsgList() {}
+ ParaCounter pc;
+};
+
+class StructureParser : public QXmlDefaultHandler
+{
+public:
+ bool startDocument();
+ bool startElement( const QString&, const QString&, const QString& ,
+ const QXmlAttributes& );
+ bool endElement( const QString&, const QString&, const QString& );
+ bool characters( const QString &ch);
+ static bool isCuttingTag(const QString &tag);
+ static bool isSingleTag(const QString &qName);
+ static bool isLiteralTag(const QString &qName);
+ void setDocumentLocator ( QXmlLocator * l ) { locator = l; }
+ bool skippedEntity ( const QString & name );
+ bool fatalError ( const QXmlParseException & );
+ bool comment ( const QString & );
+ bool error(const QXmlParseException &e ) { return fatalError(e); }
+ bool warning(const QXmlParseException &e ) { return fatalError(e); }
+ MsgList getList() const { return list; }
+ MsgList splitMessage(const MsgBlock &message);
+
+ virtual bool startCDATA();
+ virtual bool endCDATA();
+
+ static bool closureTag(const QString& message, const QString &tag);
+ static bool isClosure(const QString &message);
+ static void descape(QString &message);
+ static QString escapeLiterals( const QString &contents);
+ static QString descapeLiterals( const QString &contents);
+ static void cleanupTags( QString &contents );
+ static void removeEmptyTags( QString &contents);
+ static void stripWhiteSpace( QString &contents);
+
+private:
+ bool formatMessage(MsgBlock &message) const;
+
+ QXmlLocator *locator;
+ QString message;
+ int inside, startline, startcol;
+ int line;
+ MsgList list;
+ mutable QRegExp infos_reg;
+ mutable QRegExp do_not_split_reg;
+};
+
+void outputMsg(const char *prefix, const QString &message);
+MsgList parseXML(const char *filename);
+QString escapePO(QString msgid);
+
+#endif
diff --git a/poxml/po2xml.cpp b/poxml/po2xml.cpp
new file mode 100644
index 00000000..9e8bc1a5
--- /dev/null
+++ b/poxml/po2xml.cpp
@@ -0,0 +1,261 @@
+ // #define POXML_DEBUG
+
+#include "parser.h"
+#include <stdlib.h>
+#include <iostream>
+#include <assert.h>
+#include <qregexp.h>
+
+#include <fstream>
+#include "GettextLexer.hpp"
+#include "GettextParser.hpp"
+#include "antlr/AST.hpp"
+#include "antlr/CommonAST.hpp"
+
+using namespace std;
+
+QString translate(QString xml, QString orig, QString translation)
+{
+ QString prefix;
+ while (xml.at(0) == '<' && orig.at(0) != '<') {
+ // a XML tag as prefix
+ int index = xml.find('>');
+ assert(index != -1);
+ index++;
+ while (xml.at(index) == ' ')
+ index++;
+ prefix = prefix + xml.left(index);
+ xml = xml.mid(index, xml.length());
+ }
+
+ int index = xml.find(orig);
+ if (index == -1) {
+ qWarning("can't find\n%s\nin\n%s", orig.latin1(), xml.latin1());
+ exit(1);
+ }
+ if (!translation.isEmpty())
+ xml.replace(index, orig.length(), translation);
+ return prefix + xml;
+}
+
+int main( int argc, char **argv )
+{
+ if (argc != 3) {
+ qWarning("usage: %s english-XML translated-PO", argv[0]);
+ ::exit(1);
+ }
+
+ MsgList english = parseXML(argv[1]);
+ MsgList translated;
+
+ try {
+ ifstream s(argv[2]);
+ GettextLexer lexer(s);
+ GettextParser parser(lexer);
+ translated = parser.file();
+
+ } catch(exception& e) {
+ cerr << "exception: " << e.what() << endl;
+ return 1;
+ }
+
+ QMap<QString, QString> translations;
+ for (MsgList::ConstIterator it = translated.begin();
+ it != translated.end(); ++it)
+ {
+ QString msgstr;
+ QString msgid = escapePO((*it).msgid);
+ if ((*it).comment.find("fuzzy") < 0)
+ msgstr = escapePO((*it).msgstr);
+
+#ifdef POXML_DEBUG
+ qDebug("inserting translations '%s' -> '%s'", msgid.latin1(),msgstr.latin1());
+#endif
+ translations.insert(msgid, msgstr);
+ }
+
+ QFile xml(argv[1]);
+ xml.open(IO_ReadOnly);
+ QTextStream ds(&xml);
+ ds.setEncoding(QTextStream::UnicodeUTF8);
+ QString xml_text = ds.read();
+ xml.close();
+ QString output;
+ QTextStream ts(&output, IO_WriteOnly);
+ StructureParser::cleanupTags(xml_text);
+
+ QValueList<int> line_offsets;
+ line_offsets.append(0);
+ int index = 0;
+ while (true) {
+ index = xml_text.find('\n', index) + 1;
+ if (index <= 0)
+ break;
+ line_offsets.append(index);
+ }
+
+ int old_start_line = -1, old_start_col = -1;
+ QString old_text;
+ MsgList::Iterator old_it = english.end();
+
+ for (MsgList::Iterator it = english.begin();
+ it != english.end(); ++it)
+ {
+ BlockInfo bi = (*it).lines.first();
+ int start_pos = line_offsets[bi.start_line - 1] + bi.start_col;
+ if (!bi.end_line)
+ continue;
+ int end_pos = line_offsets[bi.end_line - 1] + bi.end_col - 1;
+
+ (*it).start = start_pos;
+ if (old_start_line == bi.start_line &&
+ old_start_col == bi.start_col)
+ {
+ (*old_it).end = bi.offset;
+ (*it).end = end_pos;
+ } else {
+ (*it).lines.first().offset = 0;
+ (*it).end = 0;
+ }
+
+ old_start_line = bi.start_line;
+ old_start_col = bi.start_col;
+ old_it = it;
+ }
+
+ int old_pos = 0;
+
+ for (MsgList::Iterator it = english.begin();
+ it != english.end(); ++it)
+ {
+ BlockInfo bi = (*it).lines.first();
+ int start_pos = line_offsets[bi.start_line - 1] + bi.start_col;
+ if (!bi.end_line)
+ continue;
+ int end_pos = line_offsets[bi.end_line - 1] + bi.end_col - 1;
+
+ QString xml = xml_text.mid(start_pos, end_pos - start_pos);
+ int index = 0;
+ while (true) {
+ index = xml.find("<!--");
+ if (index == -1)
+ break;
+ int end_index = index + 4;
+ while (xml.at(end_index) != '>' ||
+ xml.at(end_index-1) != '-' ||
+ xml.at(end_index-2) != '-')
+ {
+ end_index++;
+ }
+ xml.replace(index, end_index + 1 - index, " ");
+ index = end_index;
+ }
+ StructureParser::descape(xml);
+
+ QString descaped = StructureParser::descapeLiterals((*it).msgid);
+ if (translations.contains(descaped))
+ descaped = translations[descaped];
+
+#ifdef POXML_DEBUG
+ // assert(!descaped.isEmpty());
+#endif
+
+ if ((*it).msgid.at(0) == '<' && StructureParser::isClosure((*it).msgid)) {
+ // if the id starts with a tag, then we remembered the
+ // correct line information and need to strip the target
+ // now, so it fits
+ int index = 0;
+ while ((*it).msgid.at(index) != '>')
+ index++;
+ index++;
+ while ((*it).msgid.at(index) == ' ')
+ index++;
+ QString omsgid = (*it).msgid;
+ (*it).msgid = (*it).msgid.mid(index);
+
+ index = (*it).msgid.length() - 1;
+ while ((*it).msgid.at(index) != '<')
+ index--;
+
+ (*it).msgid = (*it).msgid.left(index);
+
+ if (!descaped.isEmpty()) {
+ if (descaped.at(0) != '<') {
+ qWarning("the translation of '%s' doesn't start with a tag.", omsgid.latin1());
+ exit(1);
+ }
+ index = 0;
+ while (index <= (int)descaped.length() && descaped.at(index) != '>')
+ index++;
+ index++;
+ while (descaped.at(index) == ' ')
+ index++;
+ descaped = descaped.mid(index);
+
+ index = descaped.length() - 1;
+ while (index >= 0 && descaped.at(index) != '<')
+ index--;
+
+ descaped = descaped.left(index);
+ }
+ }
+
+#ifdef POXML_DEBUG
+ qDebug("english \"%s\" ORIG \"%s\" %d(%d-%d) %d(%d-%d) %d %d TRANS \"%s\" %d '%s'", xml.latin1(), (*it).msgid.latin1(),
+ start_pos, bi.start_line, bi.start_col,
+ end_pos, bi.end_line, bi.end_col,
+ (*it).lines.first().offset,
+ (*it).end,
+ translations[(*it).msgid].latin1(), (*it).end,
+ descaped.latin1()
+ );
+#endif
+
+ if ((*it).end) {
+ if (!(*it).lines.first().offset && end_pos != old_pos) {
+ assert(start_pos >= old_pos);
+ ts << xml_text.mid(old_pos, start_pos - old_pos);
+ }
+ assert((*it).end >= bi.offset);
+ ts << translate(xml.mid(bi.offset, (*it).end - bi.offset),
+ (*it).msgid, descaped);
+ old_pos = end_pos;
+ } else {
+ if (start_pos != old_pos) {
+ if (start_pos < old_pos) {
+ qDebug("so far: '%s'", output.latin1());
+ }
+ assert(start_pos > old_pos);
+ ts << xml_text.mid(old_pos, start_pos - old_pos);
+ }
+ old_pos = end_pos;
+ ts << translate(xml,
+ (*it).msgid, descaped);
+ }
+ }
+
+ ts << xml_text.mid(old_pos);
+
+ output.replace(QRegExp("<trans_comment\\s*>"), "");
+ output.replace(QRegExp("</trans_comment\\s*>"), "");
+
+ StructureParser::removeEmptyTags(output);
+
+ index = 0;
+ while (true) {
+ index = output.find(QRegExp(">[^\n]"), index );
+ if ( index == -1 )
+ break;
+ if ( output.at( index - 1 ) == '/' || output.at( index - 1 ) == '-' ||
+ output.at( index - 1 ) == ']' || output.at( index - 1 ) == '?' )
+ index = index + 1;
+ else {
+ output.replace( index, 1, "\n>" );
+ index = index + 2;
+ }
+ }
+ output = StructureParser::descapeLiterals(output);
+
+ cout << output.utf8().data();
+ return 0;
+}
diff --git a/poxml/split.cpp b/poxml/split.cpp
new file mode 100644
index 00000000..28149ed6
--- /dev/null
+++ b/poxml/split.cpp
@@ -0,0 +1,162 @@
+#include "parser.h"
+#include <stdlib.h>
+#include <iostream>
+
+using namespace std;
+
+int main( int argc, char **argv )
+{
+ bool report_mismatches = qstrcmp(getenv("REPORT_MISMATCHES"), "no");
+
+ if (argc != 3) {
+ qWarning("usage: %s english-XML translated-XML", argv[0]);
+ exit(1);
+ }
+
+ MsgList english = parseXML(argv[1]);
+ MsgList translated = parseXML(argv[2]);
+
+ QMap<QString, int>::ConstIterator eit2 = english.pc.anchors.begin();
+
+ QMap<int, QString> errors;
+
+ while (eit2 != english.pc.anchors.end())
+ {
+ if (eit2.data() == translated.pc.anchors[eit2.key()]) {
+ QString key = eit2.key();
+ eit2++;
+ translated.pc.anchors.remove(key);
+ english.pc.anchors.remove(key);
+ } else {
+ errors[eit2.data()] = eit2.key();
+ eit2++;
+ }
+ }
+
+ if (report_mismatches && errors.count()) {
+ for (QMap<int, QString>::ConstIterator it = errors.begin(); it != errors.end(); ++it)
+ {
+ if (translated.pc.anchors.contains(it.data()))
+ fprintf(stderr, "id=\"%s\" not in the same paragraphs (%d vs %d)\n", it.data().latin1(),
+ english.pc.anchors[it.data()], translated.pc.anchors[it.data()]);
+ else {
+ fprintf(stderr, "id=\"%s\" not in the translated paragraphs (it's in paragraph %d in english)\n",
+ it.data().latin1(), english.pc.anchors[it.data()]);
+ }
+ }
+ ::exit(1);
+ }
+
+ MsgList::ConstIterator tit = translated.begin();
+ for (MsgList::Iterator it = english.begin();
+ it != english.end() && tit != translated.end();
+ ++tit, ++it)
+ {
+ (*it).msgstr = (*tit).msgid;
+ }
+
+ bool have_roles_of_translators = false;
+ bool have_credit_for_translators = false;
+
+ QMap<QString, int> msgids;
+ int index = 0;
+
+ for (MsgList::Iterator it = english.begin();
+ it != english.end(); )
+ {
+ if ((*it).msgid == "ROLES_OF_TRANSLATORS") {
+ if ((*it).msgstr.length() && !(*it).msgstr.contains("ROLES_OF_TRANSLATORS")) {
+ have_roles_of_translators = true;
+ }
+ else {
+ MsgList::Iterator tmp = it;
+ ++it;
+ english.remove(tmp);
+ }
+ continue;
+ }
+
+ if ((*it).msgid == "CREDIT_FOR_TRANSLATORS") {
+ if ((*it).msgstr.length() && !(*it).msgstr.contains("CREDIT_FOR_TRANSLATORS")) {
+ have_credit_for_translators = true;
+ }
+ else {
+ MsgList::Iterator tmp = it;
+ ++it;
+ english.remove(tmp);
+ }
+ continue;
+ }
+
+ if (msgids.contains((*it).msgid)) {
+ english[msgids[(*it).msgid]].lines += (*it).lines;
+ if (english[msgids[(*it).msgid]].msgstr != (*it).msgstr) {
+ fprintf(stderr, "two different translations for \"%s\" (\"%s\" and \"%s\") - choosing first one\n",
+ (*it).msgid.latin1(),
+ english[msgids[(*it).msgid]].msgstr.local8Bit().data(),
+ (*it).msgstr.local8Bit().data());
+
+ }
+ MsgList::Iterator tmp = it;
+ it++;
+ english.remove(tmp);
+ } else {
+ msgids.insert((*it).msgid, index);
+ index++;
+ it++;
+ }
+ }
+
+ int counter = 1;
+
+ while (tit != translated.end())
+ {
+ MsgBlock mb;
+ mb.msgid = QString::fromLatin1("appended paragraph %1").arg(counter++);
+ mb.msgstr = (*tit).msgid;
+ mb.lines += (*tit).lines;
+ english.append(mb);
+ tit++;
+ }
+
+ cout << "#, fuzzy\n";
+ cout << "msgid \"\"\n";
+ cout << "msgstr \"\"\n";
+ cout << "\"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\\n\"\n";
+ cout << "\"Last-Translator: FULL NAME <EMAIL@ADDRESS>\\n\"\n";
+ cout << "\"Content-Type: text/plain; charset=utf-8\\n\"\n";
+
+ for (MsgList::ConstIterator it = english.begin();
+ it != english.end(); ++it)
+ {
+ cout << "#: ";
+ for (QValueList<BlockInfo>::ConstIterator it2 =
+ (*it).lines.begin(); it2 != (*it).lines.end(); it2++) {
+ if (it2 != (*it).lines.begin())
+ cout << ", ";
+ cout << "index.docbook:" << (*it2).start_line;
+
+ }
+ cout << "\n";
+ outputMsg("msgid", StructureParser::descapeLiterals( (*it).msgid ));
+ outputMsg("msgstr", StructureParser::descapeLiterals( (*it).msgstr ));
+ cout << "\n";
+ }
+
+ if ( !getenv( "NO_CREDITS" ) ) {
+
+ if ( !have_roles_of_translators ) {
+ outputMsg("msgid", "ROLES_OF_TRANSLATORS");
+ outputMsg("msgstr", "<!--TRANS:ROLES_OF_TRANSLATORS-->");
+ cout << "\n";
+ }
+
+ if ( !have_credit_for_translators) {
+ outputMsg("msgid", "CREDIT_FOR_TRANSLATORS");
+ outputMsg("msgstr", "<!--TRANS:CREDIT_FOR_TRANSLATORS-->");
+ cout << "\n";
+ }
+ }
+
+ return 0;
+}
diff --git a/poxml/swappo.cpp b/poxml/swappo.cpp
new file mode 100644
index 00000000..94c308ae
--- /dev/null
+++ b/poxml/swappo.cpp
@@ -0,0 +1,38 @@
+#include <iostream>
+using namespace std;
+#include "GettextParser.hpp"
+#include <fstream>
+#include "GettextLexer.hpp"
+
+int main(int argc, char **argv)
+{
+ if ( argc != 2 ) {
+ qWarning( "usage: %s pofile", argv[0] );
+ return -1;
+ }
+
+ MsgList translated;
+
+ try {
+ ifstream s(argv[1]);
+ GettextLexer lexer(s);
+ GettextParser parser(lexer);
+ translated = parser.file();
+
+ } catch(exception& e) {
+ cerr << "exception: " << e.what() << endl;
+ return 1;
+ }
+
+ for (MsgList::ConstIterator it = translated.begin();
+ it != translated.end(); ++it)
+ {
+ if ( !( *it ).msgstr.isEmpty() ) {
+ outputMsg("msgid", (*it).msgstr);
+ outputMsg("msgstr", (*it).msgid);
+ cout << "\n";
+ }
+ }
+
+}
+
diff --git a/poxml/transxx.cpp b/poxml/transxx.cpp
new file mode 100644
index 00000000..dc3dde00
--- /dev/null
+++ b/poxml/transxx.cpp
@@ -0,0 +1,130 @@
+#include <iostream>
+using namespace std;
+#include "GettextParser.hpp"
+#include <fstream>
+#include "GettextLexer.hpp"
+
+#include <qregexp.h>
+#include <qdatetime.h>
+#include <qfileinfo.h>
+
+int main(int argc, char **argv)
+{
+ if ( argc != 2 && argc != 4 ) {
+ qWarning( "usage: %s [--text translation] potfile", argv[0] );
+ return -1;
+ }
+
+ QString translation = "xx";
+ QCString filename;
+
+ if( argc == 4 ) {
+ if( argv[1]!=QString("--text") ) {
+ qWarning( "usage: %s [--text translation] potfile", argv[0] );
+ return -1;
+ }
+ translation = QString::fromLocal8Bit(argv[2]);
+ filename = argv[3];
+ } else {
+ filename = argv[1];
+ }
+
+ MsgList translated;
+
+ try {
+ ifstream s(filename);
+ GettextLexer lexer(s);
+ GettextParser parser(lexer);
+ translated = parser.file();
+
+ } catch(exception& e) {
+ cerr << "exception: " << e.what() << endl;
+ return 1;
+ }
+
+ const bool is_desktop = filename.find( "desktop_") >= 0;
+
+ // The header is the last item (due too the sorting)
+ MsgList::const_iterator header = --translated.end();
+ if ( ( header == translated.end() ) || ( ! ( *header ).msgid.isEmpty() ) )
+ {
+ cerr << "Cannot find correct header msgid\n";
+ cout << "\"Content-Type: text/plain; charset=utf-8\\n\"\n";
+ cout << "\"Plural-Forms: nplurals=1; plural=0;\\n\"\n";
+ }
+ else
+ {
+ QStringList headerLines = QStringList::split( "\\n", ( *header ).msgstr, false );
+ QFileInfo fi( QString::fromLocal8Bit( filename ) );
+ QString projectId( "Project-Id-Version: " );
+ projectId += fi.baseName( false );
+ headerLines.gres( QRegExp( "^Project-Id-Version:.*" ), projectId );
+ headerLines.gres( QRegExp( "^Last-Translator:.*" ), "Last-Translator: transxx program <null@kde.org>" );
+ headerLines.gres( QRegExp( "^Language-Team:.*" ), "Language-Team: Test Language <kde-i18n-doc@kde.org>" );
+ QString revisionDate ( "PO-Revision-Date: " );
+ const QDateTime dt = QDateTime::currentDateTime( Qt::UTC );
+ revisionDate += dt.toString( "yyyy-MM-dd hh:mm+0000" );
+ headerLines.gres( QRegExp( "^PO-Revision-Date:.*" ), revisionDate );
+ headerLines << "Plural-Forms: nplurals=1; plural=0;";
+ outputMsg ( "msgid", "" );
+ outputMsg ( "msgstr", escapePO( headerLines.join("\\n") + "\\n" ) );
+ }
+ cout << "\n";
+
+ for (MsgList::ConstIterator it = translated.begin();
+ it != translated.end(); ++it)
+ {
+ QString msgid = ( *it ).msgid;
+ QString msgid_plural = ( *it ).msgid_plural;
+ if ( !msgid.isEmpty() ) {
+ outputMsg("msgid", escapePO( msgid) );
+
+ if ( ! msgid_plural.isEmpty() ) {
+ outputMsg("msgid_plural", escapePO( msgid_plural ) );
+ }
+
+ QString msgstr;
+
+ if ( msgid.find( "Definition of PluralForm" ) != -1 ) {
+ outputMsg("msgstr", "NoPlural");
+ cout << "\n";
+ continue;
+ }
+
+ if ( is_desktop ) {
+ msgstr = msgid.left( msgid.find( '=' ) + 1);
+ msgstr += translation + msgid.mid( msgid.find( '=' ) + 1) + translation;
+ outputMsg( "msgstr", escapePO(msgstr) );
+ cout << "\n";
+ continue;
+ }
+
+ if (msgid.startsWith("_n: ") || msgid.startsWith("_: ") ) { // KDE extentions
+ msgid = msgid.mid(msgid.find("\\n") + 2, msgid.length());
+ }
+
+ if (msgid.endsWith("%"))
+ msgstr = translation + msgid + " " + translation;
+ else
+ msgstr = translation + msgid + translation;
+
+ // Note: msgid has been modified, so we need to go back to the original version by the help of the iterator
+ // (Gettext is not aware of the KDE-specific handling, so it really wants a \n at start and at end in the msgstr if they were in the msgid )
+ if ( ( *it ).msgid.endsWith( "\\n" ) && ! ( *it ).msgid.endsWith( "\\\\n" ))
+ msgstr += "\n";
+ if ( ( *it ).msgid.startsWith( "\\n" ) )
+ msgstr.prepend( "\n" );
+
+ if ( msgid_plural.isEmpty() ) {
+ outputMsg("msgstr", escapePO( msgstr) );
+ }
+ else
+ {
+ outputMsg("msgstr[0]", escapePO( msgstr) );
+ }
+ cout << "\n";
+ }
+ }
+
+}
+
diff --git a/poxml/xml2pot.cpp b/poxml/xml2pot.cpp
new file mode 100644
index 00000000..593e75be
--- /dev/null
+++ b/poxml/xml2pot.cpp
@@ -0,0 +1,77 @@
+#include "parser.h"
+#include <stdlib.h>
+#include <iostream>
+#include <qfileinfo.h>
+#include <qdatetime.h>
+
+using namespace std;
+
+int main( int argc, char **argv )
+{
+ if (argc != 2) {
+ qWarning("usage: %s english-XML", argv[0]);
+ exit(1);
+ }
+
+ MsgList english = parseXML(argv[1]);
+
+ QMap<QString, int> msgids;
+ int index = 0;
+
+ for (MsgList::Iterator it = english.begin();
+ it != english.end(); )
+ {
+ if (msgids.contains((*it).msgid)) {
+ english[msgids[(*it).msgid]].lines += (*it).lines;
+ MsgList::Iterator tmp = it;
+ it++;
+ english.remove(tmp);
+ } else {
+ msgids.insert((*it).msgid, index);
+ index++;
+ it++;
+ }
+ }
+
+ const QDateTime now = QDateTime::currentDateTime( Qt::UTC );
+
+ cout << "# SOME DESCRIPTIVE TITLE.\n";
+ cout << "# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.\n";
+ cout << "#\n";
+ cout << "#, fuzzy\n";
+ cout << "msgid \"\"\n";
+ cout << "msgstr \"\"\n";
+ cout << "\"Project-Id-Version: PACKAGE VERSION\\n\"\n";
+ cout << "\"Report-Msgid-Bugs-To: http://bugs.kde.org\\n\"\n";
+ cout << "\"POT-Creation-Date: " << now.toString("yyyy-MM-dd hh:mm").utf8().data() << "+0000\\n\"\n";
+ cout << "\"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\\n\"\n";
+ cout << "\"Last-Translator: FULL NAME <EMAIL@ADDRESS>\\n\"\n";
+ cout << "\"Language-Team: LANGUAGE <kde-i18n-doc@kde.org>\\n\"\n";
+ cout << "\"MIME-Version: 1.0\\n\"\n";
+ cout << "\"Content-Type: application/x-xml2pot; charset=UTF-8\\n\"\n";
+ cout << "\"Content-Transfer-Encoding: 8bit\\n\"\n";
+ cout << "\n";
+
+ const QString fname = QFileInfo(argv[1]).fileName();
+
+ for (MsgList::ConstIterator it = english.begin();
+ it != english.end(); ++it)
+ {
+ cout << "#. Tag: " << (*it).tag.utf8() << endl;
+ cout << "#: ";
+ for (QValueList<BlockInfo>::ConstIterator it2 =
+ (*it).lines.begin(); it2 != (*it).lines.end(); it2++) {
+ if (it2 != (*it).lines.begin())
+ cout << " ";
+ cout << fname.utf8().data() << ":" << (*it2).start_line;
+
+ }
+ cout << "\n";
+ cout << "#, no-c-format\n";
+ outputMsg("msgid", StructureParser::descapeLiterals( (*it).msgid ));
+ outputMsg("msgstr", (*it).msgstr );
+ cout << "\n";
+ }
+
+ return 0;
+}
diff --git a/scheck/Makefile.am b/scheck/Makefile.am
new file mode 100644
index 00000000..3e05068a
--- /dev/null
+++ b/scheck/Makefile.am
@@ -0,0 +1,33 @@
+# This file is part of the KDE libraries
+# Copyright (C) 1997 Matthias Kalle Dalheimer (kalle@kde.org)
+# (C) 1997 Stephan Kulow (coolo@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 General Public License
+# along with this library; see the file COPYING. If not, write to
+# the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+# Boston, MA 02111-1307, USA.
+
+AM_CPPFLAGS = -DQT_PLUGIN
+
+INCLUDES = $(all_includes)
+noinst_HEADERS = scheck.h bitmaps.h
+kde_style_LTLIBRARIES = scheck.la
+scheck_la_LDFLAGS = $(all_libraries) $(KDE_PLUGIN) -module
+scheck_la_LIBADD = $(LIB_KDEUI)
+scheck_la_SOURCES = scheck.cpp
+scheck_la_METASOURCES = AUTO
+
+style_DATA = scheck.themerc
+styledir = $(kde_datadir)/kstyle/themes
+
+EXTRA_DIST = $(style_DATA)
diff --git a/scheck/README b/scheck/README
new file mode 100644
index 00000000..0f8f8293
--- /dev/null
+++ b/scheck/README
@@ -0,0 +1,22 @@
+Scheck - An interface style to highlight accel and style guide conflicts
+
+When starting an application with "KDE_LANG=xx application --style check"
+scheck will, for text parts it checks, strip the "xx"s and display the ones
+missing them (missing i18n() calls/.desktop entries) with violet background.
+
+To use it: "program -style check". Yes, there should be a verbose README.
+
+In short:
+
+- Orange shows accel conflicts.
+- Green proposed accels.
+- Dotted red lines show nested groupboxes (not prohibited, but not favored :-).
+- Potential style guide violations are marked with yellow, likely ones with red.
+- Missing colons are drawn with two small red squares.
+- Errors in window titles are marked with "foo|b|ar".
+- Violet background show untranslated string.
+
+Note: Not everything is checked (like list/combo box choices) and
+scheck is error-prone so read HIG[*] and think before you change anything. :-)
+
+*:http://developer.kde.org/documentation/standards/kde/style/basics/index.html
diff --git a/scheck/bitmaps.h b/scheck/bitmaps.h
new file mode 100644
index 00000000..43e96bd8
--- /dev/null
+++ b/scheck/bitmaps.h
@@ -0,0 +1,84 @@
+#ifndef __BITMAPS_H
+#define __BITMAPS_H
+
+/* Image bits processed by KPixmap2Bitmaps */
+static const unsigned char radiooff_light_bits[] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x08, 0x00, 0x10, 0x00, 0x10,
+ 0x00, 0x10, 0x00, 0x10, 0x00, 0x10, 0x00, 0x08, 0x00, 0x08, 0x0c, 0x06,
+ 0xf0, 0x01};
+
+static const unsigned char radiooff_gray_bits[] = {
+ 0xf0, 0x01, 0x0c, 0x06, 0x02, 0x00, 0x02, 0x00, 0x01, 0x00, 0x01, 0x00,
+ 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x02, 0x00, 0x02, 0x00, 0x00, 0x00,
+ 0x00, 0x00};
+
+static const unsigned char radiooff_dgray_bits[] = {
+ 0x00, 0x00, 0xf0, 0x01, 0x0c, 0x02, 0x04, 0x00, 0x02, 0x00, 0x02, 0x00,
+ 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00};
+
+static const unsigned char radiooff_center_bits[] = {
+ 0x00, 0x00, 0x00, 0x00, 0xf0, 0x01, 0xf8, 0x03, 0xfc, 0x07, 0xfc, 0x07,
+ 0xfc, 0x07, 0xfc, 0x07, 0xfc, 0x07, 0xf8, 0x03, 0xf0, 0x01, 0x00, 0x00,
+ 0x00, 0x00};
+
+static const unsigned char radiomask_bits[] = {
+ 0xf0, 0x01, 0xfc, 0x07, 0xfe, 0x0b, 0xfe, 0x0b, 0xff, 0x17, 0xff, 0x17,
+ 0xff, 0x17, 0xff, 0x17, 0xff, 0x17, 0xfe, 0x0b, 0xf2, 0x09, 0x0c, 0x06,
+ 0xf0, 0x01};
+
+// Checkbox "checked" bitmap
+static const unsigned char x_bits[] = {0x63, 0x77, 0x3e, 0x1c, 0x3e, 0x77, 0x63};
+
+// Arrow bitmaps
+static const QCOORD u_arrow[]={-1,-3, 0,-3, -2,-2, 1,-2, -3,-1, 2,-1, -4,0, 3,0, -4,1, 3,1};
+static const QCOORD d_arrow[]={-4,-2, 3,-2, -4,-1, 3,-1, -3,0, 2,0, -2,1, 1,1, -1,2, 0,2};
+static const QCOORD l_arrow[]={-3,-1, -3,0, -2,-2, -2,1, -1,-3, -1,2, 0,-4, 0,3, 1,-4, 1,3};
+static const QCOORD r_arrow[]={-2,-4, -2,3, -1,-4, -1,3, 0,-3, 0,2, 1,-2, 1,1, 2,-1, 2,0};
+
+namespace B3 {
+ const QCOORD u_arrow[]={ 0,-2, 0,-2, -1,-1, 1,-1, -2,0, 2,0, -3,1, 3,1 };
+ const QCOORD d_arrow[]={ -3,-2, 3,-2, -2,-1, 2,-1, -1,0, 1,0, 0,1, 0,1 };
+ const QCOORD l_arrow[]={ 1,-3, 1,-3, 0,-2, 1,-2, -1,-1, 1,-1, -2,0, 1,0, -1,1, 1,1, 0,2, 1,2, 1,3, 1,3 };
+ const QCOORD r_arrow[]={ -2,-3, -2,-3, -2,-2, -1,-2, -2,-1, 0,-1, -2,0, 1,0, -2,1, 0,1, -2,2, -1,2, -2,3, -2,3 };
+}
+
+#define QCOORDARRLEN(x) sizeof(x)/(sizeof(QCOORD)*2)
+
+
+// Fix Qt's wacky image positions
+static const char * const hc_minimize_xpm[] = {
+"12 12 2 1",
+"# c #000000",
+". c None",
+"............",
+"............",
+"............",
+"............",
+"............",
+"............",
+"............",
+"............",
+"...######...",
+"...######...",
+"............",
+"............"};
+
+static const char * const hc_close_xpm[] = {
+"12 12 2 1",
+"# c #000000",
+". c None",
+"............",
+"............",
+"............",
+"..##....##..",
+"...##..##...",
+"....####....",
+".....##.....",
+"....####....",
+"...##..##...",
+"..##....##..",
+"............",
+"............"};
+
+#endif
diff --git a/scheck/scheck.cpp b/scheck/scheck.cpp
new file mode 100644
index 00000000..8915205c
--- /dev/null
+++ b/scheck/scheck.cpp
@@ -0,0 +1,2762 @@
+/*
+ * $Id$
+ *
+ * KDE3 Style Guide compliance check "Style", v0.0.1
+ * Copyright (C) 2002 Maksim Orlovich <orlovich@cs.rochester.edu>
+ * (C) 2002 Ryan Cumming <ryan@completely.kicks-ass.org>
+ *
+ *
+ * Based on the KDE3 HighColor Style (version 1.0):
+ * Copyright (C) 2001-2002 Karol Szwed <gallium@kde.org>
+ * (C) 2001-2002 Fredrik Höglund <fredrik@kde.org>
+ *
+ * Drawing routines adapted from the KDE2 HCStyle,
+ * Copyright (C) 2000 Daniel M. Duley <mosfet@kde.org>
+ * (C) 2000 Dirk Mueller <mueller@kde.org>
+ * (C) 2001 Martijn Klingens <klingens@kde.org>
+ *
+ * Portions of code are from the Qt GUI Toolkit, Copyright (C) 1992-2003 Trolltech AS.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the 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; see the file COPYING. If not, write to
+ * the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ *
+ */
+
+#include <stdlib.h>
+
+#include <qdict.h>
+#include <qdrawutil.h>
+#include <qpainter.h>
+#include <qpointarray.h>
+#include <qstyleplugin.h>
+#include <qcheckbox.h>
+#include <qcombobox.h>
+#include <qfontmetrics.h>
+#include <qgroupbox.h>
+#include <qheader.h>
+#include <qlabel.h>
+#include <qmenubar.h>
+#include <qobjectlist.h>
+#include <qpushbutton.h>
+#include <qradiobutton.h>
+#include <qregexp.h>
+#include <qscrollbar.h>
+#include <qslider.h>
+#include <qstylesheet.h>
+#include <qtabbar.h>
+#include <qtimer.h>
+#include <qtoolbutton.h>
+#include <qtoolbar.h>
+#include <qpopupmenu.h>
+#include <qwidgetlist.h>
+
+#include <kdrawutil.h>
+#include <kaccelmanager.h>
+#include <kpixmapeffect.h>
+#include <kapplication.h>
+#include <kaboutdata.h>
+
+#include "scheck.h"
+#include "scheck.moc"
+#include "bitmaps.h"
+
+// -- Style Plugin Interface -------------------------
+class StyleCheckStylePlugin : public QStylePlugin
+{
+ public:
+ StyleCheckStylePlugin() {}
+ ~StyleCheckStylePlugin() {}
+
+ QStringList keys() const
+ {
+ return QStringList() << "Check";
+ }
+
+ QStyle* create( const QString& key )
+ {
+ if ( key == "check" )
+ return new StyleCheckStyle( );
+
+
+ return 0;
+ }
+};
+
+KDE_Q_EXPORT_PLUGIN( StyleCheckStylePlugin )
+// ---------------------------------------------------
+
+
+// ### Remove globals
+static QBitmap lightBmp;
+static QBitmap grayBmp;
+static QBitmap dgrayBmp;
+static QBitmap centerBmp;
+static QBitmap maskBmp;
+static QBitmap xBmp;
+
+static const int itemFrame = 1;
+static const int itemHMargin = 3;
+static const int itemVMargin = 0;
+static const int arrowHMargin = 6;
+static const int rightBorder = 12;
+
+// ---------------------------------------------------------------------------
+
+#include <qvaluevector.h>
+
+enum ColonMode
+{
+ ColonlessWidget = 0,
+ BuddiedWidget = 1,
+ BuddylessWidget = 2
+};
+
+enum AccelMode
+{
+ NoAccels = 0,
+ HasAccels = 1
+};
+
+enum TitleType
+{
+ ShortTitle = 0,
+ LongTitle = 1
+};
+
+namespace
+{
+
+ class StyleGuideViolation
+ {
+ private:
+ int m_position;
+ int m_severity; // 0 = error 1 = warning
+ public:
+ enum Severity
+ {
+ Error = 0,
+ Warning = 1,
+ AccelConflict = 2,
+ AccelSuggestion = 3,
+ Untranslated = 4
+ };
+
+ StyleGuideViolation() {}
+ StyleGuideViolation(int _position, int _severity = Error): m_position(_position), m_severity(_severity)
+ {}
+
+ operator int() const
+ {
+ return m_position;
+ }
+
+ int position() const
+ {
+ return m_position;
+ }
+
+ int severity() const
+ {
+ return m_severity;
+ }
+ };
+
+ class LowerCaseWords
+ {
+ private:
+ static QDict<bool>* m_words;
+ public:
+ static QDict<bool>* words()
+ {
+ if (!m_words)
+ {
+ m_words = new QDict<bool>;
+ // Prepositions under five letters, except from & under
+ m_words->insert( "for", (bool*)1);
+ m_words->insert( "in", (bool*)1);
+ m_words->insert( "with", (bool*)1);
+ m_words->insert( "to", (bool*)1);
+ m_words->insert( "of", (bool*)1);
+ m_words->insert( "on", (bool*)1);
+ m_words->insert( "at", (bool*)1);
+ m_words->insert( "by", (bool*)1);
+ m_words->insert( "into", (bool*)1);
+ m_words->insert( "per", (bool*)1);
+ m_words->insert( "vs", (bool*)1);
+
+ // Conjunctions
+ m_words->insert( "and", (bool*)1);
+ m_words->insert( "or", (bool*)1);
+ m_words->insert( "nor", (bool*)1);
+ m_words->insert( "but", (bool*)1);
+ m_words->insert( "if", (bool*)1);
+
+ // Articles
+ m_words->insert( "the", (bool*)1);
+ m_words->insert( "a", (bool*)1);
+ m_words->insert( "as", (bool*)1);
+ m_words->insert( "an", (bool*)1);
+
+ // Misc
+ m_words->insert( "http", (bool*)1);
+ }
+ return m_words;
+ }
+ };
+
+ QDict<bool>* LowerCaseWords::m_words = 0;
+
+ class ExplicitCaseWords
+ {
+ private:
+ static QDict<const char>* m_words;
+ public:
+ static QDict<const char>* words()
+ {
+ if (!m_words)
+ {
+ // Store the words like this:
+ // "lowercase", "CorrectCase"
+ m_words = new QDict<const char>(61);
+ // week day names
+ m_words->insert( "monday", "Monday");
+ m_words->insert( "tuesday", "Tuesday");
+ m_words->insert( "wednesday", "Wednesday");
+ m_words->insert( "thursday", "Thursday");
+ m_words->insert( "friday", "Friday");
+ m_words->insert( "saturday", "Saturday");
+ m_words->insert( "sunday", "Sunday");
+
+ // month names
+ m_words->insert( "january", "January");
+ m_words->insert( "february", "February");
+ m_words->insert( "march", "March");
+ m_words->insert( "april", "April");
+ m_words->insert( "may", "May");
+ m_words->insert( "june", "June");
+ m_words->insert( "july", "July");
+ m_words->insert( "august", "August");
+ m_words->insert( "september", "September");
+ m_words->insert( "october", "October");
+ m_words->insert( "november", "November");
+ m_words->insert( "december", "December");
+
+ // displayed KDE names not matched by acronym algorithm
+ m_words->insert( "konqueror", "Konqueror");
+ m_words->insert( "kicker", "Kicker");
+ m_words->insert( "kopete", "Kopete");
+ m_words->insert( "kate", "Kate");
+ m_words->insert( "konsole", "Konsole");
+ m_words->insert( "kontour", "Kontour");
+ m_words->insert( "kiten", "Kiten");
+ m_words->insert( "kooka", "Kooka");
+ m_words->insert( "noatun", "Noatun");
+
+ // computer
+ m_words->insert( "ctrl", "Ctrl");
+ m_words->insert( "java", "Java");
+ m_words->insert( "javascript", "JavaScript");
+ m_words->insert( "qt", "Qt");
+ m_words->insert( "doxygen", "Doxygen");
+ m_words->insert( "linux", "Linux");
+ m_words->insert( "unix", "UNIX");
+ m_words->insert( "internet", "Internet");
+ m_words->insert( "web", "Web");
+ m_words->insert( "motif", "Motif");
+ m_words->insert( "x11", "X11");
+ m_words->insert( "socks", "SOCKS");
+ m_words->insert( "xing", "Xing");
+ m_words->insert( "yamaha", "Yamaha");
+ m_words->insert( "hz", "Hz");
+ m_words->insert( "khz", "KHz");
+ m_words->insert( "mhz", "MHz");
+ m_words->insert( "macos", "MacOS");
+ m_words->insert( "microsoft", "Microsoft");
+ m_words->insert( "adobe", "Adobe");
+ m_words->insert( "postscript", "PostScript");
+ m_words->insert( "ghostscript", "Ghostscript");
+ m_words->insert( "vcard", "vCard");
+ m_words->insert( "midi", "MIDI");
+ m_words->insert( "isdn", "ISDN");
+ m_words->insert( "cd-rom", "CD-ROM");
+ }
+ return m_words;
+ }
+ };
+
+ QDict<const char>* ExplicitCaseWords::m_words = 0;
+}
+
+static bool xxMode;
+
+static QColor severityColor(int severity)
+{
+ if (severity == StyleGuideViolation::Error)
+ {
+ return Qt::red;
+ }
+ else if (severity == StyleGuideViolation::AccelConflict)
+ {
+ return QColor(255, 128, 0);
+ }
+ else if (severity == StyleGuideViolation::AccelSuggestion)
+ {
+ return Qt::green;
+ }
+ else if (severity == StyleGuideViolation::Untranslated)
+ {
+ return QColor(255, 0, 255);
+ }
+ else
+ {
+ return Qt::yellow;
+ }
+}
+
+// Removes '&' style accelerators from text strings
+static void removeAccelerators(QString &str)
+{
+ for (unsigned int p = 0; p < str.length(); p++)
+ {
+ if (str[p] == '&')
+ {
+ str = str.mid(0, p) + str.mid(p+1);
+ // Skip the next letter, as && mean a literal "&"
+ p++;
+ }
+ }
+}
+
+
+static void removeXX(QString &str)
+{
+ str.replace("xx",""); // simple but atm best working
+}
+
+static QString removedXX(QString str)
+{
+ if (xxMode)
+ removeXX(str);
+ return str;
+}
+
+static QString stripAccelViolations(QString str)
+{
+ int conflict_pos = str.find("(&&)");
+ if (conflict_pos >= 0)
+ {
+ str = str.mid(0, conflict_pos) + str.mid(conflict_pos+4);
+ }
+
+ int suggestion_pos = str.find("(!)");
+ if (suggestion_pos >= 0)
+ {
+ str = str.mid(0, suggestion_pos) + str.mid(suggestion_pos+3);
+ }
+
+ return str;
+}
+
+// Must be passed a string with its accelerators removed
+QString findAccelViolations(QString str, QValueVector<StyleGuideViolation> &violations)
+{
+ int conflict_pos = str.find("(&)");
+
+ if (conflict_pos >= 0)
+ str = str.mid(0, conflict_pos) + str.mid(conflict_pos+3);
+
+ int suggestion_pos = str.find("(!)");
+ if (suggestion_pos >= 0)
+ {
+ str = str.mid(0, suggestion_pos) + str.mid(suggestion_pos+3);
+ violations.push_back(StyleGuideViolation(suggestion_pos, StyleGuideViolation::AccelSuggestion));
+
+ // Conditionally "relocate" the conflict
+ if (conflict_pos >= suggestion_pos)
+ {
+ conflict_pos -= 3;
+ }
+ }
+
+ if (conflict_pos >= 0)
+ violations.push_back(StyleGuideViolation(conflict_pos, StyleGuideViolation::AccelConflict));
+
+ return str;
+}
+
+QString findUntranslatedViolations(QString str, QValueVector<StyleGuideViolation> &violations)
+{
+ if (str.find("xx")!=-1)
+ removeXX(str);
+ else {
+ for (unsigned int c=0; c<str.length(); c++)
+ violations.push_back(StyleGuideViolation(c, StyleGuideViolation::Untranslated));
+ }
+
+ return str;
+}
+
+static QValueVector<StyleGuideViolation> checkSentenceStyle(QString str, ColonMode mode = ColonlessWidget, AccelMode accelMode = HasAccels)
+{
+ QValueVector<StyleGuideViolation> violations;
+ bool afterWhiteSpace = true;
+ bool firstChar = true;
+ bool inQuote = false;
+
+ if (xxMode)
+ str = findUntranslatedViolations(str, violations);
+
+ if (accelMode == HasAccels)
+ {
+ // We care not for accelerators while parsing for capitialization
+ removeAccelerators(str);
+ str = findAccelViolations(str, violations);
+ }
+
+ for (unsigned int c=0; c<str.length(); c++)
+ {
+ // Don't parse within quotes
+ if (inQuote)
+ {
+ if (str[c] == '\"')
+ {
+ // The quote is over, return to normal operation
+ inQuote = false;
+ afterWhiteSpace = false;
+ continue;
+ }
+ }
+ else if (str[c].isSpace())
+ {
+ if (afterWhiteSpace)
+ {
+ // Discourage multiple spaces
+ violations.push_back(c);
+ }
+
+ afterWhiteSpace = true;
+ }
+ else if (str[c] == '\"')
+ {
+ // Beginning of a quote
+ // This disables parsing until the next quotation mark is found
+ inQuote = true;
+ afterWhiteSpace = false;
+ firstChar = false;
+ }
+ else if ((str[c] == '.') || (str[c] == ':') || (str[c] == ';') || (str[c] == '?') || (str[c] == '!') || (str[c] == ','))
+ {
+ // Is this a new sentence?
+ if ((str[c] == '.') || (str[c] == '?') || (str[c] == '!'))
+ {
+ // Periods not followed by whitespace are probably
+ // separators in IP addresses or URLs, and they don't
+ // need any more false positives than they already
+ // have ;)
+ if (((c + 1) < str.length()) && (str[c + 1].isSpace()))
+ {
+ // We're a new sentence
+ firstChar = true;
+ }
+ }
+
+ if (afterWhiteSpace && c)
+ {
+ // Tsk tsk, we shouldn't have punctuation after whitespace
+ violations.push_back(c - 1);
+ }
+
+ afterWhiteSpace = false;
+ }
+ else
+ {
+ if (afterWhiteSpace) //We don't check for fOO and things like that, just first letters..
+ {
+ // Try to extract the whole word..
+ QString word = QString::null;
+ for (unsigned int l = c+1; l<str.length(); l++)
+ {
+ if (!str[l].isLetter() && !str[l].isNumber() && str[l] != '&' && str[l] != '-')
+ {
+ word = str.mid(c, l - c);
+ break;
+ }
+ }
+
+ if (word.isNull()) //Looks like goes to end of string..
+ {
+ word = str.mid ( c );
+ }
+
+ // Check if it's in the explicit case word list
+ const char *correctWord = ExplicitCaseWords::words()->find(word.lower());
+
+ // Actual captialization checking
+ if (correctWord)
+ {
+ // We have been told explictly how to capitalize this word
+ // This overides the next checks
+ for (unsigned int x = 0;x < word.length();x++)
+ {
+ if (word[x] != correctWord[x])
+ {
+ violations.push_back(c + x);
+ }
+ }
+ }
+ else if (str[c].category() == QChar::Letter_Lowercase) //Lowercase character..
+ {
+ if (firstChar)
+ violations.push_back(c);
+ }
+ else if (str[c].category() == QChar::Letter_Uppercase)
+ {
+ if (!firstChar) //A possible violation -- can be a proper name..
+ {
+ //Check whether more capitalized words in here.. To guess acronyms.
+ bool acronym = false;
+ for (unsigned int d = c+1; d < str.length(); d++)
+ {
+ if (str[d].isSpace() )
+ break;
+ if (str[d].category() == QChar::Letter_Uppercase)
+ {
+ acronym = true;
+ break;
+ }
+ }
+ if (!acronym)
+ violations.push_back(c);
+ }
+ }
+ }
+ firstChar = false;
+ afterWhiteSpace = false;
+ }
+ }
+
+ bool endWithColon = false;
+ int colonIndex = -1;
+
+ for (int c = str.length() - 1; c>=0; c--)
+ {
+ if (str[c] == ':')
+ {
+ endWithColon = true;
+ colonIndex = c;
+ break;
+ }
+ if (!str[c].isSpace())
+ break;
+ }
+
+ if ( mode == ColonlessWidget && endWithColon) //Sometimes checkbox is also a label.. So we'll make a colon a warning
+ {
+ violations.push_back(StyleGuideViolation(colonIndex,StyleGuideViolation::Warning));
+ }
+
+ if (mode == BuddiedWidget && !endWithColon) //We have a buddy but lack a colon --> wrong
+ {
+ violations.push_back(-1);
+ }
+
+ if (mode == BuddylessWidget && endWithColon) //We have no buddy but we do have a colon -- potential error
+ {
+ violations.push_back(StyleGuideViolation(colonIndex,StyleGuideViolation::Warning));
+ }
+
+ return violations;
+}
+
+static QValueVector<StyleGuideViolation> checkTitleStyle(QString str, TitleType titleType = ShortTitle, AccelMode accelMode = NoAccels)
+{
+ QValueVector<StyleGuideViolation> violations;
+ bool afterWhiteSpace = true;
+
+ if (xxMode)
+ str = findUntranslatedViolations(str, violations);
+
+ if (accelMode == HasAccels)
+ {
+ // We care not for accelerators while parsing for capitialization
+ removeAccelerators(str);
+ str = findAccelViolations(str, violations);
+ }
+
+ for (unsigned int c=0; c<str.length(); c++)
+ {
+ if (str[c].isSpace())
+ {
+ if (afterWhiteSpace)
+ {
+ // Discourage multiple spaces
+ violations.push_back(c);
+ }
+
+ afterWhiteSpace = true;
+ }
+ else if ((str[c] == '.') || (str[c] == ';') || (str[c] == '?') || (str[c] == '!'))
+ {
+ // '!' Is used for marking conficting accels
+ if ((accelMode = HasAccels) && (str[c] == '!'))
+ {
+ afterWhiteSpace = false;
+ continue;
+ }
+
+ // Periods/colons not followed by whitespace are probably
+ // separators in IP addresses or URLs, and they don't
+ // need any more false positives than they already
+ // have ;)
+
+ // Check for multiple sentences
+ if (((c + 1) < str.length()) && (str[c + 1].isSpace()))
+ {
+ violations.push_back(c);
+ continue;
+ }
+
+ // Check for sentence punctuation at the end of a string,
+ // being sure not to tag ellipses
+ if ((c == str.length() - 1) && (str.right(3) != "..."))
+ violations.push_back(c);
+ }
+ else
+ {
+ if (c==str.length()-1 && str[c] == ':')
+ {
+ violations.push_back(c);
+ continue;
+ }
+ if (afterWhiteSpace) //We don't check for fOO and things like that, just first letters..
+ {
+ bool lastWord = false;
+
+ //Now, try to extract the whole word..
+ QString word = QString::null;
+ for (unsigned int l = c+1; l<str.length(); l++)
+ {
+ if (!str[l].isLetter() && !str[l].isNumber() && str[l] != '&' && str[l] != '-')
+ {
+ word = str.mid(c, l - c);
+ if (str.mid(l)=="...")
+ lastWord=true;
+ break;
+ }
+ }
+
+ if (word.isNull()) //Looks like goes to end of string..
+ {
+ word = str.mid ( c );
+ lastWord = true;
+ }
+
+ QString lower_word = word.lower();
+
+ // Check if it's in the explicit case word list
+ const char *correctWord = ExplicitCaseWords::words()->find(lower_word);
+
+ if ((titleType == ShortTitle) && (lower_word=="and" || lower_word=="a" || lower_word=="an" || lower_word=="the"))
+ {
+ // This words are 'red flagged' for short titles
+ for (unsigned int i = 0;i < word.length();i++)
+ violations.push_back(StyleGuideViolation(c + i,StyleGuideViolation::Warning));
+ }
+
+ if (correctWord)
+ {
+ // We're an uppercase word, and may have an unusual
+ // capitalization (ie, JavaScript)
+ for (unsigned int x = 0;x < word.length();x++)
+ {
+ if (word[x] != correctWord[x])
+ violations.push_back(c + x);
+ }
+ }
+ else if (c && !lastWord && LowerCaseWords::words()->find(word.lower()))
+ {
+ // We're a lowercase word
+ if (str[c].category() == QChar::Letter_Uppercase)
+ violations.push_back(c);
+ }
+ else
+ {
+ if (str[c].category() == QChar::Letter_Lowercase)
+ violations.push_back(c);
+ }
+ }
+
+ afterWhiteSpace = false;
+ }
+ }
+
+ return violations;
+}
+
+
+static void renderViolations(const QValueVector<StyleGuideViolation>& violations, QPainter* p, QRect r, int flags, QString text)
+{
+
+ if (xxMode)
+ removeXX(text);
+
+ if (violations.size()>0)
+ {
+ p->save();
+ QFontMetrics qfm = p->fontMetrics ();
+
+ QString parStr = text;
+ int len = text.length();
+
+ /*****
+ Begin code snipped from QPainter, somewhat modified
+ */
+
+
+ // str.setLength() always does a deep copy, so the replacement code below is safe.
+ parStr.setLength( len );
+ // compatible behaviour to the old implementation. Replace tabs by spaces
+ QChar *chr = (QChar*)parStr.unicode();
+ int l = len;
+ while ( l-- )
+ {
+ if ( *chr == '\t' || *chr == '\r' || *chr == '\n' )
+ *chr = ' ';
+ chr++;
+ }
+
+
+ if ( flags & Qt::ShowPrefix )
+ {
+ parStr = removedXX(stripAccelViolations(parStr));
+ removeAccelerators(parStr);
+ }
+
+ int w = qfm.width( parStr );
+ int h = qfm.height();
+
+ int xoff = r.x();
+ int yoff = r.y() + qfm.ascent();
+
+ if ( flags & Qt::AlignBottom )
+ yoff += r.height() - h;
+ else if ( flags & Qt::AlignVCenter )
+ yoff += ( r.height() - h ) / 2;
+ if ( flags & Qt::AlignRight )
+ xoff += r.width() - w;
+ else if ( flags & Qt::AlignHCenter )
+ xoff += ( r.width() - w ) / 2;
+
+
+
+ /*****
+ end code snipped from QPainter...
+ */
+
+ int yt = yoff - h;
+ int yb = yoff;;
+
+
+ QRect bnd(xoff, yoff - h, w, h);
+
+ for (unsigned int v = 0; v < violations.size(); v++)
+ {
+ if (violations[v] != -1)
+ {
+ int left = bnd.left() +
+ qfm.width(parStr, violations[v]) - 1;
+
+
+ int right = bnd.left() +
+ qfm.width(parStr, violations[v] + 1) - 1;
+
+
+ //int right = r.x() + qfm.width(text, violations[v]+1);
+ //int left = r.x() + qfm.width(text, violations[v]);
+
+ p->fillRect( left, yt, right - left + 1, yb - yt + 1, severityColor(violations[v].severity()) );
+ }
+ else
+ {
+ int right = bnd.right();
+
+ int centerX = right - 1;
+ int leftX = centerX-h/4;
+ int rightX = centerX + h/4;
+ p->setPen(severityColor(violations[v].severity()));
+ p->drawLine ( leftX, yt + 1, rightX, yt + 1 );
+ p->drawLine ( leftX, yt + h/2, rightX, yt + h/2 + 1);
+ p->drawLine ( leftX, yt+ 1, leftX, yt + h/2 + 1);
+ p->drawLine ( rightX, yt+ 1, rightX, yt + h/2 + 1);
+
+ p->drawLine ( leftX, yb - h/2, rightX, yb - h/2);
+ p->drawLine ( leftX, yb, rightX, yb);
+ p->drawLine ( leftX, yb - h/2, leftX, yb);
+ p->drawLine ( rightX, yb - h/2, rightX, yb);
+ }
+ }
+ p->restore();
+ }
+}
+
+StyleCheckTitleWatcher::StyleCheckTitleWatcher()
+{
+ QTimer* checkTimer = new QTimer(this);
+ connect( checkTimer, SIGNAL(timeout()), this, SLOT(slotCheck()) );
+ checkTimer->start(1000);
+}
+
+
+void StyleCheckTitleWatcher::addWatched(QWidget* w)
+{
+ watched.push_back(w);
+ watchedTitles.push_back(w->caption());
+}
+
+QString StyleCheckTitleWatcher::cleanErrorMarkers(QString in)
+{
+ //We add # to denote an error...So now remove it.. It helps us check whether it's the same caption as before..
+ QString out = "";
+ for (unsigned int c = 0; c < in.length(); c++)
+ {
+ if (in[c] != '|')
+ out += in[c];
+ }
+
+ return out;
+}
+
+void StyleCheckTitleWatcher::slotCheck()
+{
+ for (unsigned int c=0; c<watched.size(); c++)
+ {
+ if (!watched[c].isNull() )
+ {
+
+ QString cleaned = cleanErrorMarkers(watched[c]->caption());
+ if (cleaned != watchedTitles[c])
+ {
+ watchedTitles[c] = watched[c]->caption();
+ QValueVector<StyleGuideViolation> violations = checkTitleStyle(watched[c]->caption(), LongTitle, NoAccels);
+ if (violations.size() == 0)
+ continue;
+
+ QString out = "";
+ QString in = watched[c]->caption();
+ int prev = -1;
+ for (unsigned int v = 0; v < violations.size(); v++)
+ {
+ out += in.mid(prev + 1, violations[v] - prev - 1); //Add interval that followed last one..
+ out += '|';
+ out += in[violations[v]];
+ out += '|';
+ prev = violations[v];
+ }
+
+ out += in.mid(prev + 1); //Add the tail..
+
+ watched[c]->setCaption(out);
+ } //If changed.
+ } //If not null..
+ } //for all watched
+}
+
+
+StyleCheckStyle::StyleCheckStyle( )
+ : KStyle( 0 , ThreeButtonScrollBar )
+{
+ hoverWidget = 0L;
+ topLevelAccelManageTimer = new QTimer(this);
+ connect(topLevelAccelManageTimer, SIGNAL(timeout()), this, SLOT(slotAccelManage()));
+ watcher = new StyleCheckTitleWatcher;
+ xxMode = (QString(getenv("KDE_LANG"))=="xx");
+}
+
+
+StyleCheckStyle::~StyleCheckStyle()
+{
+ delete watcher;
+}
+
+//We walk down the widget tree until we find something we render, and sic KAccelManager in programmer's mode on those
+void StyleCheckStyle::accelManageRecursive(QWidget* widget)
+{
+ if (&widget->style() == this)
+ {
+ KAcceleratorManager::manage(widget, true);
+ return;
+ }
+
+ const QObjectList* children = widget->children();
+ if (!children)
+ return;
+ QObjectListIterator iter(*children);
+
+ QObject* walk;
+ while ((walk = iter.current()))
+ {
+ if (walk->isWidgetType())
+ accelManageRecursive(static_cast<QWidget*>(walk));
+ ++iter;
+ }
+}
+
+
+void StyleCheckStyle::slotAccelManage()
+{
+ //Walk through top-levels
+ QWidgetList* topLevels = QApplication::topLevelWidgets();
+ if (!topLevels)
+ return;
+
+ QWidgetListIt iter(*topLevels);
+
+ QWidget* walk;
+ while ((walk = iter.current()))
+ {
+ accelManageRecursive(walk);
+ ++iter;
+ }
+
+}
+
+
+void StyleCheckStyle::polish(QWidget* widget)
+{
+ /* Having a global view on the widget makes accel
+ easier to catch. However, just intruding on the main window
+ is wrong since a style can be used for a subwindow. The upshot is that we defer
+ accel management to a timer, until things stabilize, and then walk from top-levels down
+ */
+ topLevelAccelManageTimer->start(200, true);
+ //
+
+ // Put in order of highest occurance to maximise hit rate
+ if (widget->inherits("QPushButton")) {
+ widget->installEventFilter(this);
+ }
+
+ if (widget->inherits("QLabel"))
+ {
+ widget->installEventFilter(this);
+ }
+
+ if (widget->inherits("QGroupBox"))
+ {
+ widget->installEventFilter(this);
+ }
+
+ if (widget->inherits("QMainWindow") || widget->inherits("QDialog" ) )
+ {
+ watcher->addWatched(widget);
+ }
+
+ KStyle::polish( widget );
+}
+
+
+void StyleCheckStyle::unPolish(QWidget* widget)
+{
+ if (widget->inherits("QPushButton")) {
+ widget->removeEventFilter(this);
+ }
+
+ if (widget->inherits("QLabel"))
+ {
+ widget->removeEventFilter(this);
+ }
+
+ if (widget->inherits("QGroupBox"))
+ {
+ widget->removeEventFilter(this);
+ }
+
+
+
+ KStyle::unPolish( widget );
+}
+
+
+
+// This function draws primitive elements as well as their masks.
+void StyleCheckStyle::drawPrimitive( PrimitiveElement pe,
+ QPainter *p,
+ const QRect &r,
+ const QColorGroup &cg,
+ SFlags flags,
+ const QStyleOption& opt ) const
+{
+ bool down = flags & Style_Down;
+ bool on = flags & Style_On;
+
+ switch(pe)
+ {
+ // BUTTONS
+ // -------------------------------------------------------------------
+ case PE_ButtonDefault: {
+ int x1, y1, x2, y2;
+ r.coords( &x1, &y1, &x2, &y2 );
+
+ // Button default indicator
+ p->setPen( cg.shadow() );
+ p->drawLine( x1+1, y1, x2-1, y1 );
+ p->drawLine( x1, y1+1, x1, y2-1 );
+ p->drawLine( x1+1, y2, x2-1, y2 );
+ p->drawLine( x2, y1+1, x2, y2-1 );
+ break;
+ }
+
+ case PE_ButtonDropDown:
+ case PE_ButtonTool: {
+ bool sunken = on || down;
+ int x,y,w,h;
+ r.rect(&x, &y, &w, &h);
+ int x2 = x+w-1;
+ int y2 = y+h-1;
+ QPen oldPen = p->pen();
+
+ // Outer frame (round style)
+ p->setPen(cg.shadow());
+ p->drawLine(x+1,y,x2-1,y);
+ p->drawLine(x,y+1,x,y2-1);
+ p->drawLine(x+1,y2,x2-1,y2);
+ p->drawLine(x2,y+1,x2,y2-1);
+
+ // Bevel
+ p->setPen(sunken ? cg.mid() : cg.light());
+ p->drawLine(x+1, y+1, x2-1, y+1);
+ p->drawLine(x+1, y+1, x+1, y2-1);
+ p->setPen(sunken ? cg.light() : cg.mid());
+ p->drawLine(x+2, y2-1, x2-1, y2-1);
+ p->drawLine(x2-1, y+2, x2-1, y2-1);
+
+ p->fillRect(x+2, y+2, w-4, h-4, cg.button());
+
+ p->setPen( oldPen );
+ break;
+ }
+
+ // PUSH BUTTON
+ // -------------------------------------------------------------------
+ case PE_ButtonCommand: {
+ bool sunken = on || down;
+ int x, y, w, h;
+ r.rect(&x, &y, &w, &h);
+
+ if ( sunken )
+ kDrawBeButton( p, x, y, w, h, cg, true,
+ &cg.brush(QColorGroup::Mid) );
+
+ else if ( flags & Style_MouseOver ) {
+ QBrush brush(cg.button().light(110));
+ kDrawBeButton( p, x, y, w, h, cg, false, &brush );
+ }
+
+ // "Flat" button
+ else if (!(flags & (Style_Raised | Style_Sunken)))
+ p->fillRect(r, cg.button());
+
+ else
+ kDrawBeButton(p, x, y, w, h, cg, false,
+ &cg.brush(QColorGroup::Button));
+ break;
+ }
+
+
+ // BEVELS
+ // -------------------------------------------------------------------
+ case PE_ButtonBevel: {
+ int x,y,w,h;
+ r.rect(&x, &y, &w, &h);
+ bool sunken = on || down;
+ int x2 = x+w-1;
+ int y2 = y+h-1;
+
+ // Outer frame
+ p->setPen(cg.shadow());
+ p->drawRect(r);
+
+ // Bevel
+ p->setPen(sunken ? cg.mid() : cg.light());
+ p->drawLine(x+1, y+1, x2-1, y+1);
+ p->drawLine(x+1, y+1, x+1, y2-1);
+ p->setPen(sunken ? cg.light() : cg.mid());
+ p->drawLine(x+2, y2-1, x2-1, y2-1);
+ p->drawLine(x2-1, y+2, x2-1, y2-1);
+
+ if (w > 4 && h > 4) {
+ if (sunken)
+ p->fillRect(x+2, y+2, w-4, h-4, cg.button());
+ else
+ renderGradient( p, QRect(x+2, y+2, w-4, h-4),
+ cg.button(), flags & Style_Horizontal );
+ }
+ break;
+ }
+
+
+ // FOCUS RECT
+ // -------------------------------------------------------------------
+ case PE_FocusRect: {
+ p->drawWinFocusRect( r );
+ break;
+ }
+
+
+ // HEADER SECTION
+ // -------------------------------------------------------------------
+ case PE_HeaderSection: {
+ // Temporary solution for the proper orientation of gradients.
+ bool horizontal = true;
+ if (p && p->device()->devType() == QInternal::Widget) {
+ QHeader* hdr = dynamic_cast<QHeader*>(p->device());
+ if (hdr)
+ horizontal = hdr->orientation() == Horizontal;
+ }
+
+ int x,y,w,h;
+ r.rect(&x, &y, &w, &h);
+ bool sunken = on || down;
+ int x2 = x+w-1;
+ int y2 = y+h-1;
+ QPen oldPen = p->pen();
+
+ // Bevel
+ p->setPen(sunken ? cg.mid() : cg.light());
+ p->drawLine(x, y, x2-1, y);
+ p->drawLine(x, y, x, y2-1);
+ p->setPen(sunken ? cg.light() : cg.mid());
+ p->drawLine(x+1, y2-1, x2-1, y2-1);
+ p->drawLine(x2-1, y+1, x2-1, y2-1);
+ p->setPen(cg.shadow());
+ p->drawLine(x, y2, x2, y2);
+ p->drawLine(x2, y, x2, y2);
+
+ if (sunken)
+ p->fillRect(x+1, y+1, w-3, h-3, cg.button());
+ else
+ renderGradient( p, QRect(x+1, y+1, w-3, h-3),
+ cg.button(), !horizontal );
+ p->setPen( oldPen );
+ break;
+ }
+
+
+ // SCROLLBAR
+ // -------------------------------------------------------------------
+ case PE_ScrollBarSlider: {
+ // Small hack to ensure scrollbar gradients are drawn the right way.
+ flags ^= Style_Horizontal;
+
+ drawPrimitive(PE_ButtonBevel, p, r, cg, flags | Style_Enabled | Style_Raised);
+
+ // Draw a scrollbar riffle (note direction after above changes)
+ // HighColor & Default scrollbar
+ if (flags & Style_Horizontal) {
+ if (r.height() >= 15) {
+ int x = r.x()+3;
+ int y = r.y() + (r.height()-7)/2;
+ int x2 = r.right()-3;
+ p->setPen(cg.light());
+ p->drawLine(x, y, x2, y);
+ p->drawLine(x, y+3, x2, y+3);
+ p->drawLine(x, y+6, x2, y+6);
+
+ p->setPen(cg.mid());
+ p->drawLine(x, y+1, x2, y+1);
+ p->drawLine(x, y+4, x2, y+4);
+ p->drawLine(x, y+7, x2, y+7);
+ }
+ } else {
+ if (r.width() >= 15) {
+ int y = r.y()+3;
+ int x = r.x() + (r.width()-7)/2;
+ int y2 = r.bottom()-3;
+ p->setPen(cg.light());
+ p->drawLine(x, y, x, y2);
+ p->drawLine(x+3, y, x+3, y2);
+ p->drawLine(x+6, y, x+6, y2);
+
+ p->setPen(cg.mid());
+ p->drawLine(x+1, y, x+1, y2);
+ p->drawLine(x+4, y, x+4, y2);
+ p->drawLine(x+7, y, x+7, y2);
+ }
+ }
+ break;
+ }
+
+
+ case PE_ScrollBarAddPage:
+ case PE_ScrollBarSubPage: {
+ int x, y, w, h;
+ r.rect(&x, &y, &w, &h);
+ int x2 = x+w-1;
+ int y2 = y+h-1;
+
+ p->setPen(cg.shadow());
+
+ if (flags & Style_Horizontal) {
+ p->drawLine(x, y, x2, y);
+ p->drawLine(x, y2, x2, y2);
+ renderGradient(p, QRect(x, y+1, w, h-2),
+ cg.mid(), false);
+ } else {
+ p->drawLine(x, y, x, y2);
+ p->drawLine(x2, y, x2, y2);
+ renderGradient(p, QRect(x+1, y, w-2, h),
+ cg.mid(), true);
+ }
+ break;
+ }
+
+
+ case PE_ScrollBarAddLine: {
+ drawPrimitive( PE_ButtonBevel, p, r, cg, (flags & Style_Enabled) |
+ ((flags & Style_Down) ? Style_Down : Style_Raised) );
+
+ drawPrimitive( ((flags & Style_Horizontal) ? PE_ArrowRight : PE_ArrowDown),
+ p, r, cg, flags );
+ break;
+ }
+
+
+ case PE_ScrollBarSubLine: {
+ drawPrimitive( PE_ButtonBevel, p, r, cg, (flags & Style_Enabled) |
+ ((flags & Style_Down) ? Style_Down : Style_Raised) );
+
+ drawPrimitive( ((flags & Style_Horizontal) ? PE_ArrowLeft : PE_ArrowUp),
+ p, r, cg, flags );
+ break;
+ }
+
+
+ // CHECKBOX (indicator)
+ // -------------------------------------------------------------------
+ case PE_Indicator: {
+
+ bool enabled = flags & Style_Enabled;
+ bool nochange = flags & Style_NoChange;
+
+ if (xBmp.isNull()) {
+ xBmp = QBitmap(7, 7, x_bits, true);
+ xBmp.setMask(xBmp);
+ }
+
+ int x,y,w,h;
+ x=r.x(); y=r.y(); w=r.width(); h=r.height();
+ int x2 = x+w-1;
+ int y2 = y+h-1;
+
+ p->setPen(cg.mid());
+ p->drawLine(x, y, x2, y);
+ p->drawLine(x, y, x, y2);
+
+ p->setPen(cg.light());
+ p->drawLine(x2, y+1, x2, y2);
+ p->drawLine(x+1, y2, x2, y2);
+
+ p->setPen(cg.shadow());
+ p->drawLine(x+1, y+1, x2-1, y+1);
+ p->drawLine(x+1, y+1, x+1, y2-1);
+
+ p->setPen(cg.midlight());
+ p->drawLine(x2-1, y+2, x2-1, y2-1);
+ p->drawLine(x+2, y2-1, x2-1, y2-1);
+
+ if ( enabled )
+ p->fillRect(x+2, y+2, w-4, h-4,
+ down ? cg.button(): cg.base());
+ else
+ p->fillRect(x+2, y+2, w-4, h-4, cg.background());
+
+ if (!(flags & Style_Off)) {
+ if (on) {
+ p->setPen(nochange ? cg.dark() : cg.text());
+ p->drawPixmap(x+3, y+3, xBmp);
+ }
+ else {
+ p->setPen(cg.shadow());
+ p->drawRect(x+2, y+2, w-4, h-4);
+ p->setPen(nochange ? cg.text() : cg.dark());
+ p->drawLine(x+3, (y+h)/2-2, x+w-4, (y+h)/2-2);
+ p->drawLine(x+3, (y+h)/2, x+w-4, (y+h)/2);
+ p->drawLine(x+3, (y+h)/2+2, x+w-4, (y+h)/2+2);
+ }
+ }
+ break;
+ }
+
+
+ // RADIOBUTTON (exclusive indicator)
+ // -------------------------------------------------------------------
+ case PE_ExclusiveIndicator: {
+
+ if (lightBmp.isNull()) {
+ lightBmp = QBitmap(13, 13, radiooff_light_bits, true);
+ grayBmp = QBitmap(13, 13, radiooff_gray_bits, true);
+ dgrayBmp = QBitmap(13, 13, radiooff_dgray_bits, true);
+ centerBmp = QBitmap(13, 13, radiooff_center_bits, true);
+ centerBmp.setMask( centerBmp );
+ }
+
+ // Bevel
+ kColorBitmaps(p, cg, r.x(), r.y(), &lightBmp , &grayBmp,
+ NULL, &dgrayBmp);
+
+ // The center fill of the indicator (grayed out when disabled)
+ if ( flags & Style_Enabled )
+ p->setPen( down ? cg.button() : cg.base() );
+ else
+ p->setPen( cg.background() );
+ p->drawPixmap( r.x(), r.y(), centerBmp );
+
+ // Indicator "dot"
+ if ( on ) {
+ QColor color = flags & Style_NoChange ?
+ cg.dark() : cg.text();
+
+ p->setPen(color);
+ p->drawLine(5, 4, 7, 4);
+ p->drawLine(4, 5, 4, 7);
+ p->drawLine(5, 8, 7, 8);
+ p->drawLine(8, 5, 8, 7);
+ p->fillRect(5, 5, 3, 3, color);
+ }
+
+ break;
+ }
+
+
+ // RADIOBUTTON (exclusive indicator) mask
+ // -------------------------------------------------------------------
+ case PE_ExclusiveIndicatorMask: {
+ if (maskBmp.isNull()) {
+ maskBmp = QBitmap(13, 13, radiomask_bits, true);
+ maskBmp.setMask(maskBmp);
+ }
+
+ p->setPen(Qt::color1);
+ p->drawPixmap(r.x(), r.y(), maskBmp);
+ break;
+ }
+
+
+ // SPLITTER/DOCKWINDOW HANDLES
+ // -------------------------------------------------------------------
+ case PE_DockWindowResizeHandle:
+ case PE_Splitter: {
+ int x,y,w,h;
+ r.rect(&x, &y, &w, &h);
+ int x2 = x+w-1;
+ int y2 = y+h-1;
+
+ p->setPen(cg.dark());
+ p->drawRect(x, y, w, h);
+ p->setPen(cg.background());
+ p->drawPoint(x, y);
+ p->drawPoint(x2, y);
+ p->drawPoint(x, y2);
+ p->drawPoint(x2, y2);
+ p->setPen(cg.light());
+ p->drawLine(x+1, y+1, x+1, y2-1);
+ p->drawLine(x+1, y+1, x2-1, y+1);
+ p->setPen(cg.midlight());
+ p->drawLine(x+2, y+2, x+2, y2-2);
+ p->drawLine(x+2, y+2, x2-2, y+2);
+ p->setPen(cg.mid());
+ p->drawLine(x2-1, y+1, x2-1, y2-1);
+ p->drawLine(x+1, y2-1, x2-1, y2-1);
+ p->fillRect(x+3, y+3, w-5, h-5, cg.brush(QColorGroup::Background));
+ break;
+ }
+
+
+ // GENERAL PANELS
+ // -------------------------------------------------------------------
+ case PE_Panel:
+ case PE_PanelPopup:
+ case PE_WindowFrame:
+ case PE_PanelLineEdit: {
+ bool sunken = flags & Style_Sunken;
+ int lw = opt.isDefault() ? pixelMetric(PM_DefaultFrameWidth)
+ : opt.lineWidth();
+ if (lw == 2)
+ {
+ QPen oldPen = p->pen();
+ int x,y,w,h;
+ r.rect(&x, &y, &w, &h);
+ int x2 = x+w-1;
+ int y2 = y+h-1;
+ p->setPen(sunken ? cg.light() : cg.dark());
+ p->drawLine(x, y2, x2, y2);
+ p->drawLine(x2, y, x2, y2);
+ p->setPen(sunken ? cg.mid() : cg.light());
+ p->drawLine(x, y, x2, y);
+ p->drawLine(x, y, x, y2);
+ p->setPen(sunken ? cg.midlight() : cg.mid());
+ p->drawLine(x+1, y2-1, x2-1, y2-1);
+ p->drawLine(x2-1, y+1, x2-1, y2-1);
+ p->setPen(sunken ? cg.dark() : cg.midlight());
+ p->drawLine(x+1, y+1, x2-1, y+1);
+ p->drawLine(x+1, y+1, x+1, y2-1);
+ p->setPen(oldPen);
+ } else
+ KStyle::drawPrimitive(pe, p, r, cg, flags, opt);
+
+ break;
+ }
+
+
+ // MENU / TOOLBAR PANEL
+ // -------------------------------------------------------------------
+ case PE_PanelMenuBar: // Menu
+ case PE_PanelDockWindow: { // Toolbar
+ int x2 = r.x()+r.width()-1;
+ int y2 = r.y()+r.height()-1;
+
+ if (opt.lineWidth())
+ {
+ p->setPen(cg.light());
+ p->drawLine(r.x(), r.y(), x2-1, r.y());
+ p->drawLine(r.x(), r.y(), r.x(), y2-1);
+ p->setPen(cg.dark());
+ p->drawLine(r.x(), y2, x2, y2);
+ p->drawLine(x2, r.y(), x2, y2);
+
+ // ### Qt should specify Style_Horizontal where appropriate
+ renderGradient( p, QRect(r.x()+1, r.y()+1, x2-1, y2-1),
+ cg.button(), (r.width() < r.height()) &&
+ (pe != PE_PanelMenuBar) );
+ }
+ else
+ {
+ renderGradient( p, QRect(r.x(), r.y(), x2, y2),
+ cg.button(), (r.width() < r.height()) &&
+ (pe != PE_PanelMenuBar) );
+ }
+
+ break;
+ }
+
+
+
+ // TOOLBAR SEPARATOR
+ // -------------------------------------------------------------------
+ case PE_DockWindowSeparator: {
+ renderGradient( p, r, cg.button(),
+ !(flags & Style_Horizontal));
+ if ( !(flags & Style_Horizontal) ) {
+ p->setPen(cg.mid());
+ p->drawLine(4, r.height()/2, r.width()-5, r.height()/2);
+ p->setPen(cg.light());
+ p->drawLine(4, r.height()/2+1, r.width()-5, r.height()/2+1);
+ } else {
+ p->setPen(cg.mid());
+ p->drawLine(r.width()/2, 4, r.width()/2, r.height()-5);
+ p->setPen(cg.light());
+ p->drawLine(r.width()/2+1, 4, r.width()/2+1, r.height()-5);
+ }
+ break;
+ }
+
+
+ default:
+ {
+ // ARROWS
+ // -------------------------------------------------------------------
+ if (pe >= PE_ArrowUp && pe <= PE_ArrowLeft)
+ {
+ QPointArray a;
+
+ // HighColor & Default arrows
+ switch(pe) {
+ case PE_ArrowUp:
+ a.setPoints(QCOORDARRLEN(u_arrow), u_arrow);
+ break;
+
+ case PE_ArrowDown:
+ a.setPoints(QCOORDARRLEN(d_arrow), d_arrow);
+ break;
+
+ case PE_ArrowLeft:
+ a.setPoints(QCOORDARRLEN(l_arrow), l_arrow);
+ break;
+
+ default:
+ a.setPoints(QCOORDARRLEN(r_arrow), r_arrow);
+ }
+
+ p->save();
+ if ( flags & Style_Down )
+ p->translate( pixelMetric( PM_ButtonShiftHorizontal ),
+ pixelMetric( PM_ButtonShiftVertical ) );
+
+ if ( flags & Style_Enabled ) {
+ a.translate( r.x() + r.width() / 2, r.y() + r.height() / 2 );
+ p->setPen( cg.buttonText() );
+ p->drawLineSegments( a );
+ } else {
+ a.translate( r.x() + r.width() / 2 + 1, r.y() + r.height() / 2 + 1 );
+ p->setPen( cg.light() );
+ p->drawLineSegments( a );
+ a.translate( -1, -1 );
+ p->setPen( cg.mid() );
+ p->drawLineSegments( a );
+ }
+ p->restore();
+
+ } else
+ KStyle::drawPrimitive( pe, p, r, cg, flags, opt );
+ }
+ }
+}
+
+
+void StyleCheckStyle::drawKStylePrimitive( KStylePrimitive kpe,
+ QPainter* p,
+ const QWidget* widget,
+ const QRect &r,
+ const QColorGroup &cg,
+ SFlags flags,
+ const QStyleOption &opt ) const
+{
+ switch ( kpe )
+ {
+ // TOOLBAR HANDLE
+ // -------------------------------------------------------------------
+ case KPE_ToolBarHandle: {
+ int x = r.x(); int y = r.y();
+ int x2 = r.x() + r.width()-1;
+ int y2 = r.y() + r.height()-1;
+
+ if (flags & Style_Horizontal) {
+
+ renderGradient( p, r, cg.button(), false);
+ p->setPen(cg.light());
+ p->drawLine(x+1, y+4, x+1, y2-4);
+ p->drawLine(x+3, y+4, x+3, y2-4);
+ p->drawLine(x+5, y+4, x+5, y2-4);
+
+ p->setPen(cg.mid());
+ p->drawLine(x+2, y+4, x+2, y2-4);
+ p->drawLine(x+4, y+4, x+4, y2-4);
+ p->drawLine(x+6, y+4, x+6, y2-4);
+
+ } else {
+
+ renderGradient( p, r, cg.button(), true);
+ p->setPen(cg.light());
+ p->drawLine(x+4, y+1, x2-4, y+1);
+ p->drawLine(x+4, y+3, x2-4, y+3);
+ p->drawLine(x+4, y+5, x2-4, y+5);
+
+ p->setPen(cg.mid());
+ p->drawLine(x+4, y+2, x2-4, y+2);
+ p->drawLine(x+4, y+4, x2-4, y+4);
+ p->drawLine(x+4, y+6, x2-4, y+6);
+
+ }
+ break;
+ }
+
+
+ // GENERAL/KICKER HANDLE
+ // -------------------------------------------------------------------
+ case KPE_GeneralHandle: {
+ int x = r.x(); int y = r.y();
+ int x2 = r.x() + r.width()-1;
+ int y2 = r.y() + r.height()-1;
+
+ if (flags & Style_Horizontal) {
+
+ p->setPen(cg.light());
+ p->drawLine(x+1, y, x+1, y2);
+ p->drawLine(x+3, y, x+3, y2);
+ p->drawLine(x+5, y, x+5, y2);
+
+ p->setPen(cg.mid());
+ p->drawLine(x+2, y, x+2, y2);
+ p->drawLine(x+4, y, x+4, y2);
+ p->drawLine(x+6, y, x+6, y2);
+
+ } else {
+
+ p->setPen(cg.light());
+ p->drawLine(x, y+1, x2, y+1);
+ p->drawLine(x, y+3, x2, y+3);
+ p->drawLine(x, y+5, x2, y+5);
+
+ p->setPen(cg.mid());
+ p->drawLine(x, y+2, x2, y+2);
+ p->drawLine(x, y+4, x2, y+4);
+ p->drawLine(x, y+6, x2, y+6);
+
+ }
+ break;
+ }
+
+
+ // SLIDER GROOVE
+ // -------------------------------------------------------------------
+ case KPE_SliderGroove: {
+ const QSlider* slider = (const QSlider*)widget;
+ bool horizontal = slider->orientation() == Horizontal;
+ int gcenter = (horizontal ? r.height() : r.width()) / 2;
+
+ QRect gr;
+ if (horizontal)
+ gr = QRect(r.x(), r.y()+gcenter-3, r.width(), 7);
+ else
+ gr = QRect(r.x()+gcenter-3, r.y(), 7, r.height());
+
+ int x,y,w,h;
+ gr.rect(&x, &y, &w, &h);
+ int x2=x+w-1;
+ int y2=y+h-1;
+
+ // Draw the slider groove.
+ p->setPen(cg.dark());
+ p->drawLine(x+2, y, x2-2, y);
+ p->drawLine(x, y+2, x, y2-2);
+ p->fillRect(x+2,y+2,w-4, h-4,
+ slider->isEnabled() ? cg.dark() : cg.mid());
+ p->setPen(cg.shadow());
+ p->drawRect(x+1, y+1, w-2, h-2);
+ p->setPen(cg.light());
+ p->drawPoint(x+1,y2-1);
+ p->drawPoint(x2-1,y2-1);
+ p->drawLine(x2, y+2, x2, y2-2);
+ p->drawLine(x+2, y2, x2-2, y2);
+ break;
+ }
+
+ // SLIDER HANDLE
+ // -------------------------------------------------------------------
+ case KPE_SliderHandle: {
+ const QSlider* slider = (const QSlider*)widget;
+ bool horizontal = slider->orientation() == Horizontal;
+ int x,y,w,h;
+ r.rect(&x, &y, &w, &h);
+ int x2 = x+w-1;
+ int y2 = y+h-1;
+
+ p->setPen(cg.mid());
+ p->drawLine(x+1, y, x2-1, y);
+ p->drawLine(x, y+1, x, y2-1);
+ p->setPen(cg.shadow());
+ p->drawLine(x+1, y2, x2-1, y2);
+ p->drawLine(x2, y+1, x2, y2-1);
+
+ p->setPen(cg.light());
+ p->drawLine(x+1, y+1, x2-1, y+1);
+ p->drawLine(x+1, y+1, x+1, y2-1);
+ p->setPen(cg.dark());
+ p->drawLine(x+2, y2-1, x2-1, y2-1);
+ p->drawLine(x2-1, y+2, x2-1, y2-1);
+ p->setPen(cg.midlight());
+ p->drawLine(x+2, y+2, x2-2, y+2);
+ p->drawLine(x+2, y+2, x+2, y2-2);
+ p->setPen(cg.mid());
+ p->drawLine(x+3, y2-2, x2-2, y2-2);
+ p->drawLine(x2-2, y+3, x2-2, y2-2);
+ renderGradient(p, QRect(x+3, y+3, w-6, h-6),
+ cg.button(), !horizontal);
+
+ // Paint riffles
+ if (horizontal) {
+ p->setPen(cg.light());
+ p->drawLine(x+5, y+4, x+5, y2-4);
+ p->drawLine(x+8, y+4, x+8, y2-4);
+ p->drawLine(x+11,y+4, x+11, y2-4);
+ p->setPen(slider->isEnabled() ? cg.shadow(): cg.mid());
+ p->drawLine(x+6, y+4, x+6, y2-4);
+ p->drawLine(x+9, y+4, x+9, y2-4);
+ p->drawLine(x+12,y+4, x+12, y2-4);
+ } else {
+ p->setPen(cg.light());
+ p->drawLine(x+4, y+5, x2-4, y+5);
+ p->drawLine(x+4, y+8, x2-4, y+8);
+ p->drawLine(x+4, y+11, x2-4, y+11);
+ p->setPen(slider->isEnabled() ? cg.shadow() : cg.mid());
+ p->drawLine(x+4, y+6, x2-4, y+6);
+ p->drawLine(x+4, y+9, x2-4, y+9);
+ p->drawLine(x+4, y+12, x2-4, y+12);
+ }
+ break;
+ }
+
+ default:
+ KStyle::drawKStylePrimitive( kpe, p, widget, r, cg, flags, opt);
+ }
+}
+
+
+void StyleCheckStyle::drawControl( ControlElement element,
+ QPainter *p,
+ const QWidget *widget,
+ const QRect &r,
+ const QColorGroup &cg,
+ SFlags flags,
+ const QStyleOption& opt ) const
+{
+ switch (element)
+ {
+ // PUSHBUTTON
+ // -------------------------------------------------------------------
+ case CE_PushButton: {
+ if ( widget == hoverWidget )
+ flags |= Style_MouseOver;
+
+ QPushButton *button = (QPushButton*) widget;
+ QRect br = r;
+ bool btnDefault = button->isDefault();
+
+ if ( btnDefault || button->autoDefault() ) {
+ // Compensate for default indicator
+ static int di = pixelMetric( PM_ButtonDefaultIndicator );
+ br.addCoords( di, di, -di, -di );
+ }
+
+ if ( btnDefault )
+ drawPrimitive( PE_ButtonDefault, p, r, cg, flags );
+
+ drawPrimitive( PE_ButtonCommand, p, br, cg, flags );
+
+ break;
+ }
+
+
+ // PUSHBUTTON LABEL
+ // -------------------------------------------------------------------
+ case CE_PushButtonLabel: {
+ const QPushButton* button = (const QPushButton*)widget;
+ bool active = button->isOn() || button->isDown();
+ int x, y, w, h;
+ r.rect( &x, &y, &w, &h );
+
+ // Shift button contents if pushed.
+ if ( active ) {
+ x += pixelMetric(PM_ButtonShiftHorizontal, widget);
+ y += pixelMetric(PM_ButtonShiftVertical, widget);
+ flags |= Style_Sunken;
+ }
+
+ // Does the button have a popup menu?
+ if ( button->isMenuButton() ) {
+ int dx = pixelMetric( PM_MenuButtonIndicator, widget );
+ drawPrimitive( PE_ArrowDown, p, QRect(x + w - dx - 2, y + 2, dx, h - 4),
+ cg, flags, opt );
+ w -= dx;
+ }
+
+ // Draw the icon if there is one
+ if ( button->iconSet() && !button->iconSet()->isNull() ) {
+ QIconSet::Mode mode = QIconSet::Disabled;
+ QIconSet::State state = QIconSet::Off;
+
+ if (button->isEnabled())
+ mode = button->hasFocus() ? QIconSet::Active : QIconSet::Normal;
+ if (button->isToggleButton() && button->isOn())
+ state = QIconSet::On;
+
+ QPixmap pixmap = button->iconSet()->pixmap( QIconSet::Small, mode, state );
+ p->drawPixmap( x + 4, y + h / 2 - pixmap.height() / 2, pixmap );
+ int pw = pixmap.width();
+ x += pw + 4;
+ w -= pw + 4;
+ }
+
+ QValueVector<StyleGuideViolation> violations = checkTitleStyle(button->text(), ShortTitle, HasAccels);
+ renderViolations(violations, p, QRect(x,y,w,h), AlignCenter | ShowPrefix, button->text());
+
+ // Make the label indicate if the button is a default button or not
+ if ( active || button->isDefault() ) {
+ // Draw "fake" bold text - this enables the font metrics to remain
+ // the same as computed in QPushButton::sizeHint(), but gives
+ // a reasonable bold effect.
+ int i;
+
+ // Text shadow
+ if (button->isEnabled()) // Don't draw double-shadow when disabled
+ for(i=0; i<2; i++)
+ drawItem( p, QRect(x+i+1, y+1, w, h), AlignCenter | ShowPrefix,
+ button->colorGroup(), button->isEnabled(), button->pixmap(),
+ removedXX(stripAccelViolations(button->text())), -1,
+ active ? &button->colorGroup().dark() : &button->colorGroup().mid() );
+
+ // Normal Text
+ for(i=0; i<2; i++)
+ drawItem( p, QRect(x+i, y, w, h), AlignCenter | ShowPrefix,
+ button->colorGroup(), button->isEnabled(), button->pixmap(),
+ removedXX(stripAccelViolations(button->text())), -1,
+ active ? &button->colorGroup().light() : &button->colorGroup().buttonText() );
+ } else
+ drawItem( p, QRect(x, y, w, h), AlignCenter | ShowPrefix, button->colorGroup(),
+ button->isEnabled(), button->pixmap(), removedXX(stripAccelViolations(button->text())), -1,
+ active ? &button->colorGroup().light() : &button->colorGroup().buttonText() );
+
+ // Draw a focus rect if the button has focus
+ if ( flags & Style_HasFocus )
+ drawPrimitive( PE_FocusRect, p,
+ QStyle::visualRect(subRect(SR_PushButtonFocusRect, widget), widget),
+ cg, flags );
+ break;
+ }
+
+ case CE_TabBarLabel:
+ {
+ if ( opt.isDefault() )
+ break;
+
+ const QTabBar * tb = (const QTabBar *) widget;
+ QTab * t = opt.tab();
+
+ QRect tr = r;
+ if ( t->identifier() == tb->currentTab() )
+ tr.setBottom( tr.bottom() -
+ pixelMetric( QStyle::PM_DefaultFrameWidth, tb ) );
+
+ QValueVector<StyleGuideViolation> violations = checkTitleStyle(t->text(), ShortTitle, HasAccels);
+ renderViolations(violations, p, r, AlignCenter |ShowPrefix, t->text());
+
+ drawItem( p, tr, AlignCenter | ShowPrefix, cg,
+ flags & Style_Enabled, 0, removedXX(stripAccelViolations(t->text())) );
+
+ if ( (flags & Style_HasFocus) && !t->text().isEmpty() )
+ drawPrimitive( PE_FocusRect, p, r, cg );
+ break;
+ }
+
+
+ case CE_CheckBoxLabel:
+ {
+ const QCheckBox* checkbox = static_cast<const QCheckBox*>(widget);
+
+ int alignment = QApplication::reverseLayout() ? AlignRight : AlignLeft;
+
+ QValueVector<StyleGuideViolation> violations = checkSentenceStyle(checkbox->text());
+
+ renderViolations(violations, p, r, alignment | AlignVCenter | ShowPrefix, checkbox->text());
+
+ drawItem(p, r, alignment | AlignVCenter | ShowPrefix, cg,
+ flags & Style_Enabled, checkbox->pixmap(), removedXX(stripAccelViolations(checkbox->text())));
+
+ if (flags & Style_HasFocus)
+ {
+ QRect fr = visualRect(subRect(SR_CheckBoxFocusRect, widget), widget);
+ drawPrimitive(PE_FocusRect, p, fr, cg, flags);
+ }
+ break;
+ }
+
+ case CE_RadioButtonLabel:
+ {
+ const QRadioButton* rb = static_cast<const QRadioButton*>(widget);
+
+ int alignment = QApplication::reverseLayout() ? AlignRight : AlignLeft;
+
+ QValueVector<StyleGuideViolation> violations = checkSentenceStyle(rb->text());
+
+ renderViolations(violations, p, r,alignment | AlignVCenter | ShowPrefix, rb->text());
+
+ drawItem(p, r, alignment | AlignVCenter | ShowPrefix, cg,
+ flags & Style_Enabled, rb->pixmap(), removedXX(stripAccelViolations(rb->text())));
+
+ if (flags & Style_HasFocus)
+ {
+ QRect fr = visualRect(subRect(SR_CheckBoxFocusRect, widget), widget);
+ drawPrimitive(PE_FocusRect, p, fr, cg, flags);
+ }
+ break;
+ }
+
+
+ // MENUBAR ITEM (sunken panel on mouse over)
+ // -------------------------------------------------------------------
+ case CE_MenuBarItem:
+ {
+ QMenuBar *mb = (QMenuBar*)widget;
+ QMenuItem *mi = opt.menuItem();
+ QRect pr = mb->rect();
+
+ bool active = flags & Style_Active;
+ bool focused = flags & Style_HasFocus;
+
+ if ( active && focused )
+ qDrawShadePanel(p, r.x(), r.y(), r.width(), r.height(),
+ cg, true, 1, &cg.brush(QColorGroup::Midlight));
+ else
+ renderGradient( p, r, cg.button(), false,
+ r.x(), r.y()-1, pr.width()-2, pr.height()-2);
+
+ QValueVector<StyleGuideViolation> violations = checkTitleStyle(mi->text(), ShortTitle, HasAccels);
+ renderViolations(violations, p, r, AlignCenter | AlignVCenter | ShowPrefix, mi->text());
+
+ drawItem( p, r, AlignCenter | AlignVCenter | ShowPrefix
+ | DontClip | SingleLine, cg, flags & Style_Enabled,
+ mi->pixmap(), removedXX(stripAccelViolations(mi->text())) );
+
+ break;
+ }
+
+
+ // POPUPMENU ITEM
+ // -------------------------------------------------------------------
+ case CE_PopupMenuItem: {
+ const QPopupMenu *popupmenu = (const QPopupMenu *) widget;
+
+ QMenuItem *mi = opt.menuItem();
+ if ( !mi ) {
+ // Don't leave blank holes if we set NoBackground for the QPopupMenu.
+ // This only happens when the popupMenu spans more than one column.
+ if (! (widget->erasePixmap() && !widget->erasePixmap()->isNull()) )
+ p->fillRect(r, cg.brush(QColorGroup::Button) );
+ break;
+ }
+
+ int tab = opt.tabWidth();
+ int checkcol = opt.maxIconWidth();
+ bool enabled = mi->isEnabled();
+ bool checkable = popupmenu->isCheckable();
+ bool active = flags & Style_Active;
+ bool etchtext = styleHint( SH_EtchDisabledText );
+ bool reverse = QApplication::reverseLayout();
+ int x, y, w, h;
+ r.rect( &x, &y, &w, &h );
+
+ if ( checkable )
+ checkcol = QMAX( checkcol, 20 );
+
+ // Are we a menu item separator?
+ if ( mi->isSeparator() ) {
+ p->setPen( cg.dark() );
+ p->drawLine( x, y, x+w, y );
+ p->setPen( cg.light() );
+ p->drawLine( x, y+1, x+w, y+1 );
+ break;
+ }
+
+ // Draw the menu item background
+ if ( active )
+ qDrawShadePanel( p, x, y, w, h, cg, true, 1,
+ &cg.brush(QColorGroup::Midlight) );
+ // Draw the transparency pixmap
+ else if ( widget->erasePixmap() && !widget->erasePixmap()->isNull() )
+ p->drawPixmap( x, y, *widget->erasePixmap(), x, y, w, h );
+ // Draw a solid background
+ else
+ p->fillRect( r, cg.button() );
+
+ // Do we have an icon?
+ if ( mi->iconSet() ) {
+ QIconSet::Mode mode;
+ QRect cr = visualRect( QRect(x, y, checkcol, h), r );
+
+ // Select the correct icon from the iconset
+ if ( active )
+ mode = enabled ? QIconSet::Active : QIconSet::Disabled;
+ else
+ mode = enabled ? QIconSet::Normal : QIconSet::Disabled;
+
+ // Do we have an icon and are checked at the same time?
+ // Then draw a "pressed" background behind the icon
+ if ( checkable && !active && mi->isChecked() )
+ qDrawShadePanel( p, cr.x(), cr.y(), cr.width(), cr.height(),
+ cg, true, 1, &cg.brush(QColorGroup::Midlight) );
+ // Draw the icon
+ QPixmap pixmap = mi->iconSet()->pixmap( QIconSet::Small, mode );
+ QRect pmr( 0, 0, pixmap.width(), pixmap.height() );
+ pmr.moveCenter( cr.center() );
+ p->drawPixmap( pmr.topLeft(), pixmap );
+ }
+
+ // Are we checked? (This time without an icon)
+ else if ( checkable && mi->isChecked() ) {
+ int cx = reverse ? x+w - checkcol : x;
+
+ // We only have to draw the background if the menu item is inactive -
+ // if it's active the "pressed" background is already drawn
+ if ( ! active )
+ qDrawShadePanel( p, cx, y, checkcol, h, cg, true, 1,
+ &cg.brush(QColorGroup::Midlight) );
+
+ // Draw the checkmark
+ SFlags cflags = Style_Default;
+ cflags |= active ? Style_Enabled : Style_On;
+
+ drawPrimitive( PE_CheckMark, p, QRect( cx + itemFrame, y + itemFrame,
+ checkcol - itemFrame*2, h - itemFrame*2), cg, cflags );
+ }
+
+ // Time to draw the menu item label...
+ int xm = itemFrame + checkcol + itemHMargin; // X position margin
+
+ int xp = reverse ? // X position
+ x + tab + rightBorder + itemHMargin + itemFrame - 1 :
+ x + xm;
+
+ int offset = reverse ? -1 : 1; // Shadow offset for etched text
+
+ // Label width (minus the width of the accelerator portion)
+ int tw = w - xm - tab - arrowHMargin - itemHMargin * 3 - itemFrame + 1;
+
+ // Set the color for enabled and disabled text
+ // (used for both active and inactive menu items)
+ p->setPen( enabled ? cg.buttonText() : cg.mid() );
+
+ // This color will be used instead of the above if the menu item
+ // is active and disabled at the same time. (etched text)
+ QColor discol = cg.mid();
+
+ // Does the menu item draw it's own label?
+ if ( mi->custom() ) {
+ int m = itemVMargin;
+ // Save the painter state in case the custom
+ // paint method changes it in some way
+ p->save();
+
+ // Draw etched text if we're inactive and the menu item is disabled
+ if ( etchtext && !enabled && !active ) {
+ p->setPen( cg.light() );
+ mi->custom()->paint( p, cg, active, enabled, xp+offset, y+m+1, tw, h-2*m );
+ p->setPen( discol );
+ }
+ mi->custom()->paint( p, cg, active, enabled, xp, y+m, tw, h-2*m );
+ p->restore();
+ }
+ else {
+ QValueVector<StyleGuideViolation> ourViolations;
+
+ QString tmpStr = mi->text();
+ removeAccelerators(tmpStr);
+ findAccelViolations(tmpStr, ourViolations);
+
+ // The menu item doesn't draw it's own label
+ QString s = stripAccelViolations(mi->text());
+
+ // Does the menu item have a text label?
+ if ( !s.isNull() ) {
+ int t = s.find( '\t' );
+ int m = itemVMargin;
+ int text_flags = AlignVCenter | ShowPrefix | DontClip | SingleLine;
+ text_flags |= reverse ? AlignRight : AlignLeft;
+
+ // Does the menu item have a tabstop? (for the accelerator text)
+ if ( t >= 0 ) {
+ int tabx = reverse ? x + rightBorder + itemHMargin + itemFrame :
+ x + w - tab - rightBorder - itemHMargin - itemFrame;
+
+ // Draw the right part of the label (accelerator text)
+ if ( etchtext && !enabled && !active ) {
+ // Draw etched text if we're inactive and the menu item is disabled
+ p->setPen( cg.light() );
+ p->drawText( tabx+offset, y+m+1, tab, h-2*m, text_flags, removedXX(s.mid( t+1 )) );
+ p->setPen( discol );
+ }
+ p->drawText( tabx, y+m, tab, h-2*m, text_flags, removedXX(s.mid( t+1 )) );
+ s = s.left( t );
+ }
+
+ QValueVector<StyleGuideViolation> violations = checkTitleStyle(s, ShortTitle, HasAccels);
+ renderViolations(violations, p, QRect(xp, y+m, tw, h-2*m), text_flags, s);
+ renderViolations(ourViolations, p, QRect(xp, y+m, tw, h-2*m), text_flags, s);
+
+
+ // Draw the left part of the label (or the whole label
+ // if there's no accelerator)
+ if ( etchtext && !enabled && !active ) {
+ // Etched text again for inactive disabled menu items...
+ p->setPen( cg.light() );
+ p->drawText( xp+offset, y+m+1, tw, h-2*m, text_flags, removedXX(s)/*, t*/ );
+ p->setPen( discol );
+ }
+
+ p->drawText( xp, y+m, tw, h-2*m, text_flags, removedXX(s)/*, t*/ );
+
+ }
+
+ // The menu item doesn't have a text label
+ // Check if it has a pixmap instead
+ else if ( mi->pixmap() ) {
+ QPixmap *pixmap = mi->pixmap();
+
+ // Draw the pixmap
+ if ( pixmap->depth() == 1 )
+ p->setBackgroundMode( OpaqueMode );
+
+ int diffw = ( ( w - pixmap->width() ) / 2 )
+ + ( ( w - pixmap->width() ) % 2 );
+ p->drawPixmap( x+diffw, y+itemFrame, *pixmap );
+
+ if ( pixmap->depth() == 1 )
+ p->setBackgroundMode( TransparentMode );
+ }
+ }
+
+ // Does the menu item have a submenu?
+ if ( mi->popup() ) {
+ PrimitiveElement arrow = reverse ? PE_ArrowLeft : PE_ArrowRight;
+ int dim = pixelMetric(PM_MenuButtonIndicator);
+ QRect vr = visualRect( QRect( x + w - arrowHMargin - 2*itemFrame - dim,
+ y + h / 2 - dim / 2, dim, dim), r );
+
+ // Draw an arrow at the far end of the menu item
+ if ( active ) {
+ if ( enabled )
+ discol = cg.buttonText();
+
+ QColorGroup g2( discol, cg.highlight(), white, white,
+ enabled ? white : discol, discol, white );
+
+ drawPrimitive( arrow, p, vr, g2, Style_Enabled );
+ } else
+ drawPrimitive( arrow, p, vr, cg,
+ enabled ? Style_Enabled : Style_Default );
+ }
+ break;
+ }
+
+ case CE_HeaderLabel:
+ {
+ //Most of code here shamelessly lifted from QCommonStyle.
+ QRect rect = r;
+ const QHeader* header = static_cast<const QHeader*>(widget);
+ int section = opt.headerSection();
+ QIconSet* icon = header->iconSet( section );
+ if ( icon )
+ {
+ QPixmap pixmap = icon->pixmap( QIconSet::Small,
+ flags & Style_Enabled ? QIconSet::Normal : QIconSet::Disabled );
+ int pixw = pixmap.width();
+ int pixh = pixmap.height();
+ // "pixh - 1" because of tricky integer division
+ QRect pixRect = rect;
+ pixRect.setY( rect.center().y() - (pixh - 1) / 2 );
+ drawItem ( p, pixRect, AlignVCenter, cg, flags & Style_Enabled,
+ &pixmap, QString::null );
+ rect.setLeft( rect.left() + pixw + 2 );
+ }
+
+ QString s = header->label( section );
+
+ QValueVector<StyleGuideViolation> violations = checkTitleStyle(s, ShortTitle, NoAccels);
+ renderViolations(violations, p, rect, AlignVCenter, s);
+
+
+ drawItem ( p, rect, AlignVCenter, cg, flags & Style_Enabled,
+ 0, s, -1, &(cg.buttonText()) );
+
+ break;
+ }
+
+ default:
+ KStyle::drawControl(element, p, widget, r, cg, flags, opt);
+ }
+}
+
+
+void StyleCheckStyle::drawControlMask( ControlElement element,
+ QPainter *p,
+ const QWidget *widget,
+ const QRect &r,
+ const QStyleOption& opt ) const
+{
+ switch (element)
+ {
+ // PUSHBUTTON MASK
+ // ----------------------------------------------------------------------
+ case CE_PushButton: {
+ int x1, y1, x2, y2;
+ r.coords( &x1, &y1, &x2, &y2 );
+ QCOORD corners[] = { x1,y1, x2,y1, x1,y2, x2,y2 };
+ p->fillRect( r, color1 );
+ p->setPen( color0 );
+ p->drawPoints( QPointArray(4, corners) );
+ break;
+ }
+
+ default:
+ KStyle::drawControlMask(element, p, widget, r, opt);
+ }
+}
+
+
+void StyleCheckStyle::drawComplexControl( ComplexControl control,
+ QPainter *p,
+ const QWidget *widget,
+ const QRect &r,
+ const QColorGroup &cg,
+ SFlags flags,
+ SCFlags controls,
+ SCFlags active,
+ const QStyleOption& opt ) const
+{
+ switch(control)
+ {
+ // COMBOBOX
+ // -------------------------------------------------------------------
+ case CC_ComboBox: {
+
+ // Draw box and arrow
+ if ( controls & SC_ComboBoxArrow ) {
+ bool sunken = (active == SC_ComboBoxArrow);
+
+ // Draw the combo
+ int x,y,w,h;
+ r.rect(&x, &y, &w, &h);
+ int x2 = x+w-1;
+ int y2 = y+h-1;
+
+ p->setPen(cg.shadow());
+ p->drawLine(x+1, y, x2-1, y);
+ p->drawLine(x+1, y2, x2-1, y2);
+ p->drawLine(x, y+1, x, y2-1);
+ p->drawLine(x2, y+1, x2, y2-1);
+
+ // Ensure the edge notches are properly colored
+ p->setPen(cg.button());
+ p->drawPoint(x,y);
+ p->drawPoint(x,y2);
+ p->drawPoint(x2,y);
+ p->drawPoint(x2,y2);
+
+ renderGradient( p, QRect(x+2, y+2, w-4, h-4),
+ cg.button(), false);
+
+ p->setPen(sunken ? cg.light() : cg.mid());
+ p->drawLine(x2-1, y+2, x2-1, y2-1);
+ p->drawLine(x+1, y2-1, x2-1, y2-1);
+
+ p->setPen(sunken ? cg.mid() : cg.light());
+ p->drawLine(x+1, y+1, x2-1, y+1);
+ p->drawLine(x+1, y+2, x+1, y2-2);
+
+ // Get the button bounding box
+ QRect ar = QStyle::visualRect(
+ querySubControlMetrics(CC_ComboBox, widget, SC_ComboBoxArrow),
+ widget );
+
+ // Are we enabled?
+ if ( widget->isEnabled() )
+ flags |= Style_Enabled;
+
+ // Are we "pushed" ?
+ if ( active & Style_Sunken )
+ flags |= Style_Sunken;
+
+ drawPrimitive(PE_ArrowDown, p, ar, cg, flags);
+ }
+
+ // Draw an edit field if required
+ if ( controls & SC_ComboBoxEditField )
+ {
+ const QComboBox * cb = (const QComboBox *) widget;
+ QRect re = QStyle::visualRect(
+ querySubControlMetrics( CC_ComboBox, widget,
+ SC_ComboBoxEditField), widget );
+
+ // Draw the indent
+ if (cb->editable()) {
+ p->setPen( cg.dark() );
+ p->drawLine( re.x(), re.y()-1, re.x()+re.width(), re.y()-1 );
+ p->drawLine( re.x()-1, re.y(), re.x()-1, re.y()+re.height() );
+ }
+
+ if ( cb->hasFocus() ) {
+ p->setPen( cg.highlightedText() );
+ p->setBackgroundColor( cg.highlight() );
+ } else {
+ p->setPen( cg.text() );
+ p->setBackgroundColor( cg.button() );
+ }
+
+ if ( cb->hasFocus() && !cb->editable() ) {
+ // Draw the contents
+ p->fillRect( re.x(), re.y(), re.width(), re.height(),
+ cg.brush( QColorGroup::Highlight ) );
+
+ QRect re = QStyle::visualRect(
+ subRect(SR_ComboBoxFocusRect, cb), widget);
+
+ drawPrimitive( PE_FocusRect, p, re, cg,
+ Style_FocusAtBorder, QStyleOption(cg.highlight()));
+ }
+ }
+ break;
+ }
+
+ // TOOLBUTTON
+ // -------------------------------------------------------------------
+ case CC_ToolButton: {
+ const QToolButton *toolbutton = (const QToolButton *) widget;
+
+ QRect button, menuarea;
+ button = querySubControlMetrics(control, widget, SC_ToolButton, opt);
+ menuarea = querySubControlMetrics(control, widget, SC_ToolButtonMenu, opt);
+
+ SFlags bflags = flags,
+ mflags = flags;
+
+ if (active & SC_ToolButton)
+ bflags |= Style_Down;
+ if (active & SC_ToolButtonMenu)
+ mflags |= Style_Down;
+
+ if (controls & SC_ToolButton)
+ {
+ // If we're pressed, on, or raised...
+ if (bflags & (Style_Down | Style_On | Style_Raised))
+ drawPrimitive(PE_ButtonTool, p, button, cg, bflags, opt);
+
+ // Check whether to draw a background pixmap
+ else if ( toolbutton->parentWidget() &&
+ toolbutton->parentWidget()->backgroundPixmap() &&
+ !toolbutton->parentWidget()->backgroundPixmap()->isNull() )
+ {
+ QPixmap pixmap = *(toolbutton->parentWidget()->backgroundPixmap());
+ p->drawTiledPixmap( r, pixmap, toolbutton->pos() );
+ }
+ else if (widget->parent())
+ {
+ if (widget->parent()->inherits("QToolBar"))
+ {
+ QToolBar* parent = (QToolBar*)widget->parent();
+ QRect pr = parent->rect();
+
+ renderGradient( p, r, cg.button(),
+ parent->orientation() == Qt::Vertical,
+ r.x(), r.y(), pr.width()-2, pr.height()-2);
+ }
+ else if (widget->parent()->inherits("QToolBarExtensionWidget"))
+ {
+ QWidget* parent = (QWidget*)widget->parent();
+ QToolBar* toolbar = (QToolBar*)parent->parent();
+ QRect tr = toolbar->rect();
+
+ if ( toolbar->orientation() == Qt::Horizontal ) {
+ renderGradient( p, r, cg.button(), false, r.x(), r.y(),
+ r.width(), tr.height() );
+ } else {
+ renderGradient( p, r, cg.button(), true, r.x(), r.y(),
+ tr.width(), r.height() );
+ }
+ }
+ }
+ }
+
+ // Draw a toolbutton menu indicator if required
+ if (controls & SC_ToolButtonMenu)
+ {
+ if (mflags & (Style_Down | Style_On | Style_Raised))
+ drawPrimitive(PE_ButtonDropDown, p, menuarea, cg, mflags, opt);
+ drawPrimitive(PE_ArrowDown, p, menuarea, cg, mflags, opt);
+ }
+
+ if (toolbutton->hasFocus() && !toolbutton->focusProxy()) {
+ QRect fr = toolbutton->rect();
+ fr.addCoords(3, 3, -3, -3);
+ drawPrimitive(PE_FocusRect, p, fr, cg);
+ }
+
+ break;
+ }
+
+
+ default:
+ KStyle::drawComplexControl(control, p, widget,
+ r, cg, flags, controls, active, opt);
+ break;
+ }
+}
+
+
+void StyleCheckStyle::drawComplexControlMask( ComplexControl control,
+ QPainter *p,
+ const QWidget *widget,
+ const QRect &r,
+ const QStyleOption& opt ) const
+{
+ switch (control)
+ {
+ // COMBOBOX & TOOLBUTTON MASKS
+ // -------------------------------------------------------------------
+ case CC_ComboBox:
+ case CC_ToolButton: {
+ int x1, y1, x2, y2;
+ r.coords( &x1, &y1, &x2, &y2 );
+ QCOORD corners[] = { x1,y1, x2,y1, x1,y2, x2,y2 };
+ p->fillRect( r, color1 );
+ p->setPen( color0 );
+ p->drawPoints( QPointArray(4, corners) );
+ break;
+ }
+
+ default:
+ KStyle::drawComplexControlMask(control, p, widget, r, opt);
+ }
+}
+
+
+QRect StyleCheckStyle::subRect(SubRect r, const QWidget *widget) const
+{
+ // We want the focus rect for buttons to be adjusted from
+ // the Qt3 defaults to be similar to Qt 2's defaults.
+ // -------------------------------------------------------------------
+ if (r == SR_PushButtonFocusRect ) {
+ const QPushButton* button = (const QPushButton*) widget;
+ QRect wrect(widget->rect());
+ int dbw1 = 0, dbw2 = 0;
+
+ if (button->isDefault() || button->autoDefault()) {
+ dbw1 = pixelMetric(PM_ButtonDefaultIndicator, widget);
+ dbw2 = dbw1 * 2;
+ }
+
+ int dfw1 = pixelMetric(PM_DefaultFrameWidth, widget) * 2,
+ dfw2 = dfw1 * 2;
+
+ return QRect(wrect.x() + dfw1 + dbw1 + 1,
+ wrect.y() + dfw1 + dbw1 + 1,
+ wrect.width() - dfw2 - dbw2 - 1,
+ wrect.height() - dfw2 - dbw2 - 1);
+ } else
+ return KStyle::subRect(r, widget);
+}
+
+
+int StyleCheckStyle::pixelMetric(PixelMetric m, const QWidget *widget) const
+{
+ switch(m)
+ {
+ // BUTTONS
+ // -------------------------------------------------------------------
+ case PM_ButtonMargin: // Space btw. frame and label
+ return 4;
+
+ case PM_ButtonDefaultIndicator: {
+ return 3;
+ }
+
+ case PM_MenuButtonIndicator: { // Arrow width
+ return 8;
+ }
+
+ // CHECKBOXES / RADIO BUTTONS
+ // -------------------------------------------------------------------
+ case PM_ExclusiveIndicatorWidth: // Radiobutton size
+ case PM_ExclusiveIndicatorHeight:
+ case PM_IndicatorWidth: // Checkbox size
+ case PM_IndicatorHeight: {
+ return 13; // 13x13
+ }
+
+ default:
+ return KStyle::pixelMetric(m, widget);
+ }
+}
+
+
+QSize StyleCheckStyle::sizeFromContents( ContentsType contents,
+ const QWidget* widget,
+ const QSize &contentSize,
+ const QStyleOption& opt ) const
+{
+ switch (contents)
+ {
+ // PUSHBUTTON SIZE
+ // ------------------------------------------------------------------
+ case CT_PushButton: {
+ const QPushButton* button = (const QPushButton*) widget;
+ int w = contentSize.width();
+ int h = contentSize.height();
+ int bm = pixelMetric( PM_ButtonMargin, widget );
+ int fw = pixelMetric( PM_DefaultFrameWidth, widget ) * 2;
+
+ w += bm + fw + 6; // ### Add 6 to make way for bold font.
+ h += bm + fw;
+
+ // Ensure we stick to standard width and heights.
+ if ( button->isDefault() || button->autoDefault() ) {
+ if ( w < 80 && !button->pixmap() )
+ w = 80;
+
+ // Compensate for default indicator
+ int di = pixelMetric( PM_ButtonDefaultIndicator );
+ w += di * 2;
+ h += di * 2;
+ }
+
+ if ( h < 22 )
+ h = 22;
+
+ return QSize( w, h );
+ }
+
+
+ // POPUPMENU ITEM SIZE
+ // -----------------------------------------------------------------
+ case CT_PopupMenuItem: {
+ if ( ! widget || opt.isDefault() )
+ return contentSize;
+
+ const QPopupMenu *popup = (const QPopupMenu *) widget;
+ bool checkable = popup->isCheckable();
+ QMenuItem *mi = opt.menuItem();
+ int maxpmw = opt.maxIconWidth();
+ int w = contentSize.width(), h = contentSize.height();
+
+ if ( mi->custom() ) {
+ w = mi->custom()->sizeHint().width();
+ h = mi->custom()->sizeHint().height();
+ if ( ! mi->custom()->fullSpan() )
+ h += 2*itemVMargin + 2*itemFrame;
+ }
+ else if ( mi->widget() ) {
+ } else if ( mi->isSeparator() ) {
+ w = 10; // Arbitrary
+ h = 2;
+ }
+ else {
+ if ( mi->pixmap() )
+ h = QMAX( h, mi->pixmap()->height() + 2*itemFrame );
+ else {
+ // Ensure that the minimum height for text-only menu items
+ // is the same as the icon size used by KDE.
+ h = QMAX( h, 16 + 2*itemFrame );
+ h = QMAX( h, popup->fontMetrics().height()
+ + 2*itemVMargin + 2*itemFrame );
+ }
+
+ if ( mi->iconSet() )
+ h = QMAX( h, mi->iconSet()->pixmap(
+ QIconSet::Small, QIconSet::Normal).height() +
+ 2 * itemFrame );
+ }
+
+ if ( ! mi->text().isNull() && mi->text().find('\t') >= 0 )
+ w += 12;
+ else if ( mi->popup() )
+ w += 2 * arrowHMargin;
+
+ if ( maxpmw )
+ w += maxpmw + 6;
+ if ( checkable && maxpmw < 20 )
+ w += 20 - maxpmw;
+ if ( checkable || maxpmw > 0 )
+ w += 12;
+
+ w += rightBorder;
+
+ return QSize( w, h );
+ }
+
+
+ default:
+ return KStyle::sizeFromContents( contents, widget, contentSize, opt );
+ }
+}
+
+
+// Fix Qt's wacky image alignment
+QPixmap StyleCheckStyle::stylePixmap(StylePixmap stylepixmap,
+ const QWidget* widget,
+ const QStyleOption& opt) const
+{
+ switch (stylepixmap) {
+ case SP_TitleBarMinButton:
+ return QPixmap((const char **)hc_minimize_xpm);
+ case SP_TitleBarCloseButton:
+ return QPixmap((const char **)hc_close_xpm);
+ default:
+ break;
+ }
+
+ return KStyle::stylePixmap(stylepixmap, widget, opt);
+}
+
+
+bool StyleCheckStyle::eventFilter( QObject *object, QEvent *event )
+{
+ if (KStyle::eventFilter( object, event ))
+ return true;
+
+
+ // Handle push button hover effects.
+ QPushButton* button = dynamic_cast<QPushButton*>(object);
+ if ( button )
+ {
+ if ( (event->type() == QEvent::Enter) &&
+ (button->isEnabled()) ) {
+ hoverWidget = button;
+ button->repaint( false );
+ }
+ else if ( (event->type() == QEvent::Leave) &&
+ (object == hoverWidget) ) {
+ hoverWidget = 0L;
+ button->repaint( false );
+ }
+ }
+
+ if ( event->type() == QEvent::Paint && object->inherits("QLabel") )
+ {
+ QLabel* lb = static_cast<QLabel*>(object);
+ if (lb->pixmap() || lb->picture() || lb->movie() || (lb->textFormat() == Qt::RichText) ||
+ (lb->textFormat() == Qt::AutoText && QStyleSheet::mightBeRichText(lb->text())) )
+ {
+ return false;
+ }
+
+ QPainter p(lb);
+
+ QRect cr = lb->contentsRect();
+
+ int m = lb->indent();
+ if ( m < 0 && lb->frameWidth() ) // no indent, but we do have a frame
+ m = lb->fontMetrics().width('x') / 2 - lb->margin();
+ if ( m > 0 )
+ {
+ int hAlign = QApplication::horizontalAlignment( lb->alignment() );
+ if ( hAlign & AlignLeft )
+ cr.setLeft( cr.left() + m );
+ if ( hAlign & AlignRight )
+ cr.setRight( cr.right() - m );
+ if ( lb->alignment() & AlignTop )
+ cr.setTop( cr.top() + m );
+ if ( lb->alignment() & AlignBottom )
+ cr.setBottom( cr.bottom() - m );
+ }
+
+ QValueVector<StyleGuideViolation> violations;
+
+ if (QCString(lb->name()) == "KJanusWidgetTitleLabel" || lb->font().bold())
+ {
+ // We're a page title
+ violations = checkTitleStyle(lb->text(), LongTitle, lb->buddy() ? HasAccels : NoAccels);
+ }
+ else
+ {
+ // We're probably, maybe, not a page title label
+ // Further checks might be needed, depending on how often this comes up in the wild
+ violations = checkSentenceStyle(lb->text(), lb->buddy() ? BuddiedWidget: BuddylessWidget, lb->buddy() ? HasAccels : NoAccels);
+ }
+
+ if (lb->buddy())
+ {
+ renderViolations(violations, &p, cr,lb->alignment() | ShowPrefix, lb->text() );
+ // ordinary text or pixmap label
+ drawItem( &p, cr, lb->alignment(), lb->colorGroup(), lb->isEnabled(),
+ 0, removedXX(stripAccelViolations(lb->text())) );
+ }
+ else
+ {
+ renderViolations(violations, &p, cr,lb->alignment(), lb->text() );
+
+ // ordinary text or pixmap label
+ drawItem( &p, cr, lb->alignment(), lb->colorGroup(), lb->isEnabled(),
+ 0, removedXX(stripAccelViolations(lb->text())) );
+ }
+
+ p.end();
+
+ return true;
+ }
+
+ if ( event->type() == QEvent::Paint && object->inherits("QGroupBox") )
+ {
+ QPaintEvent * pevent = static_cast<QPaintEvent*>(event);
+ QGroupBox* gb = static_cast<QGroupBox*>(object);
+ bool nestedGroupBox = false;
+ QString stripped_title = removedXX(stripAccelViolations(gb->title()));
+
+ //Walk parent hierarchy to check whether any are groupboxes too..
+ QObject* parent = gb;
+
+ // GCC suggested parentheses around assignment used as truth value
+ // I suggested that it could eat me. GCC won.
+ while ( (parent = parent->parent()) )
+ {
+ if (parent->inherits("QGroupBox"))
+ {
+ nestedGroupBox = true;
+ break;
+ }
+ }
+
+ QPainter paint( gb );
+ if ( stripped_title.length() )
+ {
+ // draw title
+ QFontMetrics fm = paint.fontMetrics();
+ int h = fm.height();
+ int tw = fm.width( stripped_title, stripped_title.length() ) + 2*fm.width(QChar(' '));
+ int x;
+ if ( gb->alignment() & AlignHCenter ) // center alignment
+ x = gb->frameRect().width()/2 - tw/2;
+ else if ( gb->alignment() & AlignRight ) // right alignment
+ x = gb->frameRect().width() - tw - 8;
+ else if ( gb->alignment() & AlignLeft ) // left alignment
+ x = 8;
+ else
+ { // auto align
+ if( QApplication::reverseLayout() )
+ x = gb->frameRect().width() - tw - 8;
+ else
+ x = 8;
+ }
+ QRect r( x, 0, tw, h );
+
+ QValueVector<StyleGuideViolation> violations = checkTitleStyle( gb->title(), ShortTitle, HasAccels );
+
+ renderViolations( violations, &paint, r, AlignCenter | ShowPrefix, gb->title() );
+
+ drawItem(&paint, r, AlignCenter | ShowPrefix, gb->colorGroup(),
+ gb->isEnabled(), 0, stripped_title );
+
+ paint.setClipRegion( pevent->region().subtract( r ) );
+ }
+
+ if (nestedGroupBox)
+ {
+ paint.save();
+ QPen errorPen(Qt::red, 4, QPen::DashDotDotLine);
+ paint.setPen(errorPen);
+ paint.drawRect( gb->frameRect() );
+ paint.restore();
+ }
+ else
+ {
+ drawPrimitive( QStyle::PE_GroupBoxFrame, &paint, gb->frameRect(),
+ gb->colorGroup(), QStyle::Style_Default,
+ QStyleOption(gb->lineWidth(), gb->midLineWidth(),
+ gb->frameShape(), gb->frameShadow()) );
+ }
+ return true; //We already drew the everything
+ }
+
+ return false;
+}
+
+
+void StyleCheckStyle::renderGradient( QPainter* p, const QRect& r,
+ QColor clr, bool, int, int, int, int) const
+{
+ p->fillRect(r, clr);
+ return;
+}
+
+// vim: set noet ts=4 sw=4:
+// kate: indent-width 4; replace-tabs off; tab-width 4; space-indent off;
diff --git a/scheck/scheck.h b/scheck/scheck.h
new file mode 100644
index 00000000..ba91ca01
--- /dev/null
+++ b/scheck/scheck.h
@@ -0,0 +1,173 @@
+/*
+ * $Id$
+ *
+ * KDE3 Style Guide compliance check "Style", v0.0.1
+ * Copyright (C) 2002 Maksim Orlovich <orlovich@cs.rochester.edu>
+ * (C) 2002 Ryan Cumming <bodnar42@phalynx.dhs.org>
+ *
+ *
+ * Based on the KDE3 HighColor Style (version 1.0):
+ * Copyright (C) 2001-2002 Karol Szwed <gallium@kde.org>
+ * (C) 2001-2002 Fredrik Höglund <fredrik@kde.org>
+ *
+ * Drawing routines adapted from the KDE2 HCStyle,
+ * Copyright (C) 2000 Daniel M. Duley <mosfet@kde.org>
+ * (C) 2000 Dirk Mueller <mueller@kde.org>
+ * (C) 2001 Martijn Klingens <klingens@kde.org>
+ *
+ * Portions of code are from the Qt GUI Toolkit, Copyright (C) 1992-2000 Trolltech AS.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the 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; see the file COPYING. If not, write to
+ * the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ *
+ */
+
+#ifndef STYLE_CHECK_H
+#define STYLE_CHECK_H
+
+#include <qbitmap.h>
+#include <qheader.h>
+#include <qintdict.h>
+#include <qvaluevector.h>
+#include <qguardedptr.h>
+
+#include <kdrawutil.h>
+#include <kpixmap.h>
+#include <kstyle.h>
+
+
+class QPopupMenu;
+
+class StyleCheckTitleWatcher: public QObject
+{
+ Q_OBJECT
+
+ public:
+ StyleCheckTitleWatcher();
+ void addWatched(QWidget* w);
+ public slots:
+ void slotCheck();
+ private:
+ QString cleanErrorMarkers(QString in);
+ QValueVector<QGuardedPtr<QWidget> > watched;
+ QValueVector<QString> watchedTitles;
+};
+
+class StyleCheckStyle : public KStyle
+{
+ Q_OBJECT
+
+ public:
+ StyleCheckStyle( );
+ virtual ~StyleCheckStyle();
+
+ void polish( QWidget* widget );
+ void unPolish( QWidget* widget );
+
+
+ void drawKStylePrimitive( KStylePrimitive kpe,
+ QPainter* p,
+ const QWidget* widget,
+ const QRect &r,
+ const QColorGroup &cg,
+ SFlags flags = Style_Default,
+ const QStyleOption& = QStyleOption::Default ) const;
+
+ void drawPrimitive( PrimitiveElement pe,
+ QPainter* p,
+ const QRect &r,
+ const QColorGroup &cg,
+ SFlags flags = Style_Default,
+ const QStyleOption& = QStyleOption::Default ) const;
+
+ void drawControl( ControlElement element,
+ QPainter *p,
+ const QWidget *widget,
+ const QRect &r,
+ const QColorGroup &cg,
+ SFlags flags = Style_Default,
+ const QStyleOption& = QStyleOption::Default ) const;
+
+ void drawControlMask( ControlElement element,
+ QPainter *p,
+ const QWidget *widget,
+ const QRect &r,
+ const QStyleOption& = QStyleOption::Default ) const;
+
+ void drawComplexControl( ComplexControl control,
+ QPainter *p,
+ const QWidget *widget,
+ const QRect &r,
+ const QColorGroup &cg,
+ SFlags flags = Style_Default,
+ SCFlags controls = SC_All,
+ SCFlags active = SC_None,
+ const QStyleOption& = QStyleOption::Default ) const;
+
+ void drawComplexControlMask( ComplexControl control,
+ QPainter *p,
+ const QWidget *widget,
+ const QRect &r,
+ const QStyleOption& = QStyleOption::Default ) const;
+
+ int pixelMetric( PixelMetric m,
+ const QWidget *widget = 0 ) const;
+
+ QSize sizeFromContents( ContentsType contents,
+ const QWidget *widget,
+ const QSize &contentSize,
+ const QStyleOption& opt ) const;
+
+ QRect subRect( SubRect r,
+ const QWidget *widget ) const;
+
+ // Fix Qt3's wacky image positions
+ QPixmap stylePixmap( StylePixmap stylepixmap,
+ const QWidget *widget = 0,
+ const QStyleOption& = QStyleOption::Default ) const;
+
+ protected:
+ bool eventFilter( QObject *object, QEvent *event );
+
+ void renderGradient( QPainter* p,
+ const QRect& r,
+ QColor clr,
+ bool horizontal,
+ int px=0,
+ int py=0,
+ int pwidth=-1,
+ int pheight=-1 ) const;
+
+ QTimer *topLevelAccelManageTimer;
+ QWidget *hoverWidget;
+
+ private slots:
+ void slotAccelManage();
+
+ private:
+ void accelManageRecursive(QWidget* widget);
+
+ StyleCheckTitleWatcher* watcher;
+
+ // Disable copy constructor and = operator
+ StyleCheckStyle( const StyleCheckStyle & );
+ StyleCheckStyle& operator=( const StyleCheckStyle & );
+};
+
+// vim: set noet ts=4 sw=4:
+// kate: indent-width 4; replace-tabs off; tab-width 4; space-indent off;
+
+#endif
diff --git a/scheck/scheck.themerc b/scheck/scheck.themerc
new file mode 100644
index 00000000..24e02251
--- /dev/null
+++ b/scheck/scheck.themerc
@@ -0,0 +1,55 @@
+[Misc]
+Name=Scheck
+Name[cs]=Kontrola stylu
+Name[hi]=शेक
+Name[hu]=Stílusellenőrző
+Name[ta]=Sசரிபாரà¯à®ªà¯à®ªà¯
+Comment=Development style for searching accelerator and style guide conflicts
+Comment[bg]=Стил за Ñ‚ÑŠÑ€Ñене на уÑкорител и конфликти
+Comment[bs]=Stil razvoja za pretragu konflikata akceleratora i konflikata sa stilskim vodiÄem
+Comment[ca]=Estil de desenvolupament per a cercar conflictes amb acceleradors i la guia d'estil
+Comment[cs]=Vývojový styl pro hledání konfliktů v akcelerátorech a textech
+Comment[cy]=Arddull datblygu er chwilio am wrthdaro yn y cyflymyddion a'r canllawiau steil
+Comment[da]=Udviklingsstil til søgning efter accelerator- og stilguide konflikter
+Comment[de]=Entwicklerstil zum Auffinden von Konfikten bei Kurzbefehlen und Gestaltungsrichtlinien
+Comment[el]=Στυλ ανάπτυξης για επιταχυντή αναζήτησης και αντιθέσεις στον οδηγό στυλ
+Comment[es]=Estilo de desarrollo para buscar conflictos de accesos rápidos y guías de estilo
+Comment[et]=Arendusstiil kiirklahvi- ja stiilijuhendi konfliktide leidmiseks
+Comment[eu]=Bizkortzaile eta estilo-gida gatazken bilaketarako garapen estiloa
+Comment[fa]=سبک پیشرÙته برای جستجوی شتاب‌ده Ùˆ ناسازگاریهای راهنمای سبک
+Comment[fi]=Kehitystyyli pikanäppäinten ja tyylioppaan ristiriitojen etsimiseen
+Comment[fr]=Style de développement pour la recherche de conflits d'accélérateurs et guide de style
+Comment[gl]=Estilo de desenvolvemento para procurar conflitos en aceleradores e de guías de estilo
+Comment[hi]=तà¥à¤µà¤°à¤• खोज तथा सà¥à¤Ÿà¤¾à¤‡à¤² गाइड कानà¥à¤«à¥à¤²à¤¿à¤•à¥à¤Ÿà¥à¤¸ के लिठडेवलपमेंट शैली
+Comment[hu]=Fejlesztői stílus a gyorsbillentyűk és a stíluselőírások összeegyeztetéséhez
+Comment[is]=Þróunarstíll til að leita að árekstrum milli flýtilykla og stílaleiðarvísa
+Comment[it]=Stile di sviluppo per cercare conflitti nei tasti acceleratori e negli stili
+Comment[ja]=アクセラレータやスタイルガイドã®è¡çªã‚’探ã™ãŸã‚ã®é–‹ç™ºã‚¹ã‚¿ã‚¤ãƒ«
+Comment[ka]=გáƒáƒœáƒ•áƒ˜áƒ—áƒáƒ áƒ”ბის სტილი ძიების áƒáƒ¥áƒ¡áƒ”ლერáƒáƒ¢áƒáƒ áƒ˜áƒ¡áƒ—ვის დრსტილთრგიდის კáƒáƒœáƒ¤áƒšáƒ˜áƒ¥áƒ¢áƒ”ბი
+Comment[kk]=ÐкÑелератор мен жазу Ñтилінің қайшылықтарын іздейтін жобалау Ñтилі
+Comment[ms]=Gaya pembangunan untuk cari pintasan dan gaya pengurusan konflik
+Comment[nb]=Utviklingsstil for å finne konflikter med retningslinjene og mellom snarveistaster
+Comment[nds]=Stil för't Finnen vun Tastkombinatschoon- un Stilregel-Problemen
+Comment[ne]=गतिबरà¥à¤§à¤• र शैली मारà¥à¤—दरà¥à¤¶à¤¨ दà¥à¤µà¤¨à¥à¤¦ खोजà¥à¤¨à¤•à¤¾ लागि बिकास शैली
+Comment[nl]=Ontwikkelstijl voor het zoeken naar sneltoets- en stijlgidsconflicten
+Comment[nn]=Utviklingsstil for å finna konfliktar med retningslinjene og mellom snarvegstastar
+Comment[pl]=Styl programistyczny do wyszukiwania konfliktów klawiszy skrótu i prowadzenia stylu
+Comment[pt]=Estilo de desenvolvimento para procurar conflitos de aceleradores e de guias de estilo
+Comment[pt_BR]=Estilo de desenvolvimento para procurar conflitos de aceleradores e guias de estilo
+Comment[ru]=Стиль разработки Ð´Ð»Ñ Ð¿Ð¾Ð¸Ñка конфликтов акÑелераторов и ÑÑ‚Ð¸Ð»Ñ Ð½Ð°Ð¿Ð¸ÑÐ°Ð½Ð¸Ñ Ð¿Ñ€Ð¾Ð³Ñ€Ð°Ð¼Ð¼
+Comment[sk]=Vývojársky štýl pre hľadanie konfliktov v akcelerátoroch a štýle
+Comment[sl]=Razvijalski slog za iskanje pospeševalnikov in konfliktov v slogih
+Comment[sr]=Развојни Ñтил за тражење Ñукоба Ñа ÑтилÑким водичем и међу пречицама за брзи приÑтуп.
+Comment[sr@Latn]=Razvojni stil za traženje sukoba sa stilskim vodiÄem i meÄ‘u preÄicama za brzi pristup.
+Comment[sv]=Utvecklingsstil för att leta efter konflikter för snabbtangenter och stilguide
+Comment[ta]=தேடà¯à®¤à®²à¯ à®®à¯à®Ÿà¯à®•à¯à®•à®¿ மறà¯à®±à¯à®®à¯ பாணி வழிகாடà¯à®Ÿà®¿ எதிரà¯à®®à®±à¯ˆà®•à®³à¯à®•à¯à®•à¯ தேவையான மேமà¯à®ªà®¾à®Ÿà¯.
+Comment[tg]=Ðавъи коркард барои ҷуÑтуҷӯи низоии акÑелаторҳо ва навъи навишти барнома
+Comment[tr]=Arama hızlandırıcısı ve biçem kılavuz çelişmeleri için geliştirme biçemi
+Comment[uk]=Стиль розробки Ð´Ð»Ñ Ð¿Ð¾ÑˆÑƒÐºÑƒ конфліктів акÑелераторів та правил Ñтилю
+Comment[zh_CN]=æœç´¢åŠ é€Ÿé”®å’Œæ ·å¼æŒ‡å—冲çªçš„å¼€å‘æ ·å¼
+
+[KDE]
+WidgetStyle=Check
+
+[Desktop Entry]
+Hidden=true
diff --git a/scheck/status.txt b/scheck/status.txt
new file mode 100644
index 00000000..4860b230
--- /dev/null
+++ b/scheck/status.txt
@@ -0,0 +1,41 @@
+TODO/BUG: Handle multiline labels, richtext labels.
+
+Capitalization checking:
+
+Title style -- lower case exception list may have to be expanded
+
+window and dialog box titles - Partially working
+group box / group line labels - Done// ??? What are group line labels?
+button labels - Done.
+tab labels - Done.
+listview column headers - Done
+menu titles / menu items - Done
+derivatives of KCommand - Not a widget.
+combobox items - Not sure of what to do with those below yet
+listbox items
+tree list items
+other heading/title text - Hard to distinguish from regular labels, only works for KJanusWidget titles
+
+Sentence style
+
+edit box labels
+list box labels
+combo box labels
+slider labels
+spin box labels - If all those are regular labels, then done (need to check)
+check box labels - Done
+option button labels - Done
+
+pop-up hint text - TODO
+other non heading/title text - Kind of -- hard to distinguish from title labels.
+
+Other violations
+
+Check for nested groupboxes. - Done, when parenting hierarchy isn't bizzare.
+
+Other todo:
+
+
+Widgets on menubar
+Menu order.
+Augment title checks to check for file - App naming
diff --git a/scripts/Makefile.am b/scripts/Makefile.am
new file mode 100644
index 00000000..3cea8486
--- /dev/null
+++ b/scripts/Makefile.am
@@ -0,0 +1,57 @@
+# sorted by function
+bin_SCRIPTS = \
+ create_makefile create_makefiles adddebug \
+ cheatmake makeobj kde-build build-progress.sh pruneemptydirs \
+ cvsbackport cvsversion cvscheck cvslastchange cvslastlog cvsrevertlast \
+ noncvslist cvs-clean cvs2dist cvsblame cvsforwardport create_cvsignore \
+ colorsvn create_svnignore nonsvnlist svn2dist svnaddcurrentdir svnbackport svnforwardport \
+ svn-clean svngettags svnlastchange svnlastlog svnrevertlast svnversions \
+ svnchangesince findmissingcrystal kdesvn-build \
+ kdedoc qtdoc extractrc extractattr zonetab2pot.py \
+ licensecheck fixkdeincludes fixuifiles includemocs \
+ cxxmetric extend_dmalloc kdekillall kdelnk2desktop.py \
+ package_crystalsvg png2mng.pl kdemangen.pl
+
+# Install syntax highlighting file for KWrite/Kate.
+kdesvn_build_syntaxdir = $(kde_datadir)/katepart/syntax
+kdesvn_build_syntax_DATA = kdesvn-buildrc.xml
+
+# sorted by bin_SCRIPTS reference
+man_MANS = \
+ kde-build.1 \
+ kdesvn-build.1 \
+ cvsversion.1 cvscheck.1 \
+ noncvslist.1 \
+ cvsblame.1 \
+ includemocs.1
+
+CLEANFILES = $(man_MANS)
+
+# sorted alphabetically
+noinst_SCRIPTS = \
+ add_trace.pl alldcop.rb authors2xml.pl check_licenses colorcvs \
+ cvsaddcurrentdir fixheaders kDebug2kdDebug.sh
+
+EXTRA_DIST = completions kde-emacs \
+ colorcvsrc-sample gettext.patch kde-buildrc \
+ kde-devel-emacs.el kde-devel-gdb kde-devel-vim.vim \
+ kde.supp kdesvn-buildrc-sample
+
+# it'd be too good if this worked everywhere ...
+#%.1: %
+# pod2man $< $@
+
+kde-build.1: kde-build
+ pod2man $(srcdir)/kde-build > $@
+kdesvn-build.1: kdesvn-build
+ pod2man $(srcdir)/kdesvn-build > $@
+cvsversion.1: cvsversion
+ pod2man $(srcdir)/cvsversion > $@
+cvscheck.1: cvscheck
+ pod2man $(srcdir)/cvscheck > $@
+noncvslist.1: noncvslist
+ pod2man $(srcdir)/noncvslist > $@
+cvsblame.1: cvsblame
+ pod2man $(srcdir)/cvsblame > $@
+includemocs.1: includemocs
+ pod2man $(srcdir)/includemocs > $@
diff --git a/scripts/README b/scripts/README
new file mode 100644
index 00000000..ca3811e5
--- /dev/null
+++ b/scripts/README
@@ -0,0 +1,186 @@
+
+Stuff in this directory:
+
+=== DEBUGGING SUPPORT
+
+adddebug Modifies the Makefile to add debug info (-g)
+
+add_trace.pl Modifies a source file to add a trace as the first line
+ of every method, using kdDebug, and showing args values.
+
+kDebug2kdDebug.sh Script to convert old KDE debugging statements to their
+ modern equivalents.
+
+extend_dmalloc Script to run gdb on return-addresses
+
+kdekillall Kills the process "kdeinit: <process> with signal <signal>
+
+=== PROGRAMMING SUPPORT
+
+cheatmake Helper for saving time when recompiling, skipping files that
+ haven't changed in a meaningful way (e.g. if you only change
+ a comment...)
+
+check_licenses Old license checker for source files
+ (Use licensecheck instead)
+
+licensecheck Simple license checker for source files
+
+create_makefile Create the Makefile in a directory containing a Makefile.am
+ Saves time compared to re-running configure completely
+
+create_makefiles The recursive version of it - needs create_makefile.
+
+fixheaders Adds header files as it recognices make error output
+
+fixkdeincludes Tries to reduce the number of includes in KDE source files
+
+fixuifiles Fixes up Qt Designer .ui files (version, accels, generated names)
+ To use before any commit of a .ui file.
+
+fixfsfaddr.sed Script for sed to fix old FSF addresses
+
+includemocs Adds missing "#include foobar.moc" lines
+
+kdedoc Open a kde help page in kfm/konqueror
+
+qtdoc Open a qt help page in kfm/konqueror
+
+kde-spellcheck.pl A script to check source code for misspelings and optionally
+ correct them.
+
+=== MODERNIZATION SCRIPTS
+
+rc2kcfgxt.pl Reads an existing KConfig rc file and creates a best-guess
+ version of a KConfigXT XML file.
+
+kdelnk2desktop.py Converts old-style .kdelnk files to their modern .desktop
+ equivalents.
+
+=== USEFUL DATA FOR EXTERNAL PROGRAMS
+
+kde-devel-emacs.el An emacs file that contains many helpful functions and keybindings
+ A must for anyone using [X]Emacs to develop KDE/Qt/C++ applications.
+
+kde-devel-gdb A gdb macro definition file, to e.g. print QStrings from gdb.
+
+kde-devel-vim.vim A vim script that contains many helpful functions and keybindings
+ for vim-using KDE developers.
+
+kde.supp Some valgrind suppressions handy for ignoring stuff we don't
+ care about when valgrinding kde applications
+
+completions/ Contains useful scripts to enhance the auto-complete feature of some shells.
+
+=== INFORMATION EXTRACTION
+
+alldcop.rb Shows an pseudo-XML representation of the DCOP interfaces for
+ currently-running KDE applications. Does not require
+ Korundum.
+
+authors2xml.pl Extract author information from C++ files and print it out
+ in DocBook format as a list
+
+makeobj Script around make which basicly checks if it's in srcdir
+ or in builddir and changes to the right directory for
+ calling /usr/bin/make
+
+extractrc Extract text tags from designer's UI files and XML GUI-RC files
+
+extractattr Same as extractrc, but for use by Scripty.
+
+findmissingcrystal Looks at Crystal icons to find ones which are still
+ unchanged from kdeclassic.
+
+zonetab2pot.py Reads timezone list as its first argument or from
+ /usr/share/zoneinfo/zone.tab, and converts it to a PO file
+ template.
+
+kdemangen.pl Script to use the output from a KDE application's --author and
+ --help-all output to automatically generate a man page for the
+ application.
+
+png2mng.pl Script to convert a series of numbered .png files into a .mng
+ animation.
+
+package_crystalsvg Script to package all svg files recursively from the current
+ directory.
+
+=== SOURCE CONTROL UTILITIES (CVS and Subversion)
+=== All CVS utilities have a corresponding svn version.
+
+colorcvs Colorizes cvs commands.
+
+create_cvsignore Create a .cvsignore file (using the contents of Makefile.am)
+
+cvs-clean Recursively wipes out everything not registered in the CVS
+ server, starting from the current directory.
+
+cvs2dist Create a standalone source distribution tarball for an app
+ in a KDE CVS module.
+
+cvsaddcurrentdir Add all files in and below the current dir to cvs.
+ *.c, *.h, *.C, *.cpp, *.cc are added automatically,
+ *~, *.o, *.so, *.lo, *.la, .libs/, .deps/, .#* are ignored.
+ You will be asked for the remaining files.
+
+cvsblame Bonsai-like cvs annotate
+
+cvscheck Offline check for status of files in a checked-out module.
+
+cvsgettags List the available CVS tags for a given set of files, or
+ recursively for all files and directories. No equivalent for
+ svn.
+
+noncvslist List all files in a checked out CVS module that are unknown to
+ to the CVS server.
+
+cvsversion Display CVS version of a file without connecting to the server.
+
+cxxmetric Counts lines of code, comments and blank space in C and C++
+ source files.
+
+cvslastchange launches "cvs diff -u" to display the last applied changes for a
+ given file. HEAD branch only.
+
+cvslastlog Shows the log associated with the last change on a given file.
+
+cvsremovealltags Remove all tags from a CVS file. Use with care, and for instance
+ after copying a file on the server.
+
+cvsrevertlast Reverts all the files given on the command by one version, then
+ you can commit them.
+
+cvsbackport Backport the last commit in HEAD, to a branch.
+
+cvsforwardport Forwardport the last commit in a branch to HEAD
+
+pruneemptydirs Detects stale source dirs in a CVS tree
+
+cvslastreferenced Goes through the whole history of a file to find all modifications
+ referencing a specific string. It's useful if you want to know
+ when a function has been removed/modified/added to a file if a
+ recent cvs annotate doesn't reference it anymore.
+
+=== KDE BUILD SCRIPTS
+
+kde-build Updates and recompiles a local CVS or Subversion tree
+
+build-progress.sh Displays the progress of kde-build, times needed to complete each
+ step. And sets the titlebar of the terminal to the directory that
+ make is processing
+
+kdesvn-build Updates and recompiles a local Subversion tree.
+
+=== OTHERS
+
+gettext.patch Patch for gettext-0.10.35 to give xgettext the functionality to
+ extract scoped messages
+
+----------------
+Looking to add a script?
+
+Just add it to this README. For easy man pages see the perlpod manpage; the
+man page for many of these tools is in the script itself.
+
+$Id$
diff --git a/scripts/add_trace.pl b/scripts/add_trace.pl
new file mode 100644
index 00000000..bad152c3
--- /dev/null
+++ b/scripts/add_trace.pl
@@ -0,0 +1,124 @@
+## add_trace.pl
+## Script to add a kdDebug() call as the first line of each method
+## including as many parameters as possible (i.e. those supported by kdDebug)
+## Very useful for tracing.
+##
+## Usage: perl -i add_trace.pl myfile.cpp
+##
+## Generates all statement with kdDebug(0) so that it is very easy
+## to remove them afterwards :
+## perl -pi -e 'if (/kdDebug\(0\)/) { $_ = ""; }' myfile.cpp
+## perl -pi -e 'if (/#include <kdebug.h> \/\/ inserted by add_trace/) { $_ = ""; }' myfile.cpp
+##
+## needs perl 5.8+ for the Tie::File module
+##
+## Written by David Faure <faure@kde.org>, licensed under pizzaware.
+## 18/03/2000
+
+use Tie::File;
+
+sub insert_kdebug()
+{
+# inserts a line "include <kdebug.h>" at the beginning of each file
+ for ($i=0;$i<$#ARGV;$i++)
+ {
+ tie @LOG, 'Tie::File', $ARGV[$i];
+ unshift @LOG, '#include <kdebug.h> // inserted by add_trace';
+ }
+}
+
+insert_kdebug();
+$insignature=0;
+while (<>)
+{
+ if ( $insignature )
+ {
+ $statement .= $_;
+ chop;
+ $oneline .= $_;
+ }
+ elsif ( /^[^\s]+\s*[^\s]+::[^\s]+/ && !/typedef\s/ && !/^\s*class\s/ && !/^[^\s]+\s*[^\s]+::[^\s]+.*;/ && !/ *\/\// )
+ # A function declaration starts. A function is not a typedef, not a class, not a command and not a comment.
+ {
+ $insignature = 1;
+ $statement = $_;
+ chop;
+ $oneline = $_;
+ }
+ elsif ( /^\/\/.*/)
+ {
+ # comment
+ # do nothing
+ $insignature = 0;
+ }
+ # [^\s]+ means, one ore more characters that are no spaces
+ elsif ( /^[^\s]+\s*[^\s]+::[^\s]+.*\}/ && !/typedef\s/ && !/^\s*class\s/ )
+ {
+ # declaration and implementation in one line
+ # do nothing
+ $insignature = 0;
+ }
+ if ( $insignature )
+ {
+ if ( /\{/ ) # End of signature
+ {
+ $insignature = 0;
+ $_ = $oneline;
+ #print STDERR "Signature : $_\n";
+ print $statement;
+ $line = " kdDebug(0)";
+ if ( m/([^\*\s]+::[^\s]+)\(/ )
+ {
+ $line = $line . " << \"$1\"";
+ }
+ ## Ok now extract args
+ s/\/\*.*\*\///;
+ s/\s*\/\/.*//; # remove comments
+ s/^.*\([\s]*//; # Remove everything before first '('
+ s/\s*\)\s*:\s+.*$/,/; # Remove any ") : blah", replace with a ','
+ s/\s*\).*\{\s*$/,/; # Remove anything after ')', replace with a ','
+ s/ const[&] / /g;
+ #print STDERR "Args list : $_\n";
+ @args = split( ",", $_ );
+ foreach (@args)
+ {
+ s/^\s*//;
+ s/\s*$//;
+ #print STDERR "Argument: $_\n";
+ ## Pointer ?
+ if ( m/[a-zA-Z0-9_\s]+\*\s*([a-zA-Z0-9_]+)/ ) {
+ $line = $line . " << \" $1=\" << " . $1;
+ }
+ ## int, long ?
+ elsif ( m/^int\s+([a-zA-Z0-9_]+)/ || m/^long\s*([a-zA-Z0-9_]+)/ ) {
+ $line = $line . " << \" $1=\" << " . $1;
+ }
+ ## bool
+ elsif ( m/^bool\s+([a-zA-Z0-9_]+)/ ) {
+ $line = $line . " << \" $1=\" << (" . $1 . " ? \"true\" : \"false\" )";
+ }
+ ## QString and friends
+ elsif ( m/QString[\&\s]+([a-zA-Z0-9_]+)/ || m/QCString[\&\s]*([a-zA-Z0-9_]+)/ ) {
+ $line = $line . " << \" $1=\" << " . $1;
+ }
+ ## KURL
+ elsif ( m/KURL[\&\s]+([a-zA-Z0-9_]+)/ ) {
+ $line = $line . " << \" $1=\" << " . $1 . ".url()";
+ }
+ }
+ $line = $line . " << endl;\n";
+ if ( !m/\}/ ) {print $line;}
+ #print STDERR "Debug call added : $line\n";
+ }
+ }
+ else
+ {
+ # Normal line
+ print;
+ }
+}
+if ( $insignature )
+{
+ print STDERR "Warning, unterminated method signature !! Check the file !\n";
+ print $statement;
+}
diff --git a/scripts/adddebug b/scripts/adddebug
new file mode 100755
index 00000000..8968e89c
--- /dev/null
+++ b/scripts/adddebug
@@ -0,0 +1,63 @@
+#!/bin/sh
+# Modifies the Makefile in the current directory (and optionally its subdirs),
+# - to add debug info (-g3)
+# - optionally (default) remove optimizations (-O[1-9]?)
+# - optionally remove -DNDEBUG and -DNO_DEBUG
+
+mxdp="-maxdepth 1"
+for i in $*; do
+ case $i in
+ -k) keep=1;;
+ -r) mxdp=;;
+ -n) ndebug=1;;
+ *) echo -e "Usage: adddebug [-k] [-r] [-n]\n -k: keep optimizations (removed by default)\n -r: recursive (process all subdirectories)\n -n: compile without NDEBUG and NO_DEBUG being defined (makes kdDebug calls work)"; exit 1;;
+ esac
+done
+
+xpr='s/^((C|CXX|LD)FLAGS[ \t]*=.*)$/\1 -g3/'
+if test -z $keep; then
+ xpr="$xpr;"'s/[\t ]-O[1-9]?\b//g'
+ xpr="$xpr;"'s/[\t ]-march=\S+\b//g'
+fi
+if test -z $ndebug; then
+ xpr="$xpr;"'s/[\t ]-DNDEBUG\b//g'
+ xpr="$xpr;"'s/[\t ]-DNO_DEBUG\b//g'
+fi
+find . $mxdp -name Makefile -exec perl -pi -e "$xpr" {} \;
+
+using_unsermake=
+if head -n 1 Makefile | grep unsermake >/dev/null; then
+ using_unsermake=new
+fi
+if head -n 1 Makefile | grep automake >/dev/null; then
+ using_unsermake=old
+fi
+
+top_builddir=`grep '^top_builddir' Makefile | sed -e 's/^.*= *//'`
+
+if test "$using_unsermake" = "new"; then
+ # the idea: grab the cxxflags from MakeVars, modify them, and write them down
+ # in every Makefile after the line that says .FORWARDS
+ toplevelMakefile=$top_builddir/Makefile
+ if [ -f $toplevelMakefile ]; then
+ # warning this uses sed, so the '?' in the perl regexp above doesn't work here
+ cxxflags=`grep ^CXXFLAGS $toplevelMakefile | sed -e 's/[\t ]-O[1-9]\b//g;s/[\t ]-march=\S+\b//g;s/[\t ]-DNDEBUG\b//g;s/[\t ]-DNO_DEBUG\b//g'`
+ xpr="s/^CXXFLAGS\s*=.*//; if ( /^\.FORWARDS:/) { "'$_'" .= \"\n$cxxflags -g3\"; }"
+ find . $mxdp -name Makefile -exec perl -pi -e "$xpr" {} \;
+ else
+ echo "ERROR: top_builddir is $top_builddir but $makevars not found"
+ fi
+
+elif test "$using_unsermake" = "old"; then
+ # the idea: grab the cxxflags from MakeVars, modify them, and write them down
+ # in every Makefile after the line that includes MakeVars
+ makevars=$top_builddir/MakeVars
+ if [ -f $makevars ]; then
+ # warning this uses sed, so the '?' in the perl regexp above doesn't work here
+ cxxflags=`grep ^CXXFLAGS $makevars | sed -e 's/[\t ]-O[1-9]\b//g;s/[\t ]-march=\S+\b//g;s/[\t ]-DNDEBUG\b//g;s/[\t ]-DNO_DEBUG\b//g'`
+ xpr="s/^CXXFLAGS\s*=.*//; if ( /^include .*MakeVars$/) { "'$_'" .= \"\n$cxxflags -g3\"; }"
+ find . $mxdp -name Makefile -exec perl -pi -e "$xpr" {} \;
+ else
+ echo "ERROR: top_builddir is $top_builddir but $makevars not found"
+ fi
+fi
diff --git a/scripts/alldcop.rb b/scripts/alldcop.rb
new file mode 100755
index 00000000..b15a1fdd
--- /dev/null
+++ b/scripts/alldcop.rb
@@ -0,0 +1,91 @@
+#!/usr/bin/env ruby
+
+module DCOP
+
+ def dump_all_apps
+
+ `dcop`.split(/\n/).each do
+
+ |app|
+
+ DCOP.dump_app(app)
+
+ end
+
+ end
+
+ def dump_app(app)
+
+ print "<app name=\"#{app}\">\n"
+
+ `dcop #{app}`.split(/\n/).each do
+
+ |object|
+
+ DCOP.dump_object(app, object)
+
+ end
+
+ print "</app>\n"
+
+ end
+
+ def dump_object(app, object)
+
+ object.gsub!(/\(default\)/, '')
+ object.strip!
+
+ print " <object name=\"#{object}\">\n" unless object == "(default)"
+
+ `dcop #{app} #{object}`.split(/\n/).each do
+
+ |method|
+
+ DCOP.dump_method(app, object, method)
+
+ end
+
+ print " </object>\n"
+
+ end
+
+ def dump_method(app, object, method)
+
+ return_type, method_name, arg_str = method.split(/[ \(]/, 3)
+
+ arg_str.gsub!(/\)$/, '')
+
+ arg_list = arg_str.split(',')
+
+ print " <method name=\"#{method_name}\" return-type=\"#{return_type}\""
+
+ if arg_list.empty?
+
+ print "/>\n"
+ return
+
+ else
+
+ print ">\n"
+
+ arg_list.each do
+
+ |arg|
+
+ type, name = arg.split
+
+ print " <parameter name=\"#{name}\" type=\"#{type}\"/>\n"
+
+ end
+
+ print " </method>\n"
+
+ end
+
+ end
+
+ module_function :dump_all_apps, :dump_app, :dump_object, :dump_method
+
+end
+
+DCOP.dump_all_apps if __FILE__ == $0
diff --git a/scripts/authors2xml.pl b/scripts/authors2xml.pl
new file mode 100755
index 00000000..c2e34438
--- /dev/null
+++ b/scripts/authors2xml.pl
@@ -0,0 +1,27 @@
+#!/usr/bin/perl -w
+# Extract author information from C++ files
+# and print it out in DocBook format as a list
+# Daniel Naber <daniel.naber@t-online.de>
+# $Id$
+
+my $file = $ARGV[0];
+if( ! $file ) {
+ print "Usage: $0 <file.cpp>\n";
+ exit;
+}
+
+open(IN, $file) || die "Cannot open '$file': $!\n";
+undef $/;
+my $str = (<IN>);
+close(IN);
+
+print "<itemizedlist>\n";
+while( $str =~ m/addAuthor\s*\(\s*"(.*?)",\s*.*?,\s*"(.*?)"/gs ) {
+ my ($name, $email) = ($1, $2);
+ print "<listitem><para>$name <email>$email</email></para></listitem>\n";
+ #print "$name, $email\n";
+}
+print "</itemizedlist>\n";
+
+print STDERR "Warning: maybe you need to fix umlauts manually...\n";
+exit;
diff --git a/scripts/build-progress.sh b/scripts/build-progress.sh
new file mode 100644
index 00000000..05a9dfd7
--- /dev/null
+++ b/scripts/build-progress.sh
@@ -0,0 +1,22 @@
+#!/bin/sh
+
+# This method gives some kind of status message in the title bar of Konsole,
+# xterm, etc.. Thanks have to go to Malte Starostik
+# <malte@kde.org> for the code :-)
+set_title() {
+if ([ "$TERM" = "xterm" ] || [ "$TERM" = "xterm-color" ] || [ "$TERM" = "screen" ]) && tty -s; then
+ echo -ne "\033]0;$1\007"
+fi
+}
+. ./kde-buildrc
+set_title "Progress of kde-build script..."
+
+cd $KDELOGDIR
+while true; do
+ dir=`ls -t | head -n 1 | xargs grep "Entering directory" | tail -n 1 | awk "{print \\$4}" | sed "s'$KDESRCDIR/''g"`
+ set_title "Building $dir"
+ clear
+ grep --no-filename -i "time needed" *build* | \
+ sed "s/\:T/ T/g"
+ sleep 5
+done;
diff --git a/scripts/cheatmake b/scripts/cheatmake
new file mode 100755
index 00000000..9659a6cc
--- /dev/null
+++ b/scripts/cheatmake
@@ -0,0 +1,80 @@
+#!/bin/sh
+# Helper for saving time when recompiling, skipping files that haven't
+# changed in a meaningful way (e.g. if you only change a comment...)
+#
+# LGPL v2, David Faure <david@mandrakesoft.com>
+
+usage()
+{
+ echo "Usage:"
+ echo " $0 hidechange file Hides the fact that file was changed (use with care!)"
+ echo " $0 show Lists what make currently has to rebuild"
+ echo " $0 why file Explains why make must rebuild file"
+ exit 1;
+}
+
+if [ $# -eq 0 ]; then usage; fi
+CDPATH=
+builddir=$PWD
+
+# 'srcdir != builddir' stuff
+if test ! -f Makefile && test -n "$OBJ_SUBDIR"; then
+ builddir=$OBJ_SUBDIR
+else
+ if test ! -f Makefile && test -n "$OBJ_REPLACEMENT"; then
+ builddir=`pwd | sed -e "$OBJ_REPLACEMENT"`
+ fi
+fi
+
+if test ! -f Makefile && test -n "$OBJ_SUBDIR"; then
+ builddir=$OBJ_SUBDIR
+fi
+cd $builddir
+srcdir=`egrep '^srcdir *=' Makefile | sed -e "s#srcdir *= *##"`
+UNSERMAKE=`type -p unsermake`
+using_unsermake=
+if head -n 1 Makefile | grep unsermake >/dev/null; then
+ using_unsermake=new
+fi
+if head -n 1 Makefile | grep automake >/dev/null; then
+ using_unsermake=old
+fi
+
+
+case $1 in
+ hidechange )
+ if [ $# -ne 2 ]; then usage; fi
+ ## TODO: unsermake support (or support in unsermake itself)
+ deps=`make SUBDIRS='' -n | grep '\-o' | sed -e 's/.*-o \([^ ]*\).*/\1/'`;
+ if [ -n "$deps" ]; then
+ oldestdep=`ls -t $deps 2>/dev/null | tail -1`
+ thefile=$2
+ if [ -f $srcdir/$thefile ]; then
+ thefile=$srcdir/$thefile
+ fi
+ echo
+ echo "Setting date of $thefile back in time with:"
+ echo "touch -r $oldestdep $thefile" ; touch -r $oldestdep $thefile
+ fi
+ ;;
+ show )
+ if [ $# -ne 1 ]; then usage; fi
+ if test "$using_unsermake" != "new"; then
+ # Look at the commands that make will issue, and extract "-o output".
+ # The only trouble, with libtool, is that this gives us .libs/foo.o instead of foo.lo
+ make SUBDIRS='' -n | grep '\-o' | sed -e 's/.*-o \([^ ]*\).*/\1/'
+ else
+ # Solve the above problem (when using new-unsermake) by watching the "echo" lines for creating .lo files
+ # separately from the rest of the "-o target" lines (for libs and binaries)
+ # (For libs and bins another way would be to grep for "linking")
+ # The "ls" is for sorting by date
+ $UNSERMAKE -n | perl -e 'while(<>) { if (/by libtool/) { s/.*> //; print; } if (m/-o ([^ ]*)/ && $1!~/\.o$/) { print "$1\n"; } }' | xargs --no-run-if-empty ls -t -1
+ fi
+ ;;
+ why )
+ if [ $# -ne 2 ]; then usage; fi
+ ## TODO: unsermake support (or support in unsermake itself)
+ make SUBDIRS='' -n -d $2 | egrep -e "(newer than target \`$2'|Must)"
+ ;;
+ * ) usage ;;
+esac
diff --git a/scripts/check_licenses b/scripts/check_licenses
new file mode 100755
index 00000000..6accd259
--- /dev/null
+++ b/scripts/check_licenses
@@ -0,0 +1,88 @@
+#!/usr/bin/perl -w
+
+unless (scalar(@ARGV) == 1)
+{
+ die "Usage: check_licenses directory";
+}
+
+my $gpl = 'General Public License';
+my $gp2 = 'This is free software; it comes under the GNU';
+my $gp3 = 'License: GPL with the following explicit clarification';
+my $x11 = 'TORT OR OTHERWISE';
+my $bsd = 'INCLUDING NEGLIGENCE OR OTHERWISE';
+my $gen = 'generated';
+
+sub nameok()
+{
+ my $f = shift;
+
+ if ($f =~ /\.C$/ or $f =~ /\.cpp$/ or $f =~ /\.c$/ or $f =~ /\.h$/)
+ {
+ if ($f =~ /\.cpp$/)
+ {
+ if
+ (
+ $f !~ /meta_unload\.cpp$/
+ and $f !~ /_stub\.cpp/
+ and $f !~ /_skel.cpp/
+ and $f !~ /_closure\.cpp/
+ and $f !~ /moc\.cpp/
+ )
+ {
+ return 1;
+ }
+ else
+ {
+ return 0;
+ }
+ }
+ else
+ {
+ return 1;
+ }
+ }
+ else
+ {
+ return 0;
+ }
+}
+
+sub recursive_check()
+{
+ my $dir = shift;
+
+ opendir (DIR, $dir) or die "Can't open $dir";
+
+ my @filenames = grep { /^[^\.]/ } readdir(DIR);
+
+ for my $f (@filenames)
+ {
+ my $filename = "$dir/$f";
+
+ if (-d $filename)
+ {
+ &recursive_check($filename);
+ }
+ elsif (-f $filename and &nameok($filename))
+ {
+ open (IN, "<$filename") or die "Can't open $filename";
+
+ my $license = "!";
+
+ while (<IN>)
+ {
+ if (/$gpl/) { $license = "G"; last; }
+ if (/$gp2/) { $license = "G"; last; }
+ if (/$gp3/) { $license = "G"; last; }
+ if (/$x11/) { $license = "X"; last; }
+ if (/$bsd/) { $license = "B"; last; }
+ if (/$gen/) { $license = "g"; last; }
+ }
+
+ print "$license $filename\n";
+ }
+ }
+}
+
+&recursive_check($ARGV[0]);
+
diff --git a/scripts/colorcvs b/scripts/colorcvs
new file mode 100755
index 00000000..41c7716d
--- /dev/null
+++ b/scripts/colorcvs
@@ -0,0 +1,175 @@
+#! /usr/bin/env perl
+
+# colorcvs
+#
+# based on colorgcc
+#
+# Requires the ANSIColor module from CPAN.
+#
+# Usage:
+#
+# In a directory that occurs in your PATH _before_ the directory
+# where cvs lives, create a softlink to colorcvs:
+#
+# cvs -> colorcvs
+#
+# That's it. When "cvs" is invoked, colorcvs is run instead.
+#
+# The default settings can be overridden with ~/.colorcvsrc.
+# See the colorcvsrc-sample for more information.
+#
+# Note:
+#
+# colorcvs will only emit color codes if:
+#
+# (1) tts STDOUT is a tty.
+# (2) the value of $TERM is not listed in the "nocolor" option.
+# (3) the cvs command is not a commit or import (as the text editor
+# opened by cvs will often be hampered by colorcvs).
+#
+# If colorcvs colorizes the output, cvs's STDERR will be
+# combined with STDOUT. Otherwise, colorcvs just passes the output from
+# cvs through without modification.
+#
+# Copyright 2002 Neil Stevens <neil@qualityassistant.com>
+#
+# Copyright 1999 Jamie Moyers <jmoyers@geeks.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; version 2 of the License as published
+# by the Free Software Foundation.
+#
+# 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, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
+
+use Term::ANSIColor;
+use IPC::Open3;
+
+sub initDefaults
+{
+ $cvsPath = "/usr/bin/cvs";
+
+ $nocolor{"dumb"} = "true";
+
+ $colors{"P"} = color("reset");
+ $colors{"U"} = color("reset");
+ $colors{"C"} = color("bold red");
+ $colors{"M"} = color("bold yellow");
+ $colors{"A"} = color("cyan");
+ $colors{"R"} = color("cyan");
+ $colors{"?"} = color("bold");
+ $colors{"server"} = color("bold green");
+ $colors{"warning"} = color("bold cyan");
+}
+
+sub loadPreferences
+{
+# Usage: loadPreferences("filename");
+
+ my($filename) = @_;
+
+ open(PREFS, "<$filename") || return;
+
+ while(<PREFS>)
+ {
+ next if (m/^\#.*/); # It's a comment.
+ next if (!m/(.*):\s*(.*)/); # It's not of the form "foo: bar".
+
+ $option = $1;
+ $value = $2;
+
+ if ($option =~ /cvs/)
+ {
+ $cvsPath = $value;
+ }
+ elsif ($option eq "nocolor")
+ {
+ # The nocolor option lists terminal types, separated by
+ # spaces, not to do color on.
+ foreach $termtype (split(/\s+/, $value))
+ {
+ $nocolor{$termtype} = "true";
+ }
+ }
+ else
+ {
+ $colors{$option} = color($value);
+ }
+ }
+ close(PREFS);
+}
+
+#
+# Main program
+#
+
+# Set up default values for colors and cvs path.
+initDefaults();
+
+# Read the configuration file, if there is one.
+$configFile = $ENV{"HOME"} . "/.colorcvsrc";
+if (-f $configFile)
+{
+ loadPreferences($configFile);
+}
+
+# Get the terminal type.
+$terminal = $ENV{"TERM"} || "dumb";
+
+$commit = 0;
+foreach (@ARGV)
+{
+ if(/^ci$/ || /^commit$/ || /^import$/)
+ {
+ $commit = 1;
+ }
+}
+
+# If it's in the list of terminal types not to color, or if
+# we're writing to something that's not a tty, don't do color.
+if (! -t STDOUT || $commit == 1 || $nocolor{$terminal})
+{
+ exec $cvsPath, @ARGV
+ or die("Couldn't exec");
+}
+
+# Keep the pid of the cvs process so we can get its return
+# code and use that as our return code.
+$cvs_pid = open3('<&STDIN', \*CVSOUT, \*CVSOUT, $cvsPath, @ARGV);
+$cvsName = $cvsPath;
+$cvsName =~ s,.*/(.*)$,\1,;
+
+# Colorize the output from the cvs program.
+while(<CVSOUT>)
+{
+ chomp;
+ if (m/^(.) .+/) # S filename
+ {
+ print($colors{$1}, $_, color("reset"));
+ }
+ elsif (m/warning:/) # warning
+ {
+ print($colors{"warning"}, $_, color("reset"));
+ }
+ elsif (m/^$cvsName[^:]*: / || m/^cvs server: /) # server message
+ {
+ print($colors{"server"}, $_, color("reset"));
+ }
+ else # Anything else
+ {
+ # Print normally.
+ print(color("reset"), $_);
+ }
+ print "\n";
+}
+
+# Get the return code of the cvs program and exit with that.
+waitpid($cvs_pid, 0);
+exit ($? >> 8);
diff --git a/scripts/colorcvsrc-sample b/scripts/colorcvsrc-sample
new file mode 100644
index 00000000..3b8eeef9
--- /dev/null
+++ b/scripts/colorcvsrc-sample
@@ -0,0 +1,36 @@
+# Sample .colorcvsrc
+# These are the defaults
+
+# path to the cvs binary
+cvs: /usr/bin/cvs
+
+# Don't do color if our terminal type ($TERM) is one of these.
+# (List all terminal types on one line, seperated by whitespace.)
+nocolor: dumb
+
+# The following groups of attributes may be combined for a given color:
+#
+# clear black on_black
+# reset red on_red
+# bold green on_green
+# underline yellow on_yellow
+# underscore blue on_blue
+# blink magenta on_magenta
+# reverse cyan on_cyan
+# concealed white on_whit
+
+# colors for different types of status messages
+
+P: reset
+U: reset
+C: bold red
+M: bold yellow
+A: cyan
+R: cyan
+?: bold
+
+# this is for server messages
+server: bold green
+
+# this is for warnings
+warning: bold cyan
diff --git a/scripts/colorsvn b/scripts/colorsvn
new file mode 100755
index 00000000..f89e1c2f
--- /dev/null
+++ b/scripts/colorsvn
@@ -0,0 +1,201 @@
+#! /usr/bin/env perl
+
+# colorsvn
+#
+# based on colorgcc
+#
+# Requires the ANSIColor module from CPAN.
+#
+# Usage:
+#
+# In a directory that occurs in your PATH _before_ the directory
+# where svn lives, create a softlink to colorsvn:
+#
+# svn -> colorsvn
+#
+# That's it. When "svn" is invoked, colorsvn is run instead.
+#
+# The default settings can be overridden with ~/.colorcvsrc.
+# See the colorcvsrc-sample for more information.
+#
+# Note:
+#
+# colorsvn will only emit color codes if:
+#
+# (1) tts STDOUT is a tty.
+# (2) the value of $TERM is not listed in the "nocolor" option.
+# (3) the svn command is not a commit or import (as the text editor
+# opened by svn will often be hampered by colorsvn).
+#
+# If colorsvn colorizes the output, svn's STDERR will be
+# combined with STDOUT. Otherwise, colorsvn just passes the output from
+# svn through without modification.
+#
+# Copyright 2002 Neil Stevens <neil@qualityassistant.com>
+#
+# Copyright 1999 Jamie Moyers <jmoyers@geeks.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; version 2 of the License as published
+# by the Free Software Foundation.
+#
+# 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, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
+
+use Term::ANSIColor;
+use IPC::Open3;
+
+sub initDefaults
+{
+ $svnPath = "/usr/bin/svn";
+
+ $nocolor{"dumb"} = "true";
+
+ $colors{"P"} = color("reset");
+ $colors{"U"} = color("reset");
+ $colors{" "} = color("reset");
+ $colors{"C"} = color("bold red");
+ $colors{"M"} = color("bold yellow");
+ $colors{'G'} = color("bold yellow");
+ $colors{"A"} = color("cyan");
+ $colors{"R"} = color("cyan");
+ $colors{"D"} = color("red");
+ $colors{"I"} = color("bold");
+ $colors{"?"} = color("bold");
+ $colors{"!"} = color("bold");
+ $colors{"~"} = color("bold red");
+ $colors{"server"} = color("bold green");
+ $colors{"warning"} = color("bold cyan");
+
+ # Applies when only the properties changed
+ $propcolors{"C"} = color("bold red");
+ $propcolors{"M"} = color("yellow");
+}
+
+sub loadPreferences
+{
+# Usage: loadPreferences("filename");
+
+ my($filename) = @_;
+
+ open(PREFS, "<$filename") || return;
+
+ while(<PREFS>)
+ {
+ next if (m/^\#.*/); # It's a comment.
+ next if (!m/(.*):\s*(.*)/); # It's not of the form "foo: bar".
+
+ $option = $1;
+ $value = $2;
+
+ if ($option =~ /svn/)
+ {
+ $svnPath = $value;
+ }
+ elsif ($option eq "nocolor")
+ {
+ # The nocolor option lists terminal types, separated by
+ # spaces, not to do color on.
+ foreach $termtype (split(/\s+/, $value))
+ {
+ $nocolor{$termtype} = "true";
+ }
+ }
+ elsif ($option =~ /prop (.)/)
+ {
+ # Property color
+ $propcolors{$1} = color($value);
+ }
+ else
+ {
+ $colors{$option} = color($value);
+ }
+ }
+ close(PREFS);
+}
+
+#
+# Main program
+#
+
+# Set up default values for colors and svn path.
+initDefaults();
+
+# Read the configuration file, if there is one.
+$configFile = $ENV{"HOME"} . "/.colorcvsrc";
+if (-f $configFile)
+{
+ loadPreferences($configFile);
+}
+
+# Get the terminal type.
+$terminal = $ENV{"TERM"} || "dumb";
+
+$commit = 0;
+foreach (@ARGV)
+{
+ if(/^ci$/ || /^commit$/ || /^import$/ || /^prop/ || /^p[delsg]$/)
+ {
+ $commit = 1;
+ break;
+ }
+ elsif (! /^-/)
+ {
+ break;
+ }
+}
+
+# If it's in the list of terminal types not to color, or if
+# we're writing to something that's not a tty, don't do color.
+if (! -t STDOUT || $commit == 1 || $nocolor{$terminal})
+{
+ exec $svnPath, @ARGV
+ or die("Couldn't exec");
+}
+
+-f $svnPath or die ("$svnPath not found, add svn=/full/path/to/svn to ~/.colorcvsrc");
+
+# Keep the pid of the svn process so we can get its return
+# code and use that as our return code.
+$svn_pid = open3('<&STDIN', \*SVNOUT, \*SVNOUT, $svnPath, @ARGV);
+$svnName = $svnPath;
+$svnName =~ s,.*/(.*)$,\1,;
+
+# Colorize the output from the svn program.
+while(<SVNOUT>)
+{
+ chomp;
+ if (m/^ (.).+/) # Property changed only
+ {
+ print($propcolors{$1}, $_, color("reset"));
+ }
+ elsif (m/^(.).+/) # S filename
+ {
+ print($colors{$1}, $_, color("reset"));
+ }
+ elsif (m/warning:/) # warning
+ {
+ print($colors{"warning"}, $_, color("reset"));
+ }
+ elsif (m/^$svnName[^:]*: / || m/^svn server: /) # server message
+ {
+ print($colors{"server"}, $_, color("reset"));
+ }
+ else # Anything else
+ {
+ # Print normally.
+ print(color("reset"), $_);
+ }
+ print "\n";
+}
+
+# Get the return code of the svn program and exit with that.
+waitpid($svn_pid, 0);
+exit ($? >> 8);
diff --git a/scripts/completions/bash/dcop b/scripts/completions/bash/dcop
new file mode 100644
index 00000000..675bf6cf
--- /dev/null
+++ b/scripts/completions/bash/dcop
@@ -0,0 +1,52 @@
+# dcop completion
+#
+# Inputs:
+# $1 -- name of the command whose arguments are being completed
+# $2 -- word being completed
+# $3 -- ord preceding the word being completed
+# $COMP_LINE -- current command line
+# $COMP_PONT -- cursor position
+# $COMP_WORDS -- array containing individual words in the current
+# command line
+# $COMP_CWORD -- index into ${COMP_WORDS} of the word containing the
+# current cursor position
+# Output:
+# COMPREPLY array variable contains possible completions
+#
+# dcop syntax:
+# dcop [ application [object [function [arg1] [arg2] [arg3] ... ] ] ]
+#
+_complete_dcop ()
+{
+ local wordlist
+
+ COMPREPLY=()
+ wordlist=""
+
+ if (( $COMP_CWORD == 1 )); then
+ #
+ # Application. This one is easy, just return all names that dcop
+ # gives us.
+ #
+ wordlist=$(dcop)
+ elif (( $COMP_CWORD == 2 )); then
+ #
+ # Object. 'dcop <application>' returns all objects the application
+ # supports plus (default). The parenthesis in (default) should be
+ # omitted when using it as an argument so we need to remove them.
+ #
+ wordlist=$(dcop ${COMP_WORDS[1]} | sed -e "s,(default),default,")
+ elif (( $COMP_CWORD == 3 )); then
+ #
+ # Function. 'dcop <application> <object>' returns functions of the
+ # form 'type functionname(arguments)'. We need to return a list with
+ # the functionnames.
+ #
+ wordlist=$(dcop ${COMP_WORDS[1]} ${COMP_WORDS[2]} | sed -e "s,.* \(.*\)(.*,\1,")
+ fi
+
+ COMPREPLY=( $(compgen -W "$wordlist" "$2") )
+ return 0
+}
+
+complete -F _complete_dcop dcop
diff --git a/scripts/completions/zsh/_dcop b/scripts/completions/zsh/_dcop
new file mode 100644
index 00000000..c3fe6a50
--- /dev/null
+++ b/scripts/completions/zsh/_dcop
@@ -0,0 +1,11 @@
+#compdef dcop
+
+local tmp
+
+if [ CURRENT -eq 4 ]; then
+ tmp=(`$words[1,CURRENT-1] 2>/dev/null | sed -e "s,.* \(.*\)(.*,\1,"`)
+else
+ tmp=(`$words[1,CURRENT-1] 2>/dev/null | sed -e "s,(default),default,"`)
+fi
+
+compadd -a tmp
diff --git a/scripts/completions/zsh/_kcmshell b/scripts/completions/zsh/_kcmshell
new file mode 100644
index 00000000..57f9fc82
--- /dev/null
+++ b/scripts/completions/zsh/_kcmshell
@@ -0,0 +1,16 @@
+#compdef kcmshell=kcmshell appletproxy=appletproxy
+
+local i resource tmp dir flags
+if [ "$service" = "kcmshell" ]; then
+ resource="apps";
+ dir="/Settings";
+ flags=":t:r";
+else
+ resource="data";
+ dir="/kicker/applets";
+ flags=":t"
+fi
+for i in `kde-config --path $resource| sed -e 's/:/ /g'`; do
+ tmp=($i/$dir/**/*.desktop($flags))
+ compadd -a tmp
+done
diff --git a/scripts/completions/zsh/_kdeinit_wrapper b/scripts/completions/zsh/_kdeinit_wrapper
new file mode 100644
index 00000000..a5fd75a0
--- /dev/null
+++ b/scripts/completions/zsh/_kdeinit_wrapper
@@ -0,0 +1,6 @@
+#compdef kdeinit_wrapper
+
+# Yes, this could be improved
+
+_arguments \
+ '*::arguments: _normal'
diff --git a/scripts/completions/zsh/_kdekillall b/scripts/completions/zsh/_kdekillall
new file mode 100644
index 00000000..16ab40dc
--- /dev/null
+++ b/scripts/completions/zsh/_kdekillall
@@ -0,0 +1,8 @@
+#compdef kdekillall
+
+local progs
+progs=(`ps x | grep kdeinit: | grep -v Running | grep -v grep | sed 's,.*kdeinit: ,,' | sed 's, .*,,'`)
+
+_alternative \
+ 'signals:: _signals -p' \
+ 'compadd $progs'
diff --git a/scripts/completions/zsh/_makeobj b/scripts/completions/zsh/_makeobj
new file mode 100644
index 00000000..738a952c
--- /dev/null
+++ b/scripts/completions/zsh/_makeobj
@@ -0,0 +1,30 @@
+#compdef makeobj
+
+local index olddir dir subdir
+
+olddir=$PWD
+index="$words[(I)-[fCI]]"
+if ! ((index)); then
+ if [ ! -f Makefile ]; then
+ if [ -n "$OBJ_SUBDIR" ]; then
+ dir=$PWD
+ subdir=.
+ while [ -n "$dir" -a $dir != '/' -a ! -f $dir/$OBJ_SUBDIR/$subdir/Makefile ]; do
+ dir=$dir(:h)
+ subdir=$dir(:t)/$subdir
+ done
+ if -f $dir/$OBJ_SUBDIR/$subdir/Makefile; then
+ cd $dir/$OBJ_SUBDIR/$subdir
+ fi
+ elif [ -n "$OBJ_REPLACEMENT" ]; then
+ dir=$(echo $PWD | sed -e "$OBJ_REPLACEMENT")
+ if [ -f $dir/Makefile ]; then
+ cd $dir
+ fi
+ fi
+ fi
+fi
+
+_make
+
+cd $olddir
diff --git a/scripts/create_cvsignore b/scripts/create_cvsignore
new file mode 100755
index 00000000..2fb4c23e
--- /dev/null
+++ b/scripts/create_cvsignore
@@ -0,0 +1,55 @@
+#!/bin/sh
+# This script makes a preliminary .cvsignore in the current dir by
+# adding some standard stuff according to Makefile.am.
+# License: GPL
+
+addignore() {
+ test -f .cvsignore || \
+ ( touch .cvsignore && echo "created new .cvsignore" && cvs add .cvsignore )
+ grep -q "^$1\$" .cvsignore || \
+ ( echo "$1" >> .cvsignore && echo "added $1 to .cvsignore" )
+}
+
+recurse=0
+if test $# -eq 1; then
+ if test "$1" = "-r"; then
+ recurse=1
+ fi
+fi
+
+handledir() {
+ (
+ cd $1
+ if test -f Makefile.am; then
+ if test $recurse -eq 1; then
+ echo "Entering $1"
+ fi
+ addignore Makefile
+ addignore Makefile.in
+
+ bins=`perl -p -e 's/\\\s*\n/ /g' Makefile.am | grep _PROGRAMS | sed -e 's/.*=\s*//;s/#.*//;s/\$([^)]*)//'`
+ if test -n "$bins"; then
+ for prog in $bins; do
+ addignore "$prog"
+ done
+ fi
+ else
+ echo "Skipping $1"
+ fi
+ )
+}
+
+
+if test -f Makefile.am; then
+ if test $recurse -eq 1; then
+ find . -type d | grep -v CVS | sed -e 's,/$,,' | \
+ while read dir; do
+ handledir $dir
+ done
+ else
+ handledir .
+ fi
+else
+ echo "No Makefile.am found!"
+fi
+
diff --git a/scripts/create_makefile b/scripts/create_makefile
new file mode 100755
index 00000000..e83b61d7
--- /dev/null
+++ b/scripts/create_makefile
@@ -0,0 +1,110 @@
+#!/usr/bin/env bash
+
+# Create Makefile.in and Makefile in a directory (containing a Makefile.am !)
+# Saves time compared to re-running configure completely
+
+if [ $# -ne 1 ]; then
+ echo "$0 : creates a Makefile from a Makefile.am"
+ echo
+ echo "Usage : $0 relativepath/Makefile"
+ echo "So the argument is the file you want to create."
+ echo
+else
+ if test -f config.status && test -f configure; then
+ :
+ else
+ if test ! -f Makefile && test -n "$OBJ_SUBDIR"; then
+ cd $OBJ_SUBDIR
+ else
+ if test ! -f Makefile && test -n "$OBJ_REPLACEMENT"; then
+ objdir=`pwd | sed -e "$OBJ_REPLACEMENT"`
+ cd $objdir
+ fi
+ fi
+
+ if test ! -f Makefile && test -n "$OBJ_SUBDIR"; then
+ cd $OBJ_SUBDIR
+ fi
+
+ if test ! -f Makefile; then
+ echo "$0: in the current directory there is no Makefile"
+ echo "you will have to run it from the top build dir."
+ echo "if you do not have a Makefile there - rerun configure"
+ exit
+ fi
+
+ fi
+
+ # Handle arg with missing "/Makefile"
+ relpath=$1
+ if test -n "`echo $relpath | grep \/$`"; then
+ relpath=`echo $relpath | sed 's/\/$//'`
+ fi
+ if test -z "`echo $relpath | grep 'Makefile$'`"; then
+ relpath="$relpath/Makefile"
+ fi
+
+ # Strip leading ./, otherwise config.status chokes
+ relpath=`echo "$relpath" | sed -e 's,^\./,,'`
+
+ # Go up to toplevel dir
+ while test ! -f config.status; do
+ relpath="`basename $PWD`/$relpath"
+ cd ..
+ done
+
+ # Find out top_srcdir.
+ top_srcdir=`egrep '^top_srcdir *=' Makefile | sed -e "s#top_srcdir *= *##"`
+
+ (
+ if cd $top_srcdir ; then
+ # Check if unsermake or automake was used to create the toplevel Makefile.in
+ # (the one in $relpath might not exist yet)
+ if test -n "`sed -n -e '1p' Makefile.in | grep unsermake`"; then
+ if test -n "`sed -n -e '1p' Makefile.in | grep automake`"; then # old unsermake
+ if test -z "$UNSERMAKE"; then
+ echo "unsermake was used to build this module, but \$UNSERMAKE isn't set!"
+ exit 1
+ fi
+ $UNSERMAKE $relpath
+ exit 2
+ else # new unsermake
+ UNSERMAKE=`type -p unsermake`
+ if test ! -x "$UNSERMAKE"; then
+ echo 'Makefile was created with unsermake, but there'
+ echo 'is no unsermake in $PATH'
+ exit 1
+ fi
+ $UNSERMAKE -c $relpath
+ fi
+ else
+ # Suck in AUTOCONF/AUTOMAKE detection code
+ UNSERMAKE=no
+ eval `admin/detect-autoconf.pl`
+ /bin/sh admin/missing --run $AUTOMAKE $relpath || exit
+ if test -f admin/am_edit; then perl admin/am_edit $relpath.in ;\
+ else
+ if test -f ../admin/am_edit; then perl ../admin/am_edit $relpath.in ; \
+ fi
+ fi
+ fi
+ fi
+ )
+ case $? in
+ 1)
+ exit 1
+ ;;
+ 2)
+ createrulesfile="true"
+ ;;
+ *)
+ ;;
+ esac
+ if test -f `dirname $relpath`; then
+ rm `dirname $relpath`
+ fi
+ CONFIG_FILES=$relpath CONFIG_HEADERS= ./config.status
+ if test "$createrulesfile" = "true"; then
+ CONFIG_FILES="$relpath.rules $relpath.calls" CONFIG_HEADERS= ./config.status
+ fi
+fi
diff --git a/scripts/create_makefiles b/scripts/create_makefiles
new file mode 100755
index 00000000..955edb90
--- /dev/null
+++ b/scripts/create_makefiles
@@ -0,0 +1,34 @@
+#!/bin/sh
+# Usage : create_makefiles dir
+# (to be run from toplevel directory)
+# Will re-create all Makefiles in dir and its subdirs
+# Needs create_makefile in the path.
+#
+# David Faure <faure@kde.org>
+
+if test ! -f Makefile && test -n "$OBJ_REPLACEMENT"; then
+ objdir=`pwd | sed -e "$OBJ_REPLACEMENT"`
+ cd $objdir
+fi
+
+if test ! -f Makefile && test -n "$OBJ_SUBDIR"; then
+ cd $OBJ_SUBDIR
+fi
+
+if test ! -f Makefile; then
+ echo "$0: in the current directory there is no Makefile"
+ echo "you will have to run it from the top build dir."
+ echo "if you do not have a Makefile there - rerun configure"
+ exit
+fi
+
+srcdir=`egrep '^srcdir *=' Makefile | sed -e "s#srcdir *= *##"`
+
+( cd $srcdir ; find $1 -type d | sed -e 's,/$,,' ) | \
+ while read a; do
+ if test -f "$srcdir/$a/Makefile.am"; then
+ test -d "$a" || mkdir -p "$a"
+ create_makefile "$a/Makefile"
+ fi
+ done
+
diff --git a/scripts/create_svnignore b/scripts/create_svnignore
new file mode 100755
index 00000000..fed482fa
--- /dev/null
+++ b/scripts/create_svnignore
@@ -0,0 +1,82 @@
+#!/bin/sh
+# This script makes a preliminary svn:ignore in the current dir by
+# adding some standard stuff according to Makefile.am.
+# License: GPL
+
+addignore() {
+ if ! test -f svnignore.tmp; then
+ svn pg svn:ignore . | sed -e "s, *,," | grep -v '^$' > svnignore.tmp
+ addedsomething=0
+ fi
+ if ! grep -q "^$1\$" svnignore.tmp; then
+ echo "$1" >> svnignore.tmp && echo "added $1 to svn:ignore"
+ sort -u -o svnignore.tmp svnignore.tmp
+ addedsomething=1
+ fi
+}
+
+recurse=0
+if test $# -eq 1; then
+ if test "$1" = "-r"; then
+ recurse=1
+ fi
+fi
+
+handledir() {
+ (
+ cd $1
+ trap "rm svnignore.tmp" 1 2 15
+ if test -f Makefile.am; then
+ if test $recurse -eq 1; then
+ echo "Entering $1"
+ fi
+ addignore Makefile
+ addignore Makefile.in
+
+ bins=`perl -p -e 's/\\\s*\n/ /g' Makefile.am | egrep '_PROGRAMS|_LTLIBRARIES|_LIBRARIES' | sed -e 's/.*=\s*//;s/#.*//;s/\$([^)]*)//'`
+ if test -n "$bins"; then
+ addignore ".libs"
+ addignore ".deps"
+ for prog in $bins; do
+ addignore "$prog"
+ done
+ fi
+ grep -q LIBRARIES Makefile.am && addignore ".libs"
+ grep -q METASOURCES Makefile.am && addignore "*.moc"
+ fgrep -q .skel Makefile.am && addignore "*.kidl"
+ fgrep -q .skel Makefile.am && addignore "*_skel.c*"
+ fgrep -q .stub Makefile.am && addignore "*_stub.cpp"
+ if fgrep -q .ui Makefile.am; then
+ uis=`ls -1 *.ui 2>/dev/null`
+ for ui in $uis; do
+ addignore ${ui/.ui/.h}
+ addignore ${ui/.ui/.cpp}
+ done
+ fi
+
+ grep -q "^include.*/Doxyfile.am$" Makefile.am && addignore "Doxyfile"
+
+ if test "$addedsomething" = 1; then
+ svn propset svn:ignore -F svnignore.tmp .
+ fi
+ rm svnignore.tmp
+ else
+ echo "Skipping $1"
+ fi
+ )
+}
+
+
+if test -f Makefile.am; then
+ if test $recurse -eq 1; then
+ find . -type d | egrep -v 'CVS|.svn' | sed -e 's,/$,,' | \
+ while read dir; do
+ handledir $dir
+ done
+ else
+ handledir .
+ fi
+else
+ echo "No Makefile.am found!"
+fi
+
diff --git a/scripts/cvs-clean b/scripts/cvs-clean
new file mode 100755
index 00000000..f6ae254d
--- /dev/null
+++ b/scripts/cvs-clean
@@ -0,0 +1,90 @@
+#! /usr/bin/env perl
+
+#
+# This script recursively (beginning with the current directory)
+# wipes out everything not registered in CVS.
+#
+# written by Oswald Buddenhagen <ossi@kde.org>
+# inspired by the "old" cvs-clean target from Makefile.common
+#
+# This file is free software in terms of the modified BSD licence.
+# See kdelibs/doc/common/bsd-license.html for the exact conditions.
+#
+
+use File::Path;
+
+my $dry_run = 0;
+
+sub newfiles()
+{
+ my ($indir, $incvs) = @_;
+ for my $n (keys (%$incvs)) { delete $$indir{$n} }
+ return sort (keys (%$indir));
+}
+
+sub cvsclean()
+{
+ my $dir = shift;
+ my (%dirsdir, %filesdir, %dirscvs, %filescvs);
+ my $dnam = $dir ? $dir : ".";
+ if (!opendir (DIR, $dnam)) {
+ print STDERR "Cannot enter \"".$dnam."\".\n";
+ return;
+ }
+ for my $fn (grep (!/^\.\.?$/, readdir (DIR))) {
+ if (-d $dir.$fn) {
+ $fn eq "CVS" or $dirsdir{$fn} = 1;
+ } else {
+ $filesdir{$fn} = 1;
+ }
+ }
+ closedir (DIR);
+ if (!open (FILE, "<".$dir."CVS/Entries")) {
+ print STDERR "No CVS information in \"".$dnam."\".\n";
+ return;
+ }
+ while (<FILE>) {
+ m%^D/([^/]+)/.*$% and $dirscvs{$1} = 1;
+ m%^/([^/]+)/.*$% and $filescvs{$1} = 1;
+ }
+ close (FILE);
+ if (open (FILE, "<".$dir."CVS/Entries.Log")) {
+ while (<FILE>) {
+ m%^A D/([^/]+)/.*$% and $dirscvs{$1} = 1;
+ m%^A /([^/]+)/.*$% and $filescvs{$1} = 1;
+ m%^R D/([^/]+)/.*$% and delete $dirscvs{$1};
+ m%^R /([^/]+)/.*$% and delete $filescvs{$1};
+ }
+ close (FILE);
+ }
+ for my $fn (&newfiles (\%filesdir, \%filescvs)) {
+ print ("F ".$dir.$fn."\n");
+ unlink($dir.$fn) unless $dry_run;
+ }
+ for my $fn (&newfiles (\%dirsdir, \%dirscvs)) {
+ print ("D ".$dir.$fn."\n");
+ rmtree($dir.$fn, 0, 0) unless $dry_run;
+ }
+ for my $fn (sort (keys (%dirscvs))) {
+ &cvsclean ($dir.$fn."/");
+ }
+}
+
+my $usage =
+ "usage: cvs-clean [options]\n".
+ " --help | -h print usage information\n".
+ " --dry-run | -n print intended actions; don't change filesystem\n";
+
+foreach my $arg (@ARGV) {
+ if ($arg eq '-h' || $arg eq '--help') {
+ print $usage;
+ exit (0);
+ } elsif ($arg eq '-n' || $arg eq '--dry-run') {
+ $dry_run = 1;
+ } else {
+ print STDERR "cvs-clean: unknown argument '".$arg."'\n\n".$usage;
+ exit (1);
+ }
+}
+
+&cvsclean ("");
diff --git a/scripts/cvs2dist b/scripts/cvs2dist
new file mode 100755
index 00000000..dba8a4d9
--- /dev/null
+++ b/scripts/cvs2dist
@@ -0,0 +1,626 @@
+#! /usr/bin/env bash
+
+# This is cvs2dist
+# Webpage: http://www.katzbrown.com/shiritsu/programming/cvs2dist/
+# Newest version is always available there!
+# Please report bugs to <jason@katzbrown.com>.
+
+# Original author (of cvs2pack.sh) was Sebastian Stein <seb.stein@hpfsc.de>
+# Heavy, heavy modifications by Jason Katz-Brown <jason@katzbrown.com>
+# Some modifications for i18n inclusion by Dominique Devriese <devriese@kde.org>
+# Added --no-i18n-lang and --replace-files by Michael Buesch <mbuesch@freenet.de>
+# License: GPL (http://www.gnu.org/)
+# Last modification: 2004/10/13
+
+cmdline="$@"
+
+returndir=`pwd`
+override="README ChangeLog INSTALL AUTHORS AUTHOR COPYING COPYING.LIB TODO"
+remove="config.cache config.log config.status Makefile configure inst-apps CVS acinclude.m4 aclocal.m4 config.h config.h.bot config.h.in configure.files libtool stamp-h stamp-h.in stamp-h1 subdirs *.moc *.la .libs .deps .cvsignore autom4te.cache {arch} .arch-ids"
+toplevelremove="configure.in.bot"
+# whitespace seperated list of languages to never include.
+always_skip_languages="xx"
+
+
+exit_cleanup()
+{
+ echo -n "Cleaning up... "
+ if [ -d $temp_dir ]; then
+ test -z "$debug" && rm -Rf $temp_dir
+ fi
+ echo "done."
+}
+
+trap "exit_cleanup; exit 1" SIGINT SIGTERM
+
+test -e ~/.cvs2distrc && extraoptions=`cat ~/.cvs2distrc`
+
+# getopt usage from the getopt bash example
+# --log has optional argument
+TEMP=`getopt \
+-o v:n:r:e:a:B:dhmbgol \
+--long log::,version:,name:,required-header:,required-header-error-message:,make-unpackaged,help,no-bz2,no-bzip2,no-gzip,only-directory,remove-hidden,admin-dir:,branch:,no-i18n,no-i18n-lang:,cvs-root:,debug,replace-files: \
+-n cvs2dist -- $extraoptions "$@"`
+
+if [ $? != 0 ]; then
+ echo "Aborted." >&2
+ exit 1
+fi
+
+eval set -- "$TEMP"
+
+log="/dev/null"
+calclog=0
+doi18n="yes"
+noi18nlang=""
+replace_files=""
+cvsroot=""
+debug=""
+
+while true; do
+ case "$1" in
+ -v|--version) version=$2; shift 2 ;;
+ -n|--name) name=$2; shift 2 ;;
+ -a|--admin-dir) admindir=$2;
+ if [ `echo $admindir | sed -e 's#^/##'` = $admindir ]; then
+ admindir="`pwd`/$admindir"
+ fi
+ shift 2 ;;
+ -B|--branch) branch="-r$2"; shift 2;;
+ --debug) debug="non-empty"; shift 1 ;;
+ --cvs-root) cvsroot="$2"; shift 2 ;;
+ -r|--required-header) requiredheader=$2; shift 2 ;;
+ --no-i18n) doi18n="no"; shift 1 ;;
+ --no-i18n-lang) noi18nlang="$2"; shift 2 ;;
+ -e|--required-header-error-message) requiredmsg=$2; shift 2 ;;
+ -m|--make-unpackaged) leavedir="non-empty"; shift 1 ;;
+ -h|--help) showhelp="non-empty"; shift 1 ;;
+ -b|--no-bz2|--no-bzip2) nobzip2="non-empty"; shift 1 ;;
+ -o|--only-directory)
+ nogzip="non-empty"
+ nobzip2="non-empty"
+ leavedir="non-empty"
+ shift 1 ;;
+ -g|--no-gzip) nogzip="non-empty"; shift 1 ;;
+ -d|--remove-hidden) removehidden="non-empty"; shift 1 ;;
+ -l) calclog=1; shift 1 ;;
+ --log)
+ case "$2" in
+ # no-argument case
+ "") calclog=1; shift 2 ;;
+ # something, should be a file
+ *) log=$2
+ origlog=$log
+ if [ `echo $log | sed -e 's#^/##'` = $log ]; then
+ log="`pwd`/$log"
+ fi
+
+ shift 2 ;;
+ esac ;;
+ --replace-files) replace_files="$2"; shift 2 ;;
+ --) shift
+ break ;;
+ *) echo "Aborted."
+ exit 1 ;;
+ esac
+done
+
+count=0
+for arg do
+ test $count = 0 && module=$arg
+ test $count = 1 && directory=$arg
+
+ if [ $count -ge 2 ]; then
+ modarg=$arg
+ if [ `echo $modarg | sed -e 's#^/##'` = $modarg ]; then
+ modarg="`pwd`/$modarg"
+ fi
+ addfiles="$addfiles $modarg"
+ fi
+
+ let count count++
+done
+
+# test if a module and directory name was given
+if [ ! -z $showhelp ] || [ -z $module ] || [ -z $directory ]; then
+ echo "Usage: cvs2dist module directory [options] [addfile1] [addfile2] ..."
+ echo ""
+ echo " -n --name <name>"
+ echo " -v --version <version>"
+ echo " --cvs-root <root> the value to use as cvs root"
+ echo " variable. It is not necessary if you use --no-i18n."
+ echo " if this is not given, it is taken from the CVSROOT "
+ echo " environment variable."
+ echo " --admin-dir <dir> admin/ location (default is module/admin)"
+ echo " (symbolic links are OK.)"
+ echo " -B --branch <branch> use branch for i18n checkouts."
+ echo " --no-i18n don't try to automatically checkout the translations from cvs."
+ echo " --no-i18n-lang <languages> exclude all languages in the given comma"
+ echo " seperated list. example:"
+ echo " --no-i18n-lang uk,de,en_GB"
+ echo " --log=<logfile> If logfile unspecified, default file is used."
+ echo " (The '=' is essential and may not be ommited"
+ echo " when specifying the logfile.)"
+ echo " -l Log to default logfile."
+ echo " -m --make-unpackaged Also makes an unpacked distribution"
+ echo " in the current directory."
+ echo " -g --no-gzip Do not create gzip package."
+ echo " -b --no-bz2 Do not create bzip2 package."
+ echo " --no-bzip2 Alias for the above."
+ echo " -o --only-directory Alias for -mbg (no packages, only a directory.)"
+ echo " -r --required-header <header> Errors if header is not installed."
+ echo " -e --required-header-error-message <message>"
+ echo " Error message for above."
+ echo " -d --remove-hidden Remove hidden files/directories from packages"
+ echo " --replace-files <file-pair-list>"
+ echo " <file-pair-list> is a comma separated list of file pairs"
+ echo " which should be replaced in the final distribution package."
+ echo " Each element of a pair is separated by an @"
+ echo -n " Example: --replace-files take_this_file@and_move_it_here,"
+ echo "configure.in.bot.dist@configure.in.bot"
+ echo " The filenames are all relative to your package root."
+ echo " Please be careful! Try to avoid the usage of .. in the path. It"
+ echo " may break stuff! There can not be blank characters in the paths."
+ echo " -h --help Show this help"
+ echo ""
+ echo " Name defaults to the last part of the directory."
+ echo "By default, creates name[-version].tar.gz if gzip is installed"
+ echo "and/or name[-version].tar.bz2 if bzip2 is installed in the current"
+ echo "directory. Removes all temporary files it creates. Produces"
+ echo "tarballs that are standard distribution tarballs with a"
+ echo "configure script."
+ echo " Unless --no-i18n is given, it automatically tries to check out "
+ echo "strings and documentation translation from cvs."
+ echo " Arguments after the second are added to the toplevel directory"
+ echo "in the package. Short options can be combined, eg -dm to create"
+ echo "a directory and remove hidden files. ~/.cvs2distrc is added to"
+ echo "the beginning of command line arguments if it exists."
+ echo " '--' signifies the end of options."
+ echo ""
+ echo "Example: cvs2dist /sources/kdegames kolf/objects/picture \\"
+ echo " -n kolf-picture -v 0.9 -r \"kolf/game.h\" \\"
+ echo " --log ~/tmp/extra-file"
+ echo ""
+ echo " Creates packages of the kolf picture plugin, naming the"
+ echo " packages kolf-picture-0.9 and logging the process. For configure"
+ echo " to succeed, kolf/game.h must be installed or an error will occur."
+ echo " ~/tmp/extra-file is added to the packages."
+ echo ""
+ echo "Webpage: http://www.katzbrown.com/shiritsu/programming/cvs2dist/"
+ echo "Authors: Jason Katz-Brown <jason@katzbrown.com>,"
+ echo " Sebastian Stein <seb.stein@hpfsc.de>,"
+ echo " Dominique Devriese <devriese@kde.org>"
+ exit 1
+fi
+
+# expand module
+module=`echo $module | sed -e 's#/$##'`
+if [ `echo $module | sed -e 's#^/##'` = $module ]; then
+ module="`pwd`/$module"
+fi
+
+# test if the given module is a directory
+test -d $module
+if [ $? -ne 0 ]; then
+ echo "$module is not a directory."
+ echo "Aborted."
+ exit 1
+fi
+
+# go to our module
+cd $module
+
+directory=`echo $directory | sed -e 's#^/##'`
+
+if [ -z $name ]; then
+ name=$directory
+ # get rid of trailing slash
+ name=`echo $name | sed -e 's#/$##'`
+ # leading slash
+ name=`echo $name | sed -e 's#^/##'`
+
+ if [ `echo $name | sed -e 's#/##'` != $name ]; then
+ name=`echo $name | sed -e 's#^.*/##'`
+ fi
+fi
+
+test $calclog = 1 && log="$returndir/cvs2dist-$name.log" && origlog="cvs2dist-$name.log"
+
+# test if the given name is a sub-directory
+if [ ! -d "$directory" ]; then
+ echo "$directory is not a sub-directory of $module."
+ echo "Aborted."
+ exit 1
+fi
+
+test $log != "/dev/null" && echo "Logging to $log."
+
+echo "cvs2dist log on "`date` > $log
+echo "http://katzbrown.com/shiritsu/programming/cvs2dist/" >> $log
+echo -n "Module: $module; Directory: $directory; Name: $name; " >> $log
+if [ -z $version ]; then
+ echo "Version unspecified." >> $log
+else
+ echo "Version $version." >> $log
+fi
+echo $cmdline >> $log
+echo "--------" >> $log
+
+if [ -z $version ]; then
+ filename=$name
+else
+ filename="$name-$version"
+fi
+
+if [ -z $cvsroot ]; then
+ cvsroot="$CVSROOT";
+fi
+if [ $doi18n = "yes" ]; then
+ # a little warning...
+ echo "Will try to fetch i18n files from KDE's CVS."
+ echo "If this doesn't work, use --no-i18n."
+
+ if [ -z "$cvsroot" ]; then
+ echo "No cvs root specified, CVSROOT env var is empty, " >> $log
+ echo "and --no-i18n option is not given.." >> $log
+ echo "Using anonymous cvs.." >> $log
+ cvsroot=":pserver:anonymous@anoncvs.kde.org:/home/kde"
+ # append an entry to ~/.cvspass so the user will not be asked
+ # for a pwd. Thanks to coolo for the idea..
+ if ! grep "anoncvs.kde.org" ~/.cvspass >/dev/null 2>&1; then
+ echo "/1 :pserver:anonymous@anoncvs.kde.org:2401/home/kde A" >> ~/.cvspass
+ fi
+ fi
+fi
+
+# the temporary directory
+temp_dir="$module/cvs2dist-tmp"
+temp_dist="$temp_dir/$filename"
+
+echo "Temporary directory is $temp_dir." >> $log
+
+# make a temporary directory
+test -d $temp_dir && rm -Rf $temp_dir
+
+mkdir -p $temp_dist
+
+# check if we were able to create temp_dir
+test -d $temp_dist
+if [ $? -ne 0 ]; then
+ echo "Could not create temporary directory $temp_dist."
+ echo "$temp_dist could not be created." >> $log
+ echo "Aborted."
+ exit 1
+fi
+
+test -z "$requiredmsg" && requiredmsg="Install development package needed first! $requiredheader, for one, is missing."
+
+### configure.in.in
+if [ ! -z $requiredheader ]; then
+ naiyou="KDE_CHECK_HEADER(
+$requiredheader,
+[],
+[AC_MSG_ERROR(\"$requiredmsg\")]
+)"
+ echo $naiyou > $temp_dir/configure.in.in
+ echo "configure.in.in contents: " >> $log
+ echo "--------" >> $log
+ echo $naiyou >> $log
+ appaddfiles="$appaddfiles $temp_dir/configure.in.in"
+fi
+
+# copy all files of the module to temp_dir/name
+cp -RL $module/$directory $temp_dist/$name
+
+echo "cp -R $module/$directory $temp_dist/$name" >> $log
+
+modulename="$module"
+# get rid of trailing slash
+modulename=`echo $modulename | sed -e 's#/$##'`
+# get the last part
+modulename=`echo $modulename | sed -e 's#^.*/##'`
+
+remove="$remove $modulename.lsm"
+
+# we check out kde-i18n/subdirs in temp_dir/kde-i18n..
+if [ $doi18n = "yes" ]; then
+ pushd $temp_dir
+ echo "cvs co kde-i18n/subdirs" >> $log
+ cvs -z4 -q -d "$cvsroot" co $branch -P kde-i18n/subdirs > /dev/null 2>&1
+ i18nlangs_tmp="$(cat kde-i18n/subdirs)"
+ skiplist="`echo $noi18nlang | sed -e 's/,/ /g'`"
+ skiplist="$skiplist $always_skip_languages"
+ for lang in $i18nlangs_tmp; do
+ must_skip="no"
+ for skip in $skiplist; do
+ if [ "$lang" = "$skip" ]; then
+ must_skip="yes"
+ fi
+ done
+ if [ "$must_skip" = "no" ]; then
+ i18nlangs="$i18nlangs $lang"
+ fi
+ done
+ echo "available languages: $i18nlangs" >> $log
+ popd
+fi
+
+# if a handbook exists, we also copy it to the directory
+if [ -d $module/doc/$name ]; then
+ mkdir -p $temp_dist/doc/$name
+ cp -Rf $module/doc/$name $temp_dist/doc
+ find $module/doc/ -maxdepth 1 ! -xtype d | xargs --replace={} cp {} $temp_dist/doc
+
+ if [ $doi18n = "yes" ]; then
+ pushd $temp_dir
+ for lang in $i18nlangs; do
+ test -d $temp_dist/doc/$lang && rm -Rf $temp_dist/doc/$lang
+ docdirname="kde-i18n/$lang/docs/$modulename/$name"
+ echo "cvs co $docdirname" >> $log
+ cvs -z4 -q -d "$cvsroot" co $branch -P "$docdirname" > /dev/null 2>&1
+ if [ ! -d "$docdirname" ]; then
+ echo "$lang's $name documentation does not exist." >> $log
+ continue
+ fi
+ echo -n "Copying $lang's $name documentation over... "
+ cp -R $docdirname $temp_dist/doc/$lang
+ # we don't want KDE_DOCS = AUTO, cause that makes the
+ # build system assume that the name of the app is the
+ # same as the name of the dir the Makefile.am is in.
+ # Instead, we explicitly pass the name..
+ echo "KDE_LANG=$lang" > $temp_dist/doc/$lang/Makefile.am
+ echo "KDE_DOCS=$name" >> $temp_dist/doc/$lang/Makefile.am
+ echo "done."
+ echo "$lang documentation included." >> $log
+ done
+ popd
+ fi
+fi
+
+# clean up doc directory
+if [ -d $temp_dist/doc/$name ]; then
+ pushd $temp_dist/doc/$name
+ echo -n "make clean in $temp_dist/doc/$name/... "
+ echo >> $log
+ echo "make clean in $temp_dist/doc/$name/" >> $log
+ make clean >> $log
+ echo "--------" >> $log
+ echo "done."
+ popd
+fi
+
+if [ $doi18n = "yes" ]; then
+ test -d $temp_dist/po && rm -Rf $temp_dist/po
+ mkdir $temp_dist/po
+
+ pushd $temp_dir/
+ for lang in $i18nlangs; do
+ pofilename="kde-i18n/$lang/messages/$modulename/$name.po";
+ echo "cvs co $pofilename" >> $log
+ cvs -z4 -q -d "$cvsroot" co $branch -P "$pofilename" > /dev/null 2>&1
+ if [ ! -f "$pofilename" ]; then
+ echo "$lang's $name.po does not exist." >> $log
+ continue
+ fi
+
+ dest=$temp_dist/po/$lang
+ mkdir $dest
+ echo -n "Copying $lang's $name.po over... "
+ echo "$lang's $name.po file included." >> $log
+ cp $pofilename $dest
+ echo "done."
+
+ echo "KDE_LANG = $lang
+SUBDIRS = \$(AUTODIRS)
+POFILES = AUTO" > $dest/Makefile.am
+
+ subdirs="non_empty"
+ done
+
+ if [ -z "$subdirs" ]; then
+ rm -Rf $temp_dist/po
+ else
+ echo "SUBDIRS = \$(AUTODIRS)" > $temp_dist/po/Makefile.am
+ fi
+fi
+
+# copy the admin directory
+if [ -z $admindir ]; then
+ cp -pRL $module/admin $temp_dist
+ echo "cp -pRL $module/admin $temp_dist" >> $log
+else
+ cp -pRL $admindir $temp_dist
+ echo "cp -pRL $admindir $temp_dist" >> $log
+fi
+
+# and all files from the base dir, except directories
+echo "Copying over files from the module directory:" >> $log
+find $module ! -xtype d -maxdepth 1 | xargs --verbose --replace={} cp {} $temp_dist 2>> $log
+echo "--------" >> $log
+
+# we now enter the temp_dist and delete all unwanted files
+# and add wanted files
+cd $temp_dist
+
+# override top-level files
+echo "Override files: " >> $log
+for file in $override; do
+ test -e $temp_dist/$name/$file && mv $temp_dist/$name/$file . && echo "mv $temp_dist/$name/$file ." >> $log
+done
+
+test ! -z "$addfiles" && echo "Addfiles: " >> $log
+for file in $addfiles; do
+ test -e $file && cp -R $file $temp_dist && echo "cp -R $file $temp_dist" >> $log
+done
+
+test ! -z "$appaddfiles" && echo "Application addfiles: " >> $log
+for file in $appaddfiles; do
+ test -e $file && cp -R $file $temp_dist/$name/ && echo "cp -R $file $temp_dist/$name/" >> $log
+done
+
+echo "--------" >> $log
+
+# replace all user requested files
+if [ -n "$replace_files" ]; then
+ echo "Replace user requested files" >> $log
+ pair_list="`echo $replace_files | sed -e 's/,/ /g'`"
+ for pair in $pair_list; do
+ pair_tmp="`echo $pair | sed -e 's/@/ /g'`"
+ from="`echo $pair_tmp | awk '//{print $1}'`"
+ to="`echo $pair_tmp | awk '//{print $2}'`"
+ if [ -z "$from" ] || [ -z "$to" ]; then
+ echo "bogus pair \"$from@$to\"" >> $log
+ continue
+ fi
+ echo "Replacing \"$to\" by \"$from\"" >> $log
+ from_path="$temp_dist/$name/$from"
+ to_path="$temp_dist/$name/$to"
+ if [ ! -f "$from_path" ]; then
+ echo "$from_path does not exist!" >> $log
+ echo ""
+ echo "Warning: \"$from\" does not exist!"
+ echo -n "Please enter the path in --replace-files relative "
+ echo "to the package root of your project."
+ echo "Your package root is: \"$module/$directory\""
+ echo ""
+ continue
+ fi
+ rm -f "$to_path" && \
+ mv "$from_path" "$to_path"
+ if [ $? -ne 0 ]; then
+ echo -n "Moving \"$from_path\" failed! " >> $log
+ echo -n "This should not happen." >> $log
+ if [ -f "$to_path" ]; then
+ echo ""
+ else
+ echo " No \"$to\" will exist in the archive!" >> $log
+ fi
+ fi
+ done
+ echo "--------" >> $log
+fi
+
+# version file, if it doesn't exist
+test ! -z $version && test ! -e VERSION && echo "$name version $version" > VERSION
+
+cd $temp_dist/$name
+echo "make clean in $temp_dist/$name/:" >> $log
+echo "" >> $log
+echo -n "make clean in $temp_dist/$name/... "
+make clean >> $log
+echo "--------" >> $log
+echo "done."
+
+cd $temp_dist
+
+# remove files
+echo "Remove files: " >> $log
+for file in $remove; do
+ find . -name $file | xargs rm -Rf
+ echo "find . -name $file | xargs rm -Rf" >> $log
+done
+
+# remove more files
+echo "Remove toplevel files: " >> $log
+for file in $toplevelremove; do
+ test -e $file && rm -Rf $file && echo "rm -Rf $file" >> $log
+done
+unset file
+
+# remove hidden files
+test ! -z $removehidden && echo "Remove hidden files: " >> $log && find $temp_dist -name ".*" -and ! -name "." | xargs --verbose rm -Rf 2>> $log
+
+echo "--------" >> $log
+
+cd $temp_dist
+
+# create the configure script
+# working directory is $temp_dist
+echo "make -f Makefile.cvs in $temp_dist/:" >> $log
+echo "" >> $log
+echo -n "make -f Makefile.cvs in $temp_dist/... "
+make -f Makefile.cvs >> $log 2>> $log
+echo "rm Makefile.cvs" >> $log
+rm -f Makefile.cvs
+echo "rm autom4te.cache" >> $log
+rm -Rf autom4te.cache
+echo "--------" >> $log
+echo "done."
+
+echo "Directory will be $filename."
+
+# play around with our tar file in temp_dir
+cd $temp_dir
+
+if [ ! -z $leavedir ]; then
+ test -e $returndir/$filename && rm -Rf $returndir/$filename
+ cp -R $filename $returndir
+fi
+
+# make a tar of temp_dist
+if [ -z $nogzip ] || [ -z $nobzip2 ]; then
+ echo -n "Tarring... "
+ echo "tar cf $filename.tar $filename" >> $log
+ tar cf $filename.tar $filename >> $log
+ echo "done."
+fi
+
+if [ -z $nogzip ] && [ ! -z `which gzip 2> /dev/null` ]; then
+ cp $filename.tar $filename.tar.tmp
+ echo -n "running gzip... "
+ echo "gzip $filename.tar" >> $log
+ gzip $filename.tar
+ echo "done."
+ mv $filename.tar.tmp $filename.tar
+ mv $filename.tar.gz $returndir
+ echo "mv $filename.tar.gz $returndir" >> $log
+fi
+if [ -z $nobzip2 ] && [ ! -z `which bzip2 2> /dev/null` ]; then
+ echo -n "running bzip2... "
+ echo "bzip2 $filename.tar" >> $log
+ bzip2 $filename.tar
+ echo "done."
+ mv $filename.tar.bz2 $returndir
+ echo "mv $filename.tar.bz2 $returndir" >> $log
+fi
+
+test -e $filename.tar && rm -f $filename.tar
+
+# cleanup all tempoaries
+exit_cleanup
+
+cd $returndir
+
+test -z $leavedir && test ! -z $nobzip2 && test ! -z $nogzip && echo "Finished - no created files." && exit 1
+
+# cool, everything went ok!
+if [ -z $leavedir ]; then
+ echo "Finished. Created packages:"
+else
+ if [ -z $nogzip ] || [ -z $nobzip2 ]; then
+ echo "Finished. Created packages/directories:"
+ else
+ echo "Finished. Created directory:"
+ fi
+fi
+
+echo "--------" >> $log
+echo "Done: " >> $log
+echo "Files are in `pwd`." >> $log
+
+if [ ! -z $leavedir ] && [ -d $filename ]; then
+ ls -ld $filename
+ ls -ld $filename >> $log
+fi
+if [ -z $nogzip ] && [ -e $filename.tar.gz ]; then
+ ls -l $filename.tar.gz
+ ls -l $filename.tar.gz >> $log
+fi
+if [ -z $nobzip2 ] && [ -e $filename.tar.bz2 ]; then
+ ls -l $filename.tar.bz2
+ ls -l $filename.tar.bz2 >> $log
+fi
+if [ $log != "/dev/null" ]; then
+ echo "Created log:"
+ ls -l $origlog
+fi
diff --git a/scripts/cvsaddcurrentdir b/scripts/cvsaddcurrentdir
new file mode 100755
index 00000000..56185f27
--- /dev/null
+++ b/scripts/cvsaddcurrentdir
@@ -0,0 +1,30 @@
+#!/bin/sh
+#Alexander Neundorf <neundorf@kde.org>
+#copyright 2002, GPL
+
+#call this script to add all files in and below the current dir to cvs
+#it adds *.c, *.h, *.C, *.cpp, *.cc automatically
+#*~, *.o, *.so, *.lo, *.la, .libs/, .deps/, .#* are ignored
+#it asks for the remaining files
+
+
+#ignore dirs "CVS", ".deps", ".libs"
+#ignore files *.o, *.so, *.lo, *.la, *~, .#*
+FOUND=`find |grep -v "^\.$"| grep -v CVS| grep -v "\.[ls]\?o$"|grep -v "~$"|grep -v "\.libs/"|grep -v "\.deps/" |grep -v "\.depend/"| grep -v "/\.#" |grep -v "\.la$"`
+#echo $FOUND
+
+ask_for_adding() {
+echo
+read -p "Add file $file to cvs ? (y/n) " answer rest
+#if [ "$answer" != "y" ]; then echo $file; fi
+if [ "$answer" == "y" ]; then cvs add $file; fi
+}
+
+
+for file in $FOUND
+do
+#matches all *.h, *.c, *.cpp, *.C, *.cpp, *.cc (and some others too)
+ echo $file | grep "\.[cCh][cp]\?p\?$" && cvs add $file
+ echo $file | grep -v "\.[cCh][cp]\?p\?$" && ask_for_adding
+done
+
diff --git a/scripts/cvsbackport b/scripts/cvsbackport
new file mode 100755
index 00000000..085b27ae
--- /dev/null
+++ b/scripts/cvsbackport
@@ -0,0 +1,32 @@
+#!/bin/sh
+# Backport the last change in HEAD, to a branch.
+# Usage: cvsbackport <files>
+# WARNING: the branch tag is hardcoded into the script, make sure to check it!
+#
+# Initial author: Dirk Mueller
+# Support for multiple command-line arguments: David Faure
+
+BRANCH=KDE_3_4_BRANCH
+echo "Backporting to $BRANCH"
+TMPFILE=`mktemp cvsbackport.XXXXXX` || exit 1
+files=$*
+until test $# -eq 0; do
+
+ echo "looking for last change to $1..."
+ CVSLASTCHANGE_KEEP_WHITESPACE=1 cvslastchange $1 > $TMPFILE
+ echo "browsing last change to $1..."
+ less $TMPFILE
+ cvs up -r$BRANCH $1
+ patch < $TMPFILE
+ rm -f $TMPFILE
+ echo "showing diff for $1..."
+ cvs diff $1 | less
+
+ shift
+done
+
+echo "Press ENTER now to commit ($files) or Ctrl+C to abort"
+read confirm
+
+cvs commit $files
+cvs up -A $files
diff --git a/scripts/cvsblame b/scripts/cvsblame
new file mode 100755
index 00000000..bd3635ed
--- /dev/null
+++ b/scripts/cvsblame
@@ -0,0 +1,252 @@
+#! /usr/bin/env perl
+
+# cvs blame inspired by Bonsai
+# Author: Bernd Gehrmann <bernd@physik.hu-berlin.de>
+
+=head1 NAME
+
+cvsblame - Shows a blame-annotated representation of a CVS controlled file in Konqueror.
+
+=head1 SYNOPSIS
+
+cvsblame <filename>
+
+=head1 DESCRIPTION
+
+cvsblame opens Konqueror to display the output of cvs annotate of
+a cvs controlled file. When the mouse is on a revision number shown
+in the second column, a popup with the respective log message
+appears.
+
+In the popup, a proper mailto: link to the author of a revision
+can be created as follows: In your home directory, make a file
+.cvsblame. In that file, enter for each repository you are working
+with a line like
+
+ accounts :pserver:gehrmab@cvs.kde.org:/home/kde /home/bernd/.kdeaccounts
+
+where the accounts file contains a simple list of cvs usernames in
+the first column and the respective mail address in the second.
+
+=head1 BUGS
+
+=over 4
+
+=item Does not really work for filenames which are not in the current directory
+
+=item Is a hack. Really.
+
+=back
+
+=head1 AUTHOR
+
+Bernd Gehrmann <bernd@physik.hu-berlin.de>
+
+=cut
+
+$file = $ARGV[0];
+$outputfile = `kde-config --path tmp` || './#'; # if we put the file in the cwd, then we keep a '#' at the beggining to help CVS ignore it
+($outputfile) = split(/:/,$outputfile);
+chomp $outputfile;
+$outputfile .= "cvsblame.$$.html";
+$configfile = $ENV{HOME}. "/.cvsblame";
+$rootfile = "`pwd`/CVS/Root";
+$cvsroot = `cat "$rootfile"`;
+chop $cvsroot;
+
+#
+# Look for a username -> mail address mapping
+#
+
+if (open(CONFIG, $configfile)) {
+ while (<CONFIG>) {
+ if (/accounts\s*([^\s]*)\s+([^\s]*)/) {
+ if ($1 eq $cvsroot) {
+ $accountfile = $2;
+ }
+ }
+ }
+ close CONFIG;
+}
+if ($accountfile) {
+ open(ACCOUNTS, $accountfile) || die "Account file not found: $accountfile";
+ while (<ACCOUNTS>) {
+ if (/([^\s]*)\s+([^\s].*[^\s])\s+([^\s]+)/) {
+ $mail{$1} = "$2 &lt;$3&gt;";
+ }
+ elsif (/([^\s]*)\s+([^\s]*)/) {
+ $mail{$1} = $2;
+ }
+ }
+}
+
+
+#
+# The real work, first the html header
+#
+
+
+open(OUTPUT, ">$outputfile");
+print OUTPUT <<EOF;
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
+<html>
+ <head>
+ <title>Blame annotation for $file</title>
+ </head>
+ <script type="text/javascript">
+ function hidelog(event) {
+ var target = event.relatedTarget;
+ while (target && target.id != "popup")
+ target = target.offsetParent;
+ if (target)
+ return;
+ target = event.target;
+ while (target.id != "popup")
+ target = target.offsetParent;
+ target.style.visibility = "hidden";
+ }
+ function init() {
+ document.getElementById("popup").addEventListener("mouseout", hidelog, false);
+ }
+ function poplog(target, rev) {
+ var popup = document.getElementById("popup");
+ var x = 120, y = 0;
+ while (target && target != document)
+ {
+ x += target.offsetLeft;
+ y += target.offsetTop;
+ target = target.offsetParent;
+ }
+ popup.style.pixelLeft = x;
+ popup.style.pixelTop = y;
+ popup.innerHTML = rev;
+ popup.style.visibility = "visible";
+ return true;
+ }
+EOF
+
+#
+# Translate information from cvs log in javascript stuff
+#
+
+$revision = "";
+open (LOG, "cvs log \"$file\"|");
+while (<LOG>) {
+ chop;
+ $line = $_;
+ if ($line =~ /^revision (.*)/) {
+ $revision = $1;
+ $revstr = "log$revision";
+ $revstr =~ s/\./_/g;
+ } elsif ($line =~ /date: ([^;]*);\s*author: ([^;]*);.*/) {
+ $date = $1;
+ $author = $2;
+ if ($mail{$author}) {
+ $author = "<a href=\\\"mailto:$mail{$author}\\\">$author</a>";
+ }
+ $content = "<b>$revision</b>&nbsp;&nbsp;$author&nbsp;&nbsp;<b>$date<b>";
+ } elsif ($line eq "----------------------------" && !($revision eq "")) {
+ print OUTPUT "var $revstr = \"$content\";\n";
+ } elsif ($line eq "=============================================================================" && !($revision eq "")) {
+ print OUTPUT "var $revstr = \"$content\";\n";
+ } else {
+ $line =~ s/\"/\\\"/g;
+ $line =~ s/&/&amp;/g;
+ $line =~ s/</&lt;/g;
+ $line =~ s/>/&gt;/g;
+ $content = "$content<br>$line";
+ }
+}
+close LOG;
+
+print OUTPUT <<EOF;
+ </script>
+ <style type="text/css">
+ body {
+ background: #eeeee0;
+ }
+ #popup {
+ position: absolute;
+ background: #ffcc99;
+ border: 1px solid #80664D;
+ padding: 2px;
+ }
+ a:link {
+ text-decoration: none;
+ }
+ a:hover {
+ text-decoration: underline;
+ }
+ </style>
+ <body text="#000000" onload="init()">
+ <h1>$file</h1>
+ <table border=0 cellpadding=0 cellspacing=0 width="100%">
+EOF
+
+#
+# Information from cvs annotate
+#
+
+$color = 1;
+$lineno = 1;
+$oldrevision = "";
+$oldlineno = "";
+$oldrevstr = "";
+open (ANNOTATE, "cvs annotate \"$file\" 2>/dev/null|");
+while (<ANNOTATE>) {
+ chop;
+ $line = $_;
+ $revision = substr $line, 0, 13;
+ $revision =~ s/\s//g;
+ $author = substr $line, 14, 9;
+ $author =~ s/\s//g;
+ $date = substr $line, 23, 9;
+ $content = substr $line, 35;
+ $content =~ s/\&/&amp;/g;
+ $content =~ s/\</&lt;/g;
+ $content =~ s/\>/&gt;/g;
+ $revstr = "log$revision";
+ $revstr =~ s/\./_/g;
+ if ($revision eq $oldrevision) {
+ if ($lineno == $oldlineno+20) {
+ $linkstr = "<span onmouseover=\"return poplog(this, $revstr)\"'>";
+ $linkendstr = "</span>";
+ $revauthor = "$author $revision";
+ $oldlineno = $lineno;
+ } else {
+ $linkstr = "";
+ $linkendstr = "";
+ $revauthor = "";
+ }
+ } else {
+ $color = ($color == 0)? 1 : 0;
+ $linkstr = "<span onmouseover=\"return poplog(this, $revstr)\"'>";
+ $linkendstr = "</span>";
+ $revauthor = "$author $revision";
+ $oldlineno = $lineno;
+ $oldrevision = $revision;
+ }
+ print OUTPUT "<tr><td nowrap style=\"background: ", ($color==1)? "#EEEEE0" : "#FFFFCC", "\"><pre>";
+
+ print OUTPUT sprintf '%-5i%s%-14s%s%s', $lineno, $linkstr, $revauthor,$linkendstr, $content;
+ print OUTPUT "</pre></td></tr>\n";
+ $lineno++;
+}
+close ANNOTATE;
+
+#
+# Finally, the html footer
+#
+
+print OUTPUT <<EOF;
+ </table>
+ <div id="popup" style="visibility: hidden"></div>
+ </body>
+</html>
+EOF
+
+close OUTPUT;
+
+system("kfmclient openProfile webbrowsing $outputfile");
+
+exit 0;
diff --git a/scripts/cvscheck b/scripts/cvscheck
new file mode 100755
index 00000000..1e1da5a8
--- /dev/null
+++ b/scripts/cvscheck
@@ -0,0 +1,385 @@
+#! /usr/bin/env perl
+
+use POSIX qw(mktime ctime);
+use Time::Local qw( timegm );
+
+# Offline check for status of files in a checked-out
+# CVS module.
+# Artistic License, Dirk Mueller <mueller@kde.org> 2001-2003
+
+# based on cvschanged by
+# Sirtaj Singh Kang <taj@kde.org> Nov 1998.
+
+if ( defined $ARGV[0] && $ARGV[0] =~ /(?:-h|--help)/) {
+ print "cvscheck (c) 2001-2003 Dirk Mueller <mueller\@kde.org>\n\nUsage:\n";
+ print " cvscheck [options] <dirs>\n\n";
+ print "Prints information about the status of your local CVS checkout without\n";
+ print "communicating with the server (therefore in speed only limited by your\n";
+ print "hard-disk throughput, much unlike cvs -n up).\n\n";
+ print "Every file is printed with a status character in front of its name:\n";
+ print "? foobar.c file is not known to CVS - maybe you should add it?\n";
+ print "M foobar.c file is for sure locally modified.\n";
+ print "m foobar.c file *might* have local changes (needs a diff with the server).\n";
+ print "C foobar.c file has a CVS conflict and therefore cannot be committed.\n";
+ print "U foobar.c file is in CVS but its somehow missing in your local checkout.\n";
+ print "T foobar.c file has an unusual sticky CVS tag.\n";
+ print "A foobar.c you cvs add'ed this file but did not yet commit.\n";
+ print "R foobar.c you cvs rm'ed this file but did not yet commit.\n";
+
+print <<EOF;
+
+
+Options:
+
+-u | --unknown Show only unknown (?) files
+-m | --modified Show only modified (m/M) files
+--missing Show only missing (U) files
+-t | --tagged Show only tagged (T) files
+-a | --added Show only added (A) files
+-r | --removed Show only removed (R) files
+-c | --conflicts Show only conflict (C) files
+
+If no option is given, it defaults to show all files and diagnostic messages.
+EOF
+ exit;
+}
+
+# default is HEAD
+$standardtag = "";
+%defaulttag = ();
+@dirqueue = ();
+@merged = ();
+@uncommitted = ();
+@missing = ();
+@tagged = ();
+@removed = ();
+@unknown = ();
+@modified = ();
+@conflicts = ();
+
+%months = ( 'Jan' => 0, 'Feb' => 1, 'Mar' => 2, 'Apr' => 3, 'May' => 4,
+ 'Jun' => 5, 'Jul' => 6, 'Aug' => 7, 'Sep' => 8, 'Oct' => 9,
+ 'Nov' => 10, 'Dec' => 11);
+
+%showoptions = ();
+$optionlocal = 0;
+
+sub printinfo($)
+{
+ print @_ if (defined($showoptions{"all"}));
+}
+
+# convert text stamp to GMT
+sub strToTime
+{
+ my( $timestr ) = @_;
+
+ if( ! ($timestr =~
+ /^(\w+)\s*(\w+)\s*(\d+)\s*(\d+):(\d+):(\d+)\s*(\d+)/) ) {
+
+ return -1;
+ }
+
+ # CVS timestamps are in GMT.
+
+ my( $tm ) = timegm( $6, $5, $4, $3, $months{ $2 }, $7 - 1900);
+
+ return $tm;
+}
+
+sub processEntries
+{
+ my ( $dir ) = @_;
+ my %dirunknown = ();
+
+ opendir (DIR, "$dir") || warn "Couldn't read '$dir'";
+ # first assume all are unknown
+ while ( $e = readdir(DIR) ) {
+ next if ($e eq ".");
+ next if ($e eq "..");
+ next if ($e eq "RCS");
+ next if ($e eq "SCCS");
+ next if ($e eq "CVS");
+ next if ($e eq "CVS.adm");
+ next if ($e eq "RCSLOG");
+ next if ($e eq "tags");
+ next if ($e eq "TAGS");
+ next if ($e eq ".make.state");
+ next if ($e eq ".nse_depinfo");
+ next if ($e eq "core");
+ next if ($e eq ".libs");
+ next if ($e eq ".deps");
+ next if ($e =~ /^.+~$/);
+ next if ($e =~ /^\#.+$/);
+ next if ($e =~ /^\.\#.+$/);
+ next if ($e =~ /^,.+$/);
+ next if ($e =~ /^_\$.+$/);
+ next if ($e =~ /^.+\$$/);
+ next if ($e =~ /^.+\.old$/);
+ next if ($e =~ /^.+\.bak$/);
+ next if ($e =~ /^.+\.BAK$/);
+ next if ($e =~ /^.+\.orig$/);
+ next if ($e =~ /^.+\.rej$/);
+ next if ($e =~ /^\.del-.+$/);
+ next if ($e =~ /^.+\.a$/);
+ next if ($e =~ /^.+\.olb$/);
+ next if ($e =~ /^.+\.o$/);
+ next if ($e =~ /^.*\.obj$/);
+ next if ($e =~ /^.+\.so$/);
+ next if ($e =~ /^.+\.Z$/);
+ next if ($e =~ /^.+\.elc$/);
+ next if ($e =~ /^.+\.ln$/);
+ next if ($e =~ /^cvslog\..*$/);
+
+ # kde specific entries
+ # TODO read from CVSROOT/cvsignore - if it's been checked out!
+ next if ($e eq "config.cache");
+ next if ($e eq "config.log");
+ next if ($e eq "config.status");
+ next if ($e eq "index.cache.bz2");
+ next if ($e eq ".memdump");
+ next if ($e eq "autom4te.cache");
+ next if ($e eq "autom4te.cache");
+ next if ($e eq "Makefile.rules");
+ next if ($e eq "Makefile.calls");
+ next if ($e eq "Makefile.rules.in");
+ next if ($e eq "Makefile.calls.in");
+ next if ($e =~ /^.*\.moc$/);
+ next if ($e =~ /^.+\.gmo$/);
+ next if ($e =~ /^.+\.moc\.[^\.]+$/);
+ next if ($e =~ /^.+\.lo$/);
+ next if ($e =~ /^.+\.la$/);
+ next if ($e =~ /^.+\.rpo$/);
+ next if ($e =~ /^.+\.closure$/);
+ next if ($e =~ /^.+\.all_cpp\.cpp$/);
+ next if ($e =~ /^.+\.all_C\.C$/);
+ next if ($e =~ /^.+\.all_cc\.cc$/);
+ next if ($e =~ /^.+_meta_unload\.[^\.]+$/);
+ next if ($e =~ /^.+\.kidl$/);
+ next if ($e =~ /^.+_skel\.[^\.]+$/);
+
+ # Qt specific entries
+ next if ($e eq ".ui");
+ next if ($e eq ".moc");
+ next if ($e eq ".obj");
+
+ $dirunknown{$e} = 1;
+ }
+ closedir(DIR);
+ if( open(CVSIGNORE, $dir."/.cvsignore") ) {
+ while(<CVSIGNORE>) {
+ s/\s*$//;
+ my $line = $_;
+ foreach my $entry ( split(/ /,$line) ) {
+ if ($entry =~ /[\*\?]/) {
+ my $pattern = quotemeta $entry;
+ $pattern =~ s/\\\*/.*/g;
+ $pattern =~ s/\\\?/./g;
+ foreach $m (keys (%dirunknown)) {
+ $dirunknown{$m} = 0 if ($m =~ /^$pattern$/);
+ }
+ next;
+ }
+ $dirunknown{$entry} = 0;
+ }
+ }
+ close(CVSIGNORE);
+ }
+
+ if ( !open( ENTRIES, $dir."/CVS/Entries" ) ) {
+ &printinfo("I CVS/Entries missing in $dir\n");
+ return;
+ }
+ my $oldstandardtag = defined($defaulttag{$dir}) ? $defaulttag{$dir} : "";
+ my $staginfo = "";
+ if( open(CVSTAG, $dir."/CVS/Tag" ) ) {
+ my $line = <CVSTAG>;
+ if($line =~ /^[TDN](.+)$/) {
+ $standardtag = $1;
+ $staginfo = $1;
+ }
+ else {
+ # something with D - assume HEAD
+ $oldstandardtag = $standardtag = ""; # its HEAD
+ &printinfo("I $dir has unknown stickyness: $line");
+ }
+ close(CVSTAG);
+ }
+ else {
+ $standardtag = ""; # its HEAD
+ $staginfo = "(HEAD)";
+ }
+ &printinfo("I $dir has sticky tag $staginfo\n") if($standardtag ne $oldstandardtag);
+ while( <ENTRIES> ) {
+ if ( m#^\s*D/([^/]+)/# ) {
+ if (-d "$dir/$1" && !$optionlocal) {
+ push ( @dirqueue, "$dir/$1" );
+ $defaulttag{"$dir/$1"} = $standardtag;
+ }
+ $dirunknown{$1} = 0;
+ next;
+ }
+
+ next if !m#^\s*/([^/]+)/([-]*[\d\.]*)/([^/]+)/([^/]*)/(\S*)$#;
+ $fname = $1;
+ $ver = $2;
+ $stamp = $3;
+ $options = $4;
+ $tag = $5;
+ $tag = $1 if ($tag =~ /^[TD](.+)$/);
+
+ $dirunknown{$fname} = 0;
+
+ my $taginfo="";
+ if(defined($showoptions{"all"})) {
+ if ( $tag ne $standardtag ) {
+ if ($tag eq "") {
+ $taginfo = " (HEAD)";
+ }
+ else {
+ $taginfo = " ($tag)";
+ }
+ }
+ if ($options =~ /^\-k(.)$/) {
+ $taginfo .= " (no RCS-tags)" if($1 eq "o");
+ $taginfo .= " (RCS binary file)" if($1 eq "b");
+ $taginfo .= " (RCS values only)" if($1 eq "v");
+ $taginfo .= " (RCS keywords only)" if($1 eq "k");
+ }
+ }
+ my $state = $stamp;
+ if( $stamp =~ m(^(.+)\+(.+)$) ) {
+ $state = $1;
+ $stamp = $2;
+ }
+ if ( $state =~ /merge/ ) {
+ # modified version merged with update from server
+ # check for a conflict
+ if ( open (F, "$dir/$fname") ) {
+ my @conflict = grep /^<<<<<<</, <F>;
+ close (F);
+ if( @conflict ) {
+ push @conflicts, "$dir/$fname$taginfo";
+ next;
+ }
+ }
+ else {
+ push @missing, "$dir/$fname$taginfo";
+ next;
+ }
+ }
+ if ( $ver =~ /^\-.*/ ) {
+ push @removed, "$dir/$fname$taginfo";
+ next;
+ }
+ $mtm = strToTime( $stamp );
+ if( $mtm < 0 ) {
+ if ( $ver eq "0" ) {
+ push @uncommitted, "$dir/$fname$taginfo";
+ }
+ else {
+ push @merged, "$dir/$fname$taginfo";
+ }
+ next;
+ }
+ @sparams = lstat( "$dir/$fname" );
+
+ if ( $#sparams < 0 ) {
+ push @missing, "$dir/$fname$taginfo";
+ next;
+ }
+ if( $mtm < $sparams[ 9 ] ) {
+ push @modified, "$dir/$fname$taginfo";
+ next;
+ }
+ if ( $tag ne $standardtag ) {
+ push @tagged, "$dir/$fname$taginfo";
+ }
+ }
+ close( ENTRIES );
+
+ my @unknownlist = sort keys (%dirunknown);
+ foreach $entry (@unknownlist) {
+ next if ($dirunknown{$entry} == 0);
+ # ignore unusual files
+ next if (-l "$dir/$entry" );
+ # its a CVS directory ? might be a different module
+ if (-d "$dir/$entry" and -d "$dir/$entry/CVS") {
+ $defaulttag{"$dir/$entry"} = $standardtag;
+ push ( @dirqueue, "$dir/$entry" );
+ next;
+ }
+ push @unknown, "$dir/$entry";
+ }
+}
+
+sub printlist($$@)
+{
+ my ($status, $type, @flist) = @_;
+
+ return if (not defined($showoptions{"all"}) and
+ not defined($showoptions{"$type"}));
+
+ if(defined($showoptions{"all"})) {
+ foreach (@flist) {
+ s/\.\///;
+ print "$status $_\n";
+ }
+ }
+ else {
+ foreach(@flist) {
+ print "$_\n";
+ }
+ }
+}
+
+foreach $f ( @unknown ) {
+ $f =~ s/^\.\///;
+ print "? $f\n";
+}
+foreach (@ARGV) {
+ $showoptions{"unknown"}++ if(/^(?:-u|--unknown)$/);
+ $showoptions{"modified"}++ if(/^(?:-m|--modified)$/);
+ $showoptions{"missing"}++ if(/^(?:--missing)$/);
+ $showoptions{"tagged"}++ if(/^(?:-t|--tagged)$/);
+ $showoptions{"added"}++ if(/^(?:-a|--added)$/);
+ $showoptions{"removed"}++ if(/^(?:-r|--removed)$/);
+ $showoptions{"conflicts"}++ if(/^(?:-c|--conflicts)$/);
+ $optionlocal++ if(/^(?:-l|--local)$/);
+
+ next if (/^-/);
+ push (@dirqueue, "./$_");
+}
+
+# if no special flags set, show all files
+$showoptions{"all"}++ if(scalar(keys(%showoptions)) == 0);
+
+# Try current directory if none specified
+push(@dirqueue, ".") if( $#dirqueue < 0 );
+
+# process directory queue
+while ($#dirqueue >= 0) {
+ processEntries( pop @dirqueue );
+}
+
+&printlist("?", "unknown", @unknown);
+&printlist("M", "modified", @modified);
+&printlist("m", "modified", @merged);
+&printlist("U", "missing", @missing);
+&printlist("T", "tagged", @tagged);
+&printlist("A", "added", @uncommitted);
+&printlist("R", "removed", @removed);
+&printlist("C", "conflicts", @conflicts);
+
+=head1 NAME
+
+cvscheck -- Lists all files in checked out CVS modules that have been
+edited or changed locally. No connection is required to the CVS server,
+therefore being extremely fast.
+
+=head1 AUTHOR
+
+Dirk Mueller <mueller@kde.org>
+based on cvschanged by Sirtaj Singh Kang <taj@kde.org>
+
+=cut
diff --git a/scripts/cvsforwardport b/scripts/cvsforwardport
new file mode 100755
index 00000000..10397845
--- /dev/null
+++ b/scripts/cvsforwardport
@@ -0,0 +1,32 @@
+#!/bin/sh
+# Forwardport the last change in a branch to HEAD
+# Usage: cvsforwardport <files>
+# WARNING: the branch tag is hardcoded into the script, make sure to check it!
+#
+# Initial author: Dirk Mueller
+# Support for multiple command-line arguments: David Faure
+
+BRANCH=KDE_3_4_BRANCH
+echo "Forwardporting to HEAD"
+TMPFILE=`mktemp cvsforwardport.XXXXXX` || exit 1
+files=$*
+until test $# -eq 0; do
+
+ echo "looking for last change to $1..."
+ CVSLASTCHANGE_KEEP_WHITESPACE=1 cvslastchange $1 > $TMPFILE
+ echo "browsing last change to $1..."
+ less $TMPFILE
+ cvs up -A $1
+ patch < $TMPFILE
+ rm -f $TMPFILE
+ echo "showing diff for $1..."
+ cvs diff $1 | less
+
+ shift
+done
+
+echo "Press ENTER now to commit ($files) or Ctrl+C to abort"
+read confirm
+
+cvs commit $files
+cvs up -r $BRANCH $files
diff --git a/scripts/cvsgettags b/scripts/cvsgettags
new file mode 100755
index 00000000..9869eb06
--- /dev/null
+++ b/scripts/cvsgettags
@@ -0,0 +1,38 @@
+#!/bin/sh
+#
+# copyright (C) 2004 Roberto Teixeira <roberto@kde.org>
+#
+# This script is release under the GPL
+#
+
+#
+# This very simple script can be used to fetch available
+# cvs tags for a group of files.
+#
+# Its usage is simple, simply type something like
+#
+# gettags myfile.cpp myfile.h
+#
+# to get the available cvs tags for myfile.cpp and myfile.h
+# otherwise simply type
+#
+# gettags
+#
+# to fetch all available tags in the current directory and its
+# subdirectories.
+#
+
+usage()
+{
+ echo "Ex.:"
+ echo " $0 [file1] [file2] ..."
+}
+
+if test -z "$1"; then
+ echo "Will test tags for all files and subdirectories under `pwd`. Hope it's right"
+ echo "but if it is not, please inform the files you want to fetch the tags from."
+
+ usage
+fi
+
+cvs log $@|tr "\n" "å"|sed 's/^.*symbolic names:å\(.*\)keyword subst.*$/\1/'|tr "å" "\n"
diff --git a/scripts/cvslastchange b/scripts/cvslastchange
new file mode 100755
index 00000000..9c4688be
--- /dev/null
+++ b/scripts/cvslastchange
@@ -0,0 +1,55 @@
+#! /usr/bin/env perl
+
+use File::Basename;
+
+sub usage()
+{
+ print "Usage:\n";
+ print " $0 [ <filename > | <filename> <rev> | \n" .
+ " M +<digits> -<digits> <filename <rev> ]\n";
+ print "\n";
+
+ exit 5;
+}
+
+my $filename;
+
+my $argc = scalar @ARGV;
+
+if ($argc > 0 and $argc < 3 ) {
+ $filename = $ARGV[0];
+ $cvsversion= dirname($0) . "/cvsversion";
+ $version=`$cvsversion $filename`;
+ chomp $version;
+ $version=$ARGV[1] if ($argc > 1 and $ARGV[1] =~ /^[\d\.]{3,}$/);
+} elsif ($argc == 5) {
+ $filename=$ARGV[3] if (-f $ARGV[3]);
+ $version=$ARGV[4] if ($ARGV[4] =~ /^[\d\.]{3,}$/);
+} else {
+ &usage();
+}
+
+die "$0: filename expected" if(!length($filename));
+die "$filename: $!\n" if (! -f $filename);
+
+my $vold = $version;
+my $vnew = $version;
+
+if ($version=~/^.*\.1$/) {
+ $vold = $1 if ($version=~/^(\d+\.\d+(?:\.\d+\.\d+)*)\.\d+\.1$/);
+}
+else {
+ if ($version=~/^(.*)\.([^.]*)$/) { $v1 = $1; $v2 = $2 }
+ $v2old = ${v2}-1;
+ $vold = $v1 . '.' . $v2old;
+}
+my $base = basename($filename);
+my $dir = dirname($filename);
+my $cmd = "cd $dir; cvs -f log -N -r$vnew $base";
+print "$cmd\n";
+system("$cmd");
+my $whitespace = "";
+$whitespace = "-b" unless (defined $ENV{"CVSLASTCHANGE_KEEP_WHITESPACE"});
+$cmd = "cd $dir; cvs -f diff -kk $whitespace -p -u -r$vold -r$vnew $base";
+print "$cmd\n";
+system("$cmd");
diff --git a/scripts/cvslastlog b/scripts/cvslastlog
new file mode 100755
index 00000000..d1b45812
--- /dev/null
+++ b/scripts/cvslastlog
@@ -0,0 +1,8 @@
+#!/bin/sh
+# cvslastlog - prints log of last commit for a file
+# Depends on the version of the local file, not the one on the server
+# Requires cvsversion
+# David Faure, faure@kde.org
+
+cvs log -N -r`cvsversion $1` $1
+
diff --git a/scripts/cvslastreferenced b/scripts/cvslastreferenced
new file mode 100755
index 00000000..666a5b6d
--- /dev/null
+++ b/scripts/cvslastreferenced
@@ -0,0 +1,64 @@
+#!/usr/bin/perl -w
+# Written by Zack Rusin <zack@kde.org>
+#
+# This file is free software, licensed under the BSD licence.
+# That means that you can do anything you want with it except
+# eating too much candy since that totally messes up your teeth
+# and here in KDE land we care about your teeth. They're out
+# greatest priority right next to scoring chicks of course...
+#
+
+# This script goes through the whole history of a file to find
+# all modifications referencing specific string. It's useful if
+# you want to know when a function has been removed/modified/added
+# to a file if a recent cvs annotate doesn't anymore reference it.
+
+our $file;
+our $func;
+
+sub check_file
+{
+ my $rev1 = shift;
+ my $rev2 = shift;
+
+ my $output = `cvs diff -r $rev1 -r $rev2 $file`;
+
+ if ( $output =~ /(^[+-].+$func.+$)/m ) {
+ print "FOUND IN: cvs diff -r $rev1 -r $rev2 $file\n";
+ $_ = $1;
+ s/^([-+])\s*(.+)/$1 $2/;
+ return $_;
+ }
+ return 0;
+}
+
+sub get_revision
+{
+ my $output = `cvsversion $file`;
+ chomp $output;
+ return $output;
+}
+
+my $argc = scalar @ARGV;
+
+die "$0 <function> <file>" if ( $argc != 2 );
+$func = $ARGV[0];
+$file = $ARGV[1];
+
+my $current_revision = get_revision( $file );
+
+$current_revision =~ /(\d+)\.(\d+)/;
+$base = $1;
+$working = $2;
+
+while ( $working > 1 ) {
+ my $older = $working - 1;
+ my $res = check_file( "$base.$older", "$base.$working");
+
+ if ( $res ) {
+ print "\t($res)\n";
+ }
+ --$working;
+}
+
+print "Didn't find a reference to that $func in $file\n";
diff --git a/scripts/cvsrevertlast b/scripts/cvsrevertlast
new file mode 100755
index 00000000..96808514
--- /dev/null
+++ b/scripts/cvsrevertlast
@@ -0,0 +1,17 @@
+#!/bin/sh
+# (C) 2001 Charles Samuels <charles@kde.org>
+#
+# This script reverts all the files given on the command
+# by one version, then you can commit them. This
+# is like a less polite version of cvsblame ;)
+#
+
+for i in $@ ;
+do
+ text=`cvs status "$i" | grep '[^s]Repository revision:.*$'`
+ current=`echo $text | awk '{print $3}'`
+ previous=`echo $current | awk -F . '{ ORS="."; OFS="\n"; for (i=1; i<NF; i++) print $i; ORS=""; $NF-=1; print $NF }'`
+ echo $i... "(reverting from $current to $previous)"
+ cvs up -j $current -j $previous $i
+done
+
diff --git a/scripts/cvsversion b/scripts/cvsversion
new file mode 100755
index 00000000..200c008a
--- /dev/null
+++ b/scripts/cvsversion
@@ -0,0 +1,30 @@
+#!/bin/sh
+exec awk -F / "{ if (\$2 == \"`basename $1`\") print \$3 }" < `dirname $1`/CVS/Entries
+
+=head1 NAME
+
+cvsversion -- Displays version of the file passed as argument.
+
+=head1 SYNOPSIS
+
+ cvsversion <file>
+
+=head1 DESCRIPTION
+
+cvsversion displays the version in CVS of a file, as known by the local
+checked out directory. No connection is required to the CVS server.
+It can be used in other scripts, or simply to ask
+for diffs using
+
+cvs diff -r <version> [-r <version>] <file>
+
+=head1 EXAMPLES
+
+ cd baseline/kdelibs ; cvsversion configure.in
+ cvsversion baseline/kdelibs/configure.in
+
+=head1 AUTHOR
+
+David Faure <faure@kde.org>
+
+=cut
diff --git a/scripts/cxxmetric b/scripts/cxxmetric
new file mode 100755
index 00000000..0fae0a9b
--- /dev/null
+++ b/scripts/cxxmetric
@@ -0,0 +1,223 @@
+#!/usr/bin/perl -w
+
+# Simple Source metrics for C++
+# Taj Sun Apr 26 03:31:00 EST 1998
+# $Id$
+
+use strict;
+
+our $bigblank = 0;
+our $bigcommt = 0;
+our $bigstrcount = 0;
+our $bigstrsize = 0;
+our $bigtotal = 0;
+our $numfiles = 0;
+
+our $blocklen = 0;
+our $numblocks = 0;
+our $blockdepth = 0;
+our $blockstart = 0;
+our $blockmin = -1;
+our $blockmax = 0;
+our @blenlist = ();
+our @extensions = ( ".cpp", ".cc", ".C", ".c", ".h", ".tcc" );
+
+sub processFile
+{
+ our ( $file ) = @_;
+ our $blank = 0;
+ our $comment = 0;
+ our $total = 0;
+ our $incomment = 0;
+ our $strcount = 0;
+ our $strsize = 0;
+
+ open( SOURCE, "$file" ) ||
+ die "cxxmetric.pl: Couldn't read from $file.\n";
+
+ while( <SOURCE> ) {
+ $total++;
+
+ if ( /^\s*$/ ) {
+ $blank++;
+ next;
+ }
+
+ if ( m#^\s*//# ) {
+ $comment++;
+ next;
+ }
+
+ if ( /{/ ) {
+ # block start
+ $blockdepth += s/{/{/g;
+
+ $blockstart = $. if $blockdepth == 1;
+ }
+
+ if ( /}/ ) {
+ # block end
+
+ $blockdepth -= s/}/}/g;
+
+ if( $blockdepth == 0 ) {
+ my $thisblocklen = $. - $blockstart;
+ push @blenlist, $thisblocklen;
+
+ $blocklen += $thisblocklen;
+ $numblocks++;
+
+ if( $blockmax < $thisblocklen ) {
+ $blockmax = $thisblocklen;
+ }
+
+ if ( $blockmin == -1
+ || $blockmin > $thisblocklen ) {
+ $blockmin = $thisblocklen;
+ }
+ }
+ }
+
+ my $start = 0;
+ my $stop = 0;
+
+ if ( m#/\*# ) {
+ $start = 1;
+ }
+
+ if( m#\*/# ) {
+ $stop = 1;
+ }
+
+ if( $start ) {
+ $incomment = 1 unless $stop;
+ $comment++;
+ }
+ elsif ( $stop ) {
+ $comment++;
+ $incomment = 0;
+ }
+ elsif ( $incomment ) {
+ $comment++;
+ }
+ else {
+ my $line = $_;
+ countStrings( $line );
+ }
+ }
+
+ our $code = $total - ($comment + $blank );
+ $bigtotal += $total;
+ $bigcommt += $comment;
+ $bigblank += $blank;
+ $bigstrcount += $strcount;
+ $bigstrsize += $strsize;
+
+ our $stravglen = $strcount ? ($strsize / $strcount) : 0;
+
+ write;
+}
+
+sub buildFileList {
+ my ( $dir ) = @_;
+ my @fileList = glob( "$dir/*" );
+ my @cxxList;
+
+ foreach my $file (@fileList) {
+
+ if( -d $file ) {
+ push @cxxList, buildFileList( $file );
+ }
+ else {
+ foreach my $extension (@extensions) {
+ if( substr( $file, length( $file ) - length( $extension ) ) eq $extension ) {
+ push @cxxList, $file;
+ }
+ }
+ }
+ }
+
+ return @cxxList;
+}
+
+sub countStrings
+{
+ my $line = shift;
+
+ foreach my $string ( split( /("[^"]*)\"/, $line ) ) {
+ next unless $string =~ /^\"/;
+
+ our $strcount++;
+ our $strsize += length( $string ) - 1;
+ }
+}
+
+sub pct
+{
+ my( $top, $bottom ) = @_;
+
+ return 0 if $bottom == 0;
+
+ return int(( $top * 100 ) / $bottom);
+}
+
+our @files;
+
+if( @ARGV == 0 ) {
+ @files = buildFileList(".");
+}
+else {
+ @files = @ARGV;
+}
+
+foreach my $file ( @files ) {
+ processFile( $file );
+ ++$numfiles;
+}
+
+our $total = $bigtotal;
+our $comment = $bigcommt;
+our $blank = $bigblank;
+our $code = $bigtotal - ($bigcommt + $bigblank );
+our $file = "Total";
+
+print "\n";
+write;
+
+print "\nPercentage Code:\t" , pct( $code, $total ),"%\n";
+print "Percentage Comment:\t" , pct( $comment, $total ),"%\n";
+print "Percentage Blank:\t" , pct( $blank, $total ),"%\n";
+print "Percentage Cmt/Code:\t" , pct( $comment, $code ),"%\n";
+print "Average Code/File:\t" , int($code/$numfiles)," lines\n"
+ unless $numfiles == 0;
+
+if ( $numblocks > 0 ) {
+ my $avg = int( $blocklen / $numblocks );
+ @blenlist = sort @blenlist;
+ my $median = $blenlist[ int( $numblocks / 2 )];
+print<<EOF;
+
+Blocks:\t$numblocks
+\tLengths (lines):\tmin: $blockmin\tmax: $blockmax\tmed: $median\taverage: $avg
+EOF
+}
+
+our $bigstravglen = $bigstrcount ? int($bigstrsize / $bigstrcount) : 0;
+
+print<<EOF;
+Strings:\t$bigstrcount
+\tSize (bytes):\ttotal: $bigstrsize\taverage: $bigstravglen
+EOF
+
+exit;
+
+format STDOUT_TOP =
+ Lines Code Comment Blank Strs AvgLen File
+ ------ ------- -------- ------ ------ ------ ------
+
+.
+
+format STDOUT =
+@###### @###### @###### @###### @###### @###### @<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
+$total, $code, $comment, $blank, our $strcount, our $stravglen, $file
+.
diff --git a/scripts/extend_dmalloc b/scripts/extend_dmalloc
new file mode 100755
index 00000000..53bd7491
--- /dev/null
+++ b/scripts/extend_dmalloc
@@ -0,0 +1,159 @@
+#! /usr/bin/env perl
+#
+# script to run gdb on return-addresses
+# Usage: $0 malloc-log-file binary
+#
+# Copyright 1995 by Gray Watson
+#
+# This file is part of the dmalloc package.
+#
+# Permission to use, copy, modify, and distribute this software for
+# any purpose and without fee is hereby granted, provided that the
+# above copyright notice and this permission notice appear in all
+# copies, and that the name of Gray Watson not be used in advertising
+# or publicity pertaining to distribution of the document or software
+# without specific, written prior permission.
+#
+# Gray Watson makes no representations about the suitability of the
+# software described herein for any purpose. It is provided "as is"
+# without express or implied warranty.
+#
+# The author may be contacted at gray.watson@letters.com
+#
+# $Id$
+#
+
+#
+# Use this Perl script to run gdb and get information on the return-address
+# (ra) addresses from a dmalloc logfile output. This will search for
+# any ra= lines and will examine them and try to get the line number.
+#
+# NOTE: you may want to direct the output from the script to a file
+# else gdb seems to prompt for a return like you are on the end of a
+# page.
+#
+# Be sure to send me mail if there is an easier way to do all this.
+#
+
+###############################################################################
+# usage message
+#
+if (@ARGV != 2 ) {
+ die "Usage: $0 dmalloc-log binary-that-generated-log\n";
+}
+
+$malloc = @ARGV[0];
+$command = @ARGV[1];
+
+@addresses = ();
+
+open(malloc, $malloc);
+while ( <malloc> ) {
+ if ($_ =~ m/ra=(0x[0-9a-fA-F]+)/) {
+ push(@addresses, $1);
+ }
+}
+close(malloc);
+open(SORT, "|sort -u > $malloc.tmp");
+
+foreach $address (@addresses) {
+ print SORT "$address\n";
+}
+close(SORT);
+
+@addresses = ();
+
+open(SORT, "< $malloc.tmp");
+while ( <SORT> ) {
+ chomp $_;
+ push(@addresses, $_);
+}
+close(SORT);
+unlink $malloc.tmp;
+
+open (gdb, "|gdb -nx -q $command > $malloc.tmp") || die "Could not run gdb: $!\n";
+$| = 1;
+
+# get rid of the (gdb)
+printf (gdb "set prompt\n");
+printf (gdb "echo \\n\n");
+
+# load in the shared libraries
+printf (gdb "sharedlibrary\n");
+
+# run the program to have _definitly_ the informations
+# we need from the shared libraries. Unfortunatly gdb 4.18's
+# version of sharedlibrary does nothing ;(
+printf (gdb "b main\n");
+printf (gdb "run\n");
+
+foreach $address (@addresses) {
+
+ printf (gdb "echo -----------------------------------------------\\n\n");
+ # printf (gdb "echo Address = '%s'\n", $address);
+ printf (gdb "x %s\n", $address);
+ printf (gdb "info line *(%s)\n", $address);
+}
+printf (gdb "quit\ny\n");
+# $| = 0;
+
+close(gdb);
+
+%lines = ();
+
+open(malloc, "< $malloc.tmp");
+
+$count = 0;
+$address = "";
+$line = "";
+
+while ( <malloc> ) {
+
+ # ignore our own input
+ if ($_ =~ m/^x 0x/ || $_ =~ m/^echo ------/ || $_ =~ m/^info line/) {
+ next;
+ }
+
+ if ($_ =~ m/^--------/) {
+ if ($line) {
+ $lines{$address} = "$line";
+ }
+ $count = 0;
+ $address = "";
+ $line = "";
+ } else {
+ $count = $count + 1;
+ }
+
+ if ($count == 1 && $_ =~ m/(0x[0-9a-fA-F]+)\s*<(.*)>:\s*(\S+)/) {
+ $address = $1;
+ $line = "$2<$3>";
+ }
+
+ if ($count == 2 && $_ =~ m/Line ([0-9]+) of \"([^\"]*)\"/) {
+ $line = "$2:$1";
+ }
+
+}
+
+if ($line) {
+ $lines{$address} = "$line";
+}
+
+close(malloc);
+
+open(malloc, $malloc);
+
+while ( <malloc> ) {
+ if ($_ =~ m/ra=(0x[0-9a-fA-F]+)/) {
+ $address = $1;
+ if (defined($lines{$address})) {
+ $_ =~ s/ra=$address/$lines{$address}/;
+ print STDOUT $_;
+ } else {
+ print STDOUT $_;
+ }
+ } else {
+ print STDOUT $_;
+ }
+}
diff --git a/scripts/extractattr b/scripts/extractattr
new file mode 100755
index 00000000..324b1f56
--- /dev/null
+++ b/scripts/extractattr
@@ -0,0 +1,158 @@
+#! /usr/bin/env perl
+
+#
+# Copyright (c) 2004 Richard Evans <rich@ridas.com>
+#
+# License: LGPL 2.0
+#
+
+sub usage
+{
+ warn <<"EOF";
+
+extractattr [flags] filenames
+
+This script extracts element attributes from designer (.ui) and XMLGIU (.rc) files
+and writes on standard output (usually redirected to rc.cpp) the equivalent
+i18n() calls so that xgettext can parse them.
+
+--attr=spec : Specify the attribute to be extracted. The specification
+ consists of the following comma separated arguments:
+
+ Element,attribute[,context]
+
+ The context is optional and overrides the name set by
+ --context below. Repeat the flag to specify multiple
+ attributes:
+
+ --attr=Title,data --attr=Description,data,Stencils
+
+--context=name : Give i18n calls a context name: i18n("name", ...)
+--lines : Include source line numbers in comments (deprecated, it is switched on by default now)
+--help|? : Display this summary
+
+EOF
+
+ exit;
+}
+
+###########################################################################################
+
+use strict;
+use warnings;
+use Getopt::Long;
+
+###########################################################################################
+# Add options here as necessary - perldoc Getopt::Long for details on GetOptions
+
+GetOptions ( "attr=s" => \my @opt_attr,
+ "context=s" => \my $opt_context,
+ "lines" => \my $opt_lines,
+ "help|?" => \&usage );
+
+unless ( @ARGV )
+{
+ warn "No filename specified";
+ exit;
+}
+
+unless ( @opt_attr )
+{
+ warn "No attributes specified";
+ exit;
+}
+
+###########################################################################################
+# Program start proper - NB $. is the current line number
+
+my $code =<<'EOF';
+our $file_name;
+
+for $file_name ( @ARGV )
+{
+ my $fh;
+
+ unless ( open $fh, "<", $file_name )
+ {
+ warn "Failed to open: '$file_name': $!";
+ next;
+ }
+
+ while ( <$fh> )
+ {
+ last if $. == 1 and $_ !~ /^(?:<!DOCTYPE|<\?xml)/;
+EOF
+
+$code .= build_code(@opt_attr) . <<'EOF';
+ }
+
+ close $fh or warn "Failed to close: '$file_name': $!";
+}
+
+1;
+EOF
+
+# warn "CODE TO EVAL:\n$code\n";
+
+eval $code or die;
+
+
+sub build_code
+{
+ my $code = "\n";
+
+ my %seen;
+
+ for ( @_ )
+ {
+ my ($element, $attribute, $context) = ((split /,/), "", "", "");
+
+ length $element or die "Missing element in --attr=$_";
+ length $attribute or die "Missing attribute in --attr=$_";
+
+ if ( $seen{$element . '<' . $attribute}++ )
+ {
+ warn "Skipping duplicate flag --attr=$_ (element/attribute pair has already been specified)";
+ next;
+ }
+
+ $code .= " /<" . quotemeta($element) . qq| [^>]*?| .
+ quotemeta($attribute) . qq|="([^"]+)"/ and write_i18n('| . $context . qq|', \$1);\n|;
+ }
+
+ return "$code\n";
+}
+
+sub write_i18n
+{
+ my ($context, $text) = @_;
+
+ our $file_name;
+
+ unless ( $text )
+ {
+ print "// Skipped empty message at $file_name line $.\n";
+ return;
+ }
+
+ $text =~ s/&lt;/</g;
+ $text =~ s/&gt;/>/g;
+ $text =~ s/&apos;/\'/g;
+ $text =~ s/&quot;/\"/g;
+ $text =~ s/&amp;/&/g;
+
+ # Escape characters exactly like uic does it
+ # (As extractrc needs it, we follow the same rule to avoid to be different.)
+ $text =~ s/\\/\\\\/g; # escape \
+ $text =~ s/\"/\\\"/g; # escape "
+ $text =~ s/\r//g; # remove CR (Carriage Return)
+ $text =~ s/\n/\\n\"\n\"/g; # escape LF (Line Feed). uic also change the code line at a LF, we do not do that.
+
+ $context ||= $opt_context;
+
+ print "//i18n: file $file_name line $.\n";
+ print qq|i18n("|;
+ print qq|$context", "| if $context;
+ print qq|$text");\n|;
+}
+
diff --git a/scripts/extractrc b/scripts/extractrc
new file mode 100755
index 00000000..54c1123a
--- /dev/null
+++ b/scripts/extractrc
@@ -0,0 +1,174 @@
+#! /usr/bin/env perl
+
+### TODO: other copyrights, license?
+# Copyright (c) 2004 Richard Evans <rich@ridas.com>
+
+sub usage
+{
+ warn <<"EOF";
+
+extractrc [flags] filenames
+
+This script extracts messages from designer (.ui) and XMLGUI (.rc) files and
+writes on standard output (usually redirected to rc.cpp) the equivalent
+i18n() calls so that xgettext can parse them.
+
+--tag=name : Also extract the tag name(s). Repeat the flag to specify
+ multiple names: --tag=tag_one --tag=tag_two
+
+--tag-group=group : Use a group of tags - uses 'default' if omitted.
+ Valid groups are: @{[TAG_GROUPS()]}
+
+--context=name : Give i18n calls a context name: i18n("name", ...)
+--lines : Include source line numbers in comments (deprecated, it is switched on by default now)
+--help|? : Display this summary
+
+EOF
+
+ exit;
+}
+
+###########################################################################################
+
+use strict;
+use warnings;
+use Getopt::Long;
+
+use constant TAG_GROUP =>
+{
+ default => "[tT][eE][xX][tT]|title|string|whatsthis|tooltip|label",
+ koffice => "Example|GroupName|Text|Comment|Syntax|TypeName",
+ none => "",
+};
+
+use constant TAG_GROUPS => join ", ", map "'$_'", sort keys %{&TAG_GROUP};
+
+
+###########################################################################################
+# Add options here as necessary - perldoc Getopt::Long for details on GetOptions
+
+GetOptions ( "tag=s" => \my @opt_extra_tags,
+ "tag-group=s" => \my $opt_tag_group,
+ "context=s" => \my $opt_context, # I18N context
+ "lines" => \my $opt_lines,
+ "help|?" => \&usage );
+
+unless( @ARGV )
+{
+ warn "No filename specified";
+ exit;
+}
+
+$opt_tag_group ||= "default";
+
+die "Unknown tag group: '$opt_tag_group', should be one of " . TAG_GROUPS
+ unless exists TAG_GROUP->{$opt_tag_group};
+
+my $tags = TAG_GROUP->{$opt_tag_group};
+my $extra_tags = join "", map "|" . quotemeta, @opt_extra_tags;
+my $text_string = qr/($tags$extra_tags)( [^>]*)?>/; # Precompile regexp
+
+
+###########################################################################################
+# Program start proper - NB $. is the current line number
+
+for my $file_name ( @ARGV )
+{
+ my $fh;
+
+ unless ( open $fh, "<", $file_name )
+ {
+ # warn "Failed to open: '$file_name': $!";
+ next;
+ }
+
+ my $string = "";
+ my $in_text = 0;
+ my $start_line_no = 0;
+ my $in_skipped_prop = 0;
+ my $tag = "";
+ my $attr = "";
+ my $context = "";
+
+ while ( <$fh> )
+ {
+ last if $. == 1 and $_ !~ /^(?:<!DOCTYPE|<\?xml|<!--)/;
+
+ chomp;
+
+ $string .= "\n" . $_;
+
+ # 'database', 'associations' properties contain strings that shouldn't be translated
+
+ if ( $in_skipped_prop == 0 and $string =~ /<property name=\"(?:database|associations|populationText)\"/ )
+ {
+ $in_skipped_prop = 1;
+ }
+ elsif ( $in_skipped_prop and $string =~ /<\/property/ )
+ {
+ $string = "";
+ $in_skipped_prop = 0;
+ }
+
+ $context = $opt_context;
+
+ unless ( $in_skipped_prop or $in_text )
+ {
+ if ( ($tag, $attr) = $string =~ /<$text_string/o )
+ {
+ ($attr) = $attr =~ /\w*context=\"([^\"]*)\"/ if $attr;
+ $context = $attr if $attr;
+
+ $string =~ s/^.*<$text_string//so;
+ $in_text = 1;
+ $start_line_no = $.;
+ }
+ else
+ {
+ $string = "";
+ }
+ }
+
+ next unless $in_text;
+ next unless $string =~ /<\/$text_string/o;
+
+ my $text = $string;
+
+ $text =~ s/<\/$text_string.*$//o;
+ $text =~ s/&lt;/</g;
+ $text =~ s/&gt;/>/g;
+ $text =~ s/&amp;/&/g;
+
+ # We need to escape characters exactly like uic does it:
+ $text =~ s/\\/\\\\/g; # escape \
+ $text =~ s/\"/\\\"/g; # escape "
+ $text =~ s/\r//g; # remove CR (Carriage Return)
+ $text =~ s/\n/\\n\"\n\"/g; # escape LF (Line Feed). uic also change the code line at a LF, we do not do that.
+
+ if ( $text cmp "" )
+ {
+ print "//i18n: file $file_name line $.\n";
+ print "// xgettext: no-c-format\n";
+ print q|i18n("|;
+ print qq|$context","| if $context; # We have a I18N context
+ print qq|$text");\n|;
+ }
+ else
+ {
+ #print "// Skipped empty message at $file_name line $.\n";
+ # - seems this comment may confuse old custom xgettext of KDE3; not needed anyway
+ }
+
+ $string =~ s/^.*<\/$text_string//o;
+ $in_text = 0;
+
+ # Text can be multiline in .ui files (possibly), but we warn about it in XMLGUI .rc files.
+
+ warn "there is <text> floating in: '$file_name'" if $. != $start_line_no and $file_name =~ /\.rc$/i;
+ }
+
+ close $fh or warn "Failed to close: '$file_name': $!";
+
+ die "parsing error in $file_name" if $in_text;
+}
+
diff --git a/scripts/findmissingcrystal b/scripts/findmissingcrystal
new file mode 100755
index 00000000..258119c3
--- /dev/null
+++ b/scripts/findmissingcrystal
@@ -0,0 +1,32 @@
+#!/bin/sh
+#
+# Small script to look at Crystal icons and see which ones are still the
+# same as kdeclassic/hicolor.
+
+if [ -z "$1" ] ; then
+ echo "usage: findmissingcrystal module"
+ exit 1
+fi
+
+for icon in `find $1 -name cr*.png` ; do
+ fullname=`echo $icon | sed 's,.*cr,,'`
+ res=`echo $fullname | cut -d- -f1`
+ type=`echo $fullname | cut -d- -f2`
+ name=`echo $fullname | cut -d- -f3`
+ dir="kdeartwork/IconThemes/kdeclassic/${res}x${res}/${type}s/"
+ if [ -d "$dir" ]; then
+ classic=`find "${dir}" -name "$name"`
+ if [ -s "$classic" ]; then
+ diff=`diff $icon $classic`
+ if [ -z "$diff" ]; then
+ echo "ERR/same: $icon"
+ else
+ echo "OK /diff: $icon"
+ fi
+ else
+ echo "OK /new : $icon"
+ fi
+ else
+ echo "OK /new : $icon"
+ fi
+done
diff --git a/scripts/fixfsfaddr.sed b/scripts/fixfsfaddr.sed
new file mode 100644
index 00000000..ab96de23
--- /dev/null
+++ b/scripts/fixfsfaddr.sed
@@ -0,0 +1,30 @@
+#! /usr/bin/sed
+
+# Copyright 2005 Nicolas GOUTTE <goutte@kde.org>
+# License LGPL V2+
+
+# The script helps to fix the FSF address
+# Use:
+# find . -name .svn -prune , type f | xargs fgrep -l "Free Software Foundation" | xargs sed -i -f fixfsfaddr.sed
+# Note: you should check the changes before committing them.
+
+# Implementation note: we need to replace phrase by phrase, as
+# the wrapping of the FSF address is at different places.
+
+# Current FSF address: 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
+
+# Old address: 59 Temple Place, Suite 330, Boston, MA 02111-1307
+s/59 Temple Place,/51 Franklin Street,/
+s/59 Temple Place -/51 Franklin Street,/
+s/Suite 330,/Fifth Floor,/
+s/Suite 330$/Fifth Floor/
+s/02111-1307/02110-1301/
+
+# Very old address: 675 Mass Ave, Cambridge, MA 02139
+s/675 Mass Ave/51 Franklin Street, Fifth Floor/
+s/Cambridge/Boston/
+s/02139/02110-1301/
+# Warning: the last two replaces seem to match the address of the MIT too.
+
+# Typo in KDE: Franklin Steet
+s/Franklin Steet/Franklin Street/
diff --git a/scripts/fixheaders b/scripts/fixheaders
new file mode 100644
index 00000000..b1b0a15b
--- /dev/null
+++ b/scripts/fixheaders
@@ -0,0 +1,214 @@
+#! /usr/bin/env perl
+
+# this script is written by Stephan Kulow <coolo@kde.org> with
+# much help from Sirtaj Singh Kang <ssk@physics.unimelb.edu.au>
+
+if ($ARGV[0]) {
+ $topdir = $ARGV[0];
+} else {
+ $topdir=`pwd`;
+}
+chomp $topdir;
+
+$lastdir = '.';
+
+
+# this is the important part. Left from the '=>' you find the regular
+# expression for the g++ output and right from '=>' the header file to
+# include
+%messages =
+(
+ 'implicit declaration of function `int i18n\(\.\.\.\)\'' => "klocale",
+ '`i18n\' undeclared \(first use this function\)' => "klocale",
+ 'variable `class QPixmap \S*\' has initializer but incomplete type' => "qpixmap",
+ '`kapp\' undeclared \(first use this function\)' => "kapplication",
+ 'no matching function for call to `KLocale::' => "klocale",
+ '`klocale\' undeclared \(first use this function\)' => "klocale",
+ 'no matching function for call to `QPopupMenu::' => "qpopupmenu",
+ '`QTextStream\' undeclared \(first use this function\)' => "qtextstream",
+ '`QTextStream\' was not declared in this scope' => "qtextstream",
+ 'incomplete type `QSocketNotifier\'' => "qsocketnotifier",
+ 'no matching function for call to `KConfig' => "kconfig",
+ 'variable `class KConfig \S*\' has initializer but incomplete type' => "kconfig",
+ 'implicit declaration of function `int kdDebug' => "kdebug",
+ 'implicit declaration of function `int kdWarning' => "kdebug",
+ '`QFile\' undeclared \(first use this function' => "qfile",
+ 'variable `QFile \S*\' has initializer but incomplete type' => "qfile",
+ 'type `KConfigBase\' is not a base type for type `KConfig' => "kconfig",
+ 'invalid use of undefined type `class QAccel' => "qaccel",
+ 'invalid use of undefined type `class KAboutData' => "kaboutdata",
+ 'incomplete type `KAboutData\'' => "kaboutdata",
+ 'incomplete type `QGrid\'' => "qgrid",
+ 'invalid use of undefined type `class QGrid\'' => "qgrid",
+ 'aggregate `class KConfig \S*\' has incomplete type' => "kconfig",
+ '`stderr\' undeclared \(first use this function' => "stdio",
+ 'invalid use of undefined type `class KConfig' => "kconfig",
+ 'implicit declaration of function `int f?printf' => "stdio",
+ 'no method `KGlobal::' => "kglobal",
+ '`KGlobal\' undeclared \(first use this function\)' => "kglobal",
+ 'implicit declaration of function `int locate\(\.\.\.\)' => "kstddirs",
+ '`locate\' undeclared \(first use this function\)' => "kstddirs",
+ 'no matching function for call to `KStandardDirs' => "kstddirs",
+ 'no method `KStandardDirs::' => "kstddirs",
+ 'variable `class QFile \S*\' has initializer but incomplete type' => "qfile",
+ 'implicit declaration of function `int ICON\(\.\.\.\)' => "kiconloader",
+ '`QMessageBox\' undeclared \(first use this function\)' => "qmessagebox",
+ 'no matching function for call to `QBoxLayout::QBoxLayout' => "qlayout",
+ '`QUriDrag\' undeclared \(first use this function\)' => "qdragobject",
+ '`kdDebug\' undeclared \(first use this function\)' => "kdebug",
+ '`kdWarning\' undeclared \(first use this function\)' => "kdebug",
+ 'no matching function for call to `KMenuBar::insertItem\(QString, KPopupMenu' => "kpopupmenu",
+ 'no matching function for call to `KMenuBar::' => "kmenubar",
+ 'invalid use of undefined type `class QPointArray' => "qpointarray",
+ 'variable `QPainter \S*\' has initializer but incomplete type' => "qpainter",
+ 'invalid use of undefined type `class QRegExp' => "qregexp",
+ 'invalid use of undefined type `class QPushButton' => "qpushbutton",
+ 'cannot convert `QPushButton \*\' to `QButton \*' => "qpushbutton",
+ 'invalid use of undefined type `class QButton' => "qbutton",
+ '`QButton\' undeclared \(first use this function\)' => "qbutton",
+ 'no method `QCursor::pos' => "qcursor",
+ '`DesktopIcon\' undeclared \(first use this function\)' => "kiconloader",
+ '`BarIcon\' undeclared \(first use this function\)' => "kiconloader",
+ '`SmallIcon\' undeclared \(first use this function\)' => "kiconloader",
+ '`UserIcon\' undeclared \(first use this function\)' => "kiconloader",
+ 'implicit declaration of function `int UserIcon\(...\)\'' => "kiconloader",
+ '`KIcon\' undeclared \(first use this function\)' => "kiconloader",
+ 'invalid use of undefined type `class KIconLoader' => "kiconloader",
+ 'invalid use of undefined type `class KInstance' => "kinstance",
+ 'invalid use of undefined type `class DCOPClient' => "dcopclient",
+ '`DCOPClient\' undeclared \(first use this function\)' => "dcopclient",
+ 'invalid use of undefined type `class KStatusBar\'' => "kstatusbar",
+ 'invalid use of undefined type `class QLabel\'' => "qlabel",
+ 'invalid use of undefined type `class QImage\'' => "qimage",
+ 'invalid use of undefined type `class QImageIO\'' => "qimage",
+ 'invalid use of undefined type `class QLineEdit\'' => "qlineedit",
+ 'invalid use of undefined type `class QComboBox\'' => "qcombobox",
+ 'invalid use of undefined type `class QStyle\'' => "qstyle",
+ 'invalid use of undefined type `class KPopupMenu\'' => "kpopupmenu",
+ 'invalid use of undefined type `class QPopupMenu\'' => "qpopupmenu",
+ 'cannot convert `KPopupMenu \*\' to `QPopupMenu \*' => "kpopupmenu",
+ 'aggregate `QPopupMenu \S*\' has incomplete type' => "qpopupmenu",
+ 'invalid use of undefined type `class KURL' => "kurl",
+ 'no method `QApplication::' => "qapplication",
+ 'no method `QFile::' => "qfile",
+ 'error: \'Q3CString\' is used as a type' => "q3cstring",
+ 'error: ISO C\+\+ forbids declaration of \`Q3CString\' with' => "q3cstring",
+ 'error: incomplete type \'QPixmap\' cannot be used' => 'qpixmap',
+ 'error: invalid use of undefined type `struct QVector' => 'qvector',
+ 'error: incomplete type `Q3ValueList' => 'q3valuelist',
+ 'error: variable `Q3ValueList<' => 'q3valuelist',
+ 'error: `Q3PointArray\' undeclared' => 'q3pointarray',
+ 'error: invalid use of undefined type \`struct QColor' => 'qcolor',
+ 'error: `QX11Info::' => 'qx11info_x11',
+ 'error: incomplete type \'QX11Info' => 'qx11info_x11',
+ 'error: \'Q3AsciiDi' => 'q3asciidict'
+);
+
+# Initial values are simply to get into the while
+$exitcode=2; # exit-code from last 'make' command
+$addedone=1; # 1 when something has been fixed, means we can try again
+
+while ( $exitcode != 0 && $addedone != 0 )
+{
+ $addedone = 0;
+
+ %changes = ();
+ open(INPUT,"makeobj -j10 -k 2>&1 |") || die "Couldn't run makeobj";
+ while(<INPUT>)
+ {
+ if (/make.*Entering directory \`(.+)\'/) {
+ $lastdir = $1;
+ $lastdir =~ s/^$topdir\///;
+ print STDERR "entering $lastdir\n";
+ next;
+ }
+ if (/^([^:]*):\d*: (.*)$/) {
+ $file = $1;
+ $line = $2;
+ if ($file !~ m,^\/,) {
+ $file = "$lastdir/$file";
+ }
+ #print STDERR "file=$file\n";
+ } else {
+ # This could be a continuation line
+ if ( defined $line && $line ne "" ) {
+ $line .= $_;
+ #print STDERR "file still $file\n";
+ #print STDERR "line=$line\n";
+ } else {
+ # Compilation line, or other unparsable line -> ignore
+ print STDOUT $_;
+ next;
+ }
+ }
+
+ #print STDERR "Already having changes for $file\n" if defined($changes{$file});
+ next if defined($changes{$file});
+
+ print STDOUT $_;
+
+ foreach $message (keys %messages) {
+ if ($line =~ /$message/) {
+ $changes{$file} = $messages{$message};
+ $addedone = fixFile($file, $messages{$message});
+ }
+ }
+
+ if (defined($changes{$file})) { $file=""; $line=""; }
+ } # end of while(<INPUT>)
+ close(INPUT);
+ $exitcode=($?>>8);
+} # end of main while
+
+sub fixFile
+{
+ my( $file, $adding ) = @_;
+
+ my $lastinclude = "";
+
+ # read file
+ open ( FILE, "$file" ) || die "Can't read $file";
+
+ my $flines;
+ my $cpplevel = 0;
+
+ while (<FILE>) {
+ $flines .= $_;
+ if ($_ =~ m/^#if/ && $_ !~ m/^#ifn/) {
+ $cpplevel = $cpplevel + 1;
+ }
+ if ($_ =~ m/^#endif/) {
+ $cpplevel = $cpplevel - 1;
+ }
+ if ($cpplevel == 0 && $_ =~ m/^(#include\s*[\"<]q\S*\.h[\">]\S*)/) {
+ $lastinclude = $1;
+ }
+ }
+
+ close FILE;
+
+ if (!$lastinclude) {
+ print STDERR "ERROR: no include found in $file! (tried to add $adding.h)\n";
+ return 0;
+ }
+
+ if ($flines =~ m/#include\s*[\"<]$adding\.h[\">]\s*\n/) {
+ print STDERR "ERROR: $adding.h already included in $file!\n";
+ return 0;
+ }
+ if ($flines =~ /(\n$lastinclude)/) {
+ $flines =~ s/$lastinclude(.*\n)/$lastinclude$1#include <$adding.h>\n/;
+ print STDERR "ADDED <$adding.h> after \"$lastinclude\" in $file\n";
+ } else {
+ print STDERR "ERROR: can't find $lastinclude in $file\n";
+ return 0;
+ }
+
+ # write file
+
+ rename($file, "$file.old");
+ open( FILE, ">$file" ) || die "Can't write to $file";
+ print FILE $flines;
+ close FILE;
+ return 1;
+}
diff --git a/scripts/fixkdeincludes b/scripts/fixkdeincludes
new file mode 100644
index 00000000..54e4e9f6
--- /dev/null
+++ b/scripts/fixkdeincludes
@@ -0,0 +1,756 @@
+#!/usr/bin/perl -w
+# tries to reduce the number of includes in KDE source files
+# (c) 2001-2003 Dirk Mueller <mueller@kde.org>
+
+use File::Basename;
+use Cwd;
+
+# declaration of useful subroutines
+sub find_src_includes($);
+sub find_fixable_sources ($);
+sub find_fixable_headers($);
+sub find_removable_includes ($);
+sub warn_before_modifying ($);
+sub remove_include ($$$);
+sub replace_include ($$$);
+sub replace_include_type ($$);
+sub fix_duplicates($);
+sub fix_compat_includes($);
+sub fix_unnecessary($);
+sub fix_include_type($);
+sub copy_file($$);
+sub process_source_file($);
+sub extract_gcc_error($);
+
+# some global variables
+$verbose = 0; # turns on debugging
+$modify = 0; # if 1 it should try to fix the files as well
+$experimental = 0; # try&error if an include is obsolete (slow!!)
+@explicitfiles = (); # filled in if passing files on the command line
+
+# statistic variables
+$exp_success = 0;
+$exp_failure = 0;
+
+while (defined ($ARGV[0]))
+{
+ $_ = shift;
+ if (/^--help$|^-h$/) {
+ print "Usage: fixkdeincludes [--verbose | -v] [--experimental | -e ] [--modify | -m ]\n";
+ exit 0;
+ }
+ elsif (/^--verbose$|^-v$/) {
+ $verbose = 1; # Oh is there a problem...?
+ }
+ elsif (/^--modify$|^-m$/) {
+ $modify = 1;
+ }
+ elsif (/^--experimental$|^-e$/) {
+ $modify = 1;
+ $experimental = 1;
+ }
+ elsif (!/^-/) {
+ push @explicitfiles, $_;
+ }
+}
+
+$cppExt = "(cpp|cc|cxx|C|c\\+\\+)";
+$hExt = "(h|H|hh|hxx|hpp|h\\+\\+)";
+
+# list of compat headers. scroll down ... much of boring stuff here..
+%compatmap = (
+ 'qapp.h' => "qapplication.h",
+ 'qarray.h' => "qmemarray.h",
+ 'qbitarry.h' => "qbitarray.h",
+ 'qbttngrp.h' => "qbuttongroup.h",
+ 'qchkbox.h' => "qcheckbox.h",
+ 'qclipbrd.h' => "qclipboard.h",
+ 'qcollect.h' => "qptrcollection.h",
+ 'qcollection.h' => "qptrcollection.h",
+ 'qcombo.h' => "qcombobox.h",
+ 'qconnect.h' => "qconnection.h",
+ 'qdatetm.h' => "qdatetime.h",
+ 'qdrawutl.h' => "qdrawutil.h",
+ 'qdstream.h' => "qdatastream.h",
+ 'qfiledef.h' => "private/qfiledefs_p.h",
+ 'qfiledlg.h' => "qfiledialog.h",
+ 'qfileinf.h' => "qfileinfo.h",
+ 'qfontdta.h' => "qfontdata.h",
+ 'qfontinf.h' => "qfontinfo.h",
+ 'qfontmet.h' => "qfontmetrics.h",
+ 'qgrpbox.h' => "qgroupbox.h",
+ 'qintcach.h' => "qintcache.h",
+ 'qiodev.h' => "qiodevice.h",
+ 'qlcdnum.h' => "qlcdnumber.h",
+ 'qlined.h' => "qlineedit.h",
+ 'qlist.h' => "qptrlist.h",
+ 'qmenudta.h' => "qmenudata.h",
+ 'qmetaobj.h' => "qmetaobject.h",
+ 'qmlined.h' => "qtmultilineedit.h",
+ 'qmsgbox.h' => "qmessagebox.h",
+ 'qmultilinedit.h' => "qmultilineedit.h",
+ 'qobjcoll.h' => "qobjectlist.h>\n\#include <qobjectdict.h",
+ 'qobjdefs.h' => "qobjectdefs.h",
+ 'qpaintd.h' => "qpaintdevice.h",
+ 'qpaintdc.h' => "qpaintdevicedefs.h",
+ 'qpdevmet.h' => "qpaintdevicemetrics.h",
+ 'qpmcache.h' => "qpixmapcache.h",
+ 'qpntarry.h' => "qpointarray.h",
+ 'qpopmenu.h' => "qpopupmenu.h",
+ 'qprndlg.h' => "qprintdialog.h",
+ 'qprogbar.h' => "qprogressbar.h",
+ 'qprogdlg.h' => "qprogressdialog.h",
+ 'qpsprn.h' => "private/qpsprinter_p.h",
+ 'qpushbt.h' => "qpushbutton.h",
+ 'qqueue.h' => "qptrqueue.h",
+ 'qradiobt.h' => "qradiobutton.h",
+ 'qrangect.h' => "qrangecontrol.h",
+ 'qscrbar.h' => "qscrollbar.h",
+ 'qsocknot.h' => "qsocketnotifier.h",
+ 'qstack.h' => "qptrstack.h",
+ 'qtabdlg.h' => "qtabdialog.h",
+ 'qtstream.h' => "qtextstream.h",
+ 'qvector.h' => "qptrvector.h",
+ 'qwidcoll.h' => "qwidgetlist.h>\n\#include <qwidgetintdict.h",
+ 'qwindefs.h' => "qwindowdefs.h",
+
+# and now the KDE specific compat includes
+ 'kapp.h' => "kapplication.h",
+ 'kstddirs.h' => "kstandarddirs.h",
+ 'kuniqueapp.h' => "kuniqueapplication.h",
+ 'ktmainwindow.h'=> "kmainwindow.h",
+ 'kcolorbtn.h' => "kcolorbutton.h",
+ 'kcolordlg.h' => "kcolordialog.h",
+ 'kxmlgui.h' => "kxmlguifactory.h",
+ 'kdebugclasses.h' => "kdebug.h",
+);
+
+
+# now it starts to get interesting again
+
+# Look for source files in the given directory ($dir, first parameter)
+sub find_fixable_sources ($)
+{
+ # for now I grep the directory (requires srcdir==builddir)
+ # actually it should read the Makefile and
+ # find the _SOURCES / _OBJECTS tags that are put there by
+ # automake and am_edit, but thats an excercise to the reader ;-)
+
+ my ( $dir ) = @_;
+
+ opendir (DIR, "$dir") || die "Couldn't read '$dir'\n";
+ my @sources = grep { /^.*\.$cppExt$/o } readdir(DIR);
+ closedir(DIR);
+
+ print "found sources: [ " . join(' ', @sources) . " ] in $dir\n" if ($verbose);
+
+ # prefix them with $dir
+ my @retsources = ();
+ foreach $source(@sources) {
+ push @retsources, "$dir/$source";
+ }
+
+ return @retsources;
+}
+
+# Look for header files in the given directory ($dir, first parameter)
+sub find_fixable_headers ($)
+{
+ # for now I grep the directory (requires srcdir==builddir)
+ # actually it should read the Makefile and
+ # find the _HEADERS tags that are put there by
+ # automake and am_edit, but thats an excercise to the reader ;-)
+
+ my ( $dir ) = @_;
+
+ opendir (DIR, "$dir") || die "Couldn't read '$dir'\n";
+ my @headers = grep { /^.*\.$hExt$/o } readdir(DIR);
+ closedir(DIR);
+
+ print "found headers: [ " . join(' ', @headers) . " ] in $dir\n" if ($verbose);
+
+ # prefix them with $dir
+ my @retheaders = ();
+ foreach $source(@headers) {
+ push @retheaders, "$dir/$source";
+ }
+
+ return @retheaders;
+}
+
+sub find_removable_includes ($)
+{
+ my $srcfile = shift @_;
+ open(SRC, "< $srcfile") || die "find_removable_includes: couldn't open '$srcfile'\n";
+
+ my @includes = ();
+
+ # we skip all includes that are somehow ifdefed
+
+ my $cpplevel = 0;
+ $cpplevel = -1 if ($srcfile=~m/^.*\.$hExt$/); # plan for header-protection #ifndef/#define/#endif
+ while (<SRC>) {
+ if ($_ =~ m/^\#if/) {
+ $cpplevel = $cpplevel + 1;
+ next;
+ }
+ if ($_ =~ m/^\#endif/) {
+ $cpplevel = $cpplevel - 1;
+ next;
+ }
+ #if ($cpplevel == 0 && $_ =~ m/^\#include\s*[\"<]([qk]\S*\.h)[\">]\S*/) {
+ if ($cpplevel == 0 && (($_ =~ m/^\#include\s*\"(\S+\.h)\"\S*/) || ($_ =~ m/^\#include\s*\<([qk]\S+.h)\>\S*/))) {
+ push @includes, $1;
+ next;
+ }
+ }
+ close SRC;
+
+ print "No fixable includes found in $srcfile\n" if ($verbose and not @includes);
+ print "found includes: [ " . join(' ', @includes) . " ]\n" if ($verbose and @includes);
+
+ return @includes;
+}
+
+sub find_installed_headers($)
+{
+ my $sdir = shift @_;
+ my @includes = ();
+
+ open(I, "<$sdir/Makefile.am") || die "couldn't open $sdir/Makefile.am $!";
+
+ my $data = join('', <I>);
+ $data =~ s/\\\s*\n/ /g;
+
+ # now search for not installed headers
+ foreach my $line (split /^/, $data) {
+ if($line =~ /^(\w+)_HEADERS\s*=(.*)$/) {
+ next if $1 eq "noinst";
+ push @includes, split (' ', $2);
+ }
+ }
+ close(I);
+ return @includes;
+}
+
+# first parameter: srcfile
+# second parameter: include to remove
+# third parameter is the duplicate level: this include is removed $level times
+sub remove_include ($$$)
+{
+ my $srcfile = shift @_;
+ my $include = quotemeta(shift @_);
+ my $level = shift @_;
+
+ die "$srcfile is not read/writeable!\n" if( ! -r $srcfile || ! -w $srcfile);
+ open(I, "< $srcfile") or die "remove_include: couldn't open '$srcfile'\n";
+ my @contents = <I>;
+ close(I);
+
+ # ok, CPU time doesn't count so we do it the lazy way
+ # we should remove the last occurence of the include in the
+ # file because in case its a duplicate removing the first
+ # one could make a difference.
+ my @revcontents = reverse @contents;
+ @contents = ();
+
+ # we skip all inludes that are somehow ifdefed
+ # note the logic is reversed because it operates
+ # on reversed lines :)
+ my $cpplevel = 0;
+ $cpplevel = -1 if ($srcfile=~m/^.*\.$hExt$/); # plan for header-protection #ifndef/#define/#endif
+ foreach $line (@revcontents) {
+ if ($line =~ m/^\#if/) {
+ $cpplevel = $cpplevel - 1;
+ push @contents, $line;
+ next;
+ }
+
+ if ($line =~ m/^\#endif/) {
+ $cpplevel = $cpplevel + 1;
+ push @contents, $line;
+ next;
+ }
+
+ if ($level && $cpplevel == 0 &&
+ (($line =~ m/^\#include\s*\"$include\"\S*/) || ($line =~ m/^\#include\s*\<$include\>\S*/))) {
+ $level = $level - 1;
+ # skipping the line..
+ next;
+ }
+
+ push @contents, $line;
+ }
+
+ # now we have the fixed contents in @contents, although in wrong order
+ open(O, "> $srcfile") || die "remove_include: couldn't open '$srcfile' for writing\n";
+ print O reverse @contents;
+ close (O);
+}
+
+# first parameter: srcfile
+# second parameter: include to replace
+# third parameter the include file to replace it with
+sub replace_include ($$$)
+{
+ my $srcfile = shift @_;
+ my $include = quotemeta(shift @_);
+ my $destinclude = shift @_;
+
+ die "$srcfile is not read/writeable!\n" if( ! -r $srcfile || ! -w $srcfile);
+ open(I, "< $srcfile") or die "replace_include: couldn't open '$srcfile'\n";
+ my @contents = <I>;
+ close(I);
+
+ # ok, CPU time doesn't count so we do it the lazy way
+ my @revcontents = reverse @contents;
+ @contents = ();
+
+ # we skip all inludes that are somehow ifdefed
+ # note the logic is reversed because it operates
+ # on reversed lines :)
+ my $cpplevel = 0;
+ $cpplevel = -1 if ($srcfile=~m/^.*\.$hExt$/); # plan for header-protection #ifndef/#define/#endif
+ foreach $line (@revcontents) {
+ if ($line =~ m/^\#if/) {
+ $cpplevel = $cpplevel - 1;
+ push @contents, $line;
+ next;
+ }
+
+ if ($line =~ m/^\#endif/) {
+ $cpplevel = $cpplevel + 1;
+ push @contents, $line;
+ next;
+ }
+
+ if ($cpplevel == 0 &&
+ (($line =~ m/^\#include\s*\"$include\"\S*/) || ($line =~ m/^\#include\s*\<$include\>\S*/)))
+ {
+ print "HAH! found $include to replace in $srcfile!\n" if($verbose);
+ $line =~ s/(\#include\s*[\"<])$include([\">]\S*)/$1$destinclude$2/;
+ }
+
+ push @contents, $line;
+ }
+
+ # now we have the fixed contents in @contents
+ open(O, "> $srcfile") || die "replace_include: couldn't open '$srcfile' for writing\n";
+ print O reverse @contents;
+ close (O);
+}
+
+# fixes #include <foo.h> -> #include "foo.h"
+sub replace_include_type ($$)
+{
+ my ($srcfile, $include) = @_;
+
+ die "$srcfile is not read/writeable!\n" if( ! -r $srcfile || ! -w $srcfile);
+ open(I, "< $srcfile") or die "replace_include: couldn't open '$srcfile'\n";
+ my @contents = <I>;
+ close(I);
+
+ grep(s/^(\#include)\s*<$include>(.*)$/$1 \"$include\"$2/, @contents);
+
+ # now we have the fixed contents in @contents
+ open(O, "> $srcfile") || die "replace_include: couldn't open '$srcfile' for writing\n";
+ print O @contents;
+ close (O);
+}
+
+sub fix_duplicates($)
+{
+ my $srcfile = shift @_;
+
+ my @includes = &find_removable_includes($srcfile);
+
+ my %inclMap = ();
+
+ # initialize
+ foreach $include (@includes) {
+ $inclMap{$include} = 0;
+ }
+
+ # count number of occurences
+ foreach $include (@includes) {
+ $inclMap{$include} = $inclMap{$include} + 1;
+ }
+
+ # check for duplicates
+ foreach $include (keys %inclMap) {
+ next if $inclMap{$include} <= 1;
+
+ print "$srcfile: duplicate level ". $inclMap{$include} .": ". $include ."\n";
+
+ &remove_include($srcfile, $include, $inclMap{$include} - 1) if($modify);
+ }
+}
+
+sub extract_gcc_error($)
+{
+ my $out = shift;
+
+ # print "out: $out\n";
+
+ while ($out =~ m/^(.*?):([0-9]+):(.*)$/mg) # filename:lineno:message
+ {
+ my $field1 = $1 || "";
+ my $field2 = $2 || "";
+ my $field3 = $3 || "";
+
+ # print "f1: $field1, f2: $field2, f3: $field3\n";
+
+ next if ($field3 =~ m/\s+warning:.*/);
+ next if ($field3 =~ m/^\s*$/);
+ return basename($field1);
+ }
+ return "BUG!";
+}
+
+sub fix_compat_includes($)
+{
+ my $srcfile = shift @_;
+
+ my @includes = &find_removable_includes($srcfile);
+
+ my %inclMap = ();
+
+ # initialize
+ foreach $include (@includes) {
+ $inclMap{$include} = 0;
+ }
+
+ # count number of occurences
+ foreach $include (@includes) {
+ $inclMap{$include} = $inclMap{$include} + 1;
+ }
+
+ # check for compat headers
+ foreach $include (keys %inclMap) {
+ if( defined $compatmap{$include}) {
+ print "$srcfile: compat header: $include, to be replaced by ". $compatmap{$include} ."\n";
+ &replace_include($srcfile, $include, $compatmap{$include}) if($modify);
+ }
+ }
+}
+
+sub fix_include_type($)
+{
+ my $srcfile = shift @_;
+ my $srcdir = dirname($srcfile);
+
+ open(I, "<$srcfile") || die "couldn't open $srcfile in _fix_include_type";
+ my @bracketincs = grep s/^\s*\#include\s*<([^>]+)>\s*$/$1/, <I>;
+ close(I);
+
+ foreach my $include (@bracketincs) {
+ next if (!(-r "$srcdir/$include"));
+ next if (grep (/^$include$/, @instheaders));
+ next if ($include eq "config.h"); # oh don't get me started on that
+
+ print "$srcfile: #include <$include> should use #include \"...\"\n";
+ &replace_include_type($srcfile, $include) if($modify);
+ }
+}
+
+# copies a file from src to dest, overwrites destination if exists
+sub copy_file($$)
+{
+ my $src = shift(@_);
+ my $dst = shift(@_);
+
+ open(I, "< $src") or die "copy_file: can't open $src for input\n";
+ my @fcontents = <I>;
+ close(I);
+ open(O, "> $dst") or die "copy_file: can't open $dst for output\n";
+ print O @fcontents;
+ close(O);
+}
+
+# interrupt handler for fix_unnecessary
+sub sighandler_fix_unnecessary()
+{
+ my($sig) = @_;
+ print "Caught a SIG$sig--shutting down after restoring $srcfile\n";
+ chdir($srcdir);
+ unlink $srcfile || warn "couldn't unlink $srcfile";
+ rename $localbackup, $srcfile || warn "couldn't rename $localbackup to $srcfile";
+ exit(1);
+}
+
+sub fix_unnecessary($)
+{
+ local $srcfile = shift @_;
+ local $srcdir = dirname($srcfile);
+
+ # find canonical path for srcdir
+ my $origdir = cwd;
+ chdir($srcdir);
+ $srcdir = cwd;
+ print "srcdir=$srcdir\n" if($verbose);
+
+ my $builddir = $srcdir;
+ my $makecmd = "make";
+ if (defined $ENV{"OBJ_REPLACEMENT"})
+ {
+ # we have to use sed here, because perl can't do s#a#b#
+ $builddir = `echo $srcdir | sed -e "\$OBJ_REPLACEMENT"`;
+ chomp $builddir;
+ $makecmd = "makeobj";
+ }
+ print "builddir=$builddir\n" if($verbose);
+
+ my $tot = $exp_success + $exp_failure;
+ print "=============== $srcfile (successes: $exp_success; total: $tot)\n";
+
+ $srcfile = basename($srcfile);
+
+ # first figure out some details
+ my @includes = &find_removable_includes($srcfile);
+
+ my $blanksrc = $srcfile;
+ $blanksrc =~ s/(.*)\.[^\.]+/$1/;
+
+ print "Checking for initial compilation: ";
+ chdir($builddir);
+ my $objextension = "BUG";
+ if($srcfile =~ /\.$hExt$/o) {
+ $output = `$makecmd all 2>&1`;
+ $objextension = "all" if ( 0 == ($? >> 8));
+ }
+ else {
+ unlink "$blanksrc.lo";
+ my $output = `$makecmd $blanksrc.lo 2>&1`;
+ $objextension = ".lo" if ( 0 == ($? >> 8));
+ if($objextension eq "BUG") {
+ print "failed with .lo... ";
+ unlink "$blanksrc.o";
+ $output = `$makecmd $blanksrc.o 2>&1`;
+ $objextension = ".o" if ( 0 == ($? >> 8));
+ }
+ if($srcfile =~ /$hExt/) {
+ $output = `$makecmd $blanksrc.o 2>&1`;
+ $objextension = ".o" if ( 0 == ($? >> 8));
+ }
+ }
+ if($objextension eq "BUG") {
+ warn "can't figure out right compile command for $srcfile :-(\n" .
+ "??? unused, or didn't compile in the first place?\n" .
+ "$output";
+ chdir($origdir);
+ exit 1;
+ }
+
+ print "worked with $objextension\n";
+
+ # now try to drop some includes
+ foreach $include (@includes) {
+ # kdatastream is special because
+ # it will break the application if removed even
+ # if it continues to compile
+ next if( $include eq "kdatastream.h");
+ # I also like to have kdebug.h still in
+ # so that it's easy to add kdDebug calls
+ next if( $include eq "kdebug.h");
+ # avoid this one as it might cause
+ # certain code parts to be disabled from compilation
+ next if( $include eq "qmodules.h");
+ # don't remove this one either. causes conditional
+ # code to be compiled incorrectly
+ next if( $include eq "kdeversion.h");
+ # don't remove the config.h include
+ # conditional code may depend on this file
+ next if( $include eq "config.h");
+ # check if it is its own header file
+ my $blankhdr = $include;
+ $blankhdr =~ s/(.*)\.[^\.]+/$1/;
+ next if ($blankhdr eq $blanksrc);
+
+ chdir($srcdir);
+
+ local $localbackup = $srcfile . "#fixkdeincludes";
+
+ # preserve timestamp if possible for CVS
+ unlink $localbackup;
+ rename $srcfile, $localbackup;
+ copy_file($localbackup, $srcfile);
+
+ # revert to backup in case of interrupt (Ctrl+C)
+ $SIG{'INT'} = \&sighandler_fix_unnecessary;
+
+ # check if it still compiles
+ if($verbose) {
+ chdir($builddir);
+ # testing headers? need to compile everything
+ if($objextension eq "all") {
+ # wait a second for makefile timestamp comparisons
+ sleep 1;
+ `$makecmd all 2>&1`;
+ }
+ else {
+ unlink "$blanksrc$objextension";
+ `$makecmd $blanksrc$objextension 2>&1`;
+ }
+ die "unexpected error $output\nexitcode=" . ($? >> 8) if($? >> 8);
+ chdir($srcdir);
+ }
+
+ # duplicates have to be nuked here , so it will be dropped maximum once
+ print "trying without $include: ";
+ &remove_include($srcfile, $include, 1);
+
+ chdir($builddir);
+
+ # try if it compiles
+ if($objextension eq "all") {
+ sleep 1;
+ $output=`$makecmd $objextension 2>&1`;
+ }
+ else {
+ unlink "$builddir/$blanksrc$objextension";
+ $output=`$makecmd $blanksrc$objextension 2>&1`;
+ }
+ my $retcode = ($? >> 8);
+ #print "retcode=$retcode\n$output" if ($verbose);
+
+ chdir($srcdir);
+ if($retcode == 0) {
+ # wow, it worked, lets continue!
+ print "SUCCESS!\n";
+ $SIG{'INT'} = 'DEFAULT';
+ unlink $localbackup;
+ $exp_success = $exp_success + 1;
+ }
+ else {
+ # is this a fixable error?
+ if($objextension eq "all" and
+ &extract_gcc_error($output) ne $srcfile) {
+ print "failed (error in " . &extract_gcc_error($output) . ")\n";
+ # FIXME: implement fixup of the compilation error
+ # so that we can be much more agressive in removing
+ # unneeded includes from headers
+ }
+ else
+ {
+ # better luck next time
+ print "FATALLY failed\n";
+ }
+ unlink $srcfile;
+ rename $localbackup, $srcfile;
+ $SIG{'INT'} = 'DEFAULT';
+
+ $exp_failure = $exp_failure + 1;
+ }
+ }
+
+ print "\n";
+
+ chdir($origdir);
+}
+
+sub process_source_file($)
+{
+ local $file = shift @_;
+ my $pure = basename($file);
+ print "Checking: $file\n" if($verbose);
+ &fix_include_type($file);
+ &fix_compat_includes($file);
+ &fix_duplicates($file);
+ &fix_unnecessary($file) if ($experimental && !grep (/^$pure$/, @instheaders));
+ print "\n" if ($verbose);
+}
+
+sub check_for_automake_srcdir($)
+{
+ my $dir = shift;
+
+ return 0 if !( -r "$dir/Makefile.am");
+ return 1 if !( -r "$dir/Makefile");
+
+ # ok, now its either srcdir with srcdir==builddir, or its builddir,
+ # which we don't want.
+
+ open(I, "<$dir/Makefile") || die "couldn't read $dir/Makefile";
+ while(<I>) {
+ if(/^srcdir\s*=\s*(\S+)/) {
+ close(I);
+
+ if($1 ne ".") {
+ print "Skipping build dir: $dir\n" if($verbose);
+ return 0;
+ }
+ return 1;
+ }
+ }
+
+ close(I);
+ # ok, this makefile isn't generated by automake, we don't want that
+ return 0;
+}
+
+#############################################################################
+# here is the main logic
+#
+
+# warn about modified files
+if($modify) {
+ `cvscheck | grep '^[MmC]'`;
+ print "WARNING: you have pending local changes. You might commit them by accident!\n\n" if($? >> 8 == 0);
+}
+
+if($experimental) {
+ print "WARNING: The experimental mode is indeed experimental.\n";
+ print "It tries to reduce includes by testing if it would compile\n";
+ print "without a particular include. It might introduce subtle bugs\n";
+ print "or break compilation for make check or make final.\n\n";
+ print "This operation mode is known to be unsafe. You've been warned.\n";
+}
+
+# process files from the command line, if any
+if ( $#explicitfiles >= 0 ) {
+ foreach $file( @explicitfiles ) {
+ &process_source_file( $file );
+ }
+ exit 0;
+}
+
+# first generate a list of subdirectories
+@dirlist = ();
+push @dirlist, "." if (&check_for_automake_srcdir("."));
+die "current directory isn't srcdir!" if (!scalar @dirlist);
+foreach $dir ( @dirlist ) {
+ opendir (DIR, "$dir") || warn "Couldn't read '$dir'";
+ my $subdir = "";
+ while( $subdir = readdir(DIR)) {
+ next if ($subdir =~ /^\./);
+ next if !( -d "$dir/$subdir");
+ next if (! &check_for_automake_srcdir("$dir/$subdir"));
+
+ push @dirlist, "$dir/$subdir";
+ }
+ closedir(DIR);
+}
+
+# now iterate over all subdirs
+foreach $dir(@dirlist) {
+
+ # check if this directory wants not to be fixed
+ if(open(M, "$dir/Makefile.am")) {
+ my @mcontents = grep /(\-UQT_NO_COMPAT|\-UKDE_NO_COMPAT)/, <M>;
+ close(M);
+ if ( @mcontents ) {
+ print "Skipping directory: $dir\n";
+ next;
+ }
+ }
+
+ @headers = &find_fixable_headers($dir);
+ @instheaders = &find_installed_headers($dir);
+ foreach $file(@headers) {
+ &process_source_file($file);
+ }
+ @sources = &find_fixable_sources($dir);
+ foreach $file(@sources) {
+ &process_source_file($file);
+ }
+}
diff --git a/scripts/fixuifiles b/scripts/fixuifiles
new file mode 100755
index 00000000..785b45b4
--- /dev/null
+++ b/scripts/fixuifiles
@@ -0,0 +1,293 @@
+#!/usr/bin/perl -w
+# fixuifiles processes .ui files and removes some insanity:
+# * Too high minimum Qt version (see $minversion_* in the top of the script)
+# * Hardcoded untranslatable Alt+Letter accels (auto-added by Qt Designer)
+# * Captions that are equal to classname (auto-added by Qt Designer)
+
+# This script is licensed under the GPL version 2.
+# (c) 2004 David Faure <faure@kde.org>
+# Based on fixkdeincludes, (c) 2001-2003 Dirk Mueller <mueller@kde.org>
+
+use strict;
+use File::Basename;
+use Cwd;
+
+# Fix the version number in .ui files if it's bigger than this:
+my $default_minversion_maj = 3;
+my $default_minversion_min = 3;
+
+# Known words which are ok as captions
+my %knowncaptions = (
+ 'Settings' => '',
+ 'Statistics' => '',
+ 'General' => '',
+ 'Tracks' => '',
+ 'Constants' => '',
+ 'Preferences' => '',
+ 'Encryption' => ''
+);
+
+# declaration of useful subroutines
+sub process_ui_file($);
+sub find_ui_files($);
+sub read_required_version($);
+
+# some global variables
+my $verbose = 0; # turns on debugging
+my $omit_Qt_check = 0; # turns off Qt version checking
+my @explicitfiles = (); # filled in if passing files on the command line
+my $minversion_maj = $default_minversion_maj;
+my $minversion_min = $default_minversion_min;
+
+while (defined ($ARGV[0]))
+{
+ $_ = shift;
+ if (/^--help$|^-h$/) {
+ print "Usage: fixuifiles [OPTIONS] files...\n";
+ print "Options are:\n";
+ print "\t-v, --verbose\tBe verbose\n";
+ print "\t--omitqtcheck\tDoes not check for Qt minimum version\n";
+ exit 0;
+ }
+ elsif (/^--verbose$|^-v$/) {
+ $verbose = 1;
+ }elsif (/^--omitqtcheck/) {
+ $omit_Qt_check = 1;
+ }
+ elsif (!/^-/) {
+ push @explicitfiles, $_;
+ }
+}
+
+# Find .ui files in the given dir
+sub find_ui_files($)
+{
+ my ( $dir ) = @_;
+
+ opendir (DIR, "$dir") || die "Couldn't read '$dir'\n";
+ my @files = grep { /^.*\.ui$/ } readdir(DIR);
+ closedir(DIR);
+
+ #print "found files: [ " . join(' ', @files) . " ] in $dir\n" if ($verbose);
+
+ # prefix them with $dir
+ my @retfiles = ();
+ foreach my $file(@files) {
+ push @retfiles, "$dir/$file";
+ }
+
+ return @retfiles;
+}
+
+# Ensure the version at the top of the file is not too high
+sub fix_version($)
+{
+ my $srcfile = shift @_;
+ open(SRC, "< $srcfile") || die "fix_version: couldn't open '$srcfile'\n";
+ my @contents = <SRC>;
+ my @fixedcontents = ();
+ close(SRC);
+ my $needfix = 0;
+ my $foundversion = 0;
+ foreach my $line (@contents) {
+ if (!$foundversion && $line =~ m/version=\"([0-9]+)\.([0-9]+)(\.[0-9]+)?\"/) {
+ my $version_maj = $1;
+ my $version_min = $2;
+ if ( $version_maj > $minversion_maj ||
+ ( $version_maj == $minversion_maj && $version_min > $minversion_min ) ) {
+ $line =~ s/version=\"[0-9]+\.[0-9]+\"/version=\"$minversion_maj.$minversion_min\"/o;
+ $needfix = 1;
+ print "$srcfile: version was $version_maj.$version_min, set to $minversion_maj.$minversion_min\n";
+ }
+ $foundversion = 1;
+ }
+ push @fixedcontents, $line;
+ }
+ if (!$foundversion) {
+ # TODO improve so that the script adds the necessary line
+ print "$srcfile has no UI version, please fix it\n";
+ }
+ if ($needfix) {
+ open(SRC, "> $srcfile") || die "fix_version: couldn't open '$srcfile' for writing\n";
+ print SRC @fixedcontents;
+ close(SRC);
+ }
+}
+
+# Ensure no auto-added Alt+letter accel exists - those are untranslatable
+sub fix_accels($)
+{
+ my $srcfile = shift @_;
+ open(SRC, "< $srcfile") || die "fix_accels: couldn't open '$srcfile'\n";
+ my @contents = <SRC>;
+ close(SRC);
+ return if ( !grep( /<string>Alt\+[A-Z]<\/string>/, @contents ));
+ my @fixedcontents = ();
+
+ my $firstline;
+ my $accelsremoved = 0;
+ my $inside_accel = 0;
+ # inside_accel is 0 before <property>
+ # 1 after <property> and before <string>
+ # 2 after <string> if alt+letter, and before </property>
+ foreach my $line (@contents) {
+ if ( $inside_accel == 1 ) {
+ if ( $line =~ m/<string>(Alt\+[A-Z])<\/string>/ ) {
+ print "$srcfile: accel $1 removed\n" if ($verbose);
+ $inside_accel = 2;
+ $accelsremoved++;
+ } else { # Not alt+letter, keep accel
+ push @fixedcontents, $firstline;
+ $inside_accel = 0;
+ }
+ }
+ if ($line =~ m/property name=\"accel\"/) {
+ $inside_accel = 1;
+ $firstline = $line;
+ }
+ if ($inside_accel == 0) {
+ push @fixedcontents, $line;
+ }
+ $inside_accel = 0 if ($inside_accel && $line =~ m/<\/property>/);
+ }
+ if ($accelsremoved) {
+ print "$srcfile: $accelsremoved accels removed\n";
+ open(SRC, "> $srcfile") || die "fix_accels: couldn't open '$srcfile' for writing\n";
+ print SRC @fixedcontents;
+ close(SRC);
+ }
+}
+
+# Ensure no auto-added caption exists - it's pretty stupid to have to
+# translate Form1 or MyClassName
+sub fix_captions($)
+{
+ my $srcfile = shift @_;
+ open(SRC, "< $srcfile") || die "fix_captions: couldn't open '$srcfile'\n";
+ my @contents = <SRC>;
+ close(SRC);
+ my @fixedcontents = ();
+
+ my $firstline;
+ my $class = "";
+ my $captionsremoved = 0;
+ my $inside_caption = 0;
+ # inside_caption is 0 before <property>
+ # 1 after <property> and before <string>
+ # 2 after <string> if caption should be removed, and before </property>
+ foreach my $line (@contents) {
+ $class = $1 if ($line =~ m/<class>(.*)<\/class>/);
+ if ( $inside_caption == 1 ) {
+ $line =~ m/<string>(.*)<\/string>/ || die "Malformed XML (no string under caption)";
+ my $caption = $1;
+ print "$srcfile: caption='$caption' class='$class'\n" if ($verbose);
+ if ( ( $caption eq $class && !defined $knowncaptions{$caption} ) ||
+ ($caption =~ m/Form[0-9]/) ) {
+ if ( $caption =~ m/^[A-Z][a-z]*$/ ) {
+ print "$srcfile: removing caption '$caption' (warning! could be real caption)\n";
+ } else {
+ print "$srcfile: removing caption '$caption'\n";
+ }
+ $inside_caption = 2;
+ $captionsremoved++;
+ } else { # Real caption, keep it
+ print "$srcfile: keeping caption '$caption'\n" if ($verbose);
+ push @fixedcontents, $firstline;
+ $inside_caption = 0;
+ }
+ }
+ if ($line =~ m/property name=\"caption\"/) {
+ $inside_caption = 1;
+ $firstline = $line;
+ }
+ if ($inside_caption == 0) {
+ push @fixedcontents, $line;
+ }
+ $inside_caption = 0 if ($inside_caption && $line =~ m/<\/property>/);
+ }
+ if ($captionsremoved) {
+ open(SRC, "> $srcfile") || die "fix_captions: couldn't open '$srcfile' for writing\n";
+ print SRC @fixedcontents;
+ close(SRC);
+ }
+}
+
+# Find a .qt_minversion in $dir or any parent directory.
+sub read_required_version($)
+{
+ my $dir = Cwd::abs_path( shift @_ );
+
+ $minversion_maj = $default_minversion_maj;
+ $minversion_min = $default_minversion_min;
+ while ( length($dir) > 1 ) {
+ my $versfile = "$dir/.qt_minversion";
+ my $version;
+ if ( open (VERSFILE, "< $versfile") ) {
+ while (<VERSFILE>) {
+ $version = $_ if (!/^#/);
+ }
+ close(VERSFILE);
+ } else {
+ $versfile = "$dir/configure.in.in";
+ if ( open (VERSFILE, "< $versfile") ) {
+ while (<VERSFILE>) {
+ $version = $1 if m/^#MIN_CONFIG\(([0-9]+.[0-9]+)\)/;
+ }
+ close(VERSFILE);
+ }
+ }
+ if (defined $version && $version =~ m/([0-9]+)\.([0-9]+)/) {
+ $minversion_maj = $1;
+ $minversion_min = $2;
+ print "Found min version $1.$2 in $versfile\n" if ($verbose);
+ return;
+ }
+ $dir = dirname($dir);
+ }
+}
+
+# Process one .ui file
+sub process_ui_file($)
+{
+ my $file = shift @_;
+ &read_required_version( dirname($file) );
+
+ print "Checking: $file\n" if($verbose);
+ &fix_version($file) if(!$omit_Qt_check);
+ &fix_accels($file);
+ &fix_captions($file);
+}
+
+#############################################################################
+# here is the main logic
+#
+
+# process files from the command line, if any
+if ( $#explicitfiles >= 0 ) {
+ foreach my $file( @explicitfiles ) {
+ &process_ui_file( $file );
+ }
+ exit 0;
+}
+
+# first generate a list of subdirectories
+my @dirlist = ();
+push @dirlist, ".";
+foreach my $dir ( @dirlist ) {
+ opendir (DIR, "$dir") || warn "Couldn't read '$dir'";
+ my $subdir = "";
+ while( $subdir = readdir(DIR)) {
+ next if ($subdir =~ /^\./);
+ next if !( -d "$dir/$subdir");
+ push @dirlist, "$dir/$subdir";
+ }
+ closedir(DIR);
+}
+
+# now iterate over all subdirs
+foreach my $dir(@dirlist) {
+ my @uifile = find_ui_files($dir);
+ foreach my $file(@uifile) {
+ &process_ui_file($file);
+ }
+}
diff --git a/scripts/gettext.patch b/scripts/gettext.patch
new file mode 100644
index 00000000..9470c6f9
--- /dev/null
+++ b/scripts/gettext.patch
@@ -0,0 +1,194 @@
+diff -ru src.orig/xget-lex.c src/xget-lex.c
+--- src.orig/xget-lex.c Fri May 1 06:45:12 1998
++++ src/xget-lex.c Fri Apr 27 16:05:06 2001
+@@ -78,17 +78,18 @@
+
+ enum token_type_ty
+ {
+- token_type_character_constant,
+- token_type_eof,
+- token_type_eoln,
+- token_type_hash,
+- token_type_lp,
+- token_type_comma,
+- token_type_name,
+- token_type_number,
+- token_type_string_literal,
+- token_type_symbol,
+- token_type_white_space
++ token_type_character_constant = 0,
++ token_type_eof = 1,
++ token_type_eoln = 2,
++ token_type_hash = 3,
++ token_type_lp = 4,
++ token_type_rp = 5,
++ token_type_comma = 6,
++ token_type_name = 7,
++ token_type_number = 8,
++ token_type_string_literal = 9,
++ token_type_symbol = 10,
++ token_type_white_space = 11
+ };
+ typedef enum token_type_ty token_type_ty;
+
+@@ -941,6 +942,10 @@
+ tp->type = token_type_lp;
+ return;
+
++ case ')':
++ tp->type = token_type_rp;
++ return;
++
+ case ',':
+ tp->type = token_type_comma;
+ return;
+@@ -1236,6 +1241,11 @@
+ tp->type = xgettext_token_type_lp;
+ return;
+
++ case token_type_rp:
++ last_non_comment_line = newline_count;
++ tp->type = xgettext_token_type_rp;
++ return;
++
+ case token_type_comma:
+ last_non_comment_line = newline_count;
+
+diff -ru src.orig/xget-lex.h src/xget-lex.h
+--- src.orig/xget-lex.h Fri May 1 06:45:23 1998
++++ src/xget-lex.h Fri Apr 27 16:05:06 2001
+@@ -22,13 +22,14 @@
+
+ enum xgettext_token_type_ty
+ {
+- xgettext_token_type_eof,
+- xgettext_token_type_keyword1,
+- xgettext_token_type_keyword2,
+- xgettext_token_type_lp,
+- xgettext_token_type_comma,
+- xgettext_token_type_string_literal,
+- xgettext_token_type_symbol
++ xgettext_token_type_eof = 0,
++ xgettext_token_type_keyword1 = 1,
++ xgettext_token_type_keyword2 = 2,
++ xgettext_token_type_lp = 3,
++ xgettext_token_type_rp = 4,
++ xgettext_token_type_comma = 5,
++ xgettext_token_type_string_literal = 6,
++ xgettext_token_type_symbol = 7
+ };
+ typedef enum xgettext_token_type_ty xgettext_token_type_ty;
+
+diff -ru src.orig/xgettext.c src/xgettext.c
+--- src.orig/xgettext.c Wed Apr 29 18:57:50 1998
++++ src/xgettext.c Fri Apr 27 16:33:46 2001
+@@ -835,7 +835,8 @@
+ int is_cpp_file;
+ {
+ int state;
+-
++ char *msgid = 0;
++
+ /* Inform scanner whether we have C++ files or not. */
+ if (is_cpp_file)
+ xgettext_lex_cplusplus ();
+@@ -861,8 +862,12 @@
+ State 3 = seen one of our keywords with string in second parameter
+ State 4 = was in state 3 and now saw a left paren
+ State 5 = waiting for comma after being in state 4
+- State 6 = saw comma after being in state 5 */
++ State 6 = saw comma after being in state 5
++ State 7 = after comma and being in state 2
++ State 8 = after string and being in state 7
++ */
+ xgettext_lex (&token);
++
+ switch (token.type)
+ {
+ case xgettext_token_type_keyword1:
+@@ -886,18 +891,62 @@
+ state = 0;
+ }
+ continue;
++
++ case xgettext_token_type_rp:
++ if (state == 2 || state == 8) {
++ token.string = strdup(msgid);
++ remember_a_message (mlp, &token);
++ free(msgid);
++ msgid = 0;
++ state = 0;
++ }
++ continue;
+
+ case xgettext_token_type_comma:
+- state = state == 5 ? 6 : 0;
++ switch (state) {
++ case 5:
++ state = 6;
++ break;
++ case 2:
++ state = 7;
++ break;
++ case 8: {
++ char *newstring = (char*)malloc(strlen(msgid) + 2);
++ strcpy(newstring, "_n:");
++ strcat(newstring, msgid + 2);
++ free(msgid);
++ token.string = newstring;
++ remember_a_message (mlp, &token);
++ msgid = 0;
++ state = 0;
++ break;
++ }
++ default:
++ state = 0;
++ break;
++ }
+ continue;
+
+ case xgettext_token_type_string_literal:
+ if (extract_all || state == 2 || state == 6)
+ {
+- remember_a_message (mlp, &token);
+- state = 0;
++ if (msgid)
++ free(msgid);
++ msgid = strdup(token.string);
++ // state = 0;
+ }
+- else
++ else if (state == 7)
++ {
++ if (msgid) {
++ char *newstring = (char*)malloc(strlen(msgid) + strlen(token.string) + 20);
++ sprintf(newstring, "_: %s\n%s", msgid, token.string);
++ free(msgid);
++ free(token.string);
++ token.string = msgid = newstring;
++ state = 8;
++ }
++ }
++ else
+ {
+ free (token.string);
+ state = (state == 4 || state == 5) ? 5 : 0;
+@@ -905,8 +954,8 @@
+ continue;
+
+ case xgettext_token_type_symbol:
+- state = (state == 4 || state == 5) ? 5 : 0;
+- continue;
++ state = (state == 4 || state == 5) ? 5 : 0;
++ continue;
+
+ default:
+ state = 0;
+@@ -915,6 +964,7 @@
+ case xgettext_token_type_eof:
+ break;
+ }
++
+ break;
+ }
+
diff --git a/scripts/includemocs b/scripts/includemocs
new file mode 100755
index 00000000..32df1b20
--- /dev/null
+++ b/scripts/includemocs
@@ -0,0 +1,102 @@
+#! /usr/bin/env perl
+
+use strict;
+use Cwd;
+use File::Find;
+
+my %dir2files=();
+my $cppExt=" cpp cc cxx C c++ ";
+my $cppFiles="*.cpp *.cc *.cxx *.C *.c++";
+
+sub collectthing()
+{
+ if (/\.([^.]+)$/) {
+ my $ext=$1;
+ if (" h H hh hxx h++ " =~ / $ext /) {
+ my $line=`grep -l '^[{ \t]*Q_OBJECT' $_ 2> /dev/null`;
+ chomp($line);
+ if ($line) {
+ $dir2files{$File::Find::dir}->{headers}->{$_} = 1;
+ }
+ } elsif ($cppExt =~ / $ext /) {
+ $dir2files{$File::Find::dir}->{sources}->{$_} = 1;
+ }
+ }
+}
+
+sub checkdir($)
+{
+ my ($dir)=@_;
+ chdir($dir);
+ my $hdrs=$dir2files{$dir}->{headers};
+ my $srcs=$dir2files{$dir}->{sources};
+ foreach my $h (keys %$hdrs) {
+ (my $name=$h) =~ s/\.[^.]+$//;
+ my @answer = `grep -l "^#include[ ]*.$name\.moc." $cppFiles 2> /dev/null`;
+ if (@answer == 0) {
+ my $s;
+ foreach my $e (split(/\s+/, $cppExt)) {
+ if (exists $srcs->{$name.".".$e}) {
+ $s=$dir."/".$name.".".$e; last;
+ }
+ }
+ if ($s) {
+ print "echo >> $s ;\n";
+ print "echo '#include \"$name.moc\"' >> $s ;\n";
+ } else {
+ print "echo \"can't guess a C++ file for $dir/$h\" ;\n";
+ }
+ }
+ }
+}
+
+find (\&collectthing, cwd());
+
+foreach my $k (keys %dir2files) {
+ print STDERR "Directory $k:\n headers=[";
+ print STDERR join(", ", keys %{$dir2files{$k}->{headers}});
+ print STDERR "]\n sources=[";
+ print STDERR join(", ", keys %{$dir2files{$k}->{sources}});
+ print STDERR "]\n";
+ checkdir($k);
+}
+
+=head1 NAME
+
+includemocs -- handle mocifyable headers, whose .moc file is nowhere included.
+
+=head1 SYNOPSIS
+
+ includemocs
+
+=head1 DESCRIPTION
+
+Header files declaring a QObject descendant have to be run through moc to
+produce a .moc file. This .moc file has to be compiled, for which two
+possibilities exists: compile it separately, or #include it in the C++ file
+implementing that above mentioned class. The latter is more efficient in term
+of compilation speed.
+
+This script searches in the current directory and its subdirs for header files
+declaring a QObject descendant class. If it finds some, it looks, if there is
+a C++ file containing an '#include' for the generated .moc file. If thats not
+the case, it tries to guess into which C++ file that '#include' is placed best
+(based on the filename). If it fails to guess a proper place, it mentions
+that.
+
+On stdout commands are ouput, suitable for a shell, which, when
+evaluated, add the suggested '#include' at the end of the files.
+
+On stderr some informational messages are printed.
+
+=head1 EXAMPLES
+
+ cd kdebase ; includemocs
+ cd kdebase ; `eval includemocs 2> /dev/null`
+
+=head1 AUTHOR
+
+Michael Matz <matz@ifh.de>
+
+=cut
+
diff --git a/scripts/kDebug2kdDebug.sh b/scripts/kDebug2kdDebug.sh
new file mode 100755
index 00000000..a238845e
--- /dev/null
+++ b/scripts/kDebug2kdDebug.sh
@@ -0,0 +1,154 @@
+## kDebug2kdDebug.sh
+## Script to port from qDebug, kdebug, kDebugInfo etc. to kdDebug/kdWarning/...
+## Example:
+## kDebugInfo( [area,] "format %a - %b", arga, argb )
+## becomes
+## kdDebug( [area] ) << "format " << arga << " - " << argb << endl;
+##
+## Written by David Faure <faure@kde.org>, licensed under GPL.
+## 17/03/2000
+
+find $1 -name '*[cCph]' -type f | xargs grep -H -i 'ebug(\|warning(' \
+| grep -v 'kdDebug\|kdWarning' \
+| grep -v include \
+| sed -e "s#:.*##" \
+| sort -u \
+| while read file; do
+echo -n "working on $file "
+cp $file $file.tmp
+perl -w -i -e \
+'
+$inkdebug=0;
+while (<>)
+{
+ if ( $inkdebug )
+ {
+ chop;
+ #print "Reading line : " . $_ . "\n";
+ $statement .= $_;
+ }
+ elsif ( /kdebug\s*\(/ || /kDebug[a-zA-Z]*\s*\(/ || /qDebug\s*/ || /qWarning\s*/ )
+ {
+ # Very old kdebug stuff :)
+ s/kdebug\s*\(\s*KDEBUG_INFO,/kDebugInfo\(/;
+ s/kdebug\s*\(\s*0,/kDebugInfo\(/;
+ s/kdebug\s*\(\s*KDEBUG_WARN,/kDebugWarning\(/;
+ s/kdebug\s*\(\s*KDEBUG_ERROR,/kDebugError\(/;
+ s/kdebug\s*\(\s*KDEBUG_FATAL,/kDebugFatal\(/;
+
+ $inkdebug = 1;
+ chop;
+ $statement = $_;
+ }
+
+ if ( $inkdebug )
+ {
+ if ( /\)\s*;/ ) # look for );
+ {
+ $inkdebug = 0;
+ $_ = $statement;
+ ## Ok, now we have the full line
+ ## 1 - Parse
+ if (s/(^.*kDebug[a-zA-Z]*)\s*\(\s*//) {
+ $line=$1; # has the indentation, //, and the kDebug* name
+ } elsif (s/(^.*qDebug)\s*\(\s*// || s/(^.*qWarning)\s*\(\s*//) {
+ $line=$1;
+ } else { die "parse error on kDebug/qDebug/qWarning..."; }
+ $line=$1; # has the indentation, //, and the kDebug* name
+ $line =~ s/kDebugInfo/kdDebug/;
+ $line =~ s/kDebugArea/kdDebug/;
+ $line =~ s/qDebug/kdDebug/;
+ $line =~ s/qWarning/kdWarning/;
+ $line =~ s/kDebugWarning/kdWarning/;
+ $line =~ s/kDebugError/kdError/;
+ $line =~ s/kDebugFatal/kdFatal/;
+ $area = "";
+ if ( s/^([0-9]+)\s*,\s*//) # There is an area
+ {
+ $area = $1; # Store it
+ $line .= "(" . $area . ")";
+ } elsif ( s/^(KBABEL[^,]*)\s*,\s*//)
+ { # Example of support for #defined area (here KBABEL.*)
+ $area = $1; # Store it
+ $line .= "(" . $area . ")";
+ } else
+ { $line .= "()"; } # You can set an area here if converting qDebugs
+
+ $arguments = ""; # for final test
+ $commented = 0;
+ if ( !s/^\"([^\"]*)\"// ) # There is no format
+ {
+ s/\s*\)\s*;\s*$//;
+ $commented = s/\s*\)\s*;\s*\*\/$//; # terminating with */
+ $line = $line . " << " . $_ ;
+ } else
+ {
+ $format = $1;
+ # If we stopped on a \" we need to keep adding to format
+ while ( $format =~ m/\\$/ )
+ { s/^([^\"]*)\"// || die "problem"; $format .= "\"" . $1; }
+ s/\s*\)\s*;\s*$/,/; # replace trailing junk with , for what follows
+ $commented = s/\s*\)\s*;\s*\*\/$/,/; # terminating with */
+ $arguments = $_;
+
+ ## 2 - Look for %x
+ @stringbits = split( "(%[0-9]*[a-z])", $format );
+ foreach ( @stringbits )
+ {
+ #print $_ . "\n";
+ if ( /(%[0-9]*[a-z])/ ) # This item is a format
+ {
+ ## 3 - Find argument
+ # kludge for QString(a,b) constructions
+ $arguments =~ s/(QString\s*\([^,]+,[^,]+\))/QStrKLUDGE/;
+ $kludge = $1;
+ $arguments =~ s/\s*([^,]+)\s*,//;
+ # Remove trailing .ascii() and latin1()
+ $arg = $1;
+ $arg =~ s/QStrKLUDGE/$kludge/; ## restore original arg
+ $arg =~ s/\.ascii\(\)$//; # remove
+ $arg =~ s/\.latin1\(\)$//; # remove
+ $arg =~ s/debugString\(([^\)]+)\)/$1/; # remove
+ # If "a ? b : c" then add parenthesis
+ if ( $arg =~ m/.+\s*\?\s*.+\s*:\s*.+/ ) {
+ $arg = "(" . $arg . ")";
+ }
+ $line = $line . " << " . $arg;
+ } else # This item is some litteral
+ {
+ $line = $line . " << \"" . $_ . "\"" if ($_);
+ }
+ }
+
+ }
+ $arguments =~ s/,$//; # Remove trailing slash before next check
+ if ( $arguments ) {
+ print STDERR "Non-processed (Information lost! Check the file!) : " . $arguments . "\n";
+ }
+ $line = $line . " << endl;\n";
+ if ( $commented ) { $line .= "\*/"; }
+ print $line;
+ }
+ }
+ else
+ {
+ # Normal line
+ print;
+ }
+}
+if ( $inkdebug )
+{
+ print STDERR "Warning, unterminated kDebug call !! Check the file !\n";
+ print $arguments;
+}
+' $file.tmp
+if cmp -s $file $file.tmp > /dev/null 2>&1 ; then
+ echo "unchanged"
+ rm $file.tmp
+else
+ echo "patching"
+ mv $file.tmp $file
+fi
+
+done
+
diff --git a/scripts/kde-build b/scripts/kde-build
new file mode 100755
index 00000000..5c9a111d
--- /dev/null
+++ b/scripts/kde-build
@@ -0,0 +1,898 @@
+#! /usr/bin/env bash
+################################################################################
+# Updates and recompiles a local KDE tree from SVN #
+# (c) 2000, 2001, 2002, 2003 by Frerich Raabe <raabe@kde.org> #
+# (c) 2002, 2003 by Stephan Kulow <coolo@kde.org> #
+################################################################################
+# Do not edit this file, change kde-buildrc instead! #
+################################################################################
+
+# These strings are defined as variables to make the output look more
+# consistent.
+#
+str_okay="done!"
+str_error="failed!"
+
+# The variables whose name is prefixed with ERR_ hold the error codes which
+# are returned by the script and depend on the reason for aborting the
+# execution.
+#
+# No error has been noticed, everything seems to be fine.
+#
+err_no_error="0"
+
+# Could not change into a directory of a module - wrong owner/access
+# settings?
+#
+err_change_into_mod_dir="1"
+
+# Could not find the file 'Makefile.in' for a module, mostly happens if
+# 'make -f Makefile.cvs' hasn't been executed for a module.
+#
+err_no_makefile_in="2"
+
+# The 'configure' command failed for a module because the system doesn't
+# support certain features - I hope you activated logfile generation... ;)
+#
+err_configure_fail="3"
+
+# The compilation of a module failed - if the module is defined in
+# $critical_modules (see below) the execution is aborted, otherwise the script
+# will continue with the next module.
+#
+err_compile_fail="4"
+
+# The installation of a module failed - this mostly happens if there's not
+# enough free disk space on the partition which $KDEDIRS is mounted to.
+#
+err_install_fail="5"
+
+# The $KDESRCDIR variable wasn't set or contains a non-existant directory.
+#
+err_inv_kdesrcdir="6"
+
+# The $QTDIR variable wasn't set, points to a non-existant directory or
+# doesn't contain a bin/, lib/, or include/ subdirectory.
+#
+err_inv_qtdir="7"
+
+# ....
+
+# The configuration file couldn't be found.
+#
+err_no_config="11"
+
+# You can't mix CVS_CLEAN and INCREMENTAL_BUILD
+#
+err_cvsclean_incremental="12"
+
+# You can't mix BUILD_CLEAN and INCREMENTAL_BUILD
+#
+err_buildclean_incremental="13"
+
+# Certain modules depend on others - those "base" modules which are required
+# by others to compile and/or run should be listed here to ensure that the
+# script is aborted in case on of these modules doesn't build.
+# These modules needs to be build and installed in this specific order!
+#
+critical_modules="arts kdelibs kdebase"
+
+# Internal variable, do not change.
+#
+dateformat="`date +%Y%m%d`"
+
+# Private variables fro controlling kppp
+#
+we_started_kppp="FALSE"
+
+# Connects to the internet using kppp if desired
+#
+kppp_connect()
+{
+if [ "$USE_KPPP" = "TRUE" ]; then
+ kppp_process=`dcopfind -a kppp-*`
+ if [ "$kppp_process" = "" ]; then
+ #kppp not running
+ kppp > /dev/null 2>&1 &
+ sleep $KPPP_LOAD_TIME
+ `dcop $(dcopfind -a kppp-*) KpppIface beginConnect`
+ #wait for a while
+ sleep $KPPP_CONNECT_TIME
+ kppp_connected=`dcop $(dcopfind -a kppp-*) KpppIface isConnected`
+ if [ "$kppp_connected" = "true" ]; then
+ we_started_kppp="TRUE"
+ echo Connected OK
+ else
+ echo Could not connect, maybe you need to increase KPPP_CONNECT_TIME
+ fi
+
+ else
+ kppp_connected=`dcop $(dcopfind -a kppp-*) KpppIface isConnected`
+ if [ "$kppp_connected" = "false" ]; then
+ #Start a connection
+ `dcop $(dcopfind -a kppp-*) KpppIface beginConnect`
+ #wait for a while
+ sleep $KPPP_CONNECT_TIME
+ kppp_connected=`dcop $(dcopfind -a kppp-*) KpppIface isConnected`
+ if [ "$kppp_connected" = "true" ]; then
+ we_started_kppp="TRUE"
+ echo Connected OK
+ else
+ echo Could not connect, maybe you need to increase KPPP_CONNECT_TIME
+ fi
+ else
+ echo Kppp is already connected to the internet
+ fi
+ fi
+fi
+}
+
+# Disconnects from the internet using kppp if desired
+#
+kppp_disconnect()
+{
+if [ "$USE_KPPP" = "TRUE" ]; then
+ if [ $(dcopfind -a kppp-*) = "" ]; then
+ #kppp not running
+ echo Kppp was not running so cannot be disconnected
+ else
+ if [ "$we_started_kppp" = "TRUE" ]; then
+ echo Disconnecting kppp
+ `dcop $(dcopfind -a kppp-*) KpppIface disconnect`
+ else
+ echo We didnt connect using kppp so we wont disconnect
+ fi
+ fi
+fi
+}
+
+# This method gives some kind of status message in the title bar of Konsole,
+# xterm, etc.. Thanks have to go to Malte Starostik
+# <malte@kde.org> for the code :-)
+set_title() {
+ which printf > /dev/null 2>&1 || return
+ if ([ "$TERM" = "xterm" ] || [ "$TERM" = "xterm-color" ] || [ "$TERM" = "screen" ]) && tty -s; then
+ printf "\033]0;$1\007"
+ fi
+}
+
+# moves a log file to be named $1, so one can see on first glance
+move_logfile() {
+ rename_logfile=`echo $logfile | sed -e "s,-build-,-$1-,"`
+ mv "$logfile" "$rename_logfile"
+ logfile=$rename_logfile
+}
+
+# Executes the given command, logging the output to $logfile if requested.
+#
+log_cmd() {
+ if [ -n "$logfile" ]; then
+ eval "$1 >> $logfile 2>&1"
+ else
+ eval "$1"
+ fi
+ return $?
+}
+
+module_variable() {
+ eval "$1=\$BASE_$1"
+ varname="$1_"`echo $module|tr a-z A-Z|tr - _|sed "s/\(.*\)-[0-9]*/\1/g"`; # e.g. $1_ARTS etc.
+ varvalue=`eval echo '$'$varname`
+ if [ -n "$varvalue" ]; then
+ eval "$1=\"$varvalue\""
+ fi
+}
+
+# Inserts a "-> blah <---" style separator into $logfile, and starts a timer
+log_section() {
+ [ -z "$logfile" ] && return 0
+ len=`echo $1 | wc -m | sed -e "s,^ *,,"`
+ echo "------------------------------------------------------------------------" \
+ | sed -e "s,^,-> $1 <," -e "s,.\{$len\}$,," >> $logfile 2>&1
+ starttime=`date +%s`
+}
+
+# Computes the time elapsed since the last log_section call,
+# inserts a "----" separator, and the time needed, into $logfile
+log_endsection() {
+ [ -z "$logfile" ] && return 0
+ compute_time
+ echo "----------------------------------------------------------------------------" >> $logfile 2>&1
+ printf "%s for module %s done. Time needed: %02d:%02d:%02d\n" "$1" $module $hours $minutes $seconds >> $logfile 2>&1
+ echo "" >> $logfile 2>&1
+}
+
+# This function computes the time which was needed for a certain task, using
+# expr (instead of shell-specific features) for portability.
+#
+compute_time() {
+ duration=`expr \`date +%s\` - $starttime`
+ hours=`expr $duration / 3600`
+ minutes=`expr $duration % 3600 / 60`
+ seconds=`expr $duration % 60`
+}
+
+prepare_update() {
+ # This checks whether the user wants a certain branch and generates the
+ # command line.
+ #
+ cmd_update="svn"
+ if test -d $KDESRCDIR/$module; then
+ test -z "$SUBDIR" && { cmd_update="$cmd_update update" ; return; }
+ cmd_update="$cmd_update switch -r HEAD"
+ else
+ cmd_update="$cmd_update co"
+ fi
+ if [ -z "$ACCOUNT" ]; then
+ cmd_update="$cmd_update $ANONSVNROOT$SUBDIR"
+ else
+ cmd_update="$cmd_update"
+ if [ "$SSHACCOUNT" = "yes" ]; then
+ cmd_update="$cmd_update svn+ssh://$ACCOUNT@svn.kde.org/home/kde$SUBDIR"
+ else
+ cmd_update="$cmd_update https://$ACCOUNT@svn.kde.org/home/kde$SUBDIR"
+ fi
+ fi
+ if [ -n "$CHECKOUT_PARTIAL" -a "$1" = "toponly" ]; then # TODO
+ cmd_update="$cmd_update -N"
+ fi
+ if test ! -d $KDESRCDIR/$module; then
+ cmd_update="$cmd_update $module"
+ fi
+}
+
+# This function installs a compiled CVS module.
+#
+install_module() {
+ echo -n " Installing..."
+ set_title "Installing module $module..."
+ log_section "Installation"
+
+ if log_cmd "$cmd_make_install"; then
+ log_endsection "Installation"
+ if [ -n "$KDELOGDIR" ]; then
+ echo "Build of module $module successfully finished at `date +%c`" >> $logfile
+ [ -n "$cmd_compress" ] && eval "$cmd_compress $logfile"
+ fi
+ echo "$str_okay"
+ echo "Module $module successfully installed in $KDEDIRS!"
+ move_logfile "finished"
+ else
+ echo "$str_error"
+ move_logfile "failed"
+ [ -n "$cmd_compress" ] && eval "$cmd_compress $logfile"
+ [ $critical -eq 0 ] || exit $err_compile_fail
+ fi
+}
+
+make_makefile_cvs() {
+ cmd_make_makefile_cvs="$MAKE -f Makefile.cvs"
+ if [ "$NICECOMPILE" = yes ]; then
+ cmd_make_makefile_cvs="nice $cmd_make_makefile_cvs"
+ fi
+ unset UNSERMAKE || true
+ if [ -n "$USE_UNSERMAKE" ] && \
+ !(echo $NO_UNSERMAKE_MODULES | grep $module > /dev/null 2>&1); then
+ export UNSERMAKE=$USE_UNSERMAKE
+ fi
+
+ if [ "$INCREMENTAL_BUILD" = "yes" -a -e "Makefile.in" ]; then
+ cmd_make_makefile_cvs="echo Warning: no Makefile.cvs for module $module - as requested"
+ fi
+
+ if log_cmd "$cmd_make_makefile_cvs"; then
+ echo "$str_okay"
+ else
+ echo "$str_error"
+ fi
+}
+
+# Disable zsh feature
+CDPATH=
+
+# Get current configuration, bail out if it couldn't be found.
+# Search order is $PWD:$HOME:`dirname $0`
+# The name in $HOME is .kde-buildrc (note the leading '.')
+if [ -e "$PWD/kde-buildrc" ]; then
+ rc_file="$PWD/kde-buildrc"
+else
+ if [ -e "$HOME/.kde-buildrc" ]; then
+ rc_file="$HOME/.kde-buildrc"
+ else
+ if [ -e "`dirname $0`/kde-buildrc" ]; then
+ rc_file="`dirname $0`/kde-buildrc"
+ else
+ echo "ERROR: Cannot locate configuration file kde-buildrc!"; exit $err_no_config
+ fi
+ fi
+fi
+
+INCREMENTAL_BUILD="no"
+
+. $rc_file
+
+if [ "${INCREMENTAL_BUILD}" = "yes" -a "${CVS_CLEAN}" = "yes" ]; then
+ echo "ERROR: Cannot use CVS_CLEAN=\"yes\" and INCREMENTAL_BUILD=\"yes\" together!"; exit $err_cvsclean_incremental
+fi
+
+if [ "${INCREMENTAL_BUILD}" = "yes" -a "${BUILD_CLEAN}" = "yes" ]; then
+ echo "ERROR: Cannot use BUILD_CLEAN=\"yes\" and INCREMENTAL_BUILD=\"yes\" together!"; exit $err_buildclean_incremental
+fi
+
+domakecvs=1
+dosvnupdate=1
+dousage=0
+specifiedModules=""
+
+# Parse args
+#
+while [ $# != 0 ]
+do
+ arg=$1
+ case "$arg" in
+ --help)
+ dousage=1
+ break ;;
+ --version)
+ # Show version
+ echo "$0 version 0.8.15"
+ exit $err_no_error ;;
+ --no-update)
+ dosvnupdate=0 ;;
+ --no-check)
+ domakecvs=0 ;;
+ --incremental)
+ INCREMENTAL_BUILD="yes"
+ ;;
+ --full)
+ INCREMENTAL_BUILD="no"
+ ;;
+ -*)
+ echo "Unhandled option $arg"
+ dousage=1
+ break ;;
+ *)
+ specifiedModules="$specifiedModules $arg" ;;
+ esac
+ shift
+done
+
+# Show help info
+if [ "$dousage" -eq 1 ]; then
+ echo "usage: $0 [--options] [modules]"
+ echo "--no-update Do not update from SVN."
+ echo "--no-check Do not re-run Makefile.cvs."
+ echo "--incremental Start make right after update - risky. This also"
+ echo " disables the BUILD_CLEAN and CVS_CLEAN options."
+ echo "--full Do full setup even when INCREMENTAL_BUILD is set."
+ echo "--help Show this message."
+ exit $err_no_error
+fi
+
+# Expand ~
+QTDIR=`echo "$QTDIR" | sed -e "s,^\~/,$HOME/,"`
+KDESRCDIR=`echo "$KDESRCDIR" | sed -e "s,^\~/,$HOME/,"`
+KDEBUILDDIR=`echo "$KDEBUILDDIR" |sed -e "s,^\~/,$HOME/,"`
+KDEDIRS=`echo "$KDEDIRS" |sed -e "s,^\~/,$HOME/,"`
+KDELOGDIR=`echo "$KDELOGDIR" |sed -e "s,^\~/,$HOME/,"`
+
+# Make sure some paths are according to the rc file. Note that there are AFAIK
+# UNIX flavors which don't support LD_LIBRARY_PATH
+PATH=$QTDIR/bin:$KDEDIRS/bin:$PATH
+MANPATH=$QTDIR/doc/man:$MANPATH
+LD_LIBRARY_PATH=$KDEDIRS/lib:$QTDIR/lib:$LD_LIBRARY_PATH
+
+if [ -n "$USE_UNSERMAKE" ]; then
+ if [ -n "$MAKE" ]; then
+ echo "overwriting MAKE=$USE_UNSERMAKE"
+ fi
+ MAKE=$USE_UNSERMAKE
+ UNSERMAKE_PATH=`dirname $USE_UNSERMAKE`
+ PATH=$UNSERMAKE_PATH:$PATH
+fi
+
+if [ -z "$MAKE" ]; then
+ MAKE=make
+fi
+
+if [ -n "$specifiedModules" ]; then
+ # In case someone with a kdebase dir in $PWD does autocompletion..
+ modules=$( echo $specifiedModules | sed -e 's/\///g' )
+else
+ if [ "$ONLYLISTEDMODULES" = yes ]; then
+ if [ "$USEKDESUPPORT" = yes ]; then
+ modules="kdesupport $critical_modules $KDEMODULES"
+ else
+ modules="$critical_modules $KDEMODULES"
+ fi
+ else
+ modules="$critical_modules"
+ # This generates in 'modules' a list of the modules which shall be updated.
+ #
+ potential_modules=`find $KDESRCDIR -type d -mindepth 1 \
+ -maxdepth 1 -follow | sed -e "s@.*/?*@@"`
+ for module in $potential_modules; do
+ if [ -d $KDESRCDIR/$module/CVS -a -w $KDESRCDIR/$module ] \
+ && !(echo $EXCLUDE | grep -q $module) \
+ && !(echo $modules | grep -q $module) ; then
+ modules="$modules $module"
+ fi
+ done
+ fi
+fi
+
+# Various checks to ensure that the user didn't specify invalid data which
+# would make our script break.
+#
+if [ -n "$KDELOGDIR" -a ! -d "$KDELOGDIR" ]; then
+ if ! mkdir -p "$KDELOGDIR" > /dev/null 2>&1; then
+ echo "WARNING: Could not create logfile-directory."
+ echo "WARNING: Logfile generation deactivated."
+ KDELOGDIR=""
+ fi
+else
+ if [ -n "$KDELOGDIR" -a ! -w "$KDELOGDIR" ]; then
+ echo "WARNING: Could not obtain write access to specified logfile-directory."
+ echo "WARNING: Logfile generation deactivated."
+ KDELOGDIR=""
+ fi
+fi
+
+if [ -n "$KDELOGDIR" ]; then
+ str_error="$str_error Check the logfile in $KDELOGDIR for further information."
+fi
+
+if [ ! -d "$KDESRCDIR" ]; then
+ echo "ERROR: Invalid source directory specified!"; exit $err_inv_kdesrcdir
+fi
+if [ ! -d "$QTDIR" -o ! -d "$QTDIR/lib" -o ! -d "$QTDIR/bin" -o ! -d "$QTDIR/include" ]; then
+ echo "ERROR: Invalid Qt directory specified!"; exit $err_inv_qtdir
+fi
+
+if [ "$COMPRESSLOGS" = yes ]; then
+ if which bzip2 > /dev/null 2>&1; then
+ cmd_compress="`which bzip2` -f "
+ else
+ if which gzip > /dev/null 2>&1; then
+ cmd_compress="`which gzip` -f "
+ else
+ echo "WARNING: Neither bzip2 nor gzip was found, disabling compression of logfiles."
+ cmd_compress=""
+ fi
+ fi
+fi
+
+if which sudo > /dev/null 2>&1; then
+ cmd_sudo="sudo"
+else
+ cmd_sudo="su -c"
+fi
+
+# Clean the installation directory if selected.
+#
+if test "$INSTALLFROMSCRATCH" = yes && test -z "$specifiedModules" ; then
+ mkdir -p $KDEDIRS 2> /dev/null
+ if [ ! -w $KDEDIRS ]; then
+ echo "Enter the root password to clean the installation directory."
+ echo "WARNING: All files and directories in $KDEDIRS will be deleted!"
+ echo -n "Please enter root "
+ eval "$cmd_sudo rm -rf $KDEDIRS/*"
+ else
+ rm -rf $KDEDIRS/*
+ fi
+fi
+
+# Optionally activate cheap tweaks.
+#
+if [ "$TWEAKCOMPILE" = yes ]; then
+ CFLAGS="-O0"
+ CXXFLAGS="-O0"
+ export CFLAGS CXXFLAGS
+fi
+
+# Preprocess configuration keys, expand keywords (DISTCC)
+#
+if echo $MAKE_OPTS_COMPILE | grep DISTCC > /dev/null; then
+ if [ -n "$DISTCC_HOSTS" ]; then
+ hosts=0
+ for host in $DISTCC_HOSTS; do
+ hosts=$((${hosts} + 1))
+ done
+ hosts=$((${hosts} * 2))
+ else
+ hosts=1
+ fi
+ MAKE_OPTS_COMPILE=`echo $MAKE_OPTS_COMPILE | sed -e "s,DISTCC,$hosts,"`
+fi
+
+if echo $MAKE_OPTS_COMPILE | grep TEAMBUILDER > /dev/null; then
+ if ! which tbcompiler > /dev/null 2>&1; then
+ echo "TEAMBUILDER is not in PATH and OPTS_COMPILE has TEAMBUILDER"
+ exit 1
+ fi
+ hosts=`tbcompiler -joblimit`
+ if [ -z "$hosts" ]; then
+ hosts=1
+ fi
+ MAKE_OPTS_COMPILE=`echo $MAKE_OPTS_COMPILE | sed -e "s,TEAMBUILDER,$hosts,"`
+fi
+
+#Connect to the internet before we start enything
+#
+kppp_connect
+
+# Guess what? We'll finally start checking out the modules. :-)
+#
+# If we want to use unsermake, update that at the very beginning, so that
+# all the modules make use of the most recent unsermake version.
+#
+if [ -n "$USE_UNSERMAKE" ] && [ "$dosvnupdate" -eq 1 ]; then
+ echo -n "Updating unsermake copy in $UNSERMAKE_PATH..."
+ cd "$UNSERMAKE_PATH"
+ svn up > /dev/null 2>&1
+ echo $str_okay
+fi
+
+BASE_CONFIGUREFLAGS="$CONFIGUREFLAGS"
+BASE_SUBDIR=$SUBDIR
+BASE_CHECKOUT_PARTIAL="$CHECKOUT_PARTIAL"
+
+for module in $modules; do
+ module_variable SUBDIR
+ SUBDIR=`echo $SUBDIR | sed -e "s,@MODULE@,$module,"`
+ module_variable CHECKOUT_PARTIAL
+
+ if [ -n "$KDELOGDIR" ]; then
+ rm -f $KDELOGDIR/$module-build-*
+ rm -f $KDELOGDIR/$module-failed-*
+ rm -f $KDELOGDIR/$module-finished-*
+ logfile="$KDELOGDIR/$module-build-$dateformat.log"
+ echo "===============================================================================" > $logfile
+ echo "Build log of module $module, started on `date +%c`" >> $logfile
+ echo "===============================================================================" >> $logfile
+ echo "" >> $logfile
+ fi
+
+ set_title "Updating module $module..."
+ if [ "$dosvnupdate" -eq 0 ]; then
+ echo -n "Checking module $module (no svn update)..."
+ cmd_update_raw="echo Warning: no svn update of module $module - as requested"
+ else
+ if [ -n "$BRANCH" ]; then
+ echo -n "Updating module $module ($BRANCH)..."
+ else
+ echo -n "Updating module $module ..."
+ fi
+ prepare_update
+ cmd_update_raw="$cmd_update"
+ fi
+
+ log_section "Update $cmd_update"
+
+ if [ "$dosvnupdate" -ne 0 -a -n "$CHECKOUT_PARTIAL" ]; then
+ cmd_update_raw="$cmd_update -l $module"
+ fi
+
+ if test -d $KDESRCDIR/$module; then
+ cd $KDESRCDIR/$module
+ else
+ cd $KDESRCDIR
+ fi
+
+ if ! log_cmd "$cmd_update_raw"; then
+ echo "$str_error"
+ continue
+ fi
+
+ if [ "$dosvnupdate" -ne 0 -a -n "$CHECKOUT_PARTIAL" ]; then
+ prepare_update toponly
+ echo "defined subdirs!"
+ for part_dir in $CHECKOUT_PARTIAL; do
+ echo -n "Updating subdirectory $part_dir"
+ log_cmd "$cmd_update $module/$part_dir"
+ echo " $str_okay"
+ done
+ echo -n "Final touch..."
+ fi
+
+ if [ "$CVS_CLEAN" = "yes" -a -e admin/Makefile.common -a "$INCREMENTAL_BUILD" != "yes" ]; then
+ cmd_make_cvs_clean="$MAKE -f admin/Makefile.common cvs-clean"
+ fi
+
+ if ! log_cmd "$cmd_make_cvs_clean"; then
+ echo "$str_error"
+ continue
+ fi
+
+ if [ ! -e Makefile.cvs ]; then
+ echo "$str_okay"
+ continue
+ fi
+
+ if [ $domakecvs = 1 ] ; then
+ make_makefile_cvs
+ else
+ echo "$src_okay"
+ continue
+ fi
+
+ log_endsection "Updating"
+done
+
+# Now disconnect from the internet as we've finished updating
+#
+kppp_disconnect
+
+for module in $modules; do
+ module_variable CONFIGUREFLAGS
+
+ # Nothing to do for kde-common
+ [ "$module" = "kde-common" ] && continue
+ logfile="$KDELOGDIR/$module-build-$dateformat.log"
+
+ critical=0
+ for m in $critical_modules; do if [ $m = $module ]; then critical=1; fi; done
+
+ if ! cd $KDESRCDIR/$module; then
+ if [ $critical -eq 1 ]; then
+ echo "ERROR: Could not change into directory $KDESRCDIR/$module!"
+ exit $err_change_into_mod_dir
+ else
+ echo "WARNING: Could not change into directory $KDESRCDIR/$module."
+ echo "WARNING: Skipping module $module."
+ continue
+ fi
+ fi
+
+ # Check whether 'make -f Makefile.cvs' has been called.
+ #
+ if [ ! -e "Makefile.in" ]; then
+ if [ $critical -eq 1 ]; then
+ echo "ERROR: Please execute '$MAKE -f Makefile.cvs' first for module $module!"
+ exit $err_no_makefile_in
+ else
+ echo "WARNING: '$MAKE -f Makefile.cvs' seems not to be executed for"
+ echo "WARNING: module $module, skipping compilation."
+ continue
+ fi
+ fi
+
+ echo "Building module: $module"
+
+ if [ -n "$KDEBUILDDIR" ]; then
+
+ if [ "$BUILD_CLEAN" = "yes" -a "$INCREMENTAL_BUILD" != "yes" ]; then
+ if [ -d $KDEBUILDDIR/$module ]; then
+ echo -n " Removing build dir..."
+ set_title "Removing build dir for module $module..."
+ rm -rf $KDEBUILDDIR/$module
+ echo $str_okay
+ fi
+ fi
+ mkdir -p $KDEBUILDDIR/$module
+ cd $KDEBUILDDIR/$module
+ fi
+
+ # Configure the module.
+ #
+ echo -n " Configuring..."
+ set_title "Configuring module $module..."
+ if [ -n "$KDEBUILDDIR" ]; then
+ cmd_configure="$KDESRCDIR/$module/configure $CONFIGUREFLAGS --with-qt-dir=$QTDIR"
+ else
+ cmd_configure="./configure $CONFIGUREFLAGS --with-qt-dir=$QTDIR"
+ fi
+ if echo $CONFIGUREFLAGS | grep -v -- "--prefix=" 2>/dev/null >/dev/null; then
+ cmd_configure="$cmd_configure --prefix=$KDEDIRS"
+ fi
+ [ "$NICECOMPILE" = yes ] && cmd_configure="nice $cmd_configure"
+ configure_skipped=0
+ if [ "$INCREMENTAL_BUILD" = "yes" -a -e "Makefile" ]; then
+ cmd_configure_orig=$cmd_configure
+ cmd_configure="echo Warning: no configure for module $module - as requested"
+ configure_skipped=1
+ fi
+ log_section "Configuration"
+ if [ -n "$KDELOGDIR" -a $configure_skipped -ne 1 ]; then
+ echo $cmd_configure >> $logfile
+ fi
+
+ if ! log_cmd "$cmd_configure"; then
+ echo "$str_error"
+ move_logfile "failed"
+ [ -n "$cmd_compress" ] && eval "$cmd_compress $logfile"
+ [ $critical -eq 0 ] || exit $err_compile_fail
+ continue
+ fi
+
+ log_endsection "Configuration"
+ if [ $configure_skipped -eq 1 ]; then
+ echo " skipped."
+ else
+ echo "$str_okay"
+ fi
+
+ if [ $configure_skipped -eq 1 ]; then
+ echo -n " Updating Makefile..."
+ cmd_make_makefile="$MAKE $MAKE_OPTS Makefile"
+ [ "$NICECOMPILE" = yes ] && cmd_make_makefile="nice $cmd_make_makefile"
+ log_section "Updating Makefile"
+ if [ -n "$KDELOGDIR" ]; then
+ echo $cmd_make_makefile >> $logfile
+ fi
+ if ! log_cmd "$cmd_make_makefile"; then
+ echo -n " Falling back to normal Makefile.cvs ..."
+ worked=0
+
+ if [ -n "$KDEBUILDDIR" ]; then
+ cd $KDESRCDIR/$module # get back to the supermarket
+ fi
+ rm Makefile.in
+ make_makefile_cvs
+ if [ -n "$KDEBUILDDIR" ]; then
+ cd $KDEBUILDDIR/$module # got the sugar, honey?
+ fi
+ echo -n " Configuring..."
+ if log_cmd "$cmd_configure_orig"; then
+ if log_cmd "$cmd_make_makefile"; then
+ worked=1
+ fi
+ fi
+ if [ $worked -ne 1 ]; then
+ echo "$str_error"
+ move_logfile "failed"
+ [ -n "$cmd_compress" ] && eval "$cmd_compress $logfile"
+ [ $critical -eq 0 ] || exit $err_compile_fail
+ continue
+ fi
+ fi
+
+ log_endsection "Updating Makefile"
+ echo "$str_okay"
+ fi
+
+ # Compile the module.
+ #
+ echo -n " Compiling..."
+ set_title "Compiling module $module..."
+ use_compile_target=no
+ [ -f $KDESRCDIR/$module/Makefile.am.in ] && [ -n "$MAKE_OPTS_COMPILE" ] && [ -n "$USE_UNSERMAKE" ] \
+ && ! (echo $NO_UNSERMAKE_MODULES | grep $module > /dev/null 2>&1) \
+ && use_compile_target=yes
+ if [ "$use_compile_target" = yes ]; then
+ cmd_make="$MAKE $MAKE_OPTS_COMPILE"
+ else
+ cmd_make="$MAKE $MAKE_OPTS"
+ fi
+
+ [ $critical -eq 0 ] && cmd_make="$cmd_make -k"
+ [ "$NICECOMPILE" = yes ] && cmd_make="nice $cmd_make"
+ [ "$use_compile_target" = yes ] && cmd_make="$cmd_make compile"
+
+ log_section "Compilation $cmd_make"
+ log_cmd "$cmd_make"
+ retval=$?
+
+ if [ $retval -eq 0 ]; then
+ log_endsection "Compilation"
+ echo "$str_okay"
+
+ # Link the module
+ if [ "$use_compile_target" = yes ]; then
+ echo -n " Linking..."
+ set_title "Linking module $module..."
+ cmd_make="$MAKE $MAKE_OPTS"
+ [ $critical -eq 0 ] && cmd_make="$cmd_make -k"
+ [ "$NICECOMPILE" = yes ] && cmd_make="nice $cmd_make"
+
+ log_section "Linking $cmd_make"
+ log_cmd "$cmd_make"
+ retval=$?
+ if [ $retval -eq 0 ]; then
+ log_endsection "Linking"
+ echo "$str_okay"
+ fi
+ fi
+ fi
+
+ if [ $retval -eq 0 ]; then
+ # Install the module.
+ #
+ cmd_make_install="$MAKE $MAKE_OPTS"
+ [ $critical -eq 0 ] && cmd_make_install="$cmd_make_install -k"
+ [ "$NICECOMPILE" = yes ] && cmd_make_install="nice $cmd_make_install"
+ cmd_make_install="$cmd_make_install install"
+ if [ ! -w $KDEDIRS ]; then
+ eval "$cmd_sudo \"$cmd_make_install\""
+ else
+ install_module
+ fi
+ else
+ echo "$str_error"
+ # Attempt to display the actual error
+ grep -m1 -A2 ":[0-9]*: error:" $logfile
+ move_logfile "failed"
+ [ -n "$cmd_compress" ] && eval "$cmd_compress $logfile"
+ [ $critical -eq 0 ] || exit $err_compile_fail
+ fi
+done
+
+set_title "KDE build finished."
+
+exit $err_no_error
+
+=head1 NAME
+
+kde-build - Updates and recompiles a tree of KDE modules
+
+=head1 SYNOPSIS
+
+ kde-build
+
+=head1 DESCRIPTION
+
+kde-build has been designed to keep a local copy of several KDE
+modules up to date and recompile them. Those modules have to be saved in a
+common directory, e.g. something like
+
+ ~/kde-src/
+ |
+ +-> kdelibs/
+ |
+ +-> kdebase/
+ |
+ \-> kdenetwork/
+
+In this case, the KDE source directory would be ~/kde-src/. The script will
+take care of compiling them in the correct order, checks for dependencies
+and resolves them as far as possible.
+
+Please note that, prior to first invocation of the script, the configuration
+file 'F<kde-buildrc>' has to be modified to reflect the local environment,
+such as paths etc.
+
+=head1 RETURN VALUE
+
+The following error codes are returned by the script.
+
+0 - No error seems to have occured.
+
+1 - The script could not change into the directory of a module.
+
+2 - The script could not open the file 'Makefile.in' of a module.
+
+3 - The configuration of a module failed.
+
+4 - The compilation of a module failed.
+
+5 - The installation of a module failed.
+
+6 - An invalid source directory was specified.
+
+7 - An invalid Qt directory was specified.
+
+11 - The configuration file F<kde-buildrc> couldn't be loaded.
+
+12 - Both CVS_CLEAN and INCREMENTAL_BUILD were set
+
+13 - Both BUILD_CLEAN and INCREMENTAL_BUILD were set
+
+=head1 EXAMPLES
+
+ cd ~/scripts/; vi ./kde-buildrc; ./kde-build
+
+=head1 BUGS
+
+Probably.
+
+=head1 TODO
+
+Add a DIAGNOSIS section to this man page.
+
+=head1 AUTHOR
+
+Frerich Raabe <raabe@kde.org>
+
+=cut
+
+# vim:et:ts=2:sw=2
diff --git a/scripts/kde-buildrc b/scripts/kde-buildrc
new file mode 100644
index 00000000..e3e31d14
--- /dev/null
+++ b/scripts/kde-buildrc
@@ -0,0 +1,205 @@
+################################################################################
+# Configures the kde-build script. #
+# (c) 2000, 2001, 2002, 2003 by Frerich Raabe <raabe@kde.org> #
+# (c) 2002, 2003 by Stephan Kulow <coolo@kde.org> #
+################################################################################
+
+# Where are your KDE sources?
+#
+KDESRCDIR="$PWD"
+
+# Where your KDE should be build, leave empty if built in KDESRCDIR
+#
+KDEBUILDDIR=""
+
+# Where shall I put the binaries?
+#
+KDEDIRS="/opt/kde"
+
+# Where is your Qt 3.3.x?
+#
+QTDIR="/usr/lib/qt3"
+
+# Should kppp be used to connect to the internet?
+#
+USE_KPPP="FALSE"
+
+#Set this higher if it takes a long time to load kppp on your machine
+#
+KPPP_LOAD_TIME="5"
+
+#Set this higher if it takes a long time for you to connect
+#
+KPPP_CONNECT_TIME="50"
+
+# If you would like logfiles of the compilation process, specify a directory
+# here in which the logfiles will be saved. If you want to disable logfile
+# generation, leave this blank.
+#
+KDELOGDIR="$KDESRCDIR/log"
+
+# Do you want the logfiles to be compressed? Set this variable to "yes" to
+# make the script compress the logfiles using bzip2 (using gzip as a
+# fallback is bzip2 cannot be found) and thereby save some diskspace.
+#
+COMPRESSLOGS="no"
+
+# Whether or not you want to compile and install the kdesupport module.
+#
+USEKDESUPPORT="yes"
+
+# Add modules you want to get compiled to this space-seperated list. Note that
+# you don't have to mention the fundamental modules 'arts, 'kdesupport',
+# 'kdelibs' and 'kdebase' here since the kde-build script will care about them
+# automatically.
+# See http://wiki.kdenews.org/tiki-index.php?page=KDE+CVS+Structure for a list
+# of available modules including extragear-* or koffice.
+
+KDEMODULES="kdetoys"
+
+#KDEMODULES="kdeaccessibility kdeadmin kdeartwork kdebindings kdeedu kdegames kdegraphics kdemultimedia kdenetwork kdepim kdesdk kdetoys kdeutils kdeaddons kdevelop kdewebdev koffice"
+#KDEMODULES="$KDEMODULES extragear-libs extragear-multimedia extragear-sysadmin extragear-office extragear-addons extragear-graphics extragear-network extragear-pim extragear-toys extragear-utils"
+
+
+# If you only want to svn update the listed modules, set it to yes.
+#
+ONLYLISTEDMODULES=yes
+
+# Do you want a clean install? This is recommended but please note that
+# you cannot use your previous KDE desktop while the compilation is
+# running. Set this to "no" to install the new snapshot over the previous
+# one, otherwise set it to "yes".
+#
+INSTALLFROMSCRATCH="no"
+
+# Do you plan to use this box otherwise while compiling? If so, you'd
+# probably set this variable to "yes". If this is set to "no", the
+# compilation process will try to eat up all the ressources, which speeds up
+# the overall progress but makes it a PITA to work on this box. ;)
+#
+NICECOMPILE="yes"
+
+# Set this variable to "yes" to activate certain cheap tweaks to speed up the
+# compilation process. Those tweaks mainly consist of lowering the
+# optimization of the resulting binary code.
+#
+TWEAKCOMPILE="no"
+
+# For SVN users only: Do you have a SVN account? If so, set this variable to
+# the correct name, otherwise leave this blank to use anonymous SVN.
+#
+ACCOUNT=""
+
+# For SVN users only: set this to "yes" in case you access svn.kde.org via
+# SSH. Otherwise, set this to "no."
+#
+SSHACCOUNT="no"
+
+# In case you left the ACCOUNT value empty (and thus use anonymous SVN
+# access), you can specify an anonsvn mirror here. Check
+# http://developer.kde.org/source/anonsvn.html for a list of mirror servers.
+#
+ANONSVNROOT="svn://anonsvn.kde.org/home/kde"
+
+# Do you want any special path from subversion? If so, specify its path here e.g.
+# /branches/KDE/3.3 or /tags/KDE/3.3.0. If you want the checked out branch,
+# leave this empty. Use "/trunk" if you want the development branch for sure
+# (leaving it empty will simply update whatever is there)
+#
+# you can specify a module specific branch in through PATH_ARTS
+#
+SUBDIR="/trunk/KDE/@MODULE@"
+SUBDIR_KDESUPPORT=/trunk/kdesupport
+for esubdir in libs multimedia sysadmin office addons graphics network pim toys utils; do
+ var=SUBDIR_EXTRAGEAR_`echo $esubdir | tr 'a-z' 'A-Z'`
+ eval "$var=/trunk/extragear/$esubdir"
+done
+
+# SUBDIR_ARTS=/branches/arts/1.3
+
+# Do you want only some subdirs from some module? Specify similiar to the
+# below syntax
+#CHECKOUT_PARTIAL_KDEMULTIMEDIA=juk
+#CHECKOUT_PARTIAL_KDEEXTRAGEAR_2="kile konversation"
+
+# If there are any modules in $KDESRCDIR which you don't want to be updated,
+# you can specify them in this space-seperated list, e.g. "qt-copy kde-common".
+#
+EXCLUDE=""
+
+# --- TODO: not supported anymore with svn ---
+# If you would like a virgin svn copy set this field to "yes", otherwise set
+# this to "no" (if set to "yes", 'make -f admin/Makefile.common cvs-clean'
+# is executed for every module).
+# Developers might find this pretty dangerous considering that they could have
+# forgotten to 'svn add' a file... ;-)
+# Users who want to stay at the bleeding edge will want to activate this in
+# order to make sure there aren't any remains of a previous compile.
+#
+#CVS_CLEAN="no"
+
+# Rely on the dependencies for Makefiles and configure?
+# If you dare to trust the build system, set it to "yes" ;-)
+#
+INCREMENTAL_BUILD="yes"
+
+# Flags to be passed to the 'configure' script.
+# A note: --enable-debug adds minimum debug symbols while an appended
+# =full gives you the full power and fills up your beloved hdd much better
+# --disable-closure is actually prefered if it works for you. It will
+# not create closure targets but link with some compiler flags to make
+# sure the compiler will fail when undefined symbols are there - which
+# is much faster if it works for you.
+#
+# You can define module-specific configure flags using
+# CONFIGUREFLAGS_ARTS, CONFIGUREFLAGS_KDELIBS, etc.
+# NOTE: These used to be appended to the general $CONFIGUREFLAGS value.
+# This is no longer true, you need to use $CONFIGUREFLAGS in the _MODNAME
+# version. In case the module name contains dashes ('-'), those needs to
+# be replaced with underscores.
+#
+CONFIGUREFLAGS="--enable-debug --disable-closure"
+# example: CONFIGUREFLAGS_KDEPIM="$CONFIGUREFLAGS --enable-debug=full"
+# example: CONFIGUREFLAGS_KDEEXTRAGEAR_2="$CONFIGUREFLAGS --without-java"
+
+# Set it to the path for unsermake if you want to test it instead of
+# automake.
+# USE_UNSERMAKE="$KDESRCDIR/kdenonbeta/unsermake/unsermake"
+
+# List modules here for which unsermake should not be used.
+#
+NO_UNSERMAKE_MODULES="kdenonbeta kdebindings"
+
+# If you use an extra build directory (KDEBUILDDIR), setting this to yes will
+# remove a module's build directory before configure is called.
+#
+BUILD_CLEAN=no
+
+# If you would like to pass any parameters to make add them here. If you
+# do not want to add any parameters leave this empty.
+# example:
+# MAKE_OPTS="-j 4 -l 4"
+#
+MAKE_OPTS=""
+
+# If you use unsermake, you can define different flags for the actual
+# compilation process. This is useful if you distribute the compilation
+# process over several computers, but need to link on one. So you would
+# define -j3 here and nothing above.
+# You can also use the special "DISTCC" keyword here; if found, it will
+# be replaced by the number of hosts listed in the $DISTCC_HOSTS
+# environment variable, multiplied by two. Hence, 'DISTCC_HOSTS="a b c"' and
+# 'MAKE_OPTS_COMPILE="-jDISTCC"' will result in 'MAKE_OPTS_COMPILE="-j6"'.
+# If you set something here, the value will be used alone, otherwise
+# MAKE_OPTS will be used alone.
+# You can use the special "TEAMBUILDER" keyword too, it will put the
+# returned value of tbcompiler -joblimit in there.
+#
+#MAKE_OPTS_COMPILE=""
+
+# If you would like to compile with a different make, please set it
+# here.
+#
+#MAKE=make
+
+# vim:et:ts=2:sw=2
diff --git a/scripts/kde-devel-emacs.el b/scripts/kde-devel-emacs.el
new file mode 100644
index 00000000..55955f0f
--- /dev/null
+++ b/scripts/kde-devel-emacs.el
@@ -0,0 +1,1890 @@
+;; -*- emacs-lisp -*-
+
+; To use this file, add this to your .emacs, uncommented :
+;(load "cc-engine.elc")
+;(load "~/kde2/kdesdk/scripts/kde-devel-emacs.el")
+; (setq auto-mode-alist
+; (append '(("\\.h$" . c++-mode)) auto-mode-alist))
+
+
+; Tip: also add (gnuserv-start), to be able to use gnuclient to open new files from a shell
+
+; Add (setq magic-keys-mode t) to your .xemacs/init.el or ~/.emacs (before loading this file)
+; to enable the magic keys in C++ mode (auto-insertion of spaces and newlines).
+
+; See the end of this file for the list of key bindings and for customizing them
+
+; This file is maintained by David Faure <faure@kde.org>
+
+
+; Global variables used to differentiate between different emacs
+; versions :
+; emacs - t if GNU/Emacs is used
+; xemacs - t if XEmacs is being used
+
+(if (string= (substring (emacs-version) 0 6) "XEmacs")
+ (progn
+ (setq emacs nil)
+ (setq xemacs t))
+ (progn
+ (setq emacs t)
+ (setq xemacs nil)))
+
+
+;; ------- First part, from Arnt's "c++ stuff"
+
+(defun agulbra-c++-tab (arg)
+ "Do the right thing about tabs in c++ mode"
+ (interactive "*P")
+ (cond
+ ((and (not (looking-at "[A-Za-z0-9]"))
+ (save-excursion
+ (forward-char -1)
+ (looking-at "[A-Za-z0-9:>_\\-\\&\\.(){}\\*\\+/]")))
+ (dabbrev-expand arg))
+ (t
+ (save-excursion
+ (beginning-of-line)
+ (c-indent-command)))))
+
+(defun agulbra-clean-out-spaces ()
+ "Remove spaces at ends of lines"
+ (interactive)
+ (and (not buffer-read-only)
+ (save-excursion
+ (goto-char (point-min))
+ (let ((count 0)
+ (bmp (buffer-modified-p)))
+ (while (re-search-forward "[ \t]+$" nil t)
+ (setq count (1+ count))
+ (replace-match "" t t))
+ (set-buffer-modified-p bmp)
+ (and (buffer-modified-p)
+ (basic-save-buffer))))))
+
+; the above used to contain (untabify (point-min) (point-max)) too
+
+;; it seems that recursion in agulbra-clean-out-spaces trashes Gnu/Emacs stack
+;; one of the functions in there has to behave differently than its XEmacs
+;; counterpart does, if you're reading this in a middle of may 2002 then
+;; please email me (Zack) at zackrat@att.net and bug me to finally fix this
+(defun agulbra-c++-clean-out-spaces ()
+ "Remove spaces at ends of lines, only in c++ mode"
+ (interactive)
+ (and (eq major-mode 'c++-mode)
+ (if xemacs
+ (agulbra-clean-out-spaces)
+ )))
+
+(add-hook 'find-file-hooks 'agulbra-c++-clean-out-spaces)
+(add-hook 'write-file-hooks 'agulbra-c++-clean-out-spaces)
+
+(defun agulbra-delete-into-nomenclature (&optional arg)
+ "Delete forward until the end of a nomenclature section or word.
+With arg, to it arg times."
+ (interactive "p")
+ (save-excursion
+ (let ((b (point-marker)))
+ (c-forward-into-nomenclature arg)
+ (delete-region b (point-marker)))))
+
+
+(setq c++-mode-hook
+ (lambda ()
+ (font-lock-mode)
+ (c-set-style "stroustrup")
+ (setq c-tab-always-indent nil
+ insert-tab-mode nil
+ indent-tabs-mode nil
+ fume-auto-rescan-buffer-p nil
+ c-basic-offset 4
+ c-access-key "\\<\\(signals\\|k_dcop\\|\\(public\\|protected\\|private\\)\\([ ]+slots\\)?\\)\\>:"
+ c-hanging-comment-ender-p nil
+ c-offsets-alist (append '((case-label . 0)
+ (access-label . -)
+ (label . 0)
+ (statement-cont . c-lineup-math)
+ ) c-offsets-alist))
+ (cond ((string-match "^\\(.*/qt/src\\)/.*/" buffer-file-truename)
+ (progn
+ (make-local-variable 'compile-command)
+ (setq compile-command
+ (concat "make -k -j 3 -C "
+ (substring buffer-file-truename
+ (match-beginning 1) (match-end 1))
+ " GNUmakefile.debug && make -k -j 3 -C "
+ (substring buffer-file-truename
+ (match-beginning 1) (match-end 1))
+ " -f GNUmakefile.debug"))))
+ ((string-match "^\\\(.*/2x/src\\\)/.*/" buffer-file-truename)
+ (progn
+ (make-local-variable 'compile-command)
+ (setq compile-command
+ (concat "make -k -C "
+ (substring buffer-file-truename
+ (match-beginning 1)
+ (match-end 1)))))))
+ (define-key c++-mode-map "\C-m" 'newline-and-indent)
+ (define-key c++-mode-map "\C-i" 'agulbra-c++-tab)
+ (define-key c++-mode-map "\ef" 'c-forward-into-nomenclature)
+ (define-key c++-mode-map "\ed" 'agulbra-delete-into-nomenclature)
+ (define-key c++-mode-map "\eb" 'c-backward-into-nomenclature)
+
+ ; Add (setq magic-keys-mode t) to your .emacs (before loading this file)
+ ; to enable the magic keys in C++ mode.
+ (and (boundp 'magic-keys-mode)
+ (progn
+ (define-key c++-mode-map [\(] 'insert-parens)
+ (define-key c++-mode-map [\)] 'insert-parens2)
+ (define-key c++-mode-map [,] 'insert-comma)
+ (define-key c++-mode-map [\{] 'insert-curly-brace)
+ ))
+))
+
+(setq c-mode-hook
+ (lambda ()
+ (font-lock-mode)
+ (setq c-tab-always-indent nil
+ c-basic-offset 4
+ c-offsets-alist (append '((case-label . 4)
+ (access-label . -)
+ (label . 0)
+ (statement-cont . c-lineup-math)
+ ) c-offsets-alist))))
+
+
+(defun agulbra-make-member ()
+ "make a skeleton member function in the .cpp or .cc file"
+ (interactive)
+ (let ((class nil)
+ (function nil)
+ (file (buffer-file-name))
+ (insertion-string nil)
+ (start nil))
+ (save-excursion
+ (and (re-search-backward "^class[ \t]" nil t)
+ (progn
+ (forward-word 1)
+ (while (looking-at "[ \t]*Q_EXPORT")
+ (forward-word 2))
+ (while (looking-at "[ \t]")
+ (forward-char 1))
+ (setq start (point))
+ (while (looking-at "[A-Za-z0-9_]")
+ (forward-char 1))
+ (setq class (buffer-substring start (point))))))
+ (progn
+ (and (looking-at "$")
+ (progn
+ (search-backward ")" nil t)
+ (forward-char)
+ (backward-sexp)))
+ (and (stringp class)
+ (re-search-backward "^[ \t]")
+ (progn
+ (while (looking-at "[ \t]")
+ (forward-char 1))
+ (setq start (point))
+ (and (search-forward "(" nil t)
+ (progn
+ (forward-char -1)
+ (forward-sexp)))
+ (and (looking-at "[ \t]+const")
+ (forward-word 1))
+ (and (looking-at ";")
+ (setq function (buffer-substring start (point))))
+ (re-search-forward "(" nil t))))
+ (and (stringp function)
+ (progn ;; get rid of virtual, static, multiple spaces, default values.
+ (and (string-match "[ \t]*\\<virtual\\>[ \t]*" function)
+ (setq function (replace-match " " t t function)))
+ (and (string-match "^\\(virtual\\>\\)?[ \t]*" function)
+ (setq function (replace-match "" t t function)))
+ (and (string-match "^\\(static\\>\\)?[ \t]*" function)
+ (setq function (replace-match "" t t function)))
+ (while (string-match " +" function)
+ (setq function (replace-match " " t t function)))
+ (while (string-match "\t+" function)
+ (setq function (replace-match " " t t function)))
+ (while (string-match " ?=[^,)]+" function)
+ (setq function (replace-match " " t t function)))
+ (while (string-match " +," function)
+ (setq function (replace-match "," t t function)))))
+ (and (stringp function)
+ (stringp class)
+ (stringp file)
+ (progn
+ (cond ((string-match (concat "^ *" class "[ \\t]*(") function)
+ (progn
+ (setq insertion-string
+ (concat
+ (replace-match
+ (concat class "::" class "(")
+ t t function)
+ "\n{\n \n}\n"))))
+ ((string-match (concat "^ *~" class "[ \\t]*(") function)
+ (progn
+ (setq insertion-string
+ (concat
+ (replace-match
+ (concat class "::~" class "(")
+ t t function)
+ "\n{\n \n}\n"))))
+ ((string-match " *\\([a-zA-Z0-9_]+\\)[ \\t]*(" function)
+ (progn
+ (setq insertion-string
+ (concat
+ (replace-match
+ (concat " " class "::" "\\1(")
+ t nil function)
+ "\n{\n \n}\n"))))
+ (t
+ (error (concat "Can't parse declaration ``"
+ function "'' in class ``" class
+ "'', aborting"))))
+ (stringp insertion-string))
+ (string-match "\\.h$" file)
+ (setq f (replace-match ".cpp" t t file))
+ (if (file-readable-p f )
+ (message "")
+ (progn
+ (string-match "\\.h$" file)
+ (setq f (replace-match ".cc" t t file))
+ ))
+ (find-file f)
+ (progn
+ (goto-char (point-max))
+ (insert insertion-string)
+ (forward-char -3)
+ (save-excursion
+ (and (string-match ".*/" file)
+ (setq file (replace-match "" t nil file)))
+ (or (re-search-backward
+ (concat "^#include *\"" file "\"$") nil t)
+ (progn
+ (goto-char (point-min))
+ (re-search-forward "^$" nil t)
+ (insert "\n#include \"" file "\"\n")))))))
+ (fume-rescan-buffer)
+)
+
+
+(setq compilation-error-regexp-systems-list '(gnu of comma 4bsd)
+ compilation-ask-about-save nil)
+
+
+(defun c-guess-basic-syntax ()
+ (save-excursion
+ (save-restriction
+ (beginning-of-line)
+ (let* ((indent-point (point))
+ (case-fold-search nil)
+ (fullstate (c-parse-state))
+ (state fullstate)
+ literal containing-sexp char-before-ip char-after-ip lim
+ syntax placeholder c-in-literal-cache inswitch-p
+ tmpsymbol keyword injava-inher special-brace-list
+ ;; narrow out any enclosing class or extern "C" block
+ (inclass-p (c-narrow-out-enclosing-class state indent-point))
+ inenclosing-p)
+ ;; check for meta top-level enclosing constructs, possible
+ ;; extern language definitions, possibly (in C++) namespace
+ ;; definitions.
+ (save-excursion
+ (save-restriction
+ (widen)
+ (if (and inclass-p
+ (progn
+ (goto-char (aref inclass-p 0))
+ (looking-at (concat c-extra-toplevel-key "[^_]"))))
+ (let ((enclosing (match-string 1)))
+ (cond
+ ((string-equal enclosing "extern")
+ (setq inenclosing-p 'extern))
+ ((string-equal enclosing "namespace")
+ (setq inenclosing-p 'namespace))
+ )))))
+ ;; get the buffer position of the most nested opening brace,
+ ;; if there is one, and it hasn't been narrowed out
+ (save-excursion
+ (goto-char indent-point)
+ (skip-chars-forward " \t}")
+ (skip-chars-backward " \t")
+ (while (and state
+ (not containing-sexp))
+ (setq containing-sexp (car state)
+ state (cdr state))
+ (if (consp containing-sexp)
+ ;; if cdr == point, then containing sexp is the brace
+ ;; that opens the sexp we close
+ (if (= (cdr containing-sexp) (point))
+ (setq containing-sexp (car containing-sexp))
+ ;; otherwise, ignore this element
+ (setq containing-sexp nil))
+ ;; ignore the bufpos if its been narrowed out by the
+ ;; containing class or does not contain the indent point
+ (if (or (<= containing-sexp (point-min))
+ (>= containing-sexp indent-point))
+ (setq containing-sexp nil)))))
+
+ ;; set the limit on the farthest back we need to search
+ (setq lim (or containing-sexp
+ (if (consp (car fullstate))
+ (cdr (car fullstate))
+ nil)
+ (point-min)))
+
+ ;; cache char before and after indent point, and move point to
+ ;; the most likely position to perform the majority of tests
+ (goto-char indent-point)
+ (skip-chars-forward " \t")
+ (setq char-after-ip (char-after))
+ (c-backward-syntactic-ws lim)
+ (setq char-before-ip (char-before))
+ (goto-char indent-point)
+ (skip-chars-forward " \t")
+
+ ;; are we in a literal?
+ (setq literal (c-in-literal lim))
+
+ ;; now figure out syntactic qualities of the current line
+ (cond
+ ;; CASE 1: in a string.
+ ((memq literal '(string))
+ (c-add-syntax 'string (c-point 'bopl)))
+ ;; CASE 2: in a C or C++ style comment.
+ ((memq literal '(c c++))
+ (c-add-syntax literal (car (c-literal-limits lim))))
+ ;; CASE 3: in a cpp preprocessor macro continuation.
+ ((and (eq literal 'pound)
+ (/= (save-excursion
+ (c-beginning-of-macro lim)
+ (setq placeholder (point)))
+ (c-point 'boi)))
+ (c-add-syntax 'cpp-macro-cont placeholder))
+ ;; CASE 4: In-expression statement.
+ ((and (or c-inexpr-class-key c-inexpr-block-key c-lambda-key)
+ (setq placeholder (c-looking-at-inexpr-block)))
+ (setq tmpsymbol (assq (car placeholder)
+ '((inexpr-class . class-open)
+ (inexpr-statement . block-open))))
+ (if tmpsymbol
+ ;; It's a statement block or an anonymous class.
+ (setq tmpsymbol (cdr tmpsymbol))
+ ;; It's a Pike lambda. Check whether we are between the
+ ;; lambda keyword and the argument list or at the defun
+ ;; opener.
+ (setq tmpsymbol (if (eq char-after-ip ?{)
+ 'inline-open
+ 'lambda-intro-cont)))
+ (goto-char (cdr placeholder))
+ (back-to-indentation)
+ (c-add-syntax tmpsymbol (point))
+ (unless (eq (point) (cdr placeholder))
+ (c-add-syntax (car placeholder))))
+ ;; CASE 5: Line is at top level.
+ ((null containing-sexp)
+ (cond
+ ;; CASE 5A: we are looking at a defun, brace list, class,
+ ;; or inline-inclass method opening brace
+ ((setq special-brace-list
+ (or (and c-special-brace-lists
+ (c-looking-at-special-brace-list))
+ (eq char-after-ip ?{)))
+ (cond
+ ;; CASE 5A.1: extern language or namespace construct
+ ((save-excursion
+ (goto-char indent-point)
+ (skip-chars-forward " \t")
+ (and (c-safe (progn (c-backward-sexp 2) t))
+ (looking-at (concat c-extra-toplevel-key "[^_]"))
+ (setq keyword (match-string 1)
+ placeholder (point))
+ (or (and (string-equal keyword "namespace")
+ (setq tmpsymbol 'namespace-open))
+ (and (string-equal keyword "extern")
+ (progn
+ (c-forward-sexp 1)
+ (c-forward-syntactic-ws)
+ (eq (char-after) ?\"))
+ (setq tmpsymbol 'extern-lang-open)))
+ ))
+ (goto-char placeholder)
+ (c-add-syntax tmpsymbol (c-point 'boi)))
+ ;; CASE 5A.2: we are looking at a class opening brace
+ ((save-excursion
+ (goto-char indent-point)
+ (skip-chars-forward " \t{")
+ ;; TBD: watch out! there could be a bogus
+ ;; c-state-cache in place when we get here. we have
+ ;; to go through much chicanery to ignore the cache.
+ ;; But of course, there may not be! BLECH! BOGUS!
+ (let ((decl
+ (let ((c-state-cache nil))
+ (c-search-uplist-for-classkey (c-parse-state))
+ )))
+ (and decl
+ (setq placeholder (aref decl 0)))
+ ))
+ (c-add-syntax 'class-open placeholder))
+ ;; CASE 5A.3: brace list open
+ ((save-excursion
+ (c-beginning-of-statement-1 lim)
+ ;; c-b-o-s could have left us at point-min
+ (and (bobp)
+ (c-forward-syntactic-ws indent-point))
+ (if (looking-at "typedef[^_]")
+ (progn (c-forward-sexp 1)
+ (c-forward-syntactic-ws indent-point)))
+ (setq placeholder (c-point 'boi))
+ (or (consp special-brace-list)
+ (and (or (save-excursion
+ (goto-char indent-point)
+ (setq tmpsymbol nil)
+ (while (and (> (point) placeholder)
+ (= (c-backward-token-1 1 t) 0)
+ (/= (char-after) ?=))
+ (if (and (not tmpsymbol)
+ (looking-at "new\\>[^_]"))
+ (setq tmpsymbol 'topmost-intro-cont)))
+ (eq (char-after) ?=))
+ (looking-at "enum[ \t\n]+"))
+ (save-excursion
+ (while (and (< (point) indent-point)
+ (= (c-forward-token-1 1 t) 0)
+ (not (memq (char-after) '(?\; ?\()))))
+ (not (memq (char-after) '(?\; ?\()))
+ ))))
+ (if (and (c-major-mode-is 'java-mode)
+ (eq tmpsymbol 'topmost-intro-cont))
+ ;; We're in Java and have found that the open brace
+ ;; belongs to a "new Foo[]" initialization list,
+ ;; which means the brace list is part of an
+ ;; expression and not a top level definition. We
+ ;; therefore treat it as any topmost continuation
+ ;; even though the semantically correct symbol still
+ ;; is brace-list-open, on the same grounds as in
+ ;; case 10B.2.
+ (progn
+ (c-beginning-of-statement-1 lim)
+ (c-forward-syntactic-ws)
+ (c-add-syntax 'topmost-intro-cont (c-point 'boi)))
+ (c-add-syntax 'brace-list-open placeholder)))
+ ;; CASE 5A.4: inline defun open
+ ((and inclass-p (not inenclosing-p))
+ (c-add-syntax 'inline-open)
+ (c-add-class-syntax 'inclass inclass-p))
+ ;; CASE 5A.5: ordinary defun open
+ (t
+ (goto-char placeholder)
+ (if inclass-p
+ (c-add-syntax 'defun-open (c-point 'boi))
+ (c-add-syntax 'defun-open (c-point 'bol)))
+ )))
+ ;; CASE 5B: first K&R arg decl or member init
+ ((c-just-after-func-arglist-p)
+ (cond
+ ;; CASE 5B.1: a member init
+ ((or (eq char-before-ip ?:)
+ (eq char-after-ip ?:))
+ ;; this line should be indented relative to the beginning
+ ;; of indentation for the topmost-intro line that contains
+ ;; the prototype's open paren
+ ;; TBD: is the following redundant?
+ (if (eq char-before-ip ?:)
+ (forward-char -1))
+ (c-backward-syntactic-ws lim)
+ ;; TBD: is the preceding redundant?
+ (if (eq (char-before) ?:)
+ (progn (forward-char -1)
+ (c-backward-syntactic-ws lim)))
+ (if (eq (char-before) ?\))
+ (c-backward-sexp 1))
+ (setq placeholder (point))
+ (save-excursion
+ (and (c-safe (c-backward-sexp 1) t)
+ (looking-at "throw[^_]")
+ (c-safe (c-backward-sexp 1) t)
+ (setq placeholder (point))))
+ (goto-char placeholder)
+ (c-add-syntax 'member-init-intro (c-point 'boi))
+ ;; we don't need to add any class offset since this
+ ;; should be relative to the ctor's indentation
+ )
+ ;; CASE 5B.2: K&R arg decl intro
+ (c-recognize-knr-p
+ (c-add-syntax 'knr-argdecl-intro (c-point 'boi))
+ (if inclass-p (c-add-class-syntax 'inclass inclass-p)))
+ ;; CASE 5B.3: Inside a member init list.
+ ((c-beginning-of-member-init-list lim)
+ (c-forward-syntactic-ws)
+ (c-add-syntax 'member-init-cont (point)))
+ ;; CASE 5B.4: Nether region after a C++ or Java func
+ ;; decl, which could include a `throws' declaration.
+ (t
+ (c-beginning-of-statement-1 lim)
+ (c-add-syntax 'func-decl-cont (c-point 'boi))
+ )))
+ ;; CASE 5C: inheritance line. could be first inheritance
+ ;; line, or continuation of a multiple inheritance
+ ((or (and c-baseclass-key
+ (progn
+ (when (eq char-after-ip ?,)
+ (skip-chars-forward " \t")
+ (forward-char))
+ (looking-at c-baseclass-key)))
+ (and (or (eq char-before-ip ?:)
+ ;; watch out for scope operator
+ (save-excursion
+ (and (eq char-after-ip ?:)
+ (c-safe (progn (forward-char 1) t))
+ (not (eq (char-after) ?:))
+ )))
+ (save-excursion
+ (c-backward-syntactic-ws lim)
+ (if (eq char-before-ip ?:)
+ (progn
+ (forward-char -1)
+ (c-backward-syntactic-ws lim)))
+ (back-to-indentation)
+ (looking-at c-class-key)))
+ ;; for Java
+ (and (c-major-mode-is 'java-mode)
+ (let ((fence (save-excursion
+ (c-beginning-of-statement-1 lim)
+ (point)))
+ cont done)
+ (save-excursion
+ (while (not done)
+ (cond ((looking-at c-Java-special-key)
+ (setq injava-inher (cons cont (point))
+ done t))
+ ((or (not (c-safe (c-forward-sexp -1) t))
+ (<= (point) fence))
+ (setq done t))
+ )
+ (setq cont t)))
+ injava-inher)
+ (not (c-crosses-statement-barrier-p (cdr injava-inher)
+ (point)))
+ ))
+ (cond
+ ;; CASE 5C.1: non-hanging colon on an inher intro
+ ((eq char-after-ip ?:)
+ (c-backward-syntactic-ws lim)
+ (c-add-syntax 'inher-intro (c-point 'boi))
+ ;; don't add inclass symbol since relative point already
+ ;; contains any class offset
+ )
+ ;; CASE 5C.2: hanging colon on an inher intro
+ ((eq char-before-ip ?:)
+ (c-add-syntax 'inher-intro (c-point 'boi))
+ (if inclass-p (c-add-class-syntax 'inclass inclass-p)))
+ ;; CASE agulbrahack.1:
+ ((and inclass-p
+ c-access-key
+ (looking-at c-access-key))
+ (c-add-syntax 'access-label (c-point 'bonl))
+ )
+ ;; CASE 5C.3: in a Java implements/extends
+ (injava-inher
+ (let ((where (cdr injava-inher))
+ (cont (car injava-inher)))
+ (goto-char where)
+ (cond ((looking-at "throws[ \t\n]")
+ (c-add-syntax 'func-decl-cont
+ (progn (c-beginning-of-statement-1 lim)
+ (c-point 'boi))))
+ (cont (c-add-syntax 'inher-cont where))
+ (t (c-add-syntax 'inher-intro
+ (progn (goto-char (cdr injava-inher))
+ (c-beginning-of-statement-1 lim)
+ (point))))
+ )))
+ ;; CASE 5C.4: a continued inheritance line
+ (t
+ (c-beginning-of-inheritance-list lim)
+ (c-add-syntax 'inher-cont (point))
+ ;; don't add inclass symbol since relative point already
+ ;; contains any class offset
+ )))
+ ;; CASE 5D: this could be a top-level compound statement, a
+ ;; member init list continuation, or a template argument
+ ;; list continuation.
+ ((c-with-syntax-table (if (c-major-mode-is 'c++-mode)
+ c++-template-syntax-table
+ (syntax-table))
+ (save-excursion
+ (while (and (= (c-backward-token-1 1 t lim) 0)
+ (not (looking-at "[;{<,]"))))
+ (eq (char-after) ?,)))
+ (goto-char indent-point)
+ (c-beginning-of-member-init-list lim)
+ (cond
+ ;; CASE 5D.1: hanging member init colon, but watch out
+ ;; for bogus matches on access specifiers inside classes.
+ ((and (save-excursion
+ (setq placeholder (point))
+ (c-backward-token-1 1 t lim)
+ (and (eq (char-after) ?:)
+ (not (eq (char-before) ?:))))
+ (save-excursion
+ (goto-char placeholder)
+ (back-to-indentation)
+ (or
+ (/= (car (save-excursion
+ (parse-partial-sexp (point) placeholder)))
+ 0)
+ (and
+ (if c-access-key (not (looking-at c-access-key)) t)
+ (not (looking-at c-class-key))
+ (if c-bitfield-key (not (looking-at c-bitfield-key)) t))
+ )))
+ (goto-char placeholder)
+ (c-forward-syntactic-ws)
+ (c-add-syntax 'member-init-cont (point))
+ ;; we do not need to add class offset since relative
+ ;; point is the member init above us
+ )
+ ;; CASE 5D.2: non-hanging member init colon
+ ((progn
+ (c-forward-syntactic-ws indent-point)
+ (eq (char-after) ?:))
+ (skip-chars-forward " \t:")
+ (c-add-syntax 'member-init-cont (point)))
+ ;; CASE 5D.3: perhaps a multiple inheritance line?
+ ((save-excursion
+ (c-beginning-of-statement-1 lim)
+ (setq placeholder (point))
+ (looking-at c-inher-key))
+ (goto-char placeholder)
+ (c-add-syntax 'inher-cont (c-point 'boi)))
+ ;; CASE 5D.4: perhaps a template list continuation?
+ ((save-excursion
+ (goto-char indent-point)
+ (skip-chars-backward "^<" lim)
+ ;; not sure if this is the right test, but it should
+ ;; be fast and mostly accurate.
+ (setq placeholder (point))
+ (and (eq (char-before) ?<)
+ (not (c-in-literal lim))))
+ ;; we can probably indent it just like an arglist-cont
+ (goto-char placeholder)
+ (c-beginning-of-statement-1 lim)
+ (c-add-syntax 'template-args-cont (c-point 'boi)))
+ ;; CASE 5D.5: perhaps a top-level statement-cont
+ (t
+ (c-beginning-of-statement-1 lim)
+ ;; skip over any access-specifiers
+ (and inclass-p c-access-key
+ (while (looking-at c-access-key)
+ (forward-line 1)))
+ ;; skip over comments, whitespace
+ (c-forward-syntactic-ws indent-point)
+ (c-add-syntax 'statement-cont (c-point 'boi)))
+ ))
+ ;; CASE 5E: we are looking at a access specifier
+ ((and inclass-p
+ c-access-key
+ (looking-at c-access-key))
+ (c-add-syntax 'access-label (c-point 'bonl))
+ (c-add-class-syntax 'inclass inclass-p))
+ ;; CASE 5F: extern-lang-close or namespace-close?
+ ((and inenclosing-p
+ (eq char-after-ip ?}))
+ (setq tmpsymbol (if (eq inenclosing-p 'extern)
+ 'extern-lang-close
+ 'namespace-close))
+ (c-add-syntax tmpsymbol (aref inclass-p 0)))
+ ;; CASE 5G: we are looking at the brace which closes the
+ ;; enclosing nested class decl
+ ((and inclass-p
+ (eq char-after-ip ?})
+ (save-excursion
+ (save-restriction
+ (widen)
+ (forward-char 1)
+ (and (c-safe (progn (c-backward-sexp 1) t))
+ (= (point) (aref inclass-p 1))
+ ))))
+ (c-add-class-syntax 'class-close inclass-p))
+ ;; CASE 5H: we could be looking at subsequent knr-argdecls
+ ((and c-recognize-knr-p
+ ;; here we essentially use the hack that is used in
+ ;; Emacs' c-mode.el to limit how far back we should
+ ;; look. The assumption is made that argdecls are
+ ;; indented at least one space and that function
+ ;; headers are not indented.
+ (let ((limit (save-excursion
+ (re-search-backward "^[^ \^L\t\n#]" nil 'move)
+ (point))))
+ (save-excursion
+ (c-backward-syntactic-ws limit)
+ (setq placeholder (point))
+ (while (and (memq (char-before) '(?\; ?,))
+ (> (point) limit))
+ (beginning-of-line)
+ (setq placeholder (point))
+ (c-backward-syntactic-ws limit))
+ (and (eq (char-before) ?\))
+ (or (not c-method-key)
+ (progn
+ (c-forward-sexp -1)
+ (forward-char -1)
+ (c-backward-syntactic-ws)
+ (not (or (memq (char-before) '(?- ?+))
+ ;; or a class category
+ (progn
+ (c-forward-sexp -2)
+ (looking-at c-class-key))
+ )))))
+ ))
+ (save-excursion
+ (c-beginning-of-statement-1)
+ (not (looking-at "typedef[ \t\n]+"))))
+ (goto-char placeholder)
+ (c-add-syntax 'knr-argdecl (c-point 'boi)))
+ ;; CASE 5I: ObjC method definition.
+ ((and c-method-key
+ (looking-at c-method-key))
+ (c-add-syntax 'objc-method-intro (c-point 'boi)))
+ ;; CASE 5J: we are at the topmost level, make sure we skip
+ ;; back past any access specifiers
+ ((progn
+ (c-backward-syntactic-ws lim)
+ (while (and inclass-p
+ c-access-key
+ (not (bobp))
+ (save-excursion
+ (c-safe (progn (c-backward-sexp 1) t))
+ ;; agulbrahack 2
+ (and (looking-at "slots:")
+ (c-backward-sexp 1))
+ (looking-at c-access-key)))
+ (c-backward-sexp 1)
+ (c-backward-syntactic-ws lim))
+ (or (bobp)
+ (memq (char-before) '(?\; ?\}))))
+ ;; real beginning-of-line could be narrowed out due to
+ ;; enclosure in a class block
+ (save-restriction
+ (widen)
+ (c-add-syntax 'topmost-intro (c-point 'bol))
+ (if inclass-p
+ (progn
+ (goto-char (aref inclass-p 1))
+ (or (= (point) (c-point 'boi))
+ (goto-char (aref inclass-p 0)))
+ (cond
+ ((eq inenclosing-p 'extern)
+ (c-add-syntax 'inextern-lang (c-point 'boi)))
+ ((eq inenclosing-p 'namespace)
+ (c-add-syntax 'innamespace (c-point 'boi)))
+ (t (c-add-class-syntax 'inclass inclass-p)))
+ ))
+ ))
+ ;; CASE 5K: we are at an ObjC or Java method definition
+ ;; continuation line.
+ ((and c-method-key
+ (progn
+ (c-beginning-of-statement-1 lim)
+ (beginning-of-line)
+ (looking-at c-method-key)))
+ (c-add-syntax 'objc-method-args-cont (point)))
+ ;; CASE 5L: we are at the first argument of a template
+ ;; arglist that begins on the previous line.
+ ((eq (char-before) ?<)
+ (c-beginning-of-statement-1 lim)
+ (c-forward-syntactic-ws)
+ (c-add-syntax 'template-args-cont (c-point 'boi)))
+ ;; CASE 5M: we are at a topmost continuation line
+ (t
+ (c-beginning-of-statement-1 lim)
+ (c-forward-syntactic-ws)
+ (c-add-syntax 'topmost-intro-cont (c-point 'boi)))
+ )) ; end CASE 5
+ ;; (CASE 6 has been removed.)
+ ;; CASE 7: line is an expression, not a statement. Most
+ ;; likely we are either in a function prototype or a function
+ ;; call argument list
+ ((not (or (and c-special-brace-lists
+ (save-excursion
+ (goto-char containing-sexp)
+ (c-looking-at-special-brace-list)))
+ (eq (char-after containing-sexp) ?{)))
+ (c-backward-syntactic-ws containing-sexp)
+ (cond
+ ;; CASE 7A: we are looking at the arglist closing paren
+ ((and (or (c-major-mode-is 'pike-mode)
+ ;; Don't check this in Pike since it allows a
+ ;; comma after the last arg.
+ (not (eq char-before-ip ?,)))
+ (memq char-after-ip '(?\) ?\])))
+ (goto-char containing-sexp)
+ (setq placeholder (c-point 'boi))
+ (when (and (c-safe (backward-up-list 1) t)
+ (> (point) placeholder))
+ (forward-char)
+ (skip-chars-forward " \t")
+ (setq placeholder (point)))
+ (c-add-syntax 'arglist-close placeholder))
+ ;; CASE 7B: Looking at the opening brace of an
+ ;; in-expression block or brace list.
+ ((eq char-after-ip ?{)
+ (goto-char indent-point)
+ (setq placeholder (c-point 'boi))
+ (goto-char containing-sexp)
+ (if (c-inside-bracelist-p placeholder
+ (cons containing-sexp state))
+ (progn
+ (c-add-syntax 'brace-list-open (c-point 'boi))
+ (c-add-syntax 'inexpr-class))
+ (c-add-syntax 'block-open (c-point 'boi))
+ (c-add-syntax 'inexpr-statement)))
+ ;; CASE 7C: we are looking at the first argument in an empty
+ ;; argument list. Use arglist-close if we're actually
+ ;; looking at a close paren or bracket.
+ ((memq char-before-ip '(?\( ?\[))
+ (goto-char containing-sexp)
+ (setq placeholder (c-point 'boi))
+ (when (and (c-safe (backward-up-list 1) t)
+ (> (point) placeholder))
+ (forward-char)
+ (skip-chars-forward " \t")
+ (setq placeholder (point)))
+ (c-add-syntax 'arglist-intro placeholder))
+ ;; CASE 7D: we are inside a conditional test clause. treat
+ ;; these things as statements
+ ((save-excursion
+ (goto-char containing-sexp)
+ (and (c-safe (progn (c-forward-sexp -1) t))
+ (looking-at "\\<for\\>[^_]")))
+ (goto-char (1+ containing-sexp))
+ (c-forward-syntactic-ws indent-point)
+ (c-beginning-of-statement-1 containing-sexp)
+ (if (eq char-before-ip ?\;)
+ (c-add-syntax 'statement (point))
+ (c-add-syntax 'statement-cont (point))
+ ))
+ ;; CASE 7E: maybe a continued method call. This is the case
+ ;; when we are inside a [] bracketed exp, and what precede
+ ;; the opening bracket is not an identifier.
+ ((and c-method-key
+ (eq (char-after containing-sexp) ?\[)
+ (save-excursion
+ (goto-char (1- containing-sexp))
+ (c-backward-syntactic-ws (c-point 'bod))
+ (if (not (looking-at c-symbol-key))
+ (c-add-syntax 'objc-method-call-cont containing-sexp))
+ )))
+ ;; CASE 7F: we are looking at an arglist continuation line,
+ ;; but the preceding argument is on the same line as the
+ ;; opening paren. This case includes multi-line
+ ;; mathematical paren groupings, but we could be on a
+ ;; for-list continuation line
+ ((save-excursion
+ (goto-char (1+ containing-sexp))
+ (skip-chars-forward " \t")
+ (not (eolp)))
+ (goto-char containing-sexp)
+ (setq placeholder (c-point 'boi))
+ (when (and (c-safe (backward-up-list 1) t)
+ (> (point) placeholder))
+ (forward-char)
+ (skip-chars-forward " \t")
+ (setq placeholder (point)))
+ (c-add-syntax 'arglist-cont-nonempty placeholder))
+ ;; CASE 7G: we are looking at just a normal arglist
+ ;; continuation line
+ (t (c-beginning-of-statement-1 containing-sexp)
+ (forward-char 1)
+ (c-forward-syntactic-ws indent-point)
+ (c-add-syntax 'arglist-cont (c-point 'boi)))
+ ))
+ ;; CASE 8: func-local multi-inheritance line
+ ((and c-baseclass-key
+ (save-excursion
+ (goto-char indent-point)
+ (skip-chars-forward " \t")
+ (looking-at c-baseclass-key)))
+ (goto-char indent-point)
+ (skip-chars-forward " \t")
+ (cond
+ ;; CASE 8A: non-hanging colon on an inher intro
+ ((eq char-after-ip ?:)
+ (c-backward-syntactic-ws lim)
+ (c-add-syntax 'inher-intro (c-point 'boi)))
+ ;; CASE 8B: hanging colon on an inher intro
+ ((eq char-before-ip ?:)
+ (c-add-syntax 'inher-intro (c-point 'boi)))
+ ;; CASE 8C: a continued inheritance line
+ (t
+ (c-beginning-of-inheritance-list lim)
+ (c-add-syntax 'inher-cont (point))
+ )))
+ ;; CASE 9: we are inside a brace-list
+ ((setq special-brace-list
+ (or (and c-special-brace-lists
+ (save-excursion
+ (goto-char containing-sexp)
+ (c-looking-at-special-brace-list)))
+ (c-inside-bracelist-p containing-sexp state)))
+ (cond
+ ;; CASE 9A: In the middle of a special brace list opener.
+ ((and (consp special-brace-list)
+ (save-excursion
+ (goto-char containing-sexp)
+ (eq (char-after) ?\())
+ (eq char-after-ip (car (cdr special-brace-list))))
+ (goto-char (car (car special-brace-list)))
+ (skip-chars-backward " \t")
+ (if (and (bolp)
+ (assoc 'statement-cont
+ (setq placeholder (c-guess-basic-syntax))))
+ (setq syntax placeholder)
+ (c-beginning-of-statement-1 lim)
+ (c-forward-token-1 0)
+ (if (looking-at "typedef\\>") (c-forward-token-1 1))
+ (c-add-syntax 'brace-list-open (c-point 'boi))))
+ ;; CASE 9B: brace-list-close brace
+ ((if (consp special-brace-list)
+ ;; Check special brace list closer.
+ (progn
+ (goto-char (car (car special-brace-list)))
+ (save-excursion
+ (goto-char indent-point)
+ (back-to-indentation)
+ (or
+ ;; We were between the special close char and the `)'.
+ (and (eq (char-after) ?\))
+ (eq (1+ (point)) (cdr (car special-brace-list))))
+ ;; We were before the special close char.
+ (and (eq (char-after) (cdr (cdr special-brace-list)))
+ (= (c-forward-token-1) 0)
+ (eq (1+ (point)) (cdr (car special-brace-list)))))))
+ ;; Normal brace list check.
+ (and (eq char-after-ip ?})
+ (c-safe (progn (forward-char 1)
+ (c-backward-sexp 1)
+ t))
+ (= (point) containing-sexp)))
+ (c-add-syntax 'brace-list-close (c-point 'boi)))
+ (t
+ ;; Prepare for the rest of the cases below by going to the
+ ;; token following the opening brace
+ (if (consp special-brace-list)
+ (progn
+ (goto-char (car (car special-brace-list)))
+ (c-forward-token-1 1 nil indent-point))
+ (goto-char containing-sexp))
+ (forward-char)
+ (let ((start (point)))
+ (c-forward-syntactic-ws indent-point)
+ (goto-char (max start (c-point 'bol))))
+ (skip-chars-forward " \t\n\r" indent-point)
+ (cond
+ ;; CASE 9C: we're looking at the first line in a brace-list
+ ((= (point) indent-point)
+ (goto-char containing-sexp)
+ (c-add-syntax 'brace-list-intro (c-point 'boi))
+ ) ; end CASE 9C
+ ;; CASE 9D: this is just a later brace-list-entry or
+ ;; brace-entry-open
+ (t (if (or (eq char-after-ip ?{)
+ (and c-special-brace-lists
+ (save-excursion
+ (goto-char indent-point)
+ (c-forward-syntactic-ws (c-point 'eol))
+ (c-looking-at-special-brace-list (point)))))
+ (c-add-syntax 'brace-entry-open (point))
+ (c-add-syntax 'brace-list-entry (point))
+ )) ; end CASE 9D
+ )))) ; end CASE 9
+ ;; CASE 10: A continued statement
+ ((and (not (memq char-before-ip '(?\; ?:)))
+ (or (not (eq char-before-ip ?}))
+ (c-looking-at-inexpr-block-backward containing-sexp))
+ (> (point)
+ (save-excursion
+ (c-beginning-of-statement-1 containing-sexp)
+ (c-forward-syntactic-ws)
+ (setq placeholder (point))))
+ (/= placeholder containing-sexp))
+ (goto-char indent-point)
+ (skip-chars-forward " \t")
+ (let ((after-cond-placeholder
+ (save-excursion
+ (goto-char placeholder)
+ (if (and c-conditional-key (looking-at c-conditional-key))
+ (progn
+ (c-safe (c-skip-conditional))
+ (c-forward-syntactic-ws)
+ (if (eq (char-after) ?\;)
+ (progn
+ (forward-char 1)
+ (c-forward-syntactic-ws)))
+ (point))
+ nil))))
+ (cond
+ ;; CASE 10A: substatement
+ ((and after-cond-placeholder
+ (>= after-cond-placeholder indent-point))
+ (goto-char placeholder)
+ (if (eq char-after-ip ?{)
+ (c-add-syntax 'substatement-open (c-point 'boi))
+ (c-add-syntax 'substatement (c-point 'boi))))
+ ;; CASE 10B: open braces for class or brace-lists
+ ((setq special-brace-list
+ (or (and c-special-brace-lists
+ (c-looking-at-special-brace-list))
+ (eq char-after-ip ?{)))
+ (cond
+ ;; CASE 10B.1: class-open
+ ((save-excursion
+ (goto-char indent-point)
+ (skip-chars-forward " \t{")
+ (let ((decl (c-search-uplist-for-classkey (c-parse-state))))
+ (and decl
+ (setq placeholder (aref decl 0)))
+ ))
+ (c-add-syntax 'class-open placeholder))
+ ;; CASE 10B.2: brace-list-open
+ ((or (consp special-brace-list)
+ (save-excursion
+ (goto-char placeholder)
+ (looking-at "\\<enum\\>"))
+ (save-excursion
+ (goto-char indent-point)
+ (while (and (> (point) placeholder)
+ (= (c-backward-token-1 1 t) 0)
+ (/= (char-after) ?=)))
+ (eq (char-after) ?=)))
+ ;; The most semantically accurate symbol here is
+ ;; brace-list-open, but we report it simply as a
+ ;; statement-cont. The reason is that one normally
+ ;; adjusts brace-list-open for brace lists as
+ ;; top-level constructs, and brace lists inside
+ ;; statements is a completely different context.
+ (goto-char indent-point)
+ (c-beginning-of-closest-statement)
+ (c-add-syntax 'statement-cont (c-point 'boi)))
+ ;; CASE 10B.3: The body of a function declared inside a
+ ;; normal block. This can only occur in Pike.
+ ((and (c-major-mode-is 'pike-mode)
+ (progn
+ (goto-char indent-point)
+ (not (c-looking-at-bos))))
+ (c-beginning-of-closest-statement)
+ (c-add-syntax 'defun-open (c-point 'boi)))
+ ;; CASE 10B.4: catch-all for unknown construct.
+ (t
+ ;; Can and should I add an extensibility hook here?
+ ;; Something like c-recognize-hook so support for
+ ;; unknown constructs could be added. It's probably a
+ ;; losing proposition, so I dunno.
+ (goto-char placeholder)
+ (c-add-syntax 'statement-cont (c-point 'boi))
+ (c-add-syntax 'block-open))
+ ))
+ ;; CASE 10C: iostream insertion or extraction operator
+ ((looking-at "<<\\|>>")
+ (goto-char placeholder)
+ (and after-cond-placeholder
+ (goto-char after-cond-placeholder))
+ (while (and (re-search-forward "<<\\|>>" indent-point 'move)
+ (c-in-literal placeholder)))
+ ;; if we ended up at indent-point, then the first
+ ;; streamop is on a separate line. Indent the line like
+ ;; a statement-cont instead
+ (if (/= (point) indent-point)
+ (c-add-syntax 'stream-op (c-point 'boi))
+ (c-backward-syntactic-ws lim)
+ (c-add-syntax 'statement-cont (c-point 'boi))))
+ ;; CASE 10D: continued statement. find the accurate
+ ;; beginning of statement or substatement
+ (t
+ (c-beginning-of-statement-1 after-cond-placeholder)
+ ;; KLUDGE ALERT! c-beginning-of-statement-1 can leave
+ ;; us before the lim we're passing in. It should be
+ ;; fixed, but I'm worried about side-effects at this
+ ;; late date. Fix for v5.
+ (goto-char (or (and after-cond-placeholder
+ (max after-cond-placeholder (point)))
+ (point)))
+ (c-add-syntax 'statement-cont (point)))
+ )))
+ ;; CASE 11: an else clause?
+ ((looking-at "\\<else\\>[^_]")
+ (c-backward-to-start-of-if containing-sexp)
+ (c-add-syntax 'else-clause (c-point 'boi)))
+ ;; CASE 12: Statement. But what kind? Lets see if its a
+ ;; while closure of a do/while construct
+ ((progn
+ (goto-char indent-point)
+ (skip-chars-forward " \t")
+ (and (looking-at "while\\b[^_]")
+ (save-excursion
+ (c-backward-to-start-of-do containing-sexp)
+ (setq placeholder (point))
+ (looking-at "do\\b[^_]"))
+ ))
+ (goto-char placeholder)
+ (c-add-syntax 'do-while-closure (c-point 'boi)))
+ ;; CASE 13: A catch or finally clause? This case is simpler
+ ;; than if-else and do-while, because a block is required
+ ;; after every try, catch and finally.
+ ((save-excursion
+ (and (cond ((c-major-mode-is 'c++-mode)
+ (looking-at "\\<catch\\>[^_]"))
+ ((c-major-mode-is 'java-mode)
+ (looking-at "\\<\\(catch\\|finally\\)\\>[^_]")))
+ (c-safe (c-backward-sexp) t)
+ (eq (char-after) ?{)
+ (c-safe (c-backward-sexp) t)
+ (if (eq (char-after) ?\()
+ (c-safe (c-backward-sexp) t)
+ t)
+ (looking-at "\\<\\(try\\|catch\\)\\>[^_]")
+ (setq placeholder (c-point 'boi))))
+ (c-add-syntax 'catch-clause placeholder))
+ ;; CASE 14: A case or default label
+ ((looking-at c-switch-label-key)
+ (goto-char containing-sexp)
+ ;; check for hanging braces
+ (if (/= (point) (c-point 'boi))
+ (c-forward-sexp -1))
+ (c-add-syntax 'case-label (c-point 'boi)))
+ ;; CASE 15: any other label
+ ((looking-at c-label-key)
+ (goto-char containing-sexp)
+ ;; check for hanging braces
+ (if (/= (point) (c-point 'boi))
+ (c-forward-sexp -1))
+ (c-add-syntax 'label (c-point 'boi)))
+ ;; CASE 16: block close brace, possibly closing the defun or
+ ;; the class
+ ((eq char-after-ip ?})
+ (let* ((lim (c-safe-position containing-sexp fullstate))
+ (relpos (save-excursion
+ (goto-char containing-sexp)
+ (if (/= (point) (c-point 'boi))
+ (c-beginning-of-statement-1 lim))
+ (c-point 'boi))))
+ (cond
+ ;; CASE 16A: closing a lambda defun or an in-expression
+ ;; block?
+ ((save-excursion
+ (goto-char containing-sexp)
+ (setq placeholder (c-looking-at-inexpr-block)))
+ (setq tmpsymbol (if (eq (car placeholder) 'inlambda)
+ 'inline-close
+ 'block-close))
+ (goto-char containing-sexp)
+ (back-to-indentation)
+ (if (= containing-sexp (point))
+ (c-add-syntax tmpsymbol (point))
+ (goto-char (cdr placeholder))
+ (back-to-indentation)
+ (c-add-syntax tmpsymbol (point))
+ (if (/= (point) (cdr placeholder))
+ (c-add-syntax (car placeholder)))))
+ ;; CASE 16B: does this close an inline or a function in
+ ;; an extern block or namespace?
+ ((progn
+ (goto-char containing-sexp)
+ (setq placeholder (c-search-uplist-for-classkey state)))
+ (goto-char (aref placeholder 0))
+ (if (looking-at (concat c-extra-toplevel-key "[^_]"))
+ (c-add-syntax 'defun-close relpos)
+ (c-add-syntax 'inline-close relpos)))
+ ;; CASE 16C: if there an enclosing brace that hasn't
+ ;; been narrowed out by a class, then this is a
+ ;; block-close
+ ((and (not inenclosing-p)
+ (c-most-enclosing-brace state)
+ (or (not (c-major-mode-is 'pike-mode))
+ ;; In Pike it can be a defun-close of a
+ ;; function declared in a statement block. Let
+ ;; it through to be handled below.
+ (or (c-looking-at-bos)
+ (progn
+ (c-beginning-of-statement-1)
+ (looking-at c-conditional-key)))))
+ (c-add-syntax 'block-close relpos))
+ ;; CASE 16D: find out whether we're closing a top-level
+ ;; class or a defun
+ (t
+ (save-restriction
+ (narrow-to-region (point-min) indent-point)
+ (let ((decl (c-search-uplist-for-classkey (c-parse-state))))
+ (if decl
+ (c-add-class-syntax 'class-close decl)
+ (c-add-syntax 'defun-close relpos)))))
+ )))
+ ;; CASE 17: statement catchall
+ (t
+ ;; we know its a statement, but we need to find out if it is
+ ;; the first statement in a block
+ (goto-char containing-sexp)
+ (forward-char 1)
+ (c-forward-syntactic-ws indent-point)
+ ;; now skip forward past any case/default clauses we might find.
+ (while (or (c-skip-case-statement-forward fullstate indent-point)
+ (and (looking-at c-switch-label-key)
+ (not inswitch-p)))
+ (setq inswitch-p t))
+ ;; we want to ignore non-case labels when skipping forward
+ (while (and (looking-at c-label-key)
+ (goto-char (match-end 0)))
+ (c-forward-syntactic-ws indent-point))
+ (cond
+ ;; CASE 17A: we are inside a case/default clause inside a
+ ;; switch statement. find out if we are at the statement
+ ;; just after the case/default label.
+ ((and inswitch-p
+ (progn
+ (goto-char indent-point)
+ (c-beginning-of-statement-1 containing-sexp)
+ (setq placeholder (point))
+ (beginning-of-line)
+ (when (re-search-forward c-switch-label-key
+ (max placeholder (c-point 'eol)) t)
+ (setq placeholder (match-beginning 0)))))
+ (goto-char indent-point)
+ (skip-chars-forward " \t")
+ (if (eq (char-after) ?{)
+ (c-add-syntax 'statement-case-open placeholder)
+ (c-add-syntax 'statement-case-intro placeholder)))
+ ;; CASE 17B: continued statement
+ ((eq char-before-ip ?,)
+ (goto-char indent-point)
+ (c-beginning-of-closest-statement)
+ (c-add-syntax 'statement-cont (c-point 'boi)))
+ ;; CASE 17C: a question/colon construct? But make sure
+ ;; what came before was not a label, and what comes after
+ ;; is not a globally scoped function call!
+ ((or (and (memq char-before-ip '(?: ??))
+ (save-excursion
+ (goto-char indent-point)
+ (c-backward-syntactic-ws lim)
+ (back-to-indentation)
+ (not (looking-at c-label-key))))
+ (and (memq char-after-ip '(?: ??))
+ (save-excursion
+ (goto-char indent-point)
+ (skip-chars-forward " \t")
+ ;; watch out for scope operator
+ (not (looking-at "::")))))
+ (goto-char indent-point)
+ (c-beginning-of-closest-statement)
+ (c-add-syntax 'statement-cont (c-point 'boi)))
+ ;; CASE 17D: any old statement
+ ((< (point) indent-point)
+ (let ((safepos (c-most-enclosing-brace fullstate))
+ relpos done)
+ (goto-char indent-point)
+ (c-beginning-of-statement-1 safepos)
+ ;; It is possible we're on the brace that opens a nested
+ ;; function.
+ (if (and (eq (char-after) ?{)
+ (save-excursion
+ (c-backward-syntactic-ws safepos)
+ (not (eq (char-before) ?\;))))
+ (c-beginning-of-statement-1 safepos))
+ (if (and inswitch-p
+ (looking-at c-switch-label-key))
+ (progn
+ (goto-char (match-end 0))
+ (c-forward-syntactic-ws)))
+ (setq relpos (c-point 'boi))
+ (while (and (not done)
+ (<= safepos (point))
+ (/= relpos (point)))
+ (c-beginning-of-statement-1 safepos)
+ (if (= relpos (c-point 'boi))
+ (setq done t))
+ (setq relpos (c-point 'boi)))
+ (c-add-syntax 'statement relpos)
+ (if (eq char-after-ip ?{)
+ (c-add-syntax 'block-open))))
+ ;; CASE 17E: first statement in an in-expression block
+ ((setq placeholder
+ (save-excursion
+ (goto-char containing-sexp)
+ (c-looking-at-inexpr-block)))
+ (goto-char containing-sexp)
+ (back-to-indentation)
+ (let ((block-intro (if (eq (car placeholder) 'inlambda)
+ 'defun-block-intro
+ 'statement-block-intro)))
+ (if (= containing-sexp (point))
+ (c-add-syntax block-intro (point))
+ (goto-char (cdr placeholder))
+ (back-to-indentation)
+ (c-add-syntax block-intro (point))
+ (if (/= (point) (cdr placeholder))
+ (c-add-syntax (car placeholder)))))
+ (if (eq char-after-ip ?{)
+ (c-add-syntax 'block-open)))
+ ;; CASE 17F: first statement in an inline, or first
+ ;; statement in a top-level defun. we can tell this is it
+ ;; if there are no enclosing braces that haven't been
+ ;; narrowed out by a class (i.e. don't use bod here!)
+ ((save-excursion
+ (save-restriction
+ (widen)
+ (goto-char containing-sexp)
+ (c-narrow-out-enclosing-class state containing-sexp)
+ (not (c-most-enclosing-brace state))))
+ (goto-char containing-sexp)
+ ;; if not at boi, then defun-opening braces are hung on
+ ;; right side, so we need a different relpos
+ (if (/= (point) (c-point 'boi))
+ (progn
+ (c-backward-syntactic-ws)
+ (c-safe (c-forward-sexp (if (eq (char-before) ?\))
+ -1 -2)))
+ ;; looking at a Java throws clause following a
+ ;; method's parameter list
+ (c-beginning-of-statement-1)
+ ))
+ (c-add-syntax 'defun-block-intro (c-point 'boi)))
+ ;; CASE 17G: First statement in a function declared inside
+ ;; a normal block. This can only occur in Pike.
+ ((and (c-major-mode-is 'pike-mode)
+ (progn
+ (goto-char containing-sexp)
+ (and (not (c-looking-at-bos))
+ (progn
+ (c-beginning-of-statement-1)
+ (not (looking-at c-conditional-key))))))
+ (c-add-syntax 'defun-block-intro (c-point 'boi)))
+ ;; CASE 17H: first statement in a block
+ (t (goto-char containing-sexp)
+ (if (/= (point) (c-point 'boi))
+ (c-beginning-of-statement-1
+ (if (= (point) lim)
+ (c-safe-position (point) state) lim)))
+ (c-add-syntax 'statement-block-intro (c-point 'boi))
+ (if (eq char-after-ip ?{)
+ (c-add-syntax 'block-open)))
+ ))
+ )
+ ;; now we need to look at any modifiers
+ (goto-char indent-point)
+ (skip-chars-forward " \t")
+ (cond
+ ;; are we looking at a comment only line?
+ ((and (looking-at c-comment-start-regexp)
+ (/= (c-forward-token-1 0 nil (c-point 'eol)) 0))
+ (c-add-syntax 'comment-intro))
+ ;; we might want to give additional offset to friends (in C++).
+ ((and (c-major-mode-is 'c++-mode)
+ (looking-at c-C++-friend-key))
+ (c-add-syntax 'friend))
+ ;; Start of a preprocessor directive?
+ ((and (eq literal 'pound)
+ (= (save-excursion
+ (c-beginning-of-macro lim)
+ (setq placeholder (point)))
+ (c-point 'boi))
+ (not (and (c-major-mode-is 'pike-mode)
+ (eq (char-after (1+ placeholder)) ?\"))))
+ (c-add-syntax 'cpp-macro)))
+ ;; return the syntax
+ syntax))))
+
+
+(defun agulbra-switch-cpp-h ()
+ "Switch to the corresponding .cpp, .C, .cc or .h file."
+ (interactive)
+ (let ((n (buffer-file-name))
+ (c nil))
+ (cond ((and (string-match "\\.h$" n)
+ (progn
+ (setq c (replace-match ".cpp" t t n))
+ (file-readable-p c)))
+ (find-file c))
+ ((and (string-match "\\.h$" n)
+ (progn
+ (setq c (replace-match ".cc" t t n))
+ (file-readable-p c)))
+ (find-file c))
+ ((and (string-match "\\.h$" n)
+ (progn
+ (setq c (replace-match ".C" t t n))
+ (file-readable-p c)))
+ (find-file c))
+ ((string-match "\\.h$" n)
+ (find-file (replace-match ".cpp" t t n)))
+ ((string-match "\\.h$" n)
+ (find-file (replace-match ".cpp" t t n)))
+ ;((string-match "_[a-z]+[0-9]*.cpp$" n)
+ ; (find-file (replace-match ".h" t t n)))
+ ((string-match "\\.cpp$" n)
+ (find-file (replace-match ".h" t t n)))
+ ((string-match "\\.cc$" n)
+ (find-file (replace-match ".h" t t n)))
+ ((string-match "\\.c$" n)
+ (find-file (replace-match ".h" t t n)))
+ (t
+ (error "%s is neither .h, .cc, .C or .cpp" n)))))
+
+;; ----- Second part, contrinuted by Klaralvdalens Datakonsult
+(defvar kdab-qt-documentation
+ "http://doc.trolltech.com/3.0/XXX.html"
+ "URL for Qt documentation. XXX must be in the string.
+ Example: file:/packages/kde-src/qt-copy/doc/html/XXX.html")
+
+
+;; special case for include files
+;; Please notify blackie@klaralvdalens-datakonsult.se with any modification to this variable!
+(defvar kdab-special-includes
+ '(
+ (qlayout.h QHBoxLayout QVBoxLayout QGridLayout QBoxLayout)
+ (qlistview.h QListViewItem QCheckListItem QListViewItemIterator)
+ (qiconview.h QIconViewItem QIconDragItem QIconDrag)
+ (qdragobject.h QTextDrag QStoredDrag QUriDag QColorDrag QImageDrag QDragManager)
+ (qmime.h QMimeSource QMimeSourceFactory QWindowsMime)
+ (qptrlist.h QPtrListIterator)
+ (qevent.h QTimerEvent QMouseEvent QWheelEvent QTabletEvent QKeyEvent
+ QFocusEvent QPaintEvent QMoveEvent QResizeEvent QCloseEvent
+ QShowEvent QHideEvent QContextMenuEvent QIMEvent QDropEvent
+ QDragMoveEvent QDragEnterEvent QDragResponseEvent QDragLeaveEvent
+ QChildEvent QCustomEvent)
+ (qdatetime.h QTime QDateTime QDate)
+
+ ; Qt/Embedded
+ (qcopchannel_qws.h QCopChannel)
+ (qdirectpainter_qws.h QDirectPainter)
+ (qfontfactorybdf_qws.h QFontFactoryBDF)
+ (qfontfactoryttf_qws.h QFontFactoryFT)
+ (qfontmanager_qws.h QGlyphMetrics QGlyph QRenderedFont QDiskFont QFontManager QFontFactory)
+ (qgfx_qws.h QScreenCursor QPoolEntry QScreen QGfx)
+ (qgfxlinuxfb_qws.h QLinuxFbScreen)
+ (qgfxmatroxdefs_qws.h QQnxFbGfx QQnxScreen)
+ (qgfxraster_qws.h QGfxRasterBase QGfxRaster)
+ (qgfxvnc_qws.h QRfbRect QRfbPixelFormat QRfbServerInit QRfbSetEncodings
+ QRfbFrameBufferUpdateRequest QRfbKeyEvent QRfbPointerEvent QRfbClientCutText QVNCServer)
+ (qkeyboard_qws.h QWSKeyboardHandler)
+ (qlock_qws.h QLock QLockHolder)
+ (qmemorymanager_qws.h QMemoryManagerPixmap QMemoryManager)
+ (qsoundqss_qws.h QWSSoundServer QWSSoundClient QWSSoundServerClient QWSSoundServerSocket)
+ (qwindowsystem_qws.h QWSInternalWindowInfo QWSScreenSaver QWSWindow QWSSoundServer
+ QWSServer QWSServer KeyboardFilter QWSClient)
+ (qwsbeosdecoration_qws.h QWSBeOSDecoration)
+ (qwscursor_qws.h QWSCursor)
+ (qwsdecoration_qws.h QWSDecoration)
+ (qwsdefaultdecoration_qws.h QWSDefaultDecoration)
+ (qwsdisplay_qws.h QWSWindowInfo QWSDisplay)
+ (qwshydrodecoration_qws.h QWSHydroDecoration)
+ (qwskde2decoration_qws.h QWSKDE2Decoration)
+ (qwskdedecoration_qws.h QWSKDEDecoration)
+ (qwsmanager_qws.h QWSManager QWSButton)
+ (qwsmouse_qws.h QWSPointerCalibrationData QWSMouseHandler QCalibratedMouseHandler
+ QAutoMouseHandlerPrivate QWSMouseHandlerPrivate QVrTPanelHandlerPrivate
+ QTPanelHandlerPrivate QYopyTPanelHandlerPrivate QCustomTPanelHandlerPrivate
+ QVFbMouseHandlerPrivate)
+ (qwsproperty_qws.h QWSPropertyManager)
+ (qwsregionmanager_qws.h QWSRegionManager)
+ (qwssocket_qws.h QWSSocket QWSServerSocket)
+ (qwswindowsdecoration_qws.h QWSWindowsDecoration)
+
+ ; KDE
+ (kdebug.h kdDebug kdWarning kdError kdFatal kdBacktrace)
+
+ ) "List of special include files which do not follow the normal scheme")
+
+;; Lookup class `cls' in kdab-special-includes and return the associate include file name
+(defun kdab-map-special (cls)
+ (let ((list kdab-special-includes)
+ (found nil))
+ (while (and list (not found))
+ (let* ( (elm (car list))
+ (include-file (car elm))
+ (classes (cdr elm)))
+ ( while (and classes (not found))
+ (if (string= (downcase cls) (downcase (symbol-name (car classes))))
+ (setq found include-file)
+ (setq classes (cdr classes)))))
+ (setq list (cdr list)))
+ (if found
+ (symbol-name found)
+ nil) ; return value
+ ))
+
+
+(defun kdab-word-under-point ()
+ (save-excursion
+ (let* ((start (if (= (preceding-char) ?\ )
+ (point)
+ (progn (backward-word 1) (point))))
+ (end (progn (forward-word 1) (point))))
+ (buffer-substring start end))))
+
+
+;--------------------------------------------------------------------------------
+; Insert include file.
+; Place point anywhere on a class, and invoke this function. A result of
+; this is that an include line is added (if it does not already exists) for
+; the given class.
+;--------------------------------------------------------------------------------
+(defun kdab-insert-header ()
+ (interactive "")
+ (save-excursion
+ (let* ((word (downcase (kdab-word-under-point)))
+ (header (cond
+ ((kdab-map-special word) (kdab-map-special word))
+ ((string-match "^qdom" word) "qdom.h")
+ ((string-match "^qxml" word) "qxml.h")
+ (t (concat word ".h")))))
+ (beginning-of-buffer)
+ (if (not (re-search-forward (concat "#include *<" header ">") nil t))
+ (progn
+ ; No include existsed
+ (goto-char (point-max)) ; Using end-of-buffer makes point move, dispete save-excursion
+ (if (not (re-search-backward "^#include *[\"<][^\">]+\.h *[\">]" nil t))
+ (beginning-of-buffer)
+ (progn (end-of-line) (forward-char 1)))
+ (if (file-exists-p header)
+ (progn
+ ; See this as a local file.
+ (insert "#include \"" header "\"\n")
+ (message (concat "inserted " "#include \"" header "\"")))
+ (progn
+ (insert "#include <" header ">\n")
+ (message (concat "inserted " "#include <" header ">")))))
+ (message (concat "header file \"" header "\" is already included"))))))
+
+
+
+
+;--------------------------------------------------------------------------------
+; Start konqueror with documentation for the class under point.
+; set `kdab-qt-documentation' to specify the replacement for the documentation
+;--------------------------------------------------------------------------------
+(defun kdab-lookup-qt-documentation ()
+ (interactive "")
+ (save-excursion
+ (let* ((word (downcase (kdab-word-under-point)))
+ (url (if (not (string-match "XXX" kdab-qt-documentation))
+ (error "didn't find three X's in kdab-qt-documentation")
+ (replace-match word t t kdab-qt-documentation))))
+ (start-process "qt documentation" nil "kfmclient" "openURL" url)
+ (message (concat "Loading " url)))))
+
+
+;; ----- Third part, contributed by various KDE developers
+
+;;; func-menu is a package that scans your source file for function definitions
+;;; and makes a menubar entry that lets you jump to any particular function
+;;; definition by selecting it from the menu. The following code turns this on
+;;; for all of the recognized languages. Scanning the buffer takes some time,
+;;; but not much.
+
+(if xemacs
+ (progn
+ (require 'func-menu)
+ (add-hook 'find-file-hooks 'fume-add-menubar-entry) )
+ (progn
+ (require 'imenu)))
+ ;(add-hook 'find-file-hooks 'imenu)) )
+
+;; Switch between the declaration of a class member in .cc/.cpp/.C, and its definition in the .h file
+;; Written by David and Reggie after much hair tearing
+(defun switch-to-function-def ()
+ (interactive)
+ (let ((n (buffer-file-name))
+ (class "")
+ (fn ""))
+ (if (or (string-match "\\.cc$" n)
+ (string-match "\\.cpp$" n)
+ (string-match "\\.C$" n))
+ (let ((a (fume-function-before-point)))
+ (and (string-match "^\\(.*\\)::\\(.*\\)$" a)
+ (progn
+ (setq class (match-string 1 a))
+ (setq fn (match-string 2 a))
+ (agulbra-switch-cpp-h)
+ (goto-char 0)
+ (re-search-forward class nil t)
+ (re-search-forward (concat "[ \t]+" fn "[ \t]*(") nil t)))))
+ (if (string-match "\\.h$" n)
+ (progn
+ (save-excursion
+ (forward-line 0)
+ (re-search-forward "[ \t]+\\([^ \t(]+\\)[ \t]*(" nil t)
+ (setq fn (match-string 1))
+ (re-search-backward "^class \\([a-zA-Z0-9_]+\\)[ \t]*\\([a-zA-Z0-9_]*\\)" nil t)
+ (setq class (match-string 1))
+ (setq save (match-string 2))
+ (and (string-match "Q_EXPORT" class)
+ (setq class save))
+ (message (concat class "::" fn))
+ )
+ (agulbra-switch-cpp-h)
+ (goto-char 0)
+ (re-search-forward (concat "^[^()]*" class "::" fn "[ \t]*(") nil t)
+ (message c-syntactic-context)
+ )
+)))
+
+; Adds the current file to Makefile.am.
+; Written by David.
+(defun add-file-to-makefile-am ()
+ "add the current file to the _SOURCES tag in the Makefile.am"
+ (interactive)
+ (let ((file (buffer-name))
+ (makefile "Makefile.am"))
+ (if (file-readable-p makefile )
+ (message "")
+ (error "Makefile.am not found!")
+ )
+ (find-file makefile)
+ (goto-char (point-min))
+ (if (re-search-forward "_SOURCES" nil t)
+ (progn
+ (end-of-line)
+ ; check if line ends with '\' [had to read make-mode.el to find this one!]
+ (while (= (char-before) ?\\)
+ (end-of-line 2)) ; moves to end of next line
+ (insert " ")
+ (insert file)
+ )
+ (error "_SOURCES not found")
+ )
+ )
+ )
+
+; Inserts a kdDebug statement showing the name of the current method.
+; You need to create the empty line first.
+(defun insert-kdDebug ()
+ (interactive)
+ (insert "kdDebug() << \"")
+ (insert (fume-function-before-point))
+ (insert "\" << endl;")
+ )
+
+; Creates the ifndef/define/endif statements necessary for a header file
+(defun header-protection ()
+ (interactive)
+ (let ((f (buffer-file-name)))
+ (if (string-match "^.*/" f)
+ (setq f (replace-match "" t t f)))
+ (while (string-match "\\." f)
+ (setq f (replace-match "_" t t f)))
+ (save-excursion
+ (goto-char (point-min))
+ (insert "#ifndef " (upcase f) "\n#define " (upcase f) "\n\n")
+ (goto-char (point-max))
+ (insert "\n#endif\n")
+ )
+ )
+ )
+
+
+; Makes '(' insert '(' or ' ( ' where appropiate
+(defun insert-parens (arg) (interactive "*P")
+ (if (not (c-in-literal))
+ (let ((n nil))
+ (save-excursion
+ (setq n (or (progn (forward-char -2) (looking-at "if"))
+ (progn (forward-char -1) (looking-at "for"))
+ (progn (forward-char -1) (looking-at "case"))
+ (progn (forward-char -1) (looking-at "while"))
+ )
+ )
+ )
+ (cond
+ (n (progn
+ (insert " ")
+ (self-insert-command (prefix-numeric-value arg))
+ ;(insert " ")
+ ))
+ (t ;else
+ (self-insert-command (prefix-numeric-value arg))
+ ;(insert " ")
+ )))
+ (self-insert-command (prefix-numeric-value arg)))
+ )
+
+(defun insert-parens2 (arg) (interactive "*P")
+ (if (not (c-in-literal))
+ (let ((remv nil) (nospac nil))
+ (forward-char -2)
+ (setq remv (looking-at "( ")) ; () -> we'll have to remove that space
+ (forward-char 1)
+ (setq nospac (or (looking-at " ") (looking-at "(")) ) ; no space to be added
+ (forward-char 1)
+ (cond
+ (remv (progn
+ (delete-backward-char 1)
+ (self-insert-command (prefix-numeric-value arg)))) ; the () case
+ (nospac (self-insert-command (prefix-numeric-value arg))) ; no space to be added
+ (t ;else
+ (if abbrev-mode ; XEmacs
+ (expand-abbrev))
+ ;(insert " ")
+ (self-insert-command (prefix-numeric-value arg))
+ ))) ; normal case, prepend a space
+ ;;(blink-matching-open) ; show the matching parens
+ (self-insert-command (prefix-numeric-value arg)))
+ )
+
+; Makes ',' insert ', '
+(defun insert-comma (arg)
+ (interactive "*P")
+ (let* ((ch (char-after))
+ (spacep (not (or (eq ch ? )
+ (c-in-literal)
+ arg))))
+ (self-insert-command (prefix-numeric-value arg))
+ (if spacep
+ (insert " "))))
+
+(defun insert-curly-brace (arg) (interactive "*P")
+ (if (not (c-in-literal))
+ (let ((n nil) (o nil))
+ (save-excursion
+ (forward-char -2)
+ (setq o (looking-at "()"))
+ (forward-char 1)
+ (setq n (looking-at ")"))
+ )
+ (cond
+ (n (progn
+ (insert " ")
+ (self-insert-command (prefix-numeric-value arg))
+ (newline-and-indent)
+ (save-excursion
+ (insert "\n}")
+ (c-indent-line)
+ )))
+ (o (progn
+ (newline)
+ (self-insert-command (prefix-numeric-value arg))
+ (newline-and-indent)))
+ (t (progn ;else
+ (self-insert-command (prefix-numeric-value arg))
+ (save-excursion
+ (beginning-of-line)
+ (c-indent-command))))
+ ))
+ (self-insert-command (prefix-numeric-value arg))
+ )
+)
+
+;; have PelDel mode work
+(put 'insert-parens 'pending-delete t)
+(put 'insert-parens2 'pending-delete t)
+(put 'insert-comma 'pending-delete t)
+(put 'insert-curly-brace 'pending-delete t)
+(put 'newline-and-indent 'pending-delete t)
+
+; A wheel mouse that doesn't beep, unlike mwheel-install
+(defun scroll-me-up () (interactive) (scroll-up 4))
+(defun scroll-me-down () (interactive) (scroll-down 4))
+(defun scroll-me-up-a-bit () (interactive) (scroll-up 1))
+(defun scroll-me-down-a-bit () (interactive) (scroll-down 1))
+(define-key global-map [(button4)] 'scroll-me-down)
+(define-key global-map [(button5)] 'scroll-me-up)
+(define-key global-map [(shift button4)] 'scroll-me-down-a-bit)
+(define-key global-map [(shift button5)] 'scroll-me-up-a-bit)
+
+; Compilation
+(defun makeclean () (interactive) (compile "make clean"))
+(defun make () (interactive) (compile "make"))
+(defun makeinstall () (interactive) (compile "make install"))
+(defun makeinstallexec () (interactive) (compile "make install-exec"))
+(defun makethisfile () (interactive)
+ (let ((f (buffer-name)))
+ (if (string-match "\.cpp$" f) (setq f (replace-match "\.lo" t t f)))
+ (if (string-match "\.cc$" f) (setq f (replace-match "\.lo" t t f)))
+ (compile (concat "make " f ))))
+
+;; Indentation: 4 characters, no tabs.
+(setq c-basic-offset 4)
+(setq insert-tab-mode nil)
+(setq-default require-final-newline t)
+(setq-default next-line-add-newlines nil)
+
+;; pc-like textmarking
+(load "pc-select")
+(if xemacs
+ (pc-select-mode)
+ (pc-selection-mode))
+
+; Move in other window
+(defun scroll-other-up () (interactive) (scroll-other-window-down 1)) ; hehe :)
+(define-key global-map [(meta up)] 'scroll-other-up)
+(defun scroll-other-down () (interactive) (scroll-other-window 1))
+(define-key global-map [(meta down)] 'scroll-other-down)
+
+;; Some example bindings, feel free to customize :)
+(define-key global-map [(f2)] 'grep)
+;; FIXME: remember to get these two working on Gnu/Emacs (Zack)
+(define-key global-map [(f3)] 'fume-list-functions)
+(define-key global-map [(shift f3)] 'fume-prompt-function-goto)
+(define-key global-map [(shift button3)] 'mouse-function-menu)
+(define-key global-map [(shift f4)] 'makeclean)
+(define-key global-map [(f4)] 'make)
+(define-key global-map [(f5)] 'makeinstall)
+(define-key global-map [(shift f5)] 'makeinstallexec)
+(define-key global-map [(shift f6)] 'makethisfile)
+(define-key global-map [(f6)] 'agulbra-switch-cpp-h)
+(define-key global-map [(f7)] 'switch-to-function-def)
+;; imenu does that interactively
+(if xemacs
+ (define-key global-map [(f8)] 'function-menu))
+;(define-key global-map [(f9)] 'agulbra-make-member) ;; uncomment this for a killer feature
+(define-key global-map [(f10)] 'kdab-insert-header)
+(define-key global-map [(shift f10)] 'kdab-lookup-qt-documentation)
+(define-key global-map [(control meta d)] 'insert-kdDebug)
+
+; Standard Qt/KDE shortcuts: Ctrl+Backspace, Ctrl+Delete
+(define-key global-map [(control backspace)] 'backward-kill-word)
+(define-key global-map [(control delete)] 'kill-word)
+
+; Standard Qt/KDE shortcuts: Control Pageup and Pagedown
+(define-key global-map [(control prior)] 'beginning-of-buffer)
+(define-key global-map [(control next)] 'end-of-buffer)
+
+; currently no binding for header-protection and add-file-to-makefile-am,
+; you need to call them from M-x
+
+; -----------------------------------------------------------------
+; The above list defines the following bindings:
+;
+; F2 : offer a grep command
+;
+; F3/Shift-F3/F8/Shift-RMB : different ways to see the list of methods in the current buffer
+;
+; F4 : make
+; Shift-F4 : make clean
+; F5 : make install
+; Shift-F5 : make install-exec
+;
+; Shift-F6 : compile this file [assumes libtool is being used]
+; F6 : Switch from .cpp/.cc to .h and vice-versa
+; F7 : The same, but try to find the current method in the other file
+; F9 (if enabled) : Create a member method in the .cpp, the cursor being on the definition in the .h
+; F10: Place point on a class name, and the respective (Qt) include file will be inserted.
+; This works with all Qt classes but can easily be extended to KDE classes.
+; Shift-F10: Place point on a class name, and press Shift-F10, and konqueror will load
+; Qt documentation. Customize the location of the Qt documentation with the
+; variable kdab-qt-documentation. XXX will be replace with the class name.
+; Example (setq kdab-qt-location "file:/packages/kde-src/qt-copy/doc/html/XXX.html")
+;
+; Ctrl+Meta+D : insert a kdDebug statement with the name of the current method
+; [the new hide-all-windows shortcut conflicts with that, you may have to
+; change it, or use Ctrl+Meta+Shift+D (!!)]
+;
+; Meta Up/Down : scroll the other window (when window is split)
+
+; Other very useful keybindings to know about:
+; C-x r m to set a named bookmark in the buffer
+; C-x r b to jump to a named bookmark in the buffer
+
+(setq-default initial-scratch-message
+ "File kde-devel-emacs.el is deprecated!
+Please use KDE-Emacs from kdesdk/scripts/kde-emacs.")
diff --git a/scripts/kde-devel-gdb b/scripts/kde-devel-gdb
new file mode 100644
index 00000000..bf69d233
--- /dev/null
+++ b/scripts/kde-devel-gdb
@@ -0,0 +1,299 @@
+# This file defines handy gdb macros for printing out Qt types
+# To use it, add this line to your ~/.gdbinit :
+# source /path/to/kde/sources/kdesdk/scripts/kde-devel-gdb
+
+# Please don't use tabs in this file. When pasting a
+# macro definition to gdb, tabs are interpreted as completion.
+
+# Disable printing of static members. Qt has too many, it clutters the output
+set print static-members off
+
+define printqstring
+ printqstringdata $arg0.d
+end
+document printqstring
+ Prints the contents of a QString
+end
+define printq4string
+ printq4stringdata $arg0.d
+end
+document printq4string
+ Prints the contents of a Qt QString
+end
+
+define printqstringdata
+ set $i=0
+ set $d = (QStringData *)$arg0
+ while $i < $d->len
+ printf "%c", (char)($d->unicode[$i++].ucs & 0xff)
+ end
+ printf "\n"
+end
+document printqstringdata
+ Prints the contents of a QStringData
+ This is useful when the output of another command (e.g. printqmap)
+ shows {d = 0xdeadbeef} for a QString, i.e. the qstringdata address
+ instead of the QString object itself.
+ printqstring $s and printqstringdata $s.d are equivalent.
+end
+
+define printq4stringdata
+ set $i=0
+ set $d = $arg0
+ while $i < $d->size
+ printf "%c", (char)($d->data[$i++] & 0xff)
+ end
+ printf "\n"
+end
+document printq4stringdata
+ Prints the contents of a Qt4 QString::Data
+ This is useful when the output of another command (e.g. printqmap)
+ shows {d = 0xdeadbeef} for a QString, i.e. the qstringdata address
+ instead of the QString object itself.
+ printq4string $s and printq4stringdata $s.d are equivalent.
+end
+
+define printqstring_utf8
+ set $i=0
+ set $s = $arg0
+ while $i < $s.d->len
+ set $uc = (unsigned short) $s.d->unicode[$i++].ucs
+ if ( $uc < 0x80 )
+ printf "%c", (unsigned char)($uc & 0x7f)
+ else
+ if ( $uc < 0x0800 )
+ printf "%c", (unsigned char)(0xc0 | ($uc >> 6))
+ else
+ printf "%c", (unsigned char)(0xe0 | ($uc >> 12)
+ printf "%c", (unsigned char)(0x80 | (($uc > 6) &0x3f)
+ end
+ printf "%c", (unsigned char)(0x80 | ((uchar) $uc & 0x3f))
+ end
+ end
+ printf "\n"
+end
+document printqstring_utf8
+ Prints the contents of a QString encoded in utf8.
+ Nice if you run your debug session in a utf8 enabled terminal.
+end
+
+define printqcstring
+ print $arg0.shd.data
+ print $arg0.shd.len
+end
+document printqcstring
+ Prints the contents of a QCString (char * data, then length)
+end
+
+define printq4bytearray
+ print $arg0->d->data
+end
+document printq4bytearray
+ Prints the contents of a Qt4 QByteArray (when it contains a string)
+end
+
+define printqfont
+ print *($arg0).d
+ printqstring ($arg0).d->request.family
+ print ($arg0).d->request.pointSize
+end
+document printqfont
+ Prints the main attributes from a QFont, in particular the requested
+ family and point size
+end
+
+define printqcolor
+ printf "(%d,%d,%d)\n", ($arg0).red(), ($arg0).green(), ($arg0).blue()
+end
+document printqcolor
+ Prints a QColor as (R,G,B).
+ Usage: 'printqcolor <QColor col>
+end
+
+define printqmemarray
+ # Maybe we could find it out the type by parsing "whatis $arg0"?
+ set $arr = $arg0
+ set $sz = sizeof($arg1)
+ set $len = $arr->shd->len / $sz
+ output $len
+ printf " items in the array\n"
+ set $i = 0
+ while $i < $len
+ # print "%s[%d] = %s\n", $arr, $i, *($arg1 *)(($arr->vec)[$i])
+ print *($arg1 *)(($arr->shd->data) + ($i * $sz))
+ set $i++
+ end
+end
+document printqmemarray
+ Prints the contents of a QMemArray. Pass the type as second argument.
+end
+
+define printqptrvector
+ # Maybe we could find it out the type by parsing "whatis $arg0"?
+ set $arr = $arg0
+ set $len = $arr->len
+ output $len
+ printf " items in the vector\n"
+ set $i = 0
+ while $i < $len
+ # print "%s[%d] = %s\n", $arr, $i, *($arg1 *)(($arr->vec)[$i])
+ print *($arg1 *)(($arr->vec)[$i])
+ set $i++
+ end
+end
+document printqptrvector
+ Prints the contents of a QPtrVector. Pass the type as second argument.
+end
+
+define printqptrvectoritem
+ set $arr = $arg0
+ set $i = $arg2
+ print ($arg1 *)(($arr->vec)[$i])
+ print *($arg1 *)(($arr->vec)[$i])
+end
+document printqptrvectoritem
+ Print one item of a QPtrVector
+ Usage: printqptrvectoritem vector type index
+end
+
+define printqmap
+ set $map = $arg0
+ set $len = $map.sh->node_count
+ output $len
+ printf " items in the map\n"
+ set $header = $map.sh->header
+ # How to parse the key and value types from whatis?
+ set $it = (QMapNode<$arg1,$arg2> *)($header->left)
+ while $it != $header
+ printf " key="
+ output $it->key
+ printf " value="
+ output $it->data
+ printf "\n"
+ _qmapiterator_inc $it
+ set $it = (QMapNode<$arg1,$arg2> *)($ret)
+ end
+end
+document printqmap
+ Prints the full contents of a QMap
+ Usage: 'printqmap map keytype valuetype'
+end
+
+
+define _qmapiterator_inc
+ set $ret = $arg0
+ if $ret->right != 0
+ set $ret = $ret->right
+ while $ret->left != 0
+ set $ret = $ret->left
+ end
+ else
+ set $y = $ret->parent
+ while $ret == $y->right
+ set $ret = $y
+ set $y = $y->parent
+ end
+ if $ret->right != $y
+ set $ret = $y
+ end
+ end
+end
+document _qmapiterator_inc
+ Increment a qmap iterator (internal method, used by printqmap)
+end
+
+define printqptrlist
+ set $list = $arg0
+ set $len = $list.numNodes
+ output $len
+ printf " items in the list\n"
+ set $it = $list.firstNode
+ while $it != 0
+ output $it->data
+ printf "\n"
+ set $it = $it->next
+ end
+end
+document printqptrlist
+ Prints the contents of a QPtrList.
+ Usage: printqptrlist mylist
+end
+
+define printqvaluelist
+ set $list = $arg0
+ set $len = $list.sh->nodes
+ output $len
+ printf " items in the list\n"
+ set $it = $list.sh->node->next
+ set $end = $list.sh->node
+ while $it != $end
+ output $it->data
+ printf "\n"
+ set $it = $it->next
+ end
+end
+document printqvaluelist
+ Prints the contents of a QValueList.
+ Usage: printqvaluelist mylist
+end
+
+define printqstringlist
+ set $list = $arg0
+ set $len = $list.sh->nodes
+ output $len
+ printf " items in the list\n"
+ set $it = $list.sh->node->next
+ set $end = $list.sh->node
+ while $it != $end
+ printqstring $it->data
+ set $it = $it->next
+ end
+end
+document printqstringlist
+ Prints the contents of a QStringList.
+ Usage: printqstringlist mylist
+end
+
+# Bad implementation, requires a running process.
+# Needs to be refined, i.e. figuring out the right void* pointers casts.
+# Simon says: each Node contains the d pointer of the QString.
+define printq4stringlist
+ # This is ugly, but we need to avoid conflicts with printq4string's own vars...
+ set $q4sl_i = 0
+ set $q4sl_d = & $arg0
+ set $q4sl_sz = $q4sl_d->size()
+ while $q4sl_i < $q4sl_sz
+ output $q4sl_i
+ printf " "
+ printq4string $q4sl_d->at($q4sl_i++)
+ end
+end
+document printq4stringlist
+ Prints the contents of a Qt4 QStringList.
+ Usage: printq4stringlist mylist
+end
+
+define printqdatetime
+ printqdate ($arg0).d
+ printqtime ($arg0).t
+end
+document printqdatetime
+ Prints a QDateTime
+ Usage: printqdatetime myqdt
+end
+define printqdate
+ printf "(Y:%d M:%d D:%d)\n", ($arg0).year(), ($arg0).month(), ($arg0).day()
+end
+document printqdate
+ Prints a QDate
+ Usage: printqdate mydate
+end
+define printqtime
+ printf "(H:%d M:%d S:%d)\n", ($arg0).hour(), ($arg0).minute(), ($arg0).second()
+end
+document printqtime
+ Prints a QTime
+ Usage: printqtime mytime
+end
+
+
diff --git a/scripts/kde-devel-vim.vim b/scripts/kde-devel-vim.vim
new file mode 100644
index 00000000..bcb02b4c
--- /dev/null
+++ b/scripts/kde-devel-vim.vim
@@ -0,0 +1,428 @@
+" To use this file, add this line to your ~/.vimrc:, w/o the dquote
+" source /path/to/kde/sources/kdesdk/scripts/kde-devel-vim.vim
+"
+" For CreateChangeLogEntry() : If you don't want to re-enter your
+" Name/Email in each vim session then make sure to have the viminfo
+" option enabled in your ~/.vimrc, with the '!' flag, enabling persistent
+" storage of global variables. Something along the line of
+" set viminfo=%,!,'50,\"100,:100,n~/.viminfo
+" should do the trick.
+
+" Don't include these in filename completions
+set suffixes+=.lo,.o,.moc,.la,.closure,.loT
+
+" Search for headers here
+set path=.,/usr/include,/usr/local/include,
+if $QTDIR != ''
+ let &path = &path . $QTDIR . '/include/,'
+endif
+if $KDEDIR != ''
+ let &path = &path . $KDEDIR . '/include/,'
+ let &path = &path . $KDEDIR . '/include/arts/,'
+endif
+if $KDEDIRS != ''
+ let &path = &path . substitute( $KDEDIRS, '\(:\|$\)', '/include,', 'g' )
+ let &path = &path . substitute( $KDEDIRS, '\(:\|$\)', '/include/arts,', 'g' )
+endif
+set path+=,
+
+" Use makeobj to build
+set mp=makeobj
+
+" If TagList is Loaded then get a funny statusline
+" Only works if kde-devel-vim.vim is loaded after taglist.
+" Droping this script in ~/.vim/plugin works fine
+if exists('loaded_taglist')
+ let Tlist_Process_File_Always=1
+ set statusline=%<%f:[\ %{Tlist_Get_Tag_Prototype_By_Line()}\ ]\ %h%m%r%=%-14.(%l,%c%V%)\ %P
+endif
+
+" Insert tab character in whitespace-only lines, complete otherwise
+inoremap <Tab> <C-R>=SmartTab()<CR>
+
+if !exists("DisableSmartParens")
+" Insert a space after ( or [ and before ] or ) unless preceded by a matching
+" paren/bracket or space or inside a string or comment. Comments are only
+" recognized as such if they start on the current line :-(
+inoremap ( <C-R>=SmartParens( '(' )<CR>
+inoremap [ <C-R>=SmartParens( '[' )<CR>
+inoremap ] <C-R>=SmartParens( ']', '[' )<CR>
+inoremap ) <C-R>=SmartParens( ')', '(' )<CR>
+endif
+
+" Insert an #include statement for the current/last symbol
+inoremap <F5> <C-O>:call AddHeader()<CR>
+
+" Insert a forward declaration for the current/last symbol
+" FIXME: not implemented yet
+" inoremap <S-F5> <C-O>:call AddForward()<CR>
+
+" Switch between header and implementation files on ,h
+nmap <silent> ,h :call SwitchHeaderImpl()<CR>
+
+" Comment selected lines on ,c in visual mode
+vmap ,c :s,^,//X ,<CR>:noh<CR>
+" Uncomment selected lines on ,u in visual mode
+vmap ,u :s,^//X ,,<CR>
+
+" Insert an include guard based on the file name on ,i
+nmap ,i :call IncludeGuard()<CR>o
+
+" Insert simple debug statements into each method
+nmap ,d :call InsertMethodTracer()<CR>
+
+" Expand #i to #include <.h> or #include ".h". The latter is chosen
+" if the character typed after #i is a dquote
+" If the character is > #include <> is inserted (standard C++ headers w/o .h)
+iab #i <C-R>=SmartInclude()<CR>
+
+" Insert a stripped down CVS diff
+iab DIFF <Esc>:call RunDiff()<CR>
+
+" mark 'misplaced' tab characters
+set listchars=tab:·\ ,trail:·
+set list
+
+set incsearch
+
+function! SmartTab()
+ let col = col('.') - 1
+ if !col || getline('.')[col-1] !~ '\k'
+ return "\<Tab>"
+ else
+ return "\<C-P>"
+ endif
+endfunction
+
+function! SmartParens( char, ... )
+ if ! ( &syntax =~ '^\(c\|cpp\|java\)$' )
+ return a:char
+ endif
+ let s = strpart( getline( '.' ), 0, col( '.' ) - 1 )
+ if s =~ '//'
+ return a:char
+ endif
+ let s = substitute( s, '/\*\([^*]\|\*\@!/\)*\*/', '', 'g' )
+ let s = substitute( s, "'[^']*'", '', 'g' )
+ let s = substitute( s, '"\(\\"\|[^"]\)*"', '', 'g' )
+ if s =~ "\\([\"']\\|/\\*\\)"
+ return a:char
+ endif
+ if a:0 > 0
+ if strpart( getline( '.' ), col( '.' ) - 3, 2 ) == a:1 . ' '
+ return "\<BS>" . a:char
+ endif
+ if strpart( getline( '.' ), col( '.' ) - 2, 1 ) == ' '
+ return a:char
+ endif
+ return ' ' . a:char
+ endif
+ if a:char == '('
+ if strpart( getline( '.' ), col( '.' ) - 3, 2 ) == 'if' ||
+ \strpart( getline( '.' ), col( '.' ) - 4, 3 ) == 'for' ||
+ \strpart( getline( '.' ), col( '.' ) - 6, 5 ) == 'while' ||
+ \strpart( getline( '.' ), col( '.' ) - 7, 6 ) == 'switch'
+ return ' ( '
+ endif
+ endif
+ return a:char . ' '
+endfunction
+
+function! SwitchHeaderImpl()
+ let headers = '\.\([hH]\|hpp\|hxx\)$'
+ let impl = '\.\([cC]\|cpp\|cc\|cxx\)$'
+ let fn = expand( '%' )
+ if fn =~ headers
+ let list = glob( substitute( fn, headers, '.*', '' ) )
+ elseif fn =~ impl
+ let list = glob( substitute( fn, impl, '.*', '' ) )
+ endif
+ while strlen( list ) > 0
+ let file = substitute( list, "\n.*", '', '' )
+ let list = substitute( list, "[^\n]*", '', '' )
+ let list = substitute( list, "^\n", '', '' )
+ if ( fn =~ headers && file =~ impl ) || ( fn =~ impl && file =~ headers )
+ execute( "edit " . file )
+ return
+ endif
+ endwhile
+ echohl ErrorMsg
+ echo "File switch failed!"
+ echohl None
+endfunction
+
+function! IncludeGuard()
+ let guard = toupper( substitute( expand( '%' ), '\([^.]*\)\.h', '\1_h', '' ) )
+ call append( '^', '#define ' . guard )
+ +
+ call append( '^', '#ifndef ' . guard )
+ call append( '$', '#endif // ' . guard )
+ +
+endfunction
+
+function! SmartInclude()
+ let next = nr2char( getchar( 0 ) )
+ if next == '"'
+ return "#include \".h\"\<Left>\<Left>\<Left>"
+ endif
+ if next == '>'
+ return "#include <>\<Left>"
+ endif
+ return "#include <.h>\<Left>\<Left>\<Left>"
+endfunction
+
+function! MapIdentHeader( ident )
+ " Qt stuff
+ if a:ident =~ 'Q.*Layout'
+ return '<qlayout.h>'
+ elseif a:ident == 'QListViewItem' ||
+ \a:ident == 'QCheckListItem' ||
+ \a:ident == 'QListViewItemIterator'
+ return '<qlistview.h>'
+ elseif a:ident == 'QIconViewItem' ||
+ \a:ident == 'QIconDragItem' ||
+ \a:ident == 'QIconDrag'
+ return '<qiconview.h>'
+ elseif a:ident =~ 'Q.*Drag' ||
+ \a:ident == 'QDragManager'
+ return '<qdragobject.h>'
+ elseif a:ident == 'QMimeSource' ||
+ \a:ident == 'QMimeSourceFactory' ||
+ \a:ident == 'QWindowsMime'
+ return '<qmime.h>'
+ elseif a:ident == 'QPtrListIterator'
+ return '<qptrlist.h>'
+ elseif a:ident =~ 'Q.*Event'
+ return '<qevent.h>'
+ elseif a:ident == 'QTime' ||
+ \a:ident == 'QDate'
+ return '<qdatetime.h>'
+ elseif a:ident == 'QTimeEdit' ||
+ \a:ident == 'QDateTimeEditBase' ||
+ \a:ident == 'QDateEdit'
+ return '<qdatetimeedit.h>'
+ elseif a:ident == 'QByteArray'
+ return '<qcstring.h>'
+ elseif a:ident == 'QWidgetListIt'
+ return '<qwidgetlist.h>'
+ elseif a:ident == 'QTab'
+ return '<qtabbar.h>'
+ elseif a:ident == 'QColorGroup'
+ return '<qpalette.h>'
+ elseif a:ident == 'QActionGroup'
+ return '<qaction.h>'
+ elseif a:ident =~ 'Q.*Validator'
+ return '<qvalidator.h>'
+ elseif a:ident =~ 'QListBox.*'
+ return '<qlistbox.h>'
+ elseif a:ident == 'QChar' ||
+ \a:ident == 'QCharRef' ||
+ \a:ident == 'QConstString'
+ return '<qstring.h>'
+ elseif a:ident =~ 'QCanvas.*'
+ return '<qcanvas.h>'
+ elseif a:ident =~ 'QGL.*'
+ return '<qgl.h>'
+ elseif a:ident == 'QTableSelection' ||
+ \a:ident == 'QTableItem' ||
+ \a:ident == 'QComboTableItem' ||
+ \a:ident == 'QCheckTableItem'
+ return '<qtable.h>'
+ elseif a:ident == 'qApp'
+ return '<qapplication.h>'
+
+ " KDE stuff
+ elseif a:ident == 'K\(Double\|Int\)\(NumInput\|SpinBox\)'
+ return '<knuminput.h>'
+ elseif a:ident == 'KConfigGroup'
+ return '<kconfigbase.h>'
+ elseif a:ident == 'KListViewItem'
+ return '<klistview.h>'
+ elseif a:ident =~ 'kd\(Debug\|Warning\|Error\|Fatal\|Backtrace\)'
+ return '<kdebug.h>'
+ elseif a:ident == 'kapp'
+ return '<kapplication.h>'
+ elseif a:ident == 'i18n' ||
+ \a:ident == 'I18N_NOOP'
+ return '<klocale.h>'
+ elseif a:ident == 'locate' ||
+ \a:ident == 'locateLocal'
+ return '<kstandarddirs.h>'
+
+ " aRts stuff
+ elseif a:ident =~ '\arts_\(debug\|info\|warning\|fatal\)'
+ return '<debug.h>'
+
+ " Standard Library stuff
+ elseif a:ident =~ '\(std::\)\?\(cout\|cerr\|endl\)'
+ return '<iostream>'
+ elseif a:ident =~ '\(std::\)\?is\(alnum\|alpha\|ascii\|blank\|graph\|lower\|print\|punct\|space\|upper\|xdigit\)'
+ return '<cctype>'
+ endif
+
+ let header = tolower( substitute( a:ident, '::', '/', 'g' ) ) . '.h'
+ let check = header
+ while 1
+ if filereadable( check )
+ return '"' . check . '"'
+ endif
+ let slash = match( check, '/' )
+ if slash == -1
+ return '<' . header . '>'
+ endif
+ let check = strpart( check, slash + 1 )
+ endwhile
+endfunction
+
+" This is a rather dirty hack, but seems to work somehow :-) (malte)
+function! AddHeader()
+ let s = getline( '.' )
+ let i = col( '.' ) - 1
+ while i > 0 && strpart( s, i, 1 ) !~ '[A-Za-z0-9_:]'
+ let i = i - 1
+ endwhile
+ while i > 0 && strpart( s, i, 1 ) =~ '[A-Za-z0-9_:]'
+ let i = i - 1
+ endwhile
+ let start = match( s, '[A-Za-z0-9_]\+\(::[A-Za-z0-9_]\+\)*', i )
+ let end = matchend( s, '[A-Za-z0-9_]\+\(::[A-Za-z0-9_]\+\)*', i )
+ if end > col( '.' )
+ let end = matchend( s, '[A-Za-z0-9_]\+', i )
+ endif
+ let ident = strpart( s, start, end - start )
+ let include = '#include ' . MapIdentHeader( ident )
+
+ let line = 1
+ let incomment = 0
+ let appendpos = 0
+ let codestart = 0
+ while line <= line( '$' )
+ let s = getline( line )
+ if incomment == 1
+ let end = matchend( s, '\*/' )
+ if end == -1
+ let line = line + 1
+ continue
+ else
+ let s = strpart( s, end )
+ let incomment = 0
+ endif
+ endif
+ let s = substitute( s, '//.*', '', '' )
+ let s = substitute( s, '/\*\([^*]\|\*\@!/\)*\*/', '', 'g' )
+ if s =~ '/\*'
+ let incomment = 1
+ elseif s =~ '^' . include
+ break
+ elseif s =~ '^#include' && s !~ '\.moc"'
+ let appendpos = line
+ elseif codestart == 0 && s !~ '^$'
+ let codestart = line
+ endif
+ let line = line + 1
+ endwhile
+ if line == line( '$' ) + 1
+ if appendpos == 0
+ call append( codestart - 1, include )
+ call append( codestart, '' )
+ else
+ call append( appendpos, include )
+ endif
+ endif
+endfunction
+
+function! RunDiff()
+ echo 'Diffing....'
+ read! cvs diff -bB -I \\\#include | egrep -v '(^Index:|^=+$|^RCS file:|^retrieving revision|^diff -u|^[+-]{3})'
+endfunction
+
+function! CreateChangeLogEntry()
+ let currentBuffer = expand( "%" )
+
+ if exists( "g:EMAIL" )
+ let mail = g:EMAIL
+ elseif exists( "$EMAIL" )
+ let mail = $EMAIL
+ else
+ let mail = inputdialog( "Enter Name/Email for Changelog entry: " )
+ if mail == ""
+ echo "Aborted ChangeLog edit..."
+ return
+ endif
+ let g:EMAIL = mail
+ endif
+
+ if bufname( "ChangeLog" ) != "" && bufwinnr( bufname( "ChangeLog" ) ) != -1
+ execute bufwinnr( bufname( "ChangeLog" ) ) . " wincmd w"
+ else
+ execute "split ChangeLog"
+ endif
+
+ let lastEntry = getline( nextnonblank( 1 ) )
+ let newEntry = strftime("%Y-%m-%d") . " " . mail
+
+ if lastEntry != newEntry
+ call append( 0, "" )
+ call append( 0, "" )
+ call append( 0, newEntry )
+ endif
+
+ " like emacs, prepend the current buffer name to the entry. but unlike
+ " emacs I have no idea how to figure out the current function name :(
+ " (Simon)
+ if currentBuffer != ""
+ let newLine = "\t* " . currentBuffer . ": "
+ else
+ let newLine = "\t* "
+ endif
+
+ call append( 2, newLine )
+
+ execute "normal 3G$"
+endfunction
+
+function! AddQtSyntax()
+ if expand( "<amatch>" ) == "cpp"
+ syn keyword qtKeywords signals slots emit foreach
+ syn keyword qtMacros Q_OBJECT Q_WIDGET Q_PROPERTY Q_ENUMS Q_OVERRIDE Q_CLASSINFO Q_SETS SIGNAL SLOT
+ syn keyword qtCast qt_cast qobject_cast qvariant_cast qstyleoption_cast
+ syn keyword qtTypedef uchar uint ushort ulong Q_INT8 Q_UINT8 Q_INT16 Q_UINT16 Q_INT32 Q_UINT32 Q_LONG Q_ULONG Q_INT64 Q_UINT64 Q_LLONG Q_ULLONG pchar puchar pcchar qint8 quint8 qint16 quint16 qint32 quint32 qint64 quint64 qlonglong qulonglong
+ syn keyword kdeKeywords k_dcop k_dcop_signals
+ syn keyword kdeMacros K_DCOP ASYNC
+ syn keyword cRepeat foreach
+ syn keyword cRepeat forever
+
+ hi def link qtKeywords Statement
+ hi def link qtMacros Type
+ hi def link qtCast Statement
+ hi def link qtTypedef Type
+ hi def link kdeKeywords Statement
+ hi def link kdeMacros Type
+ endif
+endfunction
+
+function! InsertMethodTracer()
+ :normal [[kf(yBjokdDebug() << ""()" << endl;
+endfunction
+
+function! UpdateMocFiles()
+ if &syntax == "cpp"
+ let i = 1
+ while i < 80
+ let s = getline( i )
+ if s =~ '^#include ".*\.moc"'
+ let s = substitute( s, '.*"\(.*\)\.moc"', '\1.h', '' )
+ if stridx( &complete, s ) == -1
+ let &complete = &complete . ',k' . s
+ endif
+ break
+ endif
+ let i = i + 1
+ endwhile
+ endif
+endfunction
+
+autocmd Syntax * call AddQtSyntax()
+autocmd CursorHold * call UpdateMocFiles()
+
+" vim: sw=4 sts=4 et
diff --git a/scripts/kde-emacs/HACKING b/scripts/kde-emacs/HACKING
new file mode 100644
index 00000000..d3a87f22
--- /dev/null
+++ b/scripts/kde-emacs/HACKING
@@ -0,0 +1,7 @@
+Rules are simple:
+1) Make sure that your functions work both on GNU/Emacs and XEmacs.
+2) Put general variables in kde-emacs-vars.el, file related variables
+inside the related file.
+3) Export general functions to kde-emacs-general.el.
+4) Always provide documentation for both variables and functions that
+you're adding.
diff --git a/scripts/kde-emacs/dirvars.el b/scripts/kde-emacs/dirvars.el
new file mode 100644
index 00000000..5fba18e7
--- /dev/null
+++ b/scripts/kde-emacs/dirvars.el
@@ -0,0 +1,200 @@
+;;; -*- local-enable-local-variables: nil -*-
+;;; dirvars.el --- Local variables that apply to an entire directory
+
+;; Copyright (C) 2002 Matt Armstrong
+
+;; Author: Matt Armstrong <matt@lickey.com>
+;; Location: http://www.lickey.com/env/elisp/dirvars.el
+;; Keywords: files
+;; Version: 1.2
+;; Obscure: matt@squeaker.lickey.com|elisp/dirvars.el|20021213043855|48166
+
+;; This file is free software; you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation; either version 2, or (at your option)
+;; any later version.
+
+;; This file 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 GNU Emacs; see the file COPYING. If not, write to
+;; the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor,
+;; Boston, MA 02110-1301, USA.
+
+;;; Commentary:
+
+;; Emacs allows you to specify local variable values for use when
+;; editing a file either in the first line or in a local variables
+;; list.
+;;
+;; This file provides similar functionality, but for an entire
+;; directory tree.
+;;
+;; You simply place an .emacs-dirvars file in the root of your
+;; project's tree, and you can then set emacs variables like you would
+;; in a Local Variables: section at the end of a file. E.g. the
+;; contents of a typical dirvars file might look like this:
+;;
+;; ;; -*- emacs-lisp -*-
+;; ;;
+;; ;; This file is processed by the dirvars emacs package. Each variable
+;; ;; setting below is performed when this dirvars file is loaded.
+;; ;;
+;; indent-tabs-mode: nil
+;; tab-width: 8
+;; show-trailing-whitespace: t
+;; indicate-empty-lines: t
+;;
+;; Much of this code is stolen and modified from the standard Emacs
+;; files.el
+;;
+;; This code refuses to set any symbol that meets any of these
+;; criteria (this criteria is stolen from files.el):
+;;
+;; - the symbol is in the ignored-local-variables list
+;; - the symbol has the risky-local-variable property.
+;; - the symbol name ends in -hook(s), -function(s), -form(s),
+;; -program, -command, or -predicate.
+
+;;; Todo:
+
+;; Implement the following changes to keep in line with elisp coding
+;; conventions: When a package provides a modification of ordinary
+;; Emacs behavior, it is good to include a command to enable and
+;; disable the feature, Provide a command named `WHATEVER-mode' which
+;; turns the feature on or off, and make it autoload (*note
+;; Autoload::). Design the package so that simply loading it has no
+;; visible effect--that should not enable the feature.(2) Users will
+;; request the feature by invoking the command.
+;;
+;; Support customize?
+
+;;; Code:
+
+(defvar dirvars-enable-flag t
+ "*Control use of directory variables in files you visit.
+The meaningful values are nil and non-nil.")
+
+(defun dirvars-find-upwards (file-name)
+ "Find a file in the current directory or one of its parents.
+
+Returns the fully qualified file name, or nil if it isn't found.
+
+The FILE-NAME specifies the file name to search for."
+ ;; Chase links in the source file and search in the dir where it
+ ;; points.
+ (setq dir-name (or (and buffer-file-name
+ (file-name-directory (file-chase-links
+ buffer-file-name)))
+ default-directory))
+ ;; Chase links before visiting the file. This makes it easier to
+ ;; use a single file for several related directories.
+ (setq dir-name (file-chase-links dir-name))
+ (setq dir-name (expand-file-name dir-name))
+ ;; Move up in the dir hierarchy till we find a change log file.
+ (let ((file1 (concat dir-name file-name))
+ parent-dir)
+ (while (and (not (file-exists-p file1))
+ (progn (setq parent-dir
+ (file-name-directory
+ (directory-file-name
+ (file-name-directory file1))))
+ ;; Give up if we are already at the root dir.
+ (not (string= (file-name-directory file1)
+ parent-dir))))
+ ;; Move up to the parent dir and try again.
+ (setq file1 (expand-file-name file-name parent-dir)))
+ ;; If we found the file in a parent dir, use that. Otherwise,
+ ;; return nil
+ (if (or (get-file-buffer file1) (file-exists-p file1))
+ file1
+ nil)))
+
+(defun dirvars-eat-comment ()
+ (while (looking-at "[ \t\n]*;")
+ (let ((begin (point)))
+ (skip-chars-forward " \t\n")
+ (if (looking-at ";")
+ (progn
+ (end-of-line)
+ (delete-region begin (point)))))))
+
+(defun dirvars-hack-local-variables (dirvars-file)
+ (save-excursion
+ (let ((original-buffer (current-buffer))
+ (temp-buffer (get-buffer-create "*dirvars-temp*"))
+ (enable-local-variables (and ;local-enable-local-variables -- doesn't exist!
+ enable-local-variables
+ dirvars-enable-flag))
+ (continue t)
+ (parse-sexp-ignore-comments t)
+ (lisp-mode-hook nil)
+ beg)
+ (set-buffer temp-buffer)
+ (erase-buffer)
+ (lisp-mode)
+ (insert-file dirvars-file)
+ (goto-char (point-min))
+ (catch 'done
+ (while continue
+ (if (null (scan-sexps (point) 1))
+ (throw 'done nil))
+ (goto-char (scan-sexps (point) 1))
+ (goto-char (scan-sexps (point) -1))
+ (if (eobp)
+ (throw 'done nil))
+ (setq beg (point))
+ (skip-chars-forward "^:\n")
+ (if (not (looking-at ":"))
+ (error (format "Missing colon in directory variables entry at %d"
+ (point))))
+ (skip-chars-backward " \t")
+ (let* ((str (buffer-substring beg (point)))
+ (var (read str))
+ val)
+ ;; Read the variable value.
+ (skip-chars-forward "^:")
+ (forward-char 1)
+ (setq val (read (current-buffer)))
+ (save-excursion
+ (set-buffer original-buffer)
+ (dirvars-hack-one-local-variable dirvars-file
+ var val))))))))
+
+(defun dirvars-hack-one-local-variable (dirvars-file var val)
+ "\"Set\" one variable in a local variables spec.
+A few variable names are treated specially."
+ (cond ((memq var ignored-local-variables)
+ nil)
+ ;; Trap risky variables and such. This is the same logic
+ ;; that files.el uses.
+ ((or (get var 'risky-local-variable)
+ (and
+ (string-match "-hooks?$\\|-functions?$\\|-forms?$\\|-program$\\|-command$\\|-predicate$"
+ (symbol-name var))
+ (not (get var 'safe-local-variable))))
+ (message (format "Ignoring %s in %s"
+ (symbol-name var) dirvars-file)))
+ ;;check whether the var should be evaluated
+ ((eq var 'evaluate)
+ (eval val))
+ ;; Ordinary variable, really set it.
+ (t (make-local-variable var)
+ (set var val))))
+
+(defun dirvars-hack-local-variables-before ()
+ (let ((dirvars-file (dirvars-find-upwards ".emacs-dirvars")))
+ (if dirvars-file
+ (dirvars-hack-local-variables dirvars-file))))
+
+(defadvice hack-local-variables
+ (before dirvars-hack-local-variables-before)
+ "Process dirvars before a file's local variables are processed."
+ (dirvars-hack-local-variables-before))
+(ad-activate 'hack-local-variables)
+
+(provide 'dirvars)
+;;; dirvars.el ends here
diff --git a/scripts/kde-emacs/kde-emacs-bindings.el b/scripts/kde-emacs/kde-emacs-bindings.el
new file mode 100644
index 00000000..84202dfb
--- /dev/null
+++ b/scripts/kde-emacs/kde-emacs-bindings.el
@@ -0,0 +1,185 @@
+;; kde-emacs-bindings.el
+;;
+;; Copyright (C) 2002 KDE Development Team
+;;
+;; This library is free software; you can redistribute it and/or
+;; modify it under the terms of the GNU Lesser General Public
+;; License as published by the Free Software Foundation; either
+;; version 2.1 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
+;; Lesser General Public License for more details.
+;;
+;; You should have received a copy of the GNU Lesser General Public
+;; License along with this library; if not, write to the Free Software
+;; Foundation, Inc., 51 Franklin Steet, Fifth Floor, Boston, MA
+;; 02110-1301 USA
+
+; currently no binding for header-protection and add-file-to-makefile-am,
+; you need to call them from M-x
+
+; -----------------------------------------------------------------
+; The list below defines the following bindings:
+;
+; F2 : offer a grep command (use C-u F2 if you need to specify options, like -i or -w)
+; Shift-F2 : offer a grep command to search in directories below the current too..
+;
+; F3/Shift-F3/F8/Shift-RMB : different ways to see the list of methods in the current buffer
+;
+; F4 : make
+; Shift-F4 : make clean
+; F5 : make install
+; Shift-F5 : make install-exec
+;
+; Shift-F6 : compile this file [assumes libtool is being used]
+; F6 : Switch from .cpp/.cc to .h and vice-versa
+; F7 : The same, but try to find the current method in the other file
+; F9 : Create a member method in the .cpp, the cursor being on the definition in the .h
+; F10: Place point on a class name, and the respective (Qt) include file will be inserted.
+; This works with all Qt classes but can easily be extended to KDE classes.
+; Shift-F10: Place point on a class name, and "class Blah" will be inserted near the top.
+; Meta-F10: Place point on a class name, and press Meta-F10, and konqueror will load
+; Qt documentation. Customize the location of the Qt documentation with the
+; variable kdab-qt-documentation. XXX will be replace with the class name.
+; Example (setq kdab-qt-location "file:/packages/kde-src/qt-copy/doc/html/XXX.html")
+;
+; M-n: jump to the next error (after compiling) or grep matches
+;
+; Ctrl+Meta+D : insert a kdDebug statement with the name of the current method
+; [the new hide-all-windows shortcut conflicts with that, you may have to
+; change it, or use Ctrl+Meta+Shift+D (!!)]
+;
+; Meta Up/Down : scroll the other window (when window is split)
+
+; Other very useful keybindings to know about:
+; C-x r m to set a named bookmark in the buffer
+; C-x r b to jump to a named bookmark in the buffer
+; To save bookmarks to a file type:
+; M-x bookmark-write
+; and to load bookmarks from a file write:
+; M-x bookmark-load
+
+(require 'kde-emacs-core)
+(require 'kde-emacs-general)
+(require 'kde-emacs-utils)
+(require 'klaralv)
+(require 'kde-emacs-utils)
+(when (featurep 'semantic)
+ (require 'kde-emacs-semantic)
+ (require 'kde-emacs-doc))
+
+;; Wheelmouse support
+(define-key global-map [(button4)] 'scroll-me-down)
+(define-key global-map [(button5)] 'scroll-me-up)
+(define-key global-map [(shift button4)] 'scroll-me-down-a-bit)
+(define-key global-map [(shift button5)] 'scroll-me-up-a-bit)
+
+;; Some example bindings, feel free to customize :)
+(define-key global-map [(meta up)] 'scroll-other-up)
+(define-key global-map [(meta down)] 'scroll-other-down)
+(define-key global-map [(control j)] 'goto-line)
+(global-set-key [(control %)] 'match-paren) ;;for all buffers :)
+
+(if (featurep 'igrep)
+ (progn
+ (setq igrep-find-prune-clause
+ (format "-type d %s -name CVS -o -name .libs -o -name .deps %s"
+ (shell-quote-argument "(")
+ (shell-quote-argument ")")))
+ (setq igrep-find-file-clause
+ (format "-type f %s -name %s %s -name %s %s -name %s %s -name %s" ; -type l
+ (shell-quote-argument "!")
+ (shell-quote-argument "*~") ; Emacs backup
+ (shell-quote-argument "!")
+ (shell-quote-argument "*,v") ; RCS file
+ (shell-quote-argument "!")
+ (shell-quote-argument "s.*") ; SCCS file
+ (shell-quote-argument "!")
+ (shell-quote-argument "*.o") ; compiled object
+ (shell-quote-argument "!")
+ (shell-quote-argument ".#*") ; Emacs temp file
+ )
+ )
+ (define-key global-map [(f2)] 'igrep)
+ (define-key global-map [(shift f2)] 'igrep-find)
+ (define-key global-map [(f12)] 'igrep-find) ; on the console, shift f2 gives f12 for some reason..
+ ;(setq igrep-files-default 'ignore) ; too hard to use *.cc *.h with it, because of the full path
+ )
+ (define-key global-map [(f2)] 'grep))
+(define-key global-map [(shift backspace)] 'kde-delete-backward-ws)
+
+;; FIXME: remember to get these working on Gnu/Emacs (Zack)
+(when (eq kde-emacs-type 'xemacs)
+ (define-key c++-mode-map [(f8)] 'function-menu)
+ (define-key c++-mode-map [(f3)] 'fume-prompt-function-goto)
+ (define-key c++-mode-map [(shift f3)] 'fume-list-functions)
+ )
+
+(define-key global-map [(shift button3)] 'mouse-function-menu)
+(define-key global-map [(shift f4)] 'makeclean)
+(define-key global-map [(f4)] 'make)
+(define-key global-map [(f5)] 'makeinstall)
+(define-key global-map [(shift f5)] 'makeinstallexec)
+(define-key global-map [(shift f6)] 'makethisfile)
+(if kde-emacs-newline-semicolon
+ (define-key c++-mode-map "\;" 'insert-semicolon))
+(define-key c++-mode-map [(f6)] 'kde-switch-cpp-h)
+(define-key c-mode-map [(f6)] 'kde-switch-cpp-h)
+(define-key c++-mode-map [(f7)] 'switch-to-function-def)
+(define-key c++-mode-map [(f9)] 'agulbra-make-member)
+(define-key c-mode-map [(f9)] 'agulbra-make-member)
+(define-key global-map [(meta n)] 'next-error)
+
+; kde-emacs-headers:
+(define-key c++-mode-map [(f10)] 'kdab-insert-header)
+(define-key c++-mode-map [(shift f10)] 'kdab-insert-forward-decl)
+(define-key c++-mode-map [(meta f10)] 'kdab-lookup-qt-documentation)
+(define-key c++-mode-map [(control meta d)] 'insert-kdDebug)
+
+; Standard Qt/KDE shortcuts: Ctrl+Backspace, Ctrl+Delete
+(define-key global-map [(control backspace)] 'backward-kill-word)
+(define-key global-map [(control delete)] 'kill-word)
+
+; Standard Qt/KDE shortcuts: Control Pageup and Pagedown
+(define-key global-map [(control prior)] 'beginning-of-buffer)
+(define-key global-map [(control next)] 'end-of-buffer)
+
+; kde-emacs-semantic :
+; no binding for kde-license-insert; call it via M-x
+(when (featurep 'semantic)
+ (define-key c++-mode-map [(control c)(control k)(d)] 'kde-doc-function-insert)
+ (define-key c++-mode-map [(control c)(control k)(m)] 'kde-doc-multiline-insert)
+ (define-key c++-mode-map [(control c)(control k)(o)] 'kde-doc-oneliner-insert)
+ (define-key c++-mode-map [(control c)(control k)(e)] 'kde-function-expand-at-point)
+ (define-key c++-mode-map [(control c)(control k)(s)] 'kde-create-skeletons))
+
+(modify-frame-parameters (selected-frame) '((menu-bar-lines . 2)))
+(define-key c++-mode-map [menu-bar KDE]
+ (cons "KDE" c++-mode-map))
+(when (featurep 'semantic)
+ (define-key c++-mode-map [menu-bar KDE kde-doc-function-insert]
+ '("kde-doc-function-insert" . kde-doc-function-insert))
+ (define-key c++-mode-map [menu-bar KDE kde-function-expand-at-point]
+ '("kde-function-expand-at-point" . kde-function-expand-at-point))
+ (define-key c++-mode-map [menu-bar KDE kde-create-skeletons]
+ '("kde-create-skeletons" . kde-create-skeletons))
+ (define-key c++-mode-map [menu-bar KDE kde-doc-multiline-insert]
+ '("kde-doc-multiline-insert" . kde-doc-multiline-insert)))
+(define-key c++-mode-map [menu-bar KDE makeclean]
+ '("make clean" . makeclean))
+(define-key c++-mode-map [menu-bar KDE make]
+ '("make" . make))
+(define-key c++-mode-map [menu-bar KDE makeinstall]
+ '("make install" . makeinstall))
+(define-key c++-mode-map [menu-bar KDE makethisfile]
+ '("make this file" . makethisfile))
+(define-key c++-mode-map [menu-bar KDE kdeswitchcpph]
+ '("Switch to .h/.cpp file" . kde-switch-cpp-h))
+(define-key c++-mode-map [menu-bar KDE insert-kdDebug]
+ '("Insert kdDebug" . insert-kdDebug))
+
+
+(provide 'kde-emacs-bindings)
+
diff --git a/scripts/kde-emacs/kde-emacs-compat.el b/scripts/kde-emacs/kde-emacs-compat.el
new file mode 100644
index 00000000..1ff1fe7a
--- /dev/null
+++ b/scripts/kde-emacs/kde-emacs-compat.el
@@ -0,0 +1,77 @@
+;; kde-emacs-compat.el - contains compatibility functions
+;;
+;; Copyright (C) 2003 Zack Rusin <zack@kde.org>
+;; 2003 KDE Developlment team
+;; 2003 XEmacs developers
+;;
+;; This program is free software; you can redistribute it and/or
+;; modify it under the terms of the 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, write to the Free Software
+;; Foundation, Inc., 51 Franklin Steet, Fifth Floor, Boston, MA
+;; 02110-1301, USA.
+
+(require 'kde-emacs-vars)
+
+;;GNU/Emacs does not have this one
+(if (not (fboundp 'replace-in-string))
+ (defun replace-in-string (str regexp newtext &optional literal)
+ "Replace all matches in STR for REGEXP with NEWTEXT string,
+ and returns the new string.
+Optional LITERAL non-nil means do a literal replacement.
+Otherwise treat `\\' in NEWTEXT as special:
+ `\\&' in NEWTEXT means substitute original matched text.
+ `\\N' means substitute what matched the Nth `\\(...\\)'.
+ If Nth parens didn't match, substitute nothing.
+ `\\\\' means insert one `\\'.
+ `\\u' means upcase the next character.
+ `\\l' means downcase the next character.
+ `\\U' means begin upcasing all following characters.
+ `\\L' means begin downcasing all following characters.
+ `\\E' means terminate the effect of any `\\U' or `\\L'."
+ (if (> (length str) 50)
+ (with-temp-buffer
+ (insert str)
+ (goto-char 1)
+ (while (re-search-forward regexp nil t)
+ (replace-match newtext t literal))
+ (buffer-string))
+ (let ((start 0) newstr)
+ (while (string-match regexp str start)
+ (setq newstr (replace-match newtext t literal str)
+ start (+ (match-end 0) (- (length newstr) (length str)))
+ str newstr))
+ str)))
+
+ )
+
+(if (not (fboundp 'read-shell-command))
+ (progn
+ (defvar read-shell-command-map
+ (let ((map (make-sparse-keymap 'read-shell-command-map)))
+ (if (eq kde-emacs-type 'xemacs)
+ (set-keymap-parents map (list minibuffer-local-map))
+ (set-keymap-parent map minibuffer-local-map))
+ (define-key map "\t" 'comint-dynamic-complete)
+ (define-key map "\M-\t" 'comint-dynamic-complete)
+ (define-key map "\M-?" 'comint-dynamic-list-completions)
+ map)
+ "Minibuffer keymap used by `shell-command' and related commands.")
+ (defun read-shell-command (prompt &optional initial-input history default-value)
+ "Just like read-string, but uses read-shell-command-map:
+\\{read-shell-command-map}"
+ (let ((minibuffer-completion-table nil))
+ (read-from-minibuffer prompt initial-input read-shell-command-map
+ nil (or history 'shell-command-history)
+ nil default-value)))
+ ))
+
+(provide 'kde-emacs-compat)
diff --git a/scripts/kde-emacs/kde-emacs-core.el b/scripts/kde-emacs/kde-emacs-core.el
new file mode 100644
index 00000000..a954dfa0
--- /dev/null
+++ b/scripts/kde-emacs/kde-emacs-core.el
@@ -0,0 +1,3823 @@
+;; kde-emacs-core.el - core functionality,e.g. syntax & c++-mode-hook
+;;
+;; Copyright (C) 2002 KDE Development Team <www.kde.org>
+;;
+;; This library is free software; you can redistribute it and/or
+;; modify it under the terms of the GNU Lesser General Public
+;; License as published by the Free Software Foundation; either
+;; version 2.1 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
+;; Lesser General Public License for more details.
+;;
+;; You should have received a copy of the GNU Lesser General Public
+;; License along with this library; if not, write to the Free Software
+;; Foundation, Inc., 51 Franklin Steet, Fifth Floor, Boston, MA
+;; 02110-1301 USA
+
+(require 'kde-emacs-vars)
+;*---------------------------------------------------------------------*/
+;* Variables ... */
+;*---------------------------------------------------------------------*/
+
+(defcustom kde-tab-behavior 'default
+ "Specifies the current tab behavior. default will expand try to complete
+the symbol at point if at the end of something that looks like an indentifier else
+it will indent the current line if the pointer is at the beginning of the line it will
+be moved the the start of the indention. abbrev-indent behaves like default, but the
+cursor isn't moved to the beginning of the indention with tab is pressed when the cursor
+is at the beginning of the line. indent simply indents the line without trying to
+complete the symbol"
+ :group 'kde-devel
+ :version "0.1"
+ :type `(choice (const default) (const abbrev-indent) (const indent)))
+
+;*---------------------------------------------------------------------*/
+;* Functions ... */
+;*---------------------------------------------------------------------*/
+
+
+;; ------- First part, from Arnt's "c++ stuff" - slightly modified for our needs :)
+
+(defun agulbra-c++-tab (arg)
+ "Do the right thing about tabs in c++ mode.
+Try to finish the symbol, or indent the line."
+ (interactive "*P")
+ (cond
+ ((and (not (looking-at "[A-Za-z0-9]"))
+ (save-excursion
+ (forward-char -1)
+ (looking-at "[A-Za-z0-9:>_\\-\\&\\.(){}\\*\\+/]")))
+ (dabbrev-expand arg))
+ (t
+ (if (eq kde-tab-behavior 'default)
+ (c-indent-command)
+ (save-excursion
+ (beginning-of-line)
+ (c-indent-command))))))
+
+(defun agulbra-clean-out-spaces ()
+ "Remove spaces at ends of lines."
+ (interactive)
+ (and (not buffer-read-only)
+ (save-excursion
+ (goto-char (point-min))
+ (let ((count 0)
+ (bmp (buffer-modified-p)))
+ (while (re-search-forward "[ \t]+$" nil t)
+ (setq count (1+ count))
+ (replace-match "" t t))
+ (set-buffer-modified-p bmp)
+ nil
+ ))))
+
+; the above used to contain (untabify (point-min) (point-max)) too
+
+(defun agulbra-c++-clean-out-spaces ()
+ "Remove spaces at ends of lines, only in c++ mode."
+ (interactive)
+ (if (eq major-mode 'c++-mode)
+ (agulbra-clean-out-spaces)
+ )
+ )
+
+(defun agulbra-delete-into-nomenclature (&optional arg)
+ "Delete forward until the end of a nomenclature section or word.
+With arg, do it arg times."
+ (interactive "p")
+ (save-excursion
+ (let ((b (point-marker)))
+ (c-forward-into-nomenclature arg)
+ (delete-region b (point-marker)))))
+
+
+(if (not (fboundp 'font-lock-add-keywords))
+ (defun font-lock-add-keywords (mode keywords &optional append)
+ "XEmacs doesn't have font-lock-add-keywords so we provide it."
+ (font-lock-set-defaults)
+ (if (eq append 'set)
+ (setq font-lock-keywords keywords)
+ ; NOTE: write this function for XEmacs - Zack
+ ;(font-lock-remove-keywords nil keywords) ;to avoid duplicates
+ (let ((old (if (eq (car-safe font-lock-keywords) t)
+ (cdr font-lock-keywords)
+ font-lock-keywords)))
+ (setq font-lock-keywords (if append
+ (append old keywords)
+ (append keywords old))))))
+ )
+
+(c-add-style "kde-c" '("stroustrup"
+ (c-basic-offset . 4)
+ (c-offsets-alist
+ (case-label . 4)
+ (access-label . -)
+ (label . 0)
+ (statement-cont . c-lineup-math)
+ )))
+
+; ( we use Backquote ( '`' ) instead of "'" because we want
+; kde-access-labels to be evaluated... )
+(c-add-style "kde-c++" `("kde-c"
+ ;;FIXME: 1) fume functions not available on GNU/Emacs
+ ;; 2) insert-tab-mode no longer present (free variable)
+ ;; 3) c-hangin-commment-under-p no longer present (free variable)
+ (if (not (eq kde-tab-behavior 'indent))
+ (c-tab-always-indent . nil))
+ ; (insert-tab-mode nil)
+ (indent-tabs-mode . nil)
+ (if (eq kde-emacs-type 'xemacs)
+ (fume-auto-rescan-buffer-p nil))
+ (c-access-key . ,kde-access-labels)
+ (c-opt-access-key . ,kde-access-labels)
+ ; (c-hanging-comment-under-p nil)
+ (c-offsets-alist . ((case-label . 0)
+ (inline-open . 0)))
+ ))
+
+;; KDE C++ mode
+;; Not a "(setq c++-mode-hook ..." because this way we would
+;; prune all other hooks!
+(defun kde-c++-mode-hook ()
+ (font-lock-mode)
+ (c-set-style kde-c++-style)
+ (define-key c++-mode-map "\C-m" 'c-context-line-break)
+ (when (or
+ (eq kde-tab-behavior 'default)
+ (eq kde-tab-behavior 'abbrev-indent))
+ (define-key c++-mode-map "\C-i" 'agulbra-c++-tab))
+ (define-key c++-mode-map "\ef" 'c-forward-into-nomenclature)
+ (define-key c++-mode-map "\ed" 'agulbra-delete-into-nomenclature)
+ (define-key c++-mode-map "\eb" 'c-backward-into-nomenclature)
+ ;; fontify "public|protected|private slots" with one and the same face :)
+ ;; NOTE: write face-at-point function to fontify those just like other
+ ;; access specifiers
+ (font-lock-add-keywords nil '(("\\<\\(\\(public\\|protected\\|private\\) slots\\)\\>"
+ . font-lock-reference-face)))
+ ;; Add (setq magic-keys-mode nil) to your .emacs (before loading this file)
+ ;; to disable the magic keys in C++ mode.
+ (and (boundp 'magic-keys-mode) magic-keys-mode
+ (progn
+ (define-key c++-mode-map "\(" 'insert-parens)
+ (define-key c++-mode-map "\)" 'insert-parens2)
+ (define-key c++-mode-map "\," 'insert-comma)
+ (define-key c++-mode-map "\{" 'insert-curly-brace)
+ ))
+ )
+
+(defun kde-c-mode-hook ()
+ (font-lock-mode)
+ (c-set-style kde-c-style))
+
+;; NOTE : This is a completely new c-guess-basic-syntax, it's faster,
+;; better, meaner, harder, covers more cases, more c++ syntax,
+;; and is in general cooler ;) You have to have the new cc-mode
+;; to use it ( 5.30 at least, check it with "M-x c-version")
+;; If you don't have 5.30 comment out the following c-guess-basic-syntax
+;; and uncomment the one underneath.
+(cond
+ ((string-match "^5\\.30\\." c-version)
+ (defun c-guess-basic-syntax ()
+ "Return the syntactic context of the current line.
+This function does not do any hidden buffer changes."
+ (save-excursion
+ (save-restriction
+ (beginning-of-line)
+ (c-save-buffer-state
+ ((indent-point (point))
+ (case-fold-search nil)
+ (paren-state (c-parse-state))
+ literal containing-sexp char-before-ip char-after-ip lim
+ c-syntactic-context placeholder c-in-literal-cache step-type
+ tmpsymbol keyword injava-inher special-brace-list
+ ;; narrow out any enclosing class or extern "C" block
+ (inclass-p (c-narrow-out-enclosing-class paren-state
+ indent-point))
+ ;; `c-state-cache' is shadowed here so that we don't
+ ;; throw it away due to the narrowing that might be done
+ ;; by the function above. That means we must not do any
+ ;; changes during the execution of this function, since
+ ;; `c-invalidate-state-cache' then would change this local
+ ;; variable and leave a bogus value in the global one.
+ (c-state-cache (if inclass-p
+ (c-whack-state-before (point-min) paren-state)
+ paren-state))
+ (c-state-cache-start (point-min))
+ inenclosing-p macro-start in-macro-expr
+ ;; There's always at most one syntactic element which got
+ ;; a relpos. It's stored in syntactic-relpos.
+ syntactic-relpos
+ (c-stmt-delim-chars c-stmt-delim-chars))
+ ;; Check for meta top-level enclosing constructs such as
+ ;; extern language definitions.
+ (save-excursion
+ (save-restriction
+ (widen)
+ (when (and inclass-p
+ (progn
+ (goto-char (aref inclass-p 0))
+ (looking-at c-other-decl-block-key)))
+ (setq inenclosing-p (match-string 1))
+ (if (string-equal inenclosing-p "extern")
+ ;; Compatibility with legacy choice of name for the
+ ;; extern-lang syntactic symbols.
+ (setq inenclosing-p "extern-lang")))))
+
+ ;; Init some position variables:
+ ;;
+ ;; containing-sexp is the open paren of the closest
+ ;; surrounding sexp or nil if there is none that hasn't been
+ ;; narrowed out.
+ ;;
+ ;; lim is the position after the closest preceding brace sexp
+ ;; (nested sexps are ignored), or the position after
+ ;; containing-sexp if there is none, or (point-min) if
+ ;; containing-sexp is nil.
+ ;;
+ ;; c-state-cache is the state from c-parse-state at
+ ;; indent-point, without any parens outside the region
+ ;; narrowed by c-narrow-out-enclosing-class.
+ ;;
+ ;; paren-state is the state from c-parse-state outside
+ ;; containing-sexp, or at indent-point if containing-sexp is
+ ;; nil. paren-state is not limited to the narrowed region, as
+ ;; opposed to c-state-cache.
+ (if c-state-cache
+ (progn
+ (setq containing-sexp (car paren-state)
+ paren-state (cdr paren-state))
+ (if (consp containing-sexp)
+ (progn
+ (setq lim (cdr containing-sexp))
+ (if (cdr c-state-cache)
+ ;; Ignore balanced paren. The next entry
+ ;; can't be another one.
+ (setq containing-sexp (car (cdr c-state-cache))
+ paren-state (cdr paren-state))
+ ;; If there is no surrounding open paren then
+ ;; put the last balanced pair back on paren-state.
+ (setq paren-state (cons containing-sexp paren-state)
+ containing-sexp nil)))
+ (setq lim (1+ containing-sexp))))
+ (setq lim (point-min)))
+
+ ;; If we're in a parenthesis list then ',' delimits the
+ ;; "statements" rather than being an operator (with the
+ ;; exception of the "for" clause). This difference is
+ ;; typically only noticeable when statements are used in macro
+ ;; arglists.
+ (when (and containing-sexp
+ (eq (char-after containing-sexp) ?\())
+ (setq c-stmt-delim-chars c-stmt-delim-chars-with-comma))
+
+ ;; cache char before and after indent point, and move point to
+ ;; the most likely position to perform the majority of tests
+ (goto-char indent-point)
+ (c-backward-syntactic-ws lim)
+ (setq char-before-ip (char-before))
+ (goto-char indent-point)
+ (skip-chars-forward " \t")
+ (setq char-after-ip (char-after))
+
+ ;; are we in a literal?
+ (setq literal (c-in-literal lim))
+
+ ;; now figure out syntactic qualities of the current line
+ (cond
+ ;; CASE 1: in a string.
+ ((eq literal 'string)
+ (c-add-syntax 'string (c-point 'bopl)))
+ ;; CASE 2: in a C or C++ style comment.
+ ((and (memq literal '(c c++))
+ ;; This is a kludge for XEmacs where we use
+ ;; `buffer-syntactic-context', which doesn't correctly
+ ;; recognize "\*/" to end a block comment.
+ ;; `parse-partial-sexp' which is used by
+ ;; `c-literal-limits' will however do that in most
+ ;; versions, which results in that we get nil from
+ ;; `c-literal-limits' even when `c-in-literal' claims
+ ;; we're inside a comment.
+ (setq placeholder (c-literal-limits lim)))
+ (c-add-syntax literal (car placeholder)))
+ ;; CASE 3: in a cpp preprocessor macro continuation.
+ ((and (save-excursion
+ (when (c-beginning-of-macro)
+ (setq macro-start (point))))
+ (/= macro-start (c-point 'boi))
+ (progn
+ (setq tmpsymbol 'cpp-macro-cont)
+ (or (not c-syntactic-indentation-in-macros)
+ (save-excursion
+ (goto-char macro-start)
+ ;; If at the beginning of the body of a #define
+ ;; directive then analyze as cpp-define-intro
+ ;; only. Go on with the syntactic analysis
+ ;; otherwise. in-macro-expr is set if we're in a
+ ;; cpp expression, i.e. before the #define body
+ ;; or anywhere in a non-#define directive.
+ (if (c-forward-to-cpp-define-body)
+ (let ((indent-boi (c-point 'boi indent-point)))
+ (setq in-macro-expr (> (point) indent-boi)
+ tmpsymbol 'cpp-define-intro)
+ (= (point) indent-boi))
+ (setq in-macro-expr t)
+ nil)))))
+ (c-add-syntax tmpsymbol macro-start)
+ (setq macro-start nil))
+ ;; CASE 11: an else clause?
+ ((looking-at "else\\>[^_]")
+ (c-beginning-of-statement-1 containing-sexp)
+ (c-add-stmt-syntax 'else-clause nil t nil
+ containing-sexp paren-state))
+ ;; CASE 12: while closure of a do/while construct?
+ ((and (looking-at "while\\>[^_]")
+ (save-excursion
+ (prog1 (eq (c-beginning-of-statement-1 containing-sexp)
+ 'beginning)
+ (setq placeholder (point)))))
+ (goto-char placeholder)
+ (c-add-stmt-syntax 'do-while-closure nil t nil
+ containing-sexp paren-state))
+ ;; CASE 13: A catch or finally clause? This case is simpler
+ ;; than if-else and do-while, because a block is required
+ ;; after every try, catch and finally.
+ ((save-excursion
+ (and (cond ((c-major-mode-is 'c++-mode)
+ (looking-at "catch\\>[^_]"))
+ ((c-major-mode-is 'java-mode)
+ (looking-at "\\(catch\\|finally\\)\\>[^_]")))
+ (and (c-safe (c-backward-syntactic-ws)
+ (c-backward-sexp)
+ t)
+ (eq (char-after) ?{)
+ (c-safe (c-backward-syntactic-ws)
+ (c-backward-sexp)
+ t)
+ (if (eq (char-after) ?\()
+ (c-safe (c-backward-sexp) t)
+ t))
+ (looking-at "\\(try\\|catch\\)\\>[^_]")
+ (setq placeholder (point))))
+ (goto-char placeholder)
+ (c-add-stmt-syntax 'catch-clause nil t nil
+ containing-sexp paren-state))
+ ;; CASE 18: A substatement we can recognize by keyword.
+ ((save-excursion
+ (and c-opt-block-stmt-key
+ (if (c-mode-is-new-awk-p)
+ (c-awk-prev-line-incomplete-p containing-sexp) ; ACM 2002/3/29
+ (not (eq char-before-ip ?\;)))
+ (not (memq char-after-ip '(?\) ?\] ?,)))
+ (or (not (eq char-before-ip ?}))
+ (c-looking-at-inexpr-block-backward c-state-cache))
+ (> (point)
+ (progn
+ ;; Ought to cache the result from the
+ ;; c-beginning-of-statement-1 calls here.
+ (setq placeholder (point))
+ (while (eq (setq step-type
+ (c-beginning-of-statement-1 lim))
+ 'label))
+ (if (eq step-type 'previous)
+ (goto-char placeholder)
+ (setq placeholder (point))
+ (if (and (eq step-type 'same)
+ (not (looking-at c-opt-block-stmt-key)))
+ ;; Step up to the containing statement if we
+ ;; stayed in the same one.
+ (let (step)
+ (while (eq
+ (setq step
+ (c-beginning-of-statement-1 lim))
+ 'label))
+ (if (eq step 'up)
+ (setq placeholder (point))
+ ;; There was no containing statement afterall.
+ (goto-char placeholder)))))
+ placeholder))
+ (if (looking-at c-block-stmt-2-key)
+ ;; Require a parenthesis after these keywords.
+ ;; Necessary to catch e.g. synchronized in Java,
+ ;; which can be used both as statement and
+ ;; modifier.
+ (and (zerop (c-forward-token-2 1 nil))
+ (eq (char-after) ?\())
+ (looking-at c-opt-block-stmt-key))))
+ (if (eq step-type 'up)
+ ;; CASE 18A: Simple substatement.
+ (progn
+ (goto-char placeholder)
+ (cond
+ ((eq char-after-ip ?{)
+ (c-add-stmt-syntax 'substatement-open nil nil nil
+ containing-sexp paren-state))
+ ((save-excursion
+ (goto-char indent-point)
+ (back-to-indentation)
+ (looking-at c-label-key))
+ (c-add-stmt-syntax 'substatement-label nil nil nil
+ containing-sexp paren-state))
+ (t
+ (c-add-stmt-syntax 'substatement nil nil nil
+ containing-sexp paren-state))))
+ ;; CASE 18B: Some other substatement. This is shared
+ ;; with case 10.
+ (c-guess-continued-construct indent-point
+ char-after-ip
+ placeholder
+ lim
+ paren-state)))
+ ;; CASE 4: In-expression statement. C.f. cases 7B, 16A and
+ ;; 17E.
+ ((and (or c-opt-inexpr-class-key
+ c-opt-inexpr-block-key
+ c-opt-lambda-key)
+ (setq placeholder (c-looking-at-inexpr-block
+ (c-safe-position containing-sexp paren-state)
+ containing-sexp)))
+ (setq tmpsymbol (assq (car placeholder)
+ '((inexpr-class . class-open)
+ (inexpr-statement . block-open))))
+ (if tmpsymbol
+ ;; It's a statement block or an anonymous class.
+ (setq tmpsymbol (cdr tmpsymbol))
+ ;; It's a Pike lambda. Check whether we are between the
+ ;; lambda keyword and the argument list or at the defun
+ ;; opener.
+ (setq tmpsymbol (if (eq char-after-ip ?{)
+ 'inline-open
+ 'lambda-intro-cont)))
+ (goto-char (cdr placeholder))
+ (back-to-indentation)
+ (c-add-stmt-syntax tmpsymbol nil t nil
+ (c-most-enclosing-brace c-state-cache (point))
+ (c-whack-state-after (point) paren-state))
+ (unless (eq (point) (cdr placeholder))
+ (c-add-syntax (car placeholder))))
+ ;; CASE 5: Line is at top level.
+ ((null containing-sexp)
+ (cond
+ ;; CASE 5A: we are looking at a defun, brace list, class,
+ ;; or inline-inclass method opening brace
+ ((setq special-brace-list
+ (or (and c-special-brace-lists
+ (c-looking-at-special-brace-list))
+ (eq char-after-ip ?{)))
+ (cond
+ ;; CASE 5A.1: Non-class declaration block open.
+ ((save-excursion
+ (goto-char indent-point)
+ (skip-chars-forward " \t")
+ (and (c-safe (c-backward-sexp 2) t)
+ (looking-at c-other-decl-block-key)
+ (setq keyword (match-string 1)
+ placeholder (point))
+ (if (string-equal keyword "extern")
+ ;; Special case for extern-lang-open. The
+ ;; check for a following string is disabled
+ ;; since it doesn't disambiguate anything.
+ (and ;;(progn
+ ;; (c-forward-sexp 1)
+ ;; (c-forward-syntactic-ws)
+ ;; (eq (char-after) ?\"))
+ (setq tmpsymbol 'extern-lang-open))
+ (setq tmpsymbol (intern (concat keyword "-open"))))
+ ))
+ (goto-char placeholder)
+ (c-add-syntax tmpsymbol (c-point 'boi)))
+ ;; CASE 5A.2: we are looking at a class opening brace
+ ((save-excursion
+ (goto-char indent-point)
+ (skip-chars-forward " \t{")
+ (let ((decl (c-search-uplist-for-classkey (c-parse-state))))
+ (and decl
+ (setq placeholder (aref decl 0)))
+ ))
+ (c-add-syntax 'class-open placeholder))
+ ;; CASE 5A.3: brace list open
+ ((save-excursion
+ (c-beginning-of-decl-1 lim)
+ (while (looking-at c-specifier-key)
+ (goto-char (match-end 1))
+ (c-forward-syntactic-ws indent-point))
+ (setq placeholder (c-point 'boi))
+ (or (consp special-brace-list)
+ (and (or (save-excursion
+ (goto-char indent-point)
+ (setq tmpsymbol nil)
+ (while (and (> (point) placeholder)
+ (zerop (c-backward-token-2 1 t))
+ (/= (char-after) ?=))
+ (and c-opt-inexpr-brace-list-key
+ (not tmpsymbol)
+ (looking-at c-opt-inexpr-brace-list-key)
+ (setq tmpsymbol 'topmost-intro-cont)))
+ (eq (char-after) ?=))
+ (looking-at c-brace-list-key))
+ (save-excursion
+ (while (and (< (point) indent-point)
+ (zerop (c-forward-token-2 1 t))
+ (not (memq (char-after) '(?\; ?\()))))
+ (not (memq (char-after) '(?\; ?\()))
+ ))))
+ (if (and (not c-auto-newline-analysis)
+ (c-major-mode-is 'java-mode)
+ (eq tmpsymbol 'topmost-intro-cont))
+ ;; We're in Java and have found that the open brace
+ ;; belongs to a "new Foo[]" initialization list,
+ ;; which means the brace list is part of an
+ ;; expression and not a top level definition. We
+ ;; therefore treat it as any topmost continuation
+ ;; even though the semantically correct symbol still
+ ;; is brace-list-open, on the same grounds as in
+ ;; case B.2.
+ (progn
+ (c-beginning-of-statement-1 lim)
+ (c-add-syntax 'topmost-intro-cont (c-point 'boi)))
+ (c-add-syntax 'brace-list-open placeholder)))
+ ;; CASE 5A.4: inline defun open
+ ((and inclass-p (not inenclosing-p))
+ (c-add-syntax 'inline-open)
+ (c-add-class-syntax 'inclass inclass-p paren-state))
+ ;; CASE 5A.5: ordinary defun open
+ (t
+ (goto-char placeholder)
+ (if (or inclass-p macro-start)
+ (c-add-syntax 'defun-open (c-point 'boi))
+ ;; Bogus to use bol here, but it's the legacy.
+ (c-add-syntax 'defun-open (c-point 'bol)))
+ )))
+ ;; CASE 5B: first K&R arg decl or member init
+ ((c-just-after-func-arglist-p lim)
+ (cond
+ ;; CASE 5B.1: a member init
+ ((or (eq char-before-ip ?:)
+ (eq char-after-ip ?:))
+ ;; this line should be indented relative to the beginning
+ ;; of indentation for the topmost-intro line that contains
+ ;; the prototype's open paren
+ ;; TBD: is the following redundant?
+ (if (eq char-before-ip ?:)
+ (forward-char -1))
+ (c-backward-syntactic-ws lim)
+ ;; TBD: is the preceding redundant?
+ (if (eq (char-before) ?:)
+ (progn (forward-char -1)
+ (c-backward-syntactic-ws lim)))
+ (if (eq (char-before) ?\))
+ (c-backward-sexp 1))
+ (setq placeholder (point))
+ (save-excursion
+ (and (c-safe (c-backward-sexp 1) t)
+ (looking-at "throw[^_]")
+ (c-safe (c-backward-sexp 1) t)
+ (setq placeholder (point))))
+ (goto-char placeholder)
+ (c-add-syntax 'member-init-intro (c-point 'boi))
+ ;; we don't need to add any class offset since this
+ ;; should be relative to the ctor's indentation
+ )
+ ;; CASE 5B.2: K&R arg decl intro
+ (c-recognize-knr-p
+ (c-beginning-of-statement-1 lim)
+ (c-add-syntax 'knr-argdecl-intro (c-point 'boi))
+ (if inclass-p
+ (c-add-class-syntax 'inclass inclass-p paren-state)))
+ ;; CASE 5B.3: Inside a member init list.
+ ((c-beginning-of-member-init-list lim)
+ (c-forward-syntactic-ws)
+ (c-add-syntax 'member-init-cont (point)))
+ ;; CASE 5B.4: Nether region after a C++ or Java func
+ ;; decl, which could include a `throws' declaration.
+ (t
+ (c-beginning-of-statement-1 lim)
+ (c-add-syntax 'func-decl-cont (c-point 'boi))
+ )))
+ ;; CASE 5C: inheritance line. could be first inheritance
+ ;; line, or continuation of a multiple inheritance
+ ((or (and (c-major-mode-is 'c++-mode)
+ (progn
+ (when (eq char-after-ip ?,)
+ (skip-chars-forward " \t")
+ (forward-char))
+ (looking-at c-opt-postfix-decl-spec-key)))
+ (and (or (eq char-before-ip ?:)
+ ;; watch out for scope operator
+ (save-excursion
+ (and (eq char-after-ip ?:)
+ (c-safe (forward-char 1) t)
+ (not (eq (char-after) ?:))
+ )))
+ (save-excursion
+ (c-backward-syntactic-ws lim)
+ (if (eq char-before-ip ?:)
+ (progn
+ (forward-char -1)
+ (c-backward-syntactic-ws lim)))
+ (back-to-indentation)
+ (looking-at c-class-key)))
+ ;; for Java
+ (and (c-major-mode-is 'java-mode)
+ (let ((fence (save-excursion
+ (c-beginning-of-statement-1 lim)
+ (point)))
+ cont done)
+ (save-excursion
+ (while (not done)
+ (cond ((looking-at c-opt-postfix-decl-spec-key)
+ (setq injava-inher (cons cont (point))
+ done t))
+ ((or (not (c-safe (c-forward-sexp -1) t))
+ (<= (point) fence))
+ (setq done t))
+ )
+ (setq cont t)))
+ injava-inher)
+ (not (c-crosses-statement-barrier-p (cdr injava-inher)
+ (point)))
+ ))
+ (cond
+ ;; CASE 5C.1: non-hanging colon on an inher intro
+ ((eq char-after-ip ?:)
+ (c-beginning-of-statement-1 lim)
+ (c-add-syntax 'inher-intro (c-point 'boi))
+ ;; don't add inclass symbol since relative point already
+ ;; contains any class offset
+ )
+ ;; CASE 5C.2: hanging colon on an inher intro
+ ((eq char-before-ip ?:)
+ (c-beginning-of-statement-1 lim)
+ (c-add-syntax 'inher-intro (c-point 'boi))
+ (if inclass-p
+ (c-add-class-syntax 'inclass inclass-p paren-state)))
+ ;; CASE kde hack:
+ ((and inclass-p
+ c-access-key
+ (looking-at c-access-key))
+ (c-add-syntax 'access-label (c-point 'bonl))
+ (c-add-class-syntax 'inclass inclass-p paren-state)
+ )
+ ;; CASE 5C.3: in a Java implements/extends
+ (injava-inher
+ (let ((where (cdr injava-inher))
+ (cont (car injava-inher)))
+ (goto-char where)
+ (cond ((looking-at "throws\\>[^_]")
+ (c-add-syntax 'func-decl-cont
+ (progn (c-beginning-of-statement-1 lim)
+ (c-point 'boi))))
+ (cont (c-add-syntax 'inher-cont where))
+ (t (c-add-syntax 'inher-intro
+ (progn (goto-char (cdr injava-inher))
+ (c-beginning-of-statement-1 lim)
+ (point))))
+ )))
+ ;; CASE 5C.4: a continued inheritance line
+ (t
+ (c-beginning-of-inheritance-list lim)
+ (c-add-syntax 'inher-cont (point))
+ ;; don't add inclass symbol since relative point already
+ ;; contains any class offset
+ )))
+ ;; CASE 5D: this could be a top-level initialization, a
+ ;; member init list continuation, or a template argument
+ ;; list continuation.
+ ((c-with-syntax-table (if (c-major-mode-is 'c++-mode)
+ c++-template-syntax-table
+ (syntax-table))
+ (save-excursion
+ ;; Note: We use the fact that lim is always after any
+ ;; preceding brace sexp.
+ (while (and (zerop (c-backward-token-2 1 t lim))
+ (not (looking-at "[;<,=]"))))
+ (or (memq (char-after) '(?, ?=))
+ (and (c-major-mode-is 'c++-mode)
+ (zerop (c-backward-token-2 1 nil lim))
+ (eq (char-after) ?<)))))
+ (goto-char indent-point)
+ (setq placeholder
+ (c-beginning-of-member-init-list lim))
+ (cond
+ ;; CASE 5D.1: hanging member init colon, but watch out
+ ;; for bogus matches on access specifiers inside classes.
+ ((and placeholder
+ (save-excursion
+ (setq placeholder (point))
+ (c-backward-token-2 1 t lim)
+ (and (eq (char-after) ?:)
+ (not (eq (char-before) ?:))))
+ (save-excursion
+ (goto-char placeholder)
+ (back-to-indentation)
+ (or
+ (/= (car (save-excursion
+ (parse-partial-sexp (point) placeholder)))
+ 0)
+ (and
+ (if c-opt-access-key
+ (not (looking-at c-opt-access-key)) t)
+ (not (looking-at c-class-key))
+ (if c-opt-bitfield-key
+ (not (looking-at c-opt-bitfield-key)) t))
+ )))
+ (goto-char placeholder)
+ (c-forward-syntactic-ws)
+ (c-add-syntax 'member-init-cont (point))
+ ;; we do not need to add class offset since relative
+ ;; point is the member init above us
+ )
+ ;; CASE 5D.2: non-hanging member init colon
+ ((progn
+ (c-forward-syntactic-ws indent-point)
+ (eq (char-after) ?:))
+ (skip-chars-forward " \t:")
+ (c-add-syntax 'member-init-cont (point)))
+ ;; CASE 5D.3: perhaps a template list continuation?
+ ((and (c-major-mode-is 'c++-mode)
+ (save-excursion
+ (save-restriction
+ (c-with-syntax-table c++-template-syntax-table
+ (goto-char indent-point)
+ (setq placeholder (c-up-list-backward (point)))
+ (and placeholder
+ (eq (char-after placeholder) ?<))))))
+ ;; we can probably indent it just like an arglist-cont
+ (goto-char placeholder)
+ (c-beginning-of-statement-1 lim t)
+ (c-add-syntax 'template-args-cont (c-point 'boi)))
+ ;; CASE 5D.4: perhaps a multiple inheritance line?
+ ((and (c-major-mode-is 'c++-mode)
+ (save-excursion
+ (c-beginning-of-statement-1 lim)
+ (setq placeholder (point))
+ (if (looking-at "static\\>[^_]")
+ (c-forward-token-2 1 nil indent-point))
+ (and (looking-at c-class-key)
+ (zerop (c-forward-token-2 2 nil indent-point))
+ (if (eq (char-after) ?<)
+ (c-with-syntax-table c++-template-syntax-table
+ (zerop (c-forward-token-2 1 t indent-point)))
+ t)
+ (eq (char-after) ?:))))
+ (goto-char placeholder)
+ (c-add-syntax 'inher-cont (c-point 'boi)))
+ ;; CASE 5D.5: Continuation of the "expression part" of a
+ ;; top level construct.
+ (t
+ (while (and (eq (car (c-beginning-of-decl-1 containing-sexp))
+ 'same)
+ (save-excursion
+ (c-backward-syntactic-ws)
+ (eq (char-before) ?}))))
+ (c-add-stmt-syntax
+ (if (eq char-before-ip ?,)
+ ;; A preceding comma at the top level means that a
+ ;; new variable declaration starts here. Use
+ ;; topmost-intro-cont for it, for consistency with
+ ;; the first variable declaration. C.f. case 5N.
+ 'topmost-intro-cont
+ 'statement-cont)
+ nil nil nil containing-sexp paren-state))
+ ))
+ ;; CASE 5E: we are looking at a access specifier
+ ((and inclass-p
+ c-opt-access-key
+ (looking-at c-opt-access-key))
+ (setq placeholder (c-add-class-syntax 'inclass inclass-p
+ paren-state))
+ ;; Append access-label with the same anchor point as inclass gets.
+ (c-append-syntax 'access-label placeholder))
+ ;; CASE 5F: Close of a non-class declaration level block.
+ ((and inenclosing-p
+ (eq char-after-ip ?}))
+ (c-add-syntax (intern (concat inenclosing-p "-close"))
+ (aref inclass-p 0)))
+ ;; CASE 5G: we are looking at the brace which closes the
+ ;; enclosing nested class decl
+ ((and inclass-p
+ (eq char-after-ip ?})
+ (save-excursion
+ (save-restriction
+ (widen)
+ (forward-char 1)
+ (and (c-safe (c-backward-sexp 1) t)
+ (= (point) (aref inclass-p 1))
+ ))))
+ (c-add-class-syntax 'class-close inclass-p paren-state))
+ ;; CASE 5H: we could be looking at subsequent knr-argdecls
+ ((and c-recognize-knr-p
+ (not (eq char-before-ip ?}))
+ (save-excursion
+ (setq placeholder (cdr (c-beginning-of-decl-1 lim)))
+ (and placeholder
+ ;; Do an extra check to avoid tripping up on
+ ;; statements that occur in invalid contexts
+ ;; (e.g. in macro bodies where we don't really
+ ;; know the context of what we're looking at).
+ (not (and c-opt-block-stmt-key
+ (looking-at c-opt-block-stmt-key)))))
+ (< placeholder indent-point))
+ (goto-char placeholder)
+ (c-add-syntax 'knr-argdecl (point)))
+ ;; CASE 5I: ObjC method definition.
+ ((and c-opt-method-key
+ (looking-at c-opt-method-key))
+ (c-beginning-of-statement-1 lim)
+ (c-add-syntax 'objc-method-intro (c-point 'boi)))
+ ;; CASE 5P: AWK pattern or function or continuation
+ ;; thereof.
+ ((c-mode-is-new-awk-p)
+ (setq placeholder (point))
+ (c-add-stmt-syntax
+ (if (and (eq (c-beginning-of-statement-1) 'same)
+ (/= (point) placeholder))
+ 'topmost-intro-cont
+ 'topmost-intro)
+ nil nil nil
+ containing-sexp paren-state))
+ ;; CASE 5N: At a variable declaration that follows a class
+ ;; definition or some other block declaration that doesn't
+ ;; end at the closing '}'. C.f. case 5D.5.
+ ((progn
+ (c-backward-syntactic-ws lim)
+ (and (eq (char-before) ?})
+ (save-excursion
+ (let ((start (point)))
+ (if paren-state
+ ;; Speed up the backward search a bit.
+ (goto-char (car (car paren-state))))
+ (c-beginning-of-decl-1 containing-sexp)
+ (setq placeholder (point))
+ (if (= start (point))
+ ;; The '}' is unbalanced.
+ nil
+ (c-end-of-decl-1)
+ (>= (point) indent-point))))))
+ (goto-char placeholder)
+ (c-add-stmt-syntax 'topmost-intro-cont nil nil nil
+ containing-sexp paren-state))
+ ;; CASE 5J: we are at the topmost level, make
+ ;; sure we skip back past any access specifiers
+ ((progn
+ (while (and inclass-p
+ c-opt-access-key
+ (not (bobp))
+ (save-excursion
+ (c-safe (progn (c-backward-sexp 1) t))
+ (and (looking-at "slots:")
+ (c-backward-sexp 1))
+ (looking-at c-opt-access-key)))
+ (c-backward-sexp 1)
+ (c-backward-syntactic-ws lim))
+ (or (bobp)
+ (if (c-mode-is-new-awk-p)
+ (not (c-awk-prev-line-incomplete-p))
+ (memq (char-before) '(?\; ?})))
+ (and (c-major-mode-is 'objc-mode)
+ (progn
+ (c-beginning-of-statement-1 lim)
+ (eq (char-after) ?@)))))
+ ;; real beginning-of-line could be narrowed out due to
+ ;; enclosure in a class block
+ (save-restriction
+ (widen)
+ (c-add-syntax 'topmost-intro (c-point 'bol))
+ ;; Using bol instead of boi above is highly bogus, and
+ ;; it makes our lives hard to remain compatible. :P
+ (if inclass-p
+ (progn
+ (goto-char (aref inclass-p 1))
+ (or (= (point) (c-point 'boi))
+ (goto-char (aref inclass-p 0)))
+ (if inenclosing-p
+ (c-add-syntax (intern (concat "in" inenclosing-p))
+ (c-point 'boi))
+ (c-add-class-syntax 'inclass inclass-p paren-state))
+ ))
+ (when (and c-syntactic-indentation-in-macros
+ macro-start
+ (/= macro-start (c-point 'boi indent-point)))
+ (c-add-syntax 'cpp-define-intro)
+ (setq macro-start nil))
+ ))
+ ;; CASE 5K: we are at an ObjC method definition
+ ;; continuation line.
+ ((and c-opt-method-key
+ (progn
+ (c-beginning-of-statement-1 lim)
+ (beginning-of-line)
+ (looking-at c-opt-method-key)))
+ (c-add-syntax 'objc-method-args-cont (point)))
+ ;; CASE 5L: we are at the first argument of a template
+ ;; arglist that begins on the previous line.
+ ((eq (char-before) ?<)
+ (c-beginning-of-statement-1 (c-safe-position (point) paren-state))
+ (c-add-syntax 'template-args-cont (c-point 'boi)))
+ ;; CASE 5M: we are at a topmost continuation line
+ (t
+ (c-beginning-of-statement-1 (c-safe-position (point) paren-state))
+ (c-add-syntax 'topmost-intro-cont (c-point 'boi)))
+ ))
+ ;; (CASE 6 has been removed.)
+ ;; CASE 7: line is an expression, not a statement. Most
+ ;; likely we are either in a function prototype or a function
+ ;; call argument list
+ ((not (or (and c-special-brace-lists
+ (save-excursion
+ (goto-char containing-sexp)
+ (c-looking-at-special-brace-list)))
+ (eq (char-after containing-sexp) ?{)))
+ (cond
+ ;; CASE 7A: we are looking at the arglist closing paren.
+ ;; C.f. case 7F.
+ ((memq char-after-ip '(?\) ?\]))
+ (goto-char containing-sexp)
+ (setq placeholder (c-point 'boi))
+ (if (and (c-safe (backward-up-list 1) t)
+ (> (point) placeholder))
+ (progn
+ (forward-char)
+ (skip-chars-forward " \t"))
+ (goto-char placeholder))
+ (c-add-stmt-syntax 'arglist-close (list containing-sexp) t nil
+ (c-most-enclosing-brace paren-state (point))
+ (c-whack-state-after (point) paren-state)))
+ ;; CASE 7B: Looking at the opening brace of an
+ ;; in-expression block or brace list. C.f. cases 4, 16A
+ ;; and 17E.
+ ((and (eq char-after-ip ?{)
+ (progn
+ (setq placeholder (c-inside-bracelist-p (point)
+ c-state-cache))
+ (if placeholder
+ (setq tmpsymbol '(brace-list-open . inexpr-class))
+ (setq tmpsymbol '(block-open . inexpr-statement)
+ placeholder
+ (cdr-safe (c-looking-at-inexpr-block
+ (c-safe-position containing-sexp
+ paren-state)
+ containing-sexp)))
+ ;; placeholder is nil if it's a block directly in
+ ;; a function arglist. That makes us skip out of
+ ;; this case.
+ )))
+ (goto-char placeholder)
+ (back-to-indentation)
+ (c-add-stmt-syntax (car tmpsymbol) nil t nil
+ (c-most-enclosing-brace paren-state (point))
+ (c-whack-state-after (point) paren-state))
+ (if (/= (point) placeholder)
+ (c-add-syntax (cdr tmpsymbol))))
+ ;; CASE 7C: we are looking at the first argument in an empty
+ ;; argument list. Use arglist-close if we're actually
+ ;; looking at a close paren or bracket.
+ ((memq char-before-ip '(?\( ?\[))
+ (goto-char containing-sexp)
+ (setq placeholder (c-point 'boi))
+ (when (and (c-safe (backward-up-list 1) t)
+ (> (point) placeholder))
+ (forward-char)
+ (skip-chars-forward " \t")
+ (setq placeholder (point)))
+ (c-add-syntax 'arglist-intro placeholder))
+ ;; CASE 7D: we are inside a conditional test clause. treat
+ ;; these things as statements
+ ((progn
+ (goto-char containing-sexp)
+ (and (c-safe (c-forward-sexp -1) t)
+ (looking-at "\\<for\\>[^_]")))
+ (goto-char (1+ containing-sexp))
+ (c-forward-syntactic-ws indent-point)
+ (if (eq char-before-ip ?\;)
+ (c-add-syntax 'statement (point))
+ (c-add-syntax 'statement-cont (point))
+ ))
+ ;; CASE 7E: maybe a continued ObjC method call. This is the
+ ;; case when we are inside a [] bracketed exp, and what
+ ;; precede the opening bracket is not an identifier.
+ ((and c-opt-method-key
+ (eq (char-after containing-sexp) ?\[)
+ (progn
+ (goto-char (1- containing-sexp))
+ (c-backward-syntactic-ws (c-point 'bod))
+ (if (not (looking-at c-symbol-key))
+ (c-add-syntax 'objc-method-call-cont containing-sexp))
+ )))
+ ;; CASE 7F: we are looking at an arglist continuation line,
+ ;; but the preceding argument is on the same line as the
+ ;; opening paren. This case includes multi-line
+ ;; mathematical paren groupings, but we could be on a
+ ;; for-list continuation line. C.f. case 7A.
+ ((progn
+ (goto-char (1+ containing-sexp))
+ (skip-chars-forward " \t")
+ (and (not (eolp))
+ (not (looking-at "\\\\$"))))
+ (goto-char containing-sexp)
+ (setq placeholder (c-point 'boi))
+ (if (and (c-safe (backward-up-list 1) t)
+ (> (point) placeholder))
+ (progn
+ (forward-char)
+ (skip-chars-forward " \t"))
+ (goto-char placeholder))
+ (c-add-stmt-syntax 'arglist-cont-nonempty (list containing-sexp)
+ t nil
+ (c-most-enclosing-brace c-state-cache (point))
+ (c-whack-state-after (point) paren-state)))
+ ;; CASE 7G: we are looking at just a normal arglist
+ ;; continuation line
+ (t (c-forward-syntactic-ws indent-point)
+ (c-add-syntax 'arglist-cont (c-point 'boi)))
+ ))
+ ;; CASE 8: func-local multi-inheritance line
+ ((and (c-major-mode-is 'c++-mode)
+ (save-excursion
+ (goto-char indent-point)
+ (skip-chars-forward " \t")
+ (looking-at c-opt-postfix-decl-spec-key)))
+ (goto-char indent-point)
+ (skip-chars-forward " \t")
+ (cond
+ ;; CASE 8A: non-hanging colon on an inher intro
+ ((eq char-after-ip ?:)
+ (c-backward-syntactic-ws lim)
+ (c-add-syntax 'inher-intro (c-point 'boi)))
+ ;; CASE 8B: hanging colon on an inher intro
+ ((eq char-before-ip ?:)
+ (c-add-syntax 'inher-intro (c-point 'boi)))
+ ;; CASE 8C: a continued inheritance line
+ (t
+ (c-beginning-of-inheritance-list lim)
+ (c-add-syntax 'inher-cont (point))
+ )))
+ ;; CASE 9: we are inside a brace-list
+ ((and (not (c-mode-is-new-awk-p)) ; Maybe this isn't needed (ACM, 2002/3/29)
+ (setq special-brace-list
+ (or (and c-special-brace-lists
+ (save-excursion
+ (goto-char containing-sexp)
+ (c-looking-at-special-brace-list)))
+ (c-inside-bracelist-p containing-sexp paren-state))))
+ (cond
+ ;; CASE 9A: In the middle of a special brace list opener.
+ ((and (consp special-brace-list)
+ (save-excursion
+ (goto-char containing-sexp)
+ (eq (char-after) ?\())
+ (eq char-after-ip (car (cdr special-brace-list))))
+ (goto-char (car (car special-brace-list)))
+ (skip-chars-backward " \t")
+ (if (and (bolp)
+ (assoc 'statement-cont
+ (setq placeholder (c-guess-basic-syntax))))
+ (setq c-syntactic-context placeholder)
+ (c-beginning-of-statement-1
+ (c-safe-position (1- containing-sexp) paren-state))
+ (c-forward-token-2 0)
+ (while (looking-at c-specifier-key)
+ (goto-char (match-end 1))
+ (c-forward-syntactic-ws))
+ (c-add-syntax 'brace-list-open (c-point 'boi))))
+ ;; CASE 9B: brace-list-close brace
+ ((if (consp special-brace-list)
+ ;; Check special brace list closer.
+ (progn
+ (goto-char (car (car special-brace-list)))
+ (save-excursion
+ (goto-char indent-point)
+ (back-to-indentation)
+ (or
+ ;; We were between the special close char and the `)'.
+ (and (eq (char-after) ?\))
+ (eq (1+ (point)) (cdr (car special-brace-list))))
+ ;; We were before the special close char.
+ (and (eq (char-after) (cdr (cdr special-brace-list)))
+ (zerop (c-forward-token-2))
+ (eq (1+ (point)) (cdr (car special-brace-list)))))))
+ ;; Normal brace list check.
+ (and (eq char-after-ip ?})
+ (c-safe (goto-char (c-up-list-backward (point))) t)
+ (= (point) containing-sexp)))
+ (if (eq (point) (c-point 'boi))
+ (c-add-syntax 'brace-list-close (point))
+ (setq lim (c-most-enclosing-brace c-state-cache (point)))
+ (c-beginning-of-statement-1 lim)
+ (c-add-stmt-syntax 'brace-list-close nil t t lim
+ (c-whack-state-after (point) paren-state))))
+ (t
+ ;; Prepare for the rest of the cases below by going to the
+ ;; token following the opening brace
+ (if (consp special-brace-list)
+ (progn
+ (goto-char (car (car special-brace-list)))
+ (c-forward-token-2 1 nil indent-point))
+ (goto-char containing-sexp))
+ (forward-char)
+ (let ((start (point)))
+ (c-forward-syntactic-ws indent-point)
+ (goto-char (max start (c-point 'bol))))
+ (c-skip-ws-forward indent-point)
+ (cond
+ ;; CASE 9C: we're looking at the first line in a brace-list
+ ((= (point) indent-point)
+ (if (consp special-brace-list)
+ (goto-char (car (car special-brace-list)))
+ (goto-char containing-sexp))
+ (if (eq (point) (c-point 'boi))
+ (c-add-syntax 'brace-list-intro (point))
+ (setq lim (c-most-enclosing-brace c-state-cache (point)))
+ (c-beginning-of-statement-1 lim)
+ (c-add-stmt-syntax 'brace-list-intro nil t t lim
+ (c-whack-state-after (point) paren-state))))
+ ;; CASE 9D: this is just a later brace-list-entry or
+ ;; brace-entry-open
+ (t (if (or (eq char-after-ip ?{)
+ (and c-special-brace-lists
+ (save-excursion
+ (goto-char indent-point)
+ (c-forward-syntactic-ws (c-point 'eol))
+ (c-looking-at-special-brace-list (point)))))
+ (c-add-syntax 'brace-entry-open (point))
+ (c-add-syntax 'brace-list-entry (point))
+ ))
+ ))))
+ ;; CASE 10: A continued statement or top level construct.
+ ((and (if (c-mode-is-new-awk-p)
+ (c-awk-prev-line-incomplete-p containing-sexp) ; ACM 2002/3/29
+ (and (not (memq char-before-ip '(?\; ?:)))
+ (or (not (eq char-before-ip ?}))
+ (c-looking-at-inexpr-block-backward c-state-cache))))
+ (> (point)
+ (save-excursion
+ (c-beginning-of-statement-1 containing-sexp)
+ (setq placeholder (point))))
+ (/= placeholder containing-sexp))
+ ;; This is shared with case 18.
+ (c-guess-continued-construct indent-point
+ char-after-ip
+ placeholder
+ containing-sexp
+ paren-state))
+ ;; CASE 14: A case or default label
+ ((looking-at c-label-kwds-regexp)
+ (goto-char containing-sexp)
+ (setq lim (c-most-enclosing-brace c-state-cache containing-sexp))
+ (c-backward-to-block-anchor lim)
+ (c-add-stmt-syntax 'case-label nil t nil
+ lim paren-state))
+ ;; CASE 15: any other label
+ ((looking-at c-label-key)
+ (goto-char containing-sexp)
+ (setq lim (c-most-enclosing-brace c-state-cache containing-sexp))
+ (save-excursion
+ (setq tmpsymbol
+ (if (and (eq (c-beginning-of-statement-1 lim) 'up)
+ (looking-at "switch\\>[^_]"))
+ ;; If the surrounding statement is a switch then
+ ;; let's analyze all labels as switch labels, so
+ ;; that they get lined up consistently.
+ 'case-label
+ 'label)))
+ (c-backward-to-block-anchor lim)
+ (c-add-stmt-syntax tmpsymbol nil t nil
+ lim paren-state))
+ ;; CASE 16: block close brace, possibly closing the defun or
+ ;; the class
+ ((eq char-after-ip ?})
+ ;; From here on we have the next containing sexp in lim.
+ (setq lim (c-most-enclosing-brace paren-state))
+ (goto-char containing-sexp)
+ (cond
+ ;; CASE 16E: Closing a statement block? This catches
+ ;; cases where it's preceded by a statement keyword,
+ ;; which works even when used in an "invalid" context,
+ ;; e.g. a macro argument.
+ ((c-after-conditional)
+ (c-backward-to-block-anchor lim)
+ (c-add-stmt-syntax 'block-close nil t nil
+ lim paren-state))
+ ;; CASE 16A: closing a lambda defun or an in-expression
+ ;; block? C.f. cases 4, 7B and 17E.
+ ((setq placeholder (c-looking-at-inexpr-block
+ (c-safe-position containing-sexp paren-state)
+ nil))
+ (setq tmpsymbol (if (eq (car placeholder) 'inlambda)
+ 'inline-close
+ 'block-close))
+ (goto-char containing-sexp)
+ (back-to-indentation)
+ (if (= containing-sexp (point))
+ (c-add-syntax tmpsymbol (point))
+ (goto-char (cdr placeholder))
+ (back-to-indentation)
+ (c-add-stmt-syntax tmpsymbol nil t nil
+ (c-most-enclosing-brace paren-state (point))
+ (c-whack-state-after (point) paren-state))
+ (if (/= (point) (cdr placeholder))
+ (c-add-syntax (car placeholder)))))
+ ;; CASE 16B: does this close an inline or a function in
+ ;; a non-class declaration level block?
+ ((setq placeholder (c-search-uplist-for-classkey paren-state))
+ (c-backward-to-decl-anchor lim)
+ (back-to-indentation)
+ (if (save-excursion
+ (goto-char (aref placeholder 0))
+ (looking-at c-other-decl-block-key))
+ (c-add-syntax 'defun-close (point))
+ (c-add-syntax 'inline-close (point))))
+ ;; CASE 16F: Can be a defun-close of a function declared
+ ;; in a statement block, e.g. in Pike or when using gcc
+ ;; extensions. Might also trigger it with some macros
+ ;; followed by blocks, and this gives sane indentation
+ ;; then too. Let it through to be handled below.
+ ;; C.f. cases B.3 and 17G.
+ ((and (not inenclosing-p)
+ lim
+ (save-excursion
+ (and (not (c-looking-at-bos))
+ (eq (c-beginning-of-statement-1 lim nil nil t) 'same)
+ (setq placeholder (point)))))
+ (back-to-indentation)
+ (if (/= (point) containing-sexp)
+ (goto-char placeholder))
+ (c-add-stmt-syntax 'defun-close nil t nil
+ lim paren-state))
+ ;; CASE 16C: if there an enclosing brace that hasn't
+ ;; been narrowed out by a class, then this is a
+ ;; block-close. C.f. case 17H.
+ ((and (not inenclosing-p) lim)
+ ;; If the block is preceded by a case/switch label on
+ ;; the same line, we anchor at the first preceding label
+ ;; at boi. The default handling in c-add-stmt-syntax is
+ ;; really fixes it better, but we do like this to keep
+ ;; the indentation compatible with version 5.28 and
+ ;; earlier.
+ (while (and (/= (setq placeholder (point)) (c-point 'boi))
+ (eq (c-beginning-of-statement-1 lim) 'label)))
+ (goto-char placeholder)
+ (if (looking-at c-label-kwds-regexp)
+ (c-add-syntax 'block-close (point))
+ (goto-char containing-sexp)
+ ;; c-backward-to-block-anchor not necessary here; those
+ ;; situations are handled in case 16E above.
+ (c-add-stmt-syntax 'block-close nil t nil
+ lim paren-state)))
+ ;; CASE 16D: find out whether we're closing a top-level
+ ;; class or a defun
+ (t
+ (save-restriction
+ (narrow-to-region (point-min) indent-point)
+ (let ((decl (c-search-uplist-for-classkey (c-parse-state))))
+ (if decl
+ (c-add-class-syntax 'class-close decl paren-state)
+ (goto-char containing-sexp)
+ (c-backward-to-decl-anchor lim)
+ (back-to-indentation)
+ (c-add-syntax 'defun-close (point)))))
+ )))
+ ;; CASE 17: Statement or defun catchall.
+ (t
+ (goto-char indent-point)
+ ;; Back up statements until we find one that starts at boi.
+ (while (let* ((prev-point (point))
+ (last-step-type (c-beginning-of-statement-1
+ containing-sexp)))
+ (if (= (point) prev-point)
+ (progn
+ (setq step-type (or step-type last-step-type))
+ nil)
+ (setq step-type last-step-type)
+ (/= (point) (c-point 'boi)))))
+ (cond
+ ;; CASE 17B: continued statement
+ ((and (eq step-type 'same)
+ (/= (point) indent-point))
+ (c-add-stmt-syntax 'statement-cont nil nil nil
+ containing-sexp paren-state))
+ ;; CASE 17A: After a case/default label?
+ ((progn
+ (while (and (eq step-type 'label)
+ (not (looking-at c-label-kwds-regexp)))
+ (setq step-type
+ (c-beginning-of-statement-1 containing-sexp)))
+ (eq step-type 'label))
+ (c-add-stmt-syntax (if (eq char-after-ip ?{)
+ 'statement-case-open
+ 'statement-case-intro)
+ nil t nil containing-sexp paren-state))
+ ;; CASE 17D: any old statement
+ ((progn
+ (while (eq step-type 'label)
+ (setq step-type
+ (c-beginning-of-statement-1 containing-sexp)))
+ (eq step-type 'previous))
+ (c-add-stmt-syntax 'statement nil t nil
+ containing-sexp paren-state)
+ (if (eq char-after-ip ?{)
+ (c-add-syntax 'block-open)))
+ ;; CASE 17I: Inside a substatement block.
+ ((progn
+ ;; The following tests are all based on containing-sexp.
+ (goto-char containing-sexp)
+ ;; From here on we have the next containing sexp in lim.
+ (setq lim (c-most-enclosing-brace paren-state containing-sexp))
+ (c-after-conditional))
+ (c-backward-to-block-anchor lim)
+ (c-add-stmt-syntax 'statement-block-intro nil t nil
+ lim paren-state)
+ (if (eq char-after-ip ?{)
+ (c-add-syntax 'block-open)))
+ ;; CASE 17E: first statement in an in-expression block.
+ ;; C.f. cases 4, 7B and 16A.
+ ((setq placeholder (c-looking-at-inexpr-block
+ (c-safe-position containing-sexp paren-state)
+ nil))
+ (setq tmpsymbol (if (eq (car placeholder) 'inlambda)
+ 'defun-block-intro
+ 'statement-block-intro))
+ (back-to-indentation)
+ (if (= containing-sexp (point))
+ (c-add-syntax tmpsymbol (point))
+ (goto-char (cdr placeholder))
+ (back-to-indentation)
+ (c-add-stmt-syntax tmpsymbol nil t nil
+ (c-most-enclosing-brace c-state-cache (point))
+ (c-whack-state-after (point) paren-state))
+ (if (/= (point) (cdr placeholder))
+ (c-add-syntax (car placeholder))))
+ (if (eq char-after-ip ?{)
+ (c-add-syntax 'block-open)))
+ ;; CASE 17F: first statement in an inline, or first
+ ;; statement in a top-level defun. we can tell this is it
+ ;; if there are no enclosing braces that haven't been
+ ;; narrowed out by a class (i.e. don't use bod here).
+ ((save-excursion
+ (save-restriction
+ (widen)
+ (c-narrow-out-enclosing-class paren-state containing-sexp)
+ (not (c-most-enclosing-brace paren-state))))
+ (c-backward-to-decl-anchor lim)
+ (back-to-indentation)
+ (c-add-syntax 'defun-block-intro (point)))
+ ;; CASE 17G: First statement in a function declared inside
+ ;; a normal block. This can occur in Pike and with
+ ;; e.g. the gcc extensions. Might also trigger it with
+ ;; some macros followed by blocks, and this gives sane
+ ;; indentation then too. C.f. cases B.3 and 16F.
+ ((save-excursion
+ (and (not (c-looking-at-bos))
+ (eq (c-beginning-of-statement-1 lim nil nil t) 'same)
+ (setq placeholder (point))))
+ (back-to-indentation)
+ (if (/= (point) containing-sexp)
+ (goto-char placeholder))
+ (c-add-stmt-syntax 'defun-block-intro nil t nil
+ lim paren-state))
+ ;; CASE 17H: First statement in a block. C.f. case 16C.
+ (t
+ ;; If the block is preceded by a case/switch label on the
+ ;; same line, we anchor at the first preceding label at
+ ;; boi. The default handling in c-add-stmt-syntax is
+ ;; really fixes it better, but we do like this to keep the
+ ;; indentation compatible with version 5.28 and earlier.
+ (while (and (/= (setq placeholder (point)) (c-point 'boi))
+ (eq (c-beginning-of-statement-1 lim) 'label)))
+ (goto-char placeholder)
+ (if (looking-at c-label-kwds-regexp)
+ (c-add-syntax 'statement-block-intro (point))
+ (goto-char containing-sexp)
+ ;; c-backward-to-block-anchor not necessary here; those
+ ;; situations are handled in case 17I above.
+ (c-add-stmt-syntax 'statement-block-intro nil t nil
+ lim paren-state))
+ (if (eq char-after-ip ?{)
+ (c-add-syntax 'block-open)))
+ ))
+ )
+ ;; now we need to look at any modifiers
+ (goto-char indent-point)
+ (skip-chars-forward " \t")
+ ;; are we looking at a comment only line?
+ (when (and (looking-at c-comment-start-regexp)
+ (/= (c-forward-token-2 0 nil (c-point 'eol)) 0))
+ (c-append-syntax 'comment-intro))
+ ;; we might want to give additional offset to friends (in C++).
+ (when (and c-opt-friend-key
+ (looking-at c-opt-friend-key))
+ (c-append-syntax 'friend))
+
+ ;; Set syntactic-relpos.
+ (let ((p c-syntactic-context))
+ (while (and p
+ (if (integerp (car-safe (cdr-safe (car p))))
+ (progn
+ (setq syntactic-relpos (car (cdr (car p))))
+ nil)
+ t))
+ (setq p (cdr p))))
+
+ ;; Start of or a continuation of a preprocessor directive?
+ (if (and macro-start
+ (eq macro-start (c-point 'boi))
+ (not (and (c-major-mode-is 'pike-mode)
+ (eq (char-after (1+ macro-start)) ?\"))))
+ (c-append-syntax 'cpp-macro)
+ (when (and c-syntactic-indentation-in-macros macro-start)
+ (if in-macro-expr
+ (when (or
+ (< syntactic-relpos macro-start)
+ (not (or
+ (assq 'arglist-intro c-syntactic-context)
+ (assq 'arglist-cont c-syntactic-context)
+ (assq 'arglist-cont-nonempty c-syntactic-context)
+ (assq 'arglist-close c-syntactic-context))))
+ ;; If inside a cpp expression, i.e. anywhere in a
+ ;; cpp directive except a #define body, we only let
+ ;; through the syntactic analysis that is internal
+ ;; in the expression. That means the arglist
+ ;; elements, if they are anchored inside the cpp
+ ;; expression.
+ (setq c-syntactic-context nil)
+ (c-add-syntax 'cpp-macro-cont macro-start))
+ (when (and (eq macro-start syntactic-relpos)
+ (not (assq 'cpp-define-intro c-syntactic-context))
+ (save-excursion
+ (goto-char macro-start)
+ (or (not (c-forward-to-cpp-define-body))
+ (<= (point) (c-point 'boi indent-point)))))
+ ;; Inside a #define body and the syntactic analysis is
+ ;; anchored on the start of the #define. In this case
+ ;; we add cpp-define-intro to get the extra
+ ;; indentation of the #define body.
+ (c-add-syntax 'cpp-define-intro)))))
+ ;; return the syntax
+ c-syntactic-context)))))
+ ((>= (string-to-number c-version) 5.29)
+ (defun c-guess-basic-syntax ()
+ "Return the syntactic context of the current line."
+ (save-excursion
+ (save-restriction
+ (beginning-of-line)
+ (let* ((indent-point (point))
+ (case-fold-search nil)
+ (paren-state (c-parse-state))
+ literal containing-sexp char-before-ip char-after-ip lim
+ syntax placeholder c-in-literal-cache step-type
+ tmpsymbol keyword injava-inher special-brace-list
+ ;; narrow out any enclosing class or extern "C" block
+ (inclass-p (c-narrow-out-enclosing-class paren-state
+ indent-point))
+ ;; c-state-cache is shadowed here. That means we must
+ ;; not do any changes during the execution of this
+ ;; function, since c-check-state-cache then would change
+ ;; this local variable and leave a bogus value in the
+ ;; global one.
+ (c-state-cache (if inclass-p
+ (c-whack-state-before (point-min) paren-state)
+ paren-state))
+ (c-state-cache-start (point-min))
+ inenclosing-p macro-start in-macro-expr
+ ;; There's always at most one syntactic element which got
+ ;; a relpos. It's stored in syntactic-relpos.
+ syntactic-relpos
+ (c-stmt-delim-chars c-stmt-delim-chars))
+ ;; check for meta top-level enclosing constructs, possible
+ ;; extern language definitions, possibly (in C++) namespace
+ ;; definitions.
+ (save-excursion
+ (save-restriction
+ (widen)
+ (if (and inclass-p
+ (progn
+ (goto-char (aref inclass-p 0))
+ (looking-at c-other-decl-block-key)))
+ (let ((enclosing (match-string 1)))
+ (cond
+ ((string-equal enclosing "extern")
+ (setq inenclosing-p 'extern))
+ ((string-equal enclosing "namespace")
+ (setq inenclosing-p 'namespace))
+ )))))
+
+ ;; Init some position variables:
+ ;;
+ ;; containing-sexp is the open paren of the closest
+ ;; surrounding sexp or nil if there is none that hasn't been
+ ;; narrowed out.
+ ;;
+ ;; lim is the position after the closest preceding brace sexp
+ ;; (nested sexps are ignored), or the position after
+ ;; containing-sexp if there is none, or (point-min) if
+ ;; containing-sexp is nil.
+ ;;
+ ;; c-state-cache is the state from c-parse-state at
+ ;; indent-point, without any parens outside the region
+ ;; narrowed by c-narrow-out-enclosing-class.
+ ;;
+ ;; paren-state is the state from c-parse-state outside
+ ;; containing-sexp, or at indent-point if containing-sexp is
+ ;; nil. paren-state is not limited to the narrowed region, as
+ ;; opposed to c-state-cache.
+ (if c-state-cache
+ (progn
+ (setq containing-sexp (car paren-state)
+ paren-state (cdr paren-state))
+ (if (consp containing-sexp)
+ (progn
+ (setq lim (cdr containing-sexp))
+ (if (cdr c-state-cache)
+ ;; Ignore balanced paren. The next entry
+ ;; can't be another one.
+ (setq containing-sexp (car (cdr c-state-cache))
+ paren-state (cdr paren-state))
+ ;; If there is no surrounding open paren then
+ ;; put the last balanced pair back on paren-state.
+ (setq paren-state (cons containing-sexp paren-state)
+ containing-sexp nil)))
+ (setq lim (1+ containing-sexp))))
+ (setq lim (point-min)))
+
+ ;; If we're in a parenthesis list then ',' delimits the
+ ;; "statements" rather than being an operator (with the
+ ;; exception of the "for" clause). This difference is
+ ;; typically only noticeable when statements are used in macro
+ ;; arglists.
+ (when (and containing-sexp
+ (eq (char-after containing-sexp) ?\())
+ (setq c-stmt-delim-chars c-stmt-delim-chars-with-comma))
+
+ ;; cache char before and after indent point, and move point to
+ ;; the most likely position to perform the majority of tests
+ (goto-char indent-point)
+ (c-backward-syntactic-ws lim)
+ (setq char-before-ip (char-before))
+ (goto-char indent-point)
+ (skip-chars-forward " \t")
+ (setq char-after-ip (char-after))
+
+ ;; are we in a literal?
+ (setq literal (c-in-literal lim))
+
+ ;; now figure out syntactic qualities of the current line
+ (cond
+ ;; CASE 1: in a string.
+ ((eq literal 'string)
+ (c-add-syntax 'string (c-point 'bopl)))
+ ;; CASE 2: in a C or C++ style comment.
+ ((memq literal '(c c++))
+ (c-add-syntax literal (car (c-literal-limits lim))))
+ ;; CASE 3: in a cpp preprocessor macro continuation.
+ ((and (save-excursion
+ (when (c-beginning-of-macro)
+ (setq macro-start (point))))
+ (/= macro-start (c-point 'boi))
+ (progn
+ (setq tmpsymbol 'cpp-macro-cont)
+ (or (not c-syntactic-indentation-in-macros)
+ (save-excursion
+ (goto-char macro-start)
+ ;; If at the beginning of the body of a #define
+ ;; directive then analyze as cpp-define-intro
+ ;; only. Go on with the syntactic analysis
+ ;; otherwise. in-macro-expr is set if we're in a
+ ;; cpp expression, i.e. before the #define body
+ ;; or anywhere in a non-#define directive.
+ (if (c-forward-to-cpp-define-body)
+ (let ((indent-boi (c-point 'boi indent-point)))
+ (setq in-macro-expr (> (point) indent-boi)
+ tmpsymbol 'cpp-define-intro)
+ (= (point) indent-boi))
+ (setq in-macro-expr t)
+ nil)))))
+ (c-add-syntax tmpsymbol macro-start)
+ (setq macro-start nil))
+ ;; CASE 11: an else clause?
+ ((looking-at "else\\>[^_]")
+ (c-beginning-of-statement-1 containing-sexp)
+ (c-add-stmt-syntax 'else-clause t containing-sexp paren-state))
+ ;; CASE 12: while closure of a do/while construct?
+ ((and (looking-at "while\\>[^_]")
+ (save-excursion
+ (prog1 (eq (c-beginning-of-statement-1 containing-sexp)
+ 'beginning)
+ (setq placeholder (point)))))
+ (goto-char placeholder)
+ (c-add-stmt-syntax 'do-while-closure t containing-sexp paren-state))
+ ;; CASE 13: A catch or finally clause? This case is simpler
+ ;; than if-else and do-while, because a block is required
+ ;; after every try, catch and finally.
+ ((save-excursion
+ (and (cond ((c-major-mode-is 'c++-mode)
+ (looking-at "catch\\>[^_]"))
+ ((c-major-mode-is 'java-mode)
+ (looking-at "\\(catch\\|finally\\)\\>[^_]")))
+ (and (c-safe (c-backward-syntactic-ws)
+ (c-backward-sexp)
+ t)
+ (eq (char-after) ?{)
+ (c-safe (c-backward-syntactic-ws)
+ (c-backward-sexp)
+ t)
+ (if (eq (char-after) ?\()
+ (c-safe (c-backward-sexp) t)
+ t))
+ (looking-at "\\(try\\|catch\\)\\>[^_]")
+ (setq placeholder (point))))
+ (goto-char placeholder)
+ (c-add-stmt-syntax 'catch-clause t containing-sexp paren-state))
+ ;; CASE 18: A substatement we can recognize by keyword.
+ ((save-excursion
+ (and c-opt-block-stmt-key
+ (not (eq char-before-ip ?\;))
+ (not (memq char-after-ip '(?\) ?\] ?,)))
+ (or (not (eq char-before-ip ?}))
+ (c-looking-at-inexpr-block-backward c-state-cache))
+ (> (point)
+ (progn
+ ;; Ought to cache the result from the
+ ;; c-beginning-of-statement-1 calls here.
+ (setq placeholder (point))
+ (while (eq (setq step-type
+ (c-beginning-of-statement-1 lim))
+ 'label))
+ (if (eq step-type 'previous)
+ (goto-char placeholder)
+ (setq placeholder (point))
+ (if (and (eq step-type 'same)
+ (not (looking-at c-opt-block-stmt-key)))
+ ;; Step up to the containing statement if we
+ ;; stayed in the same one.
+ (let (step)
+ (while (eq
+ (setq step
+ (c-beginning-of-statement-1 lim))
+ 'label))
+ (if (eq step 'up)
+ (setq placeholder (point))
+ ;; There was no containing statement afterall.
+ (goto-char placeholder)))))
+ placeholder))
+ (if (looking-at c-block-stmt-2-key)
+ ;; Require a parenthesis after these keywords.
+ ;; Necessary to catch e.g. synchronized in Java,
+ ;; which can be used both as statement and
+ ;; modifier.
+ (and (= (c-forward-token-1 1 nil) 0)
+ (eq (char-after) ?\())
+ (looking-at c-opt-block-stmt-key))))
+ (if (eq step-type 'up)
+ ;; CASE 18A: Simple substatement.
+ (progn
+ (goto-char placeholder)
+ (cond
+ ((eq char-after-ip ?{)
+ (c-add-stmt-syntax 'substatement-open nil
+ containing-sexp paren-state))
+ ((save-excursion
+ (goto-char indent-point)
+ (back-to-indentation)
+ (looking-at c-label-key))
+ (c-add-stmt-syntax 'substatement-label nil
+ containing-sexp paren-state))
+ (t
+ (c-add-stmt-syntax 'substatement nil
+ containing-sexp paren-state))))
+ ;; CASE 18B: Some other substatement. This is shared
+ ;; with case 10.
+ (c-guess-continued-construct indent-point
+ char-after-ip
+ placeholder
+ lim
+ paren-state)))
+ ;; CASE 4: In-expression statement. C.f. cases 7B, 16A and
+ ;; 17E.
+ ((and (or c-opt-inexpr-class-key
+ c-opt-inexpr-block-key
+ c-opt-lambda-key)
+ (setq placeholder (c-looking-at-inexpr-block
+ (c-safe-position containing-sexp paren-state)
+ containing-sexp)))
+ (setq tmpsymbol (assq (car placeholder)
+ '((inexpr-class . class-open)
+ (inexpr-statement . block-open))))
+ (if tmpsymbol
+ ;; It's a statement block or an anonymous class.
+ (setq tmpsymbol (cdr tmpsymbol))
+ ;; It's a Pike lambda. Check whether we are between the
+ ;; lambda keyword and the argument list or at the defun
+ ;; opener.
+ (setq tmpsymbol (if (eq char-after-ip ?{)
+ 'inline-open
+ 'lambda-intro-cont)))
+ (goto-char (cdr placeholder))
+ (back-to-indentation)
+ (c-add-stmt-syntax tmpsymbol t
+ (c-most-enclosing-brace c-state-cache (point))
+ (c-whack-state-after (point) paren-state))
+ (unless (eq (point) (cdr placeholder))
+ (c-add-syntax (car placeholder))))
+ ;; CASE 5: Line is at top level.
+ ((null containing-sexp)
+ (cond
+ ;; CASE 5A: we are looking at a defun, brace list, class,
+ ;; or inline-inclass method opening brace
+ ((setq special-brace-list
+ (or (and c-special-brace-lists
+ (c-looking-at-special-brace-list))
+ (eq char-after-ip ?{)))
+ (cond
+ ;; CASE 5A.1: extern language or namespace construct
+ ((save-excursion
+ (goto-char indent-point)
+ (skip-chars-forward " \t")
+ (and (c-safe (progn (c-backward-sexp 2) t))
+ (looking-at c-other-decl-block-key)
+ (setq keyword (match-string 1)
+ placeholder (point))
+ (or (and (string-equal keyword "namespace")
+ (setq tmpsymbol 'namespace-open))
+ (and (string-equal keyword "extern")
+ (progn
+ (c-forward-sexp 1)
+ (c-forward-syntactic-ws)
+ (eq (char-after) ?\"))
+ (setq tmpsymbol 'extern-lang-open)))
+ ))
+ (goto-char placeholder)
+ (c-add-syntax tmpsymbol (c-point 'boi)))
+ ;; CASE 5A.2: we are looking at a class opening brace
+ ((save-excursion
+ (goto-char indent-point)
+ (skip-chars-forward " \t{")
+ (let ((decl (c-search-uplist-for-classkey (c-parse-state))))
+ (and decl
+ (setq placeholder (aref decl 0)))
+ ))
+ (c-add-syntax 'class-open placeholder))
+ ;; CASE 5A.3: brace list open
+ ((save-excursion
+ (c-beginning-of-decl-1 lim)
+ (if (looking-at "typedef\\>[^_]")
+ (progn (c-forward-sexp 1)
+ (c-forward-syntactic-ws indent-point)))
+ (setq placeholder (c-point 'boi))
+ (or (consp special-brace-list)
+ (and (or (save-excursion
+ (goto-char indent-point)
+ (setq tmpsymbol nil)
+ (while (and (> (point) placeholder)
+ (= (c-backward-token-1 1 t) 0)
+ (/= (char-after) ?=))
+ (if (and (not tmpsymbol)
+ (looking-at "new\\>[^_]"))
+ (setq tmpsymbol 'topmost-intro-cont)))
+ (eq (char-after) ?=))
+ (looking-at "enum\\>[^_]"))
+ (save-excursion
+ (while (and (< (point) indent-point)
+ (= (c-forward-token-1 1 t) 0)
+ (not (memq (char-after) '(?\; ?\()))))
+ (not (memq (char-after) '(?\; ?\()))
+ ))))
+ (if (and (c-major-mode-is 'java-mode)
+ (eq tmpsymbol 'topmost-intro-cont))
+ ;; We're in Java and have found that the open brace
+ ;; belongs to a "new Foo[]" initialization list,
+ ;; which means the brace list is part of an
+ ;; expression and not a top level definition. We
+ ;; therefore treat it as any topmost continuation
+ ;; even though the semantically correct symbol still
+ ;; is brace-list-open, on the same grounds as in
+ ;; case 10B.2.
+ (progn
+ (c-beginning-of-statement-1 lim)
+ (c-add-syntax 'topmost-intro-cont (c-point 'boi)))
+ (c-add-syntax 'brace-list-open placeholder)))
+ ;; CASE 5A.4: inline defun open
+ ((and inclass-p (not inenclosing-p))
+ (c-add-syntax 'inline-open)
+ (c-add-class-syntax 'inclass inclass-p paren-state))
+ ;; CASE 5A.5: ordinary defun open
+ (t
+ (goto-char placeholder)
+ (if (or inclass-p macro-start)
+ (c-add-syntax 'defun-open (c-point 'boi))
+ ;; Bogus to use bol here, but it's the legacy.
+ (c-add-syntax 'defun-open (c-point 'bol)))
+ )))
+ ;; CASE 5B: first K&R arg decl or member init
+ ((c-just-after-func-arglist-p nil lim)
+ (cond
+ ;; CASE 5B.1: a member init
+ ((or (eq char-before-ip ?:)
+ (eq char-after-ip ?:))
+ ;; this line should be indented relative to the beginning
+ ;; of indentation for the topmost-intro line that contains
+ ;; the prototype's open paren
+ ;; TBD: is the following redundant?
+ (if (eq char-before-ip ?:)
+ (forward-char -1))
+ (c-backward-syntactic-ws lim)
+ ;; TBD: is the preceding redundant?
+ (if (eq (char-before) ?:)
+ (progn (forward-char -1)
+ (c-backward-syntactic-ws lim)))
+ (if (eq (char-before) ?\))
+ (c-backward-sexp 1))
+ (setq placeholder (point))
+ (save-excursion
+ (and (c-safe (c-backward-sexp 1) t)
+ (looking-at "throw[^_]")
+ (c-safe (c-backward-sexp 1) t)
+ (setq placeholder (point))))
+ (goto-char placeholder)
+ (c-add-syntax 'member-init-intro (c-point 'boi))
+ ;; we don't need to add any class offset since this
+ ;; should be relative to the ctor's indentation
+ )
+ ;; CASE 5B.2: K&R arg decl intro
+ (c-recognize-knr-p
+ (c-beginning-of-statement-1 lim)
+ (c-add-syntax 'knr-argdecl-intro (c-point 'boi))
+ (if inclass-p
+ (c-add-class-syntax 'inclass inclass-p paren-state)))
+ ;; CASE 5B.3: Inside a member init list.
+ ((c-beginning-of-member-init-list lim)
+ (c-forward-syntactic-ws)
+ (c-add-syntax 'member-init-cont (point)))
+ ;; CASE 5B.4: Nether region after a C++ or Java func
+ ;; decl, which could include a `throws' declaration.
+ (t
+ (c-beginning-of-statement-1 lim)
+ (c-add-syntax 'func-decl-cont (c-point 'boi))
+ )))
+ ;; CASE 5C: inheritance line. could be first inheritance
+ ;; line, or continuation of a multiple inheritance
+ ((or (and (c-major-mode-is 'c++-mode)
+ (progn
+ (when (eq char-after-ip ?,)
+ (skip-chars-forward " \t")
+ (forward-char))
+ (looking-at c-opt-decl-spec-key)))
+ (and (or (eq char-before-ip ?:)
+ ;; watch out for scope operator
+ (save-excursion
+ (and (eq char-after-ip ?:)
+ (c-safe (progn (forward-char 1) t))
+ (not (eq (char-after) ?:))
+ )))
+ (save-excursion
+ (c-backward-syntactic-ws lim)
+ (if (eq char-before-ip ?:)
+ (progn
+ (forward-char -1)
+ (c-backward-syntactic-ws lim)))
+ (back-to-indentation)
+ (looking-at c-class-key)))
+ ;; for Java
+ (and (c-major-mode-is 'java-mode)
+ (let ((fence (save-excursion
+ (c-beginning-of-statement-1 lim)
+ (point)))
+ cont done)
+ (save-excursion
+ (while (not done)
+ (cond ((looking-at c-opt-decl-spec-key)
+ (setq injava-inher (cons cont (point))
+ done t))
+ ((or (not (c-safe (c-forward-sexp -1) t))
+ (<= (point) fence))
+ (setq done t))
+ )
+ (setq cont t)))
+ injava-inher)
+ (not (c-crosses-statement-barrier-p (cdr injava-inher)
+ (point)))
+ ))
+ (cond
+ ;; CASE 5C.1: non-hanging colon on an inher intro
+ ((eq char-after-ip ?:)
+ (c-beginning-of-statement-1 lim)
+ (c-add-syntax 'inher-intro (c-point 'boi))
+ ;; don't add inclass symbol since relative point already
+ ;; contains any class offset
+ )
+ ;; CASE 5C.2: hanging colon on an inher intro
+ ((eq char-before-ip ?:)
+ (c-beginning-of-statement-1 lim)
+ (c-add-syntax 'inher-intro (c-point 'boi))
+ (if inclass-p
+ (c-add-class-syntax 'inclass inclass-p paren-state)))
+ ;; KDE Hack Start:
+ ((and inclass-p
+ c-access-key
+ (looking-at c-access-key))
+ (c-add-syntax 'access-label (c-point 'bonl))
+ (setq placeholder (c-add-class-syntax 'inclass inclass-p
+ paren-state)))
+ ;;(nconc syntax (list (cons 'access-label placeholder))))
+ ;; KDE Hack End.
+ ;; CASE 5C.3: in a Java implements/extends
+ (injava-inher
+ (let ((where (cdr injava-inher))
+ (cont (car injava-inher)))
+ (goto-char where)
+ (cond ((looking-at "throws\\>[^_]")
+ (c-add-syntax 'func-decl-cont
+ (progn (c-beginning-of-statement-1 lim)
+ (c-point 'boi))))
+ (cont (c-add-syntax 'inher-cont where))
+ (t (c-add-syntax 'inher-intro
+ (progn (goto-char (cdr injava-inher))
+ (c-beginning-of-statement-1 lim)
+ (point))))
+ )))
+ ;; CASE 5C.4: a continued inheritance line
+ (t
+ (c-beginning-of-inheritance-list lim)
+ (c-add-syntax 'inher-cont (point))
+ ;; don't add inclass symbol since relative point already
+ ;; contains any class offset
+ )))
+ ;; CASE 5D: this could be a top-level initialization, a
+ ;; member init list continuation, or a template argument
+ ;; list continuation.
+ ((c-with-syntax-table (if (c-major-mode-is 'c++-mode)
+ c++-template-syntax-table
+ (syntax-table))
+ (save-excursion
+ ;; Note: We use the fact that lim is always after any
+ ;; preceding brace sexp.
+ (while (and (= (c-backward-token-1 1 t lim) 0)
+ (not (looking-at "[;<,=]"))))
+ (or (memq (char-after) '(?, ?=))
+ (and (c-major-mode-is 'c++-mode)
+ (= (c-backward-token-1 1 nil lim) 0)
+ (eq (char-after) ?<)))))
+ (goto-char indent-point)
+ (c-beginning-of-member-init-list lim)
+ (cond
+ ;; CASE 5D.1: hanging member init colon, but watch out
+ ;; for bogus matches on access specifiers inside classes.
+ ((and (save-excursion
+ (setq placeholder (point))
+ (c-backward-token-1 1 t lim)
+ (and (eq (char-after) ?:)
+ (not (eq (char-before) ?:))))
+ (save-excursion
+ (goto-char placeholder)
+ (back-to-indentation)
+ (or
+ (/= (car (save-excursion
+ (parse-partial-sexp (point) placeholder)))
+ 0)
+ (and
+ (if c-opt-access-key
+ (not (looking-at c-opt-access-key)) t)
+ (not (looking-at c-class-key))
+ (if c-opt-bitfield-key
+ (not (looking-at c-opt-bitfield-key)) t))
+ )))
+ (goto-char placeholder)
+ (c-forward-syntactic-ws)
+ (c-add-syntax 'member-init-cont (point))
+ ;; we do not need to add class offset since relative
+ ;; point is the member init above us
+ )
+ ;; CASE 5D.2: non-hanging member init colon
+ ((progn
+ (c-forward-syntactic-ws indent-point)
+ (eq (char-after) ?:))
+ (skip-chars-forward " \t:")
+ (c-add-syntax 'member-init-cont (point)))
+ ;; CASE 5D.3: perhaps a template list continuation?
+ ((and (c-major-mode-is 'c++-mode)
+ (save-excursion
+ (save-restriction
+ (c-with-syntax-table c++-template-syntax-table
+ (goto-char indent-point)
+ (setq placeholder (c-up-list-backward (point)))
+ (and placeholder
+ (eq (char-after placeholder) ?<))))))
+ ;; we can probably indent it just like an arglist-cont
+ (goto-char placeholder)
+ (c-beginning-of-statement-1 lim t)
+ (c-add-syntax 'template-args-cont (c-point 'boi)))
+ ;; CASE 5D.4: perhaps a multiple inheritance line?
+ ((and (c-major-mode-is 'c++-mode)
+ (save-excursion
+ (c-beginning-of-statement-1 lim)
+ (setq placeholder (point))
+ (if (looking-at "static\\>[^_]")
+ (c-forward-token-1 1 nil indent-point))
+ (and (looking-at c-class-key)
+ (= (c-forward-token-1 2 nil indent-point) 0)
+ (if (eq (char-after) ?<)
+ (c-with-syntax-table c++-template-syntax-table
+ (= (c-forward-token-1 1 t indent-point) 0))
+ t)
+ (eq (char-after) ?:))))
+ (goto-char placeholder)
+ (c-add-syntax 'inher-cont (c-point 'boi)))
+ ;; CASE 5D.5: Continuation of the "expression part" of a
+ ;; top level construct.
+ (t
+ (while (and (eq (car (c-beginning-of-decl-1 containing-sexp))
+ 'same)
+ (save-excursion
+ (c-backward-syntactic-ws)
+ (eq (char-before) ?}))))
+ (c-add-stmt-syntax
+ (if (eq char-before-ip ?,)
+ ;; A preceding comma at the top level means that a
+ ;; new variable declaration starts here. Use
+ ;; topmost-intro-cont for it, for consistency with
+ ;; the first variable declaration. C.f. case 5N.
+ 'topmost-intro-cont
+ 'statement-cont)
+ nil containing-sexp paren-state))
+ ))
+ ;; CASE 5E: we are looking at a access specifier
+ ((and inclass-p
+ c-opt-access-key
+ (looking-at c-opt-access-key))
+ (setq placeholder (c-add-class-syntax 'inclass inclass-p
+ paren-state))
+ ;; Append access-label with the same anchor point as inclass gets.
+ (nconc syntax (list (cons 'access-label placeholder))))
+ ;; CASE 5F: extern-lang-close or namespace-close?
+ ((and inenclosing-p
+ (eq char-after-ip ?}))
+ (setq tmpsymbol (if (eq inenclosing-p 'extern)
+ 'extern-lang-close
+ 'namespace-close))
+ (c-add-syntax tmpsymbol (aref inclass-p 0)))
+ ;; CASE 5G: we are looking at the brace which closes the
+ ;; enclosing nested class decl
+ ((and inclass-p
+ (eq char-after-ip ?})
+ (save-excursion
+ (save-restriction
+ (widen)
+ (forward-char 1)
+ (and (c-safe (progn (c-backward-sexp 1) t))
+ (= (point) (aref inclass-p 1))
+ ))))
+ (c-add-class-syntax 'class-close inclass-p paren-state))
+ ;; CASE 5H: we could be looking at subsequent knr-argdecls
+ ((and c-recognize-knr-p
+ (not (eq char-before-ip ?}))
+ (save-excursion
+ (setq placeholder (cdr (c-beginning-of-decl-1 lim)))
+ (and placeholder
+ ;; Do an extra check to avoid tripping up on
+ ;; statements that occur in invalid contexts
+ ;; (e.g. in macro bodies where we don't really
+ ;; know the context of what we're looking at).
+ (not (and c-opt-block-stmt-key
+ (looking-at c-opt-block-stmt-key)))))
+ (< placeholder indent-point))
+ (goto-char placeholder)
+ (c-add-syntax 'knr-argdecl (point)))
+ ;; CASE 5I: ObjC method definition.
+ ((and c-opt-method-key
+ (looking-at c-opt-method-key))
+ (c-beginning-of-statement-1 lim)
+ (c-add-syntax 'objc-method-intro (c-point 'boi)))
+ ;; CASE 5N: At a variable declaration that follows a class
+ ;; definition or some other block declaration that doesn't
+ ;; end at the closing '}'. C.f. case 5D.5.
+ ((progn
+ (c-backward-syntactic-ws lim)
+ (and (eq (char-before) ?})
+ (save-excursion
+ (let ((start (point)))
+ (if paren-state
+ ;; Speed up the backward search a bit.
+ (goto-char (car (car paren-state))))
+ (c-beginning-of-decl-1 containing-sexp)
+ (setq placeholder (point))
+ (if (= start (point))
+ ;; The '}' is unbalanced.
+ nil
+ (c-end-of-decl-1)
+ (> (point) indent-point))))))
+ (goto-char placeholder)
+ (c-add-stmt-syntax 'topmost-intro-cont nil
+ containing-sexp paren-state))
+ ;; CASE 5J: we are at the topmost level, make
+ ;; sure we skip back past any access specifiers
+ ((progn
+ (while (and inclass-p
+ c-opt-access-key
+ (not (bobp))
+ (save-excursion
+ (c-safe (progn (c-backward-sexp 1) t))
+ (and (looking-at "slots:")
+ (c-backward-sexp 1))
+ (looking-at c-opt-access-key)))
+ (c-backward-sexp 1)
+ (c-backward-syntactic-ws lim))
+ (or (bobp)
+ (memq (char-before) '(?\; ?}))
+ (and (c-major-mode-is 'objc-mode)
+ (progn
+ (c-beginning-of-statement-1 lim)
+ (eq (char-after) ?@)))))
+ ;; real beginning-of-line could be narrowed out due to
+ ;; enclosure in a class block
+ (save-restriction
+ (widen)
+ (c-add-syntax 'topmost-intro (c-point 'bol))
+ ;; Using bol instead of boi above is highly bogus, and
+ ;; it makes our lives hard to remain compatible. :P
+ (if inclass-p
+ (progn
+ (goto-char (aref inclass-p 1))
+ (or (= (point) (c-point 'boi))
+ (goto-char (aref inclass-p 0)))
+ (cond
+ ((eq inenclosing-p 'extern)
+ (c-add-syntax 'inextern-lang (c-point 'boi)))
+ ((eq inenclosing-p 'namespace)
+ (c-add-syntax 'innamespace (c-point 'boi)))
+ (t (c-add-class-syntax 'inclass inclass-p paren-state)))
+ ))
+ (when (and c-syntactic-indentation-in-macros
+ macro-start
+ (/= macro-start (c-point 'boi indent-point)))
+ (c-add-syntax 'cpp-define-intro)
+ (setq macro-start nil))
+ ))
+ ;; CASE 5K: we are at an ObjC method definition
+ ;; continuation line.
+ ((and c-opt-method-key
+ (progn
+ (c-beginning-of-statement-1 lim)
+ (beginning-of-line)
+ (looking-at c-opt-method-key)))
+ (c-add-syntax 'objc-method-args-cont (point)))
+ ;; CASE 5L: we are at the first argument of a template
+ ;; arglist that begins on the previous line.
+ ((eq (char-before) ?<)
+ (c-beginning-of-statement-1 (c-safe-position (point) paren-state))
+ (c-add-syntax 'template-args-cont (c-point 'boi)))
+ ;; CASE 5M: we are at a topmost continuation line
+ ;; KDE Hack 2
+ ;; NOTE: is there a way to detect these sooner ?
+ (t
+ (c-beginning-of-statement-1 (c-safe-position (point) paren-state))
+ (if (re-search-forward c-access-key (point-at-eol) t)
+ (progn
+ (c-add-syntax 'topmost-intro (c-point 'bol))
+ (c-add-class-syntax 'inclass inclass-p paren-state)
+ )
+ (progn
+ (c-add-syntax 'topmost-intro-cont (c-point 'boi))
+ ))
+ )
+ ))
+ ;; (CASE 6 has been removed.)
+ ;; CASE 7: line is an expression, not a statement. Most
+ ;; likely we are either in a function prototype or a function
+ ;; call argument list
+ ((not (or (and c-special-brace-lists
+ (save-excursion
+ (goto-char containing-sexp)
+ (c-looking-at-special-brace-list)))
+ (eq (char-after containing-sexp) ?{)))
+ (cond
+ ;; CASE 7A: we are looking at the arglist closing paren
+ ((memq char-after-ip '(?\) ?\]))
+ (goto-char containing-sexp)
+ (setq placeholder (c-point 'boi))
+ (when (and (c-safe (backward-up-list 1) t)
+ (> (point) placeholder))
+ (forward-char)
+ (skip-chars-forward " \t")
+ (setq placeholder (point)))
+ (c-add-syntax 'arglist-close placeholder))
+ ;; CASE 7B: Looking at the opening brace of an
+ ;; in-expression block or brace list. C.f. cases 4, 16A
+ ;; and 17E.
+ ((and (eq char-after-ip ?{)
+ (progn
+ (setq placeholder (c-inside-bracelist-p (point)
+ c-state-cache))
+ (if placeholder
+ (setq tmpsymbol '(brace-list-open . inexpr-class))
+ (setq tmpsymbol '(block-open . inexpr-statement)
+ placeholder
+ (cdr-safe (c-looking-at-inexpr-block
+ (c-safe-position containing-sexp
+ paren-state)
+ containing-sexp)))
+ ;; placeholder is nil if it's a block directly in
+ ;; a function arglist. That makes us skip out of
+ ;; this case.
+ )))
+ (goto-char placeholder)
+ (back-to-indentation)
+ (c-add-stmt-syntax (car tmpsymbol) t
+ (c-most-enclosing-brace paren-state (point))
+ (c-whack-state-after (point) paren-state))
+ (if (/= (point) placeholder)
+ (c-add-syntax (cdr tmpsymbol))))
+ ;; CASE 7C: we are looking at the first argument in an empty
+ ;; argument list. Use arglist-close if we're actually
+ ;; looking at a close paren or bracket.
+ ((memq char-before-ip '(?\( ?\[))
+ (goto-char containing-sexp)
+ (setq placeholder (c-point 'boi))
+ (when (and (c-safe (backward-up-list 1) t)
+ (> (point) placeholder))
+ (forward-char)
+ (skip-chars-forward " \t")
+ (setq placeholder (point)))
+ (c-add-syntax 'arglist-intro placeholder))
+ ;; CASE 7D: we are inside a conditional test clause. treat
+ ;; these things as statements
+ ((progn
+ (goto-char containing-sexp)
+ (and (c-safe (progn (c-forward-sexp -1) t))
+ (looking-at "\\<for\\>[^_]")))
+ (goto-char (1+ containing-sexp))
+ (c-forward-syntactic-ws indent-point)
+ (if (eq char-before-ip ?\;)
+ (c-add-syntax 'statement (point))
+ (c-add-syntax 'statement-cont (point))
+ ))
+ ;; CASE 7E: maybe a continued ObjC method call. This is the
+ ;; case when we are inside a [] bracketed exp, and what
+ ;; precede the opening bracket is not an identifier.
+ ((and c-opt-method-key
+ (eq (char-after containing-sexp) ?\[)
+ (progn
+ (goto-char (1- containing-sexp))
+ (c-backward-syntactic-ws (c-point 'bod))
+ (if (not (looking-at c-symbol-key))
+ (c-add-syntax 'objc-method-call-cont containing-sexp))
+ )))
+ ;; CASE 7F: we are looking at an arglist continuation line,
+ ;; but the preceding argument is on the same line as the
+ ;; opening paren. This case includes multi-line
+ ;; mathematical paren groupings, but we could be on a
+ ;; for-list continuation line
+ ((progn
+ (goto-char (1+ containing-sexp))
+ (skip-chars-forward " \t")
+ (and (not (eolp))
+ (not (looking-at "\\\\$"))))
+ (goto-char containing-sexp)
+ (setq placeholder (c-point 'boi))
+ (when (and (c-safe (backward-up-list 1) t)
+ (> (point) placeholder))
+ (forward-char)
+ (skip-chars-forward " \t")
+ (setq placeholder (point)))
+ (c-add-syntax 'arglist-cont-nonempty placeholder))
+ ;; CASE 7G: we are looking at just a normal arglist
+ ;; continuation line
+ (t (c-forward-syntactic-ws indent-point)
+ (c-add-syntax 'arglist-cont (c-point 'boi)))
+ ))
+ ;; CASE 8: func-local multi-inheritance line
+ ((and (c-major-mode-is 'c++-mode)
+ (save-excursion
+ (goto-char indent-point)
+ (skip-chars-forward " \t")
+ (looking-at c-opt-decl-spec-key)))
+ (goto-char indent-point)
+ (skip-chars-forward " \t")
+ (cond
+ ;; CASE 8A: non-hanging colon on an inher intro
+ ((eq char-after-ip ?:)
+ (c-backward-syntactic-ws lim)
+ (c-add-syntax 'inher-intro (c-point 'boi)))
+ ;; CASE 8B: hanging colon on an inher intro
+ ((eq char-before-ip ?:)
+ (c-add-syntax 'inher-intro (c-point 'boi)))
+ ;; CASE 8C: a continued inheritance line
+ (t
+ (c-beginning-of-inheritance-list lim)
+ (c-add-syntax 'inher-cont (point))
+ )))
+ ;; CASE 9: we are inside a brace-list
+ ((setq special-brace-list
+ (or (and c-special-brace-lists
+ (save-excursion
+ (goto-char containing-sexp)
+ (c-looking-at-special-brace-list)))
+ (c-inside-bracelist-p containing-sexp paren-state)))
+ (cond
+ ;; CASE 9A: In the middle of a special brace list opener.
+ ((and (consp special-brace-list)
+ (save-excursion
+ (goto-char containing-sexp)
+ (eq (char-after) ?\())
+ (eq char-after-ip (car (cdr special-brace-list))))
+ (goto-char (car (car special-brace-list)))
+ (skip-chars-backward " \t")
+ (if (and (bolp)
+ (assoc 'statement-cont
+ (setq placeholder (c-guess-basic-syntax))))
+ (setq syntax placeholder)
+ (c-beginning-of-statement-1
+ (c-safe-position (1- containing-sexp) paren-state))
+ (c-forward-token-1 0)
+ (if (looking-at "typedef\\>[^_]") (c-forward-token-1 1))
+ (c-add-syntax 'brace-list-open (c-point 'boi))))
+ ;; CASE 9B: brace-list-close brace
+ ((if (consp special-brace-list)
+ ;; Check special brace list closer.
+ (progn
+ (goto-char (car (car special-brace-list)))
+ (save-excursion
+ (goto-char indent-point)
+ (back-to-indentation)
+ (or
+ ;; We were between the special close char and the `)'.
+ (and (eq (char-after) ?\))
+ (eq (1+ (point)) (cdr (car special-brace-list))))
+ ;; We were before the special close char.
+ (and (eq (char-after) (cdr (cdr special-brace-list)))
+ (= (c-forward-token-1) 0)
+ (eq (1+ (point)) (cdr (car special-brace-list)))))))
+ ;; Normal brace list check.
+ (and (eq char-after-ip ?})
+ (c-safe (progn (goto-char (c-up-list-backward (point)))
+ t))
+ (= (point) containing-sexp)))
+ (if (eq (point) (c-point 'boi))
+ (c-add-syntax 'brace-list-close (point))
+ (setq lim (c-most-enclosing-brace c-state-cache (point)))
+ (c-beginning-of-statement-1 lim)
+ (c-add-stmt-syntax 'brace-list-close t lim
+ (c-whack-state-after (point) paren-state)
+ t)))
+ (t
+ ;; Prepare for the rest of the cases below by going to the
+ ;; token following the opening brace
+ (if (consp special-brace-list)
+ (progn
+ (goto-char (car (car special-brace-list)))
+ (c-forward-token-1 1 nil indent-point))
+ (goto-char containing-sexp))
+ (forward-char)
+ (let ((start (point)))
+ (c-forward-syntactic-ws indent-point)
+ (goto-char (max start (c-point 'bol))))
+ (c-skip-ws-forward indent-point)
+ (cond
+ ;; CASE 9C: we're looking at the first line in a brace-list
+ ((= (point) indent-point)
+ (if (consp special-brace-list)
+ (goto-char (car (car special-brace-list)))
+ (goto-char containing-sexp))
+ (if (eq (point) (c-point 'boi))
+ (c-add-syntax 'brace-list-intro (point))
+ (setq lim (c-most-enclosing-brace c-state-cache (point)))
+ (c-beginning-of-statement-1 lim)
+ (c-add-stmt-syntax 'brace-list-intro t lim
+ (c-whack-state-after (point) paren-state)
+ t)))
+ ;; CASE 9D: this is just a later brace-list-entry or
+ ;; brace-entry-open
+ (t (if (or (eq char-after-ip ?{)
+ (and c-special-brace-lists
+ (save-excursion
+ (goto-char indent-point)
+ (c-forward-syntactic-ws (c-point 'eol))
+ (c-looking-at-special-brace-list (point)))))
+ (c-add-syntax 'brace-entry-open (point))
+ (c-add-syntax 'brace-list-entry (point))
+ ))
+ ))))
+ ;; CASE 10: A continued statement or top level construct.
+ ((and (not (memq char-before-ip '(?\; ?:)))
+ (or (not (eq char-before-ip ?}))
+ (c-looking-at-inexpr-block-backward c-state-cache))
+ (> (point)
+ (save-excursion
+ (c-beginning-of-statement-1 containing-sexp)
+ (setq placeholder (point))))
+ (/= placeholder containing-sexp))
+ ;; This is shared with case 18.
+ (c-guess-continued-construct indent-point
+ char-after-ip
+ placeholder
+ containing-sexp
+ paren-state))
+ ;; CASE 14: A case or default label
+ ((looking-at c-label-kwds-regexp)
+ (goto-char containing-sexp)
+ (setq lim (c-most-enclosing-brace c-state-cache containing-sexp))
+ (c-backward-to-block-anchor lim)
+ (c-add-stmt-syntax 'case-label t lim paren-state))
+ ;; CASE 15: any other label
+ ((looking-at c-label-key)
+ (goto-char containing-sexp)
+ (setq lim (c-most-enclosing-brace c-state-cache containing-sexp))
+ (save-excursion
+ (setq tmpsymbol
+ (if (and (eq (c-beginning-of-statement-1 lim) 'up)
+ (looking-at "switch\\>[^_]"))
+ ;; If the surrounding statement is a switch then
+ ;; let's analyze all labels as switch labels, so
+ ;; that they get lined up consistently.
+ 'case-label
+ 'label)))
+ (c-backward-to-block-anchor lim)
+ (c-add-stmt-syntax tmpsymbol t lim paren-state))
+ ;; CASE 16: block close brace, possibly closing the defun or
+ ;; the class
+ ((eq char-after-ip ?})
+ ;; From here on we have the next containing sexp in lim.
+ (setq lim (c-most-enclosing-brace paren-state))
+ (goto-char containing-sexp)
+ (cond
+ ;; CASE 16E: Closing a statement block? This catches
+ ;; cases where it's preceded by a statement keyword,
+ ;; which works even when used in an "invalid" context,
+ ;; e.g. a macro argument.
+ ((c-after-conditional)
+ (c-backward-to-block-anchor lim)
+ (c-add-stmt-syntax 'block-close t lim paren-state))
+ ;; CASE 16A: closing a lambda defun or an in-expression
+ ;; block? C.f. cases 4, 7B and 17E.
+ ((setq placeholder (c-looking-at-inexpr-block
+ (c-safe-position containing-sexp paren-state)
+ nil))
+ (setq tmpsymbol (if (eq (car placeholder) 'inlambda)
+ 'inline-close
+ 'block-close))
+ (goto-char containing-sexp)
+ (back-to-indentation)
+ (if (= containing-sexp (point))
+ (c-add-syntax tmpsymbol (point))
+ (goto-char (cdr placeholder))
+ (back-to-indentation)
+ (c-add-stmt-syntax tmpsymbol t
+ (c-most-enclosing-brace paren-state (point))
+ (c-whack-state-after (point) paren-state))
+ (if (/= (point) (cdr placeholder))
+ (c-add-syntax (car placeholder)))))
+ ;; CASE 16B: does this close an inline or a function in
+ ;; an extern block or namespace?
+ ((setq placeholder (c-search-uplist-for-classkey paren-state))
+ (c-backward-to-decl-anchor lim)
+ (back-to-indentation)
+ (if (save-excursion
+ (goto-char (aref placeholder 0))
+ (looking-at c-other-decl-block-key))
+ (c-add-syntax 'defun-close (point))
+ (c-add-syntax 'inline-close (point))))
+ ;; CASE 16F: Can be a defun-close of a function declared
+ ;; in a statement block, e.g. in Pike or when using gcc
+ ;; extensions. Might also trigger it with some macros
+ ;; followed by blocks, and this gives sane indentation
+ ;; then too. Let it through to be handled below.
+ ;; C.f. cases B.3 and 17G.
+ ((and (not inenclosing-p)
+ lim
+ (save-excursion
+ (and (not (c-looking-at-bos))
+ (eq (c-beginning-of-statement-1 lim nil nil t) 'same)
+ (setq placeholder (point)))))
+ (back-to-indentation)
+ (if (/= (point) containing-sexp)
+ (goto-char placeholder))
+ (c-add-stmt-syntax 'defun-close t lim paren-state))
+ ;; CASE 16C: if there an enclosing brace that hasn't
+ ;; been narrowed out by a class, then this is a
+ ;; block-close. C.f. case 17H.
+ ((and (not inenclosing-p) lim)
+ ;; If the block is preceded by a case/switch label on
+ ;; the same line, we anchor at the first preceding label
+ ;; at boi. The default handling in c-add-stmt-syntax is
+ ;; really fixes it better, but we do like this to keep
+ ;; the indentation compatible with version 5.28 and
+ ;; earlier.
+ (while (and (/= (setq placeholder (point)) (c-point 'boi))
+ (eq (c-beginning-of-statement-1 lim) 'label)))
+ (goto-char placeholder)
+ (if (looking-at c-label-kwds-regexp)
+ (c-add-syntax 'block-close (point))
+ (goto-char containing-sexp)
+ ;; c-backward-to-block-anchor not necessary here; those
+ ;; situations are handled in case 16E above.
+ (c-add-stmt-syntax 'block-close t lim paren-state)))
+ ;; CASE 16D: find out whether we're closing a top-level
+ ;; class or a defun
+ (t
+ (save-restriction
+ (narrow-to-region (point-min) indent-point)
+ (let ((decl (c-search-uplist-for-classkey (c-parse-state))))
+ (if decl
+ (c-add-class-syntax 'class-close decl paren-state)
+ (goto-char containing-sexp)
+ (c-backward-to-decl-anchor lim)
+ (back-to-indentation)
+ (c-add-syntax 'defun-close (point)))))
+ )))
+ ;; CASE 17: Statement or defun catchall.
+ (t
+ (goto-char indent-point)
+ ;; Back up statements until we find one that starts at boi.
+ (while (let* ((prev-point (point))
+ (last-step-type (c-beginning-of-statement-1
+ containing-sexp)))
+ (if (= (point) prev-point)
+ (progn
+ (setq step-type (or step-type last-step-type))
+ nil)
+ (setq step-type last-step-type)
+ (/= (point) (c-point 'boi)))))
+ (cond
+ ;; CASE 17B: continued statement
+ ((and (eq step-type 'same)
+ (/= (point) indent-point))
+ (c-add-stmt-syntax 'statement-cont nil
+ containing-sexp paren-state))
+ ;; CASE 17A: After a case/default label?
+ ((progn
+ (while (and (eq step-type 'label)
+ (not (looking-at c-label-kwds-regexp)))
+ (setq step-type
+ (c-beginning-of-statement-1 containing-sexp)))
+ (eq step-type 'label))
+ (c-add-stmt-syntax (if (eq char-after-ip ?{)
+ 'statement-case-open
+ 'statement-case-intro)
+ t containing-sexp paren-state))
+ ;; CASE 17D: any old statement
+ ((progn
+ (while (eq step-type 'label)
+ (setq step-type
+ (c-beginning-of-statement-1 containing-sexp)))
+ (eq step-type 'previous))
+ (c-add-stmt-syntax 'statement t containing-sexp paren-state)
+ (if (eq char-after-ip ?{)
+ (c-add-syntax 'block-open)))
+ ;; CASE 17I: Inside a substatement block.
+ ((progn
+ ;; The following tests are all based on containing-sexp.
+ (goto-char containing-sexp)
+ ;; From here on we have the next containing sexp in lim.
+ (setq lim (c-most-enclosing-brace paren-state containing-sexp))
+ (c-after-conditional))
+ (c-backward-to-block-anchor lim)
+ (c-add-stmt-syntax 'statement-block-intro t lim paren-state)
+ (if (eq char-after-ip ?{)
+ (c-add-syntax 'block-open)))
+ ;; CASE 17E: first statement in an in-expression block.
+ ;; C.f. cases 4, 7B and 16A.
+ ((setq placeholder (c-looking-at-inexpr-block
+ (c-safe-position containing-sexp paren-state)
+ nil))
+ (setq tmpsymbol (if (eq (car placeholder) 'inlambda)
+ 'defun-block-intro
+ 'statement-block-intro))
+ (back-to-indentation)
+ (if (= containing-sexp (point))
+ (c-add-syntax tmpsymbol (point))
+ (goto-char (cdr placeholder))
+ (back-to-indentation)
+ (c-add-stmt-syntax tmpsymbol t
+ (c-most-enclosing-brace c-state-cache (point))
+ (c-whack-state-after (point) paren-state))
+ (if (/= (point) (cdr placeholder))
+ (c-add-syntax (car placeholder))))
+ (if (eq char-after-ip ?{)
+ (c-add-syntax 'block-open)))
+ ;; CASE 17F: first statement in an inline, or first
+ ;; statement in a top-level defun. we can tell this is it
+ ;; if there are no enclosing braces that haven't been
+ ;; narrowed out by a class (i.e. don't use bod here).
+ ;; However, we first check for statements that we can
+ ;; recognize by keywords. That increases the robustness in
+ ;; cases where statements are used on the top level,
+ ;; e.g. in macro definitions.
+ ((save-excursion
+ (save-restriction
+ (widen)
+ (c-narrow-out-enclosing-class paren-state containing-sexp)
+ (not (c-most-enclosing-brace paren-state))))
+ (c-backward-to-decl-anchor lim)
+ (back-to-indentation)
+ (c-add-syntax 'defun-block-intro (point)))
+ ;; CASE 17G: First statement in a function declared inside
+ ;; a normal block. This can occur in Pike and with
+ ;; e.g. the gcc extensions. Might also trigger it with
+ ;; some macros followed by blocks, and this gives sane
+ ;; indentation then too. C.f. cases B.3 and 16F.
+ ((save-excursion
+ (and (not (c-looking-at-bos))
+ (eq (c-beginning-of-statement-1 lim nil nil t) 'same)
+ (setq placeholder (point))))
+ (back-to-indentation)
+ (if (/= (point) containing-sexp)
+ (goto-char placeholder))
+ (c-add-stmt-syntax 'defun-block-intro t lim paren-state))
+ ;; CASE 17H: First statement in a block. C.f. case 16C.
+ (t
+ ;; If the block is preceded by a case/switch label on the
+ ;; same line, we anchor at the first preceding label at
+ ;; boi. The default handling in c-add-stmt-syntax is
+ ;; really fixes it better, but we do like this to keep the
+ ;; indentation compatible with version 5.28 and earlier.
+ (while (and (/= (setq placeholder (point)) (c-point 'boi))
+ (eq (c-beginning-of-statement-1 lim) 'label)))
+ (goto-char placeholder)
+ (if (looking-at c-label-kwds-regexp)
+ (c-add-syntax 'statement-block-intro (point))
+ (goto-char containing-sexp)
+ ;; c-backward-to-block-anchor not necessary here; those
+ ;; situations are handled in case 17I above.
+ (c-add-stmt-syntax 'statement-block-intro t lim paren-state))
+ (if (eq char-after-ip ?{)
+ (c-add-syntax 'block-open)))
+ ))
+ )
+ ;; now we need to look at any modifiers
+ (goto-char indent-point)
+ (skip-chars-forward " \t")
+ ;; are we looking at a comment only line?
+ (when (and (looking-at c-comment-start-regexp)
+ (/= (c-forward-token-1 0 nil (c-point 'eol)) 0))
+ (c-add-syntax 'comment-intro))
+ ;; we might want to give additional offset to friends (in C++).
+ (when (and c-opt-friend-key
+ (looking-at c-opt-friend-key))
+ (c-add-syntax 'friend))
+ ;; Start of or a continuation of a preprocessor directive?
+ (if (and macro-start
+ (eq macro-start (c-point 'boi))
+ (not (and (c-major-mode-is 'pike-mode)
+ (eq (char-after (1+ macro-start)) ?\"))))
+ (c-add-syntax 'cpp-macro)
+ (when (and c-syntactic-indentation-in-macros macro-start)
+ (if in-macro-expr
+ (when (or (< syntactic-relpos macro-start)
+ (not (or (assq 'arglist-intro syntax)
+ (assq 'arglist-cont syntax)
+ (assq 'arglist-cont-nonempty syntax)
+ (assq 'arglist-close syntax))))
+ ;; If inside a cpp expression, i.e. anywhere in a
+ ;; cpp directive except a #define body, we only let
+ ;; through the syntactic analysis that is internal
+ ;; in the expression. That means the arglist
+ ;; elements, if they are anchored inside the cpp
+ ;; expression.
+ (setq syntax `((cpp-macro-cont . ,macro-start))))
+ (when (and (eq macro-start syntactic-relpos)
+ (not (assq 'cpp-define-intro syntax))
+ (save-excursion
+ (goto-char macro-start)
+ (or (not (c-forward-to-cpp-define-body))
+ (<= (point) (c-point 'boi indent-point)))))
+ ;; Inside a #define body and the syntactic analysis is
+ ;; anchored on the start of the #define. In this case
+ ;; we add cpp-define-intro to get the extra
+ ;; indentation of the #define body.
+ (c-add-syntax 'cpp-define-intro)))))
+ ;; return the syntax
+ syntax)))))
+ ((defun c-guess-basic-syntax ()
+ (save-excursion
+ (save-restriction
+ (beginning-of-line)
+ (let* ((indent-point (point))
+ (case-fold-search nil)
+ (fullstate (c-parse-state))
+ (state fullstate)
+ literal containing-sexp char-before-ip char-after-ip lim
+ syntax placeholder c-in-literal-cache inswitch-p
+ tmpsymbol keyword injava-inher special-brace-list
+ ;; narrow out any enclosing class or extern "C" block
+ (inclass-p (c-narrow-out-enclosing-class state indent-point))
+ inenclosing-p)
+ ;; check for meta top-level enclosing constructs, possible
+ ;; extern language definitions, possibly (in C++) namespace
+ ;; definitions.
+ (save-excursion
+ (save-restriction
+ (widen)
+ (if (and inclass-p
+ (progn
+ (goto-char (aref inclass-p 0))
+ (looking-at (concat c-extra-toplevel-key "[^_]"))))
+ (let ((enclosing (match-string 1)))
+ (cond
+ ((string-equal enclosing "extern")
+ (setq inenclosing-p 'extern))
+ ((string-equal enclosing "namespace")
+ (setq inenclosing-p 'namespace))
+ )))))
+ ;; get the buffer position of the most nested opening brace,
+ ;; if there is one, and it hasn't been narrowed out
+ (save-excursion
+ (goto-char indent-point)
+ (skip-chars-forward " \t}")
+ (skip-chars-backward " \t")
+ (while (and state
+ (not containing-sexp))
+ (setq containing-sexp (car state)
+ state (cdr state))
+ (if (consp containing-sexp)
+ ;; if cdr == point, then containing sexp is the brace
+ ;; that opens the sexp we close
+ (if (= (cdr containing-sexp) (point))
+ (setq containing-sexp (car containing-sexp))
+ ;; otherwise, ignore this element
+ (setq containing-sexp nil))
+ ;; ignore the bufpos if its been narrowed out by the
+ ;; containing class or does not contain the indent point
+ (if (or (<= containing-sexp (point-min))
+ (>= containing-sexp indent-point))
+ (setq containing-sexp nil)))))
+ ;; (imenu "agulbra-c++-tab")
+ ;; set the limit on the farthest back we need to search
+ (setq lim (or containing-sexp
+ (if (consp (car fullstate))
+ (cdr (car fullstate))
+ nil)
+ (point-min)))
+
+ ;; cache char before and after indent point, and move point to
+ ;; the most likely position to perform the majority of tests
+ (goto-char indent-point)
+ (skip-chars-forward " \t")
+ (setq char-after-ip (char-after))
+ (c-backward-syntactic-ws lim)
+ (setq char-before-ip (char-before))
+ (goto-char indent-point)
+ (skip-chars-forward " \t")
+
+ ;; are we in a literal?
+ (setq literal (c-in-literal lim))
+
+ ;; now figure out syntactic qualities of the current line
+ (cond
+ ;; CASE 1: in a string.
+ ((memq literal '(string))
+ (c-add-syntax 'string (c-point 'bopl)))
+ ;; CASE 2: in a C or C++ style comment.
+ ((memq literal '(c c++))
+ (c-add-syntax literal (car (c-literal-limits lim))))
+ ;; CASE 3: in a cpp preprocessor macro continuation.
+ ((and (eq literal 'pound)
+ (/= (save-excursion
+ (c-beginning-of-macro lim)
+ (setq placeholder (point)))
+ (c-point 'boi)))
+ (c-add-syntax 'cpp-macro-cont placeholder))
+ ;; CASE 4: In-expression statement.
+ ((and (or c-inexpr-class-key c-inexpr-block-key c-lambda-key)
+ (setq placeholder (c-looking-at-inexpr-block)))
+ (setq tmpsymbol (assq (car placeholder)
+ '((inexpr-class . class-open)
+ (inexpr-statement . block-open))))
+ (if tmpsymbol
+ ;; It's a statement block or an anonymous class.
+ (setq tmpsymbol (cdr tmpsymbol))
+ ;; It's a Pike lambda. Check whether we are between the
+ ;; lambda keyword and the argument list or at the defun
+ ;; opener.
+ (setq tmpsymbol (if (eq char-after-ip ?{)
+ 'inline-open
+ 'lambda-intro-cont)))
+ (goto-char (cdr placeholder))
+ (back-to-indentation)
+ (c-add-syntax tmpsymbol (point))
+ (unless (eq (point) (cdr placeholder))
+ (c-add-syntax (car placeholder))))
+ ;; CASE 5: Line is at top level.
+ ((null containing-sexp)
+ (cond
+ ;; CASE 5A: we are looking at a defun, brace list, class,
+ ;; or inline-inclass method opening brace
+ ((setq special-brace-list
+ (or (and c-special-brace-lists
+ (c-looking-at-special-brace-list))
+ (eq char-after-ip ?{)))
+ (cond
+ ;; CASE 5A.1: extern language or namespace construct
+ ((save-excursion
+ (goto-char indent-point)
+ (skip-chars-forward " \t")
+ (and (c-safe (progn (c-backward-sexp 2) t))
+ (looking-at (concat c-extra-toplevel-key "[^_]"))
+ (setq keyword (match-string 1)
+ placeholder (point))
+ (or (and (string-equal keyword "namespace")
+ (setq tmpsymbol 'namespace-open))
+ (and (string-equal keyword "extern")
+ (progn
+ (c-forward-sexp 1)
+ (c-forward-syntactic-ws)
+ (eq (char-after) ?\"))
+ (setq tmpsymbol 'extern-lang-open)))
+ ))
+ (goto-char placeholder)
+ (c-add-syntax tmpsymbol (c-point 'boi)))
+ ;; CASE 5A.2: we are looking at a class opening brace
+ ((save-excursion
+ (goto-char indent-point)
+ (skip-chars-forward " \t{")
+ ;; TBD: watch out! there could be a bogus
+ ;; c-state-cache in place when we get here. we have
+ ;; to go through much chicanery to ignore the cache.
+ ;; But of course, there may not be! BLECH! BOGUS!
+ (let ((decl
+ (let ((c-state-cache nil))
+ (c-search-uplist-for-classkey (c-parse-state))
+ )))
+ (and decl
+ (setq placeholder (aref decl 0)))
+ ))
+ (c-add-syntax 'class-open placeholder))
+ ;; CASE 5A.3: brace list open
+ ((save-excursion
+ (c-beginning-of-statement-1 lim)
+ ;; c-b-o-s could have left us at point-min
+ (and (bobp)
+ (c-forward-syntactic-ws indent-point))
+ (if (looking-at "typedef[^_]")
+ (progn (c-forward-sexp 1)
+ (c-forward-syntactic-ws indent-point)))
+ (setq placeholder (c-point 'boi))
+ (or (consp special-brace-list)
+ (and (or (save-excursion
+ (goto-char indent-point)
+ (setq tmpsymbol nil)
+ (while (and (> (point) placeholder)
+ (= (c-backward-token-1 1 t) 0)
+ (/= (char-after) ?=))
+ (if (and (not tmpsymbol)
+ (looking-at "new\\>[^_]"))
+ (setq tmpsymbol 'topmost-intro-cont)))
+ (eq (char-after) ?=))
+ (looking-at "enum[ \t\n]+"))
+ (save-excursion
+ (while (and (< (point) indent-point)
+ (= (c-forward-token-1 1 t) 0)
+ (not (memq (char-after) '(?\; ?\()))))
+ (not (memq (char-after) '(?\; ?\()))
+ ))))
+ (if (and (c-major-mode-is 'java-mode)
+ (eq tmpsymbol 'topmost-intro-cont))
+ ;; We're in Java and have found that the open brace
+ ;; belongs to a "new Foo[]" initialization list,
+ ;; which means the brace list is part of an
+ ;; expression and not a top level definition. We
+ ;; therefore treat it as any topmost continuation
+ ;; even though the semantically correct symbol still
+ ;; is brace-list-open, on the same grounds as in
+ ;; case 10B.2.
+ (progn
+ (c-beginning-of-statement-1 lim)
+ (c-forward-syntactic-ws)
+ (c-add-syntax 'topmost-intro-cont (c-point 'boi)))
+ (c-add-syntax 'brace-list-open placeholder)))
+ ;; CASE 5A.4: inline defun open
+ ((and inclass-p (not inenclosing-p))
+ (c-add-syntax 'inline-open)
+ (c-add-class-syntax 'inclass inclass-p))
+ ;; CASE 5A.5: ordinary defun open
+ (t
+ (goto-char placeholder)
+ (if inclass-p
+ (c-add-syntax 'defun-open (c-point 'boi))
+ (c-add-syntax 'defun-open (c-point 'bol)))
+ )))
+ ;; CASE 5B: first K&R arg decl or member init
+ ((c-just-after-func-arglist-p)
+ (cond
+ ;; CASE 5B.1: a member init
+ ((or (eq char-before-ip ?:)
+ (eq char-after-ip ?:))
+ ;; this line should be indented relative to the beginning
+ ;; of indentation for the topmost-intro line that contains
+ ;; the prototype's open paren
+ ;; TBD: is the following redundant?
+ (if (eq char-before-ip ?:)
+ (forward-char -1))
+ (c-backward-syntactic-ws lim)
+ ;; TBD: is the preceding redundant?
+ (if (eq (char-before) ?:)
+ (progn (forward-char -1)
+ (c-backward-syntactic-ws lim)))
+ (if (eq (char-before) ?\))
+ (c-backward-sexp 1))
+ (setq placeholder (point))
+ (save-excursion
+ (and (c-safe (c-backward-sexp 1) t)
+ (looking-at "throw[^_]")
+ (c-safe (c-backward-sexp 1) t)
+ (setq placeholder (point))))
+ (goto-char placeholder)
+ (c-add-syntax 'member-init-intro (c-point 'boi))
+ ;; we don't need to add any class offset since this
+ ;; should be relative to the ctor's indentation
+ )
+ ;; CASE 5B.2: K&R arg decl intro
+ (c-recognize-knr-p
+ (c-add-syntax 'knr-argdecl-intro (c-point 'boi))
+ (if inclass-p (c-add-class-syntax 'inclass inclass-p)))
+ ;; CASE 5B.3: Inside a member init list.
+ ((c-beginning-of-member-init-list lim)
+ (c-forward-syntactic-ws)
+ (c-add-syntax 'member-init-cont (point)))
+ ;; CASE 5B.4: Nether region after a C++ or Java func
+ ;; decl, which could include a `throws' declaration.
+ (t
+ (c-beginning-of-statement-1 lim)
+ (c-add-syntax 'func-decl-cont (c-point 'boi))
+ )))
+ ;; CASE 5C: inheritance line. could be first inheritance
+ ;; line, or continuation of a multiple inheritance
+ ((or (and c-baseclass-key
+ (progn
+ (when (eq char-after-ip ?,)
+ (skip-chars-forward " \t")
+ (forward-char))
+ (looking-at c-baseclass-key)))
+ (and (or (eq char-before-ip ?:)
+ ;; watch out for scope operator
+ (save-excursion
+ (and (eq char-after-ip ?:)
+ (c-safe (progn (forward-char 1) t))
+ (not (eq (char-after) ?:))
+ )))
+ (save-excursion
+ (c-backward-syntactic-ws lim)
+ (if (eq char-before-ip ?:)
+ (progn
+ (forward-char -1)
+ (c-backward-syntactic-ws lim)))
+ (back-to-indentation)
+ (looking-at c-class-key)))
+ ;; for Java
+ (and (c-major-mode-is 'java-mode)
+ (let ((fence (save-excursion
+ (c-beginning-of-statement-1 lim)
+ (point)))
+ cont done)
+ (save-excursion
+ (while (not done)
+ (cond ((looking-at c-Java-special-key)
+ (setq injava-inher (cons cont (point))
+ done t))
+ ((or (not (c-safe (c-forward-sexp -1) t))
+ (<= (point) fence))
+ (setq done t))
+ )
+ (setq cont t)))
+ injava-inher)
+ (not (c-crosses-statement-barrier-p (cdr injava-inher)
+ (point)))
+ ))
+ (cond
+ ;; CASE 5C.1: non-hanging colon on an inher intro
+ ((eq char-after-ip ?:)
+ (c-backward-syntactic-ws lim)
+ (c-add-syntax 'inher-intro (c-point 'boi))
+ ;; don't add inclass symbol since relative point already
+ ;; contains any class offset
+ )
+ ;; CASE 5C.2: hanging colon on an inher intro
+ ((eq char-before-ip ?:)
+ (c-add-syntax 'inher-intro (c-point 'boi))
+ (if inclass-p (c-add-class-syntax 'inclass inclass-p)))
+ ;; CASE agulbrahack.1:
+ ((and inclass-p
+ c-access-key
+ (looking-at c-access-key))
+ (c-add-syntax 'access-label (c-point 'bonl))
+ (c-add-class-syntax 'inclass inclass-p)
+ )
+ ;; CASE 5C.3: in a Java implements/extends
+ (injava-inher
+ (let ((where (cdr injava-inher))
+ (cont (car injava-inher)))
+ (goto-char where)
+ (cond ((looking-at "throws[ \t\n]")
+ (c-add-syntax 'func-decl-cont
+ (progn (c-beginning-of-statement-1 lim)
+ (c-point 'boi))))
+ (cont (c-add-syntax 'inher-cont where))
+ (t (c-add-syntax 'inher-intro
+ (progn (goto-char (cdr injava-inher))
+ (c-beginning-of-statement-1 lim)
+ (point))))
+ )))
+ ;; CASE 5C.4: a continued inheritance line
+ (t
+ (c-beginning-of-inheritance-list lim)
+ (c-add-syntax 'inher-cont (point))
+ ;; don't add inclass symbol since relative point already
+ ;; contains any class offset
+ )))
+ ;; CASE 5D: this could be a top-level compound statement, a
+ ;; member init list continuation, or a template argument
+ ;; list continuation.
+ ((c-with-syntax-table (if (c-major-mode-is 'c++-mode)
+ c++-template-syntax-table
+ (syntax-table))
+ (save-excursion
+ (while (and (= (c-backward-token-1 1 t lim) 0)
+ (not (looking-at "[;{<,]"))))
+ (eq (char-after) ?,)))
+ (goto-char indent-point)
+ (c-beginning-of-member-init-list lim)
+ (cond
+ ;; CASE 5D.1: hanging member init colon, but watch out
+ ;; for bogus matches on access specifiers inside classes.
+ ((and (save-excursion
+ (setq plaaceholder (point))
+ (c-backward-token-1 1 t lim)
+ (and (eq (char-after) ?:)
+ (not (eq (char-before) ?:))))
+ (save-excursion
+ (goto-char placeholder)
+ (back-to-indentation)
+ (or
+ (/= (car (save-excursion
+ (parse-partial-sexp (point) placeholder)))
+ 0)
+ (and
+ (if c-access-key (not (looking-at c-access-key)) t)
+ (not (looking-at c-class-key))
+ (if c-bitfield-key (not (looking-at c-bitfield-key)) t))
+ )))
+ (goto-char placeholder)
+ (c-forward-syntactic-ws)
+ (c-add-syntax 'member-init-cont (point))
+ ;; we do not need to add class offset since relative
+ ;; point is the member init above us
+ )
+ ;; CASE 5D.2: non-hanging member init colon
+ ((progn
+ (c-forward-syntactic-ws indent-point)
+ (eq (char-after) ?:))
+ (skip-chars-forward " \t:")
+ (c-add-syntax 'member-init-cont (point)))
+ ;; CASE 5D.3: perhaps a multiple inheritance line?
+ ((save-excursion
+ (c-beginning-of-statement-1 lim)
+ (setq placeholder (point))
+ (looking-at c-inher-key))
+ (goto-char placeholder)
+ (c-add-syntax 'inher-cont (c-point 'boi)))
+ ;; CASE 5D.4: perhaps a template list continuation?
+ ((save-excursion
+ (goto-char indent-point)
+ (skip-chars-backward "^<" lim)
+ ;; not sure if this is the right test, but it should
+ ;; be fast and mostly accurate.
+ (setq placeholder (point))
+ (and (eq (char-before) ?<)
+ (not (c-in-literal lim))))
+ ;; we can probably indent it just like an arglist-cont
+ (goto-char placeholder)
+ (c-beginning-of-statement-1 lim)
+ (c-add-syntax 'template-args-cont (c-point 'boi)))
+ ;; CASE 5D.5: perhaps a top-level statement-cont
+ (t
+ (c-beginning-of-statement-1 lim)
+ ;; skip over any access-specifiers
+ (and inclass-p c-access-key
+ (while (looking-at c-access-key)
+ (forward-line 1)))
+ ;; skip over comments, whitespace
+ (c-forward-syntactic-ws indent-point)
+ (c-add-syntax 'statement-cont (c-point 'boi)))
+ ))
+ ;; CASE 5E: we are looking at a access specifier
+ ((and inclass-p
+ c-access-key
+ (looking-at c-access-key))
+ (c-add-syntax 'access-label (c-point 'bonl))
+ (c-add-class-syntax 'inclass inclass-p))
+ ;; CASE 5F: extern-lang-close or namespace-close?
+ ((and inenclosing-p
+ (eq char-after-ip ?}))
+ (setq tmpsymbol (if (eq inenclosing-p 'extern)
+ 'extern-lang-close
+ 'namespace-close))
+ (c-add-syntax tmpsymbol (aref inclass-p 0)))
+ ;; CASE 5G: we are looking at the brace which closes the
+ ;; enclosing nested class decl
+ ((and inclass-p
+ (eq char-after-ip ?})
+ (save-excursion
+ (save-restriction
+ (widen)
+ (forward-char 1)
+ (and (c-safe (progn (c-backward-sexp 1) t))
+ (= (point) (aref inclass-p 1))
+ ))))
+ (c-add-class-syntax 'class-close inclass-p))
+ ;; CASE 5H: we could be looking at subsequent knr-argdecls
+ ((and c-recognize-knr-p
+ ;; here we essentially use the hack that is used in
+ ;; Emacs' c-mode.el to limit how far back we should
+ ;; look. The assumption is made that argdecls are
+ ;; indented at least one space and that function
+ ;; headers are not indented.
+ (let ((limit (save-excursion
+ (re-search-backward "^[^ \^L\t\n#]" nil 'move)
+ (point))))
+ (save-excursion
+ (c-backward-syntactic-ws limit)
+ (setq placeholder (point))
+ (while (and (memq (char-before) '(?\; ?,))
+ (> (point) limit))
+ (beginning-of-line)
+ (setq placeholder (point))
+ (c-backward-syntactic-ws limit))
+ (and (eq (char-before) ?\))
+ (or (not c-method-key)
+ (progn
+ (c-forward-sexp -1)
+ (forward-char -1)
+ (c-backward-syntactic-ws)
+ (not (or (memq (char-before) '(?- ?+))
+ ;; or a class category
+ (progn
+ (c-forward-sexp -2)
+ (looking-at c-class-key))
+ )))))
+ ))
+ (save-excursion
+ (c-beginning-of-statement-1)
+ (not (looking-at "typedef[ \t\n]+"))))
+ (goto-char placeholder)
+ (c-add-syntax 'knr-argdecl (c-point 'boi)))
+ ;; CASE 5I: ObjC method definition.
+ ((and c-method-key
+ (looking-at c-method-key))
+ (c-add-syntax 'objc-method-intro (c-point 'boi)))
+ ;; CASE 5J: we are at the topmost level, make sure we skip
+ ;; back past any access specifiers
+ ((progn
+ (c-backward-syntactic-ws lim)
+ (while (and inclass-p
+ c-access-key
+ (not (bobp))
+ (save-excursion
+ (c-safe (progn (c-backward-sexp 1) t))
+ ;; agulbrahack 2
+ (and (looking-at "slots:")
+ (c-backward-sexp 1))
+ (looking-at c-access-key)))
+ (c-backward-sexp 1)
+ (c-backward-syntactic-ws lim))
+ (or (bobp)
+ (memq (char-before) '(?\; ?\}))))
+ ;; real beginning-of-line could be narrowed out due to
+ ;; enclosure in a class block
+ (save-restriction
+ (widen)
+ (c-add-syntax 'topmost-intro (c-point 'bol))
+ (if inclass-p
+ (progn
+ (goto-char (aref inclass-p 1))
+ (or (= (point) (c-point 'boi))
+ (goto-char (aref inclass-p 0)))
+ (cond
+ ((eq inenclosing-p 'extern)
+ (c-add-syntax 'inextern-lang (c-point 'boi)))
+ ((eq inenclosing-p 'namespace)
+ (c-add-syntax 'innamespace (c-point 'boi)))
+ (t (c-add-class-syntax 'inclass inclass-p)))
+ ))
+ ))
+ ;; CASE 5K: we are at an ObjC or Java method definition
+ ;; continuation line.
+ ((and c-method-key
+ (progn
+ (c-beginning-of-statement-1 lim)
+ (beginning-of-line)
+ (looking-at c-method-key)))
+ (c-add-syntax 'objc-method-args-cont (point)))
+ ;; CASE 5L: we are at the first argument of a template
+ ;; arglist that begins on the previous line.
+ ((eq (char-before) ?<)
+ (c-beginning-of-statement-1 lim)
+ (c-forward-syntactic-ws)
+ (c-add-syntax 'template-args-cont (c-point 'boi)))
+ ;; CASE 5M: we are at a topmost continuation line
+ (t
+ (c-beginning-of-statement-1 lim)
+ (c-forward-syntactic-ws)
+ (c-add-syntax 'topmost-intro-cont (c-point 'boi)))
+ )) ; end CASE 5
+ ;; (CASE 6 has been removed.)
+ ;; CASE 7: line is an expression, not a statement. Most
+ ;; likely we are either in a function prototype or a function
+ ;; call argument list
+ ((not (or (and c-special-brace-lists
+ (save-excursion
+ (goto-char containing-sexp)
+ (c-looking-at-special-brace-list)))
+ (eq (char-after containing-sexp) ?{)))
+ (c-backward-syntactic-ws containing-sexp)
+ (cond
+ ;; CASE 7A: we are looking at the arglist closing paren
+ ((and (or (c-major-mode-is 'pike-mode)
+ ;; Don't check this in Pike since it allows a
+ ;; comma after the last arg.
+ (not (eq char-before-ip ?,)))
+ (memq char-after-ip '(?\) ?\])))
+ (goto-char containing-sexp)
+ (setq placeholder (c-point 'boi))
+ (when (and (c-safe (backward-up-list 1) t)
+ (> (point) placeholder))
+ (forward-char)
+ (skip-chars-forward " \t")
+ (setq placeholder (point)))
+ (c-add-syntax 'arglist-close placeholder))
+ ;; CASE 7B: Looking at the opening brace of an
+ ;; in-expression block or brace list.
+ ((eq char-after-ip ?{)
+ (goto-char indent-point)
+ (setq placeholder (c-point 'boi))
+ (goto-char containing-sexp)
+ (if (c-inside-bracelist-p placeholder
+ (cons containing-sexp state))
+ (progn
+ (c-add-syntax 'brace-list-open (c-point 'boi))
+ (c-add-syntax 'inexpr-class))
+ (c-add-syntax 'block-open (c-point 'boi))
+ (c-add-syntax 'inexpr-statement)))
+ ;; CASE 7C: we are looking at the first argument in an empty
+ ;; argument list. Use arglist-close if we're actually
+ ;; looking at a close paren or bracket.
+ ((memq char-before-ip '(?\( ?\[))
+ (goto-char containing-sexp)
+ (setq placeholder (c-point 'boi))
+ (when (and (c-safe (backward-up-list 1) t)
+ (> (point) placeholder))
+ (forward-char)
+ (skip-chars-forward " \t")
+ (setq placeholder (point)))
+ (c-add-syntax 'arglist-intro placeholder))
+ ;; CASE 7D: we are inside a conditional test clause. treat
+ ;; these things as statements
+ ((save-excursion
+ (goto-char containing-sexp)
+ (and (c-safe (progn (c-forward-sexp -1) t))
+ (looking-at "\\<for\\>[^_]")))
+ (goto-char (1+ containing-sexp))
+ (c-forward-syntactic-ws indent-point)
+ (c-beginning-of-statement-1 containing-sexp)
+ (if (eq char-before-ip ?\;)
+ (c-add-syntax 'statement (point))
+ (c-add-syntax 'statement-cont (point))
+ ))
+ ;; CASE 7E: maybe a continued method call. This is the case
+ ;; when we are inside a [] bracketed exp, and what precede
+ ;; the opening bracket is not an identifier.
+ ((and c-method-key
+ (eq (char-after containing-sexp) ?\[)
+ (save-excursion
+ (goto-char (1- containing-sexp))
+ (c-backward-syntactic-ws (c-point 'bod))
+ (if (not (looking-at c-symbol-key))
+ (c-add-syntax 'objc-method-call-cont containing-sexp))
+ )))
+ ;; CASE 7F: we are looking at an arglist continuation line,
+ ;; but the preceding argument is on the same line as the
+ ;; opening paren. This case includes multi-line
+ ;; mathematical paren groupings, but we could be on a
+ ;; for-list continuation line
+ ((save-excursion
+ (goto-char (1+ containing-sexp))
+ (skip-chars-forward " \t")
+ (not (eolp)))
+ (goto-char containing-sexp)
+ (setq placeholder (c-point 'boi))
+ (when (and (c-safe (backward-up-list 1) t)
+ (> (point) placeholder))
+ (forward-char)
+ (skip-chars-forward " \t")
+ (setq placeholder (point)))
+ (c-add-syntax 'arglist-cont-nonempty placeholder))
+ ;; CASE 7G: we are looking at just a normal arglist
+ ;; continuation line
+ (t (c-beginning-of-statement-1 containing-sexp)
+ (forward-char 1)
+ (c-forward-syntactic-ws indent-point)
+ (c-add-syntax 'arglist-cont (c-point 'boi)))
+ ))
+ ;; CASE 8: func-local multi-inheritance line
+ ((and c-baseclass-key
+ (save-excursion
+ (goto-char indent-point)
+ (skip-chars-forward " \t")
+ (looking-at c-baseclass-key)))
+ (goto-char indent-point)
+ (skip-chars-forward " \t")
+ (cond
+ ;; CASE 8A: non-hanging colon on an inher intro
+ ((eq char-after-ip ?:)
+ (c-backward-syntactic-ws lim)
+ (c-add-syntax 'inher-intro (c-point 'boi)))
+ ;; CASE 8B: hanging colon on an inher intro
+ ((eq char-before-ip ?:)
+ (c-add-syntax 'inher-intro (c-point 'boi)))
+ ;; CASE 8C: a continued inheritance line
+ (t
+ (c-beginning-of-inheritance-list lim)
+ (c-add-syntax 'inher-cont (point))
+ )))
+ ;; CASE 9: we are inside a brace-list
+ ((setq special-brace-list
+ (or (and c-special-brace-lists
+ (save-excursion
+ (goto-char containing-sexp)
+ (c-looking-at-special-brace-list)))
+ (c-inside-bracelist-p containing-sexp state)))
+ (cond
+ ;; CASE 9A: In the middle of a special brace list opener.
+ ((and (consp special-brace-list)
+ (save-excursion
+ (goto-char containing-sexp)
+ (eq (char-after) ?\())
+ (eq char-after-ip (car (cdr special-brace-list))))
+ (goto-char (car (car special-brace-list)))
+ (skip-chars-backward " \t")
+ (if (and (bolp)
+ (assoc 'statement-cont
+ (setq placeholder (c-guess-basic-syntax))))
+ (setq syntax placeholder)
+ (c-beginning-of-statement-1 lim)
+ (c-forward-token-1 0)
+ (if (looking-at "typedef\\>") (c-forward-token-1 1))
+ (c-add-syntax 'brace-list-open (c-point 'boi))))
+ ;; CASE 9B: brace-list-close brace
+ ((if (consp special-brace-list)
+ ;; Check special brace list closer.
+ (progn
+ (goto-char (car (car special-brace-list)))
+ (save-excursion
+ (goto-char indent-point)
+ (back-to-indentation)
+ (or
+ ;; We were between the special close char and the `)'.
+ (and (eq (char-after) ?\))
+ (eq (1+ (point)) (cdr (car special-brace-list))))
+ ;; We were before the special close char.
+ (and (eq (char-after) (cdr (cdr special-brace-list)))
+ (= (c-forward-token-1) 0)
+ (eq (1+ (point)) (cdr (car special-brace-list)))))))
+ ;; Normal brace list check.
+ (and (eq char-after-ip ?})
+ (c-safe (progn (forward-char 1)
+ (c-backward-sexp 1)
+ t))
+ (= (point) containing-sexp)))
+ (c-add-syntax 'brace-list-close (c-point 'boi)))
+ (t
+ ;; Prepare for the rest of the cases below by going to the
+ ;; token following the opening brace
+ (if (consp special-brace-list)
+ (progn
+ (goto-char (car (car special-brace-list)))
+ (c-forward-token-1 1 nil indent-point))
+ (goto-char containing-sexp))
+ (forward-char)
+ (let ((start (point)))
+ (c-forward-syntactic-ws indent-point)
+ (goto-char (max start (c-point 'bol))))
+ (skip-chars-forward " \t\n\r" indent-point)
+ (cond
+ ;; CASE 9C: we're looking at the first line in a brace-list
+ ((= (point) indent-point)
+ (goto-char containing-sexp)
+ (c-add-syntax 'brace-list-intro (c-point 'boi))
+ ) ; end CASE 9C
+ ;; CASE 9D: this is just a later brace-list-entry or
+ ;; brace-entry-open
+ (t (if (or (eq char-after-ip ?{)
+ (and c-special-brace-lists
+ (save-excursion
+ (goto-char indent-point)
+ (c-forward-syntactic-ws (c-point 'eol))
+ (c-looking-at-special-brace-list (point)))))
+ (c-add-syntax 'brace-entry-open (point))
+ (c-add-syntax 'brace-list-entry (point))
+ )) ; end CASE 9D
+ )))) ; end CASE 9
+ ;; CASE 10: A continued statement
+ ((and (not (memq char-before-ip '(?\; ?:)))
+ (or (not (eq char-before-ip ?}))
+ (c-looking-at-inexpr-block-backward containing-sexp))
+ (> (point)
+ (save-excursion
+ (c-beginning-of-statement-1 containing-sexp)
+ (c-forward-syntactic-ws)
+ (setq placeholder (point))))
+ (/= placeholder containing-sexp))
+ (goto-char indent-point)
+ (skip-chars-forward " \t")
+ (let ((after-cond-placeholder
+ (save-excursion
+ (goto-char placeholder)
+ (if (and c-conditional-key (looking-at c-conditional-key))
+ (progn
+ (c-safe (c-skip-conditional))
+ (c-forward-syntactic-ws)
+ (if (eq (char-after) ?\;)
+ (progn
+ (forward-char 1)
+ (c-forward-syntactic-ws)))
+ (point))
+ nil))))
+ (cond
+ ;; CASE 10A: substatement
+ ((and after-cond-placeholder
+ (>= after-cond-placeholder indent-point))
+ (goto-char placeholder)
+ (if (eq char-after-ip ?{)
+ (c-add-syntax 'substatement-open (c-point 'boi))
+ (c-add-syntax 'substatement (c-point 'boi))))
+ ;; CASE 10B: open braces for class or brace-lists
+ ((setq special-brace-list
+ (or (and c-special-brace-lists
+ (c-looking-at-special-brace-list))
+ (eq char-after-ip ?{)))
+ (cond
+ ;; CASE 10B.1: class-open
+ ((save-excursion
+ (goto-char indent-point)
+ (skip-chars-forward " \t{")
+ (let ((decl (c-search-uplist-for-classkey (c-parse-state))))
+ (and decl
+ (setq placeholder (aref decl 0)))
+ ))
+ (c-add-syntax 'class-open placeholder))
+ ;; CASE 10B.2: brace-list-open
+ ((or (consp special-brace-list)
+ (save-excursion
+ (goto-char placeholder)
+ (looking-at "\\<enum\\>"))
+ (save-excursion
+ (goto-char indent-point)
+ (while (and (> (point) placeholder)
+ (= (c-backward-token-1 1 t) 0)
+ (/= (char-after) ?=)))
+ (eq (char-after) ?=)))
+ ;; The most semantically accurate symbol here is
+ ;; brace-list-open, but we report it simply as a
+ ;; statement-cont. The reason is that one normally
+ ;; adjusts brace-list-open for brace lists as
+ ;; top-level constructs, and brace lists inside
+ ;; statements is a completely different context.
+ (goto-char indent-point)
+ (c-beginning-of-closest-statement)
+ (c-add-syntax 'statement-cont (c-point 'boi)))
+ ;; CASE 10B.3: The body of a function declared inside a
+ ;; normal block. This can only occur in Pike.
+ ((and (c-major-mode-is 'pike-mode)
+ (progn
+ (goto-char indent-point)
+ (not (c-looking-at-bos))))
+ (c-beginning-of-closest-statement)
+ (c-add-syntax 'defun-open (c-point 'boi)))
+ ;; CASE 10B.4: catch-all for unknown construct.
+ (t
+ ;; Can and should I add an extensibility hook here?
+ ;; Something like c-recognize-hook so support for
+ ;; unknown constructs could be added. It's probably a
+ ;; losing proposition, so I dunno.
+ (goto-char placeholder)
+ (c-add-syntax 'statement-cont (c-point 'boi))
+ (c-add-syntax 'block-open))
+ ))
+ ;; CASE 10C: iostream insertion or extraction operator
+ ((looking-at "<<\\|>>")
+ (goto-char placeholder)
+ (and after-cond-placeholder
+ (goto-char after-cond-placeholder))
+ (while (and (re-search-forward "<<\\|>>" indent-point 'move)
+ (c-in-literal placeholder)))
+ ;; if we ended up at indent-point, then the first
+ ;; streamop is on a separate line. Indent the line like
+ ;; a statement-cont instead
+ (if (/= (point) indent-point)
+ (c-add-syntax 'stream-op (c-point 'boi))
+ (c-backward-syntactic-ws lim)
+ (c-add-syntax 'statement-cont (c-point 'boi))))
+ ;; CASE 10D: continued statement. find the accurate
+ ;; beginning of statement or substatement
+ (t
+ (c-beginning-of-statement-1 after-cond-placeholder)
+ ;; KLUDGE ALERT! c-beginning-of-statement-1 can leave
+ ;; us before the lim we're passing in. It should be
+ ;; fixed, but I'm worried about side-effects at this
+ ;; late date. Fix for v5.
+ (goto-char (or (and after-cond-placeholder
+ (max after-cond-placeholder (point)))
+ (point)))
+ (c-add-syntax 'statement-cont (point)))
+ )))
+ ;; CASE 11: an else clause?
+ ((looking-at "\\<else\\>[^_]")
+ (c-backward-to-start-of-if containing-sexp)
+ (c-add-syntax 'else-clause (c-point 'boi)))
+ ;; CASE 12: Statement. But what kind? Lets see if its a
+ ;; while closure of a do/while construct
+ ((progn
+ (goto-char indent-point)
+ (skip-chars-forward " \t")
+ (and (looking-at "while\\b[^_]")
+ (save-excursion
+ (c-backward-to-start-of-do containing-sexp)
+ (setq placeholder (point))
+ (looking-at "do\\b[^_]"))
+ ))
+ (goto-char placeholder)
+ (c-add-syntax 'do-while-closure (c-point 'boi)))
+ ;; CASE 13: A catch or finally clause? This case is simpler
+ ;; than if-else and do-while, because a block is required
+ ;; after every try, catch and finally.
+ ((save-excursion
+ (and (cond ((c-major-mode-is 'c++-mode)
+ (looking-at "\\<catch\\>[^_]"))
+ ((c-major-mode-is 'java-mode)
+ (looking-at "\\<\\(catch\\|finally\\)\\>[^_]")))
+ (c-safe (c-backward-sexp) t)
+ (eq (char-after) ?{)
+ (c-safe (c-backward-sexp) t)
+ (if (eq (char-after) ?\()
+ (c-safe (c-backward-sexp) t)
+ t)
+ (looking-at "\\<\\(try\\|catch\\)\\>[^_]")
+ (setq placeholder (c-point 'boi))))
+ (c-add-syntax 'catch-clause placeholder))
+ ;; CASE 14: A case or default label
+ ((looking-at c-switch-label-key)
+ (goto-char containing-sexp)
+ ;; check for hanging braces
+ (if (/= (point) (c-point 'boi))
+ (c-forward-sexp -1))
+ (c-add-syntax 'case-label (c-point 'boi)))
+ ;; CASE 15: any other label
+ ((looking-at c-label-key)
+ (goto-char containing-sexp)
+ ;; check for hanging braces
+ (if (/= (point) (c-point 'boi))
+ (c-forward-sexp -1))
+ (c-add-syntax 'label (c-point 'boi)))
+ ;; CASE 16: block close brace, possibly closing the defun or
+ ;; the class
+ ((eq char-after-ip ?})
+ (let* ((lim (c-safe-position containing-sexp fullstate))
+ (relpos (save-excursion
+ (goto-char containing-sexp)
+ (if (/= (point) (c-point 'boi))
+ (c-beginning-of-statement-1 lim))
+ (c-point 'boi))))
+ (cond
+ ;; CASE 16A: closing a lambda defun or an in-expression
+ ;; block?
+ ((save-excursion
+ (goto-char containing-sexp)
+ (setq placeholder (c-looking-at-inexpr-block)))
+ (setq tmpsymbol (if (eq (car placeholder) 'inlambda)
+ 'inline-close
+ 'block-close))
+ (goto-char containing-sexp)
+ (back-to-indentation)
+ (if (= containing-sexp (point))
+ (c-add-syntax tmpsymbol (point))
+ (goto-char (cdr placeholder))
+ (back-to-indentation)
+ (c-add-syntax tmpsymbol (point))
+ (if (/= (point) (cdr placeholder))
+ (c-add-syntax (car placeholder)))))
+ ;; CASE 16B: does this close an inline or a function in
+ ;; an extern block or namespace?
+ ((progn
+ (goto-char containing-sexp)
+ (setq placeholder (c-search-uplist-for-classkey state)))
+ (goto-char (aref placeholder 0))
+ (if (looking-at (concat c-extra-toplevel-key "[^_]"))
+ (c-add-syntax 'defun-close relpos)
+ (c-add-syntax 'inline-close relpos)))
+ ;; CASE 16C: if there an enclosing brace that hasn't
+ ;; been narrowed out by a class, then this is a
+ ;; block-close
+ ((and (not inenclosing-p)
+ (c-most-enclosing-brace state)
+ (or (not (c-major-mode-is 'pike-mode))
+ ;; In Pike it can be a defun-close of a
+ ;; function declared in a statement block. Let
+ ;; it through to be handled below.
+ (or (c-looking-at-bos)
+ (progn
+ (c-beginning-of-statement-1)
+ (looking-at c-conditional-key)))))
+ (c-add-syntax 'block-close relpos))
+ ;; CASE 16D: find out whether we're closing a top-level
+ ;; class or a defun
+ (t
+ (save-restriction
+ (narrow-to-region (point-min) indent-point)
+ (let ((decl (c-search-uplist-for-classkey (c-parse-state))))
+ (if decl
+ (c-add-class-syntax 'class-close decl)
+ (c-add-syntax 'defun-close relpos)))))
+ )))
+ ;; CASE 17: statement catchall
+ (t
+ ;; we know its a statement, but we need to find out if it is
+ ;; the first statement in a block
+ (goto-char containing-sexp)
+ (forward-char 1)
+ (c-forward-syntactic-ws indent-point)
+ ;; now skip forward past any case/default clauses we might find.
+ (while (or (c-skip-case-statement-forward fullstate indent-point)
+ (and (looking-at c-switch-label-key)
+ (not inswitch-p)))
+ (setq inswitch-p t))
+ ;; we want to ignore non-case labels when skipping forward
+ (while (and (looking-at c-label-key)
+ (goto-char (match-end 0)))
+ (c-forward-syntactic-ws indent-point))
+ (cond
+ ;; CASE 17A: we are inside a case/default clause inside a
+ ;; switch statement. find out if we are at the statement
+ ;; just after the case/default label.
+ ((and inswitch-p
+ (progn
+ (goto-char indent-point)
+ (c-beginning-of-statement-1 containing-sexp)
+ (setq placeholder (point))
+ (beginning-of-line)
+ (when (re-search-forward c-switch-label-key
+ (max placeholder (c-point 'eol)) t)
+ (setq placeholder (match-beginning 0)))))
+ (goto-char indent-point)
+ (skip-chars-forward " \t")
+ (if (eq (char-after) ?{)
+ (c-add-syntax 'statement-case-open placeholder)
+ (c-add-syntax 'statement-case-intro placeholder)))
+ ;; CASE 17B: continued statement
+ ((eq char-before-ip ?,)
+ (goto-char indent-point)
+ (c-beginning-of-closest-statement)
+ (c-add-syntax 'statement-cont (c-point 'boi)))
+ ;; CASE 17C: a question/colon construct? But make sure
+ ;; what came before was not a label, and what comes after
+ ;; is not a globally scoped function call!
+ ((or (and (memq char-before-ip '(?: ??))
+ (save-excursion
+ (goto-char indent-point)
+ (c-backward-syntactic-ws lim)
+ (back-to-indentation)
+ (not (looking-at c-label-key))))
+ (and (memq char-after-ip '(?: ??))
+ (save-excursion
+ (goto-char indent-point)
+ (skip-chars-forward " \t")
+ ;; watch out for scope operator
+ (not (looking-at "::")))))
+ (goto-char indent-point)
+ (c-beginning-of-closest-statement)
+ (c-add-syntax 'statement-cont (c-point 'boi)))
+ ;; CASE 17D: any old statement
+ ((< (point) indent-point)
+ (let ((safepos (c-most-enclosing-brace fullstate))
+ relpos done)
+ (goto-char indent-point)
+ (c-beginning-of-statement-1 safepos)
+ ;; It is possible we're on the brace that opens a nested
+ ;; function.
+ (if (and (eq (char-after) ?{)
+ (save-excursion
+ (c-backward-syntactic-ws safepos)
+ (not (eq (char-before) ?\;))))
+ (c-beginning-of-statement-1 safepos))
+ (if (and inswitch-p
+ (looking-at c-switch-label-key))
+ (progn
+ (goto-char (match-end 0))
+ (c-forward-syntactic-ws)))
+ (setq relpos (c-point 'boi))
+ (while (and (not done)
+ (<= safepos (point))
+ (/= relpos (point)))
+ (c-beginning-of-statement-1 safepos)
+ (if (= relpos (c-point 'boi))
+ (setq done t))
+ (setq relpos (c-point 'boi)))
+ (c-add-syntax 'statement relpos)
+ (if (eq char-after-ip ?{)
+ (c-add-syntax 'block-open))))
+ ;; CASE 17E: first statement in an in-expression block
+ ((setq placeholder
+ (save-excursion
+ (goto-char containing-sexp)
+ (c-looking-at-inexpr-block)))
+ (goto-char containing-sexp)
+ (back-to-indentation)
+ (let ((block-intro (if (eq (car placeholder) 'inlambda)
+ 'defun-block-intro
+ 'statement-block-intro)))
+ (if (= containing-sexp (point))
+ (c-add-syntax block-intro (point))
+ (goto-char (cdr placeholder))
+ (back-to-indentation)
+ (c-add-syntax block-intro (point))
+ (if (/= (point) (cdr placeholder))
+ (c-add-syntax (car placeholder)))))
+ (if (eq char-after-ip ?{)
+ (c-add-syntax 'block-open)))
+ ;; CASE 17F: first statement in an inline, or first
+ ;; statement in a top-level defun. we can tell this is it
+ ;; if there are no enclosing braces that haven't been
+ ;; narrowed out by a class (i.e. don't use bod here!)
+ ((save-excursion
+ (save-restriction
+ (widen)
+ (goto-char containing-sexp)
+ (c-narrow-out-enclosing-class state containing-sexp)
+ (not (c-most-enclosing-brace state))))
+ (goto-char containing-sexp)
+ ;; if not at boi, then defun-opening braces are hung on
+ ;; right side, so we need a different relpos
+ (if (/= (point) (c-point 'boi))
+ (progn
+ (c-backward-syntactic-ws)
+ (c-safe (c-forward-sexp (if (eq (char-before) ?\))
+ -1 -2)))
+ ;; looking at a Java throws clause following a
+ ;; method's parameter list
+ (c-beginning-of-statement-1)
+ ))
+ (c-add-syntax 'defun-block-intro (c-point 'boi)))
+ ;; CASE 17G: First statement in a function declared inside
+ ;; a normal block. This can only occur in Pike.
+ ((and (c-major-mode-is 'pike-mode)
+ (progn
+ (goto-char containing-sexp)
+ (and (not (c-looking-at-bos))
+ (progn
+ (c-beginning-of-statement-1)
+ (not (looking-at c-conditional-key))))))
+ (c-add-syntax 'defun-block-intro (c-point 'boi)))
+ ;; CASE 17H: first statement in a block
+ (t (goto-char containing-sexp)
+ (if (/= (point) (c-point 'boi))
+ (c-beginning-of-statement-1
+ (if (= (point) lim)
+ (c-safe-position (point) state) lim)))
+ (c-add-syntax 'statement-block-intro (c-point 'boi))
+ (if (eq char-after-ip ?{)
+ (c-add-syntax 'block-open)))
+ ))
+ )
+ ;; now we need to look at any modifiers
+ (goto-char indent-point)
+ (skip-chars-forward " \t")
+ (cond
+ ;; are we looking at a comment only line?
+ ((and (looking-at c-comment-start-regexp)
+ (/= (c-forward-token-1 0 nil (c-point 'eol)) 0))
+ (c-add-syntax 'comment-intro))
+ ;; we might want to give additional offset to friends (in C++).
+ ((and (c-major-mode-is 'c++-mode)
+ (looking-at c-C++-friend-key))
+ (c-add-syntax 'friend))
+ ;; Start of a preprocessor directive?
+ ((and (eq literal 'pound)
+ (= (save-excursion
+ (c-beginning-of-macro lim)
+ (setq placeholder (point)))
+ (c-point 'boi))
+ (not (and (c-major-mode-is 'pike-mode)
+ (eq (char-after (1+ placeholder)) ?\"))))
+ (c-add-syntax 'cpp-macro)))
+ ;; return the syntax
+ syntax))))))
+
+(add-hook 'find-file-hooks 'agulbra-c++-clean-out-spaces)
+(add-hook 'write-file-hooks 'agulbra-c++-clean-out-spaces)
+
+(add-hook 'c++-mode-hook 'kde-c++-mode-hook)
+(add-hook 'c-mode-hook 'kde-c-mode-hook)
+; always end a file with a newline
+(setq-default require-final-newline t)
+; 'next-line won't be adding newlines
+(setq-default next-line-add-newlines nil)
+(setq compilation-error-regexp-systems-list '(gnu of comma 4bsd)
+ compilation-ask-about-save nil)
+
+(provide 'kde-emacs-core)
diff --git a/scripts/kde-emacs/kde-emacs-doc.el b/scripts/kde-emacs/kde-emacs-doc.el
new file mode 100644
index 00000000..5fca1361
--- /dev/null
+++ b/scripts/kde-emacs/kde-emacs-doc.el
@@ -0,0 +1,322 @@
+;; kde-emacs-doc.el
+;;
+;; Copyright (C) 2002 Zack Rusin <zack@kde.org>
+;;
+;; This library is free software; you can redistribute it and/or
+;; modify it under the terms of the GNU Lesser General Public
+;; License as published by the Free Software Foundation; either
+;; version 2.1 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
+;; Lesser General Public License for more details.
+;;
+;; You should have received a copy of the GNU Lesser General Public
+;; License along with this library; if not, write to the Free Software
+;; Foundation, Inc., 51 Franklin Steet, Fifth Floor, Boston, MA
+;; 02110-1301 USA
+;;
+;;
+;;; Documentation :
+;; Interactive functions:
+;; kde-license-insert - inserts the chosen license header in the current
+;; buffer,
+;; kde-doc-function-insert - insert documentation skeleton for the function
+;; at the current location
+;; kde-doc-multiline-insert - inserts blank mutliline comment skeleton
+;; kde-doc-oneliner-insert - inserts blank one line comment skeleton
+;;
+;;; TODO :
+;; - add interactive functions to insert file, class, brief,
+;; and group comments,
+;; - change the way commenting works after license insertion,
+;; - add syntax higlighting for doxygen/kdoc keywords
+;; - add more license headers
+
+
+(require 'kde-emacs-core)
+(require 'kde-emacs-semantic)
+
+;*---------------------------------------------------------------------*/
+;* Licenses ... */
+;*---------------------------------------------------------------------*/
+
+(defvar LGPL "This library is free software; you can redistribute it and/or
+modify it under the terms of the GNU Lesser General Public
+License as published by the Free Software Foundation; either
+version 2.1 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
+Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public
+License along with this library; if not, write to the Free Software
+Foundation, Inc., 51 Franklin Steet, Fifth Floor, Boston, MA
+02110-1301 USA"
+ "GNU LGPL license header.")
+
+(defvar GPL "This program is free software; you can redistribute it and/or
+modify it under the terms of the 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, write to the Free Software
+Foundation, Inc., 51 Franklin Steet, Fifth Floor, Boston, MA
+02110-1301, USA."
+ "GNU GPL license header.")
+
+(defvar FDL "Permission is granted to copy, distribute and/or modify this document
+under the terms of the GNU Free Documentation License, Version 1.1
+or any later version published by the Free Software Foundation;
+with the Invariant Sections being LIST THEIR TITLES, with the
+Front-Cover Texts being LIST, and with the Back-Cover Texts being LIST.
+A copy of the license is included in the section entitled \"GNU
+Free Documentation License\"."
+ "GNU FDL license header.")
+
+(defvar BSD "Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+
+1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+ "BSD license header.")
+
+
+;;----------------
+;; Variables |
+;;----------------
+
+(defconst kde-doc-styles
+ '(
+ (javadoc .
+ ((start . "/**")
+ (end . "*/")
+ (separator . "\n*")
+ (oneliner . "///")
+ (element . "/**< */")
+ (param . "@param %s")
+ (return . "@return")
+ (seealso . "@see")
+ (class . "")
+ (brief . "@brief")
+ (file . "@file %s")
+ ))
+ (qt .
+ ((start . "/*!")
+ (end . "*/")
+ (separator . "\n")
+ (oneliner . "//!")
+ (element . "/*!< */")
+ (param . "\\param %s")
+ (return . "\\return")
+ (seealso . "\\sa")
+ (class . "\\class")
+ (brief . "\\brief")
+ (file . "\\file %s")
+ ))
+ )
+ "Documentation styles used by KDE.")
+
+(defcustom kde-doc-style 'javadoc
+ "Current documentation style. This variable is buffer local."
+ :group 'kde-devel
+ :version "0.1"
+ :type (if (boundp 'kde-doc-styles)
+ `(choice ,@(mapcar (lambda (s) `(const ,(car s))) kde-doc-styles))
+ 'symbol))
+(make-variable-buffer-local 'kde-doc-style)
+
+(defcustom kde-license-comment-style 'box
+ "Style to be used for `kde-license-insert'.
+See `comment-styles' for a list of available styles."
+ :group 'kde-devel
+ :version "0.1"
+ :type (if (boundp 'comment-styles)
+ `(choice ,@(mapcar (lambda (s) `(const ,(car s))) comment-styles))
+ 'symbol))
+
+;*---------------------------------------------------------------------*/
+;* Functions ... */
+;*---------------------------------------------------------------------*/
+
+(defun kde-license-header ()
+ (let ((ret (file-name-nondirectory (buffer-file-name))))
+ (setq ret (concat ret " \n\n"))
+ (setq ret (concat ret "Copyright (C) " (format-time-string "%Y ")
+ kde-full-name " <"kde-email">\n\n"))
+ ))
+
+(defun kde-license-insert (license)
+ "Inserts the chosen license header at the top of the current
+buffer."
+ (interactive (list (completing-read
+ "Which license do you want to use? "
+ '(("GNU GPL" 1) ("GNU LGPL" 2) ("GNU FDL" 3) ("BSD" 4))
+ nil t nil)))
+ (save-excursion
+ (let ((start (point-min))
+ (end)
+ )
+ (setq comment-style kde-license-comment-style)
+ (goto-char start)
+ (if license
+ (progn
+ (cond ((string= license "GNU GPL")
+ (insert (kde-license-header))
+ (insert GPL)
+ )
+ ((string= license "GNU LGPL")
+ (insert (kde-license-header))
+ (insert LGPL)
+ )
+ ((string= license "GNU FDL")
+ (insert (kde-license-header))
+ (insert FDL)
+ )
+ ((string= license "BSD")
+ (insert (kde-license-header))
+ (insert BSD)
+ )
+ )
+ (insert "\n")
+ (setq end (point))
+ (comment-region start end)
+ )
+ )
+ )
+ ))
+
+(defmacro kde-doc-type-string (arg)
+ "Maps doc element from kde-doc-style to string."
+ `(cdr (assoc ,arg (assoc kde-doc-style kde-doc-styles)))
+ )
+
+(defun kde-doc-param-string (ARG)
+ "Substitues %s in the param string with ARG."
+ (let ((par (kde-doc-type-string 'param)))
+ (if (string-match "\%s" par)
+ (replace-match ARG t t par)
+ par))
+ )
+
+(defun kde-function-documentation (function)
+ (let ((ret "") (rettype (semantic-token-type function)))
+ (setq ret (kde-doc-type-string 'start))
+ (setq ret (concat ret (kde-doc-type-string 'separator)))
+ (dolist (elt (semantic-token-function-args function) ret)
+ (setq ret (concat ret (kde-doc-type-string 'separator) " "
+ (kde-doc-param-string (semantic-token-name elt))))
+ )
+ (if (not (or
+ (kde-is-constructor function)
+ (semantic-token-function-destructor function)))
+ (progn
+ (if (listp rettype)
+ (setq rettype (car rettype)))
+ (if (not (string= rettype "void"))
+ (setq ret (concat ret (kde-doc-type-string 'separator) " " (kde-doc-type-string 'return)))
+ )
+ )
+ )
+ (setq ret (concat ret "\n" (kde-doc-type-string 'end) ))
+ ))
+
+(defun kde-doc-function-insert ()
+ "Inserts skeleton function documentation for a function
+at the current location."
+ (interactive)
+ (save-excursion
+ (let* ((pt (point))
+ (token (kde-function-at-point pt))
+ (ret "")
+ (start) (end)
+ )
+ (if (not token)
+ (error "There's no function at %d." pt)
+ (progn
+ (setq ret (kde-function-documentation token))
+ (goto-char (semantic-token-start token))
+ (previous-line)
+ (goto-char (point-at-eol))
+ (setq start (point))
+ (insert "\n " ret)
+ (setq end (semantic-token-end token))
+ (indent-region start end nil)
+ )
+ )
+ )))
+
+(defun kde-doc-oneliner-insert ()
+ "Insert oneliner comment at the current point. If the line is not empty newline is inserted."
+ (interactive)
+ (let ((thisblank)(pt))
+ (save-excursion
+ (beginning-of-line)
+ (setq pt (point))
+ (setq thisblank (looking-at "[ \t]*$"))
+ (if (not thisblank)
+ (progn
+ (newline)
+ (goto-char pt)
+ ))
+ (insert (kde-doc-type-string 'oneliner))
+ (setq pt (point-at-eol))
+ (end-of-line)
+ )
+ (goto-char pt)
+ ))
+
+(defun kde-doc-multiline-insert ()
+ "Inserts blank multiline comment at point. If the current line isn't blank
+the functions inserts a newline."
+ (interactive)
+ (let ((thisblank)(start) (end))
+ (save-excursion
+ (beginning-of-line)
+ (setq start (point))
+ (setq thisblank (looking-at "[ \t]*$"))
+ (if (not thisblank)
+ (progn
+ (newline)
+ (goto-char start)
+ ))
+ ;; The blank to fix sometimes occuring
+ ;; weird behavior in indent-region
+ (insert " "
+ (kde-doc-type-string 'start)
+ (kde-doc-type-string 'separator) "\n"
+ (kde-doc-type-string 'end)
+ )
+ (setq end (point))
+ (indent-region start end nil)
+ )
+ (goto-char start)
+ (end-of-line)
+ ))
+
+
+(provide 'kde-emacs-doc)
diff --git a/scripts/kde-emacs/kde-emacs-general.el b/scripts/kde-emacs/kde-emacs-general.el
new file mode 100644
index 00000000..be34047c
--- /dev/null
+++ b/scripts/kde-emacs/kde-emacs-general.el
@@ -0,0 +1,179 @@
+;; kde-emacs-general.el
+;;
+;; Copyright (C) 2002 KDE Development Team <www.kde.org>
+;;
+;; This library is free software; you can redistribute it and/or
+;; modify it under the terms of the GNU Lesser General Public
+;; License as published by the Free Software Foundation; either
+;; version 2.1 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
+;; Lesser General Public License for more details.
+;;
+;; You should have received a copy of the GNU Lesser General Public
+;; License along with this library; if not, write to the Free Software
+;; Foundation, Inc., 51 Franklin Steet, Fifth Floor, Boston, MA
+;; 02110-1301 USA
+
+;;; Commentary:
+;;
+
+;;; Code:
+
+(require 'kde-emacs-vars)
+
+;*---------------------------------------------------------------------*/
+;* Functions ... */
+;*---------------------------------------------------------------------*/
+
+;; Helper for kde-file-get-cpp-h
+(defun kde-find-file (filename basedir)
+ "Looks for \"filename\" under \"basedir\""
+ (if basedir
+ (let ((path (concat basedir "/" filename)))
+ (if (file-readable-p path)
+ path))
+ )
+)
+
+(defun kde-file-get-cpp-h ()
+ "Function returns a corresponding source or header file. The returned
+variable is a list of the form (FILENAME IS_READABLE) e.g. when being in
+test.h file and having test.cpp file readable in the same directory it will
+return (\"test.cpp\" t)."
+ (interactive)
+ (let* ((name (buffer-file-name))
+ (nname (file-name-sans-extension name))
+ (ext (file-name-extension name))
+ (path nil)
+ (ret nil)
+ (listit nil))
+ (cond
+ ((member ext kde-header-files)
+ (setq listit kde-source-files)
+ (while (and listit (not ret)) ; loop over the list but stop once ret is set
+ (setq path (concat nname "." (car listit)))
+ (if (file-readable-p path)
+ (setq ret (cons path t))
+ )
+ (if (not ret)
+ (if (string-match "_p$" nname)
+ (progn
+ (setq path (concat (substring nname 0 (string-match "_p$" nname)) "." (car listit)))
+ (if (file-readable-p path)
+ (setq ret (cons path t))
+ )))
+ )
+ (if (not ret)
+ (progn ; look in kde-source-directory
+ (setq path (kde-find-file (file-name-nondirectory path) kde-source-directory))
+ (if (and
+ path
+ (file-readable-p path))
+ (setq ret (cons path t))
+ ))
+ )
+ (setq listit (cdr listit)) ; ++listit
+ )
+ ; not found, will create one
+ (if (not ret)
+ (setq ret (cons (concat nname "." kde-prefered-source-extension) nil ))
+ ))
+
+ ((member ext kde-source-files)
+ (setq listit kde-header-files)
+ (while (and listit (not ret)) ; loop over the list but stop once ret is set
+ (setq path (concat nname "." (car listit)))
+ ; look in current dir
+ (if (file-readable-p path)
+ (setq ret (cons path t)))
+ (if (not ret) ;check for header_p.h files
+ (progn (setq path (concat nname "_p." (car listit)))
+ (if (file-readable-p path)
+ (setq ret (cons path t)))))
+ (if (not (file-readable-p path))
+ (progn ; look in kde-include-directory
+ (setq path (kde-find-file (file-name-nondirectory path) kde-include-directory))
+ (if (and
+ path
+ (file-readable-p path))
+ (setq ret (cons path t))
+ ))
+ )
+ (setq listit (cdr listit)) ; ++listit
+ )
+ ; not found, will create one
+ (if (not ret)
+ (setq ret (cons (concat nname "." (car kde-header-files)) nil ))
+ ))
+ )
+ ret
+ ))
+
+(defun kde-switch-cpp-h ()
+ "Switches between the source and the header file
+(both directions)."
+ (interactive)
+ (let ((file (kde-file-get-cpp-h)))
+ (if (car file)
+ (find-file (car file))
+ (error "Corresponding source file doesn't exist.")
+ )
+ ))
+
+(defun kde-delete-backward-ws ()
+ "Function deletes all preceding whitespace characters."
+ (interactive)
+ (let ((start (point))
+ end)
+ (save-excursion
+ (setq end (re-search-backward "[^ \t]" (point-at-bol) t))
+ (if (not end)
+ (setq end (point-at-bol))
+ (setq end (1+ end))))
+ (delete-backward-char (- start end))))
+
+(defun kde-skip-blank-lines ()
+ "Skips backwards past blank lines, stopping
+at a first non-blank line"
+ (let* ((start (point-at-bol))
+ (end (point-at-eol))
+ (mstring (buffer-substring start end))
+ (ret 0))
+ (while (or
+ (string-match "^[ \t\r\n]+$" mstring)
+ (and (string= mstring "")
+ (= ret 0)))
+ (setq ret (forward-line -1)) ; if ret != 0, we stop, since we're at the first line...
+ (setq start (point-at-bol)
+ end (point-at-eol))
+ (setq mstring (buffer-substring start end))
+ )
+ ))
+
+(defun kde-comments-begin ()
+ "Skip back from current point past any preceding C-based comments at the beginning of lines.
+Presumes no \"/*\" strings are nested within multi-line comments."
+ (let ((opoint))
+ (while (progn (setq opoint (point))
+ ;; To previous line
+ (if (zerop (forward-line -1))
+ (cond
+ ;; If begins with "//" or ends with "*/", then is a
+ ;; comment.
+ ((looking-at "[ \t]*\\(//\\|$\\)"))
+ ((looking-at ".*\\*/[ \t]*$")
+ (progn (end-of-line)
+ ;; Avoid //*** single line comments here.
+ (if (re-search-backward "\\(^\\|[^/]\\)/\\*" nil t)
+ (progn (beginning-of-line)
+ (looking-at "[ \t]*/\\*")))))
+ (t nil)))))
+ (goto-char opoint)
+ ;; Skip past whitespace
+ (skip-chars-forward " \t\n\r\f")
+ (beginning-of-line)))
+
+(provide 'kde-emacs-general)
diff --git a/scripts/kde-emacs/kde-emacs-semantic.el b/scripts/kde-emacs/kde-emacs-semantic.el
new file mode 100644
index 00000000..1753520b
--- /dev/null
+++ b/scripts/kde-emacs/kde-emacs-semantic.el
@@ -0,0 +1,456 @@
+;; kde-emacs-semantic.el
+;;
+;; Copyright (C) 2002 Zack Rusin <zack@kde.org>
+;;
+;; This library is free software; you can redistribute it and/or
+;; modify it under the terms of the GNU Lesser General Public
+;; License as published by the Free Software Foundation; either
+;; version 2.1 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
+;; Lesser General Public License for more details.
+;;
+;; You should have received a copy of the GNU Lesser General Public
+;; License along with this library; if not, write to the Free Software
+;; Foundation, Inc., 51 Franklin Steet, Fifth Floor, Boston, MA
+;; 02110-1301 USA
+
+;;; Commentary:
+;; Package provides four interactive functions:
+;; - kde-function-doc-insert - creates a skeleton doxygen
+;; documentation for function at point.
+;; Customize it with kde-func-doc variables.
+;;
+;; - kde-function-expanded-at-point - returns t if function at point
+;; has already been expanded.
+;;
+;; - kde-function-expand-at-point - expand (creates a stub) for function
+;; at point (as long as function is a prototype
+;; and haven't been expanded).
+;;
+;; - kde-create-skeletons - creates stubs for all methods in the current
+;; header file.
+;;
+;; Package is very flexible, look at defcustom variables for things
+;; you can customize.
+
+;;; Problems:
+;; Most problems relate to C++ syntax which isn't handled correctly
+;; by the Semantic package. For now templates aren't supported, I
+;; have a temporary solution for other problems (e.g. const functions,
+;; QT/KDE specific access specifiers)
+
+;;; Code:
+(require 'kde-emacs-vars)
+(require 'kde-emacs-general)
+
+;*---------------------------------------------------------------------*/
+;* User configuration ... */
+;*---------------------------------------------------------------------*/
+;;Not yet, not yet
+;(defcustom kde-summary-function 'semantic-uml-prototype-nonterminal
+; "*Function to use when showing info about the token"
+; :group 'kde-devel
+; :type semantic-token->text-custom-list
+; )
+
+(defcustom kde-generate-docs-with-stubs nil
+ "*Should function documentation be generated with the stubs."
+ :group 'kde-devel
+ :type 'boolean)
+
+(defcustom kde-expand-arg-start "( "
+ "*A string which specifies how the function arguments format should start.
+e.g. \"( \" would start function arguments list like : \"func( int arg\".
+and \" (\" will format the begining of the function argument list as
+follows : \"func (int arg\"."
+ :group 'kde-devel
+ :version "0.1"
+ :type 'string)
+
+(defcustom kde-expand-arg-end " )"
+ "*Just like kde-expand-arg-start but specifies how the list should end."
+ :group 'kde-devel
+ :version "0.1"
+ :type 'string)
+
+(defcustom kde-expand-arg-break ", "
+ "*Specifies how the arguments should be separated."
+ :group 'kde-devel
+ :version "0.1"
+ :type 'string)
+
+
+;*---------------------------------------------------------------------*/
+;* Functions ... */
+;*---------------------------------------------------------------------*/
+;; FIXME : semantic doesn't handle QT access specifiers
+;(setq-default global-semantic-show-unmatched-syntax-mode nil)
+;(setq-default global-semantic-show-dirty-mode nil)
+
+(defun kde-format-func-arg (arg)
+ "Formats one argument (from token to string)."
+ (let ((ret ""))
+ (if (semantic-token-variable-extra-spec arg 'const)
+ (setq ret "const "))
+ (setq ret (concat ret (car (semantic-token-type arg))))
+ (if (semantic-token-variable-extra-spec arg 'pointer)
+ (dotimes (idx (semantic-token-variable-extra-spec arg 'pointer))
+ (setq ret (concat ret "*"))
+ )
+ )
+ (if (semantic-token-variable-extra-spec arg 'reference)
+ (setq ret (concat ret "&"))
+ )
+ (setq ret (concat ret " " (semantic-token-name arg)))
+ ret
+ ))
+
+(defun kde-format-args (token)
+ "Formats all arguments from token to string.
+Token has to be the function variable list e.g.
+from semantic-token-function-args"
+ (let ((res kde-expand-arg-start) (idx 1))
+ (dolist (elt token res)
+ (setq res (concat res (kde-format-func-arg elt)))
+ (when (< idx (length token))
+ (setq res (concat res kde-expand-arg-break)))
+ (setq idx (1+ idx))
+ )
+ (setq res (concat res kde-expand-arg-end))
+ ;; if it's something like "( )" replace it with "()"
+ (when (string= res (concat kde-expand-arg-start kde-expand-arg-end))
+ (setq res (replace-regexp-in-string "([ \t]+)" "()" res)))
+ res
+ ))
+
+(defun kde-function-in-tokens (FUNC TOKENS)
+ "Search for function in tokens. FUNC has to be a function
+token and TOKENS have to be a list of functions from buffer."
+ (let ((ret)(elt))
+ (while (and TOKENS (not ret))
+ (setq elt (car TOKENS))
+ (setq TOKENS (cdr TOKENS))
+ (if (and (string= (semantic-token-name FUNC)
+ (semantic-token-name elt))
+ (equal (semantic-token-type FUNC)
+ (semantic-token-type elt))
+ ;; FIXME (semantic) : Functions in some classes don't have the
+ ;; 'parent property set !!!
+ ;;(string= (semantic-token-function-parent FUNC1)
+ ;; (semantic-token-function-parent FUNC2))
+ (string= (kde-format-args (semantic-token-function-args FUNC))
+ (kde-format-args (semantic-token-function-args elt))))
+ (setq ret t))
+ )
+ ret
+ ))
+
+(defmacro kde-label-signals (pt)
+ "Returns none-nil if the current access label == \"signals\""
+ `(save-excursion
+ (goto-char ,pt)
+ (if (looking-at ":")
+ (re-search-backward "signals" (point-at-bol) t)
+ )
+ ))
+
+(defun kde-label-namespace (pt)
+ "Return the namespace to which the variable/function at point PT belongs to."
+ (save-excursion
+ (goto-char pt)
+ (if (looking-at "::")
+ (let ((start) (end))
+ (re-search-backward "\\b\\w+" (point-at-bol) t)
+ (setq start (match-beginning 0))
+ (setq end (match-end 0))
+ (buffer-substring-no-properties start end)
+ )
+ )
+ ))
+
+(defmacro kde-label-slots (pt)
+ "Return none-nil if at PT there's slots access specifier."
+ `(save-excursion
+ (goto-char ,pt)
+ (if (looking-at ":")
+ ;; export this regex to a kde-emacs-vars defvar
+ (re-search-backward "\\(public\\|protected\\|private\\)[ \t]+slots" (point-at-bol) t))
+ ))
+
+(defmacro kde-is-constructor (function)
+ "Returns t if the FUNCTION is a constructor."
+ `(semantic-token-function-extra-spec ,function 'constructor)
+ )
+
+(defun kde-function-const (function)
+ "Returns t if the FUNCTION has been declared as const, e.g.
+if given a token representing \"int getInt() const\" this functions
+would return t"
+ (save-excursion
+ (let ((start (semantic-token-start function))
+ (end (semantic-token-end function)))
+ (goto-char end)
+ (if (re-search-backward "const\b*;" start t)
+ t
+ nil)
+ )
+ ))
+
+(defun kde-is-prototype (function)
+ "Returns t if the FUNCTION is only a prototype."
+ (cond
+ ((semantic-token-function-extra-spec function 'prototype)
+ t)
+ (t
+ (kde-function-const function))
+ ))
+
+
+
+(defun kde-function-at-point (pt)
+ "Return function at pt as a token."
+ (save-excursion
+ (let ((token)
+ (what (semantic-find-nonterminal-by-position pt (current-buffer)))
+ (ctx))
+ (goto-char pt)
+ (if (eq (semantic-token-token what) 'function)
+ what
+ (semantic-find-nonterminal-by-position pt (semantic-token-type-parts what)))
+ )
+ ))
+
+(defun kde-function-construct (token pclass)
+ "Constructs a function string from the TOKEN, with the parent class PCLASS."
+ (let ((fname (semantic-token-name token)))
+ (if (semantic-token-function-destructor token)
+ (setq fname (concat "~" fname))
+ )
+ (if pclass
+ (setq fname (concat pclass "::" fname))
+ )
+ (if (and
+ (not (kde-is-constructor token))
+ (not (semantic-token-function-destructor token)))
+ (progn
+ (cond
+ ((stringp (semantic-token-type token))
+ (setq fname (concat (semantic-token-type token) "\n" fname))
+ )
+ (t
+ (setq fname (concat (car (semantic-token-type token)) "\n" fname)))
+ )
+ (if (semantic-token-function-extra-spec token 'const)
+ (setq fname (concat "const " fname))
+ )
+ )
+ )
+ (setq fname (concat fname (kde-format-args (semantic-token-function-args token))))
+ (if (kde-function-const token)
+ (setq fname (concat fname " const" ))
+ )
+ (setq fname (concat fname "\n{" "\n}"))
+ fname
+ )
+ )
+
+(defun kde-class-expand (class-token)
+ "Returns stubs for member functions as a string.
+class-token has to be a token representing either a class or a struct."
+ (let ((ret "")
+ (name (semantic-token-name class-token))
+ (parents (semantic-token-type-parent class-token))
+ (parts (semantic-token-type-parts class-token))
+ (cur-token)
+ (cur-token-name)
+ (asignal)
+ (aslot)
+ (namespace)
+ )
+ (dolist (elt parts ret)
+ (setq cur-token (semantic-token-token elt))
+ (setq cur-token-name (semantic-token-name elt))
+ (cond
+ ((and
+ (eq cur-token 'type)
+ (stringp cur-token-name))
+ (cond
+ ((string= cur-token-name "class")
+ (kde-class-expand elt)
+ )
+ ((string= cur-token-name "enum")
+ ;;skip enums
+ )
+ ((string= cur-token-name "struct")
+ (kde-class-expand elt)
+ )
+ )
+ )
+ ((and
+ (eq cur-token 'function)
+ (stringp cur-token-name))
+ ;;FUNCTION - generate a skeleton for it
+ (if (and (kde-is-prototype elt)
+ (not asignal))
+ (setq ret (concat ret (kde-function-construct elt name) "\n\n"))
+ )
+ ;(insert (kde-function-documentation elt) "\n")
+ )
+ ((and
+ (eq cur-token 'label)
+ (stringp cur-token-name))
+ (setq aslot nil
+ asignal nil)
+ ;;LABEL - unsets both signals and slots
+ )
+ ((and
+ (eq cur-token 'variable)
+ cur-token-name)
+ ;;VARIABLE - doesn't handle static variables correctly right now
+ )
+ ((not (stringp cur-token-name))
+ (cond
+ ((kde-label-signals (car (semantic-token-extent elt)))
+ ;;SIGNALS - next prototypes belong to signals and we don't want to
+ ;; expand those
+ (setq asignal t
+ aslot nil)
+ )
+ ((kde-label-namespace (car (semantic-token-extent elt)))
+ ;;NAMESPACE - semantic doesn't handle things like Qt::ButtonState correctly
+ ;; so we do ;)
+ (setq namespace (kde-label-namespace (car (semantic-token-extent elt))))
+ )
+ ((kde-label-slots (car (semantic-token-extent elt)))
+ ;;SLOTS - for now just unset signals
+ (setq aslot t
+ asignal nil)
+ )
+ (t
+ (insert "something else at " (number-to-string (car (semantic-token-extent elt))) "\n"))
+ ))
+ (t
+ (insert "Unknown type :: " (prin1-to-string elt) " >>" (prin1-to-string cur-token) "\n"))
+ )
+ )
+ ret
+ )
+ )
+
+(defun kde-expand-tokens (tokens)
+ "Expands smenatic tokens to strings."
+ (let ((ret ""))
+ (dolist (elt tokens ret)
+ (cond
+ ((eq (semantic-token-token elt) 'type)
+ (setq ret (concat ret (kde-class-expand elt)))
+ )
+ ((eq (semantic-token-token elt) 'function)
+ (if (kde-is-prototype elt)
+ (setq ret (concat ret (kde-function-construct elt nil) "\n\n"))
+ )
+ )
+ ((eq (semantic-token-token elt) 'variable)
+ ;; skip
+ ;;(kde-extract-variable elt)
+ )
+ ((eq (semantic-token-token elt) 'include)
+ ;;ignore includes for now
+ )
+ (t (insert "Unknown type : " (prin1-to-string (semantic-token-type elt)) "\n"))
+ )
+ )
+ )
+ )
+
+
+(defun kde-tokens-in-file (FILENAME)
+ "Returns all tokens from a file with the FILENAME."
+ (let ((exists (file-readable-p FILENAME))
+ (buf (current-buffer))
+ (tokens))
+ (if exists
+ (progn
+ (find-file FILENAME)
+ (setq tokens (semantic-bovinate-toplevel t))
+ (switch-to-buffer buf)
+ tokens)
+ nil)
+ ))
+
+(defun kde-function-in-file (FUNC FILENAME)
+ "Returns non-nil if FUNC is in a file named FILENAME"
+ (let ((tokens (kde-tokens-in-file FILENAME)))
+ (if tokens
+ (kde-function-in-tokens FUNC tokens)
+ nil
+ )
+ ))
+
+(defun kde-function-is-expanded (FUNC)
+ "Returns t if the function FUNC has been expanded."
+ (let ((file (kde-file-get-cpp-h)))
+ (if (cdr file)
+ (if (kde-function-in-file FUNC (car file))
+ t
+ nil
+ )
+ nil)
+ ))
+
+(defun kde-function-expanded-at-point (PT)
+ "Returns non-nil if the function at point PT has already been expanded."
+ (interactive "d")
+ (let ((func (kde-function-at-point PT)))
+ (kde-function-is-expanded func)
+ )
+ )
+
+(defun kde-create-skeletons ()
+ "Creates functions stubs in the source file, for all functions
+in the current header file."
+ (interactive)
+ (let* ((all-tokens (semantic-bovinate-toplevel t))
+ (filename (buffer-name))
+ (cppfile (car (kde-file-get-cpp-h)))
+ (funcs (kde-expand-tokens all-tokens)))
+ (find-file cppfile)
+ (save-excursion
+ (insert "#include \"" filename "\"\n\n")
+ (insert funcs)
+ )
+ )
+ )
+
+(defun kde-function-expand-at-point (PT)
+ "Expand function at point PT."
+ (interactive "d")
+ (let ((object (semantic-find-nonterminal-by-position PT (current-buffer)))
+ (func (kde-function-at-point PT))
+ (file)
+ (buf)
+ (parent))
+ (if (and object (equal (semantic-token-type object) "class"))
+ (setq parent (semantic-token-name object)))
+ (if (and (not (kde-function-expanded-at-point PT))
+ (kde-is-prototype func))
+ (progn
+ (setq func (kde-function-construct func parent))
+ (setq file (car (kde-file-get-cpp-h)))
+ (setq buf (current-buffer))
+ (find-file file)
+ (save-excursion
+ (goto-char (point-max))
+ (insert "\n" func "\n")
+ )
+ (switch-to-buffer buf)
+ )
+ (error "Function already expanded or defined!")
+ )
+ )
+ )
+
+(provide 'kde-emacs-semantic)
diff --git a/scripts/kde-emacs/kde-emacs-tips.texi b/scripts/kde-emacs/kde-emacs-tips.texi
new file mode 100644
index 00000000..ee7c0f19
--- /dev/null
+++ b/scripts/kde-emacs/kde-emacs-tips.texi
@@ -0,0 +1,257 @@
+\input texinfo @c -*-texinfo-*-
+
+@finalout
+
+@c %**start of header
+@setfilename kde-emacs-tips
+@settitle KDE Emacs usefull programming tips
+@footnotestyle end
+@c @setchapternewpage odd !! we don't want blank pages
+@c %**end of header
+
+@dircategory Emacs
+@direntry
+* KDE Emacs: (kde-emacs). Emacs mode for editing KDE/QT C++/C code.
+@end direntry
+
+@ifnottex
+Copyright @copyright{} 2002 Zack Rusin and KDE Development Team
+
+Permission is granted to copy, distribute and/or modify this document
+under the terms of the GNU Free Documentation License, Version 1.1 or
+any later version published by the Free Software Foundation; with the
+Invariant Sections being ``The GNU Manifesto'', ``Distribution'' and
+``GNU GENERAL PUBLIC LICENSE'', with the Front-Cover texts being ``A GNU
+Manual'', and with the Back-Cover Texts as in (a) below. A copy of the
+license is included in the section entitled ``GNU Free Documentation
+License'' in the Emacs manual.
+
+(a) The FSF's Back-Cover Text is: ``You have freedom to copy and modify
+this GNU Manual, like GNU software. Copies published by the Free
+Software Foundation raise funds for GNU development.''
+
+This document is part of a collection distributed under the GNU Free
+Documentation License. If you want to distribute this document
+separately from the collection, you can do so by adding a copy of the
+license to the document, as described in section 6 of the license.
+@end ifnottex
+
+@titlepage
+@sp 10
+
+@center @titlefont{KDE Emacs Package}
+@sp 2
+@center @subtitlefont{KDE Emacs package documentation and programming tips.}
+@sp 2
+@author Zack Rusin
+
+@page
+@vskip 0pt plus 1filll
+Copyright @copyright{} 2002 Zack Rusin & KDE Development Team
+@sp 1
+Permission is granted to copy, distribute and/or modify this document
+under the terms of the GNU Free Documentation License, Version 1.1 or
+any later version published by the Free Software Foundation; with the
+Invariant Sections being ``The GNU Manifesto'', ``Distribution'' and
+``GNU GENERAL PUBLIC LICENSE'', with the Front-Cover texts being ``A GNU
+Manual'', and with the Back-Cover Texts as in (a) below. A copy of the
+license is included in the section entitled ``GNU Free Documentation
+License'' in the Emacs manual.
+
+(a) The FSF's Back-Cover Text is: ``You have freedom to copy and modify
+this GNU Manual, like GNU software. Copies published by the Free
+Software Foundation raise funds for GNU development.''
+
+This document is part of a collection distributed under the GNU Free
+Documentation License. If you want to distribute this document
+separately from the collection, you can do so by adding a copy of the
+license to the document, as described in section 6 of the license.
+@end titlepage
+
+@node Top, Introduction, (dir), (dir)
+@comment node-name, next, previous, up
+
+@macro kdeemacs
+KDE Emacs
+@end macro
+
+@ifinfo
+@top @kdeemacs{}
+
+@kdeemacs{} is an Emacs package with tons of useful features
+which ease KDE development process.
+KDE Emacs usefull programming tips.
+
+@end ifinfo
+
+@menu
+* Introduction::
+* Getting Connected::
+* Generating stubs::
+* Tips::
+@end menu
+
+@comment !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+@node Introduction, Getting Connected, Top, Top
+@comment node-name, next, previous, up
+@chapter Introduction
+@comment !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+
+@comment !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+@node Getting Connected, Generating stubs, Introduction, Top
+@comment node-name, next, previous, up
+@chapter Getting Connected
+@comment !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+@menu
+* Sect. 2.1:: Installation
+* Sect. 2.2:: Files
+* Sect. 2.3:: Keybindings
+@end menu
+
+@node Sect. 2.1, Sect. 2.2, Chapter 2, Chapter 2
+@section @code{Installation}
+@comment node-name, next, previous, up
+
+@node Sect. 2.2, Sect. 2.3, Sect. 2.1, Chapter 2
+@section @code{Files}
+@comment node-name, next, previous, up
+
+@node Sect. 2.3, , Sect 2.2, Chapter 2
+@section @code{Keybindings}
+@comment node-name, next, previous, up
+
+@comment !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+@node Generating stubs , Tips, Getting Connected, Top
+@comment node-name, next, previous, up
+@chapter Generating stubs
+@comment !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+
+@comment !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+@node Tips, Top, Generating stubs, Top
+@comment node-name, next, previous, up
+@chapter Tips
+@comment !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+
+@sp 1
+@strong{Q.} @emph{How do I hide #ifdef's in source files without
+actually changing them?}
+
+@strong{A.} Use @code{hide-ifdef-mode} which supports hiding of ifdef
+blocks without actually changing the file. In this mode @kbd{C-c @@
+C-d} hides ifdef block and @kbd{C-c @@ C-s} shows it again.
+
+@sp 1
+@strong{Q.} @emph{How do I get more informations about the keybindings
+of the currently active modes?}
+
+@strong{A.} Type @kbd{M-x describe-mode}.
+
+@sp 1
+@strong{Q.} @emph{How do I get automatic syntax higlighting of my
+custom types?}
+
+@strong{A.} Use a package named @file{ctypes.el} which does exactly
+that.
+
+@sp 1
+@strong{Q.} @emph{Is it possible to highlight dangerous syntax, just
+like Borland JBuilder does it?}
+
+@strong{A.} Yes, use the @file{cwarn.el} package.
+
+@sp 1
+@strong{Q.} @emph{How do I easily customize Emacs faces/colors?}
+
+@strong{A.} Use the @file{color-theme.el} package.
+
+@sp 1
+@strong{Q.} @emph{How do I set the taskbar Emacs identification string?}
+
+@strong{A.} To your @file{.emacs} add a line like:
+@example
+(setq frame-title-format "%b (%m)")
+@end example
+which will display ``filename (mode)'' type of string in the
+taskbar. Type @kbd{C-h v frame-title-format} to get more info.
+
+@sp 1
+@strong{Q.} @emph{Can I make Emacs jump to the matching parenthesis
+with @kbd{%} just like vi?}
+
+@strong{A.} Yes, just add to your @file{.emacs} something like:
+@example
+;; Make the % key jump to the matching {}[]() if on another, like VI
+(global-set-key "%" 'match-paren)
+
+(defun match-paren (arg)
+ "Go to the matching parenthesis if on parenthesis otherwise insert %."
+ (interactive "p")
+ (cond ((looking-at "\\s\(") (forward-list 1) (backward-char 1))
+ ((looking-at "\\s\)") (forward-char 1) (backward-list 1))
+ (t (self-insert-command (or arg 1)))))
+@end example
+
+@sp 1
+@strong{Q.} @emph{Can I have words like FIXME, TODO, HACK or NOTE
+higlighted in documentation strings?}
+
+@strong{A.} Yes, either use @file{code-keywords.el} package or wait
+till I'll add it to @kdeemacs{}.
+
+@sp 1
+@strong{Q.} @emph{I really, really hate identifiersNamedLikeThis. I'd
+like to change them to identifiers_named_like_this but the
+maintainer of the application/library that I'm hacking on doesn't
+agree with me. What can I do? }
+
+@strong{A.} Use the @file{glasses.el} package which changes
+identifiersNamedLikeThis to identifiers_named_like_this in the
+buffers you're editing and switches them back to their original form
+once you save those buffers.
+
+@sp 1
+@strong{Q.} @emph{Is it possible to get function completion or
+signature display in Emacs? Will it ever be done?}
+
+@strong{A.} Yes and yes. I've been planning on doing this for quite a
+while and hopefully will have this finished pretty soon (no dates
+though :) ) The first thing that should be done is writing a few
+fixes for the Semantic package (@file{c.bnf} to be more exact),
+because Semantic doesn't handle templates, member function declared
+as const or KDE access specifiers, once this is done all that will be
+left is using semanticdb package which efficiently stores and retrieves
+large amounts of tokens and then displaying tokens belonging to types at
+point which match current context.
+
+@sp 1
+@strong{Q.} @emph{Is there a package that would highlight changes that
+I made to a certain file?}
+
+@strong{A.} I wouldn't be writing this if there wouldn't - try
+@kbd{M-x highlight-changes-mode}.
+
+@sp 1
+@strong{Q.} @emph{How to get a diff between the stuff I have in my
+local buffer and the file on disk?}
+
+@strong{A.} Use ibuffer package. After @kbd{M-x ibuffer} typing
+@kbd{=} over a file will display a diff between the buffer and the
+file on the disk.
+
+@sp 1
+@strong{Q.} @emph{I want to temporarily highlight certain variable in
+a file, how to do it?}
+
+@strong{A.} Type @kbd{M-x hi-lock-mode}, now @kbd{C-x w h
+@emph{regexp} @key{RET} @emph{face} @key{RET}} highlights regexp with
+face in the current file and @kbd{C-x w r @emph{regexp} @key{RET}}
+unhighlights it.
+
+@node Concept Index, , Variables Index, Top
+@c node-name, next, previous, up
+@unnumbered Concept Index
+
+@printindex cp
+
+@contents
+@bye
diff --git a/scripts/kde-emacs/kde-emacs-utils.el b/scripts/kde-emacs/kde-emacs-utils.el
new file mode 100644
index 00000000..c6904539
--- /dev/null
+++ b/scripts/kde-emacs/kde-emacs-utils.el
@@ -0,0 +1,894 @@
+;; kde-emacs-utils.el
+;;
+;; Copyright (C) 2002-2005 KDE Development Team <www.kde.org>
+;;
+;; This library is free software; you can redistribute it and/or
+;; modify it under the terms of the GNU Lesser General Public
+;; License as published by the Free Software Foundation; either
+;; version 2.1 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
+;; Lesser General Public License for more details.
+;;
+;; You should have received a copy of the GNU Lesser General Public
+;; License along with this library; if not, write to the Free Software
+;; Foundation, Inc., 51 Franklin Steet, Fifth Floor, Boston, MA
+;; 02110-1301 USA
+
+
+(require 'kde-emacs-vars)
+(require 'kde-emacs-general)
+(require 'kde-emacs-compat)
+
+(if (eq kde-emacs-type 'xemacs)
+ (progn
+ (require 'func-menu)
+ (add-hook 'find-file-hooks 'fume-add-menubar-entry))
+ (require 'imenu))
+
+(defmacro c-safe-scan-lists (from count depth)
+ "Like `scan-lists' but returns nil instead of signalling errors.
+This function does not do any hidden buffer changes."
+ (if (featurep 'xemacs)
+ `(scan-lists ,from ,count ,depth nil t)
+ `(c-safe (scan-lists ,from ,count ,depth))))
+
+;; returns non-nil if the given file has a using declaration
+;; with the passed namespace
+(defun kde-file-has-using (namespace)
+ (let (found)
+ (save-excursion
+ (beginning-of-buffer)
+ (setq found (re-search-forward "^using" nil 1))
+ (if found
+ (setq found (search-forward namespace (line-end-position) 1))
+ )
+ )
+ found)
+ )
+
+;; returns non-nill if the given file has a "namespace SomeNM" declaration
+;; where SomeNM is passed via the namespace argument
+(defun kde-file-is-in-namespace (namespace)
+ (let (found)
+ (save-excursion
+ (beginning-of-buffer)
+ (setq found (re-search-forward "^namespace" nil 1))
+ (if found
+ (setq found (search-forward namespace (line-end-position) 1))
+ )
+ )
+ found)
+ )
+
+; Helper function for parsing our current position in a C++ header file
+; returns (namespace (class function)) where (a b) is a cons.
+(defun method-under-point ()
+ (let ((class nil)
+ (namespace "") ; will contain A::B::
+ (function nil))
+ (save-excursion
+ (backward-char) ; in case we're after the ';'
+ (search-forward ";" nil t) ; look for the ';'
+ (backward-char)
+ (save-excursion
+ ; Go up a level, skipping entire classes etc.
+ ; This is a modified version of (backward-up-list) which doesn't
+ ; throw an error when not found.
+ (let ((pos (c-safe-scan-lists (point) -1 1)))
+ ; +1 added here so that the regexp in the while matches the { too.
+ (goto-char (if pos (+ pos 1) (point-min))))
+ (while (re-search-backward "^[ ]*\\(class\\|namespace\\|struct\\)[ \t][^};]*{" nil t)
+ (save-excursion
+ (forward-word 1)
+ (when (looking-at "[ \t]*[A-Z_]*_EXPORT[A-Z_]*[ \t]")
+ (forward-word 1)
+ (re-search-forward "[ \t]" nil t))
+ (while (looking-at "[ \t]")
+ (forward-char 1))
+ (setq start (point))
+ ; Parse class name ("Foo" or "Foo::Bar::Blah").
+ ; Beware of "Foo:"
+ (while (or (looking-at "[A-Za-z0-9_]") (looking-at "::"))
+ (while (looking-at "[A-Za-z0-9_]")
+ (forward-char 1))
+ (while (looking-at "::")
+ (forward-char 2))
+ )
+ (cond
+ (class ; class found already, so the rest goes into the namespace
+ (setq namespace (concat (buffer-substring start (point)) "::" namespace)))
+ (t ; class==nil
+ (setq class (buffer-substring start (point)))))
+ )
+ ; Go up one level again
+ (let ((pos (c-safe-scan-lists (point) -1 1)))
+ (goto-char (if pos (+ pos 1) (point-min))))
+ ))
+
+ ; Back to where we were, parse function name
+ (let ((end (point))) ; remember where the function decl ends
+ (search-backward ")" nil t) ; look back for the end of the argument list
+ (forward-char)
+ (backward-sexp) ; brings us back to the '('
+ (backward-word 1)
+ (when (looking-at "throw[ \t]") ; exception specification, look for () again
+ (search-backward ")" nil t)
+ (forward-char)
+ (backward-sexp))
+ ; now that we moved back enough, go to beginning of line.
+ ; (we assume that the return type, function name, and '(' are on the same line)
+ (re-search-backward "^[ \t]*")
+ (while (looking-at "[ \t]")
+ (forward-char 1))
+ (setq function (buffer-substring (point) end))
+ )
+ ) ; end of global save-excursion
+ (cons namespace (cons class function)) ; the returned value
+ )
+ )
+
+; get rid of virtual, static, multiple spaces, default values.
+(defun canonical-function-sig (function)
+ (and (string-match "[ \t]*\\<virtual\\>[ \t]*" function)
+ (setq function (replace-match " " t t function)))
+ (and (string-match "^\\(virtual\\>\\)?[ \t]*" function)
+ (setq function (replace-match "" t t function)))
+ (and (string-match "^\\(explicit\\>\\)?[ \t]*" function)
+ (setq function (replace-match "" t t function)))
+ (and (string-match "^\\(static\\>\\)?[ \t]*" function)
+ (setq function (replace-match "" t t function)))
+ (while (string-match " +" function) ; simplifyWhiteSpace
+ (setq function (replace-match " " t t function)))
+ (while (string-match "\t+" function)
+ (setq function (replace-match " " t t function)))
+ (while (string-match "^ " function) ; remove leading whitespace
+ (setq function (replace-match "" t t function)))
+ (let ((startargs (string-match "(" function)))
+ (while (string-match " ?=[^,)]+" function startargs) ; remove default values
+ (setq function (replace-match " " t t function))))
+ (while (string-match " +," function) ; remove space before commas
+ (setq function (replace-match "," t t function)))
+ function ; the return value
+)
+
+; Helper method which turns the function as seen in the header
+; into the signature for its implementation
+; Returns the fully-qualified signature of the function implementation
+(defun kde-function-impl-sig (namespace class _function)
+ (let (
+ (function (canonical-function-sig _function))
+ (insertion-string nil))
+ (and (stringp class)
+ (cond
+ ((string-match (concat "^ *" class "[ \\t]*(") function) ; constructor
+ (setq insertion-string
+ (replace-match
+ (concat namespace class "::" class "(")
+ t t function)
+ ))
+ ((string-match (concat "^ *~" class "[ \\t]*(") function) ; destructor
+ (setq insertion-string
+ (replace-match
+ (concat namespace class "::~" class "(")
+ t t function)
+ ))
+ )) ; end of "class required"
+ (if (not (stringp insertion-string)) ; no ctor nor dtor
+ (if (or (string-match " *\\([a-zA-Z0-9_]+\\)[ \\t]*(" function) ; normal method
+ (string-match " *\\(operator[^ \\t]+\\)[ \\t]*(" function)) ; operator
+ (setq insertion-string
+ (replace-match
+ (if class
+ (concat " " namespace class "::" "\\1(") ; c++ method
+ (concat " " "\\1(")) ; c function
+ t nil function)
+ )
+ ; else
+ (error (concat "Can't parse declaration ``"
+ function "'' in class ``" class
+ "'', aborting"))))
+ insertion-string ; the return value
+ )
+ )
+
+;; Switch between the declaration of a class member in .cc/.cpp/.C, and its definition in the .h file
+;; Written by David and Reggie after much hair tearing
+;; Found since, might be worth looking at: http://www.hendawi.com/emacs/sourcepair.el
+(defun switch-to-function-def ()
+ (interactive)
+ (let ((n (buffer-file-name))
+ (namespace "")
+ (class "")
+ (function "")
+ found
+ )
+ (if (or (string-match "\\.cc$" n)
+ (string-match "\\.cpp$" n)
+ (string-match "\\.C$" n))
+ ; TODO replace fume-function-before-point, needed for emacs,
+ ; and for better namespace support.
+ ;(progn
+ ; (let ((pos (kde-scan-lists (point) -1 1 nil t))) ; Go up a level
+ ; (goto-char (if pos (+ pos 1) (point-min))))
+ (let ((a (fume-function-before-point)))
+ (and (string-match "^\\(.*\\)::\\(.*\\)$" a)
+ (progn
+ (setq class (match-string 1 a))
+ (setq function (match-string 2 a))
+ (kde-switch-cpp-h)
+ (goto-char 0)
+ ; Look for beginning of class ("\\s-+" means whitespace including newlines)
+ (re-search-forward
+ (concat "\\(class\\|struct\\|namespace\\)\\s-+"
+ "\\([A-Z_]+_EXPORT[A-Z_]*\\)?\\s-+" ; allow for optional EXPORT macro
+ class "\\b" ; the classname - with word separator
+ "[^;]+{" ; the optional inheritance and the '{'
+ ) nil t)
+ ;; TODO keep looking, until we find a match that's not inside a comment
+ (re-search-forward (concat "\\b" (kde-function-regexp-quote function) "[ \t]*(") nil t)))))
+ (if (string-match "\\.h$" n)
+ (progn
+ (let ((mup (method-under-point))
+ (sig "")
+ (pos 0))
+ (setq namespace (car mup))
+ (setq class (car (cdr mup)))
+ (setq function (cdr (cdr mup)))
+ (kde-switch-cpp-h)
+
+ ;; First search with namespace prefixed
+ (goto-char 0)
+ (setq sig (kde-remove-newline (kde-function-impl-sig namespace class function)))
+ (if (string-match "(.*" sig) ; remove args
+ (setq sig (replace-match "" nil t sig)))
+ (setq found (re-search-forward (concat "^[^()]*" (kde-function-regexp-quote sig) "[ \t]*(") nil t) )
+
+ (if (not found)
+ (progn
+ ; Now search without name space prefix
+
+ (goto-char 0)
+ (setq sig (kde-remove-newline (kde-function-impl-sig "" class function)))
+
+ (if (string-match "(.*" sig) ; remove args
+ (setq sig (replace-match "" nil t sig)))
+ (re-search-forward (concat "^[^()]*" (kde-function-regexp-quote sig) "[ \t]*(") nil t) ) )
+ )))))
+
+(defun kde-remove-newline (str)
+ (replace-in-string str "\n" " "))
+; quote for use as regexp, but replace spaces with "any whitespace"
+(defun kde-function-regexp-quote (str)
+ (replace-in-string (regexp-quote str) "[ \n\t]" "[ \n\t]"))
+
+; Initial implementation by Arnt Gulbransen
+; Current maintainer: David Faure
+(defun agulbra-make-member ()
+ "make a skeleton member function in the .cpp or .cc file"
+ (interactive)
+ (let* (
+ (mup (method-under-point))
+ (namespace (car mup)) ; will contain A::B::
+ (class (car (cdr mup)))
+ (function (cdr (cdr mup)))
+ (file (buffer-file-name))
+ (insertion-string (kde-function-impl-sig namespace class function))
+ (msubstr nil)
+ (start nil)
+ (newcppfile nil)
+ )
+ (setq insertion-string
+ (concat insertion-string "\n{\n"
+ (replace-in-string kde-make-member-default-impl "FUNCTION"
+ ; the function name and args, without newlines
+ (replace-in-string insertion-string "\n" " " t)
+ t)
+ "}\n"))
+ ; move to next method, to be ready for next call
+ (backward-char) ; in case we're after the ';'
+ (re-search-forward ";" nil t) ; end of this method decl
+ (let ((moveToNext t))
+ (while moveToNext
+ (re-search-forward ";" nil t) ; end of next method decl
+ (save-excursion
+ (forward-char -2) ; -1 goes to ';' itself, so go before that
+ (while (looking-at "[ \t0=]")
+ (forward-char -1))
+ (forward-char 1)
+ ; move to next method again if we're at a pure virtual method
+ (setq moveToNext (looking-at "[ \t]*=[ \t]*0;"))
+ )
+ )
+ )
+
+ (setq newcppfile (not (cdr (kde-file-get-cpp-h))))
+ (if (string-match "\\.h$" file)
+ (kde-switch-cpp-h)
+ )
+ (goto-char (point-max))
+ (kde-comments-begin)
+ (kde-skip-blank-lines)
+ (setq msubstr (buffer-substring (point-at-bol) (point-at-eol)))
+ (if (string-match "^#include.*moc.*" msubstr)
+ (progn
+ (forward-line -1)
+ (end-of-line)
+ (insert "\n")))
+ (if (string-match "}" msubstr)
+ (progn
+ (end-of-line)
+ (insert "\n")
+ (forward-line 1)
+ ))
+ (when newcppfile
+ (insert "\n"))
+ (insert insertion-string)
+ (forward-char -3)
+ (c-indent-defun)
+ (save-excursion
+ (and (string-match ".*/" file)
+ (setq file (replace-match "" t nil file)))
+ (and (string-match "\\.h$" file)
+ (functionp 'kdab-insert-include-file)
+ (kdab-insert-include-file file 't nil)))
+ (when (featurep 'fume-rescan-buffer)
+ (fume-rescan-buffer))
+ ))
+
+(defun add-file-to-buildsystem ()
+ "Add the current (C++) file to either Makefile.am or a .pro file, whichever exists."
+ ; Author: David
+ (interactive)
+ (if (file-readable-p "Makefile.am")
+ (add-file-to-makefile-am)
+ ; else: find a .pro file and add it there
+ (let* ((files (directory-files "." nil ".pro$" nil t))
+ (projfile (car files)))
+ (if projfile
+ (add-file-to-project projfile "^SOURCES[ \t]*") ; could be SOURCES= or SOURCES+=
+ ; else: error
+ (error "No build system file found")
+ )))
+ )
+
+; internal helper for add-file-to-*
+(defun add-file-to-project (makefile searchString)
+ (let ((file (buffer-name)))
+ (if (not (file-readable-p makefile))
+ (error (concat makefile " not found!"))
+ )
+ (find-file makefile)
+ (goto-char (point-min))
+ (if (re-search-forward searchString nil t)
+ (progn
+ (end-of-line)
+ ; check if line ends with '\' [had to read make-mode.el to find this one!]
+ (while (= (char-before) ?\\)
+ (end-of-line 2)) ; moves to end of next line
+ (insert " ")
+ (insert file)
+ )
+ (error (concat searchString " not found"))
+ ))
+ )
+
+(defun add-file-to-makefile-am ()
+ "Add the current file to the first _SOURCES line in the Makefile.am"
+ ; Author: David
+ (interactive)
+ (add-file-to-project "Makefile.am" "_SOURCES")
+ )
+
+
+; Inserts a kdDebug statement showing the name of the current method.
+; You need to create the empty line first.
+(defun insert-kdDebug ()
+ (interactive)
+ (insert "kdDebug() << ")
+ ;; no unnecessary fume-* functions which aren't available on GNU/Emacs
+ (insert "k_funcinfo")
+ (insert " << endl;")
+ )
+
+; finds a string to be used in the header-protection function ( see below )
+(defun kde-header-protection-definable-string ()
+ (let* ((definablestring "")
+ (f (buffer-file-name))
+ (parts (nreverse (split-string f "/")))
+ (i)
+ (first-iter t)
+ (iters (min (length parts) kde-header-protection-parts-to-show)))
+ (dotimes (i iters)
+ (let ((part (pop parts)))
+ (setq definablestring
+ (concat
+ (upcase (replace-in-string part "[\\.-]" "_"))
+ (if (not first-iter) "_" "")
+ definablestring
+ )
+ )
+ (setq first-iter nil)
+ )
+ )
+ definablestring
+ )
+ )
+
+; Creates the ifndef/define/endif statements necessary for a header file
+(defun header-protection ()
+ (interactive)
+ (let ((s (kde-header-protection-definable-string)))
+ (save-excursion
+ (goto-char (point-min))
+ (insert "#ifndef " s "\n#define " s "\n\n")
+ (goto-char (point-max))
+ (insert "\n#endif\n")
+ )
+ )
+ )
+
+; Makes '(' insert '(' or ' ( ' where appropiate
+(defun insert-parens (arg) (interactive "*P")
+ (if (not (c-in-literal))
+ (let ((n nil) (except nil))
+ (save-excursion
+ (setq n (or (progn (forward-char -2) (looking-at "if"))
+ (progn (forward-char -1) (looking-at "for"))
+ (progn (forward-char -1) (looking-at "case"))
+ (progn (forward-char -1) (looking-at "while"))
+ )
+ )
+ (setq except (or (progn (forward-char -2) (looking-at "kdDebug"))
+ (looking-at "kdError")
+ (progn (forward-char -2) (looking-at "kdWarning"))
+ )
+ )
+ )
+ (cond
+ (n (progn
+ (insert " ")
+ (self-insert-command (prefix-numeric-value arg))
+ (insert kde-emacs-after-parent-string)
+ ))
+ (t ;else
+ (self-insert-command (prefix-numeric-value arg))
+ (cond ((not except) (insert kde-emacs-after-parent-string)))
+ )))
+ (self-insert-command (prefix-numeric-value arg)))
+ )
+
+(defun insert-parens2 (arg) (interactive "*P")
+ (if (not (c-in-literal))
+ (let ((remv nil) (nospac nil))
+ (forward-char -2)
+ (setq remv (looking-at "( ")) ; () -> we'll have to remove that space
+ (forward-char 1)
+ (setq nospac ; no space to be added
+ (or (looking-at " ")
+ (looking-at "(")
+ (save-excursion ; check for kdDebug(123
+ (while (looking-at "[0-9]")
+ (forward-char -1))
+ (forward-char -7)
+ (or (looking-at "kdDebug(")
+ (looking-at "kdError(")
+ (progn (forward-char -2) (looking-at "kdWarning("))
+ )
+ )
+ )
+ )
+ (forward-char 1)
+ (cond
+ (remv (progn
+ (delete-backward-char 1)
+ (self-insert-command (prefix-numeric-value arg)))) ; the () case
+ (nospac (self-insert-command (prefix-numeric-value arg))) ; no space to be added
+ (t ;else
+ (if abbrev-mode ; XEmacs
+ (expand-abbrev))
+ (insert kde-emacs-after-parent-string)
+ (self-insert-command (prefix-numeric-value arg))
+ ))) ; normal case, prepend a space
+ ;;(blink-matching-open) ; show the matching parens
+ (self-insert-command (prefix-numeric-value arg)))
+ )
+
+; Makes ',' insert ', '
+(defun insert-comma (arg)
+ (interactive "*P")
+ (let* ((ch (char-after))
+ (spacep (not (or (eq ch ? )
+ (c-in-literal)
+ arg))))
+ (self-insert-command (prefix-numeric-value arg))
+ (if spacep
+ (insert " "))))
+
+(defun insert-semicolon (arg)
+ (interactive "*P")
+ (self-insert-command (prefix-numeric-value arg))
+ (newline-and-indent))
+
+(defun insert-curly-brace (arg) (interactive "*P")
+ (if (not (c-in-literal))
+ (let ((n nil) (o nil)
+ (spacep nil) (c nil)
+ (oneliner nil))
+ (save-excursion
+ (save-excursion
+ (if (re-search-forward "[a-zA-Z]" (point-at-eol) t)
+ (setq oneliner t)))
+ (forward-char -1) ; These three lines are for the situation where
+ (if (not (looking-at " ")) ; the user already have inserted a space after
+ (forward-char 1) ; the closing parenthesis
+ (setq spacep t))
+ (forward-char -2)
+ (setq o (looking-at "()"))
+ (forward-char 1)
+ (setq n (looking-at ")"))
+ (if (and
+ (not oneliner)
+ (not (eq
+ (count-lines (point-min) (point))
+ (count-lines (point-min) (point-max)))))
+ (progn
+ (next-line 1)
+ (beginning-of-line)
+ (if (re-search-forward "[a-zA-Z]" (point-at-eol) t)
+ (setq c (eq (car (car (c-guess-basic-syntax))) 'substatement)))
+ )
+ )
+ )
+ (cond
+ (n (progn
+ (if (not spacep) (insert " "))
+ (self-insert-command (prefix-numeric-value arg))
+ (if (not c) (newline-and-indent))
+ (if oneliner (end-of-line))
+ (save-excursion
+ (if c
+ (progn
+ (next-line 1)
+ (end-of-line)
+ ))
+ (newline-and-indent)
+ (insert "}")(c-indent-line))
+ (c-indent-line)
+ ))
+ (o (progn
+ (newline)
+ (self-insert-command (prefix-numeric-value arg))
+ (newline-and-indent)))
+ (t (progn ;else
+ (self-insert-command (prefix-numeric-value arg))
+ (save-excursion
+ (beginning-of-line)
+ (c-indent-command))))
+ ))
+ (self-insert-command (prefix-numeric-value arg))
+ )
+)
+
+;; have PelDel mode work
+(put 'insert-parens 'pending-delete t)
+(put 'insert-parens2 'pending-delete t)
+(put 'insert-comma 'pending-delete t)
+(put 'insert-curly-brace 'pending-delete t)
+(put 'newline-and-indent 'pending-delete t)
+
+; A wheel mouse that doesn't beep, unlike mwheel-install
+(defun scroll-me-up () (interactive) (scroll-up 4))
+(defun scroll-me-down () (interactive) (scroll-down 4))
+(defun scroll-me-up-a-bit () (interactive) (scroll-up 1))
+(defun scroll-me-down-a-bit () (interactive) (scroll-down 1))
+
+; Compilation
+(defun makeclean ()
+ "Executes a \"make clean\" in the current directory"
+ (interactive)
+ (compile (concat kde-emacs-make " clean"))
+ )
+
+(defun make ()
+ "Executes a \"make\" in the current directory"
+ (interactive)
+ (compile (concat kde-emacs-make " -k"))
+ )
+
+(defun makeinstall ()
+ "Executes a \"make install\" in the current directory"
+ (interactive)
+ (compile (concat kde-emacs-make " -k install"))
+ )
+
+(defun makeinstallexec ()
+ "Executes a \"make install-exec\" in the current directory"
+ (interactive)
+ (compile (concat kde-emacs-make " -k install-exec"))
+ )
+
+(defun makethisfile ()
+ "Try to compile the currently opened file"
+ (interactive)
+ (let ((f (file-name-nondirectory (buffer-file-name)))
+ (objext nil))
+
+ (if (file-readable-p "Makefile.am")
+ (setq objext "\.lo")
+ (setq objext "\.o"))
+ (if (string-match "\.cpp$" f) (setq f (replace-match objext t t f)))
+ (if (string-match "\.cc$" f) (setq f (replace-match objext t t f)))
+ (compile (concat kde-emacs-make " " f)))
+ )
+
+;; pc-like textmarking
+(when kde-use-pc-select
+ (progn
+ (load "pc-select")
+ (if (eq kde-emacs-type 'xemacs)
+ (funcall 'pc-select-mode)
+ (funcall 'pc-selection-mode))))
+
+
+; Move in other window
+(defun scroll-other-up () (interactive) (scroll-other-window-down 1)) ; hehe :)
+(defun scroll-other-down () (interactive) (scroll-other-window 1))
+
+(defun match-paren (arg)
+ "Go to the matching parenthesis if on parenthesis otherwise insert %."
+ (interactive "p")
+ (cond ((looking-at "\\s\(") (forward-list 1) (backward-char 1))
+ ((looking-at "\\s\)") (forward-char 1) (backward-list 1))
+ (t (self-insert-command (or arg 1)))))
+
+(defun kde-start-c++-header ()
+ "Start a new C++ header by inserting include guards ( see \
+ header-protection function ), inserting a license statement \
+ and putting (point) at the correct position"
+ (interactive)
+ (header-protection)
+ (insert "\n")
+ (beginning-of-buffer)
+ (kde-license-insert "GNU GPL")
+ (next-line 1)
+ (kill-line)
+ (end-of-buffer)
+ (next-line -3)
+ (insert "\n")
+)
+
+(defun kde-year-range-parse-years-string (string)
+ "parses something like \"2000, 2008-2010\" into a list of the form \
+ ((2008 . 2010)(2000 . 2000))"
+ (let ((pos -1)
+ (oldpos)
+ (l (length string))
+ (currange "")
+ (startyear)
+ (endyear)
+ (ret)
+ )
+ (while (< pos l)
+ (setq oldpos (+ pos 1))
+ (setq pos (string-match "[,]" string (+ pos 1)))
+ (unless pos (setq pos l))
+ (setq currange (substring string oldpos pos))
+ (string-match "[0-9]+" currange)
+ (setq startyear (string-to-int (match-string 0 currange)))
+ (setq endyear
+ (if (string-match "-" currange)
+ (string-to-int (substring currange (match-end 0)))
+ startyear))
+ (setq ret (cons (cons startyear endyear) ret))
+ )
+ ret
+ )
+ )
+
+(defun kde-year-range-contains-year (ranges year)
+ "checks whether year is in ranges.. ( ranges is a list as \
+ kde-year-range-parse-years-string returns.. "
+ (let ((ret))
+ (dolist (range ranges ret)
+ (when (and (>= year (car range)) (<= year (cdr range)))
+ (setq ret t))
+ )))
+
+(defun kde-year-range-to-string (ranges)
+ "converts ranges to a string.."
+ (let ((ret ""))
+ (dolist (range ranges)
+ (setq ret
+ (concat
+ (int-to-string (car range))
+ (if (/= (cdr range) (car range))
+ (concat "-" (int-to-string (cdr range)))
+ "")
+ ", "
+ ret)
+ )
+ )
+ ; remove extraneous ", "
+ (setq ret (substring ret 0 (- (length ret) 2)))
+ )
+ )
+
+; merges adjacent year ranges into one..
+(defun kde-year-range-cleanup (range)
+ (let ((origrange range))
+ (while (and range (cdr range))
+ (let ((years (car range)) (nyears (cadr range)))
+ (when (>= (+ (cdr nyears) 1) (car nyears))
+ (setcar range (cons (car nyears) (cdr years)))
+ (setcdr range (cddr range)))
+ )
+ (setq range (cdr range))
+ )
+ origrange
+ )
+ )
+
+; adds year to range..
+(defun kde-year-range-add-year (range year)
+ (while range
+ (let ((years (car range)))
+ (cond
+ ((and (>= year (car years)) (<= year (cdr years))
+ ; year is already in the range..
+ (setq range nil)))
+ ((= year (+ (cdr years) 1))
+ (setcdr years year)
+ (setq range nil))
+ ((= year (- (car years) 1))
+ (setcar years year)
+ (setq range nil))
+ )
+ )
+ (setq range (cdr range))
+ )
+ (kde-year-range-cleanup range)
+ )
+
+(defun kde-add-copyright () (interactive)
+ "Tries to add your kde-full-name and kde-email to the Copyright \
+ statements at the top of a file... It tries to figure out \
+ if it's already there, and if so, updates the line to include the \
+ current year.. ( well, replaces it by a new one, anyway :) )"
+ (let ((wascomment ""))
+ (save-excursion
+ (beginning-of-buffer)
+ (if (re-search-forward (concat "Copyright ([Cc]) \\([0-9 ,-]*\\) " (regexp-quote kde-full-name)) nil t)
+ (progn
+ (beginning-of-line)
+ (let ((years (kde-year-range-cleanup (kde-year-range-parse-years-string (match-string 1))))
+ (new-copyright-string "Copyright (C) ")
+ (this-year (string-to-int (format-time-string "%Y"))))
+ (when (not (kde-year-range-contains-year years this-year))
+ (kde-year-range-add-year years this-year))
+ (setq new-copyright-string
+ (concat new-copyright-string (kde-year-range-to-string years)))
+ ; finish new-copyright-string
+ (setq new-copyright-string
+ (concat new-copyright-string " " kde-full-name " <" kde-email ">"))
+ (beginning-of-line)
+ (re-search-forward "Copyright ([Cc])")
+ (beginning-of-line)
+ (setq wascomment
+ (buffer-substring (point)
+ (match-beginning 0)
+ ))
+ (kill-line nil)
+ (insert new-copyright-string)
+ )
+ )
+ (beginning-of-buffer)
+ (let ((first-copyright-str (re-search-forward "Copyright ([Cc])" nil t)))
+ (if first-copyright-str
+ (progn
+ (goto-char first-copyright-str)
+ (beginning-of-line)
+ (setq wascomment (buffer-substring (point) (match-beginning 0)))
+ (forward-line 1)
+ )
+ (goto-line 2))
+ )
+ (beginning-of-line)
+ (insert "Copyright (C) " (format-time-string "%Y") " "
+ kde-full-name " <" kde-email ">\n")
+ (forward-line -1)
+ )
+ (end-of-line)
+ (let ((end (point)))
+ (beginning-of-line)
+ (insert wascomment)
+ )
+ )
+ )
+ )
+
+(defun kde-emacs-file-style-update ()
+ "Updates the style header of this file"
+ (interactive)
+ (if (or (eq major-mode 'c++-mode)
+ (eq major-mode 'c-mode))
+ (let ((startpoint) (endpoint)
+ (firstline) (strings)
+ (str) (m) (m2) (var) (value)
+ (final))
+ (save-excursion
+ (beginning-of-buffer)
+ (setq startpoint (point))
+ (setq endpoint (point-at-eol)))
+ (setq firstline (buffer-substring startpoint endpoint))
+ (if (string-match "-\*-\\([A-Za-z0-9\-\+\:\; ]+\\)-\*-" firstline)
+ (delete-region startpoint endpoint))
+ (setq final (concat "-*- "
+ "Mode: " mode-name "; "
+ "c-basic-offset: " (prin1-to-string c-basic-offset) "; "
+ "indent-tabs-mode: " (prin1-to-string indent-tabs-mode) "; "
+ "tab-width: " (prin1-to-string tab-width) "; "
+ "-*-"))
+ (save-excursion
+ (beginning-of-buffer)
+ (insert final)
+ (comment-region (point-at-bol) (point-at-eol))
+ (newline)))))
+
+; Helper for qt-open-header, for Qt 4. Opens a file if it says #include "../foo/bar.h",
+; close it and open that file instead; recursively until finding a real file.
+(defun qt-follow-includes (file)
+ (let ((line "")
+ (begin nil)
+ (buffer nil))
+ (find-file file)
+ (goto-char 0)
+ (if (looking-at "#include \"")
+ (progn
+ (forward-char 10)
+ (setq begin (point))
+ (re-search-forward "\"" nil t)
+ (backward-char 1)
+ (setq file (buffer-substring begin (point)))
+ (setq buffer (current-buffer))
+ (qt-follow-includes file)
+ (kill-buffer buffer)
+ )
+ ; else: this is the right file, skip the comments and go to the class
+ (progn
+ (re-search-forward "^class" nil t)
+ (beginning-of-line))
+ )))
+
+(defun qt-open-header ()
+ "Open the Qt header file for the class under point"
+ (interactive)
+ (let* ((qtinc (concat (getenv "QTDIR") "/include/"))
+ (class (thing-at-point 'word))
+ (f nil)
+ (file nil)
+ (files nil)
+ )
+ (save-excursion
+ ; The Qt3 case: the includes are directly in $QTDIR/include/, lowercased
+ (setq f (concat qtinc (downcase class) ".h" ))
+ (if (file-readable-p f)
+ (setq file f)
+ ; For some Qt3/e classes: add _qws
+ (setq f (concat qtinc (downcase class) "_qws.h" ))
+ (if (file-readable-p f)
+ (setq file f)
+ ; The Qt4 case: the includes are in $QTDIR/include/QSomething/, in original case
+ (setq files (directory-files qtinc t nil "dirsonly"))
+ (dolist (f files nil)
+ (if (file-readable-p (concat f "/" class) )
+ (setq file (concat f "/" class))))
+ ))
+ (and file
+ (qt-follow-includes file))
+ )
+ ))
+
+(provide 'kde-emacs-utils)
diff --git a/scripts/kde-emacs/kde-emacs-vars.el b/scripts/kde-emacs/kde-emacs-vars.el
new file mode 100644
index 00000000..216e64f5
--- /dev/null
+++ b/scripts/kde-emacs/kde-emacs-vars.el
@@ -0,0 +1,147 @@
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; kde-emacs-vars.el ;;
+;; ;;
+;; Copyright (C) 2002 Zack Rusin <zack@kde.org> ;;
+;; ;;
+;; This program is free software; you can redistribute it and/or ;;
+;; modify it under the terms of the 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, write to the Free Software ;;
+;; Foundation, Inc., 51 Franklin Steet, Fifth Floor, Boston, MA ;;
+;; 02110-1301, USA. ;;
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+(defconst kde-emacs-version "0.2"
+ "KDE Emacs package version number.")
+(defun kde-emacs-version ()
+ "Returns the version of KDE Emacs package."
+ (interactive)
+ (message "KDE Emacs version : %s" kde-emacs-version))
+
+
+(defvar kde-emacs-type
+ (eval-when-compile
+ (if (string-match "XEmacs" (emacs-version))
+ 'xemacs
+ 'emacs))
+ "The type of Emacs we are running on.")
+
+;*---------------------------------------------------------------------*/
+;* Constants ... */
+;*---------------------------------------------------------------------*/
+
+(defconst kde-access-labels
+ "\\<\\(signals\\|k_dcop\\|\\(public\\|protected\\|private\\)\\([ ]+slots\\)?\\)\\>:"
+ "KDE specific access labels regexp.")
+
+(defconst kde-source-files '("cpp" "cc" "cxx" "CC" "C" "c")
+ "List of source-file extensions.")
+
+(defconst kde-header-files '("h" "H" "hh" "hxx" "hpp")
+ "List of header-file extensions.")
+
+;*---------------------------------------------------------------------*/
+;* Group ... */
+;*---------------------------------------------------------------------*/
+(defgroup kde-devel nil
+ "Development utilities."
+ :tag "KDE devel"
+ :prefix "kdedevel-"
+ :group 'programming)
+
+(defcustom kde-full-name (or user-full-name
+ (getenv "USER")
+ "Your Name")
+ "*Name used by kde-emacs."
+ :group 'kde-devel
+ :version "0.1"
+ :type 'string)
+
+(defcustom kde-email (or user-mail-address
+ (concat (getenv "LOGNAME") "@" (getenv "HOSTNAME"))
+ "Your Email")
+ "*Email address used by kde-emacs."
+ :group 'kde-devel
+ :version "0.1"
+ :type 'string)
+
+(defcustom kde-cvs-root (concat (getenv "HOME") "/cvs/kde")
+ "*Root Directory of KDE CVS Respiratory"
+ :group 'kde-devel
+ :type 'string)
+
+(defcustom magic-keys-mode 't
+ "Set this variable to true to have some special keybindings. E.g. bind '(' to a function which inserts '( ' when appropriate..."
+ :group 'kde-devel
+ :type 'boolean)
+
+(defcustom kde-emacs-make "make"
+ "Specifies the make command which KDE Emacs will use"
+ :group 'kde-devel
+ :type 'string)
+
+;;Make styles a list of the format (radio (const kde-c++) (const kde-c) style)
+;;and assign it to type.
+(defcustom kde-c++-style "kde-c++"
+ "Set this variable to the CC Mode style you would like loaded when you open a C++ KDE source code file..."
+ :group 'kde-devel
+ :type 'string)
+
+(defcustom kde-c-style "kde-c"
+ "Set this variable to the CC Mode style you would like loaded when you open a C KDE source code file..."
+ :group 'kde-devel
+ :type 'string)
+
+(defcustom kde-use-pc-select 't
+ "Set this to nil if you really hate PC Select Mode..."
+ :group 'kde-devel
+ :type 'boolean)
+
+(defcustom kde-emacs-newline-semicolon nil
+ "Set this to true to have typing \";\" automatically insert
+a newline."
+ :group 'kde-devel
+ :type 'boolean)
+
+(defcustom kde-header-protection-parts-to-show 1
+ "Set this variable to the number of parts from the file name you want to be used for the defined word in the
+header-protection function.. E.g. setting this to 3 makes header-protection define KIG_MISC_NEWTYPE_H for a
+file named /home/domi/src/kdenonbeta/kig/misc/newtype.h"
+ :group 'kde-devel
+ :type 'integer)
+
+(defcustom kde-emacs-after-parent-string " "
+ "Set this to whatever you want to have inserted after the first parenthesis. Works only if
+magic-keys-mode is set to true. "
+ :group 'kde-devel
+ :type 'string)
+
+(defcustom kde-include-directory nil
+ "Set this to the directory holding the includes for the current module/project/whatever."
+ :group 'kde-devel
+ :type 'string)
+
+(defcustom kde-source-directory nil
+ "Set this to the directory holding the sources for the current module/project/whatever."
+ :group 'kde-devel
+ :type 'string)
+
+(defcustom kde-make-member-default-impl " \n"
+ "Default implementation added by agulbra-make-member. FUNCTION gets replaced by the full signature of the function/method."
+ :group 'kde-devel
+ :type 'string)
+
+; a grep in the part of kde-source I have gives:
+; 5579 files uses .cpp, 1402 uses .cc, 10 uses .cxx, and 1 uses .C
+(defconst kde-prefered-source-extension "cpp"
+ "Source extension which kde-* functions should use for creating new files.")
+
+(provide 'kde-emacs-vars)
diff --git a/scripts/kde-emacs/kde-emacs.el b/scripts/kde-emacs/kde-emacs.el
new file mode 100644
index 00000000..b2865c53
--- /dev/null
+++ b/scripts/kde-emacs/kde-emacs.el
@@ -0,0 +1,66 @@
+;; kde-emacs.el
+;; Time-stamp: <2002-06-26 00:49:48 zack>
+;;
+;; Copyright (C) 2002 Zack Rusin <zackrat@att.net>
+;;
+;; This library is free software; you can redistribute it and/or
+;; modify it under the terms of the GNU Lesser General Public
+;; License as published by the Free Software Foundation; either
+;; version 2.1 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
+;; Lesser General Public License for more details.
+;;
+;; You should have received a copy of the GNU Lesser General Public
+;; License along with this library; if not, write to the Free Software
+;; Foundation, Inc., 51 Franklin Steet, Fifth Floor, Boston, MA
+;; 02110-1301 USA
+
+;;; Installation:
+;;
+;; Put the following lines in your ".emacs":
+;; (add-to-list 'load-path "~/path-to-kde-emacs")
+;; (require 'kde-emacs)
+;;
+;; I also strongly recommend to add the following two lines to
+;; .emacs file:
+;; (setq kde-full-name "Your Name")
+;; (setq kde-email "Your Email")
+;;
+;; You may want to byte-compile the package to speed it up
+;; a bit. To do it in the *scratch* buffer type in the following
+;; line:
+;; (byte-recompile-directory "~/kde-emacs" t)
+;; place the cursor after the closing paren and hit "Ctrl-x Ctrl-e",
+;; that's it.
+;;
+;; All keybindings are in kde-emacs-bindings.el, look at/customize
+;; this file before byte-compiling the package!
+;; If you want to see things you can customize type:
+;; M-x customize-group
+;; and type in "kde-devel" group.
+;;
+;; TODO:
+;; - in (if kde-emacs-type... change direct function calls
+;; to funcall's
+;;
+
+(require 'cc-mode) ;; needed by kde-emacs-core's test on c-version
+
+(require 'kde-emacs-compat)
+(require 'kde-emacs-core)
+(require 'kde-emacs-general)
+(require 'klaralv)
+(require 'kde-emacs-utils)
+(require 'dirvars)
+
+;; load this only if semantic package is present
+(when (featurep 'semantic)
+ (require 'kde-emacs-semantic)
+ (require 'kde-emacs-doc))
+
+(require 'kde-emacs-bindings)
+
+(provide 'kde-emacs)
diff --git a/scripts/kde-emacs/klaralv.el b/scripts/kde-emacs/klaralv.el
new file mode 100644
index 00000000..df29ff78
--- /dev/null
+++ b/scripts/kde-emacs/klaralv.el
@@ -0,0 +1,422 @@
+;; ------------------------------ COPYRIGHT NOTICE ------------------------------
+;; klaralv.el version 1.3
+;; Copyright Klaralvdalens Datakonsult AB.
+;;
+;; This program is free software; you can redistribute it and/or modify it
+;; under the terms of the 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 GNU Emacs. If you did not, write to the Free Software Foundation,
+;; Inc., 675 Mass Ave., Cambridge, MA 02139, USA.
+
+
+;; ------------------------------ INSTALLATION ------------------------------
+;; To use this file, add the current directory to your load path.
+;; you do this by inserting something like the following to your .emacs:
+;; (setq load-path (cons "/home/blackie/Emacs/" load-path))
+;;
+;; Next insert the following line into your .emacs
+;; (require 'klaralv)
+;; (global-set-key [(f5)] 'kdab-insert-header)
+;; (global-set-key [(shift f5)] 'kdab-insert-forward-decl)
+;; (setq kdab-qt-documentation "file://usr/local/qt/html/doc/XXX.html")
+;; (global-set-key [(control f5)] 'kdab-lookup-qt-documentation)
+;;
+;; If you use QTopia, and do not want include files to be prefixed with qpe/,
+;; as in qpe/qpeapplication, then insert the following code in your setup
+;; (setq kdab-prefix-qpe nil)
+
+;; ------------------------------ CONFIGURATION ------------------------------
+(defvar kdab-qt-documentation
+ "http://doc.trolltech.com/3.0/XXX.html"
+ "URL for Qt documentation. XXX must be in the string.
+ Example: file://packages/kde-src/qt-copy/doc/html/XXX.html")
+
+(defvar kdab-qpe-documentation
+ "file://opt/qtopia/doc/XXX.html"
+ "URL for QTopia documentatin. XXX must be in the string.
+ Example: file:/opt/qtopia/doc/XXX.html")
+
+
+(defvar kdab-prefix-qpe 't
+ "set this to nil if you do not want QPE header files prefixed with qpe/")
+
+;; special case for include files
+;; Please notify blackie@klaralvdalens-datakonsult.se with any modification to this variable!
+(defvar kdab-special-includes
+ '(
+ (qlayout.h QHBoxLayout QVBoxLayout QGridLayout QBoxLayout)
+ (qlistview.h QListViewItem QCheckListItem QListViewItemIterator)
+ (qiconview.h QIconViewItem QIconDragItem QIconDrag)
+ (qdragobject.h QTextDrag QStoredDrag QUriDag QColorDrag QImageDrag QDragManager)
+ (qmime.h QMimeSource QMimeSourceFactory QWindowsMime)
+ (qptrlist.h QPtrListIterator)
+ (qevent.h QTimerEvent QMouseEvent QWheelEvent QTabletEvent QKeyEvent
+ QFocusEvent QPaintEvent QMoveEvent QResizeEvent QCloseEvent
+ QShowEvent QHideEvent QContextMenuEvent QIMEvent QDropEvent
+ QDragMoveEvent QDragEnterEvent QDragResponseEvent QDragLeaveEvent
+ QChildEvent QCustomEvent)
+ (qdatetime.h QTime QDateTime QDate)
+ (qdatetimeedit.h QTimeEdit QDateTimeEditBase QDateEdit QDateTimeEdit)
+ (qcstring.h QByteArray)
+ (qobjectlist.h QObjectListIt QObjectListIterator)
+ (qwidgetlist.h QWidgetListIt)
+ (qtabbar.h QTab)
+ (qpalette.h QColorGroup)
+ (qaction.h QActionGroup)
+ (qvalidator.h QIntValidator QDoubleValidator QRegExpValidator)
+ (qlistbox.h QListBoxItem QListBoxText QListBoxPixmap)
+ (qstring.h QChar QCharRef QConstString)
+ (qcanvas.h QCanvasSprite QCanvasPolygonalItem QCanvasRectangle
+ QCanvasPolygon QCanvasEllipse QCanvasText QCanvasLine
+ QCanvasChunk QCanvas QCanvasItem QCanvasView QCanvasPixmap)
+ (qgl.h QGLFormat QGL QGLContext QGLWidget QGLColormap)
+ (qtable.h QTableSelection QTableItem QComboTableItem QCheckTableItem)
+ (qsqlfield.h QSqlField QSqlFieldInfo)
+ (qsqlrecord.h QSqlRecord QSqlRecordInfo)
+
+ ; Qt/Embedded
+ (qcopchannel_qws.h QCopChannel)
+ (qdirectpainter_qws.h QDirectPainter)
+ (qfontfactorybdf_qws.h QFontFactoryBDF)
+ (qfontfactoryttf_qws.h QFontFactoryFT)
+ (qfontmanager_qws.h QGlyphMetrics QGlyph QRenderedFont QDiskFont QFontManager QFontFactory)
+ (qgfx_qws.h QScreenCursor QPoolEntry QScreen QGfx)
+ (qgfxlinuxfb_qws.h QLinuxFbScreen)
+ (qgfxmatroxdefs_qws.h QQnxFbGfx QQnxScreen)
+ (qgfxraster_qws.h QGfxRasterBase QGfxRaster)
+ (qgfxvnc_qws.h QRfbRect QRfbPixelFormat QRfbServerInit QRfbSetEncodings
+ QRfbFrameBufferUpdateRequest QRfbKeyEvent QRfbPointerEvent QRfbClientCutText QVNCServer)
+ (qkeyboard_qws.h QWSKeyboardHandler)
+ (qlock_qws.h QLock QLockHolder)
+ (qmemorymanager_qws.h QMemoryManagerPixmap QMemoryManager)
+ (qsoundqss_qws.h QWSSoundServer QWSSoundClient QWSSoundServerClient QWSSoundServerSocket)
+ (qwindowsystem_qws.h QWSInternalWindowInfo QWSScreenSaver QWSWindow QWSSoundServer
+ QWSServer QWSServer KeyboardFilter QWSClient)
+ (qwsbeosdecoration_qws.h QWSBeOSDecoration)
+ (qwscursor_qws.h QWSCursor)
+ (qwsdecoration_qws.h QWSDecoration)
+ (qwsdefaultdecoration_qws.h QWSDefaultDecoration)
+ (qwsdisplay_qws.h QWSWindowInfo QWSDisplay)
+ (qwshydrodecoration_qws.h QWSHydroDecoration)
+ (qwskde2decoration_qws.h QWSKDE2Decoration)
+ (qwskdedecoration_qws.h QWSKDEDecoration)
+ (qwsmanager_qws.h QWSManager QWSButton)
+ (qwsmouse_qws.h QWSPointerCalibrationData QWSMouseHandler QCalibratedMouseHandler
+ QAutoMouseHandlerPrivate QWSMouseHandlerPrivate QVrTPanelHandlerPrivate
+ QTPanelHandlerPrivate QYopyTPanelHandlerPrivate QCustomTPanelHandlerPrivate
+ QVFbMouseHandlerPrivate)
+ (qwsproperty_qws.h QWSPropertyManager)
+ (qwsregionmanager_qws.h QWSRegionManager)
+ (qwssocket_qws.h QWSSocket QWSServerSocket)
+ (qwswindowsdecoration_qws.h QWSWindowsDecoration)
+ (qstatusbar.h statusBar())
+
+ ; KDE
+ (kdebug.h kdDebug kdWarning kdError kdFatal kdBacktrace)
+ (kconfig.h KConfigGroup)
+ (kiconloader.h BarIcon SmallIcon DesktopIcon KIcon)
+ (kicondialog.h KIconCanvas KIconButton)
+ (knuminput.h KDoubleNumInput KIntNumInput)
+
+ ; KDGear - http://www.klaralvdalens-datakonsult.se
+ (KDCheckableGroupBox.h KDCheckableGroupBox)
+ (KDCheckableHGroupBox.h KDCheckableHGroupBox)
+ (KDCheckableVGroupBox.h KDCheckableVGroupBox)
+ (KDCloseableWidget.h KDCloseableWidget)
+ (KDConfigDialog.h KDConfigDialog)
+ (KDConfigWidget.h KDConfigWidget)
+ (KDDateWidget.h KDDateWidget KDDateTimeWidget)
+ (KDDirMonitor.h KDDirMonitor)
+ (KDGridWidget.h KDGridWidget)
+ (KDListBoxPair.h KDListBoxPair)
+ (KDMinimizeSplitter.h KDMinimizeSplitter)
+ (KDSearchableListBox.h KDSearchableListBox)
+ (KDSemiSizingControl.h KDSemiSizingControl)
+ (KDShowHideTableControl.h KDShowHideTableControl)
+ (KDSimpleSizingControl.h KDSimpleSizingControl)
+ (KDSizingControl.h KDSizingControl)
+ (KDStream.h KDStream)
+ (KDTimeWidget.h KDTimeWidget)
+
+ ; KDChart - http://www.klaralvdalens-datakonsult.se
+ (KDChart.h KDChart)
+ (KDChartAxisParams.h KDChartAxisParams)
+ (KDChartBaseSeries.h KDChartBaseSeries)
+ (KDChartCustomBox.h KDChartCustomBox)
+ (KDChartData.h KDChartData)
+ (KDChartEnums.h KDChartEnums)
+ (KDChartListTable.h KDChartListTableData KDChartListTablePrivate)
+ (KDChartNotEnoughSpaceException.h KDChartNotEnoughSpaceException)
+ (KDChartPainter.h KDChartPainter)
+ (KDChartParams.h KDChartFrameSettings KDChartParams ModeAndChart)
+ (KDChartPlaneSeries.h KDChartPlaneSeries)
+ (KDChartPropertySet.h KDChartPropertySet)
+ (KDChartSeriesCollection.h KDChartSeriesCollection)
+ (KDChartTable.h KDChartTableData)
+ (KDChartTableBase.h KDChartTableDataBase)
+ (KDChartTextPiece.h KDChartTextPiece)
+ (KDChartUnknownTypeException.h KDChartUnknownTypeException)
+ (KDChartVectorSeries.h KDChartVectorSeries)
+ (KDChartVectorTable.h KDChartVectorTableData KDChartVectorTablePrivate)
+ (KDChartWidget.h KDChartWidget)
+ (KDFrame.h KDFrame KDFrameCorner)
+ (KDFrameProfileSection.h KDFrameProfileSection)
+
+
+ ; Useful fake entries
+ (qapplication.h qApp)
+ (kapplication.h kapp)
+ (klocale.h i18n I18N_NOOP)
+ (kstandarddirs.h locate locateLocal)
+ (stdlib.h getenv)
+ (unistd.h unlink sleep usleep)
+ (iostream cout cerr)
+ (ctype.h isalnum isalpha isascii isblank iscntrl isdigit isgraph islower isprint ispunct isspace isupper isxdigit)
+ (qeventloop.h eventloop)
+
+ )
+ "List of special include files which do not follow the normal scheme")
+
+(defvar kdab-qpe-includes
+ '(
+ (alarmserver.h AlarmServer)
+ (applnk.h AppLnk DocLnk AppLnkSet DocLnkSet)
+ (calendar.h Calendar)
+ (categories.h CategoryGroup CategoryGroup Categories CheckedListView)
+ (categorymenu.h CategoryMenu)
+ (categoryselect.h CategoryCombo CategorySelect CategoryEdit CategoryWidget)
+ (config.h Config)
+ (contact.h Contact)
+ (database.h QWSDatabase DatabaseDefaultView Database DatabaseView DatabaseDefaultView)
+ (datebookdb.h DateBookDB)
+ (datebookmonth.h DateBookMonthHeader DayItemMonth DateBookMonthTable DateBookMonth DateButton)
+ (event.h Event EffectiveEvent EffectiveEventSizeSorter EffectiveEventTimeSorter)
+ (filemanager.h FileManager)
+ (fileselector.h FileSelectorItem FileSelector)
+ (finddialog.h FindDialog)
+ (fontdatabase.h FontDatabase)
+ (fontmanager.h FontManager)
+ (global.h Global)
+ (imageedit.h ImageEdit)
+ (inputmethodinterface.h InputMethodInterface)
+ (ir.h Ir)
+ (lightstyle.h LightStyle)
+ (lnkproperties.h LnkProperties)
+ (mediaplayerplugininterface.h MediaPlayerDecoder)
+ (menubutton.h MenuButton)
+ (mimetype.h MimeType)
+ (network.h Network)
+ (palmtoprecord.h Record)
+ (palmtopuidgen.h UidGen)
+ (password.h Password)
+ (power.h PowerStatus PowerStatusManager )
+ (process.h Process)
+ (qcopenvelope_qws.h QCopEnvelope)
+ (qdawg.h QDawg)
+ (qlibrary.h QLibrary)
+ (qpeapplication.h QPEApplication)
+ (qpedecoration_qws.h QPEDecoration QPEManager)
+ (qpedialog.h QPEDialogListener)
+ (qpemenubar.h QPEMenuToolFocusManager QPEMenuBar)
+ (qpemessagebox.h QPEMessageBox)
+ (qpestyle.h QPEStyle : public QWindowsStyle)
+ (qpetoolbar.h QPEToolBar)
+ (record.h Record)
+ (resource.h Resource)
+ (sound.h Sound)
+ (storage.h StorageInfo FileSystem)
+ (task.h Task)
+ (timeconversion.h TimeConversion)
+ (timestring.h DateFormat TimeString)
+ (tzselect.h TZCombo TimeZoneSelector)
+ ))
+
+;; ------------------------------ SOURCE CODE ------------------------------
+
+;; Merge in qpe classes
+(defun kdab-get-special-include-list ()
+ (let (elm header classes (list kdab-qpe-includes) filename (result kdab-special-includes))
+ (while list
+ (setq elm (car list))
+ (setq list (cdr list))
+ (setq filename (concat (if kdab-prefix-qpe "qpe/" "") (symbol-name (car elm))))
+ (setq result (cons (cons (intern filename) (cdr elm)) result)))
+ result))
+
+;; Lookup class `cls' in kdab-special-includes and return the associate include file name
+(defun kdab-map-special (cls)
+ (let ((list (kdab-get-special-include-list))
+ (found nil))
+ (while (and list (not found))
+ (let* ( (elm (car list))
+ (include-file (car elm))
+ (classes (cdr elm)))
+ ( while (and classes (not found))
+ (if (string= (downcase cls) (downcase (symbol-name (car classes))))
+ (setq found include-file)
+ (setq classes (cdr classes)))))
+ (setq list (cdr list)))
+ (if found
+ (symbol-name found)
+ nil) ; return value
+ ))
+
+
+
+;--------------------------------------------------------------------------------
+; Insert include file for Qt program.
+; Place point anywhere on a Qt class, and invoke this function. A result of
+; this is that an include line is added (if it does not already exists) for
+; the given class.
+;--------------------------------------------------------------------------------
+(defun kdab-insert-header ( prefix )
+ "Insert include file for class at point"
+ (interactive "P")
+ (save-excursion
+ (let* ((word-at-point (if prefix
+ (read-from-minibuffer "Class: ")
+ (current-word))))
+ (kdab-insert-header-non-interactive word-at-point))))
+
+;--------------------------------------------------------------------------------
+; insert include file for `word-with-case' non-interactively.
+; for an interactive version see kdab-insert-header
+;--------------------------------------------------------------------------------
+(defun kdab-insert-header-non-interactive (word-with-case)
+ (save-excursion
+ (let* ((word (downcase word-with-case))
+ (special-header (cond
+ ((kdab-map-special word) (kdab-map-special word))
+ ((string-match "^qdom" word) "qdom.h")
+ ((string-match "^qxml" word) "qxml.h")
+ (t (concat word ".h"))))
+ header is-local)
+
+
+ ;; decide on the header file.
+ (if (file-exists-p (concat word-with-case ".h"))
+ (progn ; file exists in given case in pwd.
+ (setq header (concat word-with-case ".h"))
+ (setq is-local 't))
+ (if (file-exists-p (concat word ".h")) ; file exists in lowercase in pwd
+ (progn
+ (setq header (concat word ".h"))
+ (setq is-local 't))
+ (progn ; header in <..> path
+ (setq header special-header)
+ (setq is-local nil))))
+
+ (kdab-insert-include-file header is-local t))))
+
+;--------------------------------------------------------------------------------
+; Insert header file for header. If is-local insert it with ""
+; otherwise insert it with <>
+;--------------------------------------------------------------------------------
+(defun kdab-insert-include-file (header is-local show-message)
+ (let ((include-file (if is-local
+ (concat "#include \"" header "\"")
+ (concat "#include <" header ">"))))
+
+ (beginning-of-buffer)
+ (if (re-search-forward (concat "^ *// *\\(#include *[<\"][ \t]*" header "[ \t]*[>\"]\\)") nil t)
+ (progn
+ (replace-match "\\1")
+ (when show-message
+ (message (concat "commented in #include for " header))))
+
+ (if (not (re-search-forward (concat "#include *[\"<][ \t]*" header "[ \t]*[\">]") nil t))
+ (progn
+ ; No include existed
+ (goto-char (point-max)) ; Using end-of-buffer makes point move, despite save-excursion
+ (if (not (re-search-backward "^#include *[\"<][^\">]+\.h *[\">]" nil t))
+ (beginning-of-buffer)
+ (progn (end-of-line) (forward-char 1)))
+
+ ;; Now insert the header
+ (insert (concat include-file "\n"))
+ (when show-message
+ (message (concat "inserted " include-file))))
+ (when show-message
+ (message (concat "header file \"" header "\" is already included")))))))
+
+
+
+;----------------------------------------------------------------------------
+; Insert a forward declaration for a Qt class.
+; Place point anywhere on a Qt class, and invoke this function. A
+; result of this is that a forward declaration line is added (if it does
+; not already exist) for the given class.
+;----------------------------------------------------------------------------
+(defun kdab-insert-forward-decl ( prefix )
+ (interactive "P")
+ (save-excursion
+ (let* ((word (if prefix (read-from-minibuffer "Class: ")
+ (current-word))))
+ (beginning-of-buffer)
+ (if (re-search-forward (concat "^ *// *\\(class *" word ";\\)") nil t)
+ (progn
+ (replace-match "\\1")
+ (message (concat "commented in forward declaration for " word)))
+
+ (if (not (re-search-forward (concat "class *" word ";") nil t))
+ (progn
+ ; No forward decl existed
+ ; Look for other forward declarations and insert this one before them
+ ; (this avoids finding class Private; inside a class, or other stuff in the middle of the file)
+ (if (re-search-forward "^[ \t]*class .*;" nil t)
+ (progn
+ ; Exit namespace foo { class bar; } if necessary
+ ; This is a modified version of (backward-up-list) which doesn't
+ ; throw an error when not found.
+ (goto-char (or (scan-lists (point) -1 1 nil t) (point))) ; ### do multiple times if necessary
+ (re-search-backward "^[ \t]*namespace " nil t) ; in case of namespace foo\n{
+ (beginning-of-line))
+ ; No forward declarations found, lets search for include lines.
+ ; For those we start from the end, because we want to leave file.h first.
+ (progn (goto-char (point-max))
+ (if (re-search-backward "#include" nil t)
+ (progn (end-of-line) (forward-char 1))
+ (beginning-of-buffer))))
+
+ (progn
+ (insert "class " word ";\n")
+ (message (concat "inserted class " word ";"))))
+ (message (concat "forward decl for \"" word "\" already exists")))))))
+
+
+(defun is-qpe-class (class)
+ (let ((list kdab-qpe-includes) classes (found nil))
+ (while (and (not found) list)
+ (setq classes (cdr (car list)))
+ (while classes
+ (if (string= (downcase (symbol-name (car classes))) (downcase class))
+ (setq found 't))
+ (setq classes (cdr classes)))
+ (setq list (cdr list)))
+ found))
+
+;--------------------------------------------------------------------------------
+; Start konqueror with documentation for the class under point.
+; set `kdab-qt-documentation' and `kdab-qpe-documentation'
+; to specify the replacement for the documentation
+;--------------------------------------------------------------------------------
+(defun kdab-lookup-qt-documentation ()
+ (interactive "")
+ (save-excursion
+ (let* ((word (downcase (current-word)))
+ (doc (if (is-qpe-class word) kdab-qpe-documentation kdab-qt-documentation))
+ (url (if (not (string-match "XXX" doc))
+ (error "didn't find three X's in kdab-qt-documentation or kdab-qpe-documentation")
+ (replace-match word t t doc))))
+ (start-process "qt documentation" nil "kfmclient" "openURL" url)
+ (message (concat "Loading " url)))))
+
+(provide 'klaralv)
diff --git a/scripts/kde-spellcheck.pl b/scripts/kde-spellcheck.pl
new file mode 100755
index 00000000..2a8974e0
--- /dev/null
+++ b/scripts/kde-spellcheck.pl
@@ -0,0 +1,1537 @@
+#! /usr/bin/env perl
+
+# CORRECTIONS GO IN THE __DATA__ SECTION AT THE END OF THIS SCRIPT
+
+# Checks and corrects common spelling errors in text files - code
+# derived from kde-spellcheck.pl (Dirk Mueller <mueller@kde.org>)
+#
+# Copyright (c) 2004 Richard Evans <rich@ridas.com>
+#
+# License: LGPL 2.0
+#
+# 2004-05-14: Richard Evans <rich@ridas.com>
+#
+# Initial revision differs from kde-spellcheck.pl as follows:
+#
+# Text file detection no longer spawns external program.
+# No longer checks cwd if arguments omitted - just specify '.'
+# No longer recurses through sub directories without --recurse.
+# Can now check internal dictionary for mistakes using aspell.
+# Changes are not made unless --make-changes is specified.
+# File modification now uses an intermediate file to reduce the
+# chance of data loss.
+# Fixed bug that missed words with apostrophes.
+# Removed the code checking for "nonword misspelling" - I don't
+# believe it was doing anything useful, but please correct me
+# if that's not the case!
+# Corrected some dictionary entries.
+# Runs much, much faster.
+
+sub usage
+{
+ warn <<"EOF";
+
+kde-spellcheck.pl [flags] filenames/directories
+
+This script checks for, and optionally replaces, commonly misspelled words
+with the correct US English equivalents. The behaviour has changed from
+kde-spellcheck.pl - to check subdirectories you must specify --recurse,
+omitting arguments does not check the current directory, and changes are
+not made to files unless you specify --make-changes
+
+CAUTION IS NEEDED WHEN USING THIS SCRIPT - changes are made to the original
+file and are not programming language syntax aware - this is why the script
+only suggests the changes to be made unless --make-changes is specified.
+
+Hidden files, CVS directories, .desktop, and .moc files are excluded
+from checking.
+
+--check-dictionary : Checks the internal dictionary for potential
+ spelling mistakes - requires aspell with a US
+ English dictionary, and Text::Aspell installed.
+
+--suggest-corrections : Behaves as --check-dictionary, but also suggests
+ spelling corrections.
+
+--recurse : Check subdirectories recursively.
+--quiet : Disable informational output (not recommended).
+--make-changes : Displays the changes that would have been made.
+--help|? : Display this summary.
+
+EOF
+
+ exit;
+}
+
+use strict;
+use warnings;
+use Getopt::Long;
+use File::Temp qw( tempfile );
+use File::Copy qw( copy );
+
+my $DICTIONARY = build_dictionary_lookup_table();
+
+###########################################################################################
+# Add options here as necessary - perldoc Getopt::Long for details on GetOptions
+
+die "kde-spellcheck2 --help for usage\n"
+ unless GetOptions ( "check-dictionary" => \my $opt_check_dictionary,
+ "suggest-corrections" => \my $opt_suggest_corrections,
+ "quiet" => \my $opt_quiet,
+ "make-changes" => \my $opt_make_changes,
+ "recurse" => \my $opt_recurse,
+ "help|?" => \&usage );
+
+check_dictionary($opt_suggest_corrections) if $opt_suggest_corrections or $opt_check_dictionary;
+
+usage() unless @ARGV;
+
+require File::MMagic;
+
+my $MIME = File::MMagic->new;
+
+my @dirqueue;
+
+$opt_quiet = 0 unless $opt_make_changes;
+
+sub info; *info = $opt_quiet ? sub {} : sub { print @_ };
+
+for ( @ARGV )
+{
+ if ( -f ) { check_file($_) }
+ elsif ( -d _ ) { push @dirqueue, $_ }
+ else { warn "Unknown: '$_' is neither a directory or file" }
+}
+
+my $dir;
+
+process_directory($dir) while $dir = pop @dirqueue;
+
+$opt_make_changes or print <<EOF;
+
+NB No changes have been made to any file. Please check the output to
+see if the suggested changes are correct - if so, re-run this script
+adding argument --make-changes
+
+EOF
+
+###########################################################################################
+
+sub check_file
+{
+ my $filename = shift;
+ my $fh;
+
+ unless ( open $fh, "<", $filename )
+ {
+ warn "Failed to open: '$filename': $!";
+ return;
+ }
+
+ my $file_modified = 0;
+ my @contents = <$fh>;
+
+ close $fh or warn "Failed to close: '$filename': $!";
+
+ my $original;
+ my $line_no = 0;
+
+ for ( @contents )
+ {
+ $line_no++;
+ $original = $_ unless $opt_make_changes;
+
+ for my $word ( split /[^\w']/ ) # \W would split on apostrophe
+ {
+ next unless defined (my $correction = $DICTIONARY->{$word});
+
+ $file_modified ||= 1;
+
+ s/\b$word\b/$correction/g;
+
+ info "$filename ($line_no): $word => $correction\n";
+ }
+
+ print "FROM: $original",
+ " TO: $_\n" if !$opt_make_changes and $_ ne $original;
+ }
+
+ return unless $file_modified;
+ return unless $opt_make_changes;
+
+ info "Correcting: $filename\n";
+
+ my ($tmp_fh, $tmp_filename) = tempfile(UNLINK => 0);
+
+ eval
+ {
+ print $tmp_fh @contents or die "Write";
+
+ $tmp_fh->flush or die "Flush";
+ $tmp_fh->seek(0, 0) or die "Seek";
+ };
+
+ die "$@ failed on: '$tmp_filename': $!" if $@;
+
+ copy($tmp_fh, $filename) or die "Failed to copy: $tmp_filename => $filename: $!\n",
+ "You can manually restore from: $tmp_filename";
+
+ close $tmp_fh or warn "Close failed on: '$tmp_filename': $!";
+ unlink $tmp_filename or warn "Unlink failed on: '$tmp_filename': $!";
+}
+
+
+# Could be more robustly rewitten with File::Find / File::Find::Rules etc
+
+sub process_directory
+{
+ my $directory = shift;
+
+ info "Processing directory: $directory\n";
+
+ opendir my $dh, $directory or die "Failed to read dir: '$directory': $!";
+
+ while ( my $entry = readdir($dh) )
+ {
+ if ( $entry =~ /^\./ or
+ $entry =~ /\.desktop$/ or
+ $entry =~ /\.moc$/ or
+ $entry eq "CVS" )
+ {
+ info "Skipping excluded file or directory: $entry\n";
+ next;
+ }
+
+ my $file = "$directory/$entry";
+
+ if ( -d $file )
+ {
+ push(@dirqueue, $file) if $opt_recurse;
+ next;
+ }
+
+ next unless -f _;
+
+ # First use perl's heuristic check to discard files as quickly as possible...
+
+ unless ( -T _ )
+ {
+ info "Skipping binary file: $file\n";
+ next;
+ }
+
+ # ...it's not always good enough though, so now check the Mimetype
+
+ unless ( (my $type = $MIME->checktype_filename($file)) =~ /text/i )
+ {
+ info "Skipping $type file: $file\n";
+ next;
+ }
+
+ check_file($file);
+ }
+
+ closedir $dh or warn "Failed to close dir: '$directory': $!";
+}
+
+
+########################################################################################################
+
+sub check_dictionary
+{
+ my $suggest_corrections = shift;
+
+ print <<EOF;
+
+Attempting to check the internal dictionary - you must have aspell
+and the perl module Text::Aspell installed for this to succeed,
+otherwise the script will fail at this point.
+
+EOF
+
+ require Text::Aspell;
+
+ my $speller = Text::Aspell->new or die "Failed to create Text::Aspell instance";
+
+ # Despite the docs, set_option doesnt seem to return undef on error ...
+
+ $speller->set_option('lang','en_US')
+ or die "Text::Aspell failed to select language: 'en_US'", $speller->errstr;
+
+ # ... so try a very simple check
+
+ unless ( $speller->check('color') )
+ {
+ warn "You dont appear to have the en_US dictionary installed - cannot check";
+ exit;
+ }
+
+ print "Checking Lexicon for identical misspelling and corrections:\n";
+
+ while ( my($key, $value) = each %$DICTIONARY )
+ {
+ print "\n$key" if $key eq $value;
+ }
+
+ print "\n\nChecking Lexicon for possible misspellings:\n\n";
+
+ for my $word ( values %$DICTIONARY )
+ {
+ next if $speller->check($word);
+
+ print "$word\n";
+ print join(", ", $speller->suggest($word)), "\n\n" if $suggest_corrections;
+ }
+
+ print "\n";
+
+ exit;
+}
+
+
+########################################################################################################
+
+sub build_dictionary_lookup_table
+{
+ my %hash;
+
+ while (<DATA>)
+ {
+ next if /^\s*$/ or /^\s*#/; # Skip blank lines and comments
+
+ next unless /^\s*"([^"]+)"\s+(.*)\s*$/ or /^\s*(\S+)\s+(.*)\s*$/;
+
+ if ( $1 eq $2 )
+ {
+ warn "WARNING: Ignoring identical misspelling and correction: '$1' in __DATA__ offset line $.\n";
+ next;
+ }
+
+ $hash{$1} = $2;
+ }
+
+ return \%hash;
+}
+
+__DATA__
+
+#INCORRECT SPELLING CORRECTION
+
+aasumes assumes
+abailable available
+Abbrevation Abbreviation
+abbrevations abbreviations
+abbriviate abbreviate
+abbriviation abbreviation
+abilties abilities
+Ablolute Absolute
+abreviate abbreviate
+acces access
+accesible accessible
+accesing accessing
+accomodate accommodate
+accross across
+Acess Access
+achive achieve
+achived achieved
+achiving achieving
+acknoledged acknowledged
+acknowledgement acknowledgment
+Acknowledgements Acknowledgments
+Acknowlege Acknowledge
+acommodate accommodate
+aconyms acronyms
+acording according
+acount account
+acouting accounting
+activ active
+actons actions
+acually actually
+adapater adapter
+adatper adapter
+addded added
+adddress address
+Additinoally Additionally
+additionaly additionally
+Additionaly Additionally
+additionnal additional
+additonal additional
+
+#INCORRECT SPELLING CORRECTION
+
+Addtional Additional
+aditional additional
+adminstrator administrator
+Adminstrator Administrator
+adress address
+Adress Address
+adressed addressed
+adresses addresses
+advertize advertise
+aesthetic esthetic
+Afganistan Afghanistan
+agressive aggressive
+Agressive Aggressive
+agressively aggressively
+alignement alignment
+alligned aligned
+Allignment Alignment
+allmost almost
+allready already
+allways always
+Allways Always
+alook a look
+alot a lot
+alows allows
+alrady already
+alreay already
+alternativly alternatively
+ammount amount
+Ammount Amount
+analagous analogous
+analizer analyzer
+analogue analog
+analyse analyze
+analyses analyzes
+anfer after
+angainst against
+annoucement announcement
+announcments announcements
+anwer answer
+anwser answer
+anwsers answers
+aplication application
+appeareance appearance
+appearence appearance
+appeares appears
+apperarance appearance
+appers appears
+
+#INCORRECT SPELLING CORRECTION
+
+applicaiton application
+Applicalble Applicable
+appliction application
+appplication application
+approciated appreciated
+appropiate appropriate
+approriate appropriate
+approximatly approximately
+apropriate appropriate
+aquire acquire
+aquired acquired
+arbitarily arbitrarily
+arbitary arbitrary
+Arbitary Arbitrary
+aribrary arbitrary
+aribtrarily arbitrarily
+aribtrary arbitrary
+arround around
+assosciated associated
+assosiated associated
+assoziated associated
+asssembler assembler
+assumend assumed
+asume assume
+asynchonous asynchronous
+asyncronous asynchronous
+aticles articles
+atleast at least
+atomicly atomically
+attatchment attachment
+auhor author
+authentification authentication
+authoratative authoritative
+authorisations authorizations
+automaticaly automatically
+Automaticaly Automatically
+automaticly automatically
+autoreplacment autoreplacement
+auxilary auxiliary
+Auxilary Auxiliary
+avaible available
+Avaible Available
+availble available
+availibility availability
+availible available
+Availible Available
+avaliable available
+avaluate evaluate
+avare aware
+aviable available
+backrefences backreferences
+baloon balloon
+basicly basically
+
+#INCORRECT SPELLING CORRECTION
+
+Basicly Basically
+beautifull beautiful
+becuase because
+beeep beep
+beeing being
+beexported be exported
+befor before
+beggining beginning
+begining beginning
+behaviour behavior
+Behaviour Behavior
+Belarussian Belarusian
+beteen between
+betrween between
+betweeen between
+Blueish Bluish
+bofore before
+botton bottom
+boudaries boundaries
+boundries boundaries
+boundry boundary
+boxs boxes
+bruning burning
+buton button
+Buxfixes Bugfixes
+cacheing caching
+calulation calculation
+cancelation cancellation
+cancelled canceled
+cancelling canceling
+capabilites capabilities
+caracters characters
+cataloge catalog
+Cataloge Catalog
+catalogue catalog
+catched caught
+ceneration generation
+centralised centralized
+centre center
+Centre Center
+changable changeable
+chaning changing
+characers characters
+charachters characters
+Characteres Characters
+charakters characters
+charater character
+Chatacter Character
+chatwindow chat window
+childs children
+choosed chose
+choosen chosen
+Choosen Chosen
+
+#INCORRECT SPELLING CORRECTION
+
+chosing choosing
+cirumstances circumstances
+classess classes
+cloumn column
+Coffie Coffee
+colaboration collaboration
+collecion collection
+collumns columns
+coloum column
+coloumn column
+colour color
+colours colors
+colum column
+comamnd command
+comination combination
+commense commence
+commerical commercial
+comming coming
+commited committed
+commiting committing
+Commiting Committing
+commmand command
+commuication communication
+communcation communication
+compability compatibility
+comparision comparison
+Comparision Comparison
+comparisions comparisons
+Compatability Compatibility
+compatibilty compatibility
+compatiblity compatibility
+Compedium Compendium
+compiiled compiled
+compleion completion
+completly completely
+complient compliant
+comsumer consumer
+comunication communication
+concatonated concatenated
+concurent concurrent
+configration configuration
+Configuraton Configuration
+connent connect
+connnection connection
+consecutivly consecutively
+consequtive consecutive
+constuctors constructors
+contactlist contact list
+containg containing
+contexual contextual
+contigious contiguous
+contingous contiguous
+continouos continuous
+
+#INCORRECT SPELLING CORRECTION
+
+continous continuous
+Continous Continuous
+contiribute contribute
+contoller controller
+Contorll Control
+controler controller
+controling controlling
+controll control
+conver convert
+convient convenient
+convinience convenience
+conviniently conveniently
+coordiator coordinator
+Copys Copies
+coresponding corresponding
+corrent correct
+correponds corresponds
+Costraints Constraints
+Coudn't Couldn't
+coursor cursor
+Coverted Converted
+coypright copyright
+cricles circles
+criticisim criticism
+cryptograhy cryptography
+Culculating Calculating
+curren current
+currenty currently
+curteousy courtesy
+Custimize Customize
+customisation customization
+customise customize
+Customise Customize
+customised customized
+cutsom custom
+cutt cut
+Cutt Cut
+datas data
+DCOPCient DCOPClient
+deactive deactivate
+Deamon Daemon
+debuging debugging
+Debuging Debugging
+decriptor descriptor
+defaul default
+defered deferred
+Defininition Definition
+defintions definitions
+deleteing deleting
+Demonsrative Demonstrative
+Denstiy Density
+depencies dependencies
+
+#INCORRECT SPELLING CORRECTION
+
+dependeds depends
+dependend dependent
+dependig depending
+depricated deprecated
+derfined defined
+derivs derives
+descide decide
+desciptor descriptor
+descryption description
+desctroyed destroyed
+desiabled disabled
+desidered desired
+desination destination
+deskop desktop
+desription description
+Desription Description
+destiantion destination
+determiend determined
+determins determines
+detremines determines
+develloped developed
+developerss developers
+developped developed
+devided divided
+devide divide
+diabled disabled
+diable disable
+diaglostic diagnostic
+dialag dialog
+dialler dialer
+Dialler Dialer
+dialling dialing
+Dialling Dialing
+dialogue dialog
+diaog dialog
+didnt didn't
+diffcult difficult
+differenciate differentiate
+differenly differently
+Differntiates Differentiates
+dificulty difficulty
+Difusion Diffusion
+digitised digitized
+diplayed displayed
+dirctely directly
+dirctory directory
+direcory directory
+directorys directories
+directoy directory
+disactivate deactivate
+disappers disappears
+Disbale Disable
+
+#INCORRECT SPELLING CORRECTION
+
+discontigous discontiguous
+discpline discipline
+discription description
+disppear disappear
+dissassembler disassembler
+distingush distinguish
+distribtuion distribution
+distrubutor distributor
+divizor divisor
+docucument document
+documentaiton documentation
+documentors documenters
+doens't doesn't
+doesnt doesn't
+donnot do not
+Donot Do not
+dont don't
+dont't don't
+Dou Do
+draging dragging
+dreamt dreamed
+Droped Dropped
+duotes quotes
+durring during
+dynamicly dynamically
+eallocate deallocate
+eample example
+editory editor
+efficent efficient
+efficently efficiently
+effiency efficiency
+embedabble embeddable
+embedable embeddable
+embeddabble embeddable
+embeded embedded
+emcompass encompass
+emty empty
+encyption encryption
+enhandcements enhancements
+enles endless
+enought enough
+entitities entities
+entrys entries
+Entrys Entries
+enumarated enumerated
+envirnment environment
+envirnoment environment
+enviroment environment
+environemnt environment
+environent environment
+Equador Ecuador
+equiped equipped
+equlas equals
+
+#INCORRECT SPELLING CORRECTION
+
+errorous erroneous
+errror error
+escriptor descriptor
+espacially especially
+espesially especially
+Evalute Evaluate
+everytime every time
+exacly exactly
+exapmle example
+excecpt except
+execeeded exceeded
+execess excess
+exection execution
+execuable executable
+executeble executable
+exept except
+exisiting existing
+existance existence
+exlusively exclusively
+exmaple example
+experienceing experiencing
+explicitely explicitly
+explicity explicitly
+explit explicit
+Expresion Expression
+expresions expressions
+extented extended
+extention extension
+Extention Extension
+extentions extensions
+extesion extension
+fabilous fabulous
+falg flag
+familar familiar
+fastes fastest
+favourable favorable
+favour favor
+favourite favorite
+favours favors
+featue feature
+feeded fed
+filsystem filesystem
+firware firmware
+fisrt first
+fixiated fixated
+fixiate fixate
+fixiating fixating
+flaged flagged
+flavours flavors
+focussed focused
+folllowed followed
+follwing following
+folowing following
+
+#INCORRECT SPELLING CORRECTION
+
+Folowing Following
+footnotexs footnotes
+formaly formally
+fortunatly fortunately
+foward forward
+fragement fragment
+framesyle framestyle
+framset frameset
+fucntion function
+Fucntion Function
+fuction function
+fuctions functions
+fufill fulfill
+fulfiling fulfilling
+fullfilled fulfilled
+funcion function
+funciton function
+functin function
+funtional functional
+funtionality functionality
+funtion function
+funtions functions
+furthur further
+gaalxies galaxies
+Gamee Game
+gernerated generated
+ges goes
+Ghostscipt Ghostscript
+giude guide
+globaly globally
+goind going
+Gostscript Ghostscript
+grapphis graphics
+greyed grayed
+guaranted guaranteed
+guarenteed guaranteed
+guarrantee guarantee
+gziped gzipped
+handeling handling
+harware hardware
+Harware Hardware
+hasnt hasn't
+havn't haven't
+heigt height
+heigth height
+hiddden hidden
+Hierachical Hierarchical
+highlighlighted highlighted
+highligting highlighting
+Higlighting Highlighting
+honour honor
+honouring honoring
+
+#INCORRECT SPELLING CORRECTION
+
+honours honors
+horziontal horizontal
+hypens hyphens
+hysical physical
+iconized iconified
+illumnating illuminating
+imaginery imaginary
+i'm I'm
+imitatation imitation
+immedialely immediately
+immediatly immediately
+imortant important
+imperical empirical
+implemantation implementation
+implemenation implementation
+implenetation implementation
+implimention implementation
+implmentation implementation
+inactiv inactive
+incldue include
+incomming incoming
+Incomming Incoming
+incovenient inconvenient
+indeces indices
+indentical identical
+Indentification Identification
+indepedancy independency
+independant independent
+independend independent
+indetectable undetectable
+indicdate indicate
+indice index
+indictes indicates
+infinitv infinitive
+infomation information
+informaion information
+informatation information
+informationon information
+informations information
+Inifity Infinity
+inital initial
+initalization initialization
+initalized initialized
+initalize initialize
+Initalize Initialize
+initialisation initialization
+initialise initialize
+initialising initializing
+Initialyze Initialize
+Initilialyze Initialize
+initilization initialization
+initilize initialize
+
+#INCORRECT SPELLING CORRECTION
+
+Initilize Initialize
+innacurate inaccurate
+innacurately inaccurately
+insde inside
+inteface interface
+interactivelly interactively
+interfer interfere
+interfrace interface
+interisting interesting
+internationalisation internationalization
+interrrupt interrupt
+interrumped interrupted
+interrups interrupts
+Interupt Interrupt
+intervall interval
+intervalls intervals
+intiailize initialize
+Intial Initial
+intialisation initialization
+intialization initialization
+intialize initialize
+Intialize Initialize
+intializing initializing
+introdutionary introductory
+introdution introduction
+intrrupt interrupt
+intruction instruction
+invarient invariant
+invokation invocation
+Ionisation Ionization
+irrevesible irreversible
+isntance instance
+is'nt isn't
+issueing issuing
+istory history
+Iterface Interface
+itselfs itself
+journalised journalized
+judgement judgment
+kdelbase kdebase
+keyboad keyboard
+klicking clicking
+knowlege knowledge
+Konquerer Konqueror
+konstants constants
+kscreensave kscreensaver
+labelling labeling
+Labelling Labeling
+lauching launching
+layed laid
+learnt learned
+leats least
+lenght length
+
+#INCORRECT SPELLING CORRECTION
+
+Lenght Length
+Licenced Licensed
+licence license
+Licence License
+Licens License
+liset list
+listenening listening
+listveiw listview
+litle little
+litteral literal
+localisation localization
+losely loosely
+maanged managed
+maching matching
+magnication magnification
+magnifcation magnification
+mailboxs mailboxes
+maillinglists mailinglists
+maintainance maintenance
+maintainence maintenance
+Malicous Malicious
+mamage manage
+managment management
+Managment Management
+manangement management
+mannually manually
+Mantainer Maintainer
+manupulation manipulation
+marbels marbles
+matchs matches
+maximimum maximum
+Maxium Maximum
+mdification modification
+mdified modified
+menues menus
+mesages messages
+messanger messenger
+messanging messaging
+Microsft Microsoft
+millimetres millimeters
+mimimum minimum
+minimise minimize
+minimising minimizing
+Minimun Minimum
+Minium Minimum
+minumum minimum
+miscelaneous miscellaneous
+miscelanous miscellaneous
+miscellaneaous miscellaneous
+miscellanous miscellaneous
+Miscellanous Miscellaneous
+mispeled misspelled
+mispelled misspelled
+
+#INCORRECT SPELLING CORRECTION
+
+mistery mystery
+Modifes Modifies
+modifing modifying
+modul module
+mosue mouse
+Mozzila Mozilla
+mssing missing
+Mulitimedia Multimedia
+mulitple multiple
+multible multiple
+multipe multiple
+multy multi
+mutiple multiple
+neccesary necessary
+neccessary necessary
+necessery necessary
+nedd need
+neet need
+negativ negative
+negociated negotiated
+negociation negotiation
+neighbourhood neighborhood
+neighbour neighbor
+Neighbour Neighbor
+neighbours neighbors
+neogtiation negotiation
+nessecarry necessary
+nessecary necessary
+nessesary necessary
+nework network
+newtork network
+nickanme nickname
+nonexistant nonexistent
+noone nobody
+Noone No-one
+normalisation normalization
+noticable noticeable
+nucleous nucleus
+obtail obtain
+occoured occurred
+occouring occurring
+occurance occurrence
+occurances occurrences
+occured occurred
+occurence occurrence
+occurences occurrences
+occure occur
+occuring occurring
+occurrance occurrence
+occurrances occurrences
+ocupied occupied
+offical official
+ommited omitted
+
+#INCORRECT SPELLING CORRECTION
+
+onthe on the
+opend opened
+optimisation optimization
+optionnal optional
+orangeish orangish
+organisational organizational
+organisation organization
+Organisation Organization
+organisations organizations
+organised organized
+organise organize
+organiser organizer
+organising organizing
+Organising Organizing
+orginate originate
+Originaly Originally
+orignal original
+oscilating oscillating
+otehr other
+ouput output
+outputing outputting
+overidden overridden
+overriden overridden
+overriden overridden
+ownes owns
+pakage package
+panelised panelized
+paramaters parameters
+parametres parameters
+parametrize parameterize
+paramter parameter
+paramters parameters
+particip participle
+particularily particularly
+paticular particular
+Pendings Pending
+percetages percentages
+Perfomance Performance
+performace performance
+Periferial Peripheral
+permision permission
+permisions permissions
+permissable permissible
+Personalizsation Personalization
+perticularly particularly
+phyiscal physical
+plaforms platforms
+plese please
+politness politeness
+posibilities possibilities
+posibility possibility
+
+#INCORRECT SPELLING CORRECTION
+
+posible possible
+positon position
+possebilities possibilities
+possebility possibility
+possibilty possibility
+possiblity possibility
+posssibility possibility
+potentally potentially
+practise practice
+practising practicing
+preceeded preceded
+preceeding preceding
+precison precision
+preemphasised preemphasized
+Preemphasised Preemphasized
+prefered preferred
+Prefered Preferred
+preferrable preferable
+prefiously previously
+preformance performance
+prerequisits prerequisites
+presense presence
+pressentation presentation
+prgramm program
+Prining Printing
+priveleges privileges
+priviledge privilege
+priviledges privileges
+priviliges privileges
+probatility probability
+probelm problem
+proberly properly
+problmes problems
+proceedure procedure
+proctection protection
+proecss process
+progess progress
+programing programming
+programme program
+programm program
+promille per mill
+promiscous promiscuous
+promped prompted
+pronounciation pronunciation
+Pronounciation Pronunciation
+pronunce pronounce
+pronunciated pronounced
+properies properties
+Propertites Properties
+Propogate Propagate
+protoypes prototypes
+
+#INCORRECT SPELLING CORRECTION
+
+Proxys Proxies
+psuedo pseudo
+Psuedo Pseudo
+pult desk
+purposees purposes
+quatna quanta
+queing queuing
+querys queries
+queueing queuing
+Queueing Queuing
+quiten quiet
+quiting quitting
+readony readonly
+realise realize
+realy really
+REAMDE README
+reasonnable reasonable
+receieve receive
+recepeient recipient
+recepient recipient
+recevie receive
+recevie receive
+receving receiving
+recieved received
+recieve receive
+Recieve Receive
+reciever receiver
+recieves receives
+Recieves Receives
+recives receives
+recognised recognized
+recognise recognize
+recognises recognizes
+recomended recommended
+recommanded recommended
+recommand recommend
+recommented recommended
+redialling redialing
+reets resets
+refered referred
+Refering Referring
+Refeshes Refreshes
+refreshs refreshes
+regarless regardless
+registaration registration
+registred registered
+Regsiter Register
+regulare regular
+regularily regularly
+Reigster Register
+reimplemenations reimplementations
+
+#INCORRECT SPELLING CORRECTION
+
+Reimplemenations Reimplementations
+releated related
+relection reselection
+relevent relevant
+relocateable relocatable
+remaing remaining
+remeber remember
+remebers remembers
+remotley remotely
+renderes renders
+renewd renewed
+reorienting reorientating
+Repalcement Replacement
+replys replies
+reponsibility responsibility
+requeusts requests
+resently recently
+resetted reset
+resistent resistant
+resognized recognized
+resonable reasonable
+resoure resource
+responsability responsibility
+responsivness responsiveness
+resposible responsible
+ressources resources
+retreived retrieved
+retreive retrieve
+retults results
+Rewritebles Rewritables
+richt right
+rigths rights
+Rigt Right
+saftey safety
+satified satisfied
+savely safely
+savety safety
+scalled scaled
+scather scatter
+scenerio scenario
+sceptical skeptical
+schduler scheduler
+Sectionning Sectioning
+selction selection
+selectde selected
+sensistve sensitive
+separed separated
+separeted separated
+sepcified specified
+seperated separated
+seperately separately
+seperate separate
+seperate separate
+
+#INCORRECT SPELLING CORRECTION
+
+Seperate Separate
+seperation separation
+seperatly separately
+seperator separator
+sequencially sequentially
+sertificate certificate
+serveral several
+setted set
+sheduled scheduled
+sheme scheme
+shorctuts shortcuts
+shoud should
+shouldnt shouldn't
+Shouldnt Shouldn't
+shure sure
+Similarily Similarly
+Similiarly Similarly
+similiar similar
+simlar similar
+simpliest simplest
+simultaneuosly simultaneously
+skript script
+slewin slewing
+smaple sample
+Sombody Somebody
+somehwat somewhat
+soure source
+sparcely sparsely
+speakiing speaking
+specefied specified
+specfic specific
+specfied specified
+specialised specialized
+specifc specific
+specifed specified
+Specificiation Specification
+specifieing specifying
+specifing specifying
+specifiy specify
+Specifiy Specify
+speficied specified
+speling spelling
+spezifying specifying
+sprectrum spectrum
+standar standard
+Startp Startup
+Statfeul Stateful
+statfull stateful
+storeys storys
+straighforward straightforward
+streched stretched
+Streches Stretches
+Strech Stretch
+
+#INCORRECT SPELLING CORRECTION
+
+Striked Stroked
+stuctures structures
+styleshets stylesheets
+subcribed subscribed
+subdirectorys subdirectories
+subseqently subsequently
+Substracting Subtracting
+subystem subsystem
+succeded succeeded
+succesfully successfully
+succesful successful
+succesive successive
+succesor successor
+successfull successful
+sucessfull successful
+sucessfully successfully
+sucessfuly successfully
+sucess success
+sufficent sufficient
+superflous superfluous
+supossed supposed
+supressed suppressed
+supress suppress
+suprised surprised
+susbstitute substitute
+swaped swapped
+synchonization synchronization
+synchronisation synchronization
+Synchronisation Synchronization
+synchronised synchronized
+synchronises synchronizes
+synchronise synchronize
+synchronyze synchronize
+Syncronization Synchronization
+syncronized synchronized
+Syncronizes Synchronizes
+syncronize synchronize
+syncronizing synchronizing
+Syncronizing Synchronizing
+syncronous synchronous
+syncrounous synchronous
+syndrom syndrome
+syntex syntax
+synthetizer synthesizer
+syntheziser synthesizer
+sytem system
+talbs tables
+talse false
+tecnology technology
+temparary temporary
+Tempertures Temperatures
+terminatin terminating
+
+#INCORRECT SPELLING CORRECTION
+
+texured textured
+themc them
+thet that
+threshholds thresholds
+threshhold threshold
+throtte throttle
+throught through
+throuth through
+tiggered triggered
+tihs this
+timditiy timidity
+Timdity Timidity
+timming timing
+tranceiver transceiver
+Tranfers Transfers
+tranfer transfer
+Tranlate Translate
+tranlation translation
+transalted translated
+transation transaction
+transfering transferring
+transferrable transferable
+transmiter transmitter
+transmiting transmitting
+transmition transmission
+transmittion transmission
+transparancy transparency
+transparant transparent
+trasfered transferred
+traveller traveler
+travelling traveling
+triggerg triggering
+triggerred triggered
+truely truly
+trys tries
+uglyness ugliness
+unabiguous unambiguous
+unaccesible unaccessible
+unallowed disallowed
+unamed unnamed
+unathorized unauthorized
+uncrypted unencrypted
+Uncutt Uncut
+underlieing underlying
+underrrun underrun
+undesireable undesirable
+undestood understood
+Undexpected Unexpected
+undoedne undid
+unecessary unnecessary
+unexperienced inexperienced
+unexperience inexperience
+unfortunatly unfortunately
+
+#INCORRECT SPELLING CORRECTION
+
+Unfortunatly Unfortunately
+uniq unique
+unitialized uninitialized
+unkown unknown
+Unmoveable Unmovable
+unneccessary unnecessary
+unneccessay unnecessary
+unsellectected unselected
+unsuccesful unsuccessful
+unuseable unusable
+unusuable unusable
+unvailable unavailable
+uploades uploads
+upppercase uppercase
+usally usually
+usefull useful
+usere user
+usuable usable
+usuallly usually
+Usualy Usually
+utilisation utilization
+vaild valid
+valied valid
+valueable valuable
+varb verb
+vays ways
+verfication verification
+verically vertically
+versins versions
+verticaly vertically
+verticies vertices
+Veryify Verify
+vicitim victim
+visualisations visualizations
+visualisation visualization
+Visualisation Visualization
+visualise visualize
+visul visual
+volonteer volunteer
+Volumen Volume
+Voribis Vorbis
+vrtual virtual
+waranty warranty
+watseful wasteful
+weigth weight
+wheter whether
+whicn which
+whishes wishes
+whitch which
+whith with
+
+#INCORRECT SPELLING CORRECTION
+
+Wiazrd Wizard
+wich which
+wich which
+wierd weird
+wieving viewing
+wiev view
+wih with
+willl will
+wnat want
+workimg working
+workstatio workstation
+woud would
+wouldd would
+writting writing
+Writting Writing
+yeld yield
+yorself yourself
+you'ld you would
+yourContryCode yourCountryCode
+
diff --git a/scripts/kde.supp b/scripts/kde.supp
new file mode 100644
index 00000000..213d9bb1
--- /dev/null
+++ b/scripts/kde.supp
@@ -0,0 +1,155 @@
+#
+# Some valgrind suppressions handy for ignoring stuff we don't care
+# about when valgrinding kde applications
+#
+# Library paths and versions from debian unstable, YMMV
+#
+
+#
+# pthread errors
+#
+
+{
+ pthread_mutex_unlock
+ core:PThread
+ fun:__pthread_mutex_unlock
+}
+
+{
+ pthread_error/pthread_mutex_destroy
+ core:PThread
+ fun:pthread_error
+ fun:__pthread_mutex_destroy
+}
+
+#
+# ld.so errors
+#
+
+{
+ strchr/decompose_rpath/_dl_map_object
+ MemCheck:Cond
+ fun:strchr
+ fun:decompose_rpath
+ fun:_dl_map_object
+}
+
+{
+ strlen/libc/_dl_catch_error
+ MemCheck:Cond
+ fun:strlen
+ fun:_dl_open
+ obj:*libdl-2*.so
+ fun:_dl_catch_error*
+}
+
+{
+ strchr/libc/_dl_catch_error
+ MemCheck:Cond
+ fun:strchr
+ obj:*libc-2.2.?.so
+ fun:_dl_catch_error
+}
+
+{
+ strrchr/_dl_map_object_from_fd/_dl_map_object
+ MemCheck:Cond
+ fun:strrchr
+ fun:_dl_map_object_from_fd
+ fun:_dl_map_object
+}
+
+{
+ strlen/_dl_signal_cerror/_dl_lookup_symbol_internal
+ Memcheck:Cond
+ fun:strlen
+ fun:_dl_signal_cerror
+ fun:_dl_lookup_symbol_internal
+ fun:*dlsym
+}
+
+#
+# X library errors
+#
+
+{
+ libXft(Cond)
+ MemCheck:Cond
+ obj:/usr/X11R6/lib/libXft.so.1.1
+ obj:/usr/X11R6/lib/libXft.so.1.1
+}
+
+{
+ write(buf)/libc/libICE
+ Memcheck:Param
+ write(buf)
+ fun:__GI___libc_write
+ fun:_IceTransWrite
+ fun:_IceWrite
+ fun:IceFlush
+}
+
+{
+ write(buf)/libc/libX11
+ Memcheck:Param
+ write(buf)
+ fun:__GI___libc_write
+ fun:_X11TransWrite
+ fun:_XFlushInt
+ fun:_XFlush
+}
+
+{
+ write(buf)/libc/libX11
+ Memcheck:Param
+ write(buf)
+ fun:__GI___libc_write
+ fun:_X11TransWrite
+ fun:_XFlushInt
+ fun:_XReply
+}
+
+{
+ writev(vector[...])
+ Memcheck:Param
+ writev(vector[...])
+ fun:*writev
+ obj:libX11.so.*
+ fun:_X11TransWritev
+ fun:_XSend
+}
+
+#
+# SSL errors
+#
+
+{
+ various1/libcrypto
+ Memcheck:Value4
+ obj:*libcrypto.so.0.9.7
+}
+
+{
+ various2/libcrypto
+ Memcheck:Cond
+ obj:*libcrypto.so.0.9.7
+}
+
+{
+ ssl3_read_bytes1/libssl
+ Memcheck:Cond
+ fun:memcpy
+ fun:ssl3_read_bytes
+}
+
+{
+ ssl3_read_bytes2/libssl
+ Memcheck:Cond
+ fun:ssl3_read_bytes
+}
+
+{
+ ssl3_get_message/libssl
+ Memcheck:Cond
+ fun:ssl3_get_message
+}
diff --git a/scripts/kdedoc b/scripts/kdedoc
new file mode 100755
index 00000000..0dc20a66
--- /dev/null
+++ b/scripts/kdedoc
@@ -0,0 +1,48 @@
+#!/bin/sh
+# Run from command line, to open a kde help page in kfm/konqueror
+# Argument : The classname (case sensitive !).
+# Both doxygen and kdoc docs are supported.
+
+# You can edit this line to set the directory holding your KDE docs, or you
+# can use the environment variable KDEDOCS to avoid future conflicts with this
+# file if the default changes.
+KDEDOCS=${KDEDOCS:-"$KDEDIR/share/doc/HTML/en/kdelibs-apidocs"}
+
+if [ $# = 1 ]; then
+ if [ -e "$KDEDOCS/doxygen.css" ]; then
+ # Docs are laid out in doxygen style.
+ if [ -f "$KDEDOCS/class$1.html" ]; then
+ kfmclient exec "$KDEDOCS/class$1.html"
+ elif [ -f "$KDEDOCS"/*/html/"class$1.html" ]; then
+ kfmclient exec "$KDEDOCS"/*/html/"class$1.html"
+ else
+ classstring=`echo "$1" | sed -e 's/::/_1_1/'`
+ if [ -f "$KDEDOCS/class$classstring.html" ]; then
+ kfmclient exec "$KDEDOCS/class$classstring.html"
+ elif [ -f "$KDEDOCS"/*/html/"class$classstring.html" ]; then
+ kfmclient exec "$KDEDOCS"/*/html/"class$classstring.html"
+ elif [ -f "$KDEDOCS"/class*_1_1"$1.html" ]; then
+ kfmclient exec "$KDEDOCS"/class*_1_1"$1.html"
+ elif [ -f "$KDEDOCS"/*/html/class*_1_1"$1.html" ]; then
+ kfmclient exec "$KDEDOCS"/*/html/class*_1_1"$1.html"
+ else
+ echo "No class $1 in $KDEDOCS/*"
+ exit 1
+ fi
+ fi
+ elif [ -e "$KDEDOCS/kdecore/index.html" ]; then
+ # Docs are laid out in kdoc style.
+ if [ -f "$KDEDOCS"/*/"$1.html" ]; then
+ kfmclient exec "$KDEDOCS"/*/"$1.html"
+ else
+ echo "No class $1 in $KDEDOCS/*"
+ exit 1
+ fi
+ else
+ echo "$KDEDOCS does not appear to contain your KDE docs."
+ exit 1
+ fi
+else
+ echo "Usage : $0 <classname>"
+ exit 1
+fi
diff --git a/scripts/kdekillall b/scripts/kdekillall
new file mode 100755
index 00000000..deb5aef5
--- /dev/null
+++ b/scripts/kdekillall
@@ -0,0 +1,28 @@
+#! /bin/sh
+
+case $1 in
+ -*) signal=$1; shift;;
+esac
+if [ $# = 0 ]; then
+ echo "Usage: $0 [-<signal>] <process>"
+ echo 'Kills the process "kdeinit: <process> with signal <signal>"'
+ echo "if <signal> is not specified, it defaults to SIGTERM,"
+ echo "see kill -l for a list of possible signals"
+else
+ list=$(ps auwx | grep $USER | awk "/[k]deinit: $1/ {print \$2}")
+ if test -z "$list"; then
+ # on newer Linux kernels (>= 2.6.10) KDE is able to use
+ # prctl(PR_SET_NAME) to change the process name...
+ list=$(ps auwx | grep $USER | awk "/\[kdeinit\] $1/ {print \$2}")
+ fi
+ if test -z "$list"; then
+ # with KDE 3.4 we changed the view again...
+ list=$(ps auwx | grep $USER | awk "/$1 \[kdeinit\]/ {print \$2}")
+ fi
+ if test -n "$list"; then
+ kill $signal $list
+ else
+ echo 'No process killed'
+ exit 1
+ fi
+fi
diff --git a/scripts/kdelnk2desktop.py b/scripts/kdelnk2desktop.py
new file mode 100755
index 00000000..9d96d87c
--- /dev/null
+++ b/scripts/kdelnk2desktop.py
@@ -0,0 +1,21 @@
+#! /usr/bin/env python
+
+import os, sys, string
+
+def help():
+ print "Usage: %s <filename>.kdelnk ..."
+
+if len(sys.argv) < 2:
+ help()
+ sys.exit()
+
+for fn in sys.argv[1:]:
+ print "Doing %s ..." % fn
+ f = open(fn, 'r').readlines()
+
+ if string.find(f[0], "# KDE Config") == 0:
+ p = open(fn, 'w')
+ p.writelines(f[1:])
+ p.close()
+
+ os.rename(fn, fn[:-6]+'desktop')
diff --git a/scripts/kdemangen.pl b/scripts/kdemangen.pl
new file mode 100755
index 00000000..69951c88
--- /dev/null
+++ b/scripts/kdemangen.pl
@@ -0,0 +1,250 @@
+#! /usr/bin/env perl
+
+# kdemangen.pl
+# Copyright (C) 2003 Dominique Devriese <devriese@kde.org>
+
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the 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, write to the Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+
+
+# Here's a little explanation about this script:
+# In order to fix long-standing Debian bug #116485, I've written a
+# script that takes a KDE app, and generates a nice man page.. It uses
+# the app's "--author" and "--help-all" output, along with a description
+# from Debian's control file to get the data. I think the script works
+# great, the man pages look almost hand-written ;) I encourage you all
+# to try this out, and very much welcome any feedback, especially as to
+# how to integrate this into either the Debian KDE packaging system or
+# the KDE build system..
+
+# The idea to do this with a script allows us to easily keep the man
+# pages up to date, and is generally very low-trouble for the
+# developer...
+
+# The script is attached at the bottom..
+
+# USAGE:
+# Suppose you wanted to generate a man page for the KDE-Edu program
+# kalzium.. Then you would
+# 1 cd to /path/to/kde/srcs/kdeedu/debian ( necessary so the script
+# finds the Debian control file.. )
+# 2 run "/path/to/kdemangen.pl $(which kstars) > kstars.1"
+# 3 run "man ./kstars.1" to check out the generated page..
+
+# PROBLEMS:
+# Only works for full KDE applications that use KCmdLineArgs (
+# inherent to my approach, but most KDE apps fulfill this requirement
+# )
+
+use warnings;
+use strict;
+
+sub optionstonroff
+ {
+ my $options = shift;
+ my $ret = "";
+ foreach( split /\n/, $options )
+ {
+ if( /^ (--?[[:alpha:]]+, )?(--[[:alpha:]-]*|-[[:alpha:]])( <[[:alpha:] ]*>| [[:alpha:]]*)? *(.*)$/ )
+ {
+ my $short;
+ my $long;
+ my $arg;
+ my $desc;
+ if( $1 ) { $short = $1; } else { $short = ""; };
+ if( $2 ) { $long = $2; } else { $long = ""; };
+ if( $3 ) { $arg = $3; } else { $arg = ""; };
+ if( $4 ) { $desc = $4; } else { $desc = ""; };
+ $short =~ s/-/\\-/g;
+ $long =~ s/-/\\-/g;
+ $arg =~ s/-/\\-/g;
+ $ret .= ".TP\n";
+ $ret .= ".B $short $long $arg\n";
+ $ret .= "$desc\n";
+ }
+ elsif( /^ ([[:alpha:]]+) +(.*)$/ )
+ {
+ $ret .= ".TP\n";
+ $ret .= ".B $1\n";
+ $ret .= "$2\n";
+ }
+ elsif( /^ +(.*)$/ )
+ {
+ $ret .= "$1\n";
+ }
+ elsif( /^(.*)$/ )
+ {
+ $ret .= ".SS $1\n";
+ # this means a header like "Qt Options:" I'm wondering
+ # what to do with this, I don't know enough nroff to
+ # format it nicely, I'm affraid..
+ }
+ }
+ return $ret;
+ };
+
+sub sortoptionsfromnroff {
+ # Zack Cerza
+
+ # Rather than redo Dominique's optionstonroff(), I decided
+ # to make this function to sort the options sections created
+ # by his function.
+
+ # What it does is read line-by-line and first determine which
+ # section it's looking at via the ".SS <SECTION>" lines. Once
+ # it knows, it sets a "$in_<SECTION>" variable to "1" and
+ # begins to write the section data into $<SECTION>. When it
+ # gets to a line that contains only ".SS ", it sets
+ # $in_<SECTION> to "0" and continues.
+
+ # It's a little messy, but it's the only way I could
+ # get it to work with what little knowledge I had.
+
+ # This is the first time I've used Perl. Be kind.
+
+ my $options = shift;
+ my $ret="";
+
+ my $in_gen_opts = "0";
+ my $gen_opts = "";
+ my $in_qt_opts = "0";
+ my $qt_opts = "";
+ my $in_kde_opts = "0";
+ my $kde_opts = "";
+ my $in_opts = "0";
+ my $opts = "";
+ my $in_args = "0";
+ my $args = "";
+
+ foreach ( split /\n/, $options ) {
+ if( $in_gen_opts == "1" ) {
+ if( /^(\.SS )$/ ) { $in_gen_opts = "0"; }
+ $gen_opts .= $_;
+ $gen_opts .= "\n";
+ }
+ if( /^(\.SS.+Generic options:)$/ )
+ { $in_gen_opts = "1"; $gen_opts .= $1; $gen_opts .= "\n"; }
+
+ if( $in_qt_opts == "1" ) {
+ if( /^(\.SS )$/ ) { $in_qt_opts = "0"; }
+ $qt_opts .= $_;
+ $qt_opts .= "\n";
+ }
+ if( /^(\.SS.+Qt options:)$/ )
+ { $in_qt_opts = "1"; $qt_opts .= $1; $qt_opts .= "\n"; }
+
+ if( $in_kde_opts == "1" ) {
+ if( /^(\.SS )$/ ) { $in_kde_opts = "0"; }
+ $kde_opts .= $_;
+ $kde_opts .= "\n";
+ }
+ if( /^(\.SS.+KDE options:)$/ )
+ { $in_kde_opts = "1"; $kde_opts .= $1; $kde_opts .= "\n"; }
+
+ if( $in_opts == "1" ) {
+ if( /^(\.SS )$/ ) { $in_opts = "0"; }
+ $opts .= $_;
+ $opts .= "\n";
+ }
+ if( /^(\.SS.+Options:)$/ )
+ { $in_opts = "1"; $opts .= $1; $opts .= "\n"; }
+
+ if( $in_args == "1" ) {
+ if( /^(\.SS )$/ ) { $in_args = "0"; }
+ $args .= $_;
+ $args .= "\n";
+ }
+ if( /^(\.SS.+Arguments:)$/ )
+ { $in_args = "1"; $args .= ".SS\n"; $args .= $1; $args .= "\n"; }
+ }
+ $ret .= $args;
+ $ret .= $opts;
+ $ret .= $gen_opts;
+ $ret .= $kde_opts;
+ $ret .= $qt_opts;
+ return $ret;
+ };
+
+sub usage
+ {
+ print "This script generates a nice manual page for a KDE app which uses KCmdLineArgs..\n";
+ print "USAGE: $0 app\n";
+ print "There's more information about how to use this script in the comments at the front of the source..\n"
+ };
+
+if( $#ARGV < 0 ){
+ usage();
+ exit 1;
+}
+
+my $runapp = "$ARGV[0]";
+if ( ! -x $runapp )
+ {
+ print "Error: $runapp is not executable.\n";
+ exit 1;
+ }
+else { $runapp = "KDE_LANG=en_US $runapp"; };
+
+my $shortdescription = `$runapp --help | sed -ne '3p'`;
+chomp $shortdescription;
+
+my $synopsis = `$runapp --help | sed -n '1p' | sed -e 's/[^:]*: //'`;
+chomp $synopsis;
+$synopsis =~ s/-/\\-/g;
+my $appname = $synopsis;
+$appname =~ s/ .*$//;
+my $ucappname = uc $appname;
+
+my $options = `$runapp --help-all | sed -e '1,4d'`;
+$options = optionstonroff( $options );
+$options = sortoptionsfromnroff( $options );
+
+my $timespec = ucfirst `date '+%b %G'`;
+chomp $timespec;
+
+my $description = $shortdescription;
+if( -r "control" )
+ {
+ $description = `cat control | sed -ne '/^Description:/,/^\$/p' | egrep -v '^\\w*:.*\$' | sed -e 's/^ //' | sed -e 's/^\\.//'`;
+# leads to problems in some cases :(
+# $description =~ s/KDE ?/\n.SM KDE\n/g;
+ }
+
+my $authors = `$runapp --author | sed -ne '2,\$p' | sed -e '\$d' | sed -e 's/^ *//'`;
+$authors =~ s/\n/\n.br\n/g;
+
+print <<EOF;
+.\\\" This file was generated by kdemangen.pl
+.TH $ucappname 1 \"$timespec\" \"K Desktop Environment\" \"$shortdescription\"
+.SH NAME
+$appname
+\\- $shortdescription
+.SH SYNOPSIS
+$synopsis
+.SH DESCRIPTION
+$description
+.SH OPTIONS
+$options
+.SH SEE ALSO
+Full user documentation is available through the KDE Help Center. You can also enter the URL
+.BR help:/$appname/
+directly into konqueror or you can run
+.BR "`khelpcenter help:/$appname/'"
+from the command-line.
+.br
+.SH AUTHORS
+.nf
+$authors
+EOF
diff --git a/scripts/kdesvn-build b/scripts/kdesvn-build
new file mode 100755
index 00000000..fcd3970b
--- /dev/null
+++ b/scripts/kdesvn-build
@@ -0,0 +1,4286 @@
+#!/usr/bin/perl -w
+
+#Pod documentation:
+
+=head1 NAME
+
+=over
+
+=item B<kdesvn-build> - automate the kde svn build process
+
+=back
+
+=head1 SYNOPSIS
+
+=over
+
+=item B<kdesvn-build> I<[options]...> I<[modules]...>
+
+=back
+
+=head1 DESCRIPTION
+
+The B<kdesvn-build> script is used to automate the download, build,
+and install process for KDE (using Subversion).
+
+It is recommended that you first setup a F<.kdesvn-buildrc> file
+in your home directory. Please refer to B<kdesvn-build> help file
+in KDE help for information on how to write F<.kdesvn-buildrc>,
+or consult the sample file which should have been included
+with this program. If you don't setup a F<.kdesvn-buildrc>, a
+default set of options will be used, and a few modules will be
+built by default.
+
+After setting up F<.kdesvn-buildrc>, you can run this program from
+either the command-line or from cron. It will automatically
+download the modules from Subversion, create the build
+system, and configure and make the modules you tell it to.
+You can use this program to install KDE as well,
+if you are building KDE for a single user. Note that B<kdesvn-build>
+will try to install the modules by default.
+
+If you DO specify a package name, then your settings will still be
+read, but the script will try to build / install the package
+regardless of F<.kdesvn-buildrc>
+
+kdesvn-build reads options in the following order:
+
+=over
+
+=item 1. From the command line.
+
+=item 2. From the file F<kdesvn-buildrc> in the current directory. Note that
+ the file is not a hidden file.
+
+=item 3. From the file F<~/.kdesvn-buildrc>.
+
+=item 4. From a set of internal options.
+
+=back
+
+This utility is part of the KDE Software Development Kit.
+
+=head1 OPTIONS
+
+=over
+
+=item B<--quiet>, B<-q>
+
+With this switch kdesvn-build will only output a general overview of the build
+process. Progress output is still displayed if available.
+
+=item B<--really-quiet>
+
+With this switch only warnings and errors will be output.
+
+=item B<--verbose>, B<-v>
+
+Be very detailed in what is going on, and what actions kdesvn-build is taking.
+Only B<--debug> is more detailed.
+
+=item B<--no-svn>
+
+Skip contacting the Subversion server.
+
+=item B<--no-build>
+
+Skip the build process.
+
+=item B<--no-install>
+
+Don't automatically install after build.
+
+=item B<--svn-only>
+
+Update from Subversion only (Identical to B<--no-build> at this point).
+
+=item B<--build-only>
+
+Build only, do not perform updates or install.
+
+=item B<--rc-file=E<lt>filenameE<gt>>
+
+Read configuration from filename instead of default.
+
+=item B<--debug>
+
+Activates debug mode.
+
+=item B<--pretend>, B<-p>
+
+Do not contact the Subversion server, run make, or create / delete files
+and directories. Instead, output what the script would have done.
+
+=item B<--nice=E<lt>valueE<gt>>
+
+Allow you to run the script with a lower priority. The default value is
+10 (lower priority by 10 steps).
+
+=item B<--prefix=/kde/path>
+
+This option is a shortcut to change the setting for kdedir from the
+command line. It implies B<--reconfigure>.
+
+=item B<--color>
+
+Add color to the output.
+
+=item B<--no-color>
+
+Remove color from the output.
+
+=item B<--resume>
+
+Tries to resume the make process from the last time the script was run,
+without performing the Subversion update.
+
+=item B<--resume-from=E<lt>pkgE<gt>>
+
+Starts building from the given package, without performing the Subversion
+update.
+
+=item B<--revision=E<lt>revE<gt>>, B<-r=E<lt>revE<gt>>
+
+Forces update to revision <rev> from Subversion.
+
+=item B<--refresh-build>
+
+Start the build from scratch. This means that the build directory for the
+module B<will be deleted> before make -f Makefile.cvs is run again. You can
+use B<--recreate-configure> to do the same thing without deleting the module
+build directory.
+
+=item B<--reconfigure>
+
+Run configure again, but don't clean the build directory or re-run
+make -f Makefile.cvs.
+
+=item B<--recreate-configure>
+
+Run make -f Makefile.cvs again to redo the configure script. The build
+directory is not deleted.
+
+=item B<--no-rebuild-on-fail>
+
+Do not try to rebuild a module from scratch if it failed building. Normally
+kdesvn-build will try progressively harder to build the module before giving
+up.
+
+=item B<--build-system-only>
+
+Create the build infrastructure, but don't actually perform the build.
+
+=item B<--install>
+
+Try to install the packages passed on the command line, or all packages in
+F<~/.kdesvn-buildrc> that don't have manual-build set. Building and
+Subversion updates are not performed.
+
+=item B<--E<lt>optionE<gt>=>
+
+Any unrecognized options are added to the global configuration, overriding
+any value that may exist.
+
+For example, B<--svn-server=http://path.to.svn.server/> would change the
+setting of the global B<svn-server> option for this instance of kdesvn-build.
+
+=item B<--E<lt>moduleE<gt>,E<lt>optionE<gt>=>
+
+Likewise, allow you to override any module specific option from the
+command line.
+
+Example: B<--kdelibs,use-unsermake=false> would disable unsermake for the
+kdelibs module.
+
+=item B<--help>
+
+Display the help and exit.
+
+=item B<--author>
+
+Output the author(s)'s name.
+
+=item B<--version>
+
+Output the program version.
+
+=back
+
+=head1 EXAMPLES
+
+=over
+
+=item B<kdesvn-build>
+
+=item B<kdesvn-build> I<--no-svn kdelibs>
+
+=item B<kdesvn-bulid> I<--refresh-build> I<kdebase>
+
+=back
+
+=head1 BUGS
+
+Since kdesvn-build doesn't generally save information related to the build and
+prior settings, you may need to manually re-run kdesvn-build with a flag like
+B<--recreate-configure> if you change some options, including B<use-unsermake>.
+
+Please use KDE bugzilla at http://bugs.kde.org for information and
+reporting bugs.
+
+=head1 SEE ALSO
+
+You can find additional information at B<kdesvn-build> home page,
+F<http://kdesvn-build.kde.org/>, or using kdesvn-build
+docbook documentation, using the help kioslave, F<help:/kdesvn-build>.
+
+=head1 AUTHOR
+
+Michael Pyne <michael.pyne@kdemail.net>
+
+Man page written by:
+Carlos Leonhard Woelz <carlos.woelz@kdemail.net>
+
+=cut
+
+# Script to handle building KDE from Subversion. All of the configuration is
+# stored in the file ~/.kdesvn-buildrc.
+#
+# Please also see the documentation that should be included with this program,
+# in doc.html
+#
+# Copyright (c) 2003, 2004, 2005 Michael Pyne. <michael.pyne@kdemail.net>
+# Home page: http://kdesvn-build.kde.org/
+#
+# You may use, alter, and redistribute this software under the terms
+# of the GNU General Public License, v2 (or any later version).
+#
+# TODO: It would be better to have lockfiles in each directory as it's
+# being updated, instead of having one big lock for the script.
+
+use strict;
+use warnings;
+use Fcntl; # For sysopen constants
+use POSIX 'strftime';
+use File::Find; # For our lndir reimplementation.
+use Errno qw(:POSIX);
+
+# Debugging level constants.
+use constant {
+ DEBUG => 0,
+ WHISPER => 1,
+ INFO => 2,
+ NOTE => 3,
+ WARNING => 4,
+ ERROR => 5,
+};
+
+# Some global variables
+# Remember kids, global variables are evil! I only get to do this
+# because I'm an adult and you're not! :-P
+# Options that start with a # will replace values with the same name,
+# if the option is actually set.
+my %package_opts = (
+ 'global' => {
+ "apidox" => "",
+ "apply-qt-patches" => "",
+ "binpath" => "/bin:/usr/bin:/usr/X11R6/bin:/usr/local/bin",
+ "branch" => "",
+ "build-dir" => "build",
+ "build-system-only" => "",
+ "checkout-only" => "",
+ "configure-flags" => "--enable-debug",
+ "colorful-output" => 1, # Use color by default.
+ "cxxflags" => "-pipe",
+ "debug" => "",
+ "debug-level" => INFO,
+ "dest-dir" => '${MODULE}', # single quotes used on purpose!
+ "disable-agent-check" => 0, # If true we don't check on ssh-agent
+ "do-not-compile" => "",
+ "email-address" => "",
+ "email-on-compile-error" => "",
+ "install-after-build" => "1", # Default to true
+ "inst-apps" => "",
+ "kdedir" => "$ENV{HOME}/kde",
+ "libpath" => "",
+ "log-dir" => "log",
+ "make-install-prefix" => "", # Some people need sudo
+ "make-options" => "-j2",
+ "manual-build" => "",
+ "manual-update" => "",
+ "module-base-path" => "", # Used for tags and branches
+ "niceness" => "10",
+ "no-svn" => "",
+ "no-rebuild-on-fail" => "",
+ "override-url" => "",
+ "prefix" => "", # Override installation prefix.
+ "pretend" => "",
+ "qtdir" => "$ENV{HOME}/kdesvn/build/qt-copy",
+ "reconfigure" => "",
+ "recreate-configure" => "",
+ "refresh-build" => "",
+ "remove-after-install"=> "none", # { none, builddir, all }
+ "revision" => 0,
+ "set-env" => { }, # Hash of environment vars to set
+ "source-dir" => "$ENV{HOME}/kdesvn",
+ "stop-on-failure" => "",
+ "svn-server" => "svn://anonsvn.kde.org/home/kde",
+ "tag" => "",
+ "unsermake-options" => "--compile-jobs=2 -p",
+ "unsermake-path" => "unsermake",
+ "use-unsermake" => "1", # Default to true now, we may need a blacklist
+ }
+);
+
+# This is a hash since Perl doesn't have a "in" keyword.
+my %ignore_list; # List of packages to refuse to include in the build list.
+
+# update and build are lists since they support an ordering, which can't be
+# guaranteed using a hash unless I want a custom sort function (which isn't
+# necessarily a horrible way to go, I just chose to do it this way.
+my @update_list; # List of modules to update/checkout.
+my @build_list; # List of modules to build.
+
+# Dictionary of lists of failed modules, keyed by the name of the operation
+# that caused the failure (e.g. build). Note that output_failed_module_lists
+# uses the key name to display text to the user so it should describe the
+# actual category of failure. You should also add the key name to
+# output_failed_module_lists since it uses its own sorted list.
+my @fail_display_order = qw/build update install/;
+my %fail_lists = (
+ 'build' => [ ],
+ 'install' => [ ],
+ 'update' => [ ],
+);
+
+my $install_flag; # True if we're in install mode.
+my $BUILD_ID; # Used by logging subsystem to create a unique log dir.
+my $LOG_DATE; # Used by logging subsystem to create logs in same dir.
+my @rcfiles = ("./kdesvn-buildrc", "$ENV{HOME}/.kdesvn-buildrc");
+my $rcfile; # the file that was used; set by read_options
+
+# Colors
+my ($RED, $GREEN, $YELLOW, $NORMAL, $BOLD) = ("") x 5;
+
+# Subroutine definitions
+
+# I swear Perl must be the only language where the docs tell you to use a
+# constant that you'll never find exported without some module from CPAN.
+use constant PRIO_PROCESS => 0;
+
+# I'm lazy and would rather write in shorthand for the colors. This sub
+# allows me to do so. Put it right up top to stifle Perl warnings.
+sub clr($)
+{
+ my $str = shift;
+
+ $str =~ s/g\[/$GREEN/g;
+ $str =~ s/]/$NORMAL/g;
+ $str =~ s/y\[/$YELLOW/g;
+ $str =~ s/r\[/$RED/g;
+ $str =~ s/b\[/$BOLD/g;
+
+ return $str;
+}
+
+# Subroutine which returns true if pretend mode is on. Uses the prototype
+# feature so you don't need the parentheses to use it.
+sub pretending()
+{
+ return get_option('global', 'pretend');
+}
+
+# Subroutine which returns true if debug mode is on. Uses the prototype
+# feature so you don't need the parentheses to use it.
+sub debugging()
+{
+ return get_option('global', 'debug-level') <= DEBUG;
+}
+
+# The next few subroutines are used to print output at different importance
+# levels to allow for e.g. quiet switches, or verbose switches. The levels are,
+# from least to most important:
+# debug, whisper, info (default), note (quiet), warning (very-quiet), and error.
+#
+# You can also use the pretend output subroutine, which is emitted if, and only
+# if pretend mode is enabled.
+#
+# clr is automatically run on the input for all of those functions.
+# Also, the terminal color is automatically reset to normal as well so you don't
+# need to manually add the ] to reset.
+
+# Subroutine used to actually display the data, calls clr on each entry first.
+sub print_clr(@)
+{
+ print clr $_ foreach (@_);
+ print clr "]\n";
+}
+
+sub debug(@)
+{
+ print_clr @_ if debugging;
+}
+
+sub whisper(@)
+{
+ print_clr @_ if get_option('global', 'debug-level') <= WHISPER;
+}
+
+sub info(@)
+{
+ print_clr @_ if get_option('global', 'debug-level') <= INFO;
+}
+
+sub note(@)
+{
+ print_clr @_ if get_option('global', 'debug-level') <= NOTE;
+}
+
+sub warning(@)
+{
+ print_clr @_ if get_option('global', 'debug-level') <= WARNING;
+}
+
+# This sub has the additional side effect of printing the errno value if it
+# is set.
+sub error(@)
+{
+ print STDERR (clr $_) foreach (@_);
+ print " $!\n" if $!;
+}
+
+sub pretend(@)
+{
+ print_clr @_ if pretending;
+}
+
+# Subroutine to handle removing the lock file upon receiving a signal
+sub quit_handler
+{
+ note "Signal received, terminating.";
+ finish(5);
+}
+
+# Subroutine that returns the path of a file used to output the results of the
+# build process. It accepts one parameter, which changes the kind of file
+# returned. If the parameter is set to 'existing', then the file returned is
+# the latest file that exists, or undef if no log has been created yet. This
+# is useful for the --resume mode. All other values will return the name if a
+# file that does not yet exist.
+#
+# All files will be stored in the log directory.
+sub get_output_file
+{
+ my $logdir;
+ my $mode;
+ $mode = shift or $mode = '';
+ my $fname;
+
+ debug "get_output_file in mode $mode";
+
+ if ($mode eq 'existing')
+ {
+ # There's two ways of finding the old file. Searching backwards with
+ # valid combinations of the date and build id, or just reading in the
+ # name from a known file or location. Since the latter option is much
+ # easier, that's what I'm going with. Note that this depends on the
+ # latest symlink being in place.
+ $logdir = get_subdir_path ('global', 'log-dir');
+ $fname = "$logdir/latest/build-status";
+
+ debug "Old build status file is $fname";
+
+ # The _ at the end returns the cached file stats to avoid multiple
+ # stat() calls.
+ return "" if not -e $fname or not -r _;
+
+ return $fname;
+ }
+
+ # This call must follow the test above, because it changes the 'latest'
+ # symlink leading to failures later.
+ $logdir = get_log_dir('global');
+
+ $fname = "$logdir/build-status";
+ debug "Build status file is $fname";
+
+ return $fname;
+}
+
+# Subroutine to retrieve a subdirecty path for the given module.
+# First parameter is the name of the module, and the second
+# parameter is the option key (e.g. build-dir or log-dir).
+sub get_subdir_path
+{
+ my $module = shift;
+ my $option = shift;
+ my $dir = get_option($module, $option);
+
+ # If build-dir starts with a slash, it is an absolute path.
+ return $dir if $dir =~ /^\//;
+
+ # If it starts with a tilde, expand it out.
+ if ($dir =~ /^~/)
+ {
+ $dir =~ s/^~/$ENV{'HOME'}/;
+ }
+ else
+ {
+ # Relative directory, tack it on to the end of $kdesvn.
+ my $kdesvndir = get_kdesvn_dir();
+ $dir = "$kdesvndir/$dir";
+ }
+
+ return $dir;
+}
+
+# Subroutine to return the name of the destination directory for the checkout
+# and build routines. Based on the dest-dir option. The return value will be
+# relative to the src/build dir. The user may use the '$MODULE' or '${MODULE}'
+# sequences, which will be replaced by the name of the module in question.
+#
+# The first parameter should be the module name.
+sub get_dest_dir
+{
+ my $module = shift;
+ my $dest_dir = get_option($module, 'dest-dir');
+
+ $dest_dir =~ s/(\${MODULE})|(\$MODULE\b)/$module/g;
+
+ return $dest_dir;
+}
+
+# Convienience subroutine to get the source root dir.
+sub get_kdesvn_dir
+{
+ return get_option ('global', 'source-dir');
+}
+
+# Function to work around a Perl language limitation.
+# First parameter is the list to search.
+# Second parameter is the value to search for.
+# Returns true if the value is in the list
+sub list_has(\@$)
+{
+ my ($list_ref, $value) = @_;
+ return scalar grep ($_ eq $value, @{$list_ref});
+}
+
+# Subroutine to return the branch prefix. i.e. the part before the branch name
+# and module name.
+#
+# The first parameter is the module in question.
+# The second parameter should be 'branches' if we're dealing with a branch or
+# 'tags' if we're dealing with a tag.
+#
+# Ex: 'kdelibs' => 'branches/KDE'
+# 'kdevelop' => 'branches/kdevelop'
+sub branch_prefix
+{
+ my $module = shift;
+ my $type = shift;
+
+ # These modules seem to have their own subdir in /tags.
+ my @tag_components = qw/arts koffice amarok kst qt taglib/;
+
+ # The map call adds the kde prefix to the module names because I don't feel
+ # like typing them all in. kdevelop and konstruct are special cases.
+ my @kde_module_list = ((map {'kde' . $_} qw/-i18n -common accessibility
+ addons admin artwork base bindings edu games graphics libs
+ multimedia network nonbeta pim sdk toys utils webdev/), 'kdevelop',
+ 'konstruct');
+
+ # KDE proper modules seem to use this pattern.
+ return "$type/KDE" if list_has(@kde_module_list, $module);
+
+ # If we doing a tag just return 'tags' because the next part is the actual
+ # tag name, which is added by the caller, unless the module has its own
+ # subdirectory in /tags.
+ return "$type" if $type eq 'tags' and not list_has(@tag_components, $module);
+
+ # Everything else.
+ return "$type/$module";
+}
+
+# Subroutine to return a module URL for a module using the 'branch' option.
+# First parameter is the module in question.
+# Second parameter is the type ('tags' or 'branches')
+sub handle_branch_tag_option
+{
+ my ($module, $type) = @_;
+ my $svn_server = get_option($module, 'svn-server');
+ my $branch = branch_prefix($module, $type);
+ my $branchname = get_option($module, 'tag');
+
+ if($type eq 'branches')
+ {
+ $branchname = get_option($module, 'branch');
+ }
+
+ # Remove trailing slashes.
+ $svn_server =~ s/\/*$//;
+
+ return "$svn_server/$branch/$branchname/$module";
+}
+
+# Subroutine to return the appropriate SVN URL for a given module, based on
+# the user settings. For example, 'kdelibs' -> https://svn.kde.org/home/kde/trunk/KDE/kdelibs
+sub svn_module_url
+{
+ my $module = shift;
+ my $svn_server = get_option($module, 'svn-server');
+ my $branch = get_option($module, 'module-base-path');
+
+ # Allow user to override normal processing of the module in a few ways,
+ # to make it easier to still be able to use kdesvn-build even when I
+ # can't be there to manually update every little special case.
+ if(get_option($module, 'override-url'))
+ {
+ return get_option($module, 'override-url');
+ }
+
+ if(get_option($module, 'tag'))
+ {
+ return handle_branch_tag_option($module, 'tags');
+ }
+
+ if(get_option($module, 'branch'))
+ {
+ return handle_branch_tag_option($module, 'branches');
+ }
+
+ # The following modules are in /trunk, not /trunk/KDE. There are others,
+ # but there are the important ones. The hash is associated with the value
+ # 1 so that we can do a boolean test by looking up the module name.
+ my @non_trunk_modules = qw(extragear kdenonbeta kdesupport koffice
+ playground qt-copy valgrind KDE kdereview www l10n);
+
+ my $module_root = $module;
+ $module_root =~ s/\/.*//; # Remove everything after the first slash
+
+ if (not $branch)
+ {
+ $branch = 'trunk/KDE';
+ $branch = 'trunk' if list_has(@non_trunk_modules, $module_root);
+ }
+
+ $branch =~ s/^\/*//; # Eliminate / at beginning of string.
+ $branch =~ s/\/*$//; # Likewise at the end.
+
+ # Remove trailing slashes.
+ $svn_server =~ s/\/*$//;
+
+ return "$svn_server/$branch/$module";
+}
+
+# Convienience subroutine to return the build directory for a module. Use
+# this instead of get_subdir_path because this special-cases modules for you,
+# such as qt-copy.
+# TODO: From what I hear this hack is no longer necessary. Investigate this.
+sub get_build_dir
+{
+ my $module = shift;
+
+ # It is the responsibility of the caller to append $module!
+ return get_kdesvn_dir() if ($module eq 'qt-copy') and not get_option('qt-copy', 'use-qt-builddir-hack');
+ return get_subdir_path($module, 'build-dir');
+}
+
+# Subroutine to return a list of the different log directories that are used
+# by the different modules in the script.
+sub get_all_log_directories
+{
+ my @module_list = keys %package_opts;
+ my %log_dict;
+
+ # A hash is used to track directories to avoid duplicate entries.
+ unshift @module_list, "global";
+ $log_dict{get_subdir_path($_, 'log-dir')} = 1 foreach @module_list;
+
+ debug "Log directories are ", join (", ", keys %log_dict);
+ return keys %log_dict;
+}
+
+# Subroutine to determine the build id for this invocation of the script. The
+# idea of a build id is that we want to be able to run the script more than
+# once in a day and still retain each set of logs. So if we run the script
+# more than once in a day, we need to increment the build id so we have a
+# unique value. This subroutine sets the global variable $BUILD_ID and
+# $LOG_DATE for use by the logging subroutines.
+sub setup_logging_subsystem
+{
+ my $min_build_id = "00";
+ my $date = strftime "%F", localtime; # ISO 8601 date
+ my @log_dirs = get_all_log_directories();
+
+ for (@log_dirs)
+ {
+ my $id = "01";
+ $id++ while -e "$_/$date-$id";
+
+ # We need to use a string comparison operator to keep
+ # the magic in the ++ operator.
+ $min_build_id = $id if $id gt $min_build_id;
+ }
+
+ $LOG_DATE = $date;
+ $BUILD_ID = $min_build_id;
+}
+
+# Convienience subroutine to return the log directory for a module.
+# It also creates the directory and manages the 'latest' symlink.
+#
+# Returns undef on an error, or the name of the directory otherwise.
+sub get_log_dir
+{
+ my $module = shift;
+ my $logbase = get_subdir_path($module, 'log-dir');
+ my $logpath = "$logbase/$LOG_DATE-$BUILD_ID/$module";
+
+ $logpath = "$logbase/$LOG_DATE-$BUILD_ID" if $module eq 'global';
+
+ debug "Log directory for $module is $logpath";
+
+ if (not -e $logpath and not pretending and not super_mkdir($logpath))
+ {
+ error "Unable to create log directory r[$logpath]";
+ return undef;
+ }
+
+ # Add symlink to the directory.
+ # TODO: This probably can result in a few dozen unnecessary calls to
+ # unlink and symlink, fix this.
+ if (not pretending)
+ {
+ unlink("$logbase/latest") if -l "$logbase/latest";
+ symlink("$logbase/$LOG_DATE-$BUILD_ID", "$logbase/latest");
+ }
+
+ return $logpath;
+}
+
+# This function returns true if the given option doesn't make sense with the
+# given module.
+# blacklisted($module, $option)
+sub blacklisted
+{
+ my ($module, $option) = @_;
+
+ # Known to not work.
+ my @unsermake_ban_list = qw/valgrind kde-common qt-copy kdebindings/;
+
+ return list_has(@unsermake_ban_list, $module) if ($option eq 'use-unsermake');
+ return 0;
+}
+
+# This subroutine returns an option value for a given module. Some
+# globals can't be overridden by a module's choice. If so, the
+# module's choice will be ignored, and a warning will be issued.
+#
+# Option names are case-sensitive!
+#
+# First parameter: Name of module
+# Second paramenter: Name of option
+sub get_option
+{
+ my $module = shift;
+ my $option = shift;
+ my $global_opts = $package_opts{'global'};
+ my $defaultQtCopyArgs = '-qt-gif -plugin-imgfmt-mng -thread -no-exceptions -debug -dlopen-opengl -plugin-sql-sqlite';
+ my @lockedOpts = qw(source-dir svn-server qtdir libpath binpath kdedir
+ pretend disable-agent-check);
+
+ # These options can't override globals
+ if (list_has(@lockedOpts, $option) or $module eq 'global')
+ {
+ return ${$global_opts}{"#$option"} if exists ${$global_opts}{"#$option"};
+ return ${$global_opts}{$option};
+ }
+
+ # Don't even try this
+ return 0 if blacklisted($module, $option);
+
+ my $ref = $package_opts{$module};
+
+ # Check for a sticky option
+ return $$ref{"#$option"} if exists $$ref{"#$option"};
+
+ # Next in order of precedence
+ if (defined ${$global_opts}{"#$option"} and not
+ ($module eq 'qt-copy' and $option eq 'configure-flags'))
+ {
+ return ${$global_opts}{"#$option"};
+ }
+
+ # No sticky options left.
+ # Configure flags and CXXFLAGS are appended to the global option
+ if (($module ne 'qt-copy' && $option eq 'configure-flags')
+ || $option eq 'cxxflags')
+ {
+ my $value = ${$global_opts}{$option};
+
+ if(defined $$ref{$option})
+ {
+ my $modvalue = $$ref{$option};
+ $value .= " $modvalue";
+ }
+
+ return $value;
+ }
+
+ # As always qt-copy has to be difficult
+ if ($module eq 'qt-copy' and $option eq 'configure-flags')
+ {
+ return $defaultQtCopyArgs if not defined $$ref{$option};
+ return $$ref{$option};
+ }
+
+ # Everything else overrides the global, unless of course it's not set.
+ # If we're reading for global options, we're pretty much done.
+ return $$ref{$option} if defined $$ref{$option};
+ return ${$global_opts}{$option};
+}
+
+# Subroutine used to handle the checkout-only option. It handles
+# updating subdirectories of an already-checked-out module.
+# First parameter is the module, all remaining parameters are subdirectories
+# to check out.
+#
+# Returns 0 on success, non-zero on failure.
+sub update_module_subdirectories
+{
+ my $module = shift;
+ my $result;
+
+ # If we have elements in @path, download them now
+ for my $dir (@_)
+ {
+ info "\tUpdating g[$dir]";
+ $result = run_svn($module, "svn-up-$dir", [ 'svn', 'up', $dir ]);
+ return $result if $result;
+ }
+
+ return 0;
+}
+
+# Returns true if a module has a base component to their name (e.g. KDE/,
+# extragear/, or playground). Note that modules that aren't in trunk/KDE
+# don't necessary meet this criteria (e.g. kdereview is a module itself).
+sub has_base_module
+{
+ my $module = shift;
+
+ return $module =~ /^(extragear|playground|KDE)(\/[^\/]+)?$/;
+}
+
+# Subroutine to return the directory that a module will be stored in.
+# NOTE: The return value is a hash. The key 'module' will return the final
+# module name, the key 'path' will return the full path to the module. The
+# key 'fullpath' will return their concatenation.
+# For example, with $module == 'KDE/kdelibs', and no change in the dest-dir
+# option, you'd get something like:
+# {
+# 'path' => '/home/user/kdesvn/KDE',
+# 'module' => 'kdelibs',
+# 'fullpath' => '/home/user/kdesvn/KDE/kdelibs'
+# }
+# If dest-dir were changed to e.g. extragear-multimedia, you'd get:
+# {
+# 'path' => '/home/user/kdesvn',
+# 'module' => 'extragear-multimedia',
+# 'fullpath' => '/home/user/kdesvn/extragear-multimedia'
+# }
+# First parameter is the module.
+# Second parameter is either source or build.
+sub get_module_path_dir
+{
+ my $module = shift;
+ my $type = shift;
+ my $destdir = get_dest_dir($module);
+ my $srcbase = get_kdesvn_dir();
+ $srcbase = get_build_dir($module) if $type eq 'build';
+
+ my $combined = "$srcbase/$destdir";
+
+ # Remove dup //
+ $combined =~ s/\/+/\//;
+
+ my @parts = split(/\//, $combined);
+ my %result = ();
+ $result{'module'} = pop @parts;
+ $result{'path'} = join('/', @parts);
+ $result{'fullpath'} = "$result{path}/$result{module}";
+
+ return %result;
+}
+
+sub get_fullpath
+{
+ my ($module, $type) = @_;
+ my %pathinfo = get_module_path_dir($module, $type);
+
+ return $pathinfo{'fullpath'};
+}
+
+# Checkout a module that has not been checked out before, along with any
+# subdirectories the user desires.
+# The first parameter is the module to checkout (including extragear and
+# playground modules), all remaining parameters are subdirectories of the
+# module to checkout.
+# Returns 0 on success, non-zero on failure.
+sub checkout_module_path
+{
+ my ($module, @path) = @_;
+ my %pathinfo = get_module_path_dir($module, 'source');
+ my $result;
+ my @args;
+
+ if (not -e $pathinfo{'path'} and not super_mkdir($pathinfo{'path'}))
+ {
+ error "Unable to create path r[$pathinfo{path}]!";
+ return 1;
+ }
+
+ chdir($pathinfo{'path'});
+
+ push @args, ('svn', 'co');
+ push @args, '-N' if scalar @path;
+ push @args, svn_module_url($module);
+ push @args, $pathinfo{'module'};
+
+ note "Checking out g[$module]";
+ $result = run_svn($module, 'svn-co', \@args);
+ return $result if $result;
+
+ chdir($pathinfo{'module'}) if scalar @path;
+
+ return update_module_subdirectories($module, @path);
+}
+
+# Update a module that has already been checked out, along with any
+# subdirectories the user desires.
+# The first parameter is the module to checkout (including extragear and
+# playground modules), all remaining parameters are subdirectories of the
+# module to checkout.
+# Returns 0 on success, non-zero on failure.
+sub update_module_path
+{
+ my ($module, @path) = @_;
+ my $fullpath = get_fullpath($module, 'source');
+ my $result;
+ my @args;
+
+ chdir $fullpath;
+
+ push @args, ('svn', 'up');
+ push @args, '-N' if scalar @path;
+
+ note "Updating g[$module]";
+
+ $result = run_svn($module, 'svn-up', \@args);
+
+ if($result) # Update failed, try svn cleanup.
+ {
+ info "\tUpdate failed, trying a cleanup.";
+ $result = safe_system('svn', 'cleanup');
+
+ return $result if $result;
+
+ info "\tCleanup complete.";
+ # Now try again.
+
+ $result = run_svn($module, 'svn-up-2', \@args);
+ }
+
+ return $result if $result;
+
+ # If the admin dir exists and is a soft link, remove it so that svn can
+ # update it if need be. The link will automatically be re-created later
+ # in the process if necessary by the build functions.
+ unlink ("$fullpath/admin") if -l "$fullpath/admin";
+
+ return update_module_subdirectories($module, @path);
+}
+
+# Subroutine to run a command with redirected STDOUT and STDERR. First parameter
+# is name of the log file (relative to the log directory), and the
+# second parameter is a reference to an array with the command and
+# its arguments
+sub log_command
+{
+ my $pid;
+ my $module = shift;
+ my $filename = shift;
+ my @command = @{(shift)};
+ my $logdir = get_log_dir($module);
+
+ debug "log_command(): Module $module, Command: ", join(' ', @command);
+
+ if (pretending)
+ {
+ pretend "\tWould have run g[", join (' ', @command);
+ return 0;
+ }
+
+ if ($pid = fork)
+ {
+ # Parent
+ waitpid $pid, 0;
+
+ # If the module fails building, set an internal flag in the module
+ # options with the name of the log file containing the error message.
+ my $result = $?;
+ set_error_logfile($module, "$filename.log") if $result;
+
+ # If we are using the alias to a kdesvn-build function, it should have
+ # already printed the error message, so clear out errno (but still
+ # return failure status).
+ if ($command[0] eq 'kdesvn-build')
+ {
+ $! = 0;
+ }
+
+ return $result;
+ }
+ else
+ {
+ # Child
+ if (not defined $logdir or not -e $logdir)
+ {
+ # Error creating directory for some reason.
+ error "\tLogging to std out due to failure creating log dir.";
+ }
+
+ # Redirect stdout and stderr to the given file.
+ if (not debugging)
+ {
+# Comment this out because it conflicts with make-install-prefix
+# open (STDIN, "</dev/null");
+ open (STDOUT, ">$logdir/$filename.log") or do {
+ error "Error opening $logdir/$filename.log for logfile.";
+ # Don't abort, hopefully STDOUT still works.
+ };
+ }
+ else
+ {
+ open (STDOUT, "|tee $logdir/$filename.log") or do {
+ error "Error opening pipe to tee command.";
+ # Don't abort, hopefully STDOUT still works.
+ };
+ }
+
+ # Make sure we log everything. If the command is svn, it is possible
+ # that the client will produce output trying to get a password, so
+ # don't redirect stderr in that case.
+ open (STDERR, ">&STDOUT") unless $command[0] eq 'svn';
+
+ # Call internal function, name given by $command[1]
+ if($command[0] eq 'kdesvn-build')
+ {
+ debug "Calling $command[1]";
+
+ my $cmd = $command[1];
+ splice (@command, 0, 2); # Remove first two elements.
+
+ no strict 'refs'; # Disable restriction on symbolic subroutines.
+ if (not &{$cmd}(@command)) # Call sub
+ {
+ exit EINVAL;
+ }
+
+ exit 0;
+ }
+
+ # External command.
+ exec (@command) or do {
+ my $cmd_string = join(' ', @command);
+ error <<EOF;
+r[b[Unable to execute "$cmd_string"]!
+ $!
+
+Please check your binpath setting (it controls the PATH used by kdesvn-build).
+Currently it is set to g[$ENV{PATH}].
+EOF
+ # Don't use return, this is the child still!
+ exit 1;
+ };
+ }
+}
+
+# Subroutine to mark a file as being the error log for a module. This also
+# creates a symlink in the module log directory for easy viewing.
+# First parameter is the module in question.
+# Second parameter is the filename in the log directory of the error log.
+sub set_error_logfile
+{
+ my ($module, $logfile) = @_;
+ my $logdir = get_log_dir($module);
+
+ return unless $logfile;
+
+ set_option($module, '#error-log-file', "$logdir/$logfile");
+
+ # Setup symlink in the module log directory pointing to the appropriate
+ # file. Make sure to remove it first if it already exists.
+ unlink("$logdir/error.log") if -l "$logdir/error.log";
+
+ if(-e "$logdir/error.log")
+ {
+ # Maybe it was a regular file?
+ error "r[b[ * Unable to create symlink to error log file]";
+ return 0;
+ }
+
+ symlink "$logdir/$logfile", "$logdir/error.log";
+}
+
+# Subroutine to run make/unsermake with redirected STDOUT and STDERR,
+# and to process the percentage in unsermake (-p). First parameter
+# is name of the log file (relative to the log directory), and the
+# second parameter is a reference to an array with the command and
+# its arguments.
+#
+# TODO: This is a fork of log_command(). Find a way to re-merge them.
+# Returns 0 on success, non-zero on failure.
+sub run_make_command
+{
+ my $pid;
+ my $module = shift;
+ my $filename = shift;
+ my @command = @{(shift)};
+ my $logdir = get_log_dir($module);
+ my $isunsermake = $command[0] =~ 'unsermake';
+
+ # Don't print ANSI characters if we're not on a tty. Also, automake
+ # doesn't support printing output status. Finally, we output the whole
+ # log to screen when debugging which makes this useless.
+ if (!$isunsermake or not -t STDERR or debugging)
+ {
+ return log_command($module, $filename, \@command);
+ }
+
+ # Make sure -p is in the unsermake flags, it's the whole reason for using
+ # this function.
+ if (!(grep /^(-p)|(--print-progress)$/, @command))
+ {
+ # Add in front of element 1, deleting 0 elements.
+ splice @command, 1, 0, '-p';
+ }
+
+ if (pretending)
+ {
+ pretend "\tWould have run g[", join (' ', @command);
+ return 0;
+ }
+
+ $pid = open(CHILD, '-|');
+ if ($pid)
+ {
+ my $last = -1;
+
+ while (<CHILD>)
+ {
+ chomp;
+
+ # Update terminal (\e[K clears the line) if the percentage
+ # changed.
+ if (/([0-9]+)% (creating|compiling|linking)/)
+ {
+ print STDERR "\r$1% \e[K" unless ($1 == $last);
+ $last = $1;
+ }
+ }
+
+ close(CHILD);
+ print STDERR "\r\e[K";
+
+ # If the module fails building, set an internal flag in the module
+ # options with the name of the log file containing the error message.
+ my $result = $?;
+ set_error_logfile($module, "$filename.log") if $result;
+
+ return $result;
+ }
+ else
+ {
+ # Child
+ if (not defined $logdir or not -e $logdir)
+ {
+ # Error creating directory for some reason.
+ error "\tLogging to standard output due to failure creating log dir.";
+ }
+
+ open (STDOUT, "|tee $logdir/$filename.log") or do {
+ error "Error opening pipe to tee command."
+ };
+
+ # Make sure we log everything.
+ open (STDERR, ">&STDOUT");
+
+ exec (@command) or do {
+ my $cmd_string = join(' ', @command);
+ error <<EOF;
+r[b[Unable to execute "$cmd_string"]!
+ $!
+
+Please check your binpath setting (it controls the PATH used by kdesvn-build).
+Currently it is set to g[$ENV{PATH}].
+EOF
+ # Don't return, we're still in the child!
+ exit 1;
+ };
+ }
+}
+
+# Subroutine to determine if the given subdirectory of a module can actually be
+# built or not. For instance, /admin can never be built, and the /kalyptus subdir
+# of kdebindings can't either.
+sub is_subdir_buildable
+{
+ my ($module, $dir) = @_;
+
+ return 0 if $dir eq 'admin';
+ return 0 if $dir eq 'kalyptus' and $module eq 'kdebindings';
+ return 1;
+}
+
+# Subroutine to return the path to the given executable based on the current
+# binpath settings. e.g. if you pass make you could get '/usr/bin/make'. If
+# the executable is not found undef is returned.
+#
+# This assumes that the module environment has already been updated since
+# binpath doesn't exactly correspond to $ENV{'PATH'}.
+sub path_to_prog
+{
+ my $prog = shift;
+ my @paths = split(/:/, $ENV{'PATH'});
+
+ # If it starts with a / the path is already absolute.
+ return $prog if $prog =~ /^\//;
+
+ for my $path (@paths)
+ {
+ return "$path/$prog" if (-x "$path/$prog");
+ }
+
+ return undef;
+}
+
+# Subroutine to run the make command with the arguments given by the passed
+# list. The first argument of the list given must be the module that we're
+# making. The second argument is the "try number", used in creating the log
+# file name.
+#
+# Returns 0 on success, non-zero on failure (shell script style)
+sub safe_make (@)
+{
+ my ($module, $trynumber, $apidox, @args) = @_;
+ my $opts;
+ my $logdir = get_log_dir($module);
+ my $checkout_dirs = get_option($module, "checkout-only");
+ my @dirs = split(' ', $checkout_dirs);
+ my $installing = $trynumber eq 'install';
+ my $make = 'make';
+
+ if (get_option($module, 'use-unsermake'))
+ {
+ $make = get_option('global', 'unsermake-path');
+ $opts = get_option($module, 'unsermake-options');
+ }
+ else
+ {
+ $opts = get_option($module, 'make-options');
+ }
+
+ # Convert the path to an absolute path since I've encountered a sudo that
+ # is apparently unable to guess. Maybe it's better that it doesn't guess
+ # anyways from a security point-of-view.
+ $make = path_to_prog($make) unless pretending;
+
+ if(not defined $make)
+ {
+ # Weird, we can't find make, you'd think configure would have
+ # noticed...
+ error " r[b[*] Unable to find the g[make] executable!";
+
+ # Make sure we don't bother trying again, this is a more serious
+ # error.
+ set_option($module, "#was-rebuilt", 1);
+ return 1;
+ }
+
+ # Add make-options to the given options, as long as we're not installing
+ # If we are installing, unsermake seems to assume that the options are a
+ # make target, and parallel builds don't help with installing anyways.
+ unshift (@args, split(' ', $opts)) unless $installing;
+
+ my $description;
+
+ # Check if we're installing
+ if($installing)
+ {
+ debug "Prepending install options, apidox: $apidox.";
+
+ $description = $apidox ? "API Documentation" : clr "g[$module]";
+ unshift @args, $make, $apidox ? 'install-apidox' : 'install';
+ unshift @args, split(' ', get_option ($module, 'make-install-prefix'));
+
+ info "\tInstalling $description.";
+ }
+ else
+ {
+ $description = "Building API Documentation";
+ $description = "Compiling, attempt $trynumber" unless $apidox;
+
+ push @args, 'apidox' if $apidox;
+ unshift @args, $make;
+
+ info "\t$description...";
+ }
+
+ push (@dirs, "") if scalar @dirs == 0;
+ for my $subdir (@dirs)
+ {
+ # Some subdirectories shouldn't have make run within them.
+ next unless is_subdir_buildable($module, $subdir);
+
+ my $logname = "build-$trynumber";
+ if ($installing)
+ {
+ $logname = $apidox ? 'install-apidox' : 'install';
+ }
+
+ if ($subdir ne '')
+ {
+ $logname = $installing ? "install-$subdir" : "build-$subdir-$trynumber";
+ next if $apidox; # Don't built apidox in a subdirectory
+
+ info $installing ? "\tInstalling " : "\tBuilding ", "subdirectory g[$subdir]";
+ }
+
+ my %pathinfo = get_module_path_dir($module, 'build');
+ my $builddir = "$pathinfo{fullpath}/$subdir";
+ $builddir =~ s/\/*$//;
+
+ chdir ($builddir);
+
+ my $result = run_make_command ($module, $logname, \@args );
+ return $result if $result;
+ };
+
+ return 0;
+}
+
+# Subroutine to add a variable to the environment, but ONLY if it
+# is set. First parameter is the variable to set, the second is the
+# value to give it.
+sub setenv
+{
+ my ($var, $val) = @_;
+
+ return unless $val;
+
+ pretend "\tWould have set g[$var]=y[$val].";
+
+ $ENV{$var} = $val;
+}
+
+# Display a message to the user regarding their relative lack of
+# ~/.kdesvn-buildrc, and point them to some help. We will continue using a
+# default set of options.
+sub no_config_whine
+{
+ my $searched = join("\n ", @rcfiles);
+ my $homepage = "http://kdesvn-build.kde.org/";
+
+ note <<"HOME";
+Unable to open configuration file!
+We looked for:
+ $searched
+
+kdesvn-build will continue using a default set of options. These options may
+not apply to you, so feel free to visit the kdesvn-build homepage
+
+b[g[$homepage]
+
+and use the configuration file generator to guide you through the process of
+creating a config file to customize your kdesvn-build process.
+
+HOME
+}
+
+# This subroutine assigns the appropriate options to %package_opts and the
+# update and build lists to build a default set of modules.
+sub setup_default_modules()
+{
+ @update_list = qw(qt-copy arts kdesupport kdelibs kdebase kdeartwork
+ kdemultimedia kdepim kdeutils kdegraphics kdegames
+ kdetoys kdeedu kdeaddons);
+ @build_list = @update_list;
+
+ for my $i (@update_list) {
+ if (not exists $package_opts{$i})
+ {
+ $package_opts{$i} = { }; # Set up defaults
+ $package_opts{$i}{'set-env'} = { };
+ }
+ }
+
+ # Setup default options for qt-copy
+ $package_opts{'qt-copy'} = {
+ 'conf-flags' => q(-system-zlib -qt-gif -system-libjpeg -system-libpng
+ -plugin-imgfmt-mng -thread -no-exceptions -debug
+ -dlopen-opengl),
+ 'apply-qt-patches' => 'true',
+
+# See setup_kde35_hack() for why this option is here.
+ 'module-base-path' => 'branches/qt/3.3',
+
+ 'use-qt-builddir-hack' => 'true',
+ 'use-unsermake' => 0,
+ 'set-env' => { },
+ };
+
+ # That handy q() construct above kept the newlines, I don't want them.
+ $package_opts{'qt-copy'}{'conf-flags'} =~ s/\s+/ /gm;
+}
+
+# Reads in the options from the config file and adds them to the option store.
+# The first parameter is a reference to the file handle to read from.
+# The second parameter is 'global' if we're reading the global section, or
+# 'module' if we should expect an end module statement.
+sub parse_module
+{
+ my ($fh, $module) = @_;
+ $module = 'global' unless $module;
+
+ # Make sure we acknowledge that we read the module name in from the
+ # file.
+ if (not defined $package_opts{$module})
+ {
+ $package_opts{$module} = {
+ 'set-env' => { }
+ };
+ }
+
+ # Read in each option
+ while (<$fh>)
+ {
+ # Handle line continuation
+ chomp;
+
+ if(s/\\\s*$//) # Replace \ followed by optional space at EOL and try again.
+ {
+ $_ .= <$fh>;
+ redo unless eof($fh);
+ }
+
+ s/#.*$//; # Remove comments
+ next if /^\s*$/; # Skip blank lines
+
+ if($module eq 'global')
+ {
+ last if /^end\s+global/; # Stop
+ }
+ else
+ {
+ last if /^end\s+module/; # Stop
+ }
+
+ # The option is the first word, followed by the
+ # flags on the rest of the line. The interpretation
+ # of the flags is dependant on the option.
+ my ($option, $value) = /^\s* # Find all spaces
+ ([-\w]+) # First match, alphanumeric, -, and _
+ # (?: ) means non-capturing group, so (.*) is $value
+ # So, skip spaces and pick up the rest of the line.
+ (?:\s+(.*))?$/x;
+
+ $value = "" unless defined $value;
+
+ # Simplify this.
+ $value =~ s/\s+$//;
+ $value =~ s/^\s+//;
+ $value =~ s/\s+/ /;
+
+ # Check for false keyword and convert it to Perl false.
+ $value = 0 if lc($value) =~ /^false$/;
+
+ # Replace tildes with home directory.
+ 1 while ($value =~ s"(^|:|=)~/"$1$ENV{'HOME'}/");
+
+ set_option($module, $option, $value);
+ }
+}
+
+# This subroutine reads in the settings from the user's configuration
+# file.
+sub read_options
+{
+ # The options are stored in the file $rcfile
+ my $success = 0;
+ my $global_opts = $package_opts{'global'};
+ for my $file (@rcfiles)
+ {
+ if (open CONFIG, "<$file")
+ {
+ $success = 1;
+ $rcfile = $file;
+ last;
+ }
+ }
+
+ if (not $success)
+ {
+ if(scalar @rcfiles == 1)
+ {
+ # This can only happen if the user uses --rc-file, if we fail to
+ # load the file, we need to fail to load.
+ error <<EOM;
+Unable to open config file $rcfiles[0]
+
+Script stopping here since you specified --rc-file on the command line to
+load $rcfiles[0] manually. If you wish to run the script with no configuration
+file, leave the --rc-file option out of the command line.
+
+EOM
+ exit 1;
+ }
+
+ no_config_whine();
+ setup_default_modules();
+ return;
+ }
+
+ my ($option, $flags, $modulename);
+
+ # FIXME: Make global settings optional if only tweaks needed are for
+ # modules.
+
+ # Read in global settings
+ while (<CONFIG>)
+ {
+ s/#.*$//; # Remove comments
+ next if (/^\s*$/); # Skip blank lines
+
+ # First command in .kdesvn-buildrc should be a global
+ # options declaration, even if none are defined.
+ if (not /^global\s*$/)
+ {
+ error "Invalid configuration file: $rcfile.";
+ error "Expecting global settings section!";
+ exit 1;
+ }
+
+ # Now read in each global option
+ parse_module(\*CONFIG, 'global');
+ last;
+ }
+
+ my $using_default = 1;
+
+ # Now read in module settings
+ while (<CONFIG>)
+ {
+ s/#.*$//; # Remove comments
+ next if (/^\s*$/); # Skip blank lines
+
+ # Get modulename (has dash, dots, slashes, or letters/numbers)
+ ($modulename) = /^module\s+([-\/\.\w]+)\s*$/;
+
+ if (not $modulename)
+ {
+ warning "Invalid configuration file $rcfile!";
+ warning "Expecting a start of module section.";
+ warning "Global settings will be retained.";
+
+ $modulename = 'null'; # Keep reading the module section though.
+ }
+
+ # Don't build default modules if user has their own wishes.
+ if ($using_default)
+ {
+ $using_default = 0;
+ @update_list = @build_list = ( );
+ }
+
+ parse_module(\*CONFIG, $modulename);
+
+ next if ($modulename eq 'null');
+
+ # Done reading options, add this module to the update list
+ push (@update_list, $modulename) unless exists $ignore_list{$modulename};
+
+ # Add it to the build list, unless the build is only
+ # supposed to be done manually.
+ if (not get_option ($modulename, 'manual-build') and not exists $ignore_list{$modulename})
+ {
+ push (@build_list, $modulename);
+ }
+ }
+
+ close CONFIG;
+
+ delete $package_opts{'null'}; # Just in case.
+
+ # For the 3.5 edition we want to set the qt-copy option module-base-path
+ # to branches/qt/3.3 unless the user already has it set.
+ unless (exists $package_opts{'qt-copy'}{'module-base-path'})
+ {
+ set_option ('qt-copy', 'module-base-path', 'branches/qt/3.3');
+ }
+
+ # If the user doesn't ask to build any modules, build a default set.
+ # The good question is what exactly should be built, but oh well.
+ setup_default_modules() if $using_default;
+}
+
+# Subroutine to check if the given module needs special treatment to support
+# srcdir != builddir. If this function returns true kdesvn-build will use a
+# few hacks to simulate it, and will update e.g. configure paths appropriately
+# as well.
+sub module_needs_builddir_help
+{
+ my $module = shift;
+ my @module_help_list = qw/qt-copy kdebindings valgrind/;
+
+ # qt-copy special case to support use-qt-builddir-hack.
+ if ($module eq 'qt-copy' and not get_option('qt-copy', 'use-qt-builddir-hack'))
+ {
+ return 0;
+ }
+
+ return list_has(@module_help_list, $module);
+}
+
+# This subroutine reads the set-env option for a given module and initializes
+# the environment based on that setting.
+sub setup_module_environment
+{
+ my $module = shift;
+ my ($key, $value);
+
+ # Let's see if the user has set env vars to be set.
+ my $env_hash_ref = get_option($module, 'set-env');
+ while (($key, $value) = each %{$env_hash_ref})
+ {
+ setenv($key, $value);
+ }
+}
+
+# Subroutine to initialize some environment variable for building
+# KDE from Subversion. Change this section if a dependency changes later.
+sub initialize_environment
+{
+ $ENV{"WANT_AUTOMAKE"} = "1.7";
+ $ENV{"WANT_AUTOCONF_2_5"} = "1";
+ $ENV{"PATH"} = get_option ('global', 'binpath');
+
+ my $svnserver = get_option ('global', 'svn-server');
+
+ my $pc_path = get_option('global', 'kdedir') . "/lib/pkgconfig";
+ $pc_path .= ":" . $ENV{'PKG_CONFIG_PATH'} if ( exists $ENV{'PKG_CONFIG_PATH'} );
+ $ENV{'PKG_CONFIG_PATH'} = $pc_path;
+
+ if(-t STDOUT and get_option('global', 'colorful-output'))
+ {
+ $RED = "\e[31m";
+ $GREEN = "\e[32m";
+ $YELLOW = "\e[33m";
+ $NORMAL = "\e[0m";
+ $BOLD = "\e[1m";
+ }
+
+ # Set the process priority
+ setpriority PRIO_PROCESS, 0, get_option('global', 'niceness');
+
+ setup_module_environment ('global');
+}
+
+# Subroutine to get a list of modules to install, either from the command line
+# if it's not empty, or based on the list of modules successfully built.
+sub get_install_list
+{
+ my @install_list;
+
+ if ($#ARGV > -1)
+ {
+ @install_list = @ARGV;
+ @ARGV = ();
+ }
+ else
+ {
+ # Get list of built items from $logdir/latest/build-status
+ my $logdir = get_subdir_path('global', 'log-dir');
+
+ if (not open BUILTLIST, "<$logdir/latest/build-status")
+ {
+ error "Can't determine what modules have built. You must";
+ error "specify explicitly on the command line what modules to build.";
+ exit (1); # Don't finish, no lock has been taken.
+ }
+
+ while (<BUILTLIST>)
+ {
+ chomp;
+ if (/Succeeded/)
+ {
+ # Clip to everything before the first colon.
+ my $module = (split(/:/))[0];
+ push @install_list, $module;
+ }
+ }
+
+ close BUILTLIST;
+ }
+
+ return @install_list;
+}
+
+# Print out an error message, and a list of modules that match that error
+# message. It will also display the log file name if one can be determined.
+# The message will be displayed all in uppercase, with PACKAGES prepended, so
+# all you have to do is give a descriptive message of what this list of
+# packages failed at doing.
+sub output_failed_module_list($@)
+{
+ my ($message, @fail_list) = @_;
+ $message = uc $message; # Be annoying
+
+ debug "Message is $message";
+ debug "\tfor ", join(', ', @fail_list);
+
+ if (scalar @fail_list > 0)
+ {
+ my $homedir = $ENV{'HOME'};
+ my $logfile;
+
+ warning "\nr[b[<<< PACKAGES $message >>>]";
+
+ for (@fail_list)
+ {
+ $logfile = get_option($_, '#error-log-file');
+ $logfile = "No log file" unless $logfile;
+ $logfile =~ s|$homedir|~|;
+
+ warning "r[$_] - g[$logfile]";
+ }
+ }
+}
+
+# This subroutine reads the fail_lists dictionary to automatically call
+# output_failed_module_list for all the module failures in one function
+# call.
+sub output_failed_module_lists()
+{
+ for my $type (@fail_display_order)
+ {
+ my @failures = @{$fail_lists{$type}};
+ output_failed_module_list("failed to $type", @failures);
+ }
+}
+
+# This subroutine extract the value from options of the form --option=value,
+# which can also be expressed as --option value. The first parameter is the
+# option that the user passed to the cmd line (e.g. --prefix=/opt/foo), and
+# the second parameter is a reference to the list of command line options.
+# The return value is the value of the option (the list might be shorter by
+# 1, copy it if you don't want it to change), or undef if no value was
+# provided.
+sub extract_option_value($\@)
+{
+ my ($option, $options_ref) = @_;
+
+ if ($option =~ /=/)
+ {
+ my @value = split(/=/, $option);
+ shift @value; # We don't need the first one, that the --option part.
+
+ return undef if (scalar @value == 0);
+
+ # If we have more than one element left in @value it's because the
+ # option itself has an = in it, make sure it goes back in the answer.
+ return join('=', @value);
+ }
+
+ return undef if scalar @{$options_ref} == 0;
+ return shift @{$options_ref};
+}
+
+# Utility subroutine to handle setting the environment variable type of value.
+# Returns true (non-zero) if this subroutine handled everything, 0 otherwise.
+# The first parameter should by the reference to the hash with the 'set-env'
+# hash ref, second parameter is the exact option to check, and the third
+# option is the value to set that option to.
+sub handle_set_env
+{
+ my ($href, $option, $value) = @_;
+
+ return 0 if $option !~ /^#?set-env$/;
+
+ my ($var, @values) = split(' ', $value);
+
+ $$href{$option} = ( ) unless exists $$href{$option};
+ $$href{$option}{$var} = join(' ', @values);
+
+ return 1;
+}
+
+# Sets the option for the given module to the given value. If the data for the
+# module doesn't exist yet, it will be defined starting with a default value.
+# First parameter: module to set option for (or 'global')
+# Second parameter: option name (Preceded by # for a sticky option)
+# Third parameter: option value
+# Return value is void
+sub set_option
+{
+ my ($module, $option, $value) = @_;
+
+ # Set module options
+ if (not exists $package_opts{$module})
+ {
+ $package_opts{$module} = {
+ 'set-env' => { }
+ };
+ }
+
+ return if handle_set_env($package_opts{$module}, $option, $value);
+ $package_opts{$module}{$option} = $value;
+}
+
+# Subroutine to process the command line arguments. Any arguments so
+# processed will be removed from @ARGV.
+# The arguments are generally documented in doc.html now.
+# NOTE: Don't call finish() from this routine, the lock hasn't been obtained.
+# NOTE: The options have not been loaded yet either. Any option which
+# requires more than rudimentary processing should set a flag for later work.
+sub process_arguments
+{
+ my $arg;
+ my $version = "kdesvn-build 0.97.6 (KDE 3.5 Edition)";
+ my $author = <<DONE;
+$version was written (mostly) by:
+ Michael Pyne <michael.pyne\@kdemail.net>
+
+Many people have contributed code, bugfixes, and documentation.
+
+Please report bugs using the KDE Bugzilla, at http://bugs.kde.org/
+DONE
+
+ my @argv;
+
+ while ($_ = shift @ARGV)
+ {
+ SWITCH: {
+ /^(--version)$/ && do { print "$version\n"; exit; };
+ /^--author$/ && do { print $author; exit; };
+ /^(-h)|(--?help)$/ && do {
+ print <<DONE;
+$version
+
+This script automates the download, build, and install process for KDE (using
+Subversion).
+
+It is recommended that you first setup a .kdesvn-buildrc file in your home
+directory. Please visit http://kdesvn-build.kde.org/ for
+information on how to write the file, or consult the sample file which should
+have been included with this program. If you don't setup a .kdesvn-buildrc,
+a default set of options will be used, which a few modules to be built by
+default.
+
+After setting up .kdesvn-buildrc, you can run this program from either the
+command-line or from cron. It will automatically download the modules from
+Subversion, create the build system, and configure and make the modules you
+tell it to. If you\'d like, you can use this program to install KDE as well,
+if you\'re building KDE for a single user. Note that kdesvn-build will try
+by default to install the modules.
+
+Basic synopsis, after setting up .kdesvn-buildrc:
+\$ kdesvn-build [package names] (Download, build, and install KDE)
+
+If you don\'t specify any particular package names, then your settings
+in .kdesvn-buildrc will be used. If you DO specify a package name, then
+your settings will still be read, but the script will try to build/install
+the package regardless of .kdesvn-buildrc
+
+Copyright (c) 2003, 2004, 2005 $author
+The script is distributed under the terms of the GNU General Public License
+v2, and includes ABSOLUTELY NO WARRANTY!!!
+
+Options:
+ --no-svn Skip contacting the Subversion server.
+ --no-build Skip the build process.
+ --no-install Don't automatically install after build.
+
+ --svn-only Update from Subversion only (Identical to --no-build
+ at this point).
+ --build-only Build only, don't perform updates or install.
+
+ --pretend (or -p) Don't actually contact the Subversion server, run make,
+ or create/delete files and directories. Instead,
+ output what the script would have done.
+ --quiet (or -q) Be less descriptive of the build process, without
+ printing each little substep kdesvn-build is
+ performing.
+ --really-quiet Only warnings and errors will be displayed.
+ --verbose (or -v) Be *very* descriptive of the build process. Only
+ --debug outputs more.
+ --debug Activates debug mode.
+ --color
+ --no-color Add (or remove) color from the output.
+
+ --rc-file=<filename> Read configuration from filename instead of default.
+ --nice=<value> Allows you to run the script with a lower priority
+ The default value is 10 (lower priority by 10 steps).
+ --prefix=/kde/path This option is a shortcut to change the setting for
+ kdedir from the command line. It implies
+ --reconfigure.
+
+ --resume Tries to resume the make process from the last time
+ the script was run, without performing the Subversion
+ update.
+ --resume-from=<pkg> Starts building from the given package, without
+ performing the Subversion update.
+ --revision (or -r)=<rev> Forces update to revision <rev> from Subversion.
+
+ --refresh-build Start the build from scratch.
+ --reconfigure Run configure again, but don't clean the build
+ directory or re-run make -f Makefile.cvs.
+ --recreate-configure Run make -f Makefile.cvs again to redo the configure
+ script.
+ --no-rebuild-on-fail Don't try to rebuild a module from scratch if it
+ failed building and we didn't already try to build it
+ from scratch.
+ --build-system-only Create the build infrastructure, but don't actually
+ perform the build.
+ --install Try to install the packages passed on the command
+ line, or all packages in ~/.kdesvn-buildrc that don't
+ have manual-build set. Building and Subversion
+ updates are not performed.
+
+ --<option>= Any unrecognized options are added to the global
+ configuration, overriding any value that may exist.
+ --<module>,<option>= Likewise, this allows you to override any module
+ specific option from the command line.
+
+ --help You\'re reading it. :-)
+ --author Output the author(s)\'s name.
+ --version Output the program version.
+
+You can get more help by reading the included HTML documentation, or going
+online to http://kdesvn-build.kde.org/
+DONE
+ # We haven't done any locking... no need to finish()
+ # Avoids log-dir errors due to having not performed.
+ # read_options() and setup_logging_subsystem().
+ exit 0;
+ };
+
+ /^--install$/ && do {
+ $install_flag = 1;
+ last SWITCH;
+ };
+
+ /^--no-svn$/ && do {
+ set_option('global', '#no-svn', 1);
+ last SWITCH;
+ };
+
+ /^--no-install$/ && do {
+ set_option('global', '#install-after-build', 0);
+ last SWITCH;
+ };
+
+ /^(-v)|(--verbose)$/ && do {
+ set_option('global', '#debug-level', WHISPER);
+ last SWITCH;
+ };
+
+ /^(-q)|(--quiet)$/ && do {
+ set_option('global', '#debug-level', NOTE);
+ last SWITCH;
+ };
+
+ /^--really-quiet$/ && do {
+ set_option('global', '#debug-level', WARNING);
+ last SWITCH;
+ };
+
+ /^--debug$/ && do {
+ set_option('global', 'debug-level', DEBUG);
+ last SWITCH;
+ };
+
+ /^--reconfigure$/ && do {
+ set_option('global', '#reconfigure', 1);
+ last SWITCH;
+ };
+
+ /^--recreate-configure$/ && do {
+ set_option('global', '#recreate-configure', 1);
+ last SWITCH;
+ };
+
+ /^--color$/ && do {
+ set_option('global', '#colorful-output', 1);
+ last SWITCH;
+ };
+
+ /^--no-color$/ && do {
+ set_option('global', '#colorful-output', 0);
+ last SWITCH;
+ };
+
+ /^--no-build$/ && do {
+ set_option('global', '#manual-build', 1);
+ last SWITCH;
+ };
+
+ # Although equivalent to --no-build at this point, someday the
+ # script may interpret the two differently, so get ready now.
+ /^--svn-only$/ && do { # Identically to --no-build
+ set_option('global', '#manual-build', 1);
+ last SWITCH;
+ };
+
+ # Don't run Subversion or install
+ /^--build-only$/ && do {
+ set_option('global', '#no-svn', 1);
+ set_option('global', '#install-after-build', 0);
+ last SWITCH;
+ };
+
+ /^--build-system-only$/ && do {
+ set_option('global', '#build-system-only', 1);
+ last SWITCH;
+ };
+
+ /^--rc-file=?/ && do {
+ my $rcfile = extract_option_value($_, @ARGV);
+ if (not $rcfile)
+ {
+ print "You must specify a filename to use as the config file!\n";
+ exit 8;
+ }
+
+ @rcfiles = ( $rcfile );
+
+ last SWITCH;
+ };
+
+ /^--prefix=?/ && do {
+ my $prefix = extract_option_value($_, @ARGV);
+ if (not $prefix)
+ {
+ print "No prefix selected with the --prefix option.\n";
+ exit 8;
+ }
+
+ set_option('global', '#kdedir', $prefix);
+ set_option('global', '#reconfigure', 1);
+
+ last SWITCH;
+ };
+
+ /^--no-rebuild-on-fail$/ && do {
+ set_option('global', '#no-rebuild-on-fail', 1);
+ last SWITCH;
+ };
+
+ /^--nice=?/ && do {
+ my $niceness = extract_option_value($_, @ARGV);
+
+ if($niceness)
+ {
+ set_option('global', '#niceness', $niceness);
+ }
+ else
+ {
+ print "You need to specify a value for the --nice option\n";
+ exit 8;
+ }
+
+ last SWITCH;
+ };
+
+ /^--ignore-modules$/ && do {
+ # We need to keep read_options() from adding these modules to
+ # the build list, taken care of by ignore_list. We then need
+ # to remove the modules from the command line, taken care of
+ # by the @ARGV = () statement;
+ my @options = ();
+ foreach (@ARGV)
+ {
+ if (/^-/)
+ {
+ push @options, $_;
+ }
+ else
+ {
+ $ignore_list{$_} = 1;
+
+ # the pattern match doesn't work with $_, alias it.
+ my $module = $_;
+ @argv = grep (!/^$module$/, @argv);
+ }
+ }
+ @ARGV = @options;
+
+ last SWITCH;
+ };
+
+ /^(--dry-run)|(--pretend)|(-p)$/ && do {
+ set_option('global', '#pretend', 1);
+ last SWITCH;
+ };
+
+ /^--refresh-build$/ && do {
+ set_option('global', '#refresh-build', 1);
+ last SWITCH;
+ };
+
+ /^(--revision|-r)=?/ && do {
+ my $revision = extract_option_value($_, @ARGV);
+ if (not $revision)
+ {
+ print "No revision selected with the --revision option.\n";
+ exit 8;
+ }
+
+ set_option('global', '#revision', $revision);
+
+ last SWITCH;
+ };
+
+ /^--resume-from=?/ && do {
+ $_ = extract_option_value($_, @ARGV);
+ if (not $_)
+ {
+ print "You must pass a module to resume from to the --resume-from option!\n";
+ exit 7;
+ }
+
+ if (defined $package_opts{'global'}{'#resume'})
+ {
+ print "WARNING: Don't pass both --resume and --resume-from\n";
+ delete $package_opts{'global'}{'#resume'};
+ }
+
+ set_option('global', '#resume-from', $_);
+ set_option('global', '#no-svn', 1);
+ last SWITCH;
+ };
+
+ /^--resume$/ && do {
+ if (defined $package_opts{'global'}{'#resume'})
+ {
+ print "WARNING: Don't pass both --resume and --resume-from\n";
+ delete $package_opts{'global'}{'#resume-from'};
+ }
+
+ set_option('global', '#resume', 1);
+ set_option('global', '#no-svn', 1);
+ last SWITCH;
+ };
+
+ /^--/ && do {
+ # First let's see if they're trying to override a global option.
+ my ($option) = /^--([-\w\d\/]+)/;
+ my $value = extract_option_value($_, @ARGV);
+
+ if (exists $package_opts{'global'}{$option})
+ {
+ # Global option
+ set_option('global', "#$option", $value);
+ }
+ else
+ {
+ # Module specific option. The module options haven't been
+ # read in, so we'll just have to assume that the module the
+ # user passes actually does exist.
+ my ($module, $option) = /^--([\w\/-]+),([-\w\d\/]+)/;
+
+ if (not $module)
+ {
+ print "Unknown option $_\n";
+ exit 8;
+ }
+
+ set_option($module, "#$option", $value);
+ }
+
+ last SWITCH;
+ };
+
+ /^-/ && do { print "WARNING: Unknown option $_\n"; last SWITCH; };
+
+ # Strip trailing slashes.
+ s/\/*$//;
+ push @argv, $_; # Reconstruct correct @ARGV
+ }
+ }
+
+ @ARGV = @argv;
+}
+
+# Subroutine to try to get a lock on the script's lockfile to prevent
+# more than one script from updating KDE Subversion at once.
+# The value returned depends on the system's open() call. Normally 0
+# is failure and non-zero is success (e.g. a file descriptor to read).
+# TODO: This could be improved to not fight over the lock when the scripts are
+# handling separate tasks.
+sub get_lock
+{
+ my $lockfile = "$ENV{HOME}/.kdesvn-lock";
+ sysopen LOCKFILE, $lockfile, O_WRONLY | O_CREAT | O_EXCL;
+ my $errorCode = $!; # Save for later testing.
+
+ # Install signal handlers to ensure that the lockfile gets closed.
+ # There is a race condition here, but at worst we have a stale lock
+ # file, so I'm not *too* concerned.
+ $SIG{'HUP'} = \&quit_handler;
+ $SIG{'INT'} = \&quit_handler;
+ $SIG{'QUIT'} = \&quit_handler;
+ $SIG{'ABRT'} = \&quit_handler;
+ $SIG{'TERM'} = \&quit_handler;
+ $SIG{'PIPE'} = \&quit_handler;
+
+ # Note that we can use color codes at this point since get_lock is called
+ # after read_options (which sets up the color).
+ if($errorCode == EEXIST)
+ {
+ # Path already exists, read the PID and see if it belongs to a
+ # running process.
+ open PIDFILE, "<$lockfile" or do
+ {
+ # Lockfile is there but we can't open it?!? Maybe a race
+ # condition but I have to give up somewhere.
+ warning " WARNING: Can't open or create lockfile r[$lockfile]";
+ return 1;
+ };
+
+ my $pid = <PIDFILE>;
+ close PIDFILE;
+
+ if($pid)
+ {
+ # Recent kdesvn-build; we wrote a PID in there.
+ chomp $pid;
+
+ # See if something's running with this PID.
+ if (kill(0, $pid) == 1)
+ {
+ # Something *is* running, likely kdesvn-build. Don't use error,
+ # it'll scan for $!
+ print clr " r[*y[*r[*] kdesvn-build appears to be running. Do you want to:\n";
+ print clr " (b[Q])uit, (b[P])roceed anyways?: ";
+
+ my $choice = <STDIN>;
+ chomp $choice;
+
+ if(lc $choice ne 'p')
+ {
+ print clr " y[*] kdesvn-build run canceled.\n";
+ exit 1;
+ }
+
+ # We still can't grab the lockfile, let's just hope things
+ # work out.
+ print clr " y[*] kdesvn-build run in progress by user request.\n";
+ return 1;
+ }
+
+ # If we get here, then the program isn't running (or at least not
+ # as the current user), so allow the flow of execution to fall
+ # through below and unlink the lockfile.
+ } # pid
+
+ # No pid found, optimistically assume the user isn't running
+ # twice.
+ warning " y[WARNING]: stale kdesvn-build lockfile found, deleting.";
+ unlink $lockfile;
+ sysopen LOCKFILE, $lockfile, O_WRONLY | O_CREAT | O_EXCL and do
+ {
+ print LOCKFILE "$$\n";
+ close LOCKFILE;
+ };
+ return 1; # Hope the sysopen worked.
+ }
+
+ print LOCKFILE "$$\n";
+ close LOCKFILE;
+
+ # Even if we fail it's generally better to allow the script to proceed
+ # without being a jerk about things, especially as more non-CLI-skilled
+ # users start using kdesvn-build to build KDE.
+ return 1;
+}
+
+# Subroutine to free the lock allocated by get_lock()
+sub close_lock
+{
+ my $lockfile = "$ENV{HOME}/.kdesvn-lock";
+
+ close LOCKFILE;
+ unlink $lockfile;
+}
+
+sub adjust_update_list
+{
+ my $list_ref = shift;
+ my $build_ref = shift;
+
+ # Check to see if the user has requested for one of the modules to be
+ # built is using unsermake. If so, we need to check if kdenonbeta is
+ # already supposed to be checked out. If so, we need to make sure that
+ # unsermake is present in any checkout-only directives, and if not, we need
+ # to add kdenonbeta/unsermake to the checkout list.
+ my $unsermake_needed = grep (get_option ($_, 'use-unsermake'), @{$build_ref});
+
+ # If the user has told us that they will manage unsermake then we don't
+ # need to do anything.
+ $unsermake_needed = 0 if get_option('global', 'use-unsermake') eq 'self';
+
+ # If the user has set manual-update, don't second-guess them.
+ $unsermake_needed = 0 if get_option('kdenonbeta', 'manual-update');
+
+ debug "Do we update unsermake? ", ($unsermake_needed ? 'yes' : 'no');
+
+ if ($unsermake_needed)
+ {
+ if (not list_has(@{$list_ref}, 'kdenonbeta'))
+ {
+ whisper "Adding kdenonbeta/unsermake to build.";
+
+ # kdenonbeta isn't being downloaded by the user.
+ unshift (@{$list_ref}, 'kdenonbeta');
+ $package_opts{'kdenonbeta'} = {
+ 'manual-build' => 'true',
+ 'checkout-only' => 'unsermake',
+ '#suppress-auto-admin' => 1,
+ };
+ }
+ else
+ {
+ my $checkouts = get_option('kdenonbeta', 'checkout-only');
+
+ if ($checkouts !~ /\bunsermake\b/)
+ {
+ # kdenonbeta is being checked out, but the user has
+ # excluded unsermake.
+ set_option('kdenonbeta', 'checkout-only', "$checkouts unsermake");
+ set_option('kdenonbeta', '#suppress-auto-admin', 1);
+ }
+ }
+ }
+}
+
+# Subroutine to get the list of Subversion modules to update. Returned
+# as a list. Parse the command-line arguments first.
+sub get_update_list
+{
+ return @ARGV unless $#ARGV == -1;
+
+ my @return_list;
+ for (@update_list)
+ {
+ push @return_list, $_ if not get_option($_, "manual-update");
+ }
+
+ return @return_list;
+}
+
+# Subroutine to get the list of Subversion modules to build. Returned
+# as a list. A module will not be built if manual-build is set
+# in the module's options. The command-line arguments should have been
+# parsed first.
+#
+# This subroutine will handle the --resume and --resume-from options.
+sub get_build_list
+{
+ my $resume_point;
+ my $autoresuming;
+
+ # We check explicity for sticky options here since they can only be
+ # set from the command line.
+ if (get_option('global', '#manual-build'))
+ {
+ if (get_option('global', '#resume') || get_option('global',
+ '#resume-from'))
+ {
+ warning "I'm confused, you enabled y[--no-build] and y[--resume].";
+ warning "Skipping the build process.";
+ }
+
+ return ();
+ }
+
+ if (get_option ('global', '#resume'))
+ {
+ if (scalar @ARGV > 0)
+ {
+ warning "Ignoring modules specified on command line because y[--resume] was set.";
+ }
+
+ # Try to determine location of last existing status file.
+ my $status_fname = get_output_file('existing');
+ if (not $status_fname)
+ {
+ error "Unable to open status file from last run, can't resume!";
+ return ();
+ }
+
+ my ($line, $oldline);
+ open STATUS_FILE, "<$status_fname" or do {
+ error "Can't open $status_fname, so I can't resume!";
+ return ();
+ };
+
+ while ($line = <STATUS_FILE>)
+ {
+ $oldline = $line;
+ }
+
+ close STATUS_FILE;
+
+ if (not defined $oldline)
+ {
+ # Hmm, empty file?
+ error <<"EOF";
+Unable to read information from resume status file.
+It's probably empty, but there's no way to resume!
+EOF
+ return ();
+ }
+
+ chomp $oldline;
+ debug "The last success line is $oldline";
+
+ ($resume_point = $oldline) =~ s/^([^:]+):.*/$1/;
+ whisper "Resuming at $resume_point";
+ }
+ elsif (get_option ('global', '#resume-from'))
+ {
+ $resume_point = get_option ('global', '#resume-from');
+ $autoresuming = 1;
+ }
+
+ if ($resume_point)
+ {
+ my $resume_found = 0;
+
+ # Pop stuff off of the list until we hit the resume point.
+ while (scalar @build_list > 0 and not $resume_found)
+ {
+ $resume_found = 1 if $build_list[0] eq $resume_point;
+
+ # If we're doing an auto resume, pop off the last package read
+ # from the file. If we're doing resume from on the other hand,
+ # I'm assuming the user intends to start with building that
+ # package.
+ shift @build_list unless $resume_found and $autoresuming;
+ }
+
+ return @build_list;
+ }
+
+ return @ARGV unless $#ARGV == -1;
+
+ my @list;
+ for (@build_list)
+ {
+ push @list, $_ unless get_option($_, 'manual-update');
+ }
+
+ return @list;
+}
+
+# Used to sort module names. 'global' always starts first, modules with /
+# sort last.
+sub module_sort
+{
+ # This is always true.
+ return 0 if $a eq $b;
+
+ # Look for global modules.
+ return -1 if $a eq 'global';
+ return 1 if $b eq 'global';
+
+ # If both have /, use a normal sort.
+ return $a cmp $b if $a =~ /\// and $b =~ /\//;
+
+ # If left has slash, it's < $b (and vice versa)
+ return 1 if $a =~ /\//;
+ return -1 if $b =~ /\//;
+
+ # Normal sort.
+ return $a cmp $b;
+}
+
+# Helper subroutine for debugging purposes. Dumps all of the
+# options which have been read in to %global_opts and %package_opts.
+sub dump_options
+{
+ my ($item, $ref_item, $ref);
+ my @keys = sort module_sort keys %package_opts;
+ my $c; # $c is a color variable to be used with clr()
+
+ # Now dump the options for each module
+ foreach $item (@keys)
+ {
+ debug "\nOptions for module g[$item]:";
+ my $ref = $package_opts{$item};
+
+ foreach $ref_item (sort keys %{$package_opts{$item}})
+ {
+ # Put the first bracket in here, otherwise it breaks on some
+ # Perl systems.
+ $c = $ref_item =~ /^#/ ? 'r[' : 'g[';
+
+ if($ref_item !~ /^#?set-env$/)
+ {
+ next unless defined $$ref{$ref_item};
+ debug " ${c}$ref_item] is \"y[", $$ref{$ref_item}, clr ']"';
+ }
+ else
+ {
+ # Dump the environment variables that will be set.
+ my $setref = $$ref{$ref_item};
+
+ foreach my $envitem (keys %{$setref})
+ {
+ debug " Set env variable ${c}$envitem] to y[", $$setref{$envitem};
+ }
+ }
+ }
+ }
+}
+
+# Subroutine to unlink the given symlink if global-pretend isn't set.
+sub safe_unlink
+{
+ if (pretending)
+ {
+ pretend "\tWould have unlinked ", shift, ".";
+ return 1; # Return true
+ }
+
+ return unlink (shift);
+}
+
+# Subroutine to execute the system call on the given list if the pretend
+# global option is not set.
+sub safe_system(@)
+{
+ if (not pretending)
+ {
+ info "\tExecuting g[", join(" ", @_);
+ return system (@_) >> 8;
+ }
+
+ pretend "\tWould have run g[", join(' ', @_);
+ return 0; # Return true
+}
+
+# Helper subroutine to create a directory, including any parent
+# directories that may also need created.
+# Returns 0 on failure, non-zero on success
+sub super_mkdir
+{
+ my $pathname = shift;
+ my $temp;
+ my @parts = split (/\//, $pathname);
+
+ if (pretending)
+ {
+ pretend "\tWould have created g[$pathname]";
+ return 1;
+ }
+
+ foreach (@parts)
+ {
+ $temp .= "$_/";
+
+ next if -e $temp;
+ return 0 if not mkdir ($temp);
+ }
+
+ return 1;
+}
+
+# Subroutine to remove a package from the package build list. This
+# is for use when you've detected an error that should keep the
+# package from building, but you don't want to abort completely.
+sub dont_build
+{
+ my $module = shift;
+
+ whisper "Not building $module";
+
+ # Weed out matches of the module name
+ @build_list = grep (!/^$module$/, @build_list);
+
+ push @{$fail_lists{'update'}}, $module;
+}
+
+# Subroutine to split a url into a protocol and host
+sub split_url
+{
+ my $url = shift;
+ my ($proto, $host) = ($url =~ m|([^:]*)://([^/]*)/|);
+
+ return ($proto, $host);
+}
+
+# This subroutine checks if we are supposed to use ssh agent by examining the
+# environment, and if so checks if ssh-agent has a list of identities. If it
+# doesn't, we run ssh-add (with no arguments) and inform the user. This can
+# be controlled with the disable-agent-check parameter.
+sub check_for_ssh_agent
+{
+ my $agent_running = 0;
+ my $server = get_option('global', 'svn-server');
+ my ($proto, $host) = split_url($server);
+
+ # Don't bother with all this if the user isn't even using SSH.
+ return 1 if($proto !~ /ssh/) or get_option('global', 'disable-agent-check');
+
+ # We're using ssh to download, see if ssh-agent is running.
+ return 1 unless exists $ENV{'SSH_AGENT_PID'};
+
+ my $pid = $ENV{'SSH_AGENT_PID'};
+
+ # It's supposed to be running, let's see if there exists the program with
+ # that pid.
+ # PORTABILITY NOTE: I'm not sure if this works under *BSD or Solaris.
+ if (not -e "/proc/$pid")
+ {
+ warning "r[ *] SSH Agent is enabled, but y[doesn't seem to be running].";
+ warning "Since SSH is used to download from Subversion you may want to see why";
+ warning "SSH Agent is not working, or correct the environment variable settings.";
+
+ return 0;
+ }
+
+ # The agent is running, but does it have any keys? We can't be more specific
+ # with this check because we don't know what key is required.
+ my $keys = `ssh-add -l 2>/dev/null`;
+ if ($keys =~ /no identities/)
+ {
+ # Use print so user can't inadvertently keep us quiet about this.
+ print clr <<EOF;
+b[y[*] SSH Agent does not appear to be managing any keys. This will lead to you
+ being prompted for every module update for your SSH passphrase. So, we're
+ running g[ssh-add] for you. Please type your passphrase at the prompt when
+ requested, (or simply Ctrl-C to abort the script).
+EOF
+ my $result = system('ssh-add');
+ if ($result) # Run this code for both death-by-signal and nonzero return
+ {
+ print "\nUnable to add SSH identity, aborting.\n";
+ print "If you don't want kdesvn-build to check in the future,\n";
+ print clr "Set the g[disable-agent-check] option to g[true] in your $rcfile.\n\n";
+
+ return 0;
+ }
+ }
+
+ return 1;
+}
+
+# Subroutine to update a list of Subversion modules. The first
+# parameter is a reference of a list of the modules to update.
+# If the module has not already been checkout out, this subroutine
+# will do so for you.
+#
+# Returns 0 on success, non-zero on error.
+sub handle_updates
+{
+ my $update_ref = shift;
+ my $kdesvn = get_kdesvn_dir();
+ my $svnroot = get_option ('global', 'svn-server');
+ my $result = 0;
+ my $module;
+
+ # No reason to print out the text if we're not doing anything.
+ return 0 if get_option ('global', 'no-svn');
+ return 0 if scalar @$update_ref == 0;
+
+ return 1 if (not check_for_ssh_agent());
+
+ note "<<< Updating Subversion Directories >>>";
+ info " "; # Add newline for aesthetics unless in quiet mode.
+
+ if (not -e $kdesvn)
+ {
+ whisper "KDE Subversion download directory doesn't exist, creating.\n";
+ if (not super_mkdir ($kdesvn))
+ {
+ error "Unable to make directory r[$kdesvn]!";
+ @build_list = (); # Clear out the build list, since we can't build.
+ $install_flag = 0; # Can't install either.
+ return 1;
+ }
+ }
+
+ foreach $module (@{$update_ref})
+ {
+ my $fullpath = get_fullpath($module, 'source');
+
+ if (not exists $package_opts{$module})
+ {
+ warning "Unknown module y[$module], configure it in $rcfile.";
+
+ # Continue in case the user just needs default options, hopefully
+ # it isn't a misspelling.
+ $package_opts{$module} = { 'set-env' => { } };
+ }
+
+ next if get_option($module, 'no-svn');
+
+ my @options = split(' ', get_option($module, 'checkout-only'));
+ if (-e "$fullpath/.svn")
+ {
+ # Warn user if the current repo URL is different than expected.
+ check_module_validity($module);
+ $result = update_module_path($module, @options);
+ }
+ else
+ {
+ $result = checkout_module_path($module, @options);
+ }
+
+ if ($result)
+ {
+ error "Error updating r[$module], removing from list of packages to build.";
+ dont_build ($module);
+ }
+
+ print "\n";
+ }
+
+ info "<<< Update Complete >>>\n";
+ return $result;
+}
+
+# Subroutine to run the qt-copy apply_patches script.
+# Returns 0 on success, non-zero on failure.
+sub safe_apply_patches
+{
+ my %pathinfo = get_module_path_dir('qt-copy', 'build');
+ my $builddir = "$pathinfo{fullpath}";
+
+ if (pretending)
+ {
+ pretend "\tWould have run g[./apply_patches]";
+ return 0;
+ }
+
+ info "\tg[Applying recommended Qt patches].";
+ chdir ("$builddir");
+ return (log_command('qt-copy', 'apply-patches', [ "./apply_patches" ]));
+}
+
+# Subroutine to run and log the configure command. First parameter is the
+# path to the configure script to run, the second parameter is a scalar
+# containing all of the configure flags to apply
+sub safe_configure
+{
+ my $module = shift;
+ my $fullpath = get_fullpath($module, 'source');
+ my $script = "$fullpath/configure";
+
+ my @commands = split (/\s+/, get_option($module, 'configure-flags'));
+
+ # Get the user's CXXFLAGS
+ my $cxxflags = get_option ($module, 'cxxflags');
+ setenv ('CXXFLAGS', $cxxflags);
+ setenv ('DO_NOT_COMPILE', get_option ($module, 'do-not-compile'));
+
+ if ($module ne 'qt-copy')
+ {
+ my $kdedir = get_option ('global', 'kdedir');
+ my $prefix = get_option ($module, 'prefix');
+
+ $prefix = $kdedir unless $prefix;
+
+ push @commands, "CXXFLAGS=$cxxflags" if $cxxflags;
+ push @commands, "--prefix=$prefix";
+
+ # We're special casing these modules because we're using the lndir
+ # hack for them.
+ if (module_needs_builddir_help($module))
+ {
+ $script = get_fullpath($module, 'build') . "/configure";
+ }
+ }
+ else
+ {
+ my $qtdir = get_fullpath('qt-copy', 'build');
+
+ if(not pretending)
+ {
+ # Copy the configure script to accept the GPL license.
+ open CONFIG, "<$script";
+ open NEWCONFIG, ">$qtdir/configure.new";
+ while(<CONFIG>)
+ {
+ s/read acceptance/acceptance=yes/;
+ print NEWCONFIG $_;
+ }
+ close NEWCONFIG;
+ close CONFIG;
+ chmod 0755, "$qtdir/configure.new";
+ }
+
+ $script = "$qtdir/configure.new";
+
+ note "\tb[r[GPL license selected for Qt]. See $fullpath/LICENSE.GPL";
+ }
+
+ info "\tRunning g[configure]...";
+ unshift @commands, $script;
+
+ return log_command($module, "configure", \@commands);
+}
+
+# Subroutine to try and see if we've already tried to update kde-common
+sub has_updated_kdecommon
+{
+ # Test fast case first.
+ return 1 if get_option('global', '#has-checked-for-admin');
+
+ # Double check that it wasn't in the update list.
+ if (grep(/^(KDE\/)?kde-common$/, @update_list))
+ {
+ set_option('global', '#has-checked-for-admin', 1);
+ return 1;
+ }
+
+ return 0;
+}
+
+# Subroutine to automatically create an admir dir for a module if it doesn't
+# have one. The first parameter is the module name. It is assumed that we
+# are already in the source directory, the current directory will not be
+# changed.
+#
+# Returns boolean true on success, boolean false on failure.
+#
+# NOTE: This subroutine might try to call an svn update, as long as #no-svn
+# isn't set.
+sub create_admin_dir
+{
+ my $module = shift;
+ my $fullpath = get_fullpath($module, 'source');
+
+ # Don't bother if it's qt-copy, or if we've already got an admin
+ # directory.
+ return 1 if $module eq 'qt-copy';
+ return 1 if -e "$fullpath/admin";
+
+ # Find kde-common
+ my $admindir = get_fullpath('kde-common', 'source') . '/admin';
+ if (not -e $admindir)
+ {
+ $admindir = get_fullpath('KDE/kde-common', 'source') . '/admin';
+ }
+
+ if (not -e $admindir)
+ {
+ # Can't find kde-common, it's apparently not installed.
+ if (not has_updated_kdecommon())
+ {
+ # We haven't tried downloading it, now would be a good time.
+ note "Can't find y[kde-common], going to try downloading it.";
+
+ if (get_option('global', 'no-svn'))
+ {
+ # Not allowed to update.
+ error "r[!!] Updating has been blocked, can't get y[kde-common].";
+ return 0;
+ }
+
+ # Checkout the directory.
+ $admindir = get_fullpath('kde-common', 'source') . '/admin';
+ if (pretending)
+ {
+ pretend "Would have checked out g[kde-common]\n";
+ }
+ elsif (checkout_module_path('kde-common', 'admin') != 0)
+ {
+ return 0;
+ }
+ }
+ }
+
+ chdir ($fullpath);
+
+ whisper "\tCreating symbolic link to g[/admin directory].";
+
+ return symlink $admindir, "$fullpath/admin";
+}
+
+# Subroutine to recursively symlink a directory into another location, in a
+# similar fashion to how the XFree/X.org lndir() program does it. This is
+# reimplemented here since some systems lndir doesn't seem to work right.
+#
+# As a special exception to the GNU GPL, you may use and redistribute this
+# function however you would like (i.e. consider it public domain).
+#
+# The first parameter is the directory to symlink from.
+# The second parameter is the destination directory name.
+#
+# e.g. if you have $from/foo and $from/bar, lndir would create $to/foo and
+# $to/bar.
+#
+# All intervening directories will be created as needed. In addition, you
+# may safely run this function again if you only want to catch additional files
+# in the source directory.
+#
+# Note that this function will unconditionally output the files/directories
+# created, as it is meant to be a close match to lndir.
+#
+# RETURN VALUE: Boolean true (non-zero) if successful, Boolean false (0, "")
+# if unsuccessful.
+sub safe_lndir
+{
+ my ($from, $to) = @_;
+
+ # Create destination directory.
+ if (not -e $to)
+ {
+ print "$to\n";
+ mkdir ($to) unless pretending;
+ }
+
+ # Create closure callback subroutine.
+ my $wanted = sub {
+ my $dir = $File::Find::dir;
+ my $file = $File::Find::fullname;
+ $dir =~ s/$from/$to/;
+
+ # Ignore the .svn directory and files.
+ return if $dir =~ m,/\.svn,;
+
+ # Create the directory.
+ if (not -e $dir)
+ {
+ print "$dir\n";
+
+ if (not pretending)
+ {
+ mkdir ($dir) or die "Couldn't create directory $dir: $!";
+ }
+ }
+
+ # Symlink the file. Check if it's a regular file because File::Find
+ # has no qualms about telling you you have a file called "foo/bar"
+ # before pointing out that it was really a directory.
+ if (-f $file and not -e "$dir/$_")
+ {
+ print "$dir/$_\n";
+
+ if (not pretending)
+ {
+ symlink $File::Find::fullname, "$dir/$_" or
+ die "Couldn't create file $dir/$_: $!";
+ }
+ }
+ };
+
+ # Recursively descend from source dir using File::Find
+ eval {
+ find ({ 'wanted' => $wanted,
+ 'follow_fast' => 1,
+ 'follow_skip' => 2},
+ $from);
+ };
+
+ if ($@)
+ {
+ $! = 0; # sub error will use $! to display error message.
+ error "Unable to symlink $from to $to: $@";
+ return 0;
+ }
+
+ return 1;
+}
+
+# Subroutine to link a source directory into an alternate directory in order
+# to fake srcdir != builddir for modules that don't natively support it.
+# The first parameter is the module to prepare.
+#
+# The return value is true (non-zero) if it succeeded, and 0 (false) if it
+# failed.
+#
+# On return from the subroutine the current directory will be in the build
+# directory, since that's the only directory you should touch from then on.
+#
+# You may safely call this subroutine for modules that don't need it, they
+# will automatically be ignored.
+sub prepare_fake_builddir
+{
+ my $module = shift;
+ my $builddir = get_fullpath($module, 'build');
+ my $srcdir = get_fullpath($module, 'source');
+
+ # List reference, not a real list. The initial kdesvn-build does *NOT*
+ # fork another kdesvn-build using exec, see sub log_command() for more
+ # info.
+ my $args = [ 'kdesvn-build', 'safe_lndir', $srcdir, $builddir ];
+
+ # Skip modules that don't need special treatment.
+ return 1 unless module_needs_builddir_help($module);
+
+ # Backwards compatibility hack.
+ # kdesvn-build 0.97 and earlier would physically copy the Qt source
+ # directory to the build directory. kdesvn-build versions after that use
+ # the lndir program that is used for kdebindings and valgrind for
+ # portability reasons. This will break for users who have a real copy of
+ # Qt, so check here if the qt-copy configure script file is a real file
+ # (not a symlink), and if so, use the old method (since presumably it
+ # worked earlier).
+ if ($module eq 'qt-copy' and -e "$builddir/configure" and not -l "$builddir/configure")
+ {
+ whisper "Using deprecated qt-copy builddir faking method.";
+
+ # Use old method of copying.
+ $args = [ 'cp', '-af', $srcdir, $builddir ];
+ }
+
+ # Use an internal routine to complete the directory symlinking (or the
+ # alternate routine in the case of old qt-copy).
+ if (log_command ($module, 'create-builddir', $args))
+ {
+ warning "\tUnable to setup special build system for r[$module].";
+ return 0;
+ }
+
+ return 1; # Success
+}
+
+# Subroutine to create the build system for a module. This involves making
+# sure the directory exists and then running make -f Makefile.cvs. This
+# subroutine assumes that the module is already downloaded.
+sub safe_create_build_system
+{
+ my $module = shift;
+ my $fullpath = get_fullpath($module, 'source');
+ my $builddir = get_fullpath($module, 'build');
+ my $instapps = get_option($module, 'inst-apps');
+
+ if (pretending)
+ {
+ pretend "\tWould have created g[$module]\'s build system.";
+ return 0;
+ }
+
+ chdir ($fullpath); # Run make -f Makefile.cvs in srcdir.
+
+ # These modules will run make -f Makefile.cvs in (fake) builddir to keep
+ # srcdir clean. Except for qt-copy when not using qt-builddir-hack.
+ if(module_needs_builddir_help($module))
+ {
+ chdir ($builddir);
+ }
+
+ return 0 if $module eq 'qt-copy'; # since 3.3.6
+
+ if ($instapps)
+ {
+ open (INSTAPPS, ">inst-apps") or do {
+ error "\tUnable to create inst-apps file for r[$module]!";
+ return 1;
+ };
+
+ print INSTAPPS "$instapps\n";
+ close INSTAPPS;
+ }
+ else
+ {
+ unlink ("$fullpath/inst-apps");
+ }
+
+ my $cmd_ref = [ 'make', '-f', 'Makefile.cvs' ];
+ $cmd_ref = [ './autogen.sh' ] if $module eq 'valgrind';
+
+ if (log_command ($module, "build-system", $cmd_ref))
+ {
+ error "\tUnable to create build system for r[$module]";
+ return 1;
+ }
+
+ return 0;
+}
+
+# Subroutine to determine if a given module needs to have the build system
+# recreated from scratch.
+# If so, it returns boolean true.
+sub needs_refreshed
+{
+ my $module = shift;
+ my $builddir = get_fullpath($module, 'build');
+ my $conf_file_key = "Makefile"; # File that exists after configure is run
+
+ # Use a different file to indicate configure has been run for qt-copy
+ $conf_file_key = "src/tools/qconfig.cpp" if $module eq 'qt-copy';
+
+ if (debugging)
+ {
+ debug "Build directory not setup for $module." if not -e "$builddir";
+ debug ".refresh-me exists for $module." if -e "$builddir/.refresh-me";
+ debug "refresh-build option set for $module." if get_option($module, 'refresh-build');
+ debug "Can't find configure key file for $module." if not -e "$builddir/$conf_file_key";
+ }
+
+ return 1 if ((not -e "$builddir") ||
+ (-e "$builddir/.refresh-me") ||
+ get_option($module, "refresh-build") ||
+ (not -e "$builddir/$conf_file_key"));
+
+ return 0;
+}
+
+# Run the svn command. This is a special subroutine so that we can munge the
+# generated output to see what files have been added, and adjust the build
+# according.
+# First parameter is the module we're building.
+# Second parameter is the filename to use for the log file.
+# Third parameter is a reference to a list, which is the command ('svn') and all
+# of its arguments.
+sub run_svn
+{
+ my ($module, $logfilename, $arg_ref) = @_;
+ my %hash_count;
+ my $result;
+ my $force_refresh = 0;
+ my $conflict = 0;
+ my $logdir = get_log_dir($module);
+
+ my $revision = get_option('global', 'revision');
+ if ($revision ne '0')
+ {
+ my @tmp = @{$arg_ref};
+
+ # Insert after first two entries, deleting 0 entries from the
+ # list.
+ splice @tmp, 2, 0, '-r', $revision;
+ $arg_ref = \@tmp;
+ }
+
+ # Do svn update.
+ $result = log_command($module, $logfilename, $arg_ref);
+
+ # There will be no result if we're pretending, so don't even
+ # bother.
+ return 0 if pretending;
+
+ $logfilename = "$logdir/$logfilename.log";
+
+ # We need to open the file and try to determine what the Subversion process
+ # did.
+ open SVN_LOG, "<$logfilename";
+ while (<SVN_LOG>)
+ {
+ # The check for capitalized letters in the second column is because
+ # svn can use the first six columns for updates (the characters will
+ # all be uppercase), which makes it hard to tell apart from normal
+ # sentences (like "At Revision foo"
+
+ # Count updates and patches together.
+ $hash_count{'updated'}++ if /^U[ A-Z]/;
+ $hash_count{'updated'}++ if /^P[ A-Z]/;
+ $hash_count{'deleted'}++ if /^D[ A-Z]/;
+ $hash_count{'added'}++ if /^A[ A-Z]/;
+ $hash_count{'removed'}++ if /^R[ A-Z]/;
+ $hash_count{'merged'}++ if /^G[ A-Z]/;
+ $hash_count{'modified'}++ if /^M[ A-Z]/;
+ $hash_count{'conflicted'}++ if /^C[ A-Z]/;
+
+ # Check if we need to force a refresh.
+ $force_refresh = 1 if /^A[ A-Z]/ and /Makefile\.am/;
+ $force_refresh = 1 if /^[PAMGU][ A-Z]/ and /configure\.in\.in/;
+
+ $conflict = 1 if /^C[ A-Z]/;
+ }
+
+ close SVN_LOG;
+
+ my %endings = (
+ 'updated' => 'files were updated',
+ '1updated' => 'file was updated',
+ 'added' => 'files were added',
+ '1added' => 'file was added',
+ 'removed' => 'files were removed',
+ '1removed' => 'file was removed',
+ 'modified' => 'files were modified',
+ '1modified' => 'file was modified',
+ 'conflicted' => 'files had conflicts',
+ '1conflicted' => 'file had conflicts',
+ 'deleted' => 'files were deleted',
+ '1deleted' => 'file was deleted',
+ 'merged' => 'files had changes merged',
+ '1merged' => 'file had changes merged',
+ );
+
+ my ($key, $value);
+ while (($key, $value) = each %hash_count)
+ {
+ next unless $value > 0;
+ my $ending_key = $value > 1 ? $key : ('1' . $key);
+ my $ending = $endings{$ending_key};
+ info "\t$value $ending.";
+ }
+
+ if ($conflict)
+ {
+ warning "Source code conflict exists in r[$module], this module will not";
+ warning "build until it is resolved.";
+ dont_build($module);
+
+ return $result;
+ }
+
+ if ($force_refresh and -e get_fullpath($module, 'build'))
+ {
+ info "File(s) related to the build system were updated, forcing a refresh.";
+ set_option($module, 'refresh-build', 1);
+ set_option($module, '#cancel-clean', 1);
+ }
+
+ return $result;
+}
+
+# Subroutine to clean the build system for the given module. Works by
+# recursively deleting the directory and then recreating it. Returns
+# 0 for failure, non-zero for success.
+sub clean_build_system
+{
+ my $module = shift;
+ my $moduledir = get_fullpath($module, 'source');
+ my $builddir = get_fullpath($module, 'build');
+
+ if (pretending)
+ {
+ pretend "\tWould have cleaned build system for g[$module]";
+ return 1;
+ }
+
+ if (not -e $moduledir)
+ {
+ warning "\tUnable to clean build system for r[$module], it's not been checked out!";
+ return 0;
+ }
+
+ # Clean qt-copy separately
+ if ($module eq 'qt-copy' and not get_option('qt-copy', 'use-qt-builddir-hack'))
+ {
+ chdir ("$builddir");
+
+ if (log_command ('qt-copy', 'clean', ['make', 'clean']))
+ {
+ warning "\tr[WARNING]: Error cleaning r[qt-copy].";
+ }
+
+ unlink ("$builddir/.qmake.cache");
+
+ return 1;
+ }
+
+ if (-e "$builddir")
+ {
+ if(safe_system ('rm', '-rf', "$builddir"))
+ {
+ # Remove build directory for normal module.
+ error "\tUnable to clean r[$builddir].";
+ return 0; # False for this function.
+ }
+
+ # Let users know we're done so they don't wonder why rm -rf is taking so
+ # long and oh yeah, why'd my HD so active?...
+ info "\tOld build system cleaned, starting new build system.";
+ }
+
+ # Now create the directory
+ if (not super_mkdir ("$builddir"))
+ {
+ error "\tUnable to create directory r[$builddir].";
+ return 0;
+ }
+
+ return 1;
+}
+
+# Subroutine to setup the build system in a directory. The first parameter
+# is the module name. Returns boolean true on success, boolean false (0)
+# on failure.
+sub setup_build_system
+{
+ my $module = shift;
+ my $fullpath = get_fullpath($module, 'source');
+ my $builddir = get_fullpath($module, 'build');
+ my $do_configure = get_option ($module, 'reconfigure');
+ my $do_makeconf = get_option ($module, 'recreate-configure');
+
+ if (needs_refreshed($module))
+ {
+ # The build system needs created, either because it doesn't exist, or
+ # because the user has asked that it be completely rebuilt.
+ info "\tPreparing build system for y[$module].";
+
+ # Define this option to tell later functions that we tried to rebuild
+ # this module.
+ set_option($module, '#was-rebuilt', 1);
+
+ # Check to see if we're actually supposed to go through the cleaning
+ # process.
+ if (not get_option($module, '#cancel-clean') and
+ not clean_build_system($module))
+ {
+ warning "\tUnable to clean r[$module]!";
+ return 0;
+ }
+
+ $do_makeconf = 1;
+ }
+
+ # Symlink source directory to build directory if module doesn't support
+ # srcdir != builddir. If it's qt-copy only do so if use-qt-builddir-hack
+ # is on (true by default). Note that module_needs_builddir_help() already
+ # takes care of that test.
+ if (module_needs_builddir_help($module))
+ {
+ whisper "\tFaking builddir for g[$module]";
+ if (not prepare_fake_builddir($module))
+ {
+ error "Error creating r[$module] build system!";
+ return 0;
+ }
+ }
+
+ # Check for admin dir, if it doesn't exist, create a softlink
+ if (not create_admin_dir($module))
+ {
+ warning "Unable to find /admin directory for y[$module], it probably";
+ warning "won't build.";
+ # But continue anyways, because in this case I'm just not sure that it
+ # won't work in the future. ;)
+ }
+
+ my $confpath = module_needs_builddir_help($module) ? $builddir : $fullpath;
+
+ if ($do_makeconf or not -e "$confpath/configure")
+ {
+ whisper "\ty[Recreating configure script].";
+
+ # Update the PATH and other important environment variables.
+ update_module_environment ($module);
+
+ if (safe_create_build_system ($module))
+ {
+ error "\tUnable to create configure system from checkout.";
+ return 0;
+ }
+
+ $do_configure = 1;
+
+ if ($module eq "qt-copy" and get_option($module, 'apply-qt-patches'))
+ {
+ # Run apply-patches script
+ return 0 if safe_apply_patches ();
+ }
+
+ # Check to see if we're supposed to stop here
+ return 1 if get_option ($module, 'build-system-only');
+ }
+
+ # File which exists after configure has been run.
+ my $conf_key_file = "$builddir/Makefile";
+ $conf_key_file = "$builddir/src/tools/qconfig.cpp" if $module eq 'qt-copy';
+
+ if ($do_configure or not -e $conf_key_file)
+ {
+ if (not -e "$builddir" and not super_mkdir("$builddir"))
+ {
+ error "\tUnable to create build directory for r[$module]!!";
+ return 0;
+ }
+
+ # Now we're in the checkout directory
+ # So, switch to the build dir.
+ # builddir is automatically set to the right value for qt-copy
+ chdir ("$builddir");
+
+ # configure the module (sh script return value semantics)
+ if (safe_configure ($module))
+ {
+ error "\tUnable to configure r[$module]!";
+ return 0;
+ }
+ }
+
+ return 1;
+}
+
+# Subroutine to setup the environment for a module. First parameter is the name of
+# the module to set the environment for
+sub update_module_environment
+{
+ my $module = shift;
+ my $kdedir = get_option ($module, 'kdedir');
+ my $qtdir = get_option ($module, 'qtdir');
+ my $path = join(':', "$qtdir/bin", "$kdedir/bin", get_option ($module, 'binpath'));
+ my $libdir = join(':', "$qtdir/lib", "$kdedir/lib", get_option ($module, 'libpath'));
+
+ # Set up the children's environment. We use setenv since it
+ # won't set an environment variable to nothing. (e.g, setting
+ # QTDIR to a blank string might confuse Qt or KDE.
+
+ # Remove leading and trailing colons, just in case.
+ # Also remove more than one colon.
+ for ($path, $libdir)
+ {
+ s/:+/:/;
+ s/^:*//;
+ s/:*$//;
+ }
+
+ # Everyone loves unsermake. It's a pity that not every module will compile with it.
+ # Benjamin Meyer has an excellent article about speeding up distributed builds using
+ # unsermake. You should notice a much faster build using distcc, and
+ # a slightly faster build even with only one CPU.
+ if (get_option ($module, "use-unsermake"))
+ {
+ my $kdenonbeta = get_fullpath('kdenonbeta', 'source');
+ $path = "$kdenonbeta/unsermake:$path";
+ }
+ else
+ {
+ setenv ("UNSERMAKE", "no");
+ }
+
+ setenv ('LD_LIBRARY_PATH', $libdir);
+ setenv ('PATH', $path);
+ setenv ('KDEDIR', $kdedir);
+ setenv ('QTDIR', $qtdir);
+
+ # Qt has several defines of its own. Special case qt-copy for this
+ # reason.
+ setenv ("YACC", 'byacc -d') if ($module eq "qt-copy");
+
+ # Read in user environment defines
+ setup_module_environment ($module);
+}
+
+# Subroutine to make sure the build directory for a module is setup.
+# The module to setup is the first parameter.
+#
+# Returns boolean true on success, boolean false on failure.
+sub setup_build_directory
+{
+ my $module = shift;
+ my $builddir = get_build_dir($module);
+
+ if (not -e "$builddir")
+ {
+ whisper "\ty[$builddir] doesn't exist, creating.";
+ if (not super_mkdir ("$builddir"))
+ {
+ error "\tUnable to create r[$builddir]!";
+ return 0;
+ }
+ }
+
+ return 1;
+}
+
+# Subroutine to return a string suitable for displaying an elapsed time, (like
+# a stopwatch) would. The first parameter is the number of seconds elapsed.
+sub prettify_seconds
+{
+ my $elapsed = $_[0];
+ my $str = "";
+ my ($days,$hours,$minutes,$seconds,$fraction);
+
+ $fraction = int (100 * ($elapsed - int $elapsed));
+ $elapsed = int $elapsed;
+
+ $seconds = $elapsed % 60;
+ $elapsed = int $elapsed / 60;
+
+ $minutes = $elapsed % 60;
+ $elapsed = int $elapsed / 60;
+
+ $hours = $elapsed % 24;
+ $elapsed = int $elapsed / 24;
+
+ $days = $elapsed;
+
+ $seconds = "$seconds.$fraction" if $fraction;
+
+ my @str_list;
+
+ for (qw(days hours minutes seconds))
+ {
+ # Use a symbolic reference without needing to disable strict refs.
+ # I couldn't disable it even if I wanted to because these variables
+ # aren't global or localized global variables.
+ my $value = eval "return \$$_;";
+ my $text = $_;
+ $text =~ s/s$// if $value == 1; # Make singular
+
+ push @str_list, "$value $text" if $value or $_ eq 'seconds';
+ }
+
+ # Add 'and ' in front of last element if there was more than one.
+ push @str_list, ("and " . pop @str_list) if (scalar @str_list > 1);
+
+ $str = join (", ", @str_list);
+
+ return $str;
+}
+
+# Subroutine to determine if a given module can run make apidox. Returns
+# boolean true if make apidox can be run.
+sub make_apidox_supported
+{
+ my $module = shift;
+
+ return $module =~ /^(KDE\/)?(kde(base|games|graphics|libs|pim|velop)|koffice)$/;
+}
+
+# Subroutine to build a given module. The module to build is the first
+# parameter. The second and third paramaters is the ordinal number of the
+# module being built (1 == first module, 2 == second, etc.), and the total
+# number of modules being built respectively.
+#
+# Returns boolean false on failure, boolean true on success.
+sub build_module
+{
+ my $module = shift;
+ my $cur_module_num = shift;
+ my $total_module_num = shift;
+ my $apidox = shift;
+ my $builddir = get_fullpath($module, 'build');
+ my $trynumber = 1;
+
+ # Do some tests to make sure we're ready to build.
+ if (not exists $package_opts{$module})
+ {
+ warning "Unknown module y[$module], configure it in $rcfile.";
+ $package_opts{$module} = { 'set-env' => { } };
+ }
+
+ update_module_environment($module);
+
+ if($module eq 'qt-copy' and $builddir ne get_option('global', 'qtdir'))
+ {
+ my $qtpath = $builddir;
+ $qtpath =~ s/$ENV{HOME}/~/;
+ warning <<EOF;
+
+b[y[!!] You're building qt-copy, but QTDIR isn't set to use qt-copy!
+b[y[!!] Please set your qtdir variable in the global section of your
+b[y[!!] $rcfile to g[$qtpath]
+
+EOF
+ }
+
+ my $start_time = time;
+ while (not defined $package_opts{$module}->{'#was-rebuilt'})
+ {
+ note "Building g[$module] ($cur_module_num/$total_module_num)";
+ return 0 if not setup_build_directory($module);
+ return 0 if not setup_build_system($module);
+ return 1 if (get_option ($module, 'build-system-only'));
+
+ if (safe_make ($module, $trynumber))
+ {
+ # Build failed
+ # There are several reasons why the build could fail. If we're
+ # using unsermake for this module, then perhaps we just need to
+ # run make again. After that, we can re-run make -f Makefile.cvs
+ # and etc and then try make again. If that STILL doesn't work, we
+ # can try rm -rf $builddir/$module and rebuild.
+
+ my $elapsed = prettify_seconds (time - $start_time);
+ my $was_rebuilt = defined $package_opts{$module}{'#was-rebuilt'};
+ $start_time = time;
+
+ ++$trynumber;
+
+ if ($trynumber > 3 or $was_rebuilt or get_option ($module, 'no-rebuild-on-fail'))
+ {
+ # Well we tried, but it isn't going to happen.
+ note "\n\tUnable to build y[$module]!";
+ info "\tTook g[$elapsed].";
+ return 0;
+ }
+
+ if ($trynumber == 2)
+ {
+ # Just try again
+ info "\n\ty[Couldn't build, going to try again just in case].";
+ info "\tTook g[$elapsed].";
+ next;
+ }
+
+ # Don't remove the old modules, but re-run make -f
+ # Makefile.cvs and configure.
+ info "\n\tStill couldn't build, recreating build system (builddir is safe).";
+ info "\tTook g[$elapsed] of time.";
+
+ set_option($module, '#cancel-clean', 1);
+ set_option($module, 'refresh-build', 1);
+
+ # Loop again
+ }
+ else
+ {
+ # Build succeeded, build docs if necessary
+ my $apidox_result = 0;
+ my $build_apidox = make_apidox_supported($module) && get_option($module, 'apidox');
+ if ($build_apidox)
+ {
+ $apidox_result = safe_make ($module, $trynumber, 1);
+ error "\tCouldn't build API Documentation" if $apidox_result;
+ }
+
+ my $elapsed = prettify_seconds (time - $start_time);
+ my $do_install = get_option($module, 'install-after-build');
+
+ info "\tBuild done after g[$elapsed].";
+ if ($do_install)
+ {
+ handle_install($module, 0);
+ handle_install($module, 1) if $build_apidox and $apidox_result == 0;
+ }
+ else
+ {
+ info "\tSkipping install for y[$module]";
+ }
+
+ last; # Don't forget to exit the loop!
+ }
+ }
+
+ return 1;
+}
+
+# Subroutine to handle the build process.
+# First parameter is a reference of a list containing the packages
+# we are to build.
+# If the packages are not already checked-out and/or updated, this
+# subroutine WILL NOT do so for you.
+#
+# This subroutine assumes that the $kdesvn directory has already been
+# set up. It will create $builddir if it doesn't already exist.
+#
+# If $builddir/$module/.refresh-me exists, the subroutine will
+# completely rebuild the module.
+#
+# Returns 0 for success, non-zero for failure.
+sub handle_build
+{
+ my @build_done;
+ my $build_ref = shift;
+ my $kdesvn = get_kdesvn_dir();
+ my $svnroot = get_option ('global', 'svn-server');
+ my $module;
+ my @modules = grep (!/^(KDE\/)?kde-common$/, @{$build_ref});
+ my $result;
+ my $outfile = get_output_file ();
+
+ # No reason to print building messages if we're not building.
+ return 0 if scalar @modules == 0;
+
+ note "<<< Build Process >>>";
+
+ # Save the environment to keep module's env changes from affecting other
+ # modules.
+ my %env_backup = %ENV;
+
+ if (pretending)
+ {
+ pretend "\tWould have opened status file g[$outfile].";
+ $outfile = undef; # Don't actually try it though.
+ }
+
+ if ($outfile)
+ {
+ open STATUS_FILE, ">$outfile" or do {
+ error <<EOF;
+ Unable to open output status file r[b[$outfile]
+ You won't be able to use the g[--resume] switch next run.\n";
+EOF
+ $outfile = undef;
+ };
+ }
+
+ my $num_modules = scalar @modules;
+ my $i = 1;
+
+ while ($module = shift @modules)
+ {
+ my $start_time = time;
+
+ if (build_module ($module, $i, $num_modules))
+ {
+ my $elapsed = prettify_seconds(time - $start_time);
+ print STATUS_FILE "$module: Succeeded after $elapsed.\n" if $outfile;
+
+ info "\tOverall time for g[$module] was g[$elapsed].";
+ push @build_done, $module;
+ }
+ else
+ {
+ my $elapsed = prettify_seconds(time - $start_time);
+ print STATUS_FILE "$module: Failed after $elapsed.\n" if $outfile;
+
+ info "\tOverall time for r[$module] was g[$elapsed].";
+ push @{$fail_lists{'build'}}, $module;
+
+ if (get_option($module, 'stop-on-failure'))
+ {
+ note "\n$module didn't build, stopping here.";
+ return 1; # Error
+ }
+ }
+
+ print "\n";
+ %ENV = %env_backup;
+ $i++;
+ }
+
+ # If we have packages that failed to update we should probably mention them
+ # in the build-status file as well.
+ if ($outfile)
+ {
+ for my $failure (@{$fail_lists{'update'}})
+ {
+ print STATUS_FILE "$failure: Failed on update.\n";
+ }
+
+ close STATUS_FILE;
+ }
+
+ info "<<< Build Done >>>\n";
+ info "\n<<< g[PACKAGES SUCCESSFULLY BUILT] >>>" if scalar @build_done > 0;
+
+ if (not pretending)
+ {
+ # Print out results, and output to a file
+ open BUILT_LIST, ">$kdesvn/successfully-built";
+ foreach $module (@build_done)
+ {
+ info "$module";
+ print BUILT_LIST "$module\n";
+ }
+ close BUILT_LIST;
+ }
+ else
+ {
+ # Just print out the results
+ info 'g[', join ("]\ng[", @build_done), ']';
+ }
+
+ info " "; # Add newline for aesthetics if not in quiet mode.
+ return scalar @{$fail_lists{'build'}};
+}
+
+# Subroutine to exit the script cleanly, including removing any
+# lock files created. If a parameter is passed, it is interpreted
+# as an exit code to use
+sub finish
+{
+ my $exitcode = shift;
+ my $logdir = get_log_dir('global');
+ $exitcode = 0 unless $exitcode;
+
+ close_lock() unless pretending;
+
+ note "Your logs are saved in y[$logdir]";
+ exit $exitcode;
+}
+
+# Subroutine to determine the current repository URL for the current working
+# directory.
+sub get_repo_url
+{
+ my $output = `svn info | grep URL`;
+ $output =~ s/URL: (.*)$/$1/;
+ chomp $output;
+
+ return $output;
+}
+
+# Subroutine to determine whether or not the given module has the correct
+# URL. If not, a warning is printed out.
+# First parameter: module to check.
+# Return: Nothing.
+sub check_module_validity
+{
+ # This test reads the HD so don't bother during pretend.
+ return if pretending;
+
+ my $module = shift;
+ my $source_dir = get_fullpath($module, 'source');
+ my $module_expected_url = svn_module_url($module);
+
+ chdir($source_dir); # Required for get_repo_url
+ my $module_actual_url = get_repo_url();
+
+ if($module_actual_url ne $module_expected_url)
+ {
+ warning <<EOF;
+ y[!!]
+ y[!!] g[$module] seems to be checked out from somewhere other than expected.
+ y[!!]
+
+kdesvn-build expects: y[$module_expected_url]
+The module is actually from: y[$module_actual_url]
+
+If the module location is incorrect, you can fix it by either deleting the
+g[b[source] directory, or by changing to the source directory and running
+ svn switch $module_expected_url
+
+If the module is fine, please update your configuration file.
+EOF
+ }
+}
+
+# Subroutine to handle the installation process. Simply calls
+# 'make install' in the directory.
+sub handle_install
+{
+ my $apidox = pop; # Take parameter off end of list (@_).
+ my @no_install_modules = qw/qt-copy kde-common/;
+ my $result = 0;
+
+ for my $module (@_)
+ {
+ if (list_has(@no_install_modules, $module))
+ {
+ info "\tg[$module] doesn't need to be installed.";
+ next;
+ }
+
+ my $builddir = get_fullpath($module, 'build');
+
+ if (not exists $package_opts{$module})
+ {
+ warning "\tUnknown module y[$module], configure it in $rcfile.";
+ $package_opts{$module} = { 'set-env' => { } };
+ next;
+ }
+
+ if (not -e "$builddir/Makefile")
+ {
+ warning "\tThe build system doesn't exist for r[$module].";
+ warning "\tTherefore, we can't install it. y[:-(].";
+ next;
+ }
+
+ # Just in case, I guess.
+ update_module_environment ($module);
+
+ # The /admin directory is needed for install as well, make sure it's
+ # there.
+ if (not create_admin_dir($module))
+ {
+ warning "Unable to find /admin directory for y[$module], it probably";
+ warning "won't install.";
+ # But continue anyways, because in this case I'm just not sure that it
+ # won't work in the future. ;)
+ }
+
+ # safe_make() evilly uses the "install" parameter to use installation
+ # mode instead of compile mode. This is so we can get the subdirectory
+ # handling for free.
+ if (safe_make ($module, "install", $apidox))
+ {
+ error "\tUnable to install r[$module]!";
+ $result = 1;
+ push @{$fail_lists{'install'}}, $module;
+
+ if (get_option($module, 'stop-on-failure'))
+ {
+ note "y[Stopping here].";
+ return 1; # Error
+ }
+ }
+
+ if (pretending)
+ {
+ pretend "\tWould have installed g[$module]";
+ next;
+ }
+
+ next if $result != 0; # Don't delete anything if the build failed.
+
+ my $remove_setting = get_option($module, 'remove-after-install');
+
+ # Possibly remove the srcdir and builddir after install for users with
+ # a little bit of HD space.
+ if($remove_setting eq 'all')
+ {
+ # Remove srcdir
+ my $srcdir = get_fullpath($module, 'source');
+ note "\tRemoving b[r[$module source].";
+ system ('rm', '-rf', $srcdir);
+ }
+
+ if($remove_setting eq 'builddir' or $remove_setting eq 'all')
+ {
+ # Remove builddir
+ note "\tRemoving b[r[$module build directory].";
+ system ('rm', '-rf', $builddir);
+ }
+ }
+
+ return $result;
+}
+
+# This subroutine goes and makes sure that any entries in the update and build
+# lists that have a directory separator are faked into using the checkout-only
+# feature. This doesn't really work for install mode though.
+sub munge_lists
+{
+ debug "Munging update and build list";
+ my $cleared = 0;
+
+ for my $list_ref ( ( \@update_list, \@build_list) ) {
+ my @temp;
+
+ while ($_ = shift @$list_ref) {
+ # Split at directory separators.
+ my ($modulename, @dirs) = split(/\//);
+
+ # For these modules, the first part of the directory separator
+ # actually belongs with the module name.
+ if (has_base_module($modulename))
+ {
+ $modulename .= "/" . shift @dirs;
+ }
+
+ if (scalar @dirs > 0)
+ {
+ # Only build the specified subdirs
+ if (not $cleared)
+ {
+ debug "Clearing checkout-only option.";
+
+ $cleared = 1;
+ set_option($modulename, 'checkout-only', '');
+ }
+
+ # The user has included a directory separator in the module name, so
+ # let's fake the svn partial checkout
+ $_ = $modulename;
+
+ # Don't automatically add the /admin dir for this module now.
+ set_option($_, '#suppress-auto-admin', 1);
+
+ my $checkout_str = join ("/", @dirs);
+
+ debug "Adding $checkout_str to checkout-only for $_";
+
+ if (get_option($_, 'checkout-only') !~ /$checkout_str/)
+ {
+ $package_opts{$_}{'checkout-only'} .= " $checkout_str";
+ }
+ else
+ {
+ debug print "\tOption was already present.";
+ }
+ }
+ else
+ {
+ debug "Skipping $_ in munge process.";
+ }
+
+ # Don't add the modulename to the list twice.
+ push @temp, $_ if not list_has(@temp, $_);
+ }
+
+ @$list_ref = @temp;
+ }
+}
+
+# Subroutine to try an intelligently determine what caused the module to fail
+# to build/update/whatever. The first parameter is the name of the module,
+# and the return value is the best guess at the error. If no error is detected
+# the last 30 lines of the file are returned instead.
+sub whats_the_module_error
+{
+ my $module = shift;
+ my $file = get_option($module, '#error-log-file');
+
+ open ERRORFILE, "<$file" or return "Can't open logfile $file.\n";
+
+ my @lastlines; # Used to buffer last lines read.
+ my @errors; # Tracks errors and the file they were found in.
+ my $lastfile = ''; # Tracks last filename read in error log.
+ my $errorCount = 0;
+ my $output;
+
+ # TODO: This code is tested for gcc and GNU ld, as, etc, I'm not sure how
+ # effective it is at parsing the error output of other build toolchains.
+ while (<ERRORFILE>)
+ {
+ # Keep last 30 lines.
+ push @lastlines, $_;
+ shift @lastlines if scalar @lastlines > 30;
+
+ my ($file, $line, $msg) = /^([^:]*):(\d+):\s*(.*)$/;
+
+ next unless ($file and $line and $msg);
+ next if $msg =~ /warn/i;
+ next if $msg =~ /^in file included from/i;
+ next if $msg =~ /^\s*$/ or $file =~ /^\s*$/;
+ $msg =~ s/^error: ?//i;
+
+ if ($file eq $lastfile)
+ {
+ $errorCount++;
+ push @errors, $msg if $errorCount < 5;
+ }
+ else
+ {
+ # Check is because we print info on the last file read, so there
+ # should be a last file. ;)
+ if ($lastfile)
+ {
+ my $error = $errorCount == 1 ? "error" : "errors";
+ $output .= "$errorCount $error in $lastfile\n";
+ $output .= "Error: $_\n" foreach (@errors);
+ $output .= "\t<clipped>\n" if $errorCount > 5;
+ $output .= "\n";
+ }
+
+ $errorCount = 1;
+ @errors = ($msg);
+ }
+
+ $lastfile = $file;
+ }
+
+ close ERRORFILE;
+
+ if (not $lastfile)
+ {
+ # Print out last lines read, hopefully a more descriptive error
+ # message is in there.
+ $output .= "Can't find errors, last " . scalar @lastlines . " line(s) of the output are:\n";
+ $output .= $_ foreach (@lastlines);
+ return $output;
+ }
+
+ # Don't forget to display info on last file read since it won't be done in
+ # the loop.
+ my $error = $errorCount == 1 ? "error" : "errors";
+ $output .= "$errorCount $error in $lastfile\n";
+ $output .= "Error: $_\n" foreach (@errors);
+ $output .= "\t<clipped>\n" if $errorCount > 5;
+
+ return $output;
+}
+
+# Subroutine to get the e-mail address to send e-mail from.
+# It is pulled from the global email-address option by default.
+# The first parameter is a default e-mail address to use (may be left off, in
+# which case this function will create a default of its own if necessary.)
+sub get_email_address
+{
+ my $email = get_option('global', 'email-address');
+ my $default = shift;
+
+ # Use user's value if set.
+ return $email if $email;
+
+ # Let's use the provided default if set.
+ return $default if $default;
+
+ # Let's make a default of our own. It's likely to suck, so oh well.
+ use Sys::Hostname;
+ my $username = getpwuid($>);
+ my $hostname = hostname; # From Sys::Hostname
+
+ debug "User has no email address, using $username\@$hostname";
+
+ return "$username\@$hostname";
+}
+
+# Subroutine to look through the various failed lists, and send an email to the
+# given email address with a description of the failures. If the user has
+# selected no email address the subroutine does nothing.
+sub email_error_report
+{
+ my $email_addy = get_option('global', 'email-on-compile-error');
+ my $from_addy = get_email_address($email_addy);
+
+ return unless $email_addy;
+
+ # Initial e-mail header.
+ my $email_body = <<EOF;
+The following errors were detected in the kdesvn-build run just completed.
+
+EOF
+
+ # Loop through modules trying to find out what caused the errors.
+ my $had_error = 0;
+ for my $type (@fail_display_order)
+ {
+ for my $module (@{$fail_lists{$type}})
+ {
+ $email_body .= "$module failed to $type:\n";
+ $email_body .= "-------------------------------\n\n";
+ $email_body .= whats_the_module_error($module);
+ $email_body .= "-------------------------------\n\n";
+
+ $had_error = 1;
+ }
+ }
+
+ return unless $had_error;
+
+ # Detect Mail::Mailer.
+ my $mailer;
+ eval {
+ require Mail::Mailer;
+
+ $mailer = new Mail::Mailer;
+ } or do {
+ error " y[*] Can't open y[b[Mail::Mailer] module, so e-mailing is disabled.";
+ debug "Error was $@";
+ return;
+ };
+
+ # Sendeth the email.
+ $mailer->open({
+ 'From' => $from_addy,
+ 'To' => $email_addy,
+ 'Subject' => 'KDE Subversion build compile error',
+ });
+
+ print $mailer $email_body;
+ $mailer->close;
+}
+
+# This subroutine sets up or removes the default branch option for a few
+# modules in order to build KDE 3.5 by default. branch options in the
+# configuration file will still override these settings.
+sub setup_kde35_hack
+{
+ my @branched_modules = qw/kde-common kdeaccessibility kdeaddons kdeadmin
+ kdeartwork kdebase kdebindings kdeedu kdegames kdegraphics kdelibs
+ kdemultimedia kdenetwork kdepim kdesdk kdetoys kdeutils kdevelop
+ kdewebdev/;
+
+ # arts uses a different versioning scheme.
+ set_option('arts', 'branch', '1.5');
+
+ # koffice 1.5 is the last KDE 3 compatible release.
+ set_option('koffice', 'branch', '1.5');
+
+ # qt-copy is in branches/qt/3.3. Due to the default option handling the
+ # handling is done in setup_default_modules().
+ # set_option('qt-copy', 'module-base-path', 'branches/qt/3.3');
+
+ for my $module (@branched_modules)
+ {
+ # Default to downloading from KDE 3.5 instead of KDE 4.
+ set_option($module, 'branch', '3.5');
+ }
+}
+
+# Script starts.
+
+# Use some exception handling to avoid ucky error messages
+eval
+{
+ # Note to self: Quit changing the order around.
+ process_arguments(); # Process --help, --install, etc. first.
+ setup_kde35_hack(); # Add 'branch' options as appropriate.
+ read_options(); # If we're still here, read the options
+ initialize_environment(); # Initialize global env vars.
+
+ setup_logging_subsystem(); # Setup logging directories.
+
+ dump_options() if debugging;
+};
+
+if ($@)
+{
+ # We encountered an error.
+ print "Encountered an error in the execution of the script.\n";
+ print "The error reported was $@\n";
+ print "Please submit a bug against kdesvn-build on http://bugs.kde.org/\n";
+
+ # Don't finish, because we haven't attained the lock yet.
+ exit 99;
+}
+
+if (not pretending and not get_lock())
+{
+ print "$0 is already running!\n";
+ exit 0; # Don't finish(), it's not our lockfile!!
+}
+
+# Now use an exception trapping loop that calls finish().
+my $result;
+eval
+{
+ my $time = localtime;
+ info "Script started processing at g[$time]";
+
+ @update_list = get_update_list();
+ @build_list = get_build_list();
+
+ debug "Update list is ", join (', ', @update_list);
+ debug "Build list is ", join (', ', @build_list);
+
+ # Do some necessary adjusting. Right now this is used for supporting
+ # the command-line option shortcut to where you can enter e.g.
+ # kdelibs/khtml, and the script will only try to update that part of
+ # the module.
+ munge_lists();
+
+ # Make sure unsermake is checked out automatically if needed
+ adjust_update_list(\@update_list, \@build_list);
+
+ if (not $install_flag)
+ {
+ # No packages to install, we're in build mode
+ $result = handle_updates (\@update_list);
+ $result = handle_build (\@build_list) || $result;
+ }
+ else
+ {
+ # Installation mode (no apidox)
+ $result = handle_install (get_install_list(), 0);
+ }
+
+ output_failed_module_lists();
+ email_error_report();
+
+ $time = localtime;
+ my $color = '';
+ $color = 'r[' if $result;
+
+ info "${color}Script finished processing at g[$time]";
+};
+
+if ($@)
+{
+ # We encountered an error.
+ print "Encountered an error in the execution of the script.\n";
+ print "The error reported was $@\n";
+ print "Please submit a bug against kdesvn-build on http://bugs.kde.org/\n";
+
+ $result = 99;
+}
+
+finish($result);
+
+# vim: set et sw=4 ts=4:
diff --git a/scripts/kdesvn-buildrc-sample b/scripts/kdesvn-buildrc-sample
new file mode 100644
index 00000000..a19e13da
--- /dev/null
+++ b/scripts/kdesvn-buildrc-sample
@@ -0,0 +1,246 @@
+# Sample configuration file for kdesvn-build. (Applies to KDE 3.5)
+#
+# To use this sample configuration file, copy it to ~/.kdesvn-buildrc, and then
+# edit it to suit your desires.
+
+# Global settings go in this section. They apply to every module unless
+# overridden later.
+global
+
+# binpath controls the value of the PATH environment variable during
+# compilation. If you have unusual tools that need to be in the path to build
+# KDE, add them here. KDE's and Qt's programs are automatically added.
+ binpath /bin:/usr/bin:/usr/local/bin:/usr/X11R6/bin
+# binpath /usr/lib/ccache/bin:/bin:/usr/bin:/usr/local/bin:/usr/X11R6/bin
+
+# This is the directory that your KDE sources are downloaded to. This
+# directory also holds the build and log directories by default.
+# source-dir ~/kdesvn
+
+# This is the Qt installation to use to build KDE. The default is qt-copy
+# from Subversion.
+ qtdir ~/kdesvn/build/qt-copy
+
+# You might want to use your system's built-in Qt already (3.3 or greater, not
+# 4.x). If so, assign the qtdir option appropriately.
+# qtdir /path/to/system/qt
+
+# This is the Subversion server to download the KDE sources from. Developers:
+# Don't forget to add your username to the URL if necessary!
+# svn-server svn://anonsvn.kde.org/home/kde
+
+# This controls the configure flags passed to every module (except qt-copy) by
+# default. If you have module-specific configure flags, they will be placed
+# after these flags to allow the module setting to override the global setting.
+ configure-flags --enable-debug
+
+# These are the compilation flags to use by default when compiling KDE.
+# gcc supports a -march option in order to generate specific code for pentium4, athlon-xp,
+# etc. See the gcc man page for more information.
+ cxxflags -pipe
+
+# These are the default options passed to the make command. The default tries
+# to build with 2 parallel compiles. If you are using distcc or have SMP, you
+# should experiment with setting this value higher for best performance.
+# make-options -j2
+
+# These are the default options passed to unsermake, which supports some
+# options not present with make. The default tries to run 2 compile jobs
+# in parallel. The -p option is used to display progress information.
+# unsermake-options --compile-jobs=2 -p
+
+# This option is used to decide whether to use the unsermake build system, which
+# is usually faster and more efficient than the standard automake-based build
+# system. It is generally stable enough to use, so it defaults to on. You
+# can disable this on a module-by-module basis if it gives you problems.
+# use-unsermake true
+
+# This directory is where everything gets built before it is installed. By
+# default it is relative to the value for source-dir. You can specify an
+# absolute path if you'd like (begin the path with a slash).
+# build-dir build
+
+# This is the directory that KDE will end up installed at. The default is
+# appropriate for a single-user installation of KDE, which requires no root
+# permissions. If you'd like, you can install and use the sudo program to
+# install KDE anywhere on your system, in conjunction with the
+# make-install-prefix option.
+# kdedir ~/kde
+#
+# You can overwrite the installation directory for a given module using
+# the per-module "prefix" option. Note that when doing this you need to
+# set KDEDIRS, PATH and LD_LIBRARY_PATH to point to both directories,
+# and that you should use separate test users or KDEHOME values to separate
+# the ksycoca databases. Only set prefix if you know what you're doing.
+
+# If you would like install KDE to the system (DO NOT INSTALL *over* a prior
+# installation!), then you'll probably need to use sudo to install everything.
+# make-install-prefix sudo
+
+# You can use the set-env option to add values to the build environment.
+ set-env LDFLAGS -Wl,-O1 # Optimize the linker, takes longer.
+
+# If you use software which requires pkg-config, and you need to add entries
+# to your pkg-config path, you can also use set-env for that. Some broken
+# systems require you to set this to find e.g. glib.
+# set-env PKG_CONFIG_PATH /opt/gnome/lib/pkgconfig
+end global
+
+# qt-copy is a copy of Trolltech's Qt, optionally with some bugfixes and
+# optimizations added. It is the easiest way to get Qt if you don't already
+# have it (and you don't want to use your distro's tools to install it.)
+module qt-copy
+ configure-flags -system-zlib -qt-gif -system-libjpeg -system-libpng \
+ -plugin-imgfmt-mng -thread -no-exceptions -debug \
+ -fast -dlopen-opengl
+ apply-qt-patches true
+ use-qt-builddir-hack true
+
+ # trunk's qt-copy is 4.x now.
+ module-base-path branches/qt/3.3
+end module
+
+# arts is the KDE sound library.
+module arts
+end module
+
+# kdesupport contains taglib and QCA. taglib is required for JuK, amarok, and
+# the meta info reader for music files in Konqueror.
+module kdesupport
+end module
+
+# kdelibs are the base KDE libraries needed by all KDE applications.
+module kdelibs
+ configure-flags --enable-sendfile --enable-mitshm
+
+# If you're a programmer you may want to build the API docs. Note that
+# it takes some time. :(
+# apidox true
+end module
+
+# kdebase contains useful general-purpose programs, normally people would
+# expect a usable desktop to have these.
+module kdebase
+ configure-flags --with-pam --with-shadow
+end module
+
+# kdemultimedia contains JuK, noatun, Kaboodle, and other KDE multimedia
+# applications. It does not include amarok, which is in extragear/multimedia
+module kdemultimedia
+end module
+
+# kdesdk is a useful module for software developers. It is where kdesvn-build
+# is developed.
+module kdesdk
+end module
+
+# kdenetwork has Kopete and other useful applications for the Internet and
+# other networks.
+module kdenetwork
+end module
+
+# kdeadmin has system administration tools for your computer.
+module kdeadmin
+ configure-flags --with-shadow --with-pam=yes
+end module
+
+# kdebindings is useful for software developers, and for those who wish to run
+# some KDE programs that don't use C++. The python bindings are not included
+# by default as they never build for me. If you'd like to build all the
+# bindings, comment out the checkout-only option below.
+module kdebindings
+ checkout-only admin dcopc kalyptus smoke qtruby korundum kjsembed dcoppython
+
+# kdebindings will probably need to use the following option to install
+# successfully. You must configure the sudo program first to allow for
+# passwordless operation.
+# make-install-prefix sudo
+ use-unsermake false
+end module
+
+# kdepim contains KMail, Kontact, KOrganizer, and other insanely useful
+# programs that help you keep track of things.
+module kdepim
+ configure-flags --disable-exchange
+end module
+
+# kdeutils has miscellaneous programs which can be useful. You probably won't
+# die if you remove this from the config file though.
+module kdeutils
+end module
+
+# kdegraphics contains various programs useful for graphics editing. It
+# doesn't include Krita, which is part of KOffice, but it is worth it just for
+# KolourPaint.
+module kdegraphics
+end module
+
+# kdeaddons are nifty additions to some programs in other KDE modules. For
+# example, there are addons for Konqueror, extra Kicker applets, and Noatun
+# plugins.
+module kdeaddons
+end module
+
+# ... Well, they're games. ;)
+module kdegames
+# use-unsermake false
+end module
+
+# Contains nifty diversions of time, which generally aren't games.
+module kdetoys
+end module
+
+# Educational programs. Some are actually quite fun even if you're not trying
+# to learn anything.
+module kdeedu
+end module
+
+# The KDE Office Suite. Includes a pretty expansive collection of programs.
+# It is rather large, so you can cut download and build times by removing it
+# from this file.
+module koffice
+ # branch 1.5 # KOffice /trunk is not compatible with KDE 3.
+end module
+
+# The KDevelop IDE, useful for developing all kinds of programs. If you don't
+# plan on being a software developer you can save time by removing this from
+# your configuration.
+module kdevelop
+ use-unsermake false
+end module
+
+# Includes Quanta Plus and other web design tools.
+module kdewebdev
+end module
+
+# Modules in extragear and playground can also be added.
+# To see what you can find in the various modules, browse
+# http://websvn.kde.org/trunk/extragear and
+# http://websvn.kde.org/trunk/playground
+
+# Includes various libraries needed by other applications in extragear.
+module extragear/libs
+
+# If you don't like the default name that kdesvn-build gives modules on-disk,
+# you can use dest-dir to change it.
+# dest-dir extragear-libs
+end module
+
+# Includes the popular K3B and Amarok programs.
+module extragear/multimedia
+end module
+
+# Includes various photo management applications.
+module extragear/graphics
+ checkout-only digikamimageplugins digikam gwenview kimdaba
+end module
+
+# module extragear/network
+# # Options like checkout-only should work as before.
+# checkout-only konversation
+# end module
+
+# module playground/games
+# end module
+
+# Add more modules as needed, they support the same options as before.
diff --git a/scripts/kdesvn-buildrc.xml b/scripts/kdesvn-buildrc.xml
new file mode 100644
index 00000000..08607889
--- /dev/null
+++ b/scripts/kdesvn-buildrc.xml
@@ -0,0 +1,152 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE language SYSTEM "language.dtd">
+<!-- This goes into $KDEDIR/share/apps/katepart/syntax, or
+ it can go to $KDEHOME/share/apps/katepart/syntax
+ -->
+<language name="kdesvn-buildrc" version="0.2" kateversion="2.4" section="Configuration" extensions=".kdesvn-buildrc;kdesvn-buildrc" author="Michael Pyne &lt;michael.pyne@kdemail.net&gt;" license="LGPL">
+
+ <highlighting>
+ <list name="bools">
+ <item>true</item>
+ <item>false</item>
+ <item>TRUE</item>
+ <item>FALSE</item>
+ <item>self</item> <!-- Only used by use-unsermake, don't feel like
+ forking a separate context for it though. -->
+ </list>
+
+ <list name="setEnvOptions">
+ <item>set-env</item> <!-- Handled separately for special syntax highlighting. -->
+ </list>
+
+ <!-- These options should only have a boolean value passed to them. -->
+ <list name="boolOptions">
+ <item>apidox</item>
+ <item>apply-qt-patches</item>
+ <item>build-system-only</item>
+ <item>colorful-output</item>
+ <item>debug</item>
+ <item>disable-agent-check</item>
+ <item>manual-build</item>
+ <item>manual-update</item>
+ <item>no-svn</item>
+ <item>no-rebuild-on-fail</item>
+ <item>pretend</item>
+ <item>reconfigure</item>
+ <item>recreate-configure</item>
+ <item>refresh-build</item>
+ <item>remove-after-install</item>
+ <item>stop-on-failure</item>
+ <item>use-unsermake</item>
+ <item>use-qt-builddir-hack</item>
+ </list>
+
+ <list name="options">
+ <item>binpath</item>
+ <item>branch</item>
+ <item>build-dir</item>
+ <item>checkout-only</item>
+ <item>configure-flags</item>
+ <item>cxxflags</item>
+ <item>debug-level</item>
+ <item>dest-dir</item>
+ <item>do-not-compile</item>
+ <item>email-address</item>
+ <item>email-on-compile-error</item>
+ <item>install-after-build</item>
+ <item>inst-apps</item>
+ <item>kdedir</item>
+ <item>libpath</item>
+ <item>log-dir</item>
+ <item>make-install-prefix</item>
+ <item>make-options</item>
+ <item>module-base-path</item>
+ <item>niceness</item>
+ <item>override-url</item>
+ <item>prefix</item>
+ <item>qtdir</item>
+ <item>revision</item>
+ <item>source-dir</item>
+ <item>svn-server</item>
+ <item>tag</item>
+ <item>unsermake-options</item>
+ <item>unsermake-path</item>
+ </list>
+
+ <contexts>
+ <context name="Module" attribute="Normal Text" lineEndContext="#stay">
+ <DetectSpaces/>
+ <RegExpr attribute="Comment" String="#.*$" context="#stay"/>
+ <RegExpr attribute="Global Declaration" context="Module Options" String="global" beginRegion="Global Options" firstNonSpace="true" />
+ <RegExpr attribute="Module Declaration" context="Module Decl" String="module\s+" firstNonSpace="true" />
+ </context>
+
+ <context name="Module Decl" attribute="Module Name" lineEndContext="Module Options">
+ <RegExpr String="[a-zA-Z0-9-]*" context="#stay" beginRegion="Module Options"/>
+ <RegExpr attribute="Comment" String="#.*$" context="#stay"/>
+ </context>
+
+ <context name="Module Options" attribute="Normal Text" lineEndContext="#stay">
+ <DetectSpaces/>
+ <RegExpr attribute="Comment" String="#.*$" context="#stay"/>
+ <keyword attribute="Option Name" context="Environment Name" String="setEnvOptions" />
+ <keyword attribute="Option Name" context="Option Value" String="options"/>
+ <keyword attribute="Option Name" context="Bool Option Value" String="boolOptions"/>
+
+ <RegExpr attribute="Module Declaration" context="Module" endRegion="Module Options" String="end module" firstNonSpace="true"/>
+ <RegExpr attribute="Module Declaration" context="Module" endRegion="Global Options" String="end global" firstNonSpace="true"/>
+
+ <!-- No kdesvn-build options start with digits or a dash. -->
+ <RegExpr attribute="Possible Error" context="Option Value" String="[0-9-][a-zA-Z0-9-]+" />
+ <RegExpr attribute="Unknown Option Name" context="Option Value" String="[a-zA-Z0-9-]+" />
+ </context>
+
+ <context name="Option Value" attribute="Normal Text" lineEndContext="#pop">
+ <RegExpr attribute="Comment" String="#.*$" />
+ <DetectSpaces/>
+ <RegExpr attribute="Variable" String="\$\{[a-zA-Z0-9-]+\}"/>
+ <RegExpr attribute="Option Value" String="[a-zA-Z:0-9,./+!=@-]*" context="#stay" />
+ <LineContinue context="#stay"/>
+ <AnyChar attribute="Option Value" String="\\"/>
+ </context>
+
+ <context name="Bool Option Value" attribute="Normal Text" lineEndContext="#pop">
+ <keyword attribute="Option Value" context="#stay" String="bools"/>
+ <RegExpr attribute="Comment" String="#.*$" />
+ <DetectSpaces/>
+ <RegExpr attribute="Possible Error" String="[^\\]*"/>
+ <LineContinue attribute="Possible Error" context="#stay"/>
+ <AnyChar attribute="Possible Error" String="\\"/>
+ </context>
+
+ <context name="Environment Name" attribute="Environment Variable Name" lineEndContext="#pop">
+ <RegExpr attribute="Comment" String="#.*$" />
+ <DetectSpaces/>
+ <RegExpr attribute="Environment Variable Name" context="Option Value" String="[a-zA-Z0-9_-]+" />
+ </context>
+ </contexts>
+
+ <itemDatas>
+ <itemData name="Normal Text" defStyleNum="dsNormal" />
+ <itemData name="Comment" defStyleNum="dsComment"/>
+ <itemData name="Boolean" defStyleNum="dsDecVal" bold="true" color="purple"/>
+ <itemData name="Option Name" defStyleNum="dsKeyword" bold="false" />
+ <itemData name="Unknown Option Name" defStyleNum="dsKeyword" bold="false" color="#7D4C0B" />
+ <itemData name="Environment Variable Name" defStyleNum="dsString" color="#EE6A50" />
+ <itemData name="Option Value" defStyleNum="dsDecVal" />
+ <itemData name="Variable" defStyleNum="dsOthers" />
+ <itemData name="Module Declaration" defStyleNum="dsKeyword"/>
+ <itemData name="Module Name" defStyleNum="dsOthers" bold="true" />
+ <itemData name="Global Declaration" defStyleNum="dsKeyword"/>
+ <itemData name="Possible Error" defStyleNum="dsError" />
+ </itemDatas>
+ </highlighting>
+
+ <general>
+ <comments>
+ <comment name="singleLine" start="#"/>
+ </comments>
+ <keywords weakDeliminator="-"/>
+ </general>
+
+</language>
diff --git a/scripts/licensecheck b/scripts/licensecheck
new file mode 100755
index 00000000..1640d9f5
--- /dev/null
+++ b/scripts/licensecheck
@@ -0,0 +1,63 @@
+#!/usr/bin/perl -w
+#
+# License checker for source files
+
+# This should kept in sync with kde-common/svn/hooks/post-commit.pl
+sub checklicense($)
+{
+ my ($text) = @_;
+
+ $text =~ y/\t\n\r/ /;
+ $text =~ y/ A-Za-z.,@1-9\(\)//cd;
+ $text =~ s/\s+/ /g;
+
+ my ($gl, $qte, $license, $massave);
+
+ $gl = "";
+ $qte = "";
+ $license = "";
+ $massave = "";
+
+ $gl = " (v2)" if ($text =~ /version 2 as published by the Free Software Foundation/);
+ $gl = " (v2+)" if ($text =~ /either version 2 of the License, or .at your option. any later version/);
+ $gl = " (v2.1)" if ($text =~ /version 2\.1 as published by the Free Software Foundation/);
+ $gl = " (v2.1+)" if ($text =~ /either version 2\.1 of the License, or .at your option. any later version/);
+ $qte = " (+Qt exception)" if ($text =~ /([Pp]ermission is given|[pP]ermission is also granted|[pP]ermission) to link (the code of )?this program with (any edition of )?(Qt|the Qt library)/);
+ $massave = " (wrong address)" if ($text =~ /(?:675 Mass Ave|59 Temple Place|51 Franklin Steet|02139|02111-1307)/i); # "51 Franklin Street, 02110-1301" is the right FSF address
+
+ $license="GENERATED FILE" if ($text =~ /(All changes made in this file will be lost|DO NOT EDIT|DO NOT delete this file|[Gg]enerated by)/);
+ $license="LGPL$gl$massave $license" if ($text =~ /is free software.? you can redistribute it and.?or modify it under the terms of the GNU (Library|Lesser) General Public License/);
+ $license="GPL$gl$qte$massave $license" if ($text =~ /is free software.? you can redistribute it and.?or modify it under the terms of the GNU General Public License/);
+ ### FIXME if the license matches the next regexp, it will probably match the following one too.
+ $license="QPL (part of Qt) $license" if ($text =~ /This file is part of the .*Qt GUI Toolkit. This file may be distributed under the terms of the Q Public License as defined/);
+ $license="QPL $license" if ($text =~ /may be distributed under the terms of the Q Public License as defined by Trolltech AS/);
+ $license="X11 (BSD like) $license" if($text =~ /Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files .the Software., to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and.?or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED AS IS/);
+ $license="BSD $license" if ($text =~ /THIS SOFTWARE IS PROVIDED BY THE AUTHOR AS IS AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE/);
+ $license="MPL 1.1 $license" if ($text =~ /subject to the Mozilla Public License Version 1.1/);
+ $license="no copyright $license" if ($text !~ /copyright/i);
+ $license="UNKNOWN" if(!length($license));
+
+ $license =~ s/ $//;
+
+ return "$license";
+}
+
+my $verbose = 0;
+foreach my $arg (@ARGV) {
+ if ($arg eq "-v") {
+ $verbose = 1;
+ } else {
+ # For each file
+ if ($verbose) {
+ print "----- header -----\n";
+ print `head -n 30 $arg| sed 's/ / /g;s/\$/ /g;s#//##g' | tr -d -c ' A-Za-z.,/\@1-9()'`."\n";
+ print "--- end header ---\n";
+ }
+ open(F, "<$arg") || die "Couldn't open $arg";
+ my @c = <F>;
+ my $htxt = join '', @c[0.. ($#c > 29 ? 29 : $#c)];
+ my $license = &checklicense($htxt);
+ close(F);
+ print "$arg: $license\n";
+ }
+}
diff --git a/scripts/makeobj b/scripts/makeobj
new file mode 100755
index 00000000..cc79c663
--- /dev/null
+++ b/scripts/makeobj
@@ -0,0 +1,96 @@
+#! /usr/bin/env bash
+
+# this is a script around make which basicly checks
+# if it's in srcdir or in builddir and changes to
+# the right directory for calling /usr/bin/make
+# (C) Stephan Kulow
+
+# You may need to set OBJ_REPLACEMENT variable to get it to work.
+# In the variable use the sed syntax to switch directories, for example
+# export OBJ_REPLACEMENT="s:/home/zack/cvs/kde:/home/zack/build:"
+# will assure that the builds are performed under /home/zack/build
+# directory, when the cvs is held under /home/zack/cvs/kde.
+
+file=Makefile
+dir=.
+args=()
+
+while test $# -gt 0 ; do
+ case "${1}" in
+ -f)
+ shift
+ file="${1}"
+ shift
+ args=("${args[@]}" -f $file)
+ ;;
+ -C)
+ shift
+ dir="${1}"
+ shift ;;
+ *)
+ args=("${args[@]}" "$1")
+ shift
+ ;;
+ esac
+done
+
+if test ! -f $dir/$file; then
+ if test -n "$OBJ_SUBDIR"; then
+ dir=$PWD
+ subdir=.
+ while test ! -f $dir/$OBJ_SUBDIR/$file; do
+ subdir=`basename $dir`"/$subdir"
+ dir=`dirname $dir`
+ if test "$dir" = "/"; then
+ # the case that someone puts the compile dir in /
+ # is very unlikely, so we better skip here ;)
+ echo "can't find $OBJ_SUBDIR above current dir"
+ exit 1
+ fi
+ done
+ cd $dir/$OBJ_SUBDIR/$subdir
+ else
+ if test -n "$OBJ_REPLACEMENT"; then
+ pwd=`echo $PWD | sed -e "$OBJ_REPLACEMENT"`
+ if test ! -f $pwd/$dir/$file; then
+ # No objdir found. But if "make" will work in srcdir, then go ahead; might be a non-kde project.
+ test -f $dir/GNUmakefile && file=GNUmakefile
+ test -f $dir/makefile && file=makefile
+ test -f $dir/$file || file=""
+ if test -z "$file"; then
+ echo "no objdir found. Tried $pwd"
+ exit 1
+ fi
+ fi
+ cd $pwd/$dir
+ fi
+ fi
+else
+ cd $dir
+fi
+
+echo "makeobj[0]: Entering directory \`$PWD'"
+if test -z "$MAKE"; then
+ using_new_unsermake=0
+ if head -n 1 $file | grep unsermake >/dev/null; then
+ using_new_unsermake=1
+ fi
+ if head -n 1 $file | grep automake >/dev/null; then
+ using_new_unsermake=0
+ fi
+ if test $using_new_unsermake -eq 1; then
+ MAKE=`type -p unsermake`
+ if test ! -x "$MAKE"; then
+ echo 'Makefile was created with unsermake, but there'
+ echo 'is no unsermake in $PATH'
+ exit 1
+ fi
+ else
+ MAKE=/usr/bin/make
+ fi
+fi
+LANGUAGE=C $MAKE "${args[@]}"
+retval=$?
+echo "makeobj[0]: Leaving directory \`$PWD'"
+exit $retval
+
diff --git a/scripts/noncvslist b/scripts/noncvslist
new file mode 100755
index 00000000..69f5a591
--- /dev/null
+++ b/scripts/noncvslist
@@ -0,0 +1,127 @@
+#! /usr/bin/env perl
+
+# Offline check for extra in a checked-out
+# CVS module. Sirtaj Singh Kang <taj@kde.org> May 2000.
+# Usage:
+# noncvsfiles <module dir>...
+
+@dirqueue = @ARGV;
+%entries = ();
+@files = ();
+
+sub processEntries
+{
+ my ( $dir ) = @_;
+
+ open( ENTRIES, $dir."/CVS/Entries" )
+ || warn "Couldn't read '$dir/CVS/Entries'";
+
+ while( <ENTRIES> ) {
+ if ( m#^\s*D/([^/]+)/# ) {
+ push ( @dirqueue, "$dir/$1" );
+ $entries{ "$dir/$1" } = 1;
+ next;
+ }
+
+ next unless m#^\s*/([^/]+)/([\d\.]*)/([^/]+)/#;
+
+ $fname = $1;
+ $ver = $2;
+ $stamp = $3;
+
+ $entries{ "$dir/$fname" } = $stamp;
+ }
+
+ close( ENTRIES );
+
+ open( IGNORE, $dir."/.cvsignore" ) || return;
+
+ while( <IGNORE> ) {
+ chomp;
+ s/^\s+//;
+ s/\s+$//;
+ $entries{ "$dir/$_" } = "ignored";
+ }
+
+ close( IGNORE );
+}
+
+# month assoc array for name -> index lookups
+$mctr = 0;
+
+foreach $month ( @monthlist ) {
+ $months{ $month } = $mctr;
+ $mctr++;
+}
+
+# Try current directory if none specified
+
+if( $#dirqueue < 0 ) {
+ push( @dirqueue, "." );
+}
+
+# process directory queue, filling entries hash
+foreach $dir ( @dirqueue ) {
+ processEntries( $dir );
+
+ open( FILES, 'find "'.$dir.'" | grep -v "/CVS"|' )
+ || die "Couldn't find files in $dir";
+
+ while( <FILES> ) {
+ chop;
+ next if $_ eq '.';
+ next if m/\/\.#/; #ignore .#blah
+ push @files, $_;
+ }
+}
+
+#foreach my $entry ( sort keys %entries )
+#{
+# print $entry,"\n";
+#}
+
+my $lastfile = "";
+
+foreach my $file ( sort @files )
+{
+ next if $file eq $lastfile;
+ $lastfile = $file;
+
+ if ( !exists $entries{ $file } ) {
+ print $file,"\n";
+ }
+}
+
+=head1 NAME
+
+noncvslist -- List all files in a checked out CVS module that are not
+known by the CVS server.
+
+=head1 SYNOPSIS
+
+When the current directory is a CVS module:
+
+ noncvslist
+
+Checking checked out subdirectories:
+
+ noncvslist [<dir>...]
+
+=head1 DESCRIPTION
+
+This script will list all files and directories in the module(s) that are
+not listed in the CVS/Entries files. These may be files created during builds,
+new un-added sources files etc. It is a useful housekeeping tool.
+
+=head1 EXAMPLES
+
+Assuming baseline/ has kdelibs/ and kdebase/ checked out within it:
+
+ cd baseline/kdelibs; noncvslist
+ cd baseline; noncvslist kdelibs kdebase
+
+=head1 AUTHOR
+
+Sirtaj Singh Kang <taj@kde.org>
+
+=cut
diff --git a/scripts/nonsvnlist b/scripts/nonsvnlist
new file mode 100755
index 00000000..1a72a798
--- /dev/null
+++ b/scripts/nonsvnlist
@@ -0,0 +1,4 @@
+#!/bin/sh
+# This script lists files not in the Subversion repository
+
+svn status $1 | sed '/^\?/{s/^.......//;p};d'
diff --git a/scripts/package_crystalsvg b/scripts/package_crystalsvg
new file mode 100755
index 00000000..1502da20
--- /dev/null
+++ b/scripts/package_crystalsvg
@@ -0,0 +1,185 @@
+#! /usr/bin/env bash
+echo -n "Starting up..."
+#
+# Copyright (C) 2004 Frans Englich <frans.englich@telia.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.
+#
+# 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, write to the Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+#
+#
+# This little script assumes that in $PWD/ is a check out of various
+# KDE modules, searches them for SVG files and packages them up in a tarball,
+# all the files in the toplevel, together with this script and a list of the files(FILES)
+# telling what KDE modules/path the svg files were copied from.
+# This script is shipped with the kdesdk package.
+#
+# Author: Frans Englich <frans.englich@telia.com>
+
+
+# In what directory we should search
+SEARCH_DIR="$PWD"
+
+
+# The name of the tar ball without extension. If you're not 110% sure
+# the sources are up to date, remove the date tag'
+PKGNAME="kde_crystalsvg-$(date '+%Y-%m-%d')"
+
+
+# The path to where the package should be written
+PKGPATH="$PWD/"
+
+
+# What nice value to run find and tar with. find is too intensive..
+NICE=15 # Low..
+
+
+# Path to the LICENSE file
+LICENSE="$SEARCH_DIR"/kdelibs/pics/LICENSE.crystalsvg
+
+
+# You shouldn't need to edit anything below.
+
+
+
+
+
+
+# Sanity checks
+if [ ! -d "$SEARCH_DIR" ]; then
+ echo "$SEARCH_DIR is not an directory. Exiting."
+ exit 1;
+fi
+
+if [ ! -r $LICENSE ]; then
+ echo "The file \"$LICENSE\" do not exist or is not readable. Exiting."
+ exit 1;
+fi
+
+TMPDIR=$(mktemp -d "/tmp/kde_crystalsvg_packageXXXXXX")
+PKGDIR="$TMPDIR/$PKGNAME"
+mkdir "$PKGDIR"
+
+echo "done" # Startup
+
+# Find the SVGs
+FILES="$PKGDIR/FILES"
+echo -n "Searching for the SVG files..."
+SVGFILES=$(find "$SEARCH_DIR" -name "cr*.svg*" -type f)
+if [ $? -ne 0 ]; then
+ echo "There was an error when searching for the files. Exiting."
+ exit 1;
+fi
+echo "done" # Search
+
+echo -n "Generating README, FILES etc. files..."
+# Fill the FILES file
+echo "" >> "$FILES"
+echo "README - contains general information about this package" >> "$FILES"
+echo "FILES - this file" >> "$FILES"
+echo "LICENSE - contains the license the SVG files are licensed under" >> "$FILES"
+echo "" >> "$FILES"
+echo "From the lines below, you can find out in what KDE package and where, the SVG are located" >> $FILES
+echo "" >> "$FILES"
+echo "$SVGFILES" | sed -e s,"$SEARCH_DIR",,g | sort >> "$FILES"
+
+cp "$LICENSE" "$PKGDIR/LICENSE"
+
+# Copy the SVG files
+echo "$SVGFILES" | xargs cp --target-directory "$PKGDIR"
+
+# Fill the README file
+README="$PKGDIR/README"
+cat >> "$README" << EOF
+
+Crystal SVG sources from KDE CVS
+
+These are the Crystal SVG vector sources from KDE CVS.
+
+LOCATION
+The "FILES" file gives information about the location they come from.
+
+Most come from: kdelibs/pics/crystalsvg You can visit this cvs directory using webcvs:
+http://webcvs.kde.org/cgi-bin/cvsweb.cgi/kdelibs/pics/crystalsvg
+Due to the naming the SVGs are at the end of the list.
+
+They are in the form of .svgz, which can be renamed to svg.gz and opened with gzip -d *.svg.gz
+
+Application icons may also be found with the application sources: /<kde_app_suite>/<kde_app_name>/pics e.g. /kdebase/konqueror/pics or /kdeedu/kmplot/pics
+
+The package_svg_files script collected the sources automatically.
+
+THE ART OF MAKING ICONS
+If you want to make Crystal Icons, take a look at the Icon Guide. Here you will find information on icon making, submitting icons to kde, technical problems with svg icons, references, software and much more.
+http://kde.ground.cz/tiki-index.php?page=Icon+Guide
+
+The smaller icons are hand-fixed after they are exported to pixels. Running the sources directly on your system will probably give poorer results than using the png version of the Crystal SVG set.
+
+The most up to date info for kde artists can be found at the wiki:
+http://kde.ground.cz/tiki-index.php?page=KDE+Artists
+
+MISSING SOURCES
+Most of the icons are made by Everaldo, initiator and visionairy of the set, while Torsten is highly productive too. Besides Everaldo and Torsten, other artists added icons to the Crystal icon set. For whatever reason, some of these sources are missing. If you ever made a Crystal SVG icon, and see the source is not in this archive, please send the vector source to: icons --at-- kde --dot-- org
+If you want feedback on an icon you made: kde-artists --at-- kde --dot-- org
+And of course, Everaldo too is interested in your Crystal icons:
+"Everaldo" <everaldo --at--everaldo --dot-- com>
+
+Suse has published some Crystal Icons raw material. See the Icon Guide for more information about this. http://kde.ground.cz/tiki-index.php?page=Icon+Guide
+
+SOFTWARE
+Many SVGs made with Illustrator will not open in Sodipodi. Karbon14 (KOffice-1.3) will open these SVG files made with AI. Sometimes it takes a while and sometimes it doesn't
+get the gradients correct. However, if you then save the file from Karbon14, it will open in Sodipodi. You may also try Sketch, renamed to Skencil.
+
+BUGLIST
+Inspired? Take a look at the buglist!
+http://bugs.kde.org/buglist.cgi?short_desc_type=allwordssubstr&short_desc=&long_desc_type=allwordssubstr&long_desc=&product=artwork&component=general&version=unspecified&bug_status=UNCONFIRMED&bug_status=NEW&bug_status=ASSIGNED&bug_status=REOPENED&bugidtype=include&bug_id=&votes=&emailassigned_to1=1&emailtype1=substring&email1=&emailassigned_to2=1&emailreporter2=1&emailcc2=1&emailtype2=substring&email2=&changedin=&chfieldfrom=&chfieldto=Now&chfieldvalue=&order=Reuse+same+sort+as+last+time&cmdtype=doit&newqueryname=
+
+LICENSE & QUESTIONS
+License: see LICENSE.crystalsvg
+Questions? Write an e-mail to kde-artists --at-- kde --dot-- org
+
+EOF
+echo "done" # Generating
+
+
+
+# Package it
+echo -n "Packaging the files..."
+
+nice -n$NICE tar --create --label 'Contains the SVG files used in KDE, extracted from the sources' \
+ --directory "$TMPDIR" --bzip2 --file "$PKGPATH/$PKGNAME".tar.bz2 "$PKGNAME" 2> /dev/null
+
+
+
+#nice -n$NICE tar --create --label 'Contains the SVG files used in KDE, extracted from the sources' \
+ #--bzip2 --file "$PKGPATH"/$(eval echo "$PKGNAME").tar.bz2 --files-from "$FILESTMP" \
+ #$LICENSE $README 2> /dev/null
+if [ $? -ne 0 ]; then
+ echo "There was an error while packaging the files. Exiting."
+ exit 1;
+fi
+echo "done" # Packaging
+
+
+
+# Clean up
+rm -rf "$TMPDIR"
+
+
+
+# All done
+echo ""
+echo "Success - the package is called "$PKGNAME", located in $PKGPATH"
+echo ""
+
+# EOF
diff --git a/scripts/png2mng.pl b/scripts/png2mng.pl
new file mode 100644
index 00000000..14ef58ae
--- /dev/null
+++ b/scripts/png2mng.pl
@@ -0,0 +1,193 @@
+#! /usr/bin/perl
+
+## This script is based on cyclo.cgi, see http://homepage2.nifty.com/sophia0/
+## cyclo.cgi v0.3c (CYCLIC IMAGE) 2001.04.15 by techan
+
+# usage: png2mng <basename> <width> <height>
+
+$basename = $ARGV[0];
+
+# Image Width Height
+@w_h = ($ARGV[1], $ARGV[2]);
+
+# The number of repeats for base (integer > 1)
+$b_repeat = 1;
+
+# Ticks per second
+$tps = 20;
+
+## Main
+
+&InitCrcTable;
+
+$r = "NG\r\n\x1a\n";
+$sig_p = "\x89P".$r;
+$sig_m = "\x8aM".$r;
+
+# Check File
+@png = ();
+$size = 1;
+for ($i=0;$size > 0;) {
+ $file = $basename.sprintf('%04d.png', $i+1);
+ $size = -s $file;
+ if ($size > 0)
+ {
+ open(IN, "< $file") || &Error(1);
+ binmode(IN);
+ read(IN, $sig, 8);
+ if ($sig ne $sig_p) { close(IN); &Error(2); }
+ read(IN, $png[$i], $size-8);
+ close(IN);
+ $i++;
+ }
+}
+$number = $i;
+$it = $number * $b_repeat;
+$ti = $it;
+
+$|=1;
+binmode(STDOUT);
+
+# Signature
+print $sig_m;
+
+# MHDR
+$data = 'MHDR'.pack("N7",
+ $w_h[0], # Width
+ $w_h[1], # Height
+ $tps, # Ticks per second
+ $number, # Layers
+ $ti, # Frames
+ $ti, # Time
+ 583); # Simplicity
+&OutputData;
+
+# DEFI define objects of the number specified by $number
+for ($i=0;$i<$number;$i++) {
+ $data = 'DEFI'.pack("n",
+ $i+1); # Object_id
+ # Do_not_show: 1 byte (unsigned integer)
+ # Concrete_flag: 1 byte (unsigned integer)
+ # X_location: 4 bytes (signed integer)
+ # Y_location: 4 bytes (signed integer)
+ # Left_cb: 4 bytes (signed integer)
+ # Right_cb: 4 bytes (signed integer)
+ # Top_cb: 4 bytes (signed integer)
+ # Bottom_cb: 4 bytes (signed integer)
+ &OutputData;
+ print $png[$i];
+}
+undef(@png);
+
+# LOOP
+$data = 'LOOP'.pack("CNC",
+ 0, # Nest_level
+ $it, # Iteration_count
+ 6); # Termination_condition:
+ # 1: Decoder discretion, not cacheable.
+ # 2: User discretion, not cacheable.
+ # *3: External signal, not cacheable.
+ # 4: Deterministic, cacheable.
+ # 5: Decoder discretion, cacheable.
+ # 6: User discretion, cacheable.
+ # *7: External signal, cacheable.
+ # Iteration_min: 4 bytes(unsigned integer)
+ # Iteration_max: 4 bytes (unsigned integer)
+ # Signal_number: 4 bytes (unsigned integer)
+ # Additional signal_number: 4 bytes (unsigned integer)
+&OutputData;
+
+# SHOW
+$data = 'SHOW'.pack("nnC",
+ 1, # First_image
+ $number, # Last_image
+ 6); # Show_mode:
+ # 0: Make the images potentially visible and display them.
+ # 1: Make the images invisible.
+ # 2: Display those that are potentially visible.
+ # 3: Mark images "potentially visible" but do not display
+ # them.
+ # 4: Display any that are potentially visible after toggling.
+ # 5: Do not display even if potentially visible after toggling.
+ # 6: Step through the images in the given range, making the
+ # next image potentially visible and display it. Jump to
+ # the beginning of the range when reaching the end of the
+ # range. Perform one step for each SHOW chunk (in reverse
+ # order if last_image < first_image).
+ # 7: Make the next image in the range (cycle) potentially
+ # visible but do not display it.
+&OutputData;
+
+# ENDL
+$data = "ENDL\0"; # Nest_level: 1 byte
+&OutputData;
+
+# MEND
+print "\0\0\0\0MEND! \xf7\xd5";
+
+exit(0);
+
+sub Error
+{
+my $e = $_[0];
+
+$black = "\0\0\0";
+$red = "\xff\0\0";
+$white = "\xff\xff\xff";
+
+if ($e == 1) { $plte = $white.$black; }
+elsif ($e == 2) { $plte = $white.$red; }
+else { $plte = $red.$white; }
+
+$plte = "PLTE".$plte;
+
+$p = $sig_p;
+$p.="\0\0\0\rIHDR";
+$p.="\0\0\0\x1e\0\0\0\x0c\x01\x03\0\0\0";
+$p.="\x4f\xe0\x9f\x71";
+$p.="\0\0\0\x06".$plte.&CalcCrc($plte);
+$p.="\0\0\0\x2eIDAT";
+$p.="\x78\x9c\x63\x60\x40\x05\xbf\xcf\xcb\x7c\x60\x68\xd2\x58\xd4\x01";
+$p.="\x21\x3e\x81\x88\xe6\xf3\x4a\x40\xb1\x2e\xa5\x05\x0c\x4d\x9e\x4a";
+$p.="\x13\x18\x7e\x69\xcc\xe9\0\xab\x05\0\xb0\x88\x10\xb8";
+$p.="\x57\x3a\0\xa1";
+$p.="\0\0\0\0IEND\xaeB`\x82";
+
+$|=1;
+# print "Content-type: $mime\n";
+# print "Content-length: 121\n\n";
+binmode(STDOUT);
+print $p;
+exit(1);
+}
+
+sub InitCrcTable
+{
+my $d;
+@crc_table = ();
+for (0 .. 255) {
+ $d = $_;
+ for (0 .. 7) {
+ if ($d & 1) { $d = 0xedb88320 ^ (($d >> 1) & 0x7fffffff); }
+ else { $d = ($d >> 1) & 0x7fffffff; }
+ }
+ $crc_table[$_] = $d;
+}
+}
+
+sub CalcCrc
+{
+my $data = $_[0];
+my $c = 0xffffffff;
+foreach (unpack("C*", $data)) {
+ $c = $crc_table[($c ^ $_) & 0xff] ^ (($c >> 8) & 0xffffff);
+}
+return(pack("N", ~$c));
+}
+
+sub OutputData
+{
+print pack("N", length($data)-4).$data.&CalcCrc($data);
+undef($data);
+}
+__END__
diff --git a/scripts/pruneemptydirs b/scripts/pruneemptydirs
new file mode 100755
index 00000000..6f177a0f
--- /dev/null
+++ b/scripts/pruneemptydirs
@@ -0,0 +1,46 @@
+#!/bin/sh
+# Cleans up a local CVS/SVN tree, by removing directories containing
+# remanants of old stuff which has been removed from CVS/SVN
+# Those stale dirs often break compilation...
+
+# Works better with srcdir!=builddir (since it will not remove directories
+# containing the old executable...)
+
+# NOTE: by default the script doesn't remove anything, just prints what to do
+# Copy and paste, or use eval in scripts.
+# Use '-f' to force it to happen (use with care, no warranties, etc.!)
+
+# David Faure <faure@kde.org>, script under public domain
+
+force=0;
+if [ "$1" = "-f" ]; then force=1; fi
+
+# Look for toplevel dirs
+files=`find . -type d | grep -v CVS\$ | grep -v admin\$ | grep -v .libs\$ | fgrep -v .svn`
+toremove="rm -rf";
+for i in $files; do if test -d $i; then
+ # List their contents and filter out generated files
+ realfiles=`find $i -type f | egrep -v '.svn|CVS/|Makefile$|Makefile.in$|Makefile.rules.in$|Makefile.calls.in$|\.o$|\.lo$|\.rpo$|\.la$|\.moc|/\.#' `
+ if [ -z "$realfiles" ]; then
+ toremove="$toremove '$i'"
+ fi
+fi; done
+
+if [ "$toremove" != "rm -rf" ]; then
+ # Do the same in the builddir, if srcdir != builddir
+ if [ -n "$OBJ_REPLACEMENT" ]; then
+ bdir=`echo $PWD | sed -e "$OBJ_REPLACEMENT"`
+ if test -d $bdir; then
+ bdcmd="( cd $bdir ; $toremove )"
+ fi
+ fi
+ # Print it or do it
+ if [ $force -eq 1 ]; then
+ eval $toremove
+ eval $bdcmd
+ else
+ echo $toremove
+ echo $bdcmd
+ fi
+fi
+
diff --git a/scripts/qtdoc b/scripts/qtdoc
new file mode 100755
index 00000000..f92345d9
--- /dev/null
+++ b/scripts/qtdoc
@@ -0,0 +1,19 @@
+#!/bin/sh
+# Run from command line, to open a qt help page in kfm/konqueror
+# No argument => main page
+# Classname (case insensitive) => page for this class
+
+if [ $# = 1 ]; then
+ fname=`echo $1 | tr '[A-Z]' '[a-z]'`
+ if [ -f $QTDIR/doc/html/$fname.html ]; then
+ kdeinit_wrapper kfmclient openProfile webbrowsing file:$QTDIR/doc/html/$fname.html
+ else
+ if [ -f /usr/doc/qt2/html/$fname.html ]; then
+ kdeinit_wrapper kfmclient openProfile webbrowsing file:/usr/doc/qt2/html/$fname.html
+ else
+ echo "No such file $fname.html"
+ fi
+ fi
+else
+ kfmclient openURL file:$QTDIR/doc/html/index.html
+fi
diff --git a/scripts/rc2kcfgxt.pl b/scripts/rc2kcfgxt.pl
new file mode 100644
index 00000000..4b015dee
--- /dev/null
+++ b/scripts/rc2kcfgxt.pl
@@ -0,0 +1,95 @@
+#! /usr/bin/env perl
+#
+# rc2kcfgxt.pl version 4 by Adriaan de Groot
+#
+# This code is released to the Public Domain.
+#
+
+#
+# Usage: rc2kcfgtxt.pl < rcfile > xmlfile
+#
+# Reads an rcfile (say, kmailrc) and writes out an KConfigXT XML
+# file that represents a reasonable guess for representing the
+# rc file. No guarantees about well-formedness of the XML are made.
+#
+
+#
+# rc2kcfgxt.pl only guesses types Bool, UInt, and IntList.
+# Everything else is a String. You may need to edit the various
+# types. As of 4-1-2003, valid types are:
+#
+# type (String|StringList|Font|Rect|Size|Color|
+# Point|Int|UInt|Bool|Double|DateTime|
+# Int64|UInt64|IntList|Enum|Path) #REQUIRED
+#
+
+$group="" ;
+$key="";
+
+print <<EOF;
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE kcfg SYSTEM "http://www.kde.org/standards/kcfg/1.0/kcfg.dtd">
+<kcfg>
+EOF
+
+while(<>)
+{
+ chomp;
+ next unless $_;
+ if (/\[([-A-Za-z 0-9]+)\]/)
+ {
+ $grp = $1;
+ print " </group>\n" if ($group && (not $group =~ /^MainWindow/));
+ $group=$grp;
+ next if ($group =~ /^MainWindow/);
+ print " <group name=\"$group\">\n";
+ next;
+ }
+
+ next if $group =~ /^MainWindow/ ;
+
+ @l = split /=/;
+ $key = shift @l;
+ $value = join "=",@l;
+ $cfgkeyexpr = "";
+
+ # Escape value values that are special to XML
+ $value =~ s/</&lt;/;
+ $value =~ s/>/&gt;/;
+ $value =~ s/"/&quot;/;
+
+ if ($key =~ /[ -,.<>;:!\]\[|}{]/)
+ {
+ $cfgkeyexpr = "key=\"$key\"";
+ @key_parts = split /[ -,.<>;:!\]\[|}{]/,$key;
+ $key = "";
+ foreach $i (@key_parts)
+ {
+ next unless $i;
+ $i =~ /([a-zA-Z0-9_])([a-zA-Z0-9_]*)/;
+ $first = $1;
+ $second = $2;
+ $first =~ tr/a-z/A-Z/;
+ $key .= $first . $second;
+ }
+ }
+
+ # Find key type
+ $type="";
+ $type="Bool" if ( $value =~ /^(true|false|TRUE|FALSE)$/);
+ $type="UInt" if ( $value =~ /^[0-9]+$/);
+ $type="IntList" if ( ( not $type ) && ( $value =~ /^[0-9,]+$/ ));
+ $type="String" unless $type;
+
+ print <<EOF;
+ <entry name="$key" $cfgkeyexpr type="$type">
+ <label>
+ </label>
+ <default>$value</default>
+ </entry>
+EOF
+}
+
+print " </group>\n" if ($group && (not $group =~ /^MainWindow/));
+
+print "\n</kcfg>\n";
diff --git a/scripts/svn-clean b/scripts/svn-clean
new file mode 100755
index 00000000..3c698bd5
--- /dev/null
+++ b/scripts/svn-clean
@@ -0,0 +1,113 @@
+#! /usr/bin/env perl
+
+#
+# This script recursively (beginning with the current directory)
+# wipes out everything not registered in SVN.
+#
+# rewritten in perl by Oswald Buddenhagen <ossi@kde.org>
+# based on bash version by Thiago Macieira <thiago@kde.org>
+# inspired by cvs-clean, written by Oswald Buddenhagen <ossi@kde.org>
+# inspired by the "old" cvs-clean target from Makefile.common
+#
+# This file is free software in terms of the BSD licence. That means
+# that you can do anything with it except removing this license or
+# the above copyright notice. There is NO WARRANTY of any kind.
+#
+
+# Warning:
+# This script processes the output from the SVN executable
+# Do not run it along with colorsvn
+
+use File::Path;
+
+my $version = "svn-clean v1.0";
+my $heading = $version.": cleans up the Subversion working directory\n";
+my $usage = $heading.
+ "svn-clean [-h] [-n] [-q] [-i|-f] [dirname]\n\n".
+ "Where:\n".
+ " -h shows this help screen\n".
+ " -n dry-run: doesn't actually erase the files, just show their names\n".
+ " -i interactive: ask for confirmation before erasing the files\n".
+ " -f force: doesn't ask for confirmation before erasing\n".
+ " -q quiet: doesn't show output\n";
+
+
+my $dry_run = 0;
+my $force = 0;
+my $quiet = 0;
+
+sub check_confirm()
+{
+ return if ($force);
+
+ open(TTY, "+< /dev/tty") or die "cannot open /dev/tty";
+
+ print TTY "This will erase files and directories that aren't in Subversion\n".
+ "Are you sure you want to continue? (y/n) ";
+
+ if (<TTY> =~ /^[Yy]/) {
+ $force = 1;
+ close TTY;
+ return;
+ }
+
+ # user cancelled
+ exit 0;
+}
+
+# Parse arguments
+my $rest = 0;
+my @files = ();
+foreach my $arg (@ARGV) {
+ if ($rest) {
+ push @files, $arg;
+ } else {
+ if ($arg eq '-h' || $arg eq '--help') {
+ print $usage;
+ exit (0);
+ } elsif ($arg eq '-n' || $arg eq '--dry-run') {
+ $dry_run = 1;
+ $force = 1;
+ } elsif ($arg eq '-f' || $arg eq '--force') {
+ $force = 1;
+ } elsif ($arg eq '-i' || $arg eq '--interactive') {
+ $force = 0;
+ } elsif ($arg eq '-q' || $arg eq '--quiet') {
+ $quiet = 1;
+ } elsif ($arg eq '--') {
+ $rest = 1;
+ } elsif ($arg =~ /^-/) {
+ print STDERR "svn-clean: unknown argument '".$arg."'\n\n".$usage;
+ exit (1);
+ } else {
+ push @files, $arg;
+ }
+ }
+}
+if (!@files) {
+ push @files, '.';
+}
+
+# Unset TERM just so that no colours are output
+# in case $SVN points to colorsvn
+delete $ENV{'TERM'};
+
+#print($heading."\n") unless $quiet;
+
+foreach my $dir (@files) {
+ open SVN, "svn status --no-ignore \"".$dir."\"|";
+ while (<SVN>) {
+ /^[I?] +(.*)$/ or next;
+ my $file = $1;
+ check_confirm();
+ lstat $file;
+ if (-d _) {
+ print("D ".$file."\n") unless $quiet;
+ rmtree($file, 0, 0) unless $dry_run;
+ } else {
+ print("F ".$file."\n") unless $quiet;
+ unlink($file) unless $dry_run;
+ }
+ }
+ close SVN;
+}
diff --git a/scripts/svn2dist b/scripts/svn2dist
new file mode 100755
index 00000000..eb7ef8d9
--- /dev/null
+++ b/scripts/svn2dist
@@ -0,0 +1,638 @@
+#! /usr/bin/env bash
+
+# This is svn2dist
+# Based on cvs2dist by <jason@katzbrown.com>.
+
+# Original author (of cvs2pack.sh) was Sebastian Stein <seb.stein@hpfsc.de>
+# Heavy, heavy modifications by Jason Katz-Brown <jason@katzbrown.com>
+# Some modifications for i18n inclusion by Dominique Devriese <devriese@kde.org>
+# Added --no-i18n-lang and --replace-files by Michael Buesch <mbuesch@freenet.de>
+# License: GPL (http://www.gnu.org/)
+# Last modification: 2005/01/08
+
+echo >&2 "Warning: this script needs more testing!"
+echo >&2 ""
+
+cmdline="$@"
+
+returndir=`pwd`
+override="README ChangeLog INSTALL AUTHORS AUTHOR COPYING COPYING.LIB TODO COPYING-DOCS"
+remove="config.cache config.log config.status Makefile configure inst-apps CVS acinclude.m4 aclocal.m4 libtool subdirs *.moc *.la .libs .deps .svn .cvsignore autom4te.cache {arch} .arch-ids *.lo *.o *.bbg *.da *.bb"
+toplevelremove="configure.in.bot config.h config.h.bot config.h.in config.status config.log stamp-h stamp-h.in stamp-h1 subdirs configure.files "
+# whitespace seperated list of languages to never include.
+always_skip_languages="xx"
+
+
+exit_cleanup()
+{
+ echo -n "Cleaning up... "
+ if [ -d $temp_dir ]; then
+ test -z "$debug" && rm -Rf $temp_dir
+ fi
+ echo "done."
+}
+
+trap "exit_cleanup; exit 1" SIGINT SIGTERM
+
+test -e ~/.svn2distrc && extraoptions=`cat ~/.svn2distrc`
+
+# getopt usage from the getopt bash example
+# --log has optional argument
+TEMP=`getopt \
+-o v:n:r:e:a:B:dhmbgol \
+--long log::,version:,name:,required-header:,required-header-error-message:,make-unpackaged,help,no-bz2,no-bzip2,no-gzip,only-directory,remove-hidden,admin-dir:,branch:,no-i18n,no-i18n-lang:,svn-root:,i18n-module:,debug,replace-files: \
+-n svn2dist -- $extraoptions "$@"`
+
+if [ $? != 0 ]; then
+ echo "Aborted." >&2
+ exit 1
+fi
+
+eval set -- "$TEMP"
+
+log="/dev/null"
+calclog=0
+doi18n="yes"
+noi18nlang=""
+replace_files=""
+i18nmodule=""
+svnroot=""
+debug=
+branch="trunk"
+version=
+
+while true; do
+ case "$1" in
+ -v|--version) version=$2; shift 2 ;;
+ -n|--name) name=$2; shift 2 ;;
+ -a|--admin-dir) admindir=$2;
+ if [ `echo $admindir | sed -e 's#^/##'` = $admindir ]; then
+ admindir="`pwd`/$admindir"
+ fi
+ shift 2 ;;
+ --debug) debug="non-empty"; shift 1 ;;
+ --svn-root) svnroot="$2"; shift 2 ;;
+ --i18n-module) i18nmodule="$2"; shift 2 ;;
+ -r|--required-header) requiredheader=$2; shift 2 ;;
+ --no-i18n) doi18n="no"; shift 1 ;;
+ --no-i18n-lang) noi18nlang="$2"; shift 2 ;;
+ -e|--required-header-error-message) requiredmsg=$2; shift 2 ;;
+ -m|--make-unpackaged) leavedir="non-empty"; shift 1 ;;
+ -h|--help) showhelp="non-empty"; shift 1 ;;
+ -b|--no-bz2|--no-bzip2) nobzip2="non-empty"; shift 1 ;;
+ -o|--only-directory)
+ nogzip="non-empty"
+ nobzip2="non-empty"
+ leavedir="non-empty"
+ shift 1 ;;
+ -g|--no-gzip) nogzip="non-empty"; shift 1 ;;
+ -d|--remove-hidden) removehidden="non-empty"; shift 1 ;;
+ -l) calclog=1; shift 1 ;;
+ --log)
+ case "$2" in
+ # no-argument case
+ "") calclog=1; shift 2 ;;
+ # something, should be a file
+ *) log=$2
+ origlog=$log
+ if [ `echo $log | sed -e 's#^/##'` = $log ]; then
+ log="`pwd`/$log"
+ fi
+
+ shift 2 ;;
+ esac ;;
+ --replace-files) replace_files="$2"; shift 2 ;;
+ --) shift
+ break ;;
+ *) echo "Aborted."
+ exit 1 ;;
+ esac
+done
+
+count=0
+for arg do
+ test $count = 0 && module=$arg
+ test $count = 1 && directory=$arg
+
+ if [ $count -ge 2 ]; then
+ modarg=$arg
+ if [ `echo $modarg | sed -e 's#^/##'` = $modarg ]; then
+ modarg="`pwd`/$modarg"
+ fi
+ addfiles="$addfiles $modarg"
+ fi
+
+ let count count++
+done
+
+# test if a module and directory name was given
+if [ ! -z $showhelp ] || [ -z $module ] || [ -z $directory ]; then
+ echo "Usage: svn2dist module directory [options] [addfile1] [addfile2] ..."
+ echo ""
+ echo " -n --name <name>"
+ echo " -v --version <version>"
+ echo " --svn-root <root> the value to use as svn root"
+ echo " variable. It is not necessary if you use --no-i18n."
+ echo " --admin-dir <dir> admin/ location (default is module/admin)"
+ echo " (symbolic links are OK.)"
+ echo " -B --branch <branch> use branch for i18n checkouts."
+ echo " --no-i18n don't try to automatically checkout the translations from svn."
+ echo " --no-i18n-lang <languages> exclude all languages in the given comma"
+ echo " seperated list. example:"
+ echo " --no-i18n-lang uk,de,en_GB"
+ echo " --i18n-module <name> i18n subdir"
+ echo " if not specified it is guessed"
+ echo " from module name by replacing \"/\" by \"-\""
+ echo " --log=<logfile> If logfile unspecified, default file is used."
+ echo " (The '=' is essential and may not be ommited"
+ echo " when specifying the logfile.)"
+ echo " -l Log to default logfile."
+ echo " -m --make-unpackaged Also makes an unpacked distribution"
+ echo " in the current directory."
+ echo " -g --no-gzip Do not create gzip package."
+ echo " -b --no-bz2 Do not create bzip2 package."
+ echo " --no-bzip2 Alias for the above."
+ echo " -o --only-directory Alias for -mbg (no packages, only a directory.)"
+ echo " -r --required-header <header> Errors if header is not installed."
+ echo " -e --required-header-error-message <message>"
+ echo " Error message for above."
+ echo " -d --remove-hidden Remove hidden files/directories from packages"
+ echo " --replace-files <file-pair-list>"
+ echo " <file-pair-list> is a comma separated list of file pairs"
+ echo " which should be replaced in the final distribution package."
+ echo " Each element of a pair is separated by an @"
+ echo -n " Example: --replace-files take_this_file@and_move_it_here,"
+ echo "configure.in.bot.dist@configure.in.bot"
+ echo " The filenames are all relative to your package root."
+ echo " Please be careful! Try to avoid the usage of .. in the path. It"
+ echo " may break stuff! There can not be blank characters in the paths."
+ echo " -h --help Show this help"
+ echo ""
+ echo " Name defaults to the last part of the directory."
+ echo "By default, creates name[-version].tar.gz if gzip is installed"
+ echo "and/or name[-version].tar.bz2 if bzip2 is installed in the current"
+ echo "directory. Removes all temporary files it creates. Produces"
+ echo "tarballs that are standard distribution tarballs with a"
+ echo "configure script."
+ echo " Unless --no-i18n is given, it automatically tries to check out "
+ echo "strings and documentation translation from svn."
+ echo " Arguments after the second are added to the toplevel directory"
+ echo "in the package. Short options can be combined, eg -dm to create"
+ echo "a directory and remove hidden files. ~/.svn2distrc is added to"
+ echo "the beginning of command line arguments if it exists."
+ echo " '--' signifies the end of options."
+ echo ""
+ echo "Example: svn2dist /sources/kdegames kolf/objects/picture \\"
+ echo " -n kolf-picture -v 0.9 -r \"kolf/game.h\" \\"
+ echo " --log ~/tmp/extra-file"
+ echo ""
+ echo " Creates packages of the kolf picture plugin, naming the"
+ echo " packages kolf-picture-0.9 and logging the process. For configure"
+ echo " to succeed, kolf/game.h must be installed or an error will occur."
+ echo " ~/tmp/extra-file is added to the packages."
+ echo ""
+ echo "Webpage: http://www.katzbrown.com/shiritsu/programming/svn2dist/"
+ echo "Authors: Jason Katz-Brown <jason@katzbrown.com>,"
+ echo " Sebastian Stein <seb.stein@hpfsc.de>,"
+ echo " Dominique Devriese <devriese@kde.org>"
+ exit 1
+fi
+
+if [ -z $i18nmodule ]; then
+ i18nmodule=`echo $module | sed -e 's#/#-##'`
+fi
+
+# expand module
+module=`echo $module | sed -e 's#/$##'`
+if [ `echo $module | sed -e 's#^/##'` = $module ]; then
+ module="`pwd`/$module"
+fi
+
+# test if the given module is a directory
+test -d $module
+if [ $? -ne 0 ]; then
+ echo "$module is not a directory."
+ echo "Aborted."
+ exit 1
+fi
+
+# go to our module
+cd $module
+
+directory=`echo $directory | sed -e 's#^/##'`
+pofiles=""
+
+for makefile in `find $directory -name Makefile.am`; do
+ cat $makefile | while read line; do echo $line; done | perl -e '$mes=0; while (<STDIN>) { if (/^messages:/) { $mes=1; next; } if ($_ !~ m/^[^\t ]/) { $mes=0; } if ($mes && /\$\(XGETTEXT\)/ && / -o/) { s,.*-o \$\(podir\)/([a-z._-]+).*$,$1, ; chomp $_; $_ =~ s/\.pot/.po/; print "pofiles=\"$_ \$pofiles\"\n" } }' > _tmppot
+ . _tmppot
+ rm -f _tmppot
+done
+
+if [ -z $name ]; then
+ name=$directory
+ # get rid of trailing slash
+ name=`echo $name | sed -e 's#/$##'`
+ # leading slash
+ name=`echo $name | sed -e 's#^/##'`
+
+ if [ `echo $name | sed -e 's#/##'` != $name ]; then
+ name=`echo $name | sed -e 's#^.*/##'`
+ fi
+fi
+
+test $calclog = 1 && log="$returndir/svn2dist-$name.log" && origlog="svn2dist-$name.log"
+
+# test if the given name is a sub-directory
+if [ ! -d "$directory" ]; then
+ echo "$directory is not a sub-directory of $module."
+ echo "Aborted."
+ exit 1
+fi
+
+test $log != "/dev/null" && echo "Logging to $log."
+
+echo "svn2dist log on "`date` > $log
+echo -n "Module: $module; Directory: $directory; Name: $name; " >> $log
+if [ -z $version ]; then
+ echo "Version unspecified." >> $log
+else
+ echo "Version $version." >> $log
+fi
+echo $cmdline >> $log
+echo "--------" >> $log
+
+if [ -z $version ]; then
+ filename=$name
+else
+ filename="$name-$version"
+ VERSION=$version
+ export VERSION
+fi
+
+if [ $doi18n = "yes" ]; then
+ # a little warning...
+ echo "Will try to fetch i18n files from KDE's SVN."
+ echo "If this doesn't work, use --no-i18n."
+
+ if [ -z "$svnroot" ]; then
+ echo "No svn root specified, and --no-i18n option is not given.." >> $log
+ echo "Using anonymous svn.." >> $log
+ svnroot="svn://anonsvn.kde.org/home/kde/trunk"
+ fi
+fi
+
+# the temporary directory
+temp_dir="$module/svn2dist-tmp"
+temp_dist="$temp_dir/$filename"
+
+echo "Temporary directory is $temp_dir." >> $log
+
+# make a temporary directory
+test -d $temp_dir && rm -Rf $temp_dir
+
+mkdir $temp_dir
+mkdir $temp_dist || (echo "failed to create $temp_dist"; exit 1; )
+
+# check if we were able to create temp_dir
+test -d $temp_dist
+if [ $? -ne 0 ]; then
+ echo "Could not create temporary directory $temp_dist."
+ echo "$temp_dist could not be created." >> $log
+ echo "Aborted."
+ exit 1
+fi
+
+test -z "$requiredmsg" && requiredmsg="Install development package needed first! $requiredheader, for one, is missing."
+
+### configure.in.in
+if [ ! -z $requiredheader ]; then
+ naiyou="KDE_CHECK_HEADER(
+$requiredheader,
+[],
+[AC_MSG_ERROR(\"$requiredmsg\")]
+)"
+ echo $naiyou > $temp_dir/configure.in.in
+ echo "configure.in.in contents: " >> $log
+ echo "--------" >> $log
+ echo $naiyou >> $log
+ appaddfiles="$appaddfiles $temp_dir/configure.in.in"
+fi
+
+# copy all files of the module to temp_dir/name
+cp -RL $module/$directory $temp_dist/$name
+
+echo "cp -R $module/$directory $temp_dist/$name" >> $log
+
+modulename="$module"
+# get rid of trailing slash
+modulename=`echo $modulename | sed -e 's#/$##'`
+# get the last part
+modulename=`echo $modulename | sed -e 's#^.*/##'`
+
+remove="$remove $modulename.lsm"
+
+# we check out kde-i18n/subdirs in temp_dir/kde-i18n..
+if [ $doi18n = "yes" ]; then
+ pushd $temp_dir
+ echo "Getting i18n subdirs" >> $log
+ i18nlangs_tmp=`svn cat "$svnroot/l10n-kde3/subdirs"`
+ skiplist="`echo $noi18nlang | sed -e 's/,/ /g'`"
+ skiplist="$skiplist $always_skip_languages"
+ for lang in $i18nlangs_tmp; do
+ must_skip="no"
+ for skip in $skiplist; do
+ if [ "$lang" = "$skip" ]; then
+ must_skip="yes"
+ fi
+ done
+ if [ "$must_skip" = "no" ]; then
+ i18nlangs="$i18nlangs $lang"
+ fi
+ done
+ echo "available languages: $i18nlangs (Pofiles to fetch: $pofiles)" >> $log
+ popd
+fi
+
+# if a handbook exists, we also copy it to the directory
+if [ -d $module/doc/$name ]; then
+ mkdir -p $temp_dist/doc/$name
+ cp -Rf $module/doc/$name $temp_dist/doc
+ find $module/doc/ -maxdepth 1 ! -xtype d | xargs --replace={} cp {} $temp_dist/doc
+
+ if [ $doi18n = "yes" ]; then
+ pushd $temp_dir
+ for lang in $i18nlangs; do
+ echo -n "Checking for $lang/$name... "
+ test -d $temp_dist/doc/$lang && rm -Rf $temp_dist/doc/$lang
+ docdirname="l10n-kde3/$lang/docs/$i18nmodule/$name"
+ echo "svn export $svnroot/$docdirname $temp_dist/doc/$lang" >> $log
+ mkdir -p $temp_dist/doc
+ svn export "$svnroot/$docdirname" $temp_dist/doc/$lang >> $log 2>&1
+ if [ ! -d "$temp_dist/doc/$lang" ]; then
+ echo "$lang's $name documentation does not exist." >> $log
+ echo "does not exist"
+ continue
+ fi
+ echo "KDE_LANG = $lang
+KDE_DOCS = $name" > $temp_dist/doc/$lang/Makefile.am
+
+ echo "done."
+ echo "$lang documentation included." >> $log
+ done
+ popd
+ fi
+fi
+
+# clean up doc directory
+if [ -d $temp_dist/doc/$name ]; then
+ pushd $temp_dist/doc/$name
+ echo -n "make clean in $temp_dist/doc/$name/... "
+ echo >> $log
+ echo "make clean in $temp_dist/doc/$name/" >> $log
+ make clean >> $log
+ echo "--------" >> $log
+ echo "done."
+ popd
+fi
+
+if [ $doi18n = "yes" ]; then
+ test -d $temp_dist/po && rm -Rf $temp_dist/po
+ mkdir $temp_dist/po
+ pushd $temp_dir
+
+ for pofile in $pofiles; do
+ echo "Getting translations for $pofile from i18n..."
+
+ for lang in $i18nlangs; do
+ pofilename="l10n-kde3/$lang/messages/$i18nmodule/$pofile";
+ echo "Getting $pofilename" >> $log
+ svn cat "$svnroot/$pofilename" >$pofile 2>&1 || rm -f $pofile
+ if [ ! -f "$pofile" ]; then
+ echo "$lang's $pofile does not exist." >> $log
+ continue
+ fi
+
+ dest=$temp_dist/po/$lang
+ mkdir -p $dest
+ echo -n "Copying $lang's $pofile over... "
+ echo "$lang's $pofile file included." >> $log
+ mv $pofile $dest
+ echo "done."
+
+ echo "KDE_LANG = $lang
+SUBDIRS = \$(AUTODIRS)
+POFILES = AUTO" > $dest/Makefile.am
+
+ subdirs="non_empty"
+ done
+ done
+
+ popd
+ if [ -z "$subdirs" ]; then
+ rm -Rf $temp_dist/po
+ else
+ echo "SUBDIRS = \$(AUTODIRS)" > $temp_dist/po/Makefile.am
+ fi
+fi
+
+# copy the admin directory
+if [ -z $admindir ]; then
+ cp -pRL $module/admin $temp_dist
+ echo "cp -pRL $module/admin $temp_dist" >> $log
+else
+ cp -pRL $admindir $temp_dist
+ echo "cp -pRL $admindir $temp_dist" >> $log
+fi
+
+# and all files from the base dir, except directories
+echo "Copying over files from the module directory:" >> $log
+find $module -maxdepth 1 ! -xtype d | xargs --verbose --replace={} cp {} $temp_dist 2>> $log
+echo "--------" >> $log
+
+# we now enter the temp_dist and delete all unwanted files
+# and add wanted files
+cd $temp_dist
+
+# override top-level files
+echo "Override files: " >> $log
+for file in $override; do
+ test -e $temp_dist/$name/$file && mv $temp_dist/$name/$file . && echo "mv $temp_dist/$name/$file ." >> $log
+done
+
+test ! -z "$addfiles" && echo "Addfiles: " >> $log
+for file in $addfiles; do
+ test -e $file && cp -R $file $temp_dist && echo "cp -R $file $temp_dist" >> $log
+done
+
+test ! -z "$appaddfiles" && echo "Application addfiles: " >> $log
+for file in $appaddfiles; do
+ test -e $file && cp -R $file $temp_dist/$name/ && echo "cp -R $file $temp_dist/$name/" >> $log
+done
+
+echo "--------" >> $log
+
+# replace all user requested files
+if [ -n "$replace_files" ]; then
+ echo "Replace user requested files" >> $log
+ pair_list="`echo $replace_files | sed -e 's/,/ /g'`"
+ for pair in $pair_list; do
+ pair_tmp="`echo $pair | sed -e 's/@/ /g'`"
+ from="`echo $pair_tmp | awk '//{print $1}'`"
+ to="`echo $pair_tmp | awk '//{print $2}'`"
+ if [ -z "$from" ] || [ -z "$to" ]; then
+ echo "bogus pair \"$from@$to\"" >> $log
+ continue
+ fi
+ echo "Replacing \"$to\" by \"$from\"" >> $log
+ from_path="$temp_dist/$name/$from"
+ to_path="$temp_dist/$name/$to"
+ if [ ! -f "$from_path" ]; then
+ echo "$from_path does not exist!" >> $log
+ echo ""
+ echo "Warning: \"$from\" does not exist!"
+ echo -n "Please enter the path in --replace-files relative "
+ echo "to the package root of your project."
+ echo "Your package root is: \"$module/$directory\""
+ echo ""
+ continue
+ fi
+ rm -f "$to_path" && \
+ mv "$from_path" "$to_path"
+ if [ $? -ne 0 ]; then
+ echo -n "Moving \"$from_path\" failed! " >> $log
+ echo -n "This should not happen." >> $log
+ if [ -f "$to_path" ]; then
+ echo ""
+ else
+ echo " No \"$to\" will exist in the archive!" >> $log
+ fi
+ fi
+ done
+ echo "--------" >> $log
+fi
+
+# version file, if it doesn't exist
+test ! -z $version && test ! -e VERSION && echo "$name version $version" > VERSION
+
+cd $temp_dist/$name
+echo "make clean in $temp_dist/$name/:" >> $log
+echo "" >> $log
+echo -n "make clean in $temp_dist/$name/... "
+make clean >> $log
+echo "--------" >> $log
+echo "done."
+
+cd $temp_dist
+
+# remove files
+echo "Remove files: " >> $log
+for file in $remove; do
+ find . -name $file | xargs rm -Rf
+ echo "find . -name $file | xargs rm -Rf" >> $log
+done
+
+# remove more files
+echo "Remove toplevel files: " >> $log
+for file in $toplevelremove; do
+ test -e $file && rm -Rf $file && echo "rm -Rf $file" >> $log
+done
+unset file
+
+# remove hidden files
+test ! -z $removehidden && echo "Remove hidden files: " >> $log && find $temp_dist -name ".*" -and ! -name "." | xargs --verbose rm -Rf 2>> $log
+
+echo "--------" >> $log
+
+cd $temp_dist
+
+# create the configure script
+# working directory is $temp_dist
+export UNSERMAKE=no
+echo "make -f Makefile.cvs in $temp_dist/:" >> $log
+echo "" >> $log
+echo -n "make -f Makefile.cvs in $temp_dist/... "
+make -f Makefile.cvs >> $log 2>> $log
+echo "rm Makefile.cvs" >> $log
+rm -f Makefile.cvs
+echo "rm autom4te.cache" >> $log
+rm -Rf autom4te.cache
+echo "--------" >> $log
+echo "done."
+
+echo "Directory will be $filename."
+
+# play around with our tar file in temp_dir
+cd $temp_dir
+
+if [ ! -z $leavedir ]; then
+ test -e $returndir/$filename && rm -Rf $returndir/$filename
+ cp -R $filename $returndir
+fi
+
+# make a tar of temp_dist
+if [ -z $nogzip ] || [ -z $nobzip2 ]; then
+ echo -n "Tarring... "
+ echo "tar cf $filename.tar $filename" >> $log
+ tar cf $filename.tar $filename >> $log
+ echo "done."
+fi
+
+if [ -z $nogzip ] && [ ! -z `which gzip 2> /dev/null` ]; then
+ cp $filename.tar $filename.tar.tmp
+ echo -n "running gzip... "
+ echo "gzip $filename.tar" >> $log
+ gzip $filename.tar
+ echo "done."
+ mv $filename.tar.tmp $filename.tar
+ mv $filename.tar.gz $returndir
+ echo "mv $filename.tar.gz $returndir" >> $log
+fi
+if [ -z $nobzip2 ] && [ ! -z `which bzip2 2> /dev/null` ]; then
+ echo -n "running bzip2... "
+ echo "bzip2 $filename.tar" >> $log
+ bzip2 $filename.tar
+ echo "done."
+ mv $filename.tar.bz2 $returndir
+ echo "mv $filename.tar.bz2 $returndir" >> $log
+fi
+
+test -e $filename.tar && rm -f $filename.tar
+
+# cleanup all tempoaries
+exit_cleanup
+
+cd $returndir
+
+test -z $leavedir && test ! -z $nobzip2 && test ! -z $nogzip && echo "Finished - no created files." && exit 1
+
+# cool, everything went ok!
+if [ -z $leavedir ]; then
+ echo "Finished. Created packages:"
+else
+ if [ -z $nogzip ] || [ -z $nobzip2 ]; then
+ echo "Finished. Created packages/directories:"
+ else
+ echo "Finished. Created directory:"
+ fi
+fi
+
+echo "--------" >> $log
+echo "Done: " >> $log
+echo "Files are in `pwd`." >> $log
+
+if [ ! -z $leavedir ] && [ -d $filename ]; then
+ ls -ld $filename
+ ls -ld $filename >> $log
+fi
+if [ -z $nogzip ] && [ -e $filename.tar.gz ]; then
+ ls -l $filename.tar.gz
+ ls -l $filename.tar.gz >> $log
+fi
+if [ -z $nobzip2 ] && [ -e $filename.tar.bz2 ]; then
+ ls -l $filename.tar.bz2
+ ls -l $filename.tar.bz2 >> $log
+fi
+if [ $log != "/dev/null" ]; then
+ echo "Created log:"
+ ls -l $origlog
+fi
diff --git a/scripts/svnaddcurrentdir b/scripts/svnaddcurrentdir
new file mode 100755
index 00000000..2474bb01
--- /dev/null
+++ b/scripts/svnaddcurrentdir
@@ -0,0 +1,30 @@
+#!/bin/sh
+#Alexander Neundorf <neundorf@kde.org>
+#copyright 2002, GPL
+
+#call this script to add all files in and below the current dir to SVN
+#it adds *.c, *.h, *.C, *.cpp, *.cc automatically
+#*~, *.o, *.so, *.lo, *.la, .libs/, .deps/, .#* are ignored
+#it asks for the remaining files
+
+
+#ignore dirs "CVS", ".deps", ".libs" ".svn"
+#ignore files *.o, *.so, *.lo, *.la, *~, .#*
+FOUND=`find |grep -v "^\.$"| grep -v CVS| grep -v "\.[ls]\?o$"|grep -v "~$"|grep -v "\.libs/"|grep -v "\.deps/" |grep -v "\.svn/" |grep -v "\.depend/"| grep -v "/\.#" |grep -v "\.la$"`
+#echo $FOUND
+
+ask_for_adding() {
+echo
+read -p "Add file $file to SVN ? (y/n) " answer rest
+#if [ "$answer" != "y" ]; then echo $file; fi
+if [ "$answer" == "y" ]; then svn add $file; fi
+}
+
+
+for file in $FOUND
+do
+#matches all *.h, *.c, *.cpp, *.C, *.cpp, *.cc (and some others too)
+ echo $file | grep "\.[cCh][cp]\?p\?$" && svn add $file
+ echo $file | grep -v "\.[cCh][cp]\?p\?$" && ask_for_adding
+done
+
diff --git a/scripts/svnbackport b/scripts/svnbackport
new file mode 100755
index 00000000..cdecdcb4
--- /dev/null
+++ b/scripts/svnbackport
@@ -0,0 +1,64 @@
+#!/bin/sh
+# Backport the last change in HEAD, to a branch.
+# Usage: svnbackport <files>
+# WARNING: the branch tag is hardcoded into the script, make sure to check it!
+#
+# This is a port of the "cvsbackport" script:
+# Initial author: Dirk Mueller
+# Support for multiple command-line arguments: David Faure
+# Ported to SVN: Till Gerken
+# Help message: Thomas Zander
+#
+# It is a straight port and not very sophisticated. It might break. I hope
+# that someone else with more knowledge about Subversion will pick it up.
+# It needs to be used from within the repository so that it can guess
+# the remote URL correctly.
+#
+
+#REPOSITORY=https://svn.kde.org/home/kde
+
+if test -z "$1" -o "$1" = "-h" -o "$1" = "--help"; then
+ echo "Usage: svnbackport recentlyCommittedFile";
+ exit;
+fi
+
+BRANCH=3.5
+
+SRC_REMOTE=`svn info | grep URL: | cut -c6-`
+TARGET_REMOTE=`echo $SRC_REMOTE | sed "s|trunk/KDE|branches/KDE/$BRANCH|"`
+
+
+echo "Backporting to $BRANCH"
+TMPFILE=`mktemp svnbackport.XXXXXX` || exit 1
+files=$*
+until test $# -eq 0; do
+
+ echo "looking for last change to $1..."
+ svnlastchange $1 > $TMPFILE
+ echo "browsing last change to $1..."
+ less $TMPFILE
+
+ FILE_PATH=$1
+ FROM_URL=$SRC_REMOTE/$1
+ TO_URL=$TARGET_REMOTE/$1
+
+ echo "switching to branch..."
+ svn switch $TO_URL $FILE_PATH
+ patch $FILE_PATH $TMPFILE
+ rm -f $TMPFILE
+ echo "showing diff for $1..."
+ svn diff $FILE_PATH | less
+
+ shift
+done
+
+kdialog --yesno "Do you want to commit all changes?"
+if [ $? = 0 ]; then
+ svn ci $files
+fi
+
+echo "switching back to trunk..."
+for file in $files
+do
+ svn switch $SRC_REMOTE/$file $file
+done
diff --git a/scripts/svnchangesince b/scripts/svnchangesince
new file mode 100755
index 00000000..eec267e5
--- /dev/null
+++ b/scripts/svnchangesince
@@ -0,0 +1,63 @@
+#!/bin/sh
+#
+# Written by Thiago Macieira <thiago@kde.org>
+# This file is in the public domain.
+#
+# Shows the changes to the subversion repository since the local copy
+# was last updated.
+#
+
+showdiff=false
+showlog=true
+
+while test $# -ge 1; do
+ case "$1" in
+ -d)
+ showdiff=true
+ shift
+ ;;
+
+ -D)
+ showdiff=false
+ shift
+ ;;
+
+ -l)
+ showlog=true
+ shift
+ ;;
+
+ -L)
+ showlog=false
+ shift
+ ;;
+
+ -h)
+ cat <<EOF
+svnchangesince - Shows the changes to the SVN repository since the last update
+Usage:
+ svnchangesince [-d|-D] [-l|-L] [-h] [filenames]
+
+where:
+ -d include diffs in output
+ -D don't include diffs in output [default]
+ -l include logs in output [default]
+ -L don't include logs in output
+ -h show this help string
+EOF
+ exit 0
+ ;;
+
+ *)
+ break
+ ;;
+ esac
+done
+
+if $showlog; then
+ svn log -v -r HEAD:BASE "$@"
+fi
+
+if $showdiff; then
+ svn diff -r BASE:HEAD "$@"
+fi
diff --git a/scripts/svnforwardport b/scripts/svnforwardport
new file mode 100755
index 00000000..0e1ba917
--- /dev/null
+++ b/scripts/svnforwardport
@@ -0,0 +1,64 @@
+#!/bin/sh
+# Backport the last change in HEAD, to a branch.
+# Usage: svnforwardport <files>
+# WARNING: the branch tag is hardcoded into the script, make sure to check it!
+#
+# This is a port of the "cvsbackport" script:
+# Initial author: Dirk Mueller
+# Support for multiple command-line arguments: David Faure
+# Ported to SVN: Till Gerken
+# Help message: Thomas Zander
+#
+# It is a straight port and not very sophisticated. It might break. I hope
+# that someone else with more knowledge about Subversion will pick it up.
+# It needs to be used from within the repository so that it can guess
+# the remote URL correctly.
+#
+
+#REPOSITORY=https://svn.kde.org/home/kde
+
+if test -z "$1" -o "$1" = "-h" -o "$1" = "--help"; then
+ echo "Usage: svnforwardport recentlyCommittedFile";
+ exit;
+fi
+
+BRANCH=3.5
+
+SRC_REMOTE=`svn info | grep URL: | cut -c6-`
+TARGET_REMOTE=`echo $SRC_REMOTE | sed "s|branches/KDE/$BRANCH|trunk/KDE|"`
+
+
+echo "Forward porting from $BRANCH to trunk"
+TMPFILE=`mktemp svnforport.XXXXXX` || exit 1
+files=$*
+until test $# -eq 0; do
+
+ echo "Looking for last change to $1..."
+ svnlastchange $1 > $TMPFILE
+ echo "Browsing last change to $1..."
+ less $TMPFILE
+
+ FILE_PATH=$1
+ FROM_URL=$SRC_REMOTE/$1
+ TO_URL=$TARGET_REMOTE/$1
+
+ echo "Switching to trunk..."
+ svn switch $TO_URL $FILE_PATH
+ patch $FILE_PATH $TMPFILE
+ rm -f $TMPFILE
+ echo "Showing diff for $1..."
+ svn diff $FILE_PATH | less
+
+ shift
+done
+
+kdialog --yesno "Do you want to commit all changes?"
+if [ $? = 0 ]; then
+ svn ci $files
+fi
+
+echo "Switching back to branch..."
+for file in $files
+do
+ svn switch $SRC_REMOTE/$file $file
+done
diff --git a/scripts/svngettags b/scripts/svngettags
new file mode 100755
index 00000000..cd658f7c
--- /dev/null
+++ b/scripts/svngettags
@@ -0,0 +1,3 @@
+#!/bin/sh
+echo "There is no equivalent to cvsgettags for Subversion"
+exit 1
diff --git a/scripts/svnlastchange b/scripts/svnlastchange
new file mode 100755
index 00000000..c9c271ea
--- /dev/null
+++ b/scripts/svnlastchange
@@ -0,0 +1,172 @@
+#!/usr/bin/env perl
+#
+# This file is Copyright (C) 2005 Thiago Macieira <thiago@kde.org>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; version 2 of the License as published
+# by the Free Software Foundation.
+#
+# 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, write to the Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+# =====================================================================
+# This is a replacement for the old svnlastchange script, with a bit
+# more of functionality.
+#
+# The old one was:
+# svn log -r COMMITTED "$*"
+# svn diff -r PREV:COMMITTED "$*" || \
+# echo >&2 "Error retrieving diff: the file was probably added in the last revision"
+#
+# =====================================================================
+
+# Turn on warnings the best way depending on the Perl version.
+BEGIN {
+ if ( $] >= 5.006_000)
+ { require warnings; import warnings; }
+ else
+ { $^W = 1; }
+}
+use strict;
+
+#
+# Read the parameters
+#
+my @files;
+my $rev;
+my $special = 0;
+my $onlyrev = 0;
+my $onlylog = 0;
+while (@ARGV)
+ {
+ my $arg = shift @ARGV;
+ if ($arg eq '-h')
+ {
+ &usage;
+ exit 0;
+ }
+ elsif ($arg =~ /^-r(.*)$/)
+ {
+ $rev = $1;
+ if (length($1) == 0)
+ {
+ $rev = shift @ARGV;
+ }
+ $special = 1 if ($rev =~ /^-/);
+ }
+ elsif ($arg eq '-R')
+ {
+ $onlyrev = 1;
+ $special = 1;
+ $rev = -1 unless $rev;
+ }
+ elsif ($arg eq '-l')
+ {
+ $onlylog = 1;
+ }
+ else
+ {
+ push(@files, $arg);
+ }
+ }
+@files = ('.') unless @files;
+
+if (!$special)
+ {
+ my $prev;
+ if ($rev)
+ {
+ $prev = $rev - 1;
+ }
+ else
+ {
+ $rev = 'COMMITTED';
+ $prev = 'PREV';
+ }
+
+ system('svn', 'log', '-r', $rev, @files);
+ system('svn', 'diff', '-r', "$prev:$rev", @files) unless $onlylog;
+ exit $?;
+ }
+
+#
+# Special operation
+# Retrieve the full log in order to find the right version
+#
+foreach my $file (@files)
+ {
+ my $pid = open(LOG, '-|');
+ die "svnlastchange: cannot fork: $!\n" unless (defined $pid);
+ unless ($pid)
+ {
+ open(STDERR, ">&STDOUT")
+ or die "svnlastchange: cannot dup STDOUT: $!\n";
+ exec('svn', 'log', $file)
+ or die "svnlastchange: cannot exec svn: $!\n";
+ }
+
+ my $is_header = 0;
+ while (<LOG>)
+ {
+ s/[\r\n]+$//;
+
+ if ($is_header && /^r(\d+) \| /)
+ {
+ $rev = $rev + 1;
+ if ($rev == 0)
+ {
+ if ($onlyrev)
+ {
+ print "$1\n";
+ }
+ else
+ {
+ system('svn', 'log', '-r', $1, $file);
+ system('svn', 'diff', '-r', ($1 - 1) . ":$1", $file)
+ unless $onlylog;
+ }
+ last;
+ }
+ }
+
+ if ($_ eq '------------------------------------------------------------------------')
+ {
+ $is_header = 1;
+ }
+ else
+ {
+ $is_header = 0;
+ }
+ }
+ close(LOG);
+ exit $? if $?;
+ }
+
+sub usage
+{
+ print "svnlastchange [-hlR] [-r rev] [filename...]\n";
+ print "\n";
+ print "Where:\n";
+ print " -h shows this help screen\n";
+ print " -l shows the commit log only\n";
+ print " -R prints the revision number only (to be used with -r)\n";
+ print " -r rev shows the commit log for revision 'rev'\n";
+ print " if rev is negative, the 'rev'nth revision before the current\n";
+ print " one is shown\n";
+ print "\n";
+ print "Examples:\n";
+ print " svnlastchange . shows the last change to the current directory\n";
+ print " svnlastchange -r -2 shows the change before the last\n";
+ print " svnlastchange -R -r -1 shows the last change's revision\n";
+
+ exit 0;
+}
+
+
diff --git a/scripts/svnlastlog b/scripts/svnlastlog
new file mode 100755
index 00000000..d812b13b
--- /dev/null
+++ b/scripts/svnlastlog
@@ -0,0 +1,4 @@
+#!/bin/sh
+# This is a stripped down version of svnlastchange
+
+svnlastchange -l "$@"
diff --git a/scripts/svnrevertlast b/scripts/svnrevertlast
new file mode 100755
index 00000000..e98a2e53
--- /dev/null
+++ b/scripts/svnrevertlast
@@ -0,0 +1,9 @@
+#!/bin/sh
+
+surl=$PWD
+for i in $@ ;
+do
+ cd $surl/`dirname $i`
+ svn merge -r BASE:PREV `basename $i`
+done
+
diff --git a/scripts/svnversions b/scripts/svnversions
new file mode 100755
index 00000000..fbdca03b
--- /dev/null
+++ b/scripts/svnversions
@@ -0,0 +1,51 @@
+#! /usr/bin/env bash
+unset LANG LC_ALL
+LC_ALL=C
+export LC_ALL
+
+if [ $# -eq 1 ]; then
+ svn info $1 | awk '/^Last Changed Rev/ { print $4 }'
+else
+ for f; do
+ svn info $f | awk "/^Last Changed Rev/ { print \"$f\", \$4 }"
+ done
+fi
+
+exit
+
+=head1 NAME
+
+svnversions -- Displays version of the files passed as argument.
+
+=head1 SYNOPSIS
+
+ svnversions <file1> [<file2> [...]]
+
+=head1 DESCRIPTION
+
+svnversions displays the last revision a file in Subversion was
+changed, as known by the local checked out directory. No connection is
+required to the Subversion server. It is equivalent to the "COMMITTED"
+revision name.
+
+Unlike svnversion(1), this program returns the revision a file was
+modified. svnversion(1) tells the revision a working dir is at.
+
+It can be used in other scripts, or simply to ask for diffs using
+
+svn diff -r [<version>:]<version> <file(s)>
+
+=head1 AUTHOR
+
+Thiago Macieira <thiago@kde.org>
+
+Inspired on cvsversion, written by
+David Faure <faure@kde.org>
+
+=head1 SEE ALSO
+
+This command parses the output from 'svn info'.
+
+ svn(1), svnversion(1)
+
+=cut
diff --git a/scripts/zonetab2pot.py b/scripts/zonetab2pot.py
new file mode 100755
index 00000000..2549e8e6
--- /dev/null
+++ b/scripts/zonetab2pot.py
@@ -0,0 +1,24 @@
+#!/usr/bin/env python
+'''This script reads timezone list as its first argument
+or from /usr/share/zoneinfo/zone.tab, and converts it
+to a PO file template.
+
+This is free software, released under GPL.
+Author: Lukas Tinkl <lukas@kde.org>, 2002
+'''
+
+import sys
+import fileinput
+import string
+
+def makePOT(_file):
+ for line in fileinput.input(_file):
+ if (line[0]=='#'): #skip comments
+ continue
+ section=string.split(string.strip(line), '\t')[2] #third field, tab separated
+ newline='msgid \"' + section+ '\"\n' #msgid
+ newline+='msgstr \"\"\n' #msgstr
+ print(newline) #output to stdout
+
+if __name__ == '__main__':
+ makePOT(sys.argv[1:] or "/usr/share/zoneinfo/zone.tab")
diff --git a/umbrello/AUTHORS b/umbrello/AUTHORS
new file mode 100644
index 00000000..7bcc789c
--- /dev/null
+++ b/umbrello/AUTHORS
@@ -0,0 +1,14 @@
+Original author: Paul Hensgen <phensgen@sourceforge.net>
+
+Maintainer: Jonathan Riddell <jr @jriddell.org>
+
+Main Devs, in roughly chronological order
+
+* Jonathan Riddell (many areas)
+* Sebastian Stein (many areas)
+* Luis de la Parra Blum (various widgets & visuals)
+* Andrew Sutton (umbrello2)
+* Brian Thomas (advanced code generators, associations, various)
+* Oliver Kellogg (many areas)
+* Daniel Calviño Sánchez (refactoring, UI behavior)
+* Achim Spangler (countless bugfixes)
diff --git a/umbrello/COPYING b/umbrello/COPYING
new file mode 100644
index 00000000..0fc8a215
--- /dev/null
+++ b/umbrello/COPYING
@@ -0,0 +1,340 @@
+ GNU GENERAL PUBLIC LICENSE
+ Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+ 51 Franklin Steet, Fifth Floor, Boston, MA 02110-1301 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users. This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it. (Some other Free Software Foundation software is covered by
+the GNU Library General Public License instead.) You can apply it to
+your programs, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+ To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have. You must make sure that they, too, receive or can get the
+source code. And you must show them these terms so they know their
+rights.
+
+ We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+ Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software. If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+ Finally, any free program is threatened constantly by software
+patents. We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary. To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ GNU GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License. The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language. (Hereinafter, translation is included without limitation in
+the term "modification".) Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+ 1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+ 2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) You must cause the modified files to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ b) You must cause any work that you distribute or publish, that in
+ whole or in part contains or is derived from the Program or any
+ part thereof, to be licensed as a whole at no charge to all third
+ parties under the terms of this License.
+
+ c) If the modified program normally reads commands interactively
+ when run, you must cause it, when started running for such
+ interactive use in the most ordinary way, to print or display an
+ announcement including an appropriate copyright notice and a
+ notice that there is no warranty (or else, saying that you provide
+ a warranty) and that users may redistribute the program under
+ these conditions, and telling the user how to view a copy of this
+ License. (Exception: if the Program itself is interactive but
+ does not normally print such an announcement, your work based on
+ the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+ a) Accompany it with the complete corresponding machine-readable
+ source code, which must be distributed under the terms of Sections
+ 1 and 2 above on a medium customarily used for software interchange; or,
+
+ b) Accompany it with a written offer, valid for at least three
+ years, to give any third party, for a charge no more than your
+ cost of physically performing source distribution, a complete
+ machine-readable copy of the corresponding source code, to be
+ distributed under the terms of Sections 1 and 2 above on a medium
+ customarily used for software interchange; or,
+
+ c) Accompany it with the information you received as to the offer
+ to distribute corresponding source code. (This alternative is
+ allowed only for noncommercial distribution and only if you
+ received the program in object code or executable form with such
+ an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it. For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable. However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License. Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+ 5. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Program or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+ 6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+ 7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all. For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+ 8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded. In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+ 9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time. Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation. If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+ 10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission. For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this. Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+ NO WARRANTY
+
+ 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+ 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+ END OF TERMS AND CONDITIONS
+
+ How to Apply These Terms to Your New Programs
+
+ If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+ To do so, attach the following notices to the program. It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the program's name and a brief idea of what it does.>
+ Copyright (C) <year> <name of author>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the 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, write to the Free Software
+ Foundation, Inc., 51 Franklin Steet, Fifth Floor, Boston, MA 02110-1301 USA
+
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+ Gnomovision version 69, Copyright (C) year name of author
+ Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+ This is free software, and you are welcome to redistribute it
+ under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License. Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary. Here is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+ `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+ <signature of Ty Coon>, 1 April 1989
+ Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs. If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library. If this is what you want to do, use the GNU Library General
+Public License instead of this License.
diff --git a/umbrello/ChangeLog b/umbrello/ChangeLog
new file mode 100644
index 00000000..5b3b6fe6
--- /dev/null
+++ b/umbrello/ChangeLog
@@ -0,0 +1,644 @@
+Version 1.5.8
+
+* Bugs/wishes from http://bugs.kde.org:
+* Cannot move text and label correctly after enabling snap to grid (137041)
+* Umbrello gratuitously appends ".xmi" to the saved file name (146061)
+* Wrong pascal code generation (146676)
+* Crash when linking to undefined xmi.id (146748)
+* End Activity Symbol gets invalid when line thickness is increased (146925)
+* The size of a fork/join is not restored (147069)
+* Crash when changing the association type to containment (147202)
+* Moving component on diagram results in absurd shape of self-association (147810)
+* Crash when changing the attribute name (147919)
+* Reads XMI exported by version 1.5 but crashes when rereading after saving (147988)
+* Patch: Correct C# constructors (no return type) (150988)
+
+Version 1.5.71
+
+* Bugs/wishes from http://bugs.kde.org:
+* Preprocessor keywords ignored which causes endless loop in code import (119125)
+* Code generator for D language (124805)
+* Unstable saves and loads, class names become dirty (145709)
+* Crash on deleting class in list view (145762)
+* Class attribute documentation not generated for python (145916)
+* Python code generator does not wrap lines properly (145918)
+* Attribute documentation not generated for 'Export to XHTML' (145972)
+* Crash when moving a class in a Java UML diagram (146058)
+* Arrowheads are not shown (146064)
+* Crash when creating a class that refers to more than one other classes/datatypes (146367)
+
+Version 1.5.7
+
+* Bugs/wishes from http://bugs.kde.org:
+* C# Code Generation and export (53368)
+* Java interface inheritance, abstract classes and generics in code generation (53376)
+* Code generation ignores unidirectional association (72042)
+* Design bug in advanced code generators (84739)
+* %date% and %time% not being parsed (96612)
+* Operations of the Interface are not implemented in the class automatically (111593)
+* Relationships for entities do not live outside of the diagram (125146)
+* Multiplicity labels often are placed incorrectly (127628)
+* Association role labels are duplicated (130172)
+* Crash on adding operation to class with Advanced Code Generators enabled (131528)
+* Javascript wrong Code Generation (135527)
+* Javascript/ActionScript Code Generation creates bad format methods (135540, 144738)
+* Sequence diagram object size incorrect after toggling "Draw as Actor" (136869)
+* Incorrect Association Properties text (139872)
+* Buttons are not displayed (139913)
+* Impossible to reuse same use case in a use case diagram (140150)
+* Java 5 generics support (140669)
+* Associations not updated during move of class on diagram (140709)
+* Crash when deleting the link between a package and a class (141602)
+* Ada95 Code Generation Errors for Aggregation (141644)
+* Unable to delete multiplicity information or label from an association (141813)
+* Reinstate code generation options for C++ (141875)
+* C++ code generator does not correctly define namespaces (141876)
+* Ada code generator generates "withs" in both directions for certain associations (141956)
+* Ada code generator always generates methods abstract even if abstract box not checked (142093)
+* Missing "with" on Ada code generation for aggregation (142392)
+* Operation Properties "Type" combo box too small (143319)
+* Support duplication of diagrams (139856, 143581)
+* Crash on changing multiplicity in an association in ERD (143909)
+* Class diagram in folder not loaded correctly from xmi (144119)
+* Sequence diagram crashes during message inserting (144293)
+* No synchronisation of comments when round-tripping (144346)
+* Crash when loading xmi with actor as object of sequence diagram (144442)
+* ActionScript/JavaScript association code generation error (144788)
+* Segmentation fault on loading corrupted file (145035)
+* Crash when moving all elements in a sequence diagram (145202)
+
+Version 1.5.61
+
+* Copy/paste of attribute or operation in list view within same class
+* Improved loading of files from older versions
+* Ada import updated for Ada2005
+* Bugs fixed from http://bugs.kde.org:
+* Crash on creating various types of associations (140693, 141073, 141106, 141277)
+* Unclickable use case diagram (140870)
+* Crash on opening xmi file produced by previous version (141279)
+
+Version 1.5.6
+
+* Fixed save/reload of association widgets for collaboration diagrams
+ http://www.geeksoc.org/~jr/umbrello/uml-devel/9825.html
+ http://www.geeksoc.org/~jr/umbrello/uml-devel/9857.html
+* Fixed crash in ToolBarStateArrow destructor
+ http://www.geeksoc.org/~jr/umbrello/uml-devel/9861.html
+* Stereotype selection list for parameter properties dialog
+ http://www.geeksoc.org/~jr/umbrello/uml-devel/9862.html
+* Note widget is now always drawn on TOP of all widgets
+ http://www.geeksoc.org/~jr/umbrello/uml-devel/9863.html
+* Optimized printer margins
+ http://www.geeksoc.org/~jr/umbrello/uml-devel/9895.html
+* Improved code import for Ada and Pascal (SVN commits: 621845, 622128, 622396, 623316,
+ 623421, and 624257)
+* Bugs/wishes from http://bugs.kde.org:
+* Association line nodes don't drag along with multiply-selected classes (57878)
+* Disappearing parameters when editing class properties (114477)
+* Umbrello saves too many copies in xmi (135606)
+* XML scheme: mixup of attribute names: *color and *colour (136061)
+* Artifacts of a component diagram are wrongly placed in Deployment View folder (137564)
+* Incorrect export to SQL (138139)
+* Parentheses do not appear around the parameters of the C++ operator() (139147)
+
+Version 1.5.52
+
+* Fixed segfault in UMLClassifier::checkOperationSignature()
+ (http://www.geeksoc.org/~jr/umbrello/uml-devel/9816.html)
+* Fixed segfault on XMI close when a class uses a template
+ (http://www.geeksoc.org/~jr/umbrello/uml-devel/9818.html)
+* Fixed crashes during Tcl code generation
+* Fixed bugs in generated code of various code generators
+* Bugs/wishes from http://bugs.kde.org:
+* Shift + Left and Shift+Right causes SIGSEGV (136288)
+* Crashes on closing/opening files created with previous umbrello versions (136940)
+* Crash when opening saved document (136998)
+* Faulty behavior when a class inside of a package is modified (137497)
+
+Version 1.5.51
+
+* This is an interim release that fixes a serious regression in version 1.5.5
+ which is detailed at http://bugs.kde.org/135749 (Crash when opening a document)
+* XMI file contains deleted associations (129859)
+* Accessor methods are private instead of public (85553)
+
+Version 1.5.5
+
+* PHP5 generator creates stub methods for all interfaces a class implements (C. Brunsdon)
+* Fix load of associations in collaboration diagram (A. Spangler)
+* Fix for single selection of an unselected widget when other widgets are selected
+* Fixes for several bugs in toolbar states
+* Fix for message widget selection
+* Fix for class association not updating the association position when being moved
+* Bugs/wishes from http://bugs.kde.org:
+* Export-to-docbook and Export-to-HTML documentation generator (54307)
+* "role A properties" should give class name (69244)
+* Sharing designs, Folders, 3rd Party imports (87252, reimplementation)
+* "Open recent" list doesn't reorder when a file is opened (111757)
+* Properties menu: move to top/bottom buttons (126467)
+* Java import - importing interfaces - absent visibility treated as package
+ instead of public (131327)
+* Python code generation not independent of diagram view (131790)
+* Java import - method parameter types not resolved correctly (131825)
+* Java import: unable to import AzareusCore (131961)
+* Java import: error on multidimensional arrays (132017)
+* Java import - array types not resolved correctly (132035)
+* Java import - "final" and comments in method declaration not parsed correctly (132174)
+* Java import: spaces in strings cause next member var to be ignored (132472)
+* Java import - static member vars ignored in interfaces (132657)
+* Header file names are lowercase in .cpp file, but mixed case on the disk (134279)
+
+Version 1.5.4
+
+* Bugs/wishes from http://bugs.kde.org:
+* Transform interface to class - fixes to some issues (79433)
+* Free Pascal code import and generator (114547)
+* Enable selection of multiple classes in "Select classes" dialog (126485)
+* Crash after single click on the "UML Model" tree window (126560/129252)
+* Fix crash when importing classes from a java file (129107, 130093)
+* Cannot insert transition/association TO fork/join node in activity diagram (129914)
+* Command line switches: graphics export to directory does not work with relative paths (130600)
+* Importing java files that reference their own class name crashes (130735)
+* Importing java class (enum pattern) cause umbrello to hang (130792)
+* Importing java subinterface before superinterface results in superinterface
+ not being treated as an interface (130793)
+* Java import: method and class visibility ignored (130794)
+* Java import - static not handled correctly (130926)
+* Java import - package visibility incorrectly represented (130932)
+* Java import - random import order can result in interface being treated as class (131006)
+* Java import - associations not setup correctly, duplicate classes created (131270)
+
+Version 1.5.3
+
+* Switch to arrow tool after association creation (http://bugs.debian.org/353344)
+* Bugs/wishes from http://bugs.kde.org:
+* "Export all views" feature contributed by Daniel Calvi� S�chez (extension of 58809)
+* Static variables in java code are not marked static (59190)
+* New alignment type "distribute horizontally/vertically" (extension of 67058)
+* Save autosave file to a more obvious place (72019)
+* Usability and responsiveness improvements to code import (93296)
+* Auto-complete in parameter properties dialog in class diagram (104477)
+* Crash on application exit (112092)
+* Memory problem when importing classes from c++ sources (122668)
+* Nestable components and subsystems in Component diagram (124326)
+* Crash loading xmi file (125331, 126968)
+* User interaction with UMLWidget improvements (126391)
+* Comments are cut short when generating PHP code (126480)
+* Freeze on C++ class import (126994)
+* Crash on importing Java 1.5 classes containing annotations (127160)
+
+Version 1.5.2
+
+* fixed problem reordering methods in classes/interfaces
+ http://bugs.debian.org/348940 , http://bugs.kde.org/119991
+* fixed problem with font size computation/word wrap in note widgets
+ http://sourceforge.net/mailarchive/forum.php?thread_id=9558795&forum_id=472
+* Automatically fill useful info into the Perl writer heading template
+* Bugs/wishes from http://bugs.kde.org:
+* Fixed connection points for associations on widgets (67223)
+* Import Rose model files (81364)
+* Documentation for association roles not saved (105661)
+* Default data types not added for old Java generator (115991)
+* Custom operations in sequence diagrams become class operations (120337)
+* Fork/join symbol appears as a black box (120455)
+* Multiplicity labels positioned incorrectly when moving entities (120598)
+* Types of entity's attributes are displayed instead of their names (120742)
+* Unable to delete entity from entity list in "UML Model" frame (120750)
+* Interface names not italicized in diagram view (120761)
+* Cannot Resize Sequence Diagram Synchronous Messages (120910)
+* Sequencediagram: messages as constructor works only properly at 100% zoom (121238)
+* drag 'n drop a class when the zoom is not 1:1 don't put the class under mouse cursor (122293)
+* Documentation for associations is not retained (121478, 122063)
+* Crash when a non existing data type is used for an argument of a new method (122497)
+* Crash when importing Python files (121952)
+* "void" is imported as class and not datatypes (122184)
+* Crash when creating a datatype with the same name as a class (122188)
+* Crash when refusing to rename a class on importing typedef (122914)
+* Java import fails at abstract methods or interfaces (123661)
+
+Version 1.5.1
+
+* fix loading of associationwidget with non-default color
+* fix moving of initial and end activity by inhibiting resize
+* fix operation parameter and return types including template expressions
+* Bugs/wishes from http://bugs.kde.org:
+* Code import for Java and Python (79648)
+* Support C++ const methods (aka queries, part of 60452)
+* Change associations, aggregations, etc. on-the-fly (109963)
+* Collaboration Diagram: labels are reset to default position after moving them (117791)
+* Imported C++ classes not saved correctly in the XMI file (117875)
+* In ER models adding associations will add blank space in the entity attributes (117990)
+* ER diagrams need to underline the attribute name of primary keys (118570)
+* Cannot anchor notes to activity elements in Activity Diagram (118719)
+
+Version 1.5
+
+* Association classes
+* Advanced code generator for Ruby
+* Code generator for Tcl
+* Externalization of folders (i.e. submodel files)
+* Change interface into class and vice versa (if abstract and no attributes)
+* Image export via command line
+* All diagram objects can be resized
+* Automatic Diagram Layout (67059, not yet closed)
+
+* Bugs fixed / wishes implemented (see http://bugs.kde.org)
+ 57588 57672 58809 66461 67120 67719 72016 79433 87252 88117
+ 97162 98368 101550 105564 107405 108223 109591 109636 110073 110216
+110231 110379 110400 110843 111088 111470 111502 111759 111768 112017
+112292 112293 112333 112531 112552 112936 112991 112992 113748 114892
+
+Version 1.4.2 (maintenance release)
+
+* Bugs fixed from http://bugs.kde.org :
+97188 103170 106183 106356 106632 106673 107101 107551 108688
+
+Version 1.4.1 (maintenance release)
+
+Bugs fixed:
+* Crash on deleting attributes / enum literals
+* Crash in UMLView::createAutoAttributeAssociations()
+* Failure to import C++ enum type with comment on last literal
+* Non-Latin1 characters in diagram names
+* Generate missing "static" keyword in new C++ code generator
+* Bugs from http://bugs.kde.org :
+ 53376 57667 57875 70924 80924 89691 95353 100290 100307 101148
+103123 103133 103728 101541 104637
+
+Version 1.4
+
+* Entity relationship diagrams
+
+* Tabbed diagrams
+
+* Object creation message in sequence diagram
+
+* Notes can contain diagram hyperlinks
+
+* Move canvas items using the keyboard (Alt + arrow keys)
+
+* Improved support for parameterized classes
+
+* CORBA IDL import
+
+* PHP 5 code generator
+
+* fixed many issues in Perl code generator
+
+* Bugs fixed / wishes implemented (see http://bugs.kde.org)
+53380 53384 54928 55058 55242 57879 61945 62321 63316 67062
+67723 69592 71978 74249 74952 75010 77645 80405 80559 82342
+83834 84515 85136 85377 86083 86828 86952 86958 87111 87537
+87956 87995 88152 88245 88415 88954 89334 89485 89553 89563
+89579 89582 89699 89860 89903 90102 90106 90206 90755 91298
+91433 91434 91494 91869 91922 92116 92123 92222 92300 92301
+92781 92995 93122 93219 93297 93298 93501 93535 93696 94173
+94728 94795 94883 95082 95247 95252 95722 95924 95951 95954
+96216 96221 96964 97155 97182 97697 97887 97984 98603 98899
+ 99697 100142
+
+Version 1.3
+
+* heavily reduced memory usage and CPU load on large projects
+
+* reserved keywords added for supported languages
+
+* new tools for aligning several objects
+
+* support added for compressed XMI files (*.xmi.tgz, *.xmi.tar.bz2)
+
+* New diagram command 'Duplicate' permits the copying of diagram
+ objects including their features
+
+* New association type: Containment (circle-plus.)
+
+* Operation parameters have a 'direction' which documents whether
+ they are input or return values (in, out, inout.)
+ The IDL and Ada generators use this in their generated code.
+
+* Ability to show only public methods/members in diagram.
+
+* Improvements to scaled printing.
+
+* Crisp new icons
+
+* Improved XMI standard conformance of the file format.
+ In principle, Umbrello's XMI parser is now capable of
+ reading foreign XMI files.
+
+* Improved compatibility with old umbrello files
+
+* Support for repeatedly importing the same C++ file(s)
+
+* Umbrello places much less demand on the X server when
+ dealing with large and complex diagrams
+
+* Umbrello is still compilable with KDE 3.1 but if you have
+ such an "ancient" KDE version the new compressed-XMI file
+ format will not work.
+
+* Bugs fixed / wishes implemented (see http://bugs.kde.org)
+53361 53381 53383 55238 56184 57664 57875 66508 67058 68441
+71281 71334 71805 71969 72016 72615 72617 72644 72801 72971
+72977 73042 73139 73274 73275 73277 73278 73418 73521 73632
+73926 73975 74432 74820 75111 75318 75380 75582 75789 75935
+76114 76209 76506 77367 77377 78192 78317 78525 78806 78910
+78912 79180 79188 79202 79631 79883 80119 80299 80824 80913
+80999 81000 81790 82236 82315 82346 82406 82685 82743 82977
+83052 83430 83432 83446 83449 83546 83553 84260 84262 84516
+84549 84656 84574 85126 85196 85434 85552 85554
+
+
+Version 1.2
+
+* Canvas zoom
+
+* Undo and redo
+
+* Clipboard now uses XMI, old binary .uml file format no longer supported
+
+* Resizeable canvas
+
+* Refactoring agent
+
+* Improved code export and many new code export languages
+
+* Datatype and enum widgets and internal representation
+
+* Component and deployment diagrams
+
+* Parameterised classes (templates in C++, generics in Java)
+
+* Stereotypes on operations, attributes, etc
+
+* Asymmetric and symmetric sequence diagram messages
+
+* Corrected placement of the diamond in aggregations/compositions,
+ the diamond is at the owning class
+
+* Can change properties of multiple items at one time
+
+* Code base is tightened up (no more WidgetData classes)
+
+* Bugs fixed / wishes implemented (see http://bugs.kde.org)
+ 53354 53356 53357 53359 53362 53363 53365 53367 53371 53379
+ 53381 53385 53387 53388 53447 53487 53652 53653 53777 54183
+ 54446 54575 54816 54817 54822 54926 54969 55051 55236 55239
+ 55243 55245 55246 55247 55283 55300 55698 55729 55731 55810
+ 56166 56519 57054 57113 57197 57199 57200 57226 57424 57475
+ 57490 57521 57665 57669 57876 57877 57878 57881 57882 57883
+ 57886 57920 58339 58349 58426 58439 58489 58852 58854 59049
+ 59155 59190 59403 59408 59774 60139 60135 60204 60685 60981
+ 61972 62201 62276 63115 63248 63316 63884 63895 63897 64201
+ 64431 64435 64501 64502 64727 64881 64884 65183 65185 65312
+ 65389 65391 65407 65410 65411 65442 65444 65450 65530
+ 65635 66185 66442 66459 66461 66847 66848 66997 67209 67277
+ 67327 67765 67770 68095 68395 69330 69332 73926
+
+Version 1.1.1
+
+* No longer crashes when printing
+
+* Capitalisation corrections in strings
+
+Version 1.1 (including 1.1 rc 2)
+
+* Activites can have multiple outgoing associations
+
+* Updated and translated tips file
+
+* New handbook help file
+
+* Slovak translation added
+
+* Updated German translation
+
+* hopefully last changes needed for the name conversion to Umbrello
+
+* i18n fixes
+
+* Many bug fixes
+
+Version 1.1 rc 1
+
+* Pasteing in sequence diagrams now works correctly
+
+* Paste operation now shows dialogue messages when it can't paste everything or at all
+
+* Cut now works
+
+* Code generation wizard checks directory exists
+
+* Code generation overwrite dialogue now lets you apply option to all remaining files
+
+* Activity widgets now have borders
+
+* Actors can be generalised from other actors
+
+* Multiple objects can now be moved at once
+
+* check for metamodel=UML when loading files
+
+* Saved files have XML header
+
+* code generation wizard gives feedback on whether the file was generated
+
+* improved RPM spec file for multiple distributions
+
+* tokenizer.l compatibility improved
+
+* Can select which language to generate to from code generation panel
+
+* User interface improvements (`new attribute' etc buttons added)
+
+* Operations and attributes can have classifier scope (static)
+
+* PHP code generation
+
+* Some menu improvements
+
+* Compiler warnings reduced
+
+* i18n() added where it was missing
+
+* Various operations which made it crash fixed
+
+* Typos fixed
+
+Version 1.1 beta 2
+
+* Name changed to Umbrello UML Modeller
+
+* Java filenames have corret capitalisation
+
+* Grid is no longer printed
+
+* Widgets now keep track of their colours and use diagram colours by default
+
+* Open and save dialogues correctly remember where they were last
+
+* Checks on saving to PNG if user really wants to save to an already existing file
+
+* Sequence and collaboration messages always update when they should
+
+* Consistant position for labels on sequence messages
+
+* Nicer looking selection box
+
+* "New operation" from sequence diagram messages will now be used automaticaly on that message
+
+* Some improvements in menu consistency
+
+* Delete selected widgets with Delete key
+
+* Select all widgets on current diagram ability
+
+* Size of left hand list view now saved
+
+* White space removed from copying to PNG
+
+* Import of file format 4 from UML version 1.0.3
+
+* Solaris compatibility with setenv(), hopefully
+
+* operations and attributes now show the correct UML syntax in class diagrams
+
+Version 1.1 beta 1
+
+* The AssocCopy, MesdsageCopy and CutCopPaste classes have been
+ replaced with CUMLDrag and CUMLClipboard.
+ It supports 5 copy&paste types:
+ -- multiple empty folders (selected from the listview)
+ -- folders and multiple umlobjects (selected from the listview)
+ -- folders, multiple umlobjects and umlviews (selected from the listview)
+ -- multiple widget selection (from a diagram)
+ -- multiple operation and attribute selection (from the listview)
+ -- PNG clipboard support when copying for a diagram.
+ currently there is no ability to cut
+
+* Assosiation can be non-streight, just double click on the line.
+
+* the ..widgetData classes abstract widget data from actual widgets so there only
+ needs to be as many widgets in memory as there are in the current diagram
+
+* listview allows folders inside folders
+
+* all UMLObjects now have associated documentation
+
+* activity and state diagrams
+
+* XMI based file system
+
+* unicode UMLObject and diagram names
+
+* QCanvas used rather than QWidget
+
+* member variables now mostly use m_... format
+
+* Code generation for C++ and Java
+
+* Code import
+
+* Fixed dos line endings and untagged binary files in CVS
+
+* New project admin (Jonathan Riddell). No thanks to Sourceforge.
+
+
+Version 1.0.3
+
+* Added rename, delete options to folders
+
+* Text now remembers state
+
+* Moving text in selection move, now moves all selected.
+
+* Diagrams now into folders
+
+* Can save/load files without diagrams (use to crash on load)
+
+Version 1.0.2
+
+* Added multiple selection of icons
+
+* mass move, delete and toggle fill color
+
+* Cut, Copy to image file of selected items or selected section of diagram
+
+* Cut, Copy, Paste between diagrams.
+
+* Correctly deletes message from sequence diagram.
+
+* Recent files list now corectly handled
+
+* Error on loading files now put Untitled corerctly in the caption.
+
+* Toolbars keep session settings
+
+* Added folders for Actors, Use Cases and Concepts to help organisation
+
+* Composition, Implemantation, unidirectional associations and realizations added to class diagrams
+
+* Generalization, dependency, and unidirectional associations added to use case diagrams.
+
+* Changing text to nothing now hides the widget
+
+Version 1.0.1
+
+* Added package and stereotype options to Classes
+
+* Added to options page package and stereotype options.
+
+* print dialog added to printer interface to allow selection of diagrams to print.
+
+* Note Box size set correctly after loading.
+
+* Sequence diagram operation lines set correctly after loading.
+
+* prefix of document files changed from kde_libs_htmldir to kde_htmldir to allow documents to be installed where you like
+
+* footnote added when printing
+
+* fixed printing so print multiple pages is now correct
+
+* popup menu co-ordinates fixes for popup menus and list view
+
+* Diagram made bigger
+
+* drag and drop now correct on large diagram
+
+
+
+
+Version 1.0 (5/09/2001)
+
+* Started maintaining ChangeLog file
+
+* Setup mime type correctly
+
+* Fixed Layout Managers on GUIs
+
+* Added scope to the Concepts on Class/Concept diagrams
+ + Public, - Private, # Protected
+
+* Fixed install so can install in the directory you wish (I hope - Let me know
+if this works)
+
+* Removed hard coding of file location from program
+
+* File Extension ".uml" added if user didn't
+
+* Removed HTML welcome screen due to loading time.
+
+* Changed the icons setup by KDevelop (someone please desing better ones)
+
+* Has i18n ready to go, just need translators (any takers?)
+
+* Text Lines e.g. messages, lines of text, etc. are printed transparently.
+
+* Association prop. Dialog now has default OK button instead of Cancel.
+
+* Added options page for UML icons
+
+* Objects set to correct background colour when not using fill colour
+
+
diff --git a/umbrello/INSTALL b/umbrello/INSTALL
new file mode 100644
index 00000000..22f48d78
--- /dev/null
+++ b/umbrello/INSTALL
@@ -0,0 +1,179 @@
+You need to be the parent directory to configure the compile,
+depending on where you got the source you may need to do the extra KDE
+step of Makefile.cvs.
+
+cd kdesdk
+make -f Makefile.cvs
+./configure --prefix=`kde-config --prefix`
+cd umbrello
+make
+sudo make install
+
+
+Basic Installation
+==================
+
+ These are generic installation instructions.
+
+ The `configure' shell script attempts to guess correct values for
+various system-dependent variables used during compilation. It uses
+those values to create a `Makefile' in each directory of the package.
+It may also create one or more `.h' files containing system-dependent
+definitions. Finally, it creates a shell script `config.status' that
+you can run in the future to recreate the current configuration, a file
+`config.cache' that saves the results of its tests to speed up
+reconfiguring, and a file `config.log' containing compiler output
+(useful mainly for debugging `configure').
+
+ If you need to do unusual things to compile the package, please try
+to figure out how `configure' could check whether to do them, and mail
+diffs or instructions to the address given in the `README' so they can
+be considered for the next release. If at some point `config.cache'
+contains results you don't want to keep, you may remove or edit it.
+
+ The file `configure.in' is used to create `configure' by a program
+called `autoconf'. You only need `configure.in' if you want to change
+it or regenerate `configure' using a newer version of `autoconf'.
+
+The simplest way to compile this package is:
+
+ 1. `cd' to the directory containing the package's source code and type
+ `./configure' to configure the package for your system. If you're
+ using `csh' on an old version of System V, you might need to type
+ `sh ./configure' instead to prevent `csh' from trying to execute
+ `configure' itself.
+
+ Running `configure' takes a while. While running, it prints some
+ messages telling which features it is checking for.
+
+ 2. Type `make' to compile the package.
+
+ 3. Type `make install' to install the programs and any data files and
+ documentation.
+
+ 4. You can remove the program binaries and object files from the
+ source code directory by typing `make clean'.
+
+Compilers and Options
+=====================
+
+ Some systems require unusual options for compilation or linking that
+the `configure' script does not know about. You can give `configure'
+initial values for variables by setting them in the environment. Using
+a Bourne-compatible shell, you can do that on the command line like
+this:
+ CC=c89 CFLAGS=-O2 LIBS=-lposix ./configure
+
+Or on systems that have the `env' program, you can do it like this:
+ env CPPFLAGS=-I/usr/local/include LDFLAGS=-s ./configure
+
+Compiling For Multiple Architectures
+====================================
+
+ You can compile the package for more than one kind of computer at the
+same time, by placing the object files for each architecture in their
+own directory. To do this, you must use a version of `make' that
+supports the `VPATH' variable, such as GNU `make'. `cd' to the
+directory where you want the object files and executables to go and run
+the `configure' script. `configure' automatically checks for the
+source code in the directory that `configure' is in and in `..'.
+
+ If you have to use a `make' that does not supports the `VPATH'
+variable, you have to compile the package for one architecture at a time
+in the source code directory. After you have installed the package for
+one architecture, use `make distclean' before reconfiguring for another
+architecture.
+
+Installation Names
+==================
+
+ By default, `make install' will install the package's files in
+`/usr/local/bin', `/usr/local/man', etc. You can specify an
+installation prefix other than `/usr/local' by giving `configure' the
+option `--prefix=PATH'.
+
+ You can specify separate installation prefixes for
+architecture-specific files and architecture-independent files. If you
+give `configure' the option `--exec-prefix=PATH', the package will use
+PATH as the prefix for installing programs and libraries.
+Documentation and other data files will still use the regular prefix.
+
+ If the package supports it, you can cause programs to be installed
+with an extra prefix or suffix on their names by giving `configure' the
+option `--program-prefix=PREFIX' or `--program-suffix=SUFFIX'.
+
+Optional Features
+=================
+
+ Some packages pay attention to `--enable-FEATURE' options to
+`configure', where FEATURE indicates an optional part of the package.
+They may also pay attention to `--with-PACKAGE' options, where PACKAGE
+is something like `gnu-as' or `x' (for the X Window System). The
+`README' should mention any `--enable-' and `--with-' options that the
+package recognizes.
+
+ For packages that use the X Window System, `configure' can usually
+find the X include and library files automatically, but if it doesn't,
+you can use the `configure' options `--x-includes=DIR' and
+`--x-libraries=DIR' to specify their locations.
+
+Specifying the System Type
+==========================
+
+ There may be some features `configure' can not figure out
+automatically, but needs to determine by the type of host the package
+will run on. Usually `configure' can figure that out, but if it prints
+a message saying it can not guess the host type, give it the
+`--host=TYPE' option. TYPE can either be a short name for the system
+type, such as `sun4', or a canonical name with three fields:
+ CPU-COMPANY-SYSTEM
+
+See the file `config.sub' for the possible values of each field. If
+`config.sub' isn't included in this package, then this package doesn't
+need to know the host type.
+
+ If you are building compiler tools for cross-compiling, you can also
+use the `--target=TYPE' option to select the type of system they will
+produce code for and the `--build=TYPE' option to select the type of
+system on which you are compiling the package.
+
+Sharing Defaults
+================
+
+ If you want to set default values for `configure' scripts to share,
+you can create a site shell script called `config.site' that gives
+default values for variables like `CC', `cache_file', and `prefix'.
+`configure' looks for `PREFIX/share/config.site' if it exists, then
+`PREFIX/etc/config.site' if it exists. Or, you can set the
+`CONFIG_SITE' environment variable to the location of the site script.
+A warning: not all `configure' scripts look for a site script.
+
+Operation Controls
+==================
+
+ `configure' recognizes the following options to control how it
+operates.
+
+`--cache-file=FILE'
+ Use and save the results of the tests in FILE instead of
+ `./config.cache'. Set FILE to `/dev/null' to disable caching, for
+ debugging `configure'.
+
+`--help'
+ Print a summary of the options to `configure', and exit.
+
+`--quiet'
+`--silent'
+`-q'
+ Do not print messages saying which checks are being made.
+
+`--srcdir=DIR'
+ Look for the package's source code in directory DIR. Usually
+ `configure' can determine that directory automatically.
+
+`--version'
+ Print the version of Autoconf used to generate the `configure'
+ script, and exit.
+
+`configure' also accepts some other, not widely useful, options.
+
diff --git a/umbrello/Makefile.am b/umbrello/Makefile.am
new file mode 100644
index 00000000..f99bedf2
--- /dev/null
+++ b/umbrello/Makefile.am
@@ -0,0 +1,12 @@
+####### kdevelop will overwrite this part!!! (begin)##########
+
+SUBDIRS = umbrello
+
+####### kdevelop will overwrite this part!!! (end)############
+# not a GNU package. You can remove this line, if
+# have all needed files, that a GNU package needs
+AUTOMAKE_OPTIONS = foreign
+
+AM_CPPFLAGS = $(QT_INCLUDES)
+VERSION:=`cat ${PWD}/VERSION`
+
diff --git a/umbrello/README b/umbrello/README
new file mode 100644
index 00000000..2725d3a3
--- /dev/null
+++ b/umbrello/README
@@ -0,0 +1,10 @@
+Umbrello UML Modeller is a UML diagramming tool for KDE.
+
+UML lets you create models of object orientated software systems in a
+standard language.
+
+For more information on Umbrello see the website at
+http://uml.sf.net
+including the handbook which contains a tutorial on UML and Umbrello.
+
+For installation instructions read INSTALL.
diff --git a/umbrello/THANKS b/umbrello/THANKS
new file mode 100644
index 00000000..ab1462c5
--- /dev/null
+++ b/umbrello/THANKS
@@ -0,0 +1,93 @@
+Umbrello UML Modeller is the work of many people.
+Some of the contributors are listed at:
+ http://uml.sourceforge.net/developers.php
+
+If you find any problems or want features added please request or vote
+for them at http://bugs.kde.org and consider implementing the feature
+yourself, all contributions are very welcome.
+
+Some ideas for people wanting to contribute to Umbrello:
+ http://uml.sourceforge.net/junior-jobs.php
+
+---
+
+People who have contributed to Umbrello:
+(Please contact uml-devel if we have forgot you)
+
+Marcus Alanen <maalanen @ra.abo.fi>
+Danny Allen <dannya40uk @yahoo.co.uk>
+Laurent Bardi <laurent.Bardi @ipbs.fr>
+Zoltan Bartko <bartko.zoltan @pobox.sk>
+Luis De la Parra Blum <lparrab @gmx.net>
+Raymond Bosman <bosman @hetnet.nl>
+Clarke Brunsdon <clarke @vossoc.org>
+Ben Burton <bab @debian.org>
+Albert Cervera <albertca @jazzfree.com>
+Albert Astals Cid <tsdgeos @terra.es>
+Richard Dale <duke @tipitina.demon.co.uk>
+Vincent Decorges <vincent.decorges @eivd.ch>
+Antoine Dopffer <adopffer @nerdshack.com>
+Alan Ezust <alan.ezust @gmail.com>
+Jean-Remy Falleri <jr.falleri @gmail.com>
+Andi Fischer <andi.fischer @hispeed.ch>
+Pascal Fleury <fleury @users.sourceforge.net>
+JP Fournier (jfournier121 @rogers.com)
+Gregorio Guidi <g.guidi @sns.it>
+Jose Gutierrez <joseg @mapasysistemas.com.ar>
+Esben Mose Hansen <esben @despammed.com>
+Olaf Hartig <OleBowle @gmx.de>
+Marius Helf <marius.helf @gmx.de>
+Paul Hensgen <phensgen @bigpond.net.au>
+Michel Hermier <michel.hermier @wanadoo.fr>
+Harald Herres <harald.herres @control.de>
+David Hugh-Jones <hughjonesd @yahoo.co.uk>
+Pekka Jääskeläinen <pjaaskel @cs.tut.fi>
+Klas Kalass <klas.kalass @gmx.de>
+Oliver Kellogg <okellogg @users.sourceforge.net>
+Kleag (kleag @free.fr)
+Tobias Koenig <tokoe @kde.org>
+Piotr Kolaczkowski <P.Kolaczkowski @elka.pw.edu.pl>
+Matthias Kretz <kretz @kde.org>
+Thorsten Kunz <tk @bytecrash.net>
+Dmitry N. Kurashkin <dkur @nm.ru>
+Jari-Matti Mäkelä <jmjm @iki.fi>
+Gustavo Madrigal <gmadrigal @nextphere.com>
+martin <mv123q3 @hotmail.com>
+Rene Meyer <Rene.Meyer @sturmit.de>
+Laurent Montel <montel @kde.org>
+Yan Morin <yansanmo.site @gmail.com>
+Tom Morris <tfmorris @gmail.com>
+Lutz Mueller <lutz.mueller @gmx.de>
+Heiko Nardmann <heiko.nardmann @onlinehome.de>
+Dimitri Ognibene <ognibened @yahoo.it>
+Michael Palomas <mpalomas @gmail.com>
+Anthony Parent <anthony.parent @intel.com>
+Carsten Pfeiffer <pfeiffer @kde.org>
+Ivan Porres <iporres @abo.fi>
+Maciej Puzio <maciek @work.swmed.edu>
+Ruediger Ranft <kdebugs @rranft1.mail.htwm.de>
+Sharan Rao <sharanrao @gmail.com>
+John Ratke <jratke @comcast.net>
+Vincent Ricard <magic @magicninja.org>
+Daniel Richard G. <skunk @iskunk.org>
+Jonathan Riddell <jr @jriddell.org>
+Peeter Russak <pezz @tkwcy.ee>
+Paulo Roberto Rodriguez Sehn <paulo.sehn @gmail.com>
+Daniel Calviño Sánchez <danxuliu @gmail.com>
+Leo Savernik <l.savernik @aon.at>
+Peter Soetens <peter.soetens @mech.kuleuven.ac.be>
+Achim Spangler <Achim.Spangler @mnet-online.de>
+Sebastian Stein <seb.stein @gmx.de>
+Andrew Sutton <asutton @cs.kent.edu>
+Tanuj <tagrawal @hss.hns.com>
+Tonton <tonton-lists @team1664.org>
+Brian Thomas <brian.thomas @gsfc.nasa.gov>
+Ferenc Veres <lion @netngine.hu>
+Jean Vittor <jean.vittor @wanadoo.fr>
+Egbert Voigt <Egbert.Voigt @alcatel.de>
+Stefan Walter <sw @gegenunendlich.de>
+Jeremy Wickersheimer <jwickers @gmail.com>
+Yurgen Wolfgang <raptorsforever @softhome.net>
+Maciej J. Woloszyk <mat @esi.com.pl>
+Tobias Wulff <Tobias-Wulff @codeeye.de>
+
diff --git a/umbrello/TODO b/umbrello/TODO
new file mode 100644
index 00000000..06f3f78c
--- /dev/null
+++ b/umbrello/TODO
@@ -0,0 +1,22 @@
+There is always something to do for Umbrello UML Modeller. You can find an
+up-to-date list of remaining bugs in the bug tracker system at:
+
+http://bugs.kde.org/
+
+If you do not like chasing bugs you can add an incredible new feature. To get
+an idea what might be good feature look at the feature tracker system:
+
+http://bugs.kde.org/
+
+You can discuss a solution for a problem with the Umbrello developers at the
+Umbrello developer's mailing list:
+
+uml-devel@lists.sourceforge.net
+
+If you want to translate Umbrello to another language please join the relevant KDE translation team:
+
+http://i18n.kde.org/
+
+Finally, to get an overview look at the home page:
+
+http://uml.sourceforge.net/
diff --git a/umbrello/VERSION b/umbrello/VERSION
new file mode 100644
index 00000000..1cc9c180
--- /dev/null
+++ b/umbrello/VERSION
@@ -0,0 +1 @@
+1.5.8
diff --git a/umbrello/configure.in.in b/umbrello/configure.in.in
new file mode 100644
index 00000000..81e4fd59
--- /dev/null
+++ b/umbrello/configure.in.in
@@ -0,0 +1,112 @@
+AC_LANG_SAVE
+AC_LANG_CPLUSPLUS
+
+dnl Not GPL compatible
+dnl AC_PATH_PROG(DOT_FOUND, dot, no)
+dnl KDE_CHECK_HEADER(graphviz/pathgeom.h,
+dnl [kde_have_graphviz=yes],
+dnl [kde_have_graphviz=no])
+dnl
+dnl if test "$DOT_FOUND" != "no" -a "$kde_have_graphviz" = "yes"; then
+dnl CXXFLAGS="$CXXFLAGS -DHAVE_DOT"
+dnl GRAPHVIZ_LIB=`pkg-config --libs libgraph`
+dnl AUTOLAYOUT_DIR="autolayout"
+dnl AUTOLAYOUT_LIBS="autolayout/libautolayout.la $GRAPHVIZ_LIB -ldotgen -lgvc"
+dnl else
+dnl AUTOLAYOUT_DIR=""
+dnl AUTOLAYOUT_LIBS=""
+dnl fi
+dnl AC_SUBST(AUTOLAYOUT_DIR)
+dnl AC_SUBST(AUTOLAYOUT_LIBS)
+dnl End of Not GPL compatible
+
+AC_LANG_RESTORE
+
+
+AC_CHECK_FUNCS(setenv)
+
+dnl AH_BOTTOM(
+dnl [#if !defined(HAVE_SETENV)
+dnl #ifdef __cplusplus
+dnl extern "C"
+dnl #endif
+dnl int setenv(const char *name, const char *value, int overwrite);
+dnl #endif
+dnl ])
+
+HAVE_XSLT=yes
+
+KDE_FIND_PATH(xml2-config, XML_CONFIG, [${prefix}/bin ${exec_prefix}/bin], [
+ AC_MSG_WARN([Could not find libxml2 anywhere, check ftp://xmlsoft.org/ for libxml >= 2.4.8. (we also keep a version of it in kdesupport for CVS users' convience)])
+ HELP_SUBDIR=
+ DO_NOT_COMPILE="$DO_NOT_COMPILE umbrello"
+])
+
+if test -n "$XML_CONFIG"; then
+ vers=`$XML_CONFIG --version 2>/dev/null | sed -e 's/libxml //' | awk 'BEGIN { FS = "."; } { printf "%d", ($1 * 1000 + $2) * 1000 + $3;}'`
+ if test -n "$vers" && test "$vers" -ge 2004008
+ then
+ LIBXML_LIBS="`$XML_CONFIG --libs`"
+ LIBXML_RPATH=
+ for args in $LIBXML_LIBS; do
+ case $args in
+ -L*)
+ LIBXML_RPATH="$LIBXML_RPATH $args"
+ ;;
+ esac
+ done
+ LIBXML_RPATH=`echo $LIBXML_RPATH | sed -e "s/-L/-R/g"`
+ LIBXML_CFLAGS="`$XML_CONFIG --cflags`"
+
+ KDE_FIND_PATH(xmllint, XMLLINT, [${prefix}/bin ${exec_prefix}/bin], [XMLLINT=""])
+ AC_DEFINE_UNQUOTED(XMLLINT, "$XMLLINT", [Defines the executable of xmllint])
+ else
+ AC_MSG_WARN([You need at least libxml 2.4.8])
+ HAVE_XSLT=no
+ DO_NOT_COMPILE="$DO_NOT_COMPILE umbrello"
+ fi
+fi
+
+if test "$HAVE_XSLT" = yes; then
+
+ KDE_FIND_PATH(xslt-config, XSLT_CONFIG, [${prefix}/bin ${exec_prefix}/bin], [
+ AC_MSG_WARN([Could not find libxslt anywhere, check ftp://xmlsoft.org/ for libxslt >= 1.0.7. (we also keep a version of it in kdesupport for CVS users' convience)])
+ HAVE_XSLT=no
+ DO_NOT_COMPILE="$DO_NOT_COMPILE umbrello"
+ ])
+
+ if test -n "$XSLT_CONFIG"; then
+ vers=`$XSLT_CONFIG --version 2>/dev/null | awk 'BEGIN { FS = "."; } { printf "%d", ($1 * 1000 + $2) * 1000 + $3;}'`
+ if test -n "$vers" && test "$vers" -ge 1000007; then
+ LIBXSLT_LIBS="`$XSLT_CONFIG --libs`"
+ LIBXSLT_RPATH=
+ for args in $LIBXSLT_LIBS; do
+ case $args in
+ -L*)
+ LIBXSLT_RPATH="$LIBXSLT_RPATH $args"
+ ;;
+ esac
+ done
+ LIBXSLT_RPATH=`echo $LIBXSLT_RPATH | sed -e "s/-L/-R/g"`
+ LIBXSLT_CFLAGS="`$XSLT_CONFIG --cflags`"
+
+ else
+ AC_MSG_WARN([You need at least libxslt 1.0.7])
+ HAVE_XSLT=no
+ DO_NOT_COMPILE="$DO_NOT_COMPILE umbrello"
+ fi
+ fi
+fi
+
+if test "$have_libxslt" = "no"; then
+ DO_NOT_COMPILE="$DO_NOT_COMPILE umbrello"
+fi
+
+AC_SUBST(LIBXSLT_LIBS)
+AC_SUBST(LIBXSLT_CFLAGS)
+AC_SUBST(LIBXSLT_RPATH)
+
+AC_SUBST(LIBXML_LIBS)
+AC_SUBST(LIBXML_CFLAGS)
+AC_SUBST(LIBXML_RPATH)
+
diff --git a/umbrello/make-umbrello-release.sh b/umbrello/make-umbrello-release.sh
new file mode 100755
index 00000000..84429ad0
--- /dev/null
+++ b/umbrello/make-umbrello-release.sh
@@ -0,0 +1,60 @@
+#!/bin/sh
+#
+# Make a release from the current branches/KDE/3.5/kdesdk/umbrello
+#
+# Run this script as follows:
+# . make-umbrello-release.sh [BRANCH_VERSION]
+# BRANCH_VERSION defaults to 3.5.
+# @todo Create release from trunk if BRANCH_VERSION not given.
+# Note: trunk uses the cmake based build process.
+#
+# The script creates a directory, /tmp/kdesdk, which is used
+# as the work area for building the release.
+# The release tarfile will be placed in the current working dir.
+# The release version is taken from the VERSION file.
+#
+branchver=3.5
+if [ $# -gt 1 ]; then
+ branchver=$2
+fi
+origdir=`pwd`
+version=`grep "^[1-9]" VERSION`
+udir=umbrello-$version
+svnroot=svn://anonsvn.kde.org:/home/kde/branches/KDE/$branchver
+cd /tmp
+svn co -N $svnroot/kdesdk
+cd kdesdk
+svn co $svnroot/kdesdk/umbrello $udir
+svn co $svnroot/kde-common/admin $udir/admin
+svn co -N $svnroot/kdesdk/doc $udir/doc
+svn co $svnroot/kdesdk/doc/umbrello $udir/doc/umbrello
+cp -p Makefile.cvs $udir/
+cd $udir
+mv configure.in.in configure.in.in.orig
+echo '#MIN_CONFIG' > configure.in.in
+echo 'KDE_ENABLE_HIDDEN_VISIBILITY' >> configure.in.in
+echo 'CXXFLAGS="$CXXFLAGS $KDE_DEFAULT_CXXFLAGS"' >> configure.in.in
+echo '' >> configure.in.in
+cat configure.in.in.orig >> configure.in.in
+rm configure.in.in.orig
+perl -p -e 's@umbrello/VERSION@VERSION@g' -i `find umbrello -name Makefile.am`
+cd /tmp
+log=/tmp/kdesdk/svn2dist.log
+$origdir/../scripts/svn2dist kdesdk $udir -n umbrello --admin-dir kdesdk/$udir/admin \
+ --svn-root svn://anonsvn.kde.org/home/kde/branches/stable --log=$log -o
+mv umbrello/po kdesdk/$udir/
+rm -rf umbrello
+cd kdesdk/$udir
+make -f Makefile.cvs
+cd ..
+tarfile=${udir}.tar.bz2
+tar cfvj $tarfile --exclude=.svn --exclude=autom4te.cache $udir
+mv $tarfile $origdir/
+cd $origdir
+# rm -rf /tmp/kdesdk
+
+echo upload $tarfile to upload.sf.net
+echo wput $tarfile ftp://upload.sf.net/incoming/
+echo update uml.sf.net including uploading ChangeLog
+echo advertise on freshmeat and kde-apps
+
diff --git a/umbrello/umbrello/Makefile.am b/umbrello/umbrello/Makefile.am
new file mode 100644
index 00000000..bccd738e
--- /dev/null
+++ b/umbrello/umbrello/Makefile.am
@@ -0,0 +1,155 @@
+bin_PROGRAMS = umbrello
+
+umbrello_COMPILE_FIRST = version.h
+umbrello_SOURCES = activitywidget.cpp \
+actor.cpp \
+actorwidget.cpp \
+aligntoolbar.cpp \
+artifact.cpp \
+artifactwidget.cpp \
+association.cpp \
+associationwidget.cpp \
+assocrules.cpp \
+attribute.cpp \
+boxwidget.cpp \
+classifier.cpp \
+classifiercodedocument.cpp \
+classifierlistitem.cpp \
+classifierwidget.cpp \
+cmdlineexportallviewsevent.cpp \
+codeaccessormethod.cpp \
+codeblock.cpp \
+codeblockwithcomments.cpp \
+codeclassfield.cpp \
+codeclassfielddeclarationblock.cpp \
+codecomment.cpp \
+codedocument.cpp \
+codegenerationpolicy.cpp \
+codegenerator.cpp \
+codegenobjectwithtextblocks.cpp \
+codemethodblock.cpp \
+codeoperation.cpp \
+codeparameter.cpp \
+component.cpp \
+componentwidget.cpp \
+configurable.cpp \
+datatypewidget.cpp \
+dialog_utils.cpp \
+docwindow.cpp \
+entity.cpp \
+entityattribute.cpp \
+entitywidget.cpp \
+enum.cpp \
+enumliteral.cpp \
+enumwidget.cpp \
+floatingtextwidget.cpp \
+floatingtextwidgetcontroller.cpp \
+folder.cpp \
+forkjoinwidget.cpp \
+kplayerslideraction.cpp \
+hierarchicalcodeblock.cpp \
+import_rose.cpp \
+kstartuplogo.cpp \
+linepath.cpp \
+linkwidget.cpp \
+listpopupmenu.cpp \
+main.cpp \
+messagewidget.cpp \
+messagewidgetcontroller.cpp \
+model_utils.cpp \
+node.cpp \
+nodewidget.cpp \
+notewidget.cpp \
+notewidgetcontroller.cpp \
+objectwidget.cpp \
+objectwidgetcontroller.cpp \
+object_factory.cpp \
+operation.cpp \
+optionstate.cpp \
+ownedcodeblock.cpp \
+ownedhierarchicalcodeblock.cpp \
+package.cpp \
+packagewidget.cpp \
+petalnode.cpp \
+petaltree2uml.cpp \
+plugin.cpp \
+pluginloader.cpp \
+seqlinewidget.cpp \
+statewidget.cpp \
+stereotype.cpp \
+template.cpp \
+textblock.cpp \
+toolbarstate.cpp \
+toolbarstatearrow.cpp \
+toolbarstateassociation.cpp \
+toolbarstatefactory.cpp \
+toolbarstatemessages.cpp \
+toolbarstateother.cpp \
+toolbarstatepool.cpp \
+uml.cpp \
+umlattributelist.cpp \
+umlentityattributelist.cpp \
+umlcanvasobject.cpp \
+umlclassifierlistitemlist.cpp \
+umldoc.cpp \
+umllistview.cpp \
+umllistviewitem.cpp \
+umlnamespace.cpp \
+umlobject.cpp \
+umlobjectlist.cpp \
+umlrole.cpp \
+umlview.cpp \
+umlviewcanvas.cpp \
+umlviewimageexporter.cpp \
+umlviewimageexporterall.cpp \
+umlviewimageexportermodel.cpp \
+umlwidget.cpp \
+umlwidgetcontroller.cpp \
+uniqueid.cpp \
+usecase.cpp \
+usecasewidget.cpp \
+widgetbase.cpp \
+widget_factory.cpp \
+widget_utils.cpp \
+worktoolbar.cpp
+
+#umbrello_LDADD = ./refactoring/librefactoring.la ./codeimport/libcodeimport.la ./codeimport/kdevcppparser/libkdevcppparser.la ./clipboard/libclipboard.la ./dialogs/libdialogs.la ./codegenerators/libcodegenerator.la $(AUTOLAYOUT_LIBS) $(LIB_KDEPRINT) $(LIB_KIO)
+umbrello_LDADD = ./refactoring/librefactoring.la ./codeimport/libcodeimport.la ./codeimport/kdevcppparser/libkdevcppparser.la ./clipboard/libclipboard.la ./dialogs/libdialogs.la ./codegenerators/libcodegenerator.la ./docgenerators/libdocgenerators.la $(LIB_KDEPRINT) $(LIB_KIO)
+
+## See section "dnl Not GPL compatible" in ../configure.in.in
+# SUBDIRS = $(AUTOLAYOUT_DIR) codeimport dialogs clipboard pics codegenerators headings refactoring
+SUBDIRS = codeimport dialogs docgenerators clipboard pics codegenerators headings refactoring
+
+KDE_ICON=AUTO
+
+appdir=$(kde_datadir)/umbrello
+app_DATA = tips umbrelloui.rc
+
+xdg_apps_DATA = umbrello.desktop
+
+mimedir = $(kde_mimedir)/application
+mime_DATA = x-umbrello.desktop
+
+#INCLUDES= -Idialogs -Irefactoring $(all_includes) -I/usr/include/graphviz/
+INCLUDES= -Idialogs -Irefactoring $(all_includes)
+
+METASOURCES = AUTO
+
+umbrello_LDFLAGS = $(all_libraries) $(KDE_RPATH) -export-dynamic
+
+messages: rc.cpp
+ $(PREPARETIPS) > tips.cpp
+ $(EXTRACTRC) *.rc codegenerators/*.ui dialogs/*.ui > ./rc.cpp
+ 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`; \
+ if test -n "$$LIST"; then \
+ $(XGETTEXT) $$LIST -o $(podir)/umbrello.pot; \
+ fi
+ rm -f tips.cpp
+
+version.h: $(top_srcdir)/umbrello/VERSION
+ printf "#undef UMBRELLO_VERSION\n#define UMBRELLO_VERSION \"`cat $(top_srcdir)/umbrello/VERSION`\"\n" > version.h
+
+CLEANFILES = version.h
+
+noinst_HEADERS = version.h
+
diff --git a/umbrello/umbrello/activitywidget.cpp b/umbrello/umbrello/activitywidget.cpp
new file mode 100644
index 00000000..26ab29fd
--- /dev/null
+++ b/umbrello/umbrello/activitywidget.cpp
@@ -0,0 +1,235 @@
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * copyright (C) 2002-2006 *
+ * Umbrello UML Modeller Authors <uml-devel@uml.sf.net> *
+ ***************************************************************************/
+
+// own header
+#include "activitywidget.h"
+
+// qt includes
+#include <qpainter.h>
+
+// kde includes
+#include <klocale.h>
+#include <kdebug.h>
+#include <kinputdialog.h>
+
+// app includes
+#include "uml.h"
+#include "umldoc.h"
+#include "docwindow.h"
+#include "umlview.h"
+#include "listpopupmenu.h"
+#include "dialogs/activitydialog.h"
+
+ActivityWidget::ActivityWidget(UMLView * view, ActivityType activityType, Uml::IDType id )
+ : UMLWidget(view, id)
+{
+ UMLWidget::setBaseType( Uml::wt_Activity );
+ setActivityType( activityType );
+ updateComponentSize();
+}
+
+ActivityWidget::~ActivityWidget() {}
+
+void ActivityWidget::draw(QPainter & p, int offsetX, int offsetY) {
+ int w = width();
+ int h = height();
+ switch ( m_ActivityType )
+ {
+ case Normal :
+ UMLWidget::setPen(p);
+ if ( UMLWidget::getUseFillColour() ) {
+ p.setBrush( UMLWidget::getFillColour() );
+ }
+ {
+ const QFontMetrics &fm = getFontMetrics(FT_NORMAL);
+ const int fontHeight = fm.lineSpacing();
+ //int middleX = w / 2;
+ int textStartY = (h / 2) - (fontHeight / 2);
+ p.drawRoundRect(offsetX, offsetY, w, h, (h * 60) / w, 60);
+ p.setPen(Qt::black);
+ p.setFont( UMLWidget::getFont() );
+ p.drawText(offsetX + ACTIVITY_MARGIN, offsetY + textStartY,
+ w - ACTIVITY_MARGIN * 2, fontHeight, Qt::AlignCenter, getName());
+ }
+ UMLWidget::setPen(p);
+ break;
+ case Initial :
+ p.setPen( QPen(m_LineColour, 1) );
+ p.setBrush( WidgetBase::getLineColor() );
+ p.drawEllipse( offsetX, offsetY, w, h );
+ break;
+ case End :
+ p.setPen( QPen(m_LineColour, 1) );
+ p.setBrush( WidgetBase::getLineColor() );
+ p.drawEllipse( offsetX, offsetY, w, h );
+ p.setBrush( Qt::white );
+ p.drawEllipse( offsetX + 1, offsetY + 1, w - 2, h - 2 );
+ p.setBrush( WidgetBase::getLineColor() );
+ p.drawEllipse( offsetX + 3, offsetY + 3, w - 6, h - 6 );
+ break;
+ case Branch :
+ UMLWidget::setPen(p);
+ p.setBrush( UMLWidget::getFillColour() );
+ {
+ QPointArray array( 4 );
+ array[ 0 ] = QPoint( offsetX + w / 2, offsetY );
+ array[ 1 ] = QPoint( offsetX + w, offsetY + h / 2 );
+ array[ 2 ] = QPoint( offsetX + w / 2, offsetY + h );
+ array[ 3 ] = QPoint( offsetX, offsetY + h / 2 );
+ p.drawPolygon( array );
+ p.drawPolyline( array );
+ }
+ break;
+ }
+ if(m_bSelected)
+ drawSelected(&p, offsetX, offsetY);
+}
+
+void ActivityWidget::constrain(int& width, int& height) {
+ if (m_ActivityType == Normal) {
+ QSize minSize = calculateSize();
+ if (width < minSize.width())
+ width = minSize.width();
+ if (height < minSize.height())
+ height = minSize.height();
+ return;
+ }
+ if (width > height)
+ width = height;
+ else if (height > width)
+ height = width;
+ if (m_ActivityType == Branch) {
+ if (width < 20) {
+ width = 20;
+ height = 20;
+ } else if (width > 50) {
+ width = 50;
+ height = 50;
+ }
+ } else {
+ if (width < 15) {
+ width = 15;
+ height = 15;
+ } else if (width > 30) {
+ width = 30;
+ height = 30;
+ }
+ }
+}
+
+QSize ActivityWidget::calculateSize() {
+ int width, height;
+ if ( m_ActivityType == Normal ) {
+ const QFontMetrics &fm = getFontMetrics(FT_NORMAL);
+ const int fontHeight = fm.lineSpacing();
+ const int textWidth = fm.width(getName());
+ height = fontHeight;
+ width = textWidth > ACTIVITY_WIDTH ? textWidth : ACTIVITY_WIDTH;
+ height = height > ACTIVITY_HEIGHT ? height : ACTIVITY_HEIGHT;
+ width += ACTIVITY_MARGIN * 2;
+ height += ACTIVITY_MARGIN * 2;
+ } else {
+ width = height = 20;
+ }
+ return QSize(width, height);
+}
+
+ActivityWidget::ActivityType ActivityWidget::getActivityType() const {
+ return m_ActivityType;
+}
+
+void ActivityWidget::setActivityType( ActivityType activityType ) {
+ m_ActivityType = activityType;
+ updateComponentSize();
+ UMLWidget::m_bResizable = true;
+}
+
+void ActivityWidget::slotMenuSelection(int sel) {
+ bool done = false;
+
+ bool ok = false;
+ QString name = m_Text;
+
+ switch( sel ) {
+ case ListPopupMenu::mt_Rename:
+ name = KInputDialog::getText( i18n("Enter Activity Name"), i18n("Enter the name of the new activity:"), m_Text, &ok );
+ if( ok && name.length() > 0 )
+ m_Text = name;
+ done = true;
+ break;
+
+ case ListPopupMenu::mt_Properties:
+ showProperties();
+ done = true;
+ break;
+ }
+
+ if( !done )
+ UMLWidget::slotMenuSelection( sel );
+}
+
+void ActivityWidget::showProperties() {
+ DocWindow *docwindow = UMLApp::app()->getDocWindow();
+ docwindow->updateDocumentation(false);
+
+ ActivityDialog dialog(m_pView, this);
+ if (dialog.exec() && dialog.getChangesMade()) {
+ docwindow->showDocumentation(this, true);
+ UMLApp::app()->getDocument()->setModified(true);
+ }
+}
+
+bool ActivityWidget::isActivity(WorkToolBar::ToolBar_Buttons tbb,
+ ActivityType& resultType)
+{
+ bool status = true;
+ switch (tbb) {
+ case WorkToolBar::tbb_Initial_Activity:
+ resultType = Initial;
+ break;
+ case WorkToolBar::tbb_Activity:
+ resultType = Normal;
+ break;
+ case WorkToolBar::tbb_End_Activity:
+ resultType = End;
+ break;
+ case WorkToolBar::tbb_Branch:
+ resultType = Branch;
+ break;
+ default:
+ status = false;
+ break;
+ }
+ return status;
+}
+
+void ActivityWidget::saveToXMI( QDomDocument & qDoc, QDomElement & qElement ) {
+ QDomElement activityElement = qDoc.createElement( "activitywidget" );
+ UMLWidget::saveToXMI( qDoc, activityElement );
+ activityElement.setAttribute( "activityname", m_Text );
+ activityElement.setAttribute( "documentation", m_Doc );
+ activityElement.setAttribute( "activitytype", m_ActivityType );
+ qElement.appendChild( activityElement );
+}
+
+bool ActivityWidget::loadFromXMI( QDomElement & qElement ) {
+ if( !UMLWidget::loadFromXMI( qElement ) )
+ return false;
+ m_Text = qElement.attribute( "activityname", "" );
+ m_Doc = qElement.attribute( "documentation", "" );
+ QString type = qElement.attribute( "activitytype", "1" );
+ setActivityType( (ActivityType)type.toInt() );
+ return true;
+}
+
+
+#include "activitywidget.moc"
+
diff --git a/umbrello/umbrello/activitywidget.h b/umbrello/umbrello/activitywidget.h
new file mode 100644
index 00000000..f23d4b65
--- /dev/null
+++ b/umbrello/umbrello/activitywidget.h
@@ -0,0 +1,127 @@
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * copyright (C) 2002-2006 *
+ * Umbrello UML Modeller Authors <uml-devel@uml.sf.net> *
+ ***************************************************************************/
+
+#ifndef ACTIVITYWIDGET_H
+#define ACTIVITYWIDGET_H
+
+#include "umlwidget.h"
+#include "worktoolbar.h"
+
+#define ACTIVITY_MARGIN 5
+#define ACTIVITY_WIDTH 30
+#define ACTIVITY_HEIGHT 10
+
+/**
+ * This class is the graphical version of a UML Activity. A ActivityWidget is created
+ * by a @ref UMLView. An ActivityWidget belongs to only one @ref UMLView instance.
+ * When the @ref UMLView instance that this class belongs to, it will be automatically deleted.
+ *
+ * The ActivityWidget class inherits from the @ref UMLWidget class which adds most of the functionality
+ * to this class.
+ *
+ * @short A graphical version of a UML Activity.
+ * @author Paul Hensgen <phensgen@techie.com>
+ * Bugs and comments to uml-devel@lists.sf.net or http://bugs.kde.org
+ */
+class ActivityWidget : public UMLWidget {
+ Q_OBJECT
+
+public:
+ enum ActivityType
+ {
+ Initial = 0,
+ Normal,
+ End,
+ Branch
+ };
+
+ /**
+ * Creates a Activity widget.
+ *
+ * @param view The parent of the widget.
+ * @param activityType The type of activity.
+ * @param id The ID to assign (-1 will prompt a new ID.)
+ */
+ explicit ActivityWidget( UMLView * view, ActivityType activityType = Normal, Uml::IDType id = Uml::id_None );
+
+
+ /**
+ * destructor
+ */
+ virtual ~ActivityWidget();
+
+ /**
+ * Overrides the standard paint event.
+ */
+ void draw(QPainter & p, int offsetX, int offsetY);
+
+ /**
+ * Overrides Method from UMLWidget.
+ */
+ void constrain(int& width, int& height);
+
+ /**
+ * Returns the type of activity.
+ */
+ ActivityType getActivityType() const;
+
+ /**
+ * Sets the type of activity.
+ */
+ void setActivityType( ActivityType activityType );
+
+ /**
+ * Show a properties dialog for an ActivityWidget.
+ */
+ void showProperties();
+
+ /**
+ * Determines whether a toolbar button represents an Activity.
+ * CHECK: currently unused - can this be removed?
+ *
+ * @param tbb The toolbar button enum input value.
+ * @param resultType The ActivityType corresponding to tbb.
+ * This is only set if tbb is an Activity.
+ * @return True if tbb represents an Activity.
+ */
+ static bool isActivity( WorkToolBar::ToolBar_Buttons tbb,
+ ActivityType& resultType );
+
+ /**
+ * Saves the widget to the "activitywidget" XMI element.
+ */
+ void saveToXMI( QDomDocument & qDoc, QDomElement & qElement );
+
+ /**
+ * Loads the widget from the "activitywidget" XMI element.
+ */
+ bool loadFromXMI( QDomElement & qElement );
+
+protected:
+ /**
+ * Overrides method from UMLWidget
+ */
+ QSize calculateSize();
+
+ /**
+ * Type of activity.
+ */
+ ActivityType m_ActivityType;
+
+public slots:
+
+ /**
+ * Captures any popup menu signals for menus it created.
+ */
+ void slotMenuSelection(int sel);
+};
+
+#endif
diff --git a/umbrello/umbrello/actor.cpp b/umbrello/umbrello/actor.cpp
new file mode 100644
index 00000000..6e09c506
--- /dev/null
+++ b/umbrello/umbrello/actor.cpp
@@ -0,0 +1,40 @@
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * copyright (C) 2002-2006 *
+ * Umbrello UML Modeller Authors <uml-devel@uml.sf.net> *
+ ***************************************************************************/
+
+#include "actor.h"
+
+UMLActor::UMLActor(const QString & name, Uml::IDType id) : UMLCanvasObject(name, id) {
+ init();
+}
+
+UMLActor::~UMLActor() {}
+
+void UMLActor::init() {
+ m_BaseType = Uml::ot_Actor;
+}
+
+UMLObject* UMLActor::clone() const {
+ UMLActor *clone = new UMLActor();
+ UMLObject::copyInto(clone);
+ return clone;
+}
+
+void UMLActor::saveToXMI(QDomDocument& qDoc, QDomElement& qElement) {
+ QDomElement actorElement = UMLObject::save("UML:Actor", qDoc);
+ qElement.appendChild(actorElement);
+}
+
+bool UMLActor::load(QDomElement&) {
+ return true;
+}
+
+
+#include "actor.moc"
diff --git a/umbrello/umbrello/actor.h b/umbrello/umbrello/actor.h
new file mode 100644
index 00000000..479482e0
--- /dev/null
+++ b/umbrello/umbrello/actor.h
@@ -0,0 +1,66 @@
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * copyright (C) 2002-2006 *
+ * Umbrello UML Modeller Authors <uml-devel@uml.sf.net> *
+ ***************************************************************************/
+
+#ifndef ACTOR_H
+#define ACTOR_H
+
+#include "umlcanvasobject.h"
+
+/**
+ * This class contains the non-graphical information required for a UML Actor.
+ * This class inherits from @ref UMLCanvasObject which contains most of the
+ * information.
+ * The @ref UMLDoc class creates instances of this type.
+ *
+ * @short Information for a non-graphical UML Actor.
+ * @author Paul Hensgen <phensgen@techie.com>
+ * @see UMLCanvasObject
+ * Bugs and comments to uml-devel@lists.sf.net or http://bugs.kde.org
+ */
+class UMLActor : public UMLCanvasObject {
+ Q_OBJECT
+public:
+ /**
+ * Constructs an Actor.
+ *
+ * @param name The name of the Actor.
+ * @param id The unique id to assign to this Actor.
+ */
+ explicit UMLActor(const QString & name = "", Uml::IDType id = Uml::id_None);
+
+ /**
+ * Standard deconstructor.
+ */
+ ~UMLActor();
+
+ /**
+ * Initializes key variables of the class.
+ */
+ virtual void init();
+
+ /**
+ * Make a clone of this object.
+ */
+ virtual UMLObject* clone() const;
+
+ /**
+ * Creates the <UML:Actor> XMI element.
+ */
+ void saveToXMI( QDomDocument & qDoc, QDomElement & qElement );
+
+protected:
+ /**
+ * Loads the <UML:Actor> XMI element (empty.)
+ */
+ bool load( QDomElement & element );
+};
+
+#endif
diff --git a/umbrello/umbrello/actorwidget.cpp b/umbrello/umbrello/actorwidget.cpp
new file mode 100644
index 00000000..0001e146
--- /dev/null
+++ b/umbrello/umbrello/actorwidget.cpp
@@ -0,0 +1,79 @@
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * copyright (C) 2002-2007 *
+ * Umbrello UML Modeller Authors <uml-devel@uml.sf.net> *
+ ***************************************************************************/
+
+// own header file
+#include "actorwidget.h"
+
+// system includes
+#include <qpainter.h>
+
+// local includes
+#include "actor.h"
+#include "umlview.h"
+
+
+ActorWidget::ActorWidget(UMLView * view, UMLActor *a) : UMLWidget(view, a) {
+ UMLWidget::setBaseType( Uml::wt_Actor );
+}
+
+ActorWidget::~ActorWidget() {}
+
+void ActorWidget::draw(QPainter & p, int offsetX, int offsetY) {
+ UMLWidget::setPen(p);
+ if( UMLWidget::getUseFillColour() )
+ p.setBrush( UMLWidget::getFillColour() );
+ const int w = width();
+ const int h = height();
+ p.setFont( UMLWidget::getFont() );
+ const QFontMetrics &fm = getFontMetrics(FT_NORMAL);
+ const int textWidth = fm.width(getName());
+ const int fontHeight = fm.lineSpacing();
+ const int a_height = h - fontHeight - A_MARGIN;
+ const int h2 = a_height / 2;
+ const int w2 = w - A_MARGIN * 2;
+ const int a_width = (h2 > w2 || w > textWidth + A_MARGIN * 2 ? w2 : h2);
+ const int middleX = w / 2;
+ const int thirdY = a_height / 3;
+
+ //draw actor
+ p.drawEllipse(offsetX + middleX - a_width / 2, offsetY, a_width, thirdY); //head
+ p.drawLine(offsetX + middleX, offsetY + thirdY,
+ offsetX + middleX, offsetY + thirdY * 2); //body
+ p.drawLine(offsetX + middleX, offsetY + 2 * thirdY,
+ offsetX + middleX - a_width / 2, offsetY + a_height); //left leg
+ p.drawLine(offsetX + middleX, offsetY + 2 * thirdY,
+ offsetX + middleX + a_width / 2, offsetY + a_height); //right leg
+ p.drawLine(offsetX + middleX - a_width / 2, offsetY + thirdY + thirdY / 2,
+ offsetX + middleX + a_width / 2, offsetY + thirdY + thirdY / 2); //arms
+ //draw text
+ p.setPen(QPen(Qt::black));
+ p.drawText(offsetX + A_MARGIN, offsetY + h - fontHeight,
+ w - A_MARGIN * 2, fontHeight, Qt::AlignCenter, getName());
+ if(m_bSelected)
+ drawSelected(&p, offsetX, offsetY);
+}
+
+QSize ActorWidget::calculateSize() {
+ const QFontMetrics &fm = getFontMetrics(FT_NORMAL);
+ const int fontHeight = fm.lineSpacing();
+ const int textWidth = fm.width(getName());
+ int width = textWidth > A_WIDTH ? textWidth : A_WIDTH;
+ int height = A_HEIGHT + fontHeight + A_MARGIN;
+ width += A_MARGIN * 2;
+ return QSize(width, height);
+}
+
+void ActorWidget::saveToXMI( QDomDocument & qDoc, QDomElement & qElement ) {
+ QDomElement actorElement = qDoc.createElement( "actorwidget" );
+ UMLWidget::saveToXMI( qDoc, actorElement );
+ qElement.appendChild( actorElement );
+}
+
diff --git a/umbrello/umbrello/actorwidget.h b/umbrello/umbrello/actorwidget.h
new file mode 100644
index 00000000..6d19290c
--- /dev/null
+++ b/umbrello/umbrello/actorwidget.h
@@ -0,0 +1,78 @@
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * copyright (C) 2002-2006 *
+ * Umbrello UML Modeller Authors <uml-devel@uml.sf.net> *
+ ***************************************************************************/
+
+#ifndef ACTORWIDGET_H
+#define ACTORWIDGET_H
+
+#include "umlwidget.h"
+
+#define A_WIDTH 20
+#define A_HEIGHT 40
+#define A_MARGIN 5
+
+class UMLActor;
+
+/**
+ * This class is the graphical version of a UML Actor.
+ * An ActorWidget is created by a @ref UMLView. An ActorWidget belongs to only
+ * one @ref UMLView instance.
+ * When the @ref UMLView instance that this class belongs to is destroyed, the
+ * ActorWidget will be automatically deleted.
+ *
+ * If the UMLActor class that this ActorWidget is displaying is deleted, the
+ * @ref UMLView will make sure that this instance is also deleted.
+ *
+ * The ActorWidget class inherits from the @ref UMLWidget class which adds most
+ * of the functionality to this class.
+ *
+ * @short A graphical version of a UML Actor.
+ * @author Paul Hensgen <phensgen@techie.com>
+ * @see UMLWidget
+ * @see UMLView
+ * Bugs and comments to uml-devel@lists.sf.net or http://bugs.kde.org
+ */
+
+class ActorWidget : public UMLWidget {
+public:
+
+ /**
+ * Constructs an ActorWidget.
+ *
+ * @param view The parent of this ActorWidget.
+ * @param o The Actor class this ActorWidget will display.
+ */
+ ActorWidget(UMLView * view, UMLActor *o);
+
+
+ /**
+ * destructor
+ */
+ virtual ~ActorWidget();
+
+ /**
+ * Overrides the standard paint event.
+ */
+ void draw(QPainter & p, int offsetX, int offsetY);
+
+ /**
+ * Saves the widget to the "actorwidget" XMI element.
+ * Note: For loading from XMI, the inherited parent method is used.
+ */
+ void saveToXMI( QDomDocument & qDoc, QDomElement & qElement );
+
+protected:
+ /**
+ * Overrides method from UMLWidget.
+ */
+ QSize calculateSize();
+};
+
+#endif
diff --git a/umbrello/umbrello/aligntoolbar.cpp b/umbrello/umbrello/aligntoolbar.cpp
new file mode 100644
index 00000000..3be8689a
--- /dev/null
+++ b/umbrello/umbrello/aligntoolbar.cpp
@@ -0,0 +1,391 @@
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * copyright (C) 2004-2007 *
+ * Umbrello UML Modeller Authors <uml-devel@uml.sf.net> *
+ ***************************************************************************/
+
+// own header
+#include "aligntoolbar.h"
+
+// system includes
+#include <algorithm>
+#include <vector>
+
+// qt includes
+#include <qmainwindow.h>
+
+// kde includes
+#include <klocale.h>
+#include <kmessagebox.h>
+#include <kstandarddirs.h>
+
+// app includes
+#include "uml.h"
+#include "umldoc.h"
+#include "umlview.h"
+#include "umlwidget.h"
+#include "umlwidgetlist.h"
+
+AlignToolBar::AlignToolBar(QMainWindow* parentWindow, const char* )
+ : KToolBar(parentWindow,Qt::DockRight,false) {
+ // load images for the buttons
+ loadPixmaps();
+
+ // create the buttons
+ insertButton(m_Pixmaps[alac_align_left], alac_align_left, true, i18n("Align Left"));
+ insertButton(m_Pixmaps[alac_align_right], alac_align_right, true, i18n("Align Right"));
+ insertButton(m_Pixmaps[alac_align_top], alac_align_top, true, i18n("Align Top"));
+ insertButton(m_Pixmaps[alac_align_bottom], alac_align_bottom, true, i18n("Align Bottom"));
+ insertButton(m_Pixmaps[alac_align_vertical_middle], alac_align_vertical_middle, true, i18n("Align Vertical Middle"));
+ insertButton(m_Pixmaps[alac_align_horizontal_middle], alac_align_horizontal_middle, true, i18n("Align Horizontal Middle"));
+ insertButton(m_Pixmaps[alac_align_vertical_distribute], alac_align_vertical_distribute, true, i18n("Align Vertical Distribute"));
+ insertButton(m_Pixmaps[alac_align_horizontal_distribute], alac_align_horizontal_distribute, true, i18n("Align Horizontal Distribute"));
+
+ setOrientation( Qt::Vertical );
+ setVerticalStretchable( true );
+
+ // gets called whenever a button in the toolbar is clicked
+ connect( this, SIGNAL( released( int ) ), this, SLOT( slotButtonChanged (int ) ) );
+}
+
+AlignToolBar::~AlignToolBar() {
+}
+
+/* ------ private functions ------ */
+
+bool AlignToolBar::hasWidgetSmallerX(const UMLWidget* widget1, const UMLWidget* widget2) {
+ return widget1->getX() < widget2->getX();
+}
+
+bool AlignToolBar::hasWidgetSmallerY(const UMLWidget* widget1, const UMLWidget* widget2) {
+ return widget1->getY() < widget2->getY();
+}
+
+void AlignToolBar::loadPixmaps() {
+ KStandardDirs* dirs = KGlobal::dirs();
+ QString dataDir = dirs->findResourceDir( "data", "umbrello/pics/object.png" );
+ dataDir += "/umbrello/pics/";
+
+ m_Pixmaps[alac_align_left].load( dataDir + "align_left.png" );
+ m_Pixmaps[alac_align_right].load( dataDir + "align_right.png" );
+ m_Pixmaps[alac_align_top].load( dataDir + "align_top.png" );
+ m_Pixmaps[alac_align_bottom].load( dataDir + "align_bottom.png" );
+ m_Pixmaps[alac_align_vertical_middle].load( dataDir + "align_vert_middle.png" );
+ m_Pixmaps[alac_align_horizontal_middle].load( dataDir + "align_hori_middle.png" );
+ m_Pixmaps[alac_align_vertical_distribute].load( dataDir + "align_vert_distribute.png" );
+ m_Pixmaps[alac_align_horizontal_distribute].load( dataDir + "align_hori_distribute.png" );
+
+ return;
+}
+
+int AlignToolBar::getSmallestX(const UMLWidgetList &widgetList) {
+ UMLWidgetListIt it(widgetList);
+ UMLWidget* widget;
+
+ int smallestX = it.toFirst()->getX();
+ ++it;
+
+ while ((widget = it.current()) != 0) {
+ ++it;
+ if (smallestX > widget->getX())
+ smallestX = widget->getX();
+ }
+
+ return smallestX;
+}
+
+int AlignToolBar::getSmallestY(const UMLWidgetList &widgetList) {
+ UMLWidgetListIt it(widgetList);
+ UMLWidget* widget;
+
+ int smallestY = it.toFirst()->getY();
+ ++it;
+
+ while ((widget = it.current()) != 0) {
+ ++it;
+ if (smallestY > widget->getY())
+ smallestY = widget->getY();
+ }
+
+ return smallestY;
+}
+
+int AlignToolBar::getBiggestX(const UMLWidgetList &widgetList) {
+ UMLWidgetListIt it(widgetList);
+ UMLWidget* widget;
+
+ int biggestX = it.toFirst()->getX();
+ biggestX += it.current()->getWidth();
+ ++it;
+
+ while ((widget = it.current()) != 0) {
+ ++it;
+ if (biggestX < widget->getX() + widget->getWidth())
+ biggestX = widget->getX() + widget->getWidth();
+ }
+
+ return biggestX;
+}
+
+int AlignToolBar::getBiggestY(const UMLWidgetList &widgetList) {
+ UMLWidgetListIt it(widgetList);
+ UMLWidget* widget;
+
+ int biggestY = it.toFirst()->getY();
+ biggestY += it.current()->getHeight();
+ ++it;
+
+ while ((widget = it.current()) != 0) {
+ ++it;
+ if (biggestY < widget->getY() + widget->getHeight())
+ biggestY = widget->getY() + widget->getHeight();
+ }
+
+ return biggestY;
+}
+
+int AlignToolBar::getHeightsSum(const UMLWidgetList &widgetList) {
+ UMLWidget* widget;
+ UMLWidgetListIt it(widgetList);
+
+ int heightsSum = 0;
+
+ it.toFirst();
+ while ((widget = it.current()) != 0) {
+ ++it;
+ heightsSum += widget->getHeight();
+ }
+
+ return heightsSum;
+}
+
+int AlignToolBar::getWidthsSum(const UMLWidgetList &widgetList) {
+ UMLWidget* widget;
+ UMLWidgetListIt it(widgetList);
+
+ int widthsSum = 0;
+
+ it.toFirst();
+ while ((widget = it.current()) != 0) {
+ ++it;
+ widthsSum += widget->getWidth();
+ }
+
+ return widthsSum;
+}
+
+void AlignToolBar::alignLeft(UMLWidgetList &widgetList) {
+ int smallestX = getSmallestX(widgetList);
+
+ UMLWidget* widget;
+ UMLWidgetListIt it(widgetList);
+
+ it.toFirst();
+ while ((widget = it.current()) != 0) {
+ ++it;
+ widget->setX(smallestX);
+ }
+}
+
+void AlignToolBar::alignRight(UMLWidgetList &widgetList) {
+ int biggestX = getBiggestX(widgetList);
+
+ UMLWidget* widget;
+ UMLWidgetListIt it(widgetList);
+
+ it.toFirst();
+ while ((widget = it.current()) != 0) {
+ ++it;
+ widget->setX(biggestX - widget->getWidth());
+ }
+}
+
+void AlignToolBar::alignTop(UMLWidgetList &widgetList) {
+ int smallestY = getSmallestY(widgetList);
+
+ UMLWidget* widget;
+ UMLWidgetListIt it(widgetList);
+
+ it.toFirst();
+ while ((widget = it.current()) != 0) {
+ ++it;
+ widget->setY(smallestY);
+ }
+}
+
+void AlignToolBar::alignBottom(UMLWidgetList &widgetList) {
+ int biggestY = getBiggestY(widgetList);
+
+ UMLWidget* widget;
+ UMLWidgetListIt it(widgetList);
+
+ it.toFirst();
+ while ((widget = it.current()) != 0) {
+ ++it;
+ widget->setY(biggestY - widget->getHeight());
+ }
+}
+
+void AlignToolBar::alignVerticalMiddle(UMLWidgetList &widgetList) {
+ int smallestX = getSmallestX(widgetList);
+ int biggestX = getBiggestX(widgetList);
+ int middle = int((biggestX - smallestX) / 2) + smallestX;
+
+ UMLWidget* widget;
+ UMLWidgetListIt it(widgetList);
+
+ it.toFirst();
+ while ((widget = it.current()) != 0) {
+ ++it;
+ widget->setX(middle - int(widget->getWidth() / 2));
+ }
+}
+
+void AlignToolBar::alignHorizontalMiddle(UMLWidgetList &widgetList) {
+ int smallestY = getSmallestY(widgetList);
+ int biggestY = getBiggestY(widgetList);
+ int middle = int((biggestY - smallestY) / 2) + smallestY;
+
+ UMLWidget* widget;
+ UMLWidgetListIt it(widgetList);
+
+ it.toFirst();
+ while ((widget = it.current()) != 0) {
+ ++it;
+ widget->setY(middle - int(widget->getHeight() / 2));
+ }
+}
+
+void AlignToolBar::alignVerticalDistribute(UMLWidgetList &widgetList) {
+ int smallestY = getSmallestY(widgetList);
+ int biggestY = getBiggestY(widgetList);
+ int heightsSum = getHeightsSum(widgetList);
+ int distance = int(((biggestY - smallestY) - heightsSum) / (widgetList.count()-1.0) + 0.5);
+
+ sortWidgetList(widgetList, hasWidgetSmallerY);
+
+ UMLWidget* widget;
+ UMLWidgetListIt it(widgetList);
+
+ it = UMLWidgetListIt(widgetList);
+
+ UMLWidget* widgetPrev = it.toFirst();
+ ++it;
+ while ((widget = it.current()) != 0) {
+ ++it;
+ widget->setY(widgetPrev->getY() + widgetPrev->getHeight() + distance);
+ widgetPrev = widget;
+ }
+}
+
+void AlignToolBar::alignHorizontalDistribute(UMLWidgetList &widgetList) {
+ int smallestX = getSmallestX(widgetList);
+ int biggestX = getBiggestX(widgetList);
+ int widthsSum = getWidthsSum(widgetList);
+ int distance = int(((biggestX - smallestX) - widthsSum) / (widgetList.count()-1.0) + 0.5);
+
+ sortWidgetList(widgetList, hasWidgetSmallerX);
+
+ UMLWidget* widget;
+ UMLWidgetListIt it(widgetList);
+
+ it = UMLWidgetListIt(widgetList);
+
+ UMLWidget* widgetPrev = it.toFirst();
+ ++it;
+ while ((widget = it.current()) != 0) {
+ ++it;
+ widget->setX(widgetPrev->getX() + widgetPrev->getWidth() + distance);
+ widgetPrev = widget;
+ }
+}
+
+template<typename Compare>
+void AlignToolBar::sortWidgetList(UMLWidgetList &widgetList, Compare comp) {
+ std::vector<UMLWidget*> widgetVector;
+ UMLWidgetListIt it(widgetList);
+ while (it.current() != 0) {
+ widgetVector.push_back(*it);
+ ++it;
+ }
+ sort(widgetVector.begin(), widgetVector.end(), comp);
+
+ widgetList.clear();
+
+ for (std::vector<UMLWidget*>::iterator it=widgetVector.begin(); it != widgetVector.end(); ++it) {
+ widgetList.append(*it);
+ }
+}
+
+/* ------ private slots ------ */
+
+void AlignToolBar::slotButtonChanged(int btn) {
+ UMLView* view = UMLApp::app()->getCurrentView();
+ UMLWidgetList widgetList;
+ UMLWidget* widget;
+
+ // get the list with selected widgets (not associations)
+ view->getSelectedWidgets(widgetList);
+ UMLWidgetListIt it(widgetList);
+
+ // at least 2 widgets must be selected
+ if (widgetList.count() > 1) {
+ // now perform alignment according to the clicked button
+ switch (btn) {
+ case alac_align_left:
+ alignLeft(widgetList);
+ break;
+
+ case alac_align_right:
+ alignRight(widgetList);
+ break;
+
+ case alac_align_top:
+ alignTop(widgetList);
+ break;
+
+ case alac_align_bottom:
+ alignBottom(widgetList);
+ break;
+
+ case alac_align_vertical_middle:
+ alignVerticalMiddle(widgetList);
+ break;
+
+ case alac_align_horizontal_middle:
+ alignHorizontalMiddle(widgetList);
+ break;
+
+ case alac_align_vertical_distribute:
+ alignVerticalDistribute(widgetList);
+ break;
+
+ case alac_align_horizontal_distribute:
+ alignHorizontalDistribute(widgetList);
+ break;
+
+ } // switch (btn)
+
+ // update associations
+ it.toFirst();
+ while ((widget = it.current()) != 0) {
+ ++it;
+ widget->updateWidget();
+ }
+ UMLApp::app()->getDocument()->setModified();
+ } else {
+ KMessageBox::messageBox(0, KMessageBox::Information,
+ i18n("For alignment you have to select at least 2 objects like classes or actors. You can not align associations."),
+ i18n("Information"), i18n("&OK"), QString(""),
+ "showAlignInformation");
+ } // if (widgetList.count() > 1)
+
+ return;
+}
+
+#include "aligntoolbar.moc"
diff --git a/umbrello/umbrello/aligntoolbar.h b/umbrello/umbrello/aligntoolbar.h
new file mode 100644
index 00000000..271e9c0b
--- /dev/null
+++ b/umbrello/umbrello/aligntoolbar.h
@@ -0,0 +1,224 @@
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * copyright (C) 2004-2006 *
+ * Umbrello UML Modeller Authors <uml-devel@uml.sf.net> *
+ ***************************************************************************/
+
+#ifndef ALIGNTOOLBAR_H
+#define ALIGNTOOLBAR_H
+
+#include <qpixmap.h>
+#include <ktoolbar.h>
+#include "umlnamespace.h"
+#include "umlwidgetlist.h"
+
+class QMainWindow;
+class UMLWidget;
+
+/**
+ * This toolbar provides tools for alignment. Widgets can only be aligned, when
+ * there are at least 2 widgets (not associations) are selected
+ *
+ * @short Toolbar providing alignment tools.
+ * @author Sebastian Stein <seb.kde@hpfsc.de>
+ * Bugs and comments to uml-devel@lists.sf.net or http://bugs.kde.org
+ */
+class AlignToolBar : public KToolBar {
+ Q_OBJECT
+public:
+
+ /**
+ * Creates a bar with tools for alignment.
+ *
+ * @param parentWindow The parent of the toolbar.
+ * @param name The name of the toolbar.
+ */
+ AlignToolBar(QMainWindow* parentWindow, const char* name);
+
+ /**
+ * Standard deconstructor.
+ */
+ ~AlignToolBar();
+
+private:
+
+ /**
+ * Returns true if the first widget's X is smaller than second's.
+ * Used for sorting the UMLWidgetList.
+ *
+ * @param widget1 The widget to compare.
+ * @param widget2 The widget to compare with.
+ */
+ static bool hasWidgetSmallerX(const UMLWidget* widget1, const UMLWidget* widget2);
+
+ /**
+ * Returns true if the first widget's Y is smaller than second's.
+ * Used for sorting the UMLWidgetList.
+ *
+ * @param widget1 The widget to compare.
+ * @param widget2 The widget to compare with.
+ */
+ static bool hasWidgetSmallerY(const UMLWidget* widget1, const UMLWidget* widget2);
+
+ /**
+ * Loads toolbar icon.
+ */
+ void loadPixmaps();
+
+ /**
+ * Looks for the smallest x-value of the given UMLWidgets.
+ *
+ * @param widgetList A list with UMLWidgets.
+ */
+ int getSmallestX(const UMLWidgetList &widgetList);
+
+ /**
+ * Looks for the smallest y-value of the given UMLWidgets.
+ *
+ * @param widgetList A list with UMLWidgets.
+ */
+ int getSmallestY(const UMLWidgetList &widgetList);
+
+ /**
+ * Looks for the biggest x-value of the given UMLWidgets.
+ *
+ * @param widgetList A list with UMLWidgets.
+ */
+ int getBiggestX(const UMLWidgetList &widgetList);
+
+ /**
+ * Looks for the biggest y-value of the given UMLWidgets.
+ *
+ * @param widgetList A list with UMLWidgets.
+ */
+ int getBiggestY(const UMLWidgetList &widgetList);
+
+ /**
+ * Returns the sum of the heights of the given UMLWidgets
+ *
+ * @param widgetList A list with UMLWidgets.
+ */
+ int getHeightsSum(const UMLWidgetList &widgetList);
+
+ /**
+ * Returns the sum of the widths of the given UMLWidgets.
+ *
+ * @param widgetList A list with UMLWidgets.
+ */
+ int getWidthsSum(const UMLWidgetList &widgetList);
+
+ /**
+ * Aligns all the widgets in the list to the left.
+ *
+ * @param widgetList The list with the widgets to align.
+ */
+ void alignLeft(UMLWidgetList &widgetList);
+
+ /**
+ * Aligns all the widgets in the list to the right.
+ *
+ * @param widgetList The list with the widgets to align.
+ */
+ void alignRight(UMLWidgetList &widgetList);
+
+ /**
+ * Aligns all the widgets in the list to the top.
+ *
+ * @param widgetList The list with the widgets to align.
+ */
+ void alignTop(UMLWidgetList &widgetList);
+
+ /**
+ * Aligns all the widgets in the list to the bottom.
+ *
+ * @param widgetList The list with the widgets to align.
+ */
+ void alignBottom(UMLWidgetList &widgetList);
+
+ /**
+ * Aligns all the widgets in the list to the vertical middle.
+ *
+ * @param widgetList The list with the widgets to align.
+ */
+ void alignVerticalMiddle(UMLWidgetList &widgetList);
+
+ /**
+ * Aligns all the widgets in the list to the horizontal middle.
+ *
+ * @param widgetList The list with the widgets to align.
+ */
+ void alignHorizontalMiddle(UMLWidgetList &widgetList);
+
+ /**
+ * Distributes all the widgets in the list at the same vertical distance
+ * from one widget to the next.
+ *
+ * @param widgetList The list with the widgets to distribute.
+ */
+ void alignVerticalDistribute(UMLWidgetList &widgetList);
+
+ /**
+ * Distributes all the widgets in the list at the same horizontal distance
+ * from one widget to the next.
+ *
+ * @param widgetList The list with the widgets to distribute.
+ */
+ void alignHorizontalDistribute(UMLWidgetList &widgetList);
+
+ /**
+ * Sorts the given UMLWidgetList based on the Compare function.
+ * The list is cleared and all the widgets are added again in order.
+ *
+ * The comp function gets two const UMLWidget* params and returns
+ * a boolean telling if the first widget was smaller than the second,
+ * whatever the "smaller" concept is depending on the sorting to do.
+ *
+ * @param widgetList The list with the widgets to order.
+ * @param comp The comp function to compare the widgets.
+ */
+ template<typename Compare>
+ void sortWidgetList(UMLWidgetList &widgetList, Compare comp);
+
+ /**
+ * Used to identify the buttons.
+ */
+ enum AlignAction
+ {
+ alac_align_left = 0,
+ alac_align_right,
+ alac_align_top,
+ alac_align_bottom,
+ alac_align_vertical_middle,
+ alac_align_horizontal_middle,
+ alac_align_vertical_distribute,
+ alac_align_horizontal_distribute,
+ alac_none
+ };
+
+ /**
+ * Holds the number of buttons.
+ */
+ static const unsigned nrAlignButtons = (unsigned) alac_none -
+ (unsigned) alac_align_left;
+
+ /**
+ * Holds the icons for the different buttons.
+ */
+ QPixmap m_Pixmaps[nrAlignButtons];
+
+private slots:
+
+ /**
+ * Performs the alignment when a button was clicked.
+ *
+ * @param btn The clicked button.
+ */
+ void slotButtonChanged(int btn);
+};
+
+#endif
diff --git a/umbrello/umbrello/artifact.cpp b/umbrello/umbrello/artifact.cpp
new file mode 100644
index 00000000..12f77966
--- /dev/null
+++ b/umbrello/umbrello/artifact.cpp
@@ -0,0 +1,57 @@
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * copyright (C) 2003-2006 *
+ * Umbrello UML Modeller Authors <uml-devel@uml.sf.net> *
+ ***************************************************************************/
+
+#include "artifact.h"
+#include "association.h"
+#include "clipboard/idchangelog.h"
+#include <kdebug.h>
+#include <klocale.h>
+
+UMLArtifact::UMLArtifact(const QString & name, Uml::IDType id)
+ : UMLCanvasObject(name, id) {
+ init();
+}
+
+UMLArtifact::~UMLArtifact() {
+}
+
+void UMLArtifact::init() {
+ m_BaseType = Uml::ot_Artifact;
+ m_drawAsType = defaultDraw;
+}
+
+UMLObject* UMLArtifact::clone() const {
+ UMLArtifact *clone = new UMLArtifact();
+ UMLObject::copyInto(clone);
+ return clone;
+}
+
+void UMLArtifact::saveToXMI(QDomDocument& qDoc, QDomElement& qElement) {
+ QDomElement artifactElement = UMLObject::save("UML:Artifact", qDoc);
+ artifactElement.setAttribute("drawas", m_drawAsType);
+ qElement.appendChild(artifactElement);
+}
+
+bool UMLArtifact::load(QDomElement& element) {
+ QString drawAs = element.attribute("drawas", "0");
+ m_drawAsType = (Draw_Type)drawAs.toInt();
+ return true;
+}
+
+void UMLArtifact::setDrawAsType(Draw_Type type) {
+ m_drawAsType = type;
+}
+
+UMLArtifact::Draw_Type UMLArtifact::getDrawAsType() {
+ return m_drawAsType;
+}
+
+#include "artifact.moc"
diff --git a/umbrello/umbrello/artifact.h b/umbrello/umbrello/artifact.h
new file mode 100644
index 00000000..8b76f154
--- /dev/null
+++ b/umbrello/umbrello/artifact.h
@@ -0,0 +1,97 @@
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * copyright (C) 2003-2006 *
+ * Umbrello UML Modeller Authors <uml-devel@uml.sf.net> *
+ ***************************************************************************/
+
+#ifndef ARTIFACT_H
+#define ARTIFACT_H
+
+#include "umlcanvasobject.h"
+
+
+/**
+ * This class contains the non-graphical information required for a UML
+ * Artifact.
+ * This class inherits from @ref UMLCanvasObject which contains most of the
+ * information.
+ *
+ * @short Non-graphical information for a Artifact.
+ * @author Jonathan Riddell
+ * @see UMLCanvasObject
+ * Bugs and comments to uml-devel@lists.sf.net or http://bugs.kde.org
+ */
+class UMLArtifact : public UMLCanvasObject {
+ Q_OBJECT
+public:
+
+ /**
+ * Artifacts can be drawn using one of several icons.
+ */
+ enum Draw_Type {
+ defaultDraw,
+ file,
+ library,
+ table
+ };
+
+ /**
+ * Sets up a Artifact.
+ *
+ * @param Name The name of the Concept.
+ * @param id The unique id of the Concept.
+ */
+ explicit UMLArtifact(const QString & Name = "", Uml::IDType id = Uml::id_None);
+
+ /**
+ * Standard deconstructor.
+ */
+ virtual ~UMLArtifact();
+
+ /**
+ * Initializes key variables of the class.
+ */
+ virtual void init();
+
+ /**
+ * Make a clone of this object.
+ */
+ virtual UMLObject* clone() const;
+
+ /**
+ * Creates the UML:Artifact element including its operations,
+ * attributes and templates
+ */
+ void saveToXMI( QDomDocument & qDoc, QDomElement & qElement );
+
+ /**
+ * sets m_drawAsType for which method to draw the artifact as
+ */
+ void setDrawAsType(Draw_Type type);
+
+ /**
+ * returns the value of m_drawAsType
+ */
+ Draw_Type getDrawAsType();
+
+protected:
+ /**
+ * Loads the UML:Artifact element including its operations,
+ * attributes and templates
+ */
+ bool load( QDomElement & element );
+
+private:
+ /**
+ * Artifacts can be drawn as one of several different icons,
+ * this value choosing how to draw them.
+ */
+ Draw_Type m_drawAsType;
+};
+
+#endif
diff --git a/umbrello/umbrello/artifactwidget.cpp b/umbrello/umbrello/artifactwidget.cpp
new file mode 100644
index 00000000..931f757a
--- /dev/null
+++ b/umbrello/umbrello/artifactwidget.cpp
@@ -0,0 +1,259 @@
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * copyright (C) 2003-2007 *
+ * Umbrello UML Modeller Authors <uml-devel@uml.sf.net> *
+ ***************************************************************************/
+
+// own header
+#include "artifactwidget.h"
+
+// qt/kde includes
+#include <qpainter.h>
+#include <qpointarray.h>
+#include <kdebug.h>
+
+// app includes
+#include "artifact.h"
+#include "umlview.h"
+
+
+ArtifactWidget::ArtifactWidget(UMLView *view, UMLArtifact *a) : UMLWidget(view, a) {
+ init();
+ setSize(100, 30);
+ updateComponentSize();
+}
+
+
+void ArtifactWidget::init() {
+ UMLWidget::setBaseType( Uml::wt_Artifact );
+ m_pMenu = 0;
+}
+
+ArtifactWidget::~ArtifactWidget() {}
+
+void ArtifactWidget::drawAsNormal(QPainter& p, int offsetX, int offsetY) {
+ int w = width();
+ int h = height();
+ QFont font = UMLWidget::getFont();
+ font.setBold(true);
+ const QFontMetrics &fm = getFontMetrics(FT_BOLD);
+ const int fontHeight = fm.lineSpacing();
+ QString name = getName();
+ QString stereotype = m_pObject->getStereotype();
+
+ p.drawRect(offsetX, offsetY, w, h);
+
+ p.setPen( QPen(Qt::black) );
+ p.setFont(font);
+
+ if (!stereotype.isEmpty()) {
+ p.drawText(offsetX + ARTIFACT_MARGIN, offsetY + (h/2) - fontHeight,
+ w, fontHeight, Qt::AlignCenter, m_pObject->getStereotype(true));
+ }
+
+ int lines;
+ if (!stereotype.isEmpty()) {
+ lines = 2;
+ } else {
+ lines = 1;
+ }
+
+ if (lines == 1) {
+ p.drawText(offsetX, offsetY + (h/2) - (fontHeight/2),
+ w, fontHeight, Qt::AlignCenter, name);
+ } else {
+ p.drawText(offsetX, offsetY + (h/2),
+ w, fontHeight, Qt::AlignCenter, name);
+ }
+
+ if(m_bSelected) {
+ drawSelected(&p, offsetX, offsetY);
+ }
+}
+
+void ArtifactWidget::drawAsFile(QPainter& p, int offsetX, int offsetY) {
+ const int w = width();
+ const int h = height();
+ QFont font = UMLWidget::getFont();
+ const QFontMetrics &fm = getFontMetrics(FT_NORMAL);
+ const int fontHeight = fm.lineSpacing();
+ const QString name = getName();
+
+ int startX = offsetX + (w/2) - 25;
+ int iconHeight = h - fontHeight;
+ QPointArray pointArray(5);
+ pointArray.setPoint(0, startX, offsetY);
+ pointArray.setPoint(1, startX + 40, offsetY);
+ pointArray.setPoint(2, startX + 50, offsetY + 10);
+ pointArray.setPoint(3, startX + 50, offsetY + iconHeight);
+ pointArray.setPoint(4, startX, offsetY + iconHeight);
+ p.drawPolygon(pointArray);
+
+ p.drawLine(startX + 40, offsetY, startX + 40, offsetY + 10);
+ p.drawLine(startX + 40, offsetY + 10, startX + 50, offsetY + 10);
+ p.drawLine(startX + 40, offsetY, startX + 50, offsetY + 10);
+
+ p.setPen( QPen(Qt::black) );
+ p.setFont(font);
+
+ p.drawText(offsetX, offsetY + h - fontHeight,
+ w, fontHeight, Qt::AlignCenter, name);
+
+ if(m_bSelected) {
+ drawSelected(&p, offsetX, offsetY);
+ }
+}
+
+void ArtifactWidget::drawAsLibrary(QPainter& p, int offsetX, int offsetY) {
+ //FIXME this should have gears on it
+ const int w = width();
+ const int h = height();
+ const QFont font = UMLWidget::getFont();
+ const QFontMetrics &fm = getFontMetrics(FT_NORMAL);
+ const int fontHeight = fm.lineSpacing();
+ const QString name = getName();
+
+ const int startX = offsetX + (w/2) - 25;
+ const int iconHeight = h - fontHeight;
+ QPointArray pointArray(5);
+ pointArray.setPoint(0, startX, offsetY);
+ pointArray.setPoint(1, startX + 40, offsetY);
+ pointArray.setPoint(2, startX + 50, offsetY + 10);
+ pointArray.setPoint(3, startX + 50, offsetY + iconHeight);
+ pointArray.setPoint(4, startX, offsetY + iconHeight);
+ p.drawPolygon(pointArray);
+
+ p.drawLine(startX + 40, offsetY, startX + 40, offsetY + 10);
+ p.drawLine(startX + 40, offsetY + 10, startX + 50, offsetY + 10);
+ p.drawLine(startX + 40, offsetY, startX + 50, offsetY + 10);
+
+ p.setPen( QPen(Qt::black) );
+ p.setFont(font);
+
+ p.drawText(offsetX, offsetY + h - fontHeight,
+ w, fontHeight, Qt::AlignCenter, name);
+
+ if(m_bSelected) {
+ drawSelected(&p, offsetX, offsetY);
+ }
+}
+
+void ArtifactWidget::drawAsTable(QPainter& p, int offsetX, int offsetY) {
+ const int w = width();
+ const int h = height();
+ const QFont font = UMLWidget::getFont();
+ const QFontMetrics &fm = getFontMetrics(FT_NORMAL);
+ const int fontHeight = fm.lineSpacing();
+ const QString name = getName();
+
+ const int startX = offsetX + (w/2) - 25;
+ const int iconHeight = h - fontHeight;
+
+ p.drawRect(startX, offsetY, 50, h - fontHeight + 1);
+ p.drawLine(startX + 20, offsetY, startX + 20, offsetY + iconHeight);
+ p.drawLine(startX + 30, offsetY, startX + 30, offsetY + iconHeight);
+ p.drawLine(startX + 40, offsetY, startX + 40, offsetY + iconHeight);
+ p.drawLine(startX, offsetY + (iconHeight/2), startX + 49, offsetY + (iconHeight/2));
+ p.drawLine(startX, offsetY + (iconHeight/2) + (iconHeight/4),
+ startX + 49, offsetY + (iconHeight/2) + (iconHeight/4));
+
+ QPen thickerPen = p.pen();
+ thickerPen.setWidth(2);
+ p.setPen(thickerPen);
+ p.drawLine(startX + 10, offsetY, startX + 10, offsetY + iconHeight);
+ p.drawLine(startX, offsetY + (iconHeight/4), startX + 50, offsetY + (iconHeight/4));
+
+ p.setPen( QPen(Qt::black) );
+ p.setFont(font);
+
+ p.drawText(offsetX, offsetY + h - fontHeight,
+ w, fontHeight, Qt::AlignCenter, name);
+
+ if(m_bSelected) {
+ drawSelected(&p, offsetX, offsetY);
+ }
+}
+
+void ArtifactWidget::draw(QPainter& p, int offsetX, int offsetY) {
+ UMLWidget::setPen(p);
+ if ( UMLWidget::getUseFillColour() ) {
+ p.setBrush( UMLWidget::getFillColour() );
+ } else {
+ p.setBrush( m_pView->viewport()->backgroundColor() );
+ }
+
+ UMLArtifact *umlart = static_cast<UMLArtifact*>(m_pObject);
+ UMLArtifact::Draw_Type drawType = umlart->getDrawAsType();
+ switch (drawType) {
+ case UMLArtifact::defaultDraw:
+ return drawAsNormal(p, offsetX, offsetY);
+ break;
+ case UMLArtifact::file:
+ return drawAsFile(p, offsetX, offsetY);
+ break;
+ case UMLArtifact::library:
+ return drawAsLibrary(p, offsetX, offsetY);
+ break;
+ case UMLArtifact::table:
+ return drawAsTable(p, offsetX, offsetY);
+ break;
+ default:
+ kWarning() << "Artifact drawn as unknown type" << endl;
+ break;
+ }
+}
+
+QSize ArtifactWidget::calculateIconSize() {
+ const QFontMetrics &fm = getFontMetrics(FT_BOLD_ITALIC);
+ const int fontHeight = fm.lineSpacing();
+
+ int width = fm.width( m_pObject->getName() );
+
+ width = width<50 ? 50 : width;
+
+ int height = 50 + fontHeight;
+
+ return QSize(width, height);
+}
+
+QSize ArtifactWidget::calculateNormalSize() {
+ const QFontMetrics &fm = getFontMetrics(FT_BOLD_ITALIC);
+ const int fontHeight = fm.lineSpacing();
+
+ int width = fm.width( m_pObject->getName() );
+
+ int tempWidth = 0;
+ if(!m_pObject->getStereotype().isEmpty()) {
+ tempWidth = fm.width( m_pObject->getStereotype(true) );
+ }
+ width = tempWidth>width ? tempWidth : width;
+ width += ARTIFACT_MARGIN * 2;
+
+ int height = (2*fontHeight) + (ARTIFACT_MARGIN * 2);
+
+ return QSize(width, height);
+}
+
+QSize ArtifactWidget::calculateSize() {
+ if ( !m_pObject) {
+ return UMLWidget::calculateSize();
+ }
+ UMLArtifact *umlart = static_cast<UMLArtifact*>(m_pObject);
+ if (umlart->getDrawAsType() == UMLArtifact::defaultDraw) {
+ return calculateNormalSize();
+ } else {
+ return calculateIconSize();
+ }
+}
+
+void ArtifactWidget::saveToXMI(QDomDocument& qDoc, QDomElement& qElement) {
+ QDomElement conceptElement = qDoc.createElement("artifactwidget");
+ UMLWidget::saveToXMI(qDoc, conceptElement);
+ qElement.appendChild(conceptElement);
+}
+
diff --git a/umbrello/umbrello/artifactwidget.h b/umbrello/umbrello/artifactwidget.h
new file mode 100644
index 00000000..a68f3acc
--- /dev/null
+++ b/umbrello/umbrello/artifactwidget.h
@@ -0,0 +1,107 @@
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * copyright (C) 2003-2006 *
+ * Umbrello UML Modeller Authors <uml-devel@uml.sf.net> *
+ ***************************************************************************/
+
+#ifndef ARTIFACTWIDGET_H
+#define ARTIFACTWIDGET_H
+
+
+#include "umlwidget.h"
+
+class UMLView;
+class UMLArtifact;
+
+#define ARTIFACT_MARGIN 5
+
+/**
+ * Defines a graphical version of the Artifact.
+ * Most of the functionality will come from the @ref UMLArtifact class.
+ *
+ * @short A graphical version of a Artifact.
+ * @author Jonathan Riddell
+ * @see UMLWidget
+ * Bugs and comments to uml-devel@lists.sf.net or http://bugs.kde.org
+ */
+class ArtifactWidget : public UMLWidget {
+public:
+
+ /**
+ * Constructs a ArtifactWidget.
+ *
+ * @param view The parent of this ArtifactWidget.
+ * @param a The Artifact this widget will be representing.
+ */
+ ArtifactWidget(UMLView *view, UMLArtifact *a);
+
+ /**
+ * destructor
+ */
+ virtual ~ArtifactWidget();
+
+ /**
+ * Overrides standard method
+ */
+ void draw(QPainter& p, int offsetX, int offsetY);
+
+ /**
+ * Saves the widget to the "artifactwidget" XMI element.
+ * Note: For loading from XMI, the inherited parent method is used.
+ */
+ void saveToXMI(QDomDocument& qDoc, QDomElement& qElement);
+
+protected:
+ /**
+ * Overrides method from UMLWidget.
+ */
+ QSize calculateSize();
+
+private:
+ /**
+ * Initializes key variables of the class.
+ */
+ void init();
+
+ /**
+ * calculates the size when drawing as an icon (it's the same size for all icons)
+ */
+ QSize calculateIconSize();
+
+ /**
+ * calculates the size for drawing as a box
+ */
+ QSize calculateNormalSize();
+
+ /**
+ * draw as a file icon
+ */
+ void drawAsFile(QPainter& p, int offsetX, int offsetY);
+
+ /**
+ * draw as a library file icon
+ */
+ void drawAsLibrary(QPainter& p, int offsetX, int offsetY);
+
+ /**
+ * draw as a database table icon
+ */
+ void drawAsTable(QPainter& p, int offsetX, int offsetY);
+
+ /**
+ * draw as a box
+ */
+ void drawAsNormal(QPainter& p, int offsetX, int offsetY);
+
+ /**
+ * The right mouse button menu
+ */
+ ListPopupMenu* m_pMenu;
+};
+
+#endif
diff --git a/umbrello/umbrello/association.cpp b/umbrello/umbrello/association.cpp
new file mode 100644
index 00000000..eacc8d13
--- /dev/null
+++ b/umbrello/umbrello/association.cpp
@@ -0,0 +1,574 @@
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * copyright (C) 2003-2006 *
+ * Umbrello UML Modeller Authors <uml-devel@uml.sf.net> *
+ ***************************************************************************/
+
+// own header
+#include "association.h"
+// qt/kde includes
+#include <kdebug.h>
+#include <klocale.h>
+#include <qregexp.h>
+// app includes
+#include "classifier.h"
+#include "folder.h"
+#include "uml.h"
+#include "umldoc.h"
+#include "umlrole.h"
+#include "uniqueid.h"
+#include "model_utils.h"
+
+using namespace Uml;
+
+// static members
+const Uml::Association_Type UMLAssociation::atypeFirst = Uml::at_Generalization;
+const Uml::Association_Type UMLAssociation::atypeLast = Uml::at_Relationship;
+const unsigned UMLAssociation::nAssocTypes = (unsigned)atypeLast -
+ (unsigned)atypeFirst + 1;
+
+// constructor
+UMLAssociation::UMLAssociation( Uml::Association_Type type,
+ UMLObject * roleA, UMLObject * roleB )
+ : UMLObject("")
+{
+ init(type, roleA, roleB);
+
+ m_pRole[Uml::A]->setID( UniqueID::gen() );
+ m_pRole[Uml::B]->setID( UniqueID::gen() );
+}
+
+UMLAssociation::UMLAssociation( Uml::Association_Type type /* = Uml::at_Unknown */)
+ : UMLObject("", Uml::id_Reserved)
+{
+ init(type, NULL, NULL);
+}
+
+// destructor
+UMLAssociation::~UMLAssociation( ) {
+ if (m_pRole[A] == NULL) {
+ kError() << "UMLAssociation destructor: m_pRole[A] is NULL already"
+ << endl;
+ } else {
+ delete m_pRole[A];
+ m_pRole[A] = NULL;
+ }
+ if (m_pRole[B] == NULL) {
+ kError() << "UMLAssociation destructor: m_pRole[B] is NULL already"
+ << endl;
+ } else {
+ delete m_pRole[B];
+ m_pRole[B] = NULL;
+ }
+}
+
+bool UMLAssociation::operator==(UMLAssociation &rhs) {
+ if (this == &rhs) {
+ return true;
+ }
+ return ( UMLObject::operator== ( rhs ) &&
+ m_AssocType == rhs.m_AssocType &&
+ m_Name == rhs.m_Name &&
+ m_pRole[A] == rhs.m_pRole[A] &&
+ m_pRole[B] == rhs.m_pRole[B] );
+}
+
+const QString UMLAssociation::assocTypeStr[UMLAssociation::nAssocTypes] = {
+ /* The elements must be listed in the same order as in the
+ Uml::Association_Type. */
+ i18n("Generalization"), // at_Generalization
+ i18n("Aggregation"), // at_Aggregation
+ i18n("Dependency"), // at_Dependency
+ i18n("Association"), // at_Association
+ i18n("Self Association"), // at_Association_Self
+ i18n("Collaboration Message"), // at_Coll_Message
+ i18n("Sequence Message"), // at_Seq_Message
+ i18n("Collaboration Self Message"), // at_Coll_Message_Self
+ i18n("Sequence Self Message"), // at_Seq_Message_Self
+ i18n("Containment"), // at_Containment
+ i18n("Composition"), // at_Composition
+ i18n("Realization"), // at_Realization
+ i18n("Uni Association"), // at_UniAssociation
+ i18n("Anchor"), // at_Anchor
+ i18n("State Transition"), // at_State
+ i18n("Activity"), // at_Activity
+ };
+
+Uml::Association_Type UMLAssociation::getAssocType() const {
+ return m_AssocType;
+}
+
+QString UMLAssociation::toString ( ) const
+{
+ QString string;
+ if(m_pRole[A])
+ {
+ string += m_pRole[A]->getObject()->getName();
+ string += ':';
+ string += m_pRole[A]->getName();
+ }
+ string += ':' + typeAsString(m_AssocType) + ':';
+ if(m_pRole[B])
+ {
+ string += m_pRole[B]->getObject( )->getName();
+ string += ':';
+ string += m_pRole[B]->getName();
+ }
+ return string;
+}
+
+QString UMLAssociation::typeAsString (Uml::Association_Type atype)
+{
+ if (atype < atypeFirst || atype > atypeLast)
+ return "";
+ return assocTypeStr[(unsigned)atype - (unsigned)atypeFirst];
+}
+
+bool UMLAssociation::assocTypeHasUMLRepresentation(Uml::Association_Type atype)
+{
+ return (atype == Uml::at_Generalization ||
+ atype == Uml::at_Realization ||
+ atype == Uml::at_Association ||
+ atype == Uml::at_Association_Self ||
+ atype == Uml::at_UniAssociation ||
+ atype == Uml::at_Aggregation ||
+ atype == Uml::at_Relationship ||
+ atype == Uml::at_Composition ||
+ atype == Uml::at_Dependency);
+}
+
+bool UMLAssociation::resolveRef() {
+ bool successA = getUMLRole(A)->resolveRef();
+ bool successB = getUMLRole(B)->resolveRef();
+ if (successA && successB) {
+ UMLObject *objA = getUMLRole(A)->getObject();
+ UMLObject *objB = getUMLRole(B)->getObject();
+ // Check if need to change the assoc type to Realization
+ if (m_AssocType == Uml::at_Generalization &&
+ (objA && objA->getBaseType() == Uml::ot_Interface ||
+ objB && objB->getBaseType() == Uml::ot_Interface))
+ m_AssocType = Uml::at_Realization;
+ m_pUMLPackage->addAssocToConcepts(this);
+ return true;
+ }
+ return false;
+}
+
+void UMLAssociation::saveToXMI( QDomDocument & qDoc, QDomElement & qElement ) {
+ if (m_AssocType == Uml::at_Generalization) {
+ QDomElement assocElement = UMLObject::save("UML:Generalization", qDoc);
+ assocElement.setAttribute( "discriminator", "" );
+ assocElement.setAttribute( "child", ID2STR(getObjectId(A)) );
+ assocElement.setAttribute( "parent", ID2STR(getObjectId(B)) );
+ qElement.appendChild( assocElement );
+ return;
+ }
+ if (m_AssocType == Uml::at_Realization) {
+ QDomElement assocElement = UMLObject::save("UML:Abstraction", qDoc);
+ assocElement.setAttribute( "client", ID2STR(getObjectId(A)) );
+ assocElement.setAttribute( "supplier", ID2STR(getObjectId(B)) );
+ qElement.appendChild( assocElement );
+ return;
+ }
+ if (m_AssocType == Uml::at_Dependency) {
+ QDomElement assocElement = UMLObject::save("UML:Dependency", qDoc);
+ assocElement.setAttribute( "client", ID2STR(getObjectId(A)) );
+ assocElement.setAttribute( "supplier", ID2STR(getObjectId(B)) );
+ qElement.appendChild( assocElement );
+ return;
+ }
+ QDomElement associationElement = UMLObject::save("UML:Association", qDoc);
+ QDomElement connElement = qDoc.createElement("UML:Association.connection");
+ getUMLRole(A)->saveToXMI (qDoc, connElement);
+ getUMLRole(B)->saveToXMI (qDoc, connElement);
+ associationElement.appendChild (connElement);
+ qElement.appendChild( associationElement );
+}
+
+bool UMLAssociation::load( QDomElement & element ) {
+ if (getID() == Uml::id_None)
+ return false; // old style XMI file. No real info in this association.
+
+ UMLDoc * doc = UMLApp::app()->getDocument();
+ UMLObject * obj[2] = { NULL, NULL };
+ if (m_AssocType == Uml::at_Generalization ||
+ m_AssocType == Uml::at_Realization ||
+ m_AssocType == Uml::at_Dependency) {
+ for (unsigned r = Uml::A; r <= Uml::B; r++) {
+ const QString fetch = (m_AssocType == Uml::at_Generalization ?
+ r == Uml::A ? "child" : "parent"
+ : r == Uml::A ? "client" : "supplier");
+ QString roleIdStr = element.attribute(fetch, "");
+ if (roleIdStr.isEmpty()) {
+ // Might be given as a child node instead - see below.
+ continue;
+ }
+
+ // set umlobject of role if possible (else defer resolution)
+ obj[r] = doc->findObjectById(STR2ID(roleIdStr));
+ Uml::Role_Type role = (Uml::Role_Type)r;
+ if (obj[r] == NULL) {
+ m_pRole[role]->setSecondaryId(roleIdStr); // defer to resolveRef()
+ } else {
+ m_pRole[role]->setObject(obj[r]);
+ if (m_pUMLPackage == NULL) {
+ Uml::Model_Type mt = Model_Utils::convert_OT_MT(obj[r]->getBaseType());
+ m_pUMLPackage = doc->getRootFolder(mt);
+ kDebug() << "UMLAssociation::load(assoctype " << m_AssocType
+ << "): setting model type " << mt << endl;
+ }
+ }
+ }
+ if (obj[A] == NULL || obj[B] == NULL) {
+ for (QDomNode node = element.firstChild(); !node.isNull();
+ node = node.nextSibling()) {
+ if (node.isComment())
+ continue;
+ QDomElement tempElement = node.toElement();
+ QString tag = tempElement.tagName();
+ if (Model_Utils::isCommonXMIAttribute(tag))
+ continue;
+ // Permitted tag names:
+ // roleA: "child" "subtype" "client"
+ // roleB: "parent" "supertype" "supplier"
+ QString idStr = tempElement.attribute( "xmi.id", "" );
+ if (idStr.isEmpty())
+ idStr = tempElement.attribute( "xmi.idref", "" );
+ if (idStr.isEmpty()) {
+ QDomNode inner = node.firstChild();
+ QDomElement tmpElem = inner.toElement();
+ idStr = tmpElem.attribute( "xmi.id", "" );
+ if (idStr.isEmpty())
+ idStr = tmpElem.attribute( "xmi.idref", "" );
+ }
+ if (idStr.isEmpty()) {
+ kError() << "UMLAssociation::load (type " << m_AssocType
+ << ", id " << ID2STR(getID()) << "): "
+ << "xmi id not given for " << tag << endl;
+ continue;
+ }
+ // Since we know for sure that we're dealing with a non
+ // umbrello file, use deferred resolution unconditionally.
+ if (tagEq(tag, "child") || tagEq(tag, "subtype") || tagEq(tag, "client")) {
+ getUMLRole(A)->setSecondaryId(idStr);
+ } else {
+ getUMLRole(B)->setSecondaryId(idStr);
+ }
+ }
+ }
+
+ // its a realization if either endpoint is an interface
+ if (m_AssocType == Uml::at_Generalization &&
+ (obj[A] && obj[A]->getBaseType() == Uml::ot_Interface ||
+ obj[B] && obj[B]->getBaseType() == Uml::ot_Interface))
+ m_AssocType = Uml::at_Realization;
+
+ return true;
+ }
+
+ for (QDomNode node = element.firstChild(); !node.isNull();
+ node = node.nextSibling()) {
+ // uml13.dtd compliant format (new style)
+ if (node.isComment())
+ continue;
+ QDomElement tempElement = node.toElement();
+ QString tag = tempElement.tagName();
+ if (Model_Utils::isCommonXMIAttribute(tag))
+ continue;
+ if (!tagEq(tag, "Association.connection") &&
+ !tagEq(tag, "Namespace.ownedElement") &&
+ !tagEq(tag, "Namespace.contents")) {
+ kWarning() << "UMLAssociation::load: "
+ << "unknown child node " << tag << endl;
+ continue;
+ }
+ // Load role A.
+ node = tempElement.firstChild();
+ while (node.isComment())
+ node = node.nextSibling();
+ tempElement = node.toElement();
+ if (tempElement.isNull()) {
+ kWarning() << "UML:Association : element (A) is Null" << endl;
+ return false;
+ }
+ tag = tempElement.tagName();
+ if (!tagEq(tag, "AssociationEndRole") &&
+ !tagEq(tag, "AssociationEnd")) {
+ kWarning() << "UMLAssociation::load: "
+ << "unknown child (A) tag " << tag << endl;
+ return false;
+ }
+ if (! getUMLRole(A)->loadFromXMI(tempElement))
+ return false;
+ // Load role B.
+ node = node.nextSibling();
+ while (node.isComment())
+ node = node.nextSibling();
+ tempElement = node.toElement();
+ if (tempElement.isNull()) {
+ kWarning() << "UML:Association : element (B) is Null" << endl;
+ return false;
+ }
+ tag = tempElement.tagName();
+ if (!tagEq(tag, "AssociationEndRole") &&
+ !tagEq(tag, "AssociationEnd")) {
+ kWarning() << "UMLAssociation::load: "
+ << "unknown child (B) tag " << tag << endl;
+ return false;
+ }
+ if (! getUMLRole(B)->loadFromXMI(tempElement))
+ return false;
+
+ if (m_pUMLPackage == NULL) {
+ Uml::Model_Type mt = Model_Utils::convert_OT_MT(getObject(B)->getBaseType());
+ m_pUMLPackage = doc->getRootFolder(mt);
+ kDebug() << "UMLAssociation::load: setting model type " << mt << endl;
+ }
+
+ // setting the association type:
+ //
+ // In the old days, we could just record this on the association,
+ // and be done with it. But thats not how the UML13.dtd does things.
+ // As a result, we are checking roleA for information about the
+ // parent association (!) which by this point in the parse, should
+ // be set. However, the information that the roles are allowed to have
+ // is not complete, so we need to finish the analysis here.
+
+ // find self-associations
+ if (m_AssocType == Uml::at_Association && getObjectId(A) == getObjectId(B))
+ m_AssocType = Uml::at_Association_Self;
+
+ // fall-back default type
+ if (m_AssocType == Uml::at_Unknown) {
+ m_AssocType = Uml::at_Association;
+ }
+
+ return true;
+ }
+
+ // From here on it's old-style stuff.
+ QString assocTypeStr = element.attribute( "assoctype", "-1" );
+ Uml::Association_Type assocType = Uml::at_Unknown;
+ if (assocTypeStr[0] >= 'a' && assocTypeStr[0] <= 'z') {
+ // In an earlier version, the natural assoctype names were saved.
+ const QString assocTypeString[nAssocTypes] = {
+ "generalization", // at_Generalization
+ "aggregation", // at_Aggregation
+ "dependency", // at_Dependency
+ "association", // at_Association
+ "associationself", // at_Association_Self
+ "collmessage", // at_Coll_Message
+ "seqmessage", // at_Seq_Message
+ "collmessageself", // at_Coll_Message_Self
+ "seqmessageself", // at_Seq_Message_Self
+ "implementation", // at_Implementation
+ "composition", // at_Composition
+ "realization", // at_Realization
+ "uniassociation", // at_UniAssociation
+ "anchor", // at_Anchor
+ "state", // at_State
+ "activity", // at_Activity
+ "relationship" // at_Relationship
+ };
+
+ unsigned index;
+ for (index = 0; index < nAssocTypes; index++)
+ if (assocTypeStr == assocTypeString[index])
+ break;
+ if (index < nAssocTypes)
+ assocType = (Uml::Association_Type)index;
+ } else {
+ int assocTypeNum = assocTypeStr.toInt();
+ if (assocTypeNum < (int)atypeFirst || assocTypeNum > (int)atypeLast) {
+ kWarning() << "bad assoctype of UML:Association "
+ << ID2STR(getID()) << endl;
+ return false;
+ }
+ assocType = (Uml::Association_Type)assocTypeNum;
+ }
+ setAssocType( assocType );
+
+ Uml::IDType roleAObjID = STR2ID(element.attribute( "rolea", "-1" ));
+ Uml::IDType roleBObjID = STR2ID(element.attribute( "roleb", "-1" ));
+ if (assocType == at_Aggregation || assocType == at_Composition) {
+ // Flip roles to compensate for changed diamond logic in LinePath.
+ // For further explanations see AssociationWidget::loadFromXMI.
+ Uml::IDType tmp = roleAObjID;
+ roleAObjID = roleBObjID;
+ roleBObjID = tmp;
+ }
+
+ UMLObject * objA = doc->findObjectById(roleAObjID);
+ UMLObject * objB = doc->findObjectById(roleBObjID);
+
+ if(objA)
+ getUMLRole(A)->setObject(objA);
+ else
+ return false;
+
+ if(objB)
+ getUMLRole(B)->setObject(objB);
+ else
+ return false;
+
+ setMulti(element.attribute( "multia", "" ), A);
+ setMulti(element.attribute( "multib", "" ), B);
+
+ setRoleName(element.attribute( "namea", "" ), A);
+ setRoleName(element.attribute( "nameb", "" ), B);
+
+ setRoleDoc(element.attribute( "doca", "" ), A);
+ setRoleDoc(element.attribute( "docb", "" ), B);
+
+ // Visibility defaults to Public if it cant set it here..
+ QString visibilityA = element.attribute( "visibilitya", "0");
+ QString visibilityB = element.attribute( "visibilityb", "0");
+ if (visibilityA.toInt() > 0)
+ setVisibility((Uml::Visibility::Value)visibilityA.toInt(), A);
+ if (visibilityB.toInt() > 0)
+ setVisibility((Uml::Visibility::Value)visibilityB.toInt(), B);
+
+ // Changeability defaults to Changeable if it cant set it here..
+ QString changeabilityA = element.attribute( "changeabilitya", "0");
+ QString changeabilityB = element.attribute( "changeabilityb", "0");
+ if (changeabilityA.toInt() > 0)
+ setChangeability ( (Uml::Changeability_Type) changeabilityA.toInt(), A);
+ if (changeabilityB.toInt() > 0)
+ setChangeability ( (Uml::Changeability_Type) changeabilityB.toInt(), B);
+
+ return true;
+}
+
+UMLObject* UMLAssociation::getObject(Uml::Role_Type role) {
+ return m_pRole[role]->getObject();
+}
+
+Uml::IDType UMLAssociation::getObjectId(Uml::Role_Type role) {
+ UMLRole *roleObj = m_pRole[role];
+ UMLObject *o = roleObj->getObject();
+ if (o == NULL) {
+ QString auxID = roleObj->getSecondaryId();
+ if (auxID.isEmpty()) {
+ kError() << "UMLAssociation::getObjectId(" << role
+ << "): getObject returns NULL" << endl;
+ return Uml::id_None;
+ } else {
+ kDebug() << "UMLAssociation::getObjectId(" << role
+ << "): using secondary ID " << auxID << endl;
+ return STR2ID(auxID);
+ }
+ }
+ return o->getID();
+}
+
+/* CURRENTLY UNUSED
+Uml::IDType UMLAssociation::getRoleId(Role_Type role) const {
+ return m_pRole[role]->getID();
+}
+ */
+
+Uml::Changeability_Type UMLAssociation::getChangeability(Uml::Role_Type role) const {
+ return m_pRole[role]->getChangeability();
+}
+
+Uml::Visibility UMLAssociation::getVisibility(Uml::Role_Type role) const {
+ return m_pRole[role]->getVisibility();
+}
+
+QString UMLAssociation::getMulti(Uml::Role_Type role) const {
+ return m_pRole[role]->getMultiplicity();
+}
+
+QString UMLAssociation::getRoleName(Uml::Role_Type role) const {
+ return m_pRole[role]->getName();
+}
+
+QString UMLAssociation::getRoleDoc(Uml::Role_Type role) const {
+ return m_pRole[role]->getDoc();
+}
+
+UMLRole * UMLAssociation::getUMLRole(Uml::Role_Type role) {
+ return m_pRole[role];
+}
+
+void UMLAssociation::setOldLoadMode(bool value /* = true */) {
+ m_bOldLoadMode = value;
+}
+
+bool UMLAssociation::getOldLoadMode() const {
+ return m_bOldLoadMode;
+}
+
+void UMLAssociation::setAssocType(Uml::Association_Type assocType) {
+ m_AssocType = assocType;
+ if(m_AssocType == at_UniAssociation)
+ {
+ // In this case we need to auto-set the multiplicity/rolenames
+ // of the roles
+#ifdef VERBOSE_DEBUGGING
+ kDebug() << " A new uni-association has been created." << endl;
+#endif
+ }
+ UMLDoc *umldoc = UMLApp::app()->getDocument();
+ if (! umldoc->loading())
+ emit modified();
+}
+
+void UMLAssociation::setObject(UMLObject *obj, Uml::Role_Type role) {
+ m_pRole[role]->setObject(obj);
+}
+
+void UMLAssociation::setVisibility(Uml::Visibility value, Uml::Role_Type role) {
+ m_pRole[role]->setVisibility(value);
+}
+
+void UMLAssociation::setChangeability(Uml::Changeability_Type value, Uml::Role_Type role) {
+ m_pRole[role]->setChangeability(value);
+}
+
+void UMLAssociation::setMulti(const QString &value, Uml::Role_Type role) {
+ m_pRole[role]->setMultiplicity(value);
+}
+
+void UMLAssociation::setRoleName(const QString &value, Uml::Role_Type role) {
+ m_pRole[role]->setName(value);
+}
+
+void UMLAssociation::setRoleDoc(const QString &doc, Uml::Role_Type role) {
+ m_pRole[role]->setDoc(doc);
+}
+
+QString UMLAssociation::ChangeabilityToString(Uml::Changeability_Type type) {
+ switch (type) {
+ case Uml::chg_Frozen:
+ return "frozen";
+ break;
+ case Uml::chg_AddOnly:
+ return "addOnly";
+ break;
+ case Uml::chg_Changeable:
+ default:
+ return "changeable";
+ break;
+ }
+}
+
+void UMLAssociation::init(Uml::Association_Type type, UMLObject *roleAObj, UMLObject *roleBObj) {
+ m_AssocType = type;
+ m_BaseType = ot_Association;
+ m_Name = "";
+ m_bOldLoadMode = false;
+ nrof_parent_widgets = -1;
+ if (!UMLApp::app()->getDocument()->loading())
+ m_pUMLPackage = UMLApp::app()->getDocument()->currentRoot();
+ m_pRole[Uml::A] = new UMLRole (this, roleAObj, Uml::A);
+ m_pRole[Uml::B] = new UMLRole (this, roleBObj, Uml::B);
+}
+
+
+#include "association.moc"
diff --git a/umbrello/umbrello/association.h b/umbrello/umbrello/association.h
new file mode 100644
index 00000000..3b0ef94d
--- /dev/null
+++ b/umbrello/umbrello/association.h
@@ -0,0 +1,290 @@
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * copyright (C) 2003-2006 *
+ * Umbrello UML Modeller Authors <uml-devel@uml.sf.net> *
+ ***************************************************************************/
+
+#ifndef ASSOCIATION_H
+#define ASSOCIATION_H
+
+#include <qdom.h>
+#include "umlnamespace.h"
+#include "umlobject.h"
+
+class UMLRole;
+
+/**
+ * This class contains the non-graphic representation of an association.
+ * An association can be a generalization, realization, simple association,
+ * directed association, aggregation, or composition.
+ *
+ * @short Sets up association information.
+ * @author Oliver Kellogg <okellogg@users.sourceforge.net>
+ * @see UMLObject
+ * Bugs and comments to uml-devel@lists.sf.net or http://bugs.kde.org
+ */
+
+class UMLAssociation : public UMLObject {
+ Q_OBJECT
+ friend class AssociationWidget;
+public:
+ /**
+ * Sets up an association.
+ * A new unique ID is assigned internally.
+ *
+ * @param type The Uml::Association_Type to construct.
+ * @param roleA Pointer to the UMLObject in role A.
+ * @param roleB Pointer to the UMLObject in role B.
+ */
+ UMLAssociation(Uml::Association_Type type, UMLObject *roleA, UMLObject *roleB);
+
+ /**
+ * Constructs an association - for loading only.
+ * This constructor should not normally be used as it constructs
+ * an incomplete association (i.e. the role objects are missing.)
+ *
+ * @param type The Uml::Association_Type to construct.
+ * Default: Uml::at_Unknown.
+ */
+ UMLAssociation(Uml::Association_Type type = Uml::at_Unknown);
+
+ /**
+ * Overloaded '==' operator
+ */
+ bool operator==(UMLAssociation &rhs);
+
+ /**
+ * Standard deconstructor.
+ */
+ virtual ~UMLAssociation();
+
+ /**
+ * Returns a String representation of this UMLAssociation.
+ */
+ QString toString( ) const;
+
+ /**
+ * Converts a Uml::Association_Type to its string representation.
+ *
+ * @param atype The Association_Type enum value to convert.
+ * @return The string representation of the Association_Type.
+ */
+ static QString typeAsString(Uml::Association_Type atype);
+
+ /**
+ * Returns true if the given Association_Type has a representation as a
+ * UMLAssociation.
+ */
+ static bool assocTypeHasUMLRepresentation(Uml::Association_Type atype);
+
+ /**
+ * Returns the Association_Type of the UMLAssociation.
+ *
+ * @return The Association_Type of the UMLAssociation.
+ */
+ Uml::Association_Type getAssocType() const;
+
+ /**
+ * Returns the UMLObject assigned to the given role.
+ *
+ * @return Pointer to the UMLObject in the given role.
+ */
+ UMLObject* getObject(Uml::Role_Type role);
+
+ /**
+ * Returns the ID of the UMLObject assigned to the given role.
+ * Shorthand for getObject(role)->getID().
+ *
+ * @return ID of the UMLObject in the given role.
+ */
+ Uml::IDType getObjectId(Uml::Role_Type role);
+
+ /*
+ * Returns the ID of the UMLObject assigned to the given role.
+ * CURRENTLY UNUSED.
+ *
+ * @return ID of the UMLObject of the given role.
+ Uml::IDType getRoleId(Uml::Role_Type role) const;
+ */
+
+ /**
+ * Returns the Changeablity of the given role.
+ *
+ * @return Changeability_Type of the given role.
+ */
+ Uml::Changeability_Type getChangeability(Uml::Role_Type role) const;
+
+ /**
+ * Returns the Visibility of the given role.
+ *
+ * @return Visibility of the given role.
+ */
+ Uml::Visibility getVisibility(Uml::Role_Type role) const;
+
+ /**
+ * Returns the multiplicity assigned to the given role.
+ *
+ * @return The multiplicity assigned to the given role.
+ */
+ QString getMulti(Uml::Role_Type role) const;
+
+ /**
+ * Returns the name assigned to the role A.
+ *
+ * @return The name assigned to the given role.
+ */
+ QString getRoleName(Uml::Role_Type role) const;
+
+ /**
+ * Returns the documentation assigned to the given role.
+ *
+ * @return Documentation text of given role.
+ */
+ QString getRoleDoc(Uml::Role_Type role) const;
+
+ /**
+ * Sets the assocType of the UMLAssociation.
+ *
+ * @param assocType The Association_Type of the UMLAssociation.
+ */
+ void setAssocType(Uml::Association_Type assocType);
+
+ /**
+ * Sets the UMLObject playing the given role in the association.
+ *
+ * @param obj Pointer to the UMLObject of the given role.
+ * @param role The Uml::Role_Type played by the association
+ */
+ void setObject(UMLObject *obj, Uml::Role_Type role);
+
+ /**
+ * Sets the visibility of the given role of the UMLAssociation.
+ *
+ * @param value Visibility of role.
+ * @param role The Uml::Role_Type to which the visibility is being applied
+ */
+ void setVisibility(Uml::Visibility value, Uml::Role_Type role);
+
+ /**
+ * Sets the changeability of the given role of the UMLAssociation.
+ *
+ * @param value Changeability_Type of the given role.
+ * @param role The Uml::Role_Type to which the changeability is being set
+ */
+ void setChangeability(Uml::Changeability_Type value, Uml::Role_Type role);
+
+ /**
+ * Sets the multiplicity of the given role of the UMLAssociation.
+ *
+ * @param multi The multiplicity of the given role.
+ * @param role The Uml::Role_Type to which the multiplicity is being applied
+ */
+ void setMulti(const QString &multi, Uml::Role_Type role);
+
+ /**
+ * Sets the name of the given role of the UMLAssociation.
+ *
+ * @param roleName The name to set for the given role.
+ * @param role The Uml::Role_Type for which to set the name.
+ */
+ void setRoleName(const QString &roleName, Uml::Role_Type role);
+
+ /**
+ * Sets the documentation on the given role in the association.
+ *
+ * @param doc The string with the documentation.
+ * @param role The Uml::Role_Type to which the documentation is being applied
+ */
+ void setRoleDoc(const QString &doc, Uml::Role_Type role);
+
+ /**
+ * Convert Changeability_Type value into QString representation.
+ *
+ * @param type The Changeability_Type enum value to convert.
+ */
+ static QString ChangeabilityToString(Uml::Changeability_Type type);
+
+ /**
+ * Get the underlying UMLRole object for the given role.
+ *
+ * @return Pointer to the UMLRole object for the given role.
+ */
+ UMLRole * getUMLRole(Uml::Role_Type role);
+
+ /**
+ * Set backward compatibility flag for loading version 1.3.x files.
+ * This flag is necessary because the handling of the isNavigable
+ * attribute of <UML:AssociationEnd> was incorrect.
+ */
+ void setOldLoadMode(bool value = true);
+
+ /**
+ * Return the backward compatibility flag for loading files.
+ */
+ bool getOldLoadMode() const;
+
+ /**
+ * Make a clone of this object.
+ * Cloning associations is not supported yet.
+ */
+ virtual UMLObject* clone() const { return NULL; }
+
+ /**
+ * Resolve types. Required when dealing with foreign XMI files.
+ * Needs to be called after all UML objects are loaded from file.
+ * Overrides the method from UMLObject.
+ * Calls resolveRef() for each role.
+ *
+ * @return True for success.
+ */
+ virtual bool resolveRef();
+
+ /**
+ * Creates the <UML:Generalization> or <UML:Association> XMI element
+ * including its role objects.
+ */
+ void saveToXMI(QDomDocument& qDoc, QDomElement& qElement);
+
+protected:
+ /**
+ * Creates the <UML:Generalization> or <UML:Association> XMI element
+ * including its role objects.
+ */
+ bool load(QDomElement& element);
+
+ // keep track of number of parent widgets
+ int nrof_parent_widgets;
+
+ /**
+ * Common initializations at construction time.
+ *
+ * @param type The Association_Type to represent.
+ * @param roleAObj Pointer to the role A UMLObject.
+ * @param roleBObj Pointer to the role B UMLObject.
+ */
+ void init(Uml::Association_Type type, UMLObject *roleAObj, UMLObject *roleBObj);
+
+ /* If the type Uml::Association_Type is changed then also the following
+ must be changed accordingly:
+ atypeFirst, atypeLast, assocTypeStr[], toAssocType(), toString().
+ The ordering within assocTypeStr must match the enumeration
+ order of Uml::Association_Type.
+ */
+ static const Uml::Association_Type atypeFirst;
+ static const Uml::Association_Type atypeLast;
+ static const unsigned int nAssocTypes;
+ static const QString assocTypeStr[];
+
+ UMLRole * m_pRole[2];
+
+ Uml::Association_Type m_AssocType;
+ QString m_Name;
+ bool m_bOldLoadMode;
+};
+
+#endif
diff --git a/umbrello/umbrello/associationwidget.cpp b/umbrello/umbrello/associationwidget.cpp
new file mode 100644
index 00000000..3f2fe0b7
--- /dev/null
+++ b/umbrello/umbrello/associationwidget.cpp
@@ -0,0 +1,3614 @@
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * copyright (C) 2002-2007 *
+ * Umbrello UML Modeller Authors <uml-devel@uml.sf.net> *
+ ***************************************************************************/
+
+// own header
+#include "associationwidget.h"
+// system includes
+#include <cstdlib>
+#include <cmath>
+// qt/kde includes
+#include <qcanvas.h>
+#include <qvalidator.h>
+#include <kdebug.h>
+#include <klocale.h>
+#include <kinputdialog.h>
+#include <kcolordialog.h>
+#include <kapplication.h>
+// app includes
+#include "activitywidget.h"
+#include "uml.h"
+#include "umlview.h"
+#include "umldoc.h"
+#include "umlwidget.h"
+#include "messagewidget.h"
+#include "umlrole.h"
+#include "listpopupmenu.h"
+#include "classifierwidget.h"
+#include "classifier.h"
+#include "entity.h"
+#include "attribute.h"
+#include "operation.h"
+#include "association.h"
+#include "assocrules.h"
+#include "floatingtextwidget.h"
+#include "objectwidget.h"
+#include "model_utils.h"
+#include "widget_utils.h"
+#include "dialogs/assocpropdlg.h"
+#include "optionstate.h"
+
+using namespace Uml;
+
+// this constructor really only for loading from XMI, otherwise it
+// is bad..and shouldn't be allowed as it creates an incomplete
+// associationwidget.
+AssociationWidget::AssociationWidget(UMLView *view)
+ : WidgetBase(view)
+{
+ init(view);
+}
+
+// the preferred constructor
+AssociationWidget::AssociationWidget(UMLView *view, UMLWidget* pWidgetA,
+ Uml::Association_Type assocType, UMLWidget* pWidgetB,
+ UMLObject *umlobject /* = NULL */)
+ : WidgetBase(view)
+{
+ init(view);
+ if (umlobject) {
+ setUMLObject(umlobject);
+ } else {
+ // set up UMLAssociation obj if assoc is represented and both roles are UML objects
+ if (UMLAssociation::assocTypeHasUMLRepresentation(assocType)) {
+ UMLObject* umlRoleA = pWidgetA->getUMLObject();
+ UMLObject* umlRoleB = pWidgetB->getUMLObject();
+ if (umlRoleA != NULL && umlRoleB != NULL) {
+ bool swap;
+
+ // THis isnt correct. We could very easily have more than one
+ // of the same type of association between the same two objects.
+ // Just create the association. This search should have been
+ // done BEFORE creation of the widget, if it mattered to the code.
+ // But lets leave check in here for the time being so that debugging
+ // output is shown, in case there is a collision with code elsewhere.
+ UMLAssociation * myAssoc = m_umldoc->findAssociation( assocType, umlRoleA, umlRoleB, &swap );
+ if (myAssoc != NULL) {
+ if (assocType == at_Generalization) {
+ kDebug() << " Ignoring second construction of same generalization"
+ << endl;
+ } else {
+ kDebug() << " constructing a similar or exact same assoc " <<
+ "as an already existing assoc (swap=" << swap << ")" << endl;
+ // now, just create a new association anyways
+ myAssoc = NULL;
+ }
+ }
+ if (myAssoc == NULL)
+ myAssoc = new UMLAssociation( assocType, umlRoleA, umlRoleB );
+ setUMLAssociation(myAssoc);
+ }
+ }
+ }
+
+ setWidget(pWidgetA, A);
+ setWidget(pWidgetB, B);
+
+ setAssocType(assocType);
+
+ calculateEndingPoints();
+
+ //The AssociationWidget is set to Activated because it already has its side widgets
+ setActivated(true);
+
+ // sync UML meta-data to settings here
+ mergeAssociationDataIntoUMLRepresentation();
+
+ // Collaboration messages need a name label because it's that
+ // which lets operator== distinguish them, which in turn
+ // permits us to have more than one message between two objects.
+ if (isCollaboration()) {
+ // Create a temporary name to bring on setName()
+ int collabID = m_pView->generateCollaborationId();
+ setName('m' + QString::number(collabID));
+ }
+}
+
+AssociationWidget::~AssociationWidget() {
+}
+
+AssociationWidget& AssociationWidget::operator=(AssociationWidget & Other) {
+ m_LinePath = Other.m_LinePath;
+
+ m_pView = Other.m_pView;
+
+ if (Other.m_pName) {
+ m_pName = new FloatingTextWidget(m_pView);
+ *m_pName = *(Other.m_pName);
+ } else {
+ m_pName = NULL;
+ }
+
+ for (unsigned r = (unsigned)A; r <= (unsigned)B; r++) {
+ WidgetRole& lhs = m_role[r];
+ const WidgetRole& rhs = Other.m_role[r];
+ lhs.m_nIndex = rhs.m_nIndex;
+ lhs.m_nTotalCount = rhs.m_nTotalCount;
+
+ if (rhs.m_pMulti) {
+ lhs.m_pMulti = new FloatingTextWidget(m_pView);
+ *(lhs.m_pMulti) = *(rhs.m_pMulti);
+ } else {
+ lhs.m_pMulti = NULL;
+ }
+
+ if (rhs.m_pRole) {
+ lhs.m_pRole = new FloatingTextWidget(m_pView);
+ *(lhs.m_pRole) = *(rhs.m_pRole);
+ } else {
+ lhs.m_pRole = NULL;
+ }
+
+ if (rhs.m_pChangeWidget) {
+ lhs.m_pChangeWidget = new FloatingTextWidget(m_pView);
+ *(lhs.m_pChangeWidget) = *(rhs.m_pChangeWidget);
+ } else {
+ lhs.m_pChangeWidget = NULL;
+ }
+
+ lhs.m_pWidget = rhs.m_pWidget;
+ lhs.m_OldCorner = rhs.m_OldCorner;
+ lhs.m_WidgetRegion = rhs.m_WidgetRegion;
+ }
+
+ m_bActivated = Other.m_bActivated;
+ m_unNameLineSegment = Other.m_unNameLineSegment;
+ m_pMenu = Other.m_pMenu;
+ setUMLAssociation(Other.getAssociation());
+ m_bSelected = Other.m_bSelected;
+ m_nMovingPoint = Other.m_nMovingPoint;
+
+ return *this;
+}
+
+bool AssociationWidget::operator==(AssociationWidget & Other) {
+ if( this == &Other )
+ return true;
+
+ if( !m_pObject || !Other.m_pObject ) {
+ if( !Other.m_pObject && m_pObject )
+ return false;
+ if( Other.m_pObject && !m_pObject )
+ return false;
+ } else if( m_pObject != Other.m_pObject )
+ return false;
+
+ if (getAssocType() != Other.getAssocType())
+ return false;
+
+ if (getWidgetID(A) != Other.getWidgetID(A))
+ return false;
+
+ if (getWidgetID(B) != Other.getWidgetID(B))
+ return false;
+
+ if (getWidget(A)->getBaseType() == Uml::wt_Object &&
+ Other.getWidget(A)->getBaseType() == Uml::wt_Object) {
+ ObjectWidget *ownA = static_cast<ObjectWidget*>(getWidget(A));
+ ObjectWidget *otherA = static_cast<ObjectWidget*>(Other.getWidget(A));
+ if (ownA->getLocalID() != otherA->getLocalID())
+ return false;
+ }
+
+ if (getWidget(B)->getBaseType() == Uml::wt_Object &&
+ Other.getWidget(B)->getBaseType() == Uml::wt_Object) {
+ ObjectWidget *ownB = static_cast<ObjectWidget*>(getWidget(B));
+ ObjectWidget *otherB = static_cast<ObjectWidget*>(Other.getWidget(B));
+ if (ownB->getLocalID() != otherB->getLocalID())
+ return false;
+ }
+
+ // Two objects in a collaboration can have multiple messages between each other.
+ // Here we depend on the messages having names, and the names must be different.
+ // That is the reason why collaboration messages have strange initial names like
+ // "m29997" or similar.
+ return (getName() == Other.getName());
+}
+
+bool AssociationWidget::operator!=(AssociationWidget & Other) {
+ return !(*this == Other);
+}
+
+UMLAssociation * AssociationWidget::getAssociation () const {
+ if (m_pObject == NULL || m_pObject->getBaseType() != ot_Association)
+ return NULL;
+ return static_cast<UMLAssociation*>(m_pObject);
+}
+
+UMLAttribute * AssociationWidget::getAttribute () const {
+ if (m_pObject == NULL)
+ return NULL;
+ Uml::Object_Type ot = m_pObject->getBaseType();
+ if (ot != ot_Attribute && ot != ot_EntityAttribute)
+ return NULL;
+ return static_cast<UMLAttribute*>(m_pObject);
+}
+
+FloatingTextWidget* AssociationWidget::getMultiWidget(Uml::Role_Type role) {
+ return m_role[role].m_pMulti;
+}
+
+QString AssociationWidget::getMulti(Uml::Role_Type role) const
+{
+ if (m_role[role].m_pMulti == NULL)
+ return "";
+ return m_role[role].m_pMulti->getText();
+}
+
+FloatingTextWidget* AssociationWidget::getNameWidget()
+{
+ return m_pName;
+}
+
+QString AssociationWidget::getName() const {
+ if (m_pName == NULL)
+ return "";
+ return m_pName->getText();
+}
+
+FloatingTextWidget* AssociationWidget::getRoleWidget(Uml::Role_Type role) {
+ return m_role[role].m_pRole;
+}
+
+FloatingTextWidget* AssociationWidget::getChangeWidget(Uml::Role_Type role) {
+ return m_role[role].m_pChangeWidget;
+}
+
+FloatingTextWidget* AssociationWidget::getTextWidgetByRole(Uml::Text_Role tr) {
+ switch (tr) {
+ case tr_MultiA:
+ return m_role[A].m_pMulti;
+ case tr_MultiB:
+ return m_role[B].m_pMulti;
+ case tr_Name:
+ case tr_Coll_Message:
+ return m_pName;
+ case tr_RoleAName:
+ return m_role[A].m_pRole;
+ case tr_RoleBName:
+ return m_role[B].m_pRole;
+ case tr_ChangeA:
+ return m_role[A].m_pChangeWidget;
+ case tr_ChangeB:
+ return m_role[B].m_pChangeWidget;
+ default:
+ break;
+ }
+ return NULL;
+}
+
+QString AssociationWidget::getRoleName(Uml::Role_Type role) const {
+ if (m_role[role].m_pRole == NULL)
+ return "";
+ return m_role[role].m_pRole->getText();
+}
+
+QString AssociationWidget::getRoleDoc(Uml::Role_Type role) const {
+ if (m_pObject == NULL || m_pObject->getBaseType() != ot_Association)
+ return "";
+ UMLAssociation *umla = static_cast<UMLAssociation*>(m_pObject);
+ return umla->getRoleDoc(role);
+}
+
+void AssociationWidget::setName(const QString &strName) {
+ // set attribute of UMLAssociation associated with this associationwidget
+ UMLAssociation *umla = getAssociation();
+ if (umla)
+ umla->setName(strName);
+
+ bool newLabel = false;
+ if(!m_pName) {
+ // Don't construct the FloatingTextWidget if the string is empty.
+ if (! FloatingTextWidget::isTextValid(strName))
+ return;
+
+ newLabel = true;
+ m_pName = new FloatingTextWidget(m_pView, CalculateNameType(tr_Name), strName);
+ m_pName->setLink(this);
+ } else {
+ m_pName->setText(strName);
+ if (! FloatingTextWidget::isTextValid(strName)) {
+ //m_pName->hide();
+ m_pView->removeWidget(m_pName);
+ m_pName = NULL;
+ return;
+ }
+ }
+
+ setTextPosition( tr_Name );
+ if (newLabel) {
+ m_pName->setActivated();
+ m_pView->addWidget(m_pName);
+ }
+
+ m_pName->show();
+}
+
+void AssociationWidget::setFloatingText(Uml::Text_Role tr,
+ const QString &text,
+ FloatingTextWidget* &ft) {
+ if (! FloatingTextWidget::isTextValid(text)) {
+ if (ft) {
+ // Remove preexisting FloatingTextWidget
+ m_pView->removeWidget(ft); // physically deletes ft
+ ft = NULL;
+ }
+ return;
+ }
+
+ if (ft == NULL) {
+ ft = new FloatingTextWidget(m_pView, tr, text);
+ ft->setLink(this);
+ ft->activate();
+ setTextPosition(tr);
+ m_pView->addWidget(ft);
+ } else {
+ bool newLabel = ft->getText().isEmpty();
+ ft->setText(text);
+ if (newLabel)
+ setTextPosition(tr);
+ }
+
+ ft->show();
+}
+
+void AssociationWidget::setMulti(const QString &strMulti, Uml::Role_Type role) {
+ Text_Role tr = (role == A ? tr_MultiA : tr_MultiB);
+
+ setFloatingText(tr, strMulti, m_role[role].m_pMulti);
+
+ if (m_pObject && m_pObject->getBaseType() == ot_Association)
+ getAssociation()->setMulti(strMulti, role);
+}
+
+void AssociationWidget::setRoleName (const QString &strRole, Uml::Role_Type role) {
+ Uml::Association_Type type = getAssocType();
+ //if the association is not supposed to have a Role FloatingTextWidget
+ if (!AssocRules::allowRole(type)) {
+ return;
+ }
+
+ Text_Role tr = (role == A ? tr_RoleAName : tr_RoleBName);
+ setFloatingText(tr, strRole, m_role[role].m_pRole);
+ if (m_role[role].m_pRole) {
+ Uml::Visibility vis = getVisibility(role);
+ if (FloatingTextWidget::isTextValid(m_role[role].m_pRole->getText())) {
+ m_role[role].m_pRole->setPreText(vis.toString(true));
+ //m_role[role].m_pRole->show();
+ } else {
+ m_role[role].m_pRole->setPreText("");
+ //m_role[role].m_pRole->hide();
+ }
+ }
+
+ // set attribute of UMLAssociation associated with this associationwidget
+ if (m_pObject && m_pObject->getBaseType() == ot_Association)
+ getAssociation()->setRoleName(strRole, role);
+}
+
+void AssociationWidget::setRoleDoc (const QString &doc, Uml::Role_Type role) {
+ if (m_pObject && m_pObject->getBaseType() == ot_Association)
+ getAssociation()->setRoleDoc(doc, role);
+ else
+ m_role[role].m_RoleDoc = doc;
+}
+
+void AssociationWidget::setMessageText(FloatingTextWidget *ft) {
+ QString message;
+ if (isCollaboration()) {
+ if (m_pObject != NULL) {
+ message = getMulti(A) + ": " + getOperationText(m_pView);
+ } else {
+ message = getMulti(A) + ": " + getName();
+ }
+ } else {
+ message = getName();
+ }
+ ft->setText(message);
+}
+
+Uml::Visibility AssociationWidget::getVisibility(Uml::Role_Type role) const {
+ const UMLAssociation *assoc = getAssociation();
+ if (assoc)
+ return assoc->getVisibility(role);
+ const UMLAttribute *attr = getAttribute();
+ if (attr)
+ return attr->getVisibility();
+ return m_role[role].m_Visibility;
+}
+
+void AssociationWidget::setVisibility(Uml::Visibility value, Uml::Role_Type role)
+{
+ if (value == getVisibility(role))
+ return;
+ if (m_pObject) {
+ // update our model object
+ const Uml::Object_Type ot = m_pObject->getBaseType();
+ if (ot == ot_Association)
+ getAssociation()->setVisibility(value, role);
+ else if (ot == ot_Attribute)
+ getAttribute()->setVisibility(value);
+ }
+ m_role[role].m_Visibility = value;
+ // update role pre-text attribute as appropriate
+ if (m_role[role].m_pRole) {
+ QString scopeString = value.toString(true);
+ m_role[role].m_pRole->setPreText(scopeString);
+ }
+}
+
+Uml::Changeability_Type AssociationWidget::getChangeability(Uml::Role_Type role) const
+{
+ if (m_pObject == NULL || m_pObject->getBaseType() != ot_Association)
+ return m_role[role].m_Changeability;
+ UMLAssociation *umla = static_cast<UMLAssociation*>(m_pObject);
+ return umla->getChangeability(role);
+}
+
+void AssociationWidget::setChangeability (Uml::Changeability_Type value, Uml::Role_Type role)
+{
+ if (value == getChangeability(role))
+ return;
+ QString changeString = UMLAssociation::ChangeabilityToString(value);
+ if (m_pObject && m_pObject->getBaseType() == ot_Association) // update our model object
+ getAssociation()->setChangeability(value, role);
+ m_role[role].m_Changeability = value;
+ // update our string representation
+ setChangeWidget(changeString, role);
+}
+
+void AssociationWidget::setChangeWidget(const QString &strChangeWidget, Uml::Role_Type role) {
+ bool newLabel = false;
+ Text_Role tr = (role == A ? tr_ChangeA : tr_ChangeB);
+
+ if(!m_role[role].m_pChangeWidget) {
+ // Don't construct the FloatingTextWidget if the string is empty.
+ if (strChangeWidget.isEmpty())
+ return;
+
+ newLabel = true;
+ m_role[role].m_pChangeWidget = new FloatingTextWidget(m_pView, tr, strChangeWidget);
+ m_role[role].m_pChangeWidget->setLink(this);
+ m_pView->addWidget(m_role[role].m_pChangeWidget);
+ m_role[role].m_pChangeWidget->setPreText("{"); // all types have this
+ m_role[role].m_pChangeWidget->setPostText("}"); // all types have this
+ } else {
+ if (m_role[role].m_pChangeWidget->getText().isEmpty()) {
+ newLabel = true;
+ }
+ m_role[role].m_pChangeWidget->setText(strChangeWidget);
+ }
+ m_role[role].m_pChangeWidget->setActivated();
+
+ if (newLabel) {
+ setTextPosition( tr );
+ }
+
+ if(FloatingTextWidget::isTextValid(m_role[role].m_pChangeWidget->getText()))
+ m_role[role].m_pChangeWidget -> show();
+ else
+ m_role[role].m_pChangeWidget -> hide();
+}
+
+bool AssociationWidget::linePathStartsAt(const UMLWidget* widget) {
+ QPoint lpStart = m_LinePath.getPoint(0);
+ int startX = lpStart.x();
+ int startY = lpStart.y();
+ int wX = widget->getX();
+ int wY = widget->getY();
+ int wWidth = widget->getWidth();
+ int wHeight = widget->getHeight();
+ bool result = (startX >= wX && startX <= wX + wWidth &&
+ startY >= wY && startY <= wY + wHeight);
+ return result;
+}
+
+void AssociationWidget::setText(FloatingTextWidget *ft, const QString &text) {
+ Uml::Text_Role role = ft->getRole();
+ switch (role) {
+ case tr_Name:
+ setName(text);
+ break;
+ case tr_RoleAName:
+ setRoleName(text, A);
+ break;
+ case tr_RoleBName:
+ setRoleName(text, B);
+ break;
+ case tr_MultiA:
+ setMulti(text, A);
+ break;
+ case tr_MultiB:
+ setMulti(text, B);
+ break;
+ default:
+ break;
+ }
+}
+
+bool AssociationWidget::activate() {
+ if (m_pObject == NULL &&
+ UMLAssociation::assocTypeHasUMLRepresentation(m_AssocType)) {
+ UMLObject *myObj = m_umldoc->findObjectById(m_nId);
+ if (myObj == NULL) {
+ kError() << "AssociationWidget::activate: cannot find UMLObject "
+ << ID2STR(m_nId) << endl;
+ return false;
+ } else {
+ const Uml::Object_Type ot = myObj->getBaseType();
+ if (ot == ot_Association) {
+ UMLAssociation * myAssoc = static_cast<UMLAssociation*>(myObj);
+ setUMLAssociation(myAssoc);
+ m_LinePath.setAssocType( myAssoc->getAssocType() );
+ } else {
+ setUMLObject(myObj);
+ setAssocType(m_AssocType);
+ }
+ }
+ }
+
+ if (m_bActivated)
+ return true;
+
+ Uml::Association_Type type = getAssocType();
+
+ if (m_role[A].m_pWidget == NULL)
+ setWidget(m_pView->findWidget(getWidgetID(A)), A);
+ if (m_role[B].m_pWidget == NULL)
+ setWidget(m_pView->findWidget(getWidgetID(B)), B);
+
+ if(!m_role[A].m_pWidget || !m_role[B].m_pWidget) {
+ kDebug() << "Can't make association" << endl;
+ return false;
+ }
+
+ calculateEndingPoints();
+ m_LinePath.activate();
+
+ if (AssocRules::allowRole(type)) {
+ for (unsigned r = A; r <= B; r++) {
+ WidgetRole& robj = m_role[r];
+ if (robj.m_pRole == NULL)
+ continue;
+ robj.m_pRole->setLink(this);
+ Text_Role tr = (r == A ? tr_RoleAName : tr_RoleBName);
+ robj.m_pRole->setRole(tr);
+ Uml::Visibility vis = getVisibility((Uml::Role_Type)r);
+ robj.m_pRole->setPreText(vis.toString(true));
+
+ if (FloatingTextWidget::isTextValid(robj.m_pRole->getText()))
+ robj.m_pRole -> show();
+ else
+ robj.m_pRole -> hide();
+ if (m_pView->getType() == dt_Collaboration)
+ robj.m_pRole->setUMLObject(robj.m_pWidget->getUMLObject());
+ robj.m_pRole->activate();
+ }
+ }
+
+ if( m_pName != NULL ) {
+ m_pName->setLink(this);
+ m_pName->setRole( CalculateNameType(tr_Name) );
+
+ if ( FloatingTextWidget::isTextValid(m_pName->getText()) ) {
+ m_pName-> show();
+ } else {
+ m_pName-> hide();
+ }
+ m_pName->activate();
+ calculateNameTextSegment();
+ }
+
+ for (unsigned r = A; r <= B; r++) {
+ WidgetRole& robj = m_role[r];
+
+ FloatingTextWidget* pMulti = robj.m_pMulti;
+ if (pMulti != NULL &&
+ AssocRules::allowMultiplicity(type, robj.m_pWidget->getBaseType())) {
+ pMulti->setLink(this);
+ Text_Role tr = (r == A ? tr_MultiA : tr_MultiB);
+ pMulti->setRole(tr);
+ if (FloatingTextWidget::isTextValid(pMulti->getText()))
+ pMulti -> show();
+ else
+ pMulti -> hide();
+ pMulti->activate();
+ }
+
+ FloatingTextWidget* pChangeWidget = robj.m_pChangeWidget;
+ if (pChangeWidget != NULL ) {
+ pChangeWidget->setLink(this);
+ Text_Role tr = (r == A ? tr_ChangeA : tr_ChangeB);
+ pChangeWidget->setRole(tr);
+ if (FloatingTextWidget::isTextValid(pChangeWidget->getText()))
+ pChangeWidget -> show();
+ else
+ pChangeWidget -> hide ();
+ pChangeWidget->activate();
+ }
+ }
+
+ // Prepare the association class line if needed.
+ if (m_pAssocClassWidget && !m_pAssocClassLine) {
+ createAssocClassLine();
+ }
+
+ m_bActivated = true;
+ return true;
+}
+
+/** This function calculates which role should be set for the m_pName FloatingTextWidget */
+Uml::Text_Role AssociationWidget::CalculateNameType(Uml::Text_Role defaultRole) {
+
+ Text_Role result = defaultRole;
+ if( m_pView -> getType() == dt_Collaboration ) {
+ if(m_role[A].m_pWidget == m_role[B].m_pWidget) {
+ result = tr_Coll_Message;//for now same as other Coll_Message
+ } else {
+ result = tr_Coll_Message;
+ }
+ } else if( m_pView -> getType() == dt_Sequence ) {
+ if(m_role[A].m_pWidget == m_role[B].m_pWidget) {
+ result = tr_Seq_Message_Self;
+ } else {
+ result = tr_Seq_Message;
+ }
+ }
+
+ return result;
+}
+
+UMLWidget* AssociationWidget::getWidget(Uml::Role_Type role) {
+ return m_role[role].m_pWidget;
+}
+
+bool AssociationWidget::setWidgets( UMLWidget* widgetA,
+ Uml::Association_Type assocType,
+ UMLWidget* widgetB) {
+ //if the association already has a WidgetB or WidgetA associated, then
+ //it cannot be changed to other widget, that would require a deletion
+ //of the association and the creation of a new one
+ if ((m_role[A].m_pWidget && (m_role[A].m_pWidget != widgetA)) ||
+ (m_role[B].m_pWidget && (m_role[B].m_pWidget != widgetB))) {
+ return false;
+ }
+ setWidget(widgetA, A);
+ setAssocType(assocType);
+ setWidget(widgetB, B);
+
+ calculateEndingPoints();
+ return true;
+}
+
+/** Returns true if this association associates WidgetA to WidgetB, otherwise it returns
+ false */
+bool AssociationWidget::checkAssoc(UMLWidget * widgetA, UMLWidget *widgetB) {
+ return (widgetA == m_role[A].m_pWidget && widgetB == m_role[B].m_pWidget);
+}
+
+/** CleansUp all the association's data in the related widgets */
+void AssociationWidget::cleanup() {
+
+ //let any other associations know we are going so they can tidy their positions up
+ if(m_role[A].m_nTotalCount > 2)
+ updateAssociations(m_role[A].m_nTotalCount - 1, m_role[A].m_WidgetRegion, A);
+ if(m_role[B].m_nTotalCount > 2)
+ updateAssociations(m_role[B].m_nTotalCount - 1, m_role[B].m_WidgetRegion, B);
+
+ for (unsigned r = A; r <= B; r++) {
+ WidgetRole& robj = m_role[r];
+
+ if(robj.m_pWidget) {
+ robj.m_pWidget->removeAssoc(this);
+ robj.m_pWidget = 0;
+ }
+ if(robj.m_pRole) {
+ m_pView->removeWidget(robj.m_pRole);
+ robj.m_pRole = 0;
+ }
+ if(robj.m_pMulti) {
+ m_pView->removeWidget(robj.m_pMulti);
+ robj.m_pMulti = 0;
+ }
+ if(robj.m_pChangeWidget) {
+ m_pView->removeWidget(robj.m_pChangeWidget);
+ robj.m_pChangeWidget = 0;
+ }
+ }
+
+ if(m_pName) {
+ m_pView->removeWidget(m_pName);
+ m_pName = 0;
+ }
+
+ if (m_pObject && m_pObject->getBaseType() == ot_Association) {
+ /*
+ We do not remove the UMLAssociation from the document.
+ Why? - Well, for example we might be in the middle of
+ a cut/paste. If the UMLAssociation is removed by the cut
+ then upon pasteing we have a problem.
+ This is not quite clean yet - there should be a way to
+ explicitly delete a UMLAssociation. The Right Thing would
+ be to have a ListView representation for UMLAssociation.
+ `
+ IF we are cut n pasting, why are we handling this association as a pointer?
+ We should be using the XMI representation for a cut and paste. This
+ allows us to be clean here, AND a choice of recreating the object
+ w/ same id IF its a "cut", or a new object if its a "copy" operation
+ (in which case we wouldnt be here, in cleanup()).
+ */
+ setUMLAssociation(0);
+ }
+
+ m_LinePath.cleanup();
+ removeAssocClassLine();
+}
+
+void AssociationWidget::setUMLAssociation (UMLAssociation * assoc)
+{
+ if (m_pObject && m_pObject->getBaseType() == ot_Association) {
+ UMLAssociation *umla = getAssociation();
+
+ // safety check. Did some num-nuts try to set the existing
+ // association again? If so, just bail here
+ if (assoc && umla == assoc)
+ return;
+
+ //umla->disconnect(this); //Qt does disconnect automatically upon destruction.
+ umla->nrof_parent_widgets--;
+
+ // we are the last "owner" of this association, so delete it
+ // from the parent UMLDoc, and as a stand-alone
+ //DISCUSS: Should we really do this?
+ // It implies that an association's existence is ONLY
+ // governed by its existence on at least one diagram.
+ // OTOH, it might be argued that an association should
+ // further exist even when it's (temporarily) not present
+ // on any diagram. This is exactly what cut and paste
+ // relies on (at least the way it's implemented now)
+ // ANSWER: yes, we *should* do this.
+ // This only implies that IF an association once 'belonged'
+ // to one or more parent associationwidgets, then it must 'die' when the
+ // last widget does. UMLAssociations which never had a parent
+ // in the first place wont be affected by this code, and can happily
+ // live on without a parent.
+ //DISCUSS: Sorry Brian, but this breaks cut/paste.
+ // In particular, cut/paste means that the UMLAssociation _does_
+ // have the assocwidget parent - the only means of doing a cut/paste
+ // on the diagram is via the widgets. I.e. in practice there is no
+ // such thing as an "orphan" UMLAssociation.
+ // BTW, IMHO the concept of a widget being the parent of a UML object
+ // is fundamentally flawed. Widgets are pure presentation - they can
+ // come and go at a whim. If at all, the widgets could be considered
+ // children of the corresponding UML object.
+ //
+ // ANSWER: This is the wrong treatment of cut and paste. Associations that
+ // are being cut/n pasted should be serialized to XMI, then reconstituted
+ // (IF a paste operation) rather than passing around object pointers. Its
+ // just too hard otherwise to prevent problems in the code. Bottom line: we need to
+ // delete orphaned associations or we well get code crashes and memory leaks.
+ if (umla->nrof_parent_widgets == 0) {
+ //umla->deleteLater();
+ }
+
+ m_pObject = NULL;
+ }
+
+ if(assoc) {
+ m_pObject = assoc;
+
+ // move counter to "0" from "-1" (which means, no assocwidgets)
+ if(assoc->nrof_parent_widgets < 0)
+ assoc->nrof_parent_widgets = 0;
+
+ assoc->nrof_parent_widgets++;
+ connect(assoc, SIGNAL(modified()), this, SLOT(syncToModel()));
+ }
+
+}
+
+
+/** Returns true if the Widget is either at the starting or ending side of the association */
+bool AssociationWidget::contains(UMLWidget* widget) {
+ return (widget == m_role[A].m_pWidget || widget == m_role[B].m_pWidget);
+}
+
+bool AssociationWidget::isCollaboration() {
+ Uml::Association_Type at = getAssocType();
+ return (at == at_Coll_Message || at == at_Coll_Message_Self);
+}
+
+Uml::Association_Type AssociationWidget::getAssocType() const {
+ if (m_pObject == NULL || m_pObject->getBaseType() != ot_Association)
+ return m_AssocType;
+ UMLAssociation *umla = static_cast<UMLAssociation*>(m_pObject);
+ return umla->getAssocType();
+}
+
+/** Sets the association's type */
+void AssociationWidget::setAssocType(Uml::Association_Type type) {
+ if (m_pObject && m_pObject->getBaseType() == ot_Association)
+ getAssociation()->setAssocType(type);
+ m_AssocType = type;
+ m_LinePath.setAssocType(type);
+ // If the association new type is not supposed to have Multiplicity
+ // FloatingTexts and a Role FloatingTextWidget then set the texts
+ // to empty.
+ // NB We do not physically delete the floatingtext widgets here because
+ // those widgets are also stored in the UMLView::m_WidgetList.
+ if( !AssocRules::allowMultiplicity(type, getWidget(A)->getBaseType()) ) {
+ if (m_role[A].m_pMulti) {
+ m_role[A].m_pMulti->setName("");
+ }
+ if (m_role[B].m_pMulti) {
+ m_role[B].m_pMulti->setName("");
+ }
+ }
+ if( !AssocRules::allowRole( type ) ) {
+ if (m_role[A].m_pRole) {
+ m_role[A].m_pRole->setName("");
+ }
+ if (m_role[B].m_pRole) {
+ m_role[B].m_pRole->setName("");
+ }
+ setRoleDoc("", A);
+ setRoleDoc("", B);
+ }
+}
+
+Uml::IDType AssociationWidget::getWidgetID(Uml::Role_Type role) const {
+ if (m_role[role].m_pWidget == NULL) {
+ if (m_pObject && m_pObject->getBaseType() == ot_Association) {
+ UMLAssociation *umla = static_cast<UMLAssociation*>(m_pObject);
+ return umla->getObjectId(role);
+ }
+ kError() << "AssociationWidget::getWidgetID(): m_pWidget is NULL" << endl;
+ return Uml::id_None;
+ }
+ if (m_role[role].m_pWidget->getBaseType() == Uml::wt_Object)
+ return static_cast<ObjectWidget*>(m_role[role].m_pWidget)->getLocalID();
+ Uml::IDType id = m_role[role].m_pWidget->getID();
+ return id;
+}
+
+/** Returns a QString Object representing this AssociationWidget */
+QString AssociationWidget::toString() {
+ QString string = "";
+
+ if(m_role[A].m_pWidget) {
+ string = m_role[A].m_pWidget -> getName();
+ }
+ string.append(":");
+
+ if(m_role[A].m_pRole) {
+ string += m_role[A].m_pRole -> getText();
+ }
+ string.append(":");
+ string.append( UMLAssociation::typeAsString(getAssocType()) );
+ string.append(":");
+ if(m_role[B].m_pWidget) {
+ string += m_role[B].m_pWidget -> getName();
+ }
+
+ string.append(":");
+ if(m_role[B].m_pRole) {
+ string += m_role[B].m_pRole -> getText();
+ }
+
+ return string;
+}
+
+void AssociationWidget::mouseDoubleClickEvent(QMouseEvent * me) {
+ if (me->button() != Qt::RightButton && me->button() != Qt::LeftButton)
+ return;
+ int i = m_LinePath.onLinePath(me->pos());
+ if (i == -1) {
+ m_LinePath.setSelected(false);
+ return;
+ }
+ if (me->button() != Qt::LeftButton)
+ return;
+ const QPoint mp(me->pos());
+ /* if there is no point around the mouse pointer, we insert a new one */
+ if (! m_LinePath.isPoint(i, mp, POINT_DELTA)) {
+ m_LinePath.insertPoint(i + 1, mp);
+ if (m_nLinePathSegmentIndex == i) {
+ QPoint segStart = m_LinePath.getPoint(i);
+ QPoint segEnd = m_LinePath.getPoint(i + 2);
+ const int midSegX = segStart.x() + (segEnd.x() - segStart.x()) / 2;
+ const int midSegY = segStart.y() + (segEnd.y() - segStart.y()) / 2;
+ /*
+ kDebug() << "AssociationWidget::mouseDoubleClickEvent: "
+ << "segStart=(" << segStart.x() << "," << segStart.y()
+ << "), segEnd=(" << segEnd.x() << "," << segEnd.y()
+ << "), midSeg=(" << midSegX << "," << midSegY
+ << "), mp=(" << mp.x() << "," << mp.y() << ")"
+ << endl;
+ */
+ if (midSegX > mp.x() || midSegY < mp.y()) {
+ m_nLinePathSegmentIndex++;
+ kDebug() << "AssociationWidget::mouseDoubleClickEvent: "
+ << "setting m_nLinePathSegmentIndex to "
+ << m_nLinePathSegmentIndex << endl;
+ computeAssocClassLine();
+ }
+ }
+ } else {
+ /* deselect the line path */
+ m_LinePath.setSelected( false );
+
+ /* there was a point so we remove the point */
+ if (m_LinePath.removePoint(i, mp, POINT_DELTA)) {
+ /* Maybe reattach association class connecting line
+ to different association linepath segment. */
+ const int numberOfLines = m_LinePath.count() - 1;
+ if (m_nLinePathSegmentIndex >= numberOfLines) {
+ m_nLinePathSegmentIndex = numberOfLines - 1;
+ computeAssocClassLine();
+ }
+ }
+
+ /* select the line path */
+ m_LinePath.setSelected( true );
+ }
+
+ m_LinePath.update();
+
+ calculateNameTextSegment();
+ m_umldoc->setModified(true);
+}
+
+void AssociationWidget::moveEvent(QMoveEvent* me) {
+ // 2004-04-30: Achim Spangler
+ // Simple Approach to block moveEvent during load of
+ // XMI
+ /// @todo avoid trigger of this event during load
+ if ( m_umldoc->loading() ) {
+ // hmmh - change of position during load of XMI
+ // -> there is something wrong
+ // -> avoid movement during opening
+ // -> print warn and stay at old position
+ kWarning() << "AssociationWidget::moveEvent() called during load of XMI for ViewType: " << m_pView -> getType()
+ << ", and BaseType: " << getBaseType()
+ << endl;
+ return;
+ }
+ /*to be here a line segment has moved.
+ we need to see if the three text widgets needs to be moved.
+ there are a few things to check first though:
+
+ 1) Do they exist
+ 2) does it need to move:
+ 2a) for the multi widgets only move if they changed region, otherwise they are close enough
+ 2b) for role name move if the segment it is on moves.
+ */
+ //first see if either the first or last segments moved, else no need to recalculate their point positions
+
+ QPoint oldNamePoint = calculateTextPosition(tr_Name);
+ QPoint oldMultiAPoint = calculateTextPosition(tr_MultiA);
+ QPoint oldMultiBPoint = calculateTextPosition(tr_MultiB);
+ QPoint oldChangeAPoint = calculateTextPosition(tr_ChangeA);
+ QPoint oldChangeBPoint = calculateTextPosition(tr_ChangeB);
+ QPoint oldRoleAPoint = calculateTextPosition(tr_RoleAName);
+ QPoint oldRoleBPoint = calculateTextPosition(tr_RoleBName);
+
+ m_LinePath.setPoint( m_nMovingPoint, me->pos() );
+ int pos = m_LinePath.count() - 1;//set to last point for widget b
+
+ if ( m_nMovingPoint == 1 || (m_nMovingPoint == pos-1) ) {
+ calculateEndingPoints();
+ }
+ if (m_role[A].m_pChangeWidget && (m_nMovingPoint == 1)) {
+ setTextPositionRelatively(tr_ChangeA, oldChangeAPoint);
+ }
+ if (m_role[B].m_pChangeWidget && (m_nMovingPoint == 1)) {
+ setTextPositionRelatively(tr_ChangeB, oldChangeBPoint);
+ }
+ if (m_role[A].m_pMulti && (m_nMovingPoint == 1)) {
+ setTextPositionRelatively(tr_MultiA, oldMultiAPoint);
+ }
+ if (m_role[B].m_pMulti && (m_nMovingPoint == pos-1)) {
+ setTextPositionRelatively(tr_MultiB, oldMultiBPoint);
+ }
+
+ if (m_pName) {
+ if(m_nMovingPoint == (int)m_unNameLineSegment ||
+ m_nMovingPoint - 1 == (int)m_unNameLineSegment) {
+ setTextPositionRelatively(tr_Name, oldNamePoint);
+ }
+ }
+
+ if (m_role[A].m_pRole) {
+ setTextPositionRelatively(tr_RoleAName, oldRoleAPoint);
+ }
+ if (m_role[B].m_pRole) {
+ setTextPositionRelatively(tr_RoleBName, oldRoleBPoint);
+ }
+}
+
+
+/** Calculates and sets the first and last point in the Association's LinePath
+ Each point is a middle point of its respecting UMLWidget's Bounding rectangle
+ or a corner of it
+ This method picks which sides to use for the association */
+void AssociationWidget::calculateEndingPoints() {
+ /*
+ * For each UMLWidget the diagram is divided in four regions by its diagonals
+ * as indicated below
+ * Region 2
+ * \ /
+ * \ /
+ * +--------+
+ * | \ / |
+ * Region 1 | >< | Region 3
+ * | / \ |
+ * +--------+
+ * / \
+ * / \
+ * Region 4
+ *
+ * Each diagonal is defined by two corners of the bounding rectangle
+ *
+ * To calculate the first point in the LinePath we have to find out in which
+ * Region (defined by WidgetA's diagonals) is WidgetB's center
+ * (let's call it Region M.) After that the first point will be the middle
+ * point of the rectangle's side contained in Region M.
+ *
+ * To calculate the last point in the LinePath we repeat the above but
+ * in the opposite direction (from widgetB to WidgetA)
+ */
+
+ UMLWidget *pWidgetA = m_role[A].m_pWidget;
+ UMLWidget *pWidgetB = m_role[B].m_pWidget;
+ if (!pWidgetA || !pWidgetB)
+ return;
+ m_role[A].m_OldCorner.setX( pWidgetA->getX() );
+ m_role[A].m_OldCorner.setY( pWidgetA->getY() );
+ m_role[B].m_OldCorner.setX( pWidgetB->getX() );
+ m_role[B].m_OldCorner.setY( pWidgetB->getY() );
+ uint size = m_LinePath.count();
+ if(size < 2)
+ m_LinePath.setStartEndPoints( m_role[A].m_OldCorner, m_role[B].m_OldCorner );
+
+ // See if an association to self.
+ // See if it needs to be set up before we continue:
+ // If self association/message and doesn't have the minimum 4 points
+ // then create it. Make sure no points are out of bounds of viewing area.
+ // This only happens on first time through that we are worried about.
+ if (pWidgetA == pWidgetB && size < 4) {
+ const int DISTANCE = 50;
+ int x = pWidgetA -> getX();
+ int y = pWidgetA -> getY();
+ int h = pWidgetA -> getHeight();
+ int w = pWidgetA -> getWidth();
+ //see if above widget ok to start
+ if( y - DISTANCE > 0 ) {
+ m_LinePath.setStartEndPoints( QPoint( x + w / 4, y ) , QPoint( x + w * 3 / 4, y ) );
+ m_LinePath.insertPoint( 1, QPoint( x + w / 4, y - DISTANCE ) );
+ m_LinePath.insertPoint( 2 ,QPoint( x + w * 3 / 4, y - DISTANCE ) );
+ m_role[A].m_WidgetRegion = m_role[B].m_WidgetRegion = North;
+ } else {
+ m_LinePath.setStartEndPoints( QPoint( x + w / 4, y + h ), QPoint( x + w * 3 / 4, y + h ) );
+ m_LinePath.insertPoint( 1, QPoint( x + w / 4, y + h + DISTANCE ) );
+ m_LinePath.insertPoint( 2, QPoint( x + w * 3 / 4, y + h + DISTANCE ) );
+ m_role[A].m_WidgetRegion = m_role[B].m_WidgetRegion = South;
+ }
+ return;
+ }//end a == b
+
+ // If the line has more than one segment change the values to calculate
+ // from widget to point 1.
+ int xB = pWidgetB->getX() + pWidgetB->getWidth() / 2;
+ int yB = pWidgetB->getY() + pWidgetB->getHeight() / 2;
+ if( size > 2 ) {
+ QPoint p = m_LinePath.getPoint( 1 );
+ xB = p.x();
+ yB = p.y();
+ }
+ doUpdates(xB, yB, A);
+
+ // Now do the same for widgetB.
+ // If the line has more than one segment change the values to calculate
+ // from widgetB to the last point away from it.
+ int xA = pWidgetA->getX() + pWidgetA->getWidth() / 2;
+ int yA = pWidgetA->getY() + pWidgetA->getHeight() / 2;
+ if (size > 2 ) {
+ QPoint p = m_LinePath.getPoint( size - 2 );
+ xA = p.x();
+ yA = p.y();
+ }
+ doUpdates( xA, yA, B );
+
+ computeAssocClassLine();
+}
+
+void AssociationWidget::doUpdates(int otherX, int otherY, Uml::Role_Type role) {
+ // Find widget region.
+ Region oldRegion = m_role[role].m_WidgetRegion;
+ UMLWidget *pWidget = m_role[role].m_pWidget;
+ QRect rc(pWidget->getX(), pWidget->getY(),
+ pWidget->getWidth(), pWidget->getHeight());
+ Region& region = m_role[role].m_WidgetRegion; // alias for brevity
+ region = findPointRegion( rc, otherX, otherY);
+ // Move some regions to the standard ones.
+ switch( region ) {
+ case NorthWest:
+ region = North;
+ break;
+ case NorthEast:
+ region = East;
+ break;
+ case SouthEast:
+ region = South;
+ break;
+ case SouthWest:
+ case Center:
+ region = West;
+ break;
+ default:
+ break;
+ }
+ int regionCount = getRegionCount(region, role) + 2;//+2 = (1 for this one and one to halve it)
+ int totalCount = m_role[role].m_nTotalCount;
+ if( oldRegion != region ) {
+ updateRegionLineCount( regionCount - 1, regionCount, region, role );
+ updateAssociations( totalCount - 1, oldRegion, role );
+ } else if( totalCount != regionCount ) {
+ updateRegionLineCount( regionCount - 1, regionCount, region, role );
+ } else {
+ updateRegionLineCount( m_role[role].m_nIndex, totalCount, region, role );
+ }
+ updateAssociations( regionCount, region, role );
+}
+
+/** Read property of bool m_bActivated. */
+bool AssociationWidget::isActivated() {
+ return m_bActivated;
+}
+
+/** Set the m_bActivated flag of a widget but does not perform the Activate method */
+void AssociationWidget::setActivated(bool active /*=true*/) {
+ m_bActivated = active;
+}
+
+void AssociationWidget::syncToModel()
+{
+ UMLAssociation *uml = getAssociation();
+
+ if (uml == NULL) {
+ UMLAttribute *attr = getAttribute();
+ if (attr == NULL)
+ return;
+ setVisibility(attr->getVisibility(), B);
+ setRoleName(attr->getName(), B);
+ return;
+ }
+ // block signals until finished
+ uml->blockSignals(true);
+
+ setName(uml->getName());
+ setRoleName(uml->getRoleName(A), A);
+ setRoleName(uml->getRoleName(B), B);
+ setVisibility(uml->getVisibility(A), A);
+ setVisibility(uml->getVisibility(B), B);
+ setChangeability(uml->getChangeability(A), A);
+ setChangeability(uml->getChangeability(B), B);
+ setMulti(uml->getMulti(A), A);
+ setMulti(uml->getMulti(B), B);
+
+ uml->blockSignals(false);
+}
+
+// this will synchronize UMLAssociation w/ this new Widget
+void AssociationWidget::mergeAssociationDataIntoUMLRepresentation()
+{
+ UMLAssociation *umlassoc = getAssociation();
+ UMLAttribute *umlattr = getAttribute();
+ if (umlassoc == NULL && umlattr == NULL)
+ return;
+
+ // block emit modified signal, or we get a horrible loop
+ m_pObject->blockSignals(true);
+
+ // would be desirable to do the following
+ // so that we can be sure its back to initial state
+ // in case we missed something here.
+ //uml->init();
+
+ // floating text widgets
+ FloatingTextWidget *text = getNameWidget();
+ if (text)
+ m_pObject->setName(text->getText());
+
+ text = getRoleWidget(A);
+ if (text && umlassoc)
+ umlassoc->setRoleName(text->getText(), A);
+
+ text = getRoleWidget(B);
+ if (text) {
+ if (umlassoc)
+ umlassoc->setRoleName(text->getText(), B);
+ else if (umlattr)
+ umlattr->setName(text->getText());
+ }
+
+ text = getMultiWidget(A);
+ if (text && umlassoc)
+ umlassoc->setMulti(text->getText(), A);
+
+ text = getMultiWidget(B);
+ if (text && umlassoc)
+ umlassoc->setMulti(text->getText(), B);
+
+ // unblock
+ m_pObject->blockSignals(false);
+}
+
+void AssociationWidget::saveIdealTextPositions() {
+ m_oldNamePoint = calculateTextPosition(tr_Name);
+ m_oldMultiAPoint = calculateTextPosition(tr_MultiA);
+ m_oldMultiBPoint = calculateTextPosition(tr_MultiB);
+ m_oldChangeAPoint = calculateTextPosition(tr_ChangeA);
+ m_oldChangeBPoint = calculateTextPosition(tr_ChangeB);
+ m_oldRoleAPoint = calculateTextPosition(tr_RoleAName);
+ m_oldRoleBPoint = calculateTextPosition(tr_RoleBName);
+}
+
+/** Adjusts the ending point of the association that connects to Widget */
+void AssociationWidget::widgetMoved(UMLWidget* widget, int x, int y ) {
+ // 2004-04-30: Achim Spangler
+ // Simple Approach to block moveEvent during load of
+ // XMI
+ /// @todo avoid trigger of this event during load
+ if ( m_umldoc->loading() ) {
+ // hmmh - change of position during load of XMI
+ // -> there is something wrong
+ // -> avoid movement during opening
+ // -> print warn and stay at old position
+ kDebug() << "AssociationWidget::widgetMoved() called during load of XMI for ViewType: " << m_pView -> getType()
+ << ", and BaseType: " << getBaseType()
+ << endl;
+ return;
+ }
+
+ int dx = m_role[A].m_OldCorner.x() - x;
+ int dy = m_role[A].m_OldCorner.y() - y;
+ uint size = m_LinePath.count();
+ uint pos = size - 1;
+ calculateEndingPoints();
+
+ // Assoc to self - move all points:
+ if( m_role[A].m_pWidget == m_role[B].m_pWidget ) {
+ for( int i=1 ; i < (int)pos ; i++ ) {
+ QPoint p = m_LinePath.getPoint( i );
+ int newX = p.x() - dx;
+ int newY = p.y() - dy;
+ // safety. We DON'T want to go off the screen
+ if(newX < 0)
+ newX = 0;
+ // safety. We DON'T want to go off the screen
+ if(newY < 0)
+ newY = 0;
+ newX = m_pView -> snappedX( newX );
+ newY = m_pView -> snappedY( newY );
+ p.setX( newX );
+ p.setY( newY );
+ m_LinePath.setPoint( i, p );
+ }
+
+ if ( m_pName && !m_pName->getSelected() ) {
+ setTextPositionRelatively(tr_Name, m_oldNamePoint);
+ }
+
+ }//end if widgetA = widgetB
+ else if (m_role[A].m_pWidget==widget) {
+ if (m_pName && m_unNameLineSegment == 0 && !m_pName->getSelected() ) {
+ //only calculate position and move text if the segment it is on is moving
+ setTextPositionRelatively(tr_Name, m_oldNamePoint);
+ }
+ }//end if widgetA moved
+ else if (m_role[B].m_pWidget==widget) {
+ if (m_pName && (m_unNameLineSegment == pos-1) && !m_pName->getSelected() ) {
+ //only calculate position and move text if the segment it is on is moving
+ setTextPositionRelatively(tr_Name, m_oldNamePoint);
+ }
+ }//end if widgetB moved
+
+ if ( m_role[A].m_pRole && !m_role[A].m_pRole->getSelected() ) {
+ setTextPositionRelatively(tr_RoleAName, m_oldRoleAPoint);
+ }
+ if ( m_role[B].m_pRole && !m_role[B].m_pRole->getSelected() ) {
+ setTextPositionRelatively(tr_RoleBName, m_oldRoleBPoint);
+ }
+ if ( m_role[A].m_pMulti && !m_role[A].m_pMulti->getSelected() ) {
+ setTextPositionRelatively(tr_MultiA, m_oldMultiAPoint);
+ }
+ if ( m_role[B].m_pMulti && !m_role[B].m_pMulti->getSelected() ) {
+ setTextPositionRelatively(tr_MultiB, m_oldMultiBPoint);
+ }
+ if ( m_role[A].m_pChangeWidget && !m_role[A].m_pChangeWidget->getSelected() ) {
+ setTextPositionRelatively(tr_ChangeA, m_oldChangeAPoint);
+ }
+ if ( m_role[B].m_pChangeWidget && !m_role[B].m_pChangeWidget->getSelected() ) {
+ setTextPositionRelatively(tr_ChangeB, m_oldChangeBPoint);
+ }
+}//end method widgetMoved
+
+/** Finds out in which region of rectangle Rect contains the Point (PosX, PosY) and returns the region
+ number:
+ 1 = Region 1
+ 2 = Region 2
+ 3 = Region 3
+ 4 = Region 4
+ 5 = On diagonal 2 between Region 1 and 2
+ 6 = On diagonal 1 between Region 2 and 3
+ 7 = On diagonal 2 between Region 3 and 4
+ 8 = On diagonal 1 between Region 4 and 1
+ 9 = On diagonal 1 and On diagonal 2 (the center)
+*/
+AssociationWidget::Region AssociationWidget::findPointRegion(const QRect& Rect, int PosX, int PosY) {
+ float w = (float)Rect.width();
+ float h = (float)Rect.height();
+ float x = (float)Rect.x();
+ float y = (float)Rect.y();
+ float Slope2 = w / h;
+ float Slope1 = Slope2*(float)(-1);
+ float b1 = x + w - ( Slope1* y );
+ float b2 = x - ( Slope2* y );
+
+ float eval1 = Slope1 * (float)PosY + b1;
+ float eval2 = Slope2 *(float)PosY + b2;
+
+ Region result = Error;
+ //if inside region 1
+ if(eval1 > PosX && eval2 > PosX) {
+ result = West;
+ }
+ //if inside region 2
+ else if (eval1 > PosX && eval2 < PosX) {
+ result = North;
+ }
+ //if inside region 3
+ else if (eval1 < PosX && eval2 < PosX) {
+ result = East;
+ }
+ //if inside region 4
+ else if (eval1 < PosX && eval2 > PosX) {
+ result = South;
+ }
+ //if inside region 5
+ else if (eval1 == PosX && eval2 < PosX) {
+ result = NorthWest;
+ }
+ //if inside region 6
+ else if (eval1 < PosX && eval2 == PosX) {
+ result = NorthEast;
+ }
+ //if inside region 7
+ else if (eval1 == PosX && eval2 > PosX) {
+ result = SouthEast;
+ }
+ //if inside region 8
+ else if (eval1 > PosX && eval2 == PosX) {
+ result = SouthWest;
+ }
+ //if inside region 9
+ else if (eval1 == PosX && eval2 == PosX) {
+ result = Center;
+ }
+ return result;
+}
+
+QPoint AssociationWidget::swapXY(const QPoint &p) {
+ QPoint swapped( p.y(), p.x() );
+ return swapped;
+}
+
+/* Returns the total length of the association's LinePath:
+ result = segment_1_length + segment_2_length + ..... + segment_n_length
+ */
+float AssociationWidget::totalLength() {
+ uint size = m_LinePath.count();
+ float total_length = 0;
+
+ for(uint i = 0; i < size - 1; i++) {
+ QPoint pi = m_LinePath.getPoint( i );
+ QPoint pj = m_LinePath.getPoint( i+1 );
+ int xi = pi.y();
+ int xj = pj.y();
+ int yi = pi.x();
+ int yj = pj.x();
+ total_length += sqrt( double(((xj - xi)*(xj - xi)) + ((yj - yi)*(yj - yi))) );
+ }
+
+ return total_length;
+}
+
+
+/** Calculates which point of segment P1P2 has a distance equal to Distance from P1,
+ Lets say such point is P3, the distance from P1 to P3 must be equal to Distance
+ and if P3 is not a point of the segment P1P2 then the function returns (-1,-1)
+*/
+QPoint AssociationWidget::calculatePointAtDistance(const QPoint &P1, const QPoint &P2, float Distance) {
+ /*
+ the distance D between points (x1, y1) and (x3, y3) has the following formula:
+ --- ------------------------------
+ D = \ / 2 2
+ \ / (x3 - x1) + (y3 - y1)
+
+ D, x1 and y1 are known and the point (x3, y3) is inside line (x1,y1)(x2,y2), so if the
+ that line has the formula y = mx + b
+ then y3 = m*x3 + b
+
+ 2 2 2
+ D = (x3 - x1) + (y3 - y1)
+
+ 2 2 2 2 2
+ D = x3 - 2*x3*x1 + x1 + y3 - 2*y3*y1 + y1
+
+ 2 2 2 2 2
+ D - x1 - y1 = x3 - 2*x3*x1 + y3 - 2*y3*y1
+
+ 2 2 2 2 2
+ D - x1 - y1 = x3 - 2*x3*x1 + (m*x3 + b) - 2*(m*x3 + b)*y1
+
+ 2 2 2 2 2 2
+ D - x1 - y1 + 2*b*y1 - b = (m + 1)*x3 + (-2*x1 + 2*m*b -2*m*y1)*x3
+
+ 2 2 2 2
+ C = - D + x1 + y1 - 2*b*y1 + b
+
+
+ 2
+ A = (m + 1)
+
+ B = (-2*x1 + 2*m*b -2*m*y1)
+
+ and we have
+ 2
+ A * x3 + B * x3 - C = 0
+
+ ---------------
+ -B + --- / 2
+ \/ B - 4*A*C
+ sol_1 = --------------------------------
+ 2*A
+
+
+ ---------------
+ -B - --- / 2
+ \/ B - 4*A*C
+ sol_2 = --------------------------------
+ 2*A
+
+
+ then in the distance formula we have only one variable x3 and that is easy
+ to calculate
+ */
+ int x1 = P1.y();
+ int y1 = P1.x();
+ int x2 = P2.y();
+ int y2 = P2.x();
+
+ if(x2 == x1) {
+ return QPoint(x1, y1 + (int)Distance);
+ }
+ float slope = ((float)y2 - (float)y1) / ((float)x2 - (float)x1);
+ float b = (y1 - slope*x1);
+ float A = (slope * slope) + 1;
+ float B = (2*slope*b) - (2*x1) - (2*slope*y1);
+ float C = (b*b) - (Distance*Distance) + (x1*x1) + (y1*y1) - (2*b*y1);
+ float t = B*B - 4*A*C;
+
+ if(t < 0) {
+ return QPoint(-1, -1);
+ }
+ float sol_1 = ((-1* B) + sqrt(t) ) / (2*A);
+ float sol_2 = ((-1*B) - sqrt(t) ) / (2*A);
+
+ if(sol_1 < 0.0 && sol_2 < 0.0) {
+ return QPoint(-1, -1);
+ }
+ QPoint sol1Point((int)(slope*sol_1 + b), (int)(sol_1));
+ QPoint sol2Point((int)(slope*sol_2 + b), (int)(sol_2));
+ if(sol_1 < 0 && sol_2 >=0) {
+ if(x2 > x1) {
+ if(x1 <= sol_2 && sol_2 <= x2)
+ return sol2Point;
+ } else {
+ if(x2 <= sol_2 && sol_2 <= x1)
+ return sol2Point;
+ }
+ } else if(sol_1 >= 0 && sol_2 < 0) {
+ if(x2 > x1) {
+ if(x1 <= sol_1 && sol_1 <= x2)
+ return sol1Point;
+ } else {
+ if(x2 <= sol_1 && sol_1 <= x1)
+ return sol1Point;
+ }
+ } else {
+ if(x2 > x1) {
+ if(x1 <= sol_1 && sol_1 <= x2)
+ return sol1Point;
+ if(x1 <= sol_2 && sol_2 <= x2)
+ return sol2Point;
+ } else {
+ if(x2 <= sol_1 && sol_1 <= x1)
+ return sol1Point;
+ if(x2 <= sol_2 && sol_2 <= x1)
+ return sol2Point;
+ }
+ }
+ return QPoint(-1, -1);
+}
+
+/** Calculates which point of a perpendicular line to segment P1P2 that contains P2
+ has a distance equal to Distance from P2,
+ Lets say such point is P3, the distance from P2 to P3 must be equal to Distance
+*/
+QPoint AssociationWidget::calculatePointAtDistanceOnPerpendicular(const QPoint &P1, const QPoint &P2, float Distance) {
+ /*
+ the distance D between points (x2, y2) and (x3, y3) has the following formula:
+
+ --- ------------------------------
+ D = \ / 2 2
+ \ / (x3 - x2) + (y3 - y2)
+
+ D, x2 and y2 are known and line P2P3 is perpendicular to line (x1,y1)(x2,y2), so if the
+ line P1P2 has the formula y = m*x + b,
+ then (x1 - x2)
+ m = ----------- , because it is perpendicular to line P1P2
+ (y2 - y1)
+
+ also y2 = m*x2 + b
+ => b = y2 - m*x2
+
+ then P3 = (x3, m*x3 + b)
+
+ 2 2 2
+ D = (x3 - x2) + (y3 - y2)
+
+ 2 2 2 2 2
+ D = x3 - 2*x3*x2 + x2 + y3 - 2*y3*y2 + y2
+
+ 2 2 2 2 2
+ D - x2 - y2 = x3 - 2*x3*x2 + y3 - 2*y3*y2
+
+
+
+ 2 2 2 2 2
+ D - x2 - y2 = x3 - 2*x3*x2 + (m*x3 + b) - 2*(m*x3 + b)*y2
+
+ 2 2 2 2 2 2
+ D - x2 - y2 + 2*b*y2 - b = (m + 1)*x3 + (-2*x2 + 2*m*b -2*m*y2)*x3
+
+ 2 2 2 2
+ C = - D + x2 + y2 - 2*b*y2 + b
+
+ 2
+ A = (m + 1)
+
+ B = (-2*x2 + 2*m*b -2*m*y2)
+
+ and we have
+ 2
+ A * x3 + B * x3 - C = 0
+
+
+ ---------------
+ --- / 2
+ -B + \/ B - 4*A*C
+ sol_1 = --------------------------------
+ 2*A
+
+
+ ---------------
+ --- / 2
+ -B - \/ B - 4*A*C
+ sol_2 = --------------------------------
+ 2*A
+
+ then in the distance formula we have only one variable x3 and that is easy
+ to calculate
+ */
+ if (P1.x() == P2.x()) {
+ return QPoint((int)(P2.x() + Distance), P2.y());
+ }
+ const int x1 = P1.y();
+ const int y1 = P1.x();
+ const int x2 = P2.y();
+ const int y2 = P2.x();
+
+ float slope = ((float)x1 - (float)x2) / ((float)y2 - (float)y1);
+ float b = (y2 - slope*x2);
+ float A = (slope * slope) + 1;
+ float B = (2*slope*b) - (2*x2) - (2*slope*y2);
+ float C = (b*b) - (Distance*Distance) + (x2*x2) + (y2*y2) - (2*b*y2);
+ float t = B*B - 4*A*C;
+ if (t < 0) {
+ return QPoint(-1, -1);
+ }
+ float sol_1 = ((-1* B) + sqrt(t) ) / (2*A);
+
+ float sol_2 = ((-1*B) - sqrt(t) ) / (2*A);
+
+ if(sol_1 < 0 && sol_2 < 0) {
+ return QPoint(-1, -1);
+ }
+ QPoint sol1Point((int)(slope*sol_1 + b), (int)sol_1);
+ QPoint sol2Point((int)(slope*sol_2 + b), (int)sol_2);
+ if(sol_1 < 0 && sol_2 >=0) {
+ return sol2Point;
+ } else if(sol_1 >= 0 && sol_2 < 0) {
+ return sol1Point;
+ } else { // Choose one solution , either will work fine
+ if(slope >= 0) {
+ if(sol_1 <= sol_2)
+ return sol2Point;
+ else
+ return sol1Point;
+ } else {
+ if(sol_1 <= sol_2)
+ return sol1Point;
+ else
+ return sol2Point;
+ }
+
+ }
+ return QPoint(-1, -1); // never reached, just keep compilers happy
+}
+
+/** Calculates the intersection (PS) between line P1P2 and a perpendicular line containing
+ P3, the result is returned in ResultingPoint. and result value represents the distance
+ between ResultingPoint and P3; if this value is negative an error ocurred. */
+float AssociationWidget::perpendicularProjection(const QPoint& P1, const QPoint& P2, const QPoint& P3,
+ QPoint& ResultingPoint) {
+ //line P1P2 is Line 1 = y=slope1*x + b1
+
+ //line P3PS is Line 1 = y=slope2*x + b2
+
+ float slope2 = 0;
+ float slope1 = 0;
+ float sx = 0, sy = 0;
+ int y2 = P2.x();
+ int y1 = P1.x();
+ int x2 = P2.y();
+ int x1 = P1.y();
+ int y3 = P3.x();
+ int x3 = P3.y();
+ float distance = 0;
+ float b1 = 0;
+
+ float b2 = 0;
+
+ if(x2 == x1) {
+ sx = x2;
+ sy = y3;
+ } else if(y2 == y1) {
+ sy = y2;
+ sx = x3;
+ } else {
+ slope1 = (y2 - y1)/ (x2 - x1);
+ slope2 = (x1 - x2)/ (y2 - y1);
+ b1 = y2 - (slope1 * x2);
+ b2 = y3 - (slope2 * x3);
+ sx = (b2 - b1) / (slope1 - slope2);
+ sy = slope1*sx + b1;
+ }
+ distance = (int)( sqrt( ((x3 - sx)*(x3 - sx)) + ((y3 - sy)*(y3 - sy)) ) );
+
+ ResultingPoint.setX( (int)sy );
+ ResultingPoint.setY( (int)sx );
+
+ return distance;
+}
+
+QPoint AssociationWidget::calculateTextPosition(Uml::Text_Role role) {
+ const int SPACE = 2;
+ QPoint p(-1, -1), q(-1, -1);
+
+ // used to find out if association end point (p)
+ // is at top or bottom edge of widget.
+ bool is_top_or_bottom(false);
+ UMLWidget *pWidget(0);
+
+ if (role == tr_MultiA || role == tr_ChangeA || role == tr_RoleAName) {
+ p = m_LinePath.getPoint( 0 );
+ q = m_LinePath.getPoint( 1 );
+ pWidget = m_role[A].m_pWidget;
+ } else if (role == tr_MultiB || role == tr_ChangeB || role == tr_RoleBName) {
+ const uint lastSegment = m_LinePath.count() - 1;
+ p = m_LinePath.getPoint(lastSegment);
+ q = m_LinePath.getPoint(lastSegment - 1);
+ pWidget = m_role[B].m_pWidget;
+ } else if (role != tr_Name) {
+ kError() << "AssociationWidget::calculateTextPosition called with unsupported Text_Role "
+ << role << endl;
+ return QPoint(-1, -1);
+ }
+
+ if ( pWidget && ( pWidget->getY() == p.y() || pWidget->getY() + pWidget->height() == p.y() ))
+ is_top_or_bottom = true;
+
+ FloatingTextWidget *text = getTextWidgetByRole(role);
+ int textW = 0, textH = 0;
+ if (text) {
+ textW = text->width();
+ textH = text->height();
+ }
+
+ int x = 0, y = 0;
+
+ if (role == tr_MultiA || role == tr_MultiB) {
+ const bool isHorizontal = (p.y() == q.y());
+ const int atBottom = p.y() + SPACE;
+ const int atTop = p.y() - SPACE - textH;
+ const int atLeft = p.x() - SPACE - textW;
+ const int atRight = p.x() + SPACE;
+ y = (p.y() > q.y()) == isHorizontal ? atBottom : atTop;
+ x = (p.x() < q.x()) == isHorizontal ? atRight : atLeft;
+
+ } else if (role == tr_ChangeA || role == tr_ChangeB) {
+
+ if( p.y() > q.y() )
+ y = p.y() - SPACE - (textH * 2);
+ else
+ y = p.y() + SPACE + textH;
+
+ if( p.x() < q.x() )
+ x = p.x() + SPACE;
+ else
+ x = p.x() - SPACE - textW;
+
+ } else if (role == tr_RoleAName || role == tr_RoleBName) {
+
+ if( p.y() > q.y() )
+ y = p.y() - SPACE - textH;
+ else
+ y = p.y() + SPACE;
+
+ if( p.x() < q.x() )
+ x = p.x() + SPACE;
+ else
+ x = p.x() - SPACE - textW;
+
+ } else if (role == tr_Name) {
+
+ calculateNameTextSegment();
+ x = (int)( ( m_LinePath.getPoint(m_unNameLineSegment).x() +
+ m_LinePath.getPoint(m_unNameLineSegment + 1).x() ) / 2 );
+
+ y = (int)( ( m_LinePath.getPoint(m_unNameLineSegment).y() +
+ m_LinePath.getPoint(m_unNameLineSegment + 1).y() ) / 2 );
+ }
+
+ if (text) {
+ constrainTextPos(x, y, textW, textH, role);
+ }
+ p = QPoint( x, y );
+ return p;
+}
+
+QPoint AssociationWidget::midPoint(const QPoint& p0, const QPoint& p1) {
+ QPoint midP;
+ if (p0.x() < p1.x())
+ midP.setX(p0.x() + (p1.x() - p0.x()) / 2);
+ else
+ midP.setX(p1.x() + (p0.x() - p1.x()) / 2);
+ if (p0.y() < p1.y())
+ midP.setY(p0.y() + (p1.y() - p0.y()) / 2);
+ else
+ midP.setY(p1.y() + (p0.y() - p1.y()) / 2);
+ return midP;
+}
+
+void AssociationWidget::constrainTextPos(int &textX, int &textY,
+ int textWidth, int textHeight,
+ Uml::Text_Role tr) {
+ const int textCenterX = textX + textWidth / 2;
+ const int textCenterY = textY + textHeight / 2;
+ const uint lastSegment = m_LinePath.count() - 1;
+ QPoint p0, p1;
+ switch (tr) {
+ case tr_RoleAName:
+ case tr_MultiA:
+ case tr_ChangeA:
+ p0 = m_LinePath.getPoint(0);
+ p1 = m_LinePath.getPoint(1);
+ // If we are dealing with a single line then tie the
+ // role label to the proper half of the line, i.e.
+ // the role label must be closer to the "other"
+ // role object.
+ if (lastSegment == 1)
+ p1 = midPoint(p0, p1);
+ break;
+ case tr_RoleBName:
+ case tr_MultiB:
+ case tr_ChangeB:
+ p0 = m_LinePath.getPoint(lastSegment - 1);
+ p1 = m_LinePath.getPoint(lastSegment);
+ if (lastSegment == 1)
+ p0 = midPoint(p0, p1);
+ break;
+ case tr_Name:
+ case tr_Coll_Message: // CHECK: collab.msg texts seem to be tr_Name
+ case tr_State: // CHECK: is this used?
+ // Find the linepath segment to which the (textX,textY) is closest
+ // and constrain to the corridor of that segment (see farther below)
+ {
+ int minDistSquare = 100000; // utopian initial value
+ int lpIndex = 0;
+ for (uint i = 0; i < lastSegment; i++) {
+ p0 = m_LinePath.getPoint(i);
+ p1 = m_LinePath.getPoint(i + 1);
+ QPoint midP = midPoint(p0, p1);
+ const int deltaX = textCenterX - midP.x();
+ const int deltaY = textCenterY - midP.y();
+ const int cSquare = deltaX * deltaX + deltaY * deltaY;
+ if (cSquare < minDistSquare) {
+ minDistSquare = cSquare;
+ lpIndex = i;
+ }
+ }
+ p0 = m_LinePath.getPoint(lpIndex);
+ p1 = m_LinePath.getPoint(lpIndex + 1);
+ }
+ break;
+ default:
+ kError() << "AssociationWidget::constrainTextPos(): unexpected Text_Role "
+ << tr << endl;
+ return;
+ break;
+ }
+ /* Constraint:
+ The midpoint between p0 and p1 is taken to be the center of a circle
+ with radius D/2 where D is the distance between p0 and p1.
+ The text center needs to be within this circle else it is constrained
+ to the nearest point on the circle.
+ */
+ p0 = swapXY(p0); // go to the natural coordinate system
+ p1 = swapXY(p1); // with (0,0) in the lower left corner
+ QPoint midP = midPoint(p0, p1);
+ // If (textX,textY) is not inside the circle around midP then
+ // constrain (textX,textY) to the nearest point on that circle.
+ const int x0 = p0.x();
+ const int y0 = p0.y();
+ const int x1 = p1.x();
+ const int y1 = p1.y();
+ double r = sqrt((x1 - x0) * (x1 - x0) + (y1 - y0) * (y1 - y0)) / 2;
+ if (textWidth > r)
+ r = textWidth;
+ // swap textCenter{X,Y} to convert from Qt coord.system.
+ const QPoint origTextCenter(textCenterY, textCenterX);
+ const int relX = abs(origTextCenter.x() - midP.x());
+ const int relY = abs(origTextCenter.y() - midP.y());
+ const double negativeWhenInsideCircle = relX * relX + relY * relY - r * r;
+ if (negativeWhenInsideCircle <= 0.0) {
+ return;
+ }
+ /*
+ The original constraint was to snap the text position to the
+ midpoint but that creates unpleasant visual jitter:
+ textX = midP.y() - textWidth / 2; // go back to Qt coord.sys.
+ textY = midP.x() - textHeight / 2; // go back to Qt coord.sys.
+
+ Rather, we project the text position onto the closest point
+ on the circle:
+
+ Circle equation:
+ relX^2 + relY^2 - r^2 = 0 , or in other words
+ relY^2 = r^2 - relX^2 , or
+ relY = sqrt(r^2 - relX^2)
+ Line equation:
+ relY = a * relX + b
+ We can omit "b" because relX and relY are already relative to
+ the circle origin, therefore we can also write:
+ a = relY / relX
+ To obtain the point of intersection between the circle of radius r
+ and the line connecting the circle origin with the point (relX, relY),
+ we equate the relY:
+ a * x = sqrt(r^2 - x^2) , or in other words
+ a^2 * x^2 = r^2 - x^2 , or
+ x^2 * (a^2 + 1) = r^2 , or
+ x^2 = r^2 / (a^2 + 1) , or
+ x = sqrt(r^2 / (a^2 + 1))
+ and then
+ y = a * x
+ The resulting x and y are relative to the circle origin so we just add
+ the circle origin (X,Y) to obtain the constrained (textX,textY).
+ */
+ // Handle the special case, relX = 0.
+ if (relX == 0) {
+ if (origTextCenter.y() > midP.y())
+ textX = midP.y() + (int)r; // go back to Qt coord.sys.
+ else
+ textX = midP.y() - (int)r; // go back to Qt coord.sys.
+ textX -= textWidth / 2;
+ return;
+ }
+ const double a = (double)relY / (double)relX;
+ const double x = sqrt(r*r / (a*a + 1));
+ const double y = a * x;
+ if (origTextCenter.x() > midP.x())
+ textY = midP.x() + (int)x; // go back to Qt coord.sys.
+ else
+ textY = midP.x() - (int)x; // go back to Qt coord.sys.
+ textY -= textHeight / 2;
+ if (origTextCenter.y() > midP.y())
+ textX = midP.y() + (int)y; // go back to Qt coord.sys.
+ else
+ textX = midP.y() - (int)y; // go back to Qt coord.sys.
+ textX -= textWidth / 2;
+}
+
+void AssociationWidget::calculateNameTextSegment() {
+ if(!m_pName) {
+ return;
+ }
+ //changed to use the middle of the text
+ //i think this will give a better result.
+ //never know what sort of lines people come up with
+ //and text could be long to give a false reading
+ int xt = m_pName -> getX();
+ int yt = m_pName -> getY();
+ xt += m_pName -> getWidth() / 2;
+ yt += m_pName -> getHeight() / 2;
+ uint size = m_LinePath.count();
+ //sum of length(PTP1) and length(PTP2)
+ float total_length = 0;
+ float smallest_length = 0;
+ for(uint i = 0; i < size - 1; i++) {
+ QPoint pi = m_LinePath.getPoint( i );
+ QPoint pj = m_LinePath.getPoint( i+1 );
+ int xtiDiff = xt - pi.x();
+ int xtjDiff = xt - pj.x();
+ int ytiDiff = yt - pi.y();
+ int ytjDiff = yt - pj.y();
+ total_length = sqrt( double(xtiDiff * xtiDiff + ytiDiff * ytiDiff) )
+ + sqrt( double(xtjDiff * xtjDiff + ytjDiff * ytjDiff) );
+ //this gives the closest point
+ if( total_length < smallest_length || i == 0) {
+ smallest_length = total_length;
+ m_unNameLineSegment = i;
+ }
+ }
+}
+
+void AssociationWidget::setTextPosition(Uml::Text_Role role) {
+ bool startMove = false;
+ if( m_role[A].m_pMulti && m_role[A].m_pMulti->getStartMove() )
+ startMove = true;
+ else if( m_role[B].m_pMulti && m_role[B].m_pMulti->getStartMove() )
+ startMove = true;
+ else if( m_role[A].m_pChangeWidget && m_role[A].m_pChangeWidget->getStartMove() )
+ startMove = true;
+ else if( m_role[B].m_pChangeWidget && m_role[B].m_pChangeWidget->getStartMove() )
+ startMove = true;
+ else if( m_role[A].m_pRole && m_role[A].m_pRole->getStartMove() )
+ startMove = true;
+ else if( m_role[B].m_pRole && m_role[B].m_pRole->getStartMove() )
+ startMove = true;
+ else if( m_pName && m_pName->getStartMove() )
+ startMove = true;
+
+ if (startMove) {
+ return;
+ }
+ FloatingTextWidget *ft = getTextWidgetByRole(role);
+ if (ft == NULL)
+ return;
+ QPoint pos = calculateTextPosition(role);
+ int x = pos.x();
+ int y = pos.y();
+ if ( (x < 0 || x > FloatingTextWidget::restrictPositionMax) ||
+ (y < 0 || y > FloatingTextWidget::restrictPositionMax) ) {
+ kDebug() << "AssociationWidget::setTextPosition( " << x << " , " << y << " ) "
+ << "- was blocked because at least one value is out of bounds: ["
+ << "0 ... " << FloatingTextWidget::restrictPositionMax << "]"
+ << endl;
+ return;
+ }
+ ft->setX( x );
+ ft->setY( y );
+}
+
+void AssociationWidget::setTextPositionRelatively(Uml::Text_Role role, const QPoint &oldPosition) {
+ bool startMove = false;
+ if( m_role[A].m_pMulti && m_role[A].m_pMulti->getStartMove() )
+ startMove = true;
+ else if( m_role[B].m_pMulti && m_role[B].m_pMulti->getStartMove() )
+ startMove = true;
+ else if( m_role[A].m_pChangeWidget && m_role[A].m_pChangeWidget->getStartMove() )
+ startMove = true;
+ else if( m_role[B].m_pChangeWidget && m_role[B].m_pChangeWidget->getStartMove() )
+ startMove = true;
+ else if( m_role[A].m_pRole && m_role[A].m_pRole->getStartMove() )
+ startMove = true;
+ else if( m_role[B].m_pRole && m_role[B].m_pRole->getStartMove() )
+ startMove = true;
+ else if( m_pName && m_pName->getStartMove() )
+ startMove = true;
+
+ if (startMove) {
+ return;
+ }
+ FloatingTextWidget *ft = getTextWidgetByRole(role);
+ if (ft == NULL)
+ return;
+ int ftX = ft->getX();
+ int ftY = ft->getY();
+ if ( (ftX < 0 || ftX > FloatingTextWidget::restrictPositionMax) ||
+ (ftY < 0 || ftY > FloatingTextWidget::restrictPositionMax) ) {
+ kDebug() << "AssociationWidget::setTextPositionRelatively: "
+ << "blocked because the FloatingTextWidget original position ("
+ << ftX << "," << ftY << " is out of bounds: [0 ... "
+ << FloatingTextWidget::restrictPositionMax << "]" << endl;
+ return;
+ }
+ QPoint pos = calculateTextPosition(role);
+ int relX = pos.x() - oldPosition.x();
+ int relY = pos.y() - oldPosition.y();
+ int ftNewX = ftX + relX;
+ int ftNewY = ftY + relY;
+ if ( (ftNewX < 0 || ftNewX > FloatingTextWidget::restrictPositionMax) ||
+ (ftNewY < 0 || ftNewY > FloatingTextWidget::restrictPositionMax) ) {
+ kDebug() << "AssociationWidget::setTextPositionRelatively: "
+ << "blocked because the FloatingTextWidget new position ("
+ << ftNewX << "," << ftNewY << " is out of bounds: [0 ... "
+ << FloatingTextWidget::restrictPositionMax << "]" << endl;
+ return;
+ }
+ bool oldIgnoreSnapToGrid = ft->getIgnoreSnapToGrid();
+ ft->setIgnoreSnapToGrid( true );
+ ft->setX( ftNewX );
+ ft->setY( ftNewY );
+ ft->setIgnoreSnapToGrid( oldIgnoreSnapToGrid );
+}
+
+void AssociationWidget::removeAssocClassLine() {
+ selectAssocClassLine(false);
+ if (m_pAssocClassLine) {
+ delete m_pAssocClassLine;
+ m_pAssocClassLine = NULL;
+ }
+ if (m_pAssocClassWidget) {
+ m_pAssocClassWidget->setClassAssocWidget(NULL);
+ m_pAssocClassWidget = NULL;
+ }
+}
+
+void AssociationWidget::createAssocClassLine() {
+ if (m_pAssocClassLine == NULL)
+ m_pAssocClassLine = new QCanvasLine(m_pView->canvas());
+ computeAssocClassLine();
+ QPen pen(getLineColor(), getLineWidth(), Qt::DashLine);
+ m_pAssocClassLine->setPen(pen);
+ m_pAssocClassLine->setVisible(true);
+}
+
+void AssociationWidget::createAssocClassLine(ClassifierWidget* classifier,
+ int linePathSegmentIndex) {
+ m_nLinePathSegmentIndex = linePathSegmentIndex;
+
+ if (m_nLinePathSegmentIndex < 0) {
+ return;
+ }
+
+ m_pAssocClassWidget = classifier;
+ m_pAssocClassWidget->setClassAssocWidget(this);
+
+ createAssocClassLine();
+}
+
+void AssociationWidget::computeAssocClassLine() {
+ if (m_pAssocClassWidget == NULL || m_pAssocClassLine == NULL)
+ return;
+ if (m_nLinePathSegmentIndex < 0) {
+ kError() << "AssociationWidget::computeAssocClassLine: "
+ << "m_nLinePathSegmentIndex is not set" << endl;
+ return;
+ }
+ QPoint segStart = m_LinePath.getPoint(m_nLinePathSegmentIndex);
+ QPoint segEnd = m_LinePath.getPoint(m_nLinePathSegmentIndex + 1);
+ const int midSegX = segStart.x() + (segEnd.x() - segStart.x()) / 2;
+ const int midSegY = segStart.y() + (segEnd.y() - segStart.y()) / 2;
+
+ QPoint segmentMidPoint(midSegX, midSegY);
+ QRect classRectangle = m_pAssocClassWidget->rect();
+ QPoint cwEdgePoint = findIntercept(classRectangle, segmentMidPoint);
+ int acwMinX = cwEdgePoint.x();
+ int acwMinY = cwEdgePoint.y();
+
+ m_pAssocClassLine->setPoints(midSegX, midSegY, acwMinX, acwMinY);
+}
+
+void AssociationWidget::selectAssocClassLine(bool sel /* =true */) {
+ if (!sel) {
+ if (m_pAssocClassLineSel0) {
+ delete m_pAssocClassLineSel0;
+ m_pAssocClassLineSel0 = NULL;
+ }
+ if (m_pAssocClassLineSel1) {
+ delete m_pAssocClassLineSel1;
+ m_pAssocClassLineSel1 = NULL;
+ }
+ return;
+ }
+ if (m_pAssocClassLine == NULL) {
+ kError() << "AssociationWidget::selectAssocClassLine: "
+ << "cannot select because m_pAssocClassLine is NULL"
+ << endl;
+ return;
+ }
+ if (m_pAssocClassLineSel0)
+ delete m_pAssocClassLineSel0;
+ m_pAssocClassLineSel0 = Widget_Utils::decoratePoint(m_pAssocClassLine->startPoint());
+ if (m_pAssocClassLineSel1)
+ delete m_pAssocClassLineSel1;
+ m_pAssocClassLineSel1 = Widget_Utils::decoratePoint(m_pAssocClassLine->endPoint());
+}
+
+void AssociationWidget::mousePressEvent(QMouseEvent * me) {
+ m_nMovingPoint = -1;
+ //make sure we should be here depending on the button
+ if(me -> button() != Qt::RightButton && me->button() != Qt::LeftButton)
+ return;
+ QPoint mep = me->pos();
+ // See if `mep' is on the connecting line to the association class
+ if (onAssocClassLine(mep)) {
+ m_bSelected = true;
+ selectAssocClassLine();
+ return;
+ }
+ // See if the user has clicked on a point to start moving the line segment
+ // from that point
+ checkPoints(mep);
+ if( me -> state() != Qt::ShiftButton )
+ m_pView -> clearSelected();
+ setSelected( !m_bSelected );
+}
+
+void AssociationWidget::mouseReleaseEvent(QMouseEvent * me) {
+ if(me -> button() != Qt::RightButton && me->button() != Qt::LeftButton) {
+ setSelected( false );
+ return;
+ }
+
+ // Check whether a point was moved and whether the moved point is
+ // located on the straight line between its neighbours.
+ // if yes, remove it
+ ///@todo: check for non-horizontal / -vertical lines
+ if (m_nMovingPoint > 0 && m_nMovingPoint < m_LinePath.count() - 1)
+ {
+ QPoint m = m_LinePath.getPoint(m_nMovingPoint);
+ QPoint b = m_LinePath.getPoint(m_nMovingPoint - 1);
+ QPoint a = m_LinePath.getPoint(m_nMovingPoint + 1);
+ if ( (b.x() == m.x() && a.x() == m.x()) ||
+ (b.y() == m.y() && a.y() == m.y()) )
+ m_LinePath.removePoint(m_nMovingPoint, m, POINT_DELTA);
+ }
+ m_nMovingPoint = -1;
+ const QPoint p = me->pos();
+
+ if (me->button() != Qt::RightButton) {
+ return;
+ }
+
+ // right button action:
+ //work out the type of menu we want
+ //work out if the association allows rolenames, multiplicity, etc
+ //also must be within a certain distance to be a multiplicity menu
+ ListPopupMenu::Menu_Type menuType = ListPopupMenu::mt_Undefined;
+ const int DISTANCE = 40;//must be within this many pixels for it to be a multi menu
+ const QPoint lpStart = m_LinePath.getPoint(0);
+ const QPoint lpEnd = m_LinePath.getPoint(m_LinePath.count() - 1);
+ const int startXDiff = lpStart.x() - p.x();
+ const int startYDiff = lpStart.y() - p.y();
+ const int endXDiff = lpEnd.x() - p.x();
+ const int endYDiff = lpEnd.y() - p.y();
+ const float lengthMAP = sqrt( double(startXDiff * startXDiff + startYDiff * startYDiff) );
+ const float lengthMBP = sqrt( double(endXDiff * endXDiff + endYDiff * endYDiff) );
+ const Uml::Association_Type type = getAssocType();
+ //allow multiplicity
+ if( AssocRules::allowMultiplicity( type, getWidget(A) -> getBaseType() ) ) {
+ if(lengthMAP < DISTANCE)
+ menuType = ListPopupMenu::mt_MultiA;
+ else if(lengthMBP < DISTANCE)
+ menuType = ListPopupMenu::mt_MultiB;
+ }
+ if( menuType == ListPopupMenu::mt_Undefined ) {
+ if (type == at_Anchor || onAssocClassLine(p))
+ menuType = ListPopupMenu::mt_Anchor;
+ else if (isCollaboration())
+ menuType = ListPopupMenu::mt_Collaboration_Message;
+ else if (getAssociation() == NULL)
+ menuType = ListPopupMenu::mt_AttributeAssociation;
+ else if (AssocRules::allowRole(type))
+ menuType = ListPopupMenu::mt_FullAssociation;
+ else
+ menuType = ListPopupMenu::mt_Association_Selected;
+ }
+ m_pMenu = new ListPopupMenu(m_pView, menuType);
+ m_pMenu->popup(me -> globalPos());
+ connect(m_pMenu, SIGNAL(activated(int)), this, SLOT(slotMenuSelection(int)));
+ setSelected();
+}//end method mouseReleaseEvent
+
+bool AssociationWidget::showDialog() {
+ AssocPropDlg dlg(static_cast<QWidget*>(m_pView), this );
+ if (! dlg.exec())
+ return false;
+ QString name = getName();
+ QString doc = getDoc();
+ QString roleADoc = getRoleDoc(A), roleBDoc = getRoleDoc(B);
+ QString rnA = getRoleName(A), rnB = getRoleName(B);
+ QString ma = getMulti(A), mb = getMulti(B);
+ Uml::Visibility vA = getVisibility(A), vB = getVisibility(B);
+ Uml::Changeability_Type cA = getChangeability(A), cB = getChangeability(B);
+ //rules built into these functions to stop updating incorrect values
+ setName(name);
+ setRoleName(rnA, A);
+ setRoleName(rnB, B);
+ setDoc(doc);
+ setRoleDoc(roleADoc, A);
+ setRoleDoc(roleBDoc, B);
+ setMulti(ma, A);
+ setMulti(mb, B);
+ setVisibility(vA, A);
+ setVisibility(vB, B);
+ setChangeability(cA, A);
+ setChangeability(cB, B);
+ m_pView -> showDocumentation( this, true );
+ return true;
+}
+
+void AssociationWidget::slotMenuSelection(int sel) {
+ QString oldText, newText;
+ QFont font;
+ QRegExpValidator v(QRegExp(".*"), 0);
+ Uml::Association_Type atype = getAssocType();
+ Uml::Role_Type r = Uml::B;
+
+ //if it's a collaboration message we now just use the code in floatingtextwidget
+ //this means there's some redundant code below but that's better than duplicated code
+ if (isCollaboration() && sel != ListPopupMenu::mt_Delete) {
+ m_pName->slotMenuSelection(sel);
+ return;
+ }
+
+ switch(sel) {
+ case ListPopupMenu::mt_Properties:
+ if(atype == at_Seq_Message || atype == at_Seq_Message_Self) {
+ // show op dlg for seq. diagram here
+ // don't worry about here, I don't think it can get here as
+ // line is widget on seq. diagram
+ // here just in case - remove later after testing
+ kDebug() << "AssociationWidget::slotMenuSelection(mt_Properties): "
+ << "assoctype is " << atype << endl;
+ } else { //standard assoc dialog
+ m_pView -> updateDocumentation( false );
+ showDialog();
+ }
+ break;
+
+ case ListPopupMenu::mt_Delete:
+ if (m_pAssocClassLineSel0)
+ removeAssocClassLine();
+ else if (getAssociation())
+ m_pView->removeAssocInViewAndDoc(this);
+ else
+ m_pView->removeAssoc(this);
+ break;
+
+ case ListPopupMenu::mt_Rename_MultiA:
+ r = Uml::A; // fall through
+ case ListPopupMenu::mt_Rename_MultiB:
+ if (m_role[r].m_pMulti)
+ oldText = m_role[r].m_pMulti->getText();
+ else
+ oldText = "";
+ newText = KInputDialog::getText(i18n("Multiplicity"),
+ i18n("Enter multiplicity:"),
+ oldText, NULL, m_pView, NULL, &v);
+ if (newText != oldText) {
+ if (FloatingTextWidget::isTextValid(newText)) {
+ setMulti(newText, r);
+ } else {
+ m_pView->removeWidget(m_role[r].m_pMulti);
+ m_role[r].m_pMulti = NULL;
+ }
+ }
+ break;
+
+ case ListPopupMenu::mt_Rename_Name:
+ if(m_pName)
+ oldText = m_pName->getText();
+ else
+ oldText = "";
+ newText = KInputDialog::getText(i18n("Association Name"),
+ i18n("Enter association name:"),
+ oldText, NULL, m_pView, NULL, &v);
+ if (newText != oldText) {
+ if (FloatingTextWidget::isTextValid(newText)) {
+ setName(newText);
+ } else {
+ m_pView->removeWidget(m_pName);
+ m_pName = NULL;
+ }
+ }
+ break;
+
+ case ListPopupMenu::mt_Rename_RoleAName:
+ r = Uml::A; // fall through
+ case ListPopupMenu::mt_Rename_RoleBName:
+ if (m_role[r].m_pRole)
+ oldText = m_role[r].m_pRole->getText();
+ else
+ oldText = "";
+ newText = KInputDialog::getText(i18n("Role Name"),
+ i18n("Enter role name:"),
+ oldText, NULL, m_pView, NULL, &v);
+ if (newText != oldText) {
+ if (FloatingTextWidget::isTextValid(newText)) {
+ setRoleName(newText, r);
+ } else {
+ m_pView->removeWidget(m_role[r].m_pRole);
+ m_role[r].m_pRole = NULL;
+ }
+ }
+ break;
+
+ case ListPopupMenu::mt_Change_Font:
+ font = getFont();
+ if( KFontDialog::getFont( font, false, m_pView ) )
+ lwSetFont(font);
+ break;
+
+ case ListPopupMenu::mt_Change_Font_Selection:
+ font = getFont();
+ if( KFontDialog::getFont( font, false, m_pView ) ) {
+ m_pView -> selectionSetFont( font );
+ m_umldoc->setModified(true);
+ }
+ break;
+
+ case ListPopupMenu::mt_Line_Color:
+ case ListPopupMenu::mt_Line_Color_Selection:
+ {
+ QColor newColour;
+ if( KColorDialog::getColor(newColour) ) {
+ m_pView->selectionSetLineColor(newColour);
+ m_umldoc->setModified(true);
+ }
+ }
+ break;
+
+ case ListPopupMenu::mt_Cut:
+ m_pView->setStartedCut();
+ UMLApp::app()->slotEditCut();
+ break;
+
+ case ListPopupMenu::mt_Copy:
+ UMLApp::app()->slotEditCopy();
+ break;
+
+ case ListPopupMenu::mt_Paste:
+ UMLApp::app()->slotEditPaste();
+ break;
+
+ case ListPopupMenu::mt_Reset_Label_Positions:
+ resetTextPositions();
+ break;
+ }//end switch
+}
+
+
+void AssociationWidget::lwSetFont (QFont font) {
+ if( m_pName) {
+ m_pName->setFont( font );
+ }
+ if( m_role[A].m_pRole ) {
+ m_role[A].m_pRole->setFont( font );
+ }
+ if( m_role[B].m_pRole ) {
+ m_role[B].m_pRole->setFont( font );
+ }
+ if( m_role[A].m_pMulti ) {
+ m_role[A].m_pMulti->setFont( font );
+ }
+ if( m_role[B].m_pMulti ) {
+ m_role[B].m_pMulti->setFont( font );
+ }
+ if( m_role[A].m_pChangeWidget)
+ m_role[A].m_pChangeWidget->setFont( font );
+ if( m_role[B].m_pChangeWidget)
+ m_role[B].m_pChangeWidget->setFont( font );
+}
+
+// find a general font for the association
+QFont AssociationWidget::getFont() const {
+ QFont font;
+
+ if( m_role[A].m_pRole )
+ font = m_role[A].m_pRole -> getFont( );
+ else if( m_role[B].m_pRole)
+ font = m_role[B].m_pRole -> getFont( );
+ else if( m_role[A].m_pMulti )
+ font = m_role[A].m_pMulti -> getFont( );
+ else if( m_role[B].m_pMulti )
+ font = m_role[B].m_pMulti -> getFont( );
+ else if( m_role[A].m_pChangeWidget)
+ font = m_role[A].m_pChangeWidget-> getFont( );
+ else if( m_role[B].m_pChangeWidget)
+ font = m_role[B].m_pChangeWidget-> getFont( );
+ else if( m_pName)
+ font = m_pName-> getFont( );
+ else
+ font = m_role[A].m_pWidget -> getFont();
+
+ return font;
+}
+
+void AssociationWidget::setLineColor(const QColor &colour) {
+ WidgetBase::setLineColor(colour);
+ m_LinePath.setLineColor(colour);
+}
+
+void AssociationWidget::setLineWidth(uint width) {
+ WidgetBase::setLineWidth(width);
+ m_LinePath.setLineWidth(width);
+}
+
+void AssociationWidget::checkPoints(const QPoint &p) {
+ m_nMovingPoint = -1;
+ //only check if more than the two endpoints
+ int size = m_LinePath.count();
+ if( size <= 2 )
+ return;
+ //check all points except the end points to see if we clicked on one of them
+ QPoint tempPoint;
+ int x, y;
+ const int BOUNDARY = 4; // check for pixels around the point
+ for(int i=1;i<size-1;i++) {
+ tempPoint = m_LinePath.getPoint( i );
+ x = tempPoint.x();
+ y = tempPoint.y();
+ if( x - BOUNDARY <= p.x() && x + BOUNDARY >= p.x() &&
+ y - BOUNDARY <= p.y() && y + BOUNDARY >= p.y() ) {
+ m_nMovingPoint = i;
+ break; //no need to check the rest
+ }//end if
+ }//end for
+}
+
+void AssociationWidget::mouseMoveEvent(QMouseEvent* me) {
+ if( me->state() != Qt::LeftButton) {
+ return;
+ }
+
+ // if we have no moving point,create one
+ if (m_nMovingPoint == -1)
+ {
+ //create moving point near the mouse on the line
+ int i = m_LinePath.onLinePath(me->pos());
+
+ if (i == -1)
+ return;
+ m_LinePath.insertPoint( i + 1, me->pos() );
+ m_nMovingPoint = i + 1;
+ }
+
+ setSelected();
+ //new position for point
+ QPoint p = me->pos();
+ QPoint oldp = m_LinePath.getPoint(m_nMovingPoint);
+
+ if( m_pView -> getSnapToGrid() ) {
+ int newX = m_pView->snappedX( p.x() );
+ int newY = m_pView->snappedY( p.y() );
+ p.setX(newX);
+ p.setY(newY);
+ }
+
+ // Prevent the moving vertex from disappearing underneath a widget
+ // (else there's no way to get it back.)
+ UMLWidget *onW = m_pView->getWidgetAt(p);
+ if (onW && onW->getBaseType() != Uml::wt_Box) { // boxes are transparent
+ const int pX = p.x();
+ const int pY = p.y();
+ const int wX = onW->getX();
+ const int wY = onW->getY();
+ const int wWidth = onW->getWidth();
+ const int wHeight = onW->getHeight();
+ if (pX > wX && pX < wX + wWidth) {
+ const int midX = wX + wWidth / 2;
+ if (pX <= midX)
+ p.setX(wX);
+ else
+ p.setX(wX + wWidth);
+ }
+ if (pY > wY && pY < wY + wHeight) {
+ const int midY = wY + wHeight / 2;
+ if (pY <= midY)
+ p.setY(wY);
+ else
+ p.setY(wY + wHeight);
+ }
+ }
+
+ //move event called now
+ QMoveEvent m(p, oldp);
+ moveEvent(&m);
+ m_pView->resizeCanvasToItems();
+}
+
+AssociationWidget::Region AssociationWidget::getWidgetRegion(AssociationWidget * widget) const {
+ if(widget -> getWidget(A) == m_role[A].m_pWidget)
+ return m_role[A].m_WidgetRegion;
+ if(widget -> getWidget(B) == m_role[B].m_pWidget)
+ return m_role[B].m_WidgetRegion;
+ return Error;
+}
+
+int AssociationWidget::getRegionCount(AssociationWidget::Region region, Uml::Role_Type role) {
+ if(region == Error)
+ return 0;
+ int widgetCount = 0;
+ AssociationWidgetList list = m_pView -> getAssociationList();
+ AssociationWidgetListIt assoc_it(list);
+ AssociationWidget* assocwidget = 0;
+ while((assocwidget = assoc_it.current())) {
+ ++assoc_it;
+ //don't count this association
+ if (assocwidget == this)
+ continue;
+ const WidgetRole& otherA = assocwidget->m_role[A];
+ const WidgetRole& otherB = assocwidget->m_role[B];
+ const UMLWidget *a = otherA.m_pWidget;
+ const UMLWidget *b = otherB.m_pWidget;
+ /*
+ //don't count associations to self if both of their end points are on the same region
+ //they are different and placement won't interfere with them
+ if( a == b && otherA.m_WidgetRegion == otherB.m_WidgetRegion )
+ continue;
+ */
+ if (m_role[role].m_pWidget == a && region == otherA.m_WidgetRegion)
+ widgetCount++;
+ else if (m_role[role].m_pWidget == b && region == otherB.m_WidgetRegion)
+ widgetCount++;
+ }//end while
+ return widgetCount;
+}
+
+QPoint AssociationWidget::findIntercept(const QRect &rect, const QPoint &point) {
+ Region region = findPointRegion(rect, point.x(), point.y());
+ /*
+ const char *regionStr[] = { "Error",
+ "West", "North", "East", "South",
+ "NorthWest", "NorthEast", "SouthEast", "SouthWest",
+ "Center"
+ };
+ kDebug() << "findPointRegion(rect(" << rect.x() << "," << rect.y()
+ << "," << rect.width() << "," << rect.height() << "), p("
+ << point.x() << "," << point.y() << ")) = " << regionStr[region]
+ << endl;
+ */
+ // Move some regions to the standard ones.
+ switch (region) {
+ case NorthWest:
+ region = North;
+ break;
+ case NorthEast:
+ region = East;
+ break;
+ case SouthEast:
+ region = South;
+ break;
+ case SouthWest:
+ case Center:
+ region = West;
+ break;
+ default:
+ break;
+ }
+ // The Qt coordinate system has (0,0) in the top left corner.
+ // In order to go to the regular XY coordinate system with (0,0)
+ // in the bottom left corner, we swap the X and Y axis.
+ // That's why the following assignments look twisted.
+ const int rectHalfWidth = rect.height() / 2;
+ const int rectHalfHeight = rect.width() / 2;
+ const int rectMidX = rect.y() + rectHalfWidth;
+ const int rectMidY = rect.x() + rectHalfHeight;
+ const int pX = point.y();
+ const int pY = point.x();
+ const int dX = rectMidX - pX;
+ const int dY = rectMidY - pY;
+ switch (region) {
+ case West:
+ region = South;
+ break;
+ case North:
+ region = East;
+ break;
+ case East:
+ region = North;
+ break;
+ case South:
+ region = West;
+ break;
+ default:
+ break;
+ }
+ // Now we have regular coordinates with the point (0,0) in the
+ // bottom left corner.
+ if (region == North || region == South) {
+ int yoff = rectHalfHeight;
+ if (region == North)
+ yoff = -yoff;
+ if (dX == 0) {
+ return QPoint(rectMidY + yoff, rectMidX); // swap back X and Y
+ }
+ if (dY == 0) {
+ kError() << "AssociationWidget::findIntercept usage error: "
+ << "North/South (dY == 0)" << endl;
+ return QPoint(0,0);
+ }
+ const float m = (float)dY / (float)dX;
+ const float b = (float)pY - m * pX;
+ const int inputY = rectMidY + yoff;
+ const float outputX = ((float)inputY - b) / m;
+ return QPoint(inputY, (int)outputX); // swap back X and Y
+ } else {
+ int xoff = rectHalfWidth;
+ if (region == East)
+ xoff = -xoff;
+ if (dY == 0)
+ return QPoint(rectMidY, rectMidX + xoff); // swap back X and Y
+ if (dX == 0) {
+ kError() << "AssociationWidget::findIntercept usage error: "
+ << "East/West (dX == 0)" << endl;
+ return QPoint(0,0);
+ }
+ const float m = (float)dY / (float)dX;
+ const float b = (float)pY - m * pX;
+ const int inputX = rectMidX + xoff;
+ const float outputY = m * (float)inputX + b;
+ return QPoint((int)outputY, inputX); // swap back X and Y
+ }
+}
+
+int AssociationWidget::findInterceptOnEdge(const QRect &rect,
+ AssociationWidget::Region region,
+ const QPoint &point)
+{
+ // The Qt coordinate system has (0,0) in the top left corner.
+ // In order to go to the regular XY coordinate system with (0,0)
+ // in the bottom left corner, we swap the X and Y axis.
+ // That's why the following assignments look twisted.
+ const int rectHalfWidth = rect.height() / 2;
+ const int rectHalfHeight = rect.width() / 2;
+ const int rectMidX = rect.y() + rectHalfWidth;
+ const int rectMidY = rect.x() + rectHalfHeight;
+ const int dX = rectMidX - point.y();
+ const int dY = rectMidY - point.x();
+ switch (region) {
+ case West:
+ region = South;
+ break;
+ case North:
+ region = West;
+ break;
+ case East:
+ region = North;
+ break;
+ case South:
+ region = East;
+ break;
+ default:
+ break;
+ }
+ // Now we have regular coordinates with the point (0,0) in the
+ // bottom left corner.
+ if (region == North || region == South) {
+ if (dX == 0)
+ return rectMidY;
+ // should be rectMidX, but we go back to Qt coord.sys.
+ if (dY == 0) {
+ kError() << "AssociationWidget::findInterceptOnEdge usage error: "
+ << "North/South (dY == 0)" << endl;
+ return -1;
+ }
+ const float m = (float)dY / (float)dX;
+ float relativeX;
+ if (region == North)
+ relativeX = (float)rectHalfHeight / m;
+ else
+ relativeX = -(float)rectHalfHeight / m;
+ return (rectMidY + (int)relativeX);
+ // should be rectMidX, but we go back to Qt coord.sys.
+ } else {
+ if (dY == 0)
+ return rectMidX;
+ // should be rectMidY, but we go back to Qt coord.sys.
+ if (dX == 0) {
+ kError() << "AssociationWidget::findInterceptOnEdge usage error: "
+ << "East/West (dX == 0)" << endl;
+ return -1;
+ }
+ const float m = (float)dY / (float)dX;
+ float relativeY = m * (float)rectHalfWidth;
+ if (region == West)
+ relativeY = -relativeY;
+ return (rectMidX + (int)relativeY);
+ // should be rectMidY, but we go back to Qt coord.sys.
+ }
+}
+
+void AssociationWidget::insertIntoLists(int position, const AssociationWidget* assoc)
+{
+ bool did_insertion = false;
+ for (int index = 0; index < m_positions_len; index++) {
+ if (position < m_positions[index]) {
+ for (int moveback = m_positions_len; moveback > index; moveback--)
+ m_positions[moveback] = m_positions[moveback - 1];
+ m_positions[index] = position;
+ m_ordered.insert(index, assoc);
+ did_insertion = true;
+ break;
+ }
+ }
+ if (! did_insertion) {
+ m_positions[m_positions_len] = position;
+ m_ordered.append(assoc);
+ }
+ m_positions_len++;
+}
+
+void AssociationWidget::updateAssociations(int totalCount,
+ AssociationWidget::Region region,
+ Uml::Role_Type role)
+{
+ if( region == Error )
+ return;
+ AssociationWidgetList list = m_pView -> getAssociationList();
+ AssociationWidgetListIt assoc_it(list);
+ AssociationWidget* assocwidget = 0;
+ UMLWidget *ownWidget = m_role[role].m_pWidget;
+ m_positions_len = 0;
+ m_ordered.clear();
+ // we order the AssociationWidget list by region and x/y value
+ while ( (assocwidget = assoc_it.current()) ) {
+ ++assoc_it;
+ WidgetRole *roleA = &assocwidget->m_role[A];
+ WidgetRole *roleB = &assocwidget->m_role[B];
+ UMLWidget *wA = roleA->m_pWidget;
+ UMLWidget *wB = roleB->m_pWidget;
+ // Skip self associations.
+ if (wA == wB)
+ continue;
+ // Now we must find out with which end the assocwidget connects
+ // to the input widget (ownWidget).
+ bool inWidgetARegion = ( ownWidget == wA &&
+ region == roleA->m_WidgetRegion );
+ bool inWidgetBRegion = ( ownWidget == wB &&
+ region == roleB->m_WidgetRegion);
+ if ( !inWidgetARegion && !inWidgetBRegion )
+ continue;
+ // Determine intercept position on the edge indicated by `region'.
+ UMLWidget * otherWidget = (inWidgetARegion ? wB : wA);
+ LinePath *linepath = assocwidget->getLinePath();
+ QPoint refpoint;
+ if (assocwidget->linePathStartsAt(otherWidget))
+ refpoint = linepath->getPoint(linepath->count() - 2);
+ else
+ refpoint = linepath->getPoint(1);
+ // The point is authoritative if we're called for the second time
+ // (i.e. role==B) or it is a waypoint on the line path.
+ bool pointIsAuthoritative = (role == B || linepath->count() > 2);
+ if (! pointIsAuthoritative) {
+ // If the point is not authoritative then we use the other
+ // widget's center.
+ refpoint.setX(otherWidget->getX() + otherWidget->getWidth() / 2);
+ refpoint.setY(otherWidget->getY() + otherWidget->getHeight() / 2);
+ }
+ int intercept = findInterceptOnEdge(ownWidget->rect(), region, refpoint);
+ if (intercept < 0) {
+ kDebug() << "updateAssociations: error from findInterceptOnEdge for"
+ << " assocType=" << assocwidget->getAssocType()
+ << " ownWidget=" << ownWidget->getName()
+ << " otherWidget=" << otherWidget->getName() << endl;
+ continue;
+ }
+ insertIntoLists(intercept, assocwidget);
+ } // while ( (assocwidget = assoc_it.current()) )
+
+ // we now have an ordered list and we only have to call updateRegionLineCount
+ int index = 1;
+ for (assocwidget = m_ordered.first(); assocwidget; assocwidget = m_ordered.next()) {
+ if (ownWidget == assocwidget->getWidget(A)) {
+ assocwidget->updateRegionLineCount(index++, totalCount, region, A);
+ } else if (ownWidget == assocwidget->getWidget(B)) {
+ assocwidget->updateRegionLineCount(index++, totalCount, region, B);
+ }
+ } // for (assocwidget = ordered.first(); ...)
+}
+
+void AssociationWidget::updateRegionLineCount(int index, int totalCount,
+ AssociationWidget::Region region,
+ Uml::Role_Type role) {
+ if( region == Error )
+ return;
+ // If the association is to self and the line ends are on the same region then
+ // use a different calculation.
+ if (m_role[A].m_pWidget == m_role[B].m_pWidget &&
+ m_role[A].m_WidgetRegion == m_role[B].m_WidgetRegion) {
+ UMLWidget * pWidget = m_role[A].m_pWidget;
+ int x = pWidget -> getX();
+ int y = pWidget -> getY();
+ int wh = pWidget -> height();
+ int ww = pWidget -> width();
+ int size = m_LinePath.count();
+ // See if above widget ok to place assoc.
+ switch( m_role[A].m_WidgetRegion ) {
+ case North:
+ m_LinePath.setPoint( 0, QPoint( x + ( ww / 4 ), y ) );
+ m_LinePath.setPoint( size - 1, QPoint(x + ( ww * 3 / 4 ), y ) );
+ break;
+
+ case South:
+ m_LinePath.setPoint( 0, QPoint( x + ( ww / 4 ), y + wh ) );
+ m_LinePath.setPoint( size - 1, QPoint( x + ( ww * 3 / 4 ), y + wh ) );
+ break;
+
+ case East:
+ m_LinePath.setPoint( 0, QPoint( x + ww, y + ( wh / 4 ) ) );
+ m_LinePath.setPoint( size - 1, QPoint( x + ww, y + ( wh * 3 / 4 ) ) );
+ break;
+
+ case West:
+ m_LinePath.setPoint( 0, QPoint( x, y + ( wh / 4 ) ) );
+ m_LinePath.setPoint( size - 1, QPoint( x, y + ( wh * 3 / 4 ) ) );
+ break;
+ default:
+ break;
+ }//end switch
+ m_role[A].m_OldCorner.setX( x );
+ m_role[A].m_OldCorner.setY( y );
+ m_role[B].m_OldCorner.setX( x );
+ m_role[B].m_OldCorner.setY( y );
+
+ return;
+ }
+
+ WidgetRole& robj = m_role[role];
+ UMLWidget * pWidget = robj.m_pWidget;
+
+ robj.m_nIndex = index;
+ robj.m_nTotalCount = totalCount;
+ int x = pWidget->getX();
+ int y = pWidget->getY();
+ robj.m_OldCorner.setX(x);
+ robj.m_OldCorner.setY(y);
+ int ww = pWidget->getWidth();
+ int wh = pWidget->getHeight();
+ const bool angular = Settings::getOptionState().generalState.angularlines;
+ int ch = 0;
+ int cw = 0;
+ if (angular) {
+ uint nind = (role == A ? 1 : m_LinePath.count() - 2);
+ QPoint neighbour = m_LinePath.getPoint(nind);
+ if (neighbour.x() < x)
+ cw = 0;
+ else if (neighbour.x() > x + ww)
+ cw = 0 + ww;
+ else
+ cw = neighbour.x() - x;
+ if (neighbour.y() < y)
+ ch = 0;
+ else if (neighbour.y() > y + wh)
+ ch = 0 + wh;
+ else
+ ch = neighbour.y() - y;
+ } else {
+ ch = wh * index / totalCount;
+ cw = ww * index / totalCount;
+ }
+
+ int snapX = m_pView->snappedX(x + cw);
+ int snapY = m_pView->snappedY(y + ch);
+
+ QPoint pt;
+ if (angular) {
+ pt = QPoint(snapX, snapY);
+ } else {
+ switch(region) {
+ case West:
+ pt.setX(x);
+ pt.setY(snapY);
+ break;
+ case North:
+ pt.setX(snapX);
+ pt.setY(y);
+ break;
+ case East:
+ pt.setX(x + ww);
+ pt.setY(snapY);
+ break;
+ case South:
+ pt.setX(snapX);
+ pt.setY(y + wh);
+ break;
+ case Center:
+ pt.setX(x + ww / 2);
+ pt.setY(y + wh / 2);
+ break;
+ default:
+ break;
+ }
+ }
+ if (role == A)
+ m_LinePath.setPoint( 0, pt );
+ else {
+ m_LinePath.setPoint( m_LinePath.count() - 1, pt );
+ LinePath::Region r = ( region == South || region == North ) ?
+ LinePath::TopBottom : LinePath::LeftRight;
+ m_LinePath.setDockRegion( r );
+ }
+}
+
+void AssociationWidget::setSelected(bool _select /* = true */) {
+ m_bSelected = _select;
+ if( m_pName)
+ m_pName-> setSelected( _select );
+ if( m_role[A].m_pRole )
+ m_role[A].m_pRole -> setSelected( _select );
+ if( m_role[B].m_pRole )
+ m_role[B].m_pRole -> setSelected( _select );
+ if( m_role[A].m_pMulti )
+ m_role[A].m_pMulti -> setSelected( _select );
+ if( m_role[B].m_pMulti )
+ m_role[B].m_pMulti -> setSelected( _select );
+ if( m_role[A].m_pChangeWidget)
+ m_role[A].m_pChangeWidget-> setSelected( _select );
+ if( m_role[B].m_pChangeWidget)
+ m_role[B].m_pChangeWidget-> setSelected( _select );
+ kapp->processEvents();
+ //Update the docwindow for this association.
+ // This is done last because each of the above setSelected calls
+ // overwrites the docwindow, but we want the main association doc
+ // to win.
+ if( _select ) {
+ if( m_pView -> getSelectCount() == 0 )
+ m_pView -> showDocumentation( this, false );
+ } else
+ m_pView -> updateDocumentation( true );
+ kapp->processEvents();
+ m_LinePath.setSelected( _select );
+ if (! _select) {
+ // For now, if _select is true we don't make the assoc class line
+ // selected. But that's certainly open for discussion.
+ // At any rate, we need to deselect the assoc class line
+ // if _select is false.
+ selectAssocClassLine(false);
+ }
+}
+
+bool AssociationWidget::onAssocClassLine(const QPoint &point) {
+ if (m_pAssocClassLine == NULL)
+ return false;
+ QCanvasItemList list = m_pView->canvas()->collisions(point);
+ QCanvasItemList::iterator end(list.end());
+ for (QCanvasItemList::iterator item_it(list.begin()); item_it != end; ++item_it) {
+ if (*item_it == m_pAssocClassLine)
+ return true;
+ }
+ return false;
+}
+
+bool AssociationWidget::onAssociation(const QPoint & point) {
+ if (m_LinePath.onLinePath(point) != -1)
+ return true;
+ return onAssocClassLine(point);
+}
+
+void AssociationWidget::slotRemovePopupMenu()
+{
+ if(m_pMenu) {
+ disconnect(m_pMenu, SIGNAL(activated(int)), this, SLOT(slotMenuSelection(int)));
+ delete m_pMenu;
+ m_pMenu = 0;
+ }
+}
+
+void AssociationWidget::slotClearAllSelected() {
+ setSelected( false );
+}
+
+void AssociationWidget::moveMidPointsBy( int x, int y ) {
+ int pos = m_LinePath.count() - 1;
+ for( int i=1 ; i < (int)pos ; i++ ) {
+ QPoint p = m_LinePath.getPoint( i );
+ int newX = p.x() + x;
+ int newY = p.y() + y;
+ newX = m_pView -> snappedX( newX );
+ newY = m_pView -> snappedY( newY );
+ p.setX( newX );
+ p.setY( newY );
+ m_LinePath.setPoint( i, p );
+ }
+}
+
+void AssociationWidget::moveEntireAssoc( int x, int y ) {
+ //TODO: ADD SUPPORT FOR ASSOC. ON SEQ. DIAGRAMS WHEN NOTES BACK IN.
+ moveMidPointsBy( x, y );
+ calculateEndingPoints();
+ calculateNameTextSegment();
+ resetTextPositions();
+}
+
+QRect AssociationWidget::getAssocLineRectangle()
+{
+ QRect rectangle;
+ QPoint p;
+ uint pen_width;
+
+ /* we also want the end points connected to the other widget */
+ int pos = m_LinePath.count();
+
+ /* go through all points on the linepath */
+ for( int i=0 ; i < (int) pos; i++ )
+ {
+ p = m_LinePath.getPoint( i );
+
+ /* the first point is our starting point */
+ if (i == 0) {
+ rectangle.setRect(p.x(), p.y(), 0, 0);
+ continue;
+ }
+
+ /* the lines have the width of the pen */
+ pen_width = m_LinePath.getPen().width();
+ if (pen_width == 0)
+ pen_width = 1; // width must be at least 1
+
+ if (p.x() < rectangle.x())
+ rectangle.setX(p.x());
+ if (p.y() < rectangle.y())
+ rectangle.setY(p.y());
+ if (p.x() > rectangle.x() + rectangle.width()) {
+ int newX = p.x() - rectangle.x() + pen_width;
+ rectangle.setWidth(abs(newX));
+ }
+ if (p.y() > rectangle.y() + rectangle.height()) {
+ int newY = p.y() - rectangle.y() + pen_width;
+ rectangle.setHeight(abs(newY));
+ }
+ }
+ return rectangle;
+}
+
+void AssociationWidget::setUMLObject(UMLObject *obj) {
+ WidgetBase::setUMLObject(obj);
+ if (obj == NULL)
+ return;
+ UMLClassifier *klass = NULL;
+ UMLAttribute *attr = NULL;
+ UMLEntity *ent = NULL;
+ const Uml::Object_Type ot = obj->getBaseType();
+ switch (ot) {
+ case Uml::ot_Association:
+ setUMLAssociation(dynamic_cast<UMLAssociation*>(obj));
+ break;
+ case Uml::ot_Operation:
+ setOperation(dynamic_cast<UMLOperation *>(obj));
+ break;
+ case Uml::ot_Attribute:
+ klass = static_cast<UMLClassifier*>(obj->parent());
+ connect(klass, SIGNAL(attributeRemoved(UMLClassifierListItem*)),
+ this, SLOT(slotAttributeRemoved(UMLClassifierListItem*)));
+ attr = static_cast<UMLAttribute*>(obj);
+ connect(attr, SIGNAL(attributeChanged()), this, SLOT(slotAttributeChanged()));
+ break;
+ case Uml::ot_EntityAttribute:
+ ent = static_cast<UMLEntity*>(obj->parent());
+ connect(ent, SIGNAL(entityAttributeRemoved(UMLClassifierListItem*)),
+ this, SLOT(slotAttributeRemoved(UMLClassifierListItem*)));
+ break;
+ default:
+ kError() << "UMLAssociation constructor: cannot associate UMLObject of type "
+ << ot << endl;
+ }
+}
+
+void AssociationWidget::slotAttributeRemoved(UMLClassifierListItem* obj) {
+ if (obj != m_pObject)
+ kDebug() << "AssociationWidget::slotAttributeRemoved:(obj=" << obj
+ << "): m_pObject=" << m_pObject << endl;
+ m_pObject = NULL;
+ m_pView->removeAssoc(this);
+}
+
+void AssociationWidget::slotAttributeChanged() {
+ UMLAttribute *attr = getAttribute();
+ if (attr == NULL) {
+ kError() << "AssociationWidget::slotAttributeChanged: getAttribute returns NULL"
+ << endl;
+ return;
+ }
+ setVisibility(attr->getVisibility(), B);
+ setRoleName(attr->getName(), B);
+}
+
+void AssociationWidget::init (UMLView *view)
+{
+ WidgetBase::init(view, wt_Association);
+
+ // pointers to floating text widgets objects owned by this association
+ m_pName = 0;
+ m_role[A].m_pChangeWidget = 0;
+ m_role[B].m_pChangeWidget = 0;
+ m_role[A].m_pMulti = 0;
+ m_role[B].m_pMulti = 0;
+ m_role[A].m_pRole = 0;
+ m_role[B].m_pRole = 0;
+ m_role[A].m_pWidget = 0;
+ m_role[B].m_pWidget = 0;
+
+ // associationwidget attributes
+ m_role[A].m_WidgetRegion = Error;
+ m_role[B].m_WidgetRegion = Error;
+ m_role[A].m_nIndex = 0;
+ m_role[B].m_nIndex = 0;
+ m_role[A].m_nTotalCount = 0;
+ m_role[B].m_nTotalCount = 0;
+ m_role[A].m_Visibility = Uml::Visibility::Public;
+ m_role[B].m_Visibility = Uml::Visibility::Public;
+ m_role[A].m_Changeability = Uml::chg_Changeable;
+ m_role[B].m_Changeability = Uml::chg_Changeable;
+ m_positions_len = 0;
+ m_bActivated = false;
+ m_unNameLineSegment = 0;
+ m_pMenu = 0;
+ m_bSelected = false;
+ m_nMovingPoint = -1;
+ m_nLinePathSegmentIndex = -1;
+ m_pAssocClassWidget = NULL;
+ m_pAssocClassLine = NULL;
+ m_pAssocClassLineSel0 = m_pAssocClassLineSel1 = NULL;
+
+ // Initialize local members.
+ // These are only used if we don't have a UMLAssociation attached.
+ m_AssocType = Uml::at_Association;
+ m_umldoc = UMLApp::app()->getDocument();
+ m_LinePath.setAssociation( this );
+
+ connect(m_pView, SIGNAL(sigRemovePopupMenu()), this, SLOT(slotRemovePopupMenu()));
+ connect(m_pView, SIGNAL( sigClearAllSelected() ), this, SLOT( slotClearAllSelected() ) );
+}
+
+void AssociationWidget::resetTextPositions() {
+ if (m_role[A].m_pMulti) {
+ setTextPosition( tr_MultiA );
+ }
+ if (m_role[B].m_pMulti) {
+ setTextPosition( tr_MultiB );
+ }
+ if (m_role[A].m_pChangeWidget) {
+ setTextPosition( tr_ChangeA );
+ }
+ if (m_role[B].m_pChangeWidget) {
+ setTextPosition( tr_ChangeB );
+ }
+ if (m_pName) {
+ setTextPosition( tr_Name );
+ }
+ if (m_role[A].m_pRole) {
+ setTextPosition( tr_RoleAName );
+ }
+ if (m_role[B].m_pRole) {
+ setTextPosition( tr_RoleBName );
+ }
+}
+
+void AssociationWidget::setIndex(int index, Uml::Role_Type role) {
+ m_role[role].m_nIndex = index;
+}
+
+int AssociationWidget::getIndex(Uml::Role_Type role) const {
+ return m_role[role].m_nIndex;
+}
+
+void AssociationWidget::setTotalCount(int count, Uml::Role_Type role) {
+ m_role[role].m_nTotalCount = count;
+}
+
+int AssociationWidget::getTotalCount(Uml::Role_Type role) const {
+ return m_role[role].m_nTotalCount;
+}
+
+UMLOperation *AssociationWidget::getOperation() {
+ return dynamic_cast<UMLOperation*>(m_pObject);
+}
+
+void AssociationWidget::setOperation(UMLOperation *op) {
+ if (m_pObject)
+ disconnect(m_pObject, SIGNAL(modified()), m_pName, SLOT(setMessageText()));
+ m_pObject = op;
+ if (m_pObject)
+ connect(m_pObject, SIGNAL(modified()), m_pName, SLOT(setMessageText()));
+}
+
+UMLClassifier *AssociationWidget::getOperationOwner() {
+ Uml::Role_Type role = (isCollaboration() ? B : A);
+ UMLObject *o = getWidget(role)->getUMLObject();
+ if (o == NULL)
+ return NULL;
+ UMLClassifier *c = dynamic_cast<UMLClassifier*>(o);
+ if (c == NULL)
+ kError() << "AssociationWidget::getOperationOwner: "
+ << "getWidget(" << role << ") is not a classifier"
+ << endl;
+ return c;
+}
+
+void AssociationWidget::setSeqNumAndOp(const QString &seqNum, const QString &op) {
+ if (! op.isEmpty())
+ setName(op);
+ setMulti(seqNum, A);
+}
+
+UMLClassifier *AssociationWidget::getSeqNumAndOp(QString& seqNum, QString& op) {
+ seqNum = getMulti(A);
+ op = getName();
+ UMLObject *o = getWidget(B)->getUMLObject();
+ UMLClassifier *c = dynamic_cast<UMLClassifier*>(o);
+ return c;
+}
+
+void AssociationWidget::setCustomOpText(const QString &opText) {
+ setName(opText);
+}
+
+QString AssociationWidget::getCustomOpText() {
+ return getName();
+}
+
+void AssociationWidget::setWidget( UMLWidget* widget, Uml::Role_Type role) {
+ m_role[role].m_pWidget = widget;
+ if (widget) {
+ m_role[role].m_pWidget->addAssoc(this);
+ if (m_pObject && m_pObject->getBaseType() == ot_Association)
+ getAssociation()->setObject(widget->getUMLObject(), role);
+ }
+}
+
+void AssociationWidget::saveToXMI( QDomDocument & qDoc, QDomElement & qElement ) {
+ QDomElement assocElement = qDoc.createElement( "assocwidget" );
+
+ WidgetBase::saveToXMI(qDoc, assocElement);
+ if (m_pObject) {
+ assocElement.setAttribute( "xmi.id", ID2STR(m_pObject->getID()) );
+ }
+ assocElement.setAttribute( "type", m_AssocType );
+ if (getAssociation() == NULL) {
+ assocElement.setAttribute( "visibilityA", m_role[A].m_Visibility);
+ assocElement.setAttribute( "visibilityB", m_role[B].m_Visibility);
+ assocElement.setAttribute( "changeabilityA", m_role[A].m_Changeability);
+ assocElement.setAttribute( "changeabilityB", m_role[B].m_Changeability);
+ if (m_pObject == NULL) {
+ assocElement.setAttribute( "roleAdoc", m_role[A].m_RoleDoc);
+ assocElement.setAttribute( "roleBdoc", m_role[B].m_RoleDoc);
+ assocElement.setAttribute( "documentation", m_Doc );
+ }
+ }
+ assocElement.setAttribute( "widgetaid", ID2STR(getWidgetID(A)) );
+ assocElement.setAttribute( "widgetbid", ID2STR(getWidgetID(B)) );
+ assocElement.setAttribute( "indexa", m_role[A].m_nIndex );
+ assocElement.setAttribute( "indexb", m_role[B].m_nIndex );
+ assocElement.setAttribute( "totalcounta", m_role[A].m_nTotalCount );
+ assocElement.setAttribute( "totalcountb", m_role[B].m_nTotalCount );
+ m_LinePath.saveToXMI( qDoc, assocElement );
+
+ if( m_pName )
+ m_pName -> saveToXMI( qDoc, assocElement );
+
+ if( m_role[A].m_pMulti )
+ m_role[A].m_pMulti -> saveToXMI( qDoc, assocElement );
+
+ if( m_role[B].m_pMulti )
+ m_role[B].m_pMulti -> saveToXMI( qDoc, assocElement );
+
+ if( m_role[A].m_pRole )
+ m_role[A].m_pRole -> saveToXMI( qDoc, assocElement );
+
+ if( m_role[B].m_pRole )
+ m_role[B].m_pRole -> saveToXMI( qDoc, assocElement );
+
+ if( m_role[A].m_pChangeWidget )
+ m_role[A].m_pChangeWidget -> saveToXMI( qDoc, assocElement );
+
+ if( m_role[B].m_pChangeWidget )
+ m_role[B].m_pChangeWidget -> saveToXMI( qDoc, assocElement );
+
+ if (m_pAssocClassWidget) {
+ QString acid = ID2STR(m_pAssocClassWidget->getID());
+ assocElement.setAttribute("assocclass", acid);
+ assocElement.setAttribute("aclsegindex", m_nLinePathSegmentIndex);
+ }
+
+ qElement.appendChild( assocElement );
+}
+
+bool AssociationWidget::loadFromXMI( QDomElement & qElement,
+ const UMLWidgetList& widgets,
+ const MessageWidgetList* pMessages )
+{
+ WidgetBase::loadFromXMI(qElement);
+
+ // load child widgets first
+ QString widgetaid = qElement.attribute( "widgetaid", "-1" );
+ QString widgetbid = qElement.attribute( "widgetbid", "-1" );
+ Uml::IDType aId = STR2ID(widgetaid);
+ Uml::IDType bId = STR2ID(widgetbid);
+ UMLWidget *pWidgetA = Widget_Utils::findWidget( aId, widgets, pMessages );
+ if (!pWidgetA) {
+ kError() << "AssociationWidget::loadFromXMI(): "
+ << "cannot find widget for roleA id " << ID2STR(aId) << endl;
+ return false;
+ }
+ UMLWidget *pWidgetB = Widget_Utils::findWidget( bId, widgets, pMessages );
+ if (!pWidgetB) {
+ kError() << "AssociationWidget::loadFromXMI(): "
+ << "cannot find widget for roleB id " << ID2STR(bId) << endl;
+ return false;
+ }
+ setWidget(pWidgetA, A);
+ setWidget(pWidgetB, B);
+
+ QString type = qElement.attribute( "type", "-1" );
+ Uml::Association_Type aType = (Uml::Association_Type) type.toInt();
+
+ QString id = qElement.attribute( "xmi.id", "-1" );
+ bool oldStyleLoad = false;
+ if (id == "-1") {
+ // xmi.id not present, ergo either a pure widget association,
+ // or old (pre-1.2) style:
+ // Everything is loaded from the AssociationWidget.
+ // UMLAssociation may or may not be saved - if it is, it's a dummy.
+ // Create the UMLAssociation if both roles are UML objects;
+ // else load the info locally.
+
+ if (UMLAssociation::assocTypeHasUMLRepresentation(aType)) {
+ // lack of an association in our widget AND presence of
+ // both uml objects for each role clearly identifies this
+ // as reading in an old-school file. Note it as such, and
+ // create, and add, the UMLAssociation for this widget.
+ // Remove this special code when backwards compatibility
+ // with older files isn't important anymore. -b.t.
+ UMLObject* umlRoleA = pWidgetA->getUMLObject();
+ UMLObject* umlRoleB = pWidgetB->getUMLObject();
+ if (!m_pObject && umlRoleA && umlRoleB)
+ {
+ oldStyleLoad = true; // flag for further special config below
+ if (aType == at_Aggregation || aType == at_Composition) {
+ kWarning()<<" Old Style save file? swapping roles on association widget"<<this<<endl;
+ // We have to swap the A and B widgets to compensate
+ // for the long standing bug in LinePath of drawing
+ // the diamond at the wrong end which was fixed
+ // just before the 1.2 release.
+ // The logic here is that the user has understood
+ // that the diamond belongs at the SOURCE end of the
+ // the association (i.e. at the container, not at the
+ // contained), and has compensated for this anomaly
+ // by drawing the aggregations/compositions from
+ // target to source.
+ UMLWidget *tmpWidget = pWidgetA;
+ pWidgetA = pWidgetB;
+ pWidgetB = tmpWidget;
+ setWidget(pWidgetA, A);
+ setWidget(pWidgetB, B);
+ umlRoleA = pWidgetA->getUMLObject();
+ umlRoleB = pWidgetB->getUMLObject();
+ }
+
+ setUMLAssociation(m_umldoc->createUMLAssociation(umlRoleA, umlRoleB, aType));
+ }
+ }
+
+ setDoc( qElement.attribute("documentation", "") );
+ setRoleDoc( qElement.attribute("roleAdoc", ""), A );
+ setRoleDoc( qElement.attribute("roleBdoc", ""), B );
+
+ // visibilty defaults to Public if it cant set it here..
+ QString visibilityA = qElement.attribute( "visibilityA", "0");
+ if (visibilityA.toInt() > 0)
+ setVisibility( (Uml::Visibility::Value)visibilityA.toInt(), A);
+
+ QString visibilityB = qElement.attribute( "visibilityB", "0");
+ if (visibilityB.toInt() > 0)
+ setVisibility( (Uml::Visibility::Value)visibilityB.toInt(), B);
+
+ // Changeability defaults to "Changeable" if it cant set it here..
+ QString changeabilityA = qElement.attribute( "changeabilityA", "0");
+ if (changeabilityA.toInt() > 0)
+ setChangeability( (Uml::Changeability_Type)changeabilityA.toInt(), A);
+
+ QString changeabilityB = qElement.attribute( "changeabilityB", "0");
+ if (changeabilityB.toInt() > 0)
+ setChangeability( (Uml::Changeability_Type)changeabilityB.toInt(), B);
+
+ } else {
+
+ // we should disconnect any prior association (can this happen??)
+ if (m_pObject && m_pObject->getBaseType() == ot_Association)
+ {
+ UMLAssociation *umla = getAssociation();
+ umla->disconnect(this);
+ umla->nrof_parent_widgets--;
+ }
+
+ // New style: The xmi.id is a reference to the UMLAssociation.
+ // If the UMLObject is not found right now, we try again later
+ // during the type resolution pass - see activate().
+ m_nId = STR2ID(id);
+ UMLObject *myObj = m_umldoc->findObjectById(m_nId);
+ if (myObj) {
+ const Uml::Object_Type ot = myObj->getBaseType();
+ if (ot != ot_Association) {
+ setUMLObject(myObj);
+ } else {
+ UMLAssociation * myAssoc = static_cast<UMLAssociation*>(myObj);
+ setUMLAssociation(myAssoc);
+ if (type == "-1")
+ aType = myAssoc->getAssocType();
+ }
+ }
+ }
+
+ setAssocType(aType);
+
+ QString indexa = qElement.attribute( "indexa", "0" );
+ QString indexb = qElement.attribute( "indexb", "0" );
+ QString totalcounta = qElement.attribute( "totalcounta", "0" );
+ QString totalcountb = qElement.attribute( "totalcountb", "0" );
+ m_role[A].m_nIndex = indexa.toInt();
+ m_role[B].m_nIndex = indexb.toInt();
+ m_role[A].m_nTotalCount = totalcounta.toInt();
+ m_role[B].m_nTotalCount = totalcountb.toInt();
+
+ QString assocclassid = qElement.attribute("assocclass", "");
+ if (! assocclassid.isEmpty()) {
+ Uml::IDType acid = STR2ID(assocclassid);
+ UMLWidget *w = Widget_Utils::findWidget(acid, widgets);
+ if (w) {
+ m_pAssocClassWidget = static_cast<ClassifierWidget*>(w);
+ m_pAssocClassWidget->setClassAssocWidget(this);
+ // Preparation of the assoc class line is done in activate()
+ QString aclsegindex = qElement.attribute("aclsegindex", "0");
+ m_nLinePathSegmentIndex = aclsegindex.toInt();
+ } else {
+ kError() << "AssociationWidget::loadFromXMI: "
+ << "cannot find assocclass " << assocclassid
+ << endl;
+ }
+ }
+
+ //now load child elements
+ QDomNode node = qElement.firstChild();
+ QDomElement element = node.toElement();
+ while( !element.isNull() ) {
+ QString tag = element.tagName();
+ if( tag == "linepath" ) {
+ if( !m_LinePath.loadFromXMI( element ) )
+ return false;
+ else {
+ // set up 'old' corner from first point in line
+ // as IF this ISNT done, then the subsequent call to
+ // widgetMoved will inadvertantly think we have made a
+ // big move in the position of the association when we haven't.
+ QPoint p = m_LinePath.getPoint(0);
+ m_role[A].m_OldCorner.setX(p.x());
+ m_role[A].m_OldCorner.setY(p.y());
+ }
+ } else if (tag == "floatingtext" ||
+ tag == "UML:FloatingTextWidget") { // for bkwd compatibility
+ QString r = element.attribute( "role", "-1");
+ if( r == "-1" )
+ return false;
+ Uml::Text_Role role = (Uml::Text_Role)r.toInt();
+ FloatingTextWidget *ft = new FloatingTextWidget(m_pView, role, "", Uml::id_Reserved);
+ if( ! ft->loadFromXMI(element) ) {
+ // Most likely cause: The FloatingTextWidget is empty.
+ delete ft;
+ node = element.nextSibling();
+ element = node.toElement();
+ continue;
+ }
+ // always need this
+ ft->setLink(this);
+
+ switch( role ) {
+ case Uml::tr_MultiA:
+ m_role[A].m_pMulti = ft;
+ if(oldStyleLoad)
+ setMulti(m_role[A].m_pMulti->getText(), A);
+ break;
+
+ case Uml::tr_MultiB:
+ m_role[B].m_pMulti = ft;
+ if(oldStyleLoad)
+ setMulti(m_role[B].m_pMulti->getText(), B);
+ break;
+
+ case Uml::tr_ChangeA:
+ m_role[A].m_pChangeWidget = ft;
+ break;
+
+ case Uml::tr_ChangeB:
+ m_role[B].m_pChangeWidget = ft;
+ break;
+
+ case Uml::tr_Name:
+ m_pName = ft;
+ if(oldStyleLoad)
+ setName(m_pName->getText());
+ break;
+
+ case Uml::tr_Coll_Message:
+ case Uml::tr_Coll_Message_Self:
+ m_pName = ft;
+ ft->setLink(this);
+ ft->setActivated();
+ if(FloatingTextWidget::isTextValid(ft->getText()))
+ ft -> show();
+ else
+ ft -> hide();
+ break;
+
+ case Uml::tr_RoleAName:
+ m_role[A].m_pRole = ft;
+ setRoleName( ft->getText(), A );
+ break;
+ case Uml::tr_RoleBName:
+ m_role[B].m_pRole = ft;
+ setRoleName( ft->getText(), B );
+ break;
+ default:
+ kDebug() << "AssociationWidget::loadFromXMI(): "
+ << "unexpected FloatingTextWidget (textrole "
+ << role << ")" << endl;
+ delete ft;
+ break;
+ }
+ }
+ node = element.nextSibling();
+ element = node.toElement();
+ }
+
+ return true;
+}
+
+bool AssociationWidget::loadFromXMI( QDomElement & qElement ) {
+ const MessageWidgetList& messages = m_pView->getMessageList();
+ return loadFromXMI( qElement, m_pView->getWidgetList(), &messages );
+}
+
+#include "associationwidget.moc"
diff --git a/umbrello/umbrello/associationwidget.h b/umbrello/umbrello/associationwidget.h
new file mode 100644
index 00000000..67739450
--- /dev/null
+++ b/umbrello/umbrello/associationwidget.h
@@ -0,0 +1,1045 @@
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * copyright (C) 2002-2006 *
+ * Umbrello UML Modeller Authors <uml-devel@uml.sf.net> *
+ ***************************************************************************/
+
+#ifndef ASSOCIATIONWIDGET_H
+#define ASSOCIATIONWIDGET_H
+
+#include "widgetbase.h"
+#include "linkwidget.h"
+#include "umlwidgetlist.h"
+#include "messagewidgetlist.h"
+#include "associationwidgetlist.h"
+#include "linepath.h"
+
+class IDChangeLog;
+class ListPopupMenu;
+class QBitmap;
+class QPixmap;
+class QDataStream;
+class QCanvasLine;
+class ClassifierWidget;
+class UMLDoc;
+class UMLView;
+class UMLAssociation;
+class UMLClassifierListItem;
+class UMLAttribute;
+class UMLOperation;
+
+/**
+ * This class represents an association inside a diagram.
+ *
+ * Associations exist not only between UML objects. For example, when a Note is
+ * attached to a UML object, the Note itself is not a UML object.
+ * This class supports both kinds of associations. An association where one or
+ * both roles are not a UML object is called a "pure widget association".
+ *
+ * An AssociationWidget where both roles are UML objects has a corresponding
+ * UMLAssociation. The UMLAssociation can be retrieved using the getAssociation
+ * method.
+ * A pure widget association does not have a corresponding UMLAssociation.
+ * The getAssociation method returns NULL in this case.
+ *
+ *
+ * @author Gustavo Madrigal
+ * @short This class represents an association inside a diagram.
+ * Bugs and comments to uml-devel@lists.sf.net or http://bugs.kde.org
+ */
+class AssociationWidget : public WidgetBase, public LinkWidget {
+ Q_OBJECT
+public:
+ /**
+ * Enumeration used for stating where a line is on a widget.
+ */
+ enum Region {
+ Error = 0,
+ West, North, East, South,
+ NorthWest, NorthEast, SouthEast, SouthWest,
+ Center
+ };
+
+ /**
+ * Constructor.
+ *
+ * @param view The parent view of this widget.
+ */
+ AssociationWidget(UMLView *view);
+
+ /**
+ * Constructor.
+ *
+ * @param view The parent view of this widget.
+ * @param WidgetA Pointer to the role A widget for the association.
+ * @param Type The Association_Type for this association.
+ * @param WidgetB Pointer to the role B widget for the association.
+ * @param umlobject Pointer to the underlying UMLObject (if applicable.)
+ */
+ AssociationWidget(UMLView *view, UMLWidget* WidgetA,
+ Uml::Association_Type Type, UMLWidget* WidgetB,
+ UMLObject *umlobject = NULL);
+
+ /**
+ * Deconstructor.
+ */
+ virtual ~AssociationWidget();
+
+ /**
+ * Overrides the assignment operator.
+ */
+ AssociationWidget& operator=(AssociationWidget & Other);
+
+ /**
+ * Overrides the equality test operator.
+ */
+ bool operator==(AssociationWidget & Other);
+
+ /**
+ * Overrides the != operator.
+ */
+ bool operator!=(AssociationWidget & Other);
+
+ /**
+ * Activates the AssociationWidget after a load.
+ *
+ * @return true for success
+ */
+ bool activate();
+
+ /**
+ * Set the widget of the given role.
+ *
+ * @param widget Pointer to the UMLWidget.
+ * @param role Role for which to set the widget.
+ */
+ void setWidget(UMLWidget* widget, Uml::Role_Type role);
+
+ /**
+ * Return the multiplicity FloatingTextWidget widget of the given role.
+ *
+ * @return Pointer to the multiplicity FloatingTextWidget object.
+ */
+ FloatingTextWidget* getMultiWidget(Uml::Role_Type role);
+
+ /**
+ * Return the given role's multiplicity text.
+ *
+ * @return Text of the given role's multiplicity widget.
+ */
+ QString getMulti(Uml::Role_Type role) const;
+
+ /**
+ * Read property of FloatingTextWidget* m_pName.
+ *
+ * @return Pointer to the FloatingTextWidget name widget.
+ */
+ FloatingTextWidget* getNameWidget();
+
+ /**
+ * Returns the m_pName's text.
+ *
+ * @return Text of the FloatingTextWidget name widget.
+ */
+ QString getName() const;
+
+ /**
+ * Return the given role's FloatingTextWidget object.
+ *
+ * @return Pointer to the role's FloatingTextWidget widget.
+ */
+ FloatingTextWidget* getRoleWidget(Uml::Role_Type role);
+
+ /**
+ * Return the FloatingTextWidget object indicated by the given Text_Role.
+ *
+ * @return Pointer to the text role's FloatingTextWidget widget.
+ */
+ FloatingTextWidget* getTextWidgetByRole(Uml::Text_Role tr);
+
+ /**
+ * Return the given role's FloatingTextWidget widget text.
+ *
+ * @return The name set at the FloatingTextWidget.
+ */
+ QString getRoleName(Uml::Role_Type role) const;
+
+ /**
+ * Returns the given role's documentation.
+ */
+ QString getRoleDoc(Uml::Role_Type role) const;
+
+ /**
+ * Sets the text in the FloatingTextWidget widget representing the Name
+ * of this association.
+ */
+ void setName (const QString &strRole);
+
+ /**
+ * Sets the text in the FloatingTextWidget representing the multiplicity
+ * at the given side of the association.
+ */
+ void setMulti(const QString &strMulti, Uml::Role_Type role);
+
+ /**
+ * Gets the visibility on the given role of the association.
+ */
+ Uml::Visibility getVisibility (Uml::Role_Type role) const;
+
+ /**
+ * Sets the visibility on the given role of the association.
+ */
+ void setVisibility (Uml::Visibility visibility, Uml::Role_Type role );
+
+ /**
+ * Gets the changeability on the the given end of the Association.
+ */
+ Uml::Changeability_Type getChangeability(Uml::Role_Type role) const;
+
+ /**
+ * Sets the changeability on the the given end of the Association.
+ */
+ void setChangeability (Uml::Changeability_Type value, Uml::Role_Type role);
+
+ /**
+ * Gets the ID of the given role widget.
+ */
+ Uml::IDType getWidgetID(Uml::Role_Type role) const;
+
+ /**
+ * Gets the given role widget.
+ *
+ * @return Pointer to the role's UMLWidget.
+ */
+ UMLWidget* getWidget(Uml::Role_Type role);
+
+ /**
+ * Sets the associated widgets.
+ *
+ * @param widgetA Pointer the role A widget for the association.
+ * @param assocType The Association_Type for this association.
+ * @param widgetB Pointer the role B widget for the association.
+ */
+ bool setWidgets( UMLWidget* widgetA, Uml::Association_Type assocType, UMLWidget* widgetB);
+
+ /**
+ * Returns true if this association associates widgetA to widgetB,
+ * otherwise it returns false.
+ *
+ * @param widgetA Pointer the role A widget to check.
+ * @param widgetB Pointer the role B widget to check.
+ * @return True if widgetA and widgetB are associated.
+ */
+ bool checkAssoc(UMLWidget * widgetA, UMLWidget *widgetB);
+
+ /**
+ * Returns true if the Widget is either at the starting or ending side
+ * of the association.
+ *
+ * @return True if widget plays role A or B in this assoc.
+ */
+ bool contains(UMLWidget* widget);
+
+ /**
+ * Returns true if this AssociationWidget represents a collaboration message.
+ */
+ bool isCollaboration();
+
+ /**
+ * Gets the association's type.
+ *
+ * @return This AssociationWidget's Association_Type.
+ */
+ Uml::Association_Type getAssocType() const;
+
+ /**
+ * Sets the association's type.
+ *
+ * @param type The Association_Type to set.
+ */
+ void setAssocType(Uml::Association_Type type);
+
+ /**
+ * Returns a QString object representing this AssociationWidget.
+ *
+ * @return Textual representation of the AssociationWidget.
+ */
+ QString toString();
+
+ /**
+ * Read property of bool m_bActivated.
+ *
+ * @return True if this AssociationWidget has been activated.
+ */
+ bool isActivated();
+
+ /**
+ * Set the m_bActivated flag of a widget but does not perform the
+ * activate method.
+ *
+ * @param active The flag status to set.
+ */
+ void setActivated(bool active /*=true*/);
+
+ /**
+ * Sets the state of whether the widget is selected.
+ *
+ * @param _select The state of whether the widget is selected.
+ */
+ void setSelected(bool _select = true);
+
+ /**
+ * Returns the state of whether the widget is selected.
+ *
+ * @return Returns the state of whether the widget is selected.
+ */
+ bool getSelected() const {
+ return m_bSelected;
+ }
+
+ /**
+ * Returns a pointer to the association widget's line path.
+ */
+ LinePath* getLinePath() {
+ return &m_LinePath;
+ }
+
+ /**
+ * Adjusts the ending point of the association that connects to Widget
+ *
+ * @param widget Pointer to the widget that was moved.
+ * @param x New X coordinate of the widget.
+ * @param y New Y coordinate of the widget.
+ */
+ void widgetMoved(UMLWidget* widget, int x, int y);
+
+ /**
+ * Auxiliary method for widgetMoved():
+ * Saves all ideally computed floatingtext positions before doing any
+ * kind of change. This is necessary because a single invocation of
+ * calculateEndingPoints() modifies the LinePath ending points on ALL
+ * AssociationWidgets. This means that if we don't save the old ideal
+ * positions then they are irretrievably lost as soon as
+ * calculateEndingPoints() is invoked.
+ */
+ void saveIdealTextPositions();
+
+ /**
+ * Calculates the m_unNameLineSegment value according to the new
+ * NameText topleft corner PT.
+ * It iterates through all LinePath's segments and for each one
+ * calculates the sum of PT's distance to the start point + PT's
+ * distance to the end point. The segment with the smallest sum will
+ * be the RoleTextSegment (if this segment moves then the RoleText
+ * will move with it). It sets m_unNameLineSegment to the start point
+ * of the chosen segment.
+ *
+ * Overrides operation from LinkWidget (i.e. this method is also
+ * required by FloatingTextWidget.)
+ */
+ void calculateNameTextSegment();
+
+ /**
+ * Adds a break point (if left mouse button).
+ */
+ void mouseDoubleClickEvent(QMouseEvent * me);
+
+ /**
+ * Sets the association to be selected.
+ */
+ void mousePressEvent(QMouseEvent * me);
+
+ /**
+ * Displays the right mouse buttom menu if right button is pressed.
+ */
+ void mouseReleaseEvent(QMouseEvent * me);
+
+ /**
+ * Moves the break point being dragged.
+ */
+ void mouseMoveEvent(QMouseEvent * me);
+
+ /**
+ * Returns true if the given point is on the Association.
+ */
+ bool onAssociation(const QPoint & point);
+
+ /**
+ * Returns true if the given point is on the connecting line to
+ * the association class. Returns false if there is no association
+ * class attached, or if the given point is not on the connecting
+ * line.
+ */
+ bool onAssocClassLine(const QPoint & point);
+
+ /**
+ * Creates the association class connecting line.
+ */
+ void createAssocClassLine();
+
+ /**
+ * Creates the association class connecting line using the specified
+ * ClassifierWidget.
+ *
+ * @param classifierWidget The ClassifierWidget to use.
+ * @param linePathSegmentIndex The index of the segment where the
+ * association class is created.
+ */
+ void createAssocClassLine(ClassifierWidget* classifierWidget,
+ int linePathSegmentIndex);
+
+ /**
+ * Renders the association class connecting line selected.
+ */
+ void selectAssocClassLine(bool sel = true);
+
+ /**
+ * Moves all the mid points (all expcept start /end ) by the given amount.
+ */
+ void moveMidPointsBy( int x, int y );
+
+ /**
+ * Moves the entire association by the given offset.
+ */
+ void moveEntireAssoc( int x, int y );
+
+ /**
+ * Returns the bounding rectangle of all segments of the association.
+ */
+ QRect getAssocLineRectangle();
+
+ /**
+ * Return the first font found being used by any child widget. (They
+ * could be different fonts, so this is a slightly misleading method.)
+ */
+ QFont getFont () const;
+
+ /**
+ * Overrides the method from WidgetBase.
+ */
+ void setLineColor(const QColor &colour);
+
+ /**
+ * Overrides the method from WidgetBase.
+ */
+ void setLineWidth(uint width);
+
+ /**
+ * Set all 'owned' child widgets to this font.
+ */
+ void lwSetFont (QFont font);
+
+ /**
+ * Return the given role's changeability FloatingTextWidget widget.
+ */
+ FloatingTextWidget* getChangeWidget(Uml::Role_Type role);
+
+ /**
+ * Sets the text to the FloatingTextWidget that display the Role text of this
+ * association.
+ * For this function to work properly, the associated widget
+ * should already be set.
+ */
+ void setRoleName(const QString &strRole, Uml::Role_Type role);
+
+ /**
+ * Set the documentation on the given role.
+ */
+ void setRoleDoc(const QString &doc, Uml::Role_Type role);
+
+ /**
+ * Overrides operation from LinkWidget.
+ * Required by FloatingTextWidget.
+ * @todo Move to LinkWidget.
+ */
+ UMLClassifier *getOperationOwner();
+
+ /**
+ * Implements operation from LinkWidget.
+ * Motivated by FloatingTextWidget.
+ */
+ UMLOperation *getOperation();
+
+ /**
+ * Implements operation from LinkWidget.
+ * Motivated by FloatingTextWidget.
+ */
+ void setOperation(UMLOperation *op);
+
+ /**
+ * Overrides operation from LinkWidget.
+ * Required by FloatingTextWidget.
+ */
+ QString getCustomOpText();
+
+ /**
+ * Overrides operation from LinkWidget.
+ * Required by FloatingTextWidget.
+ */
+ void setCustomOpText(const QString &opText);
+
+ /**
+ * Overrides operation from LinkWidget.
+ * Required by FloatingTextWidget.
+ *
+ * @param ft The text widget which to update.
+ */
+ void setMessageText(FloatingTextWidget *ft);
+
+ /**
+ * Returns the UMLAssociation representation of this object.
+ *
+ * @return Pointer to the UMLAssociation that is represented by
+ * this AsociationWidget.
+ */
+ UMLAssociation * getAssociation() const;
+
+ /**
+ * Returns the UMLAttribute representation of this object.
+ *
+ * @return Pointer to the UMLAttribute that is represented by
+ * this AsociationWidget.
+ */
+ UMLAttribute * getAttribute() const;
+
+ /**
+ * Sets the text of the given FloatingTextWidget.
+ * Overrides operation from LinkWidget.
+ * Required by FloatingTextWidget.
+ */
+ void setText(FloatingTextWidget *ft, const QString &text);
+
+ /**
+ * Calls @ref setTextPosition() on all the labels.
+ * Overrides operation from LinkWidget.
+ */
+ void resetTextPositions();
+
+ /**
+ * Constrains the FloatingTextWidget X and Y values supplied.
+ * Implements the abstract operation from LinkWidget.
+ *
+ * @param textX Candidate X value (may be modified by the constraint.)
+ * @param textY Candidate Y value (may be modified by the constraint.)
+ * @param textWidth Width of the text.
+ * @param textHeight Height of the text.
+ * @param tr Uml::Text_Role of the text.
+ */
+ void constrainTextPos(int &textX, int &textY, int textWidth, int textHeight,
+ Uml::Text_Role tr);
+
+ /**
+ * Shows the association properties dialog and updates the
+ * corresponding texts if its execution is successful.
+ * Returns true for success.
+ */
+ bool showDialog();
+
+ /**
+ * Sets the Association line index for the given role.
+ */
+ void setIndex(int index, Uml::Role_Type role);
+
+ /**
+ * Returns the Association line index for the given role.
+ */
+ int getIndex(Uml::Role_Type role) const;
+
+ /**
+ * Sets the total count on the Association region.
+ */
+ void setTotalCount(int count, Uml::Role_Type role);
+
+ /**
+ * Returns the total count on the Association region.
+ */
+ int getTotalCount(Uml::Role_Type role) const;
+
+ /**
+ * Sets the total count on the Association region for widgetB.
+ */
+ void setTotalCount(int count);
+
+ /**
+ * Overrides operation from LinkWidget.
+ * Required by FloatingTextWidget.
+ *
+ * @param seqNum The new sequence number string to set.
+ * @param op The new operation string to set.
+ */
+ void setSeqNumAndOp(const QString &seqNum, const QString &op);
+
+ /**
+ * Overrides operation from LinkWidget.
+ * Required by FloatingTextWidget.
+ *
+ * @param seqNum Return this AssociationWidget's sequence number string.
+ * @param op Return this AssociationWidget's operation string.
+ */
+ UMLClassifier * getSeqNumAndOp(QString& seqNum, QString& op);
+
+ /**
+ * Calculates and sets the first and last point in the association's
+ * LinePath.
+ * Each point is a middle point of its respective UMLWidget's bounding
+ * rectangle.
+ * This method picks which sides to use for the association.
+ */
+ void calculateEndingPoints();
+
+ /**
+ * Remove dashed connecting line for association class.
+ */
+ void removeAssocClassLine();
+
+ /**
+ * Compute the end points of m_pAssocClassLine in case this
+ * association has an attached association class.
+ */
+ void computeAssocClassLine();
+
+ /**
+ * Overriding the method from WidgetBase because we need to do
+ * something extra in case this AssociationWidget represents
+ * an attribute of a classifier.
+ */
+ void setUMLObject(UMLObject *obj);
+
+ /**
+ * Saves this widget to the "assocwidget" XMI element.
+ */
+ void saveToXMI( QDomDocument & qDoc, QDomElement & qElement );
+
+ /**
+ * Loads this widget from the "assocwidget" XMI element.
+ */
+ bool loadFromXMI( QDomElement & qElement );
+
+ /**
+ * Same as above, but uses the supplied widgetList for resolving
+ * the role A and role B widgets. (The other loadFromXMI() queries
+ * the UMLView for these widgets.)
+ * Required for clipboard operations.
+ */
+ bool loadFromXMI( QDomElement & qElement, const UMLWidgetList& widgets,
+ const MessageWidgetList* pMessages = NULL);
+
+ /**
+ * Cleans up all the association's data in the related widgets.
+ */
+ void cleanup();
+
+private:
+
+ /** set our internal umlAssociation */
+ void setUMLAssociation (UMLAssociation * assoc);
+
+ /**
+ * Merges/syncs the association widget data into UML object
+ * representation.
+ * CHECK: Can we get rid of this.
+ */
+ void mergeAssociationDataIntoUMLRepresentation();
+
+ /**
+ * Finds out which region contains the point (PosX, PosY).
+ *
+ * The diagram is divided into four regions by its diagonals :
+ *
+ * Region 2
+ * \ /
+ * \ /
+ * +--------+
+ * | \ / |
+ * Region 1 | >< | Region 3
+ * | / \ |
+ * +--------+
+ * / \
+ * / \
+ * Region 4
+ *
+ *
+ * @param Rect The bounding rectangle to investigate.
+ * @param PosX X coordinate of the point to seek.
+ * @param PosY Y coordinate of the point to seek.
+ * @return The region number of the region containing the point.
+ * 1 = Region 1
+ * 2 = Region 2
+ * 3 = Region 3
+ * 4 = Region 4
+ * 5 = On diagonal 2 between Region 1 and 2
+ * 6 = On diagonal 1 between Region 2 and 3
+ * 7 = On diagonal 2 between Region 3 and 4
+ * 8 = On diagonal 1 between Region4 and 1
+ * 9 = On diagonal 1 and On diagonal 2 (the center)
+ */
+ static Region findPointRegion(const QRect& Rect, int PosX, int PosY);
+
+ /**
+ * Given a rectangle and a point, findInterceptOnEdge computes the
+ * connecting line between the middle point of the rectangle and
+ * the point, and returns the intercept of this line with the
+ * the edge of the rectangle identified by `region'.
+ * When the region is North or South, the X value is returned (Y is
+ * constant.)
+ * When the region is East or West, the Y value is returned (X is
+ * constant.)
+ * @todo This is buggy. Try replacing by findIntercept()
+ */
+ static int findInterceptOnEdge(const QRect &rect, Region region, const QPoint &point);
+
+ static QPoint findIntercept(const QRect &rect, const QPoint &point);
+
+ /**
+ * Overrides moveEvent.
+ */
+ void moveEvent(QMoveEvent *me);
+
+ /**
+ * This function calculates which role should be set for the m_pName
+ * FloatingTextWidget.
+ */
+ Uml::Text_Role CalculateNameType(Uml::Text_Role defaultRoleType);
+
+ /**
+ * Returns true if point (PosX, PosY) is close enough to any of the
+ * association's segments.
+ */
+ bool isPointInsideBoundaries(int PosX, int PosY, QPoint & SPoint,
+ uint & StartSegmentIndex, uint & EndSegmentIndex);
+
+ /**
+ * Returns a point with interchanged X and Y coordinates.
+ */
+ static QPoint swapXY(const QPoint &p);
+
+ /**
+ * Returns the total length of the association's LinePath:
+ * result = segment_1_length + segment_2_length + ... + segment_n_length
+ */
+ float totalLength();
+
+ /**
+ * Calculates which point of segment P1P2 has a distance equal to
+ * Distance from P1.
+ * Let's say such point is PX, the distance from P1 to PX must be equal
+ * to Distance and if PX is not a point of the segment P1P2 then the
+ * function returns (-1,-1).
+ */
+ static QPoint calculatePointAtDistance(const QPoint &P1, const QPoint &P2, float Distance);
+
+ /**
+ * Calculates which point of a perpendicular line to segment P1P2 that
+ * contains P2 has a distance equal to Distance from P2.
+ * Let's say such point is PX, the distance from P2 to PX must be equal
+ * to Distance.
+ */
+ static QPoint calculatePointAtDistanceOnPerpendicular(const QPoint &P1, const QPoint &P2, float Distance);
+
+ /**
+ * Calculates the intersection between line P1P2 and a perpendicular
+ * line containing P3, the result is returned in ResultingPoint.
+ * The result value represents the distance between ResultingPoint and
+ * P3. If this value is negative an error ocurred.
+ * This method is not currently used.
+ */
+ static float perpendicularProjection(const QPoint& P1, const QPoint& P2, const QPoint& P3, QPoint& ResultingPoint);
+
+ /**
+ * Return the mid point between p0 and p1
+ */
+ static QPoint midPoint(const QPoint& p0, const QPoint& p1);
+
+ /**
+ * Calculates the position of the text widget depending on the role
+ * that widget is playing.
+ * Returns the point at which to put the widget.
+ */
+ QPoint calculateTextPosition(Uml::Text_Role role);
+
+ /**
+ * Puts the text widget with the given role at the given position.
+ * This method calls @ref calculateTextPostion to get the needed position.
+ * I.e. the line segment it is on has moved and it should move the same
+ * amount as the line.
+ */
+ void setTextPosition(Uml::Text_Role role);
+
+ /**
+ * Moves the text widget with the given role by the difference between
+ * the two points.
+ */
+ void setTextPositionRelatively(Uml::Text_Role role, const QPoint &oldPosition);
+
+ /**
+ * Returns the Region the widget to line intersection is for the given
+ * widget in this Association. If the given widget is not in the
+ * Association then Region::Error is returned.
+ * Used by @ref calculateEndingPoints to work these positions out for
+ * another Association - since the number of Associations on the same
+ * region for the same widget will mean the lines will need to be
+ * spread out across the region.
+ */
+ Region getWidgetRegion(AssociationWidget * widget) const;
+
+ /**
+ * This is a pointer to the Floating Text widget which displays the
+ * name of this association.
+ */
+ FloatingTextWidget* m_pName;
+
+ /**
+ * The WidgetRole struct gathers all information pertaining to the role.
+ * The AssociationWidget class contains two WidgetRole objects, one for each
+ * side of the association (A and B).
+ */
+ struct WidgetRole {
+
+ /**
+ * This is a pointer to the Floating Text widget at the role's side
+ * of the association.
+ * This FloatingTextWidget displays the information regarding multiplicity.
+ */
+ FloatingTextWidget* m_pMulti;
+
+ /**
+ * This is a pointer to the Floating Text widget at the role's side
+ * of the association.
+ * This FloatingTextWidget displays the information regarding changeability.
+ */
+ FloatingTextWidget* m_pChangeWidget;
+
+ /**
+ * This member holds a pointer to the floating text that displays
+ * the role's label of this association.
+ */
+ FloatingTextWidget* m_pRole;
+
+ /**
+ * This member holds a pointer to the UMLWidget at this role's side
+ * of the association.
+ */
+ UMLWidget* m_pWidget;
+
+ /**
+ * This role's old top left corner before moving.
+ */
+ QPoint m_OldCorner;
+
+ /**
+ * The region of this role's widget.
+ */
+ Region m_WidgetRegion;
+
+ /**
+ * The index of where the line is on the region for this role.
+ */
+ int m_nIndex;
+
+ /**
+ * The total amount of associations on the region this role's line is on.
+ */
+ int m_nTotalCount;
+
+ // The following items are only used if m_pObject is not set.
+ Uml::Visibility m_Visibility;
+ Uml::Changeability_Type m_Changeability;
+ QString m_RoleDoc;
+
+ } m_role[2];
+
+ /**
+ * Change, create, or delete the FloatingTextWidget indicated by the given Text_Role.
+ *
+ * @param tr Text_Role of the FloatingTextWidget to change or create.
+ * @param text Text string that controls the action:
+ * If empty and ft is NULL then setFloatingText() is a no-op.
+ * If empty and ft is non-NULL then the existing ft is deleted.
+ * If non-empty and ft is NULL then a new FloatingTextWidget is created
+ * and returned in ft with the text set.
+ * If non-empty and ft is non-NULL then the existing ft text is modified.
+ * @param ft Reference to the pointer to FloatingTextWidget to change or create.
+ * On creation/deletion, the pointer value will be changed.
+ */
+ void setFloatingText(Uml::Text_Role tr, const QString &text, FloatingTextWidget* &ft);
+
+ /**
+ * Called to tell the association that another association has added
+ * a line to the region of one of its widgets. The widget is identified
+ * by its role (A or B).
+ *
+ * Called by @ref updateAssociations which is called by
+ * @ref calculateEndingPoints when required.
+ */
+ void updateRegionLineCount(int index, int totalCount,
+ AssociationWidget::Region region, Uml::Role_Type role);
+
+ /**
+ * Tells all the other view associations the new count for the
+ * given widget on a certain region. And also what index they should be.
+ */
+ void updateAssociations(int totalCount, Region region, Uml::Role_Type role);
+
+ /**
+ * Returns the number of lines there are on the given region for
+ * either widget A or B of the association.
+ */
+ int getRegionCount(Region region, Uml::Role_Type role);
+
+ /**
+ * Initialize attributes of this class at construction time.
+ */
+ void init (UMLView *view);
+
+ /**
+ * Auxiliary method for calculateEndingPoints().
+ */
+ void doUpdates(int otherX, int otherY, Uml::Role_Type role);
+
+ /**
+ * For internal purposes only.
+ * Other classes/users should use setChangeability() instead.
+ */
+ void setChangeWidget(const QString &strChangeWidget, Uml::Role_Type role);
+
+ /**
+ * Checks to see if the given point is one of the points of the line.
+ * If so will try and get the view to flag the point for moving.
+ * This is only valid if no other point id being moved and only
+ * while the left mouse button is down.
+ */
+ void checkPoints(const QPoint &p);
+
+ /**
+ * Returns true if the line path starts at the given widget.
+ */
+ bool linePathStartsAt(const UMLWidget* widget);
+
+ /**
+ * Auxiliary method for updateAssociations():
+ * Put position into m_positions and assoc into m_ordered at the
+ * correct index.
+ * m_positions and m_ordered move in parallel and are sorted by
+ * ascending position.
+ */
+ void insertIntoLists(int position, const AssociationWidget* assoc);
+
+ int m_positions[100]; ///< auxiliary variable for updateAssociations()
+ int m_positions_len; ///< auxiliary variable for updateAssociations()
+ AssociationWidgetList m_ordered; ///< auxiliary variable for updateAssociations()
+
+ /**
+ * Flag which is true if the activate method has been called for this
+ * class instance.
+ */
+ bool m_bActivated;
+
+ /**
+ * When the association has a Role Floating Text this text should move
+ * when the LinePath moves but only if the closest segment to the
+ * role text moves.
+ * This segment is:
+ * m_LinePath[m_unNameLineSegment] -- m_LinePath[m_unNameLineSegment+1]
+ */
+ uint m_unNameLineSegment;
+ UMLDoc * m_umldoc; ///< just a shorthand for UMLApp::app()->getDocument()
+ ListPopupMenu *m_pMenu;
+ bool m_bSelected;
+ int m_nMovingPoint;
+
+ /**
+ * Position of Name floatingtext saved by saveIdealTextPositions()
+ */
+ QPoint m_oldNamePoint;
+ /**
+ * Position of role A multiplicity floatingtext saved by
+ * saveIdealTextPositions()
+ */
+ QPoint m_oldMultiAPoint;
+ /**
+ * Position of role B multiplicity floatingtext saved by
+ * saveIdealTextPositions()
+ */
+ QPoint m_oldMultiBPoint;
+ /**
+ * Position of role A changeability floatingtext saved by
+ * saveIdealTextPositions()
+ */
+ QPoint m_oldChangeAPoint;
+ /**
+ * Position of role B changeability floatingtext saved by
+ * saveIdealTextPositions()
+ */
+ QPoint m_oldChangeBPoint;
+ /**
+ * Position of role A name floatingtext saved by
+ * saveIdealTextPositions()
+ */
+ QPoint m_oldRoleAPoint;
+ /**
+ * Position of role B name floatingtext saved by
+ * saveIdealTextPositions()
+ */
+ QPoint m_oldRoleBPoint;
+
+ int m_nLinePathSegmentIndex; ///< anchor for m_pAssocClassLine
+ QCanvasLine *m_pAssocClassLine; ///< used for connecting assoc. class
+ /// selection adornment for the endpoints of the assoc. class connecting line
+ QCanvasRectangle *m_pAssocClassLineSel0, *m_pAssocClassLineSel1;
+
+ ClassifierWidget *m_pAssocClassWidget; ///< used if we have an assoc. class
+
+ /**
+ * The definition points for the association line.
+ */
+ LinePath m_LinePath;
+
+ // The following items are only used if m_pObject is not set.
+ Uml::Association_Type m_AssocType;
+
+public slots:
+ /**
+ * Handles the selection from the popup menu.
+ */
+ void slotMenuSelection(int sel);
+
+ /**
+ * This slot is entered when an event has occurred on the views display,
+ * most likely a mouse event. Before it sends out that mouse event all
+ * children should make sure that they don't have a menu active or there
+ * could be more than one popup menu displayed.
+ */
+ void slotRemovePopupMenu();
+
+ /**
+ * Handles any signals that tells everyone not to be selected.
+ */
+ void slotClearAllSelected();
+
+ /**
+ * Connected to UMLClassifier::attributeRemoved() in case this
+ * AssociationWidget is linked to a classifer's attribute type.
+ *
+ * @param obj The UMLAttribute removed.
+ */
+ void slotAttributeRemoved(UMLClassifierListItem* obj);
+
+ /**
+ * Connected to UMLObject::modified() in case this
+ * AssociationWidget is linked to a classifer's attribute type.
+ *
+ * @param obj The UMLAttribute removed.
+ */
+ void slotAttributeChanged();
+
+ /**
+ * Synchronize this widget from the UMLAssociation.
+ */
+ void syncToModel();
+};
+#endif
diff --git a/umbrello/umbrello/associationwidgetlist.h b/umbrello/umbrello/associationwidgetlist.h
new file mode 100644
index 00000000..28271b74
--- /dev/null
+++ b/umbrello/umbrello/associationwidgetlist.h
@@ -0,0 +1,29 @@
+/***************************************************************************
+ associationwidgetlist.h - description
+ -------------------
+ copyright : (C) 2003 by Oliver Kellogg
+ email : okellogg@users.sourceforge.net
+ Bugs and comments to uml-devel@lists.sf.net or http://bugs.kde.org
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the 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 _ASSOCIATIONWIDGETLIST_H
+#define _ASSOCIATIONWIDGETLIST_H
+
+#include <qptrlist.h>
+
+// forward declarations
+class AssociationWidget;
+
+typedef QPtrList<AssociationWidget> AssociationWidgetList;
+typedef QPtrListIterator<AssociationWidget> AssociationWidgetListIt;
+
+#endif
diff --git a/umbrello/umbrello/assocrules.cpp b/umbrello/umbrello/assocrules.cpp
new file mode 100644
index 00000000..9e8c9a52
--- /dev/null
+++ b/umbrello/umbrello/assocrules.cpp
@@ -0,0 +1,386 @@
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * copyright (C) 2002-2007 *
+ * Umbrello UML Modeller Authors <uml-devel@uml.sf.net> *
+ ***************************************************************************/
+
+// own header
+#include "assocrules.h"
+
+// qt/kde includes
+#include <kdebug.h>
+#include <typeinfo>
+
+// local includes
+#include "uml.h"
+#include "umlview.h"
+#include "umlwidget.h"
+#include "umlobject.h"
+#include "associationwidgetlist.h"
+#include "associationwidget.h"
+#include "statewidget.h"
+#include "activitywidget.h"
+#include "forkjoinwidget.h"
+
+
+using namespace Uml;
+
+AssocRules::AssocRules() {}
+
+AssocRules::~AssocRules() {}
+
+bool allowAssociation( Association_Type/* assocType*/, const std::type_info/* &type*/ )
+{
+ return false;
+
+}
+
+bool AssocRules::allowAssociation( Uml::Association_Type assocType, UMLWidget * widget ) {
+ Widget_Type widgetType = widget -> getBaseType();
+ bool bValid = false;
+ for (int i = 0; i < m_nNumRules; i++) {
+ if (assocType == m_AssocRules[i].assoc_type) {
+ if (widgetType == m_AssocRules[i].widgetA_type
+ || widgetType == m_AssocRules[i].widgetB_type ) {
+ bValid = true;
+ }
+ }
+ }
+ if( !bValid ) {
+ // Special case: Subsystem realizes interface in component diagram
+ UMLView *view = UMLApp::app()->getCurrentView();
+ if (view && view->getType() == dt_Component && widgetType == wt_Package &&
+ (assocType == at_Generalization || assocType == at_Realization))
+ bValid = true;
+ else
+ return false;
+ }
+ AssociationWidgetList list = widget -> getAssocList();
+ AssociationWidgetListIt it( list );
+ AssociationWidget * assoc = 0;
+ switch( assocType ) {
+ case at_Association:
+ case at_UniAssociation:
+ case at_Dependency:
+ case at_Coll_Message:
+ case at_Generalization://can have many sub/super types
+ case at_Aggregation:
+ case at_Relationship:
+ case at_Composition:
+ case at_Containment:
+ return true;//doesn't matter whats already connected to widget
+ break;
+
+ case at_Association_Self:
+ return true;// we should really check that connection is to same object
+ break;
+
+ case at_Realization: // one connected to widget only (a or b)
+ while( ( assoc = it.current() ) ) {
+ if( assoc -> getAssocType() == at_Realization )
+ return false;
+ ++it;
+ }
+ return true;
+ break;
+
+ case at_State:
+ {
+ StateWidget *pState = dynamic_cast<StateWidget*>(widget);
+ return (pState == NULL || pState->getStateType() != StateWidget::End);
+ }
+ break;
+
+ case at_Activity:
+ {
+ ActivityWidget *pActivity = dynamic_cast<ActivityWidget*>(widget);
+ return (pActivity == NULL || pActivity->getActivityType() != ActivityWidget::End);
+ }
+ break;
+
+ case at_Anchor:
+ return true;
+ break;
+ default:
+ kWarning() << "allowAssociation() on unknown type" << endl;
+ break;
+ }
+ return false;
+}
+
+// when we know what we are going to connect both ends of the association to, we can
+// use this method.
+bool AssocRules::allowAssociation( Uml::Association_Type assocType,
+ UMLWidget * widgetA, UMLWidget * widgetB,
+ bool extendedCheck ) {
+ Widget_Type widgetTypeA = widgetA->getBaseType();
+ Widget_Type widgetTypeB = widgetB->getBaseType();
+ bool bValid = false;
+ for (int i = 0; i < m_nNumRules; i++) {
+ if (assocType == m_AssocRules[i].assoc_type) {
+ if( (widgetTypeA == m_AssocRules[i].widgetA_type &&
+ widgetTypeB == m_AssocRules[i].widgetB_type) ||
+ (widgetTypeB == m_AssocRules[i].widgetA_type &&
+ widgetTypeA == m_AssocRules[i].widgetB_type ) )
+ bValid = true;
+ }
+ }
+ // we can bail here for quick checks, as occur in loading files
+ // for paste or regular creation operations, we need to go further
+ if (!extendedCheck) {
+ return bValid;
+ }
+
+ if (!bValid) {
+ return false;
+ }
+ AssociationWidgetList list = widgetB -> getAssocList();
+ AssociationWidgetListIt it( list );
+ AssociationWidget * assoc = 0;
+ switch( assocType ) {
+ case at_Association:
+ case at_Association_Self:
+ case at_UniAssociation:
+ case at_Dependency:
+ case at_Coll_Message:
+ case at_Aggregation:
+ case at_Relationship:
+ return true; // doesn't matter what's already connected to widget
+ break;
+
+ case at_Composition: // can't have mutual composition
+ case at_Containment: // can't have mutual containment
+ case at_Generalization://can have many sub/super types but can't sup/sub each
+ while( ( assoc = it.current() ) ) {
+ if( ( widgetA == assoc -> getWidget(A) || widgetA == assoc -> getWidget(B) )
+ && assoc->getAssocType() == assocType )
+ return false;
+ ++it;
+ }
+ return true;
+ break;
+
+ case at_Realization: // can only connect to abstract (interface) classes
+ while( ( assoc = it.current() ) ) {
+ if( ( widgetA == assoc->getWidget(A) || widgetA == assoc->getWidget(B) )
+ && assoc->getAssocType() == at_Realization ) {
+ return false;
+ }
+ ++it;
+ }
+ if (widgetB->getBaseType() == wt_Class) {
+ return widgetB->getUMLObject()->getAbstract();
+ } else if (widgetB->getBaseType() == wt_Interface ||
+ widgetB->getBaseType() == wt_Package) {
+ return true;
+ }
+ break;
+
+ case at_State:
+ {
+ StateWidget *stateA = dynamic_cast<StateWidget*>(widgetA);
+ StateWidget *stateB = dynamic_cast<StateWidget*>(widgetB);
+ if (stateA && stateB) {
+ if (stateB->getStateType() == StateWidget::Initial)
+ return false;
+ if (stateB->getStateType() == StateWidget::End &&
+ stateA->getStateType() != StateWidget::Normal)
+ return false;
+ }
+ }
+ return true;
+ break;
+
+ case at_Activity:
+ {
+ ActivityWidget *actA = dynamic_cast<ActivityWidget*>(widgetA);
+ ActivityWidget *actB = dynamic_cast<ActivityWidget*>(widgetB);
+ // no transitions to initial activity allowed
+ if (actB && actB->getActivityType() == ActivityWidget::Initial)
+ return false;
+ // actType -1 here means "not applicable".
+ int actTypeA = -1;
+ if (actA)
+ actTypeA = actA->getActivityType();
+ int actTypeB = -1;
+ if (actB)
+ actTypeB = actB->getActivityType();
+ // only from a normal, branch or fork activity to the end
+ if (actTypeB == ActivityWidget::End &&
+ actTypeA != ActivityWidget::Normal &&
+ actTypeA != ActivityWidget::Branch &&
+ dynamic_cast<ForkJoinWidget*>(widgetA) == NULL) {
+ return false;
+ }
+ // only Forks and Branches can have more than one "outgoing" transition
+ if (actA != NULL && actTypeA != ActivityWidget::Branch) {
+ AssociationWidgetList list = widgetA->getAssocList();
+ for (AssociationWidget* assoc = list.first(); assoc; assoc = list.next()) {
+ if (assoc->getWidget(A) == widgetA) {
+ return false;
+ }
+ }
+ }
+ }
+ return true;
+ break;
+
+ case at_Anchor:
+ return true;
+ break;
+
+ default:
+ kWarning() << "allowAssociation() on unknown type" << endl;
+ break;
+ }
+ return false;
+}
+
+bool AssocRules::allowRole( Uml::Association_Type assocType ) {
+ for( int i = 0; i < m_nNumRules; i++ )
+ if( assocType == m_AssocRules[ i ].assoc_type )
+ return m_AssocRules[ i ].role;
+ return false;
+}
+
+bool AssocRules::allowMultiplicity( Uml::Association_Type assocType, Uml::Widget_Type widgetType ) {
+ for( int i = 0; i < m_nNumRules; i++ )
+ if( assocType == m_AssocRules[ i ].assoc_type )
+ if( widgetType == m_AssocRules[ i ].widgetA_type || widgetType == m_AssocRules[ i ].widgetB_type )
+ return m_AssocRules[ i ].multiplicity;
+ return false;
+}
+
+bool AssocRules::allowSelf( Uml::Association_Type assocType, Uml::Widget_Type widgetType ) {
+ for( int i = 0; i < m_nNumRules; i++ )
+ if( assocType == m_AssocRules[ i ].assoc_type )
+ if( widgetType == m_AssocRules[ i ].widgetA_type || widgetType == m_AssocRules[ i ].widgetB_type )
+ return m_AssocRules[ i ].self;
+
+ return false;
+}
+
+Uml::Association_Type AssocRules::isGeneralisationOrRealisation(UMLWidget* widgetA, UMLWidget* widgetB) {
+ Widget_Type widgetTypeA = widgetA->getBaseType();
+ Widget_Type widgetTypeB = widgetB->getBaseType();
+ for (int i = 0; i < m_nNumRules; i++) {
+ if (m_AssocRules[i].assoc_type == at_Realization &&
+ widgetTypeA == m_AssocRules[i].widgetA_type &&
+ widgetTypeB == m_AssocRules[i].widgetB_type) {
+ return at_Realization;
+ }
+ }
+ return at_Generalization;
+}
+
+AssocRules::Assoc_Rule AssocRules::m_AssocRules []= {
+ // Association widgetA widgetB role multi directional self
+ //---------------+----------------+----------------+-------+-------+-------+---------
+ { at_Association_Self,wt_Class, wt_Class, true, true, true, true },
+ { at_Association_Self,wt_Object, wt_Object, true, true, true, true },
+ { at_Association_Self,wt_Interface, wt_Interface, true, true, true, true },
+ { at_Association, wt_Class, wt_Class, true, true, true, true },
+ { at_Association, wt_Object, wt_Object, true, true, true, true },
+ { at_Association, wt_Interface, wt_Interface, true, true, true, true },
+ { at_Association, wt_Interface, wt_Class, true, true, true, false },
+ { at_Association, wt_Class, wt_Interface, true, true, true, false },
+ { at_Association, wt_Datatype, wt_Class, true, true, true, false },
+ { at_Association, wt_Class, wt_Datatype, true, true, true, false },
+ { at_Association, wt_Enum, wt_Class, true, true, true, false },
+ { at_Association, wt_Class, wt_Enum, true, true, true, false },
+ { at_Association, wt_Actor, wt_UseCase, true, false, false, false },
+ { at_Association, wt_UseCase, wt_UseCase, true, false, false, false },
+ { at_Association, wt_Actor, wt_Actor, true, false, false, false },
+ { at_Association, wt_Actor, wt_UseCase, true, false, false, false },
+ { at_Association, wt_Component, wt_Interface, true, false, false, false },
+ { at_Association, wt_Interface, wt_Artifact, true, false, false, false },
+ { at_Association, wt_Node, wt_Node, true, false, false, false },
+ { at_UniAssociation,wt_Class, wt_Class, true, true, true, true },
+ { at_UniAssociation,wt_Object, wt_Object, true, true, true, true },
+ { at_UniAssociation,wt_Interface, wt_Interface, true, true, true, true },
+ { at_UniAssociation,wt_Interface, wt_Class, true, true, true, true },
+ { at_UniAssociation,wt_Class, wt_Interface, true, true, true, true },
+ { at_UniAssociation,wt_Class, wt_Datatype, true, true, true, true },
+ { at_UniAssociation,wt_Class, wt_Enum, true, true, true, true },
+ { at_UniAssociation,wt_Actor, wt_Actor, true, false, false, false },
+ { at_UniAssociation,wt_UseCase, wt_UseCase, true, false, false, false },
+ { at_UniAssociation,wt_UseCase, wt_Actor, true, false, false, false },
+ { at_Generalization,wt_Class, wt_Datatype, false, false, false, false },
+ { at_Generalization,wt_Class, wt_Class, false, false, false, false },
+ { at_Generalization,wt_Interface, wt_Interface, false, false, false, false },
+ { at_Generalization,wt_UseCase, wt_UseCase, false, false, false, false },
+ { at_Generalization,wt_Actor, wt_Actor, false, false, false, false },
+ { at_Generalization,wt_Component, wt_Interface, false, false, false, false },
+ { at_Aggregation, wt_Class, wt_Class, true, true, false, true },
+ { at_Aggregation, wt_Class, wt_Interface, true, true, false, false },
+ { at_Aggregation, wt_Class, wt_Enum, true, true, false, false },
+ { at_Aggregation, wt_Class, wt_Datatype, true, true, false, false },
+ { at_Dependency, wt_Class, wt_Class, true, false, false, true },
+ { at_Dependency, wt_UseCase, wt_UseCase, true, false, false, false },
+ { at_Dependency, wt_Actor, wt_Actor, true, false, false, false },
+ { at_Dependency, wt_Actor, wt_UseCase, true, false, false, false },
+ { at_Dependency, wt_Package, wt_Package, true, true, true, true },
+ { at_Dependency, wt_Package, wt_Class, true, true, true, true },
+ { at_Dependency, wt_Class, wt_Package, true, true, true, true },
+ { at_Dependency, wt_Package, wt_Interface, true, true, true, true },
+ { at_Dependency, wt_Interface, wt_Package, true, true, true, true },
+ { at_Dependency, wt_Interface, wt_Interface, true, true, true, true },
+ { at_Dependency, wt_Interface, wt_Class, true, true, true, true },
+ { at_Dependency, wt_Class, wt_Interface, true, true, true, true },
+ { at_Dependency, wt_Class, wt_Datatype, true, true, true, true },
+ { at_Dependency, wt_Class, wt_Enum, true, true, true, true },
+ { at_Dependency, wt_Component, wt_Component, true, true, true, true },
+ { at_Dependency, wt_Component, wt_Interface, true, true, true, true },
+ { at_Dependency, wt_Component, wt_Artifact, true, false, false, false },
+ { at_Dependency, wt_Node, wt_Component, true, false, false, false },
+ { at_Realization, wt_Class, wt_Interface, false, false, false, false },
+ { at_Realization, wt_Interface, wt_Package, false, false, false, false },
+ { at_Realization, wt_Interface, wt_Interface, false, false, false, false },
+ { at_Realization, wt_Component, wt_Interface, false, false, false, false },
+ { at_Realization, wt_Package, wt_Interface, false, false, false, false },
+ { at_Composition, wt_Class, wt_Class, true, true, false, true },
+ { at_Composition, wt_Class, wt_Interface, true, true, false, false },
+ { at_Composition, wt_Class, wt_Enum, true, true, false, false },
+ { at_Composition, wt_Class, wt_Datatype, false, false, false, false },
+ { at_Composition, wt_Class, wt_Class, false, false, false, false },
+ { at_Containment, wt_Package, wt_Class, false, false, true, false },
+ { at_Containment, wt_Package, wt_Interface, false, false, true, false },
+ { at_Containment, wt_Package, wt_Enum, false, false, true, false },
+ { at_Containment, wt_Package, wt_Package, false, false, true, false },
+ { at_Containment, wt_Package, wt_Component, false, false, true, false },
+ { at_Containment, wt_Class, wt_Class, false, false, true, false },
+ { at_Containment, wt_Class, wt_Interface, false, false, true, false },
+ { at_Containment, wt_Class, wt_Enum, false, false, true, false },
+ { at_Containment, wt_Interface, wt_Class, false, false, true, false },
+ { at_Containment, wt_Interface, wt_Interface, false, false, true, false },
+ { at_Containment, wt_Interface, wt_Enum, false, false, true, false },
+ { at_Containment, wt_Component, wt_Component, false, false, true, false },
+ { at_Containment, wt_Component, wt_Artifact, false, false, true, false },
+ { at_Coll_Message, wt_Object, wt_Object, true, false, true, true },
+ { at_State, wt_State, wt_State, true, false, true, true },
+ { at_State, wt_ForkJoin, wt_State, true, false, true, true },
+ { at_State, wt_State, wt_ForkJoin, true, false, true, true },
+ { at_Activity, wt_Activity, wt_Activity, true, false, true, true },
+ { at_Activity, wt_ForkJoin, wt_Activity, true, false, true, true },
+ { at_Activity, wt_Activity, wt_ForkJoin, true, false, true, true },
+ { at_Anchor, wt_Class, wt_Note, false, false, false, false },
+ { at_Anchor, wt_Package, wt_Note, false, false, false, false },
+ { at_Anchor, wt_Interface, wt_Note, false, false, false, false },
+ { at_Anchor, wt_Datatype, wt_Note, false, false, false, false },
+ { at_Anchor, wt_Enum, wt_Note, false, false, false, false },
+ { at_Anchor, wt_Object, wt_Note, false, false, false, false },
+ { at_Anchor, wt_Actor, wt_Note, false, false, false, false },
+ { at_Anchor, wt_UseCase, wt_Note, false, false, false, false },
+ { at_Anchor, wt_Message, wt_Note, false, false, false, false },
+ { at_Anchor, wt_State, wt_Note, false, false, false, false },
+ { at_Anchor, wt_Activity, wt_Note, false, false, false, false },
+ { at_Relationship, wt_Entity, wt_Entity, true, true, true, true },
+};
+
+int AssocRules::m_nNumRules = sizeof( m_AssocRules ) / sizeof( AssocRules::Assoc_Rule );
+
diff --git a/umbrello/umbrello/assocrules.h b/umbrello/umbrello/assocrules.h
new file mode 100644
index 00000000..df33d6d8
--- /dev/null
+++ b/umbrello/umbrello/assocrules.h
@@ -0,0 +1,106 @@
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * copyright (C) 2002-2006 *
+ * Umbrello UML Modeller Authors <uml-devel@uml.sf.net> *
+ ***************************************************************************/
+
+#ifndef ASSOCRULES_H
+#define ASSOCRULES_H
+
+#include "umlnamespace.h"
+namespace std
+ { class type_info; }
+
+class UMLWidget;
+
+/**
+ * Used to determine rules for associations.
+ *
+ * @author Paul Hensgen
+ * Bugs and comments to uml-devel@lists.sf.net or http://bugs.kde.org
+ */
+class AssocRules {
+public:
+ /**
+ * Constructor.
+ */
+ AssocRules();
+
+ /**
+ * Deconstructor.
+ */
+ ~AssocRules();
+
+ /**
+ * Returns whether an association is going to be allowed for the given
+ * values. This method is used to test if you can start an association.
+ */
+ static bool allowAssociation( Uml::Association_Type assocType, UMLWidget * widget );
+
+ static bool allowAssociation( Uml::Association_Type assocType, const std::type_info & );
+
+ /**
+ * Returns whether an association is valid with the given variables.
+ * This method is used to finish an association.
+ */
+ static bool allowAssociation( Uml::Association_Type assocType,
+ UMLWidget * widgetA, UMLWidget * widgetB,
+ bool extendedCheck = true );
+
+ /**
+ * Returns whether to allow a role text for the given association type.
+ */
+ static bool allowRole( Uml::Association_Type assocType );
+
+ /**
+ * Returns whether to allow a multiplicity text for the given
+ * association and widget type.
+ */
+ static bool allowMultiplicity( Uml::Association_Type assocType, Uml::Widget_Type widgetType );
+
+ /**
+ * Returns whether to allow an association to self for given variables.
+ */
+ static bool allowSelf( Uml::Association_Type assocType, Uml::Widget_Type widgetType );
+
+ /**
+ * Returns whether an implements association should be a Realisation or
+ * a Generalisation.
+ * as defined in m_AssocRules.
+ */
+ static Uml::Association_Type isGeneralisationOrRealisation(UMLWidget* widgetA, UMLWidget* widgetB);
+
+private:
+
+ /**
+ * Structure to help determine association rules.
+ */
+ struct Assoc_Rule {
+ Uml::Association_Type assoc_type; ///< association type
+ Uml::Widget_Type widgetA_type; ///< type of role A widget
+ Uml::Widget_Type widgetB_type; ///< type of role B widget
+ bool role; ///< role text
+ bool multiplicity; ///< multipliciy text on association
+ /// can have an association of same type going between widget each way
+ bool directional;
+
+ bool self; ///< association to self
+ };
+
+ /**
+ * Container that holds all the rules.
+ */
+ static Assoc_Rule m_AssocRules[];
+
+ /**
+ * The number of rules known about.
+ */
+ static int m_nNumRules;
+};
+
+#endif
diff --git a/umbrello/umbrello/attribute.cpp b/umbrello/umbrello/attribute.cpp
new file mode 100644
index 00000000..3bdadeb7
--- /dev/null
+++ b/umbrello/umbrello/attribute.cpp
@@ -0,0 +1,327 @@
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * copyright (C) 2002-2007 *
+ * Umbrello UML Modeller Authors <uml-devel@uml.sf.net> *
+ ***************************************************************************/
+
+// own header
+#include "attribute.h"
+// qt/kde includes
+#include <qregexp.h>
+#include <kdebug.h>
+// app includes
+#include "classifier.h"
+#include "operation.h"
+#include "umlobject.h"
+#include "umldoc.h"
+#include "uml.h"
+#include "dialogs/umlattributedialog.h"
+#include "object_factory.h"
+
+UMLAttribute::UMLAttribute( const UMLObject *parent,
+ const QString& name, Uml::IDType id,
+ Uml::Visibility s,
+ UMLObject *type, const QString& iv )
+ : UMLClassifierListItem(parent, name, id) {
+ m_InitialValue = iv;
+ m_BaseType = Uml::ot_Attribute;
+ m_Vis = s;
+ m_ParmKind = Uml::pd_In;
+ /* CHECK: Do we need this:
+ if (type == NULL) {
+ type = Object_Factory::createUMLObject(Uml::ot_Datatype, "undef");
+ }
+ */
+ m_pSecondary = type;
+}
+
+UMLAttribute::UMLAttribute(const UMLObject *parent) : UMLClassifierListItem(parent) {
+ m_BaseType = Uml::ot_Attribute;
+ m_Vis = Uml::Visibility::Private;
+ m_ParmKind = Uml::pd_In;
+}
+
+UMLAttribute::~UMLAttribute() { }
+
+void UMLAttribute::setName(const QString &name) {
+ m_Name = name;
+ emit attributeChanged();
+ UMLObject::emitModified();
+}
+
+void UMLAttribute::setVisibility(Uml::Visibility s) {
+ m_Vis = s;
+ emit attributeChanged();
+ UMLObject::emitModified();
+}
+
+QString UMLAttribute::getInitialValue() {
+ return m_InitialValue;
+}
+
+void UMLAttribute::setInitialValue(const QString &iv) {
+ if(m_InitialValue != iv) {
+ m_InitialValue = iv;
+ UMLObject::emitModified();
+ }
+}
+
+void UMLAttribute::setParmKind (Uml::Parameter_Direction pk) {
+ m_ParmKind = pk;
+}
+
+Uml::Parameter_Direction UMLAttribute::getParmKind () const {
+ return m_ParmKind;
+}
+
+QString UMLAttribute::toString(Uml::Signature_Type sig) {
+ QString s;
+
+ if(sig == Uml::st_ShowSig || sig == Uml::st_NoSig) {
+ s = m_Vis.toString(true) + ' ';
+ }
+
+ if(sig == Uml::st_ShowSig || sig == Uml::st_SigNoVis) {
+ // Determine whether the type name needs to be scoped.
+ UMLObject *owningObject = static_cast<UMLObject*>(parent());
+ if (owningObject->getBaseType() == Uml::ot_Operation) {
+ // The immediate parent() is the UMLOperation but we want
+ // the UMLClassifier:
+ owningObject = static_cast<UMLObject*>(owningObject->parent());
+ }
+ UMLClassifier *ownParent = dynamic_cast<UMLClassifier*>(owningObject);
+ if (ownParent == NULL) {
+ kError() << "UMLAttribute::toString: parent "
+ << owningObject->getName()
+ << " is not a UMLClassifier" << endl;
+ return "";
+ }
+ QString typeName;
+ UMLClassifier *type = UMLClassifierListItem::getType();
+ if (type) {
+ UMLPackage *typeScope = type->getUMLPackage();
+ if (typeScope != ownParent && typeScope != ownParent->getUMLPackage())
+ typeName = type->getFullyQualifiedName();
+ else
+ typeName = type->getName();
+ }
+ // The default direction, "in", is not mentioned.
+ // Perhaps we should include a pd_Unspecified in
+ // Uml::Parameter_Direction to have better control over this.
+ if (m_ParmKind == Uml::pd_InOut)
+ s += "inout ";
+ else if (m_ParmKind == Uml::pd_Out)
+ s += "out ";
+ // Construct the attribute text.
+ QString string = s + getName() + " : " + typeName;
+ if(m_InitialValue.length() > 0)
+ string += " = " + m_InitialValue;
+ return string;
+ }
+ return s + getName();
+}
+
+QString UMLAttribute::getFullyQualifiedName( const QString& separator,
+ bool includeRoot /* = false */) const {
+ UMLOperation *op = NULL;
+ UMLObject *owningObject = static_cast<UMLObject*>(parent());
+ if (owningObject->getBaseType() == Uml::ot_Operation) {
+ op = static_cast<UMLOperation*>(owningObject);
+ owningObject = static_cast<UMLObject*>(owningObject->parent());
+ }
+ UMLClassifier *ownParent = dynamic_cast<UMLClassifier*>(owningObject);
+ if (ownParent == NULL) {
+ kError() << "UMLAttribute::getFullyQualifiedName(" << m_Name
+ << "): parent " << owningObject->getName()
+ << " is not a UMLClassifier" << endl;
+ return "";
+ }
+ QString tempSeparator = separator;
+ if (tempSeparator.isEmpty())
+ tempSeparator = UMLApp::app()->activeLanguageScopeSeparator();
+ QString fqn = ownParent->getFullyQualifiedName(tempSeparator, includeRoot);
+ if (op)
+ fqn.append(tempSeparator + op->getName());
+ fqn.append(tempSeparator + m_Name);
+ return fqn;
+}
+
+bool UMLAttribute::operator==( UMLAttribute &rhs) {
+ if( this == &rhs )
+ return true;
+
+ if( !UMLObject::operator==( rhs ) )
+ return false;
+
+ // The type name is the only distinguishing criterion.
+ // (Some programming languages might support more, but others don't.)
+ if (m_pSecondary != rhs.m_pSecondary)
+ return false;
+
+ return true;
+}
+
+void UMLAttribute::copyInto(UMLAttribute *rhs) const
+{
+ // call the parent first.
+ UMLClassifierListItem::copyInto(rhs);
+
+ // Copy all datamembers
+ rhs->m_pSecondary = m_pSecondary;
+ rhs->m_SecondaryId = m_SecondaryId;
+ rhs->m_InitialValue = m_InitialValue;
+ rhs->m_ParmKind = m_ParmKind;
+}
+
+UMLObject* UMLAttribute::clone() const
+{
+ //FIXME: The new attribute should be slaved to the NEW parent not the old.
+ UMLAttribute *clone = new UMLAttribute( static_cast<UMLObject*>(parent()) );
+ copyInto(clone);
+
+ return clone;
+}
+
+
+void UMLAttribute::saveToXMI( QDomDocument & qDoc, QDomElement & qElement ) {
+ QDomElement attributeElement = UMLObject::save("UML:Attribute", qDoc);
+ if (m_pSecondary == NULL) {
+ kDebug() << "UMLAttribute::saveToXMI(" << m_Name
+ << "): m_pSecondary is NULL, m_SecondaryId is '"
+ << m_SecondaryId << "'" << endl;
+ } else {
+ attributeElement.setAttribute( "type", ID2STR(m_pSecondary->getID()) );
+ }
+ if (! m_InitialValue.isEmpty())
+ attributeElement.setAttribute( "initialValue", m_InitialValue );
+ qElement.appendChild( attributeElement );
+}
+
+bool UMLAttribute::load( QDomElement & element ) {
+ m_SecondaryId = element.attribute( "type", "" );
+ // We use the m_SecondaryId as a temporary store for the xmi.id
+ // of the attribute type model object.
+ // It is resolved later on, when all classes have been loaded.
+ // This deferred resolution is required because the xmi.id may
+ // be a forward reference, i.e. it may identify a model object
+ // that has not yet been loaded.
+ if (m_SecondaryId.isEmpty()) {
+ // Perhaps the type is stored in a child node:
+ QDomNode node = element.firstChild();
+ while (!node.isNull()) {
+ if (node.isComment()) {
+ node = node.nextSibling();
+ continue;
+ }
+ QDomElement tempElement = node.toElement();
+ QString tag = tempElement.tagName();
+ if (!Uml::tagEq(tag, "type")) {
+ node = node.nextSibling();
+ continue;
+ }
+ m_SecondaryId = tempElement.attribute( "xmi.id", "" );
+ if (m_SecondaryId.isEmpty())
+ m_SecondaryId = tempElement.attribute( "xmi.idref", "" );
+ if (m_SecondaryId.isEmpty()) {
+ QDomNode inner = node.firstChild();
+ QDomElement tmpElem = inner.toElement();
+ m_SecondaryId = tmpElem.attribute( "xmi.id", "" );
+ if (m_SecondaryId.isEmpty())
+ m_SecondaryId = tmpElem.attribute( "xmi.idref", "" );
+ }
+ break;
+ }
+ if (m_SecondaryId.isEmpty()) {
+ kDebug() << "UMLAttribute::load(" << m_Name << "): "
+ << "cannot find type." << endl;
+ }
+ }
+ m_InitialValue = element.attribute( "initialValue", "" );
+ if (m_InitialValue.isEmpty()) {
+ // for backward compatibility
+ m_InitialValue = element.attribute( "value", "" );
+ }
+ return true;
+}
+
+bool UMLAttribute::showPropertiesDialog(QWidget* parent) {
+ UMLAttributeDialog dialog(parent, this);
+ return dialog.exec();
+}
+
+
+void UMLAttribute::setTemplateParams(const QString& templateParam, UMLClassifierList &templateParamList) {
+ if (templateParam.isEmpty())
+ return;
+ QString type = templateParam.simplifyWhiteSpace();
+
+ int start = type.find(QChar('<'));
+ if (start >= 0 ) {
+ int end = start;
+ int count = 1;
+ int len = type.length();
+ while (count != 0 && ++end < len) {
+ QChar c = type.at(end);
+ if (c == QChar('<')) {
+ count++;
+ }
+ if (c == QChar('>')) {
+ count--;
+ }
+ }
+ if (count != 0) {
+ //The template is ill-formated, let's quit
+ return;
+ }
+ setTemplateParams(type.mid(start + 1, end - start - 1), templateParamList);
+ setTemplateParams(type.left(start) + type.right(len - end - 1), templateParamList);
+ } else {
+ QStringList paramsList = QStringList::split(QChar(','), type);
+ for ( QStringList::Iterator it = paramsList.begin(); it != paramsList.end(); ++it ) {
+ QString param = *it;
+ if (!param.isEmpty()) {
+ UMLDoc *pDoc = UMLApp::app()->getDocument();
+ UMLObject* obj = pDoc->findUMLObject(param);
+ if (obj == NULL ) {
+ obj = pDoc->findUMLObject(param.remove(QChar(' ')));
+ }
+ if (obj != NULL ) {
+ //We want to list only the params that already exist in this document
+ //If the param doesnt't already exist, we couldn't draw an association anyway
+ UMLClassifier* tmpClassifier = static_cast<UMLClassifier*>(obj);
+ if (templateParamList.findRef(tmpClassifier) == -1) {
+ templateParamList.append(tmpClassifier);
+ }
+ }
+ }
+ }
+ }
+}
+
+
+UMLClassifierList UMLAttribute::getTemplateParams() {
+ UMLClassifierList templateParamList;
+ QString type = getType()->getName();
+ QString templateParam;
+ // Handle C++/D/Java template/generic parameters
+ const Uml::Programming_Language pl = UMLApp::app()->getActiveLanguage();
+ if (pl == Uml::pl_Cpp || pl == Uml::pl_Java || pl == Uml::pl_D) {
+ int start = type.find(QChar('<'));
+ if (start >= 0 ) {
+ int end = type.findRev(QChar('>'));
+ if (end > start) {
+ templateParam = type.mid(start + 1, end - start - 1);
+ setTemplateParams(templateParam, templateParamList);
+ }
+ }
+ }
+ return templateParamList;
+}
+
+
+#include "attribute.moc"
diff --git a/umbrello/umbrello/attribute.h b/umbrello/umbrello/attribute.h
new file mode 100644
index 00000000..85253216
--- /dev/null
+++ b/umbrello/umbrello/attribute.h
@@ -0,0 +1,157 @@
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * copyright (C) 2002-2006 *
+ * Umbrello UML Modeller Authors <uml-devel@uml.sf.net> *
+ ***************************************************************************/
+
+#ifndef ATTRIBUTE_H
+#define ATTRIBUTE_H
+
+#include "classifierlistitem.h"
+#include "umlnamespace.h"
+#include "umlclassifierlist.h"
+
+/**
+ * This class is used to set up information for an attribute. This is like
+ * a programming attribute. It has a type, name, visibility and initial value.
+ *
+ * @short Sets up attribute information.
+ * @author Paul Hensgen <phensgen@techie.com>
+ * @see UMLObject
+ * Bugs and comments to uml-devel@lists.sf.net or http://bugs.kde.org
+ */
+class UMLAttribute : public UMLClassifierListItem {
+ Q_OBJECT
+public:
+ /**
+ * Sets up an attribute.
+ *
+ * @param parent The parent of this UMLAttribute.
+ * @param name The name of this UMLAttribute.
+ * @param id The unique id given to this UMLAttribute.
+ * @param s The visibility of the UMLAttribute.
+ * @param type The type of this UMLAttribute.
+ * @param iv The initial value of the attribute.
+ */
+ UMLAttribute(const UMLObject *parent, const QString& name,
+ Uml::IDType id = Uml::id_None,
+ Uml::Visibility s = Uml::Visibility::Private,
+ UMLObject *type = 0, const QString& iv = 0);
+
+ /**
+ * Sets up an attribute.
+ *
+ * @param parent The parent of this UMLAttribute.
+ */
+ UMLAttribute(const UMLObject *parent);
+
+ /**
+ * Overloaded '==' operator
+ */
+ bool operator==( UMLAttribute &rhs);
+
+ /**
+ * destructor.
+ */
+ virtual ~UMLAttribute();
+
+ /**
+ * Copy the internal presentation of this object into the UMLAttribute
+ * object.
+ */
+ virtual void copyInto(UMLAttribute *rhs) const;
+
+ /**
+ * Reimplementation of method from UMLObject is required as
+ * an extra signal, attributeChanged(), is emitted.
+ */
+ void setName(const QString &name);
+
+ /**
+ * Reimplementation of method from UMLObject is required as
+ * an extra signal, attributeChanged(), is emitted.
+ */
+ void setVisibility(Uml::Visibility s);
+
+ /**
+ * Make a clone of the UMLAttribute.
+ */
+ virtual UMLObject* clone() const;
+
+ /**
+ * Returns The initial value of the UMLAttribute.
+ *
+ * @return The initial value of the Atrtibute.
+ */
+ QString getInitialValue();
+
+ /**
+ * Sets the initial value of the UMLAttribute.
+ *
+ * @param iv The initial value of the UMLAttribute.
+ */
+ void setInitialValue( const QString &iv );
+
+ /**
+ * Returns a string representation of the UMLAttribute.
+ *
+ * @param sig If true will show the attribute type and
+ * initial value.
+ * @return Returns a string representation of the UMLAttribute.
+ */
+ QString toString(Uml::Signature_Type sig = Uml::st_NoSig);
+
+ /**
+ * Reimplement method from UMLObject.
+ */
+ QString getFullyQualifiedName(const QString& separator = QString::null,
+ bool includeRoot = false) const;
+
+ /**
+ * Creates the <UML:Attribute> XMI element.
+ */
+ void saveToXMI( QDomDocument & qDoc, QDomElement & qElement );
+
+ /**
+ * Display the properties configuration dialog for the attribute.
+ */
+ virtual bool showPropertiesDialog(QWidget* parent);
+
+ void setParmKind (Uml::Parameter_Direction pk);
+ Uml::Parameter_Direction getParmKind () const;
+
+ /**
+ * Returns all the template params (if any) that are in the type of this attribute
+ */
+ virtual UMLClassifierList getTemplateParams();
+
+signals:
+ /**
+ * Required for informing AssociationWidgets representing this attribute
+ * that the attribute name or visibility has changed.
+ */
+ void attributeChanged();
+
+protected:
+ /**
+ * Loads the <UML:Attribute> XMI element.
+ */
+ bool load( QDomElement & element );
+
+ QString m_InitialValue; ///< text for the attribute's initial value.
+ Uml::Parameter_Direction m_ParmKind;
+
+private:
+ /**
+ * Puts in the param templateParamList all the template params that are in templateParam
+ */
+ void setTemplateParams(const QString& templateParam, UMLClassifierList &templateParamList);
+
+};
+
+#endif
diff --git a/umbrello/umbrello/autolayout/Makefile.am b/umbrello/umbrello/autolayout/Makefile.am
new file mode 100644
index 00000000..8c2a6cb3
--- /dev/null
+++ b/umbrello/umbrello/autolayout/Makefile.am
@@ -0,0 +1,20 @@
+noinst_LTLIBRARIES = libautolayout.la
+
+INCLUDES = -Idialogs -Irefactoring \
+ $(all_includes)
+#AM_CXXFLAGS = -I/usr/include/graphviz/
+
+libautolayout_la_METASOURCES = AUTO
+#noinst_HEADERS = node.h autolayout.h autolayoutdlg.h autolayouter.h canvas.h \
+# autolayouteradapter.h graphvizautolayouter.h simplecanvas.h graphvizgraph.h graphviznode.h \
+# dotautolayouter.h dotautolayouter.h baseinclude.h
+#noinst_LIBRARIES = libautolayout.la
+libautolayout_la_SOURCES = newautolayoutdialog.ui autolayoutdlg.cpp \
+ autolayouter.cpp autolayouteradapter.cpp graphvizautolayouter.cpp simplecanvas.cpp \
+ graphvizgraph.cpp graphviznode.cpp dotautolayouter.cpp neatoautolayouter.cpp \
+ circoautolayouter.cpp
+
+#libautolayout_la_LIBADD = /usr/lib/graphviz/libdotneato.la
+#libautolayout_la_LDFLAGS = -ldotneato -L/usr/lib/graphviz
+
+
diff --git a/umbrello/umbrello/autolayout/_graph.h b/umbrello/umbrello/autolayout/_graph.h
new file mode 100644
index 00000000..179a9471
--- /dev/null
+++ b/umbrello/umbrello/autolayout/_graph.h
@@ -0,0 +1,34 @@
+/*
+ * copyright (C) 2005
+ * Umbrello UML Modeller Authors <uml-devel @uml.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 AUTOLAYOUTGRAPH_H
+#define AUTOLAYOUTGRAPH_H
+#include "baseinclude.h"
+namespace Autolayout {
+
+/**
+@author Dimitri Ognibene <ognibened @yahoo.it>
+*/
+class Graph{
+public:
+ virtual ~Graph() {}
+ virtual void addNode(const char *name, int width,int heigt)=0;
+ virtual void addEdge(const char* nodea,const char*nodeb,int weight=100)=0;
+ virtual Node* getNode(const char*)=0;
+ virtual bool empty()=0;
+};
+
+}
+
+#endif
diff --git a/umbrello/umbrello/autolayout/autolayout.h b/umbrello/umbrello/autolayout/autolayout.h
new file mode 100644
index 00000000..9f34a1d8
--- /dev/null
+++ b/umbrello/umbrello/autolayout/autolayout.h
@@ -0,0 +1,45 @@
+/*
+ * copyright (C) 2005
+ * Umbrello UML Modeller Authors <uml-devel @uml.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 AUTOLAYOUT_H
+#define AUTOLAYOUT_H
+
+
+#include "canvas.h"
+#include "simplecanvas.h"
+
+#include "node.h"
+
+#include "_graph.h"
+//#include "diagram.h"
+
+
+
+#include "graphviznode.h"
+#include "graphvizgraph.h"
+
+
+
+#include "autolayouter.h"
+#include "autolayouteradapter.h"
+#include "graphvizautolayouter.h"
+#include "dotautolayouter.h"
+#include "circoautolayouter.h"
+#include "neatoautolayouter.h"
+
+
+
+
+
+#endif
diff --git a/umbrello/umbrello/autolayout/autolayoutdlg.cpp b/umbrello/umbrello/autolayout/autolayoutdlg.cpp
new file mode 100644
index 00000000..2f6b1a4c
--- /dev/null
+++ b/umbrello/umbrello/autolayout/autolayoutdlg.cpp
@@ -0,0 +1,184 @@
+/***************************************************************************
+ * copyright (C) 2005 *
+ * Umbrello UML Modeller Authors <uml-devel @uml.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. *
+ * *
+ ***************************************************************************/
+
+#include "autolayoutdlg.h"
+#include "../associationwidget.h"
+#include "../umlwidget.h"
+#include "autolayout.h"
+#include "newautolayoutdialog.h"
+#include <qcheckbox.h>
+#include <qspinbox.h>
+#include <qslider.h>
+#include <kdebug.h>
+
+
+AutolayoutDlg::AutolayoutDlg(KConfig* c,UMLView* v,QWidget *parent, const char *name)
+ :MyDialog1(parent, name)
+{
+ view=v;
+ readConfig(c);
+ config=c;
+}
+
+void AutolayoutDlg::slotSetAssociationWeight(int i)
+{
+ associationWeight=i;
+}
+
+
+void AutolayoutDlg::slotSetDependenciesWeight(int i)
+{
+ dependenciesWeight=i;
+}
+
+
+void AutolayoutDlg::slotSetGeneralizationWeight(int i)
+{
+ generalizationWeight=i;
+}
+void AutolayoutDlg::slotSetGenralizationAsEdges(bool b)
+{
+ genralizationAsEdges=b;
+}
+
+
+void AutolayoutDlg::slotSetDependenciesAsEdges(bool b)
+{
+ dependenciesAsEdges=b;
+}
+
+
+void AutolayoutDlg::slotSetAssociationAsEdges(bool b)
+{
+ associationAsEdges=b;
+}
+
+
+
+void AutolayoutDlg::slotSetCompressShapes(bool b)
+{
+ compressShapes=b;
+}
+
+
+void AutolayoutDlg::slotSetCenterDiagram(bool b)
+{
+ centerDiagram=b;
+}
+
+
+void AutolayoutDlg::slotSetClusterizeHierarchies(bool b)
+
+{
+ clusterizeHierarchies=b;
+}
+
+
+void AutolayoutDlg::slotSetShapeSeparation(int i)
+{
+ shapeSeparation=i;
+}
+
+void AutolayoutDlg::slotReloadSettings()
+{
+ readConfig(config);
+}
+
+
+void AutolayoutDlg::slotSaveSettings()
+{
+ writeConfig(config);
+}
+
+
+void AutolayoutDlg::slotDoAutolayout()
+{
+
+ Autolayout::Autolayouter* a=getAutolayouter();;
+
+ a->setAssociationAsEdges( associationAsEdges);
+ a->setAssociationWeight( associationWeight );
+ a->setCenterDiagram( centerDiagram);
+ a->setDependenciesAsEdges( dependenciesAsEdges);
+ a->setClusterizeHierarchies( clusterizeHierarchies);
+ a->setCompressShapes( compressShapes);
+ a->setDependenciesWeight( dependenciesWeight);
+ a->setGeneralizationAsEdges( genralizationAsEdges);
+ a->setGeneralizationWeight( generalizationWeight);
+ a->setNoteConnectionWeight( 1);
+ a->setNoteConnectionsAsEdges(true);
+ a->setShapeSeparation( shapeSeparation);
+ a->autolayout( view);
+ delete a;
+ a=0;
+ accept();
+}
+
+void AutolayoutDlg::readConfig( KConfig * conf)
+{
+ conf->setGroup("AutolayoutDlg");
+ associationEdgesCB->setChecked((bool)(conf->readBoolEntry( "associationAsEdges",false)));
+ centerDiagramCB->setChecked((bool)(conf->readBoolEntry( "centerDiagram",true)));
+ dependenciesEdgesCB->setChecked((bool)(conf->readBoolEntry( "dependenciesAsEdges",false)));
+ clusterizeHierarchiesCB->setChecked((bool)(conf->readBoolEntry( "clusterizeHierarchies",false)));
+ compressShapesCB->setChecked((bool)(conf->readBoolEntry( "compressShapes",true)));
+ dependenciedEdgesSL->setValue((int)(conf->readNumEntry( "dependenciesWeight",0)));
+ generalizationCB->setChecked((bool)(conf->readBoolEntry( "genralizationAsEdges",true)));
+ generalizationEdgessSL->setValue((int)(conf->readNumEntry( "generalizationWeight",1)));
+ associationEdgesSL->setValue((int)(conf->readNumEntry( "associationWeight",0)));
+ shapeSeparationSB->setValue((int)(conf->readNumEntry( "shapeSeparation",0)));
+ algorithmCOB->setCurrentItem((int)(conf->readNumEntry( "algorithm",0)));
+}
+
+void AutolayoutDlg::writeConfig( KConfig * conf)
+{
+ // conf=kapp->config();
+ conf->setGroup("AutolayoutDlg");
+ conf->writeEntry( "associationAsEdges",associationEdgesCB->isChecked());
+ conf->writeEntry( "centerDiagram", centerDiagramCB->isChecked());
+ conf->writeEntry("dependenciesAsEdges",dependenciesEdgesCB->isChecked());
+ conf->writeEntry("clusterizeHierarchies",clusterizeHierarchiesCB->isChecked());
+ conf->writeEntry("dependenciesWeight", dependenciedEdgesSL->value());
+ conf->writeEntry("genralizationAsEdges",generalizationCB->isChecked());
+
+ conf->writeEntry("generalizationWeight",generalizationEdgessSL->value());
+ conf->writeEntry("associationWeight",associationEdgesSL->value());
+ conf->writeEntry("shapeSeparation",shapeSeparationSB->value());
+ //conf->writeEntry("al
+
+
+ //algorithmCOB->setCurrentItem(conf->readNumEntry( "algorithm",0));
+
+}
+
+void AutolayoutDlg::slotSelectAlgorithm( const QString& _algname)
+{
+ algname=_algname;
+
+}
+
+Autolayout::Autolayouter * AutolayoutDlg::getAutolayouter( )
+{
+ const QString text = algorithmCOB->currentText();
+ kDebug() << "Autolayout Algorithm " << algname << " found " << text << endl;
+ if (text == "dot")
+ return new Autolayout::DotAutolayouter();
+ if (text == "circo")
+ return new Autolayout::CircoAutolayouter();
+ if (text == "neato")
+ return new Autolayout::NeatoAutolayouter();
+ kError() << "Autolayout Algorithm not found" << endl;
+ return new Autolayout::DotAutolayouter();
+}
+
+
+
+#include "autolayoutdlg.moc"
diff --git a/umbrello/umbrello/autolayout/autolayoutdlg.h b/umbrello/umbrello/autolayout/autolayoutdlg.h
new file mode 100644
index 00000000..2e40d736
--- /dev/null
+++ b/umbrello/umbrello/autolayout/autolayoutdlg.h
@@ -0,0 +1,63 @@
+/***************************************************************************
+ * copyright (C) 2005 *
+ * Umbrello UML Modeller Authors <uml-devel @uml.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 AUTOLAYOUTDLG_H
+#define AUTOLAYOUTDLG_H
+
+#include "newautolayoutdialog.h"
+#include "../umlview.h"
+#include <qobject.h>
+#include <kconfig.h>
+#include "autolayout.h"
+
+class AutolayoutDlg : public MyDialog1
+{
+ Q_OBJECT
+ public:
+ AutolayoutDlg(KConfig* c,UMLView* v, QWidget *parent = 0, const char *name = 0);
+ public slots:
+ virtual void slotSetAssociationWeight(int i);
+ virtual void slotSetDependenciesWeight(int i);
+ virtual void slotSetGeneralizationWeight(int i);
+ virtual void slotSetGenralizationAsEdges(bool b);
+ virtual void slotSetDependenciesAsEdges(bool b);
+ virtual void slotSetAssociationAsEdges(bool b);
+ virtual void slotSetCompressShapes(bool b);
+ virtual void slotSetCenterDiagram(bool b);
+ virtual void slotSetClusterizeHierarchies(bool b);
+ virtual void slotSetShapeSeparation(int i);
+ virtual void slotReloadSettings();
+ virtual void slotSaveSettings();
+ virtual void slotDoAutolayout();
+ void readConfig(KConfig*);
+ void writeConfig(KConfig*);
+ virtual void slotSelectAlgorithm(const QString&);
+
+
+ private:
+ UMLView *view;
+ int associationWeight;
+ int dependenciesWeight;
+ int generalizationWeight;
+ bool genralizationAsEdges;
+ bool dependenciesAsEdges;
+ bool associationAsEdges;
+ bool compressShapes;
+ bool centerDiagram;
+ bool clusterizeHierarchies;
+ int shapeSeparation;
+ KConfig* config;
+ QString algname;
+ Autolayout::Autolayouter* getAutolayouter();
+
+};
+
+#endif
diff --git a/umbrello/umbrello/autolayout/autolayouter.cpp b/umbrello/umbrello/autolayout/autolayouter.cpp
new file mode 100644
index 00000000..f70fd195
--- /dev/null
+++ b/umbrello/umbrello/autolayout/autolayouter.cpp
@@ -0,0 +1,29 @@
+/*
+ * copyright (C) 2005
+ * Umbrello UML Modeller Authors <uml-devel @uml.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. *
+ * *
+ ***************************************************************************/
+#include "autolayouter.h"
+
+namespace Autolayout {
+
+
+
+void Autolayouter::autolayout( UMLView * v )
+{
+ setCanvas(v);
+ setGraph(v);
+ run();
+ updateView(v);
+}
+
+} // end namespace Autolayout
+
diff --git a/umbrello/umbrello/autolayout/autolayouter.h b/umbrello/umbrello/autolayout/autolayouter.h
new file mode 100644
index 00000000..a56b1ce3
--- /dev/null
+++ b/umbrello/umbrello/autolayout/autolayouter.h
@@ -0,0 +1,64 @@
+/***************************************************************************
+ * copyright (C) 2005
+ * Umbrello UML Modeller Authors <uml-devel @uml.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 AUTOLAYOUTAUTOLAYOUTER_H
+#define AUTOLAYOUTAUTOLAYOUTER_H
+#include "baseinclude.h"
+
+namespace Autolayout {
+
+/**
+This is the super class of any class which encapsulate an autolayout algorithm
+
+
+@author Dimitri Ognibene <ognibened @yahoo.it>
+*/
+class Autolayouter {
+public:
+ virtual ~Autolayouter() {}
+
+ virtual void setNoteConnectionWeight(int i)=0;
+ virtual void setNoteConnectionsAsEdges(bool b)=0;
+ virtual void setAssociationWeight(int i)=0;
+
+ virtual void setDependenciesWeight(int i)=0;
+
+ virtual void setGeneralizationWeight(int i)=0;
+
+ virtual void setGeneralizationAsEdges(bool b)=0;
+
+ virtual void setDependenciesAsEdges(bool b)=0;
+
+ virtual void setAssociationAsEdges(bool b)=0;
+
+ virtual void setCompressShapes(bool b)=0;
+
+ virtual void setCenterDiagram(bool b)=0;
+
+ virtual void setClusterizeHierarchies(bool b)=0;
+
+ virtual void setShapeSeparation(int i)=0;
+
+ virtual void autolayout(UMLView* v);
+protected:
+ virtual void run()=0;
+ virtual void updateView(UMLView*)=0;
+ virtual Autolayout::Canvas* getCanvas()=0;
+ virtual Autolayout::Graph* getGraph()=0;
+ virtual Autolayout::Graph* setGraph(UMLView* view)=0;
+ virtual Autolayout::Canvas* setCanvas(UMLView* view)=0;
+
+
+};
+
+}
+
+#endif
diff --git a/umbrello/umbrello/autolayout/autolayouteradapter.cpp b/umbrello/umbrello/autolayout/autolayouteradapter.cpp
new file mode 100644
index 00000000..0673fde1
--- /dev/null
+++ b/umbrello/umbrello/autolayout/autolayouteradapter.cpp
@@ -0,0 +1,191 @@
+/***************************************************************************
+ * copyright (C) 2005 *
+ * Umbrello UML Modeller Authors <uml-devel @uml.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. *
+ * *
+ ***************************************************************************/
+
+#include "autolayouteradapter.h"
+
+
+namespace Autolayout
+ {
+
+ AutolayouterAdapter::AutolayouterAdapter()
+ : Autolayout::Autolayouter()
+ {}
+
+
+ AutolayouterAdapter::~AutolayouterAdapter()
+ {}}
+
+void Autolayout::AutolayouterAdapter::addRelationship( AssociationWidget * a )
+ {
+ int weight;
+ switch (a->getAssocType())
+ {
+ case Uml::at_Generalization:;
+ case Uml::at_Realization:
+ {
+ if (genralizationAsEdges)weight=generalizationWeight;
+ else return;
+ break;
+ }
+ case Uml::at_Dependency:
+ {
+ if (dependenciesAsEdges) weight=dependenciesWeight;
+ else return;
+ break;
+ }
+ case Uml::at_Anchor:
+ {
+ if (anchorsAsEdges) weight=anchorsWeight;
+ else return;
+ break;
+ }
+ case Uml::at_Aggregation:;
+ case Uml::at_Association:;
+ case Uml::at_Containment:;
+ case Uml::at_Composition:;
+ default: return;
+ /*case Uml::at_Association_Self:;
+ case Uml::at_Activity:;
+ case Uml::at_Relationship:;
+ case Uml::at_Coll_Message:;
+ case Uml::at_Seq_Message:;
+ case Uml::at_Coll_Message_Self:;
+ case Uml::at_Seq_Message_Self:;
+ case Uml::at_Containment:;
+ case Uml::at_Composition:;
+ case Uml::at_Realization:;
+ case Uml::at_UniAssociation:;
+
+ case Uml::at_State:;
+ case Uml::at_Unknown:;
+ */
+ };
+ getGraph()->addEdge(a->getWidgetID(Uml::A).c_str(),a->getWidgetID(Uml::B).c_str(),weight);
+ }
+
+void Autolayout::AutolayouterAdapter::setAssociationWeight( int i )
+ {
+ associationWeight=i;
+ }
+
+void Autolayout::AutolayouterAdapter::setDependenciesWeight( int i )
+ {
+ dependenciesWeight=i;
+ }
+
+void Autolayout::AutolayouterAdapter::setGeneralizationWeight( int i )
+ {
+ generalizationWeight=i;
+ }
+
+void Autolayout::AutolayouterAdapter::setGeneralizationAsEdges( bool b )
+ {
+ genralizationAsEdges=b;
+ }
+
+void Autolayout::AutolayouterAdapter::setDependenciesAsEdges( bool b )
+ {
+ dependenciesAsEdges=b;
+ }
+
+void Autolayout::AutolayouterAdapter::setAssociationAsEdges( bool b )
+ {
+ associationAsEdges=b;
+ }
+
+void Autolayout::AutolayouterAdapter::setCompressShapes( bool b )
+ {
+ compressShapes=b;
+ }
+
+void Autolayout::AutolayouterAdapter::setCenterDiagram( bool b )
+ {
+ centerDiagram=b;
+ }
+
+void Autolayout::AutolayouterAdapter::setClusterizeHierarchies( bool b )
+ {
+ clusterizeHierarchies=b;
+ }
+
+void Autolayout::AutolayouterAdapter::setShapeSeparation( int i )
+ {
+ shapeSeparation=i;
+ }
+
+Autolayout::Graph * Autolayout::AutolayouterAdapter::setGraph( UMLView * view )
+ {
+ if (! view) return 0;
+ Autolayout::Graph * g=getGraph();
+ if (g&&g->empty())
+ {
+ UMLWidgetList list = view->getWidgetList();
+ UMLWidget* widget;
+ for ( widget = list.first(); widget; widget= list.next() )
+ {
+ if (widget->getBaseType() == Uml::wt_Class)
+ {
+
+
+ g->addNode(widget->getID().c_str(),widget->getWidth(),
+ widget->getHeight());
+ }
+ }
+ AssociationWidgetList as_list=view->getAssociationList();
+ AssociationWidget* assoc;
+ AssociationWidgetListIt it(as_list);
+ while ( (assoc = it.current()) != 0 )
+ {
+ ++it;
+ addRelationship(assoc);
+ }
+ }
+ return g;
+ }
+
+void Autolayout::AutolayouterAdapter::updateView( UMLView* view )
+ {
+if (! view) return ;
+UMLWidgetList list = view->getWidgetList();
+ UMLWidget* widget;
+ Graph *g=getGraph();
+ if (! view||!g) return ;
+ for ( widget = list.first(); widget; widget= list.next() )
+ if (widget->getBaseType() == Uml::wt_Class)
+ {
+ Node* n =g->getNode(widget->getID().c_str());
+ //printf("old values widgets %s x,y:%d,%d\n",widget->getID().c_str(),widget->getX(),widget->getY());
+ //int x_old=widget->getX();
+ //int x_calc=n.getX();
+ //int x_calc2=30 +n.getX()-widget->getWidth()/2;
+ widget->setX(getCanvas()->getBaseX() +n->getX()-widget->getWidth()/2);
+ //int x=widget->getX();
+ widget->setY(getCanvas()->getMaxY()/2-(n->getY()+(widget->getHeight()/2)));
+
+ widget->updateWidget();
+
+ }
+ }
+
+Autolayout::Canvas * Autolayout::AutolayouterAdapter::setCanvas( UMLView* view )
+ {
+ return canvas=new Autolayout::SimpleCanvas(view->getCanvasWidth(),view->getCanvasHeight());
+ }
+
+void Autolayout::AutolayouterAdapter::setNoteConnectionWeight( int i )
+{
+noteConnectionWeight=i;
+}
+
+void Autolayout::AutolayouterAdapter::setNoteConnectionsAsEdges( bool b )
+{
+noteConnectionAsEdges=b;
+}
diff --git a/umbrello/umbrello/autolayout/autolayouteradapter.h b/umbrello/umbrello/autolayout/autolayouteradapter.h
new file mode 100644
index 00000000..7c52e742
--- /dev/null
+++ b/umbrello/umbrello/autolayout/autolayouteradapter.h
@@ -0,0 +1,87 @@
+/***************************************************************************
+ * copyright (C) 2005
+ * Umbrello UML Modeller Authors <uml-devel @uml.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 AUTOLAYOUTAUTOLAYOUTERADAPTER_H
+#define AUTOLAYOUTAUTOLAYOUTERADAPTER_H
+//#include "autolayout.h"
+#include "baseinclude.h"
+#include "autolayouter.h"
+#include "../umlnamespace.h"
+
+
+namespace Autolayout
+{
+
+/**
+@author Dimitri Ognibene <ognibened @yahoo.it>
+*/
+class AutolayouterAdapter : virtual public Autolayout::Autolayouter
+{
+public:
+ AutolayouterAdapter();
+
+ virtual ~AutolayouterAdapter();
+ virtual void setAssociationWeight(int i);
+
+ virtual void setDependenciesWeight(int i);
+
+ virtual void setGeneralizationWeight(int i);
+
+ virtual void setGeneralizationAsEdges(bool b);
+
+ virtual void setDependenciesAsEdges(bool b);
+
+ virtual void setAssociationAsEdges(bool b);
+
+ virtual void setCompressShapes(bool b);
+
+ virtual void setCenterDiagram(bool b);
+
+ virtual void setClusterizeHierarchies(bool b);
+
+ virtual void setShapeSeparation(int i);
+ virtual void setNoteConnectionsAsEdges(bool b);
+ virtual void setNoteConnectionWeight(int i);
+
+
+protected:
+ virtual void run()=0;
+ virtual void updateView(UMLView* view);
+ virtual Canvas* getCanvas(){return canvas;};
+ virtual Graph* getGraph()=0;
+ virtual Graph* setGraph(UMLView* view);
+ virtual void addRelationship(AssociationWidget* a);
+ virtual Canvas* setCanvas(UMLView* view);
+
+ int associationWeight;
+ int dependenciesWeight;
+ int generalizationWeight;
+ bool genralizationAsEdges;
+ bool dependenciesAsEdges;
+ bool associationAsEdges;
+ bool compressShapes;
+ bool centerDiagram;
+ bool clusterizeHierarchies;
+ int shapeSeparation;
+ int noteConnectionWeight;
+ bool noteConnectionAsEdges;
+ bool anchorsAsEdges;
+ int anchorsWeight;
+ Canvas* canvas;
+private:
+ //Graph* graph;
+
+
+};
+
+}
+
+#endif
diff --git a/umbrello/umbrello/autolayout/baseinclude.h b/umbrello/umbrello/autolayout/baseinclude.h
new file mode 100644
index 00000000..590c1a5c
--- /dev/null
+++ b/umbrello/umbrello/autolayout/baseinclude.h
@@ -0,0 +1,29 @@
+/*
+ * copyright (C) 2005
+ * Umbrello UML Modeller Authors <uml-devel @uml.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 AUTOLAYOUTBASEINCLUDE_H
+
+#include "../umlview.h"
+#include "../associationwidget.h"
+#include "../umlwidget.h"
+
+#include "canvas.h"
+#include "simplecanvas.h"
+
+#include "node.h"
+
+#include "_graph.h"
+
+
+#endif
diff --git a/umbrello/umbrello/autolayout/canvas.h b/umbrello/umbrello/autolayout/canvas.h
new file mode 100644
index 00000000..246df8a7
--- /dev/null
+++ b/umbrello/umbrello/autolayout/canvas.h
@@ -0,0 +1,34 @@
+/*
+ * copyright (C) 2005
+ * Umbrello UML Modeller Authors <uml-devel @uml.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 AUTOLAYOUTCANVAS_H
+#define AUTOLAYOUTCANVAS_H
+
+namespace Autolayout {
+
+/**
+@author Dimitri Ognibene <ognibened @yahoo.it>
+*/
+class Canvas{
+public:
+ virtual int getMaxX()=0;
+ virtual int getMaxY()=0;
+ virtual int getBaseX()=0;
+ virtual int getBaseY()=0;
+ virtual ~Canvas() {}
+};
+
+}
+
+#endif
diff --git a/umbrello/umbrello/autolayout/diagram.h b/umbrello/umbrello/autolayout/diagram.h
new file mode 100644
index 00000000..33bda398
--- /dev/null
+++ b/umbrello/umbrello/autolayout/diagram.h
@@ -0,0 +1,50 @@
+/*
+ * copyright (C) 2005
+ * Umbrello UML Modeller Authors <uml-devel @uml.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 AUTOLAYOUTABLEDIAGRAM_H
+#define AUTOLAYOUTABLEDIAGRAM_H
+#include <dotneato.h>
+#define internal_renderizer
+#include "autolayout.h"
+/**
+@author Dimitri Ognibene <ognibened @yahoo.it>
+Umbrello UML Modeller Authors
+*/
+namespace Autolayout{
+class Diagram//: public virtual Graph, public virtual Canvas{
+{
+private:
+ Agraph_t* g;
+ Agsym_t* a_width;
+ Agsym_t* a_height;
+ Agsym_t* a_label;
+#ifndef internal_renderizer
+ GVC_t* gvc;
+#endif
+public:
+ Diagram(int,int);
+
+ ~Diagram();
+
+ void addNode(const char *name, int width,int heigt);
+ void addEdge(const char* nodea,const char*nodeb);
+ void autolayout();
+ void save();
+ Node getNode(const char*);
+
+};
+
+
+}
+#endif
diff --git a/umbrello/umbrello/autolayout/diagram_interface.h b/umbrello/umbrello/autolayout/diagram_interface.h
new file mode 100644
index 00000000..caee5752
--- /dev/null
+++ b/umbrello/umbrello/autolayout/diagram_interface.h
@@ -0,0 +1,31 @@
+/*
+ * copyright (C) 2005
+ * Umbrello UML Modeller Authors <uml-devel @uml.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 __DIAGRAM_INTERFACE_H
+#define __DIAGRAM_INTERFACE_H
+
+class DiagramInterface
+{
+public:
+ DiagramInterface() {}
+ virtual ~DiagramInterface() {}
+
+
+private:
+ DiagramInterface( const DiagramInterface& source );
+ void operator = ( const DiagramInterface& source );
+};
+
+
+#endif // __DIAGRAM_INTERFACE_H
diff --git a/umbrello/umbrello/autolayout/dotautolayouter.cpp b/umbrello/umbrello/autolayout/dotautolayouter.cpp
new file mode 100644
index 00000000..5d197845
--- /dev/null
+++ b/umbrello/umbrello/autolayout/dotautolayouter.cpp
@@ -0,0 +1,43 @@
+/*
+ * copyright (C) 2005
+ * Umbrello UML Modeller Authors <uml-devel @uml.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. *
+ * *
+ ***************************************************************************/
+#include "dotautolayouter.h"
+
+#include <graphviz/dotprocs.h>
+
+namespace Autolayout {
+
+DotAutolayouter::DotAutolayouter()
+ : Autolayout::GraphvizAutolayouter()
+{
+}
+
+
+DotAutolayouter::~DotAutolayouter()
+{
+ dot_cleanup(gg->_agraph);
+}
+
+
+void DotAutolayouter::run()
+{
+ //#ifndef internal_renderizer
+ /* bind graph to GV context - currently must be done before layout */
+ // gvBindContext(gvc,g);
+ //#endif
+ // do layout
+ //dot_layout();
+ dot_layout( gg->_agraph );
+}
+
+}
diff --git a/umbrello/umbrello/autolayout/dotautolayouter.h b/umbrello/umbrello/autolayout/dotautolayouter.h
new file mode 100644
index 00000000..5c6530ba
--- /dev/null
+++ b/umbrello/umbrello/autolayout/dotautolayouter.h
@@ -0,0 +1,38 @@
+/*
+ * copyright (C) 2005
+ * Umbrello UML Modeller Authors <uml-devel @uml.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 AUTOLAYOUTDOTAUTOLAYOUTER_H
+#define AUTOLAYOUTDOTAUTOLAYOUTER_H
+#include "baseinclude.h"
+#include "graphvizautolayouter.h"
+
+namespace Autolayout {
+
+/**
+@author Dimitri Ognibene <ognibened @yahoo.it>
+*/
+class DotAutolayouter : virtual public Autolayout::GraphvizAutolayouter
+{
+public:
+ DotAutolayouter();
+
+ virtual ~DotAutolayouter();
+
+ virtual void run();
+
+};
+
+}
+
+#endif
diff --git a/umbrello/umbrello/autolayout/graphvizautolayouter.cpp b/umbrello/umbrello/autolayout/graphvizautolayouter.cpp
new file mode 100644
index 00000000..8defc5ef
--- /dev/null
+++ b/umbrello/umbrello/autolayout/graphvizautolayouter.cpp
@@ -0,0 +1,54 @@
+/*
+ * copyright (C) 2005
+ * Umbrello UML Modeller Authors <uml-devel @uml.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. *
+ * *
+ ***************************************************************************/
+#include "graphvizautolayouter.h"
+
+#include <graphviz/graph.h>
+
+namespace Autolayout {
+
+GraphvizAutolayouter::GraphvizAutolayouter()
+ : Autolayout::AutolayouterAdapter()
+{
+ gg = new GraphvizGraph();
+}
+
+GraphvizAutolayouter::~GraphvizAutolayouter()
+{
+ agclose(gg->_agraph);
+ delete gg;
+}
+
+void GraphvizAutolayouter::setCompressShapes( bool b )
+{
+ gg->setCompressShapes(b);
+}
+
+void GraphvizAutolayouter::setCenterDiagram( bool b )
+{
+ gg->setCenterDiagram(b);
+}
+
+void GraphvizAutolayouter::setShapeSeparation( int i )
+{
+ gg->setShapeSeparation(i);
+}
+
+Autolayout::Canvas * GraphvizAutolayouter::setCanvas( UMLView * view )
+{
+ Canvas* canvas= AutolayouterAdapter::setCanvas(view);
+ gg->setCanvas(canvas);
+}
+
+} // end namespace AutoLayout
+
diff --git a/umbrello/umbrello/autolayout/graphvizautolayouter.h b/umbrello/umbrello/autolayout/graphvizautolayouter.h
new file mode 100644
index 00000000..114ae63f
--- /dev/null
+++ b/umbrello/umbrello/autolayout/graphvizautolayouter.h
@@ -0,0 +1,50 @@
+/***************************************************************************
+ * copyright (C) 2005
+ * Umbrello UML Modeller Authors <uml-devel @uml.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 AUTOLAYOUTGRAPHVIZAUTOLAYOUTER_H
+#define AUTOLAYOUTGRAPHVIZAUTOLAYOUTER_H
+#include "baseinclude.h"
+#include "autolayouteradapter.h"
+#include "graphvizgraph.h"
+
+namespace Autolayout
+{
+
+/**
+@author Dimitri Ognibene <ognibened @yahoo.it>
+*/
+class GraphvizAutolayouter : virtual public Autolayout::AutolayouterAdapter
+{
+public:
+ GraphvizAutolayouter();
+
+
+ virtual void setCompressShapes(bool b);
+
+ virtual void setCenterDiagram(bool b);
+
+ virtual void setShapeSeparation(int i);
+
+ virtual Canvas* setCanvas(UMLView* view);
+
+ virtual ~GraphvizAutolayouter();
+
+protected:
+ virtual Graph* getGraph(){if (!gg) gg=new GraphvizGraph(); return gg;}
+
+ virtual void run()=0;
+ GraphvizGraph* gg;
+
+};
+
+}
+
+#endif
diff --git a/umbrello/umbrello/autolayout/graphvizgraph.cpp b/umbrello/umbrello/autolayout/graphvizgraph.cpp
new file mode 100644
index 00000000..716f9223
--- /dev/null
+++ b/umbrello/umbrello/autolayout/graphvizgraph.cpp
@@ -0,0 +1,150 @@
+/***************************************************************************
+ * copyright (C) 2005
+ * Umbrello UML Modeller Authors <uml-devel @uml.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. *
+ * *
+ ***************************************************************************/
+#include "graphvizgraph.h"
+
+#include <graphviz/graph.h>
+#include <kdebug.h>
+
+#define DPI 96
+
+char* _strcpy(const char* name)
+{
+ char *a;
+ strlen(name);
+ a=new char[strlen(name)+1];
+ a=strcpy(a,name);
+ return a;
+}
+namespace Autolayout
+{
+
+/**
+ *
+ * @return
+ */
+GraphvizGraph::GraphvizGraph()
+ : Autolayout::Graph()
+{
+ aginit();
+ empty_flag=true;
+ _agraph = agopen("graph",AGDIGRAPH);
+ a_width= agnodeattr(_agraph, "width", "");;
+ a_height= agnodeattr(_agraph, "height", "");
+ a_label = agnodeattr(_agraph, "label", "");
+ a_weight= agedgeattr(_agraph,"weight","");
+ agnodeattr(_agraph, "fixedsize", "true");
+ agnodeattr(_agraph, "margin", "0.01,0.01");
+ agnodeattr(_agraph, "shape", "box");
+ agraphattr(_agraph, "dpi", "DPI/0");
+
+
+}
+
+
+GraphvizGraph::~GraphvizGraph()
+{
+ nodelist.clear();
+ agclose(_agraph);
+ /* Free graph structures */
+ //#ifndef internal_renderizer
+
+ /* Clean up output file and errors */
+ // dotneato_terminate(gvc);
+ //dotneato_eof(gvc);
+
+}
+
+
+
+
+void GraphvizGraph::addEdge(const char* nodea, const char* nodeb, int weight)
+{
+ char *a=_strcpy(nodea);
+ char *b=_strcpy(nodeb);
+ char *weight_str;
+ asprintf(&weight_str,"%d",weight);
+ Agedge_t* e= agedge(_agraph,agnode(_agraph,a),agnode(_agraph,b));
+ delete[](a);
+ delete[](b);
+ agxset(e,a_weight->index,weight_str);
+
+
+}
+
+void GraphvizGraph::addNode(const char* name, int width, int height)
+{
+ char *a =_strcpy(name);
+ char *w_str,*h_str;
+ Agnode_t* node =agnode(_agraph,a);
+ delete[](a);
+ agxset(node, a_label->index, "a");
+ asprintf(&h_str,"%f",((float)height)/DPI);
+ asprintf(&w_str,"%f",((float)width)/DPI);
+ agxset(node, a_height->index,h_str);// sprintf("%d",height));
+ free (h_str);
+ agxset(node, a_width->index, w_str);
+ free (w_str);
+ empty_flag = false;
+}
+
+
+void Autolayout::GraphvizGraph::setCompressShapes( bool b )
+{
+ if (empty())
+ {
+ if (b) agraphattr(_agraph,"ratio","compress");
+ else agraphattr(_agraph,"ratio","");
+ }
+}
+
+void Autolayout::GraphvizGraph::setCenterDiagram( bool b )
+{
+ if (empty())
+ {
+ if (b) agraphattr(_agraph,"center","true");
+ else agraphattr(_agraph,"center","false");
+ }
+}
+
+void Autolayout::GraphvizGraph::setShapeSeparation( int i )
+{
+ char* a;
+ asprintf(&a,"%f",((float) i)/10.0);
+ agraphattr(_agraph,"nodesep",a);
+ free (a);
+}
+
+bool Autolayout::GraphvizGraph::empty( )
+{
+ return empty_flag;
+}
+
+Autolayout::Node* Autolayout::GraphvizGraph::getNode( const char * arg1 )
+{
+ char *a = _strcpy(arg1);
+ Autolayout::GraphvizNode* b=
+ new Autolayout::GraphvizNode(agnode(_agraph,a));
+ delete[](a);
+ nodelist.push_back(b);
+ return b;
+}
+
+void GraphvizGraph::setCanvas( Autolayout::Canvas * canvas)
+{
+ char buf[100];
+ sprintf(buf,"%f,%f",((float)canvas->getMaxX()/DPI),((float)canvas->getMaxY()/DPI));
+ kDebug() << "size: " << buf << endl;
+ agraphattr(_agraph, "size", buf);
+ agraphattr(_agraph, "page", buf);
+}
+
+} // end namespace Autolayout
+
diff --git a/umbrello/umbrello/autolayout/graphvizgraph.h b/umbrello/umbrello/autolayout/graphvizgraph.h
new file mode 100644
index 00000000..dfbf323d
--- /dev/null
+++ b/umbrello/umbrello/autolayout/graphvizgraph.h
@@ -0,0 +1,58 @@
+/*
+ * copyright (C) 2005
+ * Umbrello UML Modeller Authors <uml-devel @uml.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 AUTOLAYOUTGRAPHVIZGRAPH_H
+#define AUTOLAYOUTGRAPHVIZGRAPH_H
+
+#include "baseinclude.h"
+#include "_graph.h"
+#include "graphviznode.h"
+#include <deque>
+#include <graphviz/types.h>
+
+namespace Autolayout
+{
+
+/**
+@author Dimitri Ognibene <ognibened @yahoo.it>
+*/
+class GraphvizGraph : virtual public Autolayout::Graph
+{
+public:
+ GraphvizGraph();
+
+ virtual ~GraphvizGraph();
+
+ virtual Node* getNode(const char* arg1);
+ virtual bool empty();
+ virtual void addEdge(const char* nodea, const char* nodeb, int weight=10);
+ virtual void addNode(const char* name, int width, int heigt);
+ void setCompressShapes(bool b);
+ void setCenterDiagram(bool b);
+ void setShapeSeparation(int i);
+ void setCanvas(Canvas* );
+ Agraph_t* _agraph;
+ Agsym_t* a_width;
+ Agsym_t* a_height;
+ Agsym_t* a_label;
+ Agsym_t* a_weight;
+ std::deque<Node*> nodelist;
+ GVC_t* gvc;
+ bool empty_flag;
+ friend class GraphvizAutolayouter;
+};
+
+}
+
+#endif
diff --git a/umbrello/umbrello/autolayout/graphviznode.cpp b/umbrello/umbrello/autolayout/graphviznode.cpp
new file mode 100644
index 00000000..ea3510cf
--- /dev/null
+++ b/umbrello/umbrello/autolayout/graphviznode.cpp
@@ -0,0 +1,46 @@
+/*
+ * copyright (C) 2005
+ * Umbrello UML Modeller Authors <uml-devel @uml.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. *
+ * *
+ ***************************************************************************/
+#include "graphviznode.h"
+
+#include <stdio.h>
+#include <graphviz/types.h>
+#include <graphviz/graph.h>
+
+namespace Autolayout {
+
+
+
+GraphvizNode::~GraphvizNode()
+{
+}
+
+
+int GraphvizNode::getX()
+{
+ point p = ND_coord_i(n);
+ return p.x;
+}
+
+int GraphvizNode::getY()
+{
+ point p = ND_coord_i(n);
+ return p.y;
+}
+
+}
+
+Autolayout::GraphvizNode::GraphvizNode( Agnode_t * node )
+{
+ n=node;
+}
diff --git a/umbrello/umbrello/autolayout/graphviznode.h b/umbrello/umbrello/autolayout/graphviznode.h
new file mode 100644
index 00000000..0efcb6d8
--- /dev/null
+++ b/umbrello/umbrello/autolayout/graphviznode.h
@@ -0,0 +1,42 @@
+/*
+ * copyright (C) 2005
+ * Umbrello UML Modeller Authors <uml-devel @uml.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 AUTOLAYOUTGRAPHVIZNODE_H
+#define AUTOLAYOUTGRAPHVIZNODE_H
+
+#include "node.h"
+
+class Agnode_t;
+
+namespace Autolayout {
+
+/**
+@author Dimitri Ognibene <ognibened @yahoo.it>
+*/
+class GraphvizNode : virtual public Autolayout::Node
+{
+
+ GraphvizNode (Agnode_t* n);
+ Agnode_t* n;
+ virtual ~GraphvizNode();
+public:
+
+
+ int getX();
+ int getY();
+ friend class GraphvizGraph;
+};
+
+}
+
+#endif
diff --git a/umbrello/umbrello/autolayout/newautolayoutdialog.ui b/umbrello/umbrello/autolayout/newautolayoutdialog.ui
new file mode 100644
index 00000000..e6407a5c
--- /dev/null
+++ b/umbrello/umbrello/autolayout/newautolayoutdialog.ui
@@ -0,0 +1,554 @@
+<!DOCTYPE UI><UI version="3.3" stdsetdef="1">
+<class>MyDialog1</class>
+<widget class="QDialog">
+ <property name="name">
+ <cstring>MyDialog1</cstring>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>662</width>
+ <height>281</height>
+ </rect>
+ </property>
+ <property name="sizeGripEnabled">
+ <bool>true</bool>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QFrame">
+ <property name="name">
+ <cstring>frame12</cstring>
+ </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>La&amp;yout Algorithm</string>
+ </property>
+ <property name="buddy" stdset="0">
+ <cstring>comboBox1</cstring>
+ </property>
+ </widget>
+ <widget class="QComboBox">
+ <item>
+ <property name="text">
+ <string>dot</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>neato</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>circo</string>
+ </property>
+ </item>
+ <property name="name">
+ <cstring>algorithmCOB</cstring>
+ </property>
+ </widget>
+ </hbox>
+ </widget>
+ <widget class="QGroupBox">
+ <property name="name">
+ <cstring>groupBox1</cstring>
+ </property>
+ <property name="frameShape">
+ <enum>Panel</enum>
+ </property>
+ <property name="title">
+ <string></string>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>textLabel1</cstring>
+ </property>
+ <property name="text">
+ <string>Shape separation</string>
+ </property>
+ <property name="buddy" stdset="0">
+ <cstring>shapeSeparationSB</cstring>
+ </property>
+ </widget>
+ <widget class="QSpinBox">
+ <property name="name">
+ <cstring>shapeSeparationSB</cstring>
+ </property>
+ <property name="prefix">
+ <string></string>
+ </property>
+ <property name="maxValue">
+ <number>200</number>
+ </property>
+ <property name="value">
+ <number>100</number>
+ </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>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QCheckBox">
+ <property name="name">
+ <cstring>clusterizeHierarchiesCB</cstring>
+ </property>
+ <property name="text">
+ <string>Clusteri&amp;ze Hierarchies</string>
+ </property>
+ </widget>
+ <widget class="QCheckBox">
+ <property name="name">
+ <cstring>centerDiagramCB</cstring>
+ </property>
+ <property name="text">
+ <string>Ce&amp;nter Diagram</string>
+ </property>
+ </widget>
+ <widget class="QCheckBox">
+ <property name="name">
+ <cstring>compressShapesCB</cstring>
+ </property>
+ <property name="text">
+ <string>Co&amp;mpress Shapes</string>
+ </property>
+ </widget>
+ </hbox>
+ </widget>
+ <widget class="QSplitter">
+ <property name="name">
+ <cstring>splitter14</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <widget class="QFrame">
+ <property name="name">
+ <cstring>frame5_2_2</cstring>
+ </property>
+ <property name="frameShape">
+ <enum>StyledPanel</enum>
+ </property>
+ <property name="frameShadow">
+ <enum>Raised</enum>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QSplitter">
+ <property name="name">
+ <cstring>splitter7_4</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Vertical</enum>
+ </property>
+ <widget class="QCheckBox">
+ <property name="name">
+ <cstring>generalizationCB</cstring>
+ </property>
+ <property name="text">
+ <string>Generalization as Ed&amp;ges</string>
+ </property>
+ <property name="checked">
+ <bool>true</bool>
+ </property>
+ </widget>
+ <widget class="QSlider">
+ <property name="name">
+ <cstring>generalizationEdgessSL</cstring>
+ </property>
+ <property name="maxValue">
+ <number>100</number>
+ </property>
+ <property name="value">
+ <number>100</number>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="toolTip" stdset="0">
+ <string>Weight</string>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>Select the weight that the autolayout algoritm must use to compare association with other relationships like Generalization and Dependence</string>
+ </property>
+ </widget>
+ </widget>
+ </vbox>
+ </widget>
+ <widget class="QFrame">
+ <property name="name">
+ <cstring>frame5_2</cstring>
+ </property>
+ <property name="frameShape">
+ <enum>StyledPanel</enum>
+ </property>
+ <property name="frameShadow">
+ <enum>Raised</enum>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QSplitter">
+ <property name="name">
+ <cstring>splitter7</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Vertical</enum>
+ </property>
+ <widget class="QCheckBox">
+ <property name="name">
+ <cstring>associationEdgesCB</cstring>
+ </property>
+ <property name="text">
+ <string>Association as Ed&amp;ges</string>
+ </property>
+ </widget>
+ <widget class="QSlider">
+ <property name="name">
+ <cstring>associationEdgesSL</cstring>
+ </property>
+ <property name="enabled">
+ <bool>false</bool>
+ </property>
+ <property name="maxValue">
+ <number>100</number>
+ </property>
+ <property name="value">
+ <number>100</number>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="toolTip" stdset="0">
+ <string>Weight</string>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>Select the weight that the autolayout algoritm must use to compare association with other relationships like Generalization and Dependence</string>
+ </property>
+ </widget>
+ </widget>
+ </vbox>
+ </widget>
+ <widget class="QFrame">
+ <property name="name">
+ <cstring>frame5</cstring>
+ </property>
+ <property name="frameShape">
+ <enum>StyledPanel</enum>
+ </property>
+ <property name="frameShadow">
+ <enum>Raised</enum>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QSplitter">
+ <property name="name">
+ <cstring>splitter6</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Vertical</enum>
+ </property>
+ <widget class="QCheckBox">
+ <property name="name">
+ <cstring>dependenciesEdgesCB</cstring>
+ </property>
+ <property name="text">
+ <string>Dependencies &amp;as Edges</string>
+ </property>
+ </widget>
+ <widget class="QSlider">
+ <property name="name">
+ <cstring>dependenciedEdgesSL</cstring>
+ </property>
+ <property name="enabled">
+ <bool>false</bool>
+ </property>
+ <property name="maxValue">
+ <number>100</number>
+ </property>
+ <property name="value">
+ <number>100</number>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="toolTip" stdset="0">
+ <string>Weight</string>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>Select the weight that the autolayout algoritm must use to compare association with other relationships like Generalization and Dependence</string>
+ </property>
+ </widget>
+ </widget>
+ </vbox>
+ </widget>
+ </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>1</height>
+ </size>
+ </property>
+ </spacer>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>layout9</cstring>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QPushButton">
+ <property name="name">
+ <cstring>buttonHelp</cstring>
+ </property>
+ <property name="text">
+ <string>He&amp;lp</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>277</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ <widget class="QPushButton">
+ <property name="name">
+ <cstring>buttonOk</cstring>
+ </property>
+ <property name="text">
+ <string>&amp;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>&amp;Cancel</string>
+ </property>
+ <property name="accel">
+ <string></string>
+ </property>
+ <property name="autoDefault">
+ <bool>true</bool>
+ </property>
+ </widget>
+ <widget class="QPushButton">
+ <property name="name">
+ <cstring>restoreDefaultsBTN</cstring>
+ </property>
+ <property name="text">
+ <string>&amp;Restore Default</string>
+ </property>
+ </widget>
+ <widget class="QPushButton">
+ <property name="name">
+ <cstring>saveDefaultsBTN</cstring>
+ </property>
+ <property name="text">
+ <string>Save As Defa&amp;ult</string>
+ </property>
+ </widget>
+ </hbox>
+ </widget>
+ </vbox>
+</widget>
+<connections>
+ <connection>
+ <sender>buttonCancel</sender>
+ <signal>clicked()</signal>
+ <receiver>MyDialog1</receiver>
+ <slot>reject()</slot>
+ </connection>
+ <connection>
+ <sender>generalizationCB</sender>
+ <signal>toggled(bool)</signal>
+ <receiver>generalizationEdgessSL</receiver>
+ <slot>setEnabled(bool)</slot>
+ </connection>
+ <connection>
+ <sender>associationEdgesCB</sender>
+ <signal>toggled(bool)</signal>
+ <receiver>associationEdgesSL</receiver>
+ <slot>setEnabled(bool)</slot>
+ </connection>
+ <connection>
+ <sender>dependenciesEdgesCB</sender>
+ <signal>toggled(bool)</signal>
+ <receiver>dependenciedEdgesSL</receiver>
+ <slot>setEnabled(bool)</slot>
+ </connection>
+ <connection>
+ <sender>shapeSeparationSB</sender>
+ <signal>valueChanged(int)</signal>
+ <receiver>MyDialog1</receiver>
+ <slot>slotSetShapeSeparation(int)</slot>
+ </connection>
+ <connection>
+ <sender>clusterizeHierarchiesCB</sender>
+ <signal>toggled(bool)</signal>
+ <receiver>MyDialog1</receiver>
+ <slot>slotSetClusterizeHierarchies(bool)</slot>
+ </connection>
+ <connection>
+ <sender>centerDiagramCB</sender>
+ <signal>toggled(bool)</signal>
+ <receiver>MyDialog1</receiver>
+ <slot>slotSetCenterDiagram(bool)</slot>
+ </connection>
+ <connection>
+ <sender>compressShapesCB</sender>
+ <signal>toggled(bool)</signal>
+ <receiver>MyDialog1</receiver>
+ <slot>slotSetCompressShapes(bool)</slot>
+ </connection>
+ <connection>
+ <sender>generalizationCB</sender>
+ <signal>toggled(bool)</signal>
+ <receiver>MyDialog1</receiver>
+ <slot>slotSetGenralizationAsEdges(bool)</slot>
+ </connection>
+ <connection>
+ <sender>generalizationEdgessSL</sender>
+ <signal>valueChanged(int)</signal>
+ <receiver>MyDialog1</receiver>
+ <slot>slotSetGeneralizationWeight(int)</slot>
+ </connection>
+ <connection>
+ <sender>associationEdgesCB</sender>
+ <signal>toggled(bool)</signal>
+ <receiver>MyDialog1</receiver>
+ <slot>slotSetAssociationAsEdges(bool)</slot>
+ </connection>
+ <connection>
+ <sender>associationEdgesSL</sender>
+ <signal>valueChanged(int)</signal>
+ <receiver>MyDialog1</receiver>
+ <slot>slotSetAssociationWeight(int)</slot>
+ </connection>
+ <connection>
+ <sender>dependenciesEdgesCB</sender>
+ <signal>toggled(bool)</signal>
+ <receiver>MyDialog1</receiver>
+ <slot>slotSetDependenciesAsEdges(bool)</slot>
+ </connection>
+ <connection>
+ <sender>dependenciedEdgesSL</sender>
+ <signal>valueChanged(int)</signal>
+ <receiver>MyDialog1</receiver>
+ <slot>slotSetDependenciesWeight(int)</slot>
+ </connection>
+ <connection>
+ <sender>buttonOk</sender>
+ <signal>clicked()</signal>
+ <receiver>MyDialog1</receiver>
+ <slot>slotDoAutolayout()</slot>
+ </connection>
+ <connection>
+ <sender>restoreDefaultsBTN</sender>
+ <signal>clicked()</signal>
+ <receiver>MyDialog1</receiver>
+ <slot>slotReloadSettings()</slot>
+ </connection>
+ <connection>
+ <sender>saveDefaultsBTN</sender>
+ <signal>clicked()</signal>
+ <receiver>MyDialog1</receiver>
+ <slot>slotSaveSettings()</slot>
+ </connection>
+ <connection>
+ <sender>algorithmCOB</sender>
+ <signal>textChanged(const QString&amp;)</signal>
+ <receiver>MyDialog1</receiver>
+ <slot>slotSelectAlgorithm(const QString&amp;)</slot>
+ </connection>
+</connections>
+<slots>
+ <slot>slotDoAutolayout()</slot>
+ <slot>slotSaveSettings()</slot>
+ <slot>slotReloadSettings()</slot>
+ <slot>slotSetClusterizeHierarchies(bool b)</slot>
+ <slot>slotSetAssociationWeight(int i)</slot>
+ <slot>slotSetDependenciesWeight(int i)</slot>
+ <slot>slotSetGeneralizationWeight(int i)</slot>
+ <slot>slotSetGenralizationAsEdges(bool b)</slot>
+ <slot>slotSetDependenciesAsEdges(bool b)</slot>
+ <slot>slotSetAssociationAsEdges(bool b)</slot>
+ <slot>slotSetCompressShapes(bool b)</slot>
+ <slot>slotSetCenterDiagram(bool b)</slot>
+ <slot>slotSetShapeSeparation(int i)</slot>
+ <slot specifier="pure virtual">slotSelectAlgorithm(const QString&amp;)</slot>
+</slots>
+<layoutdefaults spacing="6" margin="11"/>
+</UI>
diff --git a/umbrello/umbrello/autolayout/node.h b/umbrello/umbrello/autolayout/node.h
new file mode 100644
index 00000000..c2532b8b
--- /dev/null
+++ b/umbrello/umbrello/autolayout/node.h
@@ -0,0 +1,37 @@
+/*
+ * copyright (C) 2005
+ * Umbrello UML Modeller Authors <uml-devel @uml.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 AUTOLAYOUTNODE_H
+#define AUTOLAYOUTNODE_H
+
+namespace Autolayout {
+
+/**
+@author Umbrello UML Modeller Authors
+*/
+class Node{
+
+ //Node(Agnode_t* n);
+
+
+ //
+public:
+ virtual ~Node() {}
+ virtual int getX()=0;
+ virtual int getY()=0;
+
+
+};
+}
+#endif
diff --git a/umbrello/umbrello/autolayout/simplecanvas.cpp b/umbrello/umbrello/autolayout/simplecanvas.cpp
new file mode 100644
index 00000000..0598c15e
--- /dev/null
+++ b/umbrello/umbrello/autolayout/simplecanvas.cpp
@@ -0,0 +1,20 @@
+/*
+ * copyright (C) 2005
+ * Umbrello UML Modeller Authors <uml-devel @uml.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. *
+ * *
+ ***************************************************************************/
+#include "simplecanvas.h"
+
+namespace Autolayout {
+
+
+
+}
diff --git a/umbrello/umbrello/autolayout/simplecanvas.h b/umbrello/umbrello/autolayout/simplecanvas.h
new file mode 100644
index 00000000..41865f8a
--- /dev/null
+++ b/umbrello/umbrello/autolayout/simplecanvas.h
@@ -0,0 +1,39 @@
+/*
+ * copyright (C) 2005
+ * Umbrello UML Modeller Authors <uml-devel @uml.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 AUTOLAYOUTSIMPLECANVAS_H
+#define AUTOLAYOUTSIMPLECANVAS_H
+
+#include "canvas.h"
+#include <qrect.h>
+namespace Autolayout {
+
+/**
+@author Dimitri Ognibene <ognibened @yahoo.it>
+*/
+class SimpleCanvas: public Canvas
+{
+public:
+ SimpleCanvas(int i, int j):max_x(i),max_y(j){}
+ virtual ~SimpleCanvas() {}
+ virtual int getMaxX(){return max_x;}
+ virtual int getMaxY(){return max_y;}
+ virtual int getBaseX(){return 0;}
+ virtual int getBaseY(){return 0;}
+ int max_x,max_y;
+};
+
+}
+
+#endif
diff --git a/umbrello/umbrello/boxwidget.cpp b/umbrello/umbrello/boxwidget.cpp
new file mode 100644
index 00000000..e1cff3d9
--- /dev/null
+++ b/umbrello/umbrello/boxwidget.cpp
@@ -0,0 +1,44 @@
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * copyright (C) 2003-2006 *
+ * Umbrello UML Modeller Authors <uml-devel@uml.sf.net> *
+ ***************************************************************************/
+
+// own header
+#include "boxwidget.h"
+// qt/kde includes
+#include <qevent.h>
+#include <kdebug.h>
+
+BoxWidget::BoxWidget(UMLView * view, Uml::IDType id)
+ : UMLWidget(view, id) {
+ setSize(100,80);
+ UMLWidget::setBaseType( Uml::wt_Box );
+ WidgetBase::m_bUsesDiagramLineColour = false; // boxes be black
+ WidgetBase::m_LineColour = QColor("black");
+ setZ(m_origZ = 0);
+}
+
+BoxWidget::~BoxWidget() {
+}
+
+void BoxWidget::draw(QPainter& p, int offsetX, int offsetY) {
+ UMLWidget::setPen(p);
+ p.drawRect( offsetX, offsetY, width(), height() );
+
+ if (m_bSelected) {
+ drawSelected(&p, offsetX, offsetY);
+ }
+}
+
+void BoxWidget::saveToXMI(QDomDocument& qDoc, QDomElement& qElement) {
+ QDomElement boxElement = qDoc.createElement("boxwidget");
+ UMLWidget::saveToXMI(qDoc, boxElement);
+ qElement.appendChild(boxElement);
+}
+
diff --git a/umbrello/umbrello/boxwidget.h b/umbrello/umbrello/boxwidget.h
new file mode 100644
index 00000000..f412fee6
--- /dev/null
+++ b/umbrello/umbrello/boxwidget.h
@@ -0,0 +1,60 @@
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * copyright (C) 2003-2006 *
+ * Umbrello UML Modeller Authors <uml-devel@uml.sf.net> *
+ ***************************************************************************/
+
+#ifndef BOXWIDGET_H
+#define BOXWIDGET_H
+//qt includes
+#include <qpainter.h>
+//app includes
+#include "umlwidget.h"
+
+// fwd decl.
+class UMLView;
+
+/**
+ * Displays a rectangular box.
+ * These widgets are diagram specific. They will still need a unique id
+ * from the @ref UMLDoc class for deletion and other purposes.
+ *
+ * @short Displays a box.
+ * @author Jonathan Riddell
+ * @see UMLWidget
+ * Bugs and comments to uml-devel@lists.sf.net or http://bugs.kde.org
+ */
+class BoxWidget : public UMLWidget {
+public:
+
+ /**
+ * Constructs a BoxWidget.
+ *
+ * @param view The parent to this widget.
+ * @param id The ID to assign (-1 will prompt a new ID.)
+ */
+ explicit BoxWidget(UMLView * view, Uml::IDType id = Uml::id_None);
+
+ /**
+ * destructor
+ */
+ virtual ~BoxWidget();
+
+ /**
+ * Draws a rectangle.
+ */
+ void draw(QPainter & p, int offsetX, int offsetY);
+
+ /**
+ * Saves the widget to the "boxwidget" XMI element.
+ * Note: For loading from XMI, the inherited parent method is used.
+ */
+ void saveToXMI(QDomDocument& qDoc, QDomElement& qElement);
+};
+
+#endif
diff --git a/umbrello/umbrello/classifier.cpp b/umbrello/umbrello/classifier.cpp
new file mode 100644
index 00000000..22deee10
--- /dev/null
+++ b/umbrello/umbrello/classifier.cpp
@@ -0,0 +1,1023 @@
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * copyright (C) 2002-2007 *
+ * Umbrello UML Modeller Authors <uml-devel@uml.sf.net> *
+ ***************************************************************************/
+// own header
+#include "classifier.h"
+// qt/kde includes
+#include <kdebug.h>
+#include <klocale.h>
+#include <kmessagebox.h>
+// app includes
+#include "association.h"
+#include "umlassociationlist.h"
+#include "operation.h"
+#include "attribute.h"
+#include "template.h"
+#include "enumliteral.h"
+#include "entityattribute.h"
+#include "enum.h"
+#include "entity.h"
+#include "stereotype.h"
+#include "umldoc.h"
+#include "uml.h"
+#include "umllistview.h"
+#include "uniqueid.h"
+#include "object_factory.h"
+#include "model_utils.h"
+#include "clipboard/idchangelog.h"
+#include "dialogs/umloperationdialog.h"
+#include "dialogs/umlattributedialog.h"
+#include "dialogs/umltemplatedialog.h"
+#include "optionstate.h"
+
+using namespace Uml;
+
+UMLClassifier::UMLClassifier(const QString & name, Uml::IDType id)
+ : UMLPackage(name, id)
+{
+ init();
+}
+
+UMLClassifier::~UMLClassifier() {
+}
+
+void UMLClassifier::init() {
+ m_BaseType = Uml::ot_Class; // default value
+ m_pClassAssoc = NULL;
+ m_isRef = false;
+}
+
+void UMLClassifier::setBaseType(Uml::Object_Type ot) {
+ m_BaseType = ot;
+ Uml::Icon_Type newIcon;
+ switch (ot) {
+ case ot_Interface:
+ UMLObject::setStereotype("interface");
+ UMLObject::m_bAbstract = true;
+ newIcon = Uml::it_Interface;
+ break;
+ case ot_Class:
+ UMLObject::setStereotype(QString());
+ UMLObject::m_bAbstract = false;
+ newIcon = Uml::it_Class;
+ break;
+ case ot_Datatype:
+ UMLObject::setStereotype("datatype");
+ UMLObject::m_bAbstract = false;
+ newIcon = Uml::it_Datatype;
+ break;
+ default:
+ kError() << "UMLClassifier::setBaseType: cannot set to type "
+ << ot << endl;
+ return;
+ }
+ // @todo get rid of direct dependencies to UMLListView
+ // (e.g. move utility methods to Model_Utils and/or use signals)
+ UMLListView *listView = UMLApp::app()->getListView();
+ listView->changeIconOf(this, newIcon);
+}
+
+bool UMLClassifier::isInterface() const {
+ return (m_BaseType == ot_Interface);
+}
+
+bool UMLClassifier::isDatatype() const {
+ return (m_BaseType == ot_Datatype);
+}
+
+UMLOperation * UMLClassifier::checkOperationSignature(
+ const QString& name,
+ UMLAttributeList opParams,
+ UMLOperation *exemptOp)
+{
+ UMLOperationList list = findOperations(name);
+ if( list.count() == 0 )
+ return NULL;
+ const int inputParmCount = opParams.count();
+
+ // there is at least one operation with the same name... compare the parameter list
+ for (UMLOperationListIt oit(list); oit.current(); ++oit)
+ {
+ UMLOperation* test = oit.current();
+ if (test == exemptOp)
+ continue;
+ UMLAttributeList testParams = test->getParmList( );
+ const int pCount = testParams.count();
+ if( pCount != inputParmCount )
+ continue;
+ int i = 0;
+ while (i < pCount) {
+ // The only criterion for equivalence is the parameter types.
+ // (Default values are not considered.)
+ if( testParams.at(i)->getTypeName() != opParams.at(i)->getTypeName() )
+ break;
+ i++;
+ }
+ if( i == pCount )
+ {//all parameters matched -> the signature is not unique
+ return test;
+ }
+ }
+ // we did not find an exact match, so the signature is unique ( acceptable )
+ return NULL;
+}
+
+UMLOperation* UMLClassifier::findOperation(const QString& name,
+ Model_Utils::NameAndType_List params) {
+ UMLOperationList list = findOperations(name);
+ if (list.count() == 0)
+ return NULL;
+ // If there are operation(s) with the same name then compare the parameter list
+ const int inputParmCount = params.count();
+ UMLOperation* test = NULL;
+ for (UMLOperationListIt oit(list); (test = oit.current()) != NULL; ++oit) {
+ UMLAttributeList testParams = test->getParmList();
+ const int pCount = testParams.count();
+ if (inputParmCount == 0 && pCount == 0)
+ break;
+ if (inputParmCount != pCount)
+ continue;
+ int i = 0;
+ for (; i < pCount; ++i) {
+ Model_Utils::NameAndType_ListIt nt(params.at(i));
+ UMLClassifier *c = dynamic_cast<UMLClassifier*>((*nt).m_type);
+ UMLClassifier *testType = testParams.at(i)->getType();
+ if (c == NULL) { //template parameter
+ if (testType->getName() != "class")
+ break;
+ } else if (c != testType)
+ break;
+ }
+ if (i == pCount)
+ break; // all parameters matched
+ }
+ return test;
+}
+
+UMLOperation* UMLClassifier::createOperation(const QString &name /*=null*/,
+ bool *isExistingOp /*=NULL*/,
+ Model_Utils::NameAndType_List *params /*=NULL*/)
+{
+ bool nameNotSet = (name.isNull() || name.isEmpty());
+ if (! nameNotSet) {
+ Model_Utils::NameAndType_List parList;
+ if (params)
+ parList = *params;
+ UMLOperation* existingOp = findOperation(name, parList);
+ if (existingOp != NULL) {
+ if (isExistingOp != NULL)
+ *isExistingOp = true;
+ return existingOp;
+ }
+ }
+ // we did not find an exact match, so the signature is unique
+ UMLOperation *op = new UMLOperation(this, name);
+ if (params) {
+ for (Model_Utils::NameAndType_ListIt it = params->begin(); it != params->end(); ++it ) {
+ const Model_Utils::NameAndType &nt = *it;
+ UMLAttribute *par = new UMLAttribute(op, nt.m_name, Uml::id_None, Uml::Visibility::Private,
+ nt.m_type, nt.m_initialValue);
+ par->setParmKind(nt.m_direction);
+ op->addParm(par);
+ }
+ }
+ if (nameNotSet || params == NULL) {
+ if (nameNotSet)
+ op->setName( uniqChildName(Uml::ot_Operation) );
+ do {
+ UMLOperationDialog operationDialogue(0, op);
+ if( operationDialogue.exec() != QDialog::Accepted ) {
+ delete op;
+ return NULL;
+ } else if (checkOperationSignature(op->getName(), op->getParmList())) {
+ KMessageBox::information(0,
+ i18n("An operation with the same name and signature already exists. You can not add it again."));
+ } else {
+ break;
+ }
+ } while(1);
+ }
+
+ // operation name is ok, formally add it to the classifier
+ if (! addOperation(op)) {
+ delete op;
+ return NULL;
+ }
+
+ UMLDoc *umldoc = UMLApp::app()->getDocument();
+ umldoc->signalUMLObjectCreated(op);
+ return op;
+}
+
+bool UMLClassifier::addOperation(UMLOperation* op, int position )
+{
+ if (m_List.findRef(op) != -1) {
+ kDebug() << "UMLClassifier::addOperation: findRef("
+ << op->getName() << ") finds op (bad)"
+ << endl;
+ return false;
+ }
+ if (checkOperationSignature(op->getName(), op->getParmList()) ) {
+ kDebug() << "UMLClassifier::addOperation: checkOperationSignature("
+ << op->getName() << ") op is non-unique" << endl;
+ return false;
+ }
+
+ if( position >= 0 && position <= (int)m_List.count() ) {
+ kDebug() << "UMLClassifier::addOperation(" << op->getName()
+ << "): inserting at position " << position << endl;
+ m_List.insert(position,op);
+ UMLClassifierListItemList itemList = getFilteredList(Uml::ot_Operation);
+ UMLClassifierListItem* currentAtt;
+ QString buf;
+ for (UMLClassifierListItemListIt it0(itemList); (currentAtt = it0.current()); ++it0)
+ buf.append(' ' + currentAtt->getName());
+ kDebug() << " UMLClassifier::addOperation list after change: " << buf << endl;
+ } else
+ m_List.append( op );
+ emit operationAdded(op);
+ UMLObject::emitModified();
+ connect(op,SIGNAL(modified()),this,SIGNAL(modified()));
+ return true;
+}
+
+bool UMLClassifier::addOperation(UMLOperation* Op, IDChangeLog* Log) {
+ if( addOperation( Op, -1 ) )
+ return true;
+ else if( Log ) {
+ Log->removeChangeByNewID( Op -> getID() );
+ }
+ return false;
+}
+
+int UMLClassifier::removeOperation(UMLOperation *op) {
+ if (op == NULL) {
+ kDebug() << "UMLClassifier::removeOperation called on NULL op"
+ << endl;
+ return -1;
+ }
+ if(!m_List.remove(op)) {
+ kDebug() << "UMLClassifier::removeOperation: can't find op "
+ << op->getName() << " in list" << endl;
+ return -1;
+ }
+ // disconnection needed.
+ // note that we don't delete the operation, just remove it from the Classifier
+ disconnect(op,SIGNAL(modified()),this,SIGNAL(modified()));
+ emit operationRemoved(op);
+ UMLObject::emitModified();
+ return m_List.count();
+}
+
+UMLObject* UMLClassifier::createTemplate(const QString& currentName /*= QString()*/) {
+ QString name = currentName;
+ bool goodName = !name.isEmpty();
+ if (!goodName)
+ name = uniqChildName(Uml::ot_Template);
+ UMLTemplate* newTemplate = new UMLTemplate(this, name);
+
+ int button = QDialog::Accepted;
+
+ while (button==QDialog::Accepted && !goodName) {
+ UMLTemplateDialog templateDialogue(0, newTemplate);
+ button = templateDialogue.exec();
+ name = newTemplate->getName();
+
+ if(name.length() == 0) {
+ KMessageBox::error(0, i18n("That is an invalid name."), i18n("Invalid Name"));
+ } else if ( findChildObject(name) != NULL ) {
+ KMessageBox::error(0, i18n("That name is already being used."), i18n("Not a Unique Name"));
+ } else {
+ goodName = true;
+ }
+ }
+
+ if (button != QDialog::Accepted) {
+ return NULL;
+ }
+
+ addTemplate(newTemplate);
+
+ UMLDoc *umldoc = UMLApp::app()->getDocument();
+ umldoc->signalUMLObjectCreated(newTemplate);
+ return newTemplate;
+}
+
+int UMLClassifier::attributes() {
+ UMLClassifierListItemList atts = getFilteredList(Uml::ot_Attribute);
+ return atts.count();
+}
+
+UMLAttributeList UMLClassifier::getAttributeList() const{
+ UMLAttributeList attributeList;
+ for (UMLObjectListIt lit(m_List); lit.current(); ++lit) {
+ UMLObject *listItem = lit.current();
+ if (listItem->getBaseType() == Uml::ot_Attribute) {
+ attributeList.append(static_cast<UMLAttribute*>(listItem));
+ }
+ }
+ return attributeList;
+}
+
+UMLOperationList UMLClassifier::findOperations(const QString &n) {
+ const bool caseSensitive = UMLApp::app()->activeLanguageIsCaseSensitive();
+ UMLOperationList list;
+ for (UMLObjectListIt lit(m_List); lit.current(); ++lit) {
+ UMLObject* obj = lit.current();
+ if (obj->getBaseType() != Uml::ot_Operation)
+ continue;
+ UMLOperation *op = static_cast<UMLOperation*>(obj);
+ if (caseSensitive) {
+ if (obj->getName() == n)
+ list.append(op);
+ } else if (obj->getName().lower() == n.lower()) {
+ list.append(op);
+ }
+ }
+ return list;
+}
+
+UMLObject* UMLClassifier::findChildObjectById(Uml::IDType id, bool considerAncestors /* =false */) {
+ UMLObject *o = UMLCanvasObject::findChildObjectById(id);
+ if (o)
+ return o;
+ if (considerAncestors) {
+ UMLClassifierList ancestors = findSuperClassConcepts();
+ for (UMLClassifier *anc = ancestors.first(); anc; anc = ancestors.next()) {
+ UMLObject *o = anc->findChildObjectById(id);
+ if (o)
+ return o;
+ }
+ }
+ return NULL;
+}
+
+UMLClassifierList UMLClassifier::findSubClassConcepts (ClassifierType type) {
+ UMLClassifierList list = getSubClasses();
+ UMLAssociationList rlist = getRealizations();
+
+ UMLClassifierList inheritingConcepts;
+ Uml::IDType myID = getID();
+ for (UMLClassifier *c = list.first(); c; c = list.next())
+ {
+ if (type == ALL || (!c->isInterface() && type == CLASS)
+ || (c->isInterface() && type == INTERFACE))
+ inheritingConcepts.append(c);
+ }
+
+ for (UMLAssociation *a = rlist.first(); a; a = rlist.next())
+ {
+ if (a->getObjectId(A) != myID)
+ {
+ UMLObject* obj = a->getObject(A);
+ UMLClassifier *concept = dynamic_cast<UMLClassifier*>(obj);
+ if (concept && (type == ALL || (!concept->isInterface() && type == CLASS)
+ || (concept->isInterface() && type == INTERFACE))
+ && (inheritingConcepts.findRef(concept) == -1))
+ inheritingConcepts.append(concept);
+ }
+ }
+
+ return inheritingConcepts;
+}
+
+UMLClassifierList UMLClassifier::findSuperClassConcepts (ClassifierType type) {
+ UMLClassifierList list = getSuperClasses();
+ UMLAssociationList rlist = getRealizations();
+
+ UMLClassifierList parentConcepts;
+ Uml::IDType myID = getID();
+ for (UMLClassifier *concept = list.first(); concept; concept = list.next())
+ {
+ if (type == ALL || (!concept->isInterface() && type == CLASS)
+ || (concept->isInterface() && type == INTERFACE))
+ parentConcepts.append(concept);
+ }
+
+ for (UMLAssociation *a = rlist.first(); a; a = rlist.next())
+ {
+ if (a->getObjectId(A) == myID)
+ {
+ UMLObject* obj = a->getObject(B);
+ UMLClassifier *concept = dynamic_cast<UMLClassifier*>(obj);
+ if (concept && (type == ALL || (!concept->isInterface() && type == CLASS)
+ || (concept->isInterface() && type == INTERFACE))
+ && (parentConcepts.findRef(concept) == -1))
+ parentConcepts.append(concept);
+ }
+ }
+
+ return parentConcepts;
+}
+
+bool UMLClassifier::operator==( UMLClassifier & rhs ) {
+ /*
+ if ( m_List.count() != rhs.m_List.count() ) {
+ return false;
+ }
+ if ( &m_List != &(rhs.m_List) ) {
+ return false;
+ }
+ */
+ return UMLCanvasObject::operator==(rhs);
+}
+
+
+void UMLClassifier::copyInto(UMLClassifier *rhs) const
+{
+ UMLCanvasObject::copyInto(rhs);
+ rhs->setBaseType(m_BaseType);
+ // CHECK: association property m_pClassAssoc is not copied
+ m_List.copyInto(&(rhs->m_List));
+}
+
+UMLObject* UMLClassifier::clone() const {
+ UMLClassifier *clone = new UMLClassifier();
+ copyInto(clone);
+ return clone;
+}
+
+bool UMLClassifier::resolveRef() {
+ bool success = UMLPackage::resolveRef();
+ // Using reentrant iteration is a bare necessity here:
+ for (UMLObjectListIt oit(m_List); oit.current(); ++oit) {
+ UMLObject* obj = oit.current();
+ /**** For reference, here is the non-reentrant iteration scheme -
+ DO NOT USE THIS !
+ for (UMLObject *obj = m_List.first(); obj; obj = m_List.next())
+ { .... }
+ ****/
+ if (obj->resolveRef()) {
+ UMLClassifierListItem *cli = static_cast<UMLClassifierListItem*>(obj);
+ switch (cli->getBaseType()) {
+ case Uml::ot_Attribute:
+ emit attributeAdded(cli);
+ break;
+ case Uml::ot_Operation:
+ emit operationAdded(cli);
+ break;
+ case Uml::ot_Template:
+ emit templateAdded(cli);
+ break;
+ default:
+ break;
+ }
+ }
+ }
+ return success;
+}
+
+bool UMLClassifier::acceptAssociationType(Uml::Association_Type type)
+{
+ switch(type)
+ {
+ case at_Generalization:
+ case at_Aggregation:
+ case at_Relationship:
+ case at_Dependency:
+ case at_Association:
+ case at_Association_Self:
+ case at_Containment:
+ case at_Composition:
+ case at_Realization:
+ case at_UniAssociation:
+ return true;
+ default:
+ return false;
+ }
+ return false; //shutup compiler warning
+}
+
+UMLAttribute* UMLClassifier::createAttribute(const QString &name,
+ UMLObject *type,
+ Uml::Visibility vis,
+ const QString &init) {
+ Uml::IDType id = UniqueID::gen();
+ QString currentName;
+ if (name.isNull()) {
+ currentName = uniqChildName(Uml::ot_Attribute);
+ } else {
+ currentName = name;
+ }
+ UMLAttribute* newAttribute = new UMLAttribute(this, currentName, id, vis, type, init);
+
+ int button = QDialog::Accepted;
+ bool goodName = false;
+
+ //check for name.isNull() stops dialog being shown
+ //when creating attribute via list view
+ while (button == QDialog::Accepted && !goodName && name.isNull()) {
+ UMLAttributeDialog attributeDialogue(0, newAttribute);
+ button = attributeDialogue.exec();
+ QString name = newAttribute->getName();
+
+ if(name.length() == 0) {
+ KMessageBox::error(0, i18n("That is an invalid name."), i18n("Invalid Name"));
+ } else if ( findChildObject(name) != NULL ) {
+ KMessageBox::error(0, i18n("That name is already being used."), i18n("Not a Unique Name"));
+ } else {
+ goodName = true;
+ }
+ }
+
+ if (button != QDialog::Accepted) {
+ delete newAttribute;
+ return NULL;
+ }
+
+ addAttribute(newAttribute);
+
+ UMLDoc *umldoc = UMLApp::app()->getDocument();
+ umldoc->signalUMLObjectCreated(newAttribute);
+ return newAttribute;
+}
+
+UMLAttribute* UMLClassifier::addAttribute(const QString &name, Uml::IDType id /* = Uml::id_None */) {
+ for (UMLObjectListIt lit(m_List); lit.current(); ++lit) {
+ UMLObject *obj = lit.current();
+ if (obj->getBaseType() == Uml::ot_Attribute && obj->getName() == name)
+ return static_cast<UMLAttribute*>(obj);
+ }
+ Uml::Visibility scope = Settings::getOptionState().classState.defaultAttributeScope;
+ UMLAttribute *a = new UMLAttribute(this, name, id, scope);
+ m_List.append(a);
+ emit attributeAdded(a);
+ UMLObject::emitModified();
+ connect(a,SIGNAL(modified()),this,SIGNAL(modified()));
+ return a;
+}
+
+UMLAttribute* UMLClassifier::addAttribute(const QString &name, UMLObject *type, Uml::Visibility scope) {
+ UMLAttribute *a = new UMLAttribute(this);
+ a->setName(name);
+ a->setVisibility(scope);
+ a->setID(UniqueID::gen());
+ if (type)
+ a->setType(type);
+ m_List.append(a);
+ emit attributeAdded(a);
+ UMLObject::emitModified();
+ connect(a,SIGNAL(modified()),this,SIGNAL(modified()));
+ return a;
+}
+
+bool UMLClassifier::addAttribute(UMLAttribute* att, IDChangeLog* Log /* = 0 */,
+ int position /* = -1 */) {
+ if (findChildObject(att->getName()) == NULL) {
+ att->parent()->removeChild( att );
+ this->insertChild( att );
+ if (position >= 0 && position < (int)m_List.count())
+ m_List.insert(position, att);
+ else
+ m_List.append(att);
+ emit attributeAdded(att);
+ UMLObject::emitModified();
+ connect(att, SIGNAL(modified()), this, SIGNAL(modified()));
+ return true;
+ } else if (Log) {
+ Log->removeChangeByNewID(att->getID());
+ delete att;
+ }
+ return false;
+}
+
+int UMLClassifier::removeAttribute(UMLAttribute* a) {
+ if (!m_List.remove(a)) {
+ kDebug() << "can't find att given in list" << endl;
+ return -1;
+ }
+ emit attributeRemoved(a);
+ UMLObject::emitModified();
+ // If we are deleting the object, then we don't need to disconnect..this is done auto-magically
+ // for us by QObject. -b.t.
+ // disconnect(a,SIGNAL(modified()),this,SIGNAL(modified()));
+ delete a;
+ return m_List.count();
+}
+
+
+void UMLClassifier::setClassAssoc(UMLAssociation *assoc) {
+ m_pClassAssoc = assoc;
+}
+
+UMLAssociation *UMLClassifier::getClassAssoc() const{
+ return m_pClassAssoc;
+}
+
+bool UMLClassifier::hasAbstractOps () {
+ UMLOperationList opl( getOpList() );
+ for(UMLOperation *op = opl.first(); op ; op = opl.next())
+ if(op->getAbstract())
+ return true;
+ return false;
+}
+
+int UMLClassifier::operations() {
+ return getOpList().count();
+}
+
+UMLOperationList UMLClassifier::getOpList(bool includeInherited) {
+ UMLOperationList ops;
+ for (UMLObjectListIt lit(m_List); lit.current(); ++lit) {
+ UMLObject *li = lit.current();
+ if (li->getBaseType() == ot_Operation)
+ ops.append(static_cast<UMLOperation*>(li));
+ }
+ if (includeInherited) {
+ UMLClassifierList parents = findSuperClassConcepts();
+ UMLClassifier *c;
+ for (UMLClassifierListIt pit(parents); (c = pit.current()) != NULL; ++pit) {
+ if (c == this) {
+ kError() << "UMLClassifier::getOpList: class " << c->getName()
+ << " is parent of itself ?!?" << endl;
+ continue;
+ }
+ // get operations for each parent by recursive call
+ UMLOperationList pops = c->getOpList(true);
+ // add these operations to operation list, but only if unique.
+ for (UMLOperation *po = pops.first(); po; po = pops.next()) {
+ QString po_as_string(po->toString(Uml::st_SigNoVis));
+ UMLOperation *o = NULL;
+ for (o = ops.first(); o; o = ops.next())
+ if (o->toString(Uml::st_SigNoVis) == po_as_string)
+ break;
+ if (!o)
+ ops.append(po);
+ }
+ }
+ }
+ return ops;
+}
+
+UMLClassifierListItemList UMLClassifier::getFilteredList(Uml::Object_Type ot) const {
+ UMLClassifierListItemList resultList;
+ UMLObject *o;
+ for (UMLObjectListIt lit(m_List); (o = lit.current()) != NULL; ++lit) {
+ if (o->getBaseType() == Uml::ot_Association)
+ continue;
+ UMLClassifierListItem *listItem = static_cast<UMLClassifierListItem*>(o);
+ if (ot == Uml::ot_UMLObject || listItem->getBaseType() == ot)
+ resultList.append(listItem);
+ }
+ return resultList;
+}
+
+UMLTemplate* UMLClassifier::addTemplate(const QString &name, Uml::IDType id) {
+ UMLTemplate *t = findTemplate(name);
+ if (t)
+ return t;
+ t = new UMLTemplate(this, name, id);
+ m_List.append(t);
+ emit templateAdded(t);
+ UMLObject::emitModified();
+ connect(t, SIGNAL(modified()), this, SIGNAL(modified()));
+ return t;
+}
+
+bool UMLClassifier::addTemplate(UMLTemplate* newTemplate, IDChangeLog* log /* = 0*/) {
+ QString name = newTemplate->getName();
+ if (findChildObject(name) == NULL) {
+ newTemplate->parent()->removeChild(newTemplate);
+ this->insertChild(newTemplate);
+ m_List.append(newTemplate);
+ emit templateAdded(newTemplate);
+ UMLObject::emitModified();
+ connect(newTemplate,SIGNAL(modified()),this,SIGNAL(modified()));
+ return true;
+ } else if (log) {
+ log->removeChangeByNewID( newTemplate->getID() );
+ delete newTemplate;
+ }
+ return false;
+}
+
+bool UMLClassifier::addTemplate(UMLTemplate* Template, int position)
+{
+ QString name = Template->getName();
+ if (findChildObject(name) == NULL) {
+ Template->parent()->removeChild(Template);
+ this->insertChild(Template);
+ if( position >= 0 && position <= (int)m_List.count() )
+ m_List.insert(position,Template);
+ else
+ m_List.append(Template);
+ emit templateAdded(Template);
+ UMLObject::emitModified();
+ connect(Template,SIGNAL(modified()),this,SIGNAL(modified()));
+ return true;
+ }
+ //else
+ return false;
+}
+
+int UMLClassifier::removeTemplate(UMLTemplate* umltemplate) {
+ if ( !m_List.remove(umltemplate) ) {
+ kWarning() << "can't find att given in list" << endl;
+ return -1;
+ }
+ emit templateRemoved(umltemplate);
+ UMLObject::emitModified();
+ disconnect(umltemplate,SIGNAL(modified()),this,SIGNAL(modified()));
+ return m_List.count();
+}
+
+
+UMLTemplate *UMLClassifier::findTemplate(const QString& name) {
+ UMLTemplateList templParams = getTemplateList();
+ for (UMLTemplate *t = templParams.first(); t; t = templParams.next()) {
+ if (t->getName() == name)
+ return t;
+ }
+ return NULL;
+}
+
+int UMLClassifier::templates() {
+ UMLClassifierListItemList tempList = getFilteredList(Uml::ot_Template);
+ return tempList.count();
+}
+
+UMLTemplateList UMLClassifier::getTemplateList() const {
+ UMLTemplateList templateList;
+ for (UMLObjectListIt lit(m_List); lit.current(); ++lit) {
+ UMLObject *listItem = lit.current();
+ if (listItem->getBaseType() == Uml::ot_Template) {
+ templateList.append(static_cast<UMLTemplate*>(listItem));
+ }
+ }
+ return templateList;
+}
+
+int UMLClassifier::takeItem(UMLClassifierListItem *item) {
+ UMLObject* currentAtt;
+ QString buf;
+ for (UMLObjectListIt it0(m_List);
+ (currentAtt = it0.current()); ++it0) {
+ QString txt = currentAtt->getName();
+ if (txt.isEmpty())
+ txt = "Type-" + QString::number((int) currentAtt->getBaseType());
+ buf.append(' ' + currentAtt->getName());
+ }
+ kDebug() << " UMLClassifier::takeItem (before): m_List is " << buf << endl;
+ int index = m_List.findRef(item);
+ if (index == -1)
+ return -1;
+ switch (item->getBaseType()) {
+ case Uml::ot_Operation: {
+ if (removeOperation(dynamic_cast<UMLOperation*>(item)) < 0)
+ index = -1;
+ break;
+ }
+ case Uml::ot_Attribute: {
+ UMLAttribute *retval = dynamic_cast<UMLAttribute*>(m_List.take());
+ if (retval) {
+ emit attributeRemoved(retval);
+ emit modified();
+ } else {
+ index = -1;
+ }
+ break;
+ }
+ case Uml::ot_Template: {
+ UMLTemplate *t = dynamic_cast<UMLTemplate*>(m_List.take());
+ if (t) {
+ emit templateRemoved(t);
+ emit modified();
+ } else {
+ index = -1;
+ }
+ break;
+ }
+ case Uml::ot_EnumLiteral: {
+ UMLEnumLiteral *el = dynamic_cast<UMLEnumLiteral*>(m_List.take());
+ if (el) {
+ UMLEnum *e = static_cast<UMLEnum*>(this);
+ e->signalEnumLiteralRemoved(el);
+ emit modified();
+ } else {
+ index = -1;
+ }
+ break;
+ }
+ case Uml::ot_EntityAttribute: {
+ UMLEntityAttribute* el = dynamic_cast<UMLEntityAttribute*>(m_List.take());
+ if (el) {
+ UMLEntity *e = static_cast<UMLEntity*>(this);
+ e->signalEntityAttributeRemoved(el);
+ emit modified();
+ } else {
+ index = -1;
+ }
+ break;
+ }
+ default:
+ index = -1;
+ break;
+ }
+ return index;
+}
+
+void UMLClassifier::setOriginType(UMLClassifier *origType) {
+ m_pSecondary = origType;
+}
+
+UMLClassifier * UMLClassifier::originType() const{
+ return static_cast<UMLClassifier*>(m_pSecondary);
+}
+
+void UMLClassifier::setIsReference(bool isRef) {
+ m_isRef = isRef;
+}
+
+bool UMLClassifier::isReference() const{
+ return m_isRef;
+}
+
+UMLAssociationList UMLClassifier::getUniAssociationToBeImplemented() {
+ UMLAssociationList associations = getSpecificAssocs(Uml::at_UniAssociation);
+ UMLAssociationList uniAssocListToBeImplemented;
+
+ for(UMLAssociation *a = associations.first(); a; a = associations.next()) {
+ if (a->getObjectId(Uml::B) == getID())
+ continue; // we need to be at the A side
+
+ QString roleNameB = a->getRoleName(Uml::B);
+ if (!roleNameB.isEmpty()) {
+ UMLAttributeList atl = getAttributeList();
+ bool found = false;
+ //make sure that an attribute with the same name doesn't already exist
+ for (UMLAttribute *at = atl.first(); at ; at = atl.next()) {
+ if (at->getName() == roleNameB) {
+ found = true;
+ break;
+ }
+ }
+ if (!found) {
+ uniAssocListToBeImplemented.append(a);
+ }
+ }
+ }
+ return uniAssocListToBeImplemented;
+}
+
+void UMLClassifier::saveToXMI(QDomDocument & qDoc, QDomElement & qElement) {
+ QString tag;
+ switch (m_BaseType) {
+ case Uml::ot_Class:
+ tag = "UML:Class";
+ break;
+ case Uml::ot_Interface:
+ tag = "UML:Interface";
+ break;
+ case Uml::ot_Datatype:
+ tag = "UML:DataType";
+ break;
+ default:
+ kError() << "UMLClassifier::saveToXMI() internal error: basetype is "
+ << m_BaseType << endl;
+ return;
+ }
+ QDomElement classifierElement = UMLObject::save(tag, qDoc);
+ if (m_BaseType == Uml::ot_Datatype && m_pSecondary != NULL)
+ classifierElement.setAttribute( "elementReference",
+ ID2STR(m_pSecondary->getID()) );
+
+ //save templates
+ UMLClassifierListItemList list = getFilteredList(Uml::ot_Template);
+ if (list.count()) {
+ QDomElement tmplElement = qDoc.createElement( "UML:ModelElement.templateParameter" );
+ for (UMLClassifierListItem *tmpl = list.first(); tmpl; tmpl = list.next() ) {
+ tmpl->saveToXMI(qDoc, tmplElement);
+ }
+ classifierElement.appendChild( tmplElement );
+ }
+
+ //save generalizations (we are the subclass, the other end is the superclass)
+ UMLAssociationList generalizations = getSpecificAssocs(Uml::at_Generalization);
+ if (generalizations.count()) {
+ QDomElement genElement = qDoc.createElement("UML:GeneralizableElement.generalization");
+ for (UMLAssociation *a = generalizations.first(); a; a = generalizations.next()) {
+ // We are the subclass if we are at the role A end.
+ if (m_nId != a->getObjectId(Uml::A))
+ continue;
+ QDomElement gElem = qDoc.createElement("UML:Generalization");
+ gElem.setAttribute( "xmi.idref", ID2STR(a->getID()) );
+ genElement.appendChild(gElem);
+ }
+ if (genElement.hasChildNodes())
+ classifierElement.appendChild( genElement );
+ }
+
+ // save attributes
+ QDomElement featureElement = qDoc.createElement( "UML:Classifier.feature" );
+ UMLClassifierListItemList attList = getFilteredList(Uml::ot_Attribute);
+ for (UMLClassifierListItem *pAtt = attList.first(); pAtt; pAtt = attList.next() )
+ pAtt -> saveToXMI( qDoc, featureElement );
+
+ // save operations
+ UMLOperationList opList = getOpList();
+ for (UMLOperation *pOp = opList.first(); pOp; pOp = opList.next() )
+ pOp -> saveToXMI( qDoc, featureElement );
+ if (featureElement.hasChildNodes())
+ classifierElement.appendChild( featureElement );
+
+ // save contained objects
+ if (m_objects.count()) {
+ QDomElement ownedElement = qDoc.createElement( "UML:Namespace.ownedElement" );
+ for (UMLObjectListIt oit(m_objects); oit.current(); ++oit) {
+ UMLObject *obj = oit.current();
+ obj->saveToXMI (qDoc, ownedElement);
+ }
+ classifierElement.appendChild( ownedElement );
+ }
+ qElement.appendChild( classifierElement );
+}
+
+UMLClassifierListItem* UMLClassifier::makeChildObject(const QString& xmiTag) {
+ UMLClassifierListItem* pObject = NULL;
+ if (tagEq(xmiTag, "Operation")) {
+ pObject = new UMLOperation(this);
+ } else if (tagEq(xmiTag, "Attribute")) {
+ if (getBaseType() != Uml::ot_Class)
+ return NULL;
+ pObject = new UMLAttribute(this);
+ } else if (tagEq(xmiTag, "TemplateParameter")) {
+ pObject = new UMLTemplate(this);
+ }
+ return pObject;
+}
+
+bool UMLClassifier::load(QDomElement& element) {
+ UMLClassifierListItem *child = NULL;
+ m_SecondaryId = element.attribute( "elementReference", "" );
+ if (!m_SecondaryId.isEmpty()) {
+ // @todo We do not currently support composition.
+ m_isRef = true;
+ }
+ bool totalSuccess = true;
+ for (QDomNode node = element.firstChild(); !node.isNull();
+ node = node.nextSibling()) {
+ if (node.isComment())
+ continue;
+ element = node.toElement();
+ QString tag = element.tagName();
+ if (tagEq(tag, "ModelElement.templateParameter") ||
+ tagEq(tag, "Classifier.feature") ||
+ tagEq(tag, "Namespace.ownedElement") ||
+ tagEq(tag, "Namespace.contents")) {
+ load(element);
+ // Not evaluating the return value from load()
+ // because we want a best effort.
+
+ } else if ((child = makeChildObject(tag)) != NULL) {
+ if (child->loadFromXMI(element)) {
+ switch (child->getBaseType()) {
+ case Uml::ot_Template:
+ addTemplate( static_cast<UMLTemplate*>(child) );
+ break;
+ case Uml::ot_Operation:
+ if (! addOperation(static_cast<UMLOperation*>(child)) ) {
+ kError() << "UMLClassifier::load: error from addOperation(op)"
+ << endl;
+ delete child;
+ totalSuccess = false;
+ }
+ break;
+ case Uml::ot_Attribute:
+ addAttribute( static_cast<UMLAttribute*>(child) );
+ break;
+ default:
+ break;
+ }
+ } else {
+ kWarning() << "UMLClassifier::load: failed to load " << tag << endl;
+ delete child;
+ totalSuccess = false;
+ }
+ } else if (!Model_Utils::isCommonXMIAttribute(tag)) {
+ UMLObject *pObject = Object_Factory::makeObjectFromXMI(tag);
+ if (pObject == NULL) {
+ // Not setting totalSuccess to false
+ // because we want a best effort.
+ continue;
+ }
+ pObject->setUMLPackage(this);
+ if (! pObject->loadFromXMI(element)) {
+ removeObject(pObject);
+ delete pObject;
+ totalSuccess = false;
+ }
+ }
+ }
+ return totalSuccess;
+}
+
+
+
+#include "classifier.moc"
diff --git a/umbrello/umbrello/classifier.h b/umbrello/umbrello/classifier.h
new file mode 100644
index 00000000..c599fe16
--- /dev/null
+++ b/umbrello/umbrello/classifier.h
@@ -0,0 +1,496 @@
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * copyright (C) 2002-2007 *
+ * Umbrello UML Modeller Authors <uml-devel@uml.sf.net> *
+ ***************************************************************************/
+
+#ifndef CLASSIFIER__H
+#define CLASSIFIER__H
+
+#include "package.h"
+#include "umlattributelist.h"
+#include "umloperationlist.h"
+#include "umlclassifierlistitemlist.h"
+#include "classifierlistitem.h"
+#include "umltemplatelist.h"
+#include "model_utils.h"
+
+// forward declarations
+class UMLAssociation;
+class IDChangeLog;
+
+/**
+ * This class defines the non-graphical information required for a
+ * UML Classifier (ie a class or interface).
+ * This class inherits from @ref UMLPackage which allows classifiers
+ * to also act as namespaces, i.e. it allows classifiers to nest.
+ *
+ * @short Information for a non-graphical Concept/Class.
+ * @author Paul Hensgen <phensgen@techie.com>
+ * Bugs and comments to uml-devel@lists.sf.net or http://bugs.kde.org
+ */
+
+class UMLClassifier : public UMLPackage {
+ Q_OBJECT
+public:
+
+ /**
+ * Enumeration identifying the type of classifier.
+ */
+ enum ClassifierType { ALL = 0, CLASS, INTERFACE, DATATYPE };
+
+
+ /**
+ * Sets up a Concept.
+ *
+ * @param name The name of the Concept.
+ * @param id The unique id of the Concept.
+ */
+ explicit UMLClassifier(const QString & name = "", Uml::IDType id = Uml::id_None);
+
+ /**
+ * Standard deconstructor.
+ */
+ virtual ~UMLClassifier();
+
+ /**
+ * Overloaded '==' operator.
+ */
+ bool operator==( UMLClassifier & rhs );
+
+ /**
+ * Copy the internal presentation of this object into the new
+ * object.
+ */
+ virtual void copyInto(UMLClassifier *rhs) const;
+
+ /**
+ * Make a clone of this object.
+ */
+ UMLObject* clone() const;
+
+ /**
+ * Creates an attribute for the class.
+ *
+ * @param name An optional name, used by when creating through UMLListView
+ * @param type An optional type, used by when creating through UMLListView
+ * @param vis An optional visibility, used by when creating through UMLListView
+ * @param init An optional initial value, used by when creating through UMLListView
+ * @return The UMLAttribute created
+ */
+ virtual UMLAttribute* createAttribute(const QString &name = QString::null,
+ UMLObject *type = 0,
+ Uml::Visibility vis = Uml::Visibility::Private,
+ const QString &init = QString::null);
+
+ /**
+ * Adds an attribute to the class.
+ * If an attribute of the given name already exists, then
+ * returns the existing attribute instead of creating a new one.
+ *
+ * @param name The name of the attribute.
+ * @param id The id of the attribute (optional.)
+ * If not given, and the attribute name
+ * does not already exist, then the method
+ * will internally assign a new ID.
+ * @return Pointer to the UMLAttribute created or found.
+ */
+ UMLAttribute* addAttribute(const QString &name, Uml::IDType id = Uml::id_None);
+
+ UMLAttribute* addAttribute(const QString &name, UMLObject *type, Uml::Visibility scope);
+
+ /**
+ * Adds an already created attribute.
+ * The attribute object must not belong to any other concept.
+ *
+ * @param Att Pointer to the UMLAttribute.
+ * @param Log Pointer to the IDChangeLog (optional.)
+ * @param position Position index for the insertion (optional.)
+ * If the position is omitted, or if it is
+ * negative or too large, the attribute is added
+ * to the end of the list.
+ * @return True if the attribute was successfully added.
+ */
+ bool addAttribute(UMLAttribute* Att, IDChangeLog* Log = 0,
+ int position = -1);
+
+ /**
+ * Removes an attribute from the class.
+ *
+ * @param a The attribute to remove.
+ * @return Count of the remaining attributes after removal.
+ * Returns -1 if the given attribute was not found.
+ */
+ int removeAttribute(UMLAttribute *a);
+
+ /**
+ * Returns the number of attributes for the class.
+ *
+ * @return The number of attributes for the class.
+ */
+ int attributes() ;
+
+ /**
+ * Returns the attributes.
+ * Same as UMLClassifier::getFilteredList(ot_Attribute) but
+ * return type is a true UMLAttributeList.
+ *
+ * @return List of true attributes for the class.
+ */
+ UMLAttributeList getAttributeList() const;
+
+ /**
+ * Creates an operation in the current document.
+ * The new operation is initialized with name, id, etc.
+ * If a method with the given profile already exists in the classifier,
+ * no new method is created and the existing operation is returned.
+ * If no name is provided, or if the params are NULL, an Operation
+ * Dialog is shown to ask the user for a name and parameters.
+ * The operation's signature is checked for validity within the parent
+ * classifier.
+ *
+ * @param name The operation name (will be chosen internally if
+ * none given.)
+ * @param isExistingOp Optional pointer to bool. If supplied, the bool is
+ * set to true if an existing operation is returned.
+ * @param params Optional list of parameter names and types.
+ * If supplied, new operation parameters are
+ * constructed using this list.
+ * @return The new operation, or NULL if the operation could not be
+ * created because for example, the user canceled the dialog
+ * or no appropriate name can be found.
+ */
+ UMLOperation* createOperation( const QString &name = QString::null,
+ bool *isExistingOp = NULL,
+ Model_Utils::NameAndType_List *params = NULL);
+
+ /**
+ * Adds an operation to the classifier, at the given position.
+ * If position is negative or too large, the attribute is added
+ * to the end of the list.
+ * The Classifier first checks and only adds the Operation if the
+ * signature does not conflict with exising operations
+ *
+ * @param Op Pointer to the UMLOperation to add.
+ * @param position Index at which to insert into the list.
+ * @return true if the Operation could be added to the Classifier.
+ */
+ bool addOperation(UMLOperation* Op, int position = -1);
+
+ /**
+ * Appends an operation to the classifier.
+ * @see bool addOperation(UMLOperation* Op, int position = -1)
+ * This function is mainly intended for the clipboard.
+ *
+ * @param Op Pointer to the UMLOperation to add.
+ * @param Log Pointer to the IDChangeLog.
+ * @return True if the operation was added successfully.
+ */
+ bool addOperation(UMLOperation* Op, IDChangeLog* Log);
+
+ /**
+ * Checks whether an operation is valid based on its signature -
+ * An operation is "valid" if the operation's name and parameter list
+ * are unique in the classifier.
+ *
+ * @param name Name of the operation to check.
+ * @param opParams The operation's argument list.
+ * @param exemptOp Pointer to the exempt method (optional.)
+ * @return NULL if the signature is valid (ok), else return a pointer
+ * to the existing UMLOperation that causes the conflict.
+ */
+ UMLOperation * checkOperationSignature( const QString& name,
+ UMLAttributeList opParams,
+ UMLOperation *exemptOp = NULL);
+
+ /**
+ * Remove an operation from the Classifier.
+ * The operation is not deleted so the caller is responsible for what
+ * happens to it after this.
+ *
+ * @param op The operation to remove.
+ * @return Count of the remaining operations after removal, or
+ * -1 if the given operation was not found.
+ */
+ int removeOperation(UMLOperation *op);
+
+ /**
+ * counts the number of operations in the Classifier.
+ *
+ * @return The number of operations for the Classifier.
+ */
+ int operations() ;
+
+ /**
+ * Return a list of operations for the Classifier.
+ * @param includeInherited Includes operations from superclasses.
+ *
+ * @return The list of operations for the Classifier.
+ */
+ UMLOperationList getOpList(bool includeInherited = false);
+
+ /**
+ * Creates a template for the concept.
+ *
+ * @return The UMLTemplate created
+ */
+ UMLObject* createTemplate(const QString& name = QString::null);
+
+ /**
+ * Adds a template to the class if it is not there yet.
+ *
+ * @param name The name of the template.
+ * @param id The id of the template.
+ * @return Pointer to the UMLTemplate object created.
+ */
+ UMLTemplate* addTemplate(const QString &name, Uml::IDType id = Uml::id_None);
+
+ /**
+ * Adds an already created template.
+ * The template object must not belong to any other concept.
+ *
+ * @param newTemplate Pointer to the UMLTemplate object to add.
+ * @param log Pointer to the IDChangeLog.
+ * @return True if the template was successfully added.
+ */
+ bool addTemplate(UMLTemplate* newTemplate, IDChangeLog* log = 0);
+
+ /**
+ * Adds an template to the class.
+ * The template object must not belong to any other class.
+ *
+ * @param Template Pointer to the UMLTemplate to add.
+ * @param position The position of the template in the list.
+ * A value of -1 will add the template at the end.
+ * @return True if the template was successfully added.
+ */
+ //TODO: if the param IDChangeLog from the method above is not being used,
+ // give position a default value of -1 and the method can replace the above one
+ bool addTemplate(UMLTemplate* Template, int position);
+
+ /**
+ * Removes a template from the class.
+ *
+ * @param umltemplate The template to remove.
+ * @return Count of the remaining templates after removal.
+ * Returns -1 if the given template was not found.
+ */
+ int removeTemplate(UMLTemplate* umltemplate);
+
+ /**
+ * Seeks the template parameter of the given name.
+ */
+ UMLTemplate *findTemplate(const QString& name);
+
+ /**
+ * Returns the number of templates for the class.
+ *
+ * @return The number of templates for the class.
+ */
+ int templates();
+
+ /**
+ * Returns the templates.
+ * Same as UMLClassifier::getFilteredList(ot_Template) but
+ * return type is a true UMLTemplateList.
+ *
+ * @return Pointer to the list of true templates for the class.
+ */
+ UMLTemplateList getTemplateList() const;
+
+ /**
+ * Take and return a subordinate item from this classifier.
+ * Ownership of the item is passed to the caller.
+ *
+ * @param item Subordinate item to take.
+ * @return Index in m_List of the item taken.
+ * Return -1 if the item is not found in m_List.
+ */
+ int takeItem(UMLClassifierListItem* item);
+
+ /**
+ * Returns the entries in m_List that are of the requested type.
+ * If the requested type is Uml::ot_UMLObject then all entries
+ * are returned.
+ *
+ * @return The list of true operations for the Concept.
+ */
+ virtual UMLClassifierListItemList getFilteredList(Uml::Object_Type ot) const;
+
+ /**
+ * Needs to be called after all UML objects are loaded from file.
+ * Calls the parent resolveRef(), and calls resolveRef() on all
+ * UMLClassifierListItems.
+ * Overrides the method from UMLObject.
+ *
+ * @return true for success.
+ */
+ virtual bool resolveRef();
+
+ /**
+ * Find a list of operations with the given name.
+ *
+ * @param n The name of the operation to find.
+ * @return The list of objects found; will be empty if none found.
+ */
+ UMLOperationList findOperations(const QString &n);
+
+ /**
+ * Find an attribute, operation, association or template.
+ *
+ * @param id The id of the object to find.
+ *
+ * @return The object found. Will return 0 if none found.
+ */
+ virtual UMLObject* findChildObjectById(Uml::IDType id, bool considerAncestors = false);
+
+ /**
+ * Find an operation of the given name and parameter signature.
+ *
+ * @param name The name of the operation to find.
+ * @param params The parameter descriptors of the operation to find.
+ *
+ * @return The operation found. Will return 0 if none found.
+ */
+ UMLOperation* findOperation(const QString& name,
+ Model_Utils::NameAndType_List params);
+
+ /**
+ * Returns a list of concepts which this concept inherits from.
+ *
+ * @param type The ClassifierType to seek.
+ * @return List of UMLClassifiers we inherit from.
+ */
+ UMLClassifierList findSuperClassConcepts(ClassifierType type = ALL);
+
+ /**
+ * Returns a list of concepts which inherit from this concept.
+ *
+ * @param type The ClassifierType to seek.
+ * @return List of UMLClassifiers that inherit from us.
+ */
+ UMLClassifierList findSubClassConcepts(ClassifierType type = ALL);
+
+ /** reimplemented from UMLObject */
+ virtual bool acceptAssociationType(Uml::Association_Type);
+
+ /**
+ * Sets the UMLAssociation for which this class shall act as an
+ * association class.
+ */
+ void setClassAssoc(UMLAssociation *assoc);
+
+ /**
+ * Returns the UMLAssociation for which this class acts as an
+ * association class. Returns NULL if this class does not act
+ * as an association class.
+ */
+ UMLAssociation *getClassAssoc() const;
+
+ /**
+ * Reimplementation of method from class UMLObject for controlling the
+ * exact type of this classifier: class, interface, or datatype.
+ */
+ void setBaseType(Uml::Object_Type ot);
+
+ /**
+ * Returns true if this classifier represents an interface.
+ */
+ bool isInterface() const;
+
+ /**
+ * Returns true if this classifier represents a datatype.
+ */
+ bool isDatatype() const;
+
+ /**
+ * Set the origin type (in case of e.g. typedef)
+ */
+ void setOriginType(UMLClassifier *origType);
+
+ /**
+ * Get the origin type (in case of e.g. typedef)
+ */
+ UMLClassifier * originType() const;
+
+ /**
+ * Set the m_isRef flag (true when dealing with a pointer type)
+ */
+ void setIsReference(bool isRef = true);
+
+ /**
+ * Get the m_isRef flag.
+ */
+ bool isReference() const;
+
+ /**
+ * Return true if this classifier has abstract operations.
+ */
+ bool hasAbstractOps ();
+
+ /**
+ * Create a new ClassifierListObject (attribute, operation, template)
+ * according to the given XMI tag.
+ * Returns NULL if the string given does not contain one of the tags
+ * <UML:Attribute>, <UML:Operation>, or <UML:TemplateParameter>.
+ * Used by the clipboard for paste operation.
+ */
+ UMLClassifierListItem* makeChildObject(const QString& xmiTag);
+
+ /**
+ * Return the list of unidirectional association that should show up in the code
+ */
+ virtual UMLAssociationList getUniAssociationToBeImplemented();
+
+signals:
+ /** Signals that a new UMLOperation has been added to the classifer.
+ */
+ void operationAdded(UMLClassifierListItem *);
+
+ /** Signals that a UMLOperation has been removed from the classifer.
+ */
+ void operationRemoved(UMLClassifierListItem *);
+
+ void templateAdded(UMLClassifierListItem*);
+ void templateRemoved(UMLClassifierListItem*);
+
+ // only applies when (m_Type == ot_Class)
+ void attributeAdded(UMLClassifierListItem*);
+ void attributeRemoved(UMLClassifierListItem*);
+
+private:
+
+ /**
+ * Initializes key variables of the class.
+ */
+ void init();
+
+ UMLAssociation *m_pClassAssoc;
+
+ bool m_isRef;
+
+protected:
+
+ /**
+ * Auxiliary to saveToXMI of inheriting classes:
+ * Saves template parameters to the given QDomElement.
+ */
+ void saveToXMI(QDomDocument& qDoc, QDomElement& qElement);
+
+ /**
+ * Auxiliary to loadFromXMI:
+ * The loading of operations is implemented here.
+ * Calls loadSpecialized() for any other tag.
+ * Child classes can override the loadSpecialized method
+ * to load its additional tags.
+ */
+ virtual bool load(QDomElement& element);
+
+};
+
+#endif // CONCEPT_H
diff --git a/umbrello/umbrello/classifiercodedocument.cpp b/umbrello/umbrello/classifiercodedocument.cpp
new file mode 100644
index 00000000..a2d2f9fc
--- /dev/null
+++ b/umbrello/umbrello/classifiercodedocument.cpp
@@ -0,0 +1,742 @@
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * copyright (C) 2004-2007 *
+ * Umbrello UML Modeller Authors <uml-devel@uml.sf.net> *
+ ***************************************************************************/
+
+/* This code generated by:
+ * Author : thomas
+ * Date : Thu Jun 19 2003
+ */
+
+// own header
+#include "classifiercodedocument.h"
+
+// qt/kde includes
+#include <kdebug.h>
+#include <qregexp.h>
+
+// local includes
+#include "association.h"
+#include "attribute.h"
+#include "operation.h"
+#include "classifierlistitem.h"
+#include "classifier.h"
+#include "codegenerator.h"
+#include "uml.h"
+#include "umldoc.h"
+#include "umlrole.h"
+#include "umlattributelist.h"
+#include "umloperationlist.h"
+#include "codegenerators/codegenfactory.h"
+
+// Constructors/Destructors
+//
+
+ClassifierCodeDocument::ClassifierCodeDocument ( UMLClassifier * parent )
+{
+ init (parent);
+}
+
+ClassifierCodeDocument::~ClassifierCodeDocument ( )
+{
+ for (CodeClassFieldListIt ccflit(m_classfieldVector); ccflit.current(); ++ccflit)
+ {
+ CodeClassField * cf = ccflit.current();
+ delete cf;
+ }
+ m_classfieldVector.clear();
+}
+
+//
+// Methods
+//
+
+
+// Accessor methods
+//
+
+/** get a list of codeclassifier objects held by this classifiercodedocument that meet the passed criteria.
+ */
+CodeClassFieldList ClassifierCodeDocument::getSpecificClassFields (CodeClassField::ClassFieldType cfType)
+{
+ CodeClassFieldList list;
+ for (CodeClassFieldListIt ccflit(m_classfieldVector); ccflit.current(); ++ccflit)
+ {
+ CodeClassField * cf = ccflit.current();
+ if (cf->getClassFieldType() == cfType)
+ list.append(cf);
+ }
+ return list;
+}
+
+/** get a list of codeclassifier objects held by this classifiercodedocument that meet the passed criteria.
+ */
+CodeClassFieldList ClassifierCodeDocument::getSpecificClassFields (CodeClassField::ClassFieldType cfType, bool isStatic)
+{
+ CodeClassFieldList list;
+ list.setAutoDelete(false);
+ for (CodeClassFieldListIt ccflit(m_classfieldVector); ccflit.current(); ++ccflit)
+ {
+ CodeClassField * cf = ccflit.current();
+ if (cf->getClassFieldType() == cfType && cf->getStatic() == isStatic)
+ list.append(cf);
+ }
+ return list;
+}
+
+/** get a list of codeclassifier objects held by this classifiercodedocument that meet the passed criteria.
+ */
+CodeClassFieldList ClassifierCodeDocument::getSpecificClassFields (CodeClassField::ClassFieldType cfType, Uml::Visibility visibility)
+{
+ CodeClassFieldList list;
+ list.setAutoDelete(false);
+ for (CodeClassFieldListIt ccflit(m_classfieldVector); ccflit.current(); ++ccflit)
+ {
+ CodeClassField * cf = ccflit.current();
+ if (cf->getClassFieldType() == cfType && cf->getVisibility() == visibility)
+ list.append(cf);
+ }
+ return list;
+}
+
+/** get a list of codeclassifier objects held by this classifiercodedocument that meet the passed criteria.
+ */
+CodeClassFieldList ClassifierCodeDocument::getSpecificClassFields (CodeClassField::ClassFieldType cfType, bool isStatic, Uml::Visibility visibility)
+{
+ CodeClassFieldList list;
+ list.setAutoDelete(false);
+ for (CodeClassFieldListIt ccflit(m_classfieldVector); ccflit.current(); ++ccflit)
+ {
+ CodeClassField * cf = ccflit.current();
+ if (cf->getClassFieldType() == cfType && cf->getVisibility() == visibility && cf->getStatic() == isStatic )
+ list.append(cf);
+ }
+ return list;
+}
+
+// do we have accessor methods for lists of objects?
+// (as opposed to lists of primitive types like 'int' or 'float', etc)
+bool ClassifierCodeDocument::hasObjectVectorClassFields() {
+ for (CodeClassFieldListIt ccflit(m_classfieldVector); ccflit.current(); ++ccflit)
+ {
+ CodeClassField * cf = ccflit.current();
+ if(cf->getClassFieldType() != CodeClassField::Attribute)
+ {
+ UMLRole * role = dynamic_cast<UMLRole*>(cf->getParentObject());
+ QString multi = role->getMultiplicity();
+ if (
+ multi.contains(QRegExp("[23456789\\*]")) ||
+ multi.contains(QRegExp("1\\d"))
+ )
+ return true;
+ }
+ }
+ return false;
+}
+
+bool ClassifierCodeDocument::hasClassFields() {
+ if(m_classfieldVector.count() > 0 )
+ return true;
+ return false;
+}
+
+/**
+ * Tell if one or more codeclassfields are derived from associations.
+ */
+bool ClassifierCodeDocument::hasAssociationClassFields() {
+ CodeClassFieldList list = getSpecificClassFields(CodeClassField::Attribute);
+ return (m_classfieldVector.count() - list.count()) > 0 ? true : false;
+}
+
+/**
+ * Tell if one or more codeclassfields are derived from attributes.
+ */
+bool ClassifierCodeDocument::hasAttributeClassFields() {
+ CodeClassFieldList list = getSpecificClassFields(CodeClassField::Attribute);
+ return list.count() > 0 ? true : false;
+}
+
+/**
+ * Add a CodeClassField object to the m_classfieldVector List
+ * @return boolean true if successful in adding
+ */
+// We DON'T add methods of the code classfield here because we need to allow
+// the codegenerator writer the liberty to organize their document as they desire.
+bool ClassifierCodeDocument::addCodeClassField ( CodeClassField * add_object ) {
+ UMLObject * umlobj = add_object->getParentObject();
+ if(!(m_classFieldMap.contains(umlobj)))
+ {
+ m_classfieldVector.append(add_object);
+ m_classFieldMap.insert(umlobj,add_object);
+
+ return true;
+ }
+ return false;
+}
+
+// this is a slot..should only be called from a signal
+void ClassifierCodeDocument::addAttributeClassField (UMLClassifierListItem *obj, bool syncToParentIfAdded) {
+ UMLAttribute *at = (UMLAttribute*)obj;
+ CodeClassField * cf = CodeGenFactory::newCodeClassField(this, at);
+ if(cf)
+ if (addCodeClassField(cf) && syncToParentIfAdded)
+ updateContent();
+}
+
+/**
+ * Remove a CodeClassField object from m_classfieldVector List
+ */
+bool ClassifierCodeDocument::removeCodeClassField ( CodeClassField * remove_object ) {
+ UMLObject * umlobj = remove_object->getParentObject();
+ if(m_classFieldMap.contains(umlobj))
+ {
+ if (m_classfieldVector.removeRef(remove_object))
+ {
+ // remove from our classfield map
+ m_classFieldMap.remove(umlobj);
+ delete remove_object;
+ return true;
+ }
+ }
+ return false;
+}
+
+void ClassifierCodeDocument::removeAttributeClassField(UMLClassifierListItem *obj)
+{
+ CodeClassField * remove_object = m_classFieldMap[obj];
+ if(remove_object)
+ removeCodeClassField(remove_object);
+}
+
+void ClassifierCodeDocument::removeAssociationClassField (UMLAssociation *assoc )
+{
+
+ // the object could be either (or both!) role a or b. We should check
+ // both parts of the association.
+ CodeClassField * remove_object = m_classFieldMap[assoc->getUMLRole(Uml::A)];
+ if(remove_object)
+ removeCodeClassField(remove_object);
+
+ // check role b
+ remove_object = m_classFieldMap[assoc->getUMLRole(Uml::B)];
+ if(remove_object)
+ removeCodeClassField(remove_object);
+
+}
+
+/**
+ * Get the list of CodeClassField objects held by m_classfieldVector
+ * @return CodeClassFieldList list of CodeClassField objects held by
+ * m_classfieldVector
+ */
+CodeClassFieldList * ClassifierCodeDocument::getCodeClassFieldList ( ) {
+ return &m_classfieldVector;
+}
+
+/**
+ * Get the value of m_parentclassifier
+ * @return the value of m_parentclassifier
+ */
+UMLClassifier * ClassifierCodeDocument::getParentClassifier ( ) {
+ return m_parentclassifier;
+}
+
+/**
+ * @return QPtrList<CodeOperation>
+ */
+QPtrList<CodeOperation> ClassifierCodeDocument::getCodeOperations ( ) {
+
+ QPtrList<CodeOperation> list;
+ list.setAutoDelete(false);
+
+ TextBlockList * tlist = getTextBlockList();
+ for (TextBlock *tb = tlist->first(); tb; tb=tlist->next())
+ {
+ CodeOperation * cop = dynamic_cast<CodeOperation*>(tb);
+ if(cop)
+ list.append(cop);
+ }
+ return list;
+}
+
+/**
+ * @param o The Operation to add
+ */
+void ClassifierCodeDocument::addOperation (UMLClassifierListItem * o) {
+ UMLOperation *op = dynamic_cast<UMLOperation*>(o);
+ if (op == NULL) {
+ kError() << "ClassifierCodeDocument::addOperation: arg is not a UMLOperation"
+ << endl;
+ }
+ QString tag = CodeOperation::findTag(op);
+ CodeOperation * codeOp = dynamic_cast<CodeOperation*>(findTextBlockByTag(tag, true));
+ bool createdNew = false;
+
+ // create the block, if it doesn't already exist
+ if(!codeOp)
+ {
+ codeOp = CodeGenFactory::newCodeOperation(this, op);
+ createdNew = true;
+ }
+
+ // now try to add it. This may fail because it (or a block with
+ // the same tag) is already in the document somewhere. IF we
+ // created this new, then we need to delete our object.
+ if(!addCodeOperation(codeOp)) // wont add if already present
+ if(createdNew)
+ delete codeOp;
+
+}
+
+/**
+ * @param op
+ */
+void ClassifierCodeDocument::removeOperation (UMLClassifierListItem * op ) {
+
+ QString tag = CodeOperation::findTag((UMLOperation*)op);
+ TextBlock *tb = findTextBlockByTag(tag, true);
+ if(tb)
+ {
+ if(removeTextBlock(tb)) // wont add if already present
+ delete tb; // delete unused operations
+ else
+ kError()<<"Cant remove CodeOperation from ClassCodeDocument!"<<endl;
+
+ }
+ else
+ kError()<<"Cant Find codeOperation for deleted operation!"<<endl;
+}
+
+// Other methods
+//
+
+void ClassifierCodeDocument::addCodeClassFieldMethods(CodeClassFieldList &list )
+{
+
+ for (CodeClassFieldListIt ccflit(list); ccflit.current(); ++ccflit)
+ {
+ CodeClassField * field = ccflit.current();
+ CodeAccessorMethodList list = field->getMethodList();
+ CodeAccessorMethod * method;
+ for (CodeAccessorMethodListIt it(list); (method = it.current()) != NULL; ++it)
+ {
+ /*
+ QString tag = method->getTag();
+ if(tag.isEmpty())
+ {
+ tag = getUniqueTag();
+ method->setTag(tag);
+ }
+ */
+ addTextBlock(method); // wont add if already exists in document, will add a tag if missing;
+
+ }
+
+ }
+
+}
+
+// add declaration blocks for the passed classfields
+void ClassifierCodeDocument::declareClassFields (CodeClassFieldList & list ,
+ CodeGenObjectWithTextBlocks * parent )
+{
+
+ for (CodeClassFieldListIt ccflit(list); ccflit.current(); ++ccflit)
+ {
+ CodeClassField * field = ccflit.current();
+ CodeClassFieldDeclarationBlock * declBlock = field->getDeclarationCodeBlock();
+
+ /*
+ // if it has a tag, check
+ if(!declBlock->getTag().isEmpty())
+ {
+ // In C++, because we may shift the declaration to a different parent
+ // block for a change in scope, we need to track down any pre-existing
+ // location, and remove FIRST before adding to new parent
+ CodeGenObjectWithTextBlocks * oldParent = findParentObjectForTaggedTextBlock (declBlock->getTag());
+ if(oldParent) {
+ if(oldParent != parent)
+ oldParent->removeTextBlock(declBlock);
+ }
+ }
+ */
+
+ parent->addTextBlock(declBlock); // wont add it IF its already present. Will give it a tag if missing
+
+ }
+}
+
+bool ClassifierCodeDocument::parentIsClass() {
+ return (m_parentclassifier->getBaseType() == Uml::ot_Class);
+}
+
+bool ClassifierCodeDocument::parentIsInterface() {
+ return (m_parentclassifier->getBaseType() == Uml::ot_Interface);
+}
+
+/**
+ * Init from a UMLClassifier object.
+ * @param classifier
+ * @param package
+ */
+void ClassifierCodeDocument::init (UMLClassifier * c )
+{
+
+ m_parentclassifier = c;
+ m_classfieldVector.setAutoDelete(false);
+
+ updateHeader();
+ syncNamesToParent();
+ // initCodeClassFields(); // cant call here?..newCodeClassField is pure virtual
+
+ // slots
+ if (parentIsClass()) {
+ connect(c,SIGNAL(attributeAdded(UMLClassifierListItem*)),this,SLOT(addAttributeClassField(UMLClassifierListItem*)));
+ connect(c,SIGNAL(attributeRemoved(UMLClassifierListItem*)),this,SLOT(removeAttributeClassField(UMLClassifierListItem*)));
+ }
+
+ connect(c,SIGNAL(sigAssociationEndAdded(UMLAssociation*)),this,SLOT(addAssociationClassField(UMLAssociation*)));
+ connect(c,SIGNAL(sigAssociationEndRemoved(UMLAssociation*)),this,SLOT(removeAssociationClassField(UMLAssociation*)));
+ connect(c,SIGNAL(operationAdded(UMLClassifierListItem*)),this,SLOT(addOperation(UMLClassifierListItem*)));
+ connect(c,SIGNAL(operationRemoved(UMLClassifierListItem*)),this,SLOT(removeOperation(UMLClassifierListItem*)));
+ connect(c,SIGNAL(modified()),this,SLOT(syncToParent()));
+
+}
+
+// IF the classifier object is modified, this will get called.
+// @todo we cannot make this virtual as long as the
+// ClassifierCodeDocument constructor calls it because that gives
+// a call-before-construction error.
+// Example of the problem: CPPSourceCodeDocument reimplementing syncNamesToParent()
+// CPPCodeGenerator::initFromParentDocument()
+// CodeDocument * codeDoc = new CPPSourceCodeDocument(c);
+// CPPSourceCodeDocument::CPPSourceCodeDocument(UMLClassifier * concept)
+// : ClassifierCodeDocument(concept)
+// ClassifierCodeDocument::ClassifierCodeDocument(concept)
+// init(concept);
+// syncNamesToParent();
+// dispatches to CPPSourceCodeDocument::syncNamesToParent()
+// but that object is not yet constructed.
+//
+void ClassifierCodeDocument::syncNamesToParent( ) {
+ QString fileName = CodeGenerator::cleanName(getParentClassifier()->getName());
+ if (!UMLApp::app()->activeLanguageIsCaseSensitive()) {
+ // @todo let the user decide about mixed case file names (codegen setup menu)
+ fileName = fileName.lower();
+ }
+ setFileName(fileName);
+ setPackage(m_parentclassifier->getUMLPackage());
+}
+
+void ClassifierCodeDocument::synchronize( ) {
+
+ updateHeader(); // doing this insures time/date stamp is at the time of this call
+ syncNamesToParent();
+ updateContent();
+ syncClassFields();
+ updateOperations();
+
+}
+
+void ClassifierCodeDocument::syncClassFields( )
+{
+ for (CodeClassFieldListIt ccflit(m_classfieldVector); ccflit.current(); ++ccflit)
+ {
+ CodeClassField * cf = ccflit.current();
+ cf->synchronize();
+ }
+}
+
+void ClassifierCodeDocument::updateOperations( ) {
+
+ UMLOperationList opList(getParentClassifier()->getOpList());
+ for (UMLOperation *op = opList.first(); op; op = opList.next())
+ {
+ QString tag = CodeOperation::findTag(op);
+ CodeOperation * codeOp = dynamic_cast<CodeOperation*>(findTextBlockByTag(tag, true));
+ bool createdNew = false;
+
+ if(!codeOp)
+ {
+ codeOp = CodeGenFactory::newCodeOperation(this, op);
+ createdNew = true;
+ }
+
+ // now try to add it. This may fail because it (or a block with
+ // the same tag) is already in the document somewhere. IF we
+ // created this new, then we need to delete our object.
+ if(!addCodeOperation(codeOp)) // wont add if already present
+ if(createdNew)
+ delete codeOp;
+
+ // synchronize all non-new operations
+ if(!createdNew)
+ codeOp->syncToParent();
+ }
+
+}
+
+void ClassifierCodeDocument::syncToParent( ) {
+ synchronize();
+}
+
+/**
+ * add codeclassfields to this classifiercodedocument. IF a codeclassfield
+ * already exists, it is not added.
+ */
+void ClassifierCodeDocument::initCodeClassFields ( ) {
+
+ UMLClassifier * c = getParentClassifier();
+ // first, do the code classifields that arise from attributes
+ if (parentIsClass()) {
+ UMLAttributeList alist = c->getAttributeList();
+ for(UMLAttribute * at = alist.first(); at; at = alist.next())
+ {
+ CodeClassField * field = CodeGenFactory::newCodeClassField(this, at);
+ addCodeClassField(field);
+ }
+
+ }
+
+ // now, do the code classifields that arise from associations
+ UMLAssociationList ap = c->getSpecificAssocs(Uml::at_Association);
+ UMLAssociationList ag = c->getAggregations();
+ UMLAssociationList ac = c->getCompositions();
+ UMLAssociationList selfAssoc = c->getSpecificAssocs(Uml::at_Association_Self);
+
+ updateAssociationClassFields(ap);
+ updateAssociationClassFields(ag);
+ updateAssociationClassFields(ac);
+ updateAssociationClassFields(selfAssoc);
+
+}
+
+void ClassifierCodeDocument::updateAssociationClassFields ( UMLAssociationList &assocList )
+{
+ CodeClassFieldList list;
+ for(UMLAssociation * a=assocList.first(); a; a=assocList.next())
+ addAssociationClassField(a, false); // syncToParent later
+}
+
+void ClassifierCodeDocument::addAssociationClassField (UMLAssociation * a, bool syncToParentIfAdded)
+{
+
+ Uml::IDType cid = getParentClassifier()->getID(); // so we know who 'we' are
+ bool printRoleA = false, printRoleB = false, shouldSync = false;
+ // it may seem counter intuitive, but you want to insert the role of the
+ // *other* class into *this* class.
+ if (a->getObjectId(Uml::A) == cid)
+ printRoleB = true;
+
+ if (a->getObjectId(Uml::B) == cid)
+ printRoleA = true;
+
+ // grab RoleB decl
+ if (printRoleB)
+ {
+
+ UMLRole * role = a->getUMLRole(Uml::B);
+ if(!m_classFieldMap.contains((UMLObject*)role))
+ {
+ CodeClassField * classfield = CodeGenFactory::newCodeClassField(this, role);
+ if( addCodeClassField(classfield))
+ shouldSync = true;
+ }
+ }
+
+ // print RoleA decl
+ if (printRoleA)
+ {
+ UMLRole * role = a->getUMLRole(Uml::A);
+ if(!m_classFieldMap.contains((UMLObject*)role))
+ {
+ CodeClassField * classfield = CodeGenFactory::newCodeClassField(this, role);
+ if( addCodeClassField(classfield))
+ shouldSync = true;
+ }
+ }
+
+ if (shouldSync && syncToParentIfAdded)
+ syncToParent(); // needed for a slot add
+
+}
+
+/** set the class attributes of this object from
+ * the passed element node.
+ */
+void ClassifierCodeDocument::setAttributesFromNode ( QDomElement & elem )
+{
+
+ // NOTE: we DON'T set the parent here as we ONLY get to this point
+ // IF the parent codegenerator could find a matching parent classifier
+ // that already has a code document.
+
+ // We FIRST set code class field stuff..check re-linnking with
+ // accessor methods by looking for our particular child element
+ QDomNode node = elem.firstChild();
+ QDomElement childElem = node.toElement();
+ while( !childElem.isNull() ) {
+ QString tag = childElem.tagName();
+ if( tag == "classfields" ) {
+ // load classfields
+ loadClassFieldsFromXMI(childElem);
+ break;
+ }
+ node = childElem.nextSibling();
+ childElem= node.toElement();
+ }
+
+ // call super-class after. THis will populate the text blocks (incl
+ // the code accessor methods above) as is appropriate
+ CodeDocument::setAttributesFromNode(elem);
+
+}
+
+// look at all classfields currently in document.. match up
+// by parent object ID and Role ID (needed for self-association CF's)
+CodeClassField *
+ClassifierCodeDocument::findCodeClassFieldFromParentID (Uml::IDType id,
+ int role_id)
+{
+ for (CodeClassFieldListIt ccflit(m_classfieldVector); ccflit.current(); ++ccflit)
+ {
+ CodeClassField * cf = ccflit.current();
+ if(role_id == -1) { // attribute-based
+ if (STR2ID(cf->getID()) == id)
+ return cf;
+ } else { // association(role)-based
+ const Uml::Role_Type r = (Uml::Role_Type)role_id;
+ UMLRole * role = dynamic_cast<UMLRole *>(cf->getParentObject());
+ if(role && STR2ID(cf->getID()) == id && role->getRole() == r)
+ return cf;
+ }
+ }
+
+ // shouldn't happen..
+ kError() << "Failed to find codeclassfield for parent uml id:"
+ << ID2STR(id) << " (role id:" << role_id
+ << ") Do you have a corrupt classifier code document?"
+ << endl;
+
+ return (CodeClassField*) NULL; // not found
+}
+
+void ClassifierCodeDocument::loadClassFieldsFromXMI( QDomElement & elem) {
+
+ QDomNode node = elem.firstChild();
+ QDomElement childElem = node.toElement();
+ while( !childElem.isNull() ) {
+ QString nodeName = childElem.tagName();
+ if( nodeName == "codeclassfield")
+ {
+ QString id = childElem.attribute("parent_id","-1");
+ int role_id = childElem.attribute("role_id","-1").toInt();
+ CodeClassField * cf = findCodeClassFieldFromParentID(STR2ID(id), role_id);
+ if(cf)
+ {
+ // Because we just may change the parent object here,
+ // we need to yank it from the map of umlobjects
+ m_classFieldMap.remove(cf->getParentObject());
+
+ // configure from XMI
+ cf->loadFromXMI(childElem);
+
+ // now add back in
+ m_classFieldMap.insert(cf->getParentObject(),cf);
+
+ } else
+ kError()<<" LoadFromXMI: can't load classfield parent_id:"<<id<<" do you have a corrupt savefile?"<<endl;
+ }
+ node = childElem.nextSibling();
+ childElem= node.toElement();
+ }
+}
+
+/**
+ * Save the XMI representation of this object
+ */
+void ClassifierCodeDocument::saveToXMI ( QDomDocument & doc, QDomElement & root ) {
+#if 0
+ // avoid the creation of primitive data type
+ QString strType;
+ if (getParentClassifier()->getBaseType() == Uml::ot_Datatype) {
+ strType = getParentClassifier()->getName();
+ // lets get the default code generator to check if it is a primitive data type
+ // there's a reason to create files for int/boolean and so ?
+ if (getParentGenerator()->isReservedKeyword(strType))
+ return;
+ }
+#endif
+ QDomElement docElement = doc.createElement( "classifiercodedocument" );
+
+ setAttributesOnNode(doc, docElement);
+
+ root.appendChild( docElement );
+}
+
+/**
+ * load params from the appropriate XMI element node.
+ */
+void ClassifierCodeDocument::loadFromXMI ( QDomElement & root ) {
+
+ // set attributes/fields
+ setAttributesFromNode(root);
+
+ // now sync our doc, needed?
+ // synchronize();
+}
+
+/** set attributes of the node that represents this class
+ * in the XMI document.
+ */
+void ClassifierCodeDocument::setAttributesOnNode ( QDomDocument & doc, QDomElement & docElement)
+{
+
+ // do super-class first
+ CodeDocument::setAttributesOnNode(doc, docElement);
+
+ // cache local attributes/fields
+ docElement.setAttribute("parent_class", ID2STR(getParentClassifier()->getID()));
+
+ // (code) class fields
+ // which we will store in its own separate child node block
+ QDomElement fieldsElement = doc.createElement( "classfields" );
+ for (CodeClassFieldListIt ccflit(m_classfieldVector); ccflit.current(); ++ccflit)
+ {
+ CodeClassField * field = ccflit.current();
+ field->saveToXMI(doc, fieldsElement);
+ }
+ docElement.appendChild( fieldsElement);
+
+}
+
+TextBlock * ClassifierCodeDocument::findCodeClassFieldTextBlockByTag (const QString &tag)
+{
+
+ for (CodeClassFieldListIt ccflit(m_classfieldVector); ccflit.current(); ++ccflit)
+ {
+ CodeClassField * cf = ccflit.current();
+ CodeClassFieldDeclarationBlock * decl = cf->getDeclarationCodeBlock();
+ if(decl && decl->getTag() == tag)
+ return decl;
+ // well, if not in the decl block, then in the methods perhaps?
+ CodeAccessorMethodList mlist = cf->getMethodList();
+ CodeAccessorMethod *m;
+ for (CodeAccessorMethodListIt it(mlist); (m = it.current()) != NULL; ++it)
+ if(m->getTag() == tag)
+ return m;
+ }
+
+ // if we get here, we failed.
+ return (TextBlock*) NULL;
+
+}
+
+
+#include "classifiercodedocument.moc"
diff --git a/umbrello/umbrello/classifiercodedocument.h b/umbrello/umbrello/classifiercodedocument.h
new file mode 100644
index 00000000..2e103034
--- /dev/null
+++ b/umbrello/umbrello/classifiercodedocument.h
@@ -0,0 +1,251 @@
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * copyright (C) 2004-2006 *
+ * Umbrello UML Modeller Authors <uml-devel@uml.sf.net> *
+ ***************************************************************************/
+
+/* This code generated by:
+ * Author : thomas
+ * Date : Thu Jun 19 2003
+ */
+
+
+
+#ifndef CLASSIFIERCODEDOCUMENT_H
+#define CLASSIFIERCODEDOCUMENT_H
+
+#include <qmap.h>
+#include <qstring.h>
+#include <qptrlist.h>
+
+#include "classifier.h"
+#include "codeaccessormethod.h"
+#include "codedocument.h"
+#include "codeoperation.h"
+#include "codeclassfield.h"
+#include "codeclassfieldlist.h"
+#include "umlassociationlist.h"
+
+class UMLRole;
+
+/**
+ * class ClassifierCodeDocument
+ * A CodeDocument which represents a UMLClassifier (e.g. a Class or Interface)
+ */
+
+class ClassifierCodeDocument : public CodeDocument
+{
+ friend class HierarchicalCodeBlock;
+ Q_OBJECT
+public:
+
+ // Constructors/Destructors
+ //
+
+
+ /**
+ * Empty Constructor
+ */
+ ClassifierCodeDocument ( UMLClassifier * parent );
+
+ /**
+ * Empty Destructor
+ */
+ virtual ~ClassifierCodeDocument ( );
+
+ /**
+ * Add a CodeClassField object to the m_classfieldVector List
+ */
+ bool addCodeClassField ( CodeClassField * add_object );
+
+ /**
+ * Remove a CodeClassField object from m_classfieldVector List
+ */
+ bool removeCodeClassField ( CodeClassField * remove_object );
+
+ /**
+ * Get the list of CodeClassField objects held by m_classfieldVector
+ * @return CodeClassFieldList list of CodeClassField objects held by
+ * m_classfieldVector
+ */
+ CodeClassFieldList * getCodeClassFieldList ( );
+
+ // some Utility methods
+
+ /**
+ * Return if the parent classifier is an interface
+ */
+ bool parentIsInterface();
+
+ /**
+ * Return if the parent classifier is a class
+ */
+ bool parentIsClass();
+
+ /**
+ * Tell if one or more codeclassfields are derived from any kind of association.
+ */
+ bool hasAssociationClassFields();
+ /**
+ * Tell if one or more codeclassfields are derived from attributes.
+ */
+ bool hasAttributeClassFields();
+
+ /**
+ * Tell if any of the accessor classfields will be of lists of objects.
+ */
+ bool hasObjectVectorClassFields();
+
+ /**
+ * Does this object have any classfields declared?
+ */
+ bool hasClassFields();
+
+ /**
+ * Get a list of codeoperation objects held by this classifiercodedocument.
+ * @return QPtrList<CodeOperation>
+ */
+ QPtrList<CodeOperation> getCodeOperations ( );
+
+ /** Get a list of codeclassifier objects held by this classifiercodedocument that meet the passed criteria.
+ * @return CodeClassFieldList
+ */
+ CodeClassFieldList getSpecificClassFields (CodeClassField::ClassFieldType cfType);
+
+ /** Get a list of codeclassifier objects held by this classifiercodedocument that meet the passed criteria.
+ * @return CodeClassFieldList
+ */
+ CodeClassFieldList getSpecificClassFields (CodeClassField::ClassFieldType cfType, bool isStatic);
+
+ /** Get a list of codeclassifier objects held by this classifiercodedocument that meet the passed criteria.
+ * @return CodeClassFieldList
+ */
+ CodeClassFieldList getSpecificClassFields (CodeClassField::ClassFieldType cfType, Uml::Visibility visibility);
+
+ /** Get a list of codeclassifier objects held by this classifiercodedocument that meet the passed criteria.
+ * @return CodeClassFieldList
+ */
+ CodeClassFieldList getSpecificClassFields (CodeClassField::ClassFieldType cfType, bool isStatic, Uml::Visibility visibility);
+
+ /** Using the parent object's UML ID, find the corresponding
+ * codeclassfield object in this classifiercodedocument. Returns
+ * NULL if no such codeclassfield object exists in this document.
+ *
+ * @param id ID of the parent object
+ * @param role_id 0 for role A of the asssociation
+ * 1 for role B of the asssociation
+ * -1 if this is an attribute.
+ */
+ CodeClassField * findCodeClassFieldFromParentID (Uml::IDType id, int role_id = -1);
+
+ /**
+ * Get the value of m_parentclassifier
+ * @return the value of m_parentclassifier
+ */
+ UMLClassifier * getParentClassifier ( );
+
+ // a utility method that allows user to easily add classfield methods to this document
+ void addCodeClassFieldMethods(CodeClassFieldList &list );
+
+ /**
+ * Utility method to appropriately populate the code classfields for this document.
+ */
+ virtual void initCodeClassFields ( );
+
+ // cause this classifier code document to synchronize to current policy
+ virtual void synchronize();
+
+ /** Will add the code operation in the correct place in the document.
+ * @return bool which is true IF the code operation was added successfully
+ */
+ virtual bool addCodeOperation (CodeOperation *opBlock) = 0;
+
+ /**
+ * Save the XMI representation of this object
+ */
+ virtual void saveToXMI ( QDomDocument & doc, QDomElement & root );
+
+ /**
+ * load params from the appropriate XMI element node.
+ */
+ virtual void loadFromXMI ( QDomElement & root );
+
+protected:
+
+ /**
+ * Load CodeClassFields from XMI element node.
+ */
+ void loadClassFieldsFromXMI( QDomElement & childElem);
+
+ /** set attributes of the node that represents this class
+ * in the XMI document.
+ */
+ virtual void setAttributesOnNode ( QDomDocument & doc, QDomElement & blockElement);
+
+ /** set the class attributes of this object from
+ * the passed element node.
+ */
+ virtual void setAttributesFromNode ( QDomElement & element);
+
+ // find a specific textblock held by any code class field in this document
+ // by its tag
+ TextBlock * findCodeClassFieldTextBlockByTag (const QString &tag);
+
+ // add the declaration text blocks for various classfields
+ void declareClassFields (CodeClassFieldList & list , CodeGenObjectWithTextBlocks * parent);
+
+ virtual void updateContent( ) = 0;
+
+ // force syncronization of child classfields to their parent objects
+ void syncClassFields( );
+
+ // IF the classifier object is modified, this will get called.
+ // @fixme We cannot make this virtual because the ClassifierCodeDocument
+ // constructor calls it.
+ void syncNamesToParent( );
+
+private:
+
+ CodeClassFieldList m_classfieldVector;
+ UMLClassifier* m_parentclassifier;
+
+ // using the passed list, update our inventory of CodeClassFields which are
+ // based on UMLRoles (e.g. derived from associations with other classifiers).
+ void updateAssociationClassFields ( UMLAssociationList &assocList );
+
+ // update code operations in this document using the parent classifier
+ void updateOperations( );
+
+ /**
+ * Maps CodeClassFields to UMLObjects. Used to prevent re-adding a class
+ * field.
+ */
+ QMap<UMLObject *,CodeClassField *> m_classFieldMap;
+
+ /**
+ * Init from a UMLClassifier object.
+ * @param classifier
+ */
+ void init ( UMLClassifier * classifier );
+
+public slots:
+
+ /**
+ * Synchronize this document to the attributes/associations of the parent classifier.
+ */
+ void addAttributeClassField(UMLClassifierListItem *at, bool syncToParentIfAdded = true);
+ void addAssociationClassField (UMLAssociation * assoc, bool syncToParentIfAdded = true);
+ void removeAttributeClassField(UMLClassifierListItem *at);
+ void removeAssociationClassField(UMLAssociation *assoc);
+ void addOperation (UMLClassifierListItem * obj);
+ void removeOperation (UMLClassifierListItem * obj);
+ void syncToParent( );
+
+};
+
+#endif // CLASSIFIERCODEDOCUMENT_H
diff --git a/umbrello/umbrello/classifierlistitem.cpp b/umbrello/umbrello/classifierlistitem.cpp
new file mode 100644
index 00000000..888f3da7
--- /dev/null
+++ b/umbrello/umbrello/classifierlistitem.cpp
@@ -0,0 +1,98 @@
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * copyright (C) 2003-2007 *
+ * Umbrello UML Modeller Authors <uml-devel@uml.sf.net> *
+ ***************************************************************************/
+
+// own header
+#include "classifierlistitem.h"
+
+// qt/kde includes
+#include <kdebug.h>
+#include <klocale.h>
+
+// local includes
+#include "classifier.h"
+#include "uml.h"
+#include "umldoc.h"
+#include "model_utils.h"
+#include "object_factory.h"
+
+UMLClassifierListItem::UMLClassifierListItem(const UMLObject *parent,
+ const QString& name, Uml::IDType id)
+ : UMLObject(parent, name, id) {
+ UMLObject *parentObj = const_cast<UMLObject*>(parent);
+ UMLClassifier *pc = dynamic_cast<UMLClassifier*>(parentObj);
+ if (pc)
+ UMLObject::setUMLPackage(pc);
+}
+
+UMLClassifierListItem::UMLClassifierListItem(const UMLObject *parent)
+ : UMLObject(parent) {
+ UMLObject *parentObj = const_cast<UMLObject*>(parent);
+ UMLClassifier *pc = dynamic_cast<UMLClassifier*>(parentObj);
+ if (pc)
+ UMLObject::setUMLPackage(pc);
+}
+
+UMLClassifierListItem::~UMLClassifierListItem() {
+}
+
+void UMLClassifierListItem::copyInto(UMLClassifierListItem *rhs) const
+{
+ // Call the parent.
+ UMLObject::copyInto(rhs);
+}
+
+QString UMLClassifierListItem::toString(Uml::Signature_Type /*sig*/) {
+ return getName();
+}
+
+UMLClassifier * UMLClassifierListItem::getType() const{
+ return static_cast<UMLClassifier*>(m_pSecondary);
+}
+
+QString UMLClassifierListItem::getTypeName() const{
+ if (m_pSecondary == NULL)
+ return m_SecondaryId;
+ const UMLPackage *typePkg = m_pSecondary->getUMLPackage();
+ if (typePkg != NULL && typePkg != m_pUMLPackage)
+ return m_pSecondary->getFullyQualifiedName();
+ return m_pSecondary->getName();
+}
+
+void UMLClassifierListItem::setType(UMLObject *type) {
+ if (m_pSecondary != type) {
+ m_pSecondary = type;
+ UMLObject::emitModified();
+ }
+}
+
+void UMLClassifierListItem::setTypeName(const QString &type) {
+ if (type.isEmpty() || type == "void") {
+ m_pSecondary = NULL;
+ m_SecondaryId = QString();
+ return;
+ }
+ UMLDoc *pDoc = UMLApp::app()->getDocument();
+ m_pSecondary = pDoc->findUMLObject(type);
+ if (m_pSecondary == NULL) {
+ // Make data type for easily identified cases
+ if (Model_Utils::isCommonDataType(type) || type.contains('*')) {
+ m_pSecondary = Object_Factory::createUMLObject(Uml::ot_Datatype, type);
+ kDebug() << "UMLClassifierListItem::setTypeName: "
+ << "created datatype for " << type << endl;
+ } else {
+ m_SecondaryId = type;
+ }
+ }
+ UMLObject::emitModified();
+}
+
+
+#include "classifierlistitem.moc"
diff --git a/umbrello/umbrello/classifierlistitem.h b/umbrello/umbrello/classifierlistitem.h
new file mode 100644
index 00000000..fd68fdf3
--- /dev/null
+++ b/umbrello/umbrello/classifierlistitem.h
@@ -0,0 +1,126 @@
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * copyright (C) 2003-2006 *
+ * Umbrello UML Modeller Authors <uml-devel@uml.sf.net> *
+ ***************************************************************************/
+
+#ifndef CLASSIFIERLISTITEM_H
+#define CLASSIFIERLISTITEM_H
+
+#include "umlobject.h"
+
+// forward declaration
+class UMLClassifier;
+
+/**
+ * Classifiers (classes, interfaces) have lists of operations,
+ * attributes, templates and others. This is a base class for
+ * the items in this list. This abstraction should remove
+ * duplication of dialogs and allow for stereotypes in lists.
+ *
+ * @short A base class for classifier list items (e.g. attributes)
+ * @author Jonathan Riddell
+ * Bugs and comments to uml-devel@lists.sf.net or http://bugs.kde.org
+ */
+
+class UMLClassifierListItem : public UMLObject {
+ Q_OBJECT
+public:
+ /**
+ * Constructor. Empty.
+ *
+ * @param parent The parent to this operation.
+ * At first sight it would appear that the type of the
+ * parent should be UMLClassifier. However, the class
+ * UMLAttribute is also used for the parameters of
+ * operations, and in this case the UMLOperation is the
+ * parent.
+ * @param name The name of the operation.
+ * @param id The id of the operation.
+ */
+ UMLClassifierListItem(const UMLObject *parent,
+ const QString& name,
+ Uml::IDType id = Uml::id_None);
+
+ /**
+ * Constructor. Empty.
+ *
+ * @param parent The parent to this operation.
+ * At first sight it would appear that the type of the
+ * parent should be UMLClassifier. However, the class
+ * UMLAttribute is also used for the parameters of
+ * operations, and in this case the UMLOperation is the
+ * parent.
+ */
+ UMLClassifierListItem(const UMLObject *parent);
+
+ /**
+ * Destructor. Empty.
+ */
+ virtual ~UMLClassifierListItem();
+
+ /**
+ * Returns the type of the UMLClassifierListItem.
+ *
+ * @return The type of the UMLClassifierListItem.
+ */
+ UMLClassifier * getType() const;
+
+ /**
+ * Returns the type name of the UMLClassifierListItem.
+ *
+ * @return The type name of the UMLClassifierListItem.
+ */
+ virtual QString getTypeName() const;
+
+ /**
+ * Sets the type name of the UMLClassifierListItem.
+ * DEPRECATED - use setType() instead.
+ *
+ * @param type The type name of the UMLClassifierListItem.
+ */
+ void setTypeName( const QString &type );
+
+ /**
+ * Sets the type of the UMLAttribute.
+ *
+ * @param type Pointer to the UMLObject of the type.
+ */
+ virtual void setType(UMLObject *type);
+
+ /**
+ * Returns a string representation of the list item.
+ *
+ * @param sig What type of operation string to show.
+ * @return The string representation of the operation.
+ */
+ virtual QString toString(Uml::Signature_Type sig = Uml::st_NoSig);
+
+ /**
+ * Display the properties configuration dialog for the list item.
+ *
+ * @param parent The parent widget.
+ * @return True for success of this operation.
+ */
+ virtual bool showPropertiesDialog(QWidget* parent) = 0;
+
+ /**
+ * Copy the internal presentation of this object into the new
+ * object.
+ */
+ virtual void copyInto(UMLClassifierListItem *rhs) const;
+
+ /**
+ * The abstract method UMLObject::clone() must be implemented
+ * by the classes inheriting from UMLClassifierListItem.
+ */
+ virtual UMLObject* clone() const = 0;
+
+};
+
+#endif
diff --git a/umbrello/umbrello/classifierwidget.cpp b/umbrello/umbrello/classifierwidget.cpp
new file mode 100644
index 00000000..4d4c1eb8
--- /dev/null
+++ b/umbrello/umbrello/classifierwidget.cpp
@@ -0,0 +1,803 @@
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * copyright (C) 2004-2007 *
+ * Umbrello UML Modeller Authors <uml-devel@uml.sf.net> *
+ ***************************************************************************/
+
+// own header
+#include "classifierwidget.h"
+// qt/kde includes
+#include <qpainter.h>
+#include <kdebug.h>
+// app includes
+#include "classifier.h"
+#include "operation.h"
+#include "template.h"
+#include "associationwidget.h"
+#include "umlview.h"
+#include "umldoc.h"
+#include "uml.h"
+#include "listpopupmenu.h"
+#include "object_factory.h"
+
+ClassifierWidget::ClassifierWidget(UMLView * view, UMLClassifier *c)
+ : UMLWidget(view, c) {
+ init();
+ if (c != NULL && c->isInterface()) {
+ WidgetBase::setBaseType(Uml::wt_Interface);
+ m_bShowStereotype = true;
+ m_bShowAttributes = false;
+ updateSigs();
+ }
+}
+
+ClassifierWidget::~ClassifierWidget() {
+ if (m_pAssocWidget)
+ m_pAssocWidget->removeAssocClassLine();
+}
+
+const int ClassifierWidget::MARGIN = 5;
+const int ClassifierWidget::CIRCLE_SIZE = 30;
+
+void ClassifierWidget::init() {
+ WidgetBase::setBaseType(Uml::wt_Class);
+
+ const Settings::OptionState& ops = m_pView->getOptionState();
+ m_bShowAccess = ops.classState.showVisibility;
+ m_bShowOperations = ops.classState.showOps;
+ m_bShowPublicOnly = false;
+ m_bShowPackage = ops.classState.showPackage;
+ m_ShowAttSigs = Uml::st_ShowSig;
+ /* setShowOpSigs( ops.classState.showOpSig );
+ Cannot do that because we get "pure virtual method called". Open code:
+ */
+ if( !ops.classState.showOpSig ) {
+ if (m_bShowAccess)
+ m_ShowOpSigs = Uml::st_NoSig;
+ else
+ m_ShowOpSigs = Uml::st_NoSigNoVis;
+
+ } else if (m_bShowAccess)
+ m_ShowOpSigs = Uml::st_ShowSig;
+ else
+ m_ShowOpSigs = Uml::st_SigNoVis;
+
+ m_bShowAttributes = ops.classState.showAtts;
+ m_bShowStereotype = ops.classState.showStereoType;
+ m_bDrawAsCircle = false;
+ m_pAssocWidget = NULL;
+ setShowAttSigs( ops.classState.showAttSig );
+}
+
+void ClassifierWidget::updateSigs() {
+ //turn on scope
+ if (m_bShowAccess) {
+ if (m_ShowOpSigs == Uml::st_NoSigNoVis) {
+ m_ShowOpSigs = Uml::st_NoSig;
+ } else if (m_ShowOpSigs == Uml::st_SigNoVis) {
+ m_ShowOpSigs = Uml::st_ShowSig;
+ }
+ } else { //turn off scope
+ if (m_ShowOpSigs == Uml::st_ShowSig) {
+ m_ShowOpSigs = Uml::st_SigNoVis;
+ } else if (m_ShowOpSigs == Uml::st_NoSig) {
+ m_ShowOpSigs = Uml::st_NoSigNoVis;
+ }
+ }
+ if (m_bShowAccess) {
+ if (m_ShowAttSigs == Uml::st_NoSigNoVis)
+ m_ShowAttSigs = Uml::st_NoSig;
+ else if (m_ShowAttSigs == Uml::st_SigNoVis)
+ m_ShowAttSigs = Uml::st_ShowSig;
+ } else {
+ if (m_ShowAttSigs == Uml::st_ShowSig)
+ m_ShowAttSigs = Uml::st_SigNoVis;
+ else if(m_ShowAttSigs == Uml::st_NoSig)
+ m_ShowAttSigs = Uml::st_NoSigNoVis;
+ }
+ updateComponentSize();
+ update();
+}
+
+void ClassifierWidget::toggleShowStereotype()
+{
+ m_bShowStereotype = !m_bShowStereotype;
+ updateSigs();
+ updateComponentSize();
+ update();
+}
+
+bool ClassifierWidget::getShowOps() const {
+ return m_bShowOperations;
+}
+
+void ClassifierWidget::setShowOps(bool _show) {
+ m_bShowOperations = _show;
+ updateSigs();
+ updateComponentSize();
+ update();
+}
+
+void ClassifierWidget::toggleShowOps() {
+ m_bShowOperations = !m_bShowOperations;
+ updateSigs();
+ updateComponentSize();
+ update();
+}
+
+bool ClassifierWidget::getShowPublicOnly() const {
+ return m_bShowPublicOnly;
+}
+
+void ClassifierWidget::setShowPublicOnly(bool _status) {
+ m_bShowPublicOnly = _status;
+ updateComponentSize();
+ update();
+}
+
+void ClassifierWidget::toggleShowPublicOnly() {
+ m_bShowPublicOnly = !m_bShowPublicOnly;
+ updateComponentSize();
+ update();
+}
+
+bool ClassifierWidget::getShowVisibility() const {
+ return m_bShowAccess;
+}
+
+void ClassifierWidget::setShowVisibility(bool _visibility) {
+ m_bShowAccess = _visibility;
+ updateSigs();
+ updateComponentSize();
+ update();
+}
+
+void ClassifierWidget::toggleShowVisibility() {
+ m_bShowAccess = !m_bShowAccess;
+ updateSigs();
+ updateComponentSize();
+ update();
+}
+
+Uml::Signature_Type ClassifierWidget::getShowOpSigs() const {
+ return m_ShowOpSigs;
+}
+
+void ClassifierWidget::setShowOpSigs(bool _status) {
+ if( !_status ) {
+ if (m_bShowAccess)
+ m_ShowOpSigs = Uml::st_NoSig;
+ else
+ m_ShowOpSigs = Uml::st_NoSigNoVis;
+ } else if (m_bShowAccess)
+ m_ShowOpSigs = Uml::st_ShowSig;
+ else
+ m_ShowOpSigs = Uml::st_SigNoVis;
+ updateComponentSize();
+ update();
+}
+
+void ClassifierWidget::toggleShowOpSigs() {
+ if (m_ShowOpSigs == Uml::st_ShowSig || m_ShowOpSigs == Uml::st_SigNoVis) {
+ if (m_bShowAccess) {
+ m_ShowOpSigs = Uml::st_NoSig;
+ } else {
+ m_ShowOpSigs = Uml::st_NoSigNoVis;
+ }
+ } else if (m_bShowAccess) {
+ m_ShowOpSigs = Uml::st_ShowSig;
+ } else {
+ m_ShowOpSigs = Uml::st_SigNoVis;
+ }
+ updateComponentSize();
+ update();
+}
+
+bool ClassifierWidget::getShowPackage() const {
+ return m_bShowPackage;
+}
+
+void ClassifierWidget::setShowPackage(bool _status) {
+ m_bShowPackage = _status;
+ updateComponentSize();
+ update();
+}
+
+void ClassifierWidget::toggleShowPackage() {
+ m_bShowPackage = !m_bShowPackage;
+ updateSigs();
+ updateComponentSize();
+ update();
+}
+
+void ClassifierWidget::setOpSignature(Uml::Signature_Type sig) {
+ m_ShowOpSigs = sig;
+ updateSigs();
+ updateComponentSize();
+ update();
+}
+
+void ClassifierWidget::setShowAtts(bool _show) {
+ m_bShowAttributes = _show;
+ updateSigs();
+
+ updateComponentSize();
+ update();
+}
+
+void ClassifierWidget::setAttSignature(Uml::Signature_Type sig) {
+ m_ShowAttSigs = sig;
+ updateSigs();
+ updateComponentSize();
+ update();
+}
+
+void ClassifierWidget::setShowAttSigs(bool _status) {
+ if( !_status ) {
+ if (m_bShowAccess)
+ m_ShowAttSigs = Uml::st_NoSig;
+ else
+ m_ShowAttSigs = Uml::st_NoSigNoVis;
+ }
+ else if (m_bShowAccess)
+ m_ShowAttSigs = Uml::st_ShowSig;
+ else
+ m_ShowAttSigs = Uml::st_SigNoVis;
+ if (UMLApp::app()->getDocument()->loading())
+ return;
+ updateComponentSize();
+ update();
+}
+
+void ClassifierWidget::toggleShowAtts()
+{
+ m_bShowAttributes = !m_bShowAttributes;
+ updateSigs();
+ updateComponentSize();
+ update();
+}
+
+void ClassifierWidget::toggleShowAttSigs()
+{
+ if (m_ShowAttSigs == Uml::st_ShowSig ||
+ m_ShowAttSigs == Uml::st_SigNoVis) {
+ if (m_bShowAccess) {
+ m_ShowAttSigs = Uml::st_NoSig;
+ } else {
+ m_ShowAttSigs = Uml::st_NoSigNoVis;
+ }
+ } else if (m_bShowAccess) {
+ m_ShowAttSigs = Uml::st_ShowSig;
+ } else {
+ m_ShowAttSigs = Uml::st_SigNoVis;
+ }
+ updateComponentSize();
+ update();
+}
+
+int ClassifierWidget::displayedMembers(Uml::Object_Type ot) {
+ int count = 0;
+ UMLClassifierListItemList list = getClassifier()->getFilteredList(ot);
+ for (UMLClassifierListItem *m = list.first(); m; m = list.next()) {
+ if (!(m_bShowPublicOnly && m->getVisibility() != Uml::Visibility::Public))
+ count++;
+ }
+ return count;
+}
+
+int ClassifierWidget::displayedOperations() {
+ if (!m_bShowOperations)
+ return 0;
+ return displayedMembers(Uml::ot_Operation);
+}
+
+QSize ClassifierWidget::calculateSize() {
+ if (!m_pObject) {
+ return UMLWidget::calculateSize();
+ }
+ if (getClassifier()->isInterface() && m_bDrawAsCircle) {
+ return calculateAsCircleSize();
+ }
+
+ const QFontMetrics &fm = getFontMetrics(UMLWidget::FT_NORMAL);
+ const int fontHeight = fm.lineSpacing();
+ // width is the width of the longest 'word'
+ int width = 0, height = 0;
+
+ // consider stereotype
+ if (m_bShowStereotype && !m_pObject->getStereotype().isEmpty()) {
+ height += fontHeight;
+ // ... width
+ const QFontMetrics &bfm = UMLWidget::getFontMetrics(UMLWidget::FT_BOLD);
+ const int stereoWidth = bfm.size(0,m_pObject->getStereotype(true)).width();
+ if (stereoWidth > width)
+ width = stereoWidth;
+ }
+
+ // consider name
+ height += fontHeight;
+ // ... width
+ QString displayedName;
+ if (m_bShowPackage)
+ displayedName = m_pObject->getFullyQualifiedName();
+ else
+ displayedName = m_pObject->getName();
+ const UMLWidget::FontType nft = (m_pObject->getAbstract() ? FT_BOLD_ITALIC : FT_BOLD);
+ //const int nameWidth = getFontMetrics(nft).boundingRect(displayName).width();
+ const int nameWidth = UMLWidget::getFontMetrics(nft).size(0,displayedName).width();
+ if (nameWidth > width)
+ width = nameWidth;
+
+ // consider attributes
+ const int numAtts = displayedAttributes();
+ if (numAtts == 0) {
+ height += fontHeight / 2; // no atts, so just add a bit of space
+ } else {
+ height += fontHeight * numAtts;
+ // calculate width of the attributes
+ UMLClassifierListItemList list = getClassifier()->getFilteredList(Uml::ot_Attribute);
+ for (UMLClassifierListItem *a = list.first(); a; a = list.next()) {
+ if (m_bShowPublicOnly && a->getVisibility() != Uml::Visibility::Public)
+ continue;
+ const int attWidth = fm.size(0,a->toString(m_ShowAttSigs)).width();
+ if (attWidth > width)
+ width = attWidth;
+ }
+ }
+
+ // consider operations
+ const int numOps = displayedOperations();
+ if (numOps == 0) {
+ height += fontHeight / 2; // no ops, so just add a bit of space
+ } else {
+ height += numOps * fontHeight;
+ // ... width
+ UMLOperationList list(getClassifier()->getOpList());
+ for (UMLOperation* op = list.first(); op; op = list.next()) {
+ if (m_bShowPublicOnly && op->getVisibility() != Uml::Visibility::Public)
+ continue;
+ const QString displayedOp = op->toString(m_ShowOpSigs);
+ UMLWidget::FontType oft;
+ oft = (op->getAbstract() ? UMLWidget::FT_ITALIC : UMLWidget::FT_NORMAL);
+ const int w = UMLWidget::getFontMetrics(oft).size(0,displayedOp).width();
+ if (w > width)
+ width = w;
+ }
+ }
+
+ // consider template box _as last_ !
+ QSize templatesBoxSize = calculateTemplatesBoxSize();
+ if (templatesBoxSize.width() != 0) {
+ // add width to largest 'word'
+ width += templatesBoxSize.width() / 2;
+ }
+ if (templatesBoxSize.height() != 0) {
+ height += templatesBoxSize.height() - MARGIN;
+ }
+
+
+ // allow for height margin
+ if (!m_bShowOperations && !m_bShowAttributes && !m_bShowStereotype) {
+ height += MARGIN * 2;
+ }
+
+ // allow for width margin
+ width += MARGIN * 2;
+
+ return QSize(width, height);
+}
+
+void ClassifierWidget::slotMenuSelection(int sel) {
+ ListPopupMenu::Menu_Type mt = (ListPopupMenu::Menu_Type)sel;
+ switch (mt) {
+ case ListPopupMenu::mt_Attribute:
+ case ListPopupMenu::mt_Operation:
+ case ListPopupMenu::mt_Template:
+ {
+ Uml::Object_Type ot = ListPopupMenu::convert_MT_OT(mt);
+ if (Object_Factory::createChildObject(getClassifier(), ot)) {
+ updateComponentSize();
+ update();
+ UMLApp::app()->getDocument()->setModified();
+ }
+ break;
+ }
+ case ListPopupMenu::mt_Show_Operations:
+ case ListPopupMenu::mt_Show_Operations_Selection:
+ toggleShowOps();
+ break;
+
+ case ListPopupMenu::mt_Show_Attributes:
+ case ListPopupMenu::mt_Show_Attributes_Selection:
+ toggleShowAtts();
+ break;
+
+ case ListPopupMenu::mt_Show_Public_Only:
+ case ListPopupMenu::mt_Show_Public_Only_Selection:
+ toggleShowPublicOnly();
+ break;
+
+ case ListPopupMenu::mt_Show_Operation_Signature:
+ case ListPopupMenu::mt_Show_Operation_Signature_Selection:
+ toggleShowOpSigs();
+ break;
+
+ case ListPopupMenu::mt_Show_Attribute_Signature:
+ case ListPopupMenu::mt_Show_Attribute_Signature_Selection:
+ toggleShowAttSigs();
+ break;
+
+ case ListPopupMenu::mt_Visibility:
+ case ListPopupMenu::mt_Visibility_Selection:
+ toggleShowVisibility();
+ break;
+
+ case ListPopupMenu::mt_Show_Packages:
+ case ListPopupMenu::mt_Show_Packages_Selection:
+ toggleShowPackage();
+ break;
+
+ case ListPopupMenu::mt_Show_Stereotypes:
+ case ListPopupMenu::mt_Show_Stereotypes_Selection:
+ toggleShowStereotype();
+ break;
+
+ case ListPopupMenu::mt_DrawAsCircle:
+ case ListPopupMenu::mt_DrawAsCircle_Selection:
+ toggleDrawAsCircle();
+ break;
+
+ case ListPopupMenu::mt_ChangeToClass:
+ case ListPopupMenu::mt_ChangeToClass_Selection:
+ changeToClass();
+ break;
+
+ case ListPopupMenu::mt_ChangeToInterface:
+ case ListPopupMenu::mt_ChangeToInterface_Selection:
+ changeToInterface();
+ break;
+
+ default:
+ UMLWidget::slotMenuSelection(sel);
+ break;
+ }
+}
+
+QSize ClassifierWidget::calculateTemplatesBoxSize() {
+ UMLTemplateList list = getClassifier()->getTemplateList();
+ int count = list.count();
+ if (count == 0) {
+ return QSize(0, 0);
+ }
+
+ int width, height;
+ height = width = 0;
+
+ QFont font = UMLWidget::getFont();
+ font.setItalic(false);
+ font.setUnderline(false);
+ font.setBold(false);
+ const QFontMetrics fm(font);
+
+ height = count * fm.lineSpacing() + (MARGIN*2);
+
+ for (UMLTemplate *t = list.first(); t; t = list.next()) {
+ int textWidth = fm.size(0, t->toString() ).width();
+ if (textWidth > width)
+ width = textWidth;
+ }
+
+ width += (MARGIN*2);
+ return QSize(width, height);
+}
+
+int ClassifierWidget::displayedAttributes() {
+ if (!m_bShowAttributes)
+ return 0;
+ return displayedMembers(Uml::ot_Attribute);
+}
+
+void ClassifierWidget::setClassAssocWidget(AssociationWidget *assocwidget) {
+ m_pAssocWidget = assocwidget;
+ UMLAssociation *umlassoc = NULL;
+ if (assocwidget)
+ umlassoc = assocwidget->getAssociation();
+ getClassifier()->setClassAssoc(umlassoc);
+}
+
+AssociationWidget *ClassifierWidget::getClassAssocWidget() {
+ return m_pAssocWidget;
+}
+
+UMLClassifier *ClassifierWidget::getClassifier() {
+ return static_cast<UMLClassifier*>(m_pObject);
+}
+
+void ClassifierWidget::draw(QPainter & p, int offsetX, int offsetY) {
+ UMLWidget::setPen(p);
+ if ( UMLWidget::getUseFillColour() )
+ p.setBrush( UMLWidget::getFillColour() );
+ else
+ p.setBrush( m_pView->viewport()->backgroundColor() );
+
+ if (getClassifier()->isInterface() && m_bDrawAsCircle) {
+ drawAsCircle(p, offsetX, offsetY);
+ return;
+ }
+
+ // Draw the bounding rectangle
+ QSize templatesBoxSize = calculateTemplatesBoxSize();
+ m_bodyOffsetY = offsetY;
+ if (templatesBoxSize.height() > 0)
+ m_bodyOffsetY += templatesBoxSize.height() - MARGIN;
+ int w = width();
+ if (templatesBoxSize.width() > 0)
+ w -= templatesBoxSize.width() / 2;
+ int h = height();
+ if (templatesBoxSize.height() > 0)
+ h -= templatesBoxSize.height() - MARGIN;
+ p.drawRect(offsetX, m_bodyOffsetY, w, h);
+
+ QFont font = UMLWidget::getFont();
+ font.setUnderline(false);
+ font.setItalic(false);
+ const QFontMetrics fm = UMLWidget::getFontMetrics(UMLWidget::FT_NORMAL);
+ const int fontHeight = fm.lineSpacing();
+
+ //If there are any templates then draw them
+ UMLTemplateList tlist = getClassifier()->getTemplateList();
+ if ( tlist.count() > 0 ) {
+ UMLWidget::setPen(p);
+ QPen pen = p.pen();
+ pen.setStyle(Qt::DotLine);
+ p.setPen(pen);
+ p.drawRect( offsetX + width() - templatesBoxSize.width(), offsetY,
+ templatesBoxSize.width(), templatesBoxSize.height() );
+ p.setPen( QPen(Qt::black) );
+ font.setBold(false);
+ p.setFont(font);
+ const int x = offsetX + width() - templatesBoxSize.width() + MARGIN;
+ int y = offsetY + MARGIN;
+ for ( UMLTemplate *t = tlist.first(); t; t = tlist.next() ) {
+ QString text = t->toString();
+ p.drawText(x, y, fm.size(0,text).width(), fontHeight, Qt::AlignVCenter, text);
+ y += fontHeight;
+ }
+ }
+
+ const int textX = offsetX + MARGIN;
+ const int textWidth = w - MARGIN * 2;
+
+ p.setPen(QPen(Qt::black));
+
+ // draw stereotype
+ font.setBold(true);
+ QString stereo = m_pObject->getStereotype();
+ /* if no stereotype is given we don't want to show the empty << >> */
+ const bool showStereotype = (m_bShowStereotype && !stereo.isEmpty());
+ const bool showNameOnly = (!m_bShowOperations && !m_bShowAttributes && !showStereotype);
+ int nameHeight = fontHeight;
+ if (showNameOnly) {
+ nameHeight = h;
+ } else if (showStereotype) {
+ p.setFont(font);
+ stereo = m_pObject->getStereotype(true);
+ p.drawText(textX, m_bodyOffsetY, textWidth, fontHeight, Qt::AlignCenter, stereo);
+ m_bodyOffsetY += fontHeight;
+ }
+
+ // draw name
+ QString name;
+ if (m_bShowPackage) {
+ name = m_pObject->getFullyQualifiedName();
+ } else {
+ name = this->getName();
+ }
+ font.setItalic( m_pObject->getAbstract() );
+ p.setFont(font);
+ p.drawText(textX, m_bodyOffsetY, textWidth, nameHeight, Qt::AlignCenter, name);
+ if (!showNameOnly) {
+ m_bodyOffsetY += fontHeight;
+ UMLWidget::setPen(p);
+ p.drawLine(offsetX, m_bodyOffsetY, offsetX + w - 1, m_bodyOffsetY);
+ p.setPen(QPen(Qt::black));
+ }
+ font.setBold(false);
+ font.setItalic(false);
+ p.setFont(font);
+
+ // draw attributes
+ const int numAtts = displayedAttributes();
+ if (m_bShowAttributes) {
+ drawMembers(p, Uml::ot_Attribute, m_ShowAttSigs, textX,
+ m_bodyOffsetY, fontHeight);
+ }
+
+ // draw dividing line between attributes and operations
+ if (!showNameOnly) {
+ if (numAtts == 0)
+ m_bodyOffsetY += fontHeight / 2; // no atts, so just add a bit of space
+ else
+ m_bodyOffsetY += fontHeight * numAtts;
+ UMLWidget::setPen(p);
+ p.drawLine(offsetX, m_bodyOffsetY, offsetX + w - 1, m_bodyOffsetY);
+ p.setPen(QPen(Qt::black));
+ }
+
+ // draw operations
+ if (m_bShowOperations) {
+ drawMembers(p, Uml::ot_Operation, m_ShowOpSigs, textX,
+ m_bodyOffsetY, fontHeight);
+ }
+
+ if (UMLWidget::m_bSelected)
+ UMLWidget::drawSelected(&p, offsetX, offsetY);
+}
+
+void ClassifierWidget::drawAsCircle(QPainter& p, int offsetX, int offsetY) {
+ int w = width();
+
+ const QFontMetrics &fm = getFontMetrics(FT_NORMAL);
+ const int fontHeight = fm.lineSpacing();
+ QString name;
+ if ( m_bShowPackage ) {
+ name = m_pObject->getFullyQualifiedName();
+ } else {
+ name = this -> getName();
+ }
+
+ p.drawEllipse(offsetX + w/2 - CIRCLE_SIZE/2, offsetY, CIRCLE_SIZE, CIRCLE_SIZE);
+ p.setPen( QPen(Qt::black) );
+
+ QFont font = UMLWidget::getFont();
+ p.setFont(font);
+ p.drawText(offsetX, offsetY + CIRCLE_SIZE, w, fontHeight, Qt::AlignCenter, name);
+
+ if (m_bSelected) {
+ drawSelected(&p, offsetX, offsetY);
+ }
+}
+
+QSize ClassifierWidget::calculateAsCircleSize() {
+ const QFontMetrics &fm = UMLWidget::getFontMetrics(UMLWidget::FT_ITALIC_UNDERLINE);
+ const int fontHeight = fm.lineSpacing();
+
+ int height = CIRCLE_SIZE + fontHeight;
+
+ int width = CIRCLE_SIZE;
+ QString displayedName;
+ if (m_bShowPackage) {
+ displayedName = m_pObject->getFullyQualifiedName();
+ } else {
+ displayedName = m_pObject->getName();
+ }
+ const int nameWidth = fm.size(0,displayedName).width();
+ if (nameWidth > width)
+ width = nameWidth;
+ width += MARGIN * 2;
+
+ return QSize(width, height);
+}
+
+void ClassifierWidget::drawMembers(QPainter & p, Uml::Object_Type ot, Uml::Signature_Type sigType,
+ int x, int y, int fontHeight) {
+ QFont f = UMLWidget::getFont();
+ f.setBold(false);
+ UMLClassifierListItemList list = getClassifier()->getFilteredList(ot);
+ for (UMLClassifierListItem *obj = list.first(); obj; obj = list.next()) {
+ if (m_bShowPublicOnly && obj->getVisibility() != Uml::Visibility::Public)
+ continue;
+ QString text = obj->toString(sigType);
+ f.setItalic( obj->getAbstract() );
+ f.setUnderline( obj->getStatic() );
+ p.setFont( f );
+ QFontMetrics fontMetrics(f);
+ p.drawText(x, y, fontMetrics.size(0,text).width(), fontHeight, Qt::AlignVCenter, text);
+ f.setItalic(false);
+ f.setUnderline(false);
+ p.setFont(f);
+ y += fontHeight;
+ }
+}
+
+void ClassifierWidget::setDrawAsCircle(bool drawAsCircle) {
+ m_bDrawAsCircle = drawAsCircle;
+ updateComponentSize();
+ update();
+}
+
+bool ClassifierWidget::getDrawAsCircle() const {
+ return m_bDrawAsCircle;
+}
+
+void ClassifierWidget::toggleDrawAsCircle() {
+ m_bDrawAsCircle = !m_bDrawAsCircle;
+ updateSigs();
+ updateComponentSize();
+ update();
+}
+
+void ClassifierWidget::changeToClass() {
+ WidgetBase::setBaseType(Uml::wt_Class);
+ getClassifier()->setBaseType(Uml::ot_Class);
+
+ const Settings::OptionState& ops = m_pView->getOptionState();
+ m_bShowAttributes = ops.classState.showAtts;
+ m_bShowStereotype = ops.classState.showStereoType;
+
+ updateComponentSize();
+ update();
+}
+
+void ClassifierWidget::changeToInterface() {
+ WidgetBase::setBaseType(Uml::wt_Interface);
+ getClassifier()->setBaseType(Uml::ot_Interface);
+
+ m_bShowAttributes = false;
+ m_bShowStereotype = true;
+
+ updateComponentSize();
+ update();
+}
+
+void ClassifierWidget::adjustAssocs(int x, int y) {
+ UMLWidget::adjustAssocs(x, y);
+
+ if (m_pDoc->loading() || m_pAssocWidget == 0) {
+ return;
+ }
+
+ m_pAssocWidget->computeAssocClassLine();
+}
+
+void ClassifierWidget::saveToXMI(QDomDocument & qDoc, QDomElement & qElement) {
+ QDomElement conceptElement;
+ UMLClassifier *umlc = getClassifier();
+ if (umlc->isInterface())
+ conceptElement = qDoc.createElement("interfacewidget");
+ else
+ conceptElement = qDoc.createElement("classwidget");
+ UMLWidget::saveToXMI( qDoc, conceptElement );
+ conceptElement.setAttribute( "showoperations", m_bShowOperations );
+ conceptElement.setAttribute( "showpubliconly", m_bShowPublicOnly );
+ conceptElement.setAttribute( "showopsigs", m_ShowOpSigs );
+ conceptElement.setAttribute( "showpackage", m_bShowPackage );
+ conceptElement.setAttribute( "showscope", m_bShowAccess );
+ if (! umlc->isInterface()) {
+ conceptElement.setAttribute("showattributes", m_bShowAttributes);
+ conceptElement.setAttribute("showattsigs", m_ShowAttSigs);
+ }
+ if (umlc->isInterface() || umlc->getAbstract())
+ conceptElement.setAttribute("drawascircle", m_bDrawAsCircle);
+ qElement.appendChild( conceptElement );
+}
+
+bool ClassifierWidget::loadFromXMI(QDomElement & qElement) {
+ if (!UMLWidget::loadFromXMI(qElement))
+ return false;
+ QString showatts = qElement.attribute( "showattributes", "0" );
+ QString showops = qElement.attribute( "showoperations", "1" );
+ QString showpubliconly = qElement.attribute( "showpubliconly", "0" );
+ QString showattsigs = qElement.attribute( "showattsigs", "600" );
+ QString showopsigs = qElement.attribute( "showopsigs", "600" );
+ QString showpackage = qElement.attribute( "showpackage", "0" );
+ QString showscope = qElement.attribute( "showscope", "0" );
+ QString drawascircle = qElement.attribute("drawascircle", "0");
+
+ m_bShowAttributes = (bool)showatts.toInt();
+ m_bShowOperations = (bool)showops.toInt();
+ m_bShowPublicOnly = (bool)showpubliconly.toInt();
+ m_ShowAttSigs = (Uml::Signature_Type)showattsigs.toInt();
+ m_ShowOpSigs = (Uml::Signature_Type)showopsigs.toInt();
+ m_bShowPackage = (bool)showpackage.toInt();
+ m_bShowAccess = (bool)showscope.toInt();
+ m_bDrawAsCircle = (bool)drawascircle.toInt();
+
+ return true;
+}
+
diff --git a/umbrello/umbrello/classifierwidget.h b/umbrello/umbrello/classifierwidget.h
new file mode 100644
index 00000000..17172460
--- /dev/null
+++ b/umbrello/umbrello/classifierwidget.h
@@ -0,0 +1,390 @@
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * copyright (C) 2004-2006 *
+ * Umbrello UML Modeller Authors <uml-devel@uml.sf.net> *
+ ***************************************************************************/
+
+#ifndef CLASSIFIERWIDGET_H
+#define CLASSIFIERWIDGET_H
+
+#include "umlwidget.h"
+
+class QPainter;
+class UMLClassifier;
+class AssociationWidget;
+
+/**
+ * @short Common implementation for class widget and interface widget
+ * @author Oliver Kellogg
+ * @see UMLWidget
+ * Bugs and comments to uml-devel@lists.sf.net or http://bugs.kde.org
+ */
+class ClassifierWidget : public UMLWidget {
+public:
+
+ /**
+ * Constructs a ClassifierWidget.
+ *
+ * @param view The parent of this ClassifierWidget.
+ * @param o The UMLObject to represent.
+ */
+ ClassifierWidget(UMLView * view, UMLClassifier * o);
+
+ /**
+ * Destructor.
+ */
+ virtual ~ClassifierWidget();
+
+ /**
+ * Toggles the status of whether to show StereoType.
+ */
+ void toggleShowStereotype();
+
+ /**
+ * Return the status of showing operations.
+ *
+ * @return Return the status of showing operations.
+ */
+ bool getShowOps() const;
+
+ /**
+ * Set the status of whether to show Operations
+ *
+ * @param _show True if operations shall be shown.
+ */
+ void setShowOps(bool _show);
+
+ /**
+ * Toggles the status of showing operations.
+ */
+ void toggleShowOps();
+
+ /**
+ * Return true if public operations/attributes are shown only.
+ */
+ bool getShowPublicOnly() const;
+
+ /**
+ * Set whether to show public operations/attributes only.
+ */
+ void setShowPublicOnly(bool _status);
+
+ /**
+ * Toggle whether to show public operations/attributes only.
+ */
+ void toggleShowPublicOnly();
+
+ /**
+ * Returns the status of whether to show visibility.
+ *
+ * @return True if visibility is shown.
+ */
+ bool getShowVisibility() const;
+
+ /**
+ * Set the status of whether to show visibility
+ *
+ * @param _visibility True if visibility shall be shown.
+ */
+ void setShowVisibility(bool _visibility);
+
+ /**
+ * Toggles the status of whether to show visibility
+ */
+ void toggleShowVisibility();
+
+ /**
+ * Return the status of showing operation signatures.
+ *
+ * @return Status of showing operation signatures.
+ */
+ Uml::Signature_Type getShowOpSigs() const;
+
+ /**
+ * Set the status of whether to show Operation signature
+ *
+ * @param _show True if operation signatures shall be shown.
+ */
+ void setShowOpSigs(bool _show);
+
+ /**
+ * Toggles the status of showing operation signatures.
+ */
+ void toggleShowOpSigs();
+
+ /**
+ * Returns the status of whether to show Package.
+ *
+ * @return True if package is shown.
+ */
+ bool getShowPackage() const;
+
+ /**
+ * Set the status of whether to show Package.
+ *
+ * @param _status True if package shall be shown.
+ */
+ void setShowPackage(bool _status);
+
+ /**
+ * Toggles the status of whether to show package.
+ */
+ void toggleShowPackage();
+
+ /**
+ * Set the type of signature to display for an Operation
+ *
+ * @param sig Type of signature to display for an operation.
+ */
+ void setOpSignature(Uml::Signature_Type sig);
+
+ /**
+ * Return the number of displayed attributes.
+ */
+ int displayedAttributes();
+
+ /**
+ * Return the number of displayed operations.
+ */
+ int displayedOperations();
+
+ /**
+ * Returns whether to show attributes.
+ * Only applies when m_pObject->getBaseType() is ot_Class.
+ *
+ * @return True if attributes are shown.
+ */
+ bool getShowAtts() const {
+ return m_bShowAttributes;
+ }
+
+ /**
+ * Toggles whether to show attributes.
+ * Only applies when m_pObject->getBaseType() is ot_Class.
+ */
+ void toggleShowAtts();
+
+ /**
+ * Returns whether to show attribute signatures.
+ * Only applies when m_pObject->getBaseType() is ot_Class.
+ *
+ * @return Status of how attribute signatures are shown.
+ */
+ Uml::Signature_Type getShowAttSigs() {
+ return m_ShowAttSigs;
+ }
+
+ /**
+ * Toggles whether to show attribute signatures.
+ * Only applies when m_pObject->getBaseType() is ot_Class.
+ */
+ void toggleShowAttSigs();
+
+ /**
+ * Sets whether to show attributes.
+ * Only applies when m_pObject->getBaseType() is ot_Class.
+ *
+ * @param _show True if attributes shall be shown.
+ */
+ void setShowAtts(bool _show);
+
+ /**
+ * Sets whether to show attribute signature
+ * Only applies when m_pObject->getBaseType() is ot_Class.
+ *
+ * @param _show True if attribute signatures shall be shown.
+ */
+ void setShowAttSigs(bool _show);
+
+ /**
+ * Sets the type of signature to display for an attribute.
+ * Only applies when m_pObject->getBaseType() is ot_Class.
+ *
+ * @param sig Type of signature to display for an attribute.
+ */
+ void setAttSignature(Uml::Signature_Type sig);
+
+ /**
+ * Returns whether to draw as circle.
+ * Only applies when m_pObject->getBaseType() is ot_Interface.
+ *
+ * @return True if widget is drawn as circle.
+ */
+ bool getDrawAsCircle() const;
+
+ /**
+ * Toggles whether to draw as circle.
+ * Only applies when m_pObject->getBaseType() is ot_Interface.
+ */
+ void toggleDrawAsCircle();
+
+ /**
+ * Sets whether to draw as circle.
+ * Only applies when m_pObject->getBaseType() is ot_Interface.
+ *
+ * @param drawAsCircle True if widget shall be drawn as circle.
+ */
+ void setDrawAsCircle(bool drawAsCircle);
+
+ /**
+ * Changes this classifier from an interface to a class.
+ * Attributes and stereotype visibility is got from the view OptionState.
+ * This widget is also updated.
+ */
+ void changeToClass();
+
+ /**
+ * Changes this classifier from a class to an interface.
+ * Attributes are hidden and stereotype is shown.
+ * This widget is also updated.
+ */
+ void changeToInterface();
+
+ /**
+ * Set the AssociationWidget when this ClassWidget acts as
+ * an association class.
+ */
+ void setClassAssocWidget(AssociationWidget *assocwidget);
+
+ /**
+ * Return the AssociationWidget when this classifier acts as
+ * an association class (else return NULL.)
+ */
+ AssociationWidget *getClassAssocWidget();
+
+ /**
+ * Return the UMLClassifier which this ClassifierWidget
+ * represents.
+ */
+ UMLClassifier *getClassifier();
+
+ /**
+ * Overrides standard method.
+ * Auxiliary to reimplementations in the derived classes.
+ */
+ void draw(QPainter & p, int offsetX, int offsetY);
+
+ /**
+ * Extends base method to adjust also the association of a class
+ * association.
+ * Executes the base method and then, if file isn't loading and the
+ * classifier acts as a class association, the association position is
+ * updated.
+ *
+ * @param x The x-coordinate.
+ * @param y The y-coordinate.
+ */
+ virtual void adjustAssocs(int x, int y);
+
+ /**
+ * Creates the "classwidget" or "interfacewidget" XML element.
+ */
+ void saveToXMI(QDomDocument & qDoc, QDomElement & qElement);
+
+ /**
+ * Loads the "classwidget" or "interfacewidget" XML element.
+ */
+ bool loadFromXMI(QDomElement & qElement);
+
+public slots:
+ /**
+ * Will be called when a menu selection has been made from the
+ * popup menu.
+ *
+ * @param sel The selection id that has been selected.
+ */
+ void slotMenuSelection(int sel);
+
+protected:
+
+ /**
+ * Initializes key variables of the class.
+ */
+ void init();
+
+ /**
+ * Calculcates the size of the templates box in the top left
+ * if it exists, returns QSize(0,0) if it doesn't.
+ *
+ * @return QSize of the templates flap.
+ */
+ QSize calculateTemplatesBoxSize();
+
+ /**
+ * Overrides method from UMLWidget.
+ */
+ QSize calculateSize();
+
+ /**
+ * Draws the interface as a circle with name underneath.
+ * Only applies when m_pObject->getBaseType() is ot_Interface.
+ */
+ void drawAsCircle(QPainter& p, int offsetX, int offsetY);
+
+ /**
+ * Calculates the size of the object when drawn as a circle.
+ * Only applies when m_pObject->getBaseType() is ot_Interface.
+ */
+ QSize calculateAsCircleSize();
+
+ /**
+ * Updates m_ShowOpSigs to match m_bShowVisibility.
+ */
+ void updateSigs();
+
+ /**
+ * Return the number of displayed members of the given Object_Type.
+ * Takes into consideration m_bShowPublicOnly but not other settings,
+ */
+ int displayedMembers(Uml::Object_Type ot);
+
+ /**
+ * Auxiliary method for draw() of child classes:
+ * Draw the attributes or operations.
+ *
+ * @param p QPainter to paint to.
+ * @param ot Object type to draw, either ot_Attribute or ot_Operation.
+ * @param sigType Governs details of the member display.
+ * @param x X coordinate at which to draw the texts.
+ * @param y Y coordinate at which text drawing commences.
+ * @param fontHeight The font height.
+ */
+ void drawMembers(QPainter & p, Uml::Object_Type ot, Uml::Signature_Type sigType,
+ int x, int y, int fontHeight);
+
+ bool m_bShowOperations; ///< Loaded/saved item.
+ bool m_bShowPublicOnly; ///< Loaded/saved item.
+ bool m_bShowAccess; ///< Loaded/saved item.
+ bool m_bShowPackage; ///< Loaded/saved item.
+ bool m_bShowAttributes; ///< Loaded/saved item.
+ bool m_bDrawAsCircle; ///< Loaded/saved item.
+ Uml::Signature_Type m_ShowAttSigs; ///< Loaded/saved item.
+ Uml::Signature_Type m_ShowOpSigs; ///< Loaded/saved item.
+
+ /**
+ * Text width margin
+ */
+ static const int MARGIN;
+
+ /**
+ * Size of circle when interface is rendered as such
+ */
+ static const int CIRCLE_SIZE;
+
+ /// Auxiliary variable for size calculations and drawing
+ int m_bodyOffsetY;
+
+ /**
+ * The related AssociationWidget in case this classifier
+ * acts as an association class
+ */
+ AssociationWidget *m_pAssocWidget;
+
+};
+
+#endif
diff --git a/umbrello/umbrello/clipboard/Makefile.am b/umbrello/umbrello/clipboard/Makefile.am
new file mode 100644
index 00000000..91dc58f7
--- /dev/null
+++ b/umbrello/umbrello/clipboard/Makefile.am
@@ -0,0 +1,6 @@
+INCLUDES = -I$(top_builddir)/umbrello/umbrello/dialogs $(all_includes)
+
+METASOURCES = AUTO
+
+noinst_LTLIBRARIES = libclipboard.la
+libclipboard_la_SOURCES = umldrag.cpp umlclipboard.cpp idchangelog.cpp
diff --git a/umbrello/umbrello/clipboard/idchangelog.cpp b/umbrello/umbrello/clipboard/idchangelog.cpp
new file mode 100644
index 00000000..1521c1cc
--- /dev/null
+++ b/umbrello/umbrello/clipboard/idchangelog.cpp
@@ -0,0 +1,97 @@
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * copyright (C) 2002-2007 *
+ * Umbrello UML Modeller Authors <uml-devel@uml.sf.net> *
+ ***************************************************************************/
+
+#include "idchangelog.h"
+
+#include <kdebug.h>
+
+IDChangeLog::IDChangeLog() {}
+
+IDChangeLog::IDChangeLog(const IDChangeLog& Other) {
+ m_LogArray = Other.m_LogArray;
+}
+
+IDChangeLog::~IDChangeLog() {}
+
+IDChangeLog& IDChangeLog::operator=(const IDChangeLog& Other) {
+ m_LogArray = Other.m_LogArray;
+
+ return *this;
+}
+
+bool IDChangeLog::operator==(const IDChangeLog& /*Other*/) {
+ /*It needs to be Implemented*/
+ return false;
+}
+
+Uml::IDType IDChangeLog::findNewID(Uml::IDType OldID) {
+ uint count = m_LogArray.size();
+ for(uint i = 0; i < count; i++) {
+ if((m_LogArray.point(i)).y() == OldID) {
+ return (m_LogArray.point(i)).x();
+ }
+ }
+
+ return Uml::id_None;
+}
+
+IDChangeLog& IDChangeLog::operator+=(const IDChangeLog& Other) {
+ //m_LogArray.putpoints(m_LogArray.size(), Other.m_LogArray.size(), Other)
+ uint count = Other.m_LogArray.size();
+ for(uint i = 0; i < count; i++) {
+ addIDChange((Other.m_LogArray.point(i)).y(), (Other.m_LogArray.point(i)).x());
+ }
+
+ return *this;
+}
+
+void IDChangeLog::addIDChange(Uml::IDType OldID, Uml::IDType NewID) {
+ uint pos;
+ if(!findIDChange(OldID, NewID, pos)) {
+ pos = m_LogArray.size();
+ m_LogArray.resize(pos + 1);
+ m_LogArray.setPoint(pos, NewID, OldID);
+ } else {
+ m_LogArray.setPoint(pos, NewID, OldID);
+ }
+}
+
+Uml::IDType IDChangeLog::findOldID(Uml::IDType NewID) {
+ uint count = m_LogArray.size();
+ for(uint i = 0; i < count; i++) {
+ if((m_LogArray.point(i)).x() == NewID) {
+ return (m_LogArray.point(i)).y();
+ }
+ }
+
+ return Uml::id_None;
+}
+
+bool IDChangeLog::findIDChange(Uml::IDType OldID, Uml::IDType NewID, uint& pos) {
+ uint count = m_LogArray.size();
+ for(uint i = 0; i < count; i++) {
+ if(((m_LogArray.point(i)).y() == OldID) && ((m_LogArray.point(i)).x() == NewID)) {
+ pos = i;
+ return true;
+ }
+ }
+
+ return false;
+}
+
+void IDChangeLog::removeChangeByNewID(Uml::IDType OldID) {
+ uint count = m_LogArray.size();
+ for(uint i = 0; i < count; i++) {
+ if((m_LogArray.point(i)).y() == OldID) {
+ m_LogArray.setPoint(i, Uml::id_None, OldID);
+ }
+ }
+}
diff --git a/umbrello/umbrello/clipboard/idchangelog.h b/umbrello/umbrello/clipboard/idchangelog.h
new file mode 100644
index 00000000..1d92cd0d
--- /dev/null
+++ b/umbrello/umbrello/clipboard/idchangelog.h
@@ -0,0 +1,126 @@
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * copyright (C) 2002-2006 *
+ * Umbrello UML Modeller Authors <uml-devel@uml.sf.net> *
+ ***************************************************************************/
+
+#ifndef IDCHANGELOG_H
+#define IDCHANGELOG_H
+
+
+/**
+ * This class contains all the ID translations done for each
+ * UMLObject pasted. It contains for each old id its new
+ * assigned id.
+ *
+ * @author Gustavo Madrigal
+ * Bugs and comments to uml-devel@lists.sf.net or http://bugs.kde.org
+ */
+
+#include <qstring.h>
+#include <qvaluevector.h>
+
+#include "../umlnamespace.h"
+
+class IDChangeLog {
+public:
+ /**
+ * Constructor.
+ */
+ IDChangeLog();
+
+ /**
+ * Copy constructor.
+ */
+ IDChangeLog(const IDChangeLog& Other);
+
+ /**
+ * Deconstructor.
+ */
+ ~IDChangeLog();
+
+ /**
+ * Overloaded '=' operator.
+ */
+ IDChangeLog& operator=(const IDChangeLog& Other);
+
+ /**
+ * Overloaded '==' operator.
+ */
+ bool operator==(const IDChangeLog& Other);
+
+ /**
+ * Adds a new ID Change to the log.
+ */
+ void addIDChange(Uml::IDType OldID, Uml::IDType NewID);
+
+ /**
+ * Appends another IDChangeLog to this instance of IDChangeLog and
+ * returns a reference to itself.
+ */
+ IDChangeLog& operator+=(const IDChangeLog& Other);
+
+ /**
+ * Returns the new assigned ID of the object that had OldID as its
+ * previous id.
+ */
+ Uml::IDType findNewID(Uml::IDType OldID);
+
+ /**
+ * Returns the old ID of an UMLobject given its new one.
+ */
+ Uml::IDType findOldID(Uml::IDType NewID);
+
+ /**
+ * Removes a change giving an New ID.
+ */
+ void removeChangeByNewID( Uml::IDType OldID);
+
+ enum SpecialIDs
+ {
+ NullID = -1000 ///< An impossible id value.
+ };
+
+private:
+ /**
+ * Each change is a Point (x=newID, y=oldID)
+ */
+ class Point {
+ public:
+ Point()
+ {}
+ Point(const Uml::IDType &x, const Uml::IDType &y)
+ : m_x(x), m_y(y)
+ {}
+ virtual ~Point() {}
+ void setX(const Uml::IDType &x) { m_x = x; }
+ Uml::IDType x() const { return m_x; }
+ void setY(const Uml::IDType &y) { m_y = y; }
+ Uml::IDType y() const { return m_y; }
+ private:
+ Uml::IDType m_x, m_y;
+ };
+class PointArray : QValueVector<Point> {
+ public:
+ void setPoint(uint i, const Uml::IDType &x, const Uml::IDType &y) {
+ Point point(x, y);
+ QValueVector<Point>::at(i) = point;
+ }
+ const Point& point( uint i ) const { return QValueVector<Point>::at(i); }
+ uint size() const { return QValueVector<Point>::size(); }
+ bool resize( uint size ) { QValueVector<Point>::resize(size); return true; }
+ };
+ PointArray m_LogArray;
+
+ /**
+ * Finds a specific change in the log.
+ */
+ bool findIDChange(Uml::IDType OldID, Uml::IDType NewID, uint& pos);
+};
+
+#endif
diff --git a/umbrello/umbrello/clipboard/umlclipboard.cpp b/umbrello/umbrello/clipboard/umlclipboard.cpp
new file mode 100644
index 00000000..c65c576e
--- /dev/null
+++ b/umbrello/umbrello/clipboard/umlclipboard.cpp
@@ -0,0 +1,694 @@
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * copyright (C) 2002-2007 *
+ * Umbrello UML Modeller Authors <uml-devel@uml.sf.net> *
+ ***************************************************************************/
+
+// own header
+#include "umlclipboard.h"
+
+// qt/kde includes
+#include <kdebug.h>
+#include <kmessagebox.h>
+#include <klocale.h>
+
+// local includes
+#include "umldrag.h"
+#include "idchangelog.h"
+#include "../associationwidget.h"
+#include "../attribute.h"
+#include "../classifier.h"
+#include "../floatingtextwidget.h"
+#include "../operation.h"
+#include "../umldoc.h"
+#include "../umllistview.h"
+#include "../umllistviewitem.h"
+#include "../umlobjectlist.h"
+#include "../umlview.h"
+#include "../umlwidget.h"
+#include "../uml.h"
+#include "../model_utils.h"
+
+UMLClipboard::UMLClipboard() {
+ m_type = clip1;
+}
+
+UMLClipboard::~UMLClipboard() {
+}
+
+QMimeSource* UMLClipboard::copy(bool fromView/*=false*/) {
+ //Clear previous copied data
+ m_AssociationList.clear();
+ m_ItemList.clear();
+ m_ObjectList.clear();
+ m_ViewList.clear();
+
+ UMLDrag *data = 0;
+ QPixmap* png = 0;
+
+ UMLListView * listView = UMLApp::app()->getListView();
+ UMLListViewItemList selectedItems;
+ selectedItems.setAutoDelete(false);
+
+ if(fromView) {
+ m_type = clip4;
+ UMLView *view = UMLApp::app()->getCurrentView();
+ view->checkSelections();
+ if(!view->getSelectedWidgets(m_WidgetList)) {
+ return 0;
+ }
+ //if there is no selected widget then there is no copy action
+ if(!m_WidgetList.count()) {
+ return 0;
+ }
+ m_AssociationList = view->getSelectedAssocs();
+ view->copyAsImage(png);
+
+ } else { //if the copy action is being performed from the ListView
+ if(!listView->getSelectedItems(selectedItems)) {
+ return 0;
+ }
+ //Set What type of copy operation are we performing and
+ //also fill m_ViewList with all the selected Diagrams
+ setCopyType(selectedItems);
+
+ //if we are copying a diagram or part of a diagram, select the items
+ //on the ListView that correspond to a UseCase, Actor or Concept
+ //in the Diagram
+ if(m_type == clip2) {
+ //Fill the member lists with all the object and stuff to be copied
+ //to the clipboard
+ selectedItems.clear();
+ //For each selected view select all the Actors, USe Cases and Concepts
+ //widgets in the ListView
+ for (UMLViewListIt vit(m_ViewList); vit.current(); ++vit) {
+ UMLObjectList objects = vit.current()->getUMLObjects();
+ for (UMLObjectListIt oit(objects); oit.current(); ++oit) {
+ UMLObject *o = oit.current();
+ UMLListViewItem *item = listView->findUMLObject(o);
+ if(item) {
+ listView->setSelected(item, true);
+ }
+ }
+ }
+ if(!listView->getSelectedItems(selectedItems)) {
+ return 0;
+ }
+ }
+ if(!fillSelectionLists(selectedItems)) {
+ return 0;
+ }
+ }
+ int i =0;
+ switch(m_type) {
+ case clip1:
+ data = new UMLDrag(m_ObjectList);
+ break;
+ case clip2:
+ data = new UMLDrag(m_ObjectList, m_ItemList, m_ViewList);
+ break;
+ case clip3:
+ data = new UMLDrag(m_ItemList);
+ break;
+ case clip4:
+ if(png) {
+ UMLView *view = UMLApp::app()->getCurrentView();
+ data = new UMLDrag(m_ObjectList, m_WidgetList,
+ m_AssociationList, *png, view->getType());
+ } else {
+ return 0;
+ }
+ break;
+ case clip5:
+ data = new UMLDrag(m_ObjectList, i);
+ // The int i is used to differentiate
+ // which UMLDrag constructor gets called.
+ break;
+ }
+
+ return (QMimeSource*)data;
+}
+
+bool UMLClipboard::paste(QMimeSource* data) {
+ UMLDoc *doc = UMLApp::app()->getDocument();
+ bool result = false;
+ doc->beginPaste();
+ switch(UMLDrag::getCodingType(data)) {
+ case 1:
+ result = pasteClip1(data);
+ break;
+ case 2:
+ result = pasteClip2(data);
+ break;
+ case 3:
+ result = pasteClip3(data);
+ break;
+ case 4:
+ result = pasteClip4(data);
+ break;
+ case 5:
+ result = pasteClip5(data);
+ break;
+ default:
+ break;
+ }
+ doc->endPaste();
+ return result;
+}
+
+bool UMLClipboard::fillSelectionLists(UMLListViewItemList& SelectedItems) {
+ UMLListViewItemListIt it(SelectedItems);
+ UMLListViewItem* item = 0;
+ Uml::ListView_Type type;
+ switch(m_type) {
+ case clip4:
+ break;
+ case clip3:
+ for ( ; it.current(); ++it ) {
+ item = (UMLListViewItem*)it.current();
+ type = item->getType();
+ if ( !Model_Utils::typeIsClassifierList(type) ) {
+ m_ItemList.append(item);
+ insertItemChildren(item, SelectedItems);
+ //Because it is being called when m_type is 3
+ //it will insert only child empty folders of other folders.
+ //If a child folder
+ //is not empty that means m_type wouldn't be 3 because if a folder is
+ //selected then its complete contents are treated as if
+ //they were selected
+ }
+ }
+ break;
+ case clip2:
+ case clip1:
+ for ( ; it.current(); ++it ) {
+ item = (UMLListViewItem*)it.current();
+ type = item->getType();
+ if ( !Model_Utils::typeIsClassifierList(type) ) {
+
+ m_ItemList.append(item);
+
+ if ( Model_Utils::typeIsCanvasWidget(type) ) {
+ m_ObjectList.append(item->getUMLObject());
+ }
+ insertItemChildren(it.current(), SelectedItems);
+ }
+ }
+ break;
+ case clip5:
+ for ( ; it.current(); ++it ) {
+ item = (UMLListViewItem*)it.current();
+ type = item->getType();
+ if( Model_Utils::typeIsClassifierList(type) ) {
+ m_ItemList.append(item);
+ m_ObjectList.append(item->getUMLObject());
+
+ } else {
+ return false;
+ }
+ }
+ break;
+ }
+
+ return true;
+}
+
+void UMLClipboard::setCopyType(UMLListViewItemList& SelectedItems) {
+ bool withDiagrams = false; //If the selection includes diagrams
+ bool withObjects = false; //If the selection includes objects
+ bool onlyAttsOps = false; //If the selection only includes Attributes and/or Operations
+ UMLListViewItemListIt it(SelectedItems);
+ for ( ; it.current(); ++it ) {
+ checkItemForCopyType(it.current(), withDiagrams, withObjects, onlyAttsOps);
+ }
+ if(onlyAttsOps) {
+ m_type = clip5;
+ } else if(withDiagrams) {
+ m_type = clip2;
+ } else if(withObjects) {
+ m_type = clip1;
+ } else {
+ m_type = clip3;
+ }
+}
+
+void UMLClipboard::checkItemForCopyType(UMLListViewItem* Item, bool & WithDiagrams, bool &WithObjects,
+ bool &OnlyAttsOps) {
+ if(!Item) {
+ return;
+ }
+ UMLDoc *doc = UMLApp::app()->getDocument();
+ OnlyAttsOps = true;
+ UMLView * view = 0;
+ UMLListViewItem * child = 0;
+ Uml::ListView_Type type = Item->getType();
+ if ( Model_Utils::typeIsCanvasWidget(type) ) {
+ WithObjects = true;
+ OnlyAttsOps = false;
+ } else if ( Model_Utils::typeIsDiagram(type) ) {
+ WithDiagrams = true;
+ OnlyAttsOps = false;
+ view = doc->findView( Item->getID() );
+ m_ViewList.append( view );
+ } else if ( Model_Utils::typeIsFolder(type) ) {
+ OnlyAttsOps = false;
+ if(Item->childCount()) {
+ child = (UMLListViewItem*)Item->firstChild();
+ while(child) {
+ checkItemForCopyType(child, WithDiagrams, WithObjects, OnlyAttsOps);
+ child = (UMLListViewItem*)child->nextSibling();
+ }
+ }
+ }
+}
+
+/** Adds the children of a UMLListViewItem to m_ItemList */
+bool UMLClipboard::insertItemChildren(UMLListViewItem * Item, UMLListViewItemList& SelectedItems) {
+ if(Item->childCount()) {
+ UMLListViewItem * child = (UMLListViewItem*)Item->firstChild();
+ int type;
+ while(child) {
+ m_ItemList.append(child);
+ type = child->getType();
+ if(type == Uml::lvt_Actor || type == Uml::lvt_UseCase || type == Uml::lvt_Class) {
+ m_ObjectList.append(child->getUMLObject());
+ }
+ // If the child is selected, remove it from the list of selected items
+ // otherwise it will be inserted twice in m_ObjectList.
+ if(child->isSelected()) {
+ SelectedItems.remove(SelectedItems.find(child) );
+ }
+ insertItemChildren(child, SelectedItems);
+ child = (UMLListViewItem*)child->nextSibling();
+ }
+ }
+ return true;
+}
+
+bool UMLClipboard::pasteChildren(UMLListViewItem *parent, IDChangeLog *chgLog) {
+ if (!parent) {
+ kWarning() << "Paste Children Error, parent missing" << endl;
+ return false;
+ }
+ UMLDoc *doc = UMLApp::app()->getDocument();
+ UMLListView *listView = UMLApp::app()->getListView();
+ UMLListViewItem *childItem = static_cast<UMLListViewItem*>(parent->firstChild());
+ while (childItem) {
+ Uml::IDType oldID = childItem->getID();
+ Uml::IDType newID = chgLog->findNewID(oldID);
+ UMLListViewItem *shouldNotExist = listView->findItem(newID);
+ if (shouldNotExist) {
+ kError() << "UMLClipboard::pasteChildren: new list view item " << ID2STR(newID)
+ << " already exists (internal error)" << endl;
+ childItem = static_cast<UMLListViewItem*>(childItem->nextSibling());
+ continue;
+ }
+ UMLObject *newObj = doc->findObjectById(newID);
+ if (newObj) {
+ kDebug() << "UMLClipboard::pasteChildren: adjusting lvitem(" << ID2STR(oldID)
+ << ") to new UMLObject(" << ID2STR(newID) << ")" << endl;
+ childItem->setUMLObject(newObj);
+ childItem->setText(newObj->getName());
+ } else {
+ kDebug() << "UMLClipboard::pasteChildren: no UMLObject found for lvitem "
+ << ID2STR(newID) << endl;
+ }
+ childItem = static_cast<UMLListViewItem*>(childItem->nextSibling());
+ }
+ return true;
+}
+
+/** Cleans the list of associations taking out the ones that point to an object
+ not in m_ObjectList. */
+void UMLClipboard::CleanAssociations(AssociationWidgetList& associations) {
+ AssociationWidgetListIt it(associations);
+ AssociationWidget* assoc = it.current();
+
+ while (assoc) {
+ ++it;
+ assoc = it.current();
+ }
+}
+
+/** If clipboard has mime type application/x-uml-clip1,
+Pastes the data from the clipboard into the current Doc */
+bool UMLClipboard::pasteClip1(QMimeSource* data) {
+ UMLObjectList objects;
+ if (! UMLDrag::decodeClip1(data, objects)) {
+ return false;
+ }
+ UMLListView *lv = UMLApp::app()->getListView();
+ if ( !lv->startedCopy() )
+ return true;
+ lv->setStartedCopy(false);
+ /* If we get here we are pasting after a Copy and need to
+ // paste possible children.
+ UMLListViewItem* itemdata = 0;
+ UMLListViewItemListIt it(itemdatalist);
+ while ( (itemdata=it.current()) != 0 ) {
+ if(itemdata -> childCount()) {
+ if(!pasteChildren(itemdata, idchanges)) {
+ return false;
+ }
+ }
+ ++it;
+ }
+ */
+ return true;
+}
+
+/** If clipboard has mime type application/x-uml-clip2,
+Pastes the data from the clipboard into the current Doc */
+bool UMLClipboard::pasteClip2(QMimeSource* data) {
+ UMLDoc *doc = UMLApp::app()->getDocument();
+ UMLListViewItemList itemdatalist;
+ UMLObjectList objects;
+ objects.setAutoDelete(false);
+ UMLViewList views;
+ IDChangeLog* idchanges = 0;
+
+ bool result = UMLDrag::decodeClip2(data, objects, itemdatalist, views);
+ if(!result) {
+ return false;
+ }
+ UMLObject *obj = 0;
+ UMLObjectListIt object_it(objects);
+ idchanges = doc->getChangeLog();
+ if(!idchanges) {
+ return false;
+ }
+ while ( (obj=object_it.current()) != 0 ) {
+ ++object_it;
+ if(!doc->assignNewIDs(obj)) {
+ kDebug()<<"UMLClipboard: error adding umlobject"<<endl;
+ return false;
+ }
+ }
+
+ UMLView * pView = 0;
+ UMLViewListIt view_it( views );
+ while ( ( pView =view_it.current()) != 0 ) {
+ ++view_it;
+ if( !doc->addUMLView( pView ) ) {
+ return false;
+ }
+ }
+
+ UMLListView *listView = UMLApp::app()->getListView();
+ UMLListViewItem* item = 0;
+ UMLListViewItem* itemdata = 0;
+ UMLListViewItemListIt it(itemdatalist);
+ while ( (itemdata=it.current()) != 0 ) {
+ item = listView->createItem(*itemdata, *idchanges);
+ if(!item) {
+ return false;
+ }
+ if(itemdata -> childCount()) {
+ if(!pasteChildren(item, idchanges)) {
+ return false;
+ }
+ }
+ ++it;
+ }
+
+ return result;
+}
+
+/** If clipboard has mime type application/x-uml-clip3,
+Pastes the data from the clipboard into the current Doc */
+bool UMLClipboard::pasteClip3(QMimeSource* data) {
+ UMLDoc *doc = UMLApp::app()->getDocument();
+ UMLListViewItemList itemdatalist;
+ UMLListViewItem* item = 0;
+ UMLListViewItem* itemdata = 0;
+ IDChangeLog* idchanges = doc->getChangeLog();
+
+ if(!idchanges) {
+ return false;
+ }
+
+ UMLListView *listView = UMLApp::app()->getListView();
+ bool result = UMLDrag::decodeClip3(data, itemdatalist, listView);
+ if(!result) {
+ return false;
+ }
+ UMLListViewItemListIt it(itemdatalist);
+ while ( (itemdata=it.current()) != 0 ) {
+ item = listView->createItem(*itemdata, *idchanges);
+ if(itemdata -> childCount()) {
+ if(!pasteChildren(item, idchanges)) {
+ return false;
+ }
+ }
+ ++it;
+ }
+
+ return result;
+}
+
+/** If clipboard has mime type application/x-uml-clip4,
+Pastes the data from the clipboard into the current Doc */
+bool UMLClipboard::pasteClip4(QMimeSource* data) {
+ UMLDoc *doc = UMLApp::app()->getDocument();
+
+ UMLObjectList objects;
+ objects.setAutoDelete(false);
+
+
+ UMLWidgetList widgets;
+ widgets.setAutoDelete(false);
+
+ AssociationWidgetList assocs;
+ assocs.setAutoDelete(false);
+
+ IDChangeLog* idchanges = 0;
+
+ Uml::Diagram_Type diagramType;
+
+ if( !UMLDrag::decodeClip4(data, objects, widgets, assocs, diagramType) ) {
+ return false;
+ }
+
+ if( diagramType != UMLApp::app()->getCurrentView()->getType() ) {
+ if( !checkPasteWidgets(widgets) ) {
+ assocs.setAutoDelete(true);
+ assocs.clear();
+ return false;
+ }
+ }
+ UMLObjectListIt object_it(objects);
+ idchanges = doc->getChangeLog();
+ if(!idchanges) {
+ return false;
+ }
+ //make sure the file we are pasting into has the objects
+ //we need if there are widgets to be pasted
+ UMLObject* obj = 0;
+ while ( (obj=object_it.current()) != 0 ) {
+ ++object_it;
+
+ if(!doc->assignNewIDs(obj)) {
+ return false;
+ }
+
+ }
+
+ //now add any widget we are want to paste
+ bool objectAlreadyExists = false;
+ UMLView *currentView = UMLApp::app()->getCurrentView();
+ currentView->beginPartialWidgetPaste();
+ UMLWidget* widget =0;
+ UMLWidgetListIt widget_it(widgets);
+ while ( (widget=widget_it.current()) != 0 ) {
+ ++widget_it;
+
+ Uml::IDType oldId = widget->getID();
+ Uml::IDType newId = idchanges->findNewID(oldId);
+ if (currentView->findWidget(newId)) {
+ kError() << "UMLClipboard::pasteClip4: widget (oldID=" << ID2STR(oldId)
+ << ", newID=" << ID2STR(newId) << ") already exists in target view."
+ << endl;
+ widgets.remove(widget);
+ delete widget;
+ objectAlreadyExists = true;
+ } else if (! currentView->addWidget(widget, true)) {
+ currentView->endPartialWidgetPaste();
+ return false;
+ }
+ }
+
+ //now paste the associations
+ AssociationWidget* assoc;
+ AssociationWidgetListIt assoc_it(assocs);
+ while ( (assoc=assoc_it.current()) != 0 ) {
+ ++assoc_it;
+ if (!currentView->addAssociation(assoc, true)) {
+ currentView->endPartialWidgetPaste();
+ return false;
+ }
+ }
+
+ //Activate all the pasted associations and widgets
+ currentView->activate();
+ currentView->endPartialWidgetPaste();
+
+ /*
+ UMLListView *listView = UMLApp::app()->getListView();
+ UMLListViewItem* item = 0;
+ UMLListViewItem* itemdata = 0;
+ UMLListViewItemListIt it(itemdatalist);
+ while ( (itemdata=it.current()) != 0 ) {
+ item = listView->createItem(*itemdata, *idchanges);
+ if(!item) {
+ return false;
+ }
+ if(itemdata -> childCount()) {
+ if(!pasteChildren(item, idchanges)) {
+ return false;
+ }
+ }
+ ++it;
+ }*/
+
+ if (objectAlreadyExists) {
+ pasteItemAlreadyExists();
+ }
+ return true;
+}
+
+/** If clipboard has mime type application/x-uml-clip5,
+Pastes the data from the clipboard into the current Doc */
+bool UMLClipboard::pasteClip5(QMimeSource* data) {
+ UMLDoc *doc = UMLApp::app()->getDocument();
+ UMLListView *listView = UMLApp::app()->getListView();
+ UMLListViewItem* lvitem = dynamic_cast<UMLListViewItem *>( listView->currentItem() );
+ if (!lvitem ||
+ (lvitem->getType() != Uml::lvt_Class && lvitem->getType() != Uml::lvt_Interface)) {
+ return false;
+ }
+ UMLClassifier *parent = dynamic_cast<UMLClassifier *>(lvitem->getUMLObject());
+ if (parent == NULL) {
+ kError() << "UMLClipboard::pasteClip5: parent is not a UMLClassifier"
+ << endl;
+ return false;
+ }
+
+ UMLObjectList objects;
+ objects.setAutoDelete(false);
+ IDChangeLog* idchanges = 0;
+ bool result = UMLDrag::decodeClip5(data, objects, parent);
+
+ if(!result) {
+ return false;
+ }
+
+ UMLObject *obj = 0;
+ doc->setModified(true);
+ idchanges = doc->getChangeLog();
+ // Assume success if at least one child object could be pasted
+ if (objects.count())
+ result = false;
+
+ for (UMLObjectListIt it(objects); (obj = it.current()) != NULL; ++it) {
+ obj->setID(doc->assignNewID(obj->getID()));
+ switch(obj->getBaseType()) {
+ case Uml::ot_Attribute :
+ {
+ UMLObject *exist = parent->findChildObject(obj->getName(), Uml::ot_Attribute);
+ if (exist) {
+ QString newName = parent->uniqChildName(Uml::ot_Attribute, obj->getName());
+ obj->setName(newName);
+ }
+ UMLAttribute *att = static_cast<UMLAttribute*>(obj);
+ if (parent->addAttribute(att, idchanges)) {
+ result = true;
+ } else {
+ kError() << "UMLClipboard::pasteClip5: " << parent->getName()
+ << "->addAttribute(" << att->getName() << ") failed" << endl;
+ }
+ break;
+ }
+ case Uml::ot_Operation :
+ {
+ UMLOperation *op = static_cast<UMLOperation*>(obj);
+ UMLOperation *exist = parent->checkOperationSignature(op->getName(), op->getParmList());
+ if (exist) {
+ QString newName = parent->uniqChildName(Uml::ot_Operation, obj->getName());
+ op->setName(newName);
+ }
+ if (parent->addOperation(op, idchanges)) {
+ result = true;
+ } else {
+ kError() << "UMLClipboard::pasteClip5: " << parent->getName()
+ << "->addOperation(" << op->getName() << ") failed" << endl;
+ }
+ break;
+ }
+ default :
+ kWarning() << "pasting unknown children type in clip type 5" << endl;
+ return false;
+ }
+ }
+
+ return result;
+}
+
+bool UMLClipboard::insertItemChildren( UMLListViewItem * item ) {
+ if( item -> childCount() ) {
+ UMLListViewItem * child =dynamic_cast<UMLListViewItem *>( item -> firstChild() );
+ while( child ) {
+ m_ItemList.append( child );
+ insertItemChildren( child );
+ child = dynamic_cast<UMLListViewItem *>( child->nextSibling() );
+ }
+ }
+ return true;
+}
+
+bool UMLClipboard::checkPasteWidgets( UMLWidgetList & widgetList ) {
+ bool retval = true;
+ UMLWidget * p = 0;
+ UMLWidgetListIt it( widgetList );
+ while ( ( p = it.current()) != 0 ) {
+ ++it;
+ switch( p -> getBaseType() ) {
+ case Uml::wt_Note:
+ break;
+
+ case Uml::wt_Text:
+ {
+ FloatingTextWidget *ft = static_cast<FloatingTextWidget*>(p);
+ if (ft->getRole() != Uml::tr_Floating) {
+ widgetList.remove(p);
+ delete ft;
+ retval = false;
+ }
+ }
+ break;
+
+ default:
+ widgetList.remove(p);
+ delete p;
+ retval = false;
+ break;
+ }
+ }
+ return retval;
+}
+
+void UMLClipboard::pasteItemAlreadyExists() {
+ UMLView *currentView = UMLApp::app()->getCurrentView();
+ KMessageBox::sorry( currentView,
+ i18n("At least one of the items in the clipboard "
+ "could not be pasted because an item of the "
+ "same name already exists. Any other items "
+ "have been pasted."),
+ i18n("Paste Error") );
+}
+
+#include "umlclipboard.moc"
diff --git a/umbrello/umbrello/clipboard/umlclipboard.h b/umbrello/umbrello/clipboard/umlclipboard.h
new file mode 100644
index 00000000..9be92111
--- /dev/null
+++ b/umbrello/umbrello/clipboard/umlclipboard.h
@@ -0,0 +1,194 @@
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * copyright (C) 2002-2006 *
+ * Umbrello UML Modeller Authors <uml-devel@uml.sf.net> *
+ ***************************************************************************/
+
+#ifndef UMLCLIPBOARD_H
+#define UMLCLIPBOARD_H
+
+#include "../associationwidgetlist.h"
+#include "../umlobjectlist.h"
+#include "../umllistviewitemlist.h"
+#include "../umllistviewitem.h"
+#include "../umlviewlist.h"
+#include "../umlwidgetlist.h"
+
+class IDChangeLog;
+class QMimeSource;
+
+/**
+ * This class manages the uml's interaction with the KDE
+ * Clipboard. It makes possible to copy stuff from one uml
+ * instance to another one.
+ *
+ * @short Clipboard management class
+ * @author Gustavo Madrigal
+ * Bugs and comments to uml-devel@lists.sf.net or http://bugs.kde.org
+ */
+class UMLClipboard : public QObject {
+ Q_OBJECT
+public:
+ /**
+ * Constructor.
+ */
+ UMLClipboard();
+
+ /**
+ * Deconstructor.
+ */
+ virtual ~UMLClipboard();
+
+ /**
+ * Inserts the clipboard's contents.
+ *
+ * @param Data Pointer to the MIME format clipboard data.
+ * @return True for successful operation.
+ */
+ bool paste(QMimeSource* Data);
+
+ /**
+ * Copies the selected stuff from the list view or current diagram
+ * to a QMimeSource ready to be put in the clipboard.
+ *
+ * @return Pointer to the created clipboard data.
+ */
+ QMimeSource* copy(bool fromView = false);
+
+ /// Enumeration that codes the different types of UML clips.
+ enum UMLCopyType
+ {
+ clip1 = 1, ///<UMLObjects (not diagrams)
+ clip2 = 2, ///<UMLObjects, UMLListViewItems (not diagrams) and diagrams
+ clip3 = 3, ///<UMLListViewItems (not diagrams)
+ clip4 = 4, ///<UMLObjects, Associations and UMLWidgets
+ clip5 = 5 ///<Only Attributes and Operations
+ };
+
+private:
+ /**
+ * Cleans the list of associations taking out the ones
+ * that point to an object not in m_ObjectList.
+ *
+ * @param associations The list of associations to process.
+ */
+ void CleanAssociations(AssociationWidgetList& associations);
+
+ /**
+ * If clipboard has mime type application/x-uml-clip1,
+ * pastes the data from the clipboard.
+ *
+ * @param data Pointer to the source clip.
+ * @return True for successful operation.
+ */
+ bool pasteClip1(QMimeSource* data);
+
+ /**
+ * If clipboard has mime type application/x-uml-clip2,
+ * pastes the data from the clipboard.
+ *
+ * @param data Pointer to the source clip.
+ * @return True for successful operation.
+ */
+ bool pasteClip2(QMimeSource* data);
+
+ /**
+ * If clipboard has mime type application/x-uml-clip3,
+ * pastes the data from the clipboard.
+ *
+ * @param data Pointer to the source clip.
+ * @return True for successful operation.
+ */
+ bool pasteClip3(QMimeSource* data);
+
+ /**
+ * If clipboard has mime type application/x-uml-clip4,
+ * pastes the data from the clipboard.
+ *
+ * @param data Pointer to the source clip.
+ * @return True for successful operation.
+ */
+ bool pasteClip4(QMimeSource* data);
+
+ /**
+ * If clipboard has mime type application/x-uml-clip5,
+ * pastes the data from the clipboard.
+ *
+ * @param data Pointer to the source clip.
+ * @return True for successful operation.
+ */
+ bool pasteClip5(QMimeSource* data);
+
+ /**
+ * When pasting widgets see if they can be pasted on
+ * different diagram types. Will return true if all the
+ * widgets to be pasted can be. At the moment this only
+ * includes NoteWidgets and lines of text.
+ *
+ * @param widgetList List of widgets to examine.
+ * @return True if all widgets can be put on different diagrams.
+ */
+ bool checkPasteWidgets(UMLWidgetList & widgetList);
+
+ UMLObjectList m_ObjectList;
+ UMLListViewItemList m_ItemList;
+ UMLWidgetList m_WidgetList;
+ AssociationWidgetList m_AssociationList;
+ UMLViewList m_ViewList;
+ UMLCopyType m_type; ///< Type of copy operation to perform.
+
+private:
+ /**
+ * Fills the member lists with all the objects and other
+ * stuff to be copied to the clipboard.
+ */
+ bool fillSelectionLists(UMLListViewItemList& SelectedItems);
+
+ /**
+ * Checks the whole list to determine the copy action
+ * type to be * performed, sets the type in the m_type
+ * member variable.
+ */
+ void setCopyType(UMLListViewItemList& SelectedItems);
+
+ /**
+ * Searches the child items of a UMLListViewItem to
+ * establish which Copy type is to be perfomed.
+ */
+ void checkItemForCopyType(UMLListViewItem* Item,
+ bool& WithDiagrams,
+ bool& WithObjects,
+ bool& OnlyAttsOps);
+
+ /**
+ * Adds the children of a UMLListViewItem to m_ItemList.
+ */
+ bool insertItemChildren(UMLListViewItem* Item,
+ UMLListViewItemList& SelectedItems);
+
+ /**
+ * Inserts the data of the children of the given item
+ * into the item data list. Used for clip type 4. Used
+ * to make * sure classes have all the attributes and
+ * operations saved.
+ */
+ bool insertItemChildren(UMLListViewItem* item);
+
+ /**
+ * Pastes the children of a UMLListViewItem (The Parent)
+ */
+ bool pasteChildren(UMLListViewItem* parent, IDChangeLog *chgLog);
+
+ /**
+ * Gives a `sorry' message box if you're pasting an item which
+ * already exists and can't be duplicated.
+ */
+ void pasteItemAlreadyExists();
+};
+
+#endif
diff --git a/umbrello/umbrello/clipboard/umldrag.cpp b/umbrello/umbrello/clipboard/umldrag.cpp
new file mode 100644
index 00000000..f9fa6629
--- /dev/null
+++ b/umbrello/umbrello/clipboard/umldrag.cpp
@@ -0,0 +1,773 @@
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * copyright (C) 2002-2007 *
+ * Umbrello UML Modeller Authors <uml-devel@uml.sf.net> *
+ ***************************************************************************/
+
+// own header
+#include "umldrag.h"
+
+// qt/kde includes
+#include <qdom.h>
+#include <kdebug.h>
+
+// local includes
+#include "idchangelog.h"
+#include "../uml.h"
+#include "../umldoc.h"
+#include "../umlview.h"
+#include "../umlobject.h"
+#include "../folder.h"
+#include "../classifier.h"
+#include "../umlwidget.h"
+#include "../umllistview.h"
+#include "../umllistviewitem.h"
+#include "../associationwidget.h"
+#include "../object_factory.h"
+#include "../model_utils.h"
+
+#define nfmt 4
+class UMLDragPrivate {
+public:
+ QCString fmt[nfmt];
+ QCString subtype;
+ QByteArray enc[nfmt];
+
+ UMLDragPrivate() {
+ setSubType("clip1", 0);
+ }
+
+ void setType(const QCString& st, int index) {
+ if (index < nfmt) {
+ fmt[index] = st.lower();
+ }
+ }
+
+ void setSubType(const QCString& st, int index) {
+ if (index < nfmt) {
+ subtype = st.lower();
+ fmt[index] = "application/x-uml-";
+ fmt[index].append(subtype);
+ }
+ }
+
+ const char* format(int i) const {
+ if(i < nfmt) {
+ return fmt[i];
+ }
+ return 0;
+ }
+};
+
+UMLDrag::UMLDrag(UMLObjectList& objects, QWidget* dragSource /*= 0*/, const char* name /*= 0*/)
+ : QDragObject(dragSource, name) {
+ data = new UMLDragPrivate;
+ setUMLDataClip1(objects);
+}
+
+UMLDrag::UMLDrag(UMLObjectList& objects, UMLListViewItemList& umlListViewItems, UMLViewList& diagrams,
+ QWidget* dragSource /*= 0*/, const char* name /*= 0*/ ): QDragObject(dragSource, name) {
+ data = new UMLDragPrivate;
+ setUMLDataClip2(objects, umlListViewItems, diagrams);
+}
+
+UMLDrag::UMLDrag(UMLListViewItemList& umlListViewItems, QWidget* dragSource /*= 0*/,
+ const char* name /*= 0*/ ): QDragObject(dragSource, name) {
+ data = new UMLDragPrivate;
+ setUMLDataClip3(umlListViewItems);
+}
+
+UMLDrag::UMLDrag(UMLObjectList& objects,
+ UMLWidgetList& widgets, AssociationWidgetList& associationDatas,
+ QPixmap& pngImage, Uml::Diagram_Type dType, QWidget * dragSource /*= 0*/,
+ const char * name /*= 0*/ ): QDragObject(dragSource, name) {
+ data = new UMLDragPrivate;
+ setUMLDataClip4(objects, widgets, associationDatas, pngImage, dType);
+}
+
+UMLDrag::UMLDrag(UMLObjectList& objects, int,
+ QWidget* /*dragSource = 0*/, const char* /*name = 0*/ ) {
+ data = new UMLDragPrivate;
+ setUMLDataClip5(objects);
+}
+
+UMLDrag::UMLDrag(QWidget* dragSource /*= 0*/, const char * name /*= 0*/ ): QDragObject(dragSource, name) {
+ data = new UMLDragPrivate;
+}
+
+UMLDrag::~UMLDrag() {
+ delete data;
+}
+
+void UMLDrag::setSubType(const QCString& string, int index) {
+ data->setSubType(string, index);
+}
+
+void UMLDrag::setEncodedData(const QByteArray& encodedData, int index) {
+ data->enc[index] = encodedData.copy();
+}
+
+QByteArray UMLDrag::encodedData(const char* dataName) const {
+ QString str(dataName);
+ for (int i = 0; i < 4; i++) {
+ if ( !qstricmp(dataName,data->fmt[i]) ) {
+ return data->enc[i];
+ }
+ }
+ return QByteArray();
+}
+
+const char* UMLDrag::format(int index) const {
+ char* result = (char*)data->format(index);
+ return result;
+}
+
+void UMLDrag::setUMLDataClip1(UMLObjectList& objects) {
+ setSubType("clip1", 0);
+
+ QDomDocument domDoc;
+ QDomElement xmiclip = domDoc.createElement("xmiclip");
+ domDoc.appendChild(xmiclip);
+ QDomElement objectsTag = domDoc.createElement("umlobjects");
+ xmiclip.appendChild(objectsTag);
+
+ UMLObjectListIt object_it(objects);
+ UMLObject* obj = 0;
+ while ( (obj=object_it.current()) != 0 ) {
+ ++object_it;
+ obj->saveToXMI(domDoc, objectsTag);
+ }
+
+ QDomElement itemsTag = domDoc.createElement("umllistviewitems");
+ xmiclip.appendChild(itemsTag);
+
+ setEncodedData(domDoc.toString().utf8(), 0);
+}
+
+void UMLDrag::setUMLDataClip2(UMLObjectList& objects, UMLListViewItemList& umlListViewItems,
+ UMLViewList& diagrams) {
+ setSubType("clip2", 0);
+
+ QDomDocument domDoc;
+ QDomElement xmiclip = domDoc.createElement("xmiclip");
+ domDoc.appendChild(xmiclip);
+ QDomElement objectsTag = domDoc.createElement("umlobjects");
+ xmiclip.appendChild(objectsTag);
+
+ UMLObjectListIt object_it(objects);
+ UMLObject* obj = 0;
+ while ( (obj=object_it.current()) != 0 ) {
+ ++object_it;
+ obj->saveToXMI(domDoc, objectsTag);
+ }
+
+ QDomElement viewsTag = domDoc.createElement("umlviews");
+ xmiclip.appendChild(viewsTag);
+
+ UMLViewListIt diagram_it(diagrams);
+ UMLView* view = 0;
+ while ( (view=diagram_it.current()) != 0 ) {
+ ++diagram_it;
+ view->saveToXMI(domDoc, viewsTag);
+ }
+
+ QDomElement itemsTag = domDoc.createElement("umllistviewitems");
+ xmiclip.appendChild(itemsTag);
+
+ UMLListViewItemListIt item_it2(umlListViewItems);
+ UMLListViewItem* item = 0;
+ while ( (item=item_it2.current()) != 0 ) {
+ ++item_it2;
+ item->saveToXMI(domDoc, itemsTag);
+ }
+ setEncodedData(domDoc.toString().utf8(), 0);
+}
+
+void UMLDrag::setUMLDataClip3(UMLListViewItemList& umlListViewItems) {
+ setSubType("clip3", 0);
+
+ QDomDocument domDoc;
+ QDomElement xmiclip = domDoc.createElement("xmiclip");
+ domDoc.appendChild(xmiclip);
+
+ QDomElement itemsTag = domDoc.createElement("umllistviewitems");
+ xmiclip.appendChild(itemsTag);
+
+ UMLListViewItemListIt item_it2(umlListViewItems);
+ UMLListViewItem* item = 0;
+ while ( (item=item_it2.current()) != 0 ) {
+ ++item_it2;
+ item->saveToXMI(domDoc, itemsTag);
+ }
+ setEncodedData(domDoc.toString().utf8(), 0);
+}
+
+void UMLDrag::setUMLDataClip4(UMLObjectList& objects, UMLWidgetList& widgets, AssociationWidgetList& associations,
+ QPixmap& pngImage, Uml::Diagram_Type dType ) {
+ setSubType("clip4", 0);
+
+ QDomDocument domDoc;
+ QDomElement xmiclip = domDoc.createElement("xmiclip");
+ xmiclip.setAttribute("diagramtype", dType);
+ domDoc.appendChild(xmiclip);
+ QDomElement objectsTag = domDoc.createElement("umlobjects");
+ xmiclip.appendChild(objectsTag);
+
+ UMLObjectListIt object_it(objects);
+ UMLObject* obj = 0;
+ while ( (obj=object_it.current()) != 0 ) {
+ ++object_it;
+ obj->saveToXMI(domDoc, objectsTag);
+ }
+
+ QDomElement widgetsTag = domDoc.createElement("widgets");
+ xmiclip.appendChild(widgetsTag);
+
+ UMLWidgetListIt widget_it(widgets);
+ UMLWidget* widget = 0;
+ while ( (widget=widget_it.current()) != 0 ) {
+ ++widget_it;
+ widget->saveToXMI(domDoc, widgetsTag);
+ }
+
+ QDomElement associationWidgetsTag = domDoc.createElement("associations");
+ xmiclip.appendChild(associationWidgetsTag);
+
+ AssociationWidgetListIt associations_it(associations);
+ AssociationWidget* association;
+ while ( (association=associations_it.current()) != 0 ) {
+ ++associations_it;
+ association->saveToXMI(domDoc, associationWidgetsTag);
+ }
+
+ QDomElement itemsTag = domDoc.createElement("umllistviewitems");
+ xmiclip.appendChild(itemsTag);
+
+ setEncodedData(domDoc.toString().utf8(), 0);
+
+ data->setType("image/PNG", 1);
+ long l_size = (pngImage.convertToImage()).numBytes();
+ QByteArray clipdata;
+ clipdata.resize(l_size);
+ QDataStream clipstream(clipdata, IO_WriteOnly);
+ clipstream << pngImage;
+ setEncodedData(clipdata, 1);
+}
+
+void UMLDrag::setUMLDataClip5(UMLObjectList& objects) {
+ setSubType("clip5", 0);
+
+ QDomDocument domDoc;
+ QDomElement xmiclip = domDoc.createElement("xmiclip");
+ domDoc.appendChild(xmiclip);
+ QDomElement objectsTag = domDoc.createElement("umlobjects");
+ xmiclip.appendChild(objectsTag);
+
+ UMLObjectListIt object_it(objects);
+ UMLObject* obj = 0;
+ while ( (obj=object_it.current()) != 0 ) {
+ ++object_it;
+ obj->saveToXMI(domDoc, objectsTag);
+ }
+
+ QDomElement itemsTag = domDoc.createElement("umllistviewitems");
+ xmiclip.appendChild(itemsTag);
+
+ setEncodedData(domDoc.toString().utf8(), 0);
+}
+
+bool UMLDrag::decodeClip1(const QMimeSource* mimeSource, UMLObjectList& objects) {
+ UMLDoc* doc = UMLApp::app()->getDocument();
+ if ( !mimeSource->provides("application/x-uml-clip1") ) {
+ return false;
+ }
+ QByteArray payload = mimeSource->encodedData("application/x-uml-clip1");
+ if ( !payload.size() ) {
+ return false;
+ }
+ QString xmiClip = QString::fromUtf8(payload);
+
+ QString error;
+ int line;
+ QDomDocument domDoc;
+ if( !domDoc.setContent(xmiClip, false, &error, &line) ) {
+ kWarning() << "Can't set content:" << error << " Line:" << line << endl;
+ return false;
+ }
+ QDomNode xmiClipNode = domDoc.firstChild();
+ QDomElement root = xmiClipNode.toElement();
+ if ( root.isNull() ) {
+ return false;
+ }
+ // make sure it is an XMI clip
+ if ( root.tagName() != "xmiclip" ) {
+ return false;
+ }
+
+ UMLListView *listView = UMLApp::app()->getListView();
+
+ //UMLObjects
+ QDomNode objectsNode = xmiClipNode.firstChild();
+ QDomNode objectElement = objectsNode.firstChild();
+ QDomElement element = objectElement.toElement();
+ if ( element.isNull() ) {
+ return false;//return ok as it means there is no umlobjects
+ }
+ UMLObject* pObject = 0;
+ while ( !element.isNull() ) {
+ pObject = 0;
+ QString type = element.tagName();
+ if (type == "UML:Association") {
+ objectElement = objectElement.nextSibling();
+ element = objectElement.toElement();
+ continue;
+ }
+ pObject = Object_Factory::makeObjectFromXMI(type);
+
+ if( !pObject ) {
+ kWarning() << "UMLDrag::decodeClip1: Given wrong type of umlobject to create: "
+ << type << endl;
+ return false;
+ }
+ pObject->setInPaste( true );
+ if( !pObject->loadFromXMI( element ) ) {
+ kWarning() << "UMLDrag::decodeClip1: failed to load object of type "
+ << type << " from XMI" << endl;
+ delete pObject;
+ return false;
+ }
+ pObject->setInPaste( false );
+ if (listView->startedCopy()) {
+ /****************************************************************
+ * If the clone() methods called IDChangeLog::addIDChange(),
+ * we could do the following:
+ UMLObject *newObj = pObject->clone();
+ delete pObject;
+ pObject = newObj;
+ * but since that's not currently the case we do: */
+ if(!doc->assignNewIDs(pObject)) {
+ return false;
+ }
+ Uml::Object_Type type = pObject->getBaseType();
+ QString newName = Model_Utils::uniqObjectName(type, pObject->getUMLPackage(),
+ pObject->getName());
+ pObject->setName(newName);
+ /****************************************************************/
+ }
+
+ pObject->resolveRef();
+
+ objects.append(pObject);
+ objectElement = objectElement.nextSibling();
+ element = objectElement.toElement();
+ }
+
+ return true;
+}
+
+bool UMLDrag::decodeClip2(const QMimeSource* mimeSource, UMLObjectList& objects,
+ UMLListViewItemList& umlListViewItems, UMLViewList& diagrams) {
+
+ if ( !mimeSource->provides("application/x-uml-clip2") ) {
+ return false;
+ }
+ QByteArray payload = mimeSource->encodedData("application/x-uml-clip2");
+ if ( !payload.size() ) {
+ return false;
+ }
+ QString xmiClip = QString::fromUtf8(payload);
+
+ QString error;
+ int line;
+ QDomDocument domDoc;
+ if( !domDoc.setContent(xmiClip, false, &error, &line) ) {
+ kWarning() << "Can't set content:" << error << " Line:" << line << endl;
+ return false;
+ }
+ QDomNode xmiClipNode = domDoc.firstChild();
+ QDomElement root = xmiClipNode.toElement();
+ if ( root.isNull() ) {
+ return false;
+ }
+ // make sure it is an XMI clip
+ if ( root.tagName() != "xmiclip" ) {
+ return false;
+ }
+
+ //UMLObjects
+ QDomNode objectsNode = xmiClipNode.firstChild();
+ QDomNode objectElement = objectsNode.firstChild();
+ QDomElement element = objectElement.toElement();
+ if ( element.isNull() ) {
+ return false;//return ok as it means there is no umlobjects
+ }
+ UMLObject* pObject = 0;
+ while ( !element.isNull() ) {
+ pObject = 0;
+ QString type = element.tagName();
+ if (type != "UML:Association") {
+ pObject = Object_Factory::makeObjectFromXMI(type);
+
+ if( !pObject ) {
+ kWarning() << "Given wrong type of umlobject to create:" << type << endl;
+ return false;
+ }
+ if( !pObject->loadFromXMI(element) ) {
+ kWarning() << "failed to load object from XMI" << endl;
+ return false;
+ }
+ objects.append(pObject);
+ }
+ objectElement = objectElement.nextSibling();
+ element = objectElement.toElement();
+ }
+
+ //UMLViews (diagrams)
+ QDomNode umlviewsNode = objectsNode.nextSibling();
+ QDomNode diagramNode = umlviewsNode.firstChild();
+ QDomElement diagramElement = diagramNode.toElement();
+ if ( diagramElement.isNull() ) {
+ kWarning() << "no diagrams in XMI clip" << endl;
+ return false;
+ }
+ UMLListView *listView = UMLApp::app()->getListView();
+ while ( !diagramElement.isNull() ) {
+ QString type = diagramElement.attribute("type", "0");
+ Uml::Diagram_Type dt = (Uml::Diagram_Type)type.toInt();
+ UMLListViewItem *parent = listView->findFolderForDiagram(dt);
+ if (parent == NULL)
+ return false;
+ UMLObject *po = parent->getUMLObject();
+ if (po == NULL || po->getBaseType() != Uml::ot_Folder) {
+ kError() << "UMLDrag::decodeClip2: bad parent for view" << endl;
+ return false;
+ }
+ UMLFolder *f = static_cast<UMLFolder*>(po);
+ UMLView* view = new UMLView(f);
+ view->loadFromXMI(diagramElement);
+ diagrams.append(view);
+ diagramNode = diagramNode.nextSibling();
+ diagramElement = diagramNode.toElement();
+ }
+
+ //listviewitems
+ QDomNode listItemNode = umlviewsNode.nextSibling();
+ QDomNode listItems = listItemNode.firstChild();
+ QDomElement listItemElement = listItems.toElement();
+ if ( listItemElement.isNull() ) {
+ kWarning() << "no listitems in XMI clip" << endl;
+ return false;
+ }
+ UMLListViewItem *currentItem = (UMLListViewItem*)listView->currentItem();
+ while ( !listItemElement.isNull() ) {
+ UMLListViewItem* itemData;
+ if (currentItem)
+ itemData = new UMLListViewItem( currentItem );
+ else
+ itemData = new UMLListViewItem( listView );
+ if ( itemData->loadFromXMI(listItemElement) )
+ umlListViewItems.append(itemData);
+ else
+ delete itemData;
+ listItems = listItems.nextSibling();
+ listItemElement = listItems.toElement();
+ }
+ return true;
+}
+
+bool UMLDrag::getClip3TypeAndID(const QMimeSource* mimeSource,
+ LvTypeAndID_List& typeAndIdList)
+{
+ if ( !mimeSource->provides("application/x-uml-clip3") ) {
+ return false;
+ }
+ QByteArray payload = mimeSource->encodedData("application/x-uml-clip3");
+ if ( !payload.size() ) {
+ return false;
+ }
+ QTextStream clipdata(payload, IO_ReadOnly);
+ QString xmiClip = QString::fromUtf8(payload);
+
+ QString error;
+ int line;
+ QDomDocument domDoc;
+ if( !domDoc.setContent(xmiClip, false, &error, &line) ) {
+ kWarning() << "getClip3Type: Can't set content:" << error << " Line:" << line << endl;
+ return false;
+ }
+ QDomNode xmiClipNode = domDoc.firstChild();
+ QDomElement root = xmiClipNode.toElement();
+ if ( root.isNull() ) {
+ return false;
+ }
+ // make sure it is an XMI clip
+ if (root.tagName() != "xmiclip") {
+ return false;
+ }
+
+ QDomNode listItemNode = xmiClipNode.firstChild();
+ QDomNode listItems = listItemNode.firstChild();
+ QDomElement listItemElement = listItems.toElement();
+ if ( listItemElement.isNull() ) {
+ kWarning() << "getClip3Type: no listitems in XMI clip" << endl;
+ return false;
+ }
+ while ( !listItemElement.isNull() ) {
+ QString typeStr = listItemElement.attribute( "type", "-1" );
+ if (typeStr == "-1") {
+ kDebug() << "getClip3Type: bad type" << endl;
+ return false;
+ }
+ QString idStr = listItemElement.attribute( "id", "-1" );
+ if (idStr == "-1") {
+ kDebug() << "getClip3Type: bad id" << endl;
+ return false;
+ }
+ LvTypeAndID * pData = new LvTypeAndID;
+ pData->type = (Uml::ListView_Type)(typeStr.toInt());
+ pData->id = STR2ID(idStr);
+ typeAndIdList.append(pData);
+ listItems = listItems.nextSibling();
+ listItemElement = listItems.toElement();
+ }
+ return true;
+}
+
+bool UMLDrag::decodeClip3(const QMimeSource* mimeSource, UMLListViewItemList& umlListViewItems,
+ const UMLListView* parentListView){
+ if ( !mimeSource->provides("application/x-uml-clip3") ) {
+ return false;
+ }
+ QByteArray payload = mimeSource->encodedData("application/x-uml-clip3");
+ if ( !payload.size() ) {
+ return false;
+ }
+ QTextStream clipdata(payload, IO_ReadOnly);
+ QString xmiClip = QString::fromUtf8(payload);
+
+ QString error;
+ int line;
+ QDomDocument domDoc;
+ if( !domDoc.setContent(xmiClip, false, &error, &line) ) {
+ kWarning() << "Can't set content:" << error << " Line:" << line << endl;
+ return false;
+ }
+ QDomNode xmiClipNode = domDoc.firstChild();
+ QDomElement root = xmiClipNode.toElement();
+ if ( root.isNull() ) {
+ return false;
+ }
+ // make sure it is an XMI clip
+ if (root.tagName() != "xmiclip") {
+ return false;
+ }
+
+ //listviewitems
+ QDomNode listItemNode = xmiClipNode.firstChild();
+ QDomNode listItems = listItemNode.firstChild();
+ QDomElement listItemElement = listItems.toElement();
+ if ( listItemElement.isNull() ) {
+ kWarning() << "no listitems in XMI clip" << endl;
+ return false;
+ }
+ while ( !listItemElement.isNull() ) {
+ // Get the ListView_Type beforehand so that we can construct an
+ // UMLListViewItem instance.
+ QString type = listItemElement.attribute( "type", "-1" );
+ if (type == "-1") {
+ kDebug() << "Pech gehabt" << endl;
+ continue;
+ }
+ Uml::ListView_Type t = (Uml::ListView_Type)(type.toInt());
+ UMLListViewItem* parent = parentListView->determineParentItem(t);
+ UMLListViewItem* itemData = new UMLListViewItem(parent);
+ if ( itemData->loadFromXMI(listItemElement) )
+ umlListViewItems.append(itemData);
+ else
+ delete itemData;
+ listItems = listItems.nextSibling();
+ listItemElement = listItems.toElement();
+ }
+ return true;
+}
+
+bool UMLDrag::decodeClip4(const QMimeSource* mimeSource, UMLObjectList& objects,
+ UMLWidgetList& widgets,
+ AssociationWidgetList& associations, Uml::Diagram_Type & dType) {
+ if ( !mimeSource->provides("application/x-uml-clip4") ) {
+ return false;
+ }
+ QByteArray payload = mimeSource->encodedData("application/x-uml-clip4");
+ if ( !payload.size() ) {
+ return false;
+ }
+
+ QString xmiClip = QString::fromUtf8(payload);
+
+ QString error;
+ int line;
+ QDomDocument domDoc;
+ if( !domDoc.setContent(xmiClip, false, &error, &line) ) {
+ kWarning() << "Can't set content:" << error << " Line:" << line << endl;
+ return false;
+ }
+ QDomNode xmiClipNode = domDoc.firstChild();
+ QDomElement root = xmiClipNode.toElement();
+ if ( root.isNull() ) {
+ return false;
+ }
+ // make sure it is an XMI clip
+ if ( root.tagName() != "xmiclip" ) {
+ return false;
+ }
+
+ dType = (Uml::Diagram_Type)(root.attribute("diagramtype", "0").toInt());
+
+ //UMLObjects
+ QDomNode objectsNode = xmiClipNode.firstChild();
+ QDomNode objectElement = objectsNode.firstChild();
+ QDomElement element = objectElement.toElement();
+ while ( !element.isNull() ) {
+ UMLObject* pObject = 0;
+ QString type = element.tagName();
+ //FIXME associations don't load
+ if (type == "UML:Association")
+ continue;
+ pObject = Object_Factory::makeObjectFromXMI(type);
+
+ if ( !pObject ) {
+ kWarning() << "Given wrong type of umlobject to create: " << type << endl;
+ return false;
+ }
+
+ if ( !pObject->loadFromXMI( element ) ) {
+ kWarning() << "failed to load object from XMI" << endl;
+ return false;
+ }
+
+ objects.append(pObject);
+ objectElement = objectElement.nextSibling();
+ element = objectElement.toElement();
+ }
+
+ //widgets
+ QDomNode widgetsNode = objectsNode.nextSibling();
+ QDomNode widgetNode = widgetsNode.firstChild();
+ QDomElement widgetElement = widgetNode.toElement();
+ if ( widgetElement.isNull() ) {
+ kWarning() << "no widgets in XMI clip" << endl;
+ return false;
+ }
+
+ UMLView *view = UMLApp::app()->getCurrentView();
+ while ( !widgetElement.isNull() ) {
+
+ UMLWidget* widget = view->loadWidgetFromXMI(widgetElement);
+ if (widget)
+ widgets.append(widget);
+
+ widgetNode = widgetNode.nextSibling();
+ widgetElement = widgetNode.toElement();
+ }
+
+ //AssociationWidgets
+ QDomNode associationWidgetsNode = widgetsNode.nextSibling();
+ QDomNode associationWidgetNode = associationWidgetsNode.firstChild();
+ QDomElement associationWidgetElement = associationWidgetNode.toElement();
+ while ( !associationWidgetElement.isNull() ) {
+ AssociationWidget* associationWidget = new AssociationWidget(view);
+ if (associationWidget->loadFromXMI(associationWidgetElement, widgets))
+ associations.append(associationWidget);
+ else {
+ //associationWidget->cleanup();
+ delete associationWidget;
+ }
+ associationWidgetNode = associationWidgetNode.nextSibling();
+ associationWidgetElement = associationWidgetNode.toElement();
+ }
+
+ return true;
+}
+
+bool UMLDrag::decodeClip5(const QMimeSource* mimeSource, UMLObjectList& objects,
+ UMLClassifier* newParent) {
+ if ( !mimeSource->provides("application/x-uml-clip5") ) {
+ return false;
+ }
+ QByteArray payload = mimeSource->encodedData("application/x-uml-clip5");
+ if ( !payload.size() ) {
+ return false;
+ }
+ QString xmiClip = QString::fromUtf8(payload);
+
+ QString error;
+ int line;
+ QDomDocument domDoc;
+ if( !domDoc.setContent(xmiClip, false, &error, &line) ) {
+ kWarning() << "Can't set content:" << error << " Line:" << line << endl;
+ return false;
+ }
+ QDomNode xmiClipNode = domDoc.firstChild();
+ QDomElement root = xmiClipNode.toElement();
+ if ( root.isNull() ) {
+ return false;
+ }
+ // make sure it is an XMI clip
+ if (root.tagName() != "xmiclip") {
+ return false;
+ }
+
+ //UMLObjects
+ QDomNode objectsNode = xmiClipNode.firstChild();
+ QDomNode objectElement = objectsNode.firstChild();
+ QDomElement element = objectElement.toElement();
+ if ( element.isNull() ) {
+ return false;//return ok as it means there is no umlobjects
+ }
+ while ( !element.isNull() ) {
+ QString type = element.tagName();
+ UMLClassifierListItem *pObject = newParent->makeChildObject(type);
+ if( !pObject ) {
+ kWarning() << "Given wrong type of umlobject to create:" << type << endl;
+ return false;
+ }
+ if( !pObject->loadFromXMI( element ) ) {
+ kWarning() << "failed to load object from XMI" << endl;
+ return false;
+ }
+ pObject->resolveRef();
+ objects.append(pObject);
+ objectElement = objectElement.nextSibling();
+ element = objectElement.toElement();
+ }
+
+ return true;
+}
+
+int UMLDrag::getCodingType(const QMimeSource* mimeSource) {
+ int result = 0;
+ if (mimeSource->provides("application/x-uml-clip1") ) {
+ result = 1;
+ }
+ if (mimeSource->provides("application/x-uml-clip2") ) {
+ result = 2;
+ }
+ if (mimeSource->provides("application/x-uml-clip3") ) {
+ result = 3;
+ }
+ if (mimeSource->provides("application/x-uml-clip4") ) {
+ result = 4;
+ }
+ if (mimeSource->provides("application/x-uml-clip5") ) {
+ result = 5;
+ }
+
+ return result;
+}
+
+#include "umldrag.moc"
diff --git a/umbrello/umbrello/clipboard/umldrag.h b/umbrello/umbrello/clipboard/umldrag.h
new file mode 100644
index 00000000..a56a138e
--- /dev/null
+++ b/umbrello/umbrello/clipboard/umldrag.h
@@ -0,0 +1,223 @@
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * copyright (C) 2002-2006 *
+ * Umbrello UML Modeller Authors <uml-devel@uml.sf.net> *
+ ***************************************************************************/
+
+#ifndef UMLDRAG_H
+#define UMLDRAG_H
+
+#include <qdragobject.h>
+#include <qobject.h>
+#include <qptrlist.h>
+
+#include "../umllistviewitemlist.h"
+#include "../associationwidgetlist.h"
+#include "../umlobjectlist.h"
+#include "../umlviewlist.h"
+#include "../umlwidgetlist.h"
+#include "../umlnamespace.h"
+
+/**
+ * This class provides encoding and decoding for the uml data that will be used
+ * in a drag and drop operation or in a copy or paste operation.
+ *
+ * @author Gustavo Madrigal, Jonathan Riddell (XMI conversion)
+ * Bugs and comments to uml-devel@lists.sf.net or http://bugs.kde.org
+ */
+
+class UMLListView;
+class UMLDragPrivate;
+class UMLClassifier;
+
+class Q_EXPORT UMLDrag : public QDragObject {
+ Q_OBJECT
+ UMLDragPrivate* data;
+public:
+
+ /**
+ * For use when the user selects only UML Objects from
+ * the ListView but no diagrams to be copied, Mime type =
+ * "application/x-uml-clip1
+ */
+ explicit UMLDrag(UMLObjectList& Objects,QWidget* dragSource = 0, const char* name = 0 );
+
+ /**
+ * For use when the user selects UML Object and Diagrams
+ * from the ListView to be copied, Mime type =
+ * "application/x-uml-clip2
+ */
+ UMLDrag(UMLObjectList &Objects, UMLListViewItemList& UMLListViewItems,
+ UMLViewList& Diagrams, QWidget * dragSource = 0, const char * name = 0 );
+
+ /**
+ * For use when the user selects only empty folders from
+ * the ListView to be copied, Mime type =
+ * "application/x-uml-clip3
+ */
+ explicit UMLDrag(UMLListViewItemList& UMLListViewItems, QWidget* dragSource = 0,
+ const char* name = 0 );
+
+ /*
+ * For use when the user selects UMLObjects from a
+ * Diagram. The Selected widegets and the relationships *
+ * between only selected widgets will be copied and also
+ * its respective ListView Items, Mime type =
+ * "application/x-uml-clip4
+ */
+ UMLDrag(UMLObjectList& Objects, UMLWidgetList& Widgets, AssociationWidgetList& Associations,
+ QPixmap& PngImage, Uml::Diagram_Type dType, QWidget* dragSource = 0,
+ const char* name = 0 );
+
+ /**
+ * For use when the user selects only Operations and/or
+ * Attributes from the ListView, Mime type =
+ * "application/x-uml-clip5
+ */
+ UMLDrag(UMLObjectList& Objects, int, QWidget* dragSource = 0, const char* name = 0);
+
+ /**
+ * Constructor
+ */
+ explicit UMLDrag(QWidget* dragSource = 0, const char* name = 0);
+
+ /**
+ * Deconstructor
+ */
+ ~UMLDrag();
+
+ /**
+ * For use when the user selects only UMLObjects from the
+ * ListView but no diagrams to be copied
+ */
+ void setUMLDataClip1(UMLObjectList& Objects);
+
+ /**
+ * For use when the user selects UML Object and Diagrams
+ * from the ListView to be copied
+ */
+ void setUMLDataClip2(UMLObjectList& Objects, UMLListViewItemList& UMLListViewItems,
+ UMLViewList& Diagrams);
+
+ /**
+ * For use when the user selects only empty folders from the ListView
+ * to be copied.
+ */
+ void setUMLDataClip3(UMLListViewItemList& UMLListViewItems);
+
+ /**
+ * For use when the user selects UML Objects from a
+ * Diagram. The Selected widegets and the relationships
+ * between only selected widgets will be copied and also
+ * its respective ListView Items
+ */
+ void setUMLDataClip4(UMLObjectList& Objects,
+ UMLWidgetList& WidgetDatas,
+ AssociationWidgetList& Associations, QPixmap& PngImage,
+ Uml::Diagram_Type dType);
+
+ /**
+ * For use when the user selects only Attirbutes and/or
+ * Operation from the ListView
+ */
+ void setUMLDataClip5(UMLObjectList& Objects);
+
+ /**
+ * Sets the type of the clip to "application/x-uml-" + sub
+ * sub should be clip[1-5]
+ */
+ virtual void setSubType(const QCString& sub, int index);
+
+ /**
+ * Sets the data in the clip
+ */
+ virtual void setEncodedData(const QByteArray&, int index);
+
+ /**
+ * Returns the type set by setSubType
+ */
+ const char* format(int index) const;
+
+ /**
+ * Returns the encoded data of the given type
+ *
+ * @param dataName the name of the data type to return
+ */
+ virtual QByteArray encodedData(const char* dataName) const;
+
+ /**
+ * For use when the user selects only UML Objects
+ * from the ListView but no diagrams to be
+ * copied, decodes Mime type =
+ * "application/x-uml-clip1
+ */
+ static bool decodeClip1(const QMimeSource* mimeSource, UMLObjectList& objects);
+
+ /**
+ * For use when the user selects UML Object and Diagrams
+ * from the ListView to be copied, decodes Mime type =
+ * "application/x-uml-clip2
+ */
+ static bool decodeClip2(const QMimeSource* mimeSource, UMLObjectList& objects,
+ UMLListViewItemList& umlListViewItems,
+ UMLViewList& diagrams);
+
+ /**
+ * For use when the user selects UMLObjects from
+ * the ListView to be copied, decodes Mime * type =
+ * "application/x-uml-clip3
+ */
+ static bool decodeClip3(const QMimeSource* mimeSource,
+ UMLListViewItemList& umlListViewItems,
+ const UMLListView* parentListView=0);
+
+ struct LvTypeAndID {
+ Uml::ListView_Type type;
+ Uml::IDType id;
+ };
+ typedef QPtrList<LvTypeAndID> LvTypeAndID_List;
+ typedef QPtrListIterator<LvTypeAndID> LvTypeAndID_It;
+
+ /**
+ * Return just the LvTypeAndID of a Clip3.
+ *
+ * @param mimeSource The encoded source.
+ * @param typeAndIdList The LvTypeAndID_List decoded from the source.
+ * @return True if decoding was successful.
+ */
+ static bool getClip3TypeAndID(const QMimeSource* mimeSource,
+ LvTypeAndID_List& typeAndIdList);
+
+ /**
+ * For use when the user selects UML Objects from a
+ * Diagram. The Selected widegets and the relationships
+ * between only * selected widgets will be copied and
+ * also its respective ListView Items, * decodes Mime
+ * type = "application/x-uml-clip4
+ */
+ static bool decodeClip4(const QMimeSource* mimeSource, UMLObjectList& objects,
+ UMLWidgetList& widgets,
+ AssociationWidgetList& associations,
+ Uml::Diagram_Type & dType);
+
+ /**
+ * For use when the user selects only Attributes and/or
+ * Operations from the ListView * copied, decodes Mime
+ * type = "application/x-uml-clip5
+ */
+ static bool decodeClip5(const QMimeSource* mimeSource, UMLObjectList& objects,
+ UMLClassifier *newParent);
+
+ /**
+ * Converts application/x-uml-clip[1-5] clip type to an integer
+ */
+ static int getCodingType(const QMimeSource* mimeSource);
+
+};
+
+#endif
diff --git a/umbrello/umbrello/cmdlineexportallviewsevent.cpp b/umbrello/umbrello/cmdlineexportallviewsevent.cpp
new file mode 100644
index 00000000..7c4b3caa
--- /dev/null
+++ b/umbrello/umbrello/cmdlineexportallviewsevent.cpp
@@ -0,0 +1,48 @@
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * copyright (C) 2006-2007 *
+ * Umbrello UML Modeller Authors <uml-devel@uml.sf.net> *
+ ***************************************************************************/
+
+// own header
+#include "cmdlineexportallviewsevent.h"
+
+// qt includes
+#include <qstringlist.h>
+
+// kde includes
+#include <kapplication.h>
+#include <kdebug.h>
+
+// app includes
+#include "uml.h"
+#include "umlviewimageexportermodel.h"
+
+
+int CmdLineExportAllViewsEvent::getType() {
+ return QEvent::User + 1;
+}
+
+CmdLineExportAllViewsEvent::CmdLineExportAllViewsEvent(const QString &imageType, const KURL &directory, const bool useFolders)
+ : QCustomEvent(CmdLineExportAllViewsEvent::getType()) {
+ m_imageType = imageType;
+ m_directory = directory;
+ m_useFolders = useFolders;
+}
+
+void CmdLineExportAllViewsEvent::exportAllViews() {
+ QStringList errors = UMLViewImageExporterModel().exportAllViews(m_imageType, m_directory, m_useFolders);
+ if (!errors.isEmpty()) {
+ kError() << "Errors while exporting:" << endl;
+ for (QStringList::Iterator it = errors.begin(); it != errors.end(); ++it) {
+ kError() << *it << endl;
+ }
+ }
+
+ kapp->sendEvent(UMLApp::app(), new QCloseEvent());
+}
diff --git a/umbrello/umbrello/cmdlineexportallviewsevent.h b/umbrello/umbrello/cmdlineexportallviewsevent.h
new file mode 100644
index 00000000..8c613bee
--- /dev/null
+++ b/umbrello/umbrello/cmdlineexportallviewsevent.h
@@ -0,0 +1,78 @@
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * copyright (C) 2006 *
+ * Umbrello UML Modeller Authors <uml-devel@uml.sf.net> *
+ ***************************************************************************/
+
+#ifndef CMDLINEEXPORTALLVIEWSEVENT_H
+#define CMDLINEEXPORTALLVIEWSEVENT_H
+
+#include <qevent.h>
+#include <kurl.h>
+
+/**
+ * This class provides an event that is posted to the UMLApp when the "export all views"
+ * option was set in the command line. Once the QT main loop begins, the event is processed.
+ *
+ * The processing made in UMLApp is execute the exportAllViews method in the event.
+ * This method exports all the views using UMLViewImageExporterModel and then finishes
+ * the application using a close event.
+ *
+ * @see UMLViewImageExporterModel
+ */
+class CmdLineExportAllViewsEvent : public QCustomEvent {
+public:
+
+ /**
+ * Returns the type of the event.
+ */
+ static int getType();
+
+ /**
+ * Constructor for CmdLineExportAllViewsEvent.
+ *
+ * @param imageType The type of the images the views will be exported to.
+ * @param directory The url of the directory where the images will be saved.
+ * @param useFolders If the tree structure of the views in the document must be created
+ * in the target directory.
+ */
+ CmdLineExportAllViewsEvent(const QString &imageType, const KURL &directory, const bool useFolders);
+
+ /**
+ * Destructor for CmdLineExportAllViewsEvent
+ */
+ virtual ~CmdLineExportAllViewsEvent() {
+ }
+
+ /**
+ * Exports all the views using UMLViewImageExporterModel, prints the errors
+ * occurred in the error output and sends a close event to the application to finish it.
+ * To export the views, it uses the attributes set when the event was created.
+ */
+ void exportAllViews();
+
+private:
+
+ /**
+ * The type of the images the views will be exported to.
+ */
+ QString m_imageType;
+
+ /**
+ * The url of the directory where the images will be saved.
+ */
+ KURL m_directory;
+
+ /**
+ * If the tree structure of the views in the document must be created
+ * in the target directory.
+ */
+ bool m_useFolders;
+};
+
+#endif
diff --git a/umbrello/umbrello/codeaccessormethod.cpp b/umbrello/umbrello/codeaccessormethod.cpp
new file mode 100644
index 00000000..329bef51
--- /dev/null
+++ b/umbrello/umbrello/codeaccessormethod.cpp
@@ -0,0 +1,195 @@
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * copyright (C) 2004-2007 *
+ * Umbrello UML Modeller Authors <uml-devel@uml.sf.net> *
+ ***************************************************************************/
+
+/* This code generated by:
+ * Author : thomas
+ * Date : Tue Jul 1 2003
+ */
+
+// own header
+#include "codeaccessormethod.h"
+
+// qt/kde includes
+#include <kdebug.h>
+
+// local includes
+#include "classifiercodedocument.h"
+#include "codeclassfield.h"
+#include "attribute.h"
+#include "umlobject.h"
+#include "umlrole.h"
+
+// Constructors/Destructors
+//
+
+CodeAccessorMethod::CodeAccessorMethod ( CodeClassField * parentCF )
+ : CodeMethodBlock ( parentCF->getParentDocument(), parentCF->getParentObject() )
+{
+ initFields(parentCF);
+}
+
+CodeAccessorMethod::~CodeAccessorMethod ( ) { }
+
+//
+// Methods
+//
+
+
+// Accessor methods
+//
+
+/**
+ * Get the value of m_parentclassfield
+ * @return the value of m_parentclassfield
+ */
+CodeClassField * CodeAccessorMethod::getParentClassField ( ) {
+ return m_parentclassfield;
+}
+
+bool CodeAccessorMethod::parentIsAttribute( ) {
+ return getParentClassField()->parentIsAttribute();
+}
+
+/**
+ * Utility method to get the value of the parent object of the parent classifield.
+ * @return the value of the parent of the parent classfield
+ */
+/*
+UMLObject * CodeAccessorMethod::getParentObject ( ) {
+ return getParentClassField()->getParentObject();
+}
+*/
+
+/** return the type of accessor method this is
+ */
+CodeAccessorMethod::AccessorType CodeAccessorMethod::getType( ) {
+ return m_accessorType;
+}
+
+/** Set the type of accessor method this is
+ */
+void CodeAccessorMethod::setType ( CodeAccessorMethod::AccessorType atype) {
+ m_accessorType = atype;
+}
+
+// Other methods
+//
+
+
+// this type of textblock is special
+// we DON'T release it when resetTextBlocks is
+// called because we re-use it over and over
+// until the codeclassfield is released.
+void CodeAccessorMethod::release () {
+ // do nothing
+}
+
+// ok, a method so the parent can force it to release
+void CodeAccessorMethod::forceRelease () {
+ if(m_parentclassfield)
+ m_parentclassfield->disconnect(this);
+ CodeMethodBlock::release();
+}
+
+/**
+ * load params from the appropriate XMI element node.
+ */
+void CodeAccessorMethod::loadFromXMI ( QDomElement & root ) {
+ setAttributesFromNode(root);
+}
+
+/**
+ * Save the XMI representation of this object
+ */
+void CodeAccessorMethod::saveToXMI ( QDomDocument & doc, QDomElement & root ) {
+ QDomElement docElement = doc.createElement( "codeaccessormethod" );
+
+ setAttributesOnNode(doc, docElement);
+
+ root.appendChild( docElement );
+}
+
+/** set attributes of the node that represents this class
+ * in the XMI document.
+ */
+void CodeAccessorMethod::setAttributesOnNode ( QDomDocument & doc, QDomElement & elem)
+{
+
+ // set super-class attributes
+ CodeMethodBlock::setAttributesOnNode(doc, elem);
+
+ // set local class attributes
+ elem.setAttribute("accessType",getType());
+ elem.setAttribute("classfield_id",getParentClassField()->getID());
+
+}
+
+/** set the class attributes of this object from
+ * the passed element node.
+ */
+void CodeAccessorMethod::setAttributesFromNode ( QDomElement & root) {
+
+ // set attributes from the XMI
+ CodeMethodBlock::setAttributesFromNode(root); // superclass load
+
+ /*
+ // I don't believe this is needed for a load from XMI. We never delete
+ // accessor methods from the parent classfield.. they are essentially
+ // in composition with the parent class and are arent meant to be out
+ // on their own. Well, this is fine for now, but IF we start allowing
+ // clipping and pasting of these methods between classes/ classfields
+ // then we may have problems (ugh.. I cant imagine allowing this, but
+ // perhaps someone will see a need to allow it. -b.t.)
+ QString id = root.attribute("classfield_id","-1");
+ CodeClassField * newCF = 0;
+ ClassifierCodeDocument * cdoc = dynamic_cast<ClassifierCodeDocument*>(getParentDocument());
+ if(cdoc)
+ newCF = cdoc->findCodeClassFieldFromParentID (STR2ID(id));
+
+ m_parentclassfield->disconnect(this); // always disconnect
+ if(newCF)
+ initFields(newCF);
+ else
+ kError()<<"ERROR: code accessor method cant load parent codeclassfield, corrupt file?"<<endl;
+
+ */
+ // now load/set other local attributes
+ setType((AccessorType) root.attribute("accessType","0").toInt());
+
+}
+
+void CodeAccessorMethod::setAttributesFromObject(TextBlock * obj)
+{
+
+ CodeMethodBlock::setAttributesFromObject(obj);
+
+ CodeAccessorMethod * mb = dynamic_cast<CodeAccessorMethod*>(obj);
+ if(mb)
+ {
+ m_parentclassfield->disconnect(this); // always disconnect
+
+ initFields(mb->getParentClassField());
+
+ setType(mb->getType());
+ }
+
+}
+
+void CodeAccessorMethod::initFields(CodeClassField * parentClassField ) {
+
+ m_parentclassfield = parentClassField;
+ m_accessorType = GET;
+ m_canDelete = false; // we cant delete these with the codeeditor, delete the UML operation instead.
+
+ connect(m_parentclassfield,SIGNAL(modified()),this,SLOT(syncToParent()));
+}
+
+#include "codeaccessormethod.moc"
diff --git a/umbrello/umbrello/codeaccessormethod.h b/umbrello/umbrello/codeaccessormethod.h
new file mode 100644
index 00000000..03e8ff67
--- /dev/null
+++ b/umbrello/umbrello/codeaccessormethod.h
@@ -0,0 +1,118 @@
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the 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 code generated by:
+ * Author : thomas
+ * Date : Tue Jul 1 2003
+ */
+
+
+
+#ifndef CODEACCESSORMETHOD_H
+#define CODEACCESSORMETHOD_H
+
+#include <qstring.h>
+#include "codemethodblock.h"
+
+class CodeClassField;
+
+class CodeAccessorMethod : public CodeMethodBlock
+{
+ friend class CodeClassField;
+ Q_OBJECT
+public:
+
+ // some types of accessor methods that are possible:
+ // "GET" is to retrieve single-valued (primative or Object) fields
+ // "SET" is to set single-valued (primative or Object) fields
+ // "ADD" is to add a value to a multiple-valued field of either primative or Object items
+ // "REMOVE" is to remove a value to a multiple-valued field of either primative or Object items
+ // "LIST" is to retrive the entire list of items in a multiple-valued field
+ enum AccessorType {GET=0, SET, ADD, REMOVE, LIST};
+
+ // Constructors/Destructors
+ //
+
+
+ /**
+ * Constructors
+ */
+ CodeAccessorMethod ( CodeClassField * field );
+
+ /**
+ * Empty Destructor
+ */
+ virtual ~CodeAccessorMethod ( );
+
+ /**
+ * Get the value of m_parentclassfield
+ * @return the value of m_parentclassfield
+ */
+ CodeClassField * getParentClassField ( );
+
+ /** return the type of accessor method this is
+ */
+ AccessorType getType( );
+
+ /** Set the type of accessor method this is
+ */
+ void setType ( AccessorType type);
+
+ /** Utility method to get the value of the parent object of the parent classifield.
+ */
+ // virtual UMLObject * getParentObject();
+
+ bool parentIsAttribute();
+
+ /**
+ * Save the XMI representation of this object
+ */
+ virtual void saveToXMI ( QDomDocument & doc, QDomElement & root );
+
+ /**
+ * load params from the appropriate XMI element node.
+ */
+ virtual void loadFromXMI ( QDomElement & root );
+
+ /** set the class attributes from a passed object
+ */
+ virtual void setAttributesFromObject (TextBlock * obj);
+
+protected:
+
+ virtual void release ();
+
+ /** set attributes of the node that represents this class
+ * in the XMI document.
+ */
+ virtual void setAttributesOnNode ( QDomDocument & doc, QDomElement & blockElement);
+
+ /** set the class attributes of this object from
+ * the passed element node.
+ */
+ virtual void setAttributesFromNode ( QDomElement & element);
+
+ virtual void updateMethodDeclaration() = 0;
+
+ virtual void updateContent() = 0;
+
+ // a method so the parent code classfield can force code block to release
+ void forceRelease ();
+
+private:
+
+ CodeClassField * m_parentclassfield;
+ AccessorType m_accessorType;
+
+ void initFields(CodeClassField * parentCF );
+
+};
+
+#endif // CODEACCESSORMETHOD_H
diff --git a/umbrello/umbrello/codeaccessormethodlist.h b/umbrello/umbrello/codeaccessormethodlist.h
new file mode 100644
index 00000000..96693f2f
--- /dev/null
+++ b/umbrello/umbrello/codeaccessormethodlist.h
@@ -0,0 +1,23 @@
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * copyright (C) 2004-2007 *
+ * Umbrello UML Modeller Authors <uml-devel@uml.sf.net> *
+ ***************************************************************************/
+
+#ifndef _CODEACCESSORMETHODLIST_H
+#define _CODEACCESSORMETHODLIST_H
+
+#include <qptrlist.h>
+
+// forward declarations
+class CodeAccessorMethod;
+
+typedef QPtrList<CodeAccessorMethod> CodeAccessorMethodList;
+typedef QPtrListIterator<CodeAccessorMethod> CodeAccessorMethodListIt;
+
+#endif
diff --git a/umbrello/umbrello/codeblock.cpp b/umbrello/umbrello/codeblock.cpp
new file mode 100644
index 00000000..d1705348
--- /dev/null
+++ b/umbrello/umbrello/codeblock.cpp
@@ -0,0 +1,143 @@
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the 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 code generated by:
+ * Author : thomas
+ * Date : Wed Jun 18 2003
+ */
+
+#include "codeblock.h"
+#include "codedocument.h"
+
+#include "hierarchicalcodeblock.h"
+
+// Constructors/Destructors
+//
+
+CodeBlock::CodeBlock ( HierarchicalCodeBlock * hblock , const QString & body )
+ : TextBlock ( hblock->getParentDocument(), body )
+{
+ initFields ( );
+}
+
+CodeBlock::CodeBlock ( CodeDocument * doc, const QString & body )
+ : TextBlock ( doc, body )
+{
+ initFields( );
+}
+
+CodeBlock::~CodeBlock ( ) { }
+
+//
+// Methods
+//
+
+
+// Accessor methods
+//
+
+
+// Public attribute accessor methods
+//
+
+
+/**
+ * Set the value of m_contentType
+ * specifies whether the content (text) of this object was generated by the code
+ * generator or was supplied by the user.
+ * @param new_var the new value of m_contentType
+ */
+void CodeBlock::setContentType ( ContentType new_var ) {
+ m_contentType = new_var;
+}
+
+/**
+ * Get the value of m_contentType
+ * specifies whether the content (text) of this object was generated by the code
+ * generator or was supplied by the user.
+ * @return the value of m_contentType
+ */
+CodeBlock::ContentType CodeBlock::getContentType ( ) {
+ return m_contentType;
+}
+
+/**
+ * Get the value of m_dialog
+ * @return the value of m_dialog
+ */
+/*
+CodeBlockDialog * CodeBlock::getDialog ( ) {
+ return m_dialog;
+}
+*/
+
+// Other methods
+//
+
+/**
+ * Save the XMI representation of this object
+ */
+void CodeBlock::saveToXMI ( QDomDocument & doc, QDomElement & root ) {
+ QDomElement blockElement = doc.createElement( "codeblock" );
+
+ // set attributes
+ setAttributesOnNode(doc, blockElement);
+
+ root.appendChild( blockElement );
+}
+
+void CodeBlock::setAttributesOnNode( QDomDocument & doc, QDomElement & blockElement)
+{
+
+ // call super-class
+ TextBlock::setAttributesOnNode(doc, blockElement);
+
+ // local attributes
+ if(m_contentType != AutoGenerated)
+ blockElement.setAttribute("contentType",getContentType());
+
+}
+
+/**
+ * load params from the appropriate XMI element node.
+ */
+void CodeBlock::loadFromXMI ( QDomElement & root ) {
+
+ setAttributesFromNode(root);
+
+}
+
+void CodeBlock::setAttributesFromNode (QDomElement & elem) {
+
+ // set attributes from the XMI in super-class
+ TextBlock::setAttributesFromNode(elem);
+
+ // set local fields now
+ setContentType(((ContentType) elem.attribute("contentType","0").toInt()));
+
+}
+
+void CodeBlock::setAttributesFromObject(TextBlock * obj)
+{
+
+ TextBlock::setAttributesFromObject(obj);
+
+ CodeBlock * cb = dynamic_cast<CodeBlock*>(obj);
+ if(cb)
+ setContentType(cb->getContentType());
+
+}
+
+void CodeBlock::initFields ( ) {
+ m_contentType = AutoGenerated;
+ // m_dialog = new CodeBlockDialog( );
+}
+
+#include "codeblock.moc"
diff --git a/umbrello/umbrello/codeblock.h b/umbrello/umbrello/codeblock.h
new file mode 100644
index 00000000..c01b6c9f
--- /dev/null
+++ b/umbrello/umbrello/codeblock.h
@@ -0,0 +1,121 @@
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * copyright (C) 2004-2006 *
+ * Umbrello UML Modeller Authors <uml-devel@uml.sf.net> *
+ ***************************************************************************/
+
+/* This code generated by:
+ * Author : thomas
+ * Date : Wed Jun 18 2003
+ */
+
+
+
+#ifndef CODEBLOCK_H
+#define CODEBLOCK_H
+
+
+#include "textblock.h"
+
+class HierarchicalCodeBlock;
+
+
+/**
+ * class CodeBlock
+ * A "chunk" of code within the code document.
+ */
+
+class CodeBlock : public TextBlock
+{
+ Q_OBJECT
+public:
+
+ enum ContentType {AutoGenerated=0, UserGenerated };
+
+ // Constructors/Destructors
+ //
+
+ /** constructor with QString so we can create & populate it in
+ * one step.
+ */
+ explicit CodeBlock ( CodeDocument * parent, const QString & body = "");
+ explicit CodeBlock ( HierarchicalCodeBlock * parent, const QString & body = "" );
+
+ /**
+ * Empty Destructor
+ */
+ virtual ~CodeBlock ( );
+
+ // Public attributes
+ //
+
+
+ // Public attribute accessor methods
+ //
+
+ /**
+ * Set the value of m_contentType
+ * specifies whether the content (text) of this object was generated by the code
+ * generator or was supplied by the user.
+ * @param new_var the new value of m_contentType
+ */
+ void setContentType ( ContentType new_var );
+
+ /**
+ * Get the value of m_contentType
+ * specifies whether the content (text) of this object was generated by the code
+ * generator or was supplied by the user.
+ * @return the value of m_contentType
+ */
+ ContentType getContentType ( );
+
+ /**
+ * Get the value of m_dialog
+ * @return the value of m_dialog
+ */
+ // CodeBlockDialog getDialog ( );
+
+ /**
+ * Save the XMI representation of this object
+ */
+ virtual void saveToXMI ( QDomDocument & doc, QDomElement & root );
+
+ /**
+ * load params from the appropriate XMI element node.
+ */
+ virtual void loadFromXMI ( QDomElement & root );
+
+ /** set the class attributes from a passed object
+ */
+ virtual void setAttributesFromObject (TextBlock * obj);
+
+protected:
+
+ /** set attributes of the node that represents this class
+ * in the XMI document.
+ */
+ virtual void setAttributesOnNode ( QDomDocument & doc, QDomElement & blockElement);
+
+ /** set the class attributes of this object from
+ * the passed element node.
+ */
+ virtual void setAttributesFromNode ( QDomElement & element);
+
+private:
+
+ // CodeBlockDialog * m_dialog;
+
+ // specifies whether the content (text) of this object
+ // was generated by the code generator or was supplied by the user (or some other way).
+ ContentType m_contentType;
+
+ void initFields ( );
+
+};
+
+#endif // CODEBLOCK_H
diff --git a/umbrello/umbrello/codeblockwithcomments.cpp b/umbrello/umbrello/codeblockwithcomments.cpp
new file mode 100644
index 00000000..0e94001f
--- /dev/null
+++ b/umbrello/umbrello/codeblockwithcomments.cpp
@@ -0,0 +1,181 @@
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * copyright (C) 2004-2007 *
+ * Umbrello UML Modeller Authors <uml-devel@uml.sf.net> *
+ ***************************************************************************/
+
+/* This code generated by:
+ * Author : thomas
+ * Date : Wed Jun 18 2003
+ */
+
+// own header
+#include "codeblockwithcomments.h"
+
+// qt/kde includes
+#include <kdebug.h>
+
+// local includes
+#include "codedocument.h"
+#include "hierarchicalcodeblock.h"
+#include "codegenerators/codegenfactory.h"
+
+// Constructors/Destructors
+//
+
+CodeBlockWithComments::CodeBlockWithComments ( HierarchicalCodeBlock * hb, const QString & body, const QString & comment)
+ : CodeBlock (hb, body)
+{
+ initFields(hb->getParentDocument(), comment);
+}
+
+CodeBlockWithComments::CodeBlockWithComments ( CodeDocument * parent , const QString & body, const QString & comment)
+ : CodeBlock (parent, body)
+{
+ initFields(parent, comment);
+}
+
+CodeBlockWithComments::~CodeBlockWithComments ( ) { }
+
+//
+// Methods
+//
+
+
+// Accessor methods
+//
+
+
+/**
+ * Set the comment on this code block.
+ */
+void CodeBlockWithComments::setComment ( CodeComment * object ) {
+ m_comment = object;
+}
+
+/**
+ * Remove a Comment object from m_commentVector List
+ */
+CodeComment * CodeBlockWithComments::getComment ( ) {
+ return m_comment;
+}
+
+// Other methods
+//
+
+/**
+ * Save the XMI representation of this object
+ */
+void CodeBlockWithComments::saveToXMI ( QDomDocument & doc, QDomElement & root ) {
+ QDomElement blockElement = doc.createElement( "codeblockwithcomments" );
+
+ // set attributes
+ setAttributesOnNode(doc, blockElement);
+
+ root.appendChild( blockElement );
+}
+
+void CodeBlockWithComments::setAttributesOnNode ( QDomDocument & doc, QDomElement & blockElement)
+{
+
+ // set super-class attributes
+ CodeBlock::setAttributesOnNode(doc, blockElement);
+
+ // set local attributes now..e.g. a comment
+ // which we will store in its own separate child node block
+ QDomElement commElement = doc.createElement( "header" );
+ getComment()->saveToXMI(doc, commElement); // comment
+ blockElement.appendChild( commElement);
+
+}
+
+void CodeBlockWithComments::setAttributesFromObject(TextBlock * obj)
+{
+
+ CodeBlock::setAttributesFromObject(obj);
+
+ CodeBlockWithComments * cb = dynamic_cast<CodeBlockWithComments*>(obj);
+ if(cb)
+ getComment()->setAttributesFromObject((TextBlock*)cb->getComment());
+
+}
+
+/**
+ * load params from the appropriate XMI element node.
+ */
+void CodeBlockWithComments::loadFromXMI ( QDomElement & root )
+{
+ setAttributesFromNode(root);
+}
+
+void CodeBlockWithComments::setAttributesFromNode( QDomElement & root)
+{
+
+ // set attributes from superclass method the XMI
+ CodeBlock::setAttributesFromNode(root);
+
+ // load comment now
+ // by looking for our particular child element
+ QDomNode node = root.firstChild();
+ QDomElement element = node.toElement();
+ bool gotComment = false;
+ while( !element.isNull() ) {
+ QString tag = element.tagName();
+ if( tag == "header" ) {
+ QDomNode cnode = element.firstChild();
+ QDomElement celem = cnode.toElement();
+ getComment()->loadFromXMI(celem);
+ gotComment = true;
+ break;
+ }
+ node = element.nextSibling();
+ element = node.toElement();
+ }
+
+ if(!gotComment)
+ kWarning()<<" loadFromXMI : Warning: unable to initialize CodeComment in block:"<<getTag()<<endl;
+
+}
+
+/**
+ * @return QString
+ */
+QString CodeBlockWithComments::toString ( ) {
+
+ QString string = QString();
+
+ if(getWriteOutText()) {
+ QString indent = getIndentationString();
+ QString endLine = getNewLineEndingChars();
+ QString body = formatMultiLineText (getText(), indent, endLine);
+ QString comment = getComment()->toString();
+
+ if(!comment.isEmpty() && getComment()->getWriteOutText())
+ string.append(comment);
+ if(!body.isEmpty())
+ string.append(body);
+ }
+
+ return string;
+}
+
+// slave indentation level for both the header and text body
+void CodeBlockWithComments::setOverallIndentationLevel ( int level )
+{
+ setIndentationLevel(level);
+ m_comment->setIndentationLevel(level);
+}
+
+void CodeBlockWithComments::initFields(CodeDocument *parent, const QString& comment)
+{
+ CodeComment * codecomment = CodeGenFactory::newCodeComment(parent);
+ codecomment->setText(comment);
+ m_comment = codecomment;
+}
+
+#include "codeblockwithcomments.moc"
diff --git a/umbrello/umbrello/codeblockwithcomments.h b/umbrello/umbrello/codeblockwithcomments.h
new file mode 100644
index 00000000..85226077
--- /dev/null
+++ b/umbrello/umbrello/codeblockwithcomments.h
@@ -0,0 +1,107 @@
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the 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 code generated by:
+ * Author : thomas
+ * Date : Wed Jun 18 2003
+ */
+
+
+
+#ifndef CODEBLOCKWITHCOMMENTS_H
+#define CODEBLOCKWITHCOMMENTS_H
+
+
+#include "codeblock.h"
+#include "codecomment.h"
+
+class HierarchicalCodeBlock;
+
+/**
+ * class CodeBlockWithComments
+ * A very common type of text block in any type of code.
+ */
+
+class CodeBlockWithComments : public CodeBlock
+{
+ Q_OBJECT
+public:
+
+ // Constructors/Destructors
+ //
+
+
+ /**
+ * Basic Constructor
+ */
+ explicit CodeBlockWithComments ( CodeDocument * doc , const QString & body = "", const QString & comment = "");
+ explicit CodeBlockWithComments ( HierarchicalCodeBlock * hblock, const QString & body = "", const QString & comment = "" );
+
+ /**
+ * Empty Destructor
+ */
+ virtual ~CodeBlockWithComments ( );
+
+
+ /**
+ * Set the Comment object
+ */
+ void setComment ( CodeComment * object );
+
+ /**
+ * Get the Comment object
+ */
+ CodeComment * getComment ( );
+
+ /**
+ * @return QString
+ */
+ virtual QString toString ( );
+
+ /** A utility method that causes the comment and body of the code block
+ * to have the same indentation level.
+ */
+ void setOverallIndentationLevel ( int level );
+
+ /**
+ * Save the XMI representation of this object
+ */
+ virtual void saveToXMI ( QDomDocument & doc, QDomElement & root );
+
+ /**
+ * load params from the appropriate XMI element node.
+ */
+ virtual void loadFromXMI ( QDomElement & root );
+
+ /** set the class attributes from a passed object
+ */
+ virtual void setAttributesFromObject (TextBlock * obj);
+
+protected:
+
+ /** set attributes of the node that represents this class
+ * in the XMI document.
+ */
+ virtual void setAttributesOnNode (QDomDocument & doc, QDomElement & blockElement);
+
+ /** set the class attributes of this object from
+ * the passed element node.
+ */
+ virtual void setAttributesFromNode ( QDomElement & element);
+
+private:
+
+ CodeComment * m_comment;
+
+ void initFields(CodeDocument *parent, const QString& comment);
+
+};
+
+#endif // CODEBLOCKWITHCOMMENTS_H
diff --git a/umbrello/umbrello/codeclassfield.cpp b/umbrello/umbrello/codeclassfield.cpp
new file mode 100644
index 00000000..a19e664d
--- /dev/null
+++ b/umbrello/umbrello/codeclassfield.cpp
@@ -0,0 +1,617 @@
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * copyright (C) 2004-2006 *
+ * Umbrello UML Modeller Authors <uml-devel@uml.sf.net> *
+ ***************************************************************************/
+
+/* This code generated by:
+ * Author : thomas
+ * Date : Fri Jun 20 2003
+ */
+
+// own header
+#include "codeclassfield.h"
+// qt/kde includes
+#include <qregexp.h>
+#include <kdebug.h>
+// app includes
+#include "association.h"
+#include "classifiercodedocument.h"
+#include "codegenerator.h"
+#include "attribute.h"
+#include "umlobject.h"
+#include "umlrole.h"
+#include "uml.h"
+#include "codegenerators/codegenfactory.h"
+
+// Constructors/Destructors
+//
+
+CodeClassField::CodeClassField ( ClassifierCodeDocument * doc , UMLRole * role)
+ : CodeParameter ( doc , (UMLObject*) role)
+{
+
+ setParentUMLObject(role);
+ initFields(true);
+
+}
+
+CodeClassField::CodeClassField ( ClassifierCodeDocument * doc , UMLAttribute * attrib)
+ : CodeParameter ( doc , (UMLObject*) attrib )
+{
+
+ setParentUMLObject(attrib);
+ initFields(true);
+
+}
+
+CodeClassField::~CodeClassField ( ) {
+
+ // remove methods from parent document
+ CodeAccessorMethodList list = m_methodVector;
+ for(CodeAccessorMethod * m = list.first(); m ; m=list.next())
+ {
+ getParentDocument()->removeTextBlock(m);
+ m->forceRelease();
+ }
+ list.clear();
+
+ // clear the decl block from parent text block list too
+ if(m_declCodeBlock)
+ {
+ getParentDocument()->removeTextBlock(m_declCodeBlock);
+ m_declCodeBlock->forceRelease();
+ delete m_declCodeBlock;
+ }
+
+}
+
+//
+// Methods
+//
+
+
+// Accessor methods
+//
+
+void CodeClassField::setParentUMLObject (UMLObject * obj) {
+ UMLRole *role = dynamic_cast<UMLRole*>(obj);
+ if(role) {
+ UMLAssociation * parentAssoc = role->getParentAssociation();
+ Uml::Association_Type atype = parentAssoc->getAssocType();
+ m_parentIsAttribute = false;
+
+ if ( atype == Uml::at_Association || atype == Uml::at_Association_Self)
+ m_classFieldType = PlainAssociation; // Plain == Self + untyped associations
+ else if (atype == Uml::at_Aggregation)
+ m_classFieldType = Aggregation;
+ else if (atype == Uml::at_Composition)
+ m_classFieldType = Composition;
+ } else {
+ m_classFieldType = Attribute;
+ m_parentIsAttribute = true;
+ }
+}
+
+// Public attribute accessor methods
+//
+
+QString CodeClassField::getTypeName ( ) {
+
+ if (parentIsAttribute())
+ {
+ UMLAttribute * at = (UMLAttribute*) getParentObject();
+ return at->getTypeName();
+ } else {
+ UMLRole * role = (UMLRole*) getParentObject();
+ if(fieldIsSingleValue()) {
+ return getUMLObjectName(role->getObject());
+ } else {
+ return role->getName();
+ }
+ }
+}
+
+// get the type of object that will be added/removed from lists
+// of objects (as per specification of associations)
+QString CodeClassField::getListObjectType() {
+ QString type = QString ("");
+ if (!parentIsAttribute())
+ {
+ UMLRole * role = dynamic_cast<UMLRole*>(getParentObject());
+ type = getUMLObjectName(role->getObject());
+ }
+ return type;
+}
+
+/**
+ * Get the value of m_isAbstract
+ * @return the value of m_isAbstract
+ */
+bool CodeClassField::parentIsAttribute ( ) {
+ return m_parentIsAttribute;
+ // return (m_classFieldType == Attribute) ? true : false;
+}
+
+/**
+ * Get the type of classfield this is.
+ */
+CodeClassField::ClassFieldType CodeClassField::getClassFieldType() {
+ return m_classFieldType;
+}
+
+/**
+ * Get the value of m_dialog
+ * @return the value of m_dialog
+ */
+/*
+CodeClassFieldDialog * CodeClassField::getDialog ( ) {
+ return m_dialog;
+}
+*/
+
+// methods like this _shouldn't_ be needed IF we properly did things thruought the code.
+QString CodeClassField::getUMLObjectName(UMLObject *obj)
+{
+ return (obj!=0)?obj->getName():QString("NULL");
+}
+
+/**
+ * Add a Method object to the m_methodVector List
+ */
+bool CodeClassField::addMethod ( CodeAccessorMethod * add_object ) {
+
+ CodeAccessorMethod::AccessorType type = add_object->getType();
+
+ if(findMethodByType(type))
+ return false;
+ /*
+ // this wont work as the key for QMap needs to inherit from QObject
+ if(m_methodMap->contains(type))
+ return false; // return false, we already have some object with this tag in the list
+ else
+ m_methodMap->insert(type, add_object);
+ */
+
+ m_methodVector.append(add_object);
+ return true;
+}
+
+/**
+ * Remove a Method object from m_methodVector List
+ */
+bool CodeClassField::removeMethod ( CodeAccessorMethod * remove_object ) {
+ // m_methodMap->erase(remove_object->getType());
+ m_methodVector.removeRef(remove_object);
+ getParentDocument()->removeTextBlock(remove_object);
+ return true;
+}
+
+/**
+ * Get the list of Method objects held by m_methodVector
+ * @return QPtrList<CodeMethodBlock *> list of Method objects held by
+ * m_methodVector
+ */
+CodeAccessorMethodList CodeClassField::getMethodList() {
+ return m_methodVector;
+}
+
+/** determine if we will *allow* methods to be viewable.
+ * this flag is often used to toggle autogeneration of accessor
+ * methods in the code class field.
+ */
+bool CodeClassField::getWriteOutMethods ()
+{
+ return m_writeOutMethods;
+}
+
+void CodeClassField::setWriteOutMethods ( bool val )
+{
+ m_writeOutMethods = val;
+ updateContent();
+}
+
+/**
+ * return the declaration statement for this class field object.
+ * will be empty until this (abstract) class is inherited in elsewhere.
+ */
+CodeClassFieldDeclarationBlock * CodeClassField::getDeclarationCodeBlock( )
+{
+ return m_declCodeBlock;
+}
+
+// Other methods
+//
+
+/**
+ * load params from the appropriate XMI element node.
+ */
+void CodeClassField::loadFromXMI ( QDomElement & root ) {
+ setAttributesFromNode(root);
+}
+
+/** set attributes of the node that represents this class
+ * in the XMI document.
+ */
+void CodeClassField::setAttributesOnNode ( QDomDocument & doc, QDomElement & cfElem)
+{
+
+ // super class
+ CodeParameter::setAttributesOnNode(doc,cfElem);
+
+ // now set local attributes/fields
+ cfElem.setAttribute("field_type",m_classFieldType);
+ cfElem.setAttribute("listClassName",m_listClassName);
+ cfElem.setAttribute("writeOutMethods",getWriteOutMethods()?"true":"false");
+
+ // record tag on declaration codeblock
+ // which we will store in its own separate child node block
+ m_declCodeBlock->saveToXMI(doc, cfElem);
+
+ // now record the tags on our accessormethods
+ CodeAccessorMethod *method;
+ for (CodeAccessorMethodListIt it(m_methodVector); (method = it.current()) != NULL; ++it)
+ {
+ method->saveToXMI(doc,cfElem);
+ }
+
+}
+
+/** set the class attributes of this object from
+ * the passed element node.
+ */
+void CodeClassField::setAttributesFromNode ( QDomElement & root) {
+
+ // always disconnect
+ getParentObject()->disconnect(this);
+
+ // superclass call.. may reset the parent object
+ CodeParameter::setAttributesFromNode(root);
+
+ // make AFTER super-class call. This will reconnect to the parent
+ // and re-check we have all needed child accessor methods and decl blocks
+ initFields( );
+
+ setWriteOutMethods(root.attribute("writeOutMethods","true") == "true" ? true : false);
+ m_listClassName = root.attribute("listClassName","");
+ m_classFieldType = (ClassFieldType) root.attribute("field_type","0").toInt();
+
+ // load accessor methods now
+ // by looking for our particular child element
+ QDomNode node = root.firstChild();
+ QDomElement element = node.toElement();
+ while( !element.isNull() ) {
+ QString tag = element.tagName();
+ if( tag == "ccfdeclarationcodeblock" ) {
+ m_declCodeBlock->loadFromXMI(element);
+ } else
+ if( tag == "codeaccessormethod" ) {
+ int type = element.attribute("accessType","0").toInt();
+ int role_id = element.attribute("role_id","-1").toInt();
+ CodeAccessorMethod * method = findMethodByType((CodeAccessorMethod::AccessorType) type, role_id);
+ if(method)
+ method->loadFromXMI(element);
+ else
+ kError()<<"Cant load code accessor method for type:"<<type<<" which doesn't exist in this codeclassfield. Is XMI out-dated or corrupt?"<<endl;
+
+ } else
+ if( tag == "header" ) {
+ // this is treated in parent.. skip over here
+ } else
+ kWarning()<<"ERROR: bad savefile? code classfield loadFromXMI got child element with unknown tag:"<<tag<<" ignoring node."<<endl;
+
+ node = element.nextSibling();
+ element = node.toElement();
+ }
+
+}
+
+/**
+ * Save the XMI representation of this object
+ */
+void CodeClassField::saveToXMI ( QDomDocument & doc, QDomElement & root ) {
+ QDomElement docElement = doc.createElement( "codeclassfield" );
+
+ setAttributesOnNode(doc, docElement);
+
+ root.appendChild( docElement );
+}
+
+int CodeClassField::minimumListOccurances( ) {
+ if (!parentIsAttribute())
+ {
+ UMLRole * role = dynamic_cast<UMLRole*>(getParentObject());
+ QString multi = role->getMultiplicity();
+ // ush. IF we had a multiplicty object, this would be much easier.
+ if(!multi.isEmpty())
+ {
+ QString lowerBoundString = multi.remove(QRegExp("\\.\\.\\d+$"));
+ if(!lowerBoundString.isEmpty() &&lowerBoundString.contains(QRegExp("^\\d+$")))
+ return lowerBoundString.toInt();
+ }
+
+ }
+ return 0;
+}
+
+int CodeClassField::maximumListOccurances( ) {
+ if (!parentIsAttribute())
+ {
+ UMLRole * role = dynamic_cast<UMLRole*>(getParentObject());
+ QString multi = role->getMultiplicity();
+ // ush. IF we had a multiplicty object, this would be much easier.
+ if(!multi.isEmpty())
+ {
+ QString upperBoundString = multi.section(QRegExp("(\\.\\.)"),1);
+ if(!upperBoundString.isEmpty() && upperBoundString.contains(QRegExp("^\\d+$")))
+ return upperBoundString.toInt();
+ else
+ return -1; // unbounded
+ } else
+ return -1; // unbounded
+
+ }
+ return 1;
+}
+
+QString CodeClassField::cleanName ( const QString &name ) {
+ return getParentDocument()->cleanName(name);
+}
+
+QString CodeClassField::fixInitialStringDeclValue(const QString& val, const QString &type)
+{
+ QString value = val;
+ // check for strings only<F2>String value = val;
+ if (!value.isEmpty() && type == "String") {
+ if (!value.startsWith("\""))
+ value.prepend("\"");
+ if (!value.endsWith("\""))
+ value.append("\"");
+ }
+ return value;
+}
+
+void CodeClassField::synchronize ()
+{
+ updateContent();
+ CodeAccessorMethod *method;
+ for (CodeAccessorMethodListIt it(m_methodVector); (method = it.current()) != NULL; ++it)
+ method->syncToParent();
+
+ if(m_declCodeBlock)
+ m_declCodeBlock->syncToParent();
+}
+
+CodeAccessorMethod * CodeClassField::findMethodByType ( CodeAccessorMethod::AccessorType type, int role_id)
+{
+ //if we already know to which file this class was written/should be written, just return it.
+ /*
+ // argh. this wont work because "accessorType' doesn't inherit from QObject.
+ if(m_methodMap->contains(type))
+ return ((*m_methodMap)[type]);
+ CodeAccessorMethod * obj = NULL;
+ */
+ if(role_id > 1 || role_id < 0)
+ {
+ for (CodeAccessorMethod * m = m_methodVector.first(); m ; m= m_methodVector.next())
+ if( m->getType() == type)
+ return m;
+ } else {
+ // ugh. forced into this underperforming algorithm because of bad association
+ // design.
+ for (CodeAccessorMethod * m = m_methodVector.first(); m ; m= m_methodVector.next())
+ {
+ UMLRole * role = dynamic_cast<UMLRole*>(m->getParentObject());
+ if(!role)
+ kError()<<" FindMethodByType() cant create role for method type:"<<m->getType()<<endl;
+ if( role && m->getType() == type && role->getRole() == role_id)
+ return m;
+ }
+
+ }
+
+ return (CodeAccessorMethod *) NULL;
+}
+
+void CodeClassField::initAccessorMethods()
+{
+
+ // everything gets potential get/set method
+ //if(!m_methodMap->contains(CodeAccessorMethod::GET))
+ if(!findMethodByType(CodeAccessorMethod::GET))
+ {
+ CodeAccessorMethod * method = CodeGenFactory::newCodeAccessorMethod (getParentDocument(), this, CodeAccessorMethod::GET);
+ if(method)
+ {
+ method->setType(CodeAccessorMethod::GET);
+ addMethod(method);
+ }
+ }
+
+ if(!findMethodByType(CodeAccessorMethod::SET))
+ {
+ CodeAccessorMethod * method = CodeGenFactory::newCodeAccessorMethod (getParentDocument(), this, CodeAccessorMethod::SET);
+ if(method) {
+ method->setType(CodeAccessorMethod::SET);
+ addMethod(method);
+ }
+ }
+
+ // add in the add,remove and list methods for things which are role based.
+ // (and only used if the role specifies a 'list' type object
+ if (!parentIsAttribute()) {
+
+ if(!findMethodByType(CodeAccessorMethod::ADD))
+ {
+ CodeAccessorMethod * method = CodeGenFactory::newCodeAccessorMethod (getParentDocument(), this, CodeAccessorMethod::ADD);
+ if(method) {
+ method->setType(CodeAccessorMethod::ADD);
+ addMethod(method);
+ }
+ }
+
+ if(!findMethodByType(CodeAccessorMethod::REMOVE))
+ {
+ CodeAccessorMethod * method = CodeGenFactory::newCodeAccessorMethod (getParentDocument(), this, CodeAccessorMethod::REMOVE);
+ if(method) {
+ method->setType(CodeAccessorMethod::REMOVE);
+ addMethod(method);
+ }
+ }
+
+ if(!findMethodByType(CodeAccessorMethod::LIST))
+ {
+ CodeAccessorMethod * method = CodeGenFactory::newCodeAccessorMethod (getParentDocument(), this, CodeAccessorMethod::LIST);
+ if(method) {
+ method->setType(CodeAccessorMethod::LIST);
+ addMethod(method);
+ }
+ }
+
+ }
+
+
+}
+
+void CodeClassField::updateContent()
+{
+
+ // Set properties for writing out the various methods derived from UMLRoles.
+ // I suppose this could be supported under individual accessor method synctoparent
+ // calls, but its going to happen again and again for many languages. Why not a catch
+ // all here? -b.t.
+ if (parentIsAttribute())
+ {
+ for ( CodeAccessorMethod *method = m_methodVector.first(); method;
+ method = m_methodVector.next() )
+ method->setWriteOutText( m_writeOutMethods );
+ return;
+ }
+ UMLRole * role = dynamic_cast<UMLRole*>(getParentObject());
+ Uml::Changeability_Type changeType = role->getChangeability();
+ bool isSingleValue = fieldIsSingleValue();
+ bool isEmptyRole = role->getName().isEmpty() ? true : false;
+
+ for (CodeAccessorMethod * method = m_methodVector.first(); method; method=m_methodVector.next())
+ {
+
+ CodeAccessorMethod::AccessorType type = method->getType();
+
+ // for role-based accessors, we DON'T write ourselves out when
+ // the name of the role is not defined OR when the global flag
+ // to not show ANY methods is set.
+ if(!m_writeOutMethods || isEmptyRole)
+ {
+ method->setWriteOutText(false);
+ continue;
+ }
+
+ // not to change if no tag (don't know what it is, OR its not an AutoGenerated method
+ if(method->getContentType() != CodeBlock::AutoGenerated)
+ continue;
+
+ // first off, some accessor methods wont appear if its a singleValue
+ // role and vice-versa
+ if(isSingleValue)
+ {
+ switch(type) {
+ case CodeAccessorMethod::SET:
+ // SET method true ONLY IF changeability is NOT Frozen
+ if (changeType != Uml::chg_Frozen)
+ method->setWriteOutText(true);
+ else
+ method->setWriteOutText(false);
+ break;
+ case CodeAccessorMethod::GET:
+ method->setWriteOutText(true);
+ break;
+ case CodeAccessorMethod::ADD:
+ case CodeAccessorMethod::REMOVE:
+ case CodeAccessorMethod::LIST:
+ default: // list/add/remove always false
+ method->setWriteOutText(false);
+ break;
+ }
+ }
+ else
+ {
+ switch(type) {
+ // get/set always false
+ case CodeAccessorMethod::GET:
+ case CodeAccessorMethod::SET:
+ method->setWriteOutText(false);
+ break;
+ case CodeAccessorMethod::ADD:
+ // ADD method true ONLY IF changeability is NOT Frozen
+ if (changeType != Uml::chg_Frozen)
+ method->setWriteOutText(true);
+ else
+ method->setWriteOutText(false);
+ break;
+ case CodeAccessorMethod::REMOVE:
+ // Remove methods ONLY IF changeability is Changeable
+ if (changeType == Uml::chg_Changeable)
+ method->setWriteOutText(true);
+ else
+ method->setWriteOutText(false);
+ break;
+ case CodeAccessorMethod::LIST:
+ default:
+ method->setWriteOutText(true);
+ break;
+ }
+ }
+ }
+}
+
+// determine whether the parent object in this classfield indicates that it is
+// a single variable or a List (Vector). One day this will be done correctly with special
+// multiplicity object that we don't have to figure out what it means via regex.
+bool CodeClassField::fieldIsSingleValue ( )
+{
+ // For the time being, all attributes ARE single values (yes,
+ // I know this isnt always true, but we have to start somewhere.)
+ if(parentIsAttribute())
+ return true;
+
+ UMLRole * role = dynamic_cast<UMLRole*>(getParentObject());
+ if(!role)
+ return true; // its really an attribute
+
+ QString multi = role->getMultiplicity();
+
+ if(multi.isEmpty() || multi.contains(QRegExp("^(0|1)$"))
+ || multi.contains(QRegExp("^0\\.\\.1$")))
+ return true;
+
+ return false;
+}
+
+void CodeClassField::initFields(bool inConstructor) {
+
+ m_writeOutMethods = false;
+ m_listClassName = QString ("");
+ m_declCodeBlock = NULL;
+
+ m_methodVector.setAutoDelete(false);
+ // m_methodMap = new QMap<CodeAccessorMethod::AccessorType, CodeAccessorMethod *>;
+
+ if (!inConstructor)
+ finishInitialization();
+}
+
+void CodeClassField::finishInitialization() {
+ m_declCodeBlock = CodeGenFactory::newDeclarationCodeBlock(getParentDocument(), this);
+ initAccessorMethods();
+ updateContent();
+
+ connect(getParentObject(),SIGNAL(modified()),this,SIGNAL(modified())); // child objects will trigger off this signal
+
+}
+
+#include "codeclassfield.moc"
diff --git a/umbrello/umbrello/codeclassfield.h b/umbrello/umbrello/codeclassfield.h
new file mode 100644
index 00000000..bd651b6e
--- /dev/null
+++ b/umbrello/umbrello/codeclassfield.h
@@ -0,0 +1,237 @@
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * copyright (C) 2004-2006 *
+ * Umbrello UML Modeller Authors <uml-devel@uml.sf.net> *
+ ***************************************************************************/
+
+/* This code generated by:
+ * Author : thomas
+ * Date : Fri Jun 20 2003
+ */
+
+
+
+#ifndef CODECLASSFIELD_H
+#define CODECLASSFIELD_H
+
+#include "codeaccessormethodlist.h"
+#include "codeclassfielddeclarationblock.h"
+#include "codeparameter.h"
+#include "codeaccessormethod.h"
+
+// #include "codeclassfielddialog.h"
+
+
+class ClassifierCodeDocument;
+class UMLAttribute;
+class UMLObject;
+class UMLRole;
+
+/**
+ * class CodeClassField
+ * a special type of parameter.. occurs on class declarations.
+ */
+
+class CodeClassField : public CodeParameter
+{
+ Q_OBJECT
+public:
+
+ enum ClassFieldType { Attribute, PlainAssociation, Self, Aggregation, Composition, Unknown_Assoc };
+
+ // Constructors/Destructors
+ //
+
+ /**
+ * Constructors
+ */
+ CodeClassField ( ClassifierCodeDocument * parentDoc , UMLAttribute * attrib );
+ CodeClassField ( ClassifierCodeDocument * parentDoc , UMLRole * role);
+
+ /**
+ * Finish off initializations of the object.
+ * This is necessary as a separate method because we cannot call
+ * virtual methods that are reimplemented in a language specific class
+ * during our own construction (the own object is not finished being
+ * constructed and therefore the C++ dispatch mechanism does not yet
+ * work as expected.)
+ */
+ void finishInitialization();
+
+ // CodeClassField ( ClassifierCodeDocument * doc , UMLRole role);
+
+ /**
+ * Empty Destructor
+ */
+ virtual ~CodeClassField ( );
+
+ // Public attributes
+ //
+
+ // Public attribute accessor methods
+ //
+
+ /**
+ * Get the value of m_dialog
+ * @return the value of m_dialog
+ */
+ // CodeClassFieldDialog getDialog ( );
+
+ // Determine if this cf is attribute or some type of association
+ QString getTypeName ( );
+
+ /**
+ * @return CodeClassFieldDeclarationBlock representing the declaration statement of this class field
+ */
+ CodeClassFieldDeclarationBlock * getDeclarationCodeBlock( );
+
+ /**
+ * Get the list of Method objects held by m_methodVector
+ * @return CodeAccessorMethodList list of Method objects held by
+ * m_methodVector
+ */
+ CodeAccessorMethodList getMethodList();
+
+ /** Utility method to allow finding particular accessor method of this
+ * code class field by its type identifier.
+ */
+ CodeAccessorMethod * findMethodByType(CodeAccessorMethod::AccessorType type, int role_id = -1);
+
+ /** Determine whether the parent object in this classfield indicates that it is
+ * a single variable or a List (Vector). One day this will be done correctly with special
+ * multiplicity object.
+ */
+ bool fieldIsSingleValue ( );
+
+ /**
+ * Get the type of classfield this is.
+ */
+ ClassFieldType getClassFieldType();
+
+ // quick utility call to figure out if parent is an attribute or not
+ bool parentIsAttribute ( );
+
+ // get the type of object that will be added/removed from lists
+ // of objects (as per specification of associations)
+ QString getListObjectType();
+
+ /** determine if we will *allow* methods to be viewable.
+ * this flag is often used to toggle autogeneration of accessor
+ * methods in the code class field.
+ */
+ bool getWriteOutMethods ();
+
+ /** determine if we will *allow* methods to be viewable.
+ * this flag is often used to toggle autogeneration of accessor
+ * methods in the code class field.
+ */
+ void setWriteOutMethods( bool val);
+
+ /** Find the minimum number of things that can occur in an association
+ * If mistakenly called on attribute CF's the default value of is "0"
+ * is returned. Similarly, if the association (role) CF doesn't have a multiplicty
+ * 0 is returned.
+ */
+ int minimumListOccurances( );
+
+ /** Find the maximum number of things that can occur in an association
+ * If mistakenly called on attribute CF's the default value of is "1"
+ * is returned. If the association (role) CF doesn't have a multiplicty
+ * or has a "*" specified then '-1' (unbounded) is returned.
+ */
+ int maximumListOccurances( );
+
+ /**
+ * Save the XMI representation of this object
+ */
+ virtual void saveToXMI ( QDomDocument & doc, QDomElement & root );
+
+ /**
+ * load params from the appropriate XMI element node.
+ */
+ virtual void loadFromXMI ( QDomElement & root );
+
+ /** Force the syncronization of the content (methods and declarations)
+ * of this class field.
+ */
+ virtual void synchronize ();
+
+protected:
+
+ /** Set the parent UMLobject appropriately.
+ */
+ void setParentUMLObject (UMLObject * obj);
+
+ // CodeClassFieldDialog * m_dialog;
+
+ /** a little utility method to make life easier for code document programmers
+ */
+ QString cleanName(const QString &name);
+
+ /** another utility method to make life easier for code document programmers
+ * this one fixes the initial declared value of string attributes so that if
+ * its empty or lacking quotations, it comes out as ""
+ */
+ QString fixInitialStringDeclValue(const QString& val, const QString &type);
+
+ // set the list class name
+ void setListClassName ( const QString &className );
+
+ /**
+ * Add a Method object to the m_methodVector List
+ */
+ bool addMethod ( CodeAccessorMethod * add );
+
+ QString getUMLObjectName(UMLObject *obj);
+
+ /**
+ * Remove a Method object from m_methodVector List
+ */
+ bool removeMethod ( CodeAccessorMethod * remove);
+
+ // Updates the status of the accessor methods
+ // as to whether or not they should be written out.
+ void updateContent();
+
+private:
+
+ QString m_listClassName;
+ ClassFieldType m_classFieldType;
+ CodeClassFieldDeclarationBlock * m_declCodeBlock;
+ CodeAccessorMethodList m_methodVector; // the list of methods related to this codeclassfield
+ bool m_parentIsAttribute;
+
+ /** This flag tells if we want the methods to have the possibility
+ * of being written out. IF the value is false, then all methods
+ * are never written out.
+ */
+ bool m_writeOutMethods;
+
+ /** set attributes of the node that represents this class
+ * in the XMI document.
+ */
+ virtual void setAttributesOnNode ( QDomDocument & doc, QDomElement & blockElement);
+
+ /** set the class attributes of this object from
+ * the passed element node.
+ */
+ virtual void setAttributesFromNode ( QDomElement & element);
+
+ /** init class fields */
+ void initFields(bool inConstructor = false);
+
+ // initialize the accessor methods for this field
+ void initAccessorMethods();
+
+signals:
+
+ void modified ();
+
+};
+
+#endif // CODECLASSFIELD_H
diff --git a/umbrello/umbrello/codeclassfielddeclarationblock.cpp b/umbrello/umbrello/codeclassfielddeclarationblock.cpp
new file mode 100644
index 00000000..d02a83fa
--- /dev/null
+++ b/umbrello/umbrello/codeclassfielddeclarationblock.cpp
@@ -0,0 +1,174 @@
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the 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 code generated by:
+ * Author : thomas
+ * Date : Fri Jul 25 2003
+ */
+
+/** basicially a class to allow for syncronization of the contents based on the
+ * values of the parentClassField's parentObject
+ */
+#include "codeclassfielddeclarationblock.h"
+
+#include "codeclassfield.h"
+#include "umlrole.h"
+
+// Constructors/Destructors
+//
+
+CodeClassFieldDeclarationBlock::CodeClassFieldDeclarationBlock ( CodeClassField * parentCF )
+ : CodeBlockWithComments ( (CodeDocument*) parentCF->getParentDocument() ),
+ OwnedCodeBlock ((UMLObject*) parentCF->getParentObject())
+{
+ init(parentCF);
+}
+
+CodeClassFieldDeclarationBlock::~CodeClassFieldDeclarationBlock ( ) {
+ // Q: is this needed??
+ // m_parentclassfield->getParentObject()->disconnect(this);
+}
+
+//
+// Methods
+//
+
+// Accessor methods
+//
+
+/**
+ * Get the value of m_parentclassfield
+ * @return the value of m_parentclassfield
+ */
+CodeClassField * CodeClassFieldDeclarationBlock::getParentClassField ( ) {
+ return m_parentclassfield;
+}
+
+/** Get the parent object of the parentCodeClassfield
+ */
+UMLObject * CodeClassFieldDeclarationBlock::getParentObject ( ) {
+ return m_parentclassfield->getParentObject();
+}
+
+CodeDocument * CodeClassFieldDeclarationBlock::getParentDocument ( ) {
+ return TextBlock::getParentDocument();
+}
+
+// Other methods
+//
+
+// this type of textblock is special
+// we DONT release it when resetTextBlocks is
+// called because we re-use it over and over
+// until the codeclassfield is released.
+void CodeClassFieldDeclarationBlock::release () {
+ // do nothing
+}
+
+void CodeClassFieldDeclarationBlock::forceRelease () {
+ if(m_parentclassfield)
+ {
+ // m_parentclassfield->getParentObject()->disconnect(this);
+ m_parentclassfield->disconnect(this);
+ }
+ m_parentclassfield = 0;
+ OwnedCodeBlock::release();
+ TextBlock::release();
+}
+
+/**
+ * Save the XMI representation of this object
+ */
+void CodeClassFieldDeclarationBlock::saveToXMI ( QDomDocument & doc, QDomElement & elem)
+{
+ QDomElement docElement = doc.createElement( "ccfdeclarationcodeblock" );
+
+ setAttributesOnNode(doc, docElement);
+
+ elem.appendChild( docElement );
+}
+
+void CodeClassFieldDeclarationBlock::loadFromXMI ( QDomElement & root )
+{
+ setAttributesFromNode(root);
+}
+
+void CodeClassFieldDeclarationBlock::setAttributesOnNode (QDomDocument & doc, QDomElement & elem ) {
+
+ // set super-class attributes
+ CodeBlockWithComments::setAttributesOnNode(doc, elem);
+ OwnedCodeBlock::setAttributesOnNode(doc, elem);
+
+}
+
+/**
+ * load params from the appropriate XMI element node.
+ */
+void CodeClassFieldDeclarationBlock::setAttributesFromNode( QDomElement & root ) {
+
+ // set attributes from the XMI
+ CodeBlockWithComments::setAttributesFromNode(root); // superclass load
+ OwnedCodeBlock::setAttributesFromNode(root); // superclass load
+
+ syncToParent();
+}
+
+/** set the class attributes from a passed object
+ */
+void CodeClassFieldDeclarationBlock::setAttributesFromObject (TextBlock * obj) {
+
+ CodeBlockWithComments::setAttributesFromObject(obj);
+
+ CodeClassFieldDeclarationBlock * ccb = dynamic_cast<CodeClassFieldDeclarationBlock*>(obj);
+ if(ccb)
+ {
+ m_parentclassfield->disconnect(this);
+ init(ccb->getParentClassField());
+
+ syncToParent();
+ }
+
+}
+
+void CodeClassFieldDeclarationBlock::syncToParent () {
+
+ // for role-based accessors, we DONT write ourselves out when
+ // the name of the role is not defined.
+ if(!(getParentClassField()->parentIsAttribute()))
+ {
+ UMLRole * parent = dynamic_cast<UMLRole*>(getParentObject());
+ if (parent == NULL)
+ return;
+ if(parent->getName().isEmpty())
+ {
+ getComment()->setWriteOutText(false);
+ setWriteOutText(false);
+ } else {
+ getComment()->setWriteOutText(true);
+ setWriteOutText(true);
+ }
+ }
+
+ // only update IF we are NOT AutoGenerated
+ if(getContentType() != AutoGenerated)
+ return;
+
+ updateContent();
+
+}
+
+void CodeClassFieldDeclarationBlock::init (CodeClassField * parentCF)
+{
+ m_parentclassfield = parentCF;
+ m_canDelete = false;
+ connect(m_parentclassfield,SIGNAL(modified()),this,SLOT(syncToParent()));
+}
+
+#include "codeclassfielddeclarationblock.moc"
diff --git a/umbrello/umbrello/codeclassfielddeclarationblock.h b/umbrello/umbrello/codeclassfielddeclarationblock.h
new file mode 100644
index 00000000..f52868e2
--- /dev/null
+++ b/umbrello/umbrello/codeclassfielddeclarationblock.h
@@ -0,0 +1,112 @@
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * copyright (C) 2004-2006 *
+ * Umbrello UML Modeller Authors <uml-devel@uml.sf.net> *
+ ***************************************************************************/
+
+/* This code generated by:
+ * Author : thomas
+ * Date : Fri Jul 25 2003
+ */
+
+#ifndef CODECLASSFIELDDECLARATIONBLOCK_H
+#define CODECLASSFIELDDECLARATIONBLOCK_H
+
+
+class UMLObject;
+class CodeClassField;
+
+#include "codeblockwithcomments.h"
+#include "ownedcodeblock.h"
+
+/**
+ * class CodeClassFieldDeclarationBlock
+ * Used to declare classifier fields (e.g. either class attributes or classifier
+ * associations) in the code document for any given code classfield. This is a
+ * special CodeBlockWithComments which is "sync'd" to the parent CodeClassField.
+ */
+
+class CodeClassFieldDeclarationBlock : public CodeBlockWithComments, public OwnedCodeBlock
+{
+ friend class CodeClassField;
+ Q_OBJECT
+public:
+
+ // Constructors/Destructors
+ //
+
+ /**
+ * Constructor
+ */
+ CodeClassFieldDeclarationBlock (CodeClassField * parent);
+
+ /**
+ * Empty Destructor
+ */
+ virtual ~CodeClassFieldDeclarationBlock ( );
+
+ /**
+ * Get the value of m_parentclassfield
+ * @return the value of m_parentclassfield
+ */
+ CodeClassField * getParentClassField ( );
+
+ /** A Utility method to get the parent object of the parentCodeClassfield
+ */
+ UMLObject * getParentObject ( );
+
+ // get the parent document
+ CodeDocument * getParentDocument ( );
+
+ /**
+ * Save the XMI representation of this object
+ */
+ virtual void saveToXMI ( QDomDocument & doc, QDomElement & root );
+
+ /**
+ * load params from the appropriate XMI element node.
+ */
+ virtual void loadFromXMI ( QDomElement & root );
+
+ /** set the class attributes from a passed object
+ */
+ virtual void setAttributesFromObject (TextBlock * obj);
+
+protected:
+
+ virtual void release ();
+
+ /** set attributes of the node that represents this class
+ * in the XMI document.
+ */
+ virtual void setAttributesOnNode ( QDomDocument & doc, QDomElement & blockElement);
+
+ /** set the class attributes of this object from
+ * the passed element node.
+ */
+ virtual void setAttributesFromNode ( QDomElement & element);
+
+ /** this is called by syncToParent
+ */
+ virtual void updateContent() = 0;
+
+ // so parent can actually release this block
+ void forceRelease ();
+
+private:
+
+ CodeClassField * m_parentclassfield;
+ void init(CodeClassField * parent);
+
+public slots:
+
+ virtual void syncToParent();
+
+};
+
+#endif // CODECLASSFIELDDECLARATIONBLOCK_H
diff --git a/umbrello/umbrello/codeclassfieldlist.h b/umbrello/umbrello/codeclassfieldlist.h
new file mode 100644
index 00000000..c9ab4892
--- /dev/null
+++ b/umbrello/umbrello/codeclassfieldlist.h
@@ -0,0 +1,23 @@
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * copyright (C) 2004-2007 *
+ * Umbrello UML Modeller Authors <uml-devel@uml.sf.net> *
+ ***************************************************************************/
+
+#ifndef _CODECLASSFIELDLIST_H
+#define _CODECLASSFIELDLIST_H
+
+#include <qptrlist.h>
+
+// forward declarations
+class CodeClassField;
+
+typedef QPtrList<CodeClassField> CodeClassFieldList;
+typedef QPtrListIterator<CodeClassField> CodeClassFieldListIt;
+
+#endif
diff --git a/umbrello/umbrello/codecomment.cpp b/umbrello/umbrello/codecomment.cpp
new file mode 100644
index 00000000..b59e52b4
--- /dev/null
+++ b/umbrello/umbrello/codecomment.cpp
@@ -0,0 +1,62 @@
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the 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 code generated by:
+ * Author : thomas
+ * Date : Wed Jun 18 2003
+ */
+
+#include "codecomment.h"
+#include "codedocument.h"
+#include <kdebug.h>
+
+// Constructors/Destructors
+//
+
+CodeComment::CodeComment (CodeDocument * doc, const QString & comment )
+ : TextBlock ( doc, comment )
+{
+
+}
+
+CodeComment::~CodeComment ( ) { }
+
+//
+// Methods
+//
+
+
+// Accessor methods
+//
+
+
+// Other methods
+//
+
+/**
+ * Save the XMI representation of this object
+ */
+void CodeComment::saveToXMI ( QDomDocument & doc, QDomElement & root ) {
+ kDebug() << "CodeComment::saveToXMI is called!" << endl;
+ QDomElement blockElement = doc.createElement( "codecomment" );
+ setAttributesOnNode(doc, blockElement); // as we added no additional fields to this class we may
+ // just use parent TextBlock method
+ root.appendChild( blockElement );
+}
+
+/**
+ * load params from the appropriate XMI element node.
+ */
+void CodeComment::loadFromXMI ( QDomElement & root ) {
+ setAttributesFromNode(root);
+}
+
+
+#include "codecomment.moc"
diff --git a/umbrello/umbrello/codecomment.h b/umbrello/umbrello/codecomment.h
new file mode 100644
index 00000000..18c2cba0
--- /dev/null
+++ b/umbrello/umbrello/codecomment.h
@@ -0,0 +1,68 @@
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the 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 code generated by:
+ * Author : thomas
+ * Date : Wed Jun 18 2003
+ */
+
+
+
+#ifndef CODECOMMENT_H
+#define CODECOMMENT_H
+
+#include <qstring.h>
+
+#include "textblock.h"
+
+/**
+ * class CodeComment
+ * Text which will be comments. These should be bracketed by what ever code type
+ * comment the language requires.
+ */
+
+class CodeComment : public TextBlock
+{
+ Q_OBJECT
+public:
+
+ // Constructors/Destructors
+ //
+
+
+ /**
+ * Empty Constructor
+ */
+ explicit CodeComment ( CodeDocument * doc, const QString & comment = "");
+
+ /**
+ * Empty Destructor
+ */
+ virtual ~CodeComment ( );
+
+ /**
+ * Save the XMI representation of this object
+ */
+ virtual void saveToXMI ( QDomDocument & doc, QDomElement & root );
+
+ /**
+ * load params from the appropriate XMI element node.
+ */
+ virtual void loadFromXMI ( QDomElement & root );
+
+protected:
+
+private:
+
+
+
+};
+
+#endif // CODECOMMENT_H
diff --git a/umbrello/umbrello/codedocument.cpp b/umbrello/umbrello/codedocument.cpp
new file mode 100644
index 00000000..e0bf0e73
--- /dev/null
+++ b/umbrello/umbrello/codedocument.cpp
@@ -0,0 +1,502 @@
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * copyright (C) 2004-2007 *
+ * Umbrello UML Modeller Authors <uml-devel@uml.sf.net> *
+ ***************************************************************************/
+
+/* This code generated by:
+ * Author : thomas
+ * Date : Wed Jun 18 2003
+ */
+
+// own header
+#include "codedocument.h"
+
+// qt/kde includes
+#include <qregexp.h>
+#include <qdatetime.h>
+#include <kdebug.h>
+
+// local includes
+#include "codegenerator.h"
+#include "package.h"
+#include "umldoc.h"
+#include "uml.h"
+
+// Constructors/Destructors
+//
+
+CodeDocument::CodeDocument () : CodeGenObjectWithTextBlocks(this)
+{
+ initDoc();
+}
+
+
+CodeDocument::~CodeDocument ( ) {
+ // delete all the text blocks we have
+ TextBlock *tb;
+ for (TextBlockListIt it(m_textblockVector); (tb = it.current()) != NULL; ++it)
+ delete tb;
+ m_textblockVector.clear();
+ delete m_header;
+}
+
+//
+// Methods
+//
+
+
+// Accessor methods
+//
+
+
+// Public attribute accessor methods
+//
+
+
+/**
+ * Set the value of m_filename
+ * @param new_var the new value of m_filename
+ */
+void CodeDocument::setFileName ( const QString &new_var ) {
+ m_filename = new_var;
+}
+
+/**
+ * Get the value of m_filename
+ * @return the value of m_filename
+ */
+QString CodeDocument::getFileName ( ) const {
+ return m_filename;
+}
+
+/**
+ * Set the value of m_filename
+ * @param new_var the new value of m_filename
+ */
+void CodeDocument::setFileExtension ( const QString &new_var ) {
+ m_fileExtension = new_var;
+ updateHeader(); // because we are using new heading file
+}
+
+/**
+ * Get the value of m_filename
+ * @return the value of m_filename
+ */
+QString CodeDocument::getFileExtension( ) const {
+ return m_fileExtension;
+}
+
+/**
+ * Set the value of the package.
+ * @param new_var the new value of m_package
+ */
+void CodeDocument::setPackage ( UMLPackage *new_var ) {
+ m_package = new_var;
+}
+
+/**
+ * Get the value of path for this code document.
+ * @return the value of the path
+ */
+QString CodeDocument::getPath ( ) {
+
+ QString path = getPackage();
+
+ // Replace all white spaces with blanks
+ path = path.simplifyWhiteSpace();
+
+ // Replace all blanks with underscore
+ path.replace(QRegExp(" "), "_");
+
+ // this allows multiple directory paths (ala Java, some other languages)
+ // in from the package specification
+ path.replace(QRegExp("\\."),"/"); // Simple hack!.. but this is more or less language
+ // dependant and should probably be commented out.
+ // Still, as a general default it may be useful -b.t.
+ return path;
+}
+
+/**
+ * Get the value of package name.
+ * @return the value of m_package->getName()
+ */
+QString CodeDocument::getPackage ( ) const {
+ if (m_package)
+ return m_package->getName();
+ return QString();
+}
+
+/**
+ * Set the value of m_ID
+ * @param new_var the new value of m_ID
+ */
+void CodeDocument::setID ( const QString &new_var ) {
+ m_ID = new_var;
+}
+
+/**
+ * Get the value of m_ID
+ * @return the value of m_ID
+ */
+QString CodeDocument::getID ( ) const {
+ return m_ID;
+}
+
+/**
+ * Set the value of m_writeOutCode
+ * Whether or not to write out this code document and any codeblocks, etc that it
+ * owns.
+ * @param new_var the new value of m_writeOutCode
+ */
+void CodeDocument::setWriteOutCode ( bool new_var ) {
+ m_writeOutCode = new_var;
+}
+
+/**
+ * Get the value of m_writeOutCode
+ * Whether or not to write out this code document and any codeblocks, etc that it
+ * owns.
+ * @return the value of m_writeOutCode
+ */
+bool CodeDocument::getWriteOutCode ( ) {
+ return m_writeOutCode;
+}
+
+/**
+ * Set the Header comment
+ */
+void CodeDocument::setHeader ( CodeComment * header ) {
+ m_header = header;
+}
+
+/**
+ * Get the Header comment
+ */
+CodeComment * CodeDocument::getHeader ( ) {
+ return m_header;
+}
+
+//
+// Other methods
+//
+
+QString CodeDocument::getUniqueTag ( const QString& prefix )
+{
+ QString tag = prefix ;
+ if(tag.isEmpty())
+ tag += "tblock";
+
+ tag = tag + "_0";
+ int number = lastTagIndex;
+ for ( ; findTextBlockByTag(tag, true); number++) {
+ tag = prefix + '_' + QString::number(number);
+ }
+ lastTagIndex = number;
+ return tag;
+}
+
+/**
+ * Insert a new text block before/after the existing text block. Returns
+ * false if it cannot insert the textblock.
+ */
+bool CodeDocument::insertTextBlock(TextBlock * newBlock, TextBlock * existingBlock, bool after)
+{
+
+ if(!newBlock || !existingBlock)
+ return false;
+
+ QString tag = existingBlock->getTag();
+ if(!findTextBlockByTag(tag, true))
+ return false;
+
+ int index = m_textblockVector.findRef(existingBlock);
+ if(index < 0)
+ {
+ // may be hiding in child hierarchical codeblock
+ for(TextBlock * tb = m_textblockVector.first(); tb ; tb = m_textblockVector.next())
+ {
+ HierarchicalCodeBlock * hb = dynamic_cast<HierarchicalCodeBlock*>(tb);
+ if(hb && hb->insertTextBlock(newBlock, existingBlock, after))
+ return true; // found, and inserted, otherwise keep going
+ }
+ // ugh. where is the child block?
+ kWarning()<<" Warning: couldnt insert text block (tag:"<<newBlock->getTag()<<"). Reference text block (tag:"<<existingBlock->getTag()<<") not found."<<endl;
+ return false;
+ }
+
+ // if we get here.. it was in this object so insert
+
+ // check for tag FIRST
+ QString new_tag = newBlock->getTag();
+
+ // assign a tag if one doesn't already exist
+ if(new_tag.isEmpty())
+ {
+ new_tag = getUniqueTag();
+ newBlock->setTag(new_tag);
+ }
+
+ if(m_textBlockTagMap.contains(new_tag))
+ return false; // return false, we already have some object with this tag in the list
+ else
+ m_textBlockTagMap.insert(new_tag, newBlock);
+
+ if(after)
+ index++;
+
+ m_textblockVector.insert(index,newBlock);
+
+ return true;
+}
+
+/**
+ * Get the value of m_dialog
+ * @return the value of m_dialog
+ */
+/*
+CodeDocumentDialog * CodeDocument::getDialog ( ) {
+ return m_dialog;
+}
+*/
+
+// Other methods
+//
+
+QString CodeDocument::cleanName ( const QString &name ) {
+ return CodeGenerator::cleanName(name);
+}
+
+// update the text and status of the head comment
+void CodeDocument::updateHeader () {
+
+ //try to find a heading file (license, coments, etc) then extract its text
+ QString headingText = UMLApp::app()->getCommonPolicy()->getHeadingFile(getFileExtension());
+
+ headingText.replace(QRegExp("%filename%"),getFileName()+getFileExtension());
+ headingText.replace(QRegExp("%filepath%"),getPath());
+ headingText.replace( QRegExp("%time%"), QTime::currentTime().toString());
+ headingText.replace( QRegExp("%date%"), QDate::currentDate().toString());
+
+ getHeader()->setText(headingText);
+
+ // update the write out status of the header
+ if(UMLApp::app()->getCommonPolicy()->getIncludeHeadings())
+ getHeader()->setWriteOutText(true);
+ else
+ getHeader()->setWriteOutText(false);
+
+}
+
+/**
+ * create the string representation of this object.
+ * @return QString
+ */
+QString CodeDocument::toString ( ) {
+
+ // IF the whole document is turned "Off" then don't bother
+ // checking individual code blocks, just send back empty string
+ if(!getWriteOutCode())
+ return QString("");
+
+ QString content = getHeader()->toString();
+
+ // update the time/date
+
+ // comments, import, package codeblocks go next
+ TextBlockList * items = getTextBlockList();
+ for (TextBlock *c = items->first(); c; c = items->next())
+ {
+ if(c->getWriteOutText()) {
+ QString str = c->toString();
+ if(!str.isEmpty())
+ content.append(str);
+ }
+ }
+ return content;
+}
+
+void CodeDocument::synchronize() {
+ updateContent();
+}
+
+// need to overload method to beable to clear the childTextBlockMap
+void CodeDocument::resetTextBlocks() {
+ CodeGenObjectWithTextBlocks::resetTextBlocks();
+ m_childTextBlockTagMap.clear();
+}
+
+/**
+ * load params from the appropriate XMI element node.
+ */
+void CodeDocument::loadFromXMI ( QDomElement & root ) {
+ setAttributesFromNode(root);
+}
+
+/** set attributes of the node that represents this class
+ * in the XMI document.
+ */
+void CodeDocument::setAttributesOnNode ( QDomDocument & doc, QDomElement & docElement)
+{
+
+ // superclass call
+ CodeGenObjectWithTextBlocks::setAttributesOnNode(doc,docElement);
+
+ // now set local attributes/fields
+ docElement.setAttribute("fileName",getFileName());
+ docElement.setAttribute("fileExt",getFileExtension());
+ Uml::IDType pkgId = Uml::id_None;
+ if (m_package)
+ pkgId = m_package->getID();
+ docElement.setAttribute("package", ID2STR(pkgId));
+ docElement.setAttribute("writeOutCode",getWriteOutCode()?"true":"false");
+ docElement.setAttribute("id",getID());
+
+ // set the a header
+ // which we will store in its own separate child node block
+ QDomElement commElement = doc.createElement( "header" );
+ getHeader()->saveToXMI(doc, commElement); // comment
+ docElement.appendChild( commElement);
+
+ // doc codePolicy?
+ // FIX: store ONLY if different from the parent generator
+ // policy.. something which is not possible right now. -b.t.
+
+}
+
+/** set the class attributes of this object from
+ * the passed element node.
+ */
+void CodeDocument::setAttributesFromNode ( QDomElement & root) {
+
+ // now set local attributes
+ setFileName(root.attribute("fileName",""));
+ setFileExtension(root.attribute("fileExt",""));
+ QString pkgStr = root.attribute("package","");
+ if (!pkgStr.isEmpty() && pkgStr != "-1") {
+ UMLDoc *umldoc = UMLApp::app()->getDocument();
+ if (pkgStr.contains( QRegExp("\\D") )) {
+ // suspecting pre-1.5.3 file format where the package name was
+ // saved instead of the package ID.
+ UMLObject *o = umldoc->findUMLObject(pkgStr);
+ m_package = dynamic_cast<UMLPackage*>(o);
+ }
+ if (m_package == NULL) {
+ UMLObject *o = umldoc->findObjectById(STR2ID(pkgStr));
+ m_package = dynamic_cast<UMLPackage*>(o);
+ }
+ }
+ setWriteOutCode(root.attribute("writeOutCode","true") == "true" ? true : false);
+ setID(root.attribute("id",""));
+
+ // load comment now
+ // by looking for our particular child element
+ QDomNode node = root.firstChild();
+ QDomElement element = node.toElement();
+ while( !element.isNull() ) {
+ QString tag = element.tagName();
+ if( tag == "header" ) {
+ QDomNode cnode = element.firstChild();
+ QDomElement celem = cnode.toElement();
+ getHeader()->loadFromXMI(celem);
+ break;
+ }
+ node = element.nextSibling();
+ element = node.toElement();
+ }
+
+ // a rare case where the super-class load is AFTER local attributes
+ CodeGenObjectWithTextBlocks::setAttributesFromNode(root);
+}
+
+/**
+ * Save the XMI representation of this object
+ */
+void CodeDocument::saveToXMI ( QDomDocument & doc, QDomElement & root ) {
+ QDomElement docElement = doc.createElement( "codedocument" );
+
+ setAttributesOnNode(doc, docElement);
+
+ root.appendChild( docElement );
+}
+
+// vanilla code documents don't have much
+// to do.. override this with a different
+// version for your own documents
+void CodeDocument::updateContent() {
+ updateHeader(); // doing this insures time/date stamp is at the time of this call
+}
+
+/**
+ * create a new CodeBlock object belonging to this CodeDocument.
+ * @return CodeBlock
+ */
+CodeBlock * CodeDocument::newCodeBlock ( ) {
+ return new CodeBlock(this);
+}
+
+/**
+ * create a new CodeBlockWithComments object belonging to this CodeDocument.
+ * @return CodeBlockWithComments
+ */
+CodeBlockWithComments * CodeDocument::newCodeBlockWithComments ( ) {
+ return new CodeBlockWithComments(this);
+}
+
+HierarchicalCodeBlock * CodeDocument::newHierarchicalCodeBlock ( ) {
+ HierarchicalCodeBlock *hb = new HierarchicalCodeBlock(this);
+ //hb->update();
+ return hb;
+}
+
+void CodeDocument::removeChildTagFromMap ( const QString &tag )
+{
+ m_childTextBlockTagMap.erase(tag);
+}
+
+void CodeDocument::addChildTagToMap ( const QString &tag, TextBlock * tb)
+{
+ m_childTextBlockTagMap.insert(tag, tb);
+}
+
+TextBlock * CodeDocument::findTextBlockByTag( const QString &tag , bool descendIntoChildren)
+{
+ //if we already know to which file this class was written/should be written, just return it.
+ if(m_textBlockTagMap.contains(tag))
+ return m_textBlockTagMap[tag];
+
+ if (descendIntoChildren)
+ if(m_childTextBlockTagMap.contains(tag))
+ return m_childTextBlockTagMap[tag];
+
+ return (TextBlock*) NULL;
+}
+
+void CodeDocument::initDoc () {
+
+ m_writeOutCode = true;
+ m_package = NULL;
+ m_fileExtension = QString("");
+ m_ID = QString(""); // leave with NO ID as a default
+
+ //m_textblockVector.setAutoDelete(false);
+
+ setHeader(new CodeComment(this));
+
+ lastTagIndex = 0;
+
+ // m_dialog = new CodeDocumentDialog( );
+
+}
+
+TextBlock * CodeDocument::findCodeClassFieldTextBlockByTag ( const QString &tag ) {
+ kWarning()<<"Called findCodeClassFieldMethodByTag("<<tag<<") for a regular CodeDocument"<<endl;
+ return (TextBlock *) NULL;
+}
+
+#include "codedocument.moc"
diff --git a/umbrello/umbrello/codedocument.h b/umbrello/umbrello/codedocument.h
new file mode 100644
index 00000000..609b70c6
--- /dev/null
+++ b/umbrello/umbrello/codedocument.h
@@ -0,0 +1,273 @@
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * copyright (C) 2004-2006 *
+ * Umbrello UML Modeller Authors <uml-devel@uml.sf.net> *
+ ***************************************************************************/
+
+/* This code generated by:
+ * Author : thomas
+ * Date : Wed Jun 18 2003
+ */
+
+#ifndef CODEDOCUMENT_H
+#define CODEDOCUMENT_H
+
+#include <qobject.h>
+#include <qmap.h>
+#include <qstring.h>
+
+#include "codegenerationpolicy.h"
+#include "codegenobjectwithtextblocks.h"
+#include "hierarchicalcodeblock.h"
+
+class QWidget;
+class CodeAccessorMethod;
+class CodeBlockWithComments;
+class CodeComment;
+class CodeOperation;
+class TextBlock;
+class UMLPackage;
+
+//#include "codedocumentdialog.h"
+
+/**
+ * class CodeDocument
+ * A document containing the code for one file.
+ */
+
+// "friend" status is needed for HBlock so it may call addChildTagToMap which
+// is protected.
+class CodeDocument : public QObject, public CodeGenObjectWithTextBlocks
+{
+ friend class HierarchicalCodeBlock;
+ Q_OBJECT
+public:
+
+ // Constructors/Destructors
+ //
+
+
+ /**
+ * Empty Constructor
+ */
+ /**
+ * Basic constructor for class.
+ */
+ CodeDocument ( );
+
+ /**
+ * Empty Destructor
+ */
+ virtual ~CodeDocument ( );
+
+ // Public attributes
+ //
+
+ // Public attribute accessor methods
+ //
+
+ /**
+ * Set the value of m_fileExtension
+ * @param new_var the new value of m_fileExtension
+ */
+ void setFileExtension ( const QString &new_var );
+
+ /**
+ * Get the value of m_fileExtension
+ * @return the value of m_fileExtension
+ */
+ QString getFileExtension ( ) const;
+
+ /**
+ * Set the complete value (name plus any extension) of m_filename
+ * @param new_var the new value of m_filename
+ */
+ void setFileName ( const QString &new_var );
+
+ /**
+ * Get the value of m_filename. This name is the "complete" filename,
+ * meaning that it contains both the file name plus any extension (e.g. "file.cpp")
+ * @return the value of m_filename
+ */
+ QString getFileName ( ) const;
+
+ /**
+ * Set the value of m_package
+ * @param new_var the new value of m_package
+ */
+ void setPackage ( UMLPackage *new_var );
+
+ /**
+ * Get the value of the package of this codedocument.
+ * @return the value of m_pathName
+ */
+ QString getPackage ( ) const;
+
+ /**
+ * Get the value of the path to this codedocument.
+ * @return the value of m_pathName
+ */
+ virtual QString getPath ( );
+
+ /**
+ * Set the value of m_ID
+ * @param new_id the new value of m_ID
+ */
+ void setID ( const QString &new_id);
+
+ /**
+ * Get the value of m_ID
+ * @return the value of m_ID
+ */
+ QString getID ( ) const;
+
+ /**
+ * Set the value of m_writeOutCode
+ * Whether or not to write out this code document and any codeblocks, etc that it
+ * owns.
+ * @param new_var the new value of m_writeOutCode
+ */
+ void setWriteOutCode ( bool new_var );
+
+ /**
+ * Get the value of m_writeOutCode
+ * Whether or not to write out this code document and any codeblocks, etc that it
+ * owns.
+ * @return the value of m_writeOutCode
+ */
+ bool getWriteOutCode ( );
+
+ /**
+ * Set a Header comment object
+ */
+ void setHeader ( CodeComment * comment );
+
+ /**
+ * Get the Header comment object
+ */
+ CodeComment * getHeader ( );
+
+ /**
+ * Insert a new text block after the existing text block. Returns
+ * false if it cannot insert the textblock.
+ */
+ bool insertTextBlock (TextBlock * newBlock, TextBlock * existingBlock, bool after = true);
+
+ /**
+ * Lookup a certain textblock by its tag value, returns NULL if it cant
+ * find the TextBlock with such a tag. If descendIntoChildren is true, then
+ * any child hierarchical textblocks will also be searched for a match.
+ */
+ TextBlock * findTextBlockByTag( const QString &tag , bool descendIntoChildren = false);
+
+ /**
+ * create the string representation of this object.
+ * @return QString
+ */
+ virtual QString toString ( );
+
+ /**
+ * Save the XMI representation of this object
+ */
+ virtual void saveToXMI ( QDomDocument & doc, QDomElement & root );
+
+ /**
+ * load params from the appropriate XMI element node.
+ */
+ virtual void loadFromXMI ( QDomElement & root );
+
+ /**
+ * create a new CodeBlock object belonging to this CodeDocument.
+ * @return CodeBlock
+ */
+ virtual CodeBlock * newCodeBlock ( );
+
+ /**
+ * create a new HierarchicalCodeBlock object belonging to this CodeDocument.
+ * @return HierarchicalCodeBlock
+ */
+ virtual HierarchicalCodeBlock * newHierarchicalCodeBlock ( );
+
+ /**
+ * create a new CodeBlockWithComments object belonging to this CodeDocument.
+ * @return CodeBlockWithComments
+ */
+ virtual CodeBlockWithComments * newCodeBlockWithComments ( );
+
+ // return a unique, and currently unallocated, text block tag for this document
+ virtual QString getUniqueTag( const QString& prefix = QString("") );
+
+ /** a little utility method to make life easier for the code document programmer
+ */
+ QString cleanName ( const QString &name );
+
+ // Cause this code document to synchronize to current generator policy
+ virtual void synchronize();
+
+
+protected:
+
+ /** set attributes of the node that represents this class
+ * in the XMI document.
+ */
+ virtual void setAttributesOnNode ( QDomDocument & doc, QDomElement & blockElement);
+
+ /** set the class attributes of this object from
+ * the passed element node.
+ */
+ virtual void setAttributesFromNode ( QDomElement & element);
+
+ // these next 2 are needed by child hierarchical code blocks so
+ // that when they call getUniqueTag, we really get a unique tag
+ // Also, it allows 'findTextBlockByTag' To find any tagged text block
+ // anywhere in the document, whether directly owned by the document OR
+ // by some child hierarchical textblock
+ void addChildTagToMap ( const QString &tag, TextBlock * tb);
+ void removeChildTagFromMap ( const QString &tag );
+
+ // update the header text of this codedocument
+ void updateHeader ();
+
+ // reset/clear our inventory of textblocks in this document
+ void resetTextBlocks();
+
+ // update the content of this code document
+ // this is where you should lay out your code document structure of textblocks
+ // in the inheriting class, should it have any text in it.
+ virtual void updateContent();
+
+ // have to implement this for CodeObjectWithTextBlocks
+ // doenst actually do anythying fo ra vannilla code document
+ virtual TextBlock * findCodeClassFieldTextBlockByTag( const QString &tag );
+
+private:
+
+ int lastTagIndex;
+ QString m_filename;
+ QString m_fileExtension;
+ QString m_ID;
+ QString m_pathName;
+ UMLPackage *m_package;
+
+ bool m_writeOutCode; // Whether or not to write out this code document
+ // and any codeblocks, etc that it owns.
+
+ CodeComment * m_header;
+
+
+ void initDoc ( ) ;
+
+ // TextBlockList m_textblockVector;
+ // QMap<QString, TextBlock *> m_textBlockTagMap;
+
+ // for recording all of the textblocks held by child hierarchical codeblocks
+ QMap<QString, TextBlock *> m_childTextBlockTagMap;
+
+};
+
+#endif // CODEDOCUMENT_H
diff --git a/umbrello/umbrello/codedocumentlist.h b/umbrello/umbrello/codedocumentlist.h
new file mode 100644
index 00000000..7cb28a72
--- /dev/null
+++ b/umbrello/umbrello/codedocumentlist.h
@@ -0,0 +1,23 @@
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * copyright (C) 2004-2007 *
+ * Umbrello UML Modeller Authors <uml-devel@uml.sf.net> *
+ ***************************************************************************/
+
+#ifndef _CODEDOCUMENTLIST_H
+#define _CODEDOCUMENTLIST_H
+
+#include <qptrlist.h>
+
+// forward declarations
+class CodeDocument;
+
+typedef QPtrList<CodeDocument> CodeDocumentList;
+typedef QPtrListIterator<CodeDocument> CodeDocumentListIt;
+
+#endif
diff --git a/umbrello/umbrello/codegenerationpolicy.cpp b/umbrello/umbrello/codegenerationpolicy.cpp
new file mode 100644
index 00000000..df84e837
--- /dev/null
+++ b/umbrello/umbrello/codegenerationpolicy.cpp
@@ -0,0 +1,587 @@
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * copyright (C) 2003-2006 *
+ * Umbrello UML Modeller Authors <uml-devel@uml.sf.net> *
+ ***************************************************************************/
+
+/* This code generated by:
+ * Author : thomas
+ * Date : Fri Jun 20 2003
+ */
+
+// own header
+#include "codegenerationpolicy.h"
+
+//system includes
+#include <cstdlib> //to get the user name
+
+// qt includes
+#include <qstringlist.h>
+#include <qregexp.h>
+#include <qtextstream.h>
+#include <qdatetime.h>
+
+// kde includes
+#include <kconfig.h>
+#include <kdeversion.h>
+#include <kdebug.h>
+#include <kstandarddirs.h>
+
+// app includes
+#include "uml.h"
+#include "umldoc.h"
+#include "dialogs/codegenerationpolicypage.h"
+
+using namespace std;
+
+#define MAXLINES 256
+
+CodeGenerationPolicy::OverwritePolicy CodeGenerationPolicy::defaultOverwritePolicy() const {
+ return Ask;
+}
+
+bool CodeGenerationPolicy::defaultVerboseSectionComments() const {
+ return true;
+}
+
+bool CodeGenerationPolicy::defaultVerboseDocumentComments() const {
+ return true;
+}
+
+bool CodeGenerationPolicy::defaultIncludeHeadings() const {
+ return true;
+}
+
+CodeGenerationPolicy::NewLineType CodeGenerationPolicy::defaultLineEndingType() const {
+ return UNIX;
+}
+
+CodeGenerationPolicy::IndentationType CodeGenerationPolicy::defaultIndentType() const {
+ return SPACE;
+}
+
+int CodeGenerationPolicy::defaultIndentAmount() const {
+ return 2;
+}
+
+CodeGenerationPolicy::ModifyNamePolicy CodeGenerationPolicy::defaultModifyNamePolicy() const {
+ return No;
+}
+
+CodeGenerationPolicy::CommentStyle CodeGenerationPolicy::defaultCommentStyle() const {
+ return SingleLine;
+}
+
+CodeGenerationPolicy::ScopePolicy CodeGenerationPolicy::defaultAttribAccessorScope() const {
+ return FromParent;
+}
+
+CodeGenerationPolicy::ScopePolicy CodeGenerationPolicy::defaultAssocFieldScope() const {
+ return FromParent;
+}
+
+bool CodeGenerationPolicy::defaultAutoGenerateConstructors() const {
+ return false;
+}
+
+
+// Constructors/Destructors
+//
+
+CodeGenerationPolicy::CodeGenerationPolicy(CodeGenerationPolicy * clone)
+{
+
+ initFields();
+ setDefaults(clone,false);
+}
+
+CodeGenerationPolicy::CodeGenerationPolicy(KConfig * config)
+{
+ initFields();
+ setDefaults(config,false);
+}
+
+CodeGenerationPolicy::~CodeGenerationPolicy ( ) { }
+
+//
+// Methods
+//
+
+
+// Accessor methods
+//
+
+
+// Public attribute accessor methods
+//
+
+/**
+ * Set the value of m_overwritePolicy
+ * Policy of how to deal with overwriting existing files. Allowed values are "ask",
+ * "yes" and "no".
+ * @param new_var the new value of m_overwritePolicy
+ */
+void CodeGenerationPolicy::setOverwritePolicy ( OverwritePolicy new_var ) {
+ m_overwritePolicy = new_var;
+}
+
+/**
+ * Get the value of m_overwritePolicy
+ * Policy of how to deal with overwriting existing files. Allowed values are "ask",
+ * "yes" and "no".
+ * @return the value of m_overwritePolicy
+ */
+CodeGenerationPolicy::OverwritePolicy CodeGenerationPolicy::getOverwritePolicy ( ) const {
+ return m_overwritePolicy;
+}
+
+/**
+ * Set the value of m_commentStyle
+ * @param new_var the new value of m_commentStyle
+ */
+void CodeGenerationPolicy::setCommentStyle ( CommentStyle new_var ) {
+ m_commentStyle = new_var;
+ emit modifiedCodeContent();
+}
+
+/**
+ * Get the value of m_commentStyle
+ * @return the value of m_commentStyle
+ */
+CodeGenerationPolicy::CommentStyle CodeGenerationPolicy::getCommentStyle ( ) {
+ return m_commentStyle;
+}
+
+/**
+ * Set the value of m_codeVerboseSectionComments
+ * Whether or not verbose code commenting for sections is desired. If true, comments
+ * for sections will be written even if the section is empty.
+ * @param new_var the new value of m_codeVerboseSectionComments
+ */
+void CodeGenerationPolicy::setCodeVerboseSectionComments ( bool new_var ) {
+ m_codeVerboseSectionComments = new_var;
+ emit modifiedCodeContent();
+}
+
+/**
+ * Get the value of m_codeVerboseSectionComments
+ * Whether or not verbose code commenting for sections is desired. If true, comments
+ * for sections will be written even if the section is empty.
+ * @return the value of m_codeVerboseSectionComments
+ */
+bool CodeGenerationPolicy::getCodeVerboseSectionComments ( ) const {
+ return m_codeVerboseSectionComments;
+}
+
+/**
+ * Set the value of m_codeVerboseDocumentComments
+ * Whether or not verbose code commenting for documentation is desired. If true,
+ * documentation for various code will be written even if no code would normally be
+ * created at that point in the file.
+ * @param new_var the new value of m_codeVerboseDocumentComments
+ */
+void CodeGenerationPolicy::setCodeVerboseDocumentComments ( bool new_var ) {
+ m_codeVerboseDocumentComments = new_var;
+ emit modifiedCodeContent();
+}
+
+/**
+ * Get the value of m_codeVerboseDocumentComments
+ * Whether or not verbose code commenting for documentation is desired. If true,
+ * documentation for various code will be written even if no code would normally be
+ * created at that point in the file.
+ * @return the value of m_codeVerboseDocumentComments
+ */
+bool CodeGenerationPolicy::getCodeVerboseDocumentComments ( ) const {
+ return m_codeVerboseDocumentComments;
+}
+
+/**
+ * Set the value of m_headingFileDir
+ * location of the header file template.
+ * @param new_var the new value of m_headingFileDir
+ */
+void CodeGenerationPolicy::setHeadingFileDir ( const QString & path) {
+ m_headingFiles.setPath(path);
+}
+
+/**
+ * Get the value of m_headingFileDir
+ * location of the header file template.
+ * @return the value of m_headingFileDir
+ */
+QString CodeGenerationPolicy::getHeadingFileDir ( ) const {
+ return m_headingFiles.absPath();
+}
+
+/**
+ * Set the value of m_includeHeadings
+ * @param new_var the new value of m_includeHeadings
+ */
+void CodeGenerationPolicy::setIncludeHeadings ( bool new_var ) {
+ m_includeHeadings = new_var;
+ emit modifiedCodeContent();
+}
+
+/**
+ * Get the value of m_includeHeadings
+ * @return the value of m_includeHeadings
+ */
+bool CodeGenerationPolicy::getIncludeHeadings ( ) const {
+ return m_includeHeadings;
+}
+
+/**
+ * Set the value of m_outputDirectory
+ * location of where output files will go.
+ * @param new_var the new value of m_outputDirectory
+ */
+void CodeGenerationPolicy::setOutputDirectory ( QDir new_var ) {
+ m_outputDirectory = new_var;
+}
+
+/**
+ * Get the value of m_outputDirectory
+ * location of where output files will go.
+ * @return the value of m_outputDirectory
+ */
+QDir CodeGenerationPolicy::getOutputDirectory ( ) {
+ return m_outputDirectory;
+}
+
+/**
+ * Set the value of m_lineEndingType
+ * What line ending characters to use.
+ * @param new_var the new value of m_lineEndingType
+ */
+void CodeGenerationPolicy::setLineEndingType ( NewLineType type) {
+ m_lineEndingType = type;
+ switch (m_lineEndingType) {
+ case MAC:
+ m_lineEndingChars = QString("\r\n");
+ break;
+ case DOS:
+ m_lineEndingChars = QString("\r");
+ break;
+ case UNIX:
+ default:
+ m_lineEndingChars = QString("\n");
+ break;
+ }
+ emit modifiedCodeContent();
+}
+
+/**
+ * Get the value of m_lineEndingType
+ * What line ending characters to use.
+ * @return the value of m_lineEndingType
+ */
+CodeGenerationPolicy::NewLineType CodeGenerationPolicy::getLineEndingType ( ) {
+ return m_lineEndingType;
+}
+
+/** Utility function to get the actual characters.
+ */
+QString CodeGenerationPolicy::getNewLineEndingChars ( ) const {
+ return m_lineEndingChars;
+}
+
+/**
+ * Set the value of m_indentationType
+ * The amount and type of whitespace to indent with.
+ * @param new_var the new value of m_indentationType
+ */
+void CodeGenerationPolicy::setIndentationType ( IndentationType new_var ) {
+ m_indentationType = new_var;
+ calculateIndentation();
+ emit modifiedCodeContent();
+}
+
+CodeGenerationPolicy::IndentationType CodeGenerationPolicy::getIndentationType ( ) {
+ return m_indentationType;
+}
+
+void CodeGenerationPolicy::setIndentationAmount ( int amount ) {
+ if(amount > -1)
+ {
+ m_indentationAmount = amount;
+ calculateIndentation();
+ emit modifiedCodeContent();
+ }
+}
+
+int CodeGenerationPolicy::getIndentationAmount ( ) {
+ return m_indentationAmount;
+}
+
+/**
+ * Utility method to get the amount (and type of whitespace) to indent with.
+ * @return the value of the indentation
+ */
+QString CodeGenerationPolicy::getIndentation ( ) const {
+ return m_indentation;
+}
+
+void CodeGenerationPolicy::calculateIndentation ( ) {
+ QString indent = "";
+ m_indentation = "";
+ switch (m_indentationType) {
+ case NONE:
+ break;
+ case TAB:
+ indent = QString("\t");
+ break;
+ default:
+ case SPACE:
+ indent = QString(" ");
+ break;
+ }
+
+ for (int i=0; i < m_indentationAmount; i++)
+ m_indentation += indent;
+}
+
+/**
+ * Set the value of m_modifyPolicy
+ * @param new_var the new value of m_modifyPolicy
+ */
+void CodeGenerationPolicy::setModifyPolicy ( ModifyNamePolicy new_var ) {
+ m_modifyPolicy = new_var;
+}
+
+/**
+ * Get the value of m_modifyPolicy
+ * @return the value of m_modifyPolicy
+ */
+CodeGenerationPolicy::ModifyNamePolicy CodeGenerationPolicy::getModifyPolicy ( ) const {
+ return m_modifyPolicy;
+}
+
+/**
+ * Set the value of m_autoGenerateConstructors
+ * @param new_var the new value
+ */
+void CodeGenerationPolicy::setAutoGenerateConstructors( bool var ) {
+ m_autoGenerateConstructors = var;
+ emit modifiedCodeContent();
+}
+
+/**
+ * Get the value of m_autoGenerateConstructors
+ * @return the value of m_autoGenerateConstructors
+ */
+bool CodeGenerationPolicy::getAutoGenerateConstructors( ){
+ return m_autoGenerateConstructors;
+}
+
+void CodeGenerationPolicy::setAttributeAccessorScope(ScopePolicy var) {
+ m_attributeAccessorScope = var;
+ emit modifiedCodeContent();
+}
+
+CodeGenerationPolicy::ScopePolicy CodeGenerationPolicy::getAttributeAccessorScope() {
+ return m_attributeAccessorScope;
+}
+
+void CodeGenerationPolicy::setAssociationFieldScope(ScopePolicy var) {
+ m_associationFieldScope = var;
+ emit modifiedCodeContent();
+}
+
+CodeGenerationPolicy::ScopePolicy CodeGenerationPolicy::getAssociationFieldScope() {
+ return m_associationFieldScope;
+}
+
+/**
+ * Create a new dialog interface for this object.
+ * @return dialog object
+ */
+CodeGenerationPolicyPage * CodeGenerationPolicy::createPage ( QWidget *pWidget, const char *name ) {
+ return new CodeGenerationPolicyPage ( pWidget, name, 0 );
+}
+
+// Other methods
+//
+
+void CodeGenerationPolicy::emitModifiedCodeContentSig() {
+ if (!UMLApp::app()->getDocument()->loading())
+ emit modifiedCodeContent();
+}
+
+void CodeGenerationPolicy::setDefaults ( CodeGenerationPolicy * clone , bool emitUpdateSignal)
+{
+
+ if(!clone)
+ return;
+
+ blockSignals(true); // we need to do this because otherwise most of these
+ // settors below will each send the modifiedCodeContent() signal
+ // needlessly (we can just make one call at the end).
+
+ setCodeVerboseSectionComments ( clone->getCodeVerboseSectionComments() );
+ setCodeVerboseDocumentComments ( clone->getCodeVerboseDocumentComments() );
+ setHeadingFileDir ( clone->getHeadingFileDir());
+ setIncludeHeadings ( clone->getIncludeHeadings());
+ setOutputDirectory ( clone->getOutputDirectory());
+ setLineEndingType ( clone->getLineEndingType());
+ setIndentationAmount ( clone->getIndentationAmount());
+ setIndentationType ( clone->getIndentationType());
+ setModifyPolicy ( clone->getModifyPolicy());
+ setOverwritePolicy ( clone->getOverwritePolicy() );
+
+ blockSignals(false); // "as you were citizen"
+
+ if(emitUpdateSignal)
+ emit modifiedCodeContent();
+
+}
+
+void CodeGenerationPolicy::setDefaults( KConfig * config, bool emitUpdateSignal)
+{
+
+ if(!config)
+ return;
+
+ blockSignals(true); // we need to do this because otherwise most of these
+ // settors below will each send the modifiedCodeContent() signal
+ // needlessly (we can just make one call at the end).
+
+ config -> setGroup("Code Generation");
+ setAttributeAccessorScope((ScopePolicy)config->readNumEntry("defaultAttributeAccessorScope",defaultAttribAccessorScope()));
+ setAssociationFieldScope((ScopePolicy)config->readNumEntry("defaultAssocFieldScope",defaultAssocFieldScope()));
+ setCommentStyle((CommentStyle)config->readNumEntry("commentStyle",defaultCommentStyle()));
+ setAutoGenerateConstructors(config->readBoolEntry("autoGenEmptyConstructors",defaultAutoGenerateConstructors()));
+ setCodeVerboseDocumentComments( config->readBoolEntry("forceDoc",defaultVerboseDocumentComments()) );
+ setCodeVerboseSectionComments( config->readBoolEntry("forceSections",defaultVerboseSectionComments()) );
+ setLineEndingType( (NewLineType) config->readNumEntry("lineEndingType",defaultLineEndingType()) );
+ setIndentationType( (IndentationType) config->readNumEntry("indentationType",defaultIndentType()) );
+ setIndentationAmount( config->readNumEntry("indentationAmount",defaultIndentAmount()));
+
+ QString path = config -> readPathEntry("outputDirectory");
+ if(path.isEmpty())
+ path = QDir::homeDirPath() + "/uml-generated-code/";
+ setOutputDirectory ( QDir (path) );
+
+ path = config -> readPathEntry("headingsDirectory");
+ if(path.isEmpty()) {
+ KStandardDirs stddirs;
+ path = stddirs.findDirs("data","umbrello/headings").first();
+ }
+ setHeadingFileDir ( path );
+
+ setIncludeHeadings( config->readBoolEntry("includeHeadings",defaultIncludeHeadings()) );
+ setOverwritePolicy( (OverwritePolicy)config->readNumEntry("overwritePolicy",defaultOverwritePolicy()));
+ setModifyPolicy( (ModifyNamePolicy)config->readNumEntry("modnamePolicy",defaultModifyNamePolicy()));
+
+ blockSignals(false); // "as you were citizen"
+
+ if(emitUpdateSignal)
+ emit modifiedCodeContent();
+
+}
+
+void CodeGenerationPolicy::writeConfig (KConfig * config) {
+
+ config->setGroup("Code Generation");
+
+ config->writeEntry("defaultAttributeAccessorScope",getAttributeAccessorScope());
+ config->writeEntry("defaultAssocFieldScope",getAssociationFieldScope());
+ config->writeEntry("commentStyle",getCommentStyle());
+ config->writeEntry("autoGenEmptyConstructors",getAutoGenerateConstructors());
+ //config->writeEntry("newCodegen", getNewCodegen());
+ config->writeEntry("forceDoc",getCodeVerboseDocumentComments());
+ config->writeEntry("forceSections",getCodeVerboseSectionComments());
+
+ config->writeEntry("lineEndingType",getLineEndingType());
+ config->writeEntry("indentationType",getIndentationType());
+ config->writeEntry("indentationAmount",getIndentationAmount());
+
+ config->writePathEntry("outputDirectory",getOutputDirectory().absPath());
+ config->writePathEntry("headingsDirectory",getHeadingFileDir());
+ config->writeEntry("includeHeadings",getIncludeHeadings());
+ config->writeEntry("overwritePolicy",getOverwritePolicy());
+ config->writeEntry("modnamePolicy", getModifyPolicy());
+
+}
+
+// return the actual text
+QString CodeGenerationPolicy::getHeadingFile(const QString& str) {
+
+ if(!getIncludeHeadings() || str.isEmpty())
+ return QString("");
+ if(str.contains(" ") ||str.contains(";")) {
+ kWarning() << "File folder must not have spaces or semi colons!" << endl;
+ return QString("");
+ }
+ //if we only get the extension, then we look for the default
+ // heading.[extension]. If there is no such file, we try to
+ // get any file with the same extension
+ QString filename;
+ if(str.startsWith(".")) {
+ if(QFile::exists(m_headingFiles.absFilePath("heading"+str)))
+ filename = m_headingFiles.absFilePath("heading"+str);
+ else {
+ m_headingFiles.setNameFilter('*' + str);
+ //if there is more than one match we just take the first one
+ filename = m_headingFiles.absFilePath(m_headingFiles.entryList().first());
+ // kWarning() << "header file name set to " << filename << " because it was *" << endl;
+ }
+ } else { //we got a file name (not only extension)
+ filename = m_headingFiles.absFilePath(str);
+ }
+
+ QFile f(filename);
+ if(!f.open(IO_ReadOnly)) {
+ // kWarning() << "Error opening heading file: " << f.name() << endl;
+ // kWarning() << "Headings directory was " << m_headingFiles.absPath() << endl;
+ return QString("");
+ }
+
+ QTextStream ts(&f);
+ QString retstr = QString("");
+ QString endLine = getNewLineEndingChars();
+ for(int l = 0; l < MAXLINES && !ts.atEnd(); l++)
+ retstr += ts.readLine()+endLine;
+
+ //do variable substitution
+ retstr.replace( QRegExp("%author%"),QString(getenv("USER"))); //get the user name from some where else
+ retstr.replace( QRegExp("%headingpath%"),filename );
+ retstr.replace( QRegExp("%time%"), QTime::currentTime().toString());
+ retstr.replace( QRegExp("%date%"), QDate::currentDate().toString());
+ // the replace filepath, time parts are also in the code document updateHeader method
+ // (which is not a virtual function)...
+
+ return retstr;
+}
+
+void CodeGenerationPolicy::initFields ( ) {
+
+ blockSignals(true);
+
+ m_overwritePolicy = defaultOverwritePolicy();
+ m_codeVerboseSectionComments = defaultVerboseSectionComments();
+ m_codeVerboseDocumentComments = defaultVerboseDocumentComments();
+ m_includeHeadings = defaultIncludeHeadings();
+ setLineEndingType(defaultLineEndingType());
+ m_indentationType = defaultIndentType();
+ m_indentationAmount = defaultIndentAmount();
+ m_modifyPolicy = defaultModifyNamePolicy();
+ m_autoGenerateConstructors = defaultAutoGenerateConstructors();
+ m_attributeAccessorScope = defaultAttribAccessorScope();
+ m_associationFieldScope = defaultAssocFieldScope();
+ m_commentStyle = defaultCommentStyle();
+
+ m_outputDirectory.setPath(QDir::home().absPath() + "/uml-generated-code/");
+ m_headingFiles.setPath(QDir::home().absPath() + "/headings/");
+
+ calculateIndentation();
+
+ blockSignals(false);
+}
+
+#include "codegenerationpolicy.moc"
diff --git a/umbrello/umbrello/codegenerationpolicy.h b/umbrello/umbrello/codegenerationpolicy.h
new file mode 100644
index 00000000..3293ec6c
--- /dev/null
+++ b/umbrello/umbrello/codegenerationpolicy.h
@@ -0,0 +1,384 @@
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * copyright (C) 2004-2006 *
+ * Umbrello UML Modeller Authors <uml-devel@uml.sf.net> *
+ ***************************************************************************/
+
+/* This code generated by:
+ * Author : thomas
+ * Date : Fri Jun 20 2003
+ */
+
+
+
+#ifndef CODEGENERATIONPOLICY_H
+#define CODEGENERATIONPOLICY_H
+
+#include <qobject.h>
+#include <qdir.h>
+#include <qdom.h>
+
+class QWidget;
+class KConfig;
+class CodeGenerationPolicyPage;
+
+/**
+ * class CodeGenerationPolicy
+ * This class describes the code generation policy for this project.
+ */
+
+class CodeGenerationPolicy : public QObject {
+ Q_OBJECT
+public:
+
+ /**
+ * OverwritePolicy can have the following values
+ * - Ok: if there is a file named the same as what you want to name your output file,
+ * you can overwrite the old file.
+ * - Ask:if there is a file named the same as what you want to name your output file,
+ * you should ask the User what to do, and give him the option to overwrite the file
+ * write the code to a different file, or to abort the generation of this class.
+ * - Never: you cannot overwrite any files. Generates a new file name like "fileName1.h", "fileName2.h"
+ * until you find an appropriate name.
+ * - Cancel: Do not output anything. This is only set if the user chooses Apply to All Remaining Files
+ * and clicks on Do not Output in the Ask dialog
+ */
+ enum OverwritePolicy {Ok=0, Ask, Never, Cancel};
+ enum ModifyNamePolicy {No=0, Underscore, Capitalise};
+ enum NewLineType {UNIX=0, DOS, MAC};
+ enum IndentationType {NONE=0, TAB, SPACE};
+ enum CommentStyle { SingleLine=0, MultiLine };
+ enum ScopePolicy { Public=200, Private, Protected, FromParent };
+
+ // set some reasonable defaults
+ OverwritePolicy defaultOverwritePolicy() const;
+ bool defaultVerboseSectionComments() const;
+ bool defaultVerboseDocumentComments() const;
+ bool defaultIncludeHeadings() const;
+ NewLineType defaultLineEndingType() const;
+ IndentationType defaultIndentType() const;
+ int defaultIndentAmount() const;
+ ModifyNamePolicy defaultModifyNamePolicy() const;
+ CommentStyle defaultCommentStyle() const;
+ ScopePolicy defaultAttribAccessorScope() const;
+ ScopePolicy defaultAssocFieldScope() const;
+ bool defaultAutoGenerateConstructors() const;
+
+ // Constructors/Destructors
+ //
+
+ /**
+ * Constructor
+ */
+ // note that as the code gen policy may be the 'default' policy, it may
+ // not be coupled with a code generator.
+ CodeGenerationPolicy (CodeGenerationPolicy * clone = 0);
+ CodeGenerationPolicy (KConfig * config );
+
+ /**
+ * Empty Destructor
+ */
+ virtual ~CodeGenerationPolicy ( );
+
+ // Public attributes
+ //
+
+ // Public attribute accessor methods
+ //
+
+ /**
+ * Set the value of m_overwritePolicy
+ * Policy of how to deal with overwriting existing files.
+ * OverwritePolicy can have the following values
+ * - Ok: if there is a file named the same as what you want to name your output file,
+ * you can overwrite the old file.
+ * - Ask:if there is a file named the same as what you want to name your output file,
+ * you should ask the User what to do, and give him the option to overwrite the file
+ * write the code to a different file, or to abort the generation of this class.
+ * - Never: you cannot overwrite any files. Generates a new file name like "fileName1.h", "fileName2.h"
+ * until you find an appropriate name.
+ * - Cancel: Do not output anything. This is only set if the user chooses Apply to All Remaining Files
+ * and clicks on Do not Output in the Ask dialog
+ *
+ * @param new_var the new value of m_overwritePolicy
+ */
+ void setOverwritePolicy ( OverwritePolicy new_var );
+
+ /**
+ * Get the value of m_overwritePolicy
+ * Policy of how to deal with overwriting existing files. Allowed values are "Ok", "Ask",
+ * "Never" "Cancel".
+ * @return the value of m_overwritePolicy
+ */
+ OverwritePolicy getOverwritePolicy ( ) const;
+
+
+ /**
+ * Set the value of m_codeVerboseSectionComments
+ * Whether or not verbose code commenting for sections is desired. If true, comments
+ * for sections will be written even if the section is empty.
+ * @param new_var the new value of m_codeVerboseSectionComments
+ */
+ void setCodeVerboseSectionComments ( bool new_var );
+
+ /**
+ * Get the value of m_codeVerboseSectionComments
+ * Whether or not verbose code commenting for sections is desired. If true, comments
+ * for sections will be written even if the section is empty.
+ * @return the value of m_codeVerboseSectionComments
+ */
+ bool getCodeVerboseSectionComments ( ) const;
+
+
+ /**
+ * Set the value of m_codeVerboseDocumentComments
+ * Whether or not verbose code commenting for documentation is desired. If true,
+ * documentation for various code will be written even if no code would normally be
+ * created at that point in the file.
+ * @param new_var the new value of m_codeVerboseDocumentComments
+ */
+ void setCodeVerboseDocumentComments ( bool new_var );
+
+ /**
+ * Get the value of m_codeVerboseDocumentComments
+ * Whether or not verbose code commenting for documentation is desired. If true,
+ * documentation for various code will be written even if no code would normally be
+ * created at that point in the file.
+ * @return the value of m_codeVerboseDocumentComments
+ */
+ bool getCodeVerboseDocumentComments ( ) const;
+
+ /**
+ * Set the value of m_headingFileDir
+ * location of the header file template.
+ * @param path the new path of m_headingFileDir
+ */
+ void setHeadingFileDir ( const QString & path);
+
+ /**
+ * Get the value of m_headingFileDir
+ * location of the header file template.
+ * @return the value of m_headingFileDir
+ */
+ QString getHeadingFileDir ( ) const;
+
+
+ /**
+ * Set the value of m_includeHeadings
+ * @param new_var the new value of m_includeHeadings
+ */
+ void setIncludeHeadings ( bool new_var );
+
+ /**
+ * Get the value of m_includeHeadings
+ * @return the value of m_includeHeadings
+ */
+ bool getIncludeHeadings ( ) const;
+
+
+ /**
+ * Set the value of m_outputDirectory
+ * location of where output files will go.
+ * @param new_var the new value of m_outputDirectory
+ */
+ void setOutputDirectory ( QDir new_var );
+
+ /**
+ * Get the value of m_outputDirectory
+ * location of where output files will go.
+ * @return the value of m_outputDirectory
+ */
+ QDir getOutputDirectory ( );
+
+ /**
+ * Set the value of m_lineEndingType
+ * What line ending characters to use.
+ * @param new_var the new value of m_lineEndingType
+ */
+ void setLineEndingType ( NewLineType new_var );
+
+ /**
+ * Get the value of m_lineEndingType
+ * What line ending characters to use.
+ * @return the value of m_lineEndingType
+ */
+ NewLineType getLineEndingType ( );
+
+ /** Utility function to get the actual characters.
+ */
+ QString getNewLineEndingChars ( ) const;
+
+ /**
+ * Set the value of m_indentationType
+ * The amount and type of whitespace to indent with.
+ * @param type the new value of m_indentationType
+ */
+ void setIndentationType ( IndentationType type );
+
+ /**
+ * Get the value of m_indentationType
+ */
+ IndentationType getIndentationType ( );
+
+ /** How many units to indent for each indentation level.
+ */
+ void setIndentationAmount ( int amount );
+ int getIndentationAmount ( );
+
+ /**
+ * Get the string representation of each level of indentation.
+ * The amount and type of whitespace to indent with.
+ * @return the value of m_indentationType
+ */
+ QString getIndentation ( ) const;
+
+ /**
+ * Set the value of m_modifyPolicy
+ * @param new_var the new value of m_modifyPolicy
+ */
+ void setModifyPolicy ( ModifyNamePolicy new_var );
+
+ /**
+ * Get the value of m_modifyPolicy
+ * @return the value of m_modifyPolicy
+ */
+ ModifyNamePolicy getModifyPolicy ( ) const;
+
+ /**
+ * Set the value of m_autoGenerateConstructors
+ * @param var the new value
+ */
+ void setAutoGenerateConstructors ( bool var );
+
+ /**
+ * Get the value of m_autoGenerateConstructors
+ * @return value the boolean value of m_autoGenerateConstructors
+ */
+ bool getAutoGenerateConstructors ( );
+
+ /**
+ * Set the value of m_attributeAccessorScope
+ * @param var the new value
+ */
+ void setAttributeAccessorScope(ScopePolicy var);
+
+ /**
+ * Get the value of m_attributeAccessorScope
+ * @return the ScopePolicy value of m_attributeAccessorScope
+ */
+ ScopePolicy getAttributeAccessorScope();
+
+ /**
+ * Set the value of m_associationFieldScope
+ * @param var the new value
+ */
+ void setAssociationFieldScope(ScopePolicy var);
+
+ /**
+ * Get the value of m_associationFieldScope
+ * @return the ScopePolicy value of m_associationFieldScope
+ */
+ ScopePolicy getAssociationFieldScope();
+
+ /**
+ * Create a new dialog interface for this object.
+ * @return dialog object
+ */
+ virtual CodeGenerationPolicyPage * createPage ( QWidget *parent = 0, const char * name = 0);
+
+ /**
+ * Gets the heading file (as a string) to be inserted at the
+ * beginning of the generated file. you give the file type as
+ * parameter and get the string. if fileName starts with a
+ * period (.) then fileName is the extension (.cpp, .h,
+ * .java) if fileName starts with another character you are
+ * requesting a specific file (mylicensefile.txt). The files
+ * can have parameters which are denoted by %parameter%.
+ *
+ * current parameters are
+ * %author%
+ * %date%
+ * %time%
+ * %filepath%
+ */
+ QString getHeadingFile(const QString& str);
+
+ /**
+ * set the defaults for this code generator from the passed generator.
+ */
+ virtual void setDefaults (CodeGenerationPolicy * defaults, bool emitUpdateSignal = true);
+
+ /**
+ * set the defaults from a config file for this code generator from the passed KConfig pointer.
+ */
+ virtual void setDefaults(KConfig * config, bool emitUpdateSignal = true);
+
+ /**
+ * write Default params to passed KConfig pointer.
+ */
+ virtual void writeConfig (KConfig * config);
+
+ void emitModifiedCodeContentSig();
+
+ /**
+ * Set the value of m_commentStyle
+ * @param new_var the new value of m_commentStyle
+ */
+ void setCommentStyle ( CommentStyle new_var );
+
+ /**
+ * Get the value of m_commentStyle
+ * @return the value of m_commentStyle
+ */
+ CommentStyle getCommentStyle ( );
+
+signals:
+
+ // this signal is sent whenever a change is made to the policy
+ // which could modifiy code document content
+ void modifiedCodeContent();
+
+protected:
+
+ // Policy of how to deal with overwriting existing files. Allowed values are "ask", "yes" and "no".
+ OverwritePolicy m_overwritePolicy;
+
+ // Whether or not verbose code commenting for sections is desired.
+ // If true, comments for sections will be written even if the section is empty.
+ bool m_codeVerboseSectionComments;
+
+ // Whether or not verbose code commenting for documentation is desired.
+ // If true, documentation for various code will be written even if no
+ //code would normally be created at that point in the file.
+ bool m_codeVerboseDocumentComments;
+
+ QDir m_headingFiles; // location of the header file template.
+ bool m_includeHeadings;
+ QDir m_outputDirectory; // location of where output files will go.
+ NewLineType m_lineEndingType; // What type of line ending characters to use.
+ IndentationType m_indentationType; // The amount and type of whitespace to indent with.
+ int m_indentationAmount; // The amount of units to indent with.
+ ModifyNamePolicy m_modifyPolicy;
+ bool m_autoGenerateConstructors;
+ CommentStyle m_commentStyle;
+ ScopePolicy m_attributeAccessorScope;
+ ScopePolicy m_associationFieldScope;
+
+ // these 2 private fields 'cache' the string values of other fields we may frequently call for
+ QString m_lineEndingChars;
+ QString m_indentation;
+
+ void calculateIndentation ( );
+
+protected:
+
+ void initFields ( );
+
+};
+
+#endif // CODEGENERATIONPOLICY_H
diff --git a/umbrello/umbrello/codegenerator.cpp b/umbrello/umbrello/codegenerator.cpp
new file mode 100644
index 00000000..a8c2ae23
--- /dev/null
+++ b/umbrello/umbrello/codegenerator.cpp
@@ -0,0 +1,723 @@
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * copyright (C) 2004-2007 *
+ * Umbrello UML Modeller Authors <uml-devel@uml.sf.net> *
+ ***************************************************************************/
+
+/* This code generated by:
+ * Author : thomas
+ * Date : Thu Jun 19 2003
+ */
+
+// own header
+#include "codegenerator.h"
+
+// system includes
+#include <cstdlib> //to get the user name
+
+// qt includes
+#include <qdatetime.h>
+#include <qregexp.h>
+#include <qdir.h>
+#include <qtextstream.h>
+
+// kde includes
+#include <kdebug.h>
+#include <klocale.h>
+#include <kmessagebox.h>
+#include <kdialogbase.h>
+#include <kapplication.h>
+
+// app includes
+#include "dialogs/overwritedialogue.h"
+#include "dialogs/codeviewerdialog.h"
+#include "codegenerators/simplecodegenerator.h"
+#include "attribute.h"
+#include "association.h"
+#include "classifier.h"
+#include "classifiercodedocument.h"
+#include "codedocument.h"
+#include "codegenerationpolicy.h"
+#include "operation.h"
+#include "uml.h"
+#include "umldoc.h"
+#include "umlobject.h"
+#include "umlattributelist.h"
+#include "umloperationlist.h"
+#include "model_utils.h"
+
+// Constructors/Destructors
+//
+
+CodeGenerator::CodeGenerator ()
+ : QObject (UMLApp::app()->getDocument())
+{
+ initFields();
+}
+
+// FIX
+// hmm. this should be pure virtual so that implemented in sub-class
+CodeGenerator::CodeGenerator (QDomElement & element )
+ : QObject (UMLApp::app()->getDocument()) {
+ initFields();
+ loadFromXMI(element); // hmm. cant call this here.. its 'pure' virtual
+}
+
+CodeGenerator::~CodeGenerator ( ) {
+ // destroy all owned codedocuments
+ CodeDocument *doc;
+ for (CodeDocumentListIt it(m_codedocumentVector);
+ (doc = it.current()) != NULL; ++it)
+ delete doc;
+ m_codedocumentVector.clear();
+}
+
+//
+// Methods
+//
+
+
+// Accessor methods
+//
+
+QString CodeGenerator::getUniqueID(CodeDocument * codeDoc)
+{
+
+ QString id = codeDoc->getID();
+
+ // does this document already exist? then just return its present id
+ if (!id.isEmpty() && findCodeDocumentByID(id))
+ return id;
+
+ // approach now differs by whether or not its a classifier code document
+ ClassifierCodeDocument * classDoc = dynamic_cast<ClassifierCodeDocument*>(codeDoc);
+ if(classDoc) {
+ UMLClassifier *c = classDoc->getParentClassifier();
+ id = ID2STR(c->getID()); // this is supposed to be unique already..
+ } else {
+
+ QString prefix = "doc";
+ QString id = prefix + "_0";
+ int number = lastIDIndex;
+ for ( ; findCodeDocumentByID(id); number++) {
+ id = prefix + '_' + QString::number(number);
+ }
+ lastIDIndex = number;
+ }
+
+ return id;
+}
+
+CodeDocument * CodeGenerator::findCodeDocumentByID( const QString &tag ) {
+ //if we already know to which file this class was written/should be written, just return it.
+ CodeDocument * doc = (CodeDocument*)NULL;
+ if((doc = m_codeDocumentDictionary.find(tag)))
+ return doc;
+
+ return doc;
+}
+
+bool CodeGenerator::addCodeDocument ( CodeDocument * doc )
+{
+ QString tag = doc->getID();
+
+ // assign a tag if one doesn't already exist
+ if(tag.isEmpty())
+ {
+ tag = getUniqueID(doc);
+ doc->setID(tag);
+ }
+
+ if(m_codeDocumentDictionary.find(tag))
+ return false; // return false, we already have some object with this tag in the list
+ else
+ m_codeDocumentDictionary.insert(tag, doc);
+
+ m_codedocumentVector.append(doc);
+ return true;
+}
+
+/**
+ * Remove a CodeDocument object from m_codedocumentVector List
+ */
+bool CodeGenerator::removeCodeDocument ( CodeDocument * remove_object ) {
+ QString tag = remove_object->getID();
+ if(!(tag.isEmpty()))
+ m_codeDocumentDictionary.remove(tag);
+ else
+ return false;
+
+ m_codedocumentVector.remove(remove_object);
+ return true;
+}
+
+/**
+ * Get the list of CodeDocument objects held by m_codedocumentVector
+ * @return QPtrList<CodeDocument *> list of CodeDocument objects held by
+ * m_codedocumentVector
+ */
+CodeDocumentList * CodeGenerator::getCodeDocumentList ( ) {
+ return &m_codedocumentVector;
+}
+
+// the vanilla version
+CodeViewerDialog * CodeGenerator::getCodeViewerDialog ( QWidget* parent, CodeDocument *doc,
+ Settings::CodeViewerState state)
+{
+ return new CodeViewerDialog(parent, doc, state);
+}
+
+// Other methods
+//
+
+void CodeGenerator::loadFromXMI (QDomElement & qElement ) {
+
+ // don't do anything for simple (compatability) code generators
+ if(dynamic_cast<SimpleCodeGenerator*>(this))
+ return;
+
+ //now look for our particular child element
+ QDomNode node = qElement.firstChild();
+ QDomElement element = node.toElement();
+ QString langType = Model_Utils::progLangToString( getLanguage() );
+
+ if (qElement.tagName() != "codegenerator"
+ || qElement.attribute("language", "UNKNOWN") != langType)
+ return;
+ // got our code generator element, now load
+ // codedocuments
+ QDomNode codeDocNode = qElement.firstChild();
+ QDomElement codeDocElement = codeDocNode.toElement();
+ while( !codeDocElement.isNull() ) {
+
+ QString docTag = codeDocElement.tagName();
+ if( docTag == "codedocument" ||
+ docTag == "classifiercodedocument"
+ ) {
+ QString id = codeDocElement.attribute( "id", "-1" );
+ CodeDocument * codeDoc = findCodeDocumentByID(id);
+ if(codeDoc)
+ codeDoc->loadFromXMI(codeDocElement);
+ else {
+ kWarning()<<" loadFromXMI: missing code document w/ id:"<<id<<", plowing ahead with pre-generated one."<<endl;
+ }
+ } else
+ kWarning()<<" loadFromXMI : got strange codegenerator child node:"<<docTag<<", ignoring."<<endl;
+
+ codeDocNode = codeDocElement.nextSibling();
+ codeDocElement = codeDocNode.toElement();
+ }
+}
+
+void CodeGenerator::saveToXMI ( QDomDocument & doc, QDomElement & root ) {
+ QString langType = Model_Utils::progLangToString( getLanguage() );
+ QDomElement docElement = doc.createElement( "codegenerator" );
+ docElement.setAttribute("language",langType);
+
+ CodeDocumentList * docList = getCodeDocumentList();
+ for (CodeDocument * codeDoc = docList->first(); codeDoc; codeDoc= docList->next())
+ codeDoc->saveToXMI(doc, docElement);
+
+ root.appendChild( docElement );
+}
+
+/**
+ * Initialize this code generator from its parent UMLDoc. When this is called, it will
+ * (re-)generate the list of code documents for this project (generator) by checking
+ * for new objects/attributes which have been added or changed in the documnet. One or more
+ * CodeDocuments will be created/overwritten/amended as is appropriate for the given language.
+ *
+ * In this 'generic' version a ClassifierCodeDocument will exist for each and
+ * every classifier that exists in our UMLDoc. IF when this is called, a code document
+ * doesn't exist for the given classifier, then we will created and add a new code
+ * document to our generator.
+ *
+ * IF you want to add non-classifier related code documents at this step,
+ * you will need to overload this method in the appropriate
+ * code generatator (see JavaCodeGenerator for an example of this).
+ */
+void CodeGenerator::initFromParentDocument( ) {
+
+ // Walk through the document converting classifiers into
+ // classifier code documents as needed (e.g only if doesn't exist)
+ UMLClassifierList concepts = UMLApp::app()->getDocument()->getClassesAndInterfaces();
+ for (UMLClassifier *c = concepts.first(); c; c = concepts.next())
+ {
+
+ // Doesn't exist? Then build one.
+ CodeDocument * codeDoc = findCodeDocumentByClassifier(c);
+ if (!codeDoc)
+ {
+ codeDoc = newClassifierCodeDocument(c);
+ addCodeDocument(codeDoc); // this will also add a unique tag to the code document
+ }
+ }
+
+}
+
+/**
+ * Force a synchronize of this code generator, and its present contents, to that of the parent UMLDocument.
+ * "UserGenerated" code will be preserved, but Autogenerated contents will be updated/replaced
+ * or removed as is apppropriate.
+ */
+void CodeGenerator::syncCodeToDocument ( ) {
+ for (CodeDocument * doc = m_codedocumentVector.first(); doc; doc=m_codedocumentVector.next())
+ doc->synchronize();
+}
+
+// in this 'vanilla' version, we only worry about adding classifier
+// documents
+void CodeGenerator::checkAddUMLObject (UMLObject * obj) {
+ if (!obj)
+ return;
+
+ UMLClassifier * c = dynamic_cast<UMLClassifier*>(obj);
+ if(c) {
+ CodeDocument * cDoc = newClassifierCodeDocument(c);
+ addCodeDocument(cDoc);
+ }
+}
+
+void CodeGenerator::checkRemoveUMLObject (UMLObject * obj)
+{
+
+ if (!obj)
+ return;
+
+ UMLClassifier * c = dynamic_cast<UMLClassifier*>(obj);
+ if(c) {
+ ClassifierCodeDocument * cDoc = (ClassifierCodeDocument*) findCodeDocumentByClassifier(c);
+ if (cDoc)
+ removeCodeDocument(cDoc);
+ }
+
+}
+
+/**
+ * @return CodeDocument
+ * @param classifier
+ */
+CodeDocument * CodeGenerator::findCodeDocumentByClassifier ( UMLClassifier * classifier ) {
+ return findCodeDocumentByID(ID2STR(classifier->getID()));
+}
+
+
+/**
+ * Write out all code documents to file as appropriate.
+ */
+void CodeGenerator::writeCodeToFile ( )
+{
+ writeListedCodeDocsToFile(&m_codedocumentVector);
+}
+
+void CodeGenerator::writeCodeToFile ( UMLClassifierList & concepts) {
+ CodeDocumentList docs;
+ docs.setAutoDelete(false);
+
+ for (UMLClassifier *concept= concepts.first(); concept; concept= concepts.next())
+ {
+ CodeDocument * doc = findCodeDocumentByClassifier(concept);
+ if(doc)
+ docs.append(doc);
+ }
+
+ writeListedCodeDocsToFile(&docs);
+}
+
+// Main method. Will write out passed code documents to file as appropriate.
+void CodeGenerator::writeListedCodeDocsToFile ( CodeDocumentList * docs ) {
+
+ // iterate thru all code documents
+ for (CodeDocument *doc = docs->first(); doc; doc = docs->next())
+ {
+
+ // we need this so we know when to emit a 'codeGenerated' signal
+ ClassifierCodeDocument * cdoc = dynamic_cast<ClassifierCodeDocument *>(doc);
+ bool codeGenSuccess = false;
+
+ // we only write the document, if so requested
+ if(doc->getWriteOutCode())
+ {
+ QString filename = findFileName(doc);
+ // check that we may open that file for writing
+ QFile file;
+ if ( openFile(file,filename) ) {
+ QTextStream stream(&file);
+ stream<<doc->toString()<<endl;
+ file.close();
+ codeGenSuccess = true; // we wrote the code OK
+ } else {
+ kWarning() << "Cannot open file :"<<filename<<" for writing " << endl;
+ }
+ }
+
+ if(cdoc)
+ emit codeGenerated(cdoc->getParentClassifier(), codeGenSuccess);
+
+ }
+
+}
+
+/**
+ * Create a new Code document belonging to this package.
+ * @return CodeDocument
+ */
+CodeDocument * CodeGenerator::newCodeDocument ( ) {
+ CodeDocument * newCodeDoc = new CodeDocument ();
+ return newCodeDoc;
+}
+
+/**
+ * @return QString
+ * @param file
+ */
+
+QString CodeGenerator::getHeadingFile( const QString &file ) {
+ return UMLApp::app()->getCommonPolicy()->getHeadingFile(file);
+}
+
+/**
+ * @return QString
+ * @param codeDoc
+ * @param name
+ */
+QString CodeGenerator::overwritableName(const QString& name, const QString &extension ) {
+
+ CodeGenerationPolicy *pol = UMLApp::app()->getCommonPolicy();
+ QDir outputDirectory = pol->getOutputDirectory();
+ QString filename = name + extension;
+
+ if (!outputDirectory.exists(filename)) {
+ return filename;
+ }
+
+ int suffix;
+ OverwriteDialogue overwriteDialog( name, outputDirectory.absPath(),
+ m_applyToAllRemaining, kapp -> mainWidget() );
+ switch (pol->getOverwritePolicy()) { //if it exists, check the OverwritePolicy we should use
+ case CodeGenerationPolicy::Ok: //ok to overwrite file
+ filename = name + extension;
+ break;
+ case CodeGenerationPolicy::Ask: //ask if we can overwrite
+ switch(overwriteDialog.exec()) {
+ case KDialogBase::Yes: //overwrite file
+ if ( overwriteDialog.applyToAllRemaining() ) {
+ pol->setOverwritePolicy(CodeGenerationPolicy::Ok);
+ filename = name + extension;
+ } else {
+ m_applyToAllRemaining = false;
+ }
+ break;
+ case KDialogBase::No: //generate similar name
+ suffix = 1;
+ while (1) {
+ filename = name + "__" + QString::number(suffix) + extension;
+ if (!outputDirectory.exists(filename))
+ break;
+ suffix++;
+ }
+ if ( overwriteDialog.applyToAllRemaining() ) {
+ pol->setOverwritePolicy(CodeGenerationPolicy::Never);
+ } else {
+ m_applyToAllRemaining = false;
+ }
+ break;
+ case KDialogBase::Cancel: //don't output anything
+ if ( overwriteDialog.applyToAllRemaining() ) {
+ pol->setOverwritePolicy(CodeGenerationPolicy::Cancel);
+ } else {
+ m_applyToAllRemaining = false;
+ }
+ return QString();
+ break;
+ }
+
+ break;
+ case CodeGenerationPolicy::Never: //generate similar name
+ suffix = 1;
+ while (1) {
+ filename = name + "__" + QString::number(suffix) + extension;
+ if (!outputDirectory.exists(filename))
+ break;
+ suffix++;
+ }
+ break;
+ case CodeGenerationPolicy::Cancel: //don't output anything
+ return QString();
+ break;
+ }
+
+ return filename;
+}
+
+
+/**
+ * @return bool
+ * @param file
+ * @param name
+ */
+bool CodeGenerator::openFile (QFile & file, const QString &fileName ) {
+ //open files for writing.
+ if(fileName.isEmpty()) {
+ kWarning() << "cannot find a file name" << endl;
+ return false;
+ } else {
+ QDir outputDirectory = UMLApp::app()->getCommonPolicy()->getOutputDirectory();
+ file.setName(outputDirectory.absFilePath(fileName));
+ if(!file.open(IO_WriteOnly)) {
+ KMessageBox::sorry(0,i18n("Cannot open file %1 for writing. Please make sure the folder exists and you have permissions to write to it.").arg(file.name()),i18n("Cannot Open File"));
+ return false;
+ }
+ return true;
+ }
+
+}
+
+
+/**
+ * @return QString
+ * @param name
+ */
+QString CodeGenerator::cleanName ( const QString &name ) {
+ QString retval = name;
+ retval.replace(QRegExp("\\W"), "_");
+ return retval;
+}
+
+QString CodeGenerator::findFileName ( CodeDocument * codeDocument ) {
+
+ //else, determine the "natural" file name
+ QString name;
+
+ // Get the path name
+ QString path = codeDocument->getPath();
+
+ // if path is given add this as a directory to the file name
+ if (!path.isEmpty()) {
+ path.replace(QRegExp("::"), "/"); // Simple hack!
+ name = path + '/' + codeDocument->getFileName();
+ path = '/' + path;
+ } else {
+ name = codeDocument->getFileName();
+ }
+
+ // Convert all "::" to "/" : Platform-specific path separator
+ name.replace(QRegExp("::"), "/"); // Simple hack!
+
+ // if a path name exists check the existence of the path directory
+ if (!path.isEmpty()) {
+ QDir outputDirectory = UMLApp::app()->getCommonPolicy()->getOutputDirectory();
+ QDir pathDir(outputDirectory.absPath() + path);
+
+ // does our complete output directory exist yet? if not, try to create it
+ if (!pathDir.exists())
+ {
+ // ugh. dir separator here is UNIX specific..
+ QStringList dirs = QStringList::split("/",pathDir.absPath());
+ QString currentDir = "";
+
+ QStringList::iterator end(dirs.end());
+ for (QStringList::iterator dir(dirs.begin()); dir != end; ++dir)
+ {
+ currentDir += '/' + *dir;
+ if (! (pathDir.exists(currentDir)
+ || pathDir.mkdir(currentDir) ) )
+ {
+ KMessageBox::error(0, i18n("Cannot create the folder:\n") +
+ pathDir.absPath() + i18n("\nPlease check the access rights"),
+ i18n("Cannot Create Folder"));
+ return NULL;
+
+ }
+ }
+ }
+ }
+
+ name.simplifyWhiteSpace();
+ name.replace(QRegExp(" "),"_");
+
+ return overwritableName( name, codeDocument->getFileExtension() );
+}
+
+void CodeGenerator::findObjectsRelated(UMLClassifier *c, UMLPackageList &cList) {
+ UMLPackage *temp;
+ UMLAssociationList associations = c->getAssociations();
+
+ for (UMLAssociation *a = associations.first(); a; a = associations.next()) {
+ temp = 0;
+ switch (a->getAssocType()) {
+ case Uml::at_Generalization:
+ case Uml::at_Realization:
+ // only the "b" end is seen by the "a" end, not other way around
+ {
+ UMLObject *objB = a->getObject(Uml::B);
+ if (objB != c)
+ temp = (UMLPackage*)objB;
+ }
+ break;
+ case Uml::at_Dependency:
+ case Uml::at_UniAssociation:
+ {
+ UMLObject *objA = a->getObject(Uml::A);
+ UMLObject *objB = a->getObject(Uml::B);
+ if (objA == c)
+ temp = static_cast<UMLPackage*>(objB);
+ }
+ break;
+ case Uml::at_Aggregation:
+ case Uml::at_Composition:
+ case Uml::at_Association:
+ {
+ UMLObject *objA = a->getObject(Uml::A);
+ UMLObject *objB = a->getObject(Uml::B);
+ if (objA == c && objB->getBaseType() != Uml::ot_Datatype)
+ temp = static_cast<UMLPackage*>(objB);
+ }
+ break;
+ default: /* all others.. like for state diagrams..we currently don't use */
+ break;
+ }
+
+ // now add in list ONLY if its not already there
+ if(temp && !cList.containsRef(temp))
+ cList.append(temp);
+ }
+
+ //operations
+ UMLOperationList opl(c->getOpList());
+ for(UMLOperation *op = opl.first(); op ; op = opl.next()) {
+ temp =0;
+ //check return value
+ temp =(UMLClassifier*) op->getType();
+ if (temp && temp->getBaseType() != Uml::ot_Datatype && !cList.containsRef(temp))
+ cList.append(temp);
+ //check parameters
+ UMLAttributeList atl = op->getParmList();
+ for (UMLAttribute *at = atl.first(); at; at = atl.next()) {
+ temp = (UMLClassifier*)at->getType();
+ if (temp && temp->getBaseType() != Uml::ot_Datatype && !cList.containsRef(temp))
+ cList.append(temp);
+ }
+
+ }
+
+ //attributes
+ if (!c->isInterface()) {
+ UMLAttributeList atl = c->getAttributeList();
+ for (UMLAttribute *at = atl.first(); at; at = atl.next()) {
+ temp=0;
+ temp = (UMLClassifier*) at->getType();
+ if (temp && temp->getBaseType() != Uml::ot_Datatype && !cList.containsRef(temp))
+ cList.append(temp);
+ }
+ }
+
+
+}
+
+/**
+ * Format an output document.
+ * @return QString
+ * @param text
+ * @param lineprefix
+ * @param linewidth
+ */
+QString CodeGenerator::formatDoc(const QString &text, const QString &linePrefix, int lineWidth) {
+ QString output;
+
+ const QString endLine = UMLApp::app()->getCommonPolicy()->getNewLineEndingChars();
+ QStringList lines = QStringList::split(endLine, text);
+ for (QStringList::ConstIterator lit = lines.begin(); lit != lines.end(); ++lit) {
+ QString input = *lit;
+ input.remove( QRegExp("\\s+$") );
+ if (input.length() < (uint)lineWidth) {
+ output += linePrefix + input + endLine;
+ continue;
+ }
+ int index;
+ while ((index = input.findRev(" ", lineWidth)) >= 0) {
+ output += linePrefix + input.left(index) + endLine; // add line
+ input.remove(0, index + 1); //and remove processed string, including
+ // white space
+ }
+ if (!input.isEmpty())
+ output += linePrefix + input + endLine;
+ }
+ return output;
+}
+
+void CodeGenerator::initFields() {
+
+ m_document = UMLApp::app()->getDocument();
+ m_codeDocumentDictionary.setAutoDelete(false);
+ m_codedocumentVector.setAutoDelete(false);
+ m_applyToAllRemaining = true;
+ lastIDIndex = 0;
+
+ // initial population of our project generator
+ // CANT Be done here because we would call pure virtual method
+ // of newClassifierDocument (bad!).
+ // We should only call from the child
+ // initFromParentDocument();
+
+}
+
+void CodeGenerator::connect_newcodegen_slots() {
+ UMLDoc *doc = UMLApp::app()->getDocument();
+ connect(doc, SIGNAL(sigObjectCreated(UMLObject*)),
+ this, SLOT(checkAddUMLObject(UMLObject*)));
+ connect(doc, SIGNAL(sigObjectRemoved(UMLObject*)),
+ this, SLOT(checkRemoveUMLObject(UMLObject*)));
+ CodeGenerationPolicy *commonPolicy = UMLApp::app()->getCommonPolicy();
+ connect(commonPolicy, SIGNAL(modifiedCodeContent()),
+ this, SLOT(syncCodeToDocument()));
+}
+
+// these are utility methods for accessing the default
+// code gen policy object and should go away when we
+// finally implement the CodeGenDialog class -b.t.
+void CodeGenerator::setForceDoc(bool f) {
+ UMLApp::app()->getCommonPolicy()->setCodeVerboseDocumentComments(f);
+}
+
+bool CodeGenerator::forceDoc() const {
+ return UMLApp::app()->getCommonPolicy()->getCodeVerboseDocumentComments();
+}
+
+void CodeGenerator::setForceSections(bool f) {
+ UMLApp::app()->getCommonPolicy()->setCodeVerboseSectionComments(f);
+}
+
+bool CodeGenerator::forceSections() const {
+ return UMLApp::app()->getCommonPolicy()->getCodeVerboseSectionComments();
+}
+
+QStringList CodeGenerator::defaultDatatypes() {
+ return QStringList();
+ //empty by default, override in your code generator
+}
+
+bool CodeGenerator::isReservedKeyword(const QString & keyword) {
+
+ const QStringList keywords = reservedKeywords();
+
+ return keywords.contains(keyword);
+}
+
+const QStringList CodeGenerator::reservedKeywords() const {
+ static QStringList emptyList;
+
+ return emptyList;
+}
+
+void CodeGenerator::createDefaultStereotypes() {
+ //empty by default, override in your code generator
+ //e.g. m_document->createDefaultStereotypes("constructor");
+}
+
+#include "codegenerator.moc"
diff --git a/umbrello/umbrello/codegenerator.h b/umbrello/umbrello/codegenerator.h
new file mode 100644
index 00000000..0928dbba
--- /dev/null
+++ b/umbrello/umbrello/codegenerator.h
@@ -0,0 +1,416 @@
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * copyright (C) 2004-2006 *
+ * Umbrello UML Modeller Authors <uml-devel@uml.sf.net> *
+ ***************************************************************************/
+
+/* This code generated by:
+ * Author : thomas
+ * Date : Thu Jun 19 2003
+ * Bugs and comments to uml-devel@lists.sf.net or http://bugs.kde.org
+ */
+
+
+#ifndef CODEGENERATOR_H
+#define CODEGENERATOR_H
+
+#include <qdict.h>
+#include <qdir.h>
+
+#include "codegenerators/codegenpolicyext.h"
+#include "codegenerationpolicy.h"
+#include "umlpackagelist.h"
+#include "umlclassifierlist.h"
+#include "codedocumentlist.h"
+#include "codeviewerstate.h"
+#include "umlnamespace.h"
+
+class UMLAttribute;
+class UMLDoc;
+class UMLObject;
+class UMLRole;
+class UMLOperation;
+
+class ClassifierCodeDocument;
+class CodeAccessorMethod;
+class CodeBlock;
+class CodeBlockWithComments;
+class CodeClassField;
+class CodeClassFieldDeclarationBlock;
+class CodeComment;
+class CodeDocument;
+class CodeOperation;
+class CodeViewerDialog;
+
+class KConfig;
+
+/**
+ * class CodeGenerator
+ * This class collects together all of the code documents which form this project,
+ * and generates code for them in a given language.
+ */
+
+/**
+ * CodeGenerator is the base class for all CodeGenerators. It
+ * provides the interface through which all Generators are invoked and
+ * the all the basic functionality. The only thing it doesn't do is to
+ * generate code =)
+ *
+ * If you want to implement a CodeGenerator for some language follow
+ * these steps:
+ *
+ * Create a class which inherits CodeGenerator. This class can have
+ * any name, I use names like CppCodeGenerator for the Cpp Generator,
+ * JavaCodeGenerator for the Java Generator and so on, but you can use what
+ * you want.
+ *
+ * The code you generate should be output to "outputDirectory" and you
+ * should respect the OverwritePolicy specified. You should call
+ * findFileName(..) to get an appropriate file name, and then you can
+ * call openFile if you want, but if you want to do it yourself you
+ *
+ * Finally put your generator in a library which can be dlopened
+ * together with a factory class (see below) and you are ready to go.
+ */
+
+
+class CodeGenerator : public QObject {
+ Q_OBJECT
+
+public:
+
+ // Constructors/Destructors
+ //
+
+ /**
+ * Constructors
+ */
+
+ /**
+ * Build a code generator.
+ * @return CodeGenerator
+ */
+ CodeGenerator ();
+
+ /**
+ * Build a code generator and then initialize it from an XMI element.
+ * @return CodeGenerator
+ * @param element an element from an XMI document
+ */
+ CodeGenerator (QDomElement & element );
+
+ /**
+ * Empty Destructor
+ */
+ virtual ~CodeGenerator ( );
+
+ // Public attribute accessor methods
+ //
+
+ /**
+ * Add a CodeDocument object to the m_codedocumentVector List
+ * @return boolean - will return false if it couldnt add a document.
+ */
+ bool addCodeDocument ( CodeDocument * add_object );
+
+ /**
+ * Replace (or possibly add a new) CodeDocument object to the m_codedocumentVector List.
+ * As names must be unique and each code document must have a name.
+ * @return boolean value which will be true if the passed document was able to replace some
+ * other document OR was added(no prior document existed..only when addIfPriorDocumentNotPresent is true).
+ * The document which was replaced will be deleted IF deleteReplacedDocument is true.
+ */
+ // bool replaceCodeDocument ( CodeDocument * replace_doc=0, bool addIfPriorDocumentNotPresent=true,
+ // bool deleteReplacedDocument=true );
+
+ /**
+ * Remove a CodeDocument object from m_codedocumentVector List
+ * @return boolean - will return false if it couldnt remove a document.
+ */
+ bool removeCodeDocument ( CodeDocument * remove_object );
+
+ /**
+ * Get the list of CodeDocument objects held by m_codedocumentVector
+ * @return CodeDocumentList list of CodeDocument objects held by
+ * m_codedocumentVector
+ */
+ CodeDocumentList * getCodeDocumentList ( );
+
+ // get a unique id for this codedocument
+ QString getUniqueID ( CodeDocument * codeDoc );
+
+ /**
+ * Save the XMI representation of this object
+ */
+ virtual void saveToXMI ( QDomDocument & doc, QDomElement & root );
+
+ /**
+ * Find a code document by the given id string.
+ * @return CodeDocument
+ */
+ CodeDocument * findCodeDocumentByID (const QString &id );
+
+ /**
+ * Write out all code documents to file as appropriate.
+ */
+ virtual void writeCodeToFile ( );
+
+ // this method is here to provide class wizard the
+ // ability to write out only those classes which
+ // are selected by the user.
+ virtual void writeCodeToFile(UMLClassifierList &list);
+
+ // these are utility methods for accessing the default
+ // code gen policy object and *perhaps* should go away when we
+ // finally implement the CodeGenDialog class -b.t.
+
+ void setModifyNamePolicy(CodeGenerationPolicy::ModifyNamePolicy p);
+ CodeGenerationPolicy::ModifyNamePolicy modifyNamePolicy()const;
+
+ void setIncludeHeadings(bool i);
+ bool includeHeadings() const;
+
+ void setHeadingFileDir(const QString &);
+ QString headingFileDir() const;
+
+ void setForceDoc(bool f);
+ bool forceDoc() const;
+
+ void setForceSections(bool f);
+ bool forceSections() const;
+
+
+ /**
+ * Gets the heading file (as a string) to be inserted at the
+ * beginning of the generated file. you give the file type as
+ * parameter and get the string. if fileName starts with a
+ * period (.) then fileName is the extension (.cpp, .h,
+ * .java) if fileName starts with another character you are
+ * requesting a specific file (mylicensefile.txt). The files
+ * can have parameters which are denoted by %parameter%.
+ *
+ * current parameters are
+ * %author%
+ * %date%
+ * %time%
+ * %filepath%
+ *
+ * @return QString
+ * @param file
+ */
+ virtual QString getHeadingFile (const QString &file );
+
+ /**
+ * Finds an appropriate file name for the given CodeDocument, taking into
+ * account the Overwrite Policy and asking the user what to do if need be
+ * (if policy == Ask).
+ *
+ * @param doc the CodeDocument for which an output file name is desired.
+ * @return the file name that should be used. (with extension) or
+ * NULL if none to be used
+ */
+ virtual QString findFileName(CodeDocument * doc);
+
+ /**
+ * Replaces spaces with underscores and capitalises as defined in m_modname
+ * @return QString
+ * @param name
+ */
+ static QString cleanName ( const QString &name );
+
+ /** Format documentation for output in source files
+ *
+ * @param text the documentation which has to be formatted
+ * @param linePrefix the prefix which has to be added in the beginnig of each line
+ * @param lineWidth the line width used for word-wrapping the documentation
+ *
+ * @return the formatted documentation text
+ */
+ QString formatDoc (const QString & text, const QString & linePrefix = " *", int lineWidth = 80 );
+
+ /**
+ * Finds all classes in the current document to which objects of class c
+ * are in some way related. Possible relations are Associations (generalization,
+ * composition, etc) as well as parameters to methods and return values
+ * this is useful in deciding which classes/files to import/include in code generation
+ * @param c the class for which relations are to be found
+ * @param cList a reference to the list into which return the result
+ */
+ static void findObjectsRelated(UMLClassifier *c, UMLPackageList &cList);
+
+ // a series of accessor method constructors that we need to define
+ // for any particular language.
+ virtual CodeDocument * newClassifierCodeDocument (UMLClassifier * classifier ) = 0;
+
+ /**
+ * @param element
+ */
+ virtual void loadFromXMI (QDomElement & element );
+
+ /**
+ * Create a new Code document belonging to this package.
+ * @return CodeDocument pointer to new code document.
+ */
+ virtual CodeDocument * newCodeDocument ( );
+
+ /**
+ * Return the unique language enum that identifies this type of code generator
+ */
+ virtual Uml::Programming_Language getLanguage() = 0;
+
+ /**
+ * Find a code document by the given classifier.
+ * @return CodeDocument
+ * @param classifier
+ */
+ //FIX
+ // NOTE: this should be 'protected' or we could have problems with CPP code generator
+ CodeDocument * findCodeDocumentByClassifier (UMLClassifier * classifier );
+
+ /**
+ * Return the default datatypes for your language (bool, int etc)
+ * Default implementation returns empty list.
+ */
+ virtual QStringList defaultDatatypes();
+
+ /** Get the editing dialog for this code document
+ */
+ virtual CodeViewerDialog * getCodeViewerDialog( QWidget* parent, CodeDocument * doc,
+ Settings::CodeViewerState state);
+
+ /**
+ * Check whether the given string is a reserved word for the
+ * language of this code generator
+ *
+ * @param rPossiblyReservedKeyword is the string to check
+ *
+ */
+ virtual bool isReservedKeyword(const QString & rPossiblyReservedKeyword);
+
+ /**
+ * get list of reserved keywords
+ */
+ virtual const QStringList reservedKeywords() const;
+
+ /**
+ * Create the default stereotypes for your language (constructor, int etc)
+ */
+ virtual void createDefaultStereotypes ();
+
+ /**
+ * Initialize this code generator from its parent UMLDoc. When this is called,
+ * it will (re-)generate the list of code documents for this project (generator)
+ * by checking for new objects/attributes which have been added or changed in the
+ * document. One or more CodeDocuments will be created/overwritten/amended as is
+ * appropriate for the given language.
+ */
+ virtual void initFromParentDocument( );
+
+ /**
+ * Connect additional slots.
+ * Only required for Advanced Code Generators.
+ * To be called after constructing the code generator (see CodeGenFactory)
+ */
+ void connect_newcodegen_slots();
+
+protected:
+
+ /**
+ * Remove (and possibly delete) all AutoGenerated content type CodeDocuments but leave
+ * the UserGenerated (and any other type) documents in this generator alone.
+ */
+ // void removeAndDeleteAllAutoGeneratedCodeDocuments ( bool deleteRemovedDocs=true );
+
+ /**
+ * Returns a name that can be written to in the output directory,
+ * respecting the overwrite policy.
+ * If a file of the given name and extension does not exist,
+ * then just returns the name.
+ * If a file of the given name and extension does exist,
+ * then opens an overwrite dialog. In this case the name returned
+ * may be a modification of the input name.
+ * This method is invoked by findFileName().
+ *
+ * @param name the proposed output file name
+ * @param extension the extension to use
+ * @return the real file name that should be used (including extension) or
+ * QString::null if none to be used
+ */
+ QString overwritableName (const QString& name, const QString &extension );
+
+ /** Opens a file named "name" for writing in the outputDirectory.
+ * If something goes wrong, it informs the user
+ * if this function returns true, you know you can write to the file
+ * @return bool
+ * @param file
+ * @param name
+ */
+ bool openFile (QFile& file, const QString &name);
+
+ /** the actual internal routine which writes code documents
+ */
+ void writeListedCodeDocsToFile(CodeDocumentList * docs);
+
+ static const char * hierarchicalCodeBlockNodeName;
+
+ // map of what code documents we currently have in this generator.
+ QDict<CodeDocument> m_codeDocumentDictionary;
+
+ /**
+ * used by overwriteDialogue to know if the apply to all
+ * remaining files checkbox should be checked (is by default)
+ */
+ bool m_applyToAllRemaining;
+
+ /**
+ * The document object
+ */
+ UMLDoc* m_document;
+
+private:
+
+ /**
+ * Maps CodeDocuments to filenames. Used for finding out which file
+ * each class was written to.
+ */
+ // this seems silly and overkill now. -b.t.
+ // QMap<CodeDocument*,QString> *m_fileMap;
+
+ CodeDocumentList m_codedocumentVector;
+ int lastIDIndex;
+
+ void initFields() ;
+
+public slots:
+
+ /** These 2 functions check for adding or removing objects to the UMLDocument */
+ virtual void checkAddUMLObject (UMLObject * obj);
+ virtual void checkRemoveUMLObject (UMLObject * obj);
+
+ /**
+ * Force a synchronize of this code generator, and its present contents, to that of the parent UMLDocument.
+ * "UserGenerated" code will be preserved, but Autogenerated contents will be updated/replaced
+ * or removed as is apppropriate.
+ */
+ virtual void syncCodeToDocument ( );
+
+signals:
+
+ /**
+ * This signal is emitted when code for a UMLClassifier has been
+ * generated. Its only really used by the codegenerationwizard to
+ * update its progress.
+ * @param concept The concept which was processed
+ * @param generated Flag, set to true if generation was successful
+ */
+ void codeGenerated(UMLClassifier* concept, bool generated);
+
+};
+
+#endif // CODEGENERATOR_H
+
diff --git a/umbrello/umbrello/codegenerators/Makefile.am b/umbrello/umbrello/codegenerators/Makefile.am
new file mode 100644
index 00000000..bc622fe0
--- /dev/null
+++ b/umbrello/umbrello/codegenerators/Makefile.am
@@ -0,0 +1,38 @@
+noinst_LTLIBRARIES = libcodegenerator.la
+
+INCLUDES = -I../dialogs -I$(top_srcdir)/umbrello/umbrello/dialogs $(all_includes)
+
+libcodegenerator_la_LDFLAGS = $(all_libraries)
+libcodegenerator_la_METASOURCES = AUTO
+libcodegenerator_la_SOURCES = codegenfactory.cpp classifierinfo.cpp \
+ javacodegenerator.cpp javaantcodedocument.cpp javacodeclassfield.cpp \
+ javaclassifiercodedocument.cpp javacodecomment.cpp javacodedocumentation.cpp \
+ javacodeoperation.cpp javacodeaccessormethod.cpp \
+ javaclassdeclarationblock.cpp javacodeclassfielddeclarationblock.cpp \
+ javacodegenerationpolicy.cpp javacodegenerationpolicypage.cpp \
+ javacodegenerationformbase.ui \
+ cppcodegenerator.cpp cppcodedocumentation.cpp cppcodeclassfield.cpp \
+ cppcodecomment.cpp cppmakecodedocument.cpp \
+ cppsourcecodedocument.cpp cppsourcecodeoperation.cpp cppsourcecodeaccessormethod.cpp \
+ cppsourcecodeclassfielddeclarationblock.cpp \
+ cppheadercodedocument.cpp cppheaderclassdeclarationblock.cpp \
+ cppheadercodeoperation.cpp cppheadercodeaccessormethod.cpp \
+ cppheadercodeclassfielddeclarationblock.cpp \
+ cppcodegenerationpolicy.cpp cppcodegenerationpolicypage.cpp \
+ cppcodegenerationformbase.ui cppcodegenerationform.cpp \
+ rubycodegenerator.cpp rubycodeclassfield.cpp \
+ rubyclassifiercodedocument.cpp rubycodecomment.cpp rubycodedocumentation.cpp \
+ rubycodeoperation.cpp rubycodeaccessormethod.cpp \
+ rubyclassdeclarationblock.cpp rubycodeclassfielddeclarationblock.cpp \
+ rubycodegenerationpolicy.cpp rubycodegenerationpolicypage.cpp \
+ rubycodegenerationformbase.ui \
+ simplecodegenerator.cpp \
+ adawriter.cpp aswriter.cpp cppwriter.cpp csharpwriter.cpp dwriter.cpp javawriter.cpp jswriter.cpp \
+ idlwriter.cpp pascalwriter.cpp perlwriter.cpp php5writer.cpp phpwriter.cpp \
+ pythonwriter.cpp rubywriter.cpp sqlwriter.cpp tclwriter.cpp xmlschemawriter.cpp \
+ xmlelementcodeblock.cpp xmlcodecomment.cpp \
+ codegen_utils.cpp
+libcodegenerator_la_COMPILE_FIRST = ../dialogs/codegenerationpolicybase.h
+
+KDE_OPTIONS = nofinal
+
diff --git a/umbrello/umbrello/codegenerators/adawriter.cpp b/umbrello/umbrello/codegenerators/adawriter.cpp
new file mode 100644
index 00000000..e1c79839
--- /dev/null
+++ b/umbrello/umbrello/codegenerators/adawriter.cpp
@@ -0,0 +1,686 @@
+/***************************************************************************
+ * adawriter.cpp - description *
+ * ------------------- *
+ * Based on javawriter.cpp by Luis De la Parra Blum *
+ * copyright : (C) 2002 by Oliver Kellogg *
+ * (C) 2003-2007 Umbrello UML Modeller Authors <uml-devel@uml.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. *
+ * *
+ ***************************************************************************/
+
+#include "adawriter.h"
+
+#include <kdebug.h>
+#include <klocale.h>
+#include <kmessagebox.h>
+#include <qfile.h>
+#include <qregexp.h>
+#include <qtextstream.h>
+
+#include "../umldoc.h"
+#include "../uml.h"
+#include "../classifier.h"
+#include "../enum.h"
+#include "../classifierlistitem.h"
+#include "../umlclassifierlistitemlist.h"
+#include "../umltemplatelist.h"
+#include "../folder.h"
+#include "../association.h"
+#include "../attribute.h"
+#include "../operation.h"
+#include "../template.h"
+#include "../umlnamespace.h"
+
+const QString AdaWriter::defaultPackageSuffix = "_Holder";
+
+AdaWriter::AdaWriter() {
+}
+
+AdaWriter::~AdaWriter() {}
+
+/**
+ * returns "Ada"
+ */
+Uml::Programming_Language AdaWriter::getLanguage() {
+ return Uml::pl_Ada;
+}
+
+
+bool AdaWriter::isOOClass(UMLClassifier *c) {
+ Uml::Object_Type ot = c->getBaseType();
+ if (ot == Uml::ot_Interface)
+ return true;
+ if (ot == Uml::ot_Enum)
+ return false;
+ if (ot != Uml::ot_Class) {
+ kDebug() << "AdaWriter::isOOClass: unknown object type " << ot << endl;
+ return false;
+ }
+ QString stype = c->getStereotype();
+ if (stype == "CORBAConstant" || stype == "CORBATypedef" ||
+ stype == "CORBAStruct" || stype == "CORBAUnion")
+ return false;
+ // CORBAValue, CORBAInterface, and all empty/unknown stereotypes are
+ // assumed to be OO classes.
+ return true;
+}
+
+QString AdaWriter::className(UMLClassifier *c, bool inOwnScope) {
+ // If the class has an enclosing package then it is assumed that
+ // the class name is the type name; if the class does not have an
+ // enclosing package then the class name acts as the Ada package
+ // name.
+ QString retval;
+ QString className = cleanName(c->getName());
+ UMLPackage *umlPkg = c->getUMLPackage();
+ if (umlPkg == UMLApp::app()->getDocument()->getRootFolder(Uml::mt_Logical)) {
+ if (! inOwnScope)
+ retval = className + '.';
+ retval.append("Object");
+ } else {
+ if (! inOwnScope)
+ retval = umlPkg->getFullyQualifiedName(".") + '.';
+ retval.append(className);
+ }
+ return retval;
+}
+
+QString AdaWriter::packageName(UMLPackage *p) {
+ // If the class has an enclosing package then it is assumed that
+ // the class name is the type name; if the class does not have an
+ // enclosing package then the class name acts as the Ada package
+ // name.
+ UMLPackage *umlPkg = p->getUMLPackage();
+ QString className = cleanName(p->getName());
+ QString retval;
+
+ if (umlPkg == UMLApp::app()->getDocument()->getRootFolder(Uml::mt_Logical))
+ umlPkg = NULL;
+
+ UMLClassifier *c = dynamic_cast<UMLClassifier*>(p);
+ if (umlPkg == NULL) {
+ retval = className;
+ if (c == NULL || !isOOClass(c))
+ retval.append(defaultPackageSuffix);
+ } else {
+ retval = umlPkg->getFullyQualifiedName(".");
+ }
+ return retval;
+}
+
+void AdaWriter::computeAssocTypeAndRole(UMLClassifier *c,
+ UMLAssociation *a,
+ QString& typeName, QString& roleName) {
+ UMLClassifier* assocEnd = dynamic_cast<UMLClassifier*>(a->getObject(Uml::B));
+ if (assocEnd == NULL)
+ return;
+ const Uml::Association_Type assocType = a->getAssocType();
+ if (assocType != Uml::at_Aggregation && assocType != Uml::at_Composition)
+ return;
+ const QString multi = a->getMulti(Uml::B);
+ bool hasNonUnityMultiplicity = (!multi.isEmpty() && multi != "1");
+ hasNonUnityMultiplicity &= !multi.contains(QRegExp("^1 *\\.\\. *1$"));
+ roleName = cleanName(a->getRoleName(Uml::B));
+ if (roleName.isEmpty())
+ roleName = cleanName(a->getName());
+ if (roleName.isEmpty()) {
+ QString artificialName = cleanName(assocEnd->getName());
+ if (hasNonUnityMultiplicity) {
+ roleName = artificialName;
+ roleName.append("_Vector");
+ } else {
+ roleName = "M_";
+ roleName.append(artificialName);
+ }
+ }
+ typeName = className(assocEnd, (assocEnd == c));
+ if (hasNonUnityMultiplicity)
+ typeName.append("_Array_Ptr");
+ else if (assocType == Uml::at_Aggregation)
+ typeName.append("_Ptr");
+}
+
+void AdaWriter::writeClass(UMLClassifier *c) {
+ if (!c) {
+ kDebug() << "Cannot write class of NULL concept!" << endl;
+ return;
+ }
+
+ const bool isClass = !c->isInterface();
+ QString classname = cleanName(c->getName());
+ QString fileName = packageName(c).lower();
+ fileName.replace('.', '-');
+
+ //find an appropriate name for our file
+ fileName = overwritableName(c, fileName, ".ads");
+ if (fileName.isEmpty()) {
+ emit codeGenerated(c, false);
+ return;
+ }
+
+ QFile file;
+ if (!openFile(file, fileName)) {
+ emit codeGenerated(c, false);
+ return;
+ }
+
+ // Start generating the code.
+
+ QTextStream ada(&file);
+ //try to find a heading file(license, comments, etc)
+ QString str;
+ str = getHeadingFile(".ads");
+ if (!str.isEmpty()) {
+ str.replace(QRegExp("%filename%"), fileName);
+ str.replace(QRegExp("%filepath%"), file.name());
+ ada << str << endl;
+ }
+
+ // Import referenced classes.
+ UMLPackageList imports;
+ findObjectsRelated(c, imports);
+ if (imports.count()) {
+ for (UMLPackage *con = imports.first(); con; con = imports.next()) {
+ if (con->getBaseType() != Uml::ot_Datatype)
+ ada << "with " << packageName(con) << "; " << m_endl;
+ }
+ ada << m_endl;
+ }
+
+ // Generate generic formals.
+ UMLTemplateList template_params = c->getTemplateList();
+ if (template_params.count()) {
+ ada << getIndent() << "generic" << m_endl;
+ m_indentLevel++;
+ for (UMLTemplate *t = template_params.first(); t; t = template_params.next()) {
+ QString formalName = t->getName();
+ QString typeName = t->getTypeName();
+ if (typeName == "class") {
+ ada << getIndent() << "type " << formalName << " is tagged private;"
+ << m_endl;
+ } else {
+ // Check whether it's a data type.
+ UMLClassifier *typeObj = t->getType();
+ if (typeObj == NULL) {
+ kError() << "AdaWriter::writeClass(template_param "
+ << typeName << "): typeObj is NULL" << endl;
+ ada << getIndent() << "type " << formalName << " is new " << typeName
+ << " with private; -- CHECK: codegen error"
+ << m_endl;
+ } else if (typeObj->getBaseType() == Uml::ot_Datatype) {
+ ada << getIndent() << formalName << " : " << typeName << ";"
+ << m_endl;
+ } else {
+ ada << getIndent() << "type " << typeName << " is new "
+ << formalName << " with private;" << m_endl;
+ }
+ }
+ }
+ m_indentLevel--;
+ }
+
+ // Here comes the package proper.
+ QString pkg = packageName(c);
+ ada << getIndent() << "package " << pkg << " is" << m_endl << m_endl;
+ m_indentLevel++;
+ if (c->getBaseType() == Uml::ot_Enum) {
+ UMLEnum *ue = static_cast<UMLEnum*>(c);
+ UMLClassifierListItemList litList = ue->getFilteredList(Uml::ot_EnumLiteral);
+ uint i = 0;
+ ada << getIndent() << "type " << classname << " is (" << m_endl;
+ m_indentLevel++;
+ for (UMLClassifierListItem *lit = litList.first(); lit; lit = litList.next()) {
+ QString enumLiteral = cleanName(lit->getName());
+ ada << getIndent() << enumLiteral;
+ if (++i < litList.count())
+ ada << "," << m_endl;
+ }
+ m_indentLevel--;
+ ada << ");" << m_endl << m_endl;
+ m_indentLevel--;
+ ada << getIndent() << "end " << pkg << ";" << m_endl << m_endl;
+ return;
+ }
+ if (! isOOClass(c)) {
+ QString stype = c->getStereotype();
+ if (stype == "CORBAConstant") {
+ ada << getIndent() << "-- " << stype << " is Not Yet Implemented" << m_endl << m_endl;
+ } else if(stype == "CORBAStruct") {
+ if (isClass) {
+ UMLAttributeList atl = c->getAttributeList();
+ UMLAttribute *at;
+ ada << getIndent() << "type " << classname << " is record" << m_endl;
+ m_indentLevel++;
+ for (at = atl.first(); at; at = atl.next()) {
+ QString name = cleanName(at->getName());
+ QString typeName = at->getTypeName();
+ ada << getIndent() << name << " : " << typeName;
+ QString initialVal = at->getInitialValue();
+ if (initialVal.latin1() && ! initialVal.isEmpty())
+ ada << " := " << initialVal;
+ ada << ";" << m_endl;
+ }
+ m_indentLevel--;
+ ada << getIndent() << "end record;" << m_endl << m_endl;
+ }
+ } else if(stype == "CORBAUnion") {
+ ada << getIndent() << "-- " << stype << " is Not Yet Implemented" << m_endl << m_endl;
+ } else if(stype == "CORBATypedef") {
+ ada << getIndent() << "-- " << stype << " is Not Yet Implemented" << m_endl << m_endl;
+ } else {
+ ada << getIndent() << "-- " << stype << ": Unknown stereotype" << m_endl << m_endl;
+ }
+ m_indentLevel--;
+ ada << getIndent() << "end " << pkg << ";" << m_endl << m_endl;
+ return;
+ }
+
+ // Write class Documentation if non-empty or if force option set.
+ if (forceDoc() || !c->getDoc().isEmpty()) {
+ ada << "--" << m_endl;
+ ada << "-- class " << classname << endl;
+ ada << formatDoc(c->getDoc(), "-- ");
+ ada << m_endl;
+ }
+
+ UMLClassifierList superclasses = c->getSuperClasses();
+
+ const QString name = className(c);
+ ada << getIndent() << "type " << name << " is ";
+ if (c->getAbstract())
+ ada << "abstract ";
+ if (superclasses.isEmpty()) {
+ ada << "tagged ";
+ } else {
+ // FIXME: Multiple inheritance is not yet supported
+ UMLClassifier* parent = superclasses.first();
+ ada << "new " << className(parent, false) << " with ";
+ }
+ ada << "private;" << m_endl << m_endl;
+ ada << getIndent() << "type " << name << "_Ptr is access all " << name << "'Class;" << m_endl << m_endl;
+ ada << getIndent() << "type " << name << "_Array is array (Positive range <>) of " << name << "_Ptr;" << m_endl << m_endl;
+ ada << getIndent() << "type " << name << "_Array_Ptr is access " << name << "_Array;" << m_endl << m_endl;
+
+ // Generate accessors for public attributes.
+ UMLAttributeList atl;
+ if (isClass) {
+ UMLAttributeList atpub;
+ atpub.setAutoDelete(false);
+
+ atl = c->getAttributeList();
+
+ UMLAttribute *at;
+ for (at = atl.first(); at; at = atl.next()) {
+ if (at->getVisibility() == Uml::Visibility::Public)
+ atpub.append(at);
+ }
+ if (forceSections() || atpub.count())
+ ada << getIndent() << "-- Accessors for public attributes:" << m_endl << m_endl;
+ for (at = atpub.first(); at; at = atpub.next()) {
+ QString member = cleanName(at->getName());
+ ada << getIndent() << "procedure Set_" << member << " (";
+ if (! at->getStatic())
+ ada << "Self : access " << name << "; ";
+ ada << "To : " << at->getTypeName() << ");" << m_endl;
+ ada << getIndent() << "function Get_" << member;
+ if (! at->getStatic())
+ ada << " (Self : access " << name << ")";
+ ada << " return " << at->getTypeName() << ";" << m_endl
+ << m_endl;
+ }
+ }
+
+ // Generate public operations.
+ UMLOperationList opl(c->getOpList());
+ UMLOperationList oppub;
+ oppub.setAutoDelete(false);
+ UMLOperation *op;
+ for (op = opl.first(); op; op = opl.next()) {
+ if (op->getVisibility() == Uml::Visibility::Public)
+ oppub.append(op);
+ }
+ if (forceSections() || oppub.count())
+ ada << getIndent() << "-- Public methods:" << m_endl << m_endl;
+ for (op = oppub.first(); op; op = oppub.next())
+ writeOperation(op, ada);
+
+ m_indentLevel--;
+ ada << getIndent() << "private" << m_endl << m_endl;
+ m_indentLevel++;
+
+ UMLAssociationList aggregations = c->getAggregations();
+ UMLAssociationList compositions = c->getCompositions();
+
+ ada << getIndent() << "type " << name << " is ";
+ if (c->getAbstract())
+ ada << "abstract ";
+ if (superclasses.isEmpty()) {
+ ada << "tagged ";
+ } else {
+ // FIXME: Multiple inheritance is not yet supported
+ UMLClassifier* parent = superclasses.first();
+ ada << "new " << className(parent, false) << " with ";
+ }
+ ada << "record" << m_endl;
+ m_indentLevel++;
+
+ if (forceSections() || !aggregations.isEmpty()) {
+ ada << getIndent() << "-- Aggregations:" << m_endl;
+ for (UMLAssociation *a = aggregations.first(); a; a = aggregations.next()) {
+ if (c != a->getObject(Uml::A))
+ continue;
+ QString typeName, roleName;
+ computeAssocTypeAndRole(c, a, typeName, roleName);
+ ada << getIndent() << roleName << " : " << typeName << ";" << m_endl;
+ }
+ ada << endl;
+ }
+ if (forceSections() || !compositions.isEmpty()) {
+ ada << getIndent() << "-- Compositions:" << m_endl;
+ for (UMLAssociation *a = compositions.first(); a; a = compositions.next()) {
+ if (c != a->getObject(Uml::A))
+ continue;
+ QString typeName, roleName;
+ computeAssocTypeAndRole(c, a, typeName, roleName);
+ ada << getIndent() << roleName << " : " << typeName << ";" << m_endl;
+ }
+ ada << endl;
+ }
+
+ if (isClass && (forceSections() || atl.count())) {
+ ada << getIndent() << "-- Attributes:" << m_endl;
+ UMLAttribute *at;
+ for (at = atl.first(); at; at = atl.next()) {
+ if (at->getStatic())
+ continue;
+ ada << getIndent() << cleanName(at->getName()) << " : "
+ << at->getTypeName();
+ if (at && at->getInitialValue().latin1() && ! at->getInitialValue().isEmpty())
+ ada << " := " << at->getInitialValue();
+ ada << ";" << m_endl;
+ }
+ }
+ bool haveAttrs = (isClass && atl.count());
+ if (aggregations.isEmpty() && compositions.isEmpty() && !haveAttrs)
+ ada << getIndent() << "null;" << m_endl;
+ m_indentLevel--;
+ ada << getIndent() << "end record;" << m_endl << m_endl;
+ if (haveAttrs) {
+ bool seen_static_attr = false;
+ for (UMLAttribute *at = atl.first(); at; at = atl.next()) {
+ if (! at->getStatic())
+ continue;
+ if (! seen_static_attr) {
+ ada << getIndent() << "-- Static attributes:" << m_endl;
+ seen_static_attr = true;
+ }
+ ada << getIndent();
+ if (at->getVisibility() == Uml::Visibility::Private)
+ ada << "-- Private: ";
+ ada << cleanName(at->getName()) << " : " << at->getTypeName();
+ if (at && at->getInitialValue().latin1() && ! at->getInitialValue().isEmpty())
+ ada << " := " << at->getInitialValue();
+ ada << ";" << m_endl;
+ }
+ if (seen_static_attr)
+ ada << m_endl;
+ }
+ // Generate protected operations.
+ UMLOperationList opprot;
+ opprot.setAutoDelete(false);
+ for (op = opl.first(); op; op = opl.next()) {
+ if (op->getVisibility() == Uml::Visibility::Protected)
+ opprot.append(op);
+ }
+ if (forceSections() || opprot.count())
+ ada << getIndent() << "-- Protected methods:" << m_endl << m_endl;
+ for (op = opprot.first(); op; op = opprot.next())
+ writeOperation(op, ada);
+
+ // Generate private operations.
+ // These are currently only generated as comments in the private part
+ // of the spec.
+ // Once umbrello supports the merging of automatically generated and
+ // hand written code sections, private operations should be generated
+ // into the package body.
+ UMLOperationList oppriv;
+ oppriv.setAutoDelete(false);
+ for (op = opl.first(); op; op = opl.next()) {
+ const Uml::Visibility::Value vis = op->getVisibility();
+ if (vis == Uml::Visibility::Private ||
+ vis == Uml::Visibility::Implementation)
+ oppriv.append(op);
+ }
+ if (forceSections() || oppriv.count())
+ ada << getIndent() << "-- Private methods:" << m_endl << m_endl;
+ for (op = oppriv.first(); op; op = oppriv.next())
+ writeOperation(op, ada, true);
+
+ m_indentLevel--;
+ ada << getIndent() << "end " << pkg << ";" << m_endl << m_endl;
+ file.close();
+ emit codeGenerated(c, true);
+}
+
+
+void AdaWriter::writeOperation(UMLOperation *op, QTextStream &ada, bool is_comment) {
+ UMLAttributeList atl = op->getParmList();
+ QString rettype = op->getTypeName();
+ bool use_procedure = (rettype.isEmpty() || rettype == "void");
+
+ ada << getIndent();
+ if (is_comment)
+ ada << "-- ";
+ if (use_procedure)
+ ada << "procedure ";
+ else
+ ada << "function ";
+ ada << cleanName(op->getName()) << " ";
+ if (! (op->getStatic() && atl.count() == 0))
+ ada << "(";
+ UMLClassifier *parentClassifier = static_cast<UMLClassifier*>(op->getUMLPackage());
+ if (! op->getStatic()) {
+ ada << "Self : access " << className(parentClassifier);
+ if (atl.count())
+ ada << ";" << m_endl;
+ }
+ if (atl.count()) {
+ uint i = 0;
+ m_indentLevel++;
+ for (UMLAttribute *at = atl.first(); at; at = atl.next()) {
+ ada << getIndent();
+ if (is_comment)
+ ada << "-- ";
+ ada << cleanName(at->getName()) << " : ";
+ Uml::Parameter_Direction pk = at->getParmKind();
+ if (pk == Uml::pd_Out)
+ ada << "out ";
+ else if (pk == Uml::pd_InOut)
+ ada << "in out ";
+ else
+ ada << "in ";
+ ada << at->getTypeName();
+ if (! at->getInitialValue().isEmpty())
+ ada << " := " << at->getInitialValue();
+ if (++i < atl.count()) //FIXME gcc warning
+ ada << ";" << m_endl;
+ }
+ m_indentLevel--;
+ }
+ if (! (op->getStatic() && atl.count() == 0))
+ ada << ")";
+ if (! use_procedure)
+ ada << " return " << rettype;
+ if (op->getAbstract())
+ ada << " is abstract";
+ ada << ";" << m_endl << m_endl;
+}
+
+QStringList AdaWriter::defaultDatatypes() {
+ QStringList l;
+ l.append("Boolean");
+ l.append("Character");
+ l.append("Positive");
+ l.append("Natural");
+ l.append("Integer");
+ l.append("Short_Integer");
+ l.append("Long_Integer");
+ l.append("Float");
+ l.append("Long_Float");
+ l.append("Duration");
+ l.append("String");
+ return l;
+}
+
+/**
+ * Check whether the given string is a reserved word for the
+ * language of this code generator
+ *
+ * @param rPossiblyReservedKeyword The string to check.
+ */
+bool AdaWriter::isReservedKeyword(const QString & rPossiblyReservedKeyword) {
+
+ const QStringList keywords = reservedKeywords();
+
+ QStringList::ConstIterator it;
+ for (it = keywords.begin(); it != keywords.end(); ++it)
+ if ((*it).lower() == rPossiblyReservedKeyword.lower())
+ return true;
+
+ return false;
+}
+
+/**
+ * get list of reserved keywords
+ */
+const QStringList AdaWriter::reservedKeywords() const {
+
+ static QStringList keywords;
+
+ if ( keywords.isEmpty() ) {
+ keywords.append( "abort" );
+ keywords.append( "abs" );
+ keywords.append( "abstract" );
+ keywords.append( "accept" );
+ keywords.append( "access" );
+ keywords.append( "aliased" );
+ keywords.append( "all" );
+ keywords.append( "and" );
+ keywords.append( "Argument_Error" );
+ keywords.append( "array" );
+ keywords.append( "Assert_Failure" );
+ keywords.append( "at" );
+ keywords.append( "begin" );
+ keywords.append( "body" );
+ keywords.append( "Boolean" );
+ keywords.append( "case" );
+ keywords.append( "Character" );
+ keywords.append( "constant" );
+ keywords.append( "Constraint_Error" );
+ keywords.append( "Conversion_Error" );
+ keywords.append( "Data_Error" );
+ keywords.append( "declare" );
+ keywords.append( "delay" );
+ keywords.append( "delta" );
+ keywords.append( "Dereference_Error" );
+ keywords.append( "Device_Error" );
+ keywords.append( "digits" );
+ keywords.append( "do" );
+ keywords.append( "Duration" );
+ keywords.append( "else" );
+ keywords.append( "elsif" );
+ keywords.append( "end" );
+ keywords.append( "End_Error" );
+ keywords.append( "entry" );
+ keywords.append( "exception" );
+ keywords.append( "exit" );
+ keywords.append( "false" );
+ keywords.append( "Float" );
+ keywords.append( "for" );
+ keywords.append( "function" );
+ keywords.append( "generic" );
+ keywords.append( "goto" );
+ keywords.append( "if" );
+ keywords.append( "in" );
+ keywords.append( "Index_Error" );
+ keywords.append( "Integer" );
+ keywords.append( "is" );
+ keywords.append( "Layout_Error" );
+ keywords.append( "Length_Error" );
+ keywords.append( "limited" );
+ keywords.append( "Long_Float" );
+ keywords.append( "Long_Integer" );
+ keywords.append( "Long_Long_Float" );
+ keywords.append( "Long_Long_Integer" );
+ keywords.append( "loop" );
+ keywords.append( "mod" );
+ keywords.append( "Mode_Error" );
+ keywords.append( "Name_Error" );
+ keywords.append( "Natural" );
+ keywords.append( "new" );
+ keywords.append( "not" );
+ keywords.append( "null" );
+ keywords.append( "of" );
+ keywords.append( "or" );
+ keywords.append( "others" );
+ keywords.append( "out" );
+ keywords.append( "package" );
+ keywords.append( "Pattern_Error" );
+ keywords.append( "Picture_Error" );
+ keywords.append( "Pointer_Error" );
+ keywords.append( "Positive" );
+ keywords.append( "pragma" );
+ keywords.append( "private" );
+ keywords.append( "procedure" );
+ keywords.append( "Program_Error" );
+ keywords.append( "protected" );
+ keywords.append( "raise" );
+ keywords.append( "range" );
+ keywords.append( "record" );
+ keywords.append( "rem" );
+ keywords.append( "renames" );
+ keywords.append( "requeue" );
+ keywords.append( "return" );
+ keywords.append( "reverse" );
+ keywords.append( "select" );
+ keywords.append( "separate" );
+ keywords.append( "Short_Float" );
+ keywords.append( "Short_Integer" );
+ keywords.append( "Short_Short_Float" );
+ keywords.append( "Short_Short_Integer" );
+ keywords.append( "Status_Error" );
+ keywords.append( "Storage_Error" );
+ keywords.append( "String" );
+ keywords.append( "subtype" );
+ keywords.append( "Tag_Error" );
+ keywords.append( "tagged" );
+ keywords.append( "task" );
+ keywords.append( "Tasking_Error" );
+ keywords.append( "terminate" );
+ keywords.append( "Terminator_Error" );
+ keywords.append( "then" );
+ keywords.append( "Time_Error" );
+ keywords.append( "Translation_Error" );
+ keywords.append( "true" );
+ keywords.append( "type" );
+ keywords.append( "until" );
+ keywords.append( "Update_Error" );
+ keywords.append( "use" );
+ keywords.append( "Use_Error" );
+ keywords.append( "when" );
+ keywords.append( "while" );
+ keywords.append( "Wide_Character" );
+ keywords.append( "Wide_String" );
+ keywords.append( "with" );
+ keywords.append( "xor" );
+ }
+
+ return keywords;
+}
+
+#include "adawriter.moc"
diff --git a/umbrello/umbrello/codegenerators/adawriter.h b/umbrello/umbrello/codegenerators/adawriter.h
new file mode 100644
index 00000000..ca5d9f67
--- /dev/null
+++ b/umbrello/umbrello/codegenerators/adawriter.h
@@ -0,0 +1,105 @@
+/***************************************************************************
+ adawriter.h - description
+ -------------------
+ Based on javawriter.h by Luis De la Parra Blum
+ begin : Sat Dec 14 2002
+ copyright : (C) 2002 by Oliver Kellogg
+ email : okellogg@users.sourceforge.net
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the 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 ADAWRITER_H
+#define ADAWRITER_H
+
+#include "simplecodegenerator.h"
+
+class UMLAssociation;
+class UMLOperation;
+
+/**
+ * class AdaWriter is a code generator for UMLClassifier objects.
+ * Create an instance of this class, and feed it a UMLClassifier when
+ * calling writeClass and it will generate an Ada package spec for
+ * that concept
+ */
+class AdaWriter : public SimpleCodeGenerator {
+ Q_OBJECT
+public:
+
+ /**
+ * Basic Constructor
+ */
+ AdaWriter ();
+
+ /**
+ * Empty Destructor
+ */
+ virtual ~AdaWriter ();
+
+ /**
+ * call this method to generate Ada code for a UMLClassifier
+ * @param c the class to generate code for
+ */
+ virtual void writeClass (UMLClassifier *c);
+
+ /**
+ * returns "Ada"
+ */
+ virtual Uml::Programming_Language getLanguage();
+
+ QStringList defaultDatatypes();
+
+ /**
+ * Check whether the given string is a reserved word for the
+ * language of this code generator
+ *
+ * @param rPossiblyReservedKeyword The string to check.
+ * @return true if the keyword is reserved
+ */
+ virtual bool isReservedKeyword(const QString & rPossiblyReservedKeyword);
+
+ /**
+ * get list of reserved keywords
+ */
+ virtual const QStringList reservedKeywords() const;
+
+private:
+
+ /**
+ * write one operation
+ * @param op the class for which we are generating code
+ * @param ada the stream associated with the output file
+ */
+ void writeOperation (UMLOperation *op, QTextStream &ada, bool is_comment = false);
+
+ /**
+ * Compute the type and role name from the given association.
+ *
+ * @param c The UMLClassifier for which code is being generated.
+ * @param a The UMLAssociation to analyze.
+ * @param typeName Return value: type name.
+ * @param roleName Return value: role name.
+ */
+ void computeAssocTypeAndRole (UMLClassifier *c,
+ UMLAssociation *a,
+ QString& typeName, QString& roleName);
+
+ bool isOOClass (UMLClassifier *c);
+
+ QString className(UMLClassifier *c, bool inOwnScope = true);
+
+ QString packageName(UMLPackage *p);
+
+ static const QString defaultPackageSuffix;
+
+};
+
+#endif // ADAWRITER_H
diff --git a/umbrello/umbrello/codegenerators/aswriter.cpp b/umbrello/umbrello/codegenerators/aswriter.cpp
new file mode 100644
index 00000000..ad55839d
--- /dev/null
+++ b/umbrello/umbrello/codegenerators/aswriter.cpp
@@ -0,0 +1,775 @@
+/***************************************************************************
+ begin : Sat Feb 08 2003
+ copyright : (C) 2003 by Alexander Blum
+ email : blum@kewbee.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. *
+ * *
+ ***************************************************************************/
+
+#include "aswriter.h"
+#include "../association.h"
+#include "../classifier.h"
+#include "../operation.h"
+#include "../umldoc.h"
+#include "../attribute.h"
+
+#include <kdebug.h>
+#include <qregexp.h>
+#include <qtextstream.h>
+
+ASWriter::ASWriter() {
+}
+
+ASWriter::~ASWriter() {}
+
+
+void ASWriter::writeClass(UMLClassifier *c)
+{
+ if(!c)
+ {
+ kDebug()<<"Cannot write class of NULL concept!" << endl;
+ return;
+ }
+
+ QString classname = cleanName(c->getName());
+ QString fileName = c->getName().lower();
+
+ //find an appropriate name for our file
+ fileName = findFileName(c,".as");
+ if (fileName.isEmpty())
+ {
+ emit codeGenerated(c, false);
+ return;
+ }
+
+ QFile fileas;
+ if(!openFile(fileas,fileName))
+ {
+ emit codeGenerated(c, false);
+ return;
+ }
+ QTextStream as(&fileas);
+
+ //////////////////////////////
+ //Start generating the code!!
+ /////////////////////////////
+
+
+ //try to find a heading file (license, coments, etc)
+ QString str;
+ str = getHeadingFile(".as");
+ if(!str.isEmpty())
+ {
+ str.replace(QRegExp("%filename%"),fileName+".as");
+ str.replace(QRegExp("%filepath%"),fileas.name());
+ as << str << m_endl;
+ }
+
+
+ //write includes
+ UMLPackageList includes;
+ findObjectsRelated(c,includes);
+ for (UMLPackage *conc = includes.first(); conc; conc = includes.next())
+ {
+ QString headerName = findFileName(conc, ".as");
+ if ( !headerName.isEmpty() )
+ {
+ as << "#include \"" << findFileName(conc,".as") << "\"" << m_endl;
+ }
+ }
+ as << m_endl;
+
+ //Write class Documentation if there is somthing or if force option
+ if(forceDoc() || !c->getDoc().isEmpty())
+ {
+ as << m_endl << "/**" << m_endl;
+ as << " * class " << classname << m_endl;
+ as << formatDoc(c->getDoc()," * ");
+ as << " */" << m_endl << m_endl;
+ }
+
+ UMLClassifierList superclasses = c->getSuperClasses();
+ UMLAssociationList aggregations = c->getAggregations();
+ UMLAssociationList compositions = c->getCompositions();
+
+ //check if class is abstract and / or has abstract methods
+ if(c->getAbstract() && !hasAbstractOps(c))
+ as << "/******************************* Abstract Class ****************************" << m_endl << " "
+ << classname << " does not have any pure virtual methods, but its author" << m_endl
+ << " defined it as an abstract class, so you should not use it directly." << m_endl
+ << " Inherit from it instead and create only objects from the derived classes" << m_endl
+ << "*****************************************************************************/" << m_endl << m_endl;
+
+ as << classname << " = function ()" << m_endl;
+ as << "{" << m_endl;
+ as << m_indentation << "this._init ();" << m_endl;
+ as << "}" << m_endl;
+ as << m_endl;
+
+ for(UMLClassifier *obj = superclasses.first();
+ obj; obj = superclasses.next()) {
+ as << classname << ".prototype = new " << cleanName(obj->getName()) << " ();" << m_endl;
+ }
+
+ as << m_endl;
+
+ const bool isClass = !c->isInterface();
+ if (isClass) {
+
+ UMLAttributeList atl = c->getAttributeList();
+
+ as << "/**" << m_endl;
+ QString temp = "_init sets all " + classname +
+ " attributes to their default values. " +
+ "Make sure to call this method within your class constructor";
+ as << formatDoc(temp, " * ");
+ as << " */" << m_endl;
+ as << classname << ".prototype._init = function ()" << m_endl;
+ as << "{" << m_endl;
+ for(UMLAttribute *at = atl.first(); at ; at = atl.next())
+ {
+ if (forceDoc() || !at->getDoc().isEmpty())
+ {
+ as << m_indentation << "/**" << m_endl
+ << formatDoc(at->getDoc(), m_indentation + " * ")
+ << m_indentation << " */" << m_endl;
+ }
+ if(!at->getInitialValue().isEmpty())
+ {
+ as << m_indentation << "this.m_" << cleanName(at->getName()) << " = " << at->getInitialValue() << ";" << m_endl;
+ }
+ else
+ {
+ as << m_indentation << "this.m_" << cleanName(at->getName()) << " = \"\";" << m_endl;
+ }
+ }
+ }
+
+ //associations
+ if (forceSections() || !aggregations.isEmpty ())
+ {
+ as << m_endl << m_indentation << "/**Aggregations: */" << m_endl;
+ writeAssociation(classname, aggregations , as );
+
+ }
+
+ if( forceSections() || !compositions.isEmpty())
+ {
+ as << m_endl << m_indentation << "/**Compositions: */" << m_endl;
+ writeAssociation(classname, compositions , as );
+ }
+
+ as << m_endl;
+ as << m_indentation << "/**Protected: */" << m_endl;
+
+ if (isClass) {
+ UMLAttributeList atl = c->getAttributeList();
+ for (UMLAttribute *at = atl.first(); at ; at = atl.next())
+ {
+ if (at->getVisibility() == Uml::Visibility::Protected)
+ {
+ as << m_indentation << "ASSetPropFlags (this, \"" << cleanName(at->getName()) << "\", 1);" << m_endl;
+ }
+ }
+ }
+
+ UMLOperationList opList(c->getOpList());
+ for (UMLOperation *op = opList.first(); op; op = opList.next())
+ {
+ if (op->getVisibility() == Uml::Visibility::Protected)
+ {
+ as << m_indentation << "ASSetPropFlags (this, \"" << cleanName(op->getName()) << "\", 1);" << m_endl;
+ }
+ }
+ as << m_endl;
+ as << m_indentation << "/**Private: */" << m_endl;
+ if (isClass) {
+ UMLAttributeList atl = c->getAttributeList();
+ for (UMLAttribute *at = atl.first(); at; at = atl.next())
+ {
+ if (at->getVisibility() == Uml::Visibility::Private)
+ {
+ as << m_indentation << "ASSetPropFlags (this, \"" << cleanName(at->getName()) << "\", 7);" << m_endl;
+ }
+ }
+ }
+
+ for (UMLOperation *op = opList.first(); op; op = opList.next())
+ {
+ if (op->getVisibility() == Uml::Visibility::Protected)
+ {
+ as << m_indentation << "ASSetPropFlags (this, \"" << cleanName(op->getName()) << "\", 7);" << m_endl;
+ }
+ }
+ as << "}" << m_endl;
+
+ as << m_endl;
+
+ //operations
+ UMLOperationList ops(c->getOpList());
+ writeOperations(classname, &ops, as);
+
+ as << m_endl;
+
+ //finish file
+
+ //close files and notfiy we are done
+ fileas.close();
+ emit codeGenerated(c, true);
+}
+
+////////////////////////////////////////////////////////////////////////////////////
+// Helper Methods
+
+
+void ASWriter::writeAssociation(QString& classname, UMLAssociationList& assocList , QTextStream &as )
+{
+ for(UMLAssociation *a = assocList.first(); a; a = assocList.next())
+ {
+ // association side
+ Uml::Role_Type role = a->getObject(Uml::A)->getName() == classname ? Uml::B:Uml::A;
+
+ QString roleName(cleanName(a->getRoleName(role)));
+
+ if (!roleName.isEmpty()) {
+
+ // association doc
+ if (forceDoc() || !a->getDoc().isEmpty()) {
+ as << m_indentation << "/**" << m_endl
+ << formatDoc(a->getDoc(), m_indentation + " * ")
+ << m_indentation << " */" << m_endl;
+ }
+
+ // role doc
+ if (forceDoc() || !a->getRoleDoc(role).isEmpty()) {
+ as << m_indentation << "/**" << m_endl
+ << formatDoc(a->getRoleDoc(role), m_indentation + " * ")
+ << m_indentation << " */" << m_endl;
+ }
+
+ bool okCvt;
+ int nMulti = a->getMulti(role).toInt(&okCvt,10);
+ bool isNotMulti = a->getMulti(role).isEmpty() || (okCvt && nMulti == 1);
+
+ QString typeName(cleanName(a->getObject(role)->getName()));
+
+ if (isNotMulti)
+ as << m_indentation << "this.m_" << roleName << " = new " << typeName << "();" << m_endl;
+ else
+ as << m_indentation << "this.m_" << roleName << " = new Array();" << m_endl;
+
+ // role visibility
+ if (a->getVisibility(role) == Uml::Visibility::Private)
+ {
+ as << m_indentation << "ASSetPropFlags (this, \"m_" << roleName << "\", 7);" << m_endl;
+ }
+ else if (a->getVisibility(role)== Uml::Visibility::Protected)
+ {
+ as << m_indentation << "ASSetPropFlags (this, \"m_" << roleName << "\", 1);" << m_endl;
+ }
+ }
+ }
+}
+
+void ASWriter::writeOperations(QString classname, UMLOperationList *opList, QTextStream &as)
+{
+ UMLOperation *op;
+ UMLAttributeList atl;
+ UMLAttribute *at;
+
+ for(op = opList->first(); op; op = opList->next())
+ {
+ atl = op -> getParmList();
+ //write method doc if we have doc || if at least one of the params has doc
+ bool writeDoc = forceDoc() || !op->getDoc().isEmpty();
+ for (at = atl.first(); at ; at = atl.next())
+ writeDoc |= !at->getDoc().isEmpty();
+
+ if( writeDoc ) //write method documentation
+ {
+ as << "/**" << m_endl << formatDoc(op->getDoc()," * ");
+
+ for (at = atl.first(); at; at = atl.next()) //write parameter documentation
+ {
+ if(forceDoc() || !at->getDoc().isEmpty())
+ {
+ as << " * @param " + cleanName(at->getName())<<m_endl;
+ as << formatDoc(at->getDoc()," * ");
+ }
+ }//end for : write parameter documentation
+ as << " */" << m_endl;
+ }//end if : write method documentation
+
+ as << classname << ".prototype." << cleanName(op->getName()) << " = function " << "(";
+
+ int i= atl.count();
+ int j=0;
+ for (at = atl.first(); at; at = atl.next(),j++)
+ {
+ as << cleanName(at->getName())
+ << (!(at->getInitialValue().isEmpty()) ? (QString(" = ")+at->getInitialValue()) : QString(""))
+ << ((j < i-1)?", ":"");
+ }
+ as << ")" << m_endl << "{" << m_endl <<
+ m_indentation << m_endl << "}" << m_endl;
+ as << m_endl << m_endl;
+ }//end for
+}
+
+/**
+ * returns "ActionScript"
+ */
+Uml::Programming_Language ASWriter::getLanguage() {
+ return Uml::pl_ActionScript;
+}
+
+const QStringList ASWriter::reservedKeywords() const {
+
+ static QStringList keywords;
+
+ if ( keywords.isEmpty() ) {
+ keywords << "abs"
+ << "acos"
+ << "add"
+ << "addListener"
+ << "addProperty"
+ << "align"
+ << "_alpha"
+ << "and"
+ << "appendChild"
+ << "apply"
+ << "Array"
+ << "asin"
+ << "atan"
+ << "atan2"
+ << "attachMovie"
+ << "attachSound"
+ << "attributes"
+ << "autoSize"
+ << "background"
+ << "backgroundColor"
+ << "BACKSPACE"
+ << "beginFill"
+ << "beginGradientFill"
+ << "blockIndent"
+ << "bold"
+ << "Boolean"
+ << "border"
+ << "borderColor"
+ << "bottomScroll"
+ << "break"
+ << "bullet"
+ << "call"
+ << "callee"
+ << "caller"
+ << "capabilities"
+ << "CAPSLOCK"
+ << "case"
+ << "ceil"
+ << "charAt"
+ << "charCodeAt"
+ << "childNodes"
+ << "chr"
+ << "clear"
+ << "clearInterval"
+ << "cloneNode"
+ << "close"
+ << "color"
+ << "Color"
+ << "comment"
+ << "concat"
+ << "connect"
+ << "contentType"
+ << "continue"
+ << "CONTROL"
+ << "cos"
+ << "createElement"
+ << "createEmptyMovieClip"
+ << "createTextField"
+ << "createTextNode"
+ << "_currentframe"
+ << "curveTo"
+ << "Date"
+ << "default"
+ << "delete"
+ << "DELETEKEY"
+ << "do"
+ << "docTypeDecl"
+ << "DOWN"
+ << "_droptarget"
+ << "duplicateMovieClip"
+ << "duration"
+ << "E"
+ << "else"
+ << "embedFonts"
+ << "enabled"
+ << "END"
+ << "endFill"
+ << "endinitclip"
+ << "ENTER"
+ << "eq"
+ << "escape"
+ << "ESCAPE"
+ << "eval"
+ << "evaluate"
+ << "exp"
+ << "false"
+ << "firstChild"
+ << "floor"
+ << "focusEnabled"
+ << "_focusrect"
+ << "font"
+ << "for"
+ << "_framesloaded"
+ << "fromCharCode"
+ << "fscommand"
+ << "function"
+ << "ge"
+ << "get"
+ << "getAscii"
+ << "getBeginIndex"
+ << "getBounds"
+ << "getBytesLoaded"
+ << "getBytesTotal"
+ << "getCaretIndex"
+ << "getCode"
+ << "getDate"
+ << "getDay"
+ << "getDepth"
+ << "getEndIndex"
+ << "getFocus"
+ << "getFontList"
+ << "getFullYear"
+ << "getHours"
+ << "getMilliseconds"
+ << "getMinutes"
+ << "getMonth"
+ << "getNewTextFormat"
+ << "getPan"
+ << "getProperty"
+ << "getRGB"
+ << "getSeconds"
+ << "getTextExtent"
+ << "getTextFormat"
+ << "getTime"
+ << "getTimer"
+ << "getTimezoneOffset"
+ << "getTransform"
+ << "getURL"
+ << "getUTCDate"
+ << "getUTCDay"
+ << "getUTCFullYear"
+ << "getUTCHours"
+ << "getUTCMilliseconds"
+ << "getUTCMinutes"
+ << "getUTCMonth"
+ << "getUTCSeconds"
+ << "getVersion"
+ << "getVolume"
+ << "getYear"
+ << "_global"
+ << "globalToLocal"
+ << "goto"
+ << "gotoAndPlay"
+ << "gotoAndStop"
+ << "gt"
+ << "hasAccessibility"
+ << "hasAudio"
+ << "hasAudioEncoder"
+ << "hasChildNodes"
+ << "hasMP3"
+ << "hasVideoEncoder"
+ << "height"
+ << "_height"
+ << "hide"
+ << "_highquality"
+ << "hitArea"
+ << "hitTest"
+ << "HOME"
+ << "hscroll"
+ << "html"
+ << "htmlText"
+ << "if"
+ << "ifFrameLoaded"
+ << "ignoreWhite"
+ << "in"
+ << "include"
+ << "indent"
+ << "indexOf"
+ << "initclip"
+ << "INSERT"
+ << "insertBefore"
+ << "install"
+ << "instanceof"
+ << "int"
+ << "isActive"
+ << "isDown"
+ << "isFinite"
+ << "isNaN"
+ << "isToggled"
+ << "italic"
+ << "join"
+ << "lastChild"
+ << "lastIndexOf"
+ << "le"
+ << "leading"
+ << "LEFT"
+ << "leftMargin"
+ << "length"
+ << "_level"
+ << "lineStyle"
+ << "lineTo"
+ << "list"
+ << "LN10"
+ << "LN2"
+ << "load"
+ << "loaded"
+ << "loadMovie"
+ << "loadMovieNum"
+ << "loadSound"
+ << "loadVariables"
+ << "loadVariablesNum"
+ << "LoadVars"
+ << "localToGlobal"
+ << "log"
+ << "LOG10E"
+ << "LOG2E"
+ << "max"
+ << "maxChars"
+ << "maxhscroll"
+ << "maxscroll"
+ << "MAX_VALUE"
+ << "mbchr"
+ << "mblength"
+ << "mbord"
+ << "mbsubstring"
+ << "method"
+ << "min"
+ << "MIN_VALUE"
+ << "moveTo"
+ << "multiline"
+ << "_name"
+ << "NaN"
+ << "ne"
+ << "NEGATIVE_INFINITY"
+ << "new"
+ << "newline"
+ << "nextFrame"
+ << "nextScene"
+ << "nextSibling"
+ << "nodeName"
+ << "nodeType"
+ << "nodeValue"
+ << "not"
+ << "null"
+ << "Number"
+ << "Object"
+ << "on"
+ << "onChanged"
+ << "onClipEvent"
+ << "onClose"
+ << "onConnect"
+ << "onData"
+ << "onDragOut"
+ << "onDragOver"
+ << "onEnterFrame"
+ << "onKeyDown"
+ << "onKeyUp"
+ << "onKillFocus"
+ << "onLoad"
+ << "onMouseDown"
+ << "onMouseMove"
+ << "onMouseUp"
+ << "onPress"
+ << "onRelease"
+ << "onReleaseOutside"
+ << "onResize"
+ << "onRollOut"
+ << "onRollOver"
+ << "onScroller"
+ << "onSetFocus"
+ << "onSoundComplete"
+ << "onUnload"
+ << "onUpdate"
+ << "onXML"
+ << "or"
+ << "ord"
+ << "_parent"
+ << "parentNode"
+ << "parseFloat"
+ << "parseInt"
+ << "parseXML"
+ << "password"
+ << "PGDN"
+ << "PGUP"
+ << "PI"
+ << "pixelAspectRatio"
+ << "play"
+ << "pop"
+ << "position"
+ << "POSITIVE_INFINITY"
+ << "pow"
+ << "prevFrame"
+ << "previousSibling"
+ << "prevScene"
+ << "print"
+ << "printAsBitmap"
+ << "printAsBitmapNum"
+ << "printNum"
+ << "__proto__"
+ << "prototype"
+ << "push"
+ << "_quality"
+ << "random"
+ << "registerClass"
+ << "removeListener"
+ << "removeMovieClip"
+ << "removeNode"
+ << "removeTextField"
+ << "replaceSel"
+ << "restrict"
+ << "return"
+ << "reverse"
+ << "RIGHT"
+ << "rightMargin"
+ << "_root"
+ << "_rotation"
+ << "round"
+ << "scaleMode"
+ << "screenColor"
+ << "screenDPI"
+ << "screenResolutionX"
+ << "screenResolutionY"
+ << "scroll"
+ << "selectable"
+ << "send"
+ << "sendAndLoad"
+ << "set"
+ << "setDate"
+ << "setFocus"
+ << "setFullYear"
+ << "setHours"
+ << "setInterval"
+ << "setMask"
+ << "setMilliseconds"
+ << "setMinutes"
+ << "setMonth"
+ << "setNewTextFormat"
+ << "setPan"
+ << "setProperty"
+ << "setRGB"
+ << "setSeconds"
+ << "setSelection"
+ << "setTextFormat"
+ << "setTime"
+ << "setTransform"
+ << "setUTCDate"
+ << "setUTCFullYear"
+ << "setUTCHours"
+ << "setUTCMilliseconds"
+ << "setUTCMinutes"
+ << "setUTCMonth"
+ << "setUTCSeconds"
+ << "setVolume"
+ << "setYear"
+ << "shift"
+ << "SHIFT"
+ << "show"
+ << "showMenu"
+ << "sin"
+ << "size"
+ << "slice"
+ << "sort"
+ << "sortOn"
+ << "Sound"
+ << "_soundbuftime"
+ << "SPACE"
+ << "splice"
+ << "split"
+ << "sqrt"
+ << "SQRT1_2"
+ << "SQRT2"
+ << "start"
+ << "startDrag"
+ << "status"
+ << "stop"
+ << "stopAllSounds"
+ << "stopDrag"
+ << "String"
+ << "substr"
+ << "substring"
+ << "super"
+ << "swapDepths"
+ << "switch"
+ << "TAB"
+ << "tabChildren"
+ << "tabEnabled"
+ << "tabIndex"
+ << "tabStops"
+ << "tan"
+ << "target"
+ << "_target"
+ << "targetPath"
+ << "tellTarget"
+ << "text"
+ << "textColor"
+ << "TextFormat"
+ << "textHeight"
+ << "textWidth"
+ << "this"
+ << "toggleHighQuality"
+ << "toLowerCase"
+ << "toString"
+ << "_totalframes"
+ << "toUpperCase"
+ << "trace"
+ << "trackAsMenu"
+ << "true"
+ << "type"
+ << "typeof"
+ << "undefined"
+ << "underline"
+ << "unescape"
+ << "uninstall"
+ << "unloadMovie"
+ << "unloadMovieNum"
+ << "unshift"
+ << "unwatch"
+ << "UP"
+ << "updateAfterEvent"
+ << "url"
+ << "_url"
+ << "useHandCursor"
+ << "UTC"
+ << "valueOf"
+ << "var"
+ << "variable"
+ << "_visible"
+ << "void"
+ << "watch"
+ << "while"
+ << "width"
+ << "_width"
+ << "with"
+ << "wordWrap"
+ << "_x"
+ << "XML"
+ << "xmlDecl"
+ << "XMLSocket"
+ << "_xmouse"
+ << "_xscale"
+ << "_y"
+ << "_ymouse";
+ }
+
+ return keywords;
+}
+
+#include "aswriter.moc"
diff --git a/umbrello/umbrello/codegenerators/aswriter.h b/umbrello/umbrello/codegenerators/aswriter.h
new file mode 100644
index 00000000..51a4a922
--- /dev/null
+++ b/umbrello/umbrello/codegenerators/aswriter.h
@@ -0,0 +1,80 @@
+/***************************************************************************
+ aswriter.h - description
+ -------------------
+ begin : Sat Feb 08 2003
+ copyright : (C) 2003 by Alexander Blum
+ email : blum@kewbee.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 ASWRITER_H
+#define ASWRITER_H
+
+#include "simplecodegenerator.h"
+#include "../umloperationlist.h"
+#include "../umlassociationlist.h"
+
+/**
+ * class ASWriter is a ActionScript code generator for UMLClassifier objects
+ * Just call writeClass and feed it a UMLClassifier;
+ */
+class ASWriter : public SimpleCodeGenerator {
+ Q_OBJECT
+public:
+
+ ASWriter();
+ virtual ~ASWriter();
+
+ /**
+ * call this method to generate Actionscript code for a UMLClassifier
+ * @param c the class you want to generate code for.
+ */
+ virtual void writeClass(UMLClassifier *c);
+
+ /**
+ * returns "ActionScript"
+ */
+ virtual Uml::Programming_Language getLanguage();
+
+ /**
+ * get list of reserved keywords
+ */
+ virtual const QStringList reservedKeywords() const;
+
+
+private:
+
+ /**
+ * we do not want to write the comment "Private methods" twice
+ */
+ bool bPrivateSectionCommentIsWritten;
+
+ /**
+ * write a list of class operations
+ *
+ * @param classname the name of the class
+ * @param opList the list of operations
+ * @param as output stream for the AS file
+ */
+ void writeOperations(QString classname, UMLOperationList *opList, QTextStream &as);
+
+ /**
+ * write a list of associations
+ *
+ * @param classname the name of the class
+ * @param assocList the list of associations
+ * @param as output stream for the AS file
+ */
+ void writeAssociation(QString& classname, UMLAssociationList& assoclist , QTextStream &as);
+
+};
+
+#endif //ASWRITER
diff --git a/umbrello/umbrello/codegenerators/classifierinfo.cpp b/umbrello/umbrello/codegenerators/classifierinfo.cpp
new file mode 100644
index 00000000..690238cf
--- /dev/null
+++ b/umbrello/umbrello/codegenerators/classifierinfo.cpp
@@ -0,0 +1,140 @@
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * copyright : (C) 2003 Brian Thomas brian.thomas@gsfc.nasa.gov *
+ * (C) 2004-2006 Umbrello UML Modeller Authors <uml-devel@uml.sf.net> *
+ ***************************************************************************/
+
+
+#include "classifierinfo.h"
+
+#include "../classifier.h"
+#include "../operation.h"
+
+ClassifierInfo::ClassifierInfo( UMLClassifier *classifier)
+{
+ classifier_ = classifier;
+
+ // set default class, file names
+ className = classifier->getName();
+ fileName = classifier->getName().lower();
+
+ // determine up-front what we are dealing with
+ isInterface = classifier->isInterface();
+
+ // sort attributes by Scope
+ if(!isInterface) {
+ UMLAttributeList atl = classifier->getAttributeList();
+ for(UMLAttribute *at=atl.first(); at ; at=atl.next()) {
+ switch(at->getVisibility())
+ {
+ case Uml::Visibility::Public:
+ if(at->getStatic())
+ static_atpub.append(at);
+ else
+ atpub.append(at);
+ break;
+ case Uml::Visibility::Protected:
+ if(at->getStatic())
+ static_atprot.append(at);
+ else
+ atprot.append(at);
+ break;
+ case Uml::Visibility::Private:
+ case Uml::Visibility::Implementation:
+ if(at->getStatic())
+ static_atpriv.append(at);
+ else
+ atpriv.append(at);
+ break;
+ }
+ }
+ }
+
+ // inheritance issues
+ superclasses = classifier->getSuperClasses(); // list of what we inherit from
+
+ subclasses = classifier->getSubClasses(); // list of what inherits from us
+
+ // another preparation, determine what we have
+ plainAssociations = classifier->getSpecificAssocs(Uml::at_Association); // BAD! only way to get "general" associations.
+
+ uniAssociations = classifier->getUniAssociationToBeImplemented();
+
+ aggregations = classifier->getAggregations();
+
+ compositions = classifier->getCompositions();
+
+ // set some summary information about the classifier now
+ hasAssociations = plainAssociations.count() > 0 || aggregations.count() > 0 || compositions.count() > 0 || uniAssociations.count() > 0;
+ hasAttributes = atpub.count() > 0 || atprot.count() > 0 || atpriv.count() > 0
+ || static_atpub.count() > 0
+ || static_atprot.count() > 0
+ || static_atpriv.count() > 0;
+
+ hasStaticAttributes = static_atpub.count() > 0
+ || static_atprot.count() > 0
+ || static_atpriv.count() > 0;
+
+ hasAccessorMethods = hasAttributes || hasAssociations;
+
+ hasOperationMethods = classifier->getOpList().last() ? true : false;
+
+ hasMethods = hasOperationMethods || hasAccessorMethods;
+
+ // this is a bit too simplistic..some associations are for
+ // SINGLE objects, and WONT be declared as Vectors, so this
+ // is a bit overly inclusive (I guess that's better than the other way around)
+ hasVectorFields = hasAssociations ? true : false;
+}
+
+ClassifierInfo::~ClassifierInfo() { }
+
+UMLClassifierList ClassifierInfo::getPlainAssocChildClassifierList()
+{
+ return findAssocClassifierObjsInRoles(&plainAssociations);
+}
+
+UMLClassifierList ClassifierInfo::getAggregateChildClassifierList()
+{
+ return findAssocClassifierObjsInRoles(&aggregations);
+}
+
+UMLClassifierList ClassifierInfo::getCompositionChildClassifierList()
+{
+ return findAssocClassifierObjsInRoles(&compositions);
+}
+
+UMLClassifierList ClassifierInfo::findAssocClassifierObjsInRoles (UMLAssociationList * list)
+{
+ UMLClassifierList classifiers;
+
+ for (UMLAssociation *a = list->first(); a; a = list->next()) {
+ // DONT accept a classifier IF the association role is empty, by
+ // convention, that means to ignore the classifier on that end of
+ // the association.
+ // We also ignore classifiers which are the same as the current one
+ // (e.g. id matches), we only want the "other" classifiers
+ if (a->getObjectId(Uml::A) == classifier_->getID() && !a->getRoleName(Uml::B).isEmpty()) {
+ UMLClassifier *c = dynamic_cast<UMLClassifier*>(a->getObject(Uml::B));
+ if(c)
+ classifiers.append(c);
+ } else if (a->getObjectId(Uml::B) == classifier_->getID() && !a->getRoleName(Uml::A).isEmpty()) {
+ UMLClassifier *c = dynamic_cast<UMLClassifier*>(a->getObject(Uml::A));
+ if(c)
+ classifiers.append(c);
+ }
+ }
+
+ return classifiers;
+}
+
+UMLAttributeList ClassifierInfo::getAttList()
+{
+ return classifier_->getAttributeList();
+}
+
diff --git a/umbrello/umbrello/codegenerators/classifierinfo.h b/umbrello/umbrello/codegenerators/classifierinfo.h
new file mode 100644
index 00000000..53b7c02b
--- /dev/null
+++ b/umbrello/umbrello/codegenerators/classifierinfo.h
@@ -0,0 +1,126 @@
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * copyright (C) 2003 Brian Thomas <brian.thomas@gsfc.nasa.gov> *
+ * copyright (C) 2004-2007 *
+ * Umbrello UML Modeller Authors <uml-devel@uml.sf.net> *
+ ***************************************************************************/
+
+#ifndef CLASSIFIERINFO_H
+#define CLASSIFIERINFO_H
+
+#include "../umldoc.h"
+#include "../attribute.h"
+#include "../association.h"
+#include "../umlclassifierlist.h"
+#include "../umlassociationlist.h"
+#include "../umlattributelist.h"
+
+#include <qstring.h>
+
+
+class UMLClassifier;
+
+
+/**
+ * class ClassInfo is an object to hold summary information about a classifier
+ * in a convenient form for easy access by a code generator.
+ */
+class ClassifierInfo {
+public:
+
+ /**
+ * Constructor, initialises a couple of variables
+ */
+ ClassifierInfo (UMLClassifier * classifier);
+
+ /**
+ * Destructor, empty
+ */
+ virtual ~ClassifierInfo();
+
+ // Fields
+ //
+
+ /**
+ * Lists of attributes of this classifier (if a class)
+ * Sorted by scope.
+ */
+ UMLAttributeList atpub;
+ UMLAttributeList atprot;
+ UMLAttributeList atpriv;
+
+ /**
+ * Lists of static attributes of this classifier (if a class)
+ */
+ UMLAttributeList static_atpub;
+ UMLAttributeList static_atprot;
+ UMLAttributeList static_atpriv;
+
+ /**
+ * Lists of types of associations this classifier has
+ */
+ UMLAssociationList plainAssociations;
+ UMLAssociationList uniAssociations;
+ UMLAssociationList aggregations;
+ UMLAssociationList compositions;
+
+ /**
+ * what sub and super classifiers are related to this class
+ */
+ UMLClassifierList superclasses;
+ UMLClassifierList subclasses;
+
+ /**
+ * Various conditional information about our classifier.
+ */
+ bool isInterface; // Whether or not this classifier is an interface.
+ bool hasAssociations;
+ bool hasAttributes;
+ bool hasStaticAttributes;
+ bool hasMethods;
+ bool hasAccessorMethods;
+ bool hasOperationMethods;
+ bool hasVectorFields;
+
+ /**
+ * Class and File names
+ */
+ QString className;
+ QString fileName;
+
+ /**
+ * utility functions to allow easy determination of what classifiers
+ * are "owned" by the current one via named association type (e.g.
+ * plain, aggregate or compositions).
+ */
+ UMLClassifierList getPlainAssocChildClassifierList();
+ UMLClassifierList getAggregateChildClassifierList();
+ UMLClassifierList getCompositionChildClassifierList();
+
+ /**
+ * Utility method to obtain list of attributes, if they exist, for
+ * the current classfier.
+ */
+ UMLAttributeList getAttList();
+
+private:
+
+ UMLClassifier* classifier_;
+
+ /**
+ * Utility method called by "get*ChildClassfierList()" methods. It basically
+ * finds all the classifiers named in each association in the given association list
+ * which arent the current one. Usefull for finding which classifiers are "owned" by the
+ * current one via declared associations such as in aggregations/compositions.
+ */
+ UMLClassifierList findAssocClassifierObjsInRoles (UMLAssociationList * list);
+
+};
+
+#endif // CLASSIFIERINFO_H
+
diff --git a/umbrello/umbrello/codegenerators/codegen_utils.cpp b/umbrello/umbrello/codegenerators/codegen_utils.cpp
new file mode 100644
index 00000000..cb94cdde
--- /dev/null
+++ b/umbrello/umbrello/codegenerators/codegen_utils.cpp
@@ -0,0 +1,413 @@
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * Copyright (C) 2004-2007 *
+ * Umbrello UML Modeller Authors <uml-devel@uml.sf.net> *
+ ***************************************************************************/
+
+// own header
+#include "codegen_utils.h"
+// app includes
+#include "../uml.h"
+#include "../umldoc.h"
+
+namespace Codegen_Utils {
+
+QStringList cppDatatypes() {
+ QStringList l;
+ l.append("int");
+ l.append("char");
+ l.append("bool");
+ l.append("float");
+ l.append("double");
+ l.append("short");
+ l.append("long");
+ l.append("unsigned int");
+ l.append("unsigned short");
+ l.append("unsigned long");
+ l.append("string");
+ return l;
+}
+
+const QStringList reservedCppKeywords() {
+
+ static QStringList keywords;
+
+ if (keywords.isEmpty()) {
+ keywords.append( "and" );
+ keywords.append( "and_eq" );
+ keywords.append( "__asm__" );
+ keywords.append( "asm" );
+ keywords.append( "__attribute__" );
+ keywords.append( "auto" );
+ keywords.append( "bitand" );
+ keywords.append( "bitor" );
+ keywords.append( "bool" );
+ keywords.append( "break" );
+ keywords.append( "BUFSIZ" );
+ keywords.append( "case" );
+ keywords.append( "catch" );
+ keywords.append( "char" );
+ keywords.append( "CHAR_BIT" );
+ keywords.append( "CHAR_MAX" );
+ keywords.append( "CHAR_MIN" );
+ keywords.append( "class" );
+ keywords.append( "CLOCKS_PER_SEC" );
+ keywords.append( "clock_t" );
+ keywords.append( "compl" );
+ keywords.append( "__complex__" );
+ keywords.append( "complex" );
+ keywords.append( "const" );
+ keywords.append( "const_cast" );
+ keywords.append( "continue" );
+ keywords.append( "__DATE__" );
+ keywords.append( "DBL_DIG" );
+ keywords.append( "DBL_EPSILON" );
+ keywords.append( "DBL_MANT_DIG" );
+ keywords.append( "DBL_MAX" );
+ keywords.append( "DBL_MAX_10_EXP" );
+ keywords.append( "DBL_MAX_EXP" );
+ keywords.append( "DBL_MIN" );
+ keywords.append( "DBL_MIN_10_EXP" );
+ keywords.append( "DBL_MIN_EXP" );
+ keywords.append( "default" );
+ keywords.append( "delete" );
+ keywords.append( "DIR" );
+ keywords.append( "div_t" );
+ keywords.append( "do" );
+ keywords.append( "double" );
+ keywords.append( "dynamic_cast" );
+ keywords.append( "E2BIG" );
+ keywords.append( "EACCES" );
+ keywords.append( "EAGAIN" );
+ keywords.append( "EBADF" );
+ keywords.append( "EBADMSG" );
+ keywords.append( "EBUSY" );
+ keywords.append( "ECANCELED" );
+ keywords.append( "ECHILD" );
+ keywords.append( "EDEADLK" );
+ keywords.append( "EDOM" );
+ keywords.append( "EEXIST" );
+ keywords.append( "EFAULT" );
+ keywords.append( "EFBIG" );
+ keywords.append( "EILSEQ" );
+ keywords.append( "EINPROGRESS" );
+ keywords.append( "EINTR" );
+ keywords.append( "EINVAL" );
+ keywords.append( "EIO" );
+ keywords.append( "EISDIR" );
+ keywords.append( "else" );
+ keywords.append( "EMFILE" );
+ keywords.append( "EMLINK" );
+ keywords.append( "EMSGSIZE" );
+ keywords.append( "ENAMETOOLONG" );
+ keywords.append( "ENFILE" );
+ keywords.append( "ENODEV" );
+ keywords.append( "ENOENT" );
+ keywords.append( "ENOEXEC" );
+ keywords.append( "ENOLCK" );
+ keywords.append( "ENOMEM" );
+ keywords.append( "ENOSPC" );
+ keywords.append( "ENOSYS" );
+ keywords.append( "ENOTDIR" );
+ keywords.append( "ENOTEMPTY" );
+ keywords.append( "ENOTSUP" );
+ keywords.append( "ENOTTY" );
+ keywords.append( "enum" );
+ keywords.append( "ENXIO" );
+ keywords.append( "EOF" );
+ keywords.append( "EPERM" );
+ keywords.append( "EPIPE" );
+ keywords.append( "ERANGE" );
+ keywords.append( "EROFS" );
+ keywords.append( "ESPIPE" );
+ keywords.append( "ESRCH" );
+ keywords.append( "ETIMEDOUT" );
+ keywords.append( "EXDEV" );
+ keywords.append( "EXIT_FAILURE" );
+ keywords.append( "EXIT_SUCCESS" );
+ keywords.append( "explicit" );
+ keywords.append( "export" );
+ keywords.append( "extern" );
+ keywords.append( "false" );
+ keywords.append( "__FILE__" );
+ keywords.append( "FILE" );
+ keywords.append( "FILENAME_MAX" );
+ keywords.append( "float" );
+ keywords.append( "FLT_DIG" );
+ keywords.append( "FLT_EPSILON" );
+ keywords.append( "FLT_MANT_DIG" );
+ keywords.append( "FLT_MAX" );
+ keywords.append( "FLT_MAX_10_EXP" );
+ keywords.append( "FLT_MAX_EXP" );
+ keywords.append( "FLT_MIN" );
+ keywords.append( "FLT_MIN_10_EXP" );
+ keywords.append( "FLT_MIN_EXP" );
+ keywords.append( "FLT_RADIX" );
+ keywords.append( "FLT_ROUNDS" );
+ keywords.append( "FOPEN_MAX" );
+ keywords.append( "for" );
+ keywords.append( "fpos_t" );
+ keywords.append( "friend" );
+ keywords.append( "__FUNCTION__" );
+ keywords.append( "__GNUC__" );
+ keywords.append( "goto" );
+ keywords.append( "HUGE_VAL" );
+ keywords.append( "if" );
+ keywords.append( "__imag__" );
+ keywords.append( "inline" );
+ keywords.append( "int" );
+ keywords.append( "INT16_MAX" );
+ keywords.append( "INT16_MIN" );
+ keywords.append( "int16_t" );
+ keywords.append( "INT32_MAX" );
+ keywords.append( "INT32_MIN" );
+ keywords.append( "int32_t" );
+ keywords.append( "INT64_MAX" );
+ keywords.append( "INT64_MIN" );
+ keywords.append( "int64_t" );
+ keywords.append( "INT8_MAX" );
+ keywords.append( "INT8_MIN" );
+ keywords.append( "int8_t" );
+ keywords.append( "INT_FAST16_MAX" );
+ keywords.append( "INT_FAST16_MIN" );
+ keywords.append( "int_fast16_t" );
+ keywords.append( "INT_FAST32_MAX" );
+ keywords.append( "INT_FAST32_MIN" );
+ keywords.append( "int_fast32_t" );
+ keywords.append( "INT_FAST64_MAX" );
+ keywords.append( "INT_FAST64_MIN" );
+ keywords.append( "int_fast64_t" );
+ keywords.append( "INT_FAST8_MAX" );
+ keywords.append( "INT_FAST8_MIN" );
+ keywords.append( "int_fast8_t" );
+ keywords.append( "INT_LEAST16_MAX" );
+ keywords.append( "INT_LEAST16_MIN" );
+ keywords.append( "int_least16_t" );
+ keywords.append( "INT_LEAST32_MAX" );
+ keywords.append( "INT_LEAST32_MIN" );
+ keywords.append( "int_least32_t" );
+ keywords.append( "INT_LEAST64_MAX" );
+ keywords.append( "INT_LEAST64_MIN" );
+ keywords.append( "int_least64_t" );
+ keywords.append( "INT_LEAST8_MAX" );
+ keywords.append( "INT_LEAST8_MIN" );
+ keywords.append( "int_least8_t" );
+ keywords.append( "INT_MAX" );
+ keywords.append( "INTMAX_MAX" );
+ keywords.append( "INTMAX_MIN" );
+ keywords.append( "intmax_t" );
+ keywords.append( "INT_MIN" );
+ keywords.append( "INTPTR_MAX" );
+ keywords.append( "INTPTR_MIN" );
+ keywords.append( "intptr_t" );
+ keywords.append( "_IOFBF" );
+ keywords.append( "_IOLBF" );
+ keywords.append( "_IONBF" );
+ keywords.append( "jmp_buf" );
+ keywords.append( "__label__" );
+ keywords.append( "LC_ALL" );
+ keywords.append( "LC_COLLATE" );
+ keywords.append( "LC_CTYPE" );
+ keywords.append( "LC_MONETARY" );
+ keywords.append( "LC_NUMERIC" );
+ keywords.append( "LC_TIME" );
+ keywords.append( "LDBL_DIG" );
+ keywords.append( "LDBL_EPSILON" );
+ keywords.append( "LDBL_MANT_DIG" );
+ keywords.append( "LDBL_MAX" );
+ keywords.append( "LDBL_MAX_10_EXP" );
+ keywords.append( "LDBL_MAX_EXP" );
+ keywords.append( "LDBL_MIN" );
+ keywords.append( "LDBL_MIN_10_EXP" );
+ keywords.append( "LDBL_MIN_EXP" );
+ keywords.append( "ldiv_t" );
+ keywords.append( "__LINE__" );
+ keywords.append( "LLONG_MAX" );
+ keywords.append( "long" );
+ keywords.append( "LONG_MAX" );
+ keywords.append( "LONG_MIN" );
+ keywords.append( "L_tmpnam" );
+ keywords.append( "M_1_PI" );
+ keywords.append( "M_2_PI" );
+ keywords.append( "M_2_SQRTPI" );
+ keywords.append( "MB_CUR_MAX" );
+ keywords.append( "MB_LEN_MAX" );
+ keywords.append( "mbstate_t" );
+ keywords.append( "M_E" );
+ keywords.append( "M_LN10" );
+ keywords.append( "M_LN2" );
+ keywords.append( "M_LOG10E" );
+ keywords.append( "M_LOG2E" );
+ keywords.append( "M_PI" );
+ keywords.append( "M_PI_2" );
+ keywords.append( "M_PI_4" );
+ keywords.append( "M_SQRT1_2" );
+ keywords.append( "M_SQRT2" );
+ keywords.append( "mutable" );
+ keywords.append( "namespace" );
+ keywords.append( "new" );
+ keywords.append( "not" );
+ keywords.append( "not_eq" );
+ keywords.append( "NPOS" );
+ keywords.append( "NULL" );
+ keywords.append( "operator" );
+ keywords.append( "or" );
+ keywords.append( "or_eq" );
+ keywords.append( "__PRETTY_FUNCTION__" );
+ keywords.append( "private" );
+ keywords.append( "protected" );
+ keywords.append( "PTRDIFF_MAX" );
+ keywords.append( "PTRDIFF_MIN" );
+ keywords.append( "ptrdiff_t" );
+ keywords.append( "public" );
+ keywords.append( "RAND_MAX" );
+ keywords.append( "__real__" );
+ keywords.append( "register" );
+ keywords.append( "reinterpret_cast" );
+ keywords.append( "restrict" );
+ keywords.append( "return" );
+ keywords.append( "SCHAR_MAX" );
+ keywords.append( "SCHAR_MIN" );
+ keywords.append( "SEEK_CUR" );
+ keywords.append( "SEEK_END" );
+ keywords.append( "SEEK_SET" );
+ keywords.append( "short" );
+ keywords.append( "SHRT_MAX" );
+ keywords.append( "SHRT_MIN" );
+ keywords.append( "SIGABRT" );
+ keywords.append( "SIGALRM" );
+ keywords.append( "SIG_ATOMIC_MAX" );
+ keywords.append( "SIG_ATOMIC_MIN" );
+ keywords.append( "sig_atomic_t" );
+ keywords.append( "SIGCHLD" );
+ keywords.append( "SIGCONT" );
+ keywords.append( "SIG_DFL" );
+ keywords.append( "SIG_ERR" );
+ keywords.append( "SIGFPE" );
+ keywords.append( "SIGHUP" );
+ keywords.append( "SIG_IGN" );
+ keywords.append( "SIGILL" );
+ keywords.append( "SIGINT" );
+ keywords.append( "SIGKILL" );
+ keywords.append( "signed" );
+ keywords.append( "SIGPIPE" );
+ keywords.append( "SIGQUIT" );
+ keywords.append( "SIGSEGV" );
+ keywords.append( "SIGSTOP" );
+ keywords.append( "SIGTERM" );
+ keywords.append( "SIGTRAP" );
+ keywords.append( "SIGTSTP" );
+ keywords.append( "SIGTTIN" );
+ keywords.append( "SIGTTOU" );
+ keywords.append( "SIGUSR1" );
+ keywords.append( "SIGUSR2" );
+ keywords.append( "SINT_MAX" );
+ keywords.append( "SINT_MIN" );
+ keywords.append( "SIZE_MAX" );
+ keywords.append( "sizeof" );
+ keywords.append( "size_t" );
+ keywords.append( "SLONG_MAX" );
+ keywords.append( "SLONG_MIN" );
+ keywords.append( "SSHRT_MAX" );
+ keywords.append( "SSHRT_MIN" );
+ keywords.append( "ssize_t" );
+ keywords.append( "static" );
+ keywords.append( "static_cast" );
+ keywords.append( "__STDC__" );
+ keywords.append( "__STDC_VERSION__" );
+ keywords.append( "stderr" );
+ keywords.append( "stdin" );
+ keywords.append( "stdout" );
+ keywords.append( "struct" );
+ keywords.append( "switch" );
+ keywords.append( "template" );
+ keywords.append( "this" );
+ keywords.append( "throw" );
+ keywords.append( "__TIME__" );
+ keywords.append( "time_t" );
+ keywords.append( "TMP_MAX" );
+ keywords.append( "true" );
+ keywords.append( "try" );
+ keywords.append( "typedef" );
+ keywords.append( "typeid" );
+ keywords.append( "typename" );
+ keywords.append( "typeof" );
+ keywords.append( "UCHAR_MAX" );
+ keywords.append( "UINT16_MAX" );
+ keywords.append( "uint16_t" );
+ keywords.append( "UINT32_MAX" );
+ keywords.append( "uint32_t" );
+ keywords.append( "UINT64_MAX" );
+ keywords.append( "uint64_t" );
+ keywords.append( "UINT8_MAX" );
+ keywords.append( "uint8_t" );
+ keywords.append( "UINT_FAST16_MAX" );
+ keywords.append( "uint_fast16_t" );
+ keywords.append( "UINT_FAST32_MAX" );
+ keywords.append( "uint_fast32_t" );
+ keywords.append( "UINT_FAST64_MAX" );
+ keywords.append( "uint_fast64_t" );
+ keywords.append( "UINT_FAST8_MAX" );
+ keywords.append( "uint_fast8_t" );
+ keywords.append( "UINT_LEAST16_MAX" );
+ keywords.append( "uint_least16_t" );
+ keywords.append( "UINT_LEAST32_MAX" );
+ keywords.append( "uint_least32_t" );
+ keywords.append( "UINT_LEAST64_MAX" );
+ keywords.append( "uint_least64_t" );
+ keywords.append( "UINT_LEAST8_MAX" );
+ keywords.append( "uint_least8_t" );
+ keywords.append( "UINT_MAX" );
+ keywords.append( "UINTMAX_MAX" );
+ keywords.append( "uintmax_t" );
+ keywords.append( "UINTPTR_MAX" );
+ keywords.append( "uintptr_t" );
+ keywords.append( "ULLONG_MAX" );
+ keywords.append( "ULONG_MAX" );
+ keywords.append( "union" );
+ keywords.append( "unsigned" );
+ keywords.append( "USHRT_MAX" );
+ keywords.append( "using" );
+ keywords.append( "va_list" );
+ keywords.append( "virtual" );
+ keywords.append( "void" );
+ keywords.append( "__volatile__" );
+ keywords.append( "volatile" );
+ keywords.append( "WCHAR_MAX" );
+ keywords.append( "WCHAR_MIN" );
+ keywords.append( "wchar_t" );
+ keywords.append( "wctrans_t" );
+ keywords.append( "wctype_t" );
+ keywords.append( "WEOF" );
+ keywords.append( "while" );
+ keywords.append( "WINT_MAX" );
+ keywords.append( "WINT_MIN" );
+ keywords.append( "wint_t" );
+ keywords.append( "xor" );
+ keywords.append( "xor_eq" );
+ }
+
+ return keywords;
+}
+
+void createCppStereotypes() {
+ UMLDoc *umldoc = UMLApp::app()->getDocument();
+ umldoc->findOrCreateStereotype("constructor");
+ // declares an operation as friend
+ umldoc->findOrCreateStereotype("friend");
+ // to use in methods that aren't abstract
+ umldoc->findOrCreateStereotype("virtual");
+}
+
+QString capitalizeFirstLetter(const QString &string) {
+ QChar firstChar = string.at(0);
+ return firstChar.upper() + string.mid(1);
+}
+
+} // end namespace Codegen_Utils
+
diff --git a/umbrello/umbrello/codegenerators/codegen_utils.h b/umbrello/umbrello/codegenerators/codegen_utils.h
new file mode 100644
index 00000000..aaa7d117
--- /dev/null
+++ b/umbrello/umbrello/codegenerators/codegen_utils.h
@@ -0,0 +1,42 @@
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * copyright (C) 2004-2007 *
+ * Umbrello UML Modeller Authors <uml-devel@uml.sf.net> *
+ ***************************************************************************/
+
+#ifndef CODEGEN_UTILS_H
+#define CODEGEN_UTILS_H
+
+#include <qstringlist.h>
+
+namespace Codegen_Utils {
+
+/**
+ * Return list of C++ datatypes
+ */
+QStringList cppDatatypes();
+
+/**
+ * Get list of C++ reserved keywords
+ */
+const QStringList reservedCppKeywords();
+
+/**
+ * Add C++ stereotypes
+ */
+void createCppStereotypes();
+
+/**
+ * Return the input string with the first letter capitalized.
+ */
+QString capitalizeFirstLetter(const QString &string);
+
+}
+
+#endif // CODEGEN_UTILS_H
+
diff --git a/umbrello/umbrello/codegenerators/codegenfactory.cpp b/umbrello/umbrello/codegenerators/codegenfactory.cpp
new file mode 100644
index 00000000..00401653
--- /dev/null
+++ b/umbrello/umbrello/codegenerators/codegenfactory.cpp
@@ -0,0 +1,360 @@
+/***************************************************************************
+ begin : Mon Jun 17 2002
+ copyright : (C) 2002 Luis De la Parra Blum <luis@delaparra.org>
+ and Brian Thomas
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * copyright (C) 2003-2007 *
+ * Umbrello UML Modeller Authors <uml-devel@uml.sf.net> *
+ ***************************************************************************/
+
+// own header
+#include "codegenfactory.h"
+
+// qt/kde includes
+#include <kdebug.h>
+
+// app includes
+#include "../codegenerator.h"
+#include "../umldoc.h"
+#include "../uml.h"
+#include "../optionstate.h"
+#include "../operation.h"
+#include "../attribute.h"
+#include "../umlrole.h"
+
+#include "adawriter.h"
+#include "cppwriter.h"
+#include "csharpwriter.h"
+#include "dwriter.h"
+#include "idlwriter.h"
+#include "javawriter.h"
+#include "pascalwriter.h"
+#include "perlwriter.h"
+#include "phpwriter.h"
+#include "php5writer.h"
+#include "pythonwriter.h"
+#include "rubywriter.h"
+#include "sqlwriter.h"
+#include "aswriter.h"
+#include "jswriter.h"
+#include "tclwriter.h"
+#include "xmlschemawriter.h"
+
+// the new
+#include "cppcodegenerator.h"
+#include "javacodegenerator.h"
+#include "rubycodegenerator.h"
+
+#include "cppheadercodedocument.h"
+#include "cppsourcecodedocument.h"
+#include "javaclassifiercodedocument.h"
+#include "rubyclassifiercodedocument.h"
+#include "javaantcodedocument.h"
+
+#include "cppheadercodeoperation.h"
+#include "cppsourcecodeoperation.h"
+#include "javacodeoperation.h"
+#include "rubycodeoperation.h"
+
+#include "cppcodeclassfield.h"
+#include "javacodeclassfield.h"
+#include "rubycodeclassfield.h"
+
+#include "cppheadercodeaccessormethod.h"
+#include "cppsourcecodeaccessormethod.h"
+#include "javacodeaccessormethod.h"
+#include "rubycodeaccessormethod.h"
+
+#include "cppheadercodeclassfielddeclarationblock.h"
+#include "cppsourcecodeclassfielddeclarationblock.h"
+#include "javacodeclassfielddeclarationblock.h"
+#include "rubycodeclassfielddeclarationblock.h"
+
+#include "cppcodedocumentation.h"
+#include "javacodecomment.h"
+#include "rubycodecomment.h"
+#include "xmlcodecomment.h"
+
+#include "cppcodegenerationpolicy.h"
+#include "javacodegenerationpolicy.h"
+#include "rubycodegenerationpolicy.h"
+
+namespace CodeGenFactory {
+
+CodeGenerator* createObject(Uml::Programming_Language pl) {
+ CodeGenerator* obj = 0;
+ Settings::OptionState optionState = Settings::getOptionState();
+ UMLApp::app()->setPolicyExt(NULL);
+ switch (pl) {
+ case Uml::pl_Ada:
+ obj = new AdaWriter();
+ break;
+ case Uml::pl_ActionScript:
+ obj = new ASWriter();
+ break;
+ case Uml::pl_Cpp:
+ if (optionState.generalState.newcodegen) {
+ obj = new CPPCodeGenerator();
+ obj->connect_newcodegen_slots();
+ } else {
+ obj = new CppWriter();
+ }
+ {
+ CPPCodeGenerationPolicy *p =
+ new CPPCodeGenerationPolicy(UMLApp::app()->getConfig());
+ UMLApp::app()->setPolicyExt(p);
+ }
+ break;
+ case Uml::pl_CSharp:
+ obj = new CSharpWriter();
+ break;
+ case Uml::pl_D:
+ obj = new DWriter();
+ break;
+ case Uml::pl_IDL:
+ obj = new IDLWriter();
+ break;
+ case Uml::pl_Java:
+ if (optionState.generalState.newcodegen) {
+ obj = new JavaCodeGenerator();
+ obj->connect_newcodegen_slots();
+ JavaCodeGenerationPolicy *p =
+ new JavaCodeGenerationPolicy(UMLApp::app()->getConfig());
+ UMLApp::app()->setPolicyExt(p);
+ } else
+ obj = new JavaWriter();
+ break;
+ case Uml::pl_JavaScript:
+ obj = new JSWriter();
+ break;
+ case Uml::pl_PHP:
+ obj = new PhpWriter();
+ break;
+ case Uml::pl_PHP5:
+ obj = new Php5Writer();
+ break;
+ case Uml::pl_Pascal:
+ obj = new PascalWriter();
+ break;
+ case Uml::pl_Perl:
+ obj = new PerlWriter();
+ break;
+ case Uml::pl_Python:
+ obj = new PythonWriter();
+ break;
+ case Uml::pl_Ruby:
+ if (optionState.generalState.newcodegen) {
+ obj = new RubyCodeGenerator();
+ obj->connect_newcodegen_slots();
+ RubyCodeGenerationPolicy *p =
+ new RubyCodeGenerationPolicy(UMLApp::app()->getConfig());
+ UMLApp::app()->setPolicyExt(p);
+ } else
+ obj = new RubyWriter();
+ break;
+ case Uml::pl_SQL:
+ obj = new SQLWriter();
+ break;
+ case Uml::pl_Tcl:
+ obj = new TclWriter();
+ break;
+ case Uml::pl_XMLSchema:
+ obj = new XMLSchemaWriter();
+ break;
+ default:
+ kWarning() << "cannot create object of type " << pl
+ << ". Type unknown" << endl;
+ break;
+ }
+ if (obj)
+ obj->initFromParentDocument();
+ return obj;
+}
+
+CodeDocument * newClassifierCodeDocument (UMLClassifier * c)
+{
+ Settings::OptionState optionState = Settings::getOptionState();
+ if (!optionState.generalState.newcodegen)
+ return NULL;
+ ClassifierCodeDocument *retval = NULL;
+ switch (UMLApp::app()->getActiveLanguage()) {
+ case Uml::pl_Cpp:
+ retval = new CPPSourceCodeDocument(c);
+ break;
+ case Uml::pl_Java:
+ retval = new JavaClassifierCodeDocument(c);
+ break;
+ case Uml::pl_Ruby:
+ retval = new RubyClassifierCodeDocument(c);
+ break;
+ default:
+ break;
+ }
+ retval->initCodeClassFields();
+ retval->synchronize();
+ return retval;
+}
+
+CodeOperation *newCodeOperation(ClassifierCodeDocument *ccd, UMLOperation * op) {
+ CodeOperation *retval = NULL;
+ switch (UMLApp::app()->getActiveLanguage()) {
+ case Uml::pl_Cpp:
+ {
+ CPPHeaderCodeDocument *hcd = dynamic_cast<CPPHeaderCodeDocument*>(ccd);
+ if (hcd)
+ return new CPPHeaderCodeOperation(hcd, op);
+ CPPSourceCodeDocument *scd = dynamic_cast<CPPSourceCodeDocument*>(ccd);
+ if (scd)
+ return new CPPSourceCodeOperation(scd, op);
+ }
+ break;
+ case Uml::pl_Java:
+ retval = new JavaCodeOperation(dynamic_cast<JavaClassifierCodeDocument*>(ccd), op);
+ break;
+ case Uml::pl_Ruby:
+ retval = new RubyCodeOperation(dynamic_cast<RubyClassifierCodeDocument*>(ccd), op);
+ break;
+ default:
+ break;
+ }
+ return retval;
+}
+
+
+CodeClassField * newCodeClassField(ClassifierCodeDocument *ccd, UMLAttribute *at) {
+ CodeClassField *retval = NULL;
+ switch (UMLApp::app()->getActiveLanguage()) {
+ case Uml::pl_Cpp:
+ retval = new CPPCodeClassField(ccd, at);
+ break;
+ case Uml::pl_Java:
+ retval = new JavaCodeClassField(ccd, at);
+ break;
+ case Uml::pl_Ruby:
+ retval = new RubyCodeClassField(ccd, at);
+ break;
+ default:
+ break;
+ }
+ retval->finishInitialization();
+ return retval;
+}
+
+CodeClassField * newCodeClassField(ClassifierCodeDocument *ccd, UMLRole *role) {
+ CodeClassField *retval = NULL;
+ switch (UMLApp::app()->getActiveLanguage()) {
+ case Uml::pl_Cpp:
+ retval = new CPPCodeClassField(ccd, role);
+ break;
+ case Uml::pl_Java:
+ retval = new JavaCodeClassField(ccd, role);
+ break;
+ case Uml::pl_Ruby:
+ retval = new RubyCodeClassField(ccd, role);
+ break;
+ default:
+ break;
+ }
+ return retval;
+}
+
+CodeAccessorMethod * newCodeAccessorMethod(ClassifierCodeDocument *ccd,
+ CodeClassField *cf,
+ CodeAccessorMethod::AccessorType type) {
+ CodeAccessorMethod *retval = NULL;
+ switch (UMLApp::app()->getActiveLanguage()) {
+ case Uml::pl_Cpp:
+ {
+ CPPHeaderCodeDocument *hcd = dynamic_cast<CPPHeaderCodeDocument*>(ccd);
+ if (hcd) {
+ CPPHeaderCodeAccessorMethod *chcam = new CPPHeaderCodeAccessorMethod(cf, type);
+ chcam->update();
+ retval = chcam;
+ } else {
+ CPPSourceCodeAccessorMethod *cscam = new CPPSourceCodeAccessorMethod(cf, type);
+ cscam->update();
+ retval = cscam;
+ }
+ }
+ break;
+ case Uml::pl_Java:
+ {
+ JavaCodeAccessorMethod *jcam = new JavaCodeAccessorMethod(cf, type);
+ jcam->update();
+ retval = jcam;
+ retval->setOverallIndentationLevel(1);
+ }
+ break;
+ case Uml::pl_Ruby:
+ {
+ RubyCodeAccessorMethod *rcam = new RubyCodeAccessorMethod(cf, type);
+ rcam->update();
+ retval = rcam;
+ retval->setOverallIndentationLevel(1);
+ }
+ break;
+ default:
+ break;
+ }
+ return retval;
+}
+
+CodeClassFieldDeclarationBlock * newDeclarationCodeBlock (ClassifierCodeDocument *cd,
+ CodeClassField * cf) {
+ CodeClassFieldDeclarationBlock *retval = NULL;
+ switch (UMLApp::app()->getActiveLanguage()) {
+ case Uml::pl_Cpp:
+ {
+ CPPHeaderCodeDocument *hcd = dynamic_cast<CPPHeaderCodeDocument*>(cd);
+ if (hcd)
+ return new CPPHeaderCodeClassFieldDeclarationBlock(cf);
+ CPPSourceCodeDocument *scd = dynamic_cast<CPPSourceCodeDocument*>(cd);
+ if (scd)
+ return new CPPSourceCodeClassFieldDeclarationBlock(cf);
+ }
+ break;
+ case Uml::pl_Java:
+ retval = new JavaCodeClassFieldDeclarationBlock(cf);
+ break;
+ case Uml::pl_Ruby:
+ retval = new RubyCodeClassFieldDeclarationBlock(cf);
+ break;
+ default:
+ break;
+ }
+ return retval;
+}
+
+CodeComment * newCodeComment (CodeDocument *cd) {
+ switch (UMLApp::app()->getActiveLanguage()) {
+ case Uml::pl_Cpp:
+ if (dynamic_cast<CPPHeaderCodeDocument*>(cd) ||
+ dynamic_cast<CPPSourceCodeDocument*>(cd))
+ return new CPPCodeDocumentation(cd);
+ break;
+ case Uml::pl_Java:
+ if (dynamic_cast<JavaClassifierCodeDocument*>(cd))
+ return new JavaCodeComment(cd);
+ break;
+ case Uml::pl_Ruby:
+ if (dynamic_cast<RubyClassifierCodeDocument*>(cd))
+ return new RubyCodeComment(cd);
+ break;
+ default:
+ break;
+ }
+ if (dynamic_cast<JavaANTCodeDocument*>(cd))
+ return new XMLCodeComment(cd);
+ return new CodeComment(cd);
+}
+
+} // end namespace CodeGenFactory
+
diff --git a/umbrello/umbrello/codegenerators/codegenfactory.h b/umbrello/umbrello/codegenerators/codegenfactory.h
new file mode 100644
index 00000000..27a0f293
--- /dev/null
+++ b/umbrello/umbrello/codegenerators/codegenfactory.h
@@ -0,0 +1,119 @@
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * copyright (C) 2004-2006 *
+ * Umbrello UML Modeller Authors <uml-devel@uml.sf.net> *
+ ***************************************************************************/
+
+#ifndef CODEGENFACTORY_H
+#define CODEGENFACTORY_H
+
+#include "../umlnamespace.h"
+#include "../codeaccessormethod.h"
+
+// fwd decls
+class CodeGenerator;
+class ClassifierCodeDocument;
+class CodeOperation;
+class CodeClassField;
+class CodeClassFieldDeclarationBlock;
+class UMLClassifier;
+class UMLOperation;
+class UMLAttribute;
+class UMLRole;
+
+/**
+ * CodeGenFactory allows creating the available code generators as well
+ * as the auxiliary objects required for the advanced code generators.
+ *
+ * @author Jonathan Riddell
+ * @author Oliver Kellogg <okellogg@users.sourceforge.net>
+ * Bugs and comments to uml-devel@lists.sf.net or http://bugs.kde.org
+ */
+namespace CodeGenFactory {
+
+ /**
+ * Create a code generator specific to the given language.
+ */
+ CodeGenerator* createObject(Uml::Programming_Language pl);
+
+
+ /**
+ * Create a CodeOperation belonging to the given ClassifierCodeDocument.
+ * Only applies to the advanced generators.
+ *
+ * @param cd the parent ClassifierCodeDocument.
+ * @param op the related UMLOperation
+ * @return CodeOperation which is specific to the current language
+ */
+ CodeOperation *newCodeOperation(ClassifierCodeDocument *cd, UMLOperation * op);
+
+ /**
+ * Create an attribute CodeClassField belonging to the given
+ * ClassifierCodeDocument.
+ * Only applies to the advanced generators.
+ *
+ * @param cd the parent ClassifierCodeDocument
+ * @param at attribute which is parent of this class field
+ * @return CodeClassField which is specific to the current language
+ */
+ CodeClassField * newCodeClassField (ClassifierCodeDocument *cd, UMLAttribute * at);
+
+ /**
+ * Create an association role CodeClassField belonging to the given
+ * ClassifierCodeDocument.
+ * Only applies to the advanced generators.
+ *
+ * @param cd the parent ClassifierCodeDocument
+ * @param role association role which is parent of this class field
+ * @return CodeClassField which is specific to the current language
+ */
+ CodeClassField * newCodeClassField(ClassifierCodeDocument *cd, UMLRole *role);
+
+ /**
+ * Create a CodeAccessorMethod object belonging to the given ClassifierCodeDocument.
+ * Only applies to the advanced generators.
+ *
+ * @param cd the parent ClassifierCodeDocument
+ * @param cf CodeClassField which is parent of this object
+ * @param type CodeAccessorMethod::AccessorType to create
+ *
+ * @return CodeAccessorMethod which is specific to the current language
+ */
+ CodeAccessorMethod * newCodeAccessorMethod(ClassifierCodeDocument *cd,
+ CodeClassField *cf,
+ CodeAccessorMethod::AccessorType type);
+
+ /**
+ * Create a CodeClassFieldDeclarationBlock object belonging to the given
+ * ClassifierCodeDocument.
+ * Only applies to the advanced generators.
+ *
+ * @param cd the parent ClassifierCodeDocument
+ * @param cf CodeClassField which is parent of this object
+ *
+ * @return CodeClassFieldDeclarationBlock which is specific to the current language
+ */
+ CodeClassFieldDeclarationBlock * newDeclarationCodeBlock (ClassifierCodeDocument *cd,
+ CodeClassField * cf);
+
+ /**
+ * Create a new CodeComment object belonging to the given CodeDocument.
+ * Only applies to the advanced generators.
+ *
+ * @param cd the parent CodeDocument
+ * @return CodeBlockWithComments
+ */
+ CodeComment * newCodeComment (CodeDocument *cd);
+
+ /**
+ * Currently unused (for possible future use)
+ */
+ CodeDocument * newClassifierCodeDocument (UMLClassifier * classifier);
+}
+
+#endif //CODEGENFACTORY_H
diff --git a/umbrello/umbrello/codegenerators/codegenpolicyext.h b/umbrello/umbrello/codegenerators/codegenpolicyext.h
new file mode 100644
index 00000000..97ace9f2
--- /dev/null
+++ b/umbrello/umbrello/codegenerators/codegenpolicyext.h
@@ -0,0 +1,52 @@
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * copyright (C) 2006 *
+ * Umbrello UML Modeller Authors <uml-devel@uml.sf.net> *
+ ***************************************************************************/
+
+#ifndef CODEGENPOLICYEXT_H
+#define CODEGENPOLICYEXT_H
+
+#include <qobject.h>
+
+class QWidget;
+class KConfig;
+class CodeGenerationPolicyPage;
+
+/**
+ * Base class for programming language specific code generation policy extensions.
+ * Not to be confused with CodeGenerationPolicy which contains the programming
+ * language independent policies.
+ *
+ * @author Oliver Kellogg <okellogg@users.sourceforge.net>
+ * Bugs and comments to uml-devel@lists.sf.net or http://bugs.kde.org
+ */
+
+class CodeGenPolicyExt : public QObject {
+public:
+ CodeGenPolicyExt() {}
+ virtual ~CodeGenPolicyExt() {}
+
+ /**
+ * Create a new dialog interface for this object.
+ * @return dialog object
+ */
+ virtual CodeGenerationPolicyPage * createPage(QWidget *parent = 0, const char *name = 0) = 0;
+
+ /**
+ * set the defaults from a config file for this code generator from the passed KConfig pointer.
+ */
+ virtual void setDefaults(KConfig * config, bool emitUpdateSignal = true) = 0;
+
+ /**
+ * write Default params to passed KConfig pointer.
+ */
+ virtual void writeConfig (KConfig * config) = 0;
+};
+
+#endif
diff --git a/umbrello/umbrello/codegenerators/cppcodeclassfield.cpp b/umbrello/umbrello/codegenerators/cppcodeclassfield.cpp
new file mode 100644
index 00000000..b6b2fb72
--- /dev/null
+++ b/umbrello/umbrello/codegenerators/cppcodeclassfield.cpp
@@ -0,0 +1,108 @@
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * copyright (C) 2004-2007 *
+ * Umbrello UML Modeller Authors <uml-devel@uml.sf.net> *
+ ***************************************************************************/
+
+/* This code generated by:
+ * Author : thomas
+ * Date : Mon Sep 1 2003
+ */
+
+// own header
+#include "cppcodeclassfield.h"
+
+// qt/kde includes
+#include <kdebug.h>
+
+// local includes
+#include "../codegenerator.h"
+#include "../classifiercodedocument.h"
+#include "../attribute.h"
+#include "../umlobject.h"
+#include "../umlrole.h"
+#include "../uml.h"
+#include "cppcodegenerationpolicy.h"
+
+
+// Constructors/Destructors
+//
+
+CPPCodeClassField::CPPCodeClassField (ClassifierCodeDocument * parentDoc, UMLRole * role)
+ : CodeClassField(parentDoc, role)
+{
+
+}
+
+CPPCodeClassField::CPPCodeClassField (ClassifierCodeDocument * parentDoc, UMLAttribute * attrib)
+ : CodeClassField(parentDoc, attrib)
+{
+
+}
+
+CPPCodeClassField::~CPPCodeClassField ( ) { }
+
+//
+// Methods
+//
+
+// Other methods
+//
+
+QString CPPCodeClassField::getFieldName() {
+ if (parentIsAttribute())
+ {
+ UMLAttribute * at = (UMLAttribute*) getParentObject();
+ return cleanName(at->getName());
+ }
+ else
+ {
+ UMLRole * role = (UMLRole*) getParentObject();
+ QString roleName = role->getName();
+ if(fieldIsSingleValue()) {
+ return roleName.replace(0, 1, roleName.left(1).lower());
+ } else {
+ return roleName.lower() + "Vector";
+ }
+ }
+}
+
+QString CPPCodeClassField::getListFieldClassName () {
+ CodeGenPolicyExt * p = UMLApp::app()->getPolicyExt();
+ CPPCodeGenerationPolicy *policy = dynamic_cast<CPPCodeGenerationPolicy*>(p);
+ return policy->getVectorClassName();
+}
+
+QString CPPCodeClassField::getInitialValue() {
+
+ if (parentIsAttribute())
+ {
+ UMLAttribute * at = dynamic_cast<UMLAttribute*>( getParentObject() );
+ if (at) {
+ return fixInitialStringDeclValue(at->getInitialValue(), getTypeName());
+ } else {
+ kError() << "CPPCodeClassField::getInitialValue: parent object is not a UMLAttribute"
+ << endl;
+ return "";
+ }
+ }
+ else
+ {
+ if(fieldIsSingleValue()) {
+ // FIX : IF the multiplicity is "1" then we should init a new object here, if its 0 or 1,
+ // then we can just return 'empty' string (minor problem).
+ return "";
+ } else {
+ return " new "+getListFieldClassName()+"( )";
+ }
+ }
+
+}
+
+
+#include "cppcodeclassfield.moc"
diff --git a/umbrello/umbrello/codegenerators/cppcodeclassfield.h b/umbrello/umbrello/codegenerators/cppcodeclassfield.h
new file mode 100644
index 00000000..d9c20255
--- /dev/null
+++ b/umbrello/umbrello/codegenerators/cppcodeclassfield.h
@@ -0,0 +1,62 @@
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * copyright (C) 2004-2006 *
+ * Umbrello UML Modeller Authors <uml-devel@uml.sf.net> *
+ ***************************************************************************/
+
+/* This code generated by:
+ * Author : thomas
+ * Date : Mon Sep 1 2003
+ */
+
+
+
+#ifndef CPPCODECLASSFIELD_H
+#define CPPCODECLASSFIELD_H
+
+#include <qstring.h>
+
+#include "../codeclassfield.h"
+
+class ClassifierCodeDocument;
+
+class CPPCodeClassField : public CodeClassField
+{
+ Q_OBJECT
+public:
+
+ // Constructors/Destructors
+ //
+
+ /**
+ * Constructors
+ */
+ CPPCodeClassField (ClassifierCodeDocument * parentDoc, UMLRole * role);
+ CPPCodeClassField (ClassifierCodeDocument * parentDoc, UMLAttribute * attrib);
+
+ /**
+ * Empty Destructor
+ */
+ virtual ~CPPCodeClassField ( );
+
+ QString getFieldType();
+ QString getFieldName();
+ QString getInitialValue();
+ /** get the name of the class which holds lists, e.g. "QPtrlist" or
+ * "Vector" or "List" and so on.
+ */
+ QString getListFieldClassName();
+
+
+protected:
+
+private:
+
+};
+
+#endif // CPPCODECLASSFIELD_H
diff --git a/umbrello/umbrello/codegenerators/cppcodecomment.cpp b/umbrello/umbrello/codegenerators/cppcodecomment.cpp
new file mode 100644
index 00000000..8d480e93
--- /dev/null
+++ b/umbrello/umbrello/codegenerators/cppcodecomment.cpp
@@ -0,0 +1,98 @@
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * copyright (C) 2004-2007 *
+ * Umbrello UML Modeller Authors <uml-devel@uml.sf.net> *
+ ***************************************************************************/
+
+/* This code generated by:
+ * Author : thomas
+ * Date : Mon Sep 1 2003
+ */
+
+// own header
+#include "cppcodecomment.h"
+
+// qt/kde includes
+#include <qregexp.h>
+
+// Constructors/Destructors
+//
+
+CPPCodeComment::CPPCodeComment ( CodeDocument * doc, const QString & text )
+ : CodeComment (doc, text)
+{
+
+}
+
+CPPCodeComment::~CPPCodeComment ( ) { }
+
+//
+// Methods
+//
+
+
+// Accessor methods
+//
+
+
+// Public attribute accessor methods
+//
+
+// Other methods
+//
+
+/**
+ * Save the XMI representation of this object
+ */
+void CPPCodeComment::saveToXMI ( QDomDocument & doc, QDomElement & root ) {
+ QDomElement blockElement = doc.createElement( "cppcodecomment" );
+ setAttributesOnNode(doc, blockElement); // as we added no additional fields to this class we may
+ // just use parent TextBlock method
+ root.appendChild( blockElement );
+}
+
+/**
+ * @return QString
+ */
+QString CPPCodeComment::toString ( )
+{
+
+ QString output = "";
+
+ // simple output method
+ if(getWriteOutText())
+ {
+ QString indent = getIndentationString();
+ QString endLine = getNewLineEndingChars();
+ output.append(formatMultiLineText (getText()+endLine, indent +"// ", endLine));
+ }
+
+ return output;
+}
+
+QString CPPCodeComment::getNewEditorLine ( int amount ) {
+ QString line = getIndentationString(amount) + "// ";
+ return line;
+}
+
+/** UnFormat a long text string. Typically, this means removing
+ * the indentaion (linePrefix) and/or newline chars from each line.
+ */
+QString CPPCodeComment::unformatText ( const QString & text , const QString & indent)
+{
+
+ // remove leading or trailing comment stuff
+ QString mytext = TextBlock::unformatText(text, indent);
+
+ // now leading slashes
+ mytext.remove(QRegExp("^\\/\\/\\s*"));
+ return mytext;
+}
+
+#include "cppcodecomment.moc"
diff --git a/umbrello/umbrello/codegenerators/cppcodecomment.h b/umbrello/umbrello/codegenerators/cppcodecomment.h
new file mode 100644
index 00000000..085e1a7f
--- /dev/null
+++ b/umbrello/umbrello/codegenerators/cppcodecomment.h
@@ -0,0 +1,83 @@
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the 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 code generated by:
+ * Author : thomas
+ * Date : Mon Sep 1 2003
+ */
+
+
+
+#ifndef CPPCODECOMMENT_H
+#define CPPCODECOMMENT_H
+
+#include <qstring.h>
+#include "../codecomment.h"
+
+/**
+ * class CPPCodeComment
+ * A CPP code comment. There is only a single styles of comments:
+ * these are simply started with double slash sequence and no terminating
+ * characters
+ */
+
+class CPPCodeComment : virtual public CodeComment
+{
+ Q_OBJECT
+public:
+
+ // Constructors/Destructors
+ //
+
+
+ /**
+ * Constructors
+ */
+ explicit CPPCodeComment ( CodeDocument * doc, const QString & text = "");
+
+ /**
+ * Empty Destructor
+ */
+ virtual ~CPPCodeComment ( );
+
+ // Public attributes
+ //
+
+
+ // other
+
+ /**
+ * Save the XMI representation of this object
+ */
+ virtual void saveToXMI ( QDomDocument & doc, QDomElement & root );
+
+ /**
+ * @return QString
+ */
+ QString toString ( );
+
+
+ /** UnFormat a long text string. Typically, this means removing
+ * the indentaion (linePrefix) and/or newline chars from each line.
+ */
+ virtual QString unformatText ( const QString & text, const QString & indent = "" );
+
+ /** a special version here because we want to not only indent
+ * the new line, but to add the "//" sequence as well.
+ */
+ virtual QString getNewEditorLine ( int amount );
+
+protected:
+
+private:
+
+};
+
+#endif // CPPCODECOMMENT_H
diff --git a/umbrello/umbrello/codegenerators/cppcodedocumentation.cpp b/umbrello/umbrello/codegenerators/cppcodedocumentation.cpp
new file mode 100644
index 00000000..833e648e
--- /dev/null
+++ b/umbrello/umbrello/codegenerators/cppcodedocumentation.cpp
@@ -0,0 +1,141 @@
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * copyright (C) 2004-2006 *
+ * Umbrello UML Modeller Authors <uml-devel@uml.sf.net> *
+ ***************************************************************************/
+
+/* This code generated by:
+ * Author : thomas
+ * Date : Mon Jun 23 2003
+ */
+
+// own header
+#include "cppcodedocumentation.h"
+// qt/kde includes
+#include <qregexp.h>
+#include <kdebug.h>
+// app includes
+#include "../codedocument.h"
+#include "../codegenerator.h"
+#include "../codegenerationpolicy.h"
+#include "../uml.h"
+
+// Constructors/Destructors
+//
+
+CPPCodeDocumentation::CPPCodeDocumentation ( CodeDocument * doc, const QString & text )
+ : CodeComment (doc, text)
+{
+
+}
+
+CPPCodeDocumentation::~CPPCodeDocumentation ( ) { }
+
+//
+// Methods
+//
+
+
+// Accessor methods
+//
+
+// Other methods
+//
+
+/**
+ * Save the XMI representation of this object
+ */
+void CPPCodeDocumentation::saveToXMI ( QDomDocument & doc, QDomElement & root ) {
+ QDomElement blockElement = doc.createElement( "cppcodedocumentation" );
+ setAttributesOnNode(doc, blockElement); // as we added no additional fields to this class we may
+ // just use parent TextBlock method
+ root.appendChild( blockElement );
+}
+
+/**
+ * @return QString
+ */
+QString CPPCodeDocumentation::toString ( )
+{
+
+ QString output = "";
+
+ // simple output method
+ if(getWriteOutText())
+ {
+ bool useDoubleDashOutput = true;
+
+ // need to figure out output type from cpp policy
+ CodeGenerationPolicy * p = UMLApp::app()->getCommonPolicy();
+ if(p->getCommentStyle() == CodeGenerationPolicy::MultiLine)
+ useDoubleDashOutput = false;
+
+ QString indent = getIndentationString();
+ QString endLine = getNewLineEndingChars();
+ QString body = getText();
+ if(useDoubleDashOutput)
+ {
+ if(!body.isEmpty())
+ output.append(formatMultiLineText (body, indent +"// ", endLine));
+ } else {
+ output.append(indent+"/**"+endLine);
+ output.append(formatMultiLineText (body, indent +" * ", endLine));
+ output.append(indent+" */"+endLine);
+ }
+ }
+
+ return output;
+}
+
+QString CPPCodeDocumentation::getNewEditorLine ( int amount )
+{
+ CodeGenerationPolicy * p = UMLApp::app()->getCommonPolicy();
+ if(p->getCommentStyle() == CodeGenerationPolicy::MultiLine)
+ return getIndentationString(amount) + " * ";
+ else
+ return getIndentationString(amount) + "// ";
+}
+
+int CPPCodeDocumentation::firstEditableLine() {
+ CodeGenerationPolicy * p = UMLApp::app()->getCommonPolicy();
+ if(p->getCommentStyle() == CodeGenerationPolicy::MultiLine)
+ return 1;
+ return 0;
+}
+
+int CPPCodeDocumentation::lastEditableLine() {
+ CodeGenerationPolicy * p = UMLApp::app()->getCommonPolicy();
+ if(p->getCommentStyle() == CodeGenerationPolicy::MultiLine)
+ {
+ return -1; // very last line is NOT editable
+ }
+ return 0;
+}
+
+/** UnFormat a long text string. Typically, this means removing
+ * the indentaion (linePrefix) and/or newline chars from each line.
+ */
+QString CPPCodeDocumentation::unformatText ( const QString & text , const QString & indent)
+{
+
+ QString mytext = TextBlock::unformatText(text, indent);
+ CodeGenerationPolicy * p = UMLApp::app()->getCommonPolicy();
+ // remove leading or trailing comment stuff
+ mytext.remove(QRegExp('^'+indent));
+ if(p->getCommentStyle() == CodeGenerationPolicy::MultiLine)
+ {
+ mytext.remove(QRegExp("^\\/\\*\\*\\s*\n?"));
+ mytext.remove(QRegExp("\\s*\\*\\/\\s*\n?$"));
+ mytext.remove(QRegExp("^\\s*\\*\\s*"));
+ } else
+ mytext.remove(QRegExp("^\\/\\/\\s*"));
+
+ return mytext;
+}
+
+
diff --git a/umbrello/umbrello/codegenerators/cppcodedocumentation.h b/umbrello/umbrello/codegenerators/cppcodedocumentation.h
new file mode 100644
index 00000000..79bc4fe0
--- /dev/null
+++ b/umbrello/umbrello/codegenerators/cppcodedocumentation.h
@@ -0,0 +1,95 @@
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * copyright (C) 2004-2006 *
+ * Umbrello UML Modeller Authors <uml-devel@uml.sf.net> *
+ ***************************************************************************/
+
+/* This code generated by:
+ * Author : thomas
+ * Date : Mon Sep 1 2003
+ */
+
+
+
+#ifndef CPPCODEDOCUMENTATION_H
+#define CPPCODEDOCUMENTATION_H
+
+#include <qstring.h>
+#include "../codecomment.h"
+
+class CodeDocument;
+
+/**
+ * class CPPCodeDocumentation
+ * A CPP code comment. There is only a single styles of comments:
+ * these are simply started with double slash sequence and no terminating
+ * characters
+ */
+
+class CPPCodeDocumentation : virtual public CodeComment
+{
+public:
+
+ // Constructors/Destructors
+ //
+
+
+ /**
+ * Constructors
+ */
+ explicit CPPCodeDocumentation ( CodeDocument * doc, const QString & text = "");
+
+ /**
+ * Empty Destructor
+ */
+ virtual ~CPPCodeDocumentation ( );
+
+ // Public attributes
+ //
+
+ // Other
+ //
+
+ /**
+ * Save the XMI representation of this object
+ */
+ virtual void saveToXMI ( QDomDocument & doc, QDomElement & root );
+
+ /**
+ * @return QString
+ */
+ QString toString ( );
+
+
+ /** UnFormat a long text string. Typically, this means removing
+ * the indentaion (linePrefix) and/or newline chars from each line.
+ */
+ virtual QString unformatText ( const QString & text, const QString & indent = "" );
+
+ /** a special version here because we want to not only indent
+ * the new line, but to add the " * " sequence as well.
+ */
+ virtual QString getNewEditorLine ( int amount );
+
+ /** Ush. These are terrifically bad and must one day go away.
+ * Both methods indicate the range of lines in this textblock
+ * which may be edited by the codeeditor (assuming that any are
+ * actually editable). The default case is no lines are editable.
+ * The line numbering starts with '0' and a '-1' means no line
+ * qualifies.
+ */
+ virtual int firstEditableLine();
+ virtual int lastEditableLine();
+
+protected:
+
+private:
+
+};
+
+#endif // CPPCODEDOCUMENTATION_H
diff --git a/umbrello/umbrello/codegenerators/cppcodegenerationform.cpp b/umbrello/umbrello/codegenerators/cppcodegenerationform.cpp
new file mode 100644
index 00000000..a4acf713
--- /dev/null
+++ b/umbrello/umbrello/codegenerators/cppcodegenerationform.cpp
@@ -0,0 +1,305 @@
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * copyright (C) 2004-2007 *
+ * Umbrello UML Modeller Authors <uml-devel@uml.sf.net> *
+ ***************************************************************************/
+
+/* This code generated by:
+ * Author : thomas
+ * Date : Thu Nov 20 2003
+ */
+
+// own header
+#include "cppcodegenerationform.h"
+
+// qt/kde includes
+#include <qlabel.h>
+#include <qregexp.h>
+#include <qlistview.h>
+#include <kfiledialog.h>
+#include <kdebug.h>
+#include <klocale.h>
+#include <kcombobox.h>
+#include <kmessagebox.h>
+
+
+CPPCodeGenerationForm::CPPCodeGenerationForm( QWidget *parent, const char *name )
+ : CPPCodeGenerationFormBase (parent,name)
+{
+ init();
+
+ GeneralOptionsListView->addColumn(tr2i18n("General Options"));
+ pOptionPackageIsANamespace = new QCheckListItem( GeneralOptionsListView,
+ tr2i18n("Package is a namespace"),
+ QCheckListItem::CheckBox );
+ pOptionVirtualDestructors = new QCheckListItem( GeneralOptionsListView,
+ tr2i18n("Virtual destructors"),
+ QCheckListItem::CheckBox );
+ pOptionGenerateEmptyConstructors = new QCheckListItem( GeneralOptionsListView,
+ tr2i18n("Generate empty constructors"),
+ QCheckListItem::CheckBox );
+ pOptionGenerateAccessorMethods = new QCheckListItem( GeneralOptionsListView,
+ tr2i18n("Generate accessor methods"),
+ QCheckListItem::CheckBox );
+ pOptionOperationsAreInline = new QCheckListItem( GeneralOptionsListView,
+ tr2i18n("Operations are inline"),
+ QCheckListItem::CheckBox );
+ pOptionAccessorsAreInline = new QCheckListItem( GeneralOptionsListView,
+ tr2i18n("Accessors are inline"),
+ QCheckListItem::CheckBox );
+
+ pOptionAccessorsArePublic = new QCheckListItem( GeneralOptionsListView,
+ tr2i18n("Accessors are public"),
+ QCheckListItem::CheckBox );
+
+ connect(GeneralOptionsListView,
+ SIGNAL(clicked(QListViewItem *)), this,
+ SLOT(generalOptionsListViewClicked(QListViewItem *))
+ );
+
+}
+
+CPPCodeGenerationForm::~CPPCodeGenerationForm()
+{
+}
+
+void CPPCodeGenerationForm::browseClicked()
+{
+ QString button = sender()->name();
+ QString file = KFileDialog::getOpenFileName( QString::null, "*.h", this, "Get Header File");
+
+ if(file.isEmpty())
+ return;
+
+ if(button=="m_browseStringButton") {
+ // search for match in history list, if absent, then add it
+ m_stringIncludeFileHistoryCombo->setCurrentItem(file, true);
+ }
+ else if(button=="m_browseListButton") {
+ // search for match in history list, if absent, then add it
+ m_listIncludeFileHistoryCombo->setCurrentItem(file, true);
+ }
+}
+
+void CPPCodeGenerationForm::generalOptionsListViewClicked(QListViewItem *pSender) {
+
+ // operations are inline and accessors are operations :)
+ if (pOptionOperationsAreInline->isOn() && pOptionGenerateAccessorMethods->isOn())
+ pOptionAccessorsAreInline->setOn(true);
+
+ if (pSender == pOptionPackageIsANamespace) {
+#if 0
+ KMessageBox::error(0, "CPPCodeGenerationForm::generalOptionsListViewClicked(): "
+ "sender=pOptionPackageIsANamespace");
+#endif
+ return;
+ }
+ if (pSender == pOptionVirtualDestructors) {
+#if 0
+ KMessageBox::error(0, "CPPCodeGenerationForm::generalOptionsListViewClicked(): "
+ "sender=pOptionVirtualDestructors");
+#endif
+ return;
+ }
+ if (pSender == pOptionGenerateEmptyConstructors) {
+#if 0
+ KMessageBox::error(0, "CPPCodeGenerationForm::generalOptionsListViewClicked(): "
+ "sender=pOptionVirtualDestructors");
+#endif
+ return;
+ }
+ if (pSender == pOptionGenerateAccessorMethods) {
+ pOptionAccessorsAreInline->setEnabled(pOptionGenerateAccessorMethods->isOn());
+ pOptionAccessorsArePublic->setEnabled(pOptionGenerateAccessorMethods->isOn());
+ // reset the value if needed
+ if (!pOptionGenerateAccessorMethods->isOn())
+ {
+ pOptionAccessorsAreInline->setOn(false);
+ pOptionAccessorsArePublic->setOn(false);
+ }
+#if 0
+ KMessageBox::error(0, "CPPCodeGenerationForm::generalOptionsListViewClicked(): "
+ "sender=pOptionGenerateAccessorMethods");
+#endif
+ return;
+ }
+ if (pSender == pOptionOperationsAreInline) {
+#if 0
+ KMessageBox::error(0, "CPPCodeGenerationForm::generalOptionsListViewClicked(): "
+ "sender=pOptionOperationsAreInline");
+#endif
+ return;
+ }
+ if (pSender == pOptionAccessorsAreInline) {
+#if 0
+ KMessageBox::error(0, "CPPCodeGenerationForm::generalOptionsListViewClicked(): "
+ "sender=pOptionAccessorsAreInline");
+#endif
+ return;
+ }
+
+#if 0
+ KMessageBox::error(0, "CPPCodeGenerationForm::generalOptionsListViewClicked(): "
+ "unknown sender");
+#endif
+ return;
+}
+
+void CPPCodeGenerationForm::init() {
+ pOptionPackageIsANamespace = NULL;
+ pOptionVirtualDestructors = NULL;
+ pOptionGenerateEmptyConstructors = NULL;
+ pOptionGenerateAccessorMethods = NULL;
+ pOptionOperationsAreInline = NULL;
+ pOptionAccessorsAreInline = NULL;
+}
+
+/**
+ *
+ * set the display state of option "Package Is Namespace"
+ *
+ */
+void CPPCodeGenerationForm::setPackageIsANamespace(bool bFlag) {
+ pOptionPackageIsANamespace->setOn(bFlag);
+}
+
+/**
+ *
+ * set the display state of option "Virtual Destructors"
+ *
+ */
+void CPPCodeGenerationForm::setVirtualDestructors(bool bFlag) {
+ pOptionVirtualDestructors->setOn(bFlag);
+}
+
+/**
+ *
+ * set the display state of option "Generate Empty Constructors"
+ *
+ */
+void CPPCodeGenerationForm::setGenerateEmptyConstructors(bool bFlag) {
+ pOptionGenerateEmptyConstructors->setOn(bFlag);
+}
+
+/**
+ *
+ * set the display state of option "Generate Accessor Methods"
+ *
+ */
+void CPPCodeGenerationForm::setGenerateAccessorMethods(bool bFlag) {
+ pOptionGenerateAccessorMethods->setOn(bFlag);
+ // initial settings
+ pOptionAccessorsAreInline->setEnabled(pOptionGenerateAccessorMethods->isOn());
+ pOptionAccessorsArePublic->setEnabled(pOptionGenerateAccessorMethods->isOn());
+ // reset the value if needed
+ if (!pOptionGenerateAccessorMethods->isOn())
+ {
+ pOptionAccessorsAreInline->setOn(false);
+ pOptionAccessorsArePublic->setOn(false);
+ }
+}
+
+/**
+ *
+ * set the display state of option "Operations Are Inline"
+ *
+ */
+void CPPCodeGenerationForm::setOperationsAreInline(bool bFlag) {
+ pOptionOperationsAreInline->setOn(bFlag);
+}
+
+/**
+ *
+ * set the display state of option "Accessors Are Inline"
+ *
+ */
+void CPPCodeGenerationForm::setAccessorsAreInline(bool bFlag) {
+ pOptionAccessorsAreInline->setOn(bFlag);
+}
+
+/**
+ *
+ * set the display state of option "Accessors Are Public"
+ *
+ */
+void CPPCodeGenerationForm::setAccessorsArePublic(bool bFlag) {
+ pOptionAccessorsArePublic->setOn(bFlag);
+}
+
+/**
+ *
+ * get the display state of option "Package Is Namespace"
+ *
+ */
+bool CPPCodeGenerationForm::getPackageIsANamespace()
+{
+ return pOptionPackageIsANamespace->isOn();
+}
+
+/**
+ *
+ * get the display state of option "Virtual Destructors"
+ *
+ */
+bool CPPCodeGenerationForm::getVirtualDestructors()
+{
+ return pOptionVirtualDestructors->isOn();
+}
+
+/**
+ *
+ * get the display state of option "Generate Empty Constructors"
+ *
+ */
+bool CPPCodeGenerationForm::getGenerateEmptyConstructors()
+{
+ return pOptionGenerateEmptyConstructors->isOn();
+}
+
+/**
+ *
+ * get the display state of option "Generate Accessor Methods"
+ *
+ */
+bool CPPCodeGenerationForm::getGenerateAccessorMethods()
+{
+ return pOptionGenerateAccessorMethods->isOn();
+}
+
+/**
+ *
+ * get the display state of option "Operations Are Inline"
+ *
+ */
+bool CPPCodeGenerationForm::getOperationsAreInline()
+{
+ return pOptionOperationsAreInline->isOn();
+}
+
+/**
+ *
+ * get the display state of option "Accessors Are Inline"
+ *
+ */
+bool CPPCodeGenerationForm::getAccessorsAreInline()
+{
+ return pOptionAccessorsAreInline->isOn();
+}
+
+/**
+ *
+ * get the display state of option "Accessors Are Public"
+ *
+ */
+bool CPPCodeGenerationForm::getAccessorsArePublic()
+{
+ return pOptionAccessorsArePublic->isOn();
+}
+
+
+#include "cppcodegenerationform.moc"
diff --git a/umbrello/umbrello/codegenerators/cppcodegenerationform.h b/umbrello/umbrello/codegenerators/cppcodegenerationform.h
new file mode 100644
index 00000000..73441a82
--- /dev/null
+++ b/umbrello/umbrello/codegenerators/cppcodegenerationform.h
@@ -0,0 +1,150 @@
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the 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 code generated by:
+ * Author : thomas
+ * Date : Wed Jul 30 2003
+ */
+
+#ifndef CPPCODEGENERATIONFORM_H
+#define CPPCODEGENERATIONFORM_H
+
+#include "cppcodegenerationformbase.h"
+
+class QCheckListItem;
+
+/**
+ * @author Brian Thomas
+ */
+
+class CPPCodeGenerationForm : public CPPCodeGenerationFormBase {
+ Q_OBJECT
+public:
+
+ /**
+ * std ctor
+ */
+ explicit CPPCodeGenerationForm (QWidget *parent=0, const char *name=0);
+
+ /**
+ * std dtor
+ */
+ virtual ~CPPCodeGenerationForm();
+
+ /**
+ * set the display state of option "Package Is A Namespace"
+ */
+ void setPackageIsANamespace(bool bFlag = true);
+
+ /**
+ * set the display state of option "Virtual Destructors"
+ */
+ void setVirtualDestructors(bool bFlag = true);
+
+ /**
+ * set the display state of option "Generate Empty Constructors"
+ */
+ void setGenerateEmptyConstructors(bool bFlag = true);
+
+ /**
+ * set the display state of option "Generate Accessor Methods"
+ */
+ void setGenerateAccessorMethods(bool bFlag = true);
+
+ /**
+ * set the display state of option "Operations Are Inline"
+ */
+ void setOperationsAreInline(bool bFlag = true);
+
+ /**
+ * set the display state of option "Accessors Are Inline"
+ */
+ void setAccessorsAreInline(bool bFlag = true);
+
+ /**
+ * set the display state of option "Accessors Are Public"
+ */
+ void setAccessorsArePublic(bool bFlag = true);
+
+ /**
+ * set the display state of option "Generate Makefile Document"
+ */
+ void setGenerateMakefileDocument(bool bFlag = true);
+
+ /**
+ * get the display state of option "Package Is A Namespace"
+ */
+ bool getPackageIsANamespace();
+
+ /**
+ * get the display state of option "Virtual Destructors"
+ */
+ bool getVirtualDestructors();
+
+ /**
+ * get the display state of option "Generate Empty Constructors"
+ */
+ bool getGenerateEmptyConstructors();
+
+ /**
+ * get the display state of option "Generate Accessors Methods"
+ */
+ bool getGenerateAccessorMethods();
+
+ /**
+ * get the display state of option "Operations Are Inline"
+ */
+ bool getOperationsAreInline();
+
+ /**
+ * get the display state of option "Accessors Are Inline"
+ */
+ bool getAccessorsAreInline();
+
+ /**
+ * get the display state of option "Accessors Are Public"
+ */
+ bool getAccessorsArePublic();
+
+ /**
+ * get the display state of option "Generate Makefile Document"
+ */
+ bool getGenerateMakefileDocument();
+
+protected:
+
+public slots:
+
+ virtual void browseClicked();
+
+private slots:
+ virtual void generalOptionsListViewClicked(QListViewItem *);
+
+private:
+
+ /*
+ * check boxes for the available options
+ */
+ QCheckListItem *pOptionPackageIsANamespace;
+ QCheckListItem *pOptionVirtualDestructors;
+ QCheckListItem *pOptionGenerateEmptyConstructors;
+ QCheckListItem *pOptionGenerateAccessorMethods;
+ QCheckListItem *pOptionOperationsAreInline;
+ QCheckListItem *pOptionAccessorsAreInline;
+ QCheckListItem *pOptionAccessorsArePublic;
+
+ /**
+ * initialize all attributes
+ */
+ void init();
+
+};
+
+#endif
+
diff --git a/umbrello/umbrello/codegenerators/cppcodegenerationformbase.ui b/umbrello/umbrello/codegenerators/cppcodegenerationformbase.ui
new file mode 100644
index 00000000..2599ae35
--- /dev/null
+++ b/umbrello/umbrello/codegenerators/cppcodegenerationformbase.ui
@@ -0,0 +1,481 @@
+<!DOCTYPE UI><UI version="3.1" stdsetdef="1">
+<class>CPPCodeGenerationFormBase</class>
+<widget class="QWidget">
+ <property name="name">
+ <cstring>CPPCodeGenerationFormBase</cstring>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>648</width>
+ <height>549</height>
+ </rect>
+ </property>
+ <widget class="QGroupBox">
+ <property name="name">
+ <cstring>groupBox1</cstring>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>11</x>
+ <y>44</y>
+ <width>436</width>
+ <height>72</height>
+ </rect>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>5</hsizetype>
+ <vsizetype>0</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="title">
+ <string>Documentation</string>
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLayoutWidget" row="0" column="0">
+ <property name="name">
+ <cstring>layout4</cstring>
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QComboBox" row="0" column="1">
+ <item>
+ <property name="text">
+ <string>Slash-Slash (//)</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>Slash-Star (/** */)</string>
+ </property>
+ </item>
+ <property name="name">
+ <cstring>m_SelectCommentStyle</cstring>
+ </property>
+ </widget>
+ <widget class="QLabel" row="0" column="0">
+ <property name="name">
+ <cstring>textLabel1</cstring>
+ </property>
+ <property name="text">
+ <string>Style:</string>
+ </property>
+ </widget>
+ </grid>
+ </widget>
+ </grid>
+ </widget>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>textLabel1_2</cstring>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>11</x>
+ <y>11</y>
+ <width>436</width>
+ <height>27</height>
+ </rect>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>5</hsizetype>
+ <vsizetype>4</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="text">
+ <string>&lt;p align="center"&gt;C++ Code Generation&lt;/p&gt;</string>
+ </property>
+ </widget>
+ <widget class="QTabWidget">
+ <property name="name">
+ <cstring>tabWidget2</cstring>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>10</x>
+ <y>120</y>
+ <width>436</width>
+ <height>305</height>
+ </rect>
+ </property>
+ <widget class="QWidget">
+ <property name="name">
+ <cstring>tab</cstring>
+ </property>
+ <attribute name="title">
+ <string>General</string>
+ </attribute>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QListView">
+ <property name="name">
+ <cstring>GeneralOptionsListView</cstring>
+ </property>
+ </widget>
+ </vbox>
+ </widget>
+ <widget class="QWidget">
+ <property name="name">
+ <cstring>tab</cstring>
+ </property>
+ <attribute name="title">
+ <string>Method Body Generation</string>
+ </attribute>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <spacer row="2" column="0">
+ <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>410</width>
+ <height>113</height>
+ </size>
+ </property>
+ </spacer>
+ <widget class="QLabel" row="0" column="0">
+ <property name="name">
+ <cstring>textLabel2_2_2_2</cstring>
+ </property>
+ <property name="text">
+ <string>Use following for classes in generated code:</string>
+ </property>
+ </widget>
+ <widget class="QLayoutWidget" row="1" column="0">
+ <property name="name">
+ <cstring>layout17</cstring>
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="KHistoryCombo" row="1" column="1" rowspan="1" colspan="2">
+ <property name="name">
+ <cstring>m_listClassHCombo</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>4</hsizetype>
+ <vsizetype>0</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="editable">
+ <bool>false</bool>
+ </property>
+ <property name="currentItem">
+ <number>0</number>
+ </property>
+ <property name="insertionPolicy">
+ <enum>NoInsertion</enum>
+ </property>
+ <property name="duplicatesEnabled">
+ <bool>false</bool>
+ </property>
+ <property name="historyItems">
+ <stringlist>
+ <string>QPtrList</string>
+ <string>vector</string>
+ </stringlist>
+ </property>
+ </widget>
+ <widget class="QLabel" row="0" column="0" rowspan="1" colspan="2">
+ <property name="name">
+ <cstring>textLabel1_3_2_2_2</cstring>
+ </property>
+ <property name="text">
+ <string>&lt;b&gt;Variable&lt;/b&gt;</string>
+ </property>
+ </widget>
+ <widget class="QPushButton" row="2" column="4" rowspan="1" colspan="2">
+ <property name="name">
+ <cstring>m_browseStringButton</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>0</hsizetype>
+ <vsizetype>0</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="maximumSize">
+ <size>
+ <width>32</width>
+ <height>32767</height>
+ </size>
+ </property>
+ <property name="text">
+ <string>...</string>
+ </property>
+ </widget>
+ <widget class="QCheckBox" row="2" column="7">
+ <property name="name">
+ <cstring>m_globalStringCheckBox</cstring>
+ </property>
+ <property name="text">
+ <string></string>
+ </property>
+ <property name="checked">
+ <bool>true</bool>
+ </property>
+ </widget>
+ <widget class="KHistoryCombo" row="2" column="1" rowspan="1" colspan="2">
+ <property name="name">
+ <cstring>m_stringClassHCombo</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>4</hsizetype>
+ <vsizetype>0</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="editable">
+ <bool>false</bool>
+ </property>
+ <property name="currentItem">
+ <number>0</number>
+ </property>
+ <property name="insertionPolicy">
+ <enum>NoInsertion</enum>
+ </property>
+ <property name="duplicatesEnabled">
+ <bool>false</bool>
+ </property>
+ <property name="historyItems">
+ <stringlist>
+ <string>QString</string>
+ <string>string</string>
+ </stringlist>
+ </property>
+ </widget>
+ <spacer row="2" column="6">
+ <property name="name">
+ <cstring>spacer2_2_2_2</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Minimum</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>20</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ <spacer row="1" column="6">
+ <property name="name">
+ <cstring>spacer1_2_2_2</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Minimum</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>20</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ <widget class="QLabel" row="2" column="0">
+ <property name="name">
+ <cstring>stringClassTextLabel</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>1</hsizetype>
+ <vsizetype>5</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="text">
+ <string>&lt;p align="center"&gt;String&lt;/p&gt;</string>
+ </property>
+ </widget>
+ <widget class="QLabel" row="1" column="0">
+ <property name="name">
+ <cstring>listClassTextLabel</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>1</hsizetype>
+ <vsizetype>5</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="text">
+ <string>&lt;p align="center"&gt;List&lt;/p&gt;</string>
+ </property>
+ </widget>
+ <widget class="KHistoryCombo" row="1" column="3">
+ <property name="name">
+ <cstring>m_listIncludeFileHistoryCombo</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="insertionPolicy">
+ <enum>AtTop</enum>
+ </property>
+ <property name="historyItems">
+ <stringlist>
+ <string>qptrlist.h</string>
+ <string>vector</string>
+ </stringlist>
+ </property>
+ </widget>
+ <widget class="QLabel" row="0" column="5" rowspan="1" colspan="3">
+ <property name="name">
+ <cstring>textLabel4_2_2_2</cstring>
+ </property>
+ <property name="text">
+ <string>&lt;i&gt;global?&lt;/i&gt;</string>
+ </property>
+ </widget>
+ <widget class="KHistoryCombo" row="2" column="3">
+ <property name="name">
+ <cstring>m_stringIncludeFileHistoryCombo</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="insertionPolicy">
+ <enum>AtTop</enum>
+ </property>
+ <property name="historyItems">
+ <stringlist>
+ <string>qstring.h</string>
+ <string>string</string>
+ </stringlist>
+ </property>
+ </widget>
+ <widget class="QCheckBox" row="1" column="7">
+ <property name="name">
+ <cstring>m_globalListCheckBox</cstring>
+ </property>
+ <property name="text">
+ <string></string>
+ </property>
+ <property name="checked">
+ <bool>true</bool>
+ </property>
+ </widget>
+ <widget class="QLabel" row="0" column="2">
+ <property name="name">
+ <cstring>textLabel3_2_2</cstring>
+ </property>
+ <property name="text">
+ <string>Class name</string>
+ </property>
+ </widget>
+ <widget class="QPushButton" row="1" column="4" rowspan="1" colspan="2">
+ <property name="name">
+ <cstring>m_browseListButton</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>4</hsizetype>
+ <vsizetype>0</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="maximumSize">
+ <size>
+ <width>32</width>
+ <height>32767</height>
+ </size>
+ </property>
+ <property name="text">
+ <string>...</string>
+ </property>
+ </widget>
+ <widget class="QLabel" row="0" column="3" rowspan="1" colspan="2">
+ <property name="name">
+ <cstring>textLabel5_2_2_2</cstring>
+ </property>
+ <property name="text">
+ <string>&lt;i&gt;&lt;p align="center"&gt;Include file&lt;/p&gt;&lt;/i&gt;</string>
+ </property>
+ </widget>
+ </grid>
+ </widget>
+ </grid>
+ </widget>
+ </widget>
+</widget>
+<customwidgets>
+</customwidgets>
+<connections>
+ <connection>
+ <sender>m_browseListButton</sender>
+ <signal>clicked()</signal>
+ <receiver>CPPCodeGenerationFormBase</receiver>
+ <slot>browseClicked()</slot>
+ </connection>
+ <connection>
+ <sender>m_browseStringButton</sender>
+ <signal>clicked()</signal>
+ <receiver>CPPCodeGenerationFormBase</receiver>
+ <slot>browseClicked()</slot>
+ </connection>
+</connections>
+<slots>
+ <slot>browseClicked()</slot>
+</slots>
+<layoutdefaults spacing="6" margin="11"/>
+<includehints>
+ <includehint>klineedit.h</includehint>
+ <includehint>klineedit.h</includehint>
+</includehints>
+</UI>
diff --git a/umbrello/umbrello/codegenerators/cppcodegenerationpolicy.cpp b/umbrello/umbrello/codegenerators/cppcodegenerationpolicy.cpp
new file mode 100644
index 00000000..d0359603
--- /dev/null
+++ b/umbrello/umbrello/codegenerators/cppcodegenerationpolicy.cpp
@@ -0,0 +1,390 @@
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * copyright (C) 2004-2006 *
+ * Umbrello UML Modeller Authors <uml-devel@uml.sf.net> *
+ ***************************************************************************/
+
+/* This code generated by:
+ * Author : thomas
+ * Date : Mon Jun 23 2003
+ */
+
+// own header
+#include "cppcodegenerationpolicy.h"
+// qt/kde includes
+#include <qregexp.h>
+#include <kdebug.h>
+#include <kconfig.h>
+// app includes
+#include "cppcodegenerationpolicypage.h"
+#include "../uml.h"
+
+const bool CPPCodeGenerationPolicy::DEFAULT_AUTO_GEN_ACCESSORS = true;
+const bool CPPCodeGenerationPolicy::DEFAULT_INLINE_ACCESSORS = false;
+const bool CPPCodeGenerationPolicy::DEFAULT_INLINE_OPERATIONS = false;
+const bool CPPCodeGenerationPolicy::DEFAULT_VIRTUAL_DESTRUCTORS = true;
+const bool CPPCodeGenerationPolicy::DEFAULT_PACKAGE_IS_NAMESPACE = true;
+const char * CPPCodeGenerationPolicy::DEFAULT_STRING_CLASS_NAME = "string";
+const char * CPPCodeGenerationPolicy::DEFAULT_STRING_CLASS_INCLUDE = "string";
+const char * CPPCodeGenerationPolicy::DEFAULT_VECTOR_CLASS_NAME = "vector";
+const char * CPPCodeGenerationPolicy::DEFAULT_VECTOR_CLASS_INCLUDE = "vector";
+const char * CPPCodeGenerationPolicy::DEFAULT_VECTOR_METHOD_APPEND = "%VARNAME%.push_back(value);";
+const char * CPPCodeGenerationPolicy::DEFAULT_VECTOR_METHOD_REMOVE = "int size = %VARNAME%.size();\nfor ( int i = 0; i < size; ++i) {\n\t%ITEMCLASS% item = %VARNAME%.at(i);\n\tif(item == value) {\n\t\tvector<%ITEMCLASS%>::iterator it = %VARNAME%.begin() + i;\n\t\t%VARNAME%.erase(it);\n\t\treturn;\n\t}\n }";
+const char * CPPCodeGenerationPolicy::DEFAULT_VECTOR_METHOD_INIT = ""; // nothing to do in std::vector
+const char * CPPCodeGenerationPolicy::DEFAULT_OBJECT_METHOD_INIT = "%VARNAME% = new %ITEMCLASS%( );";
+const bool CPPCodeGenerationPolicy::DEFAULT_STRING_INCLUDE_GLOBAL = true;
+const bool CPPCodeGenerationPolicy::DEFAULT_VECTOR_INCLUDE_GLOBAL = true;
+const bool CPPCodeGenerationPolicy::DEFAULT_PUBLIC_ACCESSORS = false;
+
+
+// Constructors/Destructors
+//
+
+CPPCodeGenerationPolicy::CPPCodeGenerationPolicy(KConfig *config)
+{
+ init();
+ setDefaults(config,false);
+}
+
+CPPCodeGenerationPolicy::~CPPCodeGenerationPolicy ( ) { }
+
+//
+// Methods
+//
+
+// Accessor methods
+//
+/**
+ * Set the value of m_publicAccessors
+ * @param new_var the new value
+ */
+void CPPCodeGenerationPolicy::setAccessorsArePublic ( bool var )
+{
+ m_publicAccessors = var;
+ // @todo we should probably use an own signal for this
+ UMLApp::app()->getCommonPolicy()->emitModifiedCodeContentSig();
+}
+
+/**
+ * Get the value of m_publicAccessors
+ * @return value the boolean value of m_publicAccessors
+ */
+bool CPPCodeGenerationPolicy::getAccessorsArePublic( )
+{
+ return m_publicAccessors;
+}
+
+/**
+ * Set the value of m_inlineAccessors
+ * @param new_var the new value
+ */
+void CPPCodeGenerationPolicy::setAccessorsAreInline ( bool var )
+{
+ m_inlineAccessors = var;
+ UMLApp::app()->getCommonPolicy()->emitModifiedCodeContentSig();
+}
+
+/**
+ * Get the value of m_inlineAccessors
+ * @return value the boolean value of m_inlineAccessors
+ */
+bool CPPCodeGenerationPolicy::getAccessorsAreInline( )
+{
+ return m_inlineAccessors;
+}
+
+/**
+ * Set the value of m_inlineOperations
+ * @param new_var the new value
+ */
+void CPPCodeGenerationPolicy::setOperationsAreInline ( bool var )
+{
+ m_inlineOperations = var;
+ UMLApp::app()->getCommonPolicy()->emitModifiedCodeContentSig();
+}
+
+/**
+ * Get the value of m_inlineOperations
+ * @return value the boolean value of m_inlineOperations
+ */
+bool CPPCodeGenerationPolicy::getOperationsAreInline( )
+{
+ return m_inlineOperations;
+}
+
+/**
+ * Set the value of m_virtualDestructors
+ * @param new_var the new value
+ */
+void CPPCodeGenerationPolicy::setDestructorsAreVirtual ( bool var )
+{
+ m_virtualDestructors = var;
+ UMLApp::app()->getCommonPolicy()->emitModifiedCodeContentSig();
+}
+
+/**
+ * Get the value of m_virtualDestructors
+ * @return value the boolean value of m_virtualDestructors
+ */
+bool CPPCodeGenerationPolicy::getDestructorsAreVirtual( )
+{
+ return m_virtualDestructors;
+}
+
+/**
+ * Set the value of m_packageIsNamespace
+ * @param new_var the new value
+ */
+void CPPCodeGenerationPolicy::setPackageIsNamespace ( bool var ) {
+ m_packageIsNamespace = var;
+ UMLApp::app()->getCommonPolicy()->emitModifiedCodeContentSig();
+}
+
+/**
+ * Get the value of m_packageIsNamespace
+ * @return value the boolean value of m_packageIsNamespace
+ */
+bool CPPCodeGenerationPolicy::getPackageIsNamespace( ) {
+ return m_packageIsNamespace;
+}
+
+/**
+ * Set the value of m_autoGenerateAccessors
+ * @param new_var the new value
+ */
+void CPPCodeGenerationPolicy::setAutoGenerateAccessors( bool var ) {
+ m_autoGenerateAccessors = var;
+ UMLApp::app()->getCommonPolicy()->emitModifiedCodeContentSig();
+}
+
+bool CPPCodeGenerationPolicy::getAutoGenerateAccessors( ){
+ return m_autoGenerateAccessors;
+}
+
+QString CPPCodeGenerationPolicy::getStringClassName() {
+ return m_stringClassName;
+}
+
+QString CPPCodeGenerationPolicy::getStringClassNameInclude() {
+ return m_stringClassNameInclude;
+}
+
+QString CPPCodeGenerationPolicy::getVectorClassName() {
+ return m_vectorClassName;
+}
+
+QString CPPCodeGenerationPolicy::getVectorClassNameInclude() {
+ return m_vectorClassNameInclude;
+}
+
+void CPPCodeGenerationPolicy::setStringClassName(const QString &value) {
+ m_stringClassName = value;
+ UMLApp::app()->getCommonPolicy()->emitModifiedCodeContentSig();
+}
+
+void CPPCodeGenerationPolicy::setStringClassNameInclude(const QString &value) {
+ m_stringClassNameInclude = value;
+ UMLApp::app()->getCommonPolicy()->emitModifiedCodeContentSig();
+}
+
+void CPPCodeGenerationPolicy::setVectorClassName(const QString &value) {
+ m_vectorClassName = value;
+ UMLApp::app()->getCommonPolicy()->emitModifiedCodeContentSig();
+}
+
+void CPPCodeGenerationPolicy::setVectorClassNameInclude(const QString &value) {
+ m_vectorClassNameInclude = value;
+ UMLApp::app()->getCommonPolicy()->emitModifiedCodeContentSig();
+}
+
+/** determine if the string include is global one */
+bool CPPCodeGenerationPolicy::stringIncludeIsGlobal () {
+ return m_stringIncludeIsGlobal;
+}
+
+bool CPPCodeGenerationPolicy::vectorIncludeIsGlobal () {
+ return m_vectorIncludeIsGlobal;
+}
+
+void CPPCodeGenerationPolicy::setStringIncludeIsGlobal(bool value) {
+ m_stringIncludeIsGlobal = value;
+ UMLApp::app()->getCommonPolicy()->emitModifiedCodeContentSig();
+}
+
+void CPPCodeGenerationPolicy::setVectorIncludeIsGlobal(bool value) {
+ m_vectorIncludeIsGlobal = value;
+ UMLApp::app()->getCommonPolicy()->emitModifiedCodeContentSig();
+}
+
+QString CPPCodeGenerationPolicy::getVectorMethodAppend(const QString & variableName, const QString & itemClassName) {
+ QString value = m_vectorMethodAppendBase;
+ if(!variableName.isEmpty())
+ value.replace(QRegExp("%VARNAME%"),variableName);
+ value.replace(QRegExp("%VECTORTYPENAME%"), m_vectorClassName);
+ if(!itemClassName.isEmpty())
+ value.replace(QRegExp("%ITEMCLASS%"),itemClassName);
+ return value;
+}
+
+QString CPPCodeGenerationPolicy::getVectorMethodRemove(const QString & variableName, const QString & itemClassName) {
+ QString value = m_vectorMethodRemoveBase;
+ if(!variableName.isEmpty())
+ value.replace(QRegExp("%VARNAME%"),variableName);
+ value.replace(QRegExp("%VECTORTYPENAME%"), m_vectorClassName);
+ if(!itemClassName.isEmpty())
+ value.replace(QRegExp("%ITEMCLASS%"),itemClassName);
+ return value;
+}
+
+QString CPPCodeGenerationPolicy::getVectorMethodInit(const QString & variableName, const QString & itemClassName) {
+ QString value = m_vectorMethodInitBase;
+ if(!variableName.isEmpty())
+ value.replace(QRegExp("%VARNAME%"),variableName);
+ value.replace(QRegExp("%VECTORTYPENAME%"), m_vectorClassName);
+ if(!itemClassName.isEmpty())
+ value.replace(QRegExp("%ITEMCLASS%"),itemClassName);
+ return value;
+}
+
+QString CPPCodeGenerationPolicy::getObjectMethodInit(const QString & variableName, const QString & itemClassName) {
+ QString value = m_objectMethodInitBase;
+ if(!variableName.isEmpty())
+ value.replace(QRegExp("%VARNAME%"),variableName);
+ value.replace(QRegExp("%VECTORTYPENAME%"), m_vectorClassName);
+ if(!itemClassName.isEmpty())
+ value.replace(QRegExp("%ITEMCLASS%"),itemClassName);
+ return value;
+}
+
+// Other methods
+//
+
+void CPPCodeGenerationPolicy::writeConfig ( KConfig * config )
+{
+
+ // write ONLY the CPP specific stuff
+ config->setGroup("CPP Code Generation");
+
+ config->writeEntry("autoGenAccessors",getAutoGenerateAccessors());
+
+ config->writeEntry("inlineAccessors",getAccessorsAreInline());
+ config->writeEntry("publicAccessors",getAccessorsArePublic());
+ config->writeEntry("inlineOps",getOperationsAreInline());
+ config->writeEntry("virtualDestructors",getDestructorsAreVirtual());
+ config->writeEntry("packageIsNamespace",getPackageIsNamespace());
+
+ config->writeEntry("stringClassName",getStringClassName());
+ config->writeEntry("stringClassNameInclude",getStringClassNameInclude());
+ config->writeEntry("stringIncludeIsGlobal",stringIncludeIsGlobal());
+
+ config->writeEntry("vectorClassName",getVectorClassName());
+ config->writeEntry("vectorClassNameInclude",getVectorClassNameInclude());
+ config->writeEntry("vectorIncludeIsGlobal",vectorIncludeIsGlobal());
+
+}
+
+void CPPCodeGenerationPolicy::setDefaults ( CPPCodeGenerationPolicy * cppclone, bool emitUpdateSignal )
+{
+ blockSignals(true); // we need to do this because otherwise most of these
+ // settors below will each send the modifiedCodeContent() signal
+ // needlessly (we can just make one call at the end).
+
+ {
+ setAutoGenerateAccessors(cppclone->getAutoGenerateAccessors());
+
+ setAccessorsAreInline(cppclone->getAccessorsAreInline());
+ setOperationsAreInline(cppclone->getOperationsAreInline());
+ setDestructorsAreVirtual(cppclone->getDestructorsAreVirtual());
+ setPackageIsNamespace(cppclone->getPackageIsNamespace());
+
+ setStringClassName(cppclone->getStringClassName() );
+ setStringClassNameInclude(cppclone->getStringClassNameInclude());
+ setStringIncludeIsGlobal(cppclone->stringIncludeIsGlobal());
+
+ setVectorClassName(cppclone->getVectorClassName());
+ setVectorClassNameInclude(cppclone->getVectorClassNameInclude());
+ setVectorIncludeIsGlobal(cppclone->vectorIncludeIsGlobal());
+
+ }
+
+ blockSignals(false); // "as you were citizen"
+
+ if(emitUpdateSignal)
+ UMLApp::app()->getCommonPolicy()->emitModifiedCodeContentSig();
+
+}
+
+void CPPCodeGenerationPolicy::setDefaults( KConfig * config, bool emitUpdateSignal )
+{
+
+ if(!config)
+ return;
+
+ blockSignals(true); // we need to do this because otherwise most of these
+ // settors below will each send the modifiedCodeContent() signal
+ // needlessly (we can just make one call at the end).
+
+ // now do cpp specific stuff
+ config -> setGroup("CPP Code Generation");
+
+ setAutoGenerateAccessors(config->readBoolEntry("autoGenAccessors",DEFAULT_AUTO_GEN_ACCESSORS));
+
+ setAccessorsAreInline(config->readBoolEntry("inlineAccessors",DEFAULT_INLINE_ACCESSORS));
+ setAccessorsArePublic(config->readBoolEntry("publicAccessors",DEFAULT_PUBLIC_ACCESSORS));
+ setOperationsAreInline(config->readBoolEntry("inlineOps",DEFAULT_INLINE_OPERATIONS));
+ setDestructorsAreVirtual(config->readBoolEntry("virtualDestructors",DEFAULT_VIRTUAL_DESTRUCTORS));
+ setPackageIsNamespace(config->readBoolEntry("packageIsNamespace",DEFAULT_PACKAGE_IS_NAMESPACE));
+
+ setStringClassName(config->readEntry("stringClassName",DEFAULT_STRING_CLASS_NAME) );
+ setStringClassNameInclude(config->readEntry("stringClassNameInclude",DEFAULT_STRING_CLASS_INCLUDE ) );
+ setStringIncludeIsGlobal(config->readBoolEntry("stringIncludeIsGlobal",DEFAULT_STRING_INCLUDE_GLOBAL) );
+
+ setVectorClassName(config->readEntry("vectorClassName",DEFAULT_VECTOR_CLASS_NAME) );
+ setVectorClassNameInclude(config->readEntry("vectorClassNameInclude",DEFAULT_VECTOR_CLASS_INCLUDE) );
+ setVectorIncludeIsGlobal(config->readBoolEntry("vectorIncludeIsGlobal",DEFAULT_VECTOR_INCLUDE_GLOBAL) );
+
+ blockSignals(false); // "as you were citizen"
+
+ if(emitUpdateSignal)
+ UMLApp::app()->getCommonPolicy()->emitModifiedCodeContentSig();
+}
+
+
+/**
+ * Create a new dialog interface for this object.
+ * @return dialog object
+ */
+CodeGenerationPolicyPage * CPPCodeGenerationPolicy::createPage ( QWidget *parent, const char *name ) {
+ return new CPPCodeGenerationPolicyPage ( parent, name, this );
+}
+
+void CPPCodeGenerationPolicy::init() {
+
+ m_inlineAccessors = DEFAULT_INLINE_ACCESSORS;
+ m_publicAccessors = DEFAULT_PUBLIC_ACCESSORS;
+ m_inlineOperations = DEFAULT_INLINE_OPERATIONS;
+ m_virtualDestructors = DEFAULT_VIRTUAL_DESTRUCTORS;
+ m_packageIsNamespace = DEFAULT_PACKAGE_IS_NAMESPACE;
+
+ m_stringClassName = DEFAULT_STRING_CLASS_NAME;
+ m_stringClassNameInclude = DEFAULT_STRING_CLASS_INCLUDE;
+ m_stringIncludeIsGlobal = DEFAULT_STRING_INCLUDE_GLOBAL;
+
+ m_vectorClassName = DEFAULT_VECTOR_CLASS_NAME;
+ m_vectorClassNameInclude = DEFAULT_VECTOR_CLASS_INCLUDE;
+ m_vectorIncludeIsGlobal = DEFAULT_VECTOR_INCLUDE_GLOBAL;
+
+ m_vectorMethodAppendBase = DEFAULT_VECTOR_METHOD_APPEND;
+ m_vectorMethodRemoveBase = DEFAULT_VECTOR_METHOD_REMOVE;
+ m_vectorMethodInitBase = DEFAULT_VECTOR_METHOD_INIT;
+ m_objectMethodInitBase = DEFAULT_OBJECT_METHOD_INIT;
+
+}
+
+
+#include "cppcodegenerationpolicy.moc"
diff --git a/umbrello/umbrello/codegenerators/cppcodegenerationpolicy.h b/umbrello/umbrello/codegenerators/cppcodegenerationpolicy.h
new file mode 100644
index 00000000..cda5d1f8
--- /dev/null
+++ b/umbrello/umbrello/codegenerators/cppcodegenerationpolicy.h
@@ -0,0 +1,227 @@
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * copyright (C) 2003-2006 *
+ * Umbrello UML Modeller Authors <uml-devel@uml.sf.net> *
+ ***************************************************************************/
+
+/* This code generated by:
+ * Author : thomas
+ * Date : Mon Jun 23 2003
+ */
+
+#ifndef CPPCODEGENERATIONPOLICY_H
+#define CPPCODEGENERATIONPOLICY_H
+
+#include <qstring.h>
+#include "codegenpolicyext.h"
+#include "../codegenerationpolicy.h"
+
+class KConfig;
+class CodeGenerationPolicyPage;
+
+class CPPCodeGenerationPolicy : public CodeGenPolicyExt
+{
+ Q_OBJECT
+public:
+
+ static const bool DEFAULT_AUTO_GEN_EMPTY_CONSTRUCTORS;
+ static const bool DEFAULT_AUTO_GEN_ACCESSORS;
+ static const bool DEFAULT_INLINE_ACCESSORS;
+ static const bool DEFAULT_INLINE_OPERATIONS;
+ static const bool DEFAULT_VIRTUAL_DESTRUCTORS;
+ static const bool DEFAULT_PACKAGE_IS_NAMESPACE;
+ static const bool DEFAULT_PUBLIC_ACCESSORS;
+
+ static const bool DEFAULT_STRING_INCLUDE_GLOBAL;
+ static const bool DEFAULT_VECTOR_INCLUDE_GLOBAL;
+
+ static const char * DEFAULT_STRING_CLASS_NAME;
+ static const char * DEFAULT_STRING_CLASS_INCLUDE;
+ static const char * DEFAULT_VECTOR_CLASS_NAME;
+ static const char * DEFAULT_VECTOR_CLASS_INCLUDE;
+ static const char * DEFAULT_VECTOR_METHOD_APPEND;
+ static const char * DEFAULT_VECTOR_METHOD_REMOVE;
+ static const char * DEFAULT_VECTOR_METHOD_INIT;
+ static const char * DEFAULT_OBJECT_METHOD_INIT;
+
+ // Constructors/Destructors
+ //
+
+ /**
+ * Constructors
+ */
+ CPPCodeGenerationPolicy ( KConfig * config = 0 );
+
+ /**
+ * Empty Destructor
+ */
+ virtual ~CPPCodeGenerationPolicy ( );
+
+ // Public attribute accessor methods
+ //
+
+ /**
+ * Set the value of m_inlineAccessors
+ * @param var the new value
+ */
+ void setAccessorsAreInline ( bool var );
+
+ /**
+ * Get the value of m_inlineAccessors
+ * @return value the boolean value of m_inlineAccessors
+ */
+ bool getAccessorsAreInline( );
+
+ /**
+ * Set the value of m_inlineOperations
+ * @param var the new value
+ */
+ void setOperationsAreInline ( bool var );
+
+ /**
+ * Get the value of m_inlineOperations
+ * @return value the boolean value of m_inlineOperations
+ */
+ bool getOperationsAreInline( );
+
+ /**
+ * Set the value of m_virtualDestructors
+ * @param var the new value
+ */
+ void setDestructorsAreVirtual ( bool var );
+
+ /**
+ * Get the value of m_virtualDestructors
+ * @return value the boolean value of m_virtualDestructors
+ */
+ bool getDestructorsAreVirtual( );
+
+ /**
+ * Set the value of m_packageIsNamespace
+ * @param var the new value
+ */
+ void setPackageIsNamespace ( bool var );
+
+ /**
+ * Get the value of m_packageIsNamespace
+ * @return value the boolean value of m_packageIsNamespace
+ */
+ bool getPackageIsNamespace( );
+
+
+ /**
+ * Set the value of m_autoGenerateAccessors
+ * @param var the new value
+ */
+ void setAutoGenerateAccessors ( bool var );
+
+ /**
+ * Get the value of m_autoGenerateAccessors
+ * @return value the boolean value of m_autoGenerateAccessors
+ */
+ bool getAutoGenerateAccessors( );
+
+ /**
+ * Set the value of m_publicAccessors
+ * @param var the new value
+ */
+ void setAccessorsArePublic ( bool var );
+
+ /**
+ * Get the value of m_publicAccessors
+ * @return value the boolean value of m_inlineAccessors
+ */
+ bool getAccessorsArePublic( );
+
+ /** We want to be flexible about which classes are allowed for generation
+ * of the CPP code. In the next 4 methods, we give accessors that allow getting
+ * the names of the classes, and their include files for string and vectors.
+ */
+ QString getStringClassName();
+ QString getStringClassNameInclude();
+ QString getVectorClassName();
+ QString getVectorClassNameInclude();
+
+ /** determine if the string include is global one */
+ bool stringIncludeIsGlobal ();
+ bool vectorIncludeIsGlobal ();
+
+ /** also allow setting these parameters! */
+ void setStringClassName(const QString &value);
+ void setStringClassNameInclude(const QString &value);
+ void setVectorClassName(const QString &value);
+ void setVectorClassNameInclude(const QString &value);
+
+ /** allow setting of these params */
+ void setStringIncludeIsGlobal (bool value);
+ void setVectorIncludeIsGlobal (bool value);
+
+ /** More flexible generation. We want to allow the user to specify how the
+ * bodies of the vector methods should be auto-generated.
+ */
+ QString getVectorMethodAppend(const QString & variableName ="", const QString & itemClassName = "");
+ QString getVectorMethodRemove(const QString & variableName ="", const QString & itemClassName = "");
+ QString getVectorMethodInit(const QString & variableName ="", const QString & itemClassName = "");
+
+ /** Be somewhat flexible about how new object classes are initialized.
+ * Not sure if this should be user configureable. For now, it isnt.
+ */
+ QString getObjectMethodInit(const QString & variableName ="", const QString & itemClassName = "");
+
+ /**
+ * set the defaults for this code generator from the passed generator.
+ */
+ virtual void setDefaults (CPPCodeGenerationPolicy * defaults, bool emitUpdateSignal = true);
+
+ /**
+ * set the defaults from a config file for this code generator from the passed KConfig pointer.
+ */
+ virtual void setDefaults(KConfig * config, bool emitUpdateSignal = true);
+
+ /**
+ * write Default params to passed KConfig pointer.
+ */
+ virtual void writeConfig (KConfig * config);
+
+ /**
+ * Create a new dialog interface for this object.
+ * @return dialog object
+ */
+ CodeGenerationPolicyPage * createPage ( QWidget *parent = 0, const char * name = 0);
+
+protected:
+
+ /**
+ */
+ void init ( );
+
+private:
+
+ bool m_autoGenerateAccessors;
+
+ bool m_inlineAccessors;
+ bool m_inlineOperations;
+ bool m_virtualDestructors;
+ bool m_packageIsNamespace;
+ bool m_publicAccessors;
+
+ bool m_stringIncludeIsGlobal;
+ bool m_vectorIncludeIsGlobal;
+
+ QString m_stringClassName;
+ QString m_stringClassNameInclude;
+ QString m_vectorClassName;
+ QString m_vectorClassNameInclude;
+ QString m_vectorMethodAppendBase;
+ QString m_vectorMethodRemoveBase;
+ QString m_vectorMethodInitBase;
+ QString m_objectMethodInitBase;
+
+};
+
+#endif // CPPCODEGENERATIONPOLICY_H
diff --git a/umbrello/umbrello/codegenerators/cppcodegenerationpolicypage.cpp b/umbrello/umbrello/codegenerators/cppcodegenerationpolicypage.cpp
new file mode 100644
index 00000000..f05833dc
--- /dev/null
+++ b/umbrello/umbrello/codegenerators/cppcodegenerationpolicypage.cpp
@@ -0,0 +1,94 @@
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * copyright (C) 2004-2006 *
+ * Umbrello UML Modeller Authors <uml-devel@uml.sf.net> *
+ ***************************************************************************/
+
+/* This code generated by:
+ * Author : thomas
+ * Date : Wed Jul 30 2003
+ */
+
+// own header
+#include "cppcodegenerationpolicypage.h"
+// qt/kde includes
+#include <kdebug.h>
+#include <klocale.h>
+#include <qlabel.h>
+#include <kcombobox.h>
+#include <qcheckbox.h>
+// app includes
+#include "cppcodegenerationformbase.h"
+#include "../uml.h"
+
+CPPCodeGenerationPolicyPage::CPPCodeGenerationPolicyPage( QWidget *parent, const char *name, CPPCodeGenerationPolicy * policy )
+ : CodeGenerationPolicyPage(parent, name, policy)
+{
+ CodeGenerationPolicy *common = UMLApp::app()->getCommonPolicy();
+ form = new CPPCodeGenerationForm(this);
+ form->m_SelectCommentStyle->setCurrentItem((int)(common->getCommentStyle()));
+ form->setPackageIsANamespace(policy->getPackageIsNamespace());
+ form->setVirtualDestructors(policy->getDestructorsAreVirtual());
+ form->setGenerateAccessorMethods(policy->getAutoGenerateAccessors());
+ form->setGenerateEmptyConstructors(common->getAutoGenerateConstructors());
+ form->setOperationsAreInline(policy->getOperationsAreInline());
+ form->setAccessorsAreInline(policy->getAccessorsAreInline());
+ form->setAccessorsArePublic(policy->getAccessorsArePublic());
+
+ form->m_stringClassHCombo->setCurrentItem(policy->getStringClassName(),true);
+ form->m_listClassHCombo->setCurrentItem(policy->getVectorClassName(),true);
+
+ form->m_stringIncludeFileHistoryCombo->setCurrentItem(policy->getStringClassNameInclude(),true);
+ form->m_listIncludeFileHistoryCombo->setCurrentItem(policy->getVectorClassNameInclude(),true);
+
+ form->m_globalStringCheckBox->setChecked(policy->stringIncludeIsGlobal());
+ form->m_globalListCheckBox->setChecked(policy->vectorIncludeIsGlobal());
+}
+
+CPPCodeGenerationPolicyPage::~CPPCodeGenerationPolicyPage()
+{
+}
+
+void CPPCodeGenerationPolicyPage::apply()
+{
+ CodeGenerationPolicy *common = UMLApp::app()->getCommonPolicy();
+
+ // now do our cpp-specific configs
+ CPPCodeGenerationPolicy * parent = (CPPCodeGenerationPolicy*) m_parentPolicy;
+
+ // block signals so that we don't generate too many sync signals for child code
+ // documents
+ parent->blockSignals(true);
+
+ common->setCommentStyle((CodeGenerationPolicy::CommentStyle ) form->m_SelectCommentStyle->currentItem());
+ common->setAutoGenerateConstructors(form->getGenerateEmptyConstructors());
+ parent->setAutoGenerateAccessors(form->getGenerateAccessorMethods());
+
+ parent->setDestructorsAreVirtual(form->getVirtualDestructors());
+ parent->setPackageIsNamespace(form->getPackageIsANamespace());
+ parent->setAccessorsAreInline(form->getAccessorsAreInline());
+ parent->setOperationsAreInline(form->getOperationsAreInline());
+ parent->setAccessorsArePublic(form->getAccessorsArePublic());
+
+ parent->setStringClassName(form->m_stringClassHCombo->currentText());
+ parent->setStringClassNameInclude(form->m_stringIncludeFileHistoryCombo->currentText());
+ parent->setStringIncludeIsGlobal(form->m_globalStringCheckBox->isChecked());
+
+ parent->setVectorClassName(form->m_listClassHCombo->currentText());
+ parent->setVectorClassNameInclude(form->m_listIncludeFileHistoryCombo->currentText());
+ parent->setVectorIncludeIsGlobal(form->m_globalListCheckBox->isChecked());
+
+ parent->blockSignals(false);
+
+ // now send out modified code content signal
+ common->emitModifiedCodeContentSig();
+
+}
+
+
+#include "cppcodegenerationpolicypage.moc"
diff --git a/umbrello/umbrello/codegenerators/cppcodegenerationpolicypage.h b/umbrello/umbrello/codegenerators/cppcodegenerationpolicypage.h
new file mode 100644
index 00000000..a1d6633b
--- /dev/null
+++ b/umbrello/umbrello/codegenerators/cppcodegenerationpolicypage.h
@@ -0,0 +1,48 @@
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * copyright (C) 2003-2006 *
+ * Umbrello UML Modeller Authors <uml-devel@uml.sf.net> *
+ ***************************************************************************/
+
+/* This code generated by:
+ * Author : thomas
+ * Date : Wed Jul 30 2003
+ */
+
+#ifndef CPPCODEGENERATIONPOLICYPAGE_H
+#define CPPCODEGENERATIONPOLICYPAGE_H
+
+#include "../dialogs/codegenerationpolicypage.h"
+
+#include "cppcodegenerationform.h"
+#include "cppcodegenerationpolicy.h"
+
+/**
+ * @author Brian Thomas
+ */
+
+class CPPCodeGenerationPolicyPage : public CodeGenerationPolicyPage {
+ Q_OBJECT
+public:
+
+ explicit CPPCodeGenerationPolicyPage (QWidget *parent=0, const char *name=0, CPPCodeGenerationPolicy * policy = 0);
+
+ virtual ~CPPCodeGenerationPolicyPage();
+
+protected:
+
+ CPPCodeGenerationForm * form;
+
+public slots:
+
+ void apply();
+
+};
+
+#endif
+
diff --git a/umbrello/umbrello/codegenerators/cppcodegenerator.cpp b/umbrello/umbrello/codegenerators/cppcodegenerator.cpp
new file mode 100644
index 00000000..1130107b
--- /dev/null
+++ b/umbrello/umbrello/codegenerators/cppcodegenerator.cpp
@@ -0,0 +1,366 @@
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * copyright (C) 2004-2006 *
+ * Umbrello UML Modeller Authors <uml-devel@uml.sf.net> *
+ ***************************************************************************/
+
+/* This code generated by:
+ * Author : thomas
+ * Date : Thu Jun 19 2003
+ */
+
+// own header
+#include "cppcodegenerator.h"
+
+// qt/kde includes
+#include <qregexp.h>
+#include <kdebug.h>
+#include <kconfig.h>
+
+// app includes
+#include "cppcodedocumentation.h"
+#include "cppcodegenerationpolicy.h"
+#include "cppsourcecodedocument.h"
+#include "cppheadercodedocument.h"
+#include "codegen_utils.h"
+#include "codeviewerdialog.h"
+#include "../codedocumentlist.h"
+#include "../uml.h"
+
+const bool CPPCodeGenerator::DEFAULT_BUILD_MAKEFILE = false;
+
+// Constructors/Destructors
+//
+
+CPPCodeGenerator::CPPCodeGenerator () {
+ initAttributes();
+}
+
+CPPCodeGenerator::~CPPCodeGenerator ( ) {
+ // destroy all separately owned codedocuments (e.g. header docs)
+ CodeDocument *doc;
+ for (CodeDocumentListIt it(m_headercodedocumentVector);
+ (doc = it.current()) != NULL; ++it)
+ delete doc;
+ m_headercodedocumentVector.clear();
+}
+
+//
+// Methods
+//
+
+// Accessor methods
+//
+
+/**
+ * returns "C++"
+ */
+Uml::Programming_Language CPPCodeGenerator::getLanguage() {
+ return Uml::pl_Cpp;
+}
+
+/**
+ * Set the value of m_createMakefile
+ * @param new_var the new value of m_createMakefile
+ */
+void CPPCodeGenerator::setCreateProjectMakefile ( bool buildIt) {
+ m_createMakefile = buildIt;
+ CodeDocument * antDoc = findCodeDocumentByID(CPPMakefileCodeDocument::DOCUMENT_ID_VALUE);
+ if (antDoc)
+ antDoc->setWriteOutCode(buildIt);
+}
+
+/**
+ * Get the value of m_createMakefile
+ * @return the value of m_createMakefile
+ */
+bool CPPCodeGenerator::getCreateProjectMakefile ( ) {
+ return m_createMakefile;
+}
+
+bool CPPCodeGenerator::addHeaderCodeDocument ( CPPHeaderCodeDocument * doc )
+{
+
+ QString tag = doc->getID();
+
+ // assign a tag if one doesn't already exist
+ if(tag.isEmpty())
+ {
+ tag = "cppheader"+ID2STR(doc->getParentClassifier()->getID());
+ doc->setID(tag);
+ }
+
+ if(m_codeDocumentDictionary.find(tag))
+ return false; // return false, we already have some object with this tag in the list
+ else
+ m_codeDocumentDictionary.insert(tag, doc);
+
+ m_headercodedocumentVector.append(doc);
+ return true;
+}
+
+/**
+ * Remove a header CodeDocument object from m_headercodedocumentVector List
+ */
+bool CPPCodeGenerator::removeHeaderCodeDocument ( CPPHeaderCodeDocument * remove_object ) {
+ QString tag = remove_object->getID();
+ if(!(tag.isEmpty()))
+ m_codeDocumentDictionary.remove(tag);
+ else
+ return false;
+
+ m_headercodedocumentVector.remove(remove_object);
+ return true;
+}
+
+// In the C++ version, we need to make both source and header files as well
+// as the makefile available.
+CodeViewerDialog * CPPCodeGenerator::getCodeViewerDialog ( QWidget* parent, CodeDocument *doc,
+ Settings::CodeViewerState state)
+{
+
+ ClassifierCodeDocument * cdoc = dynamic_cast<ClassifierCodeDocument*>(doc);
+ if(!cdoc)
+ // bah..not a classcode document?? then just use vanilla version
+ return CodeGenerator::getCodeViewerDialog(parent,doc,state);
+ else {
+ // build with passed (source) code document
+ CodeViewerDialog *dialog;
+
+ // use classifier to find appropriate header document
+ UMLClassifier * c = cdoc->getParentClassifier();
+ CPPHeaderCodeDocument * hdoc = findHeaderCodeDocumentByClassifier(c);
+ if(hdoc)
+ {
+ // if we have a header document..build with that
+ dialog = new CodeViewerDialog(parent, hdoc, state);
+ dialog->addCodeDocument(doc);
+ } else
+ // shouldn't happen, but lets try to gracefully deliver something.
+ dialog = new CodeViewerDialog(parent, doc, state);
+
+ // add in makefile if available and desired
+ if(getCreateProjectMakefile())
+ dialog->addCodeDocument(findCodeDocumentByID(CPPMakefileCodeDocument::DOCUMENT_ID_VALUE));
+
+ return dialog;
+ }
+}
+
+// Other methods
+//
+
+// Change the following dataTypes to the ones the user really
+// wants in their code. Not yet complete.
+QString CPPCodeGenerator::fixTypeName(const QString &string)
+{
+ return cleanName(string);
+}
+
+// special method needed so that we write out the header code documents
+void CPPCodeGenerator::saveToXMI ( QDomDocument & doc, QDomElement & root ) {
+ QDomElement docElement = doc.createElement( "codegenerator" );
+ docElement.setAttribute("language", "C++");
+
+ CodeDocumentList * docList = getCodeDocumentList();
+ for (CodeDocument * codeDoc = docList->first(); codeDoc; codeDoc= docList->next())
+ codeDoc->saveToXMI(doc, docElement);
+
+ for (CodeDocument * hcodeDoc = m_headercodedocumentVector.first(); hcodeDoc; hcodeDoc=m_headercodedocumentVector.next())
+ hcodeDoc->saveToXMI(doc, docElement);
+
+ root.appendChild( docElement );
+}
+
+/**
+ * Force a synchronize of this code generator, and its present contents, to that of the parent UMLDocument.
+ * Need to override parent method because we have header documents to consider too.
+ */
+void CPPCodeGenerator::syncCodeToDocument ( ) {
+
+ CodeDocumentList * docList = getCodeDocumentList();
+
+ for (CodeDocument * doc = docList->first(); doc; doc=docList->next())
+ doc->synchronize();
+
+ for (CodeDocument * hcodeDoc = m_headercodedocumentVector.first(); hcodeDoc; hcodeDoc=m_headercodedocumentVector.next())
+ hcodeDoc->synchronize();
+
+}
+
+/**
+ * Write out all code documents to file as appropriate.
+ */
+void CPPCodeGenerator::writeCodeToFile ( )
+{
+ // write all source documents (incl. Makefile)
+ writeListedCodeDocsToFile(getCodeDocumentList());
+
+ // write all header documents
+ writeListedCodeDocsToFile(&m_headercodedocumentVector);
+
+}
+
+// overridden because we need to be able to generate code for
+// both the header and source documents
+void CPPCodeGenerator::writeCodeToFile ( UMLClassifierList & concepts) {
+ CodeDocumentList docs;
+ docs.setAutoDelete(false);
+
+ for (UMLClassifier *concept= concepts.first(); concept; concept= concepts.next())
+ {
+ CodeDocument * doc = findCodeDocumentByClassifier(concept);
+ if(doc)
+ docs.append(doc);
+ CodeDocument * hdoc = findHeaderCodeDocumentByClassifier(concept);
+ if(hdoc)
+ docs.append(hdoc);
+ }
+
+ writeListedCodeDocsToFile(&docs);
+}
+
+
+/**
+ * Find a cppheadercodedocument by the given classifier.
+ * @return CPPHeaderCodeDocument
+* @param classifier
+*/
+CPPHeaderCodeDocument * CPPCodeGenerator::findHeaderCodeDocumentByClassifier (UMLClassifier * classifier )
+{
+ CodeDocument * doc = findCodeDocumentByID("cppheader"+ID2STR(classifier->getID()));
+ return dynamic_cast<CPPHeaderCodeDocument*>(doc);
+}
+
+/**
+ * @return ClassifierCodeDocument
+ * @param classifier The classifier for which the CodeDocument is to be created
+ */
+// source document version.
+CodeDocument * CPPCodeGenerator::newClassifierCodeDocument (UMLClassifier * classifier)
+{
+ ClassifierCodeDocument *doc = new CPPSourceCodeDocument(classifier);
+ doc->initCodeClassFields();
+ return doc;
+}
+
+CPPHeaderCodeDocument * CPPCodeGenerator::newHeaderClassifierCodeDocument (UMLClassifier * classifier)
+{
+ CPPHeaderCodeDocument *doc = new CPPHeaderCodeDocument(classifier);
+ doc->initCodeClassFields();
+ return doc;
+}
+
+/**
+ * @return CPPMakefileCodeDocument
+ * @param this
+ */
+CPPMakefileCodeDocument * CPPCodeGenerator::newMakefileCodeDocument ( ) {
+ return new CPPMakefileCodeDocument();
+}
+
+
+/**
+ * Overloaded so that we may have both source and header documents for each
+ * classifier.
+ */
+void CPPCodeGenerator::initFromParentDocument( ) {
+
+ // Walk through the document converting classifiers into
+ // classifier code documents as needed (e.g only if doesn't exist)
+ UMLClassifierList concepts = UMLApp::app()->getDocument()->getClassesAndInterfaces();
+ for (UMLClassifier *c = concepts.first(); c; c = concepts.next())
+ {
+
+ // Doesn't exist? Then build one.
+ CodeDocument * codeDoc = findCodeDocumentByClassifier(c);
+ if (!codeDoc)
+ {
+ codeDoc = newClassifierCodeDocument(c);
+ codeDoc->synchronize();
+ addCodeDocument(codeDoc); // this will also add a unique tag to the code document
+ }
+
+ CPPHeaderCodeDocument * hcodeDoc = findHeaderCodeDocumentByClassifier(c);
+ if (!hcodeDoc)
+ {
+ hcodeDoc = newHeaderClassifierCodeDocument(c);
+ hcodeDoc->synchronize();
+ addHeaderCodeDocument(hcodeDoc); // this will also add a unique tag to the code document
+ }
+ }
+
+}
+
+// need to worry about adding both source, and header documents for each
+// classifier
+void CPPCodeGenerator::checkAddUMLObject (UMLObject * obj) {
+ if (!obj)
+ return;
+
+ // if the obj being created is a native data type
+ // there's no reason to create a .h/.cpp file
+ if (isReservedKeyword(obj->getName()))
+ return;
+
+ UMLClassifier * c = dynamic_cast<UMLClassifier*>(obj);
+ if(c) {
+ CodeDocument * cDoc = newClassifierCodeDocument(c);
+ CPPHeaderCodeDocument * hcodeDoc = newHeaderClassifierCodeDocument(c);
+ addCodeDocument(cDoc);
+ addHeaderCodeDocument(hcodeDoc); // this will also add a unique tag to the code document
+ }
+}
+
+// need to worry about removing both source, and header documents for each
+// classifier
+void CPPCodeGenerator::checkRemoveUMLObject (UMLObject * obj)
+{
+
+ if (!obj)
+ return;
+
+ UMLClassifier * c = dynamic_cast<UMLClassifier*>(obj);
+ if(c) {
+
+ // source
+ ClassifierCodeDocument * cDoc = (ClassifierCodeDocument*) findCodeDocumentByClassifier(c);
+ if (cDoc)
+ removeCodeDocument(cDoc);
+
+ // header
+ CPPHeaderCodeDocument * hcodeDoc = findHeaderCodeDocumentByClassifier(c);
+ if (hcodeDoc)
+ removeHeaderCodeDocument(hcodeDoc);
+ }
+
+}
+
+void CPPCodeGenerator::initAttributes ( )
+{
+ m_createMakefile = false;
+
+ UMLApp::app()->setPolicyExt ( new CPPCodeGenerationPolicy(UMLApp::app()->getConfig()) );
+
+ // load Classifier documents from parent document
+ //initFromParentDocument();
+}
+
+QStringList CPPCodeGenerator::defaultDatatypes() {
+ return Codegen_Utils::cppDatatypes();
+}
+
+const QStringList CPPCodeGenerator::reservedKeywords() const {
+ return Codegen_Utils::reservedCppKeywords();
+}
+
+void CPPCodeGenerator::createDefaultStereotypes (){
+ Codegen_Utils::createCppStereotypes();
+}
+
+#include "cppcodegenerator.moc"
diff --git a/umbrello/umbrello/codegenerators/cppcodegenerator.h b/umbrello/umbrello/codegenerators/cppcodegenerator.h
new file mode 100644
index 00000000..7104d403
--- /dev/null
+++ b/umbrello/umbrello/codegenerators/cppcodegenerator.h
@@ -0,0 +1,167 @@
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * copyright (C) 2004-2006 *
+ * Umbrello UML Modeller Authors <uml-devel@uml.sf.net> *
+ ***************************************************************************/
+
+/* This code generated by:
+ * Author : thomas
+ * Date : Thu Jun 19 2003
+ */
+
+
+#ifndef CPPCODEGENERATOR_H
+#define CPPCODEGENERATOR_H
+
+#include <qstring.h>
+#include "../codedocumentlist.h"
+#include "../codeviewerstate.h"
+#include "../codegenerator.h"
+#include "../umldoc.h"
+#include "cppmakecodedocument.h"
+
+class CodeViewerDialog;
+class CPPHeaderCodeDocument;
+class CodeBlockWithComments;
+class KConfig;
+
+class CPPCodeGenerator : public CodeGenerator
+{
+ Q_OBJECT
+public:
+
+ static const bool DEFAULT_BUILD_MAKEFILE;
+
+ // Constructors/Destructors
+ //
+
+ /**
+ * Basic Constructor
+ */
+ CPPCodeGenerator ();
+
+ /**
+ * Empty Destructor
+ */
+ virtual ~CPPCodeGenerator ( );
+
+ /**
+ * Set the value of m_createMakefile
+ * @param new_var the new value of m_createMakefile
+ */
+ void setCreateProjectMakefile ( bool new_var );
+
+ /**
+ * Get the value of m_createMakefile
+ * @return the value of m_createMakefile
+ */
+ bool getCreateProjectMakefile ( );
+
+ // Public attribute accessor methods
+ //
+
+ QString fixTypeName(const QString &string);
+
+ /**
+ * Add a header CodeDocument object from m_headercodedocumentVector List
+ */
+ bool addHeaderCodeDocument ( CPPHeaderCodeDocument * doc );
+
+ /**
+ * Remove a header CodeDocument object from m_headercodedocumentVector List
+ */
+ bool removeHeaderCodeDocument ( CPPHeaderCodeDocument * remove_object );
+
+ /**
+ * returns "Cpp"
+ */
+ Uml::Programming_Language getLanguage();
+
+ // generate 2 different types of classifier code documents.
+ CodeDocument * newClassifierCodeDocument (UMLClassifier * classifier);
+ CPPHeaderCodeDocument * newHeaderClassifierCodeDocument (UMLClassifier * classifier);
+
+ /** Get the editing dialog for this code document
+ */
+ virtual CodeViewerDialog * getCodeViewerDialog( QWidget* parent, CodeDocument * doc,
+ Settings::CodeViewerState state);
+
+ /**
+ * Write out all code documents to file as appropriate.
+ */
+ virtual void writeCodeToFile ( );
+
+ // this method is here to provide class wizard the
+ // ability to write out only those classes which
+ // are selected by the user.
+ virtual void writeCodeToFile(UMLClassifierList &list);
+
+ /**
+ * Add C++ primitives as datatypes
+ */
+ QStringList defaultDatatypes();
+
+ /**
+ * Save the XMI representation of this object
+ */
+ virtual void saveToXMI ( QDomDocument & doc, QDomElement & root );
+
+ /**
+ * get list of reserved keywords
+ */
+ virtual const QStringList reservedKeywords() const;
+
+ /**
+ * Add the default stereotypes for c++ (constructor, int etc)
+ */
+ virtual void createDefaultStereotypes ();
+
+ void initFromParentDocument( );
+
+protected:
+
+ /**
+ * @return CPPMakeCodeDocument
+ */
+ CPPMakefileCodeDocument * newMakefileCodeDocument ( );
+
+ /**
+ * Find a cppheadercodedocument by the given classifier.
+ * @return CPPHeaderCodeDocument
+ * @param classifier
+ */
+ CPPHeaderCodeDocument * findHeaderCodeDocumentByClassifier (UMLClassifier * classifier );
+
+private:
+
+ bool m_createMakefile;
+
+ // a separate list for recording the header documents
+ CodeDocumentList m_headercodedocumentVector;
+
+ void initAttributes ( ) ;
+
+public slots:
+
+ /** These 2 functions check for adding or removing objects to the UMLDocument
+ * they are need to be overridden here because unlike in the Java (or most other lang)
+ * we add 2 types of classifiercodedocument per classifier,
+ * e.g. a "source" and a "header" document.
+ */
+ virtual void checkAddUMLObject (UMLObject * obj);
+ virtual void checkRemoveUMLObject (UMLObject * obj);
+
+ /**
+ * Force a synchronize of this code generator, and its present contents, to that of the parent UMLDocument.
+ * "UserGenerated" code will be preserved, but Autogenerated contents will be updated/replaced
+ * or removed as is apppropriate.
+ */
+ virtual void syncCodeToDocument ( );
+};
+
+#endif // CPPCODEGENERATOR_H
diff --git a/umbrello/umbrello/codegenerators/cppheaderclassdeclarationblock.cpp b/umbrello/umbrello/codegenerators/cppheaderclassdeclarationblock.cpp
new file mode 100644
index 00000000..ea5612c9
--- /dev/null
+++ b/umbrello/umbrello/codegenerators/cppheaderclassdeclarationblock.cpp
@@ -0,0 +1,160 @@
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * copyright (C) 2004-2006 *
+ * Umbrello UML Modeller Authors <uml-devel@uml.sf.net> *
+ ***************************************************************************/
+
+/* This code generated by:
+ * Author : thomas
+ * Date : Mon Sep 1 2003
+ */
+
+#include "cppheaderclassdeclarationblock.h"
+#include "cppcodegenerator.h"
+#include "cppcodegenerationpolicy.h"
+#include "cppcodedocumentation.h"
+#include "../model_utils.h"
+#include "../uml.h"
+
+// Constructors/Destructors
+//
+
+CPPHeaderClassDeclarationBlock::CPPHeaderClassDeclarationBlock
+ ( CPPHeaderCodeDocument * parentDoc, const QString &startText, const QString &endText, const QString &comment)
+ : OwnedHierarchicalCodeBlock(parentDoc->getParentClassifier(), parentDoc, startText, endText, comment)
+{
+ init(parentDoc, comment);
+}
+
+CPPHeaderClassDeclarationBlock::~CPPHeaderClassDeclarationBlock ( ) { }
+
+//
+// Methods
+//
+
+/**
+ * load params from the appropriate XMI element node.
+ */
+void CPPHeaderClassDeclarationBlock::loadFromXMI ( QDomElement & root )
+{
+ setAttributesFromNode(root);
+}
+
+/** set the class attributes from a passed object
+ */
+void CPPHeaderClassDeclarationBlock::setAttributesFromObject (TextBlock * obj)
+{
+ HierarchicalCodeBlock::setAttributesFromObject(obj);
+}
+
+/**
+ * Save the XMI representation of this object
+ */
+void CPPHeaderClassDeclarationBlock::saveToXMI ( QDomDocument & doc, QDomElement & root ) {
+ QDomElement blockElement = doc.createElement( "cppheaderclassdeclarationblock" );
+
+ setAttributesOnNode(doc, blockElement);
+
+ root.appendChild( blockElement );
+}
+
+// Accessor methods
+//
+
+// Other methods
+//
+
+/**
+ * update the start and end text for this hierarchicalcodeblock.
+ */
+void CPPHeaderClassDeclarationBlock::updateContent ( )
+{
+
+ CPPHeaderCodeDocument *parentDoc = dynamic_cast<CPPHeaderCodeDocument*>(getParentDocument());
+ UMLClassifier *c = parentDoc->getParentClassifier();
+ QString endLine = UMLApp::app()->getCommonPolicy()->getNewLineEndingChars();
+ bool isInterface = parentDoc->parentIsInterface(); // a little shortcut
+ QString CPPHeaderClassName = CodeGenerator::cleanName(c->getName());
+ bool forceDoc = UMLApp::app()->getCommonPolicy()->getCodeVerboseDocumentComments();
+
+ // COMMENT
+
+ //check if class is abstract.. it should have abstract methods
+ if(!isInterface && c->getAbstract() && !c->hasAbstractOps())
+ {
+ getComment()->setText("******************************* Abstract Class ****************************"+endLine
+ +CPPHeaderClassName+" does not have any pure virtual methods, but its author"+endLine
+ +" defined it as an abstract class, so you should not use it directly."+endLine
+ +" Inherit from it instead and create only objects from the derived classes"+endLine
+ +"*****************************************************************************");
+ } else {
+ if(isInterface)
+ getComment()->setText("Interface "+CPPHeaderClassName+endLine+c->getDoc());
+ else
+ getComment()->setText("Class "+CPPHeaderClassName+endLine+c->getDoc());
+ }
+
+ if(forceDoc || !c->getDoc().isEmpty())
+ getComment()->setWriteOutText(true);
+ else
+ getComment()->setWriteOutText(false);
+
+
+ // Now set START/ENDING Text
+ QString startText = "";
+
+ /*
+ */
+
+ /*
+ if(parentDoc->parentIsInterface())
+ startText.append("interface ");
+ else
+ */
+ startText.append("class ");
+
+ startText.append(CPPHeaderClassName);
+
+ // write inheritances out
+ UMLClassifierList superclasses = c->findSuperClassConcepts();
+ int nrof_superclasses = superclasses.count();
+
+ // write out inheritance
+ int i = 0;
+ if(nrof_superclasses >0)
+ startText.append(" : ");
+ for (UMLClassifier * concept= superclasses.first(); concept; concept = superclasses.next())
+ {
+ startText.append(concept->getVisibility().toString() + ' ' +
+ CodeGenerator::cleanName(concept->getName()));
+ if(i != (nrof_superclasses-1))
+ startText.append(", ");
+ i++;
+ }
+
+ // Set the header and end text for the hier.codeblock
+ setStartText(startText+" {");
+
+ // setEndText("}"); // not needed
+
+}
+
+void CPPHeaderClassDeclarationBlock::init (CPPHeaderCodeDocument *parentDoc, const QString &comment)
+{
+
+ setComment(new CPPCodeDocumentation(parentDoc));
+ getComment()->setText(comment);
+
+ setEndText("};");
+
+ updateContent();
+
+}
+
+
+#include "cppheaderclassdeclarationblock.moc"
diff --git a/umbrello/umbrello/codegenerators/cppheaderclassdeclarationblock.h b/umbrello/umbrello/codegenerators/cppheaderclassdeclarationblock.h
new file mode 100644
index 00000000..683f0475
--- /dev/null
+++ b/umbrello/umbrello/codegenerators/cppheaderclassdeclarationblock.h
@@ -0,0 +1,67 @@
+
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the 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 code generated by:
+ * Author : thomas
+ * Date : Mon Sep 1 2003
+ */
+
+#ifndef CPPHEADERCLASSDECLARATIONBLOCK_H
+#define CPPHEADERCLASSDECLARATIONBLOCK_H
+
+#include <qstring.h>
+
+#include "cppheadercodedocument.h"
+#include "../ownedhierarchicalcodeblock.h"
+
+class CPPHeaderClassDeclarationBlock : public OwnedHierarchicalCodeBlock
+{
+ Q_OBJECT
+public:
+
+ // Constructors/Destructors
+ //
+
+ /**
+ * Empty Constructor
+ */
+ explicit CPPHeaderClassDeclarationBlock ( CPPHeaderCodeDocument * parentDoc, const QString &start = "", const QString &endText = "}", const QString &comment = "");
+
+ /**
+ * Empty Destructor
+ */
+ virtual ~CPPHeaderClassDeclarationBlock ( );
+
+ /**
+ * Save the XMI representation of this object
+ */
+ virtual void saveToXMI ( QDomDocument & doc, QDomElement & root );
+
+ virtual void loadFromXMI ( QDomElement & root );
+
+protected:
+
+ /** set the class attributes from a passed object
+ */
+ virtual void setAttributesFromObject (TextBlock * obj);
+
+ /**
+ * Update the start/end text of this codeblock.
+ */
+ void updateContent ( );
+
+private:
+
+ void init (CPPHeaderCodeDocument * parent, const QString &comment);
+
+};
+
+#endif // CPPHEADERCLASSDECLARATIONBLOCK_H
diff --git a/umbrello/umbrello/codegenerators/cppheadercodeaccessormethod.cpp b/umbrello/umbrello/codegenerators/cppheadercodeaccessormethod.cpp
new file mode 100644
index 00000000..0ab67b85
--- /dev/null
+++ b/umbrello/umbrello/codegenerators/cppheadercodeaccessormethod.cpp
@@ -0,0 +1,170 @@
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * copyright (C) 2004-2007 *
+ * Umbrello UML Modeller Authors <uml-devel@uml.sf.net> *
+ ***************************************************************************/
+
+/* This code generated by:
+ * Author : thomas
+ * Date : Fri Aug 31 2003
+ */
+
+// own header
+#include "cppheadercodeaccessormethod.h"
+
+// qt/kde includes
+#include <kdebug.h>
+
+// local includes
+#include "../attribute.h"
+#include "../classifiercodedocument.h"
+#include "cppcodegenerator.h"
+#include "../umlobject.h"
+#include "../umlrole.h"
+#include "../uml.h"
+
+#include "cppsourcecodedocument.h"
+#include "cppcodegenerationpolicy.h"
+#include "cppcodeclassfield.h"
+#include "cppcodedocumentation.h"
+
+// Constructors/Destructors
+//
+
+CPPHeaderCodeAccessorMethod::CPPHeaderCodeAccessorMethod ( CodeClassField * field, CodeAccessorMethod::AccessorType type)
+ : CodeAccessorMethod ( field )
+{
+ setType(type);
+}
+
+void CPPHeaderCodeAccessorMethod::update()
+{
+ updateMethodDeclaration();
+ updateContent();
+}
+
+CPPHeaderCodeAccessorMethod::~CPPHeaderCodeAccessorMethod ( ) { }
+
+// Other
+//
+
+// we basically want to update the body of this method
+void CPPHeaderCodeAccessorMethod::updateContent( )
+{
+ CodeClassField * parentField = getParentClassField();
+ CPPCodeClassField * cppfield = dynamic_cast<CPPCodeClassField*>(parentField);
+ CodeGenPolicyExt *pe = UMLApp::app()->getPolicyExt();
+ CPPCodeGenerationPolicy * policy = dynamic_cast<CPPCodeGenerationPolicy*>(pe);
+ bool isInlineMethod = policy->getAccessorsAreInline( );
+ Uml::Visibility scope = parentField->getVisibility();
+ QString variableName = cppfield->getFieldName();
+ QString itemClassName = cppfield->getTypeName();
+ QString text;
+
+ if(isInlineMethod) {
+ switch(getType()) {
+ case CodeAccessorMethod::ADD:
+ text = policy->getVectorMethodAppend(variableName, itemClassName);
+ break;
+ case CodeAccessorMethod::REMOVE:
+ text = policy->getVectorMethodRemove(variableName, itemClassName);
+ break;
+ case CodeAccessorMethod::SET:
+ text = variableName+" = value;";
+ break;
+ case CodeAccessorMethod::LIST:
+ case CodeAccessorMethod::GET:
+ default:
+ text = "return " + variableName + ';';
+ break;
+ }
+ }
+
+ setText(text);
+}
+
+// we basically want to update the start text of this method
+void CPPHeaderCodeAccessorMethod::updateMethodDeclaration()
+{
+
+ CodeClassField * parentField = getParentClassField();
+ ClassifierCodeDocument * doc = parentField->getParentDocument();
+ CodeGenPolicyExt *pe = UMLApp::app()->getPolicyExt();
+ CPPCodeGenerationPolicy * policy = dynamic_cast<CPPCodeGenerationPolicy*>(pe);
+ CPPCodeClassField * cppfield = dynamic_cast<CPPCodeClassField*>(parentField);
+
+ bool isInlineMethod = policy->getAccessorsAreInline( );
+
+ QString vectorClassName = policy->getVectorClassName();
+ QString fieldName = cppfield->getFieldName();
+ QString fieldType = cppfield->getTypeName();
+ QString objectType = cppfield->getListObjectType();
+ if(objectType.isEmpty())
+ objectType = fieldName;
+
+ QString methodReturnType = "void";
+ QString methodName;
+ QString methodParams;
+ QString headerText;
+ QString endLine = UMLApp::app()->getCommonPolicy()->getNewLineEndingChars();
+
+ switch(getType()) {
+ case CodeAccessorMethod::ADD:
+ methodName = "add_"+fieldType;
+ methodReturnType = "void";
+ methodParams = objectType+" value ";
+ headerText = "Add a "+fieldName+" object to the "+fieldName+"List"+endLine+getParentObject()->getDoc()+endLine+"@return void";
+ break;
+ case CodeAccessorMethod::REMOVE:
+ methodName = "remove_"+fieldType;
+ methodParams = objectType+" value ";
+ methodReturnType = "void";
+ headerText = "Remove a "+fieldName+" object from the "+fieldName+"List"+endLine+getParentObject()->getDoc()+endLine+"@return void";
+ break;
+ case CodeAccessorMethod::LIST:
+ methodName = "get_"+fieldType+"_list";
+ methodReturnType = vectorClassName;
+ headerText = "Get the "+fieldName+"List"+endLine+getParentObject()->getDoc()+endLine+"@return "+vectorClassName+"with list of objects";
+ break;
+ case CodeAccessorMethod::SET:
+ methodName = "set_"+fieldName;
+ methodParams = fieldType+" value ";
+ methodReturnType = "void";
+ headerText = "Set the value of "+fieldName+endLine+getParentObject()->getDoc()+endLine+"@param value the value of "+fieldName;
+ break;
+ case CodeAccessorMethod::GET:
+ default:
+ methodName = "get_"+fieldName;
+ methodReturnType = fieldType;
+ headerText = "Get the value of "+fieldName+endLine+getParentObject()->getDoc()+endLine+"@return the value of "+fieldName;
+ break;
+ }
+
+ // set header
+ CPPCodeDocumentation * header = new CPPCodeDocumentation(doc);
+ if(!getParentObject()->getDoc().isEmpty())
+ header->setText(headerText);
+ setComment(header);
+
+ // set start/end method text
+ QString startText = methodReturnType + ' ' + methodName + " (" + methodParams +')';
+ if (isInlineMethod)
+ startText += " {";
+ else
+ startText += ';';
+ QString endText = (isInlineMethod ? "}" : "");
+
+ setStartMethodText(startText);
+ setEndMethodText(endText);
+
+ setOverallIndentationLevel(1);
+}
+
+
+
+#include "cppheadercodeaccessormethod.moc"
diff --git a/umbrello/umbrello/codegenerators/cppheadercodeaccessormethod.h b/umbrello/umbrello/codegenerators/cppheadercodeaccessormethod.h
new file mode 100644
index 00000000..7b39fc6d
--- /dev/null
+++ b/umbrello/umbrello/codegenerators/cppheadercodeaccessormethod.h
@@ -0,0 +1,57 @@
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the 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 code generated by:
+ * Author : thomas
+ * Date : Fri Aug 31 2003
+ */
+
+#ifndef CPPHEADERACCESSORMETHOD_H
+#define CPPHEADERACCESSORMETHOD_H
+
+#include "../codeaccessormethod.h"
+
+#include <qstring.h>
+
+class CodeClassField;
+
+class CPPHeaderCodeAccessorMethod : public CodeAccessorMethod
+{
+ Q_OBJECT
+public:
+
+ // Constructors/Destructors
+ //
+
+ /**
+ * Empty Constructor
+ */
+ CPPHeaderCodeAccessorMethod ( CodeClassField * field, CodeAccessorMethod::AccessorType type);
+
+ /**
+ * Empty Destructor
+ */
+ virtual ~CPPHeaderCodeAccessorMethod ( );
+
+ /**
+ * Must be called before this object is usable
+ */
+ void update();
+
+protected:
+
+ virtual void updateMethodDeclaration();
+ virtual void updateContent();
+
+private:
+
+};
+
+#endif // CPPHEADERACCESSORMETHOD_H
diff --git a/umbrello/umbrello/codegenerators/cppheadercodeclassfielddeclarationblock.cpp b/umbrello/umbrello/codegenerators/cppheadercodeclassfielddeclarationblock.cpp
new file mode 100644
index 00000000..0fdfeb0a
--- /dev/null
+++ b/umbrello/umbrello/codegenerators/cppheadercodeclassfielddeclarationblock.cpp
@@ -0,0 +1,78 @@
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the 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 code generated by:
+ * Author : thomas
+ * Date : Mon Sep 1 2003
+ */
+
+#include "cppheadercodeclassfielddeclarationblock.h"
+
+#include "cppcodeclassfield.h"
+#include "cppheadercodedocument.h"
+
+// Constructors/Destructors
+//
+
+CPPHeaderCodeClassFieldDeclarationBlock::CPPHeaderCodeClassFieldDeclarationBlock ( CodeClassField * parent )
+ : CodeClassFieldDeclarationBlock ( parent )
+{
+ setOverallIndentationLevel(1);
+ updateContent();
+}
+
+CPPHeaderCodeClassFieldDeclarationBlock::~CPPHeaderCodeClassFieldDeclarationBlock ( ) { }
+
+//
+// Methods
+//
+
+// Other methods
+//
+
+/**
+ */
+void CPPHeaderCodeClassFieldDeclarationBlock::updateContent( )
+{
+ UMLObject *umlparent = CodeClassFieldDeclarationBlock::getParentObject();
+ if (umlparent == NULL) {
+ return;
+ }
+
+ CodeClassField * cf = getParentClassField();
+ CPPCodeClassField * hcppcf = dynamic_cast<CPPCodeClassField*>(cf);
+
+ // Set the comment
+ QString notes = umlparent->getDoc();
+ getComment()->setText(notes);
+ if(notes.isEmpty())
+ getComment()->setWriteOutText(false);
+ else
+ getComment()->setWriteOutText(true);
+
+
+ // Set the body
+ QString staticValue = umlparent->getStatic() ? "static " : "";
+ QString typeName = hcppcf->getTypeName();
+ QString fieldName = hcppcf->getFieldName();
+
+ // Ugh. Sloppy exception.
+ if (!cf->parentIsAttribute() && !cf->fieldIsSingleValue())
+ typeName = hcppcf->getListFieldClassName();
+
+ QString body = staticValue + ' ' + typeName + ' ' + fieldName + ';';
+
+ setText(body);
+
+}
+
+
+
+#include "cppheadercodeclassfielddeclarationblock.moc"
diff --git a/umbrello/umbrello/codegenerators/cppheadercodeclassfielddeclarationblock.h b/umbrello/umbrello/codegenerators/cppheadercodeclassfielddeclarationblock.h
new file mode 100644
index 00000000..755507c6
--- /dev/null
+++ b/umbrello/umbrello/codegenerators/cppheadercodeclassfielddeclarationblock.h
@@ -0,0 +1,51 @@
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the 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 code generated by:
+ * Author : thomas
+ * Date : Mon Sep 1 2003
+ */
+
+#ifndef CPPHEADERCODECLASSFIELDDECLARATIONBLOCK_H
+#define CPPHEADERCODECLASSFIELDDECLARATIONBLOCK_H
+
+#include <qstring.h>
+
+#include "../codeclassfielddeclarationblock.h"
+
+class CPPHeaderCodeClassFieldDeclarationBlock : public CodeClassFieldDeclarationBlock
+{
+ Q_OBJECT
+public:
+
+ // Constructors/Destructors
+ //
+
+ /**
+ * Constructor
+ */
+ CPPHeaderCodeClassFieldDeclarationBlock ( CodeClassField * parent );
+
+ /**
+ * Empty Destructor
+ */
+ virtual ~CPPHeaderCodeClassFieldDeclarationBlock ( );
+
+protected:
+
+ // this will be called by syncToParent whenever the parent object is "modified"
+ void updateContent ( );
+
+private:
+
+
+};
+
+#endif // CPPHEADERCODECLASSFIELDDECLARATIONBLOCK_H
diff --git a/umbrello/umbrello/codegenerators/cppheadercodedocument.cpp b/umbrello/umbrello/codegenerators/cppheadercodedocument.cpp
new file mode 100644
index 00000000..fe909c5d
--- /dev/null
+++ b/umbrello/umbrello/codegenerators/cppheadercodedocument.cpp
@@ -0,0 +1,813 @@
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * copyright (C) 2004-2007 *
+ * Umbrello UML Modeller Authors <uml-devel@uml.sf.net> *
+ ***************************************************************************/
+
+/* This code generated by:
+ * Author : thomas
+ * Date : Thu Aug 28 2003
+ */
+
+/**
+ We carve the CPP document up into 2 documents, "source" and "header".
+ This one represents the header portion.
+ The sections of each are as follows:
+
+ * header
+ * includes
+ * import statements
+ * class declaration
+ * guts of the class (e.g. field decl, accessor methods, operations, dependant classes)
+*/
+
+// own header
+#include "cppheadercodedocument.h"
+
+// qt/kde includes
+#include <qregexp.h>
+#include <kdebug.h>
+
+// local includes
+#include "cppcodegenerator.h"
+#include "cppcodegenerationpolicy.h"
+#include "cppcodedocumentation.h"
+#include "cppheadercodeaccessormethod.h"
+#include "cppheadercodeoperation.h"
+#include "cppheaderclassdeclarationblock.h"
+#include "cppheadercodeclassfielddeclarationblock.h"
+#include "../umlpackagelist.h"
+#include "../package.h"
+#include "../umlclassifierlistitemlist.h"
+#include "../classifierlistitem.h"
+#include "../enum.h"
+#include "../uml.h"
+
+// Constructors/Destructors
+//
+
+CPPHeaderCodeDocument::CPPHeaderCodeDocument ( UMLClassifier * concept )
+ : ClassifierCodeDocument (concept)
+{
+ setFileExtension(".h");
+
+ //initCodeClassFields(); // this is dubious because it calls down to
+ // CodeGenFactory::newCodeClassField(this)
+ // but "this" is still in construction at that time.
+
+ // needed? I doubt it, but it feels good to do it.
+ classDeclCodeBlock = 0;
+ publicBlock = 0;
+ protectedBlock = 0;
+ privateBlock = 0;
+ namespaceBlock = 0;
+ pubConstructorBlock = 0;
+ protConstructorBlock = 0;
+ privConstructorBlock = 0;
+ pubOperationsBlock = 0;
+ privOperationsBlock = 0;
+ protOperationsBlock = 0;
+
+ // this will call updateContent() as well as other things that sync our document.
+ //synchronize();
+
+}
+
+CPPHeaderCodeDocument::~CPPHeaderCodeDocument ( ) {
+ resetTextBlocks();
+}
+
+//
+// Methods
+//
+
+// Accessor methods
+//
+
+CPPHeaderClassDeclarationBlock * CPPHeaderCodeDocument::getClassDecl()
+{
+
+ if(!classDeclCodeBlock) {
+ classDeclCodeBlock = new CPPHeaderClassDeclarationBlock (this); // was deleted before our load
+ classDeclCodeBlock->setTag("classDeclarationBlock");
+ }
+ return classDeclCodeBlock;
+}
+
+// Other methods
+//
+
+// Sigh. NOT optimal. The only reason that we need to have this
+// is so we can create the CPPHeaderClassDeclarationBlock.
+// would be better if we could create a handler interface that each
+// codeblock used so all we have to do here is add the handler
+void CPPHeaderCodeDocument::loadChildTextBlocksFromNode ( QDomElement & root)
+{
+
+ QDomNode tnode = root.firstChild();
+ QDomElement telement = tnode.toElement();
+ bool loadCheckForChildrenOK = false;
+ while( !telement.isNull() ) {
+ QString nodeName = telement.tagName();
+
+ if( nodeName == "textblocks" ) {
+
+ QDomNode node = telement.firstChild();
+ QDomElement element = node.toElement();
+
+ // if there is nothing to begin with, then we don't worry about it
+ loadCheckForChildrenOK = element.isNull() ? true : false;
+
+ while( !element.isNull() ) {
+ QString name = element.tagName();
+
+ if( name == "codecomment" ) {
+ CodeComment * block = new CPPCodeDocumentation(this);
+ block->loadFromXMI(element);
+ if(!addTextBlock(block))
+ {
+ kError()<<"Unable to add codeComment to :"<<this<<endl;
+ block->deleteLater();
+ } else
+ loadCheckForChildrenOK= true;
+ } else
+ if( name == "codeaccessormethod" ||
+ name == "ccfdeclarationcodeblock"
+ ) {
+ QString acctag = element.attribute("tag","");
+ // search for our method in the
+ TextBlock * tb = findCodeClassFieldTextBlockByTag(acctag);
+ if(!tb || !addTextBlock(tb))
+ {
+ kError()<<"Unable to add codeclassfield child method to:"<<this<<endl;
+ // DON'T delete
+ } else
+ loadCheckForChildrenOK= true;
+
+ } else
+ if( name == "codeblock" ) {
+ CodeBlock * block = newCodeBlock();
+ block->loadFromXMI(element);
+ if(!addTextBlock(block))
+ {
+ kError()<<"Unable to add codeBlock to :"<<this<<endl;
+ block->deleteLater();
+ } else
+ loadCheckForChildrenOK= true;
+ } else
+ if( name == "codeblockwithcomments" ) {
+ CodeBlockWithComments * block = newCodeBlockWithComments();
+ block->loadFromXMI(element);
+ if(!addTextBlock(block))
+ {
+ kError()<<"Unable to add codeBlockwithcomments to:"<<this<<endl;
+ block->deleteLater();
+ } else
+ loadCheckForChildrenOK= true;
+ } else
+ if( name == "header" ) {
+ // do nothing.. this is treated elsewhere
+ } else
+ if( name == "hierarchicalcodeblock" ) {
+ HierarchicalCodeBlock * block = newHierarchicalCodeBlock();
+ block->loadFromXMI(element);
+ if(!addTextBlock(block))
+ {
+ kError()<<"Unable to add hierarchicalcodeBlock to:"<<this<<endl;
+ block->deleteLater();
+ } else
+ loadCheckForChildrenOK= true;
+ } else
+ if( name == "codeoperation" ) {
+ // find the code operation by id
+ QString id = element.attribute("parent_id","-1");
+ UMLObject * obj = UMLApp::app()->getDocument()->findObjectById(STR2ID(id));
+ UMLOperation * op = dynamic_cast<UMLOperation*>(obj);
+ if(op) {
+ CodeOperation * block = new CPPHeaderCodeOperation(this, op);
+ block->loadFromXMI(element);
+ if(addTextBlock(block))
+ loadCheckForChildrenOK= true;
+ else
+ {
+ kError()<<"Unable to add codeoperation to:"<<this<<endl;
+ block->deleteLater();
+ }
+ } else
+ kError()<<"Unable to find operation create codeoperation for:"<<this<<endl;
+ }
+ else
+ if( name == "cppheaderclassdeclarationblock" )
+ {
+ CPPHeaderClassDeclarationBlock * block = getClassDecl();
+ block->loadFromXMI(element);
+ // normally this would be populated by the following syncToparent
+ // call, but we cant wait for it, so lets just do it now.
+ namespaceBlock = getHierarchicalCodeBlock("namespace", "Namespace", 0);
+
+ if(!namespaceBlock || !namespaceBlock->addTextBlock(block))
+ {
+ kError()<<"Error:cant add class declaration codeblock"<<endl;
+ // DON'T delete/release block
+ // block->release();
+ } else
+ loadCheckForChildrenOK= true;
+
+ }
+ // only needed for extreme debugging conditions (E.g. making new codeclassdocument loader)
+ //else
+ //kDebug()<<" LoadFromXMI: Got strange tag in text block stack:"<<name<<", ignorning"<<endl;
+
+ node = element.nextSibling();
+ element = node.toElement();
+ }
+ break;
+ }
+
+ tnode = telement.nextSibling();
+ telement = tnode.toElement();
+ }
+
+ if(!loadCheckForChildrenOK)
+ {
+ CodeDocument * test = dynamic_cast<CodeDocument*>(this);
+ if(test)
+ {
+ kWarning()<<" loadChildBlocks : unable to initialize any child blocks in doc: "<<test->getFileName()<<" "<<this<<endl;
+ } else {
+ HierarchicalCodeBlock * hb = dynamic_cast<HierarchicalCodeBlock*>(this);
+ if(hb)
+ kWarning()<<" loadChildBlocks : unable to initialize any child blocks in Hblock: "<<hb->getTag()<<" "<<this<<endl;
+ else
+ kDebug()<<" loadChildBlocks : unable to initialize any child blocks in UNKNOWN OBJ:"<<this<<endl;
+ }
+ }
+
+}
+
+void CPPHeaderCodeDocument::resetTextBlocks()
+{
+
+ // all special pointers need to be zero'd out.
+ classDeclCodeBlock = 0;
+ publicBlock = 0;
+ protectedBlock = 0;
+ privateBlock = 0;
+ namespaceBlock = 0;
+ pubConstructorBlock = 0;
+ protConstructorBlock = 0;
+ privConstructorBlock = 0;
+ pubOperationsBlock = 0;
+ privOperationsBlock = 0;
+ protOperationsBlock = 0;
+
+ // now do the traditional release of child text blocks
+ ClassifierCodeDocument::resetTextBlocks();
+
+}
+
+/**
+ * @param op
+ */
+// in the vannilla version, we just tack all operations on the end
+// of the document
+bool CPPHeaderCodeDocument::addCodeOperation (CodeOperation * op )
+{
+ Uml::Visibility scope = op->getParentOperation()->getVisibility();
+ if(!op->getParentOperation()->isLifeOperation())
+ {
+ switch (scope) {
+ default:
+ case Uml::Visibility::Public:
+ return pubOperationsBlock->addTextBlock(op);
+ break;
+ case Uml::Visibility::Protected:
+ return protOperationsBlock->addTextBlock(op);
+ break;
+ case Uml::Visibility::Private:
+ return privOperationsBlock->addTextBlock(op);
+ break;
+ }
+ } else {
+ switch (scope) {
+ default:
+ case Uml::Visibility::Public:
+ return pubConstructorBlock->addTextBlock(op);
+ break;
+ case Uml::Visibility::Protected:
+ return protConstructorBlock->addTextBlock(op);
+ break;
+ case Uml::Visibility::Private:
+ return privConstructorBlock->addTextBlock(op);
+ break;
+ }
+ }
+}
+
+
+/**
+ * Save the XMI representation of this object
+ * @return bool status of save
+ */
+/*
+void CPPHeaderCodeDocument::saveToXMI ( QDomDocument & doc, QDomElement & root )
+{
+ QDomElement docElement = doc.createElement( "" );
+
+ setAttributesOnNode(doc, docElement);
+
+ root.appendChild( docElement );
+}
+*/
+
+// This method will cause the class to rebuild its text representation.
+// based on the parent classifier object.
+// For any situation in which this is called, we are either building the code
+// document up, or replacing/regenerating the existing auto-generated parts. As
+// such, we will want to insert everything we resonablely will want
+// during creation. We can set various parts of the document (esp. the
+// comments) to appear or not, as needed.
+void CPPHeaderCodeDocument::updateContent( )
+{
+ // Gather info on the various fields and parent objects of this class...
+ UMLClassifier * c = getParentClassifier();
+ CodeGenPolicyExt *pe = UMLApp::app()->getPolicyExt();
+ CPPCodeGenerationPolicy * policy = dynamic_cast<CPPCodeGenerationPolicy*>(pe);
+
+ // first, set the global flag on whether or not to show classfield info
+ CodeClassFieldList * cfList = getCodeClassFieldList();
+ for(CodeClassField * field = cfList->first(); field; field = cfList->next())
+ field->setWriteOutMethods(policy->getAutoGenerateAccessors());
+
+ // attribute-based ClassFields
+ // we do it this way to have the static fields sorted out from regular ones
+ CodeClassFieldList staticPublicAttribClassFields = getSpecificClassFields (CodeClassField::Attribute, true, Uml::Visibility::Public );
+ CodeClassFieldList publicAttribClassFields = getSpecificClassFields (CodeClassField::Attribute, false, Uml::Visibility::Public );
+ CodeClassFieldList staticProtectedAttribClassFields = getSpecificClassFields (CodeClassField::Attribute, true, Uml::Visibility::Protected );
+ CodeClassFieldList protectedAttribClassFields = getSpecificClassFields (CodeClassField::Attribute, false, Uml::Visibility::Protected );
+ CodeClassFieldList staticPrivateAttribClassFields = getSpecificClassFields (CodeClassField::Attribute, true, Uml::Visibility::Private );
+ CodeClassFieldList privateAttribClassFields = getSpecificClassFields (CodeClassField::Attribute, false, Uml::Visibility::Private);
+
+ // association-based ClassFields
+ // don't care if they are static or not..all are lumped together
+ CodeClassFieldList publicPlainAssocClassFields = getSpecificClassFields ( CodeClassField::PlainAssociation , Uml::Visibility::Public);
+ CodeClassFieldList publicAggregationClassFields = getSpecificClassFields ( CodeClassField::Aggregation, Uml::Visibility::Public);
+ CodeClassFieldList publicCompositionClassFields = getSpecificClassFields ( CodeClassField::Composition, Uml::Visibility::Public );
+
+ CodeClassFieldList protPlainAssocClassFields = getSpecificClassFields ( CodeClassField::PlainAssociation , Uml::Visibility::Protected);
+ CodeClassFieldList protAggregationClassFields = getSpecificClassFields ( CodeClassField::Aggregation, Uml::Visibility::Protected);
+ CodeClassFieldList protCompositionClassFields = getSpecificClassFields ( CodeClassField::Composition, Uml::Visibility::Protected);
+
+ CodeClassFieldList privPlainAssocClassFields = getSpecificClassFields ( CodeClassField::PlainAssociation , Uml::Visibility::Private);
+ CodeClassFieldList privAggregationClassFields = getSpecificClassFields ( CodeClassField::Aggregation, Uml::Visibility::Private);
+ CodeClassFieldList privCompositionClassFields = getSpecificClassFields ( CodeClassField::Composition, Uml::Visibility::Private);
+
+ bool hasOperationMethods = c->getOpList().last() ? true : false;
+ bool hasNamespace = false;
+ bool isEnumeration = false;
+ bool isInterface = parentIsInterface();
+ bool hasclassFields = hasClassFields();
+ bool forcedoc = UMLApp::app()->getCommonPolicy()->getCodeVerboseDocumentComments();
+ QString endLine = UMLApp::app()->getCommonPolicy()->getNewLineEndingChars();
+
+ UMLClassifierList superclasses = c->findSuperClassConcepts();
+
+
+ // START GENERATING CODE/TEXT BLOCKS and COMMENTS FOR THE DOCUMENT
+ //
+
+ // Write the hash define stuff to prevent multiple parsing/inclusion of header
+ QString cppClassName = CodeGenerator::cleanName(c->getName());
+ QString hashDefine = CodeGenerator::cleanName(c->getName().upper().simplifyWhiteSpace());
+ QString defText = "#ifndef "+hashDefine + "_H"+ endLine + "#define "+ hashDefine + "_H";
+ addOrUpdateTaggedCodeBlockWithComments("hashDefBlock", defText, "", 0, false);
+
+ // INCLUDE CODEBLOCK
+ //
+ // Q: Why all utils? Isnt just List and Vector the only classes we are using?
+ // A: doesn't matter at all; its more readable to just include '*' and cpp compilers
+ // don't slow down or anything. (TZ)
+ QString includeStatement = "";
+ bool stringGlobal = policy->stringIncludeIsGlobal();
+ QString sStartBrak = stringGlobal ? "<" : "\"";
+ QString sEndBrak = stringGlobal ? ">" : "\"";
+ includeStatement.append("#include "+sStartBrak+policy->getStringClassNameInclude()+sEndBrak+endLine);
+ if ( hasObjectVectorClassFields() )
+ {
+ bool vecGlobal = policy->vectorIncludeIsGlobal();
+ QString vStartBrak = vecGlobal ? "<" : "\"";
+ QString vEndBrak = vecGlobal ? ">" : "\"";
+ QString value ="#include "+vStartBrak+policy->getVectorClassNameInclude()+vEndBrak;
+ includeStatement.append(value+endLine);
+ }
+
+ //only include classes in a different package from this class
+ UMLPackageList includes;
+ QMap<UMLPackage *,QString> packageMap; // so we don't repeat packages
+
+ CodeGenerator::findObjectsRelated(c,includes);
+ for(UMLPackage *con = includes.first(); con ; con = includes.next())
+ if (con->getBaseType() != Uml::ot_Datatype && !packageMap.contains(con))
+ {
+ packageMap.insert(con,con->getPackage());
+ if(con != getParentClassifier())
+ includeStatement.append("#include \""+CodeGenerator::cleanName(con->getName().lower())+".h\""+endLine);
+ }
+ // now, add/update the includes codeblock
+ CodeBlockWithComments * inclBlock = addOrUpdateTaggedCodeBlockWithComments("includes", includeStatement, QString::null, 0, false);
+ if(includeStatement.isEmpty() && inclBlock->getContentType() == CodeBlock::AutoGenerated)
+ inclBlock->setWriteOutText(false);
+ else
+ inclBlock->setWriteOutText(true);
+
+ // Using
+ QString usingStatement;
+ for(UMLClassifier *classifier = superclasses.first(); classifier ; classifier = superclasses.next()) {
+ if(classifier->getPackage()!=c->getPackage() && !classifier->getPackage().isEmpty()) {
+ usingStatement.append("using "+CodeGenerator::cleanName(c->getPackage())+"::"+cleanName(c->getName())+';'+endLine);
+ }
+ }
+ CodeBlockWithComments * usingBlock = addOrUpdateTaggedCodeBlockWithComments("using", usingStatement, "", 0, false);
+ if(usingStatement.isEmpty() && usingBlock->getContentType() == CodeBlock::AutoGenerated)
+ usingBlock->setWriteOutText(false);
+ else
+ usingBlock->setWriteOutText(true);
+
+ // namespace
+ // This needs special treatment. We cant use "nowriteouttext" for this, as
+ // that will prevent the class declaration from being written. Instead, we
+ // check if "hasNamspace" is true or not, and then indent the remaining code
+ // appropriately as well as set the start/end text of this namespace block.
+ if (c->getUMLPackage() && policy->getPackageIsNamespace())
+ hasNamespace = true;
+ else
+ hasNamespace = false;
+
+ // set start/end text of namespace block
+ namespaceBlock = getHierarchicalCodeBlock("namespace", "Namespace", 0);
+ if(hasNamespace) {
+ UMLPackageList pkgList = c->getPackages();
+ QString pkgs;
+ UMLPackage *pkg;
+ for (pkg = pkgList.first(); pkg != NULL; pkg = pkgList.next()) {
+ pkgs += "namespace " + CodeGenerator::cleanName(pkg->getName()) + " { ";
+ }
+ namespaceBlock->setStartText(pkgs);
+ QString closingBraces;
+ for (pkg = pkgList.first(); pkg != NULL; pkg = pkgList.next()) {
+ closingBraces += "} ";
+ }
+ namespaceBlock->setEndText(closingBraces);
+ namespaceBlock->getComment()->setWriteOutText(true);
+ } else {
+ namespaceBlock->setStartText("");
+ namespaceBlock->setEndText("");
+ namespaceBlock->getComment()->setWriteOutText(false);
+ }
+
+ // Enum types for include
+ if (!isInterface) {
+ QString enumStatement;
+ QString indent = UMLApp::app()->getCommonPolicy()->getIndentation();
+ UMLEnum* e = dynamic_cast<UMLEnum*>(c);
+ if (e) {
+ enumStatement.append(indent + "enum " + cppClassName + " {" + endLine);
+
+ // populate
+ UMLClassifierListItemList ell = e->getFilteredList(Uml::ot_EnumLiteral);
+ for (UMLClassifierListItem *el=ell.first(); el ; ) {
+ enumStatement.append(indent+indent);
+ enumStatement.append(CodeGenerator::cleanName(el->getName()));
+ if ((el=ell.next()) != 0)
+ enumStatement.append(", "+endLine);
+ else
+ break;
+ enumStatement.append(endLine);
+ }
+ enumStatement.append(indent+"};");
+ isEnumeration = true;
+ }
+ namespaceBlock->addOrUpdateTaggedCodeBlockWithComments("enums", enumStatement, "", 0, false);
+ }
+
+ // CLASS DECLARATION BLOCK
+ //
+
+ // add the class declaration block to the namespace block.
+ CPPHeaderClassDeclarationBlock * myClassDeclCodeBlock = getClassDecl();
+ namespaceBlock->addTextBlock(myClassDeclCodeBlock); // note: wont add if already present
+
+ // Is this really true?? hmm..
+ if(isEnumeration)
+ myClassDeclCodeBlock->setWriteOutText(false); // not written out IF its an enumeration class
+ else
+ myClassDeclCodeBlock->setWriteOutText(true);
+
+ //
+ // Main Sub-Blocks
+ //
+
+ // declare public, protected and private methods, attributes (fields).
+ // set the start text ONLY if this is the first time we created the objects.
+ bool createdPublicBlock = publicBlock == 0 ? true : false;
+ publicBlock = myClassDeclCodeBlock->getHierarchicalCodeBlock("publicBlock","Public stuff",0);
+ if (createdPublicBlock)
+ publicBlock->setStartText("public:");
+
+ bool createdProtBlock = protectedBlock == 0 ? true : false;
+ protectedBlock = myClassDeclCodeBlock->getHierarchicalCodeBlock("protectedBlock","Protected stuff",0);
+ if(createdProtBlock)
+ protectedBlock->setStartText("protected:");
+
+ bool createdPrivBlock = privateBlock == 0 ? true : false;
+ privateBlock = myClassDeclCodeBlock->getHierarchicalCodeBlock("privateBlock","Private stuff",0);
+ if(createdPrivBlock)
+ privateBlock->setStartText("private:");
+
+ //
+ // * CLASS FIELD declaration section
+ //
+
+ // setup/get/create the field declaration code block
+ //
+
+ // public fields: Update the comment: we only set comment to appear under the following conditions
+ HierarchicalCodeBlock * publicFieldDeclBlock = publicBlock->getHierarchicalCodeBlock("publicFieldsDecl", "Fields", 1);
+ CodeComment * pubFcomment = publicFieldDeclBlock->getComment();
+ if (!forcedoc && !hasclassFields )
+ pubFcomment->setWriteOutText(false);
+ else
+ pubFcomment->setWriteOutText(true);
+
+ // protected fields: Update the comment: we only set comment to appear under the following conditions
+ HierarchicalCodeBlock * protectedFieldDeclBlock = protectedBlock->getHierarchicalCodeBlock("protectedFieldsDecl", "Fields", 1);
+ CodeComment * protFcomment = protectedFieldDeclBlock->getComment();
+ if (!forcedoc && !hasclassFields )
+ protFcomment->setWriteOutText(false);
+ else
+ protFcomment->setWriteOutText(true);
+
+ // private fields: Update the comment: we only set comment to appear under the following conditions
+ HierarchicalCodeBlock * privateFieldDeclBlock = privateBlock->getHierarchicalCodeBlock("privateFieldsDecl", "Fields", 1);
+ CodeComment * privFcomment = privateFieldDeclBlock->getComment();
+ if (!forcedoc && !hasclassFields )
+ privFcomment->setWriteOutText(false);
+ else
+ privFcomment->setWriteOutText(true);
+
+
+ // now actually declare the fields within the appropriate HCodeBlock
+ //
+
+ // public
+ declareClassFields(staticPublicAttribClassFields, publicFieldDeclBlock);
+ declareClassFields(publicAttribClassFields, publicFieldDeclBlock);
+ declareClassFields(publicPlainAssocClassFields, publicFieldDeclBlock);
+ declareClassFields(publicAggregationClassFields, publicFieldDeclBlock);
+ declareClassFields(publicCompositionClassFields, publicFieldDeclBlock);
+
+ // protected
+ declareClassFields(staticProtectedAttribClassFields, protectedFieldDeclBlock);
+ declareClassFields(protectedAttribClassFields, protectedFieldDeclBlock);
+ declareClassFields(protPlainAssocClassFields, protectedFieldDeclBlock);
+ declareClassFields(protAggregationClassFields, protectedFieldDeclBlock);
+ declareClassFields(protCompositionClassFields, protectedFieldDeclBlock);
+
+ // private
+ declareClassFields(staticPrivateAttribClassFields, privateFieldDeclBlock);
+ declareClassFields(privateAttribClassFields, privateFieldDeclBlock);
+ declareClassFields(privPlainAssocClassFields, privateFieldDeclBlock);
+ declareClassFields(privAggregationClassFields, privateFieldDeclBlock);
+ declareClassFields(privCompositionClassFields, privateFieldDeclBlock);
+
+ //
+ // METHODS section
+ //
+
+ // get/create the method codeblock
+
+ // public methods
+ HierarchicalCodeBlock * pubMethodsBlock = publicBlock->getHierarchicalCodeBlock("pubMethodsBlock", "", 1);
+ CodeComment * pubMethodsComment = pubMethodsBlock->getComment();
+ // set conditions for showing this comment
+ if (!forcedoc && !hasclassFields && !hasOperationMethods)
+ pubMethodsComment->setWriteOutText(false);
+ else
+ pubMethodsComment->setWriteOutText(true);
+
+ // protected methods
+ HierarchicalCodeBlock * protMethodsBlock = protectedBlock->getHierarchicalCodeBlock("protMethodsBlock", "", 1);
+ CodeComment * protMethodsComment = protMethodsBlock->getComment();
+ // set conditions for showing this comment
+ if (!forcedoc && !hasclassFields && !hasOperationMethods)
+ protMethodsComment->setWriteOutText(false);
+ else
+ protMethodsComment->setWriteOutText(true);
+
+ // private methods
+ HierarchicalCodeBlock * privMethodsBlock = privateBlock->getHierarchicalCodeBlock("privMethodsBlock", "", 1);
+ CodeComment * privMethodsComment = privMethodsBlock->getComment();
+ // set conditions for showing this comment
+ if (!forcedoc && !hasclassFields && !hasOperationMethods)
+ privMethodsComment->setWriteOutText(false);
+ else
+ privMethodsComment->setWriteOutText(true);
+
+
+ // METHODS sub-section : constructor methods
+ //
+ CodeGenerationPolicy *pol = UMLApp::app()->getCommonPolicy();
+
+ // setup/get/create the constructor codeblocks
+
+ // public
+ pubConstructorBlock = pubMethodsBlock->getHierarchicalCodeBlock("constructionMethods", "Constructors", 1);
+ // special condiions for showing comment: only when autogenerateding empty constructors
+ // Although, we *should* check for other constructor methods too
+ CodeComment * pubConstComment = pubConstructorBlock->getComment();
+ if (!forcedoc && (isInterface || !pol->getAutoGenerateConstructors()))
+ pubConstComment->setWriteOutText(false);
+ else
+ pubConstComment->setWriteOutText(true);
+
+ // protected
+ protConstructorBlock = protMethodsBlock->getHierarchicalCodeBlock("constructionMethods", "Constructors", 1);
+ // special condiions for showing comment: only when autogenerateding empty constructors
+ // Although, we *should* check for other constructor methods too
+ CodeComment * protConstComment = protConstructorBlock->getComment();
+ if (!forcedoc && (isInterface || !pol->getAutoGenerateConstructors()))
+ protConstComment->setWriteOutText(false);
+ else
+ protConstComment->setWriteOutText(true);
+
+ // private
+ privConstructorBlock = privMethodsBlock->getHierarchicalCodeBlock("constructionMethods", "Constructors", 1);
+ // special condiions for showing comment: only when autogenerateding empty constructors
+ // Although, we *should* check for other constructor methods too
+ CodeComment * privConstComment = privConstructorBlock->getComment();
+ if (!forcedoc && (isInterface || !pol->getAutoGenerateConstructors()))
+ privConstComment->setWriteOutText(false);
+ else
+ privConstComment->setWriteOutText(true);
+
+ // add/get the empty constructor. I guess since there is no
+ // meta-data to state what the scope of this method is, we will make it
+ // "public" as a default. This might present problems if the user wants
+ // to move the block into the "private" or "protected" blocks.
+ QString emptyConstStatement = cppClassName + " ( ) { }";
+
+ // search for this first in the entire document. IF not present, put
+ // it in the public constructor method block
+ TextBlock * emptyConstTb = findTextBlockByTag("emptyconstructor", true);
+ CodeBlockWithComments * emptyConstBlock = dynamic_cast<CodeBlockWithComments*>(emptyConstTb);
+ if(!emptyConstBlock)
+ emptyConstBlock = pubConstructorBlock->addOrUpdateTaggedCodeBlockWithComments("emptyconstructor", emptyConstStatement, "Empty Constructor", 1, false);
+
+ // Now, as an additional condition we only show the empty constructor block
+ // IF it was desired to be shown
+ if(!isInterface && pol->getAutoGenerateConstructors())
+ emptyConstBlock->setWriteOutText(true);
+ else
+ emptyConstBlock->setWriteOutText(false);
+
+
+ // METHODS subsection : ACCESSOR METHODS
+ //
+
+ // get/create the accessor codeblock
+
+ // public
+ HierarchicalCodeBlock * pubAccessorBlock = pubMethodsBlock->getHierarchicalCodeBlock("accessorMethods", "Accessor Methods", 1);
+ // set conditions for showing section comment
+ CodeComment * pubAccessComment = pubAccessorBlock->getComment();
+ if (!forcedoc && !hasclassFields)
+ pubAccessComment->setWriteOutText(false);
+ else
+ pubAccessComment->setWriteOutText(true);
+
+ // protected
+ HierarchicalCodeBlock * protAccessorBlock = protMethodsBlock->getHierarchicalCodeBlock("accessorMethods", "Accessor Methods", 1);
+ // set conditions for showing section comment
+ CodeComment * protAccessComment = protAccessorBlock->getComment();
+ if (!forcedoc && !hasclassFields)
+ protAccessComment->setWriteOutText(false);
+ else
+ protAccessComment->setWriteOutText(true);
+
+ // private
+ HierarchicalCodeBlock * privAccessorBlock = privMethodsBlock->getHierarchicalCodeBlock("accessorMethods", "Accessor Methods", 1);
+ // set conditions for showing section comment
+ CodeComment * privAccessComment = privAccessorBlock->getComment();
+ // We've to copy the private accessorMethods to the public block
+ if (!forcedoc && !hasclassFields)
+ privAccessComment->setWriteOutText(false);
+ else
+ privAccessComment->setWriteOutText(true);
+
+ // now, 2 sub-sub sections in accessor block
+ // add/update accessor methods for attributes
+ HierarchicalCodeBlock * pubStaticAccessors = pubAccessorBlock->getHierarchicalCodeBlock("pubStaticAccessorMethods", "", 1);
+ HierarchicalCodeBlock * pubRegularAccessors = pubAccessorBlock->getHierarchicalCodeBlock("pubRegularAccessorMethods", "", 1);
+ pubStaticAccessors->getComment()->setWriteOutText(false); // never write block comment
+ pubRegularAccessors->getComment()->setWriteOutText(false); // never write block comment
+
+ HierarchicalCodeBlock * protStaticAccessors = protAccessorBlock->getHierarchicalCodeBlock("protStaticAccessorMethods", "", 1);
+ HierarchicalCodeBlock * protRegularAccessors = protAccessorBlock->getHierarchicalCodeBlock("protRegularAccessorMethods", "", 1);
+ protStaticAccessors->getComment()->setWriteOutText(false); // never write block comment
+ protRegularAccessors->getComment()->setWriteOutText(false); // never write block comment
+
+ HierarchicalCodeBlock * privStaticAccessors = privAccessorBlock->getHierarchicalCodeBlock("privStaticAccessorMethods", "", 1);
+ HierarchicalCodeBlock * privRegularAccessors = privAccessorBlock->getHierarchicalCodeBlock("privRegularAccessorMethods", "", 1);
+ privStaticAccessors->getComment()->setWriteOutText(false); // never write block comment
+ privRegularAccessors->getComment()->setWriteOutText(false); // never write block comment
+
+ // now add in accessors as appropriate
+
+ // public stuff
+ pubStaticAccessors->addCodeClassFieldMethods(staticPublicAttribClassFields);
+ pubRegularAccessors->addCodeClassFieldMethods(publicAttribClassFields);
+
+ // generate accessors as public
+ if (policy && policy->getAccessorsArePublic())
+ {
+ pubRegularAccessors->addCodeClassFieldMethods(privateAttribClassFields);
+ pubRegularAccessors->addCodeClassFieldMethods(protectedAttribClassFields);
+ }
+
+ pubRegularAccessors->addCodeClassFieldMethods(publicPlainAssocClassFields);
+ pubRegularAccessors->addCodeClassFieldMethods(publicAggregationClassFields);
+ pubRegularAccessors->addCodeClassFieldMethods(publicCompositionClassFields);
+
+ // protected stuff
+ protStaticAccessors->addCodeClassFieldMethods(staticProtectedAttribClassFields);
+
+ // accessors are public so we don't have to create it here
+ if (policy && !policy->getAccessorsArePublic())
+ protRegularAccessors->addCodeClassFieldMethods(protectedAttribClassFields);
+
+ protRegularAccessors->addCodeClassFieldMethods(protPlainAssocClassFields);
+ protRegularAccessors->addCodeClassFieldMethods(protAggregationClassFields);
+ protRegularAccessors->addCodeClassFieldMethods(protCompositionClassFields);
+
+ // private stuff
+ privStaticAccessors->addCodeClassFieldMethods(staticPrivateAttribClassFields);
+
+ // accessors are public so we don't have to create it here
+ if (policy && !policy->getAccessorsArePublic())
+ privRegularAccessors->addCodeClassFieldMethods(privateAttribClassFields);
+
+ privRegularAccessors->addCodeClassFieldMethods(privPlainAssocClassFields);
+ privRegularAccessors->addCodeClassFieldMethods(privAggregationClassFields);
+ privRegularAccessors->addCodeClassFieldMethods(privCompositionClassFields);
+
+
+ // METHODS subsection : Operation methods (e.g. methods derive from operations but which arent constructors)
+ //
+
+ // setup/get/create the operations codeblock
+
+ // public
+ pubOperationsBlock = pubMethodsBlock->getHierarchicalCodeBlock("operationMethods", "Operations", 1);
+ // set conditions for showing section comment
+ CodeComment * pubOcomment = pubOperationsBlock->getComment();
+ if (!forcedoc && !hasOperationMethods )
+ pubOcomment->setWriteOutText(false);
+ else
+ pubOcomment->setWriteOutText(true);
+
+ //protected
+ protOperationsBlock = protMethodsBlock->getHierarchicalCodeBlock("operationMethods", "Operations", 1);
+ // set conditions for showing section comment
+ CodeComment * protOcomment = protOperationsBlock->getComment();
+ if (!forcedoc && !hasOperationMethods )
+ protOcomment->setWriteOutText(false);
+ else
+ protOcomment->setWriteOutText(true);
+
+ //private
+ privOperationsBlock = privMethodsBlock->getHierarchicalCodeBlock("operationMethods", "Operations", 1);
+ // set conditions for showing section comment
+ CodeComment * privOcomment = privOperationsBlock->getComment();
+ if (!forcedoc && !hasOperationMethods )
+ privOcomment->setWriteOutText(false);
+ else
+ privOcomment->setWriteOutText(true);
+
+ // Operations
+ //
+ // nothing to do here.. "updateOperations" in parent class puts things
+ // in the right place using the "addCodeOperation" method we defined in this class
+
+ // FINISH up with hash def block close
+ QString defTextEnd = "#endif //"+hashDefine + "_H";
+ addOrUpdateTaggedCodeBlockWithComments("hashDefBlockEnd", defTextEnd, "", 0, false);
+
+}
+
+
+#include "cppheadercodedocument.moc"
diff --git a/umbrello/umbrello/codegenerators/cppheadercodedocument.h b/umbrello/umbrello/codegenerators/cppheadercodedocument.h
new file mode 100644
index 00000000..ca75627f
--- /dev/null
+++ b/umbrello/umbrello/codegenerators/cppheadercodedocument.h
@@ -0,0 +1,107 @@
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * copyright (C) 2004-2006 *
+ * Umbrello UML Modeller Authors <uml-devel@uml.sf.net> *
+ ***************************************************************************/
+
+/* This code generated by:
+ * Author : thomas
+ * Date : Thu Aug 28 2003
+ */
+
+#ifndef CPPHEADERCODEDOCUMENT_H
+#define CPPHEADERCODEDOCUMENT_H
+
+#include <qstring.h>
+
+#include "../codeclassfieldlist.h"
+#include "../classifiercodedocument.h"
+#include "../hierarchicalcodeblock.h"
+#include "classifierinfo.h"
+
+class CPPHeaderClassDeclarationBlock;
+
+/**
+ * class CPPHeaderCodeDocument
+ * A CPP UMLClassifier Header Code Document.
+ */
+
+class CPPHeaderCodeDocument : public ClassifierCodeDocument
+{
+ Q_OBJECT
+public:
+
+ // Constructors/Destructors
+ //
+
+ /**
+ * Constructor
+ */
+ CPPHeaderCodeDocument (UMLClassifier * classifier);
+
+ /**
+ * Empty Destructor
+ */
+ virtual ~CPPHeaderCodeDocument ( );
+
+ /** add a code operation to this cpp classifier code document.
+ * @return bool which is true IF the code operation was added successfully
+ */
+ bool addCodeOperation (CodeOperation * op );
+
+ /**
+ * Save the XMI representation of this object
+ */
+ //virtual void saveToXMI ( QDomDocument & doc, QDomElement & root );
+
+protected:
+
+ // reset/clear our inventory of textblocks in this document
+ void resetTextBlocks();
+
+ /**
+ * need to overwrite this for cpp header since we need to pick up the
+ * header class declaration block.
+ */
+ virtual void loadChildTextBlocksFromNode ( QDomElement & root);
+
+ void addOrUpdateCodeClassFieldMethodsInCodeBlock(CodeClassFieldList &list, CPPHeaderClassDeclarationBlock * codeBlock);
+
+ /**
+ * create a new code comment. IN this case it is a CPPCodeDocumentation object.
+ */
+ CodeComment * newCodeComment ( );
+
+ void updateContent();
+
+private:
+
+ CPPHeaderClassDeclarationBlock * classDeclCodeBlock;
+
+ HierarchicalCodeBlock * publicBlock;
+ HierarchicalCodeBlock * privateBlock;
+ HierarchicalCodeBlock * protectedBlock;
+
+ HierarchicalCodeBlock * namespaceBlock;
+
+ HierarchicalCodeBlock * pubConstructorBlock;
+ HierarchicalCodeBlock * protConstructorBlock;
+ HierarchicalCodeBlock * privConstructorBlock;
+
+ HierarchicalCodeBlock * pubOperationsBlock;
+ HierarchicalCodeBlock * privOperationsBlock;
+ HierarchicalCodeBlock * protOperationsBlock;
+
+ /**
+ *
+ */
+ CPPHeaderClassDeclarationBlock * getClassDecl();
+
+};
+
+#endif // CPPHEADERCODEDOCUMENT_H
diff --git a/umbrello/umbrello/codegenerators/cppheadercodeoperation.cpp b/umbrello/umbrello/codegenerators/cppheadercodeoperation.cpp
new file mode 100644
index 00000000..ca8ad727
--- /dev/null
+++ b/umbrello/umbrello/codegenerators/cppheadercodeoperation.cpp
@@ -0,0 +1,175 @@
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * copyright (C) 2004-2006 *
+ * Umbrello UML Modeller Authors <uml-devel@uml.sf.net> *
+ ***************************************************************************/
+
+/* This code generated by:
+ * Author : thomas
+ * Date : Mon Sep 1 2003
+ */
+
+#include "cppheadercodeoperation.h"
+
+#include "cppcodegenerator.h"
+#include "cppcodegenerationpolicy.h"
+#include "cppheadercodedocument.h"
+#include "cppcodedocumentation.h"
+#include "../uml.h"
+
+// Constructors/Destructors
+//
+
+CPPHeaderCodeOperation::CPPHeaderCodeOperation
+ ( CPPHeaderCodeDocument * doc, UMLOperation *parent, const QString & body, const QString & comment )
+ : CodeOperation (doc, parent, body, comment)
+{
+ // lets not go with the default comment and instead use
+ // full-blown cpp documentation object instead
+ setComment(new CPPCodeDocumentation(doc));
+
+ // these things never change..
+ setOverallIndentationLevel(1);
+
+ setText("");
+ setStartMethodText("");
+ setEndMethodText("");
+
+ updateMethodDeclaration();
+ updateContent();
+
+}
+
+CPPHeaderCodeOperation::~CPPHeaderCodeOperation ( ) { }
+
+// Other methods
+//
+
+// we basically just want to know whether or not to print out
+// the body of the operation.
+// In C++ if the operations are inline, then we DO print out
+// the body text.
+void CPPHeaderCodeOperation::updateContent( )
+{
+ CodeGenPolicyExt *pe = UMLApp::app()->getPolicyExt();
+ CPPCodeGenerationPolicy * policy = dynamic_cast<CPPCodeGenerationPolicy*>(pe);
+ bool isInlineMethod = policy->getOperationsAreInline( );
+
+ if(isInlineMethod)
+ setText(""); // change whatever it is to "";
+}
+
+// we basically want to update the doc and start text of this method
+void CPPHeaderCodeOperation::updateMethodDeclaration()
+{
+ ClassifierCodeDocument *ccd = dynamic_cast<ClassifierCodeDocument*>(getParentDocument());
+ bool isInterface = ccd->parentIsInterface();
+ UMLOperation * o = getParentOperation();
+
+ CodeGenPolicyExt *pe = UMLApp::app()->getPolicyExt();
+ CPPCodeGenerationPolicy * policy = dynamic_cast<CPPCodeGenerationPolicy*>(pe);
+ bool isInlineMethod = policy->getOperationsAreInline( );
+
+ QString endLine = getNewLineEndingChars();
+
+ // first, the comment on the operation, IF its autogenerated/empty
+ QString comment = o->getDoc();
+ if(comment.isEmpty() && getContentType() == CodeBlock::AutoGenerated)
+ {
+ UMLAttributeList parameters = o->getParmList();
+ for(UMLAttributeListIt iterator(parameters); iterator.current(); ++iterator) {
+ comment += endLine + "@param " + iterator.current()->getName() + ' ';
+ comment += iterator.current()->getDoc();
+ }
+ getComment()->setText(comment);
+ }
+
+ // no return type for constructors
+ QString methodReturnType = o->getTypeName();
+ QString methodName = o->getName();
+ QString paramStr = QString("");
+
+ // assemble parameters
+ UMLAttributeList list = getParentOperation()->getParmList();
+ int nrofParam = list.count();
+ int paramNum = 0;
+ for(UMLAttribute* parm = list.first(); parm; parm=list.next())
+ {
+ QString rType = parm->getTypeName();
+ QString paramName = parm->getName();
+ QString initialValue = parm->getInitialValue();
+ paramStr += rType + ' ' + paramName;
+ if(!initialValue.isEmpty())
+ paramStr += '=' + initialValue;
+
+ paramNum++;
+
+ if (paramNum != nrofParam )
+ paramStr += ", ";
+ }
+
+ // if an operation isn't a constructor or a destructor and it has no return type
+ if (o->isLifeOperation()) // constructor/destructor has no type
+ methodReturnType = "";
+ else if (methodReturnType.isEmpty()) // this operation should be 'void'
+ methodReturnType = QString("void");
+
+ // set start/end method text
+ QString prototype = methodReturnType+' '+methodName+" ("+paramStr+')';
+
+ QString startText;
+ QString endText;
+
+ applyStereotypes (prototype, o, isInlineMethod, isInterface, startText, endText);
+
+ setStartMethodText(prototype+startText);
+ setEndMethodText(endText);
+}
+
+int CPPHeaderCodeOperation::lastEditableLine() {
+ ClassifierCodeDocument * doc = dynamic_cast<ClassifierCodeDocument*>(getParentDocument());
+ UMLOperation * o = getParentOperation();
+ if(doc->parentIsInterface() || o->getAbstract())
+ return -1; // very last line is NOT editable as its a one-line declaration w/ no body in
+ // an interface.
+ return 0;
+}
+
+void CPPHeaderCodeOperation::applyStereotypes (QString& prototype, UMLOperation * pOp,
+ bool inlinePolicy, bool interface,
+ QString& start, QString& end)
+{
+ // if the class is an interface, all methods will be declared as pure
+ // virtual functions
+ start = (inlinePolicy ? " {" : ";");
+ end = (inlinePolicy ? "}" : "");
+ if (pOp->getConst())
+ prototype += " const";
+ if (interface || pOp->getAbstract()) {
+ // constructor can't be virtual or abstract
+ if (!pOp->isLifeOperation()) {
+ prototype = "virtual " + prototype + " = 0";
+ if (inlinePolicy) {
+ start = ";";
+ end = "";
+ }
+ }
+ } // constructors could not be declared as static
+ else if (pOp->getStatic() && !pOp->isLifeOperation()) {
+ prototype = "static " + prototype;
+ }
+ // apply the stereotypes
+ if (!pOp->getStereotype().isEmpty()) {
+ if ((pOp->getStereotype() == "friend") || (pOp->getStereotype(false) == "virtual")) {
+ if (!pOp->isLifeOperation() && !(interface || pOp->getAbstract()) && !pOp->getStatic())
+ prototype = pOp->getStereotype() + ' ' + prototype;
+ }
+ }
+}
+
+#include "cppheadercodeoperation.moc"
diff --git a/umbrello/umbrello/codegenerators/cppheadercodeoperation.h b/umbrello/umbrello/codegenerators/cppheadercodeoperation.h
new file mode 100644
index 00000000..1d4fbca7
--- /dev/null
+++ b/umbrello/umbrello/codegenerators/cppheadercodeoperation.h
@@ -0,0 +1,59 @@
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * copyright (C) 2004-2006 *
+ * Umbrello UML Modeller Authors <uml-devel@uml.sf.net> *
+ ***************************************************************************/
+
+/* This code generated by:
+ * Author : thomas
+ * Date : Mon Sep 1 2003
+ */
+
+
+#ifndef CPPHEADERCODEOPERATION_H
+#define CPPHEADERCODEOPERATION_H
+
+#include <qstring.h>
+#include "../codeoperation.h"
+
+class CPPHeaderCodeDocument;
+
+class CPPHeaderCodeOperation : virtual public CodeOperation
+{
+ Q_OBJECT
+public:
+
+ // Constructors/Destructors
+ //
+
+ /**
+ * Constructor
+ */
+ CPPHeaderCodeOperation ( CPPHeaderCodeDocument * doc, UMLOperation * op,
+ const QString & body = "", const QString & comment = "");
+
+ /**
+ * Empty Destructor
+ */
+ virtual ~CPPHeaderCodeOperation ( );
+
+ virtual int lastEditableLine();
+
+protected:
+
+ virtual void updateMethodDeclaration();
+ virtual void updateContent( );
+
+ /**
+ * Check to see if we have a valid stereotype to apply in the operation
+ */
+ virtual void applyStereotypes (QString&, UMLOperation *, bool, bool, QString&, QString&);
+
+};
+
+#endif // CPPHEADERCODEOPERATION_H
diff --git a/umbrello/umbrello/codegenerators/cppmakecodedocument.cpp b/umbrello/umbrello/codegenerators/cppmakecodedocument.cpp
new file mode 100644
index 00000000..d13152b4
--- /dev/null
+++ b/umbrello/umbrello/codegenerators/cppmakecodedocument.cpp
@@ -0,0 +1,78 @@
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * copyright (C) 2004-2006 *
+ * Umbrello UML Modeller Authors <uml-devel@uml.sf.net> *
+ ***************************************************************************/
+
+/* This code generated by:
+ * Author : thomas
+ * Date : Tue Jun 24 2003
+ */
+
+#include "cppcodegenerator.h"
+
+#include <qregexp.h>
+
+const char * CPPMakefileCodeDocument::DOCUMENT_ID_VALUE = "Makefile_DOC";
+
+// Constructors/Destructors
+//
+
+CPPMakefileCodeDocument::CPPMakefileCodeDocument ( )
+{
+ setFileName("Makefile"); // default name
+ setFileExtension("");
+ setID(DOCUMENT_ID_VALUE); // default id tag for this type of document
+}
+
+CPPMakefileCodeDocument::~CPPMakefileCodeDocument ( ) { }
+
+//
+// Methods
+//
+
+// Other methods
+//
+
+// we add in our code blocks that describe how to generate
+// the project here...
+void CPPMakefileCodeDocument::updateContent( ) {
+ // FIX : fill in content
+}
+
+/**
+ * @return QString
+ */
+QString CPPMakefileCodeDocument::toString ( ) {
+ return "# cpp make build document";
+}
+
+// We overwritten by CPP language implementation to get lowercase path
+QString CPPMakefileCodeDocument::getPath ( )
+{
+
+ QString path = getPackage();
+
+ // Replace all white spaces with blanks
+ path.simplifyWhiteSpace();
+
+ // Replace all blanks with underscore
+ path.replace(QRegExp(" "), "_");
+
+ path.replace(QRegExp("\\."),"/");
+ path.replace(QRegExp("::"),"/");
+
+ path.lower();
+
+ return path;
+
+}
+
+
+#include "cppmakecodedocument.moc"
diff --git a/umbrello/umbrello/codegenerators/cppmakecodedocument.h b/umbrello/umbrello/codegenerators/cppmakecodedocument.h
new file mode 100644
index 00000000..98efe272
--- /dev/null
+++ b/umbrello/umbrello/codegenerators/cppmakecodedocument.h
@@ -0,0 +1,67 @@
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * copyright (C) 2004-2006 *
+ * Umbrello UML Modeller Authors <uml-devel@uml.sf.net> *
+ ***************************************************************************/
+
+/* This code generated by:
+ * Author : thomas
+ * Date : Tue Jun 24 2003
+ */
+
+
+
+#ifndef CPPMAKECODEDOCUMENT_H
+#define CPPMAKECODEDOCUMENT_H
+
+#include "../codedocument.h"
+#include <qstring.h>
+
+/**
+ * class CPPMakefileCodeDocument
+ * Represents
+ */
+
+class CPPMakefileCodeDocument : public CodeDocument
+{
+ Q_OBJECT
+public:
+
+ static const char * DOCUMENT_ID_VALUE;
+
+ // Constructors/Destructors
+ //
+
+ /**
+ * Constructor
+ */
+ CPPMakefileCodeDocument ( );
+
+ /**
+ * Empty Destructor
+ */
+ virtual ~CPPMakefileCodeDocument ( );
+
+ /**
+ * @return QString
+ */
+ QString toString ( );
+
+ QString getPath ( );
+
+ void updateContent();
+
+protected:
+
+private:
+
+
+
+};
+
+#endif // CPPMAKECODEDOCUMENT_H
diff --git a/umbrello/umbrello/codegenerators/cppsourcecodeaccessormethod.cpp b/umbrello/umbrello/codegenerators/cppsourcecodeaccessormethod.cpp
new file mode 100644
index 00000000..da2a86cb
--- /dev/null
+++ b/umbrello/umbrello/codegenerators/cppsourcecodeaccessormethod.cpp
@@ -0,0 +1,169 @@
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * copyright (C) 2004-2007 *
+ * Umbrello UML Modeller Authors <uml-devel@uml.sf.net> *
+ ***************************************************************************/
+
+/* This code generated by:
+ * Author : thomas
+ * Date : Fri Aug 31 2003
+ */
+
+// own header
+#include "cppsourcecodeaccessormethod.h"
+
+// qt/kde includes
+#include <kdebug.h>
+
+// local includes
+#include "../attribute.h"
+#include "../classifiercodedocument.h"
+#include "../umlobject.h"
+#include "../umlrole.h"
+#include "../uml.h"
+
+#include "cppcodegenerator.h"
+#include "cppcodegenerationpolicy.h"
+#include "cppcodeclassfield.h"
+#include "cppcodedocumentation.h"
+
+// Constructors/Destructors
+//
+
+CPPSourceCodeAccessorMethod::CPPSourceCodeAccessorMethod ( CodeClassField * field, CodeAccessorMethod::AccessorType type)
+ : CodeAccessorMethod ( field )
+{
+ setType(type);
+ setEndMethodText("}");
+}
+
+void CPPSourceCodeAccessorMethod::update()
+{
+ updateMethodDeclaration();
+ updateContent();
+}
+
+CPPSourceCodeAccessorMethod::~CPPSourceCodeAccessorMethod ( ) { }
+
+// Other
+//
+
+// we basically want to update the body of this method
+void CPPSourceCodeAccessorMethod::updateContent( )
+{
+ CodeClassField * parentField = getParentClassField();
+ CPPCodeClassField * cppfield = dynamic_cast<CPPCodeClassField*>(parentField);
+ CodeGenPolicyExt *pe = UMLApp::app()->getPolicyExt();
+ CPPCodeGenerationPolicy * policy = dynamic_cast<CPPCodeGenerationPolicy*>(pe);
+ bool isInlineMethod = policy->getAccessorsAreInline( );
+
+ QString variableName = cppfield->getFieldName();
+ QString itemClassName = cppfield->getTypeName();
+ QString text;
+
+ if(isInlineMethod) {
+ switch(getType()) {
+ case CodeAccessorMethod::ADD:
+ text = policy->getVectorMethodAppend(variableName, itemClassName);
+ break;
+ case CodeAccessorMethod::REMOVE:
+ text = policy->getVectorMethodRemove(variableName, itemClassName);
+ break;
+ case CodeAccessorMethod::SET:
+ text = variableName+" = value;";
+ break;
+ case CodeAccessorMethod::LIST:
+ case CodeAccessorMethod::GET:
+ default:
+ text = "return "+variableName+';';
+ break;
+ }
+ }
+
+ setText(text);
+}
+
+// we basically want to update the start text of this method
+void CPPSourceCodeAccessorMethod::updateMethodDeclaration()
+{
+
+ CodeClassField * parentField = getParentClassField();
+ ClassifierCodeDocument * doc = parentField->getParentDocument();
+ CodeGenPolicyExt *pe = UMLApp::app()->getPolicyExt();
+ CPPCodeGenerationPolicy * policy = dynamic_cast<CPPCodeGenerationPolicy*>(pe);
+ CPPCodeClassField * cppfield = dynamic_cast<CPPCodeClassField*>(parentField);
+ UMLClassifier * c = doc->getParentClassifier();
+
+ bool isInlineMethod = policy->getAccessorsAreInline( );
+
+ QString vectorClassName = policy->getVectorClassName();
+ QString fieldName = cppfield->getFieldName();
+ QString fieldType = cppfield->getTypeName();
+ QString objectType = cppfield->getListObjectType();
+ if(objectType.isEmpty())
+ objectType = fieldName;
+
+ QString methodReturnType = "void";
+ QString methodName;
+ QString methodParams;
+ QString headerText;
+ QString className = CodeGenerator::cleanName(c->getName());
+ QString endLine = UMLApp::app()->getCommonPolicy()->getNewLineEndingChars();
+
+ switch(getType()) {
+ case CodeAccessorMethod::ADD:
+ methodName = "add_"+fieldType;
+ methodReturnType = "void";
+ methodParams = objectType+" value ";
+ headerText = "Add a "+fieldName+" object to the "+fieldName+"List"+endLine+getParentObject()->getDoc()+endLine+"@return void";
+ break;
+ case CodeAccessorMethod::REMOVE:
+ methodName = "remove_"+fieldType;
+ methodParams = objectType+" value ";
+ methodReturnType = "void";
+ headerText = "Remove a "+fieldName+" object from the "+fieldName+"List"+endLine+getParentObject()->getDoc()+endLine+"@return void";
+ break;
+ case CodeAccessorMethod::LIST:
+ methodName = "get_"+fieldType+"_list";
+ methodReturnType = vectorClassName;
+ headerText = "Get the "+fieldName+"List"+endLine+getParentObject()->getDoc()+endLine+"@return "+vectorClassName+"with list of objects";
+ break;
+ case CodeAccessorMethod::SET:
+ methodName = "set_"+fieldName;
+ methodParams = fieldType+" value ";
+ methodReturnType = "void";
+ headerText = "Set the value of "+fieldName+endLine+getParentObject()->getDoc()+endLine+"@param value the value of "+fieldName;
+ break;
+ case CodeAccessorMethod::GET:
+ default:
+ methodName = "get_"+fieldName;
+ methodReturnType = fieldType;
+ headerText = "Get the value of "+fieldName+endLine+getParentObject()->getDoc()+endLine+"@return the value of "+fieldName;
+ break;
+ }
+
+ // set header
+ CPPCodeDocumentation * header = new CPPCodeDocumentation(doc);
+ if(!getParentObject()->getDoc().isEmpty())
+ header->setText(headerText);
+ setComment(header);
+
+ // set start method text (EndText never changes)
+ setStartMethodText(methodReturnType+' '+className+"::"+methodName+" ("+methodParams+')' + " {");
+
+ setOverallIndentationLevel(0);
+
+ // these ONLY appear if they arent inline
+ if(isInlineMethod)
+ setWriteOutText(false);
+
+}
+
+
+
+#include "cppsourcecodeaccessormethod.moc"
diff --git a/umbrello/umbrello/codegenerators/cppsourcecodeaccessormethod.h b/umbrello/umbrello/codegenerators/cppsourcecodeaccessormethod.h
new file mode 100644
index 00000000..60d9c369
--- /dev/null
+++ b/umbrello/umbrello/codegenerators/cppsourcecodeaccessormethod.h
@@ -0,0 +1,57 @@
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the 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 code generated by:
+ * Author : thomas
+ * Date : Fri Jun 20 2003
+ */
+
+#ifndef CPPSOURCECODEACCESSORMETHOD_H
+#define CPPSOURCECODEACCESSORMETHOD_H
+
+#include <qstring.h>
+
+#include "../codeaccessormethod.h"
+
+class CodeClassField;
+
+class CPPSourceCodeAccessorMethod : public CodeAccessorMethod
+{
+ Q_OBJECT
+public:
+
+ // Constructors/Destructors
+ //
+
+ /**
+ * Empty Constructor
+ */
+ CPPSourceCodeAccessorMethod ( CodeClassField * field, CodeAccessorMethod::AccessorType type);
+
+ /**
+ * Empty Destructor
+ */
+ virtual ~CPPSourceCodeAccessorMethod ( );
+
+ /**
+ * Must be called before this object is usable
+ */
+ void update();
+
+protected:
+
+ virtual void updateMethodDeclaration();
+ virtual void updateContent();
+
+private:
+
+};
+
+#endif // CPPSOURCECODEACCESSORMETHOD_H
diff --git a/umbrello/umbrello/codegenerators/cppsourcecodeclassfielddeclarationblock.cpp b/umbrello/umbrello/codegenerators/cppsourcecodeclassfielddeclarationblock.cpp
new file mode 100644
index 00000000..7d60b1c3
--- /dev/null
+++ b/umbrello/umbrello/codegenerators/cppsourcecodeclassfielddeclarationblock.cpp
@@ -0,0 +1,74 @@
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the 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 code generated by:
+ * Author : thomas
+ * Date : Mon Sep 1 2003
+ */
+
+#include "cppsourcecodeclassfielddeclarationblock.h"
+
+#include "cppcodeclassfield.h"
+#include "../model_utils.h"
+
+// Constructors/Destructors
+//
+
+CPPSourceCodeClassFieldDeclarationBlock::CPPSourceCodeClassFieldDeclarationBlock ( CodeClassField * parent )
+ : CodeClassFieldDeclarationBlock ( parent )
+{
+ setOverallIndentationLevel(1);
+ updateContent();
+}
+
+CPPSourceCodeClassFieldDeclarationBlock::~CPPSourceCodeClassFieldDeclarationBlock ( ) { }
+
+//
+// Methods
+//
+
+// Other methods
+//
+
+/**
+ */
+void CPPSourceCodeClassFieldDeclarationBlock::updateContent( )
+{
+
+ /*
+ CodeClassField * cf = getParentClassField();
+ ClassifierCodeDocument * doc = cf->getParentDocument();
+ CPPCodeClassField * jcf = dynamic_cast<CPPCodeClassField*>(cf);
+ CPPClassifierCodeDocument* jdoc = dynamic_cast<CPPClassifierCodeDocument*>(doc);
+
+ // Set the comment
+ QString notes = getParentObject()->getDoc();
+ getComment()->setText(notes);
+
+ // Set the body
+ QString staticValue = getParentObject()->getStatic() ? "static " : "";
+ QString scopeStr = getParentObject()->getVisibility().toString();
+
+ QString typeName = jcf->getTypeName();
+ QString fieldName = jcf->getFieldName();
+ QString initialV = jcf->getInitialValue();
+
+ QString body = staticValue+scopeStr+" "+typeName+" "+fieldName;
+ if (!initialV.isEmpty())
+ body.append(" = " + initialV);
+ setText(body+";");
+ */
+ setText("FIX ME;");
+
+
+}
+
+
+
+#include "cppsourcecodeclassfielddeclarationblock.moc"
diff --git a/umbrello/umbrello/codegenerators/cppsourcecodeclassfielddeclarationblock.h b/umbrello/umbrello/codegenerators/cppsourcecodeclassfielddeclarationblock.h
new file mode 100644
index 00000000..e5b908a0
--- /dev/null
+++ b/umbrello/umbrello/codegenerators/cppsourcecodeclassfielddeclarationblock.h
@@ -0,0 +1,51 @@
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the 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 code generated by:
+ * Author : thomas
+ * Date : Mon Sep 1 2003
+ */
+
+#ifndef CPPSOURCECODECLASSFIELDDECLARATIONBLOCK_H
+#define CPPSOURCECODECLASSFIELDDECLARATIONBLOCK_H
+
+#include <qstring.h>
+
+#include "../codeclassfielddeclarationblock.h"
+
+class CPPSourceCodeClassFieldDeclarationBlock : public CodeClassFieldDeclarationBlock
+{
+ Q_OBJECT
+public:
+
+ // Constructors/Destructors
+ //
+
+ /**
+ * Constructor
+ */
+ CPPSourceCodeClassFieldDeclarationBlock ( CodeClassField * parent );
+
+ /**
+ * Empty Destructor
+ */
+ virtual ~CPPSourceCodeClassFieldDeclarationBlock ( );
+
+protected:
+
+ // this will be called by syncToParent whenever the parent object is "modified"
+ void updateContent ( );
+
+private:
+
+
+};
+
+#endif // CPPSOURCECODECLASSFIELDDECLARATIONBLOCK_H
diff --git a/umbrello/umbrello/codegenerators/cppsourcecodedocument.cpp b/umbrello/umbrello/codegenerators/cppsourcecodedocument.cpp
new file mode 100644
index 00000000..be054937
--- /dev/null
+++ b/umbrello/umbrello/codegenerators/cppsourcecodedocument.cpp
@@ -0,0 +1,168 @@
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * copyright (C) 2003-2006 *
+ * Umbrello UML Modeller Authors <uml-devel@uml.sf.net> *
+ ***************************************************************************/
+
+/* This code generated by:
+ * Author : thomas
+ * Date : Thu Aug 28 2003
+ */
+
+/**
+ We carve the CPP document up into 2 documents, "source" and "header".
+ The sections of each are as follows:
+
+ * header
+ * includes
+ * constructor methods
+ * all other methods
+
+*/
+
+// own header
+#include "cppsourcecodedocument.h"
+// qt/kde includes
+#include <kdebug.h>
+#include <qregexp.h>
+// app includes
+#include "cppcodegenerator.h"
+#include "cppcodegenerationpolicy.h"
+#include "cppcodedocumentation.h"
+#include "cppcodeclassfield.h"
+#include "cppsourcecodeclassfielddeclarationblock.h"
+#include "../uml.h"
+
+// Constructors/Destructors
+//
+
+CPPSourceCodeDocument::CPPSourceCodeDocument ( UMLClassifier * concept )
+ : ClassifierCodeDocument (concept) {
+ init ( );
+}
+
+CPPSourceCodeDocument::~CPPSourceCodeDocument ( ) { }
+
+//
+// Methods
+//
+
+// Accessor methods
+//
+
+// Other methods
+//
+
+QString CPPSourceCodeDocument::getCPPClassName (const QString &name) {
+ return CodeGenerator::cleanName(name);
+}
+
+// Initialize this cpp classifier code document
+void CPPSourceCodeDocument::init ( ) {
+
+ setFileExtension(".cpp");
+
+ methodsBlock = 0;
+ constructorBlock = 0;
+
+ //initCodeClassFields(); // this is dubious because it calls down to
+ // CodeGenFactory::newCodeClassField(this)
+ // but "this" is still in construction at that time.
+
+ // this will call updateContent() as well as other things that sync our document.
+ //synchronize();
+}
+
+/**
+ * @param op
+ */
+// in the vannilla version, we just tack all operations on the end
+// of the document
+bool CPPSourceCodeDocument::addCodeOperation (CodeOperation * op ) {
+
+ if(!op->getParentOperation()->isLifeOperation())
+ {
+ return methodsBlock->addTextBlock(op);
+ } else
+ return constructorBlock->addTextBlock(op);
+}
+
+
+void CPPSourceCodeDocument::resetTextBlocks()
+{
+
+ // all special pointers need to be zero'd out.
+ methodsBlock = 0;
+ constructorBlock = 0;
+
+ // now do the traditional release of child text blocks
+ ClassifierCodeDocument::resetTextBlocks();
+
+}
+
+// This method will cause the class to rebuild its text representation.
+// based on the parent classifier object.
+// For any situation in which this is called, we are either building the code
+// document up, or replacing/regenerating the existing auto-generated parts. As
+// such, we will want to insert everything we reasonably will want
+// during creation. We can set various parts of the document (esp. the
+// comments) to appear or not, as needed.
+void CPPSourceCodeDocument::updateContent( )
+{
+
+ // Gather info on the various fields and parent objects of this class...
+ //UMLClassifier * c = getParentClassifier();
+ CodeGenPolicyExt *pe = UMLApp::app()->getPolicyExt();
+ CPPCodeGenerationPolicy * policy = dynamic_cast<CPPCodeGenerationPolicy*>(pe);
+ QString endLine = UMLApp::app()->getCommonPolicy()->getNewLineEndingChars();
+
+ // first, set the global flag on whether or not to show classfield info
+ CodeClassFieldList * cfList = getCodeClassFieldList();
+ for(CodeClassField * field = cfList->first(); field; field = cfList->next())
+ field->setWriteOutMethods(policy->getAutoGenerateAccessors());
+
+ // attribute-based ClassFields
+ // we do it this way to have the static fields sorted out from regular ones
+ CodeClassFieldList staticAttribClassFields = getSpecificClassFields (CodeClassField::Attribute, true);
+ CodeClassFieldList attribClassFields = getSpecificClassFields (CodeClassField::Attribute, false);
+ // association-based ClassFields
+ // don't care if they are static or not..all are lumped together
+ CodeClassFieldList plainAssocClassFields = getSpecificClassFields ( CodeClassField::PlainAssociation );
+ CodeClassFieldList aggregationClassFields = getSpecificClassFields ( CodeClassField::Aggregation );
+ CodeClassFieldList compositionClassFields = getSpecificClassFields ( CodeClassField::Composition );
+
+ // START GENERATING CODE/TEXT BLOCKS and COMMENTS FOR THE DOCUMENT
+ //
+
+ // INCLUDE CODEBLOCK
+ QString includeStatement = "";
+ // Include own header file
+ QString myOwnName( getParentClassifier()->getName() );
+ includeStatement.append("#include \""+CodeGenerator::cleanName(myOwnName.lower())+".h\""+endLine);
+ CodeBlockWithComments * iblock = addOrUpdateTaggedCodeBlockWithComments("includes", includeStatement, QString::null, 0, false);
+ iblock->setWriteOutText(true);
+
+ // After the includes we have just 2 big blocks basically, the "constructor" block and the
+ // block for the rest of our methods (operations + accessors)
+
+ constructorBlock = getHierarchicalCodeBlock("constructionMethodsBlock", "Constructors/Destructors", 0);
+ methodsBlock = getHierarchicalCodeBlock("otherMethodsBlock", "Methods", 0);
+
+ // add accessors to the methods block
+ methodsBlock->addCodeClassFieldMethods(staticAttribClassFields);
+ methodsBlock->addCodeClassFieldMethods(attribClassFields);
+ methodsBlock->addCodeClassFieldMethods(plainAssocClassFields);
+ methodsBlock->addCodeClassFieldMethods(aggregationClassFields);
+ methodsBlock->addCodeClassFieldMethods(compositionClassFields);
+
+ // constructors and other operations are handled by the "addCodeOperation" method above.
+
+}
+
+
+#include "cppsourcecodedocument.moc"
diff --git a/umbrello/umbrello/codegenerators/cppsourcecodedocument.h b/umbrello/umbrello/codegenerators/cppsourcecodedocument.h
new file mode 100644
index 00000000..8ca59c95
--- /dev/null
+++ b/umbrello/umbrello/codegenerators/cppsourcecodedocument.h
@@ -0,0 +1,73 @@
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * copyright (C) 2004-2006 *
+ * Umbrello UML Modeller Authors <uml-devel@uml.sf.net> *
+ ***************************************************************************/
+
+/* This code generated by:
+ * Author : thomas
+ * Date : Thu Aug 28 2003
+ */
+
+#ifndef CPPSOURCECODEDOCUMENT_H
+#define CPPSOURCECODEDOCUMENT_H
+
+#include <qstring.h>
+
+#include "../classifiercodedocument.h"
+#include "../hierarchicalcodeblock.h"
+#include "classifierinfo.h"
+
+/**
+ * class CPPSourceCodeDocument
+ * A CPP UMLClassifier Source Code Document.
+ */
+
+class CPPSourceCodeDocument : public ClassifierCodeDocument
+{
+ Q_OBJECT
+public:
+
+ // Constructors/Destructors
+ //
+
+ /**
+ * Constructor
+ */
+ CPPSourceCodeDocument (UMLClassifier * classifier);
+
+ /**
+ * Empty Destructor
+ */
+ virtual ~CPPSourceCodeDocument ( );
+
+ /** add a code operation to this cpp classifier code document.
+ * @return bool which is true IF the code operation was added successfully
+ */
+ bool addCodeOperation (CodeOperation * op );
+
+protected:
+
+ // reset/clear our inventory of textblocks in this document
+ void resetTextBlocks();
+
+ // a little utility method to save us some work
+ QString getCPPClassName (const QString &name);
+
+ void updateContent();
+
+private:
+
+ HierarchicalCodeBlock * constructorBlock;
+ HierarchicalCodeBlock * methodsBlock;
+
+ void init ( );
+
+};
+
+#endif // CPPSOURCECODEDOCUMENT_H
diff --git a/umbrello/umbrello/codegenerators/cppsourcecodeoperation.cpp b/umbrello/umbrello/codegenerators/cppsourcecodeoperation.cpp
new file mode 100644
index 00000000..0d8115b6
--- /dev/null
+++ b/umbrello/umbrello/codegenerators/cppsourcecodeoperation.cpp
@@ -0,0 +1,193 @@
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * copyright (C) 2004-2006 *
+ * Umbrello UML Modeller Authors <uml-devel@uml.sf.net> *
+ ***************************************************************************/
+
+/* This code generated by:
+ * Author : thomas
+ * Date : Mon Sep 1 2003
+ */
+
+#include "cppsourcecodeoperation.h"
+
+#include "cppcodegenerator.h"
+#include "cppcodegenerationpolicy.h"
+#include "cppsourcecodedocument.h"
+#include "cppcodedocumentation.h"
+#include "../uml.h"
+
+// Constructors/Destructors
+//
+
+CPPSourceCodeOperation::CPPSourceCodeOperation ( CPPSourceCodeDocument * doc, UMLOperation *parent, const QString & body, const QString & comment )
+ : CodeOperation (doc, parent, body, comment)
+{
+ // lets not go with the default comment and instead use
+ // full-blown cpp documentation object instead
+ setComment(new CPPCodeDocumentation(doc));
+
+ // these things never change..
+ setOverallIndentationLevel(0);
+ setEndMethodText("}");
+
+ //updateMethodDeclaration();
+ CodeGenPolicyExt * pe = UMLApp::app()->getPolicyExt();
+ CPPCodeGenerationPolicy * policy = dynamic_cast<CPPCodeGenerationPolicy*>(pe);
+ UMLClassifier * c = doc->getParentClassifier();
+ UMLOperation * o = getParentOperation();
+ bool isInterface = doc->parentIsInterface();
+ bool isInlineMethod = policy->getOperationsAreInline( );
+
+ // first, the comment on the operation
+ QString cmnt = o->getDoc();
+ getComment()->setText(cmnt);
+
+ QString returnType = o->getTypeName();
+ QString methodName = o->getName();
+ QString paramStr = QString("");
+ QString className = CodeGenerator::cleanName(c->getName());
+
+ // assemble parameters
+ UMLAttributeList list = getParentOperation()->getParmList();
+ int nrofParam = list.count();
+ int paramNum = 0;
+ for(UMLAttribute* parm = list.first(); parm; parm=list.next())
+ {
+ QString rType = parm->getTypeName();
+ QString paramName = parm->getName();
+ paramStr += rType + ' ' + paramName;
+ paramNum++;
+
+ if (paramNum != nrofParam )
+ paramStr += ", ";
+ }
+
+ // no return type for constructors/destructors
+ if (o->isLifeOperation())
+ returnType = "";
+ // if an operation isn't a constructor/destructor and it has no return type
+ // this operation should be void
+ else if (returnType.isEmpty())
+ returnType = QString("void");
+
+ QString startText = returnType + ' ';
+
+ // if a property has a friend stereotype, the operation should
+ // not be a class name
+ if (o->getStereotype() != "friend")
+ startText += className + "::";
+ startText += methodName + " (" + paramStr + ')';
+ if (o->getConst())
+ startText += " const";
+ startText += " {";
+
+ setStartMethodText(startText);
+
+ // Only write this out if its a child of an interface OR is abstract.
+ // and its not inline
+ if(isInterface || o->getAbstract() || isInlineMethod)
+ {
+ setWriteOutText(false);
+ } else {
+ setWriteOutText(true);
+ }
+
+
+ updateContent();
+}
+
+CPPSourceCodeOperation::~CPPSourceCodeOperation ( ) { }
+
+// Other methods
+//
+
+// we basically just want to know whether or not to print out
+// the body of the operation.
+// In C++ if the operations are inline, then we DONT print out
+// the body text.
+void CPPSourceCodeOperation::updateContent( )
+{
+ CodeGenPolicyExt *pe = UMLApp::app()->getPolicyExt();
+ CPPCodeGenerationPolicy * policy = dynamic_cast<CPPCodeGenerationPolicy*>(pe);
+ bool isInlineMethod = policy->getOperationsAreInline();
+
+ if(!isInlineMethod)
+ setText(""); // change whatever it is to "";
+
+}
+
+// we basically want to update the doc and start text of this method
+void CPPSourceCodeOperation::updateMethodDeclaration()
+{
+
+ CPPSourceCodeDocument * doc = dynamic_cast<CPPSourceCodeDocument*>(getParentDocument());
+ CodeGenPolicyExt *pe = UMLApp::app()->getPolicyExt();
+ CPPCodeGenerationPolicy * policy = dynamic_cast<CPPCodeGenerationPolicy*>(pe);
+ UMLClassifier * c = doc->getParentClassifier();
+ UMLOperation * o = getParentOperation();
+ bool isInterface = doc->parentIsInterface();
+ bool isInlineMethod = policy->getOperationsAreInline( );
+
+ // first, the comment on the operation
+ QString comment = o->getDoc();
+ getComment()->setText(comment);
+
+ QString returnType = o->getTypeName();
+ QString methodName = o->getName();
+ QString paramStr = QString("");
+ QString className = CodeGenerator::cleanName(c->getName());
+
+ // assemble parameters
+ UMLAttributeList list = getParentOperation()->getParmList();
+ int nrofParam = list.count();
+ int paramNum = 0;
+ for(UMLAttribute* parm = list.first(); parm; parm=list.next())
+ {
+ QString rType = parm->getTypeName();
+ QString paramName = parm->getName();
+ paramStr += rType + ' ' + paramName;
+ paramNum++;
+
+ if (paramNum != nrofParam )
+ paramStr += ", ";
+ }
+
+ // no return type for constructors/destructors
+ if (o->isLifeOperation())
+ returnType = "";
+ // if an operation isn't a constructor/destructor and it has no return type
+ // this operation should be void
+ else if (returnType.isEmpty())
+ returnType = QString("void");
+
+ QString startText = returnType + ' ';
+
+ // if a property has a friend stereotype, the operation should
+ // not be a class name
+ if (o->getStereotype() != "friend")
+ startText += className + "::";
+ startText += methodName + " (" + paramStr + ')';
+ if (o->getConst())
+ startText += " const";
+ startText += " {";
+
+ setStartMethodText(startText);
+
+ // Only write this out if its a child of an interface OR is abstract.
+ // and its not inline
+ if(isInterface || o->getAbstract() || isInlineMethod)
+ {
+ setWriteOutText(false);
+ } else {
+ setWriteOutText(true);
+ }
+
+}
+
+#include "cppsourcecodeoperation.moc"
diff --git a/umbrello/umbrello/codegenerators/cppsourcecodeoperation.h b/umbrello/umbrello/codegenerators/cppsourcecodeoperation.h
new file mode 100644
index 00000000..e2112178
--- /dev/null
+++ b/umbrello/umbrello/codegenerators/cppsourcecodeoperation.h
@@ -0,0 +1,51 @@
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * copyright (C) 2004-2006 *
+ * Umbrello UML Modeller Authors <uml-devel@uml.sf.net> *
+ ***************************************************************************/
+
+/* This code generated by:
+ * Author : thomas
+ * Date : Mon Sep 1 2003
+ */
+
+
+#ifndef CPPSOURCECODEOPERATION_H
+#define CPPSOURCECODEOPERATION_H
+
+#include <qstring.h>
+#include "../codeoperation.h"
+
+class CPPSourceCodeDocument;
+
+class CPPSourceCodeOperation : virtual public CodeOperation
+{
+ Q_OBJECT
+public:
+
+ // Constructors/Destructors
+ //
+
+ /**
+ * Empty Constructor
+ */
+ CPPSourceCodeOperation ( CPPSourceCodeDocument * doc, UMLOperation * op, const QString & body = "", const QString & comment = "");
+
+ /**
+ * Empty Destructor
+ */
+ virtual ~CPPSourceCodeOperation ( );
+
+protected:
+
+ virtual void updateMethodDeclaration();
+ virtual void updateContent( );
+
+};
+
+#endif // CPPSOURCECODEOPERATION_H
diff --git a/umbrello/umbrello/codegenerators/cppwriter.cpp b/umbrello/umbrello/codegenerators/cppwriter.cpp
new file mode 100644
index 00000000..b24c12b0
--- /dev/null
+++ b/umbrello/umbrello/codegenerators/cppwriter.cpp
@@ -0,0 +1,1283 @@
+/***************************************************************************
+ * cppwriter.cpp - description *
+ * This is the "old" code generator that does not support code editing *
+ * in the Modeller but uses significantly less file space because the *
+ * source code is not replicated in the XMI file. *
+ * *
+ * copyright : (C) 2003 Brian Thomas brian.thomas@gsfc.nasa.gov *
+ * (C) 2004-2006 Umbrello UML Modeller Authors <uml-devel@uml.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. *
+ * *
+ ***************************************************************************/
+
+// own header
+#include "cppwriter.h"
+// qt/kde includes
+#include <qfile.h>
+#include <qtextstream.h>
+#include <qregexp.h>
+#include <kdebug.h>
+// app includes
+#include "classifierinfo.h"
+#include "codegen_utils.h"
+#include "../uml.h"
+#include "../umldoc.h"
+#include "../classifier.h"
+#include "../operation.h"
+#include "../template.h"
+#include "../umltemplatelist.h"
+#include "../umlclassifierlistitemlist.h"
+#include "../classifierlistitem.h"
+#include "../model_utils.h"
+#include "../codegenerationpolicy.h"
+
+// 3-14-2003: this code developed from the javawriter with parts of the
+// original cppwriter by Luis De la Parra Blum
+
+CppWriter::CppWriter()
+{
+ // Probably we could resolve this better through the use of templates,
+ // but its a quick n dirty fix for the timebeing.. until codegeneration
+ // template system is in place.
+ // You can insert code here. 3 general variables exist: "%VARNAME%"
+ // allows you to specify where the vector variable should be in your code,
+ // and "%ITEMCLASS%", if needed, where the class of the item is declared.
+ VECTOR_METHOD_APPEND = "%VARNAME%.push_back(add_object);"; // for std::vector
+ VECTOR_METHOD_REMOVE = "int i, size = %VARNAME%.size();\nfor ( i = 0; i < size; i++) {\n\t%ITEMCLASS% item = %VARNAME%.at(i);\n\tif(item == remove_object) {\n\t\tvector<%ITEMCLASS%>::iterator it = %VARNAME%.begin() + i;\n\t\t%VARNAME%.erase(it);\n\t\treturn;\n\t}\n }"; // for std::vector
+ VECTOR_METHOD_INIT = QString(); // nothing to be done
+ /*
+ VECTOR_METHOD_APPEND = "%VARNAME%.append(&add_object);"; // Qt lib implementation
+ VECTOR_METHOD_REMOVE = "%VARNAME%.removeRef(&remove_object);"; // Qt lib implementation
+ VECTOR_METHOD_INIT = "%VARNAME%.setAutoDelete(false);"; // Qt library
+ */
+
+ OBJECT_METHOD_INIT = "%VARNAME% = new %ITEMCLASS%( );"; // Qt library
+
+ // boolean config params
+ INLINE_ASSOCIATION_METHODS = false;
+
+}
+
+CppWriter::~CppWriter() { }
+
+Uml::Programming_Language CppWriter::getLanguage() {
+ return Uml::pl_Cpp;
+}
+
+CPPCodeGenerationPolicy *CppWriter::policyExt() {
+ return static_cast<CPPCodeGenerationPolicy*>(UMLApp::app()->getPolicyExt());
+}
+
+void CppWriter::writeClass(UMLClassifier *c)
+{
+
+ if (!c) {
+ kDebug() << "Cannot write class of NULL concept!\n";
+ return;
+ }
+
+ QFile fileh, filecpp;
+
+ // find an appropriate name for our file
+ QString fileName = findFileName(c, ".h");
+ if (fileName.isEmpty()) {
+ emit codeGenerated(c, false);
+ return;
+ }
+
+ // preparations
+ m_classifierInfo = new ClassifierInfo(c);
+ m_classifierInfo->fileName = fileName;
+ m_classifierInfo->className = cleanName(c->getName());
+
+ if (c->getVisibility() != Uml::Visibility::Implementation) {
+ if( !openFile(fileh, fileName)) {
+ emit codeGenerated(c, false);
+ return;
+ }
+ // write Header file
+ writeHeaderFile(c, fileh);
+ fileh.close();
+ }
+
+ // Determine whether the implementation file is required.
+ // (It is not required if the class is an enumeration.)
+ bool need_impl = true;
+ if (c->getBaseType() == Uml::ot_Enum) {
+ need_impl = false;
+ }
+ if (need_impl) {
+ fileName.replace( QRegExp(".h$"), ".cpp");
+ if( !openFile(filecpp, fileName)) {
+ emit codeGenerated(c, false);
+ return;
+ }
+ // write Source file
+ writeSourceFile(c, filecpp);
+ filecpp.close();
+ }
+
+ // Wrap up: free m_classifierInfo, emit done code
+ m_classifierInfo = 0;
+
+ emit codeGenerated(c, true);
+
+}
+
+void CppWriter::writeHeaderFile (UMLClassifier *c, QFile &fileh) {
+
+ // open stream for writing
+ QTextStream h (&fileh);
+
+ // up the indent level to one
+ m_indentLevel = 1;
+
+ // write header blurb
+ QString str = getHeadingFile(".h");
+ if(!str.isEmpty()) {
+ str.replace(QRegExp("%filename%"),m_classifierInfo->fileName + ".h");
+ str.replace(QRegExp("%filepath%"),fileh.name());
+ h << str<< m_endl;
+ }
+
+ // Write the hash define stuff to prevent multiple parsing/inclusion of header
+ QString hashDefine = m_classifierInfo->className.upper().simplifyWhiteSpace().replace(QRegExp(" "), "_");
+ writeBlankLine(h);
+ h << "#ifndef "<< hashDefine + "_H" << m_endl;
+ h << "#define "<< hashDefine + "_H" << m_endl;
+
+ writeClassDecl(c, h);
+
+ // last thing..close our hashdefine
+ h << m_endl << "#endif // " << hashDefine + "_H" << m_endl;
+
+}
+
+void CppWriter::writeHeaderAccessorMethodDecl(UMLClassifier *c, Uml::Visibility permitScope, QTextStream &stream)
+{
+
+ // attributes
+ writeHeaderAttributeAccessorMethods(permitScope, true, stream); // write static attributes first
+ writeHeaderAttributeAccessorMethods(permitScope, false, stream);
+
+ // associations
+ writeAssociationMethods(m_classifierInfo->plainAssociations, permitScope,
+ true, INLINE_ASSOCIATION_METHODS, true, c->getID(), stream);
+ writeAssociationMethods(m_classifierInfo->uniAssociations, permitScope,
+ true, INLINE_ASSOCIATION_METHODS, true, c->getID(), stream);
+ writeAssociationMethods(m_classifierInfo->aggregations, permitScope,
+ true, INLINE_ASSOCIATION_METHODS, true, c->getID(), stream);
+ writeAssociationMethods(m_classifierInfo->compositions, permitScope,
+ true, INLINE_ASSOCIATION_METHODS, false, c->getID(), stream);
+
+ writeBlankLine(stream);
+
+}
+
+void CppWriter::writeHeaderFieldDecl(UMLClassifier *c, Uml::Visibility permitScope, QTextStream &stream)
+{
+ // attributes
+ writeAttributeDecls(permitScope, true, stream); // write static attributes first
+ writeAttributeDecls(permitScope, false, stream);
+
+ // associations
+ writeAssociationDecls(m_classifierInfo->plainAssociations, permitScope, c->getID(), stream);
+ writeAssociationDecls(m_classifierInfo->uniAssociations, permitScope, c->getID(), stream);
+ writeAssociationDecls(m_classifierInfo->aggregations, permitScope, c->getID(), stream);
+ writeAssociationDecls(m_classifierInfo->compositions, permitScope, c->getID(), stream);
+
+}
+
+void CppWriter::writeSourceFile (UMLClassifier *c, QFile &filecpp ) {
+
+ // open stream for writing
+ QTextStream cpp (&filecpp);
+
+ // set the starting indentation at zero
+ m_indentLevel = 0;
+
+ //try to find a heading file (license, coments, etc)
+ QString str;
+ str = getHeadingFile(".cpp");
+ if(!str.isEmpty()) {
+ str.replace(QRegExp("%filename%"),m_classifierInfo->fileName + ".cpp");
+ str.replace(QRegExp("%filepath%"),filecpp.name());
+ cpp << str << m_endl;
+ }
+
+ // IMPORT statements
+ // Q: Why all utils? Isnt just List and Vector the only classes we are using?
+ // Our import *should* also look at operations, and check that objects being
+ // used arent in another package (and thus need to be explicitly imported here).
+ cpp << "#include \"" << m_classifierInfo->className << ".h\"" << m_endl;
+ writeBlankLine(cpp);
+
+ if (c->getVisibility() == Uml::Visibility::Implementation) {
+ writeClassDecl(c, cpp);
+ }
+
+ // Start body of class
+
+ // Constructors: anything we more we need to do here ?
+ //
+ if(!m_classifierInfo->isInterface)
+ writeConstructorMethods(cpp);
+
+ // METHODS
+ //
+
+ // write comment for section IF needed
+ QString indent = getIndent();
+ if (forceDoc() || m_classifierInfo->hasAccessorMethods || m_classifierInfo->hasOperationMethods)
+ {
+
+ writeComment(" ", indent, cpp);
+ writeComment("Methods", indent, cpp);
+ writeComment(" ", indent, cpp);
+ writeBlankLine(cpp);
+ writeBlankLine(cpp);
+ }
+
+ // write comment for sub-section IF needed
+ if (forceDoc() || m_classifierInfo->hasAccessorMethods )
+ {
+ writeComment("Accessor methods", indent, cpp);
+ writeComment(" ", indent, cpp);
+ writeBlankLine(cpp);
+ }
+
+ // Accessor methods for attributes
+ const bool bInlineAccessors = policyExt()->getAccessorsAreInline();
+ if (!bInlineAccessors && m_classifierInfo->hasAttributes)
+ {
+ writeAttributeMethods(&(m_classifierInfo->static_atpub), Uml::Visibility::Public, false, true, !bInlineAccessors, cpp);
+ writeAttributeMethods(&(m_classifierInfo->atpub), Uml::Visibility::Public, false, false, !bInlineAccessors, cpp);
+ writeAttributeMethods(&(m_classifierInfo->static_atprot), Uml::Visibility::Protected, false, true, !bInlineAccessors, cpp);
+ writeAttributeMethods(&(m_classifierInfo->atprot), Uml::Visibility::Protected, false, false, !bInlineAccessors, cpp);
+ writeAttributeMethods(&(m_classifierInfo->static_atpriv), Uml::Visibility::Private, false, true, !bInlineAccessors, cpp);
+ writeAttributeMethods(&(m_classifierInfo->atpriv), Uml::Visibility::Private, false, false, !bInlineAccessors, cpp);
+ }
+
+ // accessor methods for associations
+
+ // public
+ writeAssociationMethods(m_classifierInfo->plainAssociations, Uml::Visibility::Public, false,
+ !INLINE_ASSOCIATION_METHODS, true, c->getID(), cpp);
+ writeAssociationMethods(m_classifierInfo->uniAssociations, Uml::Visibility::Public, false,
+ !INLINE_ASSOCIATION_METHODS, true, c->getID(), cpp);
+ writeAssociationMethods(m_classifierInfo->aggregations, Uml::Visibility::Public, false,
+ !INLINE_ASSOCIATION_METHODS, true, c->getID(), cpp);
+ writeAssociationMethods(m_classifierInfo->compositions, Uml::Visibility::Public, false,
+ !INLINE_ASSOCIATION_METHODS, true, c->getID(), cpp);
+
+ // protected
+ writeAssociationMethods(m_classifierInfo->plainAssociations, Uml::Visibility::Protected, false,
+ !INLINE_ASSOCIATION_METHODS, true, c->getID(), cpp);
+ writeAssociationMethods(m_classifierInfo->uniAssociations, Uml::Visibility::Protected, false,
+ !INLINE_ASSOCIATION_METHODS, true, c->getID(), cpp);
+ writeAssociationMethods(m_classifierInfo->aggregations, Uml::Visibility::Protected, false,
+ !INLINE_ASSOCIATION_METHODS, true, c->getID(), cpp);
+ writeAssociationMethods(m_classifierInfo->compositions, Uml::Visibility::Protected, false,
+ !INLINE_ASSOCIATION_METHODS, true, c->getID(), cpp);
+
+
+ // private
+ writeAssociationMethods(m_classifierInfo->plainAssociations, Uml::Visibility::Private, false,
+ !INLINE_ASSOCIATION_METHODS, true, c->getID(), cpp);
+ writeAssociationMethods(m_classifierInfo->uniAssociations, Uml::Visibility::Private, false,
+ !INLINE_ASSOCIATION_METHODS, true, c->getID(), cpp);
+ writeAssociationMethods(m_classifierInfo->aggregations, Uml::Visibility::Private, false,
+ !INLINE_ASSOCIATION_METHODS, true, c->getID(), cpp);
+ writeAssociationMethods(m_classifierInfo->compositions, Uml::Visibility::Private, false,
+ !INLINE_ASSOCIATION_METHODS, true, c->getID(), cpp);
+ writeBlankLine(cpp);
+
+ // Other operation methods -- all other operations are now written
+ //
+
+ // write comment for sub-section IF needed
+ if (forceDoc() || m_classifierInfo->hasOperationMethods)
+ {
+ writeComment("Other methods", indent, cpp);
+ writeComment(" ", indent, cpp);
+ writeBlankLine(cpp);
+ }
+
+ if(!policyExt()->getOperationsAreInline())
+ {
+ writeOperations(c,false,Uml::Visibility::Public,cpp);
+ writeOperations(c,false,Uml::Visibility::Protected,cpp);
+ writeOperations(c,false,Uml::Visibility::Private,cpp);
+ }
+
+ // Yep, bringing up the back of the bus, our initialization method for attributes
+ writeInitAttibuteMethod (cpp);
+
+ writeBlankLine(cpp);
+
+}
+
+void CppWriter::writeClassDecl(UMLClassifier *c, QTextStream &cpp)
+{
+ UMLClassifierList superclasses = m_classifierInfo->superclasses;
+ for(UMLClassifier *classifier = superclasses.first(); classifier ;classifier = superclasses.next()) {
+ QString headerName = findFileName(classifier, ".h");
+ if (!headerName.isEmpty()) {
+ cpp << "#include \"" << headerName << "\"" << m_endl;
+ }
+ }
+
+ writeBlankLine(cpp);
+ cpp << "#include " << policyExt()->getStringClassNameInclude() << m_endl;
+ if(m_classifierInfo->hasVectorFields)
+ {
+ cpp << "#include " << policyExt()->getVectorClassNameInclude() << m_endl;
+ writeBlankLine(cpp);
+ }
+
+ if(m_classifierInfo->hasAssociations)
+ {
+ // write all includes we need to include other classes, that arent us.
+ printAssociationIncludeDecl (m_classifierInfo->plainAssociations, c->getID(), cpp);
+ printAssociationIncludeDecl (m_classifierInfo->uniAssociations, c->getID(), cpp);
+ printAssociationIncludeDecl (m_classifierInfo->aggregations, c->getID(), cpp);
+ printAssociationIncludeDecl (m_classifierInfo->compositions, c->getID(), cpp);
+
+ writeBlankLine(cpp);
+ }
+
+
+ for(UMLClassifier *classifier = superclasses.first(); classifier ; classifier = superclasses.next()) {
+ if(classifier->getPackage()!=c->getPackage() && !classifier->getPackage().isEmpty()) {
+ cpp << "using " << cleanName(classifier->getPackage()) << "::" << cleanName(classifier->getName()) << ";" << m_endl;
+ }
+ }
+
+ if(!c->getPackage().isEmpty() && policyExt()->getPackageIsNamespace())
+ cpp << m_endl << "namespace " << cleanName(c->getPackage()) << " {" << m_endl << m_endl;
+
+ //Write class Documentation if there is somthing or if force option
+ if(forceDoc() || !c->getDoc().isEmpty()) {
+ cpp << m_endl << "/**" << m_endl;
+ cpp << " * class " << m_classifierInfo->className << m_endl;
+ cpp << formatDoc(c->getDoc()," * ");
+ cpp << " */";
+ writeBlankLine(cpp);
+ writeBlankLine(cpp);
+ }
+
+ //check if class is abstract and / or has abstract methods
+ if((c->getAbstract() || m_classifierInfo->isInterface )
+ && !hasAbstractOps(c))
+ cpp << "/******************************* Abstract Class ****************************" << m_endl
+ <<m_classifierInfo->className << " does not have any pure virtual methods, but its author" << m_endl
+ <<" defined it as an abstract class, so you should not use it directly." << m_endl
+ <<" Inherit from it instead and create only objects from the derived classes" << m_endl
+ <<"*****************************************************************************/" << m_endl << m_endl;
+
+ if (c->getBaseType() == Uml::ot_Enum) {
+ UMLClassifierListItemList litList = c->getFilteredList(Uml::ot_EnumLiteral);
+ uint i = 0;
+ cpp << "enum " << m_classifierInfo->className << " {" << m_endl;
+ for (UMLClassifierListItem *lit = litList.first(); lit; lit = litList.next()) {
+ QString enumLiteral = cleanName(lit->getName());
+ cpp << getIndent() << enumLiteral;
+ if (++i < litList.count())
+ cpp << ",";
+ cpp << m_endl;
+ }
+ cpp << m_endl << "};" << m_endl; // end of class header
+ if(!c->getPackage().isEmpty() && policyExt()->getPackageIsNamespace())
+ cpp << "} // end of package namespace" << m_endl;
+ return;
+ }
+
+ // Generate template parameters.
+ UMLTemplateList template_params = c->getTemplateList();
+ if (template_params.count()) {
+ cpp << "template<";
+ for (UMLTemplate *t = template_params.first(); t; ) {
+ QString formalName = t->getName();
+ QString typeName = t->getTypeName();
+ cpp << typeName << " " << formalName;
+ if ((t = template_params.next()) != NULL)
+ cpp << ", ";
+ }
+ cpp << ">" << m_endl;
+ }
+
+ cpp << "class " << m_classifierInfo->className;
+ if (m_classifierInfo->superclasses.count() > 0)
+ cpp << " : ";
+ uint numOfSuperClasses = m_classifierInfo->superclasses.count();
+ uint i = 0;
+ for (UMLClassifier *superClass = m_classifierInfo->superclasses.first();
+ superClass ; superClass = m_classifierInfo->superclasses.next())
+ {
+ i++;
+ if (superClass->getAbstract() || superClass->isInterface())
+ cpp << "virtual ";
+ cpp << "public " << cleanName(superClass->getName());
+ if (i < numOfSuperClasses)
+ cpp << ", ";
+ }
+
+ cpp << m_endl << "{" << m_endl; // begin the body of the class
+
+
+ //declarations of operations
+ //
+
+ //
+ // write out field and operations decl grouped by visibility
+ //
+
+ // PUBLIC attribs/methods
+ cpp << "public:" << m_endl << m_endl; // print visibility decl.
+ // for public: constructors are first ops we print out
+ if(!m_classifierInfo->isInterface)
+ writeConstructorDecls(cpp);
+ writeHeaderFieldDecl(c,Uml::Visibility::Public, cpp);
+ writeHeaderAccessorMethodDecl(c, Uml::Visibility::Public, cpp);
+ writeOperations(c,true,Uml::Visibility::Public,cpp);
+
+ // PROTECTED attribs/methods
+ //
+ cpp << "protected" << ":" << m_endl << m_endl; // print visibility decl.
+ writeHeaderFieldDecl(c,Uml::Visibility::Protected, cpp);
+ writeHeaderAccessorMethodDecl(c, Uml::Visibility::Protected, cpp);
+ writeOperations(c,true,Uml::Visibility::Protected,cpp);
+
+ // PRIVATE attribs/methods
+ //
+ cpp << "private" << ":" << m_endl << m_endl; // print visibility decl.
+ writeHeaderFieldDecl(c,Uml::Visibility::Private, cpp);
+ writeHeaderAccessorMethodDecl(c, Uml::Visibility::Private, cpp);
+ writeOperations(c,true,Uml::Visibility::Private,cpp);
+ writeInitAttibuteDecl(cpp); // this is always private, used by constructors to initialize class
+
+ // end of class header
+ cpp << m_endl << "};" << m_endl;
+
+ // end of class namespace, if any
+ if(!c->getPackage().isEmpty() && policyExt()->getPackageIsNamespace())
+ cpp << "}; // end of package namespace" << m_endl;
+
+}
+
+void CppWriter::writeAttributeDecls (Uml::Visibility visibility, bool writeStatic, QTextStream &stream )
+{
+
+ if(m_classifierInfo->isInterface)
+ return;
+
+ UMLAttributeList * list;
+ switch (visibility)
+ {
+ case Uml::Visibility::Private:
+ if(writeStatic)
+ list = &(m_classifierInfo->static_atpriv);
+ else
+ list = &(m_classifierInfo->atpriv);
+ break;
+
+ case Uml::Visibility::Protected:
+ if(writeStatic)
+ list = &(m_classifierInfo->static_atprot);
+ else
+ list = &(m_classifierInfo->atprot);
+ break;
+
+ case Uml::Visibility::Public:
+ default:
+ if(writeStatic)
+ list = &(m_classifierInfo->static_atpub);
+ else
+ list = &(m_classifierInfo->atpub);
+ break;
+ }
+
+ //write documentation
+ if(forceDoc() || list->count() > 0)
+ {
+ QString strVis = Codegen_Utils::capitalizeFirstLetter(visibility.toString());
+ QString strStatic = writeStatic ? "Static ":"";
+ writeComment(strStatic + strVis + " attributes",getIndent(), stream);
+ writeComment(" ",getIndent(), stream);
+ writeBlankLine(stream);
+ }
+
+ if (list->count() > 0) {
+
+ // write attrib declarations now
+ bool isFirstAttrib = true;
+ QString documentation;
+ for(UMLAttribute *at=list->first(); at; at=list->next())
+ {
+
+ // bool noPriorDocExists = documentation.isEmpty();
+ documentation = at->getDoc();
+
+ // add a line for code clarity IF PRIOR attrib has comment on it
+ // OR this line has documentation
+ // if(!isFirstAttrib && (!documentation.isEmpty()||!noPriorDocExists))
+ // writeBlankLine(stream);
+
+ isFirstAttrib = false;
+
+ QString varName = getAttributeVariableName(at);
+
+ QString staticValue = at->getStatic() ? "static " : "";
+ QString typeName = fixTypeName(at->getTypeName());
+ if(!documentation.isEmpty())
+ writeComment(documentation, getIndent(), stream);
+ stream << getIndent() << staticValue << typeName << " " << varName << ";" << m_endl;
+
+ }
+
+ /*
+ if(list->count() > 0)
+ writeBlankLine(stream);
+ */
+
+ }
+
+}
+
+void CppWriter::writeHeaderAttributeAccessorMethods (Uml::Visibility visibility, bool writeStatic, QTextStream &stream )
+{
+ // check the current policy about generate accessors as public
+ UMLAttributeList * list;
+ switch (visibility)
+ {
+ case Uml::Visibility::Private:
+ if(writeStatic)
+ list = &(m_classifierInfo->static_atpriv);
+ else
+ list = &(m_classifierInfo->atpriv);
+ break;
+
+ case Uml::Visibility::Protected:
+ if(writeStatic)
+ list = &(m_classifierInfo->static_atprot);
+ else
+ list = &(m_classifierInfo->atprot);
+ break;
+
+ case Uml::Visibility::Public:
+ default:
+ if(writeStatic)
+ list = &(m_classifierInfo->static_atpub);
+ else
+ list = &(m_classifierInfo->atpub);
+ break;
+ }
+
+ // switch to public
+ if (visibility != Uml::Visibility::Public)
+ stream << "public:" << m_endl << m_endl;
+
+ // write accessor methods for attribs we found
+ writeAttributeMethods(list, visibility, true, false, policyExt()->getAccessorsAreInline(), stream);
+
+ // switch back to previous vis.
+ if (visibility != Uml::Visibility::Public)
+ stream << visibility.toString() << ":" << m_endl << m_endl;
+}
+
+// this is for writing *source* or *header* file attribute methods
+//
+void CppWriter::writeAttributeMethods(UMLAttributeList *attribs,
+ Uml::Visibility visibility, bool isHeaderMethod,
+ bool isStatic,
+ bool writeMethodBody, QTextStream &stream)
+{
+
+ if (!policyExt()->getAutoGenerateAccessors())
+ return;
+
+ if (forceDoc() || attribs->count() > 0)
+ {
+ QString strVis = Codegen_Utils::capitalizeFirstLetter(visibility.toString());
+ QString strStatic = (isStatic ? " static" : "");
+ writeBlankLine(stream);
+ writeComment(strVis + strStatic + " attribute accessor methods",getIndent(),stream);
+ writeComment(" ",getIndent(), stream);
+ writeBlankLine(stream);
+ }
+
+ // return now if NO attributes to work on
+ if (attribs->count() == 0)
+ return;
+
+ UMLAttribute *at;
+ for(at=attribs->first(); at; at=attribs->next())
+ {
+
+ QString varName = getAttributeVariableName(at);
+ QString methodBaseName = cleanName(at->getName());
+
+ // force capitalizing the field name, this is silly,
+ // from what I can tell, this IS the default behavior for
+ // cleanName. I dunno why its not working -b.t.
+ methodBaseName = methodBaseName.stripWhiteSpace();
+ methodBaseName.replace(0,1,methodBaseName.at(0).upper());
+
+ writeSingleAttributeAccessorMethods(at->getTypeName(), varName,
+ methodBaseName, at->getDoc(), Uml::chg_Changeable, isHeaderMethod,
+ at->getStatic(), writeMethodBody, stream);
+ }
+
+}
+
+void CppWriter::writeComment(const QString &comment, const QString &myIndent, QTextStream &cpp)
+{
+ // in the case we have several line comment..
+ // NOTE: this part of the method has the problem of adopting UNIX newline,
+ // need to resolve for using with MAC/WinDoze eventually I assume
+ if (comment.contains(QRegExp("\n"))) {
+
+ QStringList lines = QStringList::split( "\n", comment);
+ for(uint i= 0; i < lines.count(); i++)
+ {
+ cpp << myIndent << "// " << lines[i] << m_endl;
+ }
+ } else {
+ // this should be more fancy in the future, breaking it up into 80 char
+ // lines so that it doesn't look too bad
+ cpp << myIndent << "// "<< comment << m_endl;
+ }
+}
+
+void CppWriter::writeDocumentation(QString header, QString body, QString end, QTextStream &cpp)
+{
+ writeBlankLine(cpp);
+ QString indent = getIndent();
+
+ cpp << indent << "/**" << m_endl;
+ if (!header.isEmpty())
+ cpp << formatDoc(header, indent + " * ");
+ if (!body.isEmpty())
+ cpp << formatDoc(body, indent + " * ");
+ if (!end.isEmpty())
+ {
+ QStringList lines = QStringList::split( "\n", end);
+ for(uint i= 0; i < lines.count(); i++)
+ cpp << formatDoc(lines[i], indent + " * ");
+ }
+ cpp << indent << " */" << m_endl;
+}
+
+void CppWriter::writeAssociationDecls(UMLAssociationList associations, Uml::Visibility permitScope, Uml::IDType id, QTextStream &h)
+{
+
+ if( forceSections() || !associations.isEmpty() )
+ {
+ bool printRoleA = false, printRoleB = false;
+ for(UMLAssociation *a = associations.first(); a; a = associations.next())
+ {
+
+ // it may seem counter intuitive, but you want to insert the role of the
+ // *other* class into *this* class.
+ if (a->getObjectId(Uml::A) == id && !a->getRoleName(Uml::B).isEmpty())
+ printRoleB = true;
+
+ if (a->getObjectId(Uml::B) == id && !a->getRoleName(Uml::A).isEmpty())
+ printRoleA = true;
+
+ // First: we insert documentaion for association IF it has either role AND some documentation (!)
+ if ((printRoleA || printRoleB) && !(a->getDoc().isEmpty()))
+ writeComment(a->getDoc(), getIndent(), h);
+
+ // print RoleB decl
+ if (printRoleB && a->getVisibility(Uml::B) == permitScope)
+ {
+
+ QString fieldClassName = cleanName(getUMLObjectName(a->getObject(Uml::B)));
+ writeAssociationRoleDecl(fieldClassName, a->getRoleName(Uml::B), a->getMulti(Uml::B), a->getRoleDoc(Uml::B), h);
+ }
+
+ // print RoleA decl
+ if (printRoleA && a->getVisibility(Uml::A) == permitScope)
+ {
+ QString fieldClassName = cleanName(getUMLObjectName(a->getObject(Uml::A)));
+ writeAssociationRoleDecl(fieldClassName, a->getRoleName(Uml::A), a->getMulti(Uml::A), a->getRoleDoc(Uml::A), h);
+ }
+
+ // reset for next association in our loop
+ printRoleA = false;
+ printRoleB = false;
+ }
+ }
+}
+
+void CppWriter::writeAssociationRoleDecl(QString fieldClassName, QString roleName, QString multi,
+ QString doc, QTextStream &stream)
+{
+ // ONLY write out IF there is a rolename given
+ // otherwise its not meant to be declared in the code
+ if (roleName.isEmpty())
+ return;
+
+ QString indent = getIndent();
+
+ // always put space between this and prior decl, if any
+ writeBlankLine(stream);
+
+ if (!doc.isEmpty())
+ writeComment(doc, indent, stream);
+
+ // declare the association based on whether it is this a single variable
+ // or a List (Vector). One day this will be done correctly with special
+ // multiplicity object that we don't have to figure out what it means via regex.
+ if(multi.isEmpty() || multi.contains(QRegExp("^[01]$")))
+ {
+ QString fieldVarName = "m_" + roleName.lower();
+
+ // record this for later consideration of initialization IF the
+ // multi value requires 1 of these objects
+ if(ObjectFieldVariables.findIndex(fieldVarName) == -1 &&
+ multi.contains(QRegExp("^1$"))
+ )
+ {
+ // ugh. UGLY. Storing variable name and its class in pairs.
+ ObjectFieldVariables.append(fieldVarName);
+ ObjectFieldVariables.append(fieldClassName);
+ }
+
+ stream << indent << fieldClassName << " * " << fieldVarName << ";" << m_endl;
+ }
+ else
+ {
+ QString fieldVarName = "m_" + roleName.lower() + "Vector";
+
+ // record unique occurrences for later when we want to check
+ // for initialization of this vector
+ if(VectorFieldVariables.findIndex(fieldVarName) == -1)
+ VectorFieldVariables.append(fieldVarName);
+
+ stream << indent << policyExt()->getVectorClassName() <<"<" << fieldClassName << "*";
+ stream << "> " << fieldVarName << ";" << m_endl;
+ }
+}
+
+// for either source or header files
+void CppWriter::writeAssociationMethods (UMLAssociationList associations,
+ Uml::Visibility permitVisib,
+ bool isHeaderMethod,
+ bool writeMethodBody,
+ bool writePointerVar,
+ Uml::IDType myID, QTextStream &stream)
+{
+ if( forceSections() || !associations.isEmpty() )
+ {
+ for(UMLAssociation *a = associations.first(); a; a = associations.next())
+ {
+
+ // insert the methods to access the role of the other
+ // class in the code of this one
+ if (a->getObjectId(Uml::A) == myID && a->getVisibility(Uml::B) == permitVisib)
+ {
+ // only write out IF there is a rolename given
+ if(!a->getRoleName(Uml::B).isEmpty()) {
+ QString fieldClassName = getUMLObjectName(a->getObject(Uml::B)) + (writePointerVar ? " *":"");
+ writeAssociationRoleMethod(fieldClassName,
+ isHeaderMethod,
+ writeMethodBody,
+ a->getRoleName(Uml::B),
+ a->getMulti(Uml::B), a->getRoleDoc(Uml::B),
+ a->getChangeability(Uml::B), stream);
+ }
+ }
+
+ if (a->getObjectId(Uml::B) == myID && a->getVisibility(Uml::A) == permitVisib)
+ {
+ // only write out IF there is a rolename given
+ if(!a->getRoleName(Uml::A).isEmpty()) {
+ QString fieldClassName = getUMLObjectName(a->getObject(Uml::A)) + (writePointerVar ? " *":"");
+ writeAssociationRoleMethod(fieldClassName,
+ isHeaderMethod,
+ writeMethodBody,
+ a->getRoleName(Uml::A),
+ a->getMulti(Uml::A),
+ a->getRoleDoc(Uml::A),
+ a->getChangeability(Uml::A),
+ stream);
+ }
+ }
+
+ }
+ }
+}
+
+void CppWriter::writeAssociationRoleMethod (const QString &fieldClassName,
+ bool isHeaderMethod,
+ bool writeMethodBody,
+ const QString &roleName, const QString &multi,
+ const QString &description, Uml::Changeability_Type change,
+ QTextStream &stream)
+{
+ if(multi.isEmpty() || multi.contains(QRegExp("^[01]$")))
+ {
+ QString fieldVarName = "m_" + roleName.lower();
+ writeSingleAttributeAccessorMethods(fieldClassName, fieldVarName, roleName,
+ description, change, isHeaderMethod, false, writeMethodBody, stream);
+ }
+ else
+ {
+ QString fieldVarName = "m_" + roleName.lower() + "Vector";
+ writeVectorAttributeAccessorMethods(fieldClassName, fieldVarName, roleName,
+ description, change, isHeaderMethod, writeMethodBody, stream);
+ }
+}
+
+void CppWriter::writeVectorAttributeAccessorMethods (
+ const QString &fieldClassName, const QString &fieldVarName,
+ const QString &fieldName, const QString &description,
+ Uml::Changeability_Type changeType,
+ bool isHeaderMethod,
+ bool writeMethodBody,
+ QTextStream &stream)
+{
+
+ QString className = fixTypeName(fieldClassName);
+ QString fldName = Codegen_Utils::capitalizeFirstLetter(fieldName);
+ QString indent = getIndent();
+
+ // ONLY IF changeability is NOT Frozen
+ if (changeType != Uml::chg_Frozen)
+ {
+ writeDocumentation("Add a " + fldName + " object to the " + fieldVarName + " List",description,"",stream);
+ stream << indent << "void ";
+ if(!isHeaderMethod)
+ stream << m_classifierInfo->className << "::";
+ stream << "add" << fldName << " ( " << className << " add_object )";
+ if (writeMethodBody) {
+ QString method = VECTOR_METHOD_APPEND;
+ method.replace(QRegExp("%VARNAME%"),fieldVarName);
+ method.replace(QRegExp("%VECTORTYPENAME%"), policyExt()->getVectorClassName());
+ method.replace(QRegExp("%ITEMCLASS%"),className);
+ stream << indent << " {" << m_endl;
+ m_indentLevel++;
+ printTextAsSeparateLinesWithIndent(method,getIndent(),stream);
+ m_indentLevel--;
+ stream << indent << "}" << m_endl;
+ } else
+ stream << ";" << m_endl;
+ }
+
+ // ONLY IF changeability is Changeable
+ if (changeType == Uml::chg_Changeable)
+ {
+ writeDocumentation("Remove a " + fldName + " object from " + fieldVarName + " List",
+ description, "", stream);
+ stream << indent << "void ";
+ if(!isHeaderMethod)
+ stream << m_classifierInfo->className << "::";
+ stream << "remove" << fldName << " ( " << className << " remove_object )";
+ if (writeMethodBody) {
+ QString method = VECTOR_METHOD_REMOVE;
+ method.replace(QRegExp("%VARNAME%"),fieldVarName);
+ method.replace(QRegExp("%VECTORTYPENAME%"), policyExt()->getVectorClassName());
+ method.replace(QRegExp("%ITEMCLASS%"),className);
+ stream << indent << " {" << m_endl;
+ m_indentLevel++;
+ printTextAsSeparateLinesWithIndent(method,getIndent(),stream);
+ m_indentLevel--;
+ stream << indent << "}" << m_endl;
+ } else
+ stream << ";" << m_endl;
+ }
+
+ // always allow getting the list of stuff
+ QString returnVarName = policyExt()->getVectorClassName() + '<' + className + '>';
+ writeDocumentation("Get the list of " + fldName + " objects held by " + fieldVarName,
+ description,
+ "@return " + returnVarName + " list of " + fldName + " objects held by " + fieldVarName,
+ stream);
+ stream << indent << returnVarName << " ";
+ if(!isHeaderMethod)
+ stream << m_classifierInfo->className << "::";
+ stream << "get" << fldName << "List ( )";
+ if(writeMethodBody) {
+ stream << indent << " {" << m_endl;
+ m_indentLevel++;
+ stream << getIndent() << "return " << fieldVarName << ";" << m_endl;
+ m_indentLevel--;
+ stream << indent << "}" << m_endl;
+ } else
+ stream << ";" << m_endl;
+
+}
+
+
+void CppWriter::writeSingleAttributeAccessorMethods(
+ const QString& fieldClassName, const QString& fieldVarName,
+ const QString& fieldName, const QString &description,
+ Uml::Changeability_Type change,
+ bool isHeaderMethod,
+ bool isStatic,
+ bool writeMethodBody,
+ QTextStream &stream)
+{
+
+ // DON'T write this IF its a source method AND writeMethodBody is "false"
+ if(!isHeaderMethod && !writeMethodBody)
+ return;
+
+ QString className = fixTypeName(fieldClassName);
+ QString fldName = Codegen_Utils::capitalizeFirstLetter(fieldName);
+ QString indent = getIndent();
+
+ // set method
+ if (change == Uml::chg_Changeable && !isStatic) {
+ writeDocumentation("Set the value of " + fieldVarName,description,"@param new_var the new value of " + fieldVarName,stream);
+ stream << indent << "void ";
+ if(!isHeaderMethod)
+ stream << m_classifierInfo->className << "::";
+ stream << "set" << fldName << " ( " << className << " new_var )";
+
+ if(writeMethodBody) {
+ stream << indent << " {" << m_endl;
+ m_indentLevel++;
+ stream << getIndent() << indent;
+ m_indentLevel--;
+ if(isStatic)
+ stream << m_classifierInfo->className << "::";
+ stream << fieldVarName << " = new_var;" << m_endl;
+ stream << indent << "}" << m_endl;
+ } else
+ stream << ";" << m_endl;
+ }
+
+ // get method
+ writeDocumentation("Get the value of " + fieldVarName,description,"@return the value of " + fieldVarName,stream);
+ stream << indent << className << " ";
+ if(!isHeaderMethod)
+ stream << m_classifierInfo->className << "::";
+ stream << "get" << fldName << " ( )";
+
+ if(writeMethodBody) {
+ stream << indent << " {" << m_endl;
+ m_indentLevel++;
+ stream << getIndent() << "return ";
+ m_indentLevel--;
+ if(isStatic)
+ stream << m_classifierInfo->className << "::";
+ stream << fieldVarName << ";" << m_endl;
+ stream << indent << "}";
+ } else
+ stream << ";" << m_endl;
+
+ writeBlankLine(stream);
+}
+
+// one day, this should print out non-empty constructor operations too.
+void CppWriter::writeConstructorDecls(QTextStream &stream)
+{
+ const bool generateEmptyConstructors =
+ UMLApp::app()->getCommonPolicy()->getAutoGenerateConstructors();
+ if (forceDoc() || generateEmptyConstructors)
+ {
+ writeComment("Constructors/Destructors", getIndent(), stream);
+ writeComment(" ", getIndent(), stream);
+ writeBlankLine(stream);
+ }
+ if (!generateEmptyConstructors)
+ return;
+
+ writeDocumentation("", "Empty Constructor", "", stream);
+ stream << getIndent() << m_classifierInfo->className << " ( );" << m_endl;
+ writeDocumentation("", "Empty Destructor", "", stream);
+ stream << getIndent();
+ stream << "virtual ~" << m_classifierInfo->className << " ( );" << m_endl;
+ writeBlankLine(stream);
+}
+
+void CppWriter::writeInitAttibuteDecl (QTextStream &stream)
+{
+ if (UMLApp::app()->getCommonPolicy()->getAutoGenerateConstructors() &&
+ m_classifierInfo->hasAttributes)
+ stream << getIndent() << "void initAttributes ( ) ;" << m_endl;
+}
+
+void CppWriter::writeInitAttibuteMethod (QTextStream &stream)
+{
+ // only need to do this under certain conditions
+ if (!UMLApp::app()->getCommonPolicy()->getAutoGenerateConstructors() ||
+ !m_classifierInfo->hasAttributes)
+ return;
+
+ QString className = m_classifierInfo->className;
+ QString indent = getIndent();
+
+ stream << indent << "void " << className << "::" << "initAttributes ( ) {" << m_endl;
+
+ m_indentLevel++;
+ // first, initiation of fields derived from attributes
+ UMLAttributeList atl = m_classifierInfo->getAttList();
+ for(UMLAttribute *at = atl.first(); at ; at = atl.next()) {
+ if(!at->getInitialValue().isEmpty()) {
+ QString varName = getAttributeVariableName(at);
+ stream << getIndent() << varName << " = " << at->getInitialValue() << ";" << m_endl;
+ }
+ }
+ // Now initialize the association related fields (e.g. vectors)
+ if (!VECTOR_METHOD_INIT.isEmpty()) {
+ QStringList::Iterator it;
+ for( it = VectorFieldVariables.begin(); it != VectorFieldVariables.end(); ++it ) {
+ QString fieldVarName = *it;
+ QString method = VECTOR_METHOD_INIT;
+ method.replace(QRegExp("%VARNAME%"),fieldVarName);
+ method.replace(QRegExp("%VECTORTYPENAME%"), policyExt()->getVectorClassName());
+ stream << getIndent() << method << m_endl;
+ }
+ }
+
+ if (!OBJECT_METHOD_INIT.isEmpty()) {
+ QStringList::Iterator it;
+ for( it = ObjectFieldVariables.begin(); it != ObjectFieldVariables.end(); ++it ) {
+ QString fieldVarName = *it;
+ it++;
+ QString fieldClassName = *it;
+ QString method = OBJECT_METHOD_INIT;
+ method.replace(QRegExp("%VARNAME%"),fieldVarName);
+ method.replace(QRegExp("%ITEMCLASS%"),fieldClassName);
+ stream << getIndent() << method << m_endl;
+ }
+ }
+
+ // clean up
+ ObjectFieldVariables.clear(); // shouldn't be needed?
+ VectorFieldVariables.clear(); // shouldn't be needed?
+
+ m_indentLevel--;
+
+ stream << indent << "}" << m_endl;
+}
+
+// one day, this should print out non-empty constructor operations too.
+void CppWriter::writeConstructorMethods(QTextStream &stream)
+{
+ const bool generateEmptyConstructors =
+ UMLApp::app()->getCommonPolicy()->getAutoGenerateConstructors();
+
+ if (forceDoc() || generateEmptyConstructors) {
+ writeComment("Constructors/Destructors", getIndent(), stream);
+ writeComment(" ", getIndent(), stream);
+ writeBlankLine(stream);
+ }
+ if (!generateEmptyConstructors)
+ return;
+
+ QString className = m_classifierInfo->className;
+ // empty constructor
+ QString indent = getIndent();
+ stream << indent << className << "::" << className << " ( ) {" << m_endl;
+ if(m_classifierInfo->hasAttributes)
+ stream << indent << indent << "initAttributes();" << m_endl;
+ stream << indent << "}" << m_endl;
+ writeBlankLine(stream);
+
+ // empty destructor
+ stream << getIndent() << className << "::~" << className << " ( ) { }" << m_endl;
+ writeBlankLine(stream);
+}
+
+// IF the type is "string" we need to declare it as
+// the Java Object "String" (there is no string primative in Java).
+QString CppWriter::fixTypeName(const QString &string)
+{
+ if (string.isEmpty())
+ return "void";
+ if (string == "string")
+ return policyExt()->getStringClassName();
+ return string;
+}
+
+void CppWriter::writeOperations(UMLClassifier *c, bool isHeaderMethod,
+ Uml::Visibility permitScope, QTextStream &cpp) {
+
+ UMLOperationList oplist;
+
+ //sort operations by scope first and see if there are abstract methods
+ UMLOperationList inputlist = c->getOpList();
+ for (UMLOperation *op = inputlist.first(); op; op = inputlist.next()) {
+ if (op->getVisibility() == permitScope) {
+ oplist.append(op);
+ }
+ }
+
+ // do people REALLY want these comments? Hmm.
+ /*
+ if(forceSections() || oppub.count())
+ {
+ writeComment("public operations",getIndent(),cpp);
+ writeBlankLine(cpp);
+ }
+ */
+ writeOperations(oplist,isHeaderMethod, cpp);
+
+}
+
+// write operation in either header or
+// a source file
+void CppWriter::writeOperations(UMLOperationList &oplist, bool isHeaderMethod, QTextStream &cpp) {
+ QString className = m_classifierInfo->className;
+ const bool generateEmptyConstructors =
+ UMLApp::app()->getCommonPolicy()->getAutoGenerateConstructors();
+
+ // generate method decl for each operation given
+ for (UMLOperation *op = oplist.first(); op; op = oplist.next()) {
+
+ QString returnStr; // buffer for documentation
+ QString methodReturnType;
+ UMLAttributeList atl = op->getParmList(); // method parameters
+
+ if (op->isConstructorOperation()) {
+ if (generateEmptyConstructors && atl.count() == 0)
+ continue; // it's already been written, see writeConstructor{Decls,Methods}
+ } else if (op->isDestructorOperation()) {
+ if (generateEmptyConstructors)
+ continue; // it's already been written, see writeConstructor{Decls,Methods}
+ } else {
+ methodReturnType = fixTypeName(op->getTypeName());
+ if(methodReturnType != "void")
+ returnStr += "@return " + methodReturnType + '\n';
+ }
+
+ QString str;
+ if (op->getAbstract() || m_classifierInfo->isInterface) {
+ if (isHeaderMethod) {
+ // declare abstract method as 'virtual'
+ str += "virtual ";
+ }
+ }
+
+ // static declaration for header file
+ if (isHeaderMethod && op->getStatic())
+ str += "static ";
+
+ // returntype of method
+ str += methodReturnType + ' ';
+
+ if (!isHeaderMethod)
+ str += className + "::";
+
+ str += cleanName(op->getName()) + " (";
+
+ // generate parameters
+ uint j = 0;
+ for (UMLAttribute *at = atl.first(); at; at = atl.next(), j++) {
+ QString typeName = fixTypeName(at->getTypeName());
+ QString atName = cleanName(at->getName());
+ str += typeName + ' ' + atName;
+ const QString initVal = at->getInitialValue();
+ if (! initVal.isEmpty())
+ str += " = " + initVal;
+ if (j < atl.count() - 1)
+ str += ", ";
+ returnStr += "@param " + atName + ' ' + at->getDoc() + '\n';
+ }
+ str += " )";
+
+ if (op->getConst())
+ str += " const";
+
+ // method body : only gets IF its not in a header
+ if (isHeaderMethod && !policyExt()->getOperationsAreInline())
+ str += ';'; // terminate now
+ else
+ str +=getIndent() + " {\n\n" + getIndent() + '}'; // empty method body
+
+ // write it out
+ writeDocumentation("", op->getDoc(), returnStr, cpp);
+ cpp << getIndent() << str << m_endl;
+ writeBlankLine(cpp);
+ }
+}
+
+// To prevent circular including when both classifiers on either end
+// of an association have roles we need to have forward declaration of
+// the other class...but only IF its not THIS class (as could happen
+// in self-association relationship).
+void CppWriter::printAssociationIncludeDecl (UMLAssociationList list, Uml::IDType myId, QTextStream &stream)
+{
+
+ for (UMLAssociation *a = list.first(); a; a = list.next()) {
+ UMLClassifier *current = NULL;
+ bool isFirstClass = true;
+
+ // only use OTHER classes (e.g. we don't need to write includes for ourselves!!
+ // AND only IF the roleName is defined, otherwise, its not meant to be noticed.
+ if (a->getObjectId(Uml::A) == myId && !a->getRoleName(Uml::B).isEmpty()) {
+ current = dynamic_cast<UMLClassifier*>(a->getObject(Uml::B));
+ } else if (a->getObjectId(Uml::B) == myId && !a->getRoleName(Uml::A).isEmpty()) {
+ current = dynamic_cast<UMLClassifier*>(a->getObject(Uml::A));
+ isFirstClass = false;
+ }
+
+ // as header doc for this method indicates, we need to be a bit sophisticated on
+ // how to declare some associations.
+ if( current )
+ if( !isFirstClass && !a->getRoleName(Uml::A).isEmpty() && !a->getRoleName(Uml::B).isEmpty())
+ stream << "class " << current->getName() << ";" << m_endl; // special case: use forward declaration
+ else
+ stream << "#include \"" << current->getName() << ".h\"" << m_endl; // just the include statement
+ }
+}
+
+QString CppWriter::fixInitialStringDeclValue(const QString &value, const QString &type)
+{
+ QString val = value;
+ // check for strings only
+ if (!val.isEmpty() && type == policyExt()->getStringClassName()) {
+ if (!val.startsWith("\""))
+ val.prepend("\"");
+ if (!val.endsWith("\""))
+ val.append("\"");
+ }
+ return val;
+}
+
+// methods like this _shouldn't_ be needed IF we properly did things thruought the code.
+QString CppWriter::getUMLObjectName(UMLObject *obj)
+{
+ return(obj!=0)?obj->getName():QString("NULL");
+}
+
+void CppWriter::writeBlankLine(QTextStream &stream)
+{
+ stream << m_endl;
+}
+
+void CppWriter::printTextAsSeparateLinesWithIndent (const QString &text, const QString &indent, QTextStream &stream)
+{
+ if(text.isEmpty())
+ return;
+
+ QStringList lines = QStringList::split( "\n", text);
+ for(uint i= 0; i < lines.count(); i++)
+ stream << indent << lines[i] << m_endl;
+}
+
+QString CppWriter::getAttributeVariableName (UMLAttribute *at)
+{
+ QString fieldName = "m_" + cleanName(at->getName());
+ return fieldName;
+}
+
+QStringList CppWriter::defaultDatatypes() {
+ return Codegen_Utils::cppDatatypes();
+}
+
+const QStringList CppWriter::reservedKeywords() const {
+ return Codegen_Utils::reservedCppKeywords();
+}
+
diff --git a/umbrello/umbrello/codegenerators/cppwriter.h b/umbrello/umbrello/codegenerators/cppwriter.h
new file mode 100644
index 00000000..8ae58226
--- /dev/null
+++ b/umbrello/umbrello/codegenerators/cppwriter.h
@@ -0,0 +1,293 @@
+/***************************************************************************
+ cppwriter.h - description
+ This is the "old" code generator that does not support code editing
+ in the Modeller but uses significantly less file space because the
+ source code is not replicated in the XMI file.
+ -------------------
+ copyright : (C) 2003 Brian Thomas
+ (C) 2004 Umbrello UML Modeller Authors <uml-devel@uml.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 CPPWRITER_H
+#define CPPWRITER_H
+
+#include "simplecodegenerator.h"
+#include "cppcodegenerationpolicy.h"
+#include "../umloperationlist.h"
+#include "../umlattributelist.h"
+#include "../umlassociationlist.h"
+
+class QFile;
+class ClassifierInfo;
+
+/**
+ * class CppWriter is a code generator for UMLClassifier objects.
+ * Create an instance of this class, and feed it a UMLClassifier when
+ * calling writeClass and it will generate both a header (.h) and
+ * source (.cpp) file for that classifier.
+ */
+class CppWriter : public SimpleCodeGenerator {
+public:
+
+ /**
+ * Constructor, initialises a couple of variables
+ */
+ CppWriter();
+
+ /**
+ * Destructor, empty
+ */
+ virtual ~CppWriter();
+
+ /**
+ * call this method to generate cpp code for a UMLClassifier
+ * @param c the class to generate code for
+ */
+ virtual void writeClass(UMLClassifier *c);
+
+ /**
+ * returns "C++"
+ */
+ virtual Uml::Programming_Language getLanguage();
+
+ /**
+ * Add C++ primitives as datatypes
+ */
+ QStringList defaultDatatypes();
+
+ /**
+ * get list of reserved keywords
+ */
+ virtual const QStringList reservedKeywords() const;
+
+private:
+
+ /**
+ * Writes class's documentation to the class header
+ * public abstract class Foo extents {
+ */
+ void writeClassDecl(UMLClassifier *c, QTextStream &cpp);
+
+ /**
+ * Writes the comment and class constructor declaration or methods
+ */
+ void writeConstructorDecls(QTextStream &h);
+ void writeConstructorMethods(QTextStream &cpp);
+
+ /**
+ * write all field declarations, for both attributes and associations for the
+ * given permitted scope.
+ */
+ void writeFieldDecl(UMLClassifier *c, Uml::Visibility permitScope, QTextStream &stream);
+
+ /**
+ * write all method declarations, for attributes and associations
+ * for the given permitted scope.
+ */
+ void writeAccessorMethodDecl(UMLClassifier *c, Uml::Visibility permitScope, QTextStream &stream);
+
+ /**
+ * write all operations for a given class
+ * @param c the class for which we are generating code
+ * @param isHeaderMethod true when writing to a header file, false for body file
+ * @param permitScope what type of method to write (by Scope)
+ * @param j the stream associated with the output file
+ */
+ void writeOperations(UMLClassifier *c, bool isHeaderMethod, Uml::Visibility permitScope, QTextStream &j);
+
+ /**
+ * write a list of operations for a given class
+ * @param list the list of operations you want to write
+ * @param isHeaderMethod true when writing to a header file, false for body file
+ * @param j the stream associated with the output file
+ */
+ void writeOperations(UMLOperationList &list, bool isHeaderMethod, QTextStream &j);
+
+ /**
+ * write all attributes for a given class
+ * @param c the class for which we are generating code
+ * @param j the stream associated with the output file
+ */
+ void writeAttributes(UMLClassifier *c, QTextStream &j);
+
+ /**
+ * writes the Attribute declarations
+ * @param visibility the visibility of the attribs to print out
+ * @param writeStatic whether to write static or non-static attributes out
+ * @param stream text stream
+ */
+ void writeAttributeDecls (Uml::Visibility visibility, bool writeStatic, QTextStream &stream );
+
+ /**
+ * Write out fields and operations for this class selected on a particular
+ * visibility.
+ */
+ void writeHeaderFieldDecl(UMLClassifier *c, Uml::Visibility permitVisibility, QTextStream &stream);
+
+ void writeHeaderAttributeAccessorMethods (Uml::Visibility visibility, bool writeStatic, QTextStream &stream );
+
+ void writeHeaderAttributeAccessorMethodDecls(UMLClassifier *c, Uml::Visibility permitVisibility, QTextStream &stream);
+ void writeHeaderAccessorMethodDecl(UMLClassifier *c, Uml::Visibility permitScope, QTextStream &stream);
+
+
+ /**
+ * Searches a list of associations for appropriate ones to write out as attributes
+ */
+ void writeAssociationDecls(UMLAssociationList associations, Uml::Visibility permit, Uml::IDType id, QTextStream &stream);
+
+ /**
+ * Writes out an association as an attribute using Vector
+ */
+ void writeAssociationRoleDecl(QString fieldClassName, QString roleName, QString multi,
+ QString doc, QTextStream &stream);
+
+ /**
+ * calls @ref writeSingleAttributeAccessorMethods() on each of the attributes in attribs list.
+ */
+ void writeAttributeMethods(UMLAttributeList *attribs, Uml::Visibility visib, bool isHeaderMethod,
+ bool isStatic,
+ bool writeMethodBody, QTextStream &stream);
+
+ /**
+ * calls @ref writeAssociationRoleMethod() on each of the associations in the given list
+ */
+ void writeAssociationMethods(UMLAssociationList associations, Uml::Visibility permitVisib,
+ bool isHeaderMethod,
+ bool writeMethodBody, bool writePointerVar, Uml::IDType id, QTextStream &stream);
+
+ /**
+ * calls @ref writeSingleAttributeAccessorMethods() or @ref
+ * writeVectorAttributeAccessorMethods() on the association
+ * role
+ */
+ void writeAssociationRoleMethod(const QString &fieldClassName, bool isHeaderMethod, bool writeMethodBody,
+ const QString &roleName, const QString &multi,
+ const QString &description, Uml::Changeability_Type change,
+ QTextStream &stream);
+
+ /**
+ * Writes getFoo() and setFoo() accessor methods for the attribute
+ */
+ void writeSingleAttributeAccessorMethods(
+ const QString &fieldClassName, const QString &Name,
+ const QString &fieldName, const QString &description,
+ Uml::Changeability_Type change,
+ bool isHeaderMethod,
+ bool isStatic, bool writeMethodBody, QTextStream &cpp);
+
+ /**
+ * Writes addFoo() and removeFoo() accessor methods for the Vector attribute
+ */
+ void writeVectorAttributeAccessorMethods(
+ const QString &fieldClassName, const QString &fieldVarName,
+ const QString &fieldName, const QString &description,
+ Uml::Changeability_Type change,
+ bool isHeaderMethod,
+ bool writeMethodBody,
+ QTextStream &cpp);
+
+ /**
+ * Writes a // style comment
+ */
+ void writeComment(const QString &text, const QString &indent, QTextStream &cpp);
+
+ /**
+ * Writes a documentation comment
+ */
+ void writeDocumentation(QString header, QString body, QString end, QTextStream &cpp);
+
+
+ /**
+ * write the header file for this classifier.
+ */
+ void writeHeaderFile (UMLClassifier *c, QFile &file);
+
+ /**
+ * write the source code body file for this classifier.
+ */
+ void writeSourceFile (UMLClassifier *c, QFile &file);
+
+ /**
+ * utility method to break up a block of text, which has embedded newline chars,
+ * and print them to a stream as separate lines of text, indented as directed.
+ */
+ void printTextAsSeparateLinesWithIndent (const QString &text, const QString &indent,
+ QTextStream &stream);
+
+ /**
+ * Intellegently print out header include/forward decl. for associated classes.
+ */
+ void printAssociationIncludeDecl (UMLAssociationList list, Uml::IDType this_id, QTextStream &stream);
+
+ /**
+ * If needed, write out the method to initialize attributes of our class.
+ */
+ void writeInitAttibuteMethod (QTextStream &stream);
+
+ /**
+ * If needed, write out the declaration for the method to initialize attributes of our class.
+ */
+ void writeInitAttibuteDecl (QTextStream &stream);
+
+ /**
+ * Returns the name of the given object (if it exists)
+ */
+ QString getUMLObjectName(UMLObject *obj);
+
+ /**
+ * Replaces `string' with STRING_TYPENAME.
+ */
+ QString fixTypeName(const QString &string);
+
+ /**
+ * check that initial values of strings have quotes around them
+ */
+ QString fixInitialStringDeclValue(const QString &value, const QString &type);
+
+ /**
+ * Determine what the variable name of this attribute should be.
+ */
+ QString getAttributeVariableName (UMLAttribute *at);
+
+ /**
+ * Write a blank line
+ */
+ void writeBlankLine(QTextStream &stream);
+
+ /**
+ * Return the policy object
+ */
+ CPPCodeGenerationPolicy *policyExt();
+
+ /**
+ * Summary information about current classifier.
+ */
+ ClassifierInfo * m_classifierInfo;
+
+ QString VECTOR_METHOD_APPEND;
+ QString VECTOR_METHOD_REMOVE;
+ QString VECTOR_METHOD_INIT;
+ QString OBJECT_METHOD_INIT;
+
+ /**
+ * Create association methods for class attributes/associations/operations as inline decl in header.
+ */
+ bool INLINE_ASSOCIATION_METHODS;
+
+ QStringList ObjectFieldVariables;
+ QStringList VectorFieldVariables;
+
+};
+
+
+
+#endif // CPPWRITER_H
diff --git a/umbrello/umbrello/codegenerators/csharpwriter.cpp b/umbrello/umbrello/codegenerators/csharpwriter.cpp
new file mode 100644
index 00000000..73975b48
--- /dev/null
+++ b/umbrello/umbrello/codegenerators/csharpwriter.cpp
@@ -0,0 +1,725 @@
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * copyright (C) 2007 *
+ * Umbrello UML Modeller Authors <uml-devel@uml.sf.net> *
+ ***************************************************************************/
+
+//
+// C++ Implementation: csharpwriter
+//
+#include "csharpwriter.h"
+
+#include <kdebug.h>
+#include <qregexp.h>
+#include <qtextstream.h>
+
+#include "../uml.h"
+#include "../umldoc.h"
+#include "../folder.h"
+#include "../classifier.h"
+#include "../association.h"
+#include "../attribute.h"
+#include "../operation.h"
+#include "../umlnamespace.h"
+
+static const char *reserved_words[] = {
+ "abstract",
+ "as",
+ "base",
+ "bool",
+ "break",
+ "byte",
+ "case",
+ "catch",
+ "char",
+ "checked",
+ "class",
+ "const",
+ "continue",
+ "decimal",
+ "default",
+ "delegate",
+ "do",
+ "double",
+ "else",
+ "enum",
+ "event",
+ "explicit",
+ "extern",
+ "false",
+ "finally",
+ "for",
+ "foreach",
+ "goto",
+ "if",
+ "implicit",
+ "in",
+ "int",
+ "interface",
+ "internal",
+ "is",
+ "lock",
+ "long",
+ "namespace",
+ "new",
+ "null",
+ "object",
+ "operator",
+ "out",
+ "override",
+ "params",
+ "private",
+ "protected",
+ "public",
+ "readonly",
+ "ref",
+ "return",
+ "sbyte",
+ "sealed",
+ "short",
+ "sizeof",
+ "stackalloc",
+ "static",
+ "string",
+ "struct",
+ "switch",
+ "this",
+ "throw",
+ "true",
+ "try",
+ "typeof",
+ "uint",
+ "ulong",
+ "unchecked",
+ "unsafe",
+ "ushort",
+ "using",
+ "virtual",
+ "void",
+ "volatile",
+ "while",
+ 0
+};
+
+CSharpWriter::CSharpWriter()
+ : SimpleCodeGenerator()
+{
+}
+
+
+CSharpWriter::~CSharpWriter()
+{
+}
+
+QStringList CSharpWriter::defaultDatatypes() {
+ QStringList l;
+ l.append("bool");
+ l.append("byte");
+ l.append("char");
+ l.append("decimal");
+ l.append("double");
+ l.append("fixed");
+ l.append("float");
+ l.append("fixed");
+ l.append("float");
+ l.append("int");
+ l.append("long");
+ l.append("object");
+ l.append("sbyte");
+ l.append("short");
+ l.append("string");
+ l.append("uint");
+ l.append("ulong");
+ l.append("ushort");
+ return l;
+}
+
+void CSharpWriter::writeClass(UMLClassifier *c) {
+ if (!c) {
+ kDebug()<<"Cannot write class of NULL concept!" << endl;
+ return;
+ }
+
+ QString classname = cleanName(c->getName());
+ //find an appropriate name for our file
+ QString fileName = findFileName(c, ".cs");
+ if (fileName.isEmpty()) {
+ emit codeGenerated(c, false);
+ return;
+ }
+
+ QFile filecs;
+ if (!openFile(filecs, fileName)) {
+ emit codeGenerated(c, false);
+ return;
+ }
+ QTextStream cs(&filecs);
+
+ //////////////////////////////
+ //Start generating the code!!
+ /////////////////////////////
+
+
+ //try to find a heading file (license, coments, etc)
+ QString str;
+ str = getHeadingFile(".cs");
+ if (!str.isEmpty()) {
+ str.replace(QRegExp("%filename%"),fileName);
+ str.replace(QRegExp("%filepath%"),filecs.name());
+ cs<<str<<m_endl;
+ }
+
+ UMLDoc *umldoc = UMLApp::app()->getDocument();
+ UMLFolder *logicalView = umldoc->getRootFolder(Uml::mt_Logical);
+
+ // write generic includes
+ cs << "using System;" << m_endl;
+ cs << "using System.Text;" << m_endl;
+ cs << "using System.Collections;" << m_endl;
+ cs << "using System.Collections.Generic;" << m_endl << m_endl;
+
+ //write includes and namespace
+
+ UMLPackage *container = c->getUMLPackage();
+ if (container == logicalView)
+ container = NULL;
+
+ UMLPackageList includes;
+ findObjectsRelated(c, includes);
+ m_seenIncludes.clear();
+ //m_seenIncludes.append(logicalView);
+ if (includes.count()) {
+ UMLPackage *p;
+ for (UMLPackageListIt it(includes); (p = it.current()) != NULL; ++it) {
+ UMLClassifier *cl = dynamic_cast<UMLClassifier*>(p);
+ if (cl)
+ p = cl->getUMLPackage();
+ if (p != logicalView && m_seenIncludes.findRef(p) == -1 && p != container) {
+ cs << "using " << p->getFullyQualifiedName(".") << ";" << m_endl;
+ m_seenIncludes.append(p);
+ }
+ }
+ cs << m_endl;
+ }
+
+ m_container_indent = "";
+
+ if (container) {
+ cs << "namespace " << container->getFullyQualifiedName(".") << m_endl;
+ cs << "{" << m_endl << m_endl;
+ m_container_indent = m_indentation;
+ m_seenIncludes.append(container);
+ }
+
+ //Write class Documentation if there is somthing or if force option
+ if (forceDoc() || !c->getDoc().isEmpty()) {
+ cs << m_container_indent << "/// <summary>" << m_endl;
+ cs << formatDoc(c->getDoc(), m_container_indent + "/// " );
+ cs << m_container_indent << "/// </summary>" << m_endl ;
+ }
+
+ UMLClassifierList superclasses = c->getSuperClasses();
+ UMLAssociationList aggregations = c->getAggregations();
+ UMLAssociationList compositions = c->getCompositions();
+ UMLAssociationList realizations = c->getRealizations();
+ bool isInterface = c->isInterface();
+ m_unnamedRoles = 1;
+
+ cs << m_container_indent << "public ";
+
+ //check if it is an interface or regular class
+ if (isInterface) {
+ cs << "interface " << classname;
+ } else {
+ //check if class is abstract and / or has abstract methods
+ if (c->getAbstract() || c->hasAbstractOps())
+ cs << "abstract ";
+
+ cs << "class " << classname << (superclasses.count() > 0 ? " : ":"");
+
+ // write baseclass, ignore interfaces, write error on multiple inheritance
+ if (superclasses.count() > 0) {
+ UMLClassifier *obj;
+ int supers = 0;
+ for (obj = superclasses.first(); obj; obj = superclasses.next()) {
+ if (!obj->isInterface()) {
+ if (supers > 0) {
+ cs << " // AND ";
+ }
+ cs << cleanName(obj->getName());
+ supers++;
+ }
+ }
+ if (supers > 1) {
+ cs << m_endl << "//WARNING: C# does not support multiple inheritance but there is more than 1 superclass defined in your UML model!" << m_endl;
+ }
+ }
+ //check for realizations
+ UMLAssociationList realizations = c->getRealizations();
+ UMLAssociation *a;
+
+ if (!realizations.isEmpty()) {
+ for (a = realizations.first(); a; a = realizations.next()) {
+ UMLClassifier *real = (UMLClassifier*)a->getObject(Uml::B);
+ if(real != c) {
+ // write list of realizations
+ cs << ", " << real->getName();
+ }
+
+ }
+ }
+ }
+ cs << m_endl << m_container_indent << '{' << m_endl;
+
+ //associations
+ if (forceSections() || !aggregations.isEmpty()) {
+ cs << m_endl << m_container_indent << m_indentation << "#region Aggregations" << m_endl << m_endl;
+ writeAssociatedAttributes(aggregations, c, cs);
+ cs << m_endl << m_container_indent << m_indentation << "#endregion" << m_endl;
+ }
+
+ //compositions
+ if (forceSections() || !compositions.isEmpty()) {
+ cs << m_endl << m_container_indent << m_indentation << "#region Compositions" << m_endl << m_endl;
+ writeAssociatedAttributes(compositions, c, cs);
+ cs << m_endl << m_container_indent << m_indentation << "#endregion" << m_endl;
+ }
+
+ //attributes
+ // FIXME: C# allows Properties in interface!
+ if (!isInterface)
+ writeAttributes(c, cs);
+
+ //operations
+ writeOperations(c, cs);
+
+ //finish file
+ cs << m_endl << m_container_indent << "}" << m_endl << m_endl; // close class
+
+ if (container) {
+ cs << "} // end of namespace "
+ << container->getFullyQualifiedName(".") << m_endl << m_endl;
+ }
+
+ //close files and notfiy we are done
+ filecs.close();
+ emit codeGenerated(c, true);
+}
+
+////////////////////////////////////////////////////////////////////////////////////
+// Helper Methods
+
+void CSharpWriter::writeOperations(UMLClassifier *c, QTextStream &cs) {
+
+ //Lists to store operations sorted by scope
+ UMLOperationList oppub,opprot,oppriv;
+
+ bool isInterface = c->isInterface();
+ bool generateErrorStub = true;
+
+ oppub.setAutoDelete(false);
+ opprot.setAutoDelete(false);
+ oppriv.setAutoDelete(false);
+
+ //sort operations by scope first and see if there are abstract methods
+ UMLOperationList opl(c->getOpList());
+ for (UMLOperation *op = opl.first(); op ; op = opl.next()) {
+ switch (op->getVisibility()) {
+ case Uml::Visibility::Public:
+ oppub.append(op);
+ break;
+ case Uml::Visibility::Protected:
+ opprot.append(op);
+ break;
+ case Uml::Visibility::Private:
+ oppriv.append(op);
+ break;
+ default:
+ break;
+ }
+ }
+
+ // write realizations (recursive)
+ UMLAssociationList realizations = c->getRealizations();
+
+ if (!isInterface && !realizations.isEmpty()) {
+ writeRealizationsRecursive(c, &realizations, cs);
+ }
+
+ // write public operations
+ if (forceSections() || !oppub.isEmpty()) {
+ cs << m_endl << m_container_indent << m_indentation << "#region Public methods" << m_endl << m_endl;
+ writeOperations(oppub,cs,isInterface,false,generateErrorStub);
+ cs << m_container_indent << m_indentation << "#endregion" << m_endl << m_endl;
+ }
+
+ // write protected operations
+ if (forceSections() || !opprot.isEmpty()) {
+ cs << m_endl << m_container_indent << m_indentation << "#region Protected methods" << m_endl << m_endl;
+ writeOperations(opprot,cs,isInterface,false,generateErrorStub);
+ cs << m_container_indent << m_indentation << "#endregion" << m_endl << m_endl;
+ }
+
+ // write private operations
+ if (forceSections() || !oppriv.isEmpty()) {
+ cs << m_endl << m_container_indent << m_indentation << "#region Private methods" << m_endl << m_endl;
+ writeOperations(oppriv,cs,isInterface,false,generateErrorStub);
+ cs << m_container_indent << m_indentation << "#endregion" << m_endl << m_endl;
+ }
+
+ // write superclasses abstract methods
+ UMLClassifierList superclasses = c->getSuperClasses();
+
+ if (!isInterface && !c->getAbstract() && !c->hasAbstractOps()
+ && superclasses.count() > 0) {
+ writeOverridesRecursive(&superclasses, cs);
+ }
+
+}
+
+void CSharpWriter::writeOverridesRecursive(UMLClassifierList *superclasses, QTextStream &cs) {
+ // oplist for implemented abstract operations
+ UMLOperationList opabstract;
+ opabstract.setAutoDelete(false);
+ UMLClassifier *obj;
+
+ for (obj = superclasses->first(); obj; obj = superclasses->next()) {
+ if (!obj->isInterface() && obj->hasAbstractOps()) {
+ // collect abstract ops
+ UMLOperationList opl(obj->getOpList());
+ for (UMLOperation *op = opl.first(); op ; op = opl.next()) {
+ if (op->getAbstract()) {
+ opabstract.append(op);
+ }
+ }
+
+ // write abstract implementations
+ cs << m_endl << m_container_indent << m_indentation << "#region " << obj->getName() << " members" << m_endl << m_endl;
+ writeOperations(opabstract,cs,false,true,true);
+ cs << m_container_indent << m_indentation << "#endregion" << m_endl << m_endl;
+
+ opabstract.clear();
+ }
+ // Recurse to parent superclasses
+ UMLClassifierList superRecursive = obj->getSuperClasses();
+ UMLClassifierList *superRecursivePtr =& superRecursive;
+ if (superRecursivePtr->count() > 0) {
+ writeOverridesRecursive(superRecursivePtr, cs);
+ }
+ }
+}
+void CSharpWriter::writeRealizationsRecursive(UMLClassifier *currentClass, UMLAssociationList *realizations, QTextStream &cs) {
+
+ UMLAssociation *a;
+ for (a = realizations->first(); a; a = realizations->next()) {
+
+ // we know its a classifier if its in the list
+ UMLClassifier *real = (UMLClassifier*)a->getObject(Uml::B);
+
+ //FIXME: Interfaces realize themselves without this condition!?
+ if (real == currentClass)
+ continue;
+
+ // collect operations of one realization
+ UMLOperationList opreal = real->getOpList();
+
+ // write realizations
+ cs << m_endl << m_container_indent << m_indentation << "#region " << real->getName() << " members" << m_endl << m_endl;
+ writeOperations(opreal,cs,false,false,true);
+ cs << m_container_indent << m_indentation << "#endregion" << m_endl << m_endl;
+
+ // Recurse to parent realizations
+ UMLAssociationList parentReal = real->getRealizations();
+ if (!parentReal.isEmpty()) {
+ writeRealizationsRecursive(real, &parentReal, cs);
+ }
+ }
+}
+
+void CSharpWriter::writeOperations(UMLOperationList opList,
+ QTextStream &cs, bool isInterface /* = false */,
+ bool isOverride /* = false */,
+ bool generateErrorStub /* = false */) {
+
+ for (UMLOperation *op=opList.first(); op ; op=opList.next()) {
+ UMLAttributeList atl = op->getParmList();
+ UMLAttribute *at;
+
+ //write method doc if we have doc || if at least one of the params has doc
+ bool writeDoc = forceDoc() || !op->getDoc().isEmpty();
+
+ for (at = atl.first(); at; at = atl.next()) {
+ writeDoc |= !at->getDoc().isEmpty();
+ }
+
+ //write method documentation
+ if (writeDoc && !isOverride)
+ {
+ cs << m_container_indent << m_indentation << "/// <summary>" << m_endl;
+ cs << formatDoc(op->getDoc(), m_container_indent + m_indentation + "/// ");
+ cs << m_container_indent << m_indentation << "/// </summary>" << m_endl;
+
+ //write parameter documentation
+ for (at = atl.first(); at; at = atl.next())
+ {
+ if (forceDoc() || !at->getDoc().isEmpty()) {
+ cs << m_container_indent << m_indentation << "/// <param name=\"" << cleanName(at->getName()) << "\">";
+ //removing newlines from parameter doc
+ cs << formatDoc(at->getDoc(), "").replace("\n", " ").remove('\r').replace(QRegExp(" $"), "");
+ cs << "</param>" << m_endl;
+ }
+ }
+
+ // FIXME: "returns" should contain documentation, not type.
+ cs << m_container_indent << m_indentation << "/// <returns>";
+ if (! op->getTypeName().isEmpty()) {
+ cs << makeLocalTypeName(op);
+ }
+ cs << "</returns>" << m_endl;
+
+ }
+
+ // method visibility
+ cs << m_container_indent << m_indentation;
+ if (!isInterface) {
+ if (!isOverride) {
+ if (op->getAbstract()) cs << "abstract ";
+ cs << op->getVisibility().toString() << " ";
+ if (op->getStatic()) cs << "static ";
+ }
+ else {
+ // method overriding an abstract parent
+ cs << op->getVisibility().toString() << " override ";
+ if (op->getStatic()) cs << "static ";
+ }
+ }
+
+ // return type (unless constructor, destructor)
+ if (!op->isLifeOperation()) {
+ if (op->getTypeName().isEmpty()) {
+ cs << "void ";
+ }
+ else {
+ cs << makeLocalTypeName(op) << " ";
+ }
+ }
+
+ // method name
+ cs << cleanName(op->getName()) << "(";
+
+ // method parameters
+ int i= atl.count();
+ int j=0;
+ for (at = atl.first(); at; at = atl.next(), j++) {
+
+ cs << makeLocalTypeName(at) << " " << cleanName(at->getName());
+
+ // no initial values in C#
+ //<< (!(at->getInitialValue().isEmpty()) ?
+ // (QString(" = ")+at->getInitialValue()) :
+ // QString(""))
+ cs << ((j < i-1)?", ":"");
+ }
+ cs << ")";
+
+ //FIXME: how to control generation of error stub?
+ if (!isInterface && (!op->getAbstract() || isOverride)) {
+ cs << m_endl << m_container_indent << m_indentation << "{" << m_endl;
+ if (generateErrorStub) {
+ cs << m_container_indent << m_indentation << m_indentation;
+ cs << "throw new Exception(\"The method or operation is not implemented.\");" << m_endl;
+ }
+ cs << m_container_indent << m_indentation << "}" << m_endl;
+ }
+ else {
+ cs << ';' << m_endl;
+ }
+ cs << m_endl;
+ }
+}
+
+void CSharpWriter::writeAttributes(UMLClassifier *c, QTextStream &cs) {
+
+ UMLAttributeList atpub, atprot, atpriv, atdefval;
+ atpub.setAutoDelete(false);
+ atprot.setAutoDelete(false);
+ atpriv.setAutoDelete(false);
+ atdefval.setAutoDelete(false);
+
+ //sort attributes by scope and see if they have a default value
+ UMLAttributeList atl = c->getAttributeList();
+ UMLAttribute *at;
+
+ for (at = atl.first(); at ; at = atl.next()) {
+ if (!at->getInitialValue().isEmpty())
+ atdefval.append(at);
+ switch (at->getVisibility()) {
+ case Uml::Visibility::Public:
+ atpub.append(at);
+ break;
+ case Uml::Visibility::Protected:
+ atprot.append(at);
+ break;
+ case Uml::Visibility::Private:
+ atpriv.append(at);
+ break;
+ default:
+ break;
+ }
+ }
+
+ if (forceSections() || atl.count())
+ cs << m_endl << m_container_indent << m_indentation << "#region Attributes" << m_endl << m_endl;
+
+ // write public attributes
+ if (forceSections() || atpub.count()) {
+ writeAttributes(atpub,cs);
+ }
+
+ // write protected attributes
+ if (forceSections() || atprot.count()) {
+ writeAttributes(atprot,cs);
+ }
+
+ // write private attributes
+ if (forceSections() || atpriv.count()) {
+ writeAttributes(atpriv,cs);
+ }
+
+ if (forceSections() || atl.count())
+ cs << m_endl << m_container_indent << m_indentation << "#endregion" << m_endl << m_endl;
+
+}
+
+
+void CSharpWriter::writeAttributes(UMLAttributeList &atList, QTextStream &cs) {
+
+ for (UMLAttribute *at = atList.first(); at ; at = atList.next()) {
+
+ bool asProperty = true;
+ if (at->getVisibility() == Uml::Visibility::Private) {
+ asProperty = false;
+ }
+ writeAttribute(at->getDoc(), at->getVisibility(), at->getStatic(),
+ makeLocalTypeName(at), at->getName(), at->getInitialValue(), asProperty, cs);
+
+ cs << m_endl;
+ } // end for
+ return;
+}
+
+void CSharpWriter::writeAssociatedAttributes(UMLAssociationList &associated, UMLClassifier *c, QTextStream &cs) {
+
+ UMLAssociation *a;
+ for (a = associated.first(); a ; a = associated.next()) {
+ if (c != a->getObject(Uml::A)) // we need to be at the A side
+ continue;
+
+ UMLObject *o = a->getObject(Uml::B);
+ if (o == NULL) {
+ kError() << "composition role B object is NULL" << endl;
+ continue;
+ }
+ // Take name and documentaton from Role, take type name from the referenced object
+ QString roleName = cleanName(a->getRoleName(Uml::B));
+ QString typeName = cleanName(o->getName());
+ if (roleName.isEmpty()) {
+ roleName = QString("UnnamedRoleB_%1").arg(m_unnamedRoles++);
+ }
+ QString roleDoc = a->getRoleDoc(Uml::B);
+
+ //FIXME:is this simple condition enough?
+ if (a->getMulti(Uml::B).isEmpty() || a->getMulti(Uml::B) == "1") {
+ // normal attribute
+ writeAttribute(roleDoc, a->getVisibility(Uml::B), false, typeName, roleName, "", ( a->getVisibility(Uml::B) != Uml::Visibility::Private), cs);
+ } else {
+ // array
+ roleDoc += "\n(Array of " + typeName + ')';
+ writeAttribute(roleDoc, a->getVisibility(Uml::B), false, "ArrayList", roleName, "", ( a->getVisibility(Uml::B) != Uml::Visibility::Private), cs);
+ }
+ }
+}
+
+void CSharpWriter::writeAttribute(QString doc, Uml::Visibility visibility, bool isStatic, QString typeName, QString name, QString initialValue, bool asProperty, QTextStream &cs) {
+
+ if (forceDoc() || !doc.isEmpty()) {
+
+ cs << m_container_indent << m_indentation << "/// <summary>" << m_endl;
+ cs << formatDoc(doc, m_container_indent + m_indentation + "/// ");
+ cs << m_container_indent << m_indentation << "/// </summary>" << m_endl;
+
+ }
+ cs << m_container_indent << m_indentation;
+ cs << visibility.toString() << " ";
+ if (isStatic) cs << "static ";
+
+ //Variable type with/without namespace path
+ cs << typeName << " ";
+
+ cs << cleanName(name);
+
+ // FIXME: may need a GUI switch to not generate as Property?
+
+ // Generate as Property if not private
+ if (asProperty)
+ {
+ cs << m_endl;
+ cs << m_container_indent << m_indentation << "{" << m_endl;
+ cs << m_container_indent << m_indentation << m_indentation << "get" << m_endl;
+ cs << m_container_indent << m_indentation << m_indentation << "{" << m_endl;
+ cs << m_container_indent << m_indentation << m_indentation << m_indentation << "return m_" << cleanName(name) << ";" << m_endl;
+ cs << m_container_indent << m_indentation << m_indentation << "}" << m_endl;
+
+ cs << m_container_indent << m_indentation << m_indentation << "set" << m_endl;
+ cs << m_container_indent << m_indentation << m_indentation << "{" << m_endl;
+ cs << m_container_indent << m_indentation << m_indentation << m_indentation << "m_" << cleanName(name) << " = value;" << m_endl;
+ cs << m_container_indent << m_indentation << m_indentation << "}" << m_endl;
+ cs << m_container_indent << m_indentation << "}" << m_endl;
+ cs << m_container_indent << m_indentation << "private ";
+ if (isStatic) cs << "static ";
+ cs << typeName << " m_" << cleanName(name);
+ }
+
+ if (!initialValue.isEmpty())
+ cs << " = " << initialValue;
+
+ cs << ";" << m_endl << m_endl;
+}
+
+QString CSharpWriter::makeLocalTypeName(UMLClassifierListItem *cl) {
+ UMLPackage *p = cl->getType()->getUMLPackage();
+ if (m_seenIncludes.findRef(p) != -1) {
+ return cl->getType()->getName();
+ }
+ else {
+ return cl->getTypeName();
+ }
+
+}
+
+/**
+ * returns "C#"
+ */
+Uml::Programming_Language CSharpWriter::getLanguage() {
+ return Uml::pl_CSharp;
+}
+
+const QStringList CSharpWriter::reservedKeywords() const {
+
+ static QStringList keywords;
+
+ if (keywords.isEmpty()) {
+ for (int i = 0; reserved_words[i]; i++)
+ keywords.append(reserved_words[i]);
+ }
+
+ return keywords;
+}
+
+#include "csharpwriter.moc"
+
diff --git a/umbrello/umbrello/codegenerators/csharpwriter.h b/umbrello/umbrello/codegenerators/csharpwriter.h
new file mode 100644
index 00000000..a6d20f2d
--- /dev/null
+++ b/umbrello/umbrello/codegenerators/csharpwriter.h
@@ -0,0 +1,163 @@
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * copyright (C) 2007 *
+ * Umbrello UML Modeller Authors <uml-devel@uml.sf.net> *
+ ***************************************************************************/
+
+//
+// C++ Interface: csharpwriter
+//
+// @author Ferenc Veres
+//
+#ifndef CSHARPWRITER_H
+#define CSHARPWRITER_H
+
+#include "simplecodegenerator.h"
+#include "../umlattributelist.h"
+#include "../umloperationlist.h"
+#include "../classifierlistitem.h"
+#include "../umlassociationlist.h"
+
+
+/**
+ * class CSharpWriter is a C# code generator for UMLClassifier objects
+ * Just call writeClass and feed it a UMLClassifier;
+ */
+class CSharpWriter : public SimpleCodeGenerator
+{
+ Q_OBJECT
+public:
+ CSharpWriter();
+
+ virtual ~CSharpWriter();
+ /**
+ * call this method to generate Php code for a UMLClassifier
+ * @param c the class you want to generate code for.
+ */
+ virtual void writeClass(UMLClassifier *c);
+
+ /**
+ * returns "C#"
+ */
+ virtual Uml::Programming_Language getLanguage();
+
+ /**
+ * get list of reserved keywords
+ */
+ virtual const QStringList reservedKeywords() const;
+
+ /**
+ * get list of predefined data types
+ */
+ QStringList defaultDatatypes();
+
+private:
+
+ /**
+ * we do not want to write the comment "Private methods" twice
+ */
+ bool bPrivateSectionCommentIsWritten;
+
+ /**
+ * Adds extra indenting if the class is in a container (namespace)
+ */
+ QString m_container_indent;
+
+ /**
+ * Collection of included namespaces, to skip them from variable types.
+ */
+ UMLPackageList m_seenIncludes;
+
+ /**
+ * Counts associations without a role name for giving a default name.
+ */
+ int m_unnamedRoles;
+
+ /**
+ * write realizations of a class and recurse to parent classes
+
+ * @param currentClass class to start with
+ * @param realizations realizations of this class
+ * @param cs output stream
+ */
+ void writeRealizationsRecursive(UMLClassifier *currentClass,
+ UMLAssociationList *realizations,
+ QTextStream &cs);
+
+ /**
+ * write all operations for a given class
+ *
+ * @param c the concept we are generating code for
+ * @param cs output stream
+ */
+ void writeOperations(UMLClassifier *c, QTextStream &cs);
+
+ /**
+ * write a list of class operations
+ *
+ * @param opList the list of operations
+ * @param cs output stream
+ * @param interface indicates if the operation is an interface member
+ * @param isOverride implementation of an inherited abstract function
+ */
+ void writeOperations(UMLOperationList opList,
+ QTextStream &cs,
+ bool interface = false,
+ bool isOverride = false,
+ bool generateErrorStub = false);
+
+ /**
+ * write superclasses' abstract methods
+ *
+ * @param superclasses List of superclasses to start recursing on
+ * @param cs output stream
+ */
+ void writeOverridesRecursive(UMLClassifierList *superclasses, QTextStream &cs);
+
+ /** write all the attributes of a class
+ * @param c the class we are generating code for
+ * @param cs output stream
+ */
+ void writeAttributes(UMLClassifier *c, QTextStream &cs);
+
+ /** write a list of class attributes
+ * @param atList the list of attributes
+ * @param cs output stream
+ */
+ void writeAttributes(UMLAttributeList &atList, QTextStream &cs);
+
+ /**
+ * write attributes from associated objects (compositions, aggregations)
+ * @param associated list of associated objects
+ * @param c currently written class, to see association direction
+ * @param cs output stream
+ */
+ void writeAssociatedAttributes(UMLAssociationList &associated, UMLClassifier *c, QTextStream &cs);
+
+ /**
+ * write a single attribute to the output stream
+ * @param doc attribute documentation
+ * @param visibility attribute visibility
+ * @param isStatic static attribute
+ * @param typeName class/type of the attribute
+ * @param name name of the attribute
+ * @param initialValue initial value given to the attribute at declaration
+ * @param asProperty true writes as property (get/set), false writes single line variable
+ * @param cs output stream
+ */
+ void writeAttribute(QString doc, Uml::Visibility visibility, bool isStatic, QString typeName, QString name, QString initialValue, bool asProperty, QTextStream &cs);
+
+ /** find the type in used namespaces, if namespace found return short name, complete otherwise.
+ *
+ * @param at Operation or Attribute to check type
+ */
+ QString makeLocalTypeName(UMLClassifierListItem *cl);
+
+};
+
+#endif
diff --git a/umbrello/umbrello/codegenerators/dwriter.cpp b/umbrello/umbrello/codegenerators/dwriter.cpp
new file mode 100644
index 00000000..3e16b136
--- /dev/null
+++ b/umbrello/umbrello/codegenerators/dwriter.cpp
@@ -0,0 +1,970 @@
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * copyright (C) 2007 Jari-Matti Mäkelä <jmjm@iki.fi> *
+ * Umbrello UML Modeller Authors <uml-devel@uml.sf.net> *
+ ***************************************************************************/
+
+/***************************************************************************
+ This is the "old" code generator that does not support code editing
+ in the Modeller but uses significantly less file space because the
+ source code is not replicated in the XMI file.
+ ***************************************************************************/
+
+// own header
+#include "dwriter.h"
+// qt includes
+#include <qfile.h>
+#include <qtextstream.h>
+#include <qregexp.h>
+// kde includes
+#include <kdebug.h>
+// app includes
+#include "../umldoc.h"
+#include "../classifier.h"
+#include "../operation.h"
+#include "../attribute.h"
+#include "../association.h"
+#include "../template.h"
+#include "../umltemplatelist.h"
+#include "codegen_utils.h"
+
+DWriter::DWriter() {
+ startline = m_endl + m_indentation;
+}
+
+DWriter::~DWriter() {}
+
+Uml::Programming_Language DWriter::getLanguage() {
+ return Uml::pl_D;
+}
+
+// FIXME: doesn't work yet
+void DWriter::writeModuleDecl(UMLClassifier *c, QTextStream &d) {
+ if(!c->getPackage().isEmpty())
+ d << "module " << c->getPackage() << ";" << m_endl;
+
+ writeBlankLine(d);
+}
+
+void DWriter::writeModuleImports(UMLClassifier *c, QTextStream &d) {
+ // another preparation, determine what we have
+ UMLAssociationList associations = c->getSpecificAssocs(Uml::at_Association); // BAD! only way to get "general" associations.
+ UMLAssociationList uniAssociations = c->getUniAssociationToBeImplemented();
+
+ UMLAssociationList aggregations = c->getAggregations();
+ UMLAssociationList compositions = c->getCompositions();
+
+ bool hasAssociations = aggregations.count() + associations.count() +
+ compositions.count() + uniAssociations.count() > 0;
+
+ if (hasAssociations) {
+ // import tango, if that mode is set
+ writeBlankLine(d);
+ }
+
+ //only import classes in a different package as this class
+ UMLPackageList imports;
+ findObjectsRelated(c, imports);
+ for (UMLPackage *con = imports.first(); con; con = imports.next()) {
+ if (con->getBaseType() == Uml::ot_Datatype)
+ continue;
+ QString pkg = con->getPackage();
+ if (!pkg.isEmpty() && pkg != c->getPackage())
+ d << "import " << pkg << "." << cleanName(con->getName()) << ";"
+ << m_endl;
+ }
+
+ writeBlankLine(d);
+}
+
+void DWriter::writeClass(UMLClassifier *c) {
+ if (!c) {
+ kDebug()<<"Cannot write class of NULL concept!\n";
+ return;
+ }
+
+ isInterface = c->isInterface();
+
+ QString fileName = cleanName(c->getName().lower());
+
+ //find an appropriate name for our file
+ fileName = findFileName(c, ".d");
+ if (fileName.isEmpty()) {
+ emit codeGenerated(c, false);
+ return;
+ }
+
+ // check that we may open that file for writing
+ QFile file;
+ if ( !openFile(file, fileName) ) {
+ emit codeGenerated(c, false);
+ return;
+ }
+
+ // open text stream to file
+ QTextStream d(&file);
+
+ //try to find a heading file (license, coments, etc)
+ QString str;
+ str = getHeadingFile(".d");
+ if(!str.isEmpty()) {
+ str.replace(QRegExp("%filename%"),fileName);
+ str.replace(QRegExp("%filepath%"),file.name());
+ d<<str<<m_endl;
+ }
+
+ // source file begins with the module declaration
+ writeModuleDecl(c, d);
+
+ // imports
+ writeModuleImports(c, d);
+
+ // write the opening declaration for the class incl any documentation,
+ // interfaces and/or inheritence issues we have
+ writeClassDecl(c, d);
+
+ // start body of class
+ d << " {" << m_endl;
+
+
+ // Preparations
+ //
+
+ // sort attributes by Scope
+ UMLAttributeList atl;
+ UMLAttributeList atpub, atprot, atpriv, atpkg, atexport;
+ UMLAttributeList final_atpub, final_atprot, final_atpriv, final_atpkg, final_atexport;
+
+ atpub.setAutoDelete(false);
+ final_atpub.setAutoDelete(false);
+ atprot.setAutoDelete(false);
+ final_atprot.setAutoDelete(false);
+ atpriv.setAutoDelete(false);
+ final_atpriv.setAutoDelete(false);
+ atpkg.setAutoDelete(false);
+ final_atpkg.setAutoDelete(false);
+ atexport.setAutoDelete(false);
+ final_atexport.setAutoDelete(false);
+
+ if (!isInterface) {
+ UMLAttributeList atl = c->getAttributeList();
+ for (UMLAttribute *at = atl.first(); at ; at = atl.next()) {
+ switch(at->getVisibility())
+ {
+ case Uml::Visibility::Public:
+ if(at->getStatic())
+ final_atpub.append(at);
+ else
+ atpub.append(at);
+ break;
+ case Uml::Visibility::Protected:
+ if(at->getStatic())
+ final_atprot.append(at);
+ else
+ atprot.append(at);
+ break;
+ case Uml::Visibility::Private:
+ if(at->getStatic())
+ final_atpriv.append(at);
+ else
+ atpriv.append(at);
+ break;/* TODO: requires support from the gui & other structures
+ case Uml::Visibility::Package:
+ if(at->getStatic())
+ final_atpkg.append(at);
+ else
+ atpkg.append(at);
+ break;
+ case Uml::Visibility::Export:
+ if(at->getStatic())
+ final_atexport.append(at);
+ else
+ atexport.append(at);
+ break;*/
+ default:
+ break;
+ }
+ }
+ }
+
+ // another preparation, determine what we have
+ UMLAssociationList associations = c->getSpecificAssocs(Uml::at_Association); // BAD! only way to get "general" associations.
+ UMLAssociationList uniAssociations = c->getUniAssociationToBeImplemented();
+
+ UMLAssociationList aggregations = c->getAggregations();
+ UMLAssociationList compositions = c->getCompositions();
+
+ bool hasAssociations = aggregations.count() + associations.count() + compositions.count() + uniAssociations.count() > 0;
+ bool hasAttributes = atl.count() > 0;
+ bool hasAccessorMethods = hasAttributes || hasAssociations;
+ bool hasOperationMethods = c->getOpList().count() > 0;
+
+ // ATTRIBUTES
+ //
+
+ // write comment for section IF needed
+ if (forceDoc() || hasAccessorMethods)
+ {
+ writeComment("", m_indentation, d);
+ writeComment("Fields", m_indentation, d);
+ writeComment("", m_indentation, d);
+ writeBlankLine(d);
+ }
+
+ writeAttributeDecls(final_atpub, final_atprot, final_atpriv, d);
+ writeAttributeDecls(atpub, atprot, atpriv, d);
+
+ writeAssociationDecls(associations, c->getID(), d);
+ writeAssociationDecls(uniAssociations, c->getID(), d);
+ writeAssociationDecls(aggregations, c->getID(), d);
+ writeAssociationDecls(compositions, c->getID(), d);
+
+ //FIXME: find constructors and write them here
+
+ // write constructors
+ if(!isInterface) writeConstructor(c, d);
+
+
+ // METHODS
+ //
+
+ // write comment for sub-section IF needed
+ if (forceDoc() || hasAccessorMethods ) {
+ writeComment("", m_indentation, d);
+ writeComment("Accessors", m_indentation, d);
+ writeComment("", m_indentation, d);
+ writeBlankLine(d);
+ }
+
+
+ // Accessors for attributes
+ writeAttributeMethods(final_atpub, Uml::Visibility::Public, d);
+ writeAttributeMethods(final_atprot, Uml::Visibility::Protected, d);
+ writeAttributeMethods(final_atpriv, Uml::Visibility::Private, d);
+ writeAttributeMethods(atpub, Uml::Visibility::Public, d);
+ writeAttributeMethods(atprot, Uml::Visibility::Protected, d);
+ writeAttributeMethods(atpriv, Uml::Visibility::Private, d);
+
+ // accessor methods for associations
+
+ // first: determine the name of the other class
+ writeAssociationMethods(associations, c, d);
+ writeAssociationMethods(uniAssociations, c, d);
+ writeAssociationMethods(aggregations, c, d);
+ writeAssociationMethods(compositions, c, d);
+
+ // Other operation methods
+ // all other operations are now written
+
+ // write comment for sub-section IF needed
+ if (forceDoc() || hasOperationMethods) {
+ writeComment("", m_indentation, d);
+ writeComment("Other methods", m_indentation, d);
+ writeComment("", m_indentation, d);
+ writeBlankLine(d);
+ }
+
+ writeOperations(c, d);
+
+ d << "}" << m_endl; // end class
+
+ file.close();
+ emit codeGenerated(c, true);
+}
+
+void DWriter::writeClassDecl(UMLClassifier *c, QTextStream &d) {
+
+ // class documentation
+ if (!c->getDoc().isEmpty()) {
+ writeDocumentation("", c->getDoc(), "", "", d);
+ }
+
+ /*
+ * Class declaration
+ *
+ * (private) class foo(T, ..., Z) : class1, ..., classN, interface1, ..., interfaceN
+ * a b c d e f g
+ */
+
+ // (a) visibility modifier
+ switch(c->getVisibility()) {
+ case Uml::Visibility::Private: d << "private "; break;
+ default: break;
+ }
+
+ // (b) keyword
+ // TODO what about structs?
+ if (isInterface) {
+ d << "interface ";
+ } else {
+ if (c->getAbstract()) {
+ d << "abstract ";
+ }
+
+ d << "class ";
+ }
+
+ // (c) class name
+ QString classname = cleanName(c->getName()); // our class name
+ d << classname;
+
+ // (d) template parameters
+ UMLTemplateList template_params = c->getTemplateList();
+ if (template_params.count()) {
+ d << "(";
+
+ for (UMLTemplate *t = template_params.first(); t; ) {
+ // TODO: hm, leaving the type blank results in "class"
+ // so we omit it (also because "class" in this context is illegal)
+ if (t->getTypeName() != "class") {
+ d << t->getTypeName();
+ d << " ";
+ }
+
+ d << t->getName();
+
+ if ((t = template_params.next()) != NULL)
+ d << ", ";
+ }
+
+ d << ")";
+ }
+
+ // (e) inheritances
+ UMLClassifierList superclasses =
+ c->findSuperClassConcepts(UMLClassifier::CLASS);
+ UMLClassifierList superinterfaces =
+ c->findSuperClassConcepts(UMLClassifier::INTERFACE);
+
+ int count = superclasses.count() + superinterfaces.count();
+
+ if (count > 0) {
+ d << " : ";
+
+ // (f) base classes
+ for (UMLClassifier * concept= superclasses.first(); concept; concept = superclasses.next()) {
+ d << cleanName(concept->getName());
+
+ count--;
+
+ if (count>0) d << ", ";
+ }
+
+ // (g) interfaces
+ for (UMLClassifier * concept= superinterfaces.first(); concept; concept = superinterfaces.next()) {
+ d << cleanName(concept->getName());
+
+ count--;
+
+ if (count>0) d << ", ";
+ }
+ }
+}
+
+void DWriter::writeProtectionMod(Uml::Visibility visibility, QTextStream &d) {
+ d << m_indentation << scopeToDDecl(visibility) << ":" << m_endl << m_endl;
+}
+
+void DWriter::writeAttributeDecl(Uml::Visibility visibility, UMLAttributeList &atlist, QTextStream &d) {
+ if (atlist.count()==0) return;
+
+ writeProtectionMod(visibility, d);
+
+ for(UMLAttribute *at=atlist.first(); at; at=atlist.next()) {
+ // documentation
+ if (!at->getDoc().isEmpty()) {
+ writeComment(at->getDoc(), m_indentation, d, true);
+ }
+
+ d << m_indentation;
+
+ // static attribute?
+ if (at->getStatic()) d << "static ";
+
+ // method return type
+ d << fixTypeName(at->getTypeName()) << " ";
+
+ // TODO: find out whether this class has accessors or not
+ bool hasAccessorMethods = true;
+
+ // attribute name
+ if (hasAccessorMethods) {
+ d << "m_";
+ }
+ d << cleanName(at->getName());
+
+ // initial value
+ QString initVal = fixInitialStringDeclValue(at->getInitialValue(), at->getTypeName());
+ if (!initVal.isEmpty()) d << " = " << initVal;
+ d << ";" << m_endl << m_endl;
+ }
+}
+
+void DWriter::writeAttributeDecls(UMLAttributeList &atpub, UMLAttributeList &atprot,
+ UMLAttributeList &atpriv, QTextStream &d ) {
+
+ writeAttributeDecl(Uml::Visibility::Public, atpub, d);
+ writeAttributeDecl(Uml::Visibility::Protected, atprot, d);
+ writeAttributeDecl(Uml::Visibility::Private, atpriv, d);
+ //TODO: export and package
+}
+
+void DWriter::writeAttributeMethods(UMLAttributeList &atpub, Uml::Visibility visibility, QTextStream &d) {
+ if (atpub.count()==0) return;
+
+ writeProtectionMod(visibility, d);
+
+ for(UMLAttribute *at=atpub.first(); at; at=atpub.next()) {
+ QString fieldName = cleanName(at->getName());
+ writeSingleAttributeAccessorMethods(
+ at->getTypeName(), "m_" + fieldName, fieldName, at->getDoc(),
+ visibility, Uml::chg_Changeable, at->getStatic(), d);
+ }
+}
+
+void DWriter::writeComment(const QString &comment, const QString &myIndent,
+ QTextStream &d, bool dDocStyle) {
+ if(dDocStyle) {
+ d << myIndent << "/**" << m_endl;
+ }
+
+ QStringList lines = QStringList::split("\n", comment);
+
+ if (lines.count() == 0) lines << comment;
+
+ for (uint i = 0; i < lines.count(); ++i) {
+ QString tmp = lines[i];
+
+ while (tmp.length() > 77) {
+ uint l = tmp.left(77).findRev(' ');
+ if (l < 1) l = tmp.find(' ', 77);
+ if (l < 1 || l > tmp.length()) {
+ d << myIndent << (dDocStyle ? " * " : "// ") << tmp << m_endl;
+ break;
+ }
+ d << myIndent << (dDocStyle ? " * " : "// ") << tmp.left(l) << m_endl;
+ tmp = tmp.right(tmp.length() - l);
+ }
+
+ d << myIndent << (dDocStyle ? " * " : "// ") << tmp << m_endl;
+ }
+
+ if(dDocStyle) {
+ d << myIndent << " */" << m_endl;
+ }
+}
+
+void DWriter::writeDocumentation(QString header, QString body, QString end, QString indent, QTextStream &d) {
+ d << indent << "/**" << m_endl;
+ if (!header.isEmpty())
+ d << formatDoc(header, indent+" * ");
+ if (!body.isEmpty())
+ d << formatDoc(body, indent+" * ");
+ if (!end.isEmpty())
+ {
+ QStringList lines = QStringList::split( "\n", end);
+ for (uint i= 0; i < lines.count(); i++)
+ d << formatDoc(lines[i], indent + " * ");
+ }
+ d<<indent<< " */" << m_endl;
+}
+
+void DWriter::writeAssociationDecls(UMLAssociationList associations, Uml::IDType id, QTextStream &d) {
+
+ if( forceSections() || !associations.isEmpty() )
+ {
+ bool printRoleA = false, printRoleB = false;
+ for(UMLAssociation *a = associations.first(); a; a = associations.next())
+ {
+ // it may seem counter intuitive, but you want to insert the role of the
+ // *other* class into *this* class.
+ if (a->getObjectId(Uml::A) == id)
+ printRoleB = true;
+
+ if (a->getObjectId(Uml::B) == id)
+ printRoleA = true;
+
+ // First: we insert documentaion for association IF it has either role AND some documentation (!)
+ if ((printRoleA || printRoleB) && !(a->getDoc().isEmpty()))
+ writeComment(a->getDoc(), m_indentation, d);
+
+ // print RoleB decl
+ if (printRoleB)
+ {
+ QString fieldClassName = cleanName(getUMLObjectName(a->getObject(Uml::B)));
+ writeAssociationRoleDecl(fieldClassName, a->getRoleName(Uml::B), a->getMulti(Uml::B), a->getRoleDoc(Uml::B), a->getVisibility(Uml::B), d);
+ }
+
+ // print RoleA decl
+ if (printRoleA)
+ {
+ QString fieldClassName = cleanName(getUMLObjectName(a->getObject(Uml::A)));
+ writeAssociationRoleDecl(fieldClassName, a->getRoleName(Uml::A), a->getMulti(Uml::A), a->getRoleDoc(Uml::A), a->getVisibility(Uml::A), d);
+ }
+ }
+ }
+}
+
+void DWriter::writeAssociationRoleDecl(QString fieldClassName,
+ QString roleName, QString multi,
+ QString doc, Uml::Visibility /*visib*/, QTextStream &d) {
+ // ONLY write out IF there is a rolename given
+ // otherwise its not meant to be declared in the code
+ if (roleName.isEmpty()) return;
+
+ if (!doc.isEmpty()) {
+ writeComment(doc, m_indentation, d);
+ }
+
+ bool hasAccessors = true;
+
+ // declare the association based on whether it is this a single variable
+ // or a List (Vector). One day this will be done correctly with special
+ // multiplicity object that we don't have to figure out what it means via regex.
+ if(multi.isEmpty() || multi.contains(QRegExp("^[01]$"))) {
+ d << m_indentation << fieldClassName << " ";
+
+ if (hasAccessors) d << "m_";
+
+ d << deCapitaliseFirstLetter(roleName) << ";";
+ } else {
+ d << m_indentation << fieldClassName << "[] ";
+ //TODO: templated containers
+
+ if (hasAccessors) d << "m_";
+
+ d << pluralize(deCapitaliseFirstLetter(roleName)) << ";";
+ // from here we could initialize default values, or put in an init() section
+ // of the constructors
+ }
+
+ // always put space between this and following decl, if any
+ writeBlankLine(d);
+}
+
+void DWriter::writeAssociationMethods (UMLAssociationList associations, UMLClassifier *thisClass, QTextStream &d) {
+ if( forceSections() || !associations.isEmpty() ) {
+ for(UMLAssociation *a = associations.first(); a; a = associations.next()) {
+ // insert the methods to access the role of the other
+ // class in the code of this one
+ if (a->getObjectId(Uml::A) == thisClass->getID()) {
+ // only write out IF there is a rolename given
+ if(!a->getRoleName(Uml::B).isEmpty()) {
+ QString fieldClassName = getUMLObjectName(a->getObject(Uml::B));
+ writeAssociationRoleMethod(fieldClassName,
+ a->getRoleName(Uml::B),
+ a->getMulti(Uml::B), a->getRoleDoc(Uml::B),
+ a->getVisibility(Uml::B),
+ a->getChangeability(Uml::B), d);
+ }
+ }
+
+ if (a->getObjectId(Uml::B) == thisClass->getID()) {
+ // only write out IF there is a rolename given
+ if(!a->getRoleName(Uml::A).isEmpty()) {
+ QString fieldClassName = getUMLObjectName(a->getObject(Uml::A));
+ writeAssociationRoleMethod(fieldClassName, a->getRoleName(Uml::A),
+ a->getMulti(Uml::A),
+ a->getRoleDoc(Uml::A),
+ a->getVisibility(Uml::A),
+ a->getChangeability(Uml::A),
+ d);
+ }
+ }
+ }
+ }
+}
+
+void DWriter::writeAssociationRoleMethod (QString fieldClassName, QString roleName, QString multi,
+ QString description, Uml::Visibility visib, Uml::Changeability_Type change,
+ QTextStream &d) {
+ if(multi.isEmpty() || multi.contains(QRegExp("^[01]$"))) {
+ QString fieldVarName = "m_" + deCapitaliseFirstLetter(roleName);
+
+ writeSingleAttributeAccessorMethods(
+ fieldClassName, fieldVarName, roleName, description, visib, change, false, d);
+ } else {
+ QString fieldVarName = "m_" + pluralize(deCapitaliseFirstLetter(roleName));
+
+ writeVectorAttributeAccessorMethods(
+ fieldClassName, fieldVarName, pluralize(roleName), description, visib, change, d);
+ }
+}
+
+void DWriter::writeVectorAttributeAccessorMethods (QString fieldClassName, QString fieldVarName,
+ QString fieldName, QString description,
+ Uml::Visibility /*visibility*/, Uml::Changeability_Type changeType,
+ QTextStream &d) {
+
+ fieldClassName = fixTypeName(fieldClassName);
+ QString fieldNameUP = unPluralize(fieldName);
+ QString fieldNameUC = Codegen_Utils::capitalizeFirstLetter(fieldNameUP);
+
+ // ONLY IF changeability is NOT Frozen
+ if (changeType != Uml::chg_Frozen) {
+ writeDocumentation("Adds a " + fieldNameUP + " to the list of " +
+ fieldName + '.', description, "", m_indentation, d);
+
+ d << m_indentation << "void add" << fieldNameUC << "(";
+ d << fieldClassName << " new" << fieldNameUC << ") {";
+ d << startline << m_indentation << fieldVarName << " ~= new" << fieldNameUC << ";";
+ d << startline << "}" << m_endl << m_endl;
+ }
+
+ // ONLY IF changeability is Changeable
+ if (changeType == Uml::chg_Changeable) {
+ writeDocumentation("Removes a " + fieldNameUP + " from the list of " +
+ fieldName + '.', description, "", m_indentation, d);
+
+ d << m_indentation << "void remove" << fieldNameUC << "(";
+ d << fieldClassName << " " << fieldNameUP << ") {" << startline;
+ d << m_indentation << "int idx = " << fieldVarName << ".length;" << startline;
+ d << m_indentation << "foreach(i, o; " << fieldVarName << ")" << startline;
+ d << m_indentation << m_indentation << "if (o && o == " << fieldNameUP << ") {" << startline;
+ d << m_indentation << m_indentation << m_indentation << "idx = i;" << startline;
+ d << m_indentation << m_indentation << m_indentation << "break;" << startline;
+ d << m_indentation << m_indentation << "}" << m_endl << startline;
+ d << m_indentation << fieldVarName << " = " << fieldVarName;
+ d << "[0..idx] ~ " << fieldVarName << "[idx..$];" << startline;
+ d << "}" << m_endl << m_endl;
+ }
+
+ // always allow getting the list of stuff
+ writeDocumentation("Returns the list of " + fieldName + '.',
+ description, "@return List of " + fieldName + '.',
+ m_indentation, d);
+
+ d << m_indentation << fieldClassName << "[] get" << fieldName << "() {";
+ d << startline << m_indentation << "return " << fieldVarName << ";";
+ d << startline << "}" << m_endl << m_endl;
+}
+
+
+void DWriter::writeSingleAttributeAccessorMethods(QString fieldClassName,
+ QString fieldVarName, QString fieldName, QString description, Uml::Visibility /*visibility*/,
+ Uml::Changeability_Type change, bool isFinal, QTextStream &d) {
+
+ fieldClassName = fixTypeName(fieldClassName);
+ QString fieldNameUC = Codegen_Utils::capitalizeFirstLetter(fieldName);
+ if (fieldName.left(2) == "m_") fieldName = fieldName.right(fieldName.length()-2);
+
+ // set method
+ if (change == Uml::chg_Changeable && !isFinal) {
+ writeDocumentation("Sets the value of " + fieldName + '.', description,
+ "@param new" + fieldNameUC + " The new value of " + fieldName + '.',
+ m_indentation, d);
+
+ d << m_indentation << fieldClassName << " " << fieldName << "(";
+ d << fieldClassName << " new" << fieldNameUC << ") {";
+ d << startline << m_indentation << "return " << fieldVarName << " = new" << fieldNameUC << ";";
+ d << startline << "}" << m_endl << m_endl;
+ }
+
+ // get method
+ writeDocumentation("Returns the value of " + fieldName + '.', description,
+ "@return The value of " + fieldName + '.',
+ m_indentation, d);
+
+ d << m_indentation << fieldClassName << " " << fieldName << "() {";
+ d << startline << m_indentation << "return " << fieldVarName << ";";
+ d << startline << "}" << m_endl << m_endl;
+}
+
+void DWriter::writeConstructor(UMLClassifier *c, QTextStream &d) {
+
+ if (forceDoc())
+ {
+ d<<startline;
+ writeComment("", m_indentation, d);
+ writeComment("Constructors", m_indentation, d);
+ writeComment("", m_indentation, d);
+ writeBlankLine(d);
+ }
+
+ // write the first constructor
+ QString className = cleanName(c->getName());
+ d << m_indentation << "public this("<<") { }";
+
+}
+
+// IF the type is "string" we need to declare it as
+// the D Object "String" (there is no string primative in D).
+// Same thing again for "bool" to "boolean"
+QString DWriter::fixTypeName(const QString& string) {
+ if (string.isEmpty())
+ return "void";
+ if (string == "string")
+ return "char[]";
+ if (string == "unsigned short")
+ return "ushort";
+ if (string == "unsigned int")
+ return "uint";
+ if (string == "unsigned long")
+ return "ulong";
+ return string;
+}
+
+QStringList DWriter::defaultDatatypes() {
+ QStringList l;
+ l << "void"
+ << "bool"
+ << "byte"
+ << "ubyte"
+ << "short"
+ << "ushort"
+ << "int"
+ << "uint"
+ << "long"
+ << "ulong"
+ << "cent"
+ << "ucent"
+ << "float"
+ << "double"
+ << "real"
+ << "ifloat"
+ << "idouble"
+ << "ireal"
+ << "cfloat"
+ << "cdouble"
+ << "creal"
+ << "char"
+ << "wchar"
+ << "dchar";
+ return l;
+}
+
+
+bool DWriter::compareDMethod(UMLOperation *op1, UMLOperation *op2) {
+ if (op1 == NULL || op2 == NULL)
+ return false;
+ if (op1 == op2)
+ return true;
+ if (op1->getName() != op2->getName())
+ return false;
+ UMLAttributeList atl1 = op1->getParmList();
+ UMLAttributeList atl2 = op2->getParmList();
+ if (atl1.count() != atl2.count())
+ return false;
+ UMLAttribute *at1;
+ UMLAttribute *at2;
+ for (at1 = atl1.first(), at2 = atl2.first(); at1 && at2 ; at1 = atl1.next(),at2 = atl2.next())
+ {
+ if (at1->getTypeName() != at2->getTypeName())
+ return false;
+ }
+ return true;
+
+}
+
+bool DWriter::dMethodInList(UMLOperation *umlOp, UMLOperationList &opl) {
+ for (UMLOperation *op = opl.first(); op; op = opl.next()) {
+ if (DWriter::compareDMethod(op, umlOp)) {
+ return true;
+ }
+ }
+ return false;
+}
+
+void DWriter::getSuperImplementedOperations(UMLClassifier *c, UMLOperationList &yetImplementedOpList ,UMLOperationList &toBeImplementedOpList, bool noClassInPath) {
+ UMLClassifierList superClasses = c->findSuperClassConcepts();
+
+ for (UMLClassifier *concept= superClasses.first(); concept; concept = superClasses.next())
+ {
+ getSuperImplementedOperations(concept, yetImplementedOpList, toBeImplementedOpList, (concept->isInterface() && noClassInPath));
+ UMLOperationList opl = concept->getOpList();
+ for (UMLOperation *op = opl.first(); op; op = opl.next()) {
+ if (concept->isInterface() && noClassInPath) {
+ if (!DWriter::dMethodInList(op,toBeImplementedOpList))
+ toBeImplementedOpList.append(op);
+ }
+ else
+ {
+ if (!DWriter::dMethodInList(op, yetImplementedOpList))
+ yetImplementedOpList.append(op);
+ }
+ }
+ }
+
+}
+
+void DWriter::getInterfacesOperationsToBeImplemented(UMLClassifier *c, UMLOperationList &opList ) {
+ UMLOperationList yetImplementedOpList;
+ UMLOperationList toBeImplementedOpList;
+
+ getSuperImplementedOperations(c,yetImplementedOpList, toBeImplementedOpList);
+ for (UMLOperation *op = toBeImplementedOpList.first(); op; op = toBeImplementedOpList.next())
+ {
+ if ( ! DWriter::dMethodInList(op, yetImplementedOpList) && ! DWriter::dMethodInList(op, opList) )
+ opList.append(op);
+ }
+}
+
+void DWriter::writeOperations(UMLClassifier *c, QTextStream &d) {
+ UMLOperationList opl;
+ UMLOperationList oppub,opprot,oppriv;
+ oppub.setAutoDelete(false);
+ opprot.setAutoDelete(false);
+ oppriv.setAutoDelete(false);
+
+ //sort operations by scope first and see if there are abstract methods
+ opl = c->getOpList();
+ if (! c->isInterface()) {
+ getInterfacesOperationsToBeImplemented(c, opl);
+ }
+ for (UMLOperation *op = opl.first(); op; op = opl.next()) {
+ switch(op->getVisibility()) {
+ case Uml::Visibility::Public:
+ oppub.append(op);
+ break;
+ case Uml::Visibility::Protected:
+ opprot.append(op);
+ break;
+ case Uml::Visibility::Private:
+ oppriv.append(op);
+ break;
+ default: //TODO: package, export
+ break;
+ }
+ }
+
+ // do people REALLY want these comments? Hmm.
+ /*
+ if(forceSections() || oppub.count())
+ {
+ writeComment("public operations",m_indentation,d);
+ writeBlankLine(d);
+ }
+ */
+
+ if (oppub.count() > 0) {
+ writeProtectionMod(Uml::Visibility::Public, d);
+
+ writeOperations(oppub,d);
+ }
+
+ if (opprot.count() > 0) {
+ writeProtectionMod(Uml::Visibility::Protected, d);
+
+ writeOperations(opprot, d);
+ }
+
+ if (oppriv.count() > 0) {
+ writeProtectionMod(Uml::Visibility::Private, d);
+
+ writeOperations(oppriv, d);
+ }
+
+}
+
+void DWriter::writeOperations(UMLOperationList &oplist, QTextStream &d) {
+ UMLAttributeList atl;
+ QString str;
+
+ // generate method decl for each operation given
+ for(UMLOperation *op=oplist.first(); op; op=oplist.next()) {
+ QString returnStr = "";
+ // write documentation
+
+ QString methodReturnType = fixTypeName(op->getTypeName());
+
+ //TODO: return type comment
+ if(methodReturnType != "void") {
+ returnStr += "@return " + methodReturnType + m_endl;
+ }
+
+ str = ""; // reset for next method
+ if (op->getAbstract() && !isInterface) str += "abstract ";
+ if (op->getStatic()) str += "static ";
+
+ str += methodReturnType + ' ' +cleanName(op->getName()) + '(';
+
+ atl = op->getParmList();
+ int i = atl.count();
+ int j = 0;
+ for (UMLAttribute *at = atl.first(); at; at = atl.next(), j++) {
+ QString typeName = fixTypeName(at->getTypeName());
+ QString atName = cleanName(at->getName());
+ str += typeName + ' ' + atName +
+ (!(at->getInitialValue().isEmpty()) ?
+ (QString(" = ")+at->getInitialValue()) :
+ QString(""))
+ + ((j < i-1)?", ":"");
+ returnStr += "@param " + atName+' '+at->getDoc() + m_endl;
+ }
+
+ str+= ')';
+
+ // method only gets a body IF its not abstract
+ if (op->getAbstract() || isInterface)
+ str += ';'; // terminate now
+ else
+ str += startline + '{' + startline + '}'; // empty method body
+
+ // write it out
+ writeDocumentation("", op->getDoc(), returnStr, m_indentation, d);
+ d << m_indentation << str << m_endl << m_endl;
+ }
+}
+
+QString DWriter::fixInitialStringDeclValue(QString value, QString type) {
+ // check for strings only
+ if (!value.isEmpty() && type == "String") {
+ if (!value.startsWith("\""))
+ value.prepend("\"");
+ if (!value.endsWith("\""))
+ value.append("\"");
+ }
+ return value;
+}
+
+QString DWriter::scopeToDDecl(Uml::Visibility scope) {
+ QString scopeString;
+
+ switch(scope) {
+ case Uml::Visibility::Public: scopeString = "public"; break;
+ case Uml::Visibility::Protected: scopeString = "protected"; break;
+ case Uml::Visibility::Private: scopeString = "private"; break;
+ default: break; //TODO: package and export
+ }
+
+ return scopeString;
+}
+
+// methods like this _shouldn't_ be needed IF we properly did things thruought the code.
+QString DWriter::getUMLObjectName(UMLObject *obj) {
+ return(obj!=0)?obj->getName():QString("NULL");
+}
+
+QString DWriter::deCapitaliseFirstLetter(QString string) {
+ string.replace( 0, 1, string[0].lower());
+ return string;
+}
+
+QString DWriter::pluralize(QString string) {
+ return string + (string.right(1) == "s" ? "es" : "s");
+}
+
+QString DWriter::unPluralize(QString string) {
+ // does not handle special cases liek datum -> data, etc.
+
+ if (string.length() > 2 && string.right(3) == "ses") {
+ return string.left(string.length() - 2);
+ }
+
+ if (string.right(1) == "s") {
+ return string.left(string.length() - 1);
+ }
+
+ return string;
+}
+
+void DWriter::writeBlankLine(QTextStream &d) {
+ d << m_endl;
+}
+
diff --git a/umbrello/umbrello/codegenerators/dwriter.h b/umbrello/umbrello/codegenerators/dwriter.h
new file mode 100644
index 00000000..38828359
--- /dev/null
+++ b/umbrello/umbrello/codegenerators/dwriter.h
@@ -0,0 +1,276 @@
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * copyright (C) 2007 Jari-Matti Mäkelä <jmjm@iki.fi> *
+ * Umbrello UML Modeller Authors <uml-devel@uml.sf.net> *
+ ***************************************************************************/
+
+/***************************************************************************
+ This is the "old" code generator that does not support code editing
+ in the Modeller but uses significantly less file space because the
+ source code is not replicated in the XMI file.
+ ***************************************************************************/
+
+#ifndef DWRITER_H
+#define DWRITER_H
+
+#include "simplecodegenerator.h"
+#include "../umloperationlist.h"
+#include "../umlattributelist.h"
+#include "../umlassociationlist.h"
+
+class UMLOperation;
+
+/**
+ * class DWriter is a code generator for UMLClassifier objects.
+ * Create an instance of this class, and feed it a UMLClassifier when
+ * calling writeClass and it will generate a d source file for
+ * that concept
+ */
+class DWriter : public SimpleCodeGenerator {
+public:
+
+ /**
+ * Constructor, initialises a couple of variables
+ */
+ DWriter();
+
+ /**
+ * Destructor, empty
+ */
+ virtual ~DWriter();
+
+ /**
+ * call this method to generate d code for a UMLClassifier
+ * @param c the class to generate code for
+ */
+ virtual void writeClass(UMLClassifier *c);
+
+ /**
+ * returns "D"
+ */
+ virtual Uml::Programming_Language getLanguage();
+
+ /**
+ * Overrides method from class CodeGenerator
+ */
+ QStringList defaultDatatypes();
+
+private:
+
+ /**
+ * Writes the module declaration.
+ */
+ void writeModuleDecl(UMLClassifier *c, QTextStream &d);
+
+ /**
+ * Writes the module imports.
+ */
+ void writeModuleImports(UMLClassifier *c, QTextStream &d);
+
+ /**
+ * Writes class's documentation then the class header
+ * public abstract class Foo extents {
+ */
+ void writeClassDecl(UMLClassifier *c, QTextStream &d);
+
+ /**
+ * Writes the comment and class constructor
+ */
+ void writeConstructor(UMLClassifier *c, QTextStream &d);
+
+ /**
+ * return true if the two operations have the same name and the same parameters
+ * @param op1 first operation to be compared
+ * @param op2 second operation to be compared
+ */
+ static bool compareDMethod(UMLOperation *op1, UMLOperation *op2);
+
+ /**
+ * return true if the operation is in the list
+ * @param umlOp operation to be searched
+ * @param opl list of operations
+ */
+ static bool dMethodInList(UMLOperation *umlOp, UMLOperationList &opl);
+
+ /**
+ * get all operations which a given class inherit from all its super interfaces and get all operations
+ * which this given class inherit from all its super classes
+ * @param c the class for which we are generating code
+ * @param yetImplementedOpList the list of yet implemented operations
+ * @param toBeImplementedOpList the list of to be implemented operations
+ * @param noClassInPath tells if there is a class between the base class and the current interface
+ */
+ void getSuperImplementedOperations(UMLClassifier *c, UMLOperationList &yetImplementedOpList ,UMLOperationList &toBeImplementedOpList, bool noClassInPath = true);
+
+ /**
+ * get all operations which a given class inherit from all its super interfaces and that should be implemented
+ * @param c the class for which we are generating code
+ * @param opl the list of operations used to append the operations
+ */
+ void getInterfacesOperationsToBeImplemented(UMLClassifier *c, UMLOperationList &opl);
+
+ /**
+ * write all operations for a given class
+ * @param c the class for which we are generating code
+ * @param j the stream associated with the output file
+ */
+ void writeOperations(UMLClassifier *c, QTextStream &j);
+
+ /**
+ * write a list of operations for a given class
+ * @param list the list of operations you want to write
+ * @param j the stream associated with the output file
+ */
+ void writeOperations(UMLOperationList &list, QTextStream &j);
+
+ /**
+ * write all attributes for a given class
+ * @param c the class for which we are generating code
+ * @param j the stream associated with the output file
+ */
+ void writeAttributes(UMLClassifier *c, QTextStream &j);
+
+ /**
+ * Writes the protection modifier line.
+ * @param visibility protection modifier
+ * @param d text stream
+ */
+ void writeProtectionMod(Uml::Visibility visibility, QTextStream &d);
+
+ /**
+ * Writes attribute declarations with a specific
+ * protection modifier.
+ * @param prot the protection modifier
+ * @param atlist attribute list
+ * @param d text stream
+ */
+ void writeAttributeDecl(Uml::Visibility visibility, UMLAttributeList &atlist, QTextStream &d);
+
+ /**
+ * writes the Attribute declarations
+ * @param atpub List of public attributes
+ * @param atprot list of protected attributes
+ * @param atpriv list of private attributes
+ * @param d text stream
+ */
+ void writeAttributeDecls(UMLAttributeList &atpub, UMLAttributeList &atprot,
+ UMLAttributeList &atpriv, QTextStream &d );
+
+ /**
+ * Searches a list of associations for appropriate ones to write out as attributes
+ */
+ void writeAssociationDecls(UMLAssociationList associations, Uml::IDType id, QTextStream &d);
+
+ /**
+ * Writes out an association as an attribute using Vector
+ */
+ void writeAssociationRoleDecl(QString fieldClassName, QString roleName, QString multi,
+ QString doc, Uml::Visibility visib, QTextStream &d);
+
+ /**
+ * calls @ref writeSingleAttributeAccessorMethods() on each of the attributes in atpub
+ */
+ void writeAttributeMethods(UMLAttributeList &atpub, Uml::Visibility visibility, QTextStream &d);
+
+ /**
+ * calls @ref writeAssociationRoleMethod() on each of the associations in the given list
+ */
+ void writeAssociationMethods(UMLAssociationList associations, UMLClassifier *thisClass,
+ QTextStream &d);
+
+ /**
+ * calls @ref writeSingleAttributeAccessorMethods() or @ref
+ * writeVectorAttributeAccessorMethods() on the assocaition
+ * role
+ */
+ void writeAssociationRoleMethod(QString fieldClassName, QString roleName, QString multi,
+ QString description, Uml::Visibility visib, Uml::Changeability_Type change,
+ QTextStream &d);
+
+ /**
+ * Writes getFoo() and setFoo() accessor methods for the attribute
+ */
+ void writeSingleAttributeAccessorMethods(QString fieldClassName, QString fieldVarName,
+ QString fieldName, QString description,
+ Uml::Visibility visibility, Uml::Changeability_Type change,
+ bool isFinal, QTextStream &d);
+
+ /**
+ * Writes addFoo() and removeFoo() accessor methods for the Vector attribute
+ */
+ void writeVectorAttributeAccessorMethods(QString fieldClassName, QString fieldVarName,
+ QString fieldName, QString description,
+ Uml::Visibility visibility, Uml::Changeability_Type change,
+ QTextStream &d);
+
+ /**
+ * Writes a // style comment
+ */
+ void writeComment(const QString &text, const QString &indent, QTextStream &d, bool dDocStyle=false);
+
+ /**
+ * Writes a documentation comment
+ */
+ void writeDocumentation(QString header, QString body, QString end, QString indent, QTextStream &d);
+
+ /**
+ * Returns the name of the given object (if it exists)
+ */
+ QString getUMLObjectName(UMLObject *obj);
+
+ /**
+ * Lowers the case of the first letter in the given string
+ */
+ QString deCapitaliseFirstLetter(QString string);
+
+ /**
+ * Returns the plural form of a subject.
+ */
+ QString pluralize(QString string);
+
+ /**
+ * Returns the non-plural form of a subject.
+ */
+ QString unPluralize(QString string);
+
+ /**
+ * Replaces `string' with `String' and `bool' with `boolean'
+ */
+ QString fixTypeName(const QString& string);
+
+ /**
+ * check that initial values of strings have quotes around them
+ */
+ QString fixInitialStringDeclValue(QString value, QString type);
+
+ /**
+ * Write a blank line
+ */
+ void writeBlankLine(QTextStream& d);
+
+ /**
+ * a little method for converting scope to string value
+ */
+ QString scopeToDDecl(Uml::Visibility scope);
+
+ /**
+ * A \n, used at the end of each line
+ */
+ QString startline;
+
+ /**
+ * Whether or not this concept is an interface.
+ */
+ bool isInterface;
+
+};
+
+
+#endif // DWRITER_H
+
diff --git a/umbrello/umbrello/codegenerators/idlwriter.cpp b/umbrello/umbrello/codegenerators/idlwriter.cpp
new file mode 100644
index 00000000..a893acc3
--- /dev/null
+++ b/umbrello/umbrello/codegenerators/idlwriter.cpp
@@ -0,0 +1,482 @@
+/***************************************************************************
+ * copyright (C) 2003-2005 *
+ * Umbrello UML Modeller Authors <uml-devel@uml.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. *
+ * *
+ ***************************************************************************/
+
+#include "idlwriter.h"
+
+#include <kdebug.h>
+#include <kmessagebox.h>
+#include <qfile.h>
+#include <qregexp.h>
+#include <qtextstream.h>
+
+#include "../umldoc.h"
+#include "../classifier.h"
+#include "../enum.h"
+#include "../classifierlistitem.h"
+#include "../umlclassifierlistitemlist.h"
+#include "../package.h"
+#include "../association.h"
+#include "../attribute.h"
+#include "../operation.h"
+#include "../umlnamespace.h"
+
+IDLWriter::IDLWriter() : SimpleCodeGenerator(false) {
+}
+
+IDLWriter::~IDLWriter() {}
+
+bool IDLWriter::isOOClass(UMLClassifier *c) {
+ QString stype = c->getStereotype();
+ if (stype == "CORBAConstant" || stype == "CORBAEnum" ||
+ stype == "CORBAStruct" || stype == "CORBAUnion" ||
+ stype == "CORBASequence" || stype == "CORBAArray" ||
+ stype == "CORBATypedef")
+ return false;
+
+ // CORBAValue, CORBAInterface, and all empty/unknown stereotypes are
+ // assumed to be OO classes.
+ return true;
+}
+
+bool IDLWriter::assocTypeIsMappableToAttribute(Uml::Association_Type at) {
+ return (at == Uml::at_Aggregation || at == Uml::at_Association ||
+ at == Uml::at_Composition || at == Uml::at_UniAssociation);
+}
+
+/**
+ * returns "IDL"
+ */
+Uml::Programming_Language IDLWriter::getLanguage() {
+ return Uml::pl_IDL;
+}
+
+void IDLWriter::computeAssocTypeAndRole
+(UMLAssociation *a, UMLClassifier *c, QString& typeName, QString& roleName)
+{
+ // Determine which is the "remote" end of the association:
+ bool IAmRoleA = true;
+ UMLObject *other = a->getObject(Uml::B);
+ Uml::Association_Type at = a->getAssocType();
+ if (c->getName() == other->getName()) {
+ if (at == Uml::at_Aggregation || at == Uml::at_Composition ||
+ at == Uml::at_UniAssociation) {
+ // Assuming unidirectional association, and we are
+ // at the "wrong" side.
+ // Returning roleName = QString::null tells caller to
+ // skip this association at this side.
+ roleName = QString();
+ return;
+ }
+ IAmRoleA = false;
+ other = a->getObject(Uml::A);
+ }
+ // Construct the type name:
+ typeName = cleanName(other->getName());
+ QString multiplicity;
+ if (IAmRoleA)
+ multiplicity = a->getMulti(Uml::B);
+ else
+ multiplicity = a->getMulti(Uml::A);
+ if (!multiplicity.isEmpty() && multiplicity != "1")
+ typeName.append("Vector");
+ // Construct the member name:
+ if (IAmRoleA)
+ roleName = a->getRoleName(Uml::B);
+ else
+ roleName = a->getRoleName(Uml::A);
+ if (roleName.isEmpty()) {
+ roleName = a->getName();
+ if (roleName.isEmpty()) {
+ roleName = "m_" + typeName;
+ }
+ }
+}
+
+void IDLWriter::writeClass(UMLClassifier *c) {
+ if (!c) {
+ kDebug() << "Cannot write class of NULL concept!" << endl;
+ return;
+ }
+
+ const bool isClass = !c->isInterface();
+ QString classname = cleanName(c->getName());
+
+ //find an appropriate name for our file
+ QString fileName = findFileName(c, ".idl");
+ if (fileName.isEmpty()) {
+ emit codeGenerated(c, false);
+ return;
+ }
+
+ QFile file;
+ if (!openFile(file, fileName)) {
+ emit codeGenerated(c, false);
+ return;
+ }
+
+ // Start generating the code.
+
+ QTextStream idl(&file);
+ //try to find a heading file(license, comments, etc)
+ QString str;
+ str = getHeadingFile(".idl");
+ if (!str.isEmpty()) {
+ str.replace(QRegExp("%filename%"), fileName);
+ str.replace(QRegExp("%filepath%"), file.name());
+ idl << str << m_endl;
+ }
+
+ // Write includes.
+ UMLPackageList includes;
+ findObjectsRelated(c, includes);
+ if (includes.count()) {
+ for (UMLPackage *conc = includes.first(); conc; conc = includes.next()) {
+ if (conc->getBaseType() == Uml::ot_Datatype)
+ continue;
+ QString incName = findFileName(conc, ".idl");
+ if (!incName.isEmpty())
+ idl << "#include \"" << incName << "\"" << m_endl;
+ }
+ idl << m_endl;
+ }
+
+ // Generate the module declaration(s) for the package(s) in which
+ // we are embedded.
+ UMLPackageList pkgList = c->getPackages();
+ UMLPackage *pkg;
+ for (pkg = pkgList.first(); pkg != NULL; pkg = pkgList.next()) {
+ idl << getIndent() << "module " << pkg->getName() << " {" << m_endl << m_endl;
+ m_indentLevel++;
+ }
+
+ // Write class Documentation if non-empty or if force option set.
+ if (forceDoc() || !c->getDoc().isEmpty()) {
+ idl << "//" << m_endl;
+ idl << "// class " << classname << m_endl;
+ idl << formatDoc(c->getDoc(), "// ");
+ idl << m_endl;
+ }
+
+ if (c->getBaseType() == Uml::ot_Enum) {
+ UMLClassifierListItemList litList = c->getFilteredList(Uml::ot_EnumLiteral);
+ uint i = 0;
+ idl << getIndent() << "enum " << classname << " {" << m_endl;
+ m_indentLevel++;
+ for (UMLClassifierListItem *lit = litList.first(); lit; lit = litList.next()) {
+ QString enumLiteral = cleanName(lit->getName());
+ idl << getIndent() << enumLiteral;
+ if (++i < litList.count())
+ idl << ",";
+ idl << m_endl;
+ }
+ m_indentLevel--;
+ idl << getIndent() << "};" << m_endl << m_endl;
+ // Close the modules inside which we might be nested.
+ for (pkg = pkgList.first(); pkg != NULL; pkg = pkgList.next()) {
+ m_indentLevel--;
+ idl << getIndent() << "};" << m_endl << m_endl;
+ }
+ return;
+ }
+ if (! isOOClass(c)) {
+ QString stype = c->getStereotype();
+ if (stype == "CORBAConstant") {
+ kError() << "The stereotype " << stype << " cannot be applied to "
+ << c->getName() << ", but only to attributes." << endl;
+ return;
+ }
+ if (!isClass) {
+ kError() << "The stereotype " << stype
+ << " cannot be applied to " << c->getName()
+ << ", but only to classes." << endl;
+ return;
+ }
+ if (stype == "CORBAEnum") {
+ UMLAttributeList atl = c->getAttributeList();
+ UMLAttribute *at;
+ idl << getIndent() << "enum " << classname << " {" << m_endl;
+ m_indentLevel++;
+ uint i = 0;
+ for (at = atl.first(); at; at = atl.next()) {
+ QString enumLiteral = cleanName(at->getName());
+ idl << getIndent() << enumLiteral;
+ if (++i < atl.count())
+ idl << ",";
+ idl << m_endl;
+ }
+ m_indentLevel--;
+ idl << getIndent() << "};" << m_endl << m_endl;
+ } else if (stype == "CORBAStruct") {
+ UMLAttributeList atl = c->getAttributeList();
+ UMLAttribute *at;
+ idl << getIndent() << "struct " << classname << " {" << m_endl;
+ m_indentLevel++;
+ for (at = atl.first(); at; at = atl.next()) {
+ QString name = cleanName(at->getName());
+ idl << getIndent() << at->getTypeName() << " " << name << ";" << m_endl;
+ // Initial value not possible in IDL.
+ }
+ UMLAssociationList compositions = c->getCompositions();
+ if (!compositions.isEmpty()) {
+ idl << getIndent() << "// Compositions." << m_endl;
+ for (UMLAssociation *a = compositions.first(); a; a = compositions.next()) {
+ QString memberType, memberName;
+ computeAssocTypeAndRole(a, c, memberType, memberName);
+ idl << getIndent() << memberType << " " << memberName << ";" << m_endl;
+ }
+ }
+ UMLAssociationList aggregations = c->getAggregations();
+ if (!aggregations.isEmpty()) {
+ idl << getIndent() << "// Aggregations." << m_endl;
+ for (UMLAssociation *a = aggregations.first(); a; a = aggregations.next()) {
+ QString memberType, memberName;
+ computeAssocTypeAndRole(a, c, memberType, memberName);
+ idl << getIndent() << memberType << " " << memberName << ";" << m_endl;
+ }
+ }
+ m_indentLevel--;
+ idl << getIndent() << "};" << m_endl << m_endl;
+ } else if (stype == "CORBAUnion") {
+ idl << getIndent() << "// " << stype << " " << c->getName()
+ << " is Not Yet Implemented" << m_endl << m_endl;
+ } else if (stype == "CORBATypedef") {
+ UMLClassifierList superclasses = c->getSuperClasses();
+ UMLClassifier* firstParent = superclasses.first();
+ idl << getIndent() << "typedef " << firstParent->getName() << " "
+ << c->getName() << ";" << m_endl << m_endl;
+ } else {
+ idl << getIndent() << "// " << stype << ": Unknown stereotype" << m_endl << m_endl;
+ }
+ // Close the modules inside which we might be nested.
+ for (pkg = pkgList.first(); pkg != NULL; pkg = pkgList.next()) {
+ m_indentLevel--;
+ idl << getIndent() << "};" << m_endl << m_endl;
+ }
+ return;
+ }
+
+ idl << getIndent();
+ if (c->getAbstract())
+ idl << "abstract ";
+ bool isValuetype = (c->getStereotype() == "CORBAValue");
+ if (isValuetype)
+ idl << "valuetype ";
+ else
+ idl << "interface ";
+ idl << c->getName();
+ UMLClassifierList superclasses = c->getSuperClasses();
+ if (! superclasses.isEmpty()) {
+ idl << " : ";
+ UMLClassifier *parent = superclasses.first();
+ int n_parents = superclasses.count();
+ while (n_parents--) {
+ idl << parent->getFullyQualifiedName("::");
+ if (n_parents)
+ idl << ", ";
+ parent = superclasses.next();
+ }
+ }
+ idl << " {" << m_endl << m_endl;
+ m_indentLevel++;
+
+ // Generate auxiliary declarations for multiplicity of associations
+ UMLAssociation *a;
+ bool didComment = false;
+ UMLAssociationList assocs = c->getAssociations();
+ for (a = assocs.first(); a; a = assocs.next()) {
+ if (! assocTypeIsMappableToAttribute(a->getAssocType()))
+ continue;
+ QString multiplicity = a->getMulti(Uml::A);
+ if (multiplicity.isEmpty() || multiplicity == "1")
+ continue;
+ if (!didComment) {
+ idl << getIndent() << "// Types for association multiplicities" << m_endl << m_endl;
+ didComment = true;
+ }
+ UMLClassifier* other = (UMLClassifier*)a->getObject(Uml::A);
+ QString bareName = cleanName(other->getName());
+ idl << getIndent() << "typedef sequence<" << other->getFullyQualifiedName("::")
+ << "> " << bareName << "Vector;" << m_endl << m_endl;
+ }
+
+ // Generate public attributes.
+ if (isClass) {
+ UMLAttributeList atl = c->getAttributeList();
+ if (forceSections() || atl.count()) {
+ idl << getIndent() << "// Attributes:" << m_endl << m_endl;
+ for (UMLAttribute *at = atl.first(); at; at = atl.next()) {
+ QString attName = cleanName(at->getName());
+ Uml::Visibility scope = at->getVisibility();
+ idl << getIndent();
+ if (isValuetype) {
+ if (scope == Uml::Visibility::Public)
+ idl << "public ";
+ else
+ idl << "private ";
+ } else {
+ if (scope != Uml::Visibility::Public) {
+ idl << "// visibility should be: "
+ << scope.toString()
+ << m_endl;
+ idl << getIndent();
+ }
+ idl << "attribute ";
+ }
+ idl << at->getTypeName() << " " << attName << ";"
+ << m_endl << m_endl;
+ }
+ }
+ }
+
+ // Generate public operations.
+ UMLOperationList opl(c->getOpList());
+ UMLOperationList oppub;
+ UMLOperation *op;
+ for (op = opl.first(); op; op = opl.next()) {
+ if (op->getVisibility() == Uml::Visibility::Public)
+ oppub.append(op);
+ }
+ if (forceSections() || oppub.count()) {
+ idl << getIndent() << "// Public methods:" << m_endl << m_endl;
+ for (op = oppub.first(); op; op = oppub.next())
+ writeOperation(op, idl);
+ idl << m_endl;
+ }
+
+
+ if (forceSections() || !assocs.isEmpty()) {
+ idl << getIndent() << "// Associations:" << m_endl << m_endl;
+ for (a = assocs.first(); a; a = assocs.next()) {
+ Uml::Association_Type at = a->getAssocType();
+ if (! assocTypeIsMappableToAttribute(at))
+ continue;
+ QString typeName, roleName;
+ computeAssocTypeAndRole(a, c, typeName, roleName);
+ if (roleName.isEmpty()) // presumably because we are at the "wrong" end
+ continue;
+ idl << getIndent() << "// " << UMLAssociation::typeAsString(at) << m_endl;
+ idl << getIndent();
+ if (isValuetype)
+ idl << "public ";
+ else
+ idl << "attribute ";
+ idl << typeName << " " << roleName << ";" << m_endl;
+ }
+ idl << m_endl;
+ }
+
+ m_indentLevel--;
+ idl << getIndent() << "};" << m_endl << m_endl;
+
+ // Close the modules inside which we might be nested.
+ for (pkg = pkgList.first(); pkg != NULL; pkg = pkgList.next()) {
+ m_indentLevel--;
+ idl << getIndent() << "};" << m_endl << m_endl;
+ }
+ file.close();
+ emit codeGenerated(c, true);
+}
+
+
+void IDLWriter::writeOperation(UMLOperation *op, QTextStream &idl, bool is_comment) {
+ UMLAttributeList atl = op->getParmList();
+ QString rettype = op->getTypeName();
+
+ if (rettype.isEmpty())
+ rettype = "void";
+ idl << getIndent();
+ if (is_comment)
+ idl << "// ";
+ idl << rettype << " " << cleanName(op->getName()) << " (";
+ if (atl.count()) {
+ idl << m_endl;
+ m_indentLevel++;
+ uint i = 0;
+ for (UMLAttribute *at = atl.first(); at; at = atl.next()) {
+ idl << getIndent();
+ if (is_comment)
+ idl << "// ";
+ Uml::Parameter_Direction pk = at->getParmKind();
+ if (pk == Uml::pd_Out)
+ idl << "out ";
+ else if (pk == Uml::pd_InOut)
+ idl << "inout ";
+ else
+ idl << "in ";
+ idl << at->getTypeName() << " " << cleanName(at->getName());
+ if (++i < atl.count())
+ idl << "," << m_endl;
+ }
+ m_indentLevel--;
+ }
+ idl << ");" << m_endl << m_endl;
+}
+
+QStringList IDLWriter::defaultDatatypes() {
+ QStringList l;
+ l.append("boolean");
+ l.append("char");
+ l.append("octet");
+ l.append("short");
+ l.append("unsigned short");
+ l.append("long");
+ l.append("unsigned long");
+ l.append("float");
+ l.append("double");
+ l.append("string");
+ l.append("any");
+ return l;
+}
+
+const QStringList IDLWriter::reservedKeywords() const {
+
+ static QStringList keywords;
+
+ if (keywords.isEmpty()) {
+ keywords << "any"
+ << "attribute"
+ << "boolean"
+ << "case"
+ << "char"
+ << "const"
+ << "context"
+ << "default"
+ << "double"
+ << "enum"
+ << "exception"
+ << "FALSE"
+ << "float"
+ << "in"
+ << "inout"
+ << "interface"
+ << "long"
+ << "module"
+ << "octet"
+ << "oneway"
+ << "out"
+ << "raises"
+ << "readonly"
+ << "sequence"
+ << "short"
+ << "string"
+ << "struct"
+ << "switch"
+ << "TRUE"
+ << "typedef"
+ << "union"
+ << "unsigned"
+ << "void";
+ }
+
+ return keywords;
+}
+
+
diff --git a/umbrello/umbrello/codegenerators/idlwriter.h b/umbrello/umbrello/codegenerators/idlwriter.h
new file mode 100644
index 00000000..c44cabd6
--- /dev/null
+++ b/umbrello/umbrello/codegenerators/idlwriter.h
@@ -0,0 +1,74 @@
+/***************************************************************************
+ idlwriter.h - description
+ -------------------
+ begin : Sat Jan 4 2003
+ copyright : (C) 2003 by Oliver Kellogg
+ email : okellogg@users.sourceforge.net
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the 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 IDLWRITER_H
+#define IDLWRITER_H
+
+#include "simplecodegenerator.h"
+
+class UMLAssociation;
+class UMLOperation;
+
+/**
+ * Class IDLWriter is a code generator for UMLClassifier objects.
+ * Create an instance of this class, and feed it a UMLClassifier when
+ * calling writeClass and it will generate an IDL interface for that
+ * concept.
+ */
+class IDLWriter : public SimpleCodeGenerator {
+public:
+
+ IDLWriter ();
+ virtual ~IDLWriter ();
+
+ /**
+ * call this method to generate IDL code for a UMLClassifier
+ * @param c the class to generate code for
+ */
+ virtual void writeClass (UMLClassifier *c);
+
+ /**
+ * returns "IDL"
+ */
+ virtual Uml::Programming_Language getLanguage();
+
+ QStringList defaultDatatypes();
+
+ /**
+ * get list of reserved keywords
+ */
+ virtual const QStringList reservedKeywords() const;
+
+private:
+
+ /**
+ * write one operation
+ * @param op the class for which we are generating code
+ * @param idl the stream associated with the output file
+ */
+ void writeOperation(UMLOperation* op, QTextStream& idl, bool is_comment = false);
+
+ void computeAssocTypeAndRole(UMLAssociation* a, UMLClassifier *c,
+ QString& typeName, QString& roleName);
+
+ static bool isOOClass(UMLClassifier* c);
+
+ static bool assocTypeIsMappableToAttribute(Uml::Association_Type at);
+
+};
+
+#endif // IDLWRITER_H
diff --git a/umbrello/umbrello/codegenerators/javaantcodedocument.cpp b/umbrello/umbrello/codegenerators/javaantcodedocument.cpp
new file mode 100644
index 00000000..a3a174a3
--- /dev/null
+++ b/umbrello/umbrello/codegenerators/javaantcodedocument.cpp
@@ -0,0 +1,312 @@
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * copyright (C) 2004-2007 *
+ * Umbrello UML Modeller Authors <uml-devel@uml.sf.net> *
+ ***************************************************************************/
+
+/* This code generated by:
+ * Author : thomas
+ * Date : Tue Jun 24 2003
+ */
+
+// own header
+#include "javaantcodedocument.h"
+
+// qt/kde includes
+#include <qregexp.h>
+#include <kdebug.h>
+
+// local includes
+#include "javacodegenerator.h"
+#include "xmlcodecomment.h"
+#include "xmlelementcodeblock.h"
+#include "codegenfactory.h"
+#include "../umldoc.h"
+#include "../uml.h"
+
+
+// Constructors/Destructors
+//
+
+JavaANTCodeDocument::JavaANTCodeDocument ( )
+{
+ setFileName("build"); // default name
+ setFileExtension(".xml");
+ setID("ANTDOC"); // default id tag for this type of document
+}
+
+JavaANTCodeDocument::~JavaANTCodeDocument ( ) { }
+
+//
+// Methods
+//
+
+// Other methods
+//
+
+/**
+ * create a new CodeBlockWithComments object belonging to this CodeDocument.
+ * @return CodeBlockWithComments
+ */
+/*
+CodeBlockWithComments * JavaANTCodeDocument::newCodeBlockWithComments ( ) {
+ return new XMLElementCodeBlock(this,"empty");
+}
+*/
+
+HierarchicalCodeBlock * JavaANTCodeDocument::newHierarchicalCodeBlock ( ) {
+ return new XMLElementCodeBlock(this,"empty");
+}
+
+// Sigh. NOT optimal. The only reason that we need to have this
+// is so we can create the XMLNodes, if needed.
+// would be better if we could create a handler interface that each
+// codeblock used so all we have to do here is add the handler
+void JavaANTCodeDocument::loadChildTextBlocksFromNode ( QDomElement & root)
+{
+
+ QDomNode tnode = root.firstChild();
+ QDomElement telement = tnode.toElement();
+ bool loadCheckForChildrenOK = false;
+ while( !telement.isNull() ) {
+ QString nodeName = telement.tagName();
+
+ if( nodeName == "textblocks" ) {
+
+ QDomNode node = telement.firstChild();
+ QDomElement element = node.toElement();
+
+ // if there is nothing to begin with, then we don't worry about it
+ loadCheckForChildrenOK = element.isNull() ? true : false;
+
+ while( !element.isNull() ) {
+ QString name = element.tagName();
+
+ if( name == "codecomment" ) {
+ CodeComment * block = new XMLCodeComment(this);
+ block->loadFromXMI(element);
+ if(!addTextBlock(block))
+ {
+ kError()<<"Unable to add codeComment to :"<<this<<endl;
+ block->deleteLater();
+ } else
+ loadCheckForChildrenOK= true;
+ } else
+ if( name == "codeaccessormethod" ||
+ name == "ccfdeclarationcodeblock"
+ ) {
+ QString acctag = element.attribute("tag","");
+ // search for our method in the
+ TextBlock * tb = findCodeClassFieldTextBlockByTag(acctag);
+ if(!tb || !addTextBlock(tb))
+ {
+ kError()<<"Unable to add codeclassfield child method to:"<<this<<endl;
+ // DON'T delete
+ } else
+ loadCheckForChildrenOK= true;
+
+ } else
+ if( name == "codeblock" ) {
+ CodeBlock * block = newCodeBlock();
+ block->loadFromXMI(element);
+ if(!addTextBlock(block))
+ {
+ kError()<<"Unable to add codeBlock to :"<<this<<endl;
+ block->deleteLater();
+ } else
+ loadCheckForChildrenOK= true;
+ } else
+ if( name == "codeblockwithcomments" ) {
+ CodeBlockWithComments * block = newCodeBlockWithComments();
+ block->loadFromXMI(element);
+ if(!addTextBlock(block))
+ {
+ kError()<<"Unable to add codeBlockwithcomments to:"<<this<<endl;
+ block->deleteLater();
+ } else
+ loadCheckForChildrenOK= true;
+ } else
+ if( name == "header" ) {
+ // do nothing.. this is treated elsewhere
+ } else
+ if( name == "hierarchicalcodeblock" ) {
+ HierarchicalCodeBlock * block = newHierarchicalCodeBlock();
+ block->loadFromXMI(element);
+ if(!addTextBlock(block))
+ {
+ kError()<<"Unable to add hierarchicalcodeBlock to:"<<this<<endl;
+ block->deleteLater();
+ } else
+ loadCheckForChildrenOK= true;
+ } else
+ if( name == "codeoperation" ) {
+ // find the code operation by id
+ QString id = element.attribute("parent_id","-1");
+ UMLObject * obj = UMLApp::app()->getDocument()->findObjectById(STR2ID(id));
+ UMLOperation * op = dynamic_cast<UMLOperation*>(obj);
+ if(op) {
+ CodeOperation * block = 0;
+ kError() << "TODO: implement CodeGenFactory::newCodeOperation() for JavaANTCodeDocument" << endl;
+ break; // remove when above is implemented
+ block->loadFromXMI(element);
+ if(addTextBlock(block))
+ loadCheckForChildrenOK= true;
+ else
+ {
+ kError()<<"Unable to add codeoperation to:"<<this<<endl;
+ block->deleteLater();
+ }
+ } else
+ kError()<<"Unable to find operation create codeoperation for:"<<this<<endl;
+ } else
+ if( name == "xmlelementblock" ) {
+ QString xmltag = element.attribute("nodeName","UNKNOWN");
+ XMLElementCodeBlock * block = new XMLElementCodeBlock(this,xmltag);
+ block->loadFromXMI(element);
+ if(!addTextBlock(block))
+ {
+ kError()<<"Unable to add XMLelement to Java ANT document:"<<this<<endl;
+ block->deleteLater();
+ } else
+ loadCheckForChildrenOK= true;
+ }
+ /*
+ // only needed for extreme debugging conditions (E.g. making new codeclassdocument loader)
+ else
+ kDebug()<<" LoadFromXMI: Got strange tag in text block stack:"<<name<<", ignorning"<<endl;
+ */
+
+ node = element.nextSibling();
+ element = node.toElement();
+ }
+ break;
+ }
+
+ tnode = telement.nextSibling();
+ telement = tnode.toElement();
+ }
+
+ if(!loadCheckForChildrenOK)
+ {
+ CodeDocument * test = dynamic_cast<CodeDocument*>(this);
+ if(test)
+ {
+ kWarning()<<" loadChildBlocks : unable to initialize any child blocks in doc: "<<test->getFileName()<<" "<<this<<endl;
+ } else {
+ HierarchicalCodeBlock * hb = dynamic_cast<HierarchicalCodeBlock*>(this);
+ if(hb)
+ kWarning()<<" loadChildBlocks : unable to initialize any child blocks in Hblock: "<<hb->getTag()<<" "<<this<<endl;
+ else
+ kDebug()<<" loadChildBlocks : unable to initialize any child blocks in UNKNOWN OBJ:"<<this<<endl;
+ }
+ }
+
+}
+
+/** set the class attributes of this object from
+ * the passed element node.
+ */
+void JavaANTCodeDocument::setAttributesFromNode ( QDomElement & root)
+{
+
+ // superclass save
+ CodeDocument::setAttributesFromNode(root);
+
+ // now set local attributes
+ // setPackage(root.attribute("package",""));
+
+}
+
+/**
+ * load params from the appropriate XMI element node.
+ */
+void JavaANTCodeDocument::loadFromXMI ( QDomElement & root ) {
+ setAttributesFromNode(root);
+}
+
+/** set attributes of the node that represents this class
+ * in the XMI document.
+ */
+void JavaANTCodeDocument::setAttributesOnNode ( QDomDocument & doc, QDomElement & docElement)
+{
+
+ // superclass call
+ CodeDocument::setAttributesOnNode(doc,docElement);
+
+ // now set local attributes/fields
+ //FIX
+}
+
+/**
+ * Save the XMI representation of this object
+ */
+void JavaANTCodeDocument::saveToXMI ( QDomDocument & doc, QDomElement & root ) {
+ QDomElement docElement = doc.createElement( "codedocument" );
+
+ setAttributesOnNode(doc, docElement);
+
+ root.appendChild( docElement );
+}
+
+// we add in our code blocks that describe how to generate
+// the project here...
+void JavaANTCodeDocument::updateContent( ) {
+ // FIX : fill in more content based on classes
+ // which exist
+ CodeBlockWithComments * xmlDecl = getCodeBlockWithComments("xmlDecl","",0);
+ xmlDecl->setText("<?xml version=\"1.0\"?>");
+ addTextBlock(xmlDecl);
+
+ XMLElementCodeBlock * rootNode = new XMLElementCodeBlock(this, "project", "Java ANT build document");
+ rootNode->setTag("projectDecl");
+ addTextBlock(rootNode);
+
+ // <project name="XDF" default="help" basedir=".">
+ //HierarchicalCodeBlock * projDecl = xmlDecl->getHierarchicalCodeBlock("projectDecl", "Java ANT build document", 1);
+
+ // set some global properties for the build
+ /*
+ <!-- set global properties for this build -->
+ <!-- paths -->
+ <property name="docApi.dir" value="docs/api"/>
+ <property name="path" value="gov/nasa/gsfc/adc/xdf"/>
+ <property name="src" value="src/${path}/"/>
+ <property name="top" value="."/>
+ <property name="build" value="${top}/gov"/>
+ <property name="buildDir" value="${path}"/>
+ <!-- compiler directives -->
+ <property name="build.compiler" value="modern"/>
+ <property name="useDeprecation" value="no"/>
+ <property name="jarname" value="${project}.jar"/>
+ */
+
+}
+
+// We overwritten by Java language implementation to get lowercase path
+QString JavaANTCodeDocument::getPath ( )
+{
+
+ QString path = getPackage();
+
+ // Replace all white spaces with blanks
+ path.simplifyWhiteSpace();
+
+ // Replace all blanks with underscore
+ path.replace(QRegExp(" "), "_");
+
+ path.replace(QRegExp("\\."),"/");
+ path.replace(QRegExp("::"), "/");
+
+ path.lower();
+
+ return path;
+
+}
+
+
+#include "javaantcodedocument.moc"
diff --git a/umbrello/umbrello/codegenerators/javaantcodedocument.h b/umbrello/umbrello/codegenerators/javaantcodedocument.h
new file mode 100644
index 00000000..9d7372f3
--- /dev/null
+++ b/umbrello/umbrello/codegenerators/javaantcodedocument.h
@@ -0,0 +1,100 @@
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * copyright (C) 2004-2006 *
+ * Umbrello UML Modeller Authors <uml-devel@uml.sf.net> *
+ ***************************************************************************/
+
+/* This code generated by:
+ * Author : thomas
+ * Date : Tue Jun 24 2003
+ */
+
+
+
+#ifndef JAVAANTCODEDOCUMENT_H
+#define JAVAANTCODEDOCUMENT_H
+
+#include <qstring.h>
+#include <qdom.h>
+
+#include "../codedocument.h"
+
+/**
+ * class JavaANTCodeDocument
+ * Represents
+ */
+
+class JavaANTCodeDocument : public CodeDocument
+{
+ Q_OBJECT
+public:
+
+ // Constructors/Destructors
+ //
+
+ /**
+ * Constructor
+ */
+ JavaANTCodeDocument ( );
+
+ /**
+ * Empty Destructor
+ */
+ virtual ~JavaANTCodeDocument ( );
+
+ QString getPath ( );
+
+ void updateContent();
+
+ /**
+ * Save the XMI representation of this object
+ */
+ virtual void saveToXMI ( QDomDocument & doc, QDomElement & root );
+
+ /**
+ * load params from the appropriate XMI element node.
+ */
+ virtual void loadFromXMI ( QDomElement & root );
+
+ /**
+ * create a new HierarchicalCodeBlock object belonging to this CodeDocument.
+ * @return HierarchicalCodeBlock
+ */
+ virtual HierarchicalCodeBlock * newHierarchicalCodeBlock ( );
+
+ /**
+ * create a new CodeBlockWithComments object belonging to this CodeDocument.
+ * @return CodeBlockWithComments
+ */
+ // virtual CodeBlockWithComments * newCodeBlockWithComments ( );
+
+protected:
+
+ /** set attributes of the node that represents this class
+ * in the XMI document.
+ */
+ virtual void setAttributesOnNode ( QDomDocument & doc, QDomElement & blockElement);
+
+ /** set the class attributes of this object from
+ * the passed element node.
+ */
+ virtual void setAttributesFromNode ( QDomElement & element);
+
+ /**
+ * need to overwrite this for java since we need to pick up the
+ * xml declaration blocks.
+ */
+ virtual void loadChildTextBlocksFromNode ( QDomElement & root);
+
+private:
+
+
+
+};
+
+#endif // JAVAANTCODEDOCUMENT_H
diff --git a/umbrello/umbrello/codegenerators/javaclassdeclarationblock.cpp b/umbrello/umbrello/codegenerators/javaclassdeclarationblock.cpp
new file mode 100644
index 00000000..0e4ccdbf
--- /dev/null
+++ b/umbrello/umbrello/codegenerators/javaclassdeclarationblock.cpp
@@ -0,0 +1,169 @@
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * copyright (C) 2004-2006 *
+ * Umbrello UML Modeller Authors <uml-devel@uml.sf.net> *
+ ***************************************************************************/
+
+/* This code generated by:
+ * Author : thomas
+ * Date : Wed Jul 16 2003
+ */
+#include "javaclassdeclarationblock.h"
+#include "javacodedocumentation.h"
+#include "../codegenerator.h"
+#include "../codegenerationpolicy.h"
+#include "../uml.h"
+
+// Constructors/Destructors
+//
+
+JavaClassDeclarationBlock::JavaClassDeclarationBlock
+ ( JavaClassifierCodeDocument * parentDoc, const QString &startText, const QString &endText, const QString &comment)
+ : OwnedHierarchicalCodeBlock(parentDoc->getParentClassifier(), parentDoc, startText, endText, comment)
+{
+ init(parentDoc, comment);
+}
+
+JavaClassDeclarationBlock::~JavaClassDeclarationBlock ( ) { }
+
+//
+// Methods
+//
+
+/**
+ * Save the XMI representation of this object
+ */
+void JavaClassDeclarationBlock::saveToXMI ( QDomDocument & doc, QDomElement & root ) {
+ QDomElement blockElement = doc.createElement( "javaclassdeclarationblock" );
+
+ setAttributesOnNode(doc, blockElement);
+
+ root.appendChild( blockElement );
+}
+
+/**
+ * load params from the appropriate XMI element node.
+ */
+void JavaClassDeclarationBlock::loadFromXMI ( QDomElement & root )
+{
+ setAttributesFromNode(root);
+}
+
+// Accessor methods
+//
+
+// Other methods
+//
+
+/**
+ * update the start and end text for this ownedhierarchicalcodeblock.
+ */
+void JavaClassDeclarationBlock::updateContent ( )
+{
+
+ JavaClassifierCodeDocument *parentDoc = dynamic_cast<JavaClassifierCodeDocument*>(getParentDocument());
+ UMLClassifier *c = parentDoc->getParentClassifier();
+ CodeGenerationPolicy *commonPolicy = UMLApp::app()->getCommonPolicy();
+ QString endLine = commonPolicy->getNewLineEndingChars();
+ bool isInterface = parentDoc->parentIsInterface(); // a little shortcut
+ QString JavaClassName = parentDoc->getJavaClassName(c->getName());
+
+ // COMMENT
+ if(isInterface)
+ getComment()->setText("Interface "+JavaClassName+endLine+c->getDoc());
+ else
+ getComment()->setText("Class "+JavaClassName+endLine+c->getDoc());
+
+ bool forceDoc = UMLApp::app()->getCommonPolicy()->getCodeVerboseDocumentComments();
+ if(forceDoc || !c->getDoc().isEmpty())
+ getComment()->setWriteOutText(true);
+ else
+ getComment()->setWriteOutText(false);
+
+
+ // Now set START/ENDING Text
+ QString startText = "";
+ // In Java, we need declare abstract only on classes
+ if (c->getAbstract() && !isInterface)
+ startText.append("abstract ");
+
+ if (c->getVisibility() != Uml::Visibility::Public) {
+ // We should probably emit a warning in here .. java doesn't like to allow
+ // private/protected classes. The best we can do (I believe)
+ // is to let these declarations default to "package visibility"
+ // which is a level between traditional "private" and "protected"
+ // scopes. To get this visibility level we just print nothing..
+ } else
+ startText.append("public ");
+
+ if(parentDoc->parentIsInterface())
+ startText.append("interface ");
+ else
+ startText.append("class ");
+
+ startText.append(JavaClassName);
+
+ // write inheritances out
+ UMLClassifierList superclasses =
+ c->findSuperClassConcepts(UMLClassifier::CLASS);
+ UMLClassifierList superinterfaces =
+ c->findSuperClassConcepts(UMLClassifier::INTERFACE);
+ int nrof_superclasses = superclasses.count();
+ int nrof_superinterfaces = superinterfaces.count();
+
+ // write out inheritance
+ int i = 0;
+ if(nrof_superclasses >0)
+ startText.append(" extends ");
+ for (UMLClassifier * concept= superclasses.first(); concept; concept = superclasses.next())
+ {
+ startText.append(parentDoc->cleanName(concept->getName()));
+ if(i != (nrof_superclasses-1))
+ startText.append(", ");
+ i++;
+ }
+
+ // write out what we 'implement'
+ i = 0;
+ if(nrof_superinterfaces >0)
+ {
+ // In Java interfaces "extend" other interfaces. Classes "implement" interfaces
+ if(isInterface)
+ startText.append(" extends ");
+ else
+ startText.append(" implements ");
+ }
+ for (UMLClassifier * concept= superinterfaces.first(); concept; concept = superinterfaces.next())
+ {
+ startText.append(parentDoc->cleanName(concept->getName()));
+ if(i != (nrof_superinterfaces-1))
+ startText.append(", ");
+ i++;
+ }
+
+ // Set the header and end text for the hier.codeblock
+ setStartText(startText+" {");
+
+ // setEndText("}"); // not needed
+
+}
+
+void JavaClassDeclarationBlock::init (JavaClassifierCodeDocument *parentDoc, const QString &comment)
+{
+
+ setComment(new JavaCodeDocumentation(parentDoc));
+ getComment()->setText(comment);
+
+ setEndText("}");
+
+ updateContent();
+
+}
+
+
+#include "javaclassdeclarationblock.moc"
diff --git a/umbrello/umbrello/codegenerators/javaclassdeclarationblock.h b/umbrello/umbrello/codegenerators/javaclassdeclarationblock.h
new file mode 100644
index 00000000..136df809
--- /dev/null
+++ b/umbrello/umbrello/codegenerators/javaclassdeclarationblock.h
@@ -0,0 +1,66 @@
+
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the 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 code generated by:
+ * Author : thomas
+ * Date : Wed Jul 16 2003
+ */
+
+#ifndef JAVACLASSDECLARATIONBLOCK_H
+#define JAVACLASSDECLARATIONBLOCK_H
+
+#include <qstring.h>
+
+#include "javaclassifiercodedocument.h"
+#include "../ownedhierarchicalcodeblock.h"
+
+class JavaClassDeclarationBlock : public OwnedHierarchicalCodeBlock
+{
+ Q_OBJECT
+public:
+
+ // Constructors/Destructors
+ //
+
+ /**
+ * Empty Constructor
+ */
+ explicit JavaClassDeclarationBlock ( JavaClassifierCodeDocument * parentDoc, const QString &start = "", const QString &endText = "}", const QString &comment = "");
+
+ /**
+ * Empty Destructor
+ */
+ virtual ~JavaClassDeclarationBlock ( );
+
+ /**
+ * Save the XMI representation of this object
+ */
+ virtual void saveToXMI ( QDomDocument & doc, QDomElement & root );
+
+ /**
+ * load params from the appropriate XMI element node.
+ */
+ virtual void loadFromXMI ( QDomElement & root );
+
+protected:
+
+ /**
+ * Update the start/end text of this codeblock.
+ */
+ void updateContent ( );
+
+private:
+
+ void init (JavaClassifierCodeDocument * parent, const QString &comment);
+
+};
+
+#endif // JAVACLASSDECLARATIONBLOCK_H
diff --git a/umbrello/umbrello/codegenerators/javaclassifiercodedocument.cpp b/umbrello/umbrello/codegenerators/javaclassifiercodedocument.cpp
new file mode 100644
index 00000000..44e6f242
--- /dev/null
+++ b/umbrello/umbrello/codegenerators/javaclassifiercodedocument.cpp
@@ -0,0 +1,583 @@
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * copyright (C) 2004-2007 *
+ * Umbrello UML Modeller Authors <uml-devel@uml.sf.net> *
+ ***************************************************************************/
+
+/* This code generated by:
+ * Author : thomas
+ * Date : Mon Jun 23 2003
+ */
+
+/**
+ We carve the Java document up into sections as follows:
+
+ * header
+ * package declaration
+ * import statements
+ * class declaration
+ * guts of the class (e.g. field decl, accessor methods, operations, dependant classes)
+*/
+
+// own header
+#include "javaclassifiercodedocument.h"
+
+// qt/kde includes
+#include <kdebug.h>
+#include <qregexp.h>
+
+// local includes
+#include "javacodegenerator.h"
+#include "javacodecomment.h"
+#include "javaclassdeclarationblock.h"
+#include "javacodeclassfielddeclarationblock.h"
+#include "codegen_utils.h"
+#include "../classifier.h"
+#include "../codegenerationpolicy.h"
+#include "../uml.h"
+
+// Constructors/Destructors
+//
+
+JavaClassifierCodeDocument::JavaClassifierCodeDocument ( UMLClassifier * concept )
+ : ClassifierCodeDocument (concept) {
+ init();
+}
+
+JavaClassifierCodeDocument::~JavaClassifierCodeDocument ( ) { }
+
+//
+// Methods
+//
+
+// Accessor methods
+//
+
+// Make it easier on ourselves
+JavaCodeGenerationPolicy * JavaClassifierCodeDocument::getJavaPolicy() {
+ CodeGenPolicyExt *pe = UMLApp::app()->getPolicyExt();
+ JavaCodeGenerationPolicy * policy = dynamic_cast<JavaCodeGenerationPolicy*>(pe);
+ return policy;
+}
+
+/**
+ * Get the dialog widget which allows user interaction with the object parameters.
+ * @return CodeDocumentDialog
+ */
+/*
+CodeDocumentDialog JavaClassifierCodeDocument::getDialog ( ) {
+
+}
+*/
+
+bool JavaClassifierCodeDocument::forceDoc () {
+ return UMLApp::app()->getCommonPolicy()->getCodeVerboseDocumentComments();
+}
+
+// We overwritten by Java language implementation to get lowercase path
+QString JavaClassifierCodeDocument::getPath ( )
+{
+
+ QString path = getPackage();
+
+ // Replace all white spaces with blanks
+ path.simplifyWhiteSpace();
+
+ // Replace all blanks with underscore
+ path.replace(QRegExp(" "), "_");
+
+ path.replace(QRegExp("\\."),"/");
+ path.replace(QRegExp("::"), "/");
+
+ path.lower();
+
+ return path;
+
+}
+
+
+// Other methods
+//
+
+QString JavaClassifierCodeDocument::getJavaClassName (const QString &name) {
+ return Codegen_Utils::capitalizeFirstLetter(CodeGenerator::cleanName(name));
+}
+
+// Initialize this java classifier code document
+void JavaClassifierCodeDocument::init ( ) {
+
+ setFileExtension(".java");
+
+ //initCodeClassFields(); // this is dubious because it calls down to
+ // CodeGenFactory::newCodeClassField(this)
+ // but "this" is still in construction at that time.
+
+ classDeclCodeBlock = 0;
+ operationsBlock = 0;
+ constructorBlock = 0;
+
+ // this will call updateContent() as well as other things that sync our document.
+ synchronize();
+}
+
+/**
+ * @param op
+ */
+// in the vannilla version, we just tack all operations on the end
+// of the document
+bool JavaClassifierCodeDocument::addCodeOperation (CodeOperation * op ) {
+
+ if(!op->getParentOperation()->isLifeOperation())
+ return operationsBlock->addTextBlock(op);
+ else
+ return constructorBlock->addTextBlock(op);
+}
+
+// Sigh. NOT optimal. The only reason that we need to have this
+// is so we can create the JavaClassDeclarationBlock.
+// would be better if we could create a handler interface that each
+// codeblock used so all we have to do here is add the handler
+// for "javaclassdeclarationblock"
+void JavaClassifierCodeDocument::loadChildTextBlocksFromNode ( QDomElement & root)
+{
+
+ QDomNode tnode = root.firstChild();
+ QDomElement telement = tnode.toElement();
+ bool loadCheckForChildrenOK = false;
+ while( !telement.isNull() ) {
+ QString nodeName = telement.tagName();
+
+ if( nodeName == "textblocks" ) {
+
+ QDomNode node = telement.firstChild();
+ QDomElement element = node.toElement();
+
+ // if there is nothing to begin with, then we don't worry about it
+ loadCheckForChildrenOK = element.isNull() ? true : false;
+
+ while( !element.isNull() ) {
+ QString name = element.tagName();
+
+ if( name == "codecomment" ) {
+ CodeComment * block = new JavaCodeComment(this);
+ block->loadFromXMI(element);
+ if(!addTextBlock(block))
+ {
+ kError()<<"loadFromXMI : unable to add codeComment to :"<<this<<endl;
+ block->deleteLater();
+ } else
+ loadCheckForChildrenOK= true;
+ } else
+ if( name == "codeaccessormethod" ||
+ name == "ccfdeclarationcodeblock"
+ ) {
+ QString acctag = element.attribute("tag","");
+ // search for our method in the
+ TextBlock * tb = findCodeClassFieldTextBlockByTag(acctag);
+ if(!tb || !addTextBlock(tb))
+ {
+ kError()<<"loadFromXMI : unable to add codeclassfield child method to:"<<this<<endl;
+ // DON'T delete
+ } else
+ loadCheckForChildrenOK= true;
+
+ } else
+ if( name == "codeblock" ) {
+ CodeBlock * block = newCodeBlock();
+ block->loadFromXMI(element);
+ if(!addTextBlock(block))
+ {
+ kError()<<"loadFromXMI : unable to add codeBlock to :"<<this<<endl;
+ block->deleteLater();
+ } else
+ loadCheckForChildrenOK= true;
+ } else
+ if( name == "codeblockwithcomments" ) {
+ CodeBlockWithComments * block = newCodeBlockWithComments();
+ block->loadFromXMI(element);
+ if(!addTextBlock(block))
+ {
+ kError()<<"loadFromXMI : unable to add codeBlockwithcomments to:"<<this<<endl;
+ block->deleteLater();
+ } else
+ loadCheckForChildrenOK= true;
+ } else
+ if( name == "header" ) {
+ // do nothing.. this is treated elsewhere
+ } else
+ if( name == "hierarchicalcodeblock" ) {
+ HierarchicalCodeBlock * block = newHierarchicalCodeBlock();
+ block->loadFromXMI(element);
+ if(!addTextBlock(block))
+ {
+ kError()<<"Unable to add hierarchicalcodeBlock to:"<<this<<endl;
+ block->deleteLater();
+ } else
+ loadCheckForChildrenOK= true;
+ } else
+ if( name == "codeoperation" ) {
+ // find the code operation by id
+ QString id = element.attribute("parent_id","-1");
+ UMLObject * obj = UMLApp::app()->getDocument()->findObjectById(STR2ID(id));
+ UMLOperation * op = dynamic_cast<UMLOperation*>(obj);
+ if(op) {
+ CodeOperation * block = new JavaCodeOperation(this, op);
+ block->loadFromXMI(element);
+ if(addTextBlock(block))
+ loadCheckForChildrenOK= true;
+ else
+ {
+ kError()<<"Unable to add codeoperation to:"<<this<<endl;
+ block->deleteLater();
+ }
+ } else
+ kError()<<"Unable to find operation create codeoperation for:"<<this<<endl;
+ } else
+ if( name == "javaclassdeclarationblock" )
+ {
+ JavaClassDeclarationBlock * block = getClassDecl();
+ block->loadFromXMI(element);
+ if(!addTextBlock(block))
+ {
+ kError()<<"Unable to add java code declaration block to:"<<this<<endl;
+ // DON'T delete.
+ // block->deleteLater();
+ } else
+ loadCheckForChildrenOK= true;
+ }
+ // This last item is only needed for extreme debugging conditions
+ // (E.g. making new codeclassdocument loader)
+ // else
+ // kDebug()<<" LoadFromXMI: Got strange tag in text block stack:"<<name<<", ignorning"<<endl;
+
+ node = element.nextSibling();
+ element = node.toElement();
+ }
+ break;
+ }
+
+ tnode = telement.nextSibling();
+ telement = tnode.toElement();
+ }
+
+ if(!loadCheckForChildrenOK)
+ {
+ CodeDocument * test = dynamic_cast<CodeDocument*>(this);
+ if(test)
+ {
+ kWarning()<<" loadChildBlocks : unable to initialize any child blocks in doc: "<<test->getFileName()<<" "<<this<<endl;
+ } else {
+ HierarchicalCodeBlock * hb = dynamic_cast<HierarchicalCodeBlock*>(this);
+ if(hb)
+ kWarning()<<" loadChildBlocks : unable to initialize any child blocks in Hblock: "<<hb->getTag()<<" "<<this<<endl;
+ else
+ kDebug()<<" loadChildBlocks : unable to initialize any child blocks in UNKNOWN OBJ:"<<this<<endl;
+ }
+ }
+
+
+}
+
+QString JavaClassifierCodeDocument::scopeToJavaDecl(Uml::Visibility scope)
+{
+ QString scopeString;
+ switch(scope)
+ {
+ case Uml::Visibility::Public:
+ scopeString = "public";
+ break;
+ case Uml::Visibility::Protected:
+ scopeString = "protected";
+ break;
+ case Uml::Visibility::Private:
+ case Uml::Visibility::Implementation:
+ default:
+ scopeString = "private";
+ break;
+ }
+ return scopeString;
+}
+
+JavaClassDeclarationBlock * JavaClassifierCodeDocument::getClassDecl()
+{
+ if(!classDeclCodeBlock)
+ {
+ classDeclCodeBlock = new JavaClassDeclarationBlock (this);
+ classDeclCodeBlock->setTag("ClassDeclBlock");
+ }
+ return classDeclCodeBlock;
+}
+
+void JavaClassifierCodeDocument::resetTextBlocks()
+{
+
+ // all special pointers to text blocks need to be zero'd out
+ operationsBlock = 0;
+ constructorBlock = 0;
+ classDeclCodeBlock = 0;
+
+ // now do traditional release of text blocks.
+ ClassifierCodeDocument::resetTextBlocks();
+}
+
+// This method will cause the class to rebuild its text representation.
+// based on the parent classifier object.
+// For any situation in which this is called, we are either building the code
+// document up, or replacing/regenerating the existing auto-generated parts. As
+// such, we will want to insert everything we resonablely will want
+// during creation. We can set various parts of the document (esp. the
+// comments) to appear or not, as needed.
+void JavaClassifierCodeDocument::updateContent( )
+{
+ // Gather info on the various fields and parent objects of this class...
+ UMLClassifier * c = getParentClassifier();
+ CodeGenerationPolicy * commonPolicy = UMLApp::app()->getCommonPolicy();
+ CodeGenPolicyExt * pe = UMLApp::app()->getPolicyExt();
+ JavaCodeGenerationPolicy * policy = dynamic_cast<JavaCodeGenerationPolicy*>(pe);
+
+ // first, set the global flag on whether or not to show classfield info
+ // This depends on whether or not we have attribute/association classes
+ CodeClassFieldList * cfList = getCodeClassFieldList();
+ for(CodeClassField * field = cfList->first(); field; field = cfList->next())
+ if(field->parentIsAttribute())
+ field->setWriteOutMethods(policy->getAutoGenerateAttribAccessors());
+ else
+ field->setWriteOutMethods(policy->getAutoGenerateAssocAccessors());
+
+ // attribute-based ClassFields
+ // we do it this way to have the static fields sorted out from regular ones
+ CodeClassFieldList staticAttribClassFields = getSpecificClassFields (CodeClassField::Attribute, true);
+ CodeClassFieldList attribClassFields = getSpecificClassFields (CodeClassField::Attribute, false);
+ // association-based ClassFields
+ // don't care if they are static or not..all are lumped together
+ CodeClassFieldList plainAssocClassFields = getSpecificClassFields ( CodeClassField::PlainAssociation );
+ CodeClassFieldList aggregationClassFields = getSpecificClassFields ( CodeClassField::Aggregation );
+ CodeClassFieldList compositionClassFields = getSpecificClassFields ( CodeClassField::Composition );
+
+ bool isInterface = parentIsInterface();
+ bool hasOperationMethods = c->getOpList().last() ? true : false;
+ QString endLine = commonPolicy->getNewLineEndingChars(); // a shortcut..so we don't have to call this all the time
+
+ //
+ // START GENERATING CODE/TEXT BLOCKS and COMMENTS FOR THE DOCUMENT
+ //
+
+ //
+ // PACKAGE CODE BLOCK
+ //
+ QString pkgs = getPackage();
+ pkgs.replace(QRegExp("::"), ".");
+ QString packageText = getPackage().isEmpty() ? "" : "package "+pkgs+';'+endLine;
+ CodeBlockWithComments * pblock = addOrUpdateTaggedCodeBlockWithComments("packages", packageText, "", 0, false);
+ if(packageText.isEmpty() && pblock->getContentType() == CodeBlock::AutoGenerated)
+ pblock->setWriteOutText(false);
+ else
+ pblock->setWriteOutText(true);
+
+ // IMPORT CODEBLOCK
+ //
+ // Q: Why all utils? Isnt just List and Vector the only classes we are using?
+ // A: doesn't matter at all; its more readable to just include '*' and java compilers
+ // don't slow down or anything. (TZ)
+ QString importStatement = "";
+ if ( hasObjectVectorClassFields() )
+ importStatement.append("import java.util.*;");
+
+ //only import classes in a different package from this class
+ UMLPackageList imports;
+ QMap<UMLPackage*, QString> packageMap; // so we don't repeat packages
+
+ CodeGenerator::findObjectsRelated(c,imports);
+ for(UMLPackage *con = imports.first(); con ; con = imports.next())
+ // NO (default) datatypes in the import statement.. use defined
+ // ones whould be possible, but no idea how to do that...at least for now.
+ // Dynamic casting is slow..not an optimal way to do this.
+ if (!packageMap.contains(con) && con->getBaseType() != Uml::ot_Datatype)
+ {
+ packageMap.insert(con, con->getPackage());
+
+ // now, we DON'T need to import classes that are already in our own package
+ // (that is, IF a package is specified). Otherwise, we should have a declaration.
+ if (con->getPackage() != c->getPackage() ||
+ (c->getPackage().isEmpty() && con->getPackage().isEmpty()))
+ {
+ importStatement.append(endLine+"import ");
+ if(!con->getPackage().isEmpty())
+ importStatement.append(con->getPackage()+'.');
+ importStatement.append(CodeGenerator::cleanName(con->getName())+';');
+ }
+ }
+ // now, add/update the imports codeblock
+ CodeBlockWithComments * iblock = addOrUpdateTaggedCodeBlockWithComments("imports", importStatement, "", 0, false);
+ if(importStatement.isEmpty() && iblock->getContentType() == CodeBlock::AutoGenerated)
+ iblock->setWriteOutText(false);
+ else
+ iblock->setWriteOutText(true);
+
+ // CLASS DECLARATION BLOCK
+ //
+
+ // get the declaration block. If its not already present, add it too
+ JavaClassDeclarationBlock * myClassDeclCodeBlock = getClassDecl();
+ addTextBlock(myClassDeclCodeBlock); // note: wont add if already present
+
+ // NOW create document in sections..
+ // now we want to populate the body of our class
+ // our layout is the following general groupings of code blocks:
+
+ // start java classifier document
+
+ // header comment
+
+ // package code block
+
+ // import code block
+
+ // class declaration
+
+ // section:
+ // - class field declaration section comment
+ // - class field declarations (0+ codeblocks)
+
+ // section:
+ // - methods section comment
+
+ // sub-section: constructor ops
+ // - constructor method section comment
+ // - constructor methods (0+ codeblocks)
+
+ // sub-section: accessors
+ // - accessor method section comment
+ // - static accessor methods (0+ codeblocks)
+ // - non-static accessor methods (0+ codeblocks)
+
+ // sub-section: non-constructor ops
+ // - operation method section comment
+ // - operations (0+ codeblocks)
+
+ // end class declaration
+
+ // end java classifier document
+
+
+ // Q: Why use the more complicated scheme of arranging code blocks within codeblocks?
+ // A: This will allow us later to preserve the format of our document so that if
+ // codeblocks are added, they may be easily added in the correct place, rather than at
+ // the end of the document, or by using a difficult algorithm to find the location of
+ // the last appropriate code block sibling (which may not exist.. for example user adds
+ // a constructor operation, but there currently are no constructor code blocks
+ // within the document).
+
+ //
+ // * CLASS FIELD declaration section
+ //
+
+ // get/create the field declaration code block
+ HierarchicalCodeBlock * fieldDeclBlock = myClassDeclCodeBlock->getHierarchicalCodeBlock("fieldsDecl", "Fields", 1);
+
+ // Update the comment: we only set comment to appear under the following conditions
+ CodeComment * fcomment = fieldDeclBlock->getComment();
+ if (isInterface || (!forceDoc() && !hasClassFields()) )
+ fcomment->setWriteOutText(false);
+ else
+ fcomment->setWriteOutText(true);
+
+ // now actually declare the fields within the appropriate HCodeBlock
+ declareClassFields(staticAttribClassFields, fieldDeclBlock);
+ declareClassFields(attribClassFields, fieldDeclBlock);
+ declareClassFields(plainAssocClassFields, fieldDeclBlock);
+ declareClassFields(aggregationClassFields, fieldDeclBlock);
+ declareClassFields(compositionClassFields, fieldDeclBlock);
+
+ //
+ // METHODS section
+ //
+
+ // get/create the method codeblock
+ HierarchicalCodeBlock * methodsBlock = myClassDeclCodeBlock->getHierarchicalCodeBlock("methodsBlock", "Methods", 1);
+
+ // Update the section comment
+ CodeComment * methodsComment = methodsBlock->getComment();
+ // set conditions for showing this comment
+ if (!forceDoc() && !hasClassFields() && !hasOperationMethods)
+ methodsComment->setWriteOutText(false);
+ else
+ methodsComment->setWriteOutText(true);
+
+ // METHODS sub-section : constructor methods
+ //
+
+ // get/create the constructor codeblock
+ HierarchicalCodeBlock * constBlock = methodsBlock->getHierarchicalCodeBlock("constructorMethods", "Constructors", 1);
+ constructorBlock = constBlock; // record this codeblock for later, when operations are updated
+
+ // special condiions for showing comment: only when autogenerateding empty constructors
+ // Although, we *should* check for other constructor methods too
+ CodeComment * constComment = constBlock->getComment();
+ CodeGenerationPolicy *pol = UMLApp::app()->getCommonPolicy();
+ if (!forceDoc() && (isInterface || !pol->getAutoGenerateConstructors()))
+ constComment->setWriteOutText(false);
+ else
+ constComment->setWriteOutText(true);
+
+ // add/get the empty constructor
+ QString JavaClassName = getJavaClassName(c->getName());
+ QString emptyConstStatement = "public "+JavaClassName+" ( ) { }";
+ CodeBlockWithComments * emptyConstBlock =
+ constBlock->addOrUpdateTaggedCodeBlockWithComments("emptyconstructor", emptyConstStatement, "Empty Constructor", 1, false);
+ // Now, as an additional condition we only show the empty constructor block
+ // IF it was desired to be shown
+ if(parentIsClass() && pol->getAutoGenerateConstructors())
+ emptyConstBlock->setWriteOutText(true);
+ else
+ emptyConstBlock->setWriteOutText(false);
+
+ // METHODS subsection : ACCESSOR METHODS
+ //
+
+ // get/create the accessor codeblock
+ HierarchicalCodeBlock * accessorBlock = methodsBlock->getHierarchicalCodeBlock("accessorMethods", "Accessor Methods", 1);
+
+ // set conditions for showing section comment
+ CodeComment * accessComment = accessorBlock->getComment();
+ if (!forceDoc() && !hasClassFields())
+ accessComment->setWriteOutText(false);
+ else
+ accessComment->setWriteOutText(true);
+
+ // now, 2 sub-sub sections in accessor block
+ // add/update accessor methods for attributes
+ HierarchicalCodeBlock * staticAccessors = accessorBlock->getHierarchicalCodeBlock("staticAccessorMethods", "", 1);
+ staticAccessors->getComment()->setWriteOutText(false); // never write block comment
+ staticAccessors->addCodeClassFieldMethods(staticAttribClassFields);
+ staticAccessors->addCodeClassFieldMethods(attribClassFields);
+
+ // add/update accessor methods for associations
+ HierarchicalCodeBlock * regularAccessors = accessorBlock->getHierarchicalCodeBlock("regularAccessorMethods", "", 1);
+ regularAccessors->getComment()->setWriteOutText(false); // never write block comment
+ regularAccessors->addCodeClassFieldMethods(plainAssocClassFields);
+ regularAccessors->addCodeClassFieldMethods(aggregationClassFields);
+ regularAccessors->addCodeClassFieldMethods(compositionClassFields);
+
+ // METHODS subsection : Operation methods (which arent constructors)
+ //
+
+ // get/create the operations codeblock
+ operationsBlock = methodsBlock->getHierarchicalCodeBlock("operationMethods", "Operations", 1);
+
+ // set conditions for showing section comment
+ CodeComment * ocomment = operationsBlock->getComment();
+ if (!forceDoc() && !hasOperationMethods )
+ ocomment->setWriteOutText(false);
+ else
+ ocomment->setWriteOutText(true);
+
+}
+
+
+#include "javaclassifiercodedocument.moc"
diff --git a/umbrello/umbrello/codegenerators/javaclassifiercodedocument.h b/umbrello/umbrello/codegenerators/javaclassifiercodedocument.h
new file mode 100644
index 00000000..ddad6e1a
--- /dev/null
+++ b/umbrello/umbrello/codegenerators/javaclassifiercodedocument.h
@@ -0,0 +1,110 @@
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * copyright (C) 2004-2006 *
+ * Umbrello UML Modeller Authors <uml-devel@uml.sf.net> *
+ ***************************************************************************/
+
+/* This code generated by:
+ * Author : thomas
+ * Date : Mon Jun 23 2003
+ */
+
+
+
+#ifndef JAVACLASSIFIERCODEDOCUMENT_H
+#define JAVACLASSIFIERCODEDOCUMENT_H
+
+#include <qstring.h>
+
+#include "../codeclassfieldlist.h"
+#include "../classifiercodedocument.h"
+#include "../classifier.h"
+#include "../hierarchicalcodeblock.h"
+#include "classifierinfo.h"
+#include "javacodeclassfield.h"
+#include "javacodeoperation.h"
+
+class JavaClassDeclarationBlock;
+class JavaCodeGenerationPolicy;
+
+/**
+ * class JavaClassifierCodeDocument
+ * A Java UMLClassifier Code Document.
+ */
+
+class JavaClassifierCodeDocument : public ClassifierCodeDocument
+{
+ Q_OBJECT
+public:
+
+ // Constructors/Destructors
+ //
+
+
+ /**
+ * Constructor
+ */
+ JavaClassifierCodeDocument (UMLClassifier * classifier);
+
+ /**
+ * Empty Destructor
+ */
+ virtual ~JavaClassifierCodeDocument ( );
+
+ /**
+ * Get the dialog widget which allows user interaction with the object parameters.
+ * @return CodeDocumentDialog
+ */
+ //CodeDocumentDialog getDialog ( );
+
+ QString scopeToJavaDecl(Uml::Visibility scope);
+
+ // Make it easier on ourselves
+ JavaCodeGenerationPolicy * getJavaPolicy();
+
+ QString getJavaClassName (const QString &name);
+
+ QString getPath();
+
+ /** add a code operation to this java classifier code document.
+ * @return bool which is true IF the code operation was added successfully
+ */
+ bool addCodeOperation (CodeOperation * op );
+
+protected:
+
+ // reset/clear our inventory of textblocks in this document
+ void resetTextBlocks();
+
+ /**
+ * need to overwrite this for java since we need to pick up the
+ * java class declaration block.
+ */
+ virtual void loadChildTextBlocksFromNode ( QDomElement & root);
+
+ void addOrUpdateCodeClassFieldMethodsInCodeBlock(CodeClassFieldList &list, JavaClassDeclarationBlock * codeBlock);
+
+ bool forceDoc ();
+
+ void updateContent();
+
+private:
+
+ JavaClassDeclarationBlock * classDeclCodeBlock;
+ HierarchicalCodeBlock * constructorBlock;
+ HierarchicalCodeBlock * operationsBlock;
+
+ ClassifierInfo * info;
+
+ void init ( );
+ JavaClassDeclarationBlock * getClassDecl();
+
+
+};
+
+#endif // JAVACLASSIFIERCODEDOCUMENT_H
diff --git a/umbrello/umbrello/codegenerators/javacodeaccessormethod.cpp b/umbrello/umbrello/codegenerators/javacodeaccessormethod.cpp
new file mode 100644
index 00000000..524e6a48
--- /dev/null
+++ b/umbrello/umbrello/codegenerators/javacodeaccessormethod.cpp
@@ -0,0 +1,223 @@
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * copyright (C) 2004-2007 *
+ * Umbrello UML Modeller Authors <uml-devel@uml.sf.net> *
+ ***************************************************************************/
+
+/* This code generated by:
+ * Author : thomas
+ * Date : Fri Jun 20 2003
+ */
+
+// own header
+#include "javacodeaccessormethod.h"
+
+// qt/kde includes
+#include <kdebug.h>
+
+// local includes
+#include "../attribute.h"
+#include "../codegenerator.h"
+#include "../codegenerationpolicy.h"
+#include "../classifiercodedocument.h"
+#include "../umlobject.h"
+#include "../umlrole.h"
+#include "../uml.h"
+#include "codegen_utils.h"
+#include "javaclassifiercodedocument.h"
+#include "javacodegenerationpolicy.h"
+#include "javacodeclassfield.h"
+#include "javacodedocumentation.h"
+
+// Constructors/Destructors
+//
+
+JavaCodeAccessorMethod::JavaCodeAccessorMethod ( CodeClassField * field, CodeAccessorMethod::AccessorType type)
+ : CodeAccessorMethod ( field )
+{
+ setType(type);
+
+ // lets use full-blown comment
+ JavaClassifierCodeDocument* jccd = dynamic_cast<JavaClassifierCodeDocument*>(field->getParentDocument());
+ setComment(new JavaCodeDocumentation(jccd));
+}
+
+JavaCodeAccessorMethod::~JavaCodeAccessorMethod ( ) { }
+
+// Other methods
+//
+
+void JavaCodeAccessorMethod::setAttributesOnNode ( QDomDocument & doc, QDomElement & blockElement)
+{
+
+ // set super-class attributes
+ CodeAccessorMethod::setAttributesOnNode(doc, blockElement);
+
+ // set local attributes now
+}
+
+void JavaCodeAccessorMethod::setAttributesFromNode( QDomElement & root)
+{
+
+ // set attributes from superclass method the XMI
+ CodeAccessorMethod::setAttributesFromNode(root);
+
+ // load local stuff
+
+}
+
+void JavaCodeAccessorMethod::updateContent( )
+{
+
+ CodeClassField * parentField = getParentClassField();
+ JavaCodeClassField * javafield = dynamic_cast<JavaCodeClassField*>(parentField);
+ QString fieldName = javafield->getFieldName();
+
+ QString text = "";
+ switch(getType()) {
+ case CodeAccessorMethod::ADD:
+ {
+ int maxOccurs = javafield->maximumListOccurances();
+ QString fieldType = javafield->getTypeName();
+ QString indent = getIndentation();
+ QString endLine = UMLApp::app()->getCommonPolicy()->getNewLineEndingChars();
+ if(maxOccurs > 0)
+ text += "if ("+fieldName+".size() < "+ QString::number(maxOccurs)+") {"+endLine+indent;
+ text += fieldName+".add(value);";
+ if(maxOccurs > 0)
+ {
+ text += endLine+"} else {"+endLine;
+ text += indent + "System.err.println(\"ERROR: Cant add"+fieldType+" to "+fieldName+", minimum number of items reached.\");"+endLine+'}'+endLine;
+ }
+ break;
+ }
+ case CodeAccessorMethod::GET:
+ text = "return "+fieldName+';';
+ break;
+ case CodeAccessorMethod::LIST:
+ text = "return (List) "+fieldName+';';
+ break;
+ case CodeAccessorMethod::REMOVE:
+ {
+ int minOccurs = javafield->minimumListOccurances();
+ QString fieldType = javafield->getTypeName();
+ QString endLine = UMLApp::app()->getCommonPolicy()->getNewLineEndingChars();
+ QString indent = getIndentation();
+
+ if(minOccurs > 0)
+ text += "if ("+fieldName+".size() >= "+ QString::number(minOccurs)+") {"+endLine+indent;
+ text += fieldName+".remove(value);";
+ if(minOccurs > 0)
+ {
+ text += endLine+"} else {"+endLine;
+ text += indent + "System.err.println(\"ERROR: Cant remove"+fieldType+" from "+fieldName+", minimum number of items reached.\");"+endLine+'}'+endLine;
+ }
+ break;
+ }
+ case CodeAccessorMethod::SET:
+ text = fieldName+" = value;";
+ break;
+ default:
+ // do nothing
+ break;
+ }
+
+ setText(text);
+
+}
+
+void JavaCodeAccessorMethod::updateMethodDeclaration()
+{
+
+ JavaCodeClassField * javafield = dynamic_cast<JavaCodeClassField*>(getParentClassField());
+ JavaClassifierCodeDocument * javadoc = dynamic_cast<JavaClassifierCodeDocument*>(javafield->getParentDocument());
+ CodeGenerationPolicy *commonpolicy = UMLApp::app()->getCommonPolicy();
+
+ // gather defs
+ CodeGenerationPolicy::ScopePolicy scopePolicy = commonpolicy->getAttributeAccessorScope();
+ QString strVis = javadoc->scopeToJavaDecl(javafield->getVisibility());
+ QString fieldName = javafield->getFieldName();
+ QString fieldType = javafield->getTypeName();
+ QString objectType = javafield->getListObjectType();
+ if(objectType.isEmpty())
+ objectType = fieldName;
+ QString endLine = UMLApp::app()->getCommonPolicy()->getNewLineEndingChars();
+
+ // set scope of this accessor appropriately..if its an attribute,
+ // we need to be more sophisticated
+ if(javafield->parentIsAttribute())
+ switch (scopePolicy) {
+ case CodeGenerationPolicy::Public:
+ case CodeGenerationPolicy::Private:
+ case CodeGenerationPolicy::Protected:
+ strVis = javadoc->scopeToJavaDecl((Uml::Visibility::Value) scopePolicy);
+ break;
+ default:
+ case CodeGenerationPolicy::FromParent:
+ // do nothing..already have taken parent value
+ break;
+ }
+
+ // some variables we will need to populate
+ QString headerText = "";
+ QString methodReturnType = "";
+ QString methodName = "";
+ QString methodParams = "";
+
+ switch(getType()) {
+ case CodeAccessorMethod::ADD:
+ methodName = "add" + Codegen_Utils::capitalizeFirstLetter(fieldType);
+ methodReturnType = "void";
+ methodParams = objectType+" value ";
+ headerText = "Add an object of type "+objectType+" to the List "+fieldName+endLine+getParentObject()->getDoc()+endLine+"@return void";
+ break;
+ case CodeAccessorMethod::GET:
+ methodName = "get" + Codegen_Utils::capitalizeFirstLetter(fieldName);
+ methodReturnType = fieldType;
+ headerText = "Get the value of "+fieldName+endLine+getParentObject()->getDoc()+endLine+"@return the value of "+fieldName;
+ break;
+ case CodeAccessorMethod::LIST:
+ methodName = "get" + Codegen_Utils::capitalizeFirstLetter(fieldType)+"List";
+ methodReturnType = "List";
+ headerText = "Get the list of "+fieldName+endLine+getParentObject()->getDoc()+endLine+"@return List of "+fieldName;
+ break;
+ case CodeAccessorMethod::REMOVE:
+ methodName = "remove" + Codegen_Utils::capitalizeFirstLetter(fieldType);
+ methodReturnType = "void";
+ methodParams = objectType+" value ";
+ headerText = "Remove an object of type "+objectType+" from the List "+fieldName+endLine+getParentObject()->getDoc();
+ break;
+ case CodeAccessorMethod::SET:
+ methodName = "set" + Codegen_Utils::capitalizeFirstLetter(fieldName);
+ methodReturnType = "void";
+ methodParams = fieldType + " value ";
+ headerText = "Set the value of "+fieldName+endLine+getParentObject()->getDoc()+endLine;
+ break;
+ default:
+ // do nothing..no idea what this is
+ kWarning()<<"Warning: cant generate JavaCodeAccessorMethod for type: "<<getType()<<endl;
+ break;
+ }
+
+ // set header once.
+ if(getComment()->getText().isEmpty())
+ getComment()->setText(headerText);
+
+ // set start/end method text
+ setStartMethodText(strVis+' '+methodReturnType+' '+methodName+" ( "+methodParams+" ) {");
+ setEndMethodText("}");
+
+}
+
+void JavaCodeAccessorMethod::update()
+{
+ updateMethodDeclaration();
+ updateContent();
+}
+
+#include "javacodeaccessormethod.moc"
diff --git a/umbrello/umbrello/codegenerators/javacodeaccessormethod.h b/umbrello/umbrello/codegenerators/javacodeaccessormethod.h
new file mode 100644
index 00000000..5a109b59
--- /dev/null
+++ b/umbrello/umbrello/codegenerators/javacodeaccessormethod.h
@@ -0,0 +1,65 @@
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the 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 code generated by:
+ * Author : thomas
+ * Date : Thu Oct 2 2003
+ */
+
+#ifndef JAVACODEACCESSORMETHOD_H
+#define JAVACODEACCESSORMETHOD_H
+
+#include <qstring.h>
+
+#include "../codeaccessormethod.h"
+
+class CodeClassField;
+
+class JavaCodeAccessorMethod : public CodeAccessorMethod
+{
+ Q_OBJECT
+public:
+
+ // Constructors/Destructors
+ //
+
+ /**
+ * Constructor
+ */
+ JavaCodeAccessorMethod ( CodeClassField * field, CodeAccessorMethod::AccessorType type);
+
+ /**
+ * Empty Destructor
+ */
+ virtual ~JavaCodeAccessorMethod ( );
+
+ /**
+ * Must be called before this object is usable
+ */
+ void update();
+
+protected:
+
+ /** set attributes of the node that represents this class
+ * in the XMI document.
+ */
+ virtual void setAttributesOnNode ( QDomDocument & doc, QDomElement & blockElement);
+
+ /** set the class attributes of this object from
+ * the passed element node.
+ */
+ virtual void setAttributesFromNode ( QDomElement & element);
+
+ virtual void updateMethodDeclaration();
+ virtual void updateContent();
+
+};
+
+#endif // JAVACODEACCESSORMETHOD_H
diff --git a/umbrello/umbrello/codegenerators/javacodeclassfield.cpp b/umbrello/umbrello/codegenerators/javacodeclassfield.cpp
new file mode 100644
index 00000000..627b9b3e
--- /dev/null
+++ b/umbrello/umbrello/codegenerators/javacodeclassfield.cpp
@@ -0,0 +1,111 @@
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * copyright (C) 2004-2007 *
+ * Umbrello UML Modeller Authors <uml-devel@uml.sf.net> *
+ ***************************************************************************/
+
+/* This code generated by:
+ * Author : thomas
+ * Date : Mon Jun 30 2003
+ */
+
+// own header
+#include "javacodeclassfield.h"
+
+// qt/kde includes
+#include <qregexp.h>
+#include <kdebug.h>
+
+// local includes
+#include "javacodecomment.h"
+#include "javacodegenerator.h"
+
+#include "../attribute.h"
+#include "../umlobject.h"
+#include "../umlrole.h"
+#include "../uml.h"
+
+// #include "javacodeaccessormethod.h"
+#include "javaclassifiercodedocument.h"
+
+// Constructors/Destructors
+//
+
+JavaCodeClassField::JavaCodeClassField (ClassifierCodeDocument * parentDoc, UMLRole * role)
+ : CodeClassField(parentDoc, role)
+{
+
+}
+
+JavaCodeClassField::JavaCodeClassField (ClassifierCodeDocument * parentDoc, UMLAttribute * attrib)
+ : CodeClassField(parentDoc, attrib)
+{
+
+}
+
+JavaCodeClassField::~JavaCodeClassField ( ) { }
+
+//
+// Methods
+//
+
+// Other methods
+//
+
+QString JavaCodeClassField::getFieldName() {
+ if (parentIsAttribute())
+ {
+ UMLAttribute * at = (UMLAttribute*) getParentObject();
+ return cleanName(at->getName());
+ }
+ else
+ {
+ UMLRole * role = (UMLRole*) getParentObject();
+ QString roleName = role->getName();
+ if(fieldIsSingleValue()) {
+ return roleName.replace(0, 1, roleName.left(1).lower());
+ } else {
+ return roleName.lower() + "Vector";
+ }
+ }
+}
+
+
+QString JavaCodeClassField::getInitialValue() {
+
+ if (parentIsAttribute())
+ {
+ UMLAttribute * at = dynamic_cast<UMLAttribute*>( getParentObject() );
+ if (at) {
+ return fixInitialStringDeclValue(at->getInitialValue(), getTypeName());
+ } else {
+ kError() << "JavaodeClassField::getInitialValue: parent object is not a UMLAttribute"
+ << endl;
+ return "";
+ }
+ return fixInitialStringDeclValue(at->getInitialValue(), getTypeName());
+ }
+ else
+ {
+ if(fieldIsSingleValue()) {
+ // FIX : IF the multiplicity is "1" then we should init a new object here, if its 0 or 1,
+ // then we can just return 'empty' string (minor problem).
+ return QString("");
+ } else {
+ return " new "+JavaCodeGenerator::getListFieldClassName()+"( )";
+ }
+ }
+
+}
+
+QString JavaCodeClassField::getTypeName ( )
+{
+ return JavaCodeGenerator::fixTypeName(CodeClassField::getTypeName());
+}
+
+#include "javacodeclassfield.moc"
diff --git a/umbrello/umbrello/codegenerators/javacodeclassfield.h b/umbrello/umbrello/codegenerators/javacodeclassfield.h
new file mode 100644
index 00000000..5ed1cea4
--- /dev/null
+++ b/umbrello/umbrello/codegenerators/javacodeclassfield.h
@@ -0,0 +1,59 @@
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the 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 code generated by:
+ * Author : thomas
+ * Date : Mon Jun 30 2003
+ */
+
+
+
+#ifndef JAVACODECLASSFIELD_H
+#define JAVACODECLASSFIELD_H
+
+#include <qstring.h>
+
+#include "../codeclassfield.h"
+
+class ClassifierCodeDocument;
+
+class JavaCodeClassField : public CodeClassField
+{
+ Q_OBJECT
+public:
+
+ // Constructors/Destructors
+ //
+
+ /**
+ * Constructors
+ */
+ JavaCodeClassField (ClassifierCodeDocument * parentDoc, UMLRole * role);
+ JavaCodeClassField (ClassifierCodeDocument * parentDoc, UMLAttribute * attrib);
+
+ /**
+ * Empty Destructor
+ */
+ virtual ~JavaCodeClassField ( );
+
+ QString getFieldType();
+ QString getFieldName();
+ QString getInitialValue();
+
+ QString getTypeName ( );
+protected:
+
+private:
+
+ // void initDeclCodeBlock ();
+
+};
+
+#endif // JAVACODECLASSFIELD_H
diff --git a/umbrello/umbrello/codegenerators/javacodeclassfielddeclarationblock.cpp b/umbrello/umbrello/codegenerators/javacodeclassfielddeclarationblock.cpp
new file mode 100644
index 00000000..87ebf78a
--- /dev/null
+++ b/umbrello/umbrello/codegenerators/javacodeclassfielddeclarationblock.cpp
@@ -0,0 +1,118 @@
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * copyright (C) 2004-2006 *
+ * Umbrello UML Modeller Authors <uml-devel@uml.sf.net> *
+ ***************************************************************************/
+
+/* This code generated by:
+ * Author : thomas
+ * Date : Fri Jul 25 2003
+ */
+
+#include "javacodeclassfielddeclarationblock.h"
+
+#include "javacodeclassfield.h"
+#include "javaclassifiercodedocument.h"
+#include "javacodegenerationpolicy.h"
+#include "../codegenerator.h"
+#include "../classifier.h"
+#include "../umlrole.h"
+#include "../uml.h"
+
+// Constructors/Destructors
+//
+
+JavaCodeClassFieldDeclarationBlock::JavaCodeClassFieldDeclarationBlock ( CodeClassField * parent )
+ : CodeClassFieldDeclarationBlock ( parent )
+{
+ setOverallIndentationLevel(1);
+ updateContent();
+}
+
+JavaCodeClassFieldDeclarationBlock::~JavaCodeClassFieldDeclarationBlock ( ) { }
+
+//
+// Methods
+//
+
+
+
+// Other methods
+//
+
+/**
+ */
+void JavaCodeClassFieldDeclarationBlock::updateContent( )
+{
+
+ CodeClassField * cf = getParentClassField();
+ ClassifierCodeDocument * doc = cf->getParentDocument();
+ JavaCodeClassField * jcf = dynamic_cast<JavaCodeClassField*>(cf);
+ JavaClassifierCodeDocument* jdoc = dynamic_cast<JavaClassifierCodeDocument*>(doc);
+ CodeGenerationPolicy * commonpolicy = UMLApp::app()->getCommonPolicy();
+
+ CodeGenerationPolicy::ScopePolicy scopePolicy = commonpolicy->getAssociationFieldScope();
+
+ // Set the comment
+ QString notes = getParentObject()->getDoc();
+ getComment()->setText(notes);
+
+ // Set the body
+ QString staticValue = getParentObject()->getStatic() ? "static " : "";
+ QString scopeStr = jdoc->scopeToJavaDecl(getParentObject()->getVisibility());
+
+ // IF this is from an association, then scope taken as appropriate to policy
+ if(!jcf->parentIsAttribute())
+ {
+ switch (scopePolicy) {
+ case CodeGenerationPolicy::Public:
+ case CodeGenerationPolicy::Private:
+ case CodeGenerationPolicy::Protected:
+ scopeStr = jdoc->scopeToJavaDecl((Uml::Visibility::Value) scopePolicy);
+ break;
+ default:
+ case CodeGenerationPolicy::FromParent:
+ // do nothing here... will leave as from parent object
+ break;
+ }
+ }
+
+ QString typeName = jcf->getTypeName();
+ QString fieldName = jcf->getFieldName();
+ QString initialV = jcf->getInitialValue();
+
+ if (!cf->parentIsAttribute() && !cf->fieldIsSingleValue())
+ typeName = "List";
+
+ QString body = staticValue+scopeStr+' '+typeName+' '+fieldName;
+ if (!initialV.isEmpty())
+ body.append(" = " + initialV);
+ else if (!cf->parentIsAttribute())
+ {
+ UMLRole * role = dynamic_cast<UMLRole*>(cf->getParentObject());
+ if (role->getObject()->getBaseType() == Uml::ot_Interface)
+ {
+ // do nothing.. can't instanciate an interface
+ } else {
+
+ // FIX?: IF a constructor method exists in the classifiercodedoc
+ // of the parent Object, then we can use that instead (if its empty).
+ if(cf->fieldIsSingleValue())
+ {
+ if(!typeName.isEmpty())
+ body.append(" = new " + typeName + " ( )");
+ } else
+ body.append(" = new Vector ( )");
+ }
+ }
+
+ setText(body+';');
+
+}
+
+#include "javacodeclassfielddeclarationblock.moc"
diff --git a/umbrello/umbrello/codegenerators/javacodeclassfielddeclarationblock.h b/umbrello/umbrello/codegenerators/javacodeclassfielddeclarationblock.h
new file mode 100644
index 00000000..8166fced
--- /dev/null
+++ b/umbrello/umbrello/codegenerators/javacodeclassfielddeclarationblock.h
@@ -0,0 +1,51 @@
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the 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 code generated by:
+ * Author : thomas
+ * Date : Fri Jul 25 2003
+ */
+
+#ifndef JAVACODECLASSFIELDDECLARATIONBLOCK_H
+#define JAVACODECLASSFIELDDECLARATIONBLOCK_H
+
+#include <qstring.h>
+
+#include "../codeclassfielddeclarationblock.h"
+
+class JavaCodeClassFieldDeclarationBlock : public CodeClassFieldDeclarationBlock
+{
+ Q_OBJECT
+public:
+
+ // Constructors/Destructors
+ //
+
+ /**
+ * Constructor
+ */
+ JavaCodeClassFieldDeclarationBlock ( CodeClassField * parent );
+
+ /**
+ * Empty Destructor
+ */
+ virtual ~JavaCodeClassFieldDeclarationBlock ( );
+
+protected:
+
+ // this will be called by syncToParent whenever the parent object is "modified"
+ void updateContent ( );
+
+private:
+
+
+};
+
+#endif // JAVACODECLASSFIELDDECLARATIONBLOCK_H
diff --git a/umbrello/umbrello/codegenerators/javacodecomment.cpp b/umbrello/umbrello/codegenerators/javacodecomment.cpp
new file mode 100644
index 00000000..bec0e87b
--- /dev/null
+++ b/umbrello/umbrello/codegenerators/javacodecomment.cpp
@@ -0,0 +1,84 @@
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the 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 code generated by:
+ * Author : thomas
+ * Date : Mon Jun 23 2003
+ */
+
+#include "javacodecomment.h"
+#include <qregexp.h>
+
+// Constructors/Destructors
+//
+
+JavaCodeComment::JavaCodeComment ( CodeDocument * doc, const QString & text )
+ : CodeComment (doc, text)
+{
+
+}
+
+JavaCodeComment::~JavaCodeComment ( ) { }
+
+//
+// Methods
+//
+
+
+// Accessor methods
+//
+
+
+// Public attribute accessor methods
+//
+
+// Other methods
+//
+
+QString JavaCodeComment::getNewEditorLine ( int amount ) {
+ QString line = getIndentationString(amount) + "// ";
+ return line;
+}
+
+/** UnFormat a long text string. Typically, this means removing
+ * the indentaion (linePrefix) and/or newline chars from each line.
+ */
+QString JavaCodeComment::unformatText ( const QString & text , const QString & indent)
+{
+
+ // remove leading or trailing comment stuff
+ QString mytext = TextBlock::unformatText(text, indent);
+
+ // now leading slashes
+ mytext.remove(QRegExp("^\\/\\/\\s*"));
+ return mytext;
+}
+
+/**
+ * @return QString
+ */
+QString JavaCodeComment::toString ( )
+{
+
+ QString output = "";
+
+ // simple output method
+ if(getWriteOutText())
+ {
+ QString indent = getIndentationString();
+ QString endLine = getNewLineEndingChars();
+ output.append(formatMultiLineText (getText(), indent +"// ", endLine));
+ }
+
+ return output;
+}
+
+
+#include "javacodecomment.moc"
diff --git a/umbrello/umbrello/codegenerators/javacodecomment.h b/umbrello/umbrello/codegenerators/javacodecomment.h
new file mode 100644
index 00000000..1f9b1d8d
--- /dev/null
+++ b/umbrello/umbrello/codegenerators/javacodecomment.h
@@ -0,0 +1,77 @@
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the 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 code generated by:
+ * Author : thomas
+ * Date : Mon Jun 23 2003
+ */
+
+
+
+#ifndef JAVACODECOMMENT_H
+#define JAVACODECOMMENT_H
+
+#include <qstring.h>
+#include "../codecomment.h"
+
+/**
+ * class JavaCodeComment
+ * A Java code comment. There is only a single styles of comments:
+ * these are simply started with double slash sequence and no terminating
+ * characters
+ */
+
+class JavaCodeComment : virtual public CodeComment
+{
+ Q_OBJECT
+public:
+
+ // Constructors/Destructors
+ //
+
+
+ /**
+ * Constructors
+ */
+ explicit JavaCodeComment ( CodeDocument * doc, const QString & text = "");
+
+ /**
+ * Empty Destructor
+ */
+ virtual ~JavaCodeComment ( );
+
+ // Public attributes
+ //
+
+
+ // other
+
+ /**
+ * @return QString
+ */
+ QString toString ( );
+
+ /** UnFormat a long text string. Typically, this means removing
+ * the indentaion (linePrefix) and/or newline chars from each line.
+ */
+ virtual QString unformatText ( const QString & text, const QString & indent = "" );
+
+ /** a special version here because we want to not only indent
+ * the new line, but to add the "//" sequence as well.
+ */
+ virtual QString getNewEditorLine ( int amount );
+
+protected:
+
+private:
+
+};
+
+#endif // JAVACODECOMMENT_H
diff --git a/umbrello/umbrello/codegenerators/javacodedocumentation.cpp b/umbrello/umbrello/codegenerators/javacodedocumentation.cpp
new file mode 100644
index 00000000..e831d885
--- /dev/null
+++ b/umbrello/umbrello/codegenerators/javacodedocumentation.cpp
@@ -0,0 +1,143 @@
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * copyright (C) 2004-2007 *
+ * Umbrello UML Modeller Authors <uml-devel@uml.sf.net> *
+ ***************************************************************************/
+
+/* This code generated by:
+ * Author : thomas
+ * Date : Mon Jun 23 2003
+ */
+
+// own header
+#include "javacodedocumentation.h"
+
+// qt/kde includes
+#include <qregexp.h>
+#include <kdebug.h>
+
+// local includes
+#include "javaclassifiercodedocument.h"
+#include "../codegenerationpolicy.h"
+#include "../uml.h"
+
+// Constructors/Destructors
+//
+
+JavaCodeDocumentation::JavaCodeDocumentation ( JavaClassifierCodeDocument * doc, const QString & text )
+ : CodeComment(doc, text)
+{
+
+}
+
+JavaCodeDocumentation::~JavaCodeDocumentation ( ) { }
+
+//
+// Methods
+//
+
+
+// Accessor methods
+//
+
+// Other methods
+//
+
+/**
+ * Save the XMI representation of this object
+ */
+void JavaCodeDocumentation::saveToXMI ( QDomDocument & doc, QDomElement & root ) {
+ QDomElement blockElement = doc.createElement( "javacodedocumentation" );
+ setAttributesOnNode(doc, blockElement); // as we added no additional fields to this class we may
+ // just use parent TextBlock method
+ root.appendChild( blockElement );
+}
+
+/**
+ * @return QString
+ */
+QString JavaCodeDocumentation::toString ( )
+{
+
+ QString output = "";
+
+ // simple output method
+ if(getWriteOutText())
+ {
+ bool useDoubleDashOutput = true;
+
+ // need to figure out output type from java policy
+ CodeGenerationPolicy *p = UMLApp::app()->getCommonPolicy();
+ if(p->getCommentStyle() == CodeGenerationPolicy::MultiLine)
+ useDoubleDashOutput = false;
+
+ QString indent = getIndentationString();
+ QString endLine = getNewLineEndingChars();
+ QString body = getText();
+ if(useDoubleDashOutput)
+ {
+ if(!body.isEmpty())
+ output.append(formatMultiLineText (body, indent +"// ", endLine));
+ } else {
+ output.append(indent+"/**"+endLine);
+ output.append(formatMultiLineText (body, indent +" * ", endLine));
+ output.append(indent+" */"+endLine);
+ }
+ }
+
+ return output;
+}
+
+QString JavaCodeDocumentation::getNewEditorLine ( int amount )
+{
+ CodeGenerationPolicy *p = UMLApp::app()->getCommonPolicy();
+ if(p->getCommentStyle() == CodeGenerationPolicy::MultiLine)
+ return getIndentationString(amount) + " * ";
+ else
+ return getIndentationString(amount) + "// ";
+}
+
+int JavaCodeDocumentation::firstEditableLine() {
+ CodeGenerationPolicy *p = UMLApp::app()->getCommonPolicy();
+ if(p->getCommentStyle() == CodeGenerationPolicy::MultiLine)
+ return 1;
+ return 0;
+}
+
+int JavaCodeDocumentation::lastEditableLine() {
+ CodeGenerationPolicy *p = UMLApp::app()->getCommonPolicy();
+ if(p->getCommentStyle() == CodeGenerationPolicy::MultiLine)
+ {
+ return -1; // very last line is NOT editable
+ }
+ return 0;
+}
+
+/** UnFormat a long text string. Typically, this means removing
+ * the indentaion (linePrefix) and/or newline chars from each line.
+ */
+QString JavaCodeDocumentation::unformatText ( const QString & text , const QString & indent)
+{
+
+ QString mytext = TextBlock::unformatText(text, indent);
+ CodeGenerationPolicy *p = UMLApp::app()->getCommonPolicy();
+ // remove leading or trailing comment stuff
+ mytext.remove(QRegExp('^'+indent));
+ if(p->getCommentStyle() == CodeGenerationPolicy::MultiLine)
+ {
+ mytext.remove(QRegExp("^\\/\\*\\*\\s*\n?"));
+ mytext.remove(QRegExp("\\s*\\*\\/\\s*\n?$"));
+ mytext.remove(QRegExp("^\\s*\\*\\s*"));
+ } else
+ mytext.remove(QRegExp("^\\/\\/\\s*"));
+
+ return mytext;
+}
+
+
+#include "javacodedocumentation.moc"
diff --git a/umbrello/umbrello/codegenerators/javacodedocumentation.h b/umbrello/umbrello/codegenerators/javacodedocumentation.h
new file mode 100644
index 00000000..246b87a6
--- /dev/null
+++ b/umbrello/umbrello/codegenerators/javacodedocumentation.h
@@ -0,0 +1,95 @@
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the 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 code generated by:
+ * Author : thomas
+ * Date : Mon Jun 23 2003
+ */
+
+
+
+#ifndef JAVACODEDOCUMENTATION_H
+#define JAVACODEDOCUMENTATION_H
+
+#include <qstring.h>
+#include "../codecomment.h"
+
+class JavaClassifierCodeDocument;
+
+/**
+ * class JavaCodeDocumentation
+ * A Java code comment. There is only a single styles of comments:
+ * these are simply started with double slash sequence and no terminating
+ * characters
+ */
+
+class JavaCodeDocumentation : virtual public CodeComment
+{
+ Q_OBJECT
+public:
+
+ // Constructors/Destructors
+ //
+
+
+ /**
+ * Constructors
+ */
+ explicit JavaCodeDocumentation ( JavaClassifierCodeDocument * doc, const QString & text = "");
+
+ /**
+ * Empty Destructor
+ */
+ virtual ~JavaCodeDocumentation ( );
+
+ // Public attributes
+ //
+
+ // Other
+ //
+
+ /**
+ * Save the XMI representation of this object
+ */
+ virtual void saveToXMI ( QDomDocument & doc, QDomElement & root );
+
+ /**
+ * @return QString
+ */
+ QString toString ( );
+
+ /** UnFormat a long text string. Typically, this means removing
+ * the indentaion (linePrefix) and/or newline chars from each line.
+ */
+ virtual QString unformatText ( const QString & text, const QString & indent = "" );
+
+ /** a special version here because we want to not only indent
+ * the new line, but to add the " * " sequence as well.
+ */
+ virtual QString getNewEditorLine ( int amount );
+
+ /** Ush. These are terrifically bad and must one day go away.
+ * Both methods indicate the range of lines in this textblock
+ * which may be edited by the codeeditor (assuming that any are
+ * actually editable). The default case is no lines are editable.
+ * The line numbering starts with '0' and a '-1' means no line
+ * qualifies.
+ */
+ virtual int firstEditableLine();
+ virtual int lastEditableLine();
+
+
+protected:
+
+private:
+
+};
+
+#endif // JAVACODEDOCUMENTATION_H
diff --git a/umbrello/umbrello/codegenerators/javacodegenerationformbase.ui b/umbrello/umbrello/codegenerators/javacodegenerationformbase.ui
new file mode 100644
index 00000000..cd39611a
--- /dev/null
+++ b/umbrello/umbrello/codegenerators/javacodegenerationformbase.ui
@@ -0,0 +1,277 @@
+<!DOCTYPE UI><UI version="3.2" stdsetdef="1">
+<class>JavaCodeGenerationFormBase</class>
+<widget class="QWidget">
+ <property name="name">
+ <cstring>Form1</cstring>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>462</width>
+ <height>376</height>
+ </rect>
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLayoutWidget" row="0" column="0">
+ <property name="name">
+ <cstring>layout6</cstring>
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QGroupBox" row="3" column="0">
+ <property name="name">
+ <cstring>groupBox3</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>5</hsizetype>
+ <vsizetype>4</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="title">
+ <string>Project Generation</string>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QCheckBox">
+ <property name="name">
+ <cstring>m_makeANTDocumentCheckBox</cstring>
+ </property>
+ <property name="text">
+ <string>Create ANT build document</string>
+ </property>
+ </widget>
+ </vbox>
+ </widget>
+ <widget class="QGroupBox" row="2" column="0">
+ <property name="name">
+ <cstring>groupBox2</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>5</hsizetype>
+ <vsizetype>4</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="title">
+ <string>Auto-Generate Methods</string>
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLayoutWidget" row="0" column="0">
+ <property name="name">
+ <cstring>layout2</cstring>
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QCheckBox" row="0" column="0">
+ <property name="name">
+ <cstring>m_generateConstructors</cstring>
+ </property>
+ <property name="text">
+ <string>Empty constructor methods</string>
+ </property>
+ <property name="checked">
+ <bool>false</bool>
+ </property>
+ </widget>
+ <widget class="QCheckBox" row="2" column="0">
+ <property name="name">
+ <cstring>m_generateAssocAccessors</cstring>
+ </property>
+ <property name="text">
+ <string>Association accessor methods</string>
+ </property>
+ <property name="checked">
+ <bool>true</bool>
+ </property>
+ </widget>
+ <widget class="QCheckBox" row="1" column="0">
+ <property name="name">
+ <cstring>m_generateAttribAccessors</cstring>
+ </property>
+ <property name="text">
+ <string>Attribute accessor methods</string>
+ </property>
+ <property name="checked">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </grid>
+ </widget>
+ <widget class="QLayoutWidget" row="1" column="0">
+ <property name="name">
+ <cstring>layout4</cstring>
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QComboBox" row="0" column="1">
+ <item>
+ <property name="text">
+ <string>Public</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>Private</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>Protected</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>From Parent Object</string>
+ </property>
+ </item>
+ <property name="name">
+ <cstring>m_accessorScopeCB</cstring>
+ </property>
+ <property name="currentItem">
+ <number>3</number>
+ </property>
+ </widget>
+ <widget class="QLabel" row="0" column="0">
+ <property name="name">
+ <cstring>textLabel1_3</cstring>
+ </property>
+ <property name="text">
+ <string>Default attribute accessor scope:</string>
+ </property>
+ </widget>
+ </grid>
+ </widget>
+ <widget class="QLayoutWidget" row="2" column="0">
+ <property name="name">
+ <cstring>layout4</cstring>
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLabel" row="0" column="0">
+ <property name="name">
+ <cstring>textLabel1_3_2</cstring>
+ </property>
+ <property name="text">
+ <string>Default association field scope:</string>
+ </property>
+ </widget>
+ <widget class="QComboBox" row="0" column="1">
+ <item>
+ <property name="text">
+ <string>Public</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>Private</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>Protected</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>From Parent Role</string>
+ </property>
+ </item>
+ <property name="name">
+ <cstring>m_assocFieldScopeCB</cstring>
+ </property>
+ <property name="currentItem">
+ <number>3</number>
+ </property>
+ </widget>
+ </grid>
+ </widget>
+ </grid>
+ </widget>
+ <widget class="QGroupBox" row="1" column="0">
+ <property name="name">
+ <cstring>groupBox1</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>5</hsizetype>
+ <vsizetype>4</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="title">
+ <string>Documentation</string>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>textLabel1</cstring>
+ </property>
+ <property name="text">
+ <string>Style:</string>
+ </property>
+ </widget>
+ <widget class="QComboBox">
+ <item>
+ <property name="text">
+ <string>Slash-Slash (//)</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>Slash-Star (/** */)</string>
+ </property>
+ </item>
+ <property name="name">
+ <cstring>m_SelectCommentStyle</cstring>
+ </property>
+ </widget>
+ </hbox>
+ </widget>
+ <widget class="QLabel" row="0" column="0">
+ <property name="name">
+ <cstring>textLabel1_2</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>5</hsizetype>
+ <vsizetype>4</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="text">
+ <string>&lt;p align="center"&gt;Java Code Generation&lt;/p&gt;</string>
+ </property>
+ </widget>
+ </grid>
+ </widget>
+ </grid>
+</widget>
+<layoutdefaults spacing="6" margin="11"/>
+</UI>
diff --git a/umbrello/umbrello/codegenerators/javacodegenerationpolicy.cpp b/umbrello/umbrello/codegenerators/javacodegenerationpolicy.cpp
new file mode 100644
index 00000000..2dcc834e
--- /dev/null
+++ b/umbrello/umbrello/codegenerators/javacodegenerationpolicy.cpp
@@ -0,0 +1,188 @@
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * copyright (C) 2004-2006 *
+ * Umbrello UML Modeller Authors <uml-devel@uml.sf.net> *
+ ***************************************************************************/
+
+/* This code generated by:
+ * Author : thomas
+ * Date : Mon Jun 23 2003
+ */
+
+// own header
+#include "javacodegenerationpolicy.h"
+// qt/kde includes
+#include <kconfig.h>
+// app includes
+#include "javacodegenerationpolicypage.h"
+#include "javacodegenerator.h"
+#include "../uml.h"
+
+const bool JavaCodeGenerationPolicy::DEFAULT_AUTO_GEN_ATTRIB_ACCESSORS = true;
+const bool JavaCodeGenerationPolicy::DEFAULT_AUTO_GEN_ASSOC_ACCESSORS = true;
+
+// Constructors/Destructors
+/*
+
+JavaCodeGenerationPolicy::JavaCodeGenerationPolicy(CodeGenerationPolicy *defaults)
+ : CodeGenerationPolicy(defaults)
+{
+ init();
+ setDefaults(defaults,false);
+}
+ */
+
+JavaCodeGenerationPolicy::JavaCodeGenerationPolicy(KConfig *config)
+ // : CodeGenerationPolicy(config)
+{
+ init();
+ setDefaults(config,false);
+}
+
+JavaCodeGenerationPolicy::~JavaCodeGenerationPolicy ( ) { }
+
+//
+// Methods
+//
+
+// Accessor methods
+//
+
+// Public attribute accessor methods
+//
+
+/**
+ * Set the value of m_autoGenerateAttribAccessors
+ * @param new_var the new value
+ */
+void JavaCodeGenerationPolicy::setAutoGenerateAttribAccessors( bool var ) {
+ m_autoGenerateAttribAccessors = var;
+ m_commonPolicy->emitModifiedCodeContentSig();
+}
+
+/**
+ * Set the value of m_autoGenerateAssocAccessors
+ * @param new_var the new value
+ */
+void JavaCodeGenerationPolicy::setAutoGenerateAssocAccessors( bool var ) {
+ m_autoGenerateAssocAccessors = var;
+ m_commonPolicy->emitModifiedCodeContentSig();
+}
+
+/**
+ * Get the value of m_autoGenerateAttribAccessors
+ * @return the value of m_autoGenerateAttribAccessors
+ */
+bool JavaCodeGenerationPolicy::getAutoGenerateAttribAccessors( ){
+ return m_autoGenerateAttribAccessors;
+}
+
+/**
+ * Get the value of m_autoGenerateAssocAccessors
+ * @return the value of m_autoGenerateAssocAccessors
+ */
+bool JavaCodeGenerationPolicy::getAutoGenerateAssocAccessors( ){
+ return m_autoGenerateAssocAccessors;
+}
+
+// Other methods
+//
+
+void JavaCodeGenerationPolicy::writeConfig ( KConfig * config )
+{
+
+ // write ONLY the Java specific stuff
+ config->setGroup("Java Code Generation");
+
+ config->writeEntry("autoGenAccessors",getAutoGenerateAttribAccessors());
+ config->writeEntry("autoGenAssocAccessors",getAutoGenerateAssocAccessors());
+
+ CodeGenerator *codegen = UMLApp::app()->getGenerator();
+ JavaCodeGenerator *javacodegen = dynamic_cast<JavaCodeGenerator*>(codegen);
+ if (javacodegen)
+ config->writeEntry("buildANTDocument", javacodegen->getCreateANTBuildFile());
+
+}
+
+void JavaCodeGenerationPolicy::setDefaults ( CodeGenPolicyExt * clone, bool emitUpdateSignal )
+{
+
+ JavaCodeGenerationPolicy * jclone;
+ if (!clone)
+ return;
+
+ // NOW block signals for java param setting
+ blockSignals(true); // we need to do this because otherwise most of these
+ // settors below will each send the modifiedCodeContent() signal
+ // needlessly (we can just make one call at the end).
+
+
+ // now do java-specific stuff IF our clone is also a JavaCodeGenerationPolicy object
+ if((jclone = dynamic_cast<JavaCodeGenerationPolicy*>(clone)))
+ {
+ setAutoGenerateAttribAccessors(jclone->getAutoGenerateAttribAccessors());
+ setAutoGenerateAssocAccessors(jclone->getAutoGenerateAssocAccessors());
+ }
+
+ blockSignals(false); // "as you were citizen"
+
+ if(emitUpdateSignal)
+ m_commonPolicy->emitModifiedCodeContentSig();
+
+}
+
+void JavaCodeGenerationPolicy::setDefaults( KConfig * config, bool emitUpdateSignal )
+{
+
+ if(!config)
+ return;
+
+ // call method at the common policy to init default stuff
+ m_commonPolicy->setDefaults(config, false);
+
+ // NOW block signals (because call to super-class method will leave value at "true")
+ blockSignals(true); // we need to do this because otherwise most of these
+ // settors below will each send the modifiedCodeContent() signal
+ // needlessly (we can just make one call at the end).
+
+ // now do java specific stuff
+ config -> setGroup("Java Code Generation");
+
+ setAutoGenerateAttribAccessors(config->readBoolEntry("autoGenAccessors",DEFAULT_AUTO_GEN_ATTRIB_ACCESSORS));
+ setAutoGenerateAssocAccessors(config->readBoolEntry("autoGenAssocAccessors",DEFAULT_AUTO_GEN_ASSOC_ACCESSORS));
+
+ CodeGenerator *codegen = UMLApp::app()->getGenerator();
+ JavaCodeGenerator *javacodegen = dynamic_cast<JavaCodeGenerator*>(codegen);
+ if (javacodegen) {
+ bool mkant = config->readBoolEntry("buildANTDocument", JavaCodeGenerator::DEFAULT_BUILD_ANT_DOC);
+ javacodegen->setCreateANTBuildFile(mkant);
+ }
+
+ blockSignals(false); // "as you were citizen"
+
+ if(emitUpdateSignal)
+ m_commonPolicy->emitModifiedCodeContentSig();
+}
+
+
+/**
+ * Create a new dialog interface for this object.
+ * @return dialog object
+ */
+CodeGenerationPolicyPage * JavaCodeGenerationPolicy::createPage ( QWidget *parent, const char *name ) {
+ return new JavaCodeGenerationPolicyPage ( parent, name, this );
+}
+
+void JavaCodeGenerationPolicy::init() {
+ m_commonPolicy = UMLApp::app()->getCommonPolicy();
+ m_autoGenerateAttribAccessors = DEFAULT_AUTO_GEN_ATTRIB_ACCESSORS;
+ m_autoGenerateAssocAccessors = DEFAULT_AUTO_GEN_ASSOC_ACCESSORS;
+}
+
+
+#include "javacodegenerationpolicy.moc"
diff --git a/umbrello/umbrello/codegenerators/javacodegenerationpolicy.h b/umbrello/umbrello/codegenerators/javacodegenerationpolicy.h
new file mode 100644
index 00000000..2a40cb57
--- /dev/null
+++ b/umbrello/umbrello/codegenerators/javacodegenerationpolicy.h
@@ -0,0 +1,116 @@
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * copyright (C) 2003-2006 *
+ * Umbrello UML Modeller Authors <uml-devel@uml.sf.net> *
+ ***************************************************************************/
+
+/* This code generated by:
+ * Author : thomas
+ * Date : Mon Jun 23 2003
+ */
+
+#ifndef JAVACODEGENERATIONPOLICY_H
+#define JAVACODEGENERATIONPOLICY_H
+
+#include <qstring.h>
+#include "codegenpolicyext.h"
+#include "../codegenerationpolicy.h"
+
+class KConfig;
+class CodeGenerationPolicyPage;
+
+class JavaCodeGenerationPolicy : public CodeGenPolicyExt
+{
+ Q_OBJECT
+public:
+
+ static const bool DEFAULT_AUTO_GEN_ATTRIB_ACCESSORS;
+ static const bool DEFAULT_AUTO_GEN_ASSOC_ACCESSORS;
+
+ // Constructors/Destructors
+ //
+
+ /**
+ * Constructors
+ */
+ //JavaCodeGenerationPolicy (CodeGenerationPolicy * defaults = 0);
+ JavaCodeGenerationPolicy (KConfig * config = 0);
+
+ /**
+ * Empty Destructor
+ */
+ virtual ~JavaCodeGenerationPolicy ( );
+
+ // Public attributes
+ //
+
+
+ // Public attribute accessor methods
+ //
+
+ /**
+ * Set the value of m_autoGenerateAttribAccessors
+ * @param var the new value
+ */
+ void setAutoGenerateAttribAccessors ( bool var );
+
+ /**
+ * Get the value of m_autoGenerateAttribAccessors
+ * @return value the boolean value of m_autoGenerateAttribAccessors
+ */
+ bool getAutoGenerateAttribAccessors( );
+
+ /**
+ * Set the value of m_autoGenerateAssocAccessors
+ * @param var the new value
+ */
+ void setAutoGenerateAssocAccessors ( bool var );
+
+ /**
+ * Get the value of m_autoGenerateAssocAccessors
+ * @return value the boolean value of m_autoGenerateAssocAccessors
+ */
+ bool getAutoGenerateAssocAccessors( );
+
+ /**
+ * set the defaults for this code generator from the passed generator.
+ */
+ virtual void setDefaults (CodeGenPolicyExt * defaults, bool emitUpdateSignal = true);
+
+ /**
+ * set the defaults from a config file for this code generator from the passed KConfig pointer.
+ */
+ virtual void setDefaults(KConfig * config, bool emitUpdateSignal = true);
+
+ /**
+ * write Default params to passed KConfig pointer.
+ */
+ virtual void writeConfig (KConfig * config);
+
+ /**
+ * Create a new dialog interface for this object.
+ * @return dialog object
+ */
+ CodeGenerationPolicyPage * createPage ( QWidget *parent = 0, const char * name = 0);
+
+protected:
+
+ /**
+ */
+ void init ( );
+
+private:
+
+ CodeGenerationPolicy *m_commonPolicy;
+ bool m_autoGenerateConstructors;
+ bool m_autoGenerateAttribAccessors;
+ bool m_autoGenerateAssocAccessors;
+
+};
+
+#endif // JAVACODEGENERATIONPOLICY_H
diff --git a/umbrello/umbrello/codegenerators/javacodegenerationpolicypage.cpp b/umbrello/umbrello/codegenerators/javacodegenerationpolicypage.cpp
new file mode 100644
index 00000000..fd6d2ae3
--- /dev/null
+++ b/umbrello/umbrello/codegenerators/javacodegenerationpolicypage.cpp
@@ -0,0 +1,84 @@
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * copyright (C) 2004-2006 *
+ * Umbrello UML Modeller Authors <uml-devel@uml.sf.net> *
+ ***************************************************************************/
+
+/* This code generated by:
+ * Author : thomas
+ * Date : Wed Jul 30 2003
+ */
+
+// own header
+#include "javacodegenerationpolicypage.h"
+// qt/kde includes
+#include <qlabel.h>
+#include <qcombobox.h>
+#include <qcheckbox.h>
+#include <kdebug.h>
+#include <klocale.h>
+// app includes
+#include "javacodegenerationformbase.h"
+#include "../uml.h"
+
+JavaCodeGenerationPolicyPage::JavaCodeGenerationPolicyPage( QWidget *parent, const char *name, JavaCodeGenerationPolicy * policy )
+ : CodeGenerationPolicyPage(parent, name, policy)
+{
+ CodeGenerationPolicy *commonPolicy = UMLApp::app()->getCommonPolicy();
+ form = new JavaCodeGenerationFormBase(this);
+ form->m_SelectCommentStyle->setCurrentItem((int)(commonPolicy->getCommentStyle()));
+ form->m_generateConstructors->setChecked(commonPolicy->getAutoGenerateConstructors());
+ form->m_generateAttribAccessors->setChecked(policy->getAutoGenerateAttribAccessors());
+ form->m_generateAssocAccessors->setChecked(policy->getAutoGenerateAssocAccessors());
+ form->m_accessorScopeCB->setCurrentItem(commonPolicy->getAttributeAccessorScope() - 200);
+ form->m_assocFieldScopeCB->setCurrentItem(commonPolicy->getAssociationFieldScope() - 200);
+
+ /**
+ * @todo unclean - CreateANTBuildFile attribute should be in java policy
+ CodeGenerator *codegen = UMLApp::app()->getGenerator();
+ JavaCodeGenerator *javacodegen = dynamic_cast<JavaCodeGenerator*>(codegen);
+ if (javacodegen)
+ form->m_makeANTDocumentCheckBox->setChecked(javacodegen->getCreateANTBuildFile());
+ */
+}
+
+JavaCodeGenerationPolicyPage::~JavaCodeGenerationPolicyPage()
+{
+}
+
+void JavaCodeGenerationPolicyPage::apply()
+{
+ CodeGenerationPolicy *commonPolicy = UMLApp::app()->getCommonPolicy();
+ JavaCodeGenerationPolicy * parent = (JavaCodeGenerationPolicy*) m_parentPolicy;
+
+ // block signals so we don't cause too many update content calls to code documents
+ commonPolicy->blockSignals(true);
+
+ commonPolicy->setCommentStyle((CodeGenerationPolicy::CommentStyle ) form->m_SelectCommentStyle->currentItem());
+ commonPolicy->setAttributeAccessorScope((CodeGenerationPolicy::ScopePolicy) (form->m_accessorScopeCB->currentItem()+200));
+ commonPolicy->setAssociationFieldScope((CodeGenerationPolicy::ScopePolicy) (form->m_assocFieldScopeCB->currentItem()+200));
+ commonPolicy->setAutoGenerateConstructors(form->m_generateConstructors->isChecked());
+ parent->setAutoGenerateAttribAccessors(form->m_generateAttribAccessors->isChecked());
+ parent->setAutoGenerateAssocAccessors(form->m_generateAssocAccessors->isChecked());
+
+ /**
+ * @todo unclean - CreateANTBuildFile attribute should be in java policy
+ CodeGenerator *codegen = UMLApp::app()->getGenerator();
+ JavaCodeGenerator *javacodegen = dynamic_cast<JavaCodeGenerator*>(codegen);
+ if (javacodegen)
+ javacodegen->setCreateANTBuildFile(form->m_makeANTDocumentCheckBox->isChecked());
+ */
+ commonPolicy->blockSignals(false);
+
+ // now send out modified code content signal
+ commonPolicy->emitModifiedCodeContentSig();
+
+}
+
+
+#include "javacodegenerationpolicypage.moc"
diff --git a/umbrello/umbrello/codegenerators/javacodegenerationpolicypage.h b/umbrello/umbrello/codegenerators/javacodegenerationpolicypage.h
new file mode 100644
index 00000000..3b6f85e0
--- /dev/null
+++ b/umbrello/umbrello/codegenerators/javacodegenerationpolicypage.h
@@ -0,0 +1,48 @@
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * copyright (C) 2003-2006 *
+ * Umbrello UML Modeller Authors <uml-devel@uml.sf.net> *
+ ***************************************************************************/
+
+/* This code generated by:
+ * Author : thomas
+ * Date : Wed Jul 30 2003
+ */
+
+#ifndef JAVACODEGENERATIONPOLICYPAGE_H
+#define JAVACODEGENERATIONPOLICYPAGE_H
+
+#include "../dialogs/codegenerationpolicypage.h"
+#include "javacodegenerationformbase.h"
+
+#include "javacodegenerationpolicy.h"
+
+/**
+ * @author Brian Thomas
+ */
+
+class JavaCodeGenerationPolicyPage : public CodeGenerationPolicyPage {
+ Q_OBJECT
+public:
+
+ explicit JavaCodeGenerationPolicyPage (QWidget *parent=0, const char *name=0, JavaCodeGenerationPolicy * policy = 0);
+
+ virtual ~JavaCodeGenerationPolicyPage();
+
+protected:
+
+ JavaCodeGenerationFormBase * form;
+
+public slots:
+
+ void apply();
+
+};
+
+#endif
+
diff --git a/umbrello/umbrello/codegenerators/javacodegenerator.cpp b/umbrello/umbrello/codegenerators/javacodegenerator.cpp
new file mode 100644
index 00000000..167804af
--- /dev/null
+++ b/umbrello/umbrello/codegenerators/javacodegenerator.cpp
@@ -0,0 +1,339 @@
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * copyright (C) 2004-2006 *
+ * Umbrello UML Modeller Authors <uml-devel@uml.sf.net> *
+ ***************************************************************************/
+
+/* This code generated by:
+ * Author : thomas
+ * Date : Thu Jun 19 2003
+ */
+
+// own header
+#include "javacodegenerator.h"
+
+// qt/kde includes
+#include <qregexp.h>
+#include <kconfig.h>
+#include <kdebug.h>
+#include <klocale.h>
+#include <kmessagebox.h>
+
+// local includes
+#include "javacodecomment.h"
+#include "codeviewerdialog.h"
+#include "../uml.h"
+
+const bool JavaCodeGenerator::DEFAULT_BUILD_ANT_DOC = false;
+
+// Constructors/Destructors
+//
+
+JavaCodeGenerator::JavaCodeGenerator (QDomElement & elem)
+ : CodeGenerator(elem)
+{
+ init();
+}
+
+JavaCodeGenerator::JavaCodeGenerator ()
+{
+ init();
+}
+
+JavaCodeGenerator::~JavaCodeGenerator ( ) { }
+
+//
+// Methods
+//
+
+// Accessor methods
+//
+
+// return our language
+Uml::Programming_Language JavaCodeGenerator::getLanguage() {
+ return Uml::pl_Java;
+}
+
+/**
+ * Set the value of m_createANTBuildFile
+ * @param new_var the new value of m_createANTBuildFile
+ */
+void JavaCodeGenerator::setCreateANTBuildFile ( bool buildIt) {
+ m_createANTBuildFile = buildIt;
+ CodeDocument * antDoc = findCodeDocumentByID("ANTDOC");
+ if (antDoc)
+ antDoc->setWriteOutCode(buildIt);
+}
+
+/**
+ * Get the value of m_createANTBuildFile
+ * @return the value of m_createANTBuildFile
+ */
+bool JavaCodeGenerator::getCreateANTBuildFile ( ) {
+ return m_createANTBuildFile;
+}
+
+// In the Java version, we make the ANT build file also available.
+CodeViewerDialog * JavaCodeGenerator::getCodeViewerDialog ( QWidget* parent, CodeDocument *doc,
+ Settings::CodeViewerState state)
+{
+ CodeViewerDialog *dialog = new CodeViewerDialog(parent, doc, state);
+ if(getCreateANTBuildFile())
+ dialog->addCodeDocument(findCodeDocumentByID("ANTDOC"));
+ return dialog;
+}
+
+
+JavaCodeGenerationPolicy * JavaCodeGenerator::getJavaPolicy() {
+ return dynamic_cast<JavaCodeGenerationPolicy*>(UMLApp::app()->getPolicyExt());
+}
+
+bool JavaCodeGenerator::getAutoGenerateAttribAccessors ( )
+{
+ return getJavaPolicy()->getAutoGenerateAttribAccessors ();
+}
+
+bool JavaCodeGenerator::getAutoGenerateAssocAccessors ( )
+{
+ return getJavaPolicy()->getAutoGenerateAssocAccessors ();
+}
+
+QString JavaCodeGenerator::getListFieldClassName () {
+ return QString("Vector");
+}
+
+// Other methods
+//
+
+// IF the type is "string" we need to declare it as
+// the Java Object "String" (there is no string primative in Java).
+// Same thing again for "bool" to "boolean"
+QString JavaCodeGenerator::fixTypeName(const QString &string)
+{
+ if (string.isEmpty() || string.contains(QRegExp("^\\s+$")))
+ return "void";
+ if (string == "string")
+ return "String";
+ if (string == "bool")
+ return "boolean";
+ return cleanName(string);
+}
+
+/**
+ * @return JavaANTCodeDocument
+ */
+JavaANTCodeDocument * JavaCodeGenerator::newANTCodeDocument ( ) {
+ return new JavaANTCodeDocument();
+}
+
+/**
+ * @return ClassifierCodeDocument
+ * @param classifier
+ */
+CodeDocument * JavaCodeGenerator::newClassifierCodeDocument ( UMLClassifier * c)
+{
+ JavaClassifierCodeDocument * doc = new JavaClassifierCodeDocument(c);
+ doc->initCodeClassFields();
+ return doc;
+}
+
+void JavaCodeGenerator::init() {
+ // load Classifier documents from parent document
+ //initFromParentDocument();
+
+ // add in an ANT document
+ JavaANTCodeDocument * buildDoc = newANTCodeDocument( );
+ addCodeDocument(buildDoc);
+
+ // set our 'writeout' policy for that code document
+ setCreateANTBuildFile(DEFAULT_BUILD_ANT_DOC);
+}
+
+QStringList JavaCodeGenerator::defaultDatatypes() {
+ QStringList l;
+ l.append("int");
+ l.append("char");
+ l.append("boolean");
+ l.append("float");
+ l.append("double");
+ l.append("byte");
+ l.append("short");
+ l.append("long");
+ l.append("String");
+ return l;
+}
+
+const QStringList JavaCodeGenerator::reservedKeywords() const {
+
+ static QStringList keywords;
+
+ if (keywords.isEmpty()) {
+ keywords << "abstract"
+ << "AbstractMethodError"
+ << "ArithmeticException"
+ << "ArrayIndexOutOfBoundsException"
+ << "ArrayStoreException"
+ << "assert"
+ << "AssertionError"
+ << "auto"
+ << "boolean"
+ << "Boolean"
+ << "break"
+ << "byte"
+ << "Byte"
+ << "catch"
+ << "char"
+ << "Character"
+ << "CharSequence"
+ << "Class"
+ << "ClassCastException"
+ << "ClassCircularityError"
+ << "ClassFormatError"
+ << "ClassLoader"
+ << "ClassNotFoundException"
+ << "clone"
+ << "Cloneable"
+ << "CloneNotSupportedException"
+ << "Comparable"
+ << "Compiler"
+ << "const"
+ << "continue"
+ << "default"
+ << "delete"
+ << "do"
+ << "double"
+ << "Double"
+ << "else"
+ << "enum"
+ << "equals"
+ << "Error"
+ << "Exception"
+ << "ExceptionInInitializerError"
+ << "extends"
+ << "extern"
+ << "false"
+ << "final"
+ << "finalize"
+ << "finally"
+ << "float"
+ << "Float"
+ << "for"
+ << "friend"
+ << "getClass"
+ << "goto"
+ << "hashCode"
+ << "if"
+ << "IllegalAccessError"
+ << "IllegalAccessException"
+ << "IllegalArgumentException"
+ << "IllegalMonitorStateException"
+ << "IllegalStateException"
+ << "IllegalThreadStateException"
+ << "implements"
+ << "import"
+ << "IncompatibleClassChangeError"
+ << "IndexOutOfBoundsException"
+ << "InheritableThreadLocal"
+ << "inline"
+ << "instanceof"
+ << "InstantiationError"
+ << "InstantiationException"
+ << "int"
+ << "Integer"
+ << "interface"
+ << "InternalError"
+ << "InterruptedException"
+ << "LinkageError"
+ << "long"
+ << "Long"
+ << "Math"
+ << "native"
+ << "NegativeArraySizeException"
+ << "new"
+ << "nextgroup=javaUserLabelRef"
+ << "NoClassDefFoundError"
+ << "NoSuchFieldError"
+ << "NoSuchFieldException"
+ << "NoSuchMethodError"
+ << "NoSuchMethodException"
+ << "notify"
+ << "notifyAll"
+ << "null"
+ << "NullPointerException"
+ << "Number"
+ << "NumberFormatException"
+ << "Object"
+ << "operator"
+ << "OutOfMemoryError"
+ << "package"
+ << "Package"
+ << "private"
+ << "Process"
+ << "protected"
+ << "public"
+ << "redeclared"
+ << "register"
+ << "return"
+ << "Runnable"
+ << "Runtime"
+ << "RuntimeException"
+ << "RuntimePermission"
+ << "SecurityException"
+ << "SecurityManager"
+ << "serializable"
+ << "short"
+ << "Short"
+ << "signed"
+ << "sizeof"
+ << "skipwhite"
+ << "StackOverflowError"
+ << "StackTraceElement"
+ << "static"
+ << "strictfp"
+ << "StrictMath"
+ << "String"
+ << "StringBuffer"
+ << "StringIndexOutOfBoundsException"
+ << "struct"
+ << "super"
+ << "switch"
+ << "synchronized"
+ << "template"
+ << "this"
+ << "Thread"
+ << "ThreadDeath"
+ << "ThreadGroup"
+ << "ThreadLocal"
+ << "throw"
+ << "Throwable"
+ << "throws"
+ << "toString"
+ << "transient"
+ << "true"
+ << "try"
+ << "typedef"
+ << "union"
+ << "UnknownError"
+ << "UnsatisfiedLinkError"
+ << "unsigned"
+ << "UnsupportedClassVersionError"
+ << "UnsupportedOperationException"
+ << "VerifyError"
+ << "VirtualMachineError"
+ << "void"
+ << "Void"
+ << "volatile"
+ << "wait"
+ << "while";
+ }
+
+ return keywords;
+}
+
+#include "javacodegenerator.moc"
+
diff --git a/umbrello/umbrello/codegenerators/javacodegenerator.h b/umbrello/umbrello/codegenerators/javacodegenerator.h
new file mode 100644
index 00000000..29edb16f
--- /dev/null
+++ b/umbrello/umbrello/codegenerators/javacodegenerator.h
@@ -0,0 +1,150 @@
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * copyright (C) 2004-2006 *
+ * Umbrello UML Modeller Authors <uml-devel@uml.sf.net> *
+ ***************************************************************************/
+
+/* This code generated by:
+ * Author : thomas
+ * Date : Thu Jun 19 2003
+ */
+
+
+
+#ifndef JAVACODEGENERATOR_H
+#define JAVACODEGENERATOR_H
+
+#include <qstring.h>
+#include "../codeviewerstate.h"
+#include "../codegenerator.h"
+#include "../codeblockwithcomments.h"
+#include "../umldoc.h"
+
+#include "classifierinfo.h"
+#include "javaclassifiercodedocument.h"
+#include "javaantcodedocument.h"
+
+#include "javacodegenerationpolicy.h"
+
+class CodeViewerDialog;
+
+class JavaCodeGenerator : public CodeGenerator
+{
+ Q_OBJECT
+public:
+
+ // Constructors/Destructors
+ //
+
+ static const bool DEFAULT_BUILD_ANT_DOC;
+
+ /**
+ * Empty Constructor
+ */
+ JavaCodeGenerator ();
+ JavaCodeGenerator (QDomElement & element);
+
+ /**
+ * Empty Destructor
+ */
+ virtual ~JavaCodeGenerator ( );
+
+ // Public attributes
+ //
+
+
+ // Public attribute accessor methods
+ //
+
+
+ /**
+ * Set the value of m_createANTBuildFile
+ * @param new_var the new value of m_createANTBuildFile
+ */
+ void setCreateANTBuildFile ( bool new_var );
+
+ /**
+ * Get the value of m_createANTBuildFile
+ * @return the value of m_createANTBuildFile
+ */
+ bool getCreateANTBuildFile ( );
+
+ /**
+ * A utility method to get the javaCodeGenerationPolicy()->getAutoGenerateAttribAccessors() value.
+ */
+ bool getAutoGenerateAttribAccessors( );
+
+ /**
+ * A utility method to get the javaCodeGenerationPolicy()->getAutoGenerateAssocAccessors() value.
+ */
+ bool getAutoGenerateAssocAccessors( );
+
+ /**
+ * Get the list variable class name to use. For Java, we have set this to "Vector".
+ */
+ static QString getListFieldClassName();
+
+ /** Get the editing dialog for this code document
+ */
+ virtual CodeViewerDialog * getCodeViewerDialog( QWidget* parent, CodeDocument * doc,
+ Settings::CodeViewerState state);
+
+ // Other methods
+ //
+
+ /**
+ * Utility function for getting the java code generation policy.
+ */
+ JavaCodeGenerationPolicy * getJavaPolicy();
+
+ /**
+ * @return ClassifierCodeDocument
+ * @param classifier
+ */
+ CodeDocument * newClassifierCodeDocument (UMLClassifier * classifier);
+
+ // return "Java"
+ Uml::Programming_Language getLanguage();
+
+ /**
+ * Adds Java's primitives as datatypes
+ */
+ virtual QStringList defaultDatatypes();
+
+ /**
+ * IF the type is "string" we need to declare it as
+ * the Java Object "String" (there is no string primative in Java).
+ * Same thing again for "bool" to "boolean".
+ */
+ static QString fixTypeName(const QString &string);
+
+ /**
+ * get list of reserved keywords
+ */
+ virtual const QStringList reservedKeywords() const;
+
+protected:
+
+ /** create the codeblock that will represent the class declaration
+ * for this classifier
+ */
+ CodeBlockWithComments * createClassDecl ( UMLClassifier *c, ClassifierInfo *info, JavaClassifierCodeDocument * doc);
+
+ /**
+ * @return JavaANTCodeDocument
+ */
+ JavaANTCodeDocument * newANTCodeDocument ( );
+
+private:
+
+ void init();
+
+ bool m_createANTBuildFile;
+};
+
+#endif // JAVACODEGENERATOR_H
diff --git a/umbrello/umbrello/codegenerators/javacodeoperation.cpp b/umbrello/umbrello/codegenerators/javacodeoperation.cpp
new file mode 100644
index 00000000..84ce0331
--- /dev/null
+++ b/umbrello/umbrello/codegenerators/javacodeoperation.cpp
@@ -0,0 +1,132 @@
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * copyright (C) 2004-2006 *
+ * Umbrello UML Modeller Authors <uml-devel@uml.sf.net> *
+ ***************************************************************************/
+
+/* This code generated by:
+ * Author : thomas
+ * Date : Mon Jun 30 2003
+ */
+
+#include "javacodeoperation.h"
+
+#include "javaclassifiercodedocument.h"
+#include "javacodedocumentation.h"
+#include "javacodegenerator.h"
+#include "../uml.h"
+
+// Constructors/Destructors
+//
+
+JavaCodeOperation::JavaCodeOperation
+ ( JavaClassifierCodeDocument * doc, UMLOperation *parent, const QString & body, const QString & comment )
+ : CodeOperation (doc, parent, body, comment)
+{
+ // lets not go with the default comment and instead use
+ // full-blown java documentation object instead
+ setComment(new JavaCodeDocumentation(doc));
+
+ // these things never change..
+ setOverallIndentationLevel(1);
+
+ updateMethodDeclaration();
+ updateContent();
+}
+
+JavaCodeOperation::~JavaCodeOperation ( ) { }
+
+// Other methods
+//
+
+// we basically want to update the doc and start text of this method
+void JavaCodeOperation::updateMethodDeclaration()
+{
+
+ CodeDocument * doc = getParentDocument();
+ JavaClassifierCodeDocument * javadoc = dynamic_cast<JavaClassifierCodeDocument*>(doc);
+ UMLOperation * o = getParentOperation();
+ bool isInterface = javadoc->getParentClassifier()->isInterface();
+ QString endLine = getNewLineEndingChars();
+
+ // now, the starting text.
+ QString strVis = javadoc->scopeToJavaDecl(o->getVisibility());
+ // no return type for constructors
+ QString fixedReturn = JavaCodeGenerator::fixTypeName(o->getTypeName());
+ QString returnType = o->isConstructorOperation() ? QString("") : (fixedReturn + QString(" "));
+ QString methodName = o->getName();
+ QString paramStr = QString("");
+
+ // assemble parameters
+ UMLAttributeList list = getParentOperation()->getParmList();
+ int nrofParam = list.count();
+ int paramNum = 0;
+ for(UMLAttribute* parm = list.first(); parm; parm=list.next())
+ {
+ QString rType = parm->getTypeName();
+ QString paramName = parm->getName();
+ paramStr += rType + ' ' + paramName;
+ paramNum++;
+
+ if (paramNum != nrofParam )
+ paramStr += ", ";
+ }
+ QString maybeStatic;
+ if (o->getStatic())
+ maybeStatic = "static ";
+ QString startText = strVis + ' ' + maybeStatic + returnType + methodName + " (" + paramStr + ')';
+
+ // IF the parent is an interface, our operations look different
+ // e.g. they have no body
+ if(isInterface) {
+ startText += ';';
+ setEndMethodText("");
+ } else {
+ startText += " {";
+ setEndMethodText("}");
+ }
+
+ setStartMethodText(startText);
+
+ // Lastly, for text content generation, we fix the comment on the
+ // operation, IF the codeop is autogenerated & currently empty
+ QString comment = o->getDoc();
+ if(comment.isEmpty() && getContentType() == CodeBlock::AutoGenerated)
+ {
+ UMLAttributeList parameters = o->getParmList();
+ for(UMLAttributeListIt iterator(parameters); iterator.current(); ++iterator) {
+ comment += endLine + "@param " + iterator.current()->getName() + ' ';
+ comment += iterator.current()->getDoc();
+ }
+ // add a returns statement too
+ if(!returnType.isEmpty())
+ comment += endLine + "@return " + returnType + ' ';
+ getComment()->setText(comment);
+ }
+
+
+ // In Java, for interfaces..we DON'T write out non-public
+ // method declarations.
+ if(isInterface)
+ {
+ UMLOperation * o = getParentOperation();
+ if(o->getVisibility() != Uml::Visibility::Public)
+ setWriteOutText(false);
+ }
+
+}
+
+int JavaCodeOperation::lastEditableLine() {
+ ClassifierCodeDocument * doc = dynamic_cast<ClassifierCodeDocument*>(getParentDocument());
+ if(doc->parentIsInterface())
+ return -1; // very last line is NOT editable as its a one-line declaration w/ no body in
+ // an interface.
+ return 0;
+}
+
+#include "javacodeoperation.moc"
diff --git a/umbrello/umbrello/codegenerators/javacodeoperation.h b/umbrello/umbrello/codegenerators/javacodeoperation.h
new file mode 100644
index 00000000..08a555d8
--- /dev/null
+++ b/umbrello/umbrello/codegenerators/javacodeoperation.h
@@ -0,0 +1,52 @@
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * copyright (C) 2004-2006 *
+ * Umbrello UML Modeller Authors <uml-devel@uml.sf.net> *
+ ***************************************************************************/
+
+/* This code generated by:
+ * Author : thomas
+ * Date : Mon Jun 30 2003
+ */
+
+
+#ifndef JAVACODEOPERATION_H
+#define JAVACODEOPERATION_H
+
+#include <qstring.h>
+#include "../codeoperation.h"
+
+class JavaClassifierCodeDocument;
+
+class JavaCodeOperation : virtual public CodeOperation
+{
+ Q_OBJECT
+public:
+
+ // Constructors/Destructors
+ //
+
+ /**
+ * Empty Constructor
+ */
+ JavaCodeOperation ( JavaClassifierCodeDocument * doc, UMLOperation * op, const QString & body = "", const QString & comment = "");
+
+ /**
+ * Empty Destructor
+ */
+ virtual ~JavaCodeOperation ( );
+
+ virtual int lastEditableLine();
+
+protected:
+
+ void updateMethodDeclaration();
+
+};
+
+#endif // JAVACODEOPERATION_H
diff --git a/umbrello/umbrello/codegenerators/javawriter.cpp b/umbrello/umbrello/codegenerators/javawriter.cpp
new file mode 100644
index 00000000..3e945c60
--- /dev/null
+++ b/umbrello/umbrello/codegenerators/javawriter.cpp
@@ -0,0 +1,936 @@
+/***************************************************************************
+ javawriter.cpp - description
+ This is the "old" code generator that does not support code editing
+ in the Modeller but uses significantly less file space because the
+ source code is not replicated in the XMI file.
+ -------------------
+ copyright : (C) 2003 Brian Thomas brian.thomas@gsfc.nasa.gov
+ (C) 2004-2006 Umbrello UML Modeller Authors <uml-devel@uml.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. *
+ * *
+ ***************************************************************************/
+
+// own header
+#include "javawriter.h"
+// qt includes
+#include <qfile.h>
+#include <qtextstream.h>
+#include <qregexp.h>
+// kde includes
+#include <kdebug.h>
+// app includes
+#include "codegen_utils.h"
+#include "../umldoc.h"
+#include "../classifier.h"
+#include "../operation.h"
+#include "../attribute.h"
+#include "../association.h"
+#include "../template.h"
+#include "../umltemplatelist.h"
+
+JavaWriter::JavaWriter() {
+ startline = m_endl + m_indentation;
+}
+
+JavaWriter::~JavaWriter() {}
+
+Uml::Programming_Language JavaWriter::getLanguage() {
+ return Uml::pl_Java;
+}
+
+void JavaWriter::writeClass(UMLClassifier *c)
+{
+
+ if (!c) {
+ kDebug()<<"Cannot write class of NULL concept!\n";
+ return;
+ }
+
+ isInterface = c->isInterface();
+
+ QString fileName = cleanName(c->getName().lower());
+
+ //find an appropriate name for our file
+ fileName = findFileName(c,".java");
+ if (fileName.isEmpty()) {
+ emit codeGenerated(c, false);
+ return;
+ }
+
+ // check that we may open that file for writing
+ QFile file;
+ if ( !openFile(file, fileName) ) {
+ emit codeGenerated(c, false);
+ return;
+ }
+
+ // Preparations
+ //
+
+ // sort attributes by Scope
+ UMLAttributeList atl;
+ UMLAttributeList atpub, atprot, atpriv;
+ UMLAttributeList final_atpub, final_atprot, final_atpriv;
+ atpub.setAutoDelete(false);
+ final_atpub.setAutoDelete(false);
+ atprot.setAutoDelete(false);
+ final_atprot.setAutoDelete(false);
+ atpriv.setAutoDelete(false);
+ final_atpriv.setAutoDelete(false);
+
+ if (!isInterface) {
+ UMLAttributeList atl = c->getAttributeList();
+ for (UMLAttribute *at = atl.first(); at ; at = atl.next()) {
+ switch(at->getVisibility())
+ {
+ case Uml::Visibility::Public:
+ if(at->getStatic())
+ final_atpub.append(at);
+ else
+ atpub.append(at);
+ break;
+ case Uml::Visibility::Protected:
+ if(at->getStatic())
+ final_atprot.append(at);
+ else
+ atprot.append(at);
+ break;
+ case Uml::Visibility::Private:
+ if(at->getStatic())
+ final_atpriv.append(at);
+ else
+ atpriv.append(at);
+ break;
+ default:
+ break;
+ }
+ }
+ }
+
+ // another preparation, determine what we have
+ UMLAssociationList associations = c->getSpecificAssocs(Uml::at_Association); // BAD! only way to get "general" associations.
+ UMLAssociationList uniAssociations = c->getUniAssociationToBeImplemented();
+
+ UMLAssociationList aggregations = c->getAggregations();
+ UMLAssociationList compositions = c->getCompositions();
+
+ bool hasAssociations = aggregations.count() > 0 || associations.count() > 0 || compositions.count() > 0 || uniAssociations.count() > 0;
+ bool hasAttributes = (atl.count() > 0);
+ bool hasAccessorMethods = hasAttributes || hasAssociations;
+ bool hasOperationMethods = (c->getOpList().count() > 0);
+ // this is a bit too simplistic..some associations are for
+ // SINGLE objects, and WONT be declared as Vectors, so this
+ // is a bit overly inclusive
+ bool hasVectorFields = hasAssociations ? true : false;
+
+ // open text stream to file
+ QTextStream java(&file);
+
+ //try to find a heading file (license, coments, etc)
+ QString str;
+ str = getHeadingFile(".java");
+ if(!str.isEmpty()) {
+ str.replace(QRegExp("%filename%"),fileName);
+ str.replace(QRegExp("%filepath%"),file.name());
+ java<<str<<m_endl;
+ }
+
+ if(!c->getPackage().isEmpty())
+ java<<"package "<<c->getPackage()<<";"<<m_endl;
+
+ // IMPORT statements
+ // Q: Why all utils? Isnt just List and Vector the only classes we are using?
+ // A: doesn't matter at all; its more readable to just include '*' and java compilers
+ // don't slow down or anything. (TZ)
+ if (hasVectorFields )
+ {
+ writeBlankLine(java);
+ java<<"import java.util.*;"<<m_endl;
+ }
+
+ //only import classes in a different package as this class
+ UMLPackageList imports;
+ findObjectsRelated(c,imports);
+ for (UMLPackage *con = imports.first(); con; con = imports.next()) {
+ if (con->getBaseType() == Uml::ot_Datatype)
+ continue;
+ QString pkg = con->getPackage();
+ if (!pkg.isEmpty() && pkg != c->getPackage())
+ java << "import " << pkg << "." << cleanName(con->getName()) << ";"
+ << m_endl;
+ }
+ writeBlankLine(java);
+
+ // write the opening declaration for the class incl any documentation,
+ // interfaces and/or inheritence issues we have
+ writeClassDecl(c, java);
+
+ // start body of class
+ java<<" {"<<m_endl;
+
+ // ATTRIBUTES
+ //
+
+ // write comment for section IF needed
+ if (forceDoc() || hasAccessorMethods)
+ {
+ writeComment("", m_indentation, java);
+ writeComment("Fields", m_indentation, java);
+ writeComment("", m_indentation, java);
+ writeBlankLine(java);
+ }
+
+ writeAttributeDecls(final_atpub, final_atprot, final_atpriv, java);
+ writeAttributeDecls(atpub, atprot, atpriv, java);
+
+ writeAssociationDecls(associations, c->getID(), java);
+ writeAssociationDecls(uniAssociations, c->getID(), java);
+ writeAssociationDecls(aggregations, c->getID(), java);
+ writeAssociationDecls(compositions, c->getID(), java);
+
+ // Constructors: anything we more we need to do here ?
+ //
+ if(!isInterface)
+ writeConstructor(c, java);
+
+ // METHODS
+ //
+
+ // write comment for section IF needed
+ if (forceDoc() || hasAccessorMethods || hasOperationMethods)
+ {
+
+ java<<startline;
+ writeComment("", m_indentation, java);
+ writeComment("Methods", m_indentation, java);
+ writeComment("", m_indentation, java);
+ writeBlankLine(java);
+ writeBlankLine(java);
+ }
+
+ // write comment for sub-section IF needed
+ if (forceDoc() || hasAccessorMethods )
+ {
+ writeComment("", m_indentation, java);
+ writeComment("Accessor methods", m_indentation, java);
+ writeComment("", m_indentation, java);
+ writeBlankLine(java);
+ }
+
+ // Accessors for attributes
+ writeAttributeMethods(final_atpub, Uml::Visibility::Public, java);
+ writeAttributeMethods(final_atprot, Uml::Visibility::Protected, java);
+ writeAttributeMethods(final_atpriv, Uml::Visibility::Private, java);
+ writeAttributeMethods(atpub, Uml::Visibility::Public, java);
+ writeAttributeMethods(atprot, Uml::Visibility::Protected, java);
+ writeAttributeMethods(atpriv, Uml::Visibility::Private, java);
+
+ // accessor methods for associations
+
+ // first: determine the name of the other class
+ writeAssociationMethods(associations, c, java);
+ writeAssociationMethods(uniAssociations, c, java);
+ writeAssociationMethods(aggregations, c, java);
+ writeAssociationMethods(compositions, c, java);
+
+ // Other operation methods
+ // all other operations are now written
+
+ // write comment for sub-section IF needed
+ if (forceDoc() || hasOperationMethods)
+ {
+ writeComment("", m_indentation, java);
+ writeComment("Other methods", m_indentation, java);
+ writeComment("", m_indentation, java);
+ writeBlankLine(java);
+ }
+ writeOperations(c,java);
+
+ writeBlankLine(java);
+ java<<"}"<<m_endl; // end class
+
+ file.close();
+ emit codeGenerated(c, true);
+}
+
+void JavaWriter::writeClassDecl(UMLClassifier *c, QTextStream &java)
+{
+
+ QString classname = cleanName(c->getName()); // our class name
+
+ // write documentation for class, if any, first
+ if(forceDoc() || !c->getDoc().isEmpty())
+ {
+ if(isInterface)
+ writeDocumentation("Interface "+classname,c->getDoc(),"","",java);
+ else
+ writeDocumentation("Class "+classname,c->getDoc(),"","",java);
+
+ writeBlankLine(java);
+ }
+
+ // Now write the actual class declaration
+ QString scope = ""; // = scopeToJavaDecl(c->getVisibility());
+ if (c->getVisibility() != Uml::Visibility::Public) {
+ // We should emit a warning in here .. java doesn't like to allow
+ // private/protected classes. The best we can do (I believe)
+ // is to let these declarations default to "package visibility"
+ // which is a level between traditional "private" and "protected"
+ // scopes. To get this visibility level we just print nothing..
+ } else
+ scope = "public ";
+
+ java<<((c->getAbstract() && !isInterface) ? QString("abstract ") : QString(""))<<scope;
+ if(isInterface)
+ java<<"interface ";
+ else
+ java<<"class ";
+
+ java<<classname;
+
+ // Generics
+ UMLTemplateList template_params = c->getTemplateList();
+ if (template_params.count()) {
+ java << "<";
+ for (UMLTemplate *t = template_params.first(); t; ) {
+ QString formalName = t->getName();
+ java << formalName;
+ QString typeName = t->getTypeName();
+ if (typeName != "class") {
+ java << " extends " << typeName;
+ }
+ if ((t = template_params.next()) != NULL)
+ java << ", ";
+ }
+ java << ">" << m_endl;
+ }
+
+ // write inheritances out
+ UMLClassifier *concept;
+ UMLClassifierList superclasses = c->findSuperClassConcepts(UMLClassifier::CLASS);
+
+ int i = 0;
+ for (concept= superclasses.first(); concept; concept = superclasses.next())
+ {
+ if (i == 0)
+ {
+ java<< " extends ";
+ }
+ else
+ {
+ //The java generated code is wrong ! : No multiple inheritence of class
+ java<< ", " ;
+ }
+ java<< cleanName(concept->getName());
+ i++;
+ }
+
+ UMLClassifierList superInterfaces = c->findSuperClassConcepts(UMLClassifier::INTERFACE);
+ i = 0;
+ for (concept= superInterfaces.first(); concept; concept = superInterfaces.next())
+ {
+ if (i == 0)
+ {
+ if (isInterface)
+ java<< " extends ";
+ else
+ java<< " implements ";
+ }
+ else
+ {
+ //The java generated code is OK ! : multiple inheritence of interface
+ java<< ", " ;
+ }
+ java<< cleanName(concept->getName());
+ i++;
+ }
+
+}
+
+void JavaWriter::writeAttributeDecls(UMLAttributeList &atpub, UMLAttributeList &atprot,
+ UMLAttributeList &atpriv, QTextStream &java )
+{
+ UMLAttribute *at;
+
+ for(at=atpub.first(); at; at=atpub.next())
+ {
+ QString documentation = at->getDoc();
+ QString staticValue = at->getStatic() ? "static " : "";
+ QString typeName = fixTypeName(at->getTypeName());
+ QString initialValue = fixInitialStringDeclValue(at->getInitialValue(), typeName);
+ if(!documentation.isEmpty())
+ writeComment(documentation, m_indentation, java, true);
+ java<<startline<<staticValue<<"public "<<typeName<<" "<<cleanName(at->getName())
+ <<(initialValue.isEmpty()?QString(""):QString(" = ") + initialValue)<<";";
+ }
+
+ for(at=atprot.first();at;at=atprot.next())
+ {
+ QString documentation = at->getDoc();
+ QString typeName = fixTypeName(at->getTypeName());
+ QString staticValue = at->getStatic() ? "static " : "";
+ QString initialValue = fixInitialStringDeclValue(at->getInitialValue(), typeName);
+ if(!documentation.isEmpty())
+ writeComment(documentation, m_indentation, java, true);
+ java<<startline<<staticValue<<"protected "<<typeName<<" "<<cleanName(at->getName())
+ <<(initialValue.isEmpty()?QString(""):QString(" = ") + initialValue)<<";";
+ }
+
+ for(at=atpriv.first();at;at=atpriv.next())
+ {
+ QString documentation = at->getDoc();
+ QString typeName = fixTypeName(at->getTypeName());
+ QString staticValue = at->getStatic() ? "static " : "";
+ QString initialValue = fixInitialStringDeclValue(at->getInitialValue(), typeName);
+ if(!documentation.isEmpty())
+ writeComment(documentation, m_indentation, java, true);
+ java<<startline<<staticValue<<"private "<<typeName<<" "<<cleanName(at->getName())
+ <<(initialValue.isEmpty()?QString(""):QString(" = ") + initialValue)<<";";
+ }
+
+}
+
+void JavaWriter::writeAttributeMethods(UMLAttributeList &atpub, Uml::Visibility visibility, QTextStream &java)
+{
+
+ UMLAttribute *at;
+ for(at=atpub.first(); at; at=atpub.next())
+ {
+ QString fieldName = cleanName(at->getName());
+ // force capitalizing the field name, this is silly,
+ // from what I can tell, this IS the default behavior for
+ // cleanName. I dunno why its not working -b.t.
+ fieldName.stripWhiteSpace();
+ fieldName.replace(0,1,fieldName.at(0).upper());
+
+ writeSingleAttributeAccessorMethods(at->getTypeName(),
+ cleanName(at->getName()),
+ fieldName,
+ at->getDoc(),
+ visibility, Uml::chg_Changeable, at->getStatic(), java);
+ }
+
+}
+
+void JavaWriter::writeComment(const QString &comment, const QString &myIndent,
+ QTextStream &java, bool javaDocStyle)
+{
+ // in the case we have several line comment..
+ // NOTE: this part of the method has the problem of adopting UNIX newline,
+ // need to resolve for using with MAC/WinDoze eventually I assume
+ if (comment.contains(QRegExp("\n"))) {
+
+ if(javaDocStyle)
+ java << myIndent << "/**" << m_endl;
+ QStringList lines = QStringList::split( "\n", comment);
+ for(uint i= 0; i < lines.count(); i++)
+ {
+ writeBlankLine(java);
+ if(javaDocStyle)
+ java<<myIndent<<" * ";
+ else
+ java<<myIndent<<"// ";
+ java << lines[i];
+ }
+ if(javaDocStyle)
+ java << myIndent << " */" << m_endl;
+ } else {
+ // this should be more fancy in the future, breaking it up into 80 char
+ // lines so that it doesn't look too bad
+ writeBlankLine(java);
+ if(javaDocStyle)
+ java << myIndent << "/**" << m_endl << myIndent << " *";
+ else
+ java<<myIndent<<"//";
+ if(comment.length() > 0)
+ java << " " << comment;
+ if(javaDocStyle)
+ java << m_endl << myIndent << " */";
+ }
+}
+
+void JavaWriter::writeDocumentation(QString header, QString body, QString end, QString indent, QTextStream &java)
+{
+ writeBlankLine(java);
+ java<<indent<<"/**"<<m_endl;
+ if (!header.isEmpty())
+ java<<formatDoc(header, indent+" * ");
+ if (!body.isEmpty())
+ java<<formatDoc(body, indent+" * ");
+ if (!end.isEmpty())
+ {
+ QStringList lines = QStringList::split( "\n", end);
+ for(uint i= 0; i < lines.count(); i++)
+ java<<formatDoc(lines[i], indent+" * ");
+ }
+ java<<indent<<" */";
+}
+
+void JavaWriter::writeAssociationDecls(UMLAssociationList associations, Uml::IDType id, QTextStream &java)
+{
+
+ if( forceSections() || !associations.isEmpty() )
+ {
+ bool printRoleA = false, printRoleB = false;
+ for(UMLAssociation *a = associations.first(); a; a = associations.next())
+ {
+ // it may seem counter intuitive, but you want to insert the role of the
+ // *other* class into *this* class.
+ if (a->getObjectId(Uml::A) == id)
+ printRoleB = true;
+
+ if (a->getObjectId(Uml::B) == id)
+ printRoleA = true;
+
+ // First: we insert documentaion for association IF it has either role AND some documentation (!)
+ if ((printRoleA || printRoleB) && !(a->getDoc().isEmpty()))
+ writeComment(a->getDoc(), m_indentation, java);
+
+ // print RoleB decl
+ if (printRoleB)
+ {
+ QString fieldClassName = cleanName(getUMLObjectName(a->getObject(Uml::B)));
+ writeAssociationRoleDecl(fieldClassName, a->getRoleName(Uml::B), a->getMulti(Uml::B), a->getRoleDoc(Uml::B), a->getVisibility(Uml::B), java);
+ }
+
+ // print RoleA decl
+ if (printRoleA)
+ {
+ QString fieldClassName = cleanName(getUMLObjectName(a->getObject(Uml::A)));
+ writeAssociationRoleDecl(fieldClassName, a->getRoleName(Uml::A), a->getMulti(Uml::A), a->getRoleDoc(Uml::A), a->getVisibility(Uml::A), java);
+ }
+ }
+ }
+}
+
+void JavaWriter::writeAssociationRoleDecl(QString fieldClassName,
+ QString roleName, QString multi,
+ QString doc, Uml::Visibility visib, QTextStream &java)
+{
+ // ONLY write out IF there is a rolename given
+ // otherwise its not meant to be declared in the code
+ if (roleName.isEmpty())
+ return;
+
+ QString scope = scopeToJavaDecl(visib);
+
+ // always put space between this and prior decl, if any
+ writeBlankLine(java);
+
+ if (!doc.isEmpty())
+ writeComment(doc, m_indentation, java);
+
+ // declare the association based on whether it is this a single variable
+ // or a List (Vector). One day this will be done correctly with special
+ // multiplicity object that we don't have to figure out what it means via regex.
+ if(multi.isEmpty() || multi.contains(QRegExp("^[01]$")))
+ {
+ QString fieldVarName = "m_" + roleName.replace(0, 1, roleName.left(1).lower());
+ java<<startline<<scope<<" "<<fieldClassName<<" "<<fieldVarName<<";";
+ }
+ else
+ {
+ QString fieldVarName = roleName.lower() + "Vector";
+ java<<startline<<scope<<" Vector "<<fieldVarName<<" = new Vector();";
+ // from here we could initialize default values, or put in an init() section
+ // of the constructors
+ }
+
+}
+
+void JavaWriter::writeAssociationMethods (UMLAssociationList associations, UMLClassifier *thisClass, QTextStream &java)
+{
+ if( forceSections() || !associations.isEmpty() )
+ {
+ for(UMLAssociation *a = associations.first(); a; a = associations.next())
+ {
+
+ // insert the methods to access the role of the other
+ // class in the code of this one
+ if (a->getObjectId(Uml::A) == thisClass->getID())
+ {
+ // only write out IF there is a rolename given
+ if(!a->getRoleName(Uml::B).isEmpty()) {
+ QString fieldClassName = getUMLObjectName(a->getObject(Uml::B));
+ writeAssociationRoleMethod(fieldClassName,
+ a->getRoleName(Uml::B),
+ a->getMulti(Uml::B), a->getRoleDoc(Uml::B),
+ a->getVisibility(Uml::B),
+ a->getChangeability(Uml::B), java);
+ }
+ }
+
+ if (a->getObjectId(Uml::B) == thisClass->getID())
+ {
+ // only write out IF there is a rolename given
+ if(!a->getRoleName(Uml::A).isEmpty()) {
+ QString fieldClassName = getUMLObjectName(a->getObject(Uml::A));
+ writeAssociationRoleMethod(fieldClassName, a->getRoleName(Uml::A),
+ a->getMulti(Uml::A),
+ a->getRoleDoc(Uml::A),
+ a->getVisibility(Uml::A),
+ a->getChangeability(Uml::A),
+ java);
+ }
+ }
+
+ }
+ }
+}
+
+void JavaWriter::writeAssociationRoleMethod (QString fieldClassName, QString roleName, QString multi,
+ QString description, Uml::Visibility visib, Uml::Changeability_Type change,
+ QTextStream &java)
+{
+ if(multi.isEmpty() || multi.contains(QRegExp("^[01]$")))
+ {
+ QString fieldVarName = "m_" + roleName.replace(0, 1, roleName.left(1).lower());
+ writeSingleAttributeAccessorMethods(fieldClassName, fieldVarName, roleName,
+ description, visib, change, false, java);
+ }
+ else
+ {
+ QString fieldVarName = roleName.lower() + "Vector";
+ writeVectorAttributeAccessorMethods(fieldClassName, fieldVarName, roleName,
+ description, visib, change, java);
+ }
+}
+
+void JavaWriter::writeVectorAttributeAccessorMethods (QString fieldClassName, QString fieldVarName,
+ QString fieldName, QString description,
+ Uml::Visibility visibility, Uml::Changeability_Type changeType,
+ QTextStream &java)
+{
+
+ fieldClassName = fixTypeName(fieldClassName);
+ fieldName = Codegen_Utils::capitalizeFirstLetter(fieldName);
+ QString strVis = scopeToJavaDecl(visibility);
+
+ // ONLY IF changeability is NOT Frozen
+ if (changeType != Uml::chg_Frozen)
+ {
+ writeDocumentation("Add a "+fieldName+" object to the "+fieldVarName+" List",description,"",m_indentation,java);
+ java<<startline<<strVis<<" void add"<<fieldName<<" ( "<<fieldClassName<<" new_object ) {";
+ java<<startline<<m_indentation<<fieldVarName<<".add(new_object);";
+ java<<startline<<"}"<<m_endl;
+ }
+
+ // ONLY IF changeability is Changeable
+ if (changeType == Uml::chg_Changeable)
+ {
+ writeDocumentation("Remove a "+fieldName+" object from "+fieldVarName+" List",description,"",m_indentation,java);
+ java<<startline<<strVis<<" void remove"<<fieldName<<" ( "<<fieldClassName<<" new_object )";
+ java<<startline<<"{";
+ java<<startline<<m_indentation<<fieldVarName<<".remove(new_object);";
+ java<<startline<<"}"<<m_endl;
+ }
+
+ // always allow getting the list of stuff
+ writeDocumentation("Get the List of "+fieldName+" objects held by "+fieldVarName,description,"@return List of "+fieldName+" objects held by "+fieldVarName,m_indentation,java);
+ java<<startline<<strVis<<" List get"<<fieldName<<"List ( ) {";
+ java<<startline<<m_indentation<<"return (List) "<<fieldVarName<<";";
+ java<<startline<<"}"<<m_endl;
+ writeBlankLine(java);
+}
+
+
+void JavaWriter::writeSingleAttributeAccessorMethods(QString fieldClassName, QString fieldVarName,
+ QString fieldName, QString description,
+ Uml::Visibility visibility, Uml::Changeability_Type change,
+ bool isFinal, QTextStream &java)
+{
+
+ QString strVis = scopeToJavaDecl(visibility);
+ fieldClassName = fixTypeName(fieldClassName);
+ fieldName = Codegen_Utils::capitalizeFirstLetter(fieldName);
+
+ // set method
+ if (change == Uml::chg_Changeable && !isFinal) {
+ writeDocumentation("Set the value of "+fieldVarName,description,"@param newVar the new value of "+fieldVarName,m_indentation,java);
+ java<<startline<<strVis<<" void set"<<fieldName<<" ( "<<fieldClassName<<" newVar ) {";
+ java<<startline<<m_indentation<<fieldVarName<<" = newVar;";
+ java<<startline<<"}"<<m_endl;
+ }
+
+ // get method
+ writeDocumentation("Get the value of "+fieldVarName,description,"@return the value of "+fieldVarName,m_indentation,java);
+ java<<startline<<strVis<<" "<<fieldClassName<<" get"<<fieldName<<" ( ) {";
+ java<<startline<<m_indentation<<"return "<<fieldVarName<<";";
+ java<<startline<<"}";
+ writeBlankLine(java);
+}
+
+void JavaWriter::writeConstructor(UMLClassifier *c, QTextStream &java)
+{
+
+ if (forceDoc())
+ {
+ java<<startline;
+ writeComment("", m_indentation, java);
+ writeComment("Constructors", m_indentation, java);
+ writeComment("", m_indentation, java);
+ writeBlankLine(java);
+ }
+
+ // write the first constructor
+ QString className = cleanName(c->getName());
+ java<<m_indentation<<"public "<<className<<" () { };";
+
+}
+
+// IF the type is "string" we need to declare it as
+// the Java Object "String" (there is no string primative in Java).
+// Same thing again for "bool" to "boolean"
+QString JavaWriter::fixTypeName(const QString& string)
+{
+ if (string.isEmpty())
+ return "void";
+ if (string == "string")
+ return "String";
+ if (string == "bool")
+ return "boolean";
+ return string;
+}
+
+QStringList JavaWriter::defaultDatatypes() {
+ QStringList l;
+ l.append("int");
+ l.append("char");
+ l.append("boolean");
+ l.append("float");
+ l.append("double");
+ l.append("byte");
+ l.append("short");
+ l.append("long");
+ l.append("String");
+ return l;
+}
+
+
+bool JavaWriter::compareJavaMethod(UMLOperation *op1, UMLOperation *op2)
+{
+ if (op1 == NULL || op2 == NULL)
+ return false;
+ if (op1 == op2)
+ return true;
+ if (op1->getName() != op2->getName())
+ return false;
+ UMLAttributeList atl1 = op1->getParmList();
+ UMLAttributeList atl2 = op2->getParmList();
+ if (atl1.count() != atl2.count())
+ return false;
+ UMLAttribute *at1;
+ UMLAttribute *at2;
+ for (at1 = atl1.first(), at2 = atl2.first(); at1 && at2 ; at1 = atl1.next(),at2 = atl2.next())
+ {
+ if (at1->getTypeName() != at2->getTypeName())
+ return false;
+ }
+ return true;
+
+}
+
+bool JavaWriter::javaMethodInList(UMLOperation *umlOp, UMLOperationList &opl)
+{
+ for (UMLOperation *op = opl.first(); op; op = opl.next()) {
+ if (JavaWriter::compareJavaMethod(op, umlOp)) {
+ return true;
+ }
+ }
+ return false;
+}
+
+void JavaWriter::getSuperImplementedOperations(UMLClassifier *c, UMLOperationList &yetImplementedOpList ,UMLOperationList &toBeImplementedOpList, bool noClassInPath)
+{
+ UMLClassifierList superClasses = c->findSuperClassConcepts();
+
+ for (UMLClassifier *concept= superClasses.first(); concept; concept = superClasses.next())
+ {
+ getSuperImplementedOperations(concept, yetImplementedOpList, toBeImplementedOpList, (concept->isInterface() && noClassInPath));
+ UMLOperationList opl = concept->getOpList();
+ for (UMLOperation *op = opl.first(); op; op = opl.next()) {
+ if (concept->isInterface() && noClassInPath) {
+ if (!JavaWriter::javaMethodInList(op,toBeImplementedOpList))
+ toBeImplementedOpList.append(op);
+ }
+ else
+ {
+ if (!JavaWriter::javaMethodInList(op, yetImplementedOpList))
+ yetImplementedOpList.append(op);
+ }
+ }
+ }
+
+}
+
+void JavaWriter::getInterfacesOperationsToBeImplemented(UMLClassifier *c, UMLOperationList &opList )
+{
+ UMLOperationList yetImplementedOpList;
+ UMLOperationList toBeImplementedOpList;
+
+ getSuperImplementedOperations(c,yetImplementedOpList, toBeImplementedOpList);
+ for (UMLOperation *op = toBeImplementedOpList.first(); op; op = toBeImplementedOpList.next())
+ {
+ if ( ! JavaWriter::javaMethodInList(op, yetImplementedOpList) && ! JavaWriter::javaMethodInList(op, opList) )
+ opList.append(op);
+ }
+}
+
+void JavaWriter::writeOperations(UMLClassifier *c, QTextStream &java) {
+ UMLOperationList opl;
+ UMLOperationList oppub,opprot,oppriv;
+ oppub.setAutoDelete(false);
+ opprot.setAutoDelete(false);
+ oppriv.setAutoDelete(false);
+
+ //sort operations by scope first and see if there are abstract methods
+ opl = c->getOpList();
+ if (! c->isInterface()) {
+ getInterfacesOperationsToBeImplemented(c, opl);
+ }
+ for (UMLOperation *op = opl.first(); op; op = opl.next()) {
+ switch(op->getVisibility()) {
+ case Uml::Visibility::Public:
+ oppub.append(op);
+ break;
+ case Uml::Visibility::Protected:
+ opprot.append(op);
+ break;
+ case Uml::Visibility::Private:
+ oppriv.append(op);
+ break;
+ default:
+ break;
+ }
+ }
+
+ // do people REALLY want these comments? Hmm.
+ /*
+ if(forceSections() || oppub.count())
+ {
+ writeComment("public operations",m_indentation,java);
+ writeBlankLine(java);
+ }
+ */
+ writeOperations(oppub,java);
+
+ /*
+ if(forceSections() || opprot.count())
+ {
+ writeComment("protected operations",m_indentation,java);
+ writeBlankLine(java);
+ }
+ */
+ writeOperations(opprot,java);
+
+ /*
+ if(forceSections() || oppriv.count())
+ {
+ writeComment("private operations",m_indentation,java);
+ writeBlankLine(java);
+ }
+ */
+ writeOperations(oppriv,java);
+
+}
+
+void JavaWriter::writeOperations(UMLOperationList &oplist, QTextStream &java) {
+ UMLOperation *op;
+ UMLAttributeList atl;
+ UMLAttribute *at;
+ int i,j;
+ QString str;
+
+ // generate method decl for each operation given
+ for( op=oplist.first(); op ;op=oplist.next())
+ {
+
+ QString returnStr = "";
+ // write documentation
+
+ QString methodReturnType = fixTypeName(op->getTypeName());
+ if(methodReturnType != "void")
+ returnStr += "@return "+methodReturnType+"\n";
+
+ str = ""; // reset for next method
+ str += ((op->getAbstract() && !isInterface) ? "abstract ":"");
+ str += scopeToJavaDecl(op->getVisibility()) + ' ';
+ str += (op->getStatic() ? "static ":"");
+ str += methodReturnType + ' ' +cleanName(op->getName()) + "( ";
+
+ atl = op->getParmList();
+ i= atl.count();
+ j=0;
+ for (at = atl.first(); at; at = atl.next(), j++) {
+ QString typeName = fixTypeName(at->getTypeName());
+ QString atName = cleanName(at->getName());
+ str += typeName + ' ' + atName +
+ (!(at->getInitialValue().isEmpty()) ?
+ (QString(" = ")+at->getInitialValue()) :
+ QString(""))
+ + ((j < i-1)?", ":"");
+ returnStr += "@param "+atName+' '+at->getDoc()+"\n";
+ }
+ str+= " )";
+
+ // method only gets a body IF its not abstract
+ if (op->getAbstract() || isInterface)
+ str+=";\n\n"; // terminate now
+ else
+ str+=startline+"{\n\n"+m_indentation+"}\n\n"; // empty method body
+
+ // write it out
+ writeDocumentation("", op->getDoc(), returnStr, m_indentation, java);
+ java<<startline<<str;
+ }
+}
+
+QString JavaWriter::fixInitialStringDeclValue(QString value, QString type)
+{
+ // check for strings only
+ if (!value.isEmpty() && type == "String") {
+ if (!value.startsWith("\""))
+ value.prepend("\"");
+ if (!value.endsWith("\""))
+ value.append("\"");
+ }
+ return value;
+}
+
+QString JavaWriter::scopeToJavaDecl(Uml::Visibility scope)
+{
+ QString scopeString;
+ switch(scope)
+ {
+ case Uml::Visibility::Public:
+ scopeString = "public";
+ break;
+ case Uml::Visibility::Protected:
+ scopeString = "protected";
+ break;
+ case Uml::Visibility::Private:
+ default:
+ scopeString = "private";
+ break;
+ }
+ return scopeString;
+}
+
+// methods like this _shouldn't_ be needed IF we properly did things thruought the code.
+QString JavaWriter::getUMLObjectName(UMLObject *obj)
+{
+ return(obj!=0)?obj->getName():QString("NULL");
+}
+
+void JavaWriter::writeBlankLine(QTextStream &java)
+{
+ java<<m_endl;
+}
+
diff --git a/umbrello/umbrello/codegenerators/javawriter.h b/umbrello/umbrello/codegenerators/javawriter.h
new file mode 100644
index 00000000..2469f6d0
--- /dev/null
+++ b/umbrello/umbrello/codegenerators/javawriter.h
@@ -0,0 +1,236 @@
+/***************************************************************************
+ javawriter.h - description
+ This is the "old" code generator that does not support code editing
+ in the Modeller but uses significantly less file space because the
+ source code is not replicated in the XMI file.
+ -------------------
+ copyright : (C) 2003 Brian Thomas
+ (C) 2004 Umbrello UML Modeller Authors <uml-devel@uml.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 JAVAWRITER_H
+#define JAVAWRITER_H
+
+#include "simplecodegenerator.h"
+#include "../umloperationlist.h"
+#include "../umlattributelist.h"
+#include "../umlassociationlist.h"
+
+class UMLOperation;
+
+/**
+ * class JavaWriter is a code generator for UMLClassifier objects.
+ * Create an instance of this class, and feed it a UMLClassifier when
+ * calling writeClass and it will generate a java source file for
+ * that concept
+ */
+class JavaWriter : public SimpleCodeGenerator {
+public:
+
+ /**
+ * Constructor, initialises a couple of variables
+ */
+ JavaWriter();
+
+ /**
+ * Destructor, empty
+ */
+ virtual ~JavaWriter();
+
+ /**
+ * call this method to generate java code for a UMLClassifier
+ * @param c the class to generate code for
+ */
+ virtual void writeClass(UMLClassifier *c);
+
+ /**
+ * returns "Java"
+ */
+ virtual Uml::Programming_Language getLanguage();
+
+ /**
+ * Overrides method from class CodeGenerator
+ */
+ QStringList defaultDatatypes();
+
+private:
+
+ /**
+ * Writes class's documentation then the class header
+ * public abstract class Foo extents {
+ */
+ void writeClassDecl(UMLClassifier *c, QTextStream &java);
+
+ /**
+ * Writes the comment and class constructor
+ */
+ void writeConstructor(UMLClassifier *c, QTextStream &java);
+
+ /**
+ * return true if the two operations have the same name and the same parameters
+ * @param op1 first operation to be compared
+ * @param op2 second operation to be compared
+ */
+ static bool compareJavaMethod(UMLOperation *op1, UMLOperation *op2);
+
+ /**
+ * return true if the operation is in the list
+ * @param umlOp operation to be searched
+ * @param opl list of operations
+ */
+ static bool javaMethodInList(UMLOperation *umlOp, UMLOperationList &opl);
+
+ /**
+ * get all operations which a given class inherit from all its super interfaces and get all operations
+ * which this given class inherit from all its super classes
+ * @param c the class for which we are generating code
+ * @param yetImplementedOpList the list of yet implemented operations
+ * @param toBeImplementedOpList the list of to be implemented operations
+ * @param noClassInPath tells if there is a class between the base class and the current interface
+ */
+ void getSuperImplementedOperations(UMLClassifier *c, UMLOperationList &yetImplementedOpList ,UMLOperationList &toBeImplementedOpList, bool noClassInPath = true);
+
+ /**
+ * get all operations which a given class inherit from all its super interfaces and that should be implemented
+ * @param c the class for which we are generating code
+ * @param opl the list of operations used to append the operations
+ */
+ void getInterfacesOperationsToBeImplemented(UMLClassifier *c, UMLOperationList &opl);
+
+ /**
+ * write all operations for a given class
+ * @param c the class for which we are generating code
+ * @param j the stream associated with the output file
+ */
+ void writeOperations(UMLClassifier *c, QTextStream &j);
+
+ /**
+ * write a list of operations for a given class
+ * @param list the list of operations you want to write
+ * @param j the stream associated with the output file
+ */
+ void writeOperations(UMLOperationList &list, QTextStream &j);
+
+ /**
+ * write all attributes for a given class
+ * @param c the class for which we are generating code
+ * @param j the stream associated with the output file
+ */
+ void writeAttributes(UMLClassifier *c, QTextStream &j);
+
+ /**
+ * writes the Attribute declarations
+ * @param atpub List of public attributes
+ * @param atprot list of protected attributes
+ * @param atpriv list of private attributes
+ * @param java text stream
+ */
+ void writeAttributeDecls(UMLAttributeList &atpub, UMLAttributeList &atprot,
+ UMLAttributeList &atpriv, QTextStream &java );
+
+ /**
+ * Searches a list of associations for appropriate ones to write out as attributes
+ */
+ void writeAssociationDecls(UMLAssociationList associations, Uml::IDType id, QTextStream &java);
+
+ /**
+ * Writes out an association as an attribute using Vector
+ */
+ void writeAssociationRoleDecl(QString fieldClassName, QString roleName, QString multi,
+ QString doc, Uml::Visibility visib, QTextStream &java);
+
+ /**
+ * calls @ref writeSingleAttributeAccessorMethods() on each of the attributes in atpub
+ */
+ void writeAttributeMethods(UMLAttributeList &atpub, Uml::Visibility visibility, QTextStream &java);
+
+ /**
+ * calls @ref writeAssociationRoleMethod() on each of the associations in the given list
+ */
+ void writeAssociationMethods(UMLAssociationList associations, UMLClassifier *thisClass,
+ QTextStream &java);
+
+ /**
+ * calls @ref writeSingleAttributeAccessorMethods() or @ref
+ * writeVectorAttributeAccessorMethods() on the assocaition
+ * role
+ */
+ void writeAssociationRoleMethod(QString fieldClassName, QString roleName, QString multi,
+ QString description, Uml::Visibility visib, Uml::Changeability_Type change,
+ QTextStream &java);
+
+ /**
+ * Writes getFoo() and setFoo() accessor methods for the attribute
+ */
+ void writeSingleAttributeAccessorMethods(QString fieldClassName, QString fieldVarName,
+ QString fieldName, QString description,
+ Uml::Visibility visibility, Uml::Changeability_Type change,
+ bool isFinal, QTextStream &java);
+
+ /**
+ * Writes addFoo() and removeFoo() accessor methods for the Vector attribute
+ */
+ void writeVectorAttributeAccessorMethods(QString fieldClassName, QString fieldVarName,
+ QString fieldName, QString description,
+ Uml::Visibility visibility, Uml::Changeability_Type change,
+ QTextStream &java);
+
+ /**
+ * Writes a // style comment
+ */
+ void writeComment(const QString &text, const QString &indent, QTextStream &java, bool javaDocStyle=false);
+
+ /**
+ * Writes a documentation comment
+ */
+ void writeDocumentation(QString header, QString body, QString end, QString indent, QTextStream &java);
+
+ /**
+ * Returns the name of the given object (if it exists)
+ */
+ QString getUMLObjectName(UMLObject *obj);
+
+ /**
+ * Replaces `string' with `String' and `bool' with `boolean'
+ */
+ QString fixTypeName(const QString& string);
+
+ /**
+ * check that initial values of strings have quotes around them
+ */
+ QString fixInitialStringDeclValue(QString value, QString type);
+
+ /**
+ * Write a blank line
+ */
+ void writeBlankLine(QTextStream& java);
+
+ /**
+ * a little method for converting scope to string value
+ */
+ QString scopeToJavaDecl(Uml::Visibility scope);
+
+ /**
+ * A \n, used at the end of each line
+ */
+ QString startline;
+
+ /**
+ * Whether or not this concept is an interface.
+ */
+ bool isInterface;
+
+};
+
+
+#endif // JAVAWRITER_H
+
diff --git a/umbrello/umbrello/codegenerators/jswriter.cpp b/umbrello/umbrello/codegenerators/jswriter.cpp
new file mode 100644
index 00000000..1dbb45d6
--- /dev/null
+++ b/umbrello/umbrello/codegenerators/jswriter.cpp
@@ -0,0 +1,308 @@
+/***************************************************************************
+ begin : Sat Feb 08 2003
+ copyright : (C) 2003 by Alexander Blum
+ email : blum@kewbee.de
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License js published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#include "jswriter.h"
+#include "../association.h"
+#include "../classifier.h"
+#include "../operation.h"
+#include "../umldoc.h"
+#include "../attribute.h"
+
+#include <kdebug.h>
+
+#include <qregexp.h>
+#include <qtextstream.h>
+
+JSWriter::JSWriter() {
+}
+
+JSWriter::~JSWriter() {}
+
+
+void JSWriter::writeClass(UMLClassifier *c)
+{
+ if(!c)
+ {
+ kDebug()<<"Cannot write class of NULL concept!" << endl;
+ return;
+ }
+
+ QString classname = cleanName(c->getName());
+ QString fileName = c->getName().lower();
+
+ //find an appropriate name for our file
+ fileName = findFileName(c,".js");
+ if (fileName.isEmpty())
+ {
+ emit codeGenerated(c, false);
+ return;
+ }
+
+ QFile filejs;
+ if(!openFile(filejs, fileName))
+ {
+ emit codeGenerated(c, false);
+ return;
+ }
+ QTextStream js(&filejs);
+
+ //////////////////////////////
+ //Start generating the code!!
+ /////////////////////////////
+
+
+ //try to find a heading file (license, coments, etc)
+ QString str;
+ str = getHeadingFile(".js");
+ if(!str.isEmpty())
+ {
+ str.replace(QRegExp("%filename%"),fileName);
+ str.replace(QRegExp("%filepath%"),filejs.name());
+ js << str << m_endl;
+ }
+
+
+ //write includes
+ UMLPackageList includes;
+ findObjectsRelated(c,includes);
+ for (UMLPackage *conc = includes.first(); conc; conc = includes.next())
+ {
+ QString headerName = findFileName(conc, ".js");
+ if ( !headerName.isEmpty() )
+ {
+ js << "#include \"" << headerName << "\"" << m_endl;
+ }
+ }
+ js << m_endl;
+
+ //Write class Documentation if there is somthing or if force option
+ if(forceDoc() || !c->getDoc().isEmpty())
+ {
+ js << m_endl << "/**" << m_endl;
+ js << " * class " << classname << m_endl;
+ js << formatDoc(c->getDoc()," * ");
+ js << " */" << m_endl << m_endl;
+ }
+
+
+ //check if class is abstract and / or has abstract methods
+ if(c->getAbstract() && !hasAbstractOps(c))
+ js << "/******************************* Abstract Class ****************************" << m_endl << " "
+ << classname << " does not have any pure virtual methods, but its author" << m_endl
+ << " defined it as an abstract class, so you should not use it directly." << m_endl
+ << " Inherit from it instead and create only objects from the derived classes" << m_endl
+ << "*****************************************************************************/" << m_endl << m_endl;
+
+ js << classname << " = function ()" << m_endl;
+ js << "{" << m_endl;
+ js << m_indentation << "this._init ();" << m_endl;
+ js << "}" << m_endl;
+ js << m_endl;
+
+ UMLClassifierList superclasses = c->getSuperClasses();
+ for (UMLClassifier *obj = superclasses.first();
+ obj; obj = superclasses.next()) {
+ js << classname << ".prototype = new " << cleanName(obj->getName()) << " ();" << m_endl;
+ }
+
+ js << m_endl;
+
+ if (! c->isInterface()) {
+ UMLAttributeList atl = c->getAttributeList();
+
+ js << "/**" << m_endl;
+ QString temp = "_init sets all " + classname + " attributes to their default value."
+ " Make sure to call this method within your class constructor";
+ js << formatDoc(temp, " * ");
+ js << " */" << m_endl;
+ js << classname << ".prototype._init = function ()" << m_endl;
+ js << "{" << m_endl;
+ for(UMLAttribute *at = atl.first(); at ; at = atl.next())
+ {
+ if (forceDoc() || !at->getDoc().isEmpty())
+ {
+ js << m_indentation << "/**" << m_endl
+ << formatDoc(at->getDoc(), m_indentation + " * ")
+ << m_indentation << " */" << m_endl;
+ }
+ if(!at->getInitialValue().isEmpty())
+ {
+ js << m_indentation << "this.m_" << cleanName(at->getName()) << " = " << at->getInitialValue() << ";" << m_endl;
+ }
+ else
+ {
+ js << m_indentation << "this.m_" << cleanName(at->getName()) << " = \"\";" << m_endl;
+ }
+ }
+ }
+
+ //associations
+ UMLAssociationList aggregations = c->getAggregations();
+ if (forceSections() || !aggregations.isEmpty ())
+ {
+ js << m_endl << m_indentation << "/**Aggregations: */" << m_endl;
+ writeAssociation(classname, aggregations , js );
+
+ }
+ UMLAssociationList compositions = c->getCompositions();
+ if( forceSections() || !compositions.isEmpty())
+ {
+ js << m_endl << m_indentation << "/**Compositions: */" << m_endl;
+ writeAssociation(classname, compositions , js );
+
+ }
+ js << m_endl;
+ js << "}" << m_endl;
+ js << m_endl;
+
+ //operations
+ UMLOperationList ops(c->getOpList());
+ writeOperations(classname, &ops, js);
+
+ js << m_endl;
+
+ //finish file
+
+ //close files and notfiy we are done
+ filejs.close();
+ emit codeGenerated(c, true);
+}
+
+////////////////////////////////////////////////////////////////////////////////////
+// Helper Methods
+
+void JSWriter::writeAssociation(QString& classname, UMLAssociationList& assocList , QTextStream &js)
+{
+ for (UMLAssociation *a = assocList.first(); a; a = assocList.next()) {
+ // association side
+ Uml::Role_Type role = (a->getObject(Uml::A)->getName() == classname ? Uml::B : Uml::A);
+
+ QString roleName(cleanName(a->getRoleName(role)));
+
+ if (!roleName.isEmpty()) {
+
+ // association doc
+ if (forceDoc() || !a->getDoc().isEmpty())
+ {
+ js << m_indentation << "/**" << m_endl
+ << formatDoc(a->getDoc(), m_indentation + " * ")
+ << m_indentation << " */" << m_endl;
+ }
+
+ // role doc
+ if (forceDoc() || !a->getRoleDoc(role).isEmpty())
+ {
+ js << m_indentation << "/**" << m_endl
+ << formatDoc(a->getRoleDoc(role), m_indentation + " * ")
+ << m_indentation << " */" << m_endl;
+ }
+
+ bool okCvt;
+ int nMulti = a->getMulti(role).toInt(&okCvt,10);
+ bool isNotMulti = a->getMulti(role).isEmpty() || (okCvt && nMulti == 1);
+
+ QString typeName(cleanName(a->getObject(role)->getName()));
+
+ if (isNotMulti)
+ js << m_indentation << "this.m_" << roleName << " = new " << typeName << "();" << m_endl;
+ else
+ js << m_indentation << "this.m_" << roleName << " = new Array();" << m_endl;
+
+ // role visibility
+ }
+ }
+}
+
+void JSWriter::writeOperations(QString classname, UMLOperationList *opList, QTextStream &js)
+{
+ UMLOperation *op;
+ UMLAttribute *at;
+
+ for(op = opList->first(); op; op = opList->next())
+ {
+ UMLAttributeList atl = op->getParmList();
+ //write method doc if we have doc || if at least one of the params has doc
+ bool writeDoc = forceDoc() || !op->getDoc().isEmpty();
+ for (at = atl.first(); at; at = atl.next())
+ writeDoc |= !at->getDoc().isEmpty();
+
+ if( writeDoc ) //write method documentation
+ {
+ js << "/**" << m_endl << formatDoc(op->getDoc()," * ");
+
+ for (at = atl.first(); at; at = atl.next()) //write parameter documentation
+ {
+ if(forceDoc() || !at->getDoc().isEmpty())
+ {
+ js << " * @param " + cleanName(at->getName())<<m_endl;
+ js << formatDoc(at->getDoc()," * ");
+ }
+ }//end for : write parameter documentation
+ js << " */" << m_endl;
+ }//end if : write method documentation
+
+ js << classname << ".prototype." << cleanName(op->getName()) << " = function " << "(";
+
+ int i = atl.count();
+ int j=0;
+ for (at = atl.first(); at ;at = atl.next(),j++)
+ {
+ js << cleanName(at->getName())
+ << (!(at->getInitialValue().isEmpty()) ? (QString(" = ")+at->getInitialValue()) : QString(""))
+ << ((j < i-1)?", ":"");
+ }
+ js << ")" << m_endl << "{" << m_endl <<
+ m_indentation << m_endl << "}" << m_endl;
+ js << m_endl << m_endl;
+ }//end for
+}
+
+/**
+ * returns "JavaScript"
+ */
+Uml::Programming_Language JSWriter::getLanguage() {
+ return Uml::pl_JavaScript;
+}
+
+const QStringList JSWriter::reservedKeywords() const {
+
+ static QStringList keywords;
+
+ if (keywords.isEmpty()) {
+ keywords << "break"
+ << "case"
+ << "const"
+ << "continue"
+ << "default"
+ << "else"
+ << "false"
+ << "for"
+ << "function"
+ << "if"
+ << "in"
+ << "new"
+ << "return"
+ << "switch"
+ << "this"
+ << "true"
+ << "var"
+ << "while"
+ << "with";
+ }
+
+ return keywords;
+}
+
+#include "jswriter.moc"
diff --git a/umbrello/umbrello/codegenerators/jswriter.h b/umbrello/umbrello/codegenerators/jswriter.h
new file mode 100644
index 00000000..a9c5ebde
--- /dev/null
+++ b/umbrello/umbrello/codegenerators/jswriter.h
@@ -0,0 +1,78 @@
+/***************************************************************************
+ jswriter.h - description
+ -------------------
+ begin : Sat Feb 08 2003
+ copyright : (C) 2003 by Alexander Blum
+ email : blum@kewbee.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 JSWRITER_H
+#define JSWRITER_H
+
+#include "simplecodegenerator.h"
+#include "../umloperationlist.h"
+#include "../umlassociationlist.h"
+
+/**
+ * class JSWriter is a JavaScript code generator for UMLClassifier objects
+ * Just call writeClass and feed it a UMLClassifier;
+ */
+class JSWriter : public SimpleCodeGenerator {
+ Q_OBJECT
+public:
+
+ JSWriter();
+ virtual ~JSWriter();
+
+ /**
+ * call this method to generate Actionscript code for a UMLClassifier
+ * @param c the class you want to generate code for.
+ */
+ virtual void writeClass(UMLClassifier *c);
+
+ /**
+ * returns "JavaScript"
+ */
+ virtual Uml::Programming_Language getLanguage();
+
+ /**
+ * get list of reserved keywords
+ */
+ virtual const QStringList reservedKeywords() const;
+
+private:
+
+ /**
+ * we do not want to write the comment "Private methods" twice
+ */
+ bool bPrivateSectionCommentIsWritten;
+
+ /**
+ * write a list of class operations
+ *
+ * @param classname the name of the class
+ * @param opList the list of operations
+ * @param js output stream for the JS file
+ */
+ void writeOperations(QString classname, UMLOperationList *opList, QTextStream &js);
+
+ /**
+ * write a list of associations
+ *
+ * @param classname the name of the class
+ * @param assocList the list of associations
+ * @param as output stream for the AS file
+ */
+ void writeAssociation(QString& classname, UMLAssociationList& assoclist , QTextStream &js);
+};
+
+#endif //JSWRITER
diff --git a/umbrello/umbrello/codegenerators/pascalwriter.cpp b/umbrello/umbrello/codegenerators/pascalwriter.cpp
new file mode 100644
index 00000000..92a45bd2
--- /dev/null
+++ b/umbrello/umbrello/codegenerators/pascalwriter.cpp
@@ -0,0 +1,542 @@
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * copyright (C) 2006 *
+ * Umbrello UML Modeller Authors <uml-devel@uml.sf.net> *
+ ***************************************************************************/
+
+#include "pascalwriter.h"
+
+#include <kdebug.h>
+#include <klocale.h>
+#include <kmessagebox.h>
+#include <qfile.h>
+#include <qregexp.h>
+#include <qtextstream.h>
+
+#include "../umldoc.h"
+#include "../uml.h"
+#include "../classifier.h"
+#include "../enum.h"
+#include "../classifierlistitem.h"
+#include "../umlclassifierlistitemlist.h"
+#include "../umltemplatelist.h"
+#include "../folder.h"
+#include "../association.h"
+#include "../attribute.h"
+#include "../operation.h"
+#include "../template.h"
+#include "../umlnamespace.h"
+#include "classifierinfo.h"
+
+const QString PascalWriter::defaultPackageSuffix = "_Holder";
+
+PascalWriter::PascalWriter() {
+}
+
+PascalWriter::~PascalWriter() {}
+
+/**
+ * returns "Pascal"
+ */
+Uml::Programming_Language PascalWriter::getLanguage() {
+ return Uml::pl_Pascal;
+}
+
+
+bool PascalWriter::isOOClass(UMLClassifier *c) {
+ Uml::Object_Type ot = c->getBaseType();
+ if (ot == Uml::ot_Interface)
+ return true;
+ if (ot == Uml::ot_Enum)
+ return false;
+ if (ot != Uml::ot_Class) {
+ kDebug() << "PascalWriter::isOOClass: unknown object type " << ot << endl;
+ return false;
+ }
+ QString stype = c->getStereotype();
+ if (stype == "CORBAConstant" || stype == "CORBATypedef" ||
+ stype == "CORBAStruct" || stype == "CORBAUnion")
+ return false;
+ // CORBAValue, CORBAInterface, and all empty/unknown stereotypes are
+ // assumed to be OO classes.
+ return true;
+}
+
+QString PascalWriter::qualifiedName(UMLPackage *p, bool withType, bool byValue) {
+ UMLPackage *umlPkg = p->getUMLPackage();
+ QString className = cleanName(p->getName());
+ QString retval;
+
+ if (umlPkg == UMLApp::app()->getDocument()->getRootFolder(Uml::mt_Logical))
+ umlPkg = NULL;
+
+ UMLClassifier *c = dynamic_cast<UMLClassifier*>(p);
+ if (umlPkg == NULL) {
+ retval = className;
+ if (c == NULL || !isOOClass(c))
+ retval.append(defaultPackageSuffix);
+ } else {
+ retval = umlPkg->getFullyQualifiedName(".");
+ if (isOOClass(c)) {
+ retval.append(".");
+ retval.append(className);
+ }
+ }
+ if (! withType)
+ return retval;
+ if (c && isOOClass(c)) {
+ retval.append(".Object");
+ if (! byValue)
+ retval.append("_Ptr");
+ } else {
+ retval.append(".");
+ retval.append(className);
+ }
+ return retval;
+}
+
+void PascalWriter::computeAssocTypeAndRole
+(UMLAssociation *a, QString& typeName, QString& roleName) {
+ roleName = a->getRoleName(Uml::A);
+ if (roleName.isEmpty()) {
+ if (a->getMulti(Uml::A).isEmpty()) {
+ roleName = "M_";
+ roleName.append(typeName);
+ } else {
+ roleName = typeName;
+ roleName.append("_Vector");
+ }
+ }
+ UMLClassifier* c = dynamic_cast<UMLClassifier*>(a->getObject(Uml::A));
+ if (c == NULL)
+ return;
+ typeName = cleanName(c->getName());
+ if (! a->getMulti(Uml::A).isEmpty())
+ typeName.append("_Array_Access");
+}
+
+void PascalWriter::writeClass(UMLClassifier *c) {
+ if (!c) {
+ kDebug() << "Cannot write class of NULL concept!" << endl;
+ return;
+ }
+
+ const bool isClass = !c->isInterface();
+ QString classname = cleanName(c->getName());
+ QString fileName = qualifiedName(c).lower();
+ fileName.replace('.', '-');
+
+ //find an appropriate name for our file
+ fileName = overwritableName(c, fileName, ".pas");
+ if (fileName.isEmpty()) {
+ emit codeGenerated(c, false);
+ return;
+ }
+
+ QFile file;
+ if (!openFile(file, fileName)) {
+ emit codeGenerated(c, false);
+ return;
+ }
+
+ // Start generating the code.
+
+ QTextStream pas(&file);
+ //try to find a heading file(license, comments, etc)
+ QString str;
+ str = getHeadingFile(".pas");
+ if (!str.isEmpty()) {
+ str.replace(QRegExp("%filename%"), fileName);
+ str.replace(QRegExp("%filepath%"), file.name());
+ pas << str << endl;
+ }
+
+ QString unit = qualifiedName(c);
+ pas << "unit " << unit << ";" << m_endl << m_endl;
+ pas << "INTERFACE" << m_endl << m_endl;
+ // Use referenced classes.
+ UMLPackageList imports;
+ findObjectsRelated(c, imports);
+ if (imports.count()) {
+ pas << "uses" << m_endl;
+ bool first = true;
+ for (UMLPackage *con = imports.first(); con; con = imports.next()) {
+ if (con->getBaseType() != Uml::ot_Datatype) {
+ if (first)
+ first = false;
+ else
+ pas << "," << m_endl;
+ pas << " " << qualifiedName(con);
+ }
+ }
+ pas << ";" << m_endl << m_endl;
+ }
+
+ pas << "type" << m_endl;
+ m_indentLevel++;
+ if (c->getBaseType() == Uml::ot_Enum) {
+ UMLEnum *ue = static_cast<UMLEnum*>(c);
+ UMLClassifierListItemList litList = ue->getFilteredList(Uml::ot_EnumLiteral);
+ uint i = 0;
+ pas << getIndent() << classname << " = (" << m_endl;
+ m_indentLevel++;
+ for (UMLClassifierListItem *lit = litList.first(); lit; lit = litList.next()) {
+ QString enumLiteral = cleanName(lit->getName());
+ pas << getIndent() << enumLiteral;
+ if (++i < litList.count())
+ pas << "," << m_endl;
+ }
+ m_indentLevel--;
+ pas << ");" << m_endl << m_endl;
+ m_indentLevel--;
+ pas << "end." << m_endl << m_endl;
+ return;
+ }
+ UMLAttributeList atl = c->getAttributeList();
+ if (! isOOClass(c)) {
+ QString stype = c->getStereotype();
+ if (stype == "CORBAConstant") {
+ pas << getIndent() << "// " << stype << " is Not Yet Implemented" << m_endl << m_endl;
+ } else if(stype == "CORBAStruct") {
+ if (isClass) {
+ UMLAttribute *at;
+ pas << getIndent() << classname << " = record" << m_endl;
+ m_indentLevel++;
+ for (at = atl.first(); at; at = atl.next()) {
+ QString name = cleanName(at->getName());
+ QString typeName = at->getTypeName();
+ pas << getIndent() << name << " : " << typeName;
+ QString initialVal = at->getInitialValue();
+ if (initialVal.latin1() && ! initialVal.isEmpty())
+ pas << " := " << initialVal;
+ pas << ";" << m_endl;
+ }
+ m_indentLevel--;
+ pas << "end;" << m_endl << m_endl;
+ }
+ } else if(stype == "CORBAUnion") {
+ pas << getIndent() << "// " << stype << " is Not Yet Implemented" << m_endl << m_endl;
+ } else if(stype == "CORBATypedef") {
+ pas << getIndent() << "// " << stype << " is Not Yet Implemented" << m_endl << m_endl;
+ } else {
+ pas << getIndent() << "// " << stype << ": Unknown stereotype" << m_endl << m_endl;
+ }
+ m_indentLevel--;
+ pas << getIndent() << "end." << m_endl << m_endl;
+ return;
+ }
+
+ // Write class Documentation if non-empty or if force option set.
+ if (forceDoc() || !c->getDoc().isEmpty()) {
+ pas << "//" << m_endl;
+ pas << "// class " << classname << endl;
+ pas << formatDoc(c->getDoc(), "// ");
+ pas << m_endl;
+ }
+
+ UMLClassifierList superclasses = c->getSuperClasses();
+
+ pas << getIndent() << classname << " = object";
+ if (!superclasses.isEmpty()) {
+ // FIXME: Multiple inheritance is not yet supported
+ UMLClassifier* parent = superclasses.first();
+ pas << "(" << qualifiedName(parent) << ")";
+ }
+ pas << m_endl;
+
+ ClassifierInfo info(c);
+ UMLAttributeList atpub = info.atpub;
+ if (isClass && (forceSections() || atpub.count())) {
+ pas << getIndent() << "// Public attributes:" << m_endl;
+ UMLAttribute *at;
+ for (at = atpub.first(); at; at = atpub.next()) {
+ // if (at->getStatic())
+ // continue;
+ pas << getIndent() << cleanName(at->getName()) << " : "
+ << at->getTypeName();
+ if (at && at->getInitialValue().latin1() && ! at->getInitialValue().isEmpty())
+ pas << " := " << at->getInitialValue();
+ pas << ";" << m_endl;
+ }
+ }
+ bool haveAttrs = (isClass && atl.count());
+
+ // Generate public operations.
+ UMLOperationList opl(c->getOpList());
+ UMLOperationList oppub;
+ oppub.setAutoDelete(false);
+ UMLOperation *op;
+ for (op = opl.first(); op; op = opl.next()) {
+ if (op->getVisibility() == Uml::Visibility::Public)
+ oppub.append(op);
+ }
+ if (forceSections() || oppub.count())
+ pas << getIndent() << "// Public methods:" << m_endl << m_endl;
+ for (op = oppub.first(); op; op = oppub.next())
+ writeOperation(op, pas);
+
+ if (info.atprot.count()) {
+ pas << "protected" << m_endl << m_endl;
+ UMLAttribute *at;
+ UMLAttributeList atprot = info.atprot;
+ for (at = atprot.first(); at; at = atprot.next()) {
+ // if (at->getStatic())
+ // continue;
+ pas << getIndent() << cleanName(at->getName()) << " : "
+ << at->getTypeName();
+ if (at && at->getInitialValue().latin1() && ! at->getInitialValue().isEmpty())
+ pas << " := " << at->getInitialValue();
+ pas << ";" << m_endl;
+ }
+ pas << m_endl;
+ }
+ if (info.atpriv.count()) {
+ pas << "private" << m_endl << m_endl;
+ UMLAttribute *at;
+ UMLAttributeList atpriv = info.atpriv;
+ for (at = atpriv.first(); at; at = atpriv.next()) {
+ // if (at->getStatic())
+ // continue;
+ pas << getIndent() << cleanName(at->getName()) << " : "
+ << at->getTypeName();
+ if (at && at->getInitialValue().latin1() && ! at->getInitialValue().isEmpty())
+ pas << " := " << at->getInitialValue();
+ pas << ";" << m_endl;
+ }
+ pas << m_endl;
+ }
+ pas << getIndent() << "end;" << m_endl << m_endl;
+
+ pas << getIndent() << "P" << classname << " = ^" << classname <<";" << m_endl << m_endl;
+
+ m_indentLevel--;
+ pas << "end;" << m_endl << m_endl;
+ file.close();
+ emit codeGenerated(c, true);
+}
+
+
+void PascalWriter::writeOperation(UMLOperation *op, QTextStream &pas, bool is_comment) {
+ if (op->getStatic()) {
+ pas << "// TODO: generate status method " << op->getName() << m_endl;
+ return;
+ }
+ UMLAttributeList atl = op->getParmList();
+ QString rettype = op->getTypeName();
+ bool use_procedure = (rettype.isEmpty() || rettype == "void");
+
+ pas << getIndent();
+ if (is_comment)
+ pas << "// ";
+ if (use_procedure)
+ pas << "procedure ";
+ else
+ pas << "function ";
+ pas << cleanName(op->getName()) << " ";
+ if (atl.count()) {
+ pas << "(" << m_endl;
+ uint i = 0;
+ m_indentLevel++;
+ for (UMLAttribute *at = atl.first(); at; at = atl.next()) {
+ pas << getIndent();
+ if (is_comment)
+ pas << "// ";
+ pas << cleanName(at->getName()) << " : ";
+ Uml::Parameter_Direction pk = at->getParmKind();
+ if (pk != Uml::pd_In)
+ pas << "var ";
+ pas << at->getTypeName();
+ if (! at->getInitialValue().isEmpty())
+ pas << " := " << at->getInitialValue();
+ if (++i < (uint)atl.count())
+ pas << ";" << m_endl;
+ }
+ m_indentLevel--;
+ pas << ")";
+ }
+ if (! use_procedure)
+ pas << " : " << rettype;
+ pas << "; virtual; abstract;" << m_endl << m_endl;
+ // TBH, we make the methods abstract here because we don't have the means
+ // for generating meaningful implementations.
+}
+
+QStringList PascalWriter::defaultDatatypes() {
+ QStringList l;
+ l.append("AnsiString");
+ l.append("Boolean");
+ l.append("Byte");
+ l.append("ByteBool");
+ l.append("Cardinal");
+ l.append("Character");
+ l.append("Currency");
+ l.append("Double");
+ l.append("Extended");
+ l.append("Int64");
+ l.append("Integer");
+ l.append("Longint");
+ l.append("LongBool");
+ l.append("Longword");
+ l.append("QWord");
+ l.append("Real");
+ l.append("Shortint");
+ l.append("ShortString");
+ l.append("Single");
+ l.append("Smallint");
+ l.append("String");
+ l.append("WideString");
+ l.append("Word");
+ return l;
+}
+
+/**
+ * Check whether the given string is a reserved word for the
+ * language of this code generator
+ *
+ * @param rPossiblyReservedKeyword The string to check.
+ */
+bool PascalWriter::isReservedKeyword(const QString & rPossiblyReservedKeyword) {
+
+ const QStringList keywords = reservedKeywords();
+
+ QStringList::ConstIterator it;
+ for (it = keywords.begin(); it != keywords.end(); ++it)
+ if ((*it).lower() == rPossiblyReservedKeyword.lower())
+ return true;
+
+ return false;
+}
+
+/**
+ * get list of reserved keywords
+ */
+const QStringList PascalWriter::reservedKeywords() const {
+
+ static QStringList keywords;
+
+ if ( keywords.isEmpty() ) {
+ keywords.append( "absolute" );
+ keywords.append( "abstract" );
+ keywords.append( "and" );
+ keywords.append( "array" );
+ keywords.append( "as" );
+ keywords.append( "asm" );
+ keywords.append( "assembler" );
+ keywords.append( "automated" );
+ keywords.append( "begin" );
+ keywords.append( "case" );
+ keywords.append( "cdecl" );
+ keywords.append( "class" );
+ keywords.append( "const" );
+ keywords.append( "constructor" );
+ keywords.append( "contains" );
+ keywords.append( "default" );
+ keywords.append( "deprecated" );
+ keywords.append( "destructor" );
+ keywords.append( "dispid" );
+ keywords.append( "dispinterface" );
+ keywords.append( "div" );
+ keywords.append( "do" );
+ keywords.append( "downto" );
+ keywords.append( "dynamic" );
+ keywords.append( "else" );
+ keywords.append( "end" );
+ keywords.append( "except" );
+ keywords.append( "export" );
+ keywords.append( "exports" );
+ keywords.append( "external" );
+ keywords.append( "far" );
+ keywords.append( "file" );
+ keywords.append( "final" );
+ keywords.append( "finalization" );
+ keywords.append( "finally" );
+ keywords.append( "for" );
+ keywords.append( "forward" );
+ keywords.append( "function" );
+ keywords.append( "goto" );
+ keywords.append( "if" );
+ keywords.append( "implementation" );
+ keywords.append( "implements" );
+ keywords.append( "in" );
+ keywords.append( "index" );
+ keywords.append( "inherited" );
+ keywords.append( "initialization" );
+ keywords.append( "inline" );
+ keywords.append( "inline" );
+ keywords.append( "interface" );
+ keywords.append( "is" );
+ keywords.append( "label" );
+ keywords.append( "library" );
+ keywords.append( "library" );
+ keywords.append( "local" );
+ keywords.append( "message" );
+ keywords.append( "mod" );
+ keywords.append( "name" );
+ keywords.append( "near" );
+ keywords.append( "nil" );
+ keywords.append( "nodefault" );
+ keywords.append( "not" );
+ keywords.append( "object" );
+ keywords.append( "of" );
+ keywords.append( "or" );
+ keywords.append( "out" );
+ keywords.append( "overload" );
+ keywords.append( "override" );
+ keywords.append( "package" );
+ keywords.append( "packed" );
+ keywords.append( "pascal" );
+ keywords.append( "platform" );
+ keywords.append( "private" );
+ keywords.append( "procedure" );
+ keywords.append( "program" );
+ keywords.append( "property" );
+ keywords.append( "protected" );
+ keywords.append( "public" );
+ keywords.append( "published" );
+ keywords.append( "raise" );
+ keywords.append( "read" );
+ keywords.append( "readonly" );
+ keywords.append( "record" );
+ keywords.append( "register" );
+ keywords.append( "reintroduce" );
+ keywords.append( "repeat" );
+ keywords.append( "requires" );
+ keywords.append( "resident" );
+ keywords.append( "resourcestring" );
+ keywords.append( "safecall" );
+ keywords.append( "sealed" );
+ keywords.append( "set" );
+ keywords.append( "shl" );
+ keywords.append( "shr" );
+ keywords.append( "static" );
+ keywords.append( "stdcall" );
+ keywords.append( "stored" );
+ keywords.append( "string" );
+ keywords.append( "then" );
+ keywords.append( "threadvar" );
+ keywords.append( "to" );
+ keywords.append( "try" );
+ keywords.append( "type" );
+ keywords.append( "unit" );
+ keywords.append( "unsafe" );
+ keywords.append( "until" );
+ keywords.append( "uses" );
+ keywords.append( "var" );
+ keywords.append( "varargs" );
+ keywords.append( "virtual" );
+ keywords.append( "while" );
+ keywords.append( "with" );
+ keywords.append( "write" );
+ keywords.append( "writeonly" );
+ keywords.append( "xor" );
+ }
+
+ return keywords;
+}
+
+#include "pascalwriter.moc"
diff --git a/umbrello/umbrello/codegenerators/pascalwriter.h b/umbrello/umbrello/codegenerators/pascalwriter.h
new file mode 100644
index 00000000..bc34d762
--- /dev/null
+++ b/umbrello/umbrello/codegenerators/pascalwriter.h
@@ -0,0 +1,86 @@
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * copyright (C) 2006 *
+ * Umbrello UML Modeller Authors <uml-devel@uml.sf.net> *
+ ***************************************************************************/
+
+#ifndef PASCALWRITER_H
+#define PASCALWRITER_H
+
+#include "simplecodegenerator.h"
+
+class UMLAssociation;
+class UMLOperation;
+
+/**
+ * Pascal class writer
+ * @author Oliver Kellogg
+ * Bugs and comments to uml-devel@lists.sf.net or http://bugs.kde.org
+ */
+class PascalWriter : public SimpleCodeGenerator {
+ Q_OBJECT
+public:
+
+ /**
+ * Basic Constructor
+ */
+ PascalWriter ();
+
+ /**
+ * Empty Destructor
+ */
+ virtual ~PascalWriter ();
+
+ /**
+ * call this method to generate Ada code for a UMLClassifier
+ * @param c the class to generate code for
+ */
+ virtual void writeClass (UMLClassifier *c);
+
+ /**
+ * returns "Pascal"
+ */
+ virtual Uml::Programming_Language getLanguage();
+
+ QStringList defaultDatatypes();
+
+ /**
+ * Check whether the given string is a reserved word for the
+ * language of this code generator
+ *
+ * @param rPossiblyReservedKeyword The string to check.
+ */
+ virtual bool isReservedKeyword(const QString & rPossiblyReservedKeyword);
+
+ /**
+ * get list of reserved keywords
+ */
+ virtual const QStringList reservedKeywords() const;
+
+private:
+
+ /**
+ * write one operation
+ * @param op the class for which we are generating code
+ * @param ada the stream associated with the output file
+ */
+ void writeOperation (UMLOperation *op, QTextStream &ada, bool is_comment = false);
+
+ void computeAssocTypeAndRole (UMLAssociation *a, QString& typeName, QString& roleName);
+
+ bool isOOClass (UMLClassifier *c);
+
+ QString qualifiedName
+ (UMLPackage *p, bool withType = false, bool byValue = false);
+
+ static const QString defaultPackageSuffix;
+
+};
+
+#endif // PASCALWRITER_H
+
diff --git a/umbrello/umbrello/codegenerators/perlwriter.cpp b/umbrello/umbrello/codegenerators/perlwriter.cpp
new file mode 100644
index 00000000..7c8360fa
--- /dev/null
+++ b/umbrello/umbrello/codegenerators/perlwriter.cpp
@@ -0,0 +1,716 @@
+/***************************************************************************
+ begin : Wed Jan 22 2003
+ copyright : (C) 2003 by David Hugh-Jones
+ (C) 2004-2006 Umbrello UML Modeller Authors <uml-devel@uml.sf.net>
+ email : hughjonesd@yahoo.co.uk
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the 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 "perlwriter.h"
+#include "../classifier.h"
+#include "../operation.h"
+#include "../umldoc.h"
+#include "../association.h"
+#include "../attribute.h"
+#include "../uml.h"
+
+#include <kdebug.h>
+#include <qregexp.h>
+#include <qstring.h>
+#include <qdir.h>
+#include <qdatetime.h>
+#include <qtextstream.h>
+
+PerlWriter::PerlWriter()
+{
+}
+
+PerlWriter::~PerlWriter() {}
+
+bool PerlWriter::GetUseStatements(UMLClassifier *c, QString &Ret,
+ QString &ThisPkgName){
+
+ if(!c){
+ return(false);
+ }
+
+ UMLPackageList includes;
+ findObjectsRelated(c,includes);
+ UMLPackage *conc;
+ QString AV = "@";
+ QString SV = "$";
+ QString HV = "%";
+ for(conc = includes.first(); conc ;conc = includes.next()) {
+ if (conc->getBaseType() == Uml::ot_Datatype)
+ continue;
+ QString neatName = cleanName(conc->getName());
+ if (neatName != AV && neatName != SV && neatName != HV) {
+ QString OtherPkgName = conc->getPackage(".");
+ OtherPkgName.replace(QRegExp("\\."),"::");
+ QString OtherName = OtherPkgName + "::" + cleanName(conc->getName());
+
+ // Only print out the use statement if the other package isn't the
+ // same as the one we are working on. (This happens for the
+ // "Singleton" design pattern.)
+ if(OtherName != ThisPkgName){
+ Ret += "use ";
+ Ret += OtherName;
+ Ret += ';';
+ Ret += m_endl;
+ }
+ }
+ }
+ UMLClassifierList superclasses = c->getSuperClasses();
+ if (superclasses.count()) {
+ Ret += m_endl;
+ Ret += "use base qw( ";
+ for (UMLClassifier *obj = superclasses.first();
+ obj; obj = superclasses.next()) {
+ QString packageName = obj->getPackage(".");
+ packageName.replace(QRegExp("\\."),"::");
+
+ Ret += packageName + "::" + cleanName(obj->getName()) + ' ';
+ }
+ Ret += ");" + m_endl;
+ }
+
+ return(true);
+}
+
+void PerlWriter::writeClass(UMLClassifier *c) {
+
+ /* if(!c) {
+ kDebug()<<"Cannot write class of NULL concept!" << endl;
+ return;
+ }
+ */
+ QString classname = cleanName(c->getName());// this is fine: cleanName is "::-clean"
+ QString packageName = c->getPackage(".");
+ QString fileName;
+
+ // Replace all white spaces with blanks
+ packageName.simplifyWhiteSpace();
+
+ // Replace all blanks with underscore
+ packageName.replace(QRegExp(" "), "_");
+
+ // Replace all dots (".") with double colon scope resolution operators
+ // ("::")
+ packageName.replace(QRegExp("\\."),"::");
+
+ // Store complete package name
+ QString ThisPkgName = packageName + "::" + classname;
+
+ fileName = findFileName(c, ".pm");
+ // the above lower-cases my nice class names. That is bad.
+ // correct solution: refactor,
+ // split massive findFileName up, reimplement
+ // parts here
+ // actual solution: shameful ".pm" hack in codegenerator
+
+ CodeGenerationPolicy *pol = UMLApp::app()->getCommonPolicy();
+ QString curDir = pol->getOutputDirectory().absPath();
+ if (fileName.contains("::")) {
+ // create new directories for each level
+ QString newDir;
+ newDir = curDir;
+ QString fragment = fileName;
+ QDir* existing = new QDir (curDir);
+ QRegExp regEx("(.*)(::)");
+ regEx.setMinimal(true);
+ while (regEx.search(fragment) > -1) {
+ newDir = regEx.cap(1);
+ fragment.remove(0, (regEx.pos(2) + 2)); // get round strange minimal matching bug
+ existing->setPath(curDir + '/' + newDir);
+ if (! existing->exists()) {
+ existing->setPath(curDir);
+ if (! existing->mkdir(newDir)) {
+ emit codeGenerated(c, false);
+ return;
+ }
+ }
+ curDir += '/' + newDir;
+ }
+ fileName = fragment + ".pm";
+ }
+ if (fileName.isEmpty()) {
+ emit codeGenerated(c, false);
+ return;
+ }
+ QString oldDir = pol->getOutputDirectory().absPath();
+ pol->setOutputDirectory(curDir);
+ QFile fileperl;
+ if(!openFile(fileperl, fileName)) {
+ emit codeGenerated(c, false);
+ return;
+ }
+ QTextStream perl(&fileperl);
+ pol->setOutputDirectory(oldDir);
+
+ //======================================================================
+ // Start generating the code!!
+ //======================================================================
+
+ // try to find a heading file (license, comments, etc)
+ QString str;
+ bool bPackageDeclared = false;
+ bool bUseStmsWritten = false;
+
+ str = getHeadingFile(".pm"); // what this mean?
+ if(!str.isEmpty()) {
+ str.replace(QRegExp("%filename%"),fileName);
+ str.replace(QRegExp("%filepath%"),fileperl.name());
+ str.replace(QRegExp("%year%"),QDate::currentDate().toString("yyyy"));
+ str.replace(QRegExp("%date%"),QDate::currentDate().toString());
+ str.replace(QRegExp("%time%"),QTime::currentTime().toString());
+ str.replace(QRegExp("%package-name%"),ThisPkgName);
+ if(str.find(QRegExp("%PACKAGE-DECLARE%"))){
+ str.replace(QRegExp("%PACKAGE-DECLARE%"),
+ "package " + ThisPkgName + ';'
+ + m_endl + m_endl
+ + "#UML_MODELER_BEGIN_PERSONAL_VARS_" + classname
+ + m_endl + m_endl
+ + "#UML_MODELER_END_PERSONAL_VARS_" + classname
+ + m_endl
+ );
+ bPackageDeclared = true;
+ }
+
+ if(str.find(QRegExp("%USE-STATEMENTS%"))){
+ QString UseStms;
+ if(GetUseStatements(c,UseStms,ThisPkgName)){
+ str.replace(QRegExp("%USE-STATEMENTS%"), UseStms);
+ bUseStmsWritten = true;
+ }
+ }
+
+ perl<<str<<m_endl;
+ }
+
+ // if the package wasn't declared above during keyword substitution,
+ // add it now. (At the end of the file.)
+ if(! bPackageDeclared){
+ perl << m_endl << m_endl << "package " <<ThisPkgName << ";" << m_endl
+ << m_endl;
+ //write includes
+ perl << m_endl << "#UML_MODELER_BEGIN_PERSONAL_VARS_" << classname
+ << m_endl ;
+ perl << m_endl << "#UML_MODELER_END_PERSONAL_VARS_" << classname
+ << m_endl << m_endl ;
+ }
+
+ if(! bUseStmsWritten){
+ QString UseStms;
+ if(GetUseStatements(c,UseStms,ThisPkgName)){
+ perl<<UseStms<<m_endl;
+ }
+ }
+
+ perl << m_endl;
+
+ // Do we really need these for anything???
+ UMLAssociationList aggregations = c->getAggregations();
+ UMLAssociationList compositions = c->getCompositions();
+
+ //Write class Documentation
+ if(forceDoc() || !c->getDoc().isEmpty()) {
+ perl << m_endl << "=head1";
+ perl << " " << classname.upper() << m_endl << m_endl;
+ perl << c->getDoc();
+ perl << m_endl << m_endl << "=cut" << m_endl << m_endl;
+ }
+
+ //check if class is abstract and / or has abstract methods
+ if(c->getAbstract())
+ perl << "=head1 ABSTRACT CLASS" << m_endl << m_endl << "=cut" << m_endl;
+
+ //attributes
+ if (! c->isInterface())
+ writeAttributes(c, perl); // keep for documentation's sake
+
+ //operations
+ writeOperations(c,perl);
+
+ perl << m_endl;
+
+ //finish file
+ //perl << m_endl << m_endl << "=cut" << m_endl;
+ perl << m_endl << m_endl << "return 1;" << m_endl;
+
+ //close files and notify we are done
+ fileperl.close();
+ emit codeGenerated(c, true);
+}
+
+/**
+ * returns "Perl"
+ */
+Uml::Programming_Language PerlWriter::getLanguage() {
+ return Uml::pl_Perl;
+}
+
+////////////////////////////////////////////////////////////////////////////////////
+// Helper Methods
+
+void PerlWriter::writeOperations(UMLClassifier *c, QTextStream &perl) {
+
+ //Lists to store operations sorted by scope
+ UMLOperationList oppub,opprot,oppriv;
+
+ oppub.setAutoDelete(false);
+ opprot.setAutoDelete(false);
+ oppriv.setAutoDelete(false);
+
+ //sort operations by scope first and see if there are abstract methods
+ //keep this for documentation only!
+ UMLOperationList opl(c->getOpList());
+ for(UMLOperation *op = opl.first(); op ; op = opl.next()) {
+ switch(op->getVisibility()) {
+ case Uml::Visibility::Public:
+ oppub.append(op);
+ break;
+ case Uml::Visibility::Protected:
+ opprot.append(op);
+ break;
+ case Uml::Visibility::Private:
+ oppriv.append(op);
+ break;
+ default:
+ break;
+ }
+ }
+
+ QString classname(cleanName(c->getName()));
+
+ //write operations to file
+ if(forceSections() || !oppub.isEmpty()) {
+ perl << m_endl << "=head1 PUBLIC METHODS" << m_endl << m_endl ;
+ writeOperations(classname,oppub,perl);
+ perl << m_endl << m_endl << "=cut" << m_endl << m_endl;
+ }
+
+ if(forceSections() || !opprot.isEmpty()) {
+ perl << m_endl << "=head1 METHODS FOR SUBCLASSING" << m_endl << m_endl ;
+ //perl << "=pod " << m_endl << m_endl << "=head3 " ;
+ writeOperations(classname,opprot,perl);
+ perl << m_endl << m_endl << "=cut" << m_endl << m_endl;
+ }
+
+ if(forceSections() || !oppriv.isEmpty()) {
+ perl << m_endl << "=head1 PRIVATE METHODS" << m_endl << m_endl ;
+ //perl << "=pod " << m_endl << m_endl << "=head3 " ;
+ writeOperations(classname,oppriv,perl);
+ perl << m_endl << m_endl << "=cut" << m_endl << m_endl;
+ }
+
+ // moved here for perl
+ if (!c->isInterface() && hasDefaultValueAttr(c)) {
+ UMLAttributeList atl = c->getAttributeList();
+
+ perl << m_endl;
+ perl << m_endl << "=head2 _init" << m_endl << m_endl << m_endl;
+ perl << "_init sets all " + classname + " attributes to their default values unless already set" << m_endl << m_endl << "=cut" << m_endl << m_endl;
+ perl << "sub _init {" << m_endl << m_indentation << "my $self = shift;" << m_endl<<m_endl;
+
+ for(UMLAttribute *at = atl.first(); at ; at = atl.next()) {
+ if(!at->getInitialValue().isEmpty())
+ perl << m_indentation << "defined $self->{" << cleanName(at->getName())<<"}"
+ << " or $self->{" << cleanName(at->getName()) << "} = "
+ << at->getInitialValue() << ";" << m_endl;
+ }
+
+ perl << " }" << m_endl;
+ }
+
+ perl << m_endl << m_endl;
+}
+
+void PerlWriter::writeOperations(const QString &/* classname */, UMLOperationList &opList, QTextStream &perl) {
+ UMLOperation *op;
+ UMLAttribute *at;
+
+ for(op=opList.first(); op ; op=opList.next())
+ {
+ UMLAttributeList atl = op->getParmList();
+ //write method doc if we have doc || if at least one of the params has doc
+ bool writeDoc = forceDoc() || !op->getDoc().isEmpty();
+ for (at = atl.first(); at ; at = atl.next())
+ writeDoc |= !at->getDoc().isEmpty();
+
+ if( writeDoc ) //write method documentation
+ {
+ perl << "=pod " << m_endl << m_endl << "=head3 " ;
+ perl << cleanName(op->getName()) << m_endl << m_endl;
+
+ perl << " Parameters :" << m_endl ;
+ //write parameter documentation
+ for (at = atl.first(); at ; at = atl.next()) {
+ if(forceDoc() || !at->getDoc().isEmpty()) {
+ perl << " "
+ << cleanName(at->getName()) << " : "
+ << at->getTypeName() << " : "
+ << at->getDoc()
+ << m_endl;
+ }
+ }//end for : write parameter documentation
+
+ perl << m_endl;
+ perl << " Return : " << m_endl;
+ perl << " " << op->getTypeName();
+ perl << m_endl << m_endl;
+ perl << " Description : " << m_endl;
+ perl << " " << op->getDoc();
+ perl << m_endl << m_endl << "=cut" << m_endl << m_endl;
+ }//end if : write method documentation
+
+ perl << "sub " << cleanName(op->getName()) << m_endl << "{" << m_endl;
+ perl << " my($self";
+
+ bool bStartPrinted = false;
+ //write parameters
+ for (at = atl.first(); at; at = atl.next()) {
+ if (!bStartPrinted) {
+ bStartPrinted = true;
+ perl << "," << m_endl;
+ }
+ perl << " $"<< cleanName(at->getName()) << ", # "
+ << at->getTypeName() << " : " << at->getDoc() << m_endl;
+ }
+
+ perl << " ) = @_;" << m_endl;
+
+ perl << "#UML_MODELER_BEGIN_PERSONAL_CODE_" << cleanName(op->getName());
+ perl << m_endl << "#UML_MODELER_END_PERSONAL_CODE_" << cleanName(op->getName()) << m_endl;
+ perl << "}" << m_endl;
+ perl << m_endl << m_endl;
+ }//end for
+}
+
+
+void PerlWriter::writeAttributes(UMLClassifier *c, QTextStream &perl) {
+ UMLAttributeList atpub, atprot, atpriv, atdefval;
+ atpub.setAutoDelete(false);
+ atprot.setAutoDelete(false);
+ atpriv.setAutoDelete(false);
+ atdefval.setAutoDelete(false);
+
+ //sort attributes by scope and see if they have a default value
+ UMLAttributeList atl = c->getAttributeList();
+ UMLAttribute *at;
+ for(at = atl.first(); at ; at = atl.next()) {
+ if(!at->getInitialValue().isEmpty())
+ atdefval.append(at);
+ switch(at->getVisibility()) {
+ case Uml::Visibility::Public:
+ atpub.append(at);
+ break;
+ case Uml::Visibility::Protected:
+ atprot.append(at);
+ break;
+ case Uml::Visibility::Private:
+ atpriv.append(at);
+ break;
+ default:
+ break;
+ }
+ }
+
+
+ if(forceSections() || atpub.count()) {
+ writeAttributes(atpub,perl);
+ }
+ /* not needed as writeAttributes only writes documentation
+ if(forceSections() || atprot.count()) {
+ writeAttributes(atprot,perl);
+ }
+
+ if(forceSections() || atpriv.count()) {
+ writeAttributes(atpriv,perl);
+ }
+ */
+}
+
+
+void PerlWriter::writeAttributes(UMLAttributeList &atList, QTextStream &perl)
+{
+ perl << m_endl << "=head1 PUBLIC ATTRIBUTES" << m_endl << m_endl;
+ perl << "=pod " << m_endl << m_endl ;
+ for (UMLAttribute *at = atList.first(); at ; at = atList.next())
+ {
+ if (forceDoc() || !at->getDoc().isEmpty())
+ {
+ perl << "=head3 " << cleanName(at->getName()) << m_endl << m_endl ;
+ perl << " Description : " << at->getDoc() << m_endl << m_endl;
+ }
+ } // end for
+ perl << m_endl << m_endl << "=cut" << m_endl << m_endl;
+ return;
+}
+
+QStringList PerlWriter::defaultDatatypes() {
+ QStringList l;
+ l.append("$");
+ l.append("@");
+ l.append("%");
+ return l;
+}
+
+const QStringList PerlWriter::reservedKeywords() const {
+
+ static QStringList keywords;
+
+ if (keywords.isEmpty()) {
+ keywords << "abs"
+ << "accept"
+ << "alarm"
+ << "and"
+ << "atan2"
+ << "BEGIN"
+ << "bind"
+ << "binmode"
+ << "bless"
+ << "byte"
+ << "caller"
+ << "carp"
+ << "chdir"
+ << "chmod"
+ << "chomp"
+ << "chop"
+ << "chown"
+ << "chr"
+ << "chroot"
+ << "close"
+ << "closedir"
+ << "cmp"
+ << "confess"
+ << "connect"
+ << "continue"
+ << "cos"
+ << "croak"
+ << "crypt"
+ << "dbmclose"
+ << "dbmopen"
+ << "defined"
+ << "delete"
+ << "die"
+ << "do"
+ << "dump"
+ << "each"
+ << "else"
+ << "elsif"
+ << "END"
+ << "endgrent"
+ << "endhostent"
+ << "endnetent"
+ << "endprotoent"
+ << "endpwent"
+ << "endservent"
+ << "eof"
+ << "eq"
+ << "eval"
+ << "exec"
+ << "exists"
+ << "exit"
+ << "exp"
+ << "fcntl"
+ << "fileno"
+ << "flock"
+ << "for"
+ << "foreach"
+ << "fork"
+ << "format"
+ << "formline"
+ << "ge"
+ << "getc"
+ << "getgrent"
+ << "getgrgid"
+ << "getgrnam"
+ << "gethostbyaddr"
+ << "gethostbyname"
+ << "gethostent"
+ << "getlogin"
+ << "getnetbyaddr"
+ << "getnetbyname"
+ << "getnetent"
+ << "getpeername"
+ << "getpgrp"
+ << "getppid"
+ << "getpriority"
+ << "getprotobyname"
+ << "getprotobynumber"
+ << "getprotoent"
+ << "getpwent"
+ << "getpwnam"
+ << "getpwuid"
+ << "getservbyname"
+ << "getservbyport"
+ << "getservent"
+ << "getsockname"
+ << "getsockopt"
+ << "glob"
+ << "gmtime"
+ << "goto"
+ << "grep"
+ << "gt"
+ << "hex"
+ << "if"
+ << "import"
+ << "index"
+ << "int"
+ << "integer"
+ << "ioctl"
+ << "join"
+ << "keys"
+ << "kill"
+ << "last"
+ << "lc"
+ << "lcfirst"
+ << "le"
+ << "length"
+ << "lib"
+ << "link"
+ << "listen"
+ << "local"
+ << "localtime"
+ << "lock"
+ << "log"
+ << "lstat"
+ << "lt"
+ << "map"
+ << "mkdir"
+ << "msgctl"
+ << "msgget"
+ << "msgrcv"
+ << "msgsnd"
+ << "my"
+ << "ne"
+ << "new"
+ << "next"
+ << "no"
+ << "not"
+ << "oct"
+ << "open"
+ << "opendir"
+ << "or"
+ << "ord"
+ << "our"
+ << "pack"
+ << "package"
+ << "pipe"
+ << "pop"
+ << "pos"
+ << "print"
+ << "printf"
+ << "prototype"
+ << "push"
+ << "quotemeta"
+ << "rand"
+ << "read"
+ << "readdir"
+ << "readline"
+ << "readlink"
+ << "readpipe"
+ << "recv"
+ << "redo"
+ << "ref"
+ << "rename"
+ << "require"
+ << "reset"
+ << "return"
+ << "reverse"
+ << "rewinddir"
+ << "rindex"
+ << "rmdir"
+ << "scalar"
+ << "seek"
+ << "seekdir"
+ << "select"
+ << "semctl"
+ << "semget"
+ << "semop"
+ << "send"
+ << "setgrent"
+ << "sethostent"
+ << "setnetent"
+ << "setpgrp"
+ << "setpriority"
+ << "setprotoent"
+ << "setpwent"
+ << "setservent"
+ << "setsockopt"
+ << "shift"
+ << "shmctl"
+ << "shmget"
+ << "shmread"
+ << "shmwrite"
+ << "shutdown"
+ << "sigtrap"
+ << "sin"
+ << "sleep"
+ << "socket"
+ << "socketpair"
+ << "sort"
+ << "splice"
+ << "split"
+ << "sprintf"
+ << "sqrt"
+ << "srand"
+ << "stat"
+ << "strict"
+ << "study"
+ << "sub"
+ << "subs"
+ << "substr"
+ << "switch"
+ << "symlink"
+ << "syscall"
+ << "sysopen"
+ << "sysread"
+ << "sysseek"
+ << "system"
+ << "syswrite"
+ << "tell"
+ << "telldir"
+ << "tie"
+ << "tied"
+ << "time"
+ << "times"
+ << "truncate"
+ << "uc"
+ << "ucfirst"
+ << "umask"
+ << "undef"
+ << "unless"
+ << "unlink"
+ << "unpack"
+ << "unshift"
+ << "untie"
+ << "until"
+ << "use"
+ << "utf8"
+ << "utime"
+ << "values"
+ << "vars"
+ << "vec"
+ << "wait"
+ << "waitpid"
+ << "wantarray"
+ << "warn"
+ << "warnings"
+ << "while"
+ << "write"
+ << "xor";
+ }
+
+ return keywords;
+}
+
+#include "perlwriter.moc"
diff --git a/umbrello/umbrello/codegenerators/perlwriter.h b/umbrello/umbrello/codegenerators/perlwriter.h
new file mode 100644
index 00000000..9dac4e56
--- /dev/null
+++ b/umbrello/umbrello/codegenerators/perlwriter.h
@@ -0,0 +1,101 @@
+/***************************************************************************
+ perlwriter.h - description
+ -------------------
+ begin : Wed Jan 22 2003
+ copyright : (C) 2003 by David Hugh-Jones
+ email : hughjonesd@yahoo.co.uk
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the 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 PERLWRITER_H
+#define PERLWRITER_H
+
+#include "simplecodegenerator.h"
+#include "../umlattributelist.h"
+#include "../umloperationlist.h"
+
+class UMLOperation;
+class UMLAttribute;
+class UMLClassifier;
+
+/**
+ * class PerlWriter is a Perl code generator for UMLClassifier objects
+ * Just call writeClass and feed it a UMLClassifier;
+ */
+class PerlWriter : public SimpleCodeGenerator {
+ Q_OBJECT
+public:
+
+ PerlWriter();
+ virtual ~PerlWriter();
+
+ /**
+ * call this method to generate Perl code for a UMLClassifier
+ * @param c the class you want to generate code for.
+ */
+ virtual void writeClass(UMLClassifier *c);
+
+ /**
+ * returns "Perl"
+ */
+ virtual Uml::Programming_Language getLanguage();
+
+ /**
+ * get list of reserved keywords
+ */
+ virtual const QStringList reservedKeywords() const;
+
+ QStringList defaultDatatypes();
+
+private:
+
+ /**
+ * we do not want to write the comment "Private methods" twice
+ * not sure whether this is php specific
+ */
+ bool bPrivateSectionCommentIsWritten;
+
+ /**
+ * write all operations for a given class
+ *
+ * @param c the concept we are generating code for
+ * @param perl output stream for the Perl file
+ */
+ void writeOperations(UMLClassifier *c, QTextStream &perl);
+
+ /**
+ * write a list of class operations
+ *
+ * @param classname the name of the class
+ * @param opList the list of operations
+ * @param perl output stream for the Perl file
+ */
+ void writeOperations(const QString &classname, UMLOperationList &opList,
+ QTextStream &perl);
+
+ /** write all the attributes of a class
+ * @param c the class we are generating code for
+ * @param perl output stream for the Perl file
+ */
+ void writeAttributes(UMLClassifier *c, QTextStream &perl);
+
+ /** write a list of class attributes
+ * @param atList the list of attributes
+ * @param perl output stream for the Perl file
+ */
+ void writeAttributes(UMLAttributeList &atList, QTextStream &perl);
+
+ bool GetUseStatements(UMLClassifier *c, QString &Ret,
+ QString &ThisPkgName);
+
+};
+
+#endif //PERLWRITER
diff --git a/umbrello/umbrello/codegenerators/php5writer.cpp b/umbrello/umbrello/codegenerators/php5writer.cpp
new file mode 100644
index 00000000..044d3afe
--- /dev/null
+++ b/umbrello/umbrello/codegenerators/php5writer.cpp
@@ -0,0 +1,3418 @@
+/***************************************************************************
+ begin : Thu Oct 17 2002
+ copyright : (C) 2002 by Heiko Nardmann
+ email : h.nardmann@secunet.de
+ (C) 2003-2006 Umbrello UML Modeller Authors <uml-devel@uml.sf.net>
+ php5 version by Thorsten Kunz (tk AT bytecrash DOT net)
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the 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 "php5writer.h"
+
+#include <kdebug.h>
+#include <qregexp.h>
+#include <qtextstream.h>
+
+#include "../umldoc.h"
+#include "../classifier.h"
+#include "../association.h"
+#include "../attribute.h"
+#include "../operation.h"
+#include "../umlnamespace.h"
+
+static const char *php5words[] =
+ {
+ "abs",
+ "abstract",
+ "acos",
+ "acosh",
+ "add",
+ "addAction",
+ "addColor",
+ "addEntry",
+ "addFill",
+ "addShape",
+ "addString",
+ "add_namespace",
+ "addcslashes",
+ "addslashes",
+ "addstring",
+ "aggregate",
+ "aggregate_info",
+ "aggregate_methods",
+ "aggregate_methods_by_list",
+ "aggregate_methods_by_regexp",
+ "aggregate_properties",
+ "aggregate_properties_by_list",
+ "aggregate_properties_by_regexp",
+ "aggregation_info",
+ "align",
+ "apache_child_terminate",
+ "apache_lookup_uri",
+ "apache_note",
+ "apache_request_headers",
+ "apache_response_headers",
+ "apache_setenv",
+ "append_child",
+ "append_sibling",
+ "array",
+ "array_change_key_case",
+ "array_chunk",
+ "array_count_values",
+ "array_diff",
+ "array_diff_assoc",
+ "array_fill",
+ "array_filter",
+ "array_flip",
+ "array_intersect",
+ "array_intersect_assoc",
+ "array_key_exists",
+ "array_keys",
+ "array_map",
+ "array_merge",
+ "array_merge_recursive",
+ "array_multisort",
+ "array_pad",
+ "array_pop",
+ "array_push",
+ "array_rand",
+ "array_reduce",
+ "array_reverse",
+ "array_search",
+ "array_shift",
+ "array_slice",
+ "array_splice",
+ "array_sum",
+ "array_unique",
+ "array_unshift",
+ "array_values",
+ "array_walk",
+ "arsort",
+ "ascii2ebcdic",
+ "asin",
+ "asinh",
+ "asort",
+ "aspell_check",
+ "aspell_new",
+ "aspell_suggest",
+ "assert",
+ "assert_options",
+ "assign",
+ "atan",
+ "atan2",
+ "atanh",
+ "attreditable",
+ "attributes",
+ "base64_decode",
+ "base64_encode",
+ "base_convert",
+ "basename",
+ "bcadd",
+ "bccomp",
+ "bcdiv",
+ "bcmod",
+ "bcmul",
+ "bcpow",
+ "bcpowmod",
+ "bcscale",
+ "bcsqrt",
+ "bcsub",
+ "bin2hex",
+ "bindec",
+ "bindtextdomain",
+ "bind_textdomain_codeset",
+ "bool",
+ "break",
+ "bzclose",
+ "bzcompress",
+ "bzdecompress",
+ "bzerrno",
+ "bzerror",
+ "bzerrstr",
+ "bzflush",
+ "bzopen",
+ "bzread",
+ "bzwrite",
+ "cal_days_in_month",
+ "cal_from_jd",
+ "cal_info",
+ "call_user_func",
+ "call_user_func_array",
+ "call_user_method",
+ "call_user_method_array",
+ "cal_to_jd",
+ "ccvs_add",
+ "ccvs_auth",
+ "ccvs_command",
+ "ccvs_count",
+ "ccvs_delete",
+ "ccvs_done",
+ "ccvs_init",
+ "ccvs_lookup",
+ "ccvs_new",
+ "ccvs_report",
+ "ccvs_return",
+ "ccvs_reverse",
+ "ccvs_sale",
+ "ccvs_status",
+ "ccvs_textvalue",
+ "ccvs_void",
+ "ceil",
+ "chdir",
+ "checkdate",
+ "checkdnsrr",
+ "checkin",
+ "checkout",
+ "chgrp",
+ "child_nodes",
+ "children",
+ "chmod",
+ "chop",
+ "chown",
+ "chr",
+ "chroot",
+ "chunk_split",
+ "class",
+ "class_exists",
+ "clearstatcache",
+ "clone_node",
+ "closedir",
+ "closelog",
+ "com_addref",
+ "com_get",
+ "com_invoke",
+ "com_isenum",
+ "com_load",
+ "com_load_typelib",
+ "compact",
+ "com_propget",
+ "com_propput",
+ "com_propset",
+ "com_release",
+ "com_set",
+ "connection_aborted",
+ "connection_status",
+ "connection_timeout",
+ "constant",
+ "content",
+ "continue",
+ "convert_cyr_string",
+ "_COOKIE",
+ "copy",
+ "cos",
+ "cosh",
+ "count",
+ "count_chars",
+ "cpdf_add_annotation",
+ "cpdf_add_outline",
+ "cpdf_arc",
+ "cpdf_begin_text",
+ "cpdf_circle",
+ "cpdf_clip",
+ "cpdf_close",
+ "cpdf_closepath",
+ "cpdf_closepath_fill_stroke",
+ "cpdf_closepath_stroke",
+ "cpdf_continue_text",
+ "cpdf_curveto",
+ "cpdf_end_text",
+ "cpdf_fill",
+ "cpdf_fill_stroke",
+ "cpdf_finalize",
+ "cpdf_finalize_page",
+ "cpdf_global_set_document_limits",
+ "cpdf_import_jpeg",
+ "cpdf_lineto",
+ "cpdf_moveto",
+ "cpdf_newpath",
+ "cpdf_open",
+ "cpdf_output_buffer",
+ "cpdf_page_init",
+ "cpdf_place_inline_image",
+ "cpdf_rect",
+ "cpdf_restore",
+ "cpdf_rlineto",
+ "cpdf_rmoveto",
+ "cpdf_rotate",
+ "cpdf_rotate_text",
+ "cpdf_save",
+ "cpdf_save_to_file",
+ "cpdf_scale",
+ "cpdf_set_action_url",
+ "cpdf_set_char_spacing",
+ "cpdf_set_creator",
+ "cpdf_set_current_page",
+ "cpdf_setdash",
+ "cpdf_setflat",
+ "cpdf_set_font",
+ "cpdf_set_font_directories",
+ "cpdf_set_font_map_file",
+ "cpdf_setgray",
+ "cpdf_setgray_fill",
+ "cpdf_setgray_stroke",
+ "cpdf_set_horiz_scaling",
+ "cpdf_set_keywords",
+ "cpdf_set_leading",
+ "cpdf_setlinecap",
+ "cpdf_setlinejoin",
+ "cpdf_setlinewidth",
+ "cpdf_setmiterlimit",
+ "cpdf_set_page_animation",
+ "cpdf_setrgbcolor",
+ "cpdf_setrgbcolor_fill",
+ "cpdf_setrgbcolor_stroke",
+ "cpdf_set_subject",
+ "cpdf_set_text_matrix",
+ "cpdf_set_text_pos",
+ "cpdf_set_text_rendering",
+ "cpdf_set_text_rise",
+ "cpdf_set_title",
+ "cpdf_set_viewer_preferences",
+ "cpdf_set_word_spacing",
+ "cpdf_show",
+ "cpdf_show_xy",
+ "cpdf_stringwidth",
+ "cpdf_stroke",
+ "cpdf_text",
+ "cpdf_translate",
+ "crack_check",
+ "crack_closedict",
+ "crack_getlastmessage",
+ "crack_opendict",
+ "crc32",
+ "create_attribute",
+ "create_cdata_section",
+ "create_comment",
+ "create_element",
+ "create_element_ns",
+ "create_entity_reference",
+ "create_function",
+ "create_processing_instruction",
+ "create_text_node",
+ "crypt",
+ "ctype_alnum",
+ "ctype_alpha",
+ "ctype_cntrl",
+ "ctype_digit",
+ "ctype_graph",
+ "ctype_lower",
+ "ctype_print",
+ "ctype_punct",
+ "ctype_space",
+ "ctype_upper",
+ "ctype_xdigit",
+ "curl_close",
+ "curl_errno",
+ "curl_error",
+ "curl_exec",
+ "curl_getinfo",
+ "curl_init",
+ "curl_setopt",
+ "curl_version",
+ "current",
+ "cybercash_base64_decode",
+ "cybercash_base64_encode",
+ "cybercash_decr",
+ "cybercash_encr",
+ "cybermut_creerformulairecm",
+ "cybermut_creerreponsecm",
+ "cybermut_testmac",
+ "cyrus_authenticate",
+ "cyrus_bind",
+ "cyrus_close",
+ "cyrus_connect",
+ "cyrus_query",
+ "cyrus_unbind",
+ "data",
+ "date",
+ "dba_close",
+ "dba_delete",
+ "dba_exists",
+ "dba_fetch",
+ "dba_firstkey",
+ "dba_handlers",
+ "dba_insert",
+ "dba_list",
+ "dba_nextkey",
+ "dba_open",
+ "dba_optimize",
+ "dba_popen",
+ "dba_replace",
+ "dbase_add_record",
+ "dbase_close",
+ "dbase_create",
+ "dbase_delete_record",
+ "dbase_get_record",
+ "dbase_get_record_with_names",
+ "dbase_numfields",
+ "dbase_numrecords",
+ "dbase_open",
+ "dbase_pack",
+ "dbase_replace_record",
+ "dba_sync",
+ "dblist",
+ "dbmclose",
+ "dbmdelete",
+ "dbmexists",
+ "dbmfetch",
+ "dbmfirstkey",
+ "dbminsert",
+ "dbmnextkey",
+ "dbmopen",
+ "dbmreplace",
+ "dbplus_add",
+ "dbplus_aql",
+ "dbplus_chdir",
+ "dbplus_close",
+ "dbplus_curr",
+ "dbplus_errcode",
+ "dbplus_errno",
+ "dbplus_find",
+ "dbplus_first",
+ "dbplus_flush",
+ "dbplus_freealllocks",
+ "dbplus_freelock",
+ "dbplus_freerlocks",
+ "dbplus_getlock",
+ "dbplus_getunique",
+ "dbplus_info",
+ "dbplus_last",
+ "dbplus_lockrel",
+ "dbplus_next",
+ "dbplus_open",
+ "dbplus_prev",
+ "dbplus_rchperm",
+ "dbplus_rcreate",
+ "dbplus_rcrtexact",
+ "dbplus_rcrtlike",
+ "dbplus_resolve",
+ "dbplus_restorepos",
+ "dbplus_rkeys",
+ "dbplus_ropen",
+ "dbplus_rquery",
+ "dbplus_rrename",
+ "dbplus_rsecindex",
+ "dbplus_runlink",
+ "dbplus_rzap",
+ "dbplus_savepos",
+ "dbplus_setindex",
+ "dbplus_setindexbynumber",
+ "dbplus_sql",
+ "dbplus_tcl",
+ "dbplus_tremove",
+ "dbplus_undo",
+ "dbplus_undoprepare",
+ "dbplus_unlockrel",
+ "dbplus_unselect",
+ "dbplus_update",
+ "dbplus_xlockrel",
+ "dbplus_xunlockrel",
+ "dbstat",
+ "dbx_close",
+ "dbx_compare",
+ "dbx_connect",
+ "dbx_error",
+ "dbx_escape_string",
+ "dbx_query",
+ "dbx_sort",
+ "dcgettext",
+ "dcngettext",
+ "dcstat",
+ "deaggregate",
+ "debug_backtrace",
+ "debugger_off",
+ "debugger_on",
+ "decbin",
+ "dechex",
+ "declare",
+ "decoct",
+ "DEFAULT_INCLUDE_PATH",
+ "define",
+ "defined",
+ "define_syslog_variables",
+ "deg2rad",
+ "delete",
+ "description",
+ "dgettext",
+ "die",
+ "dio_close",
+ "dio_fcntl",
+ "dio_open",
+ "dio_read",
+ "dio_seek",
+ "dio_stat",
+ "dio_tcsetattr",
+ "dio_truncate",
+ "dio_write",
+ "dir",
+ "dirname",
+ "disk_free_space",
+ "diskfreespace",
+ "disk_total_space",
+ "dl",
+ "dngettext",
+ "dns_check_record",
+ "dns_get_mx",
+ "dns_get_record",
+ "do",
+ "doctype",
+ "document_element",
+ "DOCUMENT_ROOT",
+ "domxml_new_doc",
+ "domxml_open_file",
+ "domxml_open_mem",
+ "domxml_version",
+ "domxml_xmltree",
+ "domxml_xslt_stylesheet",
+ "domxml_xslt_stylesheet_doc",
+ "domxml_xslt_stylesheet_file",
+ "dotnet_load",
+ "doubleval",
+ "drawCurve",
+ "drawCurveTo",
+ "drawLine",
+ "drawLineTo",
+ "dstanchors",
+ "dstofsrcanchors",
+ "dump_file",
+ "dump_mem",
+ "dump_node",
+ "each",
+ "E_ALL",
+ "easter_date",
+ "easter_days",
+ "ebcdic2ascii",
+ "echo",
+ "E_COMPILE_ERROR",
+ "E_COMPILE_WARNING",
+ "E_CORE_ERROR",
+ "E_CORE_WARNING",
+ "E_ERROR",
+ "else",
+ "elseif",
+ "empty",
+ "end",
+ "endfor",
+ "endforeach",
+ "endif",
+ "endswitch",
+ "endwhile",
+ "E_NOTICE",
+ "entities",
+ "_ENV",
+ "E_PARSE",
+ "ereg",
+ "eregi",
+ "eregi_replace",
+ "ereg_replace",
+ "error_log",
+ "error_reporting",
+ "escapeshellarg",
+ "escapeshellcmd",
+ "E_USER_ERROR",
+ "E_USER_NOTICE",
+ "E_USER_WARNING",
+ "eval",
+ "E_WARNING",
+ "exec",
+ "exif_imagetype",
+ "exif_read_data",
+ "exif_thumbnail",
+ "exit",
+ "exp",
+ "explode",
+ "expm1",
+ "extension_loaded",
+ "extract",
+ "ezmlm_hash",
+ "FALSE",
+ "fbsql_affected_rows",
+ "fbsql_autocommit",
+ "fbsql_change_user",
+ "fbsql_close",
+ "fbsql_commit",
+ "fbsql_connect",
+ "fbsql_create_blob",
+ "fbsql_create_clob",
+ "fbsql_create_db",
+ "fbsql_database",
+ "fbsql_database_password",
+ "fbsql_data_seek",
+ "fbsql_db_query",
+ "fbsql_db_status",
+ "fbsql_drop_db",
+ "fbsql_errno",
+ "fbsql_error",
+ "fbsql_fetch_array",
+ "fbsql_fetch_assoc",
+ "fbsql_fetch_field",
+ "fbsql_fetch_lengths",
+ "fbsql_fetch_object",
+ "fbsql_fetch_row",
+ "fbsql_field_flags",
+ "fbsql_field_len",
+ "fbsql_field_name",
+ "fbsql_field_seek",
+ "fbsql_field_table",
+ "fbsql_field_type",
+ "fbsql_free_result",
+ "fbsql_get_autostart_info",
+ "fbsql_hostname",
+ "fbsql_insert_id",
+ "fbsql_list_dbs",
+ "fbsql_list_fields",
+ "fbsql_list_tables",
+ "fbsql_next_result",
+ "fbsql_num_fields",
+ "fbsql_num_rows",
+ "fbsql_password",
+ "fbsql_pconnect",
+ "fbsql_query",
+ "fbsql_read_blob",
+ "fbsql_read_clob",
+ "fbsql_result",
+ "fbsql_rollback",
+ "fbsql_select_db",
+ "fbsql_set_lob_mode",
+ "fbsql_set_transaction",
+ "fbsql_start_db",
+ "fbsql_stop_db",
+ "fbsql_tablename",
+ "fbsql_username",
+ "fbsql_warnings",
+ "fclose",
+ "fdf_add_doc_javascript",
+ "fdf_add_template",
+ "fdf_close",
+ "fdf_create",
+ "fdf_errno",
+ "fdf_error",
+ "fdf_get_ap",
+ "fdf_get_attachment",
+ "fdf_get_encoding",
+ "fdf_get_file",
+ "fdf_get_status",
+ "fdf_get_value",
+ "fdf_get_version",
+ "fdf_header",
+ "fdf_next_field_name",
+ "fdf_open",
+ "fdf_open_string",
+ "fdf_save",
+ "fdf_save_string",
+ "fdf_set_ap",
+ "fdf_set_encoding",
+ "fdf_set_file",
+ "fdf_set_flags",
+ "fdf_set_javascript_action",
+ "fdf_set_opt",
+ "fdf_set_status",
+ "fdf_set_submit_form_action",
+ "fdf_set_target_frame",
+ "fdf_set_value",
+ "fdf_set_version",
+ "feof",
+ "fflush",
+ "fgetc",
+ "fgetcsv",
+ "fgets",
+ "fgetss",
+ "file",
+ "__FILE__",
+ "fileatime",
+ "filectime",
+ "file_exists",
+ "file_get_contents",
+ "filegroup",
+ "fileinode",
+ "filemtime",
+ "fileowner",
+ "fileperms",
+ "filepro",
+ "filepro_fieldcount",
+ "filepro_fieldname",
+ "filepro_fieldtype",
+ "filepro_fieldwidth",
+ "filepro_retrieve",
+ "filepro_rowcount",
+ "_FILES",
+ "filesize",
+ "filetype",
+ "find",
+ "first_child",
+ "floatval",
+ "flock",
+ "floor",
+ "flush",
+ "fmod",
+ "fnmatch",
+ "fopen",
+ "for",
+ "foreach",
+ "fpassthru",
+ "fprintf",
+ "fputs",
+ "fread",
+ "frenchtojd",
+ "fribidi_log2vis",
+ "fscanf",
+ "fseek",
+ "fsockopen",
+ "fstat",
+ "ftell",
+ "ftok",
+ "ftp_cdup",
+ "ftp_chdir",
+ "ftp_close",
+ "ftp_connect",
+ "ftp_delete",
+ "ftp_exec",
+ "ftp_fget",
+ "ftp_fput",
+ "ftp_get",
+ "ftp_get_option",
+ "ftp_login",
+ "ftp_mdtm",
+ "ftp_mkdir",
+ "ftp_nb_continue",
+ "ftp_nb_fget",
+ "ftp_nb_fput",
+ "ftp_nb_get",
+ "ftp_nb_put",
+ "ftp_nlist",
+ "ftp_pasv",
+ "ftp_put",
+ "ftp_pwd",
+ "ftp_quit",
+ "ftp_rawlist",
+ "ftp_rename",
+ "ftp_rmdir",
+ "ftp_set_option",
+ "ftp_site",
+ "ftp_size",
+ "ftp_ssl_connect",
+ "ftp_systype",
+ "ftruncate",
+ "ftstat",
+ "func_get_arg",
+ "func_get_args",
+ "func_num_args",
+ "function",
+ "function_exists",
+ "fwrite",
+ "GATEWAY_INTERFACE",
+ "gd_info",
+ "_GET",
+ "getallheaders",
+ "get_attribute",
+ "get_attribute_node",
+ "get_browser",
+ "get_cfg_var",
+ "get_class",
+ "get_class_methods",
+ "get_class_vars",
+ "get_content",
+ "get_current_user",
+ "getcwd",
+ "getdate",
+ "get_declared_classes",
+ "get_defined_constants",
+ "get_defined_functions",
+ "get_defined_vars",
+ "get_element_by_id",
+ "get_elements_by_tagname",
+ "getenv",
+ "get_extension_funcs",
+ "getHeight",
+ "gethostbyaddr",
+ "gethostbyname",
+ "gethostbynamel",
+ "get_html_translation_table",
+ "getimagesize",
+ "get_included_files",
+ "get_include_path",
+ "getlastmod",
+ "get_loaded_extensions",
+ "get_magic_quotes_gpc",
+ "get_magic_quotes_runtime",
+ "get_meta_tags",
+ "getmxrr",
+ "getmygid",
+ "getmyinode",
+ "getmypid",
+ "getmyuid",
+ "get_object_vars",
+ "getopt",
+ "get_parent_class",
+ "getprotobyname",
+ "getprotobynumber",
+ "getrandmax",
+ "get_required_files",
+ "get_resource_type",
+ "getrusage",
+ "getservbyname",
+ "getservbyport",
+ "getshape1",
+ "getshape2",
+ "gettext",
+ "gettimeofday",
+ "gettype",
+ "getwidth",
+ "getWidth",
+ "glob",
+ "global",
+ "GLOBALS",
+ "gmdate",
+ "gmmktime",
+ "gmp_abs",
+ "gmp_add",
+ "gmp_and",
+ "gmp_clrbit",
+ "gmp_cmp",
+ "gmp_com",
+ "gmp_div",
+ "gmp_divexact",
+ "gmp_div_q",
+ "gmp_div_qr",
+ "gmp_div_r",
+ "gmp_fact",
+ "gmp_gcd",
+ "gmp_gcdext",
+ "gmp_hamdist",
+ "gmp_init",
+ "gmp_intval",
+ "gmp_invert",
+ "gmp_jacobi",
+ "gmp_legendre",
+ "gmp_mod",
+ "gmp_mul",
+ "gmp_neg",
+ "gmp_or",
+ "gmp_perfect_square",
+ "gmp_popcount",
+ "gmp_pow",
+ "gmp_powm",
+ "gmp_prob_prime",
+ "gmp_random",
+ "gmp_scan0",
+ "gmp_scan1",
+ "gmp_setbit",
+ "gmp_sign",
+ "gmp_sqrt",
+ "gmp_sqrtrm",
+ "gmp_strval",
+ "gmp_sub",
+ "gmp_xor",
+ "gmstrftime",
+ "gregoriantojd",
+ "gzclose",
+ "gzcompress",
+ "gzdeflate",
+ "gzencode",
+ "gzeof",
+ "gzfile",
+ "gzgetc",
+ "gzgets",
+ "gzgetss",
+ "gzinflate",
+ "gzopen",
+ "gzpassthru",
+ "gzputs",
+ "gzread",
+ "gzrewind",
+ "gzseek",
+ "gztell",
+ "gzuncompress",
+ "gzwrite",
+ "has_attribute",
+ "has_attributess",
+ "has_child_nodes",
+ "header",
+ "headers_sent",
+ "hebrev",
+ "hebrevc",
+ "hexdec",
+ "highlight_file",
+ "highlight_string",
+ "html_dump_mem",
+ "htmlentities",
+ "html_entity_decode",
+ "htmlspecialchars",
+ "HTTP_ACCEPT",
+ "HTTP_ACCEPT_CHARSET",
+ "HTTP_ACCEPT_LANGUAGE",
+ "HTTP_CONNECTION",
+ "HTTP_COOKIE_VARS",
+ "HTTP_ENCODING",
+ "HTTP_ENV_VARS",
+ "HTTP_GET_VARS",
+ "HTTP_HOST",
+ "HTTP_POST_FILES",
+ "HTTP_POST_VARS",
+ "HTTP_RAW_POST_DATA",
+ "HTTP_REFERER",
+ "HTTP_SERVER_VARS",
+ "HTTP_SESSION_VARS",
+ "HTTP_STATE_VARS",
+ "HTTP_USER_AGENT",
+ "hw_api_attribute",
+ "hw_api_content",
+ "hwapi_hgcsp",
+ "hw_api_object",
+ "hw_Array2Objrec",
+ "hw_changeobject",
+ "hw_Children",
+ "hw_ChildrenObj",
+ "hw_Close",
+ "hw_Connect",
+ "hw_connection_info",
+ "hw_Cp",
+ "hw_Deleteobject",
+ "hw_DocByAnchor",
+ "hw_DocByAnchorObj",
+ "hw_Document_Attributes",
+ "hw_Document_BodyTag",
+ "hw_Document_Content",
+ "hw_Document_SetContent",
+ "hw_Document_Size",
+ "hw_dummy",
+ "hw_EditText",
+ "hw_Error",
+ "hw_ErrorMsg",
+ "hw_Free_Document",
+ "hw_GetAnchors",
+ "hw_GetAnchorsObj",
+ "hw_GetAndLock",
+ "hw_GetChildColl",
+ "hw_GetChildCollObj",
+ "hw_GetChildDocColl",
+ "hw_GetChildDocCollObj",
+ "hw_GetObject",
+ "hw_GetObjectByQuery",
+ "hw_GetObjectByQueryColl",
+ "hw_GetObjectByQueryCollObj",
+ "hw_GetObjectByQueryObj",
+ "hw_GetParents",
+ "hw_GetParentsObj",
+ "hw_getrellink",
+ "hw_GetRemote",
+ "hw_GetRemoteChildren",
+ "hw_GetSrcByDestObj",
+ "hw_GetText",
+ "hw_getusername",
+ "hw_Identify",
+ "hw_InCollections",
+ "hw_Info",
+ "hw_InsColl",
+ "hw_InsDoc",
+ "hw_insertanchors",
+ "hw_InsertDocument",
+ "hw_InsertObject",
+ "hw_mapid",
+ "hw_Modifyobject",
+ "hw_Mv",
+ "hw_New_Document",
+ "hw_Objrec2Array",
+ "hw_Output_Document",
+ "hw_pConnect",
+ "hw_PipeDocument",
+ "hw_Root",
+ "hw_setlinkroot",
+ "hw_stat",
+ "hwstat",
+ "hw_Unlock",
+ "hw_Who",
+ "hypot",
+ "ibase_blob_add",
+ "ibase_blob_cancel",
+ "ibase_blob_close",
+ "ibase_blob_create",
+ "ibase_blob_echo",
+ "ibase_blob_get",
+ "ibase_blob_import",
+ "ibase_blob_info",
+ "ibase_blob_open",
+ "ibase_close",
+ "ibase_commit",
+ "ibase_connect",
+ "ibase_errmsg",
+ "ibase_execute",
+ "ibase_fetch_object",
+ "ibase_fetch_row",
+ "ibase_field_info",
+ "ibase_free_query",
+ "ibase_free_result",
+ "ibase_num_fields",
+ "ibase_pconnect",
+ "ibase_prepare",
+ "ibase_query",
+ "ibase_rollback",
+ "ibase_timefmt",
+ "ibase_trans",
+ "iconv",
+ "iconv_get_encoding",
+ "iconv_set_encoding",
+ "identify",
+ "if",
+ "ifx_affected_rows",
+ "ifx_blobinfile_mode",
+ "ifx_byteasvarchar",
+ "ifx_close",
+ "ifx_connect",
+ "ifx_copy_blob",
+ "ifx_create_blob",
+ "ifx_create_char",
+ "ifx_do",
+ "ifx_error",
+ "ifx_errormsg",
+ "ifx_fetch_row",
+ "ifx_fieldproperties",
+ "ifx_fieldtypes",
+ "ifx_free_blob",
+ "ifx_free_char",
+ "ifx_free_result",
+ "ifx_get_blob",
+ "ifx_get_char",
+ "ifx_getsqlca",
+ "ifx_htmltbl_result",
+ "ifx_nullformat",
+ "ifx_num_fields",
+ "ifx_num_rows",
+ "ifx_pconnect",
+ "ifx_prepare",
+ "ifx_query",
+ "ifx_textasvarchar",
+ "ifx_update_blob",
+ "ifx_update_char",
+ "ifxus_close_slob",
+ "ifxus_create_slob",
+ "ifxus_free_slob",
+ "ifxus_open_slob",
+ "ifxus_read_slob",
+ "ifxus_seek_slob",
+ "ifxus_tell_slob",
+ "ifxus_write_slob",
+ "ignore_user_abort",
+ "image2wbmp",
+ "imagealphablending",
+ "imagearc",
+ "imagechar",
+ "imagecharup",
+ "imagecolorallocate",
+ "imagecolorallocatealpha",
+ "imagecolorat",
+ "imagecolorclosest",
+ "imagecolorclosestalpha",
+ "imagecolorclosesthwb",
+ "imagecolordeallocate",
+ "imagecolorexact",
+ "imagecolorexactalpha",
+ "imagecolorresolve",
+ "imagecolorresolvealpha",
+ "imagecolorset",
+ "imagecolorsforindex",
+ "imagecolorstotal",
+ "imagecolortransparent",
+ "imagecopy",
+ "imagecopymerge",
+ "imagecopymergegray",
+ "imagecopyresampled",
+ "imagecopyresized",
+ "imagecreate",
+ "imagecreatefromgd",
+ "imagecreatefromgd2",
+ "imagecreatefromgd2part",
+ "imagecreatefromgif",
+ "imagecreatefromjpeg",
+ "imagecreatefrompng",
+ "imagecreatefromstring",
+ "imagecreatefromwbmp",
+ "imagecreatefromxbm",
+ "imagecreatefromxpm",
+ "imagecreatetruecolor",
+ "imagedashedline",
+ "imagedestroy",
+ "imageellipse",
+ "imagefill",
+ "imagefilledarc",
+ "imagefilledellipse",
+ "imagefilledpolygon",
+ "imagefilledrectangle",
+ "imagefilltoborder",
+ "imagefontheight",
+ "imagefontwidth",
+ "imageftbbox",
+ "imagefttext",
+ "imagegammacorrect",
+ "imagegd",
+ "imagegd2",
+ "imagegif",
+ "imageinterlace",
+ "imagejpeg",
+ "imageline",
+ "imageloadfont",
+ "imagepalettecopy",
+ "imagepng",
+ "imagepolygon",
+ "imagepsbbox",
+ "imagepscopyfont",
+ "imagepsencodefont",
+ "imagepsextendfont",
+ "imagepsfreefont",
+ "imagepsloadfont",
+ "imagepsslantfont",
+ "imagepstext",
+ "imagerectangle",
+ "imagerotate",
+ "imagesetbrush",
+ "imagesetpixel",
+ "imagesetstyle",
+ "imagesetthickness",
+ "imagesettile",
+ "imagestring",
+ "imagestringup",
+ "imagesx",
+ "imagesy",
+ "imagetruecolortopalette",
+ "imagettfbbox",
+ "imagettftext",
+ "imagetypes",
+ "image_type_to_mime_type",
+ "imagewbmp",
+ "imap_8bit",
+ "imap_alerts",
+ "imap_append",
+ "imap_base64",
+ "imap_binary",
+ "imap_body",
+ "imap_bodystruct",
+ "imap_check",
+ "imap_clearflag_full",
+ "imap_close",
+ "imap_createmailbox",
+ "imap_delete",
+ "imap_deletemailbox",
+ "imap_errors",
+ "imap_expunge",
+ "imap_fetchbody",
+ "imap_fetchheader",
+ "imap_fetch_overview",
+ "imap_fetchstructure",
+ "imap_getmailboxes",
+ "imap_get_quota",
+ "imap_get_quotaroot",
+ "imap_getsubscribed",
+ "imap_header",
+ "imap_headerinfo",
+ "imap_headers",
+ "imap_last_error",
+ "imap_list",
+ "imap_listmailbox",
+ "imap_listscan",
+ "imap_listsubscribed",
+ "imap_lsub",
+ "imap_mail",
+ "imap_mailboxmsginfo",
+ "imap_mail_compose",
+ "imap_mail_copy",
+ "imap_mail_move",
+ "imap_mime_header_decode",
+ "imap_msgno",
+ "imap_num_msg",
+ "imap_num_recent",
+ "imap_open",
+ "imap_ping",
+ "imap_qprint",
+ "imap_renamemailbox",
+ "imap_reopen",
+ "imap_rfc822_parse_adrlist",
+ "imap_rfc822_parse_headers",
+ "imap_rfc822_write_address",
+ "imap_scanmailbox",
+ "imap_search",
+ "imap_setacl",
+ "imap_setflag_full",
+ "imap_set_quota",
+ "imap_sort",
+ "imap_status",
+ "imap_subscribe",
+ "imap_thread",
+ "imap_uid",
+ "imap_undelete",
+ "imap_unsubscribe",
+ "imap_utf7_decode",
+ "imap_utf7_encode",
+ "imap_utf8",
+ "implements",
+ "implode",
+ "import_request_variables",
+ "in_array",
+ "include",
+ "include_once",
+ "info",
+ "ingres_autocommit",
+ "ingres_close",
+ "ingres_commit",
+ "ingres_connect",
+ "ingres_fetch_array",
+ "ingres_fetch_object",
+ "ingres_fetch_row",
+ "ingres_field_length",
+ "ingres_field_name",
+ "ingres_field_nullable",
+ "ingres_field_precision",
+ "ingres_field_scale",
+ "ingres_field_type",
+ "ingres_num_fields",
+ "ingres_num_rows",
+ "ingres_pconnect",
+ "ingres_query",
+ "ingres_rollback",
+ "ini_alter",
+ "ini_get",
+ "ini_get_all",
+ "ini_restore",
+ "ini_set",
+ "insert",
+ "insertanchor",
+ "insert_before",
+ "insertcollection",
+ "insertdocument",
+ "int",
+ "interface",
+ "internal_subset",
+ "intval",
+ "ip2long",
+ "iptcembed",
+ "iptcparse",
+ "ircg_channel_mode",
+ "ircg_disconnect",
+ "ircg_fetch_error_msg",
+ "ircg_get_username",
+ "ircg_html_encode",
+ "ircg_ignore_add",
+ "ircg_ignore_del",
+ "ircg_is_conn_alive",
+ "ircg_join",
+ "ircg_kick",
+ "ircg_lookup_format_messages",
+ "ircg_msg",
+ "ircg_nick",
+ "ircg_nickname_escape",
+ "ircg_nickname_unescape",
+ "ircg_notice",
+ "ircg_part",
+ "ircg_pconnect",
+ "ircg_register_format_messages",
+ "ircg_set_current",
+ "ircg_set_file",
+ "ircg_set_on_die",
+ "ircg_topic",
+ "ircg_whois",
+ "is_a",
+ "is_array",
+ "is_blank_node",
+ "is_bool",
+ "is_callable",
+ "is_dir",
+ "is_double",
+ "is_executable",
+ "is_file",
+ "is_finite",
+ "is_float",
+ "is_infinite",
+ "is_int",
+ "is_integer",
+ "is_link",
+ "is_long",
+ "is_nan",
+ "is_null",
+ "is_numeric",
+ "is_object",
+ "is_readable",
+ "is_real",
+ "is_resource",
+ "is_scalar",
+ "isset",
+ "is_string",
+ "is_subclass_of",
+ "is_uploaded_file",
+ "is_writable",
+ "is_writeable",
+ "java_last_exception_clear",
+ "java_last_exception_get",
+ "jddayofweek",
+ "jdmonthname",
+ "jdtofrench",
+ "jdtogregorian",
+ "jdtojewish",
+ "jdtojulian",
+ "jdtounix",
+ "jewishtojd",
+ "join",
+ "jpeg2wbmp",
+ "juliantojd",
+ "key",
+ "krsort",
+ "ksort",
+ "langdepvalue",
+ "last_child",
+ "lcg_value",
+ "ldap_8859_to_t61",
+ "ldap_add",
+ "ldap_bind",
+ "ldap_close",
+ "ldap_compare",
+ "ldap_connect",
+ "ldap_count_entries",
+ "ldap_delete",
+ "ldap_dn2ufn",
+ "ldap_err2str",
+ "ldap_errno",
+ "ldap_error",
+ "ldap_explode_dn",
+ "ldap_first_attribute",
+ "ldap_first_entry",
+ "ldap_first_reference",
+ "ldap_free_result",
+ "ldap_get_attributes",
+ "ldap_get_dn",
+ "ldap_get_entries",
+ "ldap_get_option",
+ "ldap_get_values",
+ "ldap_get_values_len",
+ "ldap_list",
+ "ldap_mod_add",
+ "ldap_mod_del",
+ "ldap_modify",
+ "ldap_mod_replace",
+ "ldap_next_attribute",
+ "ldap_next_entry",
+ "ldap_next_reference",
+ "ldap_parse_reference",
+ "ldap_parse_result",
+ "ldap_read",
+ "ldap_rename",
+ "ldap_search",
+ "ldap_set_option",
+ "ldap_set_rebind_proc",
+ "ldap_sort",
+ "ldap_start_tls",
+ "ldap_t61_to_8859",
+ "ldap_unbind",
+ "levenshtein",
+ "__LINE__",
+ "link",
+ "linkinfo",
+ "list",
+ "localeconv",
+ "localtime",
+ "lock",
+ "log",
+ "log10",
+ "log1p",
+ "long2ip",
+ "lstat",
+ "ltrim",
+ "mail",
+ "mailparse_determine_best_xfer_encoding",
+ "mailparse_msg_create",
+ "mailparse_msg_extract_part",
+ "mailparse_msg_extract_part_file",
+ "mailparse_msg_free",
+ "mailparse_msg_get_part",
+ "mailparse_msg_get_part_data",
+ "mailparse_msg_get_structure",
+ "mailparse_msg_parse",
+ "mailparse_msg_parse_file",
+ "mailparse_rfc822_parse_addresses",
+ "mailparse_stream_encode",
+ "mailparse_uudecode_all",
+ "main",
+ "max",
+ "mb_convert_case",
+ "mb_convert_encoding",
+ "mb_convert_kana",
+ "mb_convert_variables",
+ "mb_decode_mimeheader",
+ "mb_decode_numericentity",
+ "mb_detect_encoding",
+ "mb_detect_order",
+ "mb_encode_mimeheader",
+ "mb_encode_numericentity",
+ "mb_ereg",
+ "mb_eregi",
+ "mb_eregi_replace",
+ "mb_ereg_match",
+ "mb_ereg_replace",
+ "mb_ereg_search",
+ "mb_ereg_search_getpos",
+ "mb_ereg_search_getregs",
+ "mb_ereg_search_init",
+ "mb_ereg_search_pos",
+ "mb_ereg_search_regs",
+ "mb_ereg_search_setpos",
+ "mb_get_info",
+ "mb_http_input",
+ "mb_http_output",
+ "mb_internal_encoding",
+ "mb_language",
+ "mb_output_handler",
+ "mb_parse_str",
+ "mb_preferred_mime_name",
+ "mb_regex_encoding",
+ "mb_regex_set_options",
+ "mb_send_mail",
+ "mb_split",
+ "mb_strcut",
+ "mb_strimwidth",
+ "mb_strlen",
+ "mb_strpos",
+ "mb_strrpos",
+ "mb_strtolower",
+ "mb_strtoupper",
+ "mb_strwidth",
+ "mb_substitute_character",
+ "mb_substr",
+ "mb_substr_count",
+ "mcal_append_event",
+ "mcal_close",
+ "mcal_create_calendar",
+ "mcal_date_compare",
+ "mcal_date_valid",
+ "mcal_day_of_week",
+ "mcal_day_of_year",
+ "mcal_days_in_month",
+ "mcal_delete_calendar",
+ "mcal_delete_event",
+ "mcal_event_add_attribute",
+ "mcal_event_init",
+ "mcal_event_set_alarm",
+ "mcal_event_set_category",
+ "mcal_event_set_class",
+ "mcal_event_set_description",
+ "mcal_event_set_end",
+ "mcal_event_set_recur_daily",
+ "mcal_event_set_recur_monthly_mday",
+ "mcal_event_set_recur_monthly_wday",
+ "mcal_event_set_recur_none",
+ "mcal_event_set_recur_weekly",
+ "mcal_event_set_recur_yearly",
+ "mcal_event_set_start",
+ "mcal_event_set_title",
+ "mcal_expunge",
+ "mcal_fetch_current_stream_event",
+ "mcal_fetch_event",
+ "mcal_is_leap_year",
+ "mcal_list_alarms",
+ "mcal_list_events",
+ "mcal_next_recurrence",
+ "mcal_open",
+ "mcal_popen",
+ "mcal_rename_calendar",
+ "mcal_reopen",
+ "mcal_snooze",
+ "mcal_store_event",
+ "mcal_time_valid",
+ "mcal_week_of_year",
+ "mcrypt_cbc",
+ "mcrypt_cfb",
+ "mcrypt_create_iv",
+ "mcrypt_decrypt",
+ "mcrypt_ecb",
+ "mcrypt_enc_get_algorithms_name",
+ "mcrypt_enc_get_block_size",
+ "mcrypt_enc_get_iv_size",
+ "mcrypt_enc_get_key_size",
+ "mcrypt_enc_get_modes_name",
+ "mcrypt_enc_get_supported_key_sizes",
+ "mcrypt_enc_is_block_algorithm",
+ "mcrypt_enc_is_block_algorithm_mode",
+ "mcrypt_enc_is_block_mode",
+ "mcrypt_encrypt",
+ "mcrypt_enc_self_test",
+ "mcrypt_generic",
+ "mcrypt_generic_deinit",
+ "mcrypt_generic_end",
+ "mcrypt_generic_init",
+ "mcrypt_get_block_size",
+ "mcrypt_get_cipher_name",
+ "mcrypt_get_iv_size",
+ "mcrypt_get_key_size",
+ "mcrypt_list_algorithms",
+ "mcrypt_list_modes",
+ "mcrypt_module_close",
+ "mcrypt_module_get_algo_block_size",
+ "mcrypt_module_get_algo_key_size",
+ "mcrypt_module_get_supported_key_sizes",
+ "mcrypt_module_is_block_algorithm",
+ "mcrypt_module_is_block_algorithm_mode",
+ "mcrypt_module_is_block_mode",
+ "mcrypt_module_open",
+ "mcrypt_module_self_test",
+ "mcrypt_ofb",
+ "mcve_adduser",
+ "mcve_adduserarg",
+ "mcve_bt",
+ "mcve_checkstatus",
+ "mcve_chkpwd",
+ "mcve_chngpwd",
+ "mcve_completeauthorizations",
+ "mcve_connect",
+ "mcve_connectionerror",
+ "mcve_deleteresponse",
+ "mcve_deletetrans",
+ "mcve_deleteusersetup",
+ "mcve_deluser",
+ "mcve_destroyconn",
+ "mcve_destroyengine",
+ "mcve_disableuser",
+ "mcve_edituser",
+ "mcve_enableuser",
+ "mcve_force",
+ "mcve_getcell",
+ "mcve_getcellbynum",
+ "mcve_getcommadelimited",
+ "mcve_getheader",
+ "mcve_getuserarg",
+ "mcve_getuserparam",
+ "mcve_gft",
+ "mcve_gl",
+ "mcve_gut",
+ "mcve_initconn",
+ "mcve_initengine",
+ "mcve_initusersetup",
+ "mcve_iscommadelimited",
+ "mcve_liststats",
+ "mcve_listusers",
+ "mcve_maxconntimeout",
+ "mcve_monitor",
+ "mcve_numcolumns",
+ "mcve_numrows",
+ "mcve_override",
+ "mcve_parsecommadelimited",
+ "mcve_ping",
+ "mcve_preauth",
+ "mcve_preauthcompletion",
+ "mcve_qc",
+ "mcve_responseparam",
+ "mcve_return",
+ "mcve_returncode",
+ "mcve_returnstatus",
+ "mcve_sale",
+ "mcve_setblocking",
+ "mcve_setdropfile",
+ "mcve_setip",
+ "mcve_setssl",
+ "mcve_settimeout",
+ "mcve_settle",
+ "mcve_text_avs",
+ "mcve_text_code",
+ "mcve_text_cv",
+ "mcve_transactionauth",
+ "mcve_transactionavs",
+ "mcve_transactionbatch",
+ "mcve_transactioncv",
+ "mcve_transactionid",
+ "mcve_transactionitem",
+ "mcve_transactionssent",
+ "mcve_transactiontext",
+ "mcve_transinqueue",
+ "mcve_transnew",
+ "mcve_transparam",
+ "mcve_transsend",
+ "mcve_ub",
+ "mcve_uwait",
+ "mcve_verifyconnection",
+ "mcve_verifysslcert",
+ "mcve_void",
+ "md5",
+ "md5_file",
+ "mdecrypt_generic",
+ "memory_get_usage",
+ "metaphone",
+ "method_exists",
+ "mhash",
+ "mhash_count",
+ "mhash_get_block_size",
+ "mhash_get_hash_name",
+ "mhash_keygen_s2k",
+ "microtime",
+ "mime_content_type",
+ "mimetype",
+ "min",
+ "ming_setcubicthreshold",
+ "ming_setscale",
+ "ming_useswfversion",
+ "mkdir",
+ "mktime",
+ "money_format",
+ "move",
+ "movePen",
+ "movePenTo",
+ "moveTo",
+ "move_uploaded_file",
+ "msession_connect",
+ "msession_count",
+ "msession_create",
+ "msession_destroy",
+ "msession_disconnect",
+ "msession_find",
+ "msession_get",
+ "msession_get_array",
+ "msession_getdata",
+ "msession_inc",
+ "msession_list",
+ "msession_listvar",
+ "msession_lock",
+ "msession_plugin",
+ "msession_randstr",
+ "msession_set",
+ "msession_set_array",
+ "msession_setdata",
+ "msession_timeout",
+ "msession_uniq",
+ "msession_unlock",
+ "msg_get_queue",
+ "msg_receive",
+ "msg_remove_queue",
+ "msg_send",
+ "msg_set_queue",
+ "msg_stat_queue",
+ "msql",
+ "msql_affected_rows",
+ "msql_close",
+ "msql_connect",
+ "msql_create_db",
+ "msql_createdb",
+ "msql_data_seek",
+ "msql_dbname",
+ "msql_drop_db",
+ "msql_dropdb",
+ "msql_error",
+ "msql_fetch_array",
+ "msql_fetch_field",
+ "msql_fetch_object",
+ "msql_fetch_row",
+ "msql_fieldflags",
+ "msql_fieldlen",
+ "msql_fieldname",
+ "msql_field_seek",
+ "msql_fieldtable",
+ "msql_fieldtype",
+ "msql_free_result",
+ "msql_freeresult",
+ "msql_list_dbs",
+ "msql_listdbs",
+ "msql_list_fields",
+ "msql_listfields",
+ "msql_list_tables",
+ "msql_listtables",
+ "msql_num_fields",
+ "msql_numfields",
+ "msql_num_rows",
+ "msql_numrows",
+ "msql_pconnect",
+ "msql_query",
+ "msql_regcase",
+ "msql_result",
+ "msql_select_db",
+ "msql_selectdb",
+ "msql_tablename",
+ "mssql_bind",
+ "mssql_close",
+ "mssql_connect",
+ "mssql_data_seek",
+ "mssql_execute",
+ "mssql_fetch_array",
+ "mssql_fetch_assoc",
+ "mssql_fetch_batch",
+ "mssql_fetch_field",
+ "mssql_fetch_object",
+ "mssql_fetch_row",
+ "mssql_field_length",
+ "mssql_field_name",
+ "mssql_field_seek",
+ "mssql_field_type",
+ "mssql_free_result",
+ "mssql_free_statement",
+ "mssql_get_last_message",
+ "mssql_guid_string",
+ "mssql_init",
+ "mssql_min_error_severity",
+ "mssql_min_message_severity",
+ "mssql_next_result",
+ "mssql_num_fields",
+ "mssql_num_rows",
+ "mssql_pconnect",
+ "mssql_query",
+ "mssql_result",
+ "mssql_rows_affected",
+ "mssql_select_db",
+ "mt_getrandmax",
+ "mt_rand",
+ "mt_srand",
+ "multColor",
+ "muscat_close",
+ "muscat_get",
+ "muscat_give",
+ "muscat_setup",
+ "muscat_setup_net",
+ "mysql_affected_rows",
+ "mysql_change_user",
+ "mysql_client_encoding",
+ "mysql_close",
+ "mysql_connect",
+ "mysql_create_db",
+ "mysql_data_seek",
+ "mysql_db_name",
+ "mysql_db_query",
+ "mysql_drop_db",
+ "mysql_errno",
+ "mysql_error",
+ "mysql_escape_string",
+ "mysql_fetch_array",
+ "mysql_fetch_assoc",
+ "mysql_fetch_field",
+ "mysql_fetch_lengths",
+ "mysql_fetch_object",
+ "mysql_fetch_row",
+ "mysql_field_flags",
+ "mysql_field_len",
+ "mysql_field_name",
+ "mysql_field_seek",
+ "mysql_field_table",
+ "mysql_field_type",
+ "mysql_free_result",
+ "mysql_get_client_info",
+ "mysql_get_host_info",
+ "mysql_get_proto_info",
+ "mysql_get_server_info",
+ "mysql_info",
+ "mysql_insert_id",
+ "mysql_list_dbs",
+ "mysql_list_fields",
+ "mysql_list_processes",
+ "mysql_list_tables",
+ "mysql_num_fields",
+ "mysql_num_rows",
+ "mysql_pconnect",
+ "mysql_ping",
+ "mysql_query",
+ "mysql_real_escape_string",
+ "mysql_result",
+ "mysql_select_db",
+ "mysql_stat",
+ "mysql_tablename",
+ "mysql_thread_id",
+ "mysql_unbuffered_query",
+ "name",
+ "natcasesort",
+ "natsort",
+ "ncurses_addch",
+ "ncurses_addchnstr",
+ "ncurses_addchstr",
+ "ncurses_addnstr",
+ "ncurses_addstr",
+ "ncurses_assume_default_colors",
+ "ncurses_attroff",
+ "ncurses_attron",
+ "ncurses_attrset",
+ "ncurses_baudrate",
+ "ncurses_beep",
+ "ncurses_bkgd",
+ "ncurses_bkgdset",
+ "ncurses_border",
+ "ncurses_can_change_color",
+ "ncurses_cbreak",
+ "ncurses_clear",
+ "ncurses_clrtobot",
+ "ncurses_clrtoeol",
+ "ncurses_color_set",
+ "ncurses_curs_set",
+ "ncurses_define_key",
+ "ncurses_def_prog_mode",
+ "ncurses_def_shell_mode",
+ "ncurses_delay_output",
+ "ncurses_delch",
+ "ncurses_deleteln",
+ "ncurses_delwin",
+ "ncurses_doupdate",
+ "ncurses_echo",
+ "ncurses_echochar",
+ "ncurses_end",
+ "ncurses_erase",
+ "ncurses_erasechar",
+ "ncurses_filter",
+ "ncurses_flash",
+ "ncurses_flushinp",
+ "ncurses_getch",
+ "ncurses_getmouse",
+ "ncurses_halfdelay",
+ "ncurses_has_colors",
+ "ncurses_has_ic",
+ "ncurses_has_il",
+ "ncurses_has_key",
+ "ncurses_hline",
+ "ncurses_inch",
+ "ncurses_init",
+ "ncurses_init_color",
+ "ncurses_init_pair",
+ "ncurses_insch",
+ "ncurses_insdelln",
+ "ncurses_insertln",
+ "ncurses_insstr",
+ "ncurses_instr",
+ "ncurses_isendwin",
+ "ncurses_keyok",
+ "ncurses_killchar",
+ "ncurses_longname",
+ "ncurses_mouseinterval",
+ "ncurses_mousemask",
+ "ncurses_move",
+ "ncurses_mvaddch",
+ "ncurses_mvaddchnstr",
+ "ncurses_mvaddchstr",
+ "ncurses_mvaddnstr",
+ "ncurses_mvaddstr",
+ "ncurses_mvcur",
+ "ncurses_mvdelch",
+ "ncurses_mvgetch",
+ "ncurses_mvhline",
+ "ncurses_mvinch",
+ "ncurses_mvvline",
+ "ncurses_mvwaddstr",
+ "ncurses_napms",
+ "ncurses_newwin",
+ "ncurses_nl",
+ "ncurses_nocbreak",
+ "ncurses_noecho",
+ "ncurses_nonl",
+ "ncurses_noqiflush",
+ "ncurses_noraw",
+ "ncurses_putp",
+ "ncurses_qiflush",
+ "ncurses_raw",
+ "ncurses_refresh",
+ "ncurses_resetty",
+ "ncurses_savetty",
+ "ncurses_scr_dump",
+ "ncurses_scr_init",
+ "ncurses_scrl",
+ "ncurses_scr_restore",
+ "ncurses_scr_set",
+ "ncurses_slk_attr",
+ "ncurses_slk_attroff",
+ "ncurses_slk_attron",
+ "ncurses_slk_attrset",
+ "ncurses_slk_clear",
+ "ncurses_slk_color",
+ "ncurses_slk_init",
+ "ncurses_slk_noutrefresh",
+ "ncurses_slk_refresh",
+ "ncurses_slk_restore",
+ "ncurses_slk_touch",
+ "ncurses_standend",
+ "ncurses_standout",
+ "ncurses_start_color",
+ "ncurses_termattrs",
+ "ncurses_termname",
+ "ncurses_timeout",
+ "ncurses_typeahead",
+ "ncurses_ungetch",
+ "ncurses_ungetmouse",
+ "ncurses_use_default_colors",
+ "ncurses_use_env",
+ "ncurses_use_extended_names",
+ "ncurses_vidattr",
+ "ncurses_vline",
+ "ncurses_wrefresh",
+ "new",
+ "next",
+ "nextframe",
+ "next_sibling",
+ "ngettext",
+ "nl2br",
+ "nl_langinfo",
+ "node_name",
+ "node_type",
+ "node_value",
+ "notations",
+ "notes_body",
+ "notes_copy_db",
+ "notes_create_db",
+ "notes_create_note",
+ "notes_drop_db",
+ "notes_find_note",
+ "notes_header_info",
+ "notes_list_msgs",
+ "notes_mark_read",
+ "notes_mark_unread",
+ "notes_nav_create",
+ "notes_search",
+ "notes_unread",
+ "notes_version",
+ "NULL",
+ "number_format",
+ "ob_clean",
+ "ob_end_clean",
+ "ob_end_flush",
+ "ob_flush",
+ "ob_get_contents",
+ "ob_get_length",
+ "ob_get_level",
+ "ob_get_status",
+ "ob_gzhandler",
+ "ob_iconv_handler",
+ "ob_implicit_flush",
+ "object",
+ "objectbyanchor",
+ "ob_start",
+ "ocibindbyname",
+ "ocicancel",
+ "OCICollAppend",
+ "ocicollassign",
+ "ocicollassignelem",
+ "ocicollgetelem",
+ "ocicollmax",
+ "ocicollsize",
+ "ocicolltrim",
+ "ocicolumnisnull",
+ "ocicolumnname",
+ "ocicolumnprecision",
+ "ocicolumnscale",
+ "ocicolumnsize",
+ "ocicolumntype",
+ "ocicolumntyperaw",
+ "ocicommit",
+ "ocidefinebyname",
+ "ocierror",
+ "ociexecute",
+ "ocifetch",
+ "ocifetchinto",
+ "ocifetchstatement",
+ "ocifreecollection",
+ "ocifreecursor",
+ "OCIFreeDesc",
+ "ocifreestatement",
+ "ociinternaldebug",
+ "ociloadlob",
+ "ocilogoff",
+ "ocilogon",
+ "ocinewcollection",
+ "ocinewcursor",
+ "ocinewdescriptor",
+ "ocinlogon",
+ "ocinumcols",
+ "ociparse",
+ "ociplogon",
+ "ociresult",
+ "ocirollback",
+ "ocirowcount",
+ "ocisavelob",
+ "ocisavelobfile",
+ "ociserverversion",
+ "ocisetprefetch",
+ "ocistatementtype",
+ "ociwritelobtofile",
+ "octdec",
+ "odbc_autocommit",
+ "odbc_binmode",
+ "odbc_close",
+ "odbc_close_all",
+ "odbc_columnprivileges",
+ "odbc_columns",
+ "odbc_commit",
+ "odbc_connect",
+ "odbc_cursor",
+ "odbc_data_source",
+ "odbc_do",
+ "odbc_error",
+ "odbc_errormsg",
+ "odbc_exec",
+ "odbc_execute",
+ "odbc_fetch_array",
+ "odbc_fetch_into",
+ "odbc_fetch_object",
+ "odbc_fetch_row",
+ "odbc_field_len",
+ "odbc_field_name",
+ "odbc_field_num",
+ "odbc_field_precision",
+ "odbc_field_scale",
+ "odbc_field_type",
+ "odbc_foreignkeys",
+ "odbc_free_result",
+ "odbc_gettypeinfo",
+ "odbc_longreadlen",
+ "odbc_next_result",
+ "odbc_num_fields",
+ "odbc_num_rows",
+ "odbc_pconnect",
+ "odbc_prepare",
+ "odbc_primarykeys",
+ "odbc_procedurecolumns",
+ "odbc_procedures",
+ "odbc_result",
+ "odbc_result_all",
+ "odbc_rollback",
+ "odbc_setoption",
+ "odbc_specialcolumns",
+ "odbc_statistics",
+ "odbc_tableprivileges",
+ "odbc_tables",
+ "opendir",
+ "openlog",
+ "openssl_csr_export",
+ "openssl_csr_export_to_file",
+ "openssl_csr_new",
+ "openssl_csr_sign",
+ "openssl_error_string",
+ "openssl_free_key",
+ "openssl_get_privatekey",
+ "openssl_get_publickey",
+ "openssl_open",
+ "openssl_pkcs7_decrypt",
+ "openssl_pkcs7_encrypt",
+ "openssl_pkcs7_sign",
+ "openssl_pkcs7_verify",
+ "openssl_pkey_export",
+ "openssl_pkey_export_to_file",
+ "openssl_pkey_get_private",
+ "openssl_pkey_get_public",
+ "openssl_pkey_new",
+ "openssl_private_decrypt",
+ "openssl_private_encrypt",
+ "openssl_public_decrypt",
+ "openssl_public_encrypt",
+ "openssl_seal",
+ "openssl_sign",
+ "openssl_verify",
+ "openssl_x509_check_private_key",
+ "openssl_x509_checkpurpose",
+ "openssl_x509_export",
+ "openssl_x509_export_to_file",
+ "openssl_x509_free",
+ "openssl_x509_parse",
+ "openssl_x509_read",
+ "ora_bind",
+ "ora_close",
+ "ora_columnname",
+ "ora_columnsize",
+ "ora_columntype",
+ "ora_commit",
+ "ora_commitoff",
+ "ora_commiton",
+ "ora_do",
+ "ora_error",
+ "ora_errorcode",
+ "ora_exec",
+ "ora_fetch",
+ "ora_fetch_into",
+ "ora_getcolumn",
+ "ora_logoff",
+ "ora_logon",
+ "ora_numcols",
+ "ora_numrows",
+ "ora_open",
+ "ora_parse",
+ "ora_plogon",
+ "ora_rollback",
+ "ord",
+ "output",
+ "overload",
+ "ovrimos_close",
+ "ovrimos_commit",
+ "ovrimos_connect",
+ "ovrimos_cursor",
+ "ovrimos_exec",
+ "ovrimos_execute",
+ "ovrimos_fetch_into",
+ "ovrimos_fetch_row",
+ "ovrimos_field_len",
+ "ovrimos_field_name",
+ "ovrimos_field_num",
+ "ovrimos_field_type",
+ "ovrimos_free_result",
+ "ovrimos_longreadlen",
+ "ovrimos_num_fields",
+ "ovrimos_num_rows",
+ "ovrimos_prepare",
+ "ovrimos_result",
+ "ovrimos_result_all",
+ "ovrimos_rollback",
+ "owner_document",
+ "pack",
+ "parent_node",
+ "parents",
+ "parse_ini_file",
+ "parse_str",
+ "parse_url",
+ "passthru",
+ "pathinfo",
+ "PATH_TRANSLATED",
+ "pclose",
+ "pcntl_exec",
+ "pcntl_fork",
+ "pcntl_signal",
+ "pcntl_waitpid",
+ "pcntl_wexitstatus",
+ "pcntl_wifexited",
+ "pcntl_wifsignaled",
+ "pcntl_wifstopped",
+ "pcntl_wstopsig",
+ "pcntl_wtermsig",
+ "pdf_add_annotation",
+ "pdf_add_bookmark",
+ "pdf_add_launchlink",
+ "pdf_add_locallink",
+ "pdf_add_note",
+ "pdf_add_outline",
+ "pdf_add_pdflink",
+ "pdf_add_thumbnail",
+ "pdf_add_weblink",
+ "pdf_arc",
+ "pdf_arcn",
+ "pdf_attach_file",
+ "pdf_begin_page",
+ "pdf_begin_pattern",
+ "pdf_begin_template",
+ "pdf_circle",
+ "pdf_clip",
+ "pdf_close",
+ "pdf_close_image",
+ "pdf_closepath",
+ "pdf_closepath_fill_stroke",
+ "pdf_closepath_stroke",
+ "pdf_close_pdi",
+ "pdf_close_pdi_page",
+ "pdf_concat",
+ "pdf_continue_text",
+ "pdf_curveto",
+ "pdf_delete",
+ "pdf_end_page",
+ "pdf_endpath",
+ "pdf_end_pattern",
+ "pdf_end_template",
+ "pdf_fill",
+ "pdf_fill_stroke",
+ "pdf_findfont",
+ "pdf_get_buffer",
+ "pdf_get_font",
+ "pdf_get_fontname",
+ "pdf_get_fontsize",
+ "pdf_get_image_height",
+ "pdf_get_image_width",
+ "pdf_get_majorversion",
+ "pdf_get_minorversion",
+ "pdf_get_parameter",
+ "pdf_get_pdi_parameter",
+ "pdf_get_pdi_value",
+ "pdf_get_value",
+ "pdf_initgraphics",
+ "pdf_lineto",
+ "pdf_makespotcolor",
+ "pdf_moveto",
+ "pdf_new",
+ "pdf_open",
+ "pdf_open_CCITT",
+ "pdf_open_file",
+ "pdf_open_gif",
+ "pdf_open_image",
+ "pdf_open_image_file",
+ "pdf_open_jpeg",
+ "pdf_open_memory_image",
+ "pdf_open_pdi",
+ "pdf_open_pdi_page",
+ "pdf_open_png",
+ "pdf_open_tiff",
+ "pdf_place_image",
+ "pdf_place_pdi_page",
+ "pdf_rect",
+ "pdf_restore",
+ "pdf_rotate",
+ "pdf_save",
+ "pdf_scale",
+ "pdf_set_border_color",
+ "pdf_set_border_dash",
+ "pdf_set_border_style",
+ "pdf_set_char_spacing",
+ "pdf_setcolor",
+ "pdf_setdash",
+ "pdf_set_duration",
+ "pdf_setflat",
+ "pdf_set_font",
+ "pdf_setfont",
+ "pdf_setgray",
+ "pdf_setgray_fill",
+ "pdf_setgray_stroke",
+ "pdf_set_horiz_scaling",
+ "pdf_set_info",
+ "pdf_set_info_author",
+ "pdf_set_info_creator",
+ "pdf_set_info_keywords",
+ "pdf_set_info_subject",
+ "pdf_set_info_title",
+ "pdf_set_leading",
+ "pdf_setlinecap",
+ "pdf_setlinejoin",
+ "pdf_setlinewidth",
+ "pdf_setmatrix",
+ "pdf_setmiterlimit",
+ "pdf_set_parameter",
+ "pdf_setpolydash",
+ "pdf_setrgbcolor",
+ "pdf_setrgbcolor_fill",
+ "pdf_setrgbcolor_stroke",
+ "pdf_set_text_matrix",
+ "pdf_set_text_pos",
+ "pdf_set_text_rendering",
+ "pdf_set_text_rise",
+ "pdf_set_value",
+ "pdf_set_word_spacing",
+ "pdf_show",
+ "pdf_show_boxed",
+ "pdf_show_xy",
+ "pdf_skew",
+ "pdf_stringwidth",
+ "pdf_stroke",
+ "pdf_translate",
+ "PEAR_EXTENSION_DIR",
+ "PEAR_INSTALL_DIR",
+ "pfpro_cleanup",
+ "pfpro_init",
+ "pfpro_process",
+ "pfpro_process_raw",
+ "pfpro_version",
+ "pfsockopen",
+ "pg_affected_rows",
+ "pg_cancel_query",
+ "pg_client_encoding",
+ "pg_close",
+ "pg_connect",
+ "pg_connection_busy",
+ "pg_connection_reset",
+ "pg_connection_status",
+ "pg_convert",
+ "pg_copy_from",
+ "pg_copy_to",
+ "pg_dbname",
+ "pg_delete",
+ "pg_end_copy",
+ "pg_escape_bytea",
+ "pg_escape_string",
+ "pg_fetch_all",
+ "pg_fetch_array",
+ "pg_fetch_assoc",
+ "pg_fetch_object",
+ "pg_fetch_result",
+ "pg_fetch_row",
+ "pg_field_is_null",
+ "pg_field_name",
+ "pg_field_num",
+ "pg_field_prtlen",
+ "pg_field_size",
+ "pg_field_type",
+ "pg_free_result",
+ "pg_get_notify",
+ "pg_get_pid",
+ "pg_get_result",
+ "pg_host",
+ "pg_insert",
+ "pg_last_error",
+ "pg_last_notice",
+ "pg_last_oid",
+ "pg_lo_close",
+ "pg_lo_create",
+ "pg_lo_export",
+ "pg_lo_import",
+ "pg_lo_open",
+ "pg_lo_read",
+ "pg_lo_read_all",
+ "pg_lo_seek",
+ "pg_lo_tell",
+ "pg_lo_unlink",
+ "pg_lo_write",
+ "pg_meta_data",
+ "pg_num_fields",
+ "pg_num_rows",
+ "pg_options",
+ "pg_pconnect",
+ "pg_ping",
+ "pg_port",
+ "pg_put_line",
+ "pg_query",
+ "pg_result_error",
+ "pg_result_seek",
+ "pg_result_status",
+ "pg_select",
+ "pg_send_query",
+ "pg_set_client_encoding",
+ "pg_trace",
+ "pg_tty",
+ "pg_unescape_bytea",
+ "pg_untrace",
+ "pg_update",
+ "PHP_BINDIR",
+ "PHP_CONFIG_FILE_PATH",
+ "phpcredits",
+ "PHP_DATADIR",
+ "PHP_ERRMSG",
+ "PHP_EXTENSION_DIR",
+ "phpinfo",
+ "php_ini_scanned_files",
+ "PHP_LIBDIR",
+ "PHP_LOCALSTATEDIR",
+ "php_logo_guid",
+ "PHP_OS",
+ "PHP_OUTPUT_HANDLER_CONT",
+ "PHP_OUTPUT_HANDLER_END",
+ "PHP_OUTPUT_HANDLER_START",
+ "php_sapi_name",
+ "PHP_SELF",
+ "PHP_SYSCONFDIR",
+ "php_uname",
+ "phpversion",
+ "PHP_VERSION",
+ "pi",
+ "png2wbmp",
+ "popen",
+ "pos",
+ "posix_ctermid",
+ "posix_getcwd",
+ "posix_getegid",
+ "posix_geteuid",
+ "posix_getgid",
+ "posix_getgrgid",
+ "posix_getgrnam",
+ "posix_getgroups",
+ "posix_getlogin",
+ "posix_getpgid",
+ "posix_getpgrp",
+ "posix_getpid",
+ "posix_getppid",
+ "posix_getpwnam",
+ "posix_getpwuid",
+ "posix_getrlimit",
+ "posix_getsid",
+ "posix_getuid",
+ "posix_isatty",
+ "posix_kill",
+ "posix_mkfifo",
+ "posix_setegid",
+ "posix_seteuid",
+ "posix_setgid",
+ "posix_setpgid",
+ "posix_setsid",
+ "posix_setuid",
+ "posix_times",
+ "posix_ttyname",
+ "posix_uname",
+ "_POST",
+ "pow",
+ "prefix",
+ "preg_grep",
+ "preg_match",
+ "preg_match_all",
+ "preg_quote",
+ "preg_replace",
+ "preg_replace_callback",
+ "preg_split",
+ "prev",
+ "previous_sibling",
+ "print",
+ "printer_abort",
+ "printer_close",
+ "printer_create_brush",
+ "printer_create_dc",
+ "printer_create_font",
+ "printer_create_pen",
+ "printer_delete_brush",
+ "printer_delete_dc",
+ "printer_delete_font",
+ "printer_delete_pen",
+ "printer_draw_bmp",
+ "printer_draw_chord",
+ "printer_draw_elipse",
+ "printer_draw_line",
+ "printer_draw_pie",
+ "printer_draw_rectangle",
+ "printer_draw_roundrect",
+ "printer_draw_text",
+ "printer_end_doc",
+ "printer_end_page",
+ "printer_get_option",
+ "printer_list",
+ "printer_logical_fontheight",
+ "printer_open",
+ "printer_select_brush",
+ "printer_select_font",
+ "printer_select_pen",
+ "printer_set_option",
+ "printer_start_doc",
+ "printer_start_page",
+ "printer_write",
+ "printf",
+ "print_r",
+ "private",
+ "proc_close",
+ "process",
+ "proc_open",
+ "protected",
+ "pspell_add_to_personal",
+ "pspell_add_to_session",
+ "pspell_check",
+ "pspell_clear_session",
+ "pspell_config_create",
+ "pspell_config_ignore",
+ "pspell_config_mode",
+ "pspell_config_personal",
+ "pspell_config_repl",
+ "pspell_config_runtogether",
+ "pspell_config_save_repl",
+ "pspell_new",
+ "pspell_new_config",
+ "pspell_new_personal",
+ "pspell_save_wordlist",
+ "pspell_store_replacement",
+ "pspell_suggest",
+ "public",
+ "public_id",
+ "putenv",
+ "qdom_error",
+ "qdom_tree",
+ "QUERY_STRING",
+ "quoted_printable_decode",
+ "quotemeta",
+ "rad2deg",
+ "rand",
+ "range",
+ "rawurldecode",
+ "rawurlencode",
+ "read",
+ "readdir",
+ "read_exif_data",
+ "readfile",
+ "readgzfile",
+ "readline",
+ "readline_add_history",
+ "readline_clear_history",
+ "readline_completion_function",
+ "readline_info",
+ "readline_list_history",
+ "readline_read_history",
+ "readline_write_history",
+ "readlink",
+ "realpath",
+ "reason",
+ "recode",
+ "recode_file",
+ "recode_string",
+ "register_shutdown_function",
+ "register_tick_function",
+ "REMOTE_ADDR",
+ "REMOTE_PORT",
+ "remove",
+ "remove_attribute",
+ "remove_child",
+ "rename",
+ "replace",
+ "replace_child",
+ "replace_node",
+ "_REQUEST",
+ "REQUEST_METHOD",
+ "REQUEST_URI",
+ "require",
+ "require_once",
+ "reset",
+ "restore_error_handler",
+ "restore_include_path",
+ "result_dump_file",
+ "result_dump_mem",
+ "return",
+ "rewind",
+ "rewinddir",
+ "rmdir",
+ "Rotate",
+ "rotateTo",
+ "round",
+ "rsort",
+ "rtrim",
+ "save",
+ "scale",
+ "scaleTo",
+ "SCRIPT_FILENAME",
+ "SCRIPT_NAME",
+ "sem_acquire",
+ "sem_get",
+ "sem_release",
+ "sem_remove",
+ "serialize",
+ "_SERVER",
+ "SERVER_ADMIN",
+ "SERVER_NAME",
+ "SERVER_PORT",
+ "SERVER_PROTOCOL",
+ "SERVER_SIGNATURE",
+ "SERVER_SOFTWARE",
+ "sesam_affected_rows",
+ "sesam_commit",
+ "sesam_connect",
+ "sesam_diagnostic",
+ "sesam_disconnect",
+ "sesam_errormsg",
+ "sesam_execimm",
+ "sesam_fetch_array",
+ "sesam_fetch_result",
+ "sesam_fetch_row",
+ "sesam_field_array",
+ "sesam_field_name",
+ "sesam_free_result",
+ "sesam_num_fields",
+ "sesam_query",
+ "sesam_rollback",
+ "sesam_seek_row",
+ "sesam_settransaction",
+ "_SESSION",
+ "session_cache_expire",
+ "session_cache_limiter",
+ "session_decode",
+ "session_destroy",
+ "session_encode",
+ "session_get_cookie_params",
+ "session_id",
+ "session_is_registered",
+ "session_module_name",
+ "session_name",
+ "session_readonly",
+ "session_register",
+ "session_save_path",
+ "session_set_cookie_params",
+ "session_set_save_handler",
+ "session_start",
+ "session_unregister",
+ "session_unset",
+ "session_write_close",
+ "setAction",
+ "set_attribute",
+ "setbackground",
+ "setbounds",
+ "setcolor",
+ "setColor",
+ "setcommitedversion",
+ "set_content",
+ "setcookie",
+ "setDepth",
+ "setdimension",
+ "setdown",
+ "set_error_handler",
+ "set_file_buffer",
+ "setFont",
+ "setframes",
+ "setHeight",
+ "setHit",
+ "set_include_path",
+ "setindentation",
+ "setLeftFill",
+ "setLeftMargin",
+ "setLine",
+ "setLineSpacing",
+ "setlocale",
+ "set_magic_quotes_runtime",
+ "setMargins",
+ "set_name",
+ "setname",
+ "setName",
+ "set_namespace",
+ "setOver",
+ "setrate",
+ "setRatio",
+ "setRightFill",
+ "setrightMargin",
+ "setSpacing",
+ "set_time_limit",
+ "settype",
+ "setUp",
+ "sha1",
+ "sha1_file",
+ "shell_exec",
+ "shm_attach",
+ "shm_detach",
+ "shm_get_var",
+ "shmop_close",
+ "shmop_delete",
+ "shmop_open",
+ "shmop_read",
+ "shmop_size",
+ "shmop_write",
+ "shm_put_var",
+ "shm_remove",
+ "shm_remove_var",
+ "show_source",
+ "shuffle",
+ "similar_text",
+ "sin",
+ "sinh",
+ "sizeof",
+ "skewX",
+ "skewXTo",
+ "skewY",
+ "skewYTo",
+ "sleep",
+ "snmpget",
+ "snmp_get_quick_print",
+ "snmprealwalk",
+ "snmpset",
+ "snmp_set_quick_print",
+ "snmpwalk",
+ "snmpwalkoid",
+ "socket_accept",
+ "socket_bind",
+ "socket_clear_error",
+ "socket_close",
+ "socket_connect",
+ "socket_create",
+ "socket_create_listen",
+ "socket_create_pair",
+ "socket_get_option",
+ "socket_getpeername",
+ "socket_getsockname",
+ "socket_get_status",
+ "socket_iovec_add",
+ "socket_iovec_alloc",
+ "socket_iovec_delete",
+ "socket_iovec_fetch",
+ "socket_iovec_free",
+ "socket_iovec_set",
+ "socket_last_error",
+ "socket_listen",
+ "socket_read",
+ "socket_readv",
+ "socket_recv",
+ "socket_recvfrom",
+ "socket_recvmsg",
+ "socket_select",
+ "socket_send",
+ "socket_sendmsg",
+ "socket_sendto",
+ "socket_set_blocking",
+ "socket_set_nonblock",
+ "socket_set_option",
+ "socket_set_timeout",
+ "socket_shutdown",
+ "socket_strerror",
+ "socket_write",
+ "socket_writev",
+ "sort",
+ "soundex",
+ "specified",
+ "split",
+ "spliti",
+ "sprintf",
+ "sql_regcase",
+ "sqrt",
+ "srand",
+ "srcanchors",
+ "srcsofdst",
+ "sscanf",
+ "stat",
+ "static",
+ "stdClass",
+ "strcasecmp",
+ "strchr",
+ "strcmp",
+ "strcoll",
+ "strcspn",
+ "stream_context_create",
+ "stream_context_get_options",
+ "stream_context_set_option",
+ "stream_context_set_params",
+ "stream_filter_append",
+ "stream_filter_prepend",
+ "stream_get_filters",
+ "stream_get_meta_data",
+ "stream_get_wrappers",
+ "streammp3",
+ "stream_register_filter",
+ "stream_register_wrapper",
+ "stream_select",
+ "stream_set_blocking",
+ "stream_set_timeout",
+ "stream_set_write_buffer",
+ "strftime",
+ "stripcslashes",
+ "stripslashes",
+ "strip_tags",
+ "stristr",
+ "strlen",
+ "strnatcasecmp",
+ "strnatcmp",
+ "strncasecmp",
+ "strncmp",
+ "str_pad",
+ "strpos",
+ "strrchr",
+ "str_repeat",
+ "str_replace",
+ "strrev",
+ "str_rot13",
+ "strrpos",
+ "str_shuffle",
+ "strspn",
+ "strstr",
+ "strtok",
+ "strtolower",
+ "strtotime",
+ "strtoupper",
+ "strtr",
+ "strval",
+ "str_word_count",
+ "substr",
+ "substr_count",
+ "substr_replace",
+ "SWFAction",
+ "swf_actiongeturl",
+ "swf_actiongotoframe",
+ "swf_actiongotolabel",
+ "swf_actionnextframe",
+ "swf_actionplay",
+ "swf_actionprevframe",
+ "swf_actionsettarget",
+ "swf_actionstop",
+ "swf_actiontogglequality",
+ "swf_actionwaitforframe",
+ "swf_addbuttonrecord",
+ "swf_addcolor",
+ "SWFBitmap",
+ "SWFbutton",
+ "swfbutton_keypress",
+ "swf_closefile",
+ "swf_definebitmap",
+ "swf_definefont",
+ "swf_defineline",
+ "swf_definepoly",
+ "swf_definerect",
+ "swf_definetext",
+ "SWFDisplayItem",
+ "swf_endbutton",
+ "swf_enddoaction",
+ "swf_endshape",
+ "swf_endsymbol",
+ "SWFFill",
+ "SWFFont",
+ "swf_fontsize",
+ "swf_fontslant",
+ "swf_fonttracking",
+ "swf_getbitmapinfo",
+ "swf_getfontinfo",
+ "swf_getframe",
+ "SWFGradient",
+ "swf_labelframe",
+ "swf_lookat",
+ "swf_modifyobject",
+ "SWFMorph",
+ "SWFMovie",
+ "swf_mulcolor",
+ "swf_nextid",
+ "swf_oncondition",
+ "swf_openfile",
+ "swf_ortho",
+ "swf_ortho2",
+ "swf_perspective",
+ "swf_placeobject",
+ "swf_polarview",
+ "swf_popmatrix",
+ "swf_posround",
+ "swf_pushmatrix",
+ "swf_removeobject",
+ "swf_rotate",
+ "swf_scale",
+ "swf_setfont",
+ "swf_setframe",
+ "SWFShape",
+ "swf_shapearc",
+ "swf_shapecurveto",
+ "swf_shapecurveto3",
+ "swf_shapefillbitmapclip",
+ "swf_shapefillbitmaptile",
+ "swf_shapefilloff",
+ "swf_shapefillsolid",
+ "swf_shapelinesolid",
+ "swf_shapelineto",
+ "swf_shapemoveto",
+ "swf_showframe",
+ "SWFSprite",
+ "swf_startbutton",
+ "swf_startdoaction",
+ "swf_startshape",
+ "swf_startsymbol",
+ "SWFText",
+ "SWFTextField",
+ "swf_textwidth",
+ "swf_translate",
+ "swf_viewport",
+ "switch",
+ "sybase_affected_rows",
+ "sybase_close",
+ "sybase_connect",
+ "sybase_data_seek",
+ "sybase_fetch_array",
+ "sybase_fetch_field",
+ "sybase_fetch_object",
+ "sybase_fetch_row",
+ "sybase_field_seek",
+ "sybase_free_result",
+ "sybase_get_last_message",
+ "sybase_min_client_severity",
+ "sybase_min_error_severity",
+ "sybase_min_message_severity",
+ "sybase_min_server_severity",
+ "sybase_num_fields",
+ "sybase_num_rows",
+ "sybase_pconnect",
+ "sybase_query",
+ "sybase_result",
+ "sybase_select_db",
+ "symlink",
+ "syslog",
+ "system",
+ "system_id",
+ "tagname",
+ "tan",
+ "tanh",
+ "target",
+ "tempnam",
+ "textdomain",
+ "time",
+ "title",
+ "tmpfile",
+ "token_get_all",
+ "token_name",
+ "touch",
+ "trigger_error",
+ "trim",
+ "TRUE",
+ "type",
+ "uasort",
+ "ucfirst",
+ "ucwords",
+ "udm_add_search_limit",
+ "udm_alloc_agent",
+ "udm_api_version",
+ "udm_cat_list",
+ "udm_cat_path",
+ "udm_check_charset",
+ "udm_check_stored",
+ "udm_clear_search_limits",
+ "udm_close_stored",
+ "udm_crc32",
+ "udm_errno",
+ "udm_error",
+ "udm_find",
+ "udm_free_agent",
+ "udm_free_ispell_data",
+ "udm_free_res",
+ "udm_get_doc_count",
+ "udm_get_res_field",
+ "udm_get_res_param",
+ "udm_load_ispell_data",
+ "udm_open_stored",
+ "udm_set_agent_param",
+ "uksort",
+ "umask",
+ "uniqid",
+ "unixtojd",
+ "unlink",
+ "unlink_node",
+ "unlock",
+ "unpack",
+ "unregister_tick_function",
+ "unserialize",
+ "unset",
+ "urldecode",
+ "urlencode",
+ "user",
+ "user_error",
+ "userlist",
+ "usleep",
+ "usort",
+ "utf8_decode",
+ "utf8_encode",
+ "value",
+ "values",
+ "var",
+ "var_dump",
+ "var_export",
+ "version_compare",
+ "virtual",
+ "vpopmail_add_alias_domain",
+ "vpopmail_add_alias_domain_ex",
+ "vpopmail_add_domain",
+ "vpopmail_add_domain_ex",
+ "vpopmail_add_user",
+ "vpopmail_alias_add",
+ "vpopmail_alias_del",
+ "vpopmail_alias_del_domain",
+ "vpopmail_alias_get",
+ "vpopmail_alias_get_all",
+ "vpopmail_auth_user",
+ "vpopmail_del_domain",
+ "vpopmail_del_domain_ex",
+ "vpopmail_del_user",
+ "vpopmail_error",
+ "vpopmail_passwd",
+ "vpopmail_set_user_quota",
+ "vprintf",
+ "vsprintf",
+ "w32api_deftype",
+ "w32api_init_dtype",
+ "w32api_invoke_function",
+ "w32api_register_function",
+ "w32api_set_call_method",
+ "wddx_add_vars",
+ "wddx_deserialize",
+ "wddx_packet_end",
+ "wddx_packet_start",
+ "wddx_serialize_value",
+ "wddx_serialize_vars",
+ "while",
+ "wordwrap",
+ "xinclude",
+ "xml_error_string",
+ "xml_get_current_byte_index",
+ "xml_get_current_column_number",
+ "xml_get_current_line_number",
+ "xml_get_error_code",
+ "xml_parse",
+ "xml_parse_into_struct",
+ "xml_parser_create",
+ "xml_parser_create_ns",
+ "xml_parser_free",
+ "xml_parser_get_option",
+ "xml_parser_set_option",
+ "xmlrpc_decode",
+ "xmlrpc_decode_request",
+ "xmlrpc_encode",
+ "xmlrpc_encode_request",
+ "xmlrpc_get_type",
+ "xmlrpc_parse_method_descriptions",
+ "xmlrpc_server_add_introspection_data",
+ "xmlrpc_server_call_method",
+ "xmlrpc_server_create",
+ "xmlrpc_server_destroy",
+ "xmlrpc_server_register_introspection_callback",
+ "xmlrpc_server_register_method",
+ "xmlrpc_set_type",
+ "xml_set_character_data_handler",
+ "xml_set_default_handler",
+ "xml_set_element_handler",
+ "xml_set_end_namespace_decl_handler",
+ "xml_set_external_entity_ref_handler",
+ "xml_set_notation_decl_handler",
+ "xml_set_object",
+ "xml_set_processing_instruction_handler",
+ "xml_set_start_namespace_decl_handler",
+ "xml_set_unparsed_entity_decl_handler",
+ "xpath_eval",
+ "xpath_eval_expression",
+ "xpath_new_context",
+ "xptr_eval",
+ "xptr_new_context",
+ "xslt_create",
+ "xslt_errno",
+ "xslt_error",
+ "xslt_free",
+ "xslt_output_process",
+ "xslt_set_base",
+ "xslt_set_encoding",
+ "xslt_set_error_handler",
+ "xslt_set_log",
+ "xslt_set_sax_handler",
+ "xslt_set_sax_handlers",
+ "xslt_set_scheme_handler",
+ "xslt_set_scheme_handlers",
+ "yaz_addinfo",
+ "yaz_ccl_conf",
+ "yaz_ccl_parse",
+ "yaz_close",
+ "yaz_connect",
+ "yaz_database",
+ "yaz_element",
+ "yaz_errno",
+ "yaz_error",
+ "yaz_get_option",
+ "yaz_hits",
+ "yaz_itemorder",
+ "yaz_present",
+ "yaz_range",
+ "yaz_record",
+ "yaz_scan",
+ "yaz_scan_result",
+ "yaz_schema",
+ "yaz_search",
+ "yaz_set_option",
+ "yaz_sort",
+ "yaz_syntax",
+ "yaz_wait",
+ "yp_all",
+ "yp_cat",
+ "yp_errno",
+ "yp_err_string",
+ "yp_first",
+ "yp_get_default_domain",
+ "yp_master",
+ "yp_match",
+ "yp_next",
+ "yp_order",
+ "zend_logo_guid",
+ "zend_version",
+ "zend_version",
+ "zip_close",
+ "zip_entry_close",
+ "zip_entry_compressedsize",
+ "zip_entry_compressionmethod",
+ "zip_entry_filesize",
+ "zip_entry_name",
+ "zip_entry_open",
+ "zip_entry_read",
+ "zip_open",
+ "zip_read",
+ 0
+ };
+
+Php5Writer::Php5Writer() {
+}
+
+Php5Writer::~Php5Writer() {}
+
+
+void Php5Writer::writeClass(UMLClassifier *c) {
+ if(!c) {
+ kDebug()<<"Cannot write class of NULL concept!" << endl;
+ return;
+ }
+
+ QString classname = cleanName(c->getName());
+ //find an appropriate name for our file
+ QString fileName = findFileName(c, ".php");
+ if (fileName.isEmpty()) {
+ emit codeGenerated(c, false);
+ return;
+ }
+
+ QFile filephp;
+ if(!openFile(filephp, fileName)) {
+ emit codeGenerated(c, false);
+ return;
+ }
+ QTextStream php(&filephp);
+
+ //////////////////////////////
+ //Start generating the code!!
+ /////////////////////////////
+
+
+ //try to find a heading file (license, coments, etc)
+ QString str;
+ str = getHeadingFile(".php");
+ if(!str.isEmpty()) {
+ str.replace(QRegExp("%filename%"),fileName);
+ str.replace(QRegExp("%filepath%"),filephp.name());
+ php<<str<<m_endl;
+ }
+
+
+ //write includes
+ UMLPackageList includes;
+ findObjectsRelated(c,includes);
+ UMLPackage *conc;
+ for(conc = includes.first(); conc ;conc = includes.next()) {
+ QString headerName = findFileName(conc, ".php");
+ if (!headerName.isEmpty()) {
+ php << "require_once '" << headerName << "';" << m_endl;
+ }
+ }
+ php << m_endl;
+
+ //Write class Documentation if there is somthing or if force option
+ if(forceDoc() || !c->getDoc().isEmpty()) {
+ php << m_endl << "/**" << m_endl;
+ php << " * class " << classname << m_endl;
+ php << formatDoc(c->getDoc()," * ");
+ php << " */" << m_endl ;
+ }
+
+ UMLClassifierList superclasses = c->getSuperClasses();
+ UMLAssociationList aggregations = c->getAggregations();
+ UMLAssociationList compositions = c->getCompositions();
+ UMLAssociationList realizations = c->getRealizations();
+ UMLAssociation *a;
+ bool isInterface = c->isInterface();
+
+ //check if it is an interface or regular class
+ if(isInterface) {
+ php << "interface " << classname;
+ } else {
+ //check if class is abstract and / or has abstract methods
+ if(c->getAbstract())
+ php << "abstract ";
+ php << "class " << classname << (superclasses.count() > 0 ? " extends ":"");
+ if(superclasses.count() > 0) {
+ //php5 does not support multiple inheritance so only use the first one and print a warning if more are used
+ UMLClassifier *obj = superclasses.first();
+ php << cleanName(obj->getName());
+ if(superclasses.count() > 1)
+ php << m_indentation << "//WARNING: PHP5 does not support multiple inheritance but there is more than 1 superclass defined in your UML model!";
+ }
+ //check for realizations
+ if( !realizations.isEmpty()) {
+ int rc = realizations.count();
+ int ri = rc;
+ for (a = realizations.first(); a; a = realizations.next()) {
+ UMLObject *o = a->getObject(Uml::B);
+ QString typeName = cleanName(o->getName());
+ if(ri == rc)
+ php << m_endl << m_indentation << m_indentation << m_indentation << "implements ";
+ php << typeName << (--rc == 0 ? "" : ", ");
+ }
+ }
+ }
+ php << m_endl << '{' << m_endl;
+
+ //associations
+ if( forceSections() || !aggregations.isEmpty()) {
+ php<< m_endl << m_indentation << "/** Aggregations: */" << m_endl;
+ for (a = aggregations.first(); a; a = aggregations.next()) {
+ php<< m_endl;
+ //maybe we should parse the string here and take multiplicity into account to decide
+ //which container to use.
+ UMLObject *o = a->getObject(Uml::A);
+ if (o == NULL) {
+ kError() << "aggregation role A object is NULL" << endl;
+ continue;
+ }
+ QString typeName = cleanName(o->getName());
+ if (a->getMulti(Uml::A).isEmpty()) {
+ php << m_indentation << "var $m_" << ';' << m_endl;
+ } else {
+ php << m_indentation << "var $m_" << "Vector = array();" << m_endl;
+ }
+ }//end for
+ }
+
+ if( forceSections() || !compositions.isEmpty()) {
+ php<< m_endl << m_indentation << "/** Compositions: */" << m_endl;
+ for (a = compositions.first(); a ; a = compositions.next()) {
+ // see comment on Aggregation about multiplicity...
+ UMLObject *o = a->getObject(Uml::A);
+ if (o == NULL) {
+ kError() << "composition role A object is NULL" << endl;
+ continue;
+ }
+ QString typeName = cleanName(o->getName());
+ if (a->getMulti(Uml::A).isEmpty()) {
+ php << m_indentation << "var $m_" << ';' << m_endl;
+ } else {
+ php << m_indentation << "var $m_" << "Vector = array();" << m_endl;
+ }
+ }
+ }
+
+ //attributes
+ if (!isInterface)
+ writeAttributes(c, php);
+
+ //operations
+ writeOperations(c,php);
+
+ php << m_endl;
+
+ //finish file
+ php << m_endl << "} // end of " << classname << m_endl;
+ php << "?>" << m_endl;
+
+ //close files and notfiy we are done
+ filephp.close();
+ emit codeGenerated(c, true);
+}
+
+////////////////////////////////////////////////////////////////////////////////////
+// Helper Methods
+
+void Php5Writer::writeOperations(UMLClassifier *c, QTextStream &php) {
+
+ //Lists to store operations sorted by scope
+ UMLOperationList oppub,opprot,oppriv;
+
+ bool isInterface = c->isInterface();
+ bool generateErrorStub = false;
+
+ oppub.setAutoDelete(false);
+ opprot.setAutoDelete(false);
+ oppriv.setAutoDelete(false);
+
+ //sort operations by scope first and see if there are abstract methods
+ UMLOperationList opl(c->getOpList());
+ for(UMLOperation *op = opl.first(); op ; op = opl.next()) {
+ switch(op->getVisibility()) {
+ case Uml::Visibility::Public:
+ oppub.append(op);
+ break;
+ case Uml::Visibility::Protected:
+ opprot.append(op);
+ break;
+ case Uml::Visibility::Private:
+ oppriv.append(op);
+ break;
+ default:
+ break;
+ }
+ }
+
+ QString classname(cleanName(c->getName()));
+
+ //write operations to file
+ if(forceSections() || !oppub.isEmpty()) {
+ php << m_endl;
+ writeOperations(classname,oppub,php,isInterface,generateErrorStub);
+ }
+
+ if(forceSections() || !opprot.isEmpty()) {
+ php << m_endl;
+ writeOperations(classname,opprot,php,isInterface,generateErrorStub);
+ }
+
+ if(forceSections() || !oppriv.isEmpty()) {
+ php << m_endl;
+ writeOperations(classname,oppriv,php,isInterface,generateErrorStub);
+ }
+
+
+ // build an oplist for all of the realized operations
+ UMLOperationList opreal;
+ opreal.setAutoDelete(false);
+
+ // go through each of the realizations, taking each op
+ UMLAssociationList realizations = c->getRealizations();
+ UMLAssociation *a;
+
+ if( !realizations.isEmpty()) {
+ for (a = realizations.first(); a; a = realizations.next()) {
+
+ // we know its a classifier if its in the list
+ UMLClassifier *real = (UMLClassifier*)a->getObject(Uml::B);
+
+ UMLOperationList opl(real->getOpList());
+ for(UMLOperation *op = opl.first(); op ; op = opl.next()) {
+ opreal.append(op);
+ }
+ }
+ }
+
+ // write out all the realizations operations
+ writeOperations(classname,opreal,php,false,true);
+
+}
+
+void Php5Writer::writeOperations(const QString &/* classname */, UMLOperationList &opList,
+ QTextStream &php, bool isInterface /* = false */,
+ bool generateErrorStub /* = false */) {
+ for (UMLOperation *op=opList.first(); op ; op=opList.next()) {
+ UMLAttributeList atl = op->getParmList();
+ UMLAttribute *at;
+ //write method doc if we have doc || if at least one of the params has doc
+ bool writeDoc = forceDoc() || !op->getDoc().isEmpty();
+ for (at = atl.first(); at; at = atl.next())
+ writeDoc |= !at->getDoc().isEmpty();
+
+ if( writeDoc ) //write method documentation
+ {
+ php <<m_indentation << "/**" << m_endl <<formatDoc(op->getDoc(),m_indentation + " * ");
+ php << m_indentation << " *" << m_endl;
+
+ for (at = atl.first(); at; at = atl.next()) //write parameter documentation
+ {
+ if(forceDoc() || !at->getDoc().isEmpty()) {
+ php <<m_indentation << " * @param " + at->getTypeName() + ' ' + cleanName(at->getName());
+ php << ' ' + formatDoc(at->getDoc(),"") << m_endl;
+ }
+ }//end for : write parameter documentation
+ php << m_indentation << " * @return " << op->getTypeName() << m_endl;
+ if (op->getAbstract()) php << m_indentation << " * @abstract" << m_endl;
+ if (op->getStatic()) php << m_indentation << " * @static" << m_endl;
+ switch(op->getVisibility()) {
+ case Uml::Visibility::Public:
+ php << m_indentation << " * @access public" << m_endl;
+ break;
+ case Uml::Visibility::Protected:
+ php << m_indentation << " * @access protected" << m_endl;
+ break;
+ case Uml::Visibility::Private:
+ php << m_indentation << " * @access private" << m_endl;
+ break;
+ default:
+ break;
+ }
+ php <<m_indentation << " */" << m_endl;
+ }//end if : write method documentation
+
+ php << m_indentation;
+ if (op->getAbstract()) php << "abstract ";
+ switch(op->getVisibility()) {
+ case Uml::Visibility::Public:
+ php << "public ";
+ break;
+ case Uml::Visibility::Protected:
+ php << "protected ";
+ break;
+ case Uml::Visibility::Private:
+ php << "private ";
+ break;
+ default:
+ break;
+ }
+ if (op->getStatic()) php << "static ";
+ php << "function " << cleanName(op->getName()) << "(";
+
+ int i= atl.count();
+ int j=0;
+ for (at = atl.first(); at; at = atl.next(), j++) {
+ php << " $" << cleanName(at->getName())
+ << (!(at->getInitialValue().isEmpty()) ?
+ (QString(" = ")+at->getInitialValue()) :
+ QString(""))
+ << ((j < i-1)?", ":"");
+ }
+ php <<" )";
+ if(!isInterface && !op->getAbstract()) {
+ php << " {" << m_endl << m_indentation << m_indentation;
+ if(generateErrorStub) {
+ php << "trigger_error(\"Implement \" . __FUNCTION__);";
+ }
+ php << m_endl << m_indentation << "} // end of member function " + cleanName(op->getName()) + m_endl;
+ }
+ else {
+ php << ';' + m_endl;
+ }
+ php << m_endl;
+ }//end for
+}
+
+void Php5Writer::writeAttributes(UMLClassifier *c, QTextStream &php) {
+ UMLAttributeList atpub, atprot, atpriv, atdefval;
+ atpub.setAutoDelete(false);
+ atprot.setAutoDelete(false);
+ atpriv.setAutoDelete(false);
+ atdefval.setAutoDelete(false);
+
+ //sort attributes by scope and see if they have a default value
+ UMLAttributeList atl = c->getAttributeList();
+ UMLAttribute *at;
+ for(at = atl.first(); at ; at = atl.next()) {
+ if(!at->getInitialValue().isEmpty())
+ atdefval.append(at);
+ switch(at->getVisibility()) {
+ case Uml::Visibility::Public:
+ atpub.append(at);
+ break;
+ case Uml::Visibility::Protected:
+ atprot.append(at);
+ break;
+ case Uml::Visibility::Private:
+ atpriv.append(at);
+ break;
+ default:
+ break;
+ }
+ }
+
+ if(forceSections() || atl.count())
+ php<< m_endl << m_indentation << " /*** Attributes: ***/" << m_endl <<m_endl;
+
+ if(forceSections() || atpub.count()) {
+ writeAttributes(atpub,php);
+ }
+
+ if(forceSections() || atprot.count()) {
+ writeAttributes(atprot,php);
+ }
+
+ if(forceSections() || atpriv.count()) {
+ writeAttributes(atpriv,php);
+ }
+}
+
+
+void Php5Writer::writeAttributes(UMLAttributeList &atList, QTextStream &php) {
+ for (UMLAttribute *at = atList.first(); at ; at = atList.next()) {
+ bool isStatic = at->getStatic();
+ if (forceDoc() || !at->getDoc().isEmpty()) {
+ php << m_indentation << "/**" << m_endl << formatDoc(at->getDoc(), m_indentation + " * ");
+ if(isStatic) php << m_indentation << " * @static" << m_endl;
+ switch(at->getVisibility()) {
+ case Uml::Visibility::Public:
+ php << m_indentation << " * @access public" << m_endl;
+ break;
+ case Uml::Visibility::Protected:
+ php << m_indentation << " * @access protected" << m_endl;
+ break;
+ case Uml::Visibility::Private:
+ php << m_indentation << " * @access private" << m_endl;
+ break;
+ default:
+ break;
+ }
+ php << m_indentation << " */" << m_endl;
+ }
+ php << m_indentation;
+ switch(at->getVisibility()) {
+ case Uml::Visibility::Public:
+ php << "public ";
+ break;
+ case Uml::Visibility::Protected:
+ php << "protected ";
+ break;
+ case Uml::Visibility::Private:
+ php << "private ";
+ break;
+ default:
+ break;
+ }
+ if(isStatic) php << "static ";
+ php << "$" << cleanName(at->getName());
+ if(!at->getInitialValue().isEmpty())
+ php << " = " << at->getInitialValue();
+ php << ";" << m_endl << m_endl;
+ } // end for
+ return;
+}
+
+/**
+ * returns "PHP"
+ */
+Uml::Programming_Language Php5Writer::getLanguage() {
+ return Uml::pl_PHP5;
+}
+
+const QStringList Php5Writer::reservedKeywords() const {
+
+ static QStringList keywords;
+
+ if (keywords.isEmpty()) {
+ for (int i = 0; php5words[i]; i++)
+ keywords.append(php5words[i]);
+ }
+
+ return keywords;
+}
+
+#include "php5writer.moc"
+
diff --git a/umbrello/umbrello/codegenerators/php5writer.h b/umbrello/umbrello/codegenerators/php5writer.h
new file mode 100644
index 00000000..3adc983c
--- /dev/null
+++ b/umbrello/umbrello/codegenerators/php5writer.h
@@ -0,0 +1,95 @@
+/***************************************************************************
+ php5writer.h - description
+ -------------------
+ begin : Thu Oct 17 2002
+ copyright : (C) 2002 by Heiko Nardmann
+ email : h.nardmann@secunet.de
+
+ php5 version by Thorsten Kunz (tk AT bytecrash DOT net)
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the 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 PHP5WRITER_H
+#define PHP5WRITER_H
+
+#include "simplecodegenerator.h"
+#include "../umlattributelist.h"
+#include "../umloperationlist.h"
+
+/**
+ * class Php5Writer is a PHP code generator for UMLClassifier objects
+ * Just call writeClass and feed it a UMLClassifier;
+ */
+class Php5Writer : public SimpleCodeGenerator {
+ Q_OBJECT
+public:
+
+ Php5Writer();
+ virtual ~Php5Writer();
+
+ /**
+ * call this method to generate Php code for a UMLClassifier
+ * @param c the class you want to generate code for.
+ */
+ virtual void writeClass(UMLClassifier *c);
+
+ /**
+ * returns "PHP"
+ */
+ virtual Uml::Programming_Language getLanguage();
+
+ /**
+ * get list of reserved keywords
+ */
+ virtual const QStringList reservedKeywords() const;
+
+private:
+
+ /**
+ * we do not want to write the comment "Private methods" twice
+ */
+ bool bPrivateSectionCommentIsWritten;
+
+ /**
+ * write all operations for a given class
+ *
+ * @param c the concept we are generating code for
+ * @param php output stream for the PHP file
+ */
+ void writeOperations(UMLClassifier *c, QTextStream &php);
+
+ /**
+ * write a list of class operations
+ *
+ * @param classname the name of the class
+ * @param opList the list of operations
+ * @param php output stream for the PHP file
+ * @param interface indicates if the operation is an interface member
+ */
+ void writeOperations(const QString &classname, UMLOperationList &opList,
+ QTextStream &php,
+ bool interface = false, bool generateErrorStub = false);
+
+ /** write all the attributes of a class
+ * @param c the class we are generating code for
+ * @param php output stream for the PHP file
+ */
+ void writeAttributes(UMLClassifier *c, QTextStream &php);
+
+ /** write a list of class attributes
+ * @param atList the list of attributes
+ * @param php output stream for the PHP file
+ */
+ void writeAttributes(UMLAttributeList &atList, QTextStream &php);
+};
+
+#endif //PHP5WRITER
+
diff --git a/umbrello/umbrello/codegenerators/phpwriter.cpp b/umbrello/umbrello/codegenerators/phpwriter.cpp
new file mode 100644
index 00000000..6d71c102
--- /dev/null
+++ b/umbrello/umbrello/codegenerators/phpwriter.cpp
@@ -0,0 +1,3339 @@
+/***************************************************************************
+ begin : Thu Oct 17 2002
+ copyright : (C) 2002 by Heiko Nardmann
+ email : h.nardmann@secunet.de
+ (C) 2003-2006 Umbrello UML Modeller Authors <uml-devel@uml.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. *
+ * *
+ ***************************************************************************/
+
+#include "phpwriter.h"
+
+#include <kdebug.h>
+#include <qregexp.h>
+#include <qtextstream.h>
+
+#include "../umldoc.h"
+#include "../classifier.h"
+#include "../association.h"
+#include "../attribute.h"
+#include "../operation.h"
+#include "../umlnamespace.h"
+
+static const char *words[] =
+ {
+ "abs",
+ "acos",
+ "acosh",
+ "add",
+ "addAction",
+ "addColor",
+ "addcslashes",
+ "addEntry",
+ "addFill",
+ "add_namespace",
+ "addShape",
+ "addslashes",
+ "addstring",
+ "addString",
+ "aggregate",
+ "aggregate_info",
+ "aggregate_methods",
+ "aggregate_methods_by_list",
+ "aggregate_methods_by_regexp",
+ "aggregate_properties",
+ "aggregate_properties_by_list",
+ "aggregate_properties_by_regexp",
+ "aggregation_info",
+ "align",
+ "apache_child_terminate",
+ "apache_lookup_uri",
+ "apache_note",
+ "apache_request_headers",
+ "apache_response_headers",
+ "apache_setenv",
+ "append_child",
+ "append_sibling",
+ "array",
+ "array_change_key_case",
+ "array_chunk",
+ "array_count_values",
+ "array_diff",
+ "array_diff_assoc",
+ "array_fill",
+ "array_filter",
+ "array_flip",
+ "array_intersect",
+ "array_intersect_assoc",
+ "array_key_exists",
+ "array_keys",
+ "array_map",
+ "array_merge",
+ "array_merge_recursive",
+ "array_multisort",
+ "array_pad",
+ "array_pop",
+ "array_push",
+ "array_rand",
+ "array_reduce",
+ "array_reverse",
+ "array_search",
+ "array_shift",
+ "array_slice",
+ "array_splice",
+ "array_sum",
+ "array_unique",
+ "array_unshift",
+ "array_values",
+ "array_walk",
+ "arsort",
+ "ascii2ebcdic",
+ "asin",
+ "asinh",
+ "asort",
+ "aspell_check",
+ "aspell_new",
+ "aspell_suggest",
+ "assert",
+ "assert_options",
+ "assign",
+ "atan",
+ "atan2",
+ "atanh",
+ "attreditable",
+ "attributes",
+ "base64_decode",
+ "base64_encode",
+ "base_convert",
+ "basename",
+ "bcadd",
+ "bccomp",
+ "bcdiv",
+ "bcmod",
+ "bcmul",
+ "bcpow",
+ "bcpowmod",
+ "bcscale",
+ "bcsqrt",
+ "bcsub",
+ "bin2hex",
+ "bindec",
+ "bindtextdomain",
+ "bind_textdomain_codeset",
+ "bool",
+ "break",
+ "bzclose",
+ "bzcompress",
+ "bzdecompress",
+ "bzerrno",
+ "bzerror",
+ "bzerrstr",
+ "bzflush",
+ "bzopen",
+ "bzread",
+ "bzwrite",
+ "cal_days_in_month",
+ "cal_from_jd",
+ "cal_info",
+ "call_user_func",
+ "call_user_func_array",
+ "call_user_method",
+ "call_user_method_array",
+ "cal_to_jd",
+ "ccvs_add",
+ "ccvs_auth",
+ "ccvs_command",
+ "ccvs_count",
+ "ccvs_delete",
+ "ccvs_done",
+ "ccvs_init",
+ "ccvs_lookup",
+ "ccvs_new",
+ "ccvs_report",
+ "ccvs_return",
+ "ccvs_reverse",
+ "ccvs_sale",
+ "ccvs_status",
+ "ccvs_textvalue",
+ "ccvs_void",
+ "ceil",
+ "chdir",
+ "checkdate",
+ "checkdnsrr",
+ "checkin",
+ "checkout",
+ "chgrp",
+ "child_nodes",
+ "children",
+ "chmod",
+ "chop",
+ "chown",
+ "chr",
+ "chroot",
+ "chunk_split",
+ "class",
+ "class_exists",
+ "clearstatcache",
+ "clone_node",
+ "closedir",
+ "closelog",
+ "com_addref",
+ "com_get",
+ "com_invoke",
+ "com_isenum",
+ "com_load",
+ "com_load_typelib",
+ "compact",
+ "com_propget",
+ "com_propput",
+ "com_propset",
+ "com_release",
+ "com_set",
+ "connection_aborted",
+ "connection_status",
+ "connection_timeout",
+ "constant",
+ "content",
+ "continue",
+ "convert_cyr_string",
+ "_COOKIE",
+ "copy",
+ "cos",
+ "cosh",
+ "count",
+ "count_chars",
+ "cpdf_add_annotation",
+ "cpdf_add_outline",
+ "cpdf_arc",
+ "cpdf_begin_text",
+ "cpdf_circle",
+ "cpdf_clip",
+ "cpdf_close",
+ "cpdf_closepath",
+ "cpdf_closepath_fill_stroke",
+ "cpdf_closepath_stroke",
+ "cpdf_continue_text",
+ "cpdf_curveto",
+ "cpdf_end_text",
+ "cpdf_fill",
+ "cpdf_fill_stroke",
+ "cpdf_finalize",
+ "cpdf_finalize_page",
+ "cpdf_global_set_document_limits",
+ "cpdf_import_jpeg",
+ "cpdf_lineto",
+ "cpdf_moveto",
+ "cpdf_newpath",
+ "cpdf_open",
+ "cpdf_output_buffer",
+ "cpdf_page_init",
+ "cpdf_place_inline_image",
+ "cpdf_rect",
+ "cpdf_restore",
+ "cpdf_rlineto",
+ "cpdf_rmoveto",
+ "cpdf_rotate",
+ "cpdf_rotate_text",
+ "cpdf_save",
+ "cpdf_save_to_file",
+ "cpdf_scale",
+ "cpdf_set_action_url",
+ "cpdf_set_char_spacing",
+ "cpdf_set_creator",
+ "cpdf_set_current_page",
+ "cpdf_setdash",
+ "cpdf_setflat",
+ "cpdf_set_font",
+ "cpdf_set_font_directories",
+ "cpdf_set_font_map_file",
+ "cpdf_setgray",
+ "cpdf_setgray_fill",
+ "cpdf_setgray_stroke",
+ "cpdf_set_horiz_scaling",
+ "cpdf_set_keywords",
+ "cpdf_set_leading",
+ "cpdf_setlinecap",
+ "cpdf_setlinejoin",
+ "cpdf_setlinewidth",
+ "cpdf_setmiterlimit",
+ "cpdf_set_page_animation",
+ "cpdf_setrgbcolor",
+ "cpdf_setrgbcolor_fill",
+ "cpdf_setrgbcolor_stroke",
+ "cpdf_set_subject",
+ "cpdf_set_text_matrix",
+ "cpdf_set_text_pos",
+ "cpdf_set_text_rendering",
+ "cpdf_set_text_rise",
+ "cpdf_set_title",
+ "cpdf_set_viewer_preferences",
+ "cpdf_set_word_spacing",
+ "cpdf_show",
+ "cpdf_show_xy",
+ "cpdf_stringwidth",
+ "cpdf_stroke",
+ "cpdf_text",
+ "cpdf_translate",
+ "crack_check",
+ "crack_closedict",
+ "crack_getlastmessage",
+ "crack_opendict",
+ "crc32",
+ "create_attribute",
+ "create_cdata_section",
+ "create_comment",
+ "create_element",
+ "create_element_ns",
+ "create_entity_reference",
+ "create_function",
+ "create_processing_instruction",
+ "create_text_node",
+ "crypt",
+ "ctype_alnum",
+ "ctype_alpha",
+ "ctype_cntrl",
+ "ctype_digit",
+ "ctype_graph",
+ "ctype_lower",
+ "ctype_print",
+ "ctype_punct",
+ "ctype_space",
+ "ctype_upper",
+ "ctype_xdigit",
+ "curl_close",
+ "curl_errno",
+ "curl_error",
+ "curl_exec",
+ "curl_getinfo",
+ "curl_init",
+ "curl_setopt",
+ "curl_version",
+ "current",
+ "cybercash_base64_decode",
+ "cybercash_base64_encode",
+ "cybercash_decr",
+ "cybercash_encr",
+ "cybermut_creerformulairecm",
+ "cybermut_creerreponsecm",
+ "cybermut_testmac",
+ "cyrus_authenticate",
+ "cyrus_bind",
+ "cyrus_close",
+ "cyrus_connect",
+ "cyrus_query",
+ "cyrus_unbind",
+ "data",
+ "date",
+ "dba_close",
+ "dba_delete",
+ "dba_exists",
+ "dba_fetch",
+ "dba_firstkey",
+ "dba_handlers",
+ "dba_insert",
+ "dba_list",
+ "dba_nextkey",
+ "dba_open",
+ "dba_optimize",
+ "dba_popen",
+ "dba_replace",
+ "dbase_add_record",
+ "dbase_close",
+ "dbase_create",
+ "dbase_delete_record",
+ "dbase_get_record",
+ "dbase_get_record_with_names",
+ "dbase_numfields",
+ "dbase_numrecords",
+ "dbase_open",
+ "dbase_pack",
+ "dbase_replace_record",
+ "dba_sync",
+ "dblist",
+ "dbmclose",
+ "dbmdelete",
+ "dbmexists",
+ "dbmfetch",
+ "dbmfirstkey",
+ "dbminsert",
+ "dbmnextkey",
+ "dbmopen",
+ "dbmreplace",
+ "dbplus_add",
+ "dbplus_aql",
+ "dbplus_chdir",
+ "dbplus_close",
+ "dbplus_curr",
+ "dbplus_errcode",
+ "dbplus_errno",
+ "dbplus_find",
+ "dbplus_first",
+ "dbplus_flush",
+ "dbplus_freealllocks",
+ "dbplus_freelock",
+ "dbplus_freerlocks",
+ "dbplus_getlock",
+ "dbplus_getunique",
+ "dbplus_info",
+ "dbplus_last",
+ "dbplus_lockrel",
+ "dbplus_next",
+ "dbplus_open",
+ "dbplus_prev",
+ "dbplus_rchperm",
+ "dbplus_rcreate",
+ "dbplus_rcrtexact",
+ "dbplus_rcrtlike",
+ "dbplus_resolve",
+ "dbplus_restorepos",
+ "dbplus_rkeys",
+ "dbplus_ropen",
+ "dbplus_rquery",
+ "dbplus_rrename",
+ "dbplus_rsecindex",
+ "dbplus_runlink",
+ "dbplus_rzap",
+ "dbplus_savepos",
+ "dbplus_setindex",
+ "dbplus_setindexbynumber",
+ "dbplus_sql",
+ "dbplus_tcl",
+ "dbplus_tremove",
+ "dbplus_undo",
+ "dbplus_undoprepare",
+ "dbplus_unlockrel",
+ "dbplus_unselect",
+ "dbplus_update",
+ "dbplus_xlockrel",
+ "dbplus_xunlockrel",
+ "dbstat",
+ "dbx_close",
+ "dbx_compare",
+ "dbx_connect",
+ "dbx_error",
+ "dbx_escape_string",
+ "dbx_query",
+ "dbx_sort",
+ "dcgettext",
+ "dcngettext",
+ "dcstat",
+ "deaggregate",
+ "debug_backtrace",
+ "debugger_off",
+ "debugger_on",
+ "decbin",
+ "dechex",
+ "declare",
+ "decoct",
+ "DEFAULT_INCLUDE_PATH",
+ "define",
+ "defined",
+ "define_syslog_variables",
+ "deg2rad",
+ "delete",
+ "description",
+ "dgettext",
+ "die",
+ "dio_close",
+ "dio_fcntl",
+ "dio_open",
+ "dio_read",
+ "dio_seek",
+ "dio_stat",
+ "dio_tcsetattr",
+ "dio_truncate",
+ "dio_write",
+ "dir",
+ "dirname",
+ "disk_free_space",
+ "diskfreespace",
+ "disk_total_space",
+ "dl",
+ "dngettext",
+ "dns_check_record",
+ "dns_get_mx",
+ "dns_get_record",
+ "do",
+ "doctype",
+ "document_element",
+ "DOCUMENT_ROOT",
+ "domxml_new_doc",
+ "domxml_open_file",
+ "domxml_open_mem",
+ "domxml_version",
+ "domxml_xmltree",
+ "domxml_xslt_stylesheet",
+ "domxml_xslt_stylesheet_doc",
+ "domxml_xslt_stylesheet_file",
+ "dotnet_load",
+ "doubleval",
+ "drawCurve",
+ "drawCurveTo",
+ "drawLine",
+ "drawLineTo",
+ "dstanchors",
+ "dstofsrcanchors",
+ "dump_file",
+ "dump_mem",
+ "dump_node",
+ "each",
+ "E_ALL",
+ "easter_date",
+ "easter_days",
+ "ebcdic2ascii",
+ "echo",
+ "E_COMPILE_ERROR",
+ "E_COMPILE_WARNING",
+ "E_CORE_ERROR",
+ "E_CORE_WARNING",
+ "E_ERROR",
+ "else",
+ "elseif",
+ "empty",
+ "end",
+ "endfor",
+ "endforeach",
+ "endif",
+ "endswitch",
+ "endwhile",
+ "E_NOTICE",
+ "entities",
+ "_ENV",
+ "E_PARSE",
+ "ereg",
+ "eregi",
+ "eregi_replace",
+ "ereg_replace",
+ "error_log",
+ "error_reporting",
+ "escapeshellarg",
+ "escapeshellcmd",
+ "E_USER_ERROR",
+ "E_USER_NOTICE",
+ "E_USER_WARNING",
+ "eval",
+ "E_WARNING",
+ "exec",
+ "exif_imagetype",
+ "exif_read_data",
+ "exif_thumbnail",
+ "exit",
+ "exp",
+ "explode",
+ "expm1",
+ "extension_loaded",
+ "extract",
+ "ezmlm_hash",
+ "FALSE",
+ "fbsql_affected_rows",
+ "fbsql_autocommit",
+ "fbsql_change_user",
+ "fbsql_close",
+ "fbsql_commit",
+ "fbsql_connect",
+ "fbsql_create_blob",
+ "fbsql_create_clob",
+ "fbsql_create_db",
+ "fbsql_database",
+ "fbsql_database_password",
+ "fbsql_data_seek",
+ "fbsql_db_query",
+ "fbsql_db_status",
+ "fbsql_drop_db",
+ "fbsql_errno",
+ "fbsql_error",
+ "fbsql_fetch_array",
+ "fbsql_fetch_assoc",
+ "fbsql_fetch_field",
+ "fbsql_fetch_lengths",
+ "fbsql_fetch_object",
+ "fbsql_fetch_row",
+ "fbsql_field_flags",
+ "fbsql_field_len",
+ "fbsql_field_name",
+ "fbsql_field_seek",
+ "fbsql_field_table",
+ "fbsql_field_type",
+ "fbsql_free_result",
+ "fbsql_get_autostart_info",
+ "fbsql_hostname",
+ "fbsql_insert_id",
+ "fbsql_list_dbs",
+ "fbsql_list_fields",
+ "fbsql_list_tables",
+ "fbsql_next_result",
+ "fbsql_num_fields",
+ "fbsql_num_rows",
+ "fbsql_password",
+ "fbsql_pconnect",
+ "fbsql_query",
+ "fbsql_read_blob",
+ "fbsql_read_clob",
+ "fbsql_result",
+ "fbsql_rollback",
+ "fbsql_select_db",
+ "fbsql_set_lob_mode",
+ "fbsql_set_transaction",
+ "fbsql_start_db",
+ "fbsql_stop_db",
+ "fbsql_tablename",
+ "fbsql_username",
+ "fbsql_warnings",
+ "fclose",
+ "fdf_add_doc_javascript",
+ "fdf_add_template",
+ "fdf_close",
+ "fdf_create",
+ "fdf_errno",
+ "fdf_error",
+ "fdf_get_ap",
+ "fdf_get_attachment",
+ "fdf_get_encoding",
+ "fdf_get_file",
+ "fdf_get_status",
+ "fdf_get_value",
+ "fdf_get_version",
+ "fdf_header",
+ "fdf_next_field_name",
+ "fdf_open",
+ "fdf_open_string",
+ "fdf_save",
+ "fdf_save_string",
+ "fdf_set_ap",
+ "fdf_set_encoding",
+ "fdf_set_file",
+ "fdf_set_flags",
+ "fdf_set_javascript_action",
+ "fdf_set_opt",
+ "fdf_set_status",
+ "fdf_set_submit_form_action",
+ "fdf_set_target_frame",
+ "fdf_set_value",
+ "fdf_set_version",
+ "feof",
+ "fflush",
+ "fgetc",
+ "fgetcsv",
+ "fgets",
+ "fgetss",
+ "file",
+ "__FILE__",
+ "fileatime",
+ "filectime",
+ "file_exists",
+ "file_get_contents",
+ "filegroup",
+ "fileinode",
+ "filemtime",
+ "fileowner",
+ "fileperms",
+ "filepro",
+ "filepro_fieldcount",
+ "filepro_fieldname",
+ "filepro_fieldtype",
+ "filepro_fieldwidth",
+ "filepro_retrieve",
+ "filepro_rowcount",
+ "_FILES",
+ "filesize",
+ "filetype",
+ "find",
+ "first_child",
+ "floatval",
+ "flock",
+ "floor",
+ "flush",
+ "fmod",
+ "fnmatch",
+ "fopen",
+ "for",
+ "foreach",
+ "fpassthru",
+ "fprintf",
+ "fputs",
+ "fread",
+ "frenchtojd",
+ "fribidi_log2vis",
+ "fscanf",
+ "fseek",
+ "fsockopen",
+ "fstat",
+ "ftell",
+ "ftok",
+ "ftp_cdup",
+ "ftp_chdir",
+ "ftp_close",
+ "ftp_connect",
+ "ftp_delete",
+ "ftp_exec",
+ "ftp_fget",
+ "ftp_fput",
+ "ftp_get",
+ "ftp_get_option",
+ "ftp_login",
+ "ftp_mdtm",
+ "ftp_mkdir",
+ "ftp_nb_continue",
+ "ftp_nb_fget",
+ "ftp_nb_fput",
+ "ftp_nb_get",
+ "ftp_nb_put",
+ "ftp_nlist",
+ "ftp_pasv",
+ "ftp_put",
+ "ftp_pwd",
+ "ftp_quit",
+ "ftp_rawlist",
+ "ftp_rename",
+ "ftp_rmdir",
+ "ftp_set_option",
+ "ftp_site",
+ "ftp_size",
+ "ftp_ssl_connect",
+ "ftp_systype",
+ "ftruncate",
+ "ftstat",
+ "func_get_arg",
+ "func_get_args",
+ "func_num_args",
+ "function",
+ "function_exists",
+ "fwrite",
+ "GATEWAY_INTERFACE",
+ "gd_info",
+ "_GET",
+ "getallheaders",
+ "get_attribute",
+ "get_attribute_node",
+ "get_browser",
+ "get_cfg_var",
+ "get_class",
+ "get_class_methods",
+ "get_class_vars",
+ "get_content",
+ "get_current_user",
+ "getcwd",
+ "getdate",
+ "get_declared_classes",
+ "get_defined_constants",
+ "get_defined_functions",
+ "get_defined_vars",
+ "get_element_by_id",
+ "get_elements_by_tagname",
+ "getenv",
+ "get_extension_funcs",
+ "getHeight",
+ "gethostbyaddr",
+ "gethostbyname",
+ "gethostbynamel",
+ "get_html_translation_table",
+ "getimagesize",
+ "get_included_files",
+ "get_include_path",
+ "getlastmod",
+ "get_loaded_extensions",
+ "get_magic_quotes_gpc",
+ "get_magic_quotes_runtime",
+ "get_meta_tags",
+ "getmxrr",
+ "getmygid",
+ "getmyinode",
+ "getmypid",
+ "getmyuid",
+ "get_object_vars",
+ "getopt",
+ "get_parent_class",
+ "getprotobyname",
+ "getprotobynumber",
+ "getrandmax",
+ "get_required_files",
+ "get_resource_type",
+ "getrusage",
+ "getservbyname",
+ "getservbyport",
+ "getshape1",
+ "getshape2",
+ "gettext",
+ "gettimeofday",
+ "gettype",
+ "getwidth",
+ "getWidth",
+ "glob",
+ "global",
+ "GLOBALS",
+ "gmdate",
+ "gmmktime",
+ "gmp_abs",
+ "gmp_add",
+ "gmp_and",
+ "gmp_clrbit",
+ "gmp_cmp",
+ "gmp_com",
+ "gmp_div",
+ "gmp_divexact",
+ "gmp_div_q",
+ "gmp_div_qr",
+ "gmp_div_r",
+ "gmp_fact",
+ "gmp_gcd",
+ "gmp_gcdext",
+ "gmp_hamdist",
+ "gmp_init",
+ "gmp_intval",
+ "gmp_invert",
+ "gmp_jacobi",
+ "gmp_legendre",
+ "gmp_mod",
+ "gmp_mul",
+ "gmp_neg",
+ "gmp_or",
+ "gmp_perfect_square",
+ "gmp_popcount",
+ "gmp_pow",
+ "gmp_powm",
+ "gmp_prob_prime",
+ "gmp_random",
+ "gmp_scan0",
+ "gmp_scan1",
+ "gmp_setbit",
+ "gmp_sign",
+ "gmp_sqrt",
+ "gmp_sqrtrm",
+ "gmp_strval",
+ "gmp_sub",
+ "gmp_xor",
+ "gmstrftime",
+ "gregoriantojd",
+ "gzclose",
+ "gzcompress",
+ "gzdeflate",
+ "gzencode",
+ "gzeof",
+ "gzfile",
+ "gzgetc",
+ "gzgets",
+ "gzgetss",
+ "gzinflate",
+ "gzopen",
+ "gzpassthru",
+ "gzputs",
+ "gzread",
+ "gzrewind",
+ "gzseek",
+ "gztell",
+ "gzuncompress",
+ "gzwrite",
+ "has_attribute",
+ "has_attributess",
+ "has_child_nodes",
+ "header",
+ "headers_sent",
+ "hebrev",
+ "hebrevc",
+ "hexdec",
+ "highlight_file",
+ "highlight_string",
+ "html_dump_mem",
+ "htmlentities",
+ "html_entity_decode",
+ "htmlspecialchars",
+ "HTTP_ACCEPT",
+ "HTTP_ACCEPT_CHARSET",
+ "HTTP_ACCEPT_LANGUAGE",
+ "HTTP_CONNECTION",
+ "HTTP_COOKIE_VARS",
+ "HTTP_ENCODING",
+ "HTTP_ENV_VARS",
+ "HTTP_GET_VARS",
+ "HTTP_HOST",
+ "HTTP_POST_FILES",
+ "HTTP_POST_VARS",
+ "HTTP_RAW_POST_DATA",
+ "HTTP_REFERER",
+ "HTTP_SERVER_VARS",
+ "HTTP_SESSION_VARS",
+ "HTTP_STATE_VARS",
+ "HTTP_USER_AGENT",
+ "hw_api_attribute",
+ "hw_api_content",
+ "hwapi_hgcsp",
+ "hw_api_object",
+ "hw_Array2Objrec",
+ "hw_changeobject",
+ "hw_Children",
+ "hw_ChildrenObj",
+ "hw_Close",
+ "hw_Connect",
+ "hw_connection_info",
+ "hw_Cp",
+ "hw_Deleteobject",
+ "hw_DocByAnchor",
+ "hw_DocByAnchorObj",
+ "hw_Document_Attributes",
+ "hw_Document_BodyTag",
+ "hw_Document_Content",
+ "hw_Document_SetContent",
+ "hw_Document_Size",
+ "hw_dummy",
+ "hw_EditText",
+ "hw_Error",
+ "hw_ErrorMsg",
+ "hw_Free_Document",
+ "hw_GetAnchors",
+ "hw_GetAnchorsObj",
+ "hw_GetAndLock",
+ "hw_GetChildColl",
+ "hw_GetChildCollObj",
+ "hw_GetChildDocColl",
+ "hw_GetChildDocCollObj",
+ "hw_GetObject",
+ "hw_GetObjectByQuery",
+ "hw_GetObjectByQueryColl",
+ "hw_GetObjectByQueryCollObj",
+ "hw_GetObjectByQueryObj",
+ "hw_GetParents",
+ "hw_GetParentsObj",
+ "hw_getrellink",
+ "hw_GetRemote",
+ "hw_GetRemoteChildren",
+ "hw_GetSrcByDestObj",
+ "hw_GetText",
+ "hw_getusername",
+ "hw_Identify",
+ "hw_InCollections",
+ "hw_Info",
+ "hw_InsColl",
+ "hw_InsDoc",
+ "hw_insertanchors",
+ "hw_InsertDocument",
+ "hw_InsertObject",
+ "hw_mapid",
+ "hw_Modifyobject",
+ "hw_Mv",
+ "hw_New_Document",
+ "hw_Objrec2Array",
+ "hw_Output_Document",
+ "hw_pConnect",
+ "hw_PipeDocument",
+ "hw_Root",
+ "hw_setlinkroot",
+ "hw_stat",
+ "hwstat",
+ "hw_Unlock",
+ "hw_Who",
+ "hypot",
+ "ibase_blob_add",
+ "ibase_blob_cancel",
+ "ibase_blob_close",
+ "ibase_blob_create",
+ "ibase_blob_echo",
+ "ibase_blob_get",
+ "ibase_blob_import",
+ "ibase_blob_info",
+ "ibase_blob_open",
+ "ibase_close",
+ "ibase_commit",
+ "ibase_connect",
+ "ibase_errmsg",
+ "ibase_execute",
+ "ibase_fetch_object",
+ "ibase_fetch_row",
+ "ibase_field_info",
+ "ibase_free_query",
+ "ibase_free_result",
+ "ibase_num_fields",
+ "ibase_pconnect",
+ "ibase_prepare",
+ "ibase_query",
+ "ibase_rollback",
+ "ibase_timefmt",
+ "ibase_trans",
+ "iconv",
+ "iconv_get_encoding",
+ "iconv_set_encoding",
+ "identify",
+ "if",
+ "ifx_affected_rows",
+ "ifx_blobinfile_mode",
+ "ifx_byteasvarchar",
+ "ifx_close",
+ "ifx_connect",
+ "ifx_copy_blob",
+ "ifx_create_blob",
+ "ifx_create_char",
+ "ifx_do",
+ "ifx_error",
+ "ifx_errormsg",
+ "ifx_fetch_row",
+ "ifx_fieldproperties",
+ "ifx_fieldtypes",
+ "ifx_free_blob",
+ "ifx_free_char",
+ "ifx_free_result",
+ "ifx_get_blob",
+ "ifx_get_char",
+ "ifx_getsqlca",
+ "ifx_htmltbl_result",
+ "ifx_nullformat",
+ "ifx_num_fields",
+ "ifx_num_rows",
+ "ifx_pconnect",
+ "ifx_prepare",
+ "ifx_query",
+ "ifx_textasvarchar",
+ "ifx_update_blob",
+ "ifx_update_char",
+ "ifxus_close_slob",
+ "ifxus_create_slob",
+ "ifxus_free_slob",
+ "ifxus_open_slob",
+ "ifxus_read_slob",
+ "ifxus_seek_slob",
+ "ifxus_tell_slob",
+ "ifxus_write_slob",
+ "ignore_user_abort",
+ "image2wbmp",
+ "imagealphablending",
+ "imagearc",
+ "imagechar",
+ "imagecharup",
+ "imagecolorallocate",
+ "imagecolorallocatealpha",
+ "imagecolorat",
+ "imagecolorclosest",
+ "imagecolorclosestalpha",
+ "imagecolorclosesthwb",
+ "imagecolordeallocate",
+ "imagecolorexact",
+ "imagecolorexactalpha",
+ "imagecolorresolve",
+ "imagecolorresolvealpha",
+ "imagecolorset",
+ "imagecolorsforindex",
+ "imagecolorstotal",
+ "imagecolortransparent",
+ "imagecopy",
+ "imagecopymerge",
+ "imagecopymergegray",
+ "imagecopyresampled",
+ "imagecopyresized",
+ "imagecreate",
+ "imagecreatefromgd",
+ "imagecreatefromgd2",
+ "imagecreatefromgd2part",
+ "imagecreatefromgif",
+ "imagecreatefromjpeg",
+ "imagecreatefrompng",
+ "imagecreatefromstring",
+ "imagecreatefromwbmp",
+ "imagecreatefromxbm",
+ "imagecreatefromxpm",
+ "imagecreatetruecolor",
+ "imagedashedline",
+ "imagedestroy",
+ "imageellipse",
+ "imagefill",
+ "imagefilledarc",
+ "imagefilledellipse",
+ "imagefilledpolygon",
+ "imagefilledrectangle",
+ "imagefilltoborder",
+ "imagefontheight",
+ "imagefontwidth",
+ "imageftbbox",
+ "imagefttext",
+ "imagegammacorrect",
+ "imagegd",
+ "imagegd2",
+ "imagegif",
+ "imageinterlace",
+ "imagejpeg",
+ "imageline",
+ "imageloadfont",
+ "imagepalettecopy",
+ "imagepng",
+ "imagepolygon",
+ "imagepsbbox",
+ "imagepscopyfont",
+ "imagepsencodefont",
+ "imagepsextendfont",
+ "imagepsfreefont",
+ "imagepsloadfont",
+ "imagepsslantfont",
+ "imagepstext",
+ "imagerectangle",
+ "imagerotate",
+ "imagesetbrush",
+ "imagesetpixel",
+ "imagesetstyle",
+ "imagesetthickness",
+ "imagesettile",
+ "imagestring",
+ "imagestringup",
+ "imagesx",
+ "imagesy",
+ "imagetruecolortopalette",
+ "imagettfbbox",
+ "imagettftext",
+ "imagetypes",
+ "image_type_to_mime_type",
+ "imagewbmp",
+ "imap_8bit",
+ "imap_alerts",
+ "imap_append",
+ "imap_base64",
+ "imap_binary",
+ "imap_body",
+ "imap_bodystruct",
+ "imap_check",
+ "imap_clearflag_full",
+ "imap_close",
+ "imap_createmailbox",
+ "imap_delete",
+ "imap_deletemailbox",
+ "imap_errors",
+ "imap_expunge",
+ "imap_fetchbody",
+ "imap_fetchheader",
+ "imap_fetch_overview",
+ "imap_fetchstructure",
+ "imap_getmailboxes",
+ "imap_get_quota",
+ "imap_get_quotaroot",
+ "imap_getsubscribed",
+ "imap_header",
+ "imap_headerinfo",
+ "imap_headers",
+ "imap_last_error",
+ "imap_list",
+ "imap_listmailbox",
+ "imap_listscan",
+ "imap_listsubscribed",
+ "imap_lsub",
+ "imap_mail",
+ "imap_mailboxmsginfo",
+ "imap_mail_compose",
+ "imap_mail_copy",
+ "imap_mail_move",
+ "imap_mime_header_decode",
+ "imap_msgno",
+ "imap_num_msg",
+ "imap_num_recent",
+ "imap_open",
+ "imap_ping",
+ "imap_qprint",
+ "imap_renamemailbox",
+ "imap_reopen",
+ "imap_rfc822_parse_adrlist",
+ "imap_rfc822_parse_headers",
+ "imap_rfc822_write_address",
+ "imap_scanmailbox",
+ "imap_search",
+ "imap_setacl",
+ "imap_setflag_full",
+ "imap_set_quota",
+ "imap_sort",
+ "imap_status",
+ "imap_subscribe",
+ "imap_thread",
+ "imap_uid",
+ "imap_undelete",
+ "imap_unsubscribe",
+ "imap_utf7_decode",
+ "imap_utf7_encode",
+ "imap_utf8",
+ "implode",
+ "import_request_variables",
+ "in_array",
+ "include",
+ "include_once",
+ "info",
+ "ingres_autocommit",
+ "ingres_close",
+ "ingres_commit",
+ "ingres_connect",
+ "ingres_fetch_array",
+ "ingres_fetch_object",
+ "ingres_fetch_row",
+ "ingres_field_length",
+ "ingres_field_name",
+ "ingres_field_nullable",
+ "ingres_field_precision",
+ "ingres_field_scale",
+ "ingres_field_type",
+ "ingres_num_fields",
+ "ingres_num_rows",
+ "ingres_pconnect",
+ "ingres_query",
+ "ingres_rollback",
+ "ini_alter",
+ "ini_get",
+ "ini_get_all",
+ "ini_restore",
+ "ini_set",
+ "insert",
+ "insertanchor",
+ "insert_before",
+ "insertcollection",
+ "insertdocument",
+ "int",
+ "internal_subset",
+ "intval",
+ "ip2long",
+ "iptcembed",
+ "iptcparse",
+ "ircg_channel_mode",
+ "ircg_disconnect",
+ "ircg_fetch_error_msg",
+ "ircg_get_username",
+ "ircg_html_encode",
+ "ircg_ignore_add",
+ "ircg_ignore_del",
+ "ircg_is_conn_alive",
+ "ircg_join",
+ "ircg_kick",
+ "ircg_lookup_format_messages",
+ "ircg_msg",
+ "ircg_nick",
+ "ircg_nickname_escape",
+ "ircg_nickname_unescape",
+ "ircg_notice",
+ "ircg_part",
+ "ircg_pconnect",
+ "ircg_register_format_messages",
+ "ircg_set_current",
+ "ircg_set_file",
+ "ircg_set_on_die",
+ "ircg_topic",
+ "ircg_whois",
+ "is_a",
+ "is_array",
+ "is_blank_node",
+ "is_bool",
+ "is_callable",
+ "is_dir",
+ "is_double",
+ "is_executable",
+ "is_file",
+ "is_finite",
+ "is_float",
+ "is_infinite",
+ "is_int",
+ "is_integer",
+ "is_link",
+ "is_long",
+ "is_nan",
+ "is_null",
+ "is_numeric",
+ "is_object",
+ "is_readable",
+ "is_real",
+ "is_resource",
+ "is_scalar",
+ "isset",
+ "is_string",
+ "is_subclass_of",
+ "is_uploaded_file",
+ "is_writable",
+ "is_writeable",
+ "java_last_exception_clear",
+ "java_last_exception_get",
+ "jddayofweek",
+ "jdmonthname",
+ "jdtofrench",
+ "jdtogregorian",
+ "jdtojewish",
+ "jdtojulian",
+ "jdtounix",
+ "jewishtojd",
+ "join",
+ "jpeg2wbmp",
+ "juliantojd",
+ "key",
+ "krsort",
+ "ksort",
+ "langdepvalue",
+ "last_child",
+ "lcg_value",
+ "ldap_8859_to_t61",
+ "ldap_add",
+ "ldap_bind",
+ "ldap_close",
+ "ldap_compare",
+ "ldap_connect",
+ "ldap_count_entries",
+ "ldap_delete",
+ "ldap_dn2ufn",
+ "ldap_err2str",
+ "ldap_errno",
+ "ldap_error",
+ "ldap_explode_dn",
+ "ldap_first_attribute",
+ "ldap_first_entry",
+ "ldap_first_reference",
+ "ldap_free_result",
+ "ldap_get_attributes",
+ "ldap_get_dn",
+ "ldap_get_entries",
+ "ldap_get_option",
+ "ldap_get_values",
+ "ldap_get_values_len",
+ "ldap_list",
+ "ldap_mod_add",
+ "ldap_mod_del",
+ "ldap_modify",
+ "ldap_mod_replace",
+ "ldap_next_attribute",
+ "ldap_next_entry",
+ "ldap_next_reference",
+ "ldap_parse_reference",
+ "ldap_parse_result",
+ "ldap_read",
+ "ldap_rename",
+ "ldap_search",
+ "ldap_set_option",
+ "ldap_set_rebind_proc",
+ "ldap_sort",
+ "ldap_start_tls",
+ "ldap_t61_to_8859",
+ "ldap_unbind",
+ "levenshtein",
+ "__LINE__",
+ "link",
+ "linkinfo",
+ "list",
+ "localeconv",
+ "localtime",
+ "lock",
+ "log",
+ "log10",
+ "log1p",
+ "long2ip",
+ "lstat",
+ "ltrim",
+ "mail",
+ "mailparse_determine_best_xfer_encoding",
+ "mailparse_msg_create",
+ "mailparse_msg_extract_part",
+ "mailparse_msg_extract_part_file",
+ "mailparse_msg_free",
+ "mailparse_msg_get_part",
+ "mailparse_msg_get_part_data",
+ "mailparse_msg_get_structure",
+ "mailparse_msg_parse",
+ "mailparse_msg_parse_file",
+ "mailparse_rfc822_parse_addresses",
+ "mailparse_stream_encode",
+ "mailparse_uudecode_all",
+ "main",
+ "max",
+ "mb_convert_case",
+ "mb_convert_encoding",
+ "mb_convert_kana",
+ "mb_convert_variables",
+ "mb_decode_mimeheader",
+ "mb_decode_numericentity",
+ "mb_detect_encoding",
+ "mb_detect_order",
+ "mb_encode_mimeheader",
+ "mb_encode_numericentity",
+ "mb_ereg",
+ "mb_eregi",
+ "mb_eregi_replace",
+ "mb_ereg_match",
+ "mb_ereg_replace",
+ "mb_ereg_search",
+ "mb_ereg_search_getpos",
+ "mb_ereg_search_getregs",
+ "mb_ereg_search_init",
+ "mb_ereg_search_pos",
+ "mb_ereg_search_regs",
+ "mb_ereg_search_setpos",
+ "mb_get_info",
+ "mb_http_input",
+ "mb_http_output",
+ "mb_internal_encoding",
+ "mb_language",
+ "mb_output_handler",
+ "mb_parse_str",
+ "mb_preferred_mime_name",
+ "mb_regex_encoding",
+ "mb_regex_set_options",
+ "mb_send_mail",
+ "mb_split",
+ "mb_strcut",
+ "mb_strimwidth",
+ "mb_strlen",
+ "mb_strpos",
+ "mb_strrpos",
+ "mb_strtolower",
+ "mb_strtoupper",
+ "mb_strwidth",
+ "mb_substitute_character",
+ "mb_substr",
+ "mb_substr_count",
+ "mcal_append_event",
+ "mcal_close",
+ "mcal_create_calendar",
+ "mcal_date_compare",
+ "mcal_date_valid",
+ "mcal_day_of_week",
+ "mcal_day_of_year",
+ "mcal_days_in_month",
+ "mcal_delete_calendar",
+ "mcal_delete_event",
+ "mcal_event_add_attribute",
+ "mcal_event_init",
+ "mcal_event_set_alarm",
+ "mcal_event_set_category",
+ "mcal_event_set_class",
+ "mcal_event_set_description",
+ "mcal_event_set_end",
+ "mcal_event_set_recur_daily",
+ "mcal_event_set_recur_monthly_mday",
+ "mcal_event_set_recur_monthly_wday",
+ "mcal_event_set_recur_none",
+ "mcal_event_set_recur_weekly",
+ "mcal_event_set_recur_yearly",
+ "mcal_event_set_start",
+ "mcal_event_set_title",
+ "mcal_expunge",
+ "mcal_fetch_current_stream_event",
+ "mcal_fetch_event",
+ "mcal_is_leap_year",
+ "mcal_list_alarms",
+ "mcal_list_events",
+ "mcal_next_recurrence",
+ "mcal_open",
+ "mcal_popen",
+ "mcal_rename_calendar",
+ "mcal_reopen",
+ "mcal_snooze",
+ "mcal_store_event",
+ "mcal_time_valid",
+ "mcal_week_of_year",
+ "mcrypt_cbc",
+ "mcrypt_cfb",
+ "mcrypt_create_iv",
+ "mcrypt_decrypt",
+ "mcrypt_ecb",
+ "mcrypt_enc_get_algorithms_name",
+ "mcrypt_enc_get_block_size",
+ "mcrypt_enc_get_iv_size",
+ "mcrypt_enc_get_key_size",
+ "mcrypt_enc_get_modes_name",
+ "mcrypt_enc_get_supported_key_sizes",
+ "mcrypt_enc_is_block_algorithm",
+ "mcrypt_enc_is_block_algorithm_mode",
+ "mcrypt_enc_is_block_mode",
+ "mcrypt_encrypt",
+ "mcrypt_enc_self_test",
+ "mcrypt_generic",
+ "mcrypt_generic_deinit",
+ "mcrypt_generic_end",
+ "mcrypt_generic_init",
+ "mcrypt_get_block_size",
+ "mcrypt_get_cipher_name",
+ "mcrypt_get_iv_size",
+ "mcrypt_get_key_size",
+ "mcrypt_list_algorithms",
+ "mcrypt_list_modes",
+ "mcrypt_module_close",
+ "mcrypt_module_get_algo_block_size",
+ "mcrypt_module_get_algo_key_size",
+ "mcrypt_module_get_supported_key_sizes",
+ "mcrypt_module_is_block_algorithm",
+ "mcrypt_module_is_block_algorithm_mode",
+ "mcrypt_module_is_block_mode",
+ "mcrypt_module_open",
+ "mcrypt_module_self_test",
+ "mcrypt_ofb",
+ "mcve_adduser",
+ "mcve_adduserarg",
+ "mcve_bt",
+ "mcve_checkstatus",
+ "mcve_chkpwd",
+ "mcve_chngpwd",
+ "mcve_completeauthorizations",
+ "mcve_connect",
+ "mcve_connectionerror",
+ "mcve_deleteresponse",
+ "mcve_deletetrans",
+ "mcve_deleteusersetup",
+ "mcve_deluser",
+ "mcve_destroyconn",
+ "mcve_destroyengine",
+ "mcve_disableuser",
+ "mcve_edituser",
+ "mcve_enableuser",
+ "mcve_force",
+ "mcve_getcell",
+ "mcve_getcellbynum",
+ "mcve_getcommadelimited",
+ "mcve_getheader",
+ "mcve_getuserarg",
+ "mcve_getuserparam",
+ "mcve_gft",
+ "mcve_gl",
+ "mcve_gut",
+ "mcve_initconn",
+ "mcve_initengine",
+ "mcve_initusersetup",
+ "mcve_iscommadelimited",
+ "mcve_liststats",
+ "mcve_listusers",
+ "mcve_maxconntimeout",
+ "mcve_monitor",
+ "mcve_numcolumns",
+ "mcve_numrows",
+ "mcve_override",
+ "mcve_parsecommadelimited",
+ "mcve_ping",
+ "mcve_preauth",
+ "mcve_preauthcompletion",
+ "mcve_qc",
+ "mcve_responseparam",
+ "mcve_return",
+ "mcve_returncode",
+ "mcve_returnstatus",
+ "mcve_sale",
+ "mcve_setblocking",
+ "mcve_setdropfile",
+ "mcve_setip",
+ "mcve_setssl",
+ "mcve_settimeout",
+ "mcve_settle",
+ "mcve_text_avs",
+ "mcve_text_code",
+ "mcve_text_cv",
+ "mcve_transactionauth",
+ "mcve_transactionavs",
+ "mcve_transactionbatch",
+ "mcve_transactioncv",
+ "mcve_transactionid",
+ "mcve_transactionitem",
+ "mcve_transactionssent",
+ "mcve_transactiontext",
+ "mcve_transinqueue",
+ "mcve_transnew",
+ "mcve_transparam",
+ "mcve_transsend",
+ "mcve_ub",
+ "mcve_uwait",
+ "mcve_verifyconnection",
+ "mcve_verifysslcert",
+ "mcve_void",
+ "md5",
+ "md5_file",
+ "mdecrypt_generic",
+ "memory_get_usage",
+ "metaphone",
+ "method_exists",
+ "mhash",
+ "mhash_count",
+ "mhash_get_block_size",
+ "mhash_get_hash_name",
+ "mhash_keygen_s2k",
+ "microtime",
+ "mime_content_type",
+ "mimetype",
+ "min",
+ "ming_setcubicthreshold",
+ "ming_setscale",
+ "ming_useswfversion",
+ "mkdir",
+ "mktime",
+ "money_format",
+ "move",
+ "movePen",
+ "movePenTo",
+ "moveTo",
+ "move_uploaded_file",
+ "msession_connect",
+ "msession_count",
+ "msession_create",
+ "msession_destroy",
+ "msession_disconnect",
+ "msession_find",
+ "msession_get",
+ "msession_get_array",
+ "msession_getdata",
+ "msession_inc",
+ "msession_list",
+ "msession_listvar",
+ "msession_lock",
+ "msession_plugin",
+ "msession_randstr",
+ "msession_set",
+ "msession_set_array",
+ "msession_setdata",
+ "msession_timeout",
+ "msession_uniq",
+ "msession_unlock",
+ "msg_get_queue",
+ "msg_receive",
+ "msg_remove_queue",
+ "msg_send",
+ "msg_set_queue",
+ "msg_stat_queue",
+ "msql",
+ "msql_affected_rows",
+ "msql_close",
+ "msql_connect",
+ "msql_create_db",
+ "msql_createdb",
+ "msql_data_seek",
+ "msql_dbname",
+ "msql_drop_db",
+ "msql_dropdb",
+ "msql_error",
+ "msql_fetch_array",
+ "msql_fetch_field",
+ "msql_fetch_object",
+ "msql_fetch_row",
+ "msql_fieldflags",
+ "msql_fieldlen",
+ "msql_fieldname",
+ "msql_field_seek",
+ "msql_fieldtable",
+ "msql_fieldtype",
+ "msql_free_result",
+ "msql_freeresult",
+ "msql_list_dbs",
+ "msql_listdbs",
+ "msql_list_fields",
+ "msql_listfields",
+ "msql_list_tables",
+ "msql_listtables",
+ "msql_num_fields",
+ "msql_numfields",
+ "msql_num_rows",
+ "msql_numrows",
+ "msql_pconnect",
+ "msql_query",
+ "msql_regcase",
+ "msql_result",
+ "msql_select_db",
+ "msql_selectdb",
+ "msql_tablename",
+ "mssql_bind",
+ "mssql_close",
+ "mssql_connect",
+ "mssql_data_seek",
+ "mssql_execute",
+ "mssql_fetch_array",
+ "mssql_fetch_assoc",
+ "mssql_fetch_batch",
+ "mssql_fetch_field",
+ "mssql_fetch_object",
+ "mssql_fetch_row",
+ "mssql_field_length",
+ "mssql_field_name",
+ "mssql_field_seek",
+ "mssql_field_type",
+ "mssql_free_result",
+ "mssql_free_statement",
+ "mssql_get_last_message",
+ "mssql_guid_string",
+ "mssql_init",
+ "mssql_min_error_severity",
+ "mssql_min_message_severity",
+ "mssql_next_result",
+ "mssql_num_fields",
+ "mssql_num_rows",
+ "mssql_pconnect",
+ "mssql_query",
+ "mssql_result",
+ "mssql_rows_affected",
+ "mssql_select_db",
+ "mt_getrandmax",
+ "mt_rand",
+ "mt_srand",
+ "multColor",
+ "muscat_close",
+ "muscat_get",
+ "muscat_give",
+ "muscat_setup",
+ "muscat_setup_net",
+ "mysql_affected_rows",
+ "mysql_change_user",
+ "mysql_client_encoding",
+ "mysql_close",
+ "mysql_connect",
+ "mysql_create_db",
+ "mysql_data_seek",
+ "mysql_db_name",
+ "mysql_db_query",
+ "mysql_drop_db",
+ "mysql_errno",
+ "mysql_error",
+ "mysql_escape_string",
+ "mysql_fetch_array",
+ "mysql_fetch_assoc",
+ "mysql_fetch_field",
+ "mysql_fetch_lengths",
+ "mysql_fetch_object",
+ "mysql_fetch_row",
+ "mysql_field_flags",
+ "mysql_field_len",
+ "mysql_field_name",
+ "mysql_field_seek",
+ "mysql_field_table",
+ "mysql_field_type",
+ "mysql_free_result",
+ "mysql_get_client_info",
+ "mysql_get_host_info",
+ "mysql_get_proto_info",
+ "mysql_get_server_info",
+ "mysql_info",
+ "mysql_insert_id",
+ "mysql_list_dbs",
+ "mysql_list_fields",
+ "mysql_list_processes",
+ "mysql_list_tables",
+ "mysql_num_fields",
+ "mysql_num_rows",
+ "mysql_pconnect",
+ "mysql_ping",
+ "mysql_query",
+ "mysql_real_escape_string",
+ "mysql_result",
+ "mysql_select_db",
+ "mysql_stat",
+ "mysql_tablename",
+ "mysql_thread_id",
+ "mysql_unbuffered_query",
+ "name",
+ "natcasesort",
+ "natsort",
+ "ncurses_addch",
+ "ncurses_addchnstr",
+ "ncurses_addchstr",
+ "ncurses_addnstr",
+ "ncurses_addstr",
+ "ncurses_assume_default_colors",
+ "ncurses_attroff",
+ "ncurses_attron",
+ "ncurses_attrset",
+ "ncurses_baudrate",
+ "ncurses_beep",
+ "ncurses_bkgd",
+ "ncurses_bkgdset",
+ "ncurses_border",
+ "ncurses_can_change_color",
+ "ncurses_cbreak",
+ "ncurses_clear",
+ "ncurses_clrtobot",
+ "ncurses_clrtoeol",
+ "ncurses_color_set",
+ "ncurses_curs_set",
+ "ncurses_define_key",
+ "ncurses_def_prog_mode",
+ "ncurses_def_shell_mode",
+ "ncurses_delay_output",
+ "ncurses_delch",
+ "ncurses_deleteln",
+ "ncurses_delwin",
+ "ncurses_doupdate",
+ "ncurses_echo",
+ "ncurses_echochar",
+ "ncurses_end",
+ "ncurses_erase",
+ "ncurses_erasechar",
+ "ncurses_filter",
+ "ncurses_flash",
+ "ncurses_flushinp",
+ "ncurses_getch",
+ "ncurses_getmouse",
+ "ncurses_halfdelay",
+ "ncurses_has_colors",
+ "ncurses_has_ic",
+ "ncurses_has_il",
+ "ncurses_has_key",
+ "ncurses_hline",
+ "ncurses_inch",
+ "ncurses_init",
+ "ncurses_init_color",
+ "ncurses_init_pair",
+ "ncurses_insch",
+ "ncurses_insdelln",
+ "ncurses_insertln",
+ "ncurses_insstr",
+ "ncurses_instr",
+ "ncurses_isendwin",
+ "ncurses_keyok",
+ "ncurses_killchar",
+ "ncurses_longname",
+ "ncurses_mouseinterval",
+ "ncurses_mousemask",
+ "ncurses_move",
+ "ncurses_mvaddch",
+ "ncurses_mvaddchnstr",
+ "ncurses_mvaddchstr",
+ "ncurses_mvaddnstr",
+ "ncurses_mvaddstr",
+ "ncurses_mvcur",
+ "ncurses_mvdelch",
+ "ncurses_mvgetch",
+ "ncurses_mvhline",
+ "ncurses_mvinch",
+ "ncurses_mvvline",
+ "ncurses_mvwaddstr",
+ "ncurses_napms",
+ "ncurses_newwin",
+ "ncurses_nl",
+ "ncurses_nocbreak",
+ "ncurses_noecho",
+ "ncurses_nonl",
+ "ncurses_noqiflush",
+ "ncurses_noraw",
+ "ncurses_putp",
+ "ncurses_qiflush",
+ "ncurses_raw",
+ "ncurses_refresh",
+ "ncurses_resetty",
+ "ncurses_savetty",
+ "ncurses_scr_dump",
+ "ncurses_scr_init",
+ "ncurses_scrl",
+ "ncurses_scr_restore",
+ "ncurses_scr_set",
+ "ncurses_slk_attr",
+ "ncurses_slk_attroff",
+ "ncurses_slk_attron",
+ "ncurses_slk_attrset",
+ "ncurses_slk_clear",
+ "ncurses_slk_color",
+ "ncurses_slk_init",
+ "ncurses_slk_noutrefresh",
+ "ncurses_slk_refresh",
+ "ncurses_slk_restore",
+ "ncurses_slk_touch",
+ "ncurses_standend",
+ "ncurses_standout",
+ "ncurses_start_color",
+ "ncurses_termattrs",
+ "ncurses_termname",
+ "ncurses_timeout",
+ "ncurses_typeahead",
+ "ncurses_ungetch",
+ "ncurses_ungetmouse",
+ "ncurses_use_default_colors",
+ "ncurses_use_env",
+ "ncurses_use_extended_names",
+ "ncurses_vidattr",
+ "ncurses_vline",
+ "ncurses_wrefresh",
+ "new",
+ "next",
+ "nextframe",
+ "next_sibling",
+ "ngettext",
+ "nl2br",
+ "nl_langinfo",
+ "node_name",
+ "node_type",
+ "node_value",
+ "notations",
+ "notes_body",
+ "notes_copy_db",
+ "notes_create_db",
+ "notes_create_note",
+ "notes_drop_db",
+ "notes_find_note",
+ "notes_header_info",
+ "notes_list_msgs",
+ "notes_mark_read",
+ "notes_mark_unread",
+ "notes_nav_create",
+ "notes_search",
+ "notes_unread",
+ "notes_version",
+ "NULL",
+ "number_format",
+ "ob_clean",
+ "ob_end_clean",
+ "ob_end_flush",
+ "ob_flush",
+ "ob_get_contents",
+ "ob_get_length",
+ "ob_get_level",
+ "ob_get_status",
+ "ob_gzhandler",
+ "ob_iconv_handler",
+ "ob_implicit_flush",
+ "object",
+ "objectbyanchor",
+ "ob_start",
+ "ocibindbyname",
+ "ocicancel",
+ "OCICollAppend",
+ "ocicollassign",
+ "ocicollassignelem",
+ "ocicollgetelem",
+ "ocicollmax",
+ "ocicollsize",
+ "ocicolltrim",
+ "ocicolumnisnull",
+ "ocicolumnname",
+ "ocicolumnprecision",
+ "ocicolumnscale",
+ "ocicolumnsize",
+ "ocicolumntype",
+ "ocicolumntyperaw",
+ "ocicommit",
+ "ocidefinebyname",
+ "ocierror",
+ "ociexecute",
+ "ocifetch",
+ "ocifetchinto",
+ "ocifetchstatement",
+ "ocifreecollection",
+ "ocifreecursor",
+ "OCIFreeDesc",
+ "ocifreestatement",
+ "ociinternaldebug",
+ "ociloadlob",
+ "ocilogoff",
+ "ocilogon",
+ "ocinewcollection",
+ "ocinewcursor",
+ "ocinewdescriptor",
+ "ocinlogon",
+ "ocinumcols",
+ "ociparse",
+ "ociplogon",
+ "ociresult",
+ "ocirollback",
+ "ocirowcount",
+ "ocisavelob",
+ "ocisavelobfile",
+ "ociserverversion",
+ "ocisetprefetch",
+ "ocistatementtype",
+ "ociwritelobtofile",
+ "octdec",
+ "odbc_autocommit",
+ "odbc_binmode",
+ "odbc_close",
+ "odbc_close_all",
+ "odbc_columnprivileges",
+ "odbc_columns",
+ "odbc_commit",
+ "odbc_connect",
+ "odbc_cursor",
+ "odbc_data_source",
+ "odbc_do",
+ "odbc_error",
+ "odbc_errormsg",
+ "odbc_exec",
+ "odbc_execute",
+ "odbc_fetch_array",
+ "odbc_fetch_into",
+ "odbc_fetch_object",
+ "odbc_fetch_row",
+ "odbc_field_len",
+ "odbc_field_name",
+ "odbc_field_num",
+ "odbc_field_precision",
+ "odbc_field_scale",
+ "odbc_field_type",
+ "odbc_foreignkeys",
+ "odbc_free_result",
+ "odbc_gettypeinfo",
+ "odbc_longreadlen",
+ "odbc_next_result",
+ "odbc_num_fields",
+ "odbc_num_rows",
+ "odbc_pconnect",
+ "odbc_prepare",
+ "odbc_primarykeys",
+ "odbc_procedurecolumns",
+ "odbc_procedures",
+ "odbc_result",
+ "odbc_result_all",
+ "odbc_rollback",
+ "odbc_setoption",
+ "odbc_specialcolumns",
+ "odbc_statistics",
+ "odbc_tableprivileges",
+ "odbc_tables",
+ "opendir",
+ "openlog",
+ "openssl_csr_export",
+ "openssl_csr_export_to_file",
+ "openssl_csr_new",
+ "openssl_csr_sign",
+ "openssl_error_string",
+ "openssl_free_key",
+ "openssl_get_privatekey",
+ "openssl_get_publickey",
+ "openssl_open",
+ "openssl_pkcs7_decrypt",
+ "openssl_pkcs7_encrypt",
+ "openssl_pkcs7_sign",
+ "openssl_pkcs7_verify",
+ "openssl_pkey_export",
+ "openssl_pkey_export_to_file",
+ "openssl_pkey_get_private",
+ "openssl_pkey_get_public",
+ "openssl_pkey_new",
+ "openssl_private_decrypt",
+ "openssl_private_encrypt",
+ "openssl_public_decrypt",
+ "openssl_public_encrypt",
+ "openssl_seal",
+ "openssl_sign",
+ "openssl_verify",
+ "openssl_x509_check_private_key",
+ "openssl_x509_checkpurpose",
+ "openssl_x509_export",
+ "openssl_x509_export_to_file",
+ "openssl_x509_free",
+ "openssl_x509_parse",
+ "openssl_x509_read",
+ "ora_bind",
+ "ora_close",
+ "ora_columnname",
+ "ora_columnsize",
+ "ora_columntype",
+ "ora_commit",
+ "ora_commitoff",
+ "ora_commiton",
+ "ora_do",
+ "ora_error",
+ "ora_errorcode",
+ "ora_exec",
+ "ora_fetch",
+ "ora_fetch_into",
+ "ora_getcolumn",
+ "ora_logoff",
+ "ora_logon",
+ "ora_numcols",
+ "ora_numrows",
+ "ora_open",
+ "ora_parse",
+ "ora_plogon",
+ "ora_rollback",
+ "ord",
+ "output",
+ "overload",
+ "ovrimos_close",
+ "ovrimos_commit",
+ "ovrimos_connect",
+ "ovrimos_cursor",
+ "ovrimos_exec",
+ "ovrimos_execute",
+ "ovrimos_fetch_into",
+ "ovrimos_fetch_row",
+ "ovrimos_field_len",
+ "ovrimos_field_name",
+ "ovrimos_field_num",
+ "ovrimos_field_type",
+ "ovrimos_free_result",
+ "ovrimos_longreadlen",
+ "ovrimos_num_fields",
+ "ovrimos_num_rows",
+ "ovrimos_prepare",
+ "ovrimos_result",
+ "ovrimos_result_all",
+ "ovrimos_rollback",
+ "owner_document",
+ "pack",
+ "parent_node",
+ "parents",
+ "parse_ini_file",
+ "parse_str",
+ "parse_url",
+ "passthru",
+ "pathinfo",
+ "PATH_TRANSLATED",
+ "pclose",
+ "pcntl_exec",
+ "pcntl_fork",
+ "pcntl_signal",
+ "pcntl_waitpid",
+ "pcntl_wexitstatus",
+ "pcntl_wifexited",
+ "pcntl_wifsignaled",
+ "pcntl_wifstopped",
+ "pcntl_wstopsig",
+ "pcntl_wtermsig",
+ "pdf_add_annotation",
+ "pdf_add_bookmark",
+ "pdf_add_launchlink",
+ "pdf_add_locallink",
+ "pdf_add_note",
+ "pdf_add_outline",
+ "pdf_add_pdflink",
+ "pdf_add_thumbnail",
+ "pdf_add_weblink",
+ "pdf_arc",
+ "pdf_arcn",
+ "pdf_attach_file",
+ "pdf_begin_page",
+ "pdf_begin_pattern",
+ "pdf_begin_template",
+ "pdf_circle",
+ "pdf_clip",
+ "pdf_close",
+ "pdf_close_image",
+ "pdf_closepath",
+ "pdf_closepath_fill_stroke",
+ "pdf_closepath_stroke",
+ "pdf_close_pdi",
+ "pdf_close_pdi_page",
+ "pdf_concat",
+ "pdf_continue_text",
+ "pdf_curveto",
+ "pdf_delete",
+ "pdf_end_page",
+ "pdf_endpath",
+ "pdf_end_pattern",
+ "pdf_end_template",
+ "pdf_fill",
+ "pdf_fill_stroke",
+ "pdf_findfont",
+ "pdf_get_buffer",
+ "pdf_get_font",
+ "pdf_get_fontname",
+ "pdf_get_fontsize",
+ "pdf_get_image_height",
+ "pdf_get_image_width",
+ "pdf_get_majorversion",
+ "pdf_get_minorversion",
+ "pdf_get_parameter",
+ "pdf_get_pdi_parameter",
+ "pdf_get_pdi_value",
+ "pdf_get_value",
+ "pdf_initgraphics",
+ "pdf_lineto",
+ "pdf_makespotcolor",
+ "pdf_moveto",
+ "pdf_new",
+ "pdf_open",
+ "pdf_open_CCITT",
+ "pdf_open_file",
+ "pdf_open_gif",
+ "pdf_open_image",
+ "pdf_open_image_file",
+ "pdf_open_jpeg",
+ "pdf_open_memory_image",
+ "pdf_open_pdi",
+ "pdf_open_pdi_page",
+ "pdf_open_png",
+ "pdf_open_tiff",
+ "pdf_place_image",
+ "pdf_place_pdi_page",
+ "pdf_rect",
+ "pdf_restore",
+ "pdf_rotate",
+ "pdf_save",
+ "pdf_scale",
+ "pdf_set_border_color",
+ "pdf_set_border_dash",
+ "pdf_set_border_style",
+ "pdf_set_char_spacing",
+ "pdf_setcolor",
+ "pdf_setdash",
+ "pdf_set_duration",
+ "pdf_setflat",
+ "pdf_set_font",
+ "pdf_setfont",
+ "pdf_setgray",
+ "pdf_setgray_fill",
+ "pdf_setgray_stroke",
+ "pdf_set_horiz_scaling",
+ "pdf_set_info",
+ "pdf_set_info_author",
+ "pdf_set_info_creator",
+ "pdf_set_info_keywords",
+ "pdf_set_info_subject",
+ "pdf_set_info_title",
+ "pdf_set_leading",
+ "pdf_setlinecap",
+ "pdf_setlinejoin",
+ "pdf_setlinewidth",
+ "pdf_setmatrix",
+ "pdf_setmiterlimit",
+ "pdf_set_parameter",
+ "pdf_setpolydash",
+ "pdf_setrgbcolor",
+ "pdf_setrgbcolor_fill",
+ "pdf_setrgbcolor_stroke",
+ "pdf_set_text_matrix",
+ "pdf_set_text_pos",
+ "pdf_set_text_rendering",
+ "pdf_set_text_rise",
+ "pdf_set_value",
+ "pdf_set_word_spacing",
+ "pdf_show",
+ "pdf_show_boxed",
+ "pdf_show_xy",
+ "pdf_skew",
+ "pdf_stringwidth",
+ "pdf_stroke",
+ "pdf_translate",
+ "PEAR_EXTENSION_DIR",
+ "PEAR_INSTALL_DIR",
+ "pfpro_cleanup",
+ "pfpro_init",
+ "pfpro_process",
+ "pfpro_process_raw",
+ "pfpro_version",
+ "pfsockopen",
+ "pg_affected_rows",
+ "pg_cancel_query",
+ "pg_client_encoding",
+ "pg_close",
+ "pg_connect",
+ "pg_connection_busy",
+ "pg_connection_reset",
+ "pg_connection_status",
+ "pg_convert",
+ "pg_copy_from",
+ "pg_copy_to",
+ "pg_dbname",
+ "pg_delete",
+ "pg_end_copy",
+ "pg_escape_bytea",
+ "pg_escape_string",
+ "pg_fetch_all",
+ "pg_fetch_array",
+ "pg_fetch_assoc",
+ "pg_fetch_object",
+ "pg_fetch_result",
+ "pg_fetch_row",
+ "pg_field_is_null",
+ "pg_field_name",
+ "pg_field_num",
+ "pg_field_prtlen",
+ "pg_field_size",
+ "pg_field_type",
+ "pg_free_result",
+ "pg_get_notify",
+ "pg_get_pid",
+ "pg_get_result",
+ "pg_host",
+ "pg_insert",
+ "pg_last_error",
+ "pg_last_notice",
+ "pg_last_oid",
+ "pg_lo_close",
+ "pg_lo_create",
+ "pg_lo_export",
+ "pg_lo_import",
+ "pg_lo_open",
+ "pg_lo_read",
+ "pg_lo_read_all",
+ "pg_lo_seek",
+ "pg_lo_tell",
+ "pg_lo_unlink",
+ "pg_lo_write",
+ "pg_meta_data",
+ "pg_num_fields",
+ "pg_num_rows",
+ "pg_options",
+ "pg_pconnect",
+ "pg_ping",
+ "pg_port",
+ "pg_put_line",
+ "pg_query",
+ "pg_result_error",
+ "pg_result_seek",
+ "pg_result_status",
+ "pg_select",
+ "pg_send_query",
+ "pg_set_client_encoding",
+ "pg_trace",
+ "pg_tty",
+ "pg_unescape_bytea",
+ "pg_untrace",
+ "pg_update",
+ "PHP_BINDIR",
+ "PHP_CONFIG_FILE_PATH",
+ "phpcredits",
+ "PHP_DATADIR",
+ "PHP_ERRMSG",
+ "PHP_EXTENSION_DIR",
+ "phpinfo",
+ "php_ini_scanned_files",
+ "PHP_LIBDIR",
+ "PHP_LOCALSTATEDIR",
+ "php_logo_guid",
+ "PHP_OS",
+ "PHP_OUTPUT_HANDLER_CONT",
+ "PHP_OUTPUT_HANDLER_END",
+ "PHP_OUTPUT_HANDLER_START",
+ "php_sapi_name",
+ "PHP_SELF",
+ "PHP_SYSCONFDIR",
+ "php_uname",
+ "phpversion",
+ "PHP_VERSION",
+ "pi",
+ "png2wbmp",
+ "popen",
+ "pos",
+ "posix_ctermid",
+ "posix_getcwd",
+ "posix_getegid",
+ "posix_geteuid",
+ "posix_getgid",
+ "posix_getgrgid",
+ "posix_getgrnam",
+ "posix_getgroups",
+ "posix_getlogin",
+ "posix_getpgid",
+ "posix_getpgrp",
+ "posix_getpid",
+ "posix_getppid",
+ "posix_getpwnam",
+ "posix_getpwuid",
+ "posix_getrlimit",
+ "posix_getsid",
+ "posix_getuid",
+ "posix_isatty",
+ "posix_kill",
+ "posix_mkfifo",
+ "posix_setegid",
+ "posix_seteuid",
+ "posix_setgid",
+ "posix_setpgid",
+ "posix_setsid",
+ "posix_setuid",
+ "posix_times",
+ "posix_ttyname",
+ "posix_uname",
+ "_POST",
+ "pow",
+ "prefix",
+ "preg_grep",
+ "preg_match",
+ "preg_match_all",
+ "preg_quote",
+ "preg_replace",
+ "preg_replace_callback",
+ "preg_split",
+ "prev",
+ "previous_sibling",
+ "print",
+ "printer_abort",
+ "printer_close",
+ "printer_create_brush",
+ "printer_create_dc",
+ "printer_create_font",
+ "printer_create_pen",
+ "printer_delete_brush",
+ "printer_delete_dc",
+ "printer_delete_font",
+ "printer_delete_pen",
+ "printer_draw_bmp",
+ "printer_draw_chord",
+ "printer_draw_elipse",
+ "printer_draw_line",
+ "printer_draw_pie",
+ "printer_draw_rectangle",
+ "printer_draw_roundrect",
+ "printer_draw_text",
+ "printer_end_doc",
+ "printer_end_page",
+ "printer_get_option",
+ "printer_list",
+ "printer_logical_fontheight",
+ "printer_open",
+ "printer_select_brush",
+ "printer_select_font",
+ "printer_select_pen",
+ "printer_set_option",
+ "printer_start_doc",
+ "printer_start_page",
+ "printer_write",
+ "printf",
+ "print_r",
+ "private",
+ "proc_close",
+ "process",
+ "proc_open",
+ "protected",
+ "pspell_add_to_personal",
+ "pspell_add_to_session",
+ "pspell_check",
+ "pspell_clear_session",
+ "pspell_config_create",
+ "pspell_config_ignore",
+ "pspell_config_mode",
+ "pspell_config_personal",
+ "pspell_config_repl",
+ "pspell_config_runtogether",
+ "pspell_config_save_repl",
+ "pspell_new",
+ "pspell_new_config",
+ "pspell_new_personal",
+ "pspell_save_wordlist",
+ "pspell_store_replacement",
+ "pspell_suggest",
+ "public",
+ "public_id",
+ "putenv",
+ "qdom_error",
+ "qdom_tree",
+ "QUERY_STRING",
+ "quoted_printable_decode",
+ "quotemeta",
+ "rad2deg",
+ "rand",
+ "range",
+ "rawurldecode",
+ "rawurlencode",
+ "read",
+ "readdir",
+ "read_exif_data",
+ "readfile",
+ "readgzfile",
+ "readline",
+ "readline_add_history",
+ "readline_clear_history",
+ "readline_completion_function",
+ "readline_info",
+ "readline_list_history",
+ "readline_read_history",
+ "readline_write_history",
+ "readlink",
+ "realpath",
+ "reason",
+ "recode",
+ "recode_file",
+ "recode_string",
+ "register_shutdown_function",
+ "register_tick_function",
+ "REMOTE_ADDR",
+ "REMOTE_PORT",
+ "remove",
+ "remove_attribute",
+ "remove_child",
+ "rename",
+ "replace",
+ "replace_child",
+ "replace_node",
+ "_REQUEST",
+ "REQUEST_METHOD",
+ "REQUEST_URI",
+ "require",
+ "require_once",
+ "reset",
+ "restore_error_handler",
+ "restore_include_path",
+ "result_dump_file",
+ "result_dump_mem",
+ "return",
+ "rewind",
+ "rewinddir",
+ "rmdir",
+ "Rotate",
+ "rotateTo",
+ "round",
+ "rsort",
+ "rtrim",
+ "save",
+ "scale",
+ "scaleTo",
+ "SCRIPT_FILENAME",
+ "SCRIPT_NAME",
+ "sem_acquire",
+ "sem_get",
+ "sem_release",
+ "sem_remove",
+ "serialize",
+ "_SERVER",
+ "SERVER_ADMIN",
+ "SERVER_NAME",
+ "SERVER_PORT",
+ "SERVER_PROTOCOL",
+ "SERVER_SIGNATURE",
+ "SERVER_SOFTWARE",
+ "sesam_affected_rows",
+ "sesam_commit",
+ "sesam_connect",
+ "sesam_diagnostic",
+ "sesam_disconnect",
+ "sesam_errormsg",
+ "sesam_execimm",
+ "sesam_fetch_array",
+ "sesam_fetch_result",
+ "sesam_fetch_row",
+ "sesam_field_array",
+ "sesam_field_name",
+ "sesam_free_result",
+ "sesam_num_fields",
+ "sesam_query",
+ "sesam_rollback",
+ "sesam_seek_row",
+ "sesam_settransaction",
+ "_SESSION",
+ "session_cache_expire",
+ "session_cache_limiter",
+ "session_decode",
+ "session_destroy",
+ "session_encode",
+ "session_get_cookie_params",
+ "session_id",
+ "session_is_registered",
+ "session_module_name",
+ "session_name",
+ "session_readonly",
+ "session_register",
+ "session_save_path",
+ "session_set_cookie_params",
+ "session_set_save_handler",
+ "session_start",
+ "session_unregister",
+ "session_unset",
+ "session_write_close",
+ "setAction",
+ "set_attribute",
+ "setbackground",
+ "setbounds",
+ "setcolor",
+ "setColor",
+ "setcommitedversion",
+ "set_content",
+ "setcookie",
+ "setDepth",
+ "setdimension",
+ "setdown",
+ "set_error_handler",
+ "set_file_buffer",
+ "setFont",
+ "setframes",
+ "setHeight",
+ "setHit",
+ "set_include_path",
+ "setindentation",
+ "setLeftFill",
+ "setLeftMargin",
+ "setLine",
+ "setLineSpacing",
+ "setlocale",
+ "set_magic_quotes_runtime",
+ "setMargins",
+ "set_name",
+ "setname",
+ "setName",
+ "set_namespace",
+ "setOver",
+ "setrate",
+ "setRatio",
+ "setRightFill",
+ "setrightMargin",
+ "setSpacing",
+ "set_time_limit",
+ "settype",
+ "setUp",
+ "sha1",
+ "sha1_file",
+ "shell_exec",
+ "shm_attach",
+ "shm_detach",
+ "shm_get_var",
+ "shmop_close",
+ "shmop_delete",
+ "shmop_open",
+ "shmop_read",
+ "shmop_size",
+ "shmop_write",
+ "shm_put_var",
+ "shm_remove",
+ "shm_remove_var",
+ "show_source",
+ "shuffle",
+ "similar_text",
+ "sin",
+ "sinh",
+ "sizeof",
+ "skewX",
+ "skewXTo",
+ "skewY",
+ "skewYTo",
+ "sleep",
+ "snmpget",
+ "snmp_get_quick_print",
+ "snmprealwalk",
+ "snmpset",
+ "snmp_set_quick_print",
+ "snmpwalk",
+ "snmpwalkoid",
+ "socket_accept",
+ "socket_bind",
+ "socket_clear_error",
+ "socket_close",
+ "socket_connect",
+ "socket_create",
+ "socket_create_listen",
+ "socket_create_pair",
+ "socket_get_option",
+ "socket_getpeername",
+ "socket_getsockname",
+ "socket_get_status",
+ "socket_iovec_add",
+ "socket_iovec_alloc",
+ "socket_iovec_delete",
+ "socket_iovec_fetch",
+ "socket_iovec_free",
+ "socket_iovec_set",
+ "socket_last_error",
+ "socket_listen",
+ "socket_read",
+ "socket_readv",
+ "socket_recv",
+ "socket_recvfrom",
+ "socket_recvmsg",
+ "socket_select",
+ "socket_send",
+ "socket_sendmsg",
+ "socket_sendto",
+ "socket_set_blocking",
+ "socket_set_nonblock",
+ "socket_set_option",
+ "socket_set_timeout",
+ "socket_shutdown",
+ "socket_strerror",
+ "socket_write",
+ "socket_writev",
+ "sort",
+ "soundex",
+ "specified",
+ "split",
+ "spliti",
+ "sprintf",
+ "sql_regcase",
+ "sqrt",
+ "srand",
+ "srcanchors",
+ "srcsofdst",
+ "sscanf",
+ "stat",
+ "static",
+ "stdClass",
+ "strcasecmp",
+ "strchr",
+ "strcmp",
+ "strcoll",
+ "strcspn",
+ "stream_context_create",
+ "stream_context_get_options",
+ "stream_context_set_option",
+ "stream_context_set_params",
+ "stream_filter_append",
+ "stream_filter_prepend",
+ "stream_get_filters",
+ "stream_get_meta_data",
+ "stream_get_wrappers",
+ "streammp3",
+ "stream_register_filter",
+ "stream_register_wrapper",
+ "stream_select",
+ "stream_set_blocking",
+ "stream_set_timeout",
+ "stream_set_write_buffer",
+ "strftime",
+ "stripcslashes",
+ "stripslashes",
+ "strip_tags",
+ "stristr",
+ "strlen",
+ "strnatcasecmp",
+ "strnatcmp",
+ "strncasecmp",
+ "strncmp",
+ "str_pad",
+ "strpos",
+ "strrchr",
+ "str_repeat",
+ "str_replace",
+ "strrev",
+ "str_rot13",
+ "strrpos",
+ "str_shuffle",
+ "strspn",
+ "strstr",
+ "strtok",
+ "strtolower",
+ "strtotime",
+ "strtoupper",
+ "strtr",
+ "strval",
+ "str_word_count",
+ "substr",
+ "substr_count",
+ "substr_replace",
+ "SWFAction",
+ "swf_actiongeturl",
+ "swf_actiongotoframe",
+ "swf_actiongotolabel",
+ "swf_actionnextframe",
+ "swf_actionplay",
+ "swf_actionprevframe",
+ "swf_actionsettarget",
+ "swf_actionstop",
+ "swf_actiontogglequality",
+ "swf_actionwaitforframe",
+ "swf_addbuttonrecord",
+ "swf_addcolor",
+ "SWFBitmap",
+ "SWFbutton",
+ "swfbutton_keypress",
+ "swf_closefile",
+ "swf_definebitmap",
+ "swf_definefont",
+ "swf_defineline",
+ "swf_definepoly",
+ "swf_definerect",
+ "swf_definetext",
+ "SWFDisplayItem",
+ "swf_endbutton",
+ "swf_enddoaction",
+ "swf_endshape",
+ "swf_endsymbol",
+ "SWFFill",
+ "SWFFont",
+ "swf_fontsize",
+ "swf_fontslant",
+ "swf_fonttracking",
+ "swf_getbitmapinfo",
+ "swf_getfontinfo",
+ "swf_getframe",
+ "SWFGradient",
+ "swf_labelframe",
+ "swf_lookat",
+ "swf_modifyobject",
+ "SWFMorph",
+ "SWFMovie",
+ "swf_mulcolor",
+ "swf_nextid",
+ "swf_oncondition",
+ "swf_openfile",
+ "swf_ortho",
+ "swf_ortho2",
+ "swf_perspective",
+ "swf_placeobject",
+ "swf_polarview",
+ "swf_popmatrix",
+ "swf_posround",
+ "swf_pushmatrix",
+ "swf_removeobject",
+ "swf_rotate",
+ "swf_scale",
+ "swf_setfont",
+ "swf_setframe",
+ "SWFShape",
+ "swf_shapearc",
+ "swf_shapecurveto",
+ "swf_shapecurveto3",
+ "swf_shapefillbitmapclip",
+ "swf_shapefillbitmaptile",
+ "swf_shapefilloff",
+ "swf_shapefillsolid",
+ "swf_shapelinesolid",
+ "swf_shapelineto",
+ "swf_shapemoveto",
+ "swf_showframe",
+ "SWFSprite",
+ "swf_startbutton",
+ "swf_startdoaction",
+ "swf_startshape",
+ "swf_startsymbol",
+ "SWFText",
+ "SWFTextField",
+ "swf_textwidth",
+ "swf_translate",
+ "swf_viewport",
+ "switch",
+ "sybase_affected_rows",
+ "sybase_close",
+ "sybase_connect",
+ "sybase_data_seek",
+ "sybase_fetch_array",
+ "sybase_fetch_field",
+ "sybase_fetch_object",
+ "sybase_fetch_row",
+ "sybase_field_seek",
+ "sybase_free_result",
+ "sybase_get_last_message",
+ "sybase_min_client_severity",
+ "sybase_min_error_severity",
+ "sybase_min_message_severity",
+ "sybase_min_server_severity",
+ "sybase_num_fields",
+ "sybase_num_rows",
+ "sybase_pconnect",
+ "sybase_query",
+ "sybase_result",
+ "sybase_select_db",
+ "symlink",
+ "syslog",
+ "system",
+ "system_id",
+ "tagname",
+ "tan",
+ "tanh",
+ "target",
+ "tempnam",
+ "textdomain",
+ "time",
+ "title",
+ "tmpfile",
+ "token_get_all",
+ "token_name",
+ "touch",
+ "trigger_error",
+ "trim",
+ "TRUE",
+ "type",
+ "uasort",
+ "ucfirst",
+ "ucwords",
+ "udm_add_search_limit",
+ "udm_alloc_agent",
+ "udm_api_version",
+ "udm_cat_list",
+ "udm_cat_path",
+ "udm_check_charset",
+ "udm_check_stored",
+ "udm_clear_search_limits",
+ "udm_close_stored",
+ "udm_crc32",
+ "udm_errno",
+ "udm_error",
+ "udm_find",
+ "udm_free_agent",
+ "udm_free_ispell_data",
+ "udm_free_res",
+ "udm_get_doc_count",
+ "udm_get_res_field",
+ "udm_get_res_param",
+ "udm_load_ispell_data",
+ "udm_open_stored",
+ "udm_set_agent_param",
+ "uksort",
+ "umask",
+ "uniqid",
+ "unixtojd",
+ "unlink",
+ "unlink_node",
+ "unlock",
+ "unpack",
+ "unregister_tick_function",
+ "unserialize",
+ "unset",
+ "urldecode",
+ "urlencode",
+ "user",
+ "user_error",
+ "userlist",
+ "usleep",
+ "usort",
+ "utf8_decode",
+ "utf8_encode",
+ "value",
+ "values",
+ "var",
+ "var_dump",
+ "var_export",
+ "version_compare",
+ "virtual",
+ "vpopmail_add_alias_domain",
+ "vpopmail_add_alias_domain_ex",
+ "vpopmail_add_domain",
+ "vpopmail_add_domain_ex",
+ "vpopmail_add_user",
+ "vpopmail_alias_add",
+ "vpopmail_alias_del",
+ "vpopmail_alias_del_domain",
+ "vpopmail_alias_get",
+ "vpopmail_alias_get_all",
+ "vpopmail_auth_user",
+ "vpopmail_del_domain",
+ "vpopmail_del_domain_ex",
+ "vpopmail_del_user",
+ "vpopmail_error",
+ "vpopmail_passwd",
+ "vpopmail_set_user_quota",
+ "vprintf",
+ "vsprintf",
+ "w32api_deftype",
+ "w32api_init_dtype",
+ "w32api_invoke_function",
+ "w32api_register_function",
+ "w32api_set_call_method",
+ "wddx_add_vars",
+ "wddx_deserialize",
+ "wddx_packet_end",
+ "wddx_packet_start",
+ "wddx_serialize_value",
+ "wddx_serialize_vars",
+ "while",
+ "wordwrap",
+ "xinclude",
+ "xml_error_string",
+ "xml_get_current_byte_index",
+ "xml_get_current_column_number",
+ "xml_get_current_line_number",
+ "xml_get_error_code",
+ "xml_parse",
+ "xml_parse_into_struct",
+ "xml_parser_create",
+ "xml_parser_create_ns",
+ "xml_parser_free",
+ "xml_parser_get_option",
+ "xml_parser_set_option",
+ "xmlrpc_decode",
+ "xmlrpc_decode_request",
+ "xmlrpc_encode",
+ "xmlrpc_encode_request",
+ "xmlrpc_get_type",
+ "xmlrpc_parse_method_descriptions",
+ "xmlrpc_server_add_introspection_data",
+ "xmlrpc_server_call_method",
+ "xmlrpc_server_create",
+ "xmlrpc_server_destroy",
+ "xmlrpc_server_register_introspection_callback",
+ "xmlrpc_server_register_method",
+ "xmlrpc_set_type",
+ "xml_set_character_data_handler",
+ "xml_set_default_handler",
+ "xml_set_element_handler",
+ "xml_set_end_namespace_decl_handler",
+ "xml_set_external_entity_ref_handler",
+ "xml_set_notation_decl_handler",
+ "xml_set_object",
+ "xml_set_processing_instruction_handler",
+ "xml_set_start_namespace_decl_handler",
+ "xml_set_unparsed_entity_decl_handler",
+ "xpath_eval",
+ "xpath_eval_expression",
+ "xpath_new_context",
+ "xptr_eval",
+ "xptr_new_context",
+ "xslt_create",
+ "xslt_errno",
+ "xslt_error",
+ "xslt_free",
+ "xslt_output_process",
+ "xslt_set_base",
+ "xslt_set_encoding",
+ "xslt_set_error_handler",
+ "xslt_set_log",
+ "xslt_set_sax_handler",
+ "xslt_set_sax_handlers",
+ "xslt_set_scheme_handler",
+ "xslt_set_scheme_handlers",
+ "yaz_addinfo",
+ "yaz_ccl_conf",
+ "yaz_ccl_parse",
+ "yaz_close",
+ "yaz_connect",
+ "yaz_database",
+ "yaz_element",
+ "yaz_errno",
+ "yaz_error",
+ "yaz_get_option",
+ "yaz_hits",
+ "yaz_itemorder",
+ "yaz_present",
+ "yaz_range",
+ "yaz_record",
+ "yaz_scan",
+ "yaz_scan_result",
+ "yaz_schema",
+ "yaz_search",
+ "yaz_set_option",
+ "yaz_sort",
+ "yaz_syntax",
+ "yaz_wait",
+ "yp_all",
+ "yp_cat",
+ "yp_errno",
+ "yp_err_string",
+ "yp_first",
+ "yp_get_default_domain",
+ "yp_master",
+ "yp_match",
+ "yp_next",
+ "yp_order",
+ "zend_logo_guid",
+ "zend_version",
+ "zend_version",
+ "zip_close",
+ "zip_entry_close",
+ "zip_entry_compressedsize",
+ "zip_entry_compressionmethod",
+ "zip_entry_filesize",
+ "zip_entry_name",
+ "zip_entry_open",
+ "zip_entry_read",
+ "zip_open",
+ "zip_read",
+ 0
+ };
+
+PhpWriter::PhpWriter() {
+}
+
+PhpWriter::~PhpWriter() {}
+
+
+void PhpWriter::writeClass(UMLClassifier *c) {
+ if(!c) {
+ kDebug()<<"Cannot write class of NULL concept!" << endl;
+ return;
+ }
+
+ QString classname = cleanName(c->getName());
+ //find an appropriate name for our file
+ QString fileName = findFileName(c, ".php");
+ if (fileName.isEmpty()) {
+ emit codeGenerated(c, false);
+ return;
+ }
+
+ QFile filephp;
+ if(!openFile(filephp, fileName)) {
+ emit codeGenerated(c, false);
+ return;
+ }
+ QTextStream php(&filephp);
+
+ //////////////////////////////
+ //Start generating the code!!
+ /////////////////////////////
+
+
+ //try to find a heading file (license, coments, etc)
+ QString str;
+ str = getHeadingFile(".php");
+ if(!str.isEmpty()) {
+ str.replace(QRegExp("%filename%"),fileName);
+ str.replace(QRegExp("%filepath%"),filephp.name());
+ php<<str<<m_endl;
+ }
+
+
+ //write includes
+ UMLPackageList includes;
+ findObjectsRelated(c,includes);
+ UMLPackage *conc;
+ for(conc = includes.first(); conc ;conc = includes.next()) {
+ QString headerName = findFileName(conc, ".php");
+ if (headerName.isEmpty()) {
+ php << "include '" << headerName << "';" << m_endl;
+ }
+ }
+ php << m_endl;
+
+ //Write class Documentation if there is somthing or if force option
+ if(forceDoc() || !c->getDoc().isEmpty()) {
+ php << m_endl << "/**" << m_endl;
+ php << " * class " << classname << m_endl;
+ php << formatDoc(c->getDoc()," * ");
+ php << " */" << m_endl ;
+ }
+
+ UMLClassifierList superclasses = c->getSuperClasses();
+ UMLAssociationList aggregations = c->getAggregations();
+ UMLAssociationList compositions = c->getCompositions();
+ UMLAssociation *a;
+
+ //check if class is abstract and / or has abstract methods
+ //FG if(c->getAbstract() && !hasAbstractOps(c))
+ if(c->getAbstract())
+ php << "/******************************* Abstract Class ****************************" << m_endl << " "
+ << classname << " does not have any pure virtual methods, but its author" << m_endl
+ << " defined it as an abstract class, so you should not use it directly." << m_endl
+ << " Inherit from it instead and create only objects from the derived classes" << m_endl
+ << "*****************************************************************************/" << m_endl << m_endl;
+
+ php << "class " << classname << (superclasses.count() > 0 ? " extends ":"");
+ for (UMLClassifier *obj = superclasses.first();
+ obj; obj = superclasses.next()) {
+ php<<cleanName(obj->getName());
+ }
+ php<< m_endl << "{" << m_endl;
+
+ //associations
+ if( forceSections() || !aggregations.isEmpty()) {
+ php<< m_endl << m_indentation << "/** Aggregations: */" << m_endl;
+ for (a = aggregations.first(); a; a = aggregations.next()) {
+ php<< m_endl;
+ //maybe we should parse the string here and take multiplicity into account to decide
+ //which container to use.
+ UMLObject *o = a->getObject(Uml::A);
+ QString typeName = cleanName(o->getName());
+ if (a->getMulti(Uml::A).isEmpty()) {
+ php << m_indentation << "var $m_" << ";" << m_endl;
+ } else {
+ php << m_indentation << "var $m_" << "Vector = array();" << m_endl;
+ }
+ }//end for
+ }
+
+ if( forceSections() || !compositions.isEmpty()) {
+ php<< m_endl << m_indentation << "/** Compositions: */" << m_endl;
+ for (a = compositions.first(); a ; a = compositions.next()) {
+ // see comment on Aggregation about multiplicity...
+ UMLObject *o = a->getObject(Uml::A);
+ QString typeName = cleanName(o->getName());
+ if (a->getMulti(Uml::A).isEmpty()) {
+ php << m_indentation << "var $m_" << ";" << m_endl;
+ } else {
+ php << m_indentation << "var $m_" << "Vector = array();" << m_endl;
+ }
+ }
+ }
+
+ const bool isClass = !c->isInterface();
+
+ //attributes
+ if (isClass)
+ writeAttributes(c, php);
+
+ //operations
+ writeOperations(c,php);
+
+ if (isClass && hasDefaultValueAttr(c)) {
+ UMLAttributeList atl = c->getAttributeList();
+ php << m_endl;
+
+ php << m_indentation << "/**" << m_endl;
+ QString temp = "initAttributes sets all " + classname + " attributes to its default value."
+ " Make sure to call this method within your class constructor";
+ php << formatDoc(temp,m_indentation + " * ");
+ php << m_indentation << " */" << m_endl;
+ php << m_indentation << "function "<<"initAttributes( )" << m_endl;
+ php << m_indentation << "{" << m_endl;
+ for(UMLAttribute* at = atl.first(); at; at = atl.next()) {
+ if(!at->getInitialValue().isEmpty()) {
+ php << m_indentation << m_indentation << "$this->" << cleanName(at->getName()) << " = " <<
+ at->getInitialValue() << ";" << m_endl;
+ }
+ }
+ php << m_indentation << "}" << m_endl;
+ }
+
+ php << m_endl;
+
+ //finish file
+ php << m_endl << "} // end of " << classname << m_endl;
+ php << "?>" << m_endl;
+
+ //close files and notfiy we are done
+ filephp.close();
+ emit codeGenerated(c, true);
+}
+
+////////////////////////////////////////////////////////////////////////////////////
+// Helper Methods
+
+void PhpWriter::writeOperations(UMLClassifier *c, QTextStream &php) {
+
+ //Lists to store operations sorted by scope
+ UMLOperationList oppub,opprot,oppriv;
+
+ oppub.setAutoDelete(false);
+ opprot.setAutoDelete(false);
+ oppriv.setAutoDelete(false);
+
+ //sort operations by scope first and see if there are abstract methods
+ UMLOperationList opl(c->getOpList());
+ for(UMLOperation *op = opl.first(); op ; op = opl.next()) {
+ switch(op->getVisibility()) {
+ case Uml::Visibility::Public:
+ oppub.append(op);
+ break;
+ case Uml::Visibility::Protected:
+ opprot.append(op);
+ break;
+ case Uml::Visibility::Private:
+ oppriv.append(op);
+ break;
+ default:
+ break;
+ }
+ }
+
+ QString classname(cleanName(c->getName()));
+
+ //write operations to file
+ if(forceSections() || !oppub.isEmpty()) {
+ php << m_endl;
+ writeOperations(classname,oppub,php);
+ }
+
+ if(forceSections() || !opprot.isEmpty()) {
+ php << m_endl;
+ writeOperations(classname,opprot,php);
+ }
+
+ if(forceSections() || !oppriv.isEmpty()) {
+ php << m_endl;
+ writeOperations(classname,oppriv,php);
+ }
+}
+
+void PhpWriter::writeOperations(QString /* classname */, UMLOperationList &opList, QTextStream &php) {
+ UMLOperation *op;
+ UMLAttribute *at;
+
+ for(op=opList.first(); op ; op=opList.next()) {
+ UMLAttributeList atl = op->getParmList();
+ //write method doc if we have doc || if at least one of the params has doc
+ bool writeDoc = forceDoc() || !op->getDoc().isEmpty();
+ for (at = atl.first(); at; at = atl.next())
+ writeDoc |= !at->getDoc().isEmpty();
+
+ if( writeDoc ) //write method documentation
+ {
+ php <<m_indentation << "/**" << m_endl <<formatDoc(op->getDoc(),m_indentation + " * ");
+ php << m_indentation << " *" << m_endl;
+
+ for (at = atl.first(); at; at = atl.next()) //write parameter documentation
+ {
+ if(forceDoc() || !at->getDoc().isEmpty()) {
+ php <<m_indentation << " * @param " + at->getTypeName() + " " + cleanName(at->getName());
+ php << " " + formatDoc(at->getDoc(),"");
+ }
+ }//end for : write parameter documentation
+ php << m_indentation << " * @return " << op->getTypeName() << m_endl;
+ if (op->getAbstract()) php << m_indentation << " * @abstract" << m_endl;
+ if (op->getStatic()) php << m_indentation << " * @static" << m_endl;
+ switch(op->getVisibility()) {
+ case Uml::Visibility::Public:
+ php << m_indentation << " * @access public" << m_endl;
+ break;
+ case Uml::Visibility::Protected:
+ php << m_indentation << " * @access protected" << m_endl;
+ break;
+ case Uml::Visibility::Private:
+ php << m_indentation << " * @access private" << m_endl;
+ break;
+ default:
+ break;
+ }
+ php <<m_indentation << " */" << m_endl;
+ }//end if : write method documentation
+
+ php << m_indentation << "function " << cleanName(op->getName()) << "(";
+
+ int i= atl.count();
+ int j=0;
+ for (at = atl.first(); at; at = atl.next(), j++) {
+ php << " $" << cleanName(at->getName())
+ << (!(at->getInitialValue().isEmpty()) ?
+ (QString(" = ")+at->getInitialValue()) :
+ QString(""))
+ << ((j < i-1)?", ":"");
+ }
+ php <<" )" << m_endl << m_indentation << "{" << m_endl << m_indentation << m_indentation << m_endl << m_indentation << "} // end of member function " + cleanName(op->getName()) + m_endl;
+ php << m_endl;
+ }//end for
+}
+
+void PhpWriter::writeAttributes(UMLClassifier *c, QTextStream &php) {
+ UMLAttributeList atpub, atprot, atpriv, atdefval;
+ atpub.setAutoDelete(false);
+ atprot.setAutoDelete(false);
+ atpriv.setAutoDelete(false);
+ atdefval.setAutoDelete(false);
+
+ //sort attributes by scope and see if they have a default value
+ UMLAttributeList atl = c->getAttributeList();
+ UMLAttribute *at;
+ for(at = atl.first(); at ; at = atl.next()) {
+ if(!at->getInitialValue().isEmpty())
+ atdefval.append(at);
+ switch(at->getVisibility()) {
+ case Uml::Visibility::Public:
+ atpub.append(at);
+ break;
+ case Uml::Visibility::Protected:
+ atprot.append(at);
+ break;
+ case Uml::Visibility::Private:
+ atpriv.append(at);
+ break;
+ default:
+ break;
+ }
+ }
+
+ if(forceSections() || atl.count())
+ php<< m_endl << m_indentation << " /*** Attributes: ***/" << m_endl <<m_endl;
+
+ if(forceSections() || atpub.count()) {
+ writeAttributes(atpub,php);
+ }
+
+ if(forceSections() || atprot.count()) {
+ writeAttributes(atprot,php);
+ }
+
+ if(forceSections() || atpriv.count()) {
+ writeAttributes(atpriv,php);
+ }
+}
+
+
+void PhpWriter::writeAttributes(UMLAttributeList &atList, QTextStream &php) {
+ for (UMLAttribute *at = atList.first(); at ; at = atList.next()) {
+ if (forceDoc() || !at->getDoc().isEmpty()) {
+ php << m_indentation << "/**" << m_endl << formatDoc(at->getDoc(), m_indentation + " * ");
+ switch(at->getVisibility()) {
+ case Uml::Visibility::Public:
+ php << m_indentation << " * @access public" << m_endl;
+ break;
+ case Uml::Visibility::Protected:
+ php << m_indentation << " * @access protected" << m_endl;
+ break;
+ case Uml::Visibility::Private:
+ php << m_indentation << " * @access private" << m_endl;
+ break;
+ default:
+ break;
+ }
+
+ php << m_indentation << " */" << m_endl;
+ }
+ php << m_indentation << "var " << "$" << cleanName(at->getName()) << ";" << m_endl;
+
+ } // end for
+ return;
+}
+
+/**
+ * returns "PHP"
+ */
+Uml::Programming_Language PhpWriter::getLanguage() {
+ return Uml::pl_PHP;
+}
+
+const QStringList PhpWriter::reservedKeywords() const {
+
+ static QStringList keywords;
+
+ if (keywords.isEmpty()) {
+ for (int i = 0; words[i]; i++)
+ keywords.append(words[i]);
+ }
+
+ return keywords;
+}
+
+#include "phpwriter.moc"
+
diff --git a/umbrello/umbrello/codegenerators/phpwriter.h b/umbrello/umbrello/codegenerators/phpwriter.h
new file mode 100644
index 00000000..a3acb68b
--- /dev/null
+++ b/umbrello/umbrello/codegenerators/phpwriter.h
@@ -0,0 +1,90 @@
+/***************************************************************************
+ phpwriter.h - description
+ -------------------
+ begin : Thu Oct 17 2002
+ copyright : (C) 2002 by Heiko Nardmann
+ email : h.nardmann@secunet.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 PHPWRITER_H
+#define PHPWRITER_H
+
+#include "simplecodegenerator.h"
+#include "../umlattributelist.h"
+#include "../umloperationlist.h"
+
+/**
+ * class PhpWriter is a PHP code generator for UMLClassifier objects
+ * Just call writeClass and feed it a UMLClassifier;
+ */
+class PhpWriter : public SimpleCodeGenerator {
+ Q_OBJECT
+public:
+
+ PhpWriter();
+ virtual ~PhpWriter();
+
+ /**
+ * call this method to generate Php code for a UMLClassifier
+ * @param c the class you want to generate code for.
+ */
+ virtual void writeClass(UMLClassifier *c);
+
+ /**
+ * returns "PHP"
+ */
+ virtual Uml::Programming_Language getLanguage();
+
+ /**
+ * get list of reserved keywords
+ */
+ virtual const QStringList reservedKeywords() const;
+
+private:
+
+ /**
+ * we do not want to write the comment "Private methods" twice
+ */
+ bool bPrivateSectionCommentIsWritten;
+
+ /**
+ * write all operations for a given class
+ *
+ * @param c the concept we are generating code for
+ * @param php output stream for the PHP file
+ */
+ void writeOperations(UMLClassifier *c, QTextStream &php);
+
+ /**
+ * write a list of class operations
+ *
+ * @param classname the name of the class
+ * @param opList the list of operations
+ * @param php output stream for the PHP file
+ */
+ void writeOperations(QString classname, UMLOperationList &opList,
+ QTextStream &php);
+
+ /** write all the attributes of a class
+ * @param c the class we are generating code for
+ * @param php output stream for the PHP file
+ */
+ void writeAttributes(UMLClassifier *c, QTextStream &php);
+
+ /** write a list of class attributes
+ * @param atList the list of attributes
+ * @param php output stream for the PHP file
+ */
+ void writeAttributes(UMLAttributeList &atList, QTextStream &php);
+};
+
+#endif //PHPWRITER
diff --git a/umbrello/umbrello/codegenerators/pythonwriter.cpp b/umbrello/umbrello/codegenerators/pythonwriter.cpp
new file mode 100644
index 00000000..a5ac2b28
--- /dev/null
+++ b/umbrello/umbrello/codegenerators/pythonwriter.cpp
@@ -0,0 +1,438 @@
+/***************************************************************************
+ pythonwriter.h - description
+ -------------------
+ begin : Sat Dec 21 2002
+ copyright : Vincent Decorges
+ email : vincent.decorges@eivd.ch
+ (C) 2003-2006 Umbrello UML Modeller Authors <uml-devel@uml.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. *
+ * *
+ ***************************************************************************/
+
+#include "pythonwriter.h"
+
+#include <kdebug.h>
+#include <klocale.h>
+#include <kmessagebox.h>
+#include <qfile.h>
+#include <qtextstream.h>
+#include <qregexp.h>
+
+#include "../umldoc.h"
+#include "../umlattributelist.h"
+#include "../association.h"
+#include "../attribute.h"
+#include "../classifier.h"
+#include "../attribute.h"
+#include "../operation.h"
+#include "../umlnamespace.h"
+
+PythonWriter::PythonWriter() : m_bNeedPass(true) {
+}
+
+PythonWriter::~PythonWriter() {}
+
+void PythonWriter::writeClass(UMLClassifier *c) {
+ if(!c) {
+ kDebug()<<"Cannot write class of NULL concept!" << endl;
+ return;
+ }
+
+ QString classname = cleanName(c->getName());
+
+ UMLClassifierList superclasses = c->getSuperClasses();
+ UMLAssociationList aggregations = c->getAggregations();
+ UMLAssociationList compositions = c->getCompositions();
+
+ m_bNeedPass = true;
+
+ //find an appropriate name for our file
+ QString fileName = findFileName(c, ".py");
+ if (fileName.isEmpty()) {
+ emit codeGenerated(c, false);
+ return;
+ }
+
+ QChar first = fileName.at(0);
+ //Replace the first letter of the filename because
+ //python class begin with an upper caracter (convention)
+ first = first.upper();
+ fileName = fileName.replace(0, 1, first);
+
+ QFile fileh;
+ if( !openFile(fileh, fileName) ) {
+ emit codeGenerated(c, false);
+ return;
+ }
+ QTextStream h(&fileh);
+
+ //////////////////////////////
+ //Start generating the code!!
+ /////////////////////////////
+
+
+ //try to find a heading file (license, coments, etc)
+ QString str;
+
+ str = getHeadingFile(".py");
+ if(!str.isEmpty()) {
+ str.replace(QRegExp("%filename%"), fileName);
+ str.replace(QRegExp("%filepath%"), fileh.name());
+ h<<str<<m_endl;
+ }
+
+ // generate import statement for superclasses and take packages into account
+ str = cleanName(c->getName());
+ QString pkg = cleanName(c->getPackage());
+ if (!pkg.isEmpty())
+ str.prepend(pkg + '.');
+ QStringList includesList = QStringList(str); //save imported classes
+ int i = superclasses.count();
+ for (UMLClassifier *classifier = superclasses.first();
+ classifier && i; classifier = superclasses.next(), i--) {
+ str = cleanName(classifier->getName());
+ pkg = cleanName(classifier->getPackage());
+ if (!pkg.isEmpty())
+ str.prepend(pkg + '.');
+ includesList.append(str);
+ h << "from " + str + " import *" << m_endl;
+ }
+
+ //write includes and take namespaces into account
+ UMLPackageList includes;
+ findObjectsRelated(c,includes);
+ UMLPackage* conc;
+ for(conc = includes.first(); conc ;conc = includes.next()) {
+ QString headerName = findFileName(conc, ".py");
+ if ( !headerName.isEmpty() ) {
+ headerName.remove(QRegExp(".py$"));
+ first = headerName.at(0);
+ first = first.upper();
+ headerName = headerName.replace(0, 1, first);
+ str = headerName.replace(QChar('/'),QChar('.'));
+ if (includesList.findIndex(str) < 0) // not yet imported
+ h << "from " << str << " import *" << m_endl;
+ }
+ }
+ h<<m_endl;
+
+ h << "class " << classname << (superclasses.count() > 0 ? " (" : "(object)");
+ i = superclasses.count();
+
+ for (UMLClassifier *obj = superclasses.first();
+ obj && i; obj = superclasses.next(), i--) {
+
+ h<<cleanName(obj->getName())<<(i>1?", ":"");
+ }
+
+
+ h<<(superclasses.count() > 0 ? ")":"")<<":"<<m_endl<<m_endl;
+
+ if (forceDoc() || !c->getDoc().isEmpty()) {
+ h << m_indentation << "\"\"\"" << m_endl;
+ h << formatDoc(c->getDoc(), m_indentation + ' ') << m_endl;
+ h << m_indentation << ":version:" << m_endl;
+ h << m_indentation << ":author:" << m_endl;
+ h << m_indentation << "\"\"\"" << m_endl << m_endl;
+ m_bNeedPass = false;
+ }
+
+ // attributes
+ writeAttributes(c->getAttributeList(), h);
+
+ //operations
+ writeOperations(c,h);
+
+ if (m_bNeedPass)
+ h << m_indentation << "pass" << m_endl;
+
+ //finish files
+ h<<m_endl<<m_endl;
+
+ //close files and notfiy we are done
+ fileh.close();
+ emit codeGenerated(c, true);
+}
+
+
+////////////////////////////////////////////////////////////////////////////////////
+// Helper Methods
+
+void PythonWriter::writeAttributes(UMLAttributeList atList, QTextStream &py) {
+ if (!forceDoc() || atList.count() == 0)
+ return;
+ py << m_indentation << "\"\"\" ATTRIBUTES" << m_endl << m_endl;
+ for (UMLAttribute *at = atList.first(); at; at = atList.next()) {
+ py << formatDoc(at->getDoc(), m_indentation + ' ') << m_endl;
+ Uml::Visibility vis = at->getVisibility();
+ py << m_indentation << cleanName(at->getName()) << " ("
+ << vis.toString() << ")" << m_endl << m_endl ;
+ } // end for
+ py << m_indentation << "\"\"\"" << m_endl << m_endl;
+}
+
+void PythonWriter::writeOperations(UMLClassifier *c, QTextStream &h) {
+
+ //Lists to store operations sorted by scope
+ UMLOperationList oppub,opprot,oppriv;
+
+ oppub.setAutoDelete(false);
+ opprot.setAutoDelete(false);
+ oppriv.setAutoDelete(false);
+
+ //sort operations by scope first and see if there are abstract methods
+ UMLOperationList opl(c->getOpList());
+ for(UMLOperation *op = opl.first(); op ; op = opl.next()) {
+ switch(op->getVisibility()) {
+ case Uml::Visibility::Public:
+ oppub.append(op);
+ break;
+ case Uml::Visibility::Protected:
+ opprot.append(op);
+ break;
+ case Uml::Visibility::Private:
+ oppriv.append(op);
+ break;
+ default:
+ break;
+ }
+ }
+
+ QString classname(cleanName(c->getName()));
+
+ //write operations to file
+ if(forceSections() || !oppub.isEmpty()) {
+ writeOperations(classname,oppub,h,PUBLIC);
+ }
+
+ if(forceSections() || !opprot.isEmpty()) {
+ writeOperations(classname,opprot,h,PROTECTED);
+ }
+
+ if(forceSections() || !oppriv.isEmpty()) {
+ writeOperations(classname,oppriv,h,PRIVATE);
+ }
+
+}
+
+void PythonWriter::writeOperations(const QString& /*classname*/, UMLOperationList &opList,
+ QTextStream &h, Access access) {
+ UMLOperation *op;
+ UMLAttribute *at;
+
+ QString sAccess;
+
+ switch (access) {
+
+ case PUBLIC:
+ sAccess = QString("");
+ break;
+ case PRIVATE:
+ sAccess = QString("__");
+ break;
+ case PROTECTED:
+ sAccess = QString("_");
+ break;
+ }
+
+
+ for(op=opList.first(); op ; op=opList.next()) {
+ UMLAttributeList atl = op->getParmList();
+ //write method doc if we have doc || if at least one of the params has doc
+ bool writeDoc = forceDoc() || !op->getDoc().isEmpty();
+ for (at = atl.first(); at; at = atl.next())
+ writeDoc |= !at->getDoc().isEmpty();
+
+ h<< m_indentation << "def "<< sAccess + cleanName(op->getName()) << "(self";
+
+ int j=0;
+ for (at = atl.first(); at; at = atl.next(), j++) {
+ h << ", " << cleanName(at->getName())
+ << (!(at->getInitialValue().isEmpty()) ?
+ (QString(" = ")+at->getInitialValue()) :
+ QString(""));
+ }
+
+ h<<"):"<<m_endl;
+
+ if( writeDoc ) //write method documentation
+ {
+ h << m_indentation << m_indentation << "\"\"\"" << m_endl;
+ h << formatDoc(op->getDoc(), m_indentation + m_indentation + ' ') << m_endl;
+
+ for (at = atl.first(); at; at = atl.next()) //write parameter documentation
+ {
+ if(forceDoc() || !at->getDoc().isEmpty()) {
+ h<<m_indentation<<m_indentation<<"@param "<<at->getTypeName()<<
+ " " << cleanName(at->getName());
+ h<<" : "<<at->getDoc()<<m_endl;
+ }
+ }//end for : write parameter documentation
+ h<<m_indentation<<m_indentation<<"@return " + op->getTypeName()<<" :"<<m_endl;
+ h<<m_indentation<<m_indentation<<"@author"<<m_endl;
+ h<<m_indentation<<m_indentation<<"\"\"\""<<m_endl;
+ }
+ h<<m_indentation<<m_indentation<<"pass"<<m_endl<<m_endl;
+ m_bNeedPass = false;
+ }//end for
+}
+
+/**
+ * returns "Python"
+ */
+Uml::Programming_Language PythonWriter::getLanguage() {
+ return Uml::pl_Python;
+}
+
+const QStringList PythonWriter::reservedKeywords() const {
+
+ static QStringList keywords;
+
+ if (keywords.isEmpty()) {
+ keywords << "abs"
+ << "and"
+ << "apply"
+ << "ArithmeticError"
+ << "assert"
+ << "AssertionError"
+ << "AttributeError"
+ << "break"
+ << "buffer"
+ << "callable"
+ << "chr"
+ << "class"
+ << "classmethod"
+ << "cmp"
+ << "coerce"
+ << "compile"
+ << "complex"
+ << "continue"
+ << "def"
+ << "del"
+ << "delattr"
+ << "DeprecationWarning"
+ << "dict"
+ << "dir"
+ << "divmod"
+ << "elif"
+ << "Ellipsis"
+ << "else"
+ << "EnvironmentError"
+ << "EOFError"
+ << "eval"
+ << "except"
+ << "Exception"
+ << "exec"
+ << "execfile"
+ << "file"
+ << "filter"
+ << "finally"
+ << "float"
+ << "FloatingPointError"
+ << "for"
+ << "from"
+ << "getattr"
+ << "global"
+ << "globals"
+ << "hasattr"
+ << "hash"
+ << "hex"
+ << "id"
+ << "if"
+ << "import"
+ << "__import__"
+ << "ImportError"
+ << "in"
+ << "IndentationError"
+ << "IndexError"
+ << "input"
+ << "int"
+ << "intern"
+ << "IOError"
+ << "is"
+ << "isinstance"
+ << "issubclass"
+ << "iter"
+ << "KeyboardInterrupt"
+ << "KeyError"
+ << "lambda"
+ << "len"
+ << "list"
+ << "locals"
+ << "long"
+ << "LookupError"
+ << "map"
+ << "max"
+ << "MemoryError"
+ << "min"
+ << "NameError"
+ << "None"
+ << "not"
+ << "NotImplemented"
+ << "NotImplementedError"
+ << "object"
+ << "oct"
+ << "open"
+ << "or"
+ << "ord"
+ << "OSError"
+ << "OverflowError"
+ << "OverflowWarning"
+ << "pass"
+ << "pow"
+ << "print"
+ << "property"
+ << "raise"
+ << "range"
+ << "raw_input"
+ << "reduce"
+ << "ReferenceError"
+ << "reload"
+ << "repr"
+ << "return"
+ << "round"
+ << "RuntimeError"
+ << "RuntimeWarning"
+ << "setattr"
+ << "slice"
+ << "StandardError"
+ << "staticmethod"
+ << "StopIteration"
+ << "str"
+ << "super"
+ << "SyntaxError"
+ << "SyntaxWarning"
+ << "SystemError"
+ << "SystemExit"
+ << "TabError"
+ << "try"
+ << "tuple"
+ << "type"
+ << "TypeError"
+ << "UnboundLocalError"
+ << "unichr"
+ << "unicode"
+ << "UnicodeError"
+ << "UserWarning"
+ << "ValueError"
+ << "vars"
+ << "Warning"
+ << "while"
+ << "WindowsError"
+ << "xrange"
+ << "yield"
+ << "ZeroDivisionError"
+ << "zip";
+ }
+
+ return keywords;
+}
+
+#include "pythonwriter.moc"
diff --git a/umbrello/umbrello/codegenerators/pythonwriter.h b/umbrello/umbrello/codegenerators/pythonwriter.h
new file mode 100644
index 00000000..f9e5b31a
--- /dev/null
+++ b/umbrello/umbrello/codegenerators/pythonwriter.h
@@ -0,0 +1,86 @@
+/***************************************************************************
+ pythonwriter.h - description
+ -------------------
+ begin : Sat Dec 21 2002
+ author : Vincent Decorges
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * copyright (C) 2003-2007 *
+ * Umbrello UML Modeller Authors <uml-devel@uml.sf.net> *
+ ***************************************************************************/
+
+#ifndef PYTHONWRITER_H
+#define PYTHONWRITER_H
+
+#include "simplecodegenerator.h"
+#include "../umlattributelist.h"
+#include "../umloperationlist.h"
+
+enum Access {PRIVATE, PUBLIC, PROTECTED};
+
+/**
+ * class PythonWriter is a python code generator for UMLClassifier objects
+ * Just call writeClass and feed it a UMLClassifier;
+ */
+class PythonWriter : public SimpleCodeGenerator {
+ Q_OBJECT
+public:
+
+ PythonWriter();
+ virtual ~PythonWriter();
+
+ /**
+ * call this method to generate C++ code for a UMLClassifier
+ * @param c the class you want to generate code for.
+ */
+ virtual void writeClass(UMLClassifier *c);
+
+ /**
+ * returns "Python"
+ */
+ virtual Uml::Programming_Language getLanguage();
+
+ /**
+ * get list of reserved keywords
+ */
+ virtual const QStringList reservedKeywords() const;
+
+private:
+
+ /**
+ * write all attributes for a given class
+ *
+ * @param c the concept we are generating code for
+ * @param py output stream for the header file
+ */
+ void writeAttributes(UMLAttributeList atList, QTextStream &py);
+
+ /**
+ * write all operations for a given class
+ *
+ * @param c the concept we are generating code for
+ * @param h output stream for the header file
+ */
+ void writeOperations(UMLClassifier *c, QTextStream &h);
+
+ /**
+ * write a list of class operations
+ *
+ * @param classname the name of the class
+ * @param opList the list of operations
+ * @param h output stream for the header file
+ */
+ void writeOperations(const QString& classname, UMLOperationList &opList,
+ QTextStream &h, Access access);
+
+ bool m_bNeedPass; ///< True as long as no "pass" has been written
+};
+
+#endif //PYTHONWRITER
diff --git a/umbrello/umbrello/codegenerators/rubyclassdeclarationblock.cpp b/umbrello/umbrello/codegenerators/rubyclassdeclarationblock.cpp
new file mode 100644
index 00000000..cae5d322
--- /dev/null
+++ b/umbrello/umbrello/codegenerators/rubyclassdeclarationblock.cpp
@@ -0,0 +1,147 @@
+/***************************************************************************
+ rubyclassdeclarationblock.cpp
+ Derived from the Java code generator by thomas
+
+ begin : Thur Jul 21 2005
+ author : Richard Dale
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * copyright (C) 2006 *
+ * Umbrello UML Modeller Authors <uml-devel@uml.sf.net> *
+ ***************************************************************************/
+
+#include "rubyclassdeclarationblock.h"
+#include "rubycodedocumentation.h"
+#include "rubycodegenerator.h"
+#include "../uml.h"
+
+// Constructors/Destructors
+//
+
+RubyClassDeclarationBlock::RubyClassDeclarationBlock
+ ( RubyClassifierCodeDocument * parentDoc, const QString &startText, const QString &endText, const QString &comment)
+ : OwnedHierarchicalCodeBlock(parentDoc->getParentClassifier(), parentDoc, startText, endText, comment)
+{
+ init(parentDoc, comment);
+}
+
+RubyClassDeclarationBlock::~RubyClassDeclarationBlock ( ) { }
+
+//
+// Methods
+//
+
+/**
+ * Save the XMI representation of this object
+ */
+void RubyClassDeclarationBlock::saveToXMI ( QDomDocument & doc, QDomElement & root ) {
+ QDomElement blockElement = doc.createElement( "rubyclassdeclarationblock" );
+
+ setAttributesOnNode(doc, blockElement);
+
+ root.appendChild( blockElement );
+}
+
+/**
+ * load params from the appropriate XMI element node.
+ */
+void RubyClassDeclarationBlock::loadFromXMI ( QDomElement & root )
+{
+ setAttributesFromNode(root);
+}
+
+// Accessor methods
+//
+
+// Other methods
+//
+
+/**
+ * update the start and end text for this ownedhierarchicalcodeblock.
+ */
+void RubyClassDeclarationBlock::updateContent ( )
+{
+
+ RubyClassifierCodeDocument *parentDoc = dynamic_cast<RubyClassifierCodeDocument*>(getParentDocument());
+ UMLClassifier *c = parentDoc->getParentClassifier();
+ CodeGenerationPolicy * p = UMLApp::app()->getCommonPolicy();
+ QString endLine = p->getNewLineEndingChars();
+ bool isInterface = parentDoc->parentIsInterface(); // a little shortcut
+ QString RubyClassName = parentDoc->getRubyClassName(c->getName());
+ bool forceDoc = p->getCodeVerboseDocumentComments();
+
+ // COMMENT
+ QString comment = c->getDoc();
+ comment.replace("@ref ", "");
+ comment.replace("@see", "_See_");
+ comment.replace("@short", "_Summary_");
+ comment.replace("@author", "_Author_");
+
+ if (isInterface)
+ getComment()->setText("Module " + RubyClassName + endLine + comment);
+ else
+ getComment()->setText("Class " + RubyClassName + endLine + comment);
+
+ if(forceDoc || !c->getDoc().isEmpty())
+ getComment()->setWriteOutText(true);
+ else
+ getComment()->setWriteOutText(false);
+
+
+ // Now set START/ENDING Text
+ QString startText = "";
+
+ if (parentDoc->parentIsInterface()) {
+ startText.append("module ");
+ } else {
+ startText.append("class ");
+ }
+
+ UMLClassifierList superclasses = c->findSuperClassConcepts(UMLClassifier::CLASS);
+ UMLClassifierList superinterfaces = c->findSuperClassConcepts(UMLClassifier::INTERFACE);
+
+ // write out inheritance
+ startText.append(RubyClassName);
+
+ int i = 0;
+ for (UMLClassifier * concept= superclasses.first(); concept; concept = superclasses.next()) {
+ if (i == 0) {
+ startText.append(QString(" < ") + RubyCodeGenerator::cppToRubyType(concept->getName()) + endLine);
+ } else {
+ // After the first superclass name in the list, assume the classes
+ // are ruby modules that can be mixed in,
+ startText.append("include " + RubyCodeGenerator::cppToRubyType(concept->getName()) + endLine);
+ }
+ i++;
+ }
+
+ // Write out the interfaces we 'implement'. Are these modules to be mixed in, in Ruby?
+ for (UMLClassifier * concept= superinterfaces.first(); concept; concept = superinterfaces.next()) {
+ startText.append(QString("include ") + RubyCodeGenerator::cppToRubyType(concept->getName()) + endLine);
+ }
+
+ // Set the header and end text for the hier.codeblock
+ setStartText(startText);
+}
+
+void RubyClassDeclarationBlock::init (RubyClassifierCodeDocument *parentDoc, const QString &comment)
+{
+
+ setComment(new RubyCodeDocumentation(parentDoc));
+ getComment()->setText(comment);
+
+ setEndText("end");
+
+ updateContent();
+
+}
+
+
+#include "rubyclassdeclarationblock.moc"
diff --git a/umbrello/umbrello/codegenerators/rubyclassdeclarationblock.h b/umbrello/umbrello/codegenerators/rubyclassdeclarationblock.h
new file mode 100644
index 00000000..a7732662
--- /dev/null
+++ b/umbrello/umbrello/codegenerators/rubyclassdeclarationblock.h
@@ -0,0 +1,74 @@
+
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the 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 code generated by:
+ * Author : thomas
+ * Date : Wed Jul 16 2003
+ */
+
+#ifndef RUBYCLASSDECLARATIONBLOCK_H
+#define RUBYCLASSDECLARATIONBLOCK_H
+
+#include <qstring.h>
+
+/***************************************************************************
+ rubyclassdeclarationblock.h
+ Derived from the Java code generator by thomas
+
+ begin : Thur Jul 21 2005
+ author : Richard Dale
+ ***************************************************************************/
+
+#include "rubyclassifiercodedocument.h"
+#include "../ownedhierarchicalcodeblock.h"
+
+class RubyClassDeclarationBlock : public OwnedHierarchicalCodeBlock
+{
+ Q_OBJECT
+public:
+
+ // Constructors/Destructors
+ //
+
+ /**
+ * Empty Constructor
+ */
+ explicit RubyClassDeclarationBlock ( RubyClassifierCodeDocument * parentDoc, const QString &start = "", const QString &endText = "end", const QString &comment = "");
+
+ /**
+ * Empty Destructor
+ */
+ virtual ~RubyClassDeclarationBlock ( );
+
+ /**
+ * Save the XMI representation of this object
+ */
+ virtual void saveToXMI ( QDomDocument & doc, QDomElement & root );
+
+ /**
+ * load params from the appropriate XMI element node.
+ */
+ virtual void loadFromXMI ( QDomElement & root );
+
+protected:
+
+ /**
+ * Update the start/end text of this codeblock.
+ */
+ void updateContent ( );
+
+private:
+
+ void init (RubyClassifierCodeDocument * parent, const QString &comment);
+
+};
+
+#endif // RUBYCLASSDECLARATIONBLOCK_H
diff --git a/umbrello/umbrello/codegenerators/rubyclassifiercodedocument.cpp b/umbrello/umbrello/codegenerators/rubyclassifiercodedocument.cpp
new file mode 100644
index 00000000..1c136df8
--- /dev/null
+++ b/umbrello/umbrello/codegenerators/rubyclassifiercodedocument.cpp
@@ -0,0 +1,646 @@
+/***************************************************************************
+ rubyclassifiercodedocument.cpp
+ Derived from the Java code generator by thomas
+
+ begin : Thur Jul 21 2005
+ author : Richard Dale
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * copyright (C) 2006-2007 *
+ * Umbrello UML Modeller Authors <uml-devel@uml.sf.net> *
+ ***************************************************************************/
+
+/**
+ We carve the Ruby document up into sections as follows:
+
+ * header
+ * class declaration
+ * guts of the class (e.g. accessor methods, operations, dependant classes)
+*/
+
+// own header
+#include "rubyclassifiercodedocument.h"
+
+// qt/kde includes
+#include <qregexp.h>
+#include <kdebug.h>
+
+// local includes
+#include "rubycodegenerator.h"
+#include "rubycodecomment.h"
+#include "rubyclassdeclarationblock.h"
+#include "rubycodeclassfielddeclarationblock.h"
+#include "rubycodeoperation.h"
+#include "codegen_utils.h"
+#include "../classifier.h"
+#include "../uml.h"
+
+// Constructors/Destructors
+//
+
+RubyClassifierCodeDocument::RubyClassifierCodeDocument ( UMLClassifier * concept )
+ : ClassifierCodeDocument (concept) {
+ init();
+}
+
+RubyClassifierCodeDocument::~RubyClassifierCodeDocument ( ) { }
+
+//
+// Methods
+//
+
+// Accessor methods
+//
+
+// Make it easier on ourselves
+RubyCodeGenerationPolicy * RubyClassifierCodeDocument::getRubyPolicy() {
+ CodeGenPolicyExt *pe = UMLApp::app()->getPolicyExt();
+ RubyCodeGenerationPolicy * policy = dynamic_cast<RubyCodeGenerationPolicy*>(pe);
+ return policy;
+}
+
+/**
+ * Get the dialog widget which allows user interaction with the object parameters.
+ * @return CodeDocumentDialog
+ */
+/*
+CodeDocumentDialog RubyClassifierCodeDocument::getDialog ( ) {
+
+}
+*/
+
+// We overwritten by Ruby language implementation to get lowercase path
+QString RubyClassifierCodeDocument::getPath ( )
+{
+
+ QString path = getPackage();
+
+ // Replace all white spaces with blanks
+ path.simplifyWhiteSpace();
+
+ // Replace all blanks with underscore
+ path.replace(QRegExp(" "), "_");
+
+ path.replace(QRegExp("\\."),"/");
+ path.replace(QRegExp("::"), "/");
+
+ path.lower();
+
+ return path;
+
+}
+
+
+// Other methods
+//
+
+QString RubyClassifierCodeDocument::getRubyClassName (const QString &name) {
+ CodeGenerator *g = UMLApp::app()->getGenerator();
+ return Codegen_Utils::capitalizeFirstLetter(g->cleanName(name));
+}
+
+// Initialize this ruby classifier code document
+void RubyClassifierCodeDocument::init ( ) {
+
+ setFileExtension(".rb");
+
+ //initCodeClassFields(); // this is dubious because it calls down to
+ // CodeGenFactory::newCodeClassField(this)
+ // but "this" is still in construction at that time.
+
+ classDeclCodeBlock = 0;
+ publicBlock = 0;
+ protectedBlock = 0;
+ privateBlock = 0;
+ pubConstructorBlock = 0;
+ protConstructorBlock = 0;
+ privConstructorBlock = 0;
+ pubOperationsBlock = 0;
+ privOperationsBlock = 0;
+ protOperationsBlock = 0;
+
+ // this will call updateContent() as well as other things that sync our document.
+ synchronize();
+}
+
+/**
+ * @param op
+ */
+// in the vanilla version, we just tack all operations on the end
+// of the document
+bool RubyClassifierCodeDocument::addCodeOperation (CodeOperation * op )
+{
+ Uml::Visibility scope = op->getParentOperation()->getVisibility();
+ if(!op->getParentOperation()->isConstructorOperation())
+ {
+ switch (scope) {
+ default:
+ case Uml::Visibility::Public:
+ return pubOperationsBlock->addTextBlock(op);
+ break;
+ case Uml::Visibility::Protected:
+ return protOperationsBlock->addTextBlock(op);
+ break;
+ case Uml::Visibility::Private:
+ return privOperationsBlock->addTextBlock(op);
+ break;
+ }
+ } else {
+ switch (scope) {
+ default:
+ case Uml::Visibility::Public:
+ return pubConstructorBlock->addTextBlock(op);
+ break;
+ case Uml::Visibility::Protected:
+ return protConstructorBlock->addTextBlock(op);
+ break;
+ case Uml::Visibility::Private:
+ return privConstructorBlock->addTextBlock(op);
+ break;
+ }
+ }
+}
+
+// Sigh. NOT optimal. The only reason that we need to have this
+// is so we can create the RubyClassDeclarationBlock.
+// would be better if we could create a handler interface that each
+// codeblock used so all we have to do here is add the handler
+// for "rubyclassdeclarationblock"
+void RubyClassifierCodeDocument::loadChildTextBlocksFromNode ( QDomElement & root)
+{
+
+ QDomNode tnode = root.firstChild();
+ QDomElement telement = tnode.toElement();
+ bool loadCheckForChildrenOK = false;
+ while( !telement.isNull() ) {
+ QString nodeName = telement.tagName();
+
+ if( nodeName == "textblocks" ) {
+
+ QDomNode node = telement.firstChild();
+ QDomElement element = node.toElement();
+
+ // if there is nothing to begin with, then we don't worry about it
+ loadCheckForChildrenOK = element.isNull() ? true : false;
+
+ while( !element.isNull() ) {
+ QString name = element.tagName();
+
+ if( name == "codecomment" ) {
+ CodeComment * block = new RubyCodeComment(this);
+ block->loadFromXMI(element);
+ if(!addTextBlock(block))
+ {
+ kError()<<"loadFromXMI : unable to add codeComment to :"<<this<<endl;
+ block->deleteLater();
+ } else
+ loadCheckForChildrenOK= true;
+ } else
+ if( name == "codeaccessormethod" ||
+ name == "ccfdeclarationcodeblock"
+ ) {
+ QString acctag = element.attribute("tag","");
+ // search for our method in the
+ TextBlock * tb = findCodeClassFieldTextBlockByTag(acctag);
+ if(!tb || !addTextBlock(tb))
+ {
+ kError()<<"loadFromXMI : unable to add codeclassfield child method to:"<<this<<endl;
+ // DON'T delete
+ } else
+ loadCheckForChildrenOK= true;
+
+ } else
+ if( name == "codeblock" ) {
+ CodeBlock * block = newCodeBlock();
+ block->loadFromXMI(element);
+ if(!addTextBlock(block))
+ {
+ kError()<<"loadFromXMI : unable to add codeBlock to :"<<this<<endl;
+ block->deleteLater();
+ } else
+ loadCheckForChildrenOK= true;
+ } else
+ if( name == "codeblockwithcomments" ) {
+ CodeBlockWithComments * block = newCodeBlockWithComments();
+ block->loadFromXMI(element);
+ if(!addTextBlock(block))
+ {
+ kError()<<"loadFromXMI : unable to add codeBlockwithcomments to:"<<this<<endl;
+ block->deleteLater();
+ } else
+ loadCheckForChildrenOK= true;
+ } else
+ if( name == "header" ) {
+ // do nothing.. this is treated elsewhere
+ } else
+ if( name == "hierarchicalcodeblock" ) {
+ HierarchicalCodeBlock * block = newHierarchicalCodeBlock();
+ block->loadFromXMI(element);
+ if(!addTextBlock(block))
+ {
+ kError()<<"Unable to add hierarchicalcodeBlock to:"<<this<<endl;
+ block->deleteLater();
+ } else
+ loadCheckForChildrenOK= true;
+ } else
+ if( name == "codeoperation" ) {
+ // find the code operation by id
+ QString id = element.attribute("parent_id","-1");
+ UMLObject * obj = UMLApp::app()->getDocument()->findObjectById(STR2ID(id));
+ UMLOperation * op = dynamic_cast<UMLOperation*>(obj);
+ if(op) {
+ CodeOperation * block = new RubyCodeOperation(this, op);
+ block->loadFromXMI(element);
+ if(addTextBlock(block))
+ loadCheckForChildrenOK= true;
+ else
+ {
+ kError()<<"Unable to add codeoperation to:"<<this<<endl;
+ block->deleteLater();
+ }
+ } else
+ kError()<<"Unable to find operation create codeoperation for:"<<this<<endl;
+ } else
+ if( name == "rubyclassdeclarationblock" )
+ {
+ RubyClassDeclarationBlock * block = getClassDecl();
+ block->loadFromXMI(element);
+ if(!addTextBlock(block))
+ {
+ kError()<<"Unable to add ruby code declaration block to:"<<this<<endl;
+ // DON'T delete.
+ // block->deleteLater();
+ } else
+ loadCheckForChildrenOK= true;
+ }
+ // This last item is only needed for extreme debugging conditions
+ // (E.g. making new codeclassdocument loader)
+ // else
+ // kDebug()<<" LoadFromXMI: Got strange tag in text block stack:"<<name<<", ignorning"<<endl;
+
+ node = element.nextSibling();
+ element = node.toElement();
+ }
+ break;
+ }
+
+ tnode = telement.nextSibling();
+ telement = tnode.toElement();
+ }
+
+ if(!loadCheckForChildrenOK)
+ {
+ CodeDocument * test = dynamic_cast<CodeDocument*>(this);
+ if(test)
+ {
+ kWarning()<<" loadChildBlocks : unable to initialize any child blocks in doc: "<<test->getFileName()<<" "<<this<<endl;
+ } else {
+ HierarchicalCodeBlock * hb = dynamic_cast<HierarchicalCodeBlock*>(this);
+ if(hb)
+ kWarning()<<" loadChildBlocks : unable to initialize any child blocks in Hblock: "<<hb->getTag()<<" "<<this<<endl;
+ else
+ kDebug()<<" loadChildBlocks : unable to initialize any child blocks in UNKNOWN OBJ:"<<this<<endl;
+ }
+ }
+
+
+}
+
+QString RubyClassifierCodeDocument::scopeToRubyDecl(Uml::Visibility scope)
+{
+ QString scopeString;
+ switch(scope)
+ {
+ case Uml::Visibility::Public:
+ scopeString = "public";
+ break;
+ case Uml::Visibility::Protected:
+ scopeString = "protected";
+ break;
+ case Uml::Visibility::Private:
+ default:
+ scopeString = "private";
+ break;
+ }
+ return scopeString;
+}
+
+RubyClassDeclarationBlock * RubyClassifierCodeDocument::getClassDecl()
+{
+ if(!classDeclCodeBlock)
+ {
+ classDeclCodeBlock = new RubyClassDeclarationBlock (this);
+ classDeclCodeBlock->setTag("ClassDeclBlock");
+ }
+ return classDeclCodeBlock;
+}
+
+void RubyClassifierCodeDocument::resetTextBlocks()
+{
+
+ // all special pointers to text blocks need to be zero'd out
+ operationsBlock = 0;
+ constructorBlock = 0;
+ classDeclCodeBlock = 0;
+
+ // now do traditional release of text blocks.
+ ClassifierCodeDocument::resetTextBlocks();
+}
+
+// This method will cause the class to rebuild its text representation.
+// based on the parent classifier object.
+// For any situation in which this is called, we are either building the code
+// document up, or replacing/regenerating the existing auto-generated parts. As
+// such, we will want to insert everything we resonablely will want
+// during creation. We can set various parts of the document (esp. the
+// comments) to appear or not, as needed.
+void RubyClassifierCodeDocument::updateContent( )
+{
+ // Gather info on the various fields and parent objects of this class...
+ UMLClassifier * c = getParentClassifier();
+ RubyCodeGenerator * gen = dynamic_cast<RubyCodeGenerator*>(UMLApp::app()->getGenerator());
+
+ // first, set the global flag on whether or not to show classfield info
+ // This depends on whether or not we have attribute/association classes
+ CodeClassFieldList * cfList = getCodeClassFieldList();
+ for(CodeClassField * field = cfList->first(); field; field = cfList->next())
+ if(field->parentIsAttribute())
+ field->setWriteOutMethods(gen->getAutoGenerateAttribAccessors());
+ else
+ field->setWriteOutMethods(gen->getAutoGenerateAssocAccessors());
+
+ // attribute-based ClassFields
+ // we do it this way to have the static fields sorted out from regular ones
+ CodeClassFieldList staticPublicAttribClassFields = getSpecificClassFields (CodeClassField::Attribute, true, Uml::Visibility::Public );
+ CodeClassFieldList publicAttribClassFields = getSpecificClassFields (CodeClassField::Attribute, false, Uml::Visibility::Public );
+ CodeClassFieldList staticProtectedAttribClassFields = getSpecificClassFields (CodeClassField::Attribute, true, Uml::Visibility::Protected );
+ CodeClassFieldList protectedAttribClassFields = getSpecificClassFields (CodeClassField::Attribute, false, Uml::Visibility::Protected );
+ CodeClassFieldList staticPrivateAttribClassFields = getSpecificClassFields (CodeClassField::Attribute, true, Uml::Visibility::Private );
+ CodeClassFieldList privateAttribClassFields = getSpecificClassFields (CodeClassField::Attribute, false, Uml::Visibility::Private);
+
+ // association-based ClassFields
+ // don't care if they are static or not..all are lumped together
+ CodeClassFieldList publicPlainAssocClassFields = getSpecificClassFields ( CodeClassField::PlainAssociation , Uml::Visibility::Public);
+ CodeClassFieldList publicAggregationClassFields = getSpecificClassFields ( CodeClassField::Aggregation, Uml::Visibility::Public);
+ CodeClassFieldList publicCompositionClassFields = getSpecificClassFields ( CodeClassField::Composition, Uml::Visibility::Public );
+
+ CodeClassFieldList protPlainAssocClassFields = getSpecificClassFields ( CodeClassField::PlainAssociation , Uml::Visibility::Protected);
+ CodeClassFieldList protAggregationClassFields = getSpecificClassFields ( CodeClassField::Aggregation, Uml::Visibility::Protected);
+ CodeClassFieldList protCompositionClassFields = getSpecificClassFields ( CodeClassField::Composition, Uml::Visibility::Protected);
+
+ CodeClassFieldList privPlainAssocClassFields = getSpecificClassFields ( CodeClassField::PlainAssociation , Uml::Visibility::Private);
+ CodeClassFieldList privAggregationClassFields = getSpecificClassFields ( CodeClassField::Aggregation, Uml::Visibility::Private);
+ CodeClassFieldList privCompositionClassFields = getSpecificClassFields ( CodeClassField::Composition, Uml::Visibility::Private);
+
+ bool isInterface = parentIsInterface();
+ bool hasOperationMethods = c->getOpList().last() ? true : false;
+ CodeGenerationPolicy *pol = UMLApp::app()->getCommonPolicy();
+ QString endLine = pol->getNewLineEndingChars(); // a shortcut..so we don't have to call this all the time
+
+ //
+ // START GENERATING CODE/TEXT BLOCKS and COMMENTS FOR THE DOCUMENT
+ //
+
+
+ // CLASS DECLARATION BLOCK
+ //
+
+ // get the declaration block. If its not already present, add it too
+ RubyClassDeclarationBlock * myClassDeclCodeBlock = getClassDecl();
+ addTextBlock(myClassDeclCodeBlock); // note: wont add if already present
+
+ // declare public, protected and private methods, attributes (fields).
+ // set the start text ONLY if this is the first time we created the objects.
+ bool createdPublicBlock = publicBlock == 0 ? true : false;
+ publicBlock = myClassDeclCodeBlock->getHierarchicalCodeBlock("publicBlock","Public Items",0);
+ if (createdPublicBlock)
+ publicBlock->setStartText("public");
+
+ bool createdProtBlock = protectedBlock == 0 ? true : false;
+ protectedBlock = myClassDeclCodeBlock->getHierarchicalCodeBlock("protectedBlock","Protected Items",0);
+ if(createdProtBlock)
+ protectedBlock->setStartText("protected");
+
+ bool createdPrivBlock = privateBlock == 0 ? true : false;
+ privateBlock = myClassDeclCodeBlock->getHierarchicalCodeBlock("privateBlock","Private Items",0);
+ if(createdPrivBlock)
+ privateBlock->setStartText("private");
+
+ // NOW create document in sections..
+ // now we want to populate the body of our class
+ // our layout is the following general groupings of code blocks:
+
+ // start ruby classifier document
+
+ // header comment
+
+ // class declaration
+
+ // section:
+
+ // section:
+ // - methods section comment
+
+ // sub-section: constructor ops
+ // - constructor method section comment
+ // - constructor methods (0+ codeblocks)
+
+ // sub-section: accessors
+ // - accessor method section comment
+ // - static accessor methods (0+ codeblocks)
+ // - non-static accessor methods (0+ codeblocks)
+
+ // sub-section: non-constructor ops
+ // - operation method section comment
+ // - operations (0+ codeblocks)
+
+ // end class declaration
+
+ // end ruby classifier document
+
+
+ // Q: Why use the more complicated scheme of arranging code blocks within codeblocks?
+ // A: This will allow us later to preserve the format of our document so that if
+ // codeblocks are added, they may be easily added in the correct place, rather than at
+ // the end of the document, or by using a difficult algorithm to find the location of
+ // the last appropriate code block sibling (which may not exist.. for example user adds
+ // a constructor operation, but there currently are no constructor code blocks
+ // within the document).
+
+
+ //
+ // METHODS section
+ //
+
+ // get/create the method codeblock
+ // public methods
+ HierarchicalCodeBlock * pubMethodsBlock = publicBlock->getHierarchicalCodeBlock("pubMethodsBlock", "", 1);
+ CodeComment * pubMethodsComment = pubMethodsBlock->getComment();
+ bool forceDoc = pol->getCodeVerboseDocumentComments();
+ // set conditions for showing this comment
+ if (!forceDoc && !hasClassFields() && !hasOperationMethods)
+ pubMethodsComment->setWriteOutText(false);
+ else
+ pubMethodsComment->setWriteOutText(true);
+
+ // protected methods
+ HierarchicalCodeBlock * protMethodsBlock = protectedBlock->getHierarchicalCodeBlock("protMethodsBlock", "", 1);
+ CodeComment * protMethodsComment = protMethodsBlock->getComment();
+ // set conditions for showing this comment
+ if (!forceDoc && !hasClassFields() && !hasOperationMethods)
+ protMethodsComment->setWriteOutText(false);
+ else
+ protMethodsComment->setWriteOutText(true);
+
+ // private methods
+ HierarchicalCodeBlock * privMethodsBlock = privateBlock->getHierarchicalCodeBlock("privMethodsBlock", "", 1);
+ CodeComment * privMethodsComment = privMethodsBlock->getComment();
+ // set conditions for showing this comment
+ if (!forceDoc && !hasClassFields() && !hasOperationMethods)
+ privMethodsComment->setWriteOutText(false);
+ else
+ privMethodsComment->setWriteOutText(true);
+
+ // METHODS sub-section : constructor methods
+ //
+
+ // public
+ pubConstructorBlock = pubMethodsBlock->getHierarchicalCodeBlock("constructionMethods", "Constructors", 1);
+ // special condiions for showing comment: only when autogenerateding empty constructors
+ // Although, we *should* check for other constructor methods too
+ CodeComment * pubConstComment = pubConstructorBlock->getComment();
+ if (!forceDoc && (isInterface || !pol->getAutoGenerateConstructors()))
+ pubConstComment->setWriteOutText(false);
+ else
+ pubConstComment->setWriteOutText(true);
+
+ // protected
+ protConstructorBlock = protMethodsBlock->getHierarchicalCodeBlock("constructionMethods", "Constructors", 1);
+ // special condiions for showing comment: only when autogenerateding empty constructors
+ // Although, we *should* check for other constructor methods too
+ CodeComment * protConstComment = protConstructorBlock->getComment();
+ if (!forceDoc && (isInterface || !pol->getAutoGenerateConstructors()))
+ protConstComment->setWriteOutText(false);
+ else
+ protConstComment->setWriteOutText(true);
+
+ // private
+ privConstructorBlock = privMethodsBlock->getHierarchicalCodeBlock("constructionMethods", "Constructors", 1);
+ // special condiions for showing comment: only when autogenerateding empty constructors
+ // Although, we *should* check for other constructor methods too
+ CodeComment * privConstComment = privConstructorBlock->getComment();
+ if (!forceDoc && (isInterface || !pol->getAutoGenerateConstructors()))
+ privConstComment->setWriteOutText(false);
+ else
+ privConstComment->setWriteOutText(true);
+
+ // get/create the accessor codeblock
+ // public
+ HierarchicalCodeBlock * pubAccessorBlock = pubMethodsBlock->getHierarchicalCodeBlock("accessorMethods", "Accessor Methods", 1);
+ // set conditions for showing section comment
+ CodeComment * pubAccessComment = pubAccessorBlock->getComment();
+ if (!forceDoc && !hasClassFields())
+ pubAccessComment->setWriteOutText(false);
+ else
+ pubAccessComment->setWriteOutText(true);
+
+ // protected
+ HierarchicalCodeBlock * protAccessorBlock = protMethodsBlock->getHierarchicalCodeBlock("accessorMethods", "Accessor Methods", 1);
+ // set conditions for showing section comment
+ CodeComment * protAccessComment = protAccessorBlock->getComment();
+ if (!forceDoc && !hasClassFields())
+ protAccessComment->setWriteOutText(false);
+ else
+ protAccessComment->setWriteOutText(true);
+
+ // private
+ HierarchicalCodeBlock * privAccessorBlock = privMethodsBlock->getHierarchicalCodeBlock("accessorMethods", "Accessor Methods", 1);
+ // set conditions for showing section comment
+ CodeComment * privAccessComment = privAccessorBlock->getComment();
+ if (!forceDoc && !hasClassFields())
+ privAccessComment->setWriteOutText(false);
+ else
+ privAccessComment->setWriteOutText(true);
+
+ // now, 2 sub-sub sections in accessor block
+ // add/update accessor methods for attributes
+ HierarchicalCodeBlock * pubStaticAccessors = pubAccessorBlock->getHierarchicalCodeBlock("pubStaticAccessorMethods", "", 1);
+ HierarchicalCodeBlock * pubRegularAccessors = pubAccessorBlock->getHierarchicalCodeBlock("pubRegularAccessorMethods", "", 1);
+ pubStaticAccessors->getComment()->setWriteOutText(false); // never write block comment
+ pubRegularAccessors->getComment()->setWriteOutText(false); // never write block comment
+
+ HierarchicalCodeBlock * protStaticAccessors = protAccessorBlock->getHierarchicalCodeBlock("protStaticAccessorMethods", "", 1);
+ HierarchicalCodeBlock * protRegularAccessors = protAccessorBlock->getHierarchicalCodeBlock("protRegularAccessorMethods", "", 1);
+ protStaticAccessors->getComment()->setWriteOutText(false); // never write block comment
+ protRegularAccessors->getComment()->setWriteOutText(false); // never write block comment
+
+ HierarchicalCodeBlock * privStaticAccessors = privAccessorBlock->getHierarchicalCodeBlock("privStaticAccessorMethods", "", 1);
+ HierarchicalCodeBlock * privRegularAccessors = privAccessorBlock->getHierarchicalCodeBlock("privRegularAccessorMethods", "", 1);
+ privStaticAccessors->getComment()->setWriteOutText(false); // never write block comment
+ privRegularAccessors->getComment()->setWriteOutText(false); // never write block comment
+ // now add in accessors as appropriate
+
+ // public stuff
+ pubStaticAccessors->addCodeClassFieldMethods(staticPublicAttribClassFields);
+ pubRegularAccessors->addCodeClassFieldMethods(publicAttribClassFields);
+ pubRegularAccessors->addCodeClassFieldMethods(publicPlainAssocClassFields);
+ pubRegularAccessors->addCodeClassFieldMethods(publicAggregationClassFields);
+ pubRegularAccessors->addCodeClassFieldMethods(publicCompositionClassFields);
+
+ // protected stuff
+ protStaticAccessors->addCodeClassFieldMethods(staticProtectedAttribClassFields);
+ protRegularAccessors->addCodeClassFieldMethods(protectedAttribClassFields);
+ protRegularAccessors->addCodeClassFieldMethods(protPlainAssocClassFields);
+ protRegularAccessors->addCodeClassFieldMethods(protAggregationClassFields);
+ protRegularAccessors->addCodeClassFieldMethods(protCompositionClassFields);
+
+ // private stuff
+ privStaticAccessors->addCodeClassFieldMethods(staticPrivateAttribClassFields);
+ privRegularAccessors->addCodeClassFieldMethods(privateAttribClassFields);
+ privRegularAccessors->addCodeClassFieldMethods(privPlainAssocClassFields);
+ privRegularAccessors->addCodeClassFieldMethods(privAggregationClassFields);
+ privRegularAccessors->addCodeClassFieldMethods(privCompositionClassFields);
+
+ // METHODS subsection : Operation methods (which aren't constructors)
+ //
+
+ // setup/get/create the operations codeblock
+
+ // public
+ pubOperationsBlock = pubMethodsBlock->getHierarchicalCodeBlock("operationMethods", "Operations", 1);
+ // set conditions for showing section comment
+ CodeComment * pubOcomment = pubOperationsBlock->getComment();
+ if (!forceDoc && !hasOperationMethods )
+ pubOcomment->setWriteOutText(false);
+ else
+ pubOcomment->setWriteOutText(true);
+
+ //protected
+ protOperationsBlock = protMethodsBlock->getHierarchicalCodeBlock("operationMethods", "Operations", 1);
+ // set conditions for showing section comment
+ CodeComment * protOcomment = protOperationsBlock->getComment();
+ if (!forceDoc && !hasOperationMethods )
+ protOcomment->setWriteOutText(false);
+ else
+ protOcomment->setWriteOutText(true);
+
+ //private
+ privOperationsBlock = privMethodsBlock->getHierarchicalCodeBlock("operationMethods", "Operations", 1);
+ // set conditions for showing section comment
+ CodeComment * privOcomment = privOperationsBlock->getComment();
+ if (!forceDoc && !hasOperationMethods )
+ privOcomment->setWriteOutText(false);
+ else
+ privOcomment->setWriteOutText(true);
+
+}
+
+
+#include "rubyclassifiercodedocument.moc"
diff --git a/umbrello/umbrello/codegenerators/rubyclassifiercodedocument.h b/umbrello/umbrello/codegenerators/rubyclassifiercodedocument.h
new file mode 100644
index 00000000..c5f89d07
--- /dev/null
+++ b/umbrello/umbrello/codegenerators/rubyclassifiercodedocument.h
@@ -0,0 +1,126 @@
+/***************************************************************************
+ rubyclassdeclarationblock.cpp
+ Derived from the Java code generator by thomas
+
+ begin : Thur Jul 21 2005
+ author : Richard Dale
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * copyright (C) 2006-2007 *
+ * Umbrello UML Modeller Authors <uml-devel@uml.sf.net> *
+ ***************************************************************************/
+
+
+#ifndef RUBYCLASSIFIERCODEDOCUMENT_H
+#define RUBYCLASSIFIERCODEDOCUMENT_H
+
+#include <qstring.h>
+
+#include "../codeclassfieldlist.h"
+#include "../classifiercodedocument.h"
+#include "../classifier.h"
+#include "../hierarchicalcodeblock.h"
+#include "classifierinfo.h"
+#include "rubycodeclassfield.h"
+#include "rubycodeoperation.h"
+
+class RubyClassDeclarationBlock;
+class RubyCodeGenerationPolicy;
+
+/**
+ * class RubyClassifierCodeDocument
+ * A Ruby UMLClassifier Code Document.
+ */
+
+class RubyClassifierCodeDocument : public ClassifierCodeDocument
+{
+ Q_OBJECT
+public:
+
+ // Constructors/Destructors
+ //
+
+
+ /**
+ * Constructor
+ */
+ RubyClassifierCodeDocument (UMLClassifier * classifier);
+
+ /**
+ * Empty Destructor
+ */
+ virtual ~RubyClassifierCodeDocument ( );
+
+ /**
+ * Get the dialog widget which allows user interaction with the object parameters.
+ * @return CodeDocumentDialog
+ */
+ //CodeDocumentDialog getDialog ( );
+
+ QString scopeToRubyDecl(Uml::Visibility scope);
+
+ // Make it easier on ourselves
+ RubyCodeGenerationPolicy * getRubyPolicy();
+
+ QString getRubyClassName (const QString &name);
+
+ QString getPath();
+
+ /** add a code operation to this ruby classifier code document.
+ * @return bool which is true IF the code operation was added successfully
+ */
+ bool addCodeOperation (CodeOperation * op );
+
+protected:
+
+ // reset/clear our inventory of textblocks in this document
+ void resetTextBlocks();
+
+ /**
+ * need to overwrite this for ruby since we need to pick up the
+ * ruby class declaration block.
+ */
+ virtual void loadChildTextBlocksFromNode ( QDomElement & root);
+
+ void addOrUpdateCodeClassFieldMethodsInCodeBlock(CodeClassFieldList &list, RubyClassDeclarationBlock * codeBlock);
+
+ bool forceDoc ();
+
+ void updateContent();
+
+private:
+
+ RubyClassDeclarationBlock * classDeclCodeBlock;
+ HierarchicalCodeBlock * constructorBlock;
+ HierarchicalCodeBlock * operationsBlock;
+
+ HierarchicalCodeBlock * publicBlock;
+ HierarchicalCodeBlock * privateBlock;
+ HierarchicalCodeBlock * protectedBlock;
+
+// HierarchicalCodeBlock * namespaceBlock;
+
+ HierarchicalCodeBlock * pubConstructorBlock;
+ HierarchicalCodeBlock * protConstructorBlock;
+ HierarchicalCodeBlock * privConstructorBlock;
+
+ HierarchicalCodeBlock * pubOperationsBlock;
+ HierarchicalCodeBlock * privOperationsBlock;
+ HierarchicalCodeBlock * protOperationsBlock;
+
+ ClassifierInfo * info;
+
+ void init ( );
+ RubyClassDeclarationBlock * getClassDecl();
+
+
+};
+
+#endif // RUBYCLASSIFIERCODEDOCUMENT_H
diff --git a/umbrello/umbrello/codegenerators/rubycodeaccessormethod.cpp b/umbrello/umbrello/codegenerators/rubycodeaccessormethod.cpp
new file mode 100644
index 00000000..a3f55c44
--- /dev/null
+++ b/umbrello/umbrello/codegenerators/rubycodeaccessormethod.cpp
@@ -0,0 +1,233 @@
+/***************************************************************************
+ rubycodeaccessormethod.cpp
+ Derived from the Java code generator by thomas
+
+ begin : Thur Jul 21 2005
+ author : Richard Dale
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * copyright (C) 2006-2007 *
+ * Umbrello UML Modeller Authors <uml-devel@uml.sf.net> *
+ ***************************************************************************/
+
+// own header
+#include "rubycodeaccessormethod.h"
+
+// qt/kde includes
+#include <qregexp.h>
+#include <kdebug.h>
+
+// local includes
+#include "../attribute.h"
+#include "../codegenerator.h"
+#include "../classifiercodedocument.h"
+#include "../umlobject.h"
+#include "../umlrole.h"
+#include "../uml.h"
+#include "codegen_utils.h"
+#include "rubyclassifiercodedocument.h"
+#include "rubycodegenerationpolicy.h"
+#include "rubycodegenerator.h"
+#include "rubycodeclassfield.h"
+#include "rubycodedocumentation.h"
+
+// Constructors/Destructors
+//
+
+RubyCodeAccessorMethod::RubyCodeAccessorMethod ( CodeClassField * field, CodeAccessorMethod::AccessorType type)
+ : CodeAccessorMethod ( field )
+{
+ setType(type);
+
+ // lets use full-blown comment
+ RubyClassifierCodeDocument *rccd = dynamic_cast<RubyClassifierCodeDocument*>(field->getParentDocument());
+ setComment(new RubyCodeDocumentation(rccd));
+}
+
+RubyCodeAccessorMethod::~RubyCodeAccessorMethod ( ) { }
+
+// Other methods
+//
+
+void RubyCodeAccessorMethod::setAttributesOnNode ( QDomDocument & doc, QDomElement & blockElement)
+{
+
+ // set super-class attributes
+ CodeAccessorMethod::setAttributesOnNode(doc, blockElement);
+
+ // set local attributes now
+}
+
+void RubyCodeAccessorMethod::setAttributesFromNode( QDomElement & root)
+{
+
+ // set attributes from superclass method the XMI
+ CodeAccessorMethod::setAttributesFromNode(root);
+
+ // load local stuff
+
+}
+
+void RubyCodeAccessorMethod::updateContent( )
+{
+
+ CodeClassField * parentField = getParentClassField();
+ RubyCodeClassField * rubyfield = dynamic_cast<RubyCodeClassField*>(parentField);
+ QString fieldName = rubyfield->getFieldName();
+ QString endLine = UMLApp::app()->getCommonPolicy()->getNewLineEndingChars();
+
+ QString text = "";
+ switch(getType()) {
+ case CodeAccessorMethod::ADD:
+ {
+ int maxOccurs = rubyfield->maximumListOccurances();
+ QString fieldType = rubyfield->getTypeName();
+ QString indent = getIndentation();
+ if(maxOccurs > 0)
+ text += "if "+fieldName+".size() < "+ QString::number(maxOccurs)+' '+endLine+indent;
+ text += fieldName+".push(value)";
+ if(maxOccurs > 0)
+ {
+ text += endLine+"else"+endLine;
+ text += indent + "puts(\"ERROR: Can't add"+fieldType+" to "+fieldName+", minimum number of items reached.\")"+endLine+"end"+endLine;
+ }
+ break;
+ }
+ case CodeAccessorMethod::GET:
+// text = "return "+fieldName;
+ break;
+ case CodeAccessorMethod::LIST:
+ text = "return "+fieldName;
+ break;
+ case CodeAccessorMethod::REMOVE:
+ {
+ int minOccurs = rubyfield->minimumListOccurances();
+ RubyClassifierCodeDocument * rubydoc = dynamic_cast<RubyClassifierCodeDocument*>(rubyfield->getParentDocument());
+ QString fieldType = rubyfield->getTypeName();
+ QString indent = getIndentation();
+
+ if(minOccurs > 0)
+ text += "if "+fieldName+".size() >= "+ QString::number(minOccurs)+endLine+indent;
+ text += fieldName+".delete(value)";
+ if(minOccurs > 0)
+ {
+ text += endLine+"else"+endLine;
+ text += indent + "puts(\"ERROR: Cant remove"+fieldType+" from "+fieldName+", minimum number of items reached.\")"+endLine+"end"+endLine;
+ }
+ break;
+ }
+ case CodeAccessorMethod::SET:
+// text = fieldName+" = value";
+ break;
+ default:
+ // do nothing
+ break;
+ }
+
+ setText(text);
+
+}
+
+void RubyCodeAccessorMethod::updateMethodDeclaration()
+{
+
+ RubyCodeClassField * rubyfield = dynamic_cast<RubyCodeClassField*>(getParentClassField());
+ RubyClassifierCodeDocument * rubydoc = dynamic_cast<RubyClassifierCodeDocument*>(rubyfield->getParentDocument());
+
+ // gather defs
+ CodeGenerationPolicy *p = UMLApp::app()->getCommonPolicy();
+ CodeGenerationPolicy::ScopePolicy scopePolicy = p->getAttributeAccessorScope();
+ QString strVis = rubydoc->scopeToRubyDecl(rubyfield->getVisibility());
+ QString fieldName = RubyCodeGenerator::cppToRubyName(rubyfield->getFieldName());
+ QString fieldType = RubyCodeGenerator::cppToRubyType(rubyfield->getTypeName());
+ QString objectType = rubyfield->getListObjectType();
+ if(objectType.isEmpty())
+ objectType = fieldName;
+ QString endLine = p->getNewLineEndingChars();
+
+ QString description = getParentObject()->getDoc();
+ description.replace(QRegExp("m_[npb](?=[A-Z])"), "");
+ description.replace("m_", "");
+ description.replace(QRegExp("[\\n\\r]+[\\t ]*"), endLine);
+
+ // set scope of this accessor appropriately..if its an attribute,
+ // we need to be more sophisticated
+ if(rubyfield->parentIsAttribute())
+ switch (scopePolicy) {
+ case CodeGenerationPolicy::Public:
+ case CodeGenerationPolicy::Private:
+ case CodeGenerationPolicy::Protected:
+ strVis = rubydoc->scopeToRubyDecl((Uml::Visibility::Value) scopePolicy);
+ break;
+ default:
+ case CodeGenerationPolicy::FromParent:
+ // do nothing..already have taken parent value
+ break;
+ }
+
+ // some variables we will need to populate
+ QString headerText = "";
+ QString methodReturnType = "";
+ QString methodName = "";
+ QString methodParams = "";
+
+ switch(getType()) {
+ case CodeAccessorMethod::ADD:
+ methodName = "add" + Codegen_Utils::capitalizeFirstLetter(fieldType);
+ methodReturnType = "";
+ methodParams = objectType+" value ";
+ headerText = "Add an object of type "+objectType+" to the Array "+fieldName+endLine+description+endLine+"@return nil";
+ setStartMethodText("def "+ methodName + '(' + methodParams + ')');
+ setEndMethodText("end");
+ break;
+ case CodeAccessorMethod::GET:
+ headerText = "Get the value of " + fieldName + endLine + description;
+ setStartMethodText(QString("attr_reader :") + fieldName);
+ setEndMethodText("");
+ break;
+ case CodeAccessorMethod::LIST:
+ methodName = "get" + Codegen_Utils::capitalizeFirstLetter(fieldType)+"List";
+ methodReturnType = "";
+ headerText = "Get the list of "+fieldName+endLine+description+endLine+"_returns_ List of "+fieldName;
+ setStartMethodText("def "+ methodName + '(' + methodParams + ')');
+ setEndMethodText("end");
+ break;
+ case CodeAccessorMethod::REMOVE:
+ methodName = "remove" + Codegen_Utils::capitalizeFirstLetter(fieldType);
+ methodReturnType = "";
+ methodParams = objectType+" value ";
+ headerText = "Remove an object of type "+objectType+" from the List "+fieldName+endLine+description;
+ setStartMethodText("def "+ methodName + '(' + methodParams + ')');
+ setEndMethodText("end");
+ break;
+ case CodeAccessorMethod::SET:
+ headerText = "Set the value of " + fieldName + endLine + description;
+ setStartMethodText(QString("attr_writer :") + fieldName);
+ setEndMethodText("");
+ break;
+ default:
+ // do nothing..no idea what this is
+ kWarning()<<"Warning: can't generate RubyCodeAccessorMethod for type: "<<getType()<<endl;
+ break;
+ }
+
+ // set header once.
+ if (getComment()->getText().isEmpty())
+ getComment()->setText(headerText);
+
+}
+
+void RubyCodeAccessorMethod::update()
+{
+ updateMethodDeclaration();
+ updateContent();
+}
+
+#include "rubycodeaccessormethod.moc"
diff --git a/umbrello/umbrello/codegenerators/rubycodeaccessormethod.h b/umbrello/umbrello/codegenerators/rubycodeaccessormethod.h
new file mode 100644
index 00000000..7eb9c892
--- /dev/null
+++ b/umbrello/umbrello/codegenerators/rubycodeaccessormethod.h
@@ -0,0 +1,73 @@
+/***************************************************************************
+ rubycodeaccessormethod.cpp
+ Derived from the Java code generator by thomas
+
+ begin : Thur Jul 21 2005
+ author : Richard Dale
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the 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 code generated by:
+ * Author : thomas
+ * Date : Thu Oct 2 2003
+ */
+
+#ifndef RUBYCODEACCESSORMETHOD_H
+#define RUBYCODEACCESSORMETHOD_H
+
+#include <qstring.h>
+
+#include "../codeaccessormethod.h"
+#include "rubycodeclassfield.h"
+
+class RubyCodeAccessorMethod : public CodeAccessorMethod
+{
+ Q_OBJECT
+public:
+
+ // Constructors/Destructors
+ //
+
+ /**
+ * Constructor
+ */
+ RubyCodeAccessorMethod ( CodeClassField * field, CodeAccessorMethod::AccessorType type);
+
+ /**
+ * Empty Destructor
+ */
+ virtual ~RubyCodeAccessorMethod ( );
+
+ /**
+ * Must be called before this object is usable
+ */
+ void update();
+
+protected:
+
+ /** set attributes of the node that represents this class
+ * in the XMI document.
+ */
+ virtual void setAttributesOnNode ( QDomDocument & doc, QDomElement & blockElement);
+
+ /** set the class attributes of this object from
+ * the passed element node.
+ */
+ virtual void setAttributesFromNode ( QDomElement & element);
+
+ virtual void updateMethodDeclaration();
+ virtual void updateContent();
+
+private:
+
+};
+
+#endif // RUBYCODEACCESSORMETHOD_H
diff --git a/umbrello/umbrello/codegenerators/rubycodeclassfield.cpp b/umbrello/umbrello/codegenerators/rubycodeclassfield.cpp
new file mode 100644
index 00000000..35438abd
--- /dev/null
+++ b/umbrello/umbrello/codegenerators/rubycodeclassfield.cpp
@@ -0,0 +1,113 @@
+/***************************************************************************
+ rubycodeclassfield.cpp
+ Derived from the Java code generator by thomas
+
+ begin : Thur Jul 21 2005
+ author : Richard Dale
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * copyright (C) 2006-2007 *
+ * Umbrello UML Modeller Authors <uml-devel@uml.sf.net> *
+ ***************************************************************************/
+
+// own header
+#include "rubycodeclassfield.h"
+
+// qt/kde includes
+#include <qregexp.h>
+#include <kdebug.h>
+
+// local includes
+#include "rubycodecomment.h"
+#include "rubycodegenerator.h"
+
+#include "../attribute.h"
+#include "../umlobject.h"
+#include "../umlrole.h"
+#include "../uml.h"
+
+#include "rubyclassifiercodedocument.h"
+
+// Constructors/Destructors
+//
+
+RubyCodeClassField::RubyCodeClassField (ClassifierCodeDocument * parentDoc, UMLRole * role)
+ : CodeClassField(parentDoc, role)
+{
+
+}
+
+RubyCodeClassField::RubyCodeClassField (ClassifierCodeDocument * parentDoc, UMLAttribute * attrib)
+ : CodeClassField(parentDoc, attrib)
+{
+
+}
+
+RubyCodeClassField::~RubyCodeClassField ( ) { }
+
+//
+// Methods
+//
+
+// Other methods
+//
+
+QString RubyCodeClassField::getFieldName() {
+ if (parentIsAttribute())
+ {
+ UMLAttribute * at = (UMLAttribute*) getParentObject();
+ return cleanName(at->getName());
+ }
+ else
+ {
+ UMLRole * role = (UMLRole*) getParentObject();
+ QString roleName = role->getName();
+ if(fieldIsSingleValue()) {
+ return roleName.replace(0, 1, roleName.left(1).lower());
+ } else {
+ return roleName.lower() + "Array";
+ }
+ }
+}
+
+
+QString RubyCodeClassField::getInitialValue() {
+
+ if (parentIsAttribute())
+ {
+ UMLAttribute * at = dynamic_cast<UMLAttribute*>( getParentObject() );
+ if (at) {
+ return fixInitialStringDeclValue(at->getInitialValue(), getTypeName());
+ } else {
+ kError() << "RubyodeClassField::getInitialValue: parent object is not a UMLAttribute"
+ << endl;
+ return "";
+ }
+ return fixInitialStringDeclValue(at->getInitialValue(), getTypeName());
+ }
+ else
+ {
+ if(fieldIsSingleValue()) {
+ // FIX : IF the multiplicity is "1" then we should init a new object here, if its 0 or 1,
+ // then we can just return 'empty' string (minor problem).
+ return QString("");
+ } else {
+ return RubyCodeGenerator::getListFieldClassName()+".new()";
+ }
+ }
+
+}
+
+QString RubyCodeClassField::getTypeName ( )
+{
+ return RubyCodeGenerator::cppToRubyType(CodeClassField::getTypeName());
+}
+
+#include "rubycodeclassfield.moc"
diff --git a/umbrello/umbrello/codegenerators/rubycodeclassfield.h b/umbrello/umbrello/codegenerators/rubycodeclassfield.h
new file mode 100644
index 00000000..384f0b5d
--- /dev/null
+++ b/umbrello/umbrello/codegenerators/rubycodeclassfield.h
@@ -0,0 +1,61 @@
+/***************************************************************************
+ rubycodeclassfield.cpp
+ Derived from the Java code generator by thomas
+
+ begin : Thur Jul 21 2005
+ author : Richard Dale
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * copyright (C) 2006-2007 *
+ * Umbrello UML Modeller Authors <uml-devel@uml.sf.net> *
+ ***************************************************************************/
+
+#ifndef RUBYCODECLASSFIELD_H
+#define RUBYCODECLASSFIELD_H
+
+#include <qstring.h>
+
+#include "../codeclassfield.h"
+
+class ClassifierCodeDocument;
+
+class RubyCodeClassField : public CodeClassField
+{
+ Q_OBJECT
+public:
+
+ // Constructors/Destructors
+ //
+
+ /**
+ * Constructors
+ */
+ RubyCodeClassField (ClassifierCodeDocument * parentDoc, UMLRole * role);
+ RubyCodeClassField (ClassifierCodeDocument * parentDoc, UMLAttribute * attrib);
+
+ /**
+ * Empty Destructor
+ */
+ virtual ~RubyCodeClassField ( );
+
+ QString getFieldType();
+ QString getFieldName();
+ QString getInitialValue();
+
+ QString getTypeName ( );
+protected:
+
+private:
+
+ // void initDeclCodeBlock ();
+
+};
+
+#endif // RUBYCODECLASSFIELD_H
diff --git a/umbrello/umbrello/codegenerators/rubycodeclassfielddeclarationblock.cpp b/umbrello/umbrello/codegenerators/rubycodeclassfielddeclarationblock.cpp
new file mode 100644
index 00000000..380c05e0
--- /dev/null
+++ b/umbrello/umbrello/codegenerators/rubycodeclassfielddeclarationblock.cpp
@@ -0,0 +1,112 @@
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * copyright (C) 2006 *
+ * Umbrello UML Modeller Authors <uml-devel@uml.sf.net> *
+ ***************************************************************************/
+
+#include "rubycodeclassfielddeclarationblock.h"
+
+#include "rubycodeclassfield.h"
+#include "rubyclassifiercodedocument.h"
+#include "rubycodegenerationpolicy.h"
+#include "../classifier.h"
+#include "../umlrole.h"
+#include "../codegenerator.h"
+#include "../uml.h"
+
+// Constructors/Destructors
+//
+
+RubyCodeClassFieldDeclarationBlock::RubyCodeClassFieldDeclarationBlock ( CodeClassField * parent )
+ : CodeClassFieldDeclarationBlock ( parent )
+{
+ setOverallIndentationLevel(1);
+ updateContent();
+}
+
+RubyCodeClassFieldDeclarationBlock::~RubyCodeClassFieldDeclarationBlock ( ) { }
+
+//
+// Methods
+//
+
+
+
+// Other methods
+//
+
+/**
+ */
+void RubyCodeClassFieldDeclarationBlock::updateContent( )
+{
+
+ CodeClassField * cf = getParentClassField();
+ ClassifierCodeDocument * doc = cf->getParentDocument();
+ RubyCodeClassField * rcf = dynamic_cast<RubyCodeClassField*>(cf);
+ RubyClassifierCodeDocument* rdoc = dynamic_cast<RubyClassifierCodeDocument*>(doc);
+ CodeGenerationPolicy * p = UMLApp::app()->getCommonPolicy();
+ CodeGenerationPolicy::ScopePolicy scopePolicy = p->getAssociationFieldScope();
+
+ // Set the comment
+ QString notes = getParentObject()->getDoc();
+ getComment()->setText(notes);
+
+ // Set the body
+ QString staticValue = getParentObject()->getStatic() ? "static " : "";
+ QString scopeStr = rdoc->scopeToRubyDecl(getParentObject()->getVisibility());
+
+ // IF this is from an association, then scope taken as appropriate to policy
+ if(!rcf->parentIsAttribute())
+ {
+ switch (scopePolicy) {
+ case CodeGenerationPolicy::Public:
+ case CodeGenerationPolicy::Private:
+ case CodeGenerationPolicy::Protected:
+ scopeStr = rdoc->scopeToRubyDecl((Uml::Visibility::Value) scopePolicy);
+ break;
+ default:
+ case CodeGenerationPolicy::FromParent:
+ // do nothing here... will leave as from parent object
+ break;
+ }
+ }
+
+ QString typeName = rcf->getTypeName();
+ QString fieldName = rcf->getFieldName();
+ QString initialV = rcf->getInitialValue();
+
+ if (!cf->parentIsAttribute() && !cf->fieldIsSingleValue())
+ typeName = "Array";
+
+ QString body = staticValue+scopeStr+' '+typeName+' '+fieldName;
+ if (!initialV.isEmpty())
+ body.append(" = " + initialV);
+ else if (!cf->parentIsAttribute())
+ {
+ UMLRole * role = dynamic_cast<UMLRole*>(cf->getParentObject());
+ if (role->getObject()->getBaseType() == Uml::ot_Interface)
+ {
+ // do nothing.. can't instanciate an interface
+ } else {
+
+ // FIX?: IF a constructor method exists in the classifiercodedoc
+ // of the parent Object, then we can use that instead (if its empty).
+ if(cf->fieldIsSingleValue())
+ {
+ if(!typeName.isEmpty())
+ body.append(" = " + typeName + ".new()");
+ } else
+ body.append(" = []");
+ }
+ }
+
+ setText(body);
+
+}
+
+#include "rubycodeclassfielddeclarationblock.moc"
diff --git a/umbrello/umbrello/codegenerators/rubycodeclassfielddeclarationblock.h b/umbrello/umbrello/codegenerators/rubycodeclassfielddeclarationblock.h
new file mode 100644
index 00000000..c3e18a68
--- /dev/null
+++ b/umbrello/umbrello/codegenerators/rubycodeclassfielddeclarationblock.h
@@ -0,0 +1,55 @@
+/***************************************************************************
+ rubycodeclassfielddeclarationblock.cpp
+ Derived from the Java code generator by thomas
+
+ begin : Thur Jul 21 2005
+ author : Richard Dale
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * copyright (C) 2006-2007 *
+ * Umbrello UML Modeller Authors <uml-devel@uml.sf.net> *
+ ***************************************************************************/
+
+#ifndef RUBYCODECLASSFIELDDECLARATIONBLOCK_H
+#define RUBYCODECLASSFIELDDECLARATIONBLOCK_H
+
+#include <qstring.h>
+
+#include "../codeclassfielddeclarationblock.h"
+
+class RubyCodeClassFieldDeclarationBlock : public CodeClassFieldDeclarationBlock
+{
+ Q_OBJECT
+public:
+
+ // Constructors/Destructors
+ //
+
+ /**
+ * Constructor
+ */
+ RubyCodeClassFieldDeclarationBlock ( CodeClassField * parent );
+
+ /**
+ * Empty Destructor
+ */
+ virtual ~RubyCodeClassFieldDeclarationBlock ( );
+
+protected:
+
+ // this will be called by syncToParent whenever the parent object is "modified"
+ void updateContent ( );
+
+private:
+
+
+};
+
+#endif // RUBYCODECLASSFIELDDECLARATIONBLOCK_H
diff --git a/umbrello/umbrello/codegenerators/rubycodecomment.cpp b/umbrello/umbrello/codegenerators/rubycodecomment.cpp
new file mode 100644
index 00000000..46374128
--- /dev/null
+++ b/umbrello/umbrello/codegenerators/rubycodecomment.cpp
@@ -0,0 +1,85 @@
+/***************************************************************************
+ rubycodecomment.cpp
+ Derived from the Java code generator by thomas
+
+ begin : Thur Jul 21 2005
+ author : Richard Dale
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * copyright (C) 2006-2007 *
+ * Umbrello UML Modeller Authors <uml-devel@uml.sf.net> *
+ ***************************************************************************/
+
+#include "rubycodecomment.h"
+#include <qregexp.h>
+
+// Constructors/Destructors
+//
+
+RubyCodeComment::RubyCodeComment(CodeDocument * doc, const QString & text)
+ : CodeComment(doc, text)
+{
+
+}
+
+RubyCodeComment::~RubyCodeComment( ) { }
+
+//
+// Methods
+//
+
+
+// Accessor methods
+//
+
+
+// Public attribute accessor methods
+//
+
+// Other methods
+//
+
+QString RubyCodeComment::getNewEditorLine( int amount ) {
+ QString line = getIndentationString(amount) + "# ";
+ return line;
+}
+
+/** UnFormat a long text string. Typically, this means removing
+ * the indentaion (linePrefix) and/or newline chars from each line.
+ */
+QString RubyCodeComment::unformatText(const QString & text, const QString & indent)
+{
+ // remove leading or trailing comment stuff
+ QString mytext = TextBlock::unformatText(text, indent);
+
+ // now leading hash
+ mytext.remove(QRegExp("^#\\s*"));
+ return mytext;
+}
+
+/**
+ * @return QString
+ */
+QString RubyCodeComment::toString( )
+{
+ QString output = "";
+
+ // simple output method
+ if (getWriteOutText()) {
+ QString indent = getIndentationString();
+ QString endLine = getNewLineEndingChars();
+ output.append(formatMultiLineText(getText(), indent + "# ", endLine + endLine));
+ }
+
+ return output;
+}
+
+
+#include "rubycodecomment.moc"
diff --git a/umbrello/umbrello/codegenerators/rubycodecomment.h b/umbrello/umbrello/codegenerators/rubycodecomment.h
new file mode 100644
index 00000000..35fb87a8
--- /dev/null
+++ b/umbrello/umbrello/codegenerators/rubycodecomment.h
@@ -0,0 +1,69 @@
+/***************************************************************************
+ rubycodecomment.h
+ Derived from the Java code generator by thomas
+
+ begin : Thur Jul 21 2005
+ author : Richard Dale
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * copyright (C) 2006-2007 *
+ * Umbrello UML Modeller Authors <uml-devel@uml.sf.net> *
+ ***************************************************************************/
+
+#ifndef RUBYCODECOMMENT_H
+#define RUBYCODECOMMENT_H
+
+#include <qstring.h>
+#include "../codecomment.h"
+
+/**
+ * class RubyCodeComment
+ * A Ruby code comment. There are two styles of comments:
+ * these are simply started with a hash and no terminating
+ * characters, or delimited by '=begin' and '=end' tags at the
+ * start of lines
+ */
+
+class RubyCodeComment : virtual public CodeComment
+{
+ Q_OBJECT
+public:
+ /**
+ * Constructors
+ */
+ explicit RubyCodeComment ( CodeDocument * doc, const QString & text = "");
+
+ /**
+ * Empty Destructor
+ */
+ virtual ~RubyCodeComment ( );
+
+ /**
+ * @return QString
+ */
+ QString toString ( );
+
+ /** UnFormat a long text string. Typically, this means removing
+ * the indentaion (linePrefix) and/or newline chars from each line.
+ */
+ virtual QString unformatText ( const QString & text, const QString & indent = "" );
+
+ /** a special version here because we want to not only indent
+ * the new line, but to add the "#" as well.
+ */
+ virtual QString getNewEditorLine ( int amount );
+
+protected:
+
+private:
+
+};
+
+#endif // RUBYCODECOMMENT_H
diff --git a/umbrello/umbrello/codegenerators/rubycodedocumentation.cpp b/umbrello/umbrello/codegenerators/rubycodedocumentation.cpp
new file mode 100644
index 00000000..6c69530a
--- /dev/null
+++ b/umbrello/umbrello/codegenerators/rubycodedocumentation.cpp
@@ -0,0 +1,145 @@
+/***************************************************************************
+ rubycodedocumentation.cpp
+ Derived from the Java code generator by thomas
+
+ begin : Thur Jul 21 2005
+ author : Richard Dale
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * copyright (C) 2006-2007 *
+ * Umbrello UML Modeller Authors <uml-devel@uml.sf.net> *
+ ***************************************************************************/
+
+// own header
+#include "rubycodedocumentation.h"
+
+// qt/kde includes
+#include <qregexp.h>
+#include <kdebug.h>
+
+// local includes
+#include "rubyclassifiercodedocument.h"
+#include "rubycodegenerationpolicy.h"
+#include "../uml.h"
+
+// Constructors/Destructors
+//
+
+RubyCodeDocumentation::RubyCodeDocumentation ( RubyClassifierCodeDocument * doc, const QString & text )
+ : CodeComment ((CodeDocument*) doc, text)
+{
+
+}
+
+RubyCodeDocumentation::~RubyCodeDocumentation ( ) { }
+
+//
+// Methods
+//
+
+
+// Accessor methods
+//
+
+// Other methods
+//
+
+/**
+ * Save the XMI representation of this object
+ */
+void RubyCodeDocumentation::saveToXMI ( QDomDocument & doc, QDomElement & root ) {
+ QDomElement blockElement = doc.createElement( "rubycodedocumentation" );
+ setAttributesOnNode(doc, blockElement); // as we added no additional fields to this class we may
+ // just use parent TextBlock method
+ root.appendChild( blockElement );
+}
+
+/**
+ * @return QString
+ */
+QString RubyCodeDocumentation::toString ( )
+{
+
+ QString output = "";
+
+ // simple output method
+ if(getWriteOutText())
+ {
+ bool useHashOutput = true;
+
+ // need to figure out output type from ruby policy
+ CodeGenerationPolicy *p = UMLApp::app()->getCommonPolicy();
+ if(p->getCommentStyle() == CodeGenerationPolicy::MultiLine)
+ useHashOutput = false;
+
+ QString indent = getIndentationString();
+ QString endLine = getNewLineEndingChars();
+ QString body = getText();
+ if( useHashOutput)
+ {
+ if(!body.isEmpty())
+ output.append(formatMultiLineText (body, indent +"# ", endLine));
+ } else {
+ output.append("=begin rdoc"+endLine);
+ output.append(formatMultiLineText (body, indent +' ', endLine));
+ output.append("=end"+endLine);
+ }
+ }
+
+ return output;
+}
+
+QString RubyCodeDocumentation::getNewEditorLine ( int amount )
+{
+ CodeGenerationPolicy *p = UMLApp::app()->getCommonPolicy();
+ if(p->getCommentStyle() == CodeGenerationPolicy::MultiLine)
+ return getIndentationString(amount) + ' ';
+ else
+ return getIndentationString(amount) + "# ";
+}
+
+int RubyCodeDocumentation::firstEditableLine() {
+ CodeGenerationPolicy *p = UMLApp::app()->getCommonPolicy();
+ if(p->getCommentStyle() == CodeGenerationPolicy::MultiLine)
+ return 1;
+ return 0;
+}
+
+int RubyCodeDocumentation::lastEditableLine() {
+ CodeGenerationPolicy *p = UMLApp::app()->getCommonPolicy();
+ if(p->getCommentStyle() == CodeGenerationPolicy::MultiLine)
+ {
+ return -1; // very last line is NOT editable
+ }
+ return 0;
+}
+
+/** UnFormat a long text string. Typically, this means removing
+ * the indentaion (linePrefix) and/or newline chars from each line.
+ */
+QString RubyCodeDocumentation::unformatText ( const QString & text , const QString & indent)
+{
+
+ QString mytext = TextBlock::unformatText(text, indent);
+ CodeGenerationPolicy *p = UMLApp::app()->getCommonPolicy();
+ // remove leading or trailing comment stuff
+ mytext.remove(QRegExp('^'+indent));
+ if(p->getCommentStyle() == CodeGenerationPolicy::MultiLine)
+ {
+ mytext.remove(QRegExp("^=begin\\s*(rdoc)?\\s*\n?"));
+ mytext.remove(QRegExp("^=end\\s*\n?$"));
+ } else
+ mytext.remove(QRegExp("^#\\s*"));
+
+ return mytext;
+}
+
+
+#include "rubycodedocumentation.moc"
diff --git a/umbrello/umbrello/codegenerators/rubycodedocumentation.h b/umbrello/umbrello/codegenerators/rubycodedocumentation.h
new file mode 100644
index 00000000..72908f78
--- /dev/null
+++ b/umbrello/umbrello/codegenerators/rubycodedocumentation.h
@@ -0,0 +1,97 @@
+/***************************************************************************
+ rubycodedocumentation.h
+ Derived from the Java code generator by thomas
+
+ begin : Thur Jul 21 2005
+ author : Richard Dale
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * copyright (C) 2006-2007 *
+ * Umbrello UML Modeller Authors <uml-devel@uml.sf.net> *
+ ***************************************************************************/
+
+#ifndef RUBYCODEDOCUMENTATION_H
+#define RUBYCODEDOCUMENTATION_H
+
+#include <qstring.h>
+#include "../codecomment.h"
+
+class RubyClassifierCodeDocument;
+
+/**
+ * class RubyCodeDocumentation
+ * A Ruby code comment. There is only a single styles of comments:
+ * these are simply started with a hash and no terminating
+ * characters
+ */
+
+class RubyCodeDocumentation : virtual public CodeComment
+{
+ Q_OBJECT
+public:
+
+ // Constructors/Destructors
+ //
+
+
+ /**
+ * Constructors
+ */
+ explicit RubyCodeDocumentation ( RubyClassifierCodeDocument * doc, const QString & text = "");
+
+ /**
+ * Empty Destructor
+ */
+ virtual ~RubyCodeDocumentation ( );
+
+ // Public attributes
+ //
+
+ // Other
+ //
+
+ /**
+ * Save the XMI representation of this object
+ */
+ virtual void saveToXMI ( QDomDocument & doc, QDomElement & root );
+
+ /**
+ * @return QString
+ */
+ QString toString ( );
+
+ /** UnFormat a long text string. Typically, this means removing
+ * the indentaion (linePrefix) and/or newline chars from each line.
+ */
+ virtual QString unformatText ( const QString & text, const QString & indent = "" );
+
+ /** a special version here because we want to not only indent
+ * the new line, but to add the "# " sequence as well.
+ */
+ virtual QString getNewEditorLine ( int amount );
+
+ /** Ush. These are terrifically bad and must one day go away.
+ * Both methods indicate the range of lines in this textblock
+ * which may be edited by the codeeditor (assuming that any are
+ * actually editable). The default case is no lines are editable.
+ * The line numbering starts with '0' and a '-1' means no line
+ * qualifies.
+ */
+ virtual int firstEditableLine();
+ virtual int lastEditableLine();
+
+
+protected:
+
+private:
+
+};
+
+#endif // RUBYCODEDOCUMENTATION_H
diff --git a/umbrello/umbrello/codegenerators/rubycodegenerationformbase.ui b/umbrello/umbrello/codegenerators/rubycodegenerationformbase.ui
new file mode 100644
index 00000000..14bcf0f2
--- /dev/null
+++ b/umbrello/umbrello/codegenerators/rubycodegenerationformbase.ui
@@ -0,0 +1,248 @@
+<!DOCTYPE UI><UI version="3.2" stdsetdef="1">
+<class>RubyCodeGenerationFormBase</class>
+<widget class="QWidget">
+ <property name="name">
+ <cstring>Form1</cstring>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>462</width>
+ <height>376</height>
+ </rect>
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLayoutWidget" row="0" column="0">
+ <property name="name">
+ <cstring>layout6</cstring>
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QGroupBox" row="2" column="0">
+ <property name="name">
+ <cstring>groupBox2</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>5</hsizetype>
+ <vsizetype>4</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="title">
+ <string>Auto-Generate Methods</string>
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLayoutWidget" row="0" column="0">
+ <property name="name">
+ <cstring>layout2</cstring>
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QCheckBox" row="0" column="0">
+ <property name="name">
+ <cstring>m_generateConstructors</cstring>
+ </property>
+ <property name="text">
+ <string>Empty constructor methods</string>
+ </property>
+ <property name="checked">
+ <bool>false</bool>
+ </property>
+ </widget>
+ <widget class="QCheckBox" row="2" column="0">
+ <property name="name">
+ <cstring>m_generateAssocAccessors</cstring>
+ </property>
+ <property name="text">
+ <string>Association accessor methods</string>
+ </property>
+ <property name="checked">
+ <bool>true</bool>
+ </property>
+ </widget>
+ <widget class="QCheckBox" row="1" column="0">
+ <property name="name">
+ <cstring>m_generateAttribAccessors</cstring>
+ </property>
+ <property name="text">
+ <string>Attribute accessor methods</string>
+ </property>
+ <property name="checked">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </grid>
+ </widget>
+ <widget class="QLayoutWidget" row="1" column="0">
+ <property name="name">
+ <cstring>layout4</cstring>
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QComboBox" row="0" column="1">
+ <item>
+ <property name="text">
+ <string>Public</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>Private</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>Protected</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>From Parent Object</string>
+ </property>
+ </item>
+ <property name="name">
+ <cstring>m_accessorScopeCB</cstring>
+ </property>
+ <property name="currentItem">
+ <number>3</number>
+ </property>
+ </widget>
+ <widget class="QLabel" row="0" column="0">
+ <property name="name">
+ <cstring>textLabel1_3</cstring>
+ </property>
+ <property name="text">
+ <string>Default attribute accessor scope:</string>
+ </property>
+ </widget>
+ </grid>
+ </widget>
+ <widget class="QLayoutWidget" row="2" column="0">
+ <property name="name">
+ <cstring>layout4</cstring>
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLabel" row="0" column="0">
+ <property name="name">
+ <cstring>textLabel1_3_2</cstring>
+ </property>
+ <property name="text">
+ <string>Default association field scope:</string>
+ </property>
+ </widget>
+ <widget class="QComboBox" row="0" column="1">
+ <item>
+ <property name="text">
+ <string>Public</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>Private</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>Protected</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>From Parent Role</string>
+ </property>
+ </item>
+ <property name="name">
+ <cstring>m_assocFieldScopeCB</cstring>
+ </property>
+ <property name="currentItem">
+ <number>3</number>
+ </property>
+ </widget>
+ </grid>
+ </widget>
+ </grid>
+ </widget>
+ <widget class="QGroupBox" row="1" column="0">
+ <property name="name">
+ <cstring>groupBox1</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>5</hsizetype>
+ <vsizetype>4</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="title">
+ <string>Documentation</string>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>textLabel1</cstring>
+ </property>
+ <property name="text">
+ <string>Style:</string>
+ </property>
+ </widget>
+ <widget class="QComboBox">
+ <item>
+ <property name="text">
+ <string>Hash (#)</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>Begin-End (=begin =end)</string>
+ </property>
+ </item>
+ <property name="name">
+ <cstring>m_SelectCommentStyle</cstring>
+ </property>
+ </widget>
+ </hbox>
+ </widget>
+ <widget class="QLabel" row="0" column="0">
+ <property name="name">
+ <cstring>textLabel1_2</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>5</hsizetype>
+ <vsizetype>4</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="text">
+ <string>&lt;p align="center"&gt;Ruby Code Generation&lt;/p&gt;</string>
+ </property>
+ </widget>
+ </grid>
+ </widget>
+ </grid>
+</widget>
+<layoutdefaults spacing="6" margin="11"/>
+</UI>
diff --git a/umbrello/umbrello/codegenerators/rubycodegenerationpolicy.cpp b/umbrello/umbrello/codegenerators/rubycodegenerationpolicy.cpp
new file mode 100644
index 00000000..1a01421a
--- /dev/null
+++ b/umbrello/umbrello/codegenerators/rubycodegenerationpolicy.cpp
@@ -0,0 +1,170 @@
+/***************************************************************************
+ rubycodegenerationpolicy.cpp
+ Derived from the Java code generator by thomas
+
+ begin : Thur Jul 21 2005
+ author : Richard Dale
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * copyright (C) 2006-2007 *
+ * Umbrello UML Modeller Authors <uml-devel@uml.sf.net> *
+ ***************************************************************************/
+
+// own header
+#include "rubycodegenerationpolicy.h"
+// qt/kde includes
+#include <kconfig.h>
+// app includes
+#include "rubycodegenerationpolicypage.h"
+#include "rubycodegenerator.h"
+#include "../uml.h"
+
+const bool RubyCodeGenerationPolicy::DEFAULT_AUTO_GEN_ATTRIB_ACCESSORS = true;
+const bool RubyCodeGenerationPolicy::DEFAULT_AUTO_GEN_ASSOC_ACCESSORS = true;
+
+// Constructors/Destructors
+//
+
+RubyCodeGenerationPolicy::RubyCodeGenerationPolicy(KConfig *config)
+{
+ init();
+ setDefaults(config,false);
+}
+
+RubyCodeGenerationPolicy::~RubyCodeGenerationPolicy ( ) { }
+
+//
+// Methods
+//
+
+// Accessor methods
+//
+
+// Public attribute accessor methods
+//
+
+/**
+ * Set the value of m_autoGenerateAttribAccessors
+ * @param new_var the new value
+ */
+void RubyCodeGenerationPolicy::setAutoGenerateAttribAccessors( bool var ) {
+ m_autoGenerateAttribAccessors = var;
+ m_commonPolicy->emitModifiedCodeContentSig();
+}
+
+/**
+ * Set the value of m_autoGenerateAssocAccessors
+ * @param new_var the new value
+ */
+void RubyCodeGenerationPolicy::setAutoGenerateAssocAccessors( bool var ) {
+ m_autoGenerateAssocAccessors = var;
+ m_commonPolicy->emitModifiedCodeContentSig();
+}
+
+/**
+ * Get the value of m_autoGenerateAttribAccessors
+ * @return the value of m_autoGenerateAttribAccessors
+ */
+bool RubyCodeGenerationPolicy::getAutoGenerateAttribAccessors( ){
+ return m_autoGenerateAttribAccessors;
+}
+
+/**
+ * Get the value of m_autoGenerateAssocAccessors
+ * @return the value of m_autoGenerateAssocAccessors
+ */
+bool RubyCodeGenerationPolicy::getAutoGenerateAssocAccessors( ){
+ return m_autoGenerateAssocAccessors;
+}
+
+// Other methods
+//
+
+void RubyCodeGenerationPolicy::writeConfig ( KConfig * config )
+{
+ // @todo do we need to call CodeGenerationPolicy::writeConfig ???
+
+ // write ONLY the Ruby specific stuff
+ config->setGroup("Ruby Code Generation");
+
+ config->writeEntry("autoGenAccessors",getAutoGenerateAttribAccessors());
+ config->writeEntry("autoGenAssocAccessors",getAutoGenerateAssocAccessors());
+}
+
+void RubyCodeGenerationPolicy::setDefaults ( CodeGenPolicyExt * clone, bool emitUpdateSignal )
+{
+
+ RubyCodeGenerationPolicy * rclone;
+ if (!clone)
+ return;
+
+ // NOW block signals for ruby param setting
+ blockSignals(true); // we need to do this because otherwise most of these
+ // settors below will each send the modifiedCodeContent() signal
+ // needlessly (we can just make one call at the end).
+
+
+ // now do ruby-specific stuff IF our clone is also a RubyCodeGenerationPolicy object
+ if((rclone = dynamic_cast<RubyCodeGenerationPolicy*>(clone)))
+ {
+ setAutoGenerateAttribAccessors(rclone->getAutoGenerateAttribAccessors());
+ setAutoGenerateAssocAccessors(rclone->getAutoGenerateAssocAccessors());
+ }
+
+ blockSignals(false); // "as you were citizen"
+
+ if(emitUpdateSignal)
+ m_commonPolicy->emitModifiedCodeContentSig();
+
+}
+
+void RubyCodeGenerationPolicy::setDefaults( KConfig * config, bool emitUpdateSignal )
+{
+
+ if(!config)
+ return;
+
+ // call the superclass to init default stuff
+ m_commonPolicy->setDefaults(config, false);
+
+ // NOW block signals (because call to super-class method will leave value at "true")
+ blockSignals(true); // we need to do this because otherwise most of these
+ // settors below will each send the modifiedCodeContent() signal
+ // needlessly (we can just make one call at the end).
+
+ // now do ruby specific stuff
+ config -> setGroup("Ruby Code Generation");
+
+ setAutoGenerateAttribAccessors(config->readBoolEntry("autoGenAccessors",DEFAULT_AUTO_GEN_ATTRIB_ACCESSORS));
+ setAutoGenerateAssocAccessors(config->readBoolEntry("autoGenAssocAccessors",DEFAULT_AUTO_GEN_ASSOC_ACCESSORS));
+
+ blockSignals(false); // "as you were citizen"
+
+ if(emitUpdateSignal)
+ m_commonPolicy->emitModifiedCodeContentSig();
+}
+
+
+/**
+ * Create a new dialog interface for this object.
+ * @return dialog object
+ */
+CodeGenerationPolicyPage * RubyCodeGenerationPolicy::createPage ( QWidget *parent, const char *name ) {
+ return new RubyCodeGenerationPolicyPage ( parent, name, this );
+}
+
+void RubyCodeGenerationPolicy::init() {
+ m_commonPolicy = UMLApp::app()->getCommonPolicy();
+ m_autoGenerateAttribAccessors = DEFAULT_AUTO_GEN_ATTRIB_ACCESSORS;
+ m_autoGenerateAssocAccessors = DEFAULT_AUTO_GEN_ASSOC_ACCESSORS;
+}
+
+
+#include "rubycodegenerationpolicy.moc"
diff --git a/umbrello/umbrello/codegenerators/rubycodegenerationpolicy.h b/umbrello/umbrello/codegenerators/rubycodegenerationpolicy.h
new file mode 100644
index 00000000..aa1a7146
--- /dev/null
+++ b/umbrello/umbrello/codegenerators/rubycodegenerationpolicy.h
@@ -0,0 +1,117 @@
+/***************************************************************************
+ rubycodegenerationpolicy.cpp
+ Derived from the Java code generator by thomas
+
+ begin : Thur Jul 21 2005
+ author : Richard Dale
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * copyright (C) 2005-2006 *
+ * Umbrello UML Modeller Authors <uml-devel@uml.sf.net> *
+ ***************************************************************************/
+
+#ifndef RUBYCODEGENERATIONPOLICY_H
+#define RUBYCODEGENERATIONPOLICY_H
+
+#include <qstring.h>
+#include "codegenpolicyext.h"
+#include "../codegenerationpolicy.h"
+
+class KConfig;
+class CodeGenerationPolicyPage;
+
+class RubyCodeGenerationPolicy : public CodeGenPolicyExt
+{
+ Q_OBJECT
+public:
+
+ static const bool DEFAULT_AUTO_GEN_ATTRIB_ACCESSORS;
+ static const bool DEFAULT_AUTO_GEN_ASSOC_ACCESSORS;
+
+ // Constructors/Destructors
+ //
+
+ /**
+ * Constructors
+ */
+ RubyCodeGenerationPolicy (KConfig * config = 0);
+
+ /**
+ * Empty Destructor
+ */
+ virtual ~RubyCodeGenerationPolicy ( );
+
+ // Public attributes
+ //
+
+
+ // Public attribute accessor methods
+ //
+
+ /**
+ * Set the value of m_autoGenerateAttribAccessors
+ * @param var the new value
+ */
+ void setAutoGenerateAttribAccessors ( bool var );
+
+ /**
+ * Get the value of m_autoGenerateAttribAccessors
+ * @return value the boolean value of m_autoGenerateAttribAccessors
+ */
+ bool getAutoGenerateAttribAccessors( );
+
+ /**
+ * Set the value of m_autoGenerateAssocAccessors
+ * @param var the new value
+ */
+ void setAutoGenerateAssocAccessors ( bool var );
+
+ /**
+ * Get the value of m_autoGenerateAssocAccessors
+ * @return value the boolean value of m_autoGenerateAssocAccessors
+ */
+ bool getAutoGenerateAssocAccessors( );
+
+ /**
+ * set the defaults for this code generator from the passed generator.
+ */
+ virtual void setDefaults (CodeGenPolicyExt * defaults, bool emitUpdateSignal = true);
+
+ /**
+ * set the defaults from a config file for this code generator from the passed KConfig pointer.
+ */
+ virtual void setDefaults(KConfig * config, bool emitUpdateSignal = true);
+
+ /**
+ * write Default params to passed KConfig pointer.
+ */
+ virtual void writeConfig (KConfig * config);
+
+ /**
+ * Create a new dialog interface for this object.
+ * @return dialog object
+ */
+ CodeGenerationPolicyPage * createPage ( QWidget *parent = 0, const char * name = 0);
+
+protected:
+
+ /**
+ */
+ void init ( );
+
+private:
+
+ CodeGenerationPolicy *m_commonPolicy;
+ bool m_autoGenerateAttribAccessors;
+ bool m_autoGenerateAssocAccessors;
+
+};
+
+#endif // RUBYCODEGENERATIONPOLICY_H
diff --git a/umbrello/umbrello/codegenerators/rubycodegenerationpolicypage.cpp b/umbrello/umbrello/codegenerators/rubycodegenerationpolicypage.cpp
new file mode 100644
index 00000000..1e9080c9
--- /dev/null
+++ b/umbrello/umbrello/codegenerators/rubycodegenerationpolicypage.cpp
@@ -0,0 +1,75 @@
+/***************************************************************************
+ rubycodegenerationpolicypage.cpp
+ Derived from the Java code generator by thomas
+
+ begin : Thur Jul 21 2005
+ author : Richard Dale
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * copyright (C) 2006-2007 *
+ * Umbrello UML Modeller Authors <uml-devel@uml.sf.net> *
+ ***************************************************************************/
+
+// own header
+#include "rubycodegenerationpolicypage.h"
+// qt/kde includes
+#include <qlabel.h>
+#include <qcombobox.h>
+#include <qcheckbox.h>
+#include <kdebug.h>
+#include <klocale.h>
+// app includes
+#include "rubycodegenerationformbase.h"
+#include "../codegenerationpolicy.h"
+#include "../uml.h"
+
+RubyCodeGenerationPolicyPage::RubyCodeGenerationPolicyPage( QWidget *parent, const char *name, RubyCodeGenerationPolicy * policy )
+ : CodeGenerationPolicyPage(parent, name, policy)
+{
+ CodeGenerationPolicy *common = UMLApp::app()->getCommonPolicy();
+ form = new RubyCodeGenerationFormBase(this);
+ form->m_SelectCommentStyle->setCurrentItem((int)(common->getCommentStyle()));
+ form->m_generateConstructors->setChecked(common->getAutoGenerateConstructors());
+ form->m_generateAttribAccessors->setChecked(policy->getAutoGenerateAttribAccessors());
+ form->m_generateAssocAccessors->setChecked(policy->getAutoGenerateAssocAccessors());
+ form->m_accessorScopeCB->setCurrentItem((common->getAttributeAccessorScope() - 200));
+ form->m_assocFieldScopeCB->setCurrentItem((common->getAssociationFieldScope() - 200));
+}
+
+RubyCodeGenerationPolicyPage::~RubyCodeGenerationPolicyPage()
+{
+}
+
+void RubyCodeGenerationPolicyPage::apply()
+{
+ CodeGenerationPolicy *common = UMLApp::app()->getCommonPolicy();
+
+ // now do our ruby-specific configs
+ RubyCodeGenerationPolicy * parent = (RubyCodeGenerationPolicy*) m_parentPolicy;
+
+ // block signals so we don't cause too many update content calls to code documents
+ parent->blockSignals(true);
+
+ common->setCommentStyle((CodeGenerationPolicy::CommentStyle) form->m_SelectCommentStyle->currentItem());
+ common->setAttributeAccessorScope((CodeGenerationPolicy::ScopePolicy) (form->m_accessorScopeCB->currentItem()+200));
+ common->setAssociationFieldScope((CodeGenerationPolicy::ScopePolicy) (form->m_assocFieldScopeCB->currentItem()+200));
+ common->setAutoGenerateConstructors(form->m_generateConstructors->isChecked());
+ parent->setAutoGenerateAttribAccessors(form->m_generateAttribAccessors->isChecked());
+ parent->setAutoGenerateAssocAccessors(form->m_generateAssocAccessors->isChecked());
+
+ parent->blockSignals(false);
+
+ // now send out modified code content signal
+ common->emitModifiedCodeContentSig();
+
+}
+
+
+#include "rubycodegenerationpolicypage.moc"
diff --git a/umbrello/umbrello/codegenerators/rubycodegenerationpolicypage.h b/umbrello/umbrello/codegenerators/rubycodegenerationpolicypage.h
new file mode 100644
index 00000000..6fc06aed
--- /dev/null
+++ b/umbrello/umbrello/codegenerators/rubycodegenerationpolicypage.h
@@ -0,0 +1,51 @@
+/***************************************************************************
+ rubycodegenerationpolicypage.h
+ Derived from the Java code generator by thomas
+
+ begin : Thur Jul 21 2005
+ author : Richard Dale
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * copyright (C) 2005-2006 *
+ * Umbrello UML Modeller Authors <uml-devel@uml.sf.net> *
+ ***************************************************************************/
+
+#ifndef RUBYCODEGENERATIONPOLICYPAGE_H
+#define RUBYCODEGENERATIONPOLICYPAGE_H
+
+#include "../dialogs/codegenerationpolicypage.h"
+#include "rubycodegenerationformbase.h"
+
+#include "rubycodegenerationpolicy.h"
+
+/**
+ * @author Brian Thomas
+ */
+
+class RubyCodeGenerationPolicyPage : public CodeGenerationPolicyPage {
+ Q_OBJECT
+public:
+
+ explicit RubyCodeGenerationPolicyPage (QWidget *parent=0, const char *name=0, RubyCodeGenerationPolicy * policy = 0);
+
+ virtual ~RubyCodeGenerationPolicyPage();
+
+protected:
+
+ RubyCodeGenerationFormBase * form;
+
+public slots:
+
+ void apply();
+
+};
+
+#endif
+
diff --git a/umbrello/umbrello/codegenerators/rubycodegenerator.cpp b/umbrello/umbrello/codegenerators/rubycodegenerator.cpp
new file mode 100644
index 00000000..3e20ce50
--- /dev/null
+++ b/umbrello/umbrello/codegenerators/rubycodegenerator.cpp
@@ -0,0 +1,186 @@
+/***************************************************************************
+ rubycodegenerator.cpp
+ Derived from the Java code generator by thomas
+
+ begin : Thur Jul 21 2005
+ author : Richard Dale
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * copyright (C) 2006-2007 *
+ * Umbrello UML Modeller Authors <uml-devel@uml.sf.net> *
+ ***************************************************************************/
+
+// own header
+#include "rubycodegenerator.h"
+
+// qt/kde includes
+#include <qregexp.h>
+#include <kconfig.h>
+#include <kdebug.h>
+#include <klocale.h>
+#include <kmessagebox.h>
+
+// local includes
+#include "rubycodecomment.h"
+#include "codeviewerdialog.h"
+#include "../uml.h"
+
+// Constructors/Destructors
+//
+
+RubyCodeGenerator::RubyCodeGenerator (QDomElement & elem )
+ : CodeGenerator(elem)
+{
+}
+
+RubyCodeGenerator::RubyCodeGenerator ()
+{
+}
+
+RubyCodeGenerator::~RubyCodeGenerator ( ) { }
+
+//
+// Methods
+//
+
+// Accessor methods
+//
+
+// return our language
+Uml::Programming_Language RubyCodeGenerator::getLanguage() {
+ return Uml::pl_Ruby;
+}
+
+// In the Java version, we make the ANT build file also available.
+CodeViewerDialog * RubyCodeGenerator::getCodeViewerDialog ( QWidget* parent, CodeDocument *doc,
+ Settings::CodeViewerState state)
+{
+ CodeViewerDialog *dialog = new CodeViewerDialog(parent, doc, state);
+ return dialog;
+}
+
+
+RubyCodeGenerationPolicy * RubyCodeGenerator::getRubyPolicy() {
+ return dynamic_cast<RubyCodeGenerationPolicy*>(UMLApp::app()->getPolicyExt());
+}
+
+bool RubyCodeGenerator::getAutoGenerateAttribAccessors ( )
+{
+ return getRubyPolicy()->getAutoGenerateAttribAccessors ();
+}
+
+bool RubyCodeGenerator::getAutoGenerateAssocAccessors ( )
+{
+ return getRubyPolicy()->getAutoGenerateAssocAccessors ();
+}
+
+QString RubyCodeGenerator::getListFieldClassName () {
+ return QString("Array");
+}
+
+// Other methods
+//
+
+QString RubyCodeGenerator::cppToRubyType(const QString &typeStr) {
+ QString type = cleanName(typeStr);
+ type.replace("const ", "");
+ type.replace(QRegExp("[*&\\s]"), "");
+ type.replace(QRegExp("[<>]"), "_");
+ type.replace("QStringList", "Array");
+ type.replace(QRegExp("^string$"),"String");
+ type.replace("QString", "String");
+ type.replace("bool", "true|false");
+ type.replace(QRegExp("^(uint|int|ushort|short|ulong|long)$"), "Integer");
+ type.replace(QRegExp("^(float|double)$"), "Float");
+ type.replace(QRegExp("^Q(?=[A-Z])"), "Qt::");
+ type.replace(QRegExp("^K(?!(DE|Parts|IO)"), "KDE::");
+
+ return type;
+}
+
+QString RubyCodeGenerator::cppToRubyName(const QString &nameStr) {
+ QString name = cleanName(nameStr);
+ name.replace(QRegExp("^m_"), "");
+ name.replace(QRegExp("^[pbn](?=[A-Z])"), "");
+ name = name.mid(0, 1).lower() + name.mid(1);
+ return name;
+}
+
+/**
+ * @return ClassifierCodeDocument
+ * @param classifier
+ */
+CodeDocument * RubyCodeGenerator::newClassifierCodeDocument ( UMLClassifier * c)
+{
+ RubyClassifierCodeDocument * doc = new RubyClassifierCodeDocument(c);
+ doc->initCodeClassFields();
+ return doc;
+}
+
+/* These initializations are done in CodeGenFactory::createObject()
+void RubyCodeGenerator::initFields() {
+ UMLApp::app()->setPolicyExt ( new RubyCodeGenerationPolicy(UMLApp::app()->getConfig()) );
+ // load Classifier documents from parent document
+ initFromParentDocument();
+}
+ */
+
+const QStringList RubyCodeGenerator::reservedKeywords() const {
+
+ static QStringList keywords;
+
+ if (keywords.isEmpty()) {
+ keywords << "__FILE__"
+ << "__LINE__"
+ << "BEGIN"
+ << "END"
+ << "alias"
+ << "and"
+ << "begin"
+ << "break"
+ << "case"
+ << "class"
+ << "def"
+ << "defined?"
+ << "do"
+ << "else"
+ << "elsif"
+ << "end"
+ << "ensure"
+ << "false"
+ << "for"
+ << "if"
+ << "in"
+ << "module"
+ << "next"
+ << "nil"
+ << "not"
+ << "or"
+ << "redo"
+ << "rescue"
+ << "retry"
+ << "return"
+ << "self"
+ << "super"
+ << "then"
+ << "true"
+ << "undef"
+ << "unless"
+ << "until"
+ << "when"
+ << "while"
+ << "yield";
+ }
+
+ return keywords;
+}
+
+#include "rubycodegenerator.moc"
+
diff --git a/umbrello/umbrello/codegenerators/rubycodegenerator.h b/umbrello/umbrello/codegenerators/rubycodegenerator.h
new file mode 100644
index 00000000..9cc878f0
--- /dev/null
+++ b/umbrello/umbrello/codegenerators/rubycodegenerator.h
@@ -0,0 +1,129 @@
+/***************************************************************************
+ rubycodegenerator.cpp
+ Derived from the Java code generator by thomas
+
+ begin : Thur Jul 21 2005
+ author : Richard Dale
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * copyright (C) 2006-2007 *
+ * Umbrello UML Modeller Authors <uml-devel@uml.sf.net> *
+ ***************************************************************************/
+
+#ifndef RUBYCODEGENERATOR_H
+#define RUBYCODEGENERATOR_H
+
+#include <qstring.h>
+#include "../codeviewerstate.h"
+#include "../codegenerator.h"
+#include "../codeblockwithcomments.h"
+#include "../umldoc.h"
+
+#include "classifierinfo.h"
+#include "rubyclassifiercodedocument.h"
+
+#include "rubycodegenerationpolicy.h"
+
+class CodeViewerDialog;
+
+class RubyCodeGenerator : public CodeGenerator
+{
+ Q_OBJECT
+public:
+
+ // Constructors/Destructors
+ //
+
+ /**
+ * Empty Constructor
+ */
+ RubyCodeGenerator ();
+ RubyCodeGenerator (QDomElement & element);
+
+ /**
+ * Empty Destructor
+ */
+ virtual ~RubyCodeGenerator ( );
+
+ // Public attributes
+ //
+
+
+ // Public attribute accessor methods
+ //
+
+ /**
+ * A utility method to get the rubyCodeGenerationPolicy()->getAutoGenerateAttribAccessors() value.
+ */
+ bool getAutoGenerateAttribAccessors( );
+
+ /**
+ * A utility method to get the rubyCodeGenerationPolicy()->getAutoGenerateAssocAccessors() value.
+ */
+ bool getAutoGenerateAssocAccessors( );
+
+ /**
+ * Get the list variable class name to use. For Ruby, we have set this to "Array".
+ */
+ static QString getListFieldClassName();
+
+ /** Get the editing dialog for this code document
+ */
+ virtual CodeViewerDialog * getCodeViewerDialog( QWidget* parent, CodeDocument * doc,
+ Settings::CodeViewerState state);
+
+ // Other methods
+ //
+
+ /**
+ * Utility function for getting the ruby code generation policy.
+ */
+ RubyCodeGenerationPolicy * getRubyPolicy();
+
+ /**
+ * @return ClassifierCodeDocument
+ * @param classifier
+ */
+ CodeDocument * newClassifierCodeDocument (UMLClassifier * classifier);
+
+ // return "Ruby"
+ Uml::Programming_Language getLanguage();
+
+ /**
+ * Convert a C++ type such as 'int' or 'QWidget' to
+ * ruby types Integer and Qt::Widget
+ *
+ * @param cppType the C++ type to be converted
+ */
+ static QString cppToRubyType(const QString &cppType);
+
+ /**
+ * Convert C++ names such as 'm_foobar' or pFoobar to
+ * just 'foobar' for ruby
+ *
+ * @param cppName the C++ name to be converted
+ */
+ static QString cppToRubyName(const QString &cppName);
+
+ /**
+ * get list of reserved keywords
+ */
+ virtual const QStringList reservedKeywords() const;
+
+protected:
+
+ /** create the codeblock that will represent the class declaration
+ * for this classifier
+ */
+ CodeBlockWithComments * createClassDecl ( UMLClassifier *c, ClassifierInfo *info, RubyClassifierCodeDocument * doc);
+
+};
+
+#endif // RUBYCODEGENERATOR_H
diff --git a/umbrello/umbrello/codegenerators/rubycodeoperation.cpp b/umbrello/umbrello/codegenerators/rubycodeoperation.cpp
new file mode 100644
index 00000000..6f16fb96
--- /dev/null
+++ b/umbrello/umbrello/codegenerators/rubycodeoperation.cpp
@@ -0,0 +1,226 @@
+/***************************************************************************
+ rubycodeoperation.cpp
+ Derived from the Java code generator by thomas
+
+ begin : Thur Jul 21 2005
+ author : Richard Dale
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * copyright (C) 2006-2007 *
+ * Umbrello UML Modeller Authors <uml-devel@uml.sf.net> *
+ ***************************************************************************/
+
+// own header
+#include "rubycodeoperation.h"
+
+// qt/kde includes
+#include <qregexp.h>
+
+// local includes
+#include "rubyclassifiercodedocument.h"
+#include "rubycodedocumentation.h"
+#include "rubycodegenerator.h"
+#include "../uml.h"
+
+// Constructors/Destructors
+//
+
+RubyCodeOperation::RubyCodeOperation ( RubyClassifierCodeDocument * doc, UMLOperation *parent, const QString & body, const QString & comment )
+ : CodeOperation (doc, parent, body, comment)
+{
+ // lets not go with the default comment and instead use
+ // full-blown ruby documentation object instead
+ setComment(new RubyCodeDocumentation(doc));
+
+ // these things never change..
+ setOverallIndentationLevel(1);
+
+ updateMethodDeclaration();
+ updateContent();
+
+}
+
+RubyCodeOperation::~RubyCodeOperation ( ) { }
+
+// Other methods
+//
+
+// we basically want to update the doc and start text of this method
+void RubyCodeOperation::updateMethodDeclaration()
+{
+
+ CodeDocument * doc = getParentDocument();
+ RubyClassifierCodeDocument * rubydoc = dynamic_cast<RubyClassifierCodeDocument*>(doc);
+ UMLClassifier *c = rubydoc->getParentClassifier();
+ UMLOperation * o = getParentOperation();
+ bool isInterface = rubydoc->getParentClassifier()->isInterface();
+ QString endLine = getNewLineEndingChars();
+
+ // now, the starting text.
+ QString strVis = rubydoc->scopeToRubyDecl(o->getVisibility());
+ // no return type for constructors
+ QString fixedReturn = RubyCodeGenerator::cppToRubyType(o->getTypeName());
+ QString returnType = o->isConstructorOperation() ? QString("") : (fixedReturn + QString(" "));
+ QString methodName = o->getName();
+
+ QString RubyClassName = rubydoc->getRubyClassName(c->getName());
+
+ // Skip destructors, and operator methods which
+ // can't be defined in ruby
+ if ( methodName.startsWith("~")
+ || QRegExp("operator\\s*(=|--|\\+\\+|!=)$").exactMatch(methodName) )
+ {
+ getComment()->setText("");
+ return;
+ }
+
+ if (RubyClassName == methodName) {
+ methodName = "initialize";
+ }
+
+ methodName.replace(QRegExp("operator\\s*"), "");
+ methodName = methodName.mid(0, 1).lower() + methodName.mid(1);
+
+ QString paramStr = QString("");
+ QStringList commentedParams;
+
+ // assemble parameters
+ UMLAttributeList list = getParentOperation()->getParmList();
+ int nrofParam = list.count();
+ int paramNum = 0;
+ for(UMLAttribute* parm = list.first(); parm; parm = list.next())
+ {
+ QString paramName = RubyCodeGenerator::cppToRubyName(parm->getName());
+ paramStr += paramName;
+ if (! parm->getInitialValue().isEmpty()) {
+ paramStr += QString(" = ") + RubyCodeGenerator::cppToRubyType(parm->getInitialValue());
+ }
+ paramNum++;
+
+ if (paramNum != nrofParam )
+ paramStr += ", ";
+ }
+
+ QString startText;
+ if (isInterface) {
+ // Assume 'isInterface' means a module in Ruby, so
+ // generate module methods
+ startText = "def "+ RubyClassName + '.' + methodName + '(' + paramStr +')';
+ } else {
+ startText = "def "+ methodName + '(' + paramStr +')';
+ }
+
+ startText += "";
+ setEndMethodText("end");
+
+ setStartMethodText(startText);
+
+ // Lastly, for text content generation, we fix the comment on the
+ // operation, IF the codeop is autogenerated & currently empty
+ QString comment = o->getDoc();
+
+ if (comment.isEmpty()) {
+ if (getContentType() == CodeBlock::AutoGenerated) {
+ UMLAttributeList parameters = o->getParmList();
+ for(UMLAttributeListIt iterator(parameters); iterator.current(); ++iterator) {
+ comment += endLine + "* _" + iterator.current()->getName() + "_ ";
+ comment += (' ' + iterator.current()->getDoc().replace( QRegExp("[\\n\\r]+[\\t ]*"),
+ endLine + " " ) );
+ }
+ // add a returns statement too
+ if(!returnType.isEmpty() && !QRegExp("^void\\s*$").exactMatch(returnType))
+ comment += endLine + "* _returns_ " + returnType + ' ';
+ getComment()->setText(comment);
+ }
+ } else {
+ comment.replace(QRegExp("[\\n\\r]+ *"), endLine);
+ comment.replace(QRegExp("[\\n\\r]+\\t*"), endLine);
+
+ comment.replace(" m_", " ");
+ comment.replace(QRegExp("\\s[npb](?=[A-Z])"), " ");
+ QRegExp re_params("@param (\\w)(\\w*)");
+ int pos = re_params.search(comment);
+ while (pos != -1) {
+ comment.replace( re_params.cap(0),
+ QString("@param _") + re_params.cap(1).lower() + re_params.cap(2) + '_' );
+ commentedParams.append(re_params.cap(1).lower() + re_params.cap(2));
+
+ pos += re_params.matchedLength() + 3;
+ pos = re_params.search(comment, pos);
+ }
+
+ UMLAttributeList parameters = o->getParmList();
+ for (UMLAttributeListIt iterator(parameters); iterator.current(); ++iterator) {
+ // Only write an individual @param entry if one hasn't been found already
+ // in the main doc comment
+ if (commentedParams.contains(RubyCodeGenerator::cppToRubyName(iterator.current()->getName())) == 0) {
+ comment += (endLine + "@param _" + RubyCodeGenerator::cppToRubyName(iterator.current()->getName()) + '_');
+ if (iterator.current()->getDoc().isEmpty()) {
+ comment += (' ' + RubyCodeGenerator::cppToRubyType(iterator.current()->getTypeName()));
+ } else {
+ comment += (' ' + iterator.current()->getDoc().replace(QRegExp("[\\n\\r]+[\\t ]*"), endLine + " "));
+ }
+ }
+ }
+
+ comment.replace("@ref ", "");
+ comment.replace("@param", "*");
+ comment.replace("@return", "* _returns_");
+
+ // All lines after the first one starting with '*' in the doc comment
+ // must be indented correctly. If they aren't a list
+ // item starting with '*', then indent the text with
+ // two spaces, ' ', to line up with the list item.
+ pos = comment.find(endLine + '*');
+ if (pos != -1) {
+ pos += endLine.length() + 1;
+ pos = comment.find(endLine, pos);
+ }
+
+ while (pos > 0) {
+ pos += endLine.length();
+ if (comment[pos] != '*') {
+ comment.insert(pos, " ");
+ pos += 2;
+ }
+
+ pos = comment.find(endLine, pos);
+ }
+
+ QString typeStr = RubyCodeGenerator::cppToRubyType(o->getTypeName());
+ if ( !typeStr.isEmpty()
+ && !QRegExp("^void\\s*$").exactMatch(typeStr)
+ && comment.contains("_returns_") == 0 )
+ {
+ comment += endLine + "* _returns_ " + typeStr;
+ }
+
+ getComment()->setText(comment);
+ }
+
+ // In Java, for interfaces..we DONT write out non-public
+ // method declarations. And for Ruby modules?
+ if (isInterface) {
+ UMLOperation * o = getParentOperation();
+ if(o->getVisibility() != Uml::Visibility::Public)
+ setWriteOutText(false);
+ }
+
+}
+
+int RubyCodeOperation::lastEditableLine() {
+ ClassifierCodeDocument * doc = dynamic_cast<ClassifierCodeDocument*>(getParentDocument());
+ if(doc->parentIsInterface())
+ return -1; // very last line is NOT editable as its a one-line declaration w/ no body in
+ // an interface.
+ return 0;
+}
+
+#include "rubycodeoperation.moc"
diff --git a/umbrello/umbrello/codegenerators/rubycodeoperation.h b/umbrello/umbrello/codegenerators/rubycodeoperation.h
new file mode 100644
index 00000000..c8e8cea4
--- /dev/null
+++ b/umbrello/umbrello/codegenerators/rubycodeoperation.h
@@ -0,0 +1,54 @@
+/***************************************************************************
+ rubycodeoperation.h
+ Derived from the Java code generator by thomas
+
+ begin : Thur Jul 21 2005
+ author : Richard Dale
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * copyright (C) 2006-2007 *
+ * Umbrello UML Modeller Authors <uml-devel@uml.sf.net> *
+ ***************************************************************************/
+
+#ifndef RUBYCODEOPERATION_H
+#define RUBYCODEOPERATION_H
+
+#include <qstring.h>
+#include "../codeoperation.h"
+
+class RubyClassifierCodeDocument;
+
+class RubyCodeOperation : virtual public CodeOperation
+{
+ Q_OBJECT
+public:
+
+ // Constructors/Destructors
+ //
+
+ /**
+ * Empty Constructor
+ */
+ RubyCodeOperation ( RubyClassifierCodeDocument * doc, UMLOperation * op, const QString & body = "", const QString & comment = "");
+
+ /**
+ * Empty Destructor
+ */
+ virtual ~RubyCodeOperation ( );
+
+ virtual int lastEditableLine();
+
+protected:
+
+ void updateMethodDeclaration();
+
+};
+
+#endif // RUBYCODEOPERATION_H
diff --git a/umbrello/umbrello/codegenerators/rubywriter.cpp b/umbrello/umbrello/codegenerators/rubywriter.cpp
new file mode 100644
index 00000000..aa9a5271
--- /dev/null
+++ b/umbrello/umbrello/codegenerators/rubywriter.cpp
@@ -0,0 +1,448 @@
+/***************************************************************************
+ rubywriter.h - description
+ -------------------
+ begin : Sat Dec 21 2002
+ copyright : Vincent Decorges
+ email : vincent.decorges@eivd.ch
+ (C) 2003-2006 Umbrello UML Modeller Authors <uml-devel@uml.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. *
+ * *
+ ***************************************************************************/
+
+#include "rubywriter.h"
+
+#include <kdebug.h>
+#include <klocale.h>
+#include <kmessagebox.h>
+#include <qfile.h>
+#include <qtextstream.h>
+#include <qregexp.h>
+
+#include "classifierinfo.h"
+#include "../umldoc.h"
+#include "../umlattributelist.h"
+#include "../association.h"
+#include "../attribute.h"
+#include "../classifier.h"
+#include "../operation.h"
+#include "../umlnamespace.h"
+
+RubyWriter::RubyWriter() {
+}
+
+RubyWriter::~RubyWriter() {}
+
+void RubyWriter::writeClass(UMLClassifier *c) {
+ if(!c) {
+ kDebug()<<"Cannot write class of NULL concept!" << endl;
+ return;
+ }
+
+ QString classname = cleanName(c->getName());
+
+ UMLClassifierList superclasses = c->getSuperClasses();
+ UMLAssociationList aggregations = c->getAggregations();
+ UMLAssociationList compositions = c->getCompositions();
+
+ //find an appropriate name for our file
+ QString fileName = findFileName(c, ".rb");
+ if (fileName.isEmpty()) {
+ emit codeGenerated(c, false);
+ return;
+ }
+
+ QFile fileh;
+ if( !openFile(fileh, fileName) ) {
+ emit codeGenerated(c, false);
+ return;
+ }
+ QTextStream h(&fileh);
+
+ // preparations
+ classifierInfo = new ClassifierInfo(c);
+ classifierInfo->fileName = fileName;
+ classifierInfo->className = cleanName(c->getName());
+
+ //////////////////////////////
+ //Start generating the code!!
+ /////////////////////////////
+
+
+ //try to find a heading file (license, coments, etc)
+ QString str;
+
+ str = getHeadingFile(".rb");
+ if(!str.isEmpty()) {
+ str.replace(QRegExp("%filename%"), fileName);
+ str.replace(QRegExp("%filepath%"), fileh.name());
+ h<<str<<m_endl;
+ }
+
+ if(forceDoc() || !c->getDoc().isEmpty()) {
+ QString docStr = c->getDoc();
+ docStr.replace(QRegExp("\\n"), "\n# ");
+ docStr.replace("@ref ", "");
+ docStr.replace("@see", "_See_");
+ docStr.replace("@short", "_Summary_");
+ docStr.replace("@author", "_Author_");
+ h<<"#"<<m_endl;
+ h<<"# "<<docStr<<m_endl;
+ h<<"#"<<m_endl<<m_endl;
+ }
+
+ // write inheritances out
+ UMLClassifier *concept;
+
+ h<< "class " << cppToRubyType(classname) << (superclasses.count() > 0 ? " < ":"");
+
+ int i = 0;
+ for (concept = superclasses.first(); concept; concept = superclasses.next()) {
+ if (i == 0) {
+ h << cppToRubyType(concept->getName()) << m_endl;
+ } else {
+ // Assume ruby modules that can be mixed in, after the first
+ // superclass name in the list
+ h << m_indentation << "include "<< cppToRubyType(concept->getName()) << m_endl;
+ }
+ i++;
+ }
+
+ h << m_endl;
+
+ // write comment for sub-section IF needed
+ if (forceDoc() || classifierInfo->hasAccessorMethods) {
+ h << m_indentation << "#" << m_endl;
+ h << m_indentation << "# Accessor Methods" << m_endl;
+ h << m_indentation << "#" << m_endl << m_endl;
+
+ // Accessor methods for attributes
+ writeAttributeMethods(&(classifierInfo->atpub), Uml::Visibility::Public, h);
+ writeAttributeMethods(&(classifierInfo->atprot), Uml::Visibility::Protected, h);
+ writeAttributeMethods(&(classifierInfo->atpriv), Uml::Visibility::Private, h);
+ h << m_endl;
+ }
+
+ //operations
+ writeOperations(c, h);
+
+ //finish files
+ h << "end" << m_endl << m_endl;
+
+ //close files and notfiy we are done
+ fileh.close();
+ emit codeGenerated(c, true);
+}
+
+
+////////////////////////////////////////////////////////////////////////////////////
+// Helper Methods
+
+QString RubyWriter::cppToRubyType(const QString &typeStr) {
+ QString type = cleanName(typeStr);
+ type.replace("const ", "");
+ type.replace(QRegExp("[*&\\s]"), "");
+ type.replace(QRegExp("[<>]"), "_");
+ type.replace("QStringList", "Array");
+ type.replace("QString", "String");
+ type.replace("bool", "true|false");
+ type.replace(QRegExp("^(uint|int|ushort|short|ulong|long)$"), "Integer");
+ type.replace(QRegExp("^(float|double)$"), "Float");
+ type.replace(QRegExp("^Q(?=[A-Z])"), "Qt::");
+ type.replace(QRegExp("^K(?!(DE|Parts|IO)"), "KDE::");
+
+ return type;
+}
+
+QString RubyWriter::cppToRubyName(const QString &nameStr) {
+ QString name = cleanName(nameStr);
+ name.replace(QRegExp("^m_"), "");
+ name.replace(QRegExp("^[pbn](?=[A-Z])"), "");
+ name = name.mid(0, 1).lower() + name.mid(1);
+ return name;
+}
+
+void RubyWriter::writeOperations(UMLClassifier *c,QTextStream &h) {
+
+ //Lists to store operations sorted by scope
+ UMLOperationList oppub,opprot,oppriv;
+
+ oppub.setAutoDelete(false);
+ opprot.setAutoDelete(false);
+ oppriv.setAutoDelete(false);
+
+ //sort operations by scope first and see if there are abstract methods
+ UMLOperationList opl(c->getOpList());
+ for(UMLOperation *op = opl.first(); op ; op = opl.next()) {
+ switch(op->getVisibility()) {
+ case Uml::Visibility::Public:
+ oppub.append(op);
+ break;
+ case Uml::Visibility::Protected:
+ opprot.append(op);
+ break;
+ case Uml::Visibility::Private:
+ oppriv.append(op);
+ break;
+ default:
+ break;
+ }
+ }
+
+ QString classname(cleanName(c->getName()));
+
+ //write operations to file
+ if(forceSections() || !oppub.isEmpty()) {
+ writeOperations(classname, oppub, Uml::Visibility::Public, h);
+ }
+
+ if(forceSections() || !opprot.isEmpty()) {
+ writeOperations(classname, opprot, Uml::Visibility::Protected, h);
+ }
+
+ if(forceSections() || !oppriv.isEmpty()) {
+ writeOperations(classname, oppriv, Uml::Visibility::Private, h);
+ }
+
+}
+
+void RubyWriter::writeOperations(const QString &classname, UMLOperationList &opList,
+ Uml::Visibility permitScope, QTextStream &h)
+{
+ UMLOperation *op;
+ UMLAttribute *at;
+
+ switch (permitScope) {
+ case Uml::Visibility::Public:
+ h << m_indentation << "public" << m_endl << m_endl;
+ break;
+ case Uml::Visibility::Protected:
+ h << m_indentation << "protected" << m_endl << m_endl;
+ break;
+ case Uml::Visibility::Private:
+ h << m_indentation << "private" << m_endl << m_endl;
+ break;
+ default:
+ break;
+ }
+
+ for (op=opList.first(); op ; op=opList.next()) {
+ QString methodName = cleanName(op->getName());
+ QStringList commentedParams;
+
+ // Skip destructors, and operator methods which
+ // can't be defined in ruby
+ if ( methodName.startsWith("~")
+ || methodName == "operator ="
+ || methodName == "operator --"
+ || methodName == "operator ++"
+ || methodName == "operator !=" )
+ {
+ continue;
+ }
+
+ if (methodName == classname) {
+ methodName = "initialize";
+ }
+
+ methodName.replace("operator ", "");
+ methodName = methodName.mid(0, 1).lower() + methodName.mid(1);
+
+ UMLAttributeList atl = op->getParmList();
+ //write method doc if we have doc || if at least one of the params has doc
+ bool writeDoc = forceDoc() || !op->getDoc().isEmpty();
+ // Always write out the docs for ruby as the type of the
+ // arguments and return value of the methods is useful
+ writeDoc = true;
+// for (at = atl.first(); at; at = atl.next())
+// writeDoc |= !at->getDoc().isEmpty();
+
+ if (writeDoc) {
+ h << m_indentation << "#" << m_endl;
+ QString docStr = op->getDoc();
+
+ docStr.replace(QRegExp("[\\n\\r]+ *"), m_endl);
+ docStr.replace(QRegExp("[\\n\\r]+\\t*"), m_endl);
+
+ docStr.replace(" m_", " ");
+ docStr.replace(QRegExp("\\s[npb](?=[A-Z])"), " ");
+ QRegExp re_params("@param (\\w)(\\w*)");
+ int pos = re_params.search(docStr);
+ while (pos != -1) {
+ docStr.replace( re_params.cap(0),
+ QString("@param _") + re_params.cap(1).lower() + re_params.cap(2) + '_' );
+ commentedParams.append(re_params.cap(1).lower() + re_params.cap(2));
+
+ pos += re_params.matchedLength() + 3;
+ pos = re_params.search(docStr, pos);
+ }
+
+ docStr.replace("\n", QString("\n") + m_indentation + "# ");
+
+ // Write parameter documentation
+ for (at = atl.first(); at ; at = atl.next()) {
+ // Only write an individual @param entry if one hasn't been found already
+ // in the main doc comment
+ if (commentedParams.contains(cppToRubyName(at->getName())) == 0) {
+ docStr += (m_endl + m_indentation + "# @param _" + cppToRubyName(at->getName()) + '_');
+ if (at->getDoc().isEmpty()) {
+ docStr += (' ' + cppToRubyType(at->getTypeName()));
+ } else {
+ docStr += (' ' + at->getDoc().replace(QRegExp("[\\n\\r]+[\\t ]*"), m_endl + " "));
+ }
+ }
+ }
+
+ docStr.replace("@ref ", "");
+ docStr.replace("@param", "*");
+ docStr.replace("@return", "* _returns_");
+
+ // All lines after the first '# *' in the doc comment
+ // must be indented correctly. If they aren't a list
+ // item starting with '# *', then indent the text with
+ // three spaces, '# ', to line up with the list item.
+ pos = docStr.find("# *");
+ QRegExp re_linestart("# (?!\\*)");
+ pos = re_linestart.search(docStr, pos);
+ while (pos > 0) {
+ docStr.insert(pos + 1, " ");
+
+ pos += re_linestart.matchedLength() + 2;
+ pos = re_linestart.search(docStr, pos);
+ }
+
+ h << m_indentation << "# "<< docStr << m_endl;
+
+ QString typeStr = cppToRubyType(op->getTypeName());
+ if (!typeStr.isEmpty() && typeStr != "void" && docStr.contains("_returns_") == 0) {
+ h << m_indentation << "# * _returns_ " << typeStr << m_endl;
+ }
+ }
+
+ h<< m_indentation << "def " + methodName << "(";
+
+ int j=0;
+ for (at = atl.first(); at; at = atl.next(), j++) {
+ QString nameStr = cppToRubyName(at->getName());
+ if (j > 0) {
+ h << ", " << nameStr;
+ } else {
+ h << nameStr;
+ }
+ h << (!(at->getInitialValue().isEmpty()) ?
+ (QString(" = ") + cppToRubyType(at->getInitialValue())) :
+ QString(""));
+ }
+
+ h <<")" << m_endl;
+
+ h << m_indentation << m_indentation << m_endl;
+
+ h << m_indentation << "end" << m_endl << m_endl;
+
+ }//end for
+
+}
+
+// this is for writing file attribute methods
+//
+void RubyWriter::writeAttributeMethods(UMLAttributeList *attribs,
+ Uml::Visibility visibility, QTextStream &stream)
+{
+ // return now if NO attributes to work on
+ if (attribs->count() == 0 || visibility == Uml::Visibility::Private)
+ return;
+
+ UMLAttribute *at;
+ for(at=attribs->first(); at; at=attribs->next())
+ {
+ QString varName = cppToRubyName(cleanName(at->getName()));
+
+ writeSingleAttributeAccessorMethods(varName, at->getDoc(), stream);
+ }
+
+}
+
+void RubyWriter::writeSingleAttributeAccessorMethods(
+ const QString &fieldName,
+ const QString &descr,
+ QTextStream &h)
+{
+ QString description = descr;
+ description.replace(QRegExp("m_[npb](?=[A-Z])"), "");
+ description.replace("m_", "");
+ description.replace("\n", QString("\n") + m_indentation + "# ");
+
+ if (!description.isEmpty()) {
+ h << m_indentation << "# " << description << m_endl;
+ }
+
+ h << m_indentation << "attr_accessor :" << fieldName << m_endl << m_endl;
+
+ return;
+}
+
+/**
+ * returns "Ruby"
+ */
+Uml::Programming_Language RubyWriter::getLanguage() {
+ return Uml::pl_Ruby;
+}
+
+const QStringList RubyWriter::reservedKeywords() const {
+
+ static QStringList keywords;
+
+ if (keywords.isEmpty()) {
+ keywords << "__FILE__"
+ << "__LINE__"
+ << "BEGIN"
+ << "END"
+ << "alias"
+ << "and"
+ << "begin"
+ << "break"
+ << "case"
+ << "class"
+ << "def"
+ << "defined?"
+ << "do"
+ << "else"
+ << "elsif"
+ << "end"
+ << "ensure"
+ << "false"
+ << "for"
+ << "if"
+ << "in"
+ << "module"
+ << "next"
+ << "nil"
+ << "not"
+ << "or"
+ << "redo"
+ << "rescue"
+ << "retry"
+ << "return"
+ << "self"
+ << "super"
+ << "then"
+ << "true"
+ << "undef"
+ << "unless"
+ << "until"
+ << "when"
+ << "while"
+ << "yield";
+ }
+
+ return keywords;
+}
+
+#include "rubywriter.moc"
diff --git a/umbrello/umbrello/codegenerators/rubywriter.h b/umbrello/umbrello/codegenerators/rubywriter.h
new file mode 100644
index 00000000..8f1547ad
--- /dev/null
+++ b/umbrello/umbrello/codegenerators/rubywriter.h
@@ -0,0 +1,113 @@
+/***************************************************************************
+ rubywriter.h - description
+ -------------------
+ begin : Mon Jul 18 2005
+ author : Richard Dale
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * copyright (C) 2006-2007 *
+ * Umbrello UML Modeller Authors <uml-devel@uml.sf.net> *
+ ***************************************************************************/
+
+#ifndef RUBYWRITER_H
+#define RUBYWRITER_H
+
+#include "simplecodegenerator.h"
+#include "../umloperationlist.h"
+#include "../umlattributelist.h"
+
+#include <qstringlist.h>
+
+class ClassifierInfo;
+
+/**
+ * class RubyWriter is a ruby code generator for UMLClassifier objects
+ * Just call writeClass and feed it a UMLClassifier;
+ */
+class RubyWriter : public SimpleCodeGenerator {
+ Q_OBJECT
+public:
+
+ RubyWriter();
+ virtual ~RubyWriter();
+
+ /**
+ * call this method to generate C++ code for a UMLClassifier
+ * @param c the class you want to generate code for.
+ */
+ virtual void writeClass(UMLClassifier *c);
+
+ /**
+ * returns "Ruby"
+ */
+ virtual Uml::Programming_Language getLanguage();
+
+ /**
+ * get list of reserved keywords
+ */
+ virtual const QStringList reservedKeywords() const;
+
+private:
+ /**
+ * Convert a C++ type such as 'int' or 'QWidget' to
+ * ruby types Integer and Qt::Widget
+ *
+ * @param cppType the C++ type to be converted
+ */
+ QString cppToRubyType(const QString &cppType);
+
+ /**
+ * Convert C++ names such as 'm_foobar' or pFoobar to
+ * just 'foobar' for ruby
+ *
+ * @param cppName the C++ name to be converted
+ */
+ QString cppToRubyName(const QString &cppName);
+
+ /**
+ * calls @ref writeSingleAttributeAccessorMethods() on each of the attributes in attribs list.
+ */
+ void writeAttributeMethods(UMLAttributeList *attribs,
+ Uml::Visibility visibility, QTextStream &stream);
+
+
+ /**
+ * write all method declarations, for attributes and associations
+ * for the given permitted scope.
+ */
+ void writeSingleAttributeAccessorMethods(const QString &fieldName,
+ const QString &description,
+ QTextStream &h);
+
+ /**
+ * write all operations for a given class
+ *
+ * @param c the concept we are generating code for
+ * @param h output stream for the header file
+ */
+ void writeOperations(UMLClassifier *c, QTextStream &h);
+
+ /**
+ * write a list of class operations
+ *
+ * @param classname the name of the class
+ * @param opList the list of operations
+ * @param h output stream for the header file
+ */
+ void writeOperations(const QString &classname, UMLOperationList &opList,
+ Uml::Visibility permitScope, QTextStream &h);
+
+ /**
+ * Summary information about current classifier.
+ */
+ ClassifierInfo * classifierInfo;
+};
+
+#endif //RUBYWRITER
diff --git a/umbrello/umbrello/codegenerators/simplecodegenerator.cpp b/umbrello/umbrello/codegenerators/simplecodegenerator.cpp
new file mode 100644
index 00000000..98477f15
--- /dev/null
+++ b/umbrello/umbrello/codegenerators/simplecodegenerator.cpp
@@ -0,0 +1,292 @@
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * copyright (C) 2004-2006 *
+ * Umbrello UML Modeller Authors <uml-devel@uml.sf.net> *
+ ***************************************************************************/
+
+/* This code generated by:
+ * Author : thomas
+ * Date : Sep Mon 1 2003
+ */
+
+// own header
+#include "simplecodegenerator.h"
+// system includes
+#include <cstdlib> //to get the user name
+// qt includes
+#include <qdatetime.h>
+#include <qregexp.h>
+#include <qdir.h>
+// kde includes
+#include <klocale.h>
+#include <kdebug.h>
+#include <kmessagebox.h>
+#include <kdialog.h>
+#include <kapplication.h>
+// app includes
+#include "../dialogs/overwritedialogue.h"
+#include "../model_utils.h"
+#include "../attribute.h"
+#include "../umloperationlist.h"
+#include "../umlattributelist.h"
+#include "../classifier.h"
+#include "../codedocument.h"
+#include "../codegenerationpolicy.h"
+#include "../operation.h"
+#include "../umldoc.h"
+#include "../uml.h"
+
+// Constructors/Destructors
+//
+
+SimpleCodeGenerator::SimpleCodeGenerator (bool createDirHierarchyForPackages /* =true */)
+{
+ m_indentLevel = 0;
+ UMLDoc * parentDoc = UMLApp::app()->getDocument();
+ parentDoc->disconnect(this); // disconnect from UMLDoc.. we arent planning to be synced at all
+ m_createDirHierarchyForPackages = createDirHierarchyForPackages;
+ initFields(parentDoc);
+}
+
+SimpleCodeGenerator::~SimpleCodeGenerator ( ) { }
+
+//
+// Methods
+//
+
+// Accessor methods
+//
+
+
+// Other methods
+//
+
+QString SimpleCodeGenerator::getIndent ()
+{
+ QString myIndent;
+ for (int i = 0 ; i < m_indentLevel ; i++)
+ myIndent.append(m_indentation);
+ return myIndent;
+}
+
+QString SimpleCodeGenerator::findFileName(UMLPackage* concept, const QString &ext) {
+
+ //if we already know to which file this class was written/should be written, just return it.
+ if (m_fileMap.contains(concept))
+ return m_fileMap[concept];
+
+ //else, determine the "natural" file name
+ QString name;
+ // Get the package name
+ QString package = concept->getPackage(".");
+
+ // Replace all white spaces with blanks
+ package.simplifyWhiteSpace();
+
+ // Replace all blanks with underscore
+ package.replace(QRegExp(" "), "_");
+
+ // Convert all "::" to "/" : Platform-specific path separator
+ // package.replace(QRegExp("::"), "/");
+
+ // if package is given add this as a directory to the file name
+ if (!package.isEmpty() && m_createDirHierarchyForPackages) {
+ name = package + '.' + concept->getName();
+ name.replace(QRegExp("\\."),"/");
+ package.replace(QRegExp("\\."), "/");
+ package = '/' + package;
+ } else {
+ name = concept->getFullyQualifiedName("-");
+ }
+
+ if (! UMLApp::app()->activeLanguageIsCaseSensitive()) {
+ package = package.lower();
+ name = name.lower();
+ }
+
+ // if a package name exists check the existence of the package directory
+ if (!package.isEmpty() && m_createDirHierarchyForPackages) {
+ QDir pathDir(UMLApp::app()->getCommonPolicy()->getOutputDirectory().absPath() + package);
+ // does our complete output directory exist yet? if not, try to create it
+ if (!pathDir.exists())
+ {
+ QStringList dirs = QStringList::split("/",pathDir.absPath());
+ QString currentDir = "";
+
+ QStringList::iterator end(dirs.end());
+ for (QStringList::iterator dir(dirs.begin()); dir != end; ++dir)
+ {
+ currentDir += '/' + *dir;
+ if (! (pathDir.exists(currentDir)
+ || pathDir.mkdir(currentDir) ) )
+ {
+ KMessageBox::error(0, i18n("Cannot create the folder:\n") +
+ pathDir.absPath() + i18n("\nPlease check the access rights"),
+ i18n("Cannot Create Folder"));
+ return NULL;
+ }
+ }
+ }
+ }
+
+
+ name.simplifyWhiteSpace();
+ name.replace(QRegExp(" "),"_");
+
+ QString extension = ext.simplifyWhiteSpace();
+ extension.replace(' ', '_');
+
+ return overwritableName(concept, name, extension);
+}
+
+QString SimpleCodeGenerator::overwritableName(UMLPackage* concept, const QString &name, const QString &ext) {
+ //check if a file named "name" with extension "ext" already exists
+ CodeGenerationPolicy *commonPolicy = UMLApp::app()->getCommonPolicy();
+ QDir outputDir = commonPolicy->getOutputDirectory();
+ QString filename = name + ext;
+ if(!outputDir.exists(filename)) {
+ m_fileMap.insert(concept,filename);
+ return filename; //if not, "name" is OK and we have not much to to
+ }
+
+ int suffix;
+ OverwriteDialogue overwriteDialogue( filename, outputDir.absPath(),
+ m_applyToAllRemaining, kapp -> mainWidget() );
+ switch(commonPolicy->getOverwritePolicy()) { //if it exists, check the OverwritePolicy we should use
+ case CodeGenerationPolicy::Ok: //ok to overwrite file
+ break;
+ case CodeGenerationPolicy::Ask: //ask if we can overwrite
+ switch(overwriteDialogue.exec()) {
+ case KDialogBase::Yes: //overwrite file
+ if ( overwriteDialogue.applyToAllRemaining() ) {
+ commonPolicy->setOverwritePolicy(CodeGenerationPolicy::Ok);
+ } else {
+ m_applyToAllRemaining = false;
+ }
+ break;
+ case KDialogBase::No: //generate similar name
+ suffix = 1;
+ while (1) {
+ filename = name + "__" + QString::number(suffix) + ext;
+ if (!outputDir.exists(filename))
+ break;
+ suffix++;
+ }
+ if ( overwriteDialogue.applyToAllRemaining() ) {
+ commonPolicy->setOverwritePolicy(CodeGenerationPolicy::Never);
+ } else {
+ m_applyToAllRemaining = false;
+ }
+ break;
+ case KDialogBase::Cancel: //don't output anything
+ if ( overwriteDialogue.applyToAllRemaining() ) {
+ commonPolicy->setOverwritePolicy(CodeGenerationPolicy::Cancel);
+ } else {
+ m_applyToAllRemaining = false;
+ }
+ return NULL;
+ break;
+ }
+
+ break;
+ case CodeGenerationPolicy::Never: //generate similar name
+ suffix = 1;
+ while (1) {
+ filename = name + "__" + QString::number(suffix) + ext;
+ if (!outputDir.exists(filename))
+ break;
+ suffix++;
+ }
+ break;
+ case CodeGenerationPolicy::Cancel: //don't output anything
+ return NULL;
+ break;
+ }
+
+ m_fileMap.insert(concept, filename);
+ return filename;
+}
+
+
+bool SimpleCodeGenerator::hasDefaultValueAttr(UMLClassifier *c) {
+ UMLAttributeList atl = c->getAttributeList();
+ for(UMLAttribute *at = atl.first(); at; at = atl.next())
+ if(!at->getInitialValue().isEmpty())
+ return true;
+ return false;
+}
+
+bool SimpleCodeGenerator::hasAbstractOps(UMLClassifier *c) {
+ UMLOperationList opl(c->getOpList());
+ for(UMLOperation *op = opl.first(); op ; op = opl.next())
+ if(op->getAbstract())
+ return true;
+ return false;
+}
+
+/**
+ * @return ClassifierCodeDocument
+ * @param classifier
+ * @param this This package generator object.
+ */
+CodeDocument * SimpleCodeGenerator::newClassifierCodeDocument(UMLClassifier* /*classifier*/)
+{
+ return (CodeDocument*)NULL;
+}
+
+// write all concepts in project to file
+void SimpleCodeGenerator::writeCodeToFile ( ) {
+ m_fileMap.clear(); // need to do this, else just keep getting same directory to write to.
+ UMLClassifierList concepts = m_doc->getClassesAndInterfaces();
+ for (UMLClassifier *c = concepts.first(); c; c = concepts.next()) {
+ if (! Model_Utils::isCommonDataType(c->getName()))
+ this->writeClass(c); // call the writer for each class.
+ }
+}
+
+// write only selected concepts to file
+void SimpleCodeGenerator::writeCodeToFile ( UMLClassifierList & concepts) {
+ m_fileMap.clear(); // ??
+ for (UMLClassifier *c = concepts.first(); c; c = concepts.next())
+ this->writeClass(c); // call the writer for each class.
+}
+
+void SimpleCodeGenerator::initFields ( UMLDoc * parentDoc ) {
+
+ // load Classifier documents from parent document
+ // initFromParentDocument();
+
+ m_fileMap.clear();
+ m_applyToAllRemaining = true;
+ m_doc = parentDoc;
+
+ // this really is just being used to sync the internal params
+ // to the codegenpolicy as there are no code documents to really sync.
+ syncCodeToDocument();
+}
+
+// a little method to provide some compatability between
+// the newer codegenpolicy object and the older class fields.
+void SimpleCodeGenerator::syncCodeToDocument() {
+
+ CodeGenerationPolicy *policy = UMLApp::app()->getCommonPolicy();
+
+ m_indentation = policy->getIndentation();
+ m_endl = policy->getNewLineEndingChars();
+
+}
+
+
+// override parent method
+void SimpleCodeGenerator::initFromParentDocument( )
+{
+ // Do nothing
+}
+
+
+#include "simplecodegenerator.moc"
diff --git a/umbrello/umbrello/codegenerators/simplecodegenerator.h b/umbrello/umbrello/codegenerators/simplecodegenerator.h
new file mode 100644
index 00000000..d75a0660
--- /dev/null
+++ b/umbrello/umbrello/codegenerators/simplecodegenerator.h
@@ -0,0 +1,120 @@
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the 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 code generated by:
+ * Author : thomas
+ * Date : Sep Mon 1 2003
+ *
+ * copyright (C) 2004
+ * Umbrello UML Modeller Authors <uml-devel@uml.sf.net>
+ */
+
+
+#ifndef SIMPLECODEGENERATOR_H
+#define SIMPLECODEGENERATOR_H
+
+#include <qstringlist.h>
+#include <qstring.h>
+#include <qmap.h>
+
+#include "../codegenerator.h"
+#include "../umlnamespace.h"
+
+class UMLDoc;
+
+/**
+ * A simple code generator interface designed to work with
+ * the existing codewriters.
+ */
+class SimpleCodeGenerator : public CodeGenerator
+{
+ Q_OBJECT
+public:
+
+ // Constructors/Destructors
+ //
+
+ /**
+ * Empty Constructor
+ */
+ SimpleCodeGenerator (bool createDirHierarchyForPackages = true);
+
+ /**
+ * Empty Destructor
+ */
+ virtual ~SimpleCodeGenerator ( );
+
+ // Public attribute accessor methods
+ //
+
+ void writeCodeToFile ( UMLClassifierList & concepts);
+ void writeCodeToFile ( );
+
+ /**
+ * call this method to generate code for a UMLClassifier
+ * @param c the class you want to generate code for.
+ */
+ virtual void writeClass(UMLClassifier *c) = 0;
+
+ /**
+ * This is implemented only because we HAVE to.
+ * @return ClassifierCodeDocument
+ * @param classifier
+ */
+ CodeDocument * newClassifierCodeDocument (UMLClassifier * classifier);
+
+protected:
+
+ // compatability methods..
+ QString findFileName(UMLPackage* concept, const QString &ext);
+ QString overwritableName(UMLPackage* concept, const QString &name, const QString &ext);
+ bool hasDefaultValueAttr(UMLClassifier *c);
+ bool hasAbstractOps(UMLClassifier *c);
+
+ /**
+ * Returns the current indent string based on m_indentLevel and m_indentation.
+ */
+ QString getIndent ();
+
+ /**
+ * Maps UMLObjects to filenames. Used for finding out which file
+ * each class was written to.
+ */
+ QMap<UMLPackage*,QString> m_fileMap;
+
+ // the parent document
+ UMLDoc *m_doc;
+
+ /**
+ * For some code generators, it does not make much sense to create a
+ * directory for each package because that would lead to a rather
+ * sparsely populated directory tree (maximum of just one source file
+ * per directory.)
+ */
+ bool m_createDirHierarchyForPackages;
+
+ /* Old Attributes writers will look for */
+ QString m_indentation;
+ int m_indentLevel;
+ QString m_endl;
+
+ // override parent method..we need special handling
+ void initFromParentDocument( );
+
+private:
+
+ void initFields ( UMLDoc * doc) ;
+
+public slots:
+
+ void syncCodeToDocument ( );
+
+};
+
+#endif // SIMPLECODEGENERATOR_H
diff --git a/umbrello/umbrello/codegenerators/sqlwriter.cpp b/umbrello/umbrello/codegenerators/sqlwriter.cpp
new file mode 100644
index 00000000..f01e8bbe
--- /dev/null
+++ b/umbrello/umbrello/codegenerators/sqlwriter.cpp
@@ -0,0 +1,394 @@
+/***************************************************************************
+ begin : 10.02.2003
+ copyright : (C) 2003 Nikolaus Gradwohl
+ email : guru@local-guru.net
+ (C) 2004-2006 Umbrello UML Modeller Authors <uml-devel@uml.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. *
+ * *
+ ***************************************************************************/
+
+#include "sqlwriter.h"
+
+#include <kdebug.h>
+
+#include <klocale.h>
+#include <kmessagebox.h>
+#include <qfile.h>
+#include <qtextstream.h>
+#include <qregexp.h>
+
+#include "../classifier.h"
+#include "../operation.h"
+#include "../umlnamespace.h"
+#include "../association.h"
+#include "../attribute.h"
+
+SQLWriter::SQLWriter() {
+}
+
+SQLWriter::~SQLWriter() {}
+
+void SQLWriter::writeClass(UMLClassifier *c) {
+
+ if(!c) {
+ kDebug()<<"Cannot write class of NULL concept!" << endl;
+ return;
+ }
+
+ const bool isClass = !c->isInterface();
+ QString classname = cleanName(c->getName());
+
+ //find an appropriate name for our file
+ QString fileName = findFileName(c, ".sql");
+ if (fileName.isEmpty()) {
+ emit codeGenerated(c, false);
+ return;
+ }
+
+ QFile file;
+ if( !openFile(file, fileName) ) {
+ emit codeGenerated(c, false);
+ return;
+ }
+
+ //Start generating the code!!
+
+ QTextStream sql(&file);
+ //try to find a heading file (license, coments, etc)
+ QString str;
+ str = getHeadingFile(".sql");
+ if(!str.isEmpty()) {
+ str.replace(QRegExp("%filename%"),fileName);
+ str.replace(QRegExp("%filepath%"),file.name());
+ sql<<str<<m_endl;
+ }
+
+ //Write class Documentation if there is somthing or if force option
+ if(forceDoc() || !c->getDoc().isEmpty()) {
+ sql << m_endl << "--" << m_endl;
+ sql<<"-- TABLE: "<<classname<<m_endl;
+ sql<<formatDoc(c->getDoc(),"-- ");
+ sql << "-- " << m_endl << m_endl;
+ }
+
+ sql << "CREATE TABLE "<< classname << " ( " << m_endl;
+
+ if (isClass)
+ writeAttributes(c, sql);
+
+ sql << m_endl << ");" << m_endl;
+
+ QMap<UMLAssociation*,UMLAssociation*> constraintMap; // so we don't repeat constraint
+ UMLAssociationList aggregations = c->getAggregations();
+ if( forceSections() || !aggregations.isEmpty() ) {
+ for(UMLAssociation* a = aggregations.first(); a; a = aggregations.next()) {
+ UMLObject *objA = a->getObject(Uml::A);
+ UMLObject *objB = a->getObject(Uml::B);
+ if (objA->getID() == c->getID() && objB->getID() != c->getID())
+ continue;
+ constraintMap[a] = a;
+ }
+ }
+
+ QMap<UMLAssociation*,UMLAssociation*>::Iterator itor = constraintMap.begin();
+ for (;itor != constraintMap.end();itor++) {
+ UMLAssociation* a = itor.data();
+ sql << "ALTER TABLE "<< classname
+ << " ADD CONSTRAINT " << a->getName() << " FOREIGN KEY ("
+ << a->getRoleName(Uml::B) << ") REFERENCES "
+ << a->getObject(Uml::A)->getName()
+ << " (" << a->getRoleName(Uml::A) << ");" << m_endl;
+ }
+
+
+ file.close();
+ emit codeGenerated(c, true);
+}
+
+
+void SQLWriter::writeAttributes(UMLClassifier *c, QTextStream &sql) {
+ UMLAttributeList atpub, atprot, atpriv, atimp;
+ atpub.setAutoDelete(false);
+ atprot.setAutoDelete(false);
+ atpriv.setAutoDelete(false);
+ atimp.setAutoDelete(false);
+
+ //sort attributes by scope and see if they have a default value
+ UMLAttributeList atl = c->getAttributeList();
+ for(UMLAttribute* at=atl.first(); at ; at=atl.next()) {
+ switch(at->getVisibility()) {
+ case Uml::Visibility::Public:
+ atpub.append(at);
+ break;
+ case Uml::Visibility::Protected:
+ atprot.append(at);
+ break;
+ case Uml::Visibility::Private:
+ atpriv.append(at);
+ break;
+ case Uml::Visibility::Implementation:
+ atimp.append(at);
+ break;
+ }
+ }
+
+ // now print the attributes; they are sorted by there scope
+ // in front of the first attribute shouldn't be a , -> so we need to find
+ // out, when the first attribute was added
+ bool first = true;
+
+ if (atpub.count() > 0)
+ {
+ printAttributes(sql, atpub, first);
+ first = false;
+ }
+
+ if (atprot.count() > 0)
+ {
+ printAttributes(sql, atprot, first);
+ first = false;
+ }
+
+ if (atpriv.count() > 0)
+ {
+ printAttributes(sql, atpriv, first);
+ first = false;
+ }
+
+ if (atimp.count() > 0)
+ {
+ printAttributes(sql, atimp, first);
+ first = false;
+ }
+
+ return;
+}
+
+void SQLWriter::printAttributes(QTextStream& sql, UMLAttributeList attributeList, bool first) {
+ QString attrDoc = "";
+ UMLAttribute* at;
+
+ for (at=attributeList.first();at;at=attributeList.next())
+ {
+ // print , after attribute
+ if (first == false) {
+ sql <<",";
+ } else {
+ first = false;
+ }
+
+ // print documentation/comment of last attribute at end of line
+ if (attrDoc.isEmpty() == false)
+ {
+ sql << " -- " << attrDoc << m_endl;
+ } else {
+ sql << m_endl;
+ }
+
+ // write the attribute
+ sql << m_indentation << cleanName(at->getName()) << " " << at->getTypeName() << " "
+ << (at->getInitialValue().isEmpty()?QString(""):QString(" DEFAULT ")+at->getInitialValue());
+
+ // now get documentation/comment of current attribute
+ attrDoc = at->getDoc();
+ }
+
+ // print documentation/comment at end of line
+ if (attrDoc.isEmpty() == false)
+ {
+ sql << " -- " << attrDoc << m_endl;
+ } else {
+ sql << m_endl;
+ }
+
+ return;
+}
+
+Uml::Programming_Language SQLWriter::getLanguage() {
+ return Uml::pl_SQL;
+}
+
+QStringList SQLWriter::defaultDatatypes() {
+ QStringList l;
+ l.append("varchar");
+ l.append("tinyint");
+ l.append("smallint");
+ l.append("mediumint");
+ l.append("bigint");
+ l.append("float");
+ l.append("double");
+ l.append("decimal");
+ l.append("date");
+ l.append("datetime");
+ l.append("time");
+ l.append("timestamp");
+ l.append("year");
+ l.append("char");
+ l.append("tinyblob");
+ l.append("blob");
+ l.append("mediumblob");
+ l.append("longblob");
+ l.append("tinytext");
+ l.append("text");
+ l.append("mediumtext");
+ l.append("longtext");
+ l.append("enum");
+ l.append("set");
+ return l;
+}
+
+const QStringList SQLWriter::reservedKeywords() const {
+
+ static QStringList keywords;
+
+ if (keywords.isEmpty()) {
+ keywords << "access"
+ << "add"
+ << "all"
+ << "alter"
+ << "analyze"
+ << "and"
+ << "any"
+ << "as"
+ << "asc"
+ << "audit"
+ << "begin"
+ << "between"
+ << "boolean"
+ << "by"
+ << "char"
+ << "character"
+ << "check"
+ << "cluster"
+ << "column"
+ << "comment"
+ << "commit"
+ << "compress"
+ << "connect"
+ << "create"
+ << "current"
+ << "cursor"
+ << "date"
+ << "decimal"
+ << "default"
+ << "delete"
+ << "desc"
+ << "distinct"
+ << "drop"
+ << "else"
+ << "elsif"
+ << "end"
+ << "escape"
+ << "exception"
+ << "exclusive"
+ << "execute"
+ << "exists"
+ << "explain"
+ << "false"
+ << "file"
+ << "float"
+ << "for"
+ << "from"
+ << "function"
+ << "grant"
+ << "group"
+ << "having"
+ << "identified"
+ << "if"
+ << "immediate"
+ << "in"
+ << "increment"
+ << "index"
+ << "initial"
+ << "insert"
+ << "integer"
+ << "intersect"
+ << "into"
+ << "is"
+ << "level"
+ << "like"
+ << "lock"
+ << "long"
+ << "loop"
+ << "maxextents"
+ << "minus"
+ << "mlslabel"
+ << "mode"
+ << "modify"
+ << "noaudit"
+ << "nocompress"
+ << "not"
+ << "nowait"
+ << "null"
+ << "number"
+ << "of"
+ << "offline"
+ << "on"
+ << "online"
+ << "option"
+ << "or"
+ << "order"
+ << "out"
+ << "pctfree"
+ << "prior"
+ << "privileges"
+ << "procedure"
+ << "public"
+ << "raw"
+ << "rename"
+ << "resource"
+ << "return"
+ << "revoke"
+ << "rollback"
+ << "row"
+ << "rowid"
+ << "rowlabel"
+ << "rownum"
+ << "rows"
+ << "savepoint"
+ << "select"
+ << "session"
+ << "set"
+ << "share"
+ << "size"
+ << "smallint"
+ << "some"
+ << "start"
+ << "successful"
+ << "synonym"
+ << "sysdate"
+ << "table"
+ << "then"
+ << "to"
+ << "trigger"
+ << "true"
+ << "truncate"
+ << "type"
+ << "uid"
+ << "union"
+ << "unique"
+ << "update"
+ << "user"
+ << "using"
+ << "validate"
+ << "values"
+ << "varchar"
+ << "varchar2"
+ << "varray"
+ << "view"
+ << "whenever"
+ << "where"
+ << "with";
+ }
+
+ return keywords;
+}
+
+#include "sqlwriter.moc"
diff --git a/umbrello/umbrello/codegenerators/sqlwriter.h b/umbrello/umbrello/codegenerators/sqlwriter.h
new file mode 100644
index 00000000..c500e2e7
--- /dev/null
+++ b/umbrello/umbrello/codegenerators/sqlwriter.h
@@ -0,0 +1,77 @@
+/***************************************************************************
+ sqlwriter.h - description
+ -------------------
+ begin : 10.02.2003
+ copyright : (C) 2003 by Nikolaus Gradwohl
+ email : guru@local-guru.net
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the 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 SQLWRITER_H
+#define SQLWRITER_H
+
+#include "simplecodegenerator.h"
+#include "../umlattributelist.h"
+
+/**
+ * class SQLWriter is a code generator for UMLClassifier objects.
+ * Create an instance of this class, and feed it a UMLClassifier when
+ * calling writeClass and it will generate a sql source file for
+ * that concept
+ */
+class SQLWriter : public SimpleCodeGenerator {
+ Q_OBJECT
+public:
+
+ SQLWriter();
+ virtual ~SQLWriter();
+
+ /**
+ * call this method to generate sql code for a UMLClassifier
+ * @param c the class to generate code for
+ */
+ virtual void writeClass(UMLClassifier *c);
+
+ /**
+ * returns "SQL"
+ */
+ virtual Uml::Programming_Language getLanguage();
+
+ /**
+ * Reimplement method from CodeGenerator.
+ */
+ virtual QStringList defaultDatatypes();
+
+ /**
+ * get list of reserved keywords
+ */
+ virtual const QStringList reservedKeywords() const;
+
+private:
+
+ /**
+ * write all attributes for a given class
+ * @param c the class for which we are generating code
+ * @param j the stream associated with the output file
+ */
+ void writeAttributes(UMLClassifier *c, QTextStream &j);
+
+ /**
+ * Prints out attributes as columns in the table
+ *
+ * @param sql the stream we should print to
+ * @param attributeList the attributes to be printed
+ * @param first if the attributes are the first one
+ */
+ void printAttributes(QTextStream& sql, UMLAttributeList attributeList, bool first);
+};
+
+#endif // SQLWRITER_H
diff --git a/umbrello/umbrello/codegenerators/tclwriter.cpp b/umbrello/umbrello/codegenerators/tclwriter.cpp
new file mode 100644
index 00000000..d8607aa7
--- /dev/null
+++ b/umbrello/umbrello/codegenerators/tclwriter.cpp
@@ -0,0 +1,951 @@
+/***************************************************************************
+ begin : Thu Jul 26 2005
+ copyright : (C) 2005 by Rene Meyer
+ email : rene.meyer@sturmit.de
+ (C) 2006 Umbrello UML Modeller Authors <uml-devel@uml.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. *
+ * *
+ ***************************************************************************/
+
+// own header
+#include "tclwriter.h"
+// qt/kde includes
+#include <qfile.h>
+#include <qtextstream.h>
+#include <qregexp.h>
+#include <kdebug.h>
+// app includes
+#include "classifierinfo.h"
+#include "codegen_utils.h"
+#include "../umldoc.h"
+#include "../classifier.h"
+#include "../operation.h"
+#include "../template.h"
+#include "../umltemplatelist.h"
+#include "../umlclassifierlistitemlist.h"
+#include "../classifierlistitem.h"
+#include "../model_utils.h"
+
+static const char *tclwords[] = {
+ "body",
+ "break",
+ "case",
+ "class",
+ "common",
+ "concat",
+ "configbody",
+ "constructor",
+ "continue",
+ "default",
+ "destructor",
+ "else",
+ "elseif",
+ "for",
+ "foreach",
+ "global",
+ "if",
+ "incr",
+ "lappend",
+ "lindex",
+ "list",
+ "llength",
+ "load",
+ "lrange",
+ "lreplace",
+ "method",
+ "namespace",
+ "private",
+ "proc",
+ "protected",
+ "public",
+ "return",
+ "set",
+ "source",
+ "switch",
+ "then",
+ "upvar",
+ "variable",
+ "virtual",
+ "while",
+ 0
+ };
+
+TclWriter::TclWriter()
+{
+}
+
+TclWriter::~TclWriter()
+{
+}
+
+Uml::Programming_Language
+TclWriter::getLanguage()
+{
+ return Uml::pl_Tcl;
+}
+
+void
+TclWriter::writeClass(UMLClassifier * c)
+{
+
+ if (!c) {
+ kDebug() << "Cannot write class of NULL concept!\n";
+ return;
+ }
+ QFile fileh, filetcl;
+
+ // find an appropriate name for our file
+ QString fileName = findFileName(c, ".tcl");
+ if (fileName.isEmpty()) {
+ emit codeGenerated(c, false);
+ return;
+ }
+
+ if (!openFile(fileh, fileName)) {
+ emit codeGenerated(c, false);
+ return;
+ }
+ // preparations
+ classifierInfo = new ClassifierInfo(c);
+ classifierInfo->fileName = fileName;
+ classifierInfo->className = cleanName(c->getName());
+ mClass = cleanName(c->getName());
+ if (!c->getPackage().isEmpty()) {
+ mNamespace = "::" + cleanName(c->getPackage());
+ mClassGlobal = mNamespace + "::" + mClass;
+ } else {
+ mNamespace = "::";
+ mClassGlobal = "::" + mClass;
+ }
+
+ // write Header file
+ writeHeaderFile(c, fileh);
+ fileh.close();
+
+ // Determine whether the implementation file is required.
+ // (It is not required if the class is an enumeration.)
+ bool need_impl = true;
+ if (!classifierInfo->isInterface) {
+ if (c->getBaseType() == Uml::ot_Enum)
+ need_impl = false;
+ }
+ if (need_impl) {
+ if (!openFile(filetcl, fileName + "body")) {
+ emit codeGenerated(c, false);
+ return;
+ }
+ // write Source file
+ writeSourceFile(c, filetcl);
+ filetcl.close();
+ }
+ // Wrap up: free classifierInfo, emit done code
+ classifierInfo = 0;
+
+ emit codeGenerated(c, true);
+
+}
+
+void
+TclWriter::writeHeaderFile(UMLClassifier * c, QFile & fileh)
+{
+ // open stream for writing
+ QTextStream stream(&fileh);
+ mStream = &stream;
+
+ // reset the indent level
+ m_indentLevel = 0;
+
+ // write header blurb
+ QString str = getHeadingFile(".tcl");
+ if (!str.isEmpty()) {
+ str.replace(QRegExp("%filename%"), classifierInfo->fileName);
+ str.replace(QRegExp("%filepath%"), fileh.name());
+ writeCode(str);
+ }
+ // set current namespace
+ writeCode("namespace eval " + mNamespace + " {");
+ m_indentLevel++;
+
+ // check on already existing
+ writeComm("Do not load twice");
+ writeCode("if {[namespace exist " + mClass + "]} return");
+
+ // source used superclass files
+ UMLClassifierList superclasses = classifierInfo->superclasses;
+ if (superclasses.count() > 0) {
+ writeComm
+ ("Source found and used class files and import class command if necessary");
+
+ for (UMLClassifier * classifier = superclasses.first(); classifier;
+ classifier = superclasses.next()) {
+ writeUse(classifier);
+ }
+ }
+ // write all "source" we need to include other classes, that arent us.
+ if (classifierInfo->hasAssociations) {
+ writeAssociationIncl(classifierInfo->plainAssociations, c->getID(),
+ "Associations");
+ writeAssociationIncl(classifierInfo->aggregations, c->getID(),
+ "Aggregations");
+ writeAssociationIncl(classifierInfo->compositions, c->getID(),
+ "Compositions");
+ }
+ //Write class Documentation
+ writeDocu("\n@class\t" + mClass + m_endl + c->getDoc());
+
+ //check if class is abstract and / or has abstract methods
+ if ((c->getAbstract() || classifierInfo->isInterface)
+ && !hasAbstractOps(c)) {
+ writeComm("TODO abstract class" + mClass +
+ "\nInherit from it and create only objects from the derived classes");
+ }
+ // check on enum classes
+ if (!classifierInfo->isInterface) {
+ // use tcl-list for enum's
+ if (c->getBaseType() == Uml::ot_Enum) {
+ UMLClassifierListItemList litList =
+ c->getFilteredList(Uml::ot_EnumLiteral);
+ writeCode("set enum_" + mClass + " [list\\");
+ m_indentLevel++;
+ for (UMLClassifierListItem * lit = litList.first(); lit;
+ lit = litList.next()) {
+ QString enumLiteral = cleanName(lit->getName());
+ writeCode(enumLiteral + "\\");
+ }
+ m_indentLevel--;
+ writeCode("];# end of enum");
+ m_indentLevel--;
+ writeCode("};# end of namespace");
+ return;
+ }
+ }
+ // Generate template parameters.
+ UMLTemplateList template_params = c->getTemplateList();
+ if (template_params.count()) {
+ writeCode("#TODO template<");
+ for (UMLTemplate * t = template_params.first(); t;
+ t = template_params.next()) {
+ QString formalName = t->getName();
+ QString typeName = t->getTypeName();
+ writeCode(typeName + "# " + formalName);
+ }
+ }
+ // start my own class
+ writeCode("class " + mClass + " {");
+ m_indentLevel++;
+ if (classifierInfo->superclasses.count() > 0) {
+ QString code = "inherit";
+ for (UMLClassifier * superClass = classifierInfo->superclasses.first();
+ superClass; superClass = classifierInfo->superclasses.next()) {
+ /*
+ if (superClass->getAbstract() || superClass->isInterface())
+ stream << getIndent() << "virtual ";
+ */
+ if (superClass->getPackage().isEmpty()) {
+ code += " ::" + cleanName(superClass->getName());
+ } else {
+ code +=
+ " ::" + cleanName(superClass->getPackage()) + "::" +
+ cleanName(superClass->getName());
+ }
+ }
+ writeCode(code);
+ }
+ //
+ //declarations of operations
+ //
+ // write out field and operations decl grouped by visibility
+ //
+
+ // PUBLIC attribs/methods
+ // for public: constructors are first ops we print out
+ if (!classifierInfo->isInterface) {
+ writeConstructorHeader();
+ writeDestructorHeader();
+ }
+ // attributes
+ writeAttributeDecl(Uml::Visibility::Public, true); // write static attributes first
+ writeAttributeDecl(Uml::Visibility::Public, false);
+ // associations
+ writeAssociationDecl(classifierInfo->plainAssociations, Uml::Visibility::Public,
+ c->getID(), "Associations");
+ writeAssociationDecl(classifierInfo->aggregations, Uml::Visibility::Public, c->getID(),
+ "Aggregations");
+ writeAssociationDecl(classifierInfo->compositions, Uml::Visibility::Public, c->getID(),
+ "Compositions");
+ //TODO writeHeaderAccessorMethodDecl(c, Uml::Visibility::Public, stream);
+ writeOperationHeader(c, Uml::Visibility::Public);
+
+ // PROTECTED attribs/methods
+ //
+ // attributes
+ writeAttributeDecl(Uml::Visibility::Protected, true); // write static attributes first
+ writeAttributeDecl(Uml::Visibility::Protected, false);
+ // associations
+ writeAssociationDecl(classifierInfo->plainAssociations, Uml::Visibility::Protected,
+ c->getID(), "Association");
+ writeAssociationDecl(classifierInfo->aggregations, Uml::Visibility::Protected,
+ c->getID(), "Aggregation");
+ writeAssociationDecl(classifierInfo->compositions, Uml::Visibility::Protected,
+ c->getID(), "Composition");
+ //TODO writeHeaderAccessorMethodDecl(c, Uml::Visibility::Protected, stream);
+ writeOperationHeader(c, Uml::Visibility::Protected);
+
+ // PRIVATE attribs/methods
+ //
+ // attributes
+ writeAttributeDecl(Uml::Visibility::Private, true); // write static attributes first
+ writeAttributeDecl(Uml::Visibility::Private, false);
+ // associations
+ writeAssociationDecl(classifierInfo->plainAssociations, Uml::Visibility::Private,
+ c->getID(), "Associations");
+ writeAssociationDecl(classifierInfo->aggregations, Uml::Visibility::Private, c->getID(),
+ "Aggregations");
+ writeAssociationDecl(classifierInfo->compositions, Uml::Visibility::Private, c->getID(),
+ "Compositions");
+ //TODO writeHeaderAccessorMethodDecl(c, Uml::Visibility::Public, stream);
+ writeOperationHeader(c, Uml::Visibility::Private);
+ writeInitAttributeHeader(); // this is always private, used by constructors to initialize class
+
+ // end of class header
+ m_indentLevel--;
+ writeCode("};# end of class");
+
+ // end of class namespace, if any
+ m_indentLevel--;
+ writeCode("};# end of namespace");
+}
+
+void
+TclWriter::writeSourceFile(UMLClassifier * c, QFile & filetcl)
+{
+ // open stream for writing
+ QTextStream stream(&filetcl);
+ mStream = &stream;
+
+ // set the starting indentation at zero
+ m_indentLevel = 0;
+
+ //try to find a heading file (license, coments, etc)
+ QString str;
+ str = getHeadingFile(".tclbody");
+ if (!str.isEmpty()) {
+ str.replace(QRegExp("%filename%"), classifierInfo->fileName + "body");
+ str.replace(QRegExp("%filepath%"), filetcl.name());
+ writeCode(str);
+ }
+ // Start body of class
+
+ // constructors are first ops we print out
+ if (!classifierInfo->isInterface) {
+ writeConstructorSource();
+ writeDestructorSource();
+ }
+ // Public attributes have in tcl a configbody method
+ writeAttributeSource();
+ // Association access functions
+ writeAssociationSource(classifierInfo->plainAssociations, c->getID());
+ writeAssociationSource(classifierInfo->aggregations, c->getID());
+ writeAssociationSource(classifierInfo->compositions, c->getID());
+ // Procedures and methods
+ writeOperationSource(c, Uml::Visibility::Public);
+ writeOperationSource(c, Uml::Visibility::Protected);
+ writeOperationSource(c, Uml::Visibility::Private);
+ // Yep, bringing up the back of the bus, our initialization method for attributes
+ writeInitAttributeSource();
+}
+
+void
+TclWriter::writeCode(const QString &text)
+{
+ *mStream << getIndent() << text << m_endl;
+}
+
+void
+TclWriter::writeComm(const QString &text)
+{
+ QStringList lines = QStringList::split("\n", text, true);
+ for (uint i = 0; i < lines.count(); i++) {
+ *mStream << getIndent() << "# " << lines[i] << m_endl;
+ }
+}
+
+void
+TclWriter::writeDocu(const QString &text)
+{
+ QStringList lines = QStringList::split("\n", text, true);
+ for (uint i = 0; i < lines.count(); i++) {
+ *mStream << getIndent() << "## " << lines[i] << m_endl;
+ }
+}
+
+// To prevent circular including when both classifiers on either end
+// of an association have roles we need to have forward declaration of
+// the other class...but only IF its not THIS class (as could happen
+// in self-association relationship).
+void
+TclWriter::writeAssociationIncl(UMLAssociationList list, Uml::IDType myId,
+ const QString &type)
+{
+ for (UMLAssociation * a = list.first(); a; a = list.next()) {
+ UMLClassifier *classifier = NULL;
+
+ writeComm(m_endl + type + m_endl + a->toString() + m_endl + a->getDoc());
+ // only use OTHER classes (e.g. we don't need to write includes for ourselves!!
+ // AND only IF the roleName is defined, otherwise, its not meant to be noticed.
+ if (a->getObjectId(Uml::A) == myId && !a->getRoleName(Uml::B).isEmpty()) {
+ classifier = dynamic_cast < UMLClassifier * >(a->getObject(Uml::B));
+ writeUse(classifier);
+ } else if (a->getObjectId(Uml::B) == myId
+ && !a->getRoleName(Uml::A).isEmpty()) {
+ classifier = dynamic_cast < UMLClassifier * >(a->getObject(Uml::A));
+ if (classifier->getPackage().isEmpty())
+ writeCode("namespace eval " + cleanName(classifier->getName()) +
+ " {}");
+ } else {
+ // CHECK: This crashes (classifier still NULL from above)
+ /*
+ writeCode("namespace eval " + cleanName(classifier->getPackage()) +
+ "::" + cleanName(classifier->getName()) + " {}");
+ */
+ }
+ }
+}
+
+void
+TclWriter::writeUse(UMLClassifier * c)
+{
+ QString myNs;
+
+ if (!c->getPackage().isEmpty()) {
+ myNs = cleanName(c->getPackage());
+ } else {
+ myNs = "";
+ }
+ // if different package
+ if (("::"+myNs) != mNamespace) {
+ if (c->getPackage().isEmpty()) {
+ writeCode("source " + findFileName(c, ".tcl"));
+ writeCode("namespace import ::" + cleanName(c->getName()));
+ } else {
+ writeCode("package require " + myNs);
+ writeCode("namespace import ::" + myNs + "::" +
+ cleanName(c->getName()));
+ }
+ } else {
+ // source the file
+ writeCode("source " + findFileName(c, ".tcl"));
+ }
+}
+
+void
+TclWriter::writeConstructorHeader()
+{
+
+ writeDocu
+ (m_endl + "@func constructor" + m_endl +
+ "@par args contain all configuration parameters" + m_endl);
+
+ writeCode("constructor {args} {}" + m_endl);
+}
+
+void
+TclWriter::writeConstructorSource()
+{
+ writeComm(mClassGlobal + "::constructor");
+ writeCode(mClassGlobal + "::constructor {args} {");
+ m_indentLevel++;
+ if (classifierInfo->hasAttributes) {
+ writeCode("initAttributes");
+ }
+ writeCode("eval configure $args");
+ m_indentLevel--;
+ writeCode('}' + m_endl);
+}
+
+void
+TclWriter::writeDestructorHeader()
+{
+
+ writeDocu(m_endl + "@func destructor" + m_endl);
+
+ writeCode("destructor {} {}");
+}
+
+void
+TclWriter::writeDestructorSource()
+{
+ writeComm(mClassGlobal + "::destructor");
+ writeCode(mClassGlobal + "::destructor {} {" + m_endl + '}' + m_endl);
+}
+
+void
+TclWriter::writeAttributeDecl(Uml::Visibility visibility, bool writeStatic)
+{
+ if (classifierInfo->isInterface)
+ return;
+
+ QString scope = visibility.toString();
+ QString type;
+ if (writeStatic) {
+ type = "common";
+ } else {
+ type = "variable";
+ }
+ UMLAttributeList *list = NULL;
+ switch (visibility) {
+ case Uml::Visibility::Private:
+ if (writeStatic) {
+ list = &(classifierInfo->static_atpriv);
+ } else {
+ list = &(classifierInfo->atpriv);
+ }
+ break;
+
+ case Uml::Visibility::Protected:
+ if (writeStatic) {
+ list = &(classifierInfo->static_atprot);
+ } else {
+ list = &(classifierInfo->atprot);
+ }
+ break;
+
+ case Uml::Visibility::Public:
+ if (writeStatic) {
+ list = &(classifierInfo->static_atpub);
+ } else {
+ list = &(classifierInfo->atpub);
+ }
+ break;
+ default:
+ break;
+ }
+
+ if (list && list->count() > 0) {
+ writeComm(m_endl + scope + ' ' + type + " attributes" + m_endl);
+ // write attrib declarations now
+ QString documentation;
+ for (UMLAttribute * at = list->first(); at; at = list->next()) {
+ documentation = at->getDoc();
+ QString varName = cleanName(at->getName());
+ QString typeName = fixTypeName(at->getTypeName());
+ writeDocu(m_endl + "@var " + scope + ' ' + type + ' ' + typeName + ' ' +
+ varName + m_endl + documentation);
+ writeCode(scope + ' ' + type + ' ' + varName + m_endl);
+ }
+ }
+}
+
+void
+TclWriter::writeAssociationDecl(UMLAssociationList associations,
+ Uml::Visibility permitScope, Uml::IDType id,
+ const QString &/*type*/)
+{
+ if (forceSections() || !associations.isEmpty()) {
+ bool printRoleA = false, printRoleB = false;
+ for (UMLAssociation * a = associations.first(); a;
+ a = associations.next()) {
+
+ // it may seem counter intuitive, but you want to insert the role of the
+ // *other* class into *this* class.
+ if (a->getObjectId(Uml::A) == id && !a->getRoleName(Uml::B).isEmpty())
+ printRoleB = true;
+
+ if (a->getObjectId(Uml::B) == id && !a->getRoleName(Uml::A).isEmpty())
+ printRoleA = true;
+
+ // First: we insert documentaion for association IF it has either role AND some documentation (!)
+ // print RoleB decl
+ if (printRoleB && a->getVisibility(Uml::B) == permitScope) {
+
+ QString fieldClassName =
+ cleanName(getUMLObjectName(a->getObject(Uml::B)));
+ writeAssociationRoleDecl(fieldClassName, a->getRoleName(Uml::B),
+ a->getMulti(Uml::B), a->getRoleDoc(Uml::B),
+ permitScope.toString());
+ }
+ // print RoleA decl
+ if (printRoleA && a->getVisibility(Uml::A) == permitScope) {
+ QString fieldClassName =
+ cleanName(getUMLObjectName(a->getObject(Uml::A)));
+ writeAssociationRoleDecl(fieldClassName, a->getRoleName(Uml::A),
+ a->getMulti(Uml::A), a->getRoleDoc(Uml::A),
+ permitScope.toString());
+ }
+ // reset for next association in our loop
+ printRoleA = false;
+ printRoleB = false;
+ }
+ }
+}
+
+void
+TclWriter::writeAssociationRoleDecl(const QString &fieldClassName, const QString &roleName,
+ const QString &multi, const QString &doc, const QString &scope)
+{
+ // ONLY write out IF there is a rolename given
+ // otherwise its not meant to be declared in the code
+ if (roleName.isEmpty())
+ return;
+
+
+ // declare the association based on whether it is this a single variable
+ // or a List (Vector). One day this will be done correctly with special
+ // multiplicity object that we don't have to figure out what it means via regex.
+ if (multi.isEmpty() || multi.contains(QRegExp("^[01]$"))) {
+ QString fieldVarName = roleName.lower();
+
+ // record this for later consideration of initialization IF the
+ // multi value requires 1 of these objects
+ if (ObjectFieldVariables.findIndex(fieldVarName) == -1 &&
+ multi.contains(QRegExp("^1$"))
+ ) {
+ // ugh. UGLY. Storing variable name and its class in pairs.
+ ObjectFieldVariables.append(fieldVarName);
+ ObjectFieldVariables.append(fieldClassName);
+ }
+ writeDocu(m_endl + "@var " + scope + " variable <" + fieldClassName +
+ "> " + fieldVarName + m_endl + doc);
+ writeCode(scope + " variable " + fieldVarName + m_endl);
+ } else {
+ QString fieldVarName = roleName.lower();
+
+ // record unique occurrences for later when we want to check
+ // for initialization of this vector
+ if (VectorFieldVariables.findIndex(fieldVarName) == -1)
+ VectorFieldVariables.append(fieldVarName);
+ writeDocu(m_endl + "@var" + scope + " variable <" + fieldClassName +
+ "*> " + fieldVarName + m_endl + doc);
+ writeCode(scope + " variable " + fieldVarName + m_endl);
+ }
+}
+
+void
+TclWriter::writeInitAttributeHeader()
+{
+ if (classifierInfo->hasAttributes) {
+ writeDocu("@method private initAttributes" + m_endl +
+ "Initialize all internal variables");
+ writeCode("private method initAttributes {}");
+ }
+}
+
+void
+TclWriter::writeInitAttributeSource()
+{
+ // only need to do this under certain conditions
+ if (classifierInfo->hasAttributes) {
+ QString varName;
+
+ writeComm(mClassGlobal + "::initAttributes");
+ writeCode("body " + mClassGlobal + "::initAttributes {} {");
+ m_indentLevel++;
+
+ // first, initiation of fields derived from attributes
+ UMLAttributeList atl = classifierInfo->getAttList();
+ for (UMLAttribute * at = atl.first(); at; at = atl.next()) {
+ if (!at->getInitialValue().isEmpty()) {
+ varName = cleanName(at->getName());
+ writeCode("set " + varName + ' ' + at->getInitialValue());
+ }
+ }
+ // Now initialize the association related fields (e.g. vectors)
+ QStringList::Iterator it;
+ for (it = VectorFieldVariables.begin();
+ it != VectorFieldVariables.end(); ++it) {
+ varName = *it;
+ writeCode("set " + varName + " [list]");
+ }
+
+ for (it = ObjectFieldVariables.begin();
+ it != ObjectFieldVariables.end(); ++it) {
+ varName = *it;
+ it++;
+ QString fieldClassName = *it;
+ writeCode("set " + varName + " [list]");
+ }
+ // clean up
+ ObjectFieldVariables.clear(); // shouldn't be needed?
+ VectorFieldVariables.clear(); // shouldn't be needed?
+
+ m_indentLevel--;
+ writeCode('}' + m_endl);
+ }
+}
+
+void
+TclWriter::writeOperationHeader(UMLClassifier * c, Uml::Visibility permitScope)
+{
+
+ UMLOperationList oplist;
+ UMLOperation *op;
+ UMLAttribute *at;
+ int j;
+
+ //sort operations by scope first and see if there are abstract methods
+ UMLOperationList inputlist = c->getOpList();
+ for (UMLOperation * op = inputlist.first(); op; op = inputlist.next()) {
+ switch (op->getVisibility()) {
+ case Uml::Visibility::Public:
+ if (permitScope == Uml::Visibility::Public)
+ oplist.append(op);
+ break;
+ case Uml::Visibility::Protected:
+ if (permitScope == Uml::Visibility::Protected)
+ oplist.append(op);
+ break;
+ case Uml::Visibility::Private:
+ if (permitScope == Uml::Visibility::Private)
+ oplist.append(op);
+ break;
+ default:
+ break;
+ }
+ }
+
+ // generate method decl for each operation given
+ if (oplist.count() > 0) {
+ writeComm("Operations");
+ }
+ for (op = oplist.first(); op; op = oplist.next()) {
+ QString doc = "";
+ QString code = "";
+ QString methodReturnType = fixTypeName(op->getTypeName());
+ QString name = cleanName(op->getName());
+ QString scope = permitScope.toString();
+ if (op->getAbstract() || classifierInfo->isInterface) {
+ //TODO declare abstract method as 'virtual'
+ // str += "virtual ";
+ }
+ // declaration for header file
+ if (op->getStatic()) {
+ doc = m_endl + "@fn " + scope + " proc " + name + m_endl;
+ code = scope + " proc " + name + " {";
+ } else {
+ doc = m_endl + "@fn " + scope + " method " + name + m_endl;
+ code = scope + " method " + name + " {";
+ }
+ // method parameters
+ UMLAttributeList atl = op->getParmList();
+ j = 0;
+ for (at = atl.first(); at; at = atl.next(), j++) {
+ QString typeName = fixTypeName(at->getTypeName());
+ QString atName = cleanName(at->getName());
+ if (at->getInitialValue().isEmpty()) {
+ doc +=
+ "@param " + typeName + ' ' + atName + m_endl + at->getDoc() +
+ m_endl;
+ code += ' ' + atName;
+ } else {
+ doc +=
+ "@param " + typeName + ' ' + atName + " (default=" +
+ at->getInitialValue() + ") " + m_endl + at->getDoc() + m_endl;
+ code += " {" + atName + ' ' + at->getInitialValue() + "} ";
+ }
+ }
+ if (methodReturnType != "void") {
+ doc += "@return " + methodReturnType + m_endl;
+ }
+ writeDocu(doc + op->getDoc());
+ writeCode(code + "} {}" + m_endl);
+ }
+}
+
+void
+TclWriter::writeOperationSource(UMLClassifier * c, Uml::Visibility permitScope)
+{
+
+ UMLOperationList oplist;
+ UMLOperation *op;
+ UMLAttribute *at;
+ int j;
+
+ //sort operations by scope first and see if there are abstract methods
+ UMLOperationList inputlist = c->getOpList();
+ for (UMLOperation * op = inputlist.first(); op; op = inputlist.next()) {
+ switch (op->getVisibility()) {
+ case Uml::Visibility::Public:
+ if (permitScope == Uml::Visibility::Public)
+ oplist.append(op);
+ break;
+ case Uml::Visibility::Protected:
+ if (permitScope == Uml::Visibility::Protected)
+ oplist.append(op);
+ break;
+ case Uml::Visibility::Private:
+ if (permitScope == Uml::Visibility::Private)
+ oplist.append(op);
+ break;
+ default:
+ break;
+ }
+ }
+
+ // generate source for each operation given
+ for (op = oplist.first(); op; op = oplist.next()) {
+ QString code = "";
+ QString methodReturnType = fixTypeName(op->getTypeName());
+ QString name;
+ // no code needed
+ if (op->getAbstract() || classifierInfo->isInterface) {
+ continue;
+ }
+ name = mClassGlobal + "::" + cleanName(op->getName());
+ writeComm(name);
+ code = "body " + name + " {";
+ // parameters
+ UMLAttributeList atl = op->getParmList();
+ j = 0;
+ for (at = atl.first(); at; at = atl.next(), j++) {
+ QString atName = cleanName(at->getName());
+ if (at->getInitialValue().isEmpty()) {
+ code += ' ' + atName;
+ } else {
+ code += " {" + atName + ' ' + at->getInitialValue() + "} ";
+ }
+ }
+ writeCode(code += "} {");
+ m_indentLevel++;
+ if (methodReturnType != "void") {
+ writeCode("return " + methodReturnType);
+ } else {
+ writeCode("return");
+ }
+ m_indentLevel--;
+ writeCode('}' + m_endl);
+ }
+}
+
+void
+TclWriter::writeAttributeSource()
+{
+ UMLAttributeList *list = &(classifierInfo->atpub);
+ UMLAttribute *at;
+ for (at = list->first(); at; at = list->next()) {
+ QString name = mClassGlobal + "::" + cleanName(at->getName());
+
+ writeComm(name);
+ writeCode("configbody " + name + " {} {" + m_endl + '}' + m_endl);
+ }
+}
+
+void
+TclWriter::writeAssociationSource(UMLAssociationList associations,
+ Uml::IDType id)
+{
+ if (associations.isEmpty()) {
+ return;
+ }
+
+ bool printRoleA = false, printRoleB = false;
+ for (UMLAssociation * a = associations.first(); a; a = associations.next()) {
+
+ // it may seem counter intuitive, but you want to insert the role of the
+ // *other* class into *this* class.
+ if (a->getObjectId(Uml::A) == id && !a->getRoleName(Uml::B).isEmpty())
+ printRoleB = true;
+
+ if (a->getObjectId(Uml::B) == id && !a->getRoleName(Uml::A).isEmpty())
+ printRoleA = true;
+
+ // print RoleB source
+ if (printRoleB && a->getVisibility(Uml::B) == Uml::Visibility::Public) {
+
+ QString fieldClassName =
+ cleanName(getUMLObjectName(a->getObject(Uml::B)));
+ writeAssociationRoleSource(fieldClassName, a->getRoleName(Uml::B),
+ a->getMulti(Uml::B));
+ }
+ // print RoleA source
+ if (printRoleA && a->getVisibility(Uml::A) == Uml::Visibility::Public) {
+ QString fieldClassName =
+ cleanName(getUMLObjectName(a->getObject(Uml::A)));
+ writeAssociationRoleSource(fieldClassName, a->getRoleName(Uml::A),
+ a->getMulti(Uml::A));
+ }
+ // reset for next association in our loop
+ printRoleA = false;
+ printRoleB = false;
+ }
+}
+
+void
+TclWriter::writeAssociationRoleSource(const QString &fieldClassName,
+ const QString &roleName, const QString &multi)
+{
+ // ONLY write out IF there is a rolename given
+ // otherwise its not meant to be declared in the code
+ if (roleName.isEmpty())
+ return;
+
+ // declare the association based on whether it is this a single variable
+ // or a List (Vector). One day this will be done correctly with special
+ // multiplicity object that we don't have to figure out what it means via regex.
+ if (multi.isEmpty() || multi.contains(QRegExp("^[01]$"))) {
+ QString fieldVarName = roleName.lower();
+
+ writeCode("configbody " + mClassGlobal + "::" + fieldVarName + " {} {");
+ m_indentLevel++;
+ writeCode("if {![$" + fieldVarName + " isa " + fieldClassName + "]} {");
+ m_indentLevel++;
+ writeCode("return -code error \"expected object of class: " +
+ fieldClassName + "\"");
+ m_indentLevel--;
+ writeCode("}");
+ m_indentLevel--;
+
+ } else {
+ QString fieldVarName = roleName.lower();
+
+ writeCode("configbody " + mClassGlobal + "::" + fieldVarName + " {} {");
+ m_indentLevel++;
+ writeCode("foreach myObj $" + fieldVarName + " {");
+ m_indentLevel++;
+ writeCode("if {![$myObj isa " + fieldClassName + "]} {");
+ m_indentLevel++;
+ writeCode("return -code error \"expected object of class: " +
+ fieldClassName + "\"");
+ m_indentLevel--;
+ writeCode("}");
+ m_indentLevel--;
+ writeCode("}");
+ m_indentLevel--;
+ }
+ writeCode('}' + m_endl);
+}
+
+QString
+TclWriter::fixTypeName(const QString &string)
+{
+ if (string.isEmpty())
+ return "void";
+ return string;
+}
+
+// methods like this _shouldn't_ be needed IF we properly did things thruought the code.
+QString
+TclWriter::getUMLObjectName(UMLObject * obj)
+{
+ return (obj != 0) ? obj->getName() : QString("NULL");
+}
+
+const QStringList
+TclWriter::reservedKeywords() const
+{
+ static QStringList keywords;
+
+ if (keywords.isEmpty())
+ {
+ for (int i = 0; tclwords[i]; i++)
+ keywords.append(tclwords[i]);
+ }
+ return keywords;
+}
+
diff --git a/umbrello/umbrello/codegenerators/tclwriter.h b/umbrello/umbrello/codegenerators/tclwriter.h
new file mode 100644
index 00000000..0c4d71c5
--- /dev/null
+++ b/umbrello/umbrello/codegenerators/tclwriter.h
@@ -0,0 +1,174 @@
+/***************************************************************************
+ tclwriter.h - description
+ -------------------
+ begin : Thu Jul 26 2005
+ copyright : (C) 2005 by Rene Meyer
+ email : rene.meyer@sturmit.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 TCLWRITER_H
+#define TCLWRITER_H
+
+#include <qstringlist.h>
+#include "simplecodegenerator.h"
+#include "../umloperationlist.h"
+#include "../umlattributelist.h"
+#include "../umlassociationlist.h"
+
+class QFile;
+class QTextStream;
+class ClassifierInfo;
+
+/**
+ * class TclWriter is a code generator for UMLClassifier objects.
+ * Create an instance of this class, and feed it a UMLClassifier when
+ * calling writeClass and it will generate both a header (.h) and
+ * source (.tcl) file for that classifier.
+ */
+class TclWriter : public SimpleCodeGenerator
+{
+public:
+
+ /**
+ * Constructor, initialises a couple of variables
+ */
+ TclWriter();
+
+ /**
+ * Destructor, empty
+ */
+ virtual ~ TclWriter();
+
+ /**
+ * call this method to generate tcl code for a UMLClassifier
+ * @param c the class to generate code for
+ */
+ virtual void writeClass(UMLClassifier * c);
+
+ /**
+ * returns "Tcl"
+ */
+ virtual Uml::Programming_Language getLanguage();
+
+ /**
+ * get list of reserved keywords
+ */
+ virtual const QStringList reservedKeywords() const;
+
+private:
+ /**
+ * Current output stream.
+ */
+ QTextStream * mStream;
+ /**
+ * write the header file for this classifier.
+ */
+ void writeHeaderFile(UMLClassifier * c, QFile & file);
+
+ /**
+ * write the source code body file for this classifier.
+ */
+ void writeSourceFile(UMLClassifier * c, QFile & file);
+
+ /**
+ * write the source codei text.
+ */
+ void writeCode(const QString &text);
+
+ /**
+ * write comment text.
+ */
+ void writeComm(const QString &text);
+
+ /**
+ * write documentation text.
+ */
+ void writeDocu(const QString &text);
+
+ void writeConstructorDecl();
+
+ void writeDestructorDecl();
+
+ /**
+ * Summary information about current classifier.
+ */
+ ClassifierInfo *classifierInfo;
+ QString mNamespace;
+ QString mClass;
+ QString mClassGlobal;
+
+ /**
+ * writes the Attribute declarations
+ * @param visibility the visibility of the attribs to print out
+ * @param writeStatic whether to write static or non-static attributes out
+ * @param stream text stream
+ */
+ void writeAttributeDecl(Uml::Visibility visibility, bool writeStatic);
+
+ void writeAssociationIncl(UMLAssociationList list,
+ Uml::IDType myId, const QString &type);
+ /**
+ * Searches a list of associations for appropriate ones to write out as attributes
+ */
+ void writeAssociationDecl(UMLAssociationList associations,
+ Uml::Visibility permit, Uml::IDType id,
+ const QString &type);
+
+ /**
+ * Writes out an association as an attribute using Vector
+ */
+ void writeAssociationRoleDecl(const QString &fieldClassName,
+ const QString &roleName, const QString &multi, const QString &doc, const QString &docname);
+
+ /**
+ * If needed, write out the declaration for the method to initialize attributes of our class.
+ */
+ void writeInitAttributeHeader();
+ void writeInitAttributeSource();
+
+ void writeConstructorHeader();
+ void writeConstructorSource();
+ void writeDestructorHeader();
+ void writeDestructorSource();
+ void writeOperationHeader(UMLClassifier * c,
+ Uml::Visibility permitScope);
+ void writeOperationSource(UMLClassifier * c,
+ Uml::Visibility permitScope);
+ void writeAttributeSource();
+ void writeAssociationSource(UMLAssociationList associations,
+ Uml::IDType id);
+ void writeAssociationRoleSource(const QString &fieldClassName,
+ const QString &roleName,
+ const QString &multi);
+ void writeUse(UMLClassifier * c);
+
+
+
+ /**
+ * Returns the name of the given object (if it exists)
+ */
+ QString getUMLObjectName(UMLObject * obj);
+
+ /**
+ * Replaces `string' with STRING_TYPENAME.
+ */
+ QString fixTypeName(const QString &string);
+
+ QStringList ObjectFieldVariables;
+ QStringList VectorFieldVariables;
+
+};
+
+
+
+#endif // TCLWRITER_H
diff --git a/umbrello/umbrello/codegenerators/xmlcodecomment.cpp b/umbrello/umbrello/codegenerators/xmlcodecomment.cpp
new file mode 100644
index 00000000..5f44620b
--- /dev/null
+++ b/umbrello/umbrello/codegenerators/xmlcodecomment.cpp
@@ -0,0 +1,67 @@
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * copyright (C) 2004-2007 *
+ * Umbrello UML Modeller Authors <uml-devel@uml.sf.net> *
+ ***************************************************************************/
+
+/* This code generated by:
+ * Author : thomas
+ * Date : Mon Sep 26 2003
+ */
+
+#include "xmlcodecomment.h"
+
+#include <kdebug.h>
+
+// Constructors/Destructors
+//
+
+XMLCodeComment::XMLCodeComment ( CodeDocument * doc, const QString & text )
+ : CodeComment (doc, text)
+{
+
+}
+
+XMLCodeComment::~XMLCodeComment ( ) { }
+
+//
+// Methods
+//
+
+
+// Accessor methods
+//
+
+// Other methods
+//
+
+/**
+ * @return QString
+ */
+QString XMLCodeComment::toString ( )
+{
+
+ QString output = "";
+
+ // simple output method
+ if(getWriteOutText())
+ {
+ QString indent = getIndentationString();
+ QString endLine = getNewLineEndingChars();
+ QString body = getText();
+ output.append(indent+"<!-- ");
+ if(!body.isEmpty())
+ output.append(formatMultiLineText (body, indent, endLine));
+ output.append(indent+"-->"+endLine);
+ }
+
+ return output;
+}
+
+
+#include "xmlcodecomment.moc"
diff --git a/umbrello/umbrello/codegenerators/xmlcodecomment.h b/umbrello/umbrello/codegenerators/xmlcodecomment.h
new file mode 100644
index 00000000..a30bcbab
--- /dev/null
+++ b/umbrello/umbrello/codegenerators/xmlcodecomment.h
@@ -0,0 +1,68 @@
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the 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 code generated by:
+ * Author : thomas
+ * Date : Mon Sep 26 2003
+ */
+
+
+
+#ifndef XMLCODECOMMENT_H
+#define XMLCODECOMMENT_H
+
+#include <qstring.h>
+#include "../codecomment.h"
+
+class CodeDocument;
+
+/**
+ * class XMLCodeDocumentation
+ * A XML (code) comment.
+ */
+
+class XMLCodeComment: virtual public CodeComment
+{
+ Q_OBJECT
+public:
+
+ // Constructors/Destructors
+ //
+
+
+ /**
+ * Constructors
+ */
+ explicit XMLCodeComment ( CodeDocument * doc, const QString & text = "" );
+
+ /**
+ * Empty Destructor
+ */
+ virtual ~XMLCodeComment( );
+
+ // Public attributes
+ //
+
+ // Other
+ //
+
+ /**
+ * @return QString
+ */
+ QString toString ( );
+
+
+protected:
+
+private:
+
+};
+
+#endif // XMLCODECOMMENT_H
diff --git a/umbrello/umbrello/codegenerators/xmlelementcodeblock.cpp b/umbrello/umbrello/codegenerators/xmlelementcodeblock.cpp
new file mode 100644
index 00000000..7e702619
--- /dev/null
+++ b/umbrello/umbrello/codegenerators/xmlelementcodeblock.cpp
@@ -0,0 +1,166 @@
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * copyright (C) 2004-2007 *
+ * Umbrello UML Modeller Authors <uml-devel@uml.sf.net> *
+ ***************************************************************************/
+
+/* This code generated by:
+ * Author : thomas
+ * Date : Wed Sep 26 2003
+ */
+
+// own header
+#include "xmlelementcodeblock.h"
+
+// qt/kde includes
+#include <kdebug.h>
+
+// local includes
+#include "xmlcodecomment.h"
+#include "../attribute.h"
+#include "../codedocument.h"
+
+// Constructors/Destructors
+//
+
+XMLElementCodeBlock::XMLElementCodeBlock ( CodeDocument * parentDoc, const QString & nodeName, const QString & comment)
+ : HierarchicalCodeBlock(parentDoc)
+{
+ init(parentDoc, nodeName, comment);
+}
+
+XMLElementCodeBlock::~XMLElementCodeBlock ( ) { }
+
+//
+// Methods
+//
+
+/**
+ * Save the XMI representation of this object
+ */
+void XMLElementCodeBlock::saveToXMI ( QDomDocument & doc, QDomElement & root ) {
+ QDomElement blockElement = doc.createElement( "xmlelementblock" );
+
+ setAttributesOnNode(doc, blockElement);
+
+ root.appendChild( blockElement );
+}
+
+/**
+ * load params from the appropriate XMI element node.
+ */
+void XMLElementCodeBlock::loadFromXMI ( QDomElement & root )
+{
+ setAttributesFromNode(root);
+}
+
+/** set attributes of the node that represents this class
+ * in the XMI document.
+ */
+void XMLElementCodeBlock::setAttributesOnNode ( QDomDocument & doc, QDomElement & docElement)
+{
+
+ // superclass call
+ HierarchicalCodeBlock::setAttributesOnNode(doc,docElement);
+
+ // now set local attributes/fields
+ docElement.setAttribute("nodeName",getNodeName());
+
+}
+
+/** set the class attributes of this object from
+ * the passed element node.
+ */
+void XMLElementCodeBlock::setAttributesFromNode ( QDomElement & root) {
+
+ // superclass call
+ HierarchicalCodeBlock::setAttributesFromNode(root);
+
+ // now set local attributes
+ setNodeName(root.attribute("nodeName","UNKNOWN"));
+
+}
+
+// Accessor methods
+//
+
+void XMLElementCodeBlock::setNodeName (const QString &name) {
+ m_nodeName = name;
+}
+
+QString XMLElementCodeBlock::getNodeName () {
+ return m_nodeName;
+}
+
+void XMLElementCodeBlock::addAttribute (UMLAttribute * at) {
+ m_attList.append(at);
+}
+
+UMLAttributeList * XMLElementCodeBlock::getAttributeList() {
+ return & m_attList;
+}
+
+
+// Other methods
+//
+
+/**
+ * update the start and end text for this ownedhierarchicalcodeblock.
+ */
+void XMLElementCodeBlock::updateContent ( )
+{
+
+ QString endLine = getNewLineEndingChars();
+
+ QString nodeName = getNodeName();
+
+ // Now update START/ENDING Text
+ QString startText = '<' + nodeName;
+ QString endText = "";
+
+ UMLAttributeList * alist = getAttributeList();
+ for (UMLAttribute *at = alist->first(); at; at=alist->next())
+ {
+ if(at->getInitialValue().isEmpty())
+ kWarning()<<" XMLElementCodeBlock : cant print out attribute that lacks an initial value"<<endl;
+ else {
+ startText.append(" " +at->getName()+"=\"");
+ startText.append(at->getInitialValue()+"\"");
+ }
+ }
+
+ // now set close of starting/ending node, the style depending on whether we have child text or not
+ if(getTextBlockList()->count())
+ {
+ startText.append(">");
+ endText = "</" + nodeName + '>';
+ } else {
+ startText.append("/>");
+ endText = "";
+ }
+
+ setStartText(startText);
+ setEndText(endText);
+
+}
+
+void XMLElementCodeBlock::init (CodeDocument *parentDoc, const QString &nodeName, const QString &comment)
+{
+
+ setComment(new XMLCodeComment(parentDoc));
+ getComment()->setText(comment);
+
+ m_nodeName = nodeName;
+
+ updateContent();
+
+}
+
+
+#include "xmlelementcodeblock.moc"
diff --git a/umbrello/umbrello/codegenerators/xmlelementcodeblock.h b/umbrello/umbrello/codegenerators/xmlelementcodeblock.h
new file mode 100644
index 00000000..b0acd277
--- /dev/null
+++ b/umbrello/umbrello/codegenerators/xmlelementcodeblock.h
@@ -0,0 +1,88 @@
+
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the 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 code generated by:
+ * Author : thomas
+ * Date : Wed Sep 26 2003
+ */
+
+#ifndef XMLELEMENTCODEBLOCK_H
+#define XMLELEMENTCODEBLOCK_H
+
+#include <qstring.h>
+
+#include "../umlattributelist.h"
+#include "../hierarchicalcodeblock.h"
+
+class CodeDocument;
+class UMLAttribute;
+
+class XMLElementCodeBlock : public HierarchicalCodeBlock
+{
+ Q_OBJECT
+public:
+
+ // Constructors/Destructors
+ //
+
+ /**
+ * Empty Constructor
+ */
+ XMLElementCodeBlock ( CodeDocument * parentDoc, const QString & nodeName, const QString & comment = "");
+
+ /**
+ * Empty Destructor
+ */
+ virtual ~XMLElementCodeBlock ( );
+
+ /**
+ * Save the XMI representation of this object
+ */
+ virtual void saveToXMI ( QDomDocument & doc, QDomElement & root );
+
+ /**
+ * load params from the appropriate XMI element node.
+ */
+ virtual void loadFromXMI ( QDomElement & root );
+
+ virtual UMLAttributeList * getAttributeList();
+
+ virtual void setNodeName (const QString &name);
+ virtual QString getNodeName ();
+
+ void addAttribute (UMLAttribute * at);
+
+protected:
+
+ /** set attributes of the node that represents this class
+ * in the XMI document.
+ */
+ virtual void setAttributesOnNode ( QDomDocument & doc, QDomElement & blockElement);
+
+ /** set the class attributes of this object from
+ * the passed element node.
+ */
+ virtual void setAttributesFromNode ( QDomElement & element);
+
+ /**
+ * Update the start/end text of this codeblock.
+ */
+ void updateContent ( );
+
+private:
+
+ UMLAttributeList m_attList;
+ QString m_nodeName;
+ void init (CodeDocument * parent, const QString &nodeName, const QString &comment);
+
+};
+
+#endif // XMLELEMENTCODEBLOCK_H
diff --git a/umbrello/umbrello/codegenerators/xmlschemawriter.cpp b/umbrello/umbrello/codegenerators/xmlschemawriter.cpp
new file mode 100644
index 00000000..303d3230
--- /dev/null
+++ b/umbrello/umbrello/codegenerators/xmlschemawriter.cpp
@@ -0,0 +1,809 @@
+/***************************************************************************
+ copyright : (C) 2003 Brian Thomas brian.thomas@gsfc.nasa.gov
+ (C) 2004-2006 Umbrello UML Modeller Authors <uml-devel@uml.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. *
+ * *
+ ***************************************************************************/
+
+#include "xmlschemawriter.h"
+
+#include <kdebug.h>
+
+#include <klocale.h>
+#include <kmessagebox.h>
+#include <qfile.h>
+#include <qtextstream.h>
+#include <qregexp.h>
+
+#include "../umldoc.h"
+#include "../classifier.h"
+#include "../operation.h"
+#include "../umlnamespace.h"
+
+// Constructor
+XMLSchemaWriter::XMLSchemaWriter()
+{
+
+ packageNamespaceTag = "tns";
+ packageNamespaceURI = "http://foo.example.com/";
+ schemaNamespaceTag = "xs";
+ schemaNamespaceURI = "http://www.w3.org/2001/XMLSchema";
+}
+
+// form of..."the Destructor"!!
+XMLSchemaWriter::~XMLSchemaWriter() {
+}
+
+/**
+ * returns "XMLSchema"
+ */
+Uml::Programming_Language XMLSchemaWriter::getLanguage() {
+ return Uml::pl_XMLSchema;
+}
+
+// main method for invoking..
+void XMLSchemaWriter::writeClass(UMLClassifier *c)
+{
+
+ if (!c) {
+ kDebug()<<"Cannot write class of NULL classifier!\n";
+ return;
+ }
+
+ // find an appropriate name for our file
+ QString fileName = findFileName(c,".xsd");
+
+ if (fileName.isEmpty()) {
+ emit codeGenerated(c, false);
+ return;
+ }
+
+ // check that we may open that file for writing
+ QFile file;
+ if ( !openFile(file, fileName) ) {
+ emit codeGenerated(c, false);
+ return;
+ }
+
+ QTextStream XMLschema(&file);
+
+ // set package namespace tag appropriately
+ if(!c->getPackage().isEmpty())
+ packageNamespaceTag = c->getPackage();
+
+ // START WRITING
+
+ // 0. FIRST THING: open the xml processing instruction. This MUST be
+ // the first thing in the file
+ XMLschema<<"<?xml version=\"1.0\"?>"<<m_endl;
+
+ // 1. create the header
+ QString headerText = getHeadingFile(".xsd");
+ if(!headerText.isEmpty()) {
+ headerText.replace(QRegExp("%filename%"),fileName);
+ headerText.replace(QRegExp("%filepath%"),file.name());
+ }
+ if(!headerText.isEmpty())
+ XMLschema<<headerText<<m_endl;
+
+ // 2. Open schema element node with appropriate namespace decl
+ XMLschema<<"<"<<makeSchemaTag("schema");
+ // common namespaces we know will be in the file..
+ XMLschema<<" targetNamespace=\""<<packageNamespaceURI+packageNamespaceTag<<"\""<<m_endl;
+ XMLschema<<" xmlns:"<<schemaNamespaceTag<<"=\""<<schemaNamespaceURI<<"\"";
+ XMLschema<<" xmlns:"<<packageNamespaceTag<<"=\""<<packageNamespaceURI+packageNamespaceTag<<"\"";
+
+ XMLschema<<">"<<m_endl; // close opening declaration
+
+ m_indentLevel++;
+
+ // 3? IMPORT statements -- do we need to do anything here? I suppose if
+ // our document has more than one package, which is possible, we are missing
+ // the correct import statements. Leave that for later at this time.
+ /*
+ //only import classes in a different package as this class
+ UMLPackageList imports;
+ findObjectsRelated(c,imports);
+ for(UMLPackage *con = imports.first(); con ; con = imports.next())
+ if(con->getPackage() != c->getPackage())
+ XMLschema<<"import "<<con->getPackage()<<"."<<cleanName(con->getName())<<";"<<m_endl;
+ */
+
+ // 4. BODY of the schema.
+ // start the writing by sending this classifier, the "root" for this particular
+ // schema, to writeClassifier method, which will subsequently call itself on all
+ // related classifiers and thus populate the schema.
+ writeClassifier(c, XMLschema);
+
+ // 5. What remains is to make the root node declaration
+ XMLschema<<m_endl;
+ writeElementDecl(getElementName(c), getElementTypeName(c), XMLschema);
+
+ // 6. Finished: now we may close schema decl
+ m_indentLevel--;
+ XMLschema<<getIndent()<<"</"<<makeSchemaTag("schema")<<">"<<m_endl; // finished.. close schema node
+
+ // bookeeping for code generation
+ emit codeGenerated(c, true);
+
+ // tidy up. no dangling open files please..
+ file.close();
+
+ // need to clear HERE, NOT in the destructor because we want each
+ // schema that we write to have all related classes.
+ writtenClassifiers.clear();
+}
+
+void XMLSchemaWriter::writeElementDecl( const QString &elementName, const QString &elementTypeName, QTextStream &XMLschema)
+{
+ if(forceDoc())
+ writeComment(elementName+" is the root element, declared here.", XMLschema);
+
+ XMLschema<<getIndent()<<"<"<<makeSchemaTag("element")
+ <<" name=\""<<elementName<<"\""
+ <<" type=\""<<makePackageTag(elementTypeName)<<"\""
+ <<"/>"<<m_endl;
+
+}
+
+void XMLSchemaWriter::writeClassifier (UMLClassifier *c, QTextStream &XMLschema)
+{
+
+ // NO doing this 2 or more times.
+ if(hasBeenWritten(c))
+ return;
+
+ XMLschema<<m_endl;
+
+ // write documentation for class, if any, first
+ if(forceDoc() || !c->getDoc().isEmpty())
+ writeComment(c->getDoc(),XMLschema);
+
+ if(c->getAbstract() || c->isInterface() )
+ writeAbstractClassifier(c,XMLschema); // if its an interface or abstract class
+ else
+ writeConcreteClassifier(c,XMLschema);
+
+}
+
+UMLAttributeList XMLSchemaWriter::findAttributes (UMLClassifier *c)
+{
+ // sort attributes by Scope
+ UMLAttributeList attribs;
+ attribs.setAutoDelete(false);
+
+ if (!c->isInterface()) {
+ UMLAttributeList atl = c->getAttributeList();
+ for(UMLAttribute *at=atl.first(); at ; at=atl.next()) {
+ switch(at->getVisibility())
+ {
+ case Uml::Visibility::Public:
+ case Uml::Visibility::Protected:
+ attribs.append(at);
+ break;
+ case Uml::Visibility::Private:
+ // DO NOTHING! no way to print in the schema
+ break;
+ default:
+ break;
+ }
+ }
+ }
+ return attribs;
+}
+
+// We have to do 2 things with abstract classifiers (e.g. abstract classes and interfaces)
+// which is to:
+// 1) declare it as a complexType so it may be inherited (I can see an option here: to NOT write
+// this complexType declaration IF the classifier itself isnt inherited by or is inheriting
+// from anything because no other element will use this complexType).
+// 2) Create a group so that elements, which obey the abstract class /interface may be placed in
+// aggregation with other elements (again, and option here to NOT write the group if no other
+// element use the interface in element aggregation)
+//
+
+void XMLSchemaWriter::writeAbstractClassifier (UMLClassifier *c, QTextStream &XMLschema)
+{
+
+ // preparations
+ UMLClassifierList subclasses = c->findSubClassConcepts(); // list of what inherits from us
+ UMLClassifierList superclasses = c->findSuperClassConcepts(); // list of what we inherit from
+
+ // write the main declaration
+ writeConcreteClassifier (c, XMLschema);
+ writeGroupClassifierDecl (c, subclasses, XMLschema);
+
+ markAsWritten(c);
+
+ // now go back and make sure all sub-classing nodes are declared
+ if(subclasses.count() > 0)
+ {
+
+ QString elementName = getElementName(c);
+ UMLAttributeList attribs = findAttributes(c);
+ QStringList attribGroups = findAttributeGroups(c);
+
+ writeAttributeGroupDecl(elementName, attribs, XMLschema);
+
+ // now write out inheriting classes, as needed
+ for(UMLClassifier * classifier = subclasses.first(); classifier; classifier = subclasses.next())
+ writeClassifier(classifier, XMLschema);
+ }
+
+ // write out any superclasses as needed
+ for(UMLClassifier *classifier = superclasses.first(); classifier; classifier = superclasses.next())
+ writeClassifier(classifier, XMLschema);
+
+}
+
+void XMLSchemaWriter::writeGroupClassifierDecl (UMLClassifier *c,
+ UMLClassifierList subclasses,
+ QTextStream &XMLschema)
+{
+
+ // name of class, subclassing classifiers
+ QString elementTypeName = getElementGroupTypeName(c);
+
+ // start Writing node but only if it has subclasses? Nah..right now put in empty group
+ XMLschema<<getIndent()<<"<"<<makeSchemaTag("group")<<" name=\""<<elementTypeName<<"\">"<<m_endl;
+ m_indentLevel++;
+
+ XMLschema<<getIndent()<<"<"<<makeSchemaTag("choice")<<">"<<m_endl;
+ m_indentLevel++;
+
+ for(UMLClassifier *classifier = subclasses.first(); classifier; classifier = subclasses.next()) {
+ writeAssociationRoleDecl(classifier, "1", XMLschema);
+ }
+
+ m_indentLevel--;
+ XMLschema<<getIndent()<<"</"<<makeSchemaTag("choice")<<">"<<m_endl;
+
+ m_indentLevel--;
+
+ // finish node
+ XMLschema<<getIndent()<<"</"<<makeSchemaTag("group")<<">"<<m_endl;
+
+}
+
+void XMLSchemaWriter::writeComplexTypeClassifierDecl (UMLClassifier *c,
+ UMLAssociationList associations,
+ UMLAssociationList aggregations,
+ UMLAssociationList compositions,
+ UMLClassifierList superclasses,
+ QTextStream &XMLschema)
+{
+
+ // Preparations
+ //
+
+ // sort attributes by Scope
+ UMLAttributeList attribs = findAttributes(c);
+ QStringList attribGroups = findAttributeGroups(c);
+
+ // test for relevant associations
+ bool hasAssociations = determineIfHasChildNodes(c);
+ bool hasSuperclass = superclasses.count()> 0;
+ bool hasAttributes = attribs.count() > 0 || attribGroups.count() > 0;
+
+ // START WRITING
+
+ // start body of element
+ QString elementTypeName = getElementTypeName(c);
+
+ XMLschema<<getIndent()<<"<"<<makeSchemaTag("complexType")<<" name=\""<<elementTypeName<<"\"";
+
+ if(hasAssociations || hasAttributes || hasSuperclass)
+ {
+
+ XMLschema<<">"<<m_endl;
+
+ m_indentLevel++;
+
+ if(hasSuperclass)
+ {
+ QString superClassName = getElementTypeName(superclasses.first());
+ XMLschema<<getIndent()<<"<"<<makeSchemaTag("complexContent")<<">"<<m_endl;
+
+ //PROBLEM: we only treat ONE superclass for inheritence.. bah.
+ m_indentLevel++;
+ XMLschema<<getIndent()<<"<"<<makeSchemaTag("extension")<<" base=\""<<makePackageTag(superClassName)
+ <<"\"";
+ if(hasAssociations || hasAttributes )
+ XMLschema<<">"<<m_endl;
+ else
+ XMLschema<<"/>"<<m_endl;
+
+ m_indentLevel++;
+ }
+
+ if(hasAssociations)
+ {
+ // Child Elements (from most associations)
+ //
+ bool didFirstOne = false;
+ didFirstOne = writeAssociationDecls(associations, true, didFirstOne, c->getID(), XMLschema);
+ didFirstOne = writeAssociationDecls(aggregations, false, didFirstOne, c->getID(), XMLschema);
+ didFirstOne = writeAssociationDecls(compositions, false, didFirstOne, c->getID(), XMLschema);
+
+ if (didFirstOne) {
+ m_indentLevel--;
+ XMLschema<<getIndent()<<"</"<<makeSchemaTag("sequence")<<">"<<m_endl;
+ }
+ }
+
+ // ATTRIBUTES
+ //
+ if(hasAttributes)
+ {
+ writeAttributeDecls(attribs, XMLschema);
+ for(uint i= 0; i < attribGroups.count(); i++)
+ XMLschema<<getIndent()<<"<"<<makeSchemaTag("attributeGroup")<<" ref=\""
+ <<makePackageTag(attribGroups[i])<<"\"/>"<<m_endl;
+ }
+
+ if(hasSuperclass)
+ {
+ m_indentLevel--;
+
+ if(hasAssociations || hasAttributes )
+ XMLschema<<getIndent()<<"</"<<makeSchemaTag("extension")<<">"<<m_endl;
+
+ m_indentLevel--;
+ XMLschema<<getIndent()<<"</"<<makeSchemaTag("complexContent")<<">"<<m_endl;
+ }
+
+ // close this element decl
+ m_indentLevel--;
+ XMLschema<<getIndent()<<"</"<<makeSchemaTag("complexType")<<">"<<m_endl;
+
+ } else
+ XMLschema<<"/>"<<m_endl; // empty node. just close this element decl
+
+}
+
+void XMLSchemaWriter::writeConcreteClassifier (UMLClassifier *c, QTextStream &XMLschema)
+{
+
+ // preparations.. gather information about this classifier
+ //
+ UMLClassifierList superclasses = c->findSuperClassConcepts(); // list of what inherits from us
+ UMLClassifierList subclasses = c->findSubClassConcepts(); // list of what we inherit from
+ UMLAssociationList aggregations = c->getAggregations();
+ UMLAssociationList compositions = c->getCompositions();
+ // BAD! only way to get "general" associations.
+ UMLAssociationList associations = c->getSpecificAssocs(Uml::at_Association);
+
+ // write the main declaration
+ writeComplexTypeClassifierDecl(c, associations, aggregations, compositions, superclasses, XMLschema);
+
+ markAsWritten(c);
+
+ // Now write out any child def's
+ writeChildObjsInAssociation(c, associations, XMLschema);
+ writeChildObjsInAssociation(c, aggregations, XMLschema);
+ writeChildObjsInAssociation(c, compositions, XMLschema);
+
+ // write out any superclasses as needed
+ for(UMLClassifier *classifier = superclasses.first(); classifier; classifier = superclasses.next())
+ writeClassifier(classifier, XMLschema);
+
+ // write out any subclasses as needed
+ for(UMLClassifier *classifier = subclasses.first(); classifier; classifier = subclasses.next())
+ writeClassifier(classifier, XMLschema);
+}
+
+// these exist for abstract classes only (which become xs:group nodes)
+QStringList XMLSchemaWriter::findAttributeGroups (UMLClassifier *c)
+{
+ // we need to look for any class we inherit from. IF these
+ // have attributes, then we need to notice
+ QStringList list;
+ UMLClassifierList superclasses = c->findSuperClassConcepts(); // list of what inherits from us
+ for(UMLClassifier *classifier = superclasses.first(); classifier; classifier = superclasses.next())
+ {
+ if(classifier->getAbstract())
+ {
+ // only classes have attributes..
+ if (!classifier->isInterface()) {
+ UMLAttributeList attribs = c->getAttributeList();
+ if (attribs.count() > 0)
+ list.append(getElementName(classifier)+"AttribGroupType");
+ }
+ }
+ }
+ return list;
+}
+
+bool XMLSchemaWriter::determineIfHasChildNodes( UMLClassifier *c)
+{
+ UMLObjectList aggList = findChildObjsInAssociations (c, c->getAggregations());
+ UMLObjectList compList = findChildObjsInAssociations (c, c->getCompositions());
+ UMLAssociationList associations = c->getSpecificAssocs(Uml::at_Association); // BAD! only way to get "general" associations.
+ UMLObjectList assocList = findChildObjsInAssociations (c, associations);
+ return aggList.count() > 0 || compList.count() > 0 || assocList.count() > 0;
+}
+
+void XMLSchemaWriter::writeChildObjsInAssociation (UMLClassifier *c,
+ UMLAssociationList assoc,
+ QTextStream &XMLschema)
+{
+
+ UMLObjectList list = findChildObjsInAssociations (c, assoc);
+ for(UMLObject * obj = list.first(); obj; obj = list.next())
+ {
+ UMLClassifier * thisClassifier = dynamic_cast<UMLClassifier*>(obj);
+ if(thisClassifier)
+ writeClassifier(thisClassifier, XMLschema);
+ }
+}
+
+bool XMLSchemaWriter::hasBeenWritten(UMLClassifier *c) {
+ if (writtenClassifiers.contains(c))
+ return true;
+ else
+ return false;
+}
+
+void XMLSchemaWriter::markAsWritten(UMLClassifier *c) {
+ writtenClassifiers.append(c);
+}
+
+void XMLSchemaWriter::writeAttributeDecls(UMLAttributeList &attribs, QTextStream &XMLschema )
+{
+
+ UMLAttribute *at;
+ for(at=attribs.first(); at; at=attribs.next())
+ {
+ writeAttributeDecl(at,XMLschema);
+ }
+
+}
+
+void XMLSchemaWriter::writeAttributeDecl(UMLAttribute *attrib, QTextStream &XMLschema )
+{
+
+ QString documentation = attrib->getDoc();
+ QString typeName = fixTypeName(attrib->getTypeName());
+ bool isStatic = attrib->getStatic();
+ QString initialValue = fixInitialStringDeclValue(attrib->getInitialValue(), typeName);
+
+ if(!documentation.isEmpty())
+ writeComment(documentation, XMLschema);
+
+ XMLschema<<getIndent()<<"<"<<makeSchemaTag("attribute")
+ <<" name=\""<<cleanName(attrib->getName())<<"\""
+ <<" type=\""<<typeName<<"\"";
+
+ // default value?
+ if(!initialValue.isEmpty())
+ {
+ // IF its static, then we use "fixed", otherwise, we use "default" decl.
+ // For the default decl, we _must_ use "optional" decl
+ if(isStatic)
+ XMLschema<<" use=\"required\" fixed=\""<<initialValue<<"\"";
+ else
+ XMLschema<<" use=\"optional\" default=\""<<initialValue<<"\"";
+ }
+
+ // finish decl
+ XMLschema<<"/>"<<m_endl;
+
+}
+
+void XMLSchemaWriter::writeAttributeGroupDecl (const QString &elementName, UMLAttributeList &attribs, QTextStream &XMLschema )
+{
+
+ if (attribs.count()> 0) {
+
+ // write a little documentation
+ writeComment("attributes for element "+elementName,XMLschema);
+
+ // open attribute group
+ XMLschema<<getIndent()<<"<"<<makeSchemaTag("attributeGroup")<<" name=\""<<elementName+"AttribGroupType"<<"\">"<<m_endl;
+
+ m_indentLevel++;
+
+ for( UMLAttribute *at=attribs.first(); at; at=attribs.next())
+ {
+ writeAttributeDecl(at,XMLschema);
+ }
+
+ m_indentLevel--;
+
+ // close attrib group node
+ XMLschema<<getIndent()<<"</"<<makeSchemaTag("attributeGroup")<<">"<<m_endl;
+ }
+}
+
+void XMLSchemaWriter::writeComment( const QString &comment, QTextStream &XMLschema )
+{
+ // in the case we have several line comment..
+ // NOTE: this part of the method has the problem of adopting UNIX newline,
+ // need to resolve for using with MAC/WinDoze eventually I assume
+ QString indent = getIndent();
+ XMLschema<<indent<<"<!-- ";
+ if (comment.contains(QRegExp("\n"))) {
+ XMLschema<<m_endl;
+ QStringList lines = QStringList::split( "\n", comment);
+ for(uint i= 0; i < lines.count(); i++)
+ XMLschema<<indent<<" "<<lines[i]<<m_endl;
+
+ XMLschema<<indent<<"-->"<<m_endl;
+ } else {
+ // this should be more fancy in the future, breaking it up into 80 char
+ // lines so that it doesn't look too bad
+ XMLschema<<comment<<" -->"<<m_endl;
+ }
+}
+
+// all that matters here is roleA, the role served by the children of this class
+// in any composition or aggregation association. In full associations, I have only
+// considered the case of "self" association, so it shouldn't matter if we use role A or
+// B to find the child class as long as we don't use BOTH roles. I bet this will fail
+// badly for someone using a plain association between 2 different classes. THAT should
+// be done, but isnt yet (this is why I have left role b code in for now). -b.t.
+bool XMLSchemaWriter::writeAssociationDecls(UMLAssociationList associations,
+ bool noRoleNameOK, bool didFirstOne, Uml::IDType id, QTextStream &XMLschema)
+{
+
+ if( !associations.isEmpty() )
+ {
+ bool printRoleA = false, printRoleB = false;
+
+ for(UMLAssociation *a = associations.first(); a; a = associations.next())
+ {
+ // it may seem counter intuitive, but you want to insert the role of the
+ // *other* class into *this* class.
+
+ if (a->getObjectId(Uml::A) == id && a->getVisibility(Uml::B) != Uml::Visibility::Private)
+ printRoleB = true;
+
+ if (a->getObjectId(Uml::B) == id && a->getVisibility(Uml::A) != Uml::Visibility::Private)
+ printRoleA = true;
+
+ // First: we insert documentaion for association IF it has either role
+ // AND some documentation (!)
+ if ((printRoleA || printRoleB) && !(a->getDoc().isEmpty()))
+ writeComment(a->getDoc(), XMLschema);
+
+ // opening for sequence
+ if(!didFirstOne && (printRoleA || printRoleB))
+ {
+ didFirstOne = true;
+ XMLschema<<getIndent()<<"<"<<makeSchemaTag("sequence")<<">"<<m_endl;
+ m_indentLevel++;
+ }
+
+ // print RoleB decl
+ /*
+ // As mentioned in the header comment for this method: this block of code is
+ // commented out for now as it will only be needed if/when plain associations
+ // between different classes are to be treated
+ if (printRoleB)
+ {
+ UMLClassifier *classifierB = dynamic_cast<UMLClassifier*>(a->getObjectB());
+ if (classifierB) {
+ // ONLY write out IF there is a rolename given
+ // otherwise its not meant to be declared
+ if (!a->getRoleNameB().isEmpty() || noRoleNameOK)
+ writeAssociationRoleDecl(classifierB, a->getMultiB(), XMLschema);
+ }
+ }
+ */
+
+ // print RoleA decl
+ if (printRoleA)
+ {
+ UMLClassifier *classifierA = dynamic_cast<UMLClassifier*>(a->getObject(Uml::A));
+ if (classifierA) {
+ // ONLY write out IF there is a rolename given
+ // otherwise its not meant to be declared
+ if (!a->getRoleName(Uml::A).isEmpty() || noRoleNameOK )
+ writeAssociationRoleDecl(classifierA, a->getMulti(Uml::A), XMLschema);
+ }
+ }
+ }
+
+ }
+
+ return didFirstOne;
+}
+
+UMLObjectList XMLSchemaWriter::findChildObjsInAssociations (UMLClassifier *c, UMLAssociationList associations)
+{
+ Uml::IDType id = c->getID();
+ UMLObjectList list;
+ for(UMLAssociation *a = associations.first(); a; a = associations.next())
+ {
+ if (a->getObjectId(Uml::A) == id
+ && a->getVisibility(Uml::B) != Uml::Visibility::Private
+ && !a->getRoleName(Uml::B).isEmpty()
+ )
+ list.append(a->getObject(Uml::B));
+
+ if (a->getObjectId(Uml::B) == id
+ && a->getVisibility(Uml::A) != Uml::Visibility::Private
+ && !a->getRoleName(Uml::A).isEmpty()
+ )
+ list.append(a->getObject(Uml::A));
+ }
+ return list;
+}
+
+void XMLSchemaWriter::writeAssociationRoleDecl( UMLClassifier *c, const QString &multi, QTextStream &XMLschema)
+{
+
+ bool isAbstract = c->getAbstract();
+ bool isInterface = c->isInterface();
+
+ QString elementName = getElementName(c);
+ QString doc = c->getDoc();
+
+ if (!doc.isEmpty())
+ writeComment(doc, XMLschema);
+
+
+ // Min/Max Occurs is based on whether it is this a single element
+ // or a List (maxoccurs>1). One day this will be done correctly with special
+ // multiplicity object that we don't have to figure out what it means via regex.
+ QString minOccurs = "0";
+ QString maxOccurs = "unbounded";
+ if (multi.isEmpty())
+ {
+ // in this case, association will only specify ONE element can exist
+ // as a child
+ minOccurs = "1";
+ maxOccurs = "1";
+ }
+ else
+ {
+ QStringList values = QStringList::split( QRegExp("[^\\d{1,}|\\*]"), multi);
+
+ // could use some improvement here.. for sequences like "0..1,3..5,10" we
+ // don't capture the whole "richness" of the multi. Instead we translate it
+ // now to minOccurs="0" maxOccurs="10"
+ if (values.count() > 0)
+ {
+ // populate both with the actual value as long as our value isnt an asterix
+ // In that case, use special value (from above)
+ if(values[0].contains(QRegExp("\\d{1,}")))
+ minOccurs = values[0]; // use first number in sequence
+
+ if(values[values.count()-1].contains(QRegExp("\\d{1,}")))
+ maxOccurs = values[values.count()-1]; // use only last number in sequence
+ }
+ }
+
+ // Now declare the class in the association as an element or group.
+ //
+ // In a semi-arbitrary way, we have decided to make abstract classes into
+ // "groups" and concrete classes into "complexTypes".
+ //
+ // This is because about the only thing you can do with an abstract
+ // class (err. node) is inherit from it with a "concrete" element. Therefore,
+ // in this manner, we need a group node for abstract classes to lay out the child
+ // element choices so that the child, concrete class may be plugged into whatever spot
+ // it parent could go. The tradeoff is that "group" nodes may not be extended, so the
+ // choices that you lay out here are it (e.g. no more nodes may inherit" from this group)
+ //
+ // The flipside for concrete classes is that we want to use them as elements in our document.
+ // Unfortunately, about all you can do with complexTypes in terms of inheritance, is to
+ // use these as the basis for a new node type. This is NOT full inheritence because the new
+ // class (err. element node) wont be able to go into the document where it parent went without
+ // you heavily editing the schema.
+ //
+ // Therefore, IF a group is abstract, but has no inheriting sub-classes, there are no choices, and its nigh
+ // on pointless to declare it as a group, in this special case, abstract classes get declared
+ // as complexTypes.
+ //
+ // Of course, in OO methodology, you should be able to inherit from
+ // any class, but schema just don't allow use to have full inheritence using either groups
+ // or complexTypes. Thus we have taken a middle rode. If someone wants to key me into a
+ // better way to represent this, I'd be happy to listen. =b.t.
+ //
+ // UPDATE: partial solution to the above: as of 13-Mar-2003 we now write BOTH a complexType
+ // AND a group declaration for interfaces AND classes which are inherited from.
+ //
+ if ((isAbstract || isInterface ) && c->findSubClassConcepts().count() > 0)
+ XMLschema<<getIndent()<<"<"<<makeSchemaTag("group")
+ <<" ref=\""<<makePackageTag(getElementGroupTypeName(c))<<"\"";
+ else
+ XMLschema<<getIndent()<<"<"<<makeSchemaTag("element")
+ <<" name=\""<<getElementName(c)<<"\""
+ <<" type=\""<<makePackageTag(getElementTypeName(c))<<"\"";
+
+ // min/max occurs
+ if (minOccurs != "1")
+ XMLschema<<" minOccurs=\""<<minOccurs<<"\"";
+
+ if (maxOccurs != "1")
+ XMLschema<<" maxOccurs=\""<<maxOccurs<<"\"";
+
+ // tidy up the node
+ XMLschema<<"/>"<<m_endl;
+
+}
+
+// IF the type is "string" we need to declare it as
+// the XMLSchema Object "String" (there is no string primative in XMLSchema).
+// Same thing again for "bool" to "boolean"
+QString XMLSchemaWriter::fixTypeName(const QString& string)
+{
+ // string.replace(QRegExp("^string$"),schemaNamespaceTag+":string");
+ // string.replace(QRegExp("^bool$"),schemaNamespaceTag+":boolean");
+ return schemaNamespaceTag + ':' + string;
+}
+
+QString XMLSchemaWriter::fixInitialStringDeclValue(QString value, const QString &type)
+{
+ // check for strings only
+ if (!value.isEmpty() && type == "xs:string") {
+ if (!value.startsWith("\""))
+ value.remove(0,1);
+ if (!value.endsWith("\""))
+ value.remove(value.length(),1);
+ }
+ return value;
+}
+
+QString XMLSchemaWriter::getElementName(UMLClassifier *c)
+{
+ return cleanName(c->getName());
+}
+
+QString XMLSchemaWriter::getElementTypeName(UMLClassifier *c)
+{
+ QString elementName = getElementName(c);
+ return elementName + "ComplexType";
+}
+
+QString XMLSchemaWriter::getElementGroupTypeName(UMLClassifier *c)
+{
+ QString elementName = getElementName(c);
+ return elementName + "GroupType";
+}
+
+QString XMLSchemaWriter::makePackageTag (QString tagName) {
+ tagName.prepend( packageNamespaceTag + ':');
+ return tagName;
+}
+
+QString XMLSchemaWriter::makeSchemaTag (QString tagName) {
+ tagName.prepend( schemaNamespaceTag + ':');
+ return tagName;
+}
+
+const QStringList XMLSchemaWriter::reservedKeywords() const {
+
+ static QStringList keywords;
+
+ if (keywords.isEmpty()) {
+ keywords << "ATTLIST"
+ << "CDATA"
+ << "DOCTYPE"
+ << "ELEMENT"
+ << "ENTITIES"
+ << "ENTITY"
+ << "ID"
+ << "IDREF"
+ << "IDREFS"
+ << "NMTOKEN"
+ << "NMTOKENS"
+ << "NOTATION"
+ << "PUBLIC"
+ << "SHORTREF"
+ << "SYSTEM"
+ << "USEMAP";
+ }
+
+ return keywords;
+}
+
+#include "xmlschemawriter.moc"
diff --git a/umbrello/umbrello/codegenerators/xmlschemawriter.h b/umbrello/umbrello/codegenerators/xmlschemawriter.h
new file mode 100644
index 00000000..caf9f906
--- /dev/null
+++ b/umbrello/umbrello/codegenerators/xmlschemawriter.h
@@ -0,0 +1,249 @@
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * copyright (C) 2003 Brian Thomas <brian.thomas@gsfc.nasa.gov> *
+ * copyright (C) 2004-2007 *
+ * Umbrello UML Modeller Authors <uml-devel@uml.sf.net> *
+ ***************************************************************************/
+
+#ifndef XMLSCHEMAWRITER_H
+#define XMLSCHEMAWRITER_H
+
+#include "../codegenerator.h"
+#include "../attribute.h"
+#include "../association.h"
+#include "../umlclassifierlist.h"
+#include "../umlattributelist.h"
+#include "../umlobjectlist.h"
+#include "../umlassociationlist.h"
+#include "simplecodegenerator.h"
+
+/**
+ * Class XMLSchemaWriter is a code generator for UMLClassifier objects.
+ * Create an instance of this class, and feed it a UMLClassifier when
+ * calling writeClass and it will generate a XMLschema source file for
+ * that concept
+ *
+ * Our basic approach is to map UMLClassifiers (classes/interfaces) into
+ * XML elements (or nodes). We declare these element in the schema either
+ * as complexType or as groups based on whether they are concrete or abstract
+ * in nature. This is not a perfect decision, but thats life with XML Schema...
+ * you cant fully represent Objects in the XML world ..yet. -b.t.
+ */
+
+class XMLSchemaWriter : public SimpleCodeGenerator
+{
+ Q_OBJECT
+public:
+
+ /**
+ * Constructor, initialises a couple of variables
+ */
+ XMLSchemaWriter();
+
+ /**
+ * Destructor, empty
+ */
+ virtual ~XMLSchemaWriter();
+
+ /**
+ * call this method to generate XMLschema code for a UMLClassifier
+ * @param c the class to generate code for
+ */
+ virtual void writeClass(UMLClassifier *c);
+
+ /**
+ * returns "XMLSchema"
+ */
+ virtual Uml::Programming_Language getLanguage();
+
+ /**
+ * get list of reserved keywords
+ */
+ virtual const QStringList reservedKeywords() const;
+
+private:
+
+ /**
+ * Writes concept's documentation then guts
+ */
+ void writeClassifier(UMLClassifier *c, QTextStream &XMLSchema);
+ void writeAbstractClassifier(UMLClassifier *c, QTextStream &XMLSchema);
+ void writeConcreteClassifier(UMLClassifier *c, QTextStream &XMLSchema);
+
+ /**
+ * write a <complexType> declaration for this classifier
+ */
+ void writeComplexTypeClassifierDecl(UMLClassifier *c,
+ UMLAssociationList associations,
+ UMLAssociationList aggregations,
+ UMLAssociationList compositions,
+ UMLClassifierList superclassifiers,
+ QTextStream &XMLSchema);
+
+ /**
+ * write a <group> declaration for this classifier. Used for interfaces to classes with
+ * inheriting children.
+ */
+ void writeGroupClassifierDecl(UMLClassifier *c,
+ UMLClassifierList superclassifiers,
+ QTextStream &XMLSchema);
+
+ /**
+ * find if the classifier would have any Child elements.
+ */
+ bool determineIfHasChildNodes( UMLClassifier *c);
+
+ /**
+ * write all attributes for a given class
+ * @param c the class for which we are generating code
+ * @param j the stream associated with the output file
+ */
+ void writeAttributes(UMLClassifier *c, QTextStream &j);
+
+ /**
+ * write an element declaration.
+ */
+ void writeElementDecl( const QString &elementName, const QString &elementTypeName, QTextStream &XMLschema);
+
+ /**
+ * writes the Attribute declarations
+ * @param attribs List of attributes
+ * @param XMLschema text stream
+ */
+ void writeAttributeDecls(UMLAttributeList &attribs, QTextStream &XMLschema );
+
+ /**
+ * write an element attribute.
+ */
+ void writeAttributeDecl(UMLAttribute *attrib, QTextStream &XMLschema );
+
+ /**
+ * Find all attributes for this concept.
+ */
+ UMLAttributeList findAttributes (UMLClassifier *c);
+
+ /**
+ * Discover the string name of all the attribute groups (which are child nodes)
+ * of this concept (err.. element)
+ */
+ QStringList findAttributeGroups (UMLClassifier *c);
+
+ /**
+ * Searches a list of associations for appropriate ones to write out as attributes.
+ * This works well for compositions, aggregations and self-associations but will
+ * not work right for plain associations between 2 different classes.
+ */
+ bool writeAssociationDecls(UMLAssociationList associations, bool noRoleOK, bool didOne,
+ Uml::IDType id, QTextStream &XMLschema);
+
+ /**
+ * Find all attributes that belong in group
+ */
+ void writeAttributeGroupDecl(const QString &elementName, UMLAttributeList &attribs, QTextStream &XMLschema );
+
+ /**
+ * Writes out an association as an attribute using Vector
+ */
+ void writeAssociationRoleDecl(UMLClassifier *c, const QString &multi, QTextStream &XMLschema);
+
+ /**
+ * Construct an element tag with the schema namespace
+ */
+ QString makeSchemaTag ( QString tagName );
+
+ /**
+ * Construct an element tag with the package namespace
+ */
+ QString makePackageTag ( QString tagName );
+
+ /**
+ * Writes a comment
+ */
+ void writeComment(const QString &text, QTextStream &XMLschema);
+
+ /**
+ * Find and return a list of child UMLObjects pointed to by the associations
+ * in this UMLClassifier.
+ */
+ UMLObjectList findChildObjsInAssociations (UMLClassifier *c, UMLAssociationList associations);
+
+ /**
+ * Replaces `string' with `String' and `bool' with `boolean'
+ */
+ QString fixTypeName(const QString& string);
+
+ /**
+ * check that initial values of strings DONT have quotes around them
+ * (we get double quoting then!!
+ */
+ QString fixInitialStringDeclValue( QString value, const QString &type);
+
+ /**
+ * Find the element node name for this concept.
+ */
+ QString getElementName(UMLClassifier *c);
+
+ /**
+ * Find the element node "type" name. Used in the "complexType" which
+ * might define that element node.
+ */
+ QString getElementTypeName(UMLClassifier *c);
+
+ /**
+ * Find the group node "type" name. Used for elements which define an interface/are abstract.
+ */
+ QString getElementGroupTypeName(UMLClassifier *c);
+
+ /**
+ * Find all the child objects in this association and make sure they get
+ * written out (if they havent already been)
+ */
+ void writeChildObjsInAssociation (UMLClassifier *c, UMLAssociationList assoc, QTextStream &s);
+
+ /**
+ * Quick check to see if we have written the declaration for this concept yet.
+ */
+ bool hasBeenWritten(UMLClassifier *c);
+
+ /**
+ * mark a concept as written, so it is not repeatedly re-declared in the schema
+ */
+ void markAsWritten(UMLClassifier *c);
+
+ /**
+ * The basic schemaNamespace tag
+ */
+ QString schemaNamespaceTag;
+
+ /**
+ * The basic schemaNamespace tag
+ */
+ QString packageNamespaceTag;
+
+ /*
+ * The basic schemaNamespace URI
+ */
+ QString schemaNamespaceURI;
+
+ /**
+ * The basic schemaNamespace URI
+ */
+ QString packageNamespaceURI;
+
+ /**
+ * A \n, used at the end of each line
+ */
+ QString startline;
+
+ /**
+ * a list of UMLClassifiers we have already written
+ */
+ UMLClassifierList writtenClassifiers;
+};
+
+#endif // XMLSCHEMAWRITER_H
diff --git a/umbrello/umbrello/codegenobjectwithtextblocks.cpp b/umbrello/umbrello/codegenobjectwithtextblocks.cpp
new file mode 100644
index 00000000..383c188f
--- /dev/null
+++ b/umbrello/umbrello/codegenobjectwithtextblocks.cpp
@@ -0,0 +1,517 @@
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * copyright (C) 2004-2007 *
+ * Umbrello UML Modeller Authors <uml-devel@uml.sf.net> *
+ ***************************************************************************/
+
+/* This code generated by:
+ * Author : thomas
+ * Date : Tue Aug 19 2003
+ */
+
+// own header
+#include "codegenobjectwithtextblocks.h"
+
+// qt/kde includes
+#include <kdebug.h>
+
+// local includes
+#include "umldoc.h"
+#include "codedocument.h"
+#include "codeoperation.h"
+#include "codegenerators/codegenfactory.h"
+#include "classifiercodedocument.h"
+#include "hierarchicalcodeblock.h"
+#include "uml.h"
+
+// Constructors/Destructors
+//
+
+CodeGenObjectWithTextBlocks::CodeGenObjectWithTextBlocks ( CodeDocument *parent )
+ : m_pCodeDoc(parent)
+{
+ initFields();
+}
+
+CodeGenObjectWithTextBlocks::~CodeGenObjectWithTextBlocks ( ) {
+ resetTextBlocks();
+ // delete all the text blocks we have
+ TextBlock *tb;
+ for (TextBlockListIt it(m_textblockVector); (tb = it.current()) != NULL; ++it)
+ delete tb;
+
+ m_textBlockTagMap.clear();
+ m_textblockVector.clear();
+}
+
+//
+// Methods
+//
+
+
+// Accessor methods
+//
+
+/**
+ * Get the list of TextBlock objects held by m_textblockVector
+ * @return QPtrList<TextBlock *> list of TextBlock objects held by
+ * m_textblockVector
+ */
+TextBlockList * CodeGenObjectWithTextBlocks::getTextBlockList ( ) {
+ return &m_textblockVector;
+}
+
+// Other methods
+//
+
+/**
+ * Add a TextBlock object to the m_textblockVector List
+ */
+bool CodeGenObjectWithTextBlocks::addTextBlock(TextBlock* add_object ) {
+
+ QString tag = add_object->getTag();
+
+ // assign a tag if one doesn't already exist
+ if(tag.isEmpty())
+ {
+ tag = getUniqueTag();
+ add_object->setTag(tag);
+ }
+ else
+ {
+
+ // if it has a tag, check to see that its not in some other parent object
+ // IF it is then we will need to remove it FIRST before adding to new parent
+ CodeDocument * parentDoc = add_object->getParentDocument();
+ if(parentDoc) {
+
+ CodeGenObjectWithTextBlocks * oldParent = parentDoc->findParentObjectForTaggedTextBlock (tag);
+ if(oldParent && oldParent != this)
+ oldParent->removeTextBlock(add_object);
+ }
+ }
+
+ if(m_textBlockTagMap.contains(tag))
+ return false; // return false, we already have some object with this tag in the list
+
+ // if we get here, then the object is a "fresh" one, we havent
+ // added before. Add it now and return true.
+ m_textBlockTagMap.insert(tag, add_object);
+ m_textblockVector.append(add_object);
+
+ return true;
+}
+
+/**
+ * Remove a TextBlock object from m_textblockVector List
+ */
+bool CodeGenObjectWithTextBlocks::removeTextBlock ( TextBlock * remove_object ) {
+
+ // check if we can remove it from our local list
+ if(!m_textblockVector.removeRef(remove_object))
+ {
+ // may be hiding in child hierarchical codeblock
+ TextBlock * tb;
+ for(TextBlockListIt it(m_textblockVector); (tb = it.current()) != NULL; ++it)
+ {
+ HierarchicalCodeBlock * hb = dynamic_cast<HierarchicalCodeBlock*>(tb);
+ if(hb && hb->removeTextBlock(remove_object))
+ return true;
+ }
+ }
+
+ // if we get here.. it was in this object so remove from our map
+ QString tag = remove_object->getTag();
+ if(!tag.isEmpty())
+ m_textBlockTagMap.erase(tag);
+
+ return true;
+}
+
+TextBlock * CodeGenObjectWithTextBlocks::findTextBlockByTag( const QString &tag )
+{
+ //if we already know to which file this class was written/should be written, just return it.
+ if(m_textBlockTagMap.contains(tag))
+ return m_textBlockTagMap[tag];
+
+ return (TextBlock*) NULL;
+}
+
+// IMPORTANT: this will only search for a parent from the viewpoint of this object
+// and down into its Hierarchical codeblocks. This means you should start any
+// search from the parent document of the text block. This method NOT meant for
+// casual usage.
+CodeGenObjectWithTextBlocks * CodeGenObjectWithTextBlocks::findParentObjectForTaggedTextBlock (const QString & tag) {
+
+ // what??!? no tag, then CANT be here
+ if(tag.isEmpty())
+ return (CodeGenObjectWithTextBlocks*) NULL;
+
+ if(!findTextBlockByTag(tag))
+ {
+ // may be hiding in child hierarchical codeblock
+ for(TextBlock * tb = m_textblockVector.first(); tb ; tb = m_textblockVector.next())
+ {
+ HierarchicalCodeBlock * hb = dynamic_cast<HierarchicalCodeBlock*>(tb);
+ if(hb) {
+ CodeGenObjectWithTextBlocks* cgowtb = dynamic_cast<CodeGenObjectWithTextBlocks*>(hb);
+ CodeGenObjectWithTextBlocks * obj = cgowtb->findParentObjectForTaggedTextBlock(tag);
+ if(obj)
+ return obj;
+ }
+ }
+
+ } else
+ return this;
+
+ // shouldn't happen unless the textblock doesn't exist in this object
+ // or its children at all
+ return (CodeGenObjectWithTextBlocks*) NULL;
+
+}
+
+/**
+ * @return HierarchicalCodeBlock
+ * @param tag
+ * @param comment
+ * @param indentLevel
+ */
+HierarchicalCodeBlock * CodeGenObjectWithTextBlocks::getHierarchicalCodeBlock ( const QString &tag, const QString &comment, int indentLevel ) {
+
+ // now actually declare the fields
+ HierarchicalCodeBlock * codeBlock = dynamic_cast<HierarchicalCodeBlock*>(findTextBlockByTag(tag));
+ if (!codeBlock) {
+ codeBlock = newHierarchicalCodeBlock();
+ codeBlock->setTag(tag);
+ codeBlock->setComment(CodeGenFactory::newCodeComment(m_pCodeDoc));
+ // don't write empty comments out
+ if(comment.isEmpty())
+ codeBlock->getComment()->setWriteOutText(false);
+
+ if(!addTextBlock(codeBlock))
+ {
+ delete codeBlock;
+ return (HierarchicalCodeBlock*) NULL;
+ }
+ }
+
+ codeBlock->setOverallIndentationLevel (indentLevel);
+ codeBlock->getComment()->setText(comment);
+
+ return codeBlock;
+}
+
+
+/**
+ * @return CodeBlockWithComments
+ * @param tag
+ * @param comment
+ * @param indentLevel
+ */
+CodeBlockWithComments * CodeGenObjectWithTextBlocks::getCodeBlockWithComments ( const QString &tag, const QString &comment, int indentLevel ) {
+
+ // now actually declare the fields
+ CodeBlockWithComments * codeBlock = dynamic_cast<CodeBlockWithComments*>(findTextBlockByTag(tag));
+ if (!codeBlock) {
+ codeBlock = newCodeBlockWithComments();
+ codeBlock->setTag(tag);
+ codeBlock->setComment(CodeGenFactory::newCodeComment(m_pCodeDoc));
+ // don't write empty comments out
+ if(comment.isEmpty())
+ codeBlock->getComment()->setWriteOutText(false);
+ if(!addTextBlock(codeBlock))
+ return (CodeBlockWithComments*) NULL;
+ }
+ codeBlock->setOverallIndentationLevel (indentLevel);
+ codeBlock->getComment()->setText(comment);
+
+ return codeBlock;
+
+}
+
+
+/**
+ * @return CodeComment
+ * @param tag
+ * @param text
+ * @param indentationLevel
+ */
+CodeComment * CodeGenObjectWithTextBlocks::addOrUpdateTaggedCodeComment ( const QString &tag, const QString &text, int indentationLevel)
+{
+
+ TextBlock * tBlock = findTextBlockByTag(tag);
+ CodeComment * codeComment = dynamic_cast<CodeComment*>(tBlock);
+ bool createdCodeComment = false;
+
+ if(!codeComment) {
+ createdCodeComment = true;
+ codeComment = CodeGenFactory::newCodeComment(m_pCodeDoc);
+ codeComment->setTag(tag);
+ if(!addTextBlock(codeComment))
+ {
+ delete codeComment;
+ return (CodeComment*) NULL; // hmm. total failure..,was there a preexisting comment with this tag?? lets return null
+ }
+ }
+
+ codeComment->setText(text);
+ if(createdCodeComment)
+ if(!text.isEmpty())
+ codeComment->setWriteOutText(true); // set to visible, if we created
+ else
+ codeComment->setWriteOutText(false); // set to not visible, if we created
+
+ codeComment->setIndentationLevel(indentationLevel);
+
+ return codeComment;
+}
+
+
+/**
+ * @return CodeBlockWithComments
+ * @param tag
+ * @param text
+ * @param comment
+ * @param indentLevel
+ * @param forceUserBlockUpdate
+ */
+CodeBlockWithComments * CodeGenObjectWithTextBlocks::addOrUpdateTaggedCodeBlockWithComments (const QString &tag, const QString &text, const QString &ctext, int indentLevel, bool forceUserBlockUpdate )
+{
+
+ TextBlock * tBlock = findTextBlockByTag(tag);
+ CodeBlockWithComments * codeBlock = dynamic_cast<CodeBlockWithComments*>(tBlock);
+ bool createdCodeBlock = false;
+
+ if(!codeBlock) {
+ createdCodeBlock = true;
+ codeBlock = newCodeBlockWithComments();
+ codeBlock->setTag(tag);
+ if(!addTextBlock(codeBlock))
+ {
+ delete codeBlock;
+ return (CodeBlockWithComments*) NULL; // hmm. total failure..,was there a preexisting codeblock with this tag?? lets return null
+ }
+ }
+
+ // ONLY update IF we are forcing the update of user blocks OR its an "AutoGenerated" Block
+ if(forceUserBlockUpdate || codeBlock->getContentType() == CodeBlock::AutoGenerated)
+ {
+
+ codeBlock->setText(text);
+ codeBlock->getComment()->setText(ctext);
+
+ // if we created this from scratch, make it write out only when the block isnt empty
+ if (createdCodeBlock)
+ {
+ if(!ctext.isEmpty())
+ codeBlock->getComment()->setWriteOutText(true);
+ else
+ codeBlock->getComment()->setWriteOutText(false);
+
+ if(!text.isEmpty())
+ codeBlock->setWriteOutText(true);
+ else
+ codeBlock->setWriteOutText(false);
+ }
+
+ codeBlock->setOverallIndentationLevel(indentLevel);
+
+ }
+
+ return codeBlock;
+
+}
+
+void CodeGenObjectWithTextBlocks::resetTextBlocks() {
+ TextBlock *tb;
+ for (TextBlockListIt it(m_textblockVector); (tb = it.current()) != NULL; ++it)
+ delete tb;
+ m_textBlockTagMap.clear();
+ m_textblockVector.clear();
+}
+
+
+void CodeGenObjectWithTextBlocks::setAttributesFromObject (CodeGenObjectWithTextBlocks * obj)
+{
+ TextBlockList * list = obj->getTextBlockList();
+ for (TextBlock * tb = list->first(); tb; tb=list->next())
+ {
+ // FIX : we need some functionality like
+ // loadChildTextBlocksFromObject(obj) here
+ }
+}
+
+void CodeGenObjectWithTextBlocks::setAttributesOnNode (QDomDocument & doc, QDomElement & root) {
+
+ // set a section to hold document content
+ QDomElement tblockElement = doc.createElement( "textblocks" );
+
+ // only concrete calls to textblocks are saved
+ TextBlockList * tbList = getTextBlockList();
+ for (TextBlock * block = tbList->first(); block; block= tbList->next())
+ block->saveToXMI(doc, tblockElement);
+
+ root.appendChild( tblockElement);
+
+}
+
+/** set the class attributes of this object from
+ * the passed element node.
+ */
+void CodeGenObjectWithTextBlocks::setAttributesFromNode ( QDomElement & root)
+{
+
+ // clear existing codeblocks
+ resetTextBlocks();
+
+ // now load em back in
+ loadChildTextBlocksFromNode(root);
+
+}
+
+// load text blocks
+// in this vanilla version, we only load comments and codeblocks
+// as they are the only instanciatable (vanilla) things
+// this method should be overridden if this class is inherited
+// by some other class that is concrete and takes children
+// derived from codeblock/codecomment
+void CodeGenObjectWithTextBlocks::loadChildTextBlocksFromNode ( QDomElement & root)
+{
+
+ QDomNode tnode = root.firstChild();
+ QDomElement telement = tnode.toElement();
+ bool loadCheckForChildrenOK = false;
+ while( !telement.isNull() ) {
+ QString nodeName = telement.tagName();
+
+ if( nodeName == "textblocks" ) {
+
+ QDomNode node = telement.firstChild();
+ QDomElement element = node.toElement();
+
+ // if there is nothing to begin with, then we don't worry about it
+ loadCheckForChildrenOK = element.isNull() ? true : false;
+
+ while( !element.isNull() ) {
+ QString name = element.tagName();
+
+ if( name == "codecomment" ) {
+ CodeComment * block = CodeGenFactory::newCodeComment(m_pCodeDoc);
+ block->loadFromXMI(element);
+ if(!addTextBlock(block))
+ {
+ kError()<<"loadFromXMI: unable to add codeComment to :"<<this<<endl;
+ delete block;
+ } else
+ loadCheckForChildrenOK= true;
+ } else
+ if( name == "codeaccessormethod" ||
+ name == "ccfdeclarationcodeblock"
+ ) {
+ QString acctag = element.attribute("tag","");
+ // search for our method in the
+ TextBlock * tb = findCodeClassFieldTextBlockByTag(acctag);
+ if(!tb || !addTextBlock(tb))
+ {
+ kError()<<"loadFromXMI : unable to add code accessor/decl method block (tag:"<<acctag<<") to:"<<this<<endl;
+ // DON'T delete
+
+ } else
+ loadCheckForChildrenOK= true;
+
+ } else
+ if( name == "codeblock" ) {
+ CodeBlock * block = newCodeBlock();
+ block->loadFromXMI(element);
+ if(!addTextBlock(block))
+ {
+ kError()<<"loadFromXMI : unable to add codeBlock to :"<<this<<endl;
+ delete block;
+ } else
+ loadCheckForChildrenOK= true;
+ } else
+ if( name == "codeblockwithcomments" ) {
+ CodeBlockWithComments * block = newCodeBlockWithComments();
+ block->loadFromXMI(element);
+ if(!addTextBlock(block))
+ {
+ kError()<<"loadFromXMI : unable to add codeBlockwithcomments to:"<<this<<endl;
+ delete block;
+ } else
+ loadCheckForChildrenOK= true;
+ } else
+ if( name == "header" ) {
+ // do nothing.. this is treated elsewhere
+ } else
+ if( name == "hierarchicalcodeblock" ) {
+ HierarchicalCodeBlock * block = new HierarchicalCodeBlock(m_pCodeDoc);
+ block->loadFromXMI(element);
+ if(!addTextBlock(block))
+ {
+ kError()<<"loadFromXMI : unable to add hierarchicalcodeBlock to:"<<this<<endl;
+ delete block;
+ } else
+ loadCheckForChildrenOK= true;
+ } else
+ if( name == "codeoperation" ) {
+ // find the code operation by id
+ QString id = element.attribute("parent_id","-1");
+ UMLObject * obj = UMLApp::app()->getDocument()->findObjectById(STR2ID(id));
+ UMLOperation * op = dynamic_cast<UMLOperation*>(obj);
+ if(op) {
+ CodeOperation * block = CodeGenFactory::newCodeOperation(dynamic_cast<ClassifierCodeDocument*>(m_pCodeDoc), op);
+ block->loadFromXMI(element);
+ if(addTextBlock(block))
+ loadCheckForChildrenOK= true;
+ else
+ {
+ kError()<<"loadFromXMI : unable to add codeoperation to:"<<this<<endl;
+ delete block;
+ }
+ } else
+ kError()<<"loadFromXMI : unable to create codeoperation for obj id:"<<id<<endl;
+ }
+ /*
+ // only needed for extreme debugging conditions (E.g. making new codeclassdocument loader)
+ else
+ kWarning()<<" LoadFromXMI: Got strange tag in text block stack:"<<name.latin1()<<", ignorning"<<endl;
+ */
+
+ node = element.nextSibling();
+ element = node.toElement();
+ }
+ break;
+ }
+
+ tnode = telement.nextSibling();
+ telement = tnode.toElement();
+ }
+
+ if(!loadCheckForChildrenOK)
+ {
+ CodeDocument * test = dynamic_cast<CodeDocument*>(this);
+ if(test)
+ {
+ kWarning()<<" loadChildBlocks : unable to initialize any child blocks in doc: "<<test->getFileName()<<" "<<this<<endl;
+ } else {
+ HierarchicalCodeBlock * hb = dynamic_cast<HierarchicalCodeBlock*>(this);
+ if(hb)
+ kWarning()<<" loadChildBlocks : unable to initialize any child blocks in Hblock: "<<hb->getTag()<<" "<<this<<endl;
+ else
+ kDebug()<<" loadChildBlocks : unable to initialize any child blocks in UNKNOWN OBJ:"<<this<<endl;
+ }
+ }
+
+}
+
+void CodeGenObjectWithTextBlocks::initFields ( ) {
+
+ m_textblockVector.setAutoDelete(false);
+
+}
+
diff --git a/umbrello/umbrello/codegenobjectwithtextblocks.h b/umbrello/umbrello/codegenobjectwithtextblocks.h
new file mode 100644
index 00000000..4e784b07
--- /dev/null
+++ b/umbrello/umbrello/codegenobjectwithtextblocks.h
@@ -0,0 +1,192 @@
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * copyright (C) 2004-2006 *
+ * Umbrello UML Modeller Authors <uml-devel@uml.sf.net> *
+ ***************************************************************************/
+
+/* This code generated by:
+ * Author : thomas
+ * Date : Tue Aug 19 2003
+ */
+
+#ifndef CODEGENOBJECTWITHTEXTBLOCKS_H
+#define CODEGENOBJECTWITHTEXTBLOCKS_H
+
+#include <qmap.h>
+#include "codeaccessormethod.h"
+#include "textblocklist.h"
+
+class CodeBlock;
+class CodeBlockWithComments;
+class CodeClassField;
+class CodeComment;
+class CodeDocument;
+class HierarchicalCodeBlock;
+class TextBlock;
+
+
+/**
+ * class CodeGenObjectWithTextBlocks
+ * This abstract class is for code generator objects which 'own' text blocks.
+ */
+
+class CodeGenObjectWithTextBlocks
+{
+public:
+
+ // Constructors/Destructors
+ //
+
+ /**
+ * Constructor
+ */
+ CodeGenObjectWithTextBlocks ( CodeDocument *parent );
+
+ /**
+ * Empty Destructor
+ */
+ virtual ~CodeGenObjectWithTextBlocks ( );
+
+ /**
+ * Add a TextBlock object to the m_textblockVector List
+ * @return boolean value where false means not added because an TextBlock
+ * object with that tag already exists in this document.
+ */
+ virtual bool addTextBlock ( TextBlock * add_object );
+
+ /**
+ * Remove a TextBlock object from m_textblockVector List
+ */
+ virtual bool removeTextBlock ( TextBlock * remove_object );
+
+ /**
+ * Insert a new text block before/after the existing text block. Returns
+ * false if it cannot insert the textblock.
+ */
+ virtual bool insertTextBlock (TextBlock * newBlock, TextBlock * existingBlock, bool after) = 0;
+
+ /**
+ * Get the list of TextBlock objects held by m_textblockVector
+ * @return TextBlockList list of TextBlock objects held by m_textblockVector
+ */
+ TextBlockList * getTextBlockList ( );
+
+ /**
+ * Will get a hierarchicalcodeblock from the document with given tag. IF the codeblock
+ * doesn't exist, then it will create it at the end of the document textBlock
+ * list and pass back a reference.
+ * @return HierarchicalCodeBlock
+ * @param tag
+ * @param comment
+ * @param indentLevel
+ */
+ virtual HierarchicalCodeBlock * getHierarchicalCodeBlock ( const QString &tag, const QString &comment, int indentLevel );
+
+ /**
+ * Will get a codeblockwithcomments from the document with given tag. IF the codeblock
+ * doesn't exist, then it will create it at the end of the document textBlock
+ * list and pass back a reference.
+ * @return CodeBlockWithComments
+ * @param tag
+ * @param comment
+ * @param indentLevel
+ */
+ virtual CodeBlockWithComments * getCodeBlockWithComments ( const QString &tag, const QString &comment, int indentLevel );
+
+ /** allows the user to add a code comment to the end of the list
+ * of text blocks in this document OR, if a text block already exists
+ * with that tag, it will update it with the passed text as appropriate.
+ * @return codeblock/comment pointer to the object which was created/updated.
+ * @return CodeComment
+ * @param tag
+ * @param text
+ * @param indentationLevel
+ */
+ CodeComment * addOrUpdateTaggedCodeComment (const QString &tag = "", const QString &text = "", int indentationLevel = 0 );
+
+ /** allows the user to either add a code block with comments to the end of the list
+ * of text blocks in this document OR, if a text block already exists
+ * with that tag, it will update it with the passed text as appropriate.
+ * @return codeblock/comment pointer to the object which was created/updated.
+ * @return CodeBlockWithComments
+ * @param tag
+ * @param text
+ * @param comment
+ * @param indentLevel
+ * @param forceUserBlockUpdate
+ */
+ CodeBlockWithComments * addOrUpdateTaggedCodeBlockWithComments (const QString &tag, const QString &text, const QString &comment, int indentLevel, bool forceUserBlockUpdate );
+
+ /**
+ * @return TextBlock
+ * @param tag
+ */
+ virtual TextBlock * findTextBlockByTag ( const QString &tag );
+
+ /**
+ * @return QString
+ * @param prefix
+ */
+ virtual QString getUniqueTag (const QString& prefix = "" ) = 0;
+
+ /** Virtual methods that return a new code document objects.
+ */
+ virtual CodeBlock * newCodeBlock() = 0;
+ virtual CodeBlockWithComments * newCodeBlockWithComments() = 0;
+ virtual HierarchicalCodeBlock * newHierarchicalCodeBlock() = 0;
+
+ /** Find the direct parent for a given textblock. This
+ * may be any object which holds text blocks, e.g. a CodeGenObjectWithTextBlocks.
+ * @return parent object. Could return null if the textblock is missing from the
+ * branch of the document tree being examined.
+ */
+ CodeGenObjectWithTextBlocks * findParentObjectForTaggedTextBlock (const QString & tag);
+
+protected:
+
+ /** set attributes of the node that represents this class
+ * in the XMI document.
+ */
+ virtual void setAttributesOnNode (QDomDocument & doc, QDomElement & elem );
+
+ /** set the class attributes of this object from
+ * the passed element node.
+ */
+ virtual void setAttributesFromNode ( QDomElement & element);
+
+ virtual void setAttributesFromObject (CodeGenObjectWithTextBlocks * obj);
+
+ /**
+ * in this vanilla version, we only load comments and codeblocks
+ * as they are the only instanciatable (vanilla) things
+ * this method should be overridden if this class is inherited
+ * by some other class that is concrete and takes children
+ * derived from codeblock/codecomment/hierarchicalcb/ownedhiercodeblock
+ */
+ virtual void loadChildTextBlocksFromNode ( QDomElement & root);
+
+ // reset/clear the inventory text blocks held by this object
+ virtual void resetTextBlocks();
+
+ QMap<QString, TextBlock *> m_textBlockTagMap;
+ TextBlockList m_textblockVector;
+
+ // find specific text block belonging to code classfields.
+ // block may not presently be alocated t othe textblock list.
+ virtual TextBlock * findCodeClassFieldTextBlockByTag( const QString &tag) = 0;
+
+private:
+
+ void initFields ();
+
+ // needed in order to use findTextBlocksByTag
+ CodeDocument *m_pCodeDoc;
+
+};
+
+#endif // CODEGENOBJECTWITHTEXTBLOCKS_H
diff --git a/umbrello/umbrello/codeimport/Makefile.am b/umbrello/umbrello/codeimport/Makefile.am
new file mode 100644
index 00000000..5f821fab
--- /dev/null
+++ b/umbrello/umbrello/codeimport/Makefile.am
@@ -0,0 +1,6 @@
+INCLUDES = -I./kdevcppparser $(all_includes)
+
+noinst_LTLIBRARIES = libcodeimport.la
+libcodeimport_la_SOURCES = adaimport.cpp classimport.cpp cppimport.cpp idlimport.cpp import_utils.cpp javaimport.cpp nativeimportbase.cpp pascalimport.cpp pythonimport.cpp
+
+SUBDIRS = kdevcppparser
diff --git a/umbrello/umbrello/codeimport/adaimport.cpp b/umbrello/umbrello/codeimport/adaimport.cpp
new file mode 100644
index 00000000..54ac3907
--- /dev/null
+++ b/umbrello/umbrello/codeimport/adaimport.cpp
@@ -0,0 +1,588 @@
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * copyright (C) 2005-2007 *
+ * Umbrello UML Modeller Authors <uml-devel@uml.sf.net> *
+ ***************************************************************************/
+
+// own header
+#include "adaimport.h"
+
+#include <stdio.h>
+// qt/kde includes
+#include <qregexp.h>
+#include <kdebug.h>
+// app includes
+#include "import_utils.h"
+#include "../uml.h"
+#include "../umldoc.h"
+#include "../package.h"
+#include "../folder.h"
+#include "../classifier.h"
+#include "../enum.h"
+#include "../operation.h"
+#include "../attribute.h"
+#include "../association.h"
+
+AdaImport::AdaImport() : NativeImportBase("--") {
+ initVars();
+}
+
+AdaImport::~AdaImport() {
+}
+
+void AdaImport::initVars() {
+ m_inGenericFormalPart = false;
+ m_classesDefinedInThisScope.clear();
+ m_renaming.clear();
+}
+
+/// Split the line so that a string is returned as a single element of the list,
+/// when not in a string then split at white space.
+QStringList AdaImport::split(const QString& lin) {
+ QStringList list;
+ QString listElement;
+ bool inString = false;
+ bool seenSpace = false;
+ QString line = lin.stripWhiteSpace();
+ uint len = line.length();
+ for (uint i = 0; i < len; i++) {
+ const QChar& c = line[i];
+ if (inString) {
+ listElement += c;
+ if (c == '"') {
+ if (i < len - 1 && line[i + 1] == '"') {
+ i++; // escaped quotation mark
+ continue;
+ }
+ list.append(listElement);
+ listElement = QString();
+ inString = false;
+ }
+ } else if (c == '"') {
+ inString = true;
+ if (!listElement.isEmpty())
+ list.append(listElement);
+ listElement = QString(c);
+ seenSpace = false;
+ } else if (c == '\'') {
+ if (i < len - 2 && line[i + 2] == '\'') {
+ // character constant
+ if (!listElement.isEmpty())
+ list.append(listElement);
+ listElement = line.mid(i, 3);
+ i += 2;
+ list.append(listElement);
+ listElement = QString();
+ continue;
+ }
+ listElement += c;
+ seenSpace = false;
+ } else if (c.isSpace()) {
+ if (seenSpace)
+ continue;
+ seenSpace = true;
+ if (!listElement.isEmpty()) {
+ list.append(listElement);
+ listElement = QString();
+ }
+ } else {
+ listElement += c;
+ seenSpace = false;
+ }
+ }
+ if (!listElement.isEmpty())
+ list.append(listElement);
+ return list;
+}
+
+void AdaImport::fillSource(const QString& word) {
+ QString lexeme;
+ const uint len = word.length();
+ for (uint i = 0; i < len; i++) {
+ QChar c = word[i];
+ if (c.isLetterOrNumber() || c == '_' || c == '.' || c == '#') {
+ lexeme += c;
+ } else {
+ if (!lexeme.isEmpty()) {
+ m_source.append(lexeme);
+ lexeme = QString();
+ }
+ if (c == ':' && word[i + 1] == '=') {
+ m_source.append(":=");
+ i++;
+ } else {
+ m_source.append(QString(c));
+ }
+ }
+ }
+ if (!lexeme.isEmpty())
+ m_source.append(lexeme);
+}
+
+QString AdaImport::expand(const QString& name) {
+ QRegExp pfxRegExp("^(\\w+)\\.");
+ pfxRegExp.setCaseSensitive(false);
+ int pos = pfxRegExp.search(name);
+ if (pos == -1)
+ return name;
+ QString result = name;
+ QString pfx = pfxRegExp.cap(1);
+ if (m_renaming.contains(pfx)) {
+ result.remove(pfxRegExp);
+ result.prepend(m_renaming[pfx] + '.');
+ }
+ return result;
+}
+
+void AdaImport::parseStems(const QStringList& stems) {
+ if (stems.isEmpty())
+ return;
+ QString base = stems.first();
+ uint i = 0;
+ while (1) {
+ QString filename = base + ".ads";
+ if (! m_parsedFiles.contains(filename)) {
+ // Save current m_source and m_srcIndex.
+ QStringList source(m_source);
+ uint srcIndex = m_srcIndex;
+ m_source.clear();
+ parseFile(filename);
+ // Restore m_source and m_srcIndex.
+ m_source = source;
+ m_srcIndex = srcIndex;
+ // Also reset m_currentAccess.
+ // CHECK: need to reset more stuff?
+ m_currentAccess = Uml::Visibility::Public;
+ }
+ if (++i >= stems.count())
+ break;
+ base += '-' + stems[i];
+ }
+}
+
+bool AdaImport::parseStmt() {
+ const uint srcLength = m_source.count();
+ QString keyword = m_source[m_srcIndex];
+ UMLDoc *umldoc = UMLApp::app()->getDocument();
+ //kDebug() << '"' << keyword << '"' << endl;
+ if (keyword == "with") {
+ if (m_inGenericFormalPart) {
+ // mapping of generic formal subprograms or packages is not yet implemented
+ return false;
+ }
+ while (++m_srcIndex < srcLength && m_source[m_srcIndex] != ";") {
+ QStringList components = QStringList::split(".", m_source[m_srcIndex].lower());
+ const QString& prefix = components.first();
+ if (prefix == "system" || prefix == "ada" || prefix == "gnat" ||
+ prefix == "interfaces" || prefix == "text_io" ||
+ prefix == "unchecked_conversion" ||
+ prefix == "unchecked_deallocation") {
+ if (advance() != ",")
+ break;
+ continue;
+ }
+ parseStems(components);
+ if (advance() != ",")
+ break;
+ }
+ return true;
+ }
+ if (keyword == "generic") {
+ m_inGenericFormalPart = true;
+ return true;
+ }
+ if (keyword == "package") {
+ const QString& name = advance();
+ QStringList parentPkgs = QStringList::split(".", name.lower());
+ parentPkgs.pop_back(); // exclude the current package
+ parseStems(parentPkgs);
+ UMLObject *ns = NULL;
+ if (advance() == "is") {
+ ns = Import_Utils::createUMLObject(Uml::ot_Package, name,
+ m_scope[m_scopeIndex], m_comment);
+ if (m_source[m_srcIndex + 1] == "new") {
+ m_srcIndex++;
+ QString pkgName = advance();
+ UMLObject *gp = Import_Utils::createUMLObject(Uml::ot_Package, pkgName,
+ m_scope[m_scopeIndex]);
+ gp->setStereotype("generic");
+ // Add binding from instantiator to instantiatee
+ UMLAssociation *assoc = new UMLAssociation(Uml::at_Dependency, ns, gp);
+ assoc->setUMLPackage(umldoc->getRootFolder(Uml::mt_Logical));
+ assoc->setStereotype("bind");
+ // Work around missing display of stereotype in AssociationWidget:
+ assoc->setName(assoc->getStereotype(true));
+ umldoc->addAssociation(assoc);
+ skipStmt();
+ } else {
+ m_scope[++m_scopeIndex] = static_cast<UMLPackage*>(ns);
+ }
+ } else if (m_source[m_srcIndex] == "renames") {
+ m_renaming[name] = advance();
+ } else {
+ kError() << "AdaImport::parseStmt: unexpected: " << m_source[m_srcIndex] << endl;
+ skipStmt("is");
+ }
+ if (m_inGenericFormalPart) {
+ ns->setStereotype("generic");
+ m_inGenericFormalPart = false;
+ }
+ return true;
+ }
+ if (m_inGenericFormalPart)
+ return false; // skip generic formal parameter (not yet implemented)
+ if (keyword == "subtype") {
+ QString name = advance();
+ advance(); // "is"
+ QString base = expand(advance());
+ base.remove("Standard.", false);
+ UMLObject *type = umldoc->findUMLObject(base, Uml::ot_UMLObject, m_scope[m_scopeIndex]);
+ if (type == NULL) {
+ type = Import_Utils::createUMLObject(Uml::ot_Datatype, base, m_scope[m_scopeIndex]);
+ }
+ UMLObject *subtype = Import_Utils::createUMLObject(type->getBaseType(), name,
+ m_scope[m_scopeIndex], m_comment);
+ UMLAssociation *assoc = new UMLAssociation(Uml::at_Dependency, subtype, type);
+ assoc->setUMLPackage(umldoc->getRootFolder(Uml::mt_Logical));
+ assoc->setStereotype("subtype");
+ // Work around missing display of stereotype in AssociationWidget:
+ assoc->setName(assoc->getStereotype(true));
+ umldoc->addAssociation(assoc);
+ skipStmt();
+ return true;
+ }
+ if (keyword == "type") {
+ QString name = advance();
+ QString next = advance();
+ if (next == "(") {
+ kDebug() << "AdaImport::parseStmt(" << name << "): "
+ << "discriminant handling is not yet implemented" << endl;
+ // @todo Find out how to map discriminated record to UML.
+ // For now, we just create a pro forma empty record.
+ Import_Utils::createUMLObject(Uml::ot_Class, name, m_scope[m_scopeIndex],
+ m_comment, "record");
+ skipStmt("end");
+ if ((next = advance()) == "case")
+ m_srcIndex += 2; // skip "case" ";"
+ skipStmt();
+ return true;
+ }
+ if (next == ";") {
+ // forward declaration
+ Import_Utils::createUMLObject(Uml::ot_Class, name, m_scope[m_scopeIndex],
+ m_comment);
+ return true;
+ }
+ if (next != "is") {
+ kError() << "AdaImport::parseStmt: expecting \"is\"" << endl;
+ return false;
+ }
+ next = advance();
+ if (next == "(") {
+ // enum type
+ UMLObject *ns = Import_Utils::createUMLObject(Uml::ot_Enum,
+ name, m_scope[m_scopeIndex], m_comment);
+ UMLEnum *enumType = static_cast<UMLEnum*>(ns);
+ while ((next = advance()) != ")") {
+ Import_Utils::addEnumLiteral(enumType, next, m_comment);
+ m_comment = QString();
+ if (advance() != ",")
+ break;
+ }
+ skipStmt();
+ return true;
+ }
+ bool isTaggedType = false;
+ if (next == "abstract") {
+ m_isAbstract = true;
+ next = advance();
+ }
+ if (next == "tagged") {
+ isTaggedType = true;
+ next = advance();
+ }
+ if (next == "limited" ||
+ next == "task" ||
+ next == "protected" ||
+ next == "synchronized") {
+ next = advance(); // we can't (yet?) represent that
+ }
+ if (next == "private" ||
+ next == "interface" ||
+ next == "record" ||
+ (next == "null" &&
+ m_source[m_srcIndex+1] == "record")) {
+ Uml::Object_Type t = (next == "interface" ? Uml::ot_Interface : Uml::ot_Class);
+ UMLObject *ns = Import_Utils::createUMLObject(t, name, m_scope[m_scopeIndex], m_comment);
+ if (t == Uml::ot_Interface) {
+ while ((next = advance()) == "and") {
+ UMLClassifier *klass = static_cast<UMLClassifier*>(ns);
+ QString base = expand(advance());
+ UMLObject *p = Import_Utils::createUMLObject(Uml::ot_Interface, base, m_scope[m_scopeIndex]);
+ UMLClassifier *parent = static_cast<UMLClassifier*>(p);
+ Import_Utils::createGeneralization(klass, parent);
+ }
+ } else {
+ ns->setAbstract(m_isAbstract);
+ }
+ m_isAbstract = false;
+ if (isTaggedType) {
+ if (! m_classesDefinedInThisScope.contains(ns))
+ m_classesDefinedInThisScope.append(ns);
+ } else {
+ ns->setStereotype("record");
+ }
+ if (next == "record")
+ m_klass = static_cast<UMLClassifier*>(ns);
+ else
+ skipStmt();
+ return true;
+ }
+ if (next == "new") {
+ QString base = expand(advance());
+ QStringList baseInterfaces;
+ while ((next = advance()) == "and") {
+ baseInterfaces.append(expand(advance()));
+ }
+ const bool isExtension = (next == "with");
+ Uml::Object_Type t;
+ if (isExtension || m_isAbstract) {
+ t = Uml::ot_Class;
+ } else {
+ base.remove("Standard.", false);
+ UMLObject *known = umldoc->findUMLObject(base, Uml::ot_UMLObject, m_scope[m_scopeIndex]);
+ t = (known ? known->getBaseType() : Uml::ot_Datatype);
+ }
+ UMLObject *ns = Import_Utils::createUMLObject(t, base, NULL);
+ UMLClassifier *parent = static_cast<UMLClassifier*>(ns);
+ ns = Import_Utils::createUMLObject(t, name, m_scope[m_scopeIndex], m_comment);
+ if (isExtension) {
+ next = advance();
+ if (next == "null" || next == "record") {
+ UMLClassifier *klass = static_cast<UMLClassifier*>(ns);
+ Import_Utils::createGeneralization(klass, parent);
+ if (next == "record") {
+ // Set the m_klass for attributes.
+ m_klass = klass;
+ }
+ if (baseInterfaces.count()) {
+ t = Uml::ot_Interface;
+ QStringList::Iterator end(baseInterfaces.end());
+ for (QStringList::Iterator bi(baseInterfaces.begin()); bi != end; ++bi) {
+ ns = Import_Utils::createUMLObject(t, *bi, m_scope[m_scopeIndex]);
+ parent = static_cast<UMLClassifier*>(ns);
+ Import_Utils::createGeneralization(klass, parent);
+ }
+ }
+ }
+ }
+ skipStmt();
+ return true;
+ }
+ // Datatypes: TO BE DONE
+ return false;
+ }
+ if (keyword == "private") {
+ m_currentAccess = Uml::Visibility::Private;
+ return true;
+ }
+ if (keyword == "end") {
+ if (m_klass) {
+ if (advance() != "record") {
+ kError() << "end: expecting \"record\" at "
+ << m_source[m_srcIndex] << endl;
+ }
+ m_klass = NULL;
+ } else if (m_scopeIndex) {
+ if (advance() != ";") {
+ QString scopeName = m_scope[m_scopeIndex]->getFullyQualifiedName();
+ if (scopeName.lower() != m_source[m_srcIndex].lower())
+ kError() << "end: expecting " << scopeName << ", found "
+ << m_source[m_srcIndex] << endl;
+ }
+ m_scopeIndex--;
+ m_currentAccess = Uml::Visibility::Public; // @todo make a stack for this
+ } else {
+ kError() << "importAda: too many \"end\"" << endl;
+ }
+ skipStmt();
+ return true;
+ }
+ // subprogram
+ if (keyword == "not")
+ keyword = advance();
+ if (keyword == "overriding")
+ keyword = advance();
+ if (keyword == "function" || keyword == "procedure") {
+ const QString& name = advance();
+ QString returnType;
+ if (advance() != "(") {
+ // Unlike an Ada package, a UML package does not support
+ // subprograms.
+ // In order to map those, we would need to create a UML
+ // class with stereotype <<utility>> for the Ada package.
+ kDebug() << "ignoring parameterless " << keyword << " " << name << endl;
+ skipStmt();
+ return true;
+ }
+ UMLClassifier *klass = NULL;
+ UMLOperation *op = NULL;
+ const uint MAX_PARNAMES = 16;
+ while (m_srcIndex < srcLength && m_source[m_srcIndex] != ")") {
+ QString parName[MAX_PARNAMES];
+ uint parNameCount = 0;
+ do {
+ if (parNameCount >= MAX_PARNAMES) {
+ kError() << "MAX_PARNAMES is exceeded at " << name << endl;
+ break;
+ }
+ parName[parNameCount++] = advance();
+ } while (advance() == ",");
+ if (m_source[m_srcIndex] != ":") {
+ kError() << "importAda: expecting ':'" << endl;
+ skipStmt();
+ break;
+ }
+ const QString &direction = advance();
+ QString typeName;
+ Uml::Parameter_Direction dir = Uml::pd_In;
+ if (direction == "access") {
+ // Oops, we have to improvise here because there
+ // is no such thing as "access" in UML.
+ // So we use the next best thing, "inout".
+ // Better ideas, anyone?
+ dir = Uml::pd_InOut;
+ typeName = advance();
+ } else if (direction == "in") {
+ if (m_source[m_srcIndex + 1] == "out") {
+ dir = Uml::pd_InOut;
+ m_srcIndex++;
+ }
+ typeName = advance();
+ } else if (direction == "out") {
+ dir = Uml::pd_Out;
+ typeName = advance();
+ } else {
+ typeName = direction; // In Ada, the default direction is "in"
+ }
+ typeName.remove("Standard.", false);
+ typeName = expand(typeName);
+ if (op == NULL) {
+ // In Ada, the first parameter indicates the class.
+ UMLObject *type = Import_Utils::createUMLObject(Uml::ot_Class, typeName, m_scope[m_scopeIndex]);
+ Uml::Object_Type t = type->getBaseType();
+ if ((t != Uml::ot_Interface &&
+ (t != Uml::ot_Class || type->getStereotype() == "record")) ||
+ !m_classesDefinedInThisScope.contains(type)) {
+ // Not an instance bound method - we cannot represent it.
+ skipStmt(")");
+ break;
+ }
+ klass = static_cast<UMLClassifier*>(type);
+ op = Import_Utils::makeOperation(klass, name);
+ // The controlling parameter is suppressed.
+ parNameCount--;
+ if (parNameCount) {
+ for (uint i = 0; i < parNameCount; i++)
+ parName[i] = parName[i + 1];
+ }
+ }
+ for (uint i = 0; i < parNameCount; i++) {
+ UMLAttribute *att = Import_Utils::addMethodParameter(op, typeName, parName[i]);
+ att->setParmKind(dir);
+ }
+ if (advance() != ";")
+ break;
+ }
+ if (keyword == "function") {
+ if (advance() != "return") {
+ if (klass)
+ kError() << "importAda: expecting \"return\" at function "
+ << name << endl;
+ return false;
+ }
+ returnType = expand(advance());
+ returnType.remove("Standard.", false);
+ }
+ bool isAbstract = false;
+ if (advance() == "is" && advance() == "abstract")
+ isAbstract = true;
+ if (klass != NULL && op != NULL)
+ Import_Utils::insertMethod(klass, op, m_currentAccess, returnType,
+ false, isAbstract, false, false, m_comment);
+ skipStmt();
+ return true;
+ }
+ if (keyword == "task" || keyword == "protected") {
+ // Can task and protected objects/types be mapped to UML?
+ bool isType = false;
+ QString name = advance();
+ if (name == "type") {
+ isType = true;
+ name = advance();
+ }
+ QString next = advance();
+ if (next == "(") {
+ skipStmt(")"); // skip discriminant
+ next = advance();
+ }
+ if (next == "is")
+ skipStmt("end");
+ skipStmt();
+ return true;
+ }
+ if (keyword == "for") { // rep spec
+ QString typeName = advance();
+ QString next = advance();
+ if (next == "'") {
+ advance(); // skip qualifier
+ next = advance();
+ }
+ if (next == "use") {
+ if (advance() == "record")
+ skipStmt("end");
+ } else {
+ kError() << "importAda: expecting \"use\" at rep spec of "
+ << typeName << endl;
+ }
+ skipStmt();
+ return true;
+ }
+ // At this point we're only interested in attribute declarations.
+ if (m_klass == NULL || keyword == "null") {
+ skipStmt();
+ return true;
+ }
+ const QString& name = keyword;
+ if (advance() != ":") {
+ kError() << "adaImport: expecting \":\" at " << name << " "
+ << m_source[m_srcIndex] << endl;
+ skipStmt();
+ return true;
+ }
+ QString nextToken = advance();
+ if (nextToken == "aliased")
+ nextToken = advance();
+ QString typeName = expand(nextToken);
+ QString initialValue;
+ if (advance() == ":=") {
+ initialValue = advance();
+ QString token;
+ while ((token = advance()) != ";") {
+ initialValue.append(' ' + token);
+ }
+ }
+ UMLObject *o = Import_Utils::insertAttribute(m_klass, m_currentAccess, name,
+ typeName, m_comment);
+ UMLAttribute *attr = static_cast<UMLAttribute*>(o);
+ attr->setInitialValue(initialValue);
+ skipStmt();
+ return true;
+}
+
+
diff --git a/umbrello/umbrello/codeimport/adaimport.h b/umbrello/umbrello/codeimport/adaimport.h
new file mode 100644
index 00000000..14e41926
--- /dev/null
+++ b/umbrello/umbrello/codeimport/adaimport.h
@@ -0,0 +1,88 @@
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * copyright (C) 2005-2007 *
+ * Umbrello UML Modeller Authors <uml-devel@uml.sf.net> *
+ ***************************************************************************/
+
+#ifndef ADAIMPORT_H
+#define ADAIMPORT_H
+
+#include <qmap.h>
+#include <qstringlist.h>
+
+#include "nativeimportbase.h"
+#include "../umlobjectlist.h"
+
+/**
+ * Ada code import
+ * @author Oliver Kellogg
+ * Bugs and comments to uml-devel@lists.sf.net or http://bugs.kde.org
+ */
+class AdaImport : public NativeImportBase {
+public:
+ AdaImport();
+ virtual ~AdaImport();
+
+protected:
+ /**
+ * Reimplement operation from NativeImportBase.
+ */
+ void initVars();
+
+ /**
+ * Implement abstract operation from NativeImportBase.
+ */
+ bool parseStmt();
+
+ /**
+ * Split the line so that a string is returned as a single element of the list.
+ * When not in a string then split at white space.
+ * Reimplementation of method from NativeImportBase is required because of
+ * Ada's tic which is liable to be confused with the beginning of a character
+ * constant.
+ */
+ QStringList split(const QString& line);
+
+ /**
+ * Implement abstract operation from NativeImportBase.
+ */
+ void fillSource(const QString& word);
+
+ /**
+ * Apply package renamings to the given name.
+ *
+ * @return expanded name
+ */
+ QString expand(const QString& name);
+
+ /**
+ * Parse all files that can be formed by concatenation of the given stems.
+ */
+ void parseStems(const QStringList& stems);
+
+ bool m_inGenericFormalPart; ///< auxiliary variable
+
+ /**
+ * List for keeping track of tagged objects declared in the current scope.
+ * This is required for distinguishing primitive from non primitive
+ * methods.
+ */
+ UMLObjectList m_classesDefinedInThisScope;
+
+ typedef QMap<QString, QString> StringMap;
+
+ /**
+ * Map of package renamings.
+ * Keyed by the renaming. Value returns the expanded name.
+ */
+ StringMap m_renaming;
+
+};
+
+#endif
+
diff --git a/umbrello/umbrello/codeimport/classimport.cpp b/umbrello/umbrello/codeimport/classimport.cpp
new file mode 100644
index 00000000..ed675bda
--- /dev/null
+++ b/umbrello/umbrello/codeimport/classimport.cpp
@@ -0,0 +1,58 @@
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * copyright (C) 2006 *
+ * Umbrello UML Modeller Authors <uml-devel@uml.sf.net> *
+ ***************************************************************************/
+
+// own header
+#include "classimport.h"
+// qt/kde includes
+#include <qregexp.h>
+#include <klocale.h>
+// app includes
+#include "../umldoc.h"
+#include "../uml.h"
+#include "idlimport.h"
+#include "pythonimport.h"
+#include "javaimport.h"
+#include "adaimport.h"
+#include "pascalimport.h"
+#include "cppimport.h"
+
+void ClassImport::importFiles(const QStringList &fileList) {
+ initialize();
+ UMLDoc *umldoc = UMLApp::app()->getDocument();
+ uint processedFilesCount = 0;
+ for (QStringList::const_iterator fileIT = fileList.begin();
+ fileIT != fileList.end(); ++fileIT) {
+ QString fileName = (*fileIT);
+ umldoc->writeToStatusBar(i18n("Importing file: %1 Progress: %2/%3").
+ arg(fileName).arg(processedFilesCount).arg(fileList.size()));
+ parseFile(fileName);
+ processedFilesCount++;
+ }
+ umldoc->writeToStatusBar(i18n("Ready."));
+}
+
+ClassImport *ClassImport::createImporterByFileExt(const QString &filename) {
+ ClassImport *classImporter;
+ if (filename.endsWith(".idl"))
+ classImporter = new IDLImport();
+ else if (filename.endsWith(".py"))
+ classImporter = new PythonImport();
+ else if (filename.endsWith(".java"))
+ classImporter = new JavaImport();
+ else if (filename.contains( QRegExp("\\.ad[sba]$") ))
+ classImporter = new AdaImport();
+ else if (filename.endsWith(".pas"))
+ classImporter = new PascalImport();
+ else
+ classImporter = new CppImport(); // the default.
+ return classImporter;
+}
+
diff --git a/umbrello/umbrello/codeimport/classimport.h b/umbrello/umbrello/codeimport/classimport.h
new file mode 100644
index 00000000..351ddec5
--- /dev/null
+++ b/umbrello/umbrello/codeimport/classimport.h
@@ -0,0 +1,61 @@
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * copyright (C) 2005-2006 *
+ * Umbrello UML Modeller Authors <uml-devel@uml.sf.net> *
+ ***************************************************************************/
+
+#ifndef CLASSIMPORT_H
+#define CLASSIMPORT_H
+
+#include <qstringlist.h>
+
+/**
+ * Interfaces classparser library to uml models
+ * Abstract base for programming language specific import classes
+ * @author Mikko Pasanen
+ * @author Oliver Kellogg
+ * Bugs and comments to uml-devel@lists.sf.net or http://bugs.kde.org
+ */
+
+class ClassImport {
+public:
+ ClassImport() {}
+ virtual ~ClassImport() {}
+
+ /**
+ * Import files.
+ *
+ * @param files List of files to import.
+ */
+ void importFiles(const QStringList &files);
+
+ /**
+ * Factory method.
+ */
+ static ClassImport *createImporterByFileExt(const QString &filename);
+
+protected:
+ /**
+ * Initialize the importer.
+ * This is called by importFiles() once, before entering
+ * the loop for importing one or more files.
+ * To be implemented by inheriting classes.
+ */
+ virtual void initialize() = 0;
+
+ /**
+ * Import a single file.
+ * To be implemented by inheriting classes.
+ *
+ * @param filename The file to import.
+ */
+ virtual void parseFile(const QString& filename) = 0;
+
+};
+
+#endif
diff --git a/umbrello/umbrello/codeimport/cppimport.cpp b/umbrello/umbrello/codeimport/cppimport.cpp
new file mode 100644
index 00000000..4537c038
--- /dev/null
+++ b/umbrello/umbrello/codeimport/cppimport.cpp
@@ -0,0 +1,109 @@
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * copyright (C) 2005-2007 *
+ * Umbrello UML Modeller Authors <uml-devel@uml.sf.net> *
+ ***************************************************************************/
+
+// own header
+#include "cppimport.h"
+// qt/kde includes
+#include <qmap.h>
+#include <qregexp.h>
+#include <kmessagebox.h>
+#include <kdebug.h>
+// app includes
+#include "import_utils.h"
+#include "../umlobject.h"
+#include "../docwindow.h"
+#include "../package.h"
+#include "../enum.h"
+#include "../classifier.h"
+#include "../operation.h"
+#include "../attribute.h"
+#include "../template.h"
+#include "../association.h"
+#include "kdevcppparser/lexer.h"
+#include "kdevcppparser/driver.h"
+#include "kdevcppparser/cpptree2uml.h"
+
+// static members
+CppDriver * CppImport::ms_driver;
+QStringList CppImport::ms_seenFiles;
+
+class CppDriver : public Driver {
+public:
+ void setupLexer(Lexer* lexer) {
+ Driver::setupLexer(lexer);
+ lexer->setRecordComments(true);
+ }
+};
+
+CppImport::CppImport() {
+ ms_driver = new CppDriver();
+}
+
+CppImport::~CppImport() {}
+
+void CppImport::feedTheModel(const QString& fileName) {
+ if (ms_seenFiles.find(fileName) != ms_seenFiles.end())
+ return;
+ ms_seenFiles.append(fileName);
+ QMap<QString, Dependence> deps = ms_driver->dependences(fileName);
+ if (! deps.empty()) {
+ QMap<QString, Dependence>::Iterator it;
+ for (it = deps.begin(); it != deps.end(); ++it) {
+ if (it.data().second == Dep_Global) // don't want these
+ continue;
+ QString includeFile = it.key();
+ if (includeFile.isEmpty()) {
+ kError() << fileName << ": " << it.data().first
+ << " not found" << endl;
+ continue;
+ }
+ kDebug() << fileName << ": " << includeFile << " => " << it.data().first << endl;
+ if (ms_seenFiles.find(includeFile) == ms_seenFiles.end())
+ feedTheModel(includeFile);
+ }
+ }
+ TranslationUnitAST *ast = ms_driver->translationUnit( fileName );
+ if (ast == NULL) {
+ kError() << "CppImport::feedTheModel: " << fileName << " not found" << endl;
+ return;
+ }
+ CppTree2Uml modelFeeder( fileName );
+ modelFeeder.parseTranslationUnit( ast );
+}
+
+void CppImport::initialize() {
+ // Reset the driver
+ ms_driver->reset();
+ // The driver shall attempt to parse included files.
+ ms_driver->setResolveDependencesEnabled( true );
+ // Add some standard include paths
+ ms_driver->addIncludePath( "/usr/include" );
+ ms_driver->addIncludePath( "/usr/include/c++" );
+ ms_driver->addIncludePath( "/usr/include/g++" );
+ ms_driver->addIncludePath( "/usr/local/include" );
+ QStringList incPathList = Import_Utils::includePathList();
+ if (incPathList.count()) {
+ QStringList::Iterator end(incPathList.end());
+ for (QStringList::Iterator i(incPathList.begin()); i != end; ++i) {
+ ms_driver->addIncludePath( *i );
+ }
+
+ }
+ ms_seenFiles.clear();
+}
+
+void CppImport::parseFile(const QString& fileName) {
+ if (ms_seenFiles.find(fileName) != ms_seenFiles.end())
+ return;
+ ms_driver->parseFile( fileName );
+ feedTheModel(fileName);
+}
+
diff --git a/umbrello/umbrello/codeimport/cppimport.h b/umbrello/umbrello/codeimport/cppimport.h
new file mode 100644
index 00000000..3d5d8195
--- /dev/null
+++ b/umbrello/umbrello/codeimport/cppimport.h
@@ -0,0 +1,59 @@
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * copyright (C) 2005-2006 *
+ * Umbrello UML Modeller Authors <uml-devel@uml.sf.net> *
+ ***************************************************************************/
+
+#ifndef CPPIMPORT_H
+#define CPPIMPORT_H
+
+#include <qstring.h>
+#include "classimport.h"
+
+class CppDriver;
+
+/**
+ * C++ code import
+ * @author Oliver Kellogg
+ * Bugs and comments to uml-devel@lists.sf.net or http://bugs.kde.org
+ */
+
+class CppImport : public ClassImport {
+public:
+ CppImport();
+ virtual ~CppImport();
+
+protected:
+ /**
+ * Implement abstract operation from ClassImport for C++.
+ */
+ void initialize();
+
+ /**
+ * Import a single file.
+ *
+ * @param filename The file to import.
+ */
+ void parseFile(const QString& filename);
+
+private:
+ /**
+ * Auxiliary method for recursively traversing the #include dependencies
+ * in order to feed innermost includes to the model before dependent
+ * includes. It is important that includefiles are fed to the model
+ * in proper order so that references between UML objects are created
+ * properly.
+ */
+ void feedTheModel(const QString& fileName);
+
+ static CppDriver * ms_driver;
+ static QStringList ms_seenFiles; ///< auxiliary buffer for feedTheModel()
+
+};
+
+#endif
diff --git a/umbrello/umbrello/codeimport/idlimport.cpp b/umbrello/umbrello/codeimport/idlimport.cpp
new file mode 100644
index 00000000..6d228baf
--- /dev/null
+++ b/umbrello/umbrello/codeimport/idlimport.cpp
@@ -0,0 +1,356 @@
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * copyright (C) 2005 *
+ * Umbrello UML Modeller Authors <uml-devel@uml.sf.net> *
+ ***************************************************************************/
+
+// own header
+#include "idlimport.h"
+
+#include <stdio.h>
+// qt/kde includes
+// #include <qprocess.h> //should use this instead of popen()
+#include <qstringlist.h>
+#include <qregexp.h>
+#include <kdebug.h>
+// app includes
+#include "import_utils.h"
+#include "../uml.h"
+#include "../umldoc.h"
+#include "../umlpackagelist.h"
+#include "../package.h"
+#include "../classifier.h"
+#include "../enum.h"
+#include "../operation.h"
+#include "../attribute.h"
+
+IDLImport::IDLImport() : NativeImportBase("//") {
+ m_isOneway = m_isReadonly = m_isAttribute = false;
+ setMultiLineComment("/*", "*/");
+}
+
+IDLImport::~IDLImport() {
+}
+
+/// Check for split type names (e.g. unsigned long long)
+QString IDLImport::joinTypename() {
+ QString typeName = m_source[m_srcIndex];
+ if (m_source[m_srcIndex] == "unsigned")
+ typeName += ' ' + advance();
+ if (m_source[m_srcIndex] == "long" &&
+ (m_source[m_srcIndex + 1] == "long" || m_source[m_srcIndex + 1] == "double"))
+ typeName += ' ' + advance();
+ return typeName;
+}
+
+bool IDLImport::preprocess(QString& line) {
+ // Ignore C preprocessor generated lines.
+ if (line.startsWith("#"))
+ return true; // done
+ return NativeImportBase::preprocess(line);
+}
+
+void IDLImport::fillSource(const QString& word) {
+ QString lexeme;
+ const uint len = word.length();
+ for (uint i = 0; i < len; i++) {
+ QChar c = word[i];
+ if (c.isLetterOrNumber() || c == '_') {
+ lexeme += c;
+ } else if (c == ':' && word[i + 1] == ':') {
+ // compress scoped name into lexeme
+ lexeme += "::";
+ i++;
+ } else if (c == '<') {
+ // compress sequence or bounded string into lexeme
+ do {
+ lexeme += word[i];
+ } while (word[i] != '>' && ++i < len);
+ } else {
+ if (!lexeme.isEmpty()) {
+ m_source.append(lexeme);
+ lexeme = QString();
+ }
+ m_source.append(QString(c));
+ }
+ }
+ if (!lexeme.isEmpty())
+ m_source.append(lexeme);
+}
+
+void IDLImport::parseFile(const QString& filename) {
+ if (filename.contains('/')) {
+ QString path = filename;
+ path.remove( QRegExp("/[^/]+$") );
+ kDebug() << "IDLImport::parseFile: adding path " << path << endl;
+ Import_Utils::addIncludePath(path);
+ }
+ QStringList includePaths = Import_Utils::includePathList();
+ //QProcess command("cpp", UMLAp::app());
+ QString command("cpp -C"); // -C means "preserve comments"
+ for (QStringList::Iterator pathIt = includePaths.begin();
+ pathIt != includePaths.end(); ++pathIt) {
+ QString path = (*pathIt);
+ //command.addArgument(" -I" + path);
+ command += " -I" + path;
+ }
+ command += ' ' + filename;
+ kDebug() << "importIDL: " << command << endl;
+ FILE *fp = popen(command.ascii(), "r");
+ if (fp == NULL) {
+ kError() << "IDLImport::parseFile: cannot popen(" << command << ")" << endl;
+ return;
+ }
+ // Scan the input file into the QStringList m_source.
+ m_source.clear();
+ char buf[256];
+ while (fgets(buf, sizeof(buf), fp) != NULL) {
+ int len = strlen(buf);
+ if (buf[len - 1] == '\n')
+ buf[--len] = '\0';
+ NativeImportBase::scan( QString(buf) );
+ }
+ // Parse the QStringList m_source.
+ m_scopeIndex = 0;
+ m_scope[0] = NULL;
+ const uint srcLength = m_source.count();
+ for (m_srcIndex = 0; m_srcIndex < srcLength; m_srcIndex++) {
+ const QString& keyword = m_source[m_srcIndex];
+ //kDebug() << '"' << keyword << '"' << endl;
+ if (keyword.startsWith(m_singleLineCommentIntro)) {
+ m_comment = keyword.mid(m_singleLineCommentIntro.length());
+ continue;
+ }
+ if (! parseStmt())
+ skipStmt();
+ m_currentAccess = Uml::Visibility::Public;
+ m_comment = QString();
+ }
+ pclose(fp);
+}
+
+bool IDLImport::parseStmt() {
+ const QString& keyword = m_source[m_srcIndex];
+ const uint srcLength = m_source.count();
+ if (keyword == "module") {
+ const QString& name = advance();
+ UMLObject *ns = Import_Utils::createUMLObject(Uml::ot_Package,
+ name, m_scope[m_scopeIndex], m_comment);
+ m_scope[++m_scopeIndex] = static_cast<UMLPackage*>(ns);
+ m_scope[m_scopeIndex]->setStereotype("CORBAModule");
+ if (advance() != "{") {
+ kError() << "importIDL: unexpected: " << m_source[m_srcIndex] << endl;
+ skipStmt("{");
+ }
+ return true;
+ }
+ if (keyword == "interface") {
+ const QString& name = advance();
+ UMLObject *ns = Import_Utils::createUMLObject(Uml::ot_Class,
+ name, m_scope[m_scopeIndex], m_comment);
+ m_scope[++m_scopeIndex] = m_klass = static_cast<UMLClassifier*>(ns);
+ m_klass->setStereotype("CORBAInterface");
+ m_klass->setAbstract(m_isAbstract);
+ m_isAbstract = false;
+ m_comment = QString();
+ if (advance() == ";") // forward declaration
+ return true;
+ if (m_source[m_srcIndex] == ":") {
+ while (++m_srcIndex < srcLength && m_source[m_srcIndex] != "{") {
+ const QString& baseName = m_source[m_srcIndex];
+ Import_Utils::createGeneralization(m_klass, baseName);
+ if (advance() != ",")
+ break;
+ }
+ }
+ if (m_source[m_srcIndex] != "{") {
+ kError() << "importIDL: ignoring excess chars at "
+ << name << endl;
+ skipStmt("{");
+ }
+ return true;
+ }
+ if (keyword == "struct" || keyword == "exception") {
+ const QString& name = advance();
+ UMLObject *ns = Import_Utils::createUMLObject(Uml::ot_Class,
+ name, m_scope[m_scopeIndex], m_comment);
+ m_scope[++m_scopeIndex] = m_klass = static_cast<UMLClassifier*>(ns);
+ if (keyword == "struct")
+ m_klass->setStereotype("CORBAStruct");
+ else
+ m_klass->setStereotype("CORBAException");
+ if (advance() != "{") {
+ kError() << "importIDL: expecting '{' at " << name << endl;
+ skipStmt("{");
+ }
+ return true;
+ }
+ if (keyword == "union") {
+ // TBD. <gulp>
+ skipStmt("}");
+ m_srcIndex++; // advance to ';'
+ return true;
+ }
+ if (keyword == "enum") {
+ const QString& name = advance();
+ UMLObject *ns = Import_Utils::createUMLObject(Uml::ot_Enum,
+ name, m_scope[m_scopeIndex], m_comment);
+ UMLEnum *enumType = static_cast<UMLEnum*>(ns);
+ m_srcIndex++; // skip name
+ while (++m_srcIndex < srcLength && m_source[m_srcIndex] != "}") {
+ Import_Utils::addEnumLiteral(enumType, m_source[m_srcIndex]);
+ if (advance() != ",")
+ break;
+ }
+ skipStmt();
+ return true;
+ }
+ if (keyword == "typedef") {
+ const QString& existingType = advance();
+ const QString& newType = advance();
+ Import_Utils::createUMLObject(Uml::ot_Class, newType, m_scope[m_scopeIndex],
+ m_comment, "CORBATypedef" /* stereotype */);
+ // @todo How do we convey the existingType ?
+ skipStmt();
+ return true;
+ }
+ if (keyword == "const") {
+ skipStmt();
+ return true;
+ }
+ if (keyword == "custom") {
+ return true;
+ }
+ if (keyword == "abstract") {
+ m_isAbstract = true;
+ return true;
+ }
+ if (keyword == "valuetype") {
+ const QString& name = advance();
+ UMLObject *ns = Import_Utils::createUMLObject(Uml::ot_Class,
+ name, m_scope[m_scopeIndex], m_comment);
+ m_scope[++m_scopeIndex] = m_klass = static_cast<UMLClassifier*>(ns);
+ m_klass->setAbstract(m_isAbstract);
+ m_isAbstract = false;
+ if (advance() == ";") // forward declaration
+ return true;
+ if (m_source[m_srcIndex] == ":") {
+ if (advance() == "truncatable")
+ m_srcIndex++;
+ while (m_srcIndex < srcLength && m_source[m_srcIndex] != "{") {
+ const QString& baseName = m_source[m_srcIndex];
+ Import_Utils::createGeneralization(m_klass, baseName);
+ if (advance() != ",")
+ break;
+ m_srcIndex++;
+ }
+ }
+ if (m_source[m_srcIndex] != "{") {
+ kError() << "importIDL: ignoring excess chars at "
+ << name << endl;
+ skipStmt("{");
+ }
+ return true;
+ }
+ if (keyword == "public") {
+ return true;
+ }
+ if (keyword == "private") {
+ m_currentAccess = Uml::Visibility::Private;
+ return true;
+ }
+ if (keyword == "readonly") {
+ m_isReadonly = true;
+ return true;
+ }
+ if (keyword == "attribute") {
+ m_isAttribute = true;
+ return true;
+ }
+ if (keyword == "oneway") {
+ m_isOneway = true;
+ return true;
+ }
+ if (keyword == "}") {
+ if (m_scopeIndex)
+ m_klass = dynamic_cast<UMLClassifier*>(m_scope[--m_scopeIndex]);
+ else
+ kError() << "importIDL: too many }" << endl;
+ m_srcIndex++; // skip ';'
+ return true;
+ }
+ if (keyword == ";")
+ return true;
+ // At this point, we expect `keyword' to be a type name
+ // (of a member of struct or valuetype, or return type
+ // of an operation.) Up next is the name of the attribute
+ // or operation.
+ if (! keyword.contains( QRegExp("^\\w") )) {
+ kError() << "importIDL: ignoring " << keyword << endl;
+ return false;
+ }
+ QString typeName = joinTypename();
+ QString name = advance();
+ if (name.contains( QRegExp("\\W") )) {
+ kError() << "importIDL: expecting name in " << name << endl;
+ return false;
+ }
+ // At this point we most definitely need a class.
+ if (m_klass == NULL) {
+ kError() << "importIDL: no class set for " << name << endl;
+ return false;
+ }
+ QString nextToken = advance();
+ if (nextToken == "(") {
+ // operation
+ UMLOperation *op = Import_Utils::makeOperation(m_klass, name);
+ m_srcIndex++;
+ while (m_srcIndex < srcLength && m_source[m_srcIndex] != ")") {
+ const QString &direction = m_source[m_srcIndex++];
+ QString typeName = joinTypename();
+ const QString &parName = advance();
+ UMLAttribute *att = Import_Utils::addMethodParameter(op, typeName, parName);
+ Uml::Parameter_Direction dir;
+ if (Model_Utils::stringToDirection(direction, dir))
+ att->setParmKind(dir);
+ else
+ kError() << "importIDL: expecting parameter direction at "
+ << direction << endl;
+ if (advance() != ",")
+ break;
+ m_srcIndex++;
+ }
+ Import_Utils::insertMethod(m_klass, op, Uml::Visibility::Public, typeName,
+ false, false, false, false, m_comment);
+ if (m_isOneway) {
+ op->setStereotype("oneway");
+ m_isOneway = false;
+ }
+ skipStmt(); // skip possible "raises" clause
+ return true;
+ }
+ // At this point we know it's some kind of attribute declaration.
+ while (1) {
+ while (nextToken != "," && nextToken != ";") {
+ name += nextToken; // add possible array dimensions to `name'
+ nextToken = advance();
+ }
+ UMLObject *o = Import_Utils::insertAttribute(m_klass, m_currentAccess, name, typeName, m_comment);
+ UMLAttribute *attr = static_cast<UMLAttribute*>(o);
+ if (m_isReadonly) {
+ attr->setStereotype("readonly");
+ m_isReadonly = false;
+ }
+ if (nextToken != ",")
+ break;
+ name = advance();
+ nextToken = advance();
+ }
+ return true;
+}
+
diff --git a/umbrello/umbrello/codeimport/idlimport.h b/umbrello/umbrello/codeimport/idlimport.h
new file mode 100644
index 00000000..6945364f
--- /dev/null
+++ b/umbrello/umbrello/codeimport/idlimport.h
@@ -0,0 +1,54 @@
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * copyright (C) 2005 *
+ * Umbrello UML Modeller Authors <uml-devel@uml.sf.net> *
+ ***************************************************************************/
+
+#ifndef IDLIMPORT_H
+#define IDLIMPORT_H
+
+#include "nativeimportbase.h"
+
+/**
+ * CORBA IDL code import
+ * @author Oliver Kellogg
+ * Bugs and comments to uml-devel@lists.sf.net or http://bugs.kde.org
+ */
+class IDLImport : public NativeImportBase {
+public:
+ IDLImport();
+ virtual ~IDLImport();
+
+ /**
+ * Implement abstract operation from NativeImportBase.
+ */
+ bool parseStmt();
+
+ /**
+ * Reimplement operation from NativeImportBase.
+ * Need to do this because we use the external C preprocessor.
+ */
+ void parseFile(const QString& file);
+
+ /**
+ * Override operation from NativeImportBase.
+ */
+ bool preprocess(QString& line);
+
+ /**
+ * Implement abstract operation from NativeImportBase.
+ */
+ void fillSource(const QString& word);
+
+protected:
+ QString joinTypename();
+ bool m_isOneway, m_isReadonly, m_isAttribute;
+};
+
+#endif
+
diff --git a/umbrello/umbrello/codeimport/import_utils.cpp b/umbrello/umbrello/codeimport/import_utils.cpp
new file mode 100644
index 00000000..92a87867
--- /dev/null
+++ b/umbrello/umbrello/codeimport/import_utils.cpp
@@ -0,0 +1,464 @@
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * copyright (C) 2005-2007 *
+ * Umbrello UML Modeller Authors <uml-devel@uml.sf.net> *
+ ***************************************************************************/
+
+// own header
+#include "import_utils.h"
+// qt/kde includes
+#include <qmap.h>
+#include <qregexp.h>
+#include <kmessagebox.h>
+#include <kdebug.h>
+#include <klocale.h>
+// app includes
+#include "../uml.h"
+#include "../umldoc.h"
+#include "../umllistview.h"
+#include "../umllistviewitem.h"
+#include "../umlobject.h"
+#include "../package.h"
+#include "../folder.h"
+#include "../enum.h"
+#include "../classifier.h"
+#include "../operation.h"
+#include "../attribute.h"
+#include "../template.h"
+#include "../association.h"
+#include "../object_factory.h"
+
+#include <stdlib.h>
+
+namespace Import_Utils {
+
+/**
+ * Flag manipulated by createUMLObject().
+ * Global state is generally bad, I know.
+ * It would be cleaner to make this into a return value from
+ * createUMLObject().
+ */
+bool bNewUMLObjectWasCreated = false;
+
+/**
+ * Related classifier for creation of dependencies on template
+ * parameters in createUMLObject().
+ */
+UMLClassifier * gRelatedClassifier = NULL;
+
+/**
+ * On encountering a scoped typename string where the scopes
+ * have not yet been seen, we synthesize UML objects for the
+ * unknown scopes (using a question dialog to the user to decide
+ * whether to treat a scope as a class or as a package.)
+ * However, such an unknown scope is put at the global level.
+ * I.e. before calling createUMLObject() we set this flag to true.
+ */
+bool bPutAtGlobalScope = false;
+
+/**
+ * The include path list (see addIncludePath() and includePathList())
+ */
+QStringList incPathList;
+
+void putAtGlobalScope(bool yesno) {
+ bPutAtGlobalScope = yesno;
+}
+
+void setRelatedClassifier(UMLClassifier *c) {
+ gRelatedClassifier = c;
+}
+
+void assignUniqueIdOnCreation(bool yesno) {
+ Object_Factory::assignUniqueIdOnCreation(yesno);
+}
+
+bool newUMLObjectWasCreated() {
+ return bNewUMLObjectWasCreated;
+}
+
+QString formatComment(const QString &comment) {
+ if (comment.isEmpty())
+ return comment;
+
+ QStringList lines = QStringList::split("\n", comment);
+ QString& first = lines.first();
+ QRegExp wordex("\\w");
+ if (first.startsWith("/*")) {
+ int wordpos = wordex.search(first);
+ if (wordpos != -1)
+ first = first.mid(wordpos); // remove comment start
+ else
+ lines.pop_front(); // nothing interesting on this line
+ }
+ QString& last = lines.last();
+ int endpos = last.find("*/");
+ if (endpos != -1) {
+ if (last.contains(wordex))
+ last = last.mid(0, endpos - 1); // remove comment end
+ else
+ lines.pop_back(); // nothing interesting on this line
+ }
+ if (! lines.count())
+ return "";
+
+ QStringList::Iterator end(lines.end());
+ for (QStringList::Iterator lit(lines.begin()); lit != end; ++lit) {
+ (*lit).remove(QRegExp("^\\s+"));
+ (*lit).remove(QRegExp("^\\*+\\s?"));
+ }
+ return lines.join("\n");
+}
+
+/*
+UMLObject* findUMLObject(QString name,
+ Uml::Object_Type type) {
+ // Why an extra wrapper? See comment at addMethodParameter()
+ UMLObject * o = umldoc->findUMLObject(name, type);
+ return o;
+}
+ */
+
+UMLObject *createUMLObject(Uml::Object_Type type,
+ const QString& inName,
+ UMLPackage *parentPkg,
+ const QString& comment,
+ const QString& stereotype) {
+ QString name = inName;
+ UMLDoc *umldoc = UMLApp::app()->getDocument();
+ UMLFolder *logicalView = umldoc->getRootFolder(Uml::mt_Logical);
+ const Uml::Programming_Language pl = UMLApp::app()->getActiveLanguage();
+ if (parentPkg == NULL) {
+ // kDebug() << "Import_Utils::createUMLObject(" << name
+ // << "): parentPkg is NULL, assuming Logical View" << endl;
+ parentPkg = logicalView;
+ }
+ UMLObject * o = umldoc->findUMLObject(name, type, parentPkg);
+ bNewUMLObjectWasCreated = false;
+ if (o == NULL) {
+ // Strip possible adornments and look again.
+ int isConst = name.contains(QRegExp("^const "));
+ name.remove(QRegExp("^const\\s+"));
+ QString typeName(name);
+ const int isAdorned = typeName.contains( QRegExp("[^\\w:\\. ]") );
+ const int isPointer = typeName.contains('*');
+ const int isRef = typeName.contains('&');
+ typeName.remove(QRegExp("[^\\w:\\. ].*$"));
+ typeName = typeName.simplifyWhiteSpace();
+ UMLObject *origType = umldoc->findUMLObject(typeName, Uml::ot_UMLObject, parentPkg);
+ if (origType == NULL) {
+ // Still not found. Create the stripped down type.
+ if (bPutAtGlobalScope)
+ parentPkg = logicalView;
+ // Find, or create, the scopes.
+ QStringList components;
+ if (typeName.contains("::")) {
+ components = QStringList::split("::", typeName);
+ } else if (typeName.contains(".")) {
+ components = QStringList::split(".", typeName);
+ }
+ if (components.count() > 1) {
+ typeName = components.back();
+ components.pop_back();
+ while ( components.count() ) {
+ QString scopeName = components.front();
+ components.pop_front();
+ o = umldoc->findUMLObject(scopeName, Uml::ot_UMLObject, parentPkg);
+ if (o) {
+ parentPkg = static_cast<UMLPackage*>(o);
+ continue;
+ }
+ int wantNamespace = KMessageBox::Yes;
+ if (pl == Uml::pl_Cpp) {
+ /* We know std and Qt are namespaces */
+ if (scopeName != "std" && scopeName != "Qt") {
+ wantNamespace = KMessageBox::questionYesNo(NULL,
+ i18n("Is the scope %1 a namespace or a class?").arg(scopeName),
+ i18n("C++ Import Requests Your Help"),
+ i18n("Namespace"), i18n("Class"));
+ }
+ }
+ Uml::Object_Type ot = (wantNamespace == KMessageBox::Yes ? Uml::ot_Package : Uml::ot_Class);
+ o = Object_Factory::createUMLObject(ot, scopeName, parentPkg);
+ parentPkg = static_cast<UMLPackage*>(o);
+ UMLListView *listView = UMLApp::app()->getListView();
+ UMLListViewItem *lvitem = listView->findUMLObject(o);
+ listView->setCurrentItem(lvitem);
+ }
+ // All scope qualified datatypes live in the global scope.
+ bPutAtGlobalScope = true;
+ }
+ Uml::Object_Type t = type;
+ if (type == Uml::ot_UMLObject || isAdorned)
+ t = Uml::ot_Class;
+ origType = Object_Factory::createUMLObject(t, typeName, parentPkg, false);
+ bNewUMLObjectWasCreated = true;
+ bPutAtGlobalScope = false;
+ }
+ if (isConst || isAdorned) {
+ // Create the full given type (including adornments.)
+ if (isConst)
+ name.prepend("const ");
+ o = Object_Factory::createUMLObject(Uml::ot_Datatype, name,
+ umldoc->getDatatypeFolder(),
+ false); //solicitNewName
+ UMLClassifier *dt = static_cast<UMLClassifier*>(o);
+ UMLClassifier *c = dynamic_cast<UMLClassifier*>(origType);
+ if (c)
+ dt->setOriginType(c);
+ else
+ kError() << "createUMLObject(" << name << "): "
+ << "origType " << typeName << " is not a UMLClassifier"
+ << endl;
+ if (isRef || isPointer)
+ dt->setIsReference();
+ /*
+ if (isPointer) {
+ UMLObject *pointerDecl = Object_Factory::createUMLObject(Uml::ot_Datatype, type);
+ UMLClassifier *dt = static_cast<UMLClassifier*>(pointerDecl);
+ dt->setOriginType(classifier);
+ dt->setIsReference();
+ classifier = dt;
+ } */
+ } else {
+ o = origType;
+ }
+ } else if (parentPkg && !bPutAtGlobalScope) {
+ UMLPackage *existingPkg = o->getUMLPackage();
+ if (existingPkg != umldoc->getDatatypeFolder()) {
+ if (existingPkg)
+ existingPkg->removeObject(o);
+ else
+ kError() << "createUMLObject(" << name << "): "
+ << "o->getUMLPackage() was NULL" << endl;
+ o->setUMLPackage(parentPkg);
+ parentPkg->addObject(o);
+ }
+ }
+ QString strippedComment = formatComment(comment);
+ if (! strippedComment.isEmpty()) {
+ o->setDoc(strippedComment);
+ }
+ if (!stereotype.isEmpty()) {
+ o->setStereotype(stereotype);
+ }
+ if (gRelatedClassifier == NULL || gRelatedClassifier == o)
+ return o;
+ QRegExp templateInstantiation("^[\\w:\\.]+\\s*<(.*)>");
+ int pos = templateInstantiation.search(name);
+ if (pos == -1)
+ return o;
+ // Create dependencies on template parameters.
+ QString caption = templateInstantiation.cap(1);
+ QStringList params = QStringList::split(QRegExp("[^\\w:\\.]+"), caption);
+ if (!params.count())
+ return o;
+ QStringList::Iterator end(params.end());
+ for (QStringList::Iterator it(params.begin()); it != end; ++it) {
+ UMLObject *p = umldoc->findUMLObject(*it, Uml::ot_UMLObject, parentPkg);
+ if (p == NULL || p->getBaseType() == Uml::ot_Datatype)
+ continue;
+ const Uml::Association_Type at = Uml::at_Dependency;
+ UMLAssociation *assoc = umldoc->findAssociation(at, gRelatedClassifier, p);
+ if (assoc)
+ continue;
+ assoc = new UMLAssociation(at, gRelatedClassifier, p);
+ assoc->setUMLPackage(umldoc->getRootFolder(Uml::mt_Logical));
+ umldoc->addAssociation(assoc);
+ }
+ return o;
+}
+
+UMLOperation* makeOperation(UMLClassifier *parent, const QString &name) {
+ UMLOperation *op = Object_Factory::createOperation(parent, name);
+ return op;
+}
+
+UMLObject* insertAttribute(UMLClassifier *owner,
+ Uml::Visibility scope,
+ const QString& name,
+ UMLClassifier *attrType,
+ const QString& comment /* ="" */,
+ bool isStatic /* =false */) {
+ Uml::Object_Type ot = owner->getBaseType();
+ Uml::Programming_Language pl = UMLApp::app()->getActiveLanguage();
+ if (! (ot == Uml::ot_Class || ot == Uml::ot_Interface && pl == Uml::pl_Java)) {
+ kDebug() << "insertAttribute: Don't know what to do with "
+ << owner->getName() << " (object type " << ot << ")" << endl;
+ return NULL;
+ }
+ UMLObject *o = owner->findChildObject(name, Uml::ot_Attribute);
+ if (o) {
+ return o;
+ }
+
+ UMLAttribute *attr = owner->addAttribute(name, attrType, scope);
+ attr->setStatic(isStatic);
+ QString strippedComment = formatComment(comment);
+ if (! strippedComment.isEmpty()) {
+ attr->setDoc(strippedComment);
+ }
+
+ UMLApp::app()->getDocument()->setModified(true);
+ return attr;
+}
+
+UMLObject* insertAttribute(UMLClassifier *owner, Uml::Visibility scope,
+ const QString& name,
+ const QString& type,
+ const QString& comment /* ="" */,
+ bool isStatic /* =false */) {
+ UMLObject *attrType = owner->findTemplate(type);
+ if (attrType == NULL) {
+ bPutAtGlobalScope = true;
+ gRelatedClassifier = owner;
+ attrType = createUMLObject(Uml::ot_UMLObject, type, owner);
+ gRelatedClassifier = NULL;
+ bPutAtGlobalScope = false;
+ }
+ return insertAttribute (owner, scope, name,
+ static_cast<UMLClassifier*>(attrType),
+ comment, isStatic);
+}
+
+void insertMethod(UMLClassifier *klass, UMLOperation* &op,
+ Uml::Visibility scope, const QString& type,
+ bool isStatic, bool isAbstract,
+ bool isFriend, bool isConstructor,
+ const QString& comment) {
+ op->setVisibility(scope);
+ if (!type.isEmpty() // return type may be missing (constructor/destructor)
+ && type != "void") {
+ if (type == klass->getName()) {
+ op->setType(klass);
+ } else {
+ UMLObject *typeObj = klass->findTemplate(type);
+ if (typeObj == NULL) {
+ bPutAtGlobalScope = true;
+ gRelatedClassifier = klass;
+ typeObj = createUMLObject(Uml::ot_UMLObject, type, klass);
+ gRelatedClassifier = NULL;
+ bPutAtGlobalScope = false;
+ op->setType(typeObj);
+ }
+ }
+ }
+
+ op->setStatic(isStatic);
+ op->setAbstract(isAbstract);
+
+ // if the operation is friend, add it as a stereotype
+ if (isFriend)
+ op->setStereotype("friend");
+ // if the operation is a constructor, add it as a stereotype
+ if (isConstructor)
+ op->setStereotype("constructor");
+
+ QString strippedComment = formatComment(comment);
+ if (! strippedComment.isEmpty()) {
+ op->setDoc(strippedComment);
+ }
+
+ UMLAttributeList params = op->getParmList();
+ UMLOperation *exist = klass->checkOperationSignature(op->getName(), params);
+ if (exist) {
+ // copy contents to existing operation
+ exist->setVisibility(scope);
+ exist->setStatic(isStatic);
+ exist->setAbstract(isAbstract);
+ if (! strippedComment.isEmpty())
+ exist->setDoc(strippedComment);
+ UMLAttributeList exParams = exist->getParmList();
+ UMLAttribute *param, *exParam = exParams.first();
+ for (UMLAttributeListIt it(params); (param = it.current()) != NULL;
+ ++it, exParam = exParams.next()) {
+ exParam->setName(param->getName());
+ exParam->setVisibility(param->getVisibility());
+ exParam->setStatic(param->getStatic());
+ exParam->setAbstract(param->getAbstract());
+ exParam->setDoc(param->getDoc());
+ exParam->setInitialValue(param->getInitialValue());
+ exParam->setParmKind(param->getParmKind());
+ }
+ // delete incoming UMLOperation and pass out the existing one
+ delete op;
+ op = exist;
+ } else {
+ klass->addOperation(op);
+ }
+}
+
+UMLAttribute* addMethodParameter(UMLOperation *method,
+ const QString& type,
+ const QString& name) {
+ UMLClassifier *owner = static_cast<UMLClassifier*>(method->parent());
+ UMLObject *typeObj = owner->findTemplate(type);
+ if (typeObj == NULL) {
+ bPutAtGlobalScope = true;
+ gRelatedClassifier = owner;
+ typeObj = createUMLObject(Uml::ot_UMLObject, type, owner);
+ gRelatedClassifier = NULL;
+ bPutAtGlobalScope = false;
+ }
+ UMLAttribute *attr = Object_Factory::createAttribute(method, name, typeObj);
+ method->addParm(attr);
+ return attr;
+}
+
+void addEnumLiteral(UMLEnum *enumType, const QString &literal, const QString &comment) {
+ UMLObject *el = enumType->addEnumLiteral(literal);
+ el->setDoc(comment);
+}
+
+void createGeneralization(UMLClassifier *child, UMLClassifier *parent) {
+ // if the child is an interface, so is the parent.
+ if (child->isInterface())
+ parent->setBaseType(Uml::ot_Interface);
+ Uml::Association_Type association = Uml::at_Generalization;
+
+ if (parent->isInterface() && !child->isInterface()) {
+ // if the parent is an interface, but the child is not, then
+ // this is really realization.
+ //
+ association = Uml::at_Realization;
+ }
+ UMLAssociation *assoc = new UMLAssociation(association, child, parent);
+ UMLDoc *umldoc = UMLApp::app()->getDocument();
+ assoc->setUMLPackage(umldoc->getRootFolder(Uml::mt_Logical));
+ umldoc->addAssociation(assoc);
+}
+
+void createGeneralization(UMLClassifier *child, const QString &parentName) {
+ UMLObject *parentObj = createUMLObject( Uml::ot_Class, parentName );
+ UMLClassifier *parent = static_cast<UMLClassifier*>(parentObj);
+ createGeneralization(child, parent);
+}
+
+QStringList includePathList() {
+ QStringList includePathList(incPathList);
+ char *umbrello_incpath = getenv( "UMBRELLO_INCPATH" );
+ if (umbrello_incpath) {
+ includePathList += QStringList::split( ':', umbrello_incpath );
+ }
+ return includePathList;
+}
+
+void addIncludePath(const QString& path) {
+ if (! incPathList.contains(path))
+ incPathList.append(path);
+}
+
+
+bool isDatatype(const QString& name, UMLPackage *parentPkg) {
+ UMLDoc *umldoc = UMLApp::app()->getDocument();
+ UMLObject * o = umldoc->findUMLObject(name, Uml::ot_Datatype, parentPkg);
+ return (o!=NULL);
+}
+
+} // end namespace Import_Utils
+
diff --git a/umbrello/umbrello/codeimport/import_utils.h b/umbrello/umbrello/codeimport/import_utils.h
new file mode 100644
index 00000000..7d36bc77
--- /dev/null
+++ b/umbrello/umbrello/codeimport/import_utils.h
@@ -0,0 +1,175 @@
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * copyright (C) 2005-2006 *
+ * Umbrello UML Modeller Authors <uml-devel@uml.sf.net> *
+ ***************************************************************************/
+
+#ifndef IMPORT_UTILS_H
+#define IMPORT_UTILS_H
+
+#include <qstringlist.h>
+#include "../umlnamespace.h"
+#include "../umlattributelist.h"
+
+class UMLObject;
+class UMLClassifier;
+class UMLPackage;
+class UMLOperation;
+class UMLEnum;
+
+/**
+ * Utilities for code import
+ * @author Oliver Kellogg
+ * Bugs and comments to uml-devel@lists.sf.net or http://bugs.kde.org
+ */
+
+namespace Import_Utils {
+
+ /**
+ * Find or create a document object.
+ */
+ UMLObject* createUMLObject(Uml::Object_Type type,
+ const QString& name,
+ UMLPackage *parentPkg = NULL,
+ const QString& comment = QString::null,
+ const QString& stereotype = QString::null);
+ /**
+ * Control whether an object which is newly created by createUMLObject()
+ * is put at the global scope.
+ *
+ * @param yesno When set to false, the object is created at the scope
+ * given by the parentPkg argument of createUMLObject().
+ */
+ void putAtGlobalScope(bool yesno);
+
+ /**
+ * Set a related classifier for creation of dependencies on template
+ * parameters in createUMLObject().
+ */
+ void setRelatedClassifier(UMLClassifier *c);
+
+ /**
+ * Control whether the creation methods solicit a new unique ID for the
+ * created object.
+ * By default, unique ID generation is turned on.
+ *
+ * @param yesno False turns UID generation off, true turns it on.
+ */
+ void assignUniqueIdOnCreation(bool yesno);
+
+ /**
+ * Create a UMLAttribute and insert it into the document.
+ */
+ UMLObject* insertAttribute(UMLClassifier *klass, Uml::Visibility scope,
+ const QString& name,
+ const QString& type,
+ const QString& comment = QString::null,
+ bool isStatic = false);
+ /**
+ * Create a UMLAttribute and insert it into the document.
+ * Use the specified existing attrType.
+ */
+ UMLObject* insertAttribute(UMLClassifier *klass, Uml::Visibility scope,
+ const QString& name,
+ UMLClassifier *attrType,
+ const QString& comment /* ="" */,
+ bool isStatic /* =false */);
+ /**
+ * Create a UMLOperation.
+ * The reason for this method is to not generate any Qt signals.
+ * Instead, these are generated by insertMethod().
+ * (If we generated a creation signal prematurely, i.e. without
+ * the method parameters being known yet, then that would lead to
+ * a conflict with a pre-existing parameterless method of the same
+ * name.)
+ */
+ UMLOperation* makeOperation(UMLClassifier *parent, const QString &name);
+
+ /**
+ * Insert the UMLOperation into the given classifier.
+ *
+ * @param klass The classifier into which the operation shall be added.
+ * @param op Reference to pointer to the temporary UMLOperation
+ * for insertion. The caller relinquishes ownership of the
+ * object pointed to. If an UMLOperation of same signature
+ * already exists at the classifier then the incoming
+ * UMLOperation is deleted and the pointer is set to the
+ * existing UMLOperation.
+ * @param scope The Uml::Visibility of the method
+ * @param type The return type
+ * @param isStatic boolean switch to decide if method is static
+ * @param isAbstract boolean switch to decide if method is abstract
+ * @param isFriend true boolean switch to decide if methods is a friend function
+ * @param isConstructor boolean switch to decide if methods is a constructor
+ * @param comment The Documentation for this method
+ */
+ void insertMethod(UMLClassifier *klass, UMLOperation* &op,
+ Uml::Visibility scope, const QString& type,
+ bool isStatic, bool isAbstract,
+ bool isFriend = false, bool isConstructor = false,
+ const QString& comment = QString::null);
+
+ /**
+ * Add an argument to a UMLOperation.
+ * The parentPkg arg is only used for resolving possible scope
+ * prefixes in the `type'.
+ */
+ UMLAttribute* addMethodParameter(UMLOperation *method,
+ const QString& type,
+ const QString& name);
+
+ /**
+ * Add an enum literal to an UMLEnum.
+ */
+ void addEnumLiteral(UMLEnum *enumType, const QString &literal,
+ const QString &comment = QString());
+
+ /**
+ * Create a generalization from the given child classifier to the given
+ * parent classifier.
+ */
+ void createGeneralization(UMLClassifier *child, UMLClassifier *parent);
+
+ /**
+ * Create a generalization from the existing child UMLObject to the given
+ * parent class name.
+ */
+ void createGeneralization(UMLClassifier *child, const QString &parentName);
+
+ /**
+ * Strip comment lines of leading whitespace and stars.
+ */
+ QString formatComment(const QString &comment);
+
+ /**
+ * Return the list of paths set by previous calls to addIncludePath()
+ * and the environment variable UMBRELLO_INCPATH.
+ * This list can be used for finding #included (or Ada with'ed or...)
+ * files.
+ */
+ QStringList includePathList();
+
+ /**
+ * Add a path to the include path list.
+ */
+ void addIncludePath(const QString& path);
+
+ /**
+ * Returns whether the last createUMLObject() actually created
+ * a new object or just returned an existing one.
+ */
+ bool newUMLObjectWasCreated();
+
+ /**
+ * Returns true if a type is an actual Datatype
+ */
+ bool isDatatype(const QString& name, UMLPackage *parentPkg = NULL);
+
+} // end namespace Import_Utils
+
+#endif
diff --git a/umbrello/umbrello/codeimport/javaimport.cpp b/umbrello/umbrello/codeimport/javaimport.cpp
new file mode 100644
index 00000000..8df6e5e7
--- /dev/null
+++ b/umbrello/umbrello/codeimport/javaimport.cpp
@@ -0,0 +1,549 @@
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * copyright (C) 2006-2007 *
+ * Umbrello UML Modeller Authors <uml-devel@uml.sf.net> *
+ ***************************************************************************/
+
+// own header
+#include "javaimport.h"
+
+// qt/kde includes
+#include <qfile.h>
+#include <qtextstream.h>
+#include <qstringlist.h>
+#include <qregexp.h>
+#include <kdebug.h>
+// app includes
+#include "import_utils.h"
+#include "../uml.h"
+#include "../umldoc.h"
+#include "../umlpackagelist.h"
+#include "../package.h"
+#include "../classifier.h"
+#include "../enum.h"
+#include "../operation.h"
+#include "../attribute.h"
+
+QStringList JavaImport::s_filesAlreadyParsed;
+int JavaImport::s_parseDepth = 0;
+
+JavaImport::JavaImport() : NativeImportBase("//") {
+ setMultiLineComment("/*", "*/");
+ initVars();
+}
+
+JavaImport::~JavaImport() {
+}
+
+void JavaImport::initVars() {
+ m_isStatic = false;
+}
+
+/// Catenate possible template arguments/array dimensions to the end of the type name.
+QString JavaImport::joinTypename(QString typeName) {
+ if (m_source[m_srcIndex + 1] == "<" ||
+ m_source[m_srcIndex + 1] == "[") {
+ uint start = ++m_srcIndex;
+ if (! skipToClosing(m_source[start][0]))
+ return typeName;
+ for (uint i = start; i <= m_srcIndex; i++) {
+ typeName += m_source[i];
+ }
+ }
+ // to handle multidimensional arrays, call recursively
+ if (m_source[m_srcIndex + 1] == "[") {
+ typeName = joinTypename( typeName );
+ }
+ return typeName;
+}
+
+void JavaImport::fillSource(const QString& word) {
+ QString lexeme;
+ const uint len = word.length();
+ for (uint i = 0; i < len; i++) {
+ const QChar& c = word[i];
+ if (c.isLetterOrNumber() || c == '_' || c == '.') {
+ lexeme += c;
+ } else {
+ if (!lexeme.isEmpty()) {
+ m_source.append(lexeme);
+ lexeme = QString();
+ }
+ m_source.append(QString(c));
+ }
+ }
+ if (!lexeme.isEmpty())
+ m_source.append(lexeme);
+}
+
+
+///Spawn off an import of the specified file
+void JavaImport::spawnImport( QString file ) {
+ // if the file is being parsed, don't bother
+ //
+ if (s_filesAlreadyParsed.contains( file ) ) {
+ return;
+ }
+ if (QFile::exists(file)) {
+ JavaImport importer;
+ QStringList fileList;
+ fileList.append( file );
+ s_filesAlreadyParsed.append( file );
+ importer.importFiles( fileList );
+ }
+}
+
+
+///returns the UML Object if found, or null otherwise
+UMLObject* findObject( QString name, UMLPackage *parentPkg ) {
+ UMLDoc *umldoc = UMLApp::app()->getDocument();
+ UMLObject * o = umldoc->findUMLObject(name, Uml::ot_UMLObject , parentPkg);
+ return o;
+}
+
+
+///Resolve the specified className
+UMLObject* JavaImport::resolveClass (QString className) {
+ kDebug() << "importJava trying to resolve " << className << endl;
+ // keep track if we are dealing with an array
+ //
+ bool isArray = className.contains('[');
+ // remove any [] so that the class itself can be resolved
+ //
+ QString baseClassName = className;
+ baseClassName.remove('[');
+ baseClassName.remove(']');
+
+ // java has a few implicit imports. Most relevant for this is the
+ // current package, which is in the same directory as the current file
+ // being parsed
+ //
+ QStringList file = QStringList::split( '/', m_currentFileName);
+ // remove the filename. This leaves the full path to the containing
+ // dir which should also include the package hierarchy
+ //
+ file.pop_back();
+
+ // the file we're looking for might be in the same directory as the
+ // current class
+ //
+ QString myDir = file.join( "/" );
+ QString myFile = '/' + myDir + '/' + baseClassName + ".java";
+ if ( QFile::exists(myFile) ) {
+ spawnImport( myFile );
+ if ( isArray ) {
+ // we have imported the type. For arrays we want to return
+ // the array type
+ return Import_Utils::createUMLObject(Uml::ot_Class, className, m_scope[m_scopeIndex]);
+ }
+ return findObject(baseClassName, m_scope[m_scopeIndex]);
+ }
+
+ // the class we want is not in the same package as the one being imported.
+ // use the imports to find the one we want.
+ //
+ QStringList package = QStringList::split( '.', m_currentPackage);
+ int dirsInPackageCount = package.size();
+
+ for (int count=0; count < dirsInPackageCount; count ++ ) {
+ // pop off one by one the directories, until only the source root remains
+ //
+ file.pop_back();
+ }
+ // this is now the root of any further source imports
+ QString sourceRoot = '/' + file.join("/") + '/';
+
+ for (QStringList::Iterator pathIt = m_imports.begin();
+ pathIt != m_imports.end(); ++pathIt) {
+ QString import = (*pathIt);
+ QStringList split = QStringList::split( '.', import );
+ split.pop_back(); // remove the * or the classname
+ if ( import.endsWith( "*" ) || import.endsWith( baseClassName) ) {
+ // check if the file we want is in this imported package
+ // convert the org.test type package into a filename
+ //
+ QString aFile = sourceRoot + split.join("/") + '/' + baseClassName + ".java";
+ if ( QFile::exists(aFile) ) {
+ spawnImport( aFile );
+ // we need to set the package for the class that will be resolved
+ // start at the root package
+ UMLPackage *parent = m_scope[0];
+ UMLPackage *current = NULL;
+
+ for (QStringList::Iterator it = split.begin(); it != split.end(); ++it) {
+ QString name = (*it);
+ UMLObject *ns = Import_Utils::createUMLObject(Uml::ot_Package,
+ name, parent);
+ current = static_cast<UMLPackage*>(ns);
+ parent = current;
+ } // for
+ if ( isArray ) {
+ // we have imported the type. For arrays we want to return
+ // the array type
+ return Import_Utils::createUMLObject(Uml::ot_Class, className, current);
+ }
+ // now that we have the right package, the class should be findable
+ return findObject(baseClassName, current);
+ } // if file exists
+ } // if import matches
+ } //foreach import
+ return NULL; // no match
+}
+
+
+/// keep track of the current file being parsed and reset the list of imports
+void JavaImport::parseFile(const QString& filename) {
+ m_currentFileName= filename;
+ m_imports.clear();
+ // default visibility is Impl, unless we are an interface, then it is
+ // public for member vars and methods
+ m_defaultCurrentAccess = Uml::Visibility::Implementation;
+ m_currentAccess = m_defaultCurrentAccess;
+ s_parseDepth++;
+ // in the case of self referencing types, we can avoid parsing the
+ // file twice by adding it to the list
+ s_filesAlreadyParsed.append(filename);
+ NativeImportBase::parseFile(filename);
+ s_parseDepth--;
+ if ( s_parseDepth <= 0 ) {
+ // if the user decides to clear things out and reparse, we need
+ // to honor the request, so reset things for next time.
+ s_filesAlreadyParsed.clear();
+ s_parseDepth = 0;
+ }
+}
+
+
+
+
+bool JavaImport::parseStmt() {
+ const uint srcLength = m_source.count();
+ const QString& keyword = m_source[m_srcIndex];
+ //kDebug() << '"' << keyword << '"' << endl;
+ if (keyword == "package") {
+ m_currentPackage = advance();
+ const QString& qualifiedName = m_currentPackage;
+ QStringList names = QStringList::split(".", qualifiedName);
+ for (QStringList::Iterator it = names.begin(); it != names.end(); ++it) {
+ QString name = (*it);
+ UMLObject *ns = Import_Utils::createUMLObject(Uml::ot_Package,
+ name, m_scope[m_scopeIndex], m_comment);
+ m_scope[++m_scopeIndex] = static_cast<UMLPackage*>(ns);
+ }
+ if (advance() != ";") {
+ kError() << "importJava: unexpected: " << m_source[m_srcIndex] << endl;
+ skipStmt();
+ }
+ return true;
+ }
+ if (keyword == "class" || keyword == "interface") {
+ const QString& name = advance();
+ const Uml::Object_Type t = (keyword == "class" ? Uml::ot_Class : Uml::ot_Interface);
+ UMLObject *ns = Import_Utils::createUMLObject(t, name, m_scope[m_scopeIndex], m_comment);
+ m_scope[++m_scopeIndex] = m_klass = static_cast<UMLClassifier*>(ns);
+ m_klass->setAbstract(m_isAbstract);
+ m_klass->setStatic(m_isStatic);
+ m_klass->setVisibility(m_currentAccess);
+ // The UMLObject found by createUMLObject might originally have been created as a
+ // placeholder with a type of class but if is really an interface, then we need to
+ // change it.
+ Uml::Object_Type ot = (keyword == "interface" ? Uml::ot_Interface : Uml::ot_Class);
+ m_klass->setBaseType(ot);
+ m_isAbstract = m_isStatic = false;
+ // if no modifier is specified in an interface, then it means public
+ if ( m_klass->isInterface() ) {
+ m_defaultCurrentAccess = Uml::Visibility::Public;
+ }
+ if (advance() == ";") // forward declaration
+ return true;
+ if (m_source[m_srcIndex] == "<") {
+ // template args - preliminary, rudimentary implementation
+ // @todo implement all template arg syntax
+ uint start = m_srcIndex;
+ if (! skipToClosing('<')) {
+ kError() << "importJava(" << name << "): template syntax error" << endl;
+ return false;
+ }
+ while (1) {
+ const QString arg = m_source[++start];
+ if (! arg.contains( QRegExp("^[A-Za-z_]") )) {
+ kDebug() << "importJava(" << name << "): cannot handle template syntax ("
+ << arg << ")" << endl;
+ break;
+ }
+ /* UMLTemplate *tmpl = */ m_klass->addTemplate(arg);
+ const QString next = m_source[++start];
+ if (next == ">")
+ break;
+ if (next != ",") {
+ kDebug() << "importJava(" << name << "): can't handle template syntax ("
+ << next << ")" << endl;
+ break;
+ }
+ }
+ advance(); // skip over ">"
+ }
+ if (m_source[m_srcIndex] == "extends") {
+ const QString& baseName = advance();
+ // try to resolve the class we are extending, or if impossible
+ // create a placeholder
+ UMLObject *parent = resolveClass( baseName );
+ if ( parent ) {
+ Import_Utils::createGeneralization(m_klass, static_cast<UMLClassifier*>(parent));
+ } else {
+ kDebug() << "importJava parentClass " << baseName
+ << " is not resolveable. Creating placeholder" << endl;
+ Import_Utils::createGeneralization(m_klass, baseName);
+ }
+ advance();
+ }
+ if (m_source[m_srcIndex] == "implements") {
+ while (m_srcIndex < srcLength - 1 && advance() != "{") {
+ const QString& baseName = m_source[m_srcIndex];
+ // try to resolve the interface we are implementing, if this fails
+ // create a placeholder
+ UMLObject *interface = resolveClass( baseName );
+ if ( interface ) {
+ Import_Utils::createGeneralization(m_klass, static_cast<UMLClassifier*>(interface));
+ } else {
+ kDebug() << "importJava implementing interface "<< baseName
+ <<" is not resolvable. Creating placeholder" <<endl;
+ Import_Utils::createGeneralization(m_klass, baseName);
+ }
+ if (advance() != ",")
+ break;
+ }
+ }
+ if (m_source[m_srcIndex] != "{") {
+ kError() << "importJava: ignoring excess chars at " << name
+ << " (" << m_source[m_srcIndex] << ")" << endl;
+ skipStmt("{");
+ }
+ return true;
+ }
+ if (keyword == "enum") {
+ const QString& name = advance();
+ UMLObject *ns = Import_Utils::createUMLObject(Uml::ot_Enum,
+ name, m_scope[m_scopeIndex], m_comment);
+ UMLEnum *enumType = static_cast<UMLEnum*>(ns);
+ skipStmt("{");
+ while (m_srcIndex < srcLength - 1 && advance() != "}") {
+ Import_Utils::addEnumLiteral(enumType, m_source[m_srcIndex]);
+ QString next = advance();
+ if (next == "{" || next == "(") {
+ if (! skipToClosing(next[0]))
+ return false;
+ next = advance();
+ }
+ if (next != ",") {
+ if (next == ";") {
+ // @todo handle methods in enum
+ // For now, we cheat (skip them)
+ m_source[m_srcIndex] = "{";
+ if (! skipToClosing('{'))
+ return false;
+ }
+ break;
+ }
+ }
+ return true;
+ }
+ if (keyword == "static") {
+ m_isStatic = true;
+ return true;
+ }
+ // if we detected static previously and keyword is { then this is a static block
+ if (m_isStatic && keyword == "{") {
+ // reset static flag and jump to end of static block
+ m_isStatic = false;
+ return skipToClosing('{');
+ }
+ if (keyword == "abstract") {
+ m_isAbstract = true;
+ return true;
+ }
+ if (keyword == "public") {
+ m_currentAccess = Uml::Visibility::Public;
+ return true;
+ }
+ if (keyword == "protected") {
+ m_currentAccess = Uml::Visibility::Protected;
+ return true;
+ }
+ if (keyword == "private") {
+ m_currentAccess = Uml::Visibility::Private;
+ return true;
+ }
+ if (keyword == "final" ||
+ keyword == "native" ||
+ keyword == "synchronized" ||
+ keyword == "transient" ||
+ keyword == "volatile") {
+ //@todo anything to do here?
+ return true;
+ }
+ if (keyword == "import") {
+ // keep track of imports so we can resolve classes we are dependent on
+ QString import = advance();
+ if ( import.endsWith(".") ) {
+ //this most likely an import that ends with a *
+ //
+ import = import + advance();
+ }
+ m_imports.append( import );
+
+ // move past ;
+ skipStmt();
+ return true;
+ }
+ if (keyword == "@") { // annotation
+ advance();
+ if (m_source[m_srcIndex + 1] == "(") {
+ advance();
+ skipToClosing('(');
+ }
+ return true;
+ }
+ if (keyword == "}") {
+ if (m_scopeIndex)
+ m_klass = dynamic_cast<UMLClassifier*>(m_scope[--m_scopeIndex]);
+ else
+ kError() << "importJava: too many }" << endl;
+ return true;
+ }
+ // At this point, we expect `keyword' to be a type name
+ // (of a member of class or interface, or return type
+ // of an operation.) Up next is the name of the attribute
+ // or operation.
+ if (! keyword.contains( QRegExp("^\\w") )) {
+ kError() << "importJava: ignoring " << keyword << endl;
+ return false;
+ }
+ QString typeName = m_source[m_srcIndex];
+ typeName = joinTypename(typeName);
+ // At this point we need a class.
+ if (m_klass == NULL) {
+ kError() << "importJava: no class set for " << typeName << endl;
+ return false;
+ }
+ QString name = advance();
+ QString nextToken;
+ if (typeName == m_klass->getName() && name == "(") {
+ // Constructor.
+ nextToken = name;
+ name = typeName;
+ typeName = QString();
+ } else {
+ nextToken = advance();
+ }
+ if (name.contains( QRegExp("\\W") )) {
+ kError() << "importJava: expecting name in " << name << endl;
+ return false;
+ }
+ if (nextToken == "(") {
+ // operation
+ UMLOperation *op = Import_Utils::makeOperation(m_klass, name);
+ m_srcIndex++;
+ while (m_srcIndex < srcLength && m_source[m_srcIndex] != ")") {
+ QString typeName = m_source[m_srcIndex];
+ if ( typeName == "final" || typeName.startsWith( "//") ) {
+ // ignore the "final" keyword and any comments in method args
+ typeName = advance();
+ }
+ typeName = joinTypename(typeName);
+ QString parName = advance();
+ // the Class might not be resolved yet so resolve it if necessary
+ UMLObject *obj = resolveClass(typeName);
+ if (obj) {
+ // by prepending the package, unwanted placeholder types will not get created
+ typeName = obj->getFullyQualifiedName(".");
+ }
+ /* UMLAttribute *att = */ Import_Utils::addMethodParameter(op, typeName, parName);
+ if (advance() != ",")
+ break;
+ m_srcIndex++;
+ }
+ // before adding the method, try resolving the return type
+ UMLObject *obj = resolveClass(typeName);
+ if (obj) {
+ // using the fully qualified name means that a placeholder type will not be created.
+ typeName = obj->getFullyQualifiedName(".");
+ }
+ Import_Utils::insertMethod(m_klass, op, m_currentAccess, typeName,
+ m_isStatic, m_isAbstract, false /*isFriend*/,
+ false /*isConstructor*/, m_comment);
+ m_isAbstract = m_isStatic = false;
+ // reset the default visibility
+ m_currentAccess = m_defaultCurrentAccess;
+ // At this point we do not know whether the method has a body or not.
+ do {
+ nextToken = advance();
+ } while (nextToken != "{" && nextToken != ";");
+ if (nextToken == ";") {
+ // No body (interface or abstract)
+ return true;
+ } else {
+ return skipToClosing('{');
+ }
+ }
+ // At this point we know it's some kind of attribute declaration.
+ while (1) {
+ while (nextToken != "," && nextToken != ";") {
+ if (nextToken == "=") {
+ if ((nextToken = advance()) == "new") {
+ advance();
+ if ((nextToken = advance()) == "(") {
+ skipToClosing('(');
+ if ((nextToken = advance()) == "{") {
+ skipToClosing('{');
+ } else {
+ skipStmt();
+ break;
+ }
+ } else {
+ skipStmt();
+ break;
+ }
+ } else {
+ skipStmt();
+ break;
+ }
+ } else {
+ name += nextToken; // add possible array dimensions to `name'
+ }
+ nextToken = advance();
+ }
+ // try to resolve the class type, or create a placeholder if that fails
+ UMLObject *type = resolveClass( typeName );
+ UMLObject *o;
+ if (type) {
+ o = Import_Utils::insertAttribute(m_klass, m_currentAccess, name,
+ static_cast<UMLClassifier*>(type), m_comment, m_isStatic);
+ } else {
+ o = Import_Utils::insertAttribute(m_klass, m_currentAccess, name,
+ typeName, m_comment, m_isStatic);
+ }
+ // UMLAttribute *attr = static_cast<UMLAttribute*>(o);
+ if (nextToken != ",") {
+ // reset the modifiers
+ m_isStatic = m_isAbstract = false;
+ break;
+ }
+ name = advance();
+ nextToken = advance();
+ }
+ // reset visibility to default
+ m_currentAccess = m_defaultCurrentAccess;
+ if (m_source[m_srcIndex] != ";") {
+ kError() << "importJava: ignoring trailing items at " << name << endl;
+ skipStmt();
+ }
+ return true;
+}
+
+
diff --git a/umbrello/umbrello/codeimport/javaimport.h b/umbrello/umbrello/codeimport/javaimport.h
new file mode 100644
index 00000000..30fa2395
--- /dev/null
+++ b/umbrello/umbrello/codeimport/javaimport.h
@@ -0,0 +1,106 @@
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * copyright (C) 2006 *
+ * Umbrello UML Modeller Authors <uml-devel@uml.sf.net> *
+ ***************************************************************************/
+
+#ifndef JAVAIMPORT_H
+#define JAVAIMPORT_H
+
+#include "nativeimportbase.h"
+#include "../umlobject.h"
+
+/**
+ * Java code import
+ * @author Oliver Kellogg
+ * @author JP Fournier
+ * Bugs and comments to uml-devel@lists.sf.net or http://bugs.kde.org
+ */
+class JavaImport : public NativeImportBase {
+public:
+ JavaImport();
+ virtual ~JavaImport();
+
+protected:
+ /**
+ * Reimplement operation from NativeImportBase.
+ */
+ void initVars();
+
+ /**
+ * Implement abstract operation from NativeImportBase.
+ */
+ bool parseStmt();
+
+ /**
+ * Implement abstract operation from NativeImportBase.
+ */
+ void fillSource(const QString& word);
+
+ /**
+ * Keep track of the filename currently being parsed
+ */
+ void parseFile(const QString& filename);
+
+ /**
+ * Try to resolve the specified class the current class depends on
+ */
+ UMLObject* resolveClass (QString className);
+
+ /**
+ * spawn off an import of the specified file
+ */
+ void spawnImport(QString file);
+
+ /**
+ * figure out if the type is really an array or template of the given typeName
+ */
+ QString joinTypename(QString typeName);
+
+ /**
+ * true if the member var or method is declared static
+ */
+ bool m_isStatic;
+
+ /**
+ * The current filename being parsed
+ */
+ QString m_currentFileName;
+
+ /**
+ * the current package of the file being parsed
+ */
+ QString m_currentPackage;
+
+ /**
+ * the imports included in the current file
+ */
+ QStringList m_imports;
+
+ /**
+ * Keep track of the files we have already parsed so we don't
+ * reparse the same ones over and over again.
+ */
+ static QStringList s_filesAlreadyParsed;
+
+ /**
+ * Keep track of the parses so that the filesAlreadyParsed
+ * can be reset when we're done.
+ */
+ static int s_parseDepth;
+
+ /**
+ * The current visibility for when the visibility is absent
+ */
+ Uml::Visibility m_defaultCurrentAccess;
+
+
+};
+
+#endif
+
diff --git a/umbrello/umbrello/codeimport/kdevcppparser/Makefile.am b/umbrello/umbrello/codeimport/kdevcppparser/Makefile.am
new file mode 100644
index 00000000..b8325478
--- /dev/null
+++ b/umbrello/umbrello/codeimport/kdevcppparser/Makefile.am
@@ -0,0 +1,5 @@
+INCLUDES = $(all_includes)
+
+noinst_LTLIBRARIES = libkdevcppparser.la
+libkdevcppparser_la_SOURCES = ast.cpp driver.cpp errors.cpp lexer.cpp lookup.cpp parser.cpp tree_parser.cpp urlutil.cpp ast_utils.cpp cpptree2uml.cpp
+
diff --git a/umbrello/umbrello/codeimport/kdevcppparser/README b/umbrello/umbrello/codeimport/kdevcppparser/README
new file mode 100644
index 00000000..3ed39eba
--- /dev/null
+++ b/umbrello/umbrello/codeimport/kdevcppparser/README
@@ -0,0 +1,56 @@
+This directory contains the C++ parser from Kdevelop-3.0.
+
+Following files are copies from the directory kdevelop/lib/cppparser:
+ ast.{h,cpp} driver.{h,cpp} errors.{h,cpp} keywords.lut.h lexer.{h,cpp}
+ lookup.{h,cpp} parser.{h,cpp} tree_parser.{h,cpp}
+
+Following files are copies from the directory kdevelop/languages/cpp:
+ ast_utils.{h,cpp}
+
+Following files are copies from the directory kdevelop/lib/util:
+ urlutil.{h,cpp}
+
+The source files cpptree2uml.{h,cpp} are based on kdevelop/languages/cpp/
+store_walker.{h,cpp}. The class CppTree2Uml inherits from class TreeParser
+and overrides certain methods from that class.
+
+CppTree2Uml visits the nodes of the abstract syntax tree constructed by the
+CppParser, and constructs UML objects on the way.
+
+The import_utils.h (in the parent directory) is the interface between the
+CppTree2Uml and Umbrello.
+import_utils implements the construction of the UML objects. CppTree2Uml calls
+the create/insert methods in the import_utils while traversing the syntax
+tree.
+
+The one and only method that Umbrello uses for accessing the C++ parser,
+and any other parser for that matter, is ClassImport::importFiles().
+The class CppImport (in the parent directory) implements that operation.
+Thus we have these classes:
+
+ +-------------------+
+ | <<interface>> |
+ | ClassImport |
+ +===================+
+Umbrello ------>| importFiles() = 0 |
+ +-------------------+
+ A
+ | <<realize>>
+ |
+ +-------------------+ +-------------------+
+ | CppImport | | CppTree2Uml |
+ +===================+ <<invoke>> +===================+
+ | importFiles() |-------------->| |
+ +-------------------+ | |
+ +-------------------+
+ |
+ +-------------------+ |
+ | <<utility>> | |
+ | Import_Utils | |
+ +===================+ |
+ | createUMLObject() | <<invoke>> |
+ | insertMethod() |<-----------------------+
+ | insertAttribute() |
+ +-------------------+
+ |
+Umbrello <--------------+
diff --git a/umbrello/umbrello/codeimport/kdevcppparser/ast.cpp b/umbrello/umbrello/codeimport/kdevcppparser/ast.cpp
new file mode 100644
index 00000000..6baca685
--- /dev/null
+++ b/umbrello/umbrello/codeimport/kdevcppparser/ast.cpp
@@ -0,0 +1,1183 @@
+/* This file is part of KDevelop
+ Copyright (C) 2002,2003 Roberto Raggi <roberto@kdevelop.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.
+*/
+
+#include "ast.h"
+#include <qstringlist.h>
+#include <kdebug.h>
+
+QString nodeTypeToString( int type )
+{
+ switch( type )
+ {
+ case NodeType_Generic:
+ return "Generic";
+ case NodeType_TemplateArgumentList:
+ return "TemplateArgumentList";
+ case NodeType_ClassOrNamespaceName:
+ return "ClassOrNamespaceName";
+ case NodeType_Name:
+ return "Name";
+ case NodeType_Declaration:
+ return "Declaration";
+ case NodeType_TypeSpecifier:
+ return "TypeSpecifier";
+ case NodeType_BaseSpecifier:
+ return "BaseSpecifier";
+ case NodeType_BaseClause:
+ return "BaseClause";
+ case NodeType_ClassSpecifier:
+ return "ClassSpecifier";
+ case NodeType_Enumerator:
+ return "Enumerator";
+ case NodeType_EnumSpecifier:
+ return "EnumSpecifier";
+ case NodeType_ElaboratedTypeSpecifier:
+ return "ElaboratedTypeSpecifier";
+ case NodeType_LinkageBody:
+ return "LinkageBody";
+ case NodeType_LinkageSpecification:
+ return "LinkageSpecification";
+ case NodeType_Namespace:
+ return "Namespace";
+ case NodeType_NamespaceAlias:
+ return "NamespaceAlias";
+ case NodeType_Using:
+ return "Using";
+ case NodeType_UsingDirective:
+ return "UsingDirective";
+ case NodeType_InitDeclaratorList:
+ return "InitDeclaratorList";
+ case NodeType_Typedef:
+ return "Typedef";
+ case NodeType_Declarator:
+ return "Declarator";
+ case NodeType_InitDeclarator:
+ return "InitDeclarator";
+ case NodeType_TemplateDeclaration:
+ return "TemplateDeclaration";
+ case NodeType_SimpleDeclaration:
+ return "SimpleDeclaration";
+ case NodeType_Statement:
+ return "Statement";
+ case NodeType_IfStatement:
+ return "IfStatement";
+ case NodeType_WhileStatement:
+ return "WhileStatement";
+ case NodeType_DoStatement:
+ return "DoStatement";
+ case NodeType_ForStatement:
+ return "ForStatement";
+ case NodeType_SwitchStatement:
+ return "SwitchStatement";
+ case NodeType_DeclarationStatement:
+ return "DeclarationStatement";
+ case NodeType_StatementList:
+ return "StatementList";
+ case NodeType_TranslationUnit:
+ return "TranslationUnit";
+ case NodeType_FunctionDefinition:
+ return "FunctionDefinition";
+ case NodeType_ExpressionStatement:
+ return "ExpressionStatement";
+ case NodeType_ParameterDeclaration:
+ return "ParameterDeclaration";
+ case NodeType_ParameterDeclarationList:
+ return "ParameterDeclarationList";
+ case NodeType_ParameterDeclarationClause:
+ return "ParameterDeclarationClause";
+ case NodeType_Group:
+ return "Group";
+ case NodeType_AccessDeclaration:
+ return "AccessDeclaration";
+ case NodeType_TypeParameter:
+ return "TypeParameter";
+ case NodeType_TemplateParameter:
+ return "TemplateParameter";
+ case NodeType_TemplateParameterList:
+ return "TemplateParameterList";
+ case NodeType_Condition:
+ return "Condition";
+ case NodeType_Custom:
+ return "Custom";
+ }
+
+ return QString::null;
+}
+
+
+// ------------------------------------------------------------------------
+AST::AST()
+ : m_nodeType( NodeType_Generic ), m_parent( 0 ),
+ m_startLine( 0 ), m_startColumn( 0 ),
+ m_endLine( 0 ), m_endColumn( 0 )
+{
+#ifndef CPPPARSER_NO_CHILDREN
+ m_children.setAutoDelete( false );
+#endif
+}
+
+AST::~AST()
+{
+#ifndef CPPPARSER_NO_CHILDREN
+ if( m_parent )
+ m_parent->removeChild( this );
+#endif
+}
+
+void AST::setStartPosition( int line, int col )
+{
+ m_startLine = line;
+ m_startColumn = col;
+}
+
+void AST::getStartPosition( int* line, int* col ) const
+{
+ if( line )
+ *line = m_startLine;
+
+ if( col )
+ * col = m_startColumn;
+}
+
+void AST::setEndPosition( int line, int col )
+{
+ m_endLine = line;
+ m_endColumn = col;
+}
+
+void AST::getEndPosition( int* line, int* col ) const
+{
+ if( line )
+ *line = m_endLine;
+
+ if( col )
+ * col = m_endColumn;
+}
+
+void AST::setParent( AST* parent )
+{
+#ifndef CPPPARSER_NO_CHILDREN
+ if( m_parent )
+ m_parent->removeChild( this );
+#endif
+
+ m_parent = parent;
+
+#ifndef CPPPARSER_NO_CHILDREN
+ if( m_parent )
+ m_parent->appendChild( this );
+#endif
+}
+
+#ifndef CPPPARSER_NO_CHILDREN
+void AST::appendChild( AST* child )
+{
+ m_children.append( child );
+}
+
+void AST::removeChild( AST* child )
+{
+ m_children.remove( child );
+}
+#endif
+
+// ------------------------------------------------------------------------
+NameAST::NameAST()
+ : m_global( false )
+{
+ m_classOrNamespaceNameList.setAutoDelete( true );
+}
+
+void NameAST::setGlobal( bool b )
+{
+ m_global = b;
+}
+
+void NameAST::setUnqualifiedName( ClassOrNamespaceNameAST::Node& unqualifiedName )
+{
+ m_unqualifiedName = unqualifiedName;
+ if( m_unqualifiedName.get() ) m_unqualifiedName->setParent( this );
+}
+
+void NameAST::addClassOrNamespaceName( ClassOrNamespaceNameAST::Node& classOrNamespaceName )
+{
+ if( !classOrNamespaceName.get() )
+ return;
+
+ classOrNamespaceName->setParent( this );
+ m_classOrNamespaceNameList.append( classOrNamespaceName.release() );
+}
+
+QString NameAST::text() const
+{
+ if( !m_unqualifiedName.get() )
+ return QString::null;
+
+ QString str;
+
+ if( m_global )
+ str += "::";
+
+ QStringList l;
+ QPtrListIterator<ClassOrNamespaceNameAST> it( m_classOrNamespaceNameList );
+ while( it.current() ){
+ str += it.current()->text() + "::";
+ ++it;
+ }
+
+ if( m_unqualifiedName.get() )
+ str += m_unqualifiedName->text();
+
+ return str;
+}
+
+// ------------------------------------------------------------------------
+DeclarationAST::DeclarationAST()
+{
+}
+
+// ------------------------------------------------------------------------
+LinkageBodyAST::LinkageBodyAST()
+{
+ m_declarationList.setAutoDelete( true );
+}
+
+void LinkageBodyAST::addDeclaration( DeclarationAST::Node& ast )
+{
+ if( !ast.get() )
+ return;
+
+ ast->setParent( this );
+ m_declarationList.append( ast.release() );
+}
+
+// ------------------------------------------------------------------------
+LinkageSpecificationAST::LinkageSpecificationAST()
+{
+}
+
+void LinkageSpecificationAST::setExternType( AST::Node& externType )
+{
+ m_externType = externType;
+ if( m_externType.get() ) m_externType->setParent( this );
+}
+
+void LinkageSpecificationAST::setLinkageBody( LinkageBodyAST::Node& linkageBody )
+{
+ m_linkageBody = linkageBody;
+ if( m_linkageBody.get() ) m_linkageBody->setParent( this );
+}
+
+void LinkageSpecificationAST::setDeclaration( DeclarationAST::Node& decl )
+{
+ m_declaration = decl;
+ if( m_declaration.get() ) m_declaration->setParent( this );
+}
+
+// ------------------------------------------------------------------------
+TranslationUnitAST::TranslationUnitAST()
+{
+ //kdDebug(9007) << "++ TranslationUnitAST::TranslationUnitAST()" << endl;
+ m_declarationList.setAutoDelete( true );
+}
+
+void TranslationUnitAST::addDeclaration( DeclarationAST::Node& ast )
+{
+ if( !ast.get() )
+ return;
+
+ ast->setParent( this );
+ m_declarationList.append( ast.release() );
+}
+
+// ------------------------------------------------------------------------
+NamespaceAST::NamespaceAST()
+{
+}
+
+void NamespaceAST::setNamespaceName( AST::Node& namespaceName )
+{
+ m_namespaceName = namespaceName;
+ if( m_namespaceName.get() ) m_namespaceName->setParent( this );
+}
+
+void NamespaceAST::setLinkageBody( LinkageBodyAST::Node& linkageBody )
+{
+ m_linkageBody = linkageBody;
+ if( m_linkageBody.get() ) m_linkageBody->setParent( this );
+}
+
+
+// ------------------------------------------------------------------------
+NamespaceAliasAST::NamespaceAliasAST()
+{
+}
+
+void NamespaceAliasAST::setNamespaceName( AST::Node& namespaceName )
+{
+ m_namespaceName = namespaceName;
+ if( m_namespaceName.get() ) m_namespaceName->setParent( this );
+}
+
+void NamespaceAliasAST::setAliasName( NameAST::Node& name )
+{
+ m_aliasName = name;
+ if( m_aliasName.get() ) m_aliasName->setParent( this );
+}
+
+// ------------------------------------------------------------------------
+UsingAST::UsingAST()
+{
+}
+
+void UsingAST::setTypeName( AST::Node& typeName )
+{
+ m_typeName = typeName;
+ if( m_typeName.get() ) m_typeName->setParent( this );
+}
+
+void UsingAST::setName( NameAST::Node& name )
+{
+ m_name = name;
+ if( m_name.get() ) m_name->setParent( this );
+}
+
+// ------------------------------------------------------------------------
+UsingDirectiveAST::UsingDirectiveAST()
+{
+}
+
+void UsingDirectiveAST::setName( NameAST::Node& name )
+{
+ m_name = name;
+ if( m_name.get() ) m_name->setParent( this );
+}
+
+TypedefAST::TypedefAST()
+{
+}
+
+void TypeSpecifierAST::setName( NameAST::Node& name )
+{
+ m_name = name;
+ if( m_name.get() ) m_name->setParent( this );
+}
+
+void TypedefAST::setTypeSpec( TypeSpecifierAST::Node& typeSpec )
+{
+ m_typeSpec = typeSpec;
+ if( m_typeSpec.get() ) m_typeSpec->setParent( this );
+}
+
+void TypedefAST::setInitDeclaratorList( InitDeclaratorListAST::Node& initDeclaratorList )
+{
+ m_initDeclaratorList = initDeclaratorList;
+ if( m_initDeclaratorList.get() ) m_initDeclaratorList->setParent( this );
+}
+
+// ------------------------------------------------------------------------
+TemplateArgumentListAST::TemplateArgumentListAST()
+{
+ m_argumentList.setAutoDelete( true );
+}
+
+void TemplateArgumentListAST::addArgument( AST::Node& arg )
+{
+ if( !arg.get() )
+ return;
+
+ arg->setParent( this );
+ m_argumentList.append( arg.release() );
+}
+
+QString TemplateArgumentListAST::text() const
+{
+ QStringList l;
+
+ QPtrListIterator<AST> it( m_argumentList );
+ while( it.current() ){
+ l.append( it.current()->text() );
+ ++it;
+ }
+
+ return l.join( ", " );
+}
+
+// ------------------------------------------------------------------------
+TemplateDeclarationAST::TemplateDeclarationAST()
+{
+}
+
+void TemplateDeclarationAST::setExported( AST::Node& exported )
+{
+ m_exported = exported;
+ if( m_exported.get() ) m_exported->setParent( this );
+}
+
+void TemplateDeclarationAST::setTemplateParameterList( TemplateParameterListAST::Node& templateParameterList )
+{
+ m_templateParameterList = templateParameterList;
+ if( m_templateParameterList.get() ) m_templateParameterList->setParent( this );
+}
+
+void TemplateDeclarationAST::setDeclaration( DeclarationAST::Node& declaration )
+{
+ m_declaration = declaration;
+ if( m_declaration.get() ) m_declaration->setParent( this );
+}
+
+// ------------------------------------------------------------------------
+ClassOrNamespaceNameAST::ClassOrNamespaceNameAST()
+{
+}
+
+void ClassOrNamespaceNameAST::setName( AST::Node& name )
+{
+ m_name = name;
+ if( m_name.get() ) m_name->setParent( this );
+}
+
+void ClassOrNamespaceNameAST::setTemplateArgumentList( TemplateArgumentListAST::Node& templateArgumentList )
+{
+ m_templateArgumentList = templateArgumentList;
+ if( m_templateArgumentList.get() ) m_templateArgumentList->setParent( this );
+}
+
+QString ClassOrNamespaceNameAST::text() const
+{
+ if( !m_name.get() )
+ return QString::null;
+
+ QString str = m_name->text();
+ if( m_templateArgumentList.get() )
+ str += QString::fromLatin1("< ") + m_templateArgumentList->text() + QString::fromLatin1(" >");
+
+ return str;
+}
+
+// ------------------------------------------------------------------------
+TypeSpecifierAST::TypeSpecifierAST()
+{
+}
+
+void TypeSpecifierAST::setCvQualify( GroupAST::Node& cvQualify )
+{
+ m_cvQualify = cvQualify;
+ if( m_cvQualify.get() ) m_cvQualify->setParent( this );
+}
+
+void TypeSpecifierAST::setCv2Qualify( GroupAST::Node& cv2Qualify )
+{
+ m_cv2Qualify = cv2Qualify;
+ if( m_cv2Qualify.get() ) m_cv2Qualify->setParent( this );
+}
+
+QString TypeSpecifierAST::text() const
+{
+ QString str;
+
+ if( m_cvQualify.get() )
+ str += m_cvQualify->text() + ' ';
+
+ if( m_name.get() )
+ str += m_name->text();
+
+ if( m_cv2Qualify.get() )
+ str += QString(" ") + m_cv2Qualify->text();
+
+ return str;
+}
+
+// ------------------------------------------------------------------------
+ClassSpecifierAST::ClassSpecifierAST()
+{
+ m_declarationList.setAutoDelete( true );
+}
+
+void ClassSpecifierAST::setClassKey( AST::Node& classKey )
+{
+ m_classKey = classKey;
+ if( m_classKey.get() ) m_classKey->setParent( this );
+}
+
+void ClassSpecifierAST::addDeclaration( DeclarationAST::Node& declaration )
+{
+ if( !declaration.get() )
+ return;
+
+ declaration->setParent( this );
+ m_declarationList.append( declaration.release() );
+}
+
+void ClassSpecifierAST::setBaseClause( BaseClauseAST::Node& baseClause )
+{
+ m_baseClause = baseClause;
+ if( m_baseClause.get() ) m_baseClause->setParent( this );
+}
+
+// ------------------------------------------------------------------------
+EnumSpecifierAST::EnumSpecifierAST()
+{
+ m_enumeratorList.setAutoDelete( true );
+}
+
+void EnumSpecifierAST::addEnumerator( EnumeratorAST::Node& enumerator )
+{
+ if( !enumerator.get() )
+ return;
+
+ enumerator->setParent( this );
+ m_enumeratorList.append( enumerator.release() );
+}
+
+
+// ------------------------------------------------------------------------
+ElaboratedTypeSpecifierAST::ElaboratedTypeSpecifierAST()
+{
+}
+
+void ElaboratedTypeSpecifierAST::setKind( AST::Node& kind )
+{
+ m_kind = kind;
+ if( m_kind.get() ) m_kind->setParent( this );
+}
+
+QString ElaboratedTypeSpecifierAST::text() const
+{
+ if( m_kind.get() )
+ return m_kind->text() + ' ' + TypeSpecifierAST::text();
+
+ return TypeSpecifierAST::text();
+}
+
+// ------------------------------------------------------------------------
+StatementAST::StatementAST()
+{
+}
+
+// ------------------------------------------------------------------------
+EnumeratorAST::EnumeratorAST()
+{
+}
+
+void EnumeratorAST::setId( AST::Node& id )
+{
+ m_id = id;
+ if( m_id.get() ) m_id->setParent( this );
+}
+
+void EnumeratorAST::setExpr( AST::Node& expr )
+{
+ m_expr = expr;
+ if( m_expr.get() ) m_expr->setParent( this );
+}
+
+// ------------------------------------------------------------------------
+BaseClauseAST::BaseClauseAST()
+{
+ m_baseSpecifierList.setAutoDelete( true );
+}
+
+void BaseClauseAST::addBaseSpecifier( BaseSpecifierAST::Node& baseSpecifier )
+{
+ if( !baseSpecifier.get() )
+ return;
+
+ baseSpecifier->setParent( this );
+ m_baseSpecifierList.append( baseSpecifier.release() );
+}
+
+// ------------------------------------------------------------------------
+BaseSpecifierAST::BaseSpecifierAST()
+{
+}
+
+void BaseSpecifierAST::setIsVirtual( AST::Node& isVirtual )
+{
+ m_isVirtual = isVirtual;
+ if( m_isVirtual.get() ) m_isVirtual->setParent( this );
+}
+
+void BaseSpecifierAST::setAccess( AST::Node& access )
+{
+ m_access = access;
+ if( m_access.get() ) m_access->setParent( this );
+}
+
+void BaseSpecifierAST::setName( NameAST::Node& name )
+{
+ m_name = name;
+ if( m_name.get() ) m_name->setParent( this );
+}
+
+// ------------------------------------------------------------------------
+SimpleDeclarationAST::SimpleDeclarationAST()
+{
+}
+
+void SimpleDeclarationAST::setFunctionSpecifier( GroupAST::Node& functionSpecifier )
+{
+ m_functionSpecifier = functionSpecifier;
+ if( m_functionSpecifier.get() ) m_functionSpecifier->setParent( this );
+}
+
+void SimpleDeclarationAST::setStorageSpecifier( GroupAST::Node& storageSpecifier )
+{
+ m_storageSpecifier = storageSpecifier;
+ if( m_storageSpecifier.get() ) m_storageSpecifier->setParent( this );
+}
+
+void SimpleDeclarationAST::setTypeSpec( TypeSpecifierAST::Node& typeSpec )
+{
+ m_typeSpec = typeSpec;
+ if( m_typeSpec.get() ) m_typeSpec->setParent( this );
+}
+
+void SimpleDeclarationAST::setInitDeclaratorList( InitDeclaratorListAST::Node& initDeclaratorList )
+{
+ m_initDeclaratorList = initDeclaratorList;
+ if( m_initDeclaratorList.get() ) m_initDeclaratorList->setParent( this );
+}
+
+void SimpleDeclarationAST::setWinDeclSpec( GroupAST::Node& winDeclSpec )
+{
+ m_winDeclSpec = winDeclSpec;
+ if( m_winDeclSpec.get() ) m_winDeclSpec->setParent( this );
+}
+
+
+// ------------------------------------------------------------------------
+InitDeclaratorListAST::InitDeclaratorListAST()
+{
+ m_initDeclaratorList.setAutoDelete( true );
+}
+
+void InitDeclaratorListAST::addInitDeclarator( InitDeclaratorAST::Node& decl )
+{
+ if( !decl.get() )
+ return;
+
+ decl->setParent( this );
+ m_initDeclaratorList.append( decl.release() );
+}
+
+// ------------------------------------------------------------------------
+DeclaratorAST::DeclaratorAST()
+{
+ m_ptrOpList.setAutoDelete( true );
+ m_arrayDimensionList.setAutoDelete( true );
+}
+
+void DeclaratorAST::setSubDeclarator( DeclaratorAST::Node& subDeclarator )
+{
+ m_subDeclarator = subDeclarator;
+ if( m_subDeclarator.get() ) m_subDeclarator->setParent( this );
+}
+
+void DeclaratorAST::setDeclaratorId( NameAST::Node& declaratorId )
+{
+ m_declaratorId = declaratorId;
+ if( m_declaratorId.get() ) m_declaratorId->setParent( this );
+}
+
+void DeclaratorAST::setBitfieldInitialization( AST::Node& bitfieldInitialization )
+{
+ m_bitfieldInitialization = bitfieldInitialization;
+ if( m_bitfieldInitialization.get() ) m_bitfieldInitialization->setParent( this );
+}
+
+void DeclaratorAST::addArrayDimension( AST::Node& arrayDimension )
+{
+ if( !arrayDimension.get() )
+ return;
+
+ arrayDimension->setParent( this );
+ m_arrayDimensionList.append( arrayDimension.release() );
+}
+
+void DeclaratorAST::setParameterDeclarationClause( AUTO_PTR<class ParameterDeclarationClauseAST>& parameterDeclarationClause )
+{
+ m_parameterDeclarationClause = parameterDeclarationClause;
+ if( m_parameterDeclarationClause.get() ) m_parameterDeclarationClause->setParent( this );
+}
+
+void DeclaratorAST::setConstant( AST::Node& constant )
+{
+ m_constant = constant;
+ if( m_constant.get() ) m_constant->setParent( this );
+}
+
+void DeclaratorAST::setExceptionSpecification( GroupAST::Node& exceptionSpecification )
+{
+ m_exceptionSpecification = exceptionSpecification;
+ if( m_exceptionSpecification.get() ) m_exceptionSpecification->setParent( this );
+}
+
+void DeclaratorAST::addPtrOp( AST::Node& ptrOp )
+{
+ if( !ptrOp.get() )
+ return;
+
+ ptrOp->setParent( this );
+ m_ptrOpList.append( ptrOp.release() );
+}
+
+// --------------------------------------------------------------------------
+InitDeclaratorAST::InitDeclaratorAST()
+{
+}
+
+void InitDeclaratorAST::setDeclarator( DeclaratorAST::Node& declarator )
+{
+ m_declarator = declarator;
+ if( m_declarator.get() ) m_declarator->setParent( this );
+}
+
+void InitDeclaratorAST::setInitializer( AST::Node& initializer )
+{
+ m_initializer = initializer;
+ if( m_initializer.get() ) m_initializer->setParent( this );
+}
+
+// --------------------------------------------------------------------------
+FunctionDefinitionAST::FunctionDefinitionAST()
+{
+}
+
+void FunctionDefinitionAST::setFunctionSpecifier( GroupAST::Node& functionSpecifier )
+{
+ m_functionSpecifier = functionSpecifier;
+ if( m_functionSpecifier.get() ) m_functionSpecifier->setParent( this );
+}
+
+void FunctionDefinitionAST::setStorageSpecifier( GroupAST::Node& storageSpecifier )
+{
+ m_storageSpecifier = storageSpecifier;
+ if( m_storageSpecifier.get() ) m_storageSpecifier->setParent( this );
+}
+
+void FunctionDefinitionAST::setTypeSpec( TypeSpecifierAST::Node& typeSpec )
+{
+ m_typeSpec = typeSpec;
+ if( m_typeSpec.get() ) m_typeSpec->setParent( this );
+}
+
+void FunctionDefinitionAST::setInitDeclarator( InitDeclaratorAST::Node& initDeclarator )
+{
+ m_initDeclarator = initDeclarator;
+ if( m_initDeclarator.get() ) m_initDeclarator->setParent( this );
+}
+
+void FunctionDefinitionAST::setFunctionBody( StatementListAST::Node& functionBody )
+{
+ m_functionBody = functionBody;
+ if( m_functionBody.get() ) m_functionBody->setParent( this );
+}
+
+void FunctionDefinitionAST::setWinDeclSpec( GroupAST::Node& winDeclSpec )
+{
+ m_winDeclSpec = winDeclSpec;
+ if( m_winDeclSpec.get() ) m_winDeclSpec->setParent( this );
+}
+
+// --------------------------------------------------------------------------
+StatementListAST::StatementListAST()
+{
+ m_statementList.setAutoDelete( true );
+}
+
+void StatementListAST::addStatement( StatementAST::Node& statement )
+{
+ if( !statement.get() )
+ return;
+
+ statement->setParent( this );
+ m_statementList.append( statement.release() );
+}
+
+// --------------------------------------------------------------------------
+IfStatementAST::IfStatementAST()
+{
+}
+
+void IfStatementAST::setCondition( ConditionAST::Node& condition )
+{
+ m_condition = condition;
+ if( m_condition.get() ) m_condition->setParent( this );
+}
+
+void IfStatementAST::setStatement( StatementAST::Node& statement )
+{
+ m_statement = statement;
+ if( m_statement.get() ) m_statement->setParent( this );
+}
+
+void IfStatementAST::setElseStatement( StatementAST::Node& elseStatement )
+{
+ m_elseStatement = elseStatement;
+ if( m_elseStatement.get() ) m_elseStatement->setParent( this );
+}
+
+// --------------------------------------------------------------------------
+WhileStatementAST::WhileStatementAST()
+{
+}
+
+void WhileStatementAST::setCondition( ConditionAST::Node& condition )
+{
+ m_condition = condition;
+ if( m_condition.get() ) m_condition->setParent( this );
+}
+
+void WhileStatementAST::setStatement( StatementAST::Node& statement )
+{
+ m_statement = statement;
+ if( m_statement.get() ) m_statement->setParent( this );
+}
+
+// --------------------------------------------------------------------------
+DoStatementAST::DoStatementAST()
+{
+}
+
+void DoStatementAST::setCondition( ConditionAST::Node& condition )
+{
+ m_condition = condition;
+ if( m_condition.get() ) m_condition->setParent( this );
+}
+
+void DoStatementAST::setStatement( StatementAST::Node& statement )
+{
+ m_statement = statement;
+ if( m_statement.get() ) m_statement->setParent( this );
+}
+
+// --------------------------------------------------------------------------
+ForStatementAST::ForStatementAST()
+{
+}
+
+void ForStatementAST::setCondition( ConditionAST::Node& condition )
+{
+ m_condition = condition;
+ if( m_condition.get() ) m_condition->setParent( this );
+}
+
+void ForStatementAST::setExpression( AST::Node& expression )
+{
+ m_expression = expression;
+ if( m_expression.get() ) m_expression->setParent( this );
+}
+
+void ForStatementAST::setStatement( StatementAST::Node& statement )
+{
+ m_statement = statement;
+ if( m_statement.get() ) m_statement->setParent( this );
+}
+
+void ForStatementAST::setInitStatement( StatementAST::Node& initStatement )
+{
+ m_initStatement = initStatement;
+ if( m_initStatement.get() ) m_initStatement->setParent( this );
+}
+
+// --------------------------------------------------------------------------
+SwitchStatementAST::SwitchStatementAST()
+{
+}
+
+void SwitchStatementAST::setCondition( ConditionAST::Node& condition )
+{
+ m_condition = condition;
+ if( m_condition.get() ) m_condition->setParent( this );
+}
+
+void SwitchStatementAST::setStatement( StatementAST::Node& statement )
+{
+ m_statement = statement;
+ if( m_statement.get() ) m_statement->setParent( this );
+}
+
+// --------------------------------------------------------------------------
+DeclarationStatementAST::DeclarationStatementAST()
+{
+}
+
+void DeclarationStatementAST::setDeclaration( DeclarationAST::Node& declaration )
+{
+ m_declaration = declaration;
+ if( m_declaration.get() ) m_declaration->setParent( this );
+}
+
+// --------------------------------------------------------------------------
+ExpressionStatementAST::ExpressionStatementAST()
+{
+}
+
+void ExpressionStatementAST::setExpression( AST::Node& expression )
+{
+ m_expression = expression;
+ if( m_expression.get() ) m_expression->setParent( this );
+}
+
+
+// --------------------------------------------------------------------------
+ParameterDeclarationAST::ParameterDeclarationAST()
+{
+}
+
+void ParameterDeclarationAST::setTypeSpec( TypeSpecifierAST::Node& typeSpec )
+{
+ m_typeSpec = typeSpec;
+ if( m_typeSpec.get() ) m_typeSpec->setParent( this );
+}
+
+void ParameterDeclarationAST::setDeclarator( DeclaratorAST::Node& declarator )
+{
+ m_declarator = declarator;
+ if( m_declarator.get() ) m_declarator->setParent( this );
+}
+
+void ParameterDeclarationAST::setExpression( AST::Node& expression )
+{
+ m_expression = expression;
+ if( m_expression.get() ) m_expression->setParent( this );
+}
+
+QString ParameterDeclarationAST::text() const
+{
+ QString str;
+ if( m_typeSpec.get() )
+ str += m_typeSpec->text() + ' ';
+
+ if( m_declarator.get() )
+ str += m_declarator->text();
+
+ if( m_expression.get() )
+ str += QString( " = " ) + m_expression->text();
+
+ return str;
+}
+
+// --------------------------------------------------------------------------
+ParameterDeclarationListAST::ParameterDeclarationListAST()
+{
+ m_parameterList.setAutoDelete( true );
+}
+
+void ParameterDeclarationListAST::addParameter( ParameterDeclarationAST::Node& parameter )
+{
+ if( !parameter.get() )
+ return;
+
+ parameter->setParent( this );
+ m_parameterList.append( parameter.release() );
+}
+
+QString ParameterDeclarationListAST::text() const
+{
+ QStringList l;
+
+ QPtrListIterator<ParameterDeclarationAST> it( m_parameterList );
+ while( it.current() ){
+ l.append( it.current()->text() );
+ ++it;
+ }
+
+ return l.join( ", " );
+}
+
+
+// --------------------------------------------------------------------------
+ParameterDeclarationClauseAST::ParameterDeclarationClauseAST()
+{
+}
+
+void ParameterDeclarationClauseAST::setParameterDeclarationList( ParameterDeclarationListAST::Node& parameterDeclarationList )
+{
+ m_parameterDeclarationList = parameterDeclarationList;
+ if( m_parameterDeclarationList.get() ) m_parameterDeclarationList->setParent( this );
+}
+
+void ParameterDeclarationClauseAST::setEllipsis( AST::Node& ellipsis )
+{
+ m_ellipsis = ellipsis;
+ if( m_ellipsis.get() ) m_ellipsis->setParent( this );
+}
+
+QString ParameterDeclarationClauseAST::text() const
+{
+ QString str;
+
+ if( m_parameterDeclarationList.get() )
+ str += m_parameterDeclarationList->text();
+
+ if( m_ellipsis.get() )
+ str += " ...";
+
+ return str;
+}
+
+
+// --------------------------------------------------------------------------
+GroupAST::GroupAST()
+{
+ m_nodeList.setAutoDelete( true );
+}
+
+void GroupAST::addNode( AST::Node& node )
+{
+ if( !node.get() )
+ return;
+
+ node->setParent( this );
+ m_nodeList.append( node.release() );
+}
+
+QString GroupAST::text() const
+{
+ QStringList l;
+
+ QPtrListIterator<AST> it( m_nodeList );
+ while( it.current() ){
+ l.append( it.current()->text() );
+ ++it;
+ }
+
+ return l.join( " " );
+}
+
+// --------------------------------------------------------------------------
+AccessDeclarationAST::AccessDeclarationAST()
+{
+ m_accessList.setAutoDelete( true );
+}
+
+void AccessDeclarationAST::addAccess( AST::Node& access )
+{
+ if( !access.get() )
+ return;
+
+ access->setParent( this );
+ m_accessList.append( access.release() );
+}
+
+QString AccessDeclarationAST::text() const
+{
+ QStringList l;
+
+ QPtrListIterator<AST> it( m_accessList );
+ while( it.current() ){
+ l.append( it.current()->text() );
+ ++it;
+ }
+
+ return l.join( " " );
+}
+
+// --------------------------------------------------------------------------
+TypeParameterAST::TypeParameterAST()
+{
+}
+
+void TypeParameterAST::setKind( AST::Node& kind )
+{
+ m_kind = kind;
+ if( m_kind.get() ) m_kind->setParent( this );
+}
+
+void TypeParameterAST::setTemplateParameterList( AUTO_PTR<class TemplateParameterListAST>& templateParameterList )
+{
+ m_templateParameterList = templateParameterList;
+ if( m_templateParameterList.get() ) m_templateParameterList->setParent( this );
+}
+
+void TypeParameterAST::setName( NameAST::Node& name )
+{
+ m_name = name;
+ if( m_name.get() ) m_name->setParent( this );
+}
+
+void TypeParameterAST::setTypeId( AST::Node& typeId )
+{
+ m_typeId = typeId;
+ if( m_typeId.get() ) m_typeId->setParent( this );
+}
+
+// --------------------------------------------------------------------------
+TemplateParameterAST::TemplateParameterAST()
+{
+}
+
+void TemplateParameterAST::setTypeParameter( TypeParameterAST::Node& typeParameter )
+{
+ m_typeParameter = typeParameter;
+ if( m_typeParameter.get() ) m_typeParameter->setParent( this );
+}
+
+void TemplateParameterAST::setTypeValueParameter( ParameterDeclarationAST::Node& typeValueParameter )
+{
+ m_typeValueParameter = typeValueParameter;
+ if( m_typeValueParameter.get() ) m_typeValueParameter->setParent( this );
+}
+
+// --------------------------------------------------------------------------
+TemplateParameterListAST::TemplateParameterListAST()
+{
+ m_templateParameterList.setAutoDelete( true );
+}
+
+void TemplateParameterListAST::addTemplateParameter( TemplateParameterAST::Node& templateParameter )
+{
+ if( !templateParameter.get() )
+ return;
+
+ templateParameter->setParent( this );
+ m_templateParameterList.append( templateParameter.release() );
+}
+
+// --------------------------------------------------------------------------
+ConditionAST::ConditionAST()
+{
+}
+
+void ConditionAST::setTypeSpec( TypeSpecifierAST::Node& typeSpec )
+{
+ m_typeSpec = typeSpec;
+ if( m_typeSpec.get() ) m_typeSpec->setParent( this );
+}
+
+void ConditionAST::setDeclarator( DeclaratorAST::Node& declarator )
+{
+ m_declarator = declarator;
+ if( m_declarator.get() ) m_declarator->setParent( this );
+}
+
+void ConditionAST::setExpression( AST::Node& expression )
+{
+ m_expression = expression;
+ if( m_expression.get() ) m_expression->setParent( this );
+}
+
+void ClassSpecifierAST::setWinDeclSpec( GroupAST::Node & winDeclSpec )
+{
+ m_winDeclSpec = winDeclSpec;
+ if( m_winDeclSpec.get() ) m_winDeclSpec->setParent( this );
+}
+
diff --git a/umbrello/umbrello/codeimport/kdevcppparser/ast.h b/umbrello/umbrello/codeimport/kdevcppparser/ast.h
new file mode 100644
index 00000000..9b7b5aac
--- /dev/null
+++ b/umbrello/umbrello/codeimport/kdevcppparser/ast.h
@@ -0,0 +1,1449 @@
+/* This file is part of KDevelop
+ Copyright (C) 2002,2003 Roberto Raggi <roberto@kdevelop.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 __ast_h
+#define __ast_h
+
+#include <memory>
+#include <qstring.h>
+#include <qptrlist.h>
+
+#if defined( Q_OS_WIN32 ) || defined( Q_CC_SUN )
+
+#ifndef _THROW0
+# define _THROW0()
+#endif
+
+template <class _Tp> class AUTO_PTR {
+private:
+ _Tp* _M_ptr;
+
+public:
+ typedef _Tp element_type;
+
+ explicit AUTO_PTR(_Tp* __p = 0) _THROW0() : _M_ptr(__p) {}
+
+ template <class _Tp1> AUTO_PTR(AUTO_PTR<_Tp1>& __a) _THROW0()
+ : _M_ptr(__a.release()) {}
+
+ AUTO_PTR(AUTO_PTR& __a) _THROW0() : _M_ptr(__a.release()) {}
+
+
+
+ template <class _Tp1>
+ AUTO_PTR& operator=(AUTO_PTR<_Tp1>& __a) _THROW0() {
+ if (__a.get() != this->get()) {
+ delete _M_ptr;
+ _M_ptr = __a.release();
+ }
+ return *this;
+ }
+
+ AUTO_PTR& operator=(AUTO_PTR& __a) _THROW0() {
+ if (&__a != this) {
+ delete _M_ptr;
+ _M_ptr = __a.release();
+ }
+ return *this;
+ }
+
+ ~AUTO_PTR() _THROW0() { delete _M_ptr; }
+
+ _Tp& operator*() const _THROW0() {
+ return *_M_ptr;
+ }
+ _Tp* operator->() const _THROW0() {
+ return _M_ptr;
+ }
+ _Tp* get() const _THROW0() {
+ return _M_ptr;
+ }
+ _Tp* release() _THROW0() {
+ _Tp* __tmp = _M_ptr;
+ _M_ptr = 0;
+ return __tmp;
+ }
+ void reset(_Tp* __p = 0) _THROW0() {
+ delete _M_ptr;
+ _M_ptr = __p;
+ }
+
+ // According to the C++ standard, these conversions are required. Most
+ // present-day compilers, however, do not enforce that requirement---and,
+ // in fact, most present-day compilers do not support the language
+ // features that these conversions rely on.
+
+
+private:
+ template<class _Tp1> struct AUTO_PTR_ref {
+ _Tp1* _M_ptr;
+ AUTO_PTR_ref(_Tp1* __p) : _M_ptr(__p) {}
+ };
+
+public:
+ AUTO_PTR(AUTO_PTR_ref<_Tp> __ref) _THROW0()
+ : _M_ptr(__ref._M_ptr) {}
+ template <class _Tp1> operator AUTO_PTR_ref<_Tp1>() _THROW0()
+ { return AUTO_PTR_ref<_Tp>(this->release()); }
+ template <class _Tp1> operator AUTO_PTR<_Tp1>() _THROW0()
+ { return AUTO_PTR<_Tp1>(this->release()) }
+
+};
+
+#else
+#define AUTO_PTR std::auto_ptr
+#endif
+
+template <class T> typename T::Node CreateNode()
+{
+ typename T::Node node( new T );
+ node->setNodeType( T::Type );
+ return node;
+}
+
+template <class T> typename T::Node NullNode()
+{
+ typename T::Node node;
+ return node;
+}
+
+enum NodeType
+{
+ NodeType_Generic = 0,
+
+ NodeType_TemplateArgumentList = 1000,
+ NodeType_ClassOrNamespaceName,
+ NodeType_Name,
+ NodeType_Declaration,
+ NodeType_TypeSpecifier,
+ NodeType_BaseSpecifier,
+ NodeType_BaseClause,
+ NodeType_ClassSpecifier,
+ NodeType_Enumerator,
+ NodeType_EnumSpecifier,
+ NodeType_ElaboratedTypeSpecifier,
+ NodeType_LinkageBody,
+ NodeType_LinkageSpecification,
+ NodeType_Namespace,
+ NodeType_NamespaceAlias,
+ NodeType_Using,
+ NodeType_UsingDirective,
+ NodeType_InitDeclaratorList,
+ NodeType_Typedef,
+ NodeType_Declarator,
+ NodeType_InitDeclarator,
+ NodeType_TemplateDeclaration,
+ NodeType_SimpleDeclaration,
+ NodeType_Statement,
+ NodeType_StatementList,
+ NodeType_IfStatement,
+ NodeType_WhileStatement,
+ NodeType_DoStatement,
+ NodeType_ForStatement,
+ NodeType_SwitchStatement,
+ NodeType_DeclarationStatement,
+ NodeType_TranslationUnit,
+ NodeType_FunctionDefinition,
+ NodeType_ExpressionStatement,
+ NodeType_ParameterDeclaration,
+ NodeType_ParameterDeclarationList,
+ NodeType_ParameterDeclarationClause,
+ NodeType_Group,
+ NodeType_AccessDeclaration,
+ NodeType_TypeParameter,
+ NodeType_TemplateParameter,
+ NodeType_TemplateParameterList,
+ NodeType_Condition,
+
+ NodeType_Custom = 2000
+};
+
+QString nodeTypeToString( int type );
+
+
+#if defined(CPPPARSER_QUICK_ALLOCATOR)
+
+#include <quick_allocator.h>
+
+#define DECLARE_ALLOC(tp) \
+ void * operator new(std::size_t) \
+ { \
+ return quick_allocator< tp >::alloc(); \
+ } \
+ \
+ void operator delete(void * p) \
+ { \
+ quick_allocator< tp >::dealloc(p); \
+ }
+#else
+
+#define DECLARE_ALLOC(tp)
+
+#endif
+
+struct Slice
+{
+ QString source;
+ int position;
+ int length;
+
+ inline Slice()
+ : position(0), length(0) {}
+};
+
+class AST
+{
+public:
+ typedef AUTO_PTR<AST> Node;
+ enum { Type=NodeType_Generic };
+
+ DECLARE_ALLOC( AST )
+
+public:
+ AST();
+ virtual ~AST();
+
+ int nodeType() const { return m_nodeType; }
+ void setNodeType( int nodeType ) { m_nodeType = nodeType; }
+
+ AST* parent() { return m_parent; }
+ void setParent( AST* parent );
+
+ void setStartPosition( int line, int col );
+ void getStartPosition( int* line, int* col ) const;
+
+ void setEndPosition( int line, int col );
+ void getEndPosition( int* line, int* col ) const;
+
+#ifndef CPPPARSER_NO_CHILDREN
+ QPtrList<AST> children() { return m_children; }
+ void appendChild( AST* child );
+ void removeChild( AST* child );
+#endif
+
+ virtual inline QString text() const
+ { return m_slice.source.mid(m_slice.position, m_slice.length); }
+
+ QString comment() const
+ { return m_comment; }
+
+ inline void setSlice( const Slice& slice )
+ { m_slice = slice; }
+
+ inline void setSlice( const QString &text, int position, int length )
+ {
+ m_slice.source = text;
+ m_slice.position = position;
+ m_slice.length = length;
+ }
+
+ inline void setText(const QString &text)
+ { setSlice(text, 0, text.length()); }
+
+ void setComment( const QString &comment )
+ { m_comment = comment; }
+
+private:
+ int m_nodeType;
+ AST* m_parent;
+ int m_startLine, m_startColumn;
+ int m_endLine, m_endColumn;
+ Slice m_slice;
+#ifndef CPPPARSER_NO_CHILDREN
+ QPtrList<AST> m_children;
+#endif
+ QString m_comment;
+
+private:
+ AST( const AST& source );
+ void operator = ( const AST& source );
+};
+
+class GroupAST: public AST
+{
+public:
+ typedef AUTO_PTR<GroupAST> Node;
+ enum { Type = NodeType_Group };
+
+ DECLARE_ALLOC( GroupAST )
+
+public:
+ GroupAST();
+
+ QPtrList<AST> nodeList() { return m_nodeList; }
+ void addNode( AST::Node& node );
+
+ virtual QString text() const;
+
+private:
+ QPtrList<AST> m_nodeList;
+
+private:
+ GroupAST( const GroupAST& source );
+ void operator = ( const GroupAST& source );
+};
+
+
+class TemplateArgumentListAST: public AST
+{
+public:
+ typedef AUTO_PTR<TemplateArgumentListAST> Node;
+ enum { Type = NodeType_TemplateArgumentList };
+
+ DECLARE_ALLOC( TemplateArgumentListAST )
+
+public:
+ TemplateArgumentListAST();
+
+ void addArgument( AST::Node& arg );
+ QPtrList<AST> argumentList() { return m_argumentList; }
+
+ virtual QString text() const;
+
+private:
+ QPtrList<AST> m_argumentList;
+
+private:
+ TemplateArgumentListAST( const TemplateArgumentListAST& source );
+ void operator = ( const TemplateArgumentListAST& source );
+};
+
+class ClassOrNamespaceNameAST: public AST
+{
+public:
+ typedef AUTO_PTR<ClassOrNamespaceNameAST> Node;
+ enum { Type = NodeType_ClassOrNamespaceName };
+
+ DECLARE_ALLOC( ClassOrNamespaceNameAST )
+
+public:
+ ClassOrNamespaceNameAST();
+
+ AST* name() { return m_name.get(); }
+ void setName( AST::Node& name );
+
+ TemplateArgumentListAST* templateArgumentList() { return m_templateArgumentList.get(); }
+ void setTemplateArgumentList( TemplateArgumentListAST::Node& templateArgumentList );
+
+ virtual QString text() const;
+
+private:
+ AST::Node m_name;
+ TemplateArgumentListAST::Node m_templateArgumentList;
+
+private:
+ ClassOrNamespaceNameAST( const ClassOrNamespaceNameAST& source );
+ void operator = ( const ClassOrNamespaceNameAST& source );
+};
+
+class NameAST: public AST
+{
+public:
+ typedef AUTO_PTR<NameAST> Node;
+ enum { Type = NodeType_Name };
+
+ DECLARE_ALLOC( NameAST )
+
+public:
+ NameAST();
+
+ bool isGlobal() const { return m_global; }
+ void setGlobal( bool b );
+
+ void addClassOrNamespaceName( ClassOrNamespaceNameAST::Node& classOrNamespaceName );
+ QPtrList<ClassOrNamespaceNameAST> classOrNamespaceNameList() { return m_classOrNamespaceNameList; }
+
+ ClassOrNamespaceNameAST* unqualifiedName() { return m_unqualifiedName.get(); }
+ void setUnqualifiedName( ClassOrNamespaceNameAST::Node& unqualifiedName );
+
+ virtual QString text() const;
+
+private:
+ bool m_global;
+ ClassOrNamespaceNameAST::Node m_unqualifiedName;
+ QPtrList<ClassOrNamespaceNameAST> m_classOrNamespaceNameList;
+
+private:
+ NameAST( const NameAST& source );
+ void operator = ( const NameAST& source );
+};
+
+class TypeParameterAST: public AST
+{
+public:
+ typedef AUTO_PTR<TypeParameterAST> Node;
+ enum { Type = NodeType_TypeParameter };
+
+ DECLARE_ALLOC( TypeParameterAST )
+
+public:
+ TypeParameterAST();
+
+ AST* kind() { return m_kind.get(); }
+ void setKind( AST::Node& kind );
+
+ class TemplateParameterListAST* templateParameterList() { return m_templateParameterList.get(); }
+ void setTemplateParameterList( AUTO_PTR<class TemplateParameterListAST>& templateParameterList );
+
+ NameAST* name() { return m_name.get(); }
+ void setName( NameAST::Node& name );
+
+ AST* typeId() { return m_typeId.get(); }
+ void setTypeId( AST::Node& typeId );
+
+private:
+ AST::Node m_kind;
+ AUTO_PTR<class TemplateParameterListAST> m_templateParameterList;
+ NameAST::Node m_name;
+ AST::Node m_typeId;
+
+private:
+ TypeParameterAST( const TypeParameterAST& source );
+ void operator = ( const TypeParameterAST& source );
+};
+
+class DeclarationAST: public AST
+{
+public:
+ typedef AUTO_PTR<DeclarationAST> Node;
+ enum { Type = NodeType_Declaration };
+
+ DECLARE_ALLOC( DeclarationAST )
+
+public:
+ DeclarationAST();
+
+private:
+ DeclarationAST( const DeclarationAST& source );
+ void operator = ( const DeclarationAST& source );
+};
+
+class AccessDeclarationAST: public DeclarationAST
+{
+public:
+ typedef AUTO_PTR<AccessDeclarationAST> Node;
+ enum { Type = NodeType_AccessDeclaration };
+
+ DECLARE_ALLOC( AccessDeclarationAST )
+
+public:
+ AccessDeclarationAST();
+
+ QPtrList<AST> accessList() { return m_accessList; }
+ void addAccess( AST::Node& access );
+
+ virtual QString text() const;
+
+private:
+ QPtrList<AST> m_accessList;
+
+private:
+ AccessDeclarationAST( const AccessDeclarationAST& source );
+ void operator = ( const AccessDeclarationAST& source );
+};
+
+class TypeSpecifierAST: public AST
+{
+public:
+ typedef AUTO_PTR<TypeSpecifierAST> Node;
+ enum { Type = NodeType_TypeSpecifier };
+
+ DECLARE_ALLOC( TypeSpecifierAST )
+
+public:
+ TypeSpecifierAST();
+
+ virtual NameAST* name() { return m_name.get(); }
+ virtual void setName( NameAST::Node& name );
+
+ GroupAST* cvQualify() { return m_cvQualify.get(); }
+ void setCvQualify( GroupAST::Node& cvQualify );
+
+ GroupAST* cv2Qualify() { return m_cv2Qualify.get(); }
+ void setCv2Qualify( GroupAST::Node& cv2Qualify );
+
+ virtual QString text() const;
+
+private:
+ NameAST::Node m_name;
+ GroupAST::Node m_cvQualify;
+ GroupAST::Node m_cv2Qualify;
+
+private:
+ TypeSpecifierAST( const TypeSpecifierAST& source );
+ void operator = ( const TypeSpecifierAST& source );
+};
+
+class BaseSpecifierAST: public AST
+{
+public:
+ typedef AUTO_PTR<BaseSpecifierAST> Node;
+ enum { Type = NodeType_BaseSpecifier };
+
+ DECLARE_ALLOC( BaseSpecifierAST )
+
+public:
+ BaseSpecifierAST();
+
+ AST* isVirtual() { return m_isVirtual.get(); }
+ void setIsVirtual( AST::Node& isVirtual );
+
+ AST* access() { return m_access.get(); }
+ void setAccess( AST::Node& access );
+
+ NameAST* name() { return m_name.get(); }
+ void setName( NameAST::Node& name );
+
+private:
+ AST::Node m_isVirtual;
+ AST::Node m_access;
+ NameAST::Node m_name;
+
+private:
+ BaseSpecifierAST( const BaseSpecifierAST& source );
+ void operator = ( const BaseSpecifierAST& source );
+};
+
+class BaseClauseAST: public AST
+{
+public:
+ typedef AUTO_PTR<BaseClauseAST> Node;
+ enum { Type = NodeType_BaseClause };
+
+ DECLARE_ALLOC( BaseClauseAST )
+
+public:
+ BaseClauseAST();
+
+ void addBaseSpecifier( BaseSpecifierAST::Node& baseSpecifier );
+ QPtrList<BaseSpecifierAST> baseSpecifierList() { return m_baseSpecifierList; }
+
+private:
+ QPtrList<BaseSpecifierAST> m_baseSpecifierList;
+
+private:
+ BaseClauseAST( const BaseClauseAST& source );
+ void operator = ( const BaseClauseAST& source );
+};
+
+class ClassSpecifierAST: public TypeSpecifierAST
+{
+public:
+ typedef AUTO_PTR<ClassSpecifierAST> Node;
+ enum { Type = NodeType_ClassSpecifier };
+
+ DECLARE_ALLOC( ClassSpecifierAST )
+
+public:
+ ClassSpecifierAST();
+
+ GroupAST* winDeclSpec() { return m_winDeclSpec.get(); }
+ void setWinDeclSpec( GroupAST::Node& winDeclSpec );
+
+ AST* classKey() { return m_classKey.get(); }
+ void setClassKey( AST::Node& classKey );
+
+ BaseClauseAST* baseClause() { return m_baseClause.get(); }
+ void setBaseClause( BaseClauseAST::Node& baseClause );
+
+ QPtrList<DeclarationAST> declarationList() { return m_declarationList; }
+ void addDeclaration( DeclarationAST::Node& declaration );
+
+private:
+ GroupAST::Node m_winDeclSpec;
+ AST::Node m_classKey;
+ BaseClauseAST::Node m_baseClause;
+ QPtrList<DeclarationAST> m_declarationList;
+
+private:
+ ClassSpecifierAST( const ClassSpecifierAST& source );
+ void operator = ( const ClassSpecifierAST& source );
+};
+
+class EnumeratorAST: public AST
+{
+public:
+ typedef AUTO_PTR<EnumeratorAST> Node;
+ enum { Type = NodeType_Enumerator };
+
+ DECLARE_ALLOC( EnumeratorAST )
+
+public:
+ EnumeratorAST();
+
+ AST* id() { return m_id.get(); }
+ void setId( AST::Node& id );
+
+ AST* expr() { return m_expr.get(); }
+ void setExpr( AST::Node& expr );
+
+private:
+ AST::Node m_id;
+ AST::Node m_expr;
+
+private:
+ EnumeratorAST( const EnumeratorAST& source );
+ void operator = ( const EnumeratorAST& source );
+};
+
+class EnumSpecifierAST: public TypeSpecifierAST
+{
+public:
+ typedef AUTO_PTR<EnumSpecifierAST> Node;
+ enum { Type = NodeType_EnumSpecifier };
+
+ DECLARE_ALLOC( EnumSpecifierAST )
+
+public:
+ EnumSpecifierAST();
+
+ void addEnumerator( EnumeratorAST::Node& enumerator );
+ QPtrList<EnumeratorAST> enumeratorList() { return m_enumeratorList; }
+
+private:
+ QPtrList<EnumeratorAST> m_enumeratorList;
+
+private:
+ EnumSpecifierAST( const EnumSpecifierAST& source );
+ void operator = ( const EnumSpecifierAST& source );
+};
+
+class ElaboratedTypeSpecifierAST: public TypeSpecifierAST
+{
+public:
+ typedef AUTO_PTR<ElaboratedTypeSpecifierAST> Node;
+ enum { Type = NodeType_ElaboratedTypeSpecifier };
+
+ DECLARE_ALLOC( ElaboratedTypeSpecifierAST )
+
+public:
+ ElaboratedTypeSpecifierAST();
+
+ AST* kind() { return m_kind.get(); }
+ void setKind( AST::Node& kind );
+
+ virtual QString text() const;
+
+private:
+ AST::Node m_kind;
+
+private:
+ ElaboratedTypeSpecifierAST( const ElaboratedTypeSpecifierAST& source );
+ void operator = ( const ElaboratedTypeSpecifierAST& source );
+};
+
+
+class LinkageBodyAST: public AST
+{
+public:
+ typedef AUTO_PTR<LinkageBodyAST> Node;
+ enum { Type = NodeType_LinkageBody };
+
+ DECLARE_ALLOC( LinkageBodyAST )
+
+public:
+ LinkageBodyAST();
+
+ void addDeclaration( DeclarationAST::Node& ast );
+ QPtrList<DeclarationAST> declarationList() { return m_declarationList; }
+
+private:
+ QPtrList<DeclarationAST> m_declarationList;
+
+private:
+ LinkageBodyAST( const LinkageBodyAST& source );
+ void operator = ( const LinkageBodyAST& source );
+};
+
+class LinkageSpecificationAST: public DeclarationAST
+{
+public:
+ typedef AUTO_PTR<LinkageSpecificationAST> Node;
+ enum { Type = NodeType_LinkageSpecification };
+
+ DECLARE_ALLOC( LinkageSpecificationAST )
+
+public:
+ LinkageSpecificationAST();
+
+ AST* externType() { return m_externType.get(); }
+ void setExternType( AST::Node& externType );
+
+ LinkageBodyAST* linkageBody() { return m_linkageBody.get(); }
+ void setLinkageBody( LinkageBodyAST::Node& linkageBody );
+
+ DeclarationAST* declaration() { return m_declaration.get(); }
+ void setDeclaration( DeclarationAST::Node& decl );
+
+private:
+ AST::Node m_externType;
+ LinkageBodyAST::Node m_linkageBody;
+ DeclarationAST::Node m_declaration;
+
+private:
+ LinkageSpecificationAST( const LinkageSpecificationAST& source );
+ void operator = ( const LinkageSpecificationAST& source );
+};
+
+class NamespaceAST: public DeclarationAST
+{
+public:
+ typedef AUTO_PTR<NamespaceAST> Node;
+ enum { Type = NodeType_Namespace };
+
+ DECLARE_ALLOC( NamespaceAST )
+
+public:
+ NamespaceAST();
+
+ AST* namespaceName() { return m_namespaceName.get(); }
+ void setNamespaceName( AST::Node& namespaceName );
+
+ LinkageBodyAST* linkageBody() { return m_linkageBody.get(); }
+ void setLinkageBody( LinkageBodyAST::Node& linkageBody );
+
+private:
+ AST::Node m_namespaceName;
+ LinkageBodyAST::Node m_linkageBody;
+
+private:
+ NamespaceAST( const NamespaceAST& source );
+ void operator = ( const NamespaceAST& source );
+};
+
+class NamespaceAliasAST: public DeclarationAST
+{
+public:
+ typedef AUTO_PTR<NamespaceAliasAST> Node;
+ enum { Type = NodeType_NamespaceAlias };
+
+ DECLARE_ALLOC( NamespaceAliasAST )
+
+public:
+ NamespaceAliasAST();
+
+ AST* namespaceName() { return m_namespaceName.get(); }
+ void setNamespaceName( AST::Node& name );
+
+ NameAST* aliasName() { return m_aliasName.get(); }
+ void setAliasName( NameAST::Node& name );
+
+private:
+ AST::Node m_namespaceName;
+ NameAST::Node m_aliasName;
+
+private:
+ NamespaceAliasAST( const NamespaceAliasAST& source );
+ void operator = ( const NamespaceAliasAST& source );
+};
+
+class UsingAST: public DeclarationAST
+{
+public:
+ typedef AUTO_PTR<UsingAST> Node;
+ enum { Type = NodeType_Using };
+
+ DECLARE_ALLOC( UsingAST )
+
+public:
+ UsingAST();
+
+ AST* typeName() { return m_typeName.get(); }
+ void setTypeName( AST::Node& typeName );
+
+ NameAST* name() { return m_name.get(); }
+ void setName( NameAST::Node& name );
+
+private:
+ AST::Node m_typeName;
+ NameAST::Node m_name;
+
+private:
+ UsingAST( const UsingAST& source );
+ void operator = ( const UsingAST& source );
+};
+
+class UsingDirectiveAST: public DeclarationAST
+{
+public:
+ typedef AUTO_PTR<UsingDirectiveAST> Node;
+ enum { Type = NodeType_UsingDirective };
+
+ DECLARE_ALLOC( UsingDirectiveAST )
+
+public:
+ UsingDirectiveAST();
+
+ NameAST* name() { return m_name.get(); }
+ void setName( NameAST::Node& name );
+
+private:
+ NameAST::Node m_name;
+
+private:
+ UsingDirectiveAST( const UsingDirectiveAST& source );
+ void operator = ( const UsingDirectiveAST& source );
+};
+
+class DeclaratorAST: public AST
+{
+public:
+ typedef AUTO_PTR<DeclaratorAST> Node;
+ enum { Type = NodeType_Declarator };
+
+ DECLARE_ALLOC( DeclaratorAST )
+
+public:
+ DeclaratorAST();
+
+ QPtrList<AST> ptrOpList() { return m_ptrOpList; }
+ void addPtrOp( AST::Node& ptrOp );
+
+ DeclaratorAST* subDeclarator() { return m_subDeclarator.get(); }
+ void setSubDeclarator( Node& subDeclarator );
+
+ NameAST* declaratorId() { return m_declaratorId.get(); }
+ void setDeclaratorId( NameAST::Node& declaratorId );
+
+ AST* bitfieldInitialization() { return m_bitfieldInitialization.get(); }
+ void setBitfieldInitialization( AST::Node& bitfieldInitialization );
+
+ QPtrList<AST> arrayDimensionList() { return m_arrayDimensionList; }
+ void addArrayDimension( AST::Node& arrayDimension );
+
+ class ParameterDeclarationClauseAST* parameterDeclarationClause() { return m_parameterDeclarationClause.get(); }
+ void setParameterDeclarationClause( AUTO_PTR<class ParameterDeclarationClauseAST>& parameterDeclarationClause );
+
+ // ### replace 'constant' with cvQualify
+ AST* constant() { return m_constant.get(); }
+ void setConstant( AST::Node& constant );
+
+ GroupAST* exceptionSpecification() { return m_exceptionSpecification.get(); }
+ void setExceptionSpecification( GroupAST::Node& exceptionSpecification );
+
+private:
+ QPtrList<AST> m_ptrOpList;
+ Node m_subDeclarator;
+ NameAST::Node m_declaratorId;
+ AST::Node m_bitfieldInitialization;
+ QPtrList<AST> m_arrayDimensionList;
+ AUTO_PTR<class ParameterDeclarationClauseAST> m_parameterDeclarationClause;
+ AST::Node m_constant;
+ GroupAST::Node m_exceptionSpecification;
+
+private:
+ DeclaratorAST( const DeclaratorAST& source );
+ void operator = ( const DeclaratorAST& source );
+};
+
+class ParameterDeclarationAST: public AST
+{
+public:
+ typedef AUTO_PTR<ParameterDeclarationAST> Node;
+ enum { Type = NodeType_ParameterDeclaration };
+
+ DECLARE_ALLOC( ParameterDeclarationAST )
+
+public:
+ ParameterDeclarationAST();
+
+ TypeSpecifierAST* typeSpec() { return m_typeSpec.get(); }
+ void setTypeSpec( TypeSpecifierAST::Node& typeSpec );
+
+ DeclaratorAST* declarator() { return m_declarator.get(); }
+ void setDeclarator( DeclaratorAST::Node& declarator );
+
+ AST* expression() { return m_expression.get(); }
+ void setExpression( AST::Node& expression );
+
+ virtual QString text() const;
+
+private:
+ TypeSpecifierAST::Node m_typeSpec;
+ DeclaratorAST::Node m_declarator;
+ AST::Node m_expression;
+
+private:
+ ParameterDeclarationAST( const ParameterDeclarationAST& source );
+ void operator = ( const ParameterDeclarationAST& source );
+};
+
+class ParameterDeclarationListAST: public AST
+{
+public:
+ typedef AUTO_PTR<ParameterDeclarationListAST> Node;
+ enum { Type = NodeType_ParameterDeclarationList };
+
+ DECLARE_ALLOC( ParameterDeclarationListAST )
+
+public:
+ ParameterDeclarationListAST();
+
+ QPtrList<ParameterDeclarationAST> parameterList() { return m_parameterList; }
+ void addParameter( ParameterDeclarationAST::Node& parameter );
+
+ virtual QString text() const;
+
+private:
+ QPtrList<ParameterDeclarationAST> m_parameterList;
+
+private:
+ ParameterDeclarationListAST( const ParameterDeclarationListAST& source );
+ void operator = ( const ParameterDeclarationListAST& source );
+};
+
+class ParameterDeclarationClauseAST: public AST
+{
+public:
+ typedef AUTO_PTR<ParameterDeclarationClauseAST> Node;
+ enum { Type = NodeType_ParameterDeclarationClause };
+
+ DECLARE_ALLOC( ParameterDeclarationClauseAST )
+
+public:
+ ParameterDeclarationClauseAST();
+
+ ParameterDeclarationListAST* parameterDeclarationList() { return m_parameterDeclarationList.get(); }
+ void setParameterDeclarationList( ParameterDeclarationListAST::Node& parameterDeclarationList );
+
+ AST* ellipsis() { return m_ellipsis.get(); }
+ void setEllipsis( AST::Node& ellipsis );
+
+ virtual QString text() const;
+
+private:
+ ParameterDeclarationListAST::Node m_parameterDeclarationList;
+ AST::Node m_ellipsis;
+
+private:
+ ParameterDeclarationClauseAST( const ParameterDeclarationClauseAST& source );
+ void operator = ( const ParameterDeclarationClauseAST& source );
+};
+
+
+class InitDeclaratorAST: public AST
+{
+public:
+ typedef AUTO_PTR<InitDeclaratorAST> Node;
+ enum { Type = NodeType_InitDeclarator };
+
+ DECLARE_ALLOC( InitDeclaratorAST )
+
+public:
+ InitDeclaratorAST();
+
+ DeclaratorAST* declarator() { return m_declarator.get(); }
+ void setDeclarator( DeclaratorAST::Node& declarator );
+
+ AST* initializer() { return m_initializer.get(); }
+ void setInitializer( AST::Node& initializer );
+
+private:
+ DeclaratorAST::Node m_declarator;
+ AST::Node m_initializer;
+
+private:
+ InitDeclaratorAST( const InitDeclaratorAST& source );
+ void operator = ( const InitDeclaratorAST& source );
+};
+
+class InitDeclaratorListAST: public AST
+{
+public:
+ typedef AUTO_PTR<InitDeclaratorListAST> Node;
+ enum { Type = NodeType_InitDeclaratorList };
+
+ DECLARE_ALLOC( InitDeclaratorListAST )
+
+public:
+ InitDeclaratorListAST();
+
+ QPtrList<InitDeclaratorAST> initDeclaratorList() { return m_initDeclaratorList; }
+ void addInitDeclarator( InitDeclaratorAST::Node& decl );
+
+private:
+ QPtrList<InitDeclaratorAST> m_initDeclaratorList;
+
+private:
+ InitDeclaratorListAST( const InitDeclaratorListAST& source );
+ void operator = ( const InitDeclaratorListAST& source );
+};
+
+class TypedefAST: public DeclarationAST
+{
+public:
+ typedef AUTO_PTR<TypedefAST> Node;
+ enum { Type = NodeType_Typedef };
+
+ DECLARE_ALLOC( TypedefAST )
+
+public:
+ TypedefAST();
+
+ TypeSpecifierAST* typeSpec() { return m_typeSpec.get(); }
+ void setTypeSpec( TypeSpecifierAST::Node& typeSpec );
+
+ InitDeclaratorListAST* initDeclaratorList() { return m_initDeclaratorList.get(); }
+ void setInitDeclaratorList( InitDeclaratorListAST::Node& initDeclaratorList );
+
+private:
+ TypeSpecifierAST::Node m_typeSpec;
+ InitDeclaratorListAST::Node m_initDeclaratorList;
+
+private:
+ TypedefAST( const TypedefAST& source );
+ void operator = ( const TypedefAST& source );
+};
+
+class TemplateParameterAST: public AST
+{
+public:
+ typedef AUTO_PTR<TemplateParameterAST> Node;
+ enum { Type = NodeType_TemplateParameter };
+
+ DECLARE_ALLOC( TemplateParameterAST )
+
+public:
+ TemplateParameterAST();
+
+ TypeParameterAST* typeParameter() { return m_typeParameter.get(); }
+ void setTypeParameter( TypeParameterAST::Node& typeParameter );
+
+ ParameterDeclarationAST* typeValueParameter() { return m_typeValueParameter.get(); }
+ void setTypeValueParameter( ParameterDeclarationAST::Node& typeValueParameter );
+
+private:
+ TypeParameterAST::Node m_typeParameter;
+ ParameterDeclarationAST::Node m_typeValueParameter;
+
+private:
+ TemplateParameterAST( const TemplateParameterAST& source );
+ void operator = ( const TemplateParameterAST& source );
+};
+
+class TemplateParameterListAST: public AST
+{
+public:
+ typedef AUTO_PTR<TemplateParameterListAST> Node;
+ enum { Type = NodeType_TemplateParameterList };
+
+ DECLARE_ALLOC( TemplateParameterListAST )
+
+public:
+ TemplateParameterListAST();
+
+ QPtrList<TemplateParameterAST> templateParameterList() { return m_templateParameterList; }
+ void addTemplateParameter( TemplateParameterAST::Node& templateParameter );
+
+private:
+ QPtrList<TemplateParameterAST> m_templateParameterList;
+
+private:
+ TemplateParameterListAST( const TemplateParameterListAST& source );
+ void operator = ( const TemplateParameterListAST& source );
+};
+
+class TemplateDeclarationAST: public DeclarationAST
+{
+public:
+ typedef AUTO_PTR<TemplateDeclarationAST> Node;
+ enum { Type = NodeType_TemplateDeclaration };
+
+ DECLARE_ALLOC( TemplateDeclarationAST )
+
+public:
+ TemplateDeclarationAST();
+
+ AST* exported() { return m_exported.get(); }
+ void setExported( AST::Node& exported );
+
+ TemplateParameterListAST* templateParameterList() { return m_templateParameterList.get(); }
+ void setTemplateParameterList( TemplateParameterListAST::Node& templateParameterList );
+
+ DeclarationAST* declaration() { return m_declaration.get(); }
+ void setDeclaration( DeclarationAST::Node& declaration );
+
+private:
+ AST::Node m_exported;
+ TemplateParameterListAST::Node m_templateParameterList;
+ DeclarationAST::Node m_declaration;
+
+private:
+ TemplateDeclarationAST( const TemplateDeclarationAST& source );
+ void operator = ( const TemplateDeclarationAST& source );
+};
+
+class SimpleDeclarationAST: public DeclarationAST
+{
+public:
+ typedef AUTO_PTR<SimpleDeclarationAST> Node;
+ enum { Type = NodeType_SimpleDeclaration };
+
+ DECLARE_ALLOC( SimpleDeclarationAST )
+
+public:
+ SimpleDeclarationAST();
+
+ GroupAST* functionSpecifier() { return m_functionSpecifier.get(); }
+ void setFunctionSpecifier( GroupAST::Node& functionSpecifier );
+
+ GroupAST* storageSpecifier() { return m_storageSpecifier.get(); }
+ void setStorageSpecifier( GroupAST::Node& storageSpecifier );
+
+ TypeSpecifierAST* typeSpec() { return m_typeSpec.get(); }
+ void setTypeSpec( TypeSpecifierAST::Node& typeSpec );
+
+ InitDeclaratorListAST* initDeclaratorList() { return m_initDeclaratorList.get(); }
+ void setInitDeclaratorList( InitDeclaratorListAST::Node& initDeclaratorList );
+
+ GroupAST* winDeclSpec() { return m_winDeclSpec.get(); }
+ void setWinDeclSpec( GroupAST::Node& winDeclSpec );
+
+private:
+ GroupAST::Node m_functionSpecifier;
+ GroupAST::Node m_storageSpecifier;
+ TypeSpecifierAST::Node m_typeSpec;
+ InitDeclaratorListAST::Node m_initDeclaratorList;
+ GroupAST::Node m_winDeclSpec;
+
+private:
+ SimpleDeclarationAST( const SimpleDeclarationAST& source );
+ void operator = ( const SimpleDeclarationAST& source );
+};
+
+class StatementAST: public AST
+{
+public:
+ typedef AUTO_PTR<StatementAST> Node;
+ enum { Type = NodeType_Statement };
+
+ DECLARE_ALLOC( StatementAST )
+
+public:
+ StatementAST();
+
+private:
+ StatementAST( const StatementAST& source );
+ void operator = ( const StatementAST& source );
+};
+
+class ExpressionStatementAST: public StatementAST
+{
+public:
+ typedef AUTO_PTR<ExpressionStatementAST> Node;
+ enum { Type = NodeType_ExpressionStatement };
+
+ DECLARE_ALLOC( ExpressionStatementAST )
+
+public:
+ ExpressionStatementAST();
+
+ AST* expression() { return m_expression.get(); }
+ void setExpression( AST::Node& expression );
+
+private:
+ AST::Node m_expression;
+
+private:
+ ExpressionStatementAST( const ExpressionStatementAST& source );
+ void operator = ( const ExpressionStatementAST& source );
+};
+
+class ConditionAST: public AST
+{
+public:
+ typedef AUTO_PTR<ConditionAST> Node;
+ enum { Type = NodeType_Condition };
+
+ DECLARE_ALLOC( ConditionAST )
+
+public:
+ ConditionAST();
+
+ TypeSpecifierAST* typeSpec() { return m_typeSpec.get(); }
+ void setTypeSpec( TypeSpecifierAST::Node& typeSpec );
+
+ DeclaratorAST* declarator() { return m_declarator.get(); }
+ void setDeclarator( DeclaratorAST::Node& declarator );
+
+ AST* expression() { return m_expression.get(); }
+ void setExpression( AST::Node& expression );
+
+private:
+ TypeSpecifierAST::Node m_typeSpec;
+ DeclaratorAST::Node m_declarator;
+ AST::Node m_expression;
+
+private:
+ ConditionAST( const ConditionAST& source );
+ void operator = ( const ConditionAST& source );
+};
+
+class IfStatementAST: public StatementAST
+{
+public:
+ typedef AUTO_PTR<IfStatementAST> Node;
+ enum { Type = NodeType_IfStatement };
+
+ DECLARE_ALLOC( IfStatementAST )
+
+public:
+ IfStatementAST();
+
+ ConditionAST* condition() const { return m_condition.get(); }
+ void setCondition( ConditionAST::Node& condition );
+
+ StatementAST* statement() { return m_statement.get(); }
+ void setStatement( StatementAST::Node& statement );
+
+ StatementAST* elseStatement() { return m_elseStatement.get(); }
+ void setElseStatement( StatementAST::Node& statement );
+
+private:
+ ConditionAST::Node m_condition;
+ StatementAST::Node m_statement;
+ StatementAST::Node m_elseStatement;
+
+private:
+ IfStatementAST( const IfStatementAST& source );
+ void operator = ( const IfStatementAST& source );
+};
+
+class WhileStatementAST: public StatementAST
+{
+public:
+ typedef AUTO_PTR<WhileStatementAST> Node;
+ enum { Type = NodeType_WhileStatement };
+
+ DECLARE_ALLOC( WhileStatementAST )
+
+public:
+ WhileStatementAST();
+
+ ConditionAST* condition() const { return m_condition.get(); }
+ void setCondition( ConditionAST::Node& condition );
+
+ StatementAST* statement() { return m_statement.get(); }
+ void setStatement( StatementAST::Node& statement );
+
+private:
+ ConditionAST::Node m_condition;
+ StatementAST::Node m_statement;
+
+private:
+ WhileStatementAST( const WhileStatementAST& source );
+ void operator = ( const WhileStatementAST& source );
+};
+
+class DoStatementAST: public StatementAST
+{
+public:
+ typedef AUTO_PTR<DoStatementAST> Node;
+ enum { Type = NodeType_DoStatement };
+
+ DECLARE_ALLOC( DoStatementAST )
+
+public:
+ DoStatementAST();
+
+ ConditionAST* condition() const { return m_condition.get(); }
+ void setCondition( ConditionAST::Node& condition );
+
+ StatementAST* statement() { return m_statement.get(); }
+ void setStatement( StatementAST::Node& statement );
+
+private:
+ ConditionAST::Node m_condition;
+ StatementAST::Node m_statement;
+
+private:
+ DoStatementAST( const DoStatementAST& source );
+ void operator = ( const DoStatementAST& source );
+};
+
+class ForStatementAST: public StatementAST
+{
+public:
+ typedef AUTO_PTR<ForStatementAST> Node;
+ enum { Type = NodeType_ForStatement };
+
+ DECLARE_ALLOC( ForStatementAST )
+
+public:
+ ForStatementAST();
+
+ StatementAST* initStatement() { return m_initStatement.get(); }
+ void setInitStatement( StatementAST::Node& statement );
+
+ ConditionAST* condition() const { return m_condition.get(); }
+ void setCondition( ConditionAST::Node& condition );
+
+ AST* expression() const { return m_expression.get(); }
+ void setExpression( AST::Node& expression );
+
+ StatementAST* statement() { return m_statement.get(); }
+ void setStatement( StatementAST::Node& statement );
+
+private:
+ ConditionAST::Node m_condition;
+ StatementAST::Node m_initStatement;
+ StatementAST::Node m_statement;
+ AST::Node m_expression;
+
+private:
+ ForStatementAST( const ForStatementAST& source );
+ void operator = ( const ForStatementAST& source );
+};
+
+class SwitchStatementAST: public StatementAST
+{
+public:
+ typedef AUTO_PTR<SwitchStatementAST> Node;
+ enum { Type = NodeType_SwitchStatement };
+
+ DECLARE_ALLOC( SwitchStatementAST )
+
+public:
+ SwitchStatementAST();
+
+ ConditionAST* condition() const { return m_condition.get(); }
+ void setCondition( ConditionAST::Node& condition );
+
+ StatementAST* statement() { return m_statement.get(); }
+ void setStatement( StatementAST::Node& statement );
+
+private:
+ ConditionAST::Node m_condition;
+ StatementAST::Node m_statement;
+
+private:
+ SwitchStatementAST( const SwitchStatementAST& source );
+ void operator = ( const SwitchStatementAST& source );
+};
+
+class StatementListAST: public StatementAST
+{
+public:
+ typedef AUTO_PTR<StatementListAST> Node;
+ enum { Type = NodeType_StatementList };
+
+ DECLARE_ALLOC( StatementListAST )
+
+public:
+ StatementListAST();
+
+ QPtrList<StatementAST> statementList() { return m_statementList; }
+ void addStatement( StatementAST::Node& statement );
+
+private:
+ QPtrList<StatementAST> m_statementList;
+
+private:
+ StatementListAST( const StatementListAST& source );
+ void operator = ( const StatementListAST& source );
+};
+
+class DeclarationStatementAST: public StatementAST
+{
+public:
+ typedef AUTO_PTR<DeclarationStatementAST> Node;
+ enum { Type = NodeType_DeclarationStatement };
+
+ DECLARE_ALLOC( DeclarationStatementAST )
+
+public:
+ DeclarationStatementAST();
+
+ DeclarationAST* declaration() { return m_declaration.get(); }
+ void setDeclaration( DeclarationAST::Node& declaration );
+
+private:
+ DeclarationAST::Node m_declaration;
+
+private:
+ DeclarationStatementAST( const DeclarationStatementAST& source );
+ void operator = ( const DeclarationStatementAST& source );
+};
+
+class FunctionDefinitionAST: public DeclarationAST
+{
+public:
+ typedef AUTO_PTR<FunctionDefinitionAST> Node;
+ enum { Type = NodeType_FunctionDefinition };
+
+ DECLARE_ALLOC( FunctionDefinitionAST )
+
+public:
+ FunctionDefinitionAST();
+
+ GroupAST* functionSpecifier() { return m_functionSpecifier.get(); }
+ void setFunctionSpecifier( GroupAST::Node& functionSpecifier );
+
+ GroupAST* storageSpecifier() { return m_storageSpecifier.get(); }
+ void setStorageSpecifier( GroupAST::Node& storageSpecifier );
+
+ TypeSpecifierAST* typeSpec() { return m_typeSpec.get(); }
+ void setTypeSpec( TypeSpecifierAST::Node& typeSpec );
+
+ InitDeclaratorAST* initDeclarator() { return m_initDeclarator.get(); }
+ void setInitDeclarator( InitDeclaratorAST::Node& initDeclarator );
+
+ StatementListAST* functionBody() { return m_functionBody.get(); }
+ void setFunctionBody( StatementListAST::Node& functionBody );
+
+ GroupAST* winDeclSpec() { return m_winDeclSpec.get(); }
+ void setWinDeclSpec( GroupAST::Node& winDeclSpec );
+
+private:
+ GroupAST::Node m_functionSpecifier;
+ GroupAST::Node m_storageSpecifier;
+ TypeSpecifierAST::Node m_typeSpec;
+ InitDeclaratorAST::Node m_initDeclarator;
+ StatementListAST::Node m_functionBody;
+ GroupAST::Node m_winDeclSpec;
+
+private:
+ FunctionDefinitionAST( const FunctionDefinitionAST& source );
+ void operator = ( const FunctionDefinitionAST& source );
+};
+
+
+class TranslationUnitAST: public AST
+{
+public:
+ typedef AUTO_PTR<TranslationUnitAST> Node;
+ enum { Type = NodeType_TranslationUnit };
+
+ DECLARE_ALLOC( TranslationUnitAST )
+
+public:
+ TranslationUnitAST();
+
+ void addDeclaration( DeclarationAST::Node& ast );
+ QPtrList<DeclarationAST> declarationList() { return m_declarationList; }
+
+private:
+ QPtrList<DeclarationAST> m_declarationList;
+
+private:
+ TranslationUnitAST( const TranslationUnitAST& source );
+ void operator = ( const TranslationUnitAST& source );
+};
+
+#endif
diff --git a/umbrello/umbrello/codeimport/kdevcppparser/ast_utils.cpp b/umbrello/umbrello/codeimport/kdevcppparser/ast_utils.cpp
new file mode 100644
index 00000000..e30f0c1e
--- /dev/null
+++ b/umbrello/umbrello/codeimport/kdevcppparser/ast_utils.cpp
@@ -0,0 +1,176 @@
+/***************************************************************************
+ * Copyright (C) 2002 by Roberto Raggi *
+ * roberto@kdevelop.org *
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the 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 "ast_utils.h"
+#include "ast.h"
+
+#include <qstringlist.h>
+#include <qregexp.h>
+
+#include <klocale.h>
+#include <kdebug.h>
+#include <kapplication.h>
+
+AST* findNodeAt( AST* node, int line, int column )
+{
+ // kdDebug(9007) << "findNodeAt(" << node << ")" << endl;
+
+ if( !node )
+ return 0;
+
+ int startLine, startColumn;
+ int endLine, endColumn;
+
+ node->getStartPosition( &startLine, &startColumn );
+ node->getEndPosition( &endLine, &endColumn );
+
+ if( (line > startLine || (line == startLine && column >= startColumn)) &&
+ (line < endLine || (line == endLine && column < endColumn)) ){
+
+ QPtrList<AST> children = node->children();
+ QPtrListIterator<AST> it( children );
+ while( it.current() ){
+ AST* a = it.current();
+ ++it;
+
+ AST* r = findNodeAt( a, line, column );
+ if( r )
+ return r;
+ }
+
+ return node;
+ }
+
+ return 0;
+}
+
+void scopeOfNode( AST* ast, QStringList& scope )
+{
+ if( !ast )
+ return;
+
+ if( ast->parent() )
+ scopeOfNode( ast->parent(), scope );
+
+ QString s;
+ switch( ast->nodeType() )
+ {
+ case NodeType_ClassSpecifier:
+ if( ((ClassSpecifierAST*)ast)->name() ){
+ s = ((ClassSpecifierAST*)ast)->name()->text();
+ s = s.isEmpty() ? QString::fromLatin1("<unnamed>") : s;
+ scope.push_back( s );
+ }
+ break;
+
+ case NodeType_Namespace:
+ {
+ AST* namespaceName = ((NamespaceAST*)ast)->namespaceName();
+ s = namespaceName ? namespaceName->text() : QString::fromLatin1("<unnamed>");
+ scope.push_back( s );
+ }
+ break;
+
+ case NodeType_FunctionDefinition:
+ {
+ FunctionDefinitionAST* funDef = static_cast<FunctionDefinitionAST*>( ast );
+ DeclaratorAST* d = funDef->initDeclarator()->declarator();
+
+ // hotfix for bug #68726
+ if ( !d->declaratorId() )
+ break;
+
+ QPtrList<ClassOrNamespaceNameAST> l = d->declaratorId()->classOrNamespaceNameList();
+ QPtrListIterator<ClassOrNamespaceNameAST> nameIt( l );
+ while( nameIt.current() ){
+ AST* name = nameIt.current()->name();
+ scope.push_back( name->text() );
+
+ ++nameIt;
+ }
+ }
+ break;
+
+ default:
+ break;
+ }
+}
+
+
+QString typeSpecToString( TypeSpecifierAST* typeSpec ) /// @todo remove
+{
+ if( !typeSpec )
+ return QString::null;
+
+ return typeSpec->text().replace( QRegExp(" :: "), "::" );
+}
+
+QString declaratorToString( DeclaratorAST* declarator, const QString& scope, bool skipPtrOp )
+{
+ if( !declarator )
+ return QString::null;
+
+ QString text;
+
+ if( !skipPtrOp ){
+ QPtrList<AST> ptrOpList = declarator->ptrOpList();
+ for( QPtrListIterator<AST> it(ptrOpList); it.current(); ++it ){
+ text += it.current()->text();
+ }
+ text += ' ';
+ }
+
+ text += scope;
+
+ if( declarator->subDeclarator() )
+ text += QString::fromLatin1("(") + declaratorToString(declarator->subDeclarator()) + QString::fromLatin1(")");
+
+ if( declarator->declaratorId() )
+ text += declarator->declaratorId()->text();
+
+ QPtrList<AST> arrays = declarator->arrayDimensionList();
+ QPtrListIterator<AST> it( arrays );
+ while( it.current() ){
+ text += "[]";
+ ++it;
+ }
+
+ if( declarator->parameterDeclarationClause() ){
+ text += "( ";
+
+ ParameterDeclarationListAST* l = declarator->parameterDeclarationClause()->parameterDeclarationList();
+ if( l != 0 ){
+ QPtrList<ParameterDeclarationAST> params = l->parameterList();
+ QPtrListIterator<ParameterDeclarationAST> it( params );
+
+ while( it.current() ){
+ QString type = typeSpecToString( it.current()->typeSpec() );
+ text += type;
+ if( !type.isEmpty() )
+ text += ' ';
+ text += declaratorToString( it.current()->declarator() );
+
+ ++it;
+
+ if( it.current() )
+ text += ", ";
+ }
+ }
+
+ text += " )";
+
+ if( declarator->constant() != 0 )
+ text += " const";
+ }
+
+ return text.replace( QRegExp(" :: "), "::" ).simplifyWhiteSpace();
+}
+
diff --git a/umbrello/umbrello/codeimport/kdevcppparser/ast_utils.h b/umbrello/umbrello/codeimport/kdevcppparser/ast_utils.h
new file mode 100644
index 00000000..187647b7
--- /dev/null
+++ b/umbrello/umbrello/codeimport/kdevcppparser/ast_utils.h
@@ -0,0 +1,29 @@
+/***************************************************************************
+ * Copyright (C) 2002 by Roberto Raggi *
+ * roberto@kdevelop.org *
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the 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 __ast_utils_h
+#define __ast_utils_h
+
+#include <qstring.h>
+
+class AST;
+class DeclaratorAST;
+class TypeSpecifierAST;
+class QStringList;
+
+namespace KTextEditor{ class EditInterface; }
+
+AST* findNodeAt( AST* unit, int line, int column );
+void scopeOfNode( AST* ast, QStringList& );
+QString typeSpecToString( TypeSpecifierAST* typeSpec );
+QString declaratorToString( DeclaratorAST* declarator, const QString& scope = QString::null, bool skipPtrOp=false );
+
+#endif // __ast_utils_h
diff --git a/umbrello/umbrello/codeimport/kdevcppparser/cpptree2uml.cpp b/umbrello/umbrello/codeimport/kdevcppparser/cpptree2uml.cpp
new file mode 100644
index 00000000..e7d0b848
--- /dev/null
+++ b/umbrello/umbrello/codeimport/kdevcppparser/cpptree2uml.cpp
@@ -0,0 +1,640 @@
+/***************************************************************************
+ * Based on kdevelop-3.0 languages/cpp/store_walker.cpp by Roberto Raggi *
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * copyright (C) 2004-2007 *
+ * Umbrello UML Modeller Authors <uml-devel@uml.sf.net> *
+ ***************************************************************************/
+
+// own header
+#include "cpptree2uml.h"
+// qt/kde includes
+#include <qfileinfo.h>
+#include <qdir.h>
+#include <qregexp.h>
+#include <kdebug.h>
+// app includes
+#include "ast_utils.h"
+#include "urlutil.h"
+#include "../import_utils.h"
+// FIXME: The sole reason for the next 2 includes is parseTypedef().
+// Make capsule methods in ClassImport, and remove these includes.
+#include "../../classifier.h"
+// FIXME The next include is motivated by template params
+#include "../../template.h"
+
+CppTree2Uml::CppTree2Uml( const QString& fileName)
+ : m_anon( 0 ), m_nsCnt( 0 ), m_clsCnt( 0 )
+{
+ m_fileName = URLUtil::canonicalPath(fileName);
+}
+
+CppTree2Uml::~CppTree2Uml()
+{
+}
+
+void CppTree2Uml::parseTranslationUnit( TranslationUnitAST* ast )
+{
+ m_currentScope.clear();
+ m_currentNamespace[0] = NULL; // index 0 is reserved (always NULL)
+ m_currentClass[0] = NULL; // index 0 is reserved (always NULL)
+ m_nsCnt = 0;
+ m_clsCnt = 0;
+
+ m_currentAccess = Uml::Visibility::Public;
+ m_inSlots = false;
+ m_inSignals = false;
+ m_inStorageSpec = false;
+ m_inTypedef = false;
+ m_currentDeclarator = 0;
+ m_anon = 0;
+
+ TreeParser::parseTranslationUnit( ast );
+}
+
+void CppTree2Uml::parseNamespace( NamespaceAST* ast )
+{
+ if (m_clsCnt > 0) {
+ kDebug() << "CppTree2Uml::parseNamespace: error - cannot nest namespace inside class"
+ << endl;
+ return;
+ }
+
+ QString nsName;
+ if( !ast->namespaceName() || ast->namespaceName()->text().isEmpty() ){
+ QFileInfo fileInfo( m_fileName );
+ QString shortFileName = fileInfo.baseName();
+
+ nsName.sprintf( "(%s_%d)", shortFileName.local8Bit().data(), m_anon++ );
+ } else {
+ nsName = ast->namespaceName()->text();
+ }
+
+#ifdef DEBUG_CPPTREE2UML
+ kDebug() << "CppTree2Uml::parseNamespace: " << nsName << endl;
+#endif
+ UMLObject * o = Import_Utils::createUMLObject( Uml::ot_Package, nsName,
+ m_currentNamespace[m_nsCnt],
+ ast->comment());
+ UMLPackage *ns = (UMLPackage *)o;
+ m_currentScope.push_back( nsName );
+ if (++m_nsCnt > STACKSIZE) {
+ kdError() << "CppTree2Uml::parseNamespace: excessive namespace nesting" << endl;
+ m_nsCnt = STACKSIZE;
+ }
+ m_currentNamespace[m_nsCnt] = ns;
+
+ TreeParser::parseNamespace( ast );
+
+ --m_nsCnt;
+ m_currentScope.pop_back();
+}
+
+void CppTree2Uml::parseTypedef( TypedefAST* ast )
+{
+#if 0
+ DeclaratorAST* oldDeclarator = m_currentDeclarator;
+
+ if( ast && ast->initDeclaratorList() && ast->initDeclaratorList()->initDeclaratorList().count() > 0 ) {
+ QPtrList<InitDeclaratorAST> lst( ast->initDeclaratorList()->initDeclaratorList() );
+ m_currentDeclarator = lst.at( 0 )->declarator();
+ }
+
+ m_inTypedef = true;
+
+ TreeParser::parseTypedef( ast );
+
+ m_inTypedef = false;
+ m_currentDeclarator = oldDeclarator;
+#else
+ TypeSpecifierAST* typeSpec = ast->typeSpec();
+ InitDeclaratorListAST* declarators = ast->initDeclaratorList();
+
+ if( typeSpec && declarators ){
+ QString typeId;
+
+ if( typeSpec->name() )
+ typeId = typeSpec->name()->text();
+
+ QPtrList<InitDeclaratorAST> l( declarators->initDeclaratorList() );
+ QPtrListIterator<InitDeclaratorAST> it( l );
+
+ InitDeclaratorAST* initDecl = 0;
+ while( 0 != (initDecl = it.current()) ){
+
+ QString type, id;
+ if( initDecl->declarator() ){
+ type = typeOfDeclaration( typeSpec, initDecl->declarator() );
+
+ DeclaratorAST* d = initDecl->declarator();
+ while( d->subDeclarator() ){
+ d = d->subDeclarator();
+ }
+
+ if( d->declaratorId() )
+ id = d->declaratorId()->text();
+ }
+//#ifdef DEBUG_CPPTREE2UML
+ kDebug() << "CppTree2Uml::parseTypedef: name=" << id << ", type=" << type << endl;
+//#endif
+ /* @todo Trace typedefs back to their root type for deciding
+ whether to build a Datatype (for pointers.) */
+ /* check out if the ID type is a Datatype
+ ex: typedef unsigned int uint;
+ where unsigned int is a known datatype
+ I'm not sure if setIsReference() should be run
+ */
+ bool isDatatype = Import_Utils::isDatatype(typeId, m_currentNamespace[m_nsCnt]);
+
+ if (type.contains('*') || isDatatype) {
+ UMLObject *inner =
+ Import_Utils::createUMLObject( Uml::ot_Class, typeId,
+ m_currentNamespace[m_nsCnt] );
+ UMLObject *typedefObj =
+ Import_Utils::createUMLObject( Uml::ot_Datatype, id,
+ m_currentNamespace[m_nsCnt] );
+ UMLClassifier *dt = static_cast<UMLClassifier*>(typedefObj);
+ dt->setIsReference();
+ dt->setOriginType(static_cast<UMLClassifier*>(inner));
+ } else {
+ Import_Utils::createUMLObject( Uml::ot_Class, id,
+ m_currentNamespace[m_nsCnt],
+ "" /* doc */,
+ "typedef" /* stereotype */);
+ }
+ ++it;
+ }
+
+ }
+#endif
+}
+
+void CppTree2Uml::parseTemplateDeclaration( TemplateDeclarationAST* ast )
+{
+ TemplateParameterListAST* parmListAST = ast->templateParameterList();
+ if (parmListAST == NULL)
+ return;
+ QPtrList<TemplateParameterAST> parmList = parmListAST->templateParameterList();
+ for (QPtrListIterator<TemplateParameterAST> it(parmList); it.current(); ++it) {
+ // The template is either a typeParameter or a typeValueParameter.
+
+ TemplateParameterAST* tmplParmNode = it.current();
+ TypeParameterAST* typeParmNode = tmplParmNode->typeParameter();
+ if (typeParmNode) {
+ NameAST* nameNode = typeParmNode->name();
+ if (nameNode) {
+ QString typeName = nameNode->unqualifiedName()->text();
+ Model_Utils::NameAndType nt(typeName, NULL);
+ m_templateParams.append(nt);
+ } else {
+ kdError() << "CppTree2Uml::parseTemplateDeclaration(type):"
+ << " nameNode is NULL" << endl;
+ }
+ }
+
+ ParameterDeclarationAST* valueNode = tmplParmNode->typeValueParameter();
+ if (valueNode) {
+ TypeSpecifierAST* typeSpec = valueNode->typeSpec();
+ if (typeSpec == NULL) {
+ kdError() << "CppTree2Uml::parseTemplateDeclaration(value):"
+ << " typeSpec is NULL" << endl;
+ continue;
+ }
+ QString typeName = typeSpec->name()->text();
+ UMLObject *t = Import_Utils::createUMLObject( Uml::ot_UMLObject, typeName,
+ m_currentNamespace[m_nsCnt] );
+ DeclaratorAST* declNode = valueNode->declarator();
+ NameAST* nameNode = declNode->declaratorId();
+ if (nameNode == NULL) {
+ kdError() << "CppTree2Uml::parseTemplateDeclaration(value):"
+ << " nameNode is NULL" << endl;
+ continue;
+ }
+ QString paramName = nameNode->unqualifiedName()->text();
+ Model_Utils::NameAndType nt(paramName, t);
+ m_templateParams.append(nt);
+ }
+ }
+
+ if( ast->declaration() )
+ TreeParser::parseDeclaration( ast->declaration() );
+}
+
+void CppTree2Uml::parseSimpleDeclaration( SimpleDeclarationAST* ast )
+{
+ TypeSpecifierAST* typeSpec = ast->typeSpec();
+ InitDeclaratorListAST* declarators = ast->initDeclaratorList();
+
+ m_comment = ast->comment();
+
+ if( typeSpec )
+ parseTypeSpecifier( typeSpec );
+
+ if( declarators ){
+ QPtrList<InitDeclaratorAST> l = declarators->initDeclaratorList();
+
+ QPtrListIterator<InitDeclaratorAST> it( l );
+ while( it.current() ){
+ parseDeclaration( ast->functionSpecifier(), ast->storageSpecifier(), typeSpec, it.current() );
+ ++it;
+ }
+ }
+}
+
+void CppTree2Uml::parseFunctionDefinition( FunctionDefinitionAST* ast )
+{
+ TypeSpecifierAST* typeSpec = ast->typeSpec();
+ GroupAST* funSpec = ast->functionSpecifier();
+ GroupAST* storageSpec = ast->storageSpecifier();
+
+ if( !ast->initDeclarator() )
+ return;
+
+ DeclaratorAST* d = ast->initDeclarator()->declarator();
+
+ if( !d->declaratorId() )
+ return;
+
+ bool isFriend = false;
+ bool isVirtual = false;
+ bool isStatic = false;
+ bool isInline = false;
+ bool isConstructor = false;
+
+ if( funSpec ){
+ QPtrList<AST> l = funSpec->nodeList();
+ QPtrListIterator<AST> it( l );
+ while( it.current() ){
+ QString text = it.current()->text();
+ if( text == "virtual" ) isVirtual = true;
+ else if( text == "inline" ) isInline = true;
+ ++it;
+ }
+ }
+
+ if( storageSpec ){
+ QPtrList<AST> l = storageSpec->nodeList();
+ QPtrListIterator<AST> it( l );
+ while( it.current() ){
+ QString text = it.current()->text();
+ if( text == "friend" ) isFriend = true;
+ else if( text == "static" ) isStatic = true;
+ ++it;
+ }
+ }
+
+ QString id = d->declaratorId()->unqualifiedName()->text().stripWhiteSpace();
+
+ UMLClassifier *c = m_currentClass[m_clsCnt];
+ if (c == NULL) {
+ kDebug() << "CppTree2Uml::parseFunctionDefinition (" << id
+ << "): need a surrounding class." << endl;
+ return;
+ }
+
+ QString returnType = typeOfDeclaration( typeSpec, d );
+ UMLOperation *m = Import_Utils::makeOperation(c, id);
+ // if a class has no return type, it could be a constructor or
+ // a destructor
+ if (d && returnType.isEmpty() && id.find("~") == -1)
+ isConstructor = true;
+
+ parseFunctionArguments( d, m );
+ Import_Utils::insertMethod( c, m, m_currentAccess, returnType,
+ isStatic, false /*isAbstract*/, isFriend, isConstructor, m_comment);
+ m_comment = "";
+
+/* For reference, Kdevelop does some more:
+ method->setFileName( m_fileName );
+ if( m_inSignals )
+ method->setSignal( true );
+ if( m_inSlots )
+ method->setSlot( true );
+ */
+}
+
+void CppTree2Uml::parseClassSpecifier( ClassSpecifierAST* ast )
+{
+ Uml::Visibility oldAccess = m_currentAccess;
+ bool oldInSlots = m_inSlots;
+ bool oldInSignals = m_inSignals;
+
+ QString kind = ast->classKey()->text();
+ m_currentAccess=Uml::Visibility::fromString(kind);
+ m_inSlots = false;
+ m_inSignals = false;
+
+ QString className;
+ if( !ast->name() && m_currentDeclarator && m_currentDeclarator->declaratorId() ) {
+ className = m_currentDeclarator->declaratorId()->text().stripWhiteSpace();
+ } else if( !ast->name() ){
+ QFileInfo fileInfo( m_fileName );
+ QString shortFileName = fileInfo.baseName();
+ className.sprintf( "(%s_%d)", shortFileName.local8Bit().data(), m_anon++ );
+ } else {
+ className = ast->name()->unqualifiedName()->text().stripWhiteSpace();
+ }
+//#ifdef DEBUG_CPPTREE2UML
+ kDebug() << "CppTree2Uml::parseClassSpecifier: name=" << className << endl;
+//#endif
+ if( !scopeOfName( ast->name(), QStringList() ).isEmpty() ){
+ kDebug() << "skip private class declarations" << endl;
+ return;
+ }
+
+ if (className.isEmpty()) {
+ className = "anon_" + QString::number(m_anon);
+ m_anon++;
+ }
+ UMLObject * o = Import_Utils::createUMLObject( Uml::ot_Class, className,
+ m_currentNamespace[m_nsCnt],
+ ast->comment() );
+ UMLClassifier *klass = static_cast<UMLClassifier*>(o);
+ flushTemplateParams(klass);
+ if ( ast->baseClause() )
+ parseBaseClause( ast->baseClause(), klass );
+
+ m_currentScope.push_back( className );
+ if (++m_clsCnt > STACKSIZE) {
+ kdError() << "CppTree2Uml::parseNamespace: excessive class nesting" << endl;
+ m_clsCnt = STACKSIZE;
+ }
+ m_currentClass[m_clsCnt] = klass;
+ if (++m_nsCnt > STACKSIZE) {
+ kdError() << "CppTree2Uml::parseNamespace: excessive namespace nesting" << endl;
+ m_nsCnt = STACKSIZE;
+ }
+ m_currentNamespace[m_nsCnt] = (UMLPackage*)klass;
+
+ TreeParser::parseClassSpecifier( ast );
+
+ --m_nsCnt;
+ --m_clsCnt;
+
+ m_currentScope.pop_back();
+
+ m_currentAccess = oldAccess;
+ m_inSlots = oldInSlots;
+ m_inSignals = oldInSignals;
+}
+
+void CppTree2Uml::parseEnumSpecifier( EnumSpecifierAST* ast )
+{
+ NameAST *nameNode = ast->name();
+ if (nameNode == NULL)
+ return; // skip constants
+ QString typeName = nameNode->unqualifiedName()->text().stripWhiteSpace();
+ if (typeName.isEmpty())
+ return; // skip constants
+ UMLObject *o = Import_Utils::createUMLObject( Uml::ot_Enum, typeName,
+ m_currentNamespace[m_nsCnt],
+ ast->comment() );
+
+ QPtrList<EnumeratorAST> l = ast->enumeratorList();
+ QPtrListIterator<EnumeratorAST> it( l );
+ while ( it.current() ) {
+ QString enumLiteral = it.current()->id()->text();
+ Import_Utils::addEnumLiteral( (UMLEnum*)o, enumLiteral );
+ ++it;
+ }
+}
+
+void CppTree2Uml::parseElaboratedTypeSpecifier( ElaboratedTypeSpecifierAST* typeSpec )
+{
+ // This is invoked for forward declarations.
+ /// @todo Refine - Currently only handles class forward declarations.
+ /// - Using typeSpec->text() is probably not good, decode
+ /// the kind() instead.
+ QString text = typeSpec->text();
+ kDebug() << "CppTree2Uml::parseElaboratedTypeSpecifier: text is " << text << endl;
+ text.remove(QRegExp("^class\\s+"));
+ UMLObject *o = Import_Utils::createUMLObject(Uml::ot_Class, text, m_currentNamespace[m_nsCnt]);
+ flushTemplateParams( static_cast<UMLClassifier*>(o) );
+}
+
+void CppTree2Uml::parseDeclaration( GroupAST* funSpec, GroupAST* storageSpec,
+ TypeSpecifierAST* typeSpec, InitDeclaratorAST* decl )
+{
+ if( m_inStorageSpec )
+ return;
+
+ DeclaratorAST* d = decl->declarator();
+
+ if( !d )
+ return;
+
+ if( !d->subDeclarator() && d->parameterDeclarationClause() )
+ return parseFunctionDeclaration( funSpec, storageSpec, typeSpec, decl );
+
+ DeclaratorAST* t = d;
+ while( t && t->subDeclarator() )
+ t = t->subDeclarator();
+
+ QString id;
+ if( t && t->declaratorId() && t->declaratorId()->unqualifiedName() )
+ id = t->declaratorId()->unqualifiedName()->text();
+
+ if( !scopeOfDeclarator(d, QStringList()).isEmpty() ){
+ kDebug() << "CppTree2Uml::parseDeclaration (" << id << "): skipping."
+ << endl;
+ return;
+ }
+
+ UMLClassifier *c = m_currentClass[m_clsCnt];
+ if (c == NULL) {
+ kDebug() << "CppTree2Uml::parseDeclaration (" << id
+ << "): need a surrounding class." << endl;
+ return;
+ }
+
+ QString typeName = typeOfDeclaration( typeSpec, d );
+ bool isFriend = false;
+ bool isStatic = false;
+ //bool isInitialized = decl->initializer() != 0;
+
+ if( storageSpec ){
+ QPtrList<AST> l = storageSpec->nodeList();
+ QPtrListIterator<AST> it( l );
+ while( it.current() ){
+ QString text = it.current()->text();
+ if( text == "friend" ) isFriend = true;
+ else if( text == "static" ) isStatic = true;
+ ++it;
+ }
+ }
+
+ Import_Utils::insertAttribute( c, m_currentAccess, id, typeName,
+ m_comment, isStatic);
+ m_comment = "";
+}
+
+void CppTree2Uml::parseAccessDeclaration( AccessDeclarationAST * access )
+{
+ QPtrList<AST> l = access->accessList();
+
+ QString accessStr = l.at( 0 )->text();
+
+ m_currentAccess=Uml::Visibility::fromString(accessStr);
+
+ m_inSlots = l.count() > 1 ? l.at( 1 )->text() == "slots" : false;
+ m_inSignals = l.count() >= 1 ? l.at( 0 )->text() == "signals" : false;
+}
+
+void CppTree2Uml::parseFunctionDeclaration( GroupAST* funSpec, GroupAST* storageSpec,
+ TypeSpecifierAST * typeSpec, InitDeclaratorAST * decl )
+{
+ bool isFriend = false;
+ bool isVirtual = false;
+ bool isStatic = false;
+ bool isInline = false;
+ bool isPure = decl->initializer() != 0;
+ bool isConstructor = false;
+
+ if( funSpec ){
+ QPtrList<AST> l = funSpec->nodeList();
+ QPtrListIterator<AST> it( l );
+ while( it.current() ){
+ QString text = it.current()->text();
+ if( text == "virtual" ) isVirtual = true;
+ else if( text == "inline" ) isInline = true;
+ ++it;
+ }
+ }
+
+ if( storageSpec ){
+ QPtrList<AST> l = storageSpec->nodeList();
+ QPtrListIterator<AST> it( l );
+ while( it.current() ){
+ QString text = it.current()->text();
+ if( text == "friend" ) isFriend = true;
+ else if( text == "static" ) isStatic = true;
+ ++it;
+ }
+ }
+
+ DeclaratorAST* d = decl->declarator();
+ QString id = d->declaratorId()->unqualifiedName()->text();
+
+ UMLClassifier *c = m_currentClass[m_clsCnt];
+ if (c == NULL) {
+ kDebug() << "CppTree2Uml::parseFunctionDeclaration (" << id
+ << "): need a surrounding class." << endl;
+ return;
+ }
+
+ QString returnType = typeOfDeclaration( typeSpec, d );
+ UMLOperation *m = Import_Utils::makeOperation(c, id);
+ // if a class has no return type, it could be a constructor or
+ // a destructor
+ if (d && returnType.isEmpty() && id.find("~") == -1)
+ isConstructor = true;
+
+ parseFunctionArguments( d, m );
+ Import_Utils::insertMethod( c, m, m_currentAccess, returnType,
+ isStatic, isPure, isFriend, isConstructor, m_comment);
+ m_comment = "";
+}
+
+void CppTree2Uml::parseFunctionArguments(DeclaratorAST* declarator,
+ UMLOperation* method)
+{
+ ParameterDeclarationClauseAST* clause = declarator->parameterDeclarationClause();
+
+ if( clause && clause->parameterDeclarationList() ){
+ ParameterDeclarationListAST* params = clause->parameterDeclarationList();
+ QPtrList<ParameterDeclarationAST> l( params->parameterList() );
+ QPtrListIterator<ParameterDeclarationAST> it( l );
+ while( it.current() ){
+ ParameterDeclarationAST* param = it.current();
+ ++it;
+
+ QString name;
+ if (param->declarator())
+ name = declaratorToString(param->declarator(), QString::null, true );
+
+ QString tp = typeOfDeclaration( param->typeSpec(), param->declarator() );
+
+ if (tp != "void")
+ Import_Utils::addMethodParameter( method, tp, name );
+ }
+ }
+}
+
+QString CppTree2Uml::typeOfDeclaration( TypeSpecifierAST* typeSpec, DeclaratorAST* declarator )
+{
+ if( !typeSpec || !declarator )
+ return QString::null;
+
+ QString text;
+
+ text += typeSpec->text();
+
+ QPtrList<AST> ptrOpList = declarator->ptrOpList();
+ for( QPtrListIterator<AST> it(ptrOpList); it.current(); ++it ){
+ text += it.current()->text();
+ }
+
+ return text;
+}
+
+void CppTree2Uml::parseBaseClause( BaseClauseAST * baseClause, UMLClassifier* klass )
+{
+ QPtrList<BaseSpecifierAST> l = baseClause->baseSpecifierList();
+ QPtrListIterator<BaseSpecifierAST> it( l );
+ while( it.current() ){
+ BaseSpecifierAST* baseSpecifier = it.current();
+ ++it;
+
+ if (baseSpecifier->name() == NULL) {
+ kDebug() << "CppTree2Uml::parseBaseClause: baseSpecifier->name() is NULL"
+ << endl;
+ continue;
+ }
+
+ QString baseName = baseSpecifier->name()->text();
+ Import_Utils::createGeneralization( klass, baseName );
+ }
+}
+
+QStringList CppTree2Uml::scopeOfName( NameAST* id, const QStringList& startScope )
+{
+ QStringList scope = startScope;
+ if( id && id->classOrNamespaceNameList().count() ){
+ if( id->isGlobal() )
+ scope.clear();
+ QPtrList<ClassOrNamespaceNameAST> l = id->classOrNamespaceNameList();
+ QPtrListIterator<ClassOrNamespaceNameAST> it( l );
+ while( it.current() ){
+ if( it.current()->name() ){
+ scope << it.current()->name()->text();
+ }
+ ++it;
+ }
+ }
+
+ return scope;
+}
+
+QStringList CppTree2Uml::scopeOfDeclarator( DeclaratorAST* d, const QStringList& startScope )
+{
+ return scopeOfName( d->declaratorId(), startScope );
+}
+
+void CppTree2Uml::flushTemplateParams(UMLClassifier *klass) {
+ if (m_templateParams.count()) {
+ Model_Utils::NameAndType_ListIt it;
+ for (it = m_templateParams.begin(); it != m_templateParams.end(); ++it) {
+ const Model_Utils::NameAndType &nt = *it;
+ kDebug() << "CppTree2Uml::parseClassSpecifier: adding template param: "
+ << nt.m_name << endl;
+ UMLTemplate *tmpl = klass->addTemplate(nt.m_name);
+ tmpl->setType(nt.m_type);
+ }
+ m_templateParams.clear();
+ }
+}
+
diff --git a/umbrello/umbrello/codeimport/kdevcppparser/cpptree2uml.h b/umbrello/umbrello/codeimport/kdevcppparser/cpptree2uml.h
new file mode 100644
index 00000000..b9791372
--- /dev/null
+++ b/umbrello/umbrello/codeimport/kdevcppparser/cpptree2uml.h
@@ -0,0 +1,98 @@
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * copyright (C) 2005-2007 *
+ * Umbrello UML Modeller Authors <uml-devel@uml.sf.net> *
+ ***************************************************************************/
+
+#ifndef CPPTREE2UML_H
+#define CPPTREE2UML_H
+
+#include "tree_parser.h"
+#include <qstringlist.h>
+#include "../../model_utils.h"
+
+// fwd decls
+class UMLClassifier;
+class UMLOperation;
+class UMLPackage;
+
+class CppTree2Uml: public TreeParser
+{
+public:
+ CppTree2Uml( const QString& fileName);
+ virtual ~CppTree2Uml();
+
+ //FileDom file() { return m_file; }
+
+ // translation-unit
+ virtual void parseTranslationUnit( TranslationUnitAST* );
+
+ // declarations
+ //virtual void parseDeclaration( DeclarationAST* ); // use parent method
+ //virtual void parseLinkageSpecification( LinkageSpecificationAST* ); // use parent method
+ virtual void parseNamespace( NamespaceAST* );
+ //virtual void parseNamespaceAlias( NamespaceAliasAST* ); // use parent method
+ //virtual void parseUsing( UsingAST* ); // use parent method
+ //virtual void parseUsingDirective( UsingDirectiveAST* ); // use parent method
+ virtual void parseTypedef( TypedefAST* );
+ virtual void parseTemplateDeclaration( TemplateDeclarationAST* );
+ virtual void parseSimpleDeclaration( SimpleDeclarationAST* );
+ virtual void parseFunctionDefinition( FunctionDefinitionAST* );
+ //virtual void parseLinkageBody( LinkageBodyAST* ); // use parent method
+ virtual void parseAccessDeclaration( AccessDeclarationAST* );
+
+ // type-specifier
+ //virtual void parseTypeSpecifier( TypeSpecifierAST* ); // use parent method
+ virtual void parseClassSpecifier( ClassSpecifierAST* );
+ virtual void parseEnumSpecifier( EnumSpecifierAST* );
+ virtual void parseElaboratedTypeSpecifier( ElaboratedTypeSpecifierAST* );
+
+ // non-overriding (locally added) methods
+
+ virtual void parseDeclaration( GroupAST* funSpec, GroupAST* storageSpec, TypeSpecifierAST* typeSpec, InitDeclaratorAST* decl );
+ virtual void parseFunctionDeclaration( GroupAST* funSpec, GroupAST* storageSpec, TypeSpecifierAST* typeSpec, InitDeclaratorAST* decl );
+ void parseFunctionArguments( DeclaratorAST* declarator, UMLOperation* method);
+ virtual void parseBaseClause( BaseClauseAST* baseClause, UMLClassifier* klass );
+
+private:
+ //NamespaceDom findOrInsertNamespace( NamespaceAST* ast, const QString& name );
+
+ QString typeOfDeclaration( TypeSpecifierAST* typeSpec, DeclaratorAST* declarator );
+ QStringList scopeOfName( NameAST* id, const QStringList& scope );
+ QStringList scopeOfDeclarator( DeclaratorAST* d, const QStringList& scope );
+ /**
+ * Flush template parameters pending in m_templateParams to the klass.
+ */
+ void flushTemplateParams(UMLClassifier *klass);
+
+private:
+ //FileDom m_file;
+ QString m_fileName;
+ QStringList m_currentScope;
+ Uml::Visibility m_currentAccess;
+ bool m_inSlots;
+ bool m_inSignals;
+ int m_anon;
+ bool m_inStorageSpec;
+ bool m_inTypedef;
+ QString m_comment;
+ Model_Utils::NameAndType_List m_templateParams;
+
+ DeclaratorAST* m_currentDeclarator;
+# define STACKSIZE 30
+ UMLPackage* m_currentNamespace[STACKSIZE+1]; ///< stack
+ UMLClassifier* m_currentClass[STACKSIZE+1]; ///< stack
+ int m_nsCnt; ///< stack top for m_currentNamespace
+ int m_clsCnt; ///< stack top for m_currentClass
+
+private:
+ CppTree2Uml( const CppTree2Uml& source );
+ void operator = ( const CppTree2Uml& source );
+};
+
+#endif // CPPTREE2UML
diff --git a/umbrello/umbrello/codeimport/kdevcppparser/driver.cpp b/umbrello/umbrello/codeimport/kdevcppparser/driver.cpp
new file mode 100644
index 00000000..84941025
--- /dev/null
+++ b/umbrello/umbrello/codeimport/kdevcppparser/driver.cpp
@@ -0,0 +1,435 @@
+/* This file is part of KDevelop
+ Copyright (C) 2002,2003 Roberto Raggi <roberto@kdevelop.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.
+*/
+
+#include "driver.h"
+#include "lexer.h"
+#include "parser.h"
+#include <kdebug.h>
+#include <stdlib.h>
+#include <qfile.h>
+#include <qfileinfo.h>
+#include <qdir.h>
+
+class DefaultSourceProvider: public SourceProvider
+{
+public:
+ DefaultSourceProvider() {}
+
+ virtual QString contents( const QString& fileName )
+ {
+ QString source;
+
+ QFile f( fileName );
+ if( f.open(IO_ReadOnly) ){
+ QTextStream s( &f );
+ source = s.read();
+ f.close();
+ }
+ return source;
+ }
+
+ virtual bool isModified( const QString& fileName )
+ {
+ Q_UNUSED( fileName );
+ return true;
+ }
+
+private:
+ DefaultSourceProvider( const DefaultSourceProvider& source );
+ void operator = ( const DefaultSourceProvider& source );
+};
+
+
+Driver::Driver()
+ : depresolv( false ), lexer( 0 )
+{
+ m_sourceProvider = new DefaultSourceProvider();
+}
+
+Driver::~Driver()
+{
+ reset();
+ delete( m_sourceProvider );
+}
+
+SourceProvider* Driver::sourceProvider()
+{
+ return m_sourceProvider;
+}
+
+void Driver::setSourceProvider( SourceProvider* sourceProvider )
+{
+ if( m_sourceProvider )
+ delete( m_sourceProvider );
+ m_sourceProvider = sourceProvider;
+}
+
+void Driver::reset( )
+{
+ m_dependences.clear();
+ m_macros.clear();
+ m_problems.clear();
+ m_includePaths.clear();
+
+ while( m_parsedUnits.size() ){
+ TranslationUnitAST* unit = *m_parsedUnits.begin();
+ m_parsedUnits.remove( m_parsedUnits.begin() );
+ delete( unit );
+ }
+}
+
+void Driver::remove( const QString & fileName )
+{
+ m_dependences.remove( fileName );
+ m_problems.remove( fileName );
+ removeAllMacrosInFile( fileName );
+
+ QMap<QString, TranslationUnitAST*>::Iterator it = m_parsedUnits.find( fileName );
+ if( it != m_parsedUnits.end() ){
+ TranslationUnitAST* unit = *it;
+ m_parsedUnits.remove( it );
+ delete( unit );
+ }
+}
+
+void Driver::removeAllMacrosInFile( const QString& fileName )
+{
+ QMap<QString, Macro>::Iterator it = m_macros.begin();
+ while( it != m_macros.end() ){
+ Macro m = *it++;
+ if( m.fileName() == fileName )
+ removeMacro( m.name() );
+ }
+}
+
+TranslationUnitAST::Node Driver::takeTranslationUnit( const QString& fileName )
+{
+ QMap<QString, TranslationUnitAST*>::Iterator it = m_parsedUnits.find( fileName );
+ TranslationUnitAST::Node unit( *it );
+ //m_parsedUnits.remove( it );
+ m_parsedUnits[ fileName] = 0;
+ return unit;
+}
+
+TranslationUnitAST* Driver::translationUnit( const QString& fileName ) const
+{
+ QMap<QString, TranslationUnitAST*>::ConstIterator it = m_parsedUnits.find( fileName );
+ return it != m_parsedUnits.end() ? *it : 0;
+}
+
+void Driver::addDependence( const QString & fileName, const Dependence & dep )
+{
+ QFileInfo fileInfo( dep.first );
+ QString fn = fileInfo.absFilePath();
+
+ if ( !depresolv ){
+ findOrInsertDependenceList( fileName ).insert( fn, dep );
+ return;
+ }
+
+ QString file = findIncludeFile( dep );
+ findOrInsertDependenceList( fileName ).insert( file, dep );
+
+ if ( m_parsedUnits.find(file) != m_parsedUnits.end() )
+ return;
+
+ if ( !QFile::exists( file ) ) {
+ Problem p( "Couldn't find include file " + dep.first,
+ lexer ? lexer->currentLine() : -1,
+ lexer ? lexer->currentColumn() : -1 );
+ addProblem( fileName, p );
+ return;
+ }
+
+ QString cfn = m_currentFileName;
+ Lexer *l = lexer;
+ parseFile( file );
+ m_currentFileName = cfn;
+ lexer = l;
+}
+
+void Driver::addMacro( const Macro & macro )
+{
+ m_macros.insert( macro.name(), macro );
+}
+
+void Driver::addProblem( const QString & fileName, const Problem & problem )
+{
+ findOrInsertProblemList( fileName ).append( problem );
+}
+
+QMap< QString, Dependence >& Driver::findOrInsertDependenceList( const QString & fileName )
+{
+ QMap<QString, QMap<QString, Dependence> >::Iterator it = m_dependences.find( fileName );
+ if( it != m_dependences.end() )
+ return it.data();
+
+ QMap<QString, Dependence> l;
+ m_dependences.insert( fileName, l );
+ return m_dependences[ fileName ];
+}
+
+QValueList < Problem >& Driver::findOrInsertProblemList( const QString & fileName )
+{
+ QMap<QString, QValueList<Problem> >::Iterator it = m_problems.find( fileName );
+ if( it != m_problems.end() )
+ return it.data();
+
+ QValueList<Problem> l;
+ m_problems.insert( fileName, l );
+ return m_problems[ fileName ];
+}
+
+QMap< QString, Dependence > Driver::dependences( const QString & fileName ) const
+{
+ QMap<QString, QMap<QString, Dependence> >::ConstIterator it = m_dependences.find( fileName );
+ if( it != m_dependences.end() )
+ return it.data();
+ return QMap<QString, Dependence>();
+}
+
+QMap< QString, Macro > Driver::macros() const
+{
+ return m_macros;
+}
+
+QValueList < Problem > Driver::problems( const QString & fileName ) const
+{
+ QMap<QString, QValueList<Problem> >::ConstIterator it = m_problems.find( fileName );
+ if( it != m_problems.end() )
+ return it.data();
+ return QValueList<Problem>();
+}
+
+void Driver::parseFile( const QString& fileName, bool onlyPreProcess, bool force )
+{
+ QFileInfo fileInfo( fileName );
+ QString absFilePath = fileInfo.absFilePath();
+
+ QMap<QString, TranslationUnitAST*>::Iterator it = m_parsedUnits.find( absFilePath );
+
+ if( force && it != m_parsedUnits.end() ){
+ takeTranslationUnit( absFilePath );
+ } else if( it != m_parsedUnits.end() && *it != 0 ){
+ // file already processed
+ return;
+ }
+
+ m_dependences.remove( fileName );
+ m_problems.remove( fileName );
+
+ m_currentFileName = fileName;
+
+ Lexer lex( this );
+ lexer = &lex;
+ setupLexer( &lex );
+
+ lex.setSource( sourceProvider()->contents(fileName) );
+
+ if( !onlyPreProcess ){
+ Parser parser( this, &lex );
+ setupParser( &parser );
+
+ TranslationUnitAST :: Node translationUnit;
+ parser.parseTranslationUnit( translationUnit );
+ m_parsedUnits.insert( fileName, translationUnit.release() );
+ fileParsed( fileName );
+ }
+
+ m_currentFileName = QString::null;
+ lexer = 0;
+}
+
+void Driver::setupLexer( Lexer * lexer )
+{
+ // stl
+ lexer->addSkipWord( "__STL_BEGIN_NAMESPACE" );
+ lexer->addSkipWord( "__STL_END_NAMESPACE" );
+ lexer->addSkipWord( "__STL_BEGIN_RELOPS_NAMESPACE" );
+ lexer->addSkipWord( "__STL_END_RELOPS_NAMESPACE" );
+ lexer->addSkipWord( "__STL_TEMPLATE_NULL" );
+ lexer->addSkipWord( "__STL_TRY" );
+ lexer->addSkipWord( "__STL_UNWIND" );
+ lexer->addSkipWord( "__STL_NOTHROW" );
+ lexer->addSkipWord( "__STL_NULL_TMPL_ARGS" );
+ lexer->addSkipWord( "__STL_UNWIND", SkipWordAndArguments );
+ lexer->addSkipWord( "__GC_CONST" );
+ lexer->addSkipWord( "__HASH_ALLOC_INIT", SkipWordAndArguments );
+ lexer->addSkipWord( "__STL_DEFAULT_ALLOCATOR", SkipWordAndArguments, "T" );
+ lexer->addSkipWord( "__STL_MUTEX_INITIALIZER" );
+ lexer->addSkipWord( "__STL_NULL_TMPL_ARGS" );
+
+ // antlr
+ lexer->addSkipWord( "ANTLR_BEGIN_NAMESPACE", SkipWordAndArguments );
+ lexer->addSkipWord( "ANTLR_USE_NAMESPACE", SkipWordAndArguments );
+ lexer->addSkipWord( "ANTLR_USING_NAMESPACE", SkipWordAndArguments );
+ lexer->addSkipWord( "ANTLR_END_NAMESPACE" );
+ lexer->addSkipWord( "ANTLR_C_USING", SkipWordAndArguments );
+ lexer->addSkipWord( "ANTLR_API" );
+
+ // gnu
+ lexer->addSkipWord( "__extension__", SkipWordAndArguments );
+ lexer->addSkipWord( "__attribute__", SkipWordAndArguments );
+ lexer->addSkipWord( "__BEGIN_DECLS" );
+ lexer->addSkipWord( "__END_DECLS" );
+ lexer->addSkipWord( "__THROW" );
+ lexer->addSkipWord( "__restrict" );
+ lexer->addSkipWord( "__restrict__" );
+ lexer->addSkipWord( "__attribute_pure__" );
+ lexer->addSkipWord( "__attribute_malloc__" );
+ lexer->addSkipWord( "__attribute_format_strfmon__" );
+ lexer->addSkipWord( "__asm__", SkipWordAndArguments );
+ lexer->addSkipWord( "__devinit" );
+ lexer->addSkipWord( "__devinit__" );
+ lexer->addSkipWord( "__init" );
+ lexer->addSkipWord( "__init__" );
+ lexer->addSkipWord( "__signed" );
+ lexer->addSkipWord( "__signed__" );
+ lexer->addSkipWord( "__unsigned" );
+ lexer->addSkipWord( "__unsigned__" );
+ lexer->addSkipWord( "asmlinkage" );
+ lexer->addSkipWord( "____cacheline_aligned" );
+ lexer->addSkipWord( "__glibcpp_class_requires", SkipWordAndArguments );
+ lexer->addSkipWord( "__glibcpp_class2_requires", SkipWordAndArguments );
+ lexer->addSkipWord( "__glibcpp_class4_requires", SkipWordAndArguments );
+ lexer->addSkipWord( "__glibcpp_function_requires", SkipWordAndArguments );
+ lexer->addSkipWord( "restrict" );
+
+ lexer->addSkipWord( "__BEGIN_NAMESPACE_STD" );
+ lexer->addSkipWord( "__END_NAMESPACE_STD" );
+ lexer->addSkipWord( "__BEGIN_NAMESPACE_C99" );
+ lexer->addSkipWord( "__END_NAMESPACE_C99" );
+ lexer->addSkipWord( "__USING_NAMESPACE_STD", SkipWordAndArguments );
+
+ // kde
+ lexer->addSkipWord( "K_SYCOCATYPE", SkipWordAndArguments );
+ lexer->addSkipWord( "EXPORT_DOCKCLASS" );
+ lexer->addSkipWord( "K_EXPORT_COMPONENT_FACTORY", SkipWordAndArguments );
+ lexer->addSkipWord( "K_SYCOCAFACTORY", SkipWordAndArguments );
+ lexer->addSkipWord( "KDE_DEPRECATED" );
+
+ // qt
+ lexer->addSkipWord( "Q_OVERRIDE", SkipWordAndArguments );
+ lexer->addSkipWord( "Q_ENUMS", SkipWordAndArguments );
+ lexer->addSkipWord( "Q_PROPERTY", SkipWordAndArguments );
+ lexer->addSkipWord( "Q_CLASSINFO", SkipWordAndArguments );
+ lexer->addSkipWord( "Q_SETS", SkipWordAndArguments );
+ lexer->addSkipWord( "Q_UNUSED", SkipWordAndArguments );
+ lexer->addSkipWord( "Q_CREATE_INSTANCE", SkipWordAndArguments );
+ lexer->addSkipWord( "Q_DUMMY_COMPARISON_OPERATOR", SkipWordAndArguments );
+ lexer->addSkipWord( "ACTIVATE_SIGNAL_WITH_PARAM", SkipWordAndArguments );
+ lexer->addSkipWord( "Q_INLINE_TEMPLATES" );
+ lexer->addSkipWord( "Q_TEMPLATE_EXTERN" );
+ lexer->addSkipWord( "Q_TYPENAME" );
+ lexer->addSkipWord( "Q_REFCOUNT" );
+ lexer->addSkipWord( "Q_EXPLICIT" );
+ lexer->addSkipWord( "QMAC_PASCAL" );
+ lexer->addSkipWord( "QT_STATIC_CONST" );
+ lexer->addSkipWord( "QT_STATIC_CONST_IMPL" );
+ lexer->addSkipWord( "QT_WIN_PAINTER_MEMBERS" );
+ lexer->addSkipWord( "QT_NC_MSGBOX" );
+ lexer->addSkipWord( "Q_VARIANT_AS", SkipWordAndArguments );
+ lexer->addSkipWord( "CALLBACK_CALL_TYPE" );
+
+ // flex
+ lexer->addSkipWord( "yyconst" );
+ lexer->addSkipWord( "YY_RULE_SETUP" );
+ lexer->addSkipWord( "YY_BREAK" );
+ lexer->addSkipWord( "YY_RESTORE_YY_MORE_OFFSET" );
+
+ // gtk
+ lexer->addSkipWord( "G_BEGIN_DECLS" );
+ lexer->addSkipWord( "G_END_DECLS" );
+ lexer->addSkipWord( "G_GNUC_CONST" );
+ lexer->addSkipWord( "G_CONST_RETURN" );
+ lexer->addSkipWord( "GTKMAIN_C_VAR" );
+ lexer->addSkipWord( "GTKVAR" );
+ lexer->addSkipWord( "GDKVAR" );
+ lexer->addSkipWord( "G_GNUC_PRINTF", SkipWordAndArguments );
+
+ // windows
+ lexer->addSkipWord( "WINAPI" );
+ lexer->addSkipWord( "__stdcall" );
+ lexer->addSkipWord( "__cdecl" );
+ lexer->addSkipWord( "_cdecl" );
+ lexer->addSkipWord( "CALLBACK" );
+
+ // gcc extensions
+ addMacro( Macro("__asm__", "asm") );
+ addMacro( Macro("__inline", "inline") );
+ addMacro( Macro("__inline__", "inline") );
+ addMacro( Macro("__const", "const") );
+ addMacro( Macro("__const__", "const") );
+ addMacro( Macro("__volatile__", "volatile") );
+ addMacro( Macro("__complex__", "") );
+}
+
+void Driver::setupParser( Parser * parser )
+{
+ Q_UNUSED( parser );
+}
+
+void Driver::removeMacro( const QString& macroName )
+{
+ m_macros.remove( macroName );
+}
+
+void Driver::addIncludePath( const QString &path )
+{
+ if( !path.stripWhiteSpace().isEmpty() )
+ m_includePaths << path;
+}
+
+QString Driver::findIncludeFile( const Dependence& dep ) const
+{
+ QString fileName = dep.first;
+
+ if( dep.second == Dep_Local ){
+ QString path = QFileInfo( currentFileName() ).dirPath( true );
+ QFileInfo fileInfo( QFileInfo(path, fileName) );
+ if ( fileInfo.exists() && fileInfo.isFile() )
+ return fileInfo.absFilePath();
+
+ }
+
+ QStringList::ConstIterator end(m_includePaths.end());
+ for ( QStringList::ConstIterator it(m_includePaths.begin()); it != end; ++it ) {
+ QFileInfo fileInfo( *it, fileName );
+ if ( fileInfo.exists() && fileInfo.isFile() )
+ return fileInfo.absFilePath();
+ }
+
+ return QString::null;
+}
+
+void Driver::setResolveDependencesEnabled( bool enabled )
+{
+ depresolv = enabled;
+ if ( depresolv )
+ setupPreProcessor();
+}
+
+void Driver::setupPreProcessor()
+{
+}
+
+void Driver::fileParsed( const QString & fileName )
+{
+ Q_UNUSED( fileName );
+}
diff --git a/umbrello/umbrello/codeimport/kdevcppparser/driver.h b/umbrello/umbrello/codeimport/kdevcppparser/driver.h
new file mode 100644
index 00000000..ecb603ab
--- /dev/null
+++ b/umbrello/umbrello/codeimport/kdevcppparser/driver.h
@@ -0,0 +1,230 @@
+/* This file is part of KDevelop
+ Copyright (C) 2002,2003 Roberto Raggi <roberto@kdevelop.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 DRIVER_H
+#define DRIVER_H
+
+#include "ast.h"
+
+#include <qpair.h>
+#include <qvaluestack.h>
+#include <qstringlist.h>
+#include <qmap.h>
+
+class Lexer;
+class Parser;
+
+class Problem
+{
+public:
+ enum
+ {
+ Level_Error = 0,
+ Level_Warning,
+ Level_Todo,
+ Level_Fixme
+ };
+
+public:
+ Problem() {}
+ Problem( const Problem& source )
+ : m_text( source.m_text ), m_line( source.m_line ),
+ m_column( source.m_column ), m_level( source.m_level ) {}
+ Problem( const QString& text, int line, int column, int level=Level_Error )
+ : m_text( text ), m_line( line ), m_column( column ), m_level(level) {}
+
+ Problem& operator = ( const Problem& source )
+ {
+ m_text = source.m_text;
+ m_line = source.m_line;
+ m_column = source.m_column;
+ m_level = source.m_level;
+ return( *this );
+ }
+
+ bool operator == ( const Problem& p ) const
+ {
+ return m_text == p.m_text && m_line == p.m_line && m_column == p.m_column && m_level == p.m_level;
+ }
+
+ QString text() const { return m_text; }
+ int line() const { return m_line; }
+ int column() const { return m_column; }
+ int level() const { return m_level; }
+
+private:
+ QString m_text;
+ int m_line;
+ int m_column;
+ int m_level;
+};
+
+enum
+{
+ Dep_Global,
+ Dep_Local
+};
+
+typedef QPair<QString, int> Dependence;
+
+class Macro
+{
+public:
+ typedef QString Argument;
+
+public:
+ Macro( bool hasArguments = false ): m_hasArguments( hasArguments ) {}
+ Macro( const QString &n, const QString &b ) : m_name( n ), m_body( b ), m_hasArguments( false ) {}
+
+ Macro( const Macro& source )
+ : m_name( source.m_name),
+ m_fileName( source.m_fileName ),
+ m_body( source.m_body ),
+ m_hasArguments( source.m_hasArguments ),
+ m_argumentList( source.m_argumentList ) {}
+
+ Macro& operator = ( const Macro& source )
+ {
+ m_name = source.m_name;
+ m_body = source.m_body;
+ m_fileName = source.m_fileName;
+ m_hasArguments = source.m_hasArguments;
+ m_argumentList = source.m_argumentList;
+ return *this;
+ }
+
+ bool operator == ( const Macro& source ) const
+ {
+ return
+ m_name == source.m_name &&
+ m_fileName == source.m_fileName &&
+ m_body == source.m_body &&
+ m_hasArguments == source.m_hasArguments &&
+ m_argumentList == source.m_argumentList;
+ }
+
+ QString name() const { return m_name; }
+ void setName( const QString& name ) { m_name = name; }
+
+ QString fileName() const { return m_fileName; }
+ void setFileName( const QString& fileName ) { m_fileName = fileName; }
+
+ QString body() const { return m_body; }
+ void setBody( const QString& body ) { m_body = body; }
+
+ bool hasArguments() const { return m_hasArguments; }
+ void setHasArguments( bool hasArguments ) { m_hasArguments = hasArguments; }
+ QValueList<Argument> argumentList() const { return m_argumentList; }
+
+ void clearArgumentList() { m_argumentList.clear(); m_hasArguments = false; }
+ void addArgument( const Argument& argument ) { m_argumentList << argument; }
+ void addArgumentList( const QValueList<Argument>& arguments ) { m_argumentList += arguments; }
+
+private:
+ QString m_name;
+ QString m_fileName;
+ QString m_body;
+ bool m_hasArguments;
+ QValueList<Argument> m_argumentList;
+};
+
+class SourceProvider
+{
+public:
+ SourceProvider() {}
+ virtual ~SourceProvider() {}
+
+ virtual QString contents( const QString& fileName ) = 0;
+ virtual bool isModified( const QString& fileName ) = 0;
+
+private:
+ SourceProvider( const SourceProvider& source );
+ void operator = ( const SourceProvider& source );
+};
+
+class Driver
+{
+public:
+ Driver();
+ virtual ~Driver();
+
+ SourceProvider* sourceProvider();
+ void setSourceProvider( SourceProvider* sourceProvider );
+
+ virtual void reset();
+
+ virtual void parseFile( const QString& fileName, bool onlyPreProcesss=false, bool force=false );
+ virtual void fileParsed( const QString& fileName );
+ virtual void remove( const QString& fileName );
+
+ virtual void addDependence( const QString& fileName, const Dependence& dep );
+ virtual void addMacro( const Macro& macro );
+ virtual void addProblem( const QString& fileName, const Problem& problem );
+
+
+ QString currentFileName() const { return m_currentFileName; }
+ TranslationUnitAST::Node takeTranslationUnit( const QString& fileName );
+ TranslationUnitAST* translationUnit( const QString& fileName ) const;
+ QMap<QString, Dependence> dependences( const QString& fileName ) const;
+ QMap<QString, Macro> macros() const;
+ QValueList<Problem> problems( const QString& fileName ) const;
+
+ bool hasMacro( const QString& name ) const { return m_macros.contains( name ); }
+ const Macro& macro( const QString& name ) const { return m_macros[ name ]; }
+ Macro& macro( const QString& name ) { return m_macros[ name ]; }
+
+ virtual void removeMacro( const QString& macroName );
+ virtual void removeAllMacrosInFile( const QString& fileName );
+
+ QStringList includePaths() const { return m_includePaths; }
+ virtual void addIncludePath( const QString &path );
+
+ /// @todo remove
+ const QMap<QString, TranslationUnitAST*> &parsedUnits() const { return m_parsedUnits; }
+
+ virtual void setResolveDependencesEnabled( bool enabled );
+ bool isResolveDependencesEnabled() const { return depresolv; }
+
+protected:
+ virtual void setupLexer( Lexer* lexer );
+ virtual void setupParser( Parser* parser );
+ virtual void setupPreProcessor();
+
+private:
+ QMap<QString, Dependence>& findOrInsertDependenceList( const QString& fileName );
+ QValueList<Problem>& findOrInsertProblemList( const QString& fileName );
+ QString findIncludeFile( const Dependence& dep ) const;
+
+private:
+ QString m_currentFileName;
+ QMap< QString, QMap<QString, Dependence> > m_dependences;
+ QMap<QString, Macro> m_macros;
+ QMap< QString, QValueList<Problem> > m_problems;
+ QMap<QString, TranslationUnitAST*> m_parsedUnits;
+ QStringList m_includePaths;
+ uint depresolv : 1;
+ Lexer *lexer;
+ SourceProvider* m_sourceProvider;
+
+private:
+ Driver( const Driver& source );
+ void operator = ( const Driver& source );
+};
+
+#endif
diff --git a/umbrello/umbrello/codeimport/kdevcppparser/errors.cpp b/umbrello/umbrello/codeimport/kdevcppparser/errors.cpp
new file mode 100644
index 00000000..154301c6
--- /dev/null
+++ b/umbrello/umbrello/codeimport/kdevcppparser/errors.cpp
@@ -0,0 +1,25 @@
+/* This file is part of KDevelop
+ Copyright (C) 2002,2003 Roberto Raggi <roberto@kdevelop.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.
+*/
+
+#include "errors.h"
+#include <klocale.h>
+
+QT_STATIC_CONST_IMPL Error& Errors::InternalError = Error( 1, -1, i18n("Internal Error") );
+QT_STATIC_CONST_IMPL Error& Errors::SyntaxError = Error( 2, -1, i18n("Syntax Error before '%1'") );
+QT_STATIC_CONST_IMPL Error& Errors::ParseError = Error( 3, -1, i18n("Parse Error before '%1'") );
diff --git a/umbrello/umbrello/codeimport/kdevcppparser/errors.h b/umbrello/umbrello/codeimport/kdevcppparser/errors.h
new file mode 100644
index 00000000..f846533d
--- /dev/null
+++ b/umbrello/umbrello/codeimport/kdevcppparser/errors.h
@@ -0,0 +1,45 @@
+/* This file is part of KDevelop
+ Copyright (C) 2002,2003 Roberto Raggi <roberto@kdevelop.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 ERRORS_H
+#define ERRORS_H
+
+#include <qstring.h>
+
+
+struct Error{
+ int code;
+ int level;
+ QString text;
+
+ Error( int c, int l, const QString& s )
+ : code( c ), level( l ), text( s )
+ {}
+};
+
+class Errors{
+public:
+ QT_STATIC_CONST Error& InternalError;
+ QT_STATIC_CONST Error& SyntaxError;
+ QT_STATIC_CONST Error& ParseError;
+};
+
+
+
+#endif
diff --git a/umbrello/umbrello/codeimport/kdevcppparser/keywords.lut.h b/umbrello/umbrello/codeimport/kdevcppparser/keywords.lut.h
new file mode 100644
index 00000000..5c276953
--- /dev/null
+++ b/umbrello/umbrello/codeimport/kdevcppparser/keywords.lut.h
@@ -0,0 +1,123 @@
+/* Automatically generated from keywords.table using /home/roberto/src/kdelibs/kjs/create_hash_table. DO NOT EDIT ! */
+
+
+static const struct HashEntry keywordEntries[] = {
+ { "template", Token_template, 0, 0, 0 },
+ { "emit", Token_emit, 0, 0, &keywordEntries[88] },
+ { "long", Token_long, 0, 0, 0 },
+ { 0, 0, 0, 0, 0 },
+ { "void", Token_void, 0, 0, &keywordEntries[113] },
+ { 0, 0, 0, 0, 0 },
+ { "explicit", Token_explicit, 0, 0, &keywordEntries[100] },
+ { "enum", Token_enum, 0, 0, &keywordEntries[105] },
+ { 0, 0, 0, 0, 0 },
+ { "continue", Token_continue, 0, 0, &keywordEntries[99] },
+ { "k_dcop_signals", Token_k_dcop_signals, 0, 0, &keywordEntries[104] },
+ { "auto", Token_auto, 0, 0, &keywordEntries[91] },
+ { 0, 0, 0, 0, 0 },
+ { "Q_OBJECT", Token_Q_OBJECT, 0, 0, &keywordEntries[86] },
+ { "and_eq", Token_and_eq, 0, 0, 0 },
+ { 0, 0, 0, 0, 0 },
+ { "operator", Token_operator, 0, 0, 0 },
+ { 0, 0, 0, 0, 0 },
+ { "class", Token_class, 0, 0, &keywordEntries[90] },
+ { 0, 0, 0, 0, 0 },
+ { 0, 0, 0, 0, 0 },
+ { "while", Token_while, 0, 0, 0 },
+ { "k_dcop", Token_k_dcop, 0, 0, 0 },
+ { "compl", Token_compl, 0, 0, 0 },
+ { "bitand", Token_bitand, 0, 0, &keywordEntries[97] },
+ { "__int64", Token_int, 0, 0, &keywordEntries[89] },
+ { 0, 0, 0, 0, 0 },
+ { 0, 0, 0, 0, 0 },
+ { "bitor", Token_bitor, 0, 0, 0 },
+ { 0, 0, 0, 0, 0 },
+ { "friend", Token_friend, 0, 0, 0 },
+ { 0, 0, 0, 0, 0 },
+ { "signed", Token_signed, 0, 0, 0 },
+ { "double", Token_double, 0, 0, 0 },
+ { "K_DCOP", Token_K_DCOP, 0, 0, &keywordEntries[111] },
+ { "const", Token_const, 0, 0, &keywordEntries[92] },
+ { 0, 0, 0, 0, 0 },
+ { "inline", Token_inline, 0, 0, &keywordEntries[98] },
+ { 0, 0, 0, 0, 0 },
+ { "do", Token_do, 0, 0, 0 },
+ { 0, 0, 0, 0, 0 },
+ { "const_cast", Token_const_cast, 0, 0, 0 },
+ { 0, 0, 0, 0, 0 },
+ { 0, 0, 0, 0, 0 },
+ { "not_eq", Token_not_eq, 0, 0, &keywordEntries[102] },
+ { 0, 0, 0, 0, 0 },
+ { "static", Token_static, 0, 0, 0 },
+ { 0, 0, 0, 0, 0 },
+ { "throw", Token_throw, 0, 0, 0 },
+ { "slots", Token_slots, 0, 0, &keywordEntries[87] },
+ { 0, 0, 0, 0, 0 },
+ { 0, 0, 0, 0, 0 },
+ { "static_cast", Token_static_cast, 0, 0, &keywordEntries[115] },
+ { "default", Token_default, 0, 0, &keywordEntries[95] },
+ { "sizeof", Token_sizeof, 0, 0, 0 },
+ { 0, 0, 0, 0, 0 },
+ { "switch", Token_switch, 0, 0, 0 },
+ { 0, 0, 0, 0, 0 },
+ { "mutable", Token_mutable, 0, 0, 0 },
+ { "dynamic_cast", Token_dynamic_cast, 0, 0, 0 },
+ { "extern", Token_extern, 0, 0, 0 },
+ { 0, 0, 0, 0, 0 },
+ { 0, 0, 0, 0, 0 },
+ { "asm", Token_asm, 0, 0, 0 },
+ { 0, 0, 0, 0, 0 },
+ { "signals", Token_signals, 0, 0, &keywordEntries[106] },
+ { 0, 0, 0, 0, 0 },
+ { 0, 0, 0, 0, 0 },
+ { "case", Token_case, 0, 0, 0 },
+ { "for", Token_for, 0, 0, 0 },
+ { "char", Token_char, 0, 0, &keywordEntries[101] },
+ { 0, 0, 0, 0, 0 },
+ { "export", Token_export, 0, 0, &keywordEntries[94] },
+ { "int", Token_int, 0, 0, 0 },
+ { 0, 0, 0, 0, 0 },
+ { "private", Token_private, 0, 0, &keywordEntries[103] },
+ { 0, 0, 0, 0, 0 },
+ { 0, 0, 0, 0, 0 },
+ { 0, 0, 0, 0, 0 },
+ { "not", Token_not, 0, 0, 0 },
+ { 0, 0, 0, 0, 0 },
+ { "else", Token_else, 0, 0, &keywordEntries[93] },
+ { 0, 0, 0, 0, 0 },
+ { 0, 0, 0, 0, 0 },
+ { "bool", Token_bool, 0, 0, 0 },
+ { "catch", Token_catch, 0, 0, 0 },
+ { "__asm__", Token_asm, 0, 0, 0 },
+ { "and", Token_and, 0, 0, 0 },
+ { "break", Token_break, 0, 0, &keywordEntries[110] },
+ { "delete", Token_delete, 0, 0, 0 },
+ { "float", Token_float, 0, 0, &keywordEntries[96] },
+ { "goto", Token_goto, 0, 0, 0 },
+ { "if", Token_if, 0, 0, 0 },
+ { "namespace", Token_namespace, 0, 0, 0 },
+ { "new", Token_new, 0, 0, 0 },
+ { "or", Token_or, 0, 0, &keywordEntries[107] },
+ { "or_eq", Token_or_eq, 0, 0, 0 },
+ { "protected", Token_protected, 0, 0, 0 },
+ { "public", Token_public, 0, 0, &keywordEntries[109] },
+ { "register", Token_register, 0, 0, 0 },
+ { "reinterpret_cast", Token_reinterpret_cast, 0, 0, 0 },
+ { "return", Token_return, 0, 0, 0 },
+ { "short", Token_short, 0, 0, 0 },
+ { "struct", Token_struct, 0, 0, 0 },
+ { "this", Token_this, 0, 0, 0 },
+ { "try", Token_try, 0, 0, &keywordEntries[108] },
+ { "typedef", Token_typedef, 0, 0, 0 },
+ { "typeid", Token_typeid, 0, 0, 0 },
+ { "typename", Token_typename, 0, 0, 0 },
+ { "union", Token_union, 0, 0, 0 },
+ { "unsigned", Token_unsigned, 0, 0, &keywordEntries[112] },
+ { "using", Token_using, 0, 0, 0 },
+ { "virtual", Token_virtual, 0, 0, &keywordEntries[114] },
+ { "volatile", Token_volatile, 0, 0, 0 },
+ { "xor", Token_xor, 0, 0, 0 },
+ { "xor_eq", Token_xor_eq, 0, 0, 0 }
+};
+
+static const struct HashTable keyword = { 2, 116, keywordEntries, 86 };
diff --git a/umbrello/umbrello/codeimport/kdevcppparser/lexer.cpp b/umbrello/umbrello/codeimport/kdevcppparser/lexer.cpp
new file mode 100644
index 00000000..2748688f
--- /dev/null
+++ b/umbrello/umbrello/codeimport/kdevcppparser/lexer.cpp
@@ -0,0 +1,1002 @@
+/* This file is part of KDevelop
+ Copyright (C) 2002,2003 Roberto Raggi <roberto@kdevelop.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.
+*/
+
+#include "lexer.h"
+#include "lookup.h"
+#include "keywords.lut.h"
+
+#include <kdebug.h>
+#include <klocale.h>
+
+#include <qregexp.h>
+#include <qmap.h>
+#include <qvaluelist.h>
+
+#if defined( KDEVELOP_BGPARSER )
+#include <qthread.h>
+
+class KDevTread: public QThread
+{
+public:
+ static void yield()
+ {
+ msleep( 0 );
+ }
+};
+
+inline void qthread_yield()
+{
+ KDevTread::yield();
+}
+
+#endif
+
+#define CREATE_TOKEN(type, start, len) Token( (type), (start), (len), m_source )
+#define ADD_TOKEN(tk) m_tokens.insert( m_size++, new Token(tk) );
+
+using namespace std;
+
+struct LexerData
+{
+ typedef QMap<QString, QString> Scope;
+ typedef QValueList<Scope> StaticChain;
+
+ StaticChain staticChain;
+
+ void beginScope()
+ {
+ Scope scope;
+ staticChain.push_front( scope );
+ }
+
+ void endScope()
+ {
+ staticChain.pop_front();
+ }
+
+ void bind( const QString& name, const QString& value )
+ {
+ Q_ASSERT( staticChain.size() > 0 );
+ staticChain.front().insert( name, value );
+ }
+
+ bool hasBind( const QString& name ) const
+ {
+ StaticChain::ConstIterator it = staticChain.begin();
+ while( it != staticChain.end() ){
+ const Scope& scope = *it;
+ ++it;
+
+ if( scope.contains(name) )
+ return true;
+ }
+
+ return false;
+ }
+
+ QString apply( const QString& name ) const
+ {
+ StaticChain::ConstIterator it = staticChain.begin();
+ while( it != staticChain.end() ){
+ const Scope& scope = *it;
+ ++it;
+
+ if( scope.contains(name) )
+ return scope[ name ];
+ }
+
+ return QString::null;
+ }
+
+};
+
+Lexer::Lexer( Driver* driver )
+ : d( new LexerData),
+ m_driver( driver ),
+ m_recordComments( false ),
+ m_recordWhiteSpaces( false ),
+ m_skipWordsEnabled( true ),
+ m_preprocessorEnabled( true ),
+ m_reportWarnings( false ),
+ m_reportMessages( false )
+{
+ m_tokens.setAutoDelete( true );
+ reset();
+ d->beginScope();
+}
+
+Lexer::~Lexer()
+{
+ d->endScope();
+ delete( d );
+}
+
+void Lexer::setSource( const QString& source )
+{
+ reset();
+ m_source = source;
+ m_ptr = 0;
+ m_endPtr = m_source.length();
+ m_inPreproc = false;
+
+ tokenize();
+}
+
+void Lexer::reset()
+{
+ m_index = 0;
+ m_size = 0;
+ m_tokens.clear();
+ m_source = QString::null;
+ m_ptr = 0;
+ m_endPtr = 0;
+ m_startLine = false;
+ m_ifLevel = 0;
+ m_skipping.resize( 200 );
+ m_skipping.fill( 0 );
+ m_trueTest.resize( 200 );
+ m_trueTest.fill( 0 );
+
+ m_currentLine = 0;
+ m_currentColumn = 0;
+}
+
+// ### should all be done with a "long" type IMO
+int Lexer::toInt( const Token& token )
+{
+ QString s = token.text();
+ if( token.type() == Token_number_literal ){
+ // hex literal ?
+ if( s[0] == '0' && (s[1] == 'x' || s[1] == 'X'))
+ return s.mid( 2 ).toInt( 0, 16 );
+ QString n;
+ int i = 0;
+ while( i < int(s.length()) && s[i].isDigit() )
+ n += s[i++];
+ // ### respect more prefixes and suffixes ?
+ return n.toInt();
+ } else if( token.type() == Token_char_literal ){
+ int i = s[0] == 'L' ? 2 : 1; // wide char ?
+ if( s[i] == '\\' ){
+ // escaped char
+ int c = s[i+1].unicode();
+ switch( c ) {
+ case '0':
+ return 0;
+ case 'n':
+ return '\n';
+ // ### more
+ default:
+ return c;
+ }
+ } else {
+ return s[i].unicode();
+ }
+ } else {
+ return 0;
+ }
+}
+
+void Lexer::getTokenPosition( const Token& token, int* line, int* col )
+{
+ token.getStartPosition( line, col );
+}
+
+void Lexer::nextToken( Token& tk, bool stopOnNewline )
+{
+ int op = 0;
+
+ if( m_size == (int)m_tokens.size() ){
+ m_tokens.resize( m_tokens.size() + 5000 );
+ }
+
+ readWhiteSpaces( !stopOnNewline );
+
+ int startLine = m_currentLine;
+ int startColumn = m_currentColumn;
+
+ QChar ch = currentChar();
+ QChar ch1 = peekChar();
+
+ if( ch.isNull() || ch.isSpace() ){
+ /* skip */
+ } else if( m_startLine && ch == '#' ){
+
+ nextChar(); // skip #
+ readWhiteSpaces( false ); // skip white spaces
+ m_startLine = false;
+
+ int start = currentPosition();
+ readIdentifier(); // read the directive
+ QString directive = m_source.mid( start, currentPosition() - start );
+
+ handleDirective( directive );
+ } else if( m_startLine && m_skipping[ m_ifLevel ] ){
+ // skip line and continue
+ m_startLine = false;
+ int ppe = preprocessorEnabled();
+ setPreprocessorEnabled( false );
+ while( currentChar() && currentChar() != '\n' ){
+ Token tok;
+ nextToken( tok, true );
+ }
+ m_startLine = true;
+ setPreprocessorEnabled( ppe );
+ return;
+ } else if( ch == '/' && ch1 == '/' ){
+ int start = currentPosition();
+ readLineComment();
+ if( recordComments() ){
+ tk = CREATE_TOKEN( Token_comment, start, currentPosition() - start );
+ tk.setStartPosition( startLine, startColumn );
+ tk.setEndPosition( m_currentLine, m_currentColumn );
+ }
+ } else if( ch == '/' && ch1 == '*' ){
+ int start = currentPosition();
+ nextChar( 2 );
+ readMultiLineComment();
+
+ if( recordComments() ){
+ tk = CREATE_TOKEN( Token_comment, start, currentPosition() - start );
+ tk.setStartPosition( startLine, startColumn );
+ tk.setEndPosition( m_currentLine, m_currentColumn );
+ }
+ } else if( ch == '\'' || (ch == 'L' && ch1 == '\'') ){
+ int start = currentPosition();
+ readCharLiteral();
+ tk = CREATE_TOKEN( Token_char_literal, start, currentPosition() - start );
+ tk.setStartPosition( startLine, startColumn );
+ tk.setEndPosition( m_currentLine, m_currentColumn );
+ } else if( ch == '"' ){
+ int start = currentPosition();
+ readStringLiteral();
+ tk = CREATE_TOKEN( Token_string_literal, start, currentPosition() - start );
+ tk.setStartPosition( startLine, startColumn );
+ tk.setEndPosition( m_currentLine, m_currentColumn );
+ } else if( ch.isLetter() || ch == '_' ){
+ int start = currentPosition();
+ readIdentifier();
+ QString ide = m_source.mid( start, currentPosition() - start );
+ int k = Lookup::find( &keyword, ide );
+ if( m_preprocessorEnabled && m_driver->hasMacro(ide) &&
+ (k == -1 || !m_driver->macro(ide).body().isEmpty()) ){
+
+
+ bool preproc = m_preprocessorEnabled;
+ m_preprocessorEnabled = false;
+
+ d->beginScope();
+
+ int svLine = currentLine();
+ int svColumn = currentColumn();
+
+// Macro& m = m_driver->macro( ide );
+ Macro m = m_driver->macro( ide );
+ //m_driver->removeMacro( m.name() );
+
+ QString ellipsisArg;
+
+ if( m.hasArguments() ){
+ int endIde = currentPosition();
+
+ readWhiteSpaces();
+ if( currentChar() == '(' ){
+ nextChar();
+ int argIdx = 0;
+ int argCount = m.argumentList().size();
+ while( currentChar() && argIdx<argCount ){
+ readWhiteSpaces();
+
+ QString argName = m.argumentList()[ argIdx ];
+
+ bool ellipsis = argName == "...";
+
+ QString arg = readArgument();
+
+ if( !ellipsis )
+ d->bind( argName, arg );
+ else
+ ellipsisArg += arg;
+
+ if( currentChar() == ',' ){
+ nextChar();
+ if( !ellipsis ){
+ ++argIdx;
+ } else {
+ ellipsisArg += ", ";
+ }
+ } else if( currentChar() == ')' ){
+ break;
+ }
+ }
+ if( currentChar() == ')' ){
+ // valid macro
+ nextChar();
+ }
+ } else {
+ tk = CREATE_TOKEN( Token_identifier, start, endIde - start );
+ tk.setStartPosition( svLine, svColumn );
+ tk.setEndPosition( svLine, svColumn + (endIde - start) );
+
+ m_startLine = false;
+
+ d->endScope(); // OPS!!
+ m_preprocessorEnabled = preproc;
+ return;
+ }
+ }
+
+ int argsEndAtLine = currentLine();
+ int argsEndAtColumn = currentColumn();
+
+#if defined( KDEVELOP_BGPARSER )
+ qthread_yield();
+#endif
+ m_source.insert( currentPosition(), m.body() );
+
+ // tokenize the macro body
+
+ QString textToInsert;
+
+ m_endPtr = currentPosition() + m.body().length();
+ while( currentChar() ){
+
+ readWhiteSpaces();
+
+ Token tok;
+ nextToken( tok );
+
+ bool stringify = !m_inPreproc && tok == '#';
+ bool merge = !m_inPreproc && tok == Token_concat;
+
+ if( stringify || merge )
+ nextToken( tok );
+
+ if( tok == Token_eof )
+ break;
+
+ QString tokText = tok.text();
+ QString str = (tok == Token_identifier && d->hasBind(tokText)) ? d->apply( tokText ) : tokText;
+ if( str == ide ){
+ //Problem p( i18n("unsafe use of macro '%1'").arg(ide), m_currentLine, m_currentColumn );
+ //m_driver->addProblem( m_driver->currentFileName(), p );
+ m_driver->removeMacro( ide );
+ // str = QString::null;
+ }
+
+ if( stringify ) {
+ textToInsert.append( QString::fromLatin1("\"") + str + QString::fromLatin1("\" ") );
+ } else if( merge ){
+ textToInsert.truncate( textToInsert.length() - 1 );
+ textToInsert.append( str );
+ } else if( tok == Token_ellipsis && d->hasBind("...") ){
+ textToInsert.append( ellipsisArg );
+ } else {
+ textToInsert.append( str + QString::fromLatin1(" ") );
+ }
+ }
+
+#if defined( KDEVELOP_BGPARSER )
+ qthread_yield();
+#endif
+ m_source.insert( currentPosition(), textToInsert );
+
+ d->endScope();
+ m_preprocessorEnabled = preproc;
+ //m_driver->addMacro( m );
+ m_currentLine = argsEndAtLine;
+ m_currentColumn = argsEndAtColumn;
+ m_endPtr = m_source.length();
+ } else if( k != -1 ){
+ tk = CREATE_TOKEN( k, start, currentPosition() - start );
+ tk.setStartPosition( startLine, startColumn );
+ tk.setEndPosition( m_currentLine, m_currentColumn );
+ } else if( m_skipWordsEnabled ){
+ QMap< QString, QPair<SkipType, QString> >::Iterator pos = m_words.find( ide );
+ if( pos != m_words.end() ){
+ if( (*pos).first == SkipWordAndArguments ){
+ readWhiteSpaces();
+ if( currentChar() == '(' )
+ skip( '(', ')' );
+ }
+ if( !(*pos).second.isEmpty() ){
+#if defined( KDEVELOP_BGPARSER )
+ qthread_yield();
+#endif
+ m_source.insert( currentPosition(), QString(" ") + (*pos).second + QString(" ") );
+ m_endPtr = m_source.length();
+ }
+ } else if( /*qt_rx.exactMatch(ide) ||*/
+ ide.endsWith("EXPORT") ||
+ (ide.startsWith("Q_EXPORT") && ide != "Q_EXPORT_INTERFACE") ||
+ ide.startsWith("QM_EXPORT") ||
+ ide.startsWith("QM_TEMPLATE")){
+
+ readWhiteSpaces();
+ if( currentChar() == '(' )
+ skip( '(', ')' );
+ } else if( ide.startsWith("K_TYPELIST_") || ide.startsWith("TYPELIST_") ){
+ tk = CREATE_TOKEN( Token_identifier, start, currentPosition() - start );
+ tk.setStartPosition( startLine, startColumn );
+ tk.setEndPosition( m_currentLine, m_currentColumn );
+ readWhiteSpaces();
+ if( currentChar() == '(' )
+ skip( '(', ')' );
+ } else{
+ tk = CREATE_TOKEN( Token_identifier, start, currentPosition() - start );
+ tk.setStartPosition( startLine, startColumn );
+ tk.setEndPosition( m_currentLine, m_currentColumn );
+ }
+ } else {
+ tk = CREATE_TOKEN( Token_identifier, start, currentPosition() - start );
+ tk.setStartPosition( startLine, startColumn );
+ tk.setEndPosition( m_currentLine, m_currentColumn );
+ }
+ } else if( ch.isNumber() ){
+ int start = currentPosition();
+ readNumberLiteral();
+ tk = CREATE_TOKEN( Token_number_literal, start, currentPosition() - start );
+ tk.setStartPosition( startLine, startColumn );
+ tk.setEndPosition( m_currentLine, m_currentColumn );
+ } else if( -1 != (op = findOperator3()) ){
+ tk = CREATE_TOKEN( op, currentPosition(), 3 );
+ nextChar( 3 );
+ tk.setStartPosition( startLine, startColumn );
+ tk.setEndPosition( m_currentLine, m_currentColumn );
+ } else if( -1 != (op = findOperator2()) ){
+ tk = CREATE_TOKEN( op, currentPosition(), 2 );
+ nextChar( 2 );
+ tk.setStartPosition( startLine, startColumn );
+ tk.setEndPosition( m_currentLine, m_currentColumn );
+ } else {
+ tk = CREATE_TOKEN( ch.unicode(), currentPosition(), 1 );
+ nextChar();
+ tk.setStartPosition( startLine, startColumn );
+ tk.setEndPosition( m_currentLine, m_currentColumn );
+ }
+
+ m_startLine = false;
+}
+
+
+void Lexer::tokenize()
+{
+ m_startLine = true;
+ m_size = 0;
+
+ for( ;; ) {
+ Token tk;
+ nextToken( tk );
+
+ if( tk.type() != -1 )
+ ADD_TOKEN( tk );
+
+ if( currentChar().isNull() )
+ break;
+ }
+
+ Token tk = CREATE_TOKEN( Token_eof, currentPosition(), 0 );
+ tk.setStartPosition( m_currentLine, m_currentColumn );
+ tk.setEndPosition( m_currentLine, m_currentColumn );
+ ADD_TOKEN( tk );
+}
+
+void Lexer::resetSkipWords()
+{
+ m_words.clear();
+}
+
+void Lexer::addSkipWord( const QString& word, SkipType skipType, const QString& str )
+{
+ m_words[ word ] = qMakePair( skipType, str );
+}
+
+void Lexer::skip( int l, int r )
+{
+ int svCurrentLine = m_currentLine;
+ int svCurrentColumn = m_currentColumn;
+
+ int count = 0;
+
+ while( !eof() ){
+ Token tk;
+ nextToken( tk );
+
+ if( (int)tk == l )
+ ++count;
+ else if( (int)tk == r )
+ --count;
+
+ if( count == 0 )
+ break;
+ }
+
+ m_currentLine = svCurrentLine;
+ m_currentColumn = svCurrentColumn;
+}
+
+QString Lexer::readArgument()
+{
+ int count = 0;
+
+ QString arg;
+
+ readWhiteSpaces();
+ while( currentChar() ){
+
+ readWhiteSpaces();
+ QChar ch = currentChar();
+
+ if( ch.isNull() || (!count && (ch == ',' || ch == ')')) )
+ break;
+
+ Token tk;
+ nextToken( tk );
+
+ if( tk == '(' ){
+ ++count;
+ } else if( tk == ')' ){
+ --count;
+ }
+
+ if( tk != -1 )
+ arg += tk.text() + ' ';
+ }
+
+ return arg.stripWhiteSpace();
+}
+
+void Lexer::handleDirective( const QString& directive )
+{
+ m_inPreproc = true;
+
+ bool skip = skipWordsEnabled();
+ bool preproc = preprocessorEnabled();
+
+ setSkipWordsEnabled( false );
+ setPreprocessorEnabled( false );
+
+ if( directive == "define" ){
+ if( !m_skipping[ m_ifLevel ] ){
+ Macro m;
+ processDefine( m );
+ }
+ } else if( directive == "else" ){
+ processElse();
+ } else if( directive == "elif" ){
+ processElif();
+ } else if( directive == "endif" ){
+ processEndif();
+ } else if( directive == "if" ){
+ processIf();
+ } else if( directive == "ifdef" ){
+ processIfdef();
+ } else if( directive == "ifndef" ){
+ processIfndef();
+ } else if( directive == "include" ){
+ if( !m_skipping[ m_ifLevel ] ){
+ processInclude();
+ }
+ } else if( directive == "undef" ){
+ if( !m_skipping[ m_ifLevel ] ){
+ processUndef();
+ }
+ }
+
+ // skip line
+ while( currentChar() && currentChar() != '\n' ){
+ Token tk;
+ nextToken( tk, true );
+ }
+
+ setSkipWordsEnabled( skip );
+ setPreprocessorEnabled( preproc );
+
+ m_inPreproc = false;
+}
+
+int Lexer::testIfLevel()
+{
+ int rtn = !m_skipping[ m_ifLevel++ ];
+ m_skipping[ m_ifLevel ] = m_skipping[ m_ifLevel - 1 ];
+ return rtn;
+}
+
+int Lexer::macroDefined()
+{
+ readWhiteSpaces( false );
+ int startWord = currentPosition();
+ readIdentifier();
+ QString word = m_source.mid( startWord, currentPosition() - startWord );
+ bool r = m_driver->hasMacro( word );
+
+ return r;
+}
+
+void Lexer::processDefine( Macro& m )
+{
+ m.setFileName( m_driver->currentFileName() );
+ readWhiteSpaces( false );
+
+ int startMacroName = currentPosition();
+ readIdentifier();
+ QString macroName = m_source.mid( startMacroName, int(currentPosition()-startMacroName) );
+ m_driver->removeMacro( macroName );
+ m.setName( macroName );
+
+ if( currentChar() == '(' ){
+ m.setHasArguments( true );
+ nextChar();
+
+ readWhiteSpaces( false );
+
+ while( currentChar() && currentChar() != ')' ){
+ readWhiteSpaces( false );
+
+ int startArg = currentPosition();
+
+ if( currentChar() == '.' && peekChar() == '.' && peekChar(2) == '.' )
+ nextChar( 3 );
+ else
+ readIdentifier();
+
+ QString arg = m_source.mid( startArg, int(currentPosition()-startArg) );
+
+ m.addArgument( Macro::Argument(arg) );
+
+ readWhiteSpaces( false );
+ if( currentChar() != ',' )
+ break;
+
+ nextChar(); // skip ','
+ }
+
+ if( currentChar() == ')' )
+ nextChar(); // skip ')'
+ }
+
+ setPreprocessorEnabled( true );
+
+ QString body;
+ while( currentChar() && currentChar() != '\n' ){
+
+ if( currentChar().isSpace() ){
+ readWhiteSpaces( false );
+ body += ' ';
+ } else {
+
+ Token tk;
+ nextToken( tk, true );
+
+ if( tk.type() != -1 ){
+ QString s = tk.text();
+ body += s;
+ }
+ }
+ }
+
+ m.setBody( body );
+ m_driver->addMacro( m );
+}
+
+void Lexer::processElse()
+{
+ if( m_ifLevel == 0 )
+ /// @todo report error
+ return;
+
+ if( m_ifLevel > 0 && m_skipping[m_ifLevel-1] )
+ m_skipping[ m_ifLevel ] = m_skipping[ m_ifLevel - 1 ];
+ else
+ m_skipping[ m_ifLevel ] = m_trueTest[ m_ifLevel ];
+}
+
+void Lexer::processElif()
+{
+ if( m_ifLevel == 0 )
+ /// @todo report error
+ return;
+
+ if( !m_trueTest[m_ifLevel] ){
+ /// @todo implement the correct semantic for elif!!
+ bool inSkip = m_ifLevel > 0 && m_skipping[ m_ifLevel-1 ];
+ m_trueTest[ m_ifLevel ] = macroExpression() != 0;
+ m_skipping[ m_ifLevel ] = inSkip ? inSkip : !m_trueTest[ m_ifLevel ];
+ }
+ else
+ m_skipping[ m_ifLevel ] = true;
+}
+
+void Lexer::processEndif()
+{
+ if( m_ifLevel == 0 )
+ /// @todo report error
+ return;
+
+ m_skipping[ m_ifLevel ] = 0;
+ m_trueTest[ m_ifLevel-- ] = 0;
+}
+
+void Lexer::processIf()
+{
+ bool inSkip = m_skipping[ m_ifLevel ];
+
+ if( testIfLevel() ) {
+#if 0
+ int n;
+ if( (n = testDefined()) != 0 ) {
+ int isdef = macroDefined();
+ m_trueTest[ m_ifLevel ] = (n == 1 && isdef) || (n == -1 && !isdef);
+ } else
+#endif
+ m_trueTest[ m_ifLevel ] = macroExpression() != 0;
+ m_skipping[ m_ifLevel ] = inSkip ? inSkip : !m_trueTest[ m_ifLevel ];
+ }
+}
+
+void Lexer::processIfdef()
+{
+ bool inSkip = m_skipping[ m_ifLevel ];
+
+ if( testIfLevel() ){
+ m_trueTest[ m_ifLevel ] = macroDefined();
+ m_skipping[ m_ifLevel ] = inSkip ? inSkip : !m_trueTest[ m_ifLevel ];
+ }
+}
+
+void Lexer::processIfndef()
+{
+ bool inSkip = m_skipping[ m_ifLevel ];
+
+ if( testIfLevel() ){
+ m_trueTest[ m_ifLevel ] = !macroDefined();
+ m_skipping[ m_ifLevel ] = inSkip ? inSkip : !m_trueTest[ m_ifLevel ];
+ }
+}
+
+void Lexer::processInclude()
+{
+ if( m_skipping[m_ifLevel] )
+ return;
+
+ readWhiteSpaces( false );
+ if( currentChar() ){
+ QChar ch = currentChar();
+ if( ch == '"' || ch == '<' ){
+ nextChar();
+ QChar ch2 = ch == QChar('"') ? QChar('"') : QChar('>');
+
+ int startWord = currentPosition();
+ while( currentChar() && currentChar() != ch2 )
+ nextChar();
+ if( currentChar() ){
+ QString word = m_source.mid( startWord, int(currentPosition()-startWord) );
+ m_driver->addDependence( m_driver->currentFileName(),
+ Dependence(word, ch == '"' ? Dep_Local : Dep_Global) );
+ nextChar();
+ }
+ }
+ }
+}
+
+void Lexer::processUndef()
+{
+ readWhiteSpaces();
+ int startWord = currentPosition();
+ readIdentifier();
+ QString word = m_source.mid( startWord, currentPosition() - startWord );
+ m_driver->removeMacro( word );
+}
+
+int Lexer::macroPrimary()
+{
+ readWhiteSpaces( false );
+ int result = 0;
+ switch( currentChar().unicode() ) {
+ case '(':
+ nextChar();
+ result = macroExpression();
+ if( currentChar() != ')' ){
+ /// @todo report error
+ return 0;
+ }
+ nextChar();
+ return result;
+
+ case '+':
+ case '-':
+ case '!':
+ case '~':
+ {
+ QChar tk = currentChar();
+ nextChar();
+ int result = macroPrimary();
+ if( tk == '-' ) return -result;
+ else if( tk == '!' ) return !result;
+ else if( tk == '~' ) return ~result;
+ }
+ break;
+
+ default:
+ {
+ Token tk;
+ nextToken( tk, false );
+ switch( tk.type() ){
+ case Token_identifier:
+ if( tk.text() == "defined" ){
+ return macroPrimary();
+ }
+ /// @todo implement
+ return m_driver->hasMacro( tk.text() );
+ case Token_number_literal:
+ case Token_char_literal:
+ return toInt( tk );
+ default:
+ break;
+ } // end switch
+
+ } // end default
+
+ } // end switch
+
+ return 0;
+}
+
+int Lexer::macroMultiplyDivide()
+{
+ int result = macroPrimary();
+ int iresult, op;
+ for (;;) {
+ readWhiteSpaces( false );
+ if( currentChar() == '*' )
+ op = 0;
+ else if( currentChar() == '/' && !(peekChar() == '*' || peekChar() == '/') )
+ op = 1;
+ else if( currentChar() == '%' )
+ op = 2;
+ else
+ break;
+ nextChar();
+ iresult = macroPrimary();
+ result = op == 0 ? (result * iresult) :
+ op == 1 ? (iresult == 0 ? 0 : (result / iresult)) :
+ (iresult == 0 ? 0 : (result % iresult)) ;
+ }
+ return result;
+}
+
+int Lexer::macroAddSubtract()
+{
+ int result = macroMultiplyDivide();
+ int iresult, ad;
+ readWhiteSpaces( false );
+ while( currentChar() == '+' || currentChar() == '-') {
+ ad = currentChar() == '+';
+ nextChar();
+ iresult = macroMultiplyDivide();
+ result = ad ? (result+iresult) : (result-iresult);
+ }
+ return result;
+}
+
+int Lexer::macroRelational()
+{
+ int result = macroAddSubtract();
+ int iresult;
+ readWhiteSpaces( false );
+ while( currentChar() == '<' || currentChar() == '>') {
+ int lt = currentChar() == '<';
+ nextChar();
+ if( currentChar() == '=') {
+ nextChar();
+
+ iresult = macroAddSubtract();
+ result = lt ? (result <= iresult) : (result >= iresult);
+ }
+ else {
+ iresult = macroAddSubtract();
+ result = lt ? (result < iresult) : (result > iresult);
+ }
+ }
+
+ return result;
+}
+
+int Lexer::macroEquality()
+{
+ int result = macroRelational();
+ int iresult, eq;
+ readWhiteSpaces( false );
+ while ((currentChar() == '=' || currentChar() == '!') && peekChar() == '=') {
+ eq = currentChar() == '=';
+ nextChar( 2 );
+ iresult = macroRelational();
+ result = eq ? (result==iresult) : (result!=iresult);
+ }
+ return result;
+}
+
+int Lexer::macroBoolAnd()
+{
+ int result = macroEquality();
+ readWhiteSpaces( false );
+ while( currentChar() == '&' && peekChar() != '&') {
+ nextChar();
+ result &= macroEquality();
+ }
+ return result;
+}
+
+int Lexer::macroBoolXor()
+{
+ int result = macroBoolAnd();
+ readWhiteSpaces( false );
+ while( currentChar() == '^') {
+ nextChar();
+ result ^= macroBoolAnd();
+ }
+ return result;
+}
+
+int Lexer::macroBoolOr()
+{
+ int result = macroBoolXor();
+ readWhiteSpaces( false );
+ while( currentChar() == '|' && peekChar() != '|') {
+ nextChar();
+ result |= macroBoolXor();
+ }
+ return result;
+}
+
+int Lexer::macroLogicalAnd()
+{
+ int result = macroBoolOr();
+ readWhiteSpaces( false );
+ while( currentChar() == '&' && peekChar() == '&') {
+ nextChar( 2 );
+ int start = currentPosition();
+ result = macroBoolOr() && result;
+ QString s = m_source.mid( start, currentPosition() - start );
+ }
+ return result;
+}
+
+int Lexer::macroLogicalOr()
+{
+ int result = macroLogicalAnd();
+ readWhiteSpaces( false );
+ while( currentChar() == '|' && peekChar() == '|') {
+ nextChar( 2 );
+ result = macroLogicalAnd() || result;
+ }
+ return result;
+}
+
+int Lexer::macroExpression()
+{
+ readWhiteSpaces( false );
+ return macroLogicalOr();
+}
+
+// *IMPORTANT*
+// please, don't include lexer.moc here, because Lexer isn't a QObject class!!
+// if you have problem while recompiling try to remove cppsupport/.deps,
+// cppsupport/Makefile.in and rerun automake/autoconf
+
diff --git a/umbrello/umbrello/codeimport/kdevcppparser/lexer.h b/umbrello/umbrello/codeimport/kdevcppparser/lexer.h
new file mode 100644
index 00000000..cce951d4
--- /dev/null
+++ b/umbrello/umbrello/codeimport/kdevcppparser/lexer.h
@@ -0,0 +1,791 @@
+/* This file is part of KDevelop
+ Copyright (C) 2002,2003 Roberto Raggi <roberto@kdevelop.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 LEXER_H
+#define LEXER_H
+
+#include "driver.h"
+
+#include <qstring.h>
+#include <qmap.h>
+#include <qvaluestack.h>
+#include <qpair.h>
+#include <qptrvector.h>
+
+enum Type {
+ Token_eof = 0,
+ Token_identifier = 1000,
+ Token_number_literal,
+ Token_char_literal,
+ Token_string_literal,
+ Token_whitespaces,
+ Token_comment,
+ Token_preproc,
+
+ Token_assign = 2000,
+ Token_ptrmem,
+ Token_ellipsis,
+ Token_scope,
+ Token_shift,
+ Token_eq,
+ Token_leq,
+ Token_geq,
+ Token_incr,
+ Token_decr,
+ Token_arrow,
+
+ Token_concat,
+
+ Token_K_DCOP,
+ Token_k_dcop,
+ Token_k_dcop_signals,
+
+ Token_Q_OBJECT,
+ Token_signals,
+ Token_slots,
+ Token_emit,
+
+ Token_and,
+ Token_and_eq,
+ Token_asm,
+ Token_auto,
+ Token_bitand,
+ Token_bitor,
+ Token_bool,
+ Token_break,
+ Token_case,
+ Token_catch,
+ Token_char,
+ Token_class,
+ Token_compl,
+ Token_const,
+ Token_const_cast,
+ Token_continue,
+ Token_default,
+ Token_delete,
+ Token_do,
+ Token_double,
+ Token_dynamic_cast,
+ Token_else,
+ Token_enum,
+ Token_explicit,
+ Token_export,
+ Token_extern,
+ Token_false,
+ Token_float,
+ Token_for,
+ Token_friend,
+ Token_goto,
+ Token_if,
+ Token_inline,
+ Token_int,
+ Token_long,
+ Token_mutable,
+ Token_namespace,
+ Token_new,
+ Token_not,
+ Token_not_eq,
+ Token_operator,
+ Token_or,
+ Token_or_eq,
+ Token_private,
+ Token_protected,
+ Token_public,
+ Token_register,
+ Token_reinterpret_cast,
+ Token_return,
+ Token_short,
+ Token_signed,
+ Token_sizeof,
+ Token_static,
+ Token_static_cast,
+ Token_struct,
+ Token_switch,
+ Token_template,
+ Token_this,
+ Token_throw,
+ Token_true,
+ Token_try,
+ Token_typedef,
+ Token_typeid,
+ Token_typename,
+ Token_union,
+ Token_unsigned,
+ Token_using,
+ Token_virtual,
+ Token_void,
+ Token_volatile,
+ Token_wchar_t,
+ Token_while,
+ Token_xor,
+ Token_xor_eq
+};
+
+enum SkipType {
+ SkipWord,
+ SkipWordAndArguments
+};
+
+struct LexerData;
+
+class Token
+{
+public:
+ Token();
+ Token( int type, int position, int length, const QString& text );
+ Token( const Token& source );
+
+ Token& operator = ( const Token& source );
+ bool operator == ( const Token& token ) const;
+ operator int () const;
+
+ bool isNull() const;
+
+ int type() const;
+ void setType( int type );
+
+ void getStartPosition( int* line, int* column ) const;
+ void setStartPosition( int line, int column );
+ void getEndPosition( int* line, int* column ) const;
+ void setEndPosition( int line, int column );
+
+ unsigned int length() const;
+ void setLength( unsigned int length );
+
+ int position() const;
+ void setPosition( int position );
+
+ QString text() const;
+
+private:
+ int m_type;
+ int m_position;
+ int m_length;
+ int m_startLine;
+ int m_startColumn;
+ int m_endLine;
+ int m_endColumn;
+ QString m_text;
+
+ friend class Lexer;
+ friend class Parser;
+}; // class Token
+
+class Lexer
+{
+public:
+ Lexer( Driver* driver );
+ ~Lexer();
+
+ bool recordComments() const;
+ void setRecordComments( bool record );
+
+ bool recordWhiteSpaces() const;
+ void setRecordWhiteSpaces( bool record );
+
+ bool reportWarnings() const;
+ void setReportWarnings( bool enable );
+
+ bool reportMessages() const;
+ void setReportMessages( bool enable );
+
+ bool skipWordsEnabled() const;
+ void setSkipWordsEnabled( bool enabled );
+
+ bool preprocessorEnabled() const;
+ void setPreprocessorEnabled( bool enabled );
+
+ void resetSkipWords();
+ void addSkipWord( const QString& word, SkipType skipType=SkipWord, const QString& str = QString::null );
+
+ QString source() const;
+ void setSource( const QString& source );
+
+ int index() const;
+ void setIndex( int index );
+
+ void reset();
+
+ const Token& tokenAt( int position ) const;
+ const Token& nextToken();
+ const Token& lookAhead( int n ) const;
+
+ static int toInt( const Token& token );
+
+ int tokenPosition( const Token& token ) const;
+ void getTokenPosition( const Token& token, int* line, int* col );
+
+ int currentLine() const { return m_currentLine; }
+ int currentColumn() const { return m_currentColumn; }
+
+private:
+ QChar currentChar() const;
+ QChar peekChar( int n=1 ) const;
+ int currentPosition() const;
+
+ void tokenize();
+ void nextToken( Token& token, bool stopOnNewline=false );
+ void nextChar();
+ void nextChar( int n );
+ void skip( int l, int r );
+ void readIdentifier();
+ void readWhiteSpaces( bool skipNewLine=true );
+ void readLineComment();
+ void readMultiLineComment();
+ void readCharLiteral();
+ void readStringLiteral();
+ void readNumberLiteral();
+
+ int findOperator3() const;
+ int findOperator2() const;
+ bool eof() const;
+
+ // preprocessor (based on an article of Al Stevens on Dr.Dobb's journal)
+ int testIfLevel();
+ int macroDefined();
+ QString readArgument();
+
+ int macroPrimary();
+ int macroMultiplyDivide();
+ int macroAddSubtract();
+ int macroRelational();
+ int macroEquality();
+ int macroBoolAnd();
+ int macroBoolXor();
+ int macroBoolOr();
+ int macroLogicalAnd();
+ int macroLogicalOr();
+ int macroExpression();
+
+ void handleDirective( const QString& directive );
+ void processDefine( Macro& macro );
+ void processElse();
+ void processElif();
+ void processEndif();
+ void processIf();
+ void processIfdef();
+ void processIfndef();
+ void processInclude();
+ void processUndef();
+
+private:
+ LexerData* d;
+ Driver* m_driver;
+ QPtrVector< Token > m_tokens;
+ int m_size;
+ int m_index;
+ QString m_source;
+ int m_ptr;
+ int m_endPtr;
+ bool m_recordComments;
+ bool m_recordWhiteSpaces;
+ bool m_startLine;
+ QMap< QString, QPair<SkipType, QString> > m_words;
+
+ int m_currentLine;
+ int m_currentColumn;
+ bool m_skipWordsEnabled;
+
+ // preprocessor
+ QMemArray<bool> m_skipping;
+ QMemArray<bool> m_trueTest;
+ int m_ifLevel;
+ bool m_preprocessorEnabled;
+ bool m_inPreproc;
+
+ bool m_reportWarnings;
+ bool m_reportMessages;
+
+private:
+ Lexer( const Lexer& source );
+ void operator = ( const Lexer& source );
+};
+
+
+inline Token::Token()
+ : m_type( -1 ),
+ m_position( 0 ),
+ m_length( 0 ),
+ m_text( 0 )
+{
+}
+
+inline Token::Token( int type, int position, int length, const QString& text )
+ : m_type( type ),
+ m_position( position ),
+ m_length( length ),
+ m_text( text )
+{
+}
+
+inline Token::Token( const Token& source )
+ : m_type( source.m_type ),
+ m_position( source.m_position ),
+ m_length( source.m_length ),
+ m_startLine( source.m_startLine ),
+ m_startColumn( source.m_startColumn ),
+ m_endLine( source.m_endLine ),
+ m_endColumn( source.m_endColumn ),
+ m_text( source.m_text )
+{
+}
+
+inline Token& Token::operator = ( const Token& source )
+{
+ m_type = source.m_type;
+ m_position = source.m_position;
+ m_length = source.m_length;
+ m_startLine = source.m_startLine;
+ m_startColumn = source.m_startColumn;
+ m_endLine = source.m_endLine;
+ m_endColumn = source.m_endColumn;
+ m_text = source.m_text;
+ return( *this );
+}
+
+inline Token::operator int () const
+{
+ return m_type;
+}
+
+inline bool Token::operator == ( const Token& token ) const
+{
+ return m_type == token.m_type &&
+ m_position == token.m_position &&
+ m_length == token.m_length &&
+ m_startLine == token.m_startLine &&
+ m_startColumn == token.m_startColumn &&
+ m_endLine == token.m_endLine &&
+ m_endColumn == token.m_endColumn &&
+ m_text == token.m_text;
+}
+
+inline bool Token::isNull() const
+{
+ return m_type == Token_eof || m_length == 0;
+}
+
+inline int Token::type() const
+{
+ return m_type;
+}
+
+inline void Token::setType( int type )
+{
+ m_type = type;
+}
+
+inline int Token::position() const
+{
+ return m_position;
+}
+
+inline QString Token::text() const
+{
+ return m_text.mid(m_position, m_length);
+}
+
+inline void Token::setStartPosition( int line, int column )
+{
+ m_startLine = line;
+ m_startColumn = column;
+}
+
+inline void Token::setEndPosition( int line, int column )
+{
+ m_endLine = line;
+ m_endColumn = column;
+}
+
+inline void Token::getStartPosition( int* line, int* column ) const
+{
+ if( line ) *line = m_startLine;
+ if( column ) *column = m_startColumn;
+}
+
+inline void Token::getEndPosition( int* line, int* column ) const
+{
+ if( line ) *line = m_endLine;
+ if( column ) *column = m_endColumn;
+}
+
+inline void Token::setPosition( int position )
+{
+ m_position = position;
+}
+
+inline unsigned int Token::length() const
+{
+ return m_length;
+}
+
+inline void Token::setLength( unsigned int length )
+{
+ m_length = length;
+}
+
+inline bool Lexer::recordComments() const
+{
+ return m_recordComments;
+}
+
+inline void Lexer::setRecordComments( bool record )
+{
+ m_recordComments = record;
+}
+
+inline bool Lexer::recordWhiteSpaces() const
+{
+ return m_recordWhiteSpaces;
+}
+
+inline void Lexer::setRecordWhiteSpaces( bool record )
+{
+ m_recordWhiteSpaces = record;
+}
+
+inline QString Lexer::source() const
+{
+ return m_source;
+}
+
+inline int Lexer::index() const
+{
+ return m_index;
+}
+
+inline void Lexer::setIndex( int index )
+{
+ m_index = index;
+}
+
+inline const Token& Lexer::nextToken()
+{
+ if( m_index < m_size )
+ return *m_tokens[ m_index++ ];
+
+ return *m_tokens[ m_index ];
+}
+
+inline const Token& Lexer::tokenAt( int n ) const
+{
+ return *m_tokens[ QMIN(n, m_size-1) ];
+}
+
+inline const Token& Lexer::lookAhead( int n ) const
+{
+ return *m_tokens[ QMIN(m_index + n, m_size-1) ];
+}
+
+inline int Lexer::tokenPosition( const Token& token ) const
+{
+ return token.position();
+}
+
+inline void Lexer::nextChar()
+{
+ if(m_source[m_ptr++] == '\n') {
+ ++m_currentLine;
+ m_currentColumn = 0;
+ m_startLine = true;
+ } else {
+ ++m_currentColumn;
+ }
+}
+
+inline void Lexer::nextChar( int n )
+{
+ m_currentColumn += n;
+ m_ptr += n;
+}
+
+inline void Lexer::readIdentifier()
+{
+ while( currentChar().isLetterOrNumber() || currentChar() == '_' )
+ nextChar();
+}
+
+inline void Lexer::readWhiteSpaces( bool skipNewLine )
+{
+ while( !currentChar().isNull() ){
+ QChar ch = currentChar();
+
+ if( ch == '\n' && !skipNewLine ){
+ break;
+ } else if( ch.isSpace() ){
+ nextChar();
+ } else if( m_inPreproc && currentChar() == '\\' ){
+ nextChar();
+ readWhiteSpaces( true );
+ } else {
+ break;
+ }
+ }
+}
+
+inline void Lexer::readLineComment()
+{
+ while( !currentChar().isNull() && currentChar() != '\n' ){
+ if( m_reportMessages && currentChar() == '@' && m_source.mid(currentPosition()+1, 4).lower() == "todo" ){
+ nextChar( 5 );
+ QString msg;
+ int line = m_currentLine;
+ int col = m_currentColumn;
+
+ while( currentChar() ){
+ if( currentChar() == '*' && peekChar() == '/' )
+ break;
+ else if( currentChar() == '\n' )
+ break;
+
+ msg += currentChar();
+ nextChar();
+ }
+ m_driver->addProblem( m_driver->currentFileName(), Problem(msg, line, col, Problem::Level_Todo) );
+ } else
+ if( m_reportMessages && m_source.mid(currentPosition(), 5).lower() == "fixme" ){
+ nextChar( 5 );
+ QString msg;
+ int line = m_currentLine;
+ int col = m_currentColumn;
+
+ while( currentChar() ){
+ if( currentChar() == '*' && peekChar() == '/' )
+ break;
+ else if( currentChar() == '\n' )
+ break;
+
+ msg += currentChar();
+ nextChar();
+ }
+ m_driver->addProblem( m_driver->currentFileName(), Problem(msg, line, col, Problem::Level_Fixme) );
+ } else
+ nextChar();
+ }
+}
+
+inline void Lexer::readMultiLineComment()
+{
+ while( !currentChar().isNull() ){
+ if( currentChar() == '*' && peekChar() == '/' ){
+ nextChar( 2 );
+ return;
+ } else if( m_reportMessages && currentChar() == '@' && m_source.mid(currentPosition()+1, 4).lower() == "todo" ){
+ nextChar( 5 );
+ QString msg;
+ int line = m_currentLine;
+ int col = m_currentColumn;
+
+ while( currentChar() ){
+ if( currentChar() == '*' && peekChar() == '/' )
+ break;
+ else if( currentChar() == '\n' )
+ break;
+ msg += currentChar();
+ nextChar();
+ }
+ m_driver->addProblem( m_driver->currentFileName(), Problem(msg, line, col, Problem::Level_Todo) );
+ } else
+ if( m_reportMessages && m_source.mid(currentPosition(), 5).lower() == "fixme" ){
+ nextChar( 5 );
+ QString msg;
+ int line = m_currentLine;
+ int col = m_currentColumn;
+
+ while( currentChar() ){
+ if( currentChar() == '*' && peekChar() == '/' )
+ break;
+ else if( currentChar() == '\n' )
+ break;
+
+ msg += currentChar();
+ nextChar();
+ }
+ m_driver->addProblem( m_driver->currentFileName(), Problem(msg, line, col, Problem::Level_Fixme) );
+ } else
+ nextChar();
+ }
+}
+
+inline void Lexer::readCharLiteral()
+{
+ if( currentChar() == '\'' )
+ nextChar(); // skip '
+ else if( currentChar() == 'L' && peekChar() == '\'' )
+ nextChar( 2 ); // slip L'
+ else
+ return;
+
+ while( !currentChar().isNull() ){
+ int len = m_endPtr - currentPosition();
+
+ if( len>=2 && (currentChar() == '\\' && peekChar() == '\'') ){
+ nextChar( 2 );
+ } else if( len>=2 && (currentChar() == '\\' && peekChar() == '\\') ){
+ nextChar( 2 );
+ } else if( currentChar() == '\'' ){
+ nextChar();
+ break;
+ } else {
+ nextChar();
+ }
+ }
+}
+
+inline void Lexer::readStringLiteral()
+{
+ if( currentChar() != '"' )
+ return;
+
+ nextChar(); // skip "
+
+ while( !currentChar().isNull() ){
+ int len = m_endPtr - m_ptr;
+
+ if( len>=2 && currentChar() == '\\' && peekChar() == '"' ){
+ nextChar( 2 );
+ } else if( len>=2 && currentChar() == '\\' && peekChar() == '\\' ){
+ nextChar( 2 );
+ } else if( currentChar() == '"' ){
+ nextChar();
+ break;
+ } else {
+ nextChar();
+ }
+ }
+}
+
+inline void Lexer::readNumberLiteral()
+{
+ while( currentChar().isLetterOrNumber() || currentChar() == '.' )
+ nextChar();
+}
+
+inline int Lexer::findOperator3() const
+{
+ int n = int(m_endPtr - m_ptr);
+
+ if( n >= 3){
+ QChar ch = currentChar(), ch1=peekChar(), ch2=peekChar(2);
+
+ if( ch == '<' && ch1 == '<' && ch2 == '=' ) return Token_assign;
+ else if( ch == '>' && ch1 == '>' && ch2 == '=' ) return Token_assign;
+ else if( ch == '-' && ch1 == '>' && ch2 == '*' ) return Token_ptrmem;
+ else if( ch == '.' && ch1 == '.' && ch2 == '.' ) return Token_ellipsis;
+ }
+
+ return -1;
+}
+
+inline int Lexer::findOperator2() const
+{
+ int n = int(m_endPtr - m_ptr);
+
+ if( n>=2 ){
+ QChar ch = currentChar(), ch1=peekChar();
+
+ if( ch == ':' && ch1 == ':' ) return Token_scope;
+ else if( ch == '.' && ch1 == '*' ) return Token_ptrmem;
+ else if( ch == '+' && ch1 == '=' ) return Token_assign;
+ else if( ch == '-' && ch1 == '=' ) return Token_assign;
+ else if( ch == '*' && ch1 == '=' ) return Token_assign;
+ else if( ch == '/' && ch1 == '=' ) return Token_assign;
+ else if( ch == '%' && ch1 == '=' ) return Token_assign;
+ else if( ch == '^' && ch1 == '=' ) return Token_assign;
+ else if( ch == '&' && ch1 == '=' ) return Token_assign;
+ else if( ch == '|' && ch1 == '=' ) return Token_assign;
+ else if( ch == '<' && ch1 == '<' ) return Token_shift;
+ else if( ch == '>' && ch1 == '>' ) return Token_shift;
+ else if( ch == '=' && ch1 == '=' ) return Token_eq;
+ else if( ch == '!' && ch1 == '=' ) return Token_eq;
+ else if( ch == '<' && ch1 == '=' ) return Token_leq;
+ else if( ch == '>' && ch1 == '=' ) return Token_geq;
+ else if( ch == '&' && ch1 == '&' ) return Token_and;
+ else if( ch == '|' && ch1 == '|' ) return Token_or;
+ else if( ch == '+' && ch1 == '+' ) return Token_incr;
+ else if( ch == '-' && ch1 == '-' ) return Token_decr;
+ else if( ch == '-' && ch1 == '>' ) return Token_arrow;
+ else if( ch == '#' && ch1 == '#' ) return Token_concat;
+ }
+
+ return -1;
+}
+
+inline bool Lexer::skipWordsEnabled() const
+{
+ return m_skipWordsEnabled;
+}
+
+inline void Lexer::setSkipWordsEnabled( bool enabled )
+{
+ m_skipWordsEnabled = enabled;
+}
+
+inline bool Lexer::preprocessorEnabled() const
+{
+ return m_preprocessorEnabled;
+}
+
+inline void Lexer::setPreprocessorEnabled( bool enabled )
+{
+ m_preprocessorEnabled = enabled;
+}
+
+inline int Lexer::currentPosition() const
+{
+ return m_ptr;
+}
+
+inline QChar Lexer::currentChar() const
+{
+ return m_ptr < m_endPtr ? m_source[m_ptr] : QChar::null;
+}
+
+inline QChar Lexer::peekChar( int n ) const
+{
+ return m_ptr+n < m_endPtr ? m_source[m_ptr + n] : QChar::null;
+}
+
+inline bool Lexer::eof() const
+{
+ return m_ptr >= m_endPtr;
+}
+
+inline bool Lexer::reportWarnings() const
+{
+ return m_reportWarnings;
+}
+
+inline void Lexer::setReportWarnings( bool enable )
+{
+ m_reportWarnings = enable;
+}
+
+inline bool Lexer::reportMessages() const
+{
+ return m_reportMessages;
+}
+
+inline void Lexer::setReportMessages( bool enable )
+{
+ m_reportMessages = enable;
+}
+
+
+#endif
diff --git a/umbrello/umbrello/codeimport/kdevcppparser/lookup.cpp b/umbrello/umbrello/codeimport/kdevcppparser/lookup.cpp
new file mode 100644
index 00000000..86299304
--- /dev/null
+++ b/umbrello/umbrello/codeimport/kdevcppparser/lookup.cpp
@@ -0,0 +1,113 @@
+// -*- c-basic-offset: 2 -*-
+/*
+ * This file is part of the KDE libraries
+ * Copyright (C) 1999-2000 Harri Porten (porten@kde.org)
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+// adapted to kdevelop by Roberto Raggi <roberto@kdevelop.org>
+
+#include "lookup.h"
+
+#include <kdebug.h>
+
+#include <stdio.h>
+#include <string.h>
+
+const HashEntry* Lookup::findEntry( const struct HashTable *table,
+ const QChar *c, unsigned int len )
+{
+ if (table->type != 2) {
+ kdDebug() << "KJS: Unknown hash table version" << endl;
+ return 0;
+ }
+ char *ascii = new char[len+1];
+ unsigned int i;
+ for(i = 0; i < len; i++, c++) {
+ if (!c->row())
+ ascii[i] = c->cell();
+ else
+ break;
+ }
+ ascii[i] = '\0';
+
+ int h = hash(ascii) % table->hashSize;
+ const HashEntry *e = &table->entries[h];
+
+ // empty bucket ?
+ if (!e->s) {
+ delete [] ascii;
+ return 0;
+ }
+
+ do {
+ // compare strings
+ if (strcmp(ascii, e->s) == 0) {
+ delete [] ascii;
+ return e;
+ }
+ // try next bucket
+ e = e->next;
+ } while (e);
+
+ delete [] ascii;
+ return 0;
+}
+
+const HashEntry* Lookup::findEntry( const struct HashTable *table,
+ const QString &s )
+{
+ return findEntry( table, s.unicode(), s.length() );
+}
+
+int Lookup::find(const struct HashTable *table,
+ const QChar *c, unsigned int len)
+{
+ const HashEntry *entry = findEntry( table, c, len );
+ if (entry)
+ return entry->value;
+ return -1;
+}
+
+int Lookup::find(const struct HashTable *table, const QString &s)
+{
+ return find(table, s.unicode(), s.length());
+}
+
+unsigned int Lookup::hash(const QChar *c, unsigned int len)
+{
+ unsigned int val = 0;
+ // ignoring rower byte
+ for (unsigned int i = 0; i < len; i++, c++)
+ val += c->cell();
+
+ return val;
+}
+
+unsigned int Lookup::hash(const QString &key)
+{
+ return hash(key.unicode(), key.length());
+}
+
+unsigned int Lookup::hash(const char *s)
+{
+ unsigned int val = 0;
+ while (*s)
+ val += *s++;
+
+ return val;
+}
diff --git a/umbrello/umbrello/codeimport/kdevcppparser/lookup.h b/umbrello/umbrello/codeimport/kdevcppparser/lookup.h
new file mode 100644
index 00000000..3e9c713c
--- /dev/null
+++ b/umbrello/umbrello/codeimport/kdevcppparser/lookup.h
@@ -0,0 +1,119 @@
+// -*- c-basic-offset: 2 -*-
+/*
+ * This file is part of the KDE libraries
+ * Copyright (C) 1999-2000 Harri Porten (porten@kde.org)
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+// adapted to kdevelop by Roberto Raggi <roberto@kdevelop.org>
+
+#ifndef _KJSLOOKUP_H_
+#define _KJSLOOKUP_H_
+
+#include <qstring.h>
+#include <stdio.h>
+
+ /**
+ * An entry in a hash table.
+ */
+ struct HashEntry {
+ /**
+ * s is the key (e.g. a property name)
+ */
+ const char *s;
+ /**
+ * value is the result value (usually an enum value)
+ */
+ int value;
+ /**
+ * attr is a set for flags (e.g. the property flags, see object.h)
+ */
+ short int attr;
+ /**
+ * params is another number. For property hashtables, it is used to
+ * denote the number of argument of the function
+ */
+ short int params;
+ /**
+ * next is the pointer to the next entry for the same hash value
+ */
+ const HashEntry *next;
+ };
+
+ /**
+ * A hash table
+ * Usually the hashtable is generated by the create_hash_table script, from a .table file.
+ *
+ * The implementation uses an array of entries, "size" is the total size of that array.
+ * The entries between 0 and hashSize-1 are the entry points
+ * for each hash value, and the entries between hashSize and size-1
+ * are the overflow entries for the hash values that need one.
+ * The "next" pointer of the entry links entry points to overflow entries,
+ * and links overflow entries between them.
+ */
+ struct HashTable {
+ /**
+ * type is a version number. Currently always 2
+ */
+ int type;
+ /**
+ * size is the total number of entries in the hashtable, including the null entries,
+ * i.e. the size of the "entries" array.
+ * Used to iterate over all entries in the table
+ */
+ int size;
+ /**
+ * pointer to the array of entries
+ * Mind that some entries in the array are null (0,0,0,0).
+ */
+ const HashEntry *entries;
+ /**
+ * the maximum value for the hash. Always smaller than size.
+ */
+ int hashSize;
+ };
+
+ /**
+ * @short Fast keyword lookup.
+ */
+ class Lookup {
+ public:
+ /**
+ * Find an entry in the table, and return its value (i.e. the value field of HashEntry)
+ */
+ static int find(const struct HashTable *table, const QString& s);
+ static int find(const struct HashTable *table, const QChar *c, unsigned int len);
+
+ /**
+ * Find an entry in the table, and return the entry
+ * This variant gives access to the other attributes of the entry,
+ * especially the attr field.
+ */
+ static const HashEntry* findEntry(const struct HashTable *table,
+ const QString &s);
+ static const HashEntry* findEntry(const struct HashTable *table,
+ const QChar *c, unsigned int len);
+
+ /**
+ * Calculate the hash value for a given key
+ */
+ static unsigned int hash(const QString &key);
+ static unsigned int hash(const QChar *c, unsigned int len);
+ static unsigned int hash(const char *s);
+ };
+
+#endif
diff --git a/umbrello/umbrello/codeimport/kdevcppparser/parser.cpp b/umbrello/umbrello/codeimport/kdevcppparser/parser.cpp
new file mode 100644
index 00000000..0314a60c
--- /dev/null
+++ b/umbrello/umbrello/codeimport/kdevcppparser/parser.cpp
@@ -0,0 +1,4238 @@
+/* This file is part of KDevelop
+ Copyright (C) 2002,2003 Roberto Raggi <roberto@kdevelop.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.
+*/
+
+// c++ support
+#include "parser.h"
+#include "driver.h"
+#include "lexer.h"
+#include "errors.h"
+
+// qt
+#include <qstring.h>
+#include <qstringlist.h>
+#include <qasciidict.h>
+
+#include <kdebug.h>
+#include <klocale.h>
+
+using namespace std;
+
+#define ADVANCE(tk, descr) \
+{ \
+ const Token& token = lex->lookAhead( 0 ); \
+ if( token != tk ){ \
+ reportError( i18n("'%1' expected found '%2'").arg(descr).arg(token.text()) ); \
+ return false; \
+ } \
+ lex->nextToken(); \
+}
+
+#define ADVANCE_NR(tk, descr) \
+{ \
+ const Token& token = lex->lookAhead( 0 ); \
+ if( token != tk ){ \
+ reportError( i18n("'%1' expected found '%2'").arg(descr).arg(token.text()) ); \
+ } \
+ else \
+ lex->nextToken(); \
+}
+
+#define CHECK(tk, descr) \
+{ \
+ const Token& token = lex->lookAhead( 0 ); \
+ if( token != tk ){ \
+ return false; \
+ } \
+ lex->nextToken(); \
+}
+
+#define MATCH(tk, descr) \
+{ \
+ const Token& token = lex->lookAhead( 0 ); \
+ if( token != tk ){ \
+ reportError( Errors::SyntaxError ); \
+ return false; \
+ } \
+}
+
+#define UPDATE_POS(node, start, end) \
+{ \
+ int line, col; \
+ const Token &a = lex->tokenAt(start); \
+ const Token &b = lex->tokenAt( end!=start ? end-1 : end ); \
+ a.getStartPosition( &line, &col ); \
+ (node)->setStartPosition( line, col ); \
+ b.getEndPosition( &line, &col ); \
+ (node)->setEndPosition( line, col ); \
+ if( (node)->nodeType() == NodeType_Generic ) { \
+ if ((start) == (end) || (end) == (start)+1) \
+ (node)->setSlice(lex->source(), a.position(), a.length()); \
+ else \
+ (node)->setText( toString((start),(end)) ); \
+ } \
+}
+
+#define AST_FROM_TOKEN(node, tk) \
+ AST::Node node = CreateNode<AST>(); \
+ UPDATE_POS( node, (tk), (tk)+1 );
+
+
+//@todo remove me
+enum
+{
+ OBJC_CLASS,
+ OBJC_PROTOCOL,
+ OBJC_ALIAS
+};
+
+struct ParserPrivateData
+{
+ ParserPrivateData()
+ {}
+};
+
+Parser::Parser( Driver* driver, Lexer* lexer )
+ : m_driver( driver ),
+ lex( lexer )
+{
+ d = new ParserPrivateData();
+
+ m_maxProblems = 5;
+ objcp = false;
+}
+
+Parser::~Parser()
+{
+ delete d;
+ d = 0;
+}
+
+bool Parser::reportError( const Error& err )
+{
+ //kdDebug(9007)<< "--- tok = " << lex->lookAhead(0).text() << " -- " << "Parser::reportError()" << endl;
+ if( m_problems < m_maxProblems ){
+ ++m_problems;
+ int line=0, col=0;
+ const Token& token = lex->lookAhead( 0 );
+ lex->getTokenPosition( token, &line, &col );
+
+ QString s = lex->lookAhead(0).text();
+ s = s.left( 30 ).stripWhiteSpace();
+ if( s.isEmpty() )
+ s = i18n( "<eof>" );
+
+ m_driver->addProblem( m_driver->currentFileName(), Problem(err.text.arg(s), line, col) );
+ }
+
+ return true;
+}
+
+bool Parser::reportError( const QString& msg )
+{
+ //kdDebug(9007)<< "--- tok = " << lex->lookAhead(0).text() << " -- " << "Parser::reportError()" << endl;
+ if( m_problems < m_maxProblems ){
+ ++m_problems;
+ int line=0, col=0;
+ const Token& token = lex->lookAhead( 0 );
+ lex->getTokenPosition( token, &line, &col );
+
+ m_driver->addProblem( m_driver->currentFileName(), Problem(msg, line, col) );
+ }
+
+ return true;
+}
+
+void Parser::syntaxError()
+{
+ (void) reportError( Errors::SyntaxError );
+}
+
+bool Parser::skipUntil( int token )
+{
+ //kdDebug(9007)<< "--- tok = " << lex->lookAhead(0).text() << " -- " << "Parser::skipUntil()" << endl;
+ while( !lex->lookAhead(0).isNull() ){
+ if( lex->lookAhead(0) == token )
+ return true;
+
+ lex->nextToken();
+ }
+
+ return false;
+}
+
+bool Parser::skipUntilDeclaration()
+{
+ //kdDebug(9007)<< "--- tok = " << lex->lookAhead(0).text() << " -- " << "Parser::skipUntilDeclaration()" << endl;
+
+ while( !lex->lookAhead(0).isNull() ){
+
+ switch( lex->lookAhead(0) ){
+ case ';':
+ case '~':
+ case Token_scope:
+ case Token_identifier:
+ case Token_operator:
+ case Token_char:
+ case Token_wchar_t:
+ case Token_bool:
+ case Token_short:
+ case Token_int:
+ case Token_long:
+ case Token_signed:
+ case Token_unsigned:
+ case Token_float:
+ case Token_double:
+ case Token_void:
+ case Token_extern:
+ case Token_namespace:
+ case Token_using:
+ case Token_typedef:
+ case Token_asm:
+ case Token_template:
+ case Token_export:
+
+ case Token_const: // cv
+ case Token_volatile: // cv
+
+ case Token_public:
+ case Token_protected:
+ case Token_private:
+ case Token_signals: // Qt
+ case Token_slots: // Qt
+ return true;
+
+ case '}':
+ return false;
+
+ default:
+ lex->nextToken();
+ }
+ }
+
+ return false;
+}
+
+bool Parser::skipUntilStatement()
+{
+ //kdDebug(9007)<< "--- tok = " << lex->lookAhead(0).text() << " -- " << "Parser::skipUntilStatement() -- token = " << lex->lookAhead(0).text() << endl;
+
+ while( !lex->lookAhead(0).isNull() ){
+ switch( lex->lookAhead(0) ){
+ case ';':
+ case '{':
+ case '}':
+ case Token_const:
+ case Token_volatile:
+ case Token_identifier:
+ case Token_case:
+ case Token_default:
+ case Token_if:
+ case Token_switch:
+ case Token_while:
+ case Token_do:
+ case Token_for:
+ case Token_break:
+ case Token_continue:
+ case Token_return:
+ case Token_goto:
+ case Token_try:
+ case Token_catch:
+ case Token_throw:
+ case Token_char:
+ case Token_wchar_t:
+ case Token_bool:
+ case Token_short:
+ case Token_int:
+ case Token_long:
+ case Token_signed:
+ case Token_unsigned:
+ case Token_float:
+ case Token_double:
+ case Token_void:
+ case Token_class:
+ case Token_struct:
+ case Token_union:
+ case Token_enum:
+ case Token_scope:
+ case Token_template:
+ case Token_using:
+ return true;
+
+ default:
+ lex->nextToken();
+ }
+ }
+
+ return false;
+}
+
+bool Parser::skip( int l, int r )
+{
+ int count = 0;
+ while( !lex->lookAhead(0).isNull() ){
+ int tk = lex->lookAhead( 0 );
+
+ if( tk == l )
+ ++count;
+ else if( tk == r )
+ --count;
+ else if( l != '{' && (tk == '{' || tk == '}' || tk == ';') )
+ return false;
+
+ if( count == 0 )
+ return true;
+
+ lex->nextToken();
+ }
+
+ return false;
+}
+
+bool Parser::skipCommaExpression( AST::Node& node )
+{
+ //kdDebug(9007)<< "--- tok = " << lex->lookAhead(0).text() << " -- " << "Parser::skipCommaExpression()" << endl;
+
+ int start = lex->index();
+
+ AST::Node expr;
+ if( !skipExpression(expr) )
+ return false;
+
+ QString comment;
+ while( lex->lookAhead(0) == ',' ){
+ comment = QString::null;
+ advanceAndCheckTrailingComment( comment );
+
+ if( !skipExpression(expr) ){
+ reportError( i18n("expression expected") );
+ return false;
+ }
+ }
+
+ AST::Node ast = CreateNode<AST>();
+ UPDATE_POS( ast, start, lex->index() );
+ node = ast;
+
+ return true;
+}
+
+bool Parser::skipExpression( AST::Node& node )
+{
+ //kdDebug(9007)<< "--- tok = " << lex->lookAhead(0).text() << " -- " << "Parser::skipExpression()" << endl;
+
+ int start = lex->index();
+
+ while( !lex->lookAhead(0).isNull() ){
+ int tk = lex->lookAhead( 0 );
+
+ switch( tk ){
+ case '(':
+ skip( '(', ')' );
+ lex->nextToken();
+ break;
+
+ case '[':
+ skip( '[', ']' );
+ lex->nextToken();
+ break;
+
+#if 0
+ case Token_identifier:
+ lex->nextToken();
+ if( lex->lookAhead( 0 ) == Token_identifier )
+ return true;
+ break;
+#endif
+
+ case ';':
+ case ',':
+ case ']':
+ case ')':
+ case '{':
+ case '}':
+ case Token_case:
+ case Token_default:
+ case Token_if:
+ case Token_while:
+ case Token_do:
+ case Token_for:
+ case Token_break:
+ case Token_continue:
+ case Token_return:
+ case Token_goto:
+ {
+ AST::Node ast = CreateNode<AST>();
+ UPDATE_POS( ast, start, lex->index() );
+ node = ast;
+ }
+ return true;
+
+ default:
+ lex->nextToken();
+ }
+ }
+
+ return false;
+}
+
+bool Parser::parseName( NameAST::Node& node )
+{
+ //kdDebug(9007)<< "--- tok = " << lex->lookAhead(0).text() << " -- " << "Parser::parseName()" << endl;
+
+ GroupAST::Node winDeclSpec;
+ parseWinDeclSpec( winDeclSpec );
+
+ int start = lex->index();
+
+ NameAST::Node ast = CreateNode<NameAST>();
+
+ if( lex->lookAhead(0) == Token_scope ){
+ ast->setGlobal( true );
+ lex->nextToken();
+ }
+
+ int idx = lex->index();
+
+ while( true ){
+ ClassOrNamespaceNameAST::Node n;
+ if( !parseUnqualifiedName(n) ) {
+ return false;
+ }
+
+ if( lex->lookAhead(0) == Token_scope ){
+ lex->nextToken();
+ ast->addClassOrNamespaceName( n );
+ if( lex->lookAhead(0) == Token_template )
+ lex->nextToken(); /// skip optional template #### @todo CHECK
+ } else {
+ ast->setUnqualifiedName( n );
+ break;
+ }
+ }
+
+ if( idx == lex->index() )
+ return false;
+
+ UPDATE_POS( ast, start, lex->index() );
+ node = ast;
+
+ return true;
+}
+
+bool Parser::parseTranslationUnit( TranslationUnitAST::Node& node )
+{
+ //kdDebug(9007)<< "--- tok = " << lex->lookAhead(0).text() << " -- " << "Parser::parseTranslationUnit()" << endl;
+
+ int start = lex->index();
+
+ m_problems = 0;
+ TranslationUnitAST::Node tun = CreateNode<TranslationUnitAST>();
+ node = tun;
+ while( !lex->lookAhead(0).isNull() ){
+ DeclarationAST::Node def;
+ int startDecl = lex->index();
+ if( !parseDeclaration(def) ){
+ // error recovery
+ if( startDecl == lex->index() )
+ lex->nextToken(); // skip at least one token
+ skipUntilDeclaration();
+ }
+ node->addDeclaration( def );
+ }
+
+ UPDATE_POS( node, start, lex->index() );
+
+ // force (0,0) as start position
+ node->setStartPosition( 0, 0 );
+
+ return m_problems == 0;
+}
+
+bool Parser::parseDeclaration( DeclarationAST::Node& node )
+{
+ //kdDebug(9007)<< "--- tok = " << lex->lookAhead(0).text() << " -- " << "Parser::parseDeclaration()" << endl;
+
+ QString comment;
+ while( lex->lookAhead(0) == Token_comment ) {
+ comment += lex->lookAhead(0).text();
+ lex->nextToken();
+ }
+ if( lex->lookAhead(0).isNull() )
+ return false;
+
+ int start = lex->index();
+ bool success = false;
+
+ switch( lex->lookAhead(0) ){
+
+ case ';':
+ lex->nextToken();
+ return true;
+
+ case Token_extern:
+ success = parseLinkageSpecification( node );
+ break;
+
+ case Token_namespace:
+ success = parseNamespace( node );
+ break;
+
+ case Token_using:
+ success = parseUsing( node );
+ break;
+
+ case Token_typedef:
+ success = parseTypedef( node );
+ break;
+
+ case Token_asm:
+ success = parseAsmDefinition( node );
+ break;
+
+ case Token_template:
+ case Token_export:
+ success = parseTemplateDeclaration( node );
+ break;
+
+ default:
+ {
+ // lex->setIndex( start );
+
+ if( objcp && parseObjcDef(node) )
+ return true;
+
+ lex->setIndex( start );
+
+ GroupAST::Node storageSpec;
+ parseStorageClassSpecifier( storageSpec );
+
+ GroupAST::Node cv;
+ parseCvQualify( cv );
+
+ TypeSpecifierAST::Node spec;
+ AST::Node declarator;
+ if( parseEnumSpecifier(spec) || parseClassSpecifier(spec) ){
+ spec->setCvQualify( cv );
+
+ GroupAST::Node cv2;
+ parseCvQualify( cv2 );
+ spec->setCv2Qualify( cv2 );
+
+ InitDeclaratorListAST::Node declarators;
+ parseInitDeclaratorList(declarators);
+ ADVANCE( ';', ";" );
+
+ if( !comment.isEmpty() ) {
+ //kdDebug(9007) << "Parser::parseDeclaration(spec): comment is " << comment << endl;
+ spec->setComment( comment );
+ }
+
+ SimpleDeclarationAST::Node ast = CreateNode<SimpleDeclarationAST>();
+ ast->setStorageSpecifier( storageSpec );
+ ast->setTypeSpec( spec );
+ ast->setInitDeclaratorList( declarators );
+ UPDATE_POS( ast, start, lex->index() );
+ node = ast;
+
+ return true;
+ }
+
+ lex->setIndex( start );
+ success = parseDeclarationInternal( node, comment );
+ }
+
+ } // end switch
+
+ if( success && !comment.isEmpty() ) {
+ //kdDebug(9007) << "Parser::parseDeclaration(): comment is " << comment << endl;
+ node->setComment( comment );
+ }
+ return success;
+}
+
+bool Parser::parseLinkageSpecification( DeclarationAST::Node& node )
+{
+ //kdDebug(9007)<< "--- tok = " << lex->lookAhead(0).text() << " -- " << "Parser::parseLinkageSpecification()" << endl;
+
+ int start = lex->index();
+
+ if( lex->lookAhead(0) != Token_extern ){
+ return false;
+ }
+ lex->nextToken();
+
+ LinkageSpecificationAST::Node ast = CreateNode<LinkageSpecificationAST>();
+
+ int startExternType = lex->index();
+ if( lex->lookAhead(0) == Token_string_literal ){
+ lex->nextToken();
+ AST::Node externType = CreateNode<AST>();
+ UPDATE_POS( externType, startExternType, lex->index() );
+
+ ast->setExternType( externType );
+ }
+
+ if( lex->lookAhead(0) == '{' ){
+ LinkageBodyAST::Node linkageBody;
+ parseLinkageBody( linkageBody );
+ ast->setLinkageBody( linkageBody );
+ } else {
+ DeclarationAST::Node decl;
+ if( !parseDeclaration(decl) ){
+ reportError( i18n("Declaration syntax error") );
+ }
+ ast->setDeclaration( decl );
+ }
+
+ UPDATE_POS( ast, start, lex->index() );
+
+ node = ast;
+
+ return true;
+}
+
+bool Parser::parseLinkageBody( LinkageBodyAST::Node& node )
+{
+ //kdDebug(9007)<< "--- tok = " << lex->lookAhead(0).text() << " -- " << "Parser::parseLinkageBody()" << endl;
+
+ int start = lex->index();
+
+ if( lex->lookAhead(0) != '{' ){
+ return false;
+ }
+ lex->nextToken();
+
+ LinkageBodyAST::Node lba = CreateNode<LinkageBodyAST>();
+ node = lba;
+
+ while( !lex->lookAhead(0).isNull() ){
+ int tk = lex->lookAhead( 0 );
+
+ if( tk == '}' )
+ break;
+
+ DeclarationAST::Node def;
+ int startDecl = lex->index();
+ if( parseDeclaration(def) ){
+ node->addDeclaration( def );
+ } else {
+ // error recovery
+ if( startDecl == lex->index() )
+ lex->nextToken(); // skip at least one token
+ skipUntilDeclaration();
+ }
+ }
+
+ if( lex->lookAhead(0) != '}' ){
+ reportError( i18n("} expected") );
+ } else
+ lex->nextToken();
+
+ UPDATE_POS( node, start, lex->index() );
+ return true;
+}
+
+bool Parser::parseNamespace( DeclarationAST::Node& node )
+{
+ //kdDebug(9007)<< "--- tok = " << lex->lookAhead(0).text() << " -- " << "Parser::parseNamespace()" << endl;
+
+ int start = lex->index();
+
+ if( lex->lookAhead(0) != Token_namespace ){
+ return false;
+ }
+ lex->nextToken();
+
+ int startNamespaceName = lex->index();
+ if( lex->lookAhead(0) == Token_identifier ){
+ lex->nextToken();
+ }
+ AST::Node namespaceName = CreateNode<AST>();
+ UPDATE_POS( namespaceName, startNamespaceName, lex->index() );
+
+ if ( lex->lookAhead(0) == '=' ) {
+ // namespace alias
+ lex->nextToken();
+
+ NameAST::Node name;
+ if( parseName(name) ){
+ ADVANCE( ';', ";" );
+
+ NamespaceAliasAST::Node ast = CreateNode<NamespaceAliasAST>();
+ ast->setNamespaceName( namespaceName );
+ ast->setAliasName( name );
+ UPDATE_POS( ast, start, lex->index() );
+ node = ast;
+ return true;
+ } else {
+ reportError( i18n("namespace expected") );
+ return false;
+ }
+ } else if( lex->lookAhead(0) != '{' ){
+ reportError( i18n("{ expected") );
+ return false;
+ }
+
+ NamespaceAST::Node ast = CreateNode<NamespaceAST>();
+ ast->setNamespaceName( namespaceName );
+
+ LinkageBodyAST::Node linkageBody;
+ parseLinkageBody( linkageBody );
+
+ ast->setLinkageBody( linkageBody );
+ UPDATE_POS( ast, start, lex->index() );
+ node = ast;
+
+ return true;
+}
+
+bool Parser::parseUsing( DeclarationAST::Node& node )
+{
+ //kdDebug(9007)<< "--- tok = " << lex->lookAhead(0).text() << " -- " << "Parser::parseUsing()" << endl;
+
+ int start = lex->index();
+
+ if( lex->lookAhead(0) != Token_using ){
+ return false;
+ }
+ lex->nextToken();
+
+ if( lex->lookAhead(0) == Token_namespace ){
+ if( !parseUsingDirective(node) ){
+ return false;
+ }
+ UPDATE_POS( node, start, lex->index() );
+ return true;
+ }
+
+ UsingAST::Node ast = CreateNode<UsingAST>();
+
+ int startTypeName = lex->index();
+ if( lex->lookAhead(0) == Token_typename ){
+ lex->nextToken();
+ AST::Node tn = CreateNode<AST>();
+ UPDATE_POS( tn, startTypeName, lex->index() );
+ ast->setTypeName( tn );
+ }
+
+ NameAST::Node name;
+ if( !parseName(name) )
+ return false;
+
+ ast->setName( name );
+
+ ADVANCE( ';', ";" );
+
+ UPDATE_POS( ast, start, lex->index() );
+ node = ast;
+
+ return true;
+}
+
+bool Parser::parseUsingDirective( DeclarationAST::Node& node )
+{
+ //kdDebug(9007)<< "--- tok = " << lex->lookAhead(0).text() << " -- " << "Parser::parseUsingDirective()" << endl;
+
+ int start = lex->index();
+
+ if( lex->lookAhead(0) != Token_namespace ){
+ return false;
+ }
+ lex->nextToken();
+
+ NameAST::Node name;
+ if( !parseName(name) ){
+ reportError( i18n("Namespace name expected") );
+ return false;
+ }
+
+ ADVANCE( ';', ";" );
+
+ UsingDirectiveAST::Node ast = CreateNode<UsingDirectiveAST>();
+ ast->setName( name );
+ UPDATE_POS( ast, start, lex->index() );
+ node = ast;
+
+ return true;
+}
+
+
+bool Parser::parseOperatorFunctionId( AST::Node& node )
+{
+ //kdDebug(9007)<< "--- tok = " << lex->lookAhead(0).text() << " -- " << "Parser::parseOperatorFunctionId()" << endl;
+
+ int start = lex->index();
+
+ if( lex->lookAhead(0) != Token_operator ){
+ return false;
+ }
+ lex->nextToken();
+
+ AST::Node op;
+ if( parseOperator(op) ){
+ AST::Node asn = CreateNode<AST>();
+ node = asn;
+ UPDATE_POS( node, start, lex->index() );
+ return true;
+ } else {
+ // parse cast operator
+ GroupAST::Node cv;
+ parseCvQualify(cv);
+
+ TypeSpecifierAST::Node spec;
+ if( !parseSimpleTypeSpecifier(spec) ){
+ syntaxError();
+ return false;
+ }
+ spec->setCvQualify( cv );
+
+ GroupAST::Node cv2;
+ parseCvQualify(cv2);
+ spec->setCv2Qualify( cv2 );
+
+ AST::Node ptrOp;
+ while( parsePtrOperator(ptrOp) )
+ ;
+
+ AST::Node asn = CreateNode<AST>();
+ node = asn;
+ UPDATE_POS( node, start, lex->index() );
+ return true;
+ }
+}
+
+bool Parser::parseTemplateArgumentList( TemplateArgumentListAST::Node& node, bool reportError )
+{
+ //kdDebug(9007)<< "--- tok = " << lex->lookAhead(0).text() << " -- " << "Parser::parseTemplateArgumentList()" << endl;
+
+ int start = lex->index();
+
+ TemplateArgumentListAST::Node ast = CreateNode<TemplateArgumentListAST>();
+
+ AST::Node templArg;
+ if( !parseTemplateArgument(templArg) )
+ return false;
+ ast->addArgument( templArg );
+
+ QString comment;
+ while( lex->lookAhead(0) == ',' ){
+ comment = QString::null;
+ advanceAndCheckTrailingComment( comment );
+
+ if( !parseTemplateArgument(templArg) ){
+ if( reportError ){
+ syntaxError();
+ break;
+ } else
+ return false;
+ }
+ if (!comment.isEmpty())
+ templArg->setComment(comment);
+ ast->addArgument( templArg );
+ }
+
+ UPDATE_POS( ast, start, lex->index() );
+ node = ast;
+
+ return true;
+}
+
+bool Parser::parseTypedef( DeclarationAST::Node& node )
+{
+ //kdDebug(9007)<< "--- tok = " << lex->lookAhead(0).text() << " -- " << "Parser::parseTypedef()" << endl;
+
+ int start = lex->index();
+
+ if( lex->lookAhead(0) != Token_typedef ){
+ return false;
+ }
+ lex->nextToken();
+
+ TypeSpecifierAST::Node spec;
+ if( !parseTypeSpecifierOrClassSpec(spec) ){
+ reportError( i18n("Need a type specifier to declare") );
+ return false;
+ }
+
+ InitDeclaratorListAST::Node declarators;
+ if( !parseInitDeclaratorList(declarators) ){
+ //reportError( i18n("Need an identifier to declare") );
+ //return false;
+ }
+
+ ADVANCE( ';', ";" );
+
+ TypedefAST::Node ast = CreateNode<TypedefAST>();
+ ast->setTypeSpec( spec );
+ ast->setInitDeclaratorList( declarators );
+ UPDATE_POS( ast, start, lex->index() );
+ node = ast;
+
+ return true;
+}
+
+bool Parser::parseAsmDefinition( DeclarationAST::Node& /*node*/ )
+{
+ //kdDebug(9007)<< "--- tok = " << lex->lookAhead(0).text() << " -- " << "Parser::parseAsmDefinition()" << endl;
+
+ ADVANCE( Token_asm, "asm" );
+
+ GroupAST::Node cv;
+ parseCvQualify( cv );
+
+ skip( '(', ')' );
+ ADVANCE( ')', ")" );
+ ADVANCE( ';', ';' );
+
+ return true;
+}
+
+bool Parser::parseTemplateDeclaration( DeclarationAST::Node& node )
+{
+ //kdDebug(9007)<< "--- tok = " << lex->lookAhead(0).text() << " -- " << "Parser::parseTemplateDeclaration()" << endl;
+
+ int start = lex->index();
+
+ AST::Node exp;
+
+ int startExport = lex->index();
+ if( lex->lookAhead(0) == Token_export ){
+ lex->nextToken();
+ AST::Node n = CreateNode<AST>();
+ UPDATE_POS( n, startExport, lex->index() );
+ exp = n;
+ }
+
+ if( lex->lookAhead(0) != Token_template ){
+ return false;
+ }
+ lex->nextToken();
+
+ TemplateParameterListAST::Node params;
+ if( lex->lookAhead(0) == '<' ){
+ lex->nextToken();
+ if (lex->lookAhead(0) != '>')
+ parseTemplateParameterList( params );
+
+ ADVANCE( '>', ">" );
+ }
+
+ DeclarationAST::Node def;
+ if( !parseDeclaration(def) ){
+ reportError( i18n("expected a declaration") );
+ }
+
+ TemplateDeclarationAST::Node ast = CreateNode<TemplateDeclarationAST>();
+ ast->setExported( exp );
+ ast->setTemplateParameterList( params );
+ ast->setDeclaration( def );
+ UPDATE_POS( ast, start, lex->index() );
+ node = ast;
+
+ return true;
+}
+
+bool Parser::parseOperator( AST::Node& /*node*/ )
+{
+ //kdDebug(9007)<< "--- tok = " << lex->lookAhead(0).text() << " -- " << "Parser::parseOperator()" << endl;
+ QString text = lex->lookAhead(0).text();
+
+ switch( lex->lookAhead(0) ){
+ case Token_new:
+ case Token_delete:
+ lex->nextToken();
+ if( lex->lookAhead(0) == '[' && lex->lookAhead(1) == ']' ){
+ lex->nextToken();
+ lex->nextToken();
+ text += "[]";
+ }
+ return true;
+
+ case '+':
+ case '-':
+ case '*':
+ case '/':
+ case '%':
+ case '^':
+ case '&':
+ case '|':
+ case '~':
+ case '!':
+ case '=':
+ case '<':
+ case '>':
+ case ',':
+ case Token_assign:
+ case Token_shift:
+ case Token_eq:
+ case Token_not_eq:
+ case Token_leq:
+ case Token_geq:
+ case Token_and:
+ case Token_or:
+ case Token_incr:
+ case Token_decr:
+ case Token_ptrmem:
+ case Token_arrow:
+ lex->nextToken();
+ return true;
+
+ default:
+ if( lex->lookAhead(0) == '(' && lex->lookAhead(1) == ')' ){
+ lex->nextToken();
+ lex->nextToken();
+ return true;
+ } else if( lex->lookAhead(0) == '[' && lex->lookAhead(1) == ']' ){
+ lex->nextToken();
+ lex->nextToken();
+ return true;
+ }
+ }
+
+ return false;
+}
+
+bool Parser::parseCvQualify( GroupAST::Node& node )
+{
+ //kdDebug(9007)<< "--- tok = " << lex->lookAhead(0).text() << " -- " << "Parser::parseCvQualify()" << endl;
+
+ int start = lex->index();
+
+ GroupAST::Node ast = CreateNode<GroupAST>();
+
+ int n = 0;
+ while( !lex->lookAhead(0).isNull() ){
+ int tk = lex->lookAhead( 0 );
+ if( tk == Token_const || tk == Token_volatile ){
+ ++n;
+ int startWord = lex->index();
+ lex->nextToken();
+ AST::Node word = CreateNode<AST>();
+ UPDATE_POS( word, startWord, lex->index() );
+ ast->addNode( word );
+ } else
+ break;
+ }
+
+ if( n == 0 )
+ return false;
+
+
+ //kdDebug(9007)<< "-----------------> token = " << lex->lookAhead(0).text() << endl;
+ UPDATE_POS( ast, start, lex->index() );
+
+ node = ast;
+ return true;
+}
+
+bool Parser::parseSimpleTypeSpecifier( TypeSpecifierAST::Node& node )
+{
+ int start = lex->index();
+ bool isIntegral = false;
+ bool done = false;
+
+ while( !done ){
+
+ switch( lex->lookAhead(0) ){
+ case Token_char:
+ case Token_wchar_t:
+ case Token_bool:
+ case Token_short:
+ case Token_int:
+ case Token_long:
+ case Token_signed:
+ case Token_unsigned:
+ case Token_float:
+ case Token_double:
+ case Token_void:
+ isIntegral = true;
+ lex->nextToken();
+ break;
+
+ default:
+ done = true;
+ }
+ }
+
+ TypeSpecifierAST::Node ast = CreateNode<TypeSpecifierAST>();
+ if( isIntegral ){
+ ClassOrNamespaceNameAST::Node cl = CreateNode<ClassOrNamespaceNameAST>();
+
+ AST::Node n = CreateNode<AST>();
+ UPDATE_POS( n, start, lex->index() );
+ cl->setName( n );
+ UPDATE_POS( cl, start, lex->index() );
+
+ NameAST::Node name = CreateNode<NameAST>();
+ name->setUnqualifiedName( cl );
+ UPDATE_POS( name, start, lex->index() );
+ ast->setName( name );
+
+ } else {
+ NameAST::Node name;
+ if( !parseName(name) ){
+ lex->setIndex( start );
+ return false;
+ }
+ ast->setName( name );
+ }
+
+ UPDATE_POS( ast, start, lex->index() );
+ node = ast;
+ return true;
+}
+
+bool Parser::parsePtrOperator( AST::Node& node )
+{
+ //kdDebug(9007)<< "--- tok = " << lex->lookAhead(0).text() << " -- " << "Parser::parsePtrOperator()" << endl;
+
+ int start = lex->index();
+
+ if( lex->lookAhead(0) == '&' ){
+ lex->nextToken();
+ } else if( lex->lookAhead(0) == '*' ){
+ lex->nextToken();
+ } else {
+ int index = lex->index();
+ AST::Node memPtr;
+ if( !parsePtrToMember(memPtr) ){
+ lex->setIndex( index );
+ return false;
+ }
+ }
+
+ GroupAST::Node cv;
+ parseCvQualify( cv );
+
+ AST::Node ast = CreateNode<AST>();
+ UPDATE_POS( ast, start, lex->index() );
+ node = ast;
+
+ return true;
+}
+
+
+bool Parser::parseTemplateArgument( AST::Node& node )
+{
+ //kdDebug(9007)<< "--- tok = " << lex->lookAhead(0).text() << " -- " << "Parser::parseTemplateArgument()" << endl;
+
+ int start = lex->index();
+ if( parseTypeId(node) ){
+ if( lex->lookAhead(0) == ',' || lex->lookAhead(0) == '>' )
+ return true;
+ }
+
+ lex->setIndex( start );
+ if( !parseLogicalOrExpression(node, true) ){
+ return false;
+ }
+
+ return true;
+}
+
+bool Parser::parseTypeSpecifier( TypeSpecifierAST::Node& spec )
+{
+ //kdDebug(9007)<< "--- tok = " << lex->lookAhead(0).text() << " -- " << "Parser::parseTypeSpecifier()" << endl;
+
+ GroupAST::Node cv;
+ parseCvQualify( cv );
+
+ if( parseElaboratedTypeSpecifier(spec) || parseSimpleTypeSpecifier(spec) ){
+ spec->setCvQualify( cv );
+
+ GroupAST::Node cv2;
+ parseCvQualify( cv2 );
+ spec->setCv2Qualify( cv2 );
+
+ return true;
+ }
+
+ return false;
+}
+
+bool Parser::parseDeclarator( DeclaratorAST::Node& node )
+{
+ //kdDebug(9007)<< "--- tok = " << lex->lookAhead(0).text() << " -- " << "Parser::parseDeclarator()" << endl;
+
+ int start = lex->index();
+
+ DeclaratorAST::Node ast = CreateNode<DeclaratorAST>();
+
+ DeclaratorAST::Node decl;
+ NameAST::Node declId;
+
+ AST::Node ptrOp;
+ while( parsePtrOperator(ptrOp) ){
+ ast->addPtrOp( ptrOp );
+ }
+
+ if( lex->lookAhead(0) == '(' ){
+ lex->nextToken();
+
+ if( !parseDeclarator(decl) ){
+ return false;
+ }
+ ast->setSubDeclarator( decl );
+
+ if( lex->lookAhead(0) != ')'){
+ return false;
+ }
+ lex->nextToken();
+ } else {
+
+ if( lex->lookAhead(0) == ':' ){
+ // unnamed bitfield
+ } else if( parseDeclaratorId(declId) ){
+ ast->setDeclaratorId( declId );
+ } else {
+ lex->setIndex( start );
+ return false;
+ }
+
+ if( lex->lookAhead(0) == ':' ){
+ lex->nextToken();
+ AST::Node expr;
+ if( !parseConstantExpression(expr) ){
+ reportError( i18n("Constant expression expected") );
+ }
+ goto update_pos;
+ }
+ }
+
+ {
+ bool isVector = true;
+
+ while( lex->lookAhead(0) == '[' ){
+ int startArray = lex->index();
+ lex->nextToken();
+ AST::Node expr;
+ parseCommaExpression( expr );
+
+ ADVANCE( ']', "]" );
+ AST::Node array = CreateNode<AST>();
+ UPDATE_POS( array, startArray, lex->index() );
+ ast->addArrayDimension( array );
+ isVector = true;
+ }
+
+ bool skipParen = false;
+ if( lex->lookAhead(0) == Token_identifier && lex->lookAhead(1) == '(' && lex->lookAhead(2) == '(' ){
+ lex->nextToken();
+ lex->nextToken();
+ skipParen = true;
+ }
+
+ if( ast->subDeclarator() && (!isVector || lex->lookAhead(0) != '(') ){
+ lex->setIndex( start );
+ return false;
+ }
+
+ int index = lex->index();
+ if( lex->lookAhead(0) == '(' ){
+ lex->nextToken();
+
+ ParameterDeclarationClauseAST::Node params;
+ if( !parseParameterDeclarationClause(params) ){
+ //kdDebug(9007)<< "----------------------> not a parameter declaration, maybe an initializer!?" << endl;
+ lex->setIndex( index );
+ goto update_pos;
+ }
+ ast->setParameterDeclarationClause( params );
+
+ if( lex->lookAhead(0) != ')' ){
+ lex->setIndex( index );
+ goto update_pos;
+ }
+
+ lex->nextToken(); // skip ')'
+
+ int startConstant = lex->index();
+ if( lex->lookAhead(0) == Token_const ){
+ lex->nextToken();
+ AST::Node constant = CreateNode<AST>();
+ UPDATE_POS( constant, startConstant, lex->index() );
+ ast->setConstant( constant );
+ }
+
+ GroupAST::Node except;
+ if( parseExceptionSpecification(except) ){
+ ast->setExceptionSpecification( except );
+ }
+ }
+
+ if( skipParen ){
+ if( lex->lookAhead(0) != ')' ){
+ reportError( i18n("')' expected") );
+ } else
+ lex->nextToken();
+ }
+
+ }
+
+update_pos:
+ UPDATE_POS( ast, start, lex->index() );
+ node = ast;
+
+ return true;
+}
+
+bool Parser::parseAbstractDeclarator( DeclaratorAST::Node& node )
+{
+ //kdDebug(9007)<< "--- tok = " << lex->lookAhead(0).text() << " -- " << "Parser::parseDeclarator()" << endl;
+ int start = lex->index();
+
+ DeclaratorAST::Node ast = CreateNode<DeclaratorAST>();
+
+ DeclaratorAST::Node decl;
+ NameAST::Node declId;
+
+ AST::Node ptrOp;
+ while( parsePtrOperator(ptrOp) ){
+ ast->addPtrOp( ptrOp );
+ }
+
+ if( lex->lookAhead(0) == '(' ){
+ lex->nextToken();
+
+ if( !parseAbstractDeclarator(decl) ){
+ return false;
+ }
+ ast->setSubDeclarator( decl );
+
+ if( lex->lookAhead(0) != ')'){
+ return false;
+ }
+ lex->nextToken();
+ }
+
+ {
+
+ while( lex->lookAhead(0) == '[' ){
+ int startArray = lex->index();
+ lex->nextToken();
+ AST::Node expr;
+ skipCommaExpression( expr );
+
+ ADVANCE( ']', "]" );
+ AST::Node array = CreateNode<AST>();
+ UPDATE_POS( array, startArray, lex->index() );
+ ast->addArrayDimension( array );
+ }
+
+ bool skipParen = false;
+ if( lex->lookAhead(0) == Token_identifier && lex->lookAhead(1) == '(' && lex->lookAhead(2) == '(' ){
+ lex->nextToken();
+ lex->nextToken();
+ skipParen = true;
+ }
+
+ int index = lex->index();
+ if( lex->lookAhead(0) == '(' ){
+ lex->nextToken();
+
+ ParameterDeclarationClauseAST::Node params;
+ if( !parseParameterDeclarationClause(params) ){
+ lex->setIndex( index );
+ goto UPDATE_POS;
+ }
+ ast->setParameterDeclarationClause( params );
+
+ if( lex->lookAhead(0) != ')' ){
+ lex->setIndex( index );
+ goto UPDATE_POS;
+ } else
+ lex->nextToken();
+
+ int startConstant = lex->index();
+ if( lex->lookAhead(0) == Token_const ){
+ lex->nextToken();
+ AST::Node constant = CreateNode<AST>();
+ UPDATE_POS( constant, startConstant, lex->index() );
+ ast->setConstant( constant );
+ }
+
+ GroupAST::Node except;
+ if( parseExceptionSpecification(except) ){
+ ast->setExceptionSpecification( except );
+ }
+ }
+
+ if( skipParen ){
+ if( lex->lookAhead(0) != ')' ){
+ reportError( i18n("')' expected") );
+ } else
+ lex->nextToken();
+ }
+
+ }
+
+UPDATE_POS:
+ UPDATE_POS( ast, start, lex->index() );
+ node = ast;
+
+ return true;
+}
+
+
+bool Parser::parseEnumSpecifier( TypeSpecifierAST::Node& node )
+{
+ //kdDebug(9007)<< "--- tok = " << lex->lookAhead(0).text() << " -- " << "Parser::parseEnumSpecifier()" << endl;
+
+ QString comment;
+ while( lex->lookAhead(0) == Token_comment ) {
+ comment += lex->lookAhead(0).text();
+ lex->nextToken();
+ }
+ if( lex->lookAhead(0).isNull() )
+ return false;
+
+ int start = lex->index();
+
+ if( lex->lookAhead(0) != Token_enum ){
+ return false;
+ }
+
+ lex->nextToken();
+
+ NameAST::Node name;
+ parseName( name );
+
+ if( lex->lookAhead(0) != '{' ){
+ lex->setIndex( start );
+ return false;
+ }
+ lex->nextToken();
+
+ EnumSpecifierAST::Node ast = CreateNode<EnumSpecifierAST>();
+ ast->setName( name );
+
+ EnumeratorAST::Node enumerator;
+ if( parseEnumerator(enumerator) ){
+ ast->addEnumerator( enumerator );
+
+ QString comment;
+ while( lex->lookAhead(0) == ',' ){
+ comment = "";
+ advanceAndCheckTrailingComment( comment );
+ if ( !comment.isEmpty() ){
+ EnumeratorAST *lastLit = ast->enumeratorList().last();
+ if( lastLit )
+ lastLit->setComment( comment );
+ }
+
+ if( !parseEnumerator(enumerator) ){
+ //reportError( i18n("Enumerator expected") );
+ break;
+ }
+
+ ast->addEnumerator( enumerator );
+ }
+ }
+
+ if( lex->lookAhead(0) == Token_comment )
+ lex->nextToken();
+ if( lex->lookAhead(0) != '}' )
+ reportError( i18n("} missing") );
+ else
+ lex->nextToken();
+
+ UPDATE_POS( ast, start, lex->index() );
+ node = ast;
+
+ return true;
+}
+
+bool Parser::parseTemplateParameterList( TemplateParameterListAST::Node& node )
+{
+ //kdDebug(9007)<< "--- tok = " << lex->lookAhead(0).text() << " -- " << "Parser::parseTemplateParameterList()" << endl;
+
+ int start = lex->index();
+
+ TemplateParameterListAST::Node ast = CreateNode<TemplateParameterListAST>();
+
+ TemplateParameterAST::Node param;
+ if( !parseTemplateParameter(param) ){
+ return false;
+ }
+ ast->addTemplateParameter( param );
+
+ QString comment;
+ while( lex->lookAhead(0) == ',' ){
+ comment = QString::null;
+ advanceAndCheckTrailingComment( comment );
+
+ if( !parseTemplateParameter(param) ){
+ syntaxError();
+ break;
+ } else {
+ if (!comment.isEmpty())
+ param->setComment(comment);
+ ast->addTemplateParameter( param );
+ }
+ }
+
+ UPDATE_POS( ast, start, lex->index() );
+ node = ast;
+
+ return true;
+}
+
+bool Parser::parseTemplateParameter( TemplateParameterAST::Node& node )
+{
+ //kdDebug(9007)<< "--- tok = " << lex->lookAhead(0).text() << " -- " << "Parser::parseTemplateParameter()" << endl;
+
+ int start = lex->index();
+ TemplateParameterAST::Node ast = CreateNode<TemplateParameterAST>();
+
+ TypeParameterAST::Node typeParameter;
+ ParameterDeclarationAST::Node param;
+
+ int tk = lex->lookAhead( 0 );
+
+ if( (tk == Token_class || tk == Token_typename || tk == Token_template) && parseTypeParameter(typeParameter) ){
+ ast->setTypeParameter( typeParameter );
+ goto ok;
+ }
+
+ if( !parseParameterDeclaration(param) )
+ return false;
+ ast->setTypeValueParameter( param );
+
+ok:
+ UPDATE_POS( ast, start, lex->index() );
+ node = ast;
+
+ return true;
+}
+
+bool Parser::parseTypeParameter( TypeParameterAST::Node& node )
+{
+ //kdDebug(9007)<< "--- tok = " << lex->lookAhead(0).text() << " -- " << "Parser::parseTypeParameter()" << endl;
+
+ int start = lex->index();
+ TypeParameterAST::Node ast = CreateNode<TypeParameterAST>();
+
+ AST_FROM_TOKEN( kind, lex->index() );
+ ast->setKind( kind );
+
+ switch( lex->lookAhead(0) ){
+
+ case Token_class:
+ case Token_typename:
+ {
+ lex->nextToken(); // skip class
+
+ // parse optional name
+ NameAST::Node name;
+ if( parseName(name) ){
+ ast->setName( name );
+ if( lex->lookAhead(0) == '=' ){
+ lex->nextToken();
+
+ AST::Node typeId;
+ if( !parseTypeId(typeId) ){
+ syntaxError();
+ return false;
+ }
+ ast->setTypeId( typeId );
+ }
+ }
+ }
+ break;
+
+ case Token_template:
+ {
+ lex->nextToken(); // skip template
+ ADVANCE( '<', '<' );
+
+ TemplateParameterListAST::Node params;
+ if( !parseTemplateParameterList(params) ){
+ return false;
+ }
+ ast->setTemplateParameterList( params );
+
+ ADVANCE( '>', ">" );
+
+ if( lex->lookAhead(0) == Token_class )
+ lex->nextToken();
+
+ // parse optional name
+ NameAST::Node name;
+ if( parseName(name) ){
+ ast->setName( name );
+ if( lex->lookAhead(0) == '=' ){
+ lex->nextToken();
+
+ AST::Node typeId;
+ if( !parseTypeId(typeId) ){
+ syntaxError();
+ return false;
+ }
+ ast->setTypeId( typeId );
+ }
+ }
+
+ if( lex->lookAhead(0) == '=' ){
+ lex->nextToken();
+
+ NameAST::Node templ_name;
+ parseName( templ_name );
+ }
+ }
+ break;
+
+ default:
+ return false;
+
+ } // end switch
+
+
+ UPDATE_POS( ast, start, lex->index() );
+ node = ast;
+ return true;
+}
+
+bool Parser::parseStorageClassSpecifier( GroupAST::Node& node )
+{
+ //kdDebug(9007)<< "--- tok = " << lex->lookAhead(0).text() << " -- " << "Parser::parseStorageClassSpecifier()" << endl;
+
+ int start = lex->index();
+ GroupAST::Node ast = CreateNode<GroupAST>();
+
+ while( !lex->lookAhead(0).isNull() ){
+ int tk = lex->lookAhead( 0 );
+ if( tk == Token_friend || tk == Token_auto || tk == Token_register || tk == Token_static ||
+ tk == Token_extern || tk == Token_mutable ){
+ int startNode = lex->index();
+ lex->nextToken();
+
+ AST::Node n = CreateNode<AST>();
+ UPDATE_POS( n, startNode, lex->index() );
+ ast->addNode( n );
+ } else
+ break;
+ }
+
+ if( ast->nodeList().count() == 0 )
+ return false;
+
+ UPDATE_POS( ast, start, lex->index() );
+ node = ast;
+ return true;
+}
+
+bool Parser::parseFunctionSpecifier( GroupAST::Node& node )
+{
+ //kdDebug(9007)<< "--- tok = " << lex->lookAhead(0).text() << " -- " << "Parser::parseFunctionSpecifier()" << endl;
+
+ int start = lex->index();
+ GroupAST::Node ast = CreateNode<GroupAST>();
+
+ while( !lex->lookAhead(0).isNull() ){
+ int tk = lex->lookAhead( 0 );
+ if( tk == Token_inline || tk == Token_virtual || tk == Token_explicit ){
+ int startNode = lex->index();
+ lex->nextToken();
+
+ AST::Node n = CreateNode<AST>();
+ UPDATE_POS( n, startNode, lex->index() );
+ ast->addNode( n );
+ } else {
+ break;
+ }
+ }
+
+ if( ast->nodeList().count() == 0 )
+ return false;
+
+ UPDATE_POS( ast, start, lex->index() );
+ node = ast;
+ return true;
+}
+
+bool Parser::parseTypeId( AST::Node& node )
+{
+ //kdDebug(9007)<< "--- tok = " << lex->lookAhead(0).text() << " -- " << "Parser::parseTypeId()" << endl;
+
+ /// @todo implement the AST for typeId
+ int start = lex->index();
+ AST::Node ast = CreateNode<AST>();
+
+ TypeSpecifierAST::Node spec;
+ if( !parseTypeSpecifier(spec) ){
+ return false;
+ }
+
+ DeclaratorAST::Node decl;
+ parseAbstractDeclarator( decl );
+
+ UPDATE_POS( ast, start, lex->index() );
+ node = ast;
+
+ return true;
+}
+
+bool Parser::parseInitDeclaratorList( InitDeclaratorListAST::Node& node )
+{
+ //kdDebug(9007)<< "--- tok = " << lex->lookAhead(0).text() << " -- " << "Parser::parseInitDeclaratorList()" << endl;
+
+ int start = lex->index();
+
+ InitDeclaratorListAST::Node ast = CreateNode<InitDeclaratorListAST>();
+ InitDeclaratorAST::Node decl;
+
+ if( !parseInitDeclarator(decl) ){
+ return false;
+ }
+ ast->addInitDeclarator( decl );
+
+ QString comment;
+ while( lex->lookAhead(0) == ',' ){
+ comment = "";
+ advanceAndCheckTrailingComment( comment );
+
+ if( !parseInitDeclarator(decl) ){
+ syntaxError();
+ break;
+ }
+ if ( !comment.isEmpty() )
+ decl->setComment( comment );
+ ast->addInitDeclarator( decl );
+ }
+ //kdDebug(9007)<< "--- tok = " << lex->lookAhead(0).text() << " -- " << "Parser::parseInitDeclaratorList() -- end" << endl;
+
+ UPDATE_POS( ast, start, lex->index() );
+ node = ast;
+
+ return true;
+}
+
+bool Parser::parseParameterDeclarationClause( ParameterDeclarationClauseAST::Node& node )
+{
+ //kdDebug(9007)<< "--- tok = " << lex->lookAhead(0).text() << " -- " << "Parser::parseParameterDeclarationClause()" << endl;
+
+ int start = lex->index();
+
+ ParameterDeclarationClauseAST::Node ast = CreateNode<ParameterDeclarationClauseAST>();
+
+ ParameterDeclarationListAST::Node params;
+ if( !parseParameterDeclarationList(params) ){
+
+ if ( lex->lookAhead(0) == ')' )
+ goto good;
+
+ if( lex->lookAhead(0) == Token_ellipsis && lex->lookAhead(1) == ')' ){
+ AST_FROM_TOKEN( ellipsis, lex->index() );
+ ast->setEllipsis( ellipsis );
+ lex->nextToken();
+ goto good;
+ }
+ return false;
+ }
+
+ if( lex->lookAhead(0) == Token_ellipsis ){
+ AST_FROM_TOKEN( ellipsis, lex->index() );
+ ast->setEllipsis( ellipsis );
+ lex->nextToken();
+ }
+
+good:
+ ast->setParameterDeclarationList( params );
+
+ /// @todo add ellipsis
+ UPDATE_POS( ast, start, lex->index() );
+ node = ast;
+
+ return true;
+}
+
+bool Parser::parseParameterDeclarationList( ParameterDeclarationListAST::Node& node )
+{
+ //kdDebug(9007)<< "--- tok = " << lex->lookAhead(0).text() << " -- " << "Parser::parseParameterDeclarationList()" << endl;
+
+ int start = lex->index();
+
+ ParameterDeclarationListAST::Node ast = CreateNode<ParameterDeclarationListAST>();
+
+ ParameterDeclarationAST::Node param;
+ if( !parseParameterDeclaration(param) ){
+ lex->setIndex( start );
+ return false;
+ }
+ ast->addParameter( param );
+
+ QString comment;
+ while( lex->lookAhead(0) == ',' ){
+ comment = QString::null;
+ advanceAndCheckTrailingComment( comment );
+
+ if( lex->lookAhead(0) == Token_ellipsis )
+ break;
+
+ if( !parseParameterDeclaration(param) ){
+ lex->setIndex( start );
+ return false;
+ }
+ if (!comment.isEmpty())
+ param->setComment(comment);
+ ast->addParameter( param );
+ }
+
+ UPDATE_POS( ast, start, lex->index() );
+ node = ast;
+
+ return true;
+}
+
+bool Parser::parseParameterDeclaration( ParameterDeclarationAST::Node& node )
+{
+ //kdDebug(9007)<< "--- tok = " << lex->lookAhead(0).text() << " -- " << "Parser::parseParameterDeclaration()" << endl;
+
+ int start = lex->index();
+
+ // parse decl spec
+ TypeSpecifierAST::Node spec;
+ if( !parseTypeSpecifier(spec) ){
+ lex->setIndex( start );
+ return false;
+ }
+
+ int index = lex->index();
+
+ DeclaratorAST::Node decl;
+ if( !parseDeclarator(decl) ){
+ lex->setIndex( index );
+
+ // try with abstract declarator
+ if( !parseAbstractDeclarator(decl) )
+ return false;
+ }
+
+ AST::Node expr;
+ if( lex->lookAhead(0) == '=' ){
+ lex->nextToken();
+ if( !parseLogicalOrExpression(expr,true) ){
+ //reportError( i18n("Expression expected") );
+ }
+ }
+
+ ParameterDeclarationAST::Node ast = CreateNode<ParameterDeclarationAST>();
+ ast->setTypeSpec( spec );
+ ast->setDeclarator( decl );
+ ast->setExpression( expr );
+
+ UPDATE_POS( ast, start, lex->index() );
+ node = ast;
+
+ return true;
+}
+
+bool Parser::parseClassSpecifier( TypeSpecifierAST::Node& node )
+{
+ //kdDebug(9007)<< "--- tok = " << lex->lookAhead(0).text() << " -- " << "Parser::parseClassSpecifier()" << endl;
+
+ int start = lex->index();
+
+ AST::Node classKey;
+ int classKeyStart = lex->index();
+
+ int kind = lex->lookAhead( 0 );
+ if( kind == Token_class || kind == Token_struct || kind == Token_union ){
+ AST::Node asn = CreateNode<AST>();
+ classKey = asn;
+ lex->nextToken();
+ UPDATE_POS( classKey, classKeyStart, lex->index() );
+ } else {
+ return false;
+ }
+
+ GroupAST::Node winDeclSpec;
+ parseWinDeclSpec( winDeclSpec );
+
+ while( lex->lookAhead(0) == Token_identifier && lex->lookAhead(1) == Token_identifier )
+ lex->nextToken();
+
+ NameAST::Node name;
+ parseName( name );
+
+ BaseClauseAST::Node bases;
+ if( lex->lookAhead(0) == ':' ){
+ if( !parseBaseClause(bases) ){
+ skipUntil( '{' );
+ }
+ }
+
+ QString comment;
+ while (lex->lookAhead(0) == Token_comment) {
+ comment += lex->lookAhead(0).text();
+ lex->nextToken();
+ }
+ if( lex->lookAhead(0) != '{' ){
+ lex->setIndex( start );
+ return false;
+ }
+
+ ADVANCE( '{', '{' );
+
+ ClassSpecifierAST::Node ast = CreateNode<ClassSpecifierAST>();
+ ast->setWinDeclSpec( winDeclSpec );
+ ast->setClassKey( classKey );
+ ast->setName( name );
+ ast->setBaseClause( bases );
+
+ while( !lex->lookAhead(0).isNull() ){
+ if( lex->lookAhead(0) == '}' )
+ break;
+
+ DeclarationAST::Node memSpec = CreateNode<DeclarationAST>();
+ int startDecl = lex->index();
+ if( !parseMemberSpecification(memSpec) ){
+ if( startDecl == lex->index() )
+ lex->nextToken(); // skip at least one token
+ skipUntilDeclaration();
+ } else
+ ast->addDeclaration( memSpec );
+ }
+
+ if( lex->lookAhead(0) != '}' ){
+ reportError( i18n("} missing") );
+ } else
+ lex->nextToken();
+
+ UPDATE_POS( ast, start, lex->index() );
+ node = ast;
+
+ return true;
+}
+
+bool Parser::parseAccessSpecifier( AST::Node& node )
+{
+ //kdDebug(9007)<< "--- tok = " << lex->lookAhead(0).text() << " -- " << "Parser::parseAccessSpecifier()" << endl;
+
+ int start = lex->index();
+
+ switch( lex->lookAhead(0) ){
+ case Token_public:
+ case Token_protected:
+ case Token_private: {
+ AST::Node asn = CreateNode<AST>();
+ node = asn;
+ lex->nextToken();
+ UPDATE_POS( node, start, lex->index() );
+ return true;
+ }
+ }
+
+ return false;
+}
+
+void Parser::advanceAndCheckTrailingComment(QString& comment)
+{
+ Token t = lex->tokenAt( lex->index() );
+ int previousTokenEndLine = 0;
+ t.getEndPosition( &previousTokenEndLine, 0 );
+ lex->nextToken();
+ if( lex->lookAhead(0) != Token_comment )
+ return;
+ t = lex->tokenAt( lex->index() );
+ int commentStartLine = 0;
+ t.getStartPosition( &commentStartLine, 0 );
+ if( commentStartLine != previousTokenEndLine )
+ return;
+ comment += lex->lookAhead(0).text();
+ lex->nextToken();
+}
+
+bool Parser::parseMemberSpecification( DeclarationAST::Node& node )
+{
+ //kdDebug(9007)<< "--- tok = " << lex->lookAhead(0).text() << " -- " << "Parser::parseMemberSpecification()" << endl;
+
+ QString comment;
+ while( lex->lookAhead(0) == Token_comment ) {
+ comment += lex->lookAhead(0).text();
+ lex->nextToken();
+ }
+ if( lex->lookAhead(0).isNull() )
+ return false;
+
+ int start = lex->index();
+
+ AST::Node access;
+
+ if( lex->lookAhead(0) == ';' ){
+ advanceAndCheckTrailingComment( comment );
+ if ( !comment.isEmpty() )
+ node->setComment( comment );
+ return true;
+ } else if( lex->lookAhead(0) == Token_Q_OBJECT || lex->lookAhead(0) == Token_K_DCOP ){
+ lex->nextToken();
+ return true;
+ } else if( lex->lookAhead(0) == Token_signals || lex->lookAhead(0) == Token_k_dcop || lex->lookAhead(0) == Token_k_dcop_signals ){
+ AccessDeclarationAST::Node ast = CreateNode<AccessDeclarationAST>();
+ lex->nextToken();
+ AST::Node n = CreateNode<AST>();
+ UPDATE_POS( n, start, lex->index() );
+ ast->addAccess( n );
+ ADVANCE( ':', ":" );
+ UPDATE_POS( ast, start, lex->index() );
+ node = ast;
+ return true;
+ } else if( parseTypedef(node) ){
+ return true;
+ } else if( parseUsing(node) ){
+ return true;
+ } else if( parseTemplateDeclaration(node) ){
+ return true;
+ } else if( parseAccessSpecifier(access) ){
+ AccessDeclarationAST::Node ast = CreateNode<AccessDeclarationAST>();
+ ast->addAccess( access );
+
+ int startSlot = lex->index();
+ if( lex->lookAhead(0) == Token_slots ){
+ lex->nextToken();
+ AST::Node sl = CreateNode<AST>();
+ UPDATE_POS( sl, startSlot, lex->index() );
+ ast->addAccess( sl );
+ }
+ ADVANCE( ':', ":" );
+ UPDATE_POS( ast, start, lex->index() );
+ node = ast;
+ return true;
+ }
+
+ lex->setIndex( start );
+
+ GroupAST::Node storageSpec;
+ parseStorageClassSpecifier( storageSpec );
+
+ GroupAST::Node cv;
+ parseCvQualify( cv );
+
+ TypeSpecifierAST::Node spec;
+ if( parseEnumSpecifier(spec) || parseClassSpecifier(spec) ){
+ spec->setCvQualify( cv );
+
+ GroupAST::Node cv2;
+ parseCvQualify( cv2 );
+ spec->setCv2Qualify( cv2 );
+
+ InitDeclaratorListAST::Node declarators;
+ parseInitDeclaratorList( declarators );
+ ADVANCE( ';', ";" );
+
+ if( !comment.isEmpty() ) {
+ //kdDebug(9007) << "Parser::parseMemberSpecification(spec): comment is " << comment << endl;
+ spec->setComment( comment );
+ }
+
+ SimpleDeclarationAST::Node ast = CreateNode<SimpleDeclarationAST>();
+ ast->setTypeSpec( spec );
+ ast->setInitDeclaratorList( declarators );
+ UPDATE_POS( ast, start, lex->index() );
+ node = ast;
+
+ return true;
+ }
+
+ lex->setIndex( start );
+
+ bool success = parseDeclarationInternal(node, comment);
+ if( success && !comment.isEmpty() ) {
+ node->setComment( comment );
+ //kdDebug(9007) << "Parser::parseMemberSpecification(): comment is " << comment << endl;
+ }
+ return success;
+}
+
+bool Parser::parseCtorInitializer( AST::Node& /*node*/ )
+{
+ //kdDebug(9007)<< "--- tok = " << lex->lookAhead(0).text() << " -- " << "Parser::parseCtorInitializer()" << endl;
+
+ if( lex->lookAhead(0) != ':' ){
+ return false;
+ }
+ lex->nextToken();
+
+ AST::Node inits;
+ if( !parseMemInitializerList(inits) ){
+ reportError( i18n("Member initializers expected") );
+ }
+
+ return true;
+}
+
+bool Parser::parseElaboratedTypeSpecifier( TypeSpecifierAST::Node& node )
+{
+ //kdDebug(9007)<< "--- tok = " << lex->lookAhead(0).text() << " -- " << "Parser::parseElaboratedTypeSpecifier()" << endl;
+
+ int start = lex->index();
+
+ int tk = lex->lookAhead( 0 );
+ if( tk == Token_class ||
+ tk == Token_struct ||
+ tk == Token_union ||
+ tk == Token_enum ||
+ tk == Token_typename )
+ {
+ AST::Node kind = CreateNode<AST>();
+ lex->nextToken();
+ UPDATE_POS( kind, start, lex->index() );
+
+ NameAST::Node name;
+
+ if( parseName(name) ){
+ ElaboratedTypeSpecifierAST::Node ast = CreateNode<ElaboratedTypeSpecifierAST>();
+ ast->setKind( kind );
+ ast->setName( name );
+ UPDATE_POS( ast, start, lex->index() );
+ node = ast;
+
+ return true;
+ }
+ }
+
+ lex->setIndex( start );
+ return false;
+}
+
+bool Parser::parseDeclaratorId( NameAST::Node& node )
+{
+ //kdDebug(9007)<< "--- tok = " << lex->lookAhead(0).text() << " -- " << "Parser::parseDeclaratorId()" << endl;
+ return parseName( node );
+}
+
+bool Parser::parseExceptionSpecification( GroupAST::Node& node )
+{
+ //kdDebug(9007)<< "--- tok = " << lex->lookAhead(0).text() << " -- " << "Parser::parseExceptionSpecification()" << endl;
+
+ if( lex->lookAhead(0) != Token_throw ){
+ return false;
+ }
+ lex->nextToken();
+
+ ADVANCE( '(', "(" );
+ if( lex->lookAhead(0) == Token_ellipsis ){
+ // extension found in MSVC++ 7.x headers
+ int start = lex->index();
+ GroupAST::Node ast = CreateNode<GroupAST>();
+ AST_FROM_TOKEN( ellipsis, lex->index() );
+ ast->addNode( ellipsis );
+ lex->nextToken();
+ UPDATE_POS( ast, start, lex->index() );
+ node = ast;
+ } else {
+ parseTypeIdList( node );
+ }
+ ADVANCE( ')', ")" );
+
+ return true;
+}
+
+bool Parser::parseEnumerator( EnumeratorAST::Node& node )
+{
+ //kdDebug(9007)<< "--- tok = " << lex->lookAhead(0).text() << " -- " << "Parser::parseEnumerator()" << endl;
+
+ QString comment;
+ while( lex->lookAhead(0) == Token_comment ) {
+ comment += lex->lookAhead(0).text();
+ lex->nextToken();
+ }
+ if( lex->lookAhead(0).isNull() )
+ return false;
+
+ int start = lex->index();
+
+ if( lex->lookAhead(0) != Token_identifier ){
+ return false;
+ }
+ lex->nextToken();
+
+ EnumeratorAST::Node ena = CreateNode<EnumeratorAST>();
+ node = ena;
+
+ AST::Node id = CreateNode<AST>();
+ UPDATE_POS( id, start, lex->index() );
+ node->setId( id );
+
+ if( lex->lookAhead(0) == '=' ){
+ lex->nextToken();
+
+ AST::Node expr;
+ if( !parseConstantExpression(expr) ){
+ reportError( i18n("Constant expression expected") );
+ }
+ node->setExpr( expr );
+ }
+
+ UPDATE_POS( node, start, lex->index() );
+
+ return true;
+}
+
+bool Parser::parseInitDeclarator( InitDeclaratorAST::Node& node )
+{
+ //kdDebug(9007)<< "--- tok = " << lex->lookAhead(0).text() << " -- " << "Parser::parseInitDeclarator()" << endl;
+
+ int start = lex->index();
+
+ DeclaratorAST::Node decl;
+ AST::Node init;
+ if( !parseDeclarator(decl) ){
+ return false;
+ }
+
+ parseInitializer( init );
+
+ InitDeclaratorAST::Node ast = CreateNode<InitDeclaratorAST>();
+ ast->setDeclarator( decl );
+ ast->setInitializer( init );
+ UPDATE_POS( ast, start, lex->index() );
+ node = ast;
+
+ return true;
+}
+
+
+
+bool Parser::parseBaseClause( BaseClauseAST::Node& node )
+{
+ //kdDebug(9007)<< "--- tok = " << lex->lookAhead(0).text() << " -- " << "Parser::parseBaseClause()" << endl;
+
+ int start = lex->index();
+ if( lex->lookAhead(0) != ':' ){
+ return false;
+ }
+ lex->nextToken();
+
+ BaseClauseAST::Node bca = CreateNode<BaseClauseAST>();
+
+ BaseSpecifierAST::Node baseSpec;
+ if( parseBaseSpecifier(baseSpec) ){
+ bca->addBaseSpecifier( baseSpec );
+
+ QString comment;
+ while( lex->lookAhead(0) == ',' ){
+ comment = QString::null;
+ advanceAndCheckTrailingComment( comment );
+
+ if( !parseBaseSpecifier(baseSpec) ){
+ reportError( i18n("Base class specifier expected") );
+ return false;
+ }
+ if (!comment.isEmpty())
+ baseSpec->setComment(comment);
+ bca->addBaseSpecifier( baseSpec );
+ }
+ } else
+ return false;
+
+ UPDATE_POS( bca, start, lex->index() );
+ node = bca;
+
+ return true;
+}
+
+bool Parser::parseInitializer( AST::Node& node )
+{
+ //kdDebug(9007)<< "--- tok = " << lex->lookAhead(0).text() << " -- " << "Parser::parseInitializer()" << endl;
+
+ if( lex->lookAhead(0) == '=' ){
+ lex->nextToken();
+
+ AST::Node init;
+ if( !parseInitializerClause(node) ){
+ reportError( i18n("Initializer clause expected") );
+ return false;
+ }
+ } else if( lex->lookAhead(0) == '(' ){
+ lex->nextToken();
+ AST::Node expr;
+ skipCommaExpression( expr );
+
+ ADVANCE( ')', ")" );
+ }
+
+ return false;
+}
+
+bool Parser::parseMemInitializerList( AST::Node& /*node*/ )
+{
+ //kdDebug(9007)<< "--- tok = " << lex->lookAhead(0).text() << " -- " << "Parser::parseMemInitializerList()" << endl;
+
+ AST::Node init;
+ if( !parseMemInitializer(init) ){
+ return false;
+ }
+
+ QString comment;
+ while( lex->lookAhead(0) == ',' ){
+ comment = QString::null;
+ advanceAndCheckTrailingComment( comment );
+
+ if( parseMemInitializer(init) ){
+ } else {
+ break;
+ }
+ }
+
+ return true;
+}
+
+bool Parser::parseMemInitializer( AST::Node& /*node*/ )
+{
+ //kdDebug(9007)<< "--- tok = " << lex->lookAhead(0).text() << " -- " << "Parser::parseMemInitializer()" << endl;
+
+ NameAST::Node initId;
+ if( !parseMemInitializerId(initId) ){
+ reportError( i18n("Identifier expected") );
+ return false;
+ }
+ ADVANCE( '(', '(' );
+ AST::Node expr;
+ skipCommaExpression( expr );
+ ADVANCE( ')', ')' );
+
+ return true;
+}
+
+bool Parser::parseTypeIdList( GroupAST::Node& node )
+{
+ //kdDebug(9007)<< "--- tok = " << lex->lookAhead(0).text() << " -- " << "Parser::parseTypeIdList()" << endl;
+
+ int start = lex->index();
+
+ AST::Node typeId;
+ if( !parseTypeId(typeId) ){
+ return false;
+ }
+
+ GroupAST::Node ast = CreateNode<GroupAST>();
+ ast->addNode( typeId );
+
+ QString comment;
+ while( lex->lookAhead(0) == ',' ){
+ comment = QString::null;
+ advanceAndCheckTrailingComment( comment );
+ if( parseTypeId(typeId) ){
+ if (!comment.isEmpty())
+ typeId->setComment(comment);
+ ast->addNode( typeId );
+ } else {
+ reportError( i18n("Type id expected") );
+ break;
+ }
+ }
+
+ UPDATE_POS( ast, start, lex->index() );
+ node = ast;
+ return true;
+}
+
+bool Parser::parseBaseSpecifier( BaseSpecifierAST::Node& node )
+{
+ //kdDebug(9007)<< "--- tok = " << lex->lookAhead(0).text() << " -- " << "Parser::parseBaseSpecifier()" << endl;
+
+ int start = lex->index();
+ BaseSpecifierAST::Node ast = CreateNode<BaseSpecifierAST>();
+
+ AST::Node access;
+ if( lex->lookAhead(0) == Token_virtual ){
+ AST_FROM_TOKEN( virt, lex->index() );
+ ast->setIsVirtual( virt );
+
+ lex->nextToken();
+
+ parseAccessSpecifier( access );
+ } else {
+ parseAccessSpecifier( access );
+
+ if( lex->lookAhead(0) == Token_virtual ){
+ AST_FROM_TOKEN( virt, lex->index() );
+ ast->setIsVirtual( virt );
+ lex->nextToken();
+ }
+ }
+
+ NameAST::Node name;
+ if( !parseName(name) ){
+ reportError( i18n("Class name expected") );
+ }
+
+ ast->setAccess( access );
+ ast->setName( name );
+ UPDATE_POS( ast, start, lex->index() );
+ node = ast;
+
+ return true;
+}
+
+
+bool Parser::parseInitializerClause( AST::Node& node )
+{
+ //kdDebug(9007)<< "--- tok = " << lex->lookAhead(0).text() << " -- " << "Parser::parseInitializerClause()" << endl;
+
+ if( lex->lookAhead(0) == '{' ){
+ if( !skip('{','}') ){
+ reportError( i18n("} missing") );
+ } else
+ lex->nextToken();
+ } else {
+ if( !parseAssignmentExpression(node) ){
+ //reportError( i18n("Expression expected") );
+ }
+ }
+
+ return true;
+}
+
+bool Parser::parseMemInitializerId( NameAST::Node& node )
+{
+ //kdDebug(9007)<< "--- tok = " << lex->lookAhead(0).text() << " -- " << "Parser::parseMemInitializerId()" << endl;
+
+ return parseName( node );
+}
+
+bool Parser::parsePtrToMember( AST::Node& /*node*/ )
+{
+ //kdDebug(9007)<< "--- tok = " << lex->lookAhead(0).text() << " -- " << "Parser::parsePtrToMember()" << endl;
+
+ if( lex->lookAhead(0) == Token_scope ){
+ lex->nextToken();
+ }
+
+ while( lex->lookAhead(0) == Token_identifier ){
+ lex->nextToken();
+
+ if( lex->lookAhead(0) == Token_scope && lex->lookAhead(1) == '*' ){
+ lex->nextToken(); // skip ::
+ lex->nextToken(); // skip *
+ return true;
+ } else
+ break;
+ }
+
+ return false;
+}
+
+bool Parser::parseUnqualifiedName( ClassOrNamespaceNameAST::Node& node )
+{
+ //kdDebug(9007)<< "--- tok = " << lex->lookAhead(0).text() << " -- " << "Parser::parseUnqualifiedName()" << endl;
+
+ int start = lex->index();
+ bool isDestructor = false;
+
+ ClassOrNamespaceNameAST::Node ast = CreateNode<ClassOrNamespaceNameAST>();
+
+ if( lex->lookAhead(0) == Token_identifier ){
+ int startName = lex->index();
+ AST::Node n = CreateNode<AST>();
+ lex->nextToken();
+ UPDATE_POS( n, startName, lex->index() );
+ ast->setName( n );
+ } else if( lex->lookAhead(0) == '~' && lex->lookAhead(1) == Token_identifier ){
+ int startName = lex->index();
+ AST::Node n = CreateNode<AST>();
+ lex->nextToken(); // skip ~
+ lex->nextToken(); // skip classname
+ UPDATE_POS( n, startName, lex->index() );
+ ast->setName( n );
+ isDestructor = true;
+ } else if( lex->lookAhead(0) == Token_operator ){
+ AST::Node n;
+ if( !parseOperatorFunctionId(n) )
+ return false;
+ ast->setName( n );
+ } else {
+ return false;
+ }
+
+ if( !isDestructor ){
+
+ int index = lex->index();
+
+ if( lex->lookAhead(0) == '<' ){
+ lex->nextToken();
+
+ // optional template arguments
+ TemplateArgumentListAST::Node args;
+ parseTemplateArgumentList( args );
+
+ if( lex->lookAhead(0) != '>' ){
+ lex->setIndex( index );
+ } else {
+ lex->nextToken();
+ ast->setTemplateArgumentList( args );
+ }
+ }
+ }
+
+ UPDATE_POS( ast, start, lex->index() );
+ node = ast;
+
+ return true;
+}
+
+bool Parser::parseStringLiteral( AST::Node& /*node*/ )
+{
+ while( !lex->lookAhead(0).isNull() ) {
+ if( lex->lookAhead(0) == Token_identifier &&
+ lex->lookAhead(0).text() == "L" && lex->lookAhead(1) == Token_string_literal ) {
+
+ lex->nextToken();
+ lex->nextToken();
+ } else if( lex->lookAhead(0) == Token_string_literal ) {
+ lex->nextToken();
+ } else
+ return false;
+ }
+ return true;
+}
+
+bool Parser::skipExpressionStatement( StatementAST::Node& node )
+{
+ //kdDebug(9007)<< "--- tok = " << lex->lookAhead(0).text() << " -- " << "Parser::skipExpressionStatement()" << endl;
+
+ int start = lex->index();
+
+ AST::Node expr;
+ skipCommaExpression( expr );
+
+ ADVANCE( ';', ";" );
+
+ ExpressionStatementAST::Node ast = CreateNode<ExpressionStatementAST>();
+ ast->setExpression( expr );
+ UPDATE_POS( ast, start, lex->index() );
+ node = ast;
+
+ return true;
+}
+
+bool Parser::parseStatement( StatementAST::Node& node ) // thanks to fiore@8080.it ;)
+{
+ //kdDebug(9007)<< "--- tok = " << lex->lookAhead(0).text() << " -- " << "Parser::parseStatement()" << endl;
+ switch( lex->lookAhead(0) ){
+
+ case Token_while:
+ return parseWhileStatement( node );
+
+ case Token_do:
+ return parseDoStatement( node );
+
+ case Token_for:
+ return parseForStatement( node );
+
+ case Token_if:
+ return parseIfStatement( node );
+
+ case Token_switch:
+ return parseSwitchStatement( node );
+
+ case Token_try:
+ return parseTryBlockStatement( node );
+
+ case Token_case:
+ case Token_default:
+ return parseLabeledStatement( node );
+
+ case Token_break:
+ case Token_continue:
+ lex->nextToken();
+ ADVANCE( ';', ";" );
+ return true;
+
+ case Token_goto:
+ lex->nextToken();
+ ADVANCE( Token_identifier, "identifier" );
+ ADVANCE( ';', ";" );
+ return true;
+
+ case Token_return:
+ {
+ lex->nextToken();
+ AST::Node expr;
+ skipCommaExpression( expr );
+ ADVANCE( ';', ";" );
+ }
+ return true;
+
+ case '{':
+ return parseCompoundStatement( node );
+
+ case Token_identifier:
+ if( parseLabeledStatement(node) )
+ return true;
+ break;
+ }
+
+ //kdDebug(9007)<< "------------> try with declaration statement" << endl;
+ if ( parseDeclarationStatement(node) )
+ return true;
+
+ return skipExpressionStatement( node );
+}
+
+bool Parser::parseCondition( ConditionAST::Node& node )
+{
+ //kdDebug(9007)<< "--- tok = " << lex->lookAhead(0).text() << " -- " << "Parser::parseCondition()" << endl;
+
+ int start = lex->index();
+
+ ConditionAST::Node ast = CreateNode<ConditionAST>();
+
+ TypeSpecifierAST::Node spec;
+ if( parseTypeSpecifier(spec) ){
+ DeclaratorAST::Node decl;
+ if( parseDeclarator(decl) && lex->lookAhead(0) == '=' ) {
+ lex->nextToken();
+
+ AST::Node expr;
+ if( skipExpression(expr) ){
+ ast->setTypeSpec( spec );
+ ast->setDeclarator( decl );
+ ast->setExpression( expr );
+
+ UPDATE_POS( ast, start, lex->index() );
+ node = ast;
+
+ return true;
+ }
+ }
+ }
+
+ lex->setIndex( start );
+
+ AST::Node expr;
+ if( !skipCommaExpression(expr) )
+ return false;
+
+ ast->setExpression( expr );
+ UPDATE_POS( ast, start, lex->index() );
+ node = ast;
+ return true;
+}
+
+
+bool Parser::parseWhileStatement( StatementAST::Node& node )
+{
+ //kdDebug(9007)<< "--- tok = " << lex->lookAhead(0).text() << " -- " << "Parser::parseWhileStatement()" << endl;
+ int start = lex->index();
+
+ ADVANCE( Token_while, "while" );
+ ADVANCE( '(' , "(" );
+
+ ConditionAST::Node cond;
+ if( !parseCondition(cond) ){
+ reportError( i18n("condition expected") );
+ return false;
+ }
+ ADVANCE( ')', ")" );
+
+ StatementAST::Node body;
+ if( !parseStatement(body) ){
+ reportError( i18n("statement expected") );
+ return false;
+ }
+
+ WhileStatementAST::Node ast = CreateNode<WhileStatementAST>();
+ ast->setCondition( cond );
+ ast->setStatement( body );
+ UPDATE_POS( ast, start, lex->index() );
+ node = ast;
+
+ return true;
+}
+
+bool Parser::parseDoStatement( StatementAST::Node& node )
+{
+ //kdDebug(9007)<< "--- tok = " << lex->lookAhead(0).text() << " -- " << "Parser::parseDoStatement()" << endl;
+ int start = lex->index();
+
+ ADVANCE( Token_do, "do" );
+
+ StatementAST::Node body;
+ if( !parseStatement(body) ){
+ reportError( i18n("statement expected") );
+ //return false;
+ }
+
+ ADVANCE_NR( Token_while, "while" );
+ ADVANCE_NR( '(' , "(" );
+
+ AST::Node expr;
+ if( !skipCommaExpression(expr) ){
+ reportError( i18n("expression expected") );
+ //return false;
+ }
+
+ ADVANCE_NR( ')', ")" );
+ ADVANCE_NR( ';', ";" );
+
+ DoStatementAST::Node ast = CreateNode<DoStatementAST>();
+ ast->setStatement( body );
+ //ast->setCondition( condition );
+ UPDATE_POS( ast, start, lex->index() );
+ node = ast;
+
+ return true;
+}
+
+bool Parser::parseForStatement( StatementAST::Node& node )
+{
+ //kdDebug(9007)<< "--- tok = " << lex->lookAhead(0).text() << " -- " << "Parser::parseForStatement()" << endl;
+ int start = lex->index();
+
+ ADVANCE( Token_for, "for" );
+ ADVANCE( '(', "(" );
+
+ StatementAST::Node init;
+ if( !parseForInitStatement(init) ){
+ reportError( i18n("for initialization expected") );
+ return false;
+ }
+
+ ConditionAST::Node cond;
+ parseCondition( cond );
+ ADVANCE( ';', ";" );
+
+ AST::Node expr;
+ skipCommaExpression( expr );
+ ADVANCE( ')', ")" );
+
+ StatementAST::Node body;
+ if( !parseStatement(body) )
+ return false;
+
+ ForStatementAST::Node ast = CreateNode<ForStatementAST>();
+ ast->setInitStatement( init );
+ ast->setCondition( cond );
+ // ast->setExpression( expression );
+ ast->setStatement( body );
+ UPDATE_POS( ast, start, lex->index() );
+ node = ast;
+
+ return true;
+}
+
+bool Parser::parseForInitStatement( StatementAST::Node& node )
+{
+ //kdDebug(9007)<< "--- tok = " << lex->lookAhead(0).text() << " -- " << "Parser::parseForInitStatement()" << endl;
+
+ if ( parseDeclarationStatement(node) )
+ return true;
+
+ return skipExpressionStatement( node );
+}
+
+bool Parser::parseCompoundStatement( StatementAST::Node& node )
+{
+ //kdDebug(9007)<< "--- tok = " << lex->lookAhead(0).text() << " -- " << "Parser::parseCompoundStatement()" << endl;
+ int start = lex->index();
+
+ if( lex->lookAhead(0) != '{' ){
+ return false;
+ }
+ lex->nextToken();
+
+ StatementListAST::Node ast = CreateNode<StatementListAST>();
+
+ while( !lex->lookAhead(0).isNull() ){
+ if( lex->lookAhead(0) == '}' )
+ break;
+
+ StatementAST::Node stmt;
+ int startStmt = lex->index();
+ if( !parseStatement(stmt) ){
+ if( startStmt == lex->index() )
+ lex->nextToken();
+ skipUntilStatement();
+ } else {
+ ast->addStatement( stmt );
+ }
+ }
+
+ if( lex->lookAhead(0) != '}' ){
+ reportError( i18n("} expected") );
+ } else {
+ lex->nextToken();
+ }
+
+ UPDATE_POS( ast, start, lex->index() );
+ node = ast;
+
+ return true;
+}
+
+bool Parser::parseIfStatement( StatementAST::Node& node )
+{
+ //kdDebug(9007)<< "--- tok = " << lex->lookAhead(0).text() << " -- " << "Parser::parseIfStatement()" << endl;
+
+ int start = lex->index();
+
+ ADVANCE( Token_if, "if" );
+
+ ADVANCE( '(' , "(" );
+
+ IfStatementAST::Node ast = CreateNode<IfStatementAST>();
+
+ ConditionAST::Node cond;
+ if( !parseCondition(cond) ){
+ reportError( i18n("condition expected") );
+ return false;
+ }
+ ADVANCE( ')', ")" );
+
+ StatementAST::Node stmt;
+ if( !parseStatement(stmt) ){
+ reportError( i18n("statement expected") );
+ return false;
+ }
+
+ ast->setCondition( cond );
+ ast->setStatement( stmt );
+
+ if( lex->lookAhead(0) == Token_else ){
+ lex->nextToken();
+ StatementAST::Node elseStmt;
+ if( !parseStatement(elseStmt) ) {
+ reportError( i18n("statement expected") );
+ return false;
+ }
+ ast->setElseStatement( elseStmt );
+ }
+
+ UPDATE_POS( ast, start, lex->index() );
+ node = ast;
+
+ return true;
+}
+
+bool Parser::parseSwitchStatement( StatementAST::Node& node )
+{
+ //kdDebug(9007)<< "--- tok = " << lex->lookAhead(0).text() << " -- " << "Parser::parseSwitchStatement()" << endl;
+ int start = lex->index();
+ ADVANCE( Token_switch, "switch" );
+
+ ADVANCE( '(' , "(" );
+
+ ConditionAST::Node cond;
+ if( !parseCondition(cond) ){
+ reportError( i18n("condition expected") );
+ return false;
+ }
+ ADVANCE( ')', ")" );
+
+ StatementAST::Node stmt;
+ if( !parseCompoundStatement(stmt) ){
+ syntaxError();
+ return false;
+ }
+
+ SwitchStatementAST::Node ast = CreateNode<SwitchStatementAST>();
+ ast->setCondition( cond );
+ ast->setStatement( stmt );
+ UPDATE_POS( ast, start, lex->index() );
+ node = ast;
+
+ return true;
+}
+
+bool Parser::parseLabeledStatement( StatementAST::Node& node )
+{
+ //kdDebug(9007)<< "--- tok = " << lex->lookAhead(0).text() << " -- " << "Parser::parseLabeledStatement()" << endl;
+ switch( lex->lookAhead(0) ){
+ case Token_identifier:
+ case Token_default:
+ if( lex->lookAhead(1) == ':' ){
+ lex->nextToken();
+ lex->nextToken();
+
+ StatementAST::Node stmt;
+ if( parseStatement(stmt) ){
+ node = stmt;
+ return true;
+ }
+ }
+ break;
+
+ case Token_case:
+ {
+ lex->nextToken();
+ AST::Node expr;
+ if( !parseConstantExpression(expr) ){
+ reportError( i18n("expression expected") );
+ } else if( lex->lookAhead(0) == Token_ellipsis ){
+ lex->nextToken();
+
+ AST::Node expr2;
+ if( !parseConstantExpression(expr2) ){
+ reportError( i18n("expression expected") );
+ }
+ }
+ ADVANCE( ':', ":" );
+
+ StatementAST::Node stmt;
+ if( parseStatement(stmt) ){
+ node = stmt;
+ return true;
+ }
+ }
+ break;
+
+ }
+
+ return false;
+}
+
+bool Parser::parseBlockDeclaration( DeclarationAST::Node& node )
+{
+ //kdDebug(9007)<< "--- tok = " << lex->lookAhead(0).text() << " -- " << "Parser::parseBlockDeclaration()" << endl;
+ switch( lex->lookAhead(0) ) {
+ case Token_typedef:
+ return parseTypedef( node );
+ case Token_using:
+ return parseUsing( node );
+ case Token_asm:
+ return parseAsmDefinition( node );
+ case Token_namespace:
+ return parseNamespaceAliasDefinition( node );
+ }
+
+ int start = lex->index();
+
+ GroupAST::Node storageSpec;
+ parseStorageClassSpecifier( storageSpec );
+
+ GroupAST::Node cv;
+ parseCvQualify( cv );
+
+ TypeSpecifierAST::Node spec;
+ if ( !parseTypeSpecifierOrClassSpec(spec) ) { // replace with simpleTypeSpecifier?!?!
+ lex->setIndex( start );
+ return false;
+ }
+ spec->setCvQualify( cv );
+
+ GroupAST::Node cv2;
+ parseCvQualify( cv2 );
+ spec->setCv2Qualify( cv2 );
+
+ InitDeclaratorListAST::Node declarators;
+ parseInitDeclaratorList( declarators );
+
+ if( lex->lookAhead(0) != ';' ){
+ lex->setIndex( start );
+ return false;
+ }
+ lex->nextToken();
+
+ SimpleDeclarationAST::Node ast = CreateNode<SimpleDeclarationAST>();
+ ast->setTypeSpec( spec );
+ ast->setInitDeclaratorList( declarators );
+ UPDATE_POS( ast, start, lex->index() );
+ node = ast;
+
+ return true;
+}
+
+bool Parser::parseNamespaceAliasDefinition( DeclarationAST::Node& /*node*/ )
+{
+ if ( lex->lookAhead(0) != Token_namespace ) {
+ return false;
+ }
+ lex->nextToken();
+
+ ADVANCE( Token_identifier, "identifier" );
+ ADVANCE( '=', "=" );
+
+ NameAST::Node name;
+ if( !parseName(name) ){
+ reportError( i18n("Namespace name expected") );
+ }
+
+ ADVANCE( ';', ";" );
+
+ return true;
+
+}
+
+bool Parser::parseDeclarationStatement( StatementAST::Node& node )
+{
+ //kdDebug(9007)<< "--- tok = " << lex->lookAhead(0).text() << " -- " << "Parser::parseDeclarationStatement()" << endl;
+
+ int start = lex->index();
+
+ DeclarationAST::Node decl;
+ if ( !parseBlockDeclaration(decl) ){
+ return false;
+ }
+
+ DeclarationStatementAST::Node ast = CreateNode<DeclarationStatementAST>();
+ ast->setDeclaration( decl );
+ UPDATE_POS( ast, start, lex->index() );
+ node = ast;
+
+ //kdDebug(9007)<< "---------------------> found a block declaration" << endl;
+ return true;
+}
+
+bool Parser::parseDeclarationInternal( DeclarationAST::Node& node, QString& comment )
+{
+ //kdDebug(9007)<< "--- tok = " << lex->lookAhead(0).text() << " -- " << "Parser::parseDeclarationInternal()" << endl;
+
+ int start = lex->index();
+
+ // that is for the case '__declspec(dllexport) int ...' or
+ // '__declspec(dllexport) inline int ...', etc.
+ GroupAST::Node winDeclSpec;
+ parseWinDeclSpec( winDeclSpec );
+
+ GroupAST::Node funSpec;
+ bool hasFunSpec = parseFunctionSpecifier( funSpec );
+
+ GroupAST::Node storageSpec;
+ bool hasStorageSpec = parseStorageClassSpecifier( storageSpec );
+
+ if( hasStorageSpec && !hasFunSpec )
+ hasFunSpec = parseFunctionSpecifier( funSpec );
+
+ // that is for the case 'friend __declspec(dllexport) ....'
+ GroupAST::Node winDeclSpec2;
+ parseWinDeclSpec( winDeclSpec2 );
+
+ GroupAST::Node cv;
+ parseCvQualify( cv );
+
+ int index = lex->index();
+ NameAST::Node name;
+ if( parseName(name) && lex->lookAhead(0) == '(' ){
+ // no type specifier, maybe a constructor or a cast operator??
+
+ lex->setIndex( index );
+
+ InitDeclaratorAST::Node declarator;
+ if( parseInitDeclarator(declarator) ){
+ int endSignature = lex->index();
+
+ switch( lex->lookAhead(0) ){
+ case ';':
+ {
+ lex->nextToken();
+
+ InitDeclaratorListAST::Node declarators = CreateNode<InitDeclaratorListAST>();
+
+ // update declarators position
+ int startLine, startColumn, endLine, endColumn;
+ if( declarator.get() ){
+ declarator->getStartPosition( &startLine, &startColumn );
+ declarator->getEndPosition( &endLine, &endColumn );
+ declarators->setStartPosition( startLine, startColumn );
+ declarators->setEndPosition( endLine, endColumn );
+ }
+ declarators->addInitDeclarator( declarator );
+
+ SimpleDeclarationAST::Node ast = CreateNode<SimpleDeclarationAST>();
+ ast->setInitDeclaratorList( declarators );
+ ast->setText( toString(start, endSignature) );
+ node = ast;
+ UPDATE_POS( node, start, lex->index() );
+ return true;
+
+ }
+ break;
+
+ case ':':
+ {
+ AST::Node ctorInit;
+ StatementListAST::Node funBody;
+ if( parseCtorInitializer(ctorInit) && parseFunctionBody(funBody) ){
+ FunctionDefinitionAST::Node ast = CreateNode<FunctionDefinitionAST>();
+ ast->setStorageSpecifier( storageSpec );
+ ast->setFunctionSpecifier( funSpec );
+ ast->setInitDeclarator( declarator );
+ ast->setFunctionBody( funBody );
+ ast->setText( toString(start, endSignature) );
+ node = ast;
+ UPDATE_POS( node, start, lex->index() );
+ return true;
+ }
+ }
+ break;
+
+ case '{':
+ {
+ StatementListAST::Node funBody;
+ if( parseFunctionBody(funBody) ){
+ FunctionDefinitionAST::Node ast = CreateNode<FunctionDefinitionAST>();
+ ast->setStorageSpecifier( storageSpec );
+ ast->setFunctionSpecifier( funSpec );
+ ast->setInitDeclarator( declarator );
+ ast->setText( toString(start, endSignature) );
+ ast->setFunctionBody( funBody );
+ node = ast;
+ UPDATE_POS( node, start, lex->index() );
+ return true;
+ }
+ }
+ break;
+
+ case '(':
+ case '[':
+ // ops!! it seems a declarator
+ goto start_decl;
+ break;
+ }
+
+ }
+
+ syntaxError();
+ return false;
+ }
+
+start_decl:
+ lex->setIndex( index );
+
+ if( lex->lookAhead(0) == Token_const && lex->lookAhead(1) == Token_identifier && lex->lookAhead(2) == '=' ){
+ // constant definition
+ lex->nextToken();
+ InitDeclaratorListAST::Node declarators;
+ if( parseInitDeclaratorList(declarators) ){
+ ADVANCE( ';', ";" );
+ DeclarationAST::Node ast = CreateNode<DeclarationAST>();
+ node = ast;
+ UPDATE_POS( node, start, lex->index() );
+ return true;
+ }
+ syntaxError();
+ return false;
+ }
+
+ TypeSpecifierAST::Node spec;
+ if( parseTypeSpecifier(spec) ){
+ if ( !hasFunSpec )
+ parseFunctionSpecifier( funSpec ); // e.g. "void inline"
+ spec->setCvQualify( cv );
+
+ InitDeclaratorListAST::Node declarators;
+
+ InitDeclaratorAST::Node decl;
+ int startDeclarator = lex->index();
+ bool maybeFunctionDefinition = false;
+
+ if( lex->lookAhead(0) != ';' ){
+ if( parseInitDeclarator(decl) && lex->lookAhead(0) == '{' ){
+ // function definition
+ maybeFunctionDefinition = true;
+ } else {
+ lex->setIndex( startDeclarator );
+ if( !parseInitDeclaratorList(declarators) ){
+ syntaxError();
+ return false;
+ }
+ }
+ }
+
+ int endSignature = lex->index();
+ switch( lex->lookAhead(0) ){
+ case ';':
+ {
+ advanceAndCheckTrailingComment( comment );
+ SimpleDeclarationAST::Node ast = CreateNode<SimpleDeclarationAST>();
+ ast->setStorageSpecifier( storageSpec );
+ ast->setFunctionSpecifier( funSpec );
+ ast->setText( toString(start, endSignature) );
+ ast->setTypeSpec( spec );
+ ast->setWinDeclSpec( winDeclSpec );
+ ast->setInitDeclaratorList( declarators );
+ node = ast;
+ UPDATE_POS( node, start, lex->index() );
+ }
+ return true;
+
+ case '{':
+ {
+ if( !maybeFunctionDefinition ){
+ syntaxError();
+ return false;
+ }
+ StatementListAST::Node funBody;
+ if ( parseFunctionBody(funBody) ) {
+ FunctionDefinitionAST::Node ast = CreateNode<FunctionDefinitionAST>();
+ ast->setWinDeclSpec( winDeclSpec );
+ ast->setStorageSpecifier( storageSpec );
+ ast->setFunctionSpecifier( funSpec );
+ ast->setText( toString(start, endSignature) );
+ ast->setTypeSpec( spec );
+ ast->setFunctionBody( funBody );
+ ast->setInitDeclarator( decl );
+ node = ast;
+ UPDATE_POS( node, start, lex->index() );
+ return true;
+ }
+ }
+ break;
+
+ }
+ }
+
+ syntaxError();
+ return false;
+}
+
+bool Parser::parseFunctionBody( StatementListAST::Node& node )
+{
+ //kdDebug(9007)<< "--- tok = " << lex->lookAhead(0).text() << " -- " << "Parser::parseFunctionBody()" << endl;
+
+ int start = lex->index();
+ if( lex->lookAhead(0) != '{' ){
+ return false;
+ }
+ lex->nextToken();
+
+ StatementListAST::Node ast = CreateNode<StatementListAST>();
+
+ while( !lex->lookAhead(0).isNull() ){
+ if( lex->lookAhead(0) == '}' )
+ break;
+
+ StatementAST::Node stmt;
+ int startStmt = lex->index();
+ if( !parseStatement(stmt) ){
+ if( startStmt == lex->index() )
+ lex->nextToken();
+ skipUntilStatement();
+ } else
+ ast->addStatement( stmt );
+ }
+
+ if( lex->lookAhead(0) != '}' ){
+ reportError( i18n("} expected") );
+ } else
+ lex->nextToken();
+
+ UPDATE_POS( ast, start, lex->index() );
+ node = ast;
+
+ return true;
+}
+
+QString Parser::toString( int start, int end, const QString& sep ) const
+{
+ QStringList l;
+
+ for( int i=start; i<end; ++i ){
+ l << lex->tokenAt(i).text();
+ }
+
+ return l.join( sep ).stripWhiteSpace();
+}
+
+bool Parser::parseTypeSpecifierOrClassSpec( TypeSpecifierAST::Node& node )
+{
+ if( parseClassSpecifier(node) )
+ return true;
+ else if( parseEnumSpecifier(node) )
+ return true;
+ else if( parseTypeSpecifier(node) )
+ return true;
+
+ return false;
+}
+
+bool Parser::parseTryBlockStatement( StatementAST::Node& node )
+{
+ //kdDebug(9007)<< "--- tok = " << lex->lookAhead(0).text() << " -- " << "Parser::parseTryBlockStatement()" << endl;
+
+ if( lex->lookAhead(0) != Token_try ){
+ return false;
+ }
+ lex->nextToken();
+
+ StatementAST::Node stmt;
+ if( !parseCompoundStatement(stmt) ){
+ syntaxError();
+ return false;
+ }
+
+ if( lex->lookAhead(0) != Token_catch ){
+ reportError( i18n("catch expected") );
+ return false;
+ }
+
+ while( lex->lookAhead(0) == Token_catch ){
+ lex->nextToken();
+ ADVANCE( '(', "(" );
+ ConditionAST::Node cond;
+ if( !parseCondition(cond) ){
+ reportError( i18n("condition expected") );
+ return false;
+ }
+ ADVANCE( ')', ")" );
+
+ StatementAST::Node body;
+ if( !parseCompoundStatement(body) ){
+ syntaxError();
+ return false;
+ }
+ }
+
+ node = stmt;
+ return true;
+}
+
+bool Parser::parsePrimaryExpression( AST::Node& /*node*/ )
+{
+ //kdDebug(9007)<< "--- tok = " << lex->lookAhead(0).text() << " -- " << "Parser::parsePrimarExpression()" << endl;
+
+
+ switch( lex->lookAhead(0) ){
+ case Token_string_literal:
+ {
+ AST::Node lit;
+ parseStringLiteral( lit );
+ }
+ return true;
+
+ case Token_number_literal:
+ case Token_char_literal:
+ case Token_true:
+ case Token_false:
+ lex->nextToken();
+ return true;
+
+ case Token_this:
+ lex->nextToken();
+ return true;
+
+ case Token_dynamic_cast:
+ case Token_static_cast:
+ case Token_reinterpret_cast:
+ case Token_const_cast:
+ {
+ lex->nextToken();
+
+ CHECK( '<', "<" );
+ AST::Node typeId;
+ parseTypeId( typeId );
+ CHECK( '>', ">" );
+
+ CHECK( '(', "(" );
+ AST::Node expr;
+ parseCommaExpression( expr );
+ CHECK( ')', ")" );
+ }
+ return true;
+
+ case Token_typeid:
+ {
+ lex->nextToken();
+ CHECK( '(', "(" );
+ AST::Node expr;
+ parseCommaExpression( expr );
+ CHECK( ')', ")" );
+ }
+ return true;
+
+ case '(':
+ {
+ lex->nextToken();
+ //kdDebug(9007)<< "--- tok = " << lex->lookAhead(0).text() << " -- " << "token = " << lex->lookAhead(0).text() << endl;
+ AST::Node expr;
+ if( !parseExpression(expr) ){
+ return false;
+ }
+ CHECK( ')', ")" );
+ }
+ return true;
+
+ default:
+ {
+ int start = lex->index();
+ TypeSpecifierAST::Node typeSpec;
+ if( parseSimpleTypeSpecifier(typeSpec) && lex->lookAhead(0) == '(' ){
+ lex->nextToken();
+ AST::Node expr;
+ parseCommaExpression( expr );
+ CHECK( ')', ")" );
+ return true;
+ }
+
+ lex->setIndex( start );
+ NameAST::Node name;
+ if( parseName(name) )
+ return true;
+ }
+ }
+
+ return false;
+}
+
+bool Parser::parsePostfixExpression( AST::Node& /*node*/ )
+{
+ //kdDebug(9007)<< "--- tok = " << lex->lookAhead(0).text() << " -- " << "Parser::parsePostfixExpression()" << endl;
+
+ AST::Node expr;
+ if( !parsePrimaryExpression(expr) )
+ return false;
+
+ while( true ){
+ switch(lex->lookAhead(0))
+ {
+ case '[':
+ {
+ lex->nextToken();
+ AST::Node e;
+ parseCommaExpression( e );
+ CHECK( ']', "]" );
+ }
+ break;
+
+ case '(':
+ {
+ lex->nextToken();
+ AST::Node funArgs;
+ parseCommaExpression( funArgs );
+ CHECK( ')', ")" );
+ }
+ break;
+
+ case Token_incr:
+ case Token_decr:
+ lex->nextToken();
+ break;
+
+ case '.':
+ case Token_arrow:
+ {
+ lex->nextToken();
+ if( lex->lookAhead(0) == Token_template )
+ lex->nextToken();
+
+ NameAST::Node name;
+ if( !parseName(name) ){
+ return false;
+ }
+ }
+ break;
+
+ case Token_typename:
+ {
+ lex->nextToken();
+
+ NameAST::Node name;
+ if( !parseName(name) ){
+ return false;
+ }
+
+ CHECK( '(', "(" );
+ AST::Node expr;
+ parseCommaExpression(expr);
+ CHECK( ')', ")" );
+ }
+ return true;
+
+ default:
+ return true;
+
+ } // end switch
+
+ } // end while
+
+ return true;
+}
+
+bool Parser::parseUnaryExpression( AST::Node& node )
+{
+ //kdDebug(9007)<< "--- tok = " << lex->lookAhead(0).text() << " -- " << "Parser::parseUnaryExpression()" << endl;
+
+ switch( lex->lookAhead(0) ){
+ case Token_incr:
+ case Token_decr:
+ case '*':
+ case '&':
+ case '+':
+ case '-':
+ case '!':
+ case '~':
+ {
+ lex->nextToken();
+ AST::Node expr;
+ return parseCastExpression( expr );
+ }
+
+ case Token_sizeof:
+ {
+ lex->nextToken();
+ int index = lex->index();
+ if( lex->lookAhead(0) == '(' ){
+ lex->nextToken();
+ AST::Node typeId;
+ if( parseTypeId(typeId) && lex->lookAhead(0) == ')' ){
+ lex->nextToken();
+ return true;
+ }
+ lex->setIndex( index );
+ }
+ AST::Node expr;
+ return parseUnaryExpression( expr );
+ }
+
+ case Token_new:
+ return parseNewExpression( node );
+
+ case Token_delete:
+ return parseDeleteExpression( node );
+ }
+
+ return parsePostfixExpression( node );
+}
+
+bool Parser::parseNewExpression( AST::Node& /*node*/ )
+{
+ //kdDebug(9007)<< "--- tok = " << lex->lookAhead(0).text() << " -- " << "Parser::parseNewExpression()" << endl;
+ if( lex->lookAhead(0) == Token_scope && lex->lookAhead(1) == Token_new )
+ lex->nextToken();
+
+ CHECK( Token_new, "new");
+
+ if( lex->lookAhead(0) == '(' ){
+ lex->nextToken();
+ AST::Node expr;
+ parseCommaExpression( expr );
+ CHECK( ')', ")" );
+ }
+
+ if( lex->lookAhead(0) == '(' ){
+ lex->nextToken();
+ AST::Node typeId;
+ parseTypeId( typeId );
+ CHECK( ')', ")" );
+ } else {
+ AST::Node typeId;
+ parseNewTypeId( typeId );
+ }
+
+ AST::Node init;
+ parseNewInitializer( init );
+ return true;
+}
+
+bool Parser::parseNewTypeId( AST::Node& /*node*/ )
+{
+ //kdDebug(9007)<< "--- tok = " << lex->lookAhead(0).text() << " -- " << "Parser::parseNewTypeId()" << endl;
+ TypeSpecifierAST::Node typeSpec;
+ if( parseTypeSpecifier(typeSpec) ){
+ AST::Node declarator;
+ parseNewDeclarator( declarator );
+ return true;
+ }
+
+ return false;
+}
+
+bool Parser::parseNewDeclarator( AST::Node& /*node*/ )
+{
+ //kdDebug(9007)<< "--- tok = " << lex->lookAhead(0).text() << " -- " << "Parser::parseNewDeclarator()" << endl;
+ AST::Node ptrOp;
+ if( parsePtrOperator(ptrOp) ){
+ AST::Node declarator;
+ parseNewDeclarator( declarator );
+ return true;
+ }
+
+ if( lex->lookAhead(0) == '[' ){
+ while( lex->lookAhead(0) == '[' ){
+ lex->nextToken();
+ AST::Node expr;
+ parseExpression( expr );
+ ADVANCE( ']', "]" );
+ }
+ return true;
+ }
+
+ return false;
+}
+
+bool Parser::parseNewInitializer( AST::Node& /*node*/ )
+{
+ //kdDebug(9007)<< "--- tok = " << lex->lookAhead(0).text() << " -- " << "Parser::parseNewInitializer()" << endl;
+ if( lex->lookAhead(0) != '(' )
+ return false;
+
+ lex->nextToken();
+ AST::Node expr;
+ parseCommaExpression( expr );
+ CHECK( ')', ")" );
+
+ return true;
+}
+
+bool Parser::parseDeleteExpression( AST::Node& /*node*/ )
+{
+ //kdDebug(9007)<< "--- tok = " << lex->lookAhead(0).text() << " -- " << "Parser::parseDeleteExpression()" << endl;
+ if( lex->lookAhead(0) == Token_scope && lex->lookAhead(1) == Token_delete )
+ lex->nextToken();
+
+ CHECK( Token_delete, "delete" );
+
+ if( lex->lookAhead(0) == '[' ){
+ lex->nextToken();
+ CHECK( ']', "]" );
+ }
+
+ AST::Node expr;
+ return parseCastExpression( expr );
+}
+
+bool Parser::parseCastExpression( AST::Node& /*node*/ )
+{
+ //kdDebug(9007)<< "--- tok = " << lex->lookAhead(0).text() << " -- " << "Parser::parseCastExpression()" << endl;
+
+ int index = lex->index();
+
+ if( lex->lookAhead(0) == '(' ){
+ lex->nextToken();
+ AST::Node typeId;
+ if ( parseTypeId(typeId) ) {
+ if ( lex->lookAhead(0) == ')' ) {
+ lex->nextToken();
+ AST::Node expr;
+ if( parseCastExpression(expr) )
+ return true;
+ }
+ }
+ }
+
+ lex->setIndex( index );
+
+ AST::Node expr;
+ return parseUnaryExpression( expr );
+}
+
+bool Parser::parsePmExpression( AST::Node& /*node*/ )
+{
+ //kdDebug(9007)<< "--- tok = " << lex->lookAhead(0).text() << " -- " << "Parser:parsePmExpression()" << endl;
+ AST::Node expr;
+ if( !parseCastExpression(expr) )
+ return false;
+
+ while( lex->lookAhead(0) == Token_ptrmem ){
+ lex->nextToken();
+
+ if( !parseCastExpression(expr) )
+ return false;
+ }
+
+ return true;
+}
+
+bool Parser::parseMultiplicativeExpression( AST::Node& /*node*/ )
+{
+ //kdDebug(9007)<< "--- tok = " << lex->lookAhead(0).text() << " -- " << "Parser::parseMultiplicativeExpression()" << endl;
+ AST::Node expr;
+ if( !parsePmExpression(expr) )
+ return false;
+
+ while( lex->lookAhead(0) == '*' || lex->lookAhead(0) == '/' || lex->lookAhead(0) == '%' ){
+ lex->nextToken();
+
+ if( !parsePmExpression(expr) )
+ return false;
+ }
+
+ return true;
+}
+
+
+bool Parser::parseAdditiveExpression( AST::Node& /*node*/ )
+{
+ //kdDebug(9007)<< "--- tok = " << lex->lookAhead(0).text() << " -- " << "Parser::parseAdditiveExpression()" << endl;
+ AST::Node expr;
+ if( !parseMultiplicativeExpression(expr) )
+ return false;
+
+ while( lex->lookAhead(0) == '+' || lex->lookAhead(0) == '-' ){
+ lex->nextToken();
+
+ if( !parseMultiplicativeExpression(expr) )
+ return false;
+ }
+
+ return true;
+}
+
+bool Parser::parseShiftExpression( AST::Node& /*node*/ )
+{
+ //kdDebug(9007)<< "--- tok = " << lex->lookAhead(0).text() << " -- " << "Parser::parseShiftExpression()" << endl;
+ AST::Node expr;
+ if( !parseAdditiveExpression(expr) )
+ return false;
+
+ while( lex->lookAhead(0) == Token_shift ){
+ lex->nextToken();
+
+ if( !parseAdditiveExpression(expr) )
+ return false;
+ }
+
+ return true;
+}
+
+bool Parser::parseRelationalExpression( AST::Node& /*node*/, bool templArgs )
+{
+ //kdDebug(9007)<< "--- tok = " << lex->lookAhead(0).text() << " -- " << "Parser::parseRelationalExpression()" << endl;
+ AST::Node expr;
+ if( !parseShiftExpression(expr) )
+ return false;
+
+ while( lex->lookAhead(0) == '<' || (lex->lookAhead(0) == '>' && !templArgs) ||
+ lex->lookAhead(0) == Token_leq || lex->lookAhead(0) == Token_geq ){
+ lex->nextToken();
+
+ if( !parseShiftExpression(expr) )
+ return false;
+ }
+
+ return true;
+}
+
+bool Parser::parseEqualityExpression( AST::Node& /*node*/, bool templArgs )
+{
+ //kdDebug(9007)<< "--- tok = " << lex->lookAhead(0).text() << " -- " << "Parser::parseEqualityExpression()" << endl;
+ AST::Node expr;
+ if( !parseRelationalExpression(expr, templArgs) )
+ return false;
+
+ while( lex->lookAhead(0) == Token_eq || lex->lookAhead(0) == Token_not_eq ){
+ lex->nextToken();
+
+ if( !parseRelationalExpression(expr, templArgs) )
+ return false;
+ }
+
+ return true;
+}
+
+bool Parser::parseAndExpression( AST::Node& /*node*/, bool templArgs )
+{
+ //kdDebug(9007)<< "--- tok = " << lex->lookAhead(0).text() << " -- " << "Parser::parseAndExpression()" << endl;
+ AST::Node expr;
+ if( !parseEqualityExpression(expr, templArgs) )
+ return false;
+
+ while( lex->lookAhead(0) == '&' ){
+ lex->nextToken();
+
+ if( !parseEqualityExpression(expr, templArgs) )
+ return false;
+ }
+
+ return true;
+}
+
+bool Parser::parseExclusiveOrExpression( AST::Node& /*node*/, bool templArgs )
+{
+ //kdDebug(9007)<< "--- tok = " << lex->lookAhead(0).text() << " -- " << "Parser::parseExclusiveOrExpression()" << endl;
+ AST::Node expr;
+ if( !parseAndExpression(expr, templArgs) )
+ return false;
+
+ while( lex->lookAhead(0) == '^' ){
+ lex->nextToken();
+
+ if( !parseAndExpression(expr, templArgs) )
+ return false;
+ }
+
+ return true;
+}
+
+bool Parser::parseInclusiveOrExpression( AST::Node& /*node*/, bool templArgs )
+{
+ //kdDebug(9007)<< "--- tok = " << lex->lookAhead(0).text() << " -- " << "Parser::parseInclusiveOrExpression()" << endl;
+ AST::Node expr;
+ if( !parseExclusiveOrExpression(expr, templArgs) )
+ return false;
+
+ while( lex->lookAhead(0) == '|' ){
+ lex->nextToken();
+
+ if( !parseExclusiveOrExpression(expr, templArgs) )
+ return false;
+ }
+
+ return true;
+}
+
+bool Parser::parseLogicalAndExpression( AST::Node& /*node*/, bool templArgs )
+{
+ //kdDebug(9007)<< "--- tok = " << lex->lookAhead(0).text() << " -- " << "Parser::parseLogicalAndExpression()" << endl;
+
+ AST::Node expr;
+ if( !parseInclusiveOrExpression(expr, templArgs) )
+ return false;
+
+ while( lex->lookAhead(0) == Token_and ){
+ lex->nextToken();
+
+ if( !parseInclusiveOrExpression(expr, templArgs) )
+ return false;
+ }
+
+ return true;
+}
+
+bool Parser::parseLogicalOrExpression( AST::Node& node, bool templArgs )
+{
+ //kdDebug(9007)<< "--- tok = " << lex->lookAhead(0).text() << " -- " << "Parser::parseLogicalOrExpression()" << endl;
+
+ int start = lex->index();
+
+ AST::Node expr;
+ if( !parseLogicalAndExpression(expr, templArgs) )
+ return false;
+
+ while( lex->lookAhead(0) == Token_or ){
+ lex->nextToken();
+
+ if( !parseLogicalAndExpression(expr, templArgs) )
+ return false;
+ }
+
+ AST::Node ast = CreateNode<AST>();
+ UPDATE_POS( ast, start, lex->index() );
+ node = ast;
+ return true;
+}
+
+bool Parser::parseConditionalExpression( AST::Node& /*node*/ )
+{
+ //kdDebug(9007)<< "--- tok = " << lex->lookAhead(0).text() << " -- " << "Parser::parseConditionalExpression()" << endl;
+ AST::Node expr;
+ if( !parseLogicalOrExpression(expr) )
+ return false;
+
+ if( lex->lookAhead(0) == '?' ){
+ lex->nextToken();
+
+ if( !parseExpression(expr) )
+ return false;
+
+ CHECK( ':', ":" );
+
+ if( !parseAssignmentExpression(expr) )
+ return false;
+ }
+
+ return true;
+}
+
+bool Parser::parseAssignmentExpression( AST::Node& node )
+{
+ //kdDebug(9007)<< "--- tok = " << lex->lookAhead(0).text() << " -- " << "Parser::parseAssignmentExpression()" << endl;
+ int start = lex->index();
+ AST::Node expr;
+ if( lex->lookAhead(0) == Token_throw && !parseThrowExpression(expr) )
+ return false;
+ else if( !parseConditionalExpression(expr) )
+ return false;
+
+ while( lex->lookAhead(0) == Token_assign || lex->lookAhead(0) == '=' ){
+ lex->nextToken();
+
+ if( !parseConditionalExpression(expr) )
+ return false;
+ }
+
+ AST::Node ast = CreateNode<AST>();
+ UPDATE_POS( ast, start, lex->index() );
+ node = ast;
+ return true;
+}
+
+bool Parser::parseConstantExpression( AST::Node& node )
+{
+ //kdDebug(9007)<< "--- tok = " << lex->lookAhead(0).text() << " -- " << "Parser::parseConstantExpression()" << endl;
+ int start = lex->index();
+ if( parseConditionalExpression(node) ){
+ AST::Node ast = CreateNode<AST>();
+ UPDATE_POS( ast, start, lex->index() );
+ node = ast;
+ return true;
+ }
+ return false;
+}
+
+bool Parser::parseExpression( AST::Node& node )
+{
+ //kdDebug(9007)<< "--- tok = " << lex->lookAhead(0).text() << " -- " << "Parser::parseExpression()" << endl;
+
+ int start = lex->index();
+
+ if( !parseCommaExpression(node) )
+ return false;
+
+ AST::Node ast = CreateNode<AST>();
+ UPDATE_POS( ast, start, lex->index() );
+ node = ast;
+ return true;
+}
+
+bool Parser::parseCommaExpression( AST::Node& node )
+{
+ //kdDebug(9007)<< "--- tok = " << lex->lookAhead(0).text() << " -- " << "Parser::parseCommaExpression()" << endl;
+ int start = lex->index();
+
+ AST::Node expr;
+ if( !parseAssignmentExpression(expr) )
+ return false;
+
+ QString comment;
+ while( lex->lookAhead(0) == ',' ){
+ comment = QString::null;
+ advanceAndCheckTrailingComment( comment );
+
+ if( !parseAssignmentExpression(expr) )
+ return false;
+ if (!comment.isEmpty())
+ expr->setComment(comment);
+ }
+
+ AST::Node ast = CreateNode<AST>();
+ UPDATE_POS( ast, start, lex->index() );
+ node = ast;
+ return true;
+}
+
+bool Parser::parseThrowExpression( AST::Node& /*node*/ )
+{
+ //kdDebug(9007)<< "--- tok = " << lex->lookAhead(0).text() << " -- " << "Parser::parseThrowExpression()" << endl;
+ if( lex->lookAhead(0) != Token_throw )
+ return false;
+
+ CHECK( Token_throw, "throw" );
+ AST::Node expr;
+ if( !parseAssignmentExpression(expr) )
+ return false;
+
+ return true;
+}
+
+bool Parser::parseIvarDeclList( AST::Node & node )
+{
+ Q_UNUSED( node );
+ return false;
+}
+
+bool Parser::parseIvarDecls( AST::Node & node )
+{
+ Q_UNUSED( node );
+ return false;
+}
+
+bool Parser::parseIvarDecl( AST::Node & node )
+{
+ Q_UNUSED( node );
+ return false;
+}
+
+bool Parser::parseIvars( AST::Node & node )
+{
+ Q_UNUSED( node );
+ return false;
+}
+
+bool Parser::parseIvarDeclarator( AST::Node & node )
+{
+ Q_UNUSED( node );
+ return false;
+}
+
+bool Parser::parseMethodDecl( AST::Node & node )
+{
+ Q_UNUSED( node );
+ return false;
+}
+
+bool Parser::parseUnarySelector( AST::Node & node )
+{
+ Q_UNUSED( node );
+ return false;
+}
+
+bool Parser::parseKeywordSelector( AST::Node & node )
+{
+ Q_UNUSED( node );
+ return false;
+}
+
+bool Parser::parseSelector( AST::Node & node )
+{
+ Q_UNUSED( node );
+ return false;
+}
+
+bool Parser::parseKeywordDecl( AST::Node & node )
+{
+ Q_UNUSED( node );
+ return false;
+}
+
+bool Parser::parseReceiver( AST::Node & node )
+{
+ Q_UNUSED( node );
+ return false;
+}
+
+bool Parser::parseObjcMessageExpr( AST::Node & node )
+{
+ Q_UNUSED( node );
+ return false;
+}
+
+bool Parser::parseMessageArgs( AST::Node & node )
+{
+ Q_UNUSED( node );
+ return false;
+}
+
+bool Parser::parseKeywordExpr( AST::Node & node )
+{
+ Q_UNUSED( node );
+ return false;
+}
+
+bool Parser::parseKeywordArgList( AST::Node & node )
+{
+ Q_UNUSED( node );
+ return false;
+}
+
+bool Parser::parseKeywordArg( AST::Node & node )
+{
+ Q_UNUSED( node );
+ return false;
+}
+
+bool Parser::parseReservedWord( AST::Node & node )
+{
+ Q_UNUSED( node );
+ return false;
+}
+
+bool Parser::parseMyParms( AST::Node & node )
+{
+ Q_UNUSED( node );
+ return false;
+}
+
+bool Parser::parseMyParm( AST::Node & node )
+{
+ Q_UNUSED( node );
+ return false;
+}
+
+bool Parser::parseOptParmList( AST::Node & node )
+{
+ Q_UNUSED( node );
+ return false;
+}
+
+bool Parser::parseObjcSelectorExpr( AST::Node & node )
+{
+ Q_UNUSED( node );
+ return false;
+}
+
+bool Parser::parseSelectorArg( AST::Node & node )
+{
+ Q_UNUSED( node );
+ return false;
+}
+
+bool Parser::parseKeywordNameList( AST::Node & node )
+{
+ Q_UNUSED( node );
+ return false;
+}
+
+bool Parser::parseKeywordName( AST::Node & node )
+{
+ Q_UNUSED( node );
+ return false;
+}
+
+bool Parser::parseObjcEncodeExpr( AST::Node & node )
+{
+ Q_UNUSED( node );
+ return false;
+}
+
+bool Parser::parseObjcString( AST::Node & node )
+{
+ Q_UNUSED( node );
+ return false;
+}
+
+bool Parser::parseProtocolRefs( AST::Node & node )
+{
+ Q_UNUSED( node );
+ return false;
+}
+
+bool Parser::parseIdentifierList( GroupAST::Node & node )
+{
+ int start = lex->index();
+
+ if( lex->lookAhead(0) != Token_identifier )
+ return false;
+
+ GroupAST::Node ast = CreateNode<GroupAST>();
+
+ AST_FROM_TOKEN( tk, lex->index() );
+ ast->addNode( tk );
+ lex->nextToken();
+
+ QString comment;
+ while( lex->lookAhead(0) == ',' ){
+ comment = QString::null;
+ advanceAndCheckTrailingComment( comment );
+ if( lex->lookAhead(0) == Token_identifier ){
+ AST_FROM_TOKEN( tk, lex->index() );
+ ast->addNode( tk );
+ lex->nextToken();
+ }
+ ADVANCE( Token_identifier, "identifier" );
+ }
+
+ node = ast;
+ UPDATE_POS( node, start, lex->index() );
+ return true;
+}
+
+bool Parser::parseIdentifierColon( AST::Node & node )
+{
+ Q_UNUSED( node );
+
+ if( lex->lookAhead(0) == Token_identifier && lex->lookAhead(1) == ':' ){
+ lex->nextToken();
+ lex->nextToken();
+ return true;
+ } // ### else if PTYPENAME -> return true ;
+
+ return false;
+}
+
+bool Parser::parseObjcProtocolExpr( AST::Node & node )
+{
+ Q_UNUSED( node );
+ return false;
+}
+
+bool Parser::parseObjcOpenBracketExpr( AST::Node & node )
+{
+ Q_UNUSED( node );
+ return false;
+}
+
+bool Parser::parseObjcCloseBracket( AST::Node & node )
+{
+ Q_UNUSED( node );
+ return false;
+}
+
+bool Parser::parseObjcDef( DeclarationAST::Node & node )
+{
+ Q_UNUSED( node );
+ return false;
+}
+
+bool Parser::parseObjcClassDef( DeclarationAST::Node & node )
+{
+ Q_UNUSED( node );
+ return false;
+}
+
+bool Parser::parseObjcClassDecl( DeclarationAST::Node & node )
+{
+ Q_UNUSED( node );
+
+ ADVANCE( OBJC_CLASS, "@class" );
+
+ GroupAST::Node idList;
+ parseIdentifierList( idList );
+ ADVANCE( ';', ";" );
+
+ return true;
+}
+
+bool Parser::parseObjcProtocolDecl( DeclarationAST::Node & node )
+{
+ Q_UNUSED( node );
+
+ ADVANCE( OBJC_PROTOCOL, "@protocol" );
+
+ GroupAST::Node idList;
+ parseIdentifierList( idList );
+ ADVANCE( ';', ";" );
+
+ return true;
+}
+
+bool Parser::parseObjcAliasDecl( DeclarationAST::Node & node )
+{
+ Q_UNUSED( node );
+
+ ADVANCE( OBJC_ALIAS, "@alias" );
+
+ GroupAST::Node idList;
+ parseIdentifierList( idList );
+ ADVANCE( ';', ";" );
+
+ return true;
+}
+
+bool Parser::parseObjcProtocolDef( DeclarationAST::Node & node )
+{
+ Q_UNUSED( node );
+ return false;
+}
+
+bool Parser::parseObjcMethodDef( DeclarationAST::Node & node )
+{
+ Q_UNUSED( node );
+ return false;
+}
+
+bool Parser::parseWinDeclSpec( GroupAST::Node & node )
+{
+ if( lex->lookAhead(0) == Token_identifier && lex->lookAhead(0).text() == "__declspec" && lex->lookAhead(1) == '(' ){
+ int start = lex->index();
+ lex->nextToken();
+ lex->nextToken(); // skip '('
+
+ parseIdentifierList( node );
+ ADVANCE( ')', ")" );
+
+ UPDATE_POS( node, start, lex->index() );
+ return true;
+ }
+
+ return false;
+}
+
diff --git a/umbrello/umbrello/codeimport/kdevcppparser/parser.h b/umbrello/umbrello/codeimport/kdevcppparser/parser.h
new file mode 100644
index 00000000..611ceb14
--- /dev/null
+++ b/umbrello/umbrello/codeimport/kdevcppparser/parser.h
@@ -0,0 +1,221 @@
+/* This file is part of KDevelop
+ Copyright (C) 2002,2003 Roberto Raggi <roberto@kdevelop.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 PARSER_H
+#define PARSER_H
+
+#include "ast.h"
+
+#include <qstring.h>
+#include <qstringlist.h>
+#include <qvaluelist.h>
+#include <qvaluestack.h>
+
+struct ParserPrivateData;
+
+class Driver;
+class Lexer;
+class Token;
+struct Error;
+
+class Parser
+{
+public:
+ Parser( Driver* driver, Lexer* lexer );
+ virtual ~Parser();
+
+private:
+ virtual bool reportError( const Error& err );
+ /** @todo remove*/ virtual bool reportError( const QString& msg );
+ /** @todo remove*/ virtual void syntaxError();
+
+public: /*rules*/
+
+ bool parseTranslationUnit( TranslationUnitAST::Node& node );
+
+ bool parseDeclaration( DeclarationAST::Node& node );
+ bool parseBlockDeclaration( DeclarationAST::Node& node );
+ bool parseLinkageSpecification( DeclarationAST::Node& node );
+ bool parseLinkageBody( LinkageBodyAST::Node& node );
+ bool parseNamespace( DeclarationAST::Node& node );
+ bool parseNamespaceAliasDefinition( DeclarationAST::Node& node );
+ bool parseUsing( DeclarationAST::Node& node );
+ bool parseUsingDirective( DeclarationAST::Node& node );
+ bool parseTypedef( DeclarationAST::Node& node );
+ bool parseAsmDefinition( DeclarationAST::Node& node );
+ bool parseTemplateDeclaration( DeclarationAST::Node& node );
+ bool parseDeclarationInternal( DeclarationAST::Node& node, QString& comment );
+
+ bool parseUnqualifiedName( ClassOrNamespaceNameAST::Node& node );
+ bool parseStringLiteral( AST::Node& node );
+ bool parseName( NameAST::Node& node );
+ bool parseOperatorFunctionId( AST::Node& node );
+ bool parseTemplateArgumentList( TemplateArgumentListAST::Node& node, bool reportError=true );
+ bool parseOperator( AST::Node& node );
+ bool parseCvQualify( GroupAST::Node& node );
+ bool parseSimpleTypeSpecifier( TypeSpecifierAST::Node& node );
+ bool parsePtrOperator( AST::Node& node );
+ bool parseTemplateArgument( AST::Node& node );
+ bool parseTypeSpecifier( TypeSpecifierAST::Node& node );
+ bool parseTypeSpecifierOrClassSpec( TypeSpecifierAST::Node& node );
+ bool parseDeclarator( DeclaratorAST::Node& node );
+ bool parseTemplateParameterList( TemplateParameterListAST::Node& node );
+ bool parseTemplateParameter( TemplateParameterAST::Node& node );
+ bool parseStorageClassSpecifier( GroupAST::Node& node );
+ bool parseFunctionSpecifier( GroupAST::Node& node );
+ bool parseInitDeclaratorList( InitDeclaratorListAST::Node& node );
+ bool parseInitDeclarator( InitDeclaratorAST::Node& node );
+ bool parseParameterDeclarationClause( ParameterDeclarationClauseAST::Node& node );
+ bool parseCtorInitializer( AST::Node& node );
+ bool parsePtrToMember( AST::Node& node );
+ bool parseEnumSpecifier( TypeSpecifierAST::Node& node );
+ bool parseClassSpecifier( TypeSpecifierAST::Node& node );
+ bool parseWinDeclSpec( GroupAST::Node& node );
+ bool parseElaboratedTypeSpecifier( TypeSpecifierAST::Node& node );
+ bool parseDeclaratorId( NameAST::Node& node );
+ bool parseExceptionSpecification( GroupAST::Node& node );
+ bool parseEnumerator( EnumeratorAST::Node& node );
+ bool parseTypeParameter( TypeParameterAST::Node& node );
+ bool parseParameterDeclaration( ParameterDeclarationAST::Node& node );
+ bool parseTypeId( AST::Node& node );
+ bool parseAbstractDeclarator( DeclaratorAST::Node& node );
+ bool parseParameterDeclarationList( ParameterDeclarationListAST::Node& node );
+ bool parseMemberSpecification( DeclarationAST::Node& node );
+ bool parseAccessSpecifier( AST::Node& node );
+ bool parseTypeIdList( GroupAST::Node& node );
+ bool parseMemInitializerList( AST::Node& node );
+ bool parseMemInitializer( AST::Node& node );
+ bool parseInitializer( AST::Node& node );
+ bool parseBaseClause( BaseClauseAST::Node& node );
+ bool parseBaseSpecifier( BaseSpecifierAST::Node& node );
+ bool parseInitializerClause( AST::Node& node );
+ bool parseMemInitializerId( NameAST::Node& node );
+ bool parseFunctionBody( StatementListAST::Node& node );
+
+ // expression
+ bool skipExpression( AST::Node& node );
+ bool skipCommaExpression( AST::Node& node );
+ bool skipExpressionStatement( StatementAST::Node& node );
+
+ bool parseExpression( AST::Node& node );
+ bool parsePrimaryExpression( AST::Node& node );
+ bool parsePostfixExpression( AST::Node& node );
+ bool parseUnaryExpression( AST::Node& node );
+ bool parseNewExpression( AST::Node& node );
+ bool parseNewTypeId( AST::Node& node );
+ bool parseNewDeclarator( AST::Node& node );
+ bool parseNewInitializer( AST::Node& node );
+ bool parseDeleteExpression( AST::Node& node );
+ bool parseCastExpression( AST::Node& node );
+ bool parsePmExpression( AST::Node& node );
+ bool parseMultiplicativeExpression( AST::Node& node );
+ bool parseAdditiveExpression( AST::Node& node );
+ bool parseShiftExpression( AST::Node& node );
+ bool parseRelationalExpression( AST::Node& node, bool templArgs=false );
+ bool parseEqualityExpression( AST::Node& node, bool templArgs=false );
+ bool parseAndExpression( AST::Node& node, bool templArgs=false );
+ bool parseExclusiveOrExpression( AST::Node& node, bool templArgs=false );
+ bool parseInclusiveOrExpression( AST::Node& node, bool templArgs=false );
+ bool parseLogicalAndExpression( AST::Node& node, bool templArgs=false );
+ bool parseLogicalOrExpression( AST::Node& node, bool templArgs=false );
+ bool parseConditionalExpression( AST::Node& node );
+ bool parseAssignmentExpression( AST::Node& node );
+ bool parseConstantExpression( AST::Node& node );
+ bool parseCommaExpression( AST::Node& node );
+ bool parseThrowExpression( AST::Node& node );
+
+ // statement
+ bool parseCondition( ConditionAST::Node& node );
+ bool parseStatement( StatementAST::Node& node );
+ bool parseWhileStatement( StatementAST::Node& node );
+ bool parseDoStatement( StatementAST::Node& node );
+ bool parseForStatement( StatementAST::Node& node );
+ bool parseCompoundStatement( StatementAST::Node& node );
+ bool parseForInitStatement( StatementAST::Node& node );
+ bool parseIfStatement( StatementAST::Node& node );
+ bool parseSwitchStatement( StatementAST::Node& node );
+ bool parseLabeledStatement( StatementAST::Node& node );
+ bool parseDeclarationStatement( StatementAST::Node& node );
+ bool parseTryBlockStatement( StatementAST::Node& node );
+
+ // objective c
+ bool parseObjcDef( DeclarationAST::Node& node );
+ bool parseObjcClassDef( DeclarationAST::Node& node );
+ bool parseObjcClassDecl( DeclarationAST::Node& node );
+ bool parseObjcProtocolDecl( DeclarationAST::Node& node );
+ bool parseObjcAliasDecl( DeclarationAST::Node& node );
+ bool parseObjcProtocolDef( DeclarationAST::Node& node );
+ bool parseObjcMethodDef( DeclarationAST::Node& node );
+
+ bool parseIvarDeclList( AST::Node& node );
+ bool parseIvarDecls( AST::Node& node );
+ bool parseIvarDecl( AST::Node& node );
+ bool parseIvars( AST::Node& node );
+ bool parseIvarDeclarator( AST::Node& node );
+ bool parseMethodDecl( AST::Node& node );
+ bool parseUnarySelector( AST::Node& node );
+ bool parseKeywordSelector( AST::Node& node );
+ bool parseSelector( AST::Node& node );
+ bool parseKeywordDecl( AST::Node& node );
+ bool parseReceiver( AST::Node& node );
+ bool parseObjcMessageExpr( AST::Node& node );
+ bool parseMessageArgs( AST::Node& node );
+ bool parseKeywordExpr( AST::Node& node );
+ bool parseKeywordArgList( AST::Node& node );
+ bool parseKeywordArg( AST::Node& node );
+ bool parseReservedWord( AST::Node& node );
+ bool parseMyParms( AST::Node& node );
+ bool parseMyParm( AST::Node& node );
+ bool parseOptParmList( AST::Node& node );
+ bool parseObjcSelectorExpr( AST::Node& node );
+ bool parseSelectorArg( AST::Node& node );
+ bool parseKeywordNameList( AST::Node& node );
+ bool parseKeywordName( AST::Node& node );
+ bool parseObjcEncodeExpr( AST::Node& node );
+ bool parseObjcString( AST::Node& node );
+ bool parseProtocolRefs( AST::Node& node );
+ bool parseIdentifierList( GroupAST::Node& node );
+ bool parseIdentifierColon( AST::Node& node );
+ bool parseObjcProtocolExpr( AST::Node& node );
+ bool parseObjcOpenBracketExpr( AST::Node& node );
+ bool parseObjcCloseBracket( AST::Node& node );
+
+ void advanceAndCheckTrailingComment(QString& comment);
+
+ bool skipUntil( int token );
+ bool skipUntilDeclaration();
+ bool skipUntilStatement();
+ bool skip( int l, int r );
+ QString toString( int start, int end, const QString& sep=" " ) const;
+
+private:
+ ParserPrivateData* d;
+ Driver* m_driver;
+ Lexer* lex;
+ int m_problems;
+ int m_maxProblems;
+ bool objcp;
+
+private:
+ Parser( const Parser& source );
+ void operator = ( const Parser& source );
+};
+
+
+#endif
diff --git a/umbrello/umbrello/codeimport/kdevcppparser/tree_parser.cpp b/umbrello/umbrello/codeimport/kdevcppparser/tree_parser.cpp
new file mode 100644
index 00000000..7f9210e2
--- /dev/null
+++ b/umbrello/umbrello/codeimport/kdevcppparser/tree_parser.cpp
@@ -0,0 +1,207 @@
+/* This file is part of KDevelop
+ Copyright (C) 2002,2003 Roberto Raggi <roberto@kdevelop.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.
+*/
+
+#include "tree_parser.h"
+#include <kdebug.h>
+
+TreeParser::TreeParser()
+{
+}
+
+TreeParser::~TreeParser()
+{
+}
+
+void TreeParser::parseTranslationUnit( TranslationUnitAST* translationUnit )
+{
+ //kdDebug(9007) << "TreeParser::parseTranslationUnit()" << endl;
+
+ QPtrList<DeclarationAST> declarations = translationUnit->declarationList();
+ QPtrListIterator<DeclarationAST> it( declarations );
+ while( it.current() ){
+ parseDeclaration( it.current() );
+ ++it;
+ }
+}
+
+void TreeParser::parseDeclaration( DeclarationAST* declaration )
+{
+ //kdDebug(9007) << "TreeParser::parseDeclaration()" << endl;
+
+ if( !declaration )
+ return;
+
+ switch( declaration->nodeType() )
+ {
+ case NodeType_LinkageSpecification:
+ parseLinkageSpecification( static_cast<LinkageSpecificationAST*>(declaration) );
+ break;
+
+ case NodeType_Namespace:
+ parseNamespace( static_cast<NamespaceAST*>(declaration) );
+ break;
+
+ case NodeType_NamespaceAlias:
+ parseNamespaceAlias( static_cast<NamespaceAliasAST*>(declaration) );
+ break;
+
+ case NodeType_Using:
+ parseUsing( static_cast<UsingAST*>(declaration) );
+ break;
+
+ case NodeType_UsingDirective:
+ parseUsingDirective( static_cast<UsingDirectiveAST*>(declaration) );
+ break;
+
+ case NodeType_Typedef:
+ parseTypedef( static_cast<TypedefAST*>(declaration) );
+ break;
+
+ case NodeType_TemplateDeclaration:
+ parseTemplateDeclaration( static_cast<TemplateDeclarationAST*>(declaration) );
+ break;
+
+ case NodeType_SimpleDeclaration:
+ parseSimpleDeclaration( static_cast<SimpleDeclarationAST*>(declaration) );
+ break;
+
+ case NodeType_FunctionDefinition:
+ parseFunctionDefinition( static_cast<FunctionDefinitionAST*>(declaration) );
+ break;
+
+ case NodeType_AccessDeclaration:
+ parseAccessDeclaration( static_cast<AccessDeclarationAST*>(declaration) );
+ break;
+ }
+}
+
+void TreeParser::parseLinkageSpecification( LinkageSpecificationAST* ast )
+{
+ //kdDebug(9007) << "TreeParser::parseLinkageSpecification()" << endl;
+ if( ast->linkageBody() )
+ parseLinkageBody( ast->linkageBody() );
+ else if( ast->declaration() )
+ parseDeclaration( ast->declaration() );
+}
+
+void TreeParser::parseNamespace( NamespaceAST* decl )
+{
+ //kdDebug(9007) << "TreeParser::parseNamespace()" << endl;
+ if( decl->linkageBody() )
+ parseLinkageBody( decl->linkageBody() );
+}
+
+void TreeParser::parseNamespaceAlias( NamespaceAliasAST* decl )
+{
+ //kdDebug(9007) << "TreeParser::parseNamespaceAlias()" << endl;
+ Q_UNUSED( decl );
+}
+
+void TreeParser::parseUsing( UsingAST* decl )
+{
+ //kdDebug(9007) << "TreeParser::parseUsing()" << endl;
+ Q_UNUSED( decl );
+}
+
+void TreeParser::parseUsingDirective( UsingDirectiveAST* decl )
+{
+ //kdDebug(9007) << "TreeParser::parseUsingDirective()" << endl;
+ Q_UNUSED( decl );
+}
+
+void TreeParser::parseTypedef( TypedefAST* decl )
+{
+ //kdDebug(9007) << "TreeParser::parseTypedef()" << endl;
+ if( decl->typeSpec() )
+ parseTypeSpecifier( decl->typeSpec() );
+}
+
+void TreeParser::parseTemplateDeclaration( TemplateDeclarationAST* decl )
+{
+ //kdDebug(9007) << "TreeParser::parseTemplateDeclaration()" << endl;
+ Q_UNUSED( decl );
+}
+
+void TreeParser::parseSimpleDeclaration( SimpleDeclarationAST* decl )
+{
+ //kdDebug(9007) << "TreeParser::parseSimpleDeclaration()" << endl;
+ Q_UNUSED( decl );
+}
+
+void TreeParser::parseFunctionDefinition( FunctionDefinitionAST* def )
+{
+ //kdDebug(9007) << "TreeParser::parseFunctionDefinition()" << endl;
+ Q_UNUSED( def );
+}
+
+void TreeParser::parseLinkageBody( LinkageBodyAST* linkageBody )
+{
+ //kdDebug(9007) << "TreeParser::parseLinkageBody()" << endl;
+ QPtrList<DeclarationAST> declarations = linkageBody->declarationList();
+ for( QPtrListIterator<DeclarationAST> it(declarations); it.current(); ++it ){
+ parseDeclaration( it.current() );
+ }
+}
+
+void TreeParser::parseTypeSpecifier( TypeSpecifierAST* typeSpec )
+{
+ //kdDebug(9007) << "TreeParser::parseTypeSpecifier()" << endl;
+ switch( typeSpec->nodeType() )
+ {
+ case NodeType_ClassSpecifier:
+ parseClassSpecifier( static_cast<ClassSpecifierAST*>(typeSpec) );
+ break;
+
+ case NodeType_EnumSpecifier:
+ parseEnumSpecifier( static_cast<EnumSpecifierAST*>(typeSpec) );
+ break;
+
+ case NodeType_ElaboratedTypeSpecifier:
+ parseElaboratedTypeSpecifier( static_cast<ElaboratedTypeSpecifierAST*>(typeSpec) );
+ break;
+ }
+}
+
+void TreeParser::parseClassSpecifier( ClassSpecifierAST* classSpec )
+{
+ //kdDebug(9007) << "TreeParser::parseClassSpecifier()" << endl;
+ QPtrList<DeclarationAST> declarations = classSpec->declarationList();
+ for( QPtrListIterator<DeclarationAST> it(declarations); it.current(); ++it ){
+ parseDeclaration( it.current() );
+ }
+}
+
+void TreeParser::parseEnumSpecifier( EnumSpecifierAST* enumSpec )
+{
+ //kdDebug(9007) << "TreeParser::parseEnumSpecifier()" << endl;
+ Q_UNUSED( enumSpec );
+}
+
+void TreeParser::parseElaboratedTypeSpecifier( ElaboratedTypeSpecifierAST* typeSpec )
+{
+ //kdDebug(9007) << "TreeParser::parseElaboratedTypeSpecifier()" << endl;
+ Q_UNUSED( typeSpec );
+}
+
+void TreeParser::parseAccessDeclaration ( AccessDeclarationAST * access )
+{
+ //kdDebug(9007) << "TreeParser::parseAccessDeclaration()" << endl;
+ Q_UNUSED( access );
+}
+
diff --git a/umbrello/umbrello/codeimport/kdevcppparser/tree_parser.h b/umbrello/umbrello/codeimport/kdevcppparser/tree_parser.h
new file mode 100644
index 00000000..42059408
--- /dev/null
+++ b/umbrello/umbrello/codeimport/kdevcppparser/tree_parser.h
@@ -0,0 +1,59 @@
+/* This file is part of KDevelop
+ Copyright (C) 2002,2003 Roberto Raggi <roberto@kdevelop.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 __tree_parser_h
+#define __tree_parser_h
+
+#include "ast.h"
+
+class TreeParser
+{
+public:
+ TreeParser();
+ virtual ~TreeParser();
+
+ // translation-unit
+ virtual void parseTranslationUnit( TranslationUnitAST* );
+
+ // declarations
+ virtual void parseDeclaration( DeclarationAST* );
+ virtual void parseLinkageSpecification( LinkageSpecificationAST* );
+ virtual void parseNamespace( NamespaceAST* );
+ virtual void parseNamespaceAlias( NamespaceAliasAST* );
+ virtual void parseUsing( UsingAST* );
+ virtual void parseUsingDirective( UsingDirectiveAST* );
+ virtual void parseTypedef( TypedefAST* );
+ virtual void parseTemplateDeclaration( TemplateDeclarationAST* );
+ virtual void parseSimpleDeclaration( SimpleDeclarationAST* );
+ virtual void parseFunctionDefinition( FunctionDefinitionAST* );
+ virtual void parseLinkageBody( LinkageBodyAST* );
+ virtual void parseAccessDeclaration( AccessDeclarationAST* );
+
+ // type-specifier
+ virtual void parseTypeSpecifier( TypeSpecifierAST* );
+ virtual void parseClassSpecifier( ClassSpecifierAST* );
+ virtual void parseEnumSpecifier( EnumSpecifierAST* );
+ virtual void parseElaboratedTypeSpecifier( ElaboratedTypeSpecifierAST* );
+
+private:
+ TreeParser( const TreeParser& source );
+ void operator = ( const TreeParser& source );
+};
+
+#endif // __tree_parser_h
diff --git a/umbrello/umbrello/codeimport/kdevcppparser/urlutil.cpp b/umbrello/umbrello/codeimport/kdevcppparser/urlutil.cpp
new file mode 100644
index 00000000..a2fd29dd
--- /dev/null
+++ b/umbrello/umbrello/codeimport/kdevcppparser/urlutil.cpp
@@ -0,0 +1,310 @@
+/* This file is part of the KDE project
+ Copyright (C) 2003 Julian Rockey <linux@jrockey.com>
+ Copyright (C) 2003 Alexander Dymo <cloudtemple@mksat.net>
+ Copyright (C) 2003 Mario Scalas <mario.scalas@libero.it>
+
+ 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.
+*/
+#include "urlutil.h"
+
+#include <qstringlist.h>
+
+#include <qdir.h>
+#include <qfileinfo.h>
+#include <kdebug.h>
+
+#include <unistd.h>
+#include <limits.h>
+#include <stdlib.h>
+
+#include <kdeversion.h>
+#if (KDE_VERSION_MINOR==0) && (KDE_VERSION_MAJOR==3)
+#include <kdevkurl.h>
+#endif
+
+///////////////////////////////////////////////////////////////////////////////
+// Namespace URLUtil
+///////////////////////////////////////////////////////////////////////////////
+
+QString URLUtil::filename(const QString & name) {
+ int slashPos = name.findRev("/");
+ return slashPos<0 ? name : name.mid(slashPos+1);
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+QString URLUtil::directory(const QString & name) {
+ int slashPos = name.findRev("/");
+ return slashPos<0 ? QString("") : name.left(slashPos);
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+QString URLUtil::relativePath(const KURL & parent, const KURL & child, uint slashPolicy) {
+ bool slashPrefix = slashPolicy & SLASH_PREFIX;
+ bool slashSuffix = slashPolicy & SLASH_SUFFIX;
+ if (parent == child)
+ return slashPrefix ? QString("/") : QString("");
+
+ if (!parent.isParentOf(child)) return QString();
+ int a=slashPrefix ? -1 : 1;
+ int b=slashSuffix ? 1 : -1;
+ return child.path(b).mid(parent.path(a).length());
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+QString URLUtil::relativePath(const QString & parent, const QString & child, uint slashPolicy) {
+ return relativePath(KURL(parent), KURL(child), slashPolicy);
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+QString URLUtil::upDir(const QString & path, bool slashSuffix) {
+ int slashPos = path.findRev("/");
+ if (slashPos<1) return QString::null;
+ return path.mid(0,slashPos+ (slashSuffix ? 1 : 0) );
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+KURL URLUtil::mergeURL(const KURL & source, const KURL & dest, const KURL & child) {
+
+ // if already a child of source, then fine
+ if (source.isParentOf(child) || source == child) return child;
+
+ // if not a child of dest, return blank URL (error)
+ if (!dest.isParentOf(child) && dest != child) return KURL();
+
+ // if child is same as dest, return source
+ if (dest == child) return source;
+
+ // calculate
+ QString childUrlStr = child.url(-1);
+ QString destStemStr = dest.url(1);
+ QString sourceStemStr = source.url(1);
+ return KURL(sourceStemStr.append( childUrlStr.mid( destStemStr.length() ) ) );
+
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+QString URLUtil::getExtension(const QString & path) {
+ int dotPos = path.findRev('.');
+ if (dotPos<0) return QString("");
+ return path.mid(dotPos+1);
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+QString URLUtil::extractPathNameRelative(const KURL &baseDirUrl, const KURL &url )
+{
+ QString absBase = extractPathNameAbsolute( baseDirUrl ),
+ absRef = extractPathNameAbsolute( url );
+ int i = absRef.find( absBase, 0, true );
+
+ if (i == -1)
+ return QString();
+
+ if (absRef == absBase)
+ return QString( "." );
+ else
+ return absRef.replace( 0, absBase.length(), QString() );
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+QString URLUtil::extractPathNameRelative(const QString &basePath, const KURL &url )
+{
+#if (KDE_VERSION_MINOR!=0) || (KDE_VERSION_MAJOR!=3)
+ KURL baseDirUrl = KURL::fromPathOrURL( basePath );
+#else
+ KURL baseDirUrl = KdevKURL::fromPathOrURL( basePath );
+#endif
+ return extractPathNameRelative( baseDirUrl, url );
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+QString URLUtil::extractPathNameRelative(const QString &basePath, const QString &absFilePath )
+{
+#if (KDE_VERSION_MINOR!=0) || (KDE_VERSION_MAJOR!=3)
+ KURL baseDirUrl = KURL::fromPathOrURL( basePath ),
+ fileUrl = KURL::fromPathOrURL( absFilePath );
+#else
+ KURL baseDirUrl = KdevKURL::fromPathOrURL( basePath ),
+ fileUrl = KdevKURL::fromPathOrURL( absFilePath );
+#endif
+ return extractPathNameRelative( baseDirUrl, fileUrl );
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+QString URLUtil::extractPathNameAbsolute( const KURL &url )
+{
+ if (isDirectory( url ))
+ return url.path( +1 ); // with trailing "/" if none is present
+ else
+ {
+ // Ok, this is an over-tight pre-condition on "url" since I hope nobody will never
+ // stress this function with absurd cases ... but who knows?
+ /*
+ QString path = url.path();
+ QFileInfo fi( path ); // Argh: QFileInfo is back ;))
+ return ( fi.exists()? path : QString() );
+ */
+ return url.path();
+ }
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+bool URLUtil::isDirectory( const KURL &url )
+{
+ return isDirectory( url.path() );
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+bool URLUtil::isDirectory( const QString &absFilePath )
+{
+ return QDir( absFilePath ).exists();
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+void URLUtil::dump( const KURL::List &urls, const QString &aMessage )
+{
+ if (!aMessage.isNull())
+ {
+ kdDebug(9000) << aMessage << endl;
+ }
+ kdDebug(9000) << " List has " << urls.count() << " elements." << endl;
+
+ for (size_t i = 0; i<urls.count(); ++i)
+ {
+ KURL url = urls[ i ];
+// kdDebug(9000) << " * Element = " << url.path() << endl;
+ }
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+QStringList URLUtil::toRelativePaths( const QString &baseDir, const KURL::List &urls)
+{
+ QStringList paths;
+
+ for (size_t i=0; i<urls.count(); ++i)
+ {
+ paths << extractPathNameRelative( baseDir, urls[i] );
+ }
+
+ return paths;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+QString URLUtil::relativePathToFile( const QString & dirUrl, const QString & fileUrl )
+{
+ if (dirUrl.isEmpty() || (dirUrl == "/"))
+ return fileUrl;
+
+ QStringList dir = QStringList::split("/", dirUrl, false);
+ QStringList file = QStringList::split("/", fileUrl, false);
+
+ QString resFileName = file.last();
+ file.remove(file.last());
+
+ uint i = 0;
+ while ( (i < dir.count()) && (i < (file.count())) && (dir[i] == file[i]) )
+ i++;
+
+ QString result_up;
+ QString result_down;
+ QString currDir;
+ QString currFile;
+ do
+ {
+ i >= dir.count() ? currDir = "" : currDir = dir[i];
+ i >= file.count() ? currFile = "" : currFile = file[i];
+ qWarning("i = %d, currDir = %s, currFile = %s", i, currDir.latin1(), currFile.latin1());
+ if (currDir.isEmpty() && currFile.isEmpty())
+ break;
+ else if (currDir.isEmpty())
+ result_down += file[i] + '/';
+ else if (currFile.isEmpty())
+ result_up += "../";
+ else
+ {
+ result_down += file[i] + '/';
+ result_up += "../";
+ }
+ i++;
+ }
+ while ( (!currDir.isEmpty()) || (!currFile.isEmpty()) );
+
+ return result_up + result_down + resFileName;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+// code from qt-3.1.2 version of QDir::canonicalPath()
+QString URLUtil::canonicalPath( const QString & path )
+{
+ QString r;
+ char cur[PATH_MAX+1];
+ if ( ::getcwd( cur, PATH_MAX ) )
+ {
+ char tmp[PATH_MAX+1];
+ if( ::realpath( QFile::encodeName( path ), tmp ) )
+ {
+ r = QFile::decodeName( tmp );
+ }
+ //always make sure we go back to the current dir
+ ::chdir( cur );
+ }
+ return r;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+//written by "Dawit A." <adawit@kde.org>
+//borrowed from his patch to KShell
+QString URLUtil::envExpand ( const QString& str )
+{
+ uint len = str.length();
+
+ if (len > 1 && str[0] == '$')
+ {
+ int pos = str.find ('/');
+
+ if (pos < 0)
+ pos = len;
+
+ char* ret = getenv( QConstString(str.unicode()+1, pos-1).string().local8Bit().data() );
+
+ if (ret)
+ {
+ QString expandedStr ( QFile::decodeName( ret ) );
+ if (pos < (int)len)
+ expandedStr += str.mid(pos);
+ return expandedStr;
+ }
+ }
+
+ return str;
+}
+
diff --git a/umbrello/umbrello/codeimport/kdevcppparser/urlutil.h b/umbrello/umbrello/codeimport/kdevcppparser/urlutil.h
new file mode 100644
index 00000000..3460d28b
--- /dev/null
+++ b/umbrello/umbrello/codeimport/kdevcppparser/urlutil.h
@@ -0,0 +1,132 @@
+/* This file is part of the KDE project
+ Copyright (C) 2003 Julian Rockey <linux@jrockey.com>
+ Copyright (C) 2003 Mario Scalas <mario.scalas@libero.it>
+
+ 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 _URLUTIL_H_
+#define _URLUTIL_H_
+
+#include <qstring.h>
+#include <qvaluelist.h>
+#include <kurl.h>
+
+namespace URLUtil
+{
+ enum SlashesPosition { SLASH_PREFIX = 1, SLASH_SUFFIX = 2 };
+
+ /**
+ * Returns the filename part of a pathname (i.e. everything past the last slash)
+ */
+ QString filename(const QString & pathName);
+ /**
+ * Returns the directory part of a path (i.e. everything up to but not including the last slash)
+ */
+ QString directory(const QString & pathName);
+ /**
+ * Returns the relative path between a parent and child URL, or blank if the specified child is not a child of parent
+ */
+ QString relativePath(const KURL & parent, const KURL & child, uint slashPolicy = SLASH_PREFIX);
+ /**
+ * Returns the relative path between a parent and child URL, or blank if the specified child is not a child of parent
+ */
+ QString relativePath(const QString & parent, const QString & child, uint slashPolicy = SLASH_PREFIX);
+ /**
+ * Returns the relative path between a directory and file. Should never return empty path.
+ * Example:
+ * dirUrl: /home/test/src
+ * fileUrl: /home/test/lib/mylib.cpp
+ * returns: ../lib/mylib.cpp
+ */
+ QString relativePathToFile( const QString & dirUrl, const QString & fileUrl );
+ /**
+ *Returns the path 'up one level' - the opposite of what filename returns
+ */
+ QString upDir(const QString & path, bool slashSuffix = false);
+ /**
+ * 'Merges' URLs - changes a URL that starts with dest to start with source instead
+ * Example:
+ * source is /home/me/
+ * dest is /home/you/
+ * child is /home/you/dir1/file1
+ * returns /home/me/dir1/fil1
+ */
+ KURL mergeURL(const KURL & source, const KURL & dest, const KURL & child);
+ /**
+ * Returns the file extension for a filename or path
+ */
+ QString getExtension(const QString & path);
+
+ /**
+ * Given a base directory url in @p baseDirUrl and the url referring to a date sub-directory or file,
+ * it will return the path relative to @p baseDirUrl.
+ * If baseDirUrl == url.path() then it will return ".".
+ * <code>
+ * KURL baseUrl, dirUrl;
+ * baseUrl.setPath( "/home/mario/src/kdevelop/" );
+ * dirUrl.setPath( "/home/mario/src/kdevelop/parts/cvs/" );
+ * QString relPathName = extractDirPathRelative( baseUrl, url ); // == "parts/cvs/"
+ * QString absPathName = extractDirPathAbsolute( url ); // == "/home/mario/src/kdevelop/parts/cvs/"
+ * </code>
+ * Note that if you pass a file name in @p url (instead of a directory) or the @p baseUrl is not contained
+ * in @p url then the function will return "" (void string).
+ */
+ QString extractPathNameRelative(const KURL &baseDirUrl, const KURL &url );
+ QString extractPathNameRelative(const QString &basePath, const KURL &url );
+ QString extractPathNameRelative(const QString &basePath, const QString &absFilePath );
+
+ /**
+ * Will return the absolute path name referred in @p url.
+ * Look at above for an example.
+ */
+ QString extractPathNameAbsolute( const KURL &url );
+
+ /**
+ * Returns a QStringList of relative (to @p baseDir) paths from a list of KURLs in @p urls
+ */
+ QStringList toRelativePaths( const QString &baseDir, const KURL::List &urls);
+
+ /**
+ * If @p url is a directory will return true, false otherwise.
+ */
+ bool isDirectory( const KURL &url );
+ bool isDirectory( const QString &absFilePath );
+
+ /**
+ * Will dump the list of KURL @p urls on standard output, eventually printing @ aMessage if it
+ * is not null.
+ */
+ void dump( const KURL::List &urls, const QString &aMessage = QString::null );
+
+ /**
+ * Same as QDir::canonicalPath in later versions of QT. Earlier versions of QT
+ * had this broken, so it's reproduced here.
+ */
+ QString canonicalPath( const QString & path );
+
+ /**
+ * Performs environment variable expansion on @p variable.
+ *
+ * @param variable the string with the environment variable to expand.
+ * @return the expanded environment variable value. if the variable
+ * cannot be expanded, @p variable itself is returned.
+ */
+ QString envExpand ( const QString &variable );
+
+}
+
+#endif
diff --git a/umbrello/umbrello/codeimport/nativeimportbase.cpp b/umbrello/umbrello/codeimport/nativeimportbase.cpp
new file mode 100644
index 00000000..058b4d19
--- /dev/null
+++ b/umbrello/umbrello/codeimport/nativeimportbase.cpp
@@ -0,0 +1,340 @@
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * copyright (C) 2005-2007 *
+ * Umbrello UML Modeller Authors <uml-devel@uml.sf.net> *
+ ***************************************************************************/
+
+// own header
+#include "nativeimportbase.h"
+
+// qt/kde includes
+#include <qfile.h>
+#include <qtextstream.h>
+#include <qregexp.h>
+#include <klocale.h>
+#include <kdebug.h>
+// app includes
+#include "import_utils.h"
+
+NativeImportBase::NativeImportBase(const QString &singleLineCommentIntro) {
+ m_singleLineCommentIntro = singleLineCommentIntro;
+ m_srcIndex = 0;
+ m_scopeIndex = 0; // index 0 is reserved for global scope
+ m_klass = NULL;
+ m_currentAccess = Uml::Visibility::Public;
+ m_isAbstract = false;
+ m_inComment = false;
+}
+
+NativeImportBase::~NativeImportBase() {
+}
+
+void NativeImportBase::setMultiLineComment(const QString &intro, const QString &end) {
+ m_multiLineCommentIntro = intro;
+ m_multiLineCommentEnd = end;
+}
+
+void NativeImportBase::setMultiLineAltComment(const QString &intro, const QString &end) {
+ m_multiLineAltCommentIntro = intro;
+ m_multiLineAltCommentEnd = end;
+}
+
+void NativeImportBase::skipStmt(QString until /* = ";" */) {
+ const uint srcLength = m_source.count();
+ while (m_srcIndex < srcLength && m_source[m_srcIndex] != until)
+ m_srcIndex++;
+}
+
+bool NativeImportBase::skipToClosing(QChar opener) {
+ QString closing;
+ switch (opener) {
+ case '{':
+ closing = "}";
+ break;
+ case '[':
+ closing = "]";
+ break;
+ case '(':
+ closing = ")";
+ break;
+ case '<':
+ closing = ">";
+ break;
+ default:
+ kError() << "NativeImportBase::skipToClosing(" << opener
+ << "): " << "illegal input character" << endl;
+ return false;
+ }
+ const QString opening(opener);
+ skipStmt(opening);
+ const uint srcLength = m_source.count();
+ int nesting = 0;
+ while (m_srcIndex < srcLength) {
+ QString nextToken = advance();
+ if (nextToken.isEmpty())
+ break;
+ if (nextToken == closing) {
+ if (nesting <= 0)
+ break;
+ nesting--;
+ } else if (nextToken == opening) {
+ nesting++;
+ }
+ }
+ if (m_srcIndex == srcLength)
+ return false;
+ return true;
+}
+
+QString NativeImportBase::advance() {
+ while (m_srcIndex < m_source.count() - 1) {
+ if (m_source[++m_srcIndex].startsWith(m_singleLineCommentIntro))
+ m_comment += m_source[m_srcIndex];
+ else
+ break;
+ }
+ if (m_srcIndex >= m_source.count() - 1 ||
+ // if last item in m_source is a comment then it is dropped too
+ (m_srcIndex == m_source.count() - 1 &&
+ m_source[m_srcIndex].startsWith(m_singleLineCommentIntro))) {
+ return QString();
+ }
+ return m_source[m_srcIndex];
+}
+
+bool NativeImportBase::preprocess(QString& line) {
+ if (m_multiLineCommentIntro.isEmpty())
+ return false;
+ // Check for end of multi line comment.
+ if (m_inComment) {
+ int delimiterLen = 0;
+ int pos = line.find(m_multiLineCommentEnd);
+ if (pos == -1) {
+ if (! m_multiLineAltCommentEnd.isEmpty())
+ pos = line.find(m_multiLineAltCommentEnd);
+ if (pos == -1) {
+ m_comment += line + "\n";
+ return true; // done
+ }
+ delimiterLen = m_multiLineAltCommentEnd.length();
+ } else {
+ delimiterLen = m_multiLineCommentEnd.length();
+ }
+ if (pos > 0) {
+ QString text = line.mid(0, pos - 1);
+ m_comment += text.stripWhiteSpace();
+ }
+ m_source.append(m_singleLineCommentIntro + m_comment); // denotes comments in `m_source'
+ m_srcIndex++;
+ m_comment = "";
+ m_inComment = false;
+ pos += delimiterLen; // pos now points behind the closed comment
+ if (pos == (int)line.length())
+ return true; // done
+ line = line.mid(pos);
+ }
+ // If we get here then m_inComment is false.
+ // Check for start of multi line comment.
+ int delimIntroLen = 0;
+ int delimEndLen = 0;
+ int pos = line.find(m_multiLineCommentIntro);
+ if (pos != -1) {
+ delimIntroLen = m_multiLineCommentIntro.length();
+ } else if (!m_multiLineAltCommentIntro.isEmpty()) {
+ pos = line.find(m_multiLineAltCommentIntro);
+ if (pos != -1)
+ delimIntroLen = m_multiLineAltCommentIntro.length();
+ }
+ if (pos != -1) {
+ int endpos = line.find(m_multiLineCommentEnd);
+ if (endpos != -1) {
+ delimEndLen = m_multiLineCommentEnd.length();
+ } else if (!m_multiLineAltCommentEnd.isEmpty()) {
+ endpos = line.find(m_multiLineAltCommentEnd);
+ if (endpos != -1)
+ delimEndLen = m_multiLineAltCommentEnd.length();
+ }
+ if (endpos == -1) {
+ m_inComment = true;
+ if (pos + delimIntroLen < (int)line.length()) {
+ QString cmnt = line.mid(pos + delimIntroLen);
+ m_comment += cmnt.stripWhiteSpace() + "\n";
+ }
+ if (pos == 0)
+ return true; // done
+ line = line.left(pos);
+ } else { // It's a multiline comment on a single line.
+ if (endpos > pos + delimIntroLen) {
+ QString cmnt = line.mid(pos + delimIntroLen, endpos - pos - delimIntroLen);
+ cmnt = cmnt.stripWhiteSpace();
+ if (!cmnt.isEmpty())
+ m_source.append(m_singleLineCommentIntro + cmnt);
+ }
+ endpos++; // endpos now points at the slash of "*/"
+ QString pre;
+ if (pos > 0)
+ pre = line.left(pos);
+ QString post;
+ if (endpos + delimEndLen < (int)line.length())
+ post = line.mid(endpos + 1);
+ line = pre + post;
+ }
+ }
+ return false; // The input was not completely consumed by preprocessing.
+}
+
+/// Split the line so that a string is returned as a single element of the list,
+/// when not in a string then split at white space.
+QStringList NativeImportBase::split(const QString& lin) {
+ QStringList list;
+ QString listElement;
+ QChar stringIntro = 0; // buffers the string introducer character
+ bool seenSpace = false;
+ QString line = lin.stripWhiteSpace();
+ for (uint i = 0; i < line.length(); i++) {
+ const QChar& c = line[i];
+ if (stringIntro) { // we are in a string
+ listElement += c;
+ if (c == stringIntro) {
+ if (line[i - 1] != '\\') {
+ list.append(listElement);
+ listElement = QString();
+ stringIntro = 0; // we are no longer in a string
+ }
+ }
+ } else if (c == '"' || c == '\'') {
+ if (!listElement.isEmpty()) {
+ list.append(listElement);
+ }
+ listElement = stringIntro = c;
+ seenSpace = false;
+ } else if (c == ' ' || c == '\t') {
+ if (seenSpace)
+ continue;
+ seenSpace = true;
+ if (!listElement.isEmpty()) {
+ list.append(listElement);
+ listElement = QString();
+ }
+ } else {
+ listElement += c;
+ seenSpace = false;
+ }
+ }
+ if (!listElement.isEmpty())
+ list.append(listElement);
+ return list;
+}
+
+/// The lexer. Tokenizes the given string and fills `m_source'.
+/// Stores possible comments in `m_comment'.
+void NativeImportBase::scan(QString line) {
+ if (preprocess(line))
+ return;
+ // Check for single line comment.
+ int pos = line.find(m_singleLineCommentIntro);
+ if (pos != -1) {
+ QString cmnt = line.mid(pos);
+ m_source.append(cmnt);
+ if (pos == 0)
+ return;
+ line = line.left(pos);
+ }
+ if (line.contains(QRegExp("^\\s*$")))
+ return;
+ QStringList words = split(line);
+ for (QStringList::Iterator it = words.begin(); it != words.end(); ++it) {
+ QString word = *it;
+ if (word[0] == '"' || word[0] == '\'')
+ m_source.append(word); // string constants are handled by split()
+ else
+ fillSource(word);
+ }
+}
+
+void NativeImportBase::initVars() {
+}
+
+void NativeImportBase::parseFile(const QString& filename) {
+ QString nameWithoutPath = filename;
+ nameWithoutPath.remove(QRegExp("^.*/"));
+ if (m_parsedFiles.contains(nameWithoutPath))
+ return;
+ m_parsedFiles.append(nameWithoutPath);
+ QString fname = filename;
+ const QString msgPrefix = "NativeImportBase::parseFile(" + filename + "): ";
+ if (filename.contains('/')) {
+ QString path = filename;
+ path.remove( QRegExp("/[^/]+$") );
+ kDebug() << msgPrefix << "adding path " << path << endl;
+ Import_Utils::addIncludePath(path);
+ }
+ if (! QFile::exists(filename)) {
+ if (filename.startsWith("/")) {
+ kError() << msgPrefix << "cannot find file" << endl;
+ return;
+ }
+ bool found = false;
+ QStringList includePaths = Import_Utils::includePathList();
+ for (QStringList::Iterator pathIt = includePaths.begin();
+ pathIt != includePaths.end(); ++pathIt) {
+ QString path = (*pathIt);
+ if (! path.endsWith("/")) {
+ path.append("/");
+ }
+ if (QFile::exists(path + filename)) {
+ fname.prepend(path);
+ found = true;
+ break;
+ }
+ }
+ if (! found) {
+ kError() << msgPrefix << "cannot find file" << endl;
+ return;
+ }
+ }
+ QFile file(fname);
+ if (! file.open(IO_ReadOnly)) {
+ kError() << msgPrefix << "cannot open file" << endl;
+ return;
+ }
+ kDebug() << msgPrefix << "parsing." << endl;
+ // Scan the input file into the QStringList m_source.
+ m_source.clear();
+ m_srcIndex = 0;
+ initVars();
+ QTextStream stream(&file);
+ while (! stream.atEnd()) {
+ QString line = stream.readLine();
+ scan(line);
+ }
+ file.close();
+ // Parse the QStringList m_source.
+ m_klass = NULL;
+ m_currentAccess = Uml::Visibility::Public;
+ m_scopeIndex = 0;
+ m_scope[0] = NULL; // index 0 is reserved for global scope
+ const uint srcLength = m_source.count();
+ for (m_srcIndex = 0; m_srcIndex < srcLength; m_srcIndex++) {
+ const QString& firstToken = m_source[m_srcIndex];
+ //kDebug() << '"' << firstToken << '"' << endl;
+ if (firstToken.startsWith(m_singleLineCommentIntro)) {
+ m_comment = firstToken.mid(m_singleLineCommentIntro.length());
+ continue;
+ }
+ if (! parseStmt())
+ skipStmt();
+ m_comment = QString();
+ }
+ kDebug() << msgPrefix << "end of parse." << endl;
+}
+
+void NativeImportBase::initialize() {
+ m_parsedFiles.clear();
+}
+
diff --git a/umbrello/umbrello/codeimport/nativeimportbase.h b/umbrello/umbrello/codeimport/nativeimportbase.h
new file mode 100644
index 00000000..cc82fd91
--- /dev/null
+++ b/umbrello/umbrello/codeimport/nativeimportbase.h
@@ -0,0 +1,227 @@
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * copyright (C) 2005-2007 *
+ * Umbrello UML Modeller Authors <uml-devel@uml.sf.net> *
+ ***************************************************************************/
+
+#ifndef NATIVEIMPORTBASE_H
+#define NATIVEIMPORTBASE_H
+
+#include <qstring.h>
+#include <qstringlist.h>
+#include "classimport.h"
+#include "../umlnamespace.h"
+
+class UMLPackage;
+class UMLClassifier;
+
+/**
+ * Intermediate base class for native Umbrello implementations of
+ * programming language import
+ *
+ * The default call sequence is as follows (RealizedLanguageImport
+ * is used as a placeholder name for the concrete language importer.)
+ * NativeImportBase RealizedLanguageImport
+ * --> importFiles()
+ * parseFile()
+ * -----------------------------------> initVars()
+ * scan()
+ * preprocess() (may be reimplemented)
+ * ---------------------------------> fillSource()
+ * -----------------------------------> parseStmt()
+ * This sequence may be changed by overriding default implementations
+ * of virtual methods in NativeImportBase.
+ *
+ * @short Base class for native implementations of language import
+ * @author Oliver Kellogg <okellogg@users.sourceforge.net>
+ * Bugs and comments to uml-devel@lists.sf.net or http://bugs.kde.org
+ */
+class NativeImportBase : public ClassImport {
+public:
+ /**
+ * Constructor
+ * @param singleLineCommentIntro "//" for IDL and Java, "--" for Ada
+ */
+ NativeImportBase(const QString &singleLineCommentIntro);
+ virtual ~NativeImportBase();
+
+protected:
+ /**
+ * Implement abstract operation from ClassImport.
+ */
+ void initialize();
+
+ /**
+ * Set the delimiter strings for a multi line comment.
+ *
+ * @param intro In languages with a C style multiline comment
+ * this is slash-star.
+ * @param end In languages with a C style multiline comment
+ * this is star-slash.
+ */
+ void setMultiLineComment(const QString &intro, const QString &end);
+ /**
+ * Set the delimiter strings for an alternative form of
+ * multi line comment. See setMultiLineComment().
+ */
+ void setMultiLineAltComment(const QString &intro, const QString &end);
+
+ /**
+ * Import a single file.
+ * The default implementation should be feasible for languages that
+ * don't depend on an external preprocessor.
+ *
+ * @param filename The file to import.
+ */
+ virtual void parseFile(const QString& filename);
+
+ /**
+ * Initialize auxiliary variables.
+ * This is called by the default implementation of parseFile()
+ * after scanning (before parsing the QStringList m_source.)
+ * The default implementation is empty.
+ */
+ virtual void initVars();
+
+ /**
+ * Scan a single line.
+ * parseFile() calls this for each line read from the input file.
+ * This in turn calls other methods such as preprocess() and fillSource().
+ *
+ * @param line The line to scan.
+ */
+ void scan(QString line);
+
+ /**
+ * Preprocess a line.
+ * May modify the given line to remove items consumed by the
+ * preprocessing such as comments or preprocessor directives.
+ * The default implementation handles multi-line comments.
+ *
+ * @param line The line to preprocess.
+ * @return True if the line was completely consumed,
+ * false if there are still items left in the line
+ * for further analysis.
+ */
+ virtual bool preprocess(QString& line);
+
+ /**
+ * Split the line so that a string is returned as a single element of the list.
+ * When not in a string then split at white space.
+ * The default implementation is suitable for C style strings and char constants.
+ */
+ virtual QStringList split(const QString& line);
+
+ /**
+ * Analyze the given word and fill `m_source'.
+ * A "word" is a whitespace delimited item from the input line.
+ * To be provided by the specific importer class.
+ */
+ virtual void fillSource(const QString& word) = 0;
+
+ /**
+ * Parse the statement which starts at m_source[m_srcIndex]
+ * leaving m_srcIndex pointing to the end of the recognized
+ * statement.
+ * To be provided by the concrete importer.
+ *
+ * @return True if the statement was recognized.
+ */
+ virtual bool parseStmt() = 0;
+
+ /**
+ * Advance m_srcIndex until m_source[m_srcIndex] contains the lexeme
+ * given by `until'.
+ */
+ void skipStmt(QString until = ";");
+
+ /**
+ * Advance m_srcIndex to the index of the corresponding closing character
+ * of the given opening. Nested opening/closing pairs are respected.
+ * Valid openers are: '{' '[' '(' '<'
+ *
+ * @return True for success, false for misuse (invalid opener) or
+ * if no matching closing character is found in m_source.
+ */
+ bool skipToClosing(QChar opener);
+
+ /**
+ * Advance m_srcIndex until m_source[m_srcIndex] contains a non-comment.
+ * Comments encountered during advancement are accumulated in `m_comment'.
+ * If m_srcIndex hits the end of m_source then QString::null is returned.
+ */
+ QString advance();
+
+ /**
+ * How to start a single line comment in this programming language.
+ */
+ QString m_singleLineCommentIntro;
+
+ /**
+ * The scanned lexemes.
+ */
+ QStringList m_source;
+ /**
+ * Used for indexing m_source.
+ */
+ uint m_srcIndex;
+
+ /**
+ * Stack of scopes for use by the specific importer.
+ */
+ UMLPackage *m_scope[32];
+ /**
+ * Indexes m_scope. Index 0 is reserved for global scope.
+ */
+ uint m_scopeIndex;
+
+ /**
+ * The class currently being processed.
+ */
+ UMLClassifier *m_klass;
+ /**
+ * The current access (public/protected/private)
+ */
+ Uml::Visibility m_currentAccess;
+ /**
+ * Intermediate accumulator for comment text.
+ */
+ QString m_comment;
+ /**
+ * True if we are currently in a multi-line comment.
+ * Only applies to languages with multi-line comments.
+ */
+ bool m_inComment;
+ /**
+ * Accumulator for abstractness
+ */
+ bool m_isAbstract;
+
+ /**
+ * List of parsed files. Contains file names without paths.
+ * Before actually parsing a given file, NativeImportBase checks
+ * whether the name is already present in this list in order to
+ * avoid parsing the same file multiple times.
+ */
+ QStringList m_parsedFiles;
+
+ /**
+ * Multi line comment delimiters
+ */
+ QString m_multiLineCommentIntro;
+ QString m_multiLineCommentEnd;
+ /**
+ * Some languages support an alternative set of multi line
+ * comment delimiters.
+ */
+ QString m_multiLineAltCommentIntro;
+ QString m_multiLineAltCommentEnd;
+};
+
+#endif
+
diff --git a/umbrello/umbrello/codeimport/pascalimport.cpp b/umbrello/umbrello/codeimport/pascalimport.cpp
new file mode 100644
index 00000000..ffe291ff
--- /dev/null
+++ b/umbrello/umbrello/codeimport/pascalimport.cpp
@@ -0,0 +1,413 @@
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * copyright (C) 2006-2007 *
+ * Umbrello UML Modeller Authors <uml-devel@uml.sf.net> *
+ ***************************************************************************/
+
+// own header
+#include "pascalimport.h"
+
+#include <stdio.h>
+// qt/kde includes
+#include <qregexp.h>
+#include <kdebug.h>
+// app includes
+#include "import_utils.h"
+#include "../uml.h"
+#include "../umldoc.h"
+#include "../package.h"
+#include "../classifier.h"
+#include "../enum.h"
+#include "../operation.h"
+#include "../attribute.h"
+
+PascalImport::PascalImport() : NativeImportBase("//") {
+ setMultiLineComment("(*", "*)");
+ setMultiLineAltComment("{", "}");
+ initVars();
+}
+
+PascalImport::~PascalImport() {
+}
+
+void PascalImport::initVars() {
+ m_inInterface = false;
+ m_section = sect_NONE;
+ NativeImportBase::m_currentAccess = Uml::Visibility::Public;
+}
+
+void PascalImport::fillSource(const QString& word) {
+ QString lexeme;
+ const uint len = word.length();
+ for (uint i = 0; i < len; i++) {
+ QChar c = word[i];
+ if (c.isLetterOrNumber() || c == '_' || c == '.' || c == '#') {
+ lexeme += c;
+ } else {
+ if (!lexeme.isEmpty()) {
+ m_source.append(lexeme);
+ lexeme = QString();
+ }
+ if (c == ':' && word[i + 1] == '=') {
+ m_source.append(":=");
+ i++;
+ } else {
+ m_source.append(QString(c));
+ }
+ }
+ }
+ if (!lexeme.isEmpty())
+ m_source.append(lexeme);
+}
+
+void PascalImport::checkModifiers(bool& isVirtual, bool& isAbstract) {
+ const uint srcLength = m_source.count();
+ while (m_srcIndex < srcLength - 1) {
+ QString lookAhead = m_source[m_srcIndex + 1].lower();
+ if (lookAhead != "virtual" && lookAhead != "abstract" &&
+ lookAhead != "override" &&
+ lookAhead != "register" && lookAhead != "cdecl" &&
+ lookAhead != "pascal" && lookAhead != "stdcall" &&
+ lookAhead != "safecall" && lookAhead != "saveregisters" &&
+ lookAhead != "popstack")
+ break;
+ if (lookAhead == "abstract")
+ isAbstract = true;
+ else if (lookAhead == "virtual")
+ isVirtual = true;
+ advance();
+ skipStmt();
+ }
+}
+
+bool PascalImport::parseStmt() {
+ const uint srcLength = m_source.count();
+ QString keyword = m_source[m_srcIndex].lower();
+ //kDebug() << '"' << keyword << '"' << endl;
+ if (keyword == "uses") {
+ while (m_srcIndex < srcLength - 1) {
+ QString unit = advance();
+ const QString& prefix = unit.lower();
+ if (prefix == "sysutils" || prefix == "types" || prefix == "classes" ||
+ prefix == "graphics" || prefix == "controls" || prefix == "strings" ||
+ prefix == "forms" || prefix == "windows" || prefix == "messages" ||
+ prefix == "variants" || prefix == "stdctrls" || prefix == "extctrls" ||
+ prefix == "activex" || prefix == "comobj" || prefix == "registry" ||
+ prefix == "classes" || prefix == "dialogs") {
+ if (advance() != ",")
+ break;
+ continue;
+ }
+ QString filename = unit + ".pas";
+ if (! m_parsedFiles.contains(unit)) {
+ // Save current m_source and m_srcIndex.
+ QStringList source(m_source);
+ uint srcIndex = m_srcIndex;
+ m_source.clear();
+ parseFile(filename);
+ // Restore m_source and m_srcIndex.
+ m_source = source;
+ m_srcIndex = srcIndex;
+ // Also reset m_currentAccess.
+ // CHECK: need to reset more stuff?
+ m_currentAccess = Uml::Visibility::Public;
+ }
+ if (advance() != ",")
+ break;
+ }
+ return true;
+ }
+ if (keyword == "unit") {
+ const QString& name = advance();
+ UMLObject *ns = Import_Utils::createUMLObject(Uml::ot_Package, name,
+ m_scope[m_scopeIndex], m_comment);
+ m_scope[++m_scopeIndex] = static_cast<UMLPackage*>(ns);
+ skipStmt();
+ return true;
+ }
+ if (keyword == "interface") {
+ m_inInterface = true;
+ return true;
+ }
+ if (keyword == "initialization" || keyword == "implementation") {
+ m_inInterface = false;
+ return true;
+ }
+ if (! m_inInterface) {
+ // @todo parseStmt() should support a notion for "quit parsing, close file immediately"
+ return false;
+ }
+ if (keyword == "label") {
+ m_section = sect_LABEL;
+ return true;
+ }
+ if (keyword == "const") {
+ m_section = sect_CONST;
+ return true;
+ }
+ if (keyword == "resourcestring") {
+ m_section = sect_RESOURCESTRING;
+ return true;
+ }
+ if (keyword == "type") {
+ m_section = sect_TYPE;
+ return true;
+ }
+ if (keyword == "var") {
+ m_section = sect_VAR;
+ return true;
+ }
+ if (keyword == "threadvar") {
+ m_section = sect_THREADVAR;
+ return true;
+ }
+ if (keyword == "automated" || keyword == "published" // no concept in UML
+ || keyword == "public") {
+ m_currentAccess = Uml::Visibility::Public;
+ return true;
+ }
+ if (keyword == "protected") {
+ m_currentAccess = Uml::Visibility::Protected;
+ return true;
+ }
+ if (keyword == "private") {
+ m_currentAccess = Uml::Visibility::Private;
+ return true;
+ }
+ if (keyword == "packed") {
+ return true; // TBC: perhaps this could be stored in a TaggedValue
+ }
+ if (keyword == "[") {
+ skipStmt("]");
+ return true;
+ }
+ if (keyword == "end") {
+ if (m_klass) {
+ m_klass = NULL;
+ } else if (m_scopeIndex) {
+ m_scopeIndex--;
+ m_currentAccess = Uml::Visibility::Public;
+ } else {
+ kError() << "importPascal: too many \"end\"" << endl;
+ }
+ skipStmt();
+ return true;
+ }
+ if (keyword == "function" || keyword == "procedure" ||
+ keyword == "constructor" || keyword == "destructor") {
+ if (m_klass == NULL) {
+ // Unlike a Pascal unit, a UML package does not support subprograms.
+ // In order to map those, we would need to create a UML class with
+ // stereotype <<utility>> for the unit, http://bugs.kde.org/89167
+ bool dummyVirtual = false;
+ bool dummyAbstract = false;
+ checkModifiers(dummyVirtual, dummyAbstract);
+ return true;
+ }
+ const QString& name = advance();
+ UMLOperation *op = Import_Utils::makeOperation(m_klass, name);
+ if (m_source[m_srcIndex + 1] == "(") {
+ advance();
+ const uint MAX_PARNAMES = 16;
+ while (m_srcIndex < srcLength && m_source[m_srcIndex] != ")") {
+ QString nextToken = m_source[m_srcIndex + 1].lower();
+ Uml::Parameter_Direction dir = Uml::pd_In;
+ if (nextToken == "var") {
+ dir = Uml::pd_InOut;
+ advance();
+ } else if (nextToken == "const") {
+ advance();
+ } else if (nextToken == "out") {
+ dir = Uml::pd_Out;
+ advance();
+ }
+ QString parName[MAX_PARNAMES];
+ uint parNameCount = 0;
+ do {
+ if (parNameCount >= MAX_PARNAMES) {
+ kError() << "MAX_PARNAMES is exceeded at " << name << endl;
+ break;
+ }
+ parName[parNameCount++] = advance();
+ } while (advance() == ",");
+ if (m_source[m_srcIndex] != ":") {
+ kError() << "importPascal: expecting ':' at " << m_source[m_srcIndex] << endl;
+ skipStmt();
+ break;
+ }
+ nextToken = advance();
+ if (nextToken.lower() == "array") {
+ nextToken = advance().lower();
+ if (nextToken != "of") {
+ kError() << "importPascal(" << name << "): expecting 'array OF' at "
+ << nextToken << endl;
+ skipStmt();
+ return false;
+ }
+ nextToken = advance();
+ }
+ for (uint i = 0; i < parNameCount; i++) {
+ UMLAttribute *att = Import_Utils::addMethodParameter(op, nextToken, parName[i]);
+ att->setParmKind(dir);
+ }
+ if (advance() != ";")
+ break;
+ }
+ }
+ QString returnType;
+ if (keyword == "function") {
+ if (advance() != ":") {
+ kError() << "importPascal: expecting \":\" at function "
+ << name << endl;
+ return false;
+ }
+ returnType = advance();
+ } else if (keyword == "constructor" || keyword == "destructor") {
+ op->setStereotype(keyword);
+ }
+ skipStmt();
+ bool isVirtual = false;
+ bool isAbstract = false;
+ checkModifiers(isVirtual, isAbstract);
+ Import_Utils::insertMethod(m_klass, op, m_currentAccess, returnType,
+ !isVirtual, isAbstract, false, false, m_comment);
+ return true;
+ }
+ if (m_section != sect_TYPE) {
+ skipStmt();
+ return true;
+ }
+ if (m_klass == NULL) {
+ const QString& name = m_source[m_srcIndex];
+ QString nextToken = advance();
+ if (nextToken != "=") {
+ kDebug() << "PascalImport::parseStmt(" << name << "): "
+ << "expecting '=' at " << nextToken << endl;
+ return false;
+ }
+ keyword = advance().lower();
+ if (keyword == "(") {
+ // enum type
+ UMLObject *ns = Import_Utils::createUMLObject(Uml::ot_Enum,
+ name, m_scope[m_scopeIndex], m_comment);
+ UMLEnum *enumType = static_cast<UMLEnum*>(ns);
+ while (++m_srcIndex < srcLength && m_source[m_srcIndex] != ")") {
+ Import_Utils::addEnumLiteral(enumType, m_source[m_srcIndex]);
+ if (advance() != ",")
+ break;
+ }
+ skipStmt();
+ return true;
+ }
+ if (keyword == "set") { // @todo implement Pascal set types
+ skipStmt();
+ return true;
+ }
+ if (keyword == "array") { // @todo implement Pascal array types
+ skipStmt();
+ return true;
+ }
+ if (keyword == "file") { // @todo implement Pascal file types
+ skipStmt();
+ return true;
+ }
+ if (keyword == "^") { // @todo implement Pascal pointer types
+ skipStmt();
+ return true;
+ }
+ if (keyword == "class" || keyword == "interface") {
+ Uml::Object_Type t = (keyword == "class" ? Uml::ot_Class : Uml::ot_Interface);
+ UMLObject *ns = Import_Utils::createUMLObject(t, name,
+ m_scope[m_scopeIndex], m_comment);
+ UMLClassifier *klass = static_cast<UMLClassifier*>(ns);
+ m_comment = QString();
+ QString lookAhead = m_source[m_srcIndex + 1];
+ if (lookAhead == "(") {
+ advance();
+ do {
+ QString base = advance();
+ UMLObject *ns = Import_Utils::createUMLObject(Uml::ot_Class, base, NULL);
+ UMLClassifier *parent = static_cast<UMLClassifier*>(ns);
+ m_comment = QString();
+ Import_Utils::createGeneralization(klass, parent);
+ } while (advance() == ",");
+ if (m_source[m_srcIndex] != ")") {
+ kError() << "PascalImport: expecting \")\" at "
+ << m_source[m_srcIndex] << endl;
+ return false;
+ }
+ lookAhead = m_source[m_srcIndex + 1];
+ }
+ if (lookAhead == ";") {
+ skipStmt();
+ return true;
+ }
+ if (lookAhead == "of") {
+ // @todo implement class-reference type
+ return false;
+ }
+ m_klass = klass;
+ m_currentAccess = Uml::Visibility::Public;
+ return true;
+ }
+ if (keyword == "record") {
+ UMLObject *ns = Import_Utils::createUMLObject(Uml::ot_Class, name,
+ m_scope[m_scopeIndex], m_comment);
+ ns->setStereotype("record");
+ m_klass = static_cast<UMLClassifier*>(ns);
+ return true;
+ }
+ if (keyword == "function" || keyword == "procedure") {
+ UMLObject *ns = Import_Utils::createUMLObject(Uml::ot_Datatype, name,
+ m_scope[m_scopeIndex], m_comment);
+ if (m_source[m_srcIndex + 1] == "(")
+ skipToClosing('(');
+ skipStmt();
+ return true;
+ }
+ // Datatypes: TO BE DONE
+ return false;
+ }
+ // At this point we need a class because we're expecting its member attributes.
+ if (m_klass == NULL) {
+ kDebug() << "importPascal: skipping " << m_source[m_srcIndex] << endl;
+ skipStmt();
+ return true;
+ }
+ QString name, stereotype;
+ if (keyword == "property") {
+ stereotype = keyword;
+ name = advance();
+ } else {
+ name = m_source[m_srcIndex];
+ }
+ if (advance() != ":") {
+ kError() << "PascalImport: expecting \":\" at " << name << " "
+ << m_source[m_srcIndex] << endl;
+ skipStmt();
+ return true;
+ }
+ QString typeName = advance();
+ QString initialValue;
+ if (advance() == "=") {
+ initialValue = advance();
+ QString token;
+ while ((token = advance()) != ";") {
+ initialValue.append(' ' + token);
+ }
+ }
+ UMLObject *o = Import_Utils::insertAttribute(m_klass, m_currentAccess, name,
+ typeName, m_comment);
+ UMLAttribute *attr = static_cast<UMLAttribute*>(o);
+ attr->setStereotype(stereotype);
+ attr->setInitialValue(initialValue);
+ skipStmt();
+ return true;
+}
+
+
diff --git a/umbrello/umbrello/codeimport/pascalimport.h b/umbrello/umbrello/codeimport/pascalimport.h
new file mode 100644
index 00000000..975dc423
--- /dev/null
+++ b/umbrello/umbrello/codeimport/pascalimport.h
@@ -0,0 +1,66 @@
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * copyright (C) 2006 *
+ * Umbrello UML Modeller Authors <uml-devel@uml.sf.net> *
+ ***************************************************************************/
+
+#ifndef PASCALIMPORT_H
+#define PASCALIMPORT_H
+
+#include "nativeimportbase.h"
+
+/**
+ * Pascal code import
+ * @author Oliver Kellogg
+ * Bugs and comments to uml-devel@lists.sf.net or http://bugs.kde.org
+ */
+class PascalImport : public NativeImportBase {
+public:
+ PascalImport();
+ virtual ~PascalImport();
+
+protected:
+ /**
+ * Reimplement operation from NativeImportBase.
+ */
+ void initVars();
+
+ /**
+ * Implement abstract operation from NativeImportBase.
+ */
+ bool parseStmt();
+
+ /**
+ * Implement abstract operation from NativeImportBase.
+ */
+ void fillSource(const QString& word);
+
+ /**
+ * Check for, and skip over, all modifiers following a method.
+ * Set the output arguments on encountering abstract and/or virtual.
+ *
+ * @param isVirtual return value, set to true when "virtual" seen
+ * @param isAbstract return value, set to true when "abstract" seen
+ */
+ void checkModifiers(bool& isVirtual, bool& isAbstract);
+
+ /**
+ * Auxiliary variable, becomes true when keyword "interface" is seen
+ */
+ bool m_inInterface;
+
+ enum Section_Type { sect_NONE, sect_LABEL, sect_CONST, sect_RESOURCESTRING,
+ sect_TYPE, sect_VAR, sect_THREADVAR };
+ /**
+ * Auxiliary variable, contains the current section
+ */
+ Section_Type m_section;
+};
+
+#endif
+
diff --git a/umbrello/umbrello/codeimport/pythonimport.cpp b/umbrello/umbrello/codeimport/pythonimport.cpp
new file mode 100644
index 00000000..af59cf8a
--- /dev/null
+++ b/umbrello/umbrello/codeimport/pythonimport.cpp
@@ -0,0 +1,190 @@
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * copyright (C) 2006 *
+ * Umbrello UML Modeller Authors <uml-devel@uml.sf.net> *
+ ***************************************************************************/
+
+// own header
+#include "pythonimport.h"
+
+// qt/kde includes
+#include <qstringlist.h>
+#include <qregexp.h>
+#include <kdebug.h>
+// app includes
+#include "import_utils.h"
+#include "../uml.h"
+#include "../umldoc.h"
+#include "../umlpackagelist.h"
+#include "../package.h"
+#include "../classifier.h"
+#include "../enum.h"
+#include "../operation.h"
+#include "../attribute.h"
+
+PythonImport::PythonImport() : NativeImportBase("#") {
+ setMultiLineComment("\"\"\"", "\"\"\"");
+ initVars();
+}
+
+PythonImport::~PythonImport() {
+}
+
+void PythonImport::initVars() {
+ m_srcIndentIndex = 0;
+ m_srcIndent[m_srcIndentIndex] = 0;
+ m_braceWasOpened = false;
+}
+
+bool PythonImport::preprocess(QString& line) {
+ if (NativeImportBase::preprocess(line))
+ return true;
+ // Handle single line comment
+ int pos = line.find(m_singleLineCommentIntro);
+ if (pos != -1) {
+ QString cmnt = line.mid(pos);
+ m_source.append(cmnt);
+ m_srcIndex++;
+ if (pos == 0)
+ return true;
+ line = line.left(pos);
+ line.remove( QRegExp("\\s+$") );
+ }
+ // Transform changes in indentation into braces a la C++/Java/Perl/...
+ pos = line.find( QRegExp("\\S") );
+ if (pos == -1)
+ return true;
+ bool isContinuation = false;
+ int leadingWhite = line.left(pos).contains( QRegExp("\\s") );
+ if (leadingWhite > m_srcIndent[m_srcIndentIndex]) {
+ if (m_srcIndex == 0) {
+ kError() << "PythonImport::preprocess(): internal error 1" << endl;
+ return true;
+ }
+ if (m_braceWasOpened) {
+ m_srcIndent[++m_srcIndentIndex] = leadingWhite;
+ m_braceWasOpened = false;
+ } else {
+ isContinuation = true;
+ }
+ } else {
+ while (m_srcIndentIndex > 0 && leadingWhite < m_srcIndent[m_srcIndentIndex]) {
+ m_srcIndentIndex--;
+ m_source.append("}");
+ m_srcIndex++;
+ }
+ }
+ if (line.endsWith(":")) {
+ line.replace( QRegExp(":$"), "{" );
+ m_braceWasOpened = true;
+ } else {
+ m_braceWasOpened = false;
+ }
+ if (!isContinuation && !m_braceWasOpened)
+ line += ';';
+ return false; // The input was not completely consumed by preprocessing.
+}
+
+void PythonImport::fillSource(const QString& word) {
+ QString lexeme;
+ const uint len = word.length();
+ for (uint i = 0; i < len; i++) {
+ const QChar& c = word[i];
+ if (c.isLetterOrNumber() || c == '_' || c == '.') {
+ lexeme += c;
+ } else {
+ if (!lexeme.isEmpty()) {
+ m_source.append(lexeme);
+ m_srcIndex++;
+ lexeme = QString();
+ }
+ m_source.append(QString(c));
+ m_srcIndex++;
+ }
+ }
+ if (!lexeme.isEmpty()) {
+ m_source.append(lexeme);
+ m_srcIndex++;
+ }
+}
+
+void PythonImport::skipBody() {
+ if (m_source[m_srcIndex] != "{")
+ skipStmt("{");
+ int braceNesting = 0;
+ QString token;
+ while (!(token = advance()).isNull()) {
+ if (token == "}") {
+ if (braceNesting <= 0)
+ break;
+ braceNesting--;
+ } else if (token == "{") {
+ braceNesting++;
+ }
+ }
+}
+
+bool PythonImport::parseStmt() {
+ const uint srcLength = m_source.count();
+ const QString& keyword = m_source[m_srcIndex];
+ if (keyword == "class") {
+ const QString& name = advance();
+ UMLObject *ns = Import_Utils::createUMLObject(Uml::ot_Class,
+ name, m_scope[m_scopeIndex], m_comment);
+ m_scope[++m_scopeIndex] = m_klass = static_cast<UMLClassifier*>(ns);
+ m_comment = QString();
+ if (advance() == "(") {
+ while (m_srcIndex < srcLength - 1 && advance() != ")") {
+ const QString& baseName = m_source[m_srcIndex];
+ Import_Utils::createGeneralization(m_klass, baseName);
+ if (advance() != ",")
+ break;
+ }
+ }
+ if (m_source[m_srcIndex] != "{") {
+ skipStmt("{");
+ }
+ return true;
+ }
+ if (keyword == "def") {
+ if (m_klass == NULL) {
+ // skip functions outside of a class
+ skipBody();
+ return true;
+ }
+ const QString& name = advance();
+ // operation
+ UMLOperation *op = Import_Utils::makeOperation(m_klass, name);
+ if (advance() != "(") {
+ kError() << "importPython def " << name << ": expecting \"(\"" << endl;
+ skipBody();
+ return true;
+ }
+ while (m_srcIndex < srcLength && advance() != ")") {
+ const QString& parName = m_source[m_srcIndex];
+ UMLAttribute *att = Import_Utils::addMethodParameter(op, "string", parName);
+ if (advance() != ",")
+ break;
+ }
+ Import_Utils::insertMethod(m_klass, op, Uml::Visibility::Public, "string",
+ false /*isStatic*/, false /*isAbstract*/, false /*isFriend*/,
+ false /*isConstructor*/, m_comment);
+ skipBody();
+ return true;
+ }
+ if (keyword == "}") {
+ if (m_scopeIndex)
+ m_klass = dynamic_cast<UMLClassifier*>(m_scope[--m_scopeIndex]);
+ else
+ kError() << "importPython: too many }" << endl;
+ return true;
+ }
+ return false; // @todo parsing of attributes
+}
+
+
diff --git a/umbrello/umbrello/codeimport/pythonimport.h b/umbrello/umbrello/codeimport/pythonimport.h
new file mode 100644
index 00000000..41fea0d4
--- /dev/null
+++ b/umbrello/umbrello/codeimport/pythonimport.h
@@ -0,0 +1,76 @@
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * copyright (C) 2006 *
+ * Umbrello UML Modeller Authors <uml-devel@uml.sf.net> *
+ ***************************************************************************/
+
+#ifndef PYTHONIMPORT_H
+#define PYTHONIMPORT_H
+
+#include "nativeimportbase.h"
+
+/**
+ * Python code import
+ * @author Oliver Kellogg
+ * Bugs and comments to uml-devel@lists.sf.net or http://bugs.kde.org
+ */
+class PythonImport : public NativeImportBase {
+public:
+ PythonImport();
+ virtual ~PythonImport();
+
+protected:
+ /**
+ * Reimplement operation from NativeImportBase.
+ */
+ void initVars();
+
+ /**
+ * Implement abstract operation from NativeImportBase.
+ */
+ bool parseStmt();
+
+ /**
+ * Implement abstract operation from NativeImportBase.
+ */
+ void fillSource(const QString& line);
+
+ /**
+ * Reimplement operation from NativeImportBase.
+ * In addition to handling multiline comments, this method transforms
+ * changes in leading indentation into braces (opening brace for increase
+ * in indentation, closing brace for decrease in indentation) in m_source.
+ * Removal of Python's indentation sensitivity simplifies subsequent
+ * processing using Umbrello's native import framework.
+ */
+ bool preprocess(QString& line);
+
+ /**
+ * Skip ahead to outermost closing brace
+ */
+ void skipBody();
+
+ /**
+ * Buffer for number of indentation characters (whitespace,
+ * i.e. tabs or spaces) at beginning of input line.
+ */
+ int m_srcIndent[100];
+
+ /**
+ * Index for m_srcIndent[]. Index 0 is reserved and contains 0.
+ */
+ int m_srcIndentIndex;
+
+ /**
+ * Auxiliary flag denoting the opening of a block
+ */
+ bool m_braceWasOpened;
+};
+
+#endif
+
diff --git a/umbrello/umbrello/codemethodblock.cpp b/umbrello/umbrello/codemethodblock.cpp
new file mode 100644
index 00000000..4a6e1f6a
--- /dev/null
+++ b/umbrello/umbrello/codemethodblock.cpp
@@ -0,0 +1,191 @@
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * copyright (C) 2004-2006 *
+ * Umbrello UML Modeller Authors <uml-devel@uml.sf.net> *
+ ***************************************************************************/
+
+/* This code generated by:
+ * Author : thomas
+ * Date : Fri Jun 20 2003
+ */
+#include "codemethodblock.h"
+#include "codeclassfield.h"
+#include "classifiercodedocument.h"
+#include "codegenerationpolicy.h"
+#include "uml.h"
+
+// Constructors/Destructors
+//
+
+CodeMethodBlock::CodeMethodBlock ( ClassifierCodeDocument * doc, UMLObject * parentObj, const QString & body, const QString & comment)
+ : CodeBlockWithComments ((CodeDocument*)doc, body, comment), OwnedCodeBlock (parentObj)
+{
+ initFields();
+}
+
+CodeMethodBlock::~CodeMethodBlock ( ) { }
+
+//
+// Methods
+//
+
+
+// Accessor methods
+//
+
+// we can just call the superclass
+CodeDocument * CodeMethodBlock::getParentDocument() {
+ return TextBlock::getParentDocument();
+}
+
+/**
+ * Get the starting text that begins this method before the body is printed.
+ */
+QString CodeMethodBlock::getStartMethodText() const {
+ return m_startMethod;
+}
+
+/**
+ * Get the ending text that finishes this method after the body is printed.
+ */
+QString CodeMethodBlock::getEndMethodText() const {
+ return m_endMethod;
+}
+
+/**
+ * Set the starting text that begins this method before the body is printed.
+ */
+void CodeMethodBlock::setStartMethodText (const QString &value) {
+ m_startMethod = value;
+}
+
+/**
+ * Set the ending text that finishes this method after the body is printed.
+ */
+void CodeMethodBlock::setEndMethodText (const QString &value) {
+ m_endMethod = value;
+}
+
+// Other methods
+//
+
+void CodeMethodBlock::release () {
+ // just call super-class versions
+ OwnedCodeBlock::release();
+ TextBlock::release();
+}
+
+/** set attributes of the node that represents this class
+ * in the XMI document.
+ */
+void CodeMethodBlock::setAttributesOnNode ( QDomDocument & doc, QDomElement & elem) {
+
+ // set super-class attributes
+ CodeBlockWithComments::setAttributesOnNode(doc, elem);
+ OwnedCodeBlock::setAttributesOnNode(doc, elem);
+
+ // set local class attributes
+ if(getContentType() != AutoGenerated)
+ {
+ QString endLine = UMLApp::app()->getCommonPolicy()->getNewLineEndingChars();
+ elem.setAttribute("startMethodText",encodeText(getStartMethodText(),endLine));
+ elem.setAttribute("endMethodText",encodeText(getEndMethodText(),endLine));
+ }
+
+}
+
+/** set the class attributes of this object from
+ * the passed element node.
+ */
+void CodeMethodBlock::setAttributesFromNode ( QDomElement & elem) {
+
+ // set attributes from the XMI
+ CodeBlockWithComments::setAttributesFromNode(elem); // superclass load
+ OwnedCodeBlock::setAttributesFromNode(elem); // superclass load
+
+ // now load local attributes
+ if(getContentType() != AutoGenerated)
+ {
+ QString endLine = UMLApp::app()->getCommonPolicy()->getNewLineEndingChars();
+ setStartMethodText(decodeText(elem.attribute("startMethodText",""),endLine));
+ setEndMethodText(decodeText(elem.attribute("endMethodText",""),endLine));
+ }
+
+}
+
+void CodeMethodBlock::setAttributesFromObject(TextBlock * obj)
+{
+
+ CodeBlockWithComments::setAttributesFromObject(obj);
+
+ CodeMethodBlock * mb = dynamic_cast<CodeMethodBlock*>(obj);
+ if(mb)
+ {
+ setStartMethodText(mb->getStartMethodText());
+ setEndMethodText(mb->getEndMethodText());
+ }
+
+}
+
+/**
+ * @return QString
+ */
+QString CodeMethodBlock::toString ( ) {
+
+ QString string = QString("");
+
+ if(getWriteOutText()) {
+
+ QString indent = getIndentationString();
+ QString bodyIndent = getIndentationString(getIndentationLevel()+1);
+ QString endLine = UMLApp::app()->getCommonPolicy()->getNewLineEndingChars();
+
+ QString startMethod = formatMultiLineText ( getStartMethodText(), indent, endLine);
+ QString body = formatMultiLineText (getText(), bodyIndent, endLine);
+ QString endMethod = formatMultiLineText( getEndMethodText(), indent, endLine);
+
+ QString comment = getComment()->toString();
+ if(!comment.isEmpty() && getComment()->getWriteOutText())
+ string.append(comment);
+
+ if(!startMethod.isEmpty())
+ string.append(startMethod);
+
+ if(!body.isEmpty())
+ string.append(body);
+
+ if(!endMethod.isEmpty())
+ string.append(endMethod);
+
+ }
+
+ return string;
+
+}
+
+void CodeMethodBlock::initFields ( ) {
+
+ m_startMethod = QString("");
+ m_endMethod = QString("");
+}
+
+void CodeMethodBlock::syncToParent ( )
+{
+
+ getComment()->setText(getParentObject()->getDoc());
+
+ updateMethodDeclaration();
+
+ // only update IF we are NOT AutoGenerated
+ if(getContentType() != AutoGenerated)
+ return;
+
+ updateContent();
+}
+
+#include "codemethodblock.moc"
diff --git a/umbrello/umbrello/codemethodblock.h b/umbrello/umbrello/codemethodblock.h
new file mode 100644
index 00000000..65cbe2e8
--- /dev/null
+++ b/umbrello/umbrello/codemethodblock.h
@@ -0,0 +1,133 @@
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the 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 code generated by:
+ * Author : thomas
+ * Date : Fri Jun 20 2003
+ */
+
+
+
+#ifndef CODEMETHODBLOCK_H
+#define CODEMETHODBLOCK_H
+
+#include <qstring.h>
+
+#include "ownedcodeblock.h"
+#include "codeblockwithcomments.h"
+#include "umlnamespace.h"
+
+class ClassifierCodeDocument;
+
+/**
+ * class CodeMethodBlock
+ * A common type of "code block" that occurs in OO code.
+ */
+
+class CodeMethodBlock : public CodeBlockWithComments, public OwnedCodeBlock
+{
+ friend class CodeGenObjectWithTextBlocks;
+ Q_OBJECT
+public:
+
+ // Constructors/Destructors
+ //
+
+
+ /**
+ * Constructors
+ */
+ CodeMethodBlock ( ClassifierCodeDocument * doc, UMLObject * parentObj,
+ const QString & body = "", const QString & comment = "");
+
+ /**
+ * Empty Destructor
+ */
+ virtual ~CodeMethodBlock ( );
+
+ // Public attributes
+ //
+
+ /**
+ * @return QString
+ */
+ virtual QString toString ( );
+
+ /**
+ * Get the starting text that begins this method before the body is printed.
+ */
+ QString getStartMethodText () const;
+
+ /**
+ * Get the ending text that finishes this method after the body is printed.
+ */
+ QString getEndMethodText () const;
+
+ // get the parent code document
+ CodeDocument * getParentDocument();
+
+protected:
+
+
+ /** causes the text block to release all of its connections
+ * and any other text blocks that it 'owns'.
+ * needed to be called prior to deletion of the textblock.
+ */
+ virtual void release ();
+
+ /**
+ * Set the starting text that begins this method before the body is printed.
+ */
+ void setStartMethodText (const QString &value);
+
+ /**
+ * Set the ending text that finishes this method after the body is printed.
+ */
+ void setEndMethodText (const QString &value);
+
+ /** this is the method called from within syncToparent().
+ * to update the start and end Method text. It is called
+ * whether or not the method is Auto or User generated.
+ */
+ virtual void updateMethodDeclaration ( ) = 0;
+
+ /** this is the method called from within syncToparent().
+ * to update the *body* of the method
+ * It is only called if the method is Auto-generated.
+ */
+ virtual void updateContent ( ) = 0;
+
+ /** set attributes of the node that represents this class
+ * in the XMI document.
+ */
+ virtual void setAttributesOnNode ( QDomDocument & doc, QDomElement & blockElement);
+
+ /** set the class attributes of this object from
+ * the passed element node.
+ */
+ virtual void setAttributesFromNode ( QDomElement & element);
+
+ /** set the class attributes from a passed object
+ */
+ virtual void setAttributesFromObject (TextBlock * obj);
+
+private:
+
+ QString m_startMethod;
+ QString m_endMethod;
+
+ void initFields ( );
+
+public slots:
+
+ virtual void syncToParent();
+};
+
+#endif // CODEMETHODBLOCK_H
diff --git a/umbrello/umbrello/codeoperation.cpp b/umbrello/umbrello/codeoperation.cpp
new file mode 100644
index 00000000..3e98af8f
--- /dev/null
+++ b/umbrello/umbrello/codeoperation.cpp
@@ -0,0 +1,177 @@
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * copyright (C) 2004-2007 *
+ * Umbrello UML Modeller Authors <uml-devel@uml.sf.net> *
+ ***************************************************************************/
+
+/* This code generated by:
+ * Author : thomas
+ * Date : Fri Jun 20 2003
+ */
+
+// own header
+#include "codeoperation.h"
+
+// qt/kde includes
+#include <kdebug.h>
+
+// local includes
+#include "codedocument.h"
+#include "codegenerator.h"
+#include "classifiercodedocument.h"
+#include "uml.h"
+#include "umldoc.h"
+#include "umlobject.h"
+
+
+// Constructors/Destructors
+//
+
+CodeOperation::CodeOperation ( ClassifierCodeDocument * doc , UMLOperation * parentOp, const QString & body, const QString & comment)
+ : CodeMethodBlock ( doc, parentOp, body, comment)
+{
+ init(parentOp);
+}
+
+CodeOperation::~CodeOperation ( ) { }
+
+//
+// Methods
+//
+
+// Accessor methods
+//
+
+/**
+ * Add a Parameter object to the m_parameterVector List
+ */
+/*
+void CodeOperation::addParameter ( CodeParameter * add_object ) {
+ m_parameterVector.append(add_object);
+}
+*/
+
+/**
+ * Remove a Parameter object from m_parameterVector List
+ */
+/*
+void CodeOperation::removeParameter ( CodeParameter * remove_object ) {
+ m_parameterVector.remove(remove_object);
+}
+*/
+
+/**
+ * Get the list of Parameter objects held by m_parameterVector
+ * @return QPtrList<CodeParameter *> list of Parameter objects held by
+ * m_parameterVector
+ */
+/*
+QPtrList<CodeParameter> CodeOperation::getParameterList ( ) {
+ return m_parameterVector;
+}
+*/
+
+/**
+ * Get the parent UMLOperation of this codeoperation.
+ */
+UMLOperation * CodeOperation::getParentOperation( ) {
+ return dynamic_cast<UMLOperation*>(getParentObject());
+}
+
+// Other methods
+//
+
+/** Save the XMI representation of this object
+ */
+void CodeOperation::saveToXMI ( QDomDocument & doc, QDomElement & root ) {
+ QDomElement blockElement = doc.createElement( "codeoperation" );
+
+ // set attributes
+ setAttributesOnNode(doc, blockElement);
+
+ root.appendChild( blockElement );
+}
+
+/**
+ * load params from the appropriate XMI element node.
+ */
+void CodeOperation::loadFromXMI ( QDomElement & root )
+{
+ setAttributesFromNode(root);
+}
+
+QString CodeOperation::findTag (UMLOperation * op) {
+ return QString("operation_" + ID2STR(op->getID()));
+}
+
+/** set attributes of the node that represents this class
+ * in the XMI document.
+ */
+void CodeOperation::setAttributesOnNode ( QDomDocument & doc, QDomElement & elem)
+{
+
+ CodeMethodBlock::setAttributesOnNode(doc,elem); // superclass
+
+}
+
+/** set the class attributes of this object from
+ * the passed element node.
+ */
+void CodeOperation::setAttributesFromNode ( QDomElement & element)
+{
+
+ CodeMethodBlock::setAttributesFromNode(element); // superclass
+
+ // now set local attributes
+
+ // oops..this is done in the parent class "ownedcodeblock".
+ // we simply need to record the parent operation here
+ // m_parentOperation->disconnect(this); // always disconnect from current parent
+
+ QString idStr = element.attribute("parent_id","-1");
+ Uml::IDType id = STR2ID(idStr);
+ UMLObject * obj = UMLApp::app()->getDocument()->findObjectById(id);
+ UMLOperation * op = dynamic_cast<UMLOperation*>(obj);
+
+ if(op)
+ init(op);
+ else
+ kError()<<"ERROR: could'nt load code operation because of missing UMLoperation, corrupt savefile?"<<endl;
+
+}
+
+void CodeOperation::setAttributesFromObject(TextBlock * obj)
+{
+
+ CodeMethodBlock::setAttributesFromObject(obj);
+
+ CodeOperation * op = dynamic_cast<CodeOperation*>(obj);
+ if(op)
+ init((UMLOperation*) op->getParentObject());
+
+}
+
+void CodeOperation::init (UMLOperation * parentOp)
+{
+
+ m_canDelete = false; // we cant delete these with the codeeditor, delete the UML operation instead.
+ setTag(CodeOperation::findTag(parentOp));
+
+ // not needed.. done by parent "ownedcodeblock" class
+ // connect(parentOp,SIGNAL(modified()),this,SLOT(syncToParent()));
+
+}
+
+void CodeOperation::updateContent() {
+ kDebug() << "CodeOperation::updateContent is called!" << endl;
+ // Empty. Unlike codeaccessor methods for most (all?) languages
+ // we don't auto-generate content for operations
+}
+
+
+#include "codeoperation.moc"
diff --git a/umbrello/umbrello/codeoperation.h b/umbrello/umbrello/codeoperation.h
new file mode 100644
index 00000000..abe97e75
--- /dev/null
+++ b/umbrello/umbrello/codeoperation.h
@@ -0,0 +1,94 @@
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the 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 code generated by:
+ * Author : thomas
+ * Date : Fri Jun 20 2003
+ */
+
+
+#ifndef CODEOPERATION_H
+#define CODEOPERATION_H
+
+#include <qstring.h>
+
+#include "codemethodblock.h"
+#include "operation.h"
+
+// class CodeParameter;
+
+class CodeOperation : public CodeMethodBlock
+{
+ Q_OBJECT
+public:
+
+ // Constructors/Destructors
+ //
+
+ /**
+ * Constructors
+ */
+ CodeOperation ( ClassifierCodeDocument * doc , UMLOperation * parent,
+ const QString & body = "", const QString & comment = "");
+
+ /**
+ * Empty Destructor
+ */
+ virtual ~CodeOperation ( );
+
+ /**
+ * Get the parent UMLOperation of this codeoperation.
+ */
+ UMLOperation * getParentOperation( );
+
+ /**
+ * Save the XMI representation of this object
+ */
+ virtual void saveToXMI ( QDomDocument & doc, QDomElement & root );
+
+ /**
+ * load params from the appropriate XMI element node.
+ */
+ virtual void loadFromXMI ( QDomElement & root );
+
+ /** Find the value of the tag that this operation would have.
+ */
+ static QString findTag (UMLOperation * op) ;
+
+ /** set the class attributes from a passed object
+ */
+ virtual void setAttributesFromObject (TextBlock * obj);
+
+protected:
+
+ // list of parameters used by this code operation.
+ // QPtrList<CodeParameter> m_parameterVector;
+
+ /** set attributes of the node that represents this class
+ * in the XMI document.
+ */
+ virtual void setAttributesOnNode ( QDomDocument & doc, QDomElement & blockElement);
+
+ /** set the class attributes of this object from
+ * the passed element node.
+ */
+ virtual void setAttributesFromNode ( QDomElement & element);
+
+ virtual void updateMethodDeclaration() = 0;
+ virtual void updateContent();
+
+private:
+
+ UMLOperation * m_parentOperation;
+ void init (UMLOperation * parentOp);
+
+};
+
+#endif // CODEOPERATION_H
diff --git a/umbrello/umbrello/codeparameter.cpp b/umbrello/umbrello/codeparameter.cpp
new file mode 100644
index 00000000..f2f429fa
--- /dev/null
+++ b/umbrello/umbrello/codeparameter.cpp
@@ -0,0 +1,287 @@
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * copyright (C) 2004-2007 *
+ * Umbrello UML Modeller Authors <uml-devel@uml.sf.net> *
+ ***************************************************************************/
+
+/* This code generated by:
+ * Author : thomas
+ * Date : Fri Jun 20 2003
+ */
+
+// own header
+#include "codeparameter.h"
+
+// qt/kde includes
+#include <kdebug.h>
+
+// local includes
+#include "association.h"
+#include "attribute.h"
+#include "classifiercodedocument.h"
+#include "umldoc.h"
+#include "umlobject.h"
+#include "umlrole.h"
+#include "uml.h"
+#include "codegenerators/codegenfactory.h"
+
+// Constructors/Destructors
+//
+
+CodeParameter::CodeParameter ( ClassifierCodeDocument * parentDoc, UMLObject * parentObject )
+ : QObject ( (QObject*) parentObject, "ACodeParam")
+{
+ initFields( parentDoc, parentObject );
+}
+
+CodeParameter::~CodeParameter ( ) { }
+
+//
+// Methods
+//
+
+
+// Accessor methods
+//
+
+/**
+ * Utility method to get the value of parent object abstract value
+ * @return the value of parent object abstrtact
+ */
+bool CodeParameter::getAbstract ( ) {
+ return m_parentObject->getAbstract();
+}
+
+/**
+ * Utility method to get the value of parent object static
+ * Whether or not this is static.
+ * @return the value of static
+ */
+bool CodeParameter::getStatic ( ) {
+ return m_parentObject->getStatic();
+}
+
+/**
+ * Utility method to get the value of parent object name
+ * The name of this code parameter.
+ * @return the value
+ */
+QString CodeParameter::getName ( ) const {
+ return m_parentObject->getName();
+}
+
+/**
+ * Utility method to get the value of parent object type.
+ * the typeName of this parameters (e.g. boolean, int, etc or perhaps Class name of
+ * an object)
+ * @return the value of type
+ */
+QString CodeParameter::getTypeName ( ) {
+ UMLAttribute * at = (UMLAttribute*) m_parentObject;
+ return at->getTypeName();
+}
+
+/**
+ * Utility method to get the value of parent object scope.
+ * The visibility of this code parameter.
+ * @return the value of parent object scope
+ */
+Uml::Visibility CodeParameter::getVisibility ( ) const {
+ return m_parentObject->getVisibility();
+}
+
+/**
+ * Set the value of m_initialValue
+ * The initial value of this code parameter
+ * @param new_var the new value of m_initialValue
+ */
+void CodeParameter::setInitialValue ( const QString &new_var ) {
+ m_initialValue = new_var;
+}
+
+/**
+ * Get the value of m_initialValue
+ * The initial value of this code parameter
+ * @return the value of m_initialValue
+ */
+QString CodeParameter::getInitialValue ( ) {
+ return m_initialValue;
+}
+
+/**
+ * Set a Comment object.
+ */
+void CodeParameter::setComment ( CodeComment * object ) {
+ m_comment = object;
+}
+
+/**
+ * Get the Comment on this object.
+ */
+CodeComment * CodeParameter::getComment ( ) {
+ return m_comment;
+}
+
+
+ClassifierCodeDocument * CodeParameter::getParentDocument ( ) {
+ return m_parentDocument;
+}
+
+/**
+ * Get the ParentObject object
+ */
+UMLObject * CodeParameter::getParentObject ( ) {
+ return m_parentObject;
+}
+
+// need to get the ID of the parent object
+// this is kind of broken for UMLRoles.
+QString CodeParameter::getID () {
+ UMLRole * role = dynamic_cast<UMLRole*>(m_parentObject);
+ if(role)
+ {
+ // cant use Role "ID" as that is used to distinquish if its
+ // role "A" or "B"
+ UMLAssociation *assoc = role->getParentAssociation();
+ return ID2STR(assoc->getID());
+ } else
+ return ID2STR(m_parentObject->getID());
+
+}
+
+// Other methods
+//
+
+void CodeParameter::setAttributesOnNode ( QDomDocument & doc, QDomElement & blockElement)
+{
+
+
+ // set local attributes
+ blockElement.setAttribute("parent_id",getID());
+
+ // setting ID's takes special treatment
+ // as UMLRoles arent properly stored in the XMI right now.
+ // (change would break the XMI format..save for big version change )
+ UMLRole * role = dynamic_cast<UMLRole*>(m_parentObject);
+ if(role)
+ blockElement.setAttribute("role_id", role->getRole());
+ else
+ blockElement.setAttribute("role_id","-1");
+
+ blockElement.setAttribute("initialValue",getInitialValue());
+
+ // a comment which we will store in its own separate child node block
+ QDomElement commElement = doc.createElement( "header" );
+ getComment()->saveToXMI(doc, commElement); // comment
+ blockElement.appendChild( commElement);
+
+}
+
+/** set the class attributes of this object from
+ * the passed element node.
+ */
+void CodeParameter::setAttributesFromNode ( QDomElement & root) {
+
+ // set local attributes, parent object first
+ QString idStr = root.attribute("parent_id","-1");
+ Uml::IDType id = STR2ID(idStr);
+
+ // always disconnect
+ m_parentObject->disconnect(this);
+
+ // now, what is the new object we want to set?
+ UMLObject * obj = UMLApp::app()->getDocument()->findObjectById(id);
+ if(obj)
+ {
+
+ // FIX..one day.
+ // Ugh. This is UGLY, but we have to do it this way because UMLRoles
+ // don't go into the document list of UMLobjects, and have the same
+ // ID as their parent UMLAssociations. So..the drill is then special
+ // for Associations..in that case we need to find out which role will
+ // serve as the parameter here. The REAL fix, of course, would be to
+ // treat UMLRoles on a more even footing, but im not sure how that change
+ // might ripple throughout the code and cause problems. Thus, since the
+ // change appears to be needed for only this part, I'll do this crappy
+ // change instead. -b.t.
+ UMLAssociation * assoc = dynamic_cast<UMLAssociation*>(obj);
+ if(assoc) {
+ // In this case we init with indicated role child obj.
+ UMLRole * role = 0;
+ int role_id = root.attribute("role_id","-1").toInt();
+ if(role_id == 1)
+ role = assoc->getUMLRole(Uml::A);
+ else if(role_id == 0)
+ role = assoc->getUMLRole(Uml::B);
+ else
+ kError() << "corrupt save file? "
+ << "cant get proper UMLRole for codeparameter uml id:"
+ << ID2STR(id) << " w/role_id:" << role_id << endl;
+
+ // init using UMLRole obj
+ initFields ( m_parentDocument, role);
+
+ } else
+ initFields ( m_parentDocument, obj); // just the regular approach
+
+ } else
+ kError() << "Cant load CodeParam: parentUMLObject w/id:"
+ << ID2STR(id) << " not found, corrupt save file?" << endl;
+
+ // other attribs now
+ setInitialValue(root.attribute("initialValue",""));
+
+ // load comment now
+ // by looking for our particular child element
+ QDomNode node = root.firstChild();
+ QDomElement element = node.toElement();
+ bool gotComment = false;
+ while( !element.isNull() ) {
+ QString tag = element.tagName();
+ if( tag == "header" ) {
+ QDomNode cnode = element.firstChild();
+ QDomElement celem = cnode.toElement();
+ getComment()->loadFromXMI(celem);
+ gotComment = true;
+ break;
+ }
+ node = element.nextSibling();
+ element = node.toElement();
+ }
+
+ if(!gotComment)
+ kWarning()<<" loadFromXMI : Warning: unable to initialize CodeComment in codeparam:"<<this<<endl;
+
+
+}
+
+/**
+ * create the string representation of this code parameter.
+ * @return QString
+ */
+void CodeParameter::syncToParent( ) {
+
+ getComment()->setText(getParentObject()->getDoc());
+
+ updateContent();
+}
+
+void CodeParameter::initFields ( ClassifierCodeDocument * doc, UMLObject * obj) {
+
+ m_parentObject = obj;
+
+ m_parentDocument = doc;
+ m_initialValue = QString("");
+
+ m_comment = CodeGenFactory::newCodeComment(m_parentDocument);
+ m_comment->setText(getParentObject()->getDoc());
+
+ connect(m_parentObject,SIGNAL(modified()),this,SLOT(syncToParent()));
+}
+
+#include "codeparameter.moc"
diff --git a/umbrello/umbrello/codeparameter.h b/umbrello/umbrello/codeparameter.h
new file mode 100644
index 00000000..8ee4dc45
--- /dev/null
+++ b/umbrello/umbrello/codeparameter.h
@@ -0,0 +1,160 @@
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * copyright (C) 2004-2006 *
+ * Umbrello UML Modeller Authors <uml-devel@uml.sf.net> *
+ ***************************************************************************/
+
+/* This code generated by:
+ * Author : thomas
+ * Date : Fri Jun 20 2003
+ */
+
+
+
+#ifndef CODEPARAMETER_H
+#define CODEPARAMETER_H
+
+
+#include "umlnamespace.h"
+#include "codecomment.h"
+
+/**
+ * class CodeParameter
+ * A parameter on some type of code.
+ */
+
+class ClassifierCodeDocument;
+class UMLObject;
+
+class CodeParameter : public QObject
+{
+ Q_OBJECT
+public:
+
+ // Constructors/Destructors
+ //
+
+ /**
+ * Empty Constructor
+ */
+ CodeParameter ( ClassifierCodeDocument * doc, UMLObject * parentObj );
+
+ /**
+ * Empty Destructor
+ */
+ virtual ~CodeParameter ( );
+
+ // Public attributes
+ //
+
+ // Public attribute accessor methods
+ //
+
+ /**
+ * Get the parent Code Document
+ */
+ ClassifierCodeDocument * getParentDocument ( );
+
+ /**
+ * Get the parent UMLObject
+ */
+ UMLObject * getParentObject ( );
+
+ /**
+ * Utility method. Get the value of parent abstract value.
+ * @return the value
+ */
+ bool getAbstract ( );
+
+ /**
+ * Utility method. Get the value of parent Static
+ * Whether or not this is static.
+ * @return the value
+ */
+ bool getStatic ( );
+
+ /**
+ * The name of this code parameter.
+ * @return the value of parameter name
+ */
+ QString getName ( ) const;
+
+ /**
+ * Get the value of m_typeName
+ * the typeName of this parameters (e.g. boolean, int, etc or perhaps Class name of
+ * an object)
+ * @return the value of m_typeName
+ */
+ virtual QString getTypeName ( );
+
+ /**
+ * Get the value of m_visibility
+ * The visibility of this code parameter.
+ * @return the value of m_visibility
+ */
+ Uml::Visibility getVisibility ( ) const;
+
+ /**
+ * Set the value of m_initialValue
+ * The initial value of this code parameter
+ * @param new_var the new value of m_initialValue
+ */
+ virtual void setInitialValue ( const QString &new_var );
+
+ /**
+ * Get the value of m_initialValue
+ * The initial value of this code parameter
+ * @return the value of m_initialValue
+ */
+ virtual QString getInitialValue ( );
+
+ /**
+ * Set a Comment
+ */
+ void setComment ( CodeComment * comment );
+
+ /**
+ * get any Comment object on this
+ */
+ CodeComment * getComment ( );
+
+ // the id of this parameter is the same as the parent UMLObject id.
+ QString getID ();
+
+protected:
+
+ virtual void updateContent() = 0;
+
+ /** set attributes of the node that represents this class
+ * in the XMI document.
+ */
+ virtual void setAttributesOnNode ( QDomDocument & doc, QDomElement & blockElement);
+
+ /** set the class attributes of this object from
+ * the passed element node.
+ */
+ virtual void setAttributesFromNode ( QDomElement & element);
+
+private:
+
+ ClassifierCodeDocument * m_parentDocument;
+ UMLObject * m_parentObject;
+ CodeComment * m_comment;
+
+ // The initial value of this code parameter
+ QString m_initialValue;
+
+ void initFields ( ClassifierCodeDocument * doc, UMLObject * obj);
+
+public slots:
+
+ void syncToParent ();
+
+};
+
+#endif // CODEPARAMETER_H
diff --git a/umbrello/umbrello/codeviewerstate.h b/umbrello/umbrello/codeviewerstate.h
new file mode 100644
index 00000000..0a45fce9
--- /dev/null
+++ b/umbrello/umbrello/codeviewerstate.h
@@ -0,0 +1,38 @@
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * copyright (C) 2004-2007 *
+ * Umbrello UML Modeller Authors <uml-devel@uml.sf.net> *
+ ***************************************************************************/
+
+#ifndef CODEVIEWERSTATE_H
+#define CODEVIEWERSTATE_H
+
+#include <qcolor.h>
+#include <qfont.h>
+
+namespace Settings {
+
+/// configurable params for the code viewer tool
+struct CodeViewerState {
+ int height;
+ int width;
+ bool showHiddenBlocks;
+ bool blocksAreHighlighted;
+ QFont font;
+ QColor paperColor;
+ QColor fontColor;
+ QColor selectedColor;
+ QColor editBlockColor;
+ QColor nonEditBlockColor;
+ QColor umlObjectColor;
+ QColor hiddenColor;
+};
+
+}
+
+#endif // CODEVIEWERSTATE_H
diff --git a/umbrello/umbrello/component.cpp b/umbrello/umbrello/component.cpp
new file mode 100644
index 00000000..6c8f674b
--- /dev/null
+++ b/umbrello/umbrello/component.cpp
@@ -0,0 +1,100 @@
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * copyright (C) 2003-2006 *
+ * Umbrello UML Modeller Authors <uml-devel@uml.sf.net> *
+ ***************************************************************************/
+
+// own header
+#include "component.h"
+// qt/kde includes
+#include <kdebug.h>
+#include <klocale.h>
+// app includes
+#include "association.h"
+#include "object_factory.h"
+#include "model_utils.h"
+#include "clipboard/idchangelog.h"
+
+UMLComponent::UMLComponent(const QString & name, Uml::IDType id)
+ : UMLPackage(name, id) {
+ init();
+}
+
+UMLComponent::~UMLComponent() {
+}
+
+void UMLComponent::init() {
+ m_BaseType = Uml::ot_Component;
+ m_executable = false;
+}
+
+UMLObject* UMLComponent::clone() const {
+ UMLComponent *clone = new UMLComponent();
+ UMLObject::copyInto(clone);
+ return clone;
+}
+
+void UMLComponent::saveToXMI(QDomDocument& qDoc, QDomElement& qElement) {
+ QDomElement componentElement = UMLObject::save("UML:Component", qDoc);
+ componentElement.setAttribute("executable", m_executable);
+ // Save contained components if any.
+ if (m_objects.count()) {
+ QDomElement ownedElement = qDoc.createElement( "UML:Namespace.ownedElement" );
+ for (UMLObject *obj = m_objects.first(); obj; obj = m_objects.next())
+ obj->saveToXMI (qDoc, ownedElement);
+ componentElement.appendChild(ownedElement);
+ }
+ qElement.appendChild(componentElement);
+}
+
+bool UMLComponent::load(QDomElement& element) {
+ QString executable = element.attribute("executable", "0");
+ m_executable = (bool)executable.toInt();
+ for (QDomNode node = element.firstChild(); !node.isNull();
+ node = node.nextSibling()) {
+ if (node.isComment())
+ continue;
+ QDomElement tempElement = node.toElement();
+ QString type = tempElement.tagName();
+ if (Model_Utils::isCommonXMIAttribute(type))
+ continue;
+ if (Uml::tagEq(type, "Namespace.ownedElement") ||
+ Uml::tagEq(type, "Namespace.contents")) {
+ //CHECK: Umbrello currently assumes that nested elements
+ // are ownedElements anyway.
+ // Therefore these tags are not further interpreted.
+ if (! load(tempElement))
+ return false;
+ continue;
+ }
+ UMLObject *pObject = Object_Factory::makeObjectFromXMI(type);
+ if( !pObject ) {
+ kWarning() << "UMLComponent::load: "
+ << "Unknown type of umlobject to create: "
+ << type << endl;
+ continue;
+ }
+ pObject->setUMLPackage(this);
+ if (pObject->loadFromXMI(tempElement)) {
+ addObject(pObject);
+ } else {
+ delete pObject;
+ }
+ }
+ return true;
+}
+
+void UMLComponent::setExecutable(bool executable) {
+ m_executable = executable;
+}
+
+bool UMLComponent::getExecutable() {
+ return m_executable;
+}
+
+#include "component.moc"
diff --git a/umbrello/umbrello/component.h b/umbrello/umbrello/component.h
new file mode 100644
index 00000000..014cf39e
--- /dev/null
+++ b/umbrello/umbrello/component.h
@@ -0,0 +1,86 @@
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * copyright (C) 2003-2006 *
+ * Umbrello UML Modeller Authors <uml-devel@uml.sf.net> *
+ ***************************************************************************/
+
+#ifndef COMPONENT_H
+#define COMPONENT_H
+
+#include "package.h"
+
+
+/**
+ * This class contains the non-graphical information required for a
+ * UML Component.
+ * This class inherits from @ref UMLPackage which contains most
+ * of the information.
+ *
+ * @short Non-graphical information for a Component.
+ * @author Jonathan Riddell
+ * @see UMLCanvasObject
+ * Bugs and comments to uml-devel@lists.sf.net or http://bugs.kde.org
+ */
+
+class UMLComponent : public UMLPackage {
+ Q_OBJECT
+public:
+ /**
+ * Sets up a Component.
+ *
+ * @param name The name of the Concept.
+ * @param id The unique id of the Concept.
+ */
+ explicit UMLComponent(const QString & name = "", Uml::IDType id = Uml::id_None);
+
+ /**
+ * Empty deconstructor.
+ */
+ virtual ~UMLComponent();
+
+ /**
+ * Initializes key variables of the class.
+ */
+ virtual void init();
+
+ /**
+ * Make a clone of this object.
+ */
+ virtual UMLObject* clone() const;
+
+ /**
+ * Creates the UML:Component element including its operations,
+ * attributes and templates
+ */
+ void saveToXMI( QDomDocument & qDoc, QDomElement & qElement );
+
+ /**
+ * sets m_executable
+ */
+ void setExecutable(bool executable);
+
+ /**
+ * returns the value of m_executable
+ */
+ bool getExecutable();
+
+protected:
+ /**
+ * Loads the UML:Component element including its operations,
+ * attributes and templates
+ */
+ bool load( QDomElement & element );
+
+private:
+ /**
+ * holds whether this is an executable component or not
+ */
+ bool m_executable;
+};
+
+#endif
diff --git a/umbrello/umbrello/componentwidget.cpp b/umbrello/umbrello/componentwidget.cpp
new file mode 100644
index 00000000..f4c38270
--- /dev/null
+++ b/umbrello/umbrello/componentwidget.cpp
@@ -0,0 +1,141 @@
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * copyright (C) 2003-2007 *
+ * Umbrello UML Modeller Authors <uml-devel@uml.sf.net> *
+ ***************************************************************************/
+
+// own header
+#include "componentwidget.h"
+
+// qt/kde includes
+#include <qpainter.h>
+
+// app includes
+#include <kdebug.h>
+#include "component.h"
+#include "umlview.h"
+
+
+ComponentWidget::ComponentWidget(UMLView * view, UMLComponent *c)
+ : UMLWidget(view, c) {
+ init();
+}
+
+void ComponentWidget::init() {
+ UMLWidget::setBaseType(Uml::wt_Component);
+ setSize(100, 30);
+ m_pMenu = 0;
+ //set defaults from m_pView
+ if (m_pView) {
+ //check to see if correct
+ const Settings::OptionState& ops = m_pView->getOptionState();
+ m_bShowStereotype = ops.classState.showStereoType;
+ }
+ //maybe loading and this may not be set.
+ if (m_pObject) {
+ updateComponentSize();
+ update();
+ }
+}
+
+ComponentWidget::~ComponentWidget() {}
+
+void ComponentWidget::draw(QPainter & p, int offsetX, int offsetY) {
+ UMLComponent *umlcomp = static_cast<UMLComponent*>(m_pObject);
+ if (umlcomp == NULL)
+ return;
+ UMLWidget::setPen(p);
+ if ( umlcomp->getExecutable() ) {
+ QPen thickerPen = p.pen();
+ thickerPen.setWidth(2);
+ p.setPen(thickerPen);
+ }
+ if ( UMLWidget::getUseFillColour() ) {
+ p.setBrush( UMLWidget::getFillColour() );
+ } else {
+ p.setBrush( m_pView->viewport()->backgroundColor() );
+ }
+
+ const int w = width();
+ const int h = height();
+ QFont font = UMLWidget::getFont();
+ font.setBold(true);
+ const QFontMetrics &fm = getFontMetrics(FT_BOLD);
+ const int fontHeight = fm.lineSpacing();
+ QString name = getName();
+ const QString stereotype = m_pObject->getStereotype();
+
+ p.drawRect(offsetX + 2*COMPONENT_MARGIN, offsetY, w - 2*COMPONENT_MARGIN, h);
+ p.drawRect(offsetX, offsetY + h/2 - fontHeight/2 - fontHeight, COMPONENT_MARGIN*4, fontHeight);
+ p.drawRect(offsetX, offsetY + h/2 + fontHeight/2, COMPONENT_MARGIN*4, fontHeight);
+
+ p.setPen( QPen(Qt::black) );
+ p.setFont(font);
+
+ int lines = 1;
+
+ if (!stereotype.isEmpty()) {
+ p.drawText(offsetX + (COMPONENT_MARGIN*4), offsetY + (h/2) - fontHeight,
+ w - (COMPONENT_MARGIN*4), fontHeight, Qt::AlignCenter,
+ m_pObject->getStereotype(true));
+ lines = 2;
+ }
+
+ if ( UMLWidget::getIsInstance() ) {
+ font.setUnderline(true);
+ p.setFont(font);
+ name = UMLWidget::getInstanceName() + " : " + name;
+ }
+
+ if (lines == 1) {
+ p.drawText(offsetX + (COMPONENT_MARGIN*4), offsetY + (h/2) - (fontHeight/2),
+ w - (COMPONENT_MARGIN*4), fontHeight, Qt::AlignCenter, name );
+ } else {
+ p.drawText(offsetX + (COMPONENT_MARGIN*4), offsetY + (h/2),
+ w - (COMPONENT_MARGIN*4), fontHeight, Qt::AlignCenter, name );
+ }
+
+ if(m_bSelected) {
+ drawSelected(&p, offsetX, offsetY);
+ }
+}
+
+QSize ComponentWidget::calculateSize() {
+ if ( !m_pObject) {
+ return QSize(70, 70);
+ }
+ const QFontMetrics &fm = getFontMetrics(FT_BOLD_ITALIC);
+ const int fontHeight = fm.lineSpacing();
+
+ QString name = m_pObject->getName();
+ if ( UMLWidget::getIsInstance() ) {
+ name = UMLWidget::getInstanceName() + " : " + name;
+ }
+
+ int width = fm.width(name);
+
+ int stereoWidth = 0;
+ if (!m_pObject->getStereotype().isEmpty()) {
+ stereoWidth = fm.width(m_pObject->getStereotype(true));
+ }
+ if (stereoWidth > width)
+ width = stereoWidth;
+ width += COMPONENT_MARGIN * 6;
+ width = 70>width ? 70 : width; //minumin width of 70
+
+ int height = (2*fontHeight) + (COMPONENT_MARGIN * 3);
+
+ return QSize(width, height);
+}
+
+void ComponentWidget::saveToXMI(QDomDocument& qDoc, QDomElement& qElement) {
+ QDomElement conceptElement = qDoc.createElement("componentwidget");
+ UMLWidget::saveToXMI(qDoc, conceptElement);
+ qElement.appendChild(conceptElement);
+}
+
diff --git a/umbrello/umbrello/componentwidget.h b/umbrello/umbrello/componentwidget.h
new file mode 100644
index 00000000..7266ef01
--- /dev/null
+++ b/umbrello/umbrello/componentwidget.h
@@ -0,0 +1,74 @@
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * copyright (C) 2003-2006 *
+ * Umbrello UML Modeller Authors <uml-devel@uml.sf.net> *
+ ***************************************************************************/
+
+#ifndef COMPONENTWIDGET_H
+#define COMPONENTWIDGET_H
+
+#include "umlwidget.h"
+
+class UMLComponent;
+
+#define COMPONENT_MARGIN 10
+
+/**
+ * Defines a graphical version of the Component. Most of the functionality
+ * will come from the @ref UMLComponent class.
+ *
+ * @short A graphical version of a Component.
+ * @author Jonathan Riddell
+ * @see UMLWidget
+ * Bugs and comments to uml-devel@lists.sf.net or http://bugs.kde.org
+ */
+class ComponentWidget : public UMLWidget {
+public:
+
+ /**
+ * Constructs a ComponentWidget.
+ *
+ * @param view The parent of this ComponentWidget.
+ * @param c The UMLComponent this will be representing.
+ */
+ ComponentWidget(UMLView * view, UMLComponent *c);
+
+ /**
+ * destructor
+ */
+ virtual ~ComponentWidget();
+
+ /**
+ * Overrides standard method
+ */
+ void draw(QPainter& p, int offsetX, int offsetY);
+
+ /**
+ * Saves to the "componentwidget" XMI element.
+ */
+ void saveToXMI(QDomDocument& qDoc, QDomElement& qElement);
+
+protected:
+ /**
+ * Overrides method from UMLWidget.
+ */
+ QSize calculateSize();
+
+private:
+ /**
+ * Initializes key variables of the class.
+ */
+ void init();
+
+ /**
+ * The right mouse button menu
+ */
+ ListPopupMenu* m_pMenu;
+};
+
+#endif
diff --git a/umbrello/umbrello/configurable.cpp b/umbrello/umbrello/configurable.cpp
new file mode 100644
index 00000000..5aaec43c
--- /dev/null
+++ b/umbrello/umbrello/configurable.cpp
@@ -0,0 +1,81 @@
+/***************************************************************************
+ begin : Mon Jan 13 2003
+ copyright : (C) 2003 by Andrew Sutton
+ email : ansutton@kent.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. *
+ * *
+ * copyright (C) 2004-2007 *
+ * Umbrello UML Modeller Authors <uml-devel@uml.sf.net> *
+ ***************************************************************************/
+
+// own header
+#include "configurable.h"
+
+// Qt includes
+#include <qstringlist.h>
+
+// KDE includes
+#include <kdebug.h>
+#include <kconfig.h>
+
+// local includes
+#include "pluginloader.h"
+#include "plugin.h"
+
+using namespace Umbrello;
+
+
+Configurable::Configurable() :
+ _plugins()
+{
+ _plugins.setAutoDelete(false);
+}
+
+Configurable::~Configurable()
+{
+ unloadPlugins();
+}
+
+bool
+Configurable::loadPlugins(KConfig *config,
+ const QString &key)
+{
+ bool ret = true;
+
+ QStringList names = config->readListEntry(key);
+ for(uint i = 0; i != names.size(); i++) {
+ const QString &name = names[i];
+
+ kdDebug() << "loading plugin " << name << endl;
+
+ // load the plugin
+ Plugin *plugin = PluginLoader::instance()->loadPlugin(name);
+
+ // keep the plugin
+ if(plugin) {
+ _plugins.append(plugin);
+ }
+ }
+
+ return ret;
+}
+
+bool
+Configurable::unloadPlugins()
+{
+ // just iterate through and dereference all the
+ // plugins.
+ for(uint i = 0; i != _plugins.count(); i++) {
+ Plugin *plugin = _plugins.at(i);
+ plugin->unload();
+ }
+ _plugins.clear();
+ return true;
+}
diff --git a/umbrello/umbrello/configurable.h b/umbrello/umbrello/configurable.h
new file mode 100644
index 00000000..8debcba1
--- /dev/null
+++ b/umbrello/umbrello/configurable.h
@@ -0,0 +1,118 @@
+/***************************************************************************
+ configurable.h
+ -------------------
+ begin : Mon Jan 13 2003
+ copyright : (C) 2003 by Andrew Sutton
+ email : ansutton@kent.edu
+ Bugs and comments to uml-devel@lists.sf.net or http://bugs.kde.org
+***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the 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 UMBRELLO_CONFIGURABLE_H
+#define UMBRELLO_CONFIGURABLE_H
+
+#include <qstring.h>
+#include <qptrlist.h>
+
+// forward declarations
+class KLibrary;
+class KConfig;
+
+/**
+ * @defgroup U2_Lib Umbrello2 API
+ * The Umbrello2 API consists of classes available to applications, command
+ * line tools and plugins. These classes define common subsets of functionality
+ * these objects. Primarily, these classes provide application support for
+ * features such as configurability and plugin management. Also provided
+ * within this API are the core interfaces for GUI management.
+ */
+
+namespace Umbrello
+{
+// forward declarations
+class Plugin;
+
+/**
+ * @ingroup U2_Lib
+ *
+ * The Configurable class is the base class of all functional objects that
+ * can be created for modeling applications. There are three types of
+ * functionality: applications (with GUIs), command line tools and plugins.
+ * This class provides a common configuration interface that the functional
+ * classes use for default configuration and plugin management. Although
+ * the Configurable class is primarily an interface it does provide some
+ * convenience methods that can be used by derived classes to help manage
+ * plugins. These methods are conceptually part of a larger (althought
+ * currently undefined) set of configuration helper methods that reduce
+ * the amount of code duplication for applications, tools and plugins.
+ *
+ * At this time, this class only assists with the configuration of the
+ * event-driven plugin management system. All interfaces and convenience
+ * methods support the hidden configuration functionality for derived
+ * classes.
+ *
+ * @todo Do we have to delete the plugin object when its unloaded? Is it
+ * possible that we can just unload the library and created objects are
+ * automatically destroyed? I need some clarification of what actually
+ * happens here...
+ */
+class Configurable
+{
+public:
+ /** Construct a configurable object. */
+ Configurable();
+
+ /**
+ * Destroy a configurable object. If there are any plugins that (for
+ * some reason) have not been unloaded, we need to unload them here.
+ */
+ virtual ~Configurable();
+
+ /**
+ * The configure interface is required to be implemented by all subclasses
+ * of this class. It is expected that configuration implementations all
+ * understand how to attain their session configuration file. These files
+ * are stored in ~/.kde/share/config. What actions are taken with the
+ * configuration class are defined by implementing classes.
+ */
+ virtual bool configure() = 0;
+
+protected:
+ /**
+ * This is a convenience method for derived classes. Configuration actions
+ * that are intended to load plugins can use this method to parse the string
+ * and actually load the plugins. The string is a set of space separated names.
+ * Each name corresponds the the share object implementing the plugin.
+ *
+ * @param config The object used for configuration.
+ * @param key The key in the group that contains libraries to load.
+ *
+ * @return True on success, false on failure.
+ */
+ bool loadPlugins(KConfig *config, const QString &key);
+
+ /**
+ * This is a convenience method for derived classes. When a functional object
+ * (i.e., application, tool or plugin) is shutdown, it can use this method
+ * to automatically unload all dependant plugins.
+ *
+ * @return True on success false on failure.
+ */
+ bool unloadPlugins();
+
+private:
+ typedef QPtrList<Plugin> PluginList;
+
+ PluginList _plugins; ///< List of loaded plugins
+};
+}
+
+#endif
diff --git a/umbrello/umbrello/cr128-mime-umbrellofile.png b/umbrello/umbrello/cr128-mime-umbrellofile.png
new file mode 100644
index 00000000..2c5684bf
--- /dev/null
+++ b/umbrello/umbrello/cr128-mime-umbrellofile.png
Binary files differ
diff --git a/umbrello/umbrello/cr16-mime-umbrellofile.png b/umbrello/umbrello/cr16-mime-umbrellofile.png
new file mode 100644
index 00000000..1f239c95
--- /dev/null
+++ b/umbrello/umbrello/cr16-mime-umbrellofile.png
Binary files differ
diff --git a/umbrello/umbrello/cr22-mime-umbrellofile.png b/umbrello/umbrello/cr22-mime-umbrellofile.png
new file mode 100644
index 00000000..6cc27cff
--- /dev/null
+++ b/umbrello/umbrello/cr22-mime-umbrellofile.png
Binary files differ
diff --git a/umbrello/umbrello/cr32-mime-umbrellofile.png b/umbrello/umbrello/cr32-mime-umbrellofile.png
new file mode 100644
index 00000000..5019e291
--- /dev/null
+++ b/umbrello/umbrello/cr32-mime-umbrellofile.png
Binary files differ
diff --git a/umbrello/umbrello/cr48-mime-umbrellofile.png b/umbrello/umbrello/cr48-mime-umbrellofile.png
new file mode 100644
index 00000000..14946716
--- /dev/null
+++ b/umbrello/umbrello/cr48-mime-umbrellofile.png
Binary files differ
diff --git a/umbrello/umbrello/cr64-mime-umbrellofile.png b/umbrello/umbrello/cr64-mime-umbrellofile.png
new file mode 100644
index 00000000..b258c668
--- /dev/null
+++ b/umbrello/umbrello/cr64-mime-umbrellofile.png
Binary files differ
diff --git a/umbrello/umbrello/crsc-mime-umbrellofile.svgz b/umbrello/umbrello/crsc-mime-umbrellofile.svgz
new file mode 100644
index 00000000..0c0eb5e4
--- /dev/null
+++ b/umbrello/umbrello/crsc-mime-umbrellofile.svgz
Binary files differ
diff --git a/umbrello/umbrello/datatypewidget.cpp b/umbrello/umbrello/datatypewidget.cpp
new file mode 100644
index 00000000..33509b95
--- /dev/null
+++ b/umbrello/umbrello/datatypewidget.cpp
@@ -0,0 +1,114 @@
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * copyright (C) 2003-2007 *
+ * Umbrello UML Modeller Authors <uml-devel@uml.sf.net> *
+ ***************************************************************************/
+
+// own header
+#include "datatypewidget.h"
+
+// qt/kde includes
+#include <qpainter.h>
+#include <kdebug.h>
+
+// app includes
+#include "classifier.h"
+#include "operation.h"
+#include "classifierlistitem.h"
+#include "umlview.h"
+#include "umldoc.h"
+#include "listpopupmenu.h"
+
+
+#define CIRCLE_SIZE 30
+
+DatatypeWidget::DatatypeWidget(UMLView* view, UMLClassifier *d) : UMLWidget(view, d) {
+ init();
+}
+
+DatatypeWidget::~DatatypeWidget() {}
+
+void DatatypeWidget::init() {
+ UMLWidget::setBaseType(Uml::wt_Datatype);
+ setSize(100, 30);
+ m_pMenu = 0;
+}
+
+void DatatypeWidget::draw(QPainter& p, int offsetX, int offsetY) {
+ UMLWidget::setPen(p);
+ if (UMLWidget::getUseFillColour()) {
+ p.setBrush(UMLWidget::getFillColour());
+ } else {
+ p.setBrush(m_pView->viewport()->backgroundColor());
+ }
+
+ int w = width();
+ int h = height();
+
+ QFontMetrics &fm = getFontMetrics(FT_NORMAL);
+ int fontHeight = fm.lineSpacing();
+ QString name = getName();
+
+ p.drawRect(offsetX, offsetY, w, h);
+ p.setPen(QPen(Qt::black));
+
+ QFont font = UMLWidget::getFont();
+ font.setBold(true);
+ p.setFont(font);
+ p.drawText(offsetX + DATATYPE_MARGIN, offsetY,
+ w - DATATYPE_MARGIN* 2,fontHeight,
+ Qt::AlignCenter, m_pObject->getStereotype(true));
+
+ font.setItalic( m_pObject->getAbstract() );
+ p.setFont(font);
+ p.drawText(offsetX + DATATYPE_MARGIN, offsetY + fontHeight,
+ w - DATATYPE_MARGIN * 2, fontHeight, Qt::AlignCenter, name);
+
+ if (m_bSelected) {
+ drawSelected(&p, offsetX, offsetY);
+ }
+}
+
+QSize DatatypeWidget::calculateSize() {
+ if (!m_pObject) {
+ return UMLWidget::calculateSize();
+ }
+ int width, height;
+ const QFontMetrics &fm = getFontMetrics(FT_NORMAL);
+ const int fontHeight = fm.lineSpacing();
+
+ int lines = 1;//always have one line - for name
+ lines++; //for the stereotype
+
+ height = width = 0;
+ height += lines * fontHeight;
+
+ //now set the width of the concept
+ //set width to name to start with
+ //set width to name to start with
+ width = getFontMetrics(FT_BOLD_ITALIC).boundingRect(m_pObject->getFullyQualifiedName()).width();
+ int w = getFontMetrics(FT_BOLD).boundingRect(m_pObject->getStereotype(true)).width();
+
+ width = w > width?w:width;
+
+ //allow for width margin
+ width += DATATYPE_MARGIN * 2;
+
+ return QSize(width, height);
+}
+
+void DatatypeWidget::saveToXMI( QDomDocument & qDoc, QDomElement & qElement ) {
+ QDomElement conceptElement = qDoc.createElement("datatypewidget");
+ UMLWidget::saveToXMI(qDoc, conceptElement);
+ qElement.appendChild(conceptElement);
+}
+
+bool DatatypeWidget::loadFromXMI( QDomElement & qElement ) {
+ return UMLWidget::loadFromXMI(qElement);
+}
+
diff --git a/umbrello/umbrello/datatypewidget.h b/umbrello/umbrello/datatypewidget.h
new file mode 100644
index 00000000..fb60d536
--- /dev/null
+++ b/umbrello/umbrello/datatypewidget.h
@@ -0,0 +1,81 @@
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * copyright (C) 2003-2007 *
+ * Umbrello UML Modeller Authors <uml-devel@uml.sf.net> *
+ ***************************************************************************/
+
+#ifndef DATATYPEWIDGET_H
+#define DATATYPEWIDGET_H
+
+#include "umlwidget.h"
+
+class UMLClassifier;
+
+#define DATATYPE_MARGIN 5
+
+/**
+ * Defines a graphical version of the datatype. Most of the functionality
+ * will come from the @ref UMLWidget class from which class inherits from.
+ *
+ * @short A graphical version of an datatype.
+ * @author Jonathan Riddell
+ * @see UMLWidget
+ * Bugs and comments to uml-devel@lists.sf.net or http://bugs.kde.org
+ */
+class DatatypeWidget : public UMLWidget {
+public:
+
+ /**
+ * Constructs an DatatypeWidget.
+ *
+ * @param view The parent of this DatatypeWidget.
+ * @param d The UMLClassifier this will be representing.
+ */
+ DatatypeWidget(UMLView* view, UMLClassifier *d);
+
+ /**
+ * Standard deconstructor.
+ */
+ virtual ~DatatypeWidget();
+
+ /**
+ * Overrides standard method.
+ */
+ void draw(QPainter& p, int offsetX, int offsetY);
+
+ /**
+ * Saves to the "datatypewidget" XMI element.
+ */
+ void saveToXMI(QDomDocument& qDoc, QDomElement& qElement);
+
+ /**
+ * Loads from a "datatypewidget" XMI element.
+ */
+ bool loadFromXMI(QDomElement& qElement);
+
+protected:
+ /**
+ * Overrides method from UMLWidget.
+ */
+ QSize calculateSize();
+
+private:
+ /**
+ * Initializes key variables of the class.
+ */
+ void init();
+
+ /**
+ * The right mouse button menu.
+ */
+ ListPopupMenu* m_pMenu;
+
+public slots:
+};
+
+#endif
diff --git a/umbrello/umbrello/dialog_utils.cpp b/umbrello/umbrello/dialog_utils.cpp
new file mode 100644
index 00000000..a6d1ff2c
--- /dev/null
+++ b/umbrello/umbrello/dialog_utils.cpp
@@ -0,0 +1,60 @@
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * copyright (C) 2004-2006 *
+ * Umbrello UML Modeller Authors <uml-devel@uml.sf.net> *
+ ***************************************************************************/
+
+// own header
+#include "dialog_utils.h"
+
+// qt/kde includes
+#include <qgroupbox.h>
+#include <qlayout.h>
+#include <qlabel.h>
+#include <qlineedit.h>
+#include <kinputdialog.h>
+
+// app includes
+#include "uml.h"
+#include "umlwidget.h"
+
+namespace Dialog_Utils {
+
+QLineEdit* makeLabeledEditField(QGroupBox *containingBox, QGridLayout *layout, int row,
+ QLabel * &label, const QString& labelText,
+ QLineEdit * &editField,
+ const QString& editFieldText /* = QString::null */)
+{
+ label = new QLabel(labelText, containingBox);
+ layout->addWidget(label, row, 0);
+ editField = new QLineEdit(editFieldText, containingBox);
+ layout->addWidget(editField, row, 1 );
+ label->setBuddy(editField);
+ return editField;
+}
+
+
+void askNameForWidget(UMLWidget * &targetWidget, const QString& dialogTitle,
+ const QString& dialogPrompt, const QString& defaultName) {
+
+ bool pressedOK = false;
+
+ QString name = KInputDialog::getText(dialogTitle, dialogPrompt, defaultName, &pressedOK, UMLApp::app());
+
+ if (pressedOK) {
+ targetWidget->setName(name);
+ } else {
+ targetWidget->cleanup();
+ delete targetWidget;
+ targetWidget = NULL;
+ }
+}
+
+
+} // end namespace Dialog_Utils
+
diff --git a/umbrello/umbrello/dialog_utils.h b/umbrello/umbrello/dialog_utils.h
new file mode 100644
index 00000000..a414a7a7
--- /dev/null
+++ b/umbrello/umbrello/dialog_utils.h
@@ -0,0 +1,63 @@
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * copyright (C) 2004-2006 *
+ * Umbrello UML Modeller Authors <uml-devel@uml.sf.net> *
+ ***************************************************************************/
+
+#ifndef DIALOG_UTILS_H
+#define DIALOG_UTILS_H
+
+#include <qstring.h>
+
+class QGroupBox;
+class QGridLayout;
+class QLabel;
+class QLineEdit;
+class UMLWidget;
+
+/**
+ * Dialog utilities.
+ * @author Oliver Kellogg
+ * Bugs and comments to uml-devel@lists.sf.net or http://bugs.kde.org
+ */
+namespace Dialog_Utils {
+
+/**
+ * Create a labeled text lineedit widget.
+ *
+ * @param containingBox The containing QGroupBox.
+ * @param layout The QGridLayout to use.
+ * @param row The row number within the QGridLayout.
+ * @param label The QLabel object allocated (return value)
+ * @param labelText The label text.
+ * @param editField The QLineEdit object allocated (return value)
+ * @param editFieldText Initialization text in the editField (optional.)
+ * @return a pointer to the QLineEdit so you can setFocus() if necessary
+ */
+QLineEdit* makeLabeledEditField(QGroupBox *containingBox, QGridLayout *layout, int row,
+ QLabel * &label, const QString& labelText,
+ QLineEdit * &editField,
+ const QString& editFieldText = QString::null);
+
+/**
+ * Helper function for requesting a name for an UMLWidget using a dialog.
+ *
+ * @param targetWidget By-reference pointer to the widget to request the name for.
+ * The widget may be deallocated, and the pointer returned
+ * set to NULL, if the user presses Cancel in the dialog.
+ * @param dialogTitle Title of the dialog.
+ * @param dialogPrompt Prompt of the dialog.
+ * @param defaultName Default value of the name field.
+ */
+void askNameForWidget(UMLWidget * &targetWidget, const QString& dialogTitle,
+ const QString& dialogPrompt, const QString& defaultName);
+
+}
+
+#endif
+
diff --git a/umbrello/umbrello/dialogs/Makefile.am b/umbrello/umbrello/dialogs/Makefile.am
new file mode 100644
index 00000000..0def48d4
--- /dev/null
+++ b/umbrello/umbrello/dialogs/Makefile.am
@@ -0,0 +1,54 @@
+noinst_LTLIBRARIES = libdialogs.la
+
+INCLUDES = -I$(top_srcdir) $(all_includes)
+
+libdialogs_la_METASOURCES = AUTO
+
+libdialogs_la_SOURCES = \
+ codegenerationoptionsbase.ui \
+ codegenerationpolicybase.ui \
+ codegenerationwizardbase.ui \
+ codeviewerdialogbase.ui \
+ codevieweroptionsbase.ui \
+ diagrampropertiespage.ui \
+ exportallviewsdialogbase.ui \
+ umlrolepropertiesbase.ui \
+activitydialog.cpp \
+activitypage.cpp \
+assocgenpage.cpp \
+assocpage.cpp \
+assocpropdlg.cpp \
+assocrolepage.cpp \
+classgenpage.cpp \
+classifierlistpage.cpp\
+classoptionspage.cpp \
+classpropdlg.cpp \
+classwizard.cpp \
+codeeditor.cpp \
+codegenerationoptionspage.cpp \
+codegenerationpolicypage.cpp \
+codegenerationwizard.cpp \
+codeviewerdialog.cpp \
+codevieweroptionspage.cpp \
+defaultcodegenpolicypage.cpp \
+diagramprintpage.cpp \
+exportallviewsdialog.cpp \
+notedialog.cpp \
+overwritedialogue.cpp \
+pkgcontentspage.cpp \
+parmpropdlg.cpp \
+selectopdlg.cpp \
+settingsdlg.cpp \
+statedialog.cpp \
+umlattributedialog.cpp \
+umlentityattributedialog.cpp \
+umloperationdialog.cpp \
+umltemplatedialog.cpp \
+umlroledialog.cpp \
+umlroleproperties.cpp \
+umlviewdialog.cpp \
+umlwidgetcolorpage.cpp
+
+libdialogs_la_LDFLAGS = $(all_libraries) $(KDE_RPATH) -export-dynamic
+
+
diff --git a/umbrello/umbrello/dialogs/activitydialog.cpp b/umbrello/umbrello/dialogs/activitydialog.cpp
new file mode 100644
index 00000000..d34782a5
--- /dev/null
+++ b/umbrello/umbrello/dialogs/activitydialog.cpp
@@ -0,0 +1,125 @@
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * copyright (C) 2002-2006 *
+ * Umbrello UML Modeller Authors <uml-devel@uml.sf.net> *
+ ***************************************************************************/
+
+// own header
+#include "activitydialog.h"
+
+//qt includes
+#include <qlayout.h>
+
+//kde includes
+#include <kiconloader.h>
+#include <klocale.h>
+
+//local includes
+#include "../umlview.h"
+#include "../activitywidget.h"
+#include "../dialog_utils.h"
+
+ActivityDialog::ActivityDialog( UMLView * pView, ActivityWidget * pWidget )
+ : KDialogBase(IconList, i18n("Properties"), Ok | Apply | Cancel | Help, Ok, pView, "_STATEDIALOG_", true, true) {
+ m_pView = pView;
+ m_pActivityWidget = pWidget;
+ m_bChangesMade = false;
+ setupPages();
+}
+
+void ActivityDialog::slotOk() {
+ applyPage( GeneralPage );
+ applyPage( ColorPage );
+ applyPage( FontPage );
+ accept();
+}
+
+void ActivityDialog::slotApply() {
+ applyPage( (Page) activePageIndex() );
+}
+
+void ActivityDialog::setupPages() {
+ setupGeneralPage();
+ setupColorPage();
+ setupFontPage();
+}
+
+void ActivityDialog::applyPage( Page page ) {
+ m_bChangesMade = true;
+ switch( page ) {
+ case GeneralPage:
+ m_pActivityWidget -> setName( m_GenPageWidgets.nameLE -> text() );
+ m_pActivityWidget -> setDoc( m_GenPageWidgets.docMLE -> text() );
+ break;
+
+ case ColorPage:
+ m_pColorPage -> updateUMLWidget();
+
+ case FontPage:
+ m_pActivityWidget -> setFont( m_pChooser -> font() );
+ break;
+ }//end switch
+}
+
+void ActivityDialog::setupGeneralPage() {
+ QString types[ ] = { i18n("Initial activity"), i18n("Activity"), i18n("End activity"), i18n( "Branch/Merge"), i18n( "Fork/Join" ) };
+ ActivityWidget::ActivityType type = m_pActivityWidget -> getActivityType();
+
+ QVBox * page = addVBoxPage( i18n("General"), i18n("General Properties"), DesktopIcon( "misc") );
+ m_GenPageWidgets.generalGB = new QGroupBox( i18n( "Properties"), (QWidget *)page );
+
+ QGridLayout * generalLayout = new QGridLayout( m_GenPageWidgets.generalGB, 2, 2 );
+ generalLayout -> setSpacing( spacingHint() );
+ generalLayout -> setMargin( fontMetrics().height() );
+
+ QString actType ( types[ (int)type ] );
+ Dialog_Utils::makeLabeledEditField( m_GenPageWidgets.generalGB, generalLayout, 0,
+ m_GenPageWidgets.typeL, i18n("Activity type:"),
+ m_GenPageWidgets.typeLE, actType );
+ m_GenPageWidgets.typeLE -> setEnabled( false );
+
+ Dialog_Utils::makeLabeledEditField( m_GenPageWidgets.generalGB, generalLayout, 1,
+ m_GenPageWidgets.nameL, i18n("Activity name:"),
+ m_GenPageWidgets.nameLE );
+
+ m_GenPageWidgets.docGB = new QGroupBox( i18n( "Documentation"), (QWidget *)page );
+
+ QHBoxLayout * docLayout = new QHBoxLayout( m_GenPageWidgets.docGB );
+ docLayout -> setSpacing( spacingHint() );
+ docLayout -> setMargin( fontMetrics().height() );
+
+ m_GenPageWidgets.docMLE = new QMultiLineEdit( m_GenPageWidgets.docGB );
+ m_GenPageWidgets.docMLE -> setText( m_pActivityWidget -> getDoc() );
+ docLayout -> addWidget( m_GenPageWidgets.docMLE );
+
+ if( type != ActivityWidget::Normal ) {
+ m_GenPageWidgets.nameLE -> setEnabled( false );
+ m_GenPageWidgets.nameLE -> setText( "" );
+ } else
+ m_GenPageWidgets.nameLE -> setText( m_pActivityWidget -> getName() );
+}
+
+void ActivityDialog::setupFontPage() {
+ QVBox * page = addVBoxPage( i18n("Font"), i18n("Font Settings"), DesktopIcon( "fonts") );
+ m_pChooser = new KFontChooser( (QWidget*)page, "font", false, QStringList(), false);
+ m_pChooser -> setFont( m_pActivityWidget -> getFont() );
+}
+
+void ActivityDialog::setupColorPage() {
+ QFrame * colorPage = addPage( i18n("Color"), i18n("Widget Colors"), DesktopIcon( "colors") );
+ QHBoxLayout * m_pColorLayout = new QHBoxLayout(colorPage);
+ m_pColorPage = new UMLWidgetColorPage( colorPage, m_pActivityWidget );
+ m_pColorLayout -> addWidget(m_pColorPage);
+}
+
+
+
+
+
+
+#include "activitydialog.moc"
diff --git a/umbrello/umbrello/dialogs/activitydialog.h b/umbrello/umbrello/dialogs/activitydialog.h
new file mode 100644
index 00000000..4dc5980b
--- /dev/null
+++ b/umbrello/umbrello/dialogs/activitydialog.h
@@ -0,0 +1,136 @@
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * copyright (C) 2002-2006 *
+ * Umbrello UML Modeller Authors <uml-devel@uml.sf.net> *
+ ***************************************************************************/
+
+#ifndef ACTIVITYDIALOG_H
+#define ACTIVITYDIALOG_H
+
+//qt class includes
+#include <qlabel.h>
+#include <qlineedit.h>
+#include <qmultilineedit.h>
+#include <qgroupbox.h>
+
+//kde class includes
+#include <kdialogbase.h>
+#include <kfontdialog.h>
+
+//local class includes
+#include "umlwidgetcolorpage.h"
+
+//forward declarations
+class UMLView;
+class ActivityWidget;
+
+/**
+ * Displays the properties for a @ref ActivityWidget
+ *
+ * @author Paul Hensgen
+ * Bugs and comments to uml-devel@lists.sf.net or http://bugs.kde.org
+ */
+
+class ActivityDialog : public KDialogBase {
+ Q_OBJECT
+
+public:
+ /**
+ * Constructor
+ */
+ ActivityDialog( UMLView * pView, ActivityWidget * pWidget );
+
+ /**
+ * Returns whether changes were made.
+ */
+ bool getChangesMade() {
+ return m_bChangesMade;
+ }
+
+protected slots:
+
+ /**
+ * Entered when OK button pressed.
+ */
+ void slotOk();
+
+ /**
+ * Entered when Apply button pressed.
+ */
+ void slotApply();
+
+protected:
+
+ enum Page
+ {
+ GeneralPage = 0,
+ ColorPage,
+ FontPage
+ };
+
+ /**
+ * Sets up the pages of the dialog.
+ */
+ void setupPages();
+
+ /**
+ * Sets up the general page of the dialog.
+ */
+ void setupGeneralPage();
+
+ /**
+ * Sets up the color page.
+ */
+ void setupColorPage();
+
+ /**
+ * Sets up the font selection page.
+ */
+ void setupFontPage();
+
+ /**
+ * Applys changes to the given page.
+ */
+ void applyPage( Page page );
+
+ /**
+ * Font chooser widget for font page.
+ */
+ KFontChooser * m_pChooser;
+
+ /**
+ * Color page
+ */
+ UMLWidgetColorPage * m_pColorPage;
+
+ /**
+ * The widget to represent.
+ */
+ ActivityWidget * m_pActivityWidget;
+
+ /**
+ * The diagram the widget is on.
+ */
+ UMLView * m_pView;
+
+ /**
+ * Holds whether changes in the dialog have been made.
+ */
+ bool m_bChangesMade;
+
+ struct GeneralPageWidgets {
+ QLabel * nameL, * typeL;
+ QLineEdit * nameLE, * typeLE;
+ QMultiLineEdit * docMLE;
+
+ QGroupBox * docGB, * generalGB;
+ }
+ m_GenPageWidgets;
+};
+
+#endif
diff --git a/umbrello/umbrello/dialogs/activitypage.cpp b/umbrello/umbrello/dialogs/activitypage.cpp
new file mode 100644
index 00000000..8d3f5931
--- /dev/null
+++ b/umbrello/umbrello/dialogs/activitypage.cpp
@@ -0,0 +1,325 @@
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * copyright (C) 2002-2006 *
+ * Umbrello UML Modeller Authors <uml-devel@uml.sf.net> *
+ ***************************************************************************/
+
+#include "activitypage.h"
+#include "../statewidget.h"
+#include "../listpopupmenu.h"
+#include "../uml.h"
+
+#include <kinputdialog.h>
+#include <klocale.h>
+#include <kbuttonbox.h>
+#include <kdebug.h>
+#include <qlayout.h>
+#include <qstringlist.h>
+
+ActivityPage::ActivityPage( QWidget * pParent, StateWidget * pWidget ) : QWidget( pParent ) {
+ m_pStateWidget = pWidget;
+ m_pMenu = 0;
+ setupPage();
+}
+
+ActivityPage::~ActivityPage() {}
+
+void ActivityPage::setupPage() {
+ int margin = fontMetrics().height();
+
+ QVBoxLayout * mainLayout = new QVBoxLayout( this );
+ mainLayout -> setSpacing(10);
+
+ m_pActivityGB = new QGroupBox(i18n("Activities"), this );
+
+ // vertical box layout for the activity lists, arrow buttons and the button box
+ QVBoxLayout* listVBoxLayout = new QVBoxLayout( m_pActivityGB );
+ listVBoxLayout -> setMargin(margin);
+ listVBoxLayout -> setSpacing ( 10 );
+
+ //horizontal box contains the list box and the move up/down buttons
+ QHBoxLayout* listHBoxLayout = new QHBoxLayout( listVBoxLayout );
+
+ m_pActivityLB = new QListBox(m_pActivityGB );
+
+ listHBoxLayout -> addWidget(m_pActivityLB);
+
+ QVBoxLayout * buttonLayout = new QVBoxLayout( listHBoxLayout );
+
+ m_pTopArrowB = new KArrowButton( m_pActivityGB );
+ m_pTopArrowB -> setEnabled( false );
+ buttonLayout -> addWidget( m_pTopArrowB );
+
+ m_pUpArrowB = new KArrowButton( m_pActivityGB );
+ m_pUpArrowB -> setEnabled( false );
+ buttonLayout -> addWidget( m_pUpArrowB );
+
+ m_pDownArrowB = new KArrowButton( m_pActivityGB, Qt::DownArrow );
+ m_pDownArrowB -> setEnabled( false );
+ buttonLayout -> addWidget( m_pDownArrowB );
+
+ m_pBottomArrowB = new KArrowButton( m_pActivityGB, Qt::DownArrow );
+ m_pBottomArrowB -> setEnabled( false );
+ buttonLayout -> addWidget( m_pBottomArrowB );
+
+
+ KButtonBox* buttonBox = new KButtonBox(m_pActivityGB);
+ buttonBox->addButton( i18n("New Activity..."), this, SLOT(slotNewActivity()) );
+ m_pDeleteActivityButton = buttonBox->addButton( i18n("Delete"),
+ this, SLOT(slotDelete()) );
+ m_pRenameButton = buttonBox->addButton( i18n("Rename"), this, SLOT(slotRename()) );
+ listVBoxLayout->addWidget(buttonBox);
+
+ mainLayout -> addWidget( m_pActivityGB );
+
+ //now fill activity list box
+ QStringList list = m_pStateWidget -> getActivityList();
+ QStringList::Iterator end(list.end());
+
+ for( QStringList::Iterator it(list.begin()); it != end; ++it ) {
+ m_pActivityLB -> insertItem( *it );
+ }
+
+ //now setup the signals
+ connect(m_pActivityLB, SIGNAL(clicked(QListBoxItem *)), this, SLOT(slotClicked(QListBoxItem *)));
+ connect(m_pActivityLB, SIGNAL(rightButtonPressed(QListBoxItem *, const QPoint &)),
+ this, SLOT(slotRightButtonPressed(QListBoxItem *, const QPoint &)));
+
+ connect(m_pActivityLB, SIGNAL(rightButtonClicked(QListBoxItem *, const QPoint &)),
+ this, SLOT(slotRightButtonClicked(QListBoxItem *, const QPoint &)));
+
+ connect( m_pTopArrowB, SIGNAL( clicked() ), this, SLOT( slotTopClicked() ) );
+ connect( m_pUpArrowB, SIGNAL( clicked() ), this, SLOT( slotUpClicked() ) );
+ connect( m_pDownArrowB, SIGNAL( clicked() ), this, SLOT( slotDownClicked() ) );
+ connect( m_pBottomArrowB, SIGNAL( clicked() ), this, SLOT( slotBottomClicked() ) );
+
+ connect( m_pActivityLB, SIGNAL( doubleClicked( QListBoxItem* ) ), this, SLOT( slotDoubleClicked( QListBoxItem* ) ) );
+
+ enableWidgets(false);
+}
+
+void ActivityPage::updateActivities() {
+ QStringList list;
+ int count = m_pActivityLB -> count();
+ for( int i = 0; i < count; i++ ) {
+ list.append( m_pActivityLB -> text( i ) );
+ }
+ m_pStateWidget -> setActivities( list );
+}
+
+void ActivityPage::slotMenuSelection( int sel ) {
+ switch( sel ) {
+ case ListPopupMenu::mt_New_Activity:
+ slotNewActivity();
+ break;
+
+ case ListPopupMenu::mt_Delete:
+ slotDelete();
+ break;
+
+ case ListPopupMenu::mt_Rename:
+ slotRename();
+ break;
+ }
+}
+
+void ActivityPage::slotNewActivity() {
+ bool ok = false;
+ QString name = m_pActivityLB->currentText();
+ name = KInputDialog::getText( i18n("New Activity"), i18n("Enter the name of the new activity:"),
+ i18n("new activity"), &ok, UMLApp::app() );
+ if( ok && name.length() > 0 ) {
+ m_pActivityLB->insertItem( name );
+ m_pStateWidget->addActivity( name );
+ }
+}
+
+void ActivityPage::slotDelete() {
+ QString name = m_pActivityLB->currentText();
+ m_pStateWidget->removeActivity(name);
+ m_pActivityLB->removeItem( m_pActivityLB->currentItem() );
+ slotClicked(0);
+}
+
+void ActivityPage::slotRename() {
+ bool ok = false;
+ QString name = m_pActivityLB -> currentText();
+ QString oldName = name;
+ name = KInputDialog::getText( i18n("Rename Activity"), i18n("Enter the new name of the activity:"), name, &ok, UMLApp::app() );
+ if( ok && name.length() > 0 ) {
+ m_pActivityLB -> changeItem( name, m_pActivityLB -> currentItem());
+ m_pStateWidget -> renameActivity( oldName, name );
+ }
+}
+
+void ActivityPage::slotRightButtonClicked(QListBoxItem * /*item*/, const QPoint &/* p*/) {
+ if(m_pMenu) {
+ m_pMenu->hide();
+ disconnect(m_pMenu, SIGNAL(activated(int)), this, SLOT(slotMenuSelection(int)));
+ delete m_pMenu;
+ m_pMenu = 0;
+ }
+}
+
+void ActivityPage::slotRightButtonPressed(QListBoxItem * item, const QPoint & p)
+{
+ ListPopupMenu::Menu_Type type = ListPopupMenu::mt_Undefined;
+ if( item ) { //pressed on an item
+ type = ListPopupMenu::mt_Activity_Selected;
+ } else { //pressed into fresh air
+ type = ListPopupMenu::mt_New_Activity;
+ }
+
+ if(m_pMenu) {
+ m_pMenu -> hide();
+ disconnect(m_pMenu, SIGNAL(activated(int)), this, SLOT(slotMenuSelection(int)));
+ delete m_pMenu;
+ m_pMenu = 0;
+ }
+ m_pMenu = new ListPopupMenu(this, type);
+ m_pMenu->popup(p);
+ connect(m_pMenu, SIGNAL(activated(int)), this, SLOT(slotMenuSelection(int)));
+}
+
+
+void ActivityPage::slotTopClicked() {
+ int count = m_pActivityLB->count();
+ int index = m_pActivityLB->currentItem();
+ //shouldn't occur, but just in case
+ if( count <= 1 || index <= 0 )
+ return;
+
+ //swap the text around in the ListBox
+ QString currentString = m_pActivityLB->text( index );
+ m_pActivityLB->removeItem( index );
+ m_pActivityLB->insertItem( currentString, 0 );
+ //set the moved item selected
+ QListBoxItem* item = m_pActivityLB->item( 0 );
+ m_pActivityLB->setSelected( item, true );
+
+ slotClicked(item);
+}
+
+void ActivityPage::slotUpClicked() {
+ int count = m_pActivityLB -> count();
+ int index = m_pActivityLB -> currentItem();
+ //shouldn't occur, but just in case
+ if( count <= 1 || index <= 0 ) {
+ return;
+ }
+
+ //swap the text around ( meaning attributes )
+ QString aboveString = m_pActivityLB -> text( index - 1 );
+ QString currentString = m_pActivityLB -> text( index );
+ m_pActivityLB -> changeItem( currentString, index -1 );
+ m_pActivityLB -> changeItem( aboveString, index );
+ //set the moved atttribute selected
+ QListBoxItem * item = m_pActivityLB -> item( index - 1 );
+ m_pActivityLB -> setSelected( item, true );
+ slotClicked(item);
+}
+
+void ActivityPage::slotDownClicked() {
+ int count = m_pActivityLB -> count();
+ int index = m_pActivityLB -> currentItem();
+ //shouldn't occur, but just in case
+ if( count <= 1 || index >= count - 1 ) {
+ return;
+ }
+
+ //swap the text around ( meaning attributes )
+ QString belowString = m_pActivityLB -> text( index + 1 );
+ QString currentString = m_pActivityLB -> text( index );
+ m_pActivityLB -> changeItem( currentString, index + 1 );
+ m_pActivityLB -> changeItem( belowString, index );
+ //set the moved atttribute selected
+ QListBoxItem * item = m_pActivityLB -> item( index + 1 );
+ m_pActivityLB -> setSelected( item, true );
+ slotClicked(item);
+}
+
+
+void ActivityPage::slotBottomClicked() {
+ int count = m_pActivityLB->count();
+ int index = m_pActivityLB->currentItem();
+ //shouldn't occur, but just in case
+ if( count <= 1 || index >= count - 1 )
+ return;
+
+ //swap the text around in the ListBox
+ QString currentString = m_pActivityLB->text( index );
+ m_pActivityLB->removeItem( index );
+ m_pActivityLB->insertItem( currentString, m_pActivityLB->count() );
+ //set the moved item selected
+ QListBoxItem* item = m_pActivityLB->item( m_pActivityLB->count() - 1 );
+ m_pActivityLB->setSelected( item, true );
+
+ slotClicked( item );
+}
+
+
+void ActivityPage::slotClicked(QListBoxItem *item) {
+ //make sure clicked on an item
+ if(!item) {
+ enableWidgets(false);
+ m_pActivityLB -> clearSelection();
+ } else {
+ enableWidgets(true);
+ }
+}
+
+void ActivityPage::slotDoubleClicked(QListBoxItem* item) {
+ if (item) {
+ slotRename();
+ }
+}
+
+void ActivityPage::enableWidgets(bool state) {
+ if( !state ) {
+ m_pTopArrowB->setEnabled( false );
+ m_pUpArrowB->setEnabled( false );
+ m_pDownArrowB->setEnabled( false );
+ m_pBottomArrowB->setEnabled( false );
+ m_pDeleteActivityButton->setEnabled(false);
+ m_pRenameButton->setEnabled(false);
+ return;
+ }
+ /*now check the order buttons.
+ Double check an item is selected
+ If only one att. in list make sure there disabled.
+ If at top item,only allow down arrow to be enabled.
+ If at bottom item. only allow up arrow to be enabled.
+ */
+ int index = m_pActivityLB->currentItem();
+ if( m_pActivityLB->count() == 1 || index == -1 ) {
+ m_pTopArrowB->setEnabled(false);
+ m_pUpArrowB->setEnabled(false);
+ m_pDownArrowB->setEnabled(false);
+ m_pBottomArrowB->setEnabled( false );
+ } else if( index == 0 ) {
+ m_pTopArrowB->setEnabled( false );
+ m_pUpArrowB->setEnabled(false);
+ m_pDownArrowB->setEnabled(true);
+ m_pBottomArrowB->setEnabled(true);
+ } else if( index == (int)m_pActivityLB->count() - 1 ) {
+ m_pTopArrowB->setEnabled(true);
+ m_pUpArrowB->setEnabled(true);
+ m_pDownArrowB->setEnabled(false);
+ m_pBottomArrowB->setEnabled(false);
+ } else {
+ m_pTopArrowB->setEnabled(true);
+ m_pUpArrowB->setEnabled(true);
+ m_pDownArrowB->setEnabled(true);
+ m_pBottomArrowB->setEnabled(true);
+ }
+ m_pDeleteActivityButton->setEnabled(true);
+ m_pRenameButton->setEnabled(true);
+}
+
+
+#include "activitypage.moc"
diff --git a/umbrello/umbrello/dialogs/activitypage.h b/umbrello/umbrello/dialogs/activitypage.h
new file mode 100644
index 00000000..7d391b96
--- /dev/null
+++ b/umbrello/umbrello/dialogs/activitypage.h
@@ -0,0 +1,94 @@
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * copyright (C) 2002-2006 *
+ * Umbrello UML Modeller Authors <uml-devel@uml.sf.net> *
+ ***************************************************************************/
+
+#ifndef ACTIVITYPAGE_H
+#define ACTIVITYPAGE_H
+//qt includes
+#include <qwidget.h>
+#include <qgroupbox.h>
+#include <qlistbox.h>
+//kde includes
+#include <karrowbutton.h>
+//app includes
+
+class StateWidget;
+class ListPopupMenu;
+
+/**
+ * @author Paul Hensgen
+ * Bugs and comments to uml-devel@lists.sf.net or http://bugs.kde.org
+ */
+class ActivityPage : public QWidget {
+ Q_OBJECT
+public:
+ /**
+ * Constructor
+ */
+ ActivityPage( QWidget * pParent, StateWidget * pWidget );
+
+ /**
+ * Deconstructor
+ */
+ ~ActivityPage();
+
+ /**
+ * Sets up the page.
+ */
+ void setupPage();
+
+ /**
+ * Sets the activities of the widget.
+ */
+ void updateActivities();
+
+protected:
+ /**
+ * Set the state of the widgets on the page with the given value.
+ *
+ * @param state The state to set the widgets as.
+ */
+ void enableWidgets(bool state);
+
+ /**
+ * The widget to get the activities from.
+ */
+ StateWidget * m_pStateWidget;
+
+ /**
+ * Popup menu used.
+ */
+ ListPopupMenu * m_pMenu;
+ //GUI widgets
+ QListBox * m_pActivityLB;
+ QGroupBox * m_pActivityGB;
+ KArrowButton * m_pUpArrowB, * m_pDownArrowB, * m_pTopArrowB, *m_pBottomArrowB;
+ QPushButton* m_pDeleteActivityButton;
+ QPushButton* m_pRenameButton;
+
+public slots:
+ /**
+ * Popup menu item selected
+ */
+ void slotMenuSelection( int sel );
+ void slotClicked( QListBoxItem* item );
+ void slotDoubleClicked( QListBoxItem* item );
+ void slotRightButtonClicked(QListBoxItem* item, const QPoint& p);
+ void slotRightButtonPressed(QListBoxItem* item, const QPoint& p);
+ void slotTopClicked();
+ void slotUpClicked();
+ void slotDownClicked();
+ void slotBottomClicked();
+ void slotNewActivity();
+ void slotDelete();
+ void slotRename();
+};
+
+#endif
diff --git a/umbrello/umbrello/dialogs/assocgenpage.cpp b/umbrello/umbrello/dialogs/assocgenpage.cpp
new file mode 100644
index 00000000..9be13ee0
--- /dev/null
+++ b/umbrello/umbrello/dialogs/assocgenpage.cpp
@@ -0,0 +1,131 @@
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * copyright (C) 2003-2006 *
+ * Umbrello UML Modeller Authors <uml-devel@uml.sf.net> *
+ ***************************************************************************/
+
+// own header
+#include "assocgenpage.h"
+
+// qt includes
+#include <qlayout.h>
+#include <kcombobox.h>
+
+// kde includes
+#include <klocale.h>
+#include <kmessagebox.h>
+#include <kdebug.h>
+
+// local includes
+#include "../association.h"
+#include "../dialog_utils.h"
+
+AssocGenPage::AssocGenPage (UMLDoc *d, QWidget *parent, AssociationWidget *assoc)
+ : QWidget(parent)
+{
+
+ m_pAssociationWidget = assoc;
+ m_pWidget = 0;
+ m_pTypeCB = 0;
+ m_pAssocNameLE = 0;
+ m_pUmldoc = d;
+
+ constructWidget();
+
+}
+
+AssocGenPage::~AssocGenPage() {}
+
+void AssocGenPage::constructWidget() {
+
+ // general configuration of the GUI
+ int margin = fontMetrics().height();
+ setMinimumSize(310,330);
+ QVBoxLayout * topLayout = new QVBoxLayout(this);
+ topLayout -> setSpacing(6);
+
+ // group boxes for name, documentation properties
+ QGroupBox *nameGB = new QGroupBox(this);
+ QGroupBox *docGB = new QGroupBox(this);
+ nameGB -> setTitle(i18n("Properties"));
+ docGB -> setTitle(i18n("Documentation"));
+ topLayout -> addWidget(nameGB);
+ topLayout -> addWidget(docGB);
+
+ QGridLayout * nameLayout = new QGridLayout(nameGB, 2, 2);
+ nameLayout -> setSpacing(6);
+ nameLayout -> setMargin(margin);
+
+ //Association name
+ QLabel *pAssocNameL = NULL;
+ QLineEdit* nameField = Dialog_Utils::makeLabeledEditField( nameGB, nameLayout, 0,
+ pAssocNameL, i18n("Name:"),
+ m_pAssocNameLE, m_pAssociationWidget->getName() );
+ nameField->setFocus();
+
+ // document
+ QHBoxLayout * docLayout = new QHBoxLayout(docGB);
+ docLayout -> setMargin(margin);
+
+ m_pDoc = new QMultiLineEdit(docGB);
+ docLayout -> addWidget(m_pDoc);
+ m_pDoc-> setText(m_pAssociationWidget-> getDoc());
+ Uml::Association_Type currentType = m_pAssociationWidget->getAssocType();
+ QString currentTypeAsString = UMLAssociation::typeAsString(currentType);
+ QLabel *pTypeL = new QLabel(i18n("Type:"), nameGB);
+ nameLayout->addWidget(pTypeL, 1, 0);
+
+ /* Here is a list of all the supported choices for changing
+ association types */
+ m_AssocTypes.clear();
+ m_AssocTypes << Uml::at_Aggregation
+ << Uml::at_Composition << Uml::at_Containment;
+
+ bool found=false;
+ m_AssocTypeStrings.clear();
+ for (uint i=0; i<m_AssocTypes.size(); ++i) {
+ if (m_AssocTypes[i] == currentType) found=true;
+ QString typeStr = UMLAssociation::typeAsString(m_AssocTypes[i]);
+ m_AssocTypeStrings << typeStr;
+ }
+
+ if (!found) {
+ m_AssocTypes.clear();
+ m_AssocTypes << currentType;
+ m_AssocTypeStrings.clear();
+ m_AssocTypeStrings << currentTypeAsString;
+ }
+
+ m_pTypeCB = new KComboBox(nameGB);
+ pTypeL->setBuddy(m_pTypeCB);
+ m_pTypeCB->insertStringList(m_AssocTypeStrings);
+ m_pTypeCB->setCompletedItems(m_AssocTypeStrings);
+ m_pTypeCB->setCurrentText(currentTypeAsString);
+ m_pTypeCB->setDuplicatesEnabled(false);//only allow one of each type in box
+ m_pTypeCB->setCompletionMode( KGlobalSettings::CompletionPopup );
+ m_pDoc->setWordWrap(QMultiLineEdit::WidgetWidth);
+ nameLayout->addWidget(m_pTypeCB, 1, 1);
+
+
+}
+
+
+void AssocGenPage::updateObject() {
+
+ if (m_pAssociationWidget) {
+ int comboBoxItem = m_pTypeCB->currentItem();
+ Uml::Association_Type newType = m_AssocTypes[comboBoxItem];
+ m_pAssociationWidget->setAssocType(newType);
+ m_pAssociationWidget->setName(m_pAssocNameLE->text());
+ m_pAssociationWidget->setDoc(m_pDoc->text());
+
+ } //end if m_pAssociationWidget
+}
+
+
+#include "assocgenpage.moc"
diff --git a/umbrello/umbrello/dialogs/assocgenpage.h b/umbrello/umbrello/dialogs/assocgenpage.h
new file mode 100644
index 00000000..3eff137f
--- /dev/null
+++ b/umbrello/umbrello/dialogs/assocgenpage.h
@@ -0,0 +1,93 @@
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * copyright (C) 2003-2006 *
+ * Umbrello UML Modeller Authors <uml-devel@uml.sf.net> *
+ ***************************************************************************/
+
+#ifndef ASSOCGENPAGE_H
+#define ASSOCGENPAGE_H
+
+//quicktime class includes
+#include <qwidget.h>
+#include <qgroupbox.h>
+#include <qlabel.h>
+#include <qlineedit.h>
+#include <qbuttongroup.h>
+#include <qmultilineedit.h>
+#include <qradiobutton.h>
+#include <qcheckbox.h>
+#include <qvaluelist.h>
+
+//my class includes
+#include "../umlobject.h"
+#include "../objectwidget.h"
+#include "../umldoc.h"
+#include "../associationwidget.h"
+
+class KComboBox;
+
+
+/**
+ * Displays properties of a UMLObject in a dialog box. This is not usually directly
+ * called. The class @ref AssocPropDlg will set this up for you.
+ *
+ * @short Display properties on a UMLObject.
+ * @author Paul Hensgen <phensgen@techie.com>
+ * Bugs and comments to uml-devel@lists.sf.net or http://bugs.kde.org
+ */
+class AssocGenPage : public QWidget {
+ Q_OBJECT
+public:
+
+ /**
+ * Sets up the AssocGenPage.
+ *
+ * @param d The UMLDoc which controls controls object creation.
+ * @param parent The parent to the AssocGenPage.
+ * @param a The AssociationWidget to display the properties of.
+ */
+ AssocGenPage(UMLDoc *d, QWidget *parent, AssociationWidget *a);
+
+ /**
+ * Standard deconstructor.
+ */
+ ~AssocGenPage();
+
+ /**
+ * Will move information from the dialog into the object.
+ * Call when the ok or apply button is pressed.
+ */
+ void updateObject();
+
+private:
+ QLineEdit * m_pAssocNameLE;
+ KComboBox *m_pTypeCB;
+
+ /* Choices for the QComboBox, and we store ints and strings
+ so we can translate both ways */
+ QValueList<Uml::Association_Type> m_AssocTypes;
+ QStringList m_AssocTypeStrings;
+
+ QMultiLineEdit * m_pDoc;
+
+ AssociationWidget *m_pAssociationWidget;
+ UMLDoc * m_pUmldoc;
+ ObjectWidget * m_pWidget;
+
+ void constructWidget();
+
+public slots:
+ /**
+ * When the draw as actor check box is toggled, the draw
+ * as multi instance need to be enabled/disabled. They
+ * both can't be available at the same time.
+ */
+ // void slotActorToggled( bool state );
+};
+
+#endif
diff --git a/umbrello/umbrello/dialogs/assocpage.cpp b/umbrello/umbrello/dialogs/assocpage.cpp
new file mode 100644
index 00000000..1b3cf5ad
--- /dev/null
+++ b/umbrello/umbrello/dialogs/assocpage.cpp
@@ -0,0 +1,127 @@
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * copyright (C) 2002-2006 *
+ * Umbrello UML Modeller Authors <uml-devel@uml.sf.net> *
+ ***************************************************************************/
+
+#include "assocpage.h"
+#include <qlayout.h>
+#include <klocale.h>
+#include "assocpropdlg.h"
+
+AssocPage::AssocPage(QWidget *parent, UMLView * v, UMLObject * o) : QWidget(parent) {
+ m_pObject = o;
+ m_pView = v;
+ int margin = fontMetrics().height();
+
+ QHBoxLayout * mainLayout = new QHBoxLayout(this);
+ mainLayout -> setSpacing(10);
+
+ m_pAssocGB = new QGroupBox(i18n("Associations"), this);
+ mainLayout -> addWidget(m_pAssocGB);
+
+ QHBoxLayout * layout = new QHBoxLayout(m_pAssocGB);
+ layout -> setSpacing(10);
+ layout -> setMargin(margin);
+
+ m_pAssocLB = new QListBox(m_pAssocGB);
+ layout -> addWidget(m_pAssocLB);
+ setMinimumSize(310, 330);
+ fillListBox();
+ m_pMenu = 0;
+
+ connect(m_pAssocLB, SIGNAL(doubleClicked(QListBoxItem *)),
+ this, SLOT(slotDoubleClick(QListBoxItem *)));
+
+ connect(m_pAssocLB, SIGNAL(rightButtonPressed(QListBoxItem *, const QPoint &)),
+ this, SLOT(slotRightButtonPressed(QListBoxItem *, const QPoint &)));
+
+ connect(m_pAssocLB, SIGNAL(rightButtonClicked(QListBoxItem *, const QPoint &)),
+ this, SLOT(slotRightButtonClicked(QListBoxItem *, const QPoint &)));
+}
+
+AssocPage::~AssocPage() {
+ disconnect(m_pAssocLB, SIGNAL(doubleClicked(QListBoxItem *)),
+ this, SLOT(slotDoubleClick(QListBoxItem *)));
+
+ disconnect(m_pAssocLB, SIGNAL(rightButtonPressed(QListBoxItem *, const QPoint &)),
+ this, SLOT(slotRightButtonPressed(QListBoxItem *, const QPoint &)));
+
+ disconnect(m_pAssocLB, SIGNAL(rightButtonClicked(QListBoxItem *, const QPoint &)),
+ this, SLOT(slotRightButtonClicked(QListBoxItem *, const QPoint &)));
+}
+
+void AssocPage::slotDoubleClick(QListBoxItem * i) {
+
+ if(!i)
+ return;
+
+ int item = m_pAssocLB -> currentItem();
+
+ AssociationWidget * a = m_List.at(item);
+
+ if (a->showDialog())
+ fillListBox();
+}
+
+void AssocPage::fillListBox() {
+ m_List.clear();
+ m_pAssocLB->clear();
+ m_pView->getWidgetAssocs(m_pObject, m_List);
+ AssociationWidgetListIt assoc_it(m_List);
+ AssociationWidget* assocwidget = 0;
+ int i = 0;
+ while((assocwidget = assoc_it.current())) {
+ if( assocwidget->getAssocType() != Uml::at_Anchor) {
+ m_pAssocLB -> insertItem(assocwidget->toString(), i++);
+ }
+ ++assoc_it;
+ }
+}
+
+void AssocPage::slotRightButtonClicked(QListBoxItem */* item*/, const QPoint &/* p*/) {
+ if(m_pMenu) {
+ m_pMenu -> hide();
+ disconnect(m_pMenu, SIGNAL(activated(int)), this, SLOT(slotPopupMenuSel(int)));
+ delete m_pMenu;
+ m_pMenu = 0;
+ }
+}
+
+void AssocPage::slotRightButtonPressed(QListBoxItem * item, const QPoint & p) {
+ if(!item)
+ return;
+ if(m_pMenu) {
+ m_pMenu -> hide();
+ disconnect(m_pMenu, SIGNAL(activated(int)), this, SLOT(slotPopupMenuSel(int)));
+ delete m_pMenu;
+ m_pMenu = 0;
+ }
+ m_pMenu = new ListPopupMenu(this, ListPopupMenu::mt_Association_Selected);
+ m_pMenu->popup(p);
+ connect(m_pMenu, SIGNAL(activated(int)), this, SLOT(slotPopupMenuSel(int)));
+}
+
+void AssocPage::slotPopupMenuSel(int id) {
+ AssociationWidget * a = m_List.at(m_pAssocLB -> currentItem());
+ switch(id) {
+ case ListPopupMenu::mt_Delete:
+ m_pView->removeAssocInViewAndDoc(a);
+ fillListBox();
+ break;
+
+ case ListPopupMenu::mt_Properties:
+ slotDoubleClick(m_pAssocLB -> item(m_pAssocLB -> currentItem()));
+ break;
+ }
+}
+
+
+
+
+#include "assocpage.moc"
diff --git a/umbrello/umbrello/dialogs/assocpage.h b/umbrello/umbrello/dialogs/assocpage.h
new file mode 100644
index 00000000..60e1e339
--- /dev/null
+++ b/umbrello/umbrello/dialogs/assocpage.h
@@ -0,0 +1,76 @@
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * copyright (C) 2002-2006 *
+ * Umbrello UML Modeller Authors <uml-devel@uml.sf.net> *
+ ***************************************************************************/
+
+
+#ifndef ASSOCPAGE_H
+#define ASSOCPAGE_H
+
+#include <qwidget.h>
+#include <qgroupbox.h>
+#include <qlistbox.h>
+#include <qptrlist.h>
+
+#include "../umlobject.h"
+#include "../umlview.h"
+#include "../associationwidgetlist.h"
+#include "../associationwidget.h"
+#include "../listpopupmenu.h"
+
+
+/**
+ * Displays a page on the tabbed dialog window of @ref ClassPropDlg.
+ * The page shows all the Associations that belong to a UMLClassifier.
+ *
+ *
+ * @see ClassPropDlg
+
+ * @see UMLClassifier
+ *
+ * @short The page shows all the Associations that belong to a UMLClassifier.
+ * @author Paul Hensgen <phensgen@techie.com>
+ * Bugs and comments to uml-devel@lists.sf.net or http://bugs.kde.org
+ */
+class AssocPage : public QWidget {
+ Q_OBJECT
+public:
+ /**
+ * Constructs an instance of AssocPage.
+ *
+ * @param parent The parent of the page
+ * @param v The view the UMLObject being represented.
+ * @param o The UMLObject being represented
+ */
+ AssocPage(QWidget *parent, UMLView * v, UMLObject * o);
+
+ /**
+ * Standard deconstructor.
+ */
+ ~AssocPage();
+private:
+ UMLObject * m_pObject;
+ UMLView * m_pView;
+ QListBox * m_pAssocLB;
+ QGroupBox * m_pAssocGB;
+ AssociationWidgetList m_List;
+ ListPopupMenu * m_pMenu;
+
+ /**
+ * Fills the list box with the objects associations.
+ */
+ void fillListBox();
+public slots:
+ void slotDoubleClick(QListBoxItem * i);
+ void slotRightButtonClicked(QListBoxItem */* item*/, const QPoint &/* p*/);
+ void slotRightButtonPressed(QListBoxItem * item, const QPoint & p);
+ void slotPopupMenuSel(int id);
+};
+
+#endif
diff --git a/umbrello/umbrello/dialogs/assocpropdlg.cpp b/umbrello/umbrello/dialogs/assocpropdlg.cpp
new file mode 100644
index 00000000..2458da13
--- /dev/null
+++ b/umbrello/umbrello/dialogs/assocpropdlg.cpp
@@ -0,0 +1,115 @@
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * copyright (C) 2002-2007 *
+ * Umbrello UML Modeller Authors <uml-devel@uml.sf.net> *
+ ***************************************************************************/
+
+// own header
+#include "assocpropdlg.h"
+
+// qt/kde includes
+#include <qlayout.h>
+#include <qlabel.h>
+
+#include <klocale.h>
+#include <kmessagebox.h>
+#include <kiconloader.h>
+#include <kdebug.h>
+
+// local includes
+#include "assocgenpage.h"
+#include "assocrolepage.h"
+#include "classpropdlg.h"
+#include "classgenpage.h"
+#include "umlwidgetcolorpage.h"
+
+#include "../umlobject.h"
+#include "../umldoc.h"
+#include "../objectwidget.h"
+#include "../uml.h"
+#include "../umlview.h"
+
+
+AssocPropDlg::AssocPropDlg (QWidget *parent, AssociationWidget * assocWidget, int pageNum)
+ : KDialogBase(IconList, i18n("Association Properties"), Ok | Apply | Cancel | Help,
+ Ok, parent, "_ASSOCPROPDLG_", true, true)
+{
+ init();
+ m_pAssoc = assocWidget;
+
+ m_pDoc = ((UMLApp *)parent) -> getDocument(); // needed?
+
+ setupPages(assocWidget);
+ showPage(pageNum);
+}
+
+AssocPropDlg::~AssocPropDlg() { }
+
+void AssocPropDlg::init ( )
+{
+ m_pAssoc = 0;
+ m_pGenPage = 0;
+ m_pRolePage = 0;
+}
+
+void AssocPropDlg::slotOk() {
+ slotApply();
+ KDialogBase::accept();
+}
+
+void AssocPropDlg::slotApply() {
+
+ if (m_pGenPage) {
+ m_pGenPage->updateObject();
+ }
+
+ if (m_pRolePage) {
+ m_pRolePage->updateObject();
+ }
+
+ if (m_pAssoc) {
+ m_pAssoc->lwSetFont( m_pChooser->font() );
+ }
+
+
+}
+
+// void AssocPropDlg::setupPages (UMLObject * c)
+void AssocPropDlg::setupPages (AssociationWidget *assocWidget)
+{
+
+ // general page
+ QFrame *page = addPage( i18n("General"), i18n("General Settings"), DesktopIcon( "misc") );
+ QHBoxLayout *genLayout = new QHBoxLayout(page);
+ page -> setMinimumSize(310, 330);
+ m_pGenPage = new AssocGenPage (m_pDoc, page, assocWidget);
+ genLayout -> addWidget(m_pGenPage);
+
+ // role page
+ QFrame * newPage = addPage( i18n("Roles"), i18n("Role Settings"), DesktopIcon( "misc") );
+ QHBoxLayout * roleLayout = new QHBoxLayout(newPage);
+ // newPage -> setMinimumSize(310, 330);
+ m_pRolePage = new AssocRolePage(m_pDoc, newPage, assocWidget);
+ roleLayout -> addWidget(m_pRolePage);
+
+ setupFontPage();
+
+}
+
+void AssocPropDlg::setupFontPage()
+{
+ if( !m_pAssoc)
+ return;
+
+ QVBox *page = addVBoxPage( i18n("Font"), i18n("Font Settings"), DesktopIcon( "fonts"));
+ m_pChooser = new KFontChooser( (QWidget*)page, "font", false, QStringList(), false);
+ m_pChooser->setFont( m_pAssoc->getFont());
+ m_pChooser->setSampleText(i18n("Association font"));
+}
+
+#include "assocpropdlg.moc"
diff --git a/umbrello/umbrello/dialogs/assocpropdlg.h b/umbrello/umbrello/dialogs/assocpropdlg.h
new file mode 100644
index 00000000..a5bdad6e
--- /dev/null
+++ b/umbrello/umbrello/dialogs/assocpropdlg.h
@@ -0,0 +1,72 @@
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * copyright (C) 2002-2006 *
+ * Umbrello UML Modeller Authors <uml-devel@uml.sf.net> *
+ ***************************************************************************/
+
+#ifndef ASSOCPROPDLG_H
+#define ASSOCPROPDLG_H
+
+//kde class includes
+#include <kdialogbase.h>
+#include <kfontdialog.h>
+#include "../associationwidget.h"
+
+class AssocRolePage;
+class AssocGenPage;
+class UMLDoc;
+// class ObjectWidget;
+// class UMLObject;
+// class UMLWidget;
+
+/**
+ * Based off of AssocPropDlg class
+ * @author Brian Thomas <Brian.A.Thomas@gsfc.nasa.gov>
+ * Bugs and comments to uml-devel@lists.sf.net or http://bugs.kde.org
+ */
+class AssocPropDlg : public KDialogBase {
+ Q_OBJECT
+public:
+
+ /**
+ * Sets up a Association Properties Dialog.
+ * @param parent The parent of the AssocPropDlg
+ * @param a The Association Widget to display properties of.
+ * @param pageNum The page to show first.
+ */
+
+ AssocPropDlg(QWidget *parent, AssociationWidget *a, int pageNum = 0);
+
+ /**
+ * Standard deconstructor
+ */
+ ~AssocPropDlg();
+
+ enum Page { page_gen = 0, page_role, page_font };
+
+protected:
+ void setupPages(AssociationWidget * assocWidget);
+ void setupFontPage();
+ void init();
+
+protected slots:
+ void slotOk();
+ void slotApply();
+
+private:
+ AssocGenPage *m_pGenPage;
+ AssocRolePage *m_pRolePage;
+ KFontChooser * m_pChooser;
+ AssociationWidget *m_pAssoc;
+
+ UMLDoc *m_pDoc; // is this needed??
+
+};
+
+#endif /* ASSOCPROPDLG_H */
+
diff --git a/umbrello/umbrello/dialogs/assocrolepage.cpp b/umbrello/umbrello/dialogs/assocrolepage.cpp
new file mode 100644
index 00000000..807a7e1e
--- /dev/null
+++ b/umbrello/umbrello/dialogs/assocrolepage.cpp
@@ -0,0 +1,293 @@
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * copyright (C) 2003-2006 *
+ * Umbrello UML Modeller Authors <uml-devel@uml.sf.net> *
+ ***************************************************************************/
+
+// own header
+#include "assocrolepage.h"
+
+// qt includes
+#include <qlayout.h>
+
+// kde includes
+#include <klocale.h>
+#include <kmessagebox.h>
+#include <kdebug.h>
+
+// local includes
+#include "../dialog_utils.h"
+
+AssocRolePage::AssocRolePage (UMLDoc *d, QWidget *parent, AssociationWidget *assoc)
+ : QWidget(parent)
+{
+
+ m_pAssociationWidget = assoc;
+ m_pWidget = 0;
+ m_pUmldoc = d;
+
+ m_pRoleALE = 0;
+ m_pRoleBLE = 0;
+ m_pMultiALE = 0;
+ m_pMultiBLE = 0;
+
+ constructWidget();
+
+}
+
+AssocRolePage::~AssocRolePage() {}
+
+void AssocRolePage::constructWidget() {
+
+ // underlying roles and objects
+ QString nameA = m_pAssociationWidget->getRoleName(Uml::A);
+ QString nameB = m_pAssociationWidget->getRoleName(Uml::B);
+ QString titleA = i18n("Role A Properties");
+ QString titleB = i18n("Role B Properties");
+ QString widgetNameA = m_pAssociationWidget->getWidget(Uml::A)->getName();
+ QString widgetNameB = m_pAssociationWidget->getWidget(Uml::B)->getName();
+ if(!widgetNameA.isEmpty())
+ titleA.append(" (" + widgetNameA + ')');
+ if(!widgetNameB.isEmpty())
+ titleB.append(" (" + widgetNameB + ')');
+
+ // general configuration of the GUI
+ int margin = fontMetrics().height();
+
+ QGridLayout * mainLayout = new QGridLayout(this, 4, 2);
+ mainLayout -> setSpacing(6);
+
+ // group boxes for role, documentation properties
+ QGroupBox *propsAGB = new QGroupBox(this);
+ QGroupBox *propsBGB = new QGroupBox(this);
+ QButtonGroup * scopeABG = new QButtonGroup(i18n("Role A Visibility"), this );
+ QButtonGroup * scopeBBG = new QButtonGroup(i18n("Role B Visibility"), this );
+ QButtonGroup * changeABG = new QButtonGroup(i18n("Role A Changeability"), this );
+ QButtonGroup * changeBBG = new QButtonGroup(i18n("Role B Changeability"), this );
+ QGroupBox *docAGB = new QGroupBox(this);
+ QGroupBox *docBGB = new QGroupBox(this);
+ propsAGB -> setTitle(titleA);
+ propsBGB -> setTitle(titleB);
+ docAGB -> setTitle(i18n("Documentation"));
+ docBGB -> setTitle(i18n("Documentation"));
+
+ QGridLayout * propsALayout = new QGridLayout(propsAGB, 2, 2);
+ propsALayout -> setSpacing(6);
+ propsALayout -> setMargin(margin);
+
+ QGridLayout * propsBLayout = new QGridLayout(propsBGB, 3, 2);
+ propsBLayout -> setSpacing(6);
+ propsBLayout -> setMargin(margin);
+
+ // Properties
+ //
+
+ // Rolename A
+ QLabel *pRoleAL = NULL;
+ Dialog_Utils::makeLabeledEditField( propsAGB, propsALayout, 0,
+ pRoleAL, i18n("Rolename:"),
+ m_pRoleALE, nameA );
+
+ // Multi A
+ QLabel *pMultiAL = NULL;
+ Dialog_Utils::makeLabeledEditField( propsAGB, propsALayout, 1,
+ pMultiAL, i18n("Multiplicity:"),
+ m_pMultiALE, m_pAssociationWidget->getMulti(Uml::A) );
+
+ // Visibility A
+ QHBoxLayout * scopeALayout = new QHBoxLayout(scopeABG);
+ scopeALayout -> setMargin(margin);
+
+ m_PublicARB = new QRadioButton(i18n("Public"), scopeABG);
+ scopeALayout -> addWidget(m_PublicARB);
+
+ m_PrivateARB = new QRadioButton(i18n("Private"), scopeABG);
+ scopeALayout -> addWidget(m_PrivateARB);
+
+ m_ProtectedARB = new QRadioButton(i18n("Protected"), scopeABG);
+ scopeALayout -> addWidget(m_ProtectedARB);
+
+ m_ImplementationARB = new QRadioButton(i18n("Implementation"), scopeABG);
+ scopeALayout -> addWidget(m_ImplementationARB);
+
+ Uml::Visibility scope = m_pAssociationWidget->getVisibility(Uml::A);
+ if( scope == Uml::Visibility::Public )
+ m_PublicARB -> setChecked( true );
+ else if( scope == Uml::Visibility::Private )
+ m_PrivateARB -> setChecked( true );
+ else if( scope == Uml::Visibility::Implementation )
+ m_PrivateARB -> setChecked( true );
+ else
+ m_ProtectedARB -> setChecked( true );
+
+ // Changeability A
+ QHBoxLayout * changeALayout = new QHBoxLayout(changeABG);
+ changeALayout -> setMargin(margin);
+
+ m_ChangeableARB = new QRadioButton(i18n("Changeable"), changeABG);
+ changeALayout -> addWidget(m_ChangeableARB);
+
+ m_FrozenARB = new QRadioButton(i18n("Frozen"), changeABG);
+ changeALayout -> addWidget(m_FrozenARB);
+
+ m_AddOnlyARB = new QRadioButton(i18n("Add only"), changeABG);
+ changeALayout -> addWidget(m_AddOnlyARB);
+
+ Uml::Changeability_Type changeability = m_pAssociationWidget->getChangeability(Uml::A);
+ if( changeability == Uml::chg_Changeable )
+ m_ChangeableARB -> setChecked( true );
+ else if( changeability == Uml::chg_Frozen )
+ m_FrozenARB -> setChecked( true );
+ else
+ m_AddOnlyARB -> setChecked( true );
+
+ // Rolename B
+ QLabel * pRoleBL = NULL;
+ Dialog_Utils::makeLabeledEditField( propsBGB, propsBLayout, 0,
+ pRoleBL, i18n("Rolename:"),
+ m_pRoleBLE, nameB );
+
+ // Multi B
+ QLabel * pMultiBL = NULL;
+ Dialog_Utils::makeLabeledEditField( propsBGB, propsBLayout, 1,
+ pMultiBL, i18n("Multiplicity:"),
+ m_pMultiBLE, m_pAssociationWidget->getMulti(Uml::B) );
+
+ // Visibility B
+
+ QHBoxLayout * scopeBLayout = new QHBoxLayout(scopeBBG);
+ scopeBLayout -> setMargin(margin);
+
+ m_PublicBRB = new QRadioButton(i18n("Public"), scopeBBG);
+ scopeBLayout -> addWidget(m_PublicBRB);
+
+ m_PrivateBRB = new QRadioButton(i18n("Private"), scopeBBG);
+ scopeBLayout -> addWidget(m_PrivateBRB);
+
+ m_ProtectedBRB = new QRadioButton(i18n("Protected"), scopeBBG);
+ scopeBLayout -> addWidget(m_ProtectedBRB);
+
+ m_ImplementationBRB = new QRadioButton(i18n("Implementation"), scopeBBG);
+ scopeBLayout -> addWidget(m_ImplementationBRB);
+
+ scope = m_pAssociationWidget->getVisibility(Uml::B);
+ if( scope == Uml::Visibility::Public )
+ m_PublicBRB -> setChecked( true );
+ else if( scope == Uml::Visibility::Private )
+ m_PrivateBRB -> setChecked( true );
+ else if( scope == Uml::Visibility::Protected )
+ m_ProtectedBRB -> setChecked( true );
+ else
+ m_ImplementationBRB -> setChecked( true );
+
+ // Changeability B
+ QHBoxLayout * changeBLayout = new QHBoxLayout(changeBBG);
+ changeBLayout -> setMargin(margin);
+
+ m_ChangeableBRB = new QRadioButton(i18n("Changeable"), changeBBG);
+ changeBLayout -> addWidget(m_ChangeableBRB);
+
+ m_FrozenBRB = new QRadioButton(i18n("Frozen"), changeBBG);
+ changeBLayout -> addWidget(m_FrozenBRB);
+
+ m_AddOnlyBRB = new QRadioButton(i18n("Add only"), changeBBG);
+ changeBLayout -> addWidget(m_AddOnlyBRB);
+
+ changeability = m_pAssociationWidget->getChangeability(Uml::B);
+ if( changeability == Uml::chg_Changeable )
+ m_ChangeableBRB -> setChecked( true );
+ else if( changeability == Uml::chg_Frozen )
+ m_FrozenBRB -> setChecked( true );
+ else
+ m_AddOnlyBRB -> setChecked( true );
+
+ // Documentation
+ //
+
+ // Document A
+ QHBoxLayout * docALayout = new QHBoxLayout(docAGB);
+ docALayout -> setMargin(margin);
+ m_pDocA = new QMultiLineEdit(docAGB);
+ docALayout -> addWidget(m_pDocA);
+ m_pDocA-> setText(m_pAssociationWidget-> getRoleDoc(Uml::A));
+ // m_pDocA-> setText("<<not implemented yet>>");
+ // m_pDocA-> setEnabled(false);
+ m_pDocA->setWordWrap(QMultiLineEdit::WidgetWidth);
+
+ // Document B
+ QHBoxLayout * docBLayout = new QHBoxLayout(docBGB);
+ docBLayout -> setMargin(margin);
+ m_pDocB = new QMultiLineEdit(docBGB);
+ docBLayout -> addWidget(m_pDocB);
+ m_pDocB-> setText(m_pAssociationWidget-> getRoleDoc(Uml::B));
+ // m_pDocB-> setEnabled(false);
+ m_pDocB->setWordWrap(QMultiLineEdit::WidgetWidth);
+
+ // add group boxes to main layout
+ mainLayout -> addWidget( propsAGB, 0, 0);
+ mainLayout -> addWidget( scopeABG, 1, 0);
+ mainLayout -> addWidget(changeABG, 2, 0);
+ mainLayout -> addWidget( docAGB, 3, 0);
+ mainLayout -> addWidget( propsBGB, 0, 1);
+ mainLayout -> addWidget( scopeBBG, 1, 1);
+ mainLayout -> addWidget(changeBBG, 2, 1);
+ mainLayout -> addWidget( docBGB, 3, 1);
+
+}
+
+void AssocRolePage::updateObject() {
+
+ if(m_pAssociationWidget) {
+
+ // set props
+ m_pAssociationWidget->setRoleName(m_pRoleALE->text(), Uml::A);
+ m_pAssociationWidget->setRoleName(m_pRoleBLE->text(), Uml::B);
+ m_pAssociationWidget->setMulti(m_pMultiALE->text(), Uml::A);
+ m_pAssociationWidget->setMulti(m_pMultiBLE->text(), Uml::B);
+
+ if(m_PrivateARB->isChecked())
+ m_pAssociationWidget->setVisibility(Uml::Visibility::Private, Uml::A);
+ else if(m_ProtectedARB->isChecked())
+ m_pAssociationWidget->setVisibility(Uml::Visibility::Protected, Uml::A);
+ else if(m_PublicARB->isChecked())
+ m_pAssociationWidget->setVisibility(Uml::Visibility::Public, Uml::A);
+ else if(m_ImplementationARB->isChecked())
+ m_pAssociationWidget->setVisibility(Uml::Visibility::Implementation, Uml::A);
+
+ if(m_PrivateBRB->isChecked())
+ m_pAssociationWidget->setVisibility(Uml::Visibility::Private, Uml::B);
+ else if(m_ProtectedBRB->isChecked())
+ m_pAssociationWidget->setVisibility(Uml::Visibility::Protected, Uml::B);
+ else if(m_PublicBRB->isChecked())
+ m_pAssociationWidget->setVisibility(Uml::Visibility::Public, Uml::B);
+ else if(m_ImplementationBRB->isChecked())
+ m_pAssociationWidget->setVisibility(Uml::Visibility::Implementation, Uml::B);
+
+ if(m_FrozenARB->isChecked())
+ m_pAssociationWidget->setChangeability(Uml::chg_Frozen, Uml::A);
+ else if(m_AddOnlyARB->isChecked())
+ m_pAssociationWidget->setChangeability(Uml::chg_AddOnly, Uml::A);
+ else
+ m_pAssociationWidget->setChangeability(Uml::chg_Changeable, Uml::A);
+
+ if(m_FrozenBRB->isChecked())
+ m_pAssociationWidget->setChangeability(Uml::chg_Frozen, Uml::B);
+ else if(m_AddOnlyBRB->isChecked())
+ m_pAssociationWidget->setChangeability(Uml::chg_AddOnly, Uml::B);
+ else
+ m_pAssociationWidget->setChangeability(Uml::chg_Changeable, Uml::B);
+
+ m_pAssociationWidget->setRoleDoc(m_pDocA->text(), Uml::A);
+ m_pAssociationWidget->setRoleDoc(m_pDocB->text(), Uml::B);
+
+ } //end if m_pAssociationWidget
+
+}
+
+
+#include "assocrolepage.moc"
diff --git a/umbrello/umbrello/dialogs/assocrolepage.h b/umbrello/umbrello/dialogs/assocrolepage.h
new file mode 100644
index 00000000..c1c4d603
--- /dev/null
+++ b/umbrello/umbrello/dialogs/assocrolepage.h
@@ -0,0 +1,85 @@
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * copyright (C) 2003-2006 *
+ * Umbrello UML Modeller Authors <uml-devel@uml.sf.net> *
+ ***************************************************************************/
+
+#ifndef ASSOCROLEPAGE_H
+#define ASSOCROLEPAGE_H
+
+//quicktime class includes
+#include <qwidget.h>
+#include <qgroupbox.h>
+#include <qlabel.h>
+#include <qlineedit.h>
+#include <qbuttongroup.h>
+#include <qmultilineedit.h>
+#include <qradiobutton.h>
+#include <qcheckbox.h>
+
+//my class includes
+#include "../umlobject.h"
+#include "../objectwidget.h"
+#include "../umldoc.h"
+#include "../associationwidget.h"
+
+/**
+ * Displays properties of a UMLObject in a dialog box. This is not usually directly
+ * called. The class @ref AssocPropDlg will set this up for you.
+ *
+ * @short Display properties on a UMLObject.
+ * @author Paul Hensgen <phensgen@techie.com>
+ * Bugs and comments to uml-devel@lists.sf.net or http://bugs.kde.org
+ */
+class AssocRolePage : public QWidget {
+ Q_OBJECT
+public:
+
+ /**
+ * Sets up the AssocRolePage.
+ *
+ * @param d The UMLDoc which controls controls object creation.
+ * @param parent The parent to the AssocRolePage.
+ * @param a The AssociationWidget to display the properties of.
+ */
+ AssocRolePage(UMLDoc *d, QWidget *parent, AssociationWidget *a);
+
+ /**
+ * Standard deconstructor.
+ */
+ ~AssocRolePage();
+
+ /**
+ * Will move information from the dialog into the object.
+ * Call when the ok or apply button is pressed.
+ */
+ void updateObject();
+
+private:
+ QLineEdit *m_pRoleALE, *m_pRoleBLE, *m_pMultiALE, *m_pMultiBLE;
+ QMultiLineEdit *m_pDocA, *m_pDocB;
+ AssociationWidget *m_pAssociationWidget;
+ UMLDoc * m_pUmldoc;
+ ObjectWidget *m_pWidget;
+ QRadioButton *m_PublicARB, *m_ProtectedARB, *m_PrivateARB, *m_ImplementationARB;
+ QRadioButton *m_PublicBRB, *m_ProtectedBRB, *m_PrivateBRB, *m_ImplementationBRB;
+ QRadioButton *m_ChangeableARB, *m_AddOnlyARB, *m_FrozenARB;
+ QRadioButton *m_ChangeableBRB, *m_AddOnlyBRB, *m_FrozenBRB;
+
+ void constructWidget();
+
+public slots:
+ /**
+ * When the draw as actor check box is toggled, the draw
+ * as multi instance need to be enabled/disabled. They
+ * both can't be available at the same time.
+ */
+ // void slotActorToggled( bool state );
+};
+
+#endif
diff --git a/umbrello/umbrello/dialogs/classgenpage.cpp b/umbrello/umbrello/dialogs/classgenpage.cpp
new file mode 100644
index 00000000..01b3d3c7
--- /dev/null
+++ b/umbrello/umbrello/dialogs/classgenpage.cpp
@@ -0,0 +1,472 @@
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * copyright (C) 2002-2006 *
+ * Umbrello UML Modeller Authors <uml-devel@uml.sf.net> *
+ ***************************************************************************/
+
+// my own header
+#include "classgenpage.h"
+
+// qt includes
+#include <qlayout.h>
+#include <qgroupbox.h>
+#include <qlabel.h>
+#include <qlineedit.h>
+#include <qbuttongroup.h>
+#include <qmultilineedit.h>
+#include <qradiobutton.h>
+#include <qcheckbox.h>
+
+// kde includes
+#include <klocale.h>
+#include <kdebug.h>
+#include <kmessagebox.h>
+#include <kcombobox.h>
+
+// my class includes
+#include "../umlobject.h"
+#include "../objectwidget.h"
+#include "../uml.h"
+#include "../umldoc.h"
+#include "../artifact.h"
+#include "../component.h"
+#include "../umlview.h"
+#include "../stereotype.h"
+
+ClassGenPage::ClassGenPage(UMLDoc* d, QWidget* parent, UMLObject* o) : QWidget(parent) {
+ m_pWidget = 0;
+ m_pObject = 0;
+ m_pInstanceWidget = 0;
+ QString name;
+ int margin = fontMetrics().height();
+ Uml::Object_Type t = o -> getBaseType();
+ m_pUmldoc = d;
+ if (t == Uml::ot_Class) {
+ name = i18n("Class &name:");
+ } else if (t == Uml::ot_Actor) {
+ name = i18n("Actor &name:");
+ } else if (t == Uml::ot_Package) {
+ name = i18n("Package &name:");
+ } else if (t == Uml::ot_UseCase) {
+ name = i18n("Use case &name:");
+ } else if (t == Uml::ot_Interface) {
+ name = i18n("Interface &name:");
+ } else if (t == Uml::ot_Component) {
+ name = i18n("Component &name:");
+ } else if (t == Uml::ot_Artifact) {
+ name = i18n("Artifact &name:");
+ } else if (t == Uml::ot_Enum) {
+ name = i18n("Enum &name:");
+ } else if (t == Uml::ot_Datatype) {
+ name = i18n("Datatype &name:");
+ } else if (t == Uml::ot_Entity) {
+ name = i18n("Entity &name:");
+ } else {
+ kWarning() << "creating class gen page for unknown widget type" << endl;
+ }
+ setMinimumSize(310,330);
+ QVBoxLayout * topLayout = new QVBoxLayout(this);
+ topLayout -> setSpacing(6);
+
+ //setup name
+ QGridLayout * m_pNameLayout = new QGridLayout(topLayout, 4, 2);
+ m_pNameLayout -> setSpacing(6);
+ m_pNameL = new QLabel(this);
+ m_pNameL -> setText(name);
+ m_pNameLayout -> addWidget(m_pNameL, 0, 0);
+
+ m_pClassNameLE = new QLineEdit(this);
+ m_pNameLayout -> addWidget(m_pClassNameLE, 0, 1);
+ m_pClassNameLE->setFocus();
+ m_pNameL->setBuddy(m_pClassNameLE);
+
+ m_pStereoTypeCB = 0;
+ m_pPackageLE = 0;
+ m_pAbstractCB = 0;
+ m_pDeconCB = 0;
+
+ m_pStereoTypeL = new QLabel(i18n("&Stereotype name:"), this);
+ m_pNameLayout -> addWidget(m_pStereoTypeL, 1, 0);
+
+ m_pStereoTypeCB = new KComboBox(true, this);
+ m_pNameLayout -> addWidget(m_pStereoTypeCB, 1, 1);
+
+ m_pStereoTypeCB->setCurrentText( o->getStereotype() );
+ m_pStereoTypeL->setBuddy(m_pStereoTypeCB);
+
+ if (t == Uml::ot_Interface || t == Uml::ot_Datatype || t == Uml::ot_Enum) {
+ m_pStereoTypeCB->setEditable(false);
+ }
+
+ if (t == Uml::ot_Class || t == Uml::ot_Interface) {
+ m_pPackageL = new QLabel(i18n("&Package name:"), this);
+ m_pNameLayout -> addWidget(m_pPackageL, 2, 0);
+
+ m_pPackageLE = new QLineEdit(this);
+ m_pNameLayout -> addWidget(m_pPackageLE, 2, 1);
+
+ m_pPackageLE -> setText(o -> getPackage());
+ m_pPackageLE -> setEnabled(false);
+ m_pPackageL->setBuddy(m_pPackageLE);
+ }
+
+ if (t == Uml::ot_Class || t == Uml::ot_UseCase ) {
+ QString abstractCaption;
+ if ( t == Uml::ot_Class ) {
+ abstractCaption = i18n("A&bstract class");
+ } else {
+ abstractCaption = i18n("A&bstract use case");
+ }
+ m_pAbstractCB = new QCheckBox( abstractCaption, this );
+ m_pAbstractCB -> setChecked( o -> getAbstract() );
+ m_pNameLayout -> addWidget( m_pAbstractCB, 3, 0 );
+ }
+
+ if (t == Uml::ot_Component) {
+ m_pExecutableCB = new QCheckBox(i18n("&Executable"), this);
+ m_pExecutableCB->setChecked( (static_cast<UMLComponent*>(o))->getExecutable() );
+ m_pNameLayout->addWidget( m_pExecutableCB, 3, 0 );
+ }
+
+ if (t == Uml::ot_Artifact) {
+ //setup artifact draw as
+ m_pDrawAsBG = new QButtonGroup(i18n("Draw As"), this);
+ QHBoxLayout* drawAsLayout = new QHBoxLayout(m_pDrawAsBG);
+ drawAsLayout->setMargin(margin);
+ m_pDrawAsBG->setExclusive(true);
+
+ m_pDefaultRB = new QRadioButton(i18n("&Default"), m_pDrawAsBG);
+ drawAsLayout->addWidget(m_pDefaultRB);
+
+ m_pFileRB = new QRadioButton(i18n("&File"), m_pDrawAsBG);
+ drawAsLayout->addWidget(m_pFileRB);
+
+ m_pLibraryRB = new QRadioButton(i18n("&Library"), m_pDrawAsBG);
+ drawAsLayout->addWidget(m_pLibraryRB);
+
+ m_pTableRB = new QRadioButton(i18n("&Table"), m_pDrawAsBG);
+ drawAsLayout->addWidget(m_pTableRB);
+
+ topLayout->addWidget(m_pDrawAsBG);
+
+ UMLArtifact::Draw_Type drawAs = (static_cast<UMLArtifact*>(o))->getDrawAsType();
+
+ if (drawAs == UMLArtifact::file) {
+ m_pFileRB->setChecked(true);
+ } else if (drawAs == UMLArtifact::library) {
+ m_pLibraryRB->setChecked(true);
+ } else if (drawAs == UMLArtifact::table) {
+ m_pTableRB->setChecked(true);
+ } else {
+ m_pDefaultRB->setChecked(true);
+ }
+ }
+
+ //setup scope
+ m_pButtonBG = new QButtonGroup(i18n("Visibility"), this);
+ QHBoxLayout * scopeLayout = new QHBoxLayout(m_pButtonBG);
+ scopeLayout -> setMargin(margin);
+ m_pButtonBG -> setExclusive(true);
+
+ m_pPublicRB = new QRadioButton(i18n("P&ublic"), m_pButtonBG);
+ scopeLayout -> addWidget(m_pPublicRB);
+
+ m_pPrivateRB = new QRadioButton(i18n("P&rivate"), m_pButtonBG);
+ scopeLayout -> addWidget(m_pPrivateRB);
+
+ m_pProtectedRB = new QRadioButton(i18n("Pro&tected"), m_pButtonBG);
+ scopeLayout -> addWidget(m_pProtectedRB);
+ topLayout -> addWidget(m_pButtonBG);
+
+ m_pImplementationRB = new QRadioButton(i18n("Imple&mentation"), m_pButtonBG);
+ scopeLayout -> addWidget(m_pImplementationRB);
+ topLayout -> addWidget(m_pButtonBG);
+ //setup documentation
+ m_pDocGB = new QGroupBox(this);
+ QHBoxLayout * docLayout = new QHBoxLayout(m_pDocGB);
+ docLayout -> setMargin(margin);
+ m_pDocGB -> setTitle(i18n("Documentation"));
+
+ m_pDoc = new QMultiLineEdit(m_pDocGB);
+ docLayout -> addWidget(m_pDoc);
+ topLayout -> addWidget(m_pDocGB);
+
+ m_pObject = o;
+ //setup fields
+ m_pClassNameLE -> setText(o -> getName());
+ m_pDoc-> setText(o -> getDoc());
+ Uml::Visibility s = o -> getVisibility();
+ if(s == Uml::Visibility::Public)
+ m_pPublicRB->setChecked(true);
+ else if(s == Uml::Visibility::Private)
+ m_pPrivateRB->setChecked(true);
+ else if(s == Uml::Visibility::Protected)
+ m_pProtectedRB->setChecked(true);
+ else
+ m_pImplementationRB -> setChecked(true);
+
+ // manage stereotypes
+ m_pStereoTypeCB -> setDuplicatesEnabled(false);//only allow one of each type in box
+ m_pStereoTypeCB->setCompletionMode( KGlobalSettings::CompletionPopup );
+ insertStereotype (QString("")); // an empty stereotype is the default
+ int defaultStereotype=0;
+ bool foundDefaultStereotype = false;
+ for (UMLStereotypeListIt it(m_pUmldoc->getStereotypes()); it.current(); ++it) {
+ if (!foundDefaultStereotype) {
+ if ( m_pObject->getStereotype() == it.current()->getName()) {
+ foundDefaultStereotype = true;
+ }
+ defaultStereotype++;
+ }
+ insertStereotype (it.current()->getName());
+ }
+ // lookup for a default stereotype, if the operation doesn't have one
+ if (foundDefaultStereotype)
+ m_pStereoTypeCB -> setCurrentItem(defaultStereotype);
+ else
+ m_pStereoTypeCB -> setCurrentItem(-1);
+
+ ///////////
+ m_pDoc->setWordWrap(QMultiLineEdit::WidgetWidth);
+ //////////
+}
+
+ClassGenPage::ClassGenPage(UMLDoc* d, QWidget* parent, ObjectWidget* o) : QWidget(parent) {
+ m_pObject = 0;
+ m_pInstanceWidget = 0;
+ m_pWidget = o;
+ m_pDeconCB = 0;
+ m_pMultiCB = 0;
+ int margin = fontMetrics().height();
+ //int t = o -> getBaseType();
+ m_pUmldoc = d;
+ setMinimumSize(310,330);
+ QGridLayout * topLayout = new QGridLayout(this, 2, 1);
+ topLayout -> setSpacing(6);
+
+ //setup name
+ QGridLayout * m_pNameLayout = new QGridLayout(topLayout, 3, 2);
+ m_pNameLayout -> setSpacing(6);
+ m_pNameL = new QLabel(this);
+ m_pNameL -> setText(i18n("Class name:"));
+ m_pNameLayout -> addWidget(m_pNameL, 0, 0);
+
+ m_pClassNameLE = new QLineEdit(this);
+ m_pClassNameLE -> setText(o -> getName());
+ m_pNameLayout -> addWidget(m_pClassNameLE, 0, 1);
+
+ m_pInstanceL = new QLabel(this);
+ m_pInstanceL -> setText(i18n("Instance name:"));
+ m_pNameLayout -> addWidget(m_pInstanceL, 1, 0);
+
+ m_pInstanceLE = new QLineEdit(this);
+ m_pInstanceLE -> setText(o -> getInstanceName());
+ m_pNameLayout -> addWidget(m_pInstanceLE, 1, 1);
+ UMLView *view = UMLApp::app()->getCurrentView();
+
+ m_pDrawActorCB = new QCheckBox( i18n( "Draw as actor" ) , this );
+ m_pDrawActorCB -> setChecked( o -> getDrawAsActor() );
+ m_pNameLayout -> addWidget( m_pDrawActorCB, 2, 0 );
+
+ if(view -> getType() == Uml::dt_Collaboration) {
+ m_pMultiCB = new QCheckBox(i18n("Multiple instance"), this);
+ m_pMultiCB -> setChecked(o -> getMultipleInstance());
+ m_pNameLayout -> addWidget(m_pMultiCB, 2,1);
+ if( m_pDrawActorCB -> isChecked() )
+ m_pMultiCB -> setEnabled( false );
+ } else//sequence diagram
+ {
+ m_pDeconCB = new QCheckBox(i18n("Show destruction"), this);
+ m_pDeconCB->setChecked(o->getShowDestruction());
+ m_pNameLayout -> addWidget(m_pDeconCB, 2,1);
+ }
+ //setup documentation
+ m_pDocGB = new QGroupBox(this);
+ topLayout -> addWidget(m_pDocGB, 1, 0);
+ QHBoxLayout * docLayout = new QHBoxLayout(m_pDocGB);
+ docLayout -> setMargin(margin);
+ m_pDocGB -> setTitle(i18n("Documentation"));
+
+ m_pDoc = new QMultiLineEdit(m_pDocGB);
+ m_pDoc->setWordWrap(QMultiLineEdit::WidgetWidth);
+ m_pDoc-> setText(o -> getDoc());
+ docLayout -> addWidget(m_pDoc);
+ m_pObject = 0;//needs to be set to zero
+ if( m_pMultiCB )
+ connect( m_pDrawActorCB, SIGNAL( toggled( bool ) ), this, SLOT( slotActorToggled( bool ) ) );
+}
+
+ClassGenPage::ClassGenPage(UMLDoc* d, QWidget* parent, UMLWidget* widget) : QWidget(parent) {
+ m_pWidget = 0;
+ m_pObject = 0;
+ m_pInstanceWidget = widget;
+ m_pDeconCB = 0;
+ m_pMultiCB = 0;
+ int margin = fontMetrics().height();
+ //int t = o -> getBaseType();
+ m_pUmldoc = d;
+ setMinimumSize(310,330);
+ QGridLayout* topLayout = new QGridLayout(this, 2, 1);
+ topLayout->setSpacing(6);
+
+ //setup name
+ QGridLayout* m_pNameLayout = new QGridLayout(topLayout, 3, 2);
+ m_pNameLayout->setSpacing(6);
+ m_pNameL = new QLabel(this);
+ if (widget->getBaseType() == Uml::wt_Component) {
+ m_pNameL->setText(i18n("Component name:"));
+ } else if (widget->getBaseType() == Uml::wt_Node) {
+ m_pNameL->setText(i18n("Node name:"));
+ } else {
+ kWarning() << "ClassGenPage called on unknown widget type" << endl;
+ }
+ m_pNameLayout->addWidget(m_pNameL, 0, 0);
+
+ m_pClassNameLE = new QLineEdit(this);
+ m_pClassNameLE->setText(widget->getName());
+ m_pNameLayout->addWidget(m_pClassNameLE, 0, 1);
+
+ m_pStereoTypeL = new QLabel(i18n("Stereotype name:"), this);
+ m_pNameLayout->addWidget(m_pStereoTypeL, 1, 0);
+
+ m_pStereoTypeCB = new KComboBox(true, this);
+ m_pNameLayout->addWidget(m_pStereoTypeCB, 1, 1);
+
+ m_pStereoTypeCB->setCurrentText( widget->getUMLObject()->getStereotype() );
+ m_pStereoTypeCB->setCompletionMode( KGlobalSettings::CompletionPopup );
+
+ m_pInstanceL = new QLabel(this);
+ m_pInstanceL->setText(i18n("Instance name:"));
+ m_pNameLayout->addWidget(m_pInstanceL, 2, 0);
+
+ m_pInstanceLE = new QLineEdit(this);
+ m_pInstanceLE->setText(widget->getInstanceName());
+ m_pNameLayout->addWidget(m_pInstanceLE, 2, 1);
+
+ //setup documentation
+ m_pDocGB = new QGroupBox(this);
+ topLayout->addWidget(m_pDocGB, 1, 0);
+ QHBoxLayout* docLayout = new QHBoxLayout(m_pDocGB);
+ docLayout->setMargin(margin);
+ m_pDocGB->setTitle(i18n("Documentation"));
+
+ m_pDoc = new QMultiLineEdit(m_pDocGB);
+ m_pDoc->setWordWrap(QMultiLineEdit::WidgetWidth);
+ m_pDoc->setText(widget->getDoc());
+ docLayout->addWidget(m_pDoc);
+ m_pObject = 0;//needs to be set to zero
+}
+
+ClassGenPage::~ClassGenPage() {}
+
+void ClassGenPage::insertStereotype( const QString& type, int index )
+{
+ m_pStereoTypeCB->insertItem( type, index );
+ m_pStereoTypeCB->completionObject()->addItem( type );
+}
+
+void ClassGenPage::updateObject() {
+ if(m_pObject) {
+ QString name = m_pClassNameLE -> text();
+
+ m_pObject -> setDoc(m_pDoc -> text());
+
+ if(m_pStereoTypeCB)
+ m_pObject -> setStereotype(m_pStereoTypeCB->currentText());
+ /**
+ * @todo enable the package lineedit field amd add logic for changing the package
+ if(m_pPackageLE)
+ m_pObject -> setPackage(m_pPackageLE -> text());
+ */
+
+ if ( m_pObject->getUMLPackage() == NULL ) {
+ kDebug() << k_funcinfo << "Parent package not set, setting it to Logical View folder"<<endl;
+ UMLFolder* folder = m_pUmldoc->getRootFolder( Uml::mt_Logical );
+ m_pObject->setUMLPackage( ( UMLPackage* )folder );
+ }
+
+ if( m_pAbstractCB )
+ m_pObject -> setAbstract( m_pAbstractCB -> isChecked() );
+ //make sure unique name
+ UMLObject *o = m_pUmldoc -> findUMLObject(name);
+ if(o && m_pObject != o) {
+ KMessageBox::sorry(this, i18n("The name you have chosen\nis already being used.\nThe name has been reset."),
+ i18n("Name is Not Unique"), false);
+ m_pClassNameLE -> setText( m_pObject -> getName() );
+ } else
+ m_pObject -> setName(name);
+ Uml::Visibility s;
+ if(m_pPublicRB -> isChecked())
+ s = Uml::Visibility::Public;
+ else if(m_pPrivateRB -> isChecked())
+ s = Uml::Visibility::Private;
+ else if(m_pProtectedRB->isChecked())
+ s = Uml::Visibility::Protected;
+ else
+ s = Uml::Visibility::Implementation;
+ m_pObject -> setVisibility(s);
+
+ if (m_pObject->getBaseType() == Uml::ot_Component) {
+ (static_cast<UMLComponent*>(m_pObject))->setExecutable( m_pExecutableCB->isChecked() );
+ }
+
+ if (m_pObject->getBaseType() == Uml::ot_Artifact) {
+ UMLArtifact::Draw_Type drawAsType;
+ if ( m_pFileRB->isChecked() ) {
+ drawAsType = UMLArtifact::file;
+ } else if ( m_pLibraryRB->isChecked() ) {
+ drawAsType = UMLArtifact::library;
+ } else if (m_pTableRB->isChecked() ) {
+ drawAsType = UMLArtifact::table;
+ } else {
+ drawAsType = UMLArtifact::defaultDraw;
+ }
+ (static_cast<UMLArtifact*>(m_pObject))->setDrawAsType(drawAsType);
+ }
+
+ }//end if m_pObject
+ else if(m_pWidget) {
+ m_pWidget -> setInstanceName(m_pInstanceLE -> text());
+ if(m_pMultiCB)
+ m_pWidget -> setMultipleInstance(m_pMultiCB -> isChecked());
+ m_pWidget -> setDrawAsActor( m_pDrawActorCB -> isChecked() );
+ if( m_pDeconCB )
+ m_pWidget -> setShowDestruction( m_pDeconCB -> isChecked() );
+ QString name = m_pClassNameLE -> text();
+ m_pWidget -> setDoc(m_pDoc -> text());
+ UMLObject * o = m_pWidget -> getUMLObject();
+ UMLObject * old = m_pUmldoc -> findUMLObject(name);
+ if(old && o != old) {
+ KMessageBox::sorry(this, i18n("The name you have chosen\nis already being used.\nThe name has been reset."),
+ i18n("Name is Not Unique"), false);
+ } else
+ o -> setName(name);
+ } else if (m_pInstanceWidget) {
+ m_pInstanceWidget->setInstanceName(m_pInstanceLE->text());
+ QString name = m_pClassNameLE->text();
+ m_pInstanceWidget->setDoc(m_pDoc->text());
+ UMLObject* o = m_pInstanceWidget->getUMLObject();
+ UMLObject* old = m_pUmldoc->findUMLObject(name);
+ if(old && o != old) {
+ KMessageBox::sorry(this, i18n("The name you have chosen\nis already being used.\nThe name has been reset."),
+ i18n("Name is Not Unique"), false);
+ } else {
+ o->setName(name);
+ }
+ o->setStereotype( m_pStereoTypeCB->currentText() );
+ }
+}
+
+void ClassGenPage::slotActorToggled( bool state ) {
+ if( m_pMultiCB )
+ m_pMultiCB -> setEnabled( !state );
+}
+
+
+
+#include "classgenpage.moc"
diff --git a/umbrello/umbrello/dialogs/classgenpage.h b/umbrello/umbrello/dialogs/classgenpage.h
new file mode 100644
index 00000000..6fd0f7d3
--- /dev/null
+++ b/umbrello/umbrello/dialogs/classgenpage.h
@@ -0,0 +1,109 @@
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * copyright (C) 2002-2006 *
+ * Umbrello UML Modeller Authors <uml-devel@uml.sf.net> *
+ ***************************************************************************/
+
+#ifndef CLASSGENPAGE_H
+#define CLASSGENPAGE_H
+
+#include <qwidget.h>
+
+class QGroupBox;
+class QLabel;
+class QLineEdit;
+class QButtonGroup;
+class QMultiLineEdit;
+class QRadioButton;
+class QCheckBox;
+class KComboBox;
+
+class UMLObject;
+class UMLWidget;
+class ObjectWidget;
+class UMLDoc;
+
+/**
+ * Displays properties of a UMLObject in a dialog box. This is not usually directly
+ * called. The class @ref ClassPropDlg will set this up for you.
+ *
+ * @short Display properties on a UMLObject.
+ * @author Paul Hensgen <phensgen@techie.com>
+ * Bugs and comments to uml-devel@lists.sf.net or http://bugs.kde.org
+ */
+class ClassGenPage : public QWidget {
+ Q_OBJECT
+public:
+
+ /**
+ * Sets up the ClassGenPage.
+ *
+ * @param d The UMLDoc which controls controls object creation.
+ * @param parent The parent to the ClassGenPage.
+ * @param o The UMLObject to display the properties of.
+ */
+ ClassGenPage(UMLDoc *d, QWidget *parent, UMLObject * o);
+
+ /**
+ * Sets up the ClassGenPage for an ObjectWidget
+ *
+ * @param d The UMLDoc which controls controls object creation.
+ * @param parent The parent to the ClassGenPage.
+ * @param o The ObjectWidget to display the properties of.
+ */
+ ClassGenPage(UMLDoc *d, QWidget *parent, ObjectWidget * o);
+
+ /**
+ * Sets up the ClassGenPage for a UMLWidget instance (used
+ * for component instances on deployment diagrams)
+ *
+ * @param d The UMLDoc which controls controls object creation.
+ * @param parent The parent to the ClassGenPage.
+ * @param widget The UMLWidget to display the properties of.
+ */
+ ClassGenPage(UMLDoc* d, QWidget* parent, UMLWidget* widget);
+
+ /**
+ * Standard deconstructor.
+ */
+ ~ClassGenPage();
+
+ /**
+ * Will move information from the dialog into the object.
+ * Call when the ok or apply button is pressed.
+ */
+ void updateObject();
+private:
+ QGroupBox *m_pDocGB;
+ QButtonGroup * m_pButtonBG;
+ QLabel * m_pNameL, * m_pInstanceL, * m_pStereoTypeL, * m_pPackageL;
+ QLineEdit * m_pClassNameLE, *m_pInstanceLE, * m_pPackageLE;
+ KComboBox * m_pStereoTypeCB;
+ QRadioButton *m_pPublicRB, *m_pPrivateRB, *m_pProtectedRB, *m_pImplementationRB;
+ QCheckBox * m_pMultiCB, * m_pDrawActorCB, * m_pAbstractCB, * m_pDeconCB;
+ QMultiLineEdit * m_pDoc;
+ UMLObject * m_pObject;
+ UMLDoc * m_pUmldoc;
+ ObjectWidget * m_pWidget;
+ UMLWidget* m_pInstanceWidget;
+ QButtonGroup* m_pDrawAsBG;
+ QRadioButton* m_pDefaultRB,* m_pFileRB,* m_pLibraryRB,* m_pTableRB;
+ QCheckBox* m_pExecutableCB;
+
+ void insertStereotype(const QString& type, int index = -1);
+
+public slots:
+ /**
+ * When the draw as actor check box is toggled, the draw
+ * as multi instance need to be enabled/disabled. They
+ * both can't be available at the same time.
+ */
+ void slotActorToggled( bool state );
+};
+
+#endif
diff --git a/umbrello/umbrello/dialogs/classifierlistpage.cpp b/umbrello/umbrello/dialogs/classifierlistpage.cpp
new file mode 100644
index 00000000..d7148660
--- /dev/null
+++ b/umbrello/umbrello/dialogs/classifierlistpage.cpp
@@ -0,0 +1,607 @@
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * copyright (C) 2003-2006 *
+ * Umbrello UML Modeller Authors <uml-devel@uml.sf.net> *
+ ***************************************************************************/
+
+#include "classifierlistpage.h"
+#include "../classifierlistitem.h"
+#include "../umldoc.h"
+#include "../classifier.h"
+#include "../enum.h"
+#include "../entity.h"
+#include "../attribute.h"
+#include "../operation.h"
+#include "../template.h"
+#include "../enumliteral.h"
+#include "../entityattribute.h"
+#include "../object_factory.h"
+#include <kapplication.h>
+#include <kbuttonbox.h>
+#include <kdebug.h>
+#include <klocale.h>
+#include <qlayout.h>
+
+using namespace Uml;
+
+ClassifierListPage::ClassifierListPage(QWidget* parent, UMLClassifier* classifier,
+ UMLDoc* doc, Uml::Object_Type type) : QWidget(parent) {
+ m_itemType = type;
+ QString typeName("");
+ QString newItemType("");
+ if (type == ot_Attribute) {
+ typeName = i18n("Attributes");
+ newItemType = i18n("N&ew Attribute...");
+ } else if (type == ot_Operation) {
+ typeName = i18n("Operations");
+ newItemType = i18n("N&ew Operation...");
+ } else if (type == ot_Template) {
+ typeName = i18n("Templates");
+ newItemType = i18n("N&ew Template...");
+ } else if (type == ot_EnumLiteral) {
+ typeName = i18n("Enum Literals");
+ newItemType = i18n("N&ew Enum Literal...");
+ } else if (type == ot_EntityAttribute) {
+ typeName = i18n("Entity Attributes");
+ newItemType = i18n("N&ew Entity Attribute...");
+ } else {
+ kWarning() << "unknown listItem type in ClassifierListPage" << endl;
+ }
+
+ m_bSigWaiting = false;
+ m_pDoc = doc;
+ m_pClassifier = classifier;
+ m_pMenu = 0;
+ int margin = fontMetrics().height();
+ setMinimumSize(310,330);
+
+ //main layout contains our two group boxes, the list and the documentation
+ QVBoxLayout* mainLayout = new QVBoxLayout( this );
+ mainLayout->setSpacing(10);
+
+ //top group box, contains a vertical layout with list box above and buttons below
+ m_pItemListGB = new QGroupBox(typeName, this );
+ QVBoxLayout* listVBoxLayout = new QVBoxLayout( m_pItemListGB );
+ listVBoxLayout->setMargin(margin);
+ listVBoxLayout->setSpacing ( 10 );
+
+ //horizontal box contains the list box and the move up/down buttons
+ QHBoxLayout* listHBoxLayout = new QHBoxLayout( listVBoxLayout );
+ m_pItemListLB = new QListBox(m_pItemListGB);
+ listHBoxLayout->addWidget(m_pItemListLB);
+
+ //the move up/down buttons (another vertical box)
+ QVBoxLayout* buttonLayout = new QVBoxLayout( listHBoxLayout );
+ m_pTopArrowB = new KArrowButton( m_pItemListGB );
+ m_pTopArrowB->setEnabled( false );
+ buttonLayout->addWidget( m_pTopArrowB );
+
+ m_pUpArrowB = new KArrowButton( m_pItemListGB );
+ m_pUpArrowB->setEnabled( false );
+ buttonLayout->addWidget( m_pUpArrowB );
+
+ m_pDownArrowB = new KArrowButton( m_pItemListGB, Qt::DownArrow );
+ m_pDownArrowB->setEnabled( false );
+ buttonLayout->addWidget( m_pDownArrowB );
+
+ m_pBottomArrowB = new KArrowButton( m_pItemListGB, Qt::DownArrow );
+ m_pBottomArrowB->setEnabled( false );
+ buttonLayout->addWidget( m_pBottomArrowB );
+
+ //the action buttons
+ KButtonBox* buttonBox = new KButtonBox(m_pItemListGB);
+ buttonBox->addButton( newItemType, this, SLOT(slotNewListItem()) );
+ m_pDeleteListItemButton = buttonBox->addButton( i18n("&Delete"),
+ this, SLOT(slotDelete()) );
+ m_pPropertiesButton = buttonBox->addButton( i18n("&Properties"), this, SLOT(slotProperties()) );
+ listVBoxLayout->addWidget(buttonBox);
+
+ mainLayout->addWidget(m_pItemListGB);
+
+ m_pDocGB = new QGroupBox(i18n("Documentation"), this);
+ QVBoxLayout* docLayout = new QVBoxLayout( m_pDocGB );
+ m_pDocTE = new QTextEdit( m_pDocGB );
+ docLayout->setMargin(margin);
+ docLayout->setSpacing ( 10 );
+ docLayout->addWidget( m_pDocTE );
+ mainLayout->addWidget(m_pDocGB);
+
+ UMLClassifierListItemList itemList(getItemList());
+
+ // add each item in the list to the ListBox and connect each item modified signal
+ // to the ListItemModified slot in this class
+ for (UMLClassifierListItem* listItem = itemList.first(); listItem != 0; listItem = itemList.next() ) {
+ m_pItemListLB->insertItem(listItem->toString(Uml::st_SigNoVis));
+ connect( listItem, SIGNAL(modified()),this,SLOT(slotListItemModified()) );
+ }
+
+ enableWidgets(false);//disable widgets until an att is chosen
+ m_pOldListItem = 0;
+ connect(m_pItemListLB, SIGNAL(clicked(QListBoxItem*)), this, SLOT(slotClicked(QListBoxItem*)));
+ connect(m_pItemListLB, SIGNAL(selectionChanged(QListBoxItem*)), this, SLOT(slotClicked(QListBoxItem*)));
+
+ connect(m_pItemListLB, SIGNAL(rightButtonPressed(QListBoxItem*, const QPoint&)),
+ this, SLOT(slotRightButtonPressed(QListBoxItem*, const QPoint&)));
+
+ connect(m_pItemListLB, SIGNAL(rightButtonClicked(QListBoxItem*, const QPoint&)),
+ this, SLOT(slotRightButtonClicked(QListBoxItem*, const QPoint&)));
+ connect(m_pDoc, SIGNAL(sigObjectCreated(UMLObject*)), this, SLOT(slotListItemCreated(UMLObject*)));
+
+ connect( m_pTopArrowB, SIGNAL( clicked() ), this, SLOT( slotTopClicked() ) );
+ connect( m_pUpArrowB, SIGNAL( clicked() ), this, SLOT( slotUpClicked() ) );
+ connect( m_pDownArrowB, SIGNAL( clicked() ), this, SLOT( slotDownClicked() ) );
+ connect( m_pBottomArrowB, SIGNAL( clicked() ), this, SLOT( slotBottomClicked() ) );
+ connect( m_pItemListLB, SIGNAL( doubleClicked( QListBoxItem* ) ),
+ this, SLOT( slotDoubleClick( QListBoxItem* ) ) );
+}
+
+ClassifierListPage::~ClassifierListPage() {
+
+}
+
+void ClassifierListPage::enableWidgets(bool state) {
+ m_pDocTE->setEnabled( state );
+ //if disabled clear contents
+ if( !state ) {
+ m_pDocTE->setText( "" );
+ m_pTopArrowB->setEnabled( false );
+ m_pUpArrowB->setEnabled( false );
+ m_pDownArrowB->setEnabled( false );
+ m_pBottomArrowB->setEnabled( false );
+ m_pDeleteListItemButton->setEnabled(false);
+ m_pPropertiesButton->setEnabled(false);
+ return;
+ }
+ /*now check the order buttons.
+ Double check an item is selected
+ If only one item in list make sure they are disabled.
+ If at top item, only allow down arrow to be enabled.
+ If at bottom item, only allow up arrow to be enabled.
+ */
+ int index = m_pItemListLB->currentItem();
+ if( m_pItemListLB->count() == 1 || index == -1 ) {
+ m_pTopArrowB->setEnabled( false );
+ m_pUpArrowB->setEnabled( false );
+ m_pDownArrowB->setEnabled( false );
+ m_pBottomArrowB->setEnabled( false );
+ } else if( index == 0 ) {
+ m_pTopArrowB->setEnabled( false );
+ m_pUpArrowB->setEnabled( false );
+ m_pDownArrowB->setEnabled( true );
+ m_pBottomArrowB->setEnabled( true );
+ } else if( index == (int)m_pItemListLB->count() - 1 ) {
+ m_pTopArrowB->setEnabled( true );
+ m_pUpArrowB->setEnabled( true );
+ m_pDownArrowB->setEnabled( false );
+ m_pBottomArrowB->setEnabled( false );
+ } else {
+ m_pTopArrowB->setEnabled( true );
+ m_pUpArrowB->setEnabled( true );
+ m_pDownArrowB->setEnabled( true );
+ m_pBottomArrowB->setEnabled( true );
+ }
+ m_pDeleteListItemButton->setEnabled(true);
+ m_pPropertiesButton->setEnabled(true);
+}
+
+void ClassifierListPage::slotClicked(QListBoxItem*item) {
+ //if not first time an item is highlighted
+ //save old highlighted item first
+ if(m_pOldListItem) {
+ m_pOldListItem->setDoc( m_pDocTE->text() );
+ }
+
+ // make sure clicked on an item
+ // it is impossible to deselect all items, because our list box has keyboard
+ // focus and so at least one item is always selected; this doesn't happen, if
+ // there are no items of course;
+ //
+ // for more information see Qt doc for void QListBox::clearSelection()
+ UMLClassifierListItem* listItem;
+ if (item == NULL) {
+ if (m_pItemListLB->count() == 0) {
+ enableWidgets(false);
+ m_pOldListItem = 0;
+ m_pItemListLB->clearSelection();
+ return;
+ }
+ m_pItemListLB->setSelected(0, true);
+ listItem = getItemList().at(0);
+ } else {
+ listItem = getItemList().at( m_pItemListLB->index(item) );
+ }
+
+ if (listItem) {
+ //now update screen
+ m_pDocTE->setText( listItem->getDoc() );
+ enableWidgets(true);
+ m_pOldListItem = listItem;
+ }
+}
+
+void ClassifierListPage::updateObject() {
+ saveCurrentItemDocumentation();
+ QListBoxItem*i = m_pItemListLB->item(m_pItemListLB->currentItem());
+ slotClicked(i);
+
+ // The rest of this function does nothing?!
+ QStringList stringList;
+ int count = m_pItemListLB->count();
+ for( int j = 0; j < count ; j++ )
+ stringList.append( m_pItemListLB->text( j ) );
+}
+
+void ClassifierListPage::slotListItemCreated(UMLObject* object) {
+ if(!m_bSigWaiting) {
+ return;
+ }
+ UMLClassifierListItem *listItem = dynamic_cast<UMLClassifierListItem*>(object);
+ if (listItem == NULL) {
+ return;
+ }
+ int index = m_pItemListLB->count();
+ m_pItemListLB->insertItem(listItem->toString(Uml::st_SigNoVis), index);
+ m_bSigWaiting = false;
+
+ // now select the new item, so that the user can go on adding doc or calling
+ // the property dialog
+ m_pItemListLB->setSelected(index, true);
+ slotClicked(m_pItemListLB->item(index));
+}
+
+void ClassifierListPage::slotListItemModified() {
+ if(!m_bSigWaiting) {
+ return;
+ }
+ //is this safe???
+ UMLClassifierListItem* object = const_cast<UMLClassifierListItem*>(dynamic_cast<const UMLClassifierListItem*>(sender()));
+ if (object == NULL)
+ return;
+ int index = m_pItemListLB->currentItem();
+ m_pItemListLB->changeItem(object->toString(Uml::st_SigNoVis), index);
+ m_bSigWaiting = false;
+}
+
+void ClassifierListPage::slotRightButtonClicked(QListBoxItem* /*item*/, const QPoint& /* p*/) {
+ if (m_pMenu) {
+ m_pMenu->hide();
+ disconnect(m_pMenu, SIGNAL(activated(int)), this, SLOT(slotPopupMenuSel(int)));
+ delete m_pMenu;
+ m_pMenu = 0;
+ }
+}
+
+void ClassifierListPage::slotRightButtonPressed(QListBoxItem* item, const QPoint& p) {
+ ListPopupMenu::Menu_Type type = ListPopupMenu::mt_Undefined;
+ if (item) { //pressed on a list item
+ if (m_itemType == ot_Attribute) {
+ type = ListPopupMenu::mt_Attribute_Selected;
+ } else if (m_itemType == ot_Operation) {
+ type = ListPopupMenu::mt_Operation_Selected;
+ } else if (m_itemType == ot_Template) {
+ type = ListPopupMenu::mt_Template_Selected;
+ } else if (m_itemType == ot_EnumLiteral) {
+ type = ListPopupMenu::mt_EnumLiteral_Selected;
+ } else if (m_itemType == ot_EntityAttribute) {
+ type = ListPopupMenu::mt_EntityAttribute_Selected;
+ } else {
+ kWarning() << "unknown type in ClassifierListPage" << endl;
+ }
+ } else { //pressed into fresh air
+ if (m_itemType == ot_Attribute) {
+ type = ListPopupMenu::mt_New_Attribute;
+ } else if (m_itemType == ot_Operation) {
+ type = ListPopupMenu::mt_New_Operation;
+ } else if (m_itemType == ot_Template) {
+ type = ListPopupMenu::mt_New_Template;
+ } else if (m_itemType == ot_EnumLiteral) {
+ type = ListPopupMenu::mt_New_EnumLiteral;
+ } else if (m_itemType == ot_EntityAttribute) {
+ type = ListPopupMenu::mt_New_EntityAttribute;
+ } else {
+ kWarning() << "unknown type in ClassifierListPage" << endl;
+ }
+ }
+ if(m_pMenu) {
+ m_pMenu->hide();
+ disconnect(m_pMenu, SIGNAL(activated(int)), this, SLOT(slotPopupMenuSel(int)));
+ delete m_pMenu;
+ m_pMenu = 0;
+ }
+ m_pMenu = new ListPopupMenu(this, type);
+
+ m_pMenu->popup(p);
+ connect(m_pMenu, SIGNAL(activated(int)), this, SLOT(slotPopupMenuSel(int)));
+}
+
+void ClassifierListPage::slotPopupMenuSel(int id) {
+ UMLClassifierListItem* listItem = getItemList().at( m_pItemListLB->currentItem() );
+ if(!listItem && id != ListPopupMenu::mt_New_Attribute) {
+ kDebug() << "can't find att from selection" << endl;
+ return;
+ }
+ switch(id) {
+ case ListPopupMenu::mt_New_Attribute:
+ case ListPopupMenu::mt_New_Operation:
+ case ListPopupMenu::mt_New_Template:
+ case ListPopupMenu::mt_New_EnumLiteral:
+ case ListPopupMenu::mt_New_EntityAttribute:
+ slotNewListItem();
+ break;
+
+ case ListPopupMenu::mt_Delete:
+ slotDelete();
+ break;
+
+ case ListPopupMenu::mt_Rename:
+ m_bSigWaiting = true;
+ m_pDoc->renameChildUMLObject(listItem);
+ break;
+
+ case ListPopupMenu::mt_Properties:
+ slotProperties();
+ break;
+ }
+}
+
+void ClassifierListPage::printItemList(QString prologue) {
+#ifdef VERBOSE_DEBUGGING
+ UMLClassifierListItem* item;
+ QString buf;
+ UMLClassifierListItemList itemList = getItemList();
+ for (UMLClassifierListItemListIt it(itemList); (item = it.current()) != NULL; ++it)
+ buf.append(' ' + item->getName());
+ kDebug() << prologue << buf << endl;
+#endif
+}
+
+void ClassifierListPage::slotTopClicked() {
+ int count = m_pItemListLB->count();
+ int index = m_pItemListLB->currentItem();
+ //shouldn't occur, but just in case
+ if( count <= 1 || index <= 0 )
+ return;
+ m_pOldListItem = NULL;
+
+ //swap the text around in the ListBox
+ QString currentString = m_pItemListLB->text( index );
+ m_pItemListLB->removeItem( index );
+ m_pItemListLB->insertItem( currentString, 0 );
+ //set the moved item selected
+ QListBoxItem* item = m_pItemListLB->item( 0 );
+ m_pItemListLB->setSelected( item, true );
+
+ //now change around in the list
+ printItemList("itemList before change: ");
+ UMLClassifierListItem* currentAtt = getItemList().at(index);
+ // NB: The index in the m_pItemListLB is not necessarily the same
+ // as the index in the UMLClassifier::m_List.
+ // Reason: getItemList() returns only a subset of all entries
+ // in UMLClassifier::m_List.
+ takeItem(currentAtt, true, index); // now we index the UMLClassifier::m_List
+ kDebug() << "ClassifierListPage::slotTopClicked(" << currentAtt->getName()
+ << "): peer index in UMLCanvasItem::m_List is " << index << endl;
+ addClassifier(currentAtt, 0);
+ printItemList("itemList after change: ");
+ slotClicked(item);
+}
+
+void ClassifierListPage::slotUpClicked() {
+ int count = m_pItemListLB->count();
+ int index = m_pItemListLB->currentItem();
+ //shouldn't occur, but just in case
+ if( count <= 1 || index <= 0 )
+ return;
+ m_pOldListItem = NULL;
+
+ //swap the text around in the ListBox
+ QString aboveString = m_pItemListLB->text( index - 1 );
+ QString currentString = m_pItemListLB->text( index );
+ m_pItemListLB->changeItem( currentString, index -1 );
+ m_pItemListLB->changeItem( aboveString, index );
+ //set the moved item selected
+ QListBoxItem* item = m_pItemListLB->item( index - 1 );
+ m_pItemListLB->setSelected( item, true );
+
+ //now change around in the list
+ printItemList("itemList before change: ");
+ UMLClassifierListItem* currentAtt = getItemList().at(index);
+ // NB: The index in the m_pItemListLB is not necessarily the same
+ // as the index in the UMLClassifier::m_List.
+ // Reason: getItemList() returns only a subset of all entries
+ // in UMLClassifier::m_List.
+ takeItem(currentAtt, true, index); // now we index the UMLClassifier::m_List
+ kDebug() << "ClassifierListPage::slotUpClicked(" << currentAtt->getName()
+ << "): peer index in UMLCanvasItem::m_List is " << index << endl;
+ if (index == -1)
+ index = 0;
+ addClassifier(currentAtt, index);
+ printItemList("itemList after change: ");
+ slotClicked( item );
+}
+
+void ClassifierListPage::slotDownClicked() {
+ int count = m_pItemListLB->count();
+ int index = m_pItemListLB->currentItem();
+ //shouldn't occur, but just in case
+ if( count <= 1 || index >= count - 1 )
+ return;
+ m_pOldListItem = NULL;
+
+ //swap the text around in the ListBox
+ QString belowString = m_pItemListLB->text( index + 1 );
+ QString currentString = m_pItemListLB->text( index );
+ m_pItemListLB->changeItem( currentString, index + 1 );
+ m_pItemListLB->changeItem( belowString, index );
+ //set the moved item selected
+ QListBoxItem* item = m_pItemListLB->item( index + 1 );
+ m_pItemListLB->setSelected( item, true );
+ //now change around in the list
+ printItemList("itemList before change: ");
+ UMLClassifierListItem* currentAtt = getItemList().at(index);
+ // NB: The index in the m_pItemListLB is not necessarily the same
+ // as the index in the UMLClassifier::m_List.
+ // Reason: getItemList() returns only a subset of all entries
+ // in UMLClassifier::m_List.
+ takeItem(currentAtt, false, index); // now we index the UMLClassifier::m_List
+ kDebug() << "ClassifierListPage::slotDownClicked(" << currentAtt->getName()
+ << "): peer index in UMLCanvasItem::m_List is " << index << endl;
+ if (index != -1)
+ index++; // because we want to go _after_ the following peer item
+ addClassifier(currentAtt, index);
+ printItemList("itemList after change: ");
+ slotClicked( item );
+}
+
+void ClassifierListPage::slotBottomClicked() {
+ int count = m_pItemListLB->count();
+ int index = m_pItemListLB->currentItem();
+ //shouldn't occur, but just in case
+ if( count <= 1 || index >= count - 1 )
+ return;
+ m_pOldListItem = NULL;
+
+ //swap the text around in the ListBox
+ QString currentString = m_pItemListLB->text( index );
+ m_pItemListLB->removeItem( index );
+ m_pItemListLB->insertItem( currentString, m_pItemListLB->count() );
+ //set the moved item selected
+ QListBoxItem* item = m_pItemListLB->item( m_pItemListLB->count() - 1 );
+ m_pItemListLB->setSelected( item, true );
+
+ //now change around in the list
+ printItemList("itemList before change: ");
+ UMLClassifierListItem* currentAtt = getItemList().at(index);
+ // NB: The index in the m_pItemListLB is not necessarily the same
+ // as the index in the UMLClassifier::m_List.
+ // Reason: getItemList() returns only a subset of all entries
+ // in UMLClassifier::m_List.
+ takeItem(currentAtt, false, index); // now we index the UMLClassifier::m_List
+ kDebug() << "ClassifierListPage::slotDownClicked(" << currentAtt->getName()
+ << "): peer index in UMLCanvasItem::m_List is " << index << endl;
+ addClassifier(currentAtt, getItemList().count());
+ printItemList("itemList after change: ");
+ slotClicked( item );
+}
+
+void ClassifierListPage::slotDoubleClick( QListBoxItem* item ) {
+ if( !item )
+ return;
+
+ UMLClassifierListItem* listItem = getItemList().at( m_pItemListLB->index( item ) );
+ if( !listItem ) {
+ kDebug() << "can't find att from selection" << endl;
+ return;
+ }
+
+ if( listItem->showPropertiesDialog(this) ) {
+ m_pItemListLB->changeItem( listItem->toString(Uml::st_SigNoVis), m_pItemListLB->index(item) );
+ }
+}
+
+void ClassifierListPage::slotDelete() {
+ UMLClassifierListItem* selectedItem = getItemList().at( m_pItemListLB->currentItem() );
+ //should really wait for signal back
+ //but really shouldn't matter
+ m_pDoc->removeUMLObject(selectedItem);
+ m_pItemListLB->removeItem( m_pItemListLB->currentItem());
+ m_pOldListItem = 0;
+ slotClicked(0);
+}
+
+void ClassifierListPage::slotProperties() {
+ saveCurrentItemDocumentation();
+ slotDoubleClick( m_pItemListLB->item( m_pItemListLB->currentItem() ) );
+}
+
+void ClassifierListPage::slotNewListItem() {
+ saveCurrentItemDocumentation();
+ m_bSigWaiting = true;
+ Object_Factory::createChildObject(m_pClassifier, m_itemType);
+}
+
+void ClassifierListPage::saveCurrentItemDocumentation() {
+ UMLClassifierListItem* selectedItem = getItemList().at( m_pItemListLB->currentItem() );
+ if (selectedItem) {
+ selectedItem->setDoc( m_pDocTE->text() );
+ }
+}
+
+UMLClassifierListItemList ClassifierListPage::getItemList() {
+ return m_pClassifier->getFilteredList(m_itemType);
+}
+
+bool ClassifierListPage::addClassifier(UMLClassifierListItem* listitem, int position) {
+ switch (m_itemType) {
+ case ot_Attribute: {
+ UMLAttribute *att = dynamic_cast<UMLAttribute*>(listitem);
+ return m_pClassifier->addAttribute(att, NULL, position);
+ }
+ case ot_Operation: {
+ UMLOperation *op = dynamic_cast<UMLOperation*>(listitem);
+ return m_pClassifier->addOperation(op, position);
+ }
+ case ot_Template: {
+ UMLTemplate* t = dynamic_cast<UMLTemplate*>(listitem);
+ return m_pClassifier->addTemplate(t, position);
+ }
+ case ot_EnumLiteral: {
+ UMLEnum* c = dynamic_cast<UMLEnum*>(m_pClassifier);
+ if (c) {
+ return c->addEnumLiteral(dynamic_cast<UMLEnumLiteral*>(listitem), position);
+ }
+ break;
+ }
+ case ot_EntityAttribute: {
+ UMLEntity* c = dynamic_cast<UMLEntity*>(m_pClassifier);
+ if (c) {
+ return c->addEntityAttribute(dynamic_cast<UMLEntityAttribute*>(listitem), position);
+ }
+ break;
+ }
+ default: {
+ kWarning() << "unknown type in ClassifierListPage" << endl;
+ return false;
+ }
+ }
+ kError() << "ClassifierListPage::addClassifier unable to handle listitem type in current state" << endl;
+ return false;
+}
+
+bool ClassifierListPage::takeItem(UMLClassifierListItem* listItem,
+ bool seekPeerBefore, int &peerIndex) {
+ int wasAtIndex = m_pClassifier->takeItem(listItem);
+ if (wasAtIndex == -1)
+ return false;
+ kapp->processEvents();
+ peerIndex = -1;
+ UMLObject *o;
+ const Uml::Object_Type seekType = listItem->getBaseType();
+ UMLObjectList listItems = m_pClassifier->subordinates();
+ UMLObjectListIt it(listItems);
+ for (int i = 0; (o = it.current()) != NULL; ++i, ++it) {
+ if (seekPeerBefore) {
+ if (i >= wasAtIndex)
+ break;
+ if (o->getBaseType() == seekType)
+ peerIndex = i;
+ } else { // seekPeerAfter
+ if (i < wasAtIndex)
+ continue;
+ if (o->getBaseType() == seekType) {
+ peerIndex = i;
+ break;
+ }
+ }
+ }
+ return true;
+}
+
+
+#include "classifierlistpage.moc"
+
diff --git a/umbrello/umbrello/dialogs/classifierlistpage.h b/umbrello/umbrello/dialogs/classifierlistpage.h
new file mode 100644
index 00000000..ea1c0b9f
--- /dev/null
+++ b/umbrello/umbrello/dialogs/classifierlistpage.h
@@ -0,0 +1,191 @@
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * copyright (C) 2003-2007 *
+ * Umbrello UML Modeller Authors <uml-devel@uml.sf.net> *
+ ***************************************************************************/
+
+#ifndef CLASSIFIERLISTPAGE_H
+#define CLASSIFIERLISTPAGE_H
+
+//qt includes
+#include <qwidget.h>
+#include <qgroupbox.h>
+#include <qlistbox.h>
+#include <qtextedit.h>
+//kde includes
+#include <karrowbutton.h>
+
+//app includes
+#include "../listpopupmenu.h"
+#include "../umlclassifierlistitemlist.h"
+
+class UMLObject;
+class UMLClassifier;
+class UMLDoc;
+
+/**
+ * A dialog page to display classifier list properties. This is not normally setup
+ * by you. It is used by the @ref ClassPropDlg and new class wizard.
+ *
+ * @short A dialog page to display classifier properties.
+ * @author Paul Hensgen, Jonathan Riddell
+ * Bugs and comments to uml-devel@lists.sf.net or http://bugs.kde.org
+ */
+class ClassifierListPage : public QWidget {
+ Q_OBJECT
+public:
+ /**
+ * Sets up the ClassifierListPage
+ *
+ * @param parent The parent to the ClassAttPage.
+ * @param classifier The Concept to display the properties of.
+ * @param doc The UMLDoc document
+ * @param type The type of listItem this handles
+ */
+ ClassifierListPage(QWidget* parent, UMLClassifier* classifier, UMLDoc* doc, Uml::Object_Type type);
+
+ /**
+ * Standard deconstructor.
+ */
+ ~ClassifierListPage();
+
+ /**
+ * Will move information from the dialog into the object.
+ * Call when the ok or apply button is pressed.
+ */
+ void updateObject();
+
+private:
+ /**
+ * Set the state of the widgets on the page with the given value.
+ *
+ * @param state The state to set the widgets as.
+ */
+ void enableWidgets(bool state);
+
+ /**
+ * Saves the documentation for the currently selected item
+ */
+ void saveCurrentItemDocumentation();
+
+ /**
+ * Get classifiers
+ */
+ UMLClassifierListItemList getItemList();
+
+ /**
+ * Attempts to add classifier to the appropriate list
+ *
+ * @param classifier Pointer to the classifier to add.
+ * @param position Index at which to insert into the list.
+ * @return true if the classifier could be added
+ *
+ */
+ bool addClassifier(UMLClassifierListItem* classifier, int position = -1);
+
+ /**
+ * Take a classifier's subordinate item.
+ * Ownership of the classifier list item is transferred to the caller.
+ * @param listitem UMLClassifierListItem to take.
+ * @param seekPeerBefore True if a peer index should be sought which
+ * is smaller than the current listitem's index.
+ * @param peerIndex Return value: Index in the UMLClassifier's
+ * item list at which a peer item, i.e. another
+ * UMLClassifierListItem of the same type as
+ * listItem, is found. If no such item exists
+ * then return -1.
+ * @return True for success.
+ */
+ bool takeItem(UMLClassifierListItem* listitem,
+ bool seekPeerBefore, int &peerIndex);
+
+ /**
+ * Utility for debugging, prints the current item list.
+ * Only effective if VERBOSE_DEBUGGING is defined.
+ */
+ void printItemList(QString prologue);
+
+ UMLClassifier* m_pClassifier;
+ QGroupBox* m_pDocGB;
+ QGroupBox* m_pItemListGB;
+ QListBox* m_pItemListLB;
+ QTextEdit* m_pDocTE;
+ Uml::Object_Type m_itemType;
+
+ KArrowButton* m_pTopArrowB;
+ KArrowButton* m_pUpArrowB;
+ KArrowButton* m_pDownArrowB;
+ KArrowButton* m_pBottomArrowB;
+ QPushButton* m_pDeleteListItemButton;
+ QPushButton* m_pPropertiesButton;
+
+ UMLClassifierListItem* m_pOldListItem;
+ UMLDoc* m_pDoc;
+ ListPopupMenu* m_pMenu;
+ bool m_bSigWaiting;
+
+public slots:
+ /**
+ * called when list view is clicked on
+ * calls enableWidgets()
+ */
+ void slotClicked(QListBoxItem* item);
+
+ /**
+ * Called when an item is selected in a right click menu
+ */
+ void slotPopupMenuSel(int id);
+
+ void slotListItemCreated(UMLObject* object);
+ void slotListItemModified();
+ void slotRightButtonClicked(QListBoxItem* item, const QPoint& p);
+ void slotRightButtonPressed(QListBoxItem* item, const QPoint& p);
+
+ /**
+ * shows properties dialog for the attribute clicked on
+ */
+ void slotDoubleClick(QListBoxItem* item);
+
+
+ /**
+ * moves selected attribute to the top of the list
+ */
+ void slotTopClicked();
+
+ /**
+ * moves selected attribute up in list
+ */
+ void slotUpClicked();
+
+ /**
+ * moved selected attribute down in list
+ */
+ void slotDownClicked();
+
+ /**
+ * moved selected attribute to the bottom of the list
+ */
+ void slotBottomClicked();
+
+ /**
+ * shows dialog for new attribute
+ */
+ void slotNewListItem();
+
+ /**
+ * removes currently seleted attribute
+ */
+ void slotDelete();
+
+ /**
+ * shows properties dialog for currently selected attribute
+ */
+ void slotProperties();
+};
+
+#endif
diff --git a/umbrello/umbrello/dialogs/classoptionspage.cpp b/umbrello/umbrello/dialogs/classoptionspage.cpp
new file mode 100644
index 00000000..7a54f2dc
--- /dev/null
+++ b/umbrello/umbrello/dialogs/classoptionspage.cpp
@@ -0,0 +1,195 @@
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * copyright (C) 2002-2007 *
+ * Umbrello UML Modeller Authors <uml-devel@uml.sf.net> *
+ ***************************************************************************/
+
+// own header
+#include "classoptionspage.h"
+
+// qt/kde includes
+#include <qlayout.h>
+#include <klocale.h>
+#include <kdebug.h>
+
+// local includes
+#include "../umlview.h"
+#include "../classifierwidget.h"
+
+
+ClassOptionsPage::ClassOptionsPage(QWidget* pParent, ClassifierWidget* pWidget)
+ : QWidget( pParent ) {
+ init();
+ //Uml::Widget_Type type = pWidget->getBaseType();
+ m_pWidget = pWidget;
+ setupPage();
+}
+
+ClassOptionsPage::ClassOptionsPage(QWidget* pParent, Settings::OptionState *options) : QWidget( pParent )
+{
+ init();
+ m_options = options;
+ setupClassPageOption();
+}
+
+void ClassOptionsPage::init() {
+ m_options = NULL;
+ m_pWidget = NULL;
+ m_pShowStereotypeCB = NULL;
+ m_pShowAttsCB = NULL;
+ m_pShowAttSigCB = NULL;
+ m_pDrawAsCircleCB = NULL;
+}
+
+ClassOptionsPage::~ClassOptionsPage() {}
+
+void ClassOptionsPage::setupPage() {
+ int margin = fontMetrics().height();
+
+ bool sig = false;
+ Uml::Signature_Type sigtype;
+
+ QVBoxLayout * topLayout = new QVBoxLayout(this);
+ topLayout -> setSpacing(6);
+ m_pVisibilityGB = new QGroupBox(i18n("Show"), this);
+ topLayout -> addWidget(m_pVisibilityGB);
+ QGridLayout * visibilityLayout = new QGridLayout(m_pVisibilityGB);
+ visibilityLayout -> setSpacing(10);
+ visibilityLayout -> setMargin(margin);
+ visibilityLayout -> setRowStretch(3, 1);
+
+ m_pShowOpsCB = new QCheckBox(i18n("Operatio&ns"), m_pVisibilityGB);
+ m_pShowOpsCB -> setChecked(m_pWidget -> getShowOps());
+ visibilityLayout -> addWidget(m_pShowOpsCB, 0, 0);
+
+ m_pShowVisibilityCB = new QCheckBox(i18n("&Visibility"), m_pVisibilityGB);
+ m_pShowVisibilityCB -> setChecked(m_pWidget -> getShowVisibility());
+ visibilityLayout -> addWidget(m_pShowVisibilityCB, 0, 1);
+
+ sigtype = m_pWidget -> getShowOpSigs();
+ if(sigtype == Uml::st_NoSig || sigtype == Uml::st_NoSigNoVis)
+ sig = false;
+ else
+ sig = true;
+ m_pShowOpSigCB = new QCheckBox(i18n("O&peration signature"), m_pVisibilityGB);
+ m_pShowOpSigCB -> setChecked(sig);
+ visibilityLayout -> addWidget(m_pShowOpSigCB, 1, 0);
+
+ m_pShowPackageCB = new QCheckBox(i18n("Pac&kage"), m_pVisibilityGB);
+ m_pShowPackageCB -> setChecked(m_pWidget -> getShowPackage());
+ visibilityLayout -> addWidget(m_pShowPackageCB, 1, 1);
+
+ Uml::Widget_Type type = m_pWidget->getBaseType();
+
+ if (type == Uml::wt_Class) {
+ m_pShowAttsCB = new QCheckBox(i18n("Att&ributes"), m_pVisibilityGB);
+ m_pShowAttsCB->setChecked(m_pWidget->getShowAtts());
+ visibilityLayout->addWidget(m_pShowAttsCB, 2, 0);
+
+ m_pShowStereotypeCB = new QCheckBox(i18n("Stereot&ype"), m_pVisibilityGB);
+ m_pShowStereotypeCB->setChecked(m_pWidget->getShowStereotype());
+ visibilityLayout->addWidget(m_pShowStereotypeCB, 2, 1);
+
+ m_pShowAttSigCB = new QCheckBox(i18n("Attr&ibute signature"), m_pVisibilityGB);
+ sigtype = m_pWidget->getShowAttSigs();
+ if(sigtype == Uml::st_NoSig || sigtype == Uml::st_NoSigNoVis)
+ sig = false;
+ else
+ sig = true;
+ m_pShowAttSigCB->setChecked(sig);
+ visibilityLayout->addWidget(m_pShowAttSigCB, 3, 0);
+
+ } else if (type == Uml::wt_Interface) {
+ m_pDrawAsCircleCB = new QCheckBox(i18n("Draw as circle"), m_pVisibilityGB);
+ m_pDrawAsCircleCB->setChecked( m_pWidget->getDrawAsCircle() );
+ visibilityLayout->addWidget(m_pDrawAsCircleCB, 2, 0);
+ }
+}
+
+void ClassOptionsPage::setupClassPageOption() {
+
+ int margin = fontMetrics().height();
+
+ QVBoxLayout * topLayout = new QVBoxLayout(this);
+ topLayout -> setSpacing(6);
+ m_pVisibilityGB = new QGroupBox(i18n("Show"), this);
+ topLayout -> addWidget(m_pVisibilityGB);
+ QGridLayout * visibilityLayout = new QGridLayout(m_pVisibilityGB);
+ visibilityLayout -> setSpacing(10);
+ visibilityLayout -> setMargin(margin);
+
+ m_pShowOpsCB = new QCheckBox(i18n("Operatio&ns"), m_pVisibilityGB);
+ m_pShowOpsCB -> setChecked( m_options->classState.showOps );
+ visibilityLayout -> addWidget(m_pShowOpsCB, 0, 0);
+
+ m_pShowOpSigCB = new QCheckBox(i18n("O&peration signature"), m_pVisibilityGB);
+ m_pShowOpSigCB -> setChecked(m_options->classState.showOpSig);
+ visibilityLayout -> addWidget(m_pShowOpSigCB, 1, 0);
+ visibilityLayout -> setRowStretch(3, 1);
+
+ m_pShowAttsCB = new QCheckBox(i18n("Att&ributes"), m_pVisibilityGB);
+ m_pShowAttsCB -> setChecked(m_options->classState.showAtts );
+ visibilityLayout -> addWidget(m_pShowAttsCB, 2, 0);
+
+ m_pShowAttSigCB = new QCheckBox(i18n("Attr&ibute signature"), m_pVisibilityGB);
+ m_pShowAttSigCB -> setChecked(m_options->classState.showAttSig);
+ visibilityLayout -> addWidget(m_pShowAttSigCB, 3, 0);
+
+ m_pShowVisibilityCB = new QCheckBox(i18n("&Visibility"), m_pVisibilityGB);
+ m_pShowVisibilityCB -> setChecked(m_options->classState.showVisibility);
+ visibilityLayout -> addWidget(m_pShowVisibilityCB, 0, 1);
+
+ m_pShowPackageCB = new QCheckBox(i18n("Pac&kage"), m_pVisibilityGB);
+ m_pShowPackageCB -> setChecked(m_options->classState.showPackage);
+ visibilityLayout -> addWidget(m_pShowPackageCB, 1, 1);
+
+ m_pShowStereotypeCB = new QCheckBox(i18n("Stereot&ype"), m_pVisibilityGB);
+ m_pShowStereotypeCB -> setChecked(m_options->classState.showStereoType);
+ visibilityLayout -> addWidget(m_pShowStereotypeCB, 2, 1);
+
+}
+
+void ClassOptionsPage::updateUMLWidget() {
+ if (m_pWidget) {
+ updateWidget();
+ } else if (m_options) {
+ updateOptionState();
+ }
+}
+
+void ClassOptionsPage::updateWidget() {
+ m_pWidget->setShowPackage( m_pShowPackageCB->isChecked() );
+ m_pWidget->setShowVisibility( m_pShowVisibilityCB->isChecked() );
+ m_pWidget->setShowOps( m_pShowOpsCB->isChecked() );
+ m_pWidget->setShowOpSigs( m_pShowOpSigCB->isChecked() );
+ Uml::Widget_Type type = m_pWidget->getBaseType();
+ if (type == Uml::wt_Class) {
+ m_pWidget->setShowStereotype( m_pShowStereotypeCB->isChecked() );
+ m_pWidget->setShowAtts( m_pShowAttsCB->isChecked() );
+ m_pWidget->setShowAttSigs( m_pShowAttSigCB->isChecked() );
+ } else if (type == Uml::wt_Interface) {
+ if (m_pDrawAsCircleCB)
+ m_pWidget->setDrawAsCircle( m_pDrawAsCircleCB->isChecked() );
+ }
+}
+
+void ClassOptionsPage::updateOptionState() {
+ m_options->classState.showVisibility = m_pShowVisibilityCB->isChecked();
+ if (m_pShowAttsCB)
+ m_options->classState.showAtts = m_pShowAttsCB->isChecked();
+ m_options->classState.showOps = m_pShowOpsCB->isChecked();
+ if (m_pShowStereotypeCB)
+ m_options->classState.showStereoType = m_pShowStereotypeCB->isChecked();
+ m_options->classState.showPackage = m_pShowPackageCB->isChecked();
+ if (m_pShowAttSigCB)
+ m_options->classState.showAttSig = m_pShowAttSigCB->isChecked();
+ m_options->classState.showOpSig = m_pShowOpSigCB->isChecked();
+}
+
+
+//#include "classoptionspage.moc"
diff --git a/umbrello/umbrello/dialogs/classoptionspage.h b/umbrello/umbrello/dialogs/classoptionspage.h
new file mode 100644
index 00000000..50d43f8c
--- /dev/null
+++ b/umbrello/umbrello/dialogs/classoptionspage.h
@@ -0,0 +1,106 @@
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * copyright (C) 2002-2006 *
+ * Umbrello UML Modeller Authors <uml-devel@uml.sf.net> *
+ ***************************************************************************/
+
+
+#ifndef CLASSOPTIONSPAGE_H
+#define CLASSOPTIONSPAGE_H
+
+#include <qwidget.h>
+#include <qgroupbox.h>
+#include <qcheckbox.h>
+
+#include "../optionstate.h"
+
+class ClassifierWidget;
+
+/**
+ * A dialog page to display options for a @ref UMLWidget and its
+ * children. This is not normally called by you. It is used by
+ * the @ref ClassPropDlg.
+ *
+ * @short A dialog page to display the options for a UMLWidget.
+ * @author Paul Hensgen <phensgen@techie.com>
+ * @see ClassPropDlg
+ * Bugs and comments to uml-devel@lists.sf.net or http://bugs.kde.org
+ */
+class ClassOptionsPage : public QWidget {
+public:
+ /**
+ * Constructor - observe and modify a Widget
+ */
+ ClassOptionsPage(QWidget* pParent, ClassifierWidget* pWidget);
+
+ /**
+ * Constructor - observe and modify an OptionState structure
+ */
+ ClassOptionsPage(QWidget* pParent, Settings::OptionState *options );
+
+ /**
+ * destructor
+ */
+ virtual ~ClassOptionsPage();
+
+ /**
+ * Updates the widget with the dialog page properties.
+ */
+ void updateUMLWidget();
+
+ /**
+ * Sets the widget to be used. Only used by @ref UMLView to set
+ * settings of a widget.
+ */
+ void setWidget( ClassifierWidget * pWidget ) {
+ m_pWidget = pWidget;
+ }
+
+protected:
+ /**
+ * Initialize optional items
+ */
+ void init();
+
+ /**
+ * Creates the page with the correct options for the class/interface
+ */
+ void setupPage();
+
+ /**
+ * Creates the page based on the OptionState
+ */
+ void setupClassPageOption();
+
+ /**
+ * Sets the ClassifierWidget's properties to those selected in this dialog page.
+ */
+ void updateWidget();
+
+ /**
+ * Sets the OptionState to the values selected in this dialog page.
+ */
+ void updateOptionState();
+
+ //GUI widgets
+ QGroupBox * m_pVisibilityGB;
+ QCheckBox * m_pShowVisibilityCB, * m_pShowAttSigCB;
+ QCheckBox * m_pShowOpSigCB, * m_pShowAttsCB, * m_pShowOpsCB;
+ QCheckBox * m_pShowStereotypeCB, * m_pShowPackageCB;
+ QCheckBox* m_pDrawAsCircleCB;
+
+ /**
+ * The classifier widget to represent in the dialog page.
+ */
+ ClassifierWidget* m_pWidget;
+ /**
+ * The OptionState structure to represent in the dialog page.
+ */
+ Settings::OptionState *m_options;
+};
+#endif
diff --git a/umbrello/umbrello/dialogs/classpropdlg.cpp b/umbrello/umbrello/dialogs/classpropdlg.cpp
new file mode 100644
index 00000000..9c4848a1
--- /dev/null
+++ b/umbrello/umbrello/dialogs/classpropdlg.cpp
@@ -0,0 +1,250 @@
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * copyright (C) 2003-2007 *
+ * Umbrello UML Modeller Authors <uml-devel@uml.sf.net> *
+ ***************************************************************************/
+
+// own header
+#include "classpropdlg.h"
+
+// qt/kde includes
+#include <qlayout.h>
+#include <kiconloader.h>
+#include <klocale.h>
+#include <kdebug.h>
+
+// app includes
+#include "classgenpage.h"
+#include "classifierlistpage.h"
+#include "pkgcontentspage.h"
+#include "assocpage.h"
+#include "classoptionspage.h"
+#include "umlwidgetcolorpage.h"
+#include "../umlobject.h"
+#include "../umldoc.h"
+#include "../classifierwidget.h"
+#include "../objectwidget.h"
+#include "../componentwidget.h"
+#include "../uml.h"
+#include "../umlview.h"
+
+ClassPropDlg::ClassPropDlg(QWidget *parent, UMLObject * c, int pageNum, bool assoc)
+ : KDialogBase(IconList, i18n("Properties"), Ok | Apply | Cancel | Help,
+ Ok, parent, "_CLASSDLG_", true, true) {
+ m_pWidget = 0;
+ m_pGenPage = 0;
+ m_pAttPage = 0;
+ m_pOpsPage = 0;
+ m_pTemplatePage = 0;
+ m_pEnumLiteralPage = 0;
+ m_pEntityAttributePage = 0;
+ m_pOptionsPage = 0;
+ m_pColorPage = 0;
+ m_Type = pt_Object;
+ m_pDoc = UMLApp::app()->getDocument();
+ m_pObject = c;
+ setupPages(c, assoc);
+ showPage(pageNum);
+}
+
+ClassPropDlg::ClassPropDlg(QWidget *parent, ObjectWidget * o)
+ : KDialogBase(IconList, i18n("Properties"), Ok | Apply | Cancel | Help,
+ Ok, parent, "_CLASSDLG_", true, true) {
+ m_pWidget = o;
+ m_pGenPage = 0;
+ m_pAttPage = 0;
+ m_pOpsPage = 0;
+ m_pTemplatePage = 0;
+ m_pEnumLiteralPage = 0;
+ m_pEntityAttributePage = 0;
+ m_pOptionsPage = 0;
+ m_Type = pt_ObjectWidget;
+ m_pObject = m_pWidget->getUMLObject();
+ m_pDoc = UMLApp::app()->getDocument();
+ QFrame *page = addPage( i18n("General"), i18n("General Settings"), DesktopIcon( "misc") );
+ page -> setMinimumSize(310, 330);
+ QHBoxLayout * topLayout = new QHBoxLayout(page);
+ m_pGenPage = new ClassGenPage(m_pDoc, page, o);
+ topLayout -> addWidget(m_pGenPage);
+
+ QFrame * newPage = addPage( i18n("Color"), i18n("Widget Colors"), DesktopIcon( "colors") );
+ QHBoxLayout * m_pColorLayout = new QHBoxLayout(newPage);
+ m_pColorPage = new UMLWidgetColorPage(newPage, o);
+ m_pColorLayout -> addWidget(m_pColorPage);
+
+ setupFontPage();
+ showPage(0);
+ setMinimumSize(340,420);
+}
+
+ClassPropDlg::ClassPropDlg(QWidget *parent, UMLWidget * w)
+ : KDialogBase(IconList, i18n("Properties"), Ok | Apply | Cancel | Help,
+ Ok, parent, "_CLASSDLG_", true, true) {
+ m_pWidget = w;
+ m_pGenPage = 0;
+ m_pAttPage = 0;
+ m_pOpsPage = 0;
+ m_pTemplatePage = 0;
+ m_pEnumLiteralPage = 0;
+ m_pEntityAttributePage = 0;
+ m_pOptionsPage = 0;
+ m_Type = pt_Widget;
+ m_pObject = w -> getUMLObject();
+ m_pDoc = ((UMLApp *)parent) -> getDocument();
+
+ if (w->getBaseType() == Uml::wt_Class
+ || w->getBaseType() == Uml::wt_Interface
+ || w->getBaseType() == Uml::wt_Package) {
+ setupPages(m_pObject, true);
+ } else if (w->getBaseType() == Uml::wt_Component) {
+ if ( w->getIsInstance() ) {
+ setupInstancePages(w);
+ } else {
+ setupPages(m_pObject);
+ }
+ } else if (w->getBaseType() == Uml::wt_Node) {
+ setupInstancePages(w);
+ } else {
+ setupPages(m_pObject);
+ }
+
+ //now setup the options page for classes
+ if (w->getBaseType() == Uml::wt_Class || w->getBaseType() == Uml::wt_Interface) {
+ QFrame* newPage = addPage( i18n("Display"), i18n("Display Options"), DesktopIcon("info") );
+ QHBoxLayout* m_pOptionsLayout = new QHBoxLayout(newPage);
+ ClassifierWidget *cw = static_cast<ClassifierWidget*>(w);
+ m_pOptionsPage = new ClassOptionsPage( newPage, cw );
+ m_pOptionsLayout -> addWidget(m_pOptionsPage);
+ }
+
+ QFrame* colorPage = addPage( i18n("Color"), i18n("Widget Colors"), DesktopIcon("colors") );
+ QHBoxLayout * m_pColorLayout = new QHBoxLayout(colorPage);
+ m_pColorPage = new UMLWidgetColorPage(colorPage, w);
+ m_pColorLayout -> addWidget(m_pColorPage);
+ setupFontPage();
+}
+
+ClassPropDlg::~ClassPropDlg() {}
+
+void ClassPropDlg::slotOk() {
+ slotApply();
+ KDialogBase::accept();
+}
+
+void ClassPropDlg::slotApply() {
+ if (m_pGenPage) {
+ m_pGenPage->updateObject();
+ }
+ if (m_pAttPage) {
+ m_pAttPage->updateObject();
+ }
+ if (m_pOpsPage) {
+ m_pOpsPage->updateObject();
+ }
+ if (m_pTemplatePage) {
+ m_pTemplatePage->updateObject();
+ }
+ if (m_pEnumLiteralPage) {
+ m_pEnumLiteralPage->updateObject();
+ }
+ if (m_pEntityAttributePage) {
+ m_pEntityAttributePage->updateObject();
+ }
+ if (m_pOptionsPage) {
+ m_pOptionsPage->updateUMLWidget();
+ }
+ if (m_pColorPage) {
+ m_pColorPage->updateUMLWidget();
+ }
+ if (m_pWidget) {
+ m_pWidget->setFont( m_pChooser->font() );
+ }
+}
+
+void ClassPropDlg::setupPages(UMLObject * c, bool assoc) {
+ QFrame *page = addPage(i18n("General"), i18n("General Settings"), DesktopIcon( "misc") );
+ QHBoxLayout * genLayout = new QHBoxLayout(page);
+ page -> setMinimumSize(310, 330);
+ m_pGenPage = new ClassGenPage(m_pDoc, page, c);
+ genLayout -> addWidget(m_pGenPage);
+ Uml::Object_Type ot = c->getBaseType();
+ //add extra pages for class
+ if (ot == Uml::ot_Class ) {
+ //setup attributes page
+ QFrame* newPage = addPage( i18n("Attributes"), i18n("Attribute Settings"), DesktopIcon("misc") );
+ m_pAttPage = new ClassifierListPage(newPage, (UMLClassifier *)c, m_pDoc, Uml::ot_Attribute);
+ QHBoxLayout * attLayout = new QHBoxLayout(newPage);
+ attLayout -> addWidget(m_pAttPage);
+ }
+
+ if (ot == Uml::ot_Class || ot == Uml::ot_Interface) {
+ //setup operations page
+ QFrame* newPage = addPage( i18n("Operations"), i18n("Operation Settings"), DesktopIcon("misc") );
+ m_pOpsPage = new ClassifierListPage(newPage, (UMLClassifier*)c, m_pDoc, Uml::ot_Operation);
+ QHBoxLayout* pOpsLayout = new QHBoxLayout(newPage);
+ pOpsLayout -> addWidget(m_pOpsPage);
+ }
+
+ if (ot == Uml::ot_Class || ot == Uml::ot_Interface) {
+ //setup templates page
+ QFrame* newPage = addPage( i18n("Templates"), i18n("Templates Settings"), DesktopIcon("misc") );
+ m_pTemplatePage = new ClassifierListPage(newPage, (UMLClassifier *)c, m_pDoc, Uml::ot_Template);
+ QHBoxLayout* templatesLayout = new QHBoxLayout(newPage);
+ templatesLayout->addWidget(m_pTemplatePage);
+ }
+ if (ot == Uml::ot_Enum) {
+ //setup enum literals page
+ QFrame* newPage = addPage( i18n("Enum Literals"), i18n("Enum Literals Settings"), DesktopIcon("misc") );
+ m_pEnumLiteralPage = new ClassifierListPage(newPage, (UMLClassifier*)c, m_pDoc, Uml::ot_EnumLiteral);
+ QHBoxLayout* enumLiteralsLayout = new QHBoxLayout(newPage);
+ enumLiteralsLayout->addWidget(m_pEnumLiteralPage);
+ }
+ if (ot == Uml::ot_Entity) {
+ //setup enum literals page
+ QFrame* newPage = addPage( i18n("Entity Attributes"), i18n("Entity Attributes Settings"), DesktopIcon("misc") );
+ m_pEntityAttributePage = new ClassifierListPage(newPage, (UMLClassifier*)c, m_pDoc, Uml::ot_EntityAttribute);
+ QHBoxLayout* entityAttributesLayout = new QHBoxLayout(newPage);
+ entityAttributesLayout->addWidget(m_pEntityAttributePage);
+ }
+ if (ot == Uml::ot_Package ) {
+ // Set up containment page.
+ QFrame* newPage = addPage( i18n("Contents"), i18n("Contents Settings"), DesktopIcon("misc") );
+ m_pPkgContentsPage = new PkgContentsPage(newPage, (UMLPackage*)(c));
+ QHBoxLayout* contentsLayout = new QHBoxLayout(newPage);
+ contentsLayout->addWidget(m_pPkgContentsPage);
+ }
+ if (assoc) {
+ QFrame* newPage = addPage(i18n("Associations"), i18n("Class Associations"), DesktopIcon( "misc") );
+ m_pAssocPage = new AssocPage(newPage, UMLApp::app()->getCurrentView(), m_pObject);
+ QHBoxLayout* assocLayout = new QHBoxLayout(newPage);
+ assocLayout -> addWidget(m_pAssocPage);
+ } else {
+ m_pAssocPage = 0;
+ }
+}
+
+void ClassPropDlg::setupInstancePages(UMLWidget* widget) {
+ QFrame* page = addPage( i18n("General"), i18n("General Settings"), DesktopIcon("misc") );
+ QHBoxLayout* genLayout = new QHBoxLayout(page);
+ page->setMinimumSize(310, 330);
+ m_pGenPage = new ClassGenPage(m_pDoc, page, widget);
+ genLayout->addWidget(m_pGenPage);
+ m_pAssocPage = 0;
+}
+
+void ClassPropDlg::setupFontPage() {
+ if( !m_pWidget )
+ return;
+ QVBox * page = addVBoxPage( i18n("Font"), i18n("Font Settings"), DesktopIcon( "fonts") );
+ m_pChooser = new KFontChooser( (QWidget*)page, "font", false, QStringList(), false);
+ m_pChooser -> setFont( m_pWidget -> getFont() );
+}
+
+
+
+#include "classpropdlg.moc"
diff --git a/umbrello/umbrello/dialogs/classpropdlg.h b/umbrello/umbrello/dialogs/classpropdlg.h
new file mode 100644
index 00000000..90c5b4ec
--- /dev/null
+++ b/umbrello/umbrello/dialogs/classpropdlg.h
@@ -0,0 +1,129 @@
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * copyright (C) 2003-2007 *
+ * Umbrello UML Modeller Authors <uml-devel@uml.sf.net> *
+ ***************************************************************************/
+
+#ifndef CLASSPROPDLG_H
+#define CLASSPROPDLG_H
+
+//kde class includes
+#include <kdialogbase.h>
+#include <kfontdialog.h>
+
+#include "../umlnamespace.h"
+
+class ClassGenPage;
+class ClassifierListPage;
+class ClassOpsPage;
+class ClassTemplatePage;
+class PkgContentsPage;
+class AssocPage;
+class ClassOptionsPage;
+class UMLWidgetColorPage;
+
+class ComponentWidget;
+class ObjectWidget;
+class UMLDoc;
+class UMLObject;
+class UMLWidget;
+
+/**
+ * @author Paul Hensgen <phensgen@techie.com>
+ * @version 1.0
+ * Bugs and comments to uml-devel@lists.sf.net or http://bugs.kde.org
+ */
+class ClassPropDlg : public KDialogBase {
+ Q_OBJECT
+public:
+ /**
+ * Sets up a ClassPropDlg.
+ *
+ * @param parent The parent of the ClassPropDlg
+ * @param c The UMLObject to display properties of.
+ * @param pageNum The page to show first.
+ * @param assoc Determines whether to display associations
+ */
+ ClassPropDlg(QWidget *parent, UMLObject *c, int pageNum = 0, bool assoc = false);
+
+ /**
+ * Sets up a ClassPropDlg.
+ *
+ * @param parent The parent of the ClassPropDlg
+ * @param o The ObjectWidget to display properties of.
+ */
+ ClassPropDlg(QWidget *parent, ObjectWidget * o);
+
+ /**
+ * Sets up a ClassPropDlg.
+ *
+ * @param parent The parent of the ClassPropDlg
+ * @param o The UMLWidget to display properties of.
+ */
+ ClassPropDlg(QWidget *parent, UMLWidget * o);
+
+
+ /**
+ * Standard deconstructor
+ */
+ ~ClassPropDlg();
+
+ enum Page{page_gen = 0, page_att, page_op, page_template,
+ page_assoc, page_options, page_color, page_font};
+
+protected slots:
+ /**
+ * Calls slotApply() and accepts (closes) the dialog
+ */
+ void slotOk();
+
+ /**
+ * Applies the settings in the dialog to the widget and object
+ */
+ void slotApply();
+
+protected:
+ /**
+ * Sets up the general, attribute, operations, template and association pages as appropriate
+ */
+ void setupPages(UMLObject * c, bool assoc = false);
+
+ /**
+ * Sets up the general page for the component
+ */
+ void setupInstancePages(UMLWidget* widget);
+
+ /**
+ * Sets up the font page
+ */
+ void setupFontPage();
+private:
+ KFontChooser * m_pChooser;
+ ClassGenPage * m_pGenPage;
+ ClassifierListPage* m_pAttPage;
+ ClassifierListPage* m_pOpsPage;
+ ClassifierListPage* m_pTemplatePage;
+ ClassifierListPage* m_pEnumLiteralPage;
+ ClassifierListPage* m_pEntityAttributePage;
+ PkgContentsPage * m_pPkgContentsPage;
+ AssocPage * m_pAssocPage;
+ ClassOptionsPage * m_pOptionsPage;
+ UMLWidgetColorPage * m_pColorPage;
+ UMLDoc *m_pDoc;
+
+ UMLObject *m_pObject;
+ UMLWidget * m_pWidget;
+
+ enum Page_Type{ pt_Object = 1, //Show General page + Assoc. page if Class i.e. no colours page
+ pt_ObjectWidget, //Shows pages needed for an ObjectWidget
+ pt_Widget //Shows pages needed for any other widget
+ };
+ Page_Type m_Type;
+};
+
+#endif
diff --git a/umbrello/umbrello/dialogs/classwizard.cpp b/umbrello/umbrello/dialogs/classwizard.cpp
new file mode 100644
index 00000000..7ac1cb27
--- /dev/null
+++ b/umbrello/umbrello/dialogs/classwizard.cpp
@@ -0,0 +1,107 @@
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * copyright (C) 2002-2006 *
+ * Umbrello UML Modeller Authors <uml-devel@uml.sf.net> *
+ ***************************************************************************/
+
+// own header
+#include "classwizard.h"
+
+// system includes
+#include <khelpmenu.h>
+#include <klocale.h>
+
+// local includes
+#include "classifierlistpage.h"
+#include "../uml.h"
+#include "../umldoc.h"
+#include "../classifier.h"
+#include "../attribute.h"
+#include "../operation.h"
+#include "../umlclassifierlistitemlist.h"
+#include "../classifierlistitem.h"
+
+ClassWizard::ClassWizard( UMLDoc * pDoc ) : KWizard( (QWidget*)pDoc -> parent(), "_CLASSWIZARD_", true) {
+ m_pDoc = pDoc;
+ //create a unique class to start with
+ UMLObject * pTemp = 0;
+ QString name = i18n("new_class");
+ QString newName = name;
+ QString num = "";
+ int i = 0;
+ m_pClass = new UMLClassifier( newName );
+ do {
+ m_pClass -> setName( newName );
+ pTemp = m_pDoc -> findUMLObject( newName );
+ num.setNum( ++i);
+ newName = name;
+ newName.append("_").append( num );
+ } while( pTemp );
+ //setup pages
+ setupPages();
+}
+
+ClassWizard::~ClassWizard() {}
+
+void ClassWizard::setupPages() {
+ //Setup General Page
+ m_pGenPage = new ClassGenPage( m_pDoc, this, m_pClass );
+ addPage( m_pGenPage, i18n("New Class") );
+ setHelpEnabled(m_pGenPage, false);
+
+ //Setup Attribute Page
+ m_pAttPage = new ClassifierListPage(this, m_pClass, m_pDoc, Uml::ot_Attribute);
+ addPage( m_pAttPage, i18n("Class Attributes") );
+
+ //Setup Operation Page
+ m_pOpPage = new ClassifierListPage(this, m_pClass, m_pDoc, Uml::ot_Operation);
+ addPage( m_pOpPage, i18n("Class Operations") );
+}
+
+void ClassWizard::showPage( QWidget * pWidget ) {
+ QWizard::showPage( pWidget );
+ if( pWidget == m_pOpPage )
+ finishButton() -> setEnabled( true );
+}
+
+void ClassWizard::next() {
+ QWidget * pWidget = currentPage();
+ if( pWidget == m_pGenPage ) {
+ m_pGenPage -> updateObject();
+ } else if( pWidget == m_pAttPage ) {
+ m_pAttPage -> updateObject();
+ }
+ QWizard::next();
+}
+
+void ClassWizard::back() {
+ QWidget * pWidget = currentPage();
+ if( pWidget == m_pAttPage ) {
+ m_pAttPage -> updateObject();
+ } else if( pWidget == m_pOpPage ) {
+ m_pOpPage -> updateObject();
+ }
+ QWizard::back();
+}
+
+void ClassWizard::accept() {
+ m_pDoc -> addUMLObject( m_pClass );
+ m_pDoc->signalUMLObjectCreated(m_pClass);
+
+ QWizard::accept();
+}
+
+void ClassWizard::reject() {
+ delete m_pClass;
+ QWizard::reject();
+}
+
+void ClassWizard::help() {
+ KHelpMenu helpMenu(this);
+ helpMenu.appHelpActivated();
+}
diff --git a/umbrello/umbrello/dialogs/classwizard.h b/umbrello/umbrello/dialogs/classwizard.h
new file mode 100644
index 00000000..bc2dabf8
--- /dev/null
+++ b/umbrello/umbrello/dialogs/classwizard.h
@@ -0,0 +1,104 @@
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * copyright (C) 2002-2006 *
+ * Umbrello UML Modeller Authors <uml-devel@uml.sf.net> *
+ ***************************************************************************/
+
+#ifndef CLASSWIZARD_H
+#define CLASSWIZARD_H
+//kde includes
+#include <kwizard.h>
+//app includes
+#include "classgenpage.h"
+
+class ClassifierListPage;
+class UMLClassifier;
+class UMLDoc;
+
+/**
+ * @author Paul Hensgen
+ * Bugs and comments to uml-devel@lists.sf.net or http://bugs.kde.org
+ */
+class ClassWizard : public KWizard {
+public:
+ /**
+ * Consrtuctor
+ */
+ ClassWizard( UMLDoc * pDoc );
+
+ /**
+ * Deconstructor
+ */
+ ~ClassWizard();
+
+protected:
+
+ /**
+ * Overrides the default method.
+ */
+ void showPage( QWidget * pWidget );
+
+ /**
+ * Overrides the default method.
+ */
+ void next();
+
+ /**
+ * Overrides the default method.
+ */
+ void back();
+
+ /**
+ * Overrides the default method.
+ */
+ void accept();
+
+ /**
+ * Overrides the default method.
+ */
+ void reject();
+
+ /**
+ * Setup the wizard pages.
+ */
+ void setupPages();
+
+ /**
+ * Page 1 - General class info
+ */
+ ClassGenPage * m_pGenPage;
+
+ /**
+ * Page 2 - Class Attributes
+ */
+ ClassifierListPage* m_pAttPage;
+
+ /**
+ * Page 3 - Class Operations
+ */
+ ClassifierListPage* m_pOpPage;
+
+ /**
+ * Document currently opened
+ */
+ UMLDoc * m_pDoc;
+
+ /**
+ * Class to create
+ */
+ UMLClassifier * m_pClass;
+
+protected slots:
+ /**
+ * Opens Umbrello handbook
+ */
+ void help();
+
+};
+
+#endif
diff --git a/umbrello/umbrello/dialogs/codeeditor.cpp b/umbrello/umbrello/dialogs/codeeditor.cpp
new file mode 100644
index 00000000..c05b80bb
--- /dev/null
+++ b/umbrello/umbrello/dialogs/codeeditor.cpp
@@ -0,0 +1,1231 @@
+
+/***************************************************************************
+ codeviewerdialog.cpp - description
+ -------------------
+ begin : Fri Aug 1 2003
+ copyright : (C) 2003 by Brian Thomas
+ email : brian.thomas@gsfc.nasa.gov
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * copyright (C) 2004-2007 *
+ * Umbrello UML Modeller Authors <uml-devel@uml.sf.net> *
+ ***************************************************************************/
+
+// own header
+#include "codeeditor.h"
+
+// qt/kde includes
+#include <qkeysequence.h>
+#include <qcursor.h>
+#include <qcolor.h>
+#include <qlabel.h>
+#include <qbrush.h>
+#include <qlayout.h>
+#include <qregexp.h>
+#include <kdebug.h>
+#include <klocale.h>
+
+// local includes
+#include "../attribute.h"
+#include "../classifier.h"
+#include "../umldoc.h"
+#include "../umlrole.h"
+
+#include "../codeaccessormethod.h"
+#include "../codegenerator.h"
+#include "../codeclassfield.h"
+#include "../codeclassfielddeclarationblock.h"
+#include "../codedocument.h"
+#include "../codeoperation.h"
+#include "../codemethodblock.h"
+#include "../classifiercodedocument.h"
+#include "../ownedhierarchicalcodeblock.h"
+#include "../codegenerators/codegenfactory.h"
+
+#include "codeviewerdialog.h"
+#include "classpropdlg.h"
+#include "umlattributedialog.h"
+#include "umlroledialog.h"
+#include "umloperationdialog.h"
+
+CodeEditor::CodeEditor ( const QString & text, const QString & context, CodeViewerDialog * parent, const char * name , CodeDocument * doc)
+ : QTextEdit ( text, context, parent, name)
+{
+ init(parent, doc);
+}
+
+CodeEditor::CodeEditor ( CodeViewerDialog * parent, const char* name, CodeDocument * doc )
+ : QTextEdit ( parent, name )
+{
+ init(parent, doc);
+}
+
+/*
+ * Destroys the object and frees any allocated resources
+ */
+CodeEditor::~CodeEditor() { }
+
+// clear the display of all text
+void CodeEditor::clearText () {
+
+ // setCaption( tr2i18n("") );
+ m_selectedTextBlock = 0;
+ m_textBlockList.clear();
+ m_tbInfoMap->clear();
+
+ // now call super-class
+ clear();
+
+}
+
+Settings::CodeViewerState CodeEditor::getState()
+{
+ return m_parentDlg->getState();
+}
+
+QLabel * CodeEditor::getComponentLabel() {
+ return m_parentDlg->componentLabel;
+}
+
+
+// FIX: used only for debugging right now.. eliminate eventually -b.t.
+void CodeEditor::clicked(int para, int pos)
+{
+ getComponentLabel()->setText("para:"+QString::number(para)+" pos:"+QString::number(pos));
+}
+
+
+bool CodeEditor::close ( bool alsoDelete )
+{
+
+ // capture last code block, if it exists
+ if(m_lastTextBlockToBeEdited)
+ {
+ updateTextBlockFromText (m_lastTextBlockToBeEdited);
+ m_lastTextBlockToBeEdited = 0;
+ }
+
+ return QTextEdit::close(alsoDelete);
+
+}
+
+void CodeEditor::doubleClicked(int para, int pos)
+{
+
+ m_lastPara = para;
+ m_lastPos = pos;
+
+ // ugh. more ugliness. We want to be able to call up the
+ // correct editing dialog for the given attribute.
+ TextBlock * tBlock = m_textBlockList.at(para);
+ editTextBlock(tBlock, para);
+
+}
+
+// allow us to edit, as appropriate, the parent UMLObject of the
+// given text block.
+void CodeEditor::editTextBlock(TextBlock * tBlock, int para) {
+
+ if(tBlock)
+ {
+ TextBlockInfo *info = (*m_tbInfoMap)[tBlock];
+ if(info) {
+ UMLObject *obj = info->getParent();
+ if(obj)
+ {
+
+ UMLAttribute * at = 0;
+ UMLRole * role = 0;
+ UMLOperation * op = 0;
+
+ if( (at = dynamic_cast<UMLAttribute*>(obj)) )
+ {
+ UMLAttributeDialog dlg( this, at);
+ if( dlg.exec() ) { rebuildView(para); }
+ }
+ else if( (dynamic_cast<UMLClassifier*>(obj)) )
+ {
+ if (obj->showProperties())
+ rebuildView(para);
+ }
+ else if( (role = dynamic_cast<UMLRole*>(obj)))
+ {
+ UMLRoleDialog dlg(this,role);
+ if( dlg.exec() ) { rebuildView(para); }
+ }
+ else if( (op = dynamic_cast<UMLOperation*>(obj)) )
+ //else if( (cop = dynamic_cast<CodeOperation*>(tBlock)) )
+ {
+ UMLOperationDialog dlg(this,op);
+ if( dlg.exec() ) { rebuildView(para); }
+ }
+ else
+ {
+ kError()<<" CodeViewerDlg ERROR: UNKNOWN parent for textBlock"<<endl;
+ }
+
+ }
+ }
+ }
+}
+
+// return whether is empty or just whitespace
+bool CodeEditor::StringIsBlank(const QString &str)
+{
+ if(str.isEmpty() || str.stripWhiteSpace().isEmpty())
+ return true;
+ return false;
+}
+
+void CodeEditor::keyPressEvent ( QKeyEvent * e ) {
+
+ // kDebug() <<"KEY PRESS EVENT:["<<e->text().latin1()<<"] ascii CODE:"<<e->ascii();
+
+ if((e->ascii() == 8) ) // || (e->ascii() == 127)) // what about delete?
+ m_backspacePressed = true;
+
+ // Q: can the MAC or WIN/DOS sequences occur?
+ if((e->ascii() == 10) || (e->ascii() == 13) || (e->text() == "\r\n"))
+ m_newLinePressed = true;
+
+ QTextEdit::keyPressEvent(e);
+}
+
+void CodeEditor::loadFromDocument ()
+{
+
+ // clear the tool
+ clearText();
+
+ // set caption on tool
+ QString caption = m_parentDoc->getFileName() + m_parentDoc->getFileExtension();
+ setCaption( tr2i18n( caption.latin1() ) );
+
+ // header for document
+ QString header = m_parentDoc->getHeader()->toString();
+ QString componentName = QString("header for file ") +caption;
+ if(!StringIsBlank(header))
+ insert(header,m_parentDoc->getHeader(),false,getState().fontColor,
+ getState().nonEditBlockColor,0,componentName);
+
+ // now all the text blocks in the document
+ TextBlockList * items = m_parentDoc->getTextBlockList();
+ appendText(items);
+
+ setCursorPosition(0,0);
+
+}
+
+void CodeEditor::insert (const QString & text, TextBlock * parent, bool editable, const QColor & fgcolor, const QColor & bgcolor, UMLObject * umlobj, const QString & displayName, int startLine)
+{
+
+ // set some params
+ bool isInsert = false;
+ setColor(fgcolor);
+
+ // its an append op if startLine is -1, otherwise its
+ // an actual insert, which is more complicated
+ if(startLine == -1)
+ {
+ startLine = paragraphs()-1;
+ QTextEdit::append(text); // put actual text in. Use insert instead of append so history is preserved?
+ }
+ else
+ {
+ isInsert = true;
+ QTextEdit::insertAt(text, startLine, 0);
+ }
+
+ // actual put in text
+
+ // now do 'paragraph' background highlighting
+ // int endLine = paragraphs()-2;
+ int endLine = text.contains(QRegExp("\n")) + startLine -1;
+ if(m_isHighlighted)
+ for(int para=startLine;para<=endLine;para++)
+ setParagraphBackgroundColor(para,bgcolor);
+
+ // record paragraph information
+ // Did we already start recording info for this parent object?
+ TextBlockInfo * tbinfo;
+ if(m_tbInfoMap->contains(parent))
+ tbinfo = (*m_tbInfoMap)[parent];
+ else {
+ tbinfo = new TextBlockInfo();
+ tbinfo->displayName = displayName;
+ tbinfo->isCodeAccessorMethod = dynamic_cast<CodeAccessorMethod*>(parent) ? true : false;
+ m_tbInfoMap->insert(parent,tbinfo);
+ }
+
+ // set a parent, if its not already set
+ if(umlobj && !tbinfo->getParent())
+ {
+ tbinfo->displayName = displayName;
+ tbinfo->setParent(umlobj);
+ tbinfo->isClickable = textBlockIsClickable(umlobj);
+ }
+
+ // now mark all lines that we just inserted as belonging to the parent
+ for(int para=startLine;para<=endLine;para++)
+ m_textBlockList.insert(para,parent);
+
+ // lastly, update the para info
+ // start position is relative to the FIRST parent position
+ int start = startLine - m_textBlockList.findRef(parent);
+ int size = endLine-startLine;
+
+ // create the object that records this particular "paragraph"
+ ParaInfo * item = new ParaInfo();
+ item->start = start;
+ item->size= size;
+ item->fgcolor = fgcolor;
+ item->bgcolor = bgcolor;
+ item->isEditable = editable;
+
+ if(isInsert)
+ {
+ // now we have to fix the 'start' value for all the para
+ // info blocks that coorspond to textblocks that we inserted
+ // inside of. This means parent tblock paragraph locations
+ // that are greater than zero in that type of textblock
+
+ int increase = size + 1;
+ QMap<TextBlock*,TextBlockInfo*>::Iterator it;
+ for ( it = m_tbInfoMap->begin(); it != m_tbInfoMap->end(); ++it )
+ {
+ TextBlock * tblock = it.key();
+ TextBlockInfo * thisTbInfo = it.data();
+ int firstLoc = m_textBlockList.findRef(tblock);
+ ParaInfo * lastPi = thisTbInfo->m_paraList.last();
+
+ for(ParaInfo * pi = thisTbInfo->m_paraList.first(); pi; pi = thisTbInfo->m_paraList.next())
+ {
+ int minPara = pi->start+firstLoc;
+
+ // only worth doing if in range of the whole
+ // representation
+ if(!pi->start && (startLine > (lastPi->start+firstLoc+lastPi->size) || endLine < minPara) )
+ break;
+
+ // now, only for those paraInfo blocks which
+ // have exceeded our last line, we increase them
+ if(pi->start && minPara >= endLine )
+ pi->start += increase;
+
+ }
+ }
+
+ }
+
+ tbinfo->m_paraList.append(item);
+
+}
+
+void CodeEditor::appendText(TextBlockList * items)
+{
+
+ for (TextBlock *tb = items->first(); tb; tb = items->next())
+ {
+ // types of things we may cast our text block into
+ // This isnt efficient, and is a vote for recording
+ // code block types in an enumerated list somewhere,
+ // as well as a generic attribute "blockType" we could
+ // quickly access, rather than casting. -b.t.
+ HierarchicalCodeBlock * hb = dynamic_cast<HierarchicalCodeBlock *>(tb);
+ CodeMethodBlock * mb = 0;
+ CodeClassFieldDeclarationBlock * db = 0;
+ CodeBlockWithComments * cb = 0;
+ // CodeComment * cm = 0;
+ if(hb)
+ appendText(hb);
+ else if ( (mb = dynamic_cast<CodeMethodBlock*>(tb)) )
+ appendText(mb);
+ else if ( (db = dynamic_cast<CodeClassFieldDeclarationBlock*>(tb)) )
+ appendText(db);
+ else if ( (cb = dynamic_cast<CodeBlockWithComments*>(tb)) )
+ appendText(cb);
+ /*
+ // no! shouldn't be any 'naked' comments floating about. Always
+ // are assocated with a parent code block
+ else if ( (cm = dynamic_cast<CodeComment*>(tb)) )
+ appendText(cm);
+ */
+ else
+ appendText(tb); // no cast worked. Just do a text block
+ }
+
+}
+
+void CodeEditor::appendText (CodeComment * comment, TextBlock * parent, UMLObject * umlObj , const QString & componentName)
+{
+
+ if(!comment->getWriteOutText() && !m_showHiddenBlocks)
+ return;
+
+ QColor bgcolor = getState().nonEditBlockColor;
+ if(!comment->getWriteOutText() && m_showHiddenBlocks)
+ bgcolor = getState().hiddenColor;
+
+ QString indent = comment->getIndentationString();
+ QString text = comment->toString(); // use comment formatting, NOT formatMultiLineText(comment->toString(), indent, "\n");
+ if(!StringIsBlank(text))
+ insert(text,parent,true,getState().fontColor, bgcolor, umlObj, componentName);
+
+}
+
+void CodeEditor::appendText (CodeBlockWithComments * cb ) {
+
+ if(!cb->getWriteOutText() && !m_showHiddenBlocks)
+ return;
+
+ QString indent = cb->getIndentationString();
+ QString body = cb->formatMultiLineText (cb->getText(), indent, "\n");
+
+ QColor bgcolor = getState().editBlockColor;
+ QString componentName = QString("CodeBlock");
+
+ appendText(cb->getComment(), cb, 0, componentName);
+
+ if(!cb->getWriteOutText() && m_showHiddenBlocks)
+ bgcolor = getState().hiddenColor;
+
+ if(!StringIsBlank(body))
+ insert(body,cb,true,getState().fontColor,bgcolor,0);
+
+}
+
+void CodeEditor::appendText (CodeClassFieldDeclarationBlock * db ) {
+
+ if(!db->getWriteOutText() && !m_showHiddenBlocks)
+ return;
+
+ QString indent = db->getIndentationString();
+ QString body = db->formatMultiLineText (db->getText(), indent, "\n");
+
+ UMLObject * parentObj = db->getParentClassField()->getParentObject();
+
+ QColor bgcolor = getState().editBlockColor;
+ QString componentName = QString("");
+ if(parentObj)
+ {
+ if(db->getParentClassField()->parentIsAttribute()) {
+ componentName = parentDocName + "::attribute_field(" + parentObj->getName() + ')';
+ } else {
+ UMLRole * role = dynamic_cast<UMLRole*>(parentObj);
+ componentName = parentDocName + "::association_field(" + role->getName() + ')';
+ }
+ bgcolor = getState().umlObjectColor;
+ }
+
+ appendText(db->getComment(), db, parentObj,componentName);
+
+ if(!db->getWriteOutText() && m_showHiddenBlocks)
+ bgcolor = getState().hiddenColor;
+
+ if(!StringIsBlank(body))
+ insert(body,db,false,getState().fontColor,bgcolor,parentObj);
+
+
+}
+
+void CodeEditor::appendText (CodeMethodBlock * mb) {
+
+ // Note: IF CodeAccessors are hidden, we DON'T show
+ // it even when requested as the hiddeness of these methods
+ // should be controled by the class fields, not the user in the editor.
+ if(!mb->getWriteOutText() && (!m_showHiddenBlocks || dynamic_cast<CodeAccessorMethod*>(mb)))
+ return;
+
+ QColor bgcolor = getState().umlObjectColor;
+ QString indent = mb->getIndentationString();
+ QString bodyIndent = mb->getIndentationString(mb->getIndentationLevel()+1);
+
+ QString startText = mb->formatMultiLineText ( mb->getStartMethodText(), indent, "\n");
+ QString body = mb->formatMultiLineText (mb->getText(), bodyIndent, "\n");
+ QString endText = mb->formatMultiLineText( mb->getEndMethodText(), indent, "\n");
+
+ if(body.isEmpty())
+ body = " \n";
+
+ if(!mb->getWriteOutText() && m_showHiddenBlocks)
+ {
+ // it gets the 'hidden' color
+ bgcolor = getState().hiddenColor;
+ }
+
+ QString componentName = QString("<b>parentless method\?</b>");
+
+ // ugly, but we need to know if there is a parent object here.
+ CodeOperation * op = dynamic_cast<CodeOperation*>(mb);
+ CodeAccessorMethod * accessor = dynamic_cast<CodeAccessorMethod*>(mb);
+ UMLObject * parentObj = 0;
+ if(op)
+ {
+ parentObj = op->getParentOperation();
+ if(((UMLOperation*)parentObj)->isConstructorOperation())
+ componentName = parentDocName + "::operation("+ parentObj->getName()+") constructor method";
+ else
+ componentName = parentDocName + "::operation("+ parentObj->getName()+") method";
+ }
+ if(accessor)
+ {
+ parentObj = accessor->getParentObject();
+ if(accessor->getParentClassField()->parentIsAttribute()) {
+ componentName = parentDocName + "::attribute_field(" + parentObj->getName() + ") accessor method";
+ } else {
+ UMLRole * role = dynamic_cast<UMLRole*>(parentObj);
+ componentName = parentDocName + "::association_field(" + role->getName() + ") accessor method";
+ }
+
+ }
+
+ //appendText(mb->getComment(), mb, parentObj, componentName);
+ appendText(mb->getComment(), mb->getComment(), parentObj, componentName);
+
+ if(!StringIsBlank(startText))
+ insert(startText,mb,false,getState().fontColor,bgcolor,parentObj);
+ // always insert body for methods..IF we don't, we create a
+ // situation where the user cant edit the body (!)
+ insert(body,mb,true,getState().fontColor,bgcolor,parentObj);
+ if(!StringIsBlank(endText))
+ insert(endText,mb,false,getState().fontColor,bgcolor,parentObj);
+
+}
+
+void CodeEditor::appendText (TextBlock * tb) {
+
+ if(!tb->getWriteOutText() && !m_showHiddenBlocks)
+ return;
+
+ QColor bgcolor = getState().nonEditBlockColor;
+ if(!tb->getWriteOutText() && m_showHiddenBlocks)
+ bgcolor = getState().hiddenColor;
+
+ QString str = tb->toString();
+ insert(str,tb,false,getState().fontColor,bgcolor);
+
+}
+
+void CodeEditor::appendText(HierarchicalCodeBlock * hblock)
+{
+
+ if(!hblock->getWriteOutText() && !m_showHiddenBlocks)
+ return;
+
+ OwnedHierarchicalCodeBlock * test = dynamic_cast<OwnedHierarchicalCodeBlock *>(hblock);
+ UMLObject * parentObj = 0;
+ QString componentName = QString("");
+ QColor paperColor = getState().nonEditBlockColor;
+ if(test)
+ {
+ parentObj = test->getParentObject();
+ UMLClassifier *c = dynamic_cast<UMLClassifier*>(parentObj);
+ if (c) {
+ QString typeStr;
+ if (c->isInterface())
+ typeStr = "Interface";
+ else
+ typeStr = "Class";
+ componentName = parentDocName + "::" + typeStr + '(' + parentObj->getName() + ')';
+ } else {
+ componentName = parentDocName + "::UNKNOWN(" + parentObj->getName() + ')';
+ }
+
+ paperColor = getState().umlObjectColor;
+ }
+
+ if(!hblock->getWriteOutText() && m_showHiddenBlocks)
+ paperColor = getState().hiddenColor;
+
+ TextBlockList * items = hblock->getTextBlockList();
+ QString indent = hblock->getIndentationString();
+ QString startText = hblock->formatMultiLineText ( hblock->getStartText(), indent, "\n");
+ QString endText = hblock->formatMultiLineText( hblock->getEndText(), indent, "\n");
+
+ appendText(hblock->getComment(), hblock, parentObj, componentName);
+
+ if(!StringIsBlank(startText))
+ insert(startText,hblock,false,getState().fontColor,paperColor, parentObj);
+ appendText(items);
+ if(!StringIsBlank(endText))
+ insert(endText,hblock,false,getState().fontColor,paperColor);
+
+}
+
+void CodeEditor::insertParagraph ( const QString & text, int para )
+{
+ QTextEdit::insertParagraph(text,para);
+}
+
+void CodeEditor::removeParagraph ( int para )
+{
+ QTextEdit::removeParagraph(para);
+}
+
+// All umlobjects which may have pop-up boxes should return true here
+// Yes, a CRAPPY way of doing this. Im not proud. =b.t.
+bool CodeEditor::textBlockIsClickable(UMLObject * obj)
+{
+
+ if( dynamic_cast<UMLAttribute*>(obj) )
+ return true;
+ else if( dynamic_cast<UMLClassifier*>(obj) )
+ return true;
+ else if( dynamic_cast<UMLRole*>(obj) )
+ return true;
+ else if( dynamic_cast<UMLOperation*>(obj) )
+ return true;
+
+ return false;
+}
+
+void CodeEditor::slotChangeSelectedBlockView()
+{
+ TextBlock * tb = m_selectedTextBlock;
+ if(tb) {
+ tb->setWriteOutText(tb->getWriteOutText() ? false : true );
+ rebuildView(m_lastPara);
+ }
+
+}
+
+// change the status of the comment writeOutText value to
+// opposite of current value
+void CodeEditor::slotChangeSelectedBlockCommentView()
+{
+
+ TextBlock * tb = m_selectedTextBlock;
+ CodeBlockWithComments * cb = 0;
+ if(tb && (cb = dynamic_cast<CodeBlockWithComments*>(tb)))
+ {
+ cb->getComment()->setWriteOutText(cb->getComment()->getWriteOutText() ? false : true );
+ rebuildView( m_lastPara );
+ }
+
+}
+
+void CodeEditor::slotInsertCodeBlockBeforeSelected()
+{
+
+ TextBlock * tb = m_selectedTextBlock;
+ CodeBlockWithComments * newBlock = m_parentDoc->newCodeBlockWithComments();
+ newBlock->setText("<<INSERT>>");
+ newBlock->getComment()->setWriteOutText(false);
+
+ m_parentDoc->insertTextBlock(newBlock, tb, false);
+
+ int location = m_textBlockList.findRef(m_selectedTextBlock); // find first para of selected block
+
+ QString body = newBlock->formatMultiLineText (newBlock->getText(), newBlock->getIndentationString(), "\n");
+
+ insert(body,newBlock,true,getState().fontColor,
+ getState().editBlockColor,0,QString("CodeBlock"),location);
+
+}
+
+void CodeEditor::slotInsertCodeBlockAfterSelected()
+{
+
+ TextBlock * tb = m_selectedTextBlock;
+ CodeBlockWithComments * newBlock = m_parentDoc->newCodeBlockWithComments();
+ newBlock->setText("<<INSERT>>");
+ newBlock->getComment()->setWriteOutText(false);
+
+ m_parentDoc->insertTextBlock(newBlock, tb, true);
+
+ // find last para of selected block
+ TextBlockInfo *tbinfo = (*m_tbInfoMap)[m_selectedTextBlock];
+ ParaInfo * lastpi = tbinfo->m_paraList.last();
+ int location = m_textBlockList.findRef(m_selectedTextBlock) + lastpi->start + lastpi->size + 1;
+
+ QString body = newBlock->formatMultiLineText (newBlock->getText(), newBlock->getIndentationString(), "\n");
+
+ insert(body,newBlock,true,getState().fontColor,
+ getState().editBlockColor,0,QString("CodeBlock"),location);
+
+}
+
+QPopupMenu * CodeEditor::createPopupMenu ( const QPoint & pos )
+{
+
+ TextBlock * tb = m_selectedTextBlock;
+ m_lastPara = paragraphAt(pos);
+
+ QPopupMenu * menu = new QPopupMenu(this);
+ // ugh. A bug in the Qt interaction between QTextEdit and Menu
+ // can sometimes trigger a clear() call of the text area after
+ // the popup menu is destroyed. The workaround is to disable
+ // the behavior by blocking the destroy signal from the menu.
+ menu->blockSignals(true);
+
+ if (m_selectedTextBlock)
+ {
+ if(tb->getWriteOutText())
+ menu->insertItem("Hide",this,SLOT(slotChangeSelectedBlockView()), Key_H, 0);
+ else
+ menu->insertItem("Show",this,SLOT(slotChangeSelectedBlockView()), Key_S, 0);
+
+ CodeBlockWithComments * cb = dynamic_cast<CodeBlockWithComments*>(tb);
+ if(cb)
+ if(cb->getComment()->getWriteOutText())
+ menu->insertItem("Hide Comment",this,SLOT(slotChangeSelectedBlockCommentView()), CTRL+Key_H, 1);
+ else
+ menu->insertItem("Show Comment",this,SLOT(slotChangeSelectedBlockCommentView()), CTRL+Key_S, 1);
+ menu->insertSeparator();
+
+ menu->insertItem("Insert Code Block Before",this,SLOT(slotInsertCodeBlockBeforeSelected()), CTRL+Key_B, 2);
+ menu->insertItem("Insert Code Block After",this,SLOT(slotInsertCodeBlockAfterSelected()), CTRL+Key_A, 3);
+
+ menu->insertSeparator();
+
+ menu->insertItem("Copy",this,SLOT(slotCopyTextBlock()), CTRL+Key_C, 4);
+ menu->insertItem("Paste",this,SLOT(slotPasteTextBlock()), CTRL+Key_V, 5);
+ menu->insertItem("Cut",this,SLOT(slotCutTextBlock()), CTRL+Key_X, 6);
+
+ // enable/disable based on conditions
+ if(m_selectedTextBlock == m_parentDoc->getHeader())
+ menu->setItemEnabled (2, false);
+
+ if(!m_textBlockToPaste)
+ menu->setItemEnabled (5, false);
+
+ if(!tb->canDelete())
+ menu->setItemEnabled (6, false);
+
+ // manythings cant be copied. RIght now, lets just limit ourselves to
+ // owned things and hierarchicalcodeblocks
+ if(dynamic_cast<OwnedCodeBlock*>(m_selectedTextBlock) ||
+ dynamic_cast<HierarchicalCodeBlock*>(m_selectedTextBlock))
+ menu->setItemEnabled (4, false);
+
+ // TBD
+ // m_selectedTextBlock->insertCodeEditMenuItems(menu, this);
+ }
+
+ return menu;
+}
+
+void CodeEditor::slotCopyTextBlock ( )
+{
+ // make a copy
+ if(dynamic_cast<HierarchicalCodeBlock*>(m_selectedTextBlock))
+ m_textBlockToPaste = m_parentDoc->newHierarchicalCodeBlock();
+ else if(dynamic_cast<CodeBlockWithComments*>(m_selectedTextBlock))
+ m_textBlockToPaste = m_parentDoc->newCodeBlockWithComments();
+ else if(dynamic_cast<CodeBlock*>(m_selectedTextBlock))
+ m_textBlockToPaste = m_parentDoc->newCodeBlock();
+ else if(dynamic_cast<CodeComment*>(m_selectedTextBlock))
+ m_textBlockToPaste = CodeGenFactory::newCodeComment(m_parentDoc);
+ else
+ {
+ kError()<<" ERROR: CodeEditor can't copy selected block:"<<m_selectedTextBlock<<" of unknown type"<<endl;
+ m_textBlockToPaste = 0;
+ return; // error!
+ }
+
+ m_textBlockToPaste->setAttributesFromObject(m_selectedTextBlock);
+
+}
+
+void CodeEditor::slotCutTextBlock ( ) {
+
+ // make a copy first
+ slotCopyTextBlock();
+
+ // This could cause problems, but we are OK as
+ // long as we only try to delete 'canDelete' textblocks
+ if(m_selectedTextBlock->canDelete())
+ {
+ // just in case there are pending edits
+ // we don't want to lose them
+ if (m_lastTextBlockToBeEdited && m_lastTextBlockToBeEdited == (CodeBlock*) m_selectedTextBlock)
+ {
+ updateTextBlockFromText (m_lastTextBlockToBeEdited);
+ m_lastTextBlockToBeEdited = 0;
+ }
+
+ m_parentDoc->removeTextBlock(m_selectedTextBlock);
+ rebuildView(m_lastPara);
+ // removeTextBlock(m_selectedTextBlock);
+ m_selectedTextBlock = 0;
+ }
+
+}
+
+void CodeEditor::slotPasteTextBlock ( ) {
+
+ if(m_textBlockToPaste)
+ {
+ m_parentDoc->insertTextBlock(m_textBlockToPaste, m_selectedTextBlock);
+ m_textBlockToPaste = 0;
+ rebuildView(m_lastPara);
+ }
+
+}
+
+void CodeEditor::slotRedrawText() {
+ rebuildView(m_lastPara);
+}
+
+void CodeEditor::init ( CodeViewerDialog * parentDlg, CodeDocument * parentDoc ) {
+
+ // safety to insure that we are up to date
+ parentDoc->synchronize();
+
+ m_parentDlg = parentDlg;
+ m_parentDoc = parentDoc;
+
+ setUndoRedoEnabled( false );
+ setCursor( QCursor( 0 ) );
+ setMouseTracking( true );
+ setReadOnly (true);
+ m_isHighlighted = getState().blocksAreHighlighted;
+ m_showHiddenBlocks = getState().showHiddenBlocks;
+
+ m_newLinePressed = false;
+ m_backspacePressed = false;
+ m_textBlockToPaste = 0;
+ m_selectedTextBlock = 0;
+ m_lastTextBlockToBeEdited = 0;
+ m_tbInfoMap = new QMap<TextBlock *, TextBlockInfo*>;
+
+ setFont( getState().font );
+
+ // set name of parent doc
+ ClassifierCodeDocument * cdoc = dynamic_cast<ClassifierCodeDocument*>(m_parentDoc);
+ if(cdoc)
+ parentDocName = cdoc->getParentClassifier()->getName();
+ else
+ parentDocName = "";
+
+ // set some viewability parameters
+ //int margin = fontMetrics().height();
+
+ QBrush pbrush = QBrush ( getState().paperColor);
+ setPaper(pbrush);
+
+ // setMargin(margin);
+
+ // connect(this,SIGNAL(newLinePressed()),this,SLOT(newLinePressed()));
+ // connect(this,SIGNAL(backspacePressed()),this,SLOT(backspacePressed()));
+ connect(this,SIGNAL(doubleClicked(int,int)),this,SLOT(doubleClicked(int,int)));
+ connect(this,SIGNAL(cursorPositionChanged(int,int)),this,SLOT(cursorPositionChanged(int,int)));
+
+ // do this last
+ loadFromDocument();
+
+}
+
+void CodeEditor::updateTextBlockFromText (TextBlock * block) {
+
+ if (block) {
+
+ CodeMethodBlock * cmb = dynamic_cast<CodeMethodBlock*>(block);
+ //QString baseIndent = block->getNewEditorLine(block->getIndentationLevel()+(cmb ? 1 : 0));
+ QString baseIndent = block->getIndentationString(block->getIndentationLevel()+(cmb ? 1 : 0));
+
+ TextBlockInfo *info = (*m_tbInfoMap)[block];
+ UMLObject * parentObj = info->getParent();
+ int pstart = m_textBlockList.findRef(block);
+ QString content = "";
+
+ // Assemble content from editiable paras
+ QPtrList<ParaInfo> list = info->m_paraList;
+ for(ParaInfo * item = list.first(); item; item=list.next())
+ {
+ if(item->isEditable)
+ {
+ int lastpara = item->start+pstart+item->size;
+ int endEdit = block->lastEditableLine();
+ int lastLineToAddNewLine = lastpara + endEdit;
+ for(int para=(item->start+pstart);para<=lastpara;para++)
+ {
+ QString line = block->unformatText(text(para), baseIndent);
+ content += line;
+ // \n are implicit in the editor (!) so we should put them
+ // back in, if there is any content from the line
+ if(!line.isEmpty() && para != lastLineToAddNewLine)
+ content += "\n";
+ }
+ }
+ }
+
+ //cerr<<"UPDATE GOT CONTENT:["<<content.latin1()<<"] to block:"<<block<<endl;
+ block->setText(content);
+
+ // if a parent for the block, try to set its documentation
+ // as long as its NOT an accessor codeblock.
+ if(parentObj && !info->isCodeAccessorMethod)
+ parentObj->setDoc(content);
+
+ // make note that its now user generated
+ if(cmb)
+ cmb->setContentType(CodeBlock::UserGenerated);
+
+ }
+}
+
+void CodeEditor::cursorPositionChanged(int para, int pos)
+{
+
+ // safety.. this is endemic of a 'bad' pointer event and can crash us otherwise
+ if(pos < 0)
+ return;
+
+ // bool lastParaIsEditable = isReadOnly() ? false : true;
+ bool lastParaIsEditable = isParaEditable(m_lastPara);
+
+ // IF last para where cursor is coming from was editable
+ // we have a variety of things to look out for.
+ if(lastParaIsEditable)
+ {
+ // If we got here as the result of a newline, then expansion
+ // of a para editablity occurs.
+ if((para-1) == m_lastPara && m_newLinePressed )
+ expandSelectedParagraph ( m_lastPara );
+
+ // conversely, we contract the zone of editablity IF we
+ // got to current position as result of backspace
+ if((para+1) == m_lastPara && m_backspacePressed )
+ contractSelectedParagraph( para );
+
+ }
+
+ // now check if the current paragraph is really editiable, and if so,
+ // so some things
+ bool editPara = isParaEditable(para);
+ if(editPara) {
+
+ TextBlock * tBlock = m_textBlockList.at(para);
+ CodeMethodBlock * cmb = dynamic_cast<CodeMethodBlock*>(tBlock);
+
+ // auto-indent new lines
+ QString currentParaText = text(para);
+ QString baseIndent = tBlock->getNewEditorLine(tBlock->getIndentationLevel()+(cmb ? 1 : 0));
+ // cerr<<"AUTO INDENT:["<<baseIndent.latin1()<<"] isMethod?"<<(cmb?"true":"false")<<endl;
+ int minPos = baseIndent.length();
+
+ // add indent chars to the current line, if missing
+ if(!m_backspacePressed && !currentParaText.contains(QRegExp('^'+baseIndent)))
+ {
+ insertAt(baseIndent,para,0);
+ setCursorPosition(para,pos+minPos);
+ return;
+ }
+
+ if(pos<minPos)
+ {
+
+ bool priorParaIsEditable = isParaEditable(para-1);
+ if(m_backspacePressed && para && priorParaIsEditable)
+ {
+ int endOfPriorLine = paragraphLength(para-1);
+ // IN this case, we remove old (para) line, and tack its
+ // contents on the line we are going to.
+ QString contents = text(para);
+ contents = contents.right(contents.length()-m_lastPos+1);
+
+ // this next thing happens when we arent deleting last line
+ // of editable text, so we want to append whats left of this line
+ // onto the one we are backspacing into
+ if(paraIsNotSingleLine(para))
+ {
+ removeParagraph(para);
+ insertAt(contents,(para-1),endOfPriorLine);
+ setCursorPosition((para-1),endOfPriorLine);
+ }
+
+ } else {
+ // well, if the following is true, then they
+ // are trying to hack away at the last line, which
+ // we cant allow to entirely disappear. Lets preserve
+ // the indentation
+ if(m_backspacePressed && !priorParaIsEditable)
+ {
+ QString contents = text(para);
+ contents = contents.right(contents.length()-m_lastPos+1);
+ contents = baseIndent + contents.left(contents.length()-1); // left is to remove trailing space
+ insertParagraph(contents,para+1);
+ removeParagraph(para);
+
+ // furthermore, IF its nothing but indentation + whitespace
+ // we switch this back to Auto-Generated.
+ if(cmb && contents.contains(QRegExp('^'+baseIndent+"\\s$")))
+ {
+ cmb->setContentType(CodeBlock::AutoGenerated);
+ cmb->syncToParent();
+ }
+
+ }
+
+ // send them to the first spot in the line which is editable
+ setCursorPosition(para,minPos);
+
+ }
+ return;
+ }
+ }
+
+ // look for changes in editability, if they occur, we need to record
+ // the edits which have been made
+ if((editPara && !m_lastTextBlockToBeEdited) || (!editPara && m_lastTextBlockToBeEdited)) {
+
+ setReadOnly(editPara ? false : true);
+
+ // IF this is a different text block, update the body of the method
+ // it belongs to
+ if(m_lastTextBlockToBeEdited && (m_lastTextBlockToBeEdited != m_textBlockList.at(para) || !editPara))
+ {
+ updateTextBlockFromText (m_lastTextBlockToBeEdited);
+ m_lastTextBlockToBeEdited = 0;
+ }
+
+ if(editPara)
+ m_lastTextBlockToBeEdited = m_textBlockList.at(para);
+ else
+ m_lastTextBlockToBeEdited = 0;
+
+ }
+
+ m_lastPara = para;
+ m_lastPos = pos;
+ m_newLinePressed = false;
+ m_backspacePressed = false;
+
+}
+
+bool CodeEditor::paraIsNotSingleLine (int para)
+{
+ TextBlock * tBlock = m_textBlockList.at(para);
+ if(tBlock)
+ {
+ int pstart = m_textBlockList.findRef(tBlock);
+ TextBlockInfo *info = (*m_tbInfoMap)[tBlock];
+ QPtrList<ParaInfo> list = info->m_paraList;
+
+ for(ParaInfo * item = list.first(); item; item=list.next())
+ if((pstart+item->start) <= para && (item->start+pstart+item->size) >= para )
+ if(item->size > 0)
+ return true;
+ }
+ return false;
+}
+
+bool CodeEditor::isParaEditable (int para) {
+
+ if (para <0)
+ return false;
+
+ TextBlock * tBlock = m_textBlockList.at(para);
+ if(tBlock)
+ {
+ int editStart = tBlock->firstEditableLine();
+ int editEnd = tBlock->lastEditableLine();
+ bool hasEditableRange = (editStart > 0 || editEnd < 0) ? true : false;
+ TextBlockInfo *info = (*m_tbInfoMap)[tBlock];
+ int pstart = m_textBlockList.findRef(tBlock);
+ int relativeLine = para - pstart;
+ QPtrList<ParaInfo> list = info->m_paraList;
+ for(ParaInfo * item = list.first(); item; item=list.next())
+ {
+ if((item->start+pstart) <= para && (item->start+pstart+item->size) >= para)
+ if(item->isEditable && hasEditableRange)
+ {
+ if ( relativeLine >= editStart && relativeLine <= (item->size + editEnd) )
+ return true;
+ else
+ return false;
+ } else
+ return item->isEditable;
+ }
+ }
+ return false;
+}
+
+void CodeEditor::changeTextBlockHighlighting(TextBlock * tBlock, bool selected) {
+
+ if(tBlock)
+ {
+ TextBlockInfo *info = (*m_tbInfoMap)[tBlock];
+ QPtrList<ParaInfo> list = info->m_paraList;
+ int pstart = m_textBlockList.findRef(tBlock);
+ for(ParaInfo * item = list.first(); item; item=list.next())
+ for(int p=(item->start+pstart);p<=(item->start+pstart+item->size);p++)
+ if(selected)
+ if(info->isClickable)
+ setParagraphBackgroundColor(p,getState().selectedColor);
+ else
+ setParagraphBackgroundColor(p,getState().nonEditBlockColor);
+ else if(m_isHighlighted)
+ setParagraphBackgroundColor(p,item->bgcolor);
+ else
+ setParagraphBackgroundColor(p,getState().paperColor);
+ }
+
+}
+
+void CodeEditor::changeShowHidden (int signal) {
+
+ if(signal)
+ m_showHiddenBlocks = true;
+ else
+ m_showHiddenBlocks = false;
+
+ rebuildView(m_lastPara);
+
+}
+
+// colorizes/uncolorizes type for ALL paragraphs
+void CodeEditor::changeHighlighting(int signal) {
+
+ int total_para = paragraphs()-1;
+ if(signal) {
+ // we want to highlight
+ m_isHighlighted = true;
+ for(int para=0;para<total_para;para++)
+ {
+ TextBlock * tblock = m_textBlockList.at(para);
+ changeTextBlockHighlighting(tblock,false);
+ }
+
+
+ } else {
+ // we DON'T want to highlight
+ m_isHighlighted = false;
+ for(int para=0;para<total_para;para++)
+ setParagraphBackgroundColor(para,getState().paperColor);
+ }
+
+ // now redo the "selected" para, should it exist
+ if(m_selectedTextBlock)
+ changeTextBlockHighlighting(m_selectedTextBlock,true);
+
+}
+
+void CodeEditor::contractSelectedParagraph( int paraToRemove ) {
+ TextBlock * tBlock = m_textBlockList.at(paraToRemove);
+ if(tBlock)
+ {
+ int pstart = m_textBlockList.findRef(tBlock);
+ TextBlockInfo *info = (*m_tbInfoMap)[tBlock];
+ QPtrList<ParaInfo> list = info->m_paraList;
+
+ bool lowerStartPosition = false;
+ for(ParaInfo * item = list.first(); item; item=list.next())
+ {
+ if(lowerStartPosition)
+ item->start -= 1;
+
+ if((pstart+item->start) <= paraToRemove && (item->start+pstart+item->size) >= paraToRemove)
+ {
+ item->size -= 1;
+ // a little cheat.. we don't want to remove last line as we need
+ // to leave a place that can be 'edited' by the tool IF the user
+ // changes their mind about method body content
+ if(item->size < 0)
+ item->size = 0;
+ lowerStartPosition = true;
+ }
+ }
+
+ m_textBlockList.remove(paraToRemove);
+ }
+}
+
+void CodeEditor::expandSelectedParagraph( int priorPara ) {
+
+
+ TextBlock * tBlock = m_textBlockList.at(priorPara);
+ if(tBlock)
+ {
+ // add this tBlock in
+ m_textBlockList.insert(priorPara,tBlock);
+ TextBlockInfo *info = (*m_tbInfoMap)[tBlock];
+ QPtrList<ParaInfo> list = info->m_paraList;
+ int pstart = m_textBlockList.findRef(tBlock);
+
+ // now update the paragraph information
+ bool upStartPosition = false;
+ for(ParaInfo * item = list.first(); item; item=list.next())
+ {
+ // AFTER we get a match, then following para's need to have start position upped too
+ if(upStartPosition)
+ item->start += 1;
+
+ if((pstart+item->start) <= priorPara && (item->start+pstart+item->size) >= priorPara)
+ {
+ item->size += 1;
+ cursorPositionChanged(m_lastPara, m_lastPos);
+ upStartPosition = true;
+ }
+ }
+ }
+
+}
+
+void CodeEditor::contentsMouseMoveEvent ( QMouseEvent * e )
+{
+
+ int para = paragraphAt(e->pos());
+
+ if (para < 0)
+ return; // shouldn't happen..
+
+ TextBlock * tblock = m_textBlockList.at(para);
+ if (tblock && m_selectedTextBlock != tblock ) {
+ TextBlockInfo * info = (*m_tbInfoMap)[tblock];
+
+ // unhighlight old selected textblock regardless of whether
+ // it was selected or not.
+ changeTextBlockHighlighting(m_selectedTextBlock,false);
+
+ // highlight new block
+ changeTextBlockHighlighting(tblock,true);
+
+ // FIX: update the label that shows what type of component this is
+ getComponentLabel()->setText("<b>"+info->displayName+"</b>");
+
+ m_selectedTextBlock = tblock;
+
+ if(m_lastTextBlockToBeEdited)
+ {
+ updateTextBlockFromText (m_lastTextBlockToBeEdited);
+ m_lastTextBlockToBeEdited = 0;
+ }
+ }
+
+ // record this as the last paragraph
+
+}
+
+
+// Rebuild our view of the document. Happens whenever we change
+// some field/aspect of an underlying UML object used to create
+// the view.
+// If connections are right, then the UMLObject will send out the modified()
+// signal which will trigger a call to re-generate the appropriate code within
+// the code document. Our burden is to appropriately prepare the tool: we clear
+// out ALL the textblocks in the QTextEdit widget and then re-show them
+// after the dialog disappears
+void CodeEditor::rebuildView( int startCursorPos ) {
+
+ loadFromDocument();
+
+ // make a minima attempt to leave the cursor (view of the code) where
+ // we started
+ int new_nrof_para = paragraphs() -1;
+ setCursorPosition((startCursorPos < new_nrof_para ? startCursorPos : 0), 0);
+
+}
+
+
+
+
+#include "codeeditor.moc"
diff --git a/umbrello/umbrello/dialogs/codeeditor.h b/umbrello/umbrello/dialogs/codeeditor.h
new file mode 100644
index 00000000..57f1fb37
--- /dev/null
+++ b/umbrello/umbrello/dialogs/codeeditor.h
@@ -0,0 +1,191 @@
+
+/***************************************************************************
+ codeeditor.h - description
+ -------------------
+ begin : Fri Aug 1 2003
+ copyright : (C) 2003 by Brian Thomas
+ email : brian.thomas@gsfc.nasa.gov
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the 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 CODEEDITOR_H
+#define CODEEDITOR_H
+
+#include <qpopupmenu.h>
+#include <qstring.h>
+#include <qlabel.h>
+#include <qtextedit.h>
+#include "../codeviewerstate.h"
+#include "../textblocklist.h"
+
+class UMLObject;
+
+class CodeViewerDialog;
+class CodeComment;
+class CodeDocument;
+class CodeClassFieldDeclarationBlock;
+class CodeMethodBlock;
+class CodeBlockWithComments;
+class HierarchicalCodeBlock;
+
+class TextBlockInfo;
+class TextBlock;
+class ParaInfo;
+
+class CodeEditor : public QTextEdit
+{
+ Q_OBJECT
+public:
+
+ explicit CodeEditor ( const QString & text, const QString & context = QString(), CodeViewerDialog * parent = 0, const char * name = 0 , CodeDocument * doc = 0);
+ explicit CodeEditor ( CodeViewerDialog * parent, const char* name = 0, CodeDocument * doc = 0);
+ ~CodeEditor ();
+
+ // return code viewer state
+ Settings::CodeViewerState getState( );
+
+protected:
+
+ bool close ( bool alsoDelete );
+
+ // various methods for appending various types of text blocks in the editor.
+ void appendText (TextBlock * tblock);
+ void appendText (HierarchicalCodeBlock * hblock);
+ void appendText (CodeClassFieldDeclarationBlock * db );
+ void appendText (TextBlockList * items);
+ void appendText (CodeMethodBlock * mb);
+ void appendText (CodeComment * comment, TextBlock * parent, UMLObject * umlObj = 0, const QString & compName="");
+ void appendText (CodeBlockWithComments * cb );
+
+ // Rebuild our view of the document. Happens whenever we change
+ // some field/aspect of an underlying UML object used to create
+ // the view.
+ // If connections are right, then the UMLObject will send out the modified()
+ // signal which will trigger a call to re-generate the appropriate code within
+ // the code document. Our burden is to appropriately prepare the tool: we clear
+ // out ALL the textblocks in the QTextEdit widget and then re-show them
+ // after the dialog disappears
+ void rebuildView( int startCursorPos );
+
+ // override the QT event so we can do appropriate things
+ void contentsMouseMoveEvent ( QMouseEvent * e );
+
+ // implemented so we may capture certain key presses, namely backspace
+ // and 'return' events.
+ void keyPressEvent ( QKeyEvent * e );
+
+ // (re) load the parent code document into the editor
+ void loadFromDocument();
+
+ // specialized popup menu for our tool
+ QPopupMenu * createPopupMenu ( const QPoint & pos );
+
+private:
+
+ QString parentDocName;
+ CodeDocument * m_parentDoc;
+ CodeViewerDialog * m_parentDlg;
+
+ int m_lastPara;
+ int m_lastPos;
+
+ bool m_newLinePressed;
+ bool m_backspacePressed;
+ bool m_isHighlighted;
+ bool m_showHiddenBlocks;
+
+ TextBlock * m_textBlockToPaste;
+ TextBlock * m_selectedTextBlock;
+ TextBlock * m_lastTextBlockToBeEdited;
+
+ QMap<TextBlock*, TextBlockInfo*> *m_tbInfoMap;
+ TextBlockList m_textBlockList;
+
+ // main insert routine. Will append if startline is not supplied.
+ void insert (const QString & text, TextBlock * parent, bool isEditable = false,
+ const QColor & fgcolor = QColor("black"), const QColor & bgcolor = QColor("white"),
+ UMLObject * umlobj = 0, const QString & displayName = "", int startLine = -1);
+
+ void editTextBlock(TextBlock * tBlock, int para);
+ void clearText();
+ QLabel * getComponentLabel();
+ bool paraIsNotSingleLine (int para);
+ void expandSelectedParagraph( int where );
+ void contractSelectedParagraph( int where );
+ void updateTextBlockFromText (TextBlock * block);
+
+ void initText ( CodeDocument * doc );
+ void init ( CodeViewerDialog * parentDlg, CodeDocument * parentDoc );
+
+ void changeTextBlockHighlighting(TextBlock * tb, bool selected);
+ bool isParaEditable (int para);
+ bool textBlockIsClickable(UMLObject * obj);
+
+ // return whether or not the passed string is empty or
+ // contains nothing but whitespace
+ static bool StringIsBlank( const QString &str );
+
+public slots:
+
+ void insertParagraph ( const QString & text, int para );
+ void removeParagraph ( int para );
+ void changeHighlighting(int signal);
+ void changeShowHidden (int signal);
+ void slotRedrawText();
+
+protected slots:
+
+ void clicked(int para, int pos );
+ void doubleClicked(int para, int pos );
+ void cursorPositionChanged(int para, int pos );
+ void slotCopyTextBlock ( );
+ void slotCutTextBlock ( );
+ void slotPasteTextBlock ( );
+ void slotChangeSelectedBlockView();
+ void slotChangeSelectedBlockCommentView();
+ void slotInsertCodeBlockAfterSelected();
+ void slotInsertCodeBlockBeforeSelected();
+
+signals:
+
+ /*
+ void sigNewLinePressed ();
+ void sigBackspacePressed ();
+ */
+
+};
+
+class ParaInfo {
+public:
+ int start; // this is a relative offset from the beginning of the tblock
+ int size;
+ QColor fgcolor;
+ QColor bgcolor;
+ bool isEditable;
+
+ ParaInfo () { isEditable = false; }
+};
+
+class TextBlockInfo {
+public:
+ QPtrList<ParaInfo> m_paraList;
+ UMLObject * m_parent;
+ QString displayName;
+ bool isClickable;
+ bool isCodeAccessorMethod;
+
+ TextBlockInfo () { m_parent = 0; isClickable = false; isCodeAccessorMethod = false; }
+ void setParent(UMLObject *p = 0) { m_parent = p; }
+ UMLObject * getParent() { return m_parent; }
+
+};
+
+#endif // CODEEDITOR_H
diff --git a/umbrello/umbrello/dialogs/codegenerationoptionsbase.ui b/umbrello/umbrello/dialogs/codegenerationoptionsbase.ui
new file mode 100644
index 00000000..f0df1e17
--- /dev/null
+++ b/umbrello/umbrello/dialogs/codegenerationoptionsbase.ui
@@ -0,0 +1,533 @@
+<!DOCTYPE UI><UI version="3.1" stdsetdef="1">
+<class>CodeGenerationOptionsBase</class>
+<widget class="QWidget">
+ <property name="name">
+ <cstring>CodeGenerationOptionsBase</cstring>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>581</width>
+ <height>525</height>
+ </rect>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>3</hsizetype>
+ <vsizetype>3</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="caption">
+ <string>Code Generation Options</string>
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QTabWidget" row="0" column="0">
+ <property name="name">
+ <cstring>tabWidget</cstring>
+ </property>
+ <property name="enabled">
+ <bool>true</bool>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>5</hsizetype>
+ <vsizetype>5</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <widget class="QWidget">
+ <property name="name">
+ <cstring>tab</cstring>
+ </property>
+ <attribute name="title">
+ <string>General</string>
+ </attribute>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>layout1</cstring>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QGroupBox">
+ <property name="name">
+ <cstring>m_SelectLanguageGroup</cstring>
+ </property>
+ <property name="title">
+ <string>Language</string>
+ </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="QComboBox">
+ <property name="name">
+ <cstring>m_SelectLanguageBox</cstring>
+ </property>
+ </widget>
+ </hbox>
+ </widget>
+ <widget class="QGroupBox">
+ <property name="name">
+ <cstring>GroupBox1</cstring>
+ </property>
+ <property name="title">
+ <string>Folders</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" rowspan="1" colspan="2">
+ <property name="name">
+ <cstring>TextLabel2</cstring>
+ </property>
+ <property name="text">
+ <string>Write all generated files to folder:</string>
+ </property>
+ </widget>
+ <widget class="QPushButton" row="1" column="2">
+ <property name="name">
+ <cstring>m_browseOutput</cstring>
+ </property>
+ <property name="text">
+ <string>Bro&amp;wse...</string>
+ </property>
+ </widget>
+ <widget class="QPushButton" row="3" column="2">
+ <property name="name">
+ <cstring>m_browseHeadings</cstring>
+ </property>
+ <property name="text">
+ <string>B&amp;rowse...</string>
+ </property>
+ </widget>
+ <widget class="QCheckBox" row="2" column="0" rowspan="1" colspan="2">
+ <property name="name">
+ <cstring>m_includeHeadings</cstring>
+ </property>
+ <property name="text">
+ <string>&amp;Include heading files from folder:</string>
+ </property>
+ <property name="checked">
+ <bool>true</bool>
+ </property>
+ </widget>
+ <widget class="QLineEdit" row="1" column="1">
+ <property name="name">
+ <cstring>m_outputDir</cstring>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>Files generated by Code Generator will be written to this folder</string>
+ </property>
+ </widget>
+ <widget class="QLineEdit" row="3" column="1">
+ <property name="name">
+ <cstring>m_headingsDir</cstring>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>Files in this folder will be used as heading files in the generated code</string>
+ </property>
+ </widget>
+ <spacer row="1" column="0">
+ <property name="name">
+ <cstring>Spacer1</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Fixed</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>30</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ <spacer row="3" column="0">
+ <property name="name">
+ <cstring>Spacer2</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Fixed</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>30</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </grid>
+ </widget>
+ <widget class="QButtonGroup">
+ <property name="name">
+ <cstring>m_overwriteGroup</cstring>
+ </property>
+ <property name="title">
+ <string>Overwrite Policy</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="QLabel">
+ <property name="name">
+ <cstring>TextLabel1</cstring>
+ </property>
+ <property name="text">
+ <string>If a file with the same name as the name code
+generator wants to use as output file already exists:</string>
+ </property>
+ </widget>
+ <widget class="QRadioButton">
+ <property name="name">
+ <cstring>m_overwrite</cstring>
+ </property>
+ <property name="text">
+ <string>O&amp;verwrite</string>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>Overwrite existing files if they exist in the destination folder</string>
+ </property>
+ </widget>
+ <widget class="QRadioButton">
+ <property name="name">
+ <cstring>m_ask</cstring>
+ </property>
+ <property name="text">
+ <string>As&amp;k</string>
+ </property>
+ <property name="checked">
+ <bool>true</bool>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>If a file with the same name already exists, ask what to do</string>
+ </property>
+ </widget>
+ <widget class="QRadioButton">
+ <property name="name">
+ <cstring>m_changeName</cstring>
+ </property>
+ <property name="text">
+ <string>&amp;Use a different name</string>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>If a file already exists in the destination folder, select a different name to use by adding a suffix to the file name</string>
+ </property>
+ </widget>
+ </vbox>
+ </widget>
+ </vbox>
+ </widget>
+ </vbox>
+ </widget>
+ <widget class="QWidget">
+ <property name="name">
+ <cstring>tab</cstring>
+ </property>
+ <attribute name="title">
+ <string>Formatting</string>
+ </attribute>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLayoutWidget" row="0" column="0">
+ <property name="name">
+ <cstring>layout8</cstring>
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QGroupBox" row="1" column="0">
+ <property name="name">
+ <cstring>groupBox5</cstring>
+ </property>
+ <property name="title">
+ <string>Lines</string>
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <spacer row="0" column="0">
+ <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>16</width>
+ <height>30</height>
+ </size>
+ </property>
+ </spacer>
+ <spacer row="2" column="0">
+ <property name="name">
+ <cstring>spacer3_2_2</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>16</width>
+ <height>30</height>
+ </size>
+ </property>
+ </spacer>
+ <spacer row="1" column="0">
+ <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>16</width>
+ <height>30</height>
+ </size>
+ </property>
+ </spacer>
+ <widget class="QLabel" row="2" column="1">
+ <property name="name">
+ <cstring>textLabel3</cstring>
+ </property>
+ <property name="text">
+ <string>Line ending style:</string>
+ </property>
+ </widget>
+ <widget class="QLabel" row="0" column="1" rowspan="1" colspan="2">
+ <property name="name">
+ <cstring>textLabel1</cstring>
+ </property>
+ <property name="text">
+ <string>Indentation type:</string>
+ </property>
+ </widget>
+ <widget class="QLabel" row="1" column="1" rowspan="1" colspan="3">
+ <property name="name">
+ <cstring>textLabel2</cstring>
+ </property>
+ <property name="text">
+ <string>Indentation amount:</string>
+ </property>
+ </widget>
+ <widget class="QComboBox" row="2" column="2" rowspan="1" colspan="3">
+ <item>
+ <property name="text">
+ <string>*NIX ("\n")</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>Windows ("\r\n")</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>Mac ("\r")</string>
+ </property>
+ </item>
+ <property name="name">
+ <cstring>m_SelectEndLineCharsBox</cstring>
+ </property>
+ </widget>
+ <widget class="QComboBox" row="0" column="3" rowspan="1" colspan="2">
+ <item>
+ <property name="text">
+ <string>No Indentation</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>Tab</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>Space</string>
+ </property>
+ </item>
+ <property name="name">
+ <cstring>m_SelectIndentationTypeBox</cstring>
+ </property>
+ </widget>
+ <widget class="KIntNumInput" row="1" column="4">
+ <property name="name">
+ <cstring>m_SelectIndentationNumber</cstring>
+ </property>
+ </widget>
+ </grid>
+ </widget>
+ <widget class="QGroupBox" row="0" column="0">
+ <property name="name">
+ <cstring>GroupBox3</cstring>
+ </property>
+ <property name="title">
+ <string>Comment Verbosity</string>
+ </property>
+ <widget class="QCheckBox">
+ <property name="name">
+ <cstring>m_forceSections</cstring>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>10</x>
+ <y>60</y>
+ <width>446</width>
+ <height>52</height>
+ </rect>
+ </property>
+ <property name="text">
+ <string>Write comments &amp;for sections even if section
+is empty</string>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>Writes comments to indicate the different sections (public, private etc) in a class, even if the sections are empty</string>
+ </property>
+ </widget>
+ <widget class="QCheckBox">
+ <property name="name">
+ <cstring>m_forceDoc</cstring>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>11</x>
+ <y>29</y>
+ <width>446</width>
+ <height>28</height>
+ </rect>
+ </property>
+ <property name="text">
+ <string>&amp;Write documentation comments even if empty</string>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>Write comments &amp;for class and method documentation even if empty</string>
+ </property>
+ </widget>
+ </widget>
+ </grid>
+ </widget>
+ </grid>
+ </widget>
+ <widget class="QWidget">
+ <property name="name">
+ <cstring>tab</cstring>
+ </property>
+ <attribute name="title">
+ <string>Language Options</string>
+ </attribute>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QFrame" row="0" column="0">
+ <property name="name">
+ <cstring>languageOptionsFrame</cstring>
+ </property>
+ <property name="frameShape">
+ <enum>StyledPanel</enum>
+ </property>
+ <property name="frameShadow">
+ <enum>Raised</enum>
+ </property>
+ </widget>
+ </grid>
+ </widget>
+ </widget>
+ </grid>
+</widget>
+<customwidgets>
+</customwidgets>
+<connections>
+ <connection>
+ <sender>m_includeHeadings</sender>
+ <signal>toggled(bool)</signal>
+ <receiver>m_browseHeadings</receiver>
+ <slot>setEnabled(bool)</slot>
+ </connection>
+ <connection>
+ <sender>m_includeHeadings</sender>
+ <signal>toggled(bool)</signal>
+ <receiver>m_headingsDir</receiver>
+ <slot>setEnabled(bool)</slot>
+ </connection>
+ <connection>
+ <sender>m_browseOutput</sender>
+ <signal>clicked()</signal>
+ <receiver>CodeGenerationOptionsBase</receiver>
+ <slot>browseClicked()</slot>
+ </connection>
+ <connection>
+ <sender>m_browseHeadings</sender>
+ <signal>clicked()</signal>
+ <receiver>CodeGenerationOptionsBase</receiver>
+ <slot>browseClicked()</slot>
+ </connection>
+ <connection>
+ <sender>m_SelectLanguageBox</sender>
+ <signal>activated(int)</signal>
+ <receiver>CodeGenerationOptionsBase</receiver>
+ <slot>activeLanguageChanged(int)</slot>
+ </connection>
+</connections>
+<slots>
+ <slot access="protected">browseClicked()</slot>
+ <slot access="protected">activeLanguageChanged(int id)</slot>
+</slots>
+<layoutdefaults spacing="6" margin="11"/>
+<includehints>
+ <includehint>knuminput.h</includehint>
+ <includehint>knuminput.h</includehint>
+</includehints>
+</UI>
diff --git a/umbrello/umbrello/dialogs/codegenerationoptionspage.cpp b/umbrello/umbrello/dialogs/codegenerationoptionspage.cpp
new file mode 100644
index 00000000..f3dc25be
--- /dev/null
+++ b/umbrello/umbrello/dialogs/codegenerationoptionspage.cpp
@@ -0,0 +1,188 @@
+/***************************************************************************
+ begin : Thu Jul 25 2002
+ copyright : (C) 2002 by Luis De la Parra
+ email : luis@delaparra.org
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * copyright (C) 2003-2006 *
+ * Umbrello UML Modeller Authors <uml-devel@uml.sf.net> *
+ ***************************************************************************/
+// own header
+#include "codegenerationoptionspage.h"
+// qt/kde includes
+#include <qcheckbox.h>
+#include <kdebug.h>
+// app includes
+#include "../codegenerator.h"
+#include "codegenerationpolicypage.h"
+#include "../codegenerators/codegenpolicyext.h"
+#include "defaultcodegenpolicypage.h"
+#include "../model_utils.h"
+#include "../uml.h"
+
+//kde include
+#include <knuminput.h>
+#include <kfiledialog.h>
+#include <klocale.h>
+
+//qt include
+#include <qlineedit.h>
+#include <qlistview.h>
+#include <qbuttongroup.h>
+
+CodeGenerationOptionsPage::CodeGenerationOptionsPage(QWidget *parent)
+ : CodeGenerationOptionsBase(parent)
+{
+ init();
+}
+
+CodeGenerationOptionsPage::~CodeGenerationOptionsPage() { }
+
+void CodeGenerationOptionsPage::init()
+{
+ m_pCodePolicyPage = 0;
+
+ CodeGenerationPolicy *policy = UMLApp::app()->getCommonPolicy();
+ m_parentPolicy = policy;
+ CodeGenerator *gen = UMLApp::app()->getGenerator();
+
+ m_forceDoc->setChecked(policy->getCodeVerboseDocumentComments());
+ m_forceSections->setChecked(policy->getCodeVerboseSectionComments());
+
+ m_outputDir->setText(policy->getOutputDirectory().absPath());
+ m_includeHeadings->setChecked(policy->getIncludeHeadings());
+ m_headingsDir->setText(policy->getHeadingFileDir());
+ m_overwriteGroup->setButton(overwriteToInteger(policy->getOverwritePolicy()));
+
+ m_SelectEndLineCharsBox->setCurrentItem(newLineToInteger(policy->getLineEndingType()));
+ m_SelectIndentationTypeBox->setCurrentItem(indentTypeToInteger(policy->getIndentationType()));
+ m_SelectIndentationNumber->setValue(policy->getIndentationAmount());
+
+ connect(this,SIGNAL(syncCodeDocumentsToParent()),gen,SLOT(syncCodeToDocument()));
+
+ // now insert the language-dependant page, should there be one
+ updateCodeGenerationPolicyTab();
+
+ setupActiveLanguageBox();
+}
+
+void CodeGenerationOptionsPage::setupActiveLanguageBox()
+{
+ int indexCounter = 0;
+ while (indexCounter < Uml::pl_Reserved) {
+ QString language = Model_Utils::progLangToString((Uml::Programming_Language) indexCounter);
+ m_SelectLanguageBox->insertItem(language, indexCounter);
+ indexCounter++;
+ }
+ m_SelectLanguageBox->setCurrentItem(UMLApp::app()->getActiveLanguage());
+}
+
+int CodeGenerationOptionsPage::indentTypeToInteger(CodeGenerationPolicy::IndentationType value) {
+ switch (value) {
+ case CodeGenerationPolicy::SPACE:
+ return 2;
+ case CodeGenerationPolicy::TAB:
+ return 1;
+ default:
+ case CodeGenerationPolicy::NONE:
+ return 0;
+ }
+}
+
+int CodeGenerationOptionsPage::newLineToInteger(CodeGenerationPolicy::NewLineType value) {
+ switch (value) {
+ case CodeGenerationPolicy::DOS:
+ return 1;
+ case CodeGenerationPolicy::MAC:
+ return 2;
+ default:
+ case CodeGenerationPolicy::UNIX:
+ return 0;
+ }
+}
+
+//0 = overwrite, 1 = ask, 2 = change name
+int CodeGenerationOptionsPage::overwriteToInteger(CodeGenerationPolicy::OverwritePolicy value) {
+ switch (value) {
+ case CodeGenerationPolicy::Ok:
+ return 0;
+ case CodeGenerationPolicy::Never:
+ return 2;
+ default:
+ case CodeGenerationPolicy::Ask:
+ return 1;
+ }
+}
+
+void CodeGenerationOptionsPage::updateCodeGenerationPolicyTab() {
+
+ if(m_pCodePolicyPage)
+ {
+ m_pCodePolicyPage->disconnect();
+ m_pCodePolicyPage = 0;
+ }
+
+ CodeGenPolicyExt *policyExt = UMLApp::app()->getPolicyExt();
+ if (policyExt)
+ m_pCodePolicyPage = policyExt->createPage(languageOptionsFrame, "codelangpolicypage");
+ else
+ m_pCodePolicyPage = new DefaultCodeGenPolicyPage(languageOptionsFrame, "codelangpolicypage");
+
+ connect(this,SIGNAL(applyClicked()),m_pCodePolicyPage,SLOT(apply()));
+
+}
+
+void CodeGenerationOptionsPage::apply() {
+
+ if(m_parentPolicy) {
+
+ m_parentPolicy->setCodeVerboseDocumentComments(m_forceDoc->isChecked());
+ m_parentPolicy->setCodeVerboseSectionComments(m_forceSections->isChecked());
+ m_parentPolicy->setOutputDirectory(QDir(m_outputDir->text()));
+ m_parentPolicy->setIncludeHeadings(m_includeHeadings->isChecked());
+ m_parentPolicy->setHeadingFileDir(m_headingsDir->text());
+ m_parentPolicy->setOverwritePolicy((CodeGenerationPolicy::OverwritePolicy)m_overwriteGroup->id(m_overwriteGroup->selected()));
+ m_parentPolicy->setLineEndingType((CodeGenerationPolicy::NewLineType) m_SelectEndLineCharsBox->currentItem());
+ m_parentPolicy->setIndentationType((CodeGenerationPolicy::IndentationType) m_SelectIndentationTypeBox->currentItem());
+ m_parentPolicy->setIndentationAmount(m_SelectIndentationNumber->value());
+
+ // emit in THIS order.. the first signal triggers any sub-class to do its apply
+ // slot, THEN, once we are all updated, we may sync the parent generator's code
+ // documents
+ emit applyClicked();
+ emit syncCodeDocumentsToParent();
+ }
+}
+
+void CodeGenerationOptionsPage::activeLanguageChanged(int /*id*/)
+{
+ emit languageChanged();
+}
+
+void CodeGenerationOptionsPage::setDefaults() {
+}
+
+void CodeGenerationOptionsPage::browseClicked() {
+
+ QString button = sender()->name();
+ QString dir = KFileDialog::getExistingDirectory();
+ if(dir.isEmpty())
+ return;
+ if(button=="m_browseOutput")
+ m_outputDir->setText(dir);
+ else if(button=="m_browseHeadings")
+ m_headingsDir->setText(dir);
+}
+
+QString CodeGenerationOptionsPage::getCodeGenerationLanguage() {
+ return m_SelectLanguageBox->currentText();
+}
+
+#include "codegenerationoptionspage.moc"
diff --git a/umbrello/umbrello/dialogs/codegenerationoptionspage.h b/umbrello/umbrello/dialogs/codegenerationoptionspage.h
new file mode 100644
index 00000000..ff939d08
--- /dev/null
+++ b/umbrello/umbrello/dialogs/codegenerationoptionspage.h
@@ -0,0 +1,74 @@
+/***************************************************************************
+ codegenerationoptionspage.h - description
+ -------------------
+ begin : Thu Jul 25 2002
+ copyright : (C) 2002 by Luis De la Parra
+ email : luis@delaparra.org
+ Bugs and comments to uml-devel@lists.sf.net or http://bugs.kde.org
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * copyright (C) 2003-2006 *
+ * Umbrello UML Modeller Authors <uml-devel@uml.sf.net> *
+ ***************************************************************************/
+
+#ifndef CODEGENERATIONOPTIONSPAGE_H
+#define CODEGENERATIONOPTIONSPAGE_H
+
+#include <qwidget.h>
+#include "codegenerationoptionsbase.h"
+#include "../codegenerationpolicy.h"
+#include "../umlnamespace.h"
+
+/**
+ * @author Luis De la Parra
+ * @author Brian Thomas
+ */
+
+class CodeGenerationPolicy;
+class CodeGenerationPolicyPage;
+
+// 2003-07-30 : Updated for new code generation system. No longer need Yucky codegenstate
+// structure.
+
+class CodeGenerationOptionsPage : public CodeGenerationOptionsBase {
+ Q_OBJECT
+public:
+ CodeGenerationOptionsPage(QWidget *parent=0);
+ ~CodeGenerationOptionsPage();
+ void setDefaults();
+ QString getCodeGenerationLanguage();
+ void updateCodeGenerationPolicyTab();
+ void apply();
+
+protected:
+ CodeGenerationPolicy * m_parentPolicy;
+
+private:
+
+ CodeGenerationPolicyPage * m_pCodePolicyPage;
+ void init();
+ int overwriteToInteger(CodeGenerationPolicy::OverwritePolicy value);
+ int newLineToInteger(CodeGenerationPolicy::NewLineType value);
+ int indentTypeToInteger(CodeGenerationPolicy::IndentationType value);
+ void setupActiveLanguageBox();
+
+protected slots:
+ void activeLanguageChanged(int id);
+ void browseClicked();
+
+signals:
+ void applyClicked();
+ void languageChanged();
+ void syncCodeDocumentsToParent();
+
+
+};
+
+#endif
diff --git a/umbrello/umbrello/dialogs/codegenerationpolicybase.ui b/umbrello/umbrello/dialogs/codegenerationpolicybase.ui
new file mode 100644
index 00000000..bbc739a7
--- /dev/null
+++ b/umbrello/umbrello/dialogs/codegenerationpolicybase.ui
@@ -0,0 +1,39 @@
+<!DOCTYPE UI><UI version="3.1" stdsetdef="1">
+<class>CodeGenerationPolicyBase</class>
+<widget class="QWidget">
+ <property name="name">
+ <cstring>CodeGenerationPolicyBase</cstring>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>519</width>
+ <height>515</height>
+ </rect>
+ </property>
+ <widget class="QFrame">
+ <property name="name">
+ <cstring>policyFrame</cstring>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>30</x>
+ <y>20</y>
+ <width>470</width>
+ <height>470</height>
+ </rect>
+ </property>
+ <property name="frameShape">
+ <enum>StyledPanel</enum>
+ </property>
+ <property name="frameShadow">
+ <enum>Raised</enum>
+ </property>
+ </widget>
+</widget>
+<slots>
+ <slot access="protected">apply()</slot>
+</slots>
+<layoutdefaults spacing="6" margin="11"/>
+</UI>
diff --git a/umbrello/umbrello/dialogs/codegenerationpolicypage.cpp b/umbrello/umbrello/dialogs/codegenerationpolicypage.cpp
new file mode 100644
index 00000000..8deb3387
--- /dev/null
+++ b/umbrello/umbrello/dialogs/codegenerationpolicypage.cpp
@@ -0,0 +1,50 @@
+/***************************************************************************
+ begin : Tue Jul 29 2003
+ copyright : (C) 2003 by Brian Thomas
+ email : brian.thomas@gsfc.nasa.gov
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * copyright (C) 2004-2007 *
+ * Umbrello UML Modeller Authors <uml-devel@uml.sf.net> *
+ ***************************************************************************/
+
+// own header
+#include "codegenerationpolicypage.h"
+
+// qt/kde includes
+#include <qlabel.h>
+#include <klocale.h>
+
+// local includes
+#include "../codegenerationpolicy.h"
+
+
+/** This is the page which comes up IF there is no special options for the
+ * code generator.
+ */
+CodeGenerationPolicyPage::CodeGenerationPolicyPage( QWidget *parent, const char *name, CodeGenPolicyExt * policy )
+ :CodeGenerationPolicyBase(parent,name)
+{
+ m_parentPolicy = policy;
+}
+
+CodeGenerationPolicyPage::~CodeGenerationPolicyPage()
+{
+ this->disconnect();
+}
+
+void CodeGenerationPolicyPage::apply() {
+ // do nothing in vanilla version
+}
+
+void CodeGenerationPolicyPage::setDefaults() { }
+
+#include "codegenerationpolicypage.moc"
+
diff --git a/umbrello/umbrello/dialogs/codegenerationpolicypage.h b/umbrello/umbrello/dialogs/codegenerationpolicypage.h
new file mode 100644
index 00000000..16590dd3
--- /dev/null
+++ b/umbrello/umbrello/dialogs/codegenerationpolicypage.h
@@ -0,0 +1,55 @@
+/***************************************************************************
+ codegenerationpolicypage.h - description
+ -------------------
+ begin : Tue Jul 29 2003
+ copyright : (C) 2003 by Brian Thomas
+ email : brian.thomas@gsfc.nasa.gov
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * copyright (C) 2004-2006 *
+ * Umbrello UML Modeller Authors <uml-devel@uml.sf.net> *
+ ***************************************************************************/
+
+#ifndef CODEGENERATIONPOLICYPAGE_H
+#define CODEGENERATIONPOLICYPAGE_H
+
+#include <qwidget.h>
+#include "codegenerationpolicybase.h"
+
+class CodeGenPolicyExt;
+
+/**
+ * @author Brian Thomas
+ */
+
+class CodeGenerationPolicyPage : public CodeGenerationPolicyBase {
+ Q_OBJECT
+public:
+ explicit CodeGenerationPolicyPage (QWidget *parent=0, const char *name=0, CodeGenPolicyExt * policy = 0);
+
+ virtual ~CodeGenerationPolicyPage();
+
+ void setDefaults();
+
+protected:
+
+ CodeGenPolicyExt * m_parentPolicy;
+
+private:
+
+public slots:
+
+ virtual void apply();
+
+
+};
+
+#endif
+
diff --git a/umbrello/umbrello/dialogs/codegenerationwizard.cpp b/umbrello/umbrello/dialogs/codegenerationwizard.cpp
new file mode 100644
index 00000000..ca726398
--- /dev/null
+++ b/umbrello/umbrello/dialogs/codegenerationwizard.cpp
@@ -0,0 +1,258 @@
+/***************************************************************************
+ codegenerationwizard.cpp - description
+ -------------------
+ begin : Wed Jul 24 2002
+ copyright : (C) 2002 by Paul Hensgen
+ email : phensgen@users.sourceforge.net
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * copyright (C) 2003-2007 *
+ * Umbrello UML Modeller Authors <uml-devel@uml.sf.net> *
+ ***************************************************************************/
+
+// own header
+#include "codegenerationwizard.h"
+
+// qt/kde includes
+#include <qdir.h>
+#include <qlistview.h>
+#include <qfileinfo.h>
+#include <qapplication.h>
+#include <kdebug.h>
+#include <klocale.h>
+#include <kmessagebox.h>
+
+// local includes
+#include "codegenerationoptionspage.h"
+#include "../classifier.h"
+#include "../codegenerator.h"
+#include "../uml.h"
+#include "../umldoc.h"
+
+
+CodeGenerationWizard::CodeGenerationWizard(UMLClassifierList *classList)
+ : CodeGenerationWizardBase((QWidget*)UMLApp::app()) {
+ m_doc = UMLApp::app()->getDocument();
+ m_app = UMLApp::app();
+ m_availableList -> setAllColumnsShowFocus(true);
+ m_availableList -> setResizeMode(QListView::AllColumns);
+ m_selectedList -> setAllColumnsShowFocus(true);
+ m_selectedList -> setResizeMode(QListView::AllColumns);
+ m_statusList -> setAllColumnsShowFocus(true);
+ m_statusList -> setResizeMode(QListView::AllColumns);
+
+ m_CodeGenerationOptionsPage = new CodeGenerationOptionsPage(this);
+ connect( m_CodeGenerationOptionsPage, SIGNAL(languageChanged()), this, SLOT(changeLanguage()) );
+
+ insertPage(m_CodeGenerationOptionsPage, i18n("Code Generation Options"), 1);
+
+ UMLClassifierList cList;
+
+ if (classList == NULL) {
+ cList = m_doc->getClassesAndInterfaces();
+ classList = &cList;
+ }
+ for (UMLClassifier *c = classList->first(); c ; c = classList->next()) {
+ new QListViewItem( m_selectedList, c->getFullyQualifiedName());
+ }
+
+ setNextEnabled(page(0),m_selectedList->childCount() > 0);
+
+ setFinishEnabled(page(2),true);
+ finishButton()->disconnect();
+ finishButton()->setText(i18n("&Generate"));
+ connect(finishButton(),SIGNAL(clicked()),this,SLOT(generateCode()));
+ if ( QApplication::reverseLayout() )
+ {
+ QPixmap tmpPixmap( *m_addButton->pixmap() );
+ m_addButton->setPixmap(*m_removeButton->pixmap());
+ m_removeButton->setPixmap(tmpPixmap);
+ }
+}
+
+CodeGenerationWizard::~CodeGenerationWizard() {}
+
+
+void CodeGenerationWizard::selectClass() {
+ moveSelectedItems(m_availableList, m_selectedList);
+
+ if (m_selectedList->childCount() > 0) {
+ setNextEnabled(currentPage(), true);
+ }
+}
+
+void CodeGenerationWizard::deselectClass() {
+ moveSelectedItems(m_selectedList, m_availableList);
+
+ if (m_selectedList->childCount() == 0) {
+ setNextEnabled(currentPage(), false);
+ }
+}
+
+void CodeGenerationWizard::generateCode() {
+ backButton()->setEnabled(false);
+
+ CodeGenerator* codeGenerator = m_app->getGenerator();
+
+ if (codeGenerator) {
+
+ cancelButton()->setEnabled(false);
+
+ connect( codeGenerator, SIGNAL(codeGenerated(UMLClassifier*, bool)),
+ this, SLOT(classGenerated(UMLClassifier*, bool)) );
+
+ UMLClassifierList cList;
+ cList.setAutoDelete(false);
+
+ for(QListViewItem *item = m_statusList->firstChild(); item;
+ item = item-> nextSibling()) {
+ UMLClassifier *concept = m_doc->findUMLClassifier(item->text(0));
+ cList.append(concept);
+ }
+ codeGenerator->writeCodeToFile(cList);
+ finishButton()->setText(i18n("Finish"));
+ finishButton()->disconnect();
+ connect(finishButton(),SIGNAL(clicked()),this,SLOT(accept()));
+
+ }
+}
+
+void CodeGenerationWizard::classGenerated(UMLClassifier* concept, bool generated) {
+ QListViewItem* item = m_statusList->findItem( concept->getFullyQualifiedName(), 0 );
+ if( !item ) {
+ kError()<<"GenerationStatusPage::Error finding class in list view"<<endl;
+ } else if (generated) {
+ item->setText( 1, i18n("Code Generated") );
+ } else {
+ item->setText( 1, i18n("Not Generated") );
+ }
+}
+
+void CodeGenerationWizard::populateStatusList() {
+ m_statusList->clear();
+ for(QListViewItem* item = m_selectedList->firstChild(); item; item = item->nextSibling()) {
+ new QListViewItem(m_statusList,item->text(0),i18n("Not Yet Generated"));
+ }
+}
+
+void CodeGenerationWizard::showPage(QWidget *page) {
+ if (indexOf(page) == 2)
+ {
+ // first save the settings to the selected generator policy
+ ((CodeGenerationOptionsPage*)QWizard::page(1))->apply();
+
+ // before going on to the final page, check that the output directory exists and is
+ // writable
+
+ // get the policy for the current code generator
+ CodeGenerationPolicy *policy = UMLApp::app()->getCommonPolicy();
+
+ // get the output directory path
+ QFileInfo info(policy->getOutputDirectory().absPath());
+ if(!info.exists())
+ {
+ if (KMessageBox::questionYesNo(this,
+ i18n("The folder %1 does not exist. Do you want to create it now?").arg(info.filePath()),
+ i18n("Output Folder Does Not Exist"), i18n("Create Folder"), i18n("Do Not Create")) == KMessageBox::Yes)
+ {
+ QDir dir;
+ if(!dir.mkdir(info.filePath()))
+ {
+ KMessageBox::sorry(this,i18n("The folder could not be created.\nPlease make sure you have write access to its parent folder or select another, valid, folder."),
+ i18n("Error Creating Folder"));
+ return;
+ }
+ //else, directory created
+ }
+ else // do not create output directory
+ {
+ KMessageBox::information(this,i18n("Please select a valid folder."),
+ i18n("Output Folder Does Not Exist"));
+ return;
+ }
+ } else {
+ //directory exists.. make sure we can write to it
+ if(!info.isWritable())
+ {
+ KMessageBox::sorry(this,i18n("The output folder exists, but it is not writable.\nPlease set the appropriate permissions or choose another folder."),
+ i18n("Error Writing to Output Folder"));
+ return;
+ }
+ // it exits and we can write... make sure it is a directory
+ if(!info.isDir())
+ {
+ KMessageBox::sorry(this,i18n("%1 does not seem to be a folder. Please choose a valid folder.").arg(info.filePath()),
+ i18n("Please Choose Valid Folder"));
+ return;
+ }
+ }
+ }
+ populateStatusList();
+ QWizard::showPage(page);
+}
+
+CodeGenerator* CodeGenerationWizard::generator() {
+ // FIX
+ /*
+ KLibLoader* loader = KLibLoader::self();
+ if(!loader) {
+ kDebug()<<"error getting KLibLoader!"<<endl;
+ return 0;
+ }
+
+ KLibFactory* fact = loader->factory(info->library.latin1());
+ if(!fact) {
+ kDebug()<<"error getting the Factory"<<endl;
+ return 0;
+ }
+
+ QObject* o=fact->create(m_doc, 0, info->object.latin1());
+ if(!o) {
+ kDebug()<<"could not create object"<<endl;
+ return 0;
+ }
+
+ CodeGenerator* g = (CodeGenerator*)o;
+ // g->setDocument(m_doc);
+ return g;
+ */
+ return (CodeGenerator*) NULL;
+}
+
+void CodeGenerationWizard::moveSelectedItems(QListView* fromList, QListView* toList) {
+ QListViewItemIterator it(fromList, QListViewItemIterator::Selected);
+ while (it.current()) {
+ QListViewItem* selectedItem = it.current();
+
+ QString name = selectedItem->text(0);
+ if (!toList->findItem(name, 0)) {
+ new QListViewItem(toList, name);
+ }
+
+ ++it;
+
+ //Removed here because it can't (really, shouldn't) be removed while
+ //iterator is pointing to it
+ fromList->removeItem(selectedItem);
+ }
+}
+
+// when we change language, we need to update the codegenoptions page
+// language-dependent stuff. THe way to do this is to call its "apply" method.
+void CodeGenerationWizard::changeLanguage()
+{
+ m_app->setActiveLanguage( m_CodeGenerationOptionsPage->getCodeGenerationLanguage() );
+ /* @todo is this needed? if yes adapt to new scheme
+ m_CodeGenerationOptionsPage->setCodeGenerator(m_doc->getCurrentCodeGenerator());
+ */
+ m_CodeGenerationOptionsPage->apply();
+}
+
+#include "codegenerationwizard.moc"
diff --git a/umbrello/umbrello/dialogs/codegenerationwizard.h b/umbrello/umbrello/dialogs/codegenerationwizard.h
new file mode 100644
index 00000000..14d5f157
--- /dev/null
+++ b/umbrello/umbrello/dialogs/codegenerationwizard.h
@@ -0,0 +1,88 @@
+/***************************************************************************
+ codegenerationwizard.h - description
+ -------------------
+ begin : Wed Jul 24 2002
+ copyright : (C) 2002 by Luis De la Parra
+ email : luis@delaparra.org
+ Bugs and comments to uml-devel@lists.sf.net or http://bugs.kde.org
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * copyright (C) 2003-2006 *
+ * Umbrello UML Modeller Authors <uml-devel@uml.sf.net> *
+ ***************************************************************************/
+
+#ifndef CODEGENERATIONWIZARD_H
+#define CODEGENERATIONWIZARD_H
+
+#include <qwidget.h>
+#include <qptrlist.h>
+#include "codegenerationwizardbase.h"
+#include "settingsdlg.h"
+#include "../umlclassifierlist.h"
+
+class UMLApp;
+class UMLDoc;
+class CodeGenerator;
+class CodeGenerationOptionsPage;
+
+/**
+ * @author Luis De la Parra
+ * based on wizard from Paul Hensgen
+ */
+
+class CodeGenerationWizard : public CodeGenerationWizardBase {
+ Q_OBJECT
+public:
+ CodeGenerationWizard(UMLClassifierList *classList);
+ ~CodeGenerationWizard();
+
+ void showPage(QWidget *);
+
+ int exec() {
+ return QWizard::exec();
+ }
+protected slots:
+
+ /**
+ * Adds the classes selected in the available classes list to the
+ * list of classes used to generate the code.
+ */
+ void selectClass();
+
+ /**
+ * Removes the classes selected in the selected classes list from the
+ * list of classes used to generate the code.
+ */
+ void deselectClass();
+ void populateStatusList();
+ void generateCode();
+ void classGenerated(UMLClassifier* concept, bool generated);
+
+private slots:
+ void changeLanguage();
+
+
+private:
+ CodeGenerator* generator();
+
+ /**
+ * Moves the selected items from first list to second list.
+ * The selected items are removed from the first list and added to the
+ * second. An item is added to the second list only if it isn't already
+ * there (no duplicated items are created).
+ */
+ void moveSelectedItems(QListView* fromList, QListView* toList);
+
+ UMLApp* m_app;
+ UMLDoc* m_doc;
+ CodeGenerationOptionsPage* m_CodeGenerationOptionsPage;
+};
+
+#endif
diff --git a/umbrello/umbrello/dialogs/codegenerationwizardbase.ui b/umbrello/umbrello/dialogs/codegenerationwizardbase.ui
new file mode 100644
index 00000000..732aa0c7
--- /dev/null
+++ b/umbrello/umbrello/dialogs/codegenerationwizardbase.ui
@@ -0,0 +1,309 @@
+<!DOCTYPE UI><UI version="3.0" stdsetdef="1">
+<class>CodeGenerationWizardBase</class>
+<widget class="QWizard">
+ <property name="name">
+ <cstring>CodeGenerationWizardBase</cstring>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>396</width>
+ <height>386</height>
+ </rect>
+ </property>
+ <property name="caption">
+ <string>Code Generation Wizard</string>
+ </property>
+ <widget class="QWidget">
+ <property name="name">
+ <cstring>select</cstring>
+ </property>
+ <attribute name="title">
+ <string>Select Classes</string>
+ </attribute>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>0</number>
+ </property>
+ <property name="spacing">
+ <number>10</number>
+ </property>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>TextLabel1</cstring>
+ </property>
+ <property name="text">
+ <string>Place all the classes you want to generate code
+for in the right hand side list</string>
+ </property>
+ </widget>
+ <widget class="QFrame">
+ <property name="name">
+ <cstring>Frame4</cstring>
+ </property>
+ <property name="frameShape">
+ <enum>Box</enum>
+ </property>
+ <property name="frameShadow">
+ <enum>Plain</enum>
+ </property>
+ <property name="margin">
+ <number>10</number>
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>20</number>
+ </property>
+ <property name="spacing">
+ <number>10</number>
+ </property>
+ <widget class="QPushButton" row="1" column="1">
+ <property name="name">
+ <cstring>m_addButton</cstring>
+ </property>
+ <property name="text">
+ <string></string>
+ </property>
+ <property name="pixmap">
+ <pixmap>image0</pixmap>
+ </property>
+ <property name="toolTip" stdset="0">
+ <string>Add class for code generation</string>
+ </property>
+ </widget>
+ <spacer row="0" column="1">
+ <property name="name" stdset="0">
+ <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>20</height>
+ </size>
+ </property>
+ </spacer>
+ <widget class="QListView" row="0" column="2" rowspan="5" colspan="1">
+ <column>
+ <property name="text">
+ <string>Classes Selected</string>
+ </property>
+ <property name="clickable">
+ <bool>true</bool>
+ </property>
+ <property name="resizeable">
+ <bool>true</bool>
+ </property>
+ </column>
+ <property name="name">
+ <cstring>m_selectedList</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>7</hsizetype>
+ <vsizetype>7</vsizetype>
+ <horstretch>1</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="selectionMode">
+ <enum>Extended</enum>
+ </property>
+ </widget>
+ <widget class="QPushButton" row="3" column="1">
+ <property name="name">
+ <cstring>m_removeButton</cstring>
+ </property>
+ <property name="text">
+ <string></string>
+ </property>
+ <property name="pixmap">
+ <pixmap>image1</pixmap>
+ </property>
+ <property name="toolTip" stdset="0">
+ <string>Remove class from Code Generation</string>
+ </property>
+ </widget>
+ <spacer row="2" column="1">
+ <property name="name" stdset="0">
+ <cstring>Spacer3</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="QListView" row="0" column="0" rowspan="5" colspan="1">
+ <column>
+ <property name="text">
+ <string>Classes Available</string>
+ </property>
+ <property name="clickable">
+ <bool>true</bool>
+ </property>
+ <property name="resizeable">
+ <bool>true</bool>
+ </property>
+ </column>
+ <property name="name">
+ <cstring>m_availableList</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>7</hsizetype>
+ <vsizetype>7</vsizetype>
+ <horstretch>1</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="selectionMode">
+ <enum>Extended</enum>
+ </property>
+ </widget>
+ <spacer row="4" column="1">
+ <property name="name" stdset="0">
+ <cstring>Spacer1_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>
+ </grid>
+ </widget>
+ </vbox>
+ </widget>
+ <widget class="QWidget">
+ <property name="name">
+ <cstring>status</cstring>
+ </property>
+ <attribute name="title">
+ <string>Code Generation Status</string>
+ </attribute>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>0</number>
+ </property>
+ <property name="spacing">
+ <number>10</number>
+ </property>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>m_label</cstring>
+ </property>
+ <property name="text">
+ <string>Press the Generation button to start the code generation</string>
+ </property>
+ </widget>
+ <widget class="QGroupBox">
+ <property name="name">
+ <cstring>GroupBox2</cstring>
+ </property>
+ <property name="title">
+ <string>Generation Status</string>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>20</number>
+ </property>
+ <property name="spacing">
+ <number>10</number>
+ </property>
+ <widget class="QListView">
+ <column>
+ <property name="text">
+ <string>Class</string>
+ </property>
+ <property name="clickable">
+ <bool>true</bool>
+ </property>
+ <property name="resizeable">
+ <bool>true</bool>
+ </property>
+ </column>
+ <column>
+ <property name="text">
+ <string>Generation Status</string>
+ </property>
+ <property name="clickable">
+ <bool>true</bool>
+ </property>
+ <property name="resizeable">
+ <bool>true</bool>
+ </property>
+ </column>
+ <property name="name">
+ <cstring>m_statusList</cstring>
+ </property>
+ </widget>
+ </vbox>
+ </widget>
+ </vbox>
+ </widget>
+</widget>
+<images>
+ <image name="image0">
+ <data format="XPM.GZ" length="915">789c65d1c96ec2301006e03b4f61c10d5580431262553db0158ad4aac74a550f633bec5b21a4d0aaefdecc8c1395605ffc79fe71e2a459176fafcfa2deac1c1348164698391c44dd9e369bcbfbc7c34fa52a432103d18e84acde55aa0d61c4cb6e1be35a67eb5aabe5b7420f592b08c8d8d1670231ca3941ca28b091463e21bd5628958f1c1355a8988f050d72e4689903645b762473e81800f5f689aaa3983d47cbec227d1949a0de8b63c0fc2642a4986764e04556536fca5492f955d022132228c53c395ae611197a109800792042ce9d63ccdc233bed8cd4fb49d43a64ae1d81b9ca69a977838cda39e74ce33117449d917ee814a97c13c721724b3406b8ba44826f3daece88c6424c55eb18330d52fb391b386ad0c847bea7b386f21e98a981726e365fe4c922b75cad372e59e4b6bbfd6ecfc922f7793866939245ee909c70eaffb9244dbfd234bdca9d2fdfd9bc3eafdbed757ba5e7f607c341f9fd1e47e39b7b3c4d6eee7bf55d7eef2b7f4698d01d</data>
+ </image>
+ <image name="image1">
+ <data format="XPM.GZ" length="915">789c65d1c76e83401006e0bb9f62656e56147b316056510eee454a9463a428872db81b775ca2bc7b9899c502c21cd86fe71f6abdc63e3fde58ad5e399ee469a1999ecb03ab99f36673fbfa7efda95479c0b8cf9a21e3d5a74af59969f6be8d235847e9da6934bc46e002e58312a82c3da2830c338e813cf44da88013a0db08b8f08003a4080471f4a0060e2d0db10b6cf21627f62c7d89b37da4680962dbd2103b408f875ce2ecd5d227de903214c43bd07743a37036210a4ebc3c688067a4148278b234c4033070a5af7de01e29336e2d23620c6c3553e2ec11a954405c594ae232a3c1d935306c669c13b54b9c21554afca153a0f0741405c01d526b49dd0d507ac6a5ee02a98d8cb0ab2d23a2012a2fe3b33d1c49e7dc9e4a674a7b8e991aa7b8a7f46cbe28e61cb35cad37859cd2f1368e77f99c63f687b48ef95c743a43ed0bb9e49224c9e55cbcdef596d6bd74df76a7dde9949fafdbebf6ffbdc760382ae5d2e47852cee5becbef4be50f94aacd35</data>
+ </image>
+</images>
+<connections>
+ <connection>
+ <sender>m_addButton</sender>
+ <signal>clicked()</signal>
+ <receiver>CodeGenerationWizardBase</receiver>
+ <slot>selectClass()</slot>
+ </connection>
+ <connection>
+ <sender>m_removeButton</sender>
+ <signal>clicked()</signal>
+ <receiver>CodeGenerationWizardBase</receiver>
+ <slot>deselectClass()</slot>
+ </connection>
+</connections>
+<forwards>
+ <forward>class UMLClassifier</forward>
+</forwards>
+<slots>
+ <slot>selectClass()</slot>
+ <slot access="protected">deselectClass()</slot>
+ <slot>classGenerated( UMLClassifier * /* c */ )</slot>
+</slots>
+<layoutdefaults spacing="6" margin="11"/>
+</UI>
diff --git a/umbrello/umbrello/dialogs/codeviewerdialog.cpp b/umbrello/umbrello/dialogs/codeviewerdialog.cpp
new file mode 100644
index 00000000..5672e576
--- /dev/null
+++ b/umbrello/umbrello/dialogs/codeviewerdialog.cpp
@@ -0,0 +1,122 @@
+/***************************************************************************
+ begin : Fri Aug 1 2003
+ copyright : (C) 2003 by Brian Thomas
+ email : brian.thomas@gsfc.nasa.gov
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * copyright (C) 2004-2007 *
+ * Umbrello UML Modeller Authors <uml-devel@uml.sf.net> *
+ ***************************************************************************/
+
+// own header
+#include "codeviewerdialog.h"
+
+// qt/kde includes
+#include <qlayout.h>
+#include <qtabwidget.h>
+#include <qcheckbox.h>
+#include <kdebug.h>
+#include <klocale.h>
+
+// local includes
+#include "../codedocument.h"
+#include "../classifiercodedocument.h"
+#include "codeeditor.h"
+
+CodeViewerDialog::CodeViewerDialog ( QWidget* parent, CodeDocument * doc,
+ Settings::CodeViewerState state,
+ const char* name, bool modal, WFlags fl )
+ : CodeViewerDialogBase ( parent, name, modal, fl )
+
+{
+ m_state = state;
+
+ initGUI(name);
+
+ addCodeDocument(doc);
+
+}
+
+/*
+ * Destroys the object and frees any allocated resources
+ */
+CodeViewerDialog::~CodeViewerDialog()
+{
+ // no need to delete child widgets, Qt does it all for us
+}
+
+void CodeViewerDialog::initGUI ( const char * name) {
+
+ if ( !name )
+ setName( "CodeViewerDialog" );
+
+ setFont( getState().font );
+
+ // set some viewability parameters
+ int margin = fontMetrics().height();
+ int width = fontMetrics().maxWidth() * getState().width;
+ int height = fontMetrics().lineSpacing() * getState().height;
+
+ m_highlightCheckBox->setChecked( getState().blocksAreHighlighted );
+ m_showHiddenCodeCB->setChecked ( getState().showHiddenBlocks );
+
+ CodeViewerDialogBaseLayout->setMargin(margin);
+
+ resize( QSize(width, height).expandedTo(minimumSizeHint()) );
+
+}
+
+/*
+ * Adds a code document to the tabbed output
+ */
+void CodeViewerDialog::addCodeDocument( CodeDocument * doc)
+{
+ CodeEditor * page = new CodeEditor ( this, "_codedocumenteditor_", doc );
+ QString fname = doc->getFileName();
+ QString ext = doc->getFileExtension();
+ m_tabWidget->insertTab(page, (fname + (ext.isEmpty()? "" : ext)));
+
+ connect( m_highlightCheckBox, SIGNAL( stateChanged(int) ), page, SLOT( changeHighlighting(int) ) );
+ connect( m_showHiddenCodeCB, SIGNAL( stateChanged(int) ), page, SLOT( changeShowHidden(int) ) );
+
+}
+
+Settings::CodeViewerState CodeViewerDialog::getState() {
+ return m_state;
+}
+
+bool CodeViewerDialog::close ( bool alsoDelete )
+{
+
+ // remember widget size for next time
+ m_state.height = height() / fontMetrics().lineSpacing();
+ m_state.width = width() / fontMetrics().maxWidth();
+
+ // remember block highlighting
+ m_state.blocksAreHighlighted = m_highlightCheckBox->isChecked();
+
+ // remember block show status
+ m_state.showHiddenBlocks = m_showHiddenCodeCB->isChecked();
+
+ // run superclass close now
+ return CodeViewerDialogBase::close(alsoDelete);
+
+}
+
+/*
+ * Sets the strings of the subwidgets using the current
+ * language.
+ */
+void CodeViewerDialog::languageChange()
+{
+ setCaption( tr2i18n( "Code Viewer" ) );
+}
+
+#include "codeviewerdialog.moc"
diff --git a/umbrello/umbrello/dialogs/codeviewerdialog.h b/umbrello/umbrello/dialogs/codeviewerdialog.h
new file mode 100644
index 00000000..7315384f
--- /dev/null
+++ b/umbrello/umbrello/dialogs/codeviewerdialog.h
@@ -0,0 +1,80 @@
+
+/***************************************************************************
+ codeviewerdialog.h - description
+ -------------------
+ begin : Fri Aug 1 2003
+ copyright : (C) 2003 by Brian Thomas
+ email : brian.thomas@gsfc.nasa.gov
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the 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 CODEVIEWERDIALOG_H
+#define CODEVIEWERDIALOG_H
+
+#include <qcolor.h>
+#include <qmap.h>
+#include <qptrlist.h>
+#include <qstring.h>
+#include <qtextedit.h>
+#include "../codeviewerstate.h"
+#include "codeviewerdialogbase.h"
+
+class CodeDocument;
+class QVBoxLayout;
+class QHBoxLayout;
+class QGridLayout;
+class QFrame;
+
+class UMLObject;
+
+/** This class is sooo ugly I don't know where to begin. For now, its a prototype
+ * that works, and thats all we need. In the future, a re-write is mandated to
+ * bring a bit of beauty to this beast. -b.t.
+ */
+class CodeViewerDialog : public CodeViewerDialogBase
+{
+ Q_OBJECT
+public:
+
+ CodeViewerDialog ( QWidget* parent, CodeDocument * doc, Settings::CodeViewerState state,
+ const char* name = 0, bool modal = false, WFlags fl = 0 );
+ ~CodeViewerDialog ();
+
+ /** return the code viewer state */
+ Settings::CodeViewerState getState( );
+
+ QString parentDocName;
+
+ /**
+ * Adds a code document to the tabbed output
+ */
+ void addCodeDocument( CodeDocument * doc);
+
+protected:
+
+ bool close ( bool alsoDelete );
+
+private:
+
+ Settings::CodeViewerState m_state;
+
+ void initGUI ( const char * name );
+
+public slots:
+
+protected slots:
+
+ virtual void languageChange();
+
+};
+
+
+#endif // CODEVIEWERDIALOG_H
diff --git a/umbrello/umbrello/dialogs/codeviewerdialogbase.ui b/umbrello/umbrello/dialogs/codeviewerdialogbase.ui
new file mode 100644
index 00000000..672aefdb
--- /dev/null
+++ b/umbrello/umbrello/dialogs/codeviewerdialogbase.ui
@@ -0,0 +1,113 @@
+<!DOCTYPE UI><UI version="3.1" stdsetdef="1">
+<class>CodeViewerDialogBase</class>
+<widget class="QDialog">
+ <property name="name">
+ <cstring>CodeViewerDialogBase</cstring>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>615</width>
+ <height>728</height>
+ </rect>
+ </property>
+ <property name="font">
+ <font>
+ <family>Courier</family>
+ </font>
+ </property>
+ <property name="caption">
+ <string>Code Viewer</string>
+ </property>
+ <property name="sizeGripEnabled">
+ <bool>true</bool>
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLayoutWidget" row="0" column="0">
+ <property name="name">
+ <cstring>layout2</cstring>
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QCheckBox" row="0" column="1">
+ <property name="name">
+ <cstring>m_showHiddenCodeCB</cstring>
+ </property>
+ <property name="text">
+ <string>Show hidden blocks</string>
+ </property>
+ </widget>
+ <widget class="QLabel" row="1" column="0" rowspan="1" colspan="3">
+ <property name="name">
+ <cstring>componentLabel</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>5</hsizetype>
+ <vsizetype>0</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="text">
+ <string>&lt;p align="center"&gt;component name here&lt;/p&gt;</string>
+ </property>
+ <property name="scaledContents">
+ <bool>true</bool>
+ </property>
+ </widget>
+ <widget class="QPushButton" row="0" column="2">
+ <property name="name">
+ <cstring>m_exitButton</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>0</hsizetype>
+ <vsizetype>0</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="text">
+ <string>Close</string>
+ </property>
+ </widget>
+ <widget class="QCheckBox" row="0" column="0">
+ <property name="name">
+ <cstring>m_highlightCheckBox</cstring>
+ </property>
+ <property name="text">
+ <string>Show block type</string>
+ </property>
+ <property name="checked">
+ <bool>false</bool>
+ </property>
+ </widget>
+ </grid>
+ </widget>
+ <widget class="QTabWidget" row="1" column="0">
+ <property name="name">
+ <cstring>m_tabWidget</cstring>
+ </property>
+ </widget>
+ </grid>
+</widget>
+<connections>
+ <connection>
+ <sender>m_exitButton</sender>
+ <signal>released()</signal>
+ <receiver>CodeViewerDialogBase</receiver>
+ <slot>close()</slot>
+ </connection>
+</connections>
+<slots>
+ <slot>changeHighlighting(int)</slot>
+</slots>
+<layoutdefaults spacing="6" margin="11"/>
+</UI>
diff --git a/umbrello/umbrello/dialogs/codevieweroptionsbase.ui b/umbrello/umbrello/dialogs/codevieweroptionsbase.ui
new file mode 100644
index 00000000..99fd198d
--- /dev/null
+++ b/umbrello/umbrello/dialogs/codevieweroptionsbase.ui
@@ -0,0 +1,369 @@
+<!DOCTYPE UI><UI version="3.1" stdsetdef="1">
+<class>CodeViewerOptionsBase</class>
+<widget class="QWidget">
+ <property name="name">
+ <cstring>CodeViewerOptionsBase</cstring>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>486</width>
+ <height>545</height>
+ </rect>
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="KFontChooser" row="0" column="0">
+ <property name="name">
+ <cstring>fontChooser</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>1</hsizetype>
+ <vsizetype>3</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ </widget>
+ <widget class="QGroupBox" row="1" column="0">
+ <property name="name">
+ <cstring>colorGroupBox</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>5</hsizetype>
+ <vsizetype>0</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="title">
+ <string>Colors</string>
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLayoutWidget" row="0" column="0">
+ <property name="name">
+ <cstring>colorLayout</cstring>
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLabel" row="0" column="2">
+ <property name="name">
+ <cstring>fontLabel</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>1</hsizetype>
+ <vsizetype>5</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="text">
+ <string>Font:</string>
+ </property>
+ </widget>
+ <widget class="KColorButton" row="0" column="5">
+ <property name="name">
+ <cstring>selectColorButton</cstring>
+ </property>
+ <property name="text">
+ <string></string>
+ </property>
+ <property name="color">
+ <color>
+ <red>255</red>
+ <green>255</green>
+ <blue>127</blue>
+ </color>
+ </property>
+ </widget>
+ <widget class="QLabel" row="0" column="0">
+ <property name="name">
+ <cstring>paperLabel</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>1</hsizetype>
+ <vsizetype>5</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="text">
+ <string>Paper:</string>
+ </property>
+ </widget>
+ <widget class="KColorButton" row="0" column="1">
+ <property name="name">
+ <cstring>paperColorButton</cstring>
+ </property>
+ <property name="text">
+ <string></string>
+ </property>
+ <property name="color">
+ <color>
+ <red>255</red>
+ <green>255</green>
+ <blue>255</blue>
+ </color>
+ </property>
+ </widget>
+ <widget class="QLabel" row="0" column="4">
+ <property name="name">
+ <cstring>selectedLabel</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>1</hsizetype>
+ <vsizetype>5</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="text">
+ <string>Selected:</string>
+ </property>
+ </widget>
+ <widget class="KColorButton" row="0" column="3">
+ <property name="name">
+ <cstring>fontColorButton</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>
+ <property name="color">
+ <color>
+ <red>0</red>
+ <green>0</green>
+ <blue>0</blue>
+ </color>
+ </property>
+ </widget>
+ </grid>
+ </widget>
+ <widget class="QLayoutWidget" row="1" column="0">
+ <property name="name">
+ <cstring>layout4</cstring>
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="KColorButton" row="1" column="3">
+ <property name="name">
+ <cstring>nonEditBlockColorButton</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>213</red>
+ <green>213</green>
+ <blue>213</blue>
+ </color>
+ </property>
+ </widget>
+ <widget class="QLayoutWidget" row="0" column="0" rowspan="1" colspan="4">
+ <property name="name">
+ <cstring>layout3</cstring>
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="KColorButton" row="0" column="3">
+ <property name="name">
+ <cstring>m_hiddenBlockColorButton</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>166</red>
+ <green>254</green>
+ <blue>248</blue>
+ </color>
+ </property>
+ </widget>
+ <widget class="KColorButton" row="0" column="1">
+ <property name="name">
+ <cstring>umlObjectColorButton</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>170</green>
+ <blue>255</blue>
+ </color>
+ </property>
+ </widget>
+ <widget class="QLabel" row="0" column="0">
+ <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>&lt;p align="right"&gt;UML object block:&lt;/p&gt;</string>
+ </property>
+ </widget>
+ <widget class="QLabel" row="0" column="2">
+ <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>&lt;p align="right"&gt;Hidden block:&lt;/p&gt;</string>
+ </property>
+ </widget>
+ </grid>
+ </widget>
+ <widget class="QLabel" row="1" column="2">
+ <property name="name">
+ <cstring>textLabel2</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>1</hsizetype>
+ <vsizetype>5</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="text">
+ <string>&lt;p align="right"&gt;Uneditable text:&lt;/p&gt;</string>
+ </property>
+ </widget>
+ <widget class="KColorButton" row="1" column="1">
+ <property name="name">
+ <cstring>editBlockColorButton</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>170</green>
+ <blue>255</blue>
+ </color>
+ </property>
+ </widget>
+ <widget class="QLabel" row="1" column="0">
+ <property name="name">
+ <cstring>textLabel3</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>1</hsizetype>
+ <vsizetype>5</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="text">
+ <string>&lt;p align="right"&gt;Editable text:&lt;/p&gt;</string>
+ </property>
+ </widget>
+ </grid>
+ </widget>
+ </grid>
+ </widget>
+ </grid>
+</widget>
+<customwidgets>
+ <customwidget>
+ <class>KFontChooser</class>
+ <header location="global">kfontdialog.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="XPM.GZ" length="4462">789c9d97c76e24490e86effd1442f3d65870d2451a0ce6206f5adeb4cc620f8c34f2553225b5a4c1befb46927fe6a1d4c0ccac4287fa8a0c26834193f5dbb785b3fd9d856fbf7d799ec9ecba5ea8afe469e15bf3727ffffeeffffcf1e797af49b2d0ffc7d142f2f55f5fbe1ecc16ea85dde9a4ed81290045faa77ca49cf4ab67ba1e3953969173651ab9d4fdf1c8a27c3872ad7c3c72d3b32c2a67c3f3444636fbef23eb7e590267e68fcc4656395d8dacf6d938ef97eaef289781cddebdb2846fccff44b989ba58e3411f3dc75158e6df1d3889539517ca49bf54fe43398d1dec4f46567f685fd9c539f43fc025f80c1c3ce8d93f28e77185f8bf0c6cfae4c0b5f9c3c6e5c0542a4b5876fe13708df39d2bd7716372aa8c93c4e4723bb2f977aadc26ceec4bdb7310e6b0bfab9c2445ecd49f1370694cebca65d260ffa6711a41aef14d24e94cee6be3348e0ae5e9c8765f07ca3e8db17f0f9c825794eb3489351fe9bb7217e4969f29388bd51ee9fda5715a19730696b852fea95c6471647ca95cf64bcf43e0cef4657b647bfe6acf213d6bb32f9a9f5992b5a64f9a8f990b6cf9ecc15d6cf9acf6b2da55a8a75cb973dee4b2d1b38b5c05de02434e87e01aacfb351df5bebddea74b5c67f9c795711ea15e357e2ecde358fb87efc0a867df8cac728a074e62e527706afb59f3cf6583be5c28bb3c35f693812d1fbdc6dbe57966fec932d899ffa4f7e38adca17e34beaeca4b9c271a18f1d5fc739257b0d70d9c68be7bed7fcee7827ab91cd8e4740cf6b19d4ffb87ab07b9bf516e72d4a3ac821b9cef6e60d84f47367ded2fae1d9f7704f6163f79000ffde27660f387ed3c5dbf54dfeebb0bf6acbe6b706bfa5ef32f8f8b18f5bf0f463f20edb77956a4e68fbc80b3c4facd163847be6bfde72ec86dbeac82715fbc0286be683cf3bc081d44f7df80d344fb0b6b7de64581fb916765297263d6fccd9b7ee97e566e8b06cfdb1f59cf2bda2f8bbc2c11df0c5c41aefdb328ca22b1feb0012eedbce24736f91b18fb796d64eb87cb60817dcdafb07d906bfd14d22f659d8785ef97b2f6d7b2df6ef1d6fb2babaac6f92e8c25b27ecc1f239b7f3a5fca5a8678ea7c2d9bc0e6ef1238b3fca2c7814d5f4cbf9334b5f833384bed3c7a5f5514f4adbe2ec07962e7590457f06f6f649b977afe2a16f42f5e070bfc591e18f7a5f1a812a9e0df39d827da4fbd8c6ccfd7785569bf945f953371a9d5a3de67950bfa2d75c63eb2fb15bdcfaaf011e6c7263846bf8f4636f91618f3c7d3c0f047fb69550efab2074e12bd6fd27957553ec33c5b043bcc7f9d0795f818fdb501a3df8ae673e507ff69021eea37063bc45ffb73550736ff36c0a84f3e0317a86f8b5f139e6ffe1f821de6d9127898ff3be00a7c3ab2cd03e3d697560ff40016e47b3bb2e96bbd559d8f32bbff4b7065f193042c98873acf240af6adbf3c83c5f2954bb0c7bcd77c107d81d2fdebc63e33ff640aaecc9e1c8151df5c803dfaadc64b52dfa03ed64636ffb4ff4b2867f453ede7227586fcd3f9264ded91fffafe236d5da37fe83c91ceb7b9e5b7f6731ff92ed7f747d6fbf7e185cf58347e3e6932e47b3430fa893edf87d795c2fc3f003b67f5f902cec17abfde0dfa3c053b3c5ffb832fc2eb8fddcf233887fc195c801f46b6f3cdc02558fba72f7d2d1a7f7e321ee58fe0cad86bbff24dd3e2fe74fef836b0c6eb60d62fa6bf5e07b3419f853dd7dc70fb8bd5f1255fd90ed30f9f3c5ff30ddff21ddff384a7fcc08ffcc4cf61cdf8855ff9e79c7e1db4dff89d3f7891977899577895d7789d377893b7f83b6fcfe937bc13b477798ff7f9800ff928ac633ee11f7cca6761d7f99c7e1b3cb908da11c7413be1943376e153cc39175c72f549ff9e17c31744429e6a6aa8a58e2ee98aaee9866e7f617fc24b7417a4f734a1293dd0233dd133cd8285177aa5f9f3b63ca5377aa78f607b919668995682e62aadd17ab0b1419b9ff41f682b48bed336edd02eed05ed7d5ea3033a0cdf1ed1f127fd273ae123fa41a774a6b685cee982228a837e42e927fd47caf8985c38651eb40b2ac38e4a5842658a97fab33fd248cb87d2c9a55cc9b5dcc82d1fc99ddccb44a6f230af2f8ff224cf417f262ff22a3fe54ddee543166549966545567f617f4dd66523dc6b2c9bb225df655b7682f692ecca9eeccfe97772c09b722847722c27c1f3eb70f66bf9116c9fca999ccbc59cfe25bf4a143a5ef8992561324a78bd92522acf9ebc78efe7cf7b153276db37bef59dbff457fedadff85b7f27abfede4ffcd4cf9ff76faeff4fffefeff8c7f5fedfdfbffc0fa355c495</data>
+ </image>
+</images>
+<layoutdefaults spacing="6" margin="11"/>
+<includehints>
+ <includehint>kcolorbutton.h</includehint>
+</includehints>
+</UI>
diff --git a/umbrello/umbrello/dialogs/codevieweroptionspage.cpp b/umbrello/umbrello/dialogs/codevieweroptionspage.cpp
new file mode 100644
index 00000000..dd120569
--- /dev/null
+++ b/umbrello/umbrello/dialogs/codevieweroptionspage.cpp
@@ -0,0 +1,70 @@
+/***************************************************************************
+ codegenerationoptionspage.cpp - description
+ -------------------
+ begin : Thu Jul 25 2002
+ copyright : (C) 2002 by Luis De la Parra
+ email : luis@delaparra.org
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * copyright (C) 2003-2007 *
+ * Umbrello UML Modeller Authors <uml-devel@uml.sf.net> *
+ ***************************************************************************/
+
+// own header
+#include "codevieweroptionspage.h"
+
+// qt/kde includes
+#include <kdebug.h>
+#include <kfontdialog.h>
+#include <kcolorbutton.h>
+
+
+CodeViewerOptionsPage::CodeViewerOptionsPage( Settings::CodeViewerState options, QWidget *parent, const char *name )
+ :CodeViewerOptionsBase(parent,name)
+{
+ init (options);
+}
+
+CodeViewerOptionsPage::~CodeViewerOptionsPage() { }
+
+void CodeViewerOptionsPage::init( Settings::CodeViewerState options )
+{
+ m_options = options;
+
+ // set widget stuff
+ /*
+ fontChooser->setFont( options.font );
+ selectColorButton -> setColor (options.selectedColor);
+ fontColorButton -> setColor (options.fontColor);
+ paperColorButton -> setColor (options.paperColor);
+ editBlockColorButton -> setColor (options.editBlockColor);
+ nonEditBlockColorButton -> setColor (options.nonEditBlockColor);
+ umlObjectColorButton -> setColor (options.umlObjectColor);
+ */
+}
+
+void CodeViewerOptionsPage::apply() {
+ /*
+ m_options.umlObjectColor = umlObjectColorButton->color();
+ m_options.editBlockColor = editBlockColorButton->color();
+ m_options.nonEditBlockColor = nonEditBlockColorButton->color();
+ m_options.selectedColor = selectColorButton->color();
+ m_options.paperColor = paperColorButton->color();
+ m_options.fontColor = fontColorButton->color();
+ m_options.font = fontChooser->font();
+ */
+ emit applyClicked();
+}
+
+Settings::CodeViewerState CodeViewerOptionsPage::getOptions() {
+ return m_options;
+}
+
+#include "codevieweroptionspage.moc"
diff --git a/umbrello/umbrello/dialogs/codevieweroptionspage.h b/umbrello/umbrello/dialogs/codevieweroptionspage.h
new file mode 100644
index 00000000..ec01f170
--- /dev/null
+++ b/umbrello/umbrello/dialogs/codevieweroptionspage.h
@@ -0,0 +1,52 @@
+/***************************************************************************
+ codegenerationoptionspage.h - description
+ -------------------
+ begin : Thu Jul 25 2002
+ copyright : (C) 2002 by Luis De la Parra
+ email : luis@delaparra.org
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the 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 CODEVIEWEROPTIONSPAGE_H
+#define CODEVIEWEROPTIONSPAGE_H
+
+#include <qwidget.h>
+#include "codevieweroptionsbase.h"
+#include "../codeviewerstate.h"
+
+/**
+ * @author Brian Thomas
+ */
+
+class CodeViewerOptionsPage : public CodeViewerOptionsBase {
+ Q_OBJECT
+public:
+ CodeViewerOptionsPage (Settings::CodeViewerState options, QWidget *parent, const char *name=0);
+ ~CodeViewerOptionsPage();
+
+ Settings::CodeViewerState getOptions();
+ void apply();
+
+protected:
+
+private:
+
+ Settings::CodeViewerState m_options;
+ void init ( Settings::CodeViewerState options);
+
+protected slots:
+
+signals:
+ void applyClicked();
+
+};
+
+#endif
diff --git a/umbrello/umbrello/dialogs/defaultcodegenpolicypage.cpp b/umbrello/umbrello/dialogs/defaultcodegenpolicypage.cpp
new file mode 100644
index 00000000..668d732d
--- /dev/null
+++ b/umbrello/umbrello/dialogs/defaultcodegenpolicypage.cpp
@@ -0,0 +1,41 @@
+
+/***************************************************************************
+ codegenerationpolicypage.cpp - description
+ -------------------
+ begin : Tue Jul 29 2003
+ copyright : (C) 2003 by Brian Thomas
+ email : brian.thomas@gsfc.nasa.gov
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * copyright (C) 2004-2007 *
+ * Umbrello UML Modeller Authors <uml-devel@uml.sf.net> *
+ ***************************************************************************/
+
+// own header
+#include "defaultcodegenpolicypage.h"
+
+// qt/kde includes
+#include <qlabel.h>
+#include <klocale.h>
+
+
+/** This is the page which comes up IF there is no special options for the
+ * code generator.
+ */
+DefaultCodeGenPolicyPage::DefaultCodeGenPolicyPage ( QWidget *parent, const char *name, CodeGenPolicyExt * policy )
+ :CodeGenerationPolicyPage(parent,name,policy)
+{
+ textLabel = new QLabel(parent,"textLabel");
+ textLabel->setText(tr2i18n("<p align=\"center\">No Options Available.</p>"));
+}
+
+DefaultCodeGenPolicyPage::~DefaultCodeGenPolicyPage() { }
+
+#include "defaultcodegenpolicypage.moc"
diff --git a/umbrello/umbrello/dialogs/defaultcodegenpolicypage.h b/umbrello/umbrello/dialogs/defaultcodegenpolicypage.h
new file mode 100644
index 00000000..c3d36332
--- /dev/null
+++ b/umbrello/umbrello/dialogs/defaultcodegenpolicypage.h
@@ -0,0 +1,42 @@
+
+/****************************************************************************
+** Form interface generated from reading ui file 'Defaultcodegenpolicypage.ui'
+**
+** Created: Fri Aug 1 12:47:23 2003
+** by: The User Interface Compiler ($Id$)
+**
+** WARNING! All changes made in this file will be lost!
+****************************************************************************/
+
+#ifndef DEFAULTCODEGENPOLICYPAGE_H
+#define DEFAULTCODEGENPOLICYPAGE_H
+
+#include <qvariant.h>
+#include <qwidget.h>
+#include "codegenerationpolicypage.h"
+
+class QVBoxLayout;
+class QHBoxLayout;
+class QGridLayout;
+class QLabel;
+class CodeGenePolicyExt;
+
+class DefaultCodeGenPolicyPage : public CodeGenerationPolicyPage
+{
+ Q_OBJECT
+
+public:
+
+ explicit DefaultCodeGenPolicyPage( QWidget* parent = 0, const char* name = 0, CodeGenPolicyExt * policy =0);
+
+ ~DefaultCodeGenPolicyPage();
+
+ QLabel* textLabel;
+
+protected:
+
+protected slots:
+
+};
+
+#endif // DEFAULTCODEGENPOLICYPAGE_H
diff --git a/umbrello/umbrello/dialogs/diagramprintpage.cpp b/umbrello/umbrello/dialogs/diagramprintpage.cpp
new file mode 100644
index 00000000..cf366197
--- /dev/null
+++ b/umbrello/umbrello/dialogs/diagramprintpage.cpp
@@ -0,0 +1,225 @@
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * copyright (C) 2002-2007 *
+ * Umbrello UML Modeller Authors <uml-devel@uml.sf.net> *
+ ***************************************************************************/
+
+// own header
+#include "diagramprintpage.h"
+
+// qt/kde includes
+#include <qlayout.h>
+#include <qptrlist.h>
+#include <qlistbox.h>
+#include <qradiobutton.h>
+#include <qcombobox.h>
+#include <qbuttongroup.h>
+#include <qgroupbox.h>
+#include <klocale.h>
+
+// local includes
+#include "../uml.h"
+#include "../umldoc.h"
+#include "../umlview.h"
+#include "../umlviewlist.h"
+#include "../umlnamespace.h"
+
+
+DiagramPrintPage::DiagramPrintPage(QWidget * parent, UMLDoc * m_pDoc) : KPrintDialogPage(parent), m_pDoc(m_pDoc) {
+ int margin = fontMetrics().height();
+ setTitle(i18n("&Diagrams"));
+ QHBoxLayout * mainLayout = new QHBoxLayout(this);
+ mainLayout -> setSpacing(10);
+ mainLayout -> setMargin(margin);
+
+ m_pFilterBG = new QButtonGroup(i18n("Filter"), this);
+ mainLayout -> addWidget(m_pFilterBG);
+ m_pFilterBG -> setExclusive(true);
+
+ QVBoxLayout * filter = new QVBoxLayout(m_pFilterBG);
+ filter -> setSpacing(10);
+ filter-> setMargin(margin);
+
+ m_pCurrentRB = new QRadioButton(i18n("&Current diagram"), m_pFilterBG);
+ filter -> addWidget(m_pCurrentRB);
+ m_pCurrentRB -> setChecked(true);
+ m_pFilterBG -> insert(m_pCurrentRB, Current);
+
+ m_pAllRB = new QRadioButton(i18n("&All diagrams"), m_pFilterBG);
+ filter -> addWidget(m_pAllRB);
+ m_pFilterBG -> insert(m_pAllRB, All);
+
+ m_pSelectRB = new QRadioButton(i18n("&Select diagrams"), m_pFilterBG);
+ filter -> addWidget(m_pSelectRB);
+ m_pFilterBG -> insert(m_pSelectRB, Select);
+
+ m_pTypeRB = new QRadioButton(i18n("&Type of diagram"), m_pFilterBG);
+ filter -> addWidget(m_pTypeRB);
+ m_pFilterBG -> insert(m_pTypeRB, Type);
+
+ m_pSelectGB = new QGroupBox(i18n("Selection"), this);
+ mainLayout -> addWidget(m_pSelectGB);
+
+ QVBoxLayout * select = new QVBoxLayout(m_pSelectGB);
+ select -> setSpacing(10);
+ select-> setMargin(margin);
+
+ m_pTypeCB = new QComboBox(m_pSelectGB);
+ select -> addWidget(m_pTypeCB);
+ m_pTypeCB -> setEnabled(false);
+
+ m_pSelectLB = new QListBox(m_pSelectGB);
+ select -> addWidget(m_pSelectLB);
+ m_pSelectLB -> setEnabled(false);
+ m_pSelectLB -> setSelectionMode(QListBox::Multi);
+ m_pSelectLB -> insertItem(UMLApp::app()->getCurrentView()->getName());
+ m_pSelectLB -> setSelected(0, true);
+ m_nIdList.clear();
+ m_nIdList.append(UMLApp::app()->getCurrentView()->getID());
+
+
+
+ m_ViewType = Uml::dt_Class;
+ connect(m_pFilterBG, SIGNAL(clicked(int)), this, SLOT(slotClicked(int)));
+ connect(m_pTypeCB, SIGNAL(activated(const QString&)), this, SLOT(slotActivated(const QString&)));
+
+ m_pTypeCB -> insertItem(i18n("Class"));
+ m_pTypeCB -> insertItem(i18n("Use Case"));
+ m_pTypeCB -> insertItem(i18n("Collaboration"));
+ m_pTypeCB -> insertItem(i18n("Sequence"));
+ m_pTypeCB -> insertItem(i18n("State"));
+ m_pTypeCB -> insertItem(i18n("Activity"));
+ m_pTypeCB -> insertItem(i18n("Component"));
+ m_pTypeCB -> insertItem(i18n("Deployment"));
+}
+
+DiagramPrintPage::~DiagramPrintPage()
+{
+ disconnect(m_pFilterBG, SIGNAL(clicked(int)), this, SLOT(slotClicked(int)));
+ disconnect(m_pTypeCB, SIGNAL(activated(const QString&)), this, SLOT(slotActivated(const QString&)));
+}
+
+void DiagramPrintPage::getOptions( QMap<QString,QString>& opts, bool /*incldef = false*/ ) {
+ int listCount = m_pSelectLB -> count();
+ int count = 0;
+
+ QString diagram(i18n("kde-uml-Diagram"));
+ for(int i=0;i<listCount;i++) {
+ if(m_pSelectLB -> isSelected(i)) {
+ UMLView *view = (UMLView *)m_pDoc -> findView(m_nIdList[i]);
+ QString sCount = QString("%1").arg(count);
+ QString sID = QString("%1").arg(ID2STR(view -> getID()));
+ opts.insert(diagram + sCount, sID);
+ count++;
+ }
+ }
+ opts.insert("kde-uml-count", QString("%1").arg(count));
+}
+
+void DiagramPrintPage::setOptions( const QMap<QString,QString>& /*opts*/ ) {}
+
+bool DiagramPrintPage::isValid( QString& msg ) {
+ int listCount = m_pSelectLB -> count();
+ bool sel = false;
+ for(int i =0;i<listCount;i++) {
+ if(m_pSelectLB -> isSelected(i)) {
+ sel = true;
+ i = listCount;
+ }
+ }
+ msg = i18n("No diagrams selected.");
+ return sel;
+}
+
+void DiagramPrintPage::slotClicked(int id) {
+ UMLViewList list = m_pDoc -> getViewIterator();
+ UMLView * view = 0;
+ QString type;
+
+ // clear list with diagrams to print
+ m_nIdList.clear();
+
+ switch(id) {
+ case Current:
+ m_pTypeCB -> setEnabled(false);
+ m_pSelectLB -> setEnabled(false);
+ m_pSelectLB -> clear();
+ m_pSelectLB -> insertItem(UMLApp::app()->getCurrentView()->getName());
+ m_pSelectLB -> setSelected(0, true);
+ m_nIdList.append(UMLApp::app()->getCurrentView()->getID());
+ break;
+
+ case All:
+
+ m_pTypeCB -> setEnabled(false);
+ m_pSelectLB -> setEnabled(false);
+ m_pSelectLB -> clear();
+ for(view = list.first(); view; view = list.next()) {
+ m_pSelectLB -> insertItem(view -> getName());
+ m_nIdList.append(view -> getID());
+ }
+ m_pSelectLB -> selectAll(true);
+ break;
+
+ case Select:
+ m_pTypeCB -> setEnabled(false);
+ m_pSelectLB -> setEnabled(true);
+ m_pSelectLB -> clear();
+ for(view = list.first(); view; view = list.next()) {
+ m_pSelectLB -> insertItem(view -> getName());
+ m_nIdList.append(view -> getID());
+ }
+ break;
+
+ case Type:
+ m_pTypeCB -> setEnabled(true);
+ m_pSelectLB -> setEnabled(true);
+ m_pSelectLB -> clear();
+ for(view = list.first(); view; view = list.next()) {
+ if(view -> getType() == m_ViewType) {
+ m_pSelectLB -> insertItem(view -> getName());
+ m_nIdList.append(view -> getID());
+ }
+ }
+ m_pSelectLB -> selectAll(true);
+ break;
+ }
+}
+
+void DiagramPrintPage::slotActivated(const QString & text) {
+ UMLViewList list = m_pDoc -> getViewIterator();
+ UMLView * view = 0;
+
+ if(text == i18n("Class"))
+ m_ViewType = Uml::dt_Class;
+ else if(text == i18n("Sequence"))
+ m_ViewType = Uml::dt_Sequence;
+ else if(text == i18n("Use Case"))
+ m_ViewType = Uml::dt_UseCase;
+ else if(text == i18n("Collaboration"))
+ m_ViewType = Uml::dt_Collaboration;
+ else if(text == i18n("State"))
+ m_ViewType = Uml::dt_State;
+ else if(text == i18n("Activity"))
+ m_ViewType = Uml::dt_Activity;
+ else if(text == i18n("Component"))
+ m_ViewType = Uml::dt_Component;
+ else if(text == i18n("Deployment"))
+ m_ViewType = Uml::dt_Deployment;
+ m_pSelectLB -> clear();
+ m_nIdList.clear();
+ for(view = list.first(); view; view = list.next()) {
+ if(view -> getType() == m_ViewType) {
+ m_pSelectLB -> insertItem(view -> getName());
+ m_nIdList.append(view -> getID());
+ }
+ }
+ m_pSelectLB -> selectAll(true);
+}
+
+#include "diagramprintpage.moc"
diff --git a/umbrello/umbrello/dialogs/diagramprintpage.h b/umbrello/umbrello/dialogs/diagramprintpage.h
new file mode 100644
index 00000000..f2184a27
--- /dev/null
+++ b/umbrello/umbrello/dialogs/diagramprintpage.h
@@ -0,0 +1,101 @@
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * copyright (C) 2002-2006 *
+ * Umbrello UML Modeller Authors <uml-devel@uml.sf.net> *
+ ***************************************************************************/
+
+#ifndef DIAGRAMPRINTPAGE_H
+#define DIAGRAMPRINTPAGE_H
+
+class QListBox;
+class QRadioButton;
+class QComboBox;
+class QButtonGroup;
+class QGroupBox;
+
+#include <kdeprint/kprintdialogpage.h>
+
+#include "../umldoc.h"
+#include "../umlview.h"
+/**
+ * This is a page on the print dialog to select what diagram(s)
+ * you wish to print. You add it to the @ref KPrinter instance.
+ *
+ * You will then need to get the options as shown in @ref KPrinter.
+ *
+ * @short A print dialog page.
+ * @author Paul Hensgen <phensgen@techie.com>
+ * @see KPrinter
+ * Bugs and comments to uml-devel@lists.sf.net or http://bugs.kde.org
+ */
+
+class DiagramPrintPage : public KPrintDialogPage {
+ Q_OBJECT
+public:
+ /**
+ * Constructs the diagram print page.
+ *
+ * @param parent The parent to the page.
+ * @param doc The @ref UMLDoc class instance being used.
+ */
+ DiagramPrintPage(QWidget * parent, UMLDoc *doc);
+
+ /**
+ * Stnadard deconstructor.
+ */
+ ~DiagramPrintPage();
+
+ /**
+ * Overriden method. It builds a list with the diagram name and the diagram
+ * IDs.
+ */
+ void getOptions(QMap<QString,QString>& opts, bool /* incldef=false */);
+
+ /**
+ * Overriden method.
+ */
+ void setOptions( const QMap<QString,QString>& /*opts*/ );
+
+ /**
+ * Overriden method.
+ */
+ bool isValid( QString& msg );
+
+private:
+ QButtonGroup * m_pFilterBG;
+ QGroupBox * m_pSelectGB;
+ QListBox * m_pSelectLB;
+ QRadioButton * m_pAllRB, * m_pCurrentRB, * m_pSelectRB, * m_pTypeRB;
+ QComboBox * m_pTypeCB;
+
+ UMLDoc * m_pDoc;
+ Uml::Diagram_Type m_ViewType;
+
+ /**
+ * list containing the IDs of diagrams to print
+ */
+ QValueList<Uml::IDType> m_nIdList;
+
+ enum FilterType{Current = 0, All, Select, Type};
+public slots:
+
+ /**
+ * Gets called when the users chooses to print all diagrams, the current
+ * diagram, a selection of diagrams or diagrams by type. It will change the
+ * listed diagrams in the diagram box.
+ */
+ void slotClicked(int id);
+
+ /**
+ * Gets called when the user chooses another diagram type. Only diagrams of
+ * this type will be shown in the diagram box.
+ */
+ void slotActivated(const QString & text);
+};
+
+#endif
diff --git a/umbrello/umbrello/dialogs/diagrampropertiespage.ui b/umbrello/umbrello/dialogs/diagrampropertiespage.ui
new file mode 100644
index 00000000..8a8d2826
--- /dev/null
+++ b/umbrello/umbrello/dialogs/diagrampropertiespage.ui
@@ -0,0 +1,410 @@
+<!DOCTYPE UI><UI version="3.1" stdsetdef="1">
+<class>DiagramPropertiesPage</class>
+<widget class="QWidget">
+ <property name="name">
+ <cstring>DiagramPropertiesPage</cstring>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>388</width>
+ <height>388</height>
+ </rect>
+ </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>Diagram Properties</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>Name:</string>
+ </property>
+ </widget>
+ <widget class="QLineEdit">
+ <property name="name">
+ <cstring>diagramName</cstring>
+ </property>
+ </widget>
+ </hbox>
+ </widget>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>layout20</cstring>
+ </property>
+ <hbox>
+ <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="QLabel">
+ <property name="name">
+ <cstring>TextLabel4</cstring>
+ </property>
+ <property name="text">
+ <string>Zoom:</string>
+ </property>
+ </widget>
+ <widget class="QSpinBox">
+ <property name="name">
+ <cstring>zoom</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>0</hsizetype>
+ <vsizetype>0</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="maxValue">
+ <number>500</number>
+ </property>
+ <property name="minValue">
+ <number>10</number>
+ </property>
+ </widget>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>textLabel1</cstring>
+ </property>
+ <property name="text">
+ <string>%</string>
+ </property>
+ </widget>
+ </hbox>
+ </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>50</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ <widget class="QCheckBox">
+ <property name="name">
+ <cstring>showOpSigs</cstring>
+ </property>
+ <property name="text">
+ <string>Show operation signature</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="QLayoutWidget">
+ <property name="name">
+ <cstring>layout7</cstring>
+ </property>
+ <hbox>
+ <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="QCheckBox">
+ <property name="name">
+ <cstring>showGrid</cstring>
+ </property>
+ <property name="text">
+ <string>Show &amp;grid</string>
+ </property>
+ </widget>
+ <widget class="QCheckBox">
+ <property name="name">
+ <cstring>snapToGrid</cstring>
+ </property>
+ <property name="text">
+ <string>Snap &amp;to grid</string>
+ </property>
+ </widget>
+ <widget class="QCheckBox">
+ <property name="name">
+ <cstring>snapComponentSizeToGrid</cstring>
+ </property>
+ <property name="text">
+ <string>Snap component size</string>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>Snap the size of the components to be a multiple of the grid spacing.
+If 'Snap to Grid' is enabled a component will always be aligned with the grid on all 4 sides.</string>
+ </property>
+ </widget>
+ </hbox>
+ </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>20</height>
+ </size>
+ </property>
+ </spacer>
+ </hbox>
+ </widget>
+ <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>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="QLabel">
+ <property name="name">
+ <cstring>TextLabel2</cstring>
+ </property>
+ <property name="text">
+ <string>Grid spacing: </string>
+ </property>
+ </widget>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>TextLabelX</cstring>
+ </property>
+ <property name="text">
+ <string>X</string>
+ </property>
+ </widget>
+ <widget class="QSpinBox">
+ <property name="name">
+ <cstring>gridSpaceX</cstring>
+ </property>
+ <property name="maxValue">
+ <number>100</number>
+ </property>
+ <property name="minValue">
+ <number>5</number>
+ </property>
+ </widget>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>TextLabel3</cstring>
+ </property>
+ <property name="text">
+ <string>Y</string>
+ </property>
+ </widget>
+ <widget class="QSpinBox">
+ <property name="name">
+ <cstring>gridSpaceY</cstring>
+ </property>
+ <property name="maxValue">
+ <number>100</number>
+ </property>
+ <property name="minValue">
+ <number>5</number>
+ </property>
+ </widget>
+ </hbox>
+ </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>
+ </hbox>
+ </widget>
+ <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>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="QLabel">
+ <property name="name">
+ <cstring>TextLabe15</cstring>
+ </property>
+ <property name="text">
+ <string>Line width: </string>
+ </property>
+ </widget>
+ <widget class="QSpinBox">
+ <property name="name">
+ <cstring>lineWidth</cstring>
+ </property>
+ <property name="maxValue">
+ <number>10</number>
+ </property>
+ <property name="minValue">
+ <number>0</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>20</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </hbox>
+ </widget>
+ </vbox>
+ </widget>
+ <widget class="QGroupBox">
+ <property name="name">
+ <cstring>GroupBox2</cstring>
+ </property>
+ <property name="title">
+ <string>Documentation</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="QTextEdit" row="0" column="0">
+ <property name="name">
+ <cstring>documentation</cstring>
+ </property>
+ </widget>
+ </grid>
+ </widget>
+ </vbox>
+</widget>
+<layoutdefaults spacing="6" margin="11"/>
+</UI>
diff --git a/umbrello/umbrello/dialogs/exportallviewsdialog.cpp b/umbrello/umbrello/dialogs/exportallviewsdialog.cpp
new file mode 100644
index 00000000..9f47afa5
--- /dev/null
+++ b/umbrello/umbrello/dialogs/exportallviewsdialog.cpp
@@ -0,0 +1,55 @@
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * copyright (C) 2006-2007 *
+ * Umbrello UML Modeller Authors <uml-devel@uml.sf.net> *
+ ***************************************************************************/
+
+// own header
+#include "exportallviewsdialog.h"
+
+// include files for Qt
+#include <qlayout.h>
+#include <qlabel.h>
+#include <qtooltip.h>
+
+// kde include files
+#include <kfilefiltercombo.h>
+#include <klocale.h>
+
+// application specific includes
+#include "../umlviewimageexportermodel.h"
+
+ExportAllViewsDialog::ExportAllViewsDialog(
+ QWidget* parent /* = 0 */,
+ const char* name /* = 0 */,
+ bool modal /* = false */,
+ WFlags fl /* = 0*/,
+ const QString &defaultMimeType /*= "image/png"*/)
+ : ExportAllViewsDialogBase(parent,name, modal,fl) {
+ // create and initialize m_imageType
+ m_imageType = new KFileFilterCombo(this, "m_imageType");
+ m_imageType->setSizePolicy(QSizePolicy(QSizePolicy::Preferred, QSizePolicy::Fixed, 0, 0, m_imageType->sizePolicy().hasHeightForWidth()));
+ m_imageType->setEditable(false);
+
+ m_imageType->setMimeFilter(UMLViewImageExporterModel::supportedMimeTypes(), defaultMimeType);
+
+ imageTypeLayout->addWidget(m_imageType);
+
+ imageTypeLabel->setBuddy(m_imageType);
+
+ // reload the strings so the m_imageType tooltip is added
+ languageChange();
+}
+
+void ExportAllViewsDialog::languageChange() {
+ ExportAllViewsDialogBase::languageChange();
+ QToolTip::add(m_imageType, tr2i18n("The format that the images will be exported to"));
+}
+
+#include "exportallviewsdialog.moc"
+
diff --git a/umbrello/umbrello/dialogs/exportallviewsdialog.h b/umbrello/umbrello/dialogs/exportallviewsdialog.h
new file mode 100644
index 00000000..37b0a2f3
--- /dev/null
+++ b/umbrello/umbrello/dialogs/exportallviewsdialog.h
@@ -0,0 +1,72 @@
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * copyright (C) 2006-2007 *
+ * Umbrello UML Modeller Authors <uml-devel@uml.sf.net> *
+ ***************************************************************************/
+
+#ifndef EXPORTALLVIEWSDIALOG_H
+#define EXPORTALLVIEWSDIALOG_H
+
+// application specific includes
+#include "exportallviewsdialogbase.h"
+
+// KDE forward declarations
+class KFileFilterCombo;
+
+/**
+ * Dialog for collecting the "Export all views" params.
+ * Inherits ExportAllViewsDialogBase and adds a KFileFilterCombo that uses
+ * only the mime types of the supported images types.
+ *
+ * The KFileFilterCombo is declared here instead of in the .ui file because QT
+ * Designer and uic don't recognize it.
+ */
+class ExportAllViewsDialog : public ExportAllViewsDialogBase {
+ Q_OBJECT
+
+public:
+
+ /**
+ * Constructor for UMLViewImageExporterModel.
+ *
+ * @param parent The parent of the dialog.
+ * @param name The internal name.
+ * @param modal If modal is true the dialog will block input to other the windows
+ * in the application until it's closed.
+ * @param fl Window flags.
+ * @param defaultMimeType The default mime type that appears in the mime types list.
+ *
+ * @see QDialog::QDialog
+ */
+ explicit ExportAllViewsDialog(QWidget* parent = 0, const char* name = 0,
+ bool modal = false, WFlags fl = 0,
+ const QString& defaultMimeType = "image/png");
+
+ /**
+ * Destructor for UMLViewImageExporterModel.
+ */
+ ~ExportAllViewsDialog() {
+ }
+
+ /**
+ * The image type selected.
+ */
+ KFileFilterCombo* m_imageType;
+
+protected slots:
+
+ /**
+ * Sets the strings of the subwidgets using the current
+ * language.
+ */
+ virtual void languageChange();
+
+};
+
+#endif
+
diff --git a/umbrello/umbrello/dialogs/exportallviewsdialogbase.ui b/umbrello/umbrello/dialogs/exportallviewsdialogbase.ui
new file mode 100644
index 00000000..c82820a3
--- /dev/null
+++ b/umbrello/umbrello/dialogs/exportallviewsdialogbase.ui
@@ -0,0 +1,216 @@
+<!DOCTYPE UI><UI version="3.3" stdsetdef="1">
+<class>ExportAllViewsDialogBase</class>
+<widget class="QDialog">
+ <property name="name">
+ <cstring>ExportAllViewsDialogBase</cstring>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>366</width>
+ <height>197</height>
+ </rect>
+ </property>
+ <property name="caption">
+ <string>Export all views</string>
+ </property>
+ <property name="sizeGripEnabled">
+ <bool>true</bool>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>mainLayout</cstring>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="spacing">
+ <number>15</number>
+ </property>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>kURLRequesterLayout</cstring>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>kURLRequesterLabel</cstring>
+ </property>
+ <property name="text">
+ <string>&amp;Directory to save the diagrams in:</string>
+ </property>
+ <property name="buddy" stdset="0">
+ <cstring>m_kURL</cstring>
+ </property>
+ <property name="toolTip" stdset="0">
+ <string>The base directory used to save the images</string>
+ </property>
+ </widget>
+ <widget class="KURLRequester">
+ <property name="name">
+ <cstring>m_kURL</cstring>
+ </property>
+ <property name="mode">
+ <number>2</number>
+ </property>
+ <property name="toolTip" stdset="0">
+ <string>The base directory used to save the images</string>
+ </property>
+ </widget>
+ </vbox>
+ </widget>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>imageTypeLayout</cstring>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>imageTypeLabel</cstring>
+ </property>
+ <property name="text">
+ <string>&amp;Image type:</string>
+ </property>
+ <property name="buddy" stdset="0">
+ <cstring>m_imageType</cstring>
+ </property>
+ <property name="toolTip" stdset="0">
+ <string>The format that the images will be exported to</string>
+ </property>
+ </widget>
+ </vbox>
+ </widget>
+ <widget class="QCheckBox">
+ <property name="name">
+ <cstring>m_useFolders</cstring>
+ </property>
+ <property name="text">
+ <string>Use &amp;folders</string>
+ </property>
+ <property name="toolTip" stdset="0">
+ <string>Create in the target directory the same tree structure used
+in the document to store the views</string>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>The views are stored in folders in the document. The same tree structure used in the document to store the views can be created in the selected base directory with this option.
+Only the folders made by the user are created in the base directory (Logical view, use case view and so on aren't created).</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>16</height>
+ </size>
+ </property>
+ </spacer>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>buttonsLayout</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>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>&amp;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>&amp;Cancel</string>
+ </property>
+ <property name="accel">
+ <string></string>
+ </property>
+ <property name="autoDefault">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </hbox>
+ </widget>
+ </vbox>
+</widget>
+<connections>
+ <connection>
+ <sender>buttonOk</sender>
+ <signal>clicked()</signal>
+ <receiver>ExportAllViewsDialogBase</receiver>
+ <slot>accept()</slot>
+ </connection>
+ <connection>
+ <sender>buttonCancel</sender>
+ <signal>clicked()</signal>
+ <receiver>ExportAllViewsDialogBase</receiver>
+ <slot>reject()</slot>
+ </connection>
+</connections>
+<layoutdefaults spacing="6" margin="11"/>
+<includehints>
+ <includehint>kurlrequester.h</includehint>
+ <includehint>klineedit.h</includehint>
+ <includehint>kpushbutton.h</includehint>
+</includehints>
+</UI>
diff --git a/umbrello/umbrello/dialogs/notedialog.cpp b/umbrello/umbrello/dialogs/notedialog.cpp
new file mode 100644
index 00000000..f310990d
--- /dev/null
+++ b/umbrello/umbrello/dialogs/notedialog.cpp
@@ -0,0 +1,53 @@
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * copyright (C) 2002-2007 *
+ * Umbrello UML Modeller Authors <uml-devel@uml.sf.net> *
+ ***************************************************************************/
+
+// own header
+#include "notedialog.h"
+
+// qt/kde includes
+#include <qlineedit.h>
+#include <qgroupbox.h>
+#include <qtextedit.h>
+#include <qlayout.h>
+#include <qlabel.h>
+#include <klocale.h>
+#include <kmessagebox.h>
+
+
+NoteDialog::NoteDialog( QWidget * parent, NoteWidget * pNote ) : KDialogBase(Plain, i18n("Note Documentation"), Help | Ok | Cancel , Ok, parent, "_NOTEDIALOG_", true, true) {
+ m_pNoteWidget = pNote;
+ int margin = fontMetrics().height();
+
+ m_pDocGB = new QGroupBox(i18n("Documentation"), plainPage());
+ QVBoxLayout * mainLayout = new QVBoxLayout(plainPage());
+ mainLayout -> addWidget(m_pDocGB);
+ mainLayout -> setSpacing(10);
+ mainLayout -> setMargin(margin);
+
+ QHBoxLayout * docLayout = new QHBoxLayout(m_pDocGB);
+ docLayout -> setSpacing(10);
+ docLayout -> setMargin(margin);
+
+ m_pDocTE = new QTextEdit( m_pDocGB );
+ m_pDocTE -> setFocus();
+ docLayout -> addWidget( m_pDocTE );
+ m_pDocTE -> setText( pNote -> getDoc() );
+ setMinimumSize(330, 160);
+}
+
+NoteDialog::~NoteDialog() {}
+
+void NoteDialog::slotOk() {
+ m_pNoteWidget -> setDoc( m_pDocTE -> text() );
+ accept();
+}
+
+#include "notedialog.moc"
diff --git a/umbrello/umbrello/dialogs/notedialog.h b/umbrello/umbrello/dialogs/notedialog.h
new file mode 100644
index 00000000..3efd1404
--- /dev/null
+++ b/umbrello/umbrello/dialogs/notedialog.h
@@ -0,0 +1,55 @@
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * copyright (C) 2002-2006 *
+ * Umbrello UML Modeller Authors <uml-devel@uml.sf.net> *
+ ***************************************************************************/
+
+#ifndef NOTEDIALOG_H
+#define NOTEDIALOG_H
+//kde includes
+#include <kdialogbase.h>
+//app includes
+#include "../notewidget.h"
+
+/**
+ * @author Paul Hensgen
+ * Bugs and comments to uml-devel@lists.sf.net or http://bugs.kde.org
+ */
+class QGroupBox;
+class QLineEdit;
+class QTextEdit;
+
+class NoteDialog : public KDialogBase {
+
+ Q_OBJECT
+
+public:
+ /**
+ * Constructs an NoteDialog.
+ */
+ NoteDialog( QWidget * parent, NoteWidget * pNote );
+
+ /**
+ * Standard deconstructor.
+ */
+ ~NoteDialog();
+
+public slots:
+ void slotOk();
+private:
+ //GUI widgets
+ QGroupBox * m_pDocGB;
+ QTextEdit * m_pDocTE;
+
+ /**
+ * Note widget to show documentation for.
+ */
+ NoteWidget * m_pNoteWidget;
+};
+
+#endif
diff --git a/umbrello/umbrello/dialogs/overwritedialogue.cpp b/umbrello/umbrello/dialogs/overwritedialogue.cpp
new file mode 100644
index 00000000..b7c4a4f4
--- /dev/null
+++ b/umbrello/umbrello/dialogs/overwritedialogue.cpp
@@ -0,0 +1,62 @@
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * copyright (C) 2003-2007 *
+ * Umbrello UML Modeller Authors <uml-devel@uml.sf.net> *
+ ***************************************************************************/
+
+// own header
+#include "overwritedialogue.h"
+
+// qt/kde includes
+#include <qcheckbox.h>
+#include <qlayout.h>
+#include <qlabel.h>
+#include <klocale.h>
+#include <kdebug.h>
+
+
+OverwriteDialogue::OverwriteDialogue(
+ const QString& fileName,
+ const QString& outputDirectory,
+ bool applyToAllRemaining, QWidget* parent, const char* name) :
+KDialogBase(Plain, i18n("Destination File Already Exists"), Ok|Apply|Cancel, Yes, parent, name) {
+
+ QVBoxLayout* layout = new QVBoxLayout( plainPage(), 0, spacingHint() );
+
+ QLabel* dialogueLabel = new QLabel(i18n("The file %1 already exists in %2.\n\nUmbrello can overwrite the file, generate a similar\nfile name or not generate this file.").arg(fileName).arg(outputDirectory), plainPage() );
+ layout->addWidget(dialogueLabel);
+
+ m_applyToAllRemaining = new QCheckBox( i18n("&Apply to all remaining files"), plainPage() );
+ m_applyToAllRemaining->setChecked(applyToAllRemaining);
+ layout->addWidget(m_applyToAllRemaining);
+
+ setButtonText(KDialogBase::Ok, i18n("&Overwrite"));
+ setButtonText(KDialogBase::Apply, i18n("&Generate Similar File Name"));
+ setButtonText(KDialogBase::Cancel, i18n("&Do Not Generate File"));
+}
+
+OverwriteDialogue::~OverwriteDialogue() {
+}
+
+void OverwriteDialogue::slotOk() {
+ done(Yes);
+}
+
+void OverwriteDialogue::slotApply() {
+ done(No);
+}
+
+void OverwriteDialogue::slotCancel() {
+ done(Cancel);
+}
+
+bool OverwriteDialogue::applyToAllRemaining() {
+ return m_applyToAllRemaining->isChecked();
+}
+
+#include "overwritedialogue.moc"
diff --git a/umbrello/umbrello/dialogs/overwritedialogue.h b/umbrello/umbrello/dialogs/overwritedialogue.h
new file mode 100644
index 00000000..a01e3366
--- /dev/null
+++ b/umbrello/umbrello/dialogs/overwritedialogue.h
@@ -0,0 +1,72 @@
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * copyright (C) 2002-2006 *
+ * Umbrello UML Modeller Authors <uml-devel@uml.sf.net> *
+ ***************************************************************************/
+
+#ifndef OVERWRITEDIALOGUE_H
+#define OVERWRITEDIALOGUE_H
+
+#include <kdialogbase.h>
+
+class QCheckBox;
+
+/**
+ * Used by CodeGenerator::findFileName when it needs to ask
+ * the user if they want to overwrite and existing file, generate a similar name
+ * or cancel. Gives an option to apply the choice to all remaining files.
+ *
+ * Uses OK and Apply buttons but overrides their text and behaviour, probably
+ * better to use user defined buttons but I couldn't work out how. KDialogBase guru needed.
+ *
+ * @author Jonathan Riddell <jr@jriddell.org>
+ * Bugs and comments to uml-devel@lists.sf.net or http://bugs.kde.org
+ */
+class OverwriteDialogue: public KDialogBase {
+ Q_OBJECT
+
+public:
+ /**
+ * constructor sets up the dialog, adding checkbox and label
+ */
+ OverwriteDialogue(const QString& fileName, const QString& outputDirectory,
+ bool applyToAllRemaining, QWidget* parent=0, const char* name=0);
+
+ /**
+ * destrictor doesn't do anything
+ */
+ ~OverwriteDialogue();
+
+ /**
+ * @return the value of the Apply To All Remaining Files checkbox
+ */
+ bool applyToAllRemaining();
+
+protected slots:
+ /**
+ * Overrides standard operation to call QDialog::done(Yes).
+ * This is a kludge, see note in class description.
+ */
+ virtual void slotOk();
+
+ /**
+ * Overrides standard operation to call QDialog::done(No).
+ */
+ virtual void slotApply();
+
+
+ /**
+ * Overrides standard operation to call QDialog::done(Cancel).
+ */
+ virtual void slotCancel();
+
+private:
+ QCheckBox* m_applyToAllRemaining;
+};
+
+#endif
diff --git a/umbrello/umbrello/dialogs/parmpropdlg.cpp b/umbrello/umbrello/dialogs/parmpropdlg.cpp
new file mode 100644
index 00000000..e8ddc245
--- /dev/null
+++ b/umbrello/umbrello/dialogs/parmpropdlg.cpp
@@ -0,0 +1,257 @@
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * copyright (C) 2002-2006 *
+ * Umbrello UML Modeller Authors <uml-devel@uml.sf.net> *
+ ***************************************************************************/
+
+// own header
+#include "parmpropdlg.h"
+
+// qt includes
+#include <qlayout.h>
+#include <qtooltip.h>
+
+// kde includes
+#include <klocale.h>
+#include <kdebug.h>
+
+// local includes
+#include "../classifier.h"
+#include "../umltemplatelist.h"
+#include "../template.h"
+#include "../umldoc.h"
+#include "../dialog_utils.h"
+#include "../object_factory.h"
+#include "../stereotype.h"
+
+#include "parmpropdlg.moc"
+
+ParmPropDlg::ParmPropDlg(QWidget * parent, UMLDoc * doc, UMLAttribute * a)
+ : KDialogBase(Plain, i18n("Parameter Properties"), Help | Ok | Cancel , Ok, parent, "_PARMPROPDLG_", true, true)
+{
+ m_pUmldoc = doc;
+ m_pAtt = a;
+ QString type, text, name, initialValue;
+ if(!a) {
+ type = text = name = initialValue = "";
+ } else {
+ type = a -> getTypeName();
+ name = a -> getName();
+ initialValue = a -> getInitialValue();
+ text = a -> getDoc();
+ }
+ int margin = fontMetrics().height();
+ setMinimumSize(300, 400);
+ //disableResize();
+ QVBoxLayout * topLayout = new QVBoxLayout(plainPage());
+ topLayout -> setSpacing(10);
+ topLayout -> setMargin(margin);
+
+ m_pParmGB = new QGroupBox(i18n("Properties"), plainPage());
+ topLayout -> addWidget(m_pParmGB);
+
+ QGridLayout * propLayout = new QGridLayout(m_pParmGB, 4, 2);
+ propLayout -> setSpacing(10);
+ propLayout -> setMargin(margin);
+
+ m_pTypeL = new QLabel(i18n("&Type:"), m_pParmGB);
+ propLayout -> addWidget(m_pTypeL, 0, 0);
+
+ m_pTypeCB = new KComboBox(m_pParmGB);
+ propLayout -> addWidget(m_pTypeCB, 0, 1);
+ m_pTypeL->setBuddy(m_pTypeCB);
+
+ Dialog_Utils::makeLabeledEditField( m_pParmGB, propLayout, 1,
+ m_pNameL, i18n("&Name:"),
+ m_pNameLE, name );
+
+ Dialog_Utils::makeLabeledEditField( m_pParmGB, propLayout, 2,
+ m_pInitialL, i18n("&Initial value:"),
+ m_pInitialLE, initialValue );
+
+ m_pStereoTypeL = new QLabel( i18n("Stereotype name:"), m_pParmGB );
+ propLayout -> addWidget(m_pStereoTypeL, 3, 0);
+ m_pStereoTypeCB = new KComboBox(true, m_pParmGB );
+ propLayout -> addWidget(m_pStereoTypeCB, 3, 1);
+
+ m_pKind = new QButtonGroup(i18n("Passing Direction"), plainPage());
+ m_pKind->setExclusive(true);
+ QToolTip::add(m_pKind, i18n("\"in\" is a readonly parameter, \"out\" is a writeonly parameter and \"inout\" is a parameter for reading and writing."));
+
+ QHBoxLayout * kindLayout = new QHBoxLayout( m_pKind );
+ kindLayout->setMargin(margin);
+
+ m_pIn = new QRadioButton( "in", m_pKind );
+ kindLayout->addWidget( m_pIn );
+
+ m_pInOut = new QRadioButton( "inout", m_pKind );
+ kindLayout->addWidget( m_pInOut );
+
+ m_pOut = new QRadioButton( "out", m_pKind );
+ kindLayout->addWidget( m_pOut );
+
+ topLayout -> addWidget(m_pKind);
+
+ m_pDocGB = new QGroupBox(i18n("Documentation"), plainPage());
+ QHBoxLayout * docLayout = new QHBoxLayout(m_pDocGB);
+ docLayout -> setMargin(margin);
+
+ m_pDoc = new QMultiLineEdit(m_pDocGB);
+ ///////////
+ m_pDoc->setWordWrap(QMultiLineEdit::WidgetWidth);
+ //////////
+ m_pDoc -> setText(text);
+ docLayout -> addWidget(m_pDoc);
+ topLayout -> addWidget(m_pDocGB);
+
+ // Check the proper Kind radiobutton.
+ if (a) {
+ Uml::Parameter_Direction kind = a->getParmKind();
+ if (kind == Uml::pd_Out)
+ m_pOut->setChecked(true);
+ else if (kind == Uml::pd_InOut)
+ m_pInOut->setChecked(true);
+ else
+ m_pIn->setChecked(true);
+ } else
+ m_pIn->setChecked(true);
+
+ m_pTypeCB->setDuplicatesEnabled(false);//only allow one of each type in box
+ m_pTypeCB->setEditable(true);
+ m_pTypeCB->setCompletionMode( KGlobalSettings::CompletionPopup );
+// m_pTypeCB->setAutoCompletion(false);
+
+ //add template parameters
+ UMLClassifier *pConcept = dynamic_cast<UMLClassifier*>( m_pAtt->parent()->parent() );
+ if (pConcept == NULL) {
+ kError() << "ParmPropDlg: grandparent of " << m_pAtt->getName()
+ << " is not a UMLClassifier" << endl;
+ } else {
+ UMLTemplateList tmplParams( pConcept->getTemplateList() );
+ for (UMLTemplate *t = tmplParams.first(); t; t = tmplParams.next())
+ insertType( t->getName() );
+ }
+ //now add the Concepts
+ UMLClassifierList namesList( m_pUmldoc->getConcepts() );
+ UMLClassifier * obj;
+ for(obj=namesList.first(); obj!=0 ;obj=namesList.next()) {
+ insertType( obj->getFullyQualifiedName() );
+ }
+
+ //work out which one to select
+ int typeBoxCount = 0;
+ bool foundType = false;
+ while (typeBoxCount < m_pTypeCB->count() && foundType == false) {
+ QString typeBoxString = m_pTypeCB->text(typeBoxCount);
+ if ( typeBoxString == type ) { //getTypeName()
+ foundType = true;
+ m_pTypeCB->setCurrentItem(typeBoxCount);
+ } else {
+ typeBoxCount++;
+ }
+ }
+
+ if (!foundType) {
+ insertType( type, 0 );
+ m_pTypeCB->setCurrentItem(0);
+ }
+
+ // manage stereotypes
+ m_pStereoTypeCB->setDuplicatesEnabled(false); //only allow one of each type in box
+ m_pStereoTypeCB->setCompletionMode( KGlobalSettings::CompletionPopup );
+ insertStereotype (QString("")); // an empty stereotype is the default
+ int defaultStereotype=0;
+ bool foundDefaultStereotype = false;
+ for (UMLStereotypeListIt it(m_pUmldoc->getStereotypes()); it.current(); ++it) {
+ if (!foundDefaultStereotype) {
+ if ( m_pAtt->getStereotype() == it.current()->getName()) {
+ foundDefaultStereotype = true;
+ }
+ defaultStereotype++;
+ }
+ insertStereotype (it.current()->getName());
+ }
+ // lookup for a default stereotype, if the operation doesn't have one
+ if (foundDefaultStereotype)
+ m_pStereoTypeCB->setCurrentItem(defaultStereotype);
+ else
+ m_pStereoTypeCB->setCurrentItem(-1);
+
+ // set tab order
+ setTabOrder(m_pKind, m_pTypeCB);
+ setTabOrder(m_pTypeCB, m_pNameLE);
+ setTabOrder(m_pNameLE, m_pInitialLE);
+ setTabOrder(m_pInitialLE, m_pStereoTypeCB);
+ setTabOrder(m_pStereoTypeCB, m_pIn);
+ setTabOrder(m_pIn, m_pDoc);
+
+ m_pNameLE->setFocus();
+}
+
+void ParmPropDlg::insertType( const QString& type, int index )
+{
+ m_pTypeCB->insertItem( type, index );
+ m_pTypeCB->completionObject()->addItem( type );
+}
+
+void ParmPropDlg::insertStereotype( const QString& type, int index )
+{
+ m_pStereoTypeCB->insertItem( type, index );
+ m_pStereoTypeCB->completionObject()->addItem( type );
+}
+
+Uml::Parameter_Direction ParmPropDlg::getParmKind() {
+ Uml::Parameter_Direction pk = Uml::pd_In;
+ if (m_pOut->isChecked())
+ pk = Uml::pd_Out;
+ else if (m_pInOut->isChecked())
+ pk = Uml::pd_InOut;
+ return pk;
+}
+
+void ParmPropDlg::slotOk() {
+ if (m_pAtt != NULL) {
+ m_pAtt->setParmKind( getParmKind() );
+ m_pAtt->setStereotype( m_pStereoTypeCB->currentText() );
+ QString typeName = m_pTypeCB->currentText();
+ UMLClassifier * pConcept = dynamic_cast<UMLClassifier*>( m_pAtt->parent()->parent() );
+ if (pConcept == NULL) {
+ kError() << "ParmPropDlg::slotOk: grandparent of " << m_pAtt->getName()
+ << " is not a UMLClassifier" << endl;
+ } else {
+ UMLTemplate *tmplParam = pConcept->findTemplate(typeName);
+ if (tmplParam) {
+ m_pAtt->setType(tmplParam);
+ accept();
+ return;
+ }
+ }
+ UMLClassifierList namesList( m_pUmldoc->getConcepts() );
+ UMLClassifier * obj;
+ for (obj = namesList.first(); obj; obj = namesList.next()) {
+ if (obj->getFullyQualifiedName() == typeName) {
+ m_pAtt->setType( obj );
+ break;
+ }
+ }
+ if (obj == NULL) {
+ // Nothing found: Create a new type on the fly.
+ // @todo There should be an extra dialog to decide whether to
+ // create a datatype or a class. For now, we create a class.
+ kDebug() << "ParmPropDlg::slotOk: " << typeName << " not found."
+ << " Creating a new class for the type." << endl;
+ UMLObject *o = Object_Factory::createUMLObject(Uml::ot_Class, typeName);
+ m_pAtt->setType(o);
+ }
+
+ }
+ accept();
+}
+
+ParmPropDlg::~ParmPropDlg() {}
+
diff --git a/umbrello/umbrello/dialogs/parmpropdlg.h b/umbrello/umbrello/dialogs/parmpropdlg.h
new file mode 100644
index 00000000..25a6153a
--- /dev/null
+++ b/umbrello/umbrello/dialogs/parmpropdlg.h
@@ -0,0 +1,125 @@
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * copyright (C) 2002-2006 *
+ * Umbrello UML Modeller Authors <uml-devel@uml.sf.net> *
+ ***************************************************************************/
+
+#ifndef PARMPROPDLG_H
+#define PARMPROPDLG_H
+
+#include <kdialogbase.h>
+#include <kcombobox.h>
+#include <qgroupbox.h>
+#include <qlabel.h>
+#include <qlayout.h>
+#include <qradiobutton.h>
+#include <qlineedit.h>
+#include <qbuttongroup.h>
+#include <qmultilineedit.h>
+#include <qcombobox.h>
+#include "../attribute.h"
+
+class UMLDoc;
+
+/**
+ * Displays a dialog box that displays properties of a paramater.
+ * You need to make sure that @ref UMLDoc is made to be the
+ * parent.
+ *
+ * @short A properties dialog box for a parameter.
+ * @author Paul Hensgen <phensgen@techie.com>
+ * Bugs and comments to uml-devel@lists.sf.net or http://bugs.kde.org
+ */
+class ParmPropDlg : public KDialogBase {
+ Q_OBJECT
+public:
+ /**
+ * Constructs a ParmPropDlg.
+ *
+ * @param parent The parent of the dialog.
+ * @param a The parameter to represent.
+ */
+ ParmPropDlg(QWidget * parent, UMLDoc * doc, UMLAttribute * a);
+
+ /**
+ * Standard deconstructor.
+ */
+ ~ParmPropDlg();
+
+ /**
+ * Returns the documentation.
+ *
+ * @return Returns the documentation.
+ */
+ QString getDoc() {
+ return m_pDoc -> text();
+ }
+
+ /**
+ * Return the name of the parameter.
+ *
+ * @return Return the name of the parameter.
+ */
+ QString getName() {
+ return m_pNameLE -> text();
+ }
+
+ /**
+ * Return the initial value of the parameter.
+ *
+ * @return Return the initial value of the parameter.
+ */
+ QString getInitialValue() {
+ return m_pInitialLE -> text();
+ }
+
+ /**
+ * Return the type name of the parameter.
+ *
+ * @return Return the type name of the parameter.
+ */
+ QString getTypeName() {
+ return m_pTypeCB -> currentText();
+ }
+
+ /**
+ * Return the kind of the parameter (in, out, or inout).
+ *
+ * @return The Uml::Parameter_Direction corresponding to
+ * the selected "Kind" radiobutton.
+ */
+ Uml::Parameter_Direction getParmKind();
+
+public slots:
+ void slotOk();
+
+protected:
+ /**
+ * Inserts @p type into the type-combobox as well as its completion object.
+ */
+ void insertType( const QString& type, int index = -1 );
+
+ /**
+ * Inserts @p type into the stereotype-combobox as well as its completion object.
+ */
+ void insertStereotype( const QString& type, int index = -1 );
+
+
+private:
+ QGroupBox * m_pParmGB, * m_pDocGB;
+ QButtonGroup *m_pKind;
+ QRadioButton * m_pIn, * m_pOut, *m_pInOut;
+ QLabel * m_pTypeL, * m_pNameL, * m_pInitialL, * m_pStereoTypeL;
+ KComboBox * m_pTypeCB, * m_pStereoTypeCB;
+ QLineEdit * m_pNameLE, * m_pInitialLE;
+ QMultiLineEdit * m_pDoc;
+ UMLDoc * m_pUmldoc;
+ UMLAttribute * m_pAtt;
+};
+
+#endif
diff --git a/umbrello/umbrello/dialogs/pkgcontentspage.cpp b/umbrello/umbrello/dialogs/pkgcontentspage.cpp
new file mode 100644
index 00000000..dd70f7fc
--- /dev/null
+++ b/umbrello/umbrello/dialogs/pkgcontentspage.cpp
@@ -0,0 +1,127 @@
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * copyright (C) 2003-2006 *
+ * Umbrello UML Modeller Authors <uml-devel@uml.sf.net> *
+ ***************************************************************************/
+
+#include "pkgcontentspage.h"
+#include <qlayout.h>
+#include <klocale.h>
+#include "../umlobjectlist.h"
+#include "../uml.h"
+#include "../umldoc.h"
+#include "classpropdlg.h"
+
+PkgContentsPage::PkgContentsPage(QWidget *parent, UMLPackage *pkg)
+ : QWidget(parent)
+{
+ m_pPackage = pkg;
+ int margin = fontMetrics().height();
+
+ QHBoxLayout * mainLayout = new QHBoxLayout(this);
+ mainLayout -> setSpacing(10);
+
+ m_pContentGB = new QGroupBox(i18n("Contained Items"), this);
+ mainLayout -> addWidget(m_pContentGB);
+
+ QHBoxLayout * layout = new QHBoxLayout(m_pContentGB);
+ layout -> setSpacing(10);
+ layout -> setMargin(margin);
+
+ m_pContentLB = new QListBox(m_pContentGB);
+ layout -> addWidget(m_pContentLB);
+ setMinimumSize(310, 330);
+ fillListBox();
+ m_pMenu = 0;
+
+ connect(m_pContentLB, SIGNAL(doubleClicked(QListBoxItem *)),
+ this, SLOT(slotDoubleClick(QListBoxItem *)));
+
+ connect(m_pContentLB, SIGNAL(rightButtonPressed(QListBoxItem *, const QPoint &)),
+ this, SLOT(slotRightButtonPressed(QListBoxItem *, const QPoint &)));
+
+ connect(m_pContentLB, SIGNAL(rightButtonClicked(QListBoxItem *, const QPoint &)),
+ this, SLOT(slotRightButtonClicked(QListBoxItem *, const QPoint &)));
+}
+
+PkgContentsPage::~PkgContentsPage() {
+ disconnect(m_pContentLB, SIGNAL(doubleClicked(QListBoxItem *)),
+ this, SLOT(slotDoubleClick(QListBoxItem *)));
+
+ disconnect(m_pContentLB, SIGNAL(rightButtonPressed(QListBoxItem *, const QPoint &)),
+ this, SLOT(slotRightButtonPressed(QListBoxItem *, const QPoint &)));
+
+ disconnect(m_pContentLB, SIGNAL(rightButtonClicked(QListBoxItem *, const QPoint &)),
+ this, SLOT(slotRightButtonClicked(QListBoxItem *, const QPoint &)));
+}
+
+void PkgContentsPage::slotDoubleClick(QListBoxItem * i) {
+ if (!i)
+ return;
+ int item = m_pContentLB -> currentItem();
+ UMLObjectList contents = m_pPackage->containedObjects();
+ UMLObject *o = contents.at(item);
+ ClassPropDlg dlg(this, o, item, true);
+ dlg.exec();
+}
+
+void PkgContentsPage::fillListBox() {
+ m_pContentLB->clear();
+ UMLObjectList contents = m_pPackage->containedObjects();
+ UMLObjectListIt objList_it(contents);
+ UMLObject* umlo = NULL;
+ int i = 0;
+ while ((umlo = objList_it.current()) != NULL) {
+ m_pContentLB->insertItem(umlo->getName(), i++);
+ ++objList_it;
+ }
+}
+
+void PkgContentsPage::slotRightButtonClicked(QListBoxItem */* item*/, const QPoint &/* p*/) {
+ if(m_pMenu) {
+ m_pMenu -> hide();
+ disconnect(m_pMenu, SIGNAL(activated(int)), this, SLOT(slotPopupMenuSel(int)));
+ delete m_pMenu;
+ m_pMenu = 0;
+ }
+}
+
+void PkgContentsPage::slotRightButtonPressed(QListBoxItem * item, const QPoint & p) {
+ if(!item)
+ return;
+ if(m_pMenu) {
+ m_pMenu -> hide();
+ disconnect(m_pMenu, SIGNAL(activated(int)), this, SLOT(slotPopupMenuSel(int)));
+ delete m_pMenu;
+ m_pMenu = 0;
+ }
+ m_pMenu = new ListPopupMenu(this, ListPopupMenu::mt_Association_Selected);
+ m_pMenu->popup(p);
+ connect(m_pMenu, SIGNAL(activated(int)), this, SLOT(slotPopupMenuSel(int)));
+}
+
+void PkgContentsPage::slotPopupMenuSel(int id) {
+ switch(id) {
+ case ListPopupMenu::mt_Delete:
+ {
+ UMLObjectList contents = m_pPackage->containedObjects();
+ UMLObject *o = contents.at( m_pContentLB->currentItem() );
+ UMLApp::app()->getDocument()->removeUMLObject(o);
+ fillListBox();
+ }
+ break;
+
+ case ListPopupMenu::mt_Properties:
+ slotDoubleClick(m_pContentLB->item(m_pContentLB->currentItem()));
+ break;
+ }
+}
+
+
+
+#include "pkgcontentspage.moc"
diff --git a/umbrello/umbrello/dialogs/pkgcontentspage.h b/umbrello/umbrello/dialogs/pkgcontentspage.h
new file mode 100644
index 00000000..8659e672
--- /dev/null
+++ b/umbrello/umbrello/dialogs/pkgcontentspage.h
@@ -0,0 +1,62 @@
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * copyright (C) 2003-2006 *
+ * Umbrello UML Modeller Authors <uml-devel@uml.sf.net> *
+ ***************************************************************************/
+
+#ifndef PKGCONTENTSPAGE_H
+#define PKGCONTENTSPAGE_H
+
+#include <qwidget.h>
+#include <qgroupbox.h>
+#include <qlistbox.h>
+#include <qptrlist.h>
+
+#include "../package.h"
+#include "../listpopupmenu.h"
+
+/**
+ * @short The page shows all the objects that belong to a @ref UMLPackage.
+ * @author Oliver Kellogg <okellogg@users.sourceforge.net>
+ * Bugs and comments to uml-devel@lists.sf.net or http://bugs.kde.org
+ */
+class PkgContentsPage : public QWidget {
+ Q_OBJECT
+public:
+ /**
+ * Constructs an instance of PkgContentsPage.
+ *
+ * @param parent The parent of the page.
+ * @param pkg The UMLPackage being represented.
+ */
+ PkgContentsPage(QWidget *parent, UMLPackage *pkg);
+
+ /**
+ * Standard destructor.
+ */
+ ~PkgContentsPage();
+
+private:
+ UMLPackage * m_pPackage;
+ QListBox * m_pContentLB;
+ QGroupBox * m_pContentGB;
+ ListPopupMenu * m_pMenu;
+
+ /**
+ * Fills the list box with the package's contents.
+ */
+ void fillListBox();
+
+public slots:
+ void slotDoubleClick(QListBoxItem * i);
+ void slotRightButtonClicked(QListBoxItem */* item*/, const QPoint &/* p*/);
+ void slotRightButtonPressed(QListBoxItem * item, const QPoint & p);
+ void slotPopupMenuSel(int id);
+};
+
+#endif
diff --git a/umbrello/umbrello/dialogs/selectopdlg.cpp b/umbrello/umbrello/dialogs/selectopdlg.cpp
new file mode 100644
index 00000000..cb9e344d
--- /dev/null
+++ b/umbrello/umbrello/dialogs/selectopdlg.cpp
@@ -0,0 +1,141 @@
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * copyright (C) 2002-2006 *
+ * Umbrello UML Modeller Authors <uml-devel@uml.sf.net> *
+ ***************************************************************************/
+
+// own header
+#include "selectopdlg.h"
+
+// qt includes
+#include <qlayout.h>
+
+// kde includes
+#include <klocale.h>
+#include <kdebug.h>
+
+// local includes
+#include "../attribute.h"
+#include "../operation.h"
+#include "../umlclassifierlistitemlist.h"
+#include "../umlview.h"
+#include "../dialog_utils.h"
+
+SelectOpDlg::SelectOpDlg(UMLView * parent, UMLClassifier * c)
+ : KDialogBase(Plain, i18n("Select Operation"), Ok | Cancel , Ok, parent, "_SELOPDLG_", true, true)
+{
+ m_pView = parent;
+ QVBoxLayout * topLayout = new QVBoxLayout(plainPage());
+
+ m_pOpGB = new QGroupBox(i18n("Select Operation"), plainPage());
+ topLayout -> addWidget(m_pOpGB);
+
+ QGridLayout * mainLayout = new QGridLayout(m_pOpGB, 3, 2);
+ mainLayout -> setSpacing(spacingHint());
+ mainLayout -> setMargin(fontMetrics().height());
+
+ Dialog_Utils::makeLabeledEditField( m_pOpGB, mainLayout, 0,
+ m_pSeqL, i18n("Sequence number:"),
+ m_pSeqLE );
+
+ m_pOpRB = new QRadioButton(i18n("Class operation:"), m_pOpGB);
+ mainLayout -> addWidget(m_pOpRB, 1, 0);
+
+ m_pOpCB = new KComboBox(m_pOpGB);
+ m_pOpCB->setCompletionMode( KGlobalSettings::CompletionPopup );
+ m_pOpCB->setDuplicatesEnabled(false);//only allow one of each type in box
+ mainLayout -> addWidget(m_pOpCB, 1, 1);
+
+ m_pCustomRB = new QRadioButton(i18n("Custom operation:"), m_pOpGB);
+ mainLayout -> addWidget(m_pCustomRB, 2, 0);
+
+ m_pOpLE = new QLineEdit(m_pOpGB);
+ mainLayout -> addWidget(m_pOpLE, 2, 1);
+
+ m_pOpBG = new QButtonGroup(0);
+ m_pOpBG -> insert(m_pOpRB, OP);
+ m_pOpBG -> insert(m_pCustomRB, CUSTOM);
+ m_pOpBG -> setExclusive(true);
+ m_pOpBG -> setButton(OP);
+
+ UMLOperationList list = c -> getOpList(true);
+ for (UMLOperation *obj = list.first(); obj; obj=list.next()) {
+ insertOperation( obj->toString(Uml::st_SigNoVis) );
+ }
+ //disableResize();
+ connect(m_pOpBG, SIGNAL(clicked(int)), this, SLOT(slotSelected(int)));
+ m_nOpCount = c -> operations();
+ slotSelected(OP);
+}
+
+SelectOpDlg::~SelectOpDlg() {
+ disconnect(m_pOpBG, SIGNAL(clicked(int)), this, SLOT(slotSelected(int)));
+ delete m_pOpBG;
+}
+
+void SelectOpDlg::insertOperation( const QString& type, int index )
+{
+ m_pOpCB->insertItem( type, index );
+ m_pOpCB->completionObject()->addItem( type );
+}
+
+QString SelectOpDlg::getOpText() {
+ if(m_pOpRB -> isChecked())
+ return m_pOpCB -> currentText();
+ else
+ return m_pOpLE -> text();
+}
+
+bool SelectOpDlg::isClassOp() const {
+ return (m_id == OP);
+}
+
+void SelectOpDlg::slotSelected(int id) {
+ if(id == OP) {
+ m_pOpLE -> setEnabled(false);
+ if(m_nOpCount > 0)
+ m_pOpCB -> setEnabled(true);
+ } else {
+ m_pOpLE -> setEnabled(true);
+ m_pOpCB -> setEnabled(false);
+ }
+ m_id = id;
+}
+
+void SelectOpDlg::setCustomOp(const QString &op) {
+ m_pOpLE -> setText(op);
+ if(op.length() > 0) {
+ slotSelected(CUSTOM);
+ m_pCustomRB -> setChecked(true);
+ }
+}
+
+bool SelectOpDlg::setClassOp(const QString &op) {
+ for (int i = 1; i!= m_pOpCB->count(); ++i)
+ {
+ if ( m_pOpCB->text(i) == op ) {
+ m_pOpCB->setCurrentItem(i);
+ m_pCustomRB -> setChecked(false);
+ slotSelected(OP);
+ return true;
+ }
+ }
+ return false;
+}
+
+QString SelectOpDlg::getSeqNumber() {
+ return m_pSeqLE->text();
+}
+
+void SelectOpDlg::setSeqNumber(const QString &num) {
+ m_pSeqLE->setText(num);
+}
+
+
+
+#include "selectopdlg.moc"
diff --git a/umbrello/umbrello/dialogs/selectopdlg.h b/umbrello/umbrello/dialogs/selectopdlg.h
new file mode 100644
index 00000000..c5d8c93b
--- /dev/null
+++ b/umbrello/umbrello/dialogs/selectopdlg.h
@@ -0,0 +1,120 @@
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * copyright (C) 2002-2006 *
+ * Umbrello UML Modeller Authors <uml-devel@uml.sf.net> *
+ ***************************************************************************/
+
+
+#ifndef SELECTOPDLG_H
+#define SELECTOPDLG_H
+
+#include <kdialogbase.h>
+
+#include <qgroupbox.h>
+#include <kcombobox.h>
+#include <qradiobutton.h>
+#include <qbuttongroup.h>
+#include <qlineedit.h>
+#include <qlabel.h>
+#include "../classifier.h"
+
+class UMLView;
+
+#define OP 0
+#define CUSTOM 1
+
+/**
+ * A dialog used to select an operation.
+ *
+ * @short A dialog to select an operation.
+ * @author Paul Hensgen <phensgen@techie.com>
+ * Bugs and comments to uml-devel@lists.sf.net or http://bugs.kde.org
+ */
+
+class SelectOpDlg : public KDialogBase
+{
+ Q_OBJECT
+public:
+ /**
+ * Constructs a SelectOpDlg instance.
+ *
+ * @param parent The parent to this instance.
+ * @param c The concept to get the operations from.
+ */
+ SelectOpDlg(UMLView * parent, UMLClassifier * c);
+
+ /**
+ * Standard deconstructor.
+ */
+ ~SelectOpDlg();
+
+ /**
+ * Returns the operation to display.
+ *
+ * @return The operation to display.
+ */
+ QString getOpText();
+
+ /**
+ * Return whether the user selected a class operation
+ * or a custom operation.
+ *
+ * @return True if user selected a class operation,
+ * false if user selected a custom operation
+ */
+ bool isClassOp() const;
+
+ /**
+ * Returns the sequence number for the operation.
+ *
+ * @return Returns the sequence number for the operation.
+ */
+ QString getSeqNumber();
+
+ /**
+ * Set the sequence number text.
+ *
+ * @param num The number to set the sequence to.
+ */
+ void setSeqNumber(const QString &num);
+
+ /**
+ * Set the custom operation text.
+ *
+ * @param op The operation to set as the custom operation.
+ */
+ void setCustomOp(const QString &op);
+ /**
+ * Set the class operation text.
+ *
+ * @param op The operation to set as the class operation.
+ * @return false if no such operation exists.
+ */
+ bool setClassOp(const QString &op);
+protected:
+ /**
+ * Inserts @p type into the type-combobox as well as its completion object.
+ */
+ void insertOperation( const QString& type, int index = -1 );
+private:
+ QGroupBox * m_pOpGB;
+ KComboBox * m_pOpCB;
+ QLabel * m_pSeqL;
+ QLineEdit * m_pOpLE, * m_pSeqLE;
+ QRadioButton * m_pCustomRB, * m_pOpRB;
+ QButtonGroup * m_pOpBG, * m_pDocGB;
+ QString m_Text;
+ int m_nOpCount;
+ int m_id; ///< takes on the value OP or CUSTOM according to what the user selected
+ UMLView *m_pView;
+public slots:
+ void slotSelected(int id);
+};
+
+#endif
+
diff --git a/umbrello/umbrello/dialogs/settingsdlg.cpp b/umbrello/umbrello/dialogs/settingsdlg.cpp
new file mode 100644
index 00000000..2bfaaf29
--- /dev/null
+++ b/umbrello/umbrello/dialogs/settingsdlg.cpp
@@ -0,0 +1,443 @@
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * copyright (C) 2002-2006 *
+ * Umbrello UML Modeller Authors <uml-devel@uml.sf.net> *
+ ***************************************************************************/
+
+// own header
+#include "settingsdlg.h"
+
+// qt includes
+#include <qlayout.h>
+#include <qtooltip.h>
+#include <qvbox.h>
+// kde includes
+#include <kdebug.h>
+#include <kiconloader.h>
+#include <klocale.h>
+#include <kfiledialog.h>
+// app includes
+#include "codegenerationoptionspage.h"
+#include "codevieweroptionspage.h"
+#include "../dialog_utils.h"
+
+SettingsDlg::SettingsDlg( QWidget * parent, Settings::OptionState *state )
+ : KDialogBase( IconList, i18n("Umbrello Setup"),
+ Help | Default | Apply | Ok | Cancel, Ok, parent, 0, true, true ) {
+ m_bChangesApplied = false;
+ m_pOptionState = state;
+ setHelp( "umbrello/index.html", QString::null );
+ setupGeneralPage();
+ setupFontPage();
+ setupUIPage();
+ setupClassPage();
+ setupCodeGenPage();
+ setupCodeViewerPage(state->codeViewerState);
+}
+
+SettingsDlg::~SettingsDlg() {}
+
+void SettingsDlg::setupUIPage() {
+ //setup UI page
+ QVBox * page = addVBoxPage( i18n("User Interface"), i18n("User Interface Settings"), DesktopIcon( "window_list") );
+
+ m_UiWidgets.colorGB = new QGroupBox( i18n("Color"), page );
+ QGridLayout * colorLayout = new QGridLayout( m_UiWidgets.colorGB, 3, 3 );
+ colorLayout -> setSpacing( spacingHint() );
+ colorLayout -> setMargin( fontMetrics().height() );
+
+ m_UiWidgets.lineColorL = new QLabel( i18n("Line color:"), m_UiWidgets.colorGB );
+ colorLayout -> addWidget( m_UiWidgets.lineColorL, 0, 0 );
+
+ m_UiWidgets.lineColorB = new KColorButton( m_pOptionState->uiState.lineColor, m_UiWidgets.colorGB );
+ colorLayout -> addWidget( m_UiWidgets.lineColorB, 0, 1 );
+
+ m_UiWidgets.lineDefaultB = new QPushButton( i18n("D&efault Color"), m_UiWidgets.colorGB );
+ colorLayout -> addWidget( m_UiWidgets.lineDefaultB, 0, 2 );
+
+ m_UiWidgets.fillColorL = new QLabel( i18n("Fill color:"), m_UiWidgets.colorGB );
+ colorLayout -> addWidget( m_UiWidgets.fillColorL, 1, 0 );
+
+ m_UiWidgets.fillColorB = new KColorButton( m_pOptionState->uiState.fillColor, m_UiWidgets.colorGB );
+ colorLayout -> addWidget( m_UiWidgets.fillColorB, 1, 1 );
+
+ m_UiWidgets.fillDefaultB = new QPushButton( i18n("De&fault Color"), m_UiWidgets.colorGB );
+ colorLayout -> addWidget( m_UiWidgets.fillDefaultB, 1, 2 );
+
+
+ m_UiWidgets.lineWidthL = new QLabel( i18n("Line width:"), m_UiWidgets.colorGB );
+ colorLayout -> addWidget( m_UiWidgets.lineWidthL, 2, 0 );
+
+ // Low-Limit: 0, High-Limit: 10, Step: 1, Initial-Val: m_pOptionState->uiState.lineWidth
+ // Number-Base: 10 ( decimal ), Parent: m_UiWidgets.colorGB
+ m_UiWidgets.lineWidthB = new KIntSpinBox( 0, 10, 1, m_pOptionState->uiState.lineWidth, 10, m_UiWidgets.colorGB );
+ colorLayout -> addWidget( m_UiWidgets.lineWidthB, 2, 1 );
+
+ m_UiWidgets.lineWidthDefaultB = new QPushButton( i18n("D&efault Width"), m_UiWidgets.colorGB );
+ colorLayout -> addWidget( m_UiWidgets.lineWidthDefaultB, 2, 2 );
+
+
+
+ m_UiWidgets.useFillColorCB = new QCheckBox( i18n("&Use fill color"), m_UiWidgets.colorGB );
+ colorLayout -> setRowStretch( 3, 2 );
+ colorLayout -> addWidget( m_UiWidgets.useFillColorCB, 3, 0 );
+ m_UiWidgets.useFillColorCB -> setChecked( m_pOptionState->uiState.useFillColor );
+
+ //connect button signals up
+ connect( m_UiWidgets.lineDefaultB, SIGNAL(clicked()), this, SLOT(slotLineBClicked()) );
+ connect( m_UiWidgets.fillDefaultB, SIGNAL(clicked()), this, SLOT(slotFillBClicked()) );
+}
+
+void SettingsDlg::setupGeneralPage() {
+ //setup General page
+
+ QVBox * page = addVBoxPage( i18n("General"), i18n("General Settings"), DesktopIcon( "misc") );
+
+ // Set up undo setting
+ m_GeneralWidgets.miscGB = new QGroupBox( i18n("Miscellaneous"), page );
+
+ QGridLayout * miscLayout = new QGridLayout( m_GeneralWidgets.miscGB, 2, 2 );
+ miscLayout -> setSpacing( spacingHint() );
+ miscLayout -> setMargin( fontMetrics().height() );
+
+ m_GeneralWidgets.undoCB = new QCheckBox( i18n("Enable undo"), m_GeneralWidgets.miscGB );
+ m_GeneralWidgets.undoCB -> setChecked( m_pOptionState->generalState.undo );
+ miscLayout -> addWidget( m_GeneralWidgets.undoCB, 0, 0 );
+
+ m_GeneralWidgets.tabdiagramsCB = new QCheckBox( i18n("Use tabbed diagrams"), m_GeneralWidgets.miscGB );
+ m_GeneralWidgets.tabdiagramsCB -> setChecked( m_pOptionState->generalState.tabdiagrams );
+ miscLayout -> addWidget( m_GeneralWidgets.tabdiagramsCB, 0, 1 );
+
+ m_GeneralWidgets.newcodegenCB = new QCheckBox( i18n("Use new C++/Java/Ruby generators"), m_GeneralWidgets.miscGB );
+ m_GeneralWidgets.newcodegenCB -> setChecked( m_pOptionState->generalState.newcodegen );
+ miscLayout -> addWidget( m_GeneralWidgets.newcodegenCB, 1, 0 );
+
+ m_GeneralWidgets.angularLinesCB = new QCheckBox( i18n("Use angular association lines"), m_GeneralWidgets.miscGB );
+ m_GeneralWidgets.angularLinesCB -> setChecked( m_pOptionState->generalState.angularlines );
+ miscLayout -> addWidget( m_GeneralWidgets.angularLinesCB, 1, 1 );
+
+ //setup autosave settings
+
+ m_GeneralWidgets.autosaveGB = new QGroupBox( i18n("Autosave"), page );
+
+ QGridLayout * autosaveLayout = new QGridLayout( m_GeneralWidgets.autosaveGB, 3, 2 );
+ autosaveLayout -> setSpacing( spacingHint() );
+ autosaveLayout -> setMargin( fontMetrics().height() );
+
+ m_GeneralWidgets.autosaveCB = new QCheckBox( i18n("E&nable autosave"), m_GeneralWidgets.autosaveGB );
+ m_GeneralWidgets.autosaveCB -> setChecked( m_pOptionState->generalState.autosave );
+ autosaveLayout -> addWidget( m_GeneralWidgets.autosaveCB, 0, 0 );
+
+ m_GeneralWidgets.autosaveL = new QLabel( i18n("Select auto-save time interval (mins):"), m_GeneralWidgets.autosaveGB );
+ autosaveLayout -> addWidget( m_GeneralWidgets.autosaveL, 1, 0 );
+
+ m_GeneralWidgets.timeISB = new KIntSpinBox( 1, 600, 1, m_pOptionState->generalState.autosavetime, 10, m_GeneralWidgets.autosaveGB );
+ m_GeneralWidgets.timeISB -> setEnabled( m_pOptionState->generalState.autosave );
+ autosaveLayout -> addWidget( m_GeneralWidgets.timeISB, 1, 1 );
+
+ // 2004-05-17 Achim Spangler: Allow definition of Suffix for autosave
+ // ( default: ".xmi" )
+ Dialog_Utils::makeLabeledEditField( m_GeneralWidgets.autosaveGB, autosaveLayout, 2,
+ m_GeneralWidgets.autosaveSuffixL, i18n("Set autosave suffix:"),
+ m_GeneralWidgets.autosaveSuffixT, m_pOptionState->generalState.autosavesuffix );
+ QString autoSaveSuffixToolTip = i18n( "<qt><p>The autosave file will be saved to ~/autosave.xmi if the autosaving occurs "
+ "before you have manually saved the file.</p>"
+ "<p>If you've already saved it, the autosave file will be saved in the same folder as the file "
+ "and will be named like the file's name, followed by the suffix specified.</p>"
+ "<p>If the suffix is equal to the suffix of the file you've saved, "
+ "the autosave will overwrite your file automatically.</p></qt>" );
+ QToolTip::add( m_GeneralWidgets.autosaveSuffixL, autoSaveSuffixToolTip );
+ QToolTip::add( m_GeneralWidgets.autosaveSuffixT, autoSaveSuffixToolTip );
+
+ //setup startup settings
+ m_GeneralWidgets.startupGB = new QGroupBox( i18n("Startup"), page );
+
+ QGridLayout * startupLayout = new QGridLayout( m_GeneralWidgets.startupGB, 3, 2 );
+ startupLayout -> setSpacing( spacingHint() );
+ startupLayout -> setMargin( fontMetrics().height() );
+
+ m_GeneralWidgets.logoCB = new QCheckBox( i18n("Sta&rtup logo"), m_GeneralWidgets.startupGB );
+ m_GeneralWidgets.logoCB -> setChecked( m_pOptionState->generalState.logo );
+ startupLayout -> addWidget( m_GeneralWidgets.logoCB, 0, 0 );
+
+ m_GeneralWidgets.tipCB = new QCheckBox( i18n("&Tip of the day"), m_GeneralWidgets.startupGB );
+ m_GeneralWidgets.tipCB -> setChecked( m_pOptionState->generalState.tip );
+ startupLayout -> addWidget( m_GeneralWidgets.tipCB, 0, 1 );
+
+ m_GeneralWidgets.loadlastCB = new QCheckBox( i18n("&Load last project"), m_GeneralWidgets.startupGB );
+ m_GeneralWidgets.loadlastCB -> setChecked( m_pOptionState->generalState.loadlast );
+ startupLayout -> addWidget( m_GeneralWidgets.loadlastCB, 1, 0 );
+
+ m_GeneralWidgets.startL = new QLabel( i18n("Start new project with:"), m_GeneralWidgets.startupGB );
+ startupLayout -> addWidget( m_GeneralWidgets.startL, 2, 0 );
+
+ m_GeneralWidgets.diagramKB = new KComboBox( m_GeneralWidgets.startupGB );
+ m_GeneralWidgets.diagramKB->setCompletionMode( KGlobalSettings::CompletionPopup );
+ startupLayout -> addWidget( m_GeneralWidgets.diagramKB, 2, 1 );
+
+ QString diagrams [] = { i18n("No Diagram"), i18n("Class Diagram"),
+ i18n("Use Case Diagram"), i18n("Sequence Diagram"),
+ i18n("Collaboration Diagram"), i18n("State Diagram"),
+ i18n("Activity Diagram"), i18n("Component Diagram"),
+ i18n("Deployment Diagram") };
+
+ //start at 1 because we don't allow No Diagram any more
+ for (int i=1; i<9; i++) {
+ insertDiagram( diagrams[i] );
+ }
+
+ m_GeneralWidgets.diagramKB->setCurrentItem( (int)m_pOptionState->generalState.diagram-1 );
+ connect( m_GeneralWidgets.autosaveCB, SIGNAL(clicked()), this, SLOT(slotAutosaveCBClicked()) );
+}
+
+/**
+* Inserts @p type into the type-combobox as well as its completion object.
+*/
+void SettingsDlg::insertDiagram( const QString& type, int index )
+{
+ m_GeneralWidgets.diagramKB->insertItem( type, index );
+ m_GeneralWidgets.diagramKB->completionObject()->addItem( type );
+}
+
+void SettingsDlg::setupClassPage() {
+ //setup class settings page
+
+ QVBox * page = addVBoxPage( i18n("Class"), i18n("Class Settings"), DesktopIcon( "edit") );
+ m_ClassWidgets.visibilityGB = new QGroupBox( i18n("Visibility"), page );
+
+ QGridLayout * visibilityLayout = new QGridLayout( m_ClassWidgets.visibilityGB );
+ visibilityLayout -> setSpacing( spacingHint() );
+ visibilityLayout -> setMargin( fontMetrics().height() );
+
+ m_ClassWidgets.showVisibilityCB = new QCheckBox(i18n("Show &visibility"), m_ClassWidgets.visibilityGB);
+ m_ClassWidgets.showVisibilityCB -> setChecked( m_pOptionState->classState.showVisibility );
+ visibilityLayout -> addWidget( m_ClassWidgets.showVisibilityCB, 0, 0 );
+
+ m_ClassWidgets.showAttsCB = new QCheckBox( i18n("Show attributes"), m_ClassWidgets.visibilityGB );
+ m_ClassWidgets.showAttsCB -> setChecked( m_pOptionState->classState.showAtts );
+ visibilityLayout -> addWidget( m_ClassWidgets.showAttsCB, 0, 1 );
+
+ m_ClassWidgets.showOpsCB = new QCheckBox( i18n("Show operations"), m_ClassWidgets.visibilityGB );
+ m_ClassWidgets.showOpsCB -> setChecked( m_pOptionState->classState.showOps );
+ visibilityLayout -> addWidget( m_ClassWidgets.showOpsCB, 1, 0 );
+
+ m_ClassWidgets.showStereotypeCB = new QCheckBox( i18n("Show stereot&ype"), m_ClassWidgets.visibilityGB );
+ m_ClassWidgets.showStereotypeCB -> setChecked( m_pOptionState->classState.showStereoType );
+ visibilityLayout -> addWidget( m_ClassWidgets.showStereotypeCB, 1, 1 );
+
+ m_ClassWidgets.showAttSigCB = new QCheckBox(i18n("Show attribute signature"), m_ClassWidgets.visibilityGB);
+ m_ClassWidgets.showAttSigCB -> setChecked( m_pOptionState->classState.showAttSig );
+ visibilityLayout -> addWidget( m_ClassWidgets.showAttSigCB, 2, 0 );
+
+
+ m_ClassWidgets.showPackageCB = new QCheckBox(i18n("Show package"), m_ClassWidgets.visibilityGB);
+ m_ClassWidgets.showPackageCB -> setChecked( m_pOptionState->classState.showPackage );
+ visibilityLayout -> addWidget( m_ClassWidgets.showPackageCB, 2, 1 );
+
+ m_ClassWidgets.showOpSigCB = new QCheckBox( i18n("Show operation signature"), m_ClassWidgets.visibilityGB );
+ m_ClassWidgets.showOpSigCB -> setChecked( m_pOptionState->classState.showOpSig );
+ visibilityLayout -> addWidget( m_ClassWidgets.showOpSigCB, 3, 0 );
+ visibilityLayout -> setRowStretch( 3, 1 );
+
+ m_ClassWidgets.scopeGB = new QGroupBox( i18n("Starting Scope"), page );
+ QGridLayout * scopeLayout = new QGridLayout( m_ClassWidgets.scopeGB );
+ scopeLayout -> setSpacing( spacingHint() );
+ scopeLayout -> setMargin( fontMetrics().height() );
+
+ m_ClassWidgets.attributeLabel = new QLabel( i18n("Default attribute scope:"), m_ClassWidgets.scopeGB);
+ scopeLayout -> addWidget( m_ClassWidgets.attributeLabel, 0, 0 );
+
+ m_ClassWidgets.operationLabel = new QLabel( i18n("Default operation scope:"), m_ClassWidgets.scopeGB);
+ scopeLayout -> addWidget( m_ClassWidgets.operationLabel, 1, 0 );
+
+ m_ClassWidgets.m_pAttribScopeCB = new KComboBox(m_ClassWidgets.scopeGB);
+ insertAttribScope( tr2i18n( "Public" ) );
+ insertAttribScope( tr2i18n( "Private" ) );
+ insertAttribScope( tr2i18n( "Protected" ) );
+ m_ClassWidgets.m_pAttribScopeCB->setCurrentItem((m_pOptionState->classState.defaultAttributeScope - 200));
+ m_ClassWidgets.m_pAttribScopeCB->setCompletionMode( KGlobalSettings::CompletionPopup );
+ scopeLayout -> addWidget( m_ClassWidgets.m_pAttribScopeCB, 0, 1 );
+
+ m_ClassWidgets.m_pOperationScopeCB = new KComboBox(m_ClassWidgets.scopeGB);
+ insertOperationScope( tr2i18n( "Public" ) );
+ insertOperationScope( tr2i18n( "Private" ) );
+ insertOperationScope( tr2i18n( "Protected" ) );
+ m_ClassWidgets.m_pOperationScopeCB->setCurrentItem((m_pOptionState->classState.defaultOperationScope - 200));
+ m_ClassWidgets.m_pOperationScopeCB->setCompletionMode( KGlobalSettings::CompletionPopup );
+ scopeLayout -> addWidget( m_ClassWidgets.m_pOperationScopeCB, 1, 1 );
+
+}
+/**
+* Inserts @p type into the type-combobox as well as its completion object.
+*/
+void SettingsDlg::insertAttribScope( const QString& type, int index )
+{
+ m_ClassWidgets.m_pAttribScopeCB->insertItem( type, index );
+ m_ClassWidgets.m_pAttribScopeCB->completionObject()->addItem( type );
+}
+/**
+* Inserts @p type into the type-combobox as well as its completion object.
+*/
+void SettingsDlg::insertOperationScope( const QString& type, int index )
+{
+ m_ClassWidgets.m_pOperationScopeCB->insertItem( type, index );
+ m_ClassWidgets.m_pOperationScopeCB->completionObject()->addItem( type );
+}
+
+void SettingsDlg::setupCodeGenPage() {
+ //setup code generation settings page
+ QVBox * page = addVBoxPage( i18n("Code Generation"), i18n("Code Generation Settings"), DesktopIcon( "source") );
+ m_pCodeGenPage = new CodeGenerationOptionsPage(page);
+ connect( m_pCodeGenPage, SIGNAL(languageChanged()), this, SLOT(slotApply()) );
+}
+
+void SettingsDlg::setupCodeViewerPage(Settings::CodeViewerState options) {
+ //setup code generation settings page
+ QVBox * page = addVBoxPage( i18n("Code Viewer"), i18n("Code Viewer Settings"), DesktopIcon( "source") );
+ m_pCodeViewerPage = new CodeViewerOptionsPage(options, page);
+}
+
+void SettingsDlg::setupFontPage() {
+ QVBox * page = addVBoxPage( i18n("Font"), i18n("Font Settings"), DesktopIcon( "fonts") );
+ m_FontWidgets.chooser = new KFontChooser( page, "font", false, QStringList(), false);
+ m_FontWidgets.chooser->setFont( m_pOptionState->uiState.font );
+
+}
+
+void SettingsDlg::slotApply() {
+ applyPage( (Settings::Page) activePageIndex() );
+ //do no emit signal applyClicked in the slot slotApply -> infinite loop
+ //emit applyClicked();
+}
+
+void SettingsDlg::slotOk() {
+ applyPage( Settings::page_general );
+ applyPage( Settings::page_font );
+ applyPage( Settings::page_UI );
+ applyPage( Settings::page_class );
+ applyPage( Settings::page_codegen );
+ applyPage( Settings::page_codeview );
+ accept();
+}
+
+
+void SettingsDlg::slotDefault() {
+ /*
+ Defaults hard coded. Make sure that this is alright.
+ If defaults are set anywhere else, like in setting up config file, make sure the same.
+ */
+ switch( activePageIndex() ) {
+ case Settings::page_general:
+ m_GeneralWidgets.autosaveCB -> setChecked( false );
+ m_GeneralWidgets.timeISB -> setValue( 5 );
+ m_GeneralWidgets.timeISB->setEnabled( true );
+ m_GeneralWidgets.logoCB -> setChecked( true );
+ m_GeneralWidgets.tipCB -> setChecked( true );
+ m_GeneralWidgets.loadlastCB -> setChecked( true );
+ m_GeneralWidgets.diagramKB -> setCurrentItem( 0 );
+ break;
+
+ case Settings::page_font:
+ m_FontWidgets.chooser -> setFont( parentWidget() -> font() );
+ break;
+
+ case Settings::page_UI:
+ m_UiWidgets.useFillColorCB -> setChecked( true );
+ m_UiWidgets.fillColorB -> setColor( QColor( 255, 255, 192 ) );
+ m_UiWidgets.lineColorB -> setColor( Qt::red );
+ m_UiWidgets.lineWidthB -> setValue( 0 );
+ break;
+
+ case Settings::page_class:
+ m_ClassWidgets.showVisibilityCB -> setChecked( false );
+ m_ClassWidgets.showAttsCB -> setChecked( true );
+ m_ClassWidgets.showOpsCB -> setChecked( true );
+ m_ClassWidgets.showStereotypeCB -> setChecked( false );
+ m_ClassWidgets.showAttSigCB -> setChecked( false );
+ m_ClassWidgets.showOpSigCB -> setChecked( false );
+ m_ClassWidgets.showPackageCB -> setChecked( false );
+ m_ClassWidgets.m_pAttribScopeCB->setCurrentItem(1); // Private
+ m_ClassWidgets.m_pOperationScopeCB->setCurrentItem(0); // Public
+ break;
+
+ case Settings::page_codegen:
+ case Settings::page_codeview:
+ // do nothing
+ break;
+ };
+}
+
+void SettingsDlg::applyPage( Settings::Page page ) {
+ m_bChangesApplied = true;
+ switch( page ) {
+ case Settings::page_general:
+ m_pOptionState->generalState.undo = m_GeneralWidgets.undoCB -> isChecked();
+ m_pOptionState->generalState.tabdiagrams = m_GeneralWidgets.tabdiagramsCB->isChecked();
+ m_pOptionState->generalState.newcodegen = m_GeneralWidgets.newcodegenCB->isChecked();
+ m_pOptionState->generalState.angularlines = m_GeneralWidgets.angularLinesCB->isChecked();
+ m_pOptionState->generalState.autosave = m_GeneralWidgets.autosaveCB -> isChecked();
+ m_pOptionState->generalState.autosavetime = m_GeneralWidgets.timeISB -> value();
+ // 2004-05-17 Achim Spangler: retrieve Suffix setting from dialog entry
+ m_pOptionState->generalState.autosavesuffix = m_GeneralWidgets.autosaveSuffixT -> text();
+ m_pOptionState->generalState.logo = m_GeneralWidgets.logoCB -> isChecked();
+ m_pOptionState->generalState.tip = m_GeneralWidgets.tipCB -> isChecked();
+ m_pOptionState->generalState.loadlast = m_GeneralWidgets.loadlastCB -> isChecked();
+ m_pOptionState->generalState.diagram = (Uml::Diagram_Type)(m_GeneralWidgets.diagramKB->currentItem() + 1);
+ break;
+
+ case Settings::page_font:
+ m_pOptionState->uiState.font = m_FontWidgets.chooser -> font();
+ break;
+
+ case Settings::page_UI:
+ m_pOptionState->uiState.useFillColor = m_UiWidgets.useFillColorCB -> isChecked();
+ m_pOptionState->uiState.fillColor = m_UiWidgets.fillColorB -> color();
+ m_pOptionState->uiState.lineColor = m_UiWidgets.lineColorB -> color();
+ m_pOptionState->uiState.lineWidth = m_UiWidgets.lineWidthB -> value();
+ break;
+
+ case Settings::page_class:
+ m_pOptionState->classState.showVisibility = m_ClassWidgets.showVisibilityCB -> isChecked();
+ m_pOptionState->classState.showAtts = m_ClassWidgets.showAttsCB -> isChecked();
+ m_pOptionState->classState.showOps = m_ClassWidgets.showOpsCB -> isChecked();
+ m_pOptionState->classState.showStereoType = m_ClassWidgets.showStereotypeCB -> isChecked();
+ m_pOptionState->classState.showAttSig = m_ClassWidgets.showAttSigCB -> isChecked();
+ m_pOptionState->classState.showOpSig = m_ClassWidgets.showOpSigCB -> isChecked();
+ m_pOptionState->classState.showPackage = m_ClassWidgets.showPackageCB -> isChecked();
+ m_pOptionState->classState.defaultAttributeScope = (Uml::Visibility::Value) (m_ClassWidgets.m_pAttribScopeCB->currentItem() + 200);
+ m_pOptionState->classState.defaultOperationScope = (Uml::Visibility::Value) (m_ClassWidgets.m_pOperationScopeCB->currentItem() + 200);
+ break;
+
+ case Settings::page_codegen:
+ m_pCodeGenPage->apply();
+ break;
+
+ case Settings::page_codeview:
+ m_pCodeViewerPage->apply();
+ m_pOptionState->codeViewerState = m_pCodeViewerPage->getOptions();
+ break;
+ }
+}
+
+void SettingsDlg::slotLineBClicked() {
+ m_UiWidgets.lineColorB -> setColor( Qt::red );
+}
+
+void SettingsDlg::slotFillBClicked() {
+ m_UiWidgets.fillColorB -> setColor( QColor(255, 255, 192) );
+}
+
+void SettingsDlg::slotAutosaveCBClicked() {
+ m_GeneralWidgets.timeISB -> setEnabled( m_GeneralWidgets.autosaveCB -> isChecked() );
+}
+
+QString SettingsDlg::getCodeGenerationLanguage() {
+ return m_pCodeGenPage->getCodeGenerationLanguage();
+}
+
+#include "settingsdlg.moc"
diff --git a/umbrello/umbrello/dialogs/settingsdlg.h b/umbrello/umbrello/dialogs/settingsdlg.h
new file mode 100644
index 00000000..30579990
--- /dev/null
+++ b/umbrello/umbrello/dialogs/settingsdlg.h
@@ -0,0 +1,177 @@
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * copyright (C) 2002-2006 *
+ * Umbrello UML Modeller Authors <uml-devel@uml.sf.net> *
+ ***************************************************************************/
+
+
+#ifndef SETTINGSDLG_H
+#define SETTINGSDLG_H
+//qt includes
+#include <qgroupbox.h>
+#include <qcheckbox.h>
+#include <qpushbutton.h>
+#include <qlabel.h>
+#include <qradiobutton.h>
+#include <qbuttongroup.h>
+#include <qdict.h>
+//kde includes
+#include <kcombobox.h>
+#include <kfontdialog.h>
+#include <kdialogbase.h>
+#include <kcolorbutton.h>
+#include <knuminput.h>
+//app includes
+
+#include "../optionstate.h"
+
+class CodeGenerationOptionsPage;
+class CodeViewerOptionsPage;
+class CodeGenerator;
+
+/**
+ * @author Paul Hensgen
+ * modified by brian thomas Aug-2003
+ * Bugs and comments to uml-devel@lists.sf.net or http://bugs.kde.org
+ */
+
+class SettingsDlg : public KDialogBase {
+
+ Q_OBJECT
+
+public:
+ SettingsDlg(QWidget * parent, Settings::OptionState *state);
+ ~SettingsDlg();
+
+ //public methods
+ bool getChangesApplied() {
+ return m_bChangesApplied;
+ }
+
+ QString getCodeGenerationLanguage();
+
+protected:
+ /**
+ * Inserts @p type into the type-combobox as well as its completion object.
+ */
+ void insertDiagram( const QString& type, int index = -1 );
+ /**
+ * Inserts @p type into the type-combobox as well as its completion object.
+ */
+ void insertAttribScope( const QString& type, int index = -1 );
+ /**
+ * Inserts @p type into the type-combobox as well as its completion object.
+ */
+ void insertOperationScope( const QString& type, int index = -1 );
+
+private:
+ //private structs
+ struct UIWidgets {
+ QGroupBox * colorGB;
+
+ QLabel * lineColorL;
+ QLabel * fillColorL;
+ QLabel * lineWidthL;
+
+ QPushButton * lineDefaultB;
+ QPushButton * fillDefaultB;
+ QPushButton * lineWidthDefaultB;
+
+ KColorButton * lineColorB;
+ KColorButton * fillColorB;
+ KIntSpinBox * lineWidthB;
+
+ QCheckBox * useFillColorCB;
+ }
+ ;//end struct UIWidgets
+
+ struct GeneralWidgets {
+ QGroupBox * miscGB;
+ QGroupBox * autosaveGB;
+ QGroupBox * startupGB;
+
+ KIntSpinBox * timeISB;
+ KComboBox * diagramKB;
+
+ QCheckBox * undoCB;
+ QCheckBox * tabdiagramsCB;
+ QCheckBox * newcodegenCB;
+ QCheckBox * angularLinesCB;
+ QCheckBox * autosaveCB;
+ QCheckBox * logoCB;
+ QCheckBox * tipCB;
+ QCheckBox * loadlastCB;
+
+ // 2004-05-17 Achim Spangler: Allow definition of Suffix for autosave
+ // ( Default: ".xmi" )
+ QLineEdit * autosaveSuffixT;
+ QLabel * autosaveSuffixL;
+ // End AutoSave Suffix
+
+ QLabel * startL;
+ QLabel * autosaveL;
+ }
+ ;//end struct GeneralWidgets
+
+ struct ClassWidgets {
+ QGroupBox * visibilityGB;
+ QGroupBox * scopeGB;
+
+ QCheckBox * showVisibilityCB;
+ QCheckBox * showAttsCB;
+ QCheckBox * showOpsCB;
+ QCheckBox * showStereotypeCB;
+ QCheckBox * showAttSigCB;
+ QCheckBox * showPackageCB;
+
+ QCheckBox * showOpSigCB;
+
+ QLabel * attributeLabel;
+ QLabel * operationLabel;
+
+ KComboBox* m_pAttribScopeCB;
+ KComboBox* m_pOperationScopeCB;
+
+ }
+ ;//end struct ClassWidgets
+
+ struct FontWidgets {
+ KFontChooser * chooser;
+ };
+
+ //private methods
+ void setupFontPage();
+ void setupUIPage();
+ void setupGeneralPage();
+ void setupClassPage();
+ void setupCodeGenPage();
+ void setupCodeViewerPage(Settings::CodeViewerState options);
+ void applyPage( Settings::Page page );
+
+ //private attributes
+ FontWidgets m_FontWidgets;
+ GeneralWidgets m_GeneralWidgets;
+ UIWidgets m_UiWidgets;
+ ClassWidgets m_ClassWidgets;
+ Settings::OptionState *m_pOptionState;
+ CodeGenerationOptionsPage * m_pCodeGenPage;
+ CodeViewerOptionsPage * m_pCodeViewerPage;
+
+ KConfig * m_pCfg;
+ bool m_bChangesApplied;
+
+private slots:
+ void slotApply();
+ void slotOk();
+ void slotDefault();
+ void slotLineBClicked();
+ void slotFillBClicked();
+ void slotAutosaveCBClicked();
+};
+
+#endif
diff --git a/umbrello/umbrello/dialogs/statedialog.cpp b/umbrello/umbrello/dialogs/statedialog.cpp
new file mode 100644
index 00000000..691597e9
--- /dev/null
+++ b/umbrello/umbrello/dialogs/statedialog.cpp
@@ -0,0 +1,147 @@
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * copyright (C) 2002-2006 *
+ * Umbrello UML Modeller Authors <uml-devel@uml.sf.net> *
+ ***************************************************************************/
+
+// own header
+#include "statedialog.h"
+
+//qt includes
+#include <qlayout.h>
+#include <qlabel.h>
+#include <qlineedit.h>
+#include <qmultilineedit.h>
+#include <qgroupbox.h>
+
+//kde includes
+#include <kiconloader.h>
+#include <klocale.h>
+#include <kfontdialog.h>
+
+//local includes
+#include "../umlview.h"
+#include "../statewidget.h"
+#include "../dialog_utils.h"
+
+StateDialog::StateDialog( UMLView * pView, StateWidget * pWidget )
+ : KDialogBase(IconList, i18n("Properties"), Ok | Apply | Cancel | Help, Ok, pView, "_STATEDIALOG_", true, true) {
+ m_pActivityPage = 0;
+ m_pView = pView;
+ m_pStateWidget = pWidget;
+ m_bChangesMade = false;
+ setupPages();
+}
+
+void StateDialog::slotOk() {
+ applyPage( GeneralPage );
+ applyPage( Activity_Page );
+ applyPage( ColorPage );
+ applyPage( FontPage );
+ accept();
+}
+
+void StateDialog::slotApply() {
+ applyPage( (Page) activePageIndex() );
+}
+
+void StateDialog::setupPages() {
+ setupGeneralPage();
+ if( m_pStateWidget -> getStateType() == StateWidget::Normal )
+ setupActivityPage();
+ setupColorPage();
+ setupFontPage();
+}
+
+void StateDialog::applyPage( Page page ) {
+ m_bChangesMade = true;
+ switch( page ) {
+ case GeneralPage:
+ m_pStateWidget -> setName( m_GenPageWidgets.nameLE -> text() );
+ m_pStateWidget -> setDoc( m_GenPageWidgets.docMLE -> text() );
+ break;
+
+ case Activity_Page:
+ if( m_pActivityPage )
+ m_pActivityPage -> updateActivities();
+ break;
+
+ case ColorPage:
+ m_pColorPage -> updateUMLWidget();
+ break;
+
+ case FontPage:
+ m_pStateWidget -> setFont( m_pChooser -> font() );
+ break;
+ }//end switch
+}
+
+void StateDialog::setupGeneralPage() {
+ QString types[ ] = { i18n("Initial state"), i18n("State"), i18n("End state") };
+ StateWidget::StateType type = m_pStateWidget -> getStateType();
+
+ QVBox * page = addVBoxPage( i18n("General"), i18n("General Properties"), DesktopIcon( "misc") );
+ m_GenPageWidgets.generalGB = new QGroupBox( i18n( "Properties"), (QWidget *)page );
+
+ QGridLayout * generalLayout = new QGridLayout( m_GenPageWidgets.generalGB, 2, 2 );
+ generalLayout -> setSpacing( spacingHint() );
+ generalLayout -> setMargin( fontMetrics().height() );
+
+ Dialog_Utils::makeLabeledEditField( m_GenPageWidgets.generalGB, generalLayout, 0,
+ m_GenPageWidgets.typeL, i18n("State type:"),
+ m_GenPageWidgets.typeLE, types[ (int)type ] );
+ m_GenPageWidgets.typeLE -> setEnabled( false );
+
+ Dialog_Utils::makeLabeledEditField( m_GenPageWidgets.generalGB, generalLayout, 1,
+ m_GenPageWidgets.nameL, i18n("State name:"),
+ m_GenPageWidgets.nameLE );
+
+ m_GenPageWidgets.docGB = new QGroupBox( i18n( "Documentation"), (QWidget *)page );
+
+ QHBoxLayout * docLayout = new QHBoxLayout( m_GenPageWidgets.docGB );
+ docLayout -> setSpacing( spacingHint() );
+ docLayout -> setMargin( fontMetrics().height() );
+
+ m_GenPageWidgets.docMLE = new QMultiLineEdit( m_GenPageWidgets.docGB );
+ m_GenPageWidgets.docMLE -> setText( m_pStateWidget -> getDoc() );
+ docLayout -> addWidget( m_GenPageWidgets.docMLE );
+
+ if( type != StateWidget::Normal ) {
+ m_GenPageWidgets.nameLE -> setEnabled( false );
+ m_GenPageWidgets.nameLE -> setText( "" );
+ } else
+ m_GenPageWidgets.nameLE -> setText( m_pStateWidget -> getName() );
+}
+
+void StateDialog::setupFontPage() {
+ if ( !m_pStateWidget )
+ return;
+ QVBox * page = addVBoxPage( i18n("Font"), i18n("Font Settings"), DesktopIcon( "fonts") );
+ m_pChooser = new KFontChooser( (QWidget*)page, "font", false, QStringList(), false);
+ m_pChooser -> setFont( m_pStateWidget -> getFont() );
+}
+
+void StateDialog::setupColorPage() {
+ QFrame * colorPage = addPage( i18n("Color"), i18n("Widget Color"), DesktopIcon( "colors") );
+ QHBoxLayout * m_pColorLayout = new QHBoxLayout(colorPage);
+ m_pColorPage = new UMLWidgetColorPage( colorPage, m_pStateWidget );
+ m_pColorLayout -> addWidget(m_pColorPage);
+}
+
+void StateDialog::setupActivityPage() {
+ QFrame * activityPage = addPage( i18n("Activities"), i18n("Activities"), DesktopIcon( "misc") );
+ QHBoxLayout * activityLayout = new QHBoxLayout( activityPage );
+ m_pActivityPage = new ActivityPage( activityPage, m_pStateWidget );
+ activityLayout -> addWidget( m_pActivityPage );
+}
+
+
+
+
+
+#include "statedialog.moc"
diff --git a/umbrello/umbrello/dialogs/statedialog.h b/umbrello/umbrello/dialogs/statedialog.h
new file mode 100644
index 00000000..d364d6be
--- /dev/null
+++ b/umbrello/umbrello/dialogs/statedialog.h
@@ -0,0 +1,144 @@
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * copyright (C) 2002-2006 *
+ * Umbrello UML Modeller Authors <uml-devel@uml.sf.net> *
+ ***************************************************************************/
+
+#ifndef STATEDIALOG_H
+#define STATEDIALOG_H
+
+//kde class includes
+#include <kdialogbase.h>
+
+//local class includes
+#include "umlwidgetcolorpage.h"
+#include "activitypage.h"
+
+//forward declarations
+class UMLView;
+class StateWidget;
+class QLabel;
+class QLineEdit;
+class QMultiLineEdit;
+class QGroupBox;
+class KFontChooser;
+
+/**
+ * Displays the properties for a @ref StateWidget
+ *
+ * @author Paul Hensgen
+ * Bugs and comments to uml-devel@lists.sf.net or http://bugs.kde.org
+ */
+
+class StateDialog : public KDialogBase {
+ Q_OBJECT
+
+public:
+ /**
+ * Constructor
+ */
+ StateDialog( UMLView * pView, StateWidget * pWidget );
+
+ /**
+ * Returns whether changes were made.
+ */
+ bool getChangesMade() {
+ return m_bChangesMade;
+ }
+
+protected slots:
+
+ enum Page
+ {
+ GeneralPage = 0,
+ Activity_Page,
+ ColorPage,
+ FontPage
+ };
+
+ /**
+ * Entered when OK button pressed.
+ */
+ void slotOk();
+
+ /**
+ * Entered when Apply button pressed.
+ */
+ void slotApply();
+protected:
+ /**
+ * Sets up the pages of the dialog.
+ */
+ void setupPages();
+
+ /**
+ * Sets up the general page of the dialog.
+ */
+ void setupGeneralPage();
+
+ /**
+ * Sets up the color page.
+ */
+ void setupColorPage();
+
+ /**
+ * Sets up the font selection page.
+ */
+ void setupFontPage();
+
+ /**
+ * Sets up the activity page.
+ */
+ void setupActivityPage();
+
+ /**
+ * Applys changes to the given page.
+ */
+ void applyPage( Page page );
+
+ /**
+ * Font chooser widget for font page.
+ */
+ KFontChooser * m_pChooser;
+
+ /**
+ * Color page
+ */
+ UMLWidgetColorPage * m_pColorPage;
+
+ /**
+ * Activity page.
+ */
+ ActivityPage * m_pActivityPage;
+
+ /**
+ * The widget to represent.
+ */
+ StateWidget * m_pStateWidget;
+
+ /**
+ * The diagram the widget is on.
+ */
+ UMLView * m_pView;
+
+ /**
+ * Holds whether changes in the dialog have been made.
+ */
+ bool m_bChangesMade;
+
+ struct GeneralPageWidgets {
+ QLabel * nameL, * typeL;
+ QLineEdit * nameLE, * typeLE;
+ QMultiLineEdit * docMLE;
+
+ QGroupBox * docGB, * generalGB;
+ }
+ m_GenPageWidgets;
+};
+
+#endif
diff --git a/umbrello/umbrello/dialogs/umlattributedialog.cpp b/umbrello/umbrello/dialogs/umlattributedialog.cpp
new file mode 100644
index 00000000..e6a52725
--- /dev/null
+++ b/umbrello/umbrello/dialogs/umlattributedialog.cpp
@@ -0,0 +1,235 @@
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * copyright (C) 2002-2006 *
+ * Umbrello UML Modeller Authors <uml-devel@uml.sf.net> *
+ ***************************************************************************/
+
+// own header
+#include "umlattributedialog.h"
+
+// qt includes
+#include <qlayout.h>
+#include <qlineedit.h>
+#include <qcheckbox.h>
+#include <qgroupbox.h>
+#include <qbuttongroup.h>
+#include <qradiobutton.h>
+#include <qlabel.h>
+
+// kde includes
+#include <kcombobox.h>
+#include <kcompletion.h>
+#include <klocale.h>
+#include <kmessagebox.h>
+#include <kdebug.h>
+
+// app includes
+#include "../attribute.h"
+#include "../classifier.h"
+#include "../template.h"
+#include "../umldoc.h"
+#include "../uml.h"
+#include "../dialog_utils.h"
+#include "../object_factory.h"
+#include "../codeimport/import_utils.h"
+
+UMLAttributeDialog::UMLAttributeDialog( QWidget * pParent, UMLAttribute * pAttribute )
+ : KDialogBase( Plain, i18n("Attribute Properties"), Help | Ok | Cancel , Ok, pParent, "_UMLATTRIBUTEDLG_", true, true) {
+ m_pAttribute = pAttribute;
+ setupDialog();
+}
+
+UMLAttributeDialog::~UMLAttributeDialog() {}
+
+void UMLAttributeDialog::setupDialog() {
+ UMLDoc * pDoc = UMLApp::app()->getDocument();
+ int margin = fontMetrics().height();
+
+ QVBoxLayout * mainLayout = new QVBoxLayout( plainPage() );
+
+ m_pValuesGB = new QGroupBox(i18n("General Properties"), plainPage() );
+ QGridLayout * valuesLayout = new QGridLayout(m_pValuesGB, 5, 2);
+ valuesLayout -> setMargin(margin);
+ valuesLayout -> setSpacing(10);
+
+ m_pTypeL = new QLabel(i18n("&Type:"), m_pValuesGB);
+ valuesLayout -> addWidget(m_pTypeL, 0, 0);
+
+ m_pTypeCB = new KComboBox(true, m_pValuesGB);
+ valuesLayout -> addWidget(m_pTypeCB, 0, 1);
+ m_pTypeL->setBuddy(m_pTypeCB);
+
+ Dialog_Utils::makeLabeledEditField( m_pValuesGB, valuesLayout, 1,
+ m_pNameL, i18n("&Name:"),
+ m_pNameLE, m_pAttribute->getName() );
+
+ Dialog_Utils::makeLabeledEditField( m_pValuesGB, valuesLayout, 2,
+ m_pInitialL, i18n("&Initial value:"),
+ m_pInitialLE, m_pAttribute->getInitialValue() );
+
+ Dialog_Utils::makeLabeledEditField( m_pValuesGB, valuesLayout, 3,
+ m_pStereoTypeL, i18n("Stereotype name:"),
+ m_pStereoTypeLE, m_pAttribute->getStereotype() );
+
+ m_pStaticCB = new QCheckBox( i18n("Classifier &scope (\"static\")"), m_pValuesGB );
+ m_pStaticCB -> setChecked( m_pAttribute -> getStatic() );
+ valuesLayout -> addWidget(m_pStaticCB, 4, 0);
+
+
+ mainLayout -> addWidget(m_pValuesGB);
+
+
+ m_pScopeBG = new QButtonGroup(i18n("Visibility"), plainPage() );
+ QHBoxLayout * scopeLayout = new QHBoxLayout(m_pScopeBG);
+ scopeLayout -> setMargin(margin);
+
+ m_pPublicRB = new QRadioButton(i18n("&Public"), m_pScopeBG);
+ scopeLayout -> addWidget(m_pPublicRB);
+
+ m_pPrivateRB = new QRadioButton(i18n("P&rivate"), m_pScopeBG);
+ scopeLayout -> addWidget(m_pPrivateRB);
+
+ m_pProtectedRB = new QRadioButton(i18n("Prot&ected"), m_pScopeBG);
+ scopeLayout -> addWidget(m_pProtectedRB);
+
+ m_pImplementationRB = new QRadioButton(i18n("I&mplementation"), m_pScopeBG);
+ scopeLayout -> addWidget(m_pImplementationRB);
+
+ mainLayout -> addWidget(m_pScopeBG);
+ Uml::Visibility scope = m_pAttribute -> getVisibility();
+ if( scope == Uml::Visibility::Public )
+ m_pPublicRB -> setChecked( true );
+ else if( scope == Uml::Visibility::Private )
+ m_pPrivateRB -> setChecked( true );
+ else if( scope == Uml::Visibility::Protected )
+ m_pProtectedRB -> setChecked( true );
+ else if( scope == Uml::Visibility::Implementation )
+ m_pImplementationRB -> setChecked( true );
+
+ m_pTypeCB->setDuplicatesEnabled(false);//only allow one of each type in box
+ m_pTypeCB->setCompletionMode( KGlobalSettings::CompletionPopup );
+
+ //now add the Concepts
+ UMLClassifierList namesList( pDoc->getConcepts() );
+ UMLClassifier* obj;
+ for (obj=namesList.first(); obj!=0; obj=namesList.next()) {
+ insertType( obj->getFullyQualifiedName() );
+ }
+
+ //work out which one to select
+ int typeBoxCount = 0;
+ bool foundType = false;
+ while (typeBoxCount < m_pTypeCB->count() && foundType == false) {
+ QString typeBoxString = m_pTypeCB->text(typeBoxCount);
+ if ( typeBoxString == m_pAttribute->getTypeName() ) {
+ foundType = true;
+ m_pTypeCB->setCurrentItem(typeBoxCount);
+ } else {
+ typeBoxCount++;
+ }
+ }
+
+ if (!foundType) {
+ insertType( m_pAttribute->getTypeName(), 0 );
+ m_pTypeCB->setCurrentItem(0);
+ }
+
+ m_pNameLE->setFocus();
+ connect( m_pNameLE, SIGNAL( textChanged ( const QString & ) ), SLOT( slotNameChanged( const QString & ) ) );
+ slotNameChanged(m_pNameLE->text() );
+}
+
+void UMLAttributeDialog::slotNameChanged( const QString &_text )
+{
+ enableButtonOK( !_text.isEmpty() );
+}
+
+bool UMLAttributeDialog::apply() {
+ QString name = m_pNameLE->text();
+ if (name.isEmpty()) {
+ KMessageBox::error(this, i18n("You have entered an invalid attribute name."),
+ i18n("Attribute Name Invalid"), false);
+ m_pNameLE->setText( m_pAttribute->getName() );
+ return false;
+ }
+ UMLClassifier * pConcept = dynamic_cast<UMLClassifier *>( m_pAttribute->parent() );
+ UMLObject *o = pConcept->findChildObject(name);
+ if (o && o != m_pAttribute) {
+ KMessageBox::error(this, i18n("The attribute name you have chosen is already being used in this operation."),
+ i18n("Attribute Name Not Unique"), false);
+ m_pNameLE->setText( m_pAttribute->getName() );
+ return false;
+ }
+ m_pAttribute->setName(name);
+ Uml::Visibility scope = Uml::Visibility::Protected;
+ if ( m_pPublicRB->isChecked() ) {
+ scope = Uml::Visibility::Public;
+ } else if ( m_pPrivateRB->isChecked() ) {
+ scope = Uml::Visibility::Private;
+ } else if ( m_pImplementationRB->isChecked() ) {
+ scope = Uml::Visibility::Implementation;
+ }
+ m_pAttribute->setVisibility(scope);
+ // Set the scope as the default in the option state
+ Settings::OptionState optionState = Settings::getOptionState();
+ optionState.classState.defaultAttributeScope = scope;
+ Settings::setOptionState(optionState);
+
+ m_pAttribute->setInitialValue( m_pInitialLE->text() );
+ m_pAttribute->setStereotype( m_pStereoTypeLE->text() );
+ m_pAttribute->setStatic( m_pStaticCB->isChecked() );
+
+ QString typeName = m_pTypeCB->currentText();
+ UMLTemplate *tmplParam = pConcept->findTemplate(typeName);
+ if (tmplParam) {
+ m_pAttribute->setType(tmplParam);
+ return true;
+ }
+ UMLDoc * pDoc = UMLApp::app()->getDocument();
+ UMLObject *obj = pDoc->findUMLObject(typeName);
+ UMLClassifier *classifier = dynamic_cast<UMLClassifier*>(obj);
+ if (classifier == NULL) {
+ Uml::Programming_Language pl = UMLApp::app()->getActiveLanguage();
+ if (pl == Uml::pl_Cpp || pl == Uml::pl_Java) {
+ // Import_Utils::createUMLObject works better for C++ namespace and java package than Object_Factory::createUMLObject
+
+ Import_Utils::setRelatedClassifier(pConcept);
+ obj = Import_Utils::createUMLObject(Uml::ot_UMLObject, typeName);
+ Import_Utils::setRelatedClassifier(NULL);
+ } else {
+ // If it's obviously a pointer type (C++) then create a datatype.
+ // Else we don't know what it is so as a compromise create a class.
+ Uml::Object_Type ot = (typeName.contains('*') ? Uml::ot_Datatype : Uml::ot_Class);
+ obj = Object_Factory::createUMLObject(ot, typeName);
+ }
+ if (obj == NULL)
+ return false;
+ classifier = static_cast<UMLClassifier*>(obj);
+ }
+ m_pAttribute->setType( classifier );
+ return true;
+}
+
+void UMLAttributeDialog::slotApply() {
+ apply();
+}
+
+void UMLAttributeDialog::slotOk() {
+ if ( apply() ) {
+ accept();
+ }
+}
+
+void UMLAttributeDialog::insertType( const QString& type, int index )
+{
+ m_pTypeCB->insertItem( type, index );
+ m_pTypeCB->completionObject()->addItem( type );
+}
+
+
+#include "umlattributedialog.moc"
diff --git a/umbrello/umbrello/dialogs/umlattributedialog.h b/umbrello/umbrello/dialogs/umlattributedialog.h
new file mode 100644
index 00000000..92305d61
--- /dev/null
+++ b/umbrello/umbrello/dialogs/umlattributedialog.h
@@ -0,0 +1,81 @@
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * copyright (C) 2002-2006 *
+ * Umbrello UML Modeller Authors <uml-devel@uml.sf.net> *
+ ***************************************************************************/
+
+#ifndef UMLATTRIBUTEDIALOG_H
+#define UMLATTRIBUTEDIALOG_H
+
+#include <kdialogbase.h>
+
+/**
+ * @author Paul Hensgen
+ * Bugs and comments to uml-devel@lists.sf.net or http://bugs.kde.org
+ */
+
+class QButtonGroup;
+class QCheckBox;
+class QGroupBox;
+class QRadioButton;
+class UMLAttribute;
+class KComboBox;
+class QLineEdit;
+
+class UMLAttributeDialog : public KDialogBase {
+ Q_OBJECT
+public:
+ UMLAttributeDialog( QWidget * pParent, UMLAttribute * pAttribute );
+ ~UMLAttributeDialog();
+
+protected:
+ /**
+ * Sets up the dialog
+ */
+ void setupDialog();
+
+ /**
+ * Checks if changes are valid and applies them if they are,
+ * else returns false
+ */
+ bool apply();
+
+ /**
+ * Inserts @p type into the type-combobox as well as its completion object.
+ */
+ void insertType( const QString& type, int index = -1 );
+
+ /**
+ * The Attribute to represent
+ */
+ UMLAttribute * m_pAttribute;
+
+ //GUI Widgets
+ QGroupBox * m_pAttsGB, * m_pValuesGB;
+ QButtonGroup * m_pScopeBG;
+ QRadioButton * m_pPublicRB, * m_pPrivateRB, * m_pProtectedRB, * m_pImplementationRB;
+ QLabel * m_pTypeL, * m_pNameL, * m_pInitialL, * m_pStereoTypeL;
+ KComboBox * m_pTypeCB;
+ QLineEdit * m_pNameLE, * m_pInitialLE, * m_pStereoTypeLE;
+ QCheckBox* m_pStaticCB;
+
+public slots:
+ /**
+ * I don't think this is used, but if we had an apply button
+ * it would slot into here
+ */
+ void slotApply();
+
+ /**
+ * Used when the OK button is clicked. Calls apply()
+ */
+ void slotOk();
+ void slotNameChanged( const QString & );
+};
+
+#endif
diff --git a/umbrello/umbrello/dialogs/umlentityattributedialog.cpp b/umbrello/umbrello/dialogs/umlentityattributedialog.cpp
new file mode 100644
index 00000000..ef6a5791
--- /dev/null
+++ b/umbrello/umbrello/dialogs/umlentityattributedialog.cpp
@@ -0,0 +1,262 @@
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * copyright (C) 2002-2007 *
+ * Umbrello UML Modeller Authors <uml-devel@uml.sf.net> *
+ ***************************************************************************/
+
+// own header
+#include "umlentityattributedialog.h"
+
+// qt includes
+#include <qlayout.h>
+#include <qlineedit.h>
+#include <qcheckbox.h>
+#include <qgroupbox.h>
+#include <qbuttongroup.h>
+#include <qradiobutton.h>
+#include <qlabel.h>
+
+// kde includes
+#include <kcombobox.h>
+#include <kcompletion.h>
+#include <klocale.h>
+#include <kmessagebox.h>
+#include <kapplication.h>
+#include <kdebug.h>
+
+// app includes
+#include "../entityattribute.h"
+#include "../classifier.h"
+#include "../umldoc.h"
+#include "../uml.h"
+#include "../codegenerator.h"
+#include "../dialog_utils.h"
+#include "../object_factory.h"
+#include "../umlclassifierlist.h"
+
+UMLEntityAttributeDialog::UMLEntityAttributeDialog( QWidget * pParent, UMLEntityAttribute * pEntityAttribute )
+ : KDialogBase( Plain, i18n("Entity Attribute Properties"), Help | Ok | Cancel , Ok, pParent, "_UMLENTITYATTRIBUTEDLG_", true, true) {
+ m_pEntityAttribute = pEntityAttribute;
+ setupDialog();
+}
+
+UMLEntityAttributeDialog::~UMLEntityAttributeDialog() {}
+
+void UMLEntityAttributeDialog::setupDialog() {
+ UMLDoc * pDoc = UMLApp::app()->getDocument();
+ int margin = fontMetrics().height();
+
+ QVBoxLayout * mainLayout = new QVBoxLayout( plainPage() );
+
+ m_pValuesGB = new QGroupBox(i18n("General Properties"), plainPage() );
+ QGridLayout * valuesLayout = new QGridLayout(m_pValuesGB, 5, 2);
+ valuesLayout -> setMargin(margin);
+ valuesLayout -> setSpacing(10);
+
+ m_pTypeL = new QLabel(i18n("&Type:"), m_pValuesGB);
+ valuesLayout -> addWidget(m_pTypeL, 0, 0);
+
+ m_pTypeCB = new KComboBox(true, m_pValuesGB);
+ valuesLayout -> addWidget(m_pTypeCB, 0, 1);
+ m_pTypeL->setBuddy(m_pTypeCB);
+
+ Dialog_Utils::makeLabeledEditField( m_pValuesGB, valuesLayout, 1,
+ m_pNameL, i18n("&Name:"),
+ m_pNameLE, m_pEntityAttribute->getName() );
+
+ Dialog_Utils::makeLabeledEditField( m_pValuesGB, valuesLayout, 2,
+ m_pInitialL, i18n("&Default value:"),
+ m_pInitialLE, m_pEntityAttribute->getInitialValue() );
+
+ Dialog_Utils::makeLabeledEditField( m_pValuesGB, valuesLayout, 3,
+ m_pStereoTypeL, i18n("Stereotype name:"),
+ m_pStereoTypeLE, m_pEntityAttribute->getStereotype() );
+
+ Dialog_Utils::makeLabeledEditField( m_pValuesGB, valuesLayout, 4,
+ m_pValuesL, i18n("Length/Values:"),
+ m_pValuesLE, m_pEntityAttribute->getValues() );
+
+ m_pAutoIncrementCB = new QCheckBox( i18n("&Auto increment"), m_pValuesGB );
+ m_pAutoIncrementCB->setChecked( m_pEntityAttribute->getAutoIncrement() );
+ valuesLayout->addWidget(m_pAutoIncrementCB, 5, 0);
+
+ m_pNullCB = new QCheckBox( i18n("Allow &null"), m_pValuesGB );
+ m_pNullCB->setChecked( m_pEntityAttribute->getNull() );
+ valuesLayout->addWidget(m_pNullCB, 6, 0);
+
+ m_pAttributesL = new QLabel(i18n("Attributes:"), m_pValuesGB);
+ valuesLayout->addWidget(m_pAttributesL, 7, 0);
+
+ m_pAttributesCB = new KComboBox(true, m_pValuesGB);
+ m_pAttributesCB->setCompletionMode( KGlobalSettings::CompletionPopup );
+ valuesLayout->addWidget(m_pAttributesCB, 7, 1);
+ m_pTypeL->setBuddy(m_pAttributesCB);
+
+ insertAttribute( m_pEntityAttribute->getAttributes() );
+ insertAttribute("");
+ insertAttribute("binary");
+ insertAttribute("unsigned");
+ insertAttribute("unsigned zerofill");
+
+ mainLayout -> addWidget(m_pValuesGB);
+
+ m_pScopeBG = new QButtonGroup(i18n("Indexing"), plainPage() );
+ QHBoxLayout* scopeLayout = new QHBoxLayout(m_pScopeBG);
+ scopeLayout->setMargin(margin);
+
+ m_pNoneRB = new QRadioButton(i18n("&None"), m_pScopeBG);
+ scopeLayout->addWidget(m_pNoneRB);
+
+ m_pPublicRB = new QRadioButton(i18n("&Primary"), m_pScopeBG);
+ scopeLayout->addWidget(m_pPublicRB);
+
+ m_pPrivateRB = new QRadioButton(i18n("&Index"), m_pScopeBG);
+ scopeLayout->addWidget(m_pPrivateRB);
+
+ m_pProtectedRB = new QRadioButton(i18n("&Unique"), m_pScopeBG);
+ scopeLayout->addWidget(m_pProtectedRB);
+
+ mainLayout->addWidget(m_pScopeBG);
+ Uml::DBIndex_Type scope = m_pEntityAttribute->getIndexType();
+ if ( scope == Uml::Primary )
+ m_pPublicRB->setChecked( true );
+ else if( scope == Uml::Index )
+ m_pPrivateRB -> setChecked( true );
+ else if( scope == Uml::Unique )
+ m_pProtectedRB -> setChecked( true );
+ else {
+ m_pNoneRB->setChecked(true);
+ }
+
+ m_pTypeCB->setDuplicatesEnabled(false);//only allow one of each type in box
+ m_pTypeCB->setCompletionMode( KGlobalSettings::CompletionPopup );
+
+ // Add the data types.
+ UMLClassifierList dataTypes = pDoc->getDatatypes();
+ if (dataTypes.count() == 0) {
+ // Switch to SQL as the active language if no datatypes are set.
+ UMLApp::app()->setActiveLanguage("SQL");
+ pDoc->addDefaultDatatypes();
+ kapp->processEvents();
+ dataTypes = pDoc->getDatatypes();
+ }
+ UMLClassifier *dat;
+ for (UMLClassifierListIt dit(dataTypes); (dat = dit.current()) != NULL; ++dit) {
+ insertType(dat->getName());
+ }
+
+ //work out which one to select
+ int typeBoxCount = 0;
+ bool foundType = false;
+ while (typeBoxCount < m_pTypeCB->count() && foundType == false) {
+ QString typeBoxString = m_pTypeCB->text(typeBoxCount);
+ if ( typeBoxString == m_pEntityAttribute->getTypeName() ) {
+ foundType = true;
+ m_pTypeCB->setCurrentItem(typeBoxCount);
+ } else {
+ typeBoxCount++;
+ }
+ }
+
+ if (!foundType) {
+ insertType( m_pEntityAttribute->getTypeName(), 0 );
+ m_pTypeCB->setCurrentItem(0);
+ }
+
+ m_pNameLE->setFocus();
+ connect( m_pNameLE, SIGNAL( textChanged ( const QString & ) ), SLOT( slotNameChanged( const QString & ) ) );
+ slotNameChanged(m_pNameLE->text() );
+}
+
+void UMLEntityAttributeDialog::slotNameChanged( const QString &_text )
+{
+ enableButtonOK( !_text.isEmpty() );
+}
+
+bool UMLEntityAttributeDialog::apply() {
+ QString name = m_pNameLE->text();
+ if (name.isEmpty()) {
+ KMessageBox::error(this, i18n("You have entered an invalid entity attribute name."),
+ i18n("Entity Attribute Name Invalid"), false);
+ m_pNameLE->setText( m_pEntityAttribute->getName() );
+ return false;
+ }
+ UMLClassifier * pConcept = dynamic_cast<UMLClassifier *>( m_pEntityAttribute->parent() );
+ UMLObject *o = pConcept->findChildObject(name);
+ if (o && o != m_pEntityAttribute) {
+ KMessageBox::error(this, i18n("The entity attribute name you have chosen is already being used in this operation."),
+ i18n("Entity Attribute Name Not Unique"), false);
+ m_pNameLE->setText( m_pEntityAttribute->getName() );
+ return false;
+ }
+ m_pEntityAttribute->setName(name);
+ m_pEntityAttribute->setInitialValue( m_pInitialLE->text() );
+ m_pEntityAttribute->setStereotype( m_pStereoTypeLE->text() );
+ m_pEntityAttribute->setValues( m_pValuesLE->text() );
+ m_pEntityAttribute->setAttributes( m_pAttributesCB->currentText() );
+ m_pEntityAttribute->setAutoIncrement( m_pAutoIncrementCB->isChecked() );
+ m_pEntityAttribute->setNull( m_pNullCB->isChecked() );
+
+ if ( m_pPublicRB->isChecked() ) {
+ m_pEntityAttribute->setIndexType(Uml::Primary);
+ } else if ( m_pPrivateRB -> isChecked() ) {
+ m_pEntityAttribute->setIndexType(Uml::Index);
+ } else if ( m_pProtectedRB -> isChecked() ) {
+ m_pEntityAttribute->setIndexType(Uml::Unique);
+ } else {
+ m_pEntityAttribute->setIndexType(Uml::None);
+ }
+
+ QString typeName = m_pTypeCB->currentText();
+ UMLDoc *pDoc = UMLApp::app()->getDocument();
+ UMLClassifierList dataTypes = pDoc->getDatatypes();
+ UMLClassifier *dat;
+ for (UMLClassifierListIt dit(dataTypes); (dat = dit.current()) != NULL; ++dit) {
+ if (typeName == dat->getName()) {
+ m_pEntityAttribute->setType(dat);
+ return true;
+ }
+ }
+ UMLObject *obj = pDoc->findUMLObject(typeName);
+ UMLClassifier *classifier = dynamic_cast<UMLClassifier*>(obj);
+ if (classifier == NULL) {
+ // If it's obviously a pointer type (C++) then create a datatype.
+ // Else we don't know what it is so as a compromise create a class.
+ Uml::Object_Type ot = (typeName.contains('*') ? Uml::ot_Datatype
+ : Uml::ot_Class);
+ obj = Object_Factory::createUMLObject(ot, typeName);
+ if (obj == NULL)
+ return false;
+ classifier = static_cast<UMLClassifier*>(obj);
+ }
+ m_pEntityAttribute->setType( classifier );
+ return true;
+}
+
+void UMLEntityAttributeDialog::slotApply() {
+ apply();
+}
+
+void UMLEntityAttributeDialog::slotOk() {
+ if ( apply() ) {
+ accept();
+ }
+}
+
+void UMLEntityAttributeDialog::insertType( const QString& type, int index ) {
+ m_pTypeCB->insertItem( type, index );
+ m_pTypeCB->completionObject()->addItem( type );
+}
+
+void UMLEntityAttributeDialog::insertAttribute( const QString& type, int index ) {
+ m_pAttributesCB->insertItem( type, index );
+ m_pAttributesCB->completionObject()->addItem( type );
+}
+
+
+#include "umlentityattributedialog.moc"
diff --git a/umbrello/umbrello/dialogs/umlentityattributedialog.h b/umbrello/umbrello/dialogs/umlentityattributedialog.h
new file mode 100644
index 00000000..0b81472e
--- /dev/null
+++ b/umbrello/umbrello/dialogs/umlentityattributedialog.h
@@ -0,0 +1,87 @@
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * copyright (C) 2002-2006 *
+ * Umbrello UML Modeller Authors <uml-devel@uml.sf.net> *
+ ***************************************************************************/
+
+#ifndef UMLENTITYATTRIBUTEDIALOG_H
+#define UMLENTITYATTRIBUTEDIALOG_H
+
+#include <kdialogbase.h>
+
+/**
+ * @author Jonathan Riddell
+ * Bugs and comments to uml-devel@lists.sf.net or http://bugs.kde.org
+ */
+
+class QButtonGroup;
+class QCheckBox;
+class QGroupBox;
+class QRadioButton;
+class UMLEntityAttribute;
+class KComboBox;
+class QLineEdit;
+
+class UMLEntityAttributeDialog : public KDialogBase {
+ Q_OBJECT
+public:
+ UMLEntityAttributeDialog( QWidget* pParent, UMLEntityAttribute* pEntityAttribute );
+ ~UMLEntityAttributeDialog();
+
+protected:
+ /**
+ * Sets up the dialog
+ */
+ void setupDialog();
+
+ /**
+ * Checks if changes are valid and applies them if they are,
+ * else returns false
+ */
+ bool apply();
+
+ /**
+ * Inserts @p type into the type-combobox as well as its completion object.
+ */
+ void insertType( const QString& type, int index = -1 );
+ /**
+ * Inserts @p type into the type-combobox as well as its completion object.
+ */
+ void insertAttribute( const QString& type, int index = -1 );
+
+ /**
+ * The EntityAttribute to represent
+ */
+ UMLEntityAttribute * m_pEntityAttribute;
+
+ //GUI Widgets
+ QGroupBox * m_pAttsGB, * m_pValuesGB;
+ QButtonGroup * m_pScopeBG;
+ QRadioButton * m_pPublicRB, * m_pPrivateRB, * m_pProtectedRB, * m_pNoneRB;
+ QLabel * m_pTypeL, * m_pNameL, * m_pInitialL, * m_pStereoTypeL, * m_pValuesL, * m_pAttributesL ;
+ KComboBox * m_pTypeCB;
+ KComboBox * m_pAttributesCB;
+ QLineEdit * m_pNameLE, * m_pInitialLE, * m_pStereoTypeLE, * m_pValuesLE;
+ QCheckBox* m_pAutoIncrementCB;
+ QCheckBox* m_pNullCB;
+
+public slots:
+ /**
+ * I don't think this is used, but if we had an apply button
+ * it would slot into here
+ */
+ void slotApply();
+
+ /**
+ * Used when the OK button is clicked. Calls apply()
+ */
+ void slotOk();
+ void slotNameChanged( const QString & );
+};
+
+#endif
diff --git a/umbrello/umbrello/dialogs/umloperationdialog.cpp b/umbrello/umbrello/dialogs/umloperationdialog.cpp
new file mode 100644
index 00000000..07c56d52
--- /dev/null
+++ b/umbrello/umbrello/dialogs/umloperationdialog.cpp
@@ -0,0 +1,530 @@
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * copyright (C) 2002-2006 *
+ * Umbrello UML Modeller Authors <uml-devel@uml.sf.net> *
+ ***************************************************************************/
+
+// own header
+#include "umloperationdialog.h"
+
+//qt includes
+#include <qlayout.h>
+#include <qgroupbox.h>
+#include <qlistbox.h>
+#include <qbuttongroup.h>
+#include <qpushbutton.h>
+#include <qradiobutton.h>
+#include <qlabel.h>
+#include <qcheckbox.h>
+#include <qlineedit.h>
+
+//kde includes
+#include <kcombobox.h>
+#include <kdebug.h>
+#include <klocale.h>
+#include <kmessagebox.h>
+#include <kbuttonbox.h>
+#include <karrowbutton.h>
+
+//app includes
+#include "../uml.h"
+#include "../umldoc.h"
+#include "../operation.h"
+#include "../classifier.h"
+#include "../template.h"
+#include "../listpopupmenu.h"
+#include "../umlattributelist.h"
+#include "../classifierlistitem.h"
+#include "../umlclassifierlistitemlist.h"
+#include "../dialog_utils.h"
+#include "parmpropdlg.h"
+#include "../stereotype.h"
+#include "../uniqueid.h"
+
+UMLOperationDialog::UMLOperationDialog( QWidget * parent, UMLOperation * pOperation )
+ : KDialogBase( Plain, i18n("Operation Properties"), Help | Ok | Cancel , Ok, parent, "_UMLOPERATIONDLG_", true, true) {
+ m_pOperation = pOperation;
+ m_doc = UMLApp::app()->getDocument();
+ m_pMenu = 0;
+ setupDialog();
+}
+
+UMLOperationDialog::~UMLOperationDialog() {}
+
+void UMLOperationDialog::setupDialog() {
+
+ int margin = fontMetrics().height();
+ QVBoxLayout * topLayout = new QVBoxLayout( plainPage() );
+
+ m_pGenGB = new QGroupBox(i18n("General Properties"), plainPage() );
+ QGridLayout * genLayout = new QGridLayout(m_pGenGB, 3, 4 );
+ genLayout -> setColStretch(1, 1);
+ genLayout -> setColStretch(3, 1);
+ genLayout -> addColSpacing(1, 200);
+ genLayout -> addColSpacing(3, 200);
+ genLayout -> setMargin(margin);
+ genLayout -> setSpacing(10);
+
+ Dialog_Utils::makeLabeledEditField( m_pGenGB, genLayout, 0,
+ m_pNameL, i18n("&Name:"),
+ m_pNameLE, m_pOperation->getName() );
+
+ m_pRtypeL = new QLabel(i18n("&Type:"), m_pGenGB );
+ genLayout -> addWidget(m_pRtypeL, 0, 2);
+
+ m_pRtypeCB = new KComboBox(true, m_pGenGB );
+ genLayout -> addWidget(m_pRtypeCB, 0, 3);
+ m_pRtypeL->setBuddy(m_pRtypeCB);
+
+ m_pStereoTypeL = new QLabel( i18n("Stereotype name:"), m_pGenGB );
+ genLayout -> addWidget(m_pStereoTypeL, 1, 0);
+ m_pStereoTypeCB = new KComboBox(true, m_pGenGB );
+ genLayout -> addWidget(m_pStereoTypeCB, 1, 1);
+
+ m_pAbstractCB = new QCheckBox( i18n("&Abstract operation"), m_pGenGB );
+ m_pAbstractCB -> setChecked( m_pOperation->getAbstract() );
+ genLayout -> addWidget( m_pAbstractCB, 2, 0 );
+ m_pStaticCB = new QCheckBox( i18n("Classifier &scope (\"static\")"), m_pGenGB );
+ m_pStaticCB -> setChecked( m_pOperation->getStatic() );
+ genLayout -> addWidget( m_pStaticCB, 2, 1 );
+ m_pQueryCB = new QCheckBox( i18n("&Query (\"const\")"), m_pGenGB );
+ m_pQueryCB -> setChecked( m_pOperation->getConst() );
+ genLayout -> addWidget( m_pQueryCB, 2, 2 );
+
+ topLayout -> addWidget( m_pGenGB );
+
+ m_pScopeBG = new QButtonGroup(i18n("Visibility"), plainPage() );
+
+ QHBoxLayout * scopeLayout = new QHBoxLayout(m_pScopeBG);
+ scopeLayout -> setMargin(margin);
+
+ m_pPublicRB = new QRadioButton(i18n("P&ublic"), m_pScopeBG);
+ scopeLayout -> addWidget(m_pPublicRB);
+
+ m_pPrivateRB = new QRadioButton(i18n("P&rivate"), m_pScopeBG);
+ scopeLayout -> addWidget(m_pPrivateRB);
+
+ m_pProtectedRB = new QRadioButton(i18n("Prot&ected"), m_pScopeBG);
+ scopeLayout -> addWidget(m_pProtectedRB);
+
+ m_pImplementationRB = new QRadioButton(i18n("I&mplementation"), m_pScopeBG);
+ scopeLayout -> addWidget(m_pImplementationRB);
+
+ topLayout -> addWidget(m_pScopeBG);
+
+ m_pParmsGB = new QGroupBox(i18n("Parameters"), plainPage() );
+ QVBoxLayout* parmsLayout = new QVBoxLayout(m_pParmsGB);
+ parmsLayout->setMargin(margin);
+ parmsLayout->setSpacing(10);
+
+ //horizontal box contains the list box and the move up/down buttons
+ QHBoxLayout* parmsHBoxLayout = new QHBoxLayout(parmsLayout);
+ m_pParmsLB = new QListBox(m_pParmsGB);
+ parmsHBoxLayout->addWidget(m_pParmsLB);
+
+ //the move up/down buttons (another vertical box)
+ QVBoxLayout* buttonLayout = new QVBoxLayout( parmsHBoxLayout );
+ m_pUpButton = new KArrowButton( m_pParmsGB );
+ m_pUpButton->setEnabled( false );
+ buttonLayout->addWidget( m_pUpButton );
+
+ m_pDownButton = new KArrowButton( m_pParmsGB, Qt::DownArrow );
+ m_pDownButton->setEnabled( false );
+ buttonLayout->addWidget( m_pDownButton );
+
+ KButtonBox* buttonBox = new KButtonBox(m_pParmsGB);
+ buttonBox->addButton( i18n("Ne&w Parameter..."), this, SLOT(slotNewParameter()) );
+ m_pDeleteButton = buttonBox->addButton( i18n("&Delete"), this, SLOT(slotDeleteParameter()) );
+ m_pPropertiesButton = buttonBox->addButton( i18n("&Properties"), this,
+ SLOT(slotParameterProperties()) );
+ parmsLayout->addWidget(buttonBox);
+
+ topLayout -> addWidget(m_pParmsGB);
+
+ m_pDeleteButton->setEnabled(false);
+ m_pPropertiesButton->setEnabled(false);
+ m_pUpButton->setEnabled(false);
+ m_pDownButton->setEnabled(false);
+
+ // Add "void". We use this for denoting "no return type" independent
+ // of the programming language.
+ // For example, the Ada generator would interpret the return type
+ // "void" as an instruction to generate a procedure instead of a
+ // function.
+ insertType( "void" );
+
+ m_pRtypeCB->setDuplicatesEnabled(false);//only allow one of each type in box
+ m_pRtypeCB->setCompletionMode( KGlobalSettings::CompletionPopup );
+
+ // add template parameters
+ UMLClassifier *classifier = dynamic_cast<UMLClassifier*>(m_pOperation->parent());
+ if (classifier) {
+ UMLClassifierListItemList tmplParams( classifier->getFilteredList(Uml::ot_Template) );
+ for (UMLClassifierListItem *li = tmplParams.first(); li; li = tmplParams.next())
+ insertType( li->getName() );
+ }
+ //now add the Classes and Interfaces (both are Concepts)
+ UMLClassifierList namesList( m_doc->getConcepts() );
+ UMLClassifier* pConcept = 0;
+ for(pConcept=namesList.first(); pConcept!=0 ;pConcept=namesList.next()) {
+ insertType( pConcept->getFullyQualifiedName() );
+ }
+
+ //work out which one to select
+ int returnBoxCount = 0;
+ bool foundReturnType = false;
+ while (returnBoxCount < m_pRtypeCB->count() && foundReturnType == false) {
+ QString returnBoxString = m_pRtypeCB->text(returnBoxCount);
+ if ( returnBoxString == m_pOperation->getTypeName() ) {
+ foundReturnType = true;
+ m_pRtypeCB->setCurrentItem(returnBoxCount);
+ break;
+ }
+ returnBoxCount++;
+ }
+
+ if (!foundReturnType) {
+ insertType( m_pOperation->getTypeName(), 0 );
+ m_pRtypeCB->setCurrentItem(0);
+ }
+
+ //fill in parm list box
+ UMLAttributeList list = m_pOperation->getParmList();
+ UMLAttribute * pAtt = 0;
+ for (pAtt = list.first(); pAtt; pAtt = list.next())
+ m_pParmsLB->insertItem( pAtt->getName() );
+
+ //set scope
+ Uml::Visibility scope = m_pOperation -> getVisibility();
+ if( scope == Uml::Visibility::Public )
+ m_pPublicRB -> setChecked( true );
+ else if( scope == Uml::Visibility::Private )
+ m_pPrivateRB -> setChecked( true );
+ else if( scope == Uml::Visibility::Protected )
+ m_pProtectedRB -> setChecked( true );
+ else if( scope == Uml::Visibility::Implementation )
+ m_pImplementationRB -> setChecked( true );
+
+ // manage stereotypes
+ m_pStereoTypeCB -> setDuplicatesEnabled(false);//only allow one of each type in box
+ m_pStereoTypeCB->setCompletionMode( KGlobalSettings::CompletionPopup );
+ insertStereotype (QString("")); // an empty stereotype is the default
+ int defaultStereotype=0;
+ bool foundDefaultStereotype = false;
+ for (UMLStereotypeListIt it(m_doc->getStereotypes()); it.current(); ++it) {
+ if (!foundDefaultStereotype) {
+ if ( m_pOperation->getStereotype() == it.current()->getName()) {
+ foundDefaultStereotype = true;
+ }
+ defaultStereotype++;
+ }
+ insertStereotype (it.current()->getName());
+ }
+ // lookup for a default stereotype, if the operation doesn't have one
+ if (foundDefaultStereotype)
+ m_pStereoTypeCB->setCurrentItem(defaultStereotype);
+ else
+ m_pStereoTypeCB->setCurrentItem(-1);
+
+ //setup parm list box signals
+ connect( m_pUpButton, SIGNAL( clicked() ), this, SLOT( slotParameterUp() ) );
+ connect( m_pDownButton, SIGNAL( clicked() ), this, SLOT( slotParameterDown() ) );
+
+ connect(m_pParmsLB, SIGNAL(clicked(QListBoxItem*)),
+ this, SLOT(slotParamsBoxClicked(QListBoxItem*)));
+
+ connect(m_pParmsLB, SIGNAL(rightButtonPressed(QListBoxItem *, const QPoint &)),
+ this, SLOT(slotParmRightButtonPressed(QListBoxItem *, const QPoint &)));
+
+ connect(m_pParmsLB, SIGNAL(rightButtonClicked(QListBoxItem *, const QPoint &)),
+ this, SLOT(slotParmRightButtonClicked(QListBoxItem *, const QPoint &)));
+
+
+ connect(m_pParmsLB, SIGNAL(doubleClicked(QListBoxItem *)),
+ this, SLOT(slotParmDoubleClick(QListBoxItem *)));
+
+ m_pNameLE->setFocus();
+ connect( m_pNameLE, SIGNAL( textChanged ( const QString & ) ), SLOT( slotNameChanged( const QString & ) ) );
+ slotNameChanged(m_pNameLE->text() );
+
+}
+
+void UMLOperationDialog::slotNameChanged( const QString &_text )
+{
+ enableButtonOK( !_text.isEmpty() );
+}
+
+
+void UMLOperationDialog::slotParmRightButtonPressed(QListBoxItem *item, const QPoint &p) {
+ ListPopupMenu::Menu_Type type = ListPopupMenu::mt_Undefined;
+ if(item)//pressed on an item
+ {
+ type = ListPopupMenu::mt_Parameter_Selected;
+ } else//pressed into fresh air
+ {
+ type = ListPopupMenu::mt_New_Parameter;
+ }
+ if(m_pMenu) {
+ m_pMenu -> hide();
+ disconnect(m_pMenu, SIGNAL(activated(int)), this, SLOT(slotParmPopupMenuSel(int)));
+ delete m_pMenu;
+ m_pMenu = 0;
+ }
+ m_pMenu = new ListPopupMenu(this, type);
+ m_pMenu->popup(p);
+ connect(m_pMenu, SIGNAL(activated(int)), this, SLOT(slotParmPopupMenuSel(int)));
+
+}
+
+void UMLOperationDialog::slotParmRightButtonClicked(QListBoxItem */*item*/, const QPoint &/*p*/) {
+ if(m_pMenu) {
+ m_pMenu -> hide();
+ disconnect(m_pMenu, SIGNAL(activated(int)), this, SLOT(slotParmPopupMenuSel(int)));
+ delete m_pMenu;
+ m_pMenu = 0;
+ }
+}
+
+void UMLOperationDialog::slotParmDoubleClick(QListBoxItem *item) {
+ if(!item)
+ return;
+ slotParmPopupMenuSel(ListPopupMenu::mt_Properties);
+}
+
+void UMLOperationDialog::slotParmPopupMenuSel(int id) {
+ if( id == ListPopupMenu::mt_Rename || id == ListPopupMenu::mt_Properties ) {
+ slotParameterProperties();
+ } else if( id == ListPopupMenu::mt_New_Parameter ) {
+ slotNewParameter();
+ }
+ else if( id == ListPopupMenu::mt_Delete ) {
+ slotDeleteParameter();
+ }
+}
+
+void UMLOperationDialog::slotNewParameter() {
+ int result = 0;
+ UMLAttribute* pAtt = 0;
+
+ QString currentName = m_pOperation->getUniqueParameterName();
+ UMLAttribute* newAttribute = new UMLAttribute(m_pOperation, currentName, Uml::id_Reserved);
+
+ ParmPropDlg dlg(this, m_doc, newAttribute);
+ result = dlg.exec();
+ QString name = dlg.getName();
+ pAtt = m_pOperation -> findParm( name );
+ if( result ) {
+ if( name.length() == 0 ) {
+ KMessageBox::error(this, i18n("You have entered an invalid parameter name."),
+ i18n("Parameter Name Invalid"), false);
+ delete newAttribute;
+ return;
+ }
+ if( !pAtt ) {
+ newAttribute->setID( UniqueID::gen() );
+ newAttribute->setName( name );
+ newAttribute->setTypeName( dlg.getTypeName() );
+ newAttribute->setInitialValue( dlg.getInitialValue() );
+ newAttribute->setDoc( dlg.getDoc() );
+ newAttribute->setParmKind( dlg.getParmKind() );
+ m_pOperation->addParm( newAttribute );
+ m_pParmsLB -> insertItem( name );
+ m_doc -> setModified( true );
+ } else {
+ KMessageBox::sorry(this, i18n("The parameter name you have chosen\nis already being used in this operation."),
+ i18n("Parameter Name Not Unique"), false);
+ delete newAttribute;
+ }
+ } else {
+ delete newAttribute;
+ }
+}
+
+void UMLOperationDialog::slotDeleteParameter() {
+ UMLAttribute* pOldAtt = m_pOperation->findParm( m_pParmsLB->currentText() );
+
+ m_pOperation->removeParm( pOldAtt );
+ m_pParmsLB->removeItem( m_pParmsLB->currentItem() );
+ m_doc->setModified(true);
+
+ m_pDeleteButton->setEnabled(false);
+ m_pPropertiesButton->setEnabled(false);
+ m_pUpButton->setEnabled(false);
+ m_pDownButton->setEnabled(false);
+}
+
+void UMLOperationDialog::slotParameterProperties() {
+ int result = 0;
+ UMLAttribute* pAtt = 0, * pOldAtt = 0;
+ pOldAtt = m_pOperation->findParm( m_pParmsLB->currentText() );
+
+ if( !pOldAtt ) {
+ kDebug() << "THE impossible has occurred for:" << m_pParmsLB->currentText() << endl;
+ return;
+ }//should never occur
+ ParmPropDlg dlg(this, m_doc, pOldAtt);
+ result = dlg.exec();
+ QString name = dlg.getName();
+ pAtt = m_pOperation->findParm( name );
+ if( result ) {
+ if( name.length() == 0 ) {
+ KMessageBox::error(this, i18n("You have entered an invalid parameter name."),
+ i18n("Parameter Name Invalid"), false);
+ return;
+ }
+ if ( !pAtt || pOldAtt->getTypeName() != dlg.getTypeName() ||
+ pOldAtt->getDoc() != dlg.getDoc() ||
+ pOldAtt->getInitialValue() != dlg.getInitialValue() ) {
+ pOldAtt->setName( name );
+ QString typeName = dlg.getTypeName();
+ if (pOldAtt->getTypeName() != typeName) {
+ UMLClassifierList namesList( m_doc->getConcepts() );
+ UMLClassifier* obj = NULL;
+ for (obj=namesList.first(); obj!=0; obj=namesList.next()) {
+ if (typeName == obj->getFullyQualifiedName()) {
+ pOldAtt->setType( obj );
+ break;
+ }
+ }
+ if (obj == NULL) {
+ // Nothing found: set type name directly. Bad.
+ kDebug() << "UMLOperationDialog::slotParameterProperties: "
+ << typeName << " not found." << endl;
+ pOldAtt->setTypeName( typeName ); // Bad.
+ }
+ }
+ m_pParmsLB->changeItem( dlg.getName(), m_pParmsLB -> currentItem() );
+ pOldAtt->setDoc( dlg.getDoc() );
+ pOldAtt->setInitialValue( dlg.getInitialValue() );
+ m_doc->setModified( true );
+ } else if( pAtt != pOldAtt ) {
+ KMessageBox::error(this, i18n("The parameter name you have chosen is already being used in this operation."),
+ i18n("Parameter Name Not Unique"), false);
+ }
+ }
+}
+
+void UMLOperationDialog::slotParameterUp()
+{
+ kDebug() << k_funcinfo << endl;
+ UMLAttribute* pOldAtt = m_pOperation->findParm( m_pParmsLB->currentText() );
+
+ m_pOperation->moveParmLeft( pOldAtt );
+ QString tmp = m_pParmsLB->currentText();
+ m_pParmsLB->changeItem( m_pParmsLB->item( m_pParmsLB->currentItem() - 1 )->text(), m_pParmsLB->currentItem() );
+ m_pParmsLB->changeItem( tmp, m_pParmsLB->currentItem() - 1 );
+ m_doc->setModified(true);
+ slotParamsBoxClicked( m_pParmsLB->selectedItem() );
+}
+
+void UMLOperationDialog::slotParameterDown()
+{
+ UMLAttribute* pOldAtt = m_pOperation->findParm( m_pParmsLB->currentText() );
+
+ m_pOperation->moveParmRight( pOldAtt );
+ QString tmp = m_pParmsLB->currentText();
+ m_pParmsLB->changeItem( m_pParmsLB->item( m_pParmsLB->currentItem() + 1 )->text(), m_pParmsLB->currentItem() );
+ m_pParmsLB->changeItem( tmp, m_pParmsLB->currentItem() + 1 );
+
+ m_doc->setModified(true);
+ slotParamsBoxClicked( m_pParmsLB->selectedItem() );
+}
+
+void UMLOperationDialog::slotParamsBoxClicked(QListBoxItem* parameterItem) {
+ if (parameterItem) {
+ m_pDeleteButton->setEnabled(true);
+ m_pPropertiesButton->setEnabled(true);
+ m_pUpButton->setEnabled( parameterItem->prev() );
+ m_pDownButton->setEnabled( parameterItem->next() );
+ } else {
+ m_pDeleteButton->setEnabled(false);
+ m_pPropertiesButton->setEnabled(false);
+ m_pUpButton->setEnabled(false);
+ m_pDownButton->setEnabled(false);
+ }
+}
+
+bool UMLOperationDialog::apply()
+{
+ QString name = m_pNameLE -> text();
+ if( name.length() == 0 ) {
+ KMessageBox::error(this, i18n("You have entered an invalid operation name."),
+ i18n("Operation Name Invalid"), false);
+ m_pNameLE -> setText( m_pOperation -> getName() );
+ return false;
+ }
+
+ UMLClassifier *classifier = dynamic_cast<UMLClassifier*>( m_pOperation->parent() );
+ if( classifier != 0L &&
+ classifier->checkOperationSignature(name, m_pOperation->getParmList(), m_pOperation) )
+ {
+ QString msg = QString(i18n("An operation with that signature already exists in %1.\n")).arg(classifier->getName())
+ +
+ QString(i18n("Choose a different name or parameter list." ));
+ KMessageBox::error(this, msg, i18n("Operation Name Invalid"), false);
+ return false;
+ }
+ m_pOperation -> setName( name );
+
+ if( m_pPublicRB -> isChecked() )
+ m_pOperation -> setVisibility( Uml::Visibility::Public );
+ else if( m_pPrivateRB -> isChecked() )
+ m_pOperation -> setVisibility( Uml::Visibility::Private );
+ else if (m_pProtectedRB -> isChecked() )
+ m_pOperation -> setVisibility( Uml::Visibility::Protected );
+ else if (m_pImplementationRB -> isChecked() )
+ m_pOperation -> setVisibility( Uml::Visibility::Implementation );
+
+ QString typeName = m_pRtypeCB->currentText();
+ UMLTemplate *tmplParam = classifier->findTemplate(typeName);
+ if (tmplParam)
+ m_pOperation->setType(tmplParam);
+ else
+ m_pOperation->setTypeName(typeName);
+
+ m_pOperation->setStereotype( m_pStereoTypeCB->currentText() );
+
+ bool isAbstract = m_pAbstractCB->isChecked();
+ m_pOperation -> setAbstract( isAbstract );
+ if (isAbstract) {
+ /* If any operation is abstract then the owning class needs
+ to be made abstract.
+ The inverse is not true: The fact that no operation is
+ abstract does not mean that the class must be non-abstract.
+ */
+ classifier->setAbstract(true);
+ }
+ m_pOperation->setStatic( m_pStaticCB->isChecked() );
+ m_pOperation->setConst( m_pQueryCB->isChecked() );
+
+ return true;
+}
+
+void UMLOperationDialog::slotApply() {
+ apply();
+}
+
+void UMLOperationDialog::slotOk() {
+ if ( apply() ) {
+ accept();
+ }
+}
+
+void UMLOperationDialog::insertType( const QString& type, int index )
+{
+ m_pRtypeCB->insertItem( type, index );
+ m_pRtypeCB->completionObject()->addItem( type );
+}
+
+void UMLOperationDialog::insertStereotype( const QString& type, int index )
+{
+ m_pStereoTypeCB->insertItem( type, index );
+ m_pStereoTypeCB->completionObject()->addItem( type );
+}
+
+#include "umloperationdialog.moc"
diff --git a/umbrello/umbrello/dialogs/umloperationdialog.h b/umbrello/umbrello/dialogs/umloperationdialog.h
new file mode 100644
index 00000000..1dee99ab
--- /dev/null
+++ b/umbrello/umbrello/dialogs/umloperationdialog.h
@@ -0,0 +1,135 @@
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * copyright (C) 2002-2006 *
+ * Umbrello UML Modeller Authors <uml-devel@uml.sf.net> *
+ ***************************************************************************/
+
+
+#ifndef UMLOPERATIONDIALOG_H
+#define UMLOPERATIONDIALOG_H
+
+//kde includes
+#include <kdialogbase.h>
+
+/**
+ * @author Paul Hensgen
+ * Bugs and comments to uml-devel@lists.sf.net or http://bugs.kde.org
+ */
+
+class UMLOperation;
+class ListPopupMenu;
+class QGroupBox;
+class QListBox;
+class QButtonGroup;
+class QRadioButton;
+class QPushButton;
+class QLabel;
+class QCheckBox;
+class KComboBox;
+class QLineEdit;
+class UMLDoc;
+class KArrowButton;
+
+class UMLOperationDialog : public KDialogBase {
+ Q_OBJECT
+
+public:
+ /**
+ * Constructor
+ */
+ UMLOperationDialog( QWidget * parent, UMLOperation * pOperation );
+
+ /**
+ * Deconstructor
+ */
+ ~UMLOperationDialog();
+
+protected:
+ /**
+ * Sets up the dialog
+ */
+ void setupDialog();
+
+ /**
+ * Checks if changes are valid and applies them if they are,
+ * else returns false
+ */
+ bool apply();
+
+ /**
+ * Inserts @p type into the type-combobox as well as its completion object.
+ */
+ void insertType( const QString& type, int index = -1 );
+
+ /**
+ * The operation to represent.
+ */
+ UMLOperation * m_pOperation;
+
+ /**
+ * The UMLDocument where all objects live
+ */
+ UMLDoc *m_doc;
+
+ /**
+ * Menu used in paramater list box.
+ */
+ ListPopupMenu * m_pMenu;
+
+ /**
+ * Inserts @p stereotype into the stereotype-combobox as well as its completion object.
+ */
+ void insertStereotype( const QString& type, int index = -1 );
+
+ //GUI widgets
+ QGroupBox * m_pParmsGB, * m_pGenGB;
+ QListBox * m_pParmsLB;
+ QButtonGroup * m_pScopeBG;
+ QRadioButton * m_pPublicRB, * m_pPrivateRB, * m_pProtectedRB, *m_pImplementationRB;
+ QLabel * m_pRtypeL, * m_pNameL, * m_pStereoTypeL;
+ KComboBox * m_pRtypeCB, * m_pStereoTypeCB;
+ QLineEdit * m_pNameLE;
+ QCheckBox * m_pAbstractCB;
+ QCheckBox * m_pStaticCB;
+ QCheckBox * m_pQueryCB;
+ QPushButton* m_pDeleteButton;
+ QPushButton* m_pPropertiesButton;
+ KArrowButton* m_pUpButton;
+ KArrowButton* m_pDownButton;
+
+public slots:
+ void slotParmRightButtonPressed(QListBoxItem *item, const QPoint &p);
+ void slotParmRightButtonClicked(QListBoxItem *item, const QPoint &p);
+ void slotParmDoubleClick(QListBoxItem *item);
+ void slotParmPopupMenuSel(int id);
+ void slotNewParameter();
+ void slotDeleteParameter();
+ void slotParameterProperties();
+ void slotParameterUp();
+ void slotParameterDown();
+
+ /**
+ * enables or disables buttons
+ */
+ void slotParamsBoxClicked(QListBoxItem* parameterItem);
+
+ /**
+ * I don't think this is used, but if we had an apply button
+ * it would slot into here
+ */
+ void slotApply();
+
+ /**
+ * Used when the OK button is clicked. Calls apply()
+ */
+ void slotOk();
+ void slotNameChanged( const QString & );
+
+};
+
+#endif
diff --git a/umbrello/umbrello/dialogs/umlroledialog.cpp b/umbrello/umbrello/dialogs/umlroledialog.cpp
new file mode 100644
index 00000000..91ad5c65
--- /dev/null
+++ b/umbrello/umbrello/dialogs/umlroledialog.cpp
@@ -0,0 +1,63 @@
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * copyright (C) 2003-2007 *
+ * Umbrello UML Modeller Authors <uml-devel@uml.sf.net> *
+ ***************************************************************************/
+
+// own header
+#include "umlroledialog.h"
+
+// qt/kde includes
+#include <qlayout.h>
+#include <kdebug.h>
+#include <klocale.h>
+
+// app includes
+#include "../umlrole.h"
+#include "umlroleproperties.h"
+
+UMLRoleDialog::UMLRoleDialog( QWidget * parent, UMLRole * pRole )
+ : KDialogBase( Plain, i18n("Role Properties"), Help | Ok | Cancel , Ok, parent, "_UMLROLEDLG_", true, true)
+{
+ m_pRole = pRole;
+ setupDialog();
+}
+
+UMLRoleDialog::~UMLRoleDialog() {}
+
+void UMLRoleDialog::setupDialog() {
+ // UMLRoleDialogLayout = new QGridLayout( this, 1, 1, 11, 6, "UMLRoleLayout");
+ m_pRoleProps = new UMLRoleProperties(this, m_pRole);
+ setMainWidget( m_pRoleProps );
+
+ resize( QSize(425, 620).expandedTo(minimumSizeHint()) );
+
+ // topLayout -> addWidget( m_pParmsGB);
+
+}
+
+bool UMLRoleDialog::apply() {
+ if( m_pRoleProps ) {
+ m_pRoleProps->updateObject();
+ return true;
+ }
+ return false;
+}
+
+void UMLRoleDialog::slotApply() {
+ apply();
+}
+
+void UMLRoleDialog::slotOk() {
+ if ( apply() ) {
+ accept();
+ }
+}
+
+
+#include "umlroledialog.moc"
diff --git a/umbrello/umbrello/dialogs/umlroledialog.h b/umbrello/umbrello/dialogs/umlroledialog.h
new file mode 100644
index 00000000..09856d34
--- /dev/null
+++ b/umbrello/umbrello/dialogs/umlroledialog.h
@@ -0,0 +1,75 @@
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * copyright (C) 2003-2006 *
+ * Umbrello UML Modeller Authors <uml-devel@uml.sf.net> *
+ ***************************************************************************/
+
+
+#ifndef UMLROLEDIALOG_H
+#define UMLROLEDIALOG_H
+
+//kde includes
+#include <kdialogbase.h>
+
+/**
+ * @author Paul Hensgen
+ */
+
+class UMLRole;
+class UMLRoleProperties;
+
+class UMLRoleDialog : public KDialogBase {
+ Q_OBJECT
+public:
+ /**
+ * Constructor
+ */
+ UMLRoleDialog( QWidget * parent, UMLRole * pRole );
+
+ /**
+ * Deconstructor
+ */
+ ~UMLRoleDialog();
+
+protected:
+
+ /**
+ * Sets up the dialog
+ */
+ void setupDialog();
+
+ /**
+ * Checks if changes are valid and applies them if they are,
+ * else returns false
+ */
+ bool apply();
+
+ /**
+ * The role to represent.
+ */
+ UMLRole * m_pRole;
+
+private:
+
+ UMLRoleProperties * m_pRoleProps;
+
+public slots:
+
+ /**
+ * I don't think this is used, but if we had an apply button
+ * it would slot into here
+ */
+ void slotApply();
+
+ /**
+ * Used when the OK button is clicked. Calls apply()
+ */
+ void slotOk();
+};
+
+#endif
diff --git a/umbrello/umbrello/dialogs/umlroleproperties.cpp b/umbrello/umbrello/dialogs/umlroleproperties.cpp
new file mode 100644
index 00000000..275d98f1
--- /dev/null
+++ b/umbrello/umbrello/dialogs/umlroleproperties.cpp
@@ -0,0 +1,114 @@
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * copyright (C) 2003-2007 *
+ * Umbrello UML Modeller Authors <uml-devel@uml.sf.net> *
+ ***************************************************************************/
+
+// own header
+#include "umlroleproperties.h"
+
+// qt/kde includes
+#include <qradiobutton.h>
+#include <qtextedit.h>
+#include <qlineedit.h>
+#include <klocale.h>
+#include <kmessagebox.h>
+#include <kdebug.h>
+
+
+UMLRoleProperties::UMLRoleProperties ( QWidget *parent, UMLRole *role)
+ : UMLRolePropertiesBase (parent)
+{
+
+ m_pRole = role;
+ constructWidget();
+
+}
+
+UMLRoleProperties::~UMLRoleProperties() { }
+
+void UMLRoleProperties::constructWidget() {
+
+ // Use Parent Role to set starting Properties
+ //
+
+ // Rolename
+ m_pRoleLE -> setText(m_pRole->getName());
+
+ // Multiplicity
+ m_pMultiLE -> setText(m_pRole->getMultiplicity());
+
+ // Visibility
+ Uml::Visibility scope = m_pRole->getVisibility();
+ if( scope == Uml::Visibility::Public )
+ m_pPublicRB -> setChecked( true );
+ else if( scope == Uml::Visibility::Private )
+ m_pPrivateRB -> setChecked( true );
+ else if( scope == Uml::Visibility::Protected )
+ m_pProtectedRB -> setChecked( true );
+ else if( scope == Uml::Visibility::Implementation )
+ m_pImplementationRB -> setChecked( true );
+
+ // Changeability
+ Uml::Changeability_Type changeability = m_pRole->getChangeability();
+ if( changeability == Uml::chg_Changeable )
+ m_pChangeableRB -> setChecked( true );
+ else if( changeability == Uml::chg_Frozen )
+ m_pFrozenRB -> setChecked( true );
+ else
+ m_pAddOnlyRB -> setChecked( true );
+
+ // Documentation
+ //
+ m_pDocTE-> setText(m_pRole-> getDoc());
+ //m_pDocTE->setWordWrap(QMultiLineEdit::WidgetWidth);
+}
+
+void UMLRoleProperties::updateObject() {
+
+ if(m_pRole) {
+
+ // block signals to save work load..we only need to emit modified once,
+ // not each time we update an attribute of the association. I suppose
+ // we could check to see IF anything changed, but thats a lot more code,
+ // and not much gained. THis way is easier, if less 'beautiful'. -b.t.
+
+ m_pRole->blockSignals(true);
+
+ // set props
+ m_pRole->setName(m_pRoleLE->text());
+ m_pRole->setMultiplicity(m_pMultiLE->text());
+
+ if(m_pPrivateRB->isChecked())
+ m_pRole->setVisibility(Uml::Visibility::Private);
+ else if(m_pProtectedRB->isChecked())
+ m_pRole->setVisibility(Uml::Visibility::Protected);
+ else if(m_pPublicRB->isChecked())
+ m_pRole->setVisibility(Uml::Visibility::Public);
+ else if(m_pImplementationRB->isChecked())
+ m_pRole->setVisibility(Uml::Visibility::Implementation);
+
+ if(m_pFrozenRB->isChecked())
+ m_pRole->setChangeability(Uml::chg_Frozen);
+ else if(m_pAddOnlyRB->isChecked())
+ m_pRole->setChangeability(Uml::chg_AddOnly);
+ else
+ m_pRole->setChangeability(Uml::chg_Changeable);
+
+ m_pRole->setDoc(m_pDocTE->text());
+
+ m_pRole->blockSignals(false);
+
+ m_pRole->emitModified();
+
+ } //end if m_pRole
+
+}
+
+
+#include "umlroleproperties.moc"
diff --git a/umbrello/umbrello/dialogs/umlroleproperties.h b/umbrello/umbrello/dialogs/umlroleproperties.h
new file mode 100644
index 00000000..34f7d3e9
--- /dev/null
+++ b/umbrello/umbrello/dialogs/umlroleproperties.h
@@ -0,0 +1,59 @@
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * copyright (C) 2003-2006 *
+ * Umbrello UML Modeller Authors <uml-devel@uml.sf.net> *
+ ***************************************************************************/
+
+#ifndef UMLROLEPROPERTIES_H
+#define UMLROLEPROPERTIES_H
+
+//my class includes
+#include "umlrolepropertiesbase.h"
+#include "../umlrole.h"
+
+/**
+ * Displays properties of a UMLRole in a widget which may be used as
+ * a properties page or a stand-alone dialog.
+ *
+ * @author Brian Thomas <brian.thomas@gsfc.nasa.gov>
+ */
+class UMLRoleProperties : public UMLRolePropertiesBase {
+ Q_OBJECT
+public:
+
+ /**
+ * Sets up the UMLRoleProperties.
+ *
+ * @param parent The parent widget to the UMLRoleProperties.
+ * @param role The UMLRole to display the properties of.
+ */
+ UMLRoleProperties( QWidget *parent, UMLRole *role);
+
+ /**
+ * Standard deconstructor.
+ */
+ ~UMLRoleProperties();
+
+ /**
+ * Will move information from the dialog into the object.
+ * Call when the ok or apply button is pressed.
+ */
+ void updateObject();
+
+protected:
+
+ // the parent role object
+ UMLRole * m_pRole;
+
+private:
+
+ void constructWidget();
+
+};
+
+#endif
diff --git a/umbrello/umbrello/dialogs/umlrolepropertiesbase.ui b/umbrello/umbrello/dialogs/umlrolepropertiesbase.ui
new file mode 100644
index 00000000..7c35a284
--- /dev/null
+++ b/umbrello/umbrello/dialogs/umlrolepropertiesbase.ui
@@ -0,0 +1,203 @@
+<!DOCTYPE UI><UI version="3.1" stdsetdef="1">
+<class>UMLRolePropertiesBase</class>
+<widget class="QWidget">
+ <property name="name">
+ <cstring>UMLRolePropertiesBase</cstring>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>572</width>
+ <height>545</height>
+ </rect>
+ </property>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>layout6</cstring>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>10</x>
+ <y>10</y>
+ <width>400</width>
+ <height>520</height>
+ </rect>
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QGroupBox" row="0" column="0">
+ <property name="name">
+ <cstring>propsGroupBox</cstring>
+ </property>
+ <property name="title">
+ <string>Role Properties</string>
+ </property>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>layout5</cstring>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>10</x>
+ <y>30</y>
+ <width>360</width>
+ <height>70</height>
+ </rect>
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLabel" row="0" column="0">
+ <property name="name">
+ <cstring>roleNameLabel</cstring>
+ </property>
+ <property name="text">
+ <string>Rolename:</string>
+ </property>
+ </widget>
+ <widget class="QLineEdit" row="1" column="1">
+ <property name="name">
+ <cstring>m_pMultiLE</cstring>
+ </property>
+ </widget>
+ <widget class="QLineEdit" row="0" column="1">
+ <property name="name">
+ <cstring>m_pRoleLE</cstring>
+ </property>
+ </widget>
+ <widget class="QLabel" row="1" column="0">
+ <property name="name">
+ <cstring>textLabel2</cstring>
+ </property>
+ <property name="text">
+ <string>Multiplicity:</string>
+ </property>
+ </widget>
+ </grid>
+ </widget>
+ </widget>
+ <widget class="QGroupBox" row="3" column="0">
+ <property name="name">
+ <cstring>docGroupBox</cstring>
+ </property>
+ <property name="title">
+ <string>Documentation</string>
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QTextEdit" row="0" column="0">
+ <property name="name">
+ <cstring>m_pDocTE</cstring>
+ </property>
+ </widget>
+ </grid>
+ </widget>
+ <widget class="QButtonGroup" row="2" column="0">
+ <property name="name">
+ <cstring>changeabilityButtonGroup</cstring>
+ </property>
+ <property name="title">
+ <string>Role Changeability</string>
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLayoutWidget" row="0" column="0">
+ <property name="name">
+ <cstring>layout2</cstring>
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QRadioButton" row="0" column="2">
+ <property name="name">
+ <cstring>m_pAddOnlyRB</cstring>
+ </property>
+ <property name="text">
+ <string>Add only</string>
+ </property>
+ </widget>
+ <widget class="QRadioButton" row="0" column="1">
+ <property name="name">
+ <cstring>m_pFrozenRB</cstring>
+ </property>
+ <property name="text">
+ <string>Frozen</string>
+ </property>
+ </widget>
+ <widget class="QRadioButton" row="0" column="0">
+ <property name="name">
+ <cstring>m_pChangeableRB</cstring>
+ </property>
+ <property name="text">
+ <string>Changeable</string>
+ </property>
+ <property name="checked">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </grid>
+ </widget>
+ </grid>
+ </widget>
+ <widget class="QButtonGroup" row="1" column="0">
+ <property name="name">
+ <cstring>visibilityButtonGroup</cstring>
+ </property>
+ <property name="title">
+ <string>Role Visibility</string>
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QRadioButton" row="0" column="0">
+ <property name="name">
+ <cstring>m_pPublicRB</cstring>
+ </property>
+ <property name="text">
+ <string>Public</string>
+ </property>
+ <property name="checked">
+ <bool>true</bool>
+ </property>
+ </widget>
+ <widget class="QRadioButton" row="0" column="1">
+ <property name="name">
+ <cstring>m_pPrivateRB</cstring>
+ </property>
+ <property name="text">
+ <string>Private</string>
+ </property>
+ </widget>
+ <widget class="QRadioButton" row="0" column="2">
+ <property name="name">
+ <cstring>m_pProtectedRB</cstring>
+ </property>
+ <property name="text">
+ <string>Protected</string>
+ </property>
+ </widget>
+ <widget class="QRadioButton" row="0" column="3">
+ <property name="name">
+ <cstring>m_pImplementationRB</cstring>
+ </property>
+ <property name="text">
+ <string>Implementation</string>
+ </property>
+ </widget>
+ </grid>
+ </widget>
+ </grid>
+ </widget>
+</widget>
+<layoutdefaults spacing="6" margin="11"/>
+</UI>
diff --git a/umbrello/umbrello/dialogs/umltemplatedialog.cpp b/umbrello/umbrello/dialogs/umltemplatedialog.cpp
new file mode 100644
index 00000000..a183d95d
--- /dev/null
+++ b/umbrello/umbrello/dialogs/umltemplatedialog.cpp
@@ -0,0 +1,161 @@
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * copyright (C) 2003-2006 *
+ * Umbrello UML Modeller Authors <uml-devel@uml.sf.net> *
+ ***************************************************************************/
+
+// own header
+#include "umltemplatedialog.h"
+
+// qt includes
+#include <qlayout.h>
+#include <qgroupbox.h>
+#include <qcombobox.h>
+#include <qlabel.h>
+#include <qlineedit.h>
+
+// kde includes
+#include <kcombobox.h>
+#include <klocale.h>
+#include <kmessagebox.h>
+#include <kdebug.h>
+
+// app includes
+#include "../template.h"
+#include "../classifier.h"
+#include "../umldoc.h"
+#include "../uml.h"
+#include "../dialog_utils.h"
+
+UMLTemplateDialog::UMLTemplateDialog(QWidget* pParent, UMLTemplate* pTemplate)
+ : KDialogBase( Plain, i18n("Template Properties"), Help | Ok | Cancel , Ok, pParent, "_UMLTemplateDLG_", true, true) {
+ m_pTemplate = pTemplate;
+ setupDialog();
+}
+
+UMLTemplateDialog::~UMLTemplateDialog() {}
+
+void UMLTemplateDialog::setupDialog() {
+ int margin = fontMetrics().height();
+
+ QVBoxLayout* mainLayout = new QVBoxLayout( plainPage() );
+
+ m_pValuesGB = new QGroupBox(i18n("General Properties"), plainPage() );
+ QGridLayout* valuesLayout = new QGridLayout(m_pValuesGB, 3, 2);
+ valuesLayout->setMargin(margin);
+ valuesLayout->setSpacing(10);
+
+ m_pTypeL = new QLabel(i18n("&Type:"), m_pValuesGB);
+ valuesLayout->addWidget(m_pTypeL, 0, 0);
+
+ m_pTypeCB = new KComboBox(m_pValuesGB);
+ valuesLayout->addWidget(m_pTypeCB, 0, 1);
+ m_pTypeL->setBuddy(m_pTypeCB);
+
+ Dialog_Utils::makeLabeledEditField( m_pValuesGB, valuesLayout, 1,
+ m_pNameL, i18n("&Name:"),
+ m_pNameLE, m_pTemplate->getName() );
+
+ Dialog_Utils::makeLabeledEditField( m_pValuesGB, valuesLayout, 2,
+ m_pStereoTypeL, i18n("&Stereotype name:"),
+ m_pStereoTypeLE, m_pTemplate->getStereotype() );
+
+ mainLayout->addWidget(m_pValuesGB);
+
+ // "class" is the nominal type of template parameter
+ insertType( "class" );
+ // Add the active data types to combo box
+ UMLDoc *pDoc = UMLApp::app()->getDocument();
+ UMLClassifierList namesList( pDoc->getConcepts() );
+ UMLClassifier* obj = 0;
+ for (obj = namesList.first(); obj; obj = namesList.next()) {
+ insertType( obj->getName() );
+ }
+
+ m_pTypeCB->setEditable(true);
+ m_pTypeCB->setDuplicatesEnabled(false);//only allow one of each type in box
+ m_pTypeCB->setCompletionMode( KGlobalSettings::CompletionPopup );
+// m_pTypeCB->setAutoCompletion(true);
+
+ //work out which one to select
+ int typeBoxCount = 0;
+ bool foundType = false;
+ while (typeBoxCount < m_pTypeCB->count() && foundType == false) {
+ QString typeBoxString = m_pTypeCB->text(typeBoxCount);
+ if ( typeBoxString == m_pTemplate->getTypeName() ) {
+ foundType = true;
+ m_pTypeCB->setCurrentItem(typeBoxCount);
+ } else {
+ typeBoxCount++;
+ }
+ }
+
+ if (!foundType) {
+ insertType( m_pTemplate->getTypeName(), 0 );
+ m_pTypeCB->setCurrentItem(0);
+ }
+
+ m_pNameLE->setFocus();
+}
+
+void UMLTemplateDialog::insertType( const QString& type, int index )
+{
+ m_pTypeCB->insertItem( type, index );
+ m_pTypeCB->completionObject()->addItem( type );
+}
+
+bool UMLTemplateDialog::apply() {
+ QString typeName = m_pTypeCB->currentText();
+ UMLDoc *pDoc = UMLApp::app()->getDocument();
+ UMLClassifierList namesList( pDoc->getConcepts() );
+ UMLClassifier* obj = 0;
+ for (obj = namesList.first(); obj; obj = namesList.next()) {
+ if (typeName == obj->getName()) {
+ m_pTemplate->setType( obj );
+ }
+ }
+ if (obj == NULL) { // not found.
+ // FIXME: This implementation is not good yet.
+ m_pTemplate->setTypeName( typeName );
+ }
+ QString name = m_pNameLE->text();
+ if( name.length() == 0 ) {
+ KMessageBox::error(this, i18n("You have entered an invalid template name."),
+ i18n("Template Name Invalid"), false);
+ m_pNameLE->setText( m_pTemplate->getName() );
+ return false;
+ }
+
+ UMLClassifier * pClass = dynamic_cast<UMLClassifier *>( m_pTemplate->parent() );
+ if (pClass) {
+ UMLObject *o = pClass->findChildObject(name);
+ if (o && o != m_pTemplate) {
+ KMessageBox::error(this, i18n("The template parameter name you have chosen is already being used in this operation."),
+ i18n("Template Name Not Unique"), false);
+ m_pNameLE->setText( m_pTemplate->getName() );
+ return false;
+ }
+ }
+ m_pTemplate->setName(name);
+
+ m_pTemplate->setStereotype( m_pStereoTypeLE->text() );
+
+ return true;
+}
+
+void UMLTemplateDialog::slotApply() {
+ apply();
+}
+
+void UMLTemplateDialog::slotOk() {
+ if ( apply() ) {
+ accept();
+ }
+}
+
+#include "umltemplatedialog.moc"
diff --git a/umbrello/umbrello/dialogs/umltemplatedialog.h b/umbrello/umbrello/dialogs/umltemplatedialog.h
new file mode 100644
index 00000000..3bdd321b
--- /dev/null
+++ b/umbrello/umbrello/dialogs/umltemplatedialog.h
@@ -0,0 +1,81 @@
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * copyright (C) 2003-2006 *
+ * Umbrello UML Modeller Authors <uml-devel@uml.sf.net> *
+ ***************************************************************************/
+
+#ifndef UMLTEMPLATEDIALOG_H
+#define UMLTEMPLATEDIALOG_H
+
+#include <kdialogbase.h>
+
+class QButtonGroup;
+class QCheckBox;
+class KComboBox;
+class QGroupBox;
+class QLineEdit;
+class QRadioButton;
+class UMLTemplate;
+
+/**
+ * A dialog to edit the properties of a class template (paramaterised class)
+ *
+ * @author Jonathan Riddell
+ * Bugs and comments to uml-devel@lists.sf.net or http://bugs.kde.org
+ */
+
+class UMLTemplateDialog : public KDialogBase {
+ Q_OBJECT
+public:
+ UMLTemplateDialog(QWidget* pParent, UMLTemplate* pAttribute);
+ ~UMLTemplateDialog();
+
+protected:
+ /**
+ * Sets up the dialog
+ */
+ void setupDialog();
+
+ /**
+ * Checks if changes are valid and applies them if they are,
+ * else returns false
+ */
+ bool apply();
+
+ /**
+ * The Attribute to represent
+ */
+ UMLTemplate* m_pTemplate;
+
+ //GUI Widgets
+ QGroupBox* m_pTemplateGB;
+ QGroupBox* m_pValuesGB;
+ QLabel *m_pTypeL, *m_pNameL, *m_pStereoTypeL;
+ KComboBox* m_pTypeCB;
+ QLineEdit *m_pNameLE, *m_pStereoTypeLE;
+
+public slots:
+ /**
+ * I don't think this is used, but if we had an apply button
+ * it would slot into here
+ */
+ void slotApply();
+
+ /**
+ * Used when the OK button is clicked. Calls apply()
+ */
+ void slotOk();
+protected:
+ /**
+ * Inserts @p type into the type-combobox as well as its completion object.
+ */
+ void insertType( const QString& type, int index = -1 );
+
+};
+
+#endif
diff --git a/umbrello/umbrello/dialogs/umlviewdialog.cpp b/umbrello/umbrello/dialogs/umlviewdialog.cpp
new file mode 100644
index 00000000..94f44059
--- /dev/null
+++ b/umbrello/umbrello/dialogs/umlviewdialog.cpp
@@ -0,0 +1,184 @@
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * copyright (C) 2002-2007 *
+ * Umbrello UML Modeller Authors <uml-devel@uml.sf.net> *
+ ***************************************************************************/
+
+// own header
+#include "umlviewdialog.h"
+
+// qt/kde includes
+#include <qvbox.h>
+#include <qlayout.h>
+#include <qcheckbox.h>
+#include <qlabel.h>
+#include <qlineedit.h>
+#include <qgroupbox.h>
+#include <qtextedit.h>
+#include <qspinbox.h>
+#include <kiconloader.h>
+#include <klocale.h>
+#include <kmessagebox.h>
+#include <kfontdialog.h>
+#include <kdebug.h>
+#include <knuminput.h>
+
+// local includes
+#include "../umlview.h"
+#include "../umldoc.h"
+#include "../uml.h"
+#include "diagrampropertiespage.h"
+
+
+UMLViewDialog::UMLViewDialog( QWidget * pParent, UMLView * pView ) : KDialogBase(IconList, i18n("Properties"), Ok | Apply | Cancel | Help,
+ Ok, pParent, "_VIEWDLG_", true, true) {
+ m_pView = pView;
+ m_options = m_pView -> getOptionState();
+ setupPages();
+}
+
+UMLViewDialog::~UMLViewDialog() {
+}
+
+void UMLViewDialog::slotOk() {
+ applyPage( General );
+ applyPage( Color );
+ applyPage( Font );
+ applyPage( Class );
+ accept();
+}
+
+void UMLViewDialog::slotApply() {
+ applyPage( (Page)activePageIndex() );
+}
+
+void UMLViewDialog::setupPages()
+{
+ setupDiagramPropertiesPage();
+ setupColorPage();
+ setupFontPage();
+ setupClassPage();
+}
+
+void UMLViewDialog::setupDiagramPropertiesPage()
+{
+ QVBox *page = addVBoxPage( i18n("General"), i18n("General Settings"), DesktopIcon( "misc") );
+ m_diagramProperties = new DiagramPropertiesPage(page);
+
+ m_diagramProperties->diagramName->setText( m_pView->getName() );
+ m_diagramProperties->zoom->setValue(m_pView->currentZoom());
+ m_diagramProperties->showOpSigs->setChecked( m_pView->getShowOpSig() );
+
+ m_diagramProperties->showGrid->setChecked(m_pView -> getShowSnapGrid());
+ m_diagramProperties->snapToGrid->setChecked(m_pView-> getSnapToGrid());
+ m_diagramProperties->snapComponentSizeToGrid->setChecked(m_pView-> getSnapComponentSizeToGrid());
+
+ m_diagramProperties->gridSpaceX->setValue( m_pView -> getSnapX());
+ m_diagramProperties->gridSpaceY->setValue( m_pView -> getSnapY());
+ m_diagramProperties->lineWidth->setValue( m_pView -> getLineWidth());
+ m_diagramProperties->documentation->setText(m_pView -> getDoc());
+
+}
+
+void UMLViewDialog::setupClassPage() {
+ if( m_pView -> getType() != Uml::dt_Class ) {
+ return;
+ }
+
+ QFrame * newPage = addPage( i18n("Display"), i18n("Classes Display Options"), DesktopIcon( "info") );
+ QHBoxLayout * m_pOptionsLayout = new QHBoxLayout( newPage );
+ m_pOptionsPage = new ClassOptionsPage( newPage, &m_options );
+ m_pOptionsLayout -> addWidget( m_pOptionsPage );
+}
+
+void UMLViewDialog::setupColorPage() {
+ QFrame * colorPage = addPage( i18n("Color"), i18n("Diagram Colors"), DesktopIcon( "colors") );
+ QHBoxLayout * m_pColorLayout = new QHBoxLayout(colorPage);
+ m_pColorPage = new UMLWidgetColorPage( colorPage, &m_options );
+ m_pColorLayout -> addWidget(m_pColorPage);
+}
+
+void UMLViewDialog::setupFontPage() {
+ QVBox * page = addVBoxPage( i18n("Font"), i18n("Font Settings"), DesktopIcon( "fonts") );
+ m_pChooser = new KFontChooser( (QWidget*)page, "font", false, QStringList(), false);
+ m_pChooser -> setFont( m_pView -> getOptionState().uiState.font );
+}
+
+void UMLViewDialog::applyPage( Page page ) {
+
+ switch (page) {
+ case General:
+ {
+ checkName();
+ m_pView->setZoom( m_diagramProperties->zoom->value() );
+ m_pView->setDoc( m_diagramProperties->documentation->text() );
+ m_pView->setSnapX( m_diagramProperties->gridSpaceX->value() );
+ m_pView->setSnapY( m_diagramProperties->gridSpaceY->value() );
+ m_pView->setLineWidth( m_diagramProperties->lineWidth->value() );
+ m_pView->setSnapToGrid( m_diagramProperties->snapToGrid->isChecked() );
+ m_pView->setSnapComponentSizeToGrid( m_diagramProperties->snapComponentSizeToGrid->isChecked() );
+ m_pView->setShowSnapGrid( m_diagramProperties->showGrid->isChecked() );
+ m_pView->setShowOpSig( m_diagramProperties->showOpSigs->isChecked() );
+ break;
+ }
+ case Color:
+ m_pColorPage->updateUMLWidget();
+ m_pView->setUseFillColor( m_options.uiState.useFillColor );
+ m_pView->setLineColor( m_options.uiState.lineColor );
+ m_pView->setFillColor( m_options.uiState.fillColor );
+ break;
+
+ case Font:
+ kDebug() << "UMLViewDialog::applyPage: setting font "
+ << m_pChooser->font().toString() << endl;
+ m_pView->setFont( m_pChooser->font(), true );
+ break;
+
+ case Class:
+ if( m_pView->getType() != Uml::dt_Class ) {
+ return;
+ }
+ m_pOptionsPage->updateUMLWidget();
+ m_pView->setClassWidgetOptions( m_pOptionsPage );
+ // sig = m_pTempWidget->getShowOpSigs();
+ // showSig = !( sig == Uml::st_NoSig || sig == Uml::st_NoSigNoVis );
+ // options.classState.showOpSig = showSig;
+ // sig = m_pTempWidget->getShowAttSigs();
+ // showSig = !( sig == Uml::st_NoSig || sig == Uml::st_NoSigNoVis );
+ // options.classState.showAttSig = showSig;
+ m_pView->setOptionState( m_options );
+ break;
+ }
+}
+
+void UMLViewDialog::checkName() {
+ QString name = m_diagramProperties->diagramName-> text();
+ UMLDoc * pDoc = UMLApp::app()-> getDocument();
+ UMLView * pView = pDoc -> findView( m_pView -> getType(), name );
+ if( name.length() == 0 ) {
+ KMessageBox::sorry(this, i18n("The name you have entered is invalid."),
+ i18n("Invalid Name"), false);
+ m_diagramProperties->diagramName->setText( m_pView->getName() );
+ return;
+ }
+ if( pView && pView != m_pView ) {
+ KMessageBox::sorry(this, i18n("The name you have entered is not unique."),
+ i18n("Name Not Unique"), false);
+ m_diagramProperties->diagramName->setText( m_pView->getName() );
+ return;
+ }
+ m_pView->setName( name );
+ pDoc->signalDiagramRenamed(m_pView);
+}
+
+
+
+
+
+
+#include "umlviewdialog.moc"
diff --git a/umbrello/umbrello/dialogs/umlviewdialog.h b/umbrello/umbrello/dialogs/umlviewdialog.h
new file mode 100644
index 00000000..b6fe4ebd
--- /dev/null
+++ b/umbrello/umbrello/dialogs/umlviewdialog.h
@@ -0,0 +1,119 @@
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * copyright (C) 2002-2006 *
+ * Umbrello UML Modeller Authors <uml-devel@uml.sf.net> *
+ ***************************************************************************/
+
+#ifndef UMLVIEWDIALOG_H
+#define UMLVIEWDIALOG_H
+//kde includes
+#include <kdialogbase.h>
+//app includes
+#include "classoptionspage.h"
+#include "umlwidgetcolorpage.h"
+#include "../optionstate.h"
+
+/**
+ * @author Paul Hensgen
+ * Bugs and comments to uml-devel@lists.sf.net or http://bugs.kde.org
+ */
+class UMLView;
+class ClassWidget;
+
+class QCheckBox;
+class QLabel;
+class QLineEdit;
+class QGroupBox;
+class QTextEdit;
+class QSpinBox;
+class KFontChooser;
+class DiagramPropertiesPage;
+
+
+class UMLViewDialog : public KDialogBase {
+ Q_OBJECT
+public:
+ /**
+ * Constructor
+ */
+ UMLViewDialog( QWidget * pParent, UMLView * pView );
+
+ /**
+ * Deconstructor
+ */
+ ~UMLViewDialog();
+protected:
+ enum Page
+ {
+ General = 0,
+ Color,
+ Font,
+ Class
+ };
+
+ /**
+ * Sets up the dialog pages.
+ */
+ void setupPages();
+
+ /**
+ * Sets up the general Diagram Properties Page
+ */
+ void setupDiagramPropertiesPage();
+
+ /**
+ * Sets up the Class page
+ */
+ void setupClassPage();
+
+ /**
+ * Sets up the color page.
+ */
+ void setupColorPage();
+
+ /**
+ * Sets up font page.
+ */
+ void setupFontPage();
+
+ /**
+ * Applys the properties of the given page.
+ */
+ void applyPage( Page page );
+
+ /**
+ * Checks whether the name is unique and sets it if it is.
+ */
+ void checkName();
+
+ /**
+ * The view to represent.
+ */
+ UMLView * m_pView;
+
+ Settings::OptionState m_options;
+
+ KFontChooser * m_pChooser;
+ DiagramPropertiesPage *m_diagramProperties;
+ ClassOptionsPage * m_pOptionsPage;
+ UMLWidgetColorPage * m_pColorPage;
+
+ //GUI widgets
+ QLabel * m_pNameL, * m_pSpinXL, * m_pSpinYL;
+ QLineEdit * m_pNameLE;
+ QGroupBox * m_pDocGB, * m_pValuesGB;
+ QCheckBox * m_pSnapToGridCB, * m_pShowSnapCB;
+ QTextEdit * m_pDocTE;
+ QSpinBox * m_pSnapXSB, * m_pSnapYSB;
+ QSpinBox * m_pLineWidthSB;
+public slots:
+ void slotOk();
+ void slotApply();
+};
+
+#endif
diff --git a/umbrello/umbrello/dialogs/umlwidgetcolorpage.cpp b/umbrello/umbrello/dialogs/umlwidgetcolorpage.cpp
new file mode 100644
index 00000000..e234a8c2
--- /dev/null
+++ b/umbrello/umbrello/dialogs/umlwidgetcolorpage.cpp
@@ -0,0 +1,114 @@
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * copyright (C) 2002-2006 *
+ * Umbrello UML Modeller Authors <uml-devel@uml.sf.net> *
+ ***************************************************************************/
+
+#include "umlwidgetcolorpage.h"
+#include "../optionstate.h"
+#include "../umlview.h"
+#include "../umlwidget.h"
+#include <klocale.h>
+#include <qlayout.h>
+#include <qgroupbox.h>
+#include <qlabel.h>
+#include <qpushbutton.h>
+#include <qcheckbox.h>
+
+#include <kcolorbutton.h>
+
+UMLWidgetColorPage::UMLWidgetColorPage( QWidget *pParent, UMLWidget *pWidget ) : QWidget( pParent )
+{
+ m_pUMLWidget = pWidget;
+ m_options = 0;
+ init();
+ m_pLineColorB->setColor( pWidget->getLineColor() );
+ m_pFillColorB->setColor( pWidget->getFillColour() );
+ m_pUseFillColorCB->setChecked( pWidget -> getUseFillColour() );
+}
+
+UMLWidgetColorPage::UMLWidgetColorPage( QWidget * pParent, Settings::OptionState *options ) : QWidget( pParent )
+{
+ m_options = options;
+ m_pUMLWidget = 0;
+ init();
+ m_pLineColorB->setColor( m_options->uiState.lineColor );
+ m_pFillColorB->setColor( m_options->uiState.fillColor );
+ m_pUseFillColorCB->setChecked( m_options->uiState.useFillColor );
+}
+
+void UMLWidgetColorPage::init()
+{
+ int margin = fontMetrics().height();
+
+ //setup GUI
+ QVBoxLayout * topLayout = new QVBoxLayout( this );
+ topLayout -> setSpacing( 6 );
+
+ m_pColorGB = new QGroupBox( i18n( "Color" ), this );
+ topLayout -> addWidget( m_pColorGB );
+ QGridLayout * colorLayout = new QGridLayout( m_pColorGB, 3, 3 );
+ colorLayout -> setMargin( margin );
+
+ m_pLineColorL = new QLabel( i18n( "&Line:" ), m_pColorGB );
+ colorLayout -> addWidget( m_pLineColorL, 0, 0 );
+
+ m_pLineColorB = new KColorButton( m_pColorGB );
+ colorLayout -> addWidget( m_pLineColorB, 0, 1 );
+ m_pLineColorL->setBuddy(m_pLineColorB);
+
+ m_pLineDefaultB = new QPushButton( i18n( "&Default" ), m_pColorGB) ;
+ colorLayout -> addWidget( m_pLineDefaultB, 0, 2 );
+
+ m_pFillColorL = new QLabel( i18n( "&Fill:" ), m_pColorGB );
+ colorLayout -> addWidget( m_pFillColorL, 1, 0 );
+
+ m_pFillColorB = new KColorButton( m_pColorGB );
+ colorLayout -> addWidget( m_pFillColorB, 1, 1 );
+ m_pFillColorL->setBuddy(m_pFillColorB);
+
+ m_pFillDefaultB = new QPushButton( i18n( "D&efault" ), m_pColorGB );
+ colorLayout -> addWidget( m_pFillDefaultB, 1, 2 );
+
+ m_pUseFillColorCB = new QCheckBox( i18n( "&Use fill" ), m_pColorGB );
+ colorLayout -> setRowStretch( 2, 2 );
+ colorLayout -> addWidget( m_pUseFillColorCB, 2, 0 );
+
+ //connect button signals up
+ connect( m_pLineDefaultB, SIGNAL( clicked() ), this, SLOT( slotLineButtonClicked() )) ;
+ connect( m_pFillDefaultB, SIGNAL( clicked() ), this, SLOT( slotFillButtonClicked() ) );
+}
+
+UMLWidgetColorPage::~UMLWidgetColorPage() {}
+
+void UMLWidgetColorPage::slotLineButtonClicked() {
+ // UMLView * pView = dynamic_cast<UMLView *>( m_pUMLWidget -> parent() );
+ m_pLineColorB -> setColor( Settings::getOptionState().uiState.lineColor );
+}
+
+void UMLWidgetColorPage::slotFillButtonClicked() {
+ // UMLView * pView = dynamic_cast<UMLView *>( m_pUMLWidget -> parent() );
+ m_pFillColorB -> setColor( Settings::getOptionState().uiState.fillColor );
+}
+
+void UMLWidgetColorPage::updateUMLWidget() {
+ if(m_pUMLWidget)
+ {
+ m_pUMLWidget->setUseFillColour( m_pUseFillColorCB -> isChecked() );
+ m_pUMLWidget->setLineColor( m_pLineColorB -> color() );
+ m_pUMLWidget->setFillColour( m_pFillColorB -> color() );
+ }
+ else if(m_options)
+ {
+ m_options->uiState.useFillColor = m_pUseFillColorCB -> isChecked();
+ m_options->uiState.lineColor = m_pLineColorB -> color();
+ m_options->uiState.fillColor = m_pFillColorB -> color();
+ }
+}
+
+#include "umlwidgetcolorpage.moc"
diff --git a/umbrello/umbrello/dialogs/umlwidgetcolorpage.h b/umbrello/umbrello/dialogs/umlwidgetcolorpage.h
new file mode 100644
index 00000000..45826338
--- /dev/null
+++ b/umbrello/umbrello/dialogs/umlwidgetcolorpage.h
@@ -0,0 +1,86 @@
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * copyright (C) 2002-2006 *
+ * Umbrello UML Modeller Authors <uml-devel@uml.sf.net> *
+ ***************************************************************************/
+
+#ifndef UMLWIDGETCOLORPAGE_H
+#define UMLWIDGETCOLORPAGE_H
+
+#include <qwidget.h>
+#include "../optionstate.h"
+
+/**
+ * @author Paul Hensgen
+ * Bugs and comments to uml-devel@lists.sf.net or http://bugs.kde.org
+ */
+class UMLWidget;
+class UMLView;
+class KColorButton;
+class QLabel;
+class QPushButton;
+class QCheckBox;
+class QGroupBox;
+
+class UMLWidgetColorPage : public QWidget {
+ Q_OBJECT
+public:
+
+ /**
+ * Constructor - Observe a UMLWidget
+ */
+ UMLWidgetColorPage( QWidget * pParent, UMLWidget * pWidget );
+
+ /**
+ * Constructor - Observe an OptionState structure
+ */
+ UMLWidgetColorPage( QWidget * pParent, Settings::OptionState *options );
+
+ /**
+ * destructor
+ */
+ virtual ~UMLWidgetColorPage();
+
+ /**
+ * Updates the @ref UMLWidget with the dialog properties.
+ */
+ void updateUMLWidget();
+
+public slots:
+ /**
+ * Sets the default line color when default line button
+ * clicked.
+ */
+ void slotLineButtonClicked();
+
+ /**
+ * Sets the default fill color when default fill button
+ * clicked.
+ */
+ void slotFillButtonClicked();
+
+protected:
+ /**
+ * The widget to set the color for.
+ */
+ UMLWidget * m_pUMLWidget;
+
+ Settings::OptionState *m_options;
+
+ //GUI widgets
+ QGroupBox * m_pColorGB;
+ QLabel * m_pLineColorL, * m_pFillColorL;
+ QCheckBox * m_pUseFillColorCB;
+ QPushButton * m_pLineDefaultB, * m_pFillDefaultB;
+ KColorButton * m_pLineColorB, * m_pFillColorB;
+private:
+ void init();
+
+};
+
+#endif
diff --git a/umbrello/umbrello/docgenerators/Makefile.am b/umbrello/umbrello/docgenerators/Makefile.am
new file mode 100644
index 00000000..47087c4c
--- /dev/null
+++ b/umbrello/umbrello/docgenerators/Makefile.am
@@ -0,0 +1,21 @@
+INCLUDES = -I$(srcdir)/.. -I$(top_srcdir)/umbrello/docgenerators -I../../../umbrello/umbrello $(LIBXML_CFLAGS) $(all_includes)
+METASOURCES = AUTO
+bin_PROGRAMS = umbodoc
+
+AM_LDFLAGS = $(all_libraries)
+umbodoc_COMPILE_FIRST = version.h
+umbodoc_SOURCES = main.cpp
+umbodoc_LDADD = $(LIB_KDECORE) $(LIBXSLT_LIBS) $(LIBXML_LIBS)
+noinst_LTLIBRARIES = libdocgenerators.la
+noinst_HEADERS = docbookgenerator.h version.h
+libdocgenerators_la_SOURCES = docbookgenerator.h docbookgenerator.cpp xhtmlgenerator.cpp
+libdocgenerators_la_LIBADD = $(LIB_KDECORE) $(LIBXSLT_LIBS) $(LIBXML_LIBS)
+
+appdir=$(kde_datadir)/umbrello
+app_DATA = xmi2docbook.xsl docbook2xhtml.xsl xmi.css common.ent
+
+version.h: $(top_srcdir)/umbrello/VERSION
+ printf "#undef UMBRELLO_VERSION\n#define UMBRELLO_VERSION \"`cat $(top_srcdir)/umbrello/VERSION`\"\n" > version.h
+
+CLEANFILES = version.h
+
diff --git a/umbrello/umbrello/docgenerators/common.ent b/umbrello/umbrello/docgenerators/common.ent
new file mode 100644
index 00000000..af88fd38
--- /dev/null
+++ b/umbrello/umbrello/docgenerators/common.ent
@@ -0,0 +1,19 @@
+
+ <!ENTITY title1 "Software Specifications" >
+ <!ENTITY title2 "" >
+ <!ENTITY actor "Actor:">
+ <!ENTITY usecase "Use Cases:">
+ <!ENTITY classes "Classes:">
+ <!ENTITY back "Back">
+ <!ENTITY packagename "Package Name:">
+ <!ENTITY classname "Class Name:">
+ <!ENTITY yes "yes">
+ <!ENTITY no "no">
+ <!ENTITY attributes "Attributes:">
+ <!ENTITY metodes "Methods:">
+ <!ENTITY parameters "Parameters:">
+
+
+
+
+
diff --git a/umbrello/umbrello/docgenerators/docbook2xhtml.xsl b/umbrello/umbrello/docgenerators/docbook2xhtml.xsl
new file mode 100644
index 00000000..8b0e5b11
--- /dev/null
+++ b/umbrello/umbrello/docgenerators/docbook2xhtml.xsl
@@ -0,0 +1,7 @@
+<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
+ version='1.0'>
+ <!--xsl:import href="docbook-xsl-1.70.1/xhtml/docbook.xsl"/-->
+ <xsl:import href="http://docbook.sourceforge.net/release/xsl/snapshot/html/docbook.xsl"/>
+ <xsl:param name="html.stylesheet">xmi.css</xsl:param>
+</xsl:stylesheet>
+
diff --git a/umbrello/umbrello/docgenerators/docbookgenerator.cpp b/umbrello/umbrello/docgenerators/docbookgenerator.cpp
new file mode 100644
index 00000000..9907d6f9
--- /dev/null
+++ b/umbrello/umbrello/docgenerators/docbookgenerator.cpp
@@ -0,0 +1,145 @@
+/***************************************************************************
+ * docbookgenerator.cpp - description *
+ * ------------------- *
+ * copyright : (C) 2006 by Gael de Chalendar (aka Kleag) *
+ * (C) 2006 Umbrello UML Modeller Authors <uml-devel@uml.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. *
+ * *
+ ***************************************************************************/
+
+#include "docbookgenerator.h"
+
+#include <libxml/xmlmemory.h>
+#include <libxml/debugXML.h>
+#include <libxml/HTMLtree.h>
+#include <libxml/xmlIO.h>
+#include <libxml/xinclude.h>
+#include <libxml/catalog.h>
+#include <libxslt/xslt.h>
+#include <libxslt/xsltInternals.h>
+#include <libxslt/transform.h>
+#include <libxslt/xsltutils.h>
+
+#include <kdebug.h>
+#include <klocale.h>
+#include <ktempfile.h>
+#include <kmessagebox.h>
+#include <kio/job.h>
+#include <kstandarddirs.h>
+#include <qfile.h>
+#include <qregexp.h>
+#include <qtextstream.h>
+
+#include "uml.h"
+#include "umldoc.h"
+#include "umlviewimageexportermodel.h"
+
+extern int xmlLoadExtDtdDefaultValue;
+
+DocbookGenerator::DocbookGenerator()
+{
+}
+
+DocbookGenerator::~DocbookGenerator() {}
+
+
+bool DocbookGenerator::generateDocbookForProject()
+{
+ UMLApp *app = UMLApp::app();
+ UMLDoc* umlDoc = app->getDocument();
+ KURL url = umlDoc->URL();
+ QString fileName = url.fileName();
+ fileName.replace(QRegExp(".xmi$"),"");
+ url.setFileName(fileName);
+ kDebug() << "Exporting to directory: " << url << endl;
+ generateDocbookForProjectInto(url);
+ return true;
+}
+
+KIO::Job* DocbookGenerator::generateDocbookForProjectInto(const KURL& destDir)
+{
+ UMLApp* app = UMLApp::app();
+ UMLDoc* umlDoc = app->getDocument();
+
+ // export all views
+ umlDoc->writeToStatusBar(i18n("Exporting all views..."));
+ QStringList errors = UMLViewImageExporterModel().exportAllViews(
+ UMLViewImageExporterModel::mimeTypeToImageType("image/png"),
+ destDir, false);
+ if (!errors.empty())
+ {
+#if KDE_IS_VERSION(3,4,0)
+ KMessageBox::errorList(app, i18n("Some errors happened when exporting the images:"), errors);
+#else
+ QString errorsCaption;
+ for (QStringList::Iterator it = errors.begin(); it != errors.end(); ++it) {
+ errorsCaption += "\n" + *it;
+ }
+ KMessageBox::error(app, i18n("Some errors happened when exporting the images:") + errorsCaption);
+#endif
+ return 0;
+ }
+
+ //write the XMI model in an in-memory char* string
+ QString xmi;
+ QTextOStream xmiStream(&xmi);
+
+ KTempFile tmpfile; // we need this tmp file if we are writing to a remote file
+
+ QFile file;
+ file.setName( tmpfile.name() );
+
+ // lets open the file for writing
+ if( !file.open( IO_WriteOnly ) ) {
+ KMessageBox::error(0, i18n("There was a problem saving file: %1").arg(tmpfile.name()), i18n("Save Error"));
+ return false;
+ }
+ umlDoc->saveToXMI(file); // save the xmi stuff to it
+ file.close();
+ tmpfile.close();
+
+ xsltStylesheetPtr cur = NULL;
+ xmlDocPtr doc, res;
+
+ const char *params[16 + 1];
+ int nbparams = 0;
+ params[nbparams] = NULL;
+
+ QString xsltFile(KGlobal::dirs()->findResource("appdata","xmi2docbook.xsl"));
+
+ xmlSubstituteEntitiesDefault(1);
+ xmlLoadExtDtdDefaultValue = 1;
+ cur = xsltParseStylesheetFile((const xmlChar *)xsltFile.latin1());
+ doc = xmlParseFile((const char*)(tmpfile.name().utf8()));
+ res = xsltApplyStylesheet(cur, doc, params);
+
+ KTempFile tmpDocBook;
+ tmpDocBook.setAutoDelete(false);
+
+ xsltSaveResultToFile(tmpDocBook.fstream(), res, cur);
+ xsltFreeStylesheet(cur);
+ xmlFreeDoc(res);
+ xmlFreeDoc(doc);
+
+ xsltCleanupGlobals();
+ xmlCleanupParser();
+
+ KURL url = umlDoc->URL();
+ QString fileName = url.fileName();
+ fileName.replace(QRegExp(".xmi$"),".docbook");
+ url.setPath(destDir.path());
+ url.addPath(fileName);
+ kDebug() << "Copying result to: " << url << endl;
+ KIO::Job* job = KIO::file_copy(tmpDocBook.file()->name(),url,-1,true,false,false);
+ job->setAutoErrorHandlingEnabled(true);
+
+ return job;
+}
+
+
+#include "docbookgenerator.moc"
diff --git a/umbrello/umbrello/docgenerators/docbookgenerator.h b/umbrello/umbrello/docgenerators/docbookgenerator.h
new file mode 100644
index 00000000..775a7383
--- /dev/null
+++ b/umbrello/umbrello/docgenerators/docbookgenerator.h
@@ -0,0 +1,78 @@
+/***************************************************************************
+ docbookgenerator.h - description
+ -------------------
+ begin : THu Jun 22 2006
+ copyright : (C) 2006 by Gael de Chalendar (aka Kleag)
+ email : kleag@free.fr
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the 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 DOCBOOKGENERATOR_H
+#define DOCBOOKGENERATOR_H
+
+#include <kurl.h>
+#include <qobject.h>
+
+class UMLDoc;
+
+namespace KIO
+{
+ class Job;
+}
+
+/**
+ * class DocbookGenerator is a documentation generator for UML documents.
+ * It uses libxslt to convert the XMI generated by UMLDoc::saveToXMI through
+ * the XSLT file stored in resources.
+ *
+ * @todo Add configure checks for libxml2 and libxslt and use conditional
+ * compilation of this library and its callers
+ * @todo allow to specify the destination and ensure that it works with distant
+ * ones
+ */
+class DocbookGenerator : public QObject
+{
+ Q_OBJECT
+ public:
+
+ /**
+ * Constructor
+ */
+ DocbookGenerator();
+
+ /**
+ * Empty Destructor
+ */
+ virtual ~DocbookGenerator();
+
+ /**
+ * Exports the current model to docbook in a directory named as the model
+ * with the .xmi suffix removed. The docbook file will have the same name
+ * with the .docbook suffix. Figures will be named as the corresponding
+ * diagrams in the GUI
+ * @todo change file naming to avoid paths with spaces or non-ASCII chars
+ * @todo better handling of error conditions
+ * @return true if saving is successful and false otherwise.
+ */
+ bool generateDocbookForProject();
+
+ /**
+ * Exports the current model to docbook in the given directory
+ * @param destDir the directory where the docbook file and the figures will
+ * be written
+ * @todo better handling of error conditions
+ * @return true if saving is successful and false otherwise.
+ */
+ KIO::Job* generateDocbookForProjectInto(const KURL& destDir);
+
+};
+
+#endif // DOCBOOKGENERATOR_H
diff --git a/umbrello/umbrello/docgenerators/main.cpp b/umbrello/umbrello/docgenerators/main.cpp
new file mode 100644
index 00000000..d4b6fc4e
--- /dev/null
+++ b/umbrello/umbrello/docgenerators/main.cpp
@@ -0,0 +1,94 @@
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * copyright (C) 2002-2006 *
+ * Umbrello UML Modeller Authors <uml-devel@uml.sf.net> *
+ ***************************************************************************/
+
+#include <unistd.h>
+
+#include <libxml/xmlmemory.h>
+#include <libxml/debugXML.h>
+#include <libxml/HTMLtree.h>
+#include <libxml/xmlIO.h>
+#include <libxml/DOCBparser.h>
+#include <libxml/xinclude.h>
+#include <libxml/catalog.h>
+#include <libxslt/xslt.h>
+#include <libxslt/xsltInternals.h>
+#include <libxslt/transform.h>
+#include <libxslt/xsltutils.h>
+
+// kde includes
+#include <kaboutdata.h>
+#include <kapplication.h>
+#include <kcmdlineargs.h>
+#include <kconfig.h>
+#include <klocale.h>
+#include <ktip.h>
+#include <kdebug.h>
+#include <kwin.h>
+
+#include "version.h"
+
+extern int xmlLoadExtDtdDefaultValue;
+
+static const char description[] =
+ I18N_NOOP("Umbrello UML Modeller autonomous code generator");
+// INSERT A DESCRIPTION FOR YOUR APPLICATION HERE
+
+
+static KCmdLineOptions options[] =
+{
+ { "+[File]", I18N_NOOP("File to transform"), 0 },
+ { "xslt <url>", I18N_NOOP("The XSLT file to use"), 0},
+ // INSERT YOUR COMMANDLINE OPTIONS HERE
+ KCmdLineLastOption
+};
+
+int main(int argc, char *argv[])
+{
+ xsltStylesheetPtr cur = NULL;
+ xmlDocPtr doc, res;
+
+ const char *params[16 + 1];
+ int nbparams = 0;
+ params[nbparams] = NULL;
+
+ KAboutData aboutData( "umbodoc", I18N_NOOP("Umbrello UML Modeller autonomous code generator"),
+ UMBRELLO_VERSION, description, KAboutData::License_GPL,
+ I18N_NOOP("(c) 2006 Gael de Chalendar (aka Kleag), (c) 2002-2006 Umbrello UML Modeller Authors"), 0,
+ "http://uml.sf.net/");
+ aboutData.addAuthor("Gael de Chalendar (aka Kleag)",0, "kleag@free.fr");
+ aboutData.addAuthor(I18N_NOOP("Umbrello UML Modeller Authors"), 0, "uml-devel@lists.sourceforge.net");
+ KCmdLineArgs::init( argc, argv, &aboutData );
+ KCmdLineArgs::addCmdLineOptions( options ); // Add our own options.
+
+ KCmdLineArgs *args = KCmdLineArgs::parsedArgs();
+
+ QCStringList xsltOpt = args->getOptionList("xslt");
+ if (xsltOpt.size() > 0)
+ {
+ QString xsltFile(xsltOpt.last());
+
+ xmlSubstituteEntitiesDefault(1);
+ xmlLoadExtDtdDefaultValue = 1;
+ cur = xsltParseStylesheetFile((const xmlChar *)xsltFile.latin1());
+ doc = xmlParseFile(args->url( 0 ).url().latin1());
+ res = xsltApplyStylesheet(cur, doc, params);
+ xsltSaveResultToFile(stdout, res, cur);
+
+ xsltFreeStylesheet(cur);
+ xmlFreeDoc(res);
+ xmlFreeDoc(doc);
+
+ xsltCleanupGlobals();
+ xmlCleanupParser();
+ }
+ return(0);
+}
+
diff --git a/umbrello/umbrello/docgenerators/xhtmlgenerator.cpp b/umbrello/umbrello/docgenerators/xhtmlgenerator.cpp
new file mode 100644
index 00000000..5da1ae75
--- /dev/null
+++ b/umbrello/umbrello/docgenerators/xhtmlgenerator.cpp
@@ -0,0 +1,171 @@
+/***************************************************************************
+ * xhtmlgenerator.cpp - description *
+ * ------------------- *
+ * copyright : (C) 2006 by Gael de Chalendar (aka Kleag) *
+ * (C) 2006 Umbrello UML Modeller Authors <uml-devel@uml.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. *
+ * *
+ ***************************************************************************/
+
+#include "xhtmlgenerator.h"
+
+#include <libxml/xmlmemory.h>
+#include <libxml/debugXML.h>
+#include <libxml/HTMLtree.h>
+#include <libxml/xmlIO.h>
+#include <libxml/xinclude.h>
+#include <libxml/catalog.h>
+#include <libxslt/xslt.h>
+#include <libxslt/xsltInternals.h>
+#include <libxslt/transform.h>
+#include <libxslt/xsltutils.h>
+
+#include <kdebug.h>
+#include <klocale.h>
+#include <ktempfile.h>
+#include <kmessagebox.h>
+#include <kio/job.h>
+#include <kstandarddirs.h>
+#include <qfile.h>
+#include <qregexp.h>
+#include <qtextstream.h>
+
+#include "uml.h"
+#include "umldoc.h"
+#include "umlviewimageexportermodel.h"
+#include "docbookgenerator.h"
+
+extern int xmlLoadExtDtdDefaultValue;
+
+XhtmlGenerator::XhtmlGenerator()
+{
+}
+
+XhtmlGenerator::~XhtmlGenerator() {}
+
+
+bool XhtmlGenerator::generateXhtmlForProject()
+{
+ UMLApp *app = UMLApp::app();
+ UMLDoc* umlDoc = app->getDocument();
+ KURL url = umlDoc->URL();
+ QString fileName = url.fileName();
+ fileName.replace(QRegExp(".xmi$"),"");
+ url.setFileName(fileName);
+ kDebug() << "Exporting to directory: " << url << endl;
+ return generateXhtmlForProjectInto(url);
+}
+
+bool XhtmlGenerator::generateXhtmlForProjectInto(const KURL& destDir)
+{
+ kDebug() << "First convert to docbook" << endl;
+ m_destDir = destDir;
+// KURL url(QString("file://")+m_tmpDir.name());
+ KIO::Job* docbookJob = DocbookGenerator().generateDocbookForProjectInto(destDir);
+ if (docbookJob == 0)
+ {
+ return false;
+ }
+ kDebug() << "Connecting..." << endl;
+ connect(docbookJob, SIGNAL(result( KIO::Job * )), this, SLOT(slotDocbookToXhtml( KIO::Job *)));
+ return true;
+}
+
+void XhtmlGenerator::slotDocbookToXhtml(KIO::Job * docbookJob)
+{
+ kDebug() << "Now convert docbook to html..." << endl;
+ if ( docbookJob->error() )
+ {
+ docbookJob->showErrorDialog( 0L );
+ return;
+ }
+
+ UMLApp* app = UMLApp::app();
+ UMLDoc* umlDoc = app->getDocument();
+
+ const KURL& url = umlDoc->URL();
+ QString docbookName = url.fileName();
+ docbookName.replace(QRegExp(".xmi$"),".docbook");
+// KURL docbookUrl(QString("file://")+m_tmpDir.name());
+ KURL docbookUrl = m_destDir;
+ docbookUrl.addPath(docbookName);
+
+ xsltStylesheetPtr cur = NULL;
+ xmlDocPtr doc, res;
+
+ const char *params[16 + 1];
+ int nbparams = 0;
+ params[nbparams] = NULL;
+
+ QString xsltFileName(KGlobal::dirs()->findResource("appdata","docbook2xhtml.xsl"));
+ kDebug() << "XSLT file is'"<<xsltFileName<<"'" << endl;
+ QFile xsltFile(xsltFileName);
+ xsltFile.open(IO_ReadOnly);
+ QString xslt = xsltFile.readAll();
+ kDebug() << "XSLT is'"<<xslt<<"'" << endl;
+ xsltFile.close();
+
+ QString localXsl = KGlobal::dirs()->findResource("data","ksgmltools2/docbook/xsl/html/docbook.xsl");
+ kDebug() << "Local xsl is'"<<localXsl<<"'" << endl;
+ if (!localXsl.isEmpty())
+ {
+ localXsl = QString("href=\"file://") + localXsl + "\"";
+ xslt.replace(QRegExp("href=\"http://[^\"]*\""),localXsl);
+ }
+ KTempFile tmpXsl;
+ *tmpXsl.textStream() << xslt;
+ tmpXsl.file()->close();
+
+
+ xmlSubstituteEntitiesDefault(1);
+ xmlLoadExtDtdDefaultValue = 1;
+ kDebug() << "Parsing stylesheet " << tmpXsl.name() << endl;
+ cur = xsltParseStylesheetFile((const xmlChar *)tmpXsl.name().latin1());
+ kDebug() << "Parsing file " << docbookUrl.path() << endl;
+ doc = xmlParseFile((const char*)(docbookUrl.path().utf8()));
+ kDebug() << "Applying stylesheet " << endl;
+ res = xsltApplyStylesheet(cur, doc, params);
+
+ KTempFile tmpXhtml;
+ tmpXhtml.setAutoDelete(false);
+
+ kDebug() << "Writing HTML result to temp file: " << tmpXhtml.file()->name() << endl;
+ xsltSaveResultToFile(tmpXhtml.fstream(), res, cur);
+
+ xsltFreeStylesheet(cur);
+ xmlFreeDoc(res);
+ xmlFreeDoc(doc);
+
+ xsltCleanupGlobals();
+ xmlCleanupParser();
+
+ QString xhtmlName = url.fileName();
+ xhtmlName.replace(QRegExp(".xmi$"),".html");
+ KURL xhtmlUrl = m_destDir;
+ xhtmlUrl.addPath(xhtmlName);
+
+ kDebug() << "Copying HTML result to: " << xhtmlUrl << endl;
+ KIO::Job* job = KIO::file_copy(tmpXhtml.file()->name(),xhtmlUrl,-1,true,false,false);
+ job->setAutoErrorHandlingEnabled(true);
+ connect (job, SIGNAL(result( KIO::Job* )), this, SLOT(slotHtmlCopyFinished( KIO::Job* )));
+
+ QString cssFileName(KGlobal::dirs()->findResource("appdata","xmi.css"));
+ kDebug() << "CSS file is'"<<cssFileName<<"'" << endl;
+ KURL cssUrl = m_destDir;
+ cssUrl.addPath("xmi.css");
+ KIO::Job* cssJob = KIO::file_copy(cssFileName,cssUrl,-1,true,false,false);
+ cssJob->setAutoErrorHandlingEnabled(true);
+}
+
+void XhtmlGenerator::slotHtmlCopyFinished( KIO::Job* )
+{
+ kDebug() << "HTML copy finished: emiting finished" << endl;
+ emit(finished());
+}
+
+#include "xhtmlgenerator.moc"
diff --git a/umbrello/umbrello/docgenerators/xhtmlgenerator.h b/umbrello/umbrello/docgenerators/xhtmlgenerator.h
new file mode 100644
index 00000000..46402382
--- /dev/null
+++ b/umbrello/umbrello/docgenerators/xhtmlgenerator.h
@@ -0,0 +1,104 @@
+/***************************************************************************
+ xhtmlgenerator.h - description
+ -------------------
+ begin : Sat Jun 24 2006
+ copyright : (C) 2006 by Gael de Chalendar (aka Kleag)
+ email : kleag@free.fr
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the 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 XHTMLGENERATOR_H
+#define XHTMLGENERATOR_H
+
+#include <kurl.h>
+#include <ktempdir.h>
+#include <qobject.h>
+
+namespace KIO
+{
+ class Job;
+}
+
+/**
+ * class XhtmlGenerator is a documentation generator for UML documents.
+ * It uses first @ref DocbookGenerator to convert the XMI generated by
+ * UMLDoc::saveToXMI to docbook and next libxslt through
+ * the XSLT file stored in resources to convert the docbook file to XHTML.
+ * The latter uses the XSLT available on the Web at
+ * http://docbook.sourceforge.net/release/xsl/snapshot/html/docbook.xsl
+ *
+ * @todo allow to specify the destination and ensure that it works with distant
+ * ones
+ */
+class XhtmlGenerator : public QObject
+{
+ Q_OBJECT
+ public:
+
+ /**
+ * Constructor
+ */
+ XhtmlGenerator();
+
+ /**
+ * Empty Destructor
+ */
+ virtual ~XhtmlGenerator();
+
+ /**
+ * Exports the current model to XHTML in a directory named as the model
+ * with the .xmi suffix removed. The XHTML file will have the same name
+ * with the .html suffix. Figures will be named as the corresponding
+ * diagrams in the GUI
+ * @todo change file naming to avoid paths with spaces or non-ASCII chars
+ * @todo better handling of error conditions
+ * @return true if saving is successful and false otherwise.
+ */
+ bool generateXhtmlForProject();
+
+ /**
+ * Exports the current model to XHTML in the given directory
+ * @param destDir the directory where the XHTML file and the figures will
+ * be written
+ * @todo better handling of error conditions
+ * @return true if saving is successful and false otherwise.
+ */
+ bool generateXhtmlForProjectInto(const KURL& destDir);
+
+ signals:
+
+ /** Emited when the documentation generation is finished */
+ void finished();
+
+ protected slots:
+
+ /** This slot is triggerd when the first part, xmi to docbook, is
+ * finished
+ * @param docbookJob the job copying the docbook file to its destination.
+ * Used only for error reporting
+ */
+ void slotDocbookToXhtml(KIO::Job * docbookJob);
+
+ /** Triggered when the copying of the HTML result file is finished. Emits
+ * the signal finished().
+ */
+ void slotHtmlCopyFinished( KIO::Job* );
+
+ private:
+
+ /** The destination directory where the final documentation will be
+ * written.
+ */
+ KURL m_destDir;
+// KTempDir m_tmpDir;
+};
+
+#endif // XHTMLGENERATOR_H
diff --git a/umbrello/umbrello/docgenerators/xmi.css b/umbrello/umbrello/docgenerators/xmi.css
new file mode 100644
index 00000000..0cb67fea
--- /dev/null
+++ b/umbrello/umbrello/docgenerators/xmi.css
@@ -0,0 +1,170 @@
+h1 {
+ font-family : Verdana, Arial, Helvetica;
+ font-size : 15pt;
+ font-weight : bold;
+ color : #333366;
+}
+
+.class-title {
+ background-color:#9999cc;
+ color : #ffffff;
+ font-family : Verdana, Helvetica;
+ font-size : 12pt;
+ font-weight : bold;
+}
+
+.class-name {
+ background-color:#ffffe0;
+ color : #6633cc;
+ font-family : Verdana, Helvetica;
+ font-size : 12pt;
+ font-weight : bold;
+}
+
+
+.interface-title {
+ background-color:#9999cc;
+ color : #ffffff;
+ font-family : Verdana, Helvetica;
+ font-size : 12pt;
+ font-weight : bold;
+}
+
+.interface-name {
+ background-color:#ffffe0;
+ color : #6633cc;
+ font-family : Verdana, Helvetica;
+ font-size : 12pt;
+ font-weight : bold;
+ font-style : italic;
+}
+
+.info-title {
+ background-color:#f0f0f0;
+ color : #888888;
+ font-family : Verdana, Helvetica;
+ font-size : 11pt;
+ font-weight : bold;
+ text-align : left;
+}
+
+.info {
+ background-color:#f0f0f0;
+ color : #000000;
+ font-family : Verdana, Helvetica;
+ font-size : 10pt;
+ text-align : left;
+}
+
+
+.class-feature {
+ background-color:#f0f0f0;
+ color : #848484;
+ font-family : Verdana, Helvetica;
+ font-size : 12pt;
+ font-weight : bold;
+ text-align : left;
+}
+
+.feature-heading {
+ color : #000099;
+ background-color:#ffffe0;
+ font-family : Verdana, Helvetica;
+ font-weight : bold;
+ font-size : 10pt;
+}
+
+.feature-detail {
+ color : #000000;
+ background-color:#ffffff;
+ font-family : Verdana, Helvetica;
+ font-size : 10pt;
+ text-align : left;
+}
+
+.comment {
+ color : #555555;
+ background-color:#ffffff;
+ font-family : Verdana, Helvetica;
+ font-size : 10pt;
+ text-align : left;
+ font-style : italic;
+}
+
+
+.datatype {
+ color : blue;
+}
+
+a.classifier:link {
+ color : blue;
+}
+
+a.classifier:visited {
+ color : blue;
+}
+
+a.interface:link {
+ color : blue;
+ font-style : italic;
+}
+
+a.interface:visited {
+ color : blue;
+ font-style : italic;
+}
+
+a.index-class:link {
+ font-family : Helvetica;
+ color : blue;
+ text-decoration : none;
+}
+
+a.index-class:visited {
+ font-family : Helvetica;
+ color : blue;
+ text-decoration : none;
+}
+
+a.index-interface:link {
+ color : blue;
+ font-style : italic;
+ text-decoration : none;
+}
+
+a.index-interface:visited {
+ color : blue;
+ font-style : italic;
+ text-decoration : none;
+}
+
+.index-title {
+ color : #000080;
+ font-family : Verdana, Helvetica;
+ font-size : 12pt;
+ font-weight : bold;
+}
+
+.parameter-heading {
+ color : #000099;
+ background-color: #f0f0f0;
+ font-family : Verdana, Helvetica;
+ font-weight : bold;
+ font-size : 10pt;
+}
+
+.property-name {
+ font-family : Verdana, Arial, Helvetica;
+ font-size : 8pt;
+ font-weight : bold;
+ color : Black;
+}
+
+.toc {
+color : #000099;
+background-color: #f0f0f0;
+font-family : Verdana, Helvetica;
+font-weight : normal;
+font-size : 10pt;
+}
+
diff --git a/umbrello/umbrello/docgenerators/xmi2docbook.sh b/umbrello/umbrello/docgenerators/xmi2docbook.sh
new file mode 100644
index 00000000..32f46928
--- /dev/null
+++ b/umbrello/umbrello/docgenerators/xmi2docbook.sh
@@ -0,0 +1,9 @@
+#! /bin/bash
+
+echo Converting from XMI to docbook...
+java -cp /usr/share/java/xalan-j2-2.6.0.jar org.apache.xalan.xslt.Process -xml -in $1.xmi -xsl /home/gael/Logiciels/kde3.5-svn/kdesdk/umbrello.withdocgen/umbrello/docgenerators/xmi2docbook.xsl -out $1.docbook
+
+echo Converting from docbook to XHTML...
+java -cp /usr/share/java/xalan-j2-2.6.0.jar org.apache.xalan.xslt.Process -in $1.docbook -xsl /home/gael/Logiciels/kde3.5-svn/kdesdk/umbrello.withdocgen/umbrello/docgenerators/docbook2xhtml.xsl -out $1.html -html
+
+echo done.
diff --git a/umbrello/umbrello/docgenerators/xmi2docbook.xsl b/umbrello/umbrello/docgenerators/xmi2docbook.xsl
new file mode 100644
index 00000000..ff10aac5
--- /dev/null
+++ b/umbrello/umbrello/docgenerators/xmi2docbook.xsl
@@ -0,0 +1,998 @@
+<?xml version="1.0"?>
+<!DOCTYPE article PUBLIC "-//OASIS//DTD Simplified DocBook XML V4.1.2.5//EN"
+ "http://www.oasis-open.org/docbook/xml/simple/4.1.2.5/sdocbook.dtd"
+ [ <!ENTITY % common SYSTEM "common.ent" > %common;] >
+
+<!--
+ Title: umbrello-xmi-to-html.xsl
+ Purpose: An XSL stylesheet for converting Umbrello 1.4 XMI to HTML.
+ Based on xmi-to-html.xsl from Objects by Design.
+
+ Copyright (C) 1999-2001, Objects by Design, Inc. All Rights Reserved.
+ Copyright (C) 2005, Oliver M. Kellogg <okellogg@users.sourceforge.net>
+ Copyright (C) 2006, Gaël de Chalendar (Kleag) <kleag@free.fr>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation. A copy of the license may be found at
+ http://www.gnu.org/licenses/gpl.html
+
+ Version: June, 16 2006
+
+ xmlns="http://www.w3.org/1999/xhtml"
+-->
+
+<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
+ version="1.0"
+ xmlns:UML="http://schema.omg.org/spec/UML/1.3"
+ exclude-result-prefixes="UML">
+
+<xsl:output method="xml" indent="yes"
+ doctype-system="http://www.oasis-open.org/docbook/xml/simple/4.1.2.5/sdocbook.dtd"
+ doctype-public="-//OASIS//DTD Simplified DocBook XML V4.1.2.5//EN" />
+
+<xsl:key
+ name="classifier"
+ match="//UML:Class"
+ use="@xmi.id"/>
+
+<xsl:key
+ name="generalization"
+ match="//UML:Generalization"
+ use="@xmi.id"/>
+
+<xsl:key
+ name="abstraction"
+ match="//UML:Abstraction"
+ use="@xmi.id"/>
+
+<xsl:key
+ name="multiplicity"
+ match="//UML:Multiplicity"
+ use="@xmi.id"/>
+
+
+<!-- Document Root -->
+<xsl:template match="/">
+ <article role="specification">
+ <xsl:apply-templates select="//UML:Model" mode="title"/>
+
+ <!-- Actors -->
+ <section id="actors">
+ <title>Actors</title>
+ <xsl:apply-templates select="//UML:Actor"/>
+ </section>
+
+ <!-- Use Cases -->
+ <section id="usecases">
+ <title>Use Cases</title>
+ <xsl:apply-templates select="//UML:UseCase"/>
+ </section>
+
+ <!-- Interfaces -->
+ <section id="interfaces">
+ <title>Interfaces</title>
+ <xsl:apply-templates select="//UML:Interface"/>
+ </section>
+
+ <!-- Classes -->
+ <section id="classes">
+ <title>Classes</title>
+ <xsl:apply-templates select="//UML:Class"/>
+ </section>
+ <!-- Diagrams -->
+ <section id="diagrams">
+ <title>Diagrams</title>
+ <xsl:apply-templates select="//diagrams/diagram"/>
+ </section>
+ </article>
+
+</xsl:template>
+
+
+<!-- Window Title -->
+<xsl:template match="UML:Model" mode="title">
+ <title>
+ <!-- Name of the model -->
+ <xsl:value-of select="@name"/>
+ </title>
+</xsl:template>
+
+
+<!-- Actor -->
+<xsl:template match="UML:Actor">
+ <xsl:variable name="element_name" select="@name"/>
+ <xsl:variable name="xmi_id" select="@xmi.id" />
+ <xsl:variable name="comment" select="@comment" />
+
+ <section>
+ <title><xsl:value-of select="$element_name"/></title>
+
+ <table frame='all'><title></title>
+ <tgroup cols='3' align='left' colsep='1' rowsep='1'>
+ <colspec colname='c1'/>
+ <colspec colname='c2'/>
+ <colspec colname='c3'/>
+ <thead>
+ <row>
+ <entry role="class-title" >Actor</entry>
+ <entry role="class-name" namest="c2" nameend="c3" ><xsl:value-of select="$element_name"/></entry>
+ </row>
+ </thead>
+ <tbody>
+ <xsl:if test="count($comment) > 0">
+ <row>
+ <entry role="comment" namest="c1" nameend="c3" ><para><xsl:value-of select="$comment"/></para></entry>
+ </row>
+ </xsl:if>
+
+ <xsl:call-template name="specifications"/>
+
+ <xsl:call-template name="realizations"/>
+
+ <xsl:call-template name="supertypes"/>
+
+ <xsl:call-template name="subtypes"/>
+
+ <xsl:call-template name="associations">
+ <xsl:with-param name="source" select="$xmi_id"/>
+ </xsl:call-template>
+
+ </tbody>
+ </tgroup>
+ </table>
+
+ </section>
+</xsl:template>
+
+<!-- Use Case -->
+<xsl:template match="UML:UseCase">
+ <xsl:variable name="element_name" select="@name"/>
+ <xsl:variable name="xmi_id" select="@xmi.id" />
+ <xsl:variable name="comment" select="@comment" />
+
+ <section>
+ <title><xsl:value-of select="$element_name"/></title>
+
+ <table frame='all'><title></title>
+ <tgroup cols='3' align='left' colsep='1' rowsep='1'>
+ <colspec colname='c1'/>
+ <colspec colname='c2'/>
+ <colspec colname='c3'/>
+ <thead>
+ <row>
+ <entry role="class-title" >Use Case</entry>
+ <entry role="class-name" namest="c2" nameend="c3" ><xsl:value-of select="$element_name"/></entry>
+ </row>
+ </thead>
+ <tbody>
+ <xsl:if test="count($comment) > 0">
+ <row>
+ <entry role="comment" namest="c1" nameend="c3" ><para><xsl:value-of select="$comment"/></para></entry>
+ </row>
+ </xsl:if>
+
+ <xsl:call-template name="specifications"/>
+
+ <xsl:call-template name="realizations"/>
+
+ <xsl:call-template name="supertypes"/>
+
+ <xsl:call-template name="subtypes"/>
+
+ <xsl:call-template name="associations">
+ <xsl:with-param name="source" select="$xmi_id"/>
+ </xsl:call-template>
+
+ </tbody>
+ </tgroup>
+ </table>
+
+ </section>
+</xsl:template>
+
+
+<!-- Interface -->
+<xsl:template match="UML:Interface">
+ <xsl:variable name="element_name" select="@name"/>
+ <xsl:variable name="comment" select="@comment" />
+ <xsl:variable name="realizations"
+ select="Foundation.Core.ModelElement.supplierDependency/
+ Foundation.Core.Abstraction"/>
+ <xsl:variable name="generalizations"
+ select="UML:Generalization"/>
+ <xsl:variable name="specializations"
+ select="Foundation.Core.GeneralizableElement.specialization/
+ Foundation.Core.Generalization"/>
+ <xsl:variable name="class_operations"
+ select="UML:Classifier.feature/UML:Operation" />
+ <section>
+ <title><xsl:value-of select="$element_name"/></title>
+ <table frame='all'><title></title>
+ <tgroup cols='3' align='left' colsep='1' rowsep='1'>
+ <colspec colname='c1'/>
+ <colspec colname='c2'/>
+ <colspec colname='c3'/>
+ <thead>
+ <row>
+ <entry role="class-title" >Interface</entry>
+ <entry role="class-name" namest="c2" nameend="c3" ><xsl:value-of select="$element_name"/></entry>
+ </row>
+ </thead>
+ <tbody>
+ <xsl:if test="count($comment) > 0">
+ <row>
+ <entry role="comment" namest="c1" nameend="c3" ><para><xsl:value-of select="$comment"/></para></entry>
+ </row>
+ </xsl:if>
+ <xsl:if test="count($class_operations) = 0">
+ <row>
+ <entry namest="c1" nameend="c3" ><para/></entry>
+ </row>
+ </xsl:if>
+
+ <xsl:if test="count($realizations) = 0
+ and count($generalizations) = 0
+ and count($specializations) = 0
+ and count($class_operations) = 0">
+ </xsl:if>
+ <xsl:call-template name="realizations"/>
+ <xsl:call-template name="supertypes"/>
+ <xsl:call-template name="subtypes"/>
+ <xsl:call-template name="operations"/>
+ </tbody>
+ </tgroup>
+ </table>
+
+ </section>
+</xsl:template>
+
+
+<!-- Class -->
+<xsl:template match="UML:Class">
+ <xsl:variable name="element_name" select="@name"/>
+ <xsl:variable name="xmi_id" select="@xmi.id" />
+ <xsl:variable name="comment" select="@comment" />
+ <xsl:variable name="class_attributes"
+ select="UML:Classifier.feature/UML:Attribute" />
+ <xsl:variable name="class_operations"
+ select="UML:Classifier.feature/UML:Operation" />
+
+ <section>
+ <title><xsl:value-of select="$element_name"/></title>
+
+ <table frame='all'><title></title>
+ <tgroup cols='3' align='left' colsep='1' rowsep='1'>
+ <colspec colname='c1'/>
+ <colspec colname='c2'/>
+ <colspec colname='c3'/>
+ <thead>
+ <row>
+ <entry role="class-title" >Class</entry>
+ <entry role="class-name" namest="c2" nameend="c3" ><xsl:value-of select="$element_name"/></entry>
+ </row>
+ </thead>
+ <tbody>
+ <xsl:if test="count($comment) > 0">
+ <row>
+ <entry role="comment" namest="c1" nameend="c3" ><para><xsl:value-of select="$comment"/></para></entry>
+ </row>
+ </xsl:if>
+ <xsl:if test="count($class_attributes) = 0
+ and count($class_operations) = 0">
+ <row>
+ <entry namest="c1" nameend="c3" ><para/></entry>
+ </row>
+ </xsl:if>
+
+ <xsl:call-template name="specifications"/>
+
+ <xsl:call-template name="realizations"/>
+
+ <xsl:call-template name="supertypes"/>
+
+ <xsl:call-template name="subtypes"/>
+
+ <xsl:call-template name="associations">
+ <xsl:with-param name="source" select="$xmi_id"/>
+ </xsl:call-template>
+
+ <xsl:call-template name="attributes"/>
+
+ <xsl:call-template name="operations"/>
+ </tbody>
+ </tgroup>
+ </table>
+
+ </section>
+</xsl:template>
+
+
+<xsl:template match="diagrams/diagram">
+ <xsl:variable name="xmi_id" select="@xmi.id" />
+ <xsl:comment >diagrambegin<xsl:value-of select="position()"/>namebegin<xsl:value-of select="@name"/>nameend</xsl:comment>
+ <xsl:comment >diagram<xsl:value-of select="position()"/>documentationbegin<xsl:value-of select="@documentation"/>documentationend</xsl:comment>
+
+ <section>
+ <title><xsl:value-of select="@name"/></title>
+ <para>
+ <xsl:value-of select="@documentation"/>
+ </para>
+ <mediaobject>
+ <imageobject>
+ <imagedata format="PNG">
+ <xsl:attribute name="fileref"><xsl:value-of select="@name"/>
+ <xsl:text>.png</xsl:text>
+ </xsl:attribute>
+ </imagedata>
+ </imageobject>
+ </mediaobject>
+ </section>
+ <xsl:if test="widgets/actorwidget">
+ <section>
+ <title>&actor;</title>
+ <xsl:for-each select="widgets/actorwidget">
+ <xsl:call-template name="actor"/>
+ </xsl:for-each>
+ </section>
+ </xsl:if>
+
+ <xsl:if test="widgets/usecasewidget">
+ <section>
+ <title>&usecase;</title>
+ <xsl:for-each select="widgets/usecasewidget">
+ <xsl:call-template name="usecase"/>
+ </xsl:for-each>
+ </section>
+ </xsl:if>
+
+ <xsl:if test="widgets/classwidget">
+ <section>
+ <title>&classes;</title>
+ <para/>
+ <!--xsl:for-each select="widgets/classwidget">
+ <xsl:call-template name="class"/>
+ </xsl:for-each-->
+ </section>
+ </xsl:if>
+
+ <xsl:comment >diagramend<xsl:value-of select="position()"/></xsl:comment>
+</xsl:template>
+
+
+<!-- The following template is designed to be called for Abstractions with the "realize"
+ stereotype, i.e. Realization relationships. It formats the name of the supplier of the
+ Abstraction dependency, i.e. the class or interface specifying the behaviour of the
+ client in the dependency.
+-->
+<!-- Specifications (interface or class) -->
+<xsl:template name="specifications">
+
+ <!-- Abstractions identify specifications -->
+ <xsl:variable name="specifications"
+ select="Foundation.Core.ModelElement.clientDependency/
+ Foundation.Core.Abstraction"/>
+
+ <xsl:if test="count($specifications) > 0">
+ <section>
+ <title>Specifications:</title>
+ <xsl:for-each select="$specifications">
+ <!-- get the supplier in the abstraction -->
+ <xsl:variable name="abstraction"
+ select="key('abstraction', ./@xmi.idref)" />
+ <xsl:variable name="target"
+ select="$abstraction/
+ Foundation.Core.Dependency.supplier/
+ */@xmi.idref" />
+ <xsl:call-template name="classify">
+ <xsl:with-param name="target" select="$target"/>
+ </xsl:call-template>
+
+ <xsl:if test="position() != last()">
+ <xsl:text>, </xsl:text>
+ </xsl:if>
+ </xsl:for-each>
+ </section>
+ </xsl:if>
+
+</xsl:template>
+
+
+<!-- The following template is designed to be called for Abstractions with the "realize"
+ stereotype, i.e. Realization relationships. It formats the name of the client of the
+ Abstraction dependency, i.e. the class realizing the specification defined by the
+ supplier in the dependency.
+-->
+<!-- Realizations (of interface) -->
+<xsl:template name="realizations">
+
+ <!-- Abstractions identify realizations -->
+ <xsl:variable name="realizations"
+ select="Foundation.Core.ModelElement.supplierDependency/
+ Foundation.Core.Abstraction"/>
+
+ <xsl:if test="count($realizations) > 0">
+ <section>
+ <title>Realizations:</title>
+ <xsl:for-each select="$realizations">
+
+ <!-- get the client in the abstraction -->
+ <xsl:variable name="abstraction"
+ select="key('abstraction', ./@xmi.idref)" />
+ <xsl:variable name="target"
+ select="$abstraction/
+ Foundation.Core.Dependency.client/
+ */@xmi.idref" />
+ <xsl:call-template name="classify">
+ <xsl:with-param name="target" select="$target"/>
+ </xsl:call-template>
+
+ <xsl:if test="position() != last()">
+ <xsl:text>, </xsl:text>
+ </xsl:if>
+ </xsl:for-each>
+ </section>
+ </xsl:if>
+
+</xsl:template>
+
+
+
+<!-- Supertypes (inheritance) -->
+<xsl:template name="supertypes">
+
+ <!-- Generalizations identify supertypes -->
+ <xsl:variable name="generalizations"
+ select="UML:Generalization"/>
+
+ <xsl:if test="count($generalizations) > 0">
+ <section>
+ <title>Supertypes:</title>
+ <xsl:for-each select="$generalizations">
+
+ <!-- get the parent in the generalization -->
+ <xsl:variable name="generalization"
+ select="key('generalization', ./@xmi.idref)" />
+ <xsl:variable name="target"
+ select="$generalization/
+ Foundation.Core.Generalization.parent/
+ */@xmi.idref" />
+ <xsl:call-template name="classify">
+ <xsl:with-param name="target" select="$target"/>
+ </xsl:call-template>
+
+ <xsl:if test="position() != last()">
+ <xsl:text>, </xsl:text>
+ </xsl:if>
+ </xsl:for-each>
+ </section>
+ </xsl:if>
+</xsl:template>
+
+
+<!-- Subtypes (inheritance) -->
+<xsl:template name="subtypes">
+
+ <!-- Specializations identify subtypes -->
+ <xsl:variable name="specializations"
+ select="Foundation.Core.GeneralizableElement.specialization/
+ Foundation.Core.Generalization"/>
+
+ <xsl:if test="count($specializations) > 0">
+ <section>
+ <title>Subtypes:</title>
+ <xsl:for-each select="$specializations">
+
+ <!-- get the child in the generalization -->
+ <xsl:variable name="generalization"
+ select="key('generalization', ./@xmi.idref)" />
+ <xsl:variable name="target"
+ select="$generalization/
+ Foundation.Core.Generalization.child/
+ */@xmi.idref" />
+ <xsl:call-template name="classify">
+ <xsl:with-param name="target" select="$target"/>
+ </xsl:call-template>
+
+ <xsl:if test="position() != last()">
+ <xsl:text>, </xsl:text>
+ </xsl:if>
+ </xsl:for-each>
+ </section>
+ </xsl:if>
+</xsl:template>
+
+
+<!-- Associations -->
+<xsl:template name="associations">
+ <xsl:param name="source"/>
+
+ <xsl:variable name="association_ends"
+ select="//UML:AssociationEnd[@type=$source]" />
+
+ <xsl:if test="count($association_ends) > 0">
+ <section>
+ <title>Associations</title>
+ <para>visibility, type, properties.</para>
+
+ <xsl:for-each select="$association_ends">
+ <xsl:for-each select="preceding-sibling::UML:AssociationEnd |
+ following-sibling::UML:AssociationEnd">
+
+ <xsl:call-template name="association_end" />
+
+ </xsl:for-each>
+ </xsl:for-each>
+ </section>
+ </xsl:if>
+</xsl:template>
+
+
+<!-- Association End -->
+<xsl:template name="association_end">
+ <!-- Visibility -->
+ <para>
+ <!--role="feature-detail"-->
+ <xsl:variable name="visibility"
+ select="@visibility" />
+ <xsl:choose>
+ <xsl:when test="string-length($visibility) > 0">
+ <xsl:value-of select="$visibility"/>
+ </xsl:when>
+ <xsl:otherwise>
+ <xsl:text disable-output-escaping="yes">&amp;nbsp;</xsl:text>
+ </xsl:otherwise>
+ </xsl:choose>
+ </para>
+
+ <!-- Type -->
+ <para>
+ <!--role="feature-detail"-->
+ <xsl:variable name="target"
+ select="Foundation.Core.AssociationEnd.type/*/@xmi.idref" />
+
+ <xsl:call-template name="classify">
+ <xsl:with-param name="target" select="$target"/>
+ </xsl:call-template>
+ </para>
+
+ <!-- Properties -->
+ <para>
+ <!--role="feature-detail"-->
+ <!-- Rolename -->
+ <xsl:variable name="rolename" select="@name"/>
+
+ <!--role="property-name"-->
+ Rolename:
+ <xsl:choose>
+ <xsl:when test="string-length($rolename) > 0">
+ <xsl:value-of select="$rolename"/>
+ </xsl:when>
+ <xsl:otherwise>(none)</xsl:otherwise>
+ </xsl:choose>
+ </para>
+
+ <!-- Multiplicity -->
+ <xsl:apply-templates select=".//Foundation.Data_Types.Multiplicity" />
+
+ <!-- Navigable -->
+ <xsl:variable name="navigable"
+ select="Foundation.Core.AssociationEnd.isNavigable/@xmi.value"/>
+ <xsl:if test="string-length($navigable) > 0">
+
+ <para>
+ <!--role="property-name"-->
+ Navigable: <xsl:value-of select="$navigable"/>
+ </para>
+ </xsl:if>
+
+ <!-- Ordering -->
+ <xsl:variable name="ordering"
+ select="Foundation.Core.AssociationEnd.ordering/@xmi.value"/>
+ <xsl:if test="string-length($ordering) > 0">
+ <para>
+ <!--role="property-name"-->
+ Ordering: <xsl:value-of select="$ordering"/>
+ </para>
+ </xsl:if>
+</xsl:template>
+
+
+<!-- Multiplicity (definition) -->
+<xsl:template match="Foundation.Data_Types.Multiplicity[@xmi.id]">
+
+ <para>
+ <!--role="property-name"-->
+ Multiplicity:
+
+ <xsl:variable name="lower"
+ select=".//Foundation.Data_Types.MultiplicityRange.lower"/>
+
+ <xsl:variable name="upper"
+ select=".//Foundation.Data_Types.MultiplicityRange.upper"/>
+
+ <xsl:value-of select="$lower" />
+ <xsl:if test="$upper != $lower">
+ <xsl:text>..</xsl:text>
+ <xsl:value-of select="$upper" />
+ </xsl:if>
+ </para>
+
+</xsl:template>
+
+<!-- Multiplicity (reference) -->
+<xsl:template match="Foundation.Data_Types.Multiplicity[@xmi.idref]">
+ <xsl:apply-templates select="key('multiplicity', @xmi.idref)" />
+</xsl:template>
+
+
+
+<!-- Attributes -->
+<xsl:template name="attributes">
+ <xsl:variable name="class_attributes"
+ select="UML:Classifier.feature/UML:Attribute" />
+ <xsl:if test="count($class_attributes) > 0">
+ <row>
+ <entry role="info-title" namest="c1" nameend="c3" >Attributes:</entry>
+ </row>
+ <row>
+ <entry role="feature-heading">visibility</entry>
+ <entry role="feature-heading">type</entry>
+ <entry role="feature-heading">name</entry>
+ </row>
+ <xsl:apply-templates select="UML:Classifier.feature/
+ UML:Attribute" />
+ </xsl:if>
+</xsl:template>
+
+
+<xsl:template match="UML:Attribute">
+ <xsl:variable name="target"
+ select='@type'/>
+
+
+ <row>
+ <entry role="feature-detail">
+ <xsl:value-of select="@visibility"/>
+ </entry>
+
+ <entry role="feature-detail">
+ <xsl:call-template name="classify">
+ <xsl:with-param name="target" select="$target" />
+ </xsl:call-template>
+ </entry>
+
+ <entry role="feature-detail">
+ <xsl:value-of select="@name"/>
+ </entry>
+ </row>
+
+ <row>
+ <entry role="comment"/>
+ <entry namest="c2" nameend="c3" role="comment"><xsl:value-of select="@comment"/></entry>
+ </row>
+
+</xsl:template>
+
+
+
+<!-- Operations -->
+<xsl:template name="operations">
+ <xsl:variable name="class_operations"
+ select="UML:Classifier.feature/UML:Operation" />
+ <xsl:if test="count($class_operations) > 0">
+ <row>
+ <entry role="info-title" namest="c1" nameend="c3" ><para>Operations:</para></entry>
+ </row>
+ <row>
+ <entry role="feature-heading" ><para>visibility</para></entry>
+ <entry role="feature-heading" ><para>return</para></entry>
+ <entry role="feature-heading" ><para>name</para></entry>
+ </row>
+
+ <xsl:apply-templates select="UML:Classifier.feature/
+ UML:Operation" />
+ </xsl:if>
+</xsl:template>
+
+
+<xsl:template match="UML:Operation">
+
+ <xsl:variable name="parameters"
+ select="UML:BehavioralFeature.parameter/
+ UML:Parameter[@kind!='return']" />
+
+ <xsl:variable name="return"
+ select="UML:BehavioralFeature.parameter/
+ UML:Parameter[@kind='return']" />
+
+ <xsl:variable name="target"
+ select="$return/@type" />
+
+ <row>
+ <entry role="feature-detail">
+ <xsl:value-of select="@visibility" />
+ </entry>
+
+ <entry role="feature-detail">
+
+ <xsl:choose>
+ <xsl:when test="string-length($target) = 0">
+ <para role="datatype"><xsl:text>void</xsl:text></para>
+ </xsl:when>
+
+ <xsl:otherwise>
+ <xsl:call-template name="classify">
+ <xsl:with-param name="target" select="$target" />
+ </xsl:call-template>
+ </xsl:otherwise>
+ </xsl:choose>
+
+ </entry>
+
+ <entry role="feature-detail">
+ <xsl:value-of select="@name"/>
+ </entry>
+
+
+ </row>
+
+ <row>
+ <entry role="comment"/>
+ <entry namest="c2" nameend="c3" role="comment"><xsl:value-of select="@comment"/></entry>
+ </row>
+
+ <xsl:variable name="parameter-count" select="count($parameters)" />
+
+ <xsl:if test="not(normalize-space($parameter-count)='0')">
+
+ <row>
+ <entry role="feature-detail" >
+ <xsl:text disable-output-escaping="yes">&amp;nbsp;</xsl:text>
+ </entry>
+
+ <entry role="parameter-heading" valign="top">parameters:</entry>
+ <entry bgcolor="#ffffff" align="right">
+ <!--table width="85%" align="right" cellpadding="0" cellspacing="0" border="0">
+ <xsl:apply-templates select="$parameters" />
+ </table-->
+ </entry>
+ </row>
+
+ </xsl:if >
+
+</xsl:template>
+
+
+
+<!-- Parameter -->
+<xsl:template match="UML:Parameter">
+ <xsl:variable name="target"
+ select="@type" />
+
+ <row>
+ <entry role="feature-detail" width="45%">
+ <xsl:call-template name="classify">
+ <xsl:with-param name="target" select="$target" />
+ </xsl:call-template>
+ </entry>
+
+ <entry role="feature-detail" width="55%">
+ <xsl:value-of select="@name"/>
+ </entry>
+ </row>
+</xsl:template>
+
+
+<!-- Classification -->
+<xsl:template name="classify">
+ <xsl:param name="target"/>
+
+ <xsl:variable name="classifier"
+ select="key('classifier', $target)" />
+
+ <xsl:variable name="classifier_name"
+ select="$classifier/@name" />
+
+ <xsl:variable name="type" select="name($classifier)" />
+
+ <!-- Get the type of the classifier (class, interface, datatype) -->
+ <xsl:variable name="classifier_type">
+ <xsl:choose>
+ <xsl:when test="$type='UML:Class'">classifier</xsl:when>
+ <xsl:when test="$type='UML:Interface'">interface</xsl:when>
+ <xsl:when test="$type='UML:DataType'">datatype</xsl:when>
+ <xsl:otherwise>classifier</xsl:otherwise>
+ </xsl:choose>
+ </xsl:variable>
+
+ <xsl:choose>
+ <!-- Datatypes don't have hyperlinks -->
+ <xsl:when test="$type='UML:DataType'">
+ <span role="datatype">
+ <xsl:value-of select="$classifier_name"/>
+ </span>
+ </xsl:when>
+
+ <!-- Classes and Interfaces have hyperlinks -->
+ <!-- The classifier type is used to style appropriately -->
+ <xsl:otherwise>
+ <xsl:if test="string-length($classifier) > 0">
+ <!--a role={$classifier_type}" href="#{$classifier_name}"-->
+ <xsl:value-of select="$classifier_name"/>
+ <!--/a-->
+ </xsl:if>
+ </xsl:otherwise>
+ </xsl:choose>
+
+</xsl:template>
+
+<!--xsl:template match="XMI.content">
+
+ <xsl:comment >maintitlebegin1&title1;maintitleend1</xsl:comment>
+ <xsl:comment >maintitlebegin2&title2;maintitleend2</xsl:comment>
+ <xsl:apply-templates select="diagrams/diagram"/>
+</xsl:template-->
+
+
+ <xsl:template name="actor">
+ <xsl:param name = "idvalue"><xsl:value-of select="@xmi.id"/></xsl:param>
+ <!--td valign="top"-->
+ <para>
+ <!--role="push"-->
+ <xsl:for-each select="//XMI.content/umlobjects/UML:Actor">
+ <xsl:if test="@xmi.id = $idvalue">
+ <emphasis><xsl:value-of select="@name"/>:</emphasis>
+ <xsl:value-of select="@documentation"/>
+ </xsl:if>
+ </xsl:for-each >
+ </para>
+ <!--/td-->
+ </xsl:template>
+
+ <xsl:template name="usecase">
+ <xsl:param name = "idvalue"><xsl:value-of select="@xmi.id"/></xsl:param>
+ <!--td valign="top"-->
+ <para>
+ <!--role="push"-->
+ <xsl:for-each select="//XMI.content/umlobjects/UML:UseCase">
+ <xsl:if test="@xmi.id = $idvalue">
+ <emphasis><xsl:value-of select="@name"/>:</emphasis>
+ <xsl:value-of select="@documentation"/>
+
+ </xsl:if>
+ </xsl:for-each >
+ </para>
+ <!--/td-->
+ </xsl:template>
+
+ <xsl:template name="class">
+ <xsl:param name = "idvalue"><xsl:value-of select="@xmi.id"/></xsl:param>
+ <!--td valign="top"-->
+ <div role="push">
+ <xsl:for-each select="//XMI.content/umlobjects/UML:Class">
+ <xsl:if test="@xmi.id = $idvalue">
+ <div role="boldtext">&packagename;<xsl:value-of select="@package"/></div>
+ <div role="boldtext">&classname;<xsl:value-of select="@name"/></div>
+ <xsl:value-of select="@documentation"/>
+ <div role="push">
+
+ Stereotype: <xsl:value-of select="@stereotype"/>
+
+ Abstarct:
+ <xsl:if test="@abstract='1'">
+ <xsl:text>&yes;</xsl:text>
+ </xsl:if>
+ <xsl:if test="@abstract='0'">
+ <xsl:text>&no;</xsl:text>
+ </xsl:if>
+
+ Visibility:
+ <xsl:if test="@scope='200'">
+ <xsl:text>public</xsl:text>
+ </xsl:if>
+ <xsl:if test="@scope='201'">
+ <xsl:text>private</xsl:text>
+ </xsl:if>
+ <xsl:if test="@scope='202'">
+ <xsl:text>protected</xsl:text>
+ </xsl:if>
+
+ <xsl:call-template name="attribute"/>
+ <xsl:call-template name="operation"/>
+ </div>
+ </xsl:if>
+ </xsl:for-each >
+ </div>
+ <!--/td-->
+ </xsl:template>
+
+
+ <xsl:template name="attribute">
+ <!--td valign="top"-->
+ <div role="boldtext">&attributes;</div>
+
+ <xsl:for-each select="UML:Attribute">
+ <xsl:value-of select="@name"/><xsl:text> - </xsl:text><xsl:value-of select="@type"/>
+ Static:
+ <xsl:if test="@static='1'">
+ <xsl:text>&yes;</xsl:text>
+ </xsl:if>
+ <xsl:if test="@static='0'">
+ <xsl:text>&no;</xsl:text>
+ </xsl:if>
+
+ Visibility:
+ <xsl:if test="@scope='200'">
+ <xsl:text>public</xsl:text>
+ </xsl:if>
+ <xsl:if test="@scope='201'">
+ <xsl:text>private</xsl:text>
+ </xsl:if>
+ <xsl:if test="@scope='202'">
+ <xsl:text>protected</xsl:text>
+ </xsl:if>
+
+ Default �t�: <xsl:value-of select="@value"/>
+
+ <xsl:value-of select="@documentation"/>
+
+ </xsl:for-each >
+ <!--/td-->
+ </xsl:template>
+
+ <xsl:template name="operation">
+ <entry valign="top">
+ <div role="boldtext">&metodes;</div>
+
+ <xsl:for-each select="UML:Operation">
+ <i>
+ <xsl:if test="@abstract='1'">
+ <xsl:text>abstract </xsl:text>
+ </xsl:if>
+ <xsl:if test="@scope='200'">
+ <xsl:text>public </xsl:text>
+ </xsl:if>
+ <xsl:if test="@scope='201'">
+ <xsl:text>private </xsl:text>
+ </xsl:if>
+ <xsl:if test="@scope='202'">
+ <xsl:text>protected </xsl:text>
+ </xsl:if>
+
+ <xsl:value-of select="@type"/><xsl:text> </xsl:text>
+
+ <xsl:value-of select="@name"/><xsl:text>(</xsl:text>
+
+ <xsl:apply-templates select="UML:Parameter" mode="diagram"/>
+ <xsl:text>)</xsl:text>
+
+ </i>
+ <xsl:value-of select="@documentation"/>
+ &parameters;
+ <xsl:for-each select="UML:Parameter">
+ <div role="push">
+ <xsl:value-of select="@type"/>
+ <xsl:text> </xsl:text>
+ <xsl:value-of select="@name"/>
+
+ <xsl:value-of select="@documentation"/>
+
+ </div>
+ </xsl:for-each>
+
+ </xsl:for-each >
+ </entry>
+ </xsl:template>
+
+ <xsl:template match="UML:Parameter" mode="diagram">
+
+ <xsl:value-of select="@type"/>
+ <xsl:text> </xsl:text>
+ <xsl:value-of select="@name"/>
+ <xsl:if test="position()!=last()">
+ <xsl:text>, </xsl:text>
+ </xsl:if>
+
+ </xsl:template>
+</xsl:stylesheet>
diff --git a/umbrello/umbrello/docwindow.cpp b/umbrello/umbrello/docwindow.cpp
new file mode 100644
index 00000000..d92c13f4
--- /dev/null
+++ b/umbrello/umbrello/docwindow.cpp
@@ -0,0 +1,223 @@
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * copyright (C) 2002-2007 *
+ * Umbrello UML Modeller Authors <uml-devel@uml.sf.net> *
+ ***************************************************************************/
+
+// own header
+#include "docwindow.h"
+
+// qt/kde includes
+#include <qgroupbox.h>
+#include <qlayout.h>
+#include <qmultilineedit.h>
+#include <klocale.h>
+
+// local includes
+#include "associationwidget.h"
+#include "umldoc.h"
+#include "umlobject.h"
+#include "umlview.h"
+#include "umlwidget.h"
+
+
+DocWindow::DocWindow( UMLDoc * doc, QWidget *parent, const char *name ) : QWidget( parent, name ) {
+ //setup visual display
+ QHBoxLayout * mainLayout = new QHBoxLayout( this );
+
+ m_pDocGB = new QGroupBox( i18n( "Documentation" ), this );
+ mainLayout -> addWidget( m_pDocGB );
+
+ QHBoxLayout * docLayout = new QHBoxLayout( m_pDocGB );
+ m_pDocMLE = new QMultiLineEdit( m_pDocGB );
+ m_pDocMLE -> setText( "" );
+ docLayout -> setMargin( fontMetrics().height() );
+ docLayout -> addWidget( m_pDocMLE);
+ m_pDocMLE -> setWordWrap(QMultiLineEdit::WidgetWidth);
+
+ //setup the documentation variables
+ //show projects documentation to start
+ m_pUMLDoc = doc;
+ m_Showing = st_Project;
+ m_pUMLObject = 0;
+ m_pUMLView = 0;
+ m_pUMLWidget = 0;
+ m_pAssocWidget = 0;
+ updateDocumentation( true, true );
+}
+
+DocWindow::~DocWindow() {}
+
+void DocWindow::showDocumentation( UMLObject * object, bool overwrite ) {
+ if( object == m_pUMLObject && !overwrite )
+ return;
+ if( object != m_pUMLObject )
+ updateDocumentation( true );
+
+ m_Showing = st_UMLObject;
+ if( !object ) {
+ m_pDocMLE->setText( m_pUMLDoc->getDocumentation() );
+ m_pUMLObject = 0;
+ return;
+ }
+ m_pUMLObject = object;
+ m_pDocMLE -> setText( m_pUMLObject -> getDoc() );
+}
+
+void DocWindow::updateDocumentation( bool clear, bool startup ) {
+
+ bool mark_modified = false;
+ if( m_pUMLObject )
+ {
+ // the file is marked modified, if the documentation differs
+ // we don't do this on startup/load of a xmi file, because every time
+ // modified is set, we get another undo/redo backup point
+ if ( startup == false && m_pDocMLE -> text() != m_pUMLObject -> getDoc() )
+ {
+ mark_modified = true;
+ }
+ m_pUMLObject -> setDoc( m_pDocMLE -> text() );
+
+ } else if( m_pUMLView ) {
+ // the file is marked modified, if the documentation differs
+ // we don't do this on startup/load of a xmi file, because every time
+ // modified is set, we get another undo/redo backup point
+ if ( startup == false && m_pDocMLE -> text() != m_pUMLView -> getDoc() )
+ {
+ mark_modified = true;
+ }
+
+ m_pUMLView -> setDoc( m_pDocMLE -> text() );
+ } else if ( m_pUMLWidget ) {
+ // the file is marked modified, if the documentation differs
+ // we don't do this on startup/load of a xmi file, because every time
+ // modified is set, we get another undo/redo backup point
+ if ( startup == false && m_pDocMLE -> text() != m_pUMLWidget -> getDoc() )
+ {
+ mark_modified = true;
+ }
+
+ m_pUMLWidget -> setDoc( m_pDocMLE -> text() );
+ } else if( m_pAssocWidget ) {
+ // the file is marked modified, if the documentation differs
+ // we don't do this on startup/load of a xmi file, because every time
+ // modified is set, we get another undo/redo backup point
+ if ( startup == false && m_pDocMLE -> text() != m_pAssocWidget -> getDoc() )
+ {
+ mark_modified = true;
+ }
+
+ m_pAssocWidget -> setDoc( m_pDocMLE -> text() );
+ } else {
+ // the file is marked modified, if the documentation differs
+ // we don't do this on startup/load of a xmi file, because every time
+ // modified is set, we get another undo/redo backup point
+ if ( startup == false && m_pDocMLE -> text() != m_pUMLDoc->getDocumentation() )
+ {
+ mark_modified = true;
+ }
+
+ m_pUMLDoc->setDocumentation( m_pDocMLE->text() );
+ }
+
+ // now do the setModified call
+ if (mark_modified == true)
+ m_pUMLDoc -> setModified( true );
+
+ // we should show the documentation of the whole project
+ if( clear ) {
+ m_pDocMLE->setText( m_pUMLDoc->getDocumentation() );
+ m_pUMLObject = 0;
+ m_pUMLView = 0;
+ m_pUMLWidget = 0;
+ m_pAssocWidget = 0;
+ m_Showing = st_Project;
+ }
+
+ return;
+}
+
+void DocWindow::showDocumentation( UMLView * view, bool overwrite ) {
+ if( view == m_pUMLView && !overwrite )
+ return;
+ if( view != m_pUMLView )
+ updateDocumentation( true );
+ m_Showing = st_UMLView;
+ if( !view ) {
+ m_pDocMLE->setText( m_pUMLDoc->getDocumentation() );
+ m_pUMLView = 0;
+ return;
+ }
+ m_pUMLView = view;
+ m_pDocMLE -> setText( m_pUMLView -> getDoc() );
+}
+
+void DocWindow::showDocumentation( UMLWidget * widget, bool overwrite ) {
+ if( widget == m_pUMLWidget && !overwrite )
+ return;
+ if( widget != m_pUMLWidget )
+ updateDocumentation( true );
+ m_Showing = st_UMLWidget;
+ if( !widget ) {
+ m_pDocMLE->setText( m_pUMLDoc->getDocumentation() );
+ m_pUMLWidget = 0;
+ return;
+ }
+ m_pUMLWidget = widget;
+ m_pDocMLE -> setText( m_pUMLWidget -> getDoc() );
+}
+
+void DocWindow::showDocumentation( AssociationWidget * widget, bool overwrite ) {
+ if( widget == m_pAssocWidget && !overwrite )
+ return;
+ if( widget != m_pAssocWidget )
+ updateDocumentation( true );
+ m_Showing = st_Association;
+ if( !widget ) {
+ m_pDocMLE->setText( m_pUMLDoc->getDocumentation() );
+ m_pAssocWidget = 0;
+ return;
+ }
+ m_pAssocWidget = widget;
+ m_pDocMLE -> setText( m_pAssocWidget -> getDoc() );
+}
+
+void DocWindow::newDocumentation( ) {
+ m_pUMLView = 0;
+ m_pUMLObject = 0;
+ m_pUMLWidget = 0;
+ m_pAssocWidget = 0;
+ m_Showing = st_Project;
+ m_pDocMLE->setText( m_pUMLDoc->getDocumentation() );
+}
+
+bool DocWindow::isTyping()
+{
+ if (m_pDocMLE->hasFocus())
+ return true;
+ else
+ return false;
+}
+
+void DocWindow::slotAssociationRemoved(AssociationWidget* association) {
+ if (association == m_pAssocWidget || association->getUMLObject() == m_pUMLObject) {
+ // In old code, the below line crashed (bugs.kde.org/89860)
+ // A hotfix was made and detailed analysis was To Be Done:
+ // newDocumentation()
+ // However, it seems to have been fixed and the below line seems to work fine
+ updateDocumentation(true);
+ }
+}
+
+void DocWindow::slotWidgetRemoved(UMLWidget* widget) {
+ if (widget == m_pUMLWidget || widget->getUMLObject() == m_pUMLObject) {
+ updateDocumentation(true);
+ }
+}
+
+#include "docwindow.moc"
diff --git a/umbrello/umbrello/docwindow.h b/umbrello/umbrello/docwindow.h
new file mode 100644
index 00000000..fb488c5f
--- /dev/null
+++ b/umbrello/umbrello/docwindow.h
@@ -0,0 +1,168 @@
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * copyright (C) 2002-2006 *
+ * Umbrello UML Modeller Authors <uml-devel@uml.sf.net> *
+ ***************************************************************************/
+
+#ifndef DOCWINDOW_H
+#define DOCWINDOW_H
+
+#include <qwidget.h>
+
+class AssociationWidget;
+class QGroupBox;
+class QMultiLineEdit;
+class UMLObject;
+class UMLDoc;
+class UMLView;
+class UMLWidget;
+
+/**
+ * @author Paul Hensgen
+ * Bugs and comments to uml-devel@lists.sf.net or http://bugs.kde.org
+ */
+
+class DocWindow : public QWidget {
+ Q_OBJECT
+public:
+ /**
+ * Constructor
+ */
+ explicit DocWindow( UMLDoc * doc, QWidget *parent = 0, const char *name = 0 );
+
+ /**
+ * Deconstructor
+ */
+ ~DocWindow();
+
+ /**
+ * Called when a widget wishes to display its documentation in the
+ * doc window. If there was already documentation there, that will
+ * be updated before being removed from the view.
+ *
+ * Also call this function if you update the documentation in another
+ * place, such as a properties dialog. Just set overwrite to true.
+ *
+ * Overwrite is used when you believe that the documentation window
+ * is already displaying documentation for the widget you wish to
+ * display.
+ * Overwrite just determines whose version is more up to date.
+ */
+ void showDocumentation( UMLObject * object, bool overwrite = false );
+
+ /**
+ * This method is the same as the one for UMLObjects except it
+ * displays documentation for a diagram.
+ */
+ void showDocumentation( UMLView * view, bool overwrite = false );
+
+ /**
+ * This method is the same as the one for UMLObjects except it
+ * displays documentation for an object instance (StateWidget/
+ * ObjectWidget).
+ */
+ void showDocumentation( UMLWidget * widget, bool overwrite = false );
+
+ /**
+ * This method is the same as the one for UMLObjects except it
+ * displays documentation for an association instance
+ * (AssociationWidget).
+ */
+ void showDocumentation( AssociationWidget * widget, bool overwrite = false );
+
+ /**
+ * Call when you wish move changes in the doc window back into the
+ * members documentation.
+ *
+ * If clear is true the doc window will display the documentation
+ * for the current project instead of the widget documentation.
+ *
+ * This is usually called before displaying a properties dialog.
+ *
+ * @param clear If true, show the documentation of current project
+ * @param startup If true, no setModified(true) calls will be done and nothing is pushed to the undo stack
+ */
+ void updateDocumentation( bool clear = false, bool startup = false );
+
+
+ /**
+ * Re-initializes the class for a new document.
+ */
+ void newDocumentation( );
+
+ /**
+ * Checks if the user is typing in the documentation edit window
+ */
+ bool isTyping();
+
+public slots:
+
+ /**
+ * An association was removed from the UMLView.
+ * If the association removed was the association which documentation is
+ * being shown, m_pAssocWidget is set to 0.
+ */
+ void slotAssociationRemoved(AssociationWidget* association);
+
+ /**
+ * A widget was removed from the UMLView.
+ * If the association removed was the association which documentation is
+ * being shown, m_pUMLWidget is set to 0.
+ */
+ void slotWidgetRemoved(UMLWidget* widget);
+
+private:
+ /**
+ * Used internally to know which type of object we are showing
+ * documentation for.
+ */
+ enum Showing_Type {
+ st_Project,
+ st_UMLView,
+ st_UMLObject,
+ st_UMLWidget,
+ st_Association
+ };
+
+ /**
+ * A pointer to the UMLObject we are going to show documentation.
+ */
+ UMLObject * m_pUMLObject;
+
+ /**
+ * A pointer to the UMLView we are going to show documentation.
+ */
+ UMLView * m_pUMLView;
+
+ /**
+ * A pointer to the Project we are going to show documentation.
+ */
+ UMLDoc * m_pUMLDoc;
+
+ /**
+ * A pointer to the UMLWidget we are going to show documentation.
+ */
+ UMLWidget * m_pUMLWidget;
+
+ /**
+ * A pointer to the association we are going to show documentation.
+ */
+ AssociationWidget * m_pAssocWidget;
+
+ /**
+ * Which type of documentation we are showing.
+ */
+ Showing_Type m_Showing;
+
+ //visual widgets
+ QMultiLineEdit * m_pDocMLE;
+ QGroupBox * m_pDocGB;
+
+};
+
+#endif
diff --git a/umbrello/umbrello/entity.cpp b/umbrello/umbrello/entity.cpp
new file mode 100644
index 00000000..b3d842ac
--- /dev/null
+++ b/umbrello/umbrello/entity.cpp
@@ -0,0 +1,217 @@
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * copyright (C) 2003-2007 *
+ * Umbrello UML Modeller Authors <uml-devel@uml.sf.net> *
+ ***************************************************************************/
+
+// own header
+#include "entity.h"
+// qt/kde includes
+#include <kdebug.h>
+#include <klocale.h>
+#include <kmessagebox.h>
+// app includes
+#include "entityattribute.h"
+#include "umldoc.h"
+#include "uml.h"
+#include "uniqueid.h"
+#include "clipboard/idchangelog.h"
+#include "dialogs/umlentityattributedialog.h"
+
+UMLEntity::UMLEntity(const QString& name, Uml::IDType id) : UMLClassifier(name, id) {
+ init();
+}
+
+UMLEntity::~UMLEntity() {
+ m_List.clear();
+}
+
+bool UMLEntity::operator==( UMLEntity& rhs ) {
+ return UMLClassifier::operator==(rhs);
+}
+
+void UMLEntity::copyInto(UMLEntity *rhs) const
+{
+ UMLClassifier::copyInto(rhs);
+}
+
+UMLObject* UMLEntity::clone() const
+{
+ UMLEntity* clone = new UMLEntity();
+ copyInto(clone);
+
+ return clone;
+}
+
+void UMLEntity::init() {
+ m_BaseType = Uml::ot_Entity;
+}
+
+UMLAttribute* UMLEntity::createAttribute(const QString &name /*=null*/, UMLObject *type /*=NULL*/) {
+ Uml::IDType id = UniqueID::gen();
+ QString currentName;
+ if (name.isNull()) {
+ currentName = uniqChildName(Uml::ot_EntityAttribute);
+ } else {
+ currentName = name;
+ }
+ const Settings::OptionState optionState = Settings::getOptionState();
+ Uml::Visibility scope = optionState.classState.defaultAttributeScope;
+ UMLEntityAttribute* newAttribute = new UMLEntityAttribute(this, currentName, id, scope, type);
+
+ int button = QDialog::Accepted;
+ bool goodName = false;
+
+ //check for name.isNull() stops dialog being shown
+ //when creating attribute via list view
+ while (button==QDialog::Accepted && !goodName && name.isNull()) {
+ UMLEntityAttributeDialog attributedialog(0, newAttribute);
+ button = attributedialog.exec();
+ QString name = newAttribute->getName();
+
+ if(name.length() == 0) {
+ KMessageBox::error(0, i18n("That is an invalid name."), i18n("Invalid Name"));
+ } else if ( findChildObject(name) != NULL ) {
+ KMessageBox::error(0, i18n("That name is already being used."), i18n("Not a Unique Name"));
+ } else {
+ goodName = true;
+ }
+ }
+
+ if (button != QDialog::Accepted) {
+ delete newAttribute;
+ return NULL;
+ }
+
+ addEntityAttribute(newAttribute);
+
+ UMLDoc *umldoc = UMLApp::app()->getDocument();
+ umldoc->signalUMLObjectCreated(newAttribute);
+ return newAttribute;
+}
+
+UMLObject* UMLEntity::addEntityAttribute(const QString& name, Uml::IDType id) {
+ UMLEntityAttribute* literal = new UMLEntityAttribute(this, name, id);
+ m_List.append(literal);
+ emit entityAttributeAdded(literal);
+ UMLObject::emitModified();
+ connect(literal,SIGNAL(modified()),this,SIGNAL(modified()));
+ return literal;
+}
+
+bool UMLEntity::addEntityAttribute(UMLEntityAttribute* attribute, IDChangeLog* Log /* = 0*/) {
+ QString name = (QString)attribute->getName();
+ if (findChildObject(name) == NULL) {
+ attribute->parent()->removeChild(attribute);
+ this->insertChild(attribute);
+ m_List.append(attribute);
+ emit entityAttributeAdded(attribute);
+ UMLObject::emitModified();
+ connect(attribute,SIGNAL(modified()),this,SIGNAL(modified()));
+ return true;
+ } else if (Log) {
+ Log->removeChangeByNewID( attribute->getID() );
+ delete attribute;
+ }
+ return false;
+}
+
+bool UMLEntity::addEntityAttribute(UMLEntityAttribute* attribute, int position) {
+ QString name = (QString)attribute->getName();
+ if (findChildObject(name) == NULL) {
+ attribute->parent()->removeChild(attribute);
+ this->insertChild(attribute);
+ if ( position >= 0 && position <= (int)m_List.count() ) {
+ m_List.insert(position,attribute);
+ } else {
+ m_List.append(attribute);
+ }
+ emit entityAttributeAdded(attribute);
+ UMLObject::emitModified();
+ connect(attribute,SIGNAL(modified()),this,SIGNAL(modified()));
+ return true;
+ }
+ return false;
+}
+
+int UMLEntity::removeEntityAttribute(UMLClassifierListItem* literal) {
+ if (!m_List.remove((UMLEntityAttribute*)literal)) {
+ kDebug() << "can't find att given in list" << endl;
+ return -1;
+ }
+ emit entityAttributeRemoved(literal);
+ UMLObject::emitModified();
+ // If we are deleting the object, then we don't need to disconnect..this is done auto-magically
+ // for us by QObject. -b.t.
+ // disconnect(a,SIGNAL(modified()),this,SIGNAL(modified()));
+ delete literal;
+ return m_List.count();
+}
+
+int UMLEntity::entityAttributes() {
+ UMLClassifierListItemList entityAttributes = getFilteredList(Uml::ot_EntityAttribute);
+ return entityAttributes.count();
+}
+
+void UMLEntity::signalEntityAttributeRemoved(UMLClassifierListItem *eattr) {
+ emit entityAttributeRemoved(eattr);
+}
+
+bool UMLEntity::resolveRef() {
+ bool success = UMLClassifier::resolveRef();
+ for (UMLObjectListIt oit(m_List); oit.current(); ++oit) {
+ UMLObject* obj = oit.current();
+ if (obj->resolveRef()) {
+ UMLClassifierListItem *cli = static_cast<UMLClassifierListItem*>(obj);
+ if (cli->getBaseType() == Uml::ot_EntityAttribute)
+ emit entityAttributeAdded(cli);
+ }
+ }
+ return success;
+}
+
+void UMLEntity::saveToXMI(QDomDocument& qDoc, QDomElement& qElement) {
+ QDomElement entityElement = UMLObject::save("UML:Entity", qDoc);
+ //save operations
+ UMLClassifierListItemList entityAttributes = getFilteredList(Uml::ot_EntityAttribute);
+ UMLClassifierListItem* pEntityAttribute = 0;
+ for (UMLClassifierListItemListIt it(entityAttributes);
+ (pEntityAttribute = it.current()) != NULL; ++it) {
+ pEntityAttribute->saveToXMI(qDoc, entityElement);
+ }
+ qElement.appendChild(entityElement);
+}
+
+bool UMLEntity::load(QDomElement& element) {
+ QDomNode node = element.firstChild();
+ while( !node.isNull() ) {
+ if (node.isComment()) {
+ node = node.nextSibling();
+ continue;
+ }
+ QDomElement tempElement = node.toElement();
+ QString tag = tempElement.tagName();
+ if (Uml::tagEq(tag, "EntityAttribute")) { // for backward compatibility
+ UMLEntityAttribute* pEntityAttribute = new UMLEntityAttribute(this);
+ if( !pEntityAttribute->loadFromXMI(tempElement) ) {
+ return false;
+ }
+ m_List.append(pEntityAttribute);
+ } else if (tag == "stereotype") {
+ kDebug() << "UMLEntity::load(" << m_Name
+ << "): losing old-format stereotype." << endl;
+ } else {
+ kWarning() << "unknown child type in UMLEntity::load" << endl;
+ }
+ node = node.nextSibling();
+ }//end while
+ return true;
+}
+
+
+#include "entity.moc"
diff --git a/umbrello/umbrello/entity.h b/umbrello/umbrello/entity.h
new file mode 100644
index 00000000..7a4a2ce9
--- /dev/null
+++ b/umbrello/umbrello/entity.h
@@ -0,0 +1,155 @@
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * copyright (C) 2003-2007 *
+ * Umbrello UML Modeller Authors <uml-devel@uml.sf.net> *
+ ***************************************************************************/
+
+#ifndef ENTITY_H
+#define ENTITY_H
+
+#include "classifier.h"
+
+class UMLEntityAttribute;
+
+/**
+ * This class contains the non-graphical information required for a UML
+ * Entity.
+ * This class inherits from @ref UMLClassifier which contains most of the
+ * information.
+ *
+ * @short Non-graphical Information for an Entity.
+ * @author Jonathan Riddell
+ * Bugs and comments to uml-devel@lists.sf.net or http://bugs.kde.org
+ */
+class UMLEntity : public UMLClassifier {
+ Q_OBJECT
+public:
+ /**
+ * Sets up an entity.
+ *
+ * @param name The name of the Entity.
+ * @param id The unique id of the Entity.
+ */
+ explicit UMLEntity(const QString& name = "", Uml::IDType id = Uml::id_None);
+
+ /**
+ * Standard deconstructor.
+ */
+ virtual ~UMLEntity();
+
+ /**
+ * Overloaded '==' operator.
+ */
+ bool operator==(UMLEntity& rhs);
+
+ /**
+ * Copy the internal presentation of this object into the new
+ * object.
+ */
+ virtual void copyInto(UMLEntity* rhs) const;
+
+ /**
+ * Make a clone of this object.
+ */
+ virtual UMLObject* clone() const;
+
+ /**
+ * Creates an entity attribute for the parent concept.
+ * Reimplementation of method from UMLClassifier.
+ *
+ * @param name An optional name, used by when creating through UMLListView
+ * @param type An optional type, used by when creating through UMLListView
+ * @return The UMLEntityAttribute created
+ */
+ UMLAttribute* createAttribute(const QString &name = QString::null,
+ UMLObject *type = 0);
+
+ /**
+ * Adds an entityAttribute to the entity.
+ *
+ * @param name The name of the entityAttribute.
+ * @param id The id of the entityAttribute (optional.)
+ * If omitted a new ID is assigned internally.
+ * @return Pointer to the UMLEntityAttribute created.
+ */
+ UMLObject* addEntityAttribute(const QString &name, Uml::IDType id = Uml::id_None);
+
+ /**
+ * Adds an already created entityAttribute.
+ * The entityAttribute object must not belong to any other concept.
+ *
+ * @param att Pointer to the UMLEntityAttribute.
+ * @param Log Pointer to the IDChangeLog.
+ * @return True if the entityAttribute was successfully added.
+ */
+ bool addEntityAttribute(UMLEntityAttribute* att, IDChangeLog* Log = 0);
+
+ /**
+ * Adds an entityAttribute to the entity, at the given position.
+ * If position is negative or too large, the entityAttribute is added
+ * to the end of the list.
+ *
+ * @param att Pointer to the UMLEntityAttribute.
+ * @param position Position index for the insertion.
+ * @return True if the entityAttribute was successfully added.
+ */
+ //TODO: give default value -1 to position (append) - now it conflicts with the method above..
+ bool addEntityAttribute(UMLEntityAttribute* att, int position );
+
+ /**
+ * Removes an entityAttribute from the class.
+ *
+ * @param a The entityAttribute to remove.
+ * @return Count of the remaining entityAttributes after removal.
+ * Returns -1 if the given entityAttribute was not found.
+ */
+ int removeEntityAttribute(UMLClassifierListItem* a);
+
+ /**
+ * Emit the entityAttributeRemoved signal.
+ */
+ void signalEntityAttributeRemoved(UMLClassifierListItem *eattr);
+
+ /**
+ * Returns the number of entityAttributes for the class.
+ *
+ * @return The number of entityAttributes for the class.
+ */
+ int entityAttributes() ;
+
+ /**
+ * Resolve the types referenced by our UMLEntityAttributes.
+ * Reimplements the method from UMLClassifier.
+ */
+ virtual bool resolveRef();
+
+ /**
+ * Creates the <UML:Entity> element including its entityliterals.
+ */
+ virtual void saveToXMI(QDomDocument& qDoc, QDomElement& qElement);
+
+signals:
+ void entityAttributeAdded(UMLClassifierListItem*);
+ void entityAttributeRemoved(UMLClassifierListItem*);
+
+protected:
+ /**
+ * Loads the <UML:Entity> element including its entityAttributes.
+ */
+ bool load(QDomElement& element);
+
+private:
+ /**
+ * Initializes key variables of the class.
+ */
+ void init();
+
+};
+
+#endif // ENTITY_H
+
diff --git a/umbrello/umbrello/entityattribute.cpp b/umbrello/umbrello/entityattribute.cpp
new file mode 100644
index 00000000..8855efcb
--- /dev/null
+++ b/umbrello/umbrello/entityattribute.cpp
@@ -0,0 +1,178 @@
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * copyright (C) 2002-2006 *
+ * Umbrello UML Modeller Authors <uml-devel@uml.sf.net> *
+ ***************************************************************************/
+
+// own header
+#include "entityattribute.h"
+// qt/kde includes
+#include <qregexp.h>
+#include <kdebug.h>
+// app includes
+#include "umlcanvasobject.h"
+#include "umldoc.h"
+#include "uml.h"
+#include "dialogs/umlentityattributedialog.h"
+#include "object_factory.h"
+
+UMLEntityAttribute::UMLEntityAttribute( const UMLObject *parent, const QString& name,
+ Uml::IDType id, Uml::Visibility s,
+ UMLObject *type, const QString& iv )
+ : UMLAttribute(parent, name, id, s, type, iv) {
+ init();
+ if (m_pSecondary) {
+ m_pSecondary->setBaseType(Uml::ot_Entity);
+ }
+}
+
+UMLEntityAttribute::UMLEntityAttribute(const UMLObject *parent) : UMLAttribute(parent) {
+ init();
+}
+
+UMLEntityAttribute::~UMLEntityAttribute() { }
+
+void UMLEntityAttribute::init() {
+ m_BaseType = Uml::ot_EntityAttribute;
+ m_indexType = Uml::None;
+ m_autoIncrement = false;
+ m_null = false;
+}
+
+QString UMLEntityAttribute::getAttributes() const{
+ return m_attributes;
+}
+
+void UMLEntityAttribute::setAttributes(const QString& attributes) {
+ m_attributes = attributes;
+}
+
+QString UMLEntityAttribute::getValues() const{
+ return m_values;
+}
+
+void UMLEntityAttribute::setValues(const QString& values) {
+ m_values = values;
+}
+
+bool UMLEntityAttribute::getAutoIncrement() const{
+ return m_autoIncrement;
+}
+
+void UMLEntityAttribute::setAutoIncrement(const bool autoIncrement) {
+ m_autoIncrement = autoIncrement;
+}
+
+Uml::DBIndex_Type UMLEntityAttribute::getIndexType() const{
+ return m_indexType;
+}
+
+void UMLEntityAttribute::setIndexType(const Uml::DBIndex_Type indexType) {
+ m_indexType = indexType;
+}
+
+bool UMLEntityAttribute::getNull() const{
+ return m_null;
+}
+
+void UMLEntityAttribute::setNull(const bool nullIn) {
+ m_null = nullIn;
+}
+
+QString UMLEntityAttribute::toString(Uml::Signature_Type sig) {
+ QString s;
+ //FIXME
+
+ if(sig == Uml::st_ShowSig || sig == Uml::st_NoSig) {
+ s=m_Vis.toString(true) + ' ';
+ } else
+ s = "";
+
+ if(sig == Uml::st_ShowSig || sig == Uml::st_SigNoVis) {
+ QString string = s + getName() + " : " + getTypeName();
+ if(m_InitialValue.length() > 0)
+ string += " = " + m_InitialValue;
+ return string;
+ } else
+ return s + getName();
+}
+
+bool UMLEntityAttribute::operator==( UMLEntityAttribute &rhs) {
+ if( this == &rhs )
+ return true;
+
+ if( !UMLObject::operator==( rhs ) )
+ return false;
+
+ // The type name is the only distinguishing criterion.
+ // (Some programming languages might support more, but others don't.)
+ if (m_pSecondary != rhs.m_pSecondary)
+ return false;
+
+ return true;
+}
+
+void UMLEntityAttribute::copyInto(UMLEntityAttribute *rhs) const
+{
+ // call the parent first.
+ UMLClassifierListItem::copyInto(rhs);
+
+ // Copy all datamembers
+ rhs->m_pSecondary = m_pSecondary;
+ rhs->m_SecondaryId = m_SecondaryId;
+ rhs->m_InitialValue = m_InitialValue;
+ rhs->m_ParmKind = m_ParmKind;
+}
+
+UMLObject* UMLEntityAttribute::clone() const
+{
+ UMLEntityAttribute* clone = new UMLEntityAttribute( (UMLEntityAttribute*)parent() );
+ copyInto(clone);
+
+ return clone;
+}
+
+
+void UMLEntityAttribute::saveToXMI( QDomDocument & qDoc, QDomElement & qElement ) {
+ QDomElement entityattributeElement = UMLObject::save("UML:EntityAttribute", qDoc);
+ if (m_pSecondary == NULL) {
+ kDebug() << "UMLEntityAttribute::saveToXMI(" << m_Name
+ << "): m_pSecondary is NULL, using local name "
+ << m_SecondaryId << endl;
+ entityattributeElement.setAttribute( "type", m_SecondaryId );
+ } else {
+ entityattributeElement.setAttribute( "type", ID2STR(m_pSecondary->getID()) );
+ }
+ entityattributeElement.setAttribute( "initialValue", m_InitialValue );
+ entityattributeElement.setAttribute( "dbindex_type", m_indexType );
+ entityattributeElement.setAttribute( "values", m_values );
+ entityattributeElement.setAttribute( "attributes", m_attributes );
+ entityattributeElement.setAttribute( "auto_increment", m_autoIncrement );
+ entityattributeElement.setAttribute( "allow_null", m_null );
+ qElement.appendChild( entityattributeElement );
+}
+
+bool UMLEntityAttribute::load( QDomElement & element ) {
+ if (! UMLAttribute::load(element))
+ return false;
+ int indexType = element.attribute( "dbindex_type", "1100" ).toInt();
+ m_indexType = ( Uml::DBIndex_Type )indexType;
+ m_values = element.attribute( "values", "" );
+ m_attributes = element.attribute( "attributes", "" );
+ m_autoIncrement = ( bool )element.attribute( "auto_increment", "" ).toInt();
+ m_null = ( bool )element.attribute( "allow_null", "" ).toInt();
+ return true;
+}
+
+bool UMLEntityAttribute::showPropertiesDialog(QWidget* parent) {
+ UMLEntityAttributeDialog dialog(parent, this);
+ return dialog.exec();
+}
+
+#include "entityattribute.moc"
+
diff --git a/umbrello/umbrello/entityattribute.h b/umbrello/umbrello/entityattribute.h
new file mode 100644
index 00000000..76af37a7
--- /dev/null
+++ b/umbrello/umbrello/entityattribute.h
@@ -0,0 +1,183 @@
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * copyright (C) 2002-2006 *
+ * Umbrello UML Modeller Authors <uml-devel@uml.sf.net> *
+ ***************************************************************************/
+
+#ifndef ENTITYATTRIBUTE_H
+#define ENTITYATTRIBUTE_H
+
+#include "attribute.h"
+#include "umlnamespace.h"
+
+/**
+ * This class is used to set up information for an entityattribute. This is a database field
+ * It has a type, name, index type and default value.
+ *
+ * @short Sets up entityattribute information.
+ * @author Jonathan Riddell <jr @jriddell.org>
+ * @see UMLObject
+ * Bugs and comments to uml-devel@lists.sf.net or http://bugs.kde.org
+ */
+class UMLEntityAttribute : public UMLAttribute {
+ Q_OBJECT
+public:
+ /**
+ * Sets up an entityattribute.
+ *
+ * @param parent The parent of this UMLEntityAttribute.
+ * @param name The name of this UMLEntityAttribute.
+ * @param id The unique id given to this UMLEntityAttribute.
+ * @param s The visibility of the UMLEntityAttribute.
+ * @param type The type of this UMLEntityAttribute.
+ * @param iv The initial value of the entityattribute.
+ */
+ UMLEntityAttribute(const UMLObject* parent, const QString& name,
+ Uml::IDType id = Uml::id_None,
+ Uml::Visibility s = Uml::Visibility::Private,
+ UMLObject *type = 0, const QString& iv = 0);
+
+ /**
+ * Sets up an entityattribute.
+ *
+ * @param parent The parent of this UMLEntityAttribute.
+ */
+ UMLEntityAttribute(const UMLObject* parent);
+
+ /**
+ * Overloaded '==' operator
+ */
+ bool operator==( UMLEntityAttribute& rhs);
+
+ /**
+ * destructor.
+ */
+ virtual ~UMLEntityAttribute();
+
+ /**
+ * Copy the internal presentation of this object into the UMLEntityAttribute
+ * object.
+ */
+ virtual void copyInto(UMLEntityAttribute* rhs) const;
+
+ /**
+ * Make a clone of the UMLEntityAttribute.
+ */
+ virtual UMLObject* clone() const;
+
+ /**
+ * Returns The value of the UMLEntityAttribute's attributes property.
+ *
+ * @return The value of the UMLEntityAttribute's attributes property.
+ */
+ QString getAttributes() const;
+
+ /**
+ * Sets the UMLEntityAttribute's attributes property.
+ *
+ * @param attributes The new value for the attributes property.
+ */
+ void setAttributes(const QString& attributes);
+
+ /**
+ * Returns the UMLEntityAttribute's index type property.
+ *
+ * @return The value of the UMLEntityAttribute's index type property.
+ */
+ Uml::DBIndex_Type getIndexType() const;
+
+ /**
+ * Sets the UMLEntityAttribute's index type property.
+ *
+ * @param indexType The UMLEntityAttribute's index type property.
+ */
+ void setIndexType(const Uml::DBIndex_Type indexType);
+
+ /**
+ * Returns the UMLEntityAttribute's length/values property.
+ *
+ * @return The UMLEntityAttribute's length/values property.
+ */
+ QString getValues() const;
+
+ /**
+ * Sets the UMLEntityAttribute's length/values property.
+ *
+ * @param values The new value of the length/values property.
+ */
+ void setValues(const QString& values);
+
+ /**
+ * Returns the UMLEntityAttribute's auto_increment boolean
+ *
+ * @return The UMLEntityAttribute's auto_increment boolean
+ */
+ bool getAutoIncrement() const;
+
+ /**
+ * Sets the UMLEntityAttribute's auto_increment property
+ *
+ * @param autoIncrement The UMLEntityAttribute's auto_increment property
+ */
+ void setAutoIncrement(const bool autoIncrement);
+
+ /**
+ * Returns the UMLEntityAttribute's allow null value.
+ *
+ * @return The UMLEntityAttribute's allow null value.
+ */
+ bool getNull() const;
+
+ /**
+ * Sets the UMLEntityAttribute's allow null value.
+ *
+ * @param null The UMLEntityAttribute's allow null value.
+ */
+ void setNull(const bool null);
+
+ /**
+ * Returns a string representation of the UMLEntityAttribute.
+ *
+ * @param sig If true will show the entityattribute type and
+ * initial value.
+ * @return Returns a string representation of the UMLEntityAttribute.
+ */
+ QString toString(Uml::Signature_Type sig = Uml::st_NoSig);
+
+ /**
+ * Creates the <UML:EntityAttribute> XMI element.
+ */
+ void saveToXMI(QDomDocument& qDoc, QDomElement& qElement);
+
+ /**
+ * Display the properties configuration dialog for the entityattribute.
+ */
+ bool showPropertiesDialog(QWidget* parent);
+
+protected:
+ /**
+ * Initialize members of this class.
+ * Auxiliary method used by constructors.
+ */
+ void init();
+
+ /**
+ * Loads the <UML:EntityAttribute> XMI element.
+ */
+ bool load(QDomElement& element);
+
+private:
+ Uml::DBIndex_Type m_indexType;
+ QString m_values;
+ QString m_attributes;
+ bool m_autoIncrement;
+ bool m_null;
+};
+
+#endif
+
diff --git a/umbrello/umbrello/entitywidget.cpp b/umbrello/umbrello/entitywidget.cpp
new file mode 100644
index 00000000..942de360
--- /dev/null
+++ b/umbrello/umbrello/entitywidget.cpp
@@ -0,0 +1,203 @@
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * copyright (C) 2003-2007 *
+ * Umbrello UML Modeller Authors <uml-devel@uml.sf.net> *
+ ***************************************************************************/
+
+// own header
+#include "entitywidget.h"
+
+// qt/kde includes
+#include <qpainter.h>
+#include <kdebug.h>
+
+// app includes
+#include "entity.h"
+#include "entityattribute.h"
+#include "classifier.h"
+#include "umlclassifierlistitemlist.h"
+#include "classifierlistitem.h"
+#include "umlview.h"
+#include "umldoc.h"
+#include "uml.h"
+#include "listpopupmenu.h"
+#include "object_factory.h"
+
+
+EntityWidget::EntityWidget(UMLView* view, UMLObject* o): UMLWidget(view, o) {
+ init();
+}
+
+void EntityWidget::init() {
+ UMLWidget::setBaseType(Uml::wt_Entity);
+ setSize(100, 30);
+ //set defaults from m_pView
+ if (m_pView) {
+ //check to see if correct
+ const Settings::OptionState& ops = m_pView->getOptionState();
+ }
+ if (! UMLApp::app()->getDocument()->loading())
+ updateComponentSize();
+}
+
+EntityWidget::~EntityWidget() {}
+
+void EntityWidget::draw(QPainter& p, int offsetX, int offsetY) {
+ UMLWidget::setPen(p);
+ if(UMLWidget::getUseFillColour())
+ p.setBrush(UMLWidget::getFillColour());
+ else
+ p.setBrush(m_pView -> viewport() -> backgroundColor());
+
+ const int w = width();
+ const int h = height();
+
+ const QFontMetrics &fm = getFontMetrics(FT_NORMAL);
+ int fontHeight = fm.lineSpacing();
+ const QString name = this->getName();
+
+ p.drawRect(offsetX, offsetY, w, h);
+ p.setPen(QPen(Qt::black));
+
+ QFont font = UMLWidget::getFont();
+ font.setBold(true);
+ p.setFont(font);
+ int y = 0;
+ if ( !m_pObject->getStereotype().isEmpty() ) {
+ p.drawText(offsetX + ENTITY_MARGIN, offsetY,
+ w - ENTITY_MARGIN * 2,fontHeight,
+ Qt::AlignCenter, m_pObject->getStereotype(true));
+ font.setItalic( m_pObject -> getAbstract() );
+ p.setFont(font);
+ p.drawText(offsetX + ENTITY_MARGIN, offsetY + fontHeight,
+ w - ENTITY_MARGIN * 2, fontHeight, Qt::AlignCenter, name);
+ font.setBold(false);
+ font.setItalic(false);
+ p.setFont(font);
+ y = fontHeight * 2;
+ } else {
+ font.setItalic( m_pObject -> getAbstract() );
+ p.setFont(font);
+ p.drawText(offsetX + ENTITY_MARGIN, offsetY,
+ w - ENTITY_MARGIN * 2, fontHeight, Qt::AlignCenter, name);
+ font.setBold(false);
+ font.setItalic(false);
+ p.setFont(font);
+
+ y = fontHeight;
+ }
+
+ UMLWidget::setPen(p);
+
+ p.drawLine(offsetX, offsetY + y, offsetX + w - 1, offsetY + y);
+
+ QFontMetrics fontMetrics(font);
+ UMLClassifier *classifier = (UMLClassifier*)m_pObject;
+ UMLClassifierListItem* entityattribute = 0;
+ UMLClassifierListItemList list = classifier->getFilteredList(Uml::ot_EntityAttribute);
+ for (entityattribute = list.first(); entityattribute; entityattribute = list.next()) {
+ QString text = entityattribute->getName();
+ p.setPen( QPen(Qt::black) );
+ UMLEntityAttribute* casted = dynamic_cast<UMLEntityAttribute*>( entityattribute );
+ if( casted && casted->getIndexType() == Uml::Primary )
+ {
+ font.setUnderline( true );
+ p.setFont( font );
+ font.setUnderline( false );
+ }
+ p.drawText(offsetX + ENTITY_MARGIN, offsetY + y,
+ fontMetrics.width(text), fontHeight, Qt::AlignVCenter, text);
+ p.setFont( font );
+ y+=fontHeight;
+ }
+
+ if (m_bSelected) {
+ drawSelected(&p, offsetX, offsetY);
+ }
+}
+
+QSize EntityWidget::calculateSize() {
+ if (!m_pObject) {
+ return UMLWidget::calculateSize();
+ }
+
+ int width, height;
+ QFont font = UMLWidget::getFont();
+ font.setItalic(false);
+ font.setUnderline(false);
+ font.setBold(false);
+ const QFontMetrics fm(font);
+
+ const int fontHeight = fm.lineSpacing();
+
+ int lines = 1;//always have one line - for name
+ if ( !m_pObject->getStereotype().isEmpty() ) {
+ lines++;
+ }
+
+ const int numberOfEntityAttributes = ((UMLEntity*)m_pObject)->entityAttributes();
+
+ height = width = 0;
+ //set the height of the entity
+
+ lines += numberOfEntityAttributes;
+ if (numberOfEntityAttributes == 0) {
+ height += fontHeight / 2; //no entity literals, so just add a bit of space
+ }
+
+ height += lines * fontHeight;
+
+ //now set the width of the concept
+ //set width to name to start with
+ // FIXME spaces to get round beastie with font width,
+ // investigate UMLWidget::getFontMetrics()
+ width = getFontMetrics(FT_BOLD_ITALIC).boundingRect(' ' + getName() + ' ').width();
+
+ const int w = getFontMetrics(FT_BOLD).boundingRect(m_pObject->getStereotype(true)).width();
+
+ width = w > width?w:width;
+
+ UMLClassifier* classifier = (UMLClassifier*)m_pObject;
+ UMLClassifierListItemList list = classifier->getFilteredList(Uml::ot_EntityAttribute);
+ UMLClassifierListItem* listItem = 0;
+ for (listItem = list.first(); listItem; listItem = list.next()) {
+ int w = fm.width( listItem->getName() );
+ width = w > width?w:width;
+ }
+
+ //allow for width margin
+ width += ENTITY_MARGIN * 2;
+
+ return QSize(width, height);
+}
+
+void EntityWidget::slotMenuSelection(int sel) {
+ switch(sel) {
+ case ListPopupMenu::mt_EntityAttribute:
+ if (Object_Factory::createChildObject(static_cast<UMLClassifier*>(m_pObject),
+ Uml::ot_EntityAttribute) ) {
+ UMLApp::app()->getDocument()->setModified();
+ }
+ break;
+ }
+ UMLWidget::slotMenuSelection(sel);
+}
+
+void EntityWidget::saveToXMI( QDomDocument& qDoc, QDomElement& qElement ) {
+ QDomElement conceptElement = qDoc.createElement("entitywidget");
+ UMLWidget::saveToXMI(qDoc, conceptElement);
+ qElement.appendChild(conceptElement);
+}
+
+bool EntityWidget::loadFromXMI( QDomElement & qElement ) {
+ if ( !UMLWidget::loadFromXMI(qElement) ) {
+ return false;
+ }
+ return true;
+}
+
diff --git a/umbrello/umbrello/entitywidget.h b/umbrello/umbrello/entitywidget.h
new file mode 100644
index 00000000..249f0984
--- /dev/null
+++ b/umbrello/umbrello/entitywidget.h
@@ -0,0 +1,82 @@
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * copyright (C) 2003-2006 *
+ * Umbrello UML Modeller Authors <uml-devel@uml.sf.net> *
+ ***************************************************************************/
+
+#ifndef ENTITYWIDGET_H
+#define ENTITYWIDGET_H
+
+#include "umlwidget.h"
+
+class UMLView;
+
+#define ENTITY_MARGIN 5
+
+/**
+ * Defines a graphical version of the entity. Most of the functionality
+ * will come from the @ref UMLWidget class from which class inherits from.
+ *
+ * @short A graphical version of an entity.
+ * @author Jonathan Riddell
+ * @see UMLWidget
+ * Bugs and comments to uml-devel@lists.sf.net or http://bugs.kde.org
+ */
+class EntityWidget : public UMLWidget {
+public:
+
+ /**
+ * Constructs an EntityWidget.
+ *
+ * @param view The parent of this EntityWidget.
+ * @param o The UMLObject this will be representing.
+ */
+ EntityWidget(UMLView* view, UMLObject* o);
+
+ /**
+ * Standard deconstructor.
+ */
+ ~EntityWidget();
+
+ /**
+ * Initializes key variables of the class.
+ */
+ void init();
+
+ /**
+ * Draws the entity as a rectangle with a box underneith with a list of literals
+ */
+ void draw(QPainter& p, int offsetX, int offsetY);
+
+ /**
+ * Saves to the "entitywidget" XMI element.
+ */
+ void saveToXMI(QDomDocument& qDoc, QDomElement& qElement);
+
+ /**
+ * Loads from an "entitywidget" XMI element.
+ */
+ bool loadFromXMI(QDomElement& qElement);
+
+protected:
+ /**
+ * Overrides method from UMLWidget.
+ */
+ QSize calculateSize();
+
+public slots:
+ /**
+ * Will be called when a menu selection has been made from the
+ * popup menu.
+ *
+ * @param sel The selection id that has been selected.
+ */
+ void slotMenuSelection(int sel);
+};
+
+#endif
diff --git a/umbrello/umbrello/enum.cpp b/umbrello/umbrello/enum.cpp
new file mode 100644
index 00000000..ba3be7b4
--- /dev/null
+++ b/umbrello/umbrello/enum.cpp
@@ -0,0 +1,206 @@
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * copyright (C) 2003-2007 *
+ * Umbrello UML Modeller Authors <uml-devel@uml.sf.net> *
+ ***************************************************************************/
+
+// own header
+#include "enum.h"
+// qt/kde includes
+#include <kdebug.h>
+#include <klocale.h>
+#include <kmessagebox.h>
+// app includes
+#include "enumliteral.h"
+#include "umldoc.h"
+#include "uml.h"
+#include "uniqueid.h"
+#include "clipboard/idchangelog.h"
+
+UMLEnum::UMLEnum(const QString& name, Uml::IDType id) : UMLClassifier(name, id) {
+ init();
+}
+
+UMLEnum::~UMLEnum() {
+ m_List.clear();
+}
+
+bool UMLEnum::operator==( UMLEnum & rhs ) {
+ return UMLClassifier::operator==(rhs);
+}
+
+void UMLEnum::copyInto(UMLEnum *rhs) const
+{
+ UMLClassifier::copyInto(rhs);
+}
+
+UMLObject* UMLEnum::clone() const
+{
+ UMLEnum *clone = new UMLEnum();
+ copyInto(clone);
+
+ return clone;
+}
+
+void UMLEnum::init() {
+ m_BaseType = Uml::ot_Enum;
+ setStereotype( "enum" );
+}
+
+UMLObject* UMLEnum::createEnumLiteral(const QString& name) {
+ Uml::IDType id = UniqueID::gen();
+ QString currentName;
+ if (name.isNull()) {
+ currentName = uniqChildName(Uml::ot_EnumLiteral);
+ } else {
+ currentName = name;
+ }
+
+ UMLEnumLiteral* newEnumLiteral = new UMLEnumLiteral(this, currentName);
+
+ bool ok = true;
+ bool goodName = false;
+
+ //check for name.isNull() stops dialog being shown
+ //when creating enum literal via list view
+ while (ok && !goodName && name.isNull()) {
+ ok = newEnumLiteral->showPropertiesDialog( UMLApp::app() );
+ QString name = newEnumLiteral->getName();
+
+ if(name.length() == 0) {
+ KMessageBox::error(0, i18n("That is an invalid name."), i18n("Invalid Name"));
+ } else {
+ goodName = true;
+ }
+ }
+
+ if (!ok) {
+ delete newEnumLiteral;
+ return NULL;
+ }
+
+ addEnumLiteral(newEnumLiteral);
+
+ UMLDoc *umldoc = UMLApp::app()->getDocument();
+ umldoc->signalUMLObjectCreated(newEnumLiteral);
+ return newEnumLiteral;
+}
+
+UMLObject* UMLEnum::addEnumLiteral(const QString &name, Uml::IDType id) {
+ UMLObject *el = UMLCanvasObject::findChildObject(name);
+ if (el != NULL) {
+ kDebug() << "UMLEnum::addEnumLiteral: " << name
+ << " is already present" << endl;
+ return el;
+ }
+ UMLEnumLiteral* literal = new UMLEnumLiteral(this, name, id);
+ m_List.append(literal);
+ UMLObject::emitModified();
+ emit enumLiteralAdded(literal);
+ connect(literal,SIGNAL(modified()),this,SIGNAL(modified()));
+ return literal;
+}
+
+bool UMLEnum::addEnumLiteral(UMLEnumLiteral* literal, IDChangeLog* Log /* = 0*/) {
+ QString name = (QString)literal->getName();
+ if (findChildObject(name) == NULL) {
+ literal->parent()->removeChild(literal);
+ this->insertChild(literal);
+ m_List.append(literal);
+ UMLObject::emitModified();
+ emit enumLiteralAdded(literal);
+ connect(literal,SIGNAL(modified()),this,SIGNAL(modified()));
+ return true;
+ } else if (Log) {
+ Log->removeChangeByNewID( literal->getID() );
+ delete literal;
+ }
+ return false;
+}
+
+bool UMLEnum::addEnumLiteral(UMLEnumLiteral* literal, int position) {
+ QString name = (QString)literal->getName();
+ if (findChildObject(name) == NULL) {
+ literal->parent()->removeChild(literal);
+ this->insertChild(literal);
+ if ( position >= 0 && position <= (int)m_List.count() ) {
+ m_List.insert(position,literal);
+ } else {
+ m_List.append(literal);
+ }
+ UMLObject::emitModified();
+ emit enumLiteralAdded(literal);
+ connect(literal,SIGNAL(modified()),this,SIGNAL(modified()));
+ return true;
+ }
+ return false;
+}
+
+int UMLEnum::removeEnumLiteral(UMLEnumLiteral* literal) {
+ if (!m_List.remove(literal)) {
+ kDebug() << "can't find att given in list" << endl;
+ return -1;
+ }
+ emit enumLiteralRemoved(literal);
+ UMLObject::emitModified();
+ // If we are deleting the object, then we don't need to disconnect..this is done auto-magically
+ // for us by QObject. -b.t.
+ // disconnect(a,SIGNAL(modified()),this,SIGNAL(modified()));
+ delete literal;
+ return m_List.count();
+}
+
+int UMLEnum::enumLiterals() {
+ return m_List.count();
+}
+
+void UMLEnum::signalEnumLiteralRemoved(UMLClassifierListItem *elit) {
+ emit enumLiteralRemoved(elit);
+}
+
+void UMLEnum::saveToXMI(QDomDocument& qDoc, QDomElement& qElement) {
+ QDomElement enumElement = UMLObject::save("UML:Enumeration", qDoc);
+ // save enum literals
+ UMLClassifierListItemList enumLiterals = getFilteredList(Uml::ot_EnumLiteral);
+ UMLClassifierListItem* pEnumLiteral = 0;
+ for (UMLClassifierListItemListIt it(enumLiterals);
+ (pEnumLiteral = it.current()) != NULL; ++it) {
+ pEnumLiteral->saveToXMI(qDoc, enumElement);
+ }
+ qElement.appendChild(enumElement);
+}
+
+bool UMLEnum::load(QDomElement& element) {
+ QDomNode node = element.firstChild();
+ while( !node.isNull() ) {
+ if (node.isComment()) {
+ node = node.nextSibling();
+ continue;
+ }
+ QDomElement tempElement = node.toElement();
+ QString tag = tempElement.tagName();
+ if (Uml::tagEq(tag, "EnumerationLiteral") ||
+ Uml::tagEq(tag, "EnumLiteral")) { // for backward compatibility
+ UMLEnumLiteral* pEnumLiteral = new UMLEnumLiteral(this);
+ if( !pEnumLiteral->loadFromXMI(tempElement) ) {
+ return false;
+ }
+ m_List.append(pEnumLiteral);
+ } else if (tag == "stereotype") {
+ kDebug() << "UMLEnum::load(" << m_Name
+ << "): losing old-format stereotype." << endl;
+ } else {
+ kWarning() << "unknown child type in UMLEnum::load" << endl;
+ }
+ node = node.nextSibling();
+ }//end while
+ return true;
+}
+
+
+#include "enum.moc"
diff --git a/umbrello/umbrello/enum.h b/umbrello/umbrello/enum.h
new file mode 100644
index 00000000..1845eb88
--- /dev/null
+++ b/umbrello/umbrello/enum.h
@@ -0,0 +1,145 @@
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * copyright (C) 2003-2006 *
+ * Umbrello UML Modeller Authors <uml-devel@uml.sf.net> *
+ ***************************************************************************/
+
+#ifndef ENUM_H
+#define ENUM_H
+
+#include "classifier.h"
+
+class UMLEnumLiteral;
+
+/**
+ * This class contains the non-graphical information required for a UML
+ * Enum.
+ * This class inherits from @ref UMLClassifier which contains most of the
+ * information.
+ *
+ * @short Non-graphical Information for an Enum.
+ * @author Jonathan Riddell
+ * Bugs and comments to uml-devel@lists.sf.net or http://bugs.kde.org
+ */
+class UMLEnum : public UMLClassifier {
+ Q_OBJECT
+public:
+ /**
+ * Sets up an enum.
+ *
+ * @param name The name of the Enum.
+ * @param id The unique id of the Enum.
+ */
+ explicit UMLEnum(const QString& name = "", Uml::IDType id = Uml::id_None);
+
+ /**
+ * Standard deconstructor.
+ */
+ virtual ~UMLEnum();
+
+ /**
+ * Overloaded '==' operator.
+ */
+ bool operator==(UMLEnum& rhs);
+
+ /**
+ * Copy the internal presentation of this object into the new
+ * object.
+ */
+ virtual void copyInto(UMLEnum *rhs) const;
+
+ /**
+ * Make a clone of this object.
+ */
+ virtual UMLObject* clone() const;
+
+ /**
+ * Creates a literal for the enum.
+ *
+ * @return The UMLEnum created
+ */
+ UMLObject* createEnumLiteral(const QString& name = QString());
+
+ /**
+ * Adds an enumliteral to the enum.
+ *
+ * @param name The name of the enumliteral.
+ * @param id The id of the enumliteral (optional.)
+ * If omitted a new ID is assigned internally.
+ * @return Pointer to the UMLEnumliteral created.
+ */
+ UMLObject* addEnumLiteral(const QString &name, Uml::IDType id = Uml::id_None);
+
+ /**
+ * Adds an already created enumliteral.
+ * The enumliteral object must not belong to any other concept.
+ *
+ * @param Att Pointer to the UMLEnumLiteral.
+ * @param Log Pointer to the IDChangeLog.
+ * @return True if the enumliteral was successfully added.
+ */
+ bool addEnumLiteral(UMLEnumLiteral* Att, IDChangeLog* Log = 0);
+
+ /**
+ * Adds an enumliteral to the enum, at the given position.
+ * If position is negative or too large, the enumliteral is added
+ * to the end of the list.
+ *
+ * @param Att Pointer to the UMLEnumLiteral.
+ * @param position Position index for the insertion.
+ * @return True if the enumliteral was successfully added.
+ */
+ //TODO: give default value -1 to position (append) - now it conflicts with the method above..
+ bool addEnumLiteral(UMLEnumLiteral* Att, int position );
+
+ /**
+ * Removes an enumliteral from the class.
+ *
+ * @param a The enumliteral to remove.
+ * @return Count of the remaining enumliterals after removal.
+ * Returns -1 if the given enumliteral was not found.
+ */
+ int removeEnumLiteral(UMLEnumLiteral *a);
+
+ /**
+ * Returns the number of enumliterals for the class.
+ *
+ * @return The number of enumliterals for the class.
+ */
+ int enumLiterals();
+
+ /**
+ * Emit the enumLiteralRemoved signal.
+ */
+ void signalEnumLiteralRemoved(UMLClassifierListItem *elit);
+
+ /**
+ * Creates the <UML:Enum> element including its enumliterals.
+ */
+ virtual void saveToXMI( QDomDocument & qDoc, QDomElement & qElement );
+
+signals:
+ void enumLiteralAdded(UMLClassifierListItem*);
+ void enumLiteralRemoved(UMLClassifierListItem*);
+
+protected:
+ /**
+ * Loads the <UML:Enum> element including its enumliterals.
+ */
+ bool load( QDomElement & element );
+
+private:
+ /**
+ * Initializes key variables of the class.
+ */
+ void init();
+
+};
+
+#endif // ENUM_H
+
diff --git a/umbrello/umbrello/enumliteral.cpp b/umbrello/umbrello/enumliteral.cpp
new file mode 100644
index 00000000..ea6eef49
--- /dev/null
+++ b/umbrello/umbrello/enumliteral.cpp
@@ -0,0 +1,74 @@
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * copyright (C) 2003-2006 *
+ * Umbrello UML Modeller Authors <uml-devel@uml.sf.net> *
+ ***************************************************************************/
+
+#include "enumliteral.h"
+
+#include <kinputdialog.h>
+#include <kdebug.h>
+#include <klocale.h>
+
+UMLEnumLiteral::UMLEnumLiteral(const UMLObject *parent,
+ const QString& name, Uml::IDType id)
+ : UMLClassifierListItem(parent, name, id) {
+ m_BaseType = Uml::ot_EnumLiteral;
+}
+
+UMLEnumLiteral::UMLEnumLiteral(const UMLObject *parent) : UMLClassifierListItem(parent) {
+ m_BaseType = Uml::ot_EnumLiteral;
+}
+
+UMLEnumLiteral::~UMLEnumLiteral() { }
+
+bool UMLEnumLiteral::operator==(UMLEnumLiteral& rhs) {
+ if ( this == &rhs ) {
+ return true;
+ }
+ if ( !UMLObject::operator==( rhs ) ) {
+ return false;
+ }
+ return true;
+}
+
+void UMLEnumLiteral::copyInto(UMLEnumLiteral *rhs) const
+{
+ UMLClassifierListItem::copyInto(rhs);
+}
+
+UMLObject* UMLEnumLiteral::clone() const
+{
+ UMLEnumLiteral *clone = new UMLEnumLiteral((UMLObject *) parent());
+ copyInto(clone);
+
+ return clone;
+}
+
+
+void UMLEnumLiteral::saveToXMI(QDomDocument& qDoc, QDomElement& qElement) {
+ QDomElement attributeElement = UMLObject::save("UML:EnumerationLiteral", qDoc);
+ qElement.appendChild( attributeElement );
+}
+
+bool UMLEnumLiteral::load(QDomElement& ) {
+ return true;
+}
+
+bool UMLEnumLiteral::showPropertiesDialog(QWidget* parent) {
+ bool ok;
+ QString name = KInputDialog::getText(i18n("Name"), i18n("Enter name:"), getName(), &ok, parent);
+ if ( ok && !name.isEmpty() ) {
+ setName(name);
+ return true;
+ } else {
+ return false;
+ }
+}
+
+
diff --git a/umbrello/umbrello/enumliteral.h b/umbrello/umbrello/enumliteral.h
new file mode 100644
index 00000000..3484012e
--- /dev/null
+++ b/umbrello/umbrello/enumliteral.h
@@ -0,0 +1,85 @@
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * copyright (C) 2003-2006 *
+ * Umbrello UML Modeller Authors <uml-devel@uml.sf.net> *
+ ***************************************************************************/
+
+#ifndef ENUMLITERAL_H
+#define ENUMLITERAL_H
+
+#include "classifierlistitem.h"
+
+/**
+ * This class is used to set up information for an enum literal. Enum
+ * literals are the values that enums can be set to.
+ *
+ * @short Sets up attribute information.
+ * @author Paul Hensgen <phensgen@techie.com>
+ * @see UMLObject
+ * Bugs and comments to uml-devel@lists.sf.net or http://bugs.kde.org
+ */
+
+class UMLEnumLiteral : public UMLClassifierListItem {
+public:
+ /**
+ * Sets up an enum literal.
+ *
+ * @param parent The parent of this UMLEnumLiteral.
+ * @param name The name of this UMLEnumLiteral.
+ * @param id The unique id given to this UMLEnumLiteral.
+ */
+ UMLEnumLiteral(const UMLObject* parent,
+ const QString& name, Uml::IDType id = Uml::id_None);
+
+ /**
+ * Sets up an enum literal.
+ *
+ * @param parent The parent of this UMLEnumLiteral.
+ */
+ UMLEnumLiteral(const UMLObject* parent);
+
+ /**
+ * Overloaded '==' operator
+ */
+ bool operator==(UMLEnumLiteral &rhs);
+
+ /**
+ * Copy the internal presentation of this object into the new
+ * object.
+ */
+ virtual void copyInto(UMLEnumLiteral *rhs) const;
+
+ /**
+ * Make a clone of this object.
+ */
+ virtual UMLObject* clone() const;
+
+ /**
+ * destructor
+ */
+ virtual ~UMLEnumLiteral();
+
+ /**
+ * Creates the <UML:EnumLiteral> XMI element.
+ */
+ void saveToXMI(QDomDocument& qDoc, QDomElement& qElement);
+
+ /**
+ * Display the properties configuration dialog for the enum literal.
+ */
+ bool showPropertiesDialog(QWidget* parent);
+
+protected:
+ /**
+ * Loads the <UML:EnumLiteral> XMI element (empty.)
+ */
+ bool load(QDomElement& element);
+
+};
+
+#endif
diff --git a/umbrello/umbrello/enumwidget.cpp b/umbrello/umbrello/enumwidget.cpp
new file mode 100644
index 00000000..2d642b31
--- /dev/null
+++ b/umbrello/umbrello/enumwidget.cpp
@@ -0,0 +1,218 @@
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * copyright (C) 2003-2007 *
+ * Umbrello UML Modeller Authors <uml-devel@uml.sf.net> *
+ ***************************************************************************/
+
+// own header
+#include "enumwidget.h"
+
+// qt/kde includes
+#include <qpainter.h>
+#include <kdebug.h>
+
+// app includes
+#include "enum.h"
+#include "enumliteral.h"
+#include "classifier.h"
+#include "umlclassifierlistitemlist.h"
+#include "classifierlistitem.h"
+#include "umlview.h"
+#include "umldoc.h"
+#include "uml.h"
+#include "listpopupmenu.h"
+#include "object_factory.h"
+
+
+EnumWidget::EnumWidget(UMLView* view, UMLObject* o) : UMLWidget(view, o) {
+ init();
+}
+
+void EnumWidget::init() {
+ UMLWidget::setBaseType(Uml::wt_Enum);
+ setSize(100, 30);
+ m_pMenu = 0;
+ //set defaults from m_pView
+ if (m_pView) {
+ //check to see if correct
+ const Settings::OptionState& ops = m_pView->getOptionState();
+ m_bShowPackage = ops.classState.showPackage;
+ } else {
+ // For completeness only. Not supposed to happen.
+ m_bShowPackage = false;
+ }
+ if (! UMLApp::app()->getDocument()->loading())
+ updateComponentSize();
+}
+
+EnumWidget::~EnumWidget() {}
+
+void EnumWidget::draw(QPainter& p, int offsetX, int offsetY) {
+ UMLWidget::setPen(p);
+ if(UMLWidget::getUseFillColour())
+ p.setBrush(UMLWidget::getFillColour());
+ else
+ p.setBrush(m_pView -> viewport() -> backgroundColor());
+
+ const int w = width();
+ const int h = height();
+
+ const QFontMetrics &fm = getFontMetrics(FT_NORMAL);
+ const int fontHeight = fm.lineSpacing();
+ QString name;
+ if ( m_bShowPackage ) {
+ name = m_pObject->getFullyQualifiedName();
+ } else {
+ name = this -> getName();
+ }
+
+ p.drawRect(offsetX, offsetY, w, h);
+ p.setPen(QPen(Qt::black));
+
+ QFont font = UMLWidget::getFont();
+ font.setBold(true);
+ p.setFont(font);
+ p.drawText(offsetX + ENUM_MARGIN, offsetY,
+ w - ENUM_MARGIN * 2,fontHeight,
+ Qt::AlignCenter, m_pObject->getStereotype(true));
+
+ font.setItalic( m_pObject -> getAbstract() );
+ p.setFont(font);
+ p.drawText(offsetX + ENUM_MARGIN, offsetY + fontHeight,
+ w - ENUM_MARGIN * 2, fontHeight, Qt::AlignCenter, name);
+ font.setBold(false);
+ font.setItalic(false);
+ p.setFont(font);
+
+ int y = fontHeight * 2;
+
+ UMLWidget::setPen(p);
+
+ p.drawLine(offsetX, offsetY + y, offsetX + w - 1, offsetY + y);
+
+ QFontMetrics fontMetrics(font);
+ UMLClassifier *classifier = (UMLClassifier*)m_pObject;
+ UMLClassifierListItem* enumLiteral = 0;
+ UMLClassifierListItemList list = classifier->getFilteredList(Uml::ot_EnumLiteral);
+ for (enumLiteral = list.first(); enumLiteral; enumLiteral = list.next()) {
+ QString text = enumLiteral->getName();
+ p.setPen( QPen(Qt::black) );
+ p.drawText(offsetX + ENUM_MARGIN, offsetY + y,
+ fontMetrics.width(text), fontHeight, Qt::AlignVCenter, text);
+ y+=fontHeight;
+ }
+
+ if (m_bSelected) {
+ drawSelected(&p, offsetX, offsetY);
+ }
+}
+
+QSize EnumWidget::calculateSize() {
+ if (!m_pObject) {
+ return UMLWidget::calculateSize();
+ }
+
+ int width, height;
+ QFont font = UMLWidget::getFont();
+ font.setItalic(false);
+ font.setUnderline(false);
+ font.setBold(false);
+ const QFontMetrics fm(font);
+
+ const int fontHeight = fm.lineSpacing();
+
+ int lines = 1;//always have one line - for name
+ lines++; //for the stereotype
+
+ const int numberOfEnumLiterals = ((UMLEnum*)m_pObject)->enumLiterals();
+
+ height = width = 0;
+ //set the height of the enum
+
+ lines += numberOfEnumLiterals;
+ if (numberOfEnumLiterals == 0) {
+ height += fontHeight / 2; //no enum literals, so just add a bit of space
+ }
+
+ height += lines * fontHeight;
+
+ //now set the width of the concept
+ //set width to name to start with
+ if (m_bShowPackage) {
+ width = getFontMetrics(FT_BOLD_ITALIC).boundingRect(m_pObject->getFullyQualifiedName()).width();
+ } else {
+ width = getFontMetrics(FT_BOLD_ITALIC).boundingRect(getName()).width();
+ }
+ int w = getFontMetrics(FT_BOLD).boundingRect(m_pObject->getStereotype(true)).width();
+
+
+ width = w > width?w:width;
+
+ UMLClassifier *classifier = (UMLClassifier*)m_pObject;
+ UMLClassifierListItemList list = classifier->getFilteredList(Uml::ot_EnumLiteral);
+ UMLClassifierListItem* listItem = 0;
+ for (listItem = list.first(); listItem; listItem = list.next()) {
+ int w = fm.width( listItem->getName() );
+ width = w > width?w:width;
+ }
+
+ //allow for width margin
+ width += ENUM_MARGIN * 2;
+
+ return QSize(width, height);
+}
+
+void EnumWidget::slotMenuSelection(int sel) {
+ switch(sel) {
+ case ListPopupMenu::mt_EnumLiteral:
+ if (Object_Factory::createChildObject(static_cast<UMLClassifier*>(m_pObject),
+ Uml::ot_EnumLiteral) ) {
+ UMLApp::app()->getDocument()->setModified();
+ }
+ break;
+ }
+ UMLWidget::slotMenuSelection(sel);
+}
+
+void EnumWidget::setShowPackage(bool _status) {
+ m_bShowPackage = _status;
+ updateComponentSize();
+ update();
+}
+
+bool EnumWidget::getShowPackage() const {
+ return m_bShowPackage;
+}
+
+void EnumWidget::saveToXMI( QDomDocument& qDoc, QDomElement& qElement ) {
+ QDomElement conceptElement = qDoc.createElement("enumwidget");
+ UMLWidget::saveToXMI(qDoc, conceptElement);
+
+ conceptElement.setAttribute("showpackage", m_bShowPackage);
+ qElement.appendChild(conceptElement);
+}
+
+bool EnumWidget::loadFromXMI( QDomElement & qElement ) {
+ if ( !UMLWidget::loadFromXMI(qElement) ) {
+ return false;
+ }
+ QString showpackage = qElement.attribute("showpackage", "0");
+
+ m_bShowPackage = (bool)showpackage.toInt();
+
+ return true;
+}
+
+void EnumWidget::toggleShowPackage() {
+ m_bShowPackage = !m_bShowPackage;
+ updateComponentSize();
+ update();
+
+ return;
+}
+
diff --git a/umbrello/umbrello/enumwidget.h b/umbrello/umbrello/enumwidget.h
new file mode 100644
index 00000000..7022ac61
--- /dev/null
+++ b/umbrello/umbrello/enumwidget.h
@@ -0,0 +1,109 @@
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * copyright (C) 2003-2006 *
+ * Umbrello UML Modeller Authors <uml-devel@uml.sf.net> *
+ ***************************************************************************/
+
+#ifndef ENUMWIDGET_H
+#define ENUMWIDGET_H
+
+#include "umlwidget.h"
+
+class UMLView;
+
+#define ENUM_MARGIN 5
+
+/**
+ * Defines a graphical version of the enum. Most of the functionality
+ * will come from the @ref UMLWidget class from which class inherits from.
+ *
+ * @short A graphical version of an enum.
+ * @author Jonathan Riddell
+ * @see UMLWidget
+ * Bugs and comments to uml-devel@lists.sf.net or http://bugs.kde.org
+ */
+class EnumWidget : public UMLWidget {
+public:
+
+ /**
+ * Constructs an EnumWidget.
+ *
+ * @param view The parent of this EnumWidget.
+ * @param o The UMLObject this will be representing.
+ */
+ EnumWidget(UMLView* view, UMLObject* o);
+
+ /**
+ * Standard deconstructor.
+ */
+ ~EnumWidget();
+
+ /**
+ * Initializes key variables of the class.
+ */
+ void init();
+
+ /**
+ * Returns the status of whether to show Package.
+ *
+ * @return True if package is shown.
+ */
+ bool getShowPackage() const;
+
+ /**
+ * Toggles the status of whether to show package.
+ */
+ void toggleShowPackage();
+
+ /**
+ * Set the status of whether to show Package.
+ *
+ * @param _status True if package shall be shown.
+ */
+ void setShowPackage(bool _status);
+
+ /**
+ * Draws the enum as a rectangle with a box underneith with a list of literals
+ */
+ void draw(QPainter& p, int offsetX, int offsetY);
+
+ /**
+ * Saves to the "enumwidget" XMI element.
+ */
+ void saveToXMI(QDomDocument& qDoc, QDomElement& qElement);
+
+ /**
+ * Loads from an "enumwidget" XMI element.
+ */
+ bool loadFromXMI(QDomElement& qElement);
+
+protected:
+ /**
+ * Overrides method from UMLWidget.
+ */
+ QSize calculateSize();
+
+ bool m_bShowPackage;
+
+private:
+ /**
+ * The right mouse button menu.
+ */
+ ListPopupMenu* m_pMenu;
+
+public slots:
+ /**
+ * Will be called when a menu selection has been made from the
+ * popup menu.
+ *
+ * @param sel The selection id that has been selected.
+ */
+ void slotMenuSelection(int sel);
+};
+
+#endif
diff --git a/umbrello/umbrello/floatingtextwidget.cpp b/umbrello/umbrello/floatingtextwidget.cpp
new file mode 100644
index 00000000..44ea3373
--- /dev/null
+++ b/umbrello/umbrello/floatingtextwidget.cpp
@@ -0,0 +1,453 @@
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * copyright (C) 2002-2007 *
+ * Umbrello UML Modeller Authors <uml-devel@uml.sf.net> *
+ ***************************************************************************/
+
+// own header
+#include "floatingtextwidget.h"
+
+// system includes
+#include <qregexp.h>
+#include <qpainter.h>
+#include <qevent.h>
+#include <qvalidator.h>
+#include <klocale.h>
+#include <kdebug.h>
+#include <kinputdialog.h>
+
+// local includes
+#include "floatingtextwidgetcontroller.h"
+#include "association.h"
+#include "umlview.h"
+#include "umldoc.h"
+#include "uml.h"
+#include "classifier.h"
+#include "listpopupmenu.h"
+#include "operation.h"
+#include "model_utils.h"
+#include "object_factory.h"
+#include "messagewidget.h"
+#include "dialogs/assocpropdlg.h"
+#include "dialogs/selectopdlg.h"
+
+
+FloatingTextWidget::FloatingTextWidget(UMLView * view, Uml::Text_Role role,
+ const QString& text, Uml::IDType id)
+ : UMLWidget(view, id, new FloatingTextWidgetController(this))
+{
+ init();
+ m_Text = text;
+ m_Role = role;
+ if ( ! UMLApp::app()->getDocument()->loading() ) {
+ updateComponentSize();
+ setZ( 10 );//make sure always on top.
+ update();
+ }
+}
+
+void FloatingTextWidget::init() {
+ // initialize loaded/saved (i.e. persistent) data
+ m_PreText = "";
+ m_Text = "";
+ m_PostText = "";
+ m_Role = Uml::tr_Floating;
+ m_Type = Uml::wt_Text;
+ // initialize non-saved (i.e. volatile) data
+ m_pLink = NULL;
+ UMLWidget::m_bResizable = false;
+}
+
+FloatingTextWidget::~FloatingTextWidget() {
+}
+
+void FloatingTextWidget::draw(QPainter & p, int offsetX, int offsetY) {
+ int w = width();
+ int h = height();
+ p.setFont( UMLWidget::getFont() );
+ QColor textColor(50, 50, 50);
+ p.setPen(textColor);
+ p.drawText( offsetX , offsetY,w,h, Qt::AlignCenter, getDisplayText() );
+ if(m_bSelected)
+ drawSelected(&p, offsetX, offsetY);
+}
+
+void FloatingTextWidget::resizeEvent(QResizeEvent * /*re*/) {}
+
+QSize FloatingTextWidget::calculateSize() {
+ const QFontMetrics &fm = getFontMetrics(FT_NORMAL);
+ int h = fm.lineSpacing();
+ int w = fm.width( getDisplayText() );
+ return QSize(w + 8, h + 4); // give a small margin
+}
+
+void FloatingTextWidget::slotMenuSelection(int sel) {
+ switch(sel) {
+ case ListPopupMenu::mt_Properties:
+ showProperties();
+ break;
+
+ case ListPopupMenu::mt_Delete:
+ m_pView -> removeWidget(this);
+ break;
+
+ case ListPopupMenu::mt_Operation:
+ {
+ kDebug() << "FloatingTextWidget::slotMenuSelection(mt_Operation) is called."
+ << endl;
+ if (m_pLink == NULL) {
+ kDebug() << "FloatingTextWidget::slotMenuSelection(mt_Operation): "
+ << "m_pLink is NULL" << endl;
+ return;
+ }
+ UMLClassifier* c = m_pLink->getOperationOwner();
+ if (c == NULL) {
+ bool ok = false;
+ QString opText = KInputDialog::getText(i18n("Name"),
+ i18n("Enter operation name:"),
+ getText(), &ok, m_pView);
+ if (ok)
+ m_pLink->setCustomOpText(opText);
+ return;
+ }
+ UMLClassifierListItem* umlObj = Object_Factory::createChildObject(c, Uml::ot_Operation);
+ if (umlObj) {
+ UMLOperation* newOperation = static_cast<UMLOperation*>( umlObj );
+ m_pLink->setOperation(newOperation);
+ }
+ }
+ break;
+
+ case ListPopupMenu::mt_Select_Operation:
+ showOpDlg();
+ break;
+
+ case ListPopupMenu::mt_Rename:
+ handleRename();
+ break;
+
+ case ListPopupMenu::mt_Change_Font:
+ {
+ QFont font = getFont();
+ if( KFontDialog::getFont( font, false, m_pView ) ) {
+ if( m_Role == Uml::tr_Floating || m_Role == Uml::tr_Seq_Message ) {
+ setFont( font );
+ } else if (m_pLink) {
+ m_pLink->lwSetFont(font);
+ }
+ }
+ }
+ break;
+
+ case ListPopupMenu::mt_Reset_Label_Positions:
+ if (m_pLink)
+ m_pLink->resetTextPositions();
+ break;
+
+ default:
+ UMLWidget::slotMenuSelection(sel);
+ break;
+ }//end switch
+}
+
+void FloatingTextWidget::handleRename() {
+ QRegExpValidator v(QRegExp(".*"), 0);
+ QString t;
+ if( m_Role == Uml::tr_RoleAName || m_Role == Uml::tr_RoleBName ) {
+ t = i18n("Enter role name:");
+ } else if (m_Role == Uml::tr_MultiA || m_Role == Uml::tr_MultiB) {
+ t = i18n("Enter multiplicity:");
+ /*
+ // NO! shouldn't be allowed
+ } else if( m_Role == Uml::tr_ChangeA || m_Role == Uml::tr_ChangeB ) {
+ t = i18n("Enter changeability");
+ */
+ } else if (m_Role == Uml::tr_Name) {
+ t = i18n("Enter association name:");
+ } else if (m_Role == Uml::tr_Floating) {
+ t = i18n("Enter new text:");
+ } else {
+ t = i18n("ERROR");
+ }
+ bool ok = false;
+ QString newText = KInputDialog::getText(i18n("Rename"), t, getText(), &ok,
+ m_pView, NULL, &v);
+ if (!ok || newText == getText())
+ return;
+}
+
+void FloatingTextWidget::changeName(const QString& newText)
+{
+
+ if (m_pLink && !isTextValid(newText)) {
+ AssociationWidget *assoc = dynamic_cast<AssociationWidget*>(m_pLink);
+ if (assoc) {
+ switch (m_Role) {
+ case Uml::tr_MultiA:
+ assoc->setMulti(QString(), Uml::A);
+ break;
+ case Uml::tr_MultiB:
+ assoc->setMulti(QString(), Uml::B);
+ break;
+ case Uml::tr_RoleAName:
+ assoc->setRoleName(QString(), Uml::A);
+ break;
+ case Uml::tr_RoleBName:
+ assoc->setRoleName(QString(), Uml::B);
+ break;
+ case Uml::tr_ChangeA:
+ assoc->setChangeability(Uml::chg_Changeable, Uml::A);
+ break;
+ case Uml::tr_ChangeB:
+ assoc->setChangeability(Uml::chg_Changeable, Uml::B);
+ break;
+ default:
+ assoc->setName(QString());
+ break;
+ }
+ } else {
+ MessageWidget *msg = dynamic_cast<MessageWidget*>(m_pLink);
+ if (msg) {
+ msg->setName(QString());
+ m_pView->removeWidget(this);
+ }
+ }
+ return;
+ }
+ if (m_pLink && m_Role != Uml::tr_Seq_Message && m_Role != Uml::tr_Seq_Message_Self) {
+ m_pLink->setText(this, newText);
+ } else {
+ setText( newText );
+ UMLApp::app()->getDocument()->setModified(true);
+ }
+ setVisible( true );
+ updateComponentSize();
+ update();
+}
+
+void FloatingTextWidget::setText(const QString &t) {
+ if (m_Role == Uml::tr_Seq_Message || m_Role == Uml::tr_Seq_Message_Self) {
+ QString seqNum, op;
+ m_pLink->getSeqNumAndOp(seqNum, op);
+ if (seqNum.length() > 0 || op.length() > 0) {
+ if (! m_pView->getShowOpSig())
+ op.replace( QRegExp("\\(.*\\)"), "()" );
+ m_Text = seqNum.append(": ").append( op );
+ } else
+ m_Text = t;
+ } else
+ m_Text = t;
+ updateComponentSize();
+ update();
+}
+
+void FloatingTextWidget::setPreText (const QString &t)
+{
+ m_PreText = t;
+ updateComponentSize();
+ update();
+}
+
+void FloatingTextWidget::setPostText(const QString &t) {
+ m_PostText = t;
+ updateComponentSize();
+ update();
+}
+
+void FloatingTextWidget::changeTextDlg() {
+ bool ok = false;
+ QString newText = KInputDialog::getText(i18n("Change Text"), i18n("Enter new text:"), getText(), &ok, m_pView);
+
+ if(ok && newText != getText() && isTextValid(newText)) {
+ setText( newText );
+ setVisible( ( getText().length() > 0 ) );
+ updateComponentSize();
+ update();
+ }
+ if(!isTextValid(newText))
+ hide();
+}
+
+void FloatingTextWidget::showOpDlg() {
+ if (m_pLink == NULL) {
+ kError() << "FloatingTextWidget::showOpDlg: m_pLink is NULL" << endl;
+ return;
+ }
+ QString seqNum, opText;
+ UMLClassifier* c = m_pLink->getSeqNumAndOp(seqNum, opText);
+ if (c == NULL) {
+ kError() << "FloatingTextWidget::showOpDlg: "
+ << "m_pLink->getSeqNumAndOp() returns a NULL classifier"
+ << endl;
+ return;
+ }
+
+ SelectOpDlg selectDlg(m_pView, c);
+ selectDlg.setSeqNumber( seqNum );
+ if (m_pLink->getOperation() == NULL) {
+ selectDlg.setCustomOp( opText );
+ } else {
+ selectDlg.setClassOp( opText );
+ }
+ int result = selectDlg.exec();
+ if(!result) {
+ return;
+ }
+ seqNum = selectDlg.getSeqNumber();
+ opText = selectDlg.getOpText();
+ if (selectDlg.isClassOp()) {
+ Model_Utils::OpDescriptor od;
+ Model_Utils::Parse_Status st = Model_Utils::parseOperation(opText, od, c);
+ if (st == Model_Utils::PS_OK) {
+ UMLClassifierList selfAndAncestors = c->findSuperClassConcepts();
+ selfAndAncestors.prepend(c);
+ UMLOperation *op = NULL;
+ for (UMLClassifier *cl = selfAndAncestors.first(); cl; cl = selfAndAncestors.next()) {
+ op = cl->findOperation(od.m_name, od.m_args);
+ if (op != NULL)
+ break;
+ }
+ if (op == NULL) {
+ // The op does not yet exist. Create a new one.
+ UMLObject *o = c->createOperation(od.m_name, NULL, &od.m_args);
+ op = static_cast<UMLOperation*>(o);
+ }
+ if (od.m_pReturnType)
+ op->setType(od.m_pReturnType);
+ m_pLink->setOperation(op);
+ opText = QString();
+ } else {
+ m_pLink->setOperation(NULL);
+ }
+ } else {
+ m_pLink->setOperation(NULL);
+ }
+ m_pLink->setSeqNumAndOp(seqNum, opText);
+ setMessageText();
+}
+
+QString FloatingTextWidget::getPreText() const {
+ return m_PreText;
+}
+
+QString FloatingTextWidget::getPostText() const {
+ return m_PostText;
+}
+
+QString FloatingTextWidget::getText() const {
+ //test to make sure not just the ":" between the seq number
+ //and the actual message widget
+ // hmm. this section looks like it could have been avoided by using pre-, post- text
+ // instead of storing in the main body of the text -b.t.
+ if(m_Role == Uml::tr_Seq_Message || m_Role == Uml::tr_Seq_Message_Self ||
+ m_Role == Uml::tr_Coll_Message || m_Role == Uml::tr_Coll_Message_Self) {
+ if( m_Text.length() <= 1 || m_Text == ": " )
+ return "";
+ }
+ return m_Text;
+}
+
+QString FloatingTextWidget::getDisplayText() const
+{
+ QString displayText = m_Text;
+ displayText.prepend(m_PreText);
+ displayText.append(m_PostText);
+ return displayText;
+}
+
+bool FloatingTextWidget::activate( IDChangeLog* ChangeLog /*= 0 */) {
+ if (! UMLWidget::activate(ChangeLog))
+ return false;
+ update();
+ return true;
+}
+
+void FloatingTextWidget::setLink(LinkWidget * l) {
+ m_pLink = l;
+}
+
+LinkWidget * FloatingTextWidget::getLink() {
+ return m_pLink;
+}
+
+void FloatingTextWidget::setRole(Uml::Text_Role role) {
+ m_Role = role;
+}
+
+Uml::Text_Role FloatingTextWidget::getRole() const {
+ return m_Role;
+}
+
+bool FloatingTextWidget::isTextValid( const QString &text ) {
+ int length = text.length();
+ if(length < 1)
+ return false;
+ for(int i=0;i<length;i++)
+ if(!text.at(i).isSpace())
+ return true;
+ return false;
+}
+
+void FloatingTextWidget::showProperties() {
+ if (m_Role == Uml::tr_Coll_Message || m_Role == Uml::tr_Coll_Message_Self ||
+ m_Role == Uml::tr_Seq_Message || m_Role == Uml::tr_Seq_Message_Self) {
+ showOpDlg();
+ } else if (m_Role == Uml::tr_Floating) {
+ // double clicking on a text line opens the dialog to change the text
+ handleRename();
+ } else if (m_pLink) {
+ m_pLink->showDialog();
+ }
+}
+
+void FloatingTextWidget::saveToXMI( QDomDocument & qDoc, QDomElement & qElement ) {
+ QDomElement textElement = qDoc.createElement( "floatingtext" );
+ UMLWidget::saveToXMI( qDoc, textElement );
+ textElement.setAttribute( "text", m_Text );
+ textElement.setAttribute( "pretext", m_PreText );
+ textElement.setAttribute( "posttext", m_PostText );
+
+ /* No need to save these - the messagewidget already did it.
+ m_Operation = qElement.attribute( "operation", "" );
+ m_SeqNum = qElement.attribute( "seqnum", "" );
+ */
+
+ textElement.setAttribute( "role", m_Role );
+ qElement.appendChild( textElement );
+}
+
+bool FloatingTextWidget::loadFromXMI( QDomElement & qElement ) {
+ if( !UMLWidget::loadFromXMI( qElement ) )
+ return false;
+
+ QString role = qElement.attribute( "role", "" );
+ if( !role.isEmpty() )
+ m_Role = (Uml::Text_Role)role.toInt();
+
+ m_PreText = qElement.attribute( "pretext", "" );
+ m_PostText = qElement.attribute( "posttext", "" );
+ m_Text = qElement.attribute( "text", "" );
+ // If all texts are empty then this is a useless widget.
+ // In that case we return false.
+ // CAVEAT: The caller should not interpret the false return value
+ // as an indication of failure since previous umbrello versions
+ // saved lots of these empty FloatingTexts.
+ bool isDummy = (m_Text.isEmpty() && m_PreText.isEmpty() && m_PostText.isEmpty());
+ return !isDummy;
+}
+
+void FloatingTextWidget::setMessageText() {
+ if (m_pLink)
+ m_pLink->setMessageText(this);
+ setVisible(getText().length() > 0);
+ updateComponentSize();
+}
+
+
+#include "floatingtextwidget.moc"
+
diff --git a/umbrello/umbrello/floatingtextwidget.h b/umbrello/umbrello/floatingtextwidget.h
new file mode 100644
index 00000000..a8a1bfa8
--- /dev/null
+++ b/umbrello/umbrello/floatingtextwidget.h
@@ -0,0 +1,303 @@
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * copyright (C) 2002-2006 *
+ * Umbrello UML Modeller Authors <uml-devel@uml.sf.net> *
+ ***************************************************************************/
+
+#ifndef FLOATINGTEXTWIDGET_H
+#define FLOATINGTEXTWIDGET_H
+
+#include "umlwidget.h"
+#include "linkwidget.h"
+
+class UMLView;
+
+class FloatingTextWidgetController;
+
+/**
+ * This is a multipurpose class. In its simplest form it will display a
+ * line of text.
+ * It can also be setup to be the text for an operation with regard to the
+ * @ref MessageWidget on the sequence diagram.
+ * It is also used for the text required for an association.
+ *
+ * The differences between all these different uses will be the popup menu
+ * that is associated with it.
+ *
+ * @short Displays a line of text or an operation.
+ * @author Paul Hensgen <phensgen@techie.com>
+ * @see UMLWidget
+ * Bugs and comments to uml-devel@lists.sf.net or http://bugs.kde.org
+ */
+
+class FloatingTextWidget : public UMLWidget {
+ Q_OBJECT
+public:
+ friend class FloatingTextWidgetController;
+
+ /** sometimes the x/y values get numbers of <0 and >10000 - which is
+ probably due to a bug somewhere in calculating the position.
+ -> workaround till problem is found: define min and max limits
+ => if x or y is outside of interval, the position is reset
+ ( e.g. by AssociationWidget::resetTextPositions() )
+ */
+ static const int restrictPositionMin = 0;
+ static const int restrictPositionMax = 3000;
+
+
+ /**
+ * Constructs a FloatingTextWidget instance.
+ *
+ * @param view The parent of this FloatingTextWidget.
+ * @param role The role this FloatingTextWidget will take up.
+ * @param text The main text to display.
+ * @param id The ID to assign (-1 will prompt a new ID.)
+ */
+ explicit FloatingTextWidget(UMLView * view, Uml::Text_Role role = Uml::tr_Floating,
+ const QString& text = "", Uml::IDType id = Uml::id_None);
+
+ /**
+ * destructor
+ */
+ virtual ~FloatingTextWidget();
+
+ /**
+ * Set the main body of text to display.
+ *
+ * @param t The text to display.
+ */
+ void setText(const QString &t);
+
+ /**
+ * Set some text to be prepended to the main body of text.
+ * @param t The text to prepend to main body which is displayed.
+ */
+ void setPreText(const QString &t);
+
+ /**
+ * Set some text to be appended to the main body of text.
+ * @param t The text to append to main body which is displayed.
+ */
+ void setPostText(const QString &t);
+
+ /**
+ * Set the sequence number to display.
+ *
+ * @param sn The sequence number to display.
+ */
+ void setSeqNum(const QString &sn);
+
+ /**
+ * Return the sequence number.
+ *
+ * @return The sequence number.
+ */
+ QString getSeqNum() const;
+
+ /**
+ * Set the operation to display.
+ *
+ * @param op The operation to display.
+ */
+ void setOperation(const QString &op);
+
+ /**
+ * Return the operation that is displayed.
+ *
+ * @return The operation that is displayed.
+ *
+ QString getOperation() const;
+ */
+
+ /**
+ * Use to get the _main body_ of text (e.g. prepended and appended
+ * text is omitted) as currently displayed by the widget.
+ *
+ * @return The main text currently being displayed by the widget.
+ */
+ QString getText() const;
+
+ /**
+ * Use to get the pre-text which is prepended to the main body of
+ * text to be displayed.
+ *
+ * @return The pre-text currently displayed by the widget.
+ */
+ QString getPreText() const;
+
+ /**
+ * Use to get the post-text which is appended to the main body of
+ * text to be displayed.
+ *
+ * @return The post-text currently displayed by the widget.
+ */
+ QString getPostText() const;
+
+ /**
+ * Use to get the total text (prepended + main body + appended)
+ * currently displayed by the widget.
+ *
+ * @return The text currently being displayed by the widget.
+ */
+ QString getDisplayText() const;
+
+ /**
+ * Displays a dialog box to change the text.
+ */
+ void changeTextDlg();
+
+ /**
+ * Set the LinkWidget that this FloatingTextWidget is related to.
+ *
+ * @param l The related LinkWidget.
+ */
+ void setLink(LinkWidget * l);
+
+ /**
+ * Returns the LinkWidget this floating text is related to.
+ *
+ * @return The LinkWidget this floating text is related to.
+ */
+ LinkWidget * getLink();
+
+ /**
+ * Returns whether this is a line of text.
+ * Used for transparency in printing.
+ *
+ * @return Returns whether this is a line of text.
+ */
+ bool isText() {
+ return true;
+ }
+
+ /**
+ * Activate the FloatingTextWidget after the saved data has been loaded
+ *
+ * @param ChangeLog Pointer to the IDChangeLog.
+ * @return true for success
+ */
+ bool activate( IDChangeLog* ChangeLog = 0 );
+
+ /**
+ * Sets the role type of this FloatingTextWidget.
+ *
+ * @param role The Text_Role of this FloatingTextWidget.
+ */
+ void setRole(Uml::Text_Role role);
+
+ /**
+ * Return the role of the text widget
+ *
+ * @return The Text_Role of this FloatingTextWidget.
+ */
+ Uml::Text_Role getRole() const;
+
+ /**
+ * For a text to be valid it must be non-empty, i.e. have a length
+ * larger that zero, and have at least one non whitespace character.
+ *
+ * @param text The string to analyze.
+ * @return True if the given text is valid.
+ */
+ static bool isTextValid(const QString &text);
+
+ /**
+ * Overrides default method
+ */
+ void draw(QPainter & p, int offsetX, int offsetY);
+
+ /**
+ * Handle the ListPopupMenu::mt_Rename case of the slotMenuSelection.
+ * Given an own method because it requires rather lengthy code.
+ */
+ void handleRename();
+
+ /**
+ * Change Name
+ */
+ void changeName(const QString& newText);
+
+ /**
+ * Shows an operation dialog box.
+ */
+ void showOpDlg();
+
+ /**
+ * Show the properties for a FloatingTextWidget.
+ * Depending on the role of the floating text wiget, the options dialog
+ * for the floating text widget, the rename dialog for floating text or
+ * the options dialog for the link widget are shown.
+ */
+ void showProperties();
+
+ /**
+ * Creates the "floatingtext" XMI element.
+ */
+ void saveToXMI( QDomDocument & qDoc, QDomElement & qElement );
+
+ /**
+ * Loads the "floatingtext" XMI element.
+ */
+ bool loadFromXMI( QDomElement & qElement );
+
+public slots:
+ /**
+ * Called when a menu selection has been made.
+ * This method is public due to called by @ref MessageWidget
+ * when this is text for a @ref MessageWidget.
+ *
+ * @param sel The selection that has been made.
+ */
+ void slotMenuSelection(int sel);
+
+ /**
+ * Sets the text for this label if it is acting as a sequence
+ * diagram message or a collaboration diagram message.
+ */
+ void setMessageText();
+
+protected:
+ /**
+ * Overrides method from UMLWidget.
+ */
+ QSize calculateSize();
+
+private:
+ /**
+ * Initializes key variables of the class.
+ */
+ void init();
+
+ /**
+ * Override default method
+ */
+ void resizeEvent(QResizeEvent* /*re*/);
+
+ /**
+ * The association or message widget we may be linked to.
+ */
+ LinkWidget * m_pLink;
+
+ //////////////////// Data loaded/saved:
+
+ /// Prepended text (such as for scope of association Role or method)
+ QString m_PreText;
+ /**
+ * Ending text (such as bracket on changability notation for
+ * association Role)
+ */
+ QString m_PostText;
+
+ /**
+ * The role the text widget will enact.
+ */
+ Uml::Text_Role m_Role;
+
+};
+
+#endif
diff --git a/umbrello/umbrello/floatingtextwidgetcontroller.cpp b/umbrello/umbrello/floatingtextwidgetcontroller.cpp
new file mode 100644
index 00000000..4c6a4aa8
--- /dev/null
+++ b/umbrello/umbrello/floatingtextwidgetcontroller.cpp
@@ -0,0 +1,119 @@
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * copyright (C) 2006 *
+ * Umbrello UML Modeller Authors <uml-devel@uml.sf.net> *
+ ***************************************************************************/
+
+// own header
+#include "floatingtextwidgetcontroller.h"
+// qt/kde includes
+#include <kdebug.h>
+// app includes
+#include "floatingtextwidget.h"
+#include "messagewidget.h"
+#include "objectwidget.h"
+
+FloatingTextWidgetController::FloatingTextWidgetController(FloatingTextWidget *floatingTextWidget):
+ UMLWidgetController(floatingTextWidget) {
+ m_floatingTextWidget = floatingTextWidget;
+ m_unconstrainedPositionX = 0;
+ m_unconstrainedPositionY = 0;
+ m_movementDirectionX = 0;
+ m_movementDirectionY = 0;
+}
+
+FloatingTextWidgetController::~FloatingTextWidgetController() {
+}
+
+void FloatingTextWidgetController::saveWidgetValues(QMouseEvent *me) {
+ UMLWidgetController::saveWidgetValues(me);
+
+ m_unconstrainedPositionX = m_widget->getX();
+ m_unconstrainedPositionY = m_widget->getY();
+ m_movementDirectionX = 0;
+ m_movementDirectionY = 0;
+}
+
+bool FloatingTextWidgetController::isInResizeArea(QMouseEvent* /*me*/) {
+ return false;
+}
+
+void FloatingTextWidgetController::moveWidgetBy(int diffX, int diffY) {
+ if (m_floatingTextWidget->m_Role == Uml::tr_Seq_Message_Self)
+ return;
+
+ if (m_floatingTextWidget->m_Role == Uml::tr_Seq_Message
+ && ((MessageWidget*)m_floatingTextWidget->m_pLink)->getSelected()) {
+ return;
+ }
+
+ m_unconstrainedPositionX += diffX;
+ m_unconstrainedPositionY += diffY;
+ QPoint constrainedPosition = constrainPosition(diffX, diffY);
+
+ int newX = constrainedPosition.x();
+ int newY = constrainedPosition.y();
+
+ if (!m_movementDirectionX) {
+ if (m_unconstrainedPositionX != constrainedPosition.x()) {
+ m_movementDirectionX = (diffX > 0)? 1: -1;
+ }
+ } else if ((m_movementDirectionX < 0 && m_unconstrainedPositionX > m_floatingTextWidget->getX()) ||
+ (m_movementDirectionX > 0 && m_unconstrainedPositionX < m_floatingTextWidget->getX()) ) {
+ newX = m_unconstrainedPositionX;
+ m_movementDirectionX = 0;
+ }
+
+ if (!m_movementDirectionY) {
+ if (m_unconstrainedPositionY != constrainedPosition.y()) {
+ m_movementDirectionY = (diffY > 0)? 1: -1;
+ }
+ } else if ((m_movementDirectionY < 0 && m_unconstrainedPositionY > m_floatingTextWidget->getY()) ||
+ (m_movementDirectionY > 0 && m_unconstrainedPositionY < m_floatingTextWidget->getY()) ) {
+ newY = m_unconstrainedPositionY;
+ m_movementDirectionY = 0;
+ }
+
+ m_floatingTextWidget->setX(newX);
+ m_floatingTextWidget->setY(newY);
+
+ if (m_floatingTextWidget->m_pLink) {
+ m_floatingTextWidget->m_pLink->calculateNameTextSegment();
+ if (m_floatingTextWidget->m_Role == Uml::tr_Seq_Message) {
+ MessageWidget* messageWidget = (MessageWidget*)m_floatingTextWidget->m_pLink;
+ messageWidget->setY(newY + m_floatingTextWidget->getHeight());
+
+ //TODO This should be moved to somewhere in MessageWidget, refactor with messagewidgetcontroller.cpp:44
+ if (messageWidget->getSequenceMessageType() == Uml::sequence_message_creation) {
+ const int objWidgetHalfHeight = messageWidget->getWidget(Uml::B)->getHeight() / 2;
+ messageWidget->getWidget(Uml::B)->UMLWidget::setY(messageWidget->getY() - objWidgetHalfHeight);
+ }
+ }
+ }
+}
+
+void FloatingTextWidgetController::constrainMovementForAllWidgets(int &diffX, int &diffY) {
+ QPoint constrainedPosition = constrainPosition(diffX, diffY);
+
+ diffX = constrainedPosition.x() - m_floatingTextWidget->getX();
+ diffY = constrainedPosition.y() - m_floatingTextWidget->getY();
+}
+
+QPoint FloatingTextWidgetController::constrainPosition(int diffX, int diffY) {
+ int newX = m_floatingTextWidget->getX() + diffX;
+ int newY = m_floatingTextWidget->getY() + diffY;
+
+ if (m_floatingTextWidget->m_pLink) {
+ m_floatingTextWidget->m_pLink->constrainTextPos(newX, newY,
+ m_floatingTextWidget->width(), m_floatingTextWidget->height(),
+ m_floatingTextWidget->m_Role);
+ }
+
+ return QPoint(newX, newY);
+}
+
diff --git a/umbrello/umbrello/floatingtextwidgetcontroller.h b/umbrello/umbrello/floatingtextwidgetcontroller.h
new file mode 100644
index 00000000..f73b359a
--- /dev/null
+++ b/umbrello/umbrello/floatingtextwidgetcontroller.h
@@ -0,0 +1,152 @@
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * copyright (C) 2006-2007 *
+ * Umbrello UML Modeller Authors <uml-devel@uml.sf.net> *
+ ***************************************************************************/
+
+#ifndef FLOATINGTEXTWIDGETCONTROLLER_H
+#define FLOATINGTEXTWIDGETCONTROLLER_H
+
+#include "umlwidgetcontroller.h"
+
+class FloatingTextWidget;
+
+/**
+ * Controller for FloatingTextWidget.
+ *
+ * When moving a FloatingTextWidget, it is constrained using constrainTextPos
+ * method from the LinkWidget, if any.
+ * This applies both when moving as part of a selection and when constraining
+ * the move of the selection because it's the receiver of mouse move events.
+ * The only exception to this is that when moving the widget, if it's a sequence
+ * message and the message widget is selected, the floating text widget isn't
+ * moved itself, but automatically by the message widget.
+ * If the sequence message wasn't part of the selection, the floating text
+ * widget moves it.
+ * When moving the floating text as part of a selection, if the position of
+ * the floating text is constrained, it's kept at that position until it can
+ * be moved to another valid position.
+ * No resize is allowed for FloatingTextWidget.
+ *
+ * @author Umbrello UML Modeller Authors <uml-devel@lists.sourceforge.net>
+ */
+class FloatingTextWidgetController : public UMLWidgetController {
+public:
+
+ /**
+ * Constructor for FloatingTextWidgetController.
+ *
+ * @param floatingTextWidget The floating text widget which uses the controller.
+ */
+ FloatingTextWidgetController(FloatingTextWidget *floatingTextWidget);
+
+ /**
+ * Destructor for MessageWidgetController.
+ */
+ ~FloatingTextWidgetController();
+
+protected:
+
+ /**
+ * Overridden from UMLWidgetController.
+ * Saves the values of the widget needed for move/resize.
+ * Calls parent method and then saves the value of m_unconstrainedPositionX/Y
+ * and m_movementDirectionX/Y.
+ *
+ * @param me The QMouseEvent to get the offset from.
+ */
+ virtual void saveWidgetValues(QMouseEvent *me);
+
+ /**
+ * Overridden from UMLWidgetController.
+ * FloatingTextWidgets can't be resized, so this method always returns false.
+ * Cursor isn't changed.
+ *
+ * @param me The QMouseEVent to check.
+ * @return true if the mouse is in resize area, false otherwise.
+ */
+ virtual bool isInResizeArea(QMouseEvent *me);
+
+ /**
+ * Overridden from UMLWidgetController.
+ * Moves the widget to a new position using the difference between the
+ * current position and the new position.
+ * If the floating text widget is part of a sequence message, and the
+ * message widget is selected, it does nothing: the message widget will
+ * update the text position when it's moved.
+ * In any other case, the floating text widget constrains its move using
+ * constrainPosition. When the position of the floating text is constrained,
+ * it's kept at that position until it can be moved to another valid
+ * position (m_unconstrainedPositionX/Y and m_movementDirectionX/Y are
+ * used for that).
+ * Moreover, if is part of a sequence message (and the message widget
+ * isn't selected), it updates the position of the message widget.
+ * @see constrainPosition
+ *
+ * @param diffX The difference between current X position and new X position.
+ * @param diffY The difference between current Y position and new Y position.
+ */
+ virtual void moveWidgetBy(int diffX, int diffY);
+
+ /**
+ * Overridden from UMLWidgetController.
+ * Modifies the value of the diffX and diffY variables used to move the
+ * widgets.
+ * The values are constrained using constrainPosition.
+ * @see constrainPosition
+ *
+ * @param diffX The difference between current X position and new X position.
+ * @param diffY The difference between current Y position and new Y position.
+ */
+ virtual void constrainMovementForAllWidgets(int &diffX, int &diffY);
+
+private:
+
+ /**
+ * Returns a constrained position for the widget after applying the position
+ * difference.
+ * If no link widget exists, the position returned is the current widget
+ * position with the difference applied. If there's a link, the position
+ * to be returned is constrained using constrainTextPos method from the
+ * LinkWidget, if any.
+ *
+ * @param diffX The difference between current X position and new X position.
+ * @param diffY The difference between current Y position and new Y position.
+ * @return A QPoint with the constrained new position.
+ */
+ QPoint constrainPosition(int diffX, int diffY);
+
+ /**
+ * The floating text widget which uses the controller.
+ */
+ FloatingTextWidget *m_floatingTextWidget;
+
+ /**
+ * The horizontal position the widget would have if its move wasn't constrained.
+ */
+ int m_unconstrainedPositionX;
+
+ /**
+ * The vertical position the widget would have if its move wasn't constrained.
+ */
+ int m_unconstrainedPositionY;
+
+ /**
+ * The X direction the widget was moved when the constrain was applied.
+ * -1 means left, 1 means right.
+ */
+ int m_movementDirectionX;
+
+ /**
+ * The Y direction the widget was moved when the constrain was applied.
+ * -1 means up, 1 means down.
+ */
+ int m_movementDirectionY;
+};
+
+#endif
diff --git a/umbrello/umbrello/folder.cpp b/umbrello/umbrello/folder.cpp
new file mode 100644
index 00000000..8317bab1
--- /dev/null
+++ b/umbrello/umbrello/folder.cpp
@@ -0,0 +1,412 @@
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * copyright (C) 2006 *
+ * Umbrello UML Modeller Authors <uml-devel@uml.sf.net> *
+ ***************************************************************************/
+
+// own header
+#include "folder.h"
+// qt/kde includes
+#include <qfile.h>
+#include <kdebug.h>
+#include <klocale.h>
+#include <kmessagebox.h>
+// app includes
+#include "uml.h"
+#include "umldoc.h"
+#include "umlview.h"
+#include "umllistview.h"
+#include "optionstate.h"
+#include "object_factory.h"
+#include "model_utils.h"
+
+UMLFolder::UMLFolder(const QString & name, Uml::IDType id)
+ : UMLPackage(name, id) {
+ init();
+}
+
+UMLFolder::~UMLFolder() {
+}
+
+void UMLFolder::init() {
+ m_BaseType = Uml::ot_Folder;
+ m_diagrams.setAutoDelete(true);
+ UMLObject::setStereotype("folder");
+}
+
+UMLObject* UMLFolder::clone() const {
+ UMLFolder *clone = new UMLFolder();
+ UMLObject::copyInto(clone);
+ return clone;
+}
+
+void UMLFolder::setLocalName(const QString& localName) {
+ m_localName = localName;
+}
+
+QString UMLFolder::getLocalName() {
+ return m_localName;
+}
+
+void UMLFolder::addView(UMLView *view) {
+ m_diagrams.append(view);
+}
+
+void UMLFolder::removeView(UMLView *view) {
+ // m_diagrams is set to autodelete!
+ m_diagrams.remove(view);
+}
+
+void UMLFolder::appendViews(UMLViewList& viewList, bool includeNested) {
+ if (includeNested) {
+ UMLObject *o;
+ for (UMLObjectListIt oit(m_objects); (o = oit.current()) != NULL; ++oit) {
+ if (o->getBaseType() == Uml::ot_Folder) {
+ UMLFolder *f = static_cast<UMLFolder*>(o);
+ f->appendViews(viewList);
+ }
+ }
+ }
+ UMLView *v;
+ for (UMLViewListIt vit(m_diagrams); (v = vit.current()) != NULL; ++vit)
+ viewList.append(v);
+}
+
+void UMLFolder::activateViews() {
+ UMLObject *o;
+ for (UMLObjectListIt oit(m_objects); (o = oit.current()) != NULL; ++oit) {
+ if (o->getBaseType() == Uml::ot_Folder) {
+ UMLFolder *f = static_cast<UMLFolder*>(o);
+ f->activateViews();
+ }
+ }
+ UMLView *v;
+ for (UMLViewListIt vit(m_diagrams); (v = vit.current()) != NULL; ++vit)
+ v->activateAfterLoad();
+ // Make sure we have a treeview item for each diagram.
+ // It may happen that we are missing them after switching off tabbed widgets.
+ Settings::OptionState optionState = Settings::getOptionState();
+ if (optionState.generalState.tabdiagrams)
+ return;
+ UMLListView *lv = UMLApp::app()->getListView();
+ for (UMLViewListIt it(m_diagrams); (v = it.current()) != NULL; ++it) {
+ if (lv->findItem(v->getID()) != NULL)
+ continue;
+ lv->createDiagramItem(v);
+ }
+}
+
+UMLView *UMLFolder::findView(Uml::IDType id) {
+ UMLView *v = NULL;
+ for (UMLViewListIt vit(m_diagrams); (v = vit.current()) != NULL; ++vit) {
+ if (v->getID() == id)
+ return v;
+ }
+ UMLObject *o;
+ for (UMLObjectListIt oit(m_objects); (o = oit.current()) != NULL; ++oit) {
+ if (o->getBaseType() != Uml::ot_Folder)
+ continue;
+ UMLFolder *f = static_cast<UMLFolder*>(o);
+ v = f->findView(id);
+ if (v)
+ break;
+ }
+ return v;
+}
+
+UMLView *UMLFolder::findView(Uml::Diagram_Type type, const QString &name, bool searchAllScopes) {
+ UMLView *v = NULL;
+ for (UMLViewListIt vit(m_diagrams); (v = vit.current()) != NULL; ++vit) {
+ if (v->getType() == type && v->getName() == name)
+ return v;
+ }
+ if (searchAllScopes) {
+ UMLObject *o;
+ for (UMLObjectListIt oit(m_objects); (o = oit.current()) != NULL; ++oit) {
+ if (o->getBaseType() != Uml::ot_Folder)
+ continue;
+ UMLFolder *f = static_cast<UMLFolder*>(o);
+ v = f->findView(type, name, searchAllScopes);
+ if (v)
+ break;
+ }
+ }
+ return v;
+}
+
+void UMLFolder::setViewOptions(const Settings::OptionState& optionState) {
+ // for each view update settings
+ UMLView *v;
+ for (UMLViewListIt vit(m_diagrams); (v = vit.current()) != NULL; ++vit)
+ v->setOptionState(optionState);
+}
+
+void UMLFolder::removeAllViews() {
+ UMLObject *o;
+ for (UMLObjectListIt oit(m_objects); (o = oit.current()) != NULL; ++oit) {
+ if (o->getBaseType() != Uml::ot_Folder)
+ continue;
+ UMLFolder *f = static_cast<UMLFolder*>(o);
+ f->removeAllViews();
+ }
+ UMLView *v = NULL;
+ for (UMLViewListIt vit(m_diagrams); (v = vit.current()) != NULL; ++vit) {
+ // TODO ------------------ check this code - bad: calling back to UMLDoc::removeView()
+ v->removeAllAssociations(); // note : It may not be apparent, but when we remove all associations
+ // from a view, it also causes any UMLAssociations that lack parent
+ // association widgets (but once had them) to remove themselves from
+ // this document.
+ UMLApp::app()->getDocument()->removeView(v, false);
+ }
+ m_diagrams.clear();
+}
+
+void UMLFolder::setFolderFile(const QString& fileName) {
+ m_folderFile = fileName;
+}
+
+QString UMLFolder::getFolderFile() {
+ return m_folderFile;
+}
+
+void UMLFolder::saveContents(QDomDocument& qDoc, QDomElement& qElement) {
+ QDomElement ownedElement = qDoc.createElement("UML:Namespace.ownedElement");
+ UMLObject *obj;
+ // Save contained objects if any.
+ for (UMLObjectListIt oit(m_objects); (obj = oit.current()) != NULL; ++oit)
+ obj->saveToXMI (qDoc, ownedElement);
+ // Save asscociations if any.
+ for (UMLObjectListIt ait(m_List); (obj = ait.current()) != NULL; ++ait)
+ obj->saveToXMI (qDoc, ownedElement);
+ qElement.appendChild(ownedElement);
+ // Save diagrams to `extension'.
+ if (m_diagrams.count()) {
+ QDomElement diagramsElement = qDoc.createElement("diagrams");
+ UMLView *pView;
+ for (UMLViewListIt vit(m_diagrams); (pView = vit.current()) != NULL; ++vit) {
+ pView->saveToXMI(qDoc, diagramsElement);
+ }
+ QDomElement extension = qDoc.createElement("XMI.extension");
+ extension.setAttribute("xmi.extender", "umbrello");
+ extension.appendChild( diagramsElement );
+ qElement.appendChild(extension);
+ }
+}
+
+void UMLFolder::save(QDomDocument& qDoc, QDomElement& qElement) {
+ UMLDoc *umldoc = UMLApp::app()->getDocument();
+ QString elementName("UML:Package");
+ const Uml::Model_Type mt = umldoc->rootFolderType(this);
+ if (mt != Uml::N_MODELTYPES)
+ elementName = "UML:Model";
+ QDomElement folderElement = UMLObject::save(elementName, qDoc);
+ saveContents(qDoc, folderElement);
+ qElement.appendChild(folderElement);
+}
+
+void UMLFolder::saveToXMI(QDomDocument& qDoc, QDomElement& qElement) {
+ if (m_folderFile.isEmpty()) {
+ save(qDoc, qElement);
+ return;
+ }
+ // See if we can create the external file.
+ // If not then internalize the folder.
+ UMLDoc *umldoc = UMLApp::app()->getDocument();
+ QString fileName = umldoc->URL().directory() + '/' + m_folderFile;
+ QFile file(fileName);
+ if (!file.open(IO_WriteOnly)) {
+ kError() << "UMLFolder::saveToXMI(" << m_folderFile << "): "
+ << "cannot create file, contents will be saved in main model file"
+ << endl;
+ m_folderFile = QString::null;
+ save(qDoc, qElement);
+ return;
+ }
+ // Okay, external file is writable. Wrap up main file.
+ QDomElement folderElement = UMLObject::save("UML:Package", qDoc);
+ QDomElement extension = qDoc.createElement("XMI.extension");
+ extension.setAttribute("xmi.extender", "umbrello");
+ QDomElement fileElement = qDoc.createElement("external_file");
+ fileElement.setAttribute("name", m_folderFile);
+ extension.appendChild(fileElement);
+ folderElement.appendChild(extension);
+ qElement.appendChild(folderElement);
+
+ // Save folder to external file.
+ QDomDocument folderDoc;
+ QDomElement folderRoot;
+ QDomProcessingInstruction xmlHeading =
+ folderDoc.createProcessingInstruction("xml",
+ "version=\"1.0\" encoding=\"UTF-8\"");
+ folderDoc.appendChild(xmlHeading);
+ folderRoot = folderDoc.createElement("external_file");
+ folderRoot.setAttribute("name", m_Name);
+ folderRoot.setAttribute("filename", m_folderFile);
+ folderRoot.setAttribute("mainModel", umldoc->URL().fileName());
+ folderRoot.setAttribute("parentId", ID2STR(m_pUMLPackage->getID()));
+ folderRoot.setAttribute("parent", m_pUMLPackage->getFullyQualifiedName("::", true));
+ saveContents(folderDoc, folderRoot);
+ folderDoc.appendChild(folderRoot);
+ QTextStream stream(&file);
+ stream.setEncoding(QTextStream::UnicodeUTF8);
+ stream << folderDoc.toString();
+ file.close();
+}
+
+bool UMLFolder::loadDiagramsFromXMI(QDomNode& diagrams) {
+ const Settings::OptionState optionState = Settings::getOptionState();
+ UMLDoc *umldoc = UMLApp::app()->getDocument();
+ bool totalSuccess = true;
+ for (QDomElement diagram = diagrams.toElement(); !diagram.isNull();
+ diagrams = diagrams.nextSibling(), diagram = diagrams.toElement()) {
+ QString tag = diagram.tagName();
+ if (tag != "diagram") {
+ kDebug() << "UMLFolder::loadDiagramsFromXMI: ignoring "
+ << tag << " in <diagrams>" << endl;
+ continue;
+ }
+ UMLView * pView = new UMLView(this);
+ pView->setOptionState(optionState);
+ if (pView->loadFromXMI(diagram)) {
+ pView->hide();
+ umldoc->addView(pView);
+ } else {
+ delete pView;
+ totalSuccess = false;
+ }
+ }
+ return totalSuccess;
+}
+
+bool UMLFolder::loadFolderFile(const QString& path) {
+ QFile file(path);
+ if (!file.exists()) {
+ KMessageBox::error(0, i18n("The folderfile %1 does not exist.").arg(path), i18n("Load Error"));
+ return false;
+ }
+ if (!file.open(IO_ReadOnly)) {
+ KMessageBox::error(0, i18n("The folderfile %1 cannot be opened.").arg(path), i18n("Load Error"));
+ return false;
+ }
+ QTextStream stream(&file);
+ QString data = stream.read();
+ file.close();
+ QDomDocument doc;
+ QString error;
+ int line;
+ if (!doc.setContent( data, false, &error, &line)) {
+ kError() << "UMLFolder::loadFolderFile: Can't set content:"
+ << error << " line:" << line << endl;
+ return false;
+ }
+ QDomNode rootNode = doc.firstChild();
+ while (rootNode.isComment() || rootNode.isProcessingInstruction()) {
+ rootNode = rootNode.nextSibling();
+ }
+ if (rootNode.isNull()) {
+ kError() << "UMLFolder::loadFolderFile: Root node is Null" << endl;
+ return false;
+ }
+ QDomElement element = rootNode.toElement();
+ QString type = element.tagName();
+ if (type != "external_file") {
+ kError() << "UMLFolder::loadFolderFile: Root node has unknown type "
+ << type << endl;
+ return false;
+ }
+ return load(element);
+}
+
+bool UMLFolder::load(QDomElement& element) {
+ UMLDoc *umldoc = UMLApp::app()->getDocument();
+ bool totalSuccess = true;
+ for (QDomNode node = element.firstChild(); !node.isNull();
+ node = node.nextSibling()) {
+ if (node.isComment())
+ continue;
+ QDomElement tempElement = node.toElement();
+ QString type = tempElement.tagName();
+ if (Model_Utils::isCommonXMIAttribute(type))
+ continue;
+ if (Uml::tagEq(type, "Namespace.ownedElement") ||
+ Uml::tagEq(type, "Namespace.contents")) {
+ //CHECK: Umbrello currently assumes that nested elements
+ // are ownedElements anyway.
+ // Therefore these tags are not further interpreted.
+ if (! load(tempElement)) {
+ kDebug() << "An error happened while loading the " << type
+ << " of the " << m_Name << endl;
+ totalSuccess = false;
+ }
+ continue;
+ } else if (type == "XMI.extension") {
+ for (QDomNode xtnode = node.firstChild(); !xtnode.isNull();
+ xtnode = xtnode.nextSibling()) {
+ QDomElement el = xtnode.toElement();
+ const QString xtag = el.tagName();
+ if (xtag == "diagrams") {
+ QDomNode diagramNode = xtnode.firstChild();
+ if (!loadDiagramsFromXMI(diagramNode))
+ totalSuccess = false;
+ } else if (xtag == "external_file") {
+ const QString rootDir(umldoc->URL().directory());
+ QString fileName = el.attribute("name", "");
+ const QString path(rootDir + '/' + fileName);
+ if (loadFolderFile(path))
+ m_folderFile = fileName;
+ } else {
+ kDebug() << "UMLFolder::load(" << m_Name
+ << "): ignoring XMI.extension " << xtag << endl;
+ continue;
+ }
+ }
+ continue;
+ }
+ // Do not re-create the predefined Datatypes folder in the Logical View,
+ // it already exists.
+ UMLFolder *logicalView = umldoc->getRootFolder(Uml::mt_Logical);
+ if (this == logicalView && Uml::tagEq(type, "Package")) {
+ QString thisName = tempElement.attribute("name", "");
+ if (thisName == "Datatypes") {
+ UMLFolder *datatypeFolder = umldoc->getDatatypeFolder();
+ if (!datatypeFolder->loadFromXMI(tempElement))
+ totalSuccess = false;
+ continue;
+ }
+ }
+ UMLObject *pObject = NULL;
+ // Avoid duplicate creation of forward declared object
+ QString idStr = tempElement.attribute("xmi.id", "");
+ if (!idStr.isEmpty()) {
+ Uml::IDType id = STR2ID(idStr);
+ pObject = umldoc->findObjectById(id);
+ if (pObject) {
+ kDebug() << "UMLFolder::load: object " << idStr
+ << "already exists" << endl;
+ }
+ }
+ if (pObject == NULL) {
+ QString stereoID = tempElement.attribute("stereotype", "");
+ pObject = Object_Factory::makeObjectFromXMI(type, stereoID);
+ if (!pObject) {
+ kWarning() << "UMLFolder::load: "
+ << "Unknown type of umlobject to create: " << type << endl;
+ continue;
+ }
+ }
+ pObject->setUMLPackage(this);
+ if (!pObject->loadFromXMI(tempElement)) {
+ removeObject(pObject);
+ delete pObject;
+ totalSuccess = false;
+ }
+ }
+ return totalSuccess;
+}
+
+#include "folder.moc"
diff --git a/umbrello/umbrello/folder.h b/umbrello/umbrello/folder.h
new file mode 100644
index 00000000..2e4d23f6
--- /dev/null
+++ b/umbrello/umbrello/folder.h
@@ -0,0 +1,199 @@
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * copyright (C) 2006 *
+ * Umbrello UML Modeller Authors <uml-devel@uml.sf.net> *
+ ***************************************************************************/
+
+#ifndef UMLFOLDER_H
+#define UMLFOLDER_H
+
+#include "package.h"
+#include "umlviewlist.h"
+#include "optionstate.h"
+
+/**
+ * This class manages the UMLObjects and UMLViews of a Folder.
+ * This class inherits from UMLPackage which contains most
+ * of the information.
+ *
+ * The UMLDoc class allocates a fixed instance of this class for
+ * each of the predefined Logical, UseCase, Component, Deployment, and
+ * Entity-Relationship folders. Further instances are created on demand
+ * for user folders.
+ *
+ * @short Non-graphical management of objects and diagrams of a Folder
+ * @author Oliver Kellogg
+ * Bugs and comments to uml-devel@lists.sf.net or http://bugs.kde.org
+ */
+
+class UMLFolder : public UMLPackage {
+ Q_OBJECT
+public:
+ /**
+ * Sets up a Folder.
+ *
+ * @param name The name of the Folder.
+ * @param id The unique id of the Folder. A new ID will be generated
+ * if this argument is left away.
+ */
+ explicit UMLFolder(const QString & name = "", Uml::IDType id = Uml::id_None);
+
+ /**
+ * Empty deconstructor.
+ */
+ virtual ~UMLFolder();
+
+ /**
+ * Initializes key variables of the class.
+ */
+ virtual void init();
+
+ /**
+ * Make a clone of this object.
+ */
+ virtual UMLObject* clone() const;
+
+ /**
+ * Set the localized name of this folder.
+ * This is set for the predefined root views (Logical,
+ * UseCase, Component, Deployment, EntityRelationship,
+ * and the Datatypes folder inside the Logical View.)
+ */
+ void setLocalName(const QString& localName);
+
+ /**
+ * Return the localized name of this folder.
+ * Only useful for the predefined root folders.
+ */
+ QString getLocalName();
+
+ /**
+ * Add a view to the diagram list.
+ */
+ void addView(UMLView *view);
+
+ /**
+ * Remove a view from the diagram list.
+ */
+ void removeView(UMLView *view);
+
+ /**
+ * Append the views in this folder to the given diagram list.
+ *
+ * @param viewList The UMLViewList to which to append the diagrams.
+ * @param includeNested Whether to include diagrams from nested folders
+ * (default: true.)
+ */
+ void appendViews(UMLViewList& viewList, bool includeNested = true);
+
+ /**
+ * Acivate the views in this folder.
+ * "Activation": Some widgets require adjustments after loading from file,
+ * those are done here.
+ */
+ void activateViews();
+
+ /**
+ * Seek a view of the given ID in this folder.
+ *
+ * @param id ID of the view to find.
+ * @return Pointer to the view if found, NULL if no view found.
+ */
+ UMLView *findView(Uml::IDType id);
+
+ /**
+ * Seek a view by the type and name given.
+ *
+ * @param type The type of view to find.
+ * @param name The name of the view to find.
+ * @param searchAllScopes Search in all subfolders (default: true.)
+ * @return Pointer to the view found, or NULL if not found.
+ */
+ UMLView * findView(Uml::Diagram_Type type, const QString &name, bool searchAllScopes = true);
+
+ /**
+ * Set the options for the views in this folder.
+ */
+ void setViewOptions(const Settings::OptionState& optionState);
+
+ /**
+ * Remove all views in this folder.
+ */
+ void removeAllViews();
+
+ /**
+ * Set the folder file name for a separate submodel.
+ */
+ void setFolderFile(const QString& fileName);
+
+ /**
+ * Get the folder file name for a separate submodel.
+ */
+ QString getFolderFile();
+
+ /**
+ * Creates a UML:Model or UML:Package element:
+ * UML:Model is created for the predefined fixed folders,
+ * UML:Package with stereotype "folder" is created for all else.
+ */
+ void saveToXMI( QDomDocument & qDoc, QDomElement & qElement );
+
+protected:
+ /**
+ * Auxiliary to saveToXMI(): Save the contained objects and diagrams.
+ * Can be used regardless of whether saving to the main model file
+ * or to an external folder file (see m_folderFile.)
+ */
+ void saveContents(QDomDocument& qDoc, QDomElement& qElement);
+
+ /**
+ * Auxiliary to saveToXMI(): Creates a <UML:Model> element when saving
+ * a predefined modelview, or a <UML:Package> element when saving a
+ * user created folder. Invokes saveContents() with the newly created
+ * element.
+ */
+ void save(QDomDocument& qDoc, QDomElement& qElement);
+
+ /**
+ * Auxiliary to load():
+ * Load the diagrams from the "diagrams" in the <XMI.extension>
+ */
+ bool loadDiagramsFromXMI(QDomNode& diagrams);
+
+ /**
+ * Folders in the listview can be marked such that their contents
+ * are saved to a separate file.
+ * This method loads the separate folder file.
+ * CAVEAT: This is not XMI standard compliant.
+ * If standard compliance is an issue then avoid folder files.
+ *
+ * @param path Fully qualified file name, i.e. absolute directory
+ * plus file name.
+ * @return True for success.
+ */
+ bool loadFolderFile(const QString& path);
+
+ /**
+ * Loads the UML:Component element.
+ */
+ bool load(QDomElement & element);
+
+private:
+ QString m_localName; ///< i18n name, only used for predefined root folders
+ /**
+ * If m_folderFile is not empty then it contains a file name to which
+ * this folder is saved.
+ * In this case the folder file acts as a physically separate submodel.
+ * What is saved in the main model is not the folder contents but a
+ * reference to the folder file.
+ */
+ QString m_folderFile;
+ UMLViewList m_diagrams;
+};
+
+#endif
diff --git a/umbrello/umbrello/forkjoinwidget.cpp b/umbrello/umbrello/forkjoinwidget.cpp
new file mode 100644
index 00000000..5a1ce3b8
--- /dev/null
+++ b/umbrello/umbrello/forkjoinwidget.cpp
@@ -0,0 +1,112 @@
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * copyright (C) 2005-2006 *
+ * Umbrello UML Modeller Authors <uml-devel@uml.sf.net> *
+ ***************************************************************************/
+
+// own header
+#include "forkjoinwidget.h"
+//qt includes
+#include <qdom.h>
+//kde includes
+#include <kcursor.h>
+#include <kdebug.h>
+//app includes
+#include "umlview.h"
+#include "listpopupmenu.h"
+
+ForkJoinWidget::ForkJoinWidget(UMLView * view, bool drawVertical, Uml::IDType id)
+ : BoxWidget(view, id), m_drawVertical(drawVertical) {
+ init();
+}
+
+void ForkJoinWidget::init() {
+ WidgetBase::setBaseType( Uml::wt_ForkJoin );
+ UMLWidget::updateComponentSize();
+}
+
+ForkJoinWidget::~ForkJoinWidget() {
+}
+
+QSize ForkJoinWidget::calculateSize() {
+ if (m_drawVertical) {
+ return QSize(4, 40);
+ } else {
+ return QSize(40, 4);
+ }
+}
+
+void ForkJoinWidget::draw(QPainter& p, int offsetX, int offsetY) {
+ p.fillRect( offsetX, offsetY, width(), height(), QBrush( Qt::black ));
+
+ if (m_bSelected) {
+ drawSelected(&p, offsetX, offsetY);
+ }
+}
+
+void ForkJoinWidget::drawSelected(QPainter *, int /*offsetX*/, int /*offsetY*/) {
+}
+
+void ForkJoinWidget::constrain(int& width, int& height) {
+ if (m_drawVertical) {
+ if (width < 4)
+ width = 4;
+ else if (width > 10)
+ width = 10;
+ if (height < 40)
+ height = 40;
+ else if (height > 100)
+ height = 100;
+ } else {
+ if (height < 4)
+ height = 4;
+ else if (height > 10)
+ height = 10;
+ if (width < 40)
+ width = 40;
+ else if (width > 100)
+ width = 100;
+ }
+}
+
+void ForkJoinWidget::slotMenuSelection(int sel) {
+ switch (sel) {
+ case ListPopupMenu::mt_Flip:
+ setDrawVertical(!m_drawVertical);
+ break;
+ default:
+ break;
+ }
+}
+
+void ForkJoinWidget::setDrawVertical(bool to) {
+ m_drawVertical = to;
+ updateComponentSize();
+ UMLWidget::adjustAssocs( getX(), getY() );
+}
+
+bool ForkJoinWidget::getDrawVertical() const {
+ return m_drawVertical;
+}
+
+void ForkJoinWidget::saveToXMI(QDomDocument& qDoc, QDomElement& qElement) {
+ QDomElement fjElement = qDoc.createElement("forkjoin");
+ UMLWidget::saveToXMI(qDoc, fjElement);
+ fjElement.setAttribute("drawvertical", m_drawVertical);
+ qElement.appendChild(fjElement);
+}
+
+bool ForkJoinWidget::loadFromXMI(QDomElement& qElement) {
+ if ( !UMLWidget::loadFromXMI(qElement) ) {
+ return false;
+ }
+ QString drawVertical = qElement.attribute("drawvertical", "0");
+ setDrawVertical( (bool)drawVertical.toInt() );
+ return true;
+}
+
diff --git a/umbrello/umbrello/forkjoinwidget.h b/umbrello/umbrello/forkjoinwidget.h
new file mode 100644
index 00000000..bf8c47c8
--- /dev/null
+++ b/umbrello/umbrello/forkjoinwidget.h
@@ -0,0 +1,103 @@
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * copyright (C) 2005-2006 *
+ * Umbrello UML Modeller Authors <uml-devel@uml.sf.net> *
+ ***************************************************************************/
+
+#ifndef FORKJOINWIDGET_H
+#define FORKJOINWIDGET_H
+//qt includes
+#include <qpainter.h>
+//app includes
+#include "boxwidget.h"
+
+// fwd decl.
+class UMLView;
+
+/**
+ * @short Displays a fork/join plate in a state diagram.
+ * @author Oliver Kellogg <okellogg@users.sourceforge.net>
+ * @see UMLWidget
+ * Bugs and comments to uml-devel@lists.sf.net or http://bugs.kde.org
+ */
+class ForkJoinWidget : public BoxWidget {
+public:
+
+ /**
+ * Constructs a ForkJoinWidget.
+ *
+ * @param view The parent to this widget.
+ * @param drawVertical Whether to draw the plate horizontally or vertically.
+ * @param id The ID to assign (-1 will prompt a new ID.)
+ */
+ explicit ForkJoinWidget(UMLView * view, bool drawVertical = false, Uml::IDType id = Uml::id_None);
+
+ /**
+ * destructor
+ */
+ virtual ~ForkJoinWidget();
+
+ /**
+ * Set whether to draw the plate vertically.
+ */
+ void setDrawVertical(bool to);
+ /**
+ * Get whether to draw the plate vertically.
+ */
+ bool getDrawVertical() const;
+
+ /**
+ * Overrides the function from UMLWidget.
+ *
+ * @param sel The command to be executed.
+ */
+ void slotMenuSelection(int sel);
+
+ /**
+ * Draws a slim solid black rectangle.
+ */
+ void draw(QPainter & p, int offsetX, int offsetY);
+
+ /**
+ * Saves the widget to the "forkjoinwidget" XMI element.
+ */
+ void saveToXMI(QDomDocument& qDoc, QDomElement& qElement);
+
+ /**
+ * Loads the widget from the "forkjoinwidget" XMI element.
+ */
+ bool loadFromXMI(QDomElement & qElement);
+
+protected:
+ /**
+ * Reimplement method from UMLWidget to suppress the resize corner.
+ * Although the ForkJoinWidget supports resizing, we suppress the
+ * resize corner because it is too large for this very slim widget.
+ */
+ void drawSelected(QPainter * p, int offsetX, int offsetY);
+
+ /**
+ * Overrides the function from UMLWidget.
+ */
+ QSize calculateSize();
+
+ /**
+ * Reimplement method from UMLWidget.
+ */
+ void constrain(int& width, int& height);
+
+private:
+ /**
+ * Initializes key variables for the class.
+ */
+ void init();
+
+ bool m_drawVertical; ///< whether to draw the plate horizontally or vertically
+};
+
+#endif
diff --git a/umbrello/umbrello/headings/Makefile.am b/umbrello/umbrello/headings/Makefile.am
new file mode 100644
index 00000000..334e9435
--- /dev/null
+++ b/umbrello/umbrello/headings/Makefile.am
@@ -0,0 +1,17 @@
+mydir = $(kde_datadir)/umbrello/headings
+my_DATA = heading.adb \
+heading.ads \
+heading.as \
+heading.cpp \
+heading.cs \
+heading.d \
+heading.h \
+heading.idl \
+heading.java \
+heading.js \
+heading.php \
+heading.pm \
+heading.py \
+heading.rb \
+heading.sql \
+heading.xsd
diff --git a/umbrello/umbrello/headings/heading.adb b/umbrello/umbrello/headings/heading.adb
new file mode 100644
index 00000000..87dc70a8
--- /dev/null
+++ b/umbrello/umbrello/headings/heading.adb
@@ -0,0 +1,29 @@
+-- %filename% - Copyright %author%
+--
+-- Here you can write a license for your code, some comments or any other
+-- information you want to have in your generated code. To to this simply
+-- configure the "headings" directory in uml to point to a directory
+-- where you have your heading files.
+--
+-- or you can just replace the contents of this file with your own.
+-- If you want to do this, this file is located at
+--
+-- %headingpath%
+--
+-- -->Code Generators searches for heading files based on the file
+-- extension i.e. it will look for a file name ending in ".h" to
+-- include in C++ header files, and for a file name ending in
+-- ".java" to include in all generated java code. If you name
+-- the file "heading.<extension>", Code Generator will always
+-- choose this file even if there are other files with the same
+-- extension in the directory. If you name the file something
+-- else, it must be the only one with that extension in the
+-- directory to guarantee that Code Generator will choose it.
+--
+-- you can use variables in your heading files which are replaced at
+-- generation time. possible variables are : author, date, time,
+-- filename and filepath. Just write %variable_name%
+--
+-- This file was generated on %date% at %time%
+-- The original location of this file is %filepath%
+
diff --git a/umbrello/umbrello/headings/heading.ads b/umbrello/umbrello/headings/heading.ads
new file mode 100644
index 00000000..1e4a582c
--- /dev/null
+++ b/umbrello/umbrello/headings/heading.ads
@@ -0,0 +1,30 @@
+-- %filename% - Copyright %author%
+--
+-- Here you can write a license for your code, some comments or any other
+-- information you want to have in your generated code. To to this simply
+-- configure the "headings" directory in uml to point to a directory
+-- where you have your heading files.
+--
+-- or you can just replace the contents of this file with your own.
+-- If you want to do this, this file is located at
+--
+-- %headingpath%
+--
+-- -->Code Generators searches for heading files based on the file
+-- extension i.e. it will look for a file name ending in ".h" to
+-- include in C++ header files, and for a file name ending in
+-- ".java" to include in all generated java code. If you name
+-- the file "heading.<extension>", Code Generator will always
+-- choose this file even if there are other files with the same
+-- extension in the directory. If you name the file something
+-- else, it must be the only one with that extension in the
+-- directory to guarantee that Code Generator will choose it.
+--
+-- you can use variables in your heading files which are replaced at
+-- generation time. possible variables are : author, date, time,
+-- filename and filepath. Just write %variable_name%
+--
+-- This file was generated on %date% at %time%
+-- The original location of this file is %filepath%
+
+
diff --git a/umbrello/umbrello/headings/heading.as b/umbrello/umbrello/headings/heading.as
new file mode 100644
index 00000000..6e3f61cd
--- /dev/null
+++ b/umbrello/umbrello/headings/heading.as
@@ -0,0 +1,29 @@
+/************************************************************************
+ %filename% - Copyright %author%
+
+Here you can write a license for your code, some comments or any other
+information you want to have in your generated code. To to this simply
+configure the "headings" directory in uml to point to a directory
+where you have your heading files.
+
+or you can just replace the contents of this file with your own.
+If you want to do this, this file is located at
+
+%headingpath%
+
+-->Code Generators searches for heading files based on the file extension
+ i.e. it will look for a file name ending in ".h" to include in C++ header
+ files, and for a file name ending in ".java" to include in all generated
+ java code.
+ If you name the file "heading.<extension>", Code Generator will always
+ choose this file even if there are other files with the same extension in the
+ directory. If you name the file something else, it must be the only one with that
+ extension in the directory to guarantee that Code Generator will choose it.
+
+you can use variables in your heading files which are replaced at generation
+time. possible variables are : author, date, time, filename and filepath.
+just write %variable_name%
+
+This file was generated on %date% at %time%
+The original location of this file is %filepath%
+**************************************************************************/
diff --git a/umbrello/umbrello/headings/heading.cpp b/umbrello/umbrello/headings/heading.cpp
new file mode 100644
index 00000000..d33911bf
--- /dev/null
+++ b/umbrello/umbrello/headings/heading.cpp
@@ -0,0 +1,29 @@
+/************************************************************************
+ %filename% - Copyright %author%
+
+Here you can write a license for your code, some comments or any other
+information you want to have in your generated code. To to this simply
+configure the "headings" directory in uml to point to a directory
+where you have your heading files.
+
+or you can just replace the contents of this file with your own.
+If you want to do this, this file is located at
+
+%headingpath%
+
+-->Code Generators searches for heading files based on the file extension
+ i.e. it will look for a file name ending in ".h" to include in C++ header
+ files, and for a file name ending in ".java" to include in all generated
+ java code.
+ If you name the file "heading.<extension>", Code Generator will always
+ choose this file even if there are other files with the same extension in the
+ directory. If you name the file something else, it must be the only one with that
+ extension in the directory to guarantee that Code Generator will choose it.
+
+you can use variables in your heading files which are replaced at generation
+time. possible variables are : author, date, time, filename and filepath.
+just write %variable_name%
+
+This file was generated on %date% at %time%
+The original location of this file is %filepath%
+**************************************************************************/
diff --git a/umbrello/umbrello/headings/heading.cs b/umbrello/umbrello/headings/heading.cs
new file mode 100644
index 00000000..6e3f61cd
--- /dev/null
+++ b/umbrello/umbrello/headings/heading.cs
@@ -0,0 +1,29 @@
+/************************************************************************
+ %filename% - Copyright %author%
+
+Here you can write a license for your code, some comments or any other
+information you want to have in your generated code. To to this simply
+configure the "headings" directory in uml to point to a directory
+where you have your heading files.
+
+or you can just replace the contents of this file with your own.
+If you want to do this, this file is located at
+
+%headingpath%
+
+-->Code Generators searches for heading files based on the file extension
+ i.e. it will look for a file name ending in ".h" to include in C++ header
+ files, and for a file name ending in ".java" to include in all generated
+ java code.
+ If you name the file "heading.<extension>", Code Generator will always
+ choose this file even if there are other files with the same extension in the
+ directory. If you name the file something else, it must be the only one with that
+ extension in the directory to guarantee that Code Generator will choose it.
+
+you can use variables in your heading files which are replaced at generation
+time. possible variables are : author, date, time, filename and filepath.
+just write %variable_name%
+
+This file was generated on %date% at %time%
+The original location of this file is %filepath%
+**************************************************************************/
diff --git a/umbrello/umbrello/headings/heading.d b/umbrello/umbrello/headings/heading.d
new file mode 100644
index 00000000..d33911bf
--- /dev/null
+++ b/umbrello/umbrello/headings/heading.d
@@ -0,0 +1,29 @@
+/************************************************************************
+ %filename% - Copyright %author%
+
+Here you can write a license for your code, some comments or any other
+information you want to have in your generated code. To to this simply
+configure the "headings" directory in uml to point to a directory
+where you have your heading files.
+
+or you can just replace the contents of this file with your own.
+If you want to do this, this file is located at
+
+%headingpath%
+
+-->Code Generators searches for heading files based on the file extension
+ i.e. it will look for a file name ending in ".h" to include in C++ header
+ files, and for a file name ending in ".java" to include in all generated
+ java code.
+ If you name the file "heading.<extension>", Code Generator will always
+ choose this file even if there are other files with the same extension in the
+ directory. If you name the file something else, it must be the only one with that
+ extension in the directory to guarantee that Code Generator will choose it.
+
+you can use variables in your heading files which are replaced at generation
+time. possible variables are : author, date, time, filename and filepath.
+just write %variable_name%
+
+This file was generated on %date% at %time%
+The original location of this file is %filepath%
+**************************************************************************/
diff --git a/umbrello/umbrello/headings/heading.h b/umbrello/umbrello/headings/heading.h
new file mode 100644
index 00000000..d33911bf
--- /dev/null
+++ b/umbrello/umbrello/headings/heading.h
@@ -0,0 +1,29 @@
+/************************************************************************
+ %filename% - Copyright %author%
+
+Here you can write a license for your code, some comments or any other
+information you want to have in your generated code. To to this simply
+configure the "headings" directory in uml to point to a directory
+where you have your heading files.
+
+or you can just replace the contents of this file with your own.
+If you want to do this, this file is located at
+
+%headingpath%
+
+-->Code Generators searches for heading files based on the file extension
+ i.e. it will look for a file name ending in ".h" to include in C++ header
+ files, and for a file name ending in ".java" to include in all generated
+ java code.
+ If you name the file "heading.<extension>", Code Generator will always
+ choose this file even if there are other files with the same extension in the
+ directory. If you name the file something else, it must be the only one with that
+ extension in the directory to guarantee that Code Generator will choose it.
+
+you can use variables in your heading files which are replaced at generation
+time. possible variables are : author, date, time, filename and filepath.
+just write %variable_name%
+
+This file was generated on %date% at %time%
+The original location of this file is %filepath%
+**************************************************************************/
diff --git a/umbrello/umbrello/headings/heading.idl b/umbrello/umbrello/headings/heading.idl
new file mode 100644
index 00000000..6e3f61cd
--- /dev/null
+++ b/umbrello/umbrello/headings/heading.idl
@@ -0,0 +1,29 @@
+/************************************************************************
+ %filename% - Copyright %author%
+
+Here you can write a license for your code, some comments or any other
+information you want to have in your generated code. To to this simply
+configure the "headings" directory in uml to point to a directory
+where you have your heading files.
+
+or you can just replace the contents of this file with your own.
+If you want to do this, this file is located at
+
+%headingpath%
+
+-->Code Generators searches for heading files based on the file extension
+ i.e. it will look for a file name ending in ".h" to include in C++ header
+ files, and for a file name ending in ".java" to include in all generated
+ java code.
+ If you name the file "heading.<extension>", Code Generator will always
+ choose this file even if there are other files with the same extension in the
+ directory. If you name the file something else, it must be the only one with that
+ extension in the directory to guarantee that Code Generator will choose it.
+
+you can use variables in your heading files which are replaced at generation
+time. possible variables are : author, date, time, filename and filepath.
+just write %variable_name%
+
+This file was generated on %date% at %time%
+The original location of this file is %filepath%
+**************************************************************************/
diff --git a/umbrello/umbrello/headings/heading.java b/umbrello/umbrello/headings/heading.java
new file mode 100644
index 00000000..6e3f61cd
--- /dev/null
+++ b/umbrello/umbrello/headings/heading.java
@@ -0,0 +1,29 @@
+/************************************************************************
+ %filename% - Copyright %author%
+
+Here you can write a license for your code, some comments or any other
+information you want to have in your generated code. To to this simply
+configure the "headings" directory in uml to point to a directory
+where you have your heading files.
+
+or you can just replace the contents of this file with your own.
+If you want to do this, this file is located at
+
+%headingpath%
+
+-->Code Generators searches for heading files based on the file extension
+ i.e. it will look for a file name ending in ".h" to include in C++ header
+ files, and for a file name ending in ".java" to include in all generated
+ java code.
+ If you name the file "heading.<extension>", Code Generator will always
+ choose this file even if there are other files with the same extension in the
+ directory. If you name the file something else, it must be the only one with that
+ extension in the directory to guarantee that Code Generator will choose it.
+
+you can use variables in your heading files which are replaced at generation
+time. possible variables are : author, date, time, filename and filepath.
+just write %variable_name%
+
+This file was generated on %date% at %time%
+The original location of this file is %filepath%
+**************************************************************************/
diff --git a/umbrello/umbrello/headings/heading.js b/umbrello/umbrello/headings/heading.js
new file mode 100644
index 00000000..6e3f61cd
--- /dev/null
+++ b/umbrello/umbrello/headings/heading.js
@@ -0,0 +1,29 @@
+/************************************************************************
+ %filename% - Copyright %author%
+
+Here you can write a license for your code, some comments or any other
+information you want to have in your generated code. To to this simply
+configure the "headings" directory in uml to point to a directory
+where you have your heading files.
+
+or you can just replace the contents of this file with your own.
+If you want to do this, this file is located at
+
+%headingpath%
+
+-->Code Generators searches for heading files based on the file extension
+ i.e. it will look for a file name ending in ".h" to include in C++ header
+ files, and for a file name ending in ".java" to include in all generated
+ java code.
+ If you name the file "heading.<extension>", Code Generator will always
+ choose this file even if there are other files with the same extension in the
+ directory. If you name the file something else, it must be the only one with that
+ extension in the directory to guarantee that Code Generator will choose it.
+
+you can use variables in your heading files which are replaced at generation
+time. possible variables are : author, date, time, filename and filepath.
+just write %variable_name%
+
+This file was generated on %date% at %time%
+The original location of this file is %filepath%
+**************************************************************************/
diff --git a/umbrello/umbrello/headings/heading.php b/umbrello/umbrello/headings/heading.php
new file mode 100644
index 00000000..7ff129ac
--- /dev/null
+++ b/umbrello/umbrello/headings/heading.php
@@ -0,0 +1,30 @@
+<?php
+/************************************************************************
+ %filename% - Copyright %author%
+
+Here you can write a license for your code, some comments or any other
+information you want to have in your generated code. To to this simply
+configure the "headings" directory in uml to point to a directory
+where you have your heading files.
+
+or you can just replace the contents of this file with your own.
+If you want to do this, this file is located at
+
+%headingpath%
+
+-->Code Generators searches for heading files based on the file extension
+ i.e. it will look for a file name ending in ".h" to include in C++ header
+ files, and for a file name ending in ".java" to include in all generated
+ java code.
+ If you name the file "heading.<extension>", Code Generator will always
+ choose this file even if there are other files with the same extension in the
+ directory. If you name the file something else, it must be the only one with that
+ extension in the directory to guarantee that Code Generator will choose it.
+
+you can use variables in your heading files which are replaced at generation
+time. possible variables are : author, date, time, filename and filepath.
+just write %variable_name%
+
+This file was generated on %date% at %time%
+The original location of this file is %filepath%
+**************************************************************************/
diff --git a/umbrello/umbrello/headings/heading.pm b/umbrello/umbrello/headings/heading.pm
new file mode 100644
index 00000000..cc02c171
--- /dev/null
+++ b/umbrello/umbrello/headings/heading.pm
@@ -0,0 +1,29 @@
+#!/usr/bin/env perl
+# %filename% - Copyright %author%
+#
+# Here you can write a license for your code, some comments or any other
+# information you want to have in your generated code. To to this simply
+# configure the "headings" directory in uml to point to a directory
+# where you have your heading files.
+#
+# or you can just replace the contents of this file with your own.
+# If you want to do this, this file is located at
+#
+# %headingpath%
+#
+# -->Code Generators searches for heading files based on the file extension
+# i.e. it will look for a file name ending in ".h" to include in C++ header
+# files, and for a file name ending in ".java" to include in all generated
+# java code.
+# If you name the file "heading.<extension>", Code Generator will always
+# choose this file even if there are other files with the same extension in the
+# directory. If you name the file something else, it must be the only one with that
+# extension in the directory to guarantee that Code Generator will choose it.
+#
+# you can use variables in your heading files which are replaced at generation
+# time. possible variables are : author, date, time, filename and filepath.
+# just write %variable_name%
+#
+# This file was generated on %date% at %time%
+# The original location of this file is %filepath%
+
diff --git a/umbrello/umbrello/headings/heading.py b/umbrello/umbrello/headings/heading.py
new file mode 100644
index 00000000..61016aef
--- /dev/null
+++ b/umbrello/umbrello/headings/heading.py
@@ -0,0 +1,29 @@
+#!/usr/bin/env python
+# %filename% - Copyright %author%
+#
+# Here you can write a license for your code, some comments or any other
+# information you want to have in your generated code. To to this simply
+# configure the "headings" directory in uml to point to a directory
+# where you have your heading files.
+#
+# or you can just replace the contents of this file with your own.
+# If you want to do this, this file is located at
+#
+# %headingpath%
+#
+# -->Code Generators searches for heading files based on the file extension
+# i.e. it will look for a file name ending in ".h" to include in C++ header
+# files, and for a file name ending in ".java" to include in all generated
+# java code.
+# If you name the file "heading.<extension>", Code Generator will always
+# choose this file even if there are other files with the same extension in the
+# directory. If you name the file something else, it must be the only one with that
+# extension in the directory to guarantee that Code Generator will choose it.
+#
+# you can use variables in your heading files which are replaced at generation
+# time. possible variables are : author, date, time, filename and filepath.
+# just write %variable_name%
+#
+# This file was generated on %date% at %time%
+# The original location of this file is %filepath%
+
diff --git a/umbrello/umbrello/headings/heading.rb b/umbrello/umbrello/headings/heading.rb
new file mode 100644
index 00000000..b4bbc9b7
--- /dev/null
+++ b/umbrello/umbrello/headings/heading.rb
@@ -0,0 +1,29 @@
+#!/usr/bin/env ruby
+# %filename% - Copyright %author%
+#
+# Here you can write a license for your code, some comments or any other
+# information you want to have in your generated code. To to this simply
+# configure the "headings" directory in uml to point to a directory
+# where you have your heading files.
+#
+# or you can just replace the contents of this file with your own.
+# If you want to do this, this file is located at
+#
+# %headingpath%
+#
+# -->Code Generators searches for heading files based on the file extension
+# i.e. it will look for a file name ending in ".h" to include in C++ header
+# files, and for a file name ending in ".java" to include in all generated
+# java code.
+# If you name the file "heading.<extension>", Code Generator will always
+# choose this file even if there are other files with the same extension in the
+# directory. If you name the file something else, it must be the only one with that
+# extension in the directory to guarantee that Code Generator will choose it.
+#
+# you can use variables in your heading files which are replaced at generation
+# time. possible variables are : author, date, time, filename and filepath.
+# just write %variable_name%
+#
+# This file was generated on %date% at %time%
+# The original location of this file is %filepath%
+
diff --git a/umbrello/umbrello/headings/heading.sql b/umbrello/umbrello/headings/heading.sql
new file mode 100644
index 00000000..f4797f56
--- /dev/null
+++ b/umbrello/umbrello/headings/heading.sql
@@ -0,0 +1,28 @@
+-- %filename% - Copyright %author%
+--
+-- Here you can write a license for your code, some comments or any other
+-- information you want to have in your generated code. To to this simply
+-- configure the "headings" directory in uml to point to a directory
+-- where you have your heading files.
+--
+-- or you can just replace the contents of this file with your own.
+-- If you want to do this, this file is located at
+--
+-- %headingpath%
+--
+-- -->Code Generators searches for heading files based on the file extension
+-- i.e. it will look for a file name ending in ".h" to include in C++ header
+-- files, and for a file name ending in ".java" to include in all generated
+-- java code.
+-- If you name the file "heading.<extension>", Code Generator will always
+-- choose this file even if there are other files with the same extension in the
+-- directory. If you name the file something else, it must be the only one with that
+-- extension in the directory to guarantee that Code Generator will choose it.
+--
+-- you can use variables in your heading files which are replaced at generation
+-- time. possible variables are : author, date, time, filename and filepath.
+-- just write %variable_name%
+--
+-- This file was generated on %date% at %time%
+-- The original location of this file is %filepath%
+
diff --git a/umbrello/umbrello/headings/heading.xsd b/umbrello/umbrello/headings/heading.xsd
new file mode 100644
index 00000000..cd50b9f5
--- /dev/null
+++ b/umbrello/umbrello/headings/heading.xsd
@@ -0,0 +1,4 @@
+<!--
+This heading is genearated using the file at
+%headingpath%
+-->
diff --git a/umbrello/umbrello/hi128-app-umbrello.png b/umbrello/umbrello/hi128-app-umbrello.png
new file mode 100644
index 00000000..ce14d9f7
--- /dev/null
+++ b/umbrello/umbrello/hi128-app-umbrello.png
Binary files differ
diff --git a/umbrello/umbrello/hi16-app-umbrello.png b/umbrello/umbrello/hi16-app-umbrello.png
new file mode 100644
index 00000000..6005f241
--- /dev/null
+++ b/umbrello/umbrello/hi16-app-umbrello.png
Binary files differ
diff --git a/umbrello/umbrello/hi16-mime-umbrellofile.png b/umbrello/umbrello/hi16-mime-umbrellofile.png
new file mode 100644
index 00000000..86b364ac
--- /dev/null
+++ b/umbrello/umbrello/hi16-mime-umbrellofile.png
Binary files differ
diff --git a/umbrello/umbrello/hi22-app-umbrello.png b/umbrello/umbrello/hi22-app-umbrello.png
new file mode 100644
index 00000000..128317d4
--- /dev/null
+++ b/umbrello/umbrello/hi22-app-umbrello.png
Binary files differ
diff --git a/umbrello/umbrello/hi32-app-umbrello.png b/umbrello/umbrello/hi32-app-umbrello.png
new file mode 100644
index 00000000..255e592c
--- /dev/null
+++ b/umbrello/umbrello/hi32-app-umbrello.png
Binary files differ
diff --git a/umbrello/umbrello/hi32-mime-umbrellofile.png b/umbrello/umbrello/hi32-mime-umbrellofile.png
new file mode 100644
index 00000000..2a298ffc
--- /dev/null
+++ b/umbrello/umbrello/hi32-mime-umbrellofile.png
Binary files differ
diff --git a/umbrello/umbrello/hi48-app-umbrello.png b/umbrello/umbrello/hi48-app-umbrello.png
new file mode 100644
index 00000000..98777102
--- /dev/null
+++ b/umbrello/umbrello/hi48-app-umbrello.png
Binary files differ
diff --git a/umbrello/umbrello/hi64-app-umbrello.png b/umbrello/umbrello/hi64-app-umbrello.png
new file mode 100644
index 00000000..cfc7062a
--- /dev/null
+++ b/umbrello/umbrello/hi64-app-umbrello.png
Binary files differ
diff --git a/umbrello/umbrello/hierarchicalcodeblock.cpp b/umbrello/umbrello/hierarchicalcodeblock.cpp
new file mode 100644
index 00000000..7c04a960
--- /dev/null
+++ b/umbrello/umbrello/hierarchicalcodeblock.cpp
@@ -0,0 +1,386 @@
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * copyright (C) 2004-2007 *
+ * Umbrello UML Modeller Authors <uml-devel@uml.sf.net> *
+ ***************************************************************************/
+
+/* This code generated by:
+ * Author : thomas
+ * Date : Wed Jun 18 2003
+ */
+
+// own header
+#include "hierarchicalcodeblock.h"
+
+// qt/kde includes
+#include <kdebug.h>
+
+// local includes
+#include "codedocument.h"
+#include "classifiercodedocument.h"
+#include "codeclassfield.h"
+#include "codegenerationpolicy.h"
+#include "codegenerators/codegenfactory.h"
+#include "uml.h"
+
+// Constructors/Destructors
+//
+
+HierarchicalCodeBlock::HierarchicalCodeBlock ( CodeDocument * doc , const QString &start, const QString &endString, const QString &comment )
+ : CodeBlockWithComments (doc, start, comment), CodeGenObjectWithTextBlocks(doc)
+{
+ setEndText(endString);
+ initAttributes();
+}
+
+HierarchicalCodeBlock::~HierarchicalCodeBlock ( ) { }
+
+//
+// Methods
+//
+
+// Accessor methods
+//
+
+/**
+ * Set the value of m_endText
+ * @param new_var the new value of m_endText
+ */
+void HierarchicalCodeBlock::setEndText ( const QString &new_var ) {
+ m_endText = new_var;
+}
+
+/**
+ * Get the value of m_endText
+ * @return the value of m_endText
+ */
+QString HierarchicalCodeBlock::getEndText ( ) {
+ return m_endText;
+}
+
+QString HierarchicalCodeBlock::getUniqueTag()
+{
+ return getUniqueTag("hblock_tag");
+}
+
+QString HierarchicalCodeBlock::getUniqueTag( const QString& prefix )
+{
+ return getParentDocument()->getUniqueTag(prefix);
+}
+
+// other methods
+
+CodeBlock * HierarchicalCodeBlock::newCodeBlock() {
+ return getParentDocument()->newCodeBlock();
+}
+
+CodeBlockWithComments * HierarchicalCodeBlock::newCodeBlockWithComments() {
+ return getParentDocument()->newCodeBlockWithComments();
+}
+
+HierarchicalCodeBlock * HierarchicalCodeBlock::newHierarchicalCodeBlock() {
+ HierarchicalCodeBlock *hb = new HierarchicalCodeBlock(getParentDocument());
+ //hb->update();
+ return hb;
+}
+
+/**
+ * Add a CodeBlock object to the m_textblockVector List
+ */
+bool HierarchicalCodeBlock::addTextBlock(TextBlock* add_object )
+{
+
+ if(CodeGenObjectWithTextBlocks::addTextBlock(add_object))
+ {
+ getParentDocument()->addChildTagToMap(add_object->getTag(), add_object);
+ return true;
+ }
+ return false;
+}
+
+/**
+ * Insert a new text block before the existing text block. Returns
+ * false if it cannot insert the textblock.
+ */
+bool HierarchicalCodeBlock::insertTextBlock(TextBlock * newBlock, TextBlock * existingBlock, bool after)
+{
+
+ if(!newBlock || !existingBlock)
+ return false;
+
+ QString tag = existingBlock->getTag();
+ // FIX: just do a quick check if the parent DOCUMENT has this.
+ // IF it does, then the lack of an index will force us into
+ // a search of any child hierarchical codeblocks we may have
+ // Its not efficient, but works. I don't think speed is a problem
+ // right now for the current implementation, but in the future
+ // when code import/roundtripping is done, it *may* be. -b.t.
+ if(!getParentDocument()->findTextBlockByTag(tag, true))
+ return false;
+
+ int index = m_textblockVector.findRef(existingBlock);
+ if(index < 0)
+ {
+ // may be hiding in child hierarchical codeblock
+ for(TextBlock * tb = m_textblockVector.first(); tb ; tb = m_textblockVector.next())
+ {
+ HierarchicalCodeBlock * hb = dynamic_cast<HierarchicalCodeBlock*>(tb);
+ if(hb && hb->insertTextBlock(newBlock, existingBlock, after))
+ return true; // found, and inserted, otherwise keep going
+ }
+ kWarning()<<" Warning: couldnt insert text block (tag:"<<newBlock->getTag()<<"). Reference text block (tag:"<<existingBlock->getTag()<<") not found."<<endl;
+ return false;
+ }
+
+ // if we get here.. it was in this object so insert
+
+ // check for tag FIRST
+ QString new_tag = newBlock->getTag();
+
+ // assign a tag if one doesn't already exist
+ if(new_tag.isEmpty())
+ {
+ new_tag = getUniqueTag();
+ newBlock->setTag(new_tag);
+ }
+
+ if(m_textBlockTagMap.contains(new_tag))
+ return false; // return false, we already have some object with this tag in the list
+ else {
+ m_textBlockTagMap.insert(new_tag, newBlock);
+ getParentDocument()->addChildTagToMap(new_tag, newBlock);
+ }
+
+
+ if(after)
+ index++;
+
+ m_textblockVector.insert(index,newBlock);
+
+ return true;
+}
+
+/**
+ * Remove a CodeBlock object from m_textblockVector List
+ */
+bool HierarchicalCodeBlock::removeTextBlock ( TextBlock * remove_object ) {
+
+ // try to remove from the list in this object
+ if(!m_textblockVector.removeRef(remove_object))
+ {
+ // may be hiding in child hierarchical codeblock
+ for(TextBlock * tb = m_textblockVector.first(); tb ; tb = m_textblockVector.next())
+ {
+ HierarchicalCodeBlock * hb = dynamic_cast<HierarchicalCodeBlock*>(tb);
+ if(hb && hb->removeTextBlock(remove_object))
+ return true; // because we got in child hb;
+ }
+ return false;
+ }
+
+ // IF we get here, the text block was in THIS object (and not a child)..
+ QString tag = remove_object->getTag();
+ if(!(tag.isEmpty()))
+ {
+ m_textBlockTagMap.erase(tag);
+ getParentDocument()->removeChildTagFromMap(tag);
+ }
+ return true;
+
+}
+
+/**
+ * @param text
+ */
+void HierarchicalCodeBlock::setStartText ( const QString &text ) {
+ m_startText = text;
+}
+
+/**
+ * @return QString
+ */
+QString HierarchicalCodeBlock::getStartText ( ) {
+ return m_startText;
+}
+
+// Other methods
+//
+
+void HierarchicalCodeBlock::addCodeClassFieldMethods(CodeClassFieldList &list )
+{
+
+ for (CodeClassFieldListIt ccflit(list); ccflit.current(); ++ccflit)
+ {
+ CodeClassField * field = ccflit.current();
+ CodeAccessorMethodList list = field->getMethodList();
+ CodeAccessorMethod * method;
+ for (CodeAccessorMethodListIt it(list); (method = it.current()) != NULL; ++it)
+ {
+ QString tag = method->getTag();
+ if(tag.isEmpty())
+ {
+ tag = getUniqueTag();
+ method->setTag(tag);
+ }
+
+ addTextBlock(method); // wont add if already exists in object;
+
+ }
+
+ }
+
+}
+
+/**
+ * Save the XMI representation of this object
+ */
+void HierarchicalCodeBlock::saveToXMI ( QDomDocument & doc, QDomElement & root ) {
+ QDomElement blockElement = doc.createElement( "hierarchicalcodeblock" );
+
+ setAttributesOnNode(doc, blockElement);
+
+ root.appendChild( blockElement );
+}
+
+void HierarchicalCodeBlock::setAttributesOnNode (QDomDocument & doc, QDomElement & elem ) {
+
+ // set super-class attributes
+ CodeBlockWithComments::setAttributesOnNode(doc, elem);
+ CodeGenObjectWithTextBlocks::setAttributesOnNode(doc, elem);
+
+ // set local class attributes
+ if(getContentType() != CodeBlock::AutoGenerated)
+ {
+ QString endLine = UMLApp::app()->getCommonPolicy()->getNewLineEndingChars();
+ elem.setAttribute("startText",encodeText(getStartText(),endLine));
+ elem.setAttribute("endText",encodeText(getEndText(),endLine));
+ }
+}
+
+/**
+ * load params from the appropriate XMI element node.
+ */
+void HierarchicalCodeBlock::loadFromXMI ( QDomElement & root ) {
+ setAttributesFromNode(root);
+}
+
+
+/** set the class attributes of this object from
+ * the passed element node.
+ */
+void HierarchicalCodeBlock::setAttributesFromNode ( QDomElement & root)
+{
+
+ // set attributes from the XMI
+ CodeBlockWithComments::setAttributesFromNode(root); // superclass load
+
+ if(getContentType() != CodeBlock::AutoGenerated)
+ {
+ QString endLine = UMLApp::app()->getCommonPolicy()->getNewLineEndingChars();
+ setStartText(decodeText(root.attribute("startText",""),endLine));
+ setEndText(decodeText(root.attribute("endText",""),endLine));
+ }
+
+ // do this *after* all other attributes saved
+ CodeGenObjectWithTextBlocks::setAttributesFromNode(root);
+
+}
+
+/** set the class attributes from a passed object
+ */
+void HierarchicalCodeBlock::setAttributesFromObject (TextBlock * obj) {
+
+ CodeBlockWithComments::setAttributesFromObject(obj);
+
+ HierarchicalCodeBlock * hb = dynamic_cast<HierarchicalCodeBlock*>(obj);
+ if(hb)
+ {
+ setStartText(hb->getStartText());
+ setEndText(hb->getEndText());
+ CodeGenObjectWithTextBlocks *cgowtb = dynamic_cast<CodeGenObjectWithTextBlocks*>(obj);
+ CodeGenObjectWithTextBlocks::setAttributesFromObject(cgowtb);
+ }
+
+}
+
+
+/**
+ * @return QString
+ */
+QString HierarchicalCodeBlock::toString ( ) {
+
+ QString string = QString();
+
+ if(getWriteOutText()) {
+ QString indent = getIndentationString();
+ QString endLine = UMLApp::app()->getCommonPolicy()->getNewLineEndingChars();
+ QString startText = "";
+ QString endText = "";
+ if (!getStartText().isEmpty())
+ startText = formatMultiLineText (getStartText(), indent, endLine);
+ if (!getEndText().isEmpty())
+ endText = formatMultiLineText (getEndText(), indent, endLine);
+
+ QString body = childTextBlocksToString();
+ QString comment = getComment()->toString();
+
+ // tack in text, if there is something there..
+ if(!comment.isEmpty() && getComment()->getWriteOutText())
+ string.append(comment);
+
+ if (!startText.isEmpty())
+ string.append(startText);
+
+ if (!body.isEmpty())
+ string.append(body);
+
+ if (!endText.isEmpty())
+ string.append(endText);
+ }
+
+ return string;
+}
+
+QString HierarchicalCodeBlock::childTextBlocksToString() {
+ TextBlockList* list = getTextBlockList();
+ QString retString = "";
+ for(TextBlock *block = list->first() ; block; block=list->next())
+ {
+ QString blockValue = block->toString();
+ if(!blockValue.isEmpty())
+ retString.append(blockValue);
+ }
+ return retString;
+}
+
+TextBlock * HierarchicalCodeBlock::findCodeClassFieldTextBlockByTag ( const QString &tag )
+{
+
+ ClassifierCodeDocument * cdoc = dynamic_cast<ClassifierCodeDocument*>(getParentDocument());
+ if(cdoc)
+ return cdoc->findCodeClassFieldTextBlockByTag(tag);
+ else
+ kError()<<" HierarchicalCodeBlock: findCodeClassFieldTextBlockByTag() finds NO parent document! Badly constructed textblock?!?"<<endl;
+
+ // if we get here, we failed.
+ return (TextBlock*) NULL;
+
+}
+
+void HierarchicalCodeBlock::initAttributes ( ) {
+ m_canDelete = false;
+ m_startText = "";
+ m_endText = "";
+}
+
+void HierarchicalCodeBlock::release () {
+ resetTextBlocks();
+ TextBlock::release();
+}
+
+#include "hierarchicalcodeblock.moc"
diff --git a/umbrello/umbrello/hierarchicalcodeblock.h b/umbrello/umbrello/hierarchicalcodeblock.h
new file mode 100644
index 00000000..3c0dcbc1
--- /dev/null
+++ b/umbrello/umbrello/hierarchicalcodeblock.h
@@ -0,0 +1,155 @@
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * copyright (C) 2004-2006 *
+ * Umbrello UML Modeller Authors <uml-devel@uml.sf.net> *
+ ***************************************************************************/
+
+/* This code generated by:
+ * Author : thomas
+ * Date : Wed Jun 18 2003
+ */
+
+
+#ifndef HIERARCHICALCODEBLOCK_H
+#define HIERARCHICALCODEBLOCK_H
+
+#include <qmap.h>
+#include <qstring.h>
+
+#include "codegenobjectwithtextblocks.h"
+#include "codeblockwithcomments.h"
+#include "codeclassfieldlist.h"
+
+class HierarchicalCodeBlock : public CodeBlockWithComments, public CodeGenObjectWithTextBlocks
+{
+ Q_OBJECT
+ friend class CodeGenObjectWithTextBlocks;
+public:
+
+ // Constructors/Destructors
+ //
+
+ /**
+ * Constructor
+ */
+ explicit HierarchicalCodeBlock ( CodeDocument * doc , const QString &startString = "", const QString &endString = "", const QString &comment = "");
+
+ /**
+ * Empty Destructor
+ */
+ virtual ~HierarchicalCodeBlock ( );
+
+ // Public attributes
+ //
+
+ // Public attribute accessor methods
+ //
+
+ /**
+ * Set the value of m_endText
+ * @param new_var the new value of m_endText
+ */
+ void setEndText ( const QString &new_var );
+
+ /**
+ * Get the value of m_endText
+ * @return the value of m_endText
+ */
+ QString getEndText ( );
+
+ /**
+ * Add a TextBlock object to the m_textblockVector List
+ */
+ bool addTextBlock ( TextBlock * add_object );
+
+ /**
+ * Insert a new text block before/after the existing text block. Returns
+ * false if it cannot insert the textblock.
+ */
+ bool insertTextBlock (TextBlock * newBlock, TextBlock * existingBlock, bool after = true);
+
+ /**
+ * Remove a TextBlock object from m_textblockVector List
+ * returns boolean - true if successful
+ */
+ bool removeTextBlock ( TextBlock * remove_object );
+
+ /**
+ * @param text
+ */
+ void setStartText ( const QString &text );
+
+ /**
+ * @return QString
+ */
+ QString getStartText ( );
+
+ /**
+ * Save the XMI representation of this object
+ */
+ virtual void saveToXMI ( QDomDocument & doc, QDomElement & root );
+
+ /**
+ * load params from the appropriate XMI element node.
+ */
+ virtual void loadFromXMI ( QDomElement & root );
+
+ /**
+ * @return QString
+ */
+ virtual QString toString ( );
+
+ // return a unique, and currently unallocated, text block tag for this hblock
+ QString getUniqueTag();
+ QString getUniqueTag( const QString& prefix );
+
+ /**
+ * Utility method to add accessormethods in this object
+ */
+ void addCodeClassFieldMethods ( CodeClassFieldList &list );
+
+ virtual CodeBlock * newCodeBlock();
+ virtual CodeBlockWithComments * newCodeBlockWithComments();
+ virtual HierarchicalCodeBlock * newHierarchicalCodeBlock();
+
+protected:
+
+ /** causes the text block to release all of its connections
+ * and any other text blocks that it 'owns'.
+ * needed to be called prior to deletion of the textblock.
+ */
+ virtual void release ();
+
+ /** set attributes of the node that represents this class
+ * in the XMI document.
+ */
+ virtual void setAttributesOnNode (QDomDocument & doc, QDomElement & elem );
+
+ /** set the class attributes of this object from
+ * the passed element node.
+ */
+ virtual void setAttributesFromNode ( QDomElement & element);
+
+ /** set the class attributes from a passed object
+ */
+ virtual void setAttributesFromObject (TextBlock * obj);
+
+ // look for specific text blocks which belong to code classfields
+ TextBlock * findCodeClassFieldTextBlockByTag ( const QString &tag );
+
+private:
+
+ QString m_startText;
+ QString m_endText;
+
+ QString childTextBlocksToString();
+ void initAttributes ( ) ;
+
+};
+
+#endif // HIERARCHICALCODEBLOCK_H
diff --git a/umbrello/umbrello/hisc-app-umbrello.svgz b/umbrello/umbrello/hisc-app-umbrello.svgz
new file mode 100644
index 00000000..27b89716
--- /dev/null
+++ b/umbrello/umbrello/hisc-app-umbrello.svgz
Binary files differ
diff --git a/umbrello/umbrello/import_rose.cpp b/umbrello/umbrello/import_rose.cpp
new file mode 100644
index 00000000..aeaeb7fb
--- /dev/null
+++ b/umbrello/umbrello/import_rose.cpp
@@ -0,0 +1,391 @@
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * copyright (C) 2006 *
+ * Umbrello UML Modeller Authors <uml-devel@uml.sf.net> *
+ ***************************************************************************/
+
+// own header
+#include "import_rose.h"
+
+// qt includes
+#include <qstring.h>
+#include <qtextstream.h>
+#include <qptrlist.h>
+#include <qstringlist.h>
+#include <qregexp.h>
+#include <qmessagebox.h>
+#include <klocale.h>
+#include <kapplication.h>
+#include <kdebug.h>
+// app includes
+#include "petalnode.h"
+#include "petaltree2uml.h"
+#include "umlnamespace.h" // only for the KDE4 compatibility macros
+
+namespace Import_Rose {
+
+typedef QPtrList<PetalNode> PetalNodeList;
+
+uint nClosures; // Multiple closing parentheses may appear on a single
+ // line. The parsing is done line-by-line and using
+ // recursive descent. This means that we can only handle
+ // _one_ closing parenthesis at a time, i.e. the closing
+ // of the currently parsed node. Since we may see more
+ // closing parentheses than we can handle, we need a
+ // counter indicating how many additional node closings
+ // have been seen.
+
+uint linum; // line number
+QString g_methodName;
+void methodName(const QString& m) {
+ g_methodName = m;
+}
+/**
+ * Auxiliary function for diagnostics: Return current location.
+ */
+QString loc() {
+ return "Import_Rose::" + g_methodName + " line " + QString::number(linum) + ": ";
+}
+
+/**
+ * Split a line into lexemes.
+ */
+QStringList scan(const QString& lin) {
+ QStringList result;
+ QString line = lin.stripWhiteSpace();
+ if (line.isEmpty())
+ return result; // empty
+ QString lexeme;
+ const uint len = line.length();
+ bool inString = false;
+ for (uint i = 0; i < len; i++) {
+ QChar c = line[i];
+ if (c == '"') {
+ lexeme += c;
+ if (inString) {
+ result.append(lexeme);
+ lexeme = QString();
+ }
+ inString = !inString;
+ } else if (inString ||
+ c.isLetterOrNumber() || c == '_' || c == '@') {
+ lexeme += c;
+ } else {
+ if (!lexeme.isEmpty()) {
+ result.append(lexeme);
+ lexeme = QString();
+ }
+ if (! c.isSpace()) {
+ result.append(QString(c));
+ }
+ }
+ }
+ if (!lexeme.isEmpty())
+ result.append(lexeme);
+ return result;
+}
+
+/**
+ * Emulate perl shift().
+ */
+QString shift(QStringList& l) {
+ QString first = l.first();
+ l.pop_front();
+ return first;
+}
+
+/**
+ * Check for closing of one or more scopes.
+ */
+bool checkClosing(QStringList& tokens) {
+ if (tokens.count() == 0)
+ return false;
+ if (tokens.last() == ")") {
+ // For a single closing parenthesis, we just return true.
+ // But if there are more closing parentheses, we need to increment
+ // nClosures for each scope.
+ tokens.pop_back();
+ while (tokens.count() && tokens.last() == ")") {
+ nClosures++;
+ tokens.pop_back();
+ }
+ return true;
+ }
+ return false;
+}
+
+/**
+ * Immediate values are numbers or quoted strings.
+ * @return True if the given text is a natural or negative number
+ * or a quoted string.
+ */
+bool isImmediateValue(QString s) {
+ return s.contains(QRegExp("^[\\d\\-\"]"));
+}
+
+/**
+ * Extract immediate values out of `l'.
+ * Examples of immediate value lists:
+ * number list: ( 123 , 456 )
+ * string list: ( "SomeText" 888 )
+ * Any enclosing parentheses are removed.
+ * All extracted items are also removed from `l'.
+ * For the example given above the following is returned:
+ * "123 456"
+ * or
+ * "\"SomeText\" 888"
+ */
+QString extractImmediateValues(QStringList& l) {
+ if (l.count() == 0)
+ return QString();
+ if (l.first() == "(")
+ l.pop_front();
+ QString result;
+ bool start = true;
+ while (l.count() && isImmediateValue(l.first())) {
+ if (start)
+ start = false;
+ else
+ result += ' ';
+ result += shift(l);
+ if (l.first() == ",")
+ l.pop_front();
+ }
+ if (l.first() == ")")
+ l.pop_front();
+ while (l.count() && l.first() == ")") {
+ nClosures++;
+ l.pop_front();
+ }
+ return result;
+}
+
+QString collectVerbatimText(QTextStream& stream) {
+ QString result;
+ QString line;
+ methodName("collectVerbatimText");
+ while (!(line = stream.readLine()).isNull()) {
+ linum++;
+ line = line.stripWhiteSpace();
+ if (line.isEmpty() || line.startsWith(")"))
+ break;
+ if (line[0] != '|') {
+ kError() << loc() << "expecting '|' at start of verbatim text" << endl;
+ return QString();
+ } else {
+ result += line.mid(1) + '\n';
+ }
+ }
+ if (line.isNull()) {
+ kError() << loc() << "premature EOF" << endl;
+ return QString();
+ }
+ if (! line.isEmpty()) {
+ for (uint i = 0; i < line.length(); i++) {
+ const QChar& clParenth = line[i];
+ if (clParenth != ')') {
+ kError() << loc() << "expected ')', found: " << clParenth << endl;
+ return QString();
+ }
+ nClosures++;
+ }
+ }
+ return result;
+}
+
+/**
+ * Extract the stripped down value from a (value ...) element.
+ * Example: for the input
+ * (value Text "This is some text")
+ * the following is extracted:
+ * "This is some text"
+ * Extracted elements and syntactic sugar of the value element are
+ * removed from the input list.
+ * The stream is passed into this method because it may be necessary
+ * to read new lines - in the case of verbatim text.
+ * The format of verbatim text in petal files is as follows:
+ *
+ * (value Text
+ * |This is the first line of verbatim text.
+ * |This is another line of verbatim text.
+ * )
+ * (The '|' character is supposed to be in the first column of the line)
+ * In this case the two lines are extracted without the leading '|'.
+ * The line ending '\n' of each line is preserved.
+ */
+QString extractValue(QStringList& l, QTextStream& stream) {
+ methodName("extractValue");
+ if (l.count() == 0)
+ return QString();
+ if (l.first() == "(")
+ l.pop_front();
+ if (l.first() != "value")
+ return QString();
+ l.pop_front(); // remove "value"
+ l.pop_front(); // remove the value type: could be e.g. "Text" or "cardinality"
+ QString result;
+ if (l.count() == 0) { // expect verbatim text to follow on subsequent lines
+ QString text = collectVerbatimText(stream);
+ nClosures--; // expect own closure
+ return text;
+ } else {
+ result = shift(l);
+ if (l.first() != ")") {
+ kError() << loc() << "expecting closing parenthesis" << endl;
+ return result;
+ }
+ l.pop_front();
+ }
+ while (l.count() && l.first() == ")") {
+ nClosures++;
+ l.pop_front();
+ }
+ return result;
+}
+
+/**
+ * Read attributes of a node.
+ * @param initialArgs Tokens on the line of the opening "(" of the node
+ * but with leading whitespace and the opening "(" removed.
+ * @param stream The QTextStream from which to read following lines.
+ * @return Pointer to the created PetalNode or NULL on error.
+ */
+PetalNode *readAttributes(QStringList initialArgs, QTextStream& stream) {
+ methodName("readAttributes");
+ if (initialArgs.count() == 0) {
+ kError() << loc() << "initialArgs is empty" << endl;
+ return NULL;
+ }
+ PetalNode::NodeType nt;
+ QString type = shift(initialArgs);
+ if (type == "object")
+ nt = PetalNode::nt_object;
+ else if (type == "list")
+ nt = PetalNode::nt_list;
+ else {
+ kError() << loc() << "unknown node type " << type << endl;
+ return NULL;
+ }
+ PetalNode *node = new PetalNode(nt);
+ bool seenClosing = checkClosing(initialArgs);
+ node->setInitialArgs(initialArgs);
+ if (seenClosing)
+ return node;
+ PetalNode::NameValueList attrs;
+ QString line;
+ while (!(line = stream.readLine()).isNull()) {
+ linum++;
+ line = line.stripWhiteSpace();
+ if (line.isEmpty())
+ continue;
+ QStringList tokens = scan(line);
+ QString stringOrNodeOpener = shift(tokens);
+ QString name;
+ if (nt == PetalNode::nt_object && !stringOrNodeOpener.contains(QRegExp("^[A-Za-z]"))) {
+ kError() << loc() << "unexpected line " << line << endl;
+ return NULL;
+ }
+ PetalNode::StringOrNode value;
+ if (nt == PetalNode::nt_object) {
+ name = stringOrNodeOpener;
+ if (tokens.count() == 0) { // expect verbatim text to follow on subsequent lines
+ value.string = collectVerbatimText(stream);
+ PetalNode::NameValue attr(name, value);
+ attrs.append(attr);
+ if (nClosures) {
+ // Decrement nClosures exactly once, namely for the own scope.
+ // Each recursion of readAttributes() is only responsible for
+ // its own scope. I.e. each further scope closing is handled by
+ // an outer recursion in case of multiple closing parentheses.
+ nClosures--;
+ break;
+ }
+ continue;
+ }
+ stringOrNodeOpener = shift(tokens);
+ } else if (stringOrNodeOpener != "(") {
+ value.string = stringOrNodeOpener;
+ PetalNode::NameValue attr;
+ attr.second = value;
+ attrs.append(attr);
+ if (tokens.count() && tokens.first() != ")") {
+ kDebug() << loc()
+ << "NYI - immediate list entry with more than one item" << endl;
+ }
+ if (checkClosing(tokens))
+ break;
+ continue;
+ }
+ if (stringOrNodeOpener == "(") {
+ QString nxt = tokens.first();
+ if (isImmediateValue(nxt)) {
+ value.string = extractImmediateValues(tokens);
+ } else if (nxt == "value" || nxt.startsWith("\"")) {
+ value.string = extractValue(tokens, stream);
+ } else {
+ kapp->processEvents();
+ value.node = readAttributes(tokens, stream);
+ if (value.node == NULL)
+ return NULL;
+ }
+ PetalNode::NameValue attr(name, value);
+ attrs.append(attr);
+ if (nClosures) {
+ // Decrement nClosures exactly once, namely for the own scope.
+ // Each recursion of readAttributes() is only responsible for
+ // its own scope. I.e. each further scope closing is handled by
+ // an outer recursion in case of multiple closing parentheses.
+ nClosures--;
+ break;
+ }
+ } else {
+ value.string = stringOrNodeOpener;
+ bool seenClosing = checkClosing(tokens);
+ PetalNode::NameValue attr(name, value);
+ attrs.append(attr);
+ if (seenClosing) {
+ break;
+ }
+ }
+ }
+ node->setAttributes(attrs);
+ return node;
+}
+
+bool loadFromMDL(QIODevice& file) {
+ QTextStream stream(&file);
+ stream.setEncoding(QTextStream::Latin1);
+ QString line;
+ PetalNode *root = NULL;
+ linum = 0;
+ while (!(line = stream.readLine()).isNull()) {
+ linum++;
+ if (line.contains( QRegExp("^\\s*\\(object Petal") )) {
+ while (!(line = stream.readLine()).isNull() && !line.contains(')')) {
+ linum++; // CHECK: do we need petal version info?
+ }
+ if (line.isNull())
+ break;
+ } else {
+ QRegExp objectRx("^\\s*\\(object ");
+ if (line.contains(objectRx)) {
+ nClosures = 0;
+ QStringList initialArgs = scan(line);
+ initialArgs.pop_front(); // remove opening parenthesis
+ root = readAttributes(initialArgs, stream);
+ }
+ }
+ }
+ file.close();
+ if (root == NULL)
+ return false;
+ return petalTree2Uml(root);
+}
+
+}
+
diff --git a/umbrello/umbrello/import_rose.h b/umbrello/umbrello/import_rose.h
new file mode 100644
index 00000000..b5090db3
--- /dev/null
+++ b/umbrello/umbrello/import_rose.h
@@ -0,0 +1,35 @@
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * copyright (C) 2006 *
+ * Umbrello UML Modeller Authors <uml-devel@uml.sf.net> *
+ ***************************************************************************/
+
+#ifndef IMPORT_ROSE__H
+#define IMPORT_ROSE__H
+
+#include <qiodevice.h>
+
+/**
+ * Rose model import
+ *
+ * @author Oliver Kellogg
+ * Bugs and comments to uml-devel@lists.sf.net or http://bugs.kde.org
+ */
+namespace Import_Rose {
+
+ /**
+ * Parse a file into the PetalNode internal tree representation
+ * and then create Umbrello objects by traversing the tree.
+ *
+ * @return True for success, false in case of error.
+ */
+ bool loadFromMDL(QIODevice & file);
+
+}
+
+#endif
diff --git a/umbrello/umbrello/kplayerslideraction.cpp b/umbrello/umbrello/kplayerslideraction.cpp
new file mode 100644
index 00000000..ae5c3f97
--- /dev/null
+++ b/umbrello/umbrello/kplayerslideraction.cpp
@@ -0,0 +1,412 @@
+/***************************************************************************
+ begin : Sat Jan 11 2003
+ copyright : (C) 2003 by kiriuja
+ email : kplayer-dev@en-directo.net
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+/* Taken from kplayer CVS 2003-09-21 (kplayer > 0.3.1) by Jonathan Riddell
+ * Changes from kplayer original marked by CHANGED
+ */
+
+#include <kapplication.h>
+#include <ktoolbar.h>
+#include <ktoolbarbutton.h>
+#include <qtooltip.h>
+#include <qwhatsthis.h>
+
+#include <kdebug.h>
+
+//CHANGED #include "kplayersettings.h"
+#include "kplayerslideraction.h"
+#include "kplayerslideraction.moc"
+
+void KPlayerPopupFrame::keyPressEvent (QKeyEvent* ev)
+{
+ switch ( ev -> key() )
+ {
+ case Qt::Key_Alt:
+ case Qt::Key_Tab:
+ case Qt::Key_Escape:
+ case Qt::Key_Return:
+ case Qt::Key_Enter:
+ close();
+ }
+}
+
+/*void KPlayerPopupFrame::closeEvent (QCloseEvent* ev)
+{
+ QFrame::closeEvent (ev);
+}
+
+void KPlayerPopupFrame::mousePressEvent (QMouseEvent* ev)
+{
+ QFrame::mousePressEvent (ev);
+//if ( ! rect().contains (ev -> pos()) )
+// m_outside_mouse_press = true;
+}
+
+void KPlayerPopupFrame::mouseReleaseEvent (QMouseEvent* ev)
+{
+ QFrame::mouseReleaseEvent (ev);
+ if ( m_outside_mouse_press )
+ {
+ m_outside_mouse_press = false;
+ if ( ! rect().contains (ev -> pos()) )
+ close();
+ }
+}*/
+
+KPlayerPopupSliderAction::KPlayerPopupSliderAction (const QString& text,
+ const QString& pix, const KShortcut& shortcut, const QObject* receiver,
+ const char* slot, QObject* parent, const char* name)
+ : KAction (text, pix, shortcut, parent, name)
+{
+ m_frame = new KPlayerPopupFrame;
+ m_frame -> setFrameStyle (QFrame::PopupPanel | QFrame::Raised);
+ m_frame -> setLineWidth (2);
+ m_slider = new KPlayerSlider (Qt::Vertical, m_frame);
+ m_frame -> resize (36, m_slider -> sizeHint().height() + 4);
+ m_slider -> setGeometry (m_frame -> contentsRect());
+ //CHANGED kdDebug() << "Popup slider size " << m_slider -> width() << "x" << m_slider -> height() << "\n";
+ connect (m_slider, SIGNAL (changed (int)), receiver, slot);
+}
+
+KPlayerPopupSliderAction::~KPlayerPopupSliderAction()
+{
+ delete m_frame;
+ m_frame = 0;
+}
+
+/*int KPlayerPopupSliderAction::plug (QWidget* widget, int index)
+{
+ Q_ASSERT (m_slider);
+ Q_ASSERT (widget);
+ Q_ASSERT (! isPlugged());
+ if ( ! m_slider || ! widget || isPlugged() )
+ return -1;
+ Q_ASSERT (widget -> inherits ("KToolBar"));
+ if ( ! widget -> inherits ("KToolBar") )
+ return -1;
+ int retval = KAction::plug (widget, index);
+// if ( retval >= 0 )
+// m_slider -> reparent (widget, QPoint());
+ return retval;
+}
+
+void KPlayerPopupSliderAction::unplug (QWidget* widget)
+{
+ Q_ASSERT (m_slider);
+ Q_ASSERT (widget);
+ Q_ASSERT (isPlugged());
+ Q_ASSERT (widget -> inherits ("KToolBar"));
+ if ( ! m_slider || ! widget || ! isPlugged() || ! widget -> inherits ("KToolBar") )
+ return;
+//m_slider -> reparent (0, QPoint());
+ KAction::unplug (widget);
+}*/
+
+void KPlayerPopupSliderAction::slotActivated (void)
+{
+ KAction::slotActivated();
+ QWidget* button = 0;
+ if ( sender() )
+ {
+ //CHANGED kdDebug() << "Sender class name: " << sender() -> className() << "\n";
+ if ( sender() -> inherits ("KToolBarButton") )
+ button = (QWidget*) sender();
+ else if ( sender() -> inherits ("KToolBar") )
+ {
+ KToolBar* toolbar = (KToolBar*) sender();
+ int index = findContainer (toolbar);
+ if ( index >= 0 )
+ button = toolbar -> getButton (itemId (index));
+ }
+ }
+ QPoint point;
+ if ( button )
+ point = button -> mapToGlobal (QPoint (0, button -> height()));
+ else
+ {
+ point = QCursor::pos() - QPoint (m_frame -> width() / 2, m_frame -> height() / 2);
+ if ( point.x() + m_frame -> width() > QApplication::desktop() -> width() )
+ point.setX (QApplication::desktop() -> width() - m_frame -> width());
+ if ( point.y() + m_frame -> height() > QApplication::desktop() -> height() )
+ point.setY (QApplication::desktop() -> height() - m_frame -> height());
+ if ( point.x() < 0 )
+ point.setX (0);
+ if ( point.y() < 0 )
+ point.setY (0);
+ }
+ //CHANGED kdDebug() << "Point: " << point.x() << "x" << point.y() << "\n";
+ m_frame -> move (point);
+ /*if ( kapp && kapp -> activeWindow() )
+ {
+ QMouseEvent me (QEvent::MouseButtonRelease, QPoint(0,0), QPoint(0,0), QMouseEvent::LeftButton, QMouseEvent::NoButton);
+ QApplication::sendEvent (kapp -> activeWindow(), &me);
+ }*/
+ m_frame -> show();
+ m_slider -> setFocus();
+}
+
+KPlayerSliderAction::KPlayerSliderAction (const QString& text, const KShortcut& cut,
+ const QObject* receiver, const char* slot, KActionCollection* parent, const char* name)
+ : KWidgetAction (new KPlayerSlider (Qt::Horizontal, 0, name), text, cut, receiver, slot, parent, name)
+ //: KAction (text, 0, parent, name)
+{
+ setAutoSized (true);
+ connect (slider(), SIGNAL (changed (int)), receiver, slot);
+}
+
+KPlayerSliderAction::~KPlayerSliderAction()
+{
+}
+
+int KPlayerSliderAction::plug (QWidget* widget, int index)
+{
+ //Q_ASSERT (widget);
+ //Q_ASSERT (! isPlugged());
+ //Q_ASSERT (slider());
+ //if ( ! slider() || ! widget || isPlugged() )
+ // return -1;
+ //Q_ASSERT (widget -> inherits ("KToolBar"));
+ //if ( ! widget -> inherits ("KToolBar") )
+ // return -1;
+ //if ( kapp && ! kapp -> authorizeKAction (name()) )
+ // return -1;
+ int result = KWidgetAction::plug (widget, index);
+ if ( result < 0 )
+ return result;
+ KToolBar* toolbar = (KToolBar*) widget;
+ //int id = getToolButtonID();
+ //kdDebug() << "Orientation: " << toolbar -> orientation() << "\n";
+ //m_slider -> reparent (toolbar, QPoint());
+ //toolbar -> insertWidget (id, 0, m_slider, index);
+ //toolbar -> setItemAutoSized (id, true);
+ //QWhatsThis::remove (m_slider);
+ //if ( ! whatsThis().isEmpty() )
+ // QWhatsThis::add (m_slider, whatsThis());
+ //if ( ! text().isEmpty() )
+ // QToolTip::add (m_slider, text());
+ //addContainer (toolbar, id);
+ //setupToolbar (toolbar -> orientation(), toolbar);
+ orientationChanged (toolbar -> orientation());
+ connect (toolbar, SIGNAL (orientationChanged (Orientation)), this, SLOT (orientationChanged (Orientation)));
+ //connect (toolbar, SIGNAL (destroyed()), this, SLOT (toolbarDestroyed()));
+ //if ( parentCollection() )
+ // parentCollection() -> connectHighlight (toolbar, this);
+ //return containerCount() - 1;
+ return result;
+}
+
+void KPlayerSliderAction::unplug (QWidget* widget)
+{
+ //Q_ASSERT (m_slider);
+ //Q_ASSERT (isPlugged());
+ //Q_ASSERT (widget -> inherits ("KToolBar"));
+ KWidgetAction::unplug (widget);
+ if ( ! slider() || ! isPlugged() || widget != slider() -> parent() )
+ return;
+ //KToolBar* toolbar = (KToolBar*) widget;
+ disconnect (widget, SIGNAL (orientationChanged (Orientation)), this, SLOT (orientationChanged (Orientation)));
+ //disconnect (toolbar, SIGNAL (destroyed()), this, SLOT (toolbarDestroyed()));
+ //m_slider -> reparent (0, QPoint());
+ /*int index = findContainer (toolbar);
+ if ( index == -1 )
+ return;
+ bar -> removeItem (menuId (index));
+ removeContainer (index);*/
+}
+
+/*void KPlayerSliderAction::setupToolbar (Orientation orientation, KToolBar* toolbar)
+{
+ if ( orientation == Qt::Horizontal )
+ {
+// toolbar -> setMinimumWidth (300);
+// toolbar -> setMinimumHeight (0);
+ toolbar -> setFixedExtentWidth (300);
+ toolbar -> setFixedExtentHeight (-1);
+// toolbar -> setHorizontallyStretchable (true);
+// toolbar -> setVerticallyStretchable (false);
+ }
+ else
+ {
+// toolbar -> setMinimumWidth (0);
+// toolbar -> setMinimumHeight (300);
+ toolbar -> setFixedExtentWidth (-1);
+ toolbar -> setFixedExtentHeight (300);
+// toolbar -> setHorizontallyStretchable (false);
+// toolbar -> setVerticallyStretchable (true);
+ }
+}*/
+
+void KPlayerSliderAction::orientationChanged (Qt::Orientation orientation)
+{
+ //if ( sender() && sender() -> inherits ("KToolBar") )
+ // setupToolbar (orientation, (KToolBar*) sender());
+ //Q_ASSERT (m_slider);
+ //Q_ASSERT (isPlugged());
+ if ( slider() )
+ slider() -> setOrientation (orientation);
+}
+
+/*void KPlayerSliderAction::toolbarDestroyed (void)
+{
+ if ( m_slider )
+ m_slider -> reparent (0, QPoint());
+}*/
+
+KPlayerSlider::KPlayerSlider (Qt::Orientation orientation, QWidget* parent, const char* name)
+//CHANGED : QSlider (orientation, parent, name)
+ : QSlider (300, 2200, 400, 1000, orientation, parent, name)
+{
+ m_changing_orientation = false;
+ setTickmarks (QSlider::Both);
+ connect (this, SIGNAL (valueChanged (int)), this, SLOT (sliderValueChanged (int)));
+}
+
+KPlayerSlider::~KPlayerSlider()
+{
+ //CHANGED kdDebug() << "KPlayerSlider destroyed\n";
+}
+
+QSize KPlayerSlider::sizeHint() const
+{
+ QSize hint = QSlider::sizeHint();
+ //CHANGED int length = kPlayerSettings() -> preferredSliderLength();
+ int length = 200;
+ if ( orientation() == Qt::Horizontal )
+ {
+ if ( hint.width() < length )
+ hint.setWidth (length);
+ }
+ else
+ {
+ if ( hint.height() < length )
+ hint.setHeight (length);
+ }
+ return hint;
+}
+
+QSize KPlayerSlider::minimumSizeHint() const
+{
+ //kdDebug() << "KPlayerSlider minimum size hint\n";
+ QSize hint = QSlider::minimumSizeHint();
+ //CHANGED int length = kPlayerSettings() -> minimumSliderLength();
+ int length = 200;
+ if ( orientation() == Qt::Horizontal )
+ {
+ if ( hint.width() < length )
+ hint.setWidth (length);
+ }
+ else
+ {
+ if ( hint.height() < length )
+ hint.setHeight (length);
+ }
+ return hint;
+}
+
+void KPlayerSlider::setOrientation (Qt::Orientation o)
+{
+ if ( o == orientation() )
+ return;
+ m_changing_orientation = true;
+ int minValue = QSlider::minValue();
+ int maxValue = QSlider::maxValue();
+ int value = QSlider::value();
+ QSlider::setOrientation (o);
+ QSlider::setMinValue (- maxValue);
+ QSlider::setMaxValue (- minValue);
+ QSlider::setValue (- value);
+ m_changing_orientation = false;
+}
+
+int KPlayerSlider::minValue (void) const
+{
+ if ( orientation() == Qt::Horizontal )
+ return QSlider::minValue();
+ return - QSlider::maxValue();
+}
+
+void KPlayerSlider::setMinValue (int minValue)
+{
+ if ( orientation() == Qt::Horizontal )
+ QSlider::setMinValue (minValue);
+ else
+ QSlider::setMaxValue (- minValue);
+}
+
+int KPlayerSlider::maxValue (void) const
+{
+ if ( orientation() == Qt::Horizontal )
+ return QSlider::maxValue();
+ return - QSlider::minValue();
+}
+
+void KPlayerSlider::setMaxValue (int maxValue)
+{
+ if ( orientation() == Qt::Horizontal )
+ QSlider::setMaxValue (maxValue);
+ else
+ QSlider::setMinValue (- maxValue);
+}
+
+int KPlayerSlider::lineStep (void) const
+{
+ return QSlider::lineStep();
+}
+
+void KPlayerSlider::setLineStep (int lineStep)
+{
+ QSlider::setLineStep (lineStep);
+}
+
+int KPlayerSlider::pageStep (void) const
+{
+ return QSlider::pageStep();
+}
+
+void KPlayerSlider::setPageStep (int pageStep)
+{
+ QSlider::setPageStep (pageStep);
+ setTickInterval (pageStep);
+}
+
+int KPlayerSlider::value (void) const
+{
+ if ( orientation() == Qt::Horizontal )
+ return QSlider::value();
+ return - QSlider::value();
+}
+
+void KPlayerSlider::setValue (int value, int)
+{
+ if ( orientation() == Qt::Horizontal )
+ QSlider::setValue (value);
+ else
+ QSlider::setValue (- value);
+}
+
+void KPlayerSlider::setup (int minValue, int maxValue, int value, int pageStep, int lineStep)
+{
+ setMinValue (minValue);
+ setMaxValue (maxValue);
+ setLineStep (lineStep);
+ setPageStep (pageStep);
+ setValue (value);
+}
+
+void KPlayerSlider::sliderValueChanged (int)
+{
+ if ( ! m_changing_orientation )
+ emit changed (value());
+}
diff --git a/umbrello/umbrello/kplayerslideraction.h b/umbrello/umbrello/kplayerslideraction.h
new file mode 100644
index 00000000..e8bb6ff9
--- /dev/null
+++ b/umbrello/umbrello/kplayerslideraction.h
@@ -0,0 +1,202 @@
+/***************************************************************************
+ kplayerslideraction.h
+ ---------------------
+ begin : Sat Jan 11 2003
+ copyright : (C) 2003 by kiriuja
+ email : kplayer-dev@en-directo.net
+ ***************************************************************************/
+
+/***************************************************************************
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the 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 KPLAYERSLIDERACTION_H
+#define KPLAYERSLIDERACTION_H
+
+#include <kaction.h>
+#include <qslider.h>
+
+/**KPlayer's slider widget. Works around the Qt upside-down slider bug.
+ * Taken from kplayer CVS 2003-09-21 (kplayer > 0.3.1) by Jonathan Riddell
+ *@author kiriuja
+ */
+class KPlayerSlider : public QSlider
+{
+ Q_OBJECT
+
+public:
+ /** The KPlayerSlider constructor. Parameters are passed on to QSlider.
+ */
+ explicit KPlayerSlider (Qt::Orientation, QWidget* parent = 0, const char* name = 0);
+ /** The KPlayerSlider destructor. Does nothing.
+ */
+ virtual ~KPlayerSlider();
+
+ /** The size hint.
+ */
+ virtual QSize sizeHint() const;
+ /** The minimum size hint.
+ */
+ virtual QSize minimumSizeHint() const;
+
+ /** The minimum value.
+ */
+ int minValue (void) const;
+ /** Sets the minimum value.
+ */
+ void setMinValue (int);
+ /** The maximum value.
+ */
+ int maxValue (void) const;
+ /** Sets the maximum value.
+ */
+ void setMaxValue (int);
+ /** The line step.
+ */
+ int lineStep (void) const;
+ /** Sets the line step.
+ */
+ void setLineStep (int);
+ /** The page step.
+ */
+ int pageStep (void) const;
+ /** Sets the page step.
+ */
+ void setPageStep (int);
+ /** The current value.
+ */
+ int value (void) const;
+ /** Sets the current value. The extra parameter prevents overriding of the virtual QSlider::setValue.
+ */
+ void setValue (int, int = 0); // do not override the virtual setValue
+
+ /** Sets up the slider by setting five options in one go.
+ */
+ void setup (int minValue, int maxValue, int value, int pageStep, int lineStep = 1);
+ /** Sets the slider orientation.
+ */
+ virtual void setOrientation (Qt::Orientation);
+
+signals:
+ /** Emitted when the slider value changes.
+ */
+ void changed (int);
+
+protected slots:
+ /** Receives the valueChanged signal from QSlider.
+ */
+ void sliderValueChanged (int);
+
+protected:
+ // Recursion prevention. Should be private.
+ bool m_changing_orientation;
+
+ friend class KPlayerSliderAction;
+ friend class KPlayerPopupSliderAction;
+};
+
+/**KPlayer popup frame.
+ *@author kiriuja
+ */
+class KPlayerPopupFrame : public QFrame
+{
+ Q_OBJECT
+
+public:
+ /** The KPlayerPopupFrame constructor. Parameters are passed on to QFrame.
+ */
+ KPlayerPopupFrame (QWidget* parent = 0, const char* name = 0)
+ : QFrame (parent, name, Qt::WType_Popup) { }
+ /** The KPlayerPopupFrame destructor. Does nothing.
+ */
+ virtual ~KPlayerPopupFrame() { }
+
+protected:
+ /** Closes the popup frame when Alt, Tab, Esc, Enter or Return is pressed.
+ */
+ virtual void keyPressEvent (QKeyEvent*);
+};
+
+/**Action representing a popup slider activated by a toolbar button.
+ *@author kiriuja
+ */
+class KPlayerPopupSliderAction : public KAction
+{
+ Q_OBJECT
+
+public:
+ /** The KPlayerPopupSliderAction constructor. Parameters are passed on to KAction.
+ */
+ KPlayerPopupSliderAction (const QString& text, const QString& pix, const KShortcut& shortcut,
+ const QObject* receiver, const char* slot, QObject* parent = 0, const char* name = 0);
+ /** The KPlayerPopupSliderAction destructor. Deletes the KPlayerPopupFrame.
+ */
+ virtual ~KPlayerPopupSliderAction();
+
+ /** Returns a pointer to the KPlayerSlider object.
+ */
+ KPlayerSlider* slider (void)
+ { return m_slider; }
+
+ /** Plugs the action into the toolbar. Reparents the slider into the toolbar. */
+ //virtual int plug (QWidget*, int = -1);
+ /** Unplugs the action from the toolbar. Reparents the slider out of the toolbar. */
+ //virtual void unplug (QWidget*);
+
+protected slots:
+ /** Pops up the slider.
+ */
+ virtual void slotActivated (void);
+
+protected:
+ /** The slider.
+ */
+ KPlayerSlider* m_slider;
+ /** The popup frame.
+ */
+ KPlayerPopupFrame* m_frame;
+};
+
+/**Slider action suitable for insertion into a toolbar.
+ *@author kiriuja
+ */
+class KPlayerSliderAction : public KWidgetAction
+{
+ Q_OBJECT
+
+public:
+ /** The KPlayerSliderAction constructor. Parameters are passed on to KAction.
+ */
+ KPlayerSliderAction (const QString& text, const KShortcut&, const QObject* receiver,
+ const char* slot, KActionCollection* parent = 0, const char* name = 0);
+ /** The KPlayerSliderAction destructor. Does nothing.
+ */
+ virtual ~KPlayerSliderAction();
+
+ /** Returns a pointer to the KPlayerSlider object.
+ */
+ KPlayerSlider* slider (void)
+ { return (KPlayerSlider*) widget(); }
+
+ /** Plugs the slider into the toolbar.
+ */
+ virtual int plug (QWidget* widget, int index = -1);
+ /** Unplugs the slider from the toolbar.
+ */
+ virtual void unplug (QWidget* widget);
+
+protected slots:
+ /** Changes the slider orientation when the toolbar orientation changes.
+ */
+ void orientationChanged (Qt::Orientation);
+
+protected:
+ /** The slider.
+ */
+ //KPlayerSlider* m_slider;
+};
+
+#endif
diff --git a/umbrello/umbrello/kstartuplogo.cpp b/umbrello/umbrello/kstartuplogo.cpp
new file mode 100644
index 00000000..5cefe463
--- /dev/null
+++ b/umbrello/umbrello/kstartuplogo.cpp
@@ -0,0 +1,55 @@
+/*
+ * copyright (C) 2000
+ * Michael Edwardes <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 "kstartuplogo.h"
+#include <kapplication.h>
+#include <kstandarddirs.h>
+#include <qtimer.h>
+
+KStartupLogo::KStartupLogo(QWidget * parent, const char *name)
+ : QWidget(parent,name, Qt::WStyle_NoBorder | Qt::WStyle_Customize | Qt::WDestructiveClose )
+,m_bReadyToHide(false) {
+ //pm.load(locate("appdata", "pics/startlogo.png"));
+ KStandardDirs * dirs = KGlobal::dirs();
+ QString dataDir = dirs -> findResourceDir("data", "umbrello/pics/object.png");
+ dataDir += "/umbrello/pics/";
+ QPixmap pm(dataDir + "startlogo.png");
+ setBackgroundPixmap(pm);
+ setGeometry(QApplication::desktop()->width()/2-pm.width()/2,
+ QApplication::desktop()->height()/2-pm.height()/2,
+ pm.width(),pm.height());
+
+ timer = new QTimer(this);
+ connect( timer, SIGNAL(timeout()), this, SLOT(timerDone()) );
+ timer->start(2000, true);
+}
+
+KStartupLogo::~KStartupLogo() {
+ delete timer;
+}
+
+void KStartupLogo::mousePressEvent( QMouseEvent*) {
+ // for the haters of raising startlogos
+ if (m_bReadyToHide)
+ hide();
+}
+
+void KStartupLogo::timerDone() {
+ this->hide();
+}
+
+void KStartupLogo::setHideEnabled(bool bEnabled) {
+ m_bReadyToHide = bEnabled;
+}
+#include "kstartuplogo.moc"
diff --git a/umbrello/umbrello/kstartuplogo.h b/umbrello/umbrello/kstartuplogo.h
new file mode 100644
index 00000000..d8f4af7a
--- /dev/null
+++ b/umbrello/umbrello/kstartuplogo.h
@@ -0,0 +1,49 @@
+/*
+ * copyright (C) 2000
+ * Michael Edwardes <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
+
+#include <qwidget.h>
+
+
+/**
+ * Displays a startup splash screen.
+ * This class is mostly borrowed from another project, probably KMyMoney2.
+ * Bugs and comments to uml-devel@lists.sf.net or http://bugs.kde.org
+ */
+class KStartupLogo : public QWidget {
+ Q_OBJECT
+public:
+ KStartupLogo(QWidget *parent=0, const char *name=0);
+ ~KStartupLogo();
+ void setHideEnabled(bool bEnabled);
+
+protected:
+ virtual void mousePressEvent( QMouseEvent*);
+ bool m_bReadyToHide;
+ QTimer* timer;
+
+public slots:
+ void timerDone();
+
+};
+
+#endif
+
+
+
+
+
diff --git a/umbrello/umbrello/linepath.cpp b/umbrello/umbrello/linepath.cpp
new file mode 100644
index 00000000..59cf105f
--- /dev/null
+++ b/umbrello/umbrello/linepath.cpp
@@ -0,0 +1,957 @@
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * copyright (C) 2002-2007 *
+ * Umbrello UML Modeller Authors <uml-devel@uml.sf.net> *
+ ***************************************************************************/
+
+// own header
+#include "linepath.h"
+
+// system includes
+#include <cstdlib>
+#include <cmath>
+
+// qt includes
+#include <qcanvas.h>
+#include <qdatastream.h>
+#include <qdom.h>
+
+// kde includes
+#include <kdebug.h>
+
+// application includes
+#include "associationwidget.h"
+#include "activitywidget.h"
+#include "widget_utils.h"
+#include "umlview.h"
+#include "umldoc.h"
+#include "uml.h"
+
+LinePath::Circle::Circle(QCanvas * canvas, int radius /* = 0 */)
+ : QCanvasEllipse(radius * 2, radius * 2, canvas) {
+}
+
+void LinePath::Circle::setX(int x) {
+ QCanvasItem::setX( (double) x );
+}
+
+void LinePath::Circle::setY(int y) {
+ QCanvasItem::setY( (double) y );
+}
+
+void LinePath::Circle::setRadius(int radius) {
+ QCanvasEllipse::setSize(radius * 2, radius * 2);
+}
+
+int LinePath::Circle::getRadius() const {
+ return (QCanvasEllipse::height() / 2);
+}
+
+void LinePath::Circle::drawShape(QPainter& p) {
+ int diameter = height();
+ int radius = diameter / 2;
+ p.drawEllipse( (int)x() - radius, (int)y() - radius, diameter, diameter);
+}
+
+LinePath::LinePath() {
+ m_RectList.setAutoDelete( true );
+ m_LineList.setAutoDelete( true );
+ m_HeadList.setAutoDelete( true );
+ m_ParallelList.setAutoDelete( true );
+ m_bSelected = false;
+ m_pClearPoly = 0;
+ m_pCircle = 0;
+ m_PointArray.resize( 4 );
+ m_ParallelLines.resize( 4 );
+ m_pAssociation = 0;
+ m_bHeadCreated = false;
+ m_bParallelLineCreated = false;
+ m_DockRegion = TopBottom;
+}
+
+LinePath::~LinePath() {}
+
+void LinePath::setAssociation(AssociationWidget * association ) {
+ if( !association )
+ return;
+ cleanup();
+ m_pAssociation = association;
+ createHeadLines();
+ if( getAssocType() == Uml::at_Coll_Message )
+ setupParallelLine();
+ UMLView * view = (UMLView *)m_pAssociation -> parent();
+ connect( view, SIGNAL( sigColorChanged( Uml::IDType ) ), this, SLOT( slotLineColorChanged( Uml::IDType ) ) );
+ connect( view, SIGNAL( sigLineWidthChanged( Uml::IDType ) ), this, SLOT( slotLineWidthChanged( Uml::IDType ) ) );
+}
+
+QPoint LinePath::getPoint( int pointIndex ) {
+ int count = m_LineList.count();
+ if( count == 0 || pointIndex > count || pointIndex < 0)
+ return QPoint( -1, -1 );
+
+ if( pointIndex == count ) {
+ QCanvasLine * line = m_LineList.last();
+ return line -> endPoint();
+ }
+ QCanvasLine * line = m_LineList.at( pointIndex );
+ return line -> startPoint();
+}
+
+bool LinePath::setPoint( int pointIndex, const QPoint &point ) {
+ int count = m_LineList.count();
+ if( count == 0 || pointIndex > count || pointIndex < 0)
+ return false;
+ if (point.x() == 0 && point.y() == 0) {
+ kError() << "LinePath::setPoint:ignoring request for (0,0)" << endl;
+ return false;
+ }
+
+ if( pointIndex == count) {
+ QCanvasLine * line = m_LineList.last();
+ QPoint p = line -> startPoint();
+ line -> setPoints( p.x(), p.y(), point.x(), point.y() );
+ moveSelected( pointIndex );
+ update();
+ return true;
+ }
+ if( pointIndex == 0 ) {
+ QCanvasLine * line = m_LineList.first();
+ QPoint p = line -> endPoint();
+ line -> setPoints( point.x(), point.y(), p.x(), p.y() );
+ moveSelected( pointIndex );
+ update();
+ return true;
+ }
+ QCanvasLine * line = m_LineList.at( pointIndex );
+ QPoint p = line -> endPoint();
+ line -> setPoints( point.x(), point.y(), p.x(), p.y() );
+ line = m_LineList.at( pointIndex - 1 );
+ p = line -> startPoint();
+ line -> setPoints( p.x(), p.y(), point.x(), point.y() );
+ moveSelected( pointIndex );
+ update();
+ return true;
+}
+
+bool LinePath::isPoint( int pointIndex, const QPoint &point, unsigned short delta) {
+ int count = m_LineList.count();
+ if ( pointIndex >= count )
+ return false;
+
+ QCanvasLine * line = m_LineList.at( pointIndex );
+
+ /* check if the given point is the start or end point of the line */
+ if ( (
+ abs( line -> endPoint().x() - point.x() ) <= delta
+ &&
+ abs( line -> endPoint().y() - point.y() ) <= delta
+ ) || (
+ abs( line -> startPoint().x() - point.x() ) <= delta
+ &&
+ abs( line -> startPoint().y() - point.y() ) <= delta
+ ) )
+ return true;
+
+ /* check if the given point is the start or end point of the line */
+ return false;
+}
+
+bool LinePath::insertPoint( int pointIndex, const QPoint &point ) {
+ int count = m_LineList.count();
+ if( count == 0 )
+ return false;
+ const bool bLoading = UMLApp::app()->getDocument()->loading();
+
+ if( count == 1 || pointIndex == 1) {
+ QCanvasLine * first = m_LineList.first();
+ QPoint sp = first -> startPoint();
+ QPoint ep = first -> endPoint();
+ first -> setPoints( sp.x(), sp.y(), point.x(), point.y() );
+ QCanvasLine * line = new QCanvasLine( getCanvas() );
+ line -> setZ( -2 );
+ line -> setPoints( point.x(), point.y(), ep.x(), ep.y() );
+ line -> setPen( getPen() );
+ line -> setVisible( true );
+ m_LineList.insert( 1, line );
+ if (!bLoading)
+ setupSelected();
+ return true;
+ }
+ if( count + 1 == pointIndex ) {
+ QCanvasLine * before = m_LineList.last();
+ QPoint sp = before -> startPoint();
+ QPoint ep = before -> endPoint();
+ before -> setPoints( sp.x(), sp.y(), point.x(), point.y() );
+ QCanvasLine * line = new QCanvasLine( getCanvas() );
+ line -> setPoints( point.x(), point.y(), ep.x(), ep.y() );
+ line -> setZ( -2 );
+ line -> setPen( getPen() );
+ line -> setVisible( true );
+ m_LineList.append( line );
+ if (!bLoading)
+ setupSelected();
+ return true;
+ }
+ QCanvasLine * before = m_LineList.at( pointIndex - 1 );
+ QPoint sp = before -> startPoint();
+ QPoint ep = before -> endPoint();
+ before -> setPoints( sp.x(), sp.y(), point.x(), point.y() );
+ QCanvasLine * line = new QCanvasLine(getCanvas() );
+ line -> setPoints( point.x(), point.y(), ep.x(), ep.y() );
+ line -> setZ( -2 );
+ line -> setPen( getPen() );
+ line -> setVisible( true );
+ m_LineList.insert( pointIndex, line );
+ if (!bLoading)
+ setupSelected();
+ return true;
+}
+
+bool LinePath::removePoint( int pointIndex, const QPoint &point, unsigned short delta )
+{
+ /* get the number of line segments */
+ int count = m_LineList.count();
+ if ( pointIndex >= count )
+ return false;
+
+ /* we don't know if the user clicked on the start- or endpoint of a
+ * line segment */
+ QCanvasLine * current_line = m_LineList.at( pointIndex );
+ if (abs( current_line -> endPoint().x() - point.x() ) <= delta
+ &&
+ abs( current_line -> endPoint().y() - point.y() ) <= delta)
+ {
+ /* the user clicked on the end point of the line;
+ * we have to make sure that this isn't the last line segment */
+ if (pointIndex >= count - 1)
+ return false;
+
+ /* the next segment will get the starting point from the current one,
+ * which is going to be removed */
+ QCanvasLine * next_line = m_LineList.at( pointIndex + 1 );
+ QPoint startPoint = current_line -> startPoint();
+ QPoint endPoint = next_line -> endPoint();
+ next_line -> setPoints(startPoint.x(), startPoint.y(),
+ endPoint.x(), endPoint.y());
+
+ } else
+ if (abs( current_line -> startPoint().x() - point.x() ) <= delta
+ &&
+ abs( current_line -> startPoint().y() - point.y() ) <= delta)
+ {
+ /* the user clicked on the start point of the line;
+ * we have to make sure that this isn't the first line segment */
+ if (pointIndex < 1)
+ return false;
+
+ /* the previous segment will get the end point from the current one,
+ * which is going to be removed */
+ QCanvasLine * previous_line = m_LineList.at( pointIndex - 1 );
+ QPoint startPoint = previous_line -> startPoint();
+ QPoint endPoint = current_line -> endPoint();
+ previous_line -> setPoints(startPoint.x(), startPoint.y(),
+ endPoint.x(), endPoint.y());
+ } else {
+ /* the user clicked neither on the start- nor on the end point of
+ * the line; this really shouldn't happen, but just make sure */
+ return false;
+ }
+
+
+ /* remove the segment from the list */
+ m_LineList.remove( pointIndex );
+
+ return true;
+}
+
+bool LinePath::setStartEndPoints( const QPoint &start, const QPoint &end ) {
+ int count = m_LineList.count();
+
+ if( count == 0 ) {
+ QCanvasLine * line = new QCanvasLine(getCanvas() );
+ line -> setPoints( start.x(), start.y(), end.x(), end.y() );
+ line -> setZ( -2 );
+ line -> setPen( getPen() );
+ line -> setVisible( true );
+ m_LineList.append( line );
+ return true;
+ }
+ bool status = setPoint( 0, start );
+ if( status)
+ return setPoint( count , end );
+ return false;
+}
+
+int LinePath::count() {
+ return m_LineList.count() + 1;
+}
+
+int LinePath::onLinePath( const QPoint &position ) {
+ QCanvasItemList list = getCanvas() -> collisions( position );
+ int index = -1;
+
+ QCanvasItemList::iterator end(list.end());
+ for(QCanvasItemList::iterator item_it(list.begin()); item_it != end; ++item_it ) {
+ if( ( index = m_LineList.findRef( (QCanvasLine*)*item_it ) ) != -1 )
+ break;
+ }//end for
+ return index;
+}
+
+void LinePath::setSelected( bool select ) {
+ if(select)
+ setupSelected();
+ else if( m_RectList.count() > 0 )
+ m_RectList.clear();
+}
+
+void LinePath::setAssocType( Uml::Association_Type type ) {
+ LineListIt it( m_LineList );
+ QCanvasLine * line = 0;
+ while( ( line = it.current() ) ) {
+ line -> setPen( getPen() );
+ ++it;
+ }
+ if( m_pClearPoly ) {
+ delete m_pClearPoly;
+ m_pClearPoly = 0;
+ }
+ if( type == Uml::at_Coll_Message )
+ setupParallelLine();
+ else
+ createHeadLines();
+ update();
+}
+
+void LinePath::update() {
+ if (getAssocType() == Uml::at_Coll_Message) {
+ if (m_bParallelLineCreated) {
+ calculateParallelLine();
+ updateParallelLine();
+ } else
+ setupParallelLine();
+ } else if (m_bHeadCreated) {
+ calculateHead();
+ updateHead();
+ } else {
+ createHeadLines();
+ }
+}
+
+void LinePath::slotLineColorChanged( Uml::IDType viewID ) {
+ if(m_pAssociation->getUMLView()->getID() != viewID) {
+ return;
+ }
+ setLineColor( m_pAssociation->getUMLView()->getLineColor() );
+}
+
+
+void LinePath::setLineColor( const QColor &color ) {
+ QCanvasLine * line = 0;
+ uint linewidth = 0;
+ LineListIt it( m_LineList );
+ while( ( line = it.current() ) ) {
+ linewidth = line->pen().width();
+ line -> setPen( QPen( color, linewidth ) );
+ ++it;
+ }
+ LineListIt hit( m_HeadList );
+ while( ( line = hit.current() ) ) {
+ linewidth = line->pen().width();
+ line -> setPen( QPen( color, linewidth ) );
+ ++hit;
+ }
+ LineListIt pit( m_ParallelList );
+ while( ( line = pit.current() ) ) {
+ linewidth = line->pen().width();
+ line -> setPen( QPen( color, linewidth ) );
+ ++pit;
+ }
+
+ if( getAssocType() == Uml::at_Aggregation )
+ if (m_pClearPoly) m_pClearPoly -> setBrush( QBrush( Qt::white ) );
+ else if( getAssocType() == Uml::at_Composition )
+ if (m_pClearPoly) m_pClearPoly -> setBrush( QBrush( color ) );
+
+ if( m_pCircle ) {
+ linewidth = m_pCircle->pen().width();
+ m_pCircle->setPen( QPen(color, linewidth) );
+ }
+}
+
+void LinePath::slotLineWidthChanged( Uml::IDType viewID ) {
+ if(m_pAssociation->getUMLView()->getID() != viewID) {
+ return;
+ }
+ setLineWidth( m_pAssociation->getUMLView()->getLineWidth() );
+}
+
+void LinePath::setLineWidth( uint width ) {
+ QCanvasLine * line = 0;
+ QColor linecolor;
+ LineListIt it( m_LineList );
+ while( ( line = it.current() ) ) {
+ linecolor = line->pen().color();
+ line -> setPen( QPen( linecolor, width ) );
+ ++it;
+ }
+ LineListIt hit( m_HeadList );
+ while( ( line = hit.current() ) ) {
+ linecolor = line->pen().color();
+ line -> setPen( QPen( linecolor, width ) );
+ ++hit;
+ }
+ LineListIt pit( m_ParallelList );
+ while( ( line = pit.current() ) ) {
+ linecolor = line->pen().color();
+ line -> setPen( QPen( linecolor, width ) );
+ ++pit;
+ }
+
+ if( m_pCircle ) {
+ linecolor = m_pCircle->pen().color();
+ m_pCircle->setPen( QPen(linecolor, width) );
+ }
+}
+
+void LinePath::moveSelected( int pointIndex ) {
+ int lineCount = m_LineList.count();
+ if( !m_bSelected ) {
+ m_RectList.clear();
+ return;
+ }
+ if( (int)m_RectList.count() + 1 != lineCount )
+ setupSelected();
+ QCanvasRectangle * rect = 0;
+ QCanvasLine * line = 0;
+ if( pointIndex == lineCount || lineCount == 1) {
+ line = m_LineList.last();
+ QPoint p = line -> endPoint();
+ rect = m_RectList.last();
+ rect -> setX( p.x() );
+ rect -> setY( p.y() );
+ rect -> setZ( 4 );
+ return;
+ }
+ line = m_LineList.at( pointIndex );
+ QPoint p = line -> startPoint();
+ rect = m_RectList.at( pointIndex );
+ rect -> setX( p.x() );
+ rect -> setY( p.y() );
+ rect -> setZ( 4 );
+}
+
+void LinePath::setupSelected() {
+ m_RectList.clear();
+ QCanvasLine * line = 0;
+ LineListIt it( m_LineList );
+ while( ( line = it.current() ) ) {
+ QPoint sp = line -> startPoint();
+ QCanvasRectangle *rect = Widget_Utils::decoratePoint(sp);
+ m_RectList.append( rect );
+ ++it;
+ }
+ //special case for last point
+ line = m_LineList.last();
+ QPoint p = line -> endPoint();
+ QCanvasRectangle *rect = Widget_Utils::decoratePoint(p);
+ m_RectList.append( rect );
+ update();
+}
+
+QPen LinePath::getPen() {
+ Uml::Association_Type type = getAssocType();
+ if( type == Uml::at_Dependency || type == Uml::at_Realization || type == Uml::at_Anchor )
+ return QPen( getLineColor(), getLineWidth(), Qt::DashLine );
+ return QPen( getLineColor(), getLineWidth() );
+}
+
+void LinePath::calculateHead() {
+ uint size = m_LineList.count();
+ QPoint farPoint;
+ int halfLength = 10;
+ double arrowAngle = 0.2618; // 0.5 * atan(sqrt(3.0) / 3.0) = 0.2618
+ Uml::Association_Type at = getAssocType();
+ bool diamond = (at == Uml::at_Aggregation || at == Uml::at_Composition);
+ if (diamond || at == Uml::at_Containment) {
+ farPoint = getPoint(1);
+ m_EgdePoint = getPoint(0);
+ if (diamond) {
+ arrowAngle *= 1.5; // wider
+ halfLength += 1; // longer
+ } else {
+ // Containment has a circle-plus symbol at the
+ // containing object. What we are tweaking here
+ // is the perpendicular line through the circle
+ // (i.e. the horizontal line of the plus sign if
+ // the objects are oriented north/south)
+ arrowAngle *= 2.5; // wider
+ halfLength -= 4; // shorter
+ }
+ } else {
+ farPoint = getPoint(size - 1);
+ m_EgdePoint = getPoint(size);
+ // We have an arrow.
+ arrowAngle *= 2.0; // wider
+ halfLength += 3; // longer
+ }
+ int xa = farPoint.x();
+ int ya = farPoint.y();
+ int xb = m_EgdePoint.x();
+ int yb = m_EgdePoint.y();
+ double deltaX = xb - xa;
+ double deltaY = yb - ya;
+ double hypotenuse = sqrt(deltaX*deltaX + deltaY*deltaY); // the length
+ double slope = atan2(deltaY, deltaX); //slope of line
+ double arrowSlope = slope + arrowAngle;
+ double cosx, siny;
+ if (hypotenuse < 1.0e-6) {
+ cosx = 1.0;
+ siny = 0.0;
+ } else {
+ cosx = halfLength * deltaX/hypotenuse;
+ siny = halfLength * deltaY/hypotenuse;
+ }
+
+ m_ArrowPointA.setX( (int)rint(xb - halfLength * cos(arrowSlope)) );
+ m_ArrowPointA.setY( (int)rint(yb - halfLength * sin(arrowSlope)) );
+ arrowSlope = slope - arrowAngle;
+ m_ArrowPointB.setX( (int)rint(xb - halfLength * cos(arrowSlope)) );
+ m_ArrowPointB.setY( (int)rint(yb - halfLength * sin(arrowSlope)) );
+
+ if(xa > xb)
+ cosx = cosx > 0 ? cosx : cosx * -1;
+ else
+ cosx = cosx > 0 ? cosx * -1: cosx;
+
+ if(ya > yb)
+ siny = siny > 0 ? siny : siny * -1;
+ else
+ siny = siny > 0 ? siny * -1 : siny;
+
+ m_MidPoint.setX( (int)rint(xb + cosx) );
+ m_MidPoint.setY( (int)rint(yb + siny) );
+
+ m_PointArray.setPoint(0, m_EgdePoint);
+ m_PointArray.setPoint(1, m_ArrowPointA);
+ if( getAssocType() == Uml::at_Realization ||
+ getAssocType() == Uml::at_Generalization ) {
+ m_PointArray.setPoint( 2, m_ArrowPointB );
+ m_PointArray.setPoint( 3, m_EgdePoint );
+ } else {
+ QPoint diamondFarPoint;
+ diamondFarPoint.setX( (int)rint(xb + cosx * 2) );
+ diamondFarPoint.setY( (int)rint(yb + siny * 2) );
+ m_PointArray.setPoint(2, diamondFarPoint);
+ m_PointArray.setPoint(3, m_ArrowPointB);
+ }
+
+}
+
+void LinePath::updateHead() {
+ int count = m_HeadList.count();
+ QCanvasLine * line = 0;
+
+ switch( getAssocType() ) {
+ case Uml::at_State:
+ case Uml::at_Activity:
+ case Uml::at_UniAssociation:
+ case Uml::at_Dependency:
+ if( count < 2)
+ return;
+ line = m_HeadList.at( 0 );
+ line -> setPoints( m_EgdePoint.x(), m_EgdePoint.y(), m_ArrowPointA.x(), m_ArrowPointA.y() );
+
+ line = m_HeadList.at( 1 );
+ line -> setPoints( m_EgdePoint.x(), m_EgdePoint.y(), m_ArrowPointB.x(), m_ArrowPointB.y() );
+ break;
+
+ case Uml::at_Relationship:
+ if (count < 2) {
+ return;
+ }
+ {
+ int xoffset = 0;
+ int yoffset = 0;
+ if( m_DockRegion == TopBottom )
+ xoffset = 8;
+ else
+ yoffset = 8;
+ line = m_HeadList.at( 0 );
+ line->setPoints( m_PointArray[2].x(), m_PointArray[2].y(),
+ m_PointArray[0].x()-xoffset, m_PointArray[0].y()-yoffset );
+
+ line = m_HeadList.at( 1 );
+ line->setPoints( m_PointArray[2].x(), m_PointArray[2].y(),
+ m_PointArray[0].x()+xoffset, m_PointArray[0].y()+yoffset );
+ }
+
+ case Uml::at_Generalization:
+ case Uml::at_Realization:
+ if( count < 3)
+ return;
+ line = m_HeadList.at( 0 );
+ line -> setPoints( m_EgdePoint.x(), m_EgdePoint.y(), m_ArrowPointA.x(), m_ArrowPointA.y() );
+
+ line = m_HeadList.at( 1 );
+ line -> setPoints( m_EgdePoint.x(), m_EgdePoint.y(), m_ArrowPointB.x(), m_ArrowPointB.y() );
+
+ line = m_HeadList.at( 2 );
+ line -> setPoints( m_ArrowPointA.x(), m_ArrowPointA.y(), m_ArrowPointB.x(), m_ArrowPointB.y() );
+ m_pClearPoly -> setPoints( m_PointArray );
+ break;
+
+ case Uml::at_Composition:
+ case Uml::at_Aggregation:
+ if( count < 4)
+ return;
+ line = m_HeadList.at( 0 );
+ line -> setPoints( m_PointArray[ 0 ].x(), m_PointArray[ 0 ].y(), m_PointArray[ 1 ].x(), m_PointArray[ 1 ].y() );
+
+ line = m_HeadList.at( 1 );
+ line -> setPoints( m_PointArray[ 1 ].x(), m_PointArray[ 1 ].y(), m_PointArray[ 2 ].x(), m_PointArray[ 2 ].y() );
+
+ line = m_HeadList.at( 2 );
+ line -> setPoints( m_PointArray[ 2 ].x(), m_PointArray[ 2 ].y(), m_PointArray[ 3 ].x(), m_PointArray[ 3 ].y() );
+
+ line = m_HeadList.at( 3 );
+ line -> setPoints( m_PointArray[ 3 ].x(), m_PointArray[ 3 ].y(), m_PointArray[ 0 ].x(), m_PointArray[ 0 ].y() );
+ m_pClearPoly -> setPoints( m_PointArray );
+ break;
+
+ case Uml::at_Containment:
+ if (count < 1)
+ return;
+ line = m_HeadList.at( 0 );
+ line->setPoints( m_PointArray[ 1 ].x(), m_PointArray[ 1 ].y(),
+ m_PointArray[ 3 ].x(), m_PointArray[ 3 ].y() );
+ m_pCircle -> setX( m_MidPoint.x() );
+ m_pCircle -> setY( m_MidPoint.y() );
+ break;
+ default:
+ break;
+ }
+}
+
+void LinePath::growList(LineList &list, int by) {
+ QPen pen( getLineColor(), getLineWidth() );
+ for (int i = 0; i < by; i++) {
+ QCanvasLine * line = new QCanvasLine( getCanvas() );
+ line -> setZ( 0 );
+ line -> setPen( pen );
+ line -> setVisible( true );
+ list.append( line );
+ }
+}
+
+void LinePath::createHeadLines() {
+ m_HeadList.clear();
+ QCanvas * canvas = getCanvas();
+ switch( getAssocType() ) {
+ case Uml::at_Activity:
+ case Uml::at_State:
+ case Uml::at_Dependency:
+ case Uml::at_UniAssociation:
+ case Uml::at_Relationship:
+ growList(m_HeadList, 2);
+ break;
+
+ case Uml::at_Generalization:
+ case Uml::at_Realization:
+ growList(m_HeadList, 3);
+ m_pClearPoly = new QCanvasPolygon( canvas );
+ m_pClearPoly -> setVisible( true );
+ m_pClearPoly -> setBrush( QBrush( Qt::white ) );
+ m_pClearPoly -> setZ( -1 );
+ break;
+
+ case Uml::at_Composition:
+ case Uml::at_Aggregation:
+ growList(m_HeadList, 4);
+ m_pClearPoly = new QCanvasPolygon( canvas );
+ m_pClearPoly -> setVisible( true );
+ if( getAssocType() == Uml::at_Aggregation )
+ m_pClearPoly -> setBrush( QBrush( Qt::white ) );
+ else
+ m_pClearPoly -> setBrush( QBrush( getLineColor() ) );
+ m_pClearPoly -> setZ( -1 );
+ break;
+
+ case Uml::at_Containment:
+ growList(m_HeadList, 1);
+ if (!m_pCircle) {
+ m_pCircle = new Circle( canvas, 6 );
+ m_pCircle->show();
+ m_pCircle->setPen( QPen( getLineColor(), getLineWidth() ) );
+ }
+ break;
+ default:
+ break;
+ }
+ m_bHeadCreated = true;
+}
+
+void LinePath::calculateParallelLine() {
+ int midCount = count() / 2;
+ double ATAN = atan(1.0);
+ int lineDist = 10;
+ //get 1/8(M) and 7/8(T) point
+ QPoint a = getPoint( midCount - 1 );
+ QPoint b = getPoint( midCount );
+ int mx = ( a.x() + b.x() ) / 2;
+ int my = ( a.y() + b.y() ) / 2;
+ int tx = ( mx + b.x() ) / 2;
+ int ty = ( my + b.y() ) / 2;
+ //find dist between M and T points
+ int distX = ( mx - tx );
+ distX *= distX;
+ int distY = ( my - ty );
+ distY *= distY;
+ double dist = sqrt( double(distX + distY) );
+ double angle = atan2( double(ty - my), double(tx - mx) ) + ( ATAN * 2 );
+ //find point from M to start line from.
+ double cosx = cos( angle ) * lineDist;
+ double siny = sin( angle ) * lineDist;
+ QPoint pointM( mx + (int)cosx, my + (int)siny );
+ //find dist between P(xb, yb)
+ distX = ( tx - b.x() );
+ distX *= distX;
+ distY = ( ty - b.y() );
+ distY *= distY;
+ dist = sqrt( double(distX + distY) );
+ //find point from T to end line
+ cosx = cos( angle ) * lineDist;
+ siny = sin( angle ) * lineDist;
+ QPoint pointT( tx + (int)cosx, ty + (int)siny );
+ m_ParallelLines[ 1 ] = pointM;
+ m_ParallelLines[ 0 ] = pointT;
+
+ int arrowDist = 5;
+ angle = atan2( double(pointT.y() - pointM.y()),
+ double(pointT.x() - pointM.x()) );
+ double arrowSlope = angle + ATAN;
+ cosx = ( cos( arrowSlope ) ) * arrowDist;
+ siny = ( sin( arrowSlope ) ) * arrowDist;
+ m_ParallelLines[ 2 ] = QPoint( pointT.x() - (int)cosx, pointT.y() - (int)siny );
+ arrowSlope = angle - ATAN;
+ cosx = ( cos( arrowSlope ) ) * arrowDist;
+ siny = ( sin( arrowSlope ) ) * arrowDist;
+ m_ParallelLines[ 3 ] = QPoint( pointT.x() - (int)cosx, pointT.y() - (int)siny );
+}
+
+void LinePath::setupParallelLine() {
+ m_ParallelList.clear();
+ growList(m_ParallelList, 3);
+ m_bParallelLineCreated = true;
+}
+
+void LinePath::updateParallelLine() {
+ if( !m_bParallelLineCreated )
+ return;
+ QCanvasLine * line = 0;
+ QPoint common = m_ParallelLines.at( 0 );
+ QPoint p = m_ParallelLines.at( 1 );
+ line = m_ParallelList.at( 0 );
+ line -> setPoints( common.x(), common.y(), p.x(), p.y() );
+
+ p = m_ParallelLines.at( 2 );
+ line = m_ParallelList.at( 1 );
+ line -> setPoints( common.x(), common.y(), p.x(), p.y() );
+
+ p = m_ParallelLines.at( 3 );
+ line = m_ParallelList.at( 2 );
+ line -> setPoints( common.x(), common.y(), p.x(), p.y() );
+}
+
+bool LinePath::operator==( LinePath & rhs ) {
+ if( this -> m_LineList.count() != rhs.m_LineList.count() )
+ return false;
+
+ //Check to see if all points at the same position
+ for( int i = 0; i< rhs.count() ; i++ ) {
+ if( this -> getPoint( i ) != rhs.getPoint( i ) )
+ return false;
+ }
+ return true;
+}
+
+LinePath & LinePath::operator=( LinePath & rhs ) {
+ if( this == &rhs )
+ return *this;
+ //clear out the old canvas objects
+ this -> m_LineList.clear();
+ this -> m_ParallelList.clear();
+ this -> m_RectList.clear();
+ this -> m_HeadList.clear();
+ int count = rhs.m_LineList.count();
+ //setup start end points
+ this -> setStartEndPoints( rhs.getPoint( 0 ), rhs.getPoint( count) );
+ //now insert the rest
+ for( int i = 1; i < count ; i++ ) {
+ this -> insertPoint( i, rhs.getPoint ( i ) );
+ }
+ this -> setAssocType( rhs.getAssocType() );
+
+ return *this;
+}
+
+QCanvas * LinePath::getCanvas() {
+ if( !m_pAssociation )
+ return 0;
+ const UMLView * view = m_pAssociation->getUMLView();
+ return view -> canvas();
+}
+
+Uml::Association_Type LinePath::getAssocType() {
+ if( m_pAssociation )
+ return m_pAssociation -> getAssocType();
+ return Uml::at_Association;
+}
+
+QColor LinePath::getLineColor() {
+ if( !m_pAssociation )
+ return Qt::black;
+ return m_pAssociation -> getLineColor();
+}
+
+uint LinePath::getLineWidth() {
+ if( !m_pAssociation )
+ return 0;
+ int viewLineWidth = m_pAssociation -> getLineWidth();
+ if ( viewLineWidth >= 0 && viewLineWidth <= 10 )
+ return viewLineWidth;
+ else {
+ kWarning() << "Ignore wrong LineWidth of " << viewLineWidth
+ << " in LinePath::getLineWidth" << endl;
+ return 0;
+ }
+}
+
+void LinePath::cleanup() {
+ if (m_pAssociation)
+ m_LineList.clear();
+ m_HeadList.clear();
+ m_RectList.clear();
+ m_ParallelList.clear();
+
+ if( m_pClearPoly )
+ delete m_pClearPoly;
+ if( m_pCircle )
+ delete m_pCircle;
+ m_pCircle = 0;
+ m_pClearPoly = 0;
+ m_bHeadCreated = m_bParallelLineCreated = false;
+ if( m_pAssociation ) {
+ UMLView * view = (UMLView *)m_pAssociation -> parent();
+ if(view) {
+ disconnect( view, SIGNAL( sigColorChanged( Uml::IDType ) ), this, SLOT( slotLineColorChanged( Uml::IDType ) ) );
+ disconnect( view, SIGNAL( sigLineWidthChanged( Uml::IDType ) ), this, SLOT( slotLineWidthChanged( Uml::IDType ) ) );
+ }
+ m_pAssociation = NULL;
+ }
+}
+
+void LinePath::setDockRegion( Region region ) {
+ m_DockRegion = region;
+}
+
+bool LinePath::hasPoints () {
+ int count = m_LineList.count();
+ if (count>1)
+ return true;
+ return false;
+}
+void LinePath::dumpPoints () {
+ int count = m_LineList.count();
+ for( int i = 1; i < count; i++ ) {
+ QPoint point = getPoint( i );
+ kDebug()<<" * point x:"<<point.x()<<" y:"<<point.y()<<endl;
+ }
+}
+
+void LinePath::saveToXMI( QDomDocument & qDoc, QDomElement & qElement ) {
+ int count = m_LineList.count();
+ QPoint point = getPoint( 0 );
+ QDomElement lineElement = qDoc.createElement( "linepath" );
+ QDomElement startElement = qDoc.createElement( "startpoint" );
+ startElement.setAttribute( "startx", point.x() );
+ startElement.setAttribute( "starty", point.y() );
+ lineElement.appendChild( startElement );
+ QDomElement endElement = qDoc.createElement( "endpoint" );
+ point = getPoint( count );
+ endElement.setAttribute( "endx", point.x() );
+ endElement.setAttribute( "endy", point.y() );
+ lineElement.appendChild( endElement );
+ for( int i = 1; i < count; i++ ) {
+ QDomElement pointElement = qDoc.createElement( "point" );
+ point = getPoint( i );
+ pointElement.setAttribute( "x", point.x() );
+ pointElement.setAttribute( "y", point.y() );
+ lineElement.appendChild( pointElement );
+ }
+ qElement.appendChild( lineElement );
+}
+
+bool LinePath::loadFromXMI( QDomElement & qElement ) {
+ QDomNode node = qElement.firstChild();
+ QDomElement startElement = node.toElement();
+ if( startElement.isNull() || startElement.tagName() != "startpoint" )
+ return false;
+ QString x = startElement.attribute( "startx", "0" );
+ int nX = x.toInt();
+ QString y = startElement.attribute( "starty", "0" );
+ int nY = y.toInt();
+ QPoint startPoint( nX, nY );
+
+ node = startElement.nextSibling();
+ QDomElement endElement = node.toElement();
+ if( endElement.isNull() || endElement.tagName() != "endpoint" )
+ return false;
+ x = endElement.attribute( "endx", "0" );
+ nX = x.toInt();
+ y = endElement.attribute( "endy", "0" );
+ nY = y.toInt();
+ QPoint endPoint( nX, nY );
+ setStartEndPoints( startPoint, endPoint );
+ QPoint point;
+ node = endElement.nextSibling();
+ QDomElement element = node.toElement();
+ int i = 1;
+ while( !element.isNull() ) {
+ if( element.tagName() == "point" ) {
+ x = element.attribute( "x", "0" );
+ y = element.attribute( "y", "0" );
+ point.setX( x.toInt() );
+ point.setY( y.toInt() );
+ insertPoint( i++, point );
+ }
+ node = element.nextSibling();
+ element = node.toElement();
+ }
+
+ return true;
+}
+
+
+void LinePath::activate() {
+ int count = m_LineList.count();
+ if (count == 0)
+ return;
+ QCanvas * canvas = getCanvas();
+ if (canvas == NULL)
+ return;
+ for (int i = 0; i < count ; i++) {
+ QCanvasLine *line = m_LineList.at(i);
+ line -> setCanvas( canvas );
+ line -> setPen( getPen() );
+ }
+}
+
+
+
+#include "linepath.moc"
diff --git a/umbrello/umbrello/linepath.h b/umbrello/umbrello/linepath.h
new file mode 100644
index 00000000..434749e3
--- /dev/null
+++ b/umbrello/umbrello/linepath.h
@@ -0,0 +1,383 @@
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * copyright (C) 2002-2006 *
+ * Umbrello UML Modeller Authors <uml-devel@uml.sf.net> *
+ ***************************************************************************/
+
+#ifndef LINEPATH_H
+#define LINEPATH_H
+#include <qobject.h>
+#include <qptrlist.h>
+#include <qpoint.h>
+#include <qpointarray.h>
+#include <qcanvas.h>
+#include <qpainter.h>
+#include "umlnamespace.h"
+
+/* how many pixels a user could click around a point */
+#define POINT_DELTA 5
+
+class AssociationWidget;
+class UMLView;
+
+// Qt forward declarations
+class QDataStream;
+class QDomDocument;
+class QDomElement;
+
+// typedefs
+typedef QPtrList<QCanvasLine> LineList;
+typedef QPtrListIterator<QCanvasLine> LineListIt;
+
+typedef QPtrList<QCanvasRectangle> RectList;
+typedef QPtrListIterator<QCanvasRectangle> RectListIt;
+
+
+/**
+ *@author Paul Hensgen
+ * Bugs and comments to uml-devel@lists.sf.net or http://bugs.kde.org
+ */
+class LinePath : public QObject {
+ Q_OBJECT
+public:
+ /**
+ * Constructor
+ */
+ LinePath();
+
+ /**
+ * Deconstructor
+ */
+ ~LinePath();
+
+ /**
+ * equal to (==) operator
+ */
+ bool operator==( LinePath & rhs );
+
+ /**
+ * copy ( = ) operator
+ */
+ LinePath & operator=( LinePath & rhs );
+
+ /**
+ * Enum to tell whether the line docks top/bottom or left/right
+ */
+ enum Region {
+ TopBottom, LeftRight
+ };
+
+ /**
+ * Tell the line where the line docks
+ */
+ void setDockRegion( Region region );
+
+ bool hasPoints ();
+ void dumpPoints ();
+
+ /**
+ * Returns the point at the point index.
+ */
+ QPoint getPoint( int pointIndex );
+
+ /**
+ * Sets the position of an already set point.
+ */
+ bool setPoint( int pointIndex, const QPoint &point );
+
+ /**
+ * Checks, if we are at an end of the segment or somewhere in the middle.
+ * We use the delta, because with the mouse it is hard to find the
+ * exactly point.
+ */
+ bool isPoint( int pointIndex, const QPoint &point, unsigned short delta = 0 );
+
+ /**
+ * Inserts a point at the given index.
+ */
+ bool insertPoint( int pointIndex, const QPoint &point );
+
+ /**
+ * Removes the point on the line given by the index, at the coordinates
+ * given by point with a fuzzy of delta
+ */
+ bool removePoint( int pointIndex, const QPoint &point, unsigned short delta = 0 );
+
+ /**
+ * Sets the start and end points.
+ */
+ bool setStartEndPoints( const QPoint &start, const QPoint &end );
+
+ /**
+ * Returns the amount of POINTS on the line.
+ * Includes start and end points.
+ */
+ int count();
+
+ /**
+ * Returns -1 if the given point is not on the line.
+ * else returns the line segment the point is on.
+ * Use the value to insert points at the point position.
+ */
+ int onLinePath( const QPoint &position );
+
+ /**
+ * Sets the canvas to be used.
+ */
+ void setCanvas( QCanvas * canvas );
+
+ /**
+ * Sets the Association type.
+ */
+ void setAssocType( Uml::Association_Type type );
+
+ /**
+ * Calls a group of methods to update the line. Used to save you calling multiple methods.
+ */
+ void update();
+
+ /**
+ * This will setup the class ready to display the line correctly.
+ * This MUST be called before you can use this class.
+ */
+ void setAssociation( AssociationWidget * association );
+
+ /**
+ * Returns the Association this class is linked to.
+ */
+ AssociationWidget * getAssociation() {
+ return m_pAssociation;
+ }
+
+ /**
+ * Sets the status of whether the line is selected or not.
+ */
+ void setSelected( bool select );
+
+ void saveToXMI( QDomDocument & qDoc, QDomElement & qElement );
+
+ bool loadFromXMI( QDomElement & qElement );
+
+ /**
+ * Activates the line list.
+ * This is needed because the m_pAssociation does not yet
+ * exist at the time of the LinePath::loadFromXMI call.
+ * However, this means that the points in the m_LineList
+ * do not have a parent when they are loaded.
+ * They need to be reparented by calling LinePath::activate()
+ * once the m_pAssociation exists.
+ */
+ void activate();
+
+ /**
+ * Removes and item created that are no longer needed.
+ */
+ void cleanup();
+
+ /**
+ * Returns the type of pen to use depending on the type of Association.
+ */
+ QPen getPen();
+
+ /**
+ * Sets the line color used by the line.
+ */
+ void setLineColor( const QColor &color );
+ /**
+ * Sets the line width used by the line.
+ */
+ void setLineWidth( uint width );
+
+protected:
+
+ /**
+ * Draw a (hollow) circle.
+ * We can't use QCanvasEllipse directly for this because it doesn't
+ * use the pen, i.e. QCanvasEllipse only draws filled ellipses.
+ */
+ class Circle : public QCanvasEllipse {
+ public:
+ explicit Circle(QCanvas * canvas, int radius = 0);
+ void setRadius(int radius);
+ int getRadius() const;
+ void setX(int x);
+ void setY(int y);
+ /**
+ * The beef: Override method from QCanvasEllipse.
+ */
+ void drawShape(QPainter& p);
+ };
+
+ /**
+ * Returns the canvas being used.
+ * Will return zero if the Association hasn't been set.
+ *
+ * This class doesn't hold this information but is a wrapper
+ * method to stop calls to undefined variable like m_pAssociation.
+ */
+ QCanvas * getCanvas();
+
+ /**
+ * Returns the Association type.
+ * Returns Uml::at_Association if association hasn't been set.
+ *
+ * This class doesn't hold this information but is a wrapper
+ * method to stop calls to undefined variable like m_pAssociation.
+ */
+ Uml::Association_Type getAssocType();
+
+ /**
+ * Returns the Line Color to use.
+ * Returns black if association not set.
+ *
+ * This class doesn't hold this information but is a wrapper
+ * method to stop calls to undefined variable like m_pAssociation.
+ */
+ QColor getLineColor();
+ /**
+ * Returns the Line Width to use.
+ * Returns 0 if association not set.
+ *
+ * This class doesn't hold this information but is a wrapper
+ * method to stop calls to undefined variable like m_pAssociation.
+ */
+ uint getLineWidth();
+
+ /**
+ * Moves the selected canvas widgets.
+ */
+ void moveSelected( int pointIndex );
+
+ /**
+ * Sets up the selected canvases needed.
+ */
+ void setupSelected();
+
+ /**
+ * Calculates the head points.
+ */
+ void calculateHead();
+
+ /**
+ * Creates the head lines to display the head.
+ */
+ void createHeadLines();
+
+ /**
+ * Create a number of new lines and append them to the given list.
+ *
+ * @param list The list into which to append lines.
+ * @param by The number of lines to insert into the given list.
+ */
+ void growList(LineList &list, int by);
+
+ /**
+ * Updates the head lines. Call after calculating the new points.
+ */
+ void updateHead();
+
+ /**
+ * Creates the line objects to display the parallel line.
+ */
+ void setupParallelLine();
+
+ /**
+ * Calculates the position of the parallel line.
+ */
+ void calculateParallelLine();
+
+ /**
+ * Updates the parallel line.
+ * Call after calculating the new position.
+ */
+ void updateParallelLine();
+
+ /********Attributes*************/
+
+ /**
+ * The association we are representing.
+ */
+ AssociationWidget * m_pAssociation;
+
+ /**
+ * Contains all the lines of the association.
+ */
+ LineList m_LineList;
+
+ /**
+ * Selected boxes list.
+ */
+ RectList m_RectList;
+
+ /**
+ * Head lines.
+ */
+ LineList m_HeadList;
+
+ /**
+ * The parallel line.
+ */
+ LineList m_ParallelList;
+
+ /**
+ * Selected status.
+ */
+ bool m_bSelected;
+
+ /**
+ * Contains calculated points used to draw the line head.
+ */
+ QPointArray m_PointArray;
+
+ /**
+ * Contains calculated points used to draw the line head.
+ */
+ QPoint m_ArrowPointA, m_ArrowPointB, m_MidPoint, m_EgdePoint;
+
+ /**
+ * A polygon object to blank out any lines we don't want to see.
+ */
+ QCanvasPolygon * m_pClearPoly;
+
+ /**
+ * The transparent circle required by containment associations.
+ */
+ Circle * m_pCircle;
+
+ /**
+ * Contains the calculated points for the parallel line
+ * on a collaboration message to use.
+ */
+ QPointArray m_ParallelLines;
+
+ /**
+ * Region where the line docks
+ */
+ Region m_DockRegion;
+
+ bool m_bHeadCreated;
+
+ bool m_bParallelLineCreated;
+
+public slots:
+
+ /**
+ * Sets the line color used by the line.
+ *
+ * @param viewID The id of the object behind the widget.
+ */
+ void slotLineColorChanged( Uml::IDType viewID );
+ /**
+ * Sets the line width used by the line.
+ *
+ * @param viewID The id of the object behind the widget.
+ */
+ void slotLineWidthChanged( Uml::IDType viewID );
+};
+
+#endif
diff --git a/umbrello/umbrello/linkwidget.cpp b/umbrello/umbrello/linkwidget.cpp
new file mode 100644
index 00000000..b1b176de
--- /dev/null
+++ b/umbrello/umbrello/linkwidget.cpp
@@ -0,0 +1,61 @@
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * copyright (C) 2004-2006 *
+ * Umbrello UML Modeller Authors <uml-devel@uml.sf.net> *
+ ***************************************************************************/
+
+// own header
+#include "linkwidget.h"
+// qt/kde includes
+#include <kdebug.h>
+// app includes
+#include "umlview.h"
+#include "umlobject.h"
+#include "classifier.h"
+#include "operation.h"
+#include "uml.h"
+
+LinkWidget::LinkWidget() {
+}
+
+LinkWidget::~LinkWidget() {
+}
+
+UMLClassifier *LinkWidget::getOperationOwner() {
+ UMLOperation *op = getOperation();
+ if (op == NULL)
+ return NULL;
+ return static_cast<UMLClassifier*>(op->parent());
+}
+
+QString LinkWidget::getOperationText(UMLView *view /* = NULL */) {
+ UMLOperation *op = getOperation();
+ if (op == NULL)
+ return getCustomOpText();
+ if (view == NULL)
+ view = UMLApp::app()->getCurrentView();
+ Uml::Signature_Type sigType;
+ if (view && view->getShowOpSig())
+ sigType = Uml::st_SigNoVis;
+ else
+ sigType = Uml::st_NoSigNoVis;
+ QString opText = op->toString(sigType);
+ return opText;
+}
+
+void LinkWidget::resetTextPositions() {
+}
+
+bool LinkWidget::showDialog() {
+ return true;
+}
+
+void LinkWidget::calculateNameTextSegment() {
+}
+
+
diff --git a/umbrello/umbrello/linkwidget.h b/umbrello/umbrello/linkwidget.h
new file mode 100644
index 00000000..0e85d615
--- /dev/null
+++ b/umbrello/umbrello/linkwidget.h
@@ -0,0 +1,128 @@
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * copyright (C) 2004-2006 *
+ * Umbrello UML Modeller Authors <uml-devel@uml.sf.net> *
+ ***************************************************************************/
+
+#ifndef LINKWIDGET_H
+#define LINKWIDGET_H
+
+#include <qfont.h>
+
+#include "umlnamespace.h"
+
+// forward declarations
+class UMLClassifier;
+class UMLOperation;
+class FloatingTextWidget;
+class UMLView;
+
+/**
+ * This is an interface realized by AssociationWidget and MessageWidget.
+ * The design of this interface was driven by the requirements of
+ * class FloatingTextWidget. As the architecture of Umbrello evolves (for
+ * example, if the class FloatingTextWidget is redesigned), it can be
+ * cleaned up.
+ *
+ * @short Interface to FloatingTextWidget for AssociationWidget and MessageWidget.
+ * @author Oliver Kellogg <okellogg@users.sourceforge.net>
+ * Bugs and comments to uml-devel@lists.sf.net or http://bugs.kde.org
+ */
+class LinkWidget {
+public:
+ LinkWidget();
+ virtual ~LinkWidget();
+
+ /**
+ * Sets the font the widget is to use.
+ * Abstract operation implemented by inheriting classes.
+ * Motivated by FloatingTextWidget::slotMenuSelection(mt_Operation)
+ *
+ * @param font Font to be set.
+ */
+ virtual void lwSetFont(QFont font) = 0;
+
+ /**
+ * Motivated by FloatingTextWidget::slotMenuSelection(mt_Operation)
+ */
+ virtual UMLClassifier *getOperationOwner();
+
+ /**
+ * Motivated by FloatingTextWidget::slotMenuSelection(mt_Operation)
+ */
+ virtual UMLOperation *getOperation() = 0;
+
+ /**
+ * Motivated by FloatingTextWidget::slotMenuSelection(mt_Operation)
+ */
+ virtual void setOperation(UMLOperation *op) = 0;
+
+ /**
+ * Motivated by getOperationText()
+ */
+ virtual QString getCustomOpText() = 0;
+
+ /**
+ * Motivated by FloatingTextWidget::slotMenuSelection(mt_Operation)
+ */
+ virtual void setCustomOpText(const QString &opText) = 0;
+
+ /**
+ * Uses getOperation() if set, else calls getCustomOpText().
+ */
+ QString getOperationText(UMLView *view = NULL);
+
+ /**
+ * Motivated by FloatingTextWidget::slotMenuSelection(mt_Reset_Label_Positions)
+ * Only applies to AssociationWidget.
+ */
+ virtual void resetTextPositions();
+
+ /**
+ * Motivated by FloatingTextWidget::setMessageText()
+ */
+ virtual void setMessageText(FloatingTextWidget *ft) = 0;
+
+ /**
+ * Motivated by FloatingTextWidget::handleRename()
+ */
+ virtual void setText(FloatingTextWidget *ft, const QString &newText) = 0;
+
+ /**
+ * Motivated by FloatingTextWidget::mouseDoubleClickEvent()
+ * Only applies to AssociationWidget.
+ */
+ virtual bool showDialog();
+
+ /**
+ * Motivated by FloatingTextWidget::showOpDlg()
+ */
+ virtual UMLClassifier *getSeqNumAndOp(QString& seqNum, QString& op) = 0;
+
+ /**
+ * Motivated by FloatingTextWidget::showOpDlg()
+ */
+ virtual void setSeqNumAndOp(const QString &seqNum, const QString &op) = 0;
+
+ /**
+ * Abstract operation implemented by inheriting classes.
+ * Motivated by FloatingTextWidget::mouseMoveEvent()
+ */
+ virtual void constrainTextPos(int &textX, int &textY,
+ int textWidth, int textHeight,
+ Uml::Text_Role tr) = 0;
+
+ /**
+ * Motivated by FloatingTextWidget::setLink().
+ * Only applies to AssociationWidget.
+ */
+ virtual void calculateNameTextSegment();
+
+};
+
+#endif
diff --git a/umbrello/umbrello/listpopupmenu.cpp b/umbrello/umbrello/listpopupmenu.cpp
new file mode 100644
index 00000000..816d661b
--- /dev/null
+++ b/umbrello/umbrello/listpopupmenu.cpp
@@ -0,0 +1,1348 @@
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * copyright (C) 2002-2006 *
+ * Umbrello UML Modeller Authors <uml-devel@uml.sf.net> *
+ ***************************************************************************/
+
+// own header
+#include "listpopupmenu.h"
+
+// qt/kde includes
+#include <kstandarddirs.h>
+#include <kiconloader.h>
+#include <klocale.h>
+#include <kdebug.h>
+
+// app includes
+#include "umlwidget.h"
+#include "umldoc.h"
+#include "umllistview.h"
+#include "umllistviewitem.h"
+#include "classifierwidget.h"
+#include "classifier.h"
+#include "floatingtextwidget.h"
+#include "uml.h"
+#include "model_utils.h"
+#include "widget_utils.h"
+#include "folder.h"
+#include "umlview.h"
+#include "statewidget.h"
+#include "activitywidget.h"
+#include "forkjoinwidget.h"
+#include "objectwidget.h"
+
+//ListPopupMenu for a UMLView (diagram)
+ListPopupMenu::ListPopupMenu(QWidget *parent, Menu_Type type, UMLView * view)
+ : KPopupMenu(parent) {
+ init();
+ setupMenu(type, view);
+}
+
+//ListPopupMenu for the tree list view
+ListPopupMenu::ListPopupMenu(QWidget *parent, Uml::ListView_Type type)
+ : KPopupMenu(parent) {
+ init();
+ Menu_Type mt = mt_Undefined;
+ switch(type)
+ {
+ case Uml::lvt_Logical_View:
+ mt = mt_Logical_View;
+ break;
+
+ case Uml::lvt_UseCase_View:
+ mt = mt_UseCase_View;
+ break;
+
+ case Uml::lvt_Component_View:
+ mt = mt_Component_View;
+ break;
+
+ case Uml::lvt_EntityRelationship_Model:
+ mt = mt_EntityRelationship_Model;
+ break;
+
+ case Uml::lvt_Deployment_View:
+ mt = mt_Deployment_View;
+ break;
+
+ case Uml::lvt_Logical_Folder:
+ mt = mt_Logical_Folder;
+ break;
+
+ case Uml::lvt_UseCase_Folder:
+ mt = mt_UseCase_Folder;
+ break;
+
+ case Uml::lvt_Component_Folder:
+ mt = mt_Component_Folder;
+ break;
+
+ case Uml::lvt_Deployment_Folder:
+ mt = mt_Deployment_Folder;
+ break;
+
+ case Uml::lvt_EntityRelationship_Folder:
+ mt = mt_EntityRelationship_Folder;
+ break;
+
+ case Uml::lvt_UseCase_Diagram:
+ mt = mt_UseCase_Diagram;
+ break;
+
+ case Uml::lvt_Class_Diagram:
+ mt = mt_Class_Diagram;
+ break;
+
+ case Uml::lvt_Collaboration_Diagram:
+ mt = mt_Collaboration_Diagram;
+ break;
+
+ case Uml::lvt_Sequence_Diagram:
+ mt = mt_Sequence_Diagram;
+ break;
+
+ case Uml::lvt_State_Diagram:
+ mt = mt_State_Diagram;
+ break;
+
+ case Uml::lvt_Activity_Diagram:
+ mt = mt_Activity_Diagram;
+ break;
+
+ case Uml::lvt_Component_Diagram:
+ mt = mt_Component_Diagram;
+ break;
+
+ case Uml::lvt_Deployment_Diagram:
+ mt = mt_Deployment_Diagram;
+ break;
+
+ case Uml::lvt_EntityRelationship_Diagram:
+ mt = mt_EntityRelationship_Diagram;
+ break;
+
+ case Uml::lvt_Actor:
+ mt = mt_Actor;
+ break;
+
+ case Uml::lvt_UseCase:
+ mt = mt_UseCase;
+ break;
+
+ case Uml::lvt_Class:
+ mt = mt_Class;
+ break;
+
+ case Uml::lvt_Package:
+ mt = mt_Package;
+ break;
+
+ case Uml::lvt_Subsystem:
+ mt = mt_Subsystem;
+ break;
+
+ case Uml::lvt_Component:
+ mt = mt_Component;
+ break;
+
+ case Uml::lvt_Node:
+ mt = mt_Node;
+ break;
+
+ case Uml::lvt_Artifact:
+ mt = mt_Artifact;
+ break;
+
+ case Uml::lvt_Interface:
+ mt = mt_Interface;
+ break;
+
+ case Uml::lvt_Enum:
+ mt = mt_Enum;
+ break;
+
+ case Uml::lvt_EnumLiteral:
+ mt = mt_EnumLiteral;
+ break;
+
+ case Uml::lvt_Datatype:
+ mt = mt_Datatype;
+ break;
+
+ case Uml::lvt_Attribute:
+ mt = mt_Attribute;
+ break;
+
+ case Uml::lvt_Operation:
+ mt = mt_Operation;
+ break;
+
+ case Uml::lvt_Template:
+ mt = mt_Template;
+ break;
+
+ case Uml::lvt_Entity:
+ mt = mt_Entity;
+ break;
+
+ case Uml::lvt_EntityAttribute:
+ mt = mt_EntityAttribute;
+ break;
+
+ case Uml::lvt_Model:
+ mt = mt_Model;
+ break;
+
+ default: ;
+ //break;
+ }
+ setupMenu(mt);
+}
+
+//ListPopupMenu for a canvas widget
+ListPopupMenu::ListPopupMenu(QWidget * parent, UMLWidget * object,
+ bool multi, bool unique)
+ : KPopupMenu(parent)
+{
+ init();
+ //make the right menu for the type
+ //make menu for logical view
+ if(!object)
+ return;
+ Uml::Widget_Type type = object -> getBaseType();
+
+ if(multi) {
+ ClassifierWidget *c = NULL;
+ if (unique && (type == Uml::wt_Class || type == Uml::wt_Interface)) {
+ c = static_cast<ClassifierWidget *>( object );
+ makeMultiClassifierPopup(c);
+ }
+ setupColorSelection(object -> getUseFillColour());
+ insertSeparator();
+ insertStdItem(mt_Cut);
+ insertStdItem(mt_Copy);
+ insertStdItem(mt_Paste);
+ insertSeparator();
+ insertItem(SmallIcon( "fonts" ), i18n( "Change Font..." ),
+ mt_Change_Font_Selection );
+ insertItem(SmallIcon( "editdelete" ), i18n("Delete Selected Items"),
+ mt_Delete_Selection);
+
+ // add this here and not above with the other stuff of the interface
+ // user might expect it at this position of the context menu
+ if (unique) {
+ if (type == Uml::wt_Interface) {
+ insertItem(i18n("Draw as Circle"), mt_DrawAsCircle_Selection);
+ setItemChecked( mt_DrawAsCircle_Selection,
+ c->getDrawAsCircle() );
+ insertItem(i18n("Change into Class"), mt_ChangeToClass_Selection);
+ } else if (type == Uml::wt_Class) {
+ UMLClassifier *umlc = c->getClassifier();
+ if (umlc->getAbstract() && umlc->attributes() == 0)
+ insertItem(i18n("Change into Interface"), mt_ChangeToInterface_Selection);
+ }
+ }
+
+ if(m_pInsert)
+ connect(m_pInsert, SIGNAL(activated(int)), this, SIGNAL(activated(int)));
+ if(m_pShow)
+ connect(m_pShow, SIGNAL(activated(int)), this, SIGNAL(activated(int)));
+ if(m_pColor)
+ connect(m_pColor, SIGNAL(activated(int)), this, SIGNAL(activated(int)));
+ return;
+ }
+
+ StateWidget *pState;
+ ActivityWidget *pActivity;
+ UMLView * pView = static_cast<UMLView *>( parent );
+
+ switch(type) {
+ case Uml::wt_Actor:
+ case Uml::wt_UseCase:
+ setupColor(object -> getUseFillColour());
+ insertStdItems(true, type);
+ insertStdItem(mt_Rename);
+ insertStdItem(mt_Change_Font);
+ insertStdItem(mt_Properties);
+ break;
+
+ case Uml::wt_Class:
+ case Uml::wt_Interface:
+ makeClassifierPopup(static_cast<ClassifierWidget*>(object));
+ break;
+
+ case Uml::wt_Enum:
+ m_pInsert = new KPopupMenu(this);
+ m_pInsert->insertItem(SmallIcon("source"), i18n("Enum Literal..."), mt_EnumLiteral);
+ insertFileNew();
+ setupColor(object->getUseFillColour());
+ insertStdItems(true, type);
+ insertStdItem(mt_Rename);
+ insertStdItem(mt_Change_Font);
+ insertStdItem(mt_Properties);
+ break;
+
+ case Uml::wt_Entity:
+ m_pInsert = new KPopupMenu(this);
+ m_pInsert->insertItem(SmallIcon("source"), i18n("Entity Attribute..."), mt_EntityAttribute);
+ insertFileNew();
+ setupColor(object->getUseFillColour());
+ insertStdItems(true, type);
+ insertStdItem(mt_Rename);
+ insertStdItem(mt_Change_Font);
+ insertStdItem(mt_Properties);
+ break;
+
+ case Uml::wt_Datatype:
+ case Uml::wt_Package:
+ case Uml::wt_Component:
+ case Uml::wt_Node:
+ case Uml::wt_Artifact:
+ setupColor(object->getUseFillColour());
+ insertStdItems(false, type);
+ insertStdItem(mt_Rename);
+ insertStdItem(mt_Change_Font);
+ insertStdItem(mt_Properties);
+ break;
+
+ case Uml::wt_Object:
+ //Used for sequence diagram and collaboration diagram widgets
+ setupColor( object->getUseFillColour() );
+ if( pView->getType() == Uml::dt_Sequence ) {
+ insertSeparator();
+ int tabUp = insertItem( SmallIcon( "1uparrow"), i18n("Move Up"), mt_Up);
+ insertItem( SmallIcon( "1downarrow"), i18n("Move Down"), mt_Down);
+ if ( !(static_cast<ObjectWidget*>(object))->canTabUp() ) {
+ setItemEnabled(tabUp, false);
+ }
+ }
+ insertStdItems(true, type);
+ insertItem(i18n("Rename Class..."), mt_Rename);
+ insertItem(i18n("Rename Object..."), mt_Rename_Object);
+ insertStdItem(mt_Change_Font);
+ insertStdItem(mt_Properties);
+ break;
+
+ case Uml::wt_Message:
+ insertStdItems(false, type);
+ insertStdItem(mt_Change_Font);
+ insertItem(SmallIcon( "filenew"), i18n("New Operation..."), mt_Operation);
+ insertItem(i18n("Select Operation..."), mt_Select_Operation);
+ break;
+
+ case Uml::wt_Note:
+ setupColor(object -> getUseFillColour());
+ insertSeparator();
+ insertStdItem(mt_Cut);
+ insertStdItem(mt_Copy);
+ insertStdItem(mt_Paste);
+ insertItem(SmallIcon( "editdelete"), i18n("Clear"), mt_Clear);
+ insertSeparator();
+ insertItem(i18n("Change Text..."), mt_Rename);
+ insertStdItem(mt_Delete);
+ insertStdItem(mt_Change_Font);
+ break;
+
+ case Uml::wt_Box:
+ insertStdItems(false, type);
+ insertStdItem(mt_Line_Color);
+ break;
+
+ case Uml::wt_State:
+ pState = static_cast< StateWidget *>( object );
+ if( pState -> getStateType() == StateWidget::Normal ) {
+ m_pInsert = new KPopupMenu(this);
+ m_pInsert -> insertItem(SmallIcon( "filenew"), i18n("Activity..."), mt_New_Activity);
+ insertFileNew();
+ }
+ setupColor( object -> getUseFillColour() );
+ insertStdItems(false, type);
+ if( pState -> getStateType() == StateWidget::Normal ) {
+ insertItem(i18n("Change State Name..."), mt_Rename);
+ insertStdItem(mt_Change_Font);
+ insertStdItem(mt_Properties);
+ }
+ break;
+
+ case Uml::wt_ForkJoin:
+ {
+ ForkJoinWidget *pForkJoin = static_cast<ForkJoinWidget*>(object);
+ if (pForkJoin->getDrawVertical())
+ insertItem(i18n("Flip Horizontal"), mt_Flip);
+ else
+ insertItem(i18n("Flip Vertical"), mt_Flip);
+ }
+ break;
+
+ case Uml::wt_Activity:
+ pActivity = static_cast<ActivityWidget *>( object );
+ if( pActivity -> getActivityType() == ActivityWidget::Normal )
+ setupColor( object -> getUseFillColour() );
+ insertStdItems(false, type);
+ if( pActivity -> getActivityType() == ActivityWidget::Normal ) {
+ insertItem(i18n("Change Activity Name..."), mt_Rename);
+ insertStdItem(mt_Change_Font);
+ insertStdItem(mt_Properties);
+ }
+ break;
+
+ case Uml::wt_Text:
+ switch( (static_cast<FloatingTextWidget*>(object))->getRole() ) {
+ case Uml::tr_MultiB:
+ insertAssocItem(i18n("Change Multiplicity..."), mt_Rename_MultiB);
+ break;
+ case Uml::tr_MultiA:
+ insertAssocItem(i18n("Change Multiplicity..."), mt_Rename_MultiA);
+ break;
+ case Uml::tr_Name:
+ insertAssocItem(i18n("Change Name"), mt_Rename_Name);
+ break;
+ case Uml::tr_RoleAName:
+ insertAssocItem(i18n("Change Role A Name..."), mt_Rename_RoleAName);
+ break;
+ case Uml::tr_RoleBName:
+ insertAssocItem(i18n("Change Role B Name..."), mt_Rename_RoleBName);
+ break;
+ case Uml::tr_ChangeA:
+ case Uml::tr_ChangeB:
+ insertStdItem(mt_Change_Font);
+ insertStdItem(mt_Reset_Label_Positions);
+ insertStdItem(mt_Properties);
+ break;
+
+ case Uml::tr_Coll_Message_Self:
+ case Uml::tr_Coll_Message:
+ case Uml::tr_Seq_Message_Self:
+ case Uml::tr_Seq_Message:
+ insertStdItem(mt_Change_Font);
+ insertItem(SmallIcon( "filenew"), i18n("New Operation..."), mt_Operation);
+ insertItem(i18n("Select Operation..."), mt_Select_Operation);
+ break;
+
+ case Uml::tr_Floating:
+ default:
+ insertStdItems(false, type);
+ insertItem(i18n("Change Text..."), mt_Rename);
+ insertStdItem(mt_Change_Font);
+ break;
+ }
+ break;
+ default:
+ break;
+ }//end switch
+
+ if(m_pInsert)
+ connect(m_pInsert, SIGNAL(activated(int)), this, SIGNAL(activated(int)));
+ if(m_pShow)
+ connect(m_pShow, SIGNAL(activated(int)), this, SIGNAL(activated(int)));
+ if(m_pColor)
+ connect(m_pColor, SIGNAL(activated(int)), this, SIGNAL(activated(int)));
+
+ bool bCutState = UMLApp::app() -> getCutCopyState();
+ setItemEnabled( mt_Cut, bCutState );
+ setItemEnabled( mt_Copy, bCutState );
+ setItemEnabled( mt_Paste, false );
+}
+
+ListPopupMenu::~ListPopupMenu() {}
+
+void ListPopupMenu::init() {
+ m_pInsert = 0;
+ m_pShow = 0;
+ m_pColor = 0;
+}
+
+void ListPopupMenu::insertFileNew() {
+ insertItem(SmallIcon("filenew"), i18n("New"), m_pInsert);
+}
+
+void ListPopupMenu::insertStdItem(Menu_Type m)
+{
+ switch (m) {
+ case mt_Properties:
+ insertItem(SmallIcon("info"), i18n("Properties"), mt_Properties);
+ break;
+ case mt_Rename:
+ insertItem(i18n("Rename..."), mt_Rename);
+ break;
+ case mt_Delete:
+ insertItem(SmallIcon("editdelete"), i18n("Delete"), mt_Delete);
+ break;
+ case mt_Cut:
+ insertItem(SmallIcon("editcut"), i18n("Cut"), mt_Cut);
+ break;
+ case mt_Copy:
+ insertItem(SmallIcon("editcopy"), i18n("Copy"), mt_Copy);
+ break;
+ case mt_Paste:
+ insertItem(SmallIcon("editpaste"), i18n("Paste"), mt_Paste);
+ break;
+ case mt_Change_Font:
+ insertItem(SmallIcon("fonts"), i18n("Change Font..."), mt_Change_Font);
+ break;
+ case mt_Line_Color:
+ insertItem(SmallIcon("color_line"), i18n("Line Color..."), mt_Line_Color);
+ break;
+ case mt_Expand_All:
+ insertItem(i18n("Expand All"), mt_Expand_All);
+ break;
+ case mt_Collapse_All:
+ insertItem(i18n("Collapse All"), mt_Collapse_All);
+ break;
+ case mt_Clone:
+ insertItem(i18n("Duplicate"), mt_Clone);
+ break;
+ case mt_Externalize_Folder:
+ insertItem(i18n("Externalize Folder..."), mt_Externalize_Folder);
+ break;
+ case mt_Internalize_Folder:
+ insertItem(i18n("Internalize Folder"), mt_Internalize_Folder);
+ break;
+ case mt_Import_Classes:
+ insertItem(BarIcon("source_cpp"), i18n("Import Classes..."), mt_Import_Classes);
+ break;
+ case mt_Package:
+ m_pInsert->insertItem(m_pixmap[pm_Package], i18n("Package"), mt_Package);
+ case mt_Subsystem:
+ m_pInsert->insertItem(m_pixmap[pm_Subsystem], i18n("Subsystem"), mt_Subsystem);
+ break;
+ case mt_Component:
+ m_pInsert->insertItem(m_pixmap[pm_Component], i18n("Component"), mt_Component);
+ break;
+ case mt_Artifact:
+ m_pInsert->insertItem(m_pixmap[pm_Artifact], i18n("Artifact"), mt_Artifact);
+ break;
+ case mt_Component_Diagram:
+ m_pInsert->insertItem(BarIcon("umbrello_diagram_component"), i18n("Component Diagram..."),
+ mt_Component_Diagram);
+ break;
+ case mt_Node:
+ m_pInsert->insertItem(m_pixmap[pm_Node], i18n("Node"), mt_Node);
+ break;
+ case mt_Deployment_Diagram:
+ m_pInsert->insertItem(Widget_Utils::iconSet(Uml::dt_Deployment), i18n("Deployment Diagram..."),
+ mt_Deployment_Diagram);
+ break;
+ case mt_Deployment_Folder:
+ case mt_Component_Folder:
+ case mt_UseCase_Folder:
+ case mt_EntityRelationship_Folder:
+ m_pInsert->insertItem(BarIcon("folder_new"), i18n("Folder"), m);
+ break;
+ case mt_Entity:
+ m_pInsert->insertItem(m_pixmap[pm_Entity], i18n("Entity"), mt_Entity);
+ break;
+ case mt_EntityRelationship_Diagram:
+ m_pInsert->insertItem(Widget_Utils::iconSet(Uml::dt_EntityRelationship), i18n("Entity Relationship Diagram..."),
+ mt_EntityRelationship_Diagram);
+ break;
+ case mt_Actor:
+ m_pInsert->insertItem(m_pixmap[pm_Actor], i18n("Actor"), mt_Actor);
+ break;
+ case mt_UseCase:
+ m_pInsert->insertItem(m_pixmap[pm_Usecase], i18n("Use Case"), mt_UseCase);
+ break;
+ case mt_UseCase_Diagram:
+ m_pInsert->insertItem(Widget_Utils::iconSet(Uml::dt_UseCase), i18n("Use Case Diagram..."),
+ mt_UseCase_Diagram);
+ break;
+ case mt_FloatText:
+ m_pInsert->insertItem(m_pixmap[pm_Text], i18n("Text Line..." ), mt_FloatText);
+ break;
+ case mt_Reset_Label_Positions:
+ insertItem(i18n("Reset Label Positions"), mt_Reset_Label_Positions);
+ break;
+ case mt_New_Parameter:
+ insertItem(SmallIcon("source"), i18n("New Parameter..."), mt_New_Parameter);
+ break;
+ case mt_New_Operation:
+ insertItem(SmallIcon("CVpublic_meth"),i18n("New Operation..."), mt_New_Operation);
+ break;
+ case mt_New_Attribute:
+ insertItem(SmallIcon("CVpublic_var"), i18n("New Attribute..."), mt_New_Attribute);
+ break;
+ case mt_New_Template:
+ insertItem(SmallIcon("source"), i18n("New Template..."), mt_New_Template);
+ break;
+ case mt_New_EnumLiteral:
+ insertItem(SmallIcon("source"), i18n("New Literal..."), mt_New_EnumLiteral);
+ break;
+ case mt_New_EntityAttribute:
+ insertItem(SmallIcon("source"), i18n("New Entity Attribute..."), mt_New_EntityAttribute);
+ break;
+ case mt_New_Activity:
+ m_pInsert->insertItem(SmallIcon("source"), i18n("Activity..."), mt_New_Activity);
+ break;
+ case mt_Export_Image:
+ insertItem(SmallIcon("image"), i18n("Export as Picture..."), mt_Export_Image);
+ break;
+ default:
+ kWarning() << "ListPopupMenu::insertStdItem called on unimplemented Menu_Type " << m << endl;
+ break;
+ }
+}
+
+void ListPopupMenu::insertStdItems(bool insertLeadingSeparator /* = true */,
+ Uml::Widget_Type type /* = wt_UMLWidget */)
+{
+ if (insertLeadingSeparator)
+ insertSeparator();
+ insertStdItem(mt_Cut);
+ insertStdItem(mt_Copy);
+ insertStdItem(mt_Paste);
+ insertSeparator();
+ if (type == Uml::wt_UMLWidget)
+ insertStdItem(mt_Rename);
+ else if (Model_Utils::isCloneable(type))
+ insertStdItem(mt_Clone);
+ insertStdItem(mt_Delete);
+}
+
+void ListPopupMenu::insertContainerItems(bool folderAndDiagrams) {
+ if (folderAndDiagrams)
+ m_pInsert -> insertItem(BarIcon("folder_new"), i18n("Folder"), mt_Logical_Folder);
+ m_pInsert -> insertItem(m_pixmap[pm_Class], i18n("Class"), mt_Class);
+ m_pInsert -> insertItem(m_pixmap[pm_Interface], i18n("Interface"), mt_Interface);
+ m_pInsert -> insertItem(m_pixmap[pm_Datatype], i18n("Datatype"), mt_Datatype);
+ m_pInsert -> insertItem(m_pixmap[pm_Enum], i18n("Enum"), mt_Enum);
+ insertStdItem(mt_Package);
+ if (folderAndDiagrams) {
+ m_pInsert->insertItem(Widget_Utils::iconSet(Uml::dt_Class), i18n("Class Diagram..."), mt_Class_Diagram);
+ m_pInsert->insertItem(Widget_Utils::iconSet(Uml::dt_State), i18n("State Diagram..."), mt_State_Diagram);
+ m_pInsert->insertItem(Widget_Utils::iconSet(Uml::dt_Activity), i18n("Activity Diagram..."), mt_Activity_Diagram);
+ m_pInsert->insertItem(Widget_Utils::iconSet(Uml::dt_Sequence), i18n("Sequence Diagram..."), mt_Sequence_Diagram);
+ m_pInsert->insertItem(Widget_Utils::iconSet(Uml::dt_Collaboration), i18n("Collaboration Diagram..."), mt_Collaboration_Diagram);
+ }
+ insertFileNew();
+}
+
+void ListPopupMenu::insertAssocItem(const QString &label, Menu_Type mt) {
+ insertItem(label, mt);
+ insertStdItem(mt_Change_Font);
+ insertStdItem(mt_Reset_Label_Positions);
+ insertStdItem(mt_Properties);
+}
+
+void ListPopupMenu::insertSubmodelAction() {
+ const Settings::OptionState& ostat = Settings::getOptionState();
+ if (ostat.generalState.tabdiagrams) {
+ // Umbrello currently does not support External Folders
+ // in combination with Tabbed Diagrams.
+ // If you need external folders then disable the tabbed diagrams
+ // in the General Settings.
+ return;
+ }
+ UMLListView *listView = UMLApp::app()->getListView();
+ UMLListViewItem *current = static_cast<UMLListViewItem*>(listView->currentItem());
+ UMLObject *o = current->getUMLObject();
+ if (o == NULL) {
+ kError() << "ListPopupMenu::insertSubmodelAction: "
+ << current->getText() << " getUMLObject() returns NULL" << endl;
+ return;
+ }
+ UMLFolder *f = dynamic_cast<UMLFolder*>(o);
+ if (f == NULL) {
+ kError() << "ListPopupMenu::insertSubmodelAction: "
+ << "current->getUMLObject (" << o->getName() << ") is not a Folder" << endl;
+ return;
+ }
+ QString submodelFile = f->getFolderFile();
+ if (submodelFile.isEmpty())
+ insertStdItem(mt_Externalize_Folder);
+ else
+ insertStdItem(mt_Internalize_Folder);
+}
+
+void ListPopupMenu::makeMultiClassifierPopup(ClassifierWidget *c)
+{
+ Uml::Widget_Type type = c->getBaseType();
+ ClassifierWidget *cls = NULL;
+
+ m_pShow = new KPopupMenu(this);
+ m_pShow->setCheckable(true);
+ if (type == Uml::wt_Class) {
+ cls = static_cast<ClassifierWidget*>(c);
+ m_pShow->insertItem( i18n("Attributes"), mt_Show_Attributes_Selection);
+ m_pShow->setItemChecked(mt_Show_Attributes_Selection,
+ cls->getShowAtts());
+ }
+ m_pShow->insertItem(i18n("Operations"), mt_Show_Operations_Selection);
+ m_pShow->setItemChecked(mt_Show_Operations_Selection, c->getShowOps());
+ m_pShow->insertItem(i18n("Public Only"), mt_Show_Public_Only_Selection);
+ m_pShow->setItemChecked(mt_Show_Public_Only_Selection, c->getShowPublicOnly());
+ m_pShow->insertItem(i18n("Visibility"), mt_Visibility_Selection);
+ m_pShow->setItemChecked(mt_Visibility_Selection, c->getShowVisibility());
+ m_pShow->insertItem(i18n("Operation Signature"),
+ mt_Show_Operation_Signature_Selection);
+ bool sig = (c->getShowOpSigs() == Uml::st_SigNoVis ||
+ c->getShowOpSigs() == Uml::st_ShowSig);
+ m_pShow->setItemChecked(mt_Show_Operation_Signature_Selection, sig);
+ if (type == Uml::wt_Class) {
+ m_pShow->insertItem(i18n("Attribute Signature"),
+ mt_Show_Attribute_Signature_Selection);
+ sig = (cls->getShowAttSigs() == Uml::st_SigNoVis ||
+ cls->getShowAttSigs() == Uml::st_ShowSig);
+ m_pShow->setItemChecked(mt_Show_Attribute_Signature_Selection, sig);
+ }
+ m_pShow->insertItem(i18n("Package"), mt_Show_Packages_Selection);
+ m_pShow->setItemChecked(mt_Show_Packages_Selection, c->getShowPackage());
+ if (type == Uml::wt_Class) {
+ m_pShow->insertItem(i18n("Stereotype"), mt_Show_Stereotypes_Selection);
+ m_pShow->setItemChecked(mt_Show_Stereotypes_Selection,
+ cls->getShowStereotype());
+ }
+ insertItem(i18n("Show"), m_pShow);
+}
+
+void ListPopupMenu::makeClassifierPopup(ClassifierWidget *c)
+{
+ Uml::Widget_Type type = c->getBaseType();
+ m_pInsert = new KPopupMenu(this);
+ if (type == Uml::wt_Class)
+ m_pInsert->insertItem(SmallIcon( "CVpublic_var" ), i18n("Attribute..."), mt_Attribute);
+ m_pInsert->insertItem( SmallIcon( "CVpublic_meth"), i18n("Operation..."), mt_Operation);
+ insertFileNew();
+
+ makeMultiClassifierPopup(c);
+
+ setupColor(c->getUseFillColour());
+ insertStdItems(true, type);
+ insertStdItem(mt_Rename);
+ insertStdItem(mt_Change_Font);
+ if (type == Uml::wt_Interface) {
+ insertItem(i18n("Draw as Circle"), mt_DrawAsCircle);
+ setItemChecked( mt_DrawAsCircle, c->getDrawAsCircle() );
+ insertItem(i18n("Change into Class"), mt_ChangeToClass);
+ } else {
+ insertItem(i18n("Refactor"), mt_Refactoring);
+ insertItem(i18n("View Code"), mt_ViewCode);
+ UMLClassifier *umlc = c->getClassifier();
+ if (umlc->getAbstract() && umlc->attributes() == 0)
+ insertItem(i18n("Change into Interface"), mt_ChangeToInterface);
+ }
+ insertStdItem(mt_Properties);
+}
+
+void ListPopupMenu::setupColor(bool fc)
+{
+ m_pColor = new KPopupMenu(this);
+ m_pColor -> insertItem(SmallIcon( "color_line"), i18n("Line Color..."), mt_Line_Color);
+ m_pColor -> insertItem(SmallIcon( "color_fill"), i18n("Fill Color..."), mt_Fill_Color);
+ m_pColor -> insertItem( i18n("Use Fill Color"), mt_Use_Fill_Color);
+
+ m_pColor -> setItemChecked(mt_Use_Fill_Color, fc);
+ insertItem(SmallIcon( "colorize"), i18n("Color"), m_pColor);
+}
+
+void ListPopupMenu::setupColorSelection(bool fc)
+{
+ m_pColor = new KPopupMenu(this);
+ m_pColor -> insertItem(SmallIcon( "color_line"), i18n("Line Color..."), mt_Line_Color_Selection);
+ m_pColor -> insertItem(SmallIcon( "color_fill"), i18n("Fill Color..."), mt_Fill_Color_Selection);
+ m_pColor -> insertItem( i18n("Use Fill Color"), mt_Use_Fill_Color);
+
+ m_pColor -> setItemChecked(mt_Use_Fill_Color, fc);
+ insertItem(SmallIcon( "colorize"), i18n("Color"), m_pColor);
+}
+
+Uml::Diagram_Type ListPopupMenu::convert_MT_DT(Menu_Type mt) {
+ Uml::Diagram_Type type = Uml::dt_Undefined;
+
+ switch(mt) {
+ case mt_UseCase_Diagram:
+ type = Uml::dt_UseCase;
+ break;
+ case mt_Class_Diagram:
+ type = Uml::dt_Class;
+ break;
+ case mt_Sequence_Diagram:
+ type = Uml::dt_Sequence;
+ break;
+ case mt_Collaboration_Diagram:
+ type = Uml::dt_Collaboration;
+ break;
+ case mt_State_Diagram:
+ type = Uml::dt_State;
+ break;
+ case mt_Activity_Diagram:
+ type = Uml::dt_Activity;
+ break;
+ case mt_Component_Diagram:
+ type = Uml::dt_Component;
+ break;
+ case mt_Deployment_Diagram:
+ type = Uml::dt_Deployment;
+ break;
+ case mt_EntityRelationship_Diagram:
+ type = Uml::dt_EntityRelationship;
+ break;
+ default:
+ break;
+ }
+ return type;
+}
+
+Uml::Object_Type ListPopupMenu::convert_MT_OT(Menu_Type mt) {
+ Uml::Object_Type type = Uml::ot_UMLObject;
+
+ switch(mt) {
+ case mt_UseCase:
+ type = Uml::ot_UseCase;
+ break;
+ case mt_Actor:
+ type = Uml::ot_Actor;
+ break;
+ case mt_Class:
+ type = Uml::ot_Class;
+ break;
+ case mt_Attribute:
+ type = Uml::ot_Attribute;
+ break;
+ case mt_EnumLiteral:
+ type = Uml::ot_EnumLiteral;
+ break;
+ case mt_EntityAttribute:
+ type = Uml::ot_EntityAttribute;
+ break;
+ case mt_Operation:
+ type = Uml::ot_Operation;
+ break;
+ default:
+ break;
+ }
+ return type;
+}
+
+void ListPopupMenu::setupMenu(Menu_Type type, UMLView* view) {
+ //make the right menu for the type
+ //make menu for logical view
+ m_pInsert = 0;
+
+ m_pShow = 0;
+ m_pColor = 0;
+
+ KStandardDirs* dirs = KGlobal::dirs();
+ QString dataDir = dirs->findResourceDir("data", "umbrello/pics/object.png");
+ dataDir += "/umbrello/pics/";
+ m_pixmap[pm_Class] .load(dataDir+"class.png", "PNG");
+ m_pixmap[pm_Package] .load(dataDir+"package.png", "PNG");
+ m_pixmap[pm_Interface] .load(dataDir+"interface.png", "PNG");
+ m_pixmap[pm_Datatype] .load(dataDir+"datatype.png", "PNG");
+ m_pixmap[pm_Enum] .load(dataDir+"enum.png", "PNG");
+ m_pixmap[pm_Actor] .load(dataDir+"actor.png", "PNG");
+ m_pixmap[pm_Usecase] .load(dataDir+"usecase.png", "PNG");
+ m_pixmap[pm_InitialState].load(dataDir+"initial_state.png", "PNG");
+ m_pixmap[pm_EndState] .load(dataDir+"end_state.png", "PNG");
+ m_pixmap[pm_Branch] .load(dataDir+"branch.png", "PNG");
+ m_pixmap[pm_Object] .load(dataDir+"object.png", "PNG");
+ m_pixmap[pm_Component] .load(dataDir+"component.png", "PNG");
+ m_pixmap[pm_Node] .load(dataDir+"node.png", "PNG");
+ m_pixmap[pm_Entity] .load(dataDir+"entity.png", "PNG");
+ m_pixmap[pm_Artifact] .load(dataDir+"artifact.png", "PNG");
+ m_pixmap[pm_Text] .load(dataDir+"text.png", "PNG");
+ m_pixmap[pm_Subsystem] .load(dataDir+"subsystem.png", "PNG");
+
+ switch(type) {
+ case mt_Logical_View:
+ m_pInsert = new KPopupMenu(this);
+ insertContainerItems(true);
+ insertSeparator();
+ insertStdItem(mt_Paste);
+ insertSeparator();
+ insertStdItem(mt_Import_Classes);
+ insertSeparator();
+ insertStdItem(mt_Expand_All);
+ insertStdItem(mt_Collapse_All);
+ break;
+
+ case mt_Component_View:
+ m_pInsert = new KPopupMenu(this);
+ insertStdItem(mt_Component_Folder);
+ insertStdItem(mt_Subsystem);
+ insertStdItem(mt_Component);
+ insertStdItem(mt_Artifact);
+ insertStdItem(mt_Component_Diagram);
+ insertFileNew();
+ insertSeparator();
+ insertStdItem(mt_Paste);
+ insertSeparator();
+ insertStdItem(mt_Expand_All);
+ insertStdItem(mt_Collapse_All);
+ break;
+
+ case mt_Deployment_View:
+ m_pInsert = new KPopupMenu(this);
+ insertStdItem(mt_Deployment_Folder);
+ insertStdItem(mt_Node);
+ insertStdItem(mt_Deployment_Diagram);
+ insertFileNew();
+ insertSeparator();
+ insertStdItem(mt_Paste);
+ insertSeparator();
+ insertStdItem(mt_Expand_All);
+ insertStdItem(mt_Collapse_All);
+ break;
+
+ case mt_EntityRelationship_Model:
+ m_pInsert = new KPopupMenu(this);
+ insertStdItem(mt_EntityRelationship_Folder);
+ insertStdItem(mt_Entity);
+ insertStdItem(mt_EntityRelationship_Diagram);
+ insertFileNew();
+ insertSeparator();
+ insertStdItem(mt_Paste);
+ insertSeparator();
+ insertStdItem(mt_Expand_All);
+ insertStdItem(mt_Collapse_All);
+ break;
+
+ case mt_UseCase_View:
+ m_pInsert = new KPopupMenu(this);
+ insertStdItem(mt_UseCase_Folder);
+ insertStdItem(mt_Actor);
+ insertStdItem(mt_UseCase);
+ insertStdItem(mt_UseCase_Diagram);
+ insertFileNew();
+ insertSeparator();
+ // insertStdItem(mt_Cut);
+ // insertStdItem(mt_Copy);
+ insertStdItem(mt_Paste);
+ insertSeparator();
+ insertStdItem(mt_Expand_All);
+ insertStdItem(mt_Collapse_All);
+ break;
+
+ case mt_Logical_Folder:
+ m_pInsert = new KPopupMenu(this);
+ insertContainerItems(true);
+ insertStdItems();
+ insertStdItem(mt_Import_Classes);
+ insertSubmodelAction();
+ insertSeparator();
+ insertStdItem(mt_Expand_All);
+ insertStdItem(mt_Collapse_All);
+ break;
+
+ case mt_Component_Folder:
+ m_pInsert = new KPopupMenu(this);
+ insertStdItem(mt_Component_Folder);
+ insertStdItem(mt_Subsystem);
+ insertStdItem(mt_Component);
+ insertStdItem(mt_Artifact);
+ insertStdItem(mt_Component_Diagram);
+ insertFileNew();
+ insertStdItems();
+ insertSubmodelAction();
+ insertSeparator();
+ insertStdItem(mt_Expand_All);
+ insertStdItem(mt_Collapse_All);
+ break;
+
+ case mt_Deployment_Folder:
+ m_pInsert = new KPopupMenu(this);
+ insertStdItem(mt_Deployment_Folder);
+ insertStdItem(mt_Node);
+ insertStdItem(mt_Deployment_Diagram);
+ insertFileNew();
+ insertStdItems();
+ insertSubmodelAction();
+ insertSeparator();
+ insertStdItem(mt_Expand_All);
+ insertStdItem(mt_Collapse_All);
+ break;
+
+ case mt_UseCase_Folder:
+ m_pInsert = new KPopupMenu(this);
+ insertStdItem(mt_UseCase_Folder);
+ insertStdItem(mt_Actor);
+ insertStdItem(mt_UseCase);
+ insertStdItem(mt_UseCase_Diagram);
+ insertFileNew();
+ insertStdItems();
+ insertSubmodelAction();
+ insertSeparator();
+ insertStdItem(mt_Expand_All);
+ insertStdItem(mt_Collapse_All);
+ break;
+
+ case mt_EntityRelationship_Folder:
+ m_pInsert = new KPopupMenu(this);
+ insertStdItem(mt_EntityRelationship_Folder);
+ insertStdItem(mt_Entity);
+ insertStdItem(mt_EntityRelationship_Diagram);
+ insertFileNew();
+ insertStdItems();
+ insertSubmodelAction();
+ insertSeparator();
+ insertStdItem(mt_Expand_All);
+ insertStdItem(mt_Collapse_All);
+ break;
+
+ case mt_UseCase_Diagram:
+ case mt_Sequence_Diagram:
+ case mt_Class_Diagram:
+ case mt_Collaboration_Diagram:
+ case mt_State_Diagram:
+ case mt_Activity_Diagram:
+ case mt_Component_Diagram:
+ case mt_Deployment_Diagram:
+ case mt_EntityRelationship_Diagram:
+ //don't insert standard items because cut/copy not currently
+ // possible with tabbed diagrams (it didn't work anyway)
+ //insertStdItems(false);
+ insertStdItem(mt_Rename);
+ insertStdItem(mt_Delete);
+ insertStdItem(mt_Export_Image);
+ insertStdItem(mt_Properties);
+ break;
+
+ //FIXME a lot of these insertItem()s could be insertStandardItem()s
+ case mt_On_UseCase_Diagram:
+ m_pInsert = new KPopupMenu( this );
+ m_pInsert -> insertItem(m_pixmap[pm_Actor], i18n( "Actor..." ), mt_Actor );
+ m_pInsert -> insertItem(m_pixmap[pm_Usecase], i18n( "Use Case..."), mt_UseCase );
+ insertStdItem(mt_FloatText );
+ insertFileNew();
+ insertSeparator();
+ setupDiagramMenu(view);
+ break;
+
+ case mt_On_Class_Diagram:
+ m_pInsert = new KPopupMenu( this );
+ m_pInsert -> insertItem(m_pixmap[pm_Class], i18n("Class..."), mt_Class);
+ m_pInsert->insertItem(m_pixmap[pm_Interface], i18n("Interface..."), mt_Interface);
+ m_pInsert->insertItem(m_pixmap[pm_Datatype], i18n("Datatype..."), mt_Datatype);
+ m_pInsert->insertItem(m_pixmap[pm_Enum], i18n("Enum..."), mt_Enum);
+ m_pInsert -> insertItem(m_pixmap[pm_Package], i18n("Package..."), mt_Package);
+ insertStdItem(mt_FloatText);
+ insertFileNew();
+ insertSeparator();
+ setupDiagramMenu(view);
+ break;
+
+ case mt_On_State_Diagram:
+ m_pInsert = new KPopupMenu( this );
+ m_pInsert -> insertItem(m_pixmap[pm_InitialState], i18n("Initial State"), mt_Initial_State );
+ m_pInsert -> insertItem(m_pixmap[pm_EndState], i18n("End State"), mt_End_State );
+ m_pInsert -> insertItem(m_pixmap[pm_Usecase], i18n("State..."), mt_State );
+ insertStdItem(mt_FloatText);
+ insertFileNew();
+ insertSeparator();
+ setupDiagramMenu(view);
+ break;
+
+ case mt_On_Activity_Diagram:
+ m_pInsert = new KPopupMenu( this );
+ m_pInsert -> insertItem(m_pixmap[pm_InitialState], i18n("Initial Activity"), mt_Initial_Activity );
+ m_pInsert -> insertItem(m_pixmap[pm_EndState], i18n("End Activity"), mt_End_Activity );
+ m_pInsert -> insertItem(m_pixmap[pm_Usecase], i18n("Activity..."), mt_Activity );
+ m_pInsert -> insertItem(m_pixmap[pm_Branch], i18n("Branch/Merge"), mt_Branch );
+ insertStdItem(mt_FloatText);
+ insertFileNew();
+ insertSeparator();
+ setupDiagramMenu(view);
+ break;
+
+ case mt_On_Component_Diagram:
+ m_pInsert = new KPopupMenu(this);
+ m_pInsert->insertItem(m_pixmap[pm_Subsystem], i18n("Subsystem..."), mt_Subsystem);
+ m_pInsert->insertItem(m_pixmap[pm_Component], i18n("Component..."), mt_Component);
+ m_pInsert->insertItem(m_pixmap[pm_Artifact], i18n("Artifact..."), mt_Artifact);
+ insertFileNew();
+ insertSeparator();
+ setupDiagramMenu(view);
+ break;
+
+ case mt_On_Deployment_Diagram:
+ m_pInsert = new KPopupMenu(this);
+ m_pInsert->insertItem(m_pixmap[pm_Node], i18n("Node..."), mt_Node);
+ insertFileNew();
+ insertSeparator();
+ setupDiagramMenu(view);
+ break;
+
+ case mt_On_EntityRelationship_Diagram:
+ m_pInsert = new KPopupMenu(this);
+ m_pInsert->insertItem(m_pixmap[pm_Entity], i18n("Entity..."), mt_Entity);
+ insertFileNew();
+ insertSeparator();
+ setupDiagramMenu(view);
+ break;
+
+ case mt_On_Sequence_Diagram:
+ case mt_On_Collaboration_Diagram:
+ m_pInsert = new KPopupMenu( this );
+ m_pInsert -> insertItem(m_pixmap[pm_Object], i18n("Object..."), mt_Object);
+ insertStdItem(mt_FloatText);
+ insertFileNew();
+ insertSeparator();
+ setupDiagramMenu(view);
+ break;
+
+ case mt_Class:
+ m_pInsert = new KPopupMenu(this);
+ m_pInsert -> insertItem(SmallIcon( "CVpublic_var"), i18n("Attribute"), mt_Attribute);
+ m_pInsert -> insertItem(SmallIcon( "CVpublic_meth"), i18n("Operation"), mt_Operation);
+ m_pInsert -> insertItem(SmallIcon("source"), i18n("Template"), mt_Template);
+ insertFileNew();
+ insertStdItems();
+ insertStdItem(mt_Properties);
+ break;
+
+ case mt_Interface:
+ m_pInsert = new KPopupMenu(this);
+ m_pInsert->insertItem(SmallIcon("CVpublic_meth"), i18n("Operation"), mt_Operation);
+ m_pInsert -> insertItem(SmallIcon("source"), i18n("Template"), mt_Template);
+ insertFileNew();
+ insertStdItems();
+ insertStdItem(mt_Properties);
+ break;
+
+ case mt_Package:
+ m_pInsert = new KPopupMenu(this);
+ insertContainerItems(false);
+ insertStdItems();
+ insertStdItem(mt_Properties);
+ insertSeparator();
+ insertStdItem(mt_Expand_All);
+ insertStdItem(mt_Collapse_All);
+ break;
+
+ case mt_Subsystem:
+ m_pInsert = new KPopupMenu(this);
+ insertStdItem(mt_Subsystem);
+ insertStdItem(mt_Component);
+ insertStdItem(mt_Artifact);
+ insertFileNew();
+ insertStdItems();
+ insertStdItem(mt_Properties);
+ insertSeparator();
+ insertStdItem(mt_Expand_All);
+ insertStdItem(mt_Collapse_All);
+ break;
+
+ case mt_Component:
+ m_pInsert = new KPopupMenu(this);
+ insertStdItem(mt_Component);
+ insertStdItem(mt_Artifact);
+ insertFileNew();
+ insertStdItems();
+ insertStdItem(mt_Properties);
+ insertSeparator();
+ insertStdItem(mt_Expand_All);
+ insertStdItem(mt_Collapse_All);
+ break;
+
+ case mt_Entity:
+ m_pInsert = new KPopupMenu(this);
+ m_pInsert->insertItem(SmallIcon("source"), i18n("Entity Attribute..."), mt_EntityAttribute);
+ insertFileNew();
+ insertStdItems();
+ insertStdItem(mt_Properties);
+ break;
+
+ case mt_EnumLiteral:
+ insertStdItems(false);
+ break;
+
+ case mt_Enum:
+ m_pInsert = new KPopupMenu(this);
+ m_pInsert->insertItem(SmallIcon("source"), i18n("Enum Literal..."), mt_EnumLiteral);
+ insertFileNew();
+ insertStdItems();
+ insertStdItem(mt_Properties);
+ break;
+
+ case mt_Datatype:
+ case mt_Node:
+ case mt_Artifact:
+ case mt_Actor:
+ case mt_UseCase:
+ case mt_Attribute:
+ case mt_EntityAttribute:
+ case mt_Operation:
+ case mt_Template:
+ insertStdItems(false);
+ insertStdItem(mt_Properties);
+ break;
+
+ case mt_New_Parameter:
+ insertStdItem(mt_New_Parameter);
+ break;
+
+ case mt_New_Operation:
+ insertStdItem(mt_New_Operation);
+ break;
+
+ case mt_New_Attribute:
+ insertStdItem(mt_New_Attribute);
+ break;
+
+ case mt_New_Template:
+ insertStdItem(mt_New_Template);
+ break;
+
+ case mt_New_EnumLiteral:
+ insertStdItem(mt_New_EnumLiteral);
+ break;
+
+ case mt_New_EntityAttribute:
+ insertStdItem(mt_New_EntityAttribute);
+ break;
+
+ case mt_New_Activity:
+ m_pInsert = new KPopupMenu(this);
+ insertStdItem(mt_New_Activity);
+ insertFileNew();
+ break;
+
+ case mt_Activity_Selected:
+ m_pInsert = new KPopupMenu(this);
+ insertStdItem(mt_New_Activity);
+ insertFileNew();
+ insertStdItem(mt_Rename);
+ insertStdItem(mt_Delete);
+ break;
+
+ case mt_Parameter_Selected:
+ insertStdItem(mt_New_Parameter);
+ insertStdItem(mt_Rename);
+ insertStdItem(mt_Delete);
+ insertStdItem(mt_Properties);
+ break;
+
+ case mt_Operation_Selected:
+ insertStdItem(mt_New_Operation);
+ insertStdItem(mt_Delete);
+ insertStdItem(mt_Properties);
+ break;
+
+ case mt_Attribute_Selected:
+ insertStdItem(mt_New_Attribute);
+ insertStdItem(mt_Delete);
+ insertStdItem(mt_Properties);
+ break;
+
+ case mt_Template_Selected:
+ insertItem(SmallIcon("source"),i18n("New Template..."), mt_New_Attribute);
+ insertStdItem(mt_Delete);
+ insertStdItem(mt_Properties);
+ break;
+
+ case mt_EnumLiteral_Selected:
+ insertStdItem(mt_New_EnumLiteral);
+ insertStdItem(mt_Delete);
+ insertStdItem(mt_Properties);
+ break;
+
+ case mt_EntityAttribute_Selected:
+ insertStdItem(mt_New_EntityAttribute);
+ insertStdItem(mt_Delete);
+ insertStdItem(mt_Properties);
+ break;
+
+ case mt_Association_Selected:
+ insertStdItem(mt_Delete);
+ insertStdItem(mt_Line_Color);
+ insertStdItem(mt_Properties);
+ break;
+
+ case mt_Anchor:
+ insertItem(SmallIcon( "editdelete"),i18n("Delete Anchor"), mt_Delete);
+ break;
+
+ case mt_RoleNameA:
+ insertAssocItem(i18n("Change Role A Name..."), mt_Rename_RoleAName);
+ break;
+
+ case mt_RoleNameB:
+ insertAssocItem(i18n("Change Role B Name..."), mt_Rename_RoleBName);
+ break;
+
+ case mt_MultiB:
+ insertAssocItem(i18n("Change Multiplicity..."), mt_Rename_MultiB);
+ break;
+
+ case mt_MultiA:
+ insertAssocItem(i18n("Change Multiplicity..."), mt_Rename_MultiA);
+ break;
+
+ case mt_Name:
+ insertAssocItem(i18n("Change Name"), mt_Rename_Name);
+ break;
+
+ case mt_FullAssociation:
+ insertStdItem(mt_Delete);
+ insertItem(i18n("Change Association Name..."), mt_Rename_Name);
+ insertItem(i18n("Change Role A Name..."), mt_Rename_RoleAName);
+ insertItem(i18n("Change Role B Name..."), mt_Rename_RoleBName);
+ insertStdItem(mt_Change_Font);
+ insertStdItem(mt_Reset_Label_Positions);
+ insertStdItem(mt_Line_Color);
+ insertStdItem(mt_Properties);
+ break;
+
+ case mt_AttributeAssociation:
+ insertStdItem(mt_Delete); // @todo add more items
+ break;
+
+ case mt_Collaboration_Message:
+ // insertStdItem(mt_Cut);
+ // insertStdItem(mt_Copy);
+ // insertStdItem(mt_Paste);
+ // insertSeparator();
+ insertStdItem(mt_Delete);
+ insertStdItem(mt_Change_Font);
+ insertStdItem(mt_New_Operation);
+ insertItem(i18n("Select Operation..."), mt_Select_Operation);
+ break;
+
+ case mt_Model:
+ insertItem(i18n("Rename..."), mt_Model);
+ break;
+
+ default:
+ insertStdItem(mt_Expand_All);
+ insertStdItem(mt_Collapse_All);
+ break;
+ }//end switch
+
+ if( view ) {
+ bool bCutState = UMLApp::app() -> getCutCopyState();
+ setItemEnabled( mt_Undo, UMLApp::app()->getUndoEnabled() );
+ setItemEnabled( mt_Redo, UMLApp::app()->getRedoEnabled() );
+ setItemEnabled( mt_Cut, bCutState );
+ setItemEnabled( mt_Copy, bCutState );
+ setItemEnabled( mt_Paste, UMLApp::app() -> getPasteState() );
+ }
+ if(m_pInsert)
+ connect(m_pInsert, SIGNAL(activated(int)), this, SIGNAL(activated(int)));
+ if(m_pShow)
+ connect(m_pShow, SIGNAL(activated(int)), this, SIGNAL(activated(int)));
+ if(m_pColor)
+ connect(m_pColor, SIGNAL(activated(int)), this, SIGNAL(activated(int)));
+}
+
+void ListPopupMenu::setupDiagramMenu(UMLView* view) {
+ insertItem(SmallIcon("undo"), i18n("Undo"), mt_Undo);
+ insertItem(SmallIcon("redo"), i18n("Redo"), mt_Redo);
+ insertSeparator();
+ insertStdItem(mt_Cut);
+ insertStdItem(mt_Copy);
+ insertStdItem(mt_Paste);
+ insertSeparator();
+ insertItem(SmallIcon("editclear"), i18n("Clear Diagram"), mt_Clear);
+ insertStdItem(mt_Export_Image);
+ insertSeparator();
+ insertItem(i18n("Snap to Grid"), mt_SnapToGrid);
+ setItemChecked(mt_SnapToGrid, view->getSnapToGrid() );
+ insertItem(i18n("Show Grid"), mt_ShowSnapGrid );
+ setItemChecked(mt_ShowSnapGrid, view->getShowSnapGrid() );
+ insertStdItem(mt_Properties);
+}
+
diff --git a/umbrello/umbrello/listpopupmenu.h b/umbrello/umbrello/listpopupmenu.h
new file mode 100644
index 00000000..58d779ab
--- /dev/null
+++ b/umbrello/umbrello/listpopupmenu.h
@@ -0,0 +1,330 @@
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * copyright (C) 2003-2007 *
+ * Umbrello UML Modeller Authors <uml-devel@uml.sf.net> *
+ ***************************************************************************/
+
+#ifndef LISTPOPUPMENU_H
+#define LISTPOPUPMENU_H
+
+#include <kpopupmenu.h>
+#include "umlnamespace.h"
+
+class UMLView;
+class UMLWidget;
+class ClassifierWidget;
+
+/**
+ * A popup menu that depending on what type it is set to will
+ * display a different menu.
+ *
+ * @short Displays a popup menu.
+ * @author Paul Hensgen <phensgen@techie.com>
+ * Bugs and comments to uml-devel@lists.sf.net or http://bugs.kde.org
+ */
+
+class ListPopupMenu : public KPopupMenu {
+public:
+
+ /// This type hosts all possible menu types.
+ enum Menu_Type
+ {
+ mt_Model,
+ mt_Logical_View,
+ mt_UseCase_View,
+ mt_Component_View,
+ mt_Deployment_View,
+ mt_EntityRelationship_Model,
+ mt_UseCase_Diagram,
+ mt_Sequence_Diagram,
+ mt_Class_Diagram,
+ mt_Collaboration_Diagram,
+ mt_State_Diagram,
+ mt_Activity_Diagram,
+ mt_Component_Diagram,
+ mt_Deployment_Diagram,
+ mt_EntityRelationship_Diagram,
+ mt_On_UseCase_Diagram,
+ mt_On_Sequence_Diagram,
+ mt_On_Class_Diagram,
+ mt_On_Collaboration_Diagram,
+ mt_On_State_Diagram,
+ mt_On_Activity_Diagram,
+ mt_On_Component_Diagram,
+ mt_On_Deployment_Diagram,
+ mt_On_EntityRelationship_Diagram,
+ mt_Logical_Folder,
+ mt_UseCase_Folder,
+ mt_Component_Folder,
+ mt_Deployment_Folder,
+ mt_EntityRelationship_Folder,
+ mt_Class,
+ mt_Package,
+ mt_Subsystem,
+ mt_Component,
+ mt_Node,
+ mt_Artifact,
+ mt_Interface,
+ mt_Enum,
+ mt_Entity,
+ mt_Datatype,
+ mt_Actor,
+ mt_UseCase,
+ mt_Attribute,
+ mt_EntityAttribute,
+ mt_EnumLiteral,
+ mt_Object,
+ mt_Initial_State,
+ mt_End_State,
+ mt_State,
+ mt_Activity,
+ mt_Initial_Activity,
+ mt_End_Activity,
+ mt_Operation,
+ mt_Template,
+ mt_New_Parameter,
+ mt_New_Operation,
+ mt_New_Attribute,
+ mt_New_Template,
+ mt_New_EnumLiteral,
+ mt_New_EntityAttribute,
+ mt_Parameter_Selected,
+ mt_Operation_Selected,
+ mt_Attribute_Selected,
+ mt_Template_Selected,
+ mt_EnumLiteral_Selected,
+ mt_EntityAttribute_Selected,
+ mt_Association_Selected, // Association without role names
+ mt_Show_Attributes,
+ mt_Show_Attributes_Selection, //SHOWATTS, multiple items
+ mt_Show_Operations,
+ mt_Show_Operations_Selection, //SHOWOPS, multiple items
+ mt_Show_Packages,
+ mt_Show_Packages_Selection, //SHOWPACKAGE, multiple items
+ mt_Show_Stereotypes,
+ mt_Show_Stereotypes_Selection, //SHOWSTEREOTYPE, multiple items
+ mt_Visibility,
+ mt_Visibility_Selection, //SCOPE, multiple items
+ mt_DrawAsCircle,
+ mt_DrawAsCircle_Selection, //DRAWASCIRCLE, multiple items
+ mt_ChangeToClass,
+ mt_ChangeToClass_Selection,
+ mt_ChangeToInterface,
+ mt_ChangeToInterface_Selection,
+ mt_Rename_Object,
+ mt_Select_Operation,
+ mt_Anchor,
+ mt_Properties,
+ mt_Rename,
+ mt_Delete,
+ mt_Export_Image,
+ mt_Import_Classes,
+ mt_Sequence_Number,
+ mt_Cut,
+ mt_Copy,
+ mt_Paste,
+ mt_Clear,
+ mt_Redo,
+ mt_Undo,
+ mt_Link_Docs,
+ mt_Show_Operation_Signature,
+ mt_Show_Operation_Signature_Selection, //SHOWOPSIG, multiple items
+ mt_Show_Attribute_Signature,
+ mt_Show_Attribute_Signature_Selection, //SHOWATTSIG, multiple items
+ mt_Message_Text,
+ mt_Collaboration_Message,
+ mt_FloatText,
+ mt_MultiA,
+ mt_MultiB,
+ mt_Name, //Association name
+ mt_FullAssociation, // Association with role names
+ mt_AttributeAssociation, // Rendering of an attribute as an association
+ mt_RoleNameA,
+ mt_RoleNameB,
+ mt_Delete_Selection,
+ mt_Reset_Label_Positions,
+ mt_Line_Color,
+ mt_Line_Color_Selection, //LINECOLOR, multiple items
+ mt_Fill_Color,
+ mt_Fill_Color_Selection, //FILLCOLOR, multiple items
+ mt_Use_Fill_Color,
+ mt_Default_Properties,
+ mt_Rename_MultiA,
+ mt_Rename_MultiB,
+ mt_Rename_Name,
+ mt_Rename_RoleAName,
+ mt_Rename_RoleBName,
+ mt_Change_Font,
+ mt_Change_Font_Selection,
+ mt_SnapToGrid,
+ mt_ShowSnapGrid,
+ mt_Activity_Selected,
+ mt_New_Activity,
+ mt_Up,
+ mt_Down,
+ mt_Branch,
+ mt_Flip,
+
+ mt_Expand_All, //Expand all items in the list
+ mt_Collapse_All, //Collapse all items in the list
+
+ mt_Refactoring,
+ mt_ViewCode, // view code document contents
+ mt_Clone, // Create a deep copy of the object.
+ mt_Show_Public_Only, // (not currently used)
+ mt_Show_Public_Only_Selection, // Show public operations/attributes only.
+ mt_Externalize_Folder, // Mark folder for saving as separate submodel
+ mt_Internalize_Folder, // Reintegrate separate submodel into main model
+
+ mt_Undefined = - 1
+ };
+
+ /**
+ * Constructs the popup menu for a diagram
+ *
+ * @param parent The parent to ListPopupMenu.
+ * @param type The type of menu to display.
+ * @param view The UMLView in which this ListPopupMenu is going to be displayed
+ */
+ explicit ListPopupMenu(QWidget* parent, Menu_Type type = mt_Undefined, UMLView* view = 0);
+
+ /**
+ * Constructs the popup menu for a list view item.
+ *
+ * @param parent The parent to ListPopupMenu.
+ * @param type The type of menu to display.
+ */
+ ListPopupMenu(QWidget* parent, Uml::ListView_Type type);
+
+ /**
+ * Constructs the popup menu for a canvas widget.
+ *
+ * @param parent The parent to ListPopupMenu.
+ * @param object The UMLWidget to represent a menu for.
+ * @param multi True if multiple items are selected.
+ * @param unique True if multiple selected items all have
+ * the same type (e.g. Class, Interface)
+ */
+ ListPopupMenu(QWidget* parent, UMLWidget* object, bool multi = false, bool unique = false);
+
+ /**
+ * Standard deconstructor.
+ */
+ ~ListPopupMenu();
+
+ /**
+ * Utility: Convert a Menu_Type value to an Object_Type value.
+ */
+ static Uml::Object_Type convert_MT_OT(Menu_Type mt);
+
+ /**
+ * Utility: Convert a Menu_Type value to a Diagram_Type value.
+ */
+ static Uml::Diagram_Type convert_MT_DT(Menu_Type mt);
+
+private:
+ /**
+ * Basic initialization - common to all constructors.
+ */
+ void init();
+
+ /**
+ * Shortcut for inserting a "File->New" choice.
+ */
+ void insertFileNew();
+
+ /**
+ * Shortcut for the most frequently used insertItem() calls.
+ *
+ * @param m The Menu_Type for which to insert a menu item.
+ */
+ void insertStdItem(Menu_Type m);
+
+ /**
+ * Shortcut for the most frequently used insertStdItem() calls.
+ *
+ * @param insertLeadingSeparator Set this true if the group shall
+ * start with a separator.
+ * @param type The Widget_Type for which to insert the menu items.
+ * If no argument is supplied then a Rename item will be
+ * included.
+ */
+ void insertStdItems(bool insertLeadingSeparator = true,
+ Uml::Widget_Type type = Uml::wt_UMLWidget);
+
+ /**
+ * Shortcut for inserting standard model items (Class, Interface,
+ * Datatype, Enum, Package) as well as diagram choices.
+ *
+ * @param folderAndDiagrams Set this true if folders and diagram
+ * types shall be included as choices.
+ */
+ void insertContainerItems(bool folderAndDiagrams);
+
+ /**
+ * Inserts a menu item for an association related text
+ * (such as name, role, multiplicity etc.)
+ *
+ * @param label The menu text.
+ * @param mt The menu type.
+ */
+ void insertAssocItem(const QString &label, Menu_Type mt);
+
+ /**
+ * Inserts a menu item for externalization/de-externalization
+ * of a folder.
+ */
+ void insertSubmodelAction();
+
+ /**
+ * Creates a popup menu for a multiple selection of class and
+ * interface widgets.
+ */
+ void makeMultiClassifierPopup(ClassifierWidget *c);
+
+ /**
+ * Creates a popup menu for a single class or interface widgets.
+ */
+ void makeClassifierPopup(ClassifierWidget *c);
+
+ /**
+ * Shortcut for commonly used menu initializations.
+ *
+ * @param type The Menu_Type for which to set up the menu.
+ * @param view The UMLView parent of the menu.
+ */
+ void setupMenu(Menu_Type type, UMLView * view = 0);
+
+ enum PixMap_Type {
+ pm_Class,
+ pm_Package,
+ pm_Interface,
+ pm_Datatype,
+ pm_Enum,
+ pm_Actor,
+ pm_Usecase,
+ pm_InitialState,
+ pm_EndState,
+ pm_Branch,
+ pm_Object,
+ pm_Component,
+ pm_Node,
+ pm_Artifact,
+ pm_Text,
+ pm_Entity,
+ pm_Subsystem,
+ pm_NUMBER_OF_PIXMAPS
+ };
+ QPixmap m_pixmap[pm_NUMBER_OF_PIXMAPS];
+ KPopupMenu * m_pInsert, * m_pShow, * m_pColor;
+ void setupColor(bool fc);
+ void setupColorSelection(bool fc);
+ void setupDiagramMenu(UMLView* view);
+};
+
+#endif
diff --git a/umbrello/umbrello/main.cpp b/umbrello/umbrello/main.cpp
new file mode 100644
index 00000000..faba82d3
--- /dev/null
+++ b/umbrello/umbrello/main.cpp
@@ -0,0 +1,208 @@
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * copyright (C) 2002-2006 *
+ * Umbrello UML Modeller Authors <uml-devel@uml.sf.net> *
+ ***************************************************************************/
+
+#include <unistd.h>
+
+// kde includes
+#include <kaboutdata.h>
+#include <kapplication.h>
+#include <kcmdlineargs.h>
+#include <kconfig.h>
+#include <klocale.h>
+#include <ktip.h>
+#include <kdebug.h>
+#include <kwin.h>
+
+// app includes
+#include "uml.h"
+#include "version.h"
+#include "umldoc.h"
+#include "cmdlineexportallviewsevent.h"
+#include "kstartuplogo.h"
+
+static const char description[] =
+ I18N_NOOP("Umbrello UML Modeller");
+// INSERT A DESCRIPTION FOR YOUR APPLICATION HERE
+
+/**
+ * @todo Add options to use the documentation generators from command line.
+ */
+static KCmdLineOptions options[] =
+ {
+ { "+[File]", I18N_NOOP("File to open"), 0 },
+ { "export <extension>", I18N_NOOP("export diagrams to extension and exit"), 0},
+ { "directory <url>", I18N_NOOP("the local directory to save the exported diagrams in"), I18N_NOOP("the directory of the file")},
+ { "use-folders", I18N_NOOP("keep the tree structure used to store the views in the document in the target directory"), 0},
+ // INSERT YOUR COMMANDLINE OPTIONS HERE
+ KCmdLineLastOption
+ };
+
+/**
+ * Determines if the application GUI should be shown based on command line arguments.
+ *
+ * @param args The command line arguments given.
+ * @return True if the GUI should be shown, false otherwise.
+ */
+bool getShowGUI(KCmdLineArgs *args);
+
+/**
+ * Creates, shows and returns the startup logo for the application if it should be shown,
+ * else returns null pointer.
+ * The startup logo is shown if it is configured to be shown and also the GUI must be shown.
+ *
+ * @param cfg The application configuration.
+ * @param showGUI If the GUI should be shown.
+ * @return The startup logo for the application, or a null pointer if it shouldn't be shown.
+ */
+KStartupLogo* showStartupLogo(KConfig* cfg, bool showGUI);
+
+/**
+ * Initializes the document used by the application.
+ * If a file was specified in command line arguments, opens that file. Else, it
+ * opens the last opened file, or a new file if there isn't any "last file used"
+ * in the configuration.
+ *
+ * @param args The command line arguments given.
+ * @param cfg The application configuration.
+ */
+void initDocument(KCmdLineArgs *args, KConfig* cfg);
+
+/**
+ * Export all the views in the document using the command line args set by the user.
+ * Errors that occurred while exporting, if any, are shown using kError().
+ *
+ * @param args The command line arguments given.
+ * @param exportOpt A list containing all the "export" arguments given.
+ */
+void exportAllViews(KCmdLineArgs *args, const QCStringList &exportOpt);
+
+extern "C" int flushEvents() {
+ kapp->processEvents();
+ return 0;
+}
+
+int main(int argc, char *argv[]) {
+ KAboutData aboutData( "umbrello", I18N_NOOP("Umbrello UML Modeller"),
+ UMBRELLO_VERSION, description, KAboutData::License_GPL,
+ I18N_NOOP("(c) 2001 Paul Hensgen, (c) 2002-2006 Umbrello UML Modeller Authors"), 0,
+ "http://uml.sf.net/");
+ aboutData.addAuthor("Paul Hensgen",0, "phensgen@users.sourceforge.net");
+ aboutData.addAuthor(I18N_NOOP("Umbrello UML Modeller Authors"), 0, "uml-devel@lists.sourceforge.net");
+ KCmdLineArgs::init( argc, argv, &aboutData );
+ KCmdLineArgs::addCmdLineOptions( options ); // Add our own options.
+
+ KApplication app;
+ if( app.isRestored() ) {
+ RESTORE( UMLApp );
+ } else {
+ KCmdLineArgs *args = KCmdLineArgs::parsedArgs();
+ bool showGUI = getShowGUI(args);
+
+ UMLApp *uml = new UMLApp();
+ flushEvents();
+ KConfig * cfg = app.config();
+
+ KStartupLogo* startLogo = showStartupLogo(cfg, showGUI);
+
+ if (showGUI) {
+ uml->show();
+ }
+ uml->initGenerator();
+
+ //show tips if wanted
+ if (showGUI) {
+ KTipDialog::showTip();
+ }
+
+ initDocument(args, cfg);
+
+ // export option
+ QCStringList exportOpt = args->getOptionList("export");
+ if (exportOpt.size() > 0) {
+ exportAllViews(args, exportOpt);
+ }
+
+ if ( showGUI && (startLogo != 0L) && !startLogo->isHidden() ) {
+ startLogo->raise();
+ }
+ }
+ return app.exec();
+}
+
+bool getShowGUI(KCmdLineArgs *args) {
+ if (args->getOptionList("export").size() > 0) {
+ return false;
+ }
+
+ return true;
+}
+
+KStartupLogo* showStartupLogo(KConfig* cfg, bool showGUI) {
+ KStartupLogo* startLogo = 0L;
+
+ cfg->setGroup( "General Options" );
+ bool showLogo = cfg->readBoolEntry( "logo", true );
+ if (showGUI && showLogo) {
+#if KDE_IS_VERSION(3,3,90)
+ startLogo = new KStartupLogo(0);
+ startLogo->setHideEnabled(true);
+ KWin::setMainWindow(startLogo, UMLApp::app()->winId());
+#else
+ startLogo = new KStartupLogo(UMLApp::app());
+ startLogo->setHideEnabled(true);
+#endif
+ KWin::setState(startLogo->winId(), NET::KeepAbove);
+ startLogo->show();
+ QApplication::flushX();
+ }
+
+ return startLogo;
+}
+
+void initDocument(KCmdLineArgs *args, KConfig* cfg) {
+ if ( args -> count() ) {
+ UMLApp::app()->openDocumentFile( args->url( 0 ) );
+ } else {
+ cfg->setGroup( "General Options" );
+ bool last = cfg->readBoolEntry( "loadlast", false );
+ QString file = cfg->readPathEntry( "lastFile" );
+ if( last && !file.isEmpty() ) {
+ UMLApp::app()->openDocumentFile( KURL( file ) );
+ } else {
+ UMLApp::app()->newDocument();
+ }
+ }
+}
+
+void exportAllViews(KCmdLineArgs *args, const QCStringList &exportOpt) {
+ QString extension(exportOpt.last());
+ kDebug() << "extension: " << extension << endl;
+
+ // export to the specified directory, or the directory where the file is saved
+ // if no directory was specified
+ KURL directory;
+ QCStringList directoryOpt = args->getOptionList("directory");
+ if (directoryOpt.size() > 0) {
+ directory = KCmdLineArgs::makeURL(directoryOpt.last());
+ } else {
+ directory = KURL(UMLApp::app()->getDocument()->URL().directory());
+ }
+
+ bool useFolders = args->isSet("use-folders");
+
+ kDebug() << "directory: " << directory.prettyURL() << endl;
+
+ // the event is posted so when the QT loop begins it's processed. UMLApp process this event executing
+ // the method it provides for exporting the views. Once all the views were exported, a quit event
+ // is sent and the app finishes without user interaction
+ kapp->postEvent(UMLApp::app(), new CmdLineExportAllViewsEvent(extension, directory, useFolders));
+}
+
diff --git a/umbrello/umbrello/messagewidget.cpp b/umbrello/umbrello/messagewidget.cpp
new file mode 100644
index 00000000..3cefc99d
--- /dev/null
+++ b/umbrello/umbrello/messagewidget.cpp
@@ -0,0 +1,792 @@
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * copyright (C) 2002-2007 *
+ * Umbrello UML Modeller Authors <uml-devel@uml.sf.net> *
+ ***************************************************************************/
+
+// onw header
+#include "messagewidget.h"
+
+//qt includes
+#include <qpainter.h>
+//kde includes
+#include <kdebug.h>
+#include <kcursor.h>
+//app includes
+#include "messagewidgetcontroller.h"
+#include "floatingtextwidget.h"
+#include "objectwidget.h"
+#include "classifier.h"
+#include "operation.h"
+#include "umlview.h"
+#include "umldoc.h"
+#include "uml.h"
+#include "uniqueid.h"
+#include "listpopupmenu.h"
+
+MessageWidget::MessageWidget(UMLView * view, ObjectWidget* a, ObjectWidget* b,
+ int y, Uml::Sequence_Message_Type sequenceMessageType,
+ Uml::IDType id /* = Uml::id_None */)
+ : UMLWidget(view, id, new MessageWidgetController(this)) {
+ init();
+ m_pOw[Uml::A] = a;
+ m_pOw[Uml::B] = b;
+ m_nY = y;
+ m_sequenceMessageType = sequenceMessageType;
+ if (m_sequenceMessageType == Uml::sequence_message_creation) {
+ y -= m_pOw[Uml::B]->getHeight() / 2;
+ m_pOw[Uml::B]->setY(y);
+ }
+ updateResizability();
+ calculateWidget();
+ y = y < getMinY() ? getMinY() : y;
+ y = y > getMaxY() ? getMaxY() : y;
+ m_nY = y;
+
+ this->activate();
+}
+
+MessageWidget::MessageWidget(UMLView * view, Uml::Sequence_Message_Type seqMsgType, Uml::IDType id)
+ : UMLWidget(view, id, new MessageWidgetController(this)) {
+ init();
+ m_sequenceMessageType = seqMsgType;
+}
+
+void MessageWidget::init() {
+ UMLWidget::setBaseType(Uml::wt_Message);
+ m_bIgnoreSnapToGrid = true;
+ m_bIgnoreSnapComponentSizeToGrid = true;
+ m_pOw[Uml::A] = m_pOw[Uml::B] = NULL;
+ m_pFText = NULL;
+ m_nY = 0;
+ setVisible(true);
+}
+
+MessageWidget::~MessageWidget() {
+}
+
+void MessageWidget::updateResizability() {
+ if (m_sequenceMessageType == Uml::sequence_message_synchronous ||
+ m_pOw[Uml::A] == m_pOw[Uml::B])
+ UMLWidget::m_bResizable = true;
+ else
+ UMLWidget::m_bResizable = false;
+}
+
+void MessageWidget::draw(QPainter& p, int offsetX, int offsetY) {
+ if(!m_pOw[Uml::A] || !m_pOw[Uml::B]) {
+ return;
+ }
+ UMLWidget::setPen(p);
+ if (m_sequenceMessageType == Uml::sequence_message_synchronous) {
+ drawSynchronous(p, offsetX, offsetY);
+ } else if (m_sequenceMessageType == Uml::sequence_message_asynchronous) {
+ drawAsynchronous(p, offsetX, offsetY);
+ } else if (m_sequenceMessageType == Uml::sequence_message_creation) {
+ drawCreation(p, offsetX, offsetY);
+ } else {
+ kWarning() << "Unknown message type" << endl;
+ }
+}
+
+void MessageWidget::drawSolidArrowhead(QPainter& p, int x, int y, Qt::ArrowType direction) {
+ int arrowheadExtentX = 4;
+ if (direction == Qt::RightArrow) {
+ arrowheadExtentX = -arrowheadExtentX;
+ }
+ QPointArray points;
+ points.putPoints(0, 3, x, y, x + arrowheadExtentX, y - 3, x + arrowheadExtentX, y + 3);
+ p.setBrush( QBrush(p.pen().color()) );
+ p.drawPolygon(points);
+}
+
+void MessageWidget::drawArrow(QPainter& p, int x, int y, int w,
+ Qt::ArrowType direction, bool useDottedLine /* = false */) {
+ int arrowheadStartX = x;
+ int arrowheadExtentX = 4;
+ if (direction == Qt::RightArrow) {
+ arrowheadStartX += w;
+ arrowheadExtentX = -arrowheadExtentX;
+ }
+ // draw upper half of arrowhead
+ p.drawLine(arrowheadStartX, y, arrowheadStartX + arrowheadExtentX, y - 3);
+ // draw lower half of arrowhead
+ p.drawLine(arrowheadStartX, y, arrowheadStartX + arrowheadExtentX, y + 3);
+ // draw arrow line
+ if (useDottedLine) {
+ QPen pen = p.pen();
+ pen.setStyle(Qt::DotLine);
+ p.setPen(pen);
+ }
+ p.drawLine(x, y, x + w, y);
+}
+
+void MessageWidget::drawSynchronous(QPainter& p, int offsetX, int offsetY) {
+ int x1 = m_pOw[Uml::A]->getX();
+ int x2 = m_pOw[Uml::B]->getX();
+ int w = getWidth() - 1;
+ int h = getHeight();
+
+ bool messageOverlaps = m_pOw[Uml::A] -> messageOverlap( getY(), this );
+
+ if(m_pOw[Uml::A] == m_pOw[Uml::B]) {
+ p.fillRect( offsetX, offsetY, 17, h, QBrush(Qt::white) ); //box
+ p.drawRect(offsetX, offsetY, 17, h); //box
+ offsetX += 17;
+ w -= 17;
+ offsetY += 3;
+ const int lowerLineY = offsetY + h - 6;
+ // draw upper line segment (leaving the life line)
+ p.drawLine(offsetX, offsetY, offsetX + w, offsetY);
+ // draw line segment parallel to (and at the right of) the life line
+ p.drawLine(offsetX + w, offsetY, offsetX + w, lowerLineY);
+ // draw lower line segment (back to the life line)
+ drawArrow(p, offsetX, lowerLineY, w, Qt::LeftArrow);
+ offsetX -= 17;
+ offsetY -= 3;
+ } else if(x1 < x2) {
+ if (messageOverlaps) {
+ offsetX += 8;
+ w -= 8;
+ }
+ QPen pen = p.pen();
+ int startX = offsetX + w - 16;
+ p.fillRect(startX, offsetY, 17, h, QBrush(Qt::white)); //box
+ p.drawRect(startX, offsetY, 17, h); //box
+ p.drawLine(offsetX, offsetY + 4, startX, offsetY + 4); //arrow line
+ drawSolidArrowhead(p, startX - 1, offsetY + 4, Qt::RightArrow);
+ drawArrow(p, offsetX, offsetY + h - 3, w - 16, Qt::LeftArrow, true); // return arrow
+ if (messageOverlaps) {
+ offsetX -= 8; //reset for drawSelected()
+ }
+ } else {
+ if (messageOverlaps) {
+ w -=8;
+ }
+ QPen pen = p.pen();
+ p.fillRect( offsetX, offsetY, 17, h, QBrush(Qt::white) ); //box
+ p.drawRect(offsetX, offsetY, 17, h); //box
+ p.drawLine(offsetX + 18, offsetY + 4, offsetX + w, offsetY + 4); //arrow line
+ drawSolidArrowhead(p, offsetX + 17, offsetY + 4, Qt::LeftArrow);
+ drawArrow(p, offsetX + 18, offsetY + h - 3, w - 18, Qt::RightArrow, true); // return arrow
+ }
+
+ if(m_bSelected) {
+ drawSelected(&p, offsetX, offsetY);
+ }
+}
+
+void MessageWidget::drawAsynchronous(QPainter& p, int offsetX, int offsetY) {
+ int x1 = m_pOw[Uml::A]->getX();
+ int x2 = m_pOw[Uml::B]->getX();
+ int w = getWidth() - 1;
+ int h = getHeight() - 1;
+ bool messageOverlapsA = m_pOw[Uml::A] -> messageOverlap( getY(), this );
+ //bool messageOverlapsB = m_pOw[Uml::B] -> messageOverlap( getY(), this );
+
+ if(m_pOw[Uml::A] == m_pOw[Uml::B]) {
+ if (messageOverlapsA) {
+ offsetX += 7;
+ w -= 7;
+ }
+ const int lowerLineY = offsetY + h - 3;
+ // draw upper line segment (leaving the life line)
+ p.drawLine(offsetX, offsetY, offsetX + w, offsetY);
+ // draw line segment parallel to (and at the right of) the life line
+ p.drawLine(offsetX + w, offsetY, offsetX + w, lowerLineY);
+ // draw lower line segment (back to the life line)
+ drawArrow(p, offsetX, lowerLineY, w, Qt::LeftArrow);
+ if (messageOverlapsA) {
+ offsetX -= 7; //reset for drawSelected()
+ }
+ } else if(x1 < x2) {
+ if (messageOverlapsA) {
+ offsetX += 7;
+ w -= 7;
+ }
+ drawArrow(p, offsetX, offsetY + 4, w, Qt::RightArrow);
+ if (messageOverlapsA) {
+ offsetX -= 7;
+ }
+ } else {
+ if (messageOverlapsA) {
+ w -= 7;
+ }
+ drawArrow(p, offsetX, offsetY + 4, w, Qt::LeftArrow);
+ }
+
+ if (m_bSelected)
+ drawSelected(&p, offsetX, offsetY);
+}
+
+void MessageWidget::drawCreation(QPainter& p, int offsetX, int offsetY) {
+ int x1 = m_pOw[Uml::A]->getX();
+ int x2 = m_pOw[Uml::B]->getX();
+ int w = getWidth() - 1;
+ //int h = getHeight() - 1;
+ bool messageOverlapsA = m_pOw[Uml::A] -> messageOverlap( getY(), this );
+ //bool messageOverlapsB = m_pOw[Uml::B] -> messageOverlap( getY(), this );
+
+ const int lineY = offsetY + 4;
+ if (x1 < x2) {
+ if (messageOverlapsA) {
+ offsetX += 7;
+ w -= 7;
+ }
+ drawArrow(p, offsetX, lineY, w, Qt::RightArrow);
+ if (messageOverlapsA) {
+ offsetX -= 7;
+ }
+ } else {
+ if (messageOverlapsA) {
+ w -= 7;
+ }
+ drawArrow(p, offsetX, lineY, w, Qt::LeftArrow);
+ }
+
+ if (m_bSelected)
+ drawSelected(&p, offsetX, offsetY);
+}
+
+int MessageWidget::onWidget(const QPoint & p) {
+ if (m_sequenceMessageType != Uml::sequence_message_synchronous) {
+ return UMLWidget::onWidget(p);
+ }
+ // Synchronous message:
+ // Consists of top arrow (call) and bottom arrow (return.)
+ if (p.x() < getX() || p.x() > getX() + getWidth())
+ return 0;
+ const int tolerance = 5; // pixels
+ const int pY = p.y();
+ const int topArrowY = getY() + 3;
+ const int bottomArrowY = getY() + getHeight() - 3;
+ if (pY < topArrowY - tolerance || pY > bottomArrowY + tolerance)
+ return 0;
+ if (getHeight() <= 2 * tolerance)
+ return 1;
+ if (pY > topArrowY + tolerance && pY < bottomArrowY - tolerance)
+ return 0;
+ return 1;
+}
+
+void MessageWidget::setTextPosition() {
+ if (m_pFText == NULL) {
+ kDebug() << "MessageWidget::setTextPosition: m_pFText is NULL"
+ << endl;
+ return;
+ }
+ if (m_pFText->getDisplayText().isEmpty()) {
+ return;
+ }
+ m_pFText->updateComponentSize();
+ int ftX = constrainX(m_pFText->getX(), m_pFText->getWidth(), m_pFText->getRole());
+ int ftY = getY() - m_pFText->getHeight();
+ m_pFText->setX( ftX );
+ m_pFText->setY( ftY );
+}
+
+int MessageWidget::constrainX(int textX, int textWidth, Uml::Text_Role tr) {
+ int result = textX;
+ const int minTextX = getX() + 5;
+ if (textX < minTextX || tr == Uml::tr_Seq_Message_Self) {
+ result = minTextX;
+ } else {
+ ObjectWidget *objectAtRight = NULL;
+ if (m_pOw[Uml::B]->getX() > m_pOw[Uml::A]->getX())
+ objectAtRight = m_pOw[Uml::B];
+ else
+ objectAtRight = m_pOw[Uml::A];
+ const int objRight_seqLineX = objectAtRight->getX() + objectAtRight->getWidth() / 2;
+ const int maxTextX = objRight_seqLineX - textWidth - 5;
+ if (maxTextX <= minTextX)
+ result = minTextX;
+ else if (textX > maxTextX)
+ result = maxTextX;
+ }
+ return result;
+}
+
+void MessageWidget::constrainTextPos(int &textX, int &textY, int textWidth, int textHeight,
+ Uml::Text_Role tr) {
+ textX = constrainX(textX, textWidth, tr);
+ // Constrain Y.
+ const int minTextY = getMinY();
+ const int maxTextY = getMaxY() - textHeight - 5;
+ if (textY < minTextY)
+ textY = minTextY;
+ else if (textY > maxTextY)
+ textY = maxTextY;
+// setY( textY + textHeight ); // NB: side effect
+}
+
+void MessageWidget::setLinkAndTextPos() {
+ if (m_pFText == NULL)
+ return;
+ m_pFText->setLink(this);
+ setTextPosition();
+}
+
+void MessageWidget::moveEvent(QMoveEvent* /*m*/) {
+ //kDebug() << "MessageWidget::moveEvent: m_pFText is " << m_pFText << endl;
+ if (!m_pFText) {
+ return;
+ }
+ //TODO why this condition?
+/* if (m_pView->getSelectCount() > 2) {
+ return;
+ }*/
+
+ setTextPosition();
+
+ emit sigMessageMoved();
+}
+
+void MessageWidget::resizeEvent(QResizeEvent* /*re*/) {
+}
+
+void MessageWidget::calculateWidget() {
+ setMessageText(m_pFText);
+ calculateDimensions();
+
+ setVisible(true);
+
+ setX(m_nPosX);
+ setY(m_nY);
+}
+
+void MessageWidget::slotWidgetMoved(Uml::IDType id) {
+ const Uml::IDType idA = m_pOw[Uml::A]->getLocalID();
+ const Uml::IDType idB = m_pOw[Uml::B]->getLocalID();
+ if (idA != id && idB != id) {
+ kDebug() << "MessageWidget::slotWidgetMoved(" << ID2STR(id)
+ << "): ignoring for idA=" << ID2STR(idA)
+ << ", idB=" << ID2STR(idB) << endl;
+ return;
+ }
+ m_nY = getY();
+ if (m_nY < getMinY())
+ m_nY = getMinY();
+ if (m_nY > getMaxY())
+ m_nY = getMaxY();
+ calculateWidget();
+ if( !m_pFText )
+ return;
+ if (m_pView->getSelectCount(true) > 1)
+ return;
+ setTextPosition();
+}
+
+bool MessageWidget::contains(ObjectWidget * w) {
+ if(m_pOw[Uml::A] == w || m_pOw[Uml::B] == w)
+ return true;
+ else
+ return false;
+}
+
+void MessageWidget::slotMenuSelection(int sel) {
+ if(sel == ListPopupMenu::mt_Delete) {
+ // This will clean up this widget and the text widget:
+ m_pView -> removeWidget(this);
+ } else {
+ if (m_pFText == NULL) {
+ Uml::Text_Role tr = Uml::tr_Seq_Message;
+ if (m_pOw[Uml::A] == m_pOw[Uml::B])
+ tr = Uml::tr_Seq_Message_Self;
+ m_pFText = new FloatingTextWidget( m_pView, tr );
+ m_pFText->setFont(UMLWidget::getFont());
+ setLinkAndTextPos();
+ m_pView->getWidgetList().append(m_pFText);
+ }
+ m_pFText -> slotMenuSelection(sel);
+ }
+}
+
+bool MessageWidget::activate(IDChangeLog * Log /*= 0*/) {
+ m_pView->resetPastePoint();
+ // UMLWidget::activate(Log); CHECK: I don't think we need this ?
+ if (m_pOw[Uml::A] == NULL) {
+ UMLWidget *pWA = m_pView->findWidget(m_widgetAId);
+ if (pWA == NULL) {
+ kDebug() << "MessageWidget::activate: role A object "
+ << ID2STR(m_widgetAId) << " not found" << endl;
+ return false;
+ }
+ m_pOw[Uml::A] = dynamic_cast<ObjectWidget*>(pWA);
+ if (m_pOw[Uml::A] == NULL) {
+ kDebug() << "MessageWidget::activate: role A widget "
+ << ID2STR(m_widgetAId) << " is not an ObjectWidget" << endl;
+ return false;
+ }
+ }
+ if (m_pOw[Uml::B] == NULL) {
+ UMLWidget *pWB = m_pView->findWidget(m_widgetBId);
+ if (pWB == NULL) {
+ kDebug() << "MessageWidget::activate: role B object "
+ << ID2STR(m_widgetBId) << " not found" << endl;
+ return false;
+ }
+ m_pOw[Uml::B] = dynamic_cast<ObjectWidget*>(pWB);
+ if (m_pOw[Uml::B] == NULL) {
+ kDebug() << "MessageWidget::activate: role B widget "
+ << ID2STR(m_widgetBId) << " is not an ObjectWidget" << endl;
+ return false;
+ }
+ }
+ updateResizability();
+
+ UMLClassifier *c = dynamic_cast<UMLClassifier*>(m_pOw[Uml::B]->getUMLObject());
+ UMLOperation *op = NULL;
+ if (c && !m_CustomOp.isEmpty()) {
+ Uml::IDType opId = STR2ID(m_CustomOp);
+ op = dynamic_cast<UMLOperation*>( c->findChildObjectById(opId, true) );
+ if (op) {
+ // If the UMLOperation is set, m_CustomOp isn't used anyway.
+ // Just setting it empty for the sake of sanity.
+ m_CustomOp = QString::null;
+ }
+ }
+
+ if( !m_pFText ) {
+ Uml::Text_Role tr = Uml::tr_Seq_Message;
+ if (m_pOw[Uml::A] == m_pOw[Uml::B])
+ tr = Uml::tr_Seq_Message_Self;
+ m_pFText = new FloatingTextWidget( m_pView, tr, "" );
+ m_pFText->setFont(UMLWidget::getFont());
+ }
+ if (op)
+ setOperation(op); // This requires a valid m_pFText.
+ setLinkAndTextPos();
+ m_pFText -> setText("");
+ m_pFText->setActivated();
+ QString messageText = m_pFText->getText();
+ m_pFText->setVisible( messageText.length() > 1 );
+
+ connect(m_pOw[Uml::A], SIGNAL(sigWidgetMoved(Uml::IDType)), this, SLOT(slotWidgetMoved(Uml::IDType)));
+ connect(m_pOw[Uml::B], SIGNAL(sigWidgetMoved(Uml::IDType)), this, SLOT(slotWidgetMoved(Uml::IDType)));
+
+ connect(this, SIGNAL(sigMessageMoved()), m_pOw[Uml::A], SLOT(slotMessageMoved()) );
+ connect(this, SIGNAL(sigMessageMoved()), m_pOw[Uml::B], SLOT(slotMessageMoved()) );
+ m_pOw[Uml::A] -> messageAdded(this);
+ m_pOw[Uml::B] -> messageAdded(this);
+ calculateDimensions();
+
+ emit sigMessageMoved();
+ return true;
+}
+
+void MessageWidget::setMessageText(FloatingTextWidget *ft) {
+ if (ft == NULL)
+ return;
+ QString displayText = m_SequenceNumber + ": " + getOperationText(m_pView);
+ ft->setText(displayText);
+ setTextPosition();
+}
+
+void MessageWidget::setText(FloatingTextWidget *ft, const QString &newText) {
+ ft->setText(newText);
+ UMLApp::app()->getDocument()->setModified(true);
+}
+
+void MessageWidget::setSeqNumAndOp(const QString &seqNum, const QString &op) {
+ setSequenceNumber( seqNum );
+ m_CustomOp = op; ///FIXME m_pOperation
+}
+
+void MessageWidget::setSequenceNumber( const QString &sequenceNumber ) {
+ m_SequenceNumber = sequenceNumber;
+}
+
+QString MessageWidget::getSequenceNumber() const {
+ return m_SequenceNumber;
+}
+
+void MessageWidget::lwSetFont (QFont font) {
+ UMLWidget::setFont( font );
+}
+
+UMLClassifier *MessageWidget::getOperationOwner() {
+ UMLObject *pObject = m_pOw[Uml::B]->getUMLObject();
+ if (pObject == NULL)
+ return NULL;
+ UMLClassifier *c = dynamic_cast<UMLClassifier*>(pObject);
+ return c;
+}
+
+UMLOperation *MessageWidget::getOperation() {
+ return static_cast<UMLOperation*>(m_pObject);
+}
+
+void MessageWidget::setOperation(UMLOperation *op) {
+ if (m_pObject && m_pFText)
+ disconnect(m_pObject, SIGNAL(modified()), m_pFText, SLOT(setMessageText()));
+ m_pObject = op;
+ if (m_pObject && m_pFText)
+ connect(m_pObject, SIGNAL(modified()), m_pFText, SLOT(setMessageText()));
+}
+
+QString MessageWidget::getCustomOpText() {
+ return m_CustomOp;
+}
+
+void MessageWidget::setCustomOpText(const QString &opText) {
+ m_CustomOp = opText;
+ m_pFText->setMessageText();
+}
+
+UMLClassifier * MessageWidget::getSeqNumAndOp(QString& seqNum, QString& op) {
+ seqNum = m_SequenceNumber;
+ UMLOperation *pOperation = getOperation();
+ if (pOperation != NULL) {
+ op = pOperation->toString(Uml::st_SigNoVis);
+ } else {
+ op = m_CustomOp;
+ }
+ UMLObject *o = m_pOw[Uml::B]->getUMLObject();
+ UMLClassifier *c = dynamic_cast<UMLClassifier*>(o);
+ return c;
+}
+
+void MessageWidget::calculateDimensions() {
+ if (m_sequenceMessageType == Uml::sequence_message_synchronous) {
+ calculateDimensionsSynchronous();
+ } else if (m_sequenceMessageType == Uml::sequence_message_asynchronous) {
+ calculateDimensionsAsynchronous();
+ } else if (m_sequenceMessageType == Uml::sequence_message_creation) {
+ calculateDimensionsCreation();
+ } else {
+ kWarning() << "Unknown message type" << endl;
+ }
+ if (! UMLApp::app()->getDocument()->loading()) {
+ adjustAssocs( getX(), getY() ); // adjust assoc lines
+ }
+}
+
+void MessageWidget::calculateDimensionsSynchronous() {
+ int x = 0;
+
+ int x1 = m_pOw[Uml::A]->getX();
+ int x2 = m_pOw[Uml::B]->getX();
+ int w1 = m_pOw[Uml::A]->getWidth() / 2;
+ int w2 = m_pOw[Uml::B]->getWidth() / 2;
+ x1 += w1;
+ x2 += w2;
+
+ int widgetWidth = 0;
+ int widgetHeight = 0;
+ if( m_pOw[Uml::A] == m_pOw[Uml::B] ) {
+ widgetWidth = 50;
+ x = x1 - 2;
+ } else if( x1 < x2 ) {
+ x = x1;
+ widgetWidth = x2 - x1 + 8;
+ } else {
+ x = x2 - 8;
+ widgetWidth = x1 - x2 + 8;
+ }
+
+ if ( height() < 20 ) {
+ widgetHeight = 20;
+ } else {
+ widgetHeight = height();
+ }
+
+ m_nPosX = x;
+ setSize(widgetWidth, widgetHeight);
+}
+
+void MessageWidget::calculateDimensionsAsynchronous() {
+ int x = 0;
+
+ int x1 = m_pOw[Uml::A]->getX();
+ int x2 = m_pOw[Uml::B]->getX();
+ int w1 = m_pOw[Uml::A]->getWidth() / 2;
+ int w2 = m_pOw[Uml::B]->getWidth() / 2;
+ x1 += w1;
+ x2 += w2;
+
+ int widgetWidth = 0;
+ int widgetHeight = 8;
+ if( m_pOw[Uml::A] == m_pOw[Uml::B] ) {
+ widgetWidth = 50;
+ x = x1;
+ if( height() < 20 ) {
+ widgetHeight = 20;
+ } else {
+ widgetHeight = height();
+ }
+ } else if( x1 < x2 ) {
+ x = x1;
+ widgetWidth = x2 - x1;
+ } else {
+ x = x2;
+ widgetWidth = x1 - x2;
+ }
+ x += 1;
+ widgetWidth -= 2;
+ m_nPosX = x;
+ setSize(widgetWidth, widgetHeight);
+}
+
+void MessageWidget::calculateDimensionsCreation() {
+ int x = 0;
+
+ int x1 = m_pOw[Uml::A]->getX();
+ int x2 = m_pOw[Uml::B]->getX();
+ int w1 = m_pOw[Uml::A]->getWidth() / 2;
+ int w2 = m_pOw[Uml::B]->getWidth();
+ x1 += w1;
+ if (x1 > x2)
+ x2 += w2;
+
+ int widgetWidth = 0;
+ int widgetHeight = 8;
+ if ( x1 < x2 ) {
+ x = x1;
+ widgetWidth = x2 - x1;
+ } else {
+ x = x2;
+ widgetWidth = x1 - x2;
+ }
+ x += 1;
+ widgetWidth -= 2;
+ m_nPosX = x;
+ m_nY = m_pOw[Uml::B]->getY() + m_pOw[Uml::B]->getHeight() / 2;
+ setSize(widgetWidth, widgetHeight);
+}
+
+void MessageWidget::cleanup() {
+ if (m_pOw[Uml::A]) {
+ disconnect(this, SIGNAL(sigMessageMoved()), m_pOw[Uml::A], SLOT(slotMessageMoved()) );
+ m_pOw[Uml::A]->messageRemoved(this);
+ }
+ if (m_pOw[Uml::B]) {
+ disconnect(this, SIGNAL(sigMessageMoved()), m_pOw[Uml::B], SLOT(slotMessageMoved()) );
+ m_pOw[Uml::B]->messageRemoved(this);
+ }
+
+ UMLWidget::cleanup();
+ if (m_pFText) {
+ m_pView->removeWidget(m_pFText);
+ m_pFText = NULL;
+ }
+}
+
+void MessageWidget::setSelected(bool _select) {
+ UMLWidget::setSelected( _select );
+ if( !m_pFText || m_pFText->getDisplayText().isEmpty())
+ return;
+ if( m_bSelected && m_pFText -> getSelected() )
+ return;
+ if( !m_bSelected && !m_pFText -> getSelected() )
+ return;
+
+ m_pView -> setSelected( m_pFText, 0 );
+ m_pFText -> setSelected( m_bSelected );
+}
+
+int MessageWidget::getMinY() {
+ if (!m_pOw[Uml::A] || !m_pOw[Uml::B]) {
+ return 0;
+ }
+ if (m_sequenceMessageType == Uml::sequence_message_creation) {
+ return m_pOw[Uml::A]->getY() + m_pOw[Uml::A]->getHeight();
+ }
+ int heightA = m_pOw[Uml::A]->getY() + m_pOw[Uml::A]->getHeight();
+ int heightB = m_pOw[Uml::B]->getY() + m_pOw[Uml::B]->getHeight();
+ int height = heightA;
+ if( heightA < heightB ) {
+ height = heightB;
+ }
+ return height;
+}
+
+int MessageWidget::getMaxY() {
+ if( !m_pOw[Uml::A] || !m_pOw[Uml::B] ) {
+ return 0;
+ }
+ int heightA = (int)((ObjectWidget*)m_pOw[Uml::A])->getEndLineY();
+ int heightB = (int)((ObjectWidget*)m_pOw[Uml::B])->getEndLineY();
+ int height = heightA;
+ if( heightA > heightB ) {
+ height = heightB;
+ }
+ return (height - this->height());
+}
+
+void MessageWidget::setWidget(ObjectWidget * ow, Uml::Role_Type role) {
+ m_pOw[role] = ow;
+ updateResizability();
+}
+
+ObjectWidget* MessageWidget::getWidget(Uml::Role_Type role) {
+ return m_pOw[role];
+}
+
+void MessageWidget::saveToXMI( QDomDocument & qDoc, QDomElement & qElement ) {
+ QDomElement messageElement = qDoc.createElement( "messagewidget" );
+ UMLWidget::saveToXMI( qDoc, messageElement );
+ messageElement.setAttribute( "widgetaid", ID2STR(m_pOw[Uml::A]->getLocalID()) );
+ messageElement.setAttribute( "widgetbid", ID2STR(m_pOw[Uml::B]->getLocalID()) );
+ UMLOperation *pOperation = getOperation();
+ if (pOperation)
+ messageElement.setAttribute( "operation", ID2STR(pOperation->getID()) );
+ else
+ messageElement.setAttribute( "operation", m_CustomOp );
+ messageElement.setAttribute( "seqnum", m_SequenceNumber );
+ messageElement.setAttribute( "sequencemessagetype", m_sequenceMessageType );
+
+ // save the corresponding message text
+ if (m_pFText && !m_pFText->getText().isEmpty()) {
+ messageElement.setAttribute( "textid", ID2STR(m_pFText->getID()) );
+ m_pFText -> saveToXMI( qDoc, messageElement );
+ }
+
+ qElement.appendChild( messageElement );
+}
+
+bool MessageWidget::loadFromXMI(QDomElement& qElement) {
+ if ( !UMLWidget::loadFromXMI(qElement) ) {
+ return false;
+ }
+ QString textid = qElement.attribute( "textid", "-1" );
+ QString widgetaid = qElement.attribute( "widgetaid", "-1" );
+ QString widgetbid = qElement.attribute( "widgetbid", "-1" );
+ m_CustomOp = qElement.attribute( "operation", "" );
+ m_SequenceNumber = qElement.attribute( "seqnum", "" );
+ QString sequenceMessageType = qElement.attribute( "sequencemessagetype", "1001" );
+ m_sequenceMessageType = (Uml::Sequence_Message_Type)sequenceMessageType.toInt();
+
+ m_widgetAId = STR2ID(widgetaid);
+ m_widgetBId = STR2ID(widgetbid);
+ m_textId = STR2ID(textid);
+
+ Uml::Text_Role tr = Uml::tr_Seq_Message;
+ if (m_widgetAId == m_widgetBId)
+ tr = Uml::tr_Seq_Message_Self;
+
+ //now load child elements
+ QDomNode node = qElement.firstChild();
+ QDomElement element = node.toElement();
+ if ( !element.isNull() ) {
+ QString tag = element.tagName();
+ if (tag == "floatingtext") {
+ m_pFText = new FloatingTextWidget( m_pView, tr, getOperationText(m_pView), m_textId );
+ if( ! m_pFText->loadFromXMI(element) ) {
+ // Most likely cause: The FloatingTextWidget is empty.
+ delete m_pFText;
+ m_pFText = NULL;
+ }
+ } else {
+ kError() << "MessageWidget::loadFromXMI: unknown tag "
+ << tag << endl;
+ }
+ }
+ return true;
+}
+
+#include "messagewidget.moc"
diff --git a/umbrello/umbrello/messagewidget.h b/umbrello/umbrello/messagewidget.h
new file mode 100644
index 00000000..66f2f639
--- /dev/null
+++ b/umbrello/umbrello/messagewidget.h
@@ -0,0 +1,401 @@
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * copyright (C) 2002-2007 *
+ * Umbrello UML Modeller Authors <uml-devel@uml.sf.net> *
+ ***************************************************************************/
+
+#ifndef MESSAGEWIDGET_H
+#define MESSAGEWIDGET_H
+
+#include "umlwidget.h"
+#include "linkwidget.h"
+
+// forward declarations
+class FloatingTextWidget;
+class ObjectWidget;
+class UMLOperation;
+class MessageWidgetController;
+
+/**
+ * Used to display a message on a sequence diagram. The message
+ * could be between two objects or a message that calls itself on
+ * an object. This class will only display the line that is
+ * required and the text will be setup by the @ref FloatingTextWidget
+ * widget that is passed in the constructor. A message can be
+ * synchronous (calls a method and gains control back on return,
+ * as happens in most programming languages) or asynchronous
+ * (calls a method and gains back control immediately).
+ *
+ * @short Displays a message.
+ * @author Paul Hensgen
+ * @see UMLWidget
+ * @see ObjectWidget
+ * @see FloatingTextWidget
+ * Bugs and comments to uml-devel@lists.sf.net or http://bugs.kde.org
+ */
+class MessageWidget : public UMLWidget, public LinkWidget {
+ Q_OBJECT
+public:
+ friend class MessageWidgetController;
+
+ /**
+ * Constructs a MessageWidget.
+ *
+ * @param view The parent to this class.
+ * @param a The role A widget for this message.
+ * @param b The role B widget for this message.
+ * @param y The vertical position to display this message.
+ * @param sequenceMessageType Whether synchronous or asynchronous
+ * @param id A unique id used for deleting this object cleanly.
+ * The default (-1) will prompt generation of a new ID.
+ */
+ MessageWidget(UMLView * view, ObjectWidget* a, ObjectWidget* b,
+ int y, Uml::Sequence_Message_Type sequenceMessageType,
+ Uml::IDType id = Uml::id_None);
+
+ /**
+ * Constructs a MessageWidget.
+ *
+ * @param view The parent to this class.
+ * @param sequenceMessageType The Uml::Sequence_Message_Type of this message widget
+ * @param id The ID to assign (-1 will prompt a new ID.)
+ */
+ MessageWidget(UMLView * view, Uml::Sequence_Message_Type sequenceMessageType, Uml::IDType id = Uml::id_None);
+
+ /**
+ * Initializes key variables of the class.
+ */
+ void init();
+
+ /**
+ * Standard deconstructor.
+ */
+ virtual ~MessageWidget();
+
+ /**
+ * Write property of QString m_SequenceNumber.
+ */
+ void setSequenceNumber( const QString &sequenceNumber );
+
+ /**
+ * Read property of QString m_SequenceNumber.
+ */
+ QString getSequenceNumber() const;
+
+ /**
+ * Returns whether the message is synchronous or asynchronous
+ */
+ Uml::Sequence_Message_Type getSequenceMessageType() const {
+ return m_sequenceMessageType;
+ }
+
+ /**
+ * Check to see if the given ObjectWidget is involved in the message.
+ *
+ * @param w The ObjectWidget to check for.
+ * @return true - if is contained, false - not contained.
+ */
+ bool contains(ObjectWidget * w);
+
+ /**
+ * Returns the related widget on the given side.
+ *
+ * @return The ObjectWidget we are related to.
+ */
+ ObjectWidget* getWidget(Uml::Role_Type role);
+
+ /**
+ * Sets the related widget on the given side.
+ *
+ * @param ow The ObjectWidget we are related to.
+ * @param role The Uml::Role_Type to be set for the ObjectWidget
+ */
+ void setWidget(ObjectWidget * ow, Uml::Role_Type role) ;
+
+ /**
+ * Returns the text widget it is related to.
+ *
+ * @return The text widget we are related to.
+ */
+ FloatingTextWidget * getFloatingTextWidget() {
+ return m_pFText;
+ }
+
+ /**
+ * Sets the text widget it is related to.
+ *
+ * @param f The text widget we are related to.
+ */
+ void setFloatingTextWidget(FloatingTextWidget * f) {
+ m_pFText = f;
+ }
+
+ /**
+ * Implements operation from LinkWidget.
+ * Required by FloatingTextWidget.
+ */
+ void lwSetFont (QFont font);
+
+ /**
+ * Overrides operation from LinkWidget.
+ * Required by FloatingTextWidget.
+ * @todo Move to LinkWidget.
+ */
+ UMLClassifier *getOperationOwner();
+
+ /**
+ * Implements operation from LinkWidget.
+ * Motivated by FloatingTextWidget.
+ */
+ UMLOperation *getOperation();
+
+ /**
+ * Implements operation from LinkWidget.
+ * Motivated by FloatingTextWidget.
+ */
+ void setOperation(UMLOperation *op);
+
+ /**
+ * Overrides operation from LinkWidget.
+ * Required by FloatingTextWidget.
+ */
+ QString getCustomOpText();
+
+ /**
+ * Overrides operation from LinkWidget.
+ * Required by FloatingTextWidget.
+ */
+ void setCustomOpText(const QString &opText);
+
+ /**
+ * Overrides operation from LinkWidget.
+ * Required by FloatingTextWidget.
+ *
+ * @param ft The text widget which to update.
+ */
+ void setMessageText(FloatingTextWidget *ft);
+
+ /**
+ * Overrides operation from LinkWidget.
+ * Required by FloatingTextWidget.
+ *
+ * @param ft The text widget which to update.
+ * @param newText The new text to set.
+ */
+ void setText(FloatingTextWidget *ft, const QString &newText);
+
+ /**
+ * Overrides operation from LinkWidget.
+ * Required by FloatingTextWidget.
+ *
+ * @param seqNum The new sequence number string to set.
+ * @param op The new operation string to set.
+ */
+ void setSeqNumAndOp(const QString &seqNum, const QString &op);
+
+ /**
+ * Overrides operation from LinkWidget.
+ * Required by FloatingTextWidget.
+ *
+ * @param seqNum Return this MessageWidget's sequence number string.
+ * @param op Return this MessageWidget's operation string.
+ */
+ UMLClassifier * getSeqNumAndOp(QString& seqNum, QString& op);
+
+ /**
+ * Calculate the geometry of the widget.
+ */
+ void calculateWidget();
+
+ /**
+ * Activates a MessageWidget. Connects its m_pOw[] pointers
+ * to UMLObjects and also send signals about its FloatingTextWidget.
+ */
+ bool activate(IDChangeLog * Log = 0);
+
+ /**
+ * Calculates the size of the widget by calling
+ * calculateDimenstionsSynchronous(),
+ * calculateDimenstionsAsynchronous(), or
+ * calculateDimensionsCreation()
+ */
+ void calculateDimensions();
+
+ /**
+ * Calculates and sets the size of the widget for a synchronous message
+ */
+ void calculateDimensionsSynchronous();
+
+ /**
+ * Calculates and sets the size of the widget for an asynchronous message
+ */
+ void calculateDimensionsAsynchronous();
+
+ /**
+ * Calculates and sets the size of the widget for a creation message
+ */
+ void calculateDimensionsCreation();
+
+ /**
+ * Calls drawSynchronous() or drawAsynchronous()
+ */
+ void draw(QPainter& p, int offsetX, int offsetY);
+
+ /**
+ * Draws the calling arrow with filled in arrowhead, the
+ * timeline box and the returning arrow with a dashed line and
+ * stick arrowhead.
+ */
+ void drawSynchronous(QPainter& p, int offsetX, int offsetY);
+
+ /**
+ * Draws a solid arrow line and a stick arrow head.
+ */
+ void drawAsynchronous(QPainter& p, int offsetX, int offsetY);
+
+ /**
+ * Draws a solid arrow line and a stick arrow head to the
+ * edge of the target object widget instead of to the
+ * sequence line.
+ */
+ void drawCreation(QPainter& p, int offsetX, int offsetY);
+
+ /**
+ * Sets the text position relative to the sequence message.
+ */
+ void setTextPosition();
+
+ /**
+ * Constrains the FloatingTextWidget X and Y values supplied.
+ * Overrides operation from LinkWidget.
+ *
+ * @param textX Candidate X value (may be modified by the constraint.)
+ * @param textY Candidate Y value (may be modified by the constraint.)
+ * @param textWidth Width of the text.
+ * @param textHeight Height of the text.
+ * @param tr Uml::Text_Role of the text.
+ */
+ void constrainTextPos(int &textX, int &textY, int textWidth, int textHeight,
+ Uml::Text_Role tr);
+
+ /**
+ * Used to cleanup any other widget it may need to delete.
+ */
+ void cleanup();
+
+ /**
+ * Sets the state of whether the widget is selected.
+ *
+ * @param _select True if the widget is selected.
+ */
+ void setSelected(bool _select);
+
+ /**
+ * Returns the minimum height this widget should be set at on
+ * a sequence diagrams. Takes into account the widget positions
+ * it is related to.
+ */
+ int getMinY();
+
+ /**
+ * Returns the maximum height this widget should be set at on
+ * a sequence diagrams. Takes into account the widget positions
+ * it is related to.
+ */
+ int getMaxY();
+
+ /**
+ * Overrides operation from UMLWidget.
+ *
+ * @param p Point to be checked.
+ *
+ * @return Non-zero if the point is on a part of the MessageWidget.
+ * NB In case of a synchronous message, the empty space
+ * between call line and return line does not count, i.e. if
+ * the point is located in that space the function returns 0.
+ */
+ int onWidget(const QPoint & p);
+
+ /**
+ * Saves to the "messagewidget" XMI element.
+ */
+ void saveToXMI( QDomDocument & qDoc, QDomElement & qElement );
+
+ /**
+ * Loads from the "messagewidget" XMI element.
+ */
+ bool loadFromXMI( QDomElement & qElement );
+
+protected:
+ /**
+ * Shortcut for calling m_pFText->setLink() followed by
+ * this->setTextPosition().
+ */
+ void setLinkAndTextPos();
+
+ /**
+ * Returns the textX arg with constraints applied.
+ * Auxiliary to setTextPosition() and constrainTextPos().
+ */
+ int constrainX(int textX, int textWidth, Uml::Text_Role tr);
+
+ /**
+ * Draw an arrow pointing in the given direction.
+ * The arrow head is not solid, i.e. it is made up of two lines
+ * like so: --->
+ * The direction can be either Qt::LeftArrow or Qt::RightArrow.
+ */
+ static void drawArrow( QPainter& p, int x, int y, int w,
+ Qt::ArrowType direction, bool useDottedLine = false );
+
+ /**
+ * Draw a solid (triangular) arrowhead pointing in the given direction.
+ * The direction can be either Qt::LeftArrow or Qt::RightArrow.
+ */
+ static void drawSolidArrowhead(QPainter& p, int x, int y, Qt::ArrowType direction);
+
+ /**
+ * Update the UMLWidget::m_bResizable flag according to the
+ * charactersitics of this message.
+ */
+ void updateResizability();
+
+ // Data loaded/saved
+ QString m_SequenceNumber;
+ QString m_CustomOp;
+ /**
+ * Whether the message is synchronous or asynchronous
+ */
+ Uml::Sequence_Message_Type m_sequenceMessageType;
+
+private:
+ void moveEvent(QMoveEvent */*m*/);
+ void resizeEvent(QResizeEvent */*re*/);
+
+ ObjectWidget * m_pOw[2];
+ FloatingTextWidget * m_pFText;
+ int m_nY;
+ /**
+ * The following variables are used by loadFromXMI() as an intermediate
+ * store. activate() resolves the IDs, i.e. after activate() the variables
+ * m_pOw[] and m_pFText can be used.
+ */
+ Uml::IDType m_widgetAId, m_widgetBId, m_textId;
+
+public slots:
+ void slotWidgetMoved(Uml::IDType id);
+ void slotMenuSelection(int sel);
+signals:
+ /**
+ * emitted when the message widget is moved up or down
+ * slots into ObjectWidget::slotMessageMoved()
+ */
+ void sigMessageMoved();
+};
+
+#endif
diff --git a/umbrello/umbrello/messagewidgetcontroller.cpp b/umbrello/umbrello/messagewidgetcontroller.cpp
new file mode 100644
index 00000000..8ffac822
--- /dev/null
+++ b/umbrello/umbrello/messagewidgetcontroller.cpp
@@ -0,0 +1,96 @@
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * copyright (C) 2006-2007 *
+ * Umbrello UML Modeller Authors <uml-devel@uml.sf.net> *
+ ***************************************************************************/
+
+// own header
+#include "messagewidgetcontroller.h"
+
+// kde includes
+#include <kcursor.h>
+#include <kdebug.h>
+
+// app includes
+#include "messagewidget.h"
+#include "floatingtextwidget.h"
+#include "objectwidget.h"
+#include "listpopupmenu.h"
+
+MessageWidgetController::MessageWidgetController(MessageWidget* messageWidget):
+ UMLWidgetController(messageWidget) {
+ m_messageWidget = messageWidget;
+ m_unconstrainedPositionY = 0;
+}
+
+MessageWidgetController::~MessageWidgetController() {
+}
+
+void MessageWidgetController::saveWidgetValues(QMouseEvent *me) {
+ UMLWidgetController::saveWidgetValues(me);
+
+ m_unconstrainedPositionY = m_widget->getY();
+}
+
+QCursor MessageWidgetController::getResizeCursor() {
+ return KCursor::sizeVerCursor();
+}
+
+void MessageWidgetController::resizeWidget(int newW, int newH) {
+ m_messageWidget->setSize(m_messageWidget->width(), newH);
+ emit m_messageWidget->sigMessageMoved();
+}
+
+void MessageWidgetController::moveWidgetBy(int diffX, int diffY) {
+ m_unconstrainedPositionY += diffY;
+ int newY = constrainPositionY(diffY);
+
+ if (m_unconstrainedPositionY != newY) {
+ if (m_unconstrainedPositionY > m_messageWidget->getY()) {
+ newY = m_unconstrainedPositionY;
+ } else {
+ return;
+ }
+ }
+
+ m_messageWidget->setY(newY);
+
+ if (m_messageWidget->m_sequenceMessageType == Uml::sequence_message_creation) {
+ const int objWidgetHalfHeight = m_messageWidget->m_pOw[Uml::B]->getHeight() / 2;
+ m_messageWidget->m_pOw[Uml::B]->UMLWidget::setY(newY - objWidgetHalfHeight);
+ }
+
+ m_messageWidget->moveEvent(0);
+}
+
+void MessageWidgetController::constrainMovementForAllWidgets(int &diffX, int &diffY) {
+ diffX = 0;
+ diffY = constrainPositionY(diffY) - m_widget->getY();
+}
+
+void MessageWidgetController::doMouseDoubleClick(QMouseEvent *me) {
+ if (m_messageWidget->m_pFText != NULL) {
+ m_messageWidget->m_pFText->slotMenuSelection(ListPopupMenu::mt_Select_Operation);
+ }
+}
+
+int MessageWidgetController::constrainPositionY(int diffY) {
+ int newY = m_widget->getY() + diffY;
+
+ int minY = m_messageWidget->getMinY();
+ if (m_messageWidget->m_pFText && !m_messageWidget->m_pFText->getDisplayText().isEmpty()) {
+ minY += m_messageWidget->m_pFText->getHeight();
+ }
+
+ if (newY < minY) {
+ newY = minY;
+ }
+
+ return newY;
+}
+
diff --git a/umbrello/umbrello/messagewidgetcontroller.h b/umbrello/umbrello/messagewidgetcontroller.h
new file mode 100644
index 00000000..921fd2bf
--- /dev/null
+++ b/umbrello/umbrello/messagewidgetcontroller.h
@@ -0,0 +1,154 @@
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * copyright (C) 2006 *
+ * Umbrello UML Modeller Authors <uml-devel@uml.sf.net> *
+ ***************************************************************************/
+
+#ifndef MESSAGEWIDGETCONTROLLER_H
+#define MESSAGEWIDGETCONTROLLER_H
+
+#include "umlwidgetcontroller.h"
+
+class MessageWidget;
+
+/**
+ * Controller for MessageWidget.
+ *
+ * When moving a MessageWidget, it is only moved along Y axis. X axis movement
+ * is always ignored.
+ * So, if the MessageWidget is being moved as part of a selection and that
+ * selection is moved in X and/or Y axis, the MessageWidget will only move in
+ * Y axis. Another constrain is applied in Y axis, so the message doesn't pass
+ * over the related object widgets. Due to this constrain, the vertical
+ * position the message would have if it wasn't constrained is calculated, so
+ * when the widget lowers the position where it was constrained it begins to
+ * move again.
+ * Also, when constraining the move of the selection because the receiver of
+ * mouse move events is a MessageWidget, all the widgets are moved only in Y
+ * axis. Another constrain is applied in Y axis, so the message doesn't pass
+ * over the related object widgets. The unconstrained position isn't need here,
+ * because the message widget is the receiver of the events, so when the cursor
+ * goes lower than where it was constrained it begins to lower automatically.
+ *
+ * Creation messages take care of moving the object created when they're moved.
+ *
+ * Only vertical resize is allowed for MessageWidget. Cursor is set to reflect
+ * this.
+ *
+ * Double click shows the dialog to select the operation of the message.
+ *
+ * @author Umbrello UML Modeller Authors <uml-devel@lists.sourceforge.net>
+ */
+class MessageWidgetController : public UMLWidgetController {
+public:
+
+ /**
+ * Constructor for MessageWidgetController.
+ *
+ * @param messageWidget The message widget which uses the controller.
+ */
+ MessageWidgetController(MessageWidget* messageWidget);
+
+ /**
+ * Destructor for MessageWidgetController.
+ */
+ ~MessageWidgetController();
+
+protected:
+
+ /**
+ * Overriden from UMLWidgetController.
+ * Saves the values of the widget needed for move/resize.
+ * Calls parent method and then saves the value of m_unconstrainedPositionY
+ *
+ * @param me The QMouseEvent to get the offset from.
+ */
+ virtual void saveWidgetValues(QMouseEvent *me);
+
+ /**
+ * Overriden from UMLWidgetController.
+ * Returns the cursor to be shown when resizing the widget.
+ * The cursor shown is KCursor::sizeVerCursor().
+ *
+ * @return The cursor to be shown when resizing the widget.
+ */
+ virtual QCursor getResizeCursor();
+
+ /**
+ * Overriden from UMLWidgetController.
+ * Resizes the height of the message widget and emits the message moved signal.
+ * Message widgets can only be resized vertically, so width isn't modified.
+ *
+ * @param newW The new width for the widget (isn't used).
+ * @param newH The new height for the widget.
+ */
+ virtual void resizeWidget(int newW, int newH);
+
+ /**
+ * Overriden from UMLWidgetController.
+ * Moves the widget to a new position using the difference between the
+ * current position and the new position. X position is ignored, and widget
+ * is only moved along Y axis. If message goes upper than the object, it's
+ * kept at this position until it should be lowered again (the unconstrained
+ * Y position is saved to know when it's the time to lower it again).
+ * If the message is a creation message, the object created is also moved to
+ * the new vertical position.
+ * @see constrainPositionY
+ *
+ * @param diffX The difference between current X position and new X position
+ * (isn't used).
+ * @param diffY The difference between current Y position and new Y position.
+ */
+ virtual void moveWidgetBy(int diffX, int diffY);
+
+ /**
+ * Overriden from UMLWidgetController.
+ * Modifies the value of the diffX and diffY variables used to move the widgets.
+ * All the widgets are constrained to be moved only in Y axis (diffX is set to 0).
+ * @see constrainPositionY
+ *
+ * @param diffX The difference between current X position and new X position.
+ * @param diffY The difference between current Y position and new Y position.
+ */
+ virtual void constrainMovementForAllWidgets(int &diffX, int &diffY);
+
+ /**
+ * Overriden from UMLWidgetController.
+ * Executes the action for double click in the widget.
+ * Shows the dialog to select the operation of the message.
+ *
+ * @param me The QMouseEvent which triggered the double click event.
+ */
+ virtual void doMouseDoubleClick(QMouseEvent *me);
+
+private:
+
+ /**
+ * Constrains the vertical position of the message widget so it doesn't go
+ * upper than the bottom side of the lower object.
+ * The height of the floating text widget in the message is taken in account
+ * if there is any and isn't empty.
+ *
+ * @param diffY The difference between current Y position and new Y position.
+ * @return The new Y position, constrained.
+ */
+ int constrainPositionY(int diffY);
+
+ /**
+ * The message widget which uses the controller.
+ */
+ MessageWidget *m_messageWidget;
+
+ /**
+ * The vertical position the widget would have if its move wasn't constrained.
+ */
+ int m_unconstrainedPositionY;
+
+};
+
+#endif
diff --git a/umbrello/umbrello/messagewidgetlist.h b/umbrello/umbrello/messagewidgetlist.h
new file mode 100644
index 00000000..559a4cf7
--- /dev/null
+++ b/umbrello/umbrello/messagewidgetlist.h
@@ -0,0 +1,22 @@
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * copyright (C) 2003-2007 *
+ * Umbrello UML Modeller Authors <uml-devel@uml.sf.net> *
+ ***************************************************************************/
+
+#ifndef MESSAGEWIDGETLIST_H
+#define MESSAGEWIDGETLIST_H
+
+#include <qptrlist.h>
+
+class MessageWidget;
+
+typedef QPtrList<MessageWidget> MessageWidgetList;
+typedef QPtrListIterator<MessageWidget> MessageWidgetListIt;
+
+#endif
diff --git a/umbrello/umbrello/model_utils.cpp b/umbrello/umbrello/model_utils.cpp
new file mode 100644
index 00000000..89e1cf33
--- /dev/null
+++ b/umbrello/umbrello/model_utils.cpp
@@ -0,0 +1,1221 @@
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * copyright (C) 2004-2006 *
+ * Umbrello UML Modeller Authors <uml-devel@uml.sf.net> *
+ ***************************************************************************/
+
+// own header
+#include "model_utils.h"
+
+// qt/kde includes
+#include <qregexp.h>
+#include <qstringlist.h>
+#include <klocale.h>
+#include <kdebug.h>
+#include <kinputdialog.h>
+
+// app includes
+#include "umlobject.h"
+#include "umlpackagelist.h"
+#include "package.h"
+#include "folder.h"
+#include "classifier.h"
+#include "enum.h"
+#include "entity.h"
+#include "template.h"
+#include "operation.h"
+#include "attribute.h"
+#include "association.h"
+#include "umlrole.h"
+#include "umldoc.h"
+#include "uml.h"
+#include "codegenerator.h"
+
+namespace Model_Utils {
+
+bool isCloneable(Uml::Widget_Type type) {
+ switch (type) {
+ case Uml::wt_Actor:
+ case Uml::wt_UseCase:
+ case Uml::wt_Class:
+ case Uml::wt_Interface:
+ case Uml::wt_Enum:
+ case Uml::wt_Datatype:
+ case Uml::wt_Package:
+ case Uml::wt_Component:
+ case Uml::wt_Node:
+ case Uml::wt_Artifact:
+ return true;
+ default:
+ return false;
+ }
+}
+
+UMLObject * findObjectInList(Uml::IDType id, const UMLObjectList& inList) {
+ for (UMLObjectListIt oit(inList); oit.current(); ++oit) {
+ UMLObject *obj = oit.current();
+ if (obj->getID() == id)
+ return obj;
+ UMLObject *o;
+ Uml::Object_Type t = obj->getBaseType();
+ switch (t) {
+ case Uml::ot_Folder:
+ case Uml::ot_Package:
+ case Uml::ot_Component:
+ o = static_cast<UMLPackage*>(obj)->findObjectById(id);
+ if (o)
+ return o;
+ break;
+ case Uml::ot_Interface:
+ case Uml::ot_Class:
+ case Uml::ot_Enum:
+ case Uml::ot_Entity:
+ o = static_cast<UMLClassifier*>(obj)->findChildObjectById(id);
+ if (o == NULL &&
+ (t == Uml::ot_Interface || t == Uml::ot_Class))
+ o = ((UMLPackage*)obj)->findObjectById(id);
+ if (o)
+ return o;
+ break;
+ case Uml::ot_Association:
+ {
+ UMLAssociation *assoc = static_cast<UMLAssociation*>(obj);
+ UMLRole *rA = assoc->getUMLRole(Uml::A);
+ if (rA->getID() == id)
+ return rA;
+ UMLRole *rB = assoc->getUMLRole(Uml::B);
+ if (rB->getID() == id)
+ return rB;
+ }
+ break;
+ default:
+ break;
+ }
+ }
+ return NULL;
+}
+
+UMLObject* findUMLObject(const UMLObjectList& inList,
+ const QString& inName,
+ Uml::Object_Type type /* = ot_UMLObject */,
+ UMLObject *currentObj /* = NULL */) {
+ const bool caseSensitive = UMLApp::app()->activeLanguageIsCaseSensitive();
+ QString name = inName;
+ QStringList components;
+#ifdef TRY_BUGFIX_120682
+ // If we have a pointer or a reference in cpp we need to remove
+ // the asterisks and ampersands in order to find the appropriate object
+ if (UMLApp::app()->getActiveLanguage() == Uml::pl_Cpp) {
+ if (name.endsWith("*"))
+ name.remove("*");
+ else if (name.contains("&"))
+ name.remove("&");
+ }
+#endif
+ QString nameWithoutFirstPrefix;
+ if (name.contains("::"))
+ components = QStringList::split("::", name);
+ else if (name.contains("."))
+ components = QStringList::split(".", name);
+ if (components.size() > 1) {
+ name = components.front();
+ components.pop_front();
+ nameWithoutFirstPrefix = components.join("::");
+ }
+ if (currentObj) {
+ UMLPackage *pkg = NULL;
+ if (dynamic_cast<UMLClassifierListItem*>(currentObj)) {
+ currentObj = static_cast<UMLObject*>(currentObj->parent());
+ }
+ pkg = dynamic_cast<UMLPackage*>(currentObj);
+ if (pkg == NULL)
+ pkg = currentObj->getUMLPackage();
+ // Remember packages that we've seen - for avoiding cycles.
+ UMLPackageList seenPkgs;
+ for (; pkg; pkg = currentObj->getUMLPackage()) {
+ if (nameWithoutFirstPrefix.isEmpty()) {
+ if (caseSensitive) {
+ if (pkg->getName() == name)
+ return pkg;
+ } else if (pkg->getName().lower() == name.lower()) {
+ return pkg;
+ }
+ }
+ if (seenPkgs.findRef(pkg) != -1) {
+ kError() << "findUMLObject(" << name << "): "
+ << "breaking out of cycle involving "
+ << pkg->getName() << endl;
+ break;
+ }
+ seenPkgs.append(pkg);
+ UMLObjectList objectsInCurrentScope = pkg->containedObjects();
+ for (UMLObjectListIt oit(objectsInCurrentScope); oit.current(); ++oit) {
+ UMLObject *obj = oit.current();
+ if (caseSensitive) {
+ if (obj->getName() != name)
+ continue;
+ } else if (obj->getName().lower() != name.lower()) {
+ continue;
+ }
+ Uml::Object_Type foundType = obj->getBaseType();
+ if (nameWithoutFirstPrefix.isEmpty()) {
+ if (type != Uml::ot_UMLObject && type != foundType) {
+ kDebug() << "findUMLObject: type mismatch for "
+ << name << " (seeking type: "
+ << type << ", found type: "
+ << foundType << ")" << endl;
+ // Class, Interface, and Datatype are all Classifiers
+ // and are considered equivalent.
+ // The caller must be prepared to handle possible mismatches.
+ if ((type == Uml::ot_Class ||
+ type == Uml::ot_Interface ||
+ type == Uml::ot_Datatype) &&
+ (foundType == Uml::ot_Class ||
+ foundType == Uml::ot_Interface ||
+ foundType == Uml::ot_Datatype)) {
+ return obj;
+ }
+ continue;
+ }
+ return obj;
+ }
+ if (foundType != Uml::ot_Package &&
+ foundType != Uml::ot_Folder &&
+ foundType != Uml::ot_Class &&
+ foundType != Uml::ot_Interface &&
+ foundType != Uml::ot_Component) {
+ kDebug() << "findUMLObject: found \"" << name
+ << "\" is not a package (?)" << endl;
+ continue;
+ }
+ UMLPackage *pkg = static_cast<UMLPackage*>(obj);
+ return findUMLObject( pkg->containedObjects(),
+ nameWithoutFirstPrefix, type );
+ }
+ currentObj = pkg;
+ }
+ }
+ for (UMLObjectListIt oit(inList); oit.current(); ++oit) {
+ UMLObject *obj = oit.current();
+ if (caseSensitive) {
+ if (obj->getName() != name)
+ continue;
+ } else if (obj->getName().lower() != name.lower()) {
+ continue;
+ }
+ Uml::Object_Type foundType = obj->getBaseType();
+ if (nameWithoutFirstPrefix.isEmpty()) {
+ if (type != Uml::ot_UMLObject && type != foundType) {
+ kDebug() << "findUMLObject: type mismatch for "
+ << name << " (seeking type: "
+ << type << ", found type: "
+ << foundType << ")" << endl;
+ continue;
+ }
+ return obj;
+ }
+ if (foundType != Uml::ot_Package &&
+ foundType != Uml::ot_Folder &&
+ foundType != Uml::ot_Class &&
+ foundType != Uml::ot_Interface &&
+ foundType != Uml::ot_Component) {
+ kDebug() << "findUMLObject: found \"" << name
+ << "\" is not a package (?)" << endl;
+ continue;
+ }
+ UMLPackage *pkg = static_cast<UMLPackage*>(obj);
+ return findUMLObject( pkg->containedObjects(),
+ nameWithoutFirstPrefix, type );
+ }
+ return NULL;
+}
+
+QString uniqObjectName(Uml::Object_Type type, UMLPackage *parentPkg, QString prefix) {
+ QString currentName = prefix;
+ if (currentName.isEmpty()) {
+ if(type == Uml::ot_Class)
+ currentName = i18n("new_class");
+ else if(type == Uml::ot_Actor)
+ currentName = i18n("new_actor");
+ else if(type == Uml::ot_UseCase)
+ currentName = i18n("new_usecase");
+ else if(type == Uml::ot_Package)
+ currentName = i18n("new_package");
+ else if(type == Uml::ot_Component)
+ currentName = i18n("new_component");
+ else if(type == Uml::ot_Node)
+ currentName = i18n("new_node");
+ else if(type == Uml::ot_Artifact)
+ currentName = i18n("new_artifact");
+ else if(type == Uml::ot_Interface)
+ currentName = i18n("new_interface");
+ else if(type == Uml::ot_Datatype)
+ currentName = i18n("new_datatype");
+ else if(type == Uml::ot_Enum)
+ currentName = i18n("new_enum");
+ else if(type == Uml::ot_Entity)
+ currentName = i18n("new_entity");
+ else if(type == Uml::ot_Folder)
+ currentName = i18n("new_folder");
+ else if(type == Uml::ot_Association)
+ currentName = i18n("new_association");
+ else {
+ currentName = i18n("new_object");
+ kWarning() << "unknown object type in umldoc::uniqObjectName()" << endl;
+ }
+ }
+ UMLDoc *doc = UMLApp::app()->getDocument();
+ QString name = currentName;
+ for (int number = 1; !doc->isUnique(name, parentPkg); number++) {
+ name = currentName + '_' + QString::number(number);
+ }
+ return name;
+}
+
+bool isCommonXMIAttribute( const QString &tag ) {
+ bool retval = (Uml::tagEq(tag, "name") ||
+ Uml::tagEq(tag, "visibility") ||
+ Uml::tagEq(tag, "isRoot") ||
+ Uml::tagEq(tag, "isLeaf") ||
+ Uml::tagEq(tag, "isAbstract") ||
+ Uml::tagEq(tag, "isSpecification") ||
+ Uml::tagEq(tag, "isActive") ||
+ Uml::tagEq(tag, "namespace") ||
+ Uml::tagEq(tag, "ownerScope") ||
+ Uml::tagEq(tag, "ModelElement.stereotype") ||
+ Uml::tagEq(tag, "GeneralizableElement.generalization") ||
+ Uml::tagEq(tag, "specialization") || //NYI
+ Uml::tagEq(tag, "clientDependency") || //NYI
+ Uml::tagEq(tag, "supplierDependency") //NYI
+ );
+ return retval;
+}
+
+bool isCommonDataType(QString type) {
+ CodeGenerator *gen = UMLApp::app()->getGenerator();
+ if (gen == NULL)
+ return false;
+ const bool caseSensitive = UMLApp::app()->activeLanguageIsCaseSensitive();
+ QStringList dataTypes = gen->defaultDatatypes();
+ QStringList::Iterator end(dataTypes.end());
+ for (QStringList::Iterator it = dataTypes.begin(); it != end; ++it) {
+ if (caseSensitive) {
+ if (type == *it)
+ return true;
+ } else if (type.lower() == (*it).lower()) {
+ return true;
+ }
+ }
+ return false;
+}
+
+bool isClassifierListitem(Uml::Object_Type type) {
+ if (type == Uml::ot_Attribute ||
+ type == Uml::ot_Operation ||
+ type == Uml::ot_Template ||
+ type == Uml::ot_EntityAttribute ||
+ type == Uml::ot_EnumLiteral) {
+ return true;
+ } else {
+ return false;
+ }
+}
+
+Uml::Model_Type guessContainer(UMLObject *o) {
+ Uml::Object_Type ot = o->getBaseType();
+ if (ot == Uml::ot_Package && o->getStereotype() == "subsystem")
+ return Uml::mt_Component;
+ Uml::Model_Type mt = Uml::N_MODELTYPES;
+ switch (ot) {
+ case Uml::ot_Package: // CHECK: packages may appear in other views?
+ case Uml::ot_Interface:
+ case Uml::ot_Datatype:
+ case Uml::ot_Enum:
+ case Uml::ot_Class:
+ case Uml::ot_Attribute:
+ case Uml::ot_Operation:
+ case Uml::ot_EnumLiteral:
+ case Uml::ot_Template:
+ mt = Uml::mt_Logical;
+ break;
+ case Uml::ot_Actor:
+ case Uml::ot_UseCase:
+ mt = Uml::mt_UseCase;
+ break;
+ case Uml::ot_Component:
+ case Uml::ot_Artifact: // trouble: artifact can also appear at Deployment
+ mt = Uml::mt_Component;
+ break;
+ case Uml::ot_Node:
+ mt = Uml::mt_Deployment;
+ break;
+ case Uml::ot_Entity:
+ case Uml::ot_EntityAttribute:
+ mt = Uml::mt_EntityRelationship;
+ break;
+ case Uml::ot_Association:
+ {
+ UMLAssociation *assoc = static_cast<UMLAssociation*>(o);
+ UMLDoc *umldoc = UMLApp::app()->getDocument();
+ for (int r = Uml::A; r <= Uml::B; r++) {
+ UMLObject *roleObj = assoc->getObject((Uml::Role_Type)r);
+ if (roleObj == NULL) {
+ // Ouch! we have been called while types are not yet resolved
+ return Uml::N_MODELTYPES;
+ }
+ UMLPackage *pkg = roleObj->getUMLPackage();
+ if (pkg) {
+ while (pkg->getUMLPackage()) { // wind back to root
+ pkg = pkg->getUMLPackage();
+ }
+ const Uml::Model_Type m = umldoc->rootFolderType(pkg);
+ if (m != Uml::N_MODELTYPES)
+ return m;
+ }
+ mt = guessContainer(roleObj);
+ if (mt != Uml::mt_Logical)
+ break;
+ }
+ }
+ break;
+ default:
+ break;
+ }
+ return mt;
+}
+
+int stringToDirection(QString input, Uml::Parameter_Direction & result) {
+ QRegExp dirx("^(in|out|inout)");
+ int pos = dirx.search(input);
+ if (pos == -1)
+ return 0;
+ const QString& dirStr = dirx.capturedTexts().first();
+ uint dirLen = dirStr.length();
+ if (input.length() > dirLen && !input[dirLen].isSpace())
+ return 0; // no match after all.
+ if (dirStr == "out")
+ result = Uml::pd_Out;
+ else if (dirStr == "inout")
+ result = Uml::pd_InOut;
+ else
+ result = Uml::pd_In;
+ return dirLen;
+}
+
+Parse_Status parseTemplate(QString t, NameAndType& nmTp, UMLClassifier *owningScope) {
+
+ UMLDoc *pDoc = UMLApp::app()->getDocument();
+
+ t = t.stripWhiteSpace();
+ if (t.isEmpty())
+ return PS_Empty;
+
+ QStringList nameAndType = QStringList::split( QRegExp("\\s*:\\s*"), t);
+ if (nameAndType.count() == 2) {
+ UMLObject *pType = NULL;
+ if (nameAndType[1] != "class") {
+ pType = pDoc->findUMLObject(nameAndType[1], Uml::ot_UMLObject, owningScope);
+ if (pType == NULL)
+ return PS_Unknown_ArgType;
+ }
+ nmTp = NameAndType(nameAndType[0], pType);
+ } else {
+ nmTp = NameAndType(t, NULL);
+ }
+ return PS_OK;
+}
+
+Parse_Status parseAttribute(QString a, NameAndType& nmTp, UMLClassifier *owningScope,
+ Uml::Visibility *vis /* = 0 */) {
+ UMLDoc *pDoc = UMLApp::app()->getDocument();
+
+ a = a.simplifyWhiteSpace();
+ if (a.isEmpty())
+ return PS_Empty;
+
+ int colonPos = a.find(':');
+ if (colonPos < 0) {
+ nmTp = NameAndType(a, NULL);
+ return PS_OK;
+ }
+ QString name = a.left(colonPos).stripWhiteSpace();
+ if (vis) {
+ QRegExp mnemonicVis("^([\\+\\#\\-\\~] *)");
+ int pos = mnemonicVis.search(name);
+ if (pos == -1) {
+ *vis = Uml::Visibility::Private; // default value
+ } else {
+ QString caption = mnemonicVis.cap(1);
+ QString strVis = caption.left(1);
+ if (strVis == "+")
+ *vis = Uml::Visibility::Public;
+ else if (strVis == "#")
+ *vis = Uml::Visibility::Protected;
+ else if (strVis == "-")
+ *vis = Uml::Visibility::Private;
+ else
+ *vis = Uml::Visibility::Implementation;
+ }
+ name.remove(mnemonicVis);
+ }
+ Uml::Parameter_Direction pd = Uml::pd_In;
+ if (name.startsWith("in ")) {
+ pd = Uml::pd_In;
+ name = name.mid(3);
+ } else if (name.startsWith("inout ")) {
+ pd = Uml::pd_InOut;
+ name = name.mid(6);
+ } else if (name.startsWith("out ")) {
+ pd = Uml::pd_Out;
+ name = name.mid(4);
+ }
+ a = a.mid(colonPos + 1).stripWhiteSpace();
+ if (a.isEmpty()) {
+ nmTp = NameAndType(name, NULL, pd);
+ return PS_OK;
+ }
+ QStringList typeAndInitialValue = QStringList::split( QRegExp("\\s*=\\s*"), a );
+ const QString &type = typeAndInitialValue[0];
+ UMLObject *pType = pDoc->findUMLObject(type, Uml::ot_UMLObject, owningScope);
+ if (pType == NULL) {
+ nmTp = NameAndType(name, NULL, pd);
+ return PS_Unknown_ArgType;
+ }
+ QString initialValue;
+ if (typeAndInitialValue.count() == 2) {
+ initialValue = typeAndInitialValue[1];
+ }
+ nmTp = NameAndType(name, pType, pd, initialValue);
+ return PS_OK;
+}
+
+Parse_Status parseOperation(QString m, OpDescriptor& desc, UMLClassifier *owningScope) {
+ UMLDoc *pDoc = UMLApp::app()->getDocument();
+
+ m = m.simplifyWhiteSpace();
+ if (m.isEmpty())
+ return PS_Empty;
+ if (m.contains(QRegExp("operator *()"))) {
+ // C++ special case: two sets of parentheses
+ desc.m_name = "operator()";
+ m.remove(QRegExp("operator *()"));
+ } else {
+ /**
+ * The search pattern includes everything up to the opening parenthesis
+ * because UML also permits non programming-language oriented designs
+ * using narrative names, for example "check water temperature".
+ */
+ QRegExp beginningUpToOpenParenth( "^([^\\(]+)" );
+ int pos = beginningUpToOpenParenth.search(m);
+ if (pos == -1)
+ return PS_Illegal_MethodName;
+ desc.m_name = beginningUpToOpenParenth.cap(1);
+ }
+ desc.m_pReturnType = NULL;
+ QRegExp pat = QRegExp("\\) *:(.*)$");
+ int pos = pat.search(m);
+ if (pos != -1) { // return type is optional
+ QString retType = pat.cap(1);
+ retType = retType.stripWhiteSpace();
+ if (retType != "void") {
+ UMLObject *pRetType = owningScope->findTemplate(retType);
+ if (pRetType == NULL) {
+ pRetType = pDoc->findUMLObject(retType, Uml::ot_UMLObject, owningScope);
+ if (pRetType == NULL)
+ return PS_Unknown_ReturnType;
+ }
+ desc.m_pReturnType = pRetType;
+ }
+ }
+ // Remove possible empty parentheses ()
+ m.remove( QRegExp("\\s*\\(\\s*\\)") );
+ desc.m_args.clear();
+ pat = QRegExp( "\\((.*)\\)" );
+ pos = pat.search(m);
+ if (pos == -1) // argument list is optional
+ return PS_OK;
+ QString arglist = pat.cap(1);
+ arglist = arglist.stripWhiteSpace();
+ if (arglist.isEmpty())
+ return PS_OK;
+ QStringList args = QStringList::split( QRegExp("\\s*,\\s*"), arglist);
+ for (QStringList::Iterator lit = args.begin(); lit != args.end(); ++lit) {
+ NameAndType nmTp;
+ Parse_Status ps = parseAttribute(*lit, nmTp, owningScope);
+ if (ps)
+ return ps;
+ desc.m_args.append(nmTp);
+ }
+ return PS_OK;
+}
+
+QString psText(Parse_Status value) {
+ const QString text[] = {
+ i18n("OK"), i18n("Empty"), i18n("Malformed argument"),
+ i18n("Unknown argument type"), i18n("Illegal method name"),
+ i18n("Unknown return type"), i18n("Unspecified error")
+ };
+ return text[(unsigned) value];
+}
+
+QString progLangToString(Uml::Programming_Language pl) {
+ switch (pl) {
+ case Uml::pl_ActionScript:
+ return "ActionScript";
+ case Uml::pl_Ada:
+ return "Ada";
+ case Uml::pl_Cpp:
+ return "C++";
+ case Uml::pl_CSharp:
+ return "C#";
+ case Uml::pl_D:
+ return "D";
+ case Uml::pl_IDL:
+ return "IDL";
+ case Uml::pl_Java:
+ return "Java";
+ case Uml::pl_JavaScript:
+ return "JavaScript";
+ case Uml::pl_Pascal:
+ return "Pascal";
+ case Uml::pl_Perl:
+ return "Perl";
+ case Uml::pl_PHP:
+ return "PHP";
+ case Uml::pl_PHP5:
+ return "PHP5";
+ case Uml::pl_Python:
+ return "Python";
+ case Uml::pl_Ruby:
+ return "Ruby";
+ case Uml::pl_SQL:
+ return "SQL";
+ case Uml::pl_Tcl:
+ return "Tcl";
+ case Uml::pl_XMLSchema:
+ return "XMLSchema";
+ default:
+ break;
+ }
+ return QString::null;
+}
+
+Uml::Programming_Language stringToProgLang(QString str) {
+ if (str == "ActionScript")
+ return Uml::pl_ActionScript;
+ if (str == "Ada")
+ return Uml::pl_Ada;
+ if (str == "C++" || str == "Cpp") // "Cpp" only for bkwd compatibility
+ return Uml::pl_Cpp;
+ if (str == "C#")
+ return Uml::pl_CSharp;
+ if (str == "D")
+ return Uml::pl_D;
+ if (str == "IDL")
+ return Uml::pl_IDL;
+ if (str == "Java")
+ return Uml::pl_Java;
+ if (str == "JavaScript")
+ return Uml::pl_JavaScript;
+ if (str == "Pascal")
+ return Uml::pl_Pascal;
+ if (str == "Perl")
+ return Uml::pl_Perl;
+ if (str == "PHP")
+ return Uml::pl_PHP;
+ if (str == "PHP5")
+ return Uml::pl_PHP5;
+ if (str == "Python")
+ return Uml::pl_Python;
+ if (str == "Ruby")
+ return Uml::pl_Ruby;
+ if (str == "SQL")
+ return Uml::pl_SQL;
+ if (str == "Tcl")
+ return Uml::pl_Tcl;
+ if (str == "XMLSchema")
+ return Uml::pl_XMLSchema;
+ return Uml::pl_Reserved;
+}
+
+bool typeIsRootView(Uml::ListView_Type type) {
+ switch (type) {
+ case Uml::lvt_View:
+ case Uml::lvt_Logical_View:
+ case Uml::lvt_UseCase_View:
+ case Uml::lvt_Component_View:
+ case Uml::lvt_Deployment_View:
+ case Uml::lvt_EntityRelationship_Model:
+ return true;
+ break;
+ default:
+ break;
+ }
+ return false;
+}
+
+bool typeIsCanvasWidget(Uml::ListView_Type type) {
+ switch (type) {
+ case Uml::lvt_Actor:
+ case Uml::lvt_UseCase:
+ case Uml::lvt_Class:
+ case Uml::lvt_Package:
+ case Uml::lvt_Logical_Folder:
+ case Uml::lvt_UseCase_Folder:
+ case Uml::lvt_Component_Folder:
+ case Uml::lvt_Deployment_Folder:
+ case Uml::lvt_EntityRelationship_Folder:
+ case Uml::lvt_Subsystem:
+ case Uml::lvt_Component:
+ case Uml::lvt_Node:
+ case Uml::lvt_Artifact:
+ case Uml::lvt_Interface:
+ case Uml::lvt_Datatype:
+ case Uml::lvt_Enum:
+ case Uml::lvt_Entity:
+ return true;
+ break;
+ default:
+ break;
+ }
+ return false;
+}
+
+bool typeIsFolder(Uml::ListView_Type type) {
+ if (typeIsRootView(type) ||
+ type == Uml::lvt_Datatype_Folder ||
+ type == Uml::lvt_Logical_Folder ||
+ type == Uml::lvt_UseCase_Folder ||
+ type == Uml::lvt_Component_Folder ||
+ type == Uml::lvt_Deployment_Folder ||
+ type == Uml::lvt_EntityRelationship_Folder) {
+ return true;
+ } else {
+ return false;
+ }
+}
+
+bool typeIsContainer(Uml::ListView_Type type) {
+ if (typeIsFolder(type))
+ return true;
+ return (type == Uml::lvt_Package ||
+ type == Uml::lvt_Subsystem ||
+ type == Uml::lvt_Component);
+}
+
+bool typeIsClassifierList(Uml::ListView_Type type) {
+ if (type == Uml::lvt_Attribute ||
+ type == Uml::lvt_Operation ||
+ type == Uml::lvt_Template ||
+ type == Uml::lvt_EntityAttribute ||
+ type == Uml::lvt_EnumLiteral) {
+ return true;
+ } else {
+ return false;
+ }
+}
+
+bool typeIsDiagram(Uml::ListView_Type type) {
+ if (type == Uml::lvt_Class_Diagram ||
+ type == Uml::lvt_Collaboration_Diagram ||
+ type == Uml::lvt_State_Diagram ||
+ type == Uml::lvt_Activity_Diagram ||
+ type == Uml::lvt_Sequence_Diagram ||
+ type == Uml::lvt_UseCase_Diagram ||
+ type == Uml::lvt_Component_Diagram ||
+ type == Uml::lvt_Deployment_Diagram ||
+ type == Uml::lvt_EntityRelationship_Diagram) {
+ return true;
+ } else {
+ return false;
+ }
+}
+
+Uml::Model_Type convert_DT_MT(Uml::Diagram_Type dt) {
+ Uml::Model_Type mt;
+ switch (dt) {
+ case Uml::dt_UseCase:
+ mt = Uml::mt_UseCase;
+ break;
+ case Uml::dt_Collaboration:
+ case Uml::dt_Class:
+ case Uml::dt_Sequence:
+ case Uml::dt_State:
+ case Uml::dt_Activity:
+ mt = Uml::mt_Logical;
+ break;
+ case Uml::dt_Component:
+ mt = Uml::mt_Component;
+ break;
+ case Uml::dt_Deployment:
+ mt = Uml::mt_Deployment;
+ break;
+ case Uml::dt_EntityRelationship:
+ mt = Uml::mt_EntityRelationship;
+ break;
+ default:
+ kError() << "Model_Utils::convert_DT_MT: illegal input value " << dt << endl;
+ mt = Uml::N_MODELTYPES;
+ break;
+ }
+ return mt;
+}
+
+Uml::ListView_Type convert_MT_LVT(Uml::Model_Type mt) {
+ Uml::ListView_Type lvt = Uml::lvt_Unknown;
+ switch (mt) {
+ case Uml::mt_Logical:
+ lvt = Uml::lvt_Logical_View;
+ break;
+ case Uml::mt_UseCase:
+ lvt = Uml::lvt_UseCase_View;
+ break;
+ case Uml::mt_Component:
+ lvt = Uml::lvt_Component_View;
+ break;
+ case Uml::mt_Deployment:
+ lvt = Uml::lvt_Deployment_View;
+ break;
+ case Uml::mt_EntityRelationship:
+ lvt = Uml::lvt_EntityRelationship_Model;
+ break;
+ default:
+ break;
+ }
+ return lvt;
+}
+
+Uml::Model_Type convert_LVT_MT(Uml::ListView_Type lvt) {
+ Uml::Model_Type mt = Uml::N_MODELTYPES;
+ switch (lvt) {
+ case Uml::lvt_Logical_View:
+ mt = Uml::mt_Logical;
+ break;
+ case Uml::lvt_UseCase_View:
+ mt = Uml::mt_UseCase;
+ break;
+ case Uml::lvt_Component_View:
+ mt = Uml::mt_Component;
+ break;
+ case Uml::lvt_Deployment_View:
+ mt = Uml::mt_Deployment;
+ break;
+ case Uml::lvt_EntityRelationship_Model:
+ mt = Uml::mt_EntityRelationship;
+ break;
+ default:
+ break;
+ }
+ return mt;
+}
+
+Uml::ListView_Type convert_DT_LVT(Uml::Diagram_Type dt) {
+ Uml::ListView_Type type = Uml::lvt_Unknown;
+ switch(dt) {
+ case Uml::dt_UseCase:
+ type = Uml::lvt_UseCase_Diagram;
+ break;
+
+ case Uml::dt_Class:
+ type = Uml::lvt_Class_Diagram;
+ break;
+
+ case Uml::dt_Sequence:
+ type = Uml::lvt_Sequence_Diagram;
+ break;
+
+ case Uml::dt_Collaboration:
+ type = Uml::lvt_Collaboration_Diagram;
+ break;
+
+ case Uml::dt_State:
+ type = Uml::lvt_State_Diagram;
+ break;
+
+ case Uml::dt_Activity:
+ type = Uml::lvt_Activity_Diagram;
+ break;
+
+ case Uml::dt_Component:
+ type = Uml::lvt_Component_Diagram;
+ break;
+
+ case Uml::dt_Deployment:
+ type = Uml::lvt_Deployment_Diagram;
+ break;
+
+ case Uml::dt_EntityRelationship:
+ type = Uml::lvt_EntityRelationship_Diagram;
+ break;
+
+ default:
+ kWarning() << "convert_DT_LVT() called on unknown diagram type" << endl;
+ }
+ return type;
+}
+
+Uml::ListView_Type convert_OT_LVT(UMLObject *o) {
+ Uml::Object_Type ot = o->getBaseType();
+ Uml::ListView_Type type = Uml::lvt_Unknown;
+ switch(ot) {
+ case Uml::ot_UseCase:
+ type = Uml::lvt_UseCase;
+ break;
+
+ case Uml::ot_Actor:
+ type = Uml::lvt_Actor;
+ break;
+
+ case Uml::ot_Class:
+ type = Uml::lvt_Class;
+ break;
+
+ case Uml::ot_Package:
+ type = Uml::lvt_Package;
+ break;
+
+ case Uml::ot_Folder:
+ {
+ UMLDoc *umldoc = UMLApp::app()->getDocument();
+ UMLFolder *f = static_cast<UMLFolder*>(o);
+ do {
+ const Uml::Model_Type mt = umldoc->rootFolderType(f);
+ if (mt != Uml::N_MODELTYPES) {
+ switch (mt) {
+ case Uml::mt_Logical:
+ type = Uml::lvt_Logical_Folder;
+ break;
+ case Uml::mt_UseCase:
+ type = Uml::lvt_UseCase_Folder;
+ break;
+ case Uml::mt_Component:
+ type = Uml::lvt_Component_Folder;
+ break;
+ case Uml::mt_Deployment:
+ type = Uml::lvt_Deployment_Folder;
+ break;
+ case Uml::mt_EntityRelationship:
+ type = Uml::lvt_EntityRelationship_Folder;
+ break;
+ default:
+ break;
+ }
+ return type;
+ }
+ } while ((f = static_cast<UMLFolder*>(f->getUMLPackage())) != NULL);
+ kError() << "convert_OT_LVT(" << o->getName()
+ << "): internal error - object is not properly nested in folder"
+ << endl;
+ }
+ break;
+
+ case Uml::ot_Component:
+ type = Uml::lvt_Component;
+ break;
+
+ case Uml::ot_Node:
+ type = Uml::lvt_Node;
+ break;
+
+ case Uml::ot_Artifact:
+ type = Uml::lvt_Artifact;
+ break;
+
+ case Uml::ot_Interface:
+ type = Uml::lvt_Interface;
+ break;
+
+ case Uml::ot_Datatype:
+ type = Uml::lvt_Datatype;
+ break;
+
+ case Uml::ot_Enum:
+ type = Uml::lvt_Enum;
+ break;
+
+ case Uml::ot_EnumLiteral:
+ type = Uml::lvt_EnumLiteral;
+ break;
+
+ case Uml::ot_Entity:
+ type = Uml::lvt_Entity;
+ break;
+
+ case Uml::ot_EntityAttribute:
+ type = Uml::lvt_EntityAttribute;
+ break;
+
+ case Uml::ot_Attribute:
+ type = Uml::lvt_Attribute;
+ break;
+
+ case Uml::ot_Operation:
+ type = Uml::lvt_Operation;
+ break;
+
+ case Uml::ot_Template:
+ type = Uml::lvt_Template;
+ break;
+ default:
+ break;
+ }
+ return type;
+}
+
+Uml::Object_Type convert_LVT_OT(Uml::ListView_Type lvt) {
+ Uml::Object_Type ot = (Uml::Object_Type)0;
+ switch (lvt) {
+ case Uml::lvt_UseCase:
+ ot = Uml::ot_UseCase;
+ break;
+
+ case Uml::lvt_Actor:
+ ot = Uml::ot_Actor;
+ break;
+
+ case Uml::lvt_Class:
+ ot = Uml::ot_Class;
+ break;
+
+ case Uml::lvt_Package:
+ case Uml::lvt_Subsystem:
+ ot = Uml::ot_Package;
+ break;
+
+ case Uml::lvt_Component:
+ ot = Uml::ot_Component;
+ break;
+
+ case Uml::lvt_Node:
+ ot = Uml::ot_Node;
+ break;
+
+ case Uml::lvt_Artifact:
+ ot = Uml::ot_Artifact;
+ break;
+
+ case Uml::lvt_Interface:
+ ot = Uml::ot_Interface;
+ break;
+
+ case Uml::lvt_Datatype:
+ ot = Uml::ot_Datatype;
+ break;
+
+ case Uml::lvt_Enum:
+ ot = Uml::ot_Enum;
+ break;
+
+ case Uml::lvt_Entity:
+ ot = Uml::ot_Entity;
+ break;
+
+ case Uml::lvt_EntityAttribute:
+ ot = Uml::ot_EntityAttribute;
+ break;
+
+ case Uml::lvt_Attribute:
+ ot = Uml::ot_Attribute;
+ break;
+
+ case Uml::lvt_Operation:
+ ot = Uml::ot_Operation;
+ break;
+
+ case Uml::lvt_Template:
+ ot = Uml::ot_Template;
+ break;
+
+ case Uml::lvt_EnumLiteral:
+ ot = Uml::ot_EnumLiteral;
+ break;
+
+ default:
+ if (typeIsFolder(lvt))
+ ot = Uml::ot_Folder;
+ break;
+ }
+ return ot;
+}
+
+Uml::Icon_Type convert_LVT_IT(Uml::ListView_Type lvt) {
+ Uml::Icon_Type icon = Uml::it_Home;
+ switch (lvt) {
+ case Uml::lvt_UseCase_View:
+ case Uml::lvt_UseCase_Folder:
+ icon = Uml::it_Folder_Grey;
+ break;
+ case Uml::lvt_Logical_View:
+ case Uml::lvt_Logical_Folder:
+ icon = Uml::it_Folder_Green;
+ break;
+ case Uml::lvt_Datatype_Folder:
+ icon = Uml::it_Folder_Orange;
+ break;
+ case Uml::lvt_Component_View:
+ case Uml::lvt_Component_Folder:
+ icon = Uml::it_Folder_Red;
+ break;
+ case Uml::lvt_Deployment_View:
+ case Uml::lvt_Deployment_Folder:
+ icon = Uml::it_Folder_Violet;
+ break;
+ case Uml::lvt_EntityRelationship_Model:
+ case Uml::lvt_EntityRelationship_Folder:
+ icon = Uml::it_Folder_Cyan;
+ break;
+
+ case Uml::lvt_Actor:
+ icon = Uml::it_Actor;
+ break;
+ case Uml::lvt_UseCase:
+ icon = Uml::it_UseCase;
+ break;
+ case Uml::lvt_Class:
+ icon = Uml::it_Class;
+ break;
+ case Uml::lvt_Package:
+ icon = Uml::it_Package;
+ break;
+ case Uml::lvt_Subsystem:
+ icon = Uml::it_Subsystem;
+ break;
+ case Uml::lvt_Component:
+ icon = Uml::it_Component;
+ break;
+ case Uml::lvt_Node:
+ icon = Uml::it_Node;
+ break;
+ case Uml::lvt_Artifact:
+ icon = Uml::it_Artifact;
+ break;
+ case Uml::lvt_Interface:
+ icon = Uml::it_Interface;
+ break;
+ case Uml::lvt_Datatype:
+ icon = Uml::it_Datatype;
+ break;
+ case Uml::lvt_Enum:
+ icon = Uml::it_Enum;
+ break;
+ case Uml::lvt_Entity:
+ icon = Uml::it_Entity;
+ break;
+ case Uml::lvt_Template:
+ icon = Uml::it_Template;
+ break;
+ case Uml::lvt_Attribute:
+ icon = Uml::it_Private_Attribute;
+ break;
+ case Uml::lvt_EntityAttribute:
+ icon = Uml::it_Private_Attribute;
+ break;
+ case Uml::lvt_EnumLiteral:
+ icon = Uml::it_Public_Attribute;
+ break;
+ case Uml::lvt_Operation:
+ icon = Uml::it_Public_Method;
+ break;
+
+ case Uml::lvt_Class_Diagram:
+ icon = Uml::it_Diagram_Class;
+ break;
+ case Uml::lvt_UseCase_Diagram:
+ icon = Uml::it_Diagram_Usecase;
+ break;
+ case Uml::lvt_Sequence_Diagram:
+ icon = Uml::it_Diagram_Sequence;
+ break;
+ case Uml::lvt_Collaboration_Diagram:
+ icon = Uml::it_Diagram_Collaboration;
+ break;
+ case Uml::lvt_State_Diagram:
+ icon = Uml::it_Diagram_State;
+ break;
+ case Uml::lvt_Activity_Diagram:
+ icon = Uml::it_Diagram_Activity;
+ break;
+ case Uml::lvt_Component_Diagram:
+ icon = Uml::it_Diagram_Component;
+ break;
+ case Uml::lvt_Deployment_Diagram:
+ icon = Uml::it_Diagram_Deployment;
+ break;
+ case Uml::lvt_EntityRelationship_Diagram:
+ icon = Uml::it_Diagram_EntityRelationship;
+ break;
+
+ default:
+ break;
+ }
+ return icon;
+}
+
+Uml::Diagram_Type convert_LVT_DT(Uml::ListView_Type lvt) {
+ Uml::Diagram_Type dt = Uml::dt_Undefined;
+ switch (lvt) {
+ case Uml::lvt_Class_Diagram:
+ dt = Uml::dt_Class;
+ break;
+ case Uml::lvt_UseCase_Diagram:
+ dt = Uml::dt_UseCase;
+ break;
+ case Uml::lvt_Sequence_Diagram:
+ dt = Uml::dt_Sequence;
+ break;
+ case Uml::lvt_Collaboration_Diagram:
+ dt = Uml::dt_Collaboration;
+ break;
+ case Uml::lvt_State_Diagram:
+ dt = Uml::dt_State;
+ break;
+ case Uml::lvt_Activity_Diagram:
+ dt = Uml::dt_Activity;
+ break;
+ case Uml::lvt_Component_Diagram:
+ dt = Uml::dt_Component;
+ break;
+ case Uml::lvt_Deployment_Diagram:
+ dt = Uml::dt_Deployment;
+ break;
+ case Uml::lvt_EntityRelationship_Diagram:
+ dt = Uml::dt_EntityRelationship;
+ break;
+ default:
+ break;
+ }
+ return dt;
+}
+
+Uml::Model_Type convert_OT_MT(Uml::Object_Type ot) {
+ Uml::Model_Type mt = Uml::N_MODELTYPES;
+ switch (ot) {
+ case Uml::ot_Actor:
+ case Uml::ot_UseCase:
+ mt = Uml::mt_UseCase;
+ break;
+ case Uml::ot_Component:
+ case Uml::ot_Artifact:
+ mt = Uml::mt_Component;
+ break;
+ case Uml::ot_Node:
+ mt = Uml::mt_Deployment;
+ break;
+ case Uml::ot_Entity:
+ case Uml::ot_EntityAttribute:
+ mt = Uml::mt_EntityRelationship;
+ break;
+ default:
+ mt = Uml::mt_Logical;
+ break;
+ }
+ return mt;
+}
+
+} // namespace Model_Utils
+
diff --git a/umbrello/umbrello/model_utils.h b/umbrello/umbrello/model_utils.h
new file mode 100644
index 00000000..3fa19afb
--- /dev/null
+++ b/umbrello/umbrello/model_utils.h
@@ -0,0 +1,328 @@
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * copyright (C) 2004-2006 *
+ * Umbrello UML Modeller Authors <uml-devel@uml.sf.net> *
+ ***************************************************************************/
+
+#ifndef MODEL_UTILS_H
+#define MODEL_UTILS_H
+
+#include <qstring.h>
+#include <qvaluelist.h>
+
+#include "umlnamespace.h"
+#include "umlobjectlist.h"
+
+/**
+ * General purpose model utilities.
+ * @author Oliver Kellogg
+ * Bugs and comments to uml-devel@lists.sf.net or http://bugs.kde.org
+ */
+
+
+// forward declarations
+class UMLClassifier;
+class UMLPackage;
+
+namespace Model_Utils {
+
+/**
+ * Determines whether the given widget type is cloneable.
+ *
+ * @param type The input Widget_Type.
+ * @return True if the given type is cloneable.
+ */
+bool isCloneable(Uml::Widget_Type type);
+
+/**
+ * Seek the given id in the given list of objects.
+ * Each list element may itself contain other objects
+ * and the search is done recursively.
+ *
+ * @param id The unique ID to seek.
+ * @param inList The UMLObjectList in which to search.
+ * @return Pointer to the UMLObject that matches the ID
+ * (NULL if none matches.)
+ */
+UMLObject * findObjectInList(Uml::IDType id, const UMLObjectList& inList);
+
+/**
+ * Find the UML object of the given type and name in the passed-in list.
+ *
+ * @param inList List in which to seek the object.
+ * @param name Name of the object to find.
+ * @param type Object_Type of the object to find (optional.)
+ * When the given type is ot_UMLObject the type is
+ * disregarded, i.e. the given name is the only
+ * search criterion.
+ * @param currentObj Object relative to which to search (optional.)
+ * If given then the enclosing scope(s) of this
+ * object are searched before the global scope.
+ * @return Pointer to the UMLObject found, or NULL if not found.
+ */
+UMLObject* findUMLObject( const UMLObjectList& inList,
+ const QString& name,
+ Uml::Object_Type type = Uml::ot_UMLObject,
+ UMLObject *currentObj = NULL);
+
+/**
+ * Returns a name for the new object, appended with a number
+ * if the default name is taken e.g. new_actor, new_actor_1
+ * etc.
+ * @param type The object type.
+ * @param parentPkg The package in which to compare the name.
+ * @param prefix The prefix to use (optional.)
+ * If no prefix is given then a type related
+ * prefix will be chosen internally.
+ */
+QString uniqObjectName(Uml::Object_Type type,
+ UMLPackage *parentPkg,
+ QString prefix = QString::null);
+
+/**
+ * Return true if the given tag is a one of the common XMI
+ * attributes, such as:
+ * "name" | "visibility" | "isRoot" | "isLeaf" | "isAbstract" |
+ * "isActive" | "ownerScope"
+ */
+bool isCommonXMIAttribute(const QString &tag);
+
+/**
+ * Return true if the given type is common among the majority
+ * of programming languages, such as "bool" or "boolean".
+ * TODO: Make this depend on the active programming language.
+ */
+bool isCommonDataType(QString type);
+
+/**
+ * Return true if the given object type is a classifier list item type.
+ */
+bool isClassifierListitem(Uml::Object_Type ot);
+
+/**
+ * Return true if the listview type also has a widget representation in diagrams.
+ */
+bool typeIsCanvasWidget(Uml::ListView_Type type);
+
+/**
+ * Return true if the listview type is one of the predefined root views
+ * (root, logical, usecase, component, deployment, datatype, or entity-
+ * relationship view.)
+ */
+bool typeIsRootView(Uml::ListView_Type type);
+
+/**
+ * Return true if the listview type is a logical, usecase or component folder.
+ */
+bool typeIsFolder(Uml::ListView_Type type);
+
+/**
+ * Return true if the listview type may act as a container for other objects,
+ * i.e. if it is a folder, package, subsystem, or component.
+ */
+bool typeIsContainer(Uml::ListView_Type type);
+
+/**
+ * Return true if the listview type is a diagram.
+ */
+bool typeIsDiagram(Uml::ListView_Type type);
+
+/**
+ * Return true if the listview type is an attribute, operation, or template.
+ */
+bool typeIsClassifierList(Uml::ListView_Type type);
+
+/**
+ * Return the Model_Type which corresponds to the given Diagram_Type.
+ */
+Uml::Model_Type convert_DT_MT(Uml::Diagram_Type dt);
+
+/**
+ * Return the ListView_Type which corresponds to the given Model_Type.
+ */
+Uml::ListView_Type convert_MT_LVT(Uml::Model_Type mt);
+
+/**
+ * Return the Model_Type which corresponds to the given ListView_Type.
+ * Returns Uml::N_MODELTYPES if the list view type given does not map
+ * to a Model_Type.
+ */
+Uml::Model_Type convert_LVT_MT(Uml::ListView_Type lvt);
+
+/**
+ * Convert a diagram type enum to the equivalent list view type.
+ */
+Uml::ListView_Type convert_DT_LVT(Uml::Diagram_Type dt);
+
+/**
+ * Converts a list view type enum to the equivalent object type.
+ *
+ * @param lvt The ListView_Type to convert.
+ * @return The converted Object_Type if the listview type
+ * has a Uml::Object_Type representation, else 0.
+ */
+Uml::Object_Type convert_LVT_OT(Uml::ListView_Type lvt);
+
+/**
+ * Convert an object's type to the equivalent list view type
+ *
+ * @param o Pointer to the UMLObject whose type shall be converted
+ * to the equivalent Uml::ListView_Type. We cannot just
+ * pass in a Uml::Object_Type because a UMLFolder is mapped
+ * to different Uml::ListView_Type values, depending on its
+ * location in one of the predefined modelviews (Logical/
+ * UseCase/etc.)
+ * @return The equivalent Uml::ListView_Type.
+ */
+Uml::ListView_Type convert_OT_LVT(UMLObject *o);
+
+/**
+ * Return the Icon_Type which corresponds to the given listview type.
+ *
+ * @param lvt ListView_Type to convert.
+ * @return The Uml::Icon_Type corresponding to the lvt.
+ * Returns it_Home in case no mapping to Uml::Icon_Type exists.
+ */
+Uml::Icon_Type convert_LVT_IT(Uml::ListView_Type lvt);
+
+/**
+ * Return the Diagram_Type which corresponds to the given listview type.
+ *
+ * @param lvt ListView_Type to convert.
+ * @return The Uml::Diagram_Type corresponding to the lvt.
+ * Returns dt_Undefined in case no mapping to Diagram_Type exists.
+ */
+Uml::Diagram_Type convert_LVT_DT(Uml::ListView_Type lvt);
+
+/**
+ * Return the Model_Type which corresponds to the given Object_Type.
+ */
+Uml::Model_Type convert_OT_MT(Uml::Object_Type ot);
+
+/**
+ * Try to guess the correct container folder type of an UMLObject.
+ * Object types that can't be guessed are mapped to Uml::mt_Logical.
+ * NOTE: This function exists mainly for handling pre-1.5.5 files
+ * and should not be used for new code.
+ */
+Uml::Model_Type guessContainer(UMLObject *o);
+
+/**
+ * Parse a direction string into the Uml::Parameter_Direction.
+ *
+ * @param input The string to parse: "in", "out", or "inout"
+ * optionally followed by whitespace.
+ * @param result The corresponding Uml::Parameter_Direction.
+ * @return Length of the string matched, excluding the optional
+ * whitespace.
+ */
+int stringToDirection(QString input, Uml::Parameter_Direction & result);
+
+/**
+ * Return string corresponding to the given Uml::Programming_Language.
+ */
+QString progLangToString(Uml::Programming_Language pl);
+
+/**
+ * Return Uml::Programming_Language corresponding to the given string.
+ */
+Uml::Programming_Language stringToProgLang(QString str);
+
+/**
+ * Return type of parseOperation()
+ */
+enum Parse_Status {
+ PS_OK, PS_Empty, PS_Malformed_Arg, PS_Unknown_ArgType,
+ PS_Illegal_MethodName, PS_Unknown_ReturnType, PS_Unspecified_Error
+};
+
+/**
+ * Data structure filled by parseAttribute()
+ */
+struct NameAndType {
+ QString m_name;
+ UMLObject *m_type;
+ Uml::Parameter_Direction m_direction;
+ QString m_initialValue;
+ NameAndType() : m_type(0), m_direction(Uml::pd_In) {
+ }
+ NameAndType(QString name, UMLObject *type,
+ Uml::Parameter_Direction direction = Uml::pd_In,
+ QString initialValue = QString::null)
+ : m_name(name), m_type(type),
+ m_direction(direction), m_initialValue(initialValue) {
+ }
+};
+
+/**
+ * Auxiliary type for OpDescriptor
+ */
+typedef QValueList<NameAndType> NameAndType_List;
+typedef QValueListIterator<NameAndType> NameAndType_ListIt;
+
+/**
+ * Data structure filled by parseOperation()
+ */
+struct OpDescriptor {
+ QString m_name;
+ NameAndType_List m_args;
+ UMLObject *m_pReturnType;
+};
+
+/**
+ * Parses a template parameter given in UML syntax.
+ *
+ * @param t Input text of the template parameter.
+ * Example: parname : partype
+ * or just: parname (for class type)
+ * @param nmTp NameAndType returned by this method.
+ * @param owningScope Pointer to the owning scope of the template param.
+ * @return Error status of the parse, PS_OK for success.
+ */
+Parse_Status parseTemplate(QString t, NameAndType& nmTp, UMLClassifier *owningScope);
+
+/**
+ * Parses an attribute given in UML syntax.
+ *
+ * @param a Input text of the attribute in UML syntax.
+ * Example: argname : argtype
+ * @param nmTp NameAndType returned by this method.
+ * @param owningScope Pointer to the owning scope of the attribute.
+ * @param vis Optional pointer to visibility (return value.)
+ * The visibility may be given at the beginning of the
+ * attribute text in mnemonic form as follows:
+ * "+" stands for public
+ * "#" stands for protected
+ * "-" stands for private
+ * "~" stands for implementation level visibility
+ *
+ * @return Error status of the parse, PS_OK for success.
+ */
+Parse_Status parseAttribute(QString a, NameAndType& nmTp, UMLClassifier *owningScope,
+ Uml::Visibility *vis = 0);
+
+/**
+ * Parses an operation given in UML syntax.
+ *
+ * @param m Input text of the operation in UML syntax.
+ * Example of a two-argument operation returning "void":
+ * methodname (arg1name : arg1type, arg2name : arg2type) : void
+ * @param desc OpDescriptor returned by this method.
+ * @param owningScope Pointer to the owning scope of the operation.
+ * @return Error status of the parse, PS_OK for success.
+ */
+Parse_Status parseOperation(QString m, OpDescriptor& desc, UMLClassifier *owningScope);
+
+/**
+ * Returns the Parse_Status as a text.
+ */
+QString psText(Parse_Status value);
+
+}
+
+#endif
diff --git a/umbrello/umbrello/node.cpp b/umbrello/umbrello/node.cpp
new file mode 100644
index 00000000..0070f481
--- /dev/null
+++ b/umbrello/umbrello/node.cpp
@@ -0,0 +1,43 @@
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * copyright (C) 2003-2006 *
+ * Umbrello UML Modeller Authors <uml-devel@uml.sf.net> *
+ ***************************************************************************/
+
+#include "node.h"
+#include <kdebug.h>
+#include <klocale.h>
+
+UMLNode::UMLNode(const QString & name, Uml::IDType id)
+ : UMLCanvasObject(name, id) {
+ init();
+}
+
+UMLNode::~UMLNode() {
+}
+
+void UMLNode::init() {
+ m_BaseType = Uml::ot_Node;
+}
+
+UMLObject* UMLNode::clone() const {
+ UMLNode *clone = new UMLNode();
+ UMLObject::copyInto(clone);
+ return clone;
+}
+
+void UMLNode::saveToXMI(QDomDocument& qDoc, QDomElement& qElement) {
+ QDomElement nodeElement = UMLObject::save("UML:Node", qDoc);
+ qElement.appendChild(nodeElement);
+}
+
+bool UMLNode::load(QDomElement& ) {
+ return true;
+}
+
+#include "node.moc"
diff --git a/umbrello/umbrello/node.h b/umbrello/umbrello/node.h
new file mode 100644
index 00000000..057ea219
--- /dev/null
+++ b/umbrello/umbrello/node.h
@@ -0,0 +1,67 @@
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * copyright (C) 2003-2006 *
+ * Umbrello UML Modeller Authors <uml-devel@uml.sf.net> *
+ ***************************************************************************/
+
+#ifndef NODE_H
+#define NODE_H
+
+#include "umlcanvasobject.h"
+
+
+/**
+ * This class contains the non-graphical information required for a UML Node.
+ * This class inherits from @ref UMLCanvasObject which contains most of the
+ * information.
+ *
+ * @short Non-graphical information for a Node.
+ * @author Jonathan Riddell
+ * @see UMLCanvasObject
+ * Bugs and comments to uml-devel@lists.sf.net or http://bugs.kde.org
+ */
+class UMLNode : public UMLCanvasObject {
+ Q_OBJECT
+public:
+ /**
+ * Sets up a Node.
+ *
+ * @param name The name of the Concept.
+ * @param id The unique id of the Concept.
+ */
+ explicit UMLNode(const QString & name = "", Uml::IDType id = Uml::id_None);
+
+ /**
+ * Empty deconstructor.
+ */
+ virtual ~UMLNode();
+
+ /**
+ * Initializes key variables of the class.
+ */
+ virtual void init();
+
+ /**
+ * Make a clone of this object.
+ */
+ virtual UMLObject* clone() const;
+
+ /**
+ * Creates the <UML:Node> XMI element.
+ */
+ void saveToXMI( QDomDocument & qDoc, QDomElement & qElement );
+
+protected:
+ /**
+ * Loads the <UML:Node> XMI element (empty.)
+ */
+ bool load( QDomElement & element );
+
+};
+
+#endif
diff --git a/umbrello/umbrello/nodewidget.cpp b/umbrello/umbrello/nodewidget.cpp
new file mode 100644
index 00000000..2bd78a93
--- /dev/null
+++ b/umbrello/umbrello/nodewidget.cpp
@@ -0,0 +1,132 @@
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * copyright (C) 2003-2007 *
+ * Umbrello UML Modeller Authors <uml-devel@uml.sf.net> *
+ ***************************************************************************/
+
+// own header
+#include "nodewidget.h"
+
+// qt/kde includes
+#include <qpainter.h>
+#include <kdebug.h>
+
+// app includes
+#include "node.h"
+#include "uml.h"
+#include "umldoc.h"
+#include "umlview.h"
+
+NodeWidget::NodeWidget(UMLView * view, UMLNode *n )
+ : UMLWidget(view, n) {
+ UMLWidget::setBaseType(Uml::wt_Node);
+ setZ(m_origZ = 1); // above box but below UMLWidget because may embed widgets
+ setSize(100, 30);
+ if (n && !UMLApp::app()->getDocument()->loading())
+ updateComponentSize();
+}
+
+NodeWidget::~NodeWidget() {}
+
+void NodeWidget::draw(QPainter & p, int offsetX, int offsetY) {
+ UMLWidget::setPen(p);
+ if ( UMLWidget::getUseFillColour() ) {
+ p.setBrush( UMLWidget::getFillColour() );
+ } else {
+ p.setBrush( m_pView->viewport()->backgroundColor() );
+ }
+ const int w = width();
+ const int h = height();
+ const int wDepth = (w/3 > DEPTH ? DEPTH : w/3);
+ const int hDepth = (h/3 > DEPTH ? DEPTH : h/3);
+ const int bodyOffsetY = offsetY + hDepth;
+ const int bodyWidth = w - wDepth;
+ const int bodyHeight = h - hDepth;
+ QFont font = UMLWidget::getFont();
+ font.setBold(true);
+ const QFontMetrics &fm = getFontMetrics(FT_BOLD);
+ const int fontHeight = fm.lineSpacing();
+ QString name = getName();
+
+ QPointArray pointArray(5);
+ pointArray.setPoint(0, offsetX, bodyOffsetY);
+ pointArray.setPoint(1, offsetX + wDepth, offsetY);
+ pointArray.setPoint(2, offsetX + w - 1, offsetY);
+ pointArray.setPoint(3, offsetX + w - 1, offsetY + bodyHeight );
+ pointArray.setPoint(4, offsetX + bodyWidth, offsetY + h - 1);
+ p.drawPolygon(pointArray);
+ p.drawRect(offsetX, bodyOffsetY, bodyWidth, bodyHeight);
+ p.drawLine(offsetX + w - 1, offsetY, offsetX + bodyWidth - 2, bodyOffsetY + 1);
+
+ p.setPen( QPen(Qt::black) );
+ p.setFont(font);
+
+ int lines = 1;
+ if (m_pObject) {
+ QString stereotype = m_pObject->getStereotype();
+ if (!stereotype.isEmpty()) {
+ p.drawText(offsetX, bodyOffsetY + (bodyHeight/2) - fontHeight,
+ bodyWidth, fontHeight, Qt::AlignCenter, m_pObject->getStereotype(true));
+ lines = 2;
+ }
+ }
+
+ if ( UMLWidget::getIsInstance() ) {
+ font.setUnderline(true);
+ p.setFont(font);
+ name = UMLWidget::getInstanceName() + " : " + name;
+ }
+
+ if (lines == 1) {
+ p.drawText(offsetX, bodyOffsetY + (bodyHeight/2) - (fontHeight/2),
+ bodyWidth, fontHeight, Qt::AlignCenter, name);
+ } else {
+ p.drawText(offsetX, bodyOffsetY + (bodyHeight/2),
+ bodyWidth, fontHeight, Qt::AlignCenter, name);
+ }
+
+ if(m_bSelected) {
+ drawSelected(&p, offsetX, offsetY);
+ }
+}
+
+QSize NodeWidget::calculateSize() {
+ if (m_pObject == NULL) {
+ kDebug() << "NodeWidget::calculateSize: m_pObject is NULL" << endl;
+ return UMLWidget::calculateSize();
+ }
+
+ const QFontMetrics &fm = getFontMetrics(FT_BOLD_ITALIC);
+ const int fontHeight = fm.lineSpacing();
+
+ QString name = m_pObject->getName();
+ if ( UMLWidget::getIsInstance() ) {
+ name = UMLWidget::getInstanceName() + " : " + name;
+ }
+
+ int width = fm.width(name);
+
+ int tempWidth = 0;
+ if (!m_pObject->getStereotype().isEmpty()) {
+ tempWidth = fm.width(m_pObject->getStereotype(true));
+ }
+ if (tempWidth > width)
+ width = tempWidth;
+ width += DEPTH;
+
+ int height = (2*fontHeight) + DEPTH;
+
+ return QSize(width, height);
+}
+
+void NodeWidget::saveToXMI(QDomDocument& qDoc, QDomElement& qElement) {
+ QDomElement conceptElement = qDoc.createElement("nodewidget");
+ UMLWidget::saveToXMI(qDoc, conceptElement);
+ qElement.appendChild(conceptElement);
+}
+
diff --git a/umbrello/umbrello/nodewidget.h b/umbrello/umbrello/nodewidget.h
new file mode 100644
index 00000000..90d28f63
--- /dev/null
+++ b/umbrello/umbrello/nodewidget.h
@@ -0,0 +1,64 @@
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * copyright (C) 2003-2006 *
+ * Umbrello UML Modeller Authors <uml-devel@uml.sf.net> *
+ ***************************************************************************/
+
+#ifndef NODEWIDGET_H
+#define NODEWIDGET_H
+
+#include "umlwidget.h"
+
+class UMLNode;
+
+/**
+ * Defines a graphical version of the Node. Most of the functionality
+ * will come from the @ref UMLNode class.
+ *
+ * @short A graphical version of a Node.
+ * @author Jonathan Riddell
+ * @see UMLWidget
+ * Bugs and comments to uml-devel@lists.sf.net or http://bugs.kde.org
+ */
+class NodeWidget : public UMLWidget {
+public:
+
+ /**
+ * Constructs a NodeWidget.
+ *
+ * @param view The parent of this NodeWidget.
+ * @param n The UMLNode this will be representing.
+ */
+ NodeWidget(UMLView * view, UMLNode *n );
+
+ /**
+ * destructor
+ */
+ virtual ~NodeWidget();
+
+ /**
+ * Overrides standard method.
+ */
+ void draw(QPainter& p, int offsetX, int offsetY);
+
+ /**
+ * Saves to the "nodewidget" XMI element.
+ * Note: For loading we use the method inherited from UMLWidget.
+ */
+ void saveToXMI(QDomDocument& qDoc, QDomElement& qElement);
+
+protected:
+ /**
+ * Overrides method from UMLWidget
+ */
+ QSize calculateSize();
+
+ static const int DEPTH = 30; ///< pixels on Z axis
+};
+
+#endif
diff --git a/umbrello/umbrello/notewidget.cpp b/umbrello/umbrello/notewidget.cpp
new file mode 100644
index 00000000..0cc7d079
--- /dev/null
+++ b/umbrello/umbrello/notewidget.cpp
@@ -0,0 +1,316 @@
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * copyright (C) 2002-2006 *
+ * Umbrello UML Modeller Authors <uml-devel@uml.sf.net> *
+ ***************************************************************************/
+
+// own header
+#include "notewidget.h"
+//qt includes
+#include <qpointarray.h>
+#include <qpainter.h>
+#include <qtextedit.h>
+#include <qframe.h>
+// kde includes
+#include <kdebug.h>
+#include <kcolordialog.h>
+// app includes
+#include "notewidgetcontroller.h"
+#include "dialogs/notedialog.h"
+#include "clipboard/umldrag.h"
+#include "umldoc.h"
+#include "umlview.h"
+#include "uml.h"
+#include "listpopupmenu.h"
+
+#define NOTEMARGIN 10
+
+NoteWidget::NoteWidget(UMLView * view, Uml::IDType id)
+ : UMLWidget(view, id, new NoteWidgetController(this)) {
+ init();
+ setSize(100,80);
+ setZ( 20 ); //make sure always on top.
+#ifdef NOTEWIDGET_EMBED_EDITOR
+ // NB: This code is currently deactivated because
+ // Zoom does not yet work with the embedded text editor.
+ m_pEditor = new QTextEdit(view);
+ m_pEditor->setFrameStyle(QFrame::NoFrame | QFrame::Plain);
+ m_pEditor->setHScrollBarMode(QScrollView::AlwaysOff);
+ m_pEditor->setVScrollBarMode(QScrollView::AlwaysOff);
+ m_pEditor->setTextFormat(Qt::RichText);
+ m_pEditor->setShown(true);
+ setEditorGeometry();
+ connect(m_pView, SIGNAL(contentsMoving(int, int)),
+ this, SLOT(slotViewScrolled(int, int)));
+#endif
+}
+
+void NoteWidget::init() {
+ UMLWidget::setBaseType(Uml::wt_Note);
+ m_DiagramLink = Uml::id_None;
+}
+
+NoteWidget::~NoteWidget() {
+#ifdef NOTEWIDGET_EMBED_EDITOR
+ delete m_pEditor;
+#endif
+}
+
+void NoteWidget::setDiagramLink(Uml::IDType viewID) {
+ UMLDoc *umldoc = UMLApp::app()->getDocument();
+ UMLView *view = umldoc->findView(viewID);
+ if (view == NULL) {
+ kError() << "NoteWidget::setDiagramLink(" << ID2STR(viewID)
+ << "): no view found for this ID." << endl;
+ return;
+ }
+ QString linkText("Diagram: " + view->getName());
+#if defined (NOTEWIDGET_EMBED_EDITOR)
+ m_pEditor->setUnderline(true);
+ m_pEditor->insert(linkText);
+ m_pEditor->setUnderline(false);
+#else
+ setDoc(linkText);
+ update();
+#endif
+ m_DiagramLink = viewID;
+}
+
+Uml::IDType NoteWidget::getDiagramLink() const {
+ return m_DiagramLink;
+}
+
+void NoteWidget::slotViewScrolled(int x, int y) {
+ setEditorGeometry(x, y);
+}
+
+void NoteWidget::setFont(QFont font) {
+ UMLWidget::setFont(font);
+#ifdef NOTEWIDGET_EMBED_EDITOR
+ m_pEditor->setFont(font);
+#endif
+}
+
+void NoteWidget::setEditorGeometry(int dx /*=0*/, int dy /*=0*/) {
+#if defined (NOTEWIDGET_EMBED_EDITOR)
+ const QRect editorGeometry( UMLWidget::getX() - dx + 6,
+ UMLWidget::getY() - dy + 10,
+ UMLWidget::getWidth() - 16,
+ UMLWidget::getHeight() - 16);
+ m_pEditor->setGeometry( editorGeometry );
+ drawText();
+#else
+ dx=0; dy=0; // avoid "unused arg" warnings
+#endif
+}
+
+void NoteWidget::setX( int x ) {
+ UMLWidget::setX(x);
+ setEditorGeometry();
+}
+
+void NoteWidget::setY( int y ) {
+ UMLWidget::setY(y);
+ setEditorGeometry();
+}
+
+QString NoteWidget::getDoc() const {
+#if defined (NOTEWIDGET_EMBED_EDITOR)
+ return m_pEditor->text();
+#else
+ return m_Text;
+#endif
+}
+
+void NoteWidget::setDoc(const QString &newText) {
+#if defined (NOTEWIDGET_EMBED_EDITOR)
+ m_pEditor->setText(newText);
+#else
+ m_Text = newText;
+#endif
+}
+
+void NoteWidget::draw(QPainter & p, int offsetX, int offsetY) {
+ int margin = 10;
+ int w = width()-1;
+
+ int h= height()-1;
+ QPointArray poly(6);
+ poly.setPoint(0, offsetX, offsetY);
+ poly.setPoint(1, offsetX, offsetY + h);
+ poly.setPoint(2, offsetX + w, offsetY + h);
+ poly.setPoint(3, offsetX + w, offsetY + margin);
+ poly.setPoint(4, offsetX + w - margin, offsetY);
+ poly.setPoint(5, offsetX, offsetY);
+ UMLWidget::setPen(p);
+ if ( UMLWidget::getUseFillColour() ) {
+ QBrush brush( UMLWidget::getFillColour() );
+ p.setBrush(brush);
+ p.drawPolygon(poly);
+#if defined (NOTEWIDGET_EMBED_EDITOR)
+ m_pEditor->setPaper(brush);
+#endif
+ } else
+ p.drawPolyline(poly);
+ p.drawLine(offsetX + w - margin, offsetY, offsetX + w - margin, offsetY + margin);
+ p.drawLine(offsetX + w - margin, offsetY + margin, offsetX + w, offsetY + margin);
+ if(m_bSelected) {
+ drawSelected(&p, offsetX, offsetY);
+ }
+
+ drawText(&p, offsetX, offsetY);
+}
+
+QSize NoteWidget::calculateSize() {
+ return QSize(50, 50);
+}
+
+void NoteWidget::slotMenuSelection(int sel) {
+ NoteDialog * dlg = 0;
+ UMLDoc *doc = UMLApp::app()->getDocument();
+ switch(sel) {
+ ///OBSOLETE - remove ListPopupMenu::mt_Link_Docs
+ // case ListPopupMenu::mt_Link_Docs:
+ // m_pView->updateNoteWidgets();
+ // doc -> setModified(true);
+ // break;
+
+ case ListPopupMenu::mt_Rename:
+ m_pView -> updateDocumentation( false );
+ dlg = new NoteDialog( m_pView, this );
+ if( dlg -> exec() ) {
+ m_pView -> showDocumentation( this, true );
+ doc -> setModified(true);
+ update();
+ }
+ delete dlg;
+ break;
+
+ default:
+ UMLWidget::slotMenuSelection(sel);
+ break;
+ }
+}
+
+void NoteWidget::drawText(QPainter * p /*=NULL*/, int offsetX /*=0*/, int offsetY /*=0*/) {
+#if defined (NOTEWIDGET_EMBED_EDITOR)
+ m_pEditor->setText( getDoc() );
+ m_pEditor->setShown(true);
+ m_pEditor->repaint();
+#else
+ if (p == NULL)
+ return;
+ /*
+ Implement word wrap for text as follows:
+ wrap at width on whole words.
+ if word is wider than width then clip word
+ if reach height exit and don't print anymore
+ start new line on \n character
+ */
+ p->setPen( Qt::black );
+ QFont font = UMLWidget::getFont();
+ p->setFont( font );
+ const QFontMetrics &fm = getFontMetrics(FT_NORMAL);
+ const int fontHeight = fm.lineSpacing();
+ QString text = getDoc();
+ if( text.length() == 0 )
+ return;
+ QString word = "";
+ QString fullLine = "";
+ QString testCombineLine = "";
+ const int margin = fm.width( "W" );
+ int textY = fontHeight / 2;
+ int textX = margin;
+ const int width = this -> width() - margin * 2;
+ const int height = this -> height() - fontHeight;
+ QChar returnChar('\n');
+ QChar c;
+ for (uint i = 0; i <= text.length(); i++) {
+ if (i < text.length()) {
+ c = text[i];
+ } else {
+ // all chars of text have been handled already ->
+ // perform this last run to spool current content of "word"
+ c = returnChar;
+ }
+ if (c == returnChar || c.isSpace()) {
+ // new word delimiter found -> its time to decide on word wrap
+ testCombineLine = fullLine + ' ' + word;
+ int textWidth = fm.width( testCombineLine );
+ if (textX + textWidth > width) {
+ // combination of "fullLine" and "word" doesn't fit into one line ->
+ // print "fullLine" in current line, update write position to next line
+ // and decide then on following actions
+ p->drawText(offsetX + textX, offsetY + textY,
+ textWidth, fontHeight, Qt::AlignLeft, fullLine );
+ fullLine = word;
+ word = "";
+ // update write position
+ textX = margin;
+ textY += fontHeight;
+ if (textY > height)
+ return;
+ // in case of c==newline ->
+ // print "word" and set write position one additional line lower
+ if (c == returnChar) {
+ // print "word" - which is now "fullLine" and set to next line
+ p->drawText(offsetX + textX, offsetY + textY,
+ textWidth, fontHeight, Qt::AlignLeft, fullLine);
+ fullLine = "";
+ textX = margin;
+ textY += fontHeight;
+ if( textY > height ) return;
+ }
+ }
+ else if ( c == returnChar ) {
+ // newline found and combination of "fullLine" and "word" fits
+ // in one line
+ p->drawText(offsetX + textX, offsetY + textY,
+ textWidth, fontHeight, Qt::AlignLeft, testCombineLine);
+ fullLine = word = "";
+ textX = margin;
+ textY += fontHeight;
+ if (textY > height)
+ return;
+ } else {
+ // word delimiter found, and combination of "fullLine", space and "word" fits into one line
+ fullLine = testCombineLine;
+ word = "";
+ }
+ } else {
+ // no word delimiter found --> add current char to "word"
+ if (c != '\0')
+ word += c;
+ }
+ }//end for
+#endif
+}
+
+void NoteWidget::saveToXMI( QDomDocument & qDoc, QDomElement & qElement ) {
+ QDomElement noteElement = qDoc.createElement( "notewidget" );
+ UMLWidget::saveToXMI( qDoc, noteElement );
+ noteElement.setAttribute( "text", getDoc() );
+ if (m_DiagramLink != Uml::id_None)
+ noteElement.setAttribute( "diagramlink", ID2STR(m_DiagramLink) );
+ qElement.appendChild( noteElement );
+}
+
+bool NoteWidget::loadFromXMI( QDomElement & qElement ) {
+ if( !UMLWidget::loadFromXMI( qElement ) )
+ return false;
+ setZ( 20 ); //make sure always on top.
+ setDoc( qElement.attribute("text", "") );
+ QString diagramlink = qElement.attribute("diagramlink", "");
+ if (!diagramlink.isEmpty())
+ m_DiagramLink = STR2ID(diagramlink);
+ return true;
+}
+
+
+#include "notewidget.moc"
+
diff --git a/umbrello/umbrello/notewidget.h b/umbrello/umbrello/notewidget.h
new file mode 100644
index 00000000..298839cb
--- /dev/null
+++ b/umbrello/umbrello/notewidget.h
@@ -0,0 +1,146 @@
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * copyright (C) 2002-2006 *
+ * Umbrello UML Modeller Authors <uml-devel@uml.sf.net> *
+ ***************************************************************************/
+
+#ifndef NOTEWIDGET_H
+#define NOTEWIDGET_H
+
+//app includes
+#include "umlwidget.h"
+
+// forward declarations
+class NoteWidgetController;
+
+// Qt forward declarations
+class QPainter;
+class QTextEdit;
+
+/**
+ * Displays a note box to allow multiple lines of text to be displayed.
+ * These widgets are diagram specific. They will still need a unique id
+ * from the @ref UMLDoc class for deletion and other purposes.
+ *
+ * @short Displays a note box.
+ * @author Paul Hensgen <phensgen@techie.com>
+ * @see UMLWidget
+ * Bugs and comments to uml-devel@lists.sf.net or http://bugs.kde.org
+ */
+class NoteWidget : public UMLWidget {
+ Q_OBJECT
+public:
+ friend class NoteWidgetController;
+
+ /**
+ * Constructs a NoteWidget.
+ *
+ * @param view The parent to this widget.
+ * @param noteType The NoteWidget::NoteType of this NoteWidget
+ * @param id The unique id of the widget.
+ * The default (-1) will prompt a new ID.
+ */
+ explicit NoteWidget(UMLView * view, Uml::IDType id = Uml::id_None );
+
+ /**
+ * destructor
+ */
+ virtual ~NoteWidget();
+
+ /**
+ * Overrides method from UMLWidget.
+ */
+ QSize calculateSize();
+
+ /**
+ * Returns the text in the box.
+ *
+ * @return The text in the box.
+ */
+ QString getDoc() const;
+
+ /**
+ * Sets the note documentation.
+ *
+ * @param newText The text to set the documentation to.
+ */
+ void setDoc(const QString &newText);
+
+ /**
+ * Set the ID of the diagram hyperlinked to this note.
+ * To switch off the hyperlink, set this to Uml::id_None.
+ *
+ * @param viewID ID of an UMLView.
+ */
+ void setDiagramLink(Uml::IDType viewID);
+
+ /**
+ * Return the ID of the diagram hyperlinked to this note.
+ *
+ * @return ID of an UMLView, or Uml::id_None if no
+ * hyperlink is set.
+ */
+ Uml::IDType getDiagramLink() const;
+
+ /**
+ * Override default method.
+ */
+ void draw(QPainter & p, int offsetX, int offsetY);
+
+ /**
+ * Override method from UMLWidget.
+ */
+ void setFont(QFont font);
+
+ /**
+ * Override method from UMLWidget.
+ */
+ void setX(int x);
+
+ /**
+ * Override method from UMLWidget.
+ */
+ void setY(int y);
+
+ /**
+ * Saves to the "notewidget" XMI element.
+ */
+ void saveToXMI( QDomDocument & qDoc, QDomElement & qElement );
+
+ /**
+ * Loads a "notewidget" XMI element.
+ */
+ bool loadFromXMI( QDomElement & qElement );
+
+public slots:
+ void slotMenuSelection(int sel);
+ void slotViewScrolled(int x, int y);
+
+protected:
+ // Data loaded/saved
+ Uml::IDType m_DiagramLink;
+
+ /**
+ * Draws the text. Auxiliary to draw().
+ */
+ void drawText(QPainter * p = NULL, int offsetX = 0, int offsetY = 0);
+private:
+ /**
+ * Initializes key variables for the class.
+ */
+ void init();
+
+ void setEditorGeometry(int dx = 0, int dy = 0);
+#if defined (NOTEWIDGET_EMBED_EDITOR)
+ QTextEdit *m_pEditor;
+#else
+ QString m_Text;
+#endif
+};
+
+#endif
diff --git a/umbrello/umbrello/notewidgetcontroller.cpp b/umbrello/umbrello/notewidgetcontroller.cpp
new file mode 100644
index 00000000..e61a7d76
--- /dev/null
+++ b/umbrello/umbrello/notewidgetcontroller.cpp
@@ -0,0 +1,49 @@
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * copyright (C) 2006 *
+ * Umbrello UML Modeller Authors <uml-devel@uml.sf.net> *
+ ***************************************************************************/
+
+// app includes
+#include "notewidgetcontroller.h"
+#include "notewidget.h"
+#include "uml.h"
+#include "umldoc.h"
+#include "listpopupmenu.h"
+
+NoteWidgetController::NoteWidgetController(NoteWidget *noteWidget):
+ UMLWidgetController(noteWidget) {
+ m_noteWidget = noteWidget;
+}
+
+NoteWidgetController::~NoteWidgetController() {
+}
+
+void NoteWidgetController::mouseMoveEvent(QMouseEvent *me) {
+ UMLWidgetController::mouseMoveEvent(me);
+ m_noteWidget->setEditorGeometry();
+}
+
+void NoteWidgetController::mouseReleaseEvent(QMouseEvent *me) {
+ UMLWidgetController::mouseReleaseEvent(me);
+ //TODO why is it needed? drawText is already called in draw,
+ //and draw is (well, I think that is) called when the canvas rectangle is resized
+ if (m_resized) {
+ m_noteWidget->drawText();
+ }
+}
+
+void NoteWidgetController::doMouseDoubleClick(QMouseEvent *me) {
+ //TODO Copied from old code. What it does?
+ if (m_noteWidget->m_DiagramLink == Uml::id_None) {
+ m_noteWidget->slotMenuSelection(ListPopupMenu::mt_Rename);
+ } else {
+ UMLDoc *umldoc = UMLApp::app()->getDocument();
+ umldoc->changeCurrentView(m_noteWidget->m_DiagramLink);
+ }
+}
diff --git a/umbrello/umbrello/notewidgetcontroller.h b/umbrello/umbrello/notewidgetcontroller.h
new file mode 100644
index 00000000..f3295ce7
--- /dev/null
+++ b/umbrello/umbrello/notewidgetcontroller.h
@@ -0,0 +1,81 @@
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * copyright (C) 2006 *
+ * Umbrello UML Modeller Authors <uml-devel@uml.sf.net> *
+ ***************************************************************************/
+
+#ifndef NOTEWIDGETCONTROLLER_H
+#define NOTEWIDGETCONTROLLER_H
+
+#include "umlwidgetcontroller.h"
+
+class NoteWidget;
+
+/**
+ * Controller for NoteWidget.
+ *
+ * MouseMove and MouseRelease execute the base code and then specific code
+ * for note widget.
+ *
+ * Double click behaviour is edit the text of the note.
+ *
+ * @author Umbrello UML Modeller Authors <uml-devel@lists.sourceforge.net>
+ */
+class NoteWidgetController : public UMLWidgetController {
+public:
+
+ /**
+ * Constructor for NoteWidgetController.
+ *
+ * @param noteWidget The NoteWidget which uses the controller.
+ */
+ NoteWidgetController(NoteWidget* noteWidget);
+
+ /**
+ * Destructor for NoteWidgetController.
+ */
+ virtual ~NoteWidgetController();
+
+ /**
+ * Overriden from UMLWidgetController.
+ * Handles a mouse move event.
+ * Executes base code and then sets the geometry of the editor.
+ *
+ * @param me The QMouseEvent event.
+ */
+ virtual void mouseMoveEvent(QMouseEvent* me);
+
+ /**
+ * Overriden from UMLWidgetController.
+ * Handles a mouse release event.
+ * Executes base code and then draws the text in the note.
+ *
+ * @param me The QMouseEvent event.
+ */
+ virtual void mouseReleaseEvent(QMouseEvent * me);
+
+protected:
+
+ /**
+ * Overriden from UMLWidgetController.
+ * Executes the action for double click in the widget.
+ * Shows the dialog to change the text of the note.
+ *
+ * @param me The QMouseEvent which triggered the double click event.
+ */
+ virtual void doMouseDoubleClick(QMouseEvent *me);
+
+private:
+
+ /**
+ * The note widget which uses the controller.
+ */
+ NoteWidget* m_noteWidget;
+};
+
+#endif
diff --git a/umbrello/umbrello/object_factory.cpp b/umbrello/umbrello/object_factory.cpp
new file mode 100644
index 00000000..f6fcbe41
--- /dev/null
+++ b/umbrello/umbrello/object_factory.cpp
@@ -0,0 +1,283 @@
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * copyright (C) 2006-2007 *
+ * Umbrello UML Modeller Authors <uml-devel@uml.sf.net> *
+ ***************************************************************************/
+
+// own header
+#include "object_factory.h"
+
+// qt/kde includes
+#include <qregexp.h>
+#include <qstringlist.h>
+#include <kapplication.h>
+#include <klocale.h>
+#include <kmessagebox.h>
+#include <kdebug.h>
+#include <kinputdialog.h>
+
+// app includes
+#include "umlobject.h"
+#include "umlpackagelist.h"
+#include "package.h"
+#include "folder.h"
+#include "classifier.h"
+#include "attribute.h"
+#include "operation.h"
+#include "enum.h"
+#include "entity.h"
+#include "actor.h"
+#include "usecase.h"
+#include "component.h"
+#include "node.h"
+#include "artifact.h"
+#include "stereotype.h"
+#include "association.h"
+#include "umldoc.h"
+#include "uml.h"
+#include "codegenerator.h"
+#include "model_utils.h"
+#include "uniqueid.h"
+
+namespace Object_Factory {
+
+Uml::IDType g_predefinedId = Uml::id_None;
+
+void assignUniqueIdOnCreation(bool yesno) {
+ if (yesno)
+ g_predefinedId = Uml::id_None;
+ else
+ g_predefinedId = Uml::id_Reserved;
+}
+
+bool assignUniqueIdOnCreation() {
+ return (g_predefinedId == Uml::id_None);
+}
+
+UMLObject* createNewUMLObject(Uml::Object_Type type, const QString &name,
+ UMLPackage *parentPkg) {
+ if (parentPkg == NULL) {
+ kError() << "Object_Factory::createNewUMLObject(" << name
+ << "): parentPkg is NULL" << endl;
+ return NULL;
+ }
+ UMLObject *o = NULL;
+ switch (type) {
+ case Uml::ot_Actor:
+ o = new UMLActor(name, g_predefinedId);
+ break;
+ case Uml::ot_UseCase:
+ o = new UMLUseCase(name, g_predefinedId);
+ break;
+ case Uml::ot_Class:
+ o = new UMLClassifier(name, g_predefinedId);
+ break;
+ case Uml::ot_Package:
+ o = new UMLPackage(name, g_predefinedId);
+ break;
+ case Uml::ot_Component:
+ o = new UMLComponent(name, g_predefinedId);
+ break;
+ case Uml::ot_Node:
+ o = new UMLNode(name, g_predefinedId);
+ break;
+ case Uml::ot_Artifact:
+ o = new UMLArtifact(name, g_predefinedId);
+ break;
+ case Uml::ot_Interface: {
+ UMLClassifier *c = new UMLClassifier(name, g_predefinedId);
+ c->setBaseType(Uml::ot_Interface);
+ o = c;
+ break;
+ }
+ case Uml::ot_Datatype: {
+ UMLClassifier *c = new UMLClassifier(name, g_predefinedId);
+ c->setBaseType(Uml::ot_Datatype);
+ o = c;
+ break;
+ }
+ case Uml::ot_Enum:
+ o = new UMLEnum(name, g_predefinedId);
+ break;
+ case Uml::ot_Entity:
+ o = new UMLEntity(name, g_predefinedId);
+ break;
+ case Uml::ot_Folder:
+ o = new UMLFolder(name, g_predefinedId);
+ break;
+ default:
+ kWarning() << "createNewUMLObject error unknown type: " << type << endl;
+ return NULL;
+ }
+ o->setUMLPackage(parentPkg);
+ UMLDoc *doc = UMLApp::app()->getDocument();
+ parentPkg->addObject(o);
+ doc->signalUMLObjectCreated(o);
+ kapp->processEvents();
+ return o;
+}
+
+UMLObject* createUMLObject(Uml::Object_Type type, const QString &n,
+ UMLPackage *parentPkg /* = NULL */,
+ bool solicitNewName /* = true */) {
+ UMLDoc *doc = UMLApp::app()->getDocument();
+ if (parentPkg == NULL) {
+ if (type == Uml::ot_Datatype) {
+ parentPkg = doc->getDatatypeFolder();
+ } else {
+ Uml::Model_Type mt = Model_Utils::convert_OT_MT(type);
+ kDebug() << "Object_Factory::createUMLObject(" << n << "): "
+ << "parentPkg is not set, assuming Model_Type " << mt << endl;
+ parentPkg = doc->getRootFolder(mt);
+ }
+ }
+ if (!n.isEmpty()) {
+ UMLObject *o = doc->findUMLObject(n, type, parentPkg);
+ if (o) {
+ if (!solicitNewName)
+ return o;
+ } else {
+ o = createNewUMLObject(type, n, parentPkg);
+ return o;
+ }
+ }
+ bool ok = false;
+ QString name = Model_Utils::uniqObjectName(type, parentPkg, n);
+ bool bValidNameEntered = false;
+ do {
+ name = KInputDialog::getText(i18n("Name"), i18n("Enter name:"), name, &ok, (QWidget*)UMLApp::app());
+ if (!ok) {
+ return 0;
+ }
+ if (name.length() == 0) {
+ KMessageBox::error(0, i18n("That is an invalid name."),
+ i18n("Invalid Name"));
+ continue;
+ }
+ CodeGenerator *codegen = UMLApp::app()->getGenerator();
+ if (codegen != NULL && codegen->isReservedKeyword(name)) {
+ KMessageBox::error(0, i18n("This is a reserved keyword for the language of the configured code generator."),
+ i18n("Reserved Keyword"));
+ continue;
+ }
+ if (! doc->isUnique(name, parentPkg)) {
+ KMessageBox::error(0, i18n("That name is already being used."),
+ i18n("Not a Unique Name"));
+ continue;
+ }
+ bValidNameEntered = true;
+ } while (bValidNameEntered == false);
+ UMLObject *o = createNewUMLObject(type, name, parentPkg);
+ return o;
+}
+
+UMLAttribute *createAttribute(UMLObject *parent, const QString& name, UMLObject *type) {
+ UMLAttribute *attr = new UMLAttribute(parent);
+ attr->setName(name);
+ attr->setType(type);
+ if (g_predefinedId == Uml::id_None)
+ attr->setID(UniqueID::gen());
+ return attr;
+}
+
+UMLOperation *createOperation(UMLClassifier *parent, const QString& name) {
+ UMLOperation *op = new UMLOperation(parent, name, g_predefinedId);
+ return op;
+}
+
+UMLClassifierListItem* createChildObject(UMLClassifier* parent, Uml::Object_Type type) {
+ UMLObject* returnObject = NULL;
+ switch (type) {
+ case Uml::ot_Attribute:
+ case Uml::ot_EntityAttribute: {
+ UMLClassifier *c = dynamic_cast<UMLClassifier*>(parent);
+ if (c && !c->isInterface())
+ returnObject = c->createAttribute();
+ break;
+ }
+ case Uml::ot_Operation: {
+ UMLClassifier *c = dynamic_cast<UMLClassifier*>(parent);
+ if (c)
+ returnObject = c->createOperation();
+ break;
+ }
+ case Uml::ot_Template: {
+ UMLClassifier *c = dynamic_cast<UMLClassifier*>(parent);
+ if (c)
+ returnObject = c->createTemplate();
+ break;
+ }
+ case Uml::ot_EnumLiteral: {
+ UMLEnum* umlenum = dynamic_cast<UMLEnum*>(parent);
+ if (umlenum) {
+ returnObject = umlenum->createEnumLiteral();
+ }
+ break;
+ }
+ default:
+ kDebug() << "ERROR UMLDoc::createChildObject type:" << type << endl;
+ }
+ return static_cast<UMLClassifierListItem*>(returnObject);
+}
+
+UMLObject* makeObjectFromXMI(const QString& xmiTag,
+ const QString& stereoID /* = QString::null */) {
+ UMLObject* pObject = 0;
+ if (Uml::tagEq(xmiTag, "UseCase")) {
+ pObject = new UMLUseCase();
+ } else if (Uml::tagEq(xmiTag, "Actor")) {
+ pObject = new UMLActor();
+ } else if (Uml::tagEq(xmiTag, "Class")) {
+ pObject = new UMLClassifier();
+ } else if (Uml::tagEq(xmiTag, "Package")) {
+ if (!stereoID.isEmpty()) {
+ UMLDoc *doc = UMLApp::app()->getDocument();
+ UMLObject *stereo = doc->findStereotypeById(STR2ID(stereoID));
+ if (stereo && stereo->getName() == "folder")
+ pObject = new UMLFolder();
+ }
+ if (pObject == NULL)
+ pObject = new UMLPackage();
+ } else if (Uml::tagEq(xmiTag, "Component")) {
+ pObject = new UMLComponent();
+ } else if (Uml::tagEq(xmiTag, "Node")) {
+ pObject = new UMLNode();
+ } else if (Uml::tagEq(xmiTag, "Artifact")) {
+ pObject = new UMLArtifact();
+ } else if (Uml::tagEq(xmiTag, "Interface")) {
+ UMLClassifier *c = new UMLClassifier();
+ c->setBaseType(Uml::ot_Interface);
+ pObject = c;
+ } else if (Uml::tagEq(xmiTag, "DataType") || Uml::tagEq(xmiTag, "Primitive")
+ || Uml::tagEq(xmiTag, "Datatype")) { // for bkwd compat.
+ UMLClassifier *c = new UMLClassifier();
+ c->setBaseType(Uml::ot_Datatype);
+ pObject = c;
+ } else if (Uml::tagEq(xmiTag, "Enumeration") ||
+ Uml::tagEq(xmiTag, "Enum")) { // for bkwd compat.
+ pObject = new UMLEnum();
+ } else if (Uml::tagEq(xmiTag, "Entity")) {
+ pObject = new UMLEntity();
+ } else if (Uml::tagEq(xmiTag, "Stereotype")) {
+ pObject = new UMLStereotype();
+ } else if (Uml::tagEq(xmiTag, "Association") ||
+ Uml::tagEq(xmiTag, "AssociationClass")) {
+ pObject = new UMLAssociation();
+ } else if (Uml::tagEq(xmiTag, "Generalization")) {
+ pObject = new UMLAssociation(Uml::at_Generalization);
+ } else if (Uml::tagEq(xmiTag, "Realization") ||
+ Uml::tagEq(xmiTag, "Abstraction")) {
+ pObject = new UMLAssociation(Uml::at_Realization);
+ } else if (Uml::tagEq(xmiTag, "Dependency")) {
+ pObject = new UMLAssociation(Uml::at_Dependency);
+ }
+ return pObject;
+}
+
+} // end namespace Object_Factory
+
diff --git a/umbrello/umbrello/object_factory.h b/umbrello/umbrello/object_factory.h
new file mode 100644
index 00000000..c7bf71d9
--- /dev/null
+++ b/umbrello/umbrello/object_factory.h
@@ -0,0 +1,84 @@
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * copyright (C) 2006 *
+ * Umbrello UML Modeller Authors <uml-devel@uml.sf.net> *
+ ***************************************************************************/
+
+#ifndef OBJECT_FACTORY__H
+#define OBJECT_FACTORY__H
+
+#include <qstring.h>
+#include "umlnamespace.h"
+
+class UMLObject;
+class UMLPackage;
+class UMLClassifier;
+class UMLClassifierListItem;
+class UMLAttribute;
+class UMLOperation;
+
+namespace Object_Factory {
+
+/**
+ * Creates a UMLObject of the given type.
+ *
+ * @param type The type of @ref UMLObject to create.
+ * @param n A name to give to the object (optional.)
+ * If not given then an input dialog prompts
+ * the user to supply a name.
+ * @param parentPkg The object's parent package.
+ * @param solicitNewName Ask user for a different name if an object
+ * of the given name already exists.
+ * If set to false and the name already exists
+ * then the existing object is returned.
+ * The default is to ask for the new name.
+ */
+UMLObject* createUMLObject(Uml::Object_Type type,
+ const QString &n = QString::null,
+ UMLPackage *parentPkg = 0,
+ bool solicitNewName = true);
+
+/**
+ * Creates an operation, attribute, template, or enum literal
+ * for the parent classifier.
+ *
+ * @param parent The parent concept
+ * @param type The type to create
+ * @return Pointer to the UMLClassifierListItem created
+ */
+UMLClassifierListItem* createChildObject(UMLClassifier *parent, Uml::Object_Type type);
+
+UMLAttribute *createAttribute(UMLObject *parent, const QString& name,
+ UMLObject *type = 0);
+
+UMLOperation *createOperation(UMLClassifier *parent, const QString& name);
+
+/**
+ * Control whether the createUMLObject() solicits a new unique ID for the
+ * created object.
+ * By default, unique ID generation is turned on.
+ *
+ * @param yesno False turns UID generation off, true turns it on.
+ */
+void assignUniqueIdOnCreation(bool yesno);
+
+/**
+ * Return whether unique ID generation is on or off.
+ */
+bool assignUniqueIdOnCreation();
+
+/**
+ * Make a new UMLObject according to the given XMI tag.
+ * Used by loadFromXMI and clipboard paste.
+ */
+UMLObject* makeObjectFromXMI(const QString& xmiTag,
+ const QString& stereoID = QString::null);
+
+}
+
+#endif
diff --git a/umbrello/umbrello/objectwidget.cpp b/umbrello/umbrello/objectwidget.cpp
new file mode 100644
index 00000000..35e7bdde
--- /dev/null
+++ b/umbrello/umbrello/objectwidget.cpp
@@ -0,0 +1,403 @@
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * copyright (C) 2002-2007 *
+ * Umbrello UML Modeller Authors <uml-devel@uml.sf.net> *
+ ***************************************************************************/
+
+// own header file
+#include "objectwidget.h"
+
+// system includes
+#include <qpainter.h>
+#include <qvalidator.h>
+#include <qevent.h>
+#include <klocale.h>
+#include <kdebug.h>
+#include <kinputdialog.h>
+
+// local includes
+#include "objectwidgetcontroller.h"
+#include "seqlinewidget.h"
+#include "umlview.h"
+#include "umldoc.h"
+#include "uml.h"
+#include "umlobject.h"
+#include "listpopupmenu.h"
+#include "docwindow.h"
+#include "dialogs/classpropdlg.h"
+
+/**
+ * The number of pixels margin between the lowest message
+ * and the bottom of the vertical line
+ */
+static const int sequenceLineMargin = 20;
+
+ObjectWidget::ObjectWidget(UMLView * view, UMLObject *o, Uml::IDType lid)
+ : UMLWidget(view, o) {
+ init();
+ if( lid != Uml::id_None )
+ m_nLocalID = lid;
+ //updateComponentSize();
+ // Doing this during loadFromXMI() gives futile updates.
+ // Instead, it is done afterwards by UMLWidget::activate()
+}
+
+void ObjectWidget::init() {
+ UMLWidget::setBaseType(Uml::wt_Object);
+ m_nLocalID = Uml::id_None;
+ m_InstanceName = "";
+ m_bMultipleInstance = false;
+ m_bDrawAsActor = false;
+ m_bShowDestruction = false;
+ messageWidgetList.setAutoDelete(false);
+ if( m_pView != NULL && m_pView -> getType() == Uml::dt_Sequence ) {
+ m_pLine = new SeqLineWidget( m_pView, this );
+
+ //Sets specific widget controller for sequence diagrams
+ delete m_widgetController;
+ m_widgetController = new ObjectWidgetController(this);
+ } else {
+ m_pLine = NULL;
+ }
+}
+
+ObjectWidget::~ObjectWidget() {}
+
+void ObjectWidget::draw(QPainter & p , int offsetX, int offsetY) {
+ if ( m_bDrawAsActor )
+ drawActor( p, offsetX, offsetY );
+ else
+ drawObject( p, offsetX, offsetY );
+
+ UMLWidget::setPen(p);
+ if(m_bSelected)
+ drawSelected(&p, offsetX, offsetY);
+}
+
+void ObjectWidget::slotMenuSelection(int sel) {
+ QString name = "";
+ switch(sel) {
+ case ListPopupMenu::mt_Rename_Object:
+ {
+ bool ok;
+ QRegExpValidator* validator = new QRegExpValidator(QRegExp(".*"), 0);
+ name = KInputDialog::getText
+ (i18n("Rename Object"),
+ i18n("Enter object name:"),
+ m_InstanceName,
+ &ok,
+ m_pView,
+ "renameobject",
+ validator);
+ if (ok) {
+ m_InstanceName = name;
+ updateComponentSize();
+ moveEvent( 0 );
+ update();
+ UMLApp::app()->getDocument()->setModified(true);
+ }
+ delete validator;
+ break;
+ }
+ case ListPopupMenu::mt_Properties:
+ showProperties();
+ updateComponentSize();
+ moveEvent( 0 );
+ update();
+ break;
+
+ case ListPopupMenu::mt_Up:
+ tabUp();
+ break;
+
+ case ListPopupMenu::mt_Down:
+ tabDown();
+ break;
+
+ default:
+ UMLWidget::slotMenuSelection(sel);
+ break;
+ }
+}
+
+QSize ObjectWidget::calculateSize() {
+ int width, height;
+ const QFontMetrics &fm = getFontMetrics(FT_UNDERLINE);
+ const int fontHeight = fm.lineSpacing();
+ const QString t = m_InstanceName + " : " + m_pObject->getName();
+ const int textWidth = fm.width(t);
+ if ( m_bDrawAsActor ) {
+ width = textWidth > A_WIDTH?textWidth:A_WIDTH;
+ height = A_HEIGHT + fontHeight + A_MARGIN;
+ width += A_MARGIN * 2;
+ } else {
+ width = textWidth > O_WIDTH?textWidth:O_WIDTH;
+ height = fontHeight + O_MARGIN * 2;
+ width += O_MARGIN * 2;
+ if (m_bMultipleInstance) {
+ width += 10;
+ height += 10;
+ }
+ }//end else drawasactor
+
+ return QSize(width, height);
+}
+
+void ObjectWidget::setDrawAsActor( bool drawAsActor ) {
+ m_bDrawAsActor = drawAsActor;
+ updateComponentSize();
+}
+
+void ObjectWidget::setMultipleInstance(bool multiple) {
+ //make sure only calling this in relation to an object on a collab. diagram
+ if(m_pView -> getType() != Uml::dt_Collaboration)
+ return;
+ m_bMultipleInstance = multiple;
+ updateComponentSize();
+ update();
+}
+
+bool ObjectWidget::activate(IDChangeLog* ChangeLog /*= 0*/) {
+ if (! UMLWidget::activate(ChangeLog))
+ return false;
+ if (m_bShowDestruction && m_pLine)
+ m_pLine->setupDestructionBox();
+ moveEvent(0);
+ return true;
+}
+
+void ObjectWidget::setX( int x ) {
+ UMLWidget::setX(x);
+ moveEvent(0);
+}
+
+void ObjectWidget::setY( int y ) {
+ UMLWidget::setY(y);
+ moveEvent(0);
+}
+
+void ObjectWidget::moveEvent(QMoveEvent */*m*/) {
+ emit sigWidgetMoved( m_nLocalID );
+ if (m_pLine) {
+ const int x = getX(); // for debugging: gdb has a problem evaluating getX() etc
+ const int w = width();
+ const int y = getY();
+ const int h = height();
+ m_pLine->setStartPoint(x + w / 2, y + h);
+ }
+}
+
+void ObjectWidget::slotColorChanged(Uml::IDType /*viewID*/) {
+ UMLWidget::setFillColour( m_pView->getFillColor() );
+ UMLWidget::setLineColor( m_pView->getLineColor() );
+
+ if( m_pLine)
+ m_pLine -> setPen( QPen( UMLWidget::getLineColor(), UMLWidget::getLineWidth(), Qt::DashLine ) );
+}
+
+void ObjectWidget::cleanup() {
+
+ UMLWidget::cleanup();
+ if( m_pLine ) {
+ m_pLine -> cleanup();
+ delete m_pLine;
+ }
+}
+
+void ObjectWidget::showProperties() {
+ DocWindow *docwindow = UMLApp::app()->getDocWindow();
+ docwindow->updateDocumentation(false);
+ ClassPropDlg *dlg = new ClassPropDlg((QWidget*)UMLApp::app(), this);
+ if (dlg->exec()) {
+ docwindow->showDocumentation(this, true);
+ UMLApp::app()->getDocument()->setModified(true);
+ }
+ dlg->close(true);//wipe from memory
+}
+
+void ObjectWidget::drawObject(QPainter & p, int offsetX, int offsetY) {
+
+ QFont oldFont = p.font();
+ QFont font = UMLWidget::getFont();
+ font.setUnderline( true );
+ p.setFont( font );
+
+ UMLWidget::setPen(p);
+ if(UMLWidget::getUseFillColour())
+ p.setBrush(UMLWidget::getFillColour());
+ else
+ p.setBrush(m_pView -> viewport() -> backgroundColor());
+ const int w = width();
+ const int h = height();
+
+ const QString t = m_InstanceName + " : " + m_pObject -> getName();
+ int multiInstOfst = 0;
+ if ( m_bMultipleInstance ) {
+ p.drawRect(offsetX + 10, offsetY + 10, w - 10, h - 10);
+ p.drawRect(offsetX + 5, offsetY + 5, w - 10, h - 10);
+ multiInstOfst = 10;
+ }
+ p.drawRect(offsetX, offsetY, w - multiInstOfst, h - multiInstOfst);
+ p.setPen(QPen(Qt::black));
+ p.drawText(offsetX + O_MARGIN, offsetY + O_MARGIN,
+ w - O_MARGIN * 2 - multiInstOfst, h - O_MARGIN * 2 - multiInstOfst,
+ Qt::AlignCenter, t);
+
+ p.setFont( oldFont );
+}
+
+void ObjectWidget::drawActor(QPainter & p, int offsetX, int offsetY) {
+ const QFontMetrics &fm = getFontMetrics(FT_UNDERLINE);
+
+ UMLWidget::setPen(p);
+ if ( UMLWidget::getUseFillColour() )
+ p.setBrush( UMLWidget::getFillColour() );
+ const int w = width();
+ const int textStartY = A_HEIGHT + A_MARGIN;
+ const int fontHeight = fm.lineSpacing();
+
+ const int middleX = offsetX + w / 2;
+ const int thirdH = A_HEIGHT / 3;
+
+ //draw actor
+ p.drawEllipse(middleX - A_WIDTH / 2, offsetY, A_WIDTH, thirdH);//head
+ p.drawLine(middleX, offsetY + thirdH, middleX, offsetY + thirdH * 2);//body
+ p.drawLine(middleX, offsetY + 2 * thirdH,
+ middleX - A_WIDTH / 2, offsetY + A_HEIGHT);//left leg
+ p.drawLine(middleX, offsetY + 2 * thirdH,
+ middleX + A_WIDTH / 2, offsetY + A_HEIGHT);//right leg
+ p.drawLine(middleX - A_WIDTH / 2, offsetY + thirdH + thirdH / 2,
+ middleX + A_WIDTH / 2, offsetY + thirdH + thirdH / 2);//arms
+ //draw text
+ p.setPen(QPen(Qt::black));
+ QString t = m_InstanceName + " : " + m_pObject -> getName();
+ p.drawText(offsetX + A_MARGIN, offsetY + textStartY,
+ w - A_MARGIN * 2, fontHeight, Qt::AlignCenter, t);
+}
+
+void ObjectWidget::tabUp() {
+ int newY = getY() - height();
+ if (newY < topMargin())
+ newY = topMargin();
+ setY( newY );
+ moveEvent( 0 );
+ adjustAssocs( getX(), newY);
+}
+
+void ObjectWidget::tabDown() {
+ int newY = getY() + height();
+ setY( newY );
+ moveEvent( 0 );
+ adjustAssocs( getX(), newY);
+}
+
+int ObjectWidget::topMargin() {
+ return 80 - height();
+}
+
+bool ObjectWidget::canTabUp() {
+ int y = getY();
+ //kDebug() << "ObjectWidget::canTabUp: y is " << y << endl;
+ return (y > topMargin());
+}
+
+void ObjectWidget::setShowDestruction( bool bShow ) {
+ m_bShowDestruction = bShow;
+ if( m_pLine )
+ m_pLine -> setupDestructionBox();
+}
+
+int ObjectWidget::getEndLineY() {
+ int y = this -> getY() + getHeight();
+ if( m_pLine)
+ y += m_pLine -> getLineLength();
+ if ( m_bShowDestruction )
+ y += 10;
+ return y;
+}
+
+void ObjectWidget::messageAdded(MessageWidget* message) {
+ if (messageWidgetList.containsRef(message) ) {
+ kError() << "ObjectWidget::messageAdded("
+ << message->getName() << ") : duplicate entry !"
+ << endl;
+ return ;
+ }
+ messageWidgetList.append(message);
+}
+
+void ObjectWidget::messageRemoved(MessageWidget* message) {
+ if ( messageWidgetList.remove(message) == false ) {
+ kError() << "ObjectWidget::messageRemoved("
+ << message->getName() << ") : missing entry !"
+ << endl;
+ return ;
+ }
+}
+
+void ObjectWidget::slotMessageMoved() {
+ MessageWidgetListIt iterator(messageWidgetList);
+ MessageWidget* message;
+ int lowestMessage = 0;
+ while ( (message = iterator.current()) != 0 ) {
+ ++iterator;
+ int messageHeight = message->getY() + message->getHeight();
+ if (lowestMessage < messageHeight) {
+ lowestMessage = messageHeight;
+ }
+ }
+ m_pLine->setEndOfLine(lowestMessage + sequenceLineMargin);
+}
+
+bool ObjectWidget::messageOverlap(int y, MessageWidget* messageWidget) {
+ MessageWidgetListIt iterator(messageWidgetList);
+ MessageWidget* message;
+ while ( (message = iterator.current()) != 0 ) {
+ ++iterator;
+ const int msgY = message->getY();
+ const int msgHeight = msgY + message->getHeight();
+ if (y >= msgY && y <= msgHeight && message != messageWidget) {
+ return true;
+ }
+ }
+ return false;
+}
+
+SeqLineWidget *ObjectWidget::getSeqLine() {
+ return m_pLine;
+}
+
+void ObjectWidget::saveToXMI( QDomDocument & qDoc, QDomElement & qElement ) {
+ QDomElement objectElement = qDoc.createElement( "objectwidget" );
+ UMLWidget::saveToXMI( qDoc, objectElement );
+ objectElement.setAttribute( "instancename", m_InstanceName );
+ objectElement.setAttribute( "drawasactor", m_bDrawAsActor );
+ objectElement.setAttribute( "multipleinstance", m_bMultipleInstance );
+ objectElement.setAttribute( "localid", ID2STR(m_nLocalID) );
+ objectElement.setAttribute( "decon", m_bShowDestruction );
+ qElement.appendChild( objectElement );
+}
+
+bool ObjectWidget::loadFromXMI( QDomElement & qElement ) {
+ if( !UMLWidget::loadFromXMI( qElement ) )
+ return false;
+ m_InstanceName = qElement.attribute( "instancename", "" );
+ QString draw = qElement.attribute( "drawasactor", "0" );
+ QString multi = qElement.attribute( "multipleinstance", "0" );
+ QString localid = qElement.attribute( "localid", "0" );
+ QString decon = qElement.attribute( "decon", "0" );
+
+ m_bDrawAsActor = (bool)draw.toInt();
+ m_bMultipleInstance = (bool)multi.toInt();
+ m_nLocalID = STR2ID(localid);
+ m_bShowDestruction = (bool)decon.toInt();
+ return true;
+
+}
+
+#include "objectwidget.moc"
diff --git a/umbrello/umbrello/objectwidget.h b/umbrello/umbrello/objectwidget.h
new file mode 100644
index 00000000..bbf63053
--- /dev/null
+++ b/umbrello/umbrello/objectwidget.h
@@ -0,0 +1,331 @@
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * copyright (C) 2002-2007 *
+ * Umbrello UML Modeller Authors <uml-devel@uml.sf.net> *
+ ***************************************************************************/
+
+#ifndef OBJECTWIDGET_H
+#define OBJECTWIDGET_H
+
+#define O_MARGIN 5
+#define O_WIDTH 40
+#define A_WIDTH 20
+#define A_HEIGHT 40
+#define A_MARGIN 5
+
+#include "messagewidgetlist.h"
+#include "messagewidget.h"
+
+
+class SeqLineWidget;
+
+/**
+ * Displays an instance UMLObject of a concept.
+ *
+ * @short Displays an instance of a Concept.
+ * @author Paul Hensgen <phensgen@techie.com>
+ * @see UMLWidget
+ * Bugs and comments to uml-devel@lists.sf.net or http://bugs.kde.org
+ */
+class ObjectWidget : public UMLWidget {
+ Q_OBJECT
+public:
+ /**
+ * Creates an ObjectWidget.
+ *
+ * @param view The parent to this object.
+ * @param o The object it will be representing.
+ * @param lid The local id for the object.
+ */
+ ObjectWidget(UMLView * view, UMLObject *o, Uml::IDType lid = Uml::id_None );
+
+ /**
+ * destructor
+ */
+ virtual ~ObjectWidget();
+
+ /**
+ * Sets the x-coordinate.
+ * Reimplements the method from UMLWidget.
+ *
+ * @param x The x-coordinate to be set.
+ */
+ virtual void setX( int x );
+
+ /**
+ * Sets the y-coordinate.
+ * Reimplements the method from UMLWidget.
+ *
+ * @param y The y-coordinate to be set.
+ */
+ virtual void setY( int y );
+
+ /**
+ * Returns the local ID for this object. This ID is used so that
+ * many objects of the same @ref UMLObject instance can be on the
+ * same diagram.
+ *
+ * @return The local ID.
+ */
+ Uml::IDType getLocalID() const {
+ return m_nLocalID;
+ }
+
+ /**
+ * Returns the instance name.
+ *
+ * @return The instance name.
+ */
+ QString getInstanceName() const {
+ return m_InstanceName;
+ }
+
+ /**
+ * Sets the instance name.
+ *
+ * @param name The name to set the instance name to.
+ */
+ void setInstanceName(const QString &name) {
+ m_InstanceName = name;
+ }
+
+ /**
+ * Returns whether object is representing a multi-object.
+ *
+ * @return True if object is representing a multi-object.
+ */
+ bool getMultipleInstance() const {
+ return m_bMultipleInstance;
+ }
+
+ /**
+ * Sets whether representing a multi-instance object.
+ *
+ * @param multiple Object state. true- multi, false - single.
+ */
+ void setMultipleInstance(bool multiple);
+
+ /**
+ * Sets the local id of the object.
+ *
+ * @param id The local id of the object.
+ */
+ void setLocalID(Uml::IDType id) {
+ m_nLocalID = id;
+ }
+
+ /**
+ * Activate the object after serializing it from a QDataStream
+ */
+ bool activate(IDChangeLog* ChangeLog = 0);
+
+ /**
+ * Override default method.
+ */
+ void draw(QPainter & p, int offsetX, int offsetY);
+
+ /**
+ * Overrides the standard operation.
+ */
+ virtual void moveEvent(QMoveEvent */*m*/);
+
+ /**
+ * Used to cleanup any other widget it may need to delete.
+ */
+ void cleanup();
+
+ /**
+ * Show a properties dialog for an ObjectWidget.
+ */
+ void showProperties();
+
+ /**
+ * Returns whether to draw as an Actor or not.
+ *
+ * @return True if widget is drawn as an actor.
+ */
+ bool getDrawAsActor() const {
+ return m_bDrawAsActor;
+ }
+
+ /**
+ * Sets whether to draw as an Actor.
+ *
+ * @param drawAsActor True if widget shall be drawn as an actor.
+ */
+ void setDrawAsActor( bool drawAsActor );
+
+ /**
+ * Sets whether to show deconstruction on sequence line.
+ *
+ * @param bShow True if destruction on line shall be shown.
+ */
+ void setShowDestruction( bool bShow );
+
+ /**
+ * Returns whether to show deconstruction on sequence line.
+ *
+ * @return True if destruction on sequence line is shown.
+ */
+ bool getShowDestruction() const {
+ return m_bShowDestruction;
+ }
+
+ /**
+ * Returns the top margin constant (Y axis value)
+ *
+ * @return Y coordinate of the space between the diagram top
+ * and the upper edge of the ObjectWidget.
+ */
+ int topMargin();
+
+ /**
+ * Returns the end Y co-ord of the seq. line.
+ *
+ * @return Y coordinate of the endpoint of the sequence line.
+ */
+ int getEndLineY();
+
+ /**
+ * Add a message widget to the list.
+ *
+ * @param message Pointer to the MessageWidget to add.
+ */
+ void messageAdded(MessageWidget* message);
+
+ /**
+ * Remove a message widget from the list.
+ *
+ * @param message Pointer to the MessageWidget to remove.
+ */
+ void messageRemoved(MessageWidget* message);
+
+ /**
+ * Returns whether or not the widget can be moved vertically up.
+ *
+ * @return True if widget can be moved upwards vertically.
+ */
+ bool canTabUp();
+
+ /**
+ * Returns whether a message is overlapping with another message.
+ * Used by MessageWidget::draw() methods.
+ *
+ * @param y The top of your message.
+ * @param messageWidget A pointer to your message so it doesn't
+ * check against itself.
+ */
+ bool messageOverlap(int y, MessageWidget* messageWidget);
+
+ /**
+ * Return the SeqLineWidget.
+ * Returns a non NULL pointer if this ObjectWidget is part of a
+ * sequence diagram.
+ */
+ SeqLineWidget *getSeqLine();
+
+ /**
+ * Saves to the "objectwidget" XMI element.
+ */
+ void saveToXMI( QDomDocument & qDoc, QDomElement & qElement );
+
+ /**
+ * Loads from a "objectwidget" XMI element.
+ */
+ bool loadFromXMI( QDomElement & qElement );
+
+public slots:
+ /**
+ * Handles a popup menu selection.
+ */
+ void slotMenuSelection(int sel);
+
+ /**
+ * Handles a color change signal.
+ */
+ virtual void slotColorChanged(Uml::IDType viewID);
+
+ /**
+ * Called when a message widget with an end on this object has
+ * moved up or down.
+ * Sets the bottom of the line to a nice position.
+ */
+ void slotMessageMoved();
+
+protected:
+ SeqLineWidget * m_pLine;
+
+ /**
+ * Overrides method from UMLWidget
+ */
+ QSize calculateSize();
+
+ /**
+ * Draw the object as an actor.
+ */
+ void drawActor(QPainter & p, int offsetX, int offsetY);
+
+ /**
+ * Draw the object as an object (default).
+ */
+ void drawObject(QPainter & p, int offsetX, int offsetY);
+
+ /**
+ * Move the object up on a sequence diagram.
+ */
+ void tabUp();
+
+ /**
+ * Move the object down on a sequence diagram.
+ */
+ void tabDown();
+
+ // Data loaded/saved:
+
+ /**
+ * Instance name of object.
+ */
+ QString m_InstanceName;
+
+ /**
+ * Local ID used on views. Needed as a it can represent a class
+ * that has many objects representing it.
+ */
+ Uml::IDType m_nLocalID;
+
+ /**
+ * Determines whether to draw an object as a multiple object
+ * instance.
+ */
+ bool m_bMultipleInstance;
+
+ /**
+ * Determines whether the object should be drawn as an Actor or
+ * an Object.
+ */
+ bool m_bDrawAsActor;
+
+ /**
+ * Determines whether to show object destruction on sequence
+ * diagram line.
+ */
+ bool m_bShowDestruction;
+
+private:
+ /**
+ * Initializes the key attributes of the class.
+ */
+ void init();
+
+ /**
+ * A list of the message widgets with an end on this widget.
+ */
+ MessageWidgetList messageWidgetList;
+};
+
+#endif
diff --git a/umbrello/umbrello/objectwidgetcontroller.cpp b/umbrello/umbrello/objectwidgetcontroller.cpp
new file mode 100644
index 00000000..1594b3fa
--- /dev/null
+++ b/umbrello/umbrello/objectwidgetcontroller.cpp
@@ -0,0 +1,44 @@
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * copyright (C) 2006-2007 *
+ * Umbrello UML Modeller Authors <uml-devel@uml.sf.net> *
+ ***************************************************************************/
+
+// own header
+#include "objectwidgetcontroller.h"
+
+// kde includes
+#include <kcursor.h>
+
+// app includes
+#include "objectwidget.h"
+#include "listpopupmenu.h"
+
+
+ObjectWidgetController::ObjectWidgetController(ObjectWidget* objectWidget):
+ UMLWidgetController(objectWidget) {
+}
+
+ObjectWidgetController::~ObjectWidgetController() {
+}
+
+QCursor ObjectWidgetController::getResizeCursor() {
+ return KCursor::sizeHorCursor();
+}
+
+void ObjectWidgetController::resizeWidget(int newW, int newH) {
+ m_widget->setSize(newW, m_widget->getHeight());
+}
+
+void ObjectWidgetController::moveWidgetBy(int diffX, int diffY) {
+ m_widget->setX(m_widget->getX() + diffX);
+}
+
+void ObjectWidgetController::constrainMovementForAllWidgets(int &diffX, int &diffY) {
+ diffY = 0;
+}
diff --git a/umbrello/umbrello/objectwidgetcontroller.h b/umbrello/umbrello/objectwidgetcontroller.h
new file mode 100644
index 00000000..1d8d699a
--- /dev/null
+++ b/umbrello/umbrello/objectwidgetcontroller.h
@@ -0,0 +1,92 @@
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * copyright (C) 2006 *
+ * Umbrello UML Modeller Authors <uml-devel@uml.sf.net> *
+ ***************************************************************************/
+
+#ifndef OBJECTWIDGETCONTROLLER_H
+#define OBJECTWIDGETCONTROLLER_H
+
+#include "umlwidgetcontroller.h"
+
+class ObjectWidget;
+
+/**
+ * Controller for ObjectWidget.
+ *
+ * When moving an ObjectWidget, it is only moved along X axis. Y axis movement
+ * is always ignored.
+ * So, if the ObjectWidget is being moved as part of a selection and that
+ * selection is moved in X and/or Y axis, the ObjectWidget will only move in X axis.
+ * Also, when constraining the move of the selection because the receiver of
+ * mouse move events is an ObjectWidget, all the widgets are moved only in X axis.
+ *
+ * Only horizontal resize is allowed for ObjectWidget. Cursor is set to reflect this.
+ *
+ * @author Umbrello UML Modeller Authors <uml-devel@lists.sourceforge.net>
+ */
+class ObjectWidgetController : public UMLWidgetController {
+public:
+
+ /**
+ * Constructor for ObjectWidgetController.
+ *
+ * @param objectWidget The object widget which uses the controller.
+ */
+ ObjectWidgetController(ObjectWidget *objectWidget);
+
+ /**
+ * Destructor for ObjectWidgetController.
+ */
+ virtual ~ObjectWidgetController();
+
+protected:
+
+ /**
+ * Overriden from UMLWidgetController.
+ * Returns the cursor to be shown when resizing the widget.
+ * The cursor shown is KCursor::sizeHorCursor().
+ *
+ * @return The cursor to be shown when resizing the widget.
+ */
+ virtual QCursor getResizeCursor();
+
+ /**
+ * Overriden from UMLWidgetController.
+ * Resizes the width of the object widget.
+ * Object widgets can only be resized horizontally, so height isn't modified.
+ *
+ * @param newW The new width for the widget.
+ * @param newH The new height for the widget (isn't used).
+ */
+ virtual void resizeWidget(int newW, int newH);
+
+ /**
+ * Overriden from UMLWidgetController.
+ * Moves the widget to a new position using the difference between the
+ * current position and the new position.
+ * Y position is ignored, and widget is only moved along X axis.
+ *
+ * @param diffX The difference between current X position and new X position.
+ * @param diffY The difference between current Y position and new Y position
+ * (isn't used).
+ */
+ virtual void moveWidgetBy(int diffX, int diffY);
+
+ /**
+ * Overriden from UMLWidgetController.
+ * Modifies the value of the diffX and diffY variables used to move the widgets.
+ * All the widgets are constrained to be moved only in X axis (diffY is set to 0).
+ *
+ * @param diffX The difference between current X position and new X position.
+ * @param diffY The difference between current Y position and new Y position.
+ */
+ virtual void constrainMovementForAllWidgets(int &diffX, int &diffY);
+};
+
+#endif
diff --git a/umbrello/umbrello/operation.cpp b/umbrello/umbrello/operation.cpp
new file mode 100644
index 00000000..1052c469
--- /dev/null
+++ b/umbrello/umbrello/operation.cpp
@@ -0,0 +1,431 @@
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * copyright (C) 2002-2007 *
+ * Umbrello UML Modeller Authors <uml-devel@uml.sf.net> *
+ ***************************************************************************/
+
+// own header
+#include "operation.h"
+
+// qt/kde includes
+#include <qregexp.h>
+#include <kdebug.h>
+#include <klocale.h>
+
+// app includes
+#include "attribute.h"
+#include "classifier.h"
+#include "uml.h"
+#include "umldoc.h"
+#include "uniqueid.h"
+#include "dialogs/umloperationdialog.h"
+
+UMLOperation::UMLOperation(const UMLClassifier *parent, const QString& name,
+ Uml::IDType id, Uml::Visibility s, UMLObject *rt)
+ : UMLClassifierListItem(parent, name, id)
+{
+ if (rt)
+ m_returnId = UniqueID::gen();
+ else
+ m_returnId = Uml::id_None;
+ m_pSecondary = rt;
+ m_Vis = s;
+ m_BaseType = Uml::ot_Operation;
+ m_bConst = false;
+}
+
+UMLOperation::UMLOperation(const UMLClassifier * parent)
+ : UMLClassifierListItem (parent)
+{
+ m_BaseType = Uml::ot_Operation;
+ m_bConst = false;
+}
+
+UMLOperation::~UMLOperation() {
+}
+
+void UMLOperation::setType(UMLObject *type) {
+ UMLClassifierListItem::setType(type);
+ if (m_returnId == Uml::id_None)
+ m_returnId = UniqueID::gen();
+}
+
+void UMLOperation::moveParmLeft(UMLAttribute * a) {
+ if (a == NULL) {
+ kDebug() << "UMLOperation::moveParmLeft called on NULL attribute"
+ << endl;
+ return;
+ }
+ kDebug() << "UMLOperation::moveParmLeft(" << a->getName() << ") called"
+ << endl;
+ disconnect(a,SIGNAL(modified()),this,SIGNAL(modified()));
+ int idx;
+ if ( (idx=m_List.find( a )) == -1 ) {
+ kDebug() << "Error move parm left " << a->getName() << endl;
+ return;
+ }
+ if ( idx == 0 )
+ return;
+ m_List.remove( a );
+ m_List.insert( idx-1, a );
+}
+
+void UMLOperation::moveParmRight(UMLAttribute * a) {
+ if (a == NULL) {
+ kDebug() << "UMLOperation::moveParmRight called on NULL attribute"
+ << endl;
+ return;
+ }
+ kDebug() << "UMLOperation::moveParmRight(" << a->getName() << ") called"
+ << endl;
+ disconnect(a,SIGNAL(modified()),this,SIGNAL(modified()));
+ int idx;
+ if ( (idx=m_List.find( a )) == -1 ) {
+ kDebug() << "Error move parm right " << a->getName() << endl;
+ return;
+ }
+ int count = m_List.count();
+ if ( idx == count-1 )
+ return;
+ m_List.remove( a );
+ m_List.insert( idx+1, a );
+}
+
+void UMLOperation::removeParm(UMLAttribute * a, bool emitModifiedSignal /* =true */) {
+ if (a == NULL) {
+ kDebug() << "UMLOperation::removeParm called on NULL attribute"
+ << endl;
+ return;
+ }
+ kDebug() << "UMLOperation::removeParm(" << a->getName() << ") called"
+ << endl;
+ disconnect(a,SIGNAL(modified()),this,SIGNAL(modified()));
+ if(!m_List.remove(a))
+ kDebug() << "Error removing parm " << a->getName() << endl;
+
+ if (emitModifiedSignal)
+ emit modified();
+}
+
+UMLAttribute* UMLOperation::findParm(const QString &name) {
+ UMLAttribute * obj=0;
+ for (obj = m_List.first(); obj; obj = m_List.next()) {
+ if (obj->getName() == name)
+ return obj;
+ }
+ return 0;
+}
+
+QString UMLOperation::toString(Uml::Signature_Type sig) {
+ QString s = "";
+
+ if(sig == Uml::st_ShowSig || sig == Uml::st_NoSig)
+ s = m_Vis.toString(true) + ' ';
+
+ s += getName();
+ Uml::Programming_Language pl = UMLApp::app()->getActiveLanguage();
+ bool parameterlessOpNeedsParentheses = (pl != Uml::pl_Pascal && pl != Uml::pl_Ada);
+
+ if (sig == Uml::st_NoSig || sig == Uml::st_NoSigNoVis) {
+ if (parameterlessOpNeedsParentheses)
+ s.append("()");
+ return s;
+ }
+ int last = m_List.count();
+ if (last) {
+ s.append("(");
+ int i = 0;
+ for (UMLAttribute *param = m_List.first(); param; param = m_List.next()) {
+ i++;
+ s.append(param->toString(Uml::st_SigNoVis));
+ if (i < last)
+ s.append(", ");
+ }
+ s.append(")");
+ } else if (parameterlessOpNeedsParentheses) {
+ s.append("()");
+ }
+ UMLClassifier *ownParent = static_cast<UMLClassifier*>(parent());
+ QString returnType;
+ UMLClassifier *retType = UMLClassifierListItem::getType();
+ if (retType) {
+ UMLPackage *retVisibility = retType->getUMLPackage();
+ if (retVisibility != ownParent && retVisibility != ownParent->getUMLPackage())
+ returnType = retType->getFullyQualifiedName();
+ else
+ returnType = retType->getName();
+ }
+ if (returnType.length() > 0 && returnType != "void") {
+ s.append(" : ");
+
+ if (returnType.startsWith("virtual ")) {
+ s += returnType.mid(8);
+ } else {
+ s += returnType;
+ }
+ }
+ return s;
+}
+
+void UMLOperation::addParm(UMLAttribute *parameter, int position) {
+ if( position >= 0 && position <= (int)m_List.count() )
+ m_List.insert(position,parameter);
+ else
+ m_List.append( parameter );
+ UMLObject::emitModified();
+ connect(parameter,SIGNAL(modified()),this,SIGNAL(modified()));
+}
+
+QString UMLOperation::getUniqueParameterName() {
+ QString currentName = i18n("new_parameter");
+ QString name = currentName;
+ for (int number = 1; findParm(name); number++) {
+ name = currentName + '_' + QString::number(number);
+ }
+ return name;
+}
+
+bool UMLOperation::operator==( UMLOperation & rhs ) {
+ if( this == &rhs )
+ return true;
+
+ if( !UMLObject::operator==( rhs ) )
+ return false;
+
+ if( getTypeName() != rhs.getTypeName() )
+ return false;
+
+ if( m_List.count() != rhs.m_List.count() )
+ return false;
+
+ if(!(m_List == rhs.m_List))
+ return false;
+
+ return true;
+}
+
+void UMLOperation::copyInto(UMLOperation *rhs) const
+{
+ UMLClassifierListItem::copyInto(rhs);
+
+ m_List.copyInto(&(rhs->m_List));
+}
+
+UMLObject* UMLOperation::clone() const
+{
+ //FIXME: The new operation should be slaved to the NEW parent not the old.
+ UMLOperation *clone = new UMLOperation( static_cast<UMLClassifier*>(parent()) );
+ copyInto(clone);
+
+ return clone;
+}
+
+bool UMLOperation::resolveRef() {
+ bool overallSuccess = UMLObject::resolveRef();
+ // See remark on iteration style in UMLClassifier::resolveRef()
+ for (UMLAttributeListIt ait(m_List); ait.current(); ++ait) {
+ UMLAttribute *pAtt = ait.current();
+ if (! pAtt->resolveRef())
+ overallSuccess = false;
+ }
+ return overallSuccess;
+}
+
+bool UMLOperation::isConstructorOperation() {
+ // if an operation has the stereotype constructor
+ // return true
+ QString strConstructor ("constructor");
+ if (getStereotype() == strConstructor)
+ return true;
+
+ UMLClassifier * c = static_cast<UMLClassifier*>(this->parent());
+ QString cName = c->getName();
+ QString opName = getName();
+ // It's a constructor operation if the operation name
+ // matches that of the parent classifier.
+ return (cName == opName);
+}
+
+bool UMLOperation::isDestructorOperation() {
+ if (getStereotype() == "destructor")
+ return true;
+ UMLClassifier * c = static_cast<UMLClassifier*>(this->parent());
+
+ QString cName = c->getName();
+ QString opName = getName();
+ // Special support for C++ syntax:
+ // It's a destructor operation if the operation name begins
+ // with "~" followed by the name of the parent classifier.
+ if (! opName.startsWith("~"))
+ return false;
+ opName.remove( QRegExp("^~\\s*") );
+ return (cName == opName);
+}
+
+bool UMLOperation::isLifeOperation() {
+ return (isConstructorOperation() || isDestructorOperation());
+}
+
+void UMLOperation::setConst(bool b) {
+ m_bConst = b;
+}
+
+bool UMLOperation::getConst() const {
+ return m_bConst;
+}
+
+bool UMLOperation::showPropertiesDialog(QWidget* parent) {
+ UMLOperationDialog dialog(parent, this);
+ return dialog.exec();
+}
+
+void UMLOperation::saveToXMI( QDomDocument & qDoc, QDomElement & qElement ) {
+ QDomElement operationElement = UMLObject::save("UML:Operation", qDoc);
+ operationElement.setAttribute( "isQuery", m_bConst ? "true" : "false" );
+ QDomElement featureElement = qDoc.createElement( "UML:BehavioralFeature.parameter" );
+ if (m_pSecondary) {
+ QDomElement retElement = qDoc.createElement("UML:Parameter");
+ if (m_returnId == Uml::id_None) {
+ kDebug() << "UMLOperation::saveToXMI(" << m_Name
+ << "): m_returnId is not set, setting it now." << endl;
+ m_returnId = UniqueID::gen();
+ }
+ retElement.setAttribute( "xmi.id", ID2STR(m_returnId) );
+ retElement.setAttribute( "type", ID2STR(m_pSecondary->getID()) );
+ retElement.setAttribute( "kind", "return" );
+ featureElement.appendChild( retElement );
+ } else {
+ kDebug() << "UMLOperation::saveToXMI: m_SecondaryId is "
+ << m_SecondaryId << endl;
+ }
+ //save each attribute here, type different
+ UMLAttribute* pAtt = 0;
+ for( pAtt = m_List.first(); pAtt != 0; pAtt = m_List.next() ) {
+ QDomElement attElement = pAtt->UMLObject::save("UML:Parameter", qDoc);
+ UMLClassifier *attrType = pAtt->getType();
+ if (attrType) {
+ attElement.setAttribute( "type", ID2STR(attrType->getID()) );
+ } else {
+ attElement.setAttribute( "type", pAtt -> getTypeName() );
+ }
+ attElement.setAttribute( "value", pAtt -> getInitialValue() );
+
+ Uml::Parameter_Direction kind = pAtt->getParmKind();
+ if (kind == Uml::pd_Out)
+ attElement.setAttribute("kind", "out");
+ else if (kind == Uml::pd_InOut)
+ attElement.setAttribute("kind", "inout");
+ // The default for the parameter kind is "in".
+
+ featureElement.appendChild( attElement );
+ }
+ if (featureElement.hasChildNodes())
+ operationElement.appendChild( featureElement );
+ qElement.appendChild( operationElement );
+}
+
+bool UMLOperation::load( QDomElement & element ) {
+ m_SecondaryId = element.attribute( "type", "" );
+ QString isQuery = element.attribute( "isQuery", "" );
+ if (!isQuery.isEmpty()) {
+ // We need this extra test for isEmpty() because load() might have been
+ // called again by the processing for BehavioralFeature.parameter (see below)
+ m_bConst = (isQuery == "true");
+ }
+ QDomNode node = element.firstChild();
+ if (node.isComment())
+ node = node.nextSibling();
+ QDomElement attElement = node.toElement();
+ while( !attElement.isNull() ) {
+ QString tag = attElement.tagName();
+ if (Uml::tagEq(tag, "BehavioralFeature.parameter")) {
+ if (! load(attElement))
+ return false;
+ } else if (Uml::tagEq(tag, "Parameter")) {
+ QString kind = attElement.attribute("kind", "");
+ if (kind.isEmpty()) {
+ // Perhaps the kind is stored in a child node:
+ for (QDomNode n = attElement.firstChild(); !n.isNull(); n = n.nextSibling()) {
+ if (n.isComment())
+ continue;
+ QDomElement tempElement = n.toElement();
+ QString tag = tempElement.tagName();
+ if (!Uml::tagEq(tag, "kind"))
+ continue;
+ kind = tempElement.attribute( "xmi.value", "" );
+ break;
+ }
+ if (kind.isEmpty()) {
+ // kDebug() << "UMLOperation::load(" << m_Name << "): "
+ // << "cannot find kind, using default \"in\"." << endl;
+ kind = "in";
+ }
+ }
+ if (kind == "return") {
+ QString returnId = attElement.attribute("xmi.id", "");
+ if (!returnId.isEmpty())
+ m_returnId = STR2ID(returnId);
+ m_SecondaryId = attElement.attribute( "type", "" );
+ if (m_SecondaryId.isEmpty()) {
+ // Perhaps the type is stored in a child node:
+ QDomNode node = attElement.firstChild();
+ while (!node.isNull()) {
+ if (node.isComment()) {
+ node = node.nextSibling();
+ continue;
+ }
+ QDomElement tempElement = node.toElement();
+ QString tag = tempElement.tagName();
+ if (!Uml::tagEq(tag, "type")) {
+ node = node.nextSibling();
+ continue;
+ }
+ m_SecondaryId = tempElement.attribute( "xmi.id", "" );
+ if (m_SecondaryId.isEmpty())
+ m_SecondaryId = tempElement.attribute( "xmi.idref", "" );
+ if (m_SecondaryId.isEmpty()) {
+ QDomNode inner = node.firstChild();
+ QDomElement tmpElem = inner.toElement();
+ m_SecondaryId = tmpElem.attribute( "xmi.id", "" );
+ if (m_SecondaryId.isEmpty())
+ m_SecondaryId = tmpElem.attribute( "xmi.idref", "" );
+ }
+ break;
+ }
+ if (m_SecondaryId.isEmpty()) {
+ kError() << "UMLOperation::load(" << m_Name << "): "
+ << "cannot find return type." << endl;
+ }
+ }
+ // Use deferred xmi.id resolution.
+ m_pSecondary = NULL;
+ } else {
+ UMLAttribute * pAtt = new UMLAttribute( this );
+ if( !pAtt->loadFromXMI(attElement) ) {
+ delete pAtt;
+ return false;
+ }
+ if (kind == "out")
+ pAtt->setParmKind(Uml::pd_Out);
+ else if (kind == "inout")
+ pAtt->setParmKind(Uml::pd_InOut);
+ else
+ pAtt->setParmKind(Uml::pd_In);
+ m_List.append( pAtt );
+ }
+ }
+ node = node.nextSibling();
+ if (node.isComment())
+ node = node.nextSibling();
+ attElement = node.toElement();
+ }//end while
+ return true;
+}
+
+
+#include "operation.moc"
diff --git a/umbrello/umbrello/operation.h b/umbrello/umbrello/operation.h
new file mode 100644
index 00000000..eb94576e
--- /dev/null
+++ b/umbrello/umbrello/operation.h
@@ -0,0 +1,209 @@
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * copyright (C) 2002-2006 *
+ * Umbrello UML Modeller Authors <uml-devel@uml.sf.net> *
+ ***************************************************************************/
+
+#ifndef OPERATION_H
+#define OPERATION_H
+
+#include "umlattributelist.h"
+#include "classifierlistitem.h"
+
+class UMLClassifier;
+
+/**
+ * This class represents an operation in the UML model.
+ *
+ * Bugs and comments to uml-devel@lists.sf.net or http://bugs.kde.org
+ */
+class UMLOperation : public UMLClassifierListItem {
+ Q_OBJECT
+public:
+ /**
+ * Constructs an UMLOperation.
+ * Not intended for general use: The operation is not tied in with
+ * umbrello's Qt signalling for object creation.
+ * If you want to create an Operation use the method in UMLDoc instead.
+ *
+ * @param parent The parent to this operation.
+ * @param name The name of the operation.
+ * @param id The id of the operation.
+ * @param s The visibility of the operation.
+ * @param rt The return type of the operation.
+ */
+ UMLOperation(const UMLClassifier * parent, const QString& name,
+ Uml::IDType id = Uml::id_None,
+ Uml::Visibility s = Uml::Visibility::Public,
+ UMLObject *rt = 0);
+
+ /**
+ * Constructs an UMLOperation.
+ * Not intended for general use: The operation is not tied in with
+ * umbrello's Qt signalling for object creation.
+ * If you want to create an Operation use the method in UMLDoc instead.
+ *
+ * @param parent The parent to this operation.
+ */
+ UMLOperation(const UMLClassifier * parent);
+public:
+
+ /**
+ * destructor
+ */
+ virtual ~UMLOperation();
+
+ /**
+ * Overloaded '==' operator.
+ */
+ bool operator==( UMLOperation & rhs );
+
+ /**
+ * Copy the internal presentation of this object into the new
+ * object.
+ */
+ virtual void copyInto(UMLOperation *rhs) const;
+
+ /**
+ * Make a clone of this object.
+ */
+ virtual UMLObject* clone() const;
+
+ /**
+ * Reimplement method from UMLClassifierListItem.
+ *
+ * @param type Pointer to the type object.
+ */
+ void setType(UMLObject *type);
+
+ /**
+ * Move a parameter one position to the left.
+ *
+ * @param a The parameter to move.
+ */
+ void moveParmLeft(UMLAttribute *a);
+
+ /**
+ *Move a parameter one position to the right.
+ *
+ * @param a The parameter to move.
+ */
+ void moveParmRight(UMLAttribute *a);
+
+ /**
+ * Remove a parameter from the operation.
+ *
+ * @param a The parameter to remove.
+ * @param emitModifiedSignal Whether to emit the "modified" signal
+ * which creates an entry in the Undo stack for the
+ * removal. Default: true.
+ */
+ void removeParm(UMLAttribute *a, bool emitModifiedSignal = true);
+
+ /**
+ * Returns a list of parameters.
+ *
+ * @return A list of the parameters in the operation.
+ */
+ UMLAttributeList getParmList() {
+ return m_List;
+ }
+
+ /**
+ * Finds a parameter of the operation.
+ *
+ * @param name The parameter name to search for.
+ * @return The found parameter, 0 if not found.
+ */
+ UMLAttribute * findParm(const QString &name);
+
+ /**
+ * Returns a string representation of the operation.
+ *
+ * @param sig What type of operation string to show.
+ * @return The string representation of the operation.
+ */
+ QString toString(Uml::Signature_Type sig = Uml::st_NoSig);
+
+ /**
+ * Add a parameter to the operation.
+ *
+ * @param parameter The parameter to add.
+ * @param position The position in the parameter list.
+ * If position = -1 the parameter will be
+ * appended to the list.
+ */
+ void addParm(UMLAttribute *parameter, int position = -1);
+
+ /**
+ * Calls resolveRef() on all parameters.
+ * Needs to be called after all UML objects are loaded from file.
+ *
+ * @return True for success.
+ */
+ bool resolveRef();
+
+ /**
+ * Returns an unused parameter name for a new parameter.
+ */
+ QString getUniqueParameterName();
+
+ /**
+ * Display the properties configuration dialog for the template.
+ */
+ bool showPropertiesDialog(QWidget* parent);
+
+ /**
+ * Returns whether this operation is a constructor.
+ *
+ * @return True if this operation is a constructor.
+ */
+ bool isConstructorOperation();
+
+ /**
+ * Returns whether this operation is a destructor.
+ *
+ * @return True if this operation is a destructor.
+ */
+ bool isDestructorOperation();
+
+ /**
+ * Shortcut for (isConstructorOperation() || isDestructorOperation())
+ *
+ * @return True if this operation is a constructor or destructor.
+ */
+ bool isLifeOperation();
+
+ /**
+ * Sets whether this operation is a query (C++ "const".)
+ */
+ void setConst(bool b);
+
+ /**
+ * Returns whether this operation is a query (C++ "const".)
+ */
+ bool getConst() const;
+
+ /**
+ * Saves to the <UML:Operation> XMI element.
+ */
+ void saveToXMI( QDomDocument & qDoc, QDomElement & qElement );
+
+protected:
+ /**
+ * Loads a <UML:Operation> XMI element.
+ */
+ bool load( QDomElement & element );
+
+private:
+ Uml::IDType m_returnId; ///< Holds the xmi.id of the <UML:Parameter kind="return">
+ UMLAttributeList m_List; /// Parameter list
+ bool m_bConst; ///< Holds the isQuery attribute of the <UML:Operation>
+};
+
+#endif
diff --git a/umbrello/umbrello/optionstate.cpp b/umbrello/umbrello/optionstate.cpp
new file mode 100644
index 00000000..16daef83
--- /dev/null
+++ b/umbrello/umbrello/optionstate.cpp
@@ -0,0 +1,27 @@
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * copyright (C) 2006 *
+ * Umbrello UML Modeller Authors <uml-devel@uml.sf.net> *
+ ***************************************************************************/
+
+#include "optionstate.h"
+
+namespace Settings{
+
+OptionState pd_optionState;
+
+OptionState& getOptionState() {
+ return pd_optionState;
+}
+
+void setOptionState(const OptionState& optstate) {
+ pd_optionState = optstate;
+}
+
+} // namespace Settings
+
diff --git a/umbrello/umbrello/optionstate.h b/umbrello/umbrello/optionstate.h
new file mode 100644
index 00000000..b8429f62
--- /dev/null
+++ b/umbrello/umbrello/optionstate.h
@@ -0,0 +1,81 @@
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * copyright (C) 2002-2006 *
+ * Umbrello UML Modeller Authors <uml-devel@uml.sf.net> *
+ ***************************************************************************/
+
+#ifndef OPTIONSTATE_H
+#define OPTIONSTATE_H
+
+
+#include "umlnamespace.h"
+#include "codeviewerstate.h"
+
+namespace Settings {
+
+enum Page
+{
+ page_general = 0,
+ page_font,
+ page_UI,
+ page_class,
+ page_codegen,
+ page_codeview
+};
+
+//public structs
+struct GeneralState {
+ bool undo;
+ bool tabdiagrams;
+ bool newcodegen;
+ bool angularlines;
+ bool autosave;
+ int time; //old autosave time, kept for compatibility
+ int autosavetime;
+ QString autosavesuffix; ///< Text input field for suffix of autosave
+ bool logo;
+ bool tip;
+ bool loadlast;
+ Uml::Diagram_Type diagram;
+ QString lastFile;
+};
+
+struct UIState {
+ bool useFillColor;
+ QColor fillColor;
+ QColor lineColor;
+ uint lineWidth;
+ QFont font;
+};
+
+struct ClassState {
+ bool showVisibility;
+ bool showAtts;
+ bool showOps;
+ bool showStereoType;
+ bool showAttSig;
+ bool showOpSig;
+ bool showPackage;
+ Uml::Visibility defaultAttributeScope;
+ Uml::Visibility defaultOperationScope;
+};
+
+struct OptionState {
+ GeneralState generalState;
+ UIState uiState;
+ ClassState classState;
+ CodeViewerState codeViewerState;
+};
+
+
+OptionState& getOptionState();
+void setOptionState(const OptionState& optstate);
+
+} // namespace Settings
+
+#endif
diff --git a/umbrello/umbrello/ownedcodeblock.cpp b/umbrello/umbrello/ownedcodeblock.cpp
new file mode 100644
index 00000000..99b3c865
--- /dev/null
+++ b/umbrello/umbrello/ownedcodeblock.cpp
@@ -0,0 +1,180 @@
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * copyright (C) 2004-2007 *
+ * Umbrello UML Modeller Authors <uml-devel@uml.sf.net> *
+ ***************************************************************************/
+
+/* This code generated by:
+ * Author : thomas
+ * Date : Tue Aug 19 2003
+ */
+
+// own header
+#include "ownedcodeblock.h"
+
+// qt/kde includes
+#include <kdebug.h>
+
+// local includes
+#include "association.h"
+#include "classifier.h"
+#include "umldoc.h"
+#include "umlobject.h"
+#include "umlrole.h"
+#include "uml.h"
+#include "codedocument.h"
+#include "codegenerator.h"
+
+
+// Constructors/Destructors
+//
+
+OwnedCodeBlock::OwnedCodeBlock ( UMLObject * parent )
+ : QObject ( (QObject*)parent, "anOwnedCodeBlock" )
+{
+ initFields(parent);
+}
+
+OwnedCodeBlock::~OwnedCodeBlock ( ) {
+ /*
+ if(m_parentObject)
+ m_parentObject->disconnect(this);
+ */
+}
+
+//
+// Methods
+//
+
+void OwnedCodeBlock::release () {
+ if(m_parentObject)
+ m_parentObject->disconnect(this);
+ m_parentObject = 0;
+}
+
+/**
+ * Get the value of m_parentObject
+ * @return the value of m_parentObject
+ */
+UMLObject * OwnedCodeBlock::getParentObject () {
+ return m_parentObject;
+}
+
+// Other methods
+//
+
+void OwnedCodeBlock::setAttributesFromObject (TextBlock * obj) {
+
+ OwnedCodeBlock * oc = dynamic_cast<OwnedCodeBlock*>(obj);
+ if(oc)
+ {
+ m_parentObject->disconnect(this);
+ initFields(oc->getParentObject());
+ }
+}
+
+/** set attributes of the node that represents this class
+ * in the XMI document.
+ */
+void OwnedCodeBlock::setAttributesOnNode(QDomDocument& /*doc*/, QDomElement& elem) {
+
+ // set local class attributes
+ // setting ID's takes special treatment
+ // as UMLRoles arent properly stored in the XMI right now.
+ // (change would break the XMI format..save for big version change )
+ UMLRole * role = dynamic_cast<UMLRole*>(m_parentObject);
+ if(role)
+ {
+ elem.setAttribute("parent_id",ID2STR(role->getParentAssociation()->getID()));
+ // CAUTION: role_id here is numerically inverted wrt Uml::Role_Type,
+ // i.e. role A is 1 and role B is 0.
+ // I'll resist the temptation to change this -
+ // in order to maintain backward compatibility.
+ elem.setAttribute("role_id", (role->getRole() == Uml::A));
+ }
+ else
+ {
+ elem.setAttribute("parent_id",ID2STR(m_parentObject->getID()));
+ //elem.setAttribute("role_id","-1");
+ }
+
+}
+
+/** set the class attributes of this object from
+ * the passed element node.
+ */
+void OwnedCodeBlock::setAttributesFromNode ( QDomElement & elem) {
+
+ // set local attributes, parent object first
+ QString idStr = elem.attribute("parent_id","-1");
+ Uml::IDType id = STR2ID(idStr);
+
+ // always disconnect from current parent
+ getParentObject()->disconnect(this);
+
+ // now, what is the new object we want to set?
+ UMLObject * obj = UMLApp::app()->getDocument()->findObjectById(id);
+ if(obj)
+ {
+
+ // FIX..one day.
+ // Ugh. This is UGLY, but we have to do it this way because UMLRoles
+ // don't go into the document list of UMLobjects, and have the same
+ // ID as their parent UMLAssociations. So..the drill is then special
+ // for Associations..in that case we need to find out which role will
+ // serve as the parametger here. The REAL fix, of course, would be to
+ // treat UMLRoles on a more even footing, but im not sure how that change
+ // might ripple throughout the code and cause problems. Thus, since the
+ // change appears to be needed for only this part, I'll do this crappy
+ // change instead. -b.t.
+ UMLAssociation * assoc = dynamic_cast<UMLAssociation*>(obj);
+ if(assoc) {
+ // In this case we init with indicated role child obj.
+ UMLRole * role = 0;
+ int role_id = elem.attribute("role_id","-1").toInt();
+ // see comment on role_id at setAttributesOnNode()
+ if(role_id == 1)
+ role = assoc->getUMLRole(Uml::A);
+ else if(role_id == 0)
+ role = assoc->getUMLRole(Uml::B);
+ else // this will cause a crash
+ kError() << "corrupt save file? "
+ << "cant get proper UMLRole for ownedcodeblock uml id:"
+ << ID2STR(id) << " w/role_id:" << role_id << endl;
+
+ // init using UMLRole obj
+ initFields ( role );
+ } else
+ initFields ( obj); // just the regular approach
+
+ }
+ else
+ kError() << "ERROR: can't load ownedcodeblock: parentUMLObject w/id:"
+ << ID2STR(id) << " not found, corrupt save file?" << endl;
+
+}
+
+void OwnedCodeBlock::initFields(UMLObject * parent )
+{
+
+ m_parentObject = parent;
+
+ // one reason for being: set up the connection between
+ // this code block and the parent UMLObject..when the parent
+ // signals a change has been made, we automatically update
+ // ourselves
+ connect(m_parentObject, SIGNAL(modified()), this, SLOT(syncToParent()));
+}
+
+/**
+ */
+void OwnedCodeBlock::syncToParent ( ) {
+ updateContent();
+}
+
+#include "ownedcodeblock.moc"
diff --git a/umbrello/umbrello/ownedcodeblock.h b/umbrello/umbrello/ownedcodeblock.h
new file mode 100644
index 00000000..b089e50e
--- /dev/null
+++ b/umbrello/umbrello/ownedcodeblock.h
@@ -0,0 +1,100 @@
+
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the 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 code generated by:
+ * Author : thomas
+ * Date : Tue Aug 19 2003
+ */
+
+#ifndef OWNEDCODEBLOCK_H
+#define OWNEDCODEBLOCK_H
+
+#include <qdom.h>
+#include <qstring.h>
+#include <qobject.h>
+
+class TextBlock;
+class CodeDocument;
+// class CodeGenObjectWithTextBlocks;
+class UMLObject;
+
+/**
+ * class OwnedCodeBlock
+ * Describes any codeblock which is 'owned' by a UMLobject of some sort and should
+ * be in sync with that parent.
+ */
+
+class OwnedCodeBlock : virtual public QObject
+{
+ Q_OBJECT
+public:
+
+ // Constructors/Destructors
+ //
+
+ /**
+ * Constructor
+ */
+ OwnedCodeBlock ( UMLObject * parent );
+
+ /**
+ * Empty Destructor
+ */
+ virtual ~OwnedCodeBlock ( );
+
+ /**
+ * @return UMLObject
+ */
+ UMLObject * getParentObject ( );
+
+ // get the parent code document of this code block
+ virtual CodeDocument * getParentDocument ( ) = 0;
+
+protected:
+
+ /** causes the text block to release all of its connections
+ * and any other text blocks that it 'owns'.
+ * needed to be called prior to deletion of the textblock.
+ */
+ virtual void release ();
+
+ /** set attributes of the node that represents this class
+ * in the XMI document.
+ */
+ virtual void setAttributesOnNode ( QDomDocument & doc, QDomElement & blockElement);
+
+ /** set the class attributes of this object from
+ * the passed element node.
+ */
+ virtual void setAttributesFromNode ( QDomElement & element);
+
+ /** set the class attributes from a passed object
+ */
+ virtual void setAttributesFromObject (TextBlock * obj);
+
+ /**
+ * This is the method called from within syncToParent
+ */
+ virtual void updateContent ( ) = 0;
+
+private:
+
+ void initFields ( UMLObject * parent );
+
+ UMLObject * m_parentObject;
+
+public slots:
+
+ virtual void syncToParent ( );
+
+};
+
+#endif // OWNEDCODEBLOCK_H
diff --git a/umbrello/umbrello/ownedhierarchicalcodeblock.cpp b/umbrello/umbrello/ownedhierarchicalcodeblock.cpp
new file mode 100644
index 00000000..bb2b38ad
--- /dev/null
+++ b/umbrello/umbrello/ownedhierarchicalcodeblock.cpp
@@ -0,0 +1,113 @@
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * copyright (C) 2004-2007 *
+ * Umbrello UML Modeller Authors <uml-devel@uml.sf.net> *
+ ***************************************************************************/
+
+/* This code generated by:
+ * Author : thomas
+ * Date : Fri Aug 07 2003
+ */
+
+// own header
+#include "ownedhierarchicalcodeblock.h"
+
+// qt/kde includes
+#include <kdebug.h>
+
+// local includes
+#include "association.h"
+#include "umldoc.h"
+#include "umlobject.h"
+#include "umlrole.h"
+#include "codedocument.h"
+#include "codegenerator.h"
+
+// Constructors/Destructors
+//
+
+OwnedHierarchicalCodeBlock::OwnedHierarchicalCodeBlock ( UMLObject *parent, CodeDocument * doc, const QString &start, const QString &end, const QString &comment)
+ : HierarchicalCodeBlock ( doc, start, end, comment), OwnedCodeBlock(parent)
+{
+
+}
+
+OwnedHierarchicalCodeBlock::~OwnedHierarchicalCodeBlock ( ) { }
+
+//
+// Methods
+//
+
+
+// Accessor methods
+//
+
+// Other methods
+//
+
+void OwnedHierarchicalCodeBlock::release () {
+ OwnedCodeBlock::release();
+ HierarchicalCodeBlock::release();
+}
+
+void OwnedHierarchicalCodeBlock::setAttributesFromObject (TextBlock * obj) {
+
+ HierarchicalCodeBlock::setAttributesFromObject(obj);
+ OwnedCodeBlock::setAttributesFromObject(obj);
+}
+
+void OwnedHierarchicalCodeBlock::setAttributesOnNode (QDomDocument & doc, QDomElement & elem ) {
+
+ // set super-class attributes
+ HierarchicalCodeBlock::setAttributesOnNode(doc, elem);
+ OwnedCodeBlock::setAttributesOnNode(doc, elem);
+
+ // set local class attributes
+ elem.setAttribute("parent_id",ID2STR(getParentObject()->getID()));
+
+ // setting ID's takes special treatment
+ // as UMLRoles arent properly stored in the XMI right now.
+ // (change would break the XMI format..save for big version change )
+ UMLRole * role = dynamic_cast<UMLRole*>(getParentObject());
+ if(role) {
+ // see comment on role_id at OwnedCodeBlock::setAttributesOnNode()
+ elem.setAttribute("role_id", (role->getRole() == Uml::A));
+ }
+ /* else
+ elem.setAttribute("role_id","-1");
+ */
+}
+
+/** set the class attributes of this object from
+ * the passed element node.
+ */
+void OwnedHierarchicalCodeBlock::setAttributesFromNode ( QDomElement & root)
+{
+
+ // set attributes from the XMI
+ HierarchicalCodeBlock::setAttributesFromNode(root); // superclass load
+ OwnedCodeBlock::setAttributesFromNode(root); // superclass load
+
+}
+
+CodeDocument * OwnedHierarchicalCodeBlock::getParentDocument() {
+ return TextBlock::getParentDocument();
+}
+
+/**
+ */
+void OwnedHierarchicalCodeBlock::syncToParent ( ) {
+
+ if(getContentType() != CodeBlock::AutoGenerated)
+ return;
+
+ updateContent();
+}
+
+
+#include "ownedhierarchicalcodeblock.moc"
diff --git a/umbrello/umbrello/ownedhierarchicalcodeblock.h b/umbrello/umbrello/ownedhierarchicalcodeblock.h
new file mode 100644
index 00000000..af5ade94
--- /dev/null
+++ b/umbrello/umbrello/ownedhierarchicalcodeblock.h
@@ -0,0 +1,98 @@
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the 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 code generated by:
+ * Author : thomas
+ * Date : Fri Aug 07 2003
+ */
+
+#ifndef OWNEDHIERARCHICALCODEBLOCK_H
+#define OWNEDHIERARCHICALCODEBLOCK_H
+
+#include "hierarchicalcodeblock.h"
+
+class UMLObject;
+class CodeDocument;
+
+/**
+ * class OwnedHierarchicalCodeBlock
+ * A "chunk" of code within the code document that is "owned" by some
+ * umlobject. This is an abstract class that should be inherited.
+ */
+
+class OwnedHierarchicalCodeBlock : public HierarchicalCodeBlock, public OwnedCodeBlock
+{
+ Q_OBJECT
+public:
+
+ // Constructors/Destructors
+ //
+
+ /** constructor with QString so we can create & populate it in
+ * one step.
+ */
+ OwnedHierarchicalCodeBlock ( UMLObject * parent, CodeDocument * parentDoc, const QString &start="", const QString &end="", const QString &comment="" );
+
+ /**
+ * Empty Destructor
+ */
+ virtual ~OwnedHierarchicalCodeBlock ( );
+
+ // Public attributes
+ //
+
+ // Return the parent code document
+ CodeDocument * getParentDocument();
+
+ // these next 2 methods should be supplied by inheriting classes
+ /**
+ * Save the XMI representation of this object
+ */
+ virtual void saveToXMI ( QDomDocument & doc, QDomElement & root ) = 0;
+
+ /**
+ * load params from the appropriate XMI element node.
+ */
+ virtual void loadFromXMI ( QDomElement & root ) = 0;
+
+protected:
+
+ /** causes the text block to release all of its connections
+ * and any other text blocks that it 'owns'.
+ * needed to be called prior to deletion of the textblock.
+ */
+ virtual void release ();
+
+ /** set attributes of the node that represents this class
+ * in the XMI document.
+ */
+ virtual void setAttributesOnNode ( QDomDocument & doc, QDomElement & blockElement);
+
+ /** set the class attributes of this object from
+ * the passed element node.
+ */
+ virtual void setAttributesFromNode ( QDomElement & element);
+
+ /** set the class attributes from a passed object
+ */
+ virtual void setAttributesFromObject (TextBlock * obj);
+
+ virtual void updateContent ( ) = 0;
+
+private:
+
+public slots:
+
+ void syncToParent ( );
+
+
+};
+
+#endif // OWNEDHIERARCHICALCODEBLOCK_H
diff --git a/umbrello/umbrello/package.cpp b/umbrello/umbrello/package.cpp
new file mode 100644
index 00000000..54dc18a5
--- /dev/null
+++ b/umbrello/umbrello/package.cpp
@@ -0,0 +1,298 @@
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * copyright (C) 2003-2006 *
+ * Umbrello UML Modeller Authors <uml-devel@uml.sf.net> *
+ ***************************************************************************/
+
+// own header file
+#include "package.h"
+
+// system includes
+#include <kdebug.h>
+#include <klocale.h>
+
+// local includes
+#include "uml.h"
+#include "umldoc.h"
+#include "classifier.h"
+#include "association.h"
+#include "object_factory.h"
+#include "model_utils.h"
+#include "umllistview.h"
+#include "umllistviewitem.h"
+
+using namespace Uml;
+
+UMLPackage::UMLPackage(const QString & name, Uml::IDType id)
+ : UMLCanvasObject(name, id) {
+ init();
+}
+
+UMLPackage::~UMLPackage() {
+}
+
+void UMLPackage::init() {
+ m_BaseType = ot_Package;
+}
+
+void UMLPackage::copyInto(UMLPackage *rhs) const
+{
+ UMLCanvasObject::copyInto(rhs);
+
+ m_objects.copyInto(&(rhs->m_objects));
+}
+
+UMLObject* UMLPackage::clone() const
+{
+ UMLPackage *clone = new UMLPackage();
+ copyInto(clone);
+
+ return clone;
+}
+
+void UMLPackage::addAssocToConcepts(UMLAssociation* a) {
+ if (! UMLAssociation::assocTypeHasUMLRepresentation(a->getAssocType()) )
+ return;
+ Uml::IDType AId = a->getObjectId(Uml::A);
+ Uml::IDType BId = a->getObjectId(Uml::B);
+ UMLObject *o;
+ for (UMLObjectListIt it(m_objects); (o = it.current()) != NULL; ++it) {
+ UMLCanvasObject *c = dynamic_cast<UMLCanvasObject*>(o);
+ if (c == NULL)
+ continue;
+ if (AId == c->getID() || (BId == c->getID())) {
+ if (c->hasAssociation(a))
+ kDebug() << "UMLPackage::addAssocToConcepts: " << c->getName()
+ << " already has association id=" << ID2STR(a->getID())
+ << endl;
+ else
+ c->addAssociationEnd(a);
+ }
+ UMLPackage *pkg = dynamic_cast<UMLPackage*>(c);
+ if (pkg)
+ pkg->addAssocToConcepts(a);
+ }
+}
+
+void UMLPackage::removeAssocFromConcepts(UMLAssociation *assoc)
+{
+ UMLObject *o;
+ for (UMLObjectListIt it(m_objects); (o = it.current()) != NULL; ++it) {
+ UMLCanvasObject *c = dynamic_cast<UMLCanvasObject*>(o);
+ if (c == NULL)
+ continue;
+ if (c->hasAssociation(assoc))
+ c->removeAssociationEnd(assoc);
+ UMLPackage *pkg = dynamic_cast<UMLPackage*>(c);
+ if (pkg)
+ pkg->removeAssocFromConcepts(assoc);
+ }
+}
+
+bool UMLPackage::addObject(UMLObject *pObject) {
+ if (pObject == NULL) {
+ kError() << "UMLPackage::addObject is called with a NULL object"
+ << endl;
+ return false;
+ }
+ if (m_objects.find(pObject) != -1) {
+ kDebug() << "UMLPackage::addObject: " << pObject->getName()
+ << " is already there" << endl;
+ return false;
+ }
+ if (pObject->getBaseType() == Uml::ot_Association) {
+ UMLAssociation *assoc = static_cast<UMLAssociation*>(pObject);
+ // Adding the UMLAssociation at the participating concepts is done
+ // again later (in UMLAssociation::resolveRef()) if they are not yet
+ // known right here.
+ if (assoc->getObject(Uml::A) && assoc->getObject(Uml::B)) {
+ UMLPackage *pkg = pObject->getUMLPackage();
+ if (pkg != this) {
+ kError() << "UMLPackage " << m_Name << " addObject: "
+ << "assoc's UMLPackage is " << pkg->getName() << endl;
+ }
+ addAssocToConcepts(assoc);
+ }
+ }
+ m_objects.append( pObject );
+ return true;
+}
+
+void UMLPackage::removeObject(UMLObject *pObject) {
+ if (pObject->getBaseType() == Uml::ot_Association) {
+ UMLObject *o = const_cast<UMLObject*>(pObject);
+ UMLAssociation *assoc = static_cast<UMLAssociation*>(o);
+ removeAssocFromConcepts(assoc);
+ }
+ if (m_objects.findRef(pObject) == -1)
+ kDebug() << m_Name << " removeObject: object with id="
+ << ID2STR(pObject->getID()) << "not found." << endl;
+ else
+ m_objects.remove(pObject);
+}
+
+void UMLPackage::removeAllObjects() {
+ UMLCanvasObject::removeAllChildObjects();
+ UMLObject *o;
+ while ((o = m_objects.first()) != NULL) {
+ UMLPackage *pkg = dynamic_cast<UMLPackage*>(o);
+ if (pkg)
+ pkg->removeAllObjects();
+ removeObject(o);
+ //delete o;
+ // CHECK: Direct usage of the destructor crashes on associations.
+ o->deleteLater();
+ }
+}
+
+UMLObjectList UMLPackage::containedObjects() {
+ return m_objects;
+}
+
+UMLObject * UMLPackage::findObject(const QString &name) {
+ const bool caseSensitive = UMLApp::app()->activeLanguageIsCaseSensitive();
+ for (UMLObjectListIt oit(m_objects); oit.current(); ++oit) {
+ UMLObject *obj = oit.current();
+ if (caseSensitive) {
+ if (obj->getName() == name)
+ return obj;
+ } else if (obj->getName().lower() == name.lower()) {
+ return obj;
+ }
+ }
+ return NULL;
+}
+
+UMLObject * UMLPackage::findObjectById(Uml::IDType id) {
+ return Model_Utils::findObjectInList(id, m_objects);
+}
+
+void UMLPackage::appendClassifiers(UMLClassifierList& classifiers,
+ bool includeNested /* = true */) {
+ for (UMLObjectListIt oit(m_objects); oit.current(); ++oit) {
+ UMLObject *o = oit.current();
+ Object_Type ot = o->getBaseType();
+ if (ot == ot_Class || ot == ot_Interface ||
+ ot == ot_Datatype || ot == ot_Enum || ot == ot_Entity) {
+ classifiers.append((UMLClassifier *)o);
+ } else if (includeNested && (ot == ot_Package || ot == ot_Folder)) {
+ UMLPackage *inner = static_cast<UMLPackage *>(o);
+ inner->appendClassifiers(classifiers);
+ }
+ }
+}
+
+void UMLPackage::appendClasses(UMLClassifierList& classes,
+ bool includeNested /* = true */) {
+ for (UMLObjectListIt oit(m_objects); oit.current(); ++oit) {
+ UMLObject *o = oit.current();
+ Object_Type ot = o->getBaseType();
+ if (ot == ot_Class) {
+ UMLClassifier *c = static_cast<UMLClassifier*>(o);
+ classes.append(c);
+ } else if (includeNested && (ot == ot_Package || ot == ot_Folder)) {
+ UMLPackage *inner = static_cast<UMLPackage *>(o);
+ inner->appendClasses(classes);
+ }
+ }
+}
+
+void UMLPackage::appendClassesAndInterfaces(UMLClassifierList& classifiers,
+ bool includeNested /* = true */) {
+ for (UMLObjectListIt oit(m_objects); oit.current(); ++oit) {
+ UMLObject *o = oit.current();
+ Object_Type ot = o->getBaseType();
+ if (ot == ot_Class || ot == ot_Interface) {
+ UMLClassifier *c = static_cast<UMLClassifier*>(o);
+ classifiers.append(c);
+ } else if (includeNested && (ot == ot_Package || ot == ot_Folder)) {
+ UMLPackage *inner = static_cast<UMLPackage *>(o);
+ inner->appendClassesAndInterfaces(classifiers);
+ }
+ }
+}
+
+void UMLPackage::appendInterfaces( UMLClassifierList& interfaces,
+ bool includeNested /* = true */) {
+ for (UMLObjectListIt oit(m_objects); oit.current(); ++oit) {
+ UMLObject *o = oit.current();
+ Object_Type ot = o->getBaseType();
+ if (ot == ot_Interface) {
+ UMLClassifier *c = static_cast<UMLClassifier*>(o);
+ interfaces.append(c);
+ } else if (includeNested && (ot == ot_Package || ot == ot_Folder)) {
+ UMLPackage *inner = static_cast<UMLPackage *>(o);
+ inner->appendInterfaces(interfaces);
+ }
+ }
+}
+
+bool UMLPackage::resolveRef() {
+ bool overallSuccess = UMLCanvasObject::resolveRef();
+ for (UMLObjectListIt oit(m_objects); oit.current(); ++oit) {
+ UMLObject *obj = oit.current();
+ if (! obj->resolveRef()) {
+ Uml::Object_Type ot = obj->getBaseType();
+ if (ot != Uml::ot_Package && ot != Uml::ot_Folder)
+ m_objects.remove(obj);
+ overallSuccess = false;
+ }
+ }
+ return overallSuccess;
+}
+
+void UMLPackage::saveToXMI(QDomDocument& qDoc, QDomElement& qElement) {
+ QDomElement packageElement = UMLObject::save("UML:Package", qDoc);
+ QDomElement ownedElement = qDoc.createElement("UML:Namespace.ownedElement");
+ UMLObject *obj;
+ // save classifiers etc.
+ for (UMLObjectListIt oit(m_objects); (obj = oit.current()) != NULL; ++oit)
+ obj->saveToXMI (qDoc, ownedElement);
+ // save associations
+ for (UMLObjectListIt ait(m_List); (obj = ait.current()) != NULL; ++ait)
+ obj->saveToXMI (qDoc, ownedElement);
+
+ packageElement.appendChild(ownedElement);
+ qElement.appendChild(packageElement);
+}
+
+bool UMLPackage::load(QDomElement& element) {
+ for (QDomNode node = element.firstChild(); !node.isNull();
+ node = node.nextSibling()) {
+ if (node.isComment())
+ continue;
+ QDomElement tempElement = node.toElement();
+ QString type = tempElement.tagName();
+ if (Model_Utils::isCommonXMIAttribute(type))
+ continue;
+ if (tagEq(type, "Namespace.ownedElement") ||
+ tagEq(type, "Namespace.contents")) {
+ //CHECK: Umbrello currently assumes that nested elements
+ // are ownedElements anyway.
+ // Therefore these tags are not further interpreted.
+ if (! load(tempElement))
+ return false;
+ continue;
+ }
+ UMLObject *pObject = Object_Factory::makeObjectFromXMI(type);
+ if( !pObject ) {
+ kWarning() << "UMLPackage::load: "
+ << "Unknown type of umlobject to create: "
+ << type << endl;
+ continue;
+ }
+ pObject->setUMLPackage(this);
+ if (!pObject->loadFromXMI(tempElement)) {
+ removeObject(pObject);
+ delete pObject;
+ }
+ }
+ return true;
+}
+
+#include "package.moc"
diff --git a/umbrello/umbrello/package.h b/umbrello/umbrello/package.h
new file mode 100644
index 00000000..b7d51000
--- /dev/null
+++ b/umbrello/umbrello/package.h
@@ -0,0 +1,198 @@
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * copyright (C) 2003-2006 *
+ * Umbrello UML Modeller Authors <uml-devel@uml.sf.net> *
+ ***************************************************************************/
+
+#ifndef PACKAGE_H
+#define PACKAGE_H
+
+#include "umlcanvasobject.h"
+#include "umlclassifierlist.h"
+
+// forward declarations
+class UMLAssociation;
+
+
+/**
+ * This class contains the non-graphical information required for a UML
+ * Package.
+ * This class inherits from @ref UMLCanvasObject which contains most of the
+ * information.
+ *
+ * @short Non-graphical information for a Package.
+ * @author Jonathan Riddell
+ * @see UMLCanvasObject
+ * Bugs and comments to uml-devel@lists.sf.net or http://bugs.kde.org
+ */
+
+class UMLPackage : public UMLCanvasObject {
+ Q_OBJECT
+public:
+ /**
+ * Sets up a Package.
+ *
+ * @param name The name of the Concept.
+ * @param id The unique id of the Concept.
+ */
+ explicit UMLPackage(const QString & name = "", Uml::IDType id = Uml::id_None);
+
+ /**
+ * Empty deconstructor.
+ */
+ virtual ~UMLPackage();
+
+ /**
+ * Copy the internal presentation of this object into the new
+ * object.
+ */
+ virtual void copyInto(UMLPackage *rhs) const;
+
+ /**
+ * Make a clone of this object.
+ */
+ virtual UMLObject* clone() const;
+
+ /**
+ * Initializes key variables of the class.
+ */
+ void init();
+
+ /**
+ * Adds an object in this package.
+ *
+ * @param pObject Pointer to the UMLObject to add.
+ * @return True if the object was actually added.
+ */
+ bool addObject(UMLObject *pObject);
+
+ /**
+ * Removes an object from this package.
+ * Does not physically delete the object.
+ *
+ * @param pObject Pointer to the UMLObject to be removed.
+ */
+ void removeObject(UMLObject *pObject);
+
+ /**
+ * Removes all objects from this package.
+ * Inner containers (e.g. nested packages) are removed recursively.
+ */
+ virtual void removeAllObjects();
+
+ /**
+ * Returns the list of objects contained in this package.
+ */
+ UMLObjectList containedObjects();
+
+ /**
+ * Adds an existing association to the matching concept in the list of concepts.
+ * The selection of the matching concept depends on the association type:
+ * For generalizations, the assoc is added to the concept that matches role A.
+ * For aggregations and compositions , the assoc is added to the concept
+ * that matches role B.
+ *
+ * @param assoc The association to add
+ */
+ void addAssocToConcepts(UMLAssociation* assoc);
+
+ /**
+ * Remove the association from the participating concepts.
+ */
+ void removeAssocFromConcepts(UMLAssociation *assoc);
+
+ /**
+ * Find the object of the given name in the list of contained objects.
+ *
+ * @param name The name to seek.
+ * @return Pointer to the UMLObject found or NULL if not found.
+ */
+ UMLObject * findObject(const QString &name);
+
+ /**
+ * Find the object of the given ID in the list of contained objects.
+ *
+ * @param id The ID to seek.
+ * @return Pointer to the UMLObject found or NULL if not found.
+ */
+ UMLObject * findObjectById(Uml::IDType id);
+
+ /**
+ * Append all classifiers from this package (and those from
+ * nested packages) to the given UMLClassifierList.
+ *
+ * @param classifiers The list to append to.
+ * @param includeNested Whether to include the classifiers from
+ * nested packages (default: true.)
+ */
+ void appendClassifiers( UMLClassifierList& classifiers,
+ bool includeNested = true );
+
+ /**
+ * Append all classes from this package (and those from
+ * nested packages) to the given UMLClassifierList.
+ *
+ * @param classes The list to append to.
+ * @param includeNested Whether to include the classes from
+ * nested packages (default: true.)
+ */
+ void appendClasses( UMLClassifierList& classes, bool includeNested = true );
+
+ /**
+ * Append all classes and interfaces from this package (and those
+ * from nested packages) to the given UMLClassifierList.
+ *
+ * @param classifiers The list to append to.
+ * @param includeNested Whether to include the classifiers from
+ * nested packages (default: true.)
+ */
+ void appendClassesAndInterfaces(UMLClassifierList& classifiers,
+ bool includeNested = true);
+
+ /**
+ * Append all interfaces from this package (and those from
+ * nested packages) to the given UMLClassifierList.
+ *
+ * @param interfaces The list to append to.
+ * @param includeNested Whether to include the interfaces from
+ * nested packages (default: true.)
+ */
+ void appendInterfaces(UMLClassifierList& interfaces,
+ bool includeNested = true );
+
+ /**
+ * Resolve types. Required when dealing with foreign XMI files.
+ * Needs to be called after all UML objects are loaded from file.
+ * Overrides the method from UMLObject.
+ * Calls resolveRef() on each contained object.
+ *
+ * @return True for overall success.
+ */
+ virtual bool resolveRef();
+
+ /**
+ * Creates the <UML:Package> XMI element.
+ */
+ virtual void saveToXMI(QDomDocument& qDoc, QDomElement& qElement);
+
+protected:
+ /**
+ * Loads the <UML:Package> XMI element.
+ * Auxiliary to UMLObject::loadFromXMI.
+ */
+ virtual bool load(QDomElement& element);
+
+ /**
+ * References to the objects contained in this package.
+ * The UMLPackage is the owner of the objects.
+ */
+ UMLObjectList m_objects;
+
+};
+
+#endif
diff --git a/umbrello/umbrello/packagewidget.cpp b/umbrello/umbrello/packagewidget.cpp
new file mode 100644
index 00000000..002f723e
--- /dev/null
+++ b/umbrello/umbrello/packagewidget.cpp
@@ -0,0 +1,133 @@
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * copyright (C) 2003-2007 *
+ * Umbrello UML Modeller Authors <uml-devel@uml.sf.net> *
+ ***************************************************************************/
+
+// own header
+#include "packagewidget.h"
+
+// qt/kde includes
+#include <qpainter.h>
+#include <kdebug.h>
+
+// app includes
+#include "package.h"
+#include "uml.h"
+#include "umldoc.h"
+#include "umlview.h"
+#include "umlobject.h"
+
+
+PackageWidget::PackageWidget(UMLView * view, UMLPackage *o)
+ : UMLWidget(view, o) {
+ init();
+}
+
+void PackageWidget::init() {
+ UMLWidget::setBaseType(Uml::wt_Package);
+ setSize(100, 30);
+ setZ(m_origZ = 1); // above box but below UMLWidget because may embed widgets
+ m_pMenu = 0;
+ //set defaults from m_pView
+ if (m_pView) {
+ //check to see if correct
+ const Settings::OptionState& ops = m_pView->getOptionState();
+ m_bShowStereotype = ops.classState.showStereoType;
+ }
+ //maybe loading and this may not be set.
+ if (m_pObject && !UMLApp::app()->getDocument()->loading())
+ updateComponentSize();
+}
+
+PackageWidget::~PackageWidget() {}
+
+void PackageWidget::draw(QPainter & p, int offsetX, int offsetY) {
+ UMLWidget::setPen(p);
+ if ( UMLWidget::getUseFillColour() )
+ p.setBrush( UMLWidget::getFillColour() );
+ else
+ p.setBrush(m_pView -> viewport() -> backgroundColor());
+
+ int w = width();
+ int h = height();
+ QFont font = UMLWidget::getFont();
+ font.setBold(true);
+ //FIXME italic is true when a package is first created until you click elsewhere, not sure why
+ font.setItalic(false);
+ const QFontMetrics &fm = getFontMetrics(FT_BOLD);
+ const int fontHeight = fm.lineSpacing();
+ QString name = getName();
+
+ p.drawRect(offsetX, offsetY, 50, fontHeight);
+ if (m_pObject->getStereotype() == "subsystem") {
+ const int fHalf = fontHeight / 2;
+ const int symY = offsetY + fHalf;
+ const int symX = offsetX + 38;
+ p.drawLine(symX, symY, symX, symY + fHalf - 2); // left leg
+ p.drawLine(symX + 8, symY, symX + 8, symY + fHalf - 2); // right leg
+ p.drawLine(symX, symY, symX + 8, symY); // waist
+ p.drawLine(symX + 4, symY, symX + 4, symY - fHalf + 2); // head
+ }
+ p.drawRect(offsetX, offsetY + fontHeight - 1, w, h - fontHeight);
+
+ p.setPen( QPen(Qt::black) );
+ p.setFont(font);
+
+ int lines = 1;
+ if (m_pObject != NULL) {
+ QString stereotype = m_pObject->getStereotype();
+ if (!stereotype.isEmpty()) {
+ p.drawText(offsetX, offsetY + fontHeight + PACKAGE_MARGIN,
+ w, fontHeight, Qt::AlignCenter, m_pObject->getStereotype(true));
+ lines = 2;
+ }
+ }
+
+ p.drawText(offsetX, offsetY + (fontHeight*lines) + PACKAGE_MARGIN,
+ w, fontHeight, Qt::AlignCenter, name );
+
+ if(m_bSelected) {
+ drawSelected(&p, offsetX, offsetY);
+ }
+}
+
+QSize PackageWidget::calculateSize() {
+ if ( !m_pObject ) {
+ return UMLWidget::calculateSize();
+ }
+
+ const QFontMetrics &fm = getFontMetrics(FT_BOLD_ITALIC);
+ const int fontHeight = fm.lineSpacing();
+
+ int lines = 1;
+
+ int width = fm.width( m_pObject->getName() );
+
+ int tempWidth = 0;
+ if (!m_pObject->getStereotype().isEmpty()) {
+ tempWidth = fm.width(m_pObject->getStereotype(true));
+ lines = 2;
+ }
+ if (tempWidth > width)
+ width = tempWidth;
+ width += PACKAGE_MARGIN * 2;
+ if (width < 70)
+ width = 70; // minumin width of 70
+
+ int height = (lines*fontHeight) + fontHeight + (PACKAGE_MARGIN * 2);
+
+ return QSize(width, height);
+}
+
+void PackageWidget::saveToXMI(QDomDocument& qDoc, QDomElement& qElement) {
+ QDomElement conceptElement = qDoc.createElement("packagewidget");
+ UMLWidget::saveToXMI(qDoc, conceptElement);
+ qElement.appendChild(conceptElement);
+}
+
diff --git a/umbrello/umbrello/packagewidget.h b/umbrello/umbrello/packagewidget.h
new file mode 100644
index 00000000..5acb63d1
--- /dev/null
+++ b/umbrello/umbrello/packagewidget.h
@@ -0,0 +1,74 @@
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * copyright (C) 2003-2006 *
+ * Umbrello UML Modeller Authors <uml-devel@uml.sf.net> *
+ ***************************************************************************/
+
+#ifndef PACKAGEWIDGET_H
+#define PACKAGEWIDGET_H
+
+#include "umlwidget.h"
+
+class UMLPackage;
+
+#define PACKAGE_MARGIN 5
+
+/**
+ * Defines a graphical version of the Package. Most of the functionality
+ * will come from the @ref UMLPackage class.
+ *
+ * @short A graphical version of a Package.
+ * @author Jonathan Riddell
+ * @see UMLWidget
+ * Bugs and comments to uml-devel@lists.sf.net or http://bugs.kde.org
+ */
+class PackageWidget : public UMLWidget {
+public:
+
+ /**
+ * Constructs a PackageWidget.
+ *
+ * @param view The parent of this PackageWidget.
+ * @param o The UMLObject this will be representing.
+ */
+ PackageWidget(UMLView * view, UMLPackage * o);
+
+ /**
+ * destructor
+ */
+ virtual ~PackageWidget();
+
+ /**
+ * Overrides standard method.
+ */
+ void draw(QPainter& p, int offsetX, int offsetY);
+
+ /**
+ * Saves to the "packagewidget" XMI element.
+ */
+ void saveToXMI(QDomDocument& qDoc, QDomElement& qElement);
+
+protected:
+ /**
+ * Overrides method from UMLWidget
+ */
+ QSize calculateSize();
+
+private:
+ /**
+ * Initializes key variables of the class.
+ */
+ void init();
+
+ /**
+ * The right mouse button menu.
+ */
+ ListPopupMenu* m_pMenu;
+};
+
+#endif
diff --git a/umbrello/umbrello/petalnode.cpp b/umbrello/umbrello/petalnode.cpp
new file mode 100644
index 00000000..9d9aa0ad
--- /dev/null
+++ b/umbrello/umbrello/petalnode.cpp
@@ -0,0 +1,61 @@
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * copyright (C) 2006 *
+ * Umbrello UML Modeller Authors <uml-devel@uml.sf.net> *
+ ***************************************************************************/
+
+// own header
+#include "petalnode.h"
+
+PetalNode::PetalNode(NodeType nt) {
+ m_type = nt;
+}
+
+PetalNode::~PetalNode() {
+}
+
+PetalNode::NodeType PetalNode::type() const {
+ return m_type;
+}
+
+QStringList PetalNode::initialArgs() const {
+ return m_initialArgs;
+}
+
+QString PetalNode::name() const {
+ if (m_initialArgs.count() == 0)
+ return QString();
+ return m_initialArgs.first();
+}
+
+PetalNode::NameValueList PetalNode::attributes() const {
+ return m_attributes;
+}
+
+/*
+void PetalNode::setType(PetalNode::NodeType t) {
+ m_type = t;
+}
+ */
+
+void PetalNode::setInitialArgs(const QStringList& args) {
+ m_initialArgs = args;
+}
+
+void PetalNode::setAttributes(PetalNode::NameValueList vl) {
+ m_attributes = vl;
+}
+
+PetalNode::StringOrNode PetalNode::findAttribute(const QString& name) const {
+ for (uint i = 0; i < m_attributes.count(); i++) {
+ if (m_attributes[i].first == name)
+ return m_attributes[i].second;
+ }
+ return StringOrNode();
+}
+
diff --git a/umbrello/umbrello/petalnode.h b/umbrello/umbrello/petalnode.h
new file mode 100644
index 00000000..705de417
--- /dev/null
+++ b/umbrello/umbrello/petalnode.h
@@ -0,0 +1,86 @@
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * copyright (C) 2006 *
+ * Umbrello UML Modeller Authors <uml-devel@uml.sf.net> *
+ ***************************************************************************/
+
+#ifndef PETALNODE__H
+#define PETALNODE__H
+
+#include <qstring.h>
+#include <qpair.h>
+#include <qvaluelist.h>
+#include <qstringlist.h>
+
+/**
+ * Rose petal node - parse tree for model import
+ *
+ * A Rose petal node can be of type:
+ * + object - initialArgs() contains the object type name and further
+ * initial arguments which depend on the exact object type
+ * - subordinate attributes are contained in attributes()
+ * + list - initialArgs() contains the list type name
+ * - list elements are contained in attributes() but the name
+ * of each NameValue is empty.
+ * + value - not represented as a node, instead the stripped down value
+ * is saved in the value string of the NameValue.
+ * Example: for the input
+ * (value Text "This is some text")
+ * the following is saved in the value string of the NameValue:
+ * "This is some text"
+ *
+ * @author Oliver Kellogg
+ * Bugs and comments to uml-devel@lists.sf.net or http://bugs.kde.org
+ */
+class PetalNode {
+public:
+ /**
+ * Use `string' if it is not empty.
+ * Use `node' if it is not NULL.
+ * Either `string' is set, or `node', but never both.
+ * (Perhaps this should be a union but that is ugly.)
+ */
+ struct StringOrNode {
+ QString string;
+ PetalNode *node;
+ StringOrNode() { node = 0; }
+ virtual ~StringOrNode() { }
+ bool isEmpty() { return (string.isEmpty() && node == 0); }
+ };
+ typedef QPair<QString, StringOrNode> NameValue;
+ typedef QValueList<NameValue> NameValueList;
+
+ enum NodeType { nt_object, nt_list };
+
+ PetalNode(NodeType nt);
+ virtual ~PetalNode();
+
+ // getters
+ NodeType type() const;
+ QStringList initialArgs() const; // name and other initial args
+ QString name() const; // convenience function: equal to initialArgs().first()
+ NameValueList attributes() const;
+ // setters
+ //void setType(NodeType nt); see constructor
+ void setInitialArgs(const QStringList& args);
+ void setAttributes(NameValueList vl);
+ // utilities
+ /**
+ * Find an attribute by name.
+ * @return The value of the attribute. StringOrNode::isEmpty() returns true
+ * if the name could not be found.
+ */
+ StringOrNode findAttribute(const QString& name) const;
+private:
+ NodeType m_type;
+ QStringList m_initialArgs;
+ NameValueList m_attributes;
+};
+
+#endif
+
diff --git a/umbrello/umbrello/petaltree2uml.cpp b/umbrello/umbrello/petaltree2uml.cpp
new file mode 100644
index 00000000..41563785
--- /dev/null
+++ b/umbrello/umbrello/petaltree2uml.cpp
@@ -0,0 +1,631 @@
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * copyright (C) 2006-2007 *
+ * Umbrello UML Modeller Authors <uml-devel@uml.sf.net> *
+ ***************************************************************************/
+
+// own header
+#include "petaltree2uml.h"
+// qt/kde includes
+#include <qregexp.h>
+#include <kdebug.h>
+// app includes
+#include "petalnode.h"
+#include "codeimport/import_utils.h"
+#include "package.h"
+#include "classifier.h"
+#include "attribute.h"
+#include "operation.h"
+#include "association.h"
+#include "umlrole.h"
+#include "actor.h"
+#include "usecase.h"
+#include "component.h"
+#include "node.h"
+#include "uml.h"
+#include "umldoc.h"
+#include "umllistview.h"
+#include "umllistviewitem.h"
+
+namespace Import_Rose {
+
+/**
+ * Return the given string without surrounding quotation marks.
+ * Also remove a possible prefix "Logical View::", it is not modeled in Umbrello.
+ */
+QString clean(const QString& s) {
+ if (s.isNull())
+ return QString();
+ QString str = s;
+ str.remove("\"");
+ str.remove(QRegExp("^Logical View::"));
+ return str;
+}
+
+/**
+ * Extract the quid attribute from a petal node and return it as a Uml::IDType.
+ */
+Uml::IDType quid(const PetalNode *node) {
+ QString quidStr = node->findAttribute("quid").string;
+ if (quidStr.isEmpty())
+ return Uml::id_None;
+ quidStr.remove("\"");
+ return STR2ID(quidStr);
+}
+
+/**
+ * Extract the quidu attribute from a petal node.
+ */
+QString quidu(const PetalNode *node) {
+ QString quiduStr = node->findAttribute("quidu").string;
+ if (quiduStr.isEmpty())
+ return QString();
+ quiduStr.remove("\"");
+ return quiduStr;
+}
+
+/**
+ * Determine the model type corresponding to a name.
+ * If the given name consists only of letters, digits, underscores, and
+ * scope separators, then return Uml::ot_Class, else return Uml::ot_Datatype.
+ */
+Uml::Object_Type typeToCreate(const QString& name) {
+ QString n = name;
+ n.remove(QRegExp("^.*::")); // don't consider the scope prefix, it may contain spaces
+ Uml::Object_Type t = (n.contains(QRegExp("\\W")) ? Uml::ot_Datatype : Uml::ot_Class);
+ return t;
+}
+
+/**
+ * Transfer the Rose attribute "exportControl" to the Umbrello object given.
+ *
+ * @param from Pointer to PetalNode from which to read the "exportControl" attribute
+ * @param to Pointer to UMLObject in which to set the Uml::Visibility
+ */
+void transferVisibility(const PetalNode *from, UMLObject *to) {
+ QString vis = from->findAttribute("exportControl").string;
+ if (!vis.isEmpty()) {
+ Uml::Visibility v = Uml::Visibility::fromString(clean(vis.lower()));
+ to->setVisibility(v);
+ }
+}
+
+/**
+ * ClassifierListReader factors the common processing for attributes, operations,
+ * and operation parameters.
+ */
+class ClassifierListReader {
+public:
+ /// constructor
+ ClassifierListReader(const char* attributeTag,
+ const char* elementName,
+ const char* itemTypeDesignator) :
+ m_attributeTag(attributeTag),
+ m_elementName(elementName),
+ m_itemTypeDesignator(itemTypeDesignator) {
+ }
+ /// destructor
+ virtual ~ClassifierListReader() {}
+
+ /**
+ * Return a UMLClassifierListItem of the specific type desired.
+ * Abstract method to be implemented by inheriting classes.
+ */
+ virtual UMLObject *createListItem() = 0;
+
+ virtual void setTypeReferences(UMLObject *item,
+ const QString& quid, const QString& type) {
+ if (!quid.isEmpty()) {
+ item->setSecondaryId(quid);
+ }
+ if (!type.isEmpty()) {
+ item->setSecondaryFallback(type);
+ }
+ }
+
+ /**
+ * Insert the given UMLClassifierListItem at the parent Umbrello object.
+ * Abstract method to be implemented by inheriting classes.
+ * NB the parent Umbrello object is not included in the ClassifierListReader
+ * class - it must be added at inheriting classes.
+ *
+ * @param node The PetalNode which corresponds to the parent Umbrello object.
+ * @param o The UMLObject to insert.
+ */
+ virtual void insertAtParent(const PetalNode *node, UMLObject *o) = 0;
+
+ /**
+ * Iterate over the attributes of the given PetalNode and for each recognized
+ * attribute do the following:
+ * - invoke createListItem()
+ * - fill common properties such as name, unique ID, visibility, etc. into
+ * the new UMLClassifierListItem
+ * - invoke insertAtParent() with the new classifier list item as the argument
+ * This is the user entry point.
+ */
+ void read(const PetalNode *node, const QString& name) {
+ PetalNode *attributes = node->findAttribute(m_attributeTag).node;
+ if (attributes == NULL) {
+#ifdef VERBOSE_DEBUGGING
+ kDebug() << "read(" << name << "): no " << m_attributeTag << " found"
+ << endl;
+#endif
+ return;
+ }
+ PetalNode::NameValueList attributeList = attributes->attributes();
+ for (uint i = 0; i < attributeList.count(); i++) {
+ PetalNode *attNode = attributeList[i].second.node;
+ QStringList initialArgs = attNode->initialArgs();
+ if (attNode->name() != m_elementName) {
+ kDebug() << "read(" << name << "): expecting " << m_elementName
+ << ", " << "found " << initialArgs[0] << endl;
+ continue;
+ }
+ UMLObject *item = createListItem();
+ if (initialArgs.count() > 1)
+ item->setName(clean(initialArgs[1]));
+ item->setID(quid(attNode));
+ QString quidref = quidu(attNode);
+ QString type = clean(attNode->findAttribute(m_itemTypeDesignator).string);
+ setTypeReferences(item, quidref, type);
+ transferVisibility(attNode, item);
+ QString doc = attNode->findAttribute("documentation").string;
+ if (! doc.isEmpty())
+ item->setDoc(doc);
+ insertAtParent(attNode, item);
+ }
+ }
+protected:
+ const QString m_attributeTag, m_elementName, m_itemTypeDesignator;
+};
+
+class AttributesReader : public ClassifierListReader {
+public:
+ AttributesReader(UMLClassifier *c)
+ : ClassifierListReader("class_attributes", "ClassAttribute", "type") {
+ m_classifier = c;
+ }
+ virtual ~AttributesReader() {}
+ UMLObject *createListItem() {
+ return new UMLAttribute(m_classifier);
+ }
+ void insertAtParent(const PetalNode *, UMLObject *item) {
+ m_classifier->addAttribute(static_cast<UMLAttribute*>(item));
+ }
+protected:
+ UMLClassifier *m_classifier;
+};
+
+class ParametersReader : public ClassifierListReader {
+public:
+ ParametersReader(UMLOperation *op)
+ : ClassifierListReader("parameters", "Parameter", "type") {
+ m_operation = op;
+ }
+ virtual ~ParametersReader() {}
+ UMLObject *createListItem() {
+ return new UMLAttribute(m_operation);
+ }
+ void insertAtParent(const PetalNode *, UMLObject *item) {
+ m_operation->addParm(static_cast<UMLAttribute*>(item));
+ }
+protected:
+ UMLOperation *m_operation;
+};
+
+class OperationsReader : public ClassifierListReader {
+public:
+ OperationsReader(UMLClassifier *c)
+ : ClassifierListReader("operations", "Operation", "result") {
+ m_classifier = c;
+ }
+ virtual ~OperationsReader() {}
+ UMLObject *createListItem() {
+ return new UMLOperation(m_classifier);
+ }
+ void insertAtParent(const PetalNode *node, UMLObject *item) {
+ UMLOperation *op = static_cast<UMLOperation*>(item);
+ ParametersReader parmReader(op);
+ parmReader.read(node, m_classifier->getName());
+ m_classifier->addOperation(op);
+ }
+protected:
+ UMLClassifier *m_classifier;
+};
+
+class SuperclassesReader : public ClassifierListReader {
+public:
+ SuperclassesReader(UMLClassifier *c)
+ : ClassifierListReader("superclasses", "Inheritance_Relationship", "supplier") {
+ m_classifier = c;
+ }
+ virtual ~SuperclassesReader() {}
+ UMLObject *createListItem() {
+ return new UMLAssociation(Uml::at_Generalization);
+ }
+ /**
+ * Override parent implementation: The secondary data is not for the
+ * UMLAssociation itself but for its role B object.
+ */
+ void setTypeReferences(UMLObject *item,
+ const QString& quid, const QString& type) {
+ UMLAssociation *assoc = static_cast<UMLAssociation*>(item);
+ if (!quid.isEmpty()) {
+ assoc->getUMLRole(Uml::B)->setSecondaryId(quid);
+ }
+ if (!type.isEmpty()) {
+ assoc->getUMLRole(Uml::B)->setSecondaryFallback(type);
+ }
+ }
+ void insertAtParent(const PetalNode *, UMLObject *item) {
+ UMLAssociation *assoc = static_cast<UMLAssociation*>(item);
+ assoc->setObject(m_classifier, Uml::A);
+ UMLApp::app()->getDocument()->addAssociation(assoc);
+ }
+protected:
+ UMLClassifier *m_classifier;
+};
+
+class RealizationsReader : public ClassifierListReader {
+public:
+ RealizationsReader(UMLClassifier *c)
+ : ClassifierListReader("realized_interfaces", "Realize_Relationship", "supplier") {
+ m_classifier = c;
+ }
+ virtual ~RealizationsReader() {}
+ UMLObject *createListItem() {
+ return new UMLAssociation(Uml::at_Realization);
+ }
+ /**
+ * Override parent implementation: The secondary data is not for the
+ * UMLAssociation itself but for its role B object.
+ */
+ void setTypeReferences(UMLObject *item,
+ const QString& quid, const QString& type) {
+ UMLAssociation *assoc = static_cast<UMLAssociation*>(item);
+ if (!quid.isEmpty()) {
+ assoc->getUMLRole(Uml::B)->setSecondaryId(quid);
+ }
+ if (!type.isEmpty()) {
+ assoc->getUMLRole(Uml::B)->setSecondaryFallback(type);
+ }
+ }
+ void insertAtParent(const PetalNode *, UMLObject *item) {
+ UMLAssociation *assoc = static_cast<UMLAssociation*>(item);
+ assoc->setObject(m_classifier, Uml::A);
+ UMLApp::app()->getDocument()->addAssociation(assoc);
+ }
+protected:
+ UMLClassifier *m_classifier;
+};
+
+/**
+ * Handle a controlled unit.
+ *
+ * @param node Pointer to the PetalNode which may contain a controlled unit
+ * @param name Name of the current node
+ * @param id QUID of the current node
+ * @param parentPkg Pointer to the current parent UMLPackage.
+ * @return True if the node actually contained a controlled unit.
+ */
+bool handleControlledUnit(PetalNode *node, const QString& name, Uml::IDType id, UMLPackage *parentPkg) {
+ if (node->findAttribute("is_unit").string != "TRUE")
+ return false;
+ bool is_loaded = (node->findAttribute("is_loaded").string != "FALSE");
+ QString file_name = node->findAttribute("file_name").string;
+ if (file_name.isEmpty()) {
+ kError() << "handleControlledUnit(" << name
+ << "): attribute file_name not found (?)" << endl;
+ return true;
+ }
+ // To Be Continued.
+
+ return true;
+}
+
+/**
+ * Create an Umbrello object from a PetalNode of the Logical View.
+ *
+ * @return True for success.
+ * Given a PetalNode for which the mapping to Umbrello is not yet
+ * implemented umbrellify() is a no-op but also returns true.
+ */
+bool umbrellify(PetalNode *node, UMLPackage *parentPkg = NULL) {
+ if (node == NULL) {
+ kError() << "umbrellify: node is NULL" << endl;
+ return false;
+ }
+ QStringList args = node->initialArgs();
+ QString objType = args[0];
+ QString name = clean(args[1]);
+ Uml::IDType id = quid(node);
+
+ if (objType == "Class_Category") {
+ UMLObject *o = Import_Utils::createUMLObject(Uml::ot_Package, name, parentPkg);
+ o->setID(id);
+ PetalNode *logical_models = node->findAttribute("logical_models").node;
+ if (logical_models) {
+ UMLPackage *localParent = static_cast<UMLPackage*>(o);
+ PetalNode::NameValueList atts = logical_models->attributes();
+ for (uint i = 0; i < atts.count(); i++) {
+ umbrellify(atts[i].second.node, localParent);
+ }
+ } else if (!handleControlledUnit(node, name, id, parentPkg)) {
+ kDebug() << "umbrellify: handling of " << objType << " " << name
+ << " is not yet implemented" << endl;
+ }
+
+ } else if (objType == "Class") {
+ UMLObject *o = Import_Utils::createUMLObject(Uml::ot_Class, name, parentPkg);
+ o->setID(id);
+ UMLClassifier *c = static_cast<UMLClassifier*>(o);
+ // set stereotype
+ QString stereotype = clean(node->findAttribute("stereotype").string);
+ if (!stereotype.isEmpty()) {
+ if (stereotype.lower() == "interface")
+ c->setBaseType(Uml::ot_Interface);
+ else
+ c->setStereotype(stereotype);
+ }
+ // insert attributes
+ AttributesReader attReader(c);
+ attReader.read(node, c->getName());
+ // insert operations
+ OperationsReader opReader(c);
+ opReader.read(node, c->getName());
+ // insert generalizations
+ SuperclassesReader superReader(c);
+ superReader.read(node, c->getName());
+ // insert realizations
+ RealizationsReader realReader(c);
+ realReader.read(node, c->getName());
+
+ } else if (objType == "Association") {
+ PetalNode *roles = node->findAttribute("roles").node;
+ if (node == NULL) {
+ kError() << "umbrellify: cannot find roles of Association" << endl;
+ return false;
+ }
+ UMLAssociation *assoc = new UMLAssociation(Uml::at_UniAssociation);
+ PetalNode::NameValueList roleList = roles->attributes();
+ for (uint i = 0; i <= 1; i++) {
+ PetalNode *roleNode = roleList[i].second.node;
+ if (roleNode == NULL) {
+ kError() << "umbrellify: roleNode of Association is NULL" << endl;
+ return false;
+ }
+ if (roleNode->name() != "Role") {
+ kDebug() << "umbrellify(" << name << "): expecting Role, found \""
+ << roleNode->name() << endl;
+ continue;
+ }
+ // index 0 corresponds to Umbrello roleB
+ // index 1 corresponds to Umbrello roleA
+ UMLRole *role = assoc->getUMLRole((Uml::Role_Type) !i);
+ QStringList initialArgs = roleNode->initialArgs();
+ if (initialArgs.count() > 1) {
+ QString roleName = clean(initialArgs[1]);
+ if (! roleName.startsWith("$UNNAMED"))
+ role->setName(roleName);
+ }
+ role->setID(quid(roleNode));
+ QString quidref = quidu(roleNode);
+ QString type = clean(roleNode->findAttribute("supplier").string);
+ if (!quidref.isEmpty()) {
+ role->setSecondaryId(quidref);
+ }
+ if (!type.isEmpty()) {
+ role->setSecondaryFallback(type);
+ }
+ QString label = clean(roleNode->findAttribute("label").string);
+ if (!label.isEmpty()) {
+ role->setName(label);
+ }
+ QString client_cardinality = clean(roleNode->findAttribute("client_cardinality").string);
+ if (!client_cardinality.isEmpty()) {
+ role->setMultiplicity(client_cardinality);
+ }
+ QString is_navigable = clean(roleNode->findAttribute("is_navigable").string);
+ if (is_navigable == "FALSE") {
+ assoc->setAssocType(Uml::at_Association);
+ }
+ QString is_aggregate = clean(roleNode->findAttribute("is_aggregate").string);
+ if (is_aggregate == "TRUE") {
+ assoc->setAssocType(Uml::at_Aggregation);
+ }
+ QString containment = clean(roleNode->findAttribute("Containment").string);
+ if (containment == "By Value") {
+ assoc->setAssocType(Uml::at_Composition);
+ }
+ QString doc = roleNode->findAttribute("documentation").string;
+ if (! doc.isEmpty())
+ role->setDoc(doc);
+ }
+ UMLApp::app()->getDocument()->addAssociation(assoc);
+
+ } else {
+ kDebug() << "umbrellify: object type " << objType
+ << " is not yet implemented" << endl;
+ }
+ return true;
+}
+
+Uml::ListView_Type folderType(UMLListViewItem *parent) {
+ Uml::ListView_Type type = Uml::lvt_Unknown;
+ switch (parent->getType()) {
+ case Uml::lvt_Logical_View:
+ case Uml::lvt_Logical_Folder:
+ type = Uml::lvt_Logical_Folder;
+ break;
+ case Uml::lvt_UseCase_View:
+ case Uml::lvt_UseCase_Folder:
+ type = Uml::lvt_UseCase_Folder;
+ break;
+ case Uml::lvt_Component_View:
+ case Uml::lvt_Component_Folder:
+ type = Uml::lvt_Component_Folder;
+ break;
+ case Uml::lvt_Deployment_View:
+ case Uml::lvt_Deployment_Folder:
+ type = Uml::lvt_Deployment_Folder;
+ break;
+ default:
+ break;
+ }
+ return type;
+}
+
+/**
+ * Create an Umbrello object from a PetalNode of the UseCase, Component,
+ * or Deployment View.
+ *
+ * @return True for success.
+ * Given a PetalNode for which the mapping to Umbrello is not yet
+ * implemented umbrellify() is a no-op but also returns true.
+ */
+bool umbrellify(PetalNode *node, const QString& modelsName, UMLListViewItem *parent) {
+ if (node == NULL) {
+ kError() << "umbrellify(" << modelsName << "): node is NULL" << endl;
+ return false;
+ }
+ QStringList args = node->initialArgs();
+ QString objType = args[0];
+ QString name = clean(args[1]);
+ Uml::IDType id = quid(node);
+ UMLObject *obj = NULL;
+ UMLListViewItem *item = NULL;
+
+ if (objType == "Class_Category") {
+ Uml::ListView_Type lvType = folderType(parent);
+ item = new UMLListViewItem( parent, name, lvType, id );
+ } else if (objType == "Class") {
+ QString stereotype = clean(node->findAttribute("stereotype").string);
+ if (stereotype == "Actor") {
+ UMLActor *act = new UMLActor(name, id);
+ item = new UMLListViewItem(parent, name, Uml::lvt_Actor, act);
+ obj = act;
+ } else {
+ kDebug() << "umbrellify(" << name << "): handling of Class stereotype "
+ << stereotype << " is not yet implemented" << endl;
+ }
+ } else if (objType == "UseCase") {
+ UMLUseCase *uc = new UMLUseCase(name, id);
+ item = new UMLListViewItem(parent, name, Uml::lvt_UseCase, uc);
+ obj = uc;
+ } else if (objType == "SubSystem") {
+ UMLComponent *comp = new UMLComponent(name, id);
+ item = new UMLListViewItem(parent, name, Uml::lvt_Component, comp);
+ obj = comp;
+ } else if (objType == "Processor" || objType == "Device") {
+ UMLNode *un = new UMLNode(name, id);
+ un->setStereotype(objType.lower());
+ item = new UMLListViewItem(parent, name, Uml::lvt_Node, un);
+ obj = un;
+ } else {
+ kDebug() << "umbrellify: object type " << objType
+ << " is not yet implemented" << endl;
+ return true;
+ }
+ PetalNode *models = node->findAttribute(modelsName).node;
+ if (models) {
+ PetalNode::NameValueList atts = models->attributes();
+ for (uint i = 0; i < atts.count(); i++) {
+ if (! umbrellify(atts[i].second.node, modelsName, item))
+ return false;
+ }
+ }
+ if (obj) {
+ QString doc = node->findAttribute("documentation").string;
+ if (! doc.isEmpty())
+ obj->setDoc(doc);
+ UMLDoc *theDocument = UMLApp::app()->getDocument();
+ theDocument->addUMLObject(obj);
+ }
+ return true;
+}
+
+/**
+ * Auxiliary function for UseCase/Component/Deployment view import
+ */
+bool importView(PetalNode *root, const QString& rootName,
+ const QString& modelsName, UMLListViewItem *lvParent) {
+ PetalNode *viewRoot = root->findAttribute(rootName).node;
+ if (viewRoot == NULL) {
+ kDebug() << "importView: cannot find " << rootName << endl;
+ return false;
+ }
+ PetalNode *models = viewRoot->findAttribute(modelsName).node;
+ if (models == NULL) {
+ kError() << "importView: cannot find " << modelsName
+ << " of " << rootName << endl;
+ return false;
+ }
+ PetalNode::NameValueList atts = models->attributes();
+ for (uint i = 0; i < atts.count(); i++) {
+ umbrellify(atts[i].second.node, modelsName, lvParent);
+ }
+ return true;
+}
+
+bool petalTree2Uml(PetalNode *root) {
+ if (root == NULL) {
+ kError() << "petalTree2Uml: root is NULL" << endl;
+ return false;
+ }
+ if (root->name() != "Design") {
+ kError() << "petalTree2Uml: expecting root name Design" << endl;
+ return false;
+ }
+ /*************************** import Logical View ********************************/
+ PetalNode *root_category = root->findAttribute("root_category").node;
+ if (root_category == NULL) {
+ kError() << "petalTree2Uml: cannot find root_category" << endl;
+ return false;
+ }
+ if (root_category->name() != "Class_Category") {
+ kError() << "petalTree2Uml: expecting root_category object Class_Category"
+ << endl;
+ return false;
+ }
+ PetalNode *logical_models = root_category->findAttribute("logical_models").node;
+ if (logical_models == NULL) {
+ kError() << "petalTree2Uml: cannot find logical_models" << endl;
+ return false;
+ }
+ UMLDoc *umldoc = UMLApp::app()->getDocument();
+ umldoc->setCurrentRoot(Uml::mt_Logical);
+ Import_Utils::assignUniqueIdOnCreation(false);
+ PetalNode::NameValueList atts = logical_models->attributes();
+ for (uint i = 0; i < atts.count(); i++) {
+ umbrellify(atts[i].second.node);
+ }
+
+ /** Shorthand for UMLApp::app()->getListView() **/
+ UMLListView *lv = UMLApp::app()->getListView();
+
+ /*************************** import Use Case View ********************************/
+ umldoc->setCurrentRoot(Uml::mt_UseCase);
+ importView(root, "root_usecase_package", "logical_models", lv->theUseCaseView());
+
+ /*************************** import Component View *******************************/
+ umldoc->setCurrentRoot(Uml::mt_Component);
+ importView(root, "root_subsystem", "physical_models", lv->theComponentView());
+
+ /*************************** import Deployment View ******************************/
+ umldoc->setCurrentRoot(Uml::mt_Deployment);
+ importView(root, "process_structure", "ProcsNDevs", lv->theDeploymentView());
+
+ /*************************** wrap up ********************************/
+ umldoc->setCurrentRoot(Uml::mt_Logical);
+ Import_Utils::assignUniqueIdOnCreation(true);
+ umldoc->resolveTypes();
+ return true;
+}
+
+} // namespace Import_Rose
+
diff --git a/umbrello/umbrello/petaltree2uml.h b/umbrello/umbrello/petaltree2uml.h
new file mode 100644
index 00000000..a60f3cbc
--- /dev/null
+++ b/umbrello/umbrello/petaltree2uml.h
@@ -0,0 +1,39 @@
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * copyright (C) 2006 *
+ * Umbrello UML Modeller Authors <uml-devel@uml.sf.net> *
+ ***************************************************************************/
+
+#ifndef PETALTREE2UML_H
+#define PETALTREE2UML_H
+
+// fwd decl
+class PetalNode;
+
+/**
+ * Traverse the PetalNode tree and create corresponding Umbrello objects
+ * for the PetalNodes encountered.
+ *
+ * @author Oliver Kellogg
+ * Bugs and comments to uml-devel@lists.sf.net or http://bugs.kde.org
+ */
+namespace Import_Rose {
+
+ /**
+ * This is really an auxiliary method for loadFromMDL() but is kept in a
+ * separate file to reflect that it is not coupled with the parser
+ * (other than by the PetalNode.)
+ *
+ * @return true for success.
+ */
+ bool petalTree2Uml(PetalNode *root);
+
+}
+
+#endif
+
diff --git a/umbrello/umbrello/pics/COPYING b/umbrello/umbrello/pics/COPYING
new file mode 100644
index 00000000..5e09cc93
--- /dev/null
+++ b/umbrello/umbrello/pics/COPYING
@@ -0,0 +1,3 @@
+Images under this directory as well as the Umbrello and Umbrello
+mimetype icons may be copied under the terms of the LGPL plus add-on as
+found in kdelibs/pics/LICENSE.crystalsvg
diff --git a/umbrello/umbrello/pics/CVglobal_meth.png b/umbrello/umbrello/pics/CVglobal_meth.png
new file mode 100644
index 00000000..a7bb6659
--- /dev/null
+++ b/umbrello/umbrello/pics/CVglobal_meth.png
Binary files differ
diff --git a/umbrello/umbrello/pics/CVglobal_var.png b/umbrello/umbrello/pics/CVglobal_var.png
new file mode 100644
index 00000000..f7f85455
--- /dev/null
+++ b/umbrello/umbrello/pics/CVglobal_var.png
Binary files differ
diff --git a/umbrello/umbrello/pics/CVimplementation_meth.png b/umbrello/umbrello/pics/CVimplementation_meth.png
new file mode 100644
index 00000000..97b23df4
--- /dev/null
+++ b/umbrello/umbrello/pics/CVimplementation_meth.png
Binary files differ
diff --git a/umbrello/umbrello/pics/CVimplementation_signal.png b/umbrello/umbrello/pics/CVimplementation_signal.png
new file mode 100644
index 00000000..c89e1e11
--- /dev/null
+++ b/umbrello/umbrello/pics/CVimplementation_signal.png
Binary files differ
diff --git a/umbrello/umbrello/pics/CVimplementation_slot.png b/umbrello/umbrello/pics/CVimplementation_slot.png
new file mode 100644
index 00000000..c1a77f5f
--- /dev/null
+++ b/umbrello/umbrello/pics/CVimplementation_slot.png
Binary files differ
diff --git a/umbrello/umbrello/pics/CVimplementation_var.png b/umbrello/umbrello/pics/CVimplementation_var.png
new file mode 100644
index 00000000..026df532
--- /dev/null
+++ b/umbrello/umbrello/pics/CVimplementation_var.png
Binary files differ
diff --git a/umbrello/umbrello/pics/CVnamespace.png b/umbrello/umbrello/pics/CVnamespace.png
new file mode 100644
index 00000000..bc40283d
--- /dev/null
+++ b/umbrello/umbrello/pics/CVnamespace.png
Binary files differ
diff --git a/umbrello/umbrello/pics/CVprivate_meth.png b/umbrello/umbrello/pics/CVprivate_meth.png
new file mode 100644
index 00000000..45c7b3e1
--- /dev/null
+++ b/umbrello/umbrello/pics/CVprivate_meth.png
Binary files differ
diff --git a/umbrello/umbrello/pics/CVprivate_signal.png b/umbrello/umbrello/pics/CVprivate_signal.png
new file mode 100644
index 00000000..114a7148
--- /dev/null
+++ b/umbrello/umbrello/pics/CVprivate_signal.png
Binary files differ
diff --git a/umbrello/umbrello/pics/CVprivate_slot.png b/umbrello/umbrello/pics/CVprivate_slot.png
new file mode 100644
index 00000000..e9b8ecd6
--- /dev/null
+++ b/umbrello/umbrello/pics/CVprivate_slot.png
Binary files differ
diff --git a/umbrello/umbrello/pics/CVprivate_var.png b/umbrello/umbrello/pics/CVprivate_var.png
new file mode 100644
index 00000000..4bf6180c
--- /dev/null
+++ b/umbrello/umbrello/pics/CVprivate_var.png
Binary files differ
diff --git a/umbrello/umbrello/pics/CVprotected_meth.png b/umbrello/umbrello/pics/CVprotected_meth.png
new file mode 100644
index 00000000..fe96d4db
--- /dev/null
+++ b/umbrello/umbrello/pics/CVprotected_meth.png
Binary files differ
diff --git a/umbrello/umbrello/pics/CVprotected_signal.png b/umbrello/umbrello/pics/CVprotected_signal.png
new file mode 100644
index 00000000..07aef0b3
--- /dev/null
+++ b/umbrello/umbrello/pics/CVprotected_signal.png
Binary files differ
diff --git a/umbrello/umbrello/pics/CVprotected_slot.png b/umbrello/umbrello/pics/CVprotected_slot.png
new file mode 100644
index 00000000..db084899
--- /dev/null
+++ b/umbrello/umbrello/pics/CVprotected_slot.png
Binary files differ
diff --git a/umbrello/umbrello/pics/CVprotected_var.png b/umbrello/umbrello/pics/CVprotected_var.png
new file mode 100644
index 00000000..f97903f0
--- /dev/null
+++ b/umbrello/umbrello/pics/CVprotected_var.png
Binary files differ
diff --git a/umbrello/umbrello/pics/CVpublic_meth.png b/umbrello/umbrello/pics/CVpublic_meth.png
new file mode 100644
index 00000000..56063b02
--- /dev/null
+++ b/umbrello/umbrello/pics/CVpublic_meth.png
Binary files differ
diff --git a/umbrello/umbrello/pics/CVpublic_signal.png b/umbrello/umbrello/pics/CVpublic_signal.png
new file mode 100644
index 00000000..5a101850
--- /dev/null
+++ b/umbrello/umbrello/pics/CVpublic_signal.png
Binary files differ
diff --git a/umbrello/umbrello/pics/CVpublic_slot.png b/umbrello/umbrello/pics/CVpublic_slot.png
new file mode 100644
index 00000000..b04b49de
--- /dev/null
+++ b/umbrello/umbrello/pics/CVpublic_slot.png
Binary files differ
diff --git a/umbrello/umbrello/pics/CVpublic_var.png b/umbrello/umbrello/pics/CVpublic_var.png
new file mode 100644
index 00000000..d17730e7
--- /dev/null
+++ b/umbrello/umbrello/pics/CVpublic_var.png
Binary files differ
diff --git a/umbrello/umbrello/pics/CVstruct.png b/umbrello/umbrello/pics/CVstruct.png
new file mode 100644
index 00000000..ec953add
--- /dev/null
+++ b/umbrello/umbrello/pics/CVstruct.png
Binary files differ
diff --git a/umbrello/umbrello/pics/Makefile.am b/umbrello/umbrello/pics/Makefile.am
new file mode 100644
index 00000000..43292145
--- /dev/null
+++ b/umbrello/umbrello/pics/Makefile.am
@@ -0,0 +1,112 @@
+picsdir = $(kde_datadir)/umbrello/pics
+
+pics_DATA = actor.png \
+aggregation.png \
+align_left.png \
+align_right.png \
+align_top.png \
+align_bottom.png \
+align_vert_middle.png \
+align_hori_middle.png \
+align_vert_distribute.png \
+align_hori_distribute.png \
+anchor.png \
+andline.png \
+arrow.png \
+association.png \
+choice-rhomb.png \
+choice-round.png \
+component.png \
+composition.png \
+containment.png \
+CVglobal_meth.png \
+CVglobal_var.png \
+CVimplementation_meth.png \
+CVimplementation_signal.png \
+CVimplementation_slot.png \
+CVimplementation_var.png \
+CVnamespace.png \
+CVprivate_meth.png \
+CVprivate_signal.png \
+CVprivate_slot.png \
+CVprivate_var.png \
+CVprotected_meth.png \
+CVprotected_signal.png \
+CVprotected_slot.png \
+CVprotected_var.png \
+CVpublic_meth.png \
+CVpublic_signal.png \
+CVpublic_slot.png \
+CVpublic_var.png \
+CVstruct.png \
+deep-history.png \
+shallow-history.png \
+dependency.png \
+end_state.png \
+generalisation.png \
+initial_state.png \
+interface.png \
+join.png \
+junction.png \
+datatype.png \
+enum.png \
+message-synchronous.png \
+message-asynchronous.png \
+note.png \
+object.png \
+startlogo.png \
+template.png \
+text.png \
+class.png \
+uniassociation.png \
+usecase.png \
+branch.png \
+fork.png \
+state-fork.png \
+package.png \
+subsystem.png \
+artifact.png \
+box.png \
+node.png \
+entity.png \
+relationship.png \
+cursor-actor.png \
+cursor-andline.png \
+cursor-choice-rhomb.png \
+cursor-choice-round.png \
+cursor-deep-history.png \
+cursor-join.png \
+cursor-junction.png \
+cursor-shallow-history.png \
+cursor-state-fork.png \
+cursor-usecase.png \
+cursor-initial_state.png \
+cursor-package.png \
+cursor-aggregation.png \
+cursor-component.png \
+cursor-containment.png \
+cursor-interface.png \
+cursor-datatype.png \
+cursor-enum.png \
+cursor-text.png \
+cursor-anchor.png \
+cursor-composition.png \
+cursor-message-asynchronous.png \
+cursor-class.png \
+cursor-artifact.png \
+cursor-dependency.png \
+cursor-message-synchronous.png \
+cursor-uniassociation.png \
+cursor-association.png \
+cursor-end_state.png \
+cursor-node.png \
+cursor-box.png \
+cursor-fork.png \
+cursor-note.png \
+cursor-branch.png \
+cursor-generalisation.png \
+cursor-object.png \
+cursor-entity.png \
+cursor-relationship.png
+
+KDE_ICON = umbrello_diagram_activity umbrello_diagram_class umbrello_diagram_collaboration umbrello_diagram_component umbrello_diagram_deployment umbrello_diagram_sequence umbrello_diagram_state umbrello_diagram_usecase umbrello_diagram_entityrelationship
diff --git a/umbrello/umbrello/pics/actor.png b/umbrello/umbrello/pics/actor.png
new file mode 100644
index 00000000..728be176
--- /dev/null
+++ b/umbrello/umbrello/pics/actor.png
Binary files differ
diff --git a/umbrello/umbrello/pics/aggregation.png b/umbrello/umbrello/pics/aggregation.png
new file mode 100644
index 00000000..cb9ce67d
--- /dev/null
+++ b/umbrello/umbrello/pics/aggregation.png
Binary files differ
diff --git a/umbrello/umbrello/pics/align_bottom.png b/umbrello/umbrello/pics/align_bottom.png
new file mode 100644
index 00000000..555239ec
--- /dev/null
+++ b/umbrello/umbrello/pics/align_bottom.png
Binary files differ
diff --git a/umbrello/umbrello/pics/align_hori_distribute.png b/umbrello/umbrello/pics/align_hori_distribute.png
new file mode 100644
index 00000000..03215af6
--- /dev/null
+++ b/umbrello/umbrello/pics/align_hori_distribute.png
Binary files differ
diff --git a/umbrello/umbrello/pics/align_hori_middle.png b/umbrello/umbrello/pics/align_hori_middle.png
new file mode 100644
index 00000000..62956a49
--- /dev/null
+++ b/umbrello/umbrello/pics/align_hori_middle.png
Binary files differ
diff --git a/umbrello/umbrello/pics/align_left.png b/umbrello/umbrello/pics/align_left.png
new file mode 100644
index 00000000..9bf21f99
--- /dev/null
+++ b/umbrello/umbrello/pics/align_left.png
Binary files differ
diff --git a/umbrello/umbrello/pics/align_right.png b/umbrello/umbrello/pics/align_right.png
new file mode 100644
index 00000000..80b5c0c5
--- /dev/null
+++ b/umbrello/umbrello/pics/align_right.png
Binary files differ
diff --git a/umbrello/umbrello/pics/align_top.png b/umbrello/umbrello/pics/align_top.png
new file mode 100644
index 00000000..b168cd5a
--- /dev/null
+++ b/umbrello/umbrello/pics/align_top.png
Binary files differ
diff --git a/umbrello/umbrello/pics/align_vert_distribute.png b/umbrello/umbrello/pics/align_vert_distribute.png
new file mode 100644
index 00000000..7da67730
--- /dev/null
+++ b/umbrello/umbrello/pics/align_vert_distribute.png
Binary files differ
diff --git a/umbrello/umbrello/pics/align_vert_middle.png b/umbrello/umbrello/pics/align_vert_middle.png
new file mode 100644
index 00000000..096782fc
--- /dev/null
+++ b/umbrello/umbrello/pics/align_vert_middle.png
Binary files differ
diff --git a/umbrello/umbrello/pics/anchor.png b/umbrello/umbrello/pics/anchor.png
new file mode 100644
index 00000000..9fc2bc06
--- /dev/null
+++ b/umbrello/umbrello/pics/anchor.png
Binary files differ
diff --git a/umbrello/umbrello/pics/andline.png b/umbrello/umbrello/pics/andline.png
new file mode 100644
index 00000000..7fe6081b
--- /dev/null
+++ b/umbrello/umbrello/pics/andline.png
Binary files differ
diff --git a/umbrello/umbrello/pics/arrow.png b/umbrello/umbrello/pics/arrow.png
new file mode 100644
index 00000000..6f48d945
--- /dev/null
+++ b/umbrello/umbrello/pics/arrow.png
Binary files differ
diff --git a/umbrello/umbrello/pics/artifact.png b/umbrello/umbrello/pics/artifact.png
new file mode 100644
index 00000000..41e3ccd9
--- /dev/null
+++ b/umbrello/umbrello/pics/artifact.png
Binary files differ
diff --git a/umbrello/umbrello/pics/association.png b/umbrello/umbrello/pics/association.png
new file mode 100644
index 00000000..60f742bb
--- /dev/null
+++ b/umbrello/umbrello/pics/association.png
Binary files differ
diff --git a/umbrello/umbrello/pics/box.png b/umbrello/umbrello/pics/box.png
new file mode 100644
index 00000000..03e2b41b
--- /dev/null
+++ b/umbrello/umbrello/pics/box.png
Binary files differ
diff --git a/umbrello/umbrello/pics/branch.png b/umbrello/umbrello/pics/branch.png
new file mode 100644
index 00000000..36bea8f5
--- /dev/null
+++ b/umbrello/umbrello/pics/branch.png
Binary files differ
diff --git a/umbrello/umbrello/pics/choice-rhomb.png b/umbrello/umbrello/pics/choice-rhomb.png
new file mode 100644
index 00000000..d067c3ee
--- /dev/null
+++ b/umbrello/umbrello/pics/choice-rhomb.png
Binary files differ
diff --git a/umbrello/umbrello/pics/choice-round.png b/umbrello/umbrello/pics/choice-round.png
new file mode 100644
index 00000000..423748d8
--- /dev/null
+++ b/umbrello/umbrello/pics/choice-round.png
Binary files differ
diff --git a/umbrello/umbrello/pics/class.png b/umbrello/umbrello/pics/class.png
new file mode 100644
index 00000000..8b47d5b0
--- /dev/null
+++ b/umbrello/umbrello/pics/class.png
Binary files differ
diff --git a/umbrello/umbrello/pics/component.png b/umbrello/umbrello/pics/component.png
new file mode 100644
index 00000000..1ba3d604
--- /dev/null
+++ b/umbrello/umbrello/pics/component.png
Binary files differ
diff --git a/umbrello/umbrello/pics/composition.png b/umbrello/umbrello/pics/composition.png
new file mode 100644
index 00000000..3d53ea48
--- /dev/null
+++ b/umbrello/umbrello/pics/composition.png
Binary files differ
diff --git a/umbrello/umbrello/pics/containment.png b/umbrello/umbrello/pics/containment.png
new file mode 100644
index 00000000..1972fda5
--- /dev/null
+++ b/umbrello/umbrello/pics/containment.png
Binary files differ
diff --git a/umbrello/umbrello/pics/cr16-action-umbrello_diagram_activity.png b/umbrello/umbrello/pics/cr16-action-umbrello_diagram_activity.png
new file mode 100644
index 00000000..0295b8b6
--- /dev/null
+++ b/umbrello/umbrello/pics/cr16-action-umbrello_diagram_activity.png
Binary files differ
diff --git a/umbrello/umbrello/pics/cr16-action-umbrello_diagram_class.png b/umbrello/umbrello/pics/cr16-action-umbrello_diagram_class.png
new file mode 100644
index 00000000..0e8c6060
--- /dev/null
+++ b/umbrello/umbrello/pics/cr16-action-umbrello_diagram_class.png
Binary files differ
diff --git a/umbrello/umbrello/pics/cr16-action-umbrello_diagram_collaboration.png b/umbrello/umbrello/pics/cr16-action-umbrello_diagram_collaboration.png
new file mode 100644
index 00000000..76207be2
--- /dev/null
+++ b/umbrello/umbrello/pics/cr16-action-umbrello_diagram_collaboration.png
Binary files differ
diff --git a/umbrello/umbrello/pics/cr16-action-umbrello_diagram_component.png b/umbrello/umbrello/pics/cr16-action-umbrello_diagram_component.png
new file mode 100644
index 00000000..f80cc31f
--- /dev/null
+++ b/umbrello/umbrello/pics/cr16-action-umbrello_diagram_component.png
Binary files differ
diff --git a/umbrello/umbrello/pics/cr16-action-umbrello_diagram_deployment.png b/umbrello/umbrello/pics/cr16-action-umbrello_diagram_deployment.png
new file mode 100644
index 00000000..fe515150
--- /dev/null
+++ b/umbrello/umbrello/pics/cr16-action-umbrello_diagram_deployment.png
Binary files differ
diff --git a/umbrello/umbrello/pics/cr16-action-umbrello_diagram_sequence.png b/umbrello/umbrello/pics/cr16-action-umbrello_diagram_sequence.png
new file mode 100644
index 00000000..e60ca4c6
--- /dev/null
+++ b/umbrello/umbrello/pics/cr16-action-umbrello_diagram_sequence.png
Binary files differ
diff --git a/umbrello/umbrello/pics/cr16-action-umbrello_diagram_state.png b/umbrello/umbrello/pics/cr16-action-umbrello_diagram_state.png
new file mode 100644
index 00000000..4fe826df
--- /dev/null
+++ b/umbrello/umbrello/pics/cr16-action-umbrello_diagram_state.png
Binary files differ
diff --git a/umbrello/umbrello/pics/cr16-action-umbrello_diagram_usecase.png b/umbrello/umbrello/pics/cr16-action-umbrello_diagram_usecase.png
new file mode 100644
index 00000000..3259c733
--- /dev/null
+++ b/umbrello/umbrello/pics/cr16-action-umbrello_diagram_usecase.png
Binary files differ
diff --git a/umbrello/umbrello/pics/cr22-action-umbrello_diagram_activity.png b/umbrello/umbrello/pics/cr22-action-umbrello_diagram_activity.png
new file mode 100644
index 00000000..053af9e5
--- /dev/null
+++ b/umbrello/umbrello/pics/cr22-action-umbrello_diagram_activity.png
Binary files differ
diff --git a/umbrello/umbrello/pics/cr22-action-umbrello_diagram_class.png b/umbrello/umbrello/pics/cr22-action-umbrello_diagram_class.png
new file mode 100644
index 00000000..cf9e168d
--- /dev/null
+++ b/umbrello/umbrello/pics/cr22-action-umbrello_diagram_class.png
Binary files differ
diff --git a/umbrello/umbrello/pics/cr22-action-umbrello_diagram_collaboration.png b/umbrello/umbrello/pics/cr22-action-umbrello_diagram_collaboration.png
new file mode 100644
index 00000000..323947e8
--- /dev/null
+++ b/umbrello/umbrello/pics/cr22-action-umbrello_diagram_collaboration.png
Binary files differ
diff --git a/umbrello/umbrello/pics/cr22-action-umbrello_diagram_component.png b/umbrello/umbrello/pics/cr22-action-umbrello_diagram_component.png
new file mode 100644
index 00000000..48202c8f
--- /dev/null
+++ b/umbrello/umbrello/pics/cr22-action-umbrello_diagram_component.png
Binary files differ
diff --git a/umbrello/umbrello/pics/cr22-action-umbrello_diagram_deployment.png b/umbrello/umbrello/pics/cr22-action-umbrello_diagram_deployment.png
new file mode 100644
index 00000000..5343363c
--- /dev/null
+++ b/umbrello/umbrello/pics/cr22-action-umbrello_diagram_deployment.png
Binary files differ
diff --git a/umbrello/umbrello/pics/cr22-action-umbrello_diagram_entityrelationship.png b/umbrello/umbrello/pics/cr22-action-umbrello_diagram_entityrelationship.png
new file mode 100644
index 00000000..570b8ac1
--- /dev/null
+++ b/umbrello/umbrello/pics/cr22-action-umbrello_diagram_entityrelationship.png
Binary files differ
diff --git a/umbrello/umbrello/pics/cr22-action-umbrello_diagram_sequence.png b/umbrello/umbrello/pics/cr22-action-umbrello_diagram_sequence.png
new file mode 100644
index 00000000..b2cfd3c2
--- /dev/null
+++ b/umbrello/umbrello/pics/cr22-action-umbrello_diagram_sequence.png
Binary files differ
diff --git a/umbrello/umbrello/pics/cr22-action-umbrello_diagram_state.png b/umbrello/umbrello/pics/cr22-action-umbrello_diagram_state.png
new file mode 100644
index 00000000..f812a17c
--- /dev/null
+++ b/umbrello/umbrello/pics/cr22-action-umbrello_diagram_state.png
Binary files differ
diff --git a/umbrello/umbrello/pics/cr22-action-umbrello_diagram_usecase.png b/umbrello/umbrello/pics/cr22-action-umbrello_diagram_usecase.png
new file mode 100644
index 00000000..bc07439d
--- /dev/null
+++ b/umbrello/umbrello/pics/cr22-action-umbrello_diagram_usecase.png
Binary files differ
diff --git a/umbrello/umbrello/pics/cursor-actor.png b/umbrello/umbrello/pics/cursor-actor.png
new file mode 100644
index 00000000..97e05a98
--- /dev/null
+++ b/umbrello/umbrello/pics/cursor-actor.png
Binary files differ
diff --git a/umbrello/umbrello/pics/cursor-aggregation.png b/umbrello/umbrello/pics/cursor-aggregation.png
new file mode 100644
index 00000000..f75e323d
--- /dev/null
+++ b/umbrello/umbrello/pics/cursor-aggregation.png
Binary files differ
diff --git a/umbrello/umbrello/pics/cursor-anchor.png b/umbrello/umbrello/pics/cursor-anchor.png
new file mode 100644
index 00000000..6facf249
--- /dev/null
+++ b/umbrello/umbrello/pics/cursor-anchor.png
Binary files differ
diff --git a/umbrello/umbrello/pics/cursor-andline.png b/umbrello/umbrello/pics/cursor-andline.png
new file mode 100644
index 00000000..ca66655d
--- /dev/null
+++ b/umbrello/umbrello/pics/cursor-andline.png
Binary files differ
diff --git a/umbrello/umbrello/pics/cursor-artifact.png b/umbrello/umbrello/pics/cursor-artifact.png
new file mode 100644
index 00000000..47965eed
--- /dev/null
+++ b/umbrello/umbrello/pics/cursor-artifact.png
Binary files differ
diff --git a/umbrello/umbrello/pics/cursor-association.png b/umbrello/umbrello/pics/cursor-association.png
new file mode 100644
index 00000000..543a857d
--- /dev/null
+++ b/umbrello/umbrello/pics/cursor-association.png
Binary files differ
diff --git a/umbrello/umbrello/pics/cursor-box.png b/umbrello/umbrello/pics/cursor-box.png
new file mode 100644
index 00000000..c4fea53c
--- /dev/null
+++ b/umbrello/umbrello/pics/cursor-box.png
Binary files differ
diff --git a/umbrello/umbrello/pics/cursor-branch.png b/umbrello/umbrello/pics/cursor-branch.png
new file mode 100644
index 00000000..a7f04705
--- /dev/null
+++ b/umbrello/umbrello/pics/cursor-branch.png
Binary files differ
diff --git a/umbrello/umbrello/pics/cursor-choice-rhomb.png b/umbrello/umbrello/pics/cursor-choice-rhomb.png
new file mode 100644
index 00000000..84db46bd
--- /dev/null
+++ b/umbrello/umbrello/pics/cursor-choice-rhomb.png
Binary files differ
diff --git a/umbrello/umbrello/pics/cursor-choice-round.png b/umbrello/umbrello/pics/cursor-choice-round.png
new file mode 100644
index 00000000..5cad8062
--- /dev/null
+++ b/umbrello/umbrello/pics/cursor-choice-round.png
Binary files differ
diff --git a/umbrello/umbrello/pics/cursor-class.png b/umbrello/umbrello/pics/cursor-class.png
new file mode 100644
index 00000000..4be74cee
--- /dev/null
+++ b/umbrello/umbrello/pics/cursor-class.png
Binary files differ
diff --git a/umbrello/umbrello/pics/cursor-component.png b/umbrello/umbrello/pics/cursor-component.png
new file mode 100644
index 00000000..6b4a814e
--- /dev/null
+++ b/umbrello/umbrello/pics/cursor-component.png
Binary files differ
diff --git a/umbrello/umbrello/pics/cursor-composition.png b/umbrello/umbrello/pics/cursor-composition.png
new file mode 100644
index 00000000..f2eabb9c
--- /dev/null
+++ b/umbrello/umbrello/pics/cursor-composition.png
Binary files differ
diff --git a/umbrello/umbrello/pics/cursor-containment.png b/umbrello/umbrello/pics/cursor-containment.png
new file mode 100644
index 00000000..824074b6
--- /dev/null
+++ b/umbrello/umbrello/pics/cursor-containment.png
Binary files differ
diff --git a/umbrello/umbrello/pics/cursor-datatype.png b/umbrello/umbrello/pics/cursor-datatype.png
new file mode 100644
index 00000000..82f20c16
--- /dev/null
+++ b/umbrello/umbrello/pics/cursor-datatype.png
Binary files differ
diff --git a/umbrello/umbrello/pics/cursor-deep-history.png b/umbrello/umbrello/pics/cursor-deep-history.png
new file mode 100644
index 00000000..9d8550d7
--- /dev/null
+++ b/umbrello/umbrello/pics/cursor-deep-history.png
Binary files differ
diff --git a/umbrello/umbrello/pics/cursor-dependency.png b/umbrello/umbrello/pics/cursor-dependency.png
new file mode 100644
index 00000000..621ddb6e
--- /dev/null
+++ b/umbrello/umbrello/pics/cursor-dependency.png
Binary files differ
diff --git a/umbrello/umbrello/pics/cursor-end_state.png b/umbrello/umbrello/pics/cursor-end_state.png
new file mode 100644
index 00000000..a282e503
--- /dev/null
+++ b/umbrello/umbrello/pics/cursor-end_state.png
Binary files differ
diff --git a/umbrello/umbrello/pics/cursor-entity.png b/umbrello/umbrello/pics/cursor-entity.png
new file mode 100644
index 00000000..dd103eb0
--- /dev/null
+++ b/umbrello/umbrello/pics/cursor-entity.png
Binary files differ
diff --git a/umbrello/umbrello/pics/cursor-enum.png b/umbrello/umbrello/pics/cursor-enum.png
new file mode 100644
index 00000000..d4cc0525
--- /dev/null
+++ b/umbrello/umbrello/pics/cursor-enum.png
Binary files differ
diff --git a/umbrello/umbrello/pics/cursor-fork.png b/umbrello/umbrello/pics/cursor-fork.png
new file mode 100644
index 00000000..40edc63c
--- /dev/null
+++ b/umbrello/umbrello/pics/cursor-fork.png
Binary files differ
diff --git a/umbrello/umbrello/pics/cursor-generalisation.png b/umbrello/umbrello/pics/cursor-generalisation.png
new file mode 100644
index 00000000..fa7a71ab
--- /dev/null
+++ b/umbrello/umbrello/pics/cursor-generalisation.png
Binary files differ
diff --git a/umbrello/umbrello/pics/cursor-initial_state.png b/umbrello/umbrello/pics/cursor-initial_state.png
new file mode 100644
index 00000000..91ae1b3e
--- /dev/null
+++ b/umbrello/umbrello/pics/cursor-initial_state.png
Binary files differ
diff --git a/umbrello/umbrello/pics/cursor-interface.png b/umbrello/umbrello/pics/cursor-interface.png
new file mode 100644
index 00000000..ad8277d5
--- /dev/null
+++ b/umbrello/umbrello/pics/cursor-interface.png
Binary files differ
diff --git a/umbrello/umbrello/pics/cursor-join.png b/umbrello/umbrello/pics/cursor-join.png
new file mode 100644
index 00000000..a485f4a8
--- /dev/null
+++ b/umbrello/umbrello/pics/cursor-join.png
Binary files differ
diff --git a/umbrello/umbrello/pics/cursor-junction.png b/umbrello/umbrello/pics/cursor-junction.png
new file mode 100644
index 00000000..be0ddee0
--- /dev/null
+++ b/umbrello/umbrello/pics/cursor-junction.png
Binary files differ
diff --git a/umbrello/umbrello/pics/cursor-message-asynchronous.png b/umbrello/umbrello/pics/cursor-message-asynchronous.png
new file mode 100644
index 00000000..549afe0e
--- /dev/null
+++ b/umbrello/umbrello/pics/cursor-message-asynchronous.png
Binary files differ
diff --git a/umbrello/umbrello/pics/cursor-message-synchronous.png b/umbrello/umbrello/pics/cursor-message-synchronous.png
new file mode 100644
index 00000000..a6535c12
--- /dev/null
+++ b/umbrello/umbrello/pics/cursor-message-synchronous.png
Binary files differ
diff --git a/umbrello/umbrello/pics/cursor-node.png b/umbrello/umbrello/pics/cursor-node.png
new file mode 100644
index 00000000..c4a14312
--- /dev/null
+++ b/umbrello/umbrello/pics/cursor-node.png
Binary files differ
diff --git a/umbrello/umbrello/pics/cursor-note.png b/umbrello/umbrello/pics/cursor-note.png
new file mode 100644
index 00000000..6b656a2e
--- /dev/null
+++ b/umbrello/umbrello/pics/cursor-note.png
Binary files differ
diff --git a/umbrello/umbrello/pics/cursor-object.png b/umbrello/umbrello/pics/cursor-object.png
new file mode 100644
index 00000000..97e0f7bf
--- /dev/null
+++ b/umbrello/umbrello/pics/cursor-object.png
Binary files differ
diff --git a/umbrello/umbrello/pics/cursor-package.png b/umbrello/umbrello/pics/cursor-package.png
new file mode 100644
index 00000000..afdbdbbe
--- /dev/null
+++ b/umbrello/umbrello/pics/cursor-package.png
Binary files differ
diff --git a/umbrello/umbrello/pics/cursor-relationship.png b/umbrello/umbrello/pics/cursor-relationship.png
new file mode 100644
index 00000000..5c4d27a3
--- /dev/null
+++ b/umbrello/umbrello/pics/cursor-relationship.png
Binary files differ
diff --git a/umbrello/umbrello/pics/cursor-shallow-history.png b/umbrello/umbrello/pics/cursor-shallow-history.png
new file mode 100644
index 00000000..8e3a83b2
--- /dev/null
+++ b/umbrello/umbrello/pics/cursor-shallow-history.png
Binary files differ
diff --git a/umbrello/umbrello/pics/cursor-state-fork.png b/umbrello/umbrello/pics/cursor-state-fork.png
new file mode 100644
index 00000000..b1028ef7
--- /dev/null
+++ b/umbrello/umbrello/pics/cursor-state-fork.png
Binary files differ
diff --git a/umbrello/umbrello/pics/cursor-text.png b/umbrello/umbrello/pics/cursor-text.png
new file mode 100644
index 00000000..91058cb0
--- /dev/null
+++ b/umbrello/umbrello/pics/cursor-text.png
Binary files differ
diff --git a/umbrello/umbrello/pics/cursor-uniassociation.png b/umbrello/umbrello/pics/cursor-uniassociation.png
new file mode 100644
index 00000000..b8980073
--- /dev/null
+++ b/umbrello/umbrello/pics/cursor-uniassociation.png
Binary files differ
diff --git a/umbrello/umbrello/pics/cursor-usecase.png b/umbrello/umbrello/pics/cursor-usecase.png
new file mode 100644
index 00000000..d91d5b40
--- /dev/null
+++ b/umbrello/umbrello/pics/cursor-usecase.png
Binary files differ
diff --git a/umbrello/umbrello/pics/datatype.png b/umbrello/umbrello/pics/datatype.png
new file mode 100644
index 00000000..cce13889
--- /dev/null
+++ b/umbrello/umbrello/pics/datatype.png
Binary files differ
diff --git a/umbrello/umbrello/pics/deep-history.png b/umbrello/umbrello/pics/deep-history.png
new file mode 100644
index 00000000..01b9d64d
--- /dev/null
+++ b/umbrello/umbrello/pics/deep-history.png
Binary files differ
diff --git a/umbrello/umbrello/pics/dependency.png b/umbrello/umbrello/pics/dependency.png
new file mode 100644
index 00000000..0cd1a323
--- /dev/null
+++ b/umbrello/umbrello/pics/dependency.png
Binary files differ
diff --git a/umbrello/umbrello/pics/end_state.png b/umbrello/umbrello/pics/end_state.png
new file mode 100644
index 00000000..ac78110c
--- /dev/null
+++ b/umbrello/umbrello/pics/end_state.png
Binary files differ
diff --git a/umbrello/umbrello/pics/entity.png b/umbrello/umbrello/pics/entity.png
new file mode 100644
index 00000000..2983c1db
--- /dev/null
+++ b/umbrello/umbrello/pics/entity.png
Binary files differ
diff --git a/umbrello/umbrello/pics/enum.png b/umbrello/umbrello/pics/enum.png
new file mode 100644
index 00000000..d4b9fcd8
--- /dev/null
+++ b/umbrello/umbrello/pics/enum.png
Binary files differ
diff --git a/umbrello/umbrello/pics/fork.png b/umbrello/umbrello/pics/fork.png
new file mode 100644
index 00000000..abb0649b
--- /dev/null
+++ b/umbrello/umbrello/pics/fork.png
Binary files differ
diff --git a/umbrello/umbrello/pics/generalisation.png b/umbrello/umbrello/pics/generalisation.png
new file mode 100644
index 00000000..2ea9d66d
--- /dev/null
+++ b/umbrello/umbrello/pics/generalisation.png
Binary files differ
diff --git a/umbrello/umbrello/pics/initial_state.png b/umbrello/umbrello/pics/initial_state.png
new file mode 100644
index 00000000..d5d6f4f3
--- /dev/null
+++ b/umbrello/umbrello/pics/initial_state.png
Binary files differ
diff --git a/umbrello/umbrello/pics/interface.png b/umbrello/umbrello/pics/interface.png
new file mode 100644
index 00000000..66d52761
--- /dev/null
+++ b/umbrello/umbrello/pics/interface.png
Binary files differ
diff --git a/umbrello/umbrello/pics/join.png b/umbrello/umbrello/pics/join.png
new file mode 100644
index 00000000..0582a7dc
--- /dev/null
+++ b/umbrello/umbrello/pics/join.png
Binary files differ
diff --git a/umbrello/umbrello/pics/junction.png b/umbrello/umbrello/pics/junction.png
new file mode 100644
index 00000000..ee131fa2
--- /dev/null
+++ b/umbrello/umbrello/pics/junction.png
Binary files differ
diff --git a/umbrello/umbrello/pics/message-asynchronous.png b/umbrello/umbrello/pics/message-asynchronous.png
new file mode 100644
index 00000000..21eb52f7
--- /dev/null
+++ b/umbrello/umbrello/pics/message-asynchronous.png
Binary files differ
diff --git a/umbrello/umbrello/pics/message-synchronous.png b/umbrello/umbrello/pics/message-synchronous.png
new file mode 100644
index 00000000..0567346d
--- /dev/null
+++ b/umbrello/umbrello/pics/message-synchronous.png
Binary files differ
diff --git a/umbrello/umbrello/pics/node.png b/umbrello/umbrello/pics/node.png
new file mode 100644
index 00000000..6a12d3a1
--- /dev/null
+++ b/umbrello/umbrello/pics/node.png
Binary files differ
diff --git a/umbrello/umbrello/pics/note.png b/umbrello/umbrello/pics/note.png
new file mode 100644
index 00000000..11bc3dd9
--- /dev/null
+++ b/umbrello/umbrello/pics/note.png
Binary files differ
diff --git a/umbrello/umbrello/pics/object.png b/umbrello/umbrello/pics/object.png
new file mode 100644
index 00000000..eb246070
--- /dev/null
+++ b/umbrello/umbrello/pics/object.png
Binary files differ
diff --git a/umbrello/umbrello/pics/package.png b/umbrello/umbrello/pics/package.png
new file mode 100644
index 00000000..8f35b7c2
--- /dev/null
+++ b/umbrello/umbrello/pics/package.png
Binary files differ
diff --git a/umbrello/umbrello/pics/relationship.png b/umbrello/umbrello/pics/relationship.png
new file mode 100644
index 00000000..8154868e
--- /dev/null
+++ b/umbrello/umbrello/pics/relationship.png
Binary files differ
diff --git a/umbrello/umbrello/pics/shallow-history.png b/umbrello/umbrello/pics/shallow-history.png
new file mode 100644
index 00000000..7d871cc1
--- /dev/null
+++ b/umbrello/umbrello/pics/shallow-history.png
Binary files differ
diff --git a/umbrello/umbrello/pics/sources/actor.svg b/umbrello/umbrello/pics/sources/actor.svg
new file mode 100644
index 00000000..ae4a2d81
--- /dev/null
+++ b/umbrello/umbrello/pics/sources/actor.svg
@@ -0,0 +1,172 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 20010904//EN"
+"http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd">
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+<svg
+ id="svg1"
+ sodipodi:version="0.32"
+ inkscape:version="0.38.1"
+ width="128.00000pt"
+ height="128.00000pt"
+ sodipodi:docbase="/home/bartkozoltan/Documents/work/umbrello/new pics"
+ sodipodi:docname="actor.svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:xlink="http://www.w3.org/1999/xlink">
+ <defs
+ id="defs3">
+ <linearGradient
+ id="linearGradient973">
+ <stop
+ style="stop-color:#0000ff;stop-opacity:0.0000000;"
+ offset="0.0000000"
+ id="stop974" />
+ <stop
+ style="stop-color:#fff;stop-opacity:1;"
+ offset="1"
+ id="stop975" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient868">
+ <stop
+ style="stop-color:#ffffff;stop-opacity:0.0000000;"
+ offset="0.0000000"
+ id="stop869" />
+ <stop
+ style="stop-color:#fff;stop-opacity:1;"
+ offset="1"
+ id="stop870" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient893">
+ <stop
+ style="stop-color:#19839a;stop-opacity:0.0000000;"
+ offset="0.0000000"
+ id="stop894" />
+ <stop
+ style="stop-color:#fff;stop-opacity:1;"
+ offset="1"
+ id="stop895" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient830">
+ <stop
+ style="stop-color:#ebffff;stop-opacity:0.0000000;"
+ offset="0.0000000"
+ id="stop831" />
+ <stop
+ style="stop-color:#fff;stop-opacity:1;"
+ offset="1"
+ id="stop832" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient826">
+ <stop
+ style="stop-color:#000;stop-opacity:1;"
+ offset="0"
+ id="stop827" />
+ <stop
+ style="stop-color:#fff;stop-opacity:1;"
+ offset="1"
+ id="stop828" />
+ </linearGradient>
+ <linearGradient
+ xlink:href="#linearGradient830"
+ id="linearGradient829"
+ x1="1.5500000"
+ y1="0.52343750"
+ x2="0.20422535"
+ y2="-0.12195122"
+ spreadMethod="reflect" />
+ <linearGradient
+ xlink:href="#linearGradient830"
+ id="linearGradient834"
+ x1="-0.31159419"
+ y1="0.19531250"
+ x2="0.77536231"
+ y2="0.94531250" />
+ <linearGradient
+ xlink:href="#linearGradient830"
+ id="linearGradient836" />
+ <linearGradient
+ xlink:href="#linearGradient868"
+ id="linearGradient892" />
+ <linearGradient
+ xlink:href="#linearGradient973"
+ id="linearGradient926"
+ x1="1.5043305e-18"
+ y1="0.50000000"
+ x2="1.0000000"
+ y2="0.50000000" />
+ <linearGradient
+ xlink:href="#linearGradient868"
+ id="linearGradient928" />
+ <linearGradient
+ xlink:href="#linearGradient830"
+ id="linearGradient937"
+ x1="0.010563380"
+ y1="0.48571429"
+ x2="0.98943663"
+ y2="0.48571429"
+ spreadMethod="pad" />
+ <radialGradient
+ xlink:href="#linearGradient973"
+ id="radialGradient976"
+ cx="0.49275362"
+ cy="0.46875000"
+ r="0.80203730"
+ fx="0.49275362"
+ fy="0.46875000"
+ spreadMethod="reflect" />
+ </defs>
+ <sodipodi:namedview
+ id="base"
+ pagecolor="#ffffff"
+ bordercolor="#666666"
+ borderopacity="1.0"
+ inkscape:pageopacity="0.0"
+ inkscape:pageshadow="2"
+ inkscape:zoom="1.0000000"
+ inkscape:cx="-134.65454"
+ inkscape:cy="66.817627"
+ inkscape:window-width="1022"
+ inkscape:window-height="701"
+ gridspacingy="1.0000000pt"
+ gridspacingx="1.0000000pt"
+ gridtolerance="1.0000000px"
+ inkscape:window-x="0"
+ inkscape:window-y="0" />
+ <g
+ id="g1190">
+ <path
+ style="fill:#ff0000;fill-opacity:1.0000000;fill-rule:evenodd;stroke:#ff0000;stroke-width:5.0000000;stroke-dasharray:none;stroke-opacity:1.0000000;"
+ d="M 25.093750,44.875000 L 29.375000,70.812500 L 75.375000,92.968750 L 74.906250,105.96875 L 9.4375000,130.71875 L 39.312500,151.71875 L 77.468750,118.50000 L 83.156250,118.43750 L 127.21875,152.31250 L 153.81250,127.56250 L 86.187500,106.68750 L 86.625000,93.218750 L 129.62500,88.812500 L 136.31250,62.625000 L 86.500000,81.250000 L 86.187500,55.250000 L 74.937500,55.375000 L 75.218750,78.562500 L 25.093750,44.875000 z "
+ id="path972"
+ sodipodi:nodetypes="ccccccccccccccccccc" />
+ <g
+ id="g909"
+ transform="matrix(0.813839,0.000000,0.000000,1.000000,22.06356,-5.625000)">
+ <path
+ sodipodi:type="arc"
+ style="fill:#ffff00;fill-rule:evenodd;stroke:#ff0000;stroke-width:10.800957;stroke-dasharray:none;"
+ id="path863"
+ sodipodi:cx="63.437500"
+ sodipodi:cy="39.375000"
+ sodipodi:rx="31.250000"
+ sodipodi:ry="31.562500"
+ d="M 94.687500 39.375000 A 31.250000 31.562500 0 1 0 32.187500,39.375000 A 31.250000 31.562500 0 1 0 94.687500 39.375000 z"
+ transform="matrix(0.841497,0.000000,0.000000,0.838191,19.68138,6.062272)" />
+ <path
+ sodipodi:type="arc"
+ style="fill:url(#linearGradient892);fill-opacity:0.75000000;fill-rule:evenodd;stroke-width:10.000000;"
+ id="path864"
+ sodipodi:cx="63.437500"
+ sodipodi:cy="39.375000"
+ sodipodi:rx="31.250000"
+ sodipodi:ry="31.562500"
+ d="M 94.687500 39.375000 A 31.250000 31.562500 0 1 0 32.187500,39.375000 A 31.250000 31.562500 0 1 0 94.687500 39.375000 z"
+ transform="matrix(0.741224,0.000000,0.000000,0.702062,25.43390,11.29160)" />
+ </g>
+ </g>
+</svg>
diff --git a/umbrello/umbrello/pics/sources/aggregation.svg b/umbrello/umbrello/pics/sources/aggregation.svg
new file mode 100644
index 00000000..7d9fe672
--- /dev/null
+++ b/umbrello/umbrello/pics/sources/aggregation.svg
@@ -0,0 +1,130 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 20010904//EN"
+"http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd">
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+<svg
+ id="svg1"
+ sodipodi:version="0.32"
+ inkscape:version="0.37"
+ width="22pt"
+ height="22pt"
+ sodipodi:docbase="/home/jr/tmp/umbrello/icons/inkscape-svg"
+ sodipodi:docname="aggregation.svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:xlink="http://www.w3.org/1999/xlink">
+ <defs
+ id="defs3">
+ <linearGradient
+ id="linearGradient868">
+ <stop
+ style="stop-color:#ffffff;stop-opacity:0.0000000;"
+ offset="0.0000000"
+ id="stop869" />
+ <stop
+ style="stop-color:#fff;stop-opacity:1;"
+ offset="1"
+ id="stop870" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient893">
+ <stop
+ style="stop-color:#19839a;stop-opacity:0.0000000;"
+ offset="0.0000000"
+ id="stop894" />
+ <stop
+ style="stop-color:#fff;stop-opacity:1;"
+ offset="1"
+ id="stop895" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient830">
+ <stop
+ style="stop-color:#ebffff;stop-opacity:0.0000000;"
+ offset="0.0000000"
+ id="stop831" />
+ <stop
+ style="stop-color:#fff;stop-opacity:1;"
+ offset="1"
+ id="stop832" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient826">
+ <stop
+ style="stop-color:#000;stop-opacity:1;"
+ offset="0"
+ id="stop827" />
+ <stop
+ style="stop-color:#fff;stop-opacity:1;"
+ offset="1"
+ id="stop828" />
+ </linearGradient>
+ <linearGradient
+ xlink:href="#linearGradient830"
+ id="linearGradient829"
+ x1="1.5500000"
+ y1="0.52343750"
+ x2="0.20422535"
+ y2="-0.12195122"
+ spreadMethod="reflect" />
+ <linearGradient
+ xlink:href="#linearGradient830"
+ id="linearGradient834"
+ x1="-0.31159419"
+ y1="0.19531250"
+ x2="0.77536231"
+ y2="0.94531250" />
+ <linearGradient
+ xlink:href="#linearGradient830"
+ id="linearGradient836" />
+ <linearGradient
+ xlink:href="#linearGradient868"
+ id="linearGradient892"
+ x1="-0.86529595"
+ y1="1.3691810"
+ x2="0.76164871"
+ y2="0.21797939" />
+ </defs>
+ <sodipodi:namedview
+ id="base"
+ pagecolor="#ffffff"
+ bordercolor="#666666"
+ borderopacity="1.0"
+ inkscape:pageopacity="0.0"
+ inkscape:pageshadow="2"
+ inkscape:zoom="22.6274170"
+ inkscape:cx="12.5539655"
+ inkscape:cy="11.2242088"
+ inkscape:window-width="1016"
+ inkscape:window-height="693"
+ gridspacingy="1.0000000pt"
+ gridspacingx="1.0000000pt"
+ gridtolerance="1.0000000px"
+ inkscape:window-x="0"
+ inkscape:window-y="0"
+ showgrid="true"
+ vertgrid="false"
+ horizgrid="false" />
+ <path
+ style="font-size:12;fill:none;fill-opacity:0.75;fill-rule:evenodd;stroke:#ff0000;stroke-width:2.41066;stroke-dashoffset:0;"
+ d="M 13.785788 0.093954178 L 13.684594 24.651886 "
+ id="path861"
+ sodipodi:nodetypes="cc" />
+ <rect
+ style="font-size:12;fill:#ffff00;fill-rule:evenodd;stroke:#ff0000;stroke-width:2.17721;"
+ id="rect854"
+ width="8.17145930"
+ height="8.02591249"
+ x="-5.79334815"
+ y="-27.37266770"
+ transform="matrix(0.625322,-0.780367,-0.632360,-0.774675,0.000000,0.000000)" />
+ <rect
+ style="font-size:12;fill:url(#linearGradient892);fill-rule:evenodd;stroke-width:11.0521;"
+ id="rect855"
+ width="32.068266"
+ height="31.499338"
+ x="-12.765084"
+ y="-157.22844"
+ transform="matrix(0.114057,-0.143654,-0.113959,-0.143717,-2.848009,-0.461202)" />
+</svg>
diff --git a/umbrello/umbrello/pics/sources/align_bottom.svg b/umbrello/umbrello/pics/sources/align_bottom.svg
new file mode 100644
index 00000000..0f292766
--- /dev/null
+++ b/umbrello/umbrello/pics/sources/align_bottom.svg
@@ -0,0 +1,261 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 20010904//EN"
+"http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd">
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+<svg
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://web.resource.org/cc/"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:xlink="http://www.w3.org/1999/xlink"
+ xmlns:sodipodi="http://inkscape.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ id="svg1"
+ sodipodi:version="0.32"
+ inkscape:version="0.42"
+ width="22pt"
+ height="22pt"
+ sodipodi:docbase="/home/dani/Proyectos/umbrello-svn/kdesdk/umbrello/umbrello/pics/sources"
+ sodipodi:docname="align_bottom.svg">
+ <metadata
+ id="metadata1589">
+ <rdf:RDF>
+ <cc:Work
+ rdf:about="">
+ <dc:format>image/svg+xml</dc:format>
+ <dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+ </cc:Work>
+ </rdf:RDF>
+ </metadata>
+ <defs
+ id="defs3">
+ <linearGradient
+ id="linearGradient993">
+ <stop
+ offset="0.0000000"
+ style="stop-color:#ffffff;stop-opacity:0.0000000;"
+ id="stop995" />
+ <stop
+ offset="1.0000000"
+ style="stop-color:#ffffff;stop-opacity:1.0000000;"
+ id="stop994" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient868">
+ <stop
+ style="stop-color:#ffffff;stop-opacity:0.0000000;"
+ offset="0.0000000"
+ id="stop869" />
+ <stop
+ style="stop-color:#fff;stop-opacity:1;"
+ offset="1"
+ id="stop870" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient893">
+ <stop
+ style="stop-color:#19839a;stop-opacity:0.0000000;"
+ offset="0.0000000"
+ id="stop894" />
+ <stop
+ style="stop-color:#fff;stop-opacity:1;"
+ offset="1"
+ id="stop895" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient830">
+ <stop
+ style="stop-color:#ebffff;stop-opacity:0.0000000;"
+ offset="0.0000000"
+ id="stop831" />
+ <stop
+ style="stop-color:#fff;stop-opacity:1;"
+ offset="1"
+ id="stop832" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient826">
+ <stop
+ style="stop-color:#000;stop-opacity:1;"
+ offset="0"
+ id="stop827" />
+ <stop
+ style="stop-color:#fff;stop-opacity:1;"
+ offset="1"
+ id="stop828" />
+ </linearGradient>
+ <linearGradient
+ xlink:href="#linearGradient830"
+ id="linearGradient829"
+ x1="1.5500000"
+ y1="0.52343750"
+ x2="0.20422535"
+ y2="-0.12195122"
+ spreadMethod="reflect" />
+ <linearGradient
+ xlink:href="#linearGradient830"
+ id="linearGradient834"
+ x1="-0.31159419"
+ y1="0.19531250"
+ x2="0.77536231"
+ y2="0.94531250" />
+ <linearGradient
+ xlink:href="#linearGradient830"
+ id="linearGradient836" />
+ <linearGradient
+ xlink:href="#linearGradient868"
+ id="linearGradient892"
+ x1="1.8449316"
+ y1="0.98914021"
+ x2="0.14743590"
+ y2="0.67741936"
+ spreadMethod="reflect" />
+ <defs
+ id="defs940">
+ <linearGradient
+ id="linearGradient941"
+ x1="0.0000000"
+ y1="0.50000000"
+ x2="1.0000000"
+ y2="0.50000000"
+ gradientUnits="objectBoundingBox"
+ spreadMethod="pad"
+ xlink:href="#linearGradient993" />
+ <linearGradient
+ id="linearGradient944">
+ <stop
+ style="stop-color:#19839a;stop-opacity:0.0000000;"
+ offset="0.0000000"
+ id="stop945" />
+ <stop
+ style="stop-color:#fff;stop-opacity:1;"
+ offset="1"
+ id="stop946" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient947">
+ <stop
+ style="stop-color:#ebffff;stop-opacity:0.0000000;"
+ offset="0.0000000"
+ id="stop948" />
+ <stop
+ style="stop-color:#fff;stop-opacity:1;"
+ offset="1"
+ id="stop949" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient950">
+ <stop
+ style="stop-color:#000;stop-opacity:1;"
+ offset="0"
+ id="stop951" />
+ <stop
+ style="stop-color:#fff;stop-opacity:1;"
+ offset="1"
+ id="stop952" />
+ </linearGradient>
+ <linearGradient
+ xlink:href="#linearGradient830"
+ id="linearGradient953"
+ x1="1.5500000"
+ y1="0.52343750"
+ x2="0.20422535"
+ y2="-0.12195122"
+ spreadMethod="reflect" />
+ <linearGradient
+ xlink:href="#linearGradient830"
+ id="linearGradient954"
+ x1="-0.31159419"
+ y1="0.19531250"
+ x2="0.77536231"
+ y2="0.94531250" />
+ <linearGradient
+ xlink:href="#linearGradient830"
+ id="linearGradient955" />
+ <linearGradient
+ xlink:href="#linearGradient868"
+ id="linearGradient956"
+ x1="-0.49264705"
+ y1="0.43750000"
+ x2="0.022058824"
+ y2="0.92187500" />
+ </defs>
+ <sodipodi:namedview
+ id="namedview957"
+ pagecolor="#ffffff"
+ bordercolor="#666666"
+ borderopacity="1.0"
+ inkscape:pageopacity="0.0"
+ inkscape:pageshadow="2"
+ inkscape:zoom="4.0000000"
+ inkscape:cx="79.132843"
+ inkscape:cy="33.777672"
+ inkscape:window-width="1022"
+ inkscape:window-height="701"
+ gridspacingy="1.0000000pt"
+ gridspacingx="1.0000000pt"
+ gridtolerance="1.0000000px"
+ inkscape:window-x="0"
+ inkscape:window-y="0" />
+ </defs>
+ <sodipodi:namedview
+ id="base"
+ pagecolor="#ffffff"
+ bordercolor="#666666"
+ borderopacity="1.0"
+ inkscape:pageopacity="0.0"
+ inkscape:pageshadow="2"
+ inkscape:zoom="22.627417"
+ inkscape:cx="13.750000"
+ inkscape:cy="11.418942"
+ inkscape:window-width="1016"
+ inkscape:window-height="713"
+ gridspacingy="1.0000000pt"
+ gridspacingx="1.0000000pt"
+ gridtolerance="1.0000000px"
+ inkscape:window-x="0"
+ inkscape:window-y="0"
+ showgrid="true"
+ showguides="false"
+ snaptoguides="true"
+ inkscape:guide-bbox="false"
+ inkscape:grid-bbox="false"
+ inkscape:current-layer="svg1">
+ <sodipodi:guide
+ orientation="horizontal"
+ position="11.048543"
+ id="guide875" />
+ <sodipodi:guide
+ orientation="vertical"
+ position="11.004349"
+ id="guide876" />
+ </sodipodi:namedview>
+ <g
+ id="g4550">
+ <rect
+ height="1.0000000"
+ style="fill:#ff0000;fill-opacity:1.0000000;fill-rule:evenodd;stroke:none;stroke-width:1.0000000;stroke-miterlimit:4.0000000;stroke-dasharray:none"
+ id="rect863"
+ width="12.500000"
+ x="7.5000000"
+ y="26.250000" />
+ <g
+ transform="matrix(-1.000000,0.000000,0.000000,-1.000000,27.50000,40.00000)"
+ id="g5975">
+ <path
+ style="font-size:12.000000px;fill:#ff0000;fill-opacity:1.0000000;fill-rule:evenodd;stroke:none;stroke-width:1.0000000;stroke-linecap:butt;stroke-miterlimit:4.0000000;stroke-opacity:1.0000000"
+ d="M 13.750000,13.750000 L 8.4000000,19.100000 L 9.1000000,19.800000 L 13.750000,15.200000 L 18.400000,19.800000 L 19.100000,19.100000 L 13.750000,13.750000 z "
+ id="path1593"
+ sodipodi:nodetypes="ccccccc" />
+ <rect
+ y="15.000000"
+ x="12.500000"
+ height="11.250000"
+ width="2.5000000"
+ id="rect1595"
+ style="font-size:12.000000px;fill:#ff0000;fill-opacity:1.0000000;fill-rule:evenodd;stroke:none;stroke-width:1.0000000pt" />
+ </g>
+ </g>
+</svg>
diff --git a/umbrello/umbrello/pics/sources/align_hori_distribute.svg b/umbrello/umbrello/pics/sources/align_hori_distribute.svg
new file mode 100644
index 00000000..f6174a83
--- /dev/null
+++ b/umbrello/umbrello/pics/sources/align_hori_distribute.svg
@@ -0,0 +1,273 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 20010904//EN"
+"http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd">
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+<svg
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://web.resource.org/cc/"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:xlink="http://www.w3.org/1999/xlink"
+ xmlns:sodipodi="http://inkscape.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ id="svg1"
+ sodipodi:version="0.32"
+ inkscape:version="0.42"
+ width="22pt"
+ height="22pt"
+ sodipodi:docbase="/home/dani/Proyectos/umbrello-svn/kdesdk/umbrello/umbrello/pics/sources"
+ sodipodi:docname="align_hori_distribute.svg"
+ inkscape:export-filename="/home/dani/Proyectos/umbrello-svn/kdesdk/umbrello/umbrello/pics/align_hori_distribute.png"
+ inkscape:export-xdpi="72.000000"
+ inkscape:export-ydpi="72.000000">
+ <metadata
+ id="metadata1589">
+ <rdf:RDF>
+ <cc:Work
+ rdf:about="">
+ <dc:format>image/svg+xml</dc:format>
+ <dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+ </cc:Work>
+ </rdf:RDF>
+ </metadata>
+ <defs
+ id="defs3">
+ <linearGradient
+ id="linearGradient993">
+ <stop
+ offset="0.0000000"
+ style="stop-color:#ffffff;stop-opacity:0.0000000;"
+ id="stop995" />
+ <stop
+ offset="1.0000000"
+ style="stop-color:#ffffff;stop-opacity:1.0000000;"
+ id="stop994" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient868">
+ <stop
+ style="stop-color:#ffffff;stop-opacity:0.0000000;"
+ offset="0.0000000"
+ id="stop869" />
+ <stop
+ style="stop-color:#fff;stop-opacity:1;"
+ offset="1"
+ id="stop870" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient893">
+ <stop
+ style="stop-color:#19839a;stop-opacity:0.0000000;"
+ offset="0.0000000"
+ id="stop894" />
+ <stop
+ style="stop-color:#fff;stop-opacity:1;"
+ offset="1"
+ id="stop895" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient830">
+ <stop
+ style="stop-color:#ebffff;stop-opacity:0.0000000;"
+ offset="0.0000000"
+ id="stop831" />
+ <stop
+ style="stop-color:#fff;stop-opacity:1;"
+ offset="1"
+ id="stop832" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient826">
+ <stop
+ style="stop-color:#000;stop-opacity:1;"
+ offset="0"
+ id="stop827" />
+ <stop
+ style="stop-color:#fff;stop-opacity:1;"
+ offset="1"
+ id="stop828" />
+ </linearGradient>
+ <linearGradient
+ xlink:href="#linearGradient830"
+ id="linearGradient829"
+ x1="1.5500000"
+ y1="0.52343750"
+ x2="0.20422535"
+ y2="-0.12195122"
+ spreadMethod="reflect" />
+ <linearGradient
+ xlink:href="#linearGradient830"
+ id="linearGradient834"
+ x1="-0.31159419"
+ y1="0.19531250"
+ x2="0.77536231"
+ y2="0.94531250" />
+ <linearGradient
+ xlink:href="#linearGradient830"
+ id="linearGradient836" />
+ <linearGradient
+ xlink:href="#linearGradient868"
+ id="linearGradient892"
+ x1="1.8449316"
+ y1="0.98914021"
+ x2="0.14743590"
+ y2="0.67741936"
+ spreadMethod="reflect" />
+ <defs
+ id="defs940">
+ <linearGradient
+ id="linearGradient941"
+ x1="0.0000000"
+ y1="0.50000000"
+ x2="1.0000000"
+ y2="0.50000000"
+ gradientUnits="objectBoundingBox"
+ spreadMethod="pad"
+ xlink:href="#linearGradient993" />
+ <linearGradient
+ id="linearGradient944">
+ <stop
+ style="stop-color:#19839a;stop-opacity:0.0000000;"
+ offset="0.0000000"
+ id="stop945" />
+ <stop
+ style="stop-color:#fff;stop-opacity:1;"
+ offset="1"
+ id="stop946" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient947">
+ <stop
+ style="stop-color:#ebffff;stop-opacity:0.0000000;"
+ offset="0.0000000"
+ id="stop948" />
+ <stop
+ style="stop-color:#fff;stop-opacity:1;"
+ offset="1"
+ id="stop949" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient950">
+ <stop
+ style="stop-color:#000;stop-opacity:1;"
+ offset="0"
+ id="stop951" />
+ <stop
+ style="stop-color:#fff;stop-opacity:1;"
+ offset="1"
+ id="stop952" />
+ </linearGradient>
+ <linearGradient
+ xlink:href="#linearGradient830"
+ id="linearGradient953"
+ x1="1.5500000"
+ y1="0.52343750"
+ x2="0.20422535"
+ y2="-0.12195122"
+ spreadMethod="reflect" />
+ <linearGradient
+ xlink:href="#linearGradient830"
+ id="linearGradient954"
+ x1="-0.31159419"
+ y1="0.19531250"
+ x2="0.77536231"
+ y2="0.94531250" />
+ <linearGradient
+ xlink:href="#linearGradient830"
+ id="linearGradient955" />
+ <linearGradient
+ xlink:href="#linearGradient868"
+ id="linearGradient956"
+ x1="-0.49264705"
+ y1="0.43750000"
+ x2="0.022058824"
+ y2="0.92187500" />
+ </defs>
+ <sodipodi:namedview
+ id="namedview957"
+ pagecolor="#ffffff"
+ bordercolor="#666666"
+ borderopacity="1.0"
+ inkscape:pageopacity="0.0"
+ inkscape:pageshadow="2"
+ inkscape:zoom="4.0000000"
+ inkscape:cx="79.132843"
+ inkscape:cy="33.777672"
+ inkscape:window-width="1022"
+ inkscape:window-height="701"
+ gridspacingy="1.0000000pt"
+ gridspacingx="1.0000000pt"
+ gridtolerance="1.0000000px"
+ inkscape:window-x="0"
+ inkscape:window-y="0" />
+ </defs>
+ <sodipodi:namedview
+ id="base"
+ pagecolor="#ffffff"
+ bordercolor="#666666"
+ borderopacity="1.0"
+ inkscape:pageopacity="0.0"
+ inkscape:pageshadow="2"
+ inkscape:zoom="16.000000"
+ inkscape:cx="13.750000"
+ inkscape:cy="13.186709"
+ inkscape:window-width="1016"
+ inkscape:window-height="713"
+ gridspacingy="1.0000000pt"
+ gridspacingx="1.0000000pt"
+ gridtolerance="1.0000000px"
+ inkscape:window-x="0"
+ inkscape:window-y="0"
+ showgrid="true"
+ showguides="false"
+ snaptoguides="true"
+ inkscape:guide-bbox="false"
+ inkscape:grid-bbox="false"
+ inkscape:current-layer="svg1">
+ <sodipodi:guide
+ orientation="horizontal"
+ position="11.048543"
+ id="guide875" />
+ <sodipodi:guide
+ orientation="vertical"
+ position="11.004349"
+ id="guide876" />
+ </sodipodi:namedview>
+ <g
+ id="g4550"
+ transform="matrix(0.000000,-1.000000,1.000000,0.000000,0.000000,27.50000)">
+ <rect
+ height="1.0000000"
+ style="fill:#ff0000;fill-opacity:1.0000000;fill-rule:evenodd;stroke:none;stroke-width:1.0000000;stroke-miterlimit:4.0000000;stroke-dasharray:none"
+ id="rect863"
+ width="12.500000"
+ x="7.5000000"
+ y="26.250000" />
+ <g
+ transform="matrix(-1.000000,0.000000,0.000000,-1.000000,27.50000,40.00000)"
+ id="g5975">
+ <path
+ style="font-size:12.000000px;fill:#ff0000;fill-opacity:1.0000000;fill-rule:evenodd;stroke:none;stroke-width:1.0000000;stroke-linecap:butt;stroke-miterlimit:4.0000000;stroke-opacity:1.0000000"
+ d="M 13.750000,13.750000 L 8.4000000,19.100000 L 9.1000000,19.800000 L 13.750000,15.200000 L 18.400000,19.800000 L 19.100000,19.100000 L 13.750000,13.750000 z "
+ id="path1593"
+ sodipodi:nodetypes="ccccccc" />
+ <rect
+ y="15.000000"
+ x="12.500000"
+ height="11.250000"
+ width="2.5000000"
+ id="rect1595"
+ style="font-size:12.000000px;fill:#ff0000;fill-opacity:1.0000000;fill-rule:evenodd;stroke:none;stroke-width:1.0000000pt" />
+ </g>
+ </g>
+ <use
+ x="0.0000000"
+ y="0.0000000"
+ xlink:href="#g4550"
+ id="use1412"
+ transform="matrix(-1.000000,0.000000,0.000000,-1.000000,27.50000,27.50000)"
+ width="27.500000"
+ height="27.500000" />
+</svg>
diff --git a/umbrello/umbrello/pics/sources/align_hori_middle.svg b/umbrello/umbrello/pics/sources/align_hori_middle.svg
new file mode 100644
index 00000000..4c7b1234
--- /dev/null
+++ b/umbrello/umbrello/pics/sources/align_hori_middle.svg
@@ -0,0 +1,257 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 20010904//EN"
+"http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd">
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+<svg
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://web.resource.org/cc/"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:xlink="http://www.w3.org/1999/xlink"
+ xmlns:sodipodi="http://inkscape.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ id="svg1"
+ sodipodi:version="0.32"
+ inkscape:version="0.42"
+ width="27.500000px"
+ height="27.500000px"
+ sodipodi:docbase="/home/dani/Proyectos/umbrello-svn/kdesdk/umbrello/umbrello/pics/sources"
+ sodipodi:docname="align_vert_distribute.svg">
+ <metadata
+ id="metadata47">
+ <rdf:RDF>
+ <cc:Work
+ rdf:about="">
+ <dc:format>image/svg+xml</dc:format>
+ <dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+ </cc:Work>
+ </rdf:RDF>
+ </metadata>
+ <defs
+ id="defs3">
+ <linearGradient
+ id="linearGradient993">
+ <stop
+ offset="0.0000000"
+ style="stop-color:#ffffff;stop-opacity:0.0000000;"
+ id="stop995" />
+ <stop
+ offset="1.0000000"
+ style="stop-color:#ffffff;stop-opacity:1.0000000;"
+ id="stop994" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient868">
+ <stop
+ style="stop-color:#ffffff;stop-opacity:0.0000000;"
+ offset="0.0000000"
+ id="stop869" />
+ <stop
+ style="stop-color:#fff;stop-opacity:1;"
+ offset="1"
+ id="stop870" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient893">
+ <stop
+ style="stop-color:#19839a;stop-opacity:0.0000000;"
+ offset="0.0000000"
+ id="stop894" />
+ <stop
+ style="stop-color:#fff;stop-opacity:1;"
+ offset="1"
+ id="stop895" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient830">
+ <stop
+ style="stop-color:#ebffff;stop-opacity:0.0000000;"
+ offset="0.0000000"
+ id="stop831" />
+ <stop
+ style="stop-color:#fff;stop-opacity:1;"
+ offset="1"
+ id="stop832" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient826">
+ <stop
+ style="stop-color:#000;stop-opacity:1;"
+ offset="0"
+ id="stop827" />
+ <stop
+ style="stop-color:#fff;stop-opacity:1;"
+ offset="1"
+ id="stop828" />
+ </linearGradient>
+ <linearGradient
+ xlink:href="#linearGradient830"
+ id="linearGradient829"
+ x1="1.5500000"
+ y1="0.52343750"
+ x2="0.20422535"
+ y2="-0.12195122"
+ spreadMethod="reflect" />
+ <linearGradient
+ xlink:href="#linearGradient830"
+ id="linearGradient834"
+ x1="-0.31159419"
+ y1="0.19531250"
+ x2="0.77536231"
+ y2="0.94531250" />
+ <linearGradient
+ xlink:href="#linearGradient830"
+ id="linearGradient836" />
+ <linearGradient
+ xlink:href="#linearGradient868"
+ id="linearGradient892"
+ x1="1.8449316"
+ y1="0.98914021"
+ x2="0.14743590"
+ y2="0.67741936"
+ spreadMethod="reflect" />
+ <defs
+ id="defs940">
+ <linearGradient
+ id="linearGradient941"
+ x1="0.0000000"
+ y1="0.50000000"
+ x2="1.0000000"
+ y2="0.50000000"
+ gradientUnits="objectBoundingBox"
+ spreadMethod="pad"
+ xlink:href="#linearGradient993" />
+ <linearGradient
+ id="linearGradient944">
+ <stop
+ style="stop-color:#19839a;stop-opacity:0.0000000;"
+ offset="0.0000000"
+ id="stop945" />
+ <stop
+ style="stop-color:#fff;stop-opacity:1;"
+ offset="1"
+ id="stop946" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient947">
+ <stop
+ style="stop-color:#ebffff;stop-opacity:0.0000000;"
+ offset="0.0000000"
+ id="stop948" />
+ <stop
+ style="stop-color:#fff;stop-opacity:1;"
+ offset="1"
+ id="stop949" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient950">
+ <stop
+ style="stop-color:#000;stop-opacity:1;"
+ offset="0"
+ id="stop951" />
+ <stop
+ style="stop-color:#fff;stop-opacity:1;"
+ offset="1"
+ id="stop952" />
+ </linearGradient>
+ <linearGradient
+ xlink:href="#linearGradient830"
+ id="linearGradient953"
+ x1="1.5500000"
+ y1="0.52343750"
+ x2="0.20422535"
+ y2="-0.12195122"
+ spreadMethod="reflect" />
+ <linearGradient
+ xlink:href="#linearGradient830"
+ id="linearGradient954"
+ x1="-0.31159419"
+ y1="0.19531250"
+ x2="0.77536231"
+ y2="0.94531250" />
+ <linearGradient
+ xlink:href="#linearGradient830"
+ id="linearGradient955" />
+ <linearGradient
+ xlink:href="#linearGradient868"
+ id="linearGradient956"
+ x1="-0.49264705"
+ y1="0.43750000"
+ x2="0.022058824"
+ y2="0.92187500" />
+ </defs>
+ <sodipodi:namedview
+ id="namedview957"
+ pagecolor="#ffffff"
+ bordercolor="#666666"
+ borderopacity="1.0"
+ inkscape:pageopacity="0.0"
+ inkscape:pageshadow="2"
+ inkscape:zoom="4.0000000"
+ inkscape:cx="79.132843"
+ inkscape:cy="33.777672"
+ inkscape:window-width="1022"
+ inkscape:window-height="701"
+ gridspacingy="1.0000000pt"
+ gridspacingx="1.0000000pt"
+ gridtolerance="1.0000000px"
+ inkscape:window-x="0"
+ inkscape:window-y="0" />
+ </defs>
+ <sodipodi:namedview
+ id="base"
+ pagecolor="#ffffff"
+ bordercolor="#666666"
+ borderopacity="1.0"
+ inkscape:pageopacity="0.0"
+ inkscape:pageshadow="2"
+ inkscape:zoom="22.627417"
+ inkscape:cx="12.844517"
+ inkscape:cy="16.176523"
+ inkscape:window-width="1016"
+ inkscape:window-height="713"
+ gridspacingy="1.2500000px"
+ gridspacingx="1.2500000px"
+ gridtolerance="1.0000000px"
+ inkscape:window-x="0"
+ inkscape:window-y="0"
+ showgrid="true"
+ showguides="false"
+ snaptoguides="true"
+ inkscape:grid-bbox="false"
+ inkscape:guide-bbox="false"
+ gridoriginy="0.0000000px"
+ gridoriginx="0.0000000px"
+ inkscape:guide-points="false"
+ inkscape:current-layer="svg1">
+ <sodipodi:guide
+ orientation="horizontal"
+ position="11.048543"
+ id="guide875" />
+ </sodipodi:namedview>
+ <g
+ id="g5975">
+ <path
+ sodipodi:nodetypes="ccccccc"
+ id="path1009"
+ d="M 13.750000,13.750000 L 8.4000000,19.100000 L 9.1000000,19.800000 L 13.750000,15.200000 L 18.400000,19.800000 L 19.100000,19.100000 L 13.750000,13.750000 z "
+ style="font-size:12.000000px;fill:#ff0000;fill-opacity:1.0000000;fill-rule:evenodd;stroke:none;stroke-width:1.0000000;stroke-linecap:butt;stroke-miterlimit:4.0000000;stroke-opacity:1.0000000" />
+ <rect
+ style="font-size:12.000000px;fill:#ff0000;fill-opacity:1.0000000;fill-rule:evenodd;stroke:none;stroke-width:1.0000000pt"
+ id="rect1209"
+ width="2.5000000"
+ height="11.250000"
+ x="12.500000"
+ y="15.000000" />
+ </g>
+ <use
+ x="0.0000000"
+ y="0.0000000"
+ xlink:href="#g5975"
+ id="use5979"
+ transform="matrix(-1.000000,0.000000,0.000000,-1.000000,27.50000,27.50000)"
+ width="27.500000"
+ height="27.500000" />
+</svg>
diff --git a/umbrello/umbrello/pics/sources/align_left.svg b/umbrello/umbrello/pics/sources/align_left.svg
new file mode 100644
index 00000000..362e4e34
--- /dev/null
+++ b/umbrello/umbrello/pics/sources/align_left.svg
@@ -0,0 +1,260 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 20010904//EN"
+"http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd">
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+<svg
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://web.resource.org/cc/"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:xlink="http://www.w3.org/1999/xlink"
+ xmlns:sodipodi="http://inkscape.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ id="svg1"
+ sodipodi:version="0.32"
+ inkscape:version="0.42"
+ width="22pt"
+ height="22pt"
+ sodipodi:docbase="/home/dani/Proyectos/umbrello-svn/kdesdk/umbrello/umbrello/pics/sources"
+ sodipodi:docname="align_left.svg">
+ <metadata
+ id="metadata5028">
+ <rdf:RDF>
+ <cc:Work
+ rdf:about="">
+ <dc:format>image/svg+xml</dc:format>
+ <dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+ </cc:Work>
+ </rdf:RDF>
+ </metadata>
+ <defs
+ id="defs3">
+ <linearGradient
+ id="linearGradient993">
+ <stop
+ offset="0.0000000"
+ style="stop-color:#ffffff;stop-opacity:0.0000000;"
+ id="stop995" />
+ <stop
+ offset="1.0000000"
+ style="stop-color:#ffffff;stop-opacity:1.0000000;"
+ id="stop994" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient868">
+ <stop
+ style="stop-color:#ffffff;stop-opacity:0.0000000;"
+ offset="0.0000000"
+ id="stop869" />
+ <stop
+ style="stop-color:#fff;stop-opacity:1;"
+ offset="1"
+ id="stop870" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient893">
+ <stop
+ style="stop-color:#19839a;stop-opacity:0.0000000;"
+ offset="0.0000000"
+ id="stop894" />
+ <stop
+ style="stop-color:#fff;stop-opacity:1;"
+ offset="1"
+ id="stop895" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient830">
+ <stop
+ style="stop-color:#ebffff;stop-opacity:0.0000000;"
+ offset="0.0000000"
+ id="stop831" />
+ <stop
+ style="stop-color:#fff;stop-opacity:1;"
+ offset="1"
+ id="stop832" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient826">
+ <stop
+ style="stop-color:#000;stop-opacity:1;"
+ offset="0"
+ id="stop827" />
+ <stop
+ style="stop-color:#fff;stop-opacity:1;"
+ offset="1"
+ id="stop828" />
+ </linearGradient>
+ <linearGradient
+ xlink:href="#linearGradient830"
+ id="linearGradient829"
+ x1="1.5500000"
+ y1="0.52343750"
+ x2="0.20422535"
+ y2="-0.12195122"
+ spreadMethod="reflect" />
+ <linearGradient
+ xlink:href="#linearGradient830"
+ id="linearGradient834"
+ x1="-0.31159419"
+ y1="0.19531250"
+ x2="0.77536231"
+ y2="0.94531250" />
+ <linearGradient
+ xlink:href="#linearGradient830"
+ id="linearGradient836" />
+ <linearGradient
+ xlink:href="#linearGradient868"
+ id="linearGradient892"
+ x1="1.8449316"
+ y1="0.98914021"
+ x2="0.14743590"
+ y2="0.67741936"
+ spreadMethod="reflect" />
+ <defs
+ id="defs940">
+ <linearGradient
+ id="linearGradient941"
+ x1="0.0000000"
+ y1="0.50000000"
+ x2="1.0000000"
+ y2="0.50000000"
+ gradientUnits="objectBoundingBox"
+ spreadMethod="pad"
+ xlink:href="#linearGradient993" />
+ <linearGradient
+ id="linearGradient944">
+ <stop
+ style="stop-color:#19839a;stop-opacity:0.0000000;"
+ offset="0.0000000"
+ id="stop945" />
+ <stop
+ style="stop-color:#fff;stop-opacity:1;"
+ offset="1"
+ id="stop946" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient947">
+ <stop
+ style="stop-color:#ebffff;stop-opacity:0.0000000;"
+ offset="0.0000000"
+ id="stop948" />
+ <stop
+ style="stop-color:#fff;stop-opacity:1;"
+ offset="1"
+ id="stop949" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient950">
+ <stop
+ style="stop-color:#000;stop-opacity:1;"
+ offset="0"
+ id="stop951" />
+ <stop
+ style="stop-color:#fff;stop-opacity:1;"
+ offset="1"
+ id="stop952" />
+ </linearGradient>
+ <linearGradient
+ xlink:href="#linearGradient830"
+ id="linearGradient953"
+ x1="1.5500000"
+ y1="0.52343750"
+ x2="0.20422535"
+ y2="-0.12195122"
+ spreadMethod="reflect" />
+ <linearGradient
+ xlink:href="#linearGradient830"
+ id="linearGradient954"
+ x1="-0.31159419"
+ y1="0.19531250"
+ x2="0.77536231"
+ y2="0.94531250" />
+ <linearGradient
+ xlink:href="#linearGradient830"
+ id="linearGradient955" />
+ <linearGradient
+ xlink:href="#linearGradient868"
+ id="linearGradient956"
+ x1="-0.49264705"
+ y1="0.43750000"
+ x2="0.022058824"
+ y2="0.92187500" />
+ </defs>
+ <sodipodi:namedview
+ id="namedview957"
+ pagecolor="#ffffff"
+ bordercolor="#666666"
+ borderopacity="1.0"
+ inkscape:pageopacity="0.0"
+ inkscape:pageshadow="2"
+ inkscape:zoom="4.0000000"
+ inkscape:cx="79.132843"
+ inkscape:cy="33.777672"
+ inkscape:window-width="1022"
+ inkscape:window-height="701"
+ gridspacingy="1.0000000pt"
+ gridspacingx="1.0000000pt"
+ gridtolerance="1.0000000px"
+ inkscape:window-x="0"
+ inkscape:window-y="0" />
+ </defs>
+ <sodipodi:namedview
+ id="base"
+ pagecolor="#ffffff"
+ bordercolor="#666666"
+ borderopacity="1.0"
+ inkscape:pageopacity="0.0"
+ inkscape:pageshadow="2"
+ inkscape:zoom="16.000000"
+ inkscape:cx="13.797281"
+ inkscape:cy="14.222243"
+ inkscape:window-width="1016"
+ inkscape:window-height="693"
+ gridspacingy="1.0000000pt"
+ gridspacingx="1.0000000pt"
+ gridtolerance="1.0000000px"
+ inkscape:window-x="0"
+ inkscape:window-y="0"
+ showgrid="true"
+ showguides="true"
+ snaptoguides="true"
+ inkscape:current-layer="svg1">
+ <sodipodi:guide
+ orientation="horizontal"
+ position="11.048543"
+ id="guide875" />
+ <sodipodi:guide
+ orientation="vertical"
+ position="11.004349"
+ id="guide876" />
+ </sodipodi:namedview>
+ <g
+ id="g4550"
+ transform="matrix(0.000000,1.000000,-1.000000,0.000000,27.50000,0.000000)">
+ <rect
+ height="1.0000000"
+ style="fill:#ff0000;fill-opacity:1.0000000;fill-rule:evenodd;stroke:none;stroke-width:1.0000000;stroke-miterlimit:4.0000000;stroke-dasharray:none"
+ id="rect4879"
+ width="12.500000"
+ x="7.5000000"
+ y="26.250000" />
+ <g
+ transform="matrix(-1.000000,0.000000,0.000000,-1.000000,27.50000,40.00000)"
+ id="g5975">
+ <path
+ style="font-size:12.000000px;fill:#ff0000;fill-opacity:1.0000000;fill-rule:evenodd;stroke:none;stroke-width:1.0000000;stroke-linecap:butt;stroke-miterlimit:4.0000000;stroke-opacity:1.0000000"
+ d="M 13.750000,13.750000 L 8.4000000,19.100000 L 9.1000000,19.800000 L 13.750000,15.200000 L 18.400000,19.800000 L 19.100000,19.100000 L 13.750000,13.750000 z "
+ id="path1593"
+ sodipodi:nodetypes="ccccccc" />
+ <rect
+ y="15.000000"
+ x="12.500000"
+ height="11.250000"
+ width="2.5000000"
+ id="rect1595"
+ style="font-size:12.000000px;fill:#ff0000;fill-opacity:1.0000000;fill-rule:evenodd;stroke:none;stroke-width:1.0000000pt" />
+ </g>
+ </g>
+</svg>
diff --git a/umbrello/umbrello/pics/sources/align_right.svg b/umbrello/umbrello/pics/sources/align_right.svg
new file mode 100644
index 00000000..8fa3af6e
--- /dev/null
+++ b/umbrello/umbrello/pics/sources/align_right.svg
@@ -0,0 +1,260 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 20010904//EN"
+"http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd">
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+<svg
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://web.resource.org/cc/"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:xlink="http://www.w3.org/1999/xlink"
+ xmlns:sodipodi="http://inkscape.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ id="svg1"
+ sodipodi:version="0.32"
+ inkscape:version="0.42"
+ width="22pt"
+ height="22pt"
+ sodipodi:docbase="/home/dani/Proyectos/umbrello-svn/kdesdk/umbrello/umbrello/pics/sources"
+ sodipodi:docname="align_right.svg">
+ <metadata
+ id="metadata4876">
+ <rdf:RDF>
+ <cc:Work
+ rdf:about="">
+ <dc:format>image/svg+xml</dc:format>
+ <dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+ </cc:Work>
+ </rdf:RDF>
+ </metadata>
+ <defs
+ id="defs3">
+ <linearGradient
+ id="linearGradient993">
+ <stop
+ offset="0.0000000"
+ style="stop-color:#ffffff;stop-opacity:0.0000000;"
+ id="stop995" />
+ <stop
+ offset="1.0000000"
+ style="stop-color:#ffffff;stop-opacity:1.0000000;"
+ id="stop994" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient868">
+ <stop
+ style="stop-color:#ffffff;stop-opacity:0.0000000;"
+ offset="0.0000000"
+ id="stop869" />
+ <stop
+ style="stop-color:#fff;stop-opacity:1;"
+ offset="1"
+ id="stop870" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient893">
+ <stop
+ style="stop-color:#19839a;stop-opacity:0.0000000;"
+ offset="0.0000000"
+ id="stop894" />
+ <stop
+ style="stop-color:#fff;stop-opacity:1;"
+ offset="1"
+ id="stop895" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient830">
+ <stop
+ style="stop-color:#ebffff;stop-opacity:0.0000000;"
+ offset="0.0000000"
+ id="stop831" />
+ <stop
+ style="stop-color:#fff;stop-opacity:1;"
+ offset="1"
+ id="stop832" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient826">
+ <stop
+ style="stop-color:#000;stop-opacity:1;"
+ offset="0"
+ id="stop827" />
+ <stop
+ style="stop-color:#fff;stop-opacity:1;"
+ offset="1"
+ id="stop828" />
+ </linearGradient>
+ <linearGradient
+ xlink:href="#linearGradient830"
+ id="linearGradient829"
+ x1="1.5500000"
+ y1="0.52343750"
+ x2="0.20422535"
+ y2="-0.12195122"
+ spreadMethod="reflect" />
+ <linearGradient
+ xlink:href="#linearGradient830"
+ id="linearGradient834"
+ x1="-0.31159419"
+ y1="0.19531250"
+ x2="0.77536231"
+ y2="0.94531250" />
+ <linearGradient
+ xlink:href="#linearGradient830"
+ id="linearGradient836" />
+ <linearGradient
+ xlink:href="#linearGradient868"
+ id="linearGradient892"
+ x1="1.8449316"
+ y1="0.98914021"
+ x2="0.14743590"
+ y2="0.67741936"
+ spreadMethod="reflect" />
+ <defs
+ id="defs940">
+ <linearGradient
+ id="linearGradient941"
+ x1="0.0000000"
+ y1="0.50000000"
+ x2="1.0000000"
+ y2="0.50000000"
+ gradientUnits="objectBoundingBox"
+ spreadMethod="pad"
+ xlink:href="#linearGradient993" />
+ <linearGradient
+ id="linearGradient944">
+ <stop
+ style="stop-color:#19839a;stop-opacity:0.0000000;"
+ offset="0.0000000"
+ id="stop945" />
+ <stop
+ style="stop-color:#fff;stop-opacity:1;"
+ offset="1"
+ id="stop946" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient947">
+ <stop
+ style="stop-color:#ebffff;stop-opacity:0.0000000;"
+ offset="0.0000000"
+ id="stop948" />
+ <stop
+ style="stop-color:#fff;stop-opacity:1;"
+ offset="1"
+ id="stop949" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient950">
+ <stop
+ style="stop-color:#000;stop-opacity:1;"
+ offset="0"
+ id="stop951" />
+ <stop
+ style="stop-color:#fff;stop-opacity:1;"
+ offset="1"
+ id="stop952" />
+ </linearGradient>
+ <linearGradient
+ xlink:href="#linearGradient830"
+ id="linearGradient953"
+ x1="1.5500000"
+ y1="0.52343750"
+ x2="0.20422535"
+ y2="-0.12195122"
+ spreadMethod="reflect" />
+ <linearGradient
+ xlink:href="#linearGradient830"
+ id="linearGradient954"
+ x1="-0.31159419"
+ y1="0.19531250"
+ x2="0.77536231"
+ y2="0.94531250" />
+ <linearGradient
+ xlink:href="#linearGradient830"
+ id="linearGradient955" />
+ <linearGradient
+ xlink:href="#linearGradient868"
+ id="linearGradient956"
+ x1="-0.49264705"
+ y1="0.43750000"
+ x2="0.022058824"
+ y2="0.92187500" />
+ </defs>
+ <sodipodi:namedview
+ id="namedview957"
+ pagecolor="#ffffff"
+ bordercolor="#666666"
+ borderopacity="1.0"
+ inkscape:pageopacity="0.0"
+ inkscape:pageshadow="2"
+ inkscape:zoom="4.0000000"
+ inkscape:cx="79.132843"
+ inkscape:cy="33.777672"
+ inkscape:window-width="1022"
+ inkscape:window-height="701"
+ gridspacingy="1.0000000pt"
+ gridspacingx="1.0000000pt"
+ gridtolerance="1.0000000px"
+ inkscape:window-x="0"
+ inkscape:window-y="0" />
+ </defs>
+ <sodipodi:namedview
+ id="base"
+ pagecolor="#ffffff"
+ bordercolor="#666666"
+ borderopacity="1.0"
+ inkscape:pageopacity="0.0"
+ inkscape:pageshadow="2"
+ inkscape:zoom="22.627417"
+ inkscape:cx="13.797281"
+ inkscape:cy="14.954476"
+ inkscape:window-width="1016"
+ inkscape:window-height="693"
+ gridspacingy="1.0000000pt"
+ gridspacingx="1.0000000pt"
+ gridtolerance="1.0000000px"
+ inkscape:window-x="0"
+ inkscape:window-y="0"
+ showgrid="true"
+ showguides="true"
+ snaptoguides="true"
+ inkscape:current-layer="svg1">
+ <sodipodi:guide
+ orientation="horizontal"
+ position="11.048543"
+ id="guide875" />
+ <sodipodi:guide
+ orientation="vertical"
+ position="11.004349"
+ id="guide876" />
+ </sodipodi:namedview>
+ <g
+ id="g4550"
+ transform="matrix(0.000000,-1.000000,1.000000,0.000000,0.000000,27.50000)">
+ <rect
+ height="1.0000000"
+ style="fill:#ff0000;fill-opacity:1.0000000;fill-rule:evenodd;stroke:none;stroke-width:1.0000000;stroke-miterlimit:4.0000000;stroke-dasharray:none"
+ id="rect4879"
+ width="12.500000"
+ x="7.5000000"
+ y="26.250000" />
+ <g
+ transform="matrix(-1.000000,0.000000,0.000000,-1.000000,27.50000,40.00000)"
+ id="g5975">
+ <path
+ style="font-size:12.000000px;fill:#ff0000;fill-opacity:1.0000000;fill-rule:evenodd;stroke:none;stroke-width:1.0000000;stroke-linecap:butt;stroke-miterlimit:4.0000000;stroke-opacity:1.0000000"
+ d="M 13.750000,13.750000 L 8.4000000,19.100000 L 9.1000000,19.800000 L 13.750000,15.200000 L 18.400000,19.800000 L 19.100000,19.100000 L 13.750000,13.750000 z "
+ id="path1593"
+ sodipodi:nodetypes="ccccccc" />
+ <rect
+ y="15.000000"
+ x="12.500000"
+ height="11.250000"
+ width="2.5000000"
+ id="rect1595"
+ style="font-size:12.000000px;fill:#ff0000;fill-opacity:1.0000000;fill-rule:evenodd;stroke:none;stroke-width:1.0000000pt" />
+ </g>
+ </g>
+</svg>
diff --git a/umbrello/umbrello/pics/sources/align_top.svg b/umbrello/umbrello/pics/sources/align_top.svg
new file mode 100644
index 00000000..e7cec488
--- /dev/null
+++ b/umbrello/umbrello/pics/sources/align_top.svg
@@ -0,0 +1,251 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 20010904//EN"
+"http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd">
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+<svg
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://web.resource.org/cc/"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:xlink="http://www.w3.org/1999/xlink"
+ xmlns:sodipodi="http://inkscape.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ id="svg1"
+ sodipodi:version="0.32"
+ inkscape:version="0.42"
+ width="22pt"
+ height="22pt"
+ sodipodi:docbase="/home/dani/Proyectos/umbrello-svn/kdesdk/umbrello/umbrello/pics/sources"
+ sodipodi:docname="align_top.svg">
+ <metadata
+ id="metadata4677">
+ <rdf:RDF>
+ <cc:Work
+ rdf:about="">
+ <dc:format>image/svg+xml</dc:format>
+ <dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+ </cc:Work>
+ </rdf:RDF>
+ </metadata>
+ <defs
+ id="defs3">
+ <linearGradient
+ id="linearGradient993">
+ <stop
+ offset="0.0000000"
+ style="stop-color:#ffffff;stop-opacity:0.0000000;"
+ id="stop995" />
+ <stop
+ offset="1.0000000"
+ style="stop-color:#ffffff;stop-opacity:1.0000000;"
+ id="stop994" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient868">
+ <stop
+ style="stop-color:#ffffff;stop-opacity:0.0000000;"
+ offset="0.0000000"
+ id="stop869" />
+ <stop
+ style="stop-color:#fff;stop-opacity:1;"
+ offset="1"
+ id="stop870" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient893">
+ <stop
+ style="stop-color:#19839a;stop-opacity:0.0000000;"
+ offset="0.0000000"
+ id="stop894" />
+ <stop
+ style="stop-color:#fff;stop-opacity:1;"
+ offset="1"
+ id="stop895" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient830">
+ <stop
+ style="stop-color:#ebffff;stop-opacity:0.0000000;"
+ offset="0.0000000"
+ id="stop831" />
+ <stop
+ style="stop-color:#fff;stop-opacity:1;"
+ offset="1"
+ id="stop832" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient826">
+ <stop
+ style="stop-color:#000;stop-opacity:1;"
+ offset="0"
+ id="stop827" />
+ <stop
+ style="stop-color:#fff;stop-opacity:1;"
+ offset="1"
+ id="stop828" />
+ </linearGradient>
+ <linearGradient
+ xlink:href="#linearGradient830"
+ id="linearGradient829"
+ x1="1.5500000"
+ y1="0.52343750"
+ x2="0.20422535"
+ y2="-0.12195122"
+ spreadMethod="reflect" />
+ <linearGradient
+ xlink:href="#linearGradient830"
+ id="linearGradient834"
+ x1="-0.31159419"
+ y1="0.19531250"
+ x2="0.77536231"
+ y2="0.94531250" />
+ <linearGradient
+ xlink:href="#linearGradient830"
+ id="linearGradient836" />
+ <linearGradient
+ xlink:href="#linearGradient868"
+ id="linearGradient892"
+ x1="1.8449316"
+ y1="0.98914021"
+ x2="0.14743590"
+ y2="0.67741936"
+ spreadMethod="reflect" />
+ <defs
+ id="defs940">
+ <linearGradient
+ id="linearGradient941"
+ x1="0.0000000"
+ y1="0.50000000"
+ x2="1.0000000"
+ y2="0.50000000"
+ gradientUnits="objectBoundingBox"
+ spreadMethod="pad"
+ xlink:href="#linearGradient993" />
+ <linearGradient
+ id="linearGradient944">
+ <stop
+ style="stop-color:#19839a;stop-opacity:0.0000000;"
+ offset="0.0000000"
+ id="stop945" />
+ <stop
+ style="stop-color:#fff;stop-opacity:1;"
+ offset="1"
+ id="stop946" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient947">
+ <stop
+ style="stop-color:#ebffff;stop-opacity:0.0000000;"
+ offset="0.0000000"
+ id="stop948" />
+ <stop
+ style="stop-color:#fff;stop-opacity:1;"
+ offset="1"
+ id="stop949" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient950">
+ <stop
+ style="stop-color:#000;stop-opacity:1;"
+ offset="0"
+ id="stop951" />
+ <stop
+ style="stop-color:#fff;stop-opacity:1;"
+ offset="1"
+ id="stop952" />
+ </linearGradient>
+ <linearGradient
+ xlink:href="#linearGradient830"
+ id="linearGradient953"
+ x1="1.5500000"
+ y1="0.52343750"
+ x2="0.20422535"
+ y2="-0.12195122"
+ spreadMethod="reflect" />
+ <linearGradient
+ xlink:href="#linearGradient830"
+ id="linearGradient954"
+ x1="-0.31159419"
+ y1="0.19531250"
+ x2="0.77536231"
+ y2="0.94531250" />
+ <linearGradient
+ xlink:href="#linearGradient830"
+ id="linearGradient955" />
+ <linearGradient
+ xlink:href="#linearGradient868"
+ id="linearGradient956"
+ x1="-0.49264705"
+ y1="0.43750000"
+ x2="0.022058824"
+ y2="0.92187500" />
+ </defs>
+ <sodipodi:namedview
+ id="namedview957"
+ pagecolor="#ffffff"
+ bordercolor="#666666"
+ borderopacity="1.0"
+ inkscape:pageopacity="0.0"
+ inkscape:pageshadow="2"
+ inkscape:zoom="4.0000000"
+ inkscape:cx="79.132843"
+ inkscape:cy="33.777672"
+ inkscape:window-width="1022"
+ inkscape:window-height="701"
+ gridspacingy="1.0000000pt"
+ gridspacingx="1.0000000pt"
+ gridtolerance="1.0000000px"
+ inkscape:window-x="0"
+ inkscape:window-y="0" />
+ </defs>
+ <sodipodi:namedview
+ id="base"
+ pagecolor="#ffffff"
+ bordercolor="#666666"
+ borderopacity="1.0"
+ inkscape:pageopacity="0.0"
+ inkscape:pageshadow="2"
+ inkscape:zoom="22.627417"
+ inkscape:cx="13.797281"
+ inkscape:cy="16.548827"
+ inkscape:window-width="1016"
+ inkscape:window-height="693"
+ gridspacingy="1.0000000pt"
+ gridspacingx="1.0000000pt"
+ gridtolerance="1.0000000px"
+ inkscape:window-x="0"
+ inkscape:window-y="0"
+ showgrid="true"
+ showguides="true"
+ snaptoguides="true"
+ inkscape:current-layer="svg1" />
+ <g
+ id="g4550"
+ transform="matrix(-1.000000,0.000000,0.000000,-1.000000,27.50000,27.50000)">
+ <rect
+ height="1.0000000"
+ style="fill:#ff0000;fill-opacity:1.0000000;fill-rule:evenodd;stroke:none;stroke-width:1.0000000;stroke-miterlimit:4.0000000;stroke-dasharray:none"
+ id="rect4680"
+ width="12.500000"
+ x="7.5000000"
+ y="26.250000" />
+ <g
+ transform="matrix(-1.000000,0.000000,0.000000,-1.000000,27.50000,40.00000)"
+ id="g5975">
+ <path
+ style="font-size:12.000000px;fill:#ff0000;fill-opacity:1.0000000;fill-rule:evenodd;stroke:none;stroke-width:1.0000000;stroke-linecap:butt;stroke-miterlimit:4.0000000;stroke-opacity:1.0000000"
+ d="M 13.750000,13.750000 L 8.4000000,19.100000 L 9.1000000,19.800000 L 13.750000,15.200000 L 18.400000,19.800000 L 19.100000,19.100000 L 13.750000,13.750000 z "
+ id="path1593"
+ sodipodi:nodetypes="ccccccc" />
+ <rect
+ y="15.000000"
+ x="12.500000"
+ height="11.250000"
+ width="2.5000000"
+ id="rect1595"
+ style="font-size:12.000000px;fill:#ff0000;fill-opacity:1.0000000;fill-rule:evenodd;stroke:none;stroke-width:1.0000000pt" />
+ </g>
+ </g>
+</svg>
diff --git a/umbrello/umbrello/pics/sources/align_vert_distribute.svg b/umbrello/umbrello/pics/sources/align_vert_distribute.svg
new file mode 100644
index 00000000..135eda26
--- /dev/null
+++ b/umbrello/umbrello/pics/sources/align_vert_distribute.svg
@@ -0,0 +1,272 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 20010904//EN"
+"http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd">
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+<svg
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://web.resource.org/cc/"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:xlink="http://www.w3.org/1999/xlink"
+ xmlns:sodipodi="http://inkscape.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ id="svg1"
+ sodipodi:version="0.32"
+ inkscape:version="0.42"
+ width="22pt"
+ height="22pt"
+ sodipodi:docbase="/home/dani/Proyectos/umbrello-svn/kdesdk/umbrello/umbrello/pics/sources"
+ sodipodi:docname="align_vert_distribute.svg"
+ inkscape:export-filename="/home/dani/Proyectos/umbrello-svn/kdesdk/umbrello/umbrello/pics/align_hori_distribute.png"
+ inkscape:export-xdpi="72.000000"
+ inkscape:export-ydpi="72.000000">
+ <metadata
+ id="metadata1589">
+ <rdf:RDF>
+ <cc:Work
+ rdf:about="">
+ <dc:format>image/svg+xml</dc:format>
+ <dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+ </cc:Work>
+ </rdf:RDF>
+ </metadata>
+ <defs
+ id="defs3">
+ <linearGradient
+ id="linearGradient993">
+ <stop
+ offset="0.0000000"
+ style="stop-color:#ffffff;stop-opacity:0.0000000;"
+ id="stop995" />
+ <stop
+ offset="1.0000000"
+ style="stop-color:#ffffff;stop-opacity:1.0000000;"
+ id="stop994" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient868">
+ <stop
+ style="stop-color:#ffffff;stop-opacity:0.0000000;"
+ offset="0.0000000"
+ id="stop869" />
+ <stop
+ style="stop-color:#fff;stop-opacity:1;"
+ offset="1"
+ id="stop870" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient893">
+ <stop
+ style="stop-color:#19839a;stop-opacity:0.0000000;"
+ offset="0.0000000"
+ id="stop894" />
+ <stop
+ style="stop-color:#fff;stop-opacity:1;"
+ offset="1"
+ id="stop895" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient830">
+ <stop
+ style="stop-color:#ebffff;stop-opacity:0.0000000;"
+ offset="0.0000000"
+ id="stop831" />
+ <stop
+ style="stop-color:#fff;stop-opacity:1;"
+ offset="1"
+ id="stop832" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient826">
+ <stop
+ style="stop-color:#000;stop-opacity:1;"
+ offset="0"
+ id="stop827" />
+ <stop
+ style="stop-color:#fff;stop-opacity:1;"
+ offset="1"
+ id="stop828" />
+ </linearGradient>
+ <linearGradient
+ xlink:href="#linearGradient830"
+ id="linearGradient829"
+ x1="1.5500000"
+ y1="0.52343750"
+ x2="0.20422535"
+ y2="-0.12195122"
+ spreadMethod="reflect" />
+ <linearGradient
+ xlink:href="#linearGradient830"
+ id="linearGradient834"
+ x1="-0.31159419"
+ y1="0.19531250"
+ x2="0.77536231"
+ y2="0.94531250" />
+ <linearGradient
+ xlink:href="#linearGradient830"
+ id="linearGradient836" />
+ <linearGradient
+ xlink:href="#linearGradient868"
+ id="linearGradient892"
+ x1="1.8449316"
+ y1="0.98914021"
+ x2="0.14743590"
+ y2="0.67741936"
+ spreadMethod="reflect" />
+ <defs
+ id="defs940">
+ <linearGradient
+ id="linearGradient941"
+ x1="0.0000000"
+ y1="0.50000000"
+ x2="1.0000000"
+ y2="0.50000000"
+ gradientUnits="objectBoundingBox"
+ spreadMethod="pad"
+ xlink:href="#linearGradient993" />
+ <linearGradient
+ id="linearGradient944">
+ <stop
+ style="stop-color:#19839a;stop-opacity:0.0000000;"
+ offset="0.0000000"
+ id="stop945" />
+ <stop
+ style="stop-color:#fff;stop-opacity:1;"
+ offset="1"
+ id="stop946" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient947">
+ <stop
+ style="stop-color:#ebffff;stop-opacity:0.0000000;"
+ offset="0.0000000"
+ id="stop948" />
+ <stop
+ style="stop-color:#fff;stop-opacity:1;"
+ offset="1"
+ id="stop949" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient950">
+ <stop
+ style="stop-color:#000;stop-opacity:1;"
+ offset="0"
+ id="stop951" />
+ <stop
+ style="stop-color:#fff;stop-opacity:1;"
+ offset="1"
+ id="stop952" />
+ </linearGradient>
+ <linearGradient
+ xlink:href="#linearGradient830"
+ id="linearGradient953"
+ x1="1.5500000"
+ y1="0.52343750"
+ x2="0.20422535"
+ y2="-0.12195122"
+ spreadMethod="reflect" />
+ <linearGradient
+ xlink:href="#linearGradient830"
+ id="linearGradient954"
+ x1="-0.31159419"
+ y1="0.19531250"
+ x2="0.77536231"
+ y2="0.94531250" />
+ <linearGradient
+ xlink:href="#linearGradient830"
+ id="linearGradient955" />
+ <linearGradient
+ xlink:href="#linearGradient868"
+ id="linearGradient956"
+ x1="-0.49264705"
+ y1="0.43750000"
+ x2="0.022058824"
+ y2="0.92187500" />
+ </defs>
+ <sodipodi:namedview
+ id="namedview957"
+ pagecolor="#ffffff"
+ bordercolor="#666666"
+ borderopacity="1.0"
+ inkscape:pageopacity="0.0"
+ inkscape:pageshadow="2"
+ inkscape:zoom="4.0000000"
+ inkscape:cx="79.132843"
+ inkscape:cy="33.777672"
+ inkscape:window-width="1022"
+ inkscape:window-height="701"
+ gridspacingy="1.0000000pt"
+ gridspacingx="1.0000000pt"
+ gridtolerance="1.0000000px"
+ inkscape:window-x="0"
+ inkscape:window-y="0" />
+ </defs>
+ <sodipodi:namedview
+ id="base"
+ pagecolor="#ffffff"
+ bordercolor="#666666"
+ borderopacity="1.0"
+ inkscape:pageopacity="0.0"
+ inkscape:pageshadow="2"
+ inkscape:zoom="11.313709"
+ inkscape:cx="13.750000"
+ inkscape:cy="16.722243"
+ inkscape:window-width="1016"
+ inkscape:window-height="713"
+ gridspacingy="1.0000000pt"
+ gridspacingx="1.0000000pt"
+ gridtolerance="1.0000000px"
+ inkscape:window-x="0"
+ inkscape:window-y="0"
+ showgrid="true"
+ showguides="false"
+ snaptoguides="true"
+ inkscape:guide-bbox="false"
+ inkscape:grid-bbox="false"
+ inkscape:current-layer="svg1">
+ <sodipodi:guide
+ orientation="horizontal"
+ position="11.048543"
+ id="guide875" />
+ <sodipodi:guide
+ orientation="vertical"
+ position="11.004349"
+ id="guide876" />
+ </sodipodi:namedview>
+ <g
+ id="g4550">
+ <rect
+ height="1.0000000"
+ style="fill:#ff0000;fill-opacity:1.0000000;fill-rule:evenodd;stroke:none;stroke-width:1.0000000;stroke-miterlimit:4.0000000;stroke-dasharray:none"
+ id="rect863"
+ width="12.500000"
+ x="7.5000000"
+ y="26.250000" />
+ <g
+ transform="matrix(-1.000000,0.000000,0.000000,-1.000000,27.50000,40.00000)"
+ id="g5975">
+ <path
+ style="font-size:12.000000px;fill:#ff0000;fill-opacity:1.0000000;fill-rule:evenodd;stroke:none;stroke-width:1.0000000;stroke-linecap:butt;stroke-miterlimit:4.0000000;stroke-opacity:1.0000000"
+ d="M 13.750000,13.750000 L 8.4000000,19.100000 L 9.1000000,19.800000 L 13.750000,15.200000 L 18.400000,19.800000 L 19.100000,19.100000 L 13.750000,13.750000 z "
+ id="path1593"
+ sodipodi:nodetypes="ccccccc" />
+ <rect
+ y="15.000000"
+ x="12.500000"
+ height="11.250000"
+ width="2.5000000"
+ id="rect1595"
+ style="font-size:12.000000px;fill:#ff0000;fill-opacity:1.0000000;fill-rule:evenodd;stroke:none;stroke-width:1.0000000pt" />
+ </g>
+ </g>
+ <use
+ x="0.0000000"
+ y="0.0000000"
+ xlink:href="#g4550"
+ id="use1412"
+ transform="matrix(-1.000000,0.000000,0.000000,-1.000000,27.50000,27.50000)"
+ width="27.500000"
+ height="27.500000" />
+</svg>
diff --git a/umbrello/umbrello/pics/sources/align_vert_middle.svg b/umbrello/umbrello/pics/sources/align_vert_middle.svg
new file mode 100644
index 00000000..b7b62def
--- /dev/null
+++ b/umbrello/umbrello/pics/sources/align_vert_middle.svg
@@ -0,0 +1,254 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 20010904//EN"
+"http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd">
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+<svg
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://web.resource.org/cc/"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:xlink="http://www.w3.org/1999/xlink"
+ xmlns:sodipodi="http://inkscape.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ id="svg1"
+ sodipodi:version="0.32"
+ inkscape:version="0.42"
+ width="22pt"
+ height="22pt"
+ sodipodi:docbase="/home/dani/Proyectos/umbrello-svn/kdesdk/umbrello/umbrello/pics/sources"
+ sodipodi:docname="align_vert_middle.svg">
+ <metadata
+ id="metadata1467">
+ <rdf:RDF>
+ <cc:Work
+ rdf:about="">
+ <dc:format>image/svg+xml</dc:format>
+ <dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+ </cc:Work>
+ </rdf:RDF>
+ </metadata>
+ <defs
+ id="defs3">
+ <linearGradient
+ id="linearGradient993">
+ <stop
+ offset="0.0000000"
+ style="stop-color:#ffffff;stop-opacity:0.0000000;"
+ id="stop995" />
+ <stop
+ offset="1.0000000"
+ style="stop-color:#ffffff;stop-opacity:1.0000000;"
+ id="stop994" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient868">
+ <stop
+ style="stop-color:#ffffff;stop-opacity:0.0000000;"
+ offset="0.0000000"
+ id="stop869" />
+ <stop
+ style="stop-color:#fff;stop-opacity:1;"
+ offset="1"
+ id="stop870" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient893">
+ <stop
+ style="stop-color:#19839a;stop-opacity:0.0000000;"
+ offset="0.0000000"
+ id="stop894" />
+ <stop
+ style="stop-color:#fff;stop-opacity:1;"
+ offset="1"
+ id="stop895" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient830">
+ <stop
+ style="stop-color:#ebffff;stop-opacity:0.0000000;"
+ offset="0.0000000"
+ id="stop831" />
+ <stop
+ style="stop-color:#fff;stop-opacity:1;"
+ offset="1"
+ id="stop832" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient826">
+ <stop
+ style="stop-color:#000;stop-opacity:1;"
+ offset="0"
+ id="stop827" />
+ <stop
+ style="stop-color:#fff;stop-opacity:1;"
+ offset="1"
+ id="stop828" />
+ </linearGradient>
+ <linearGradient
+ xlink:href="#linearGradient830"
+ id="linearGradient829"
+ x1="1.5500000"
+ y1="0.52343750"
+ x2="0.20422535"
+ y2="-0.12195122"
+ spreadMethod="reflect" />
+ <linearGradient
+ xlink:href="#linearGradient830"
+ id="linearGradient834"
+ x1="-0.31159419"
+ y1="0.19531250"
+ x2="0.77536231"
+ y2="0.94531250" />
+ <linearGradient
+ xlink:href="#linearGradient830"
+ id="linearGradient836" />
+ <linearGradient
+ xlink:href="#linearGradient868"
+ id="linearGradient892"
+ x1="1.8449316"
+ y1="0.98914021"
+ x2="0.14743590"
+ y2="0.67741936"
+ spreadMethod="reflect" />
+ <defs
+ id="defs940">
+ <linearGradient
+ id="linearGradient941"
+ x1="0.0000000"
+ y1="0.50000000"
+ x2="1.0000000"
+ y2="0.50000000"
+ gradientUnits="objectBoundingBox"
+ spreadMethod="pad"
+ xlink:href="#linearGradient993" />
+ <linearGradient
+ id="linearGradient944">
+ <stop
+ style="stop-color:#19839a;stop-opacity:0.0000000;"
+ offset="0.0000000"
+ id="stop945" />
+ <stop
+ style="stop-color:#fff;stop-opacity:1;"
+ offset="1"
+ id="stop946" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient947">
+ <stop
+ style="stop-color:#ebffff;stop-opacity:0.0000000;"
+ offset="0.0000000"
+ id="stop948" />
+ <stop
+ style="stop-color:#fff;stop-opacity:1;"
+ offset="1"
+ id="stop949" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient950">
+ <stop
+ style="stop-color:#000;stop-opacity:1;"
+ offset="0"
+ id="stop951" />
+ <stop
+ style="stop-color:#fff;stop-opacity:1;"
+ offset="1"
+ id="stop952" />
+ </linearGradient>
+ <linearGradient
+ xlink:href="#linearGradient830"
+ id="linearGradient953"
+ x1="1.5500000"
+ y1="0.52343750"
+ x2="0.20422535"
+ y2="-0.12195122"
+ spreadMethod="reflect" />
+ <linearGradient
+ xlink:href="#linearGradient830"
+ id="linearGradient954"
+ x1="-0.31159419"
+ y1="0.19531250"
+ x2="0.77536231"
+ y2="0.94531250" />
+ <linearGradient
+ xlink:href="#linearGradient830"
+ id="linearGradient955" />
+ <linearGradient
+ xlink:href="#linearGradient868"
+ id="linearGradient956"
+ x1="-0.49264705"
+ y1="0.43750000"
+ x2="0.022058824"
+ y2="0.92187500" />
+ </defs>
+ <sodipodi:namedview
+ id="namedview957"
+ pagecolor="#ffffff"
+ bordercolor="#666666"
+ borderopacity="1.0"
+ inkscape:pageopacity="0.0"
+ inkscape:pageshadow="2"
+ inkscape:zoom="4.0000000"
+ inkscape:cx="79.132843"
+ inkscape:cy="33.777672"
+ inkscape:window-width="1022"
+ inkscape:window-height="701"
+ gridspacingy="1.0000000pt"
+ gridspacingx="1.0000000pt"
+ gridtolerance="1.0000000px"
+ inkscape:window-x="0"
+ inkscape:window-y="0" />
+ </defs>
+ <sodipodi:namedview
+ id="base"
+ pagecolor="#ffffff"
+ bordercolor="#666666"
+ borderopacity="1.0"
+ inkscape:pageopacity="0.0"
+ inkscape:pageshadow="2"
+ inkscape:zoom="10.511311"
+ inkscape:cx="11.950527"
+ inkscape:cy="9.8572805"
+ inkscape:window-width="1016"
+ inkscape:window-height="693"
+ gridspacingy="1.0000000pt"
+ gridspacingx="1.0000000pt"
+ gridtolerance="1.0000000px"
+ inkscape:window-x="0"
+ inkscape:window-y="0"
+ showgrid="true"
+ showguides="false"
+ snaptoguides="true"
+ inkscape:guide-bbox="false"
+ inkscape:current-layer="svg1">
+ <sodipodi:guide
+ orientation="vertical"
+ position="11.004349"
+ id="guide876" />
+ </sodipodi:namedview>
+ <g
+ id="g5975"
+ transform="matrix(0.000000,1.000000,-1.000000,0.000000,27.50000,0.000000)">
+ <path
+ sodipodi:nodetypes="ccccccc"
+ id="path1470"
+ d="M 13.750000,13.750000 L 8.4000000,19.100000 L 9.1000000,19.800000 L 13.750000,15.200000 L 18.400000,19.800000 L 19.100000,19.100000 L 13.750000,13.750000 z "
+ style="font-size:12.000000px;fill:#ff0000;fill-opacity:1.0000000;fill-rule:evenodd;stroke:none;stroke-width:1.0000000;stroke-linecap:butt;stroke-miterlimit:4.0000000;stroke-opacity:1.0000000" />
+ <rect
+ style="font-size:12.000000px;fill:#ff0000;fill-opacity:1.0000000;fill-rule:evenodd;stroke:none;stroke-width:1.0000000pt"
+ id="rect1472"
+ width="2.5000000"
+ height="11.250000"
+ x="12.500000"
+ y="15.000000" />
+ </g>
+ <use
+ x="0.0000000"
+ y="0.0000000"
+ xlink:href="#g5975"
+ id="use1494"
+ transform="matrix(-1.000000,0.000000,0.000000,-1.000000,27.50000,27.50000)"
+ width="27.500000"
+ height="27.500000" />
+</svg>
diff --git a/umbrello/umbrello/pics/sources/anchor.svg b/umbrello/umbrello/pics/sources/anchor.svg
new file mode 100644
index 00000000..27fd26b9
--- /dev/null
+++ b/umbrello/umbrello/pics/sources/anchor.svg
@@ -0,0 +1,279 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 20010904//EN"
+"http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd">
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+<svg
+ id="svg1"
+ sodipodi:version="0.32"
+ inkscape:version="0.37"
+ width="22pt"
+ height="22pt"
+ sodipodi:docbase="/home/jr/tmp/umbrello/icons/inkscape-svg"
+ sodipodi:docname="anchor.svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:xml="http://www.w3.org/XML/1998/namespace"
+ xmlns:xlink="http://www.w3.org/1999/xlink">
+ <defs
+ id="defs3">
+ <linearGradient
+ id="linearGradient1796">
+ <stop
+ style="stop-color:#ffff21;stop-opacity:0.0000000;"
+ offset="0.0000000"
+ id="stop1797" />
+ <stop
+ style="stop-color:#fff;stop-opacity:1;"
+ offset="1"
+ id="stop1798" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient1763">
+ <stop
+ style="stop-color:#ffff21;stop-opacity:0.0000000;"
+ offset="0.0000000"
+ id="stop1764" />
+ <stop
+ style="stop-color:#fff;stop-opacity:1;"
+ offset="1"
+ id="stop1765" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient830">
+ <stop
+ style="stop-color:#ebffff;stop-opacity:0.0000000;"
+ offset="0.0000000"
+ id="stop831" />
+ <stop
+ style="stop-color:#fff;stop-opacity:1;"
+ offset="1"
+ id="stop832" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient826">
+ <stop
+ style="stop-color:#000;stop-opacity:1;"
+ offset="0"
+ id="stop827" />
+ <stop
+ style="stop-color:#fff;stop-opacity:1;"
+ offset="1"
+ id="stop828" />
+ </linearGradient>
+ <linearGradient
+ xlink:href="#linearGradient830"
+ id="linearGradient829"
+ x1="1.5500000"
+ y1="0.52343750"
+ x2="0.20422535"
+ y2="-0.12195122"
+ spreadMethod="reflect" />
+ <linearGradient
+ xlink:href="#linearGradient830"
+ id="linearGradient834"
+ x1="-0.31159419"
+ y1="0.19531250"
+ x2="0.77536231"
+ y2="0.94531250" />
+ <linearGradient
+ xlink:href="#linearGradient830"
+ id="linearGradient836" />
+ <linearGradient
+ xlink:href="#linearGradient1763"
+ id="linearGradient1762"
+ x1="-0.34579438"
+ y1="-0.16406250"
+ x2="0.71962619"
+ y2="0.80468750" />
+ <linearGradient
+ xlink:href="#linearGradient1796"
+ id="linearGradient1795"
+ x1="0.65555555"
+ y1="0.88281250"
+ x2="0.48888889"
+ y2="0.53906250"
+ spreadMethod="reflect" />
+ <defs
+ id="defs857">
+ <linearGradient
+ id="linearGradient858">
+ <stop
+ style="stop-color:#ebffff;stop-opacity:0.0000000;"
+ offset="0.0000000"
+ id="stop859" />
+ <stop
+ style="stop-color:#fff;stop-opacity:1;"
+ offset="1"
+ id="stop860" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient861">
+ <stop
+ style="stop-color:#000;stop-opacity:1;"
+ offset="0"
+ id="stop862" />
+ <stop
+ style="stop-color:#fff;stop-opacity:1;"
+ offset="1"
+ id="stop863" />
+ </linearGradient>
+ <linearGradient
+ xlink:href="#linearGradient830"
+ id="linearGradient864"
+ x1="1.5500000"
+ y1="0.52343750"
+ x2="0.20422535"
+ y2="-0.12195122"
+ spreadMethod="reflect" />
+ <linearGradient
+ xlink:href="#linearGradient830"
+ id="linearGradient865"
+ x1="-0.31159419"
+ y1="0.19531250"
+ x2="0.77536231"
+ y2="0.94531250" />
+ <linearGradient
+ xlink:href="#linearGradient830"
+ id="linearGradient866" />
+ </defs>
+ <sodipodi:namedview
+ id="namedview867"
+ pagecolor="#ffffff"
+ bordercolor="#666666"
+ borderopacity="1.0"
+ inkscape:pageopacity="0.0"
+ inkscape:pageshadow="2"
+ inkscape:zoom="0.26725582"
+ inkscape:cx="87.469639"
+ inkscape:cy="55.703730"
+ inkscape:window-width="1022"
+ inkscape:window-height="701"
+ gridspacingy="1.0000000pt"
+ gridspacingx="1.0000000pt"
+ gridtolerance="1.0000000px"
+ inkscape:window-x="0"
+ inkscape:window-y="0" />
+ </defs>
+ <sodipodi:namedview
+ id="base"
+ pagecolor="#ffffff"
+ bordercolor="#666666"
+ borderopacity="1.0"
+ inkscape:pageopacity="0.0"
+ inkscape:pageshadow="2"
+ inkscape:zoom="22.6274170"
+ inkscape:cx="13.7972814"
+ inkscape:cy="10.6838309"
+ inkscape:window-width="1016"
+ inkscape:window-height="693"
+ gridspacingy="1.0000000pt"
+ gridspacingx="1.0000000pt"
+ gridtolerance="1.0000000px"
+ inkscape:window-x="0"
+ inkscape:window-y="0"
+ showgrid="true"
+ snaptogrid="false" />
+ <rect
+ style="fill:url(#linearGradient829);fill-opacity:0.75000000;fill-rule:evenodd;stroke-width:0.45652742pt;"
+ id="rect825"
+ width="137.68759"
+ height="66.465706"
+ ry="0.0000000"
+ x="359.81241"
+ y="197.28429" />
+ <rect
+ style="fill:url(#linearGradient829);fill-opacity:0.75000000;fill-rule:evenodd;stroke-width:0.45652742pt;"
+ id="rect846"
+ width="135.18759"
+ height="37.082668"
+ ry="0.0000000"
+ x="316.25000"
+ y="81.250000" />
+ <rect
+ style="fill:url(#linearGradient829);fill-opacity:0.75000000;fill-rule:evenodd;stroke:none;stroke-width:0.45652742pt;stroke-opacity:1.0000000;"
+ id="rect847"
+ width="135.18759"
+ height="47.111610"
+ ry="0.0000000"
+ x="255.00000"
+ y="157.88839" />
+ <path
+ style="font-size:12;fill:none;fill-opacity:0.75;fill-rule:evenodd;stroke:#ff0000;stroke-width:1.25;stroke-dasharray:1.25,1.25;stroke-dashoffset:1.5;"
+ d="M 15.231442 6.8825364 L 21.810285 6.8825364 L 21.810285 6.8957665 "
+ id="path915" />
+ <path
+ style="font-size:12;fill:#f6f600;fill-rule:evenodd;stroke-width:5;"
+ d="M 8.2733326,28.387267 L 8.2733326,124.03331 L 149.01926,124.03331 L 149.01926,81.523954 C 150.50079,49.641942 119.72304,33.000935 97.500000,28.750000 L 8.2733326,28.387267 z "
+ id="path1780"
+ sodipodi:nodetypes="cccccc"
+ transform="matrix(0.108514,0.000000,0.000000,0.119774,-0.622904,-3.017803)" />
+ <path
+ style="font-size:12;fill:url(#linearGradient1762);fill-opacity:0.75;fill-rule:evenodd;stroke:#fb0000;stroke-width:1.19298;"
+ d="M 0.60632471 0.65846708 L 9.7139922 0.70128454 C 11.312264 0.55373295 14.933205 2.5419716 10.513128 5.275384 C 13.310105 4.9802809 15.174756 4.2425228 15.574325 6.6033484 L 15.603014 11.948649 L 0.60632471 11.948649 L 0.60632471 0.65846708 z "
+ id="path1781"
+ sodipodi:nodetypes="ccccccc" />
+ <text
+ xml:space="preserve"
+ style="font-size:12;font-weight:bold;font-stretch:normal;stroke-width:1pt;font-family:Bitstream Vera Sans Mono;text-anchor:middle;"
+ x="12.4761734"
+ y="21.7533916"
+ id="text838"
+ transform="scale(0.646933,0.508553)"
+ sodipodi:linespacing="100%"><tspan
+ x="12.4761734"
+ y="21.7533913"
+ sodipodi:role="line"
+ id="tspan840">XYZ</tspan></text>
+ <rect
+ style="font-size:12;fill:#ffff00;fill-rule:evenodd;stroke:#ff0000;stroke-width:1.24954;"
+ id="rect869"
+ width="13.74189394"
+ height="11.15417004"
+ x="13.18875200"
+ y="15.73248386" />
+ <rect
+ style="font-size:12;fill:url(#linearGradient829);fill-opacity:0.75;fill-rule:evenodd;stroke-width:0.456527pt;"
+ id="rect871"
+ width="12.38913868"
+ height="3.31526423"
+ ry="0"
+ x="13.81419851"
+ y="16.25072289" />
+ <text
+ xml:space="preserve"
+ style="font-size:12;stroke-width:1pt;font-family:Bitstream Vera Sans;"
+ x="26.9685458"
+ y="63.8042984"
+ id="text873"
+ transform="scale(0.510825,0.298872)"><tspan
+ id="tspan839">ABC</tspan></text>
+ <path
+ style="font-size:12;fill:none;fill-opacity:0.75;fill-rule:evenodd;stroke:#ff0000;stroke-width:0.449315;"
+ d="M 13.821664 19.408703 L 26.727376 19.408703 "
+ id="path842" />
+ <path
+ style="font-size:12;fill:none;fill-opacity:0.75;fill-rule:evenodd;stroke:#ff0000;stroke-width:0.449315;"
+ d="M 13.736684 22.820721 L 26.642397 22.820721 "
+ id="path845" />
+ <rect
+ style="font-size:12;fill:url(#linearGradient829);fill-opacity:0.75;fill-rule:evenodd;stroke-width:0.456527pt;"
+ id="rect878"
+ width="12.27865329"
+ height="3.04870009"
+ ry="0"
+ x="13.82501222"
+ y="19.53512001" />
+ <rect
+ style="font-size:12;fill:url(#linearGradient829);fill-opacity:0.75;fill-rule:evenodd;stroke-width:0.456527pt;"
+ id="rect879"
+ width="12.27865324"
+ height="2.95871878"
+ ry="0"
+ x="13.82924364"
+ y="23.11286545" />
+ <path
+ style="font-size:12;fill:none;fill-opacity:0.75;fill-rule:evenodd;stroke:#ff0000;stroke-width:1.25;stroke-dasharray:1.25,1.25;stroke-dashoffset:1.5;"
+ d="M 21.529111 5.6671972 L 21.92077 5.6671972 L 21.92077 15.845087 "
+ id="path884" />
+</svg>
diff --git a/umbrello/umbrello/pics/sources/andline.svg b/umbrello/umbrello/pics/sources/andline.svg
new file mode 100644
index 00000000..20948588
--- /dev/null
+++ b/umbrello/umbrello/pics/sources/andline.svg
@@ -0,0 +1,102 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+<svg
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://web.resource.org/cc/"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:sodipodi="http://inkscape.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ inkscape:export-ydpi="89.999504"
+ inkscape:export-xdpi="89.999504"
+ inkscape:export-filename="F:\pics\andline.png"
+ id="svg1"
+ height="22.000000px"
+ width="22.000000px"
+ y="0.00000000"
+ x="0.00000000"
+ version="1.0"
+ sodipodi:version="0.32"
+ inkscape:version="0.40+cvs"
+ sodipodi:docname="andline.svg"
+ sodipodi:docbase="F:\pics">
+ <metadata
+ id="metadata39">
+ <rdf:RDF
+ id="RDF40">
+ <cc:Work
+ rdf:about=""
+ id="Work41">
+ <dc:format
+ id="format42">image/svg+xml</dc:format>
+ <dc:type
+ id="type43"
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+ <dc:title
+ id="title1">And Line</dc:title>
+ <cc:license
+ id="license2"
+ rdf:resource="http://creativecommons.org/licenses/GPL/2.0/" />
+ <dc:date
+ id="date12">2005-02-28</dc:date>
+ </cc:Work>
+ <cc:License
+ rdf:about="http://creativecommons.org/licenses/GPL/2.0/"
+ id="License3">
+ <cc:permits
+ rdf:resource="http://web.resource.org/cc/Reproduction"
+ id="permits4" />
+ <cc:permits
+ rdf:resource="http://web.resource.org/cc/Distribution"
+ id="permits5" />
+ <cc:requires
+ rdf:resource="http://web.resource.org/cc/Notice"
+ id="requires6" />
+ <cc:permits
+ rdf:resource="http://web.resource.org/cc/DerivativeWorks"
+ id="permits7" />
+ <cc:requires
+ rdf:resource="http://web.resource.org/cc/ShareAlike"
+ id="requires8" />
+ <cc:requires
+ rdf:resource="http://web.resource.org/cc/SourceCode"
+ id="requires9" />
+ </cc:License>
+ </rdf:RDF>
+ </metadata>
+ <sodipodi:namedview
+ id="base"
+ pagecolor="#ffffff"
+ bordercolor="#666666"
+ borderopacity="1.0"
+ inkscape:pageopacity="0.00000000"
+ inkscape:pageshadow="2"
+ inkscape:window-width="1035"
+ inkscape:window-height="691"
+ inkscape:zoom="23.500000"
+ inkscape:cx="11.000000"
+ inkscape:cy="11.000000"
+ inkscape:window-x="1918"
+ inkscape:window-y="129"
+ inkscape:current-layer="svg1" />
+ <defs
+ id="defs3" />
+ <g
+ transform="translate(-0.173293,-6.209109e-2)"
+ id="g11">
+ <rect
+ rx="5.0000000"
+ ry="5.0000000"
+ y="3.9911418"
+ x="1.7973769"
+ height="14.384930"
+ width="18.709280"
+ id="rect182"
+ style="fill:#e6ca25;fill-opacity:1.0000000;stroke:#908787;stroke-width:1.8478020;stroke-linecap:butt;stroke-miterlimit:4.0000000;stroke-opacity:1.0000000" />
+ <path
+ id="path183"
+ d="M 11.189410,18.008550 C 11.181540,1.5742100 11.181540,1.5742100 11.181540,1.5742100 L 11.181540,1.5742100"
+ style="fill:none;fill-opacity:0.75000000;fill-rule:evenodd;stroke:#000000;stroke-width:1.5000000;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:4.0000000;stroke-dasharray:1.5000000 4.5000000 ;stroke-dashoffset:0.00000000;stroke-opacity:1.0000000" />
+ </g>
+</svg>
diff --git a/umbrello/umbrello/pics/sources/artifact.svg b/umbrello/umbrello/pics/sources/artifact.svg
new file mode 100644
index 00000000..4f78d3c6
--- /dev/null
+++ b/umbrello/umbrello/pics/sources/artifact.svg
@@ -0,0 +1,153 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 20010904//EN"
+"http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd">
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+<svg
+ id="svg1"
+ sodipodi:version="0.32"
+ inkscape:version="0.37"
+ width="22pt"
+ height="22pt"
+ sodipodi:docbase="/home/jr/tmp/umbrello/icons/inkscape-svg"
+ sodipodi:docname="artifact.svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:xml="http://www.w3.org/XML/1998/namespace"
+ xmlns:xlink="http://www.w3.org/1999/xlink">
+ <defs
+ id="defs3">
+ <linearGradient
+ id="linearGradient1796">
+ <stop
+ style="stop-color:#ffff21;stop-opacity:0.0000000;"
+ offset="0.0000000"
+ id="stop1797" />
+ <stop
+ style="stop-color:#fff;stop-opacity:1;"
+ offset="1"
+ id="stop1798" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient1763">
+ <stop
+ style="stop-color:#ffff21;stop-opacity:0.0000000;"
+ offset="0.0000000"
+ id="stop1764" />
+ <stop
+ style="stop-color:#fff;stop-opacity:1;"
+ offset="1"
+ id="stop1765" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient830">
+ <stop
+ style="stop-color:#ebffff;stop-opacity:0.0000000;"
+ offset="0.0000000"
+ id="stop831" />
+ <stop
+ style="stop-color:#fff;stop-opacity:1;"
+ offset="1"
+ id="stop832" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient826">
+ <stop
+ style="stop-color:#000;stop-opacity:1;"
+ offset="0"
+ id="stop827" />
+ <stop
+ style="stop-color:#fff;stop-opacity:1;"
+ offset="1"
+ id="stop828" />
+ </linearGradient>
+ <linearGradient
+ xlink:href="#linearGradient830"
+ id="linearGradient829"
+ x1="1.5500000"
+ y1="0.52343750"
+ x2="0.20422535"
+ y2="-0.12195122"
+ spreadMethod="reflect" />
+ <linearGradient
+ xlink:href="#linearGradient830"
+ id="linearGradient834"
+ x1="-0.31159419"
+ y1="0.19531250"
+ x2="0.77536231"
+ y2="0.94531250" />
+ <linearGradient
+ xlink:href="#linearGradient830"
+ id="linearGradient836" />
+ <linearGradient
+ xlink:href="#linearGradient1763"
+ id="linearGradient1762"
+ x1="-0.34579438"
+ y1="-0.16406250"
+ x2="0.71962619"
+ y2="0.80468750" />
+ <linearGradient
+ xlink:href="#linearGradient1796"
+ id="linearGradient1795"
+ x1="0.65555555"
+ y1="0.88281250"
+ x2="0.48888889"
+ y2="0.53906250"
+ spreadMethod="reflect" />
+ </defs>
+ <sodipodi:namedview
+ id="base"
+ pagecolor="#ffffff"
+ bordercolor="#666666"
+ borderopacity="1.0"
+ inkscape:pageopacity="0.0"
+ inkscape:pageshadow="2"
+ inkscape:zoom="22.6274169"
+ inkscape:cx="13.4437273"
+ inkscape:cy="10.2499949"
+ inkscape:window-width="1008"
+ inkscape:window-height="693"
+ gridspacingy="1.0000000pt"
+ gridspacingx="1.0000000pt"
+ gridtolerance="1.0000000px"
+ inkscape:window-x="0"
+ inkscape:window-y="0"
+ showgrid="true"
+ snaptogrid="false" />
+ <rect
+ style="fill:url(#linearGradient829);fill-opacity:0.75000000;fill-rule:evenodd;stroke-width:0.45652742pt;"
+ id="rect825"
+ width="137.68759"
+ height="66.465706"
+ ry="0.0000000"
+ x="359.81241"
+ y="197.28429" />
+ <rect
+ style="fill:url(#linearGradient829);fill-opacity:0.75000000;fill-rule:evenodd;stroke-width:0.45652742pt;"
+ id="rect846"
+ width="135.18759"
+ height="37.082668"
+ ry="0.0000000"
+ x="316.25000"
+ y="81.250000" />
+ <rect
+ style="fill:url(#linearGradient829);fill-opacity:0.75000000;fill-rule:evenodd;stroke:none;stroke-width:0.45652742pt;stroke-opacity:1.0000000;"
+ id="rect847"
+ width="135.18759"
+ height="47.111610"
+ ry="0.0000000"
+ x="255.00000"
+ y="157.88839" />
+ <path
+ style="font-size:12;fill:#f6f600;fill-rule:evenodd;stroke-width:5;"
+ d="M 8.2733326,28.387267 L 8.2733326,124.03331 L 149.01926,124.03331 L 149.01926,81.523954 C 150.50079,49.641942 119.72304,33.000935 97.500000,28.750000 L 8.2733326,28.387267 z "
+ id="path1780"
+ sodipodi:nodetypes="cccccc"
+ transform="matrix(0.187394,0.000000,0.000000,0.275027,-0.932117,-7.199541)" />
+ <path
+ style="font-size:12;fill:url(#linearGradient1762);fill-opacity:0.75;fill-rule:evenodd;stroke:#fb0000;stroke-width:5;"
+ d="M 8.2733326,28.387267 L 93.750000,28.750000 C 108.75000,27.500000 142.73301,44.343588 101.25000,67.500000 C 127.50000,65.000000 145.00000,58.750000 148.75000,78.750000 L 149.01926,124.03331 L 8.2733326,124.03331 L 8.2733326,28.387267 z "
+ id="path1781"
+ sodipodi:nodetypes="ccccccc"
+ transform="matrix(0.187394,0.000000,0.000000,0.275027,-0.932117,-7.199541)" />
+</svg>
diff --git a/umbrello/umbrello/pics/sources/association.svg b/umbrello/umbrello/pics/sources/association.svg
new file mode 100644
index 00000000..a51cb414
--- /dev/null
+++ b/umbrello/umbrello/pics/sources/association.svg
@@ -0,0 +1,115 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 20010904//EN"
+"http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd">
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+<svg
+ id="svg1"
+ sodipodi:version="0.32"
+ inkscape:version="0.37"
+ width="22pt"
+ height="22pt"
+ sodipodi:docbase="/home/jr/tmp/umbrello/icons/inkscape-svg"
+ sodipodi:docname="association.svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:xlink="http://www.w3.org/1999/xlink">
+ <defs
+ id="defs3">
+ <linearGradient
+ id="linearGradient868">
+ <stop
+ style="stop-color:#ff0000;stop-opacity:1.0000000;"
+ offset="0.0000000"
+ id="stop869" />
+ <stop
+ style="stop-color:#fff;stop-opacity:1;"
+ offset="1"
+ id="stop870" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient893">
+ <stop
+ style="stop-color:#19839a;stop-opacity:0.0000000;"
+ offset="0.0000000"
+ id="stop894" />
+ <stop
+ style="stop-color:#fff;stop-opacity:1;"
+ offset="1"
+ id="stop895" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient830">
+ <stop
+ style="stop-color:#ebffff;stop-opacity:0.0000000;"
+ offset="0.0000000"
+ id="stop831" />
+ <stop
+ style="stop-color:#fff;stop-opacity:1;"
+ offset="1"
+ id="stop832" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient826">
+ <stop
+ style="stop-color:#000;stop-opacity:1;"
+ offset="0"
+ id="stop827" />
+ <stop
+ style="stop-color:#fff;stop-opacity:1;"
+ offset="1"
+ id="stop828" />
+ </linearGradient>
+ <linearGradient
+ xlink:href="#linearGradient830"
+ id="linearGradient829"
+ x1="1.5500000"
+ y1="0.52343750"
+ x2="0.20422535"
+ y2="-0.12195122"
+ spreadMethod="reflect" />
+ <linearGradient
+ xlink:href="#linearGradient830"
+ id="linearGradient834"
+ x1="-0.31159419"
+ y1="0.19531250"
+ x2="0.77536231"
+ y2="0.94531250" />
+ <linearGradient
+ xlink:href="#linearGradient830"
+ id="linearGradient836" />
+ <linearGradient
+ xlink:href="#linearGradient868"
+ id="linearGradient892"
+ x1="0.096153848"
+ y1="0.60000002"
+ x2="0.14743590"
+ y2="0.67741936"
+ spreadMethod="reflect" />
+ </defs>
+ <sodipodi:namedview
+ id="base"
+ pagecolor="#ffffff"
+ bordercolor="#666666"
+ borderopacity="1.0"
+ inkscape:pageopacity="0.0"
+ inkscape:pageshadow="2"
+ inkscape:zoom="22.6274170"
+ inkscape:cx="14.4343441"
+ inkscape:cy="11.6181504"
+ inkscape:window-width="1016"
+ inkscape:window-height="693"
+ gridspacingy="1.0000000pt"
+ gridspacingx="1.0000000pt"
+ gridtolerance="1.0000000px"
+ inkscape:window-x="0"
+ inkscape:window-y="0"
+ showgrid="true" />
+ <rect
+ style="font-size:12;fill:#ff0000;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1pt;"
+ id="rect737"
+ width="2.48592234"
+ height="27.40038872"
+ x="12.54009754"
+ y="0.09961223" />
+</svg>
diff --git a/umbrello/umbrello/pics/sources/asynchro.svg b/umbrello/umbrello/pics/sources/asynchro.svg
new file mode 100644
index 00000000..7bb8054e
--- /dev/null
+++ b/umbrello/umbrello/pics/sources/asynchro.svg
@@ -0,0 +1,133 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 20010904//EN"
+"http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd">
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+<svg
+ id="svg1"
+ sodipodi:version="0.32"
+ inkscape:version="0.37"
+ width="22pt"
+ height="22pt"
+ sodipodi:docbase="/home/jr/tmp/umbrello/icons/inkscape-svg"
+ sodipodi:docname="asynchro.svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:xml="http://www.w3.org/XML/1998/namespace"
+ xmlns:xlink="http://www.w3.org/1999/xlink">
+ <defs
+ id="defs3">
+ <linearGradient
+ id="linearGradient868">
+ <stop
+ style="stop-color:#ffffff;stop-opacity:0.0000000;"
+ offset="0.0000000"
+ id="stop869" />
+ <stop
+ style="stop-color:#fff;stop-opacity:1;"
+ offset="1"
+ id="stop870" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient893">
+ <stop
+ style="stop-color:#19839a;stop-opacity:0.0000000;"
+ offset="0.0000000"
+ id="stop894" />
+ <stop
+ style="stop-color:#fff;stop-opacity:1;"
+ offset="1"
+ id="stop895" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient830">
+ <stop
+ style="stop-color:#ebffff;stop-opacity:0.0000000;"
+ offset="0.0000000"
+ id="stop831" />
+ <stop
+ style="stop-color:#fff;stop-opacity:1;"
+ offset="1"
+ id="stop832" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient826">
+ <stop
+ style="stop-color:#000;stop-opacity:1;"
+ offset="0"
+ id="stop827" />
+ <stop
+ style="stop-color:#fff;stop-opacity:1;"
+ offset="1"
+ id="stop828" />
+ </linearGradient>
+ <linearGradient
+ xlink:href="#linearGradient830"
+ id="linearGradient829"
+ x1="1.5500000"
+ y1="0.52343750"
+ x2="0.20422535"
+ y2="-0.12195122"
+ spreadMethod="reflect" />
+ <linearGradient
+ xlink:href="#linearGradient830"
+ id="linearGradient834"
+ x1="-0.31159419"
+ y1="0.19531250"
+ x2="0.77536231"
+ y2="0.94531250" />
+ <linearGradient
+ xlink:href="#linearGradient830"
+ id="linearGradient836" />
+ <linearGradient
+ xlink:href="#linearGradient868"
+ id="linearGradient892"
+ x1="-0.49264705"
+ y1="0.43750000"
+ x2="0.022058824"
+ y2="0.92187500" />
+ </defs>
+ <sodipodi:namedview
+ id="base"
+ pagecolor="#ffffff"
+ bordercolor="#666666"
+ borderopacity="1.0"
+ inkscape:pageopacity="0.0"
+ inkscape:pageshadow="2"
+ inkscape:zoom="22.6274169"
+ inkscape:cx="12.5595019"
+ inkscape:cy="9.96780389"
+ inkscape:window-width="1016"
+ inkscape:window-height="693"
+ gridspacingy="1.0000000pt"
+ gridspacingx="1.0000000pt"
+ gridtolerance="1.0000000px"
+ inkscape:window-x="0"
+ inkscape:window-y="0"
+ showgrid="true" />
+ <path
+ style="font-size:12;fill:url(#linearGradient892);fill-rule:evenodd;stroke-width:12.5;"
+ d="M 23.25456 20.532266 L 17.245615 18.773952 L 17.395532 22.409137 L 23.25456 20.532266 z "
+ id="path875"
+ sodipodi:nodetypes="cccc" />
+ <text
+ xml:space="preserve"
+ style="font-size:12;font-weight:normal;stroke-width:1pt;font-family:Bitstream Vera Sans;"
+ x="-0.14150786"
+ y="14.0554683"
+ id="text1033"
+ transform="scale(1.409838,1.034795)"><tspan
+ id="tspan1034">f(x)</tspan></text>
+ <rect
+ style="font-size:12;fill:#ff0000;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1pt;"
+ id="rect923"
+ width="16.51757205"
+ height="1.32582528"
+ x="-0.05524272"
+ y="20.04223250" />
+ <path
+ style="font-size:12;fill:#ffff00;fill-rule:evenodd;stroke:#ff0000;stroke-width:1.14332;"
+ d="M 25.48674 20.457131 L 16.806844 18.331919 L 16.858498 23.071545 L 25.48674 20.457131 z "
+ id="path874"
+ sodipodi:nodetypes="cccc" />
+</svg>
diff --git a/umbrello/umbrello/pics/sources/box.svg b/umbrello/umbrello/pics/sources/box.svg
new file mode 100644
index 00000000..9fd9bebd
--- /dev/null
+++ b/umbrello/umbrello/pics/sources/box.svg
@@ -0,0 +1,85 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 20010904//EN"
+"http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd">
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+<svg
+ id="svg1"
+ sodipodi:version="0.32"
+ inkscape:version="0.37"
+ width="22pt"
+ height="22pt"
+ sodipodi:docbase="/home/jr/tmp/umbrello/icons/inkscape-svg"
+ sodipodi:docname="box.svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:xlink="http://www.w3.org/1999/xlink">
+ <defs
+ id="defs3">
+ <linearGradient
+ id="linearGradient830">
+ <stop
+ style="stop-color:#ebffff;stop-opacity:0.0000000;"
+ offset="0.0000000"
+ id="stop831" />
+ <stop
+ style="stop-color:#fff;stop-opacity:1;"
+ offset="1"
+ id="stop832" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient826">
+ <stop
+ style="stop-color:#000;stop-opacity:1;"
+ offset="0"
+ id="stop827" />
+ <stop
+ style="stop-color:#fff;stop-opacity:1;"
+ offset="1"
+ id="stop828" />
+ </linearGradient>
+ <linearGradient
+ xlink:href="#linearGradient830"
+ id="linearGradient829"
+ x1="1.5500000"
+ y1="0.52343750"
+ x2="0.20422535"
+ y2="-0.12195122"
+ spreadMethod="reflect" />
+ <linearGradient
+ xlink:href="#linearGradient830"
+ id="linearGradient834"
+ x1="-0.31159419"
+ y1="0.19531250"
+ x2="0.77536231"
+ y2="0.94531250" />
+ <linearGradient
+ xlink:href="#linearGradient830"
+ id="linearGradient836" />
+ </defs>
+ <sodipodi:namedview
+ id="base"
+ pagecolor="#ffffff"
+ bordercolor="#666666"
+ borderopacity="1.0"
+ inkscape:pageopacity="0.0"
+ inkscape:pageshadow="2"
+ inkscape:zoom="22.6274170"
+ inkscape:cx="13.3508714"
+ inkscape:cy="11.0070359"
+ inkscape:window-width="1016"
+ inkscape:window-height="693"
+ gridspacingy="1.0000000pt"
+ gridspacingx="1.0000000pt"
+ gridtolerance="1.0000000px"
+ inkscape:window-x="0"
+ inkscape:window-y="0"
+ showgrid="true" />
+ <rect
+ style="font-size:12;fill:none;fill-rule:evenodd;stroke:#ff0000;stroke-width:1.22432;"
+ id="rect837"
+ width="23.71333344"
+ height="23.69648009"
+ x="1.95820236"
+ y="1.89102376" />
+</svg>
diff --git a/umbrello/umbrello/pics/sources/branch.svg b/umbrello/umbrello/pics/sources/branch.svg
new file mode 100644
index 00000000..939c12dc
--- /dev/null
+++ b/umbrello/umbrello/pics/sources/branch.svg
@@ -0,0 +1,128 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 20010904//EN"
+"http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd">
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+<svg
+ id="svg1"
+ sodipodi:version="0.32"
+ inkscape:version="0.38.1"
+ width="128.00000pt"
+ height="128.00000pt"
+ sodipodi:docbase="/home/bartkozoltan/Documents/work/umbrello/new pics"
+ sodipodi:docname="branch_merge.svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:xlink="http://www.w3.org/1999/xlink">
+ <defs
+ id="defs3">
+ <linearGradient
+ id="linearGradient868">
+ <stop
+ style="stop-color:#ffffff;stop-opacity:0.0000000;"
+ offset="0.0000000"
+ id="stop869" />
+ <stop
+ style="stop-color:#fff;stop-opacity:1;"
+ offset="1"
+ id="stop870" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient893">
+ <stop
+ style="stop-color:#19839a;stop-opacity:0.0000000;"
+ offset="0.0000000"
+ id="stop894" />
+ <stop
+ style="stop-color:#fff;stop-opacity:1;"
+ offset="1"
+ id="stop895" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient830">
+ <stop
+ style="stop-color:#ebffff;stop-opacity:0.0000000;"
+ offset="0.0000000"
+ id="stop831" />
+ <stop
+ style="stop-color:#fff;stop-opacity:1;"
+ offset="1"
+ id="stop832" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient826">
+ <stop
+ style="stop-color:#000;stop-opacity:1;"
+ offset="0"
+ id="stop827" />
+ <stop
+ style="stop-color:#fff;stop-opacity:1;"
+ offset="1"
+ id="stop828" />
+ </linearGradient>
+ <linearGradient
+ xlink:href="#linearGradient830"
+ id="linearGradient829"
+ x1="1.5500000"
+ y1="0.52343750"
+ x2="0.20422535"
+ y2="-0.12195122"
+ spreadMethod="reflect" />
+ <linearGradient
+ xlink:href="#linearGradient830"
+ id="linearGradient834"
+ x1="-0.31159419"
+ y1="0.19531250"
+ x2="0.77536231"
+ y2="0.94531250" />
+ <linearGradient
+ xlink:href="#linearGradient830"
+ id="linearGradient836" />
+ <linearGradient
+ xlink:href="#linearGradient868"
+ id="linearGradient892"
+ x1="0.39932632"
+ y1="0.50707734"
+ x2="0.64623892"
+ y2="0.60370040"
+ spreadMethod="reflect" />
+ </defs>
+ <sodipodi:namedview
+ id="base"
+ pagecolor="#ffffff"
+ bordercolor="#666666"
+ borderopacity="1.0"
+ inkscape:pageopacity="0.0"
+ inkscape:pageshadow="2"
+ inkscape:zoom="4.0000000"
+ inkscape:cx="79.132812"
+ inkscape:cy="69.358765"
+ inkscape:window-width="1022"
+ inkscape:window-height="701"
+ gridspacingy="1.0000000pt"
+ gridspacingx="1.0000000pt"
+ gridtolerance="1.0000000px"
+ inkscape:window-x="0"
+ inkscape:window-y="0" />
+ <g
+ id="g900"
+ transform="matrix(1.033419,0.000000,0.000000,1.028243,-0.413036,-0.304948)">
+ <rect
+ style="fill:#ffff00;fill-rule:evenodd;stroke:#ff0000;stroke-width:6.0940815;stroke-dasharray:none;"
+ id="rect854"
+ width="41.480559"
+ height="40.741544"
+ x="74.760017"
+ y="-59.764663"
+ transform="matrix(1.438607,1.462473,-1.437488,1.463230,-116.1987,-4.837583)" />
+ <rect
+ style="fill:url(#linearGradient892);fill-rule:evenodd;stroke-width:11.052127;"
+ id="rect855"
+ width="72.749743"
+ height="71.403139"
+ x="72.801592"
+ y="-35.372109"
+ transform="matrix(0.710624,0.703572,-0.699330,0.714799,0.000000,0.000000)"
+ ry="0.0000000" />
+ </g>
+</svg>
diff --git a/umbrello/umbrello/pics/sources/choice-rhomb.svg b/umbrello/umbrello/pics/sources/choice-rhomb.svg
new file mode 100644
index 00000000..9f3014f8
--- /dev/null
+++ b/umbrello/umbrello/pics/sources/choice-rhomb.svg
@@ -0,0 +1,160 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+<svg
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://web.resource.org/cc/"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:sodipodi="http://inkscape.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ id="svg1"
+ height="22.000000px"
+ width="22.000000px"
+ y="0.00000000"
+ x="0.00000000"
+ version="1.0"
+ sodipodi:version="0.32"
+ inkscape:version="0.40+cvs"
+ sodipodi:docname="choice-rhomb.svg"
+ sodipodi:docbase="F:\pics">
+ <metadata
+ id="metadata17">
+ <rdf:RDF
+ id="RDF18">
+ <cc:Work
+ rdf:about=""
+ id="Work19">
+ <dc:format
+ id="format20">image/svg+xml</dc:format>
+ <dc:type
+ id="type21"
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+ </cc:Work>
+ </rdf:RDF>
+ </metadata>
+ <sodipodi:namedview
+ id="base"
+ pagecolor="#ffffff"
+ bordercolor="#666666"
+ borderopacity="1.0"
+ inkscape:pageopacity="0.00000000"
+ inkscape:pageshadow="2"
+ inkscape:window-width="1012"
+ inkscape:window-height="579"
+ inkscape:zoom="14.727273"
+ inkscape:cx="13.750000"
+ inkscape:cy="13.750000"
+ inkscape:window-x="1811"
+ inkscape:window-y="299"
+ inkscape:current-layer="svg1" />
+ <defs
+ id="defs3">
+ <marker
+ style="overflow:visible;"
+ id="marker1"
+ refX="0.0"
+ refY="0.0"
+ orient="auto"
+ inkscape:stockid="Arrow2Mend">
+ <path
+ transform="scale(0.6) rotate(180) translate(-5,0)"
+ d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.9730900,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z "
+ style="font-size:12.0;fill-rule:evenodd;stroke-width:0.62500000;stroke-linejoin:round;"
+ id="path2"
+ sodipodi:nodetypes="cccc" />
+ </marker>
+ <marker
+ style="overflow:visible;"
+ id="Arrow2Mend"
+ refX="0.0"
+ refY="0.0"
+ orient="auto"
+ inkscape:stockid="Arrow2Mend">
+ <path
+ transform="scale(0.6) rotate(180) translate(-5,0)"
+ d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.9730900,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z "
+ style="font-size:12.0;fill-rule:evenodd;stroke-width:0.62500000;stroke-linejoin:round;"
+ id="path237"
+ sodipodi:nodetypes="cccc" />
+ </marker>
+ <marker
+ style="overflow:visible;"
+ id="marker258"
+ refX="0.0"
+ refY="0.0"
+ orient="auto"
+ inkscape:stockid="Arrow2Lend">
+ <path
+ transform="scale(1.1) rotate(180) translate(-5,0)"
+ d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.9730900,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z "
+ style="font-size:12.0;fill-rule:evenodd;stroke-width:0.62500000;stroke-linejoin:round;"
+ id="path259"
+ sodipodi:nodetypes="cccc" />
+ </marker>
+ <marker
+ style="overflow:visible;"
+ id="marker255"
+ refX="0.0"
+ refY="0.0"
+ orient="auto"
+ inkscape:stockid="Arrow2Lend">
+ <path
+ transform="scale(1.1) rotate(180) translate(-5,0)"
+ d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.9730900,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z "
+ style="font-size:12.0;fill-rule:evenodd;stroke-width:0.62500000;stroke-linejoin:round;"
+ id="path256"
+ sodipodi:nodetypes="cccc" />
+ </marker>
+ <marker
+ style="overflow:visible;"
+ id="marker252"
+ refX="0.0"
+ refY="0.0"
+ orient="auto"
+ inkscape:stockid="Arrow2Lend">
+ <path
+ transform="scale(1.1) rotate(180) translate(-5,0)"
+ d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.9730900,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z "
+ style="font-size:12.0;fill-rule:evenodd;stroke-width:0.62500000;stroke-linejoin:round;"
+ id="path253"
+ sodipodi:nodetypes="cccc" />
+ </marker>
+ <marker
+ style="overflow:visible;"
+ id="marker249"
+ refX="0.0"
+ refY="0.0"
+ orient="auto"
+ inkscape:stockid="Arrow2Lend">
+ <path
+ transform="scale(1.1) rotate(180) translate(-5,0)"
+ d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.9730900,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z "
+ style="font-size:12.0;fill-rule:evenodd;stroke-width:0.62500000;stroke-linejoin:round;"
+ id="path250"
+ sodipodi:nodetypes="cccc" />
+ </marker>
+ <marker
+ style="overflow:visible;"
+ id="Arrow2Lend"
+ refX="0.0"
+ refY="0.0"
+ orient="auto"
+ inkscape:stockid="Arrow2Lend">
+ <path
+ transform="scale(1.1) rotate(180) translate(-5,0)"
+ d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.9730900,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z "
+ style="font-size:12.0;fill-rule:evenodd;stroke-width:0.62500000;stroke-linejoin:round;"
+ id="path238"
+ sodipodi:nodetypes="cccc" />
+ </marker>
+ </defs>
+ <rect
+ style="fill:#00f5c5;fill-opacity:1.0000000;stroke:#000000;stroke-width:1.6613264;stroke-linecap:butt;stroke-miterlimit:4.0000000;stroke-dashoffset:0.00000000;stroke-opacity:1.0000000"
+ id="rect1"
+ width="12.072264"
+ height="12.027812"
+ x="9.4153738"
+ y="-5.0952759"
+ transform="matrix(0.746765,0.665088,-0.737169,0.675708,0.000000,0.000000)" />
+</svg>
diff --git a/umbrello/umbrello/pics/sources/choice-round.svg b/umbrello/umbrello/pics/sources/choice-round.svg
new file mode 100644
index 00000000..ecb862e1
--- /dev/null
+++ b/umbrello/umbrello/pics/sources/choice-round.svg
@@ -0,0 +1,178 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+<svg
+ xmlns:xml="http://www.w3.org/XML/1998/namespace"
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://web.resource.org/cc/"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:sodipodi="http://inkscape.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ sodipodi:docbase="F:\pics"
+ sodipodi:docname="choice-round.svg"
+ inkscape:version="0.40+cvs"
+ sodipodi:version="0.32"
+ version="1.0"
+ x="0.00000000"
+ y="0.00000000"
+ width="22.000000px"
+ height="22.000000px"
+ id="svg1">
+ <metadata
+ id="metadata17">
+ <rdf:RDF
+ id="RDF18">
+ <cc:Work
+ id="Work19"
+ rdf:about="">
+ <dc:format
+ id="format20">image/svg+xml</dc:format>
+ <dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage"
+ id="type21" />
+ </cc:Work>
+ </rdf:RDF>
+ </metadata>
+ <sodipodi:namedview
+ inkscape:current-layer="svg1"
+ inkscape:window-y="299"
+ inkscape:window-x="1811"
+ inkscape:cy="11.000000"
+ inkscape:cx="11.000000"
+ inkscape:zoom="18.409091"
+ inkscape:window-height="579"
+ inkscape:window-width="692"
+ inkscape:pageshadow="2"
+ inkscape:pageopacity="0.0"
+ borderopacity="1.0"
+ bordercolor="#666666"
+ pagecolor="#ffffff"
+ id="base" />
+ <defs
+ id="defs3">
+ <marker
+ inkscape:stockid="Arrow2Mend"
+ orient="auto"
+ refY="0.0"
+ refX="0.0"
+ id="marker1"
+ style="overflow:visible;">
+ <path
+ sodipodi:nodetypes="cccc"
+ id="path2"
+ style="font-size:12.0;fill-rule:evenodd;stroke-width:0.62500000;stroke-linejoin:round;"
+ d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.9730900,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z "
+ transform="scale(0.6) rotate(180) translate(-5,0)" />
+ </marker>
+ <marker
+ inkscape:stockid="Arrow2Mend"
+ orient="auto"
+ refY="0.0"
+ refX="0.0"
+ id="Arrow2Mend"
+ style="overflow:visible;">
+ <path
+ sodipodi:nodetypes="cccc"
+ id="path237"
+ style="font-size:12.0;fill-rule:evenodd;stroke-width:0.62500000;stroke-linejoin:round;"
+ d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.9730900,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z "
+ transform="scale(0.6) rotate(180) translate(-5,0)" />
+ </marker>
+ <marker
+ inkscape:stockid="Arrow2Lend"
+ orient="auto"
+ refY="0.0"
+ refX="0.0"
+ id="marker258"
+ style="overflow:visible;">
+ <path
+ sodipodi:nodetypes="cccc"
+ id="path259"
+ style="font-size:12.0;fill-rule:evenodd;stroke-width:0.62500000;stroke-linejoin:round;"
+ d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.9730900,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z "
+ transform="scale(1.1) rotate(180) translate(-5,0)" />
+ </marker>
+ <marker
+ inkscape:stockid="Arrow2Lend"
+ orient="auto"
+ refY="0.0"
+ refX="0.0"
+ id="marker255"
+ style="overflow:visible;">
+ <path
+ sodipodi:nodetypes="cccc"
+ id="path256"
+ style="font-size:12.0;fill-rule:evenodd;stroke-width:0.62500000;stroke-linejoin:round;"
+ d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.9730900,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z "
+ transform="scale(1.1) rotate(180) translate(-5,0)" />
+ </marker>
+ <marker
+ inkscape:stockid="Arrow2Lend"
+ orient="auto"
+ refY="0.0"
+ refX="0.0"
+ id="marker252"
+ style="overflow:visible;">
+ <path
+ sodipodi:nodetypes="cccc"
+ id="path253"
+ style="font-size:12.0;fill-rule:evenodd;stroke-width:0.62500000;stroke-linejoin:round;"
+ d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.9730900,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z "
+ transform="scale(1.1) rotate(180) translate(-5,0)" />
+ </marker>
+ <marker
+ inkscape:stockid="Arrow2Lend"
+ orient="auto"
+ refY="0.0"
+ refX="0.0"
+ id="marker249"
+ style="overflow:visible;">
+ <path
+ sodipodi:nodetypes="cccc"
+ id="path250"
+ style="font-size:12.0;fill-rule:evenodd;stroke-width:0.62500000;stroke-linejoin:round;"
+ d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.9730900,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z "
+ transform="scale(1.1) rotate(180) translate(-5,0)" />
+ </marker>
+ <marker
+ inkscape:stockid="Arrow2Lend"
+ orient="auto"
+ refY="0.0"
+ refX="0.0"
+ id="Arrow2Lend"
+ style="overflow:visible;">
+ <path
+ sodipodi:nodetypes="cccc"
+ id="path238"
+ style="font-size:12.0;fill-rule:evenodd;stroke-width:0.62500000;stroke-linejoin:round;"
+ d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.9730900,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z "
+ transform="scale(1.1) rotate(180) translate(-5,0)" />
+ </marker>
+ </defs>
+ <g
+ transform="translate(-383.3103,-518.6704)"
+ id="g190">
+ <path
+ transform="matrix(2.612069,0.000000,0.000000,2.612069,-637.8584,-857.8712)"
+ d="M 398.73051 531.23523 A 3.5248239 3.5248239 0 1 1 391.68086,531.23523 A 3.5248239 3.5248239 0 1 1 398.73051 531.23523 z"
+ sodipodi:ry="3.5248239"
+ sodipodi:rx="3.5248239"
+ sodipodi:cy="531.23523"
+ sodipodi:cx="395.20569"
+ id="path45"
+ style="fill:#00f5c5;fill-opacity:1.0000000;stroke:#000000;stroke-width:0.77524751;stroke-miterlimit:4.0000000;stroke-opacity:1.0000000"
+ sodipodi:type="arc" />
+ <text
+ sodipodi:linespacing="100%"
+ id="text179"
+ y="534.39539"
+ x="388.94608"
+ style="font-size:13.000000;font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;fill:#000000;fill-opacity:1.0000000;stroke:none;stroke-width:1.0000000px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1.0000000;font-family:Arial;text-anchor:start;writing-mode:lr-tb"
+ xml:space="preserve"><tspan
+ y="534.39539"
+ x="388.94608"
+ id="tspan180"
+ sodipodi:role="line">C</tspan></text>
+ </g>
+</svg>
diff --git a/umbrello/umbrello/pics/sources/class.svg b/umbrello/umbrello/pics/sources/class.svg
new file mode 100644
index 00000000..03124a31
--- /dev/null
+++ b/umbrello/umbrello/pics/sources/class.svg
@@ -0,0 +1,131 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 20010904//EN"
+"http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd">
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+<svg
+ id="svg1"
+ sodipodi:version="0.32"
+ inkscape:version="0.37"
+ width="22pt"
+ height="22pt"
+ sodipodi:docbase="/home/jr/tmp/umbrello/icons/inkscape-svg"
+ sodipodi:docname="class.svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:xml="http://www.w3.org/XML/1998/namespace"
+ xmlns:xlink="http://www.w3.org/1999/xlink">
+ <defs
+ id="defs3">
+ <linearGradient
+ id="linearGradient830">
+ <stop
+ style="stop-color:#ebffff;stop-opacity:0.0000000;"
+ offset="0.0000000"
+ id="stop831" />
+ <stop
+ style="stop-color:#fff;stop-opacity:1;"
+ offset="1"
+ id="stop832" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient826">
+ <stop
+ style="stop-color:#000;stop-opacity:1;"
+ offset="0"
+ id="stop827" />
+ <stop
+ style="stop-color:#fff;stop-opacity:1;"
+ offset="1"
+ id="stop828" />
+ </linearGradient>
+ <linearGradient
+ xlink:href="#linearGradient830"
+ id="linearGradient829"
+ x1="1.5500000"
+ y1="0.52343750"
+ x2="0.20422535"
+ y2="-0.12195122"
+ spreadMethod="reflect" />
+ <linearGradient
+ xlink:href="#linearGradient830"
+ id="linearGradient834"
+ x1="-0.31159419"
+ y1="0.19531250"
+ x2="0.77536231"
+ y2="0.94531250" />
+ <linearGradient
+ xlink:href="#linearGradient830"
+ id="linearGradient836" />
+ </defs>
+ <sodipodi:namedview
+ id="base"
+ pagecolor="#ffffff"
+ bordercolor="#666666"
+ borderopacity="1.0"
+ inkscape:pageopacity="0.0"
+ inkscape:pageshadow="2"
+ inkscape:zoom="17.1043724"
+ inkscape:cx="12.2503213"
+ inkscape:cy="6.66230400"
+ inkscape:window-width="1016"
+ inkscape:window-height="693"
+ gridspacingy="1.0000000pt"
+ gridspacingx="1.0000000pt"
+ gridtolerance="1.0000000px"
+ inkscape:window-x="0"
+ inkscape:window-y="0"
+ snaptogrid="false"
+ showgrid="true" />
+ <g
+ id="g615">
+ <rect
+ style="font-size:12;fill:#ffff00;fill-rule:evenodd;stroke:#ff0000;stroke-width:1.23963;"
+ id="rect837"
+ width="26.24992934"
+ height="26.18856802"
+ x="0.66534913"
+ y="0.71917963" />
+ <rect
+ style="font-size:12;fill:url(#linearGradient829);fill-opacity:0.75;fill-rule:evenodd;stroke-width:0.456527pt;"
+ id="rect825"
+ width="24.99192419"
+ height="7.33014917"
+ ry="0"
+ x="1.21161342"
+ y="1.36787295" />
+ <text
+ xml:space="preserve"
+ style="font-size:12;font-weight:normal;stroke-width:1pt;font-family:Bitstream Vera Sans;"
+ x="2.59171310"
+ y="11.3147535"
+ id="text838"
+ transform="scale(0.933669,0.722645)"><tspan
+ id="tspan839">ABC</tspan></text>
+ <path
+ style="font-size:12;fill:none;fill-opacity:0.75;fill-rule:evenodd;stroke:#ff0000;stroke-width:1.25;"
+ d="M 1.1533278 9.3908034 L 26.731652 9.3908034 "
+ id="path842" />
+ <path
+ style="font-size:12;fill:none;fill-opacity:0.75;fill-rule:evenodd;stroke:#ff0000;stroke-width:6.51621;stroke-dasharray:none;"
+ d="M 12.845456,96.712602 L 148.81938,96.712602"
+ id="path845"
+ transform="matrix(0.188112,0.000000,0.000000,0.195620,-1.468156,-1.975509)" />
+ <rect
+ style="font-size:12;fill:url(#linearGradient829);fill-opacity:0.75;fill-rule:evenodd;stroke-width:0.456527pt;"
+ id="rect846"
+ width="24.77268353"
+ height="6.20569849"
+ ry="0"
+ x="1.26971898"
+ y="10.02771664" />
+ <rect
+ style="font-size:12;fill:url(#linearGradient829);fill-opacity:0.75;fill-rule:evenodd;stroke-width:0.456527pt;"
+ id="rect847"
+ width="24.99192296"
+ height="8.63132715"
+ ry="0"
+ x="1.31451130"
+ y="17.58032418" />
+ </g>
+</svg>
diff --git a/umbrello/umbrello/pics/sources/component.svg b/umbrello/umbrello/pics/sources/component.svg
new file mode 100644
index 00000000..514cc765
--- /dev/null
+++ b/umbrello/umbrello/pics/sources/component.svg
@@ -0,0 +1,123 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 20010904//EN"
+"http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd">
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+<svg
+ id="svg1"
+ sodipodi:version="0.32"
+ inkscape:version="0.38.1"
+ width="128.00000pt"
+ height="128.00000pt"
+ sodipodi:docbase="/home/bartkozoltan/Documents/work/umbrello/new pics"
+ sodipodi:docname="component.svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:xml="http://www.w3.org/XML/1998/namespace"
+ xmlns:xlink="http://www.w3.org/1999/xlink">
+ <defs
+ id="defs3">
+ <linearGradient
+ id="linearGradient830">
+ <stop
+ style="stop-color:#ebffff;stop-opacity:0.0000000;"
+ offset="0.0000000"
+ id="stop831" />
+ <stop
+ style="stop-color:#fff;stop-opacity:1;"
+ offset="1"
+ id="stop832" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient826">
+ <stop
+ style="stop-color:#000;stop-opacity:1;"
+ offset="0"
+ id="stop827" />
+ <stop
+ style="stop-color:#fff;stop-opacity:1;"
+ offset="1"
+ id="stop828" />
+ </linearGradient>
+ <linearGradient
+ xlink:href="#linearGradient830"
+ id="linearGradient829"
+ x1="1.5500000"
+ y1="0.52343750"
+ x2="0.20422535"
+ y2="-0.12195122"
+ spreadMethod="reflect" />
+ <linearGradient
+ xlink:href="#linearGradient830"
+ id="linearGradient834"
+ x1="-0.31159419"
+ y1="0.19531250"
+ x2="0.77536231"
+ y2="0.94531250" />
+ <linearGradient
+ xlink:href="#linearGradient830"
+ id="linearGradient836" />
+ </defs>
+ <sodipodi:namedview
+ id="base"
+ pagecolor="#ffffff"
+ bordercolor="#666666"
+ borderopacity="1.0"
+ inkscape:pageopacity="0.0"
+ inkscape:pageshadow="2"
+ inkscape:zoom="4.0000000"
+ inkscape:cx="63.313473"
+ inkscape:cy="66.872360"
+ inkscape:window-width="1022"
+ inkscape:window-height="701"
+ gridspacingy="1.0000000pt"
+ gridspacingx="1.0000000pt"
+ gridtolerance="1.0000000px"
+ inkscape:window-x="0"
+ inkscape:window-y="0" />
+ <rect
+ style="fill:#ffff00;fill-rule:evenodd;stroke:#ff0000;stroke-width:7.5000000;stroke-dasharray:none;"
+ id="rect837"
+ width="117.17106"
+ height="134.99545"
+ x="33.896471"
+ y="12.776533" />
+ <rect
+ style="fill:url(#linearGradient829);fill-opacity:0.75000000;fill-rule:evenodd;stroke:none;stroke-width:0.45652742pt;stroke-opacity:1.0000000;"
+ id="rect825"
+ width="108.93759"
+ height="127.71573"
+ ry="0.0000000"
+ x="38.080124"
+ y="16.221853" />
+ <rect
+ style="fill:#ffff00;fill-rule:evenodd;stroke:#ff0000;stroke-width:5.0000000;stroke-dasharray:none;"
+ id="rect849"
+ width="48.366001"
+ height="19.281309"
+ x="7.6920013"
+ y="46.921844" />
+ <rect
+ style="fill:url(#linearGradient829);fill-opacity:0.75000000;fill-rule:evenodd;stroke:none;stroke-width:0.45652742pt;stroke-opacity:1.0000000;"
+ id="rect850"
+ width="40.187591"
+ height="14.590707"
+ ry="0.0000000"
+ x="10.218712"
+ y="48.954636" />
+ <rect
+ style="fill:#ffff00;fill-rule:evenodd;stroke:#ff0000;stroke-width:5.0000000;stroke-dasharray:none;"
+ id="rect851"
+ width="48.366001"
+ height="19.281309"
+ x="8.0044994"
+ y="95.984344" />
+ <rect
+ style="fill:url(#linearGradient829);fill-opacity:0.75000000;fill-rule:evenodd;stroke:none;stroke-width:0.45652742pt;stroke-opacity:1.0000000;"
+ id="rect852"
+ width="40.187592"
+ height="14.590707"
+ ry="0.0000000"
+ x="10.531210"
+ y="98.017136" />
+</svg>
diff --git a/umbrello/umbrello/pics/sources/composition.svg b/umbrello/umbrello/pics/sources/composition.svg
new file mode 100644
index 00000000..04bec885
--- /dev/null
+++ b/umbrello/umbrello/pics/sources/composition.svg
@@ -0,0 +1,128 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 20010904//EN"
+"http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd">
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+<svg
+ id="svg1"
+ sodipodi:version="0.32"
+ inkscape:version="0.38.1"
+ width="128.00000pt"
+ height="128.00000pt"
+ sodipodi:docbase="/home/bartkozoltan/Documents/work/umbrello/new pics"
+ sodipodi:docname="composition.svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:xlink="http://www.w3.org/1999/xlink">
+ <defs
+ id="defs3">
+ <linearGradient
+ id="linearGradient868">
+ <stop
+ style="stop-color:#ffffff;stop-opacity:0.0000000;"
+ offset="0.0000000"
+ id="stop869" />
+ <stop
+ style="stop-color:#fff;stop-opacity:1;"
+ offset="1"
+ id="stop870" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient893">
+ <stop
+ style="stop-color:#19839a;stop-opacity:0.0000000;"
+ offset="0.0000000"
+ id="stop894" />
+ <stop
+ style="stop-color:#fff;stop-opacity:1;"
+ offset="1"
+ id="stop895" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient830">
+ <stop
+ style="stop-color:#ffffff;stop-opacity:0.0000000;"
+ offset="0.0000000"
+ id="stop831" />
+ <stop
+ style="stop-color:#fff;stop-opacity:1;"
+ offset="1"
+ id="stop832" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient826">
+ <stop
+ style="stop-color:#000;stop-opacity:1;"
+ offset="0"
+ id="stop827" />
+ <stop
+ style="stop-color:#fff;stop-opacity:1;"
+ offset="1"
+ id="stop828" />
+ </linearGradient>
+ <linearGradient
+ xlink:href="#linearGradient830"
+ id="linearGradient829"
+ x1="1.5500000"
+ y1="0.52343750"
+ x2="0.20422535"
+ y2="-0.12195122"
+ spreadMethod="reflect" />
+ <linearGradient
+ xlink:href="#linearGradient830"
+ id="linearGradient834"
+ x1="-0.31159419"
+ y1="0.19531250"
+ x2="0.77536231"
+ y2="0.94531250" />
+ <linearGradient
+ xlink:href="#linearGradient830"
+ id="linearGradient836" />
+ <linearGradient
+ xlink:href="#linearGradient830"
+ id="linearGradient892"
+ x1="1.7810326"
+ y1="-0.77207518"
+ x2="-0.77287894"
+ y2="1.0071716"
+ spreadMethod="pad" />
+ </defs>
+ <sodipodi:namedview
+ id="base"
+ pagecolor="#ffffff"
+ bordercolor="#666666"
+ borderopacity="1.0"
+ inkscape:pageopacity="0.0"
+ inkscape:pageshadow="2"
+ inkscape:zoom="4.0000000"
+ inkscape:cx="79.132812"
+ inkscape:cy="78.777267"
+ inkscape:window-width="1022"
+ inkscape:window-height="701"
+ gridspacingy="1.0000000pt"
+ gridspacingx="1.0000000pt"
+ gridtolerance="1.0000000px"
+ inkscape:window-x="0"
+ inkscape:window-y="0" />
+ <path
+ style="fill:none;fill-opacity:0.75000000;fill-rule:evenodd;stroke:#ff0000;stroke-width:12.951884;stroke-dashoffset:0.0000000;"
+ d="M 83.854692,3.1467970 L 83.910715,142.25704"
+ id="path861"
+ sodipodi:nodetypes="cc" />
+ <rect
+ style="fill:#ff0000;fill-rule:evenodd;stroke:#ff0000;stroke-width:11.858918;"
+ id="rect854"
+ width="44.507047"
+ height="43.717121"
+ x="-20.046628"
+ y="-162.59821"
+ transform="matrix(0.588591,-0.808431,-0.588093,-0.808793,0.000000,0.000000)" />
+ <rect
+ style="fill:url(#linearGradient892);fill-rule:evenodd;stroke-width:11.052127;"
+ id="rect855"
+ width="41.237688"
+ height="40.506848"
+ x="-15.112020"
+ y="-162.64811"
+ transform="matrix(0.566729,-0.823905,-0.566229,-0.824248,0.000000,0.000000)" />
+</svg>
diff --git a/umbrello/umbrello/pics/sources/containment.svg b/umbrello/umbrello/pics/sources/containment.svg
new file mode 100644
index 00000000..7d33113b
--- /dev/null
+++ b/umbrello/umbrello/pics/sources/containment.svg
@@ -0,0 +1,141 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 20010904//EN"
+"http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd">
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+<svg
+ id="svg1"
+ sodipodi:version="0.32"
+ inkscape:version="0.37"
+ width="22pt"
+ height="22pt"
+ sodipodi:docbase="/home/jr/tmp/umbrello/icons/inkscape-svg"
+ sodipodi:docname="containment.svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:xlink="http://www.w3.org/1999/xlink">
+ <defs
+ id="defs3">
+ <linearGradient
+ id="linearGradient868">
+ <stop
+ style="stop-color:#ffffff;stop-opacity:0.0000000;"
+ offset="0.0000000"
+ id="stop869" />
+ <stop
+ style="stop-color:#fff;stop-opacity:1;"
+ offset="1"
+ id="stop870" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient893">
+ <stop
+ style="stop-color:#19839a;stop-opacity:0.0000000;"
+ offset="0.0000000"
+ id="stop894" />
+ <stop
+ style="stop-color:#fff;stop-opacity:1;"
+ offset="1"
+ id="stop895" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient830">
+ <stop
+ style="stop-color:#ebffff;stop-opacity:0.0000000;"
+ offset="0.0000000"
+ id="stop831" />
+ <stop
+ style="stop-color:#fff;stop-opacity:1;"
+ offset="1"
+ id="stop832" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient826">
+ <stop
+ style="stop-color:#000;stop-opacity:1;"
+ offset="0"
+ id="stop827" />
+ <stop
+ style="stop-color:#fff;stop-opacity:1;"
+ offset="1"
+ id="stop828" />
+ </linearGradient>
+ <linearGradient
+ xlink:href="#linearGradient830"
+ id="linearGradient829"
+ x1="1.5500000"
+ y1="0.52343750"
+ x2="0.20422535"
+ y2="-0.12195122"
+ spreadMethod="reflect" />
+ <linearGradient
+ xlink:href="#linearGradient830"
+ id="linearGradient834"
+ x1="-0.31159419"
+ y1="0.19531250"
+ x2="0.77536231"
+ y2="0.94531250" />
+ <linearGradient
+ xlink:href="#linearGradient830"
+ id="linearGradient836" />
+ <linearGradient
+ xlink:href="#linearGradient868"
+ id="linearGradient892" />
+ </defs>
+ <sodipodi:namedview
+ id="base"
+ pagecolor="#ffffff"
+ bordercolor="#666666"
+ borderopacity="1.0"
+ inkscape:pageopacity="0.0"
+ inkscape:pageshadow="2"
+ inkscape:zoom="22.6274170"
+ inkscape:cx="13.7972814"
+ inkscape:cy="10.8971871"
+ inkscape:window-width="1016"
+ inkscape:window-height="693"
+ gridspacingy="1.0000000pt"
+ gridspacingx="1.0000000pt"
+ gridtolerance="1.0000000px"
+ inkscape:window-x="0"
+ inkscape:window-y="0"
+ vertgrid="false"
+ showgrid="true" />
+ <path
+ sodipodi:type="arc"
+ style="font-size:12;fill:#ffff00;fill-rule:evenodd;stroke:#ff0000;stroke-width:10.0339;stroke-dasharray:none;"
+ id="path851"
+ sodipodi:cx="63.437500"
+ sodipodi:cy="39.375000"
+ sodipodi:rx="31.250000"
+ sodipodi:ry="31.562500"
+ d="M 94.687500 39.375000 A 31.250000 31.562500 0 1 0 32.187500,39.375000 A 31.250000 31.562500 0 1 0 94.687500 39.375000 z"
+ transform="matrix(0.172334,0.000000,0.000000,-0.171503,2.790291,27.93712)" />
+ <path
+ style="font-size:12;fill:none;fill-opacity:0.75;fill-rule:evenodd;stroke:#ff0000;stroke-width:1.2336;"
+ d="M 8.6805098 21.368615 L 18.435554 21.337956 "
+ id="path853"
+ sodipodi:nodetypes="cc" />
+ <path
+ style="font-size:12;fill:none;fill-opacity:0.75;fill-rule:evenodd;stroke:#ff0000;stroke-width:1.32889;"
+ d="M 13.745542 26.675526 L 13.810379 15.306314 "
+ id="path854"
+ sodipodi:nodetypes="cc" />
+ <path
+ sodipodi:type="arc"
+ style="font-size:12;fill:url(#linearGradient892);fill-opacity:0.75;fill-rule:evenodd;stroke-width:10;"
+ id="path858"
+ sodipodi:cx="63.437500"
+ sodipodi:cy="39.375000"
+ sodipodi:rx="31.250000"
+ sodipodi:ry="31.562500"
+ d="M 94.687500 39.375000 A 31.250000 31.562500 0 1 0 32.187500,39.375000 A 31.250000 31.562500 0 1 0 94.687500 39.375000 z"
+ transform="matrix(0.143170,0.000000,0.000000,-0.145251,4.723210,26.90351)" />
+ <rect
+ style="font-size:12;fill:#ff0000;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1pt;"
+ id="rect701"
+ width="2.48592252"
+ height="15.19174844"
+ x="12.54009724"
+ y="0.09961176" />
+</svg>
diff --git a/umbrello/umbrello/pics/sources/cursor-andline.svg b/umbrello/umbrello/pics/sources/cursor-andline.svg
new file mode 100644
index 00000000..fc315835
--- /dev/null
+++ b/umbrello/umbrello/pics/sources/cursor-andline.svg
@@ -0,0 +1,496 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+<svg
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://web.resource.org/cc/"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:sodipodi="http://inkscape.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ id="svg1"
+ height="32.000000px"
+ width="32.000000px"
+ y="0.00000000"
+ x="0.00000000"
+ version="1.0"
+ sodipodi:version="0.32"
+ inkscape:version="0.40+cvs"
+ sodipodi:docname="cursor-andline.svg"
+ sodipodi:docbase="F:\pics"
+ inkscape:export-filename="F:\pics\cursor-junction.png"
+ inkscape:export-xdpi="90.000000"
+ inkscape:export-ydpi="90.000000">
+ <metadata
+ id="metadata17">
+ <rdf:RDF
+ id="RDF18">
+ <cc:Work
+ rdf:about=""
+ id="Work19">
+ <dc:format
+ id="format20">image/svg+xml</dc:format>
+ <dc:type
+ id="type21"
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+ </cc:Work>
+ </rdf:RDF>
+ </metadata>
+ <sodipodi:namedview
+ id="base"
+ pagecolor="#ffffff"
+ bordercolor="#666666"
+ borderopacity="1.0"
+ inkscape:pageopacity="0.0"
+ inkscape:pageshadow="2"
+ inkscape:window-width="1111"
+ inkscape:window-height="870"
+ inkscape:zoom="21.750000"
+ inkscape:cx="16.000000"
+ inkscape:cy="16.000000"
+ inkscape:window-x="1861"
+ inkscape:window-y="104"
+ inkscape:current-layer="svg1" />
+ <defs
+ id="defs3">
+ <marker
+ style="overflow:visible;"
+ id="marker1"
+ refX="0.0"
+ refY="0.0"
+ orient="auto"
+ inkscape:stockid="Arrow2Mend">
+ <path
+ transform="scale(0.6) rotate(180) translate(-5,0)"
+ d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.9730900,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z "
+ style="font-size:12.0;fill-rule:evenodd;stroke-width:0.62500000;stroke-linejoin:round;"
+ id="path2"
+ sodipodi:nodetypes="cccc" />
+ </marker>
+ <marker
+ style="overflow:visible;"
+ id="Arrow2Mend"
+ refX="0.0"
+ refY="0.0"
+ orient="auto"
+ inkscape:stockid="Arrow2Mend">
+ <path
+ transform="scale(0.6) rotate(180) translate(-5,0)"
+ d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.9730900,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z "
+ style="font-size:12.0;fill-rule:evenodd;stroke-width:0.62500000;stroke-linejoin:round;"
+ id="path237"
+ sodipodi:nodetypes="cccc" />
+ </marker>
+ <marker
+ style="overflow:visible;"
+ id="marker258"
+ refX="0.0"
+ refY="0.0"
+ orient="auto"
+ inkscape:stockid="Arrow2Lend">
+ <path
+ transform="scale(1.1) rotate(180) translate(-5,0)"
+ d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.9730900,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z "
+ style="font-size:12.0;fill-rule:evenodd;stroke-width:0.62500000;stroke-linejoin:round;"
+ id="path259"
+ sodipodi:nodetypes="cccc" />
+ </marker>
+ <marker
+ style="overflow:visible;"
+ id="marker255"
+ refX="0.0"
+ refY="0.0"
+ orient="auto"
+ inkscape:stockid="Arrow2Lend">
+ <path
+ transform="scale(1.1) rotate(180) translate(-5,0)"
+ d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.9730900,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z "
+ style="font-size:12.0;fill-rule:evenodd;stroke-width:0.62500000;stroke-linejoin:round;"
+ id="path256"
+ sodipodi:nodetypes="cccc" />
+ </marker>
+ <marker
+ style="overflow:visible;"
+ id="marker252"
+ refX="0.0"
+ refY="0.0"
+ orient="auto"
+ inkscape:stockid="Arrow2Lend">
+ <path
+ transform="scale(1.1) rotate(180) translate(-5,0)"
+ d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.9730900,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z "
+ style="font-size:12.0;fill-rule:evenodd;stroke-width:0.62500000;stroke-linejoin:round;"
+ id="path253"
+ sodipodi:nodetypes="cccc" />
+ </marker>
+ <marker
+ style="overflow:visible;"
+ id="marker249"
+ refX="0.0"
+ refY="0.0"
+ orient="auto"
+ inkscape:stockid="Arrow2Lend">
+ <path
+ transform="scale(1.1) rotate(180) translate(-5,0)"
+ d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.9730900,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z "
+ style="font-size:12.0;fill-rule:evenodd;stroke-width:0.62500000;stroke-linejoin:round;"
+ id="path250"
+ sodipodi:nodetypes="cccc" />
+ </marker>
+ <marker
+ style="overflow:visible;"
+ id="Arrow2Lend"
+ refX="0.0"
+ refY="0.0"
+ orient="auto"
+ inkscape:stockid="Arrow2Lend">
+ <path
+ transform="scale(1.1) rotate(180) translate(-5,0)"
+ d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.9730900,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z "
+ style="font-size:12.0;fill-rule:evenodd;stroke-width:0.62500000;stroke-linejoin:round;"
+ id="path238"
+ sodipodi:nodetypes="cccc" />
+ </marker>
+ <marker
+ inkscape:stockid="Arrow2Lend"
+ orient="auto"
+ refY="0.0"
+ refX="0.0"
+ id="marker12"
+ style="overflow:visible;">
+ <path
+ sodipodi:nodetypes="cccc"
+ id="path455"
+ style="font-size:12.0;fill-rule:evenodd;stroke-width:0.62500000;stroke-linejoin:round;"
+ d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.9730900,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z "
+ transform="scale(1.1) rotate(180) translate(-5,0)" />
+ </marker>
+ <marker
+ inkscape:stockid="Arrow2Mend"
+ orient="auto"
+ refY="0.0"
+ refX="0.0"
+ id="marker11"
+ style="overflow:visible;">
+ <path
+ sodipodi:nodetypes="cccc"
+ id="path454"
+ style="font-size:12.0;fill-rule:evenodd;stroke-width:0.62500000;stroke-linejoin:round;"
+ d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.9730900,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z "
+ transform="scale(0.6) rotate(180) translate(-5,0)" />
+ </marker>
+ <marker
+ inkscape:stockid="Arrow2Mend"
+ orient="auto"
+ refY="0.0"
+ refX="0.0"
+ id="marker553"
+ style="overflow:visible;">
+ <path
+ sodipodi:nodetypes="cccc"
+ id="path554"
+ style="font-size:12.0;fill-rule:evenodd;stroke-width:0.62500000;stroke-linejoin:round;"
+ d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.9730900,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z "
+ transform="scale(0.6) rotate(180) translate(-5,0)" />
+ </marker>
+ <marker
+ inkscape:stockid="Arrow2Mend"
+ orient="auto"
+ refY="0.0"
+ refX="0.0"
+ id="marker556"
+ style="overflow:visible;">
+ <path
+ sodipodi:nodetypes="cccc"
+ id="path557"
+ style="font-size:12.0;fill-rule:evenodd;stroke-width:0.62500000;stroke-linejoin:round;"
+ d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.9730900,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z "
+ transform="scale(0.6) rotate(180) translate(-5,0)" />
+ </marker>
+ <marker
+ inkscape:stockid="Arrow2Lend"
+ orient="auto"
+ refY="0.0"
+ refX="0.0"
+ id="marker25"
+ style="overflow:visible;">
+ <path
+ sodipodi:nodetypes="cccc"
+ id="path26"
+ style="font-size:12.0;fill-rule:evenodd;stroke-width:0.62500000;stroke-linejoin:round;"
+ d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.9730900,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z "
+ transform="scale(1.1) rotate(180) translate(-5,0)" />
+ </marker>
+ <marker
+ inkscape:stockid="Arrow2Lend"
+ orient="auto"
+ refY="0.0"
+ refX="0.0"
+ id="marker23"
+ style="overflow:visible;">
+ <path
+ sodipodi:nodetypes="cccc"
+ id="path24"
+ style="font-size:12.0;fill-rule:evenodd;stroke-width:0.62500000;stroke-linejoin:round;"
+ d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.9730900,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z "
+ transform="scale(1.1) rotate(180) translate(-5,0)" />
+ </marker>
+ <marker
+ inkscape:stockid="Arrow2Lend"
+ orient="auto"
+ refY="0.0"
+ refX="0.0"
+ id="marker21"
+ style="overflow:visible;">
+ <path
+ sodipodi:nodetypes="cccc"
+ id="path22"
+ style="font-size:12.0;fill-rule:evenodd;stroke-width:0.62500000;stroke-linejoin:round;"
+ d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.9730900,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z "
+ transform="scale(1.1) rotate(180) translate(-5,0)" />
+ </marker>
+ <marker
+ inkscape:stockid="Arrow2Lend"
+ orient="auto"
+ refY="0.0"
+ refX="0.0"
+ id="marker19"
+ style="overflow:visible;">
+ <path
+ sodipodi:nodetypes="cccc"
+ id="path20"
+ style="font-size:12.0;fill-rule:evenodd;stroke-width:0.62500000;stroke-linejoin:round;"
+ d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.9730900,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z "
+ transform="scale(1.1) rotate(180) translate(-5,0)" />
+ </marker>
+ <marker
+ inkscape:stockid="Arrow2Lend"
+ orient="auto"
+ refY="0.0"
+ refX="0.0"
+ id="marker17"
+ style="overflow:visible;">
+ <path
+ sodipodi:nodetypes="cccc"
+ id="path18"
+ style="font-size:12.0;fill-rule:evenodd;stroke-width:0.62500000;stroke-linejoin:round;"
+ d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.9730900,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z "
+ transform="scale(1.1) rotate(180) translate(-5,0)" />
+ </marker>
+ <marker
+ inkscape:stockid="Arrow2Mend"
+ orient="auto"
+ refY="0.0"
+ refX="0.0"
+ id="marker15"
+ style="overflow:visible;">
+ <path
+ sodipodi:nodetypes="cccc"
+ id="path16"
+ style="font-size:12.0;fill-rule:evenodd;stroke-width:0.62500000;stroke-linejoin:round;"
+ d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.9730900,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z "
+ transform="scale(0.6) rotate(180) translate(-5,0)" />
+ </marker>
+ <marker
+ inkscape:stockid="Arrow2Mend"
+ orient="auto"
+ refY="0.0"
+ refX="0.0"
+ id="marker13"
+ style="overflow:visible;">
+ <path
+ sodipodi:nodetypes="cccc"
+ id="path14"
+ style="font-size:12.0;fill-rule:evenodd;stroke-width:0.62500000;stroke-linejoin:round;"
+ d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.9730900,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z "
+ transform="scale(0.6) rotate(180) translate(-5,0)" />
+ </marker>
+ <marker
+ style="overflow:visible;"
+ id="marker52"
+ refX="0.0"
+ refY="0.0"
+ orient="auto"
+ inkscape:stockid="Arrow2Lend">
+ <path
+ transform="scale(1.1) rotate(180) translate(-5,0)"
+ d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.9730900,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z "
+ style="font-size:12.0;fill-rule:evenodd;stroke-width:0.62500000;stroke-linejoin:round;"
+ id="path53"
+ sodipodi:nodetypes="cccc" />
+ </marker>
+ <marker
+ style="overflow:visible;"
+ id="marker50"
+ refX="0.0"
+ refY="0.0"
+ orient="auto"
+ inkscape:stockid="Arrow2Lend">
+ <path
+ transform="scale(1.1) rotate(180) translate(-5,0)"
+ d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.9730900,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z "
+ style="font-size:12.0;fill-rule:evenodd;stroke-width:0.62500000;stroke-linejoin:round;"
+ id="path51"
+ sodipodi:nodetypes="cccc" />
+ </marker>
+ <marker
+ style="overflow:visible;"
+ id="marker48"
+ refX="0.0"
+ refY="0.0"
+ orient="auto"
+ inkscape:stockid="Arrow2Lend">
+ <path
+ transform="scale(1.1) rotate(180) translate(-5,0)"
+ d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.9730900,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z "
+ style="font-size:12.0;fill-rule:evenodd;stroke-width:0.62500000;stroke-linejoin:round;"
+ id="path49"
+ sodipodi:nodetypes="cccc" />
+ </marker>
+ <marker
+ style="overflow:visible;"
+ id="marker46"
+ refX="0.0"
+ refY="0.0"
+ orient="auto"
+ inkscape:stockid="Arrow2Lend">
+ <path
+ transform="scale(1.1) rotate(180) translate(-5,0)"
+ d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.9730900,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z "
+ style="font-size:12.0;fill-rule:evenodd;stroke-width:0.62500000;stroke-linejoin:round;"
+ id="path47"
+ sodipodi:nodetypes="cccc" />
+ </marker>
+ <marker
+ style="overflow:visible;"
+ id="marker44"
+ refX="0.0"
+ refY="0.0"
+ orient="auto"
+ inkscape:stockid="Arrow2Lend">
+ <path
+ transform="scale(1.1) rotate(180) translate(-5,0)"
+ d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.9730900,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z "
+ style="font-size:12.0;fill-rule:evenodd;stroke-width:0.62500000;stroke-linejoin:round;"
+ id="path45"
+ sodipodi:nodetypes="cccc" />
+ </marker>
+ <marker
+ style="overflow:visible;"
+ id="marker42"
+ refX="0.0"
+ refY="0.0"
+ orient="auto"
+ inkscape:stockid="Arrow2Mend">
+ <path
+ transform="scale(0.6) rotate(180) translate(-5,0)"
+ d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.9730900,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z "
+ style="font-size:12.0;fill-rule:evenodd;stroke-width:0.62500000;stroke-linejoin:round;"
+ id="path43"
+ sodipodi:nodetypes="cccc" />
+ </marker>
+ <marker
+ style="overflow:visible;"
+ id="marker40"
+ refX="0.0"
+ refY="0.0"
+ orient="auto"
+ inkscape:stockid="Arrow2Mend">
+ <path
+ transform="scale(0.6) rotate(180) translate(-5,0)"
+ d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.9730900,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z "
+ style="font-size:12.0;fill-rule:evenodd;stroke-width:0.62500000;stroke-linejoin:round;"
+ id="path41"
+ sodipodi:nodetypes="cccc" />
+ </marker>
+ <marker
+ style="overflow:visible;"
+ id="marker20"
+ refX="0.0"
+ refY="0.0"
+ orient="auto"
+ inkscape:stockid="Arrow2Lend">
+ <path
+ transform="scale(1.1) rotate(180) translate(-5,0)"
+ d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.9730900,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z "
+ style="font-size:12.0;fill-rule:evenodd;stroke-width:0.62500000;stroke-linejoin:round;"
+ id="path21"
+ sodipodi:nodetypes="cccc" />
+ </marker>
+ <marker
+ style="overflow:visible;"
+ id="marker18"
+ refX="0.0"
+ refY="0.0"
+ orient="auto"
+ inkscape:stockid="Arrow2Mend">
+ <path
+ transform="scale(0.6) rotate(180) translate(-5,0)"
+ d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.9730900,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z "
+ style="font-size:12.0;fill-rule:evenodd;stroke-width:0.62500000;stroke-linejoin:round;"
+ id="path19"
+ sodipodi:nodetypes="cccc" />
+ </marker>
+ <marker
+ style="overflow:visible;"
+ id="marker16"
+ refX="0.0"
+ refY="0.0"
+ orient="auto"
+ inkscape:stockid="Arrow2Mend">
+ <path
+ transform="scale(0.6) rotate(180) translate(-5,0)"
+ d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.9730900,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z "
+ style="font-size:12.0;fill-rule:evenodd;stroke-width:0.62500000;stroke-linejoin:round;"
+ id="path17"
+ sodipodi:nodetypes="cccc" />
+ </marker>
+ <marker
+ style="overflow:visible;"
+ id="marker14"
+ refX="0.0"
+ refY="0.0"
+ orient="auto"
+ inkscape:stockid="Arrow2Mend">
+ <path
+ transform="scale(0.6) rotate(180) translate(-5,0)"
+ d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.9730900,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z "
+ style="font-size:12.0;fill-rule:evenodd;stroke-width:0.62500000;stroke-linejoin:round;"
+ id="path15"
+ sodipodi:nodetypes="cccc" />
+ </marker>
+ </defs>
+ <g
+ transform="translate(-367.8806,-513.0186)"
+ id="g191">
+ <path
+ style="fill:none;fill-opacity:0.75000000;fill-rule:evenodd;stroke:#000000;stroke-width:1.0000000;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:4.0000000;stroke-opacity:1.0000000"
+ d="M 377.45252,523.54977 C 377.45252,531.55430 377.45435,531.55430 377.45435,531.55430"
+ id="path85" />
+ <path
+ style="fill:none;fill-opacity:0.75000000;fill-rule:evenodd;stroke:#000000;stroke-width:1.0000000;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:4.0000000;stroke-opacity:1.0000000"
+ d="M 377.42440,513.51768 C 377.42440,521.52221 377.42623,521.52221 377.42623,521.52221"
+ id="path347" />
+ <path
+ style="fill:none;fill-opacity:0.75000000;fill-rule:evenodd;stroke:#000000;stroke-width:1.0000000;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:4.0000000;stroke-opacity:1.0000000"
+ d="M 376.44018,522.53611 C 368.43565,522.53611 368.43565,522.53794 368.43565,522.53794"
+ id="path348" />
+ <path
+ style="fill:none;fill-opacity:0.75000000;fill-rule:evenodd;stroke:#000000;stroke-width:1.0000000;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:4.0000000;stroke-opacity:1.0000000"
+ d="M 386.42981,522.49886 C 378.42528,522.49886 378.42528,522.50069 378.42528,522.50069"
+ id="path349" />
+ <rect
+ rx="5.0000000"
+ ry="5.0000000"
+ y="528.88312"
+ x="379.64066"
+ height="14.384930"
+ width="18.709280"
+ id="rect182"
+ style="opacity:0.59999990;fill:#e6ca25;fill-opacity:1.0000000;stroke:#908787;stroke-width:1.8478020;stroke-linecap:butt;stroke-miterlimit:4.0000000;stroke-opacity:1.0000000" />
+ <path
+ id="path183"
+ d="M 389.03268,542.60983 C 389.02481,526.17549 389.02481,526.17549 389.02481,526.17549 L 389.02481,526.17549"
+ style="fill:none;fill-opacity:0.75000000;fill-rule:evenodd;stroke:#000000;stroke-width:1.5000000;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:4.0000000;stroke-dasharray:1.5000000 4.5000000 ;stroke-dashoffset:0.00000000;stroke-opacity:1.0000000" />
+ </g>
+</svg>
diff --git a/umbrello/umbrello/pics/sources/cursor-choice-rhomb.svg b/umbrello/umbrello/pics/sources/cursor-choice-rhomb.svg
new file mode 100644
index 00000000..81277a0c
--- /dev/null
+++ b/umbrello/umbrello/pics/sources/cursor-choice-rhomb.svg
@@ -0,0 +1,439 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+<svg
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://web.resource.org/cc/"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:sodipodi="http://inkscape.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ id="svg1"
+ height="32.000000px"
+ width="32.000000px"
+ y="0.00000000"
+ x="0.00000000"
+ version="1.0"
+ sodipodi:version="0.32"
+ inkscape:version="0.40+cvs"
+ sodipodi:docname="cursor-choice-rhomb.svg"
+ sodipodi:docbase="F:\umbrello\pics"
+ inkscape:export-filename="F:\umbrello\pics\cursor-junction-temp.png"
+ inkscape:export-xdpi="90.000000"
+ inkscape:export-ydpi="90.000000">
+ <metadata
+ id="metadata17">
+ <rdf:RDF
+ id="RDF18">
+ <cc:Work
+ rdf:about=""
+ id="Work19">
+ <dc:format
+ id="format20">image/svg+xml</dc:format>
+ <dc:type
+ id="type21"
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+ </cc:Work>
+ </rdf:RDF>
+ </metadata>
+ <sodipodi:namedview
+ id="base"
+ pagecolor="#ffffff"
+ bordercolor="#666666"
+ borderopacity="1.0"
+ inkscape:pageopacity="1.0000000"
+ inkscape:pageshadow="2"
+ inkscape:window-width="1111"
+ inkscape:window-height="870"
+ inkscape:zoom="21.750000"
+ inkscape:cx="16.000000"
+ inkscape:cy="16.000000"
+ inkscape:window-x="1861"
+ inkscape:window-y="104"
+ inkscape:current-layer="svg1" />
+ <defs
+ id="defs3">
+ <marker
+ style="overflow:visible;"
+ id="marker1"
+ refX="0.0"
+ refY="0.0"
+ orient="auto"
+ inkscape:stockid="Arrow2Mend">
+ <path
+ transform="scale(0.6) rotate(180) translate(-5,0)"
+ d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.9730900,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z "
+ style="font-size:12.0;fill-rule:evenodd;stroke-width:0.62500000;stroke-linejoin:round;"
+ id="path2"
+ sodipodi:nodetypes="cccc" />
+ </marker>
+ <marker
+ style="overflow:visible;"
+ id="Arrow2Mend"
+ refX="0.0"
+ refY="0.0"
+ orient="auto"
+ inkscape:stockid="Arrow2Mend">
+ <path
+ transform="scale(0.6) rotate(180) translate(-5,0)"
+ d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.9730900,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z "
+ style="font-size:12.0;fill-rule:evenodd;stroke-width:0.62500000;stroke-linejoin:round;"
+ id="path237"
+ sodipodi:nodetypes="cccc" />
+ </marker>
+ <marker
+ style="overflow:visible;"
+ id="marker258"
+ refX="0.0"
+ refY="0.0"
+ orient="auto"
+ inkscape:stockid="Arrow2Lend">
+ <path
+ transform="scale(1.1) rotate(180) translate(-5,0)"
+ d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.9730900,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z "
+ style="font-size:12.0;fill-rule:evenodd;stroke-width:0.62500000;stroke-linejoin:round;"
+ id="path259"
+ sodipodi:nodetypes="cccc" />
+ </marker>
+ <marker
+ style="overflow:visible;"
+ id="marker255"
+ refX="0.0"
+ refY="0.0"
+ orient="auto"
+ inkscape:stockid="Arrow2Lend">
+ <path
+ transform="scale(1.1) rotate(180) translate(-5,0)"
+ d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.9730900,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z "
+ style="font-size:12.0;fill-rule:evenodd;stroke-width:0.62500000;stroke-linejoin:round;"
+ id="path256"
+ sodipodi:nodetypes="cccc" />
+ </marker>
+ <marker
+ style="overflow:visible;"
+ id="marker252"
+ refX="0.0"
+ refY="0.0"
+ orient="auto"
+ inkscape:stockid="Arrow2Lend">
+ <path
+ transform="scale(1.1) rotate(180) translate(-5,0)"
+ d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.9730900,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z "
+ style="font-size:12.0;fill-rule:evenodd;stroke-width:0.62500000;stroke-linejoin:round;"
+ id="path253"
+ sodipodi:nodetypes="cccc" />
+ </marker>
+ <marker
+ style="overflow:visible;"
+ id="marker249"
+ refX="0.0"
+ refY="0.0"
+ orient="auto"
+ inkscape:stockid="Arrow2Lend">
+ <path
+ transform="scale(1.1) rotate(180) translate(-5,0)"
+ d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.9730900,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z "
+ style="font-size:12.0;fill-rule:evenodd;stroke-width:0.62500000;stroke-linejoin:round;"
+ id="path250"
+ sodipodi:nodetypes="cccc" />
+ </marker>
+ <marker
+ style="overflow:visible;"
+ id="Arrow2Lend"
+ refX="0.0"
+ refY="0.0"
+ orient="auto"
+ inkscape:stockid="Arrow2Lend">
+ <path
+ transform="scale(1.1) rotate(180) translate(-5,0)"
+ d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.9730900,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z "
+ style="font-size:12.0;fill-rule:evenodd;stroke-width:0.62500000;stroke-linejoin:round;"
+ id="path238"
+ sodipodi:nodetypes="cccc" />
+ </marker>
+ <marker
+ inkscape:stockid="Arrow2Lend"
+ orient="auto"
+ refY="0.0"
+ refX="0.0"
+ id="marker12"
+ style="overflow:visible;">
+ <path
+ sodipodi:nodetypes="cccc"
+ id="path455"
+ style="font-size:12.0;fill-rule:evenodd;stroke-width:0.62500000;stroke-linejoin:round;"
+ d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.9730900,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z "
+ transform="scale(1.1) rotate(180) translate(-5,0)" />
+ </marker>
+ <marker
+ inkscape:stockid="Arrow2Mend"
+ orient="auto"
+ refY="0.0"
+ refX="0.0"
+ id="marker11"
+ style="overflow:visible;">
+ <path
+ sodipodi:nodetypes="cccc"
+ id="path454"
+ style="font-size:12.0;fill-rule:evenodd;stroke-width:0.62500000;stroke-linejoin:round;"
+ d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.9730900,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z "
+ transform="scale(0.6) rotate(180) translate(-5,0)" />
+ </marker>
+ <marker
+ inkscape:stockid="Arrow2Mend"
+ orient="auto"
+ refY="0.0"
+ refX="0.0"
+ id="marker553"
+ style="overflow:visible;">
+ <path
+ sodipodi:nodetypes="cccc"
+ id="path554"
+ style="font-size:12.0;fill-rule:evenodd;stroke-width:0.62500000;stroke-linejoin:round;"
+ d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.9730900,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z "
+ transform="scale(0.6) rotate(180) translate(-5,0)" />
+ </marker>
+ <marker
+ inkscape:stockid="Arrow2Mend"
+ orient="auto"
+ refY="0.0"
+ refX="0.0"
+ id="marker556"
+ style="overflow:visible;">
+ <path
+ sodipodi:nodetypes="cccc"
+ id="path557"
+ style="font-size:12.0;fill-rule:evenodd;stroke-width:0.62500000;stroke-linejoin:round;"
+ d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.9730900,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z "
+ transform="scale(0.6) rotate(180) translate(-5,0)" />
+ </marker>
+ <marker
+ inkscape:stockid="Arrow2Lend"
+ orient="auto"
+ refY="0.0"
+ refX="0.0"
+ id="marker25"
+ style="overflow:visible;">
+ <path
+ sodipodi:nodetypes="cccc"
+ id="path26"
+ style="font-size:12.0;fill-rule:evenodd;stroke-width:0.62500000;stroke-linejoin:round;"
+ d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.9730900,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z "
+ transform="scale(1.1) rotate(180) translate(-5,0)" />
+ </marker>
+ <marker
+ inkscape:stockid="Arrow2Lend"
+ orient="auto"
+ refY="0.0"
+ refX="0.0"
+ id="marker23"
+ style="overflow:visible;">
+ <path
+ sodipodi:nodetypes="cccc"
+ id="path24"
+ style="font-size:12.0;fill-rule:evenodd;stroke-width:0.62500000;stroke-linejoin:round;"
+ d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.9730900,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z "
+ transform="scale(1.1) rotate(180) translate(-5,0)" />
+ </marker>
+ <marker
+ inkscape:stockid="Arrow2Lend"
+ orient="auto"
+ refY="0.0"
+ refX="0.0"
+ id="marker21"
+ style="overflow:visible;">
+ <path
+ sodipodi:nodetypes="cccc"
+ id="path22"
+ style="font-size:12.0;fill-rule:evenodd;stroke-width:0.62500000;stroke-linejoin:round;"
+ d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.9730900,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z "
+ transform="scale(1.1) rotate(180) translate(-5,0)" />
+ </marker>
+ <marker
+ inkscape:stockid="Arrow2Lend"
+ orient="auto"
+ refY="0.0"
+ refX="0.0"
+ id="marker19"
+ style="overflow:visible;">
+ <path
+ sodipodi:nodetypes="cccc"
+ id="path20"
+ style="font-size:12.0;fill-rule:evenodd;stroke-width:0.62500000;stroke-linejoin:round;"
+ d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.9730900,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z "
+ transform="scale(1.1) rotate(180) translate(-5,0)" />
+ </marker>
+ <marker
+ inkscape:stockid="Arrow2Lend"
+ orient="auto"
+ refY="0.0"
+ refX="0.0"
+ id="marker17"
+ style="overflow:visible;">
+ <path
+ sodipodi:nodetypes="cccc"
+ id="path18"
+ style="font-size:12.0;fill-rule:evenodd;stroke-width:0.62500000;stroke-linejoin:round;"
+ d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.9730900,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z "
+ transform="scale(1.1) rotate(180) translate(-5,0)" />
+ </marker>
+ <marker
+ inkscape:stockid="Arrow2Mend"
+ orient="auto"
+ refY="0.0"
+ refX="0.0"
+ id="marker15"
+ style="overflow:visible;">
+ <path
+ sodipodi:nodetypes="cccc"
+ id="path16"
+ style="font-size:12.0;fill-rule:evenodd;stroke-width:0.62500000;stroke-linejoin:round;"
+ d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.9730900,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z "
+ transform="scale(0.6) rotate(180) translate(-5,0)" />
+ </marker>
+ <marker
+ inkscape:stockid="Arrow2Mend"
+ orient="auto"
+ refY="0.0"
+ refX="0.0"
+ id="marker13"
+ style="overflow:visible;">
+ <path
+ sodipodi:nodetypes="cccc"
+ id="path14"
+ style="font-size:12.0;fill-rule:evenodd;stroke-width:0.62500000;stroke-linejoin:round;"
+ d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.9730900,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z "
+ transform="scale(0.6) rotate(180) translate(-5,0)" />
+ </marker>
+ <marker
+ style="overflow:visible;"
+ id="marker52"
+ refX="0.0"
+ refY="0.0"
+ orient="auto"
+ inkscape:stockid="Arrow2Lend">
+ <path
+ transform="scale(1.1) rotate(180) translate(-5,0)"
+ d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.9730900,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z "
+ style="font-size:12.0;fill-rule:evenodd;stroke-width:0.62500000;stroke-linejoin:round;"
+ id="path53"
+ sodipodi:nodetypes="cccc" />
+ </marker>
+ <marker
+ style="overflow:visible;"
+ id="marker50"
+ refX="0.0"
+ refY="0.0"
+ orient="auto"
+ inkscape:stockid="Arrow2Lend">
+ <path
+ transform="scale(1.1) rotate(180) translate(-5,0)"
+ d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.9730900,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z "
+ style="font-size:12.0;fill-rule:evenodd;stroke-width:0.62500000;stroke-linejoin:round;"
+ id="path51"
+ sodipodi:nodetypes="cccc" />
+ </marker>
+ <marker
+ style="overflow:visible;"
+ id="marker48"
+ refX="0.0"
+ refY="0.0"
+ orient="auto"
+ inkscape:stockid="Arrow2Lend">
+ <path
+ transform="scale(1.1) rotate(180) translate(-5,0)"
+ d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.9730900,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z "
+ style="font-size:12.0;fill-rule:evenodd;stroke-width:0.62500000;stroke-linejoin:round;"
+ id="path49"
+ sodipodi:nodetypes="cccc" />
+ </marker>
+ <marker
+ style="overflow:visible;"
+ id="marker46"
+ refX="0.0"
+ refY="0.0"
+ orient="auto"
+ inkscape:stockid="Arrow2Lend">
+ <path
+ transform="scale(1.1) rotate(180) translate(-5,0)"
+ d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.9730900,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z "
+ style="font-size:12.0;fill-rule:evenodd;stroke-width:0.62500000;stroke-linejoin:round;"
+ id="path47"
+ sodipodi:nodetypes="cccc" />
+ </marker>
+ <marker
+ style="overflow:visible;"
+ id="marker44"
+ refX="0.0"
+ refY="0.0"
+ orient="auto"
+ inkscape:stockid="Arrow2Lend">
+ <path
+ transform="scale(1.1) rotate(180) translate(-5,0)"
+ d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.9730900,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z "
+ style="font-size:12.0;fill-rule:evenodd;stroke-width:0.62500000;stroke-linejoin:round;"
+ id="path45"
+ sodipodi:nodetypes="cccc" />
+ </marker>
+ <marker
+ style="overflow:visible;"
+ id="marker42"
+ refX="0.0"
+ refY="0.0"
+ orient="auto"
+ inkscape:stockid="Arrow2Mend">
+ <path
+ transform="scale(0.6) rotate(180) translate(-5,0)"
+ d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.9730900,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z "
+ style="font-size:12.0;fill-rule:evenodd;stroke-width:0.62500000;stroke-linejoin:round;"
+ id="path43"
+ sodipodi:nodetypes="cccc" />
+ </marker>
+ <marker
+ style="overflow:visible;"
+ id="marker40"
+ refX="0.0"
+ refY="0.0"
+ orient="auto"
+ inkscape:stockid="Arrow2Mend">
+ <path
+ transform="scale(0.6) rotate(180) translate(-5,0)"
+ d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.9730900,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z "
+ style="font-size:12.0;fill-rule:evenodd;stroke-width:0.62500000;stroke-linejoin:round;"
+ id="path41"
+ sodipodi:nodetypes="cccc" />
+ </marker>
+ </defs>
+ <g
+ inkscape:groupmode="layer"
+ id="layer1"
+ inkscape:label="cursor">
+ <g
+ id="g197">
+ <path
+ style="fill:none;fill-opacity:0.75000000;fill-rule:evenodd;stroke:#000000;stroke-width:1.0000000;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:4.0000000;stroke-opacity:1.0000000"
+ d="M 9.4805000,0.52068000 C 9.4805000,8.5252100 9.4823300,8.5252100 9.4823300,8.5252100"
+ id="path347" />
+ <path
+ style="fill:none;fill-opacity:0.75000000;fill-rule:evenodd;stroke:#000000;stroke-width:1.0000000;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:4.0000000;stroke-opacity:1.0000000"
+ d="M 8.4962800,9.5391100 C 0.49175000,9.5391100 0.49175000,9.5409400 0.49175000,9.5409400"
+ id="path348" />
+ <rect
+ style="fill:#00f5c5;fill-opacity:1.0000000;stroke:#000000;stroke-width:1.6613266;stroke-linecap:butt;stroke-miterlimit:4.0000000;stroke-dashoffset:0.00000000;stroke-opacity:1.0000000;opacity:1.0000000"
+ id="rect1"
+ width="12.072264"
+ height="12.027816"
+ x="24.273464"
+ y="-3.6065087"
+ transform="matrix(0.746765,0.665088,-0.737169,0.675708,0.000000,0.000000)" />
+ </g>
+ <path
+ style="fill:none;fill-opacity:0.75000000;fill-rule:evenodd;stroke:#000000;stroke-width:1.0000000;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:4.0000000;stroke-opacity:1.0000000"
+ d="M 9.5086200,10.552770 C 9.5086200,18.557300 9.5104500,18.557300 9.5104500,18.557300"
+ id="path85" />
+ <path
+ style="fill:none;fill-opacity:0.75000000;fill-rule:evenodd;stroke:#000000;stroke-width:1.0000000;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:4.0000000;stroke-opacity:1.0000000"
+ d="M 18.485910,9.5018600 C 10.481380,9.5018600 10.481380,9.5036900 10.481380,9.5036900"
+ id="path349" />
+ </g>
+</svg>
diff --git a/umbrello/umbrello/pics/sources/cursor-choice-round.svg b/umbrello/umbrello/pics/sources/cursor-choice-round.svg
new file mode 100644
index 00000000..747a511f
--- /dev/null
+++ b/umbrello/umbrello/pics/sources/cursor-choice-round.svg
@@ -0,0 +1,356 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+<svg
+ xmlns:xml="http://www.w3.org/XML/1998/namespace"
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://web.resource.org/cc/"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:sodipodi="http://inkscape.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ inkscape:export-ydpi="90.000000"
+ inkscape:export-xdpi="90.000000"
+ inkscape:export-filename="F:\pics\cursor-junction.png"
+ sodipodi:docbase="F:\pics"
+ sodipodi:docname="cursor-choice-round.svg"
+ inkscape:version="0.40+cvs"
+ sodipodi:version="0.32"
+ version="1.0"
+ x="0.00000000"
+ y="0.00000000"
+ width="32.000000px"
+ height="32.000000px"
+ id="svg1">
+ <metadata
+ id="metadata17">
+ <rdf:RDF
+ id="RDF18">
+ <cc:Work
+ id="Work19"
+ rdf:about="">
+ <dc:format
+ id="format20">image/svg+xml</dc:format>
+ <dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage"
+ id="type21" />
+ </cc:Work>
+ </rdf:RDF>
+ </metadata>
+ <sodipodi:namedview
+ inkscape:document-units="pt"
+ inkscape:current-layer="svg1"
+ inkscape:window-y="104"
+ inkscape:window-x="1861"
+ inkscape:cy="16.000000"
+ inkscape:cx="16.000000"
+ inkscape:zoom="21.750000"
+ inkscape:window-height="870"
+ inkscape:window-width="1111"
+ inkscape:pageshadow="2"
+ inkscape:pageopacity="0.0"
+ borderopacity="1.0"
+ bordercolor="#666666"
+ pagecolor="#ffffff"
+ id="base" />
+ <defs
+ id="defs3">
+ <marker
+ inkscape:stockid="Arrow2Mend"
+ orient="auto"
+ refY="0.0"
+ refX="0.0"
+ id="marker1"
+ style="overflow:visible;">
+ <path
+ sodipodi:nodetypes="cccc"
+ id="path2"
+ style="font-size:12.0;fill-rule:evenodd;stroke-width:0.62500000;stroke-linejoin:round;"
+ d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.9730900,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z "
+ transform="scale(0.6) rotate(180) translate(-5,0)" />
+ </marker>
+ <marker
+ inkscape:stockid="Arrow2Mend"
+ orient="auto"
+ refY="0.0"
+ refX="0.0"
+ id="Arrow2Mend"
+ style="overflow:visible;">
+ <path
+ sodipodi:nodetypes="cccc"
+ id="path237"
+ style="font-size:12.0;fill-rule:evenodd;stroke-width:0.62500000;stroke-linejoin:round;"
+ d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.9730900,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z "
+ transform="scale(0.6) rotate(180) translate(-5,0)" />
+ </marker>
+ <marker
+ inkscape:stockid="Arrow2Lend"
+ orient="auto"
+ refY="0.0"
+ refX="0.0"
+ id="marker258"
+ style="overflow:visible;">
+ <path
+ sodipodi:nodetypes="cccc"
+ id="path259"
+ style="font-size:12.0;fill-rule:evenodd;stroke-width:0.62500000;stroke-linejoin:round;"
+ d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.9730900,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z "
+ transform="scale(1.1) rotate(180) translate(-5,0)" />
+ </marker>
+ <marker
+ inkscape:stockid="Arrow2Lend"
+ orient="auto"
+ refY="0.0"
+ refX="0.0"
+ id="marker255"
+ style="overflow:visible;">
+ <path
+ sodipodi:nodetypes="cccc"
+ id="path256"
+ style="font-size:12.0;fill-rule:evenodd;stroke-width:0.62500000;stroke-linejoin:round;"
+ d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.9730900,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z "
+ transform="scale(1.1) rotate(180) translate(-5,0)" />
+ </marker>
+ <marker
+ inkscape:stockid="Arrow2Lend"
+ orient="auto"
+ refY="0.0"
+ refX="0.0"
+ id="marker252"
+ style="overflow:visible;">
+ <path
+ sodipodi:nodetypes="cccc"
+ id="path253"
+ style="font-size:12.0;fill-rule:evenodd;stroke-width:0.62500000;stroke-linejoin:round;"
+ d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.9730900,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z "
+ transform="scale(1.1) rotate(180) translate(-5,0)" />
+ </marker>
+ <marker
+ inkscape:stockid="Arrow2Lend"
+ orient="auto"
+ refY="0.0"
+ refX="0.0"
+ id="marker249"
+ style="overflow:visible;">
+ <path
+ sodipodi:nodetypes="cccc"
+ id="path250"
+ style="font-size:12.0;fill-rule:evenodd;stroke-width:0.62500000;stroke-linejoin:round;"
+ d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.9730900,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z "
+ transform="scale(1.1) rotate(180) translate(-5,0)" />
+ </marker>
+ <marker
+ inkscape:stockid="Arrow2Lend"
+ orient="auto"
+ refY="0.0"
+ refX="0.0"
+ id="Arrow2Lend"
+ style="overflow:visible;">
+ <path
+ sodipodi:nodetypes="cccc"
+ id="path238"
+ style="font-size:12.0;fill-rule:evenodd;stroke-width:0.62500000;stroke-linejoin:round;"
+ d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.9730900,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z "
+ transform="scale(1.1) rotate(180) translate(-5,0)" />
+ </marker>
+ <marker
+ style="overflow:visible;"
+ id="marker12"
+ refX="0.0"
+ refY="0.0"
+ orient="auto"
+ inkscape:stockid="Arrow2Lend">
+ <path
+ transform="scale(1.1) rotate(180) translate(-5,0)"
+ d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.9730900,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z "
+ style="font-size:12.0;fill-rule:evenodd;stroke-width:0.62500000;stroke-linejoin:round;"
+ id="path455"
+ sodipodi:nodetypes="cccc" />
+ </marker>
+ <marker
+ style="overflow:visible;"
+ id="marker11"
+ refX="0.0"
+ refY="0.0"
+ orient="auto"
+ inkscape:stockid="Arrow2Mend">
+ <path
+ transform="scale(0.6) rotate(180) translate(-5,0)"
+ d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.9730900,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z "
+ style="font-size:12.0;fill-rule:evenodd;stroke-width:0.62500000;stroke-linejoin:round;"
+ id="path454"
+ sodipodi:nodetypes="cccc" />
+ </marker>
+ <marker
+ style="overflow:visible;"
+ id="marker553"
+ refX="0.0"
+ refY="0.0"
+ orient="auto"
+ inkscape:stockid="Arrow2Mend">
+ <path
+ transform="scale(0.6) rotate(180) translate(-5,0)"
+ d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.9730900,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z "
+ style="font-size:12.0;fill-rule:evenodd;stroke-width:0.62500000;stroke-linejoin:round;"
+ id="path554"
+ sodipodi:nodetypes="cccc" />
+ </marker>
+ <marker
+ style="overflow:visible;"
+ id="marker556"
+ refX="0.0"
+ refY="0.0"
+ orient="auto"
+ inkscape:stockid="Arrow2Mend">
+ <path
+ transform="scale(0.6) rotate(180) translate(-5,0)"
+ d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.9730900,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z "
+ style="font-size:12.0;fill-rule:evenodd;stroke-width:0.62500000;stroke-linejoin:round;"
+ id="path557"
+ sodipodi:nodetypes="cccc" />
+ </marker>
+ <marker
+ style="overflow:visible;"
+ id="marker25"
+ refX="0.0"
+ refY="0.0"
+ orient="auto"
+ inkscape:stockid="Arrow2Lend">
+ <path
+ transform="scale(1.1) rotate(180) translate(-5,0)"
+ d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.9730900,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z "
+ style="font-size:12.0;fill-rule:evenodd;stroke-width:0.62500000;stroke-linejoin:round;"
+ id="path26"
+ sodipodi:nodetypes="cccc" />
+ </marker>
+ <marker
+ style="overflow:visible;"
+ id="marker23"
+ refX="0.0"
+ refY="0.0"
+ orient="auto"
+ inkscape:stockid="Arrow2Lend">
+ <path
+ transform="scale(1.1) rotate(180) translate(-5,0)"
+ d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.9730900,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z "
+ style="font-size:12.0;fill-rule:evenodd;stroke-width:0.62500000;stroke-linejoin:round;"
+ id="path24"
+ sodipodi:nodetypes="cccc" />
+ </marker>
+ <marker
+ style="overflow:visible;"
+ id="marker21"
+ refX="0.0"
+ refY="0.0"
+ orient="auto"
+ inkscape:stockid="Arrow2Lend">
+ <path
+ transform="scale(1.1) rotate(180) translate(-5,0)"
+ d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.9730900,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z "
+ style="font-size:12.0;fill-rule:evenodd;stroke-width:0.62500000;stroke-linejoin:round;"
+ id="path22"
+ sodipodi:nodetypes="cccc" />
+ </marker>
+ <marker
+ style="overflow:visible;"
+ id="marker19"
+ refX="0.0"
+ refY="0.0"
+ orient="auto"
+ inkscape:stockid="Arrow2Lend">
+ <path
+ transform="scale(1.1) rotate(180) translate(-5,0)"
+ d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.9730900,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z "
+ style="font-size:12.0;fill-rule:evenodd;stroke-width:0.62500000;stroke-linejoin:round;"
+ id="path20"
+ sodipodi:nodetypes="cccc" />
+ </marker>
+ <marker
+ style="overflow:visible;"
+ id="marker17"
+ refX="0.0"
+ refY="0.0"
+ orient="auto"
+ inkscape:stockid="Arrow2Lend">
+ <path
+ transform="scale(1.1) rotate(180) translate(-5,0)"
+ d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.9730900,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z "
+ style="font-size:12.0;fill-rule:evenodd;stroke-width:0.62500000;stroke-linejoin:round;"
+ id="path18"
+ sodipodi:nodetypes="cccc" />
+ </marker>
+ <marker
+ style="overflow:visible;"
+ id="marker15"
+ refX="0.0"
+ refY="0.0"
+ orient="auto"
+ inkscape:stockid="Arrow2Mend">
+ <path
+ transform="scale(0.6) rotate(180) translate(-5,0)"
+ d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.9730900,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z "
+ style="font-size:12.0;fill-rule:evenodd;stroke-width:0.62500000;stroke-linejoin:round;"
+ id="path16"
+ sodipodi:nodetypes="cccc" />
+ </marker>
+ <marker
+ style="overflow:visible;"
+ id="marker13"
+ refX="0.0"
+ refY="0.0"
+ orient="auto"
+ inkscape:stockid="Arrow2Mend">
+ <path
+ transform="scale(0.6) rotate(180) translate(-5,0)"
+ d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.9730900,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z "
+ style="font-size:12.0;fill-rule:evenodd;stroke-width:0.62500000;stroke-linejoin:round;"
+ id="path14"
+ sodipodi:nodetypes="cccc" />
+ </marker>
+ </defs>
+ <g
+ transform="translate(-367.9488,-513.0081)"
+ id="g193">
+ <path
+ id="path85"
+ d="M 377.45252,523.54977 C 377.45252,531.55430 377.45435,531.55430 377.45435,531.55430"
+ style="fill:none;fill-opacity:0.75000000;fill-rule:evenodd;stroke:#000000;stroke-width:1.0000000;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:4.0000000;stroke-opacity:1.0000000" />
+ <path
+ id="path347"
+ d="M 377.42440,513.51768 C 377.42440,521.52221 377.42623,521.52221 377.42623,521.52221"
+ style="fill:none;fill-opacity:0.75000000;fill-rule:evenodd;stroke:#000000;stroke-width:1.0000000;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:4.0000000;stroke-opacity:1.0000000" />
+ <path
+ id="path348"
+ d="M 376.44018,522.53611 C 368.43565,522.53611 368.43565,522.53794 368.43565,522.53794"
+ style="fill:none;fill-opacity:0.75000000;fill-rule:evenodd;stroke:#000000;stroke-width:1.0000000;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:4.0000000;stroke-opacity:1.0000000" />
+ <g
+ id="g29"
+ transform="translate(-0.290740,-0.387653)">
+ <path
+ sodipodi:type="arc"
+ style="fill:#00f5c5;fill-opacity:1.0000000;stroke:#000000;stroke-width:0.77524751;stroke-miterlimit:4.0000000;stroke-opacity:1.0000000"
+ id="path45"
+ sodipodi:cx="395.20569"
+ sodipodi:cy="531.23523"
+ sodipodi:rx="3.5248239"
+ sodipodi:ry="3.5248239"
+ d="M 398.73051 531.23523 A 3.5248239 3.5248239 0 1 1 391.68086,531.23523 A 3.5248239 3.5248239 0 1 1 398.73051 531.23523 z"
+ transform="matrix(2.612069,0.000000,0.000000,2.612069,-643.0990,-853.1921)" />
+ <text
+ xml:space="preserve"
+ style="font-size:13.000000;font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;fill:#000000;fill-opacity:1.0000000;stroke:none;stroke-width:1.0000000px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1.0000000;font-family:Arial;text-anchor:start;writing-mode:lr-tb"
+ x="383.70551"
+ y="539.07446"
+ id="text179"
+ sodipodi:linespacing="100%"><tspan
+ sodipodi:role="line"
+ id="tspan180"
+ x="383.70551"
+ y="539.07446">C</tspan></text>
+ </g>
+ <path
+ id="path349"
+ d="M 386.42981,522.49886 C 378.42528,522.49886 378.42528,522.50069 378.42528,522.50069"
+ style="fill:none;fill-opacity:0.75000000;fill-rule:evenodd;stroke:#000000;stroke-width:1.0000000;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:4.0000000;stroke-opacity:1.0000000" />
+ </g>
+</svg>
diff --git a/umbrello/umbrello/pics/sources/cursor-deep-history.svg b/umbrello/umbrello/pics/sources/cursor-deep-history.svg
new file mode 100644
index 00000000..2cb89831
--- /dev/null
+++ b/umbrello/umbrello/pics/sources/cursor-deep-history.svg
@@ -0,0 +1,206 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+<svg
+ xmlns:xml="http://www.w3.org/XML/1998/namespace"
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://web.resource.org/cc/"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:sodipodi="http://inkscape.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ inkscape:export-ydpi="90.000000"
+ inkscape:export-xdpi="90.000000"
+ inkscape:export-filename="F:\pics\cursor-junction.png"
+ sodipodi:docbase="F:\pics"
+ sodipodi:docname="cursor-deep-history.svg"
+ inkscape:version="0.40+cvs"
+ sodipodi:version="0.32"
+ version="1.0"
+ x="0.00000000"
+ y="0.00000000"
+ width="32.000000px"
+ height="32.000000px"
+ id="svg1">
+ <metadata
+ id="metadata17">
+ <rdf:RDF
+ id="RDF18">
+ <cc:Work
+ id="Work19"
+ rdf:about="">
+ <dc:format
+ id="format20">image/svg+xml</dc:format>
+ <dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage"
+ id="type21" />
+ </cc:Work>
+ </rdf:RDF>
+ </metadata>
+ <sodipodi:namedview
+ inkscape:current-layer="svg1"
+ inkscape:window-y="104"
+ inkscape:window-x="1861"
+ inkscape:cy="16.000000"
+ inkscape:cx="16.000000"
+ inkscape:zoom="21.750000"
+ inkscape:window-height="870"
+ inkscape:window-width="1111"
+ inkscape:pageshadow="2"
+ inkscape:pageopacity="0.0"
+ borderopacity="1.0"
+ bordercolor="#666666"
+ pagecolor="#ffffff"
+ id="base" />
+ <defs
+ id="defs3">
+ <marker
+ inkscape:stockid="Arrow2Mend"
+ orient="auto"
+ refY="0.0"
+ refX="0.0"
+ id="marker1"
+ style="overflow:visible;">
+ <path
+ sodipodi:nodetypes="cccc"
+ id="path2"
+ style="font-size:12.0;fill-rule:evenodd;stroke-width:0.62500000;stroke-linejoin:round;"
+ d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.9730900,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z "
+ transform="scale(0.6) rotate(180) translate(-5,0)" />
+ </marker>
+ <marker
+ inkscape:stockid="Arrow2Mend"
+ orient="auto"
+ refY="0.0"
+ refX="0.0"
+ id="Arrow2Mend"
+ style="overflow:visible;">
+ <path
+ sodipodi:nodetypes="cccc"
+ id="path237"
+ style="font-size:12.0;fill-rule:evenodd;stroke-width:0.62500000;stroke-linejoin:round;"
+ d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.9730900,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z "
+ transform="scale(0.6) rotate(180) translate(-5,0)" />
+ </marker>
+ <marker
+ inkscape:stockid="Arrow2Lend"
+ orient="auto"
+ refY="0.0"
+ refX="0.0"
+ id="marker258"
+ style="overflow:visible;">
+ <path
+ sodipodi:nodetypes="cccc"
+ id="path259"
+ style="font-size:12.0;fill-rule:evenodd;stroke-width:0.62500000;stroke-linejoin:round;"
+ d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.9730900,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z "
+ transform="scale(1.1) rotate(180) translate(-5,0)" />
+ </marker>
+ <marker
+ inkscape:stockid="Arrow2Lend"
+ orient="auto"
+ refY="0.0"
+ refX="0.0"
+ id="marker255"
+ style="overflow:visible;">
+ <path
+ sodipodi:nodetypes="cccc"
+ id="path256"
+ style="font-size:12.0;fill-rule:evenodd;stroke-width:0.62500000;stroke-linejoin:round;"
+ d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.9730900,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z "
+ transform="scale(1.1) rotate(180) translate(-5,0)" />
+ </marker>
+ <marker
+ inkscape:stockid="Arrow2Lend"
+ orient="auto"
+ refY="0.0"
+ refX="0.0"
+ id="marker252"
+ style="overflow:visible;">
+ <path
+ sodipodi:nodetypes="cccc"
+ id="path253"
+ style="font-size:12.0;fill-rule:evenodd;stroke-width:0.62500000;stroke-linejoin:round;"
+ d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.9730900,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z "
+ transform="scale(1.1) rotate(180) translate(-5,0)" />
+ </marker>
+ <marker
+ inkscape:stockid="Arrow2Lend"
+ orient="auto"
+ refY="0.0"
+ refX="0.0"
+ id="marker249"
+ style="overflow:visible;">
+ <path
+ sodipodi:nodetypes="cccc"
+ id="path250"
+ style="font-size:12.0;fill-rule:evenodd;stroke-width:0.62500000;stroke-linejoin:round;"
+ d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.9730900,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z "
+ transform="scale(1.1) rotate(180) translate(-5,0)" />
+ </marker>
+ <marker
+ inkscape:stockid="Arrow2Lend"
+ orient="auto"
+ refY="0.0"
+ refX="0.0"
+ id="Arrow2Lend"
+ style="overflow:visible;">
+ <path
+ sodipodi:nodetypes="cccc"
+ id="path238"
+ style="font-size:12.0;fill-rule:evenodd;stroke-width:0.62500000;stroke-linejoin:round;"
+ d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.9730900,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z "
+ transform="scale(1.1) rotate(180) translate(-5,0)" />
+ </marker>
+ </defs>
+ <g
+ transform="translate(-367.9537,-512.9979)"
+ id="g194">
+ <path
+ id="path85"
+ d="M 377.45252,523.54977 C 377.45252,531.55430 377.45435,531.55430 377.45435,531.55430"
+ style="fill:none;fill-opacity:0.75000000;fill-rule:evenodd;stroke:#000000;stroke-width:1.0000000;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:4.0000000;stroke-opacity:1.0000000" />
+ <path
+ id="path347"
+ d="M 377.42440,513.51768 C 377.42440,521.52221 377.42623,521.52221 377.42623,521.52221"
+ style="fill:none;fill-opacity:0.75000000;fill-rule:evenodd;stroke:#000000;stroke-width:1.0000000;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:4.0000000;stroke-opacity:1.0000000" />
+ <path
+ id="path348"
+ d="M 376.44018,522.53611 C 368.43565,522.53611 368.43565,522.53794 368.43565,522.53794"
+ style="fill:none;fill-opacity:0.75000000;fill-rule:evenodd;stroke:#000000;stroke-width:1.0000000;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:4.0000000;stroke-opacity:1.0000000" />
+ <path
+ id="path349"
+ d="M 386.42981,522.49886 C 378.42528,522.49886 378.42528,522.50069 378.42528,522.50069"
+ style="fill:none;fill-opacity:0.75000000;fill-rule:evenodd;stroke:#000000;stroke-width:1.0000000;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:4.0000000;stroke-opacity:1.0000000" />
+ <g
+ id="g91"
+ transform="translate(-4.030134,5.404877)">
+ <path
+ d="M 402.82519,529.87519 C 402.82519,534.58139 399.02964,538.39651 394.34760,538.39651 C 389.66555,538.39651 385.87000,534.58139 385.87000,529.87519 C 385.87000,525.16900 389.66555,521.35388 394.34760,521.35388 C 399.02964,521.35388 402.82519,525.16900 402.82519,529.87519 z "
+ style="fill:none;stroke:#d30000;stroke-width:1.2500000;stroke-miterlimit:4.0000000;stroke-opacity:1.0000000"
+ id="path21" />
+ <text
+ x="387.91888"
+ y="535.10229"
+ style="font-size:12.000000;font-style:normal;font-weight:normal;fill:#000000;fill-opacity:1.0000000;stroke:none;stroke-width:1.0000000px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1.0000000;font-family:Bitstream Vera Sans;text-anchor:start;writing-mode:lr-tb"
+ id="text111"
+ xml:space="preserve"
+ sodipodi:linespacing="100%"><tspan
+ x="387.91888"
+ y="535.10229"
+ sodipodi:role="line"
+ id="tspan1">H</tspan></text>
+ <text
+ xml:space="preserve"
+ style="font-size:11.000000;font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;fill:#000000;fill-opacity:1.0000000;stroke:none;stroke-width:1.0000000px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1.0000000;font-family:Arial;text-anchor:start;writing-mode:lr-tb"
+ x="396.16739"
+ y="532.53491"
+ id="text2"
+ sodipodi:linespacing="100%"><tspan
+ sodipodi:role="line"
+ id="tspan3"
+ x="396.16739"
+ y="532.53491">*</tspan></text>
+ </g>
+ </g>
+</svg>
diff --git a/umbrello/umbrello/pics/sources/cursor-join.svg b/umbrello/umbrello/pics/sources/cursor-join.svg
new file mode 100644
index 00000000..f84032bb
--- /dev/null
+++ b/umbrello/umbrello/pics/sources/cursor-join.svg
@@ -0,0 +1,289 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+<svg
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://web.resource.org/cc/"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:sodipodi="http://inkscape.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ inkscape:export-ydpi="90.000000"
+ inkscape:export-xdpi="90.000000"
+ inkscape:export-filename="F:\pics\cursor-junction.png"
+ sodipodi:docbase="F:\pics"
+ sodipodi:docname="cursor-join.svg"
+ inkscape:version="0.40+cvs"
+ sodipodi:version="0.32"
+ version="1.0"
+ x="0.00000000"
+ y="0.00000000"
+ width="32.000000px"
+ height="32.000000px"
+ id="svg1">
+ <metadata
+ id="metadata17">
+ <rdf:RDF
+ id="RDF18">
+ <cc:Work
+ id="Work19"
+ rdf:about="">
+ <dc:format
+ id="format20">image/svg+xml</dc:format>
+ <dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage"
+ id="type21" />
+ </cc:Work>
+ </rdf:RDF>
+ </metadata>
+ <sodipodi:namedview
+ inkscape:current-layer="svg1"
+ inkscape:window-y="104"
+ inkscape:window-x="1861"
+ inkscape:cy="16.000000"
+ inkscape:cx="16.000000"
+ inkscape:zoom="21.750000"
+ inkscape:window-height="870"
+ inkscape:window-width="1111"
+ inkscape:pageshadow="2"
+ inkscape:pageopacity="0.0"
+ borderopacity="1.0"
+ bordercolor="#666666"
+ pagecolor="#ffffff"
+ id="base" />
+ <defs
+ id="defs3">
+ <marker
+ inkscape:stockid="Arrow2Mend"
+ orient="auto"
+ refY="0.0"
+ refX="0.0"
+ id="marker200"
+ style="overflow:visible;">
+ <path
+ sodipodi:nodetypes="cccc"
+ id="path201"
+ style="font-size:12.0;fill-rule:evenodd;stroke-width:0.62500000;stroke-linejoin:round;"
+ d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.9730900,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z "
+ transform="scale(0.6) rotate(180) translate(-5,0)" />
+ </marker>
+ <marker
+ inkscape:stockid="Arrow2Mend"
+ orient="auto"
+ refY="0.0"
+ refX="0.0"
+ id="marker198"
+ style="overflow:visible;">
+ <path
+ sodipodi:nodetypes="cccc"
+ id="path199"
+ style="font-size:12.0;fill-rule:evenodd;stroke-width:0.62500000;stroke-linejoin:round;"
+ d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.9730900,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z "
+ transform="scale(0.6) rotate(180) translate(-5,0)" />
+ </marker>
+ <marker
+ inkscape:stockid="Arrow2Mend"
+ orient="auto"
+ refY="0.0"
+ refX="0.0"
+ id="marker196"
+ style="overflow:visible;">
+ <path
+ sodipodi:nodetypes="cccc"
+ id="path197"
+ style="font-size:12.0;fill-rule:evenodd;stroke-width:0.62500000;stroke-linejoin:round;"
+ d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.9730900,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z "
+ transform="scale(0.6) rotate(180) translate(-5,0)" />
+ </marker>
+ <marker
+ inkscape:stockid="Arrow2Mend"
+ orient="auto"
+ refY="0.0"
+ refX="0.0"
+ id="marker1"
+ style="overflow:visible;">
+ <path
+ sodipodi:nodetypes="cccc"
+ id="path2"
+ style="font-size:12.0;fill-rule:evenodd;stroke-width:0.62500000;stroke-linejoin:round;"
+ d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.9730900,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z "
+ transform="scale(0.6) rotate(180) translate(-5,0)" />
+ </marker>
+ <marker
+ inkscape:stockid="Arrow2Mend"
+ orient="auto"
+ refY="0.0"
+ refX="0.0"
+ id="Arrow2Mend"
+ style="overflow:visible;">
+ <path
+ sodipodi:nodetypes="cccc"
+ id="path237"
+ style="font-size:12.0;fill-rule:evenodd;stroke-width:0.62500000;stroke-linejoin:round;"
+ d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.9730900,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z "
+ transform="scale(0.6) rotate(180) translate(-5,0)" />
+ </marker>
+ <marker
+ inkscape:stockid="Arrow2Lend"
+ orient="auto"
+ refY="0.0"
+ refX="0.0"
+ id="marker258"
+ style="overflow:visible;">
+ <path
+ sodipodi:nodetypes="cccc"
+ id="path259"
+ style="font-size:12.0;fill-rule:evenodd;stroke-width:0.62500000;stroke-linejoin:round;"
+ d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.9730900,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z "
+ transform="scale(1.1) rotate(180) translate(-5,0)" />
+ </marker>
+ <marker
+ inkscape:stockid="Arrow2Lend"
+ orient="auto"
+ refY="0.0"
+ refX="0.0"
+ id="marker255"
+ style="overflow:visible;">
+ <path
+ sodipodi:nodetypes="cccc"
+ id="path256"
+ style="font-size:12.0;fill-rule:evenodd;stroke-width:0.62500000;stroke-linejoin:round;"
+ d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.9730900,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z "
+ transform="scale(1.1) rotate(180) translate(-5,0)" />
+ </marker>
+ <marker
+ inkscape:stockid="Arrow2Lend"
+ orient="auto"
+ refY="0.0"
+ refX="0.0"
+ id="marker252"
+ style="overflow:visible;">
+ <path
+ sodipodi:nodetypes="cccc"
+ id="path253"
+ style="font-size:12.0;fill-rule:evenodd;stroke-width:0.62500000;stroke-linejoin:round;"
+ d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.9730900,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z "
+ transform="scale(1.1) rotate(180) translate(-5,0)" />
+ </marker>
+ <marker
+ inkscape:stockid="Arrow2Lend"
+ orient="auto"
+ refY="0.0"
+ refX="0.0"
+ id="marker249"
+ style="overflow:visible;">
+ <path
+ sodipodi:nodetypes="cccc"
+ id="path250"
+ style="font-size:12.0;fill-rule:evenodd;stroke-width:0.62500000;stroke-linejoin:round;"
+ d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.9730900,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z "
+ transform="scale(1.1) rotate(180) translate(-5,0)" />
+ </marker>
+ <marker
+ inkscape:stockid="Arrow2Lend"
+ orient="auto"
+ refY="0.0"
+ refX="0.0"
+ id="Arrow2Lend"
+ style="overflow:visible;">
+ <path
+ sodipodi:nodetypes="cccc"
+ id="path238"
+ style="font-size:12.0;fill-rule:evenodd;stroke-width:0.62500000;stroke-linejoin:round;"
+ d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.9730900,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z "
+ transform="scale(1.1) rotate(180) translate(-5,0)" />
+ </marker>
+ <marker
+ style="overflow:visible;"
+ id="marker12"
+ refX="0.0"
+ refY="0.0"
+ orient="auto"
+ inkscape:stockid="Arrow2Lend">
+ <path
+ transform="scale(1.1) rotate(180) translate(-5,0)"
+ d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.9730900,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z "
+ style="font-size:12.0;fill-rule:evenodd;stroke-width:0.62500000;stroke-linejoin:round;"
+ id="path455"
+ sodipodi:nodetypes="cccc" />
+ </marker>
+ <marker
+ style="overflow:visible;"
+ id="marker11"
+ refX="0.0"
+ refY="0.0"
+ orient="auto"
+ inkscape:stockid="Arrow2Mend">
+ <path
+ transform="scale(0.6) rotate(180) translate(-5,0)"
+ d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.9730900,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z "
+ style="font-size:12.0;fill-rule:evenodd;stroke-width:0.62500000;stroke-linejoin:round;"
+ id="path454"
+ sodipodi:nodetypes="cccc" />
+ </marker>
+ <marker
+ style="overflow:visible;"
+ id="marker553"
+ refX="0.0"
+ refY="0.0"
+ orient="auto"
+ inkscape:stockid="Arrow2Mend">
+ <path
+ transform="scale(0.6) rotate(180) translate(-5,0)"
+ d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.9730900,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z "
+ style="font-size:12.0;fill-rule:evenodd;stroke-width:0.62500000;stroke-linejoin:round;"
+ id="path554"
+ sodipodi:nodetypes="cccc" />
+ </marker>
+ <marker
+ style="overflow:visible;"
+ id="marker556"
+ refX="0.0"
+ refY="0.0"
+ orient="auto"
+ inkscape:stockid="Arrow2Mend">
+ <path
+ transform="scale(0.6) rotate(180) translate(-5,0)"
+ d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.9730900,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z "
+ style="font-size:12.0;fill-rule:evenodd;stroke-width:0.62500000;stroke-linejoin:round;"
+ id="path557"
+ sodipodi:nodetypes="cccc" />
+ </marker>
+ </defs>
+ <g
+ transform="translate(-367.9454,-513.0373)"
+ id="g195">
+ <path
+ id="path85"
+ d="M 377.45252,523.54977 C 377.45252,531.55430 377.45435,531.55430 377.45435,531.55430"
+ style="fill:none;fill-opacity:0.75000000;fill-rule:evenodd;stroke:#000000;stroke-width:1.0000000;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:4.0000000;stroke-opacity:1.0000000" />
+ <path
+ id="path347"
+ d="M 377.42440,513.51768 C 377.42440,521.52221 377.42623,521.52221 377.42623,521.52221"
+ style="fill:none;fill-opacity:0.75000000;fill-rule:evenodd;stroke:#000000;stroke-width:1.0000000;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:4.0000000;stroke-opacity:1.0000000" />
+ <path
+ id="path348"
+ d="M 376.44018,522.53611 C 368.43565,522.53611 368.43565,522.53794 368.43565,522.53794"
+ style="fill:none;fill-opacity:0.75000000;fill-rule:evenodd;stroke:#000000;stroke-width:1.0000000;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:4.0000000;stroke-opacity:1.0000000" />
+ <path
+ id="path349"
+ d="M 386.42981,522.49886 C 378.42528,522.49886 378.42528,522.50069 378.42528,522.50069"
+ style="fill:none;fill-opacity:0.75000000;fill-rule:evenodd;stroke:#000000;stroke-width:1.0000000;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:4.0000000;stroke-opacity:1.0000000" />
+ <path
+ id="path15"
+ d="M 389.38956,527.73586 C 389.39744,543.12488 389.39744,543.12488 389.39744,543.12488 L 389.39744,543.12488"
+ style="fill:none;fill-opacity:0.75000000;fill-rule:evenodd;stroke:#000000;stroke-width:2.0250001;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:4.0000000;stroke-opacity:1.0000000" />
+ <path
+ id="path16"
+ d="M 390.87505,535.72872 L 396.61921,535.72872"
+ style="fill:none;fill-opacity:0.75000000;fill-rule:evenodd;stroke:#000000;stroke-width:0.60290909px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1.0000000;marker-start:none;marker-mid:none;marker-end:url(#Arrow2Mend)" />
+ <path
+ id="path555"
+ d="M 379.68711,540.10437 L 385.43127,540.10437"
+ style="fill:none;fill-opacity:0.75000000;fill-rule:evenodd;stroke:#000000;stroke-width:0.60290909px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1.0000000;marker-start:none;marker-mid:none;marker-end:url(#Arrow2Mend)" />
+ <path
+ id="path558"
+ d="M 379.68711,530.50226 L 385.43127,530.50226"
+ style="fill:none;fill-opacity:0.75000000;fill-rule:evenodd;stroke:#000000;stroke-width:0.60290909px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1.0000000;marker-start:none;marker-mid:none;marker-end:url(#Arrow2Mend)" />
+ </g>
+</svg>
diff --git a/umbrello/umbrello/pics/sources/cursor-junction.svg b/umbrello/umbrello/pics/sources/cursor-junction.svg
new file mode 100644
index 00000000..73154f52
--- /dev/null
+++ b/umbrello/umbrello/pics/sources/cursor-junction.svg
@@ -0,0 +1,279 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+<svg
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://web.resource.org/cc/"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:sodipodi="http://inkscape.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ id="svg1"
+ height="32.000000px"
+ width="32.000000px"
+ y="0.00000000"
+ x="0.00000000"
+ version="1.0"
+ sodipodi:version="0.32"
+ inkscape:version="0.40+cvs"
+ sodipodi:docname="cursor-junction.svg"
+ sodipodi:docbase="F:\pics"
+ inkscape:export-filename="F:\pics\cursor-junction.png"
+ inkscape:export-xdpi="90.000000"
+ inkscape:export-ydpi="90.000000">
+ <metadata
+ id="metadata17">
+ <rdf:RDF
+ id="RDF18">
+ <cc:Work
+ rdf:about=""
+ id="Work19">
+ <dc:format
+ id="format20">image/svg+xml</dc:format>
+ <dc:type
+ id="type21"
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+ </cc:Work>
+ </rdf:RDF>
+ </metadata>
+ <sodipodi:namedview
+ id="base"
+ pagecolor="#ffffff"
+ bordercolor="#666666"
+ borderopacity="1.0"
+ inkscape:pageopacity="0.0"
+ inkscape:pageshadow="2"
+ inkscape:window-width="810"
+ inkscape:window-height="682"
+ inkscape:zoom="15.875000"
+ inkscape:cx="16.000000"
+ inkscape:cy="16.000000"
+ inkscape:window-x="1861"
+ inkscape:window-y="104"
+ inkscape:current-layer="svg1" />
+ <defs
+ id="defs3">
+ <marker
+ style="overflow:visible;"
+ id="marker211"
+ refX="0.0"
+ refY="0.0"
+ orient="auto"
+ inkscape:stockid="Arrow2Mend">
+ <path
+ transform="scale(0.6) rotate(180) translate(-5,0)"
+ d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.9730900,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z "
+ style="font-size:12.0;fill-rule:evenodd;stroke-width:0.62500000;stroke-linejoin:round;"
+ id="path212"
+ sodipodi:nodetypes="cccc" />
+ </marker>
+ <marker
+ style="overflow:visible;"
+ id="marker209"
+ refX="0.0"
+ refY="0.0"
+ orient="auto"
+ inkscape:stockid="Arrow2Mend">
+ <path
+ transform="scale(0.6) rotate(180) translate(-5,0)"
+ d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.9730900,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z "
+ style="font-size:12.0;fill-rule:evenodd;stroke-width:0.62500000;stroke-linejoin:round;"
+ id="path210"
+ sodipodi:nodetypes="cccc" />
+ </marker>
+ <marker
+ style="overflow:visible;"
+ id="marker207"
+ refX="0.0"
+ refY="0.0"
+ orient="auto"
+ inkscape:stockid="Arrow2Mend">
+ <path
+ transform="scale(0.6) rotate(180) translate(-5,0)"
+ d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.9730900,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z "
+ style="font-size:12.0;fill-rule:evenodd;stroke-width:0.62500000;stroke-linejoin:round;"
+ id="path208"
+ sodipodi:nodetypes="cccc" />
+ </marker>
+ <marker
+ style="overflow:visible;"
+ id="marker205"
+ refX="0.0"
+ refY="0.0"
+ orient="auto"
+ inkscape:stockid="Arrow2Mend">
+ <path
+ transform="scale(0.6) rotate(180) translate(-5,0)"
+ d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.9730900,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z "
+ style="font-size:12.0;fill-rule:evenodd;stroke-width:0.62500000;stroke-linejoin:round;"
+ id="path206"
+ sodipodi:nodetypes="cccc" />
+ </marker>
+ <marker
+ style="overflow:visible;"
+ id="marker203"
+ refX="0.0"
+ refY="0.0"
+ orient="auto"
+ inkscape:stockid="Arrow2Mend">
+ <path
+ transform="scale(0.6) rotate(180) translate(-5,0)"
+ d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.9730900,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z "
+ style="font-size:12.0;fill-rule:evenodd;stroke-width:0.62500000;stroke-linejoin:round;"
+ id="path204"
+ sodipodi:nodetypes="cccc" />
+ </marker>
+ <marker
+ style="overflow:visible;"
+ id="marker1"
+ refX="0.0"
+ refY="0.0"
+ orient="auto"
+ inkscape:stockid="Arrow2Mend">
+ <path
+ transform="scale(0.6) rotate(180) translate(-5,0)"
+ d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.9730900,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z "
+ style="font-size:12.0;fill-rule:evenodd;stroke-width:0.62500000;stroke-linejoin:round;"
+ id="path2"
+ sodipodi:nodetypes="cccc" />
+ </marker>
+ <marker
+ style="overflow:visible;"
+ id="Arrow2Mend"
+ refX="0.0"
+ refY="0.0"
+ orient="auto"
+ inkscape:stockid="Arrow2Mend">
+ <path
+ transform="scale(0.6) rotate(180) translate(-5,0)"
+ d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.9730900,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z "
+ style="font-size:12.0;fill-rule:evenodd;stroke-width:0.62500000;stroke-linejoin:round;"
+ id="path237"
+ sodipodi:nodetypes="cccc" />
+ </marker>
+ <marker
+ style="overflow:visible;"
+ id="marker258"
+ refX="0.0"
+ refY="0.0"
+ orient="auto"
+ inkscape:stockid="Arrow2Lend">
+ <path
+ transform="scale(1.1) rotate(180) translate(-5,0)"
+ d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.9730900,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z "
+ style="font-size:12.0;fill-rule:evenodd;stroke-width:0.62500000;stroke-linejoin:round;"
+ id="path259"
+ sodipodi:nodetypes="cccc" />
+ </marker>
+ <marker
+ style="overflow:visible;"
+ id="marker255"
+ refX="0.0"
+ refY="0.0"
+ orient="auto"
+ inkscape:stockid="Arrow2Lend">
+ <path
+ transform="scale(1.1) rotate(180) translate(-5,0)"
+ d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.9730900,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z "
+ style="font-size:12.0;fill-rule:evenodd;stroke-width:0.62500000;stroke-linejoin:round;"
+ id="path256"
+ sodipodi:nodetypes="cccc" />
+ </marker>
+ <marker
+ style="overflow:visible;"
+ id="marker252"
+ refX="0.0"
+ refY="0.0"
+ orient="auto"
+ inkscape:stockid="Arrow2Lend">
+ <path
+ transform="scale(1.1) rotate(180) translate(-5,0)"
+ d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.9730900,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z "
+ style="font-size:12.0;fill-rule:evenodd;stroke-width:0.62500000;stroke-linejoin:round;"
+ id="path253"
+ sodipodi:nodetypes="cccc" />
+ </marker>
+ <marker
+ style="overflow:visible;"
+ id="marker249"
+ refX="0.0"
+ refY="0.0"
+ orient="auto"
+ inkscape:stockid="Arrow2Lend">
+ <path
+ transform="scale(1.1) rotate(180) translate(-5,0)"
+ d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.9730900,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z "
+ style="font-size:12.0;fill-rule:evenodd;stroke-width:0.62500000;stroke-linejoin:round;"
+ id="path250"
+ sodipodi:nodetypes="cccc" />
+ </marker>
+ <marker
+ style="overflow:visible;"
+ id="Arrow2Lend"
+ refX="0.0"
+ refY="0.0"
+ orient="auto"
+ inkscape:stockid="Arrow2Lend">
+ <path
+ transform="scale(1.1) rotate(180) translate(-5,0)"
+ d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.9730900,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z "
+ style="font-size:12.0;fill-rule:evenodd;stroke-width:0.62500000;stroke-linejoin:round;"
+ id="path238"
+ sodipodi:nodetypes="cccc" />
+ </marker>
+ </defs>
+ <g
+ transform="translate(-367.9140,-513.0387)"
+ id="g202">
+ <g
+ id="g350"
+ transform="translate(-3.391966,4.458013)">
+ <path
+ sodipodi:type="arc"
+ style="fill:#000000;fill-opacity:1.0000000;stroke:none;stroke-width:0.20000000;stroke-miterlimit:4.0000000;stroke-opacity:0.68161434"
+ id="path45"
+ sodipodi:cx="395.20569"
+ sodipodi:cy="531.23523"
+ sodipodi:rx="3.5248239"
+ sodipodi:ry="3.5248239"
+ d="M 398.73051 531.23523 A 3.5248239 3.5248239 0 1 1 391.68086,531.23523 A 3.5248239 3.5248239 0 1 1 398.73051 531.23523 z"
+ transform="translate(-0.668501,-2.243091)" />
+ <path
+ style="fill:none;fill-opacity:0.75000000;fill-rule:evenodd;stroke:#000000;stroke-width:0.61250001;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4.0000000;stroke-opacity:1.0000000;marker-end:url(#Arrow2Mend)"
+ d="M 386.54045,519.66500 L 390.14727,524.34150"
+ id="path134" />
+ <path
+ style="fill:none;fill-opacity:0.75000000;fill-rule:evenodd;stroke:#000000;stroke-width:0.61250001;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4.0000000;stroke-opacity:1.0000000;marker-end:url(#Arrow2Mend)"
+ d="M 402.60019,519.65950 L 398.99337,524.33600"
+ id="path251" />
+ <path
+ style="fill:none;fill-opacity:0.75000000;fill-rule:evenodd;stroke:#000000;stroke-width:0.61250001;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4.0000000;stroke-opacity:1.0000000;marker-end:url(#Arrow2Mend)"
+ d="M 394.57026,531.49266 L 394.66966,537.39766"
+ id="path254" />
+ <path
+ style="fill:none;fill-opacity:0.75000000;fill-rule:evenodd;stroke:#000000;stroke-width:0.61250001;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4.0000000;stroke-opacity:1.0000000;marker-end:url(#Arrow2Mend)"
+ d="M 396.98786,531.45492 L 400.59468,536.13142"
+ id="path260" />
+ <path
+ style="fill:none;fill-opacity:0.75000000;fill-rule:evenodd;stroke:#000000;stroke-width:0.61250001;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4.0000000;stroke-opacity:1.0000000;marker-end:url(#Arrow2Mend)"
+ d="M 392.59468,531.45492 L 388.98786,536.13142"
+ id="path435" />
+ </g>
+ <path
+ style="fill:none;fill-opacity:0.75000000;fill-rule:evenodd;stroke:#000000;stroke-width:1.0000000;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:4.0000000;stroke-opacity:1.0000000"
+ d="M 377.45252,523.54977 C 377.45252,531.55430 377.45435,531.55430 377.45435,531.55430"
+ id="path85" />
+ <path
+ style="fill:none;fill-opacity:0.75000000;fill-rule:evenodd;stroke:#000000;stroke-width:1.0000000;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:4.0000000;stroke-opacity:1.0000000"
+ d="M 377.42440,513.51768 C 377.42440,521.52221 377.42623,521.52221 377.42623,521.52221"
+ id="path347" />
+ <path
+ style="fill:none;fill-opacity:0.75000000;fill-rule:evenodd;stroke:#000000;stroke-width:1.0000000;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:4.0000000;stroke-opacity:1.0000000"
+ d="M 376.44018,522.53611 C 368.43565,522.53611 368.43565,522.53794 368.43565,522.53794"
+ id="path348" />
+ <path
+ style="fill:none;fill-opacity:0.75000000;fill-rule:evenodd;stroke:#000000;stroke-width:1.0000000;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:4.0000000;stroke-opacity:1.0000000"
+ d="M 386.42981,522.49886 C 378.42528,522.49886 378.42528,522.50069 378.42528,522.50069"
+ id="path349" />
+ </g>
+</svg>
diff --git a/umbrello/umbrello/pics/sources/cursor-shallow-history.svg b/umbrello/umbrello/pics/sources/cursor-shallow-history.svg
new file mode 100644
index 00000000..8f840682
--- /dev/null
+++ b/umbrello/umbrello/pics/sources/cursor-shallow-history.svg
@@ -0,0 +1,195 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+<svg
+ xmlns:xml="http://www.w3.org/XML/1998/namespace"
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://web.resource.org/cc/"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:sodipodi="http://inkscape.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ id="svg1"
+ height="32.000000px"
+ width="32.000000px"
+ y="0.00000000"
+ x="0.00000000"
+ version="1.0"
+ sodipodi:version="0.32"
+ inkscape:version="0.40+cvs"
+ sodipodi:docname="cursor-shallow-history.svg"
+ sodipodi:docbase="F:\pics"
+ inkscape:export-filename="F:\pics\cursor-junction.png"
+ inkscape:export-xdpi="90.000000"
+ inkscape:export-ydpi="90.000000">
+ <metadata
+ id="metadata17">
+ <rdf:RDF
+ id="RDF18">
+ <cc:Work
+ rdf:about=""
+ id="Work19">
+ <dc:format
+ id="format20">image/svg+xml</dc:format>
+ <dc:type
+ id="type21"
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+ </cc:Work>
+ </rdf:RDF>
+ </metadata>
+ <sodipodi:namedview
+ id="base"
+ pagecolor="#ffffff"
+ bordercolor="#666666"
+ borderopacity="1.0"
+ inkscape:pageopacity="0.0"
+ inkscape:pageshadow="2"
+ inkscape:window-width="1111"
+ inkscape:window-height="870"
+ inkscape:zoom="21.750000"
+ inkscape:cx="16.000000"
+ inkscape:cy="16.000000"
+ inkscape:window-x="1861"
+ inkscape:window-y="104"
+ inkscape:current-layer="svg1" />
+ <defs
+ id="defs3">
+ <marker
+ style="overflow:visible;"
+ id="marker1"
+ refX="0.0"
+ refY="0.0"
+ orient="auto"
+ inkscape:stockid="Arrow2Mend">
+ <path
+ transform="scale(0.6) rotate(180) translate(-5,0)"
+ d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.9730900,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z "
+ style="font-size:12.0;fill-rule:evenodd;stroke-width:0.62500000;stroke-linejoin:round;"
+ id="path2"
+ sodipodi:nodetypes="cccc" />
+ </marker>
+ <marker
+ style="overflow:visible;"
+ id="Arrow2Mend"
+ refX="0.0"
+ refY="0.0"
+ orient="auto"
+ inkscape:stockid="Arrow2Mend">
+ <path
+ transform="scale(0.6) rotate(180) translate(-5,0)"
+ d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.9730900,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z "
+ style="font-size:12.0;fill-rule:evenodd;stroke-width:0.62500000;stroke-linejoin:round;"
+ id="path237"
+ sodipodi:nodetypes="cccc" />
+ </marker>
+ <marker
+ style="overflow:visible;"
+ id="marker258"
+ refX="0.0"
+ refY="0.0"
+ orient="auto"
+ inkscape:stockid="Arrow2Lend">
+ <path
+ transform="scale(1.1) rotate(180) translate(-5,0)"
+ d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.9730900,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z "
+ style="font-size:12.0;fill-rule:evenodd;stroke-width:0.62500000;stroke-linejoin:round;"
+ id="path259"
+ sodipodi:nodetypes="cccc" />
+ </marker>
+ <marker
+ style="overflow:visible;"
+ id="marker255"
+ refX="0.0"
+ refY="0.0"
+ orient="auto"
+ inkscape:stockid="Arrow2Lend">
+ <path
+ transform="scale(1.1) rotate(180) translate(-5,0)"
+ d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.9730900,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z "
+ style="font-size:12.0;fill-rule:evenodd;stroke-width:0.62500000;stroke-linejoin:round;"
+ id="path256"
+ sodipodi:nodetypes="cccc" />
+ </marker>
+ <marker
+ style="overflow:visible;"
+ id="marker252"
+ refX="0.0"
+ refY="0.0"
+ orient="auto"
+ inkscape:stockid="Arrow2Lend">
+ <path
+ transform="scale(1.1) rotate(180) translate(-5,0)"
+ d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.9730900,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z "
+ style="font-size:12.0;fill-rule:evenodd;stroke-width:0.62500000;stroke-linejoin:round;"
+ id="path253"
+ sodipodi:nodetypes="cccc" />
+ </marker>
+ <marker
+ style="overflow:visible;"
+ id="marker249"
+ refX="0.0"
+ refY="0.0"
+ orient="auto"
+ inkscape:stockid="Arrow2Lend">
+ <path
+ transform="scale(1.1) rotate(180) translate(-5,0)"
+ d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.9730900,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z "
+ style="font-size:12.0;fill-rule:evenodd;stroke-width:0.62500000;stroke-linejoin:round;"
+ id="path250"
+ sodipodi:nodetypes="cccc" />
+ </marker>
+ <marker
+ style="overflow:visible;"
+ id="Arrow2Lend"
+ refX="0.0"
+ refY="0.0"
+ orient="auto"
+ inkscape:stockid="Arrow2Lend">
+ <path
+ transform="scale(1.1) rotate(180) translate(-5,0)"
+ d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.9730900,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z "
+ style="font-size:12.0;fill-rule:evenodd;stroke-width:0.62500000;stroke-linejoin:round;"
+ id="path238"
+ sodipodi:nodetypes="cccc" />
+ </marker>
+ </defs>
+ <g
+ transform="translate(-367.9487,-513.0004)"
+ id="g213">
+ <path
+ style="fill:none;fill-opacity:0.75000000;fill-rule:evenodd;stroke:#000000;stroke-width:1.0000000;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:4.0000000;stroke-opacity:1.0000000"
+ d="M 377.45252,523.54977 C 377.45252,531.55430 377.45435,531.55430 377.45435,531.55430"
+ id="path85" />
+ <path
+ style="fill:none;fill-opacity:0.75000000;fill-rule:evenodd;stroke:#000000;stroke-width:1.0000000;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:4.0000000;stroke-opacity:1.0000000"
+ d="M 377.42440,513.51768 C 377.42440,521.52221 377.42623,521.52221 377.42623,521.52221"
+ id="path347" />
+ <path
+ style="fill:none;fill-opacity:0.75000000;fill-rule:evenodd;stroke:#000000;stroke-width:1.0000000;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:4.0000000;stroke-opacity:1.0000000"
+ d="M 376.44018,522.53611 C 368.43565,522.53611 368.43565,522.53794 368.43565,522.53794"
+ id="path348" />
+ <g
+ id="g15"
+ transform="translate(-0.484567,0.193827)">
+ <path
+ id="path12"
+ style="fill:none;stroke:#d30000;stroke-width:1.2500000;stroke-miterlimit:4.0000000;stroke-opacity:1.0000000"
+ d="M 399.08565,535.18315 C 399.08565,539.88935 395.29010,543.70447 390.60806,543.70447 C 385.92601,543.70447 382.13046,539.88935 382.13046,535.18315 C 382.13046,530.47696 385.92601,526.66184 390.60806,526.66184 C 395.29010,526.66184 399.08565,530.47696 399.08565,535.18315 z " />
+ <text
+ xml:space="preserve"
+ id="text13"
+ style="font-size:12.000000;font-style:normal;font-weight:normal;fill:#000000;fill-opacity:1.0000000;stroke:none;stroke-width:1.0000000px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1.0000000;font-family:Bitstream Vera Sans;text-anchor:start;writing-mode:lr-tb"
+ y="539.54547"
+ x="385.79855"
+ sodipodi:linespacing="100%"><tspan
+ x="385.79855"
+ y="539.54547"
+ sodipodi:role="line"
+ id="tspan22">H</tspan></text>
+ </g>
+ <path
+ style="fill:none;fill-opacity:0.75000000;fill-rule:evenodd;stroke:#000000;stroke-width:1.0000000;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:4.0000000;stroke-opacity:1.0000000"
+ d="M 386.42981,522.49886 C 378.42528,522.49886 378.42528,522.50069 378.42528,522.50069"
+ id="path349" />
+ </g>
+</svg>
diff --git a/umbrello/umbrello/pics/sources/cursor-state-fork.svg b/umbrello/umbrello/pics/sources/cursor-state-fork.svg
new file mode 100644
index 00000000..92f6fa29
--- /dev/null
+++ b/umbrello/umbrello/pics/sources/cursor-state-fork.svg
@@ -0,0 +1,289 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+<svg
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://web.resource.org/cc/"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:sodipodi="http://inkscape.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ id="svg1"
+ height="32.000000px"
+ width="32.000000px"
+ y="0.00000000"
+ x="0.00000000"
+ version="1.0"
+ sodipodi:version="0.32"
+ inkscape:version="0.40+cvs"
+ sodipodi:docname="cursor-state-fork.svg"
+ sodipodi:docbase="F:\pics"
+ inkscape:export-filename="F:\pics\cursor-junction.png"
+ inkscape:export-xdpi="90.000000"
+ inkscape:export-ydpi="90.000000">
+ <metadata
+ id="metadata17">
+ <rdf:RDF
+ id="RDF18">
+ <cc:Work
+ rdf:about=""
+ id="Work19">
+ <dc:format
+ id="format20">image/svg+xml</dc:format>
+ <dc:type
+ id="type21"
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+ </cc:Work>
+ </rdf:RDF>
+ </metadata>
+ <sodipodi:namedview
+ id="base"
+ pagecolor="#ffffff"
+ bordercolor="#666666"
+ borderopacity="1.0"
+ inkscape:pageopacity="0.0"
+ inkscape:pageshadow="2"
+ inkscape:window-width="1111"
+ inkscape:window-height="870"
+ inkscape:zoom="21.750000"
+ inkscape:cx="16.000000"
+ inkscape:cy="16.000000"
+ inkscape:window-x="1861"
+ inkscape:window-y="104"
+ inkscape:current-layer="svg1" />
+ <defs
+ id="defs3">
+ <marker
+ style="overflow:visible;"
+ id="marker219"
+ refX="0.0"
+ refY="0.0"
+ orient="auto"
+ inkscape:stockid="Arrow2Mend">
+ <path
+ transform="scale(0.6) rotate(180) translate(-5,0)"
+ d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.9730900,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z "
+ style="font-size:12.0;fill-rule:evenodd;stroke-width:0.62500000;stroke-linejoin:round;"
+ id="path220"
+ sodipodi:nodetypes="cccc" />
+ </marker>
+ <marker
+ style="overflow:visible;"
+ id="marker217"
+ refX="0.0"
+ refY="0.0"
+ orient="auto"
+ inkscape:stockid="Arrow2Mend">
+ <path
+ transform="scale(0.6) rotate(180) translate(-5,0)"
+ d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.9730900,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z "
+ style="font-size:12.0;fill-rule:evenodd;stroke-width:0.62500000;stroke-linejoin:round;"
+ id="path218"
+ sodipodi:nodetypes="cccc" />
+ </marker>
+ <marker
+ style="overflow:visible;"
+ id="marker215"
+ refX="0.0"
+ refY="0.0"
+ orient="auto"
+ inkscape:stockid="Arrow2Mend">
+ <path
+ transform="scale(0.6) rotate(180) translate(-5,0)"
+ d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.9730900,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z "
+ style="font-size:12.0;fill-rule:evenodd;stroke-width:0.62500000;stroke-linejoin:round;"
+ id="path216"
+ sodipodi:nodetypes="cccc" />
+ </marker>
+ <marker
+ style="overflow:visible;"
+ id="marker1"
+ refX="0.0"
+ refY="0.0"
+ orient="auto"
+ inkscape:stockid="Arrow2Mend">
+ <path
+ transform="scale(0.6) rotate(180) translate(-5,0)"
+ d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.9730900,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z "
+ style="font-size:12.0;fill-rule:evenodd;stroke-width:0.62500000;stroke-linejoin:round;"
+ id="path2"
+ sodipodi:nodetypes="cccc" />
+ </marker>
+ <marker
+ style="overflow:visible;"
+ id="Arrow2Mend"
+ refX="0.0"
+ refY="0.0"
+ orient="auto"
+ inkscape:stockid="Arrow2Mend">
+ <path
+ transform="scale(0.6) rotate(180) translate(-5,0)"
+ d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.9730900,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z "
+ style="font-size:12.0;fill-rule:evenodd;stroke-width:0.62500000;stroke-linejoin:round;"
+ id="path237"
+ sodipodi:nodetypes="cccc" />
+ </marker>
+ <marker
+ style="overflow:visible;"
+ id="marker258"
+ refX="0.0"
+ refY="0.0"
+ orient="auto"
+ inkscape:stockid="Arrow2Lend">
+ <path
+ transform="scale(1.1) rotate(180) translate(-5,0)"
+ d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.9730900,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z "
+ style="font-size:12.0;fill-rule:evenodd;stroke-width:0.62500000;stroke-linejoin:round;"
+ id="path259"
+ sodipodi:nodetypes="cccc" />
+ </marker>
+ <marker
+ style="overflow:visible;"
+ id="marker255"
+ refX="0.0"
+ refY="0.0"
+ orient="auto"
+ inkscape:stockid="Arrow2Lend">
+ <path
+ transform="scale(1.1) rotate(180) translate(-5,0)"
+ d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.9730900,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z "
+ style="font-size:12.0;fill-rule:evenodd;stroke-width:0.62500000;stroke-linejoin:round;"
+ id="path256"
+ sodipodi:nodetypes="cccc" />
+ </marker>
+ <marker
+ style="overflow:visible;"
+ id="marker252"
+ refX="0.0"
+ refY="0.0"
+ orient="auto"
+ inkscape:stockid="Arrow2Lend">
+ <path
+ transform="scale(1.1) rotate(180) translate(-5,0)"
+ d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.9730900,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z "
+ style="font-size:12.0;fill-rule:evenodd;stroke-width:0.62500000;stroke-linejoin:round;"
+ id="path253"
+ sodipodi:nodetypes="cccc" />
+ </marker>
+ <marker
+ style="overflow:visible;"
+ id="marker249"
+ refX="0.0"
+ refY="0.0"
+ orient="auto"
+ inkscape:stockid="Arrow2Lend">
+ <path
+ transform="scale(1.1) rotate(180) translate(-5,0)"
+ d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.9730900,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z "
+ style="font-size:12.0;fill-rule:evenodd;stroke-width:0.62500000;stroke-linejoin:round;"
+ id="path250"
+ sodipodi:nodetypes="cccc" />
+ </marker>
+ <marker
+ style="overflow:visible;"
+ id="Arrow2Lend"
+ refX="0.0"
+ refY="0.0"
+ orient="auto"
+ inkscape:stockid="Arrow2Lend">
+ <path
+ transform="scale(1.1) rotate(180) translate(-5,0)"
+ d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.9730900,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z "
+ style="font-size:12.0;fill-rule:evenodd;stroke-width:0.62500000;stroke-linejoin:round;"
+ id="path238"
+ sodipodi:nodetypes="cccc" />
+ </marker>
+ <marker
+ inkscape:stockid="Arrow2Lend"
+ orient="auto"
+ refY="0.0"
+ refX="0.0"
+ id="marker12"
+ style="overflow:visible;">
+ <path
+ sodipodi:nodetypes="cccc"
+ id="path455"
+ style="font-size:12.0;fill-rule:evenodd;stroke-width:0.62500000;stroke-linejoin:round;"
+ d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.9730900,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z "
+ transform="scale(1.1) rotate(180) translate(-5,0)" />
+ </marker>
+ <marker
+ inkscape:stockid="Arrow2Mend"
+ orient="auto"
+ refY="0.0"
+ refX="0.0"
+ id="marker11"
+ style="overflow:visible;">
+ <path
+ sodipodi:nodetypes="cccc"
+ id="path454"
+ style="font-size:12.0;fill-rule:evenodd;stroke-width:0.62500000;stroke-linejoin:round;"
+ d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.9730900,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z "
+ transform="scale(0.6) rotate(180) translate(-5,0)" />
+ </marker>
+ <marker
+ inkscape:stockid="Arrow2Mend"
+ orient="auto"
+ refY="0.0"
+ refX="0.0"
+ id="marker553"
+ style="overflow:visible;">
+ <path
+ sodipodi:nodetypes="cccc"
+ id="path554"
+ style="font-size:12.0;fill-rule:evenodd;stroke-width:0.62500000;stroke-linejoin:round;"
+ d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.9730900,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z "
+ transform="scale(0.6) rotate(180) translate(-5,0)" />
+ </marker>
+ <marker
+ inkscape:stockid="Arrow2Mend"
+ orient="auto"
+ refY="0.0"
+ refX="0.0"
+ id="marker556"
+ style="overflow:visible;">
+ <path
+ sodipodi:nodetypes="cccc"
+ id="path557"
+ style="font-size:12.0;fill-rule:evenodd;stroke-width:0.62500000;stroke-linejoin:round;"
+ d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.9730900,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z "
+ transform="scale(0.6) rotate(180) translate(-5,0)" />
+ </marker>
+ </defs>
+ <g
+ transform="translate(-367.9252,-513.0373)"
+ id="g214">
+ <path
+ style="fill:none;fill-opacity:0.75000000;fill-rule:evenodd;stroke:#000000;stroke-width:1.0000000;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:4.0000000;stroke-opacity:1.0000000"
+ d="M 377.45252,523.54977 C 377.45252,531.55430 377.45435,531.55430 377.45435,531.55430"
+ id="path85" />
+ <path
+ style="fill:none;fill-opacity:0.75000000;fill-rule:evenodd;stroke:#000000;stroke-width:1.0000000;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:4.0000000;stroke-opacity:1.0000000"
+ d="M 377.42440,513.51768 C 377.42440,521.52221 377.42623,521.52221 377.42623,521.52221"
+ id="path347" />
+ <path
+ style="fill:none;fill-opacity:0.75000000;fill-rule:evenodd;stroke:#000000;stroke-width:1.0000000;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:4.0000000;stroke-opacity:1.0000000"
+ d="M 376.44018,522.53611 C 368.43565,522.53611 368.43565,522.53794 368.43565,522.53794"
+ id="path348" />
+ <path
+ style="fill:none;fill-opacity:0.75000000;fill-rule:evenodd;stroke:#000000;stroke-width:1.0000000;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:4.0000000;stroke-opacity:1.0000000"
+ d="M 386.42981,522.49886 C 378.42528,522.49886 378.42528,522.50069 378.42528,522.50069"
+ id="path349" />
+ <path
+ style="fill:none;fill-opacity:0.75000000;fill-rule:evenodd;stroke:#000000;stroke-width:2.0250001;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:4.0000000;stroke-opacity:1.0000000"
+ d="M 389.38956,527.73586 C 389.39744,543.12488 389.39744,543.12488 389.39744,543.12488 L 389.39744,543.12488"
+ id="path15" />
+ <path
+ style="fill:none;fill-opacity:0.75000000;fill-rule:evenodd;stroke:#000000;stroke-width:0.60290909px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1.0000000;marker-start:none;marker-mid:none;marker-end:url(#Arrow2Mend)"
+ d="M 379.55344,535.63181 L 385.29760,535.63181"
+ id="path16" />
+ <path
+ style="fill:none;fill-opacity:0.75000000;fill-rule:evenodd;stroke:#000000;stroke-width:0.60290909px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1.0000000;marker-start:none;marker-mid:none;marker-end:url(#Arrow2Mend)"
+ d="M 391.20254,540.10437 L 396.94670,540.10437"
+ id="path555" />
+ <path
+ style="fill:none;fill-opacity:0.75000000;fill-rule:evenodd;stroke:#000000;stroke-width:0.60290909px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1.0000000;marker-start:none;marker-mid:none;marker-end:url(#Arrow2Mend)"
+ d="M 391.20254,530.50226 L 396.94670,530.50226"
+ id="path558" />
+ </g>
+</svg>
diff --git a/umbrello/umbrello/pics/sources/datatype.svg b/umbrello/umbrello/pics/sources/datatype.svg
new file mode 100644
index 00000000..b6c1f36c
--- /dev/null
+++ b/umbrello/umbrello/pics/sources/datatype.svg
@@ -0,0 +1,121 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 20010904//EN"
+"http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd">
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+<svg
+ id="svg1"
+ sodipodi:version="0.32"
+ inkscape:version="0.37"
+ width="22pt"
+ height="22pt"
+ sodipodi:docbase="/home/jr/tmp/umbrello/icons/inkscape-svg"
+ sodipodi:docname="datatype.svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:xml="http://www.w3.org/XML/1998/namespace"
+ xmlns:xlink="http://www.w3.org/1999/xlink">
+ <defs
+ id="defs3">
+ <linearGradient
+ id="linearGradient830">
+ <stop
+ style="stop-color:#ebffff;stop-opacity:0.0000000;"
+ offset="0.0000000"
+ id="stop831" />
+ <stop
+ style="stop-color:#fff;stop-opacity:1;"
+ offset="1"
+ id="stop832" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient826">
+ <stop
+ style="stop-color:#000;stop-opacity:1;"
+ offset="0"
+ id="stop827" />
+ <stop
+ style="stop-color:#fff;stop-opacity:1;"
+ offset="1"
+ id="stop828" />
+ </linearGradient>
+ <linearGradient
+ xlink:href="#linearGradient830"
+ id="linearGradient829"
+ x1="1.5500000"
+ y1="0.52343750"
+ x2="0.20422535"
+ y2="-0.12195122"
+ spreadMethod="reflect" />
+ <linearGradient
+ xlink:href="#linearGradient830"
+ id="linearGradient834"
+ x1="-0.31159419"
+ y1="0.19531250"
+ x2="0.77536231"
+ y2="0.94531250" />
+ <linearGradient
+ xlink:href="#linearGradient830"
+ id="linearGradient836" />
+ </defs>
+ <sodipodi:namedview
+ id="base"
+ pagecolor="#ffffff"
+ bordercolor="#666666"
+ borderopacity="1.0"
+ inkscape:pageopacity="0.0"
+ inkscape:pageshadow="2"
+ inkscape:zoom="22.6274170"
+ inkscape:cx="10.0143610"
+ inkscape:cy="10.8012676"
+ inkscape:window-width="1016"
+ inkscape:window-height="693"
+ gridspacingy="1.0000000pt"
+ gridspacingx="1.0000000pt"
+ gridtolerance="1.0000000px"
+ inkscape:window-x="0"
+ inkscape:window-y="0"
+ showgrid="true" />
+ <rect
+ style="fill:url(#linearGradient829);fill-opacity:0.75000000;fill-rule:evenodd;stroke:none;stroke-width:0.45652742pt;stroke-opacity:1.0000000;"
+ id="rect847"
+ width="135.18759"
+ height="47.111610"
+ ry="0.0000000"
+ x="175.11363"
+ y="-1.7772827" />
+ <g
+ id="g751">
+ <rect
+ style="font-size:12;fill:#ffff00;fill-rule:evenodd;stroke:#ff0000;stroke-width:1.21179;"
+ id="rect837"
+ width="26.27943831"
+ height="13.71849245"
+ x="0.61992770"
+ y="6.90882921" />
+ <rect
+ style="font-size:12;fill:url(#linearGradient829);fill-opacity:0.75;fill-rule:evenodd;stroke-width:0.456527pt;"
+ id="rect825"
+ width="24.87571098"
+ height="12.43472181"
+ ry="0"
+ x="1.31112826"
+ y="7.51523018" />
+ <text
+ xml:space="preserve"
+ style="font-size:12;stroke-width:1pt;font-family:Bitstream Vera Sans Mono;text-anchor:middle;font-weight:bold;font-style:normal;writing-mode:lr;"
+ x="15.9604130"
+ y="20.7664032"
+ id="text838"
+ transform="scale(0.868102,0.571713)"
+ sodipodi:linespacing="100%"><tspan
+ x="15.9604130"
+ y="20.7664032"
+ sodipodi:role="line"
+ id="tspan747">«xy»</tspan><tspan
+ x="15.9604130"
+ y="32.7664032"
+ sodipodi:role="line"
+ id="tspan749">ABC</tspan></text>
+ </g>
+</svg>
diff --git a/umbrello/umbrello/pics/sources/deep-history.svg b/umbrello/umbrello/pics/sources/deep-history.svg
new file mode 100644
index 00000000..913cb3f4
--- /dev/null
+++ b/umbrello/umbrello/pics/sources/deep-history.svg
@@ -0,0 +1,84 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+<svg
+ xmlns:xml="http://www.w3.org/XML/1998/namespace"
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://web.resource.org/cc/"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:sodipodi="http://inkscape.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ id="svg1"
+ height="22.000000px"
+ width="22.000000px"
+ y="0.00000000"
+ x="0.00000000"
+ version="1.0"
+ sodipodi:version="0.32"
+ inkscape:version="0.40+cvs"
+ sodipodi:docname="deep-history.svg"
+ sodipodi:docbase="F:\pics">
+ <metadata
+ id="metadata39">
+ <rdf:RDF
+ id="RDF40">
+ <cc:Work
+ rdf:about=""
+ id="Work41">
+ <dc:format
+ id="format42">image/svg+xml</dc:format>
+ <dc:type
+ id="type43"
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+ </cc:Work>
+ </rdf:RDF>
+ </metadata>
+ <sodipodi:namedview
+ id="base"
+ pagecolor="#ffffff"
+ bordercolor="#666666"
+ borderopacity="1.0"
+ inkscape:pageopacity="0.0"
+ inkscape:pageshadow="2"
+ inkscape:window-width="1035"
+ inkscape:window-height="691"
+ inkscape:zoom="23.500000"
+ inkscape:cx="11.000000"
+ inkscape:cy="11.000000"
+ inkscape:window-x="1806"
+ inkscape:window-y="316"
+ inkscape:current-layer="svg1" />
+ <defs
+ id="defs3" />
+ <g
+ transform="translate(-383.3264,-518.8539)"
+ id="g91">
+ <path
+ id="path21"
+ style="fill:none;stroke:#d30000;stroke-width:1.2500000;stroke-miterlimit:4.0000000;stroke-opacity:1.0000000"
+ d="M 402.82519,529.87519 C 402.82519,534.58139 399.02964,538.39651 394.34760,538.39651 C 389.66555,538.39651 385.87000,534.58139 385.87000,529.87519 C 385.87000,525.16900 389.66555,521.35388 394.34760,521.35388 C 399.02964,521.35388 402.82519,525.16900 402.82519,529.87519 z " />
+ <text
+ sodipodi:linespacing="100%"
+ xml:space="preserve"
+ id="text111"
+ style="font-size:12.000000;font-style:normal;font-weight:normal;fill:#000000;fill-opacity:1.0000000;stroke:none;stroke-width:1.0000000px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1.0000000;font-family:Bitstream Vera Sans;text-anchor:start;writing-mode:lr-tb"
+ y="535.10229"
+ x="387.91888"><tspan
+ id="tspan1"
+ sodipodi:role="line"
+ y="535.10229"
+ x="387.91888">H</tspan></text>
+ <text
+ sodipodi:linespacing="100%"
+ id="text2"
+ y="532.53491"
+ x="396.16739"
+ style="font-size:11.000000;font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;fill:#000000;fill-opacity:1.0000000;stroke:none;stroke-width:1.0000000px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1.0000000;font-family:Arial;text-anchor:start;writing-mode:lr-tb"
+ xml:space="preserve"><tspan
+ y="532.53491"
+ x="396.16739"
+ id="tspan3"
+ sodipodi:role="line">*</tspan></text>
+ </g>
+</svg>
diff --git a/umbrello/umbrello/pics/sources/dependency.svg b/umbrello/umbrello/pics/sources/dependency.svg
new file mode 100644
index 00000000..8a98444a
--- /dev/null
+++ b/umbrello/umbrello/pics/sources/dependency.svg
@@ -0,0 +1,216 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 20010904//EN"
+"http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd">
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+<svg
+ id="svg1"
+ sodipodi:version="0.32"
+ inkscape:version="0.37"
+ width="22pt"
+ height="22pt"
+ sodipodi:docbase="/home/jr/tmp/umbrello/icons/inkscape-svg"
+ sodipodi:docname="dependency.svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:xlink="http://www.w3.org/1999/xlink">
+ <defs
+ id="defs3">
+ <linearGradient
+ id="linearGradient993">
+ <stop
+ offset="0.0000000"
+ style="stop-color:#ffffff;stop-opacity:0.0000000;"
+ id="stop995" />
+ <stop
+ offset="1.0000000"
+ style="stop-color:#ffffff;stop-opacity:1.0000000;"
+ id="stop994" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient868">
+ <stop
+ style="stop-color:#ffffff;stop-opacity:0.0000000;"
+ offset="0.0000000"
+ id="stop869" />
+ <stop
+ style="stop-color:#fff;stop-opacity:1;"
+ offset="1"
+ id="stop870" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient893">
+ <stop
+ style="stop-color:#19839a;stop-opacity:0.0000000;"
+ offset="0.0000000"
+ id="stop894" />
+ <stop
+ style="stop-color:#fff;stop-opacity:1;"
+ offset="1"
+ id="stop895" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient830">
+ <stop
+ style="stop-color:#ebffff;stop-opacity:0.0000000;"
+ offset="0.0000000"
+ id="stop831" />
+ <stop
+ style="stop-color:#fff;stop-opacity:1;"
+ offset="1"
+ id="stop832" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient826">
+ <stop
+ style="stop-color:#000;stop-opacity:1;"
+ offset="0"
+ id="stop827" />
+ <stop
+ style="stop-color:#fff;stop-opacity:1;"
+ offset="1"
+ id="stop828" />
+ </linearGradient>
+ <linearGradient
+ xlink:href="#linearGradient830"
+ id="linearGradient829"
+ x1="1.5500000"
+ y1="0.52343750"
+ x2="0.20422535"
+ y2="-0.12195122"
+ spreadMethod="reflect" />
+ <linearGradient
+ xlink:href="#linearGradient830"
+ id="linearGradient834"
+ x1="-0.31159419"
+ y1="0.19531250"
+ x2="0.77536231"
+ y2="0.94531250" />
+ <linearGradient
+ xlink:href="#linearGradient830"
+ id="linearGradient836" />
+ <linearGradient
+ xlink:href="#linearGradient868"
+ id="linearGradient892"
+ x1="1.8449316"
+ y1="0.98914021"
+ x2="0.14743590"
+ y2="0.67741936"
+ spreadMethod="reflect" />
+ <defs
+ id="defs940">
+ <linearGradient
+ id="linearGradient941"
+ x1="0.0000000"
+ y1="0.50000000"
+ x2="1.0000000"
+ y2="0.50000000"
+ gradientUnits="objectBoundingBox"
+ spreadMethod="pad"
+ xlink:href="#linearGradient993" />
+ <linearGradient
+ id="linearGradient944">
+ <stop
+ style="stop-color:#19839a;stop-opacity:0.0000000;"
+ offset="0.0000000"
+ id="stop945" />
+ <stop
+ style="stop-color:#fff;stop-opacity:1;"
+ offset="1"
+ id="stop946" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient947">
+ <stop
+ style="stop-color:#ebffff;stop-opacity:0.0000000;"
+ offset="0.0000000"
+ id="stop948" />
+ <stop
+ style="stop-color:#fff;stop-opacity:1;"
+ offset="1"
+ id="stop949" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient950">
+ <stop
+ style="stop-color:#000;stop-opacity:1;"
+ offset="0"
+ id="stop951" />
+ <stop
+ style="stop-color:#fff;stop-opacity:1;"
+ offset="1"
+ id="stop952" />
+ </linearGradient>
+ <linearGradient
+ xlink:href="#linearGradient830"
+ id="linearGradient953"
+ x1="1.5500000"
+ y1="0.52343750"
+ x2="0.20422535"
+ y2="-0.12195122"
+ spreadMethod="reflect" />
+ <linearGradient
+ xlink:href="#linearGradient830"
+ id="linearGradient954"
+ x1="-0.31159419"
+ y1="0.19531250"
+ x2="0.77536231"
+ y2="0.94531250" />
+ <linearGradient
+ xlink:href="#linearGradient830"
+ id="linearGradient955" />
+ <linearGradient
+ xlink:href="#linearGradient868"
+ id="linearGradient956"
+ x1="-0.49264705"
+ y1="0.43750000"
+ x2="0.022058824"
+ y2="0.92187500" />
+ </defs>
+ <sodipodi:namedview
+ id="namedview957"
+ pagecolor="#ffffff"
+ bordercolor="#666666"
+ borderopacity="1.0"
+ inkscape:pageopacity="0.0"
+ inkscape:pageshadow="2"
+ inkscape:zoom="4.0000000"
+ inkscape:cx="79.132843"
+ inkscape:cy="33.777672"
+ inkscape:window-width="1022"
+ inkscape:window-height="701"
+ gridspacingy="1.0000000pt"
+ gridspacingx="1.0000000pt"
+ gridtolerance="1.0000000px"
+ inkscape:window-x="0"
+ inkscape:window-y="0" />
+ </defs>
+ <sodipodi:namedview
+ id="base"
+ pagecolor="#ffffff"
+ bordercolor="#666666"
+ borderopacity="1.0"
+ inkscape:pageopacity="0.0"
+ inkscape:pageshadow="2"
+ inkscape:zoom="22.6274170"
+ inkscape:cx="13.7972814"
+ inkscape:cy="10.5907033"
+ inkscape:window-width="1016"
+ inkscape:window-height="693"
+ gridspacingy="1.0000000pt"
+ gridspacingx="1.0000000pt"
+ gridtolerance="1.0000000px"
+ inkscape:window-x="0"
+ inkscape:window-y="0"
+ showgrid="true" />
+ <path
+ style="font-size:12;fill:none;fill-opacity:0.75;fill-rule:evenodd;stroke:#ff0000;stroke-width:2.5;stroke-dasharray:5,2.5;stroke-dashoffset:0;"
+ d="M 13.748607 27.494737 L 13.746247 2.0126593 "
+ id="path861"
+ sodipodi:nodetypes="cc" />
+ <path
+ style="font-size:12;fill:none;fill-opacity:0.75;fill-rule:evenodd;stroke:#ff0000;stroke-width:1.74;"
+ d="M 8.9275346 10.500689 L 13.717045 1.762889 L 19.121251 10.500689 "
+ id="path1009"
+ sodipodi:nodetypes="ccc" />
+</svg>
diff --git a/umbrello/umbrello/pics/sources/diag_activity.svg b/umbrello/umbrello/pics/sources/diag_activity.svg
new file mode 100644
index 00000000..d5c42951
--- /dev/null
+++ b/umbrello/umbrello/pics/sources/diag_activity.svg
@@ -0,0 +1,571 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 20010904//EN"
+"http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd">
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+<svg
+ id="svg1"
+ sodipodi:version="0.32"
+ inkscape:version="0.37"
+ width="16pt"
+ height="16pt"
+ sodipodi:docbase="/home/jr/tmp/umbrello/icons/inkscape-svg"
+ sodipodi:docname="diag_activity.svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:xml="http://www.w3.org/XML/1998/namespace"
+ xmlns:xlink="http://www.w3.org/1999/xlink">
+ <defs
+ id="defs3">
+ <linearGradient
+ id="linearGradient1796">
+ <stop
+ style="stop-color:#ffff21;stop-opacity:0.0000000;"
+ offset="0.0000000"
+ id="stop1797" />
+ <stop
+ style="stop-color:#fff;stop-opacity:1;"
+ offset="1"
+ id="stop1798" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient1763">
+ <stop
+ style="stop-color:#ffffff;stop-opacity:0.0000000;"
+ offset="0.0000000"
+ id="stop1764" />
+ <stop
+ style="stop-color:#fff;stop-opacity:1;"
+ offset="1"
+ id="stop1765" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient830">
+ <stop
+ style="stop-color:#ebffff;stop-opacity:0.0000000;"
+ offset="0.0000000"
+ id="stop831" />
+ <stop
+ style="stop-color:#fff;stop-opacity:1;"
+ offset="1"
+ id="stop832" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient826">
+ <stop
+ style="stop-color:#000;stop-opacity:1;"
+ offset="0"
+ id="stop827" />
+ <stop
+ style="stop-color:#fff;stop-opacity:1;"
+ offset="1"
+ id="stop828" />
+ </linearGradient>
+ <linearGradient
+ xlink:href="#linearGradient830"
+ id="linearGradient829"
+ x1="1.5500000"
+ y1="0.52343750"
+ x2="0.20422535"
+ y2="-0.12195122"
+ spreadMethod="reflect" />
+ <linearGradient
+ xlink:href="#linearGradient830"
+ id="linearGradient834" />
+ <linearGradient
+ xlink:href="#linearGradient830"
+ id="linearGradient836" />
+ <linearGradient
+ xlink:href="#linearGradient1763"
+ id="linearGradient1762"
+ x1="-0.34579438"
+ y1="-0.16406250"
+ x2="0.71962619"
+ y2="0.80468750" />
+ <linearGradient
+ xlink:href="#linearGradient1796"
+ id="linearGradient1795"
+ x1="0.65555555"
+ y1="0.88281250"
+ x2="0.48888889"
+ y2="0.53906250"
+ spreadMethod="reflect" />
+ <defs
+ id="defs1348">
+ <linearGradient
+ id="linearGradient1349">
+ <stop
+ style="stop-color:#ebffff;stop-opacity:0.0000000;"
+ offset="0.0000000"
+ id="stop1350" />
+ <stop
+ style="stop-color:#fff;stop-opacity:1;"
+ offset="1"
+ id="stop1351" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient1352">
+ <stop
+ style="stop-color:#000;stop-opacity:1;"
+ offset="0"
+ id="stop1353" />
+ <stop
+ style="stop-color:#fff;stop-opacity:1;"
+ offset="1"
+ id="stop1354" />
+ </linearGradient>
+ <linearGradient
+ xlink:href="#linearGradient830"
+ id="linearGradient1355"
+ x1="1.5500000"
+ y1="0.52343750"
+ x2="0.20422535"
+ y2="-0.12195122"
+ spreadMethod="reflect" />
+ <linearGradient
+ xlink:href="#linearGradient830"
+ id="linearGradient1356"
+ x1="-0.31159419"
+ y1="0.19531250"
+ x2="0.77536231"
+ y2="0.94531250" />
+ <linearGradient
+ xlink:href="#linearGradient830"
+ id="linearGradient1357" />
+ </defs>
+ <sodipodi:namedview
+ id="namedview1358"
+ pagecolor="#ffffff"
+ bordercolor="#666666"
+ borderopacity="1.0"
+ inkscape:pageopacity="0.0"
+ inkscape:pageshadow="2"
+ inkscape:zoom="0.26725582"
+ inkscape:cx="87.469639"
+ inkscape:cy="55.703730"
+ inkscape:window-width="1022"
+ inkscape:window-height="701"
+ gridspacingy="1.0000000pt"
+ gridspacingx="1.0000000pt"
+ gridtolerance="1.0000000px"
+ inkscape:window-x="0"
+ inkscape:window-y="0" />
+ <defs
+ id="defs1445">
+ <linearGradient
+ id="linearGradient973">
+ <stop
+ style="stop-color:#0000ff;stop-opacity:0.0000000;"
+ offset="0.0000000"
+ id="stop974" />
+ <stop
+ style="stop-color:#fff;stop-opacity:1;"
+ offset="1"
+ id="stop975" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient868">
+ <stop
+ style="stop-color:#ffffff;stop-opacity:0.0000000;"
+ offset="0.0000000"
+ id="stop869" />
+ <stop
+ style="stop-color:#fff;stop-opacity:1;"
+ offset="1"
+ id="stop870" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient893">
+ <stop
+ style="stop-color:#19839a;stop-opacity:0.0000000;"
+ offset="0.0000000"
+ id="stop894" />
+ <stop
+ style="stop-color:#fff;stop-opacity:1;"
+ offset="1"
+ id="stop895" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient1455">
+ <stop
+ style="stop-color:#ebffff;stop-opacity:0.0000000;"
+ offset="0.0000000"
+ id="stop1456" />
+ <stop
+ style="stop-color:#fff;stop-opacity:1;"
+ offset="1"
+ id="stop1457" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient1458">
+ <stop
+ style="stop-color:#000;stop-opacity:1;"
+ offset="0"
+ id="stop1459" />
+ <stop
+ style="stop-color:#fff;stop-opacity:1;"
+ offset="1"
+ id="stop1460" />
+ </linearGradient>
+ <linearGradient
+ xlink:href="#linearGradient830"
+ id="linearGradient1461"
+ x1="1.5500000"
+ y1="0.52343750"
+ x2="0.20422535"
+ y2="-0.12195122"
+ spreadMethod="reflect" />
+ <linearGradient
+ xlink:href="#linearGradient830"
+ id="linearGradient1462"
+ x1="-0.31159419"
+ y1="0.19531250"
+ x2="0.77536231"
+ y2="0.94531250" />
+ <linearGradient
+ xlink:href="#linearGradient830"
+ id="linearGradient1463" />
+ <linearGradient
+ xlink:href="#linearGradient868"
+ id="linearGradient892" />
+ <linearGradient
+ xlink:href="#linearGradient973"
+ id="linearGradient926"
+ x1="1.5043305e-18"
+ y1="0.50000000"
+ x2="1.0000000"
+ y2="0.50000000" />
+ <linearGradient
+ xlink:href="#linearGradient868"
+ id="linearGradient928" />
+ <linearGradient
+ xlink:href="#linearGradient830"
+ id="linearGradient937"
+ x1="0.010563380"
+ y1="0.48571429"
+ x2="0.98943663"
+ y2="0.48571429"
+ spreadMethod="pad" />
+ <radialGradient
+ xlink:href="#linearGradient973"
+ id="radialGradient976"
+ cx="0.49275362"
+ cy="0.46875000"
+ r="0.80203730"
+ fx="0.49275362"
+ fy="0.46875000"
+ spreadMethod="reflect" />
+ </defs>
+ <sodipodi:namedview
+ id="namedview1469"
+ pagecolor="#ffffff"
+ bordercolor="#666666"
+ borderopacity="1.0"
+ inkscape:pageopacity="0.0"
+ inkscape:pageshadow="2"
+ inkscape:zoom="4.0000000"
+ inkscape:cx="79.132812"
+ inkscape:cy="66.817627"
+ inkscape:window-width="1022"
+ inkscape:window-height="701"
+ gridspacingy="1.0000000pt"
+ gridspacingx="1.0000000pt"
+ gridtolerance="1.0000000px"
+ inkscape:window-x="0"
+ inkscape:window-y="0" />
+ <defs
+ id="defs1515">
+ <linearGradient
+ id="linearGradient1516">
+ <stop
+ style="stop-color:#ffffff;stop-opacity:0.0000000;"
+ offset="0.0000000"
+ id="stop1517" />
+ <stop
+ style="stop-color:#fff;stop-opacity:1;"
+ offset="1"
+ id="stop1518" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient1519">
+ <stop
+ style="stop-color:#19839a;stop-opacity:0.0000000;"
+ offset="0.0000000"
+ id="stop1520" />
+ <stop
+ style="stop-color:#fff;stop-opacity:1;"
+ offset="1"
+ id="stop1521" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient1522">
+ <stop
+ style="stop-color:#ebffff;stop-opacity:0.0000000;"
+ offset="0.0000000"
+ id="stop1523" />
+ <stop
+ style="stop-color:#fff;stop-opacity:1;"
+ offset="1"
+ id="stop1524" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient1525">
+ <stop
+ style="stop-color:#000;stop-opacity:1;"
+ offset="0"
+ id="stop1526" />
+ <stop
+ style="stop-color:#fff;stop-opacity:1;"
+ offset="1"
+ id="stop1527" />
+ </linearGradient>
+ <linearGradient
+ xlink:href="#linearGradient830"
+ id="linearGradient1528"
+ x1="1.5500000"
+ y1="0.52343750"
+ x2="0.20422535"
+ y2="-0.12195122"
+ spreadMethod="reflect" />
+ <linearGradient
+ xlink:href="#linearGradient830"
+ id="linearGradient1529"
+ x1="-0.31159419"
+ y1="0.19531250"
+ x2="0.77536231"
+ y2="0.94531250" />
+ <linearGradient
+ xlink:href="#linearGradient830"
+ id="linearGradient1530" />
+ <linearGradient
+ xlink:href="#linearGradient868"
+ id="linearGradient1531" />
+ </defs>
+ <sodipodi:namedview
+ id="namedview1532"
+ pagecolor="#ffffff"
+ bordercolor="#666666"
+ borderopacity="1.0"
+ inkscape:pageopacity="0.0"
+ inkscape:pageshadow="2"
+ inkscape:zoom="4.0000000"
+ inkscape:cx="79.132812"
+ inkscape:cy="69.358765"
+ inkscape:window-width="1022"
+ inkscape:window-height="701"
+ gridspacingy="1.0000000pt"
+ gridspacingx="1.0000000pt"
+ gridtolerance="1.0000000px"
+ inkscape:window-x="0"
+ inkscape:window-y="0" />
+ <defs
+ id="defs921">
+ <linearGradient
+ id="linearGradient922">
+ <stop
+ style="stop-color:#ffffff;stop-opacity:0.0000000;"
+ offset="0.0000000"
+ id="stop923" />
+ <stop
+ style="stop-color:#fff;stop-opacity:1;"
+ offset="1"
+ id="stop924" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient925">
+ <stop
+ style="stop-color:#19839a;stop-opacity:0.0000000;"
+ offset="0.0000000"
+ id="stop926" />
+ <stop
+ style="stop-color:#fff;stop-opacity:1;"
+ offset="1"
+ id="stop927" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient929">
+ <stop
+ style="stop-color:#ebffff;stop-opacity:0.0000000;"
+ offset="0.0000000"
+ id="stop930" />
+ <stop
+ style="stop-color:#fff;stop-opacity:1;"
+ offset="1"
+ id="stop931" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient932">
+ <stop
+ style="stop-color:#000;stop-opacity:1;"
+ offset="0"
+ id="stop933" />
+ <stop
+ style="stop-color:#fff;stop-opacity:1;"
+ offset="1"
+ id="stop934" />
+ </linearGradient>
+ <linearGradient
+ xlink:href="#linearGradient830"
+ id="linearGradient935"
+ x1="1.5500000"
+ y1="0.52343750"
+ x2="0.20422535"
+ y2="-0.12195122"
+ spreadMethod="reflect" />
+ <linearGradient
+ xlink:href="#linearGradient830"
+ id="linearGradient936"
+ x1="-0.31159419"
+ y1="0.19531250"
+ x2="0.77536231"
+ y2="0.94531250" />
+ <linearGradient
+ xlink:href="#linearGradient830"
+ id="linearGradient938" />
+ <linearGradient
+ xlink:href="#linearGradient868"
+ id="linearGradient939"
+ x1="0.39932632"
+ y1="0.50707734"
+ x2="0.64623892"
+ y2="0.60370040"
+ spreadMethod="reflect" />
+ </defs>
+ <sodipodi:namedview
+ id="namedview940"
+ pagecolor="#ffffff"
+ bordercolor="#666666"
+ borderopacity="1.0"
+ inkscape:pageopacity="0.0"
+ inkscape:pageshadow="2"
+ inkscape:zoom="4.0000000"
+ inkscape:cx="79.132812"
+ inkscape:cy="69.358765"
+ inkscape:window-width="1022"
+ inkscape:window-height="701"
+ gridspacingy="1.0000000pt"
+ gridspacingx="1.0000000pt"
+ gridtolerance="1.0000000px"
+ inkscape:window-x="0"
+ inkscape:window-y="0" />
+ </defs>
+ <sodipodi:namedview
+ id="base"
+ pagecolor="#ffffff"
+ bordercolor="#666666"
+ borderopacity="1.0"
+ inkscape:pageopacity="0.0"
+ inkscape:pageshadow="2"
+ inkscape:zoom="31.9999999"
+ inkscape:cx="5.95499421"
+ inkscape:cy="8.21358110"
+ inkscape:window-width="1016"
+ inkscape:window-height="693"
+ gridspacingy="1.0000000pt"
+ gridspacingx="1.0000000pt"
+ gridtolerance="1.0000000px"
+ inkscape:window-x="0"
+ inkscape:window-y="0"
+ showgrid="true"
+ snaptogrid="false" />
+ <rect
+ style="fill:url(#linearGradient829);fill-opacity:0.75000000;fill-rule:evenodd;stroke-width:0.45652742pt;"
+ id="rect825"
+ width="137.68759"
+ height="66.465706"
+ ry="0.0000000"
+ x="359.81241"
+ y="197.28429" />
+ <rect
+ style="fill:url(#linearGradient829);fill-opacity:0.75000000;fill-rule:evenodd;stroke-width:0.45652742pt;"
+ id="rect846"
+ width="135.18759"
+ height="37.082668"
+ ry="0.0000000"
+ x="316.25000"
+ y="81.250000" />
+ <rect
+ style="fill:url(#linearGradient829);fill-opacity:0.75000000;fill-rule:evenodd;stroke:none;stroke-width:0.45652742pt;stroke-opacity:1.0000000;"
+ id="rect847"
+ width="135.18759"
+ height="47.111610"
+ ry="0.0000000"
+ x="255.00000"
+ y="157.88839" />
+ <path
+ style="font-size:12;fill:#8df2ff;fill-rule:evenodd;stroke-width:5;"
+ d="M 10.662893,8.9661054 L 10.662893,152.41231 L 155.79528,152.41231 L 155.79528,88.658436 C 157.32299,40.843037 125.58602,15.885505 102.67038,9.5101184 L 10.662893,8.9661054 z "
+ id="path1780"
+ sodipodi:nodetypes="cccccc"
+ transform="matrix(0.132695,0.000000,0.000000,0.133731,-0.712414,-0.542557)" />
+ <path
+ style="font-size:12;fill:url(#linearGradient1762);fill-opacity:0.75;fill-rule:evenodd;stroke:#0083e3;stroke-width:1.22079;"
+ d="M 0.63038772 0.64037571 L 12.041529 0.71149742 C 14.044031 0.46640741 18.580764 3.7689643 13.04278 8.3092899 C 16.547157 7.8191096 18.883407 6.5936594 19.384032 10.515101 L 19.419979 19.393892 L 0.63038772 19.393892 L 0.63038772 0.64037571 z "
+ id="path1781"
+ sodipodi:nodetypes="ccccccc" />
+ <g
+ id="g1567"
+ transform="matrix(6.414801e-2,0.000000,0.000000,8.074578e-2,0.594654,-1.730309)"
+ style="font-size:12;">
+ <path
+ sodipodi:type="arc"
+ style="fill:#ffff00;fill-rule:evenodd;stroke:#ff0000;stroke-width:6.5509048;"
+ id="path1536"
+ sodipodi:cx="63.437500"
+ sodipodi:cy="39.375000"
+ sodipodi:rx="31.250000"
+ sodipodi:ry="31.562500"
+ d="M 94.687500 39.375000 A 31.250000 31.562500 0 1 0 32.187500,39.375000 A 31.250000 31.562500 0 1 0 94.687500 39.375000 z"
+ transform="matrix(2.033142,0.000000,0.000000,1.146119,-49.35104,33.00004)" />
+ <path
+ sodipodi:type="arc"
+ style="fill:url(#linearGradient892);fill-opacity:0.75000000;fill-rule:evenodd;stroke-width:10.000000;"
+ id="path1537"
+ sodipodi:cx="63.437500"
+ sodipodi:cy="39.375000"
+ sodipodi:rx="31.250000"
+ sodipodi:ry="31.562500"
+ d="M 94.687500 39.375000 A 31.250000 31.562500 0 1 0 32.187500,39.375000 A 31.250000 31.562500 0 1 0 94.687500 39.375000 z"
+ transform="matrix(1.866513,0.000000,0.000000,0.989918,-38.73914,38.52544)" />
+ <text
+ xml:space="preserve"
+ style="font-size:12.000000;stroke-width:1.0000000pt;font-family:Bitstream Vera Sans;"
+ x="6.9204906"
+ y="27.309141"
+ id="text869"
+ transform="scale(4.148831,3.402401)"><tspan
+ id="tspan870">ABC</tspan></text>
+ </g>
+ <path
+ style="font-size:12;fill:none;fill-opacity:0.75;fill-rule:evenodd;stroke:#ff0000;stroke-width:0.62664;stroke-dashoffset:0;"
+ d="M 5.5931752 7.7939546 L 5.6661327 14.774106 L 10.262453 14.774106 "
+ id="path1573"
+ sodipodi:nodetypes="ccc" />
+ <g
+ id="g900"
+ transform="matrix(5.889270e-2,0.000000,0.000000,5.818225e-2,10.22868,10.24438)"
+ style="font-size:12;">
+ <rect
+ style="fill:#ffff00;fill-rule:evenodd;stroke:#ff0000;stroke-width:6.0940815;stroke-dasharray:none;"
+ id="rect854"
+ width="41.480559"
+ height="40.741544"
+ x="74.760017"
+ y="-59.764663"
+ transform="matrix(1.438607,1.462473,-1.437488,1.463230,-116.1987,-4.837583)" />
+ <rect
+ style="fill:url(#linearGradient892);fill-rule:evenodd;stroke-width:11.052127;"
+ id="rect855"
+ width="72.749743"
+ height="71.403139"
+ x="72.801592"
+ y="-35.372109"
+ transform="matrix(0.710624,0.703572,-0.699330,0.714799,0.000000,0.000000)"
+ ry="0.0000000" />
+ </g>
+ <path
+ style="font-size:12;fill:none;fill-opacity:0.75;fill-rule:evenodd;stroke:#ff0000;stroke-width:0.627605;"
+ d="M 8.0261215 13.401058 L 10.37964 14.734718 L 8.1045721 16.539083 "
+ id="path971"
+ sodipodi:nodetypes="ccc" />
+</svg>
diff --git a/umbrello/umbrello/pics/sources/diag_class.svg b/umbrello/umbrello/pics/sources/diag_class.svg
new file mode 100644
index 00000000..ef84ebe6
--- /dev/null
+++ b/umbrello/umbrello/pics/sources/diag_class.svg
@@ -0,0 +1,360 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 20010904//EN"
+"http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd">
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+<svg
+ id="svg1"
+ sodipodi:version="0.32"
+ inkscape:version="0.37"
+ width="16pt"
+ height="16pt"
+ sodipodi:docbase="/home/jr/tmp/umbrello/icons/inkscape-svg"
+ sodipodi:docname="diag_class.svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:xml="http://www.w3.org/XML/1998/namespace"
+ xmlns:xlink="http://www.w3.org/1999/xlink">
+ <defs
+ id="defs3">
+ <linearGradient
+ id="linearGradient1796">
+ <stop
+ style="stop-color:#ffff21;stop-opacity:0.0000000;"
+ offset="0.0000000"
+ id="stop1797" />
+ <stop
+ style="stop-color:#fff;stop-opacity:1;"
+ offset="1"
+ id="stop1798" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient1763">
+ <stop
+ style="stop-color:#ffffff;stop-opacity:0.0000000;"
+ offset="0.0000000"
+ id="stop1764" />
+ <stop
+ style="stop-color:#fff;stop-opacity:1;"
+ offset="1"
+ id="stop1765" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient830">
+ <stop
+ style="stop-color:#ebffff;stop-opacity:0.0000000;"
+ offset="0.0000000"
+ id="stop831" />
+ <stop
+ style="stop-color:#fff;stop-opacity:1;"
+ offset="1"
+ id="stop832" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient826">
+ <stop
+ style="stop-color:#000;stop-opacity:1;"
+ offset="0"
+ id="stop827" />
+ <stop
+ style="stop-color:#fff;stop-opacity:1;"
+ offset="1"
+ id="stop828" />
+ </linearGradient>
+ <linearGradient
+ xlink:href="#linearGradient830"
+ id="linearGradient829"
+ x1="1.5500000"
+ y1="0.52343750"
+ x2="0.20422535"
+ y2="-0.12195122"
+ spreadMethod="reflect" />
+ <linearGradient
+ xlink:href="#linearGradient830"
+ id="linearGradient834" />
+ <linearGradient
+ xlink:href="#linearGradient830"
+ id="linearGradient836" />
+ <linearGradient
+ xlink:href="#linearGradient1763"
+ id="linearGradient1762"
+ x1="-0.34579438"
+ y1="-0.16406250"
+ x2="0.71962619"
+ y2="0.80468750" />
+ <linearGradient
+ xlink:href="#linearGradient1796"
+ id="linearGradient1795"
+ x1="0.65555555"
+ y1="0.88281250"
+ x2="0.48888889"
+ y2="0.53906250"
+ spreadMethod="reflect" />
+ <defs
+ id="defs1348">
+ <linearGradient
+ id="linearGradient1349">
+ <stop
+ style="stop-color:#ebffff;stop-opacity:0.0000000;"
+ offset="0.0000000"
+ id="stop1350" />
+ <stop
+ style="stop-color:#fff;stop-opacity:1;"
+ offset="1"
+ id="stop1351" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient1352">
+ <stop
+ style="stop-color:#000;stop-opacity:1;"
+ offset="0"
+ id="stop1353" />
+ <stop
+ style="stop-color:#fff;stop-opacity:1;"
+ offset="1"
+ id="stop1354" />
+ </linearGradient>
+ <linearGradient
+ xlink:href="#linearGradient830"
+ id="linearGradient1355"
+ x1="1.5500000"
+ y1="0.52343750"
+ x2="0.20422535"
+ y2="-0.12195122"
+ spreadMethod="reflect" />
+ <linearGradient
+ xlink:href="#linearGradient830"
+ id="linearGradient1356"
+ x1="-0.31159419"
+ y1="0.19531250"
+ x2="0.77536231"
+ y2="0.94531250" />
+ <linearGradient
+ xlink:href="#linearGradient830"
+ id="linearGradient1357" />
+ </defs>
+ <sodipodi:namedview
+ id="namedview1358"
+ pagecolor="#ffffff"
+ bordercolor="#666666"
+ borderopacity="1.0"
+ inkscape:pageopacity="0.0"
+ inkscape:pageshadow="2"
+ inkscape:zoom="0.26725582"
+ inkscape:cx="87.469639"
+ inkscape:cy="55.703730"
+ inkscape:window-width="1022"
+ inkscape:window-height="701"
+ gridspacingy="1.0000000pt"
+ gridspacingx="1.0000000pt"
+ gridtolerance="1.0000000px"
+ inkscape:window-x="0"
+ inkscape:window-y="0" />
+ </defs>
+ <sodipodi:namedview
+ id="base"
+ pagecolor="#ffffff"
+ bordercolor="#666666"
+ borderopacity="1.0"
+ inkscape:pageopacity="0.0"
+ inkscape:pageshadow="2"
+ inkscape:zoom="31.9999999"
+ inkscape:cx="9.31250049"
+ inkscape:cy="7.28113176"
+ inkscape:window-width="1016"
+ inkscape:window-height="693"
+ gridspacingy="1.0000000pt"
+ gridspacingx="1.0000000pt"
+ gridtolerance="1.0000000px"
+ inkscape:window-x="0"
+ inkscape:window-y="0"
+ showgrid="true"
+ snaptogrid="false" />
+ <rect
+ style="fill:url(#linearGradient829);fill-opacity:0.75000000;fill-rule:evenodd;stroke-width:0.45652742pt;"
+ id="rect825"
+ width="137.68759"
+ height="66.465706"
+ ry="0.0000000"
+ x="359.81241"
+ y="197.28429" />
+ <rect
+ style="fill:url(#linearGradient829);fill-opacity:0.75000000;fill-rule:evenodd;stroke-width:0.45652742pt;"
+ id="rect846"
+ width="135.18759"
+ height="37.082668"
+ ry="0.0000000"
+ x="316.25000"
+ y="81.250000" />
+ <rect
+ style="fill:url(#linearGradient829);fill-opacity:0.75000000;fill-rule:evenodd;stroke:none;stroke-width:0.45652742pt;stroke-opacity:1.0000000;"
+ id="rect847"
+ width="135.18759"
+ height="47.111610"
+ ry="0.0000000"
+ x="255.00000"
+ y="157.88839" />
+ <g
+ id="g827">
+ <path
+ style="font-size:12;fill:#8df2ff;fill-rule:evenodd;stroke-width:5;"
+ d="M 10.662893,8.9661054 L 10.662893,152.41231 L 155.79528,152.41231 L 155.79528,88.658436 C 157.32299,40.843037 125.58602,15.885505 102.67038,9.5101184 L 10.662893,8.9661054 z "
+ id="path1780"
+ sodipodi:nodetypes="cccccc"
+ transform="matrix(0.132243,0.000000,0.000000,0.133732,-0.669713,-0.542563)" />
+ <path
+ style="font-size:12;fill:url(#linearGradient1762);fill-opacity:0.75;fill-rule:evenodd;stroke:#0083e3;stroke-width:1.22454;"
+ d="M 0.59132113 0.67943931 L 12.057516 0.75041341 C 14.069678 0.50583204 18.628299 3.8015352 13.063597 8.3324382 C 16.584879 7.8432753 18.932402 6.6203681 19.435443 10.533671 L 19.471562 19.394037 L 0.59132113 19.394037 L 0.59132113 0.67943931 z "
+ id="path1781"
+ sodipodi:nodetypes="ccccccc" />
+ <g
+ id="g1413"
+ transform="matrix(0.125094,0.000000,0.000000,0.125522,2.584431e-2,-0.563749)"
+ style="font-size:12;">
+ <rect
+ style="fill:#ffff00;fill-rule:evenodd;stroke:#ff0000;stroke-width:13.551165;stroke-dasharray:none;"
+ id="rect1360"
+ width="140.70964"
+ height="134.99545"
+ x="10.564683"
+ y="13.401533"
+ transform="matrix(0.386648,0.000000,0.000000,0.352104,11.83765,18.07640)" />
+ <rect
+ style="fill:url(#linearGradient829);fill-opacity:0.75000000;fill-rule:evenodd;stroke-width:0.45652742pt;"
+ id="rect1362"
+ width="48.750000"
+ height="10.452705"
+ ry="0.0000000"
+ x="18.750000"
+ y="25.127287" />
+ <text
+ xml:space="preserve"
+ style="font-size:12.000000;stroke-width:1.0000000pt;font-family:Bitstream Vera Sans;"
+ x="5.3621841"
+ y="17.418277"
+ id="text838"
+ transform="matrix(1.800535,0.000000,0.000000,0.909408,11.83765,18.07640)"><tspan
+ id="tspan839">ABC</tspan></text>
+ <path
+ style="fill:none;fill-opacity:0.75000000;fill-rule:evenodd;stroke:#ff0000;stroke-width:13.551165;stroke-dasharray:none;"
+ d="M 13.158769,56.609700 L 149.13268,56.609700"
+ id="path842"
+ transform="matrix(0.386648,0.000000,0.000000,0.352104,11.83765,18.07640)" />
+ <path
+ style="fill:none;fill-opacity:0.75000000;fill-rule:evenodd;stroke:#ff0000;stroke-width:13.551165;stroke-dasharray:none;"
+ d="M 12.845456,96.712602 L 148.81938,96.712602"
+ id="path845"
+ transform="matrix(0.386648,0.000000,0.000000,0.352104,11.83765,18.07640)" />
+ <rect
+ style="fill:url(#linearGradient829);fill-opacity:0.75000000;fill-rule:evenodd;stroke-width:0.45652742pt;"
+ id="rect1369"
+ width="48.750000"
+ height="9.8123989"
+ ry="0.0000000"
+ x="18.750000"
+ y="40.000000" />
+ <rect
+ style="fill:url(#linearGradient829);fill-opacity:0.75000000;fill-rule:evenodd;stroke-width:0.45652742pt;"
+ id="rect1370"
+ width="48.750000"
+ height="12.500000"
+ ry="0.0000000"
+ x="18.750000"
+ y="55.000000" />
+ </g>
+ <g
+ id="g1423"
+ transform="matrix(0.125094,0.000000,0.000000,0.125522,8.782425,9.321107)"
+ style="font-size:12;">
+ <rect
+ style="fill:#ffff00;fill-rule:evenodd;stroke:#ff0000;stroke-width:13.551165;stroke-dasharray:none;"
+ id="rect1424"
+ width="140.70964"
+ height="134.99545"
+ x="10.564683"
+ y="13.401533"
+ transform="matrix(0.386648,0.000000,0.000000,0.352104,11.83765,18.07640)" />
+ <rect
+ style="fill:url(#linearGradient829);fill-opacity:0.75000000;fill-rule:evenodd;stroke-width:0.45652742pt;"
+ id="rect1425"
+ width="48.750000"
+ height="10.452705"
+ ry="0.0000000"
+ x="18.750000"
+ y="25.127287" />
+ <text
+ xml:space="preserve"
+ style="font-size:12.000000;stroke-width:1.0000000pt;font-family:Bitstream Vera Sans;"
+ x="5.3621841"
+ y="17.418277"
+ id="text1426"
+ transform="matrix(1.800535,0.000000,0.000000,0.909408,11.83765,18.07640)"><tspan
+ id="tspan1427">ABC</tspan></text>
+ <path
+ style="fill:none;fill-opacity:0.75000000;fill-rule:evenodd;stroke:#ff0000;stroke-width:13.551165;stroke-dasharray:none;"
+ d="M 13.158769,56.609700 L 149.13268,56.609700"
+ id="path1429"
+ transform="matrix(0.386648,0.000000,0.000000,0.352104,11.83765,18.07640)" />
+ <path
+ style="fill:none;fill-opacity:0.75000000;fill-rule:evenodd;stroke:#ff0000;stroke-width:13.551165;stroke-dasharray:none;"
+ d="M 12.845456,96.712602 L 148.81938,96.712602"
+ id="path1430"
+ transform="matrix(0.386648,0.000000,0.000000,0.352104,11.83765,18.07640)" />
+ <rect
+ style="fill:url(#linearGradient829);fill-opacity:0.75000000;fill-rule:evenodd;stroke-width:0.45652742pt;"
+ id="rect1431"
+ width="48.750000"
+ height="9.8123989"
+ ry="0.0000000"
+ x="18.750000"
+ y="40.000000" />
+ <rect
+ style="fill:url(#linearGradient829);fill-opacity:0.75000000;fill-rule:evenodd;stroke-width:0.45652742pt;"
+ id="rect1432"
+ width="48.750000"
+ height="12.500000"
+ ry="0.0000000"
+ x="18.750000"
+ y="55.000000" />
+ </g>
+ <path
+ style="font-size:12;fill:none;fill-opacity:0.75;fill-rule:evenodd;stroke:#ff0000;stroke-width:5;"
+ d="M 43.750000,95.000000 L 43.750000,116.25000 L 86.250000,116.25000"
+ id="path1433"
+ sodipodi:nodetypes="ccc"
+ transform="matrix(0.125094,0.000000,0.000000,0.125522,-1.512848e-2,-5.192415e-2)" />
+ <g
+ id="g1436"
+ transform="matrix(0.125094,0.000000,0.000000,0.125522,-1.512848e-2,-5.192415e-2)"
+ style="font-size:12;">
+ <polygon
+ sodipodi:type="star"
+ style="fill:#ffff00;fill-opacity:1.0000000;fill-rule:evenodd;stroke:#ff0000;stroke-width:5.0000000;stroke-dasharray:none;stroke-opacity:1.0000000;"
+ id="polygon1434"
+ sodipodi:sides="3"
+ sodipodi:cx="27.500000"
+ sodipodi:cy="88.750000"
+ sodipodi:r1="16.682701"
+ sodipodi:r2="8.3413503"
+ sodipodi:arg1="0.51728738"
+ sodipodi:arg2="1.5644849"
+ inkscape:flatsided="true"
+ points="42.000000,97.000000 13.105290,97.182368 27.394710,72.067632 42.000000,97.000000 "
+ transform="translate(15.50000,-0.817633)" />
+ <polygon
+ sodipodi:type="star"
+ style="fill:url(#linearGradient834);fill-opacity:1.0000000;fill-rule:evenodd;stroke:none;stroke-width:5.0000000;stroke-dasharray:none;stroke-opacity:1.0000000;"
+ id="polygon1435"
+ sodipodi:sides="3"
+ sodipodi:cx="27.500000"
+ sodipodi:cy="88.750000"
+ sodipodi:r1="16.682701"
+ sodipodi:r2="8.3413503"
+ sodipodi:arg1="0.51728738"
+ sodipodi:arg2="1.5644849"
+ inkscape:flatsided="true"
+ points="42.000000,97.000000 13.105290,97.182368 27.394710,72.067632 42.000000,97.000000 "
+ transform="matrix(0.778688,0.000000,0.000000,0.739979,21.04506,22.49123)" />
+ </g>
+ </g>
+</svg>
diff --git a/umbrello/umbrello/pics/sources/diag_collaboration.svg b/umbrello/umbrello/pics/sources/diag_collaboration.svg
new file mode 100644
index 00000000..6d84d6e3
--- /dev/null
+++ b/umbrello/umbrello/pics/sources/diag_collaboration.svg
@@ -0,0 +1,1111 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 20010904//EN"
+"http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd">
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+<svg
+ id="svg1"
+ sodipodi:version="0.32"
+ inkscape:version="0.37"
+ width="16pt"
+ height="16pt"
+ sodipodi:docbase="/home/jr/tmp/umbrello/icons/inkscape-svg"
+ sodipodi:docname="diag_collaboration.svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:xml="http://www.w3.org/XML/1998/namespace"
+ xmlns:xlink="http://www.w3.org/1999/xlink">
+ <defs
+ id="defs3">
+ <linearGradient
+ id="linearGradient1796">
+ <stop
+ style="stop-color:#ffff21;stop-opacity:0.0000000;"
+ offset="0.0000000"
+ id="stop1797" />
+ <stop
+ style="stop-color:#fff;stop-opacity:1;"
+ offset="1"
+ id="stop1798" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient1763">
+ <stop
+ style="stop-color:#ffffff;stop-opacity:0.0000000;"
+ offset="0.0000000"
+ id="stop1764" />
+ <stop
+ style="stop-color:#fff;stop-opacity:1;"
+ offset="1"
+ id="stop1765" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient830">
+ <stop
+ style="stop-color:#ebffff;stop-opacity:0.0000000;"
+ offset="0.0000000"
+ id="stop831" />
+ <stop
+ style="stop-color:#fff;stop-opacity:1;"
+ offset="1"
+ id="stop832" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient826">
+ <stop
+ style="stop-color:#000;stop-opacity:1;"
+ offset="0"
+ id="stop827" />
+ <stop
+ style="stop-color:#fff;stop-opacity:1;"
+ offset="1"
+ id="stop828" />
+ </linearGradient>
+ <linearGradient
+ xlink:href="#linearGradient830"
+ id="linearGradient829"
+ x1="1.5500000"
+ y1="0.52343750"
+ x2="0.20422535"
+ y2="-0.12195122"
+ spreadMethod="reflect" />
+ <linearGradient
+ xlink:href="#linearGradient830"
+ id="linearGradient834" />
+ <linearGradient
+ xlink:href="#linearGradient830"
+ id="linearGradient836" />
+ <linearGradient
+ xlink:href="#linearGradient1763"
+ id="linearGradient1762"
+ x1="-0.34579438"
+ y1="-0.16406250"
+ x2="0.71962619"
+ y2="0.80468750" />
+ <linearGradient
+ xlink:href="#linearGradient1796"
+ id="linearGradient1795"
+ x1="0.65555555"
+ y1="0.88281250"
+ x2="0.48888889"
+ y2="0.53906250"
+ spreadMethod="reflect" />
+ <defs
+ id="defs1348">
+ <linearGradient
+ id="linearGradient1349">
+ <stop
+ style="stop-color:#ebffff;stop-opacity:0.0000000;"
+ offset="0.0000000"
+ id="stop1350" />
+ <stop
+ style="stop-color:#fff;stop-opacity:1;"
+ offset="1"
+ id="stop1351" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient1352">
+ <stop
+ style="stop-color:#000;stop-opacity:1;"
+ offset="0"
+ id="stop1353" />
+ <stop
+ style="stop-color:#fff;stop-opacity:1;"
+ offset="1"
+ id="stop1354" />
+ </linearGradient>
+ <linearGradient
+ xlink:href="#linearGradient830"
+ id="linearGradient1355"
+ x1="1.5500000"
+ y1="0.52343750"
+ x2="0.20422535"
+ y2="-0.12195122"
+ spreadMethod="reflect" />
+ <linearGradient
+ xlink:href="#linearGradient830"
+ id="linearGradient1356"
+ x1="-0.31159419"
+ y1="0.19531250"
+ x2="0.77536231"
+ y2="0.94531250" />
+ <linearGradient
+ xlink:href="#linearGradient830"
+ id="linearGradient1357" />
+ </defs>
+ <sodipodi:namedview
+ id="namedview1358"
+ pagecolor="#ffffff"
+ bordercolor="#666666"
+ borderopacity="1.0"
+ inkscape:pageopacity="0.0"
+ inkscape:pageshadow="2"
+ inkscape:zoom="0.26725582"
+ inkscape:cx="87.469639"
+ inkscape:cy="55.703730"
+ inkscape:window-width="1022"
+ inkscape:window-height="701"
+ gridspacingy="1.0000000pt"
+ gridspacingx="1.0000000pt"
+ gridtolerance="1.0000000px"
+ inkscape:window-x="0"
+ inkscape:window-y="0" />
+ <defs
+ id="defs1445">
+ <linearGradient
+ id="linearGradient973">
+ <stop
+ style="stop-color:#0000ff;stop-opacity:0.0000000;"
+ offset="0.0000000"
+ id="stop974" />
+ <stop
+ style="stop-color:#fff;stop-opacity:1;"
+ offset="1"
+ id="stop975" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient868">
+ <stop
+ style="stop-color:#ffffff;stop-opacity:0.0000000;"
+ offset="0.0000000"
+ id="stop869" />
+ <stop
+ style="stop-color:#fff;stop-opacity:1;"
+ offset="1"
+ id="stop870" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient893">
+ <stop
+ style="stop-color:#19839a;stop-opacity:0.0000000;"
+ offset="0.0000000"
+ id="stop894" />
+ <stop
+ style="stop-color:#fff;stop-opacity:1;"
+ offset="1"
+ id="stop895" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient1455">
+ <stop
+ style="stop-color:#ebffff;stop-opacity:0.0000000;"
+ offset="0.0000000"
+ id="stop1456" />
+ <stop
+ style="stop-color:#fff;stop-opacity:1;"
+ offset="1"
+ id="stop1457" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient1458">
+ <stop
+ style="stop-color:#000;stop-opacity:1;"
+ offset="0"
+ id="stop1459" />
+ <stop
+ style="stop-color:#fff;stop-opacity:1;"
+ offset="1"
+ id="stop1460" />
+ </linearGradient>
+ <linearGradient
+ xlink:href="#linearGradient830"
+ id="linearGradient1461"
+ x1="1.5500000"
+ y1="0.52343750"
+ x2="0.20422535"
+ y2="-0.12195122"
+ spreadMethod="reflect" />
+ <linearGradient
+ xlink:href="#linearGradient830"
+ id="linearGradient1462"
+ x1="-0.31159419"
+ y1="0.19531250"
+ x2="0.77536231"
+ y2="0.94531250" />
+ <linearGradient
+ xlink:href="#linearGradient830"
+ id="linearGradient1463" />
+ <linearGradient
+ xlink:href="#linearGradient868"
+ id="linearGradient892" />
+ <linearGradient
+ xlink:href="#linearGradient973"
+ id="linearGradient926"
+ x1="1.5043305e-18"
+ y1="0.50000000"
+ x2="1.0000000"
+ y2="0.50000000" />
+ <linearGradient
+ xlink:href="#linearGradient868"
+ id="linearGradient928" />
+ <linearGradient
+ xlink:href="#linearGradient830"
+ id="linearGradient937"
+ x1="0.010563380"
+ y1="0.48571429"
+ x2="0.98943663"
+ y2="0.48571429"
+ spreadMethod="pad" />
+ <radialGradient
+ xlink:href="#linearGradient973"
+ id="radialGradient976"
+ cx="0.49275362"
+ cy="0.46875000"
+ r="0.80203730"
+ fx="0.49275362"
+ fy="0.46875000"
+ spreadMethod="reflect" />
+ </defs>
+ <sodipodi:namedview
+ id="namedview1469"
+ pagecolor="#ffffff"
+ bordercolor="#666666"
+ borderopacity="1.0"
+ inkscape:pageopacity="0.0"
+ inkscape:pageshadow="2"
+ inkscape:zoom="4.0000000"
+ inkscape:cx="79.132812"
+ inkscape:cy="66.817627"
+ inkscape:window-width="1022"
+ inkscape:window-height="701"
+ gridspacingy="1.0000000pt"
+ gridspacingx="1.0000000pt"
+ gridtolerance="1.0000000px"
+ inkscape:window-x="0"
+ inkscape:window-y="0" />
+ <defs
+ id="defs1515">
+ <linearGradient
+ id="linearGradient1516">
+ <stop
+ style="stop-color:#ffffff;stop-opacity:0.0000000;"
+ offset="0.0000000"
+ id="stop1517" />
+ <stop
+ style="stop-color:#fff;stop-opacity:1;"
+ offset="1"
+ id="stop1518" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient1519">
+ <stop
+ style="stop-color:#19839a;stop-opacity:0.0000000;"
+ offset="0.0000000"
+ id="stop1520" />
+ <stop
+ style="stop-color:#fff;stop-opacity:1;"
+ offset="1"
+ id="stop1521" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient1522">
+ <stop
+ style="stop-color:#ebffff;stop-opacity:0.0000000;"
+ offset="0.0000000"
+ id="stop1523" />
+ <stop
+ style="stop-color:#fff;stop-opacity:1;"
+ offset="1"
+ id="stop1524" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient1525">
+ <stop
+ style="stop-color:#000;stop-opacity:1;"
+ offset="0"
+ id="stop1526" />
+ <stop
+ style="stop-color:#fff;stop-opacity:1;"
+ offset="1"
+ id="stop1527" />
+ </linearGradient>
+ <linearGradient
+ xlink:href="#linearGradient830"
+ id="linearGradient1528"
+ x1="1.5500000"
+ y1="0.52343750"
+ x2="0.20422535"
+ y2="-0.12195122"
+ spreadMethod="reflect" />
+ <linearGradient
+ xlink:href="#linearGradient830"
+ id="linearGradient1529"
+ x1="-0.31159419"
+ y1="0.19531250"
+ x2="0.77536231"
+ y2="0.94531250" />
+ <linearGradient
+ xlink:href="#linearGradient830"
+ id="linearGradient1530" />
+ <linearGradient
+ xlink:href="#linearGradient868"
+ id="linearGradient1531" />
+ </defs>
+ <sodipodi:namedview
+ id="namedview1532"
+ pagecolor="#ffffff"
+ bordercolor="#666666"
+ borderopacity="1.0"
+ inkscape:pageopacity="0.0"
+ inkscape:pageshadow="2"
+ inkscape:zoom="4.0000000"
+ inkscape:cx="79.132812"
+ inkscape:cy="69.358765"
+ inkscape:window-width="1022"
+ inkscape:window-height="701"
+ gridspacingy="1.0000000pt"
+ gridspacingx="1.0000000pt"
+ gridtolerance="1.0000000px"
+ inkscape:window-x="0"
+ inkscape:window-y="0" />
+ <defs
+ id="defs921">
+ <linearGradient
+ id="linearGradient922">
+ <stop
+ style="stop-color:#ffffff;stop-opacity:0.0000000;"
+ offset="0.0000000"
+ id="stop923" />
+ <stop
+ style="stop-color:#fff;stop-opacity:1;"
+ offset="1"
+ id="stop924" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient925">
+ <stop
+ style="stop-color:#19839a;stop-opacity:0.0000000;"
+ offset="0.0000000"
+ id="stop926" />
+ <stop
+ style="stop-color:#fff;stop-opacity:1;"
+ offset="1"
+ id="stop927" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient929">
+ <stop
+ style="stop-color:#ebffff;stop-opacity:0.0000000;"
+ offset="0.0000000"
+ id="stop930" />
+ <stop
+ style="stop-color:#fff;stop-opacity:1;"
+ offset="1"
+ id="stop931" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient932">
+ <stop
+ style="stop-color:#000;stop-opacity:1;"
+ offset="0"
+ id="stop933" />
+ <stop
+ style="stop-color:#fff;stop-opacity:1;"
+ offset="1"
+ id="stop934" />
+ </linearGradient>
+ <linearGradient
+ xlink:href="#linearGradient830"
+ id="linearGradient935"
+ x1="1.5500000"
+ y1="0.52343750"
+ x2="0.20422535"
+ y2="-0.12195122"
+ spreadMethod="reflect" />
+ <linearGradient
+ xlink:href="#linearGradient830"
+ id="linearGradient936"
+ x1="-0.31159419"
+ y1="0.19531250"
+ x2="0.77536231"
+ y2="0.94531250" />
+ <linearGradient
+ xlink:href="#linearGradient830"
+ id="linearGradient938" />
+ <linearGradient
+ xlink:href="#linearGradient868"
+ id="linearGradient939"
+ x1="0.39932632"
+ y1="0.50707734"
+ x2="0.64623892"
+ y2="0.60370040"
+ spreadMethod="reflect" />
+ </defs>
+ <sodipodi:namedview
+ id="namedview940"
+ pagecolor="#ffffff"
+ bordercolor="#666666"
+ borderopacity="1.0"
+ inkscape:pageopacity="0.0"
+ inkscape:pageshadow="2"
+ inkscape:zoom="4.0000000"
+ inkscape:cx="79.132812"
+ inkscape:cy="69.358765"
+ inkscape:window-width="1022"
+ inkscape:window-height="701"
+ gridspacingy="1.0000000pt"
+ gridspacingx="1.0000000pt"
+ gridtolerance="1.0000000px"
+ inkscape:window-x="0"
+ inkscape:window-y="0" />
+ <defs
+ id="defs1253">
+ <linearGradient
+ id="linearGradient1254">
+ <stop
+ style="stop-color:#ebffff;stop-opacity:0.0000000;"
+ offset="0.0000000"
+ id="stop1255" />
+ <stop
+ style="stop-color:#fff;stop-opacity:1;"
+ offset="1"
+ id="stop1256" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient1257">
+ <stop
+ style="stop-color:#000;stop-opacity:1;"
+ offset="0"
+ id="stop1258" />
+ <stop
+ style="stop-color:#fff;stop-opacity:1;"
+ offset="1"
+ id="stop1259" />
+ </linearGradient>
+ <linearGradient
+ xlink:href="#linearGradient830"
+ id="linearGradient1260"
+ x1="1.5500000"
+ y1="0.52343750"
+ x2="0.20422535"
+ y2="-0.12195122"
+ spreadMethod="reflect" />
+ <linearGradient
+ xlink:href="#linearGradient830"
+ id="linearGradient1261"
+ x1="-0.31159419"
+ y1="0.19531250"
+ x2="0.77536231"
+ y2="0.94531250" />
+ <linearGradient
+ xlink:href="#linearGradient830"
+ id="linearGradient1262" />
+ </defs>
+ <sodipodi:namedview
+ id="namedview1263"
+ pagecolor="#ffffff"
+ bordercolor="#666666"
+ borderopacity="1.0"
+ inkscape:pageopacity="0.0"
+ inkscape:pageshadow="2"
+ inkscape:zoom="4.0000000"
+ inkscape:cx="96.390219"
+ inkscape:cy="55.703735"
+ inkscape:window-width="1022"
+ inkscape:window-height="701"
+ gridspacingy="1.0000000pt"
+ gridspacingx="1.0000000pt"
+ gridtolerance="1.0000000px"
+ inkscape:window-x="0"
+ inkscape:window-y="0" />
+ <defs
+ id="defs1365">
+ <linearGradient
+ id="linearGradient1366">
+ <stop
+ style="stop-color:#ffff21;stop-opacity:0.0000000;"
+ offset="0.0000000"
+ id="stop1367" />
+ <stop
+ style="stop-color:#fff;stop-opacity:1;"
+ offset="1"
+ id="stop1368" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient1369">
+ <stop
+ style="stop-color:#ffffff;stop-opacity:0.0000000;"
+ offset="0.0000000"
+ id="stop1370" />
+ <stop
+ style="stop-color:#fff;stop-opacity:1;"
+ offset="1"
+ id="stop1371" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient1372">
+ <stop
+ style="stop-color:#ebffff;stop-opacity:0.0000000;"
+ offset="0.0000000"
+ id="stop1373" />
+ <stop
+ style="stop-color:#fff;stop-opacity:1;"
+ offset="1"
+ id="stop1374" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient1375">
+ <stop
+ style="stop-color:#000;stop-opacity:1;"
+ offset="0"
+ id="stop1376" />
+ <stop
+ style="stop-color:#fff;stop-opacity:1;"
+ offset="1"
+ id="stop1377" />
+ </linearGradient>
+ <linearGradient
+ xlink:href="#linearGradient830"
+ id="linearGradient1378"
+ x1="1.5500000"
+ y1="0.52343750"
+ x2="0.20422535"
+ y2="-0.12195122"
+ spreadMethod="reflect" />
+ <linearGradient
+ xlink:href="#linearGradient830"
+ id="linearGradient1379" />
+ <linearGradient
+ xlink:href="#linearGradient830"
+ id="linearGradient1380" />
+ <linearGradient
+ xlink:href="#linearGradient1763"
+ id="linearGradient1381"
+ x1="-0.34579438"
+ y1="-0.16406250"
+ x2="0.71962619"
+ y2="0.80468750" />
+ <linearGradient
+ xlink:href="#linearGradient1796"
+ id="linearGradient1382"
+ x1="0.65555555"
+ y1="0.88281250"
+ x2="0.48888889"
+ y2="0.53906250"
+ spreadMethod="reflect" />
+ <defs
+ id="defs1383">
+ <linearGradient
+ id="linearGradient1384">
+ <stop
+ style="stop-color:#ebffff;stop-opacity:0.0000000;"
+ offset="0.0000000"
+ id="stop1385" />
+ <stop
+ style="stop-color:#fff;stop-opacity:1;"
+ offset="1"
+ id="stop1386" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient1387">
+ <stop
+ style="stop-color:#000;stop-opacity:1;"
+ offset="0"
+ id="stop1388" />
+ <stop
+ style="stop-color:#fff;stop-opacity:1;"
+ offset="1"
+ id="stop1389" />
+ </linearGradient>
+ <linearGradient
+ xlink:href="#linearGradient830"
+ id="linearGradient1390"
+ x1="1.5500000"
+ y1="0.52343750"
+ x2="0.20422535"
+ y2="-0.12195122"
+ spreadMethod="reflect" />
+ <linearGradient
+ xlink:href="#linearGradient830"
+ id="linearGradient1391"
+ x1="-0.31159419"
+ y1="0.19531250"
+ x2="0.77536231"
+ y2="0.94531250" />
+ <linearGradient
+ xlink:href="#linearGradient830"
+ id="linearGradient1392" />
+ </defs>
+ <sodipodi:namedview
+ id="namedview1393"
+ pagecolor="#ffffff"
+ bordercolor="#666666"
+ borderopacity="1.0"
+ inkscape:pageopacity="0.0"
+ inkscape:pageshadow="2"
+ inkscape:zoom="0.26725582"
+ inkscape:cx="87.469639"
+ inkscape:cy="55.703730"
+ inkscape:window-width="1022"
+ inkscape:window-height="701"
+ gridspacingy="1.0000000pt"
+ gridspacingx="1.0000000pt"
+ gridtolerance="1.0000000px"
+ inkscape:window-x="0"
+ inkscape:window-y="0" />
+ <defs
+ id="defs1394">
+ <linearGradient
+ id="linearGradient1395">
+ <stop
+ style="stop-color:#0000ff;stop-opacity:0.0000000;"
+ offset="0.0000000"
+ id="stop1396" />
+ <stop
+ style="stop-color:#fff;stop-opacity:1;"
+ offset="1"
+ id="stop1397" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient1398">
+ <stop
+ style="stop-color:#ffffff;stop-opacity:0.0000000;"
+ offset="0.0000000"
+ id="stop1399" />
+ <stop
+ style="stop-color:#fff;stop-opacity:1;"
+ offset="1"
+ id="stop1400" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient1401">
+ <stop
+ style="stop-color:#19839a;stop-opacity:0.0000000;"
+ offset="0.0000000"
+ id="stop1402" />
+ <stop
+ style="stop-color:#fff;stop-opacity:1;"
+ offset="1"
+ id="stop1403" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient1404">
+ <stop
+ style="stop-color:#ebffff;stop-opacity:0.0000000;"
+ offset="0.0000000"
+ id="stop1405" />
+ <stop
+ style="stop-color:#fff;stop-opacity:1;"
+ offset="1"
+ id="stop1406" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient1407">
+ <stop
+ style="stop-color:#000;stop-opacity:1;"
+ offset="0"
+ id="stop1408" />
+ <stop
+ style="stop-color:#fff;stop-opacity:1;"
+ offset="1"
+ id="stop1409" />
+ </linearGradient>
+ <linearGradient
+ xlink:href="#linearGradient830"
+ id="linearGradient1410"
+ x1="1.5500000"
+ y1="0.52343750"
+ x2="0.20422535"
+ y2="-0.12195122"
+ spreadMethod="reflect" />
+ <linearGradient
+ xlink:href="#linearGradient830"
+ id="linearGradient1411"
+ x1="-0.31159419"
+ y1="0.19531250"
+ x2="0.77536231"
+ y2="0.94531250" />
+ <linearGradient
+ xlink:href="#linearGradient830"
+ id="linearGradient1412" />
+ <linearGradient
+ xlink:href="#linearGradient868"
+ id="linearGradient1413" />
+ <linearGradient
+ xlink:href="#linearGradient973"
+ id="linearGradient1414"
+ x1="1.5043305e-18"
+ y1="0.50000000"
+ x2="1.0000000"
+ y2="0.50000000" />
+ <linearGradient
+ xlink:href="#linearGradient868"
+ id="linearGradient1415" />
+ <linearGradient
+ xlink:href="#linearGradient830"
+ id="linearGradient1416"
+ x1="0.010563380"
+ y1="0.48571429"
+ x2="0.98943663"
+ y2="0.48571429"
+ spreadMethod="pad" />
+ <radialGradient
+ xlink:href="#linearGradient973"
+ id="radialGradient1417"
+ cx="0.49275362"
+ cy="0.46875000"
+ r="0.80203730"
+ fx="0.49275362"
+ fy="0.46875000"
+ spreadMethod="reflect" />
+ </defs>
+ <sodipodi:namedview
+ id="namedview1418"
+ pagecolor="#ffffff"
+ bordercolor="#666666"
+ borderopacity="1.0"
+ inkscape:pageopacity="0.0"
+ inkscape:pageshadow="2"
+ inkscape:zoom="4.0000000"
+ inkscape:cx="79.132812"
+ inkscape:cy="66.817627"
+ inkscape:window-width="1022"
+ inkscape:window-height="701"
+ gridspacingy="1.0000000pt"
+ gridspacingx="1.0000000pt"
+ gridtolerance="1.0000000px"
+ inkscape:window-x="0"
+ inkscape:window-y="0" />
+ <defs
+ id="defs1419">
+ <linearGradient
+ id="linearGradient1420">
+ <stop
+ style="stop-color:#ffffff;stop-opacity:0.0000000;"
+ offset="0.0000000"
+ id="stop1421" />
+ <stop
+ style="stop-color:#fff;stop-opacity:1;"
+ offset="1"
+ id="stop1422" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient1423">
+ <stop
+ style="stop-color:#19839a;stop-opacity:0.0000000;"
+ offset="0.0000000"
+ id="stop1424" />
+ <stop
+ style="stop-color:#fff;stop-opacity:1;"
+ offset="1"
+ id="stop1425" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient1426">
+ <stop
+ style="stop-color:#ebffff;stop-opacity:0.0000000;"
+ offset="0.0000000"
+ id="stop1427" />
+ <stop
+ style="stop-color:#fff;stop-opacity:1;"
+ offset="1"
+ id="stop1428" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient1429">
+ <stop
+ style="stop-color:#000;stop-opacity:1;"
+ offset="0"
+ id="stop1430" />
+ <stop
+ style="stop-color:#fff;stop-opacity:1;"
+ offset="1"
+ id="stop1431" />
+ </linearGradient>
+ <linearGradient
+ xlink:href="#linearGradient830"
+ id="linearGradient1432"
+ x1="1.5500000"
+ y1="0.52343750"
+ x2="0.20422535"
+ y2="-0.12195122"
+ spreadMethod="reflect" />
+ <linearGradient
+ xlink:href="#linearGradient830"
+ id="linearGradient1433"
+ x1="-0.31159419"
+ y1="0.19531250"
+ x2="0.77536231"
+ y2="0.94531250" />
+ <linearGradient
+ xlink:href="#linearGradient830"
+ id="linearGradient1434" />
+ <linearGradient
+ xlink:href="#linearGradient868"
+ id="linearGradient1435" />
+ </defs>
+ <sodipodi:namedview
+ id="namedview1436"
+ pagecolor="#ffffff"
+ bordercolor="#666666"
+ borderopacity="1.0"
+ inkscape:pageopacity="0.0"
+ inkscape:pageshadow="2"
+ inkscape:zoom="4.0000000"
+ inkscape:cx="79.132812"
+ inkscape:cy="69.358765"
+ inkscape:window-width="1022"
+ inkscape:window-height="701"
+ gridspacingy="1.0000000pt"
+ gridspacingx="1.0000000pt"
+ gridtolerance="1.0000000px"
+ inkscape:window-x="0"
+ inkscape:window-y="0" />
+ <defs
+ id="defs1437">
+ <linearGradient
+ id="linearGradient1438">
+ <stop
+ style="stop-color:#ffffff;stop-opacity:0.0000000;"
+ offset="0.0000000"
+ id="stop1439" />
+ <stop
+ style="stop-color:#fff;stop-opacity:1;"
+ offset="1"
+ id="stop1440" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient1441">
+ <stop
+ style="stop-color:#19839a;stop-opacity:0.0000000;"
+ offset="0.0000000"
+ id="stop1442" />
+ <stop
+ style="stop-color:#fff;stop-opacity:1;"
+ offset="1"
+ id="stop1443" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient1444">
+ <stop
+ style="stop-color:#ebffff;stop-opacity:0.0000000;"
+ offset="0.0000000"
+ id="stop1445" />
+ <stop
+ style="stop-color:#fff;stop-opacity:1;"
+ offset="1"
+ id="stop1446" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient1447">
+ <stop
+ style="stop-color:#000;stop-opacity:1;"
+ offset="0"
+ id="stop1448" />
+ <stop
+ style="stop-color:#fff;stop-opacity:1;"
+ offset="1"
+ id="stop1449" />
+ </linearGradient>
+ <linearGradient
+ xlink:href="#linearGradient830"
+ id="linearGradient1450"
+ x1="1.5500000"
+ y1="0.52343750"
+ x2="0.20422535"
+ y2="-0.12195122"
+ spreadMethod="reflect" />
+ <linearGradient
+ xlink:href="#linearGradient830"
+ id="linearGradient1451"
+ x1="-0.31159419"
+ y1="0.19531250"
+ x2="0.77536231"
+ y2="0.94531250" />
+ <linearGradient
+ xlink:href="#linearGradient830"
+ id="linearGradient1452" />
+ <linearGradient
+ xlink:href="#linearGradient868"
+ id="linearGradient1453"
+ x1="0.39932632"
+ y1="0.50707734"
+ x2="0.64623892"
+ y2="0.60370040"
+ spreadMethod="reflect" />
+ </defs>
+ <sodipodi:namedview
+ id="namedview1454"
+ pagecolor="#ffffff"
+ bordercolor="#666666"
+ borderopacity="1.0"
+ inkscape:pageopacity="0.0"
+ inkscape:pageshadow="2"
+ inkscape:zoom="4.0000000"
+ inkscape:cx="79.132812"
+ inkscape:cy="69.358765"
+ inkscape:window-width="1022"
+ inkscape:window-height="701"
+ gridspacingy="1.0000000pt"
+ gridspacingx="1.0000000pt"
+ gridtolerance="1.0000000px"
+ inkscape:window-x="0"
+ inkscape:window-y="0" />
+ </defs>
+ <sodipodi:namedview
+ id="namedview1455"
+ pagecolor="#ffffff"
+ bordercolor="#666666"
+ borderopacity="1.0"
+ inkscape:pageopacity="0.0"
+ inkscape:pageshadow="2"
+ inkscape:zoom="4.0000000"
+ inkscape:cx="106.45706"
+ inkscape:cy="64.249115"
+ inkscape:window-width="1022"
+ inkscape:window-height="701"
+ gridspacingy="1.0000000pt"
+ gridspacingx="1.0000000pt"
+ gridtolerance="1.0000000px"
+ inkscape:window-x="0"
+ inkscape:window-y="0"
+ showgrid="false"
+ snaptogrid="false" />
+ </defs>
+ <sodipodi:namedview
+ id="base"
+ pagecolor="#ffffff"
+ bordercolor="#666666"
+ borderopacity="1.0"
+ inkscape:pageopacity="0.0"
+ inkscape:pageshadow="2"
+ inkscape:zoom="22.6274170"
+ inkscape:cx="1.89864068"
+ inkscape:cy="9.31486758"
+ inkscape:window-width="1016"
+ inkscape:window-height="693"
+ gridspacingy="1.0000000pt"
+ gridspacingx="1.0000000pt"
+ gridtolerance="1.0000000px"
+ inkscape:window-x="0"
+ inkscape:window-y="0"
+ showgrid="true"
+ snaptogrid="false" />
+ <rect
+ style="fill:url(#linearGradient829);fill-opacity:0.75000000;fill-rule:evenodd;stroke-width:0.45652742pt;"
+ id="rect825"
+ width="137.68759"
+ height="66.465706"
+ ry="0.0000000"
+ x="359.81241"
+ y="197.28429" />
+ <rect
+ style="fill:url(#linearGradient829);fill-opacity:0.75000000;fill-rule:evenodd;stroke-width:0.45652742pt;"
+ id="rect846"
+ width="135.18759"
+ height="37.082668"
+ ry="0.0000000"
+ x="316.25000"
+ y="81.250000" />
+ <rect
+ style="fill:url(#linearGradient829);fill-opacity:0.75000000;fill-rule:evenodd;stroke:none;stroke-width:0.45652742pt;stroke-opacity:1.0000000;"
+ id="rect847"
+ width="135.18759"
+ height="47.111610"
+ ry="0.0000000"
+ x="255.00000"
+ y="157.88839" />
+ <rect
+ style="fill:url(#linearGradient829);fill-opacity:0.75000000;fill-rule:evenodd;stroke-width:0.45652742pt;"
+ id="rect1456"
+ width="137.68759"
+ height="66.465706"
+ ry="0.0000000"
+ x="359.81241"
+ y="197.28429" />
+ <rect
+ style="fill:url(#linearGradient829);fill-opacity:0.75000000;fill-rule:evenodd;stroke-width:0.45652742pt;"
+ id="rect1458"
+ width="135.18759"
+ height="47.111610"
+ ry="0.0000000"
+ x="255.00000"
+ y="157.88839" />
+ <path
+ style="font-size:12;fill:#8df2ff;fill-rule:evenodd;stroke-width:5;"
+ d="M 0.31849596 0.80526346 L 0.31849596 20.002095 L 19.625748 20.002095 L 19.625748 11.470169 C 19.828982 5.0712257 15.606949 1.731259 12.558436 0.87806654 L 0.31849596 0.80526346 z "
+ id="path1780"
+ sodipodi:nodetypes="cccccc" />
+ <path
+ style="font-size:12;fill:url(#linearGradient1762);fill-opacity:0.75;fill-rule:evenodd;stroke:#0083e3;stroke-width:1.21772;"
+ d="M 0.63498263 0.72032515 L 12.05856 0.79124256 C 14.063244 0.54685657 18.604921 3.8399269 13.0609 8.3672103 C 16.569096 7.8784382 18.907893 6.6565079 19.409064 10.566685 L 19.445049 19.419973 L 0.63498263 19.419973 L 0.63498263 0.72032515 z "
+ id="path1781"
+ sodipodi:nodetypes="ccccccc" />
+ <rect
+ style="font-size:12;fill:#ffff00;fill-rule:evenodd;stroke:#ff0000;stroke-width:0.603437;"
+ id="rect837"
+ width="9.58012390"
+ height="6.48194178"
+ x="1.66582549"
+ y="1.92005699" />
+ <rect
+ style="font-size:12;fill:url(#linearGradient829);fill-opacity:0.75;fill-rule:evenodd;stroke-width:0.456527pt;"
+ id="rect1267"
+ width="8.88955975"
+ height="5.83366172"
+ ry="0"
+ x="2.02622056"
+ y="2.26269646" />
+ <text
+ xml:space="preserve"
+ style="font-size:12;font-weight:normal;font-stretch:normal;stroke-width:1pt;font-family:Bitstream Vera Sans;font-style:normal;text-anchor:start;writing-mode:lr;"
+ x="62.241082"
+ y="18.111817"
+ id="text838"
+ transform="matrix(0.363236,0.000000,0.000000,0.306934,-20.18922,0.613913)"
+ sodipodi:linespacing="100%"><tspan
+ x="62.2410812"
+ y="18.1118164"
+ sodipodi:role="line"
+ id="tspan1117">A:B</tspan></text>
+ <path
+ style="font-size:12;fill:none;fill-opacity:0.75;fill-rule:evenodd;stroke:#000000;stroke-width:5;"
+ d="M 179.16981,52.967263 L 240.02454,52.967263"
+ id="path842"
+ transform="matrix(0.125840,0.000000,0.000000,0.125610,-20.18922,0.613913)" />
+ <path
+ style="font-size:12;fill:none;fill-opacity:0.75;fill-rule:evenodd;stroke:#ff0000;stroke-width:0.646377;stroke-dashoffset:0;"
+ d="M 3.8776774 8.5881294 L 3.8776774 15.726366 L 6.9450274 15.726366 "
+ id="path1471"
+ sodipodi:nodetypes="ccc" />
+ <path
+ style="font-size:12;fill:none;fill-opacity:0.75;fill-rule:evenodd;stroke:#ff0000;stroke-width:5;"
+ d="M 41.875000,114.68750 L 60.625000,125.31250 L 42.500000,139.68750"
+ id="path971"
+ sodipodi:nodetypes="ccc"
+ transform="matrix(0.125840,0.000000,0.000000,0.125610,-5.482262e-2,-1.413717e-2)" />
+ <rect
+ style="font-size:12;fill:#ffff00;fill-rule:evenodd;stroke:#ff0000;stroke-width:5;"
+ id="rect1605"
+ width="76.129402"
+ height="56.001663"
+ x="171.91731"
+ y="10.398407"
+ transform="matrix(0.125840,0.000000,0.000000,0.125610,-13.30508,9.803950)" />
+ <rect
+ style="font-size:12;fill:url(#linearGradient829);fill-opacity:0.75;fill-rule:evenodd;stroke-width:0.456527pt;"
+ id="rect1606"
+ width="70.641762"
+ height="50.840607"
+ ry="0.0000000"
+ x="173.90324"
+ y="12.246621"
+ transform="matrix(0.125840,0.000000,0.000000,0.125610,-13.30508,9.803950)" />
+ <text
+ xml:space="preserve"
+ style="font-size:12;font-weight:normal;font-stretch:normal;stroke-width:1pt;font-family:Bitstream Vera Sans;font-style:normal;text-anchor:start;writing-mode:lr;"
+ x="62.241082"
+ y="18.111817"
+ id="text1607"
+ transform="matrix(0.363236,0.000000,0.000000,0.306934,-13.30508,9.803950)"
+ sodipodi:linespacing="100%"><tspan
+ x="62.2410812"
+ y="18.1118164"
+ sodipodi:role="line"
+ id="tspan1125">A:B</tspan></text>
+ <path
+ style="font-size:12;fill:none;fill-opacity:0.75;fill-rule:evenodd;stroke:#000000;stroke-width:5;"
+ d="M 179.16981,52.967263 L 240.02454,52.967263"
+ id="path1610"
+ transform="matrix(0.125840,0.000000,0.000000,0.125610,-13.30508,9.803950)" />
+</svg>
diff --git a/umbrello/umbrello/pics/sources/diag_component.svg b/umbrello/umbrello/pics/sources/diag_component.svg
new file mode 100644
index 00000000..e8859441
--- /dev/null
+++ b/umbrello/umbrello/pics/sources/diag_component.svg
@@ -0,0 +1,732 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 20010904//EN"
+"http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd">
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+<svg
+ id="svg1"
+ sodipodi:version="0.32"
+ inkscape:version="0.37"
+ width="16pt"
+ height="16pt"
+ sodipodi:docbase="/home/jr/tmp/umbrello/icons/inkscape-svg"
+ sodipodi:docname="diag_component.svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:xlink="http://www.w3.org/1999/xlink">
+ <defs
+ id="defs3">
+ <linearGradient
+ id="linearGradient1796">
+ <stop
+ style="stop-color:#ffff21;stop-opacity:0.0000000;"
+ offset="0.0000000"
+ id="stop1797" />
+ <stop
+ style="stop-color:#fff;stop-opacity:1;"
+ offset="1"
+ id="stop1798" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient1763">
+ <stop
+ style="stop-color:#ffffff;stop-opacity:0.0000000;"
+ offset="0.0000000"
+ id="stop1764" />
+ <stop
+ style="stop-color:#fff;stop-opacity:1;"
+ offset="1"
+ id="stop1765" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient830">
+ <stop
+ style="stop-color:#ebffff;stop-opacity:0.0000000;"
+ offset="0.0000000"
+ id="stop831" />
+ <stop
+ style="stop-color:#fff;stop-opacity:1;"
+ offset="1"
+ id="stop832" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient826">
+ <stop
+ style="stop-color:#000;stop-opacity:1;"
+ offset="0"
+ id="stop827" />
+ <stop
+ style="stop-color:#fff;stop-opacity:1;"
+ offset="1"
+ id="stop828" />
+ </linearGradient>
+ <linearGradient
+ xlink:href="#linearGradient830"
+ id="linearGradient829"
+ x1="1.5500000"
+ y1="0.52343750"
+ x2="0.20422535"
+ y2="-0.12195122"
+ spreadMethod="reflect" />
+ <linearGradient
+ xlink:href="#linearGradient830"
+ id="linearGradient834" />
+ <linearGradient
+ xlink:href="#linearGradient830"
+ id="linearGradient836" />
+ <linearGradient
+ xlink:href="#linearGradient1763"
+ id="linearGradient1762"
+ x1="-0.34579438"
+ y1="-0.16406250"
+ x2="0.71962619"
+ y2="0.80468750" />
+ <linearGradient
+ xlink:href="#linearGradient1796"
+ id="linearGradient1795"
+ x1="0.65555555"
+ y1="0.88281250"
+ x2="0.48888889"
+ y2="0.53906250"
+ spreadMethod="reflect" />
+ <defs
+ id="defs1348">
+ <linearGradient
+ id="linearGradient1349">
+ <stop
+ style="stop-color:#ebffff;stop-opacity:0.0000000;"
+ offset="0.0000000"
+ id="stop1350" />
+ <stop
+ style="stop-color:#fff;stop-opacity:1;"
+ offset="1"
+ id="stop1351" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient1352">
+ <stop
+ style="stop-color:#000;stop-opacity:1;"
+ offset="0"
+ id="stop1353" />
+ <stop
+ style="stop-color:#fff;stop-opacity:1;"
+ offset="1"
+ id="stop1354" />
+ </linearGradient>
+ <linearGradient
+ xlink:href="#linearGradient830"
+ id="linearGradient1355"
+ x1="1.5500000"
+ y1="0.52343750"
+ x2="0.20422535"
+ y2="-0.12195122"
+ spreadMethod="reflect" />
+ <linearGradient
+ xlink:href="#linearGradient830"
+ id="linearGradient1356"
+ x1="-0.31159419"
+ y1="0.19531250"
+ x2="0.77536231"
+ y2="0.94531250" />
+ <linearGradient
+ xlink:href="#linearGradient830"
+ id="linearGradient1357" />
+ </defs>
+ <sodipodi:namedview
+ id="namedview1358"
+ pagecolor="#ffffff"
+ bordercolor="#666666"
+ borderopacity="1.0"
+ inkscape:pageopacity="0.0"
+ inkscape:pageshadow="2"
+ inkscape:zoom="0.26725582"
+ inkscape:cx="87.469639"
+ inkscape:cy="55.703730"
+ inkscape:window-width="1022"
+ inkscape:window-height="701"
+ gridspacingy="1.0000000pt"
+ gridspacingx="1.0000000pt"
+ gridtolerance="1.0000000px"
+ inkscape:window-x="0"
+ inkscape:window-y="0" />
+ <defs
+ id="defs1445">
+ <linearGradient
+ id="linearGradient973">
+ <stop
+ style="stop-color:#0000ff;stop-opacity:0.0000000;"
+ offset="0.0000000"
+ id="stop974" />
+ <stop
+ style="stop-color:#fff;stop-opacity:1;"
+ offset="1"
+ id="stop975" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient868">
+ <stop
+ style="stop-color:#ffffff;stop-opacity:0.0000000;"
+ offset="0.0000000"
+ id="stop869" />
+ <stop
+ style="stop-color:#fff;stop-opacity:1;"
+ offset="1"
+ id="stop870" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient893">
+ <stop
+ style="stop-color:#19839a;stop-opacity:0.0000000;"
+ offset="0.0000000"
+ id="stop894" />
+ <stop
+ style="stop-color:#fff;stop-opacity:1;"
+ offset="1"
+ id="stop895" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient1455">
+ <stop
+ style="stop-color:#ebffff;stop-opacity:0.0000000;"
+ offset="0.0000000"
+ id="stop1456" />
+ <stop
+ style="stop-color:#fff;stop-opacity:1;"
+ offset="1"
+ id="stop1457" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient1458">
+ <stop
+ style="stop-color:#000;stop-opacity:1;"
+ offset="0"
+ id="stop1459" />
+ <stop
+ style="stop-color:#fff;stop-opacity:1;"
+ offset="1"
+ id="stop1460" />
+ </linearGradient>
+ <linearGradient
+ xlink:href="#linearGradient830"
+ id="linearGradient1461"
+ x1="1.5500000"
+ y1="0.52343750"
+ x2="0.20422535"
+ y2="-0.12195122"
+ spreadMethod="reflect" />
+ <linearGradient
+ xlink:href="#linearGradient830"
+ id="linearGradient1462"
+ x1="-0.31159419"
+ y1="0.19531250"
+ x2="0.77536231"
+ y2="0.94531250" />
+ <linearGradient
+ xlink:href="#linearGradient830"
+ id="linearGradient1463" />
+ <linearGradient
+ xlink:href="#linearGradient868"
+ id="linearGradient892" />
+ <linearGradient
+ xlink:href="#linearGradient973"
+ id="linearGradient926"
+ x1="1.5043305e-18"
+ y1="0.50000000"
+ x2="1.0000000"
+ y2="0.50000000" />
+ <linearGradient
+ xlink:href="#linearGradient868"
+ id="linearGradient928" />
+ <linearGradient
+ xlink:href="#linearGradient830"
+ id="linearGradient937"
+ x1="0.010563380"
+ y1="0.48571429"
+ x2="0.98943663"
+ y2="0.48571429"
+ spreadMethod="pad" />
+ <radialGradient
+ xlink:href="#linearGradient973"
+ id="radialGradient976"
+ cx="0.49275362"
+ cy="0.46875000"
+ r="0.80203730"
+ fx="0.49275362"
+ fy="0.46875000"
+ spreadMethod="reflect" />
+ </defs>
+ <sodipodi:namedview
+ id="namedview1469"
+ pagecolor="#ffffff"
+ bordercolor="#666666"
+ borderopacity="1.0"
+ inkscape:pageopacity="0.0"
+ inkscape:pageshadow="2"
+ inkscape:zoom="4.0000000"
+ inkscape:cx="79.132812"
+ inkscape:cy="66.817627"
+ inkscape:window-width="1022"
+ inkscape:window-height="701"
+ gridspacingy="1.0000000pt"
+ gridspacingx="1.0000000pt"
+ gridtolerance="1.0000000px"
+ inkscape:window-x="0"
+ inkscape:window-y="0" />
+ <defs
+ id="defs1515">
+ <linearGradient
+ id="linearGradient1516">
+ <stop
+ style="stop-color:#ffffff;stop-opacity:0.0000000;"
+ offset="0.0000000"
+ id="stop1517" />
+ <stop
+ style="stop-color:#fff;stop-opacity:1;"
+ offset="1"
+ id="stop1518" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient1519">
+ <stop
+ style="stop-color:#19839a;stop-opacity:0.0000000;"
+ offset="0.0000000"
+ id="stop1520" />
+ <stop
+ style="stop-color:#fff;stop-opacity:1;"
+ offset="1"
+ id="stop1521" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient1522">
+ <stop
+ style="stop-color:#ebffff;stop-opacity:0.0000000;"
+ offset="0.0000000"
+ id="stop1523" />
+ <stop
+ style="stop-color:#fff;stop-opacity:1;"
+ offset="1"
+ id="stop1524" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient1525">
+ <stop
+ style="stop-color:#000;stop-opacity:1;"
+ offset="0"
+ id="stop1526" />
+ <stop
+ style="stop-color:#fff;stop-opacity:1;"
+ offset="1"
+ id="stop1527" />
+ </linearGradient>
+ <linearGradient
+ xlink:href="#linearGradient830"
+ id="linearGradient1528"
+ x1="1.5500000"
+ y1="0.52343750"
+ x2="0.20422535"
+ y2="-0.12195122"
+ spreadMethod="reflect" />
+ <linearGradient
+ xlink:href="#linearGradient830"
+ id="linearGradient1529"
+ x1="-0.31159419"
+ y1="0.19531250"
+ x2="0.77536231"
+ y2="0.94531250" />
+ <linearGradient
+ xlink:href="#linearGradient830"
+ id="linearGradient1530" />
+ <linearGradient
+ xlink:href="#linearGradient868"
+ id="linearGradient1531" />
+ </defs>
+ <sodipodi:namedview
+ id="namedview1532"
+ pagecolor="#ffffff"
+ bordercolor="#666666"
+ borderopacity="1.0"
+ inkscape:pageopacity="0.0"
+ inkscape:pageshadow="2"
+ inkscape:zoom="4.0000000"
+ inkscape:cx="79.132812"
+ inkscape:cy="69.358765"
+ inkscape:window-width="1022"
+ inkscape:window-height="701"
+ gridspacingy="1.0000000pt"
+ gridspacingx="1.0000000pt"
+ gridtolerance="1.0000000px"
+ inkscape:window-x="0"
+ inkscape:window-y="0" />
+ <defs
+ id="defs921">
+ <linearGradient
+ id="linearGradient922">
+ <stop
+ style="stop-color:#ffffff;stop-opacity:0.0000000;"
+ offset="0.0000000"
+ id="stop923" />
+ <stop
+ style="stop-color:#fff;stop-opacity:1;"
+ offset="1"
+ id="stop924" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient925">
+ <stop
+ style="stop-color:#19839a;stop-opacity:0.0000000;"
+ offset="0.0000000"
+ id="stop926" />
+ <stop
+ style="stop-color:#fff;stop-opacity:1;"
+ offset="1"
+ id="stop927" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient929">
+ <stop
+ style="stop-color:#ebffff;stop-opacity:0.0000000;"
+ offset="0.0000000"
+ id="stop930" />
+ <stop
+ style="stop-color:#fff;stop-opacity:1;"
+ offset="1"
+ id="stop931" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient932">
+ <stop
+ style="stop-color:#000;stop-opacity:1;"
+ offset="0"
+ id="stop933" />
+ <stop
+ style="stop-color:#fff;stop-opacity:1;"
+ offset="1"
+ id="stop934" />
+ </linearGradient>
+ <linearGradient
+ xlink:href="#linearGradient830"
+ id="linearGradient935"
+ x1="1.5500000"
+ y1="0.52343750"
+ x2="0.20422535"
+ y2="-0.12195122"
+ spreadMethod="reflect" />
+ <linearGradient
+ xlink:href="#linearGradient830"
+ id="linearGradient936"
+ x1="-0.31159419"
+ y1="0.19531250"
+ x2="0.77536231"
+ y2="0.94531250" />
+ <linearGradient
+ xlink:href="#linearGradient830"
+ id="linearGradient938" />
+ <linearGradient
+ xlink:href="#linearGradient868"
+ id="linearGradient939"
+ x1="0.39932632"
+ y1="0.50707734"
+ x2="0.64623892"
+ y2="0.60370040"
+ spreadMethod="reflect" />
+ </defs>
+ <sodipodi:namedview
+ id="namedview940"
+ pagecolor="#ffffff"
+ bordercolor="#666666"
+ borderopacity="1.0"
+ inkscape:pageopacity="0.0"
+ inkscape:pageshadow="2"
+ inkscape:zoom="4.0000000"
+ inkscape:cx="79.132812"
+ inkscape:cy="69.358765"
+ inkscape:window-width="1022"
+ inkscape:window-height="701"
+ gridspacingy="1.0000000pt"
+ gridspacingx="1.0000000pt"
+ gridtolerance="1.0000000px"
+ inkscape:window-x="0"
+ inkscape:window-y="0" />
+ <defs
+ id="defs1778">
+ <linearGradient
+ id="linearGradient1779">
+ <stop
+ style="stop-color:#ebffff;stop-opacity:0.0000000;"
+ offset="0.0000000"
+ id="stop1780" />
+ <stop
+ style="stop-color:#fff;stop-opacity:1;"
+ offset="1"
+ id="stop1781" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient1782">
+ <stop
+ style="stop-color:#000;stop-opacity:1;"
+ offset="0"
+ id="stop1783" />
+ <stop
+ style="stop-color:#fff;stop-opacity:1;"
+ offset="1"
+ id="stop1784" />
+ </linearGradient>
+ <linearGradient
+ xlink:href="#linearGradient830"
+ id="linearGradient1785"
+ x1="1.5500000"
+ y1="0.52343750"
+ x2="0.20422535"
+ y2="-0.12195122"
+ spreadMethod="reflect" />
+ <linearGradient
+ xlink:href="#linearGradient830"
+ id="linearGradient1786"
+ x1="-0.31159419"
+ y1="0.19531250"
+ x2="0.77536231"
+ y2="0.94531250" />
+ <linearGradient
+ xlink:href="#linearGradient830"
+ id="linearGradient1787" />
+ </defs>
+ <sodipodi:namedview
+ id="namedview1788"
+ pagecolor="#ffffff"
+ bordercolor="#666666"
+ borderopacity="1.0"
+ inkscape:pageopacity="0.0"
+ inkscape:pageshadow="2"
+ inkscape:zoom="4.0000000"
+ inkscape:cx="99.562933"
+ inkscape:cy="65.172729"
+ inkscape:window-width="1022"
+ inkscape:window-height="701"
+ gridspacingy="1.0000000pt"
+ gridspacingx="1.0000000pt"
+ gridtolerance="1.0000000px"
+ inkscape:window-x="0"
+ inkscape:window-y="0" />
+ <defs
+ id="defs1917">
+ <linearGradient
+ id="linearGradient1918">
+ <stop
+ style="stop-color:#ebffff;stop-opacity:0.0000000;"
+ offset="0.0000000"
+ id="stop1919" />
+ <stop
+ style="stop-color:#fff;stop-opacity:1;"
+ offset="1"
+ id="stop1920" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient1921">
+ <stop
+ style="stop-color:#000;stop-opacity:1;"
+ offset="0"
+ id="stop1922" />
+ <stop
+ style="stop-color:#fff;stop-opacity:1;"
+ offset="1"
+ id="stop1923" />
+ </linearGradient>
+ <linearGradient
+ xlink:href="#linearGradient830"
+ id="linearGradient1924"
+ x1="1.5500000"
+ y1="0.52343750"
+ x2="0.20422535"
+ y2="-0.12195122"
+ spreadMethod="reflect" />
+ <linearGradient
+ xlink:href="#linearGradient830"
+ id="linearGradient1925"
+ x1="-0.31159419"
+ y1="0.19531250"
+ x2="0.77536231"
+ y2="0.94531250" />
+ <linearGradient
+ xlink:href="#linearGradient830"
+ id="linearGradient1926" />
+ </defs>
+ <sodipodi:namedview
+ id="namedview1927"
+ pagecolor="#ffffff"
+ bordercolor="#666666"
+ borderopacity="1.0"
+ inkscape:pageopacity="0.0"
+ inkscape:pageshadow="2"
+ inkscape:zoom="4.0000000"
+ inkscape:cx="63.313473"
+ inkscape:cy="66.872360"
+ inkscape:window-width="1022"
+ inkscape:window-height="701"
+ gridspacingy="1.0000000pt"
+ gridspacingx="1.0000000pt"
+ gridtolerance="1.0000000px"
+ inkscape:window-x="0"
+ inkscape:window-y="0" />
+ </defs>
+ <sodipodi:namedview
+ id="base"
+ pagecolor="#ffffff"
+ bordercolor="#666666"
+ borderopacity="1.0"
+ inkscape:pageopacity="0.0"
+ inkscape:pageshadow="2"
+ inkscape:zoom="28.2842712"
+ inkscape:cx="9.03636094"
+ inkscape:cy="8.65257187"
+ inkscape:window-width="1016"
+ inkscape:window-height="693"
+ gridspacingy="1.0000000pt"
+ gridspacingx="1.0000000pt"
+ gridtolerance="1.0000000px"
+ inkscape:window-x="0"
+ inkscape:window-y="0"
+ showgrid="true"
+ snaptogrid="false" />
+ <rect
+ style="fill:url(#linearGradient829);fill-opacity:0.75000000;fill-rule:evenodd;stroke-width:0.45652742pt;"
+ id="rect825"
+ width="137.68759"
+ height="66.465706"
+ ry="0.0000000"
+ x="359.81241"
+ y="197.28429" />
+ <rect
+ style="fill:url(#linearGradient829);fill-opacity:0.75000000;fill-rule:evenodd;stroke-width:0.45652742pt;"
+ id="rect846"
+ width="135.18759"
+ height="37.082668"
+ ry="0.0000000"
+ x="316.25000"
+ y="81.250000" />
+ <rect
+ style="fill:url(#linearGradient829);fill-opacity:0.75000000;fill-rule:evenodd;stroke:none;stroke-width:0.45652742pt;stroke-opacity:1.0000000;"
+ id="rect847"
+ width="135.18759"
+ height="47.111610"
+ ry="0.0000000"
+ x="255.00000"
+ y="157.88839" />
+ <path
+ style="font-size:12;fill:#8df2ff;fill-rule:evenodd;stroke-width:5;"
+ d="M 0.39048661 0.89309599 L 0.39048661 20.047181 L 19.632719 20.047181 L 19.632719 11.534254 C 19.835269 5.1495589 15.627454 1.8170296 12.589207 0.96573696 L 0.39048661 0.89309599 z "
+ id="path1780"
+ sodipodi:nodetypes="cccccc" />
+ <path
+ style="font-size:12;fill:url(#linearGradient1762);fill-opacity:0.75;fill-rule:evenodd;stroke:#0083e3;stroke-width:1.22267;"
+ d="M 0.66394573 0.6429877 L 12.054746 0.71428771 C 14.053677 0.46858326 18.582323 3.7794196 13.05421 8.3311276 C 16.55234 7.8397185 18.884427 6.611196 19.384159 10.542468 L 19.420041 19.443519 L 0.66394573 19.443519 L 0.66394573 0.6429877 z "
+ id="path1781"
+ sodipodi:nodetypes="ccccccc" />
+ <path
+ style="font-size:12;fill:none;fill-opacity:0.75;fill-rule:evenodd;stroke:#ff0000;stroke-width:5;stroke-dashoffset:0;"
+ d="M 46.250000,63.437500 L 46.875000,127.68750 L 80.000000,127.68750"
+ id="path1573"
+ sodipodi:nodetypes="ccc"
+ transform="matrix(0.125416,0.000000,0.000000,0.125330,-1.342000e-2,-3.521324e-2)" />
+ <rect
+ style="font-size:12;fill:#ffff00;fill-rule:evenodd;stroke:#ff0000;stroke-width:11.9708;"
+ id="rect837"
+ width="117.17106"
+ height="134.99545"
+ x="33.896471"
+ y="12.776533"
+ transform="matrix(5.365033e-2,0.000000,0.000000,5.111246e-2,1.471943,1.669161)" />
+ <rect
+ style="font-size:12;fill:url(#linearGradient829);fill-opacity:0.75;fill-rule:evenodd;stroke-width:0.456527pt;"
+ id="rect1929"
+ width="46.101215"
+ height="50.085411"
+ ry="0.0000000"
+ x="40.383366"
+ y="19.214735"
+ transform="matrix(0.125416,0.000000,0.000000,0.125330,-1.487058,0.215447)" />
+ <rect
+ style="font-size:12;fill:#ffff00;fill-rule:evenodd;stroke:#ff0000;stroke-width:5;"
+ id="rect849"
+ width="20.689960"
+ height="9.3916094"
+ x="26.883967"
+ y="28.720773"
+ transform="matrix(0.125416,0.000000,0.000000,0.125330,-1.487058,0.215447)" />
+ <rect
+ style="font-size:12;fill:url(#linearGradient829);fill-opacity:0.75;fill-rule:evenodd;stroke-width:0.456527pt;"
+ id="rect850"
+ width="16.191408"
+ height="4.4504242"
+ ry="0.0000000"
+ x="29.464840"
+ y="31.063915"
+ transform="matrix(0.125416,0.000000,0.000000,0.125330,-1.487058,0.215447)" />
+ <rect
+ style="font-size:12;fill:#ffff00;fill-rule:evenodd;stroke:#ff0000;stroke-width:5;"
+ id="rect851"
+ width="20.689960"
+ height="9.3916094"
+ x="27.017647"
+ y="51.229589"
+ transform="matrix(0.125416,0.000000,0.000000,0.125330,-1.487058,0.215447)" />
+ <rect
+ style="font-size:12;fill:url(#linearGradient829);fill-opacity:0.75;fill-rule:evenodd;stroke-width:0.456527pt;"
+ id="rect852"
+ width="15.691408"
+ height="3.4504242"
+ ry="0.0000000"
+ x="29.598520"
+ y="54.072731"
+ transform="matrix(0.125416,0.000000,0.000000,0.125330,-1.487058,0.215447)" />
+ <rect
+ style="font-size:12;fill:#ffff00;fill-rule:evenodd;stroke:#ff0000;stroke-width:11.9708;"
+ id="rect1979"
+ width="117.17106"
+ height="134.99545"
+ x="33.896471"
+ y="12.776533"
+ transform="matrix(5.365033e-2,0.000000,0.000000,5.111246e-2,9.743065,10.52538)" />
+ <rect
+ style="font-size:12;fill:url(#linearGradient829);fill-opacity:0.75;fill-rule:evenodd;stroke-width:0.456527pt;"
+ id="rect1980"
+ width="46.101215"
+ height="50.085411"
+ ry="0.0000000"
+ x="40.383366"
+ y="19.214735"
+ transform="matrix(0.125416,0.000000,0.000000,0.125330,6.784064,9.071668)" />
+ <rect
+ style="font-size:12;fill:#ffff00;fill-rule:evenodd;stroke:#ff0000;stroke-width:5;"
+ id="rect1981"
+ width="20.689960"
+ height="9.3916094"
+ x="26.883967"
+ y="28.720773"
+ transform="matrix(0.125416,0.000000,0.000000,0.125330,6.784064,9.071668)" />
+ <rect
+ style="font-size:12;fill:url(#linearGradient829);fill-opacity:0.75;fill-rule:evenodd;stroke-width:0.456527pt;"
+ id="rect1982"
+ width="16.191408"
+ height="4.4504242"
+ ry="0.0000000"
+ x="29.464840"
+ y="31.063915"
+ transform="matrix(0.125416,0.000000,0.000000,0.125330,6.784064,9.071668)" />
+ <rect
+ style="font-size:12;fill:#ffff00;fill-rule:evenodd;stroke:#ff0000;stroke-width:5;"
+ id="rect1983"
+ width="20.689960"
+ height="9.3916094"
+ x="27.017647"
+ y="51.229589"
+ transform="matrix(0.125416,0.000000,0.000000,0.125330,6.784064,9.071668)" />
+ <rect
+ style="font-size:12;fill:url(#linearGradient829);fill-opacity:0.75;fill-rule:evenodd;stroke-width:0.456527pt;"
+ id="rect1984"
+ width="15.691408"
+ height="3.4504242"
+ ry="0.0000000"
+ x="29.598520"
+ y="54.072731"
+ transform="matrix(0.125416,0.000000,0.000000,0.125330,6.784064,9.071668)" />
+</svg>
diff --git a/umbrello/umbrello/pics/sources/diag_deployment.svg b/umbrello/umbrello/pics/sources/diag_deployment.svg
new file mode 100644
index 00000000..940cce17
--- /dev/null
+++ b/umbrello/umbrello/pics/sources/diag_deployment.svg
@@ -0,0 +1,676 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 20010904//EN"
+"http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd">
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+<svg
+ id="svg1"
+ sodipodi:version="0.32"
+ inkscape:version="0.37"
+ width="16pt"
+ height="16pt"
+ sodipodi:docbase="/home/jr/tmp/umbrello/icons/inkscape-svg"
+ sodipodi:docname="diag_deployment.svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:xml="http://www.w3.org/XML/1998/namespace"
+ xmlns:xlink="http://www.w3.org/1999/xlink">
+ <defs
+ id="defs3">
+ <linearGradient
+ id="linearGradient1796">
+ <stop
+ style="stop-color:#ffff21;stop-opacity:0.0000000;"
+ offset="0.0000000"
+ id="stop1797" />
+ <stop
+ style="stop-color:#fff;stop-opacity:1;"
+ offset="1"
+ id="stop1798" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient1763">
+ <stop
+ style="stop-color:#ffffff;stop-opacity:0.0000000;"
+ offset="0.0000000"
+ id="stop1764" />
+ <stop
+ style="stop-color:#fff;stop-opacity:1;"
+ offset="1"
+ id="stop1765" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient830">
+ <stop
+ style="stop-color:#ebffff;stop-opacity:0.0000000;"
+ offset="0.0000000"
+ id="stop831" />
+ <stop
+ style="stop-color:#fff;stop-opacity:1;"
+ offset="1"
+ id="stop832" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient826">
+ <stop
+ style="stop-color:#000;stop-opacity:1;"
+ offset="0"
+ id="stop827" />
+ <stop
+ style="stop-color:#fff;stop-opacity:1;"
+ offset="1"
+ id="stop828" />
+ </linearGradient>
+ <linearGradient
+ xlink:href="#linearGradient830"
+ id="linearGradient829"
+ x1="1.5500000"
+ y1="0.52343750"
+ x2="0.20422535"
+ y2="-0.12195122"
+ spreadMethod="reflect" />
+ <linearGradient
+ xlink:href="#linearGradient830"
+ id="linearGradient834" />
+ <linearGradient
+ xlink:href="#linearGradient830"
+ id="linearGradient836" />
+ <linearGradient
+ xlink:href="#linearGradient1763"
+ id="linearGradient1762"
+ x1="-0.34579438"
+ y1="-0.16406250"
+ x2="0.71962619"
+ y2="0.80468750" />
+ <linearGradient
+ xlink:href="#linearGradient1796"
+ id="linearGradient1795"
+ x1="0.65555555"
+ y1="0.88281250"
+ x2="0.48888889"
+ y2="0.53906250"
+ spreadMethod="reflect" />
+ <defs
+ id="defs1348">
+ <linearGradient
+ id="linearGradient1349">
+ <stop
+ style="stop-color:#ebffff;stop-opacity:0.0000000;"
+ offset="0.0000000"
+ id="stop1350" />
+ <stop
+ style="stop-color:#fff;stop-opacity:1;"
+ offset="1"
+ id="stop1351" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient1352">
+ <stop
+ style="stop-color:#000;stop-opacity:1;"
+ offset="0"
+ id="stop1353" />
+ <stop
+ style="stop-color:#fff;stop-opacity:1;"
+ offset="1"
+ id="stop1354" />
+ </linearGradient>
+ <linearGradient
+ xlink:href="#linearGradient830"
+ id="linearGradient1355"
+ x1="1.5500000"
+ y1="0.52343750"
+ x2="0.20422535"
+ y2="-0.12195122"
+ spreadMethod="reflect" />
+ <linearGradient
+ xlink:href="#linearGradient830"
+ id="linearGradient1356"
+ x1="-0.31159419"
+ y1="0.19531250"
+ x2="0.77536231"
+ y2="0.94531250" />
+ <linearGradient
+ xlink:href="#linearGradient830"
+ id="linearGradient1357" />
+ </defs>
+ <sodipodi:namedview
+ id="namedview1358"
+ pagecolor="#ffffff"
+ bordercolor="#666666"
+ borderopacity="1.0"
+ inkscape:pageopacity="0.0"
+ inkscape:pageshadow="2"
+ inkscape:zoom="0.26725582"
+ inkscape:cx="87.469639"
+ inkscape:cy="55.703730"
+ inkscape:window-width="1022"
+ inkscape:window-height="701"
+ gridspacingy="1.0000000pt"
+ gridspacingx="1.0000000pt"
+ gridtolerance="1.0000000px"
+ inkscape:window-x="0"
+ inkscape:window-y="0" />
+ <defs
+ id="defs1445">
+ <linearGradient
+ id="linearGradient973">
+ <stop
+ style="stop-color:#0000ff;stop-opacity:0.0000000;"
+ offset="0.0000000"
+ id="stop974" />
+ <stop
+ style="stop-color:#fff;stop-opacity:1;"
+ offset="1"
+ id="stop975" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient868">
+ <stop
+ style="stop-color:#ffffff;stop-opacity:0.0000000;"
+ offset="0.0000000"
+ id="stop869" />
+ <stop
+ style="stop-color:#fff;stop-opacity:1;"
+ offset="1"
+ id="stop870" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient893">
+ <stop
+ style="stop-color:#19839a;stop-opacity:0.0000000;"
+ offset="0.0000000"
+ id="stop894" />
+ <stop
+ style="stop-color:#fff;stop-opacity:1;"
+ offset="1"
+ id="stop895" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient1455">
+ <stop
+ style="stop-color:#ebffff;stop-opacity:0.0000000;"
+ offset="0.0000000"
+ id="stop1456" />
+ <stop
+ style="stop-color:#fff;stop-opacity:1;"
+ offset="1"
+ id="stop1457" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient1458">
+ <stop
+ style="stop-color:#000;stop-opacity:1;"
+ offset="0"
+ id="stop1459" />
+ <stop
+ style="stop-color:#fff;stop-opacity:1;"
+ offset="1"
+ id="stop1460" />
+ </linearGradient>
+ <linearGradient
+ xlink:href="#linearGradient830"
+ id="linearGradient1461"
+ x1="1.5500000"
+ y1="0.52343750"
+ x2="0.20422535"
+ y2="-0.12195122"
+ spreadMethod="reflect" />
+ <linearGradient
+ xlink:href="#linearGradient830"
+ id="linearGradient1462"
+ x1="-0.31159419"
+ y1="0.19531250"
+ x2="0.77536231"
+ y2="0.94531250" />
+ <linearGradient
+ xlink:href="#linearGradient830"
+ id="linearGradient1463" />
+ <linearGradient
+ xlink:href="#linearGradient868"
+ id="linearGradient892" />
+ <linearGradient
+ xlink:href="#linearGradient973"
+ id="linearGradient926"
+ x1="1.5043305e-18"
+ y1="0.50000000"
+ x2="1.0000000"
+ y2="0.50000000" />
+ <linearGradient
+ xlink:href="#linearGradient868"
+ id="linearGradient928" />
+ <linearGradient
+ xlink:href="#linearGradient830"
+ id="linearGradient937"
+ x1="0.010563380"
+ y1="0.48571429"
+ x2="0.98943663"
+ y2="0.48571429"
+ spreadMethod="pad" />
+ <radialGradient
+ xlink:href="#linearGradient973"
+ id="radialGradient976"
+ cx="0.49275362"
+ cy="0.46875000"
+ r="0.80203730"
+ fx="0.49275362"
+ fy="0.46875000"
+ spreadMethod="reflect" />
+ </defs>
+ <sodipodi:namedview
+ id="namedview1469"
+ pagecolor="#ffffff"
+ bordercolor="#666666"
+ borderopacity="1.0"
+ inkscape:pageopacity="0.0"
+ inkscape:pageshadow="2"
+ inkscape:zoom="4.0000000"
+ inkscape:cx="79.132812"
+ inkscape:cy="66.817627"
+ inkscape:window-width="1022"
+ inkscape:window-height="701"
+ gridspacingy="1.0000000pt"
+ gridspacingx="1.0000000pt"
+ gridtolerance="1.0000000px"
+ inkscape:window-x="0"
+ inkscape:window-y="0" />
+ <defs
+ id="defs1515">
+ <linearGradient
+ id="linearGradient1516">
+ <stop
+ style="stop-color:#ffffff;stop-opacity:0.0000000;"
+ offset="0.0000000"
+ id="stop1517" />
+ <stop
+ style="stop-color:#fff;stop-opacity:1;"
+ offset="1"
+ id="stop1518" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient1519">
+ <stop
+ style="stop-color:#19839a;stop-opacity:0.0000000;"
+ offset="0.0000000"
+ id="stop1520" />
+ <stop
+ style="stop-color:#fff;stop-opacity:1;"
+ offset="1"
+ id="stop1521" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient1522">
+ <stop
+ style="stop-color:#ebffff;stop-opacity:0.0000000;"
+ offset="0.0000000"
+ id="stop1523" />
+ <stop
+ style="stop-color:#fff;stop-opacity:1;"
+ offset="1"
+ id="stop1524" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient1525">
+ <stop
+ style="stop-color:#000;stop-opacity:1;"
+ offset="0"
+ id="stop1526" />
+ <stop
+ style="stop-color:#fff;stop-opacity:1;"
+ offset="1"
+ id="stop1527" />
+ </linearGradient>
+ <linearGradient
+ xlink:href="#linearGradient830"
+ id="linearGradient1528"
+ x1="1.5500000"
+ y1="0.52343750"
+ x2="0.20422535"
+ y2="-0.12195122"
+ spreadMethod="reflect" />
+ <linearGradient
+ xlink:href="#linearGradient830"
+ id="linearGradient1529"
+ x1="-0.31159419"
+ y1="0.19531250"
+ x2="0.77536231"
+ y2="0.94531250" />
+ <linearGradient
+ xlink:href="#linearGradient830"
+ id="linearGradient1530" />
+ <linearGradient
+ xlink:href="#linearGradient868"
+ id="linearGradient1531" />
+ </defs>
+ <sodipodi:namedview
+ id="namedview1532"
+ pagecolor="#ffffff"
+ bordercolor="#666666"
+ borderopacity="1.0"
+ inkscape:pageopacity="0.0"
+ inkscape:pageshadow="2"
+ inkscape:zoom="4.0000000"
+ inkscape:cx="79.132812"
+ inkscape:cy="69.358765"
+ inkscape:window-width="1022"
+ inkscape:window-height="701"
+ gridspacingy="1.0000000pt"
+ gridspacingx="1.0000000pt"
+ gridtolerance="1.0000000px"
+ inkscape:window-x="0"
+ inkscape:window-y="0" />
+ <defs
+ id="defs921">
+ <linearGradient
+ id="linearGradient922">
+ <stop
+ style="stop-color:#ffffff;stop-opacity:0.0000000;"
+ offset="0.0000000"
+ id="stop923" />
+ <stop
+ style="stop-color:#fff;stop-opacity:1;"
+ offset="1"
+ id="stop924" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient925">
+ <stop
+ style="stop-color:#19839a;stop-opacity:0.0000000;"
+ offset="0.0000000"
+ id="stop926" />
+ <stop
+ style="stop-color:#fff;stop-opacity:1;"
+ offset="1"
+ id="stop927" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient929">
+ <stop
+ style="stop-color:#ebffff;stop-opacity:0.0000000;"
+ offset="0.0000000"
+ id="stop930" />
+ <stop
+ style="stop-color:#fff;stop-opacity:1;"
+ offset="1"
+ id="stop931" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient932">
+ <stop
+ style="stop-color:#000;stop-opacity:1;"
+ offset="0"
+ id="stop933" />
+ <stop
+ style="stop-color:#fff;stop-opacity:1;"
+ offset="1"
+ id="stop934" />
+ </linearGradient>
+ <linearGradient
+ xlink:href="#linearGradient830"
+ id="linearGradient935"
+ x1="1.5500000"
+ y1="0.52343750"
+ x2="0.20422535"
+ y2="-0.12195122"
+ spreadMethod="reflect" />
+ <linearGradient
+ xlink:href="#linearGradient830"
+ id="linearGradient936"
+ x1="-0.31159419"
+ y1="0.19531250"
+ x2="0.77536231"
+ y2="0.94531250" />
+ <linearGradient
+ xlink:href="#linearGradient830"
+ id="linearGradient938" />
+ <linearGradient
+ xlink:href="#linearGradient868"
+ id="linearGradient939"
+ x1="0.39932632"
+ y1="0.50707734"
+ x2="0.64623892"
+ y2="0.60370040"
+ spreadMethod="reflect" />
+ </defs>
+ <sodipodi:namedview
+ id="namedview940"
+ pagecolor="#ffffff"
+ bordercolor="#666666"
+ borderopacity="1.0"
+ inkscape:pageopacity="0.0"
+ inkscape:pageshadow="2"
+ inkscape:zoom="4.0000000"
+ inkscape:cx="79.132812"
+ inkscape:cy="69.358765"
+ inkscape:window-width="1022"
+ inkscape:window-height="701"
+ gridspacingy="1.0000000pt"
+ gridspacingx="1.0000000pt"
+ gridtolerance="1.0000000px"
+ inkscape:window-x="0"
+ inkscape:window-y="0" />
+ <defs
+ id="defs1778">
+ <linearGradient
+ id="linearGradient1779">
+ <stop
+ style="stop-color:#ebffff;stop-opacity:0.0000000;"
+ offset="0.0000000"
+ id="stop1780" />
+ <stop
+ style="stop-color:#fff;stop-opacity:1;"
+ offset="1"
+ id="stop1781" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient1782">
+ <stop
+ style="stop-color:#000;stop-opacity:1;"
+ offset="0"
+ id="stop1783" />
+ <stop
+ style="stop-color:#fff;stop-opacity:1;"
+ offset="1"
+ id="stop1784" />
+ </linearGradient>
+ <linearGradient
+ xlink:href="#linearGradient830"
+ id="linearGradient1785"
+ x1="1.5500000"
+ y1="0.52343750"
+ x2="0.20422535"
+ y2="-0.12195122"
+ spreadMethod="reflect" />
+ <linearGradient
+ xlink:href="#linearGradient830"
+ id="linearGradient1786"
+ x1="-0.31159419"
+ y1="0.19531250"
+ x2="0.77536231"
+ y2="0.94531250" />
+ <linearGradient
+ xlink:href="#linearGradient830"
+ id="linearGradient1787" />
+ </defs>
+ <sodipodi:namedview
+ id="namedview1788"
+ pagecolor="#ffffff"
+ bordercolor="#666666"
+ borderopacity="1.0"
+ inkscape:pageopacity="0.0"
+ inkscape:pageshadow="2"
+ inkscape:zoom="4.0000000"
+ inkscape:cx="99.562933"
+ inkscape:cy="65.172729"
+ inkscape:window-width="1022"
+ inkscape:window-height="701"
+ gridspacingy="1.0000000pt"
+ gridspacingx="1.0000000pt"
+ gridtolerance="1.0000000px"
+ inkscape:window-x="0"
+ inkscape:window-y="0" />
+ </defs>
+ <sodipodi:namedview
+ id="base"
+ pagecolor="#ffffff"
+ bordercolor="#666666"
+ borderopacity="1.0"
+ inkscape:pageopacity="0.0"
+ inkscape:pageshadow="2"
+ inkscape:zoom="31.9999999"
+ inkscape:cx="9.31250051"
+ inkscape:cy="8.17808345"
+ inkscape:window-width="1016"
+ inkscape:window-height="693"
+ gridspacingy="1.0000000pt"
+ gridspacingx="1.0000000pt"
+ gridtolerance="1.0000000px"
+ inkscape:window-x="0"
+ inkscape:window-y="0"
+ showgrid="true"
+ snaptogrid="false" />
+ <rect
+ style="fill:url(#linearGradient829);fill-opacity:0.75000000;fill-rule:evenodd;stroke-width:0.45652742pt;"
+ id="rect825"
+ width="137.68759"
+ height="66.465706"
+ ry="0.0000000"
+ x="359.81241"
+ y="197.28429" />
+ <rect
+ style="fill:url(#linearGradient829);fill-opacity:0.75000000;fill-rule:evenodd;stroke-width:0.45652742pt;"
+ id="rect846"
+ width="135.18759"
+ height="37.082668"
+ ry="0.0000000"
+ x="316.25000"
+ y="81.250000" />
+ <rect
+ style="fill:url(#linearGradient829);fill-opacity:0.75000000;fill-rule:evenodd;stroke:none;stroke-width:0.45652742pt;stroke-opacity:1.0000000;"
+ id="rect847"
+ width="135.18759"
+ height="47.111610"
+ ry="0.0000000"
+ x="255.00000"
+ y="157.88839" />
+ <g
+ id="g1500">
+ <path
+ style="font-size:12;fill:#8df2ff;fill-rule:evenodd;stroke-width:5;"
+ d="M 0.71260935 0.81201239 L 0.71260935 19.93956 L 19.851798 19.93956 L 19.851798 11.438427 C 20.053263 5.0625781 15.867982 1.7346659 12.846005 0.88455272 L 0.71260935 0.81201239 z "
+ id="path1780"
+ sodipodi:nodetypes="cccccc" />
+ <path
+ style="font-size:12;fill:url(#linearGradient1762);fill-opacity:0.75;fill-rule:evenodd;stroke:#0083e3;stroke-width:1.22576;"
+ d="M 0.64263643 0.67943812 L 12.052584 0.75049689 C 14.054876 0.50562376 18.591135 3.8052584 13.053729 8.3415662 C 16.557739 7.8518198 18.893746 6.6274538 19.394319 10.545425 L 19.430261 19.41636 L 0.64263643 19.41636 L 0.64263643 0.67943812 z "
+ id="path1781"
+ sodipodi:nodetypes="ccccccc" />
+ <path
+ style="font-size:12;fill:none;fill-opacity:0.75;fill-rule:evenodd;stroke:#ff0000;stroke-width:5;stroke-dashoffset:0;"
+ d="M 46.250000,63.437500 L 46.875000,119.68750 L 77.500000,119.68750"
+ id="path1573"
+ sodipodi:nodetypes="ccc"
+ transform="matrix(0.124745,0.000000,0.000000,0.125157,3.733392e-2,2.753162e-2)" />
+ <path
+ style="font-size:12;fill:#ffff00;fill-rule:evenodd;stroke:#ff0000;stroke-width:5;"
+ d="M -84.422455,7.3251026 L -102.91372,19.247785 L -102.32767,63.644850 L -55.082643,64.524763 L -36.912006,51.706112 L -36.843985,7.8955677 L -84.422455,7.3251026 z "
+ id="path991"
+ sodipodi:nodetypes="ccccccc"
+ transform="matrix(0.124745,0.000000,0.000000,0.125157,14.69487,1.005321)" />
+ <rect
+ style="font-size:12;fill:url(#linearGradient829);fill-opacity:0.75;fill-rule:evenodd;stroke-width:0.456527pt;"
+ id="rect1794"
+ width="42.145744"
+ height="38.517403"
+ ry="0.0000000"
+ x="-100.31789"
+ y="24.109026"
+ transform="matrix(0.124736,1.482898e-3,0.000000,0.125157,14.69487,1.005321)" />
+ <text
+ xml:space="preserve"
+ style="font-size:12;stroke-width:1pt;font-family:Bitstream Vera Sans;font-weight:normal;font-style:normal;text-anchor:start;writing-mode:lr;"
+ x="-48.233853"
+ y="25.958897"
+ id="text838"
+ transform="matrix(0.243909,0.000000,0.000000,0.255155,14.69487,1.005321)"
+ sodipodi:linespacing="100%"><tspan
+ x="-48.2338524"
+ y="25.9588966"
+ sodipodi:role="line"
+ id="tspan1487">XY</tspan></text>
+ <path
+ style="font-size:12;fill:url(#linearGradient829);fill-opacity:0.75;fill-rule:evenodd;stroke-width:0.456527pt;"
+ d="M -54.267621,23.369170 L -53.907472,60.592869 L -38.977447,50.401945 L -39.362477,10.880432 L -54.267621,23.369170 z "
+ id="path944"
+ sodipodi:nodetypes="ccccc"
+ transform="matrix(0.124745,0.000000,0.000000,0.125157,14.69487,1.005321)" />
+ <path
+ style="font-size:12;fill:url(#linearGradient829);fill-opacity:0.75;fill-rule:evenodd;stroke-width:0.456527pt;"
+ d="M -83.527997,9.7916987 L -97.606582,18.881702 L -55.651918,18.333301 L -43.955918,10.104199 L -83.527997,9.7916987 z "
+ id="path990"
+ sodipodi:nodetypes="ccccc"
+ transform="matrix(0.124745,0.000000,0.000000,0.125157,14.69487,1.005321)" />
+ <path
+ style="font-size:12;fill:none;fill-opacity:0.75;fill-rule:evenodd;stroke:#ff0000;stroke-width:5;"
+ d="M -105.15625,20.312500 L -54.843750,20.937500 L -36.406250,8.1250000"
+ id="path999"
+ sodipodi:nodetypes="ccc"
+ transform="matrix(0.124745,0.000000,0.000000,0.125157,14.69487,1.005321)" />
+ <path
+ style="font-size:12;fill:none;fill-opacity:0.75;fill-rule:evenodd;stroke:#ff0000;stroke-width:5;"
+ d="M -56.532642,18.413382 L -56.592358,66.899118"
+ id="path1000"
+ sodipodi:nodetypes="cc"
+ transform="matrix(0.124745,0.000000,0.000000,0.125157,14.69487,1.005321)" />
+ <path
+ style="font-size:12;fill:#ffff00;fill-rule:evenodd;stroke:#ff0000;stroke-width:5;"
+ d="M -84.422455,7.3251026 L -102.91372,19.247785 L -102.32767,63.644850 L -55.082643,64.524763 L -36.912006,51.706112 L -36.843985,7.8955677 L -84.422455,7.3251026 z "
+ id="path1017"
+ sodipodi:nodetypes="ccccccc"
+ transform="matrix(0.124745,0.000000,0.000000,0.125157,22.74482,10.06908)" />
+ <rect
+ style="font-size:12;fill:url(#linearGradient829);fill-opacity:0.75;fill-rule:evenodd;stroke-width:0.456527pt;"
+ id="rect1018"
+ width="42.145744"
+ height="38.517403"
+ ry="0.0000000"
+ x="-100.31789"
+ y="24.109026"
+ transform="matrix(0.124736,1.482898e-3,0.000000,0.125157,22.74482,10.06908)" />
+ <text
+ xml:space="preserve"
+ style="font-size:12;stroke-width:1pt;font-family:Bitstream Vera Sans;font-weight:normal;font-style:normal;text-anchor:start;writing-mode:lr;"
+ x="-48.233853"
+ y="25.958897"
+ id="text1019"
+ transform="matrix(0.243909,0.000000,0.000000,0.255155,22.74482,10.06908)"
+ sodipodi:linespacing="100%"><tspan
+ x="-48.2338524"
+ y="25.9588966"
+ sodipodi:role="line"
+ id="tspan1498">XY</tspan></text>
+ <path
+ style="font-size:12;fill:url(#linearGradient829);fill-opacity:0.75;fill-rule:evenodd;stroke-width:0.456527pt;"
+ d="M -54.267621,23.369170 L -53.907472,60.592869 L -38.977447,50.401945 L -39.362477,10.880432 L -54.267621,23.369170 z "
+ id="path1022"
+ sodipodi:nodetypes="ccccc"
+ transform="matrix(0.124745,0.000000,0.000000,0.125157,22.74482,10.06908)" />
+ <path
+ style="font-size:12;fill:url(#linearGradient829);fill-opacity:0.75;fill-rule:evenodd;stroke-width:0.456527pt;"
+ d="M -83.527997,9.7916987 L -97.606582,18.881702 L -55.651918,18.333301 L -43.955918,10.104199 L -83.527997,9.7916987 z "
+ id="path1023"
+ sodipodi:nodetypes="ccccc"
+ transform="matrix(0.124745,0.000000,0.000000,0.125157,22.74482,10.06908)" />
+ <path
+ style="font-size:12;fill:none;fill-opacity:0.75;fill-rule:evenodd;stroke:#ff0000;stroke-width:5;"
+ d="M -105.15625,20.312500 L -54.843750,20.937500 L -36.406250,8.1250000"
+ id="path1024"
+ sodipodi:nodetypes="ccc"
+ transform="matrix(0.124745,0.000000,0.000000,0.125157,22.74482,10.06908)" />
+ <path
+ style="font-size:12;fill:none;fill-opacity:0.75;fill-rule:evenodd;stroke:#ff0000;stroke-width:5;"
+ d="M -56.532642,18.413382 L -56.592358,66.899118"
+ id="path1025"
+ sodipodi:nodetypes="cc"
+ transform="matrix(0.124745,0.000000,0.000000,0.125157,22.74482,10.06908)" />
+ </g>
+</svg>
diff --git a/umbrello/umbrello/pics/sources/diag_entityrelationship.svg b/umbrello/umbrello/pics/sources/diag_entityrelationship.svg
new file mode 100644
index 00000000..586f8e2e
--- /dev/null
+++ b/umbrello/umbrello/pics/sources/diag_entityrelationship.svg
@@ -0,0 +1,715 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 20010904//EN"
+"http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd">
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+<svg
+ id="svg1"
+ sodipodi:version="0.32"
+ inkscape:version="0.40"
+ width="16pt"
+ height="16pt"
+ sodipodi:docbase="/home/jr/devel/kdesdk/umbrello/umbrello/pics/sources"
+ sodipodi:docname="diag_entityrelationship.svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:xml="http://www.w3.org/XML/1998/namespace"
+ xmlns:xlink="http://www.w3.org/1999/xlink"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:cc="http://web.resource.org/cc/"
+ xmlns:dc="http://purl.org/dc/elements/1.1/">
+ <metadata
+ id="metadata1733">
+ <rdf:RDF
+ id="RDF1734">
+ <cc:Work
+ rdf:about=""
+ id="Work1735">
+ <dc:format
+ id="format1736">image/svg+xml</dc:format>
+ <dc:type
+ id="type1738"
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+ </cc:Work>
+ </rdf:RDF>
+ </metadata>
+ <defs
+ id="defs3">
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient830"
+ id="linearGradient1089"
+ spreadMethod="reflect"
+ x1="23.537647"
+ y1="37.602750"
+ x2="3.7720042"
+ y2="28.123806"
+ gradientTransform="matrix(1.701614,0.000000,0.000000,1.095210,-5.421016e-16,-22.63705)"
+ gradientUnits="userSpaceOnUse" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient830"
+ id="linearGradient1213"
+ spreadMethod="reflect"
+ x1="21.635329"
+ y1="9.6104371"
+ x2="3.4203537"
+ y2="0.87514110"
+ gradientTransform="scale(1.846475,0.541572)"
+ gradientUnits="userSpaceOnUse" />
+ <linearGradient
+ id="linearGradient1796">
+ <stop
+ style="stop-color:#ffff21;stop-opacity:0.0000000;"
+ offset="0.0000000"
+ id="stop1797" />
+ <stop
+ style="stop-color:#fff;stop-opacity:1;"
+ offset="1"
+ id="stop1798" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient1763">
+ <stop
+ style="stop-color:#ffffff;stop-opacity:0.0000000;"
+ offset="0.0000000"
+ id="stop1764" />
+ <stop
+ style="stop-color:#fff;stop-opacity:1;"
+ offset="1"
+ id="stop1765" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient830">
+ <stop
+ style="stop-color:#ebffff;stop-opacity:0.0000000;"
+ offset="0.0000000"
+ id="stop831" />
+ <stop
+ style="stop-color:#fff;stop-opacity:1;"
+ offset="1"
+ id="stop832" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient826">
+ <stop
+ style="stop-color:#000;stop-opacity:1;"
+ offset="0"
+ id="stop827" />
+ <stop
+ style="stop-color:#fff;stop-opacity:1;"
+ offset="1"
+ id="stop828" />
+ </linearGradient>
+ <linearGradient
+ xlink:href="#linearGradient830"
+ id="linearGradient829"
+ x1="1.5500000"
+ y1="0.52343750"
+ x2="0.20422535"
+ y2="-0.12195122"
+ spreadMethod="reflect" />
+ <linearGradient
+ xlink:href="#linearGradient830"
+ id="linearGradient834" />
+ <linearGradient
+ xlink:href="#linearGradient830"
+ id="linearGradient836" />
+ <linearGradient
+ xlink:href="#linearGradient1763"
+ id="linearGradient1762"
+ x1="-0.34579438"
+ y1="-0.16406250"
+ x2="0.71962619"
+ y2="0.80468750" />
+ <linearGradient
+ xlink:href="#linearGradient1796"
+ id="linearGradient1795"
+ x1="0.65555555"
+ y1="0.88281250"
+ x2="0.48888889"
+ y2="0.53906250"
+ spreadMethod="reflect" />
+ <defs
+ id="defs1348">
+ <linearGradient
+ id="linearGradient1349">
+ <stop
+ style="stop-color:#ebffff;stop-opacity:0.0000000;"
+ offset="0.0000000"
+ id="stop1350" />
+ <stop
+ style="stop-color:#fff;stop-opacity:1;"
+ offset="1"
+ id="stop1351" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient1352">
+ <stop
+ style="stop-color:#000;stop-opacity:1;"
+ offset="0"
+ id="stop1353" />
+ <stop
+ style="stop-color:#fff;stop-opacity:1;"
+ offset="1"
+ id="stop1354" />
+ </linearGradient>
+ <linearGradient
+ xlink:href="#linearGradient830"
+ id="linearGradient1355"
+ x1="1.5500000"
+ y1="0.52343750"
+ x2="0.20422535"
+ y2="-0.12195122"
+ spreadMethod="reflect" />
+ <linearGradient
+ xlink:href="#linearGradient830"
+ id="linearGradient1356"
+ x1="-0.31159419"
+ y1="0.19531250"
+ x2="0.77536231"
+ y2="0.94531250" />
+ <linearGradient
+ xlink:href="#linearGradient830"
+ id="linearGradient1357" />
+ </defs>
+ <sodipodi:namedview
+ id="namedview1358"
+ pagecolor="#ffffff"
+ bordercolor="#666666"
+ borderopacity="1.0"
+ inkscape:pageopacity="0.0"
+ inkscape:pageshadow="2"
+ inkscape:zoom="0.26725582"
+ inkscape:cx="87.469639"
+ inkscape:cy="55.703730"
+ inkscape:window-width="1022"
+ inkscape:window-height="701"
+ gridspacingy="1.0000000pt"
+ gridspacingx="1.0000000pt"
+ gridtolerance="1.0000000px"
+ inkscape:window-x="0"
+ inkscape:window-y="0" />
+ <defs
+ id="defs1445">
+ <linearGradient
+ id="linearGradient973">
+ <stop
+ style="stop-color:#0000ff;stop-opacity:0.0000000;"
+ offset="0.0000000"
+ id="stop974" />
+ <stop
+ style="stop-color:#fff;stop-opacity:1;"
+ offset="1"
+ id="stop975" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient868">
+ <stop
+ style="stop-color:#ffffff;stop-opacity:0.0000000;"
+ offset="0.0000000"
+ id="stop869" />
+ <stop
+ style="stop-color:#fff;stop-opacity:1;"
+ offset="1"
+ id="stop870" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient893">
+ <stop
+ style="stop-color:#19839a;stop-opacity:0.0000000;"
+ offset="0.0000000"
+ id="stop894" />
+ <stop
+ style="stop-color:#fff;stop-opacity:1;"
+ offset="1"
+ id="stop895" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient1455">
+ <stop
+ style="stop-color:#ebffff;stop-opacity:0.0000000;"
+ offset="0.0000000"
+ id="stop1456" />
+ <stop
+ style="stop-color:#fff;stop-opacity:1;"
+ offset="1"
+ id="stop1457" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient1458">
+ <stop
+ style="stop-color:#000;stop-opacity:1;"
+ offset="0"
+ id="stop1459" />
+ <stop
+ style="stop-color:#fff;stop-opacity:1;"
+ offset="1"
+ id="stop1460" />
+ </linearGradient>
+ <linearGradient
+ xlink:href="#linearGradient830"
+ id="linearGradient1461"
+ x1="1.5500000"
+ y1="0.52343750"
+ x2="0.20422535"
+ y2="-0.12195122"
+ spreadMethod="reflect" />
+ <linearGradient
+ xlink:href="#linearGradient830"
+ id="linearGradient1462"
+ x1="-0.31159419"
+ y1="0.19531250"
+ x2="0.77536231"
+ y2="0.94531250" />
+ <linearGradient
+ xlink:href="#linearGradient830"
+ id="linearGradient1463" />
+ <linearGradient
+ xlink:href="#linearGradient868"
+ id="linearGradient892" />
+ <linearGradient
+ xlink:href="#linearGradient973"
+ id="linearGradient926"
+ x1="1.5043305e-18"
+ y1="0.50000000"
+ x2="1.0000000"
+ y2="0.50000000" />
+ <linearGradient
+ xlink:href="#linearGradient868"
+ id="linearGradient928" />
+ <linearGradient
+ xlink:href="#linearGradient830"
+ id="linearGradient937"
+ x1="0.010563380"
+ y1="0.48571429"
+ x2="0.98943663"
+ y2="0.48571429"
+ spreadMethod="pad" />
+ <radialGradient
+ xlink:href="#linearGradient973"
+ id="radialGradient976"
+ cx="0.49275362"
+ cy="0.46875000"
+ r="0.80203730"
+ fx="0.49275362"
+ fy="0.46875000"
+ spreadMethod="reflect" />
+ </defs>
+ <sodipodi:namedview
+ id="namedview1469"
+ pagecolor="#ffffff"
+ bordercolor="#666666"
+ borderopacity="1.0"
+ inkscape:pageopacity="0.0"
+ inkscape:pageshadow="2"
+ inkscape:zoom="4.0000000"
+ inkscape:cx="79.132812"
+ inkscape:cy="66.817627"
+ inkscape:window-width="1022"
+ inkscape:window-height="701"
+ gridspacingy="1.0000000pt"
+ gridspacingx="1.0000000pt"
+ gridtolerance="1.0000000px"
+ inkscape:window-x="0"
+ inkscape:window-y="0" />
+ <defs
+ id="defs1515">
+ <linearGradient
+ id="linearGradient1516">
+ <stop
+ style="stop-color:#ffffff;stop-opacity:0.0000000;"
+ offset="0.0000000"
+ id="stop1517" />
+ <stop
+ style="stop-color:#fff;stop-opacity:1;"
+ offset="1"
+ id="stop1518" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient1519">
+ <stop
+ style="stop-color:#19839a;stop-opacity:0.0000000;"
+ offset="0.0000000"
+ id="stop1520" />
+ <stop
+ style="stop-color:#fff;stop-opacity:1;"
+ offset="1"
+ id="stop1521" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient1522">
+ <stop
+ style="stop-color:#ebffff;stop-opacity:0.0000000;"
+ offset="0.0000000"
+ id="stop1523" />
+ <stop
+ style="stop-color:#fff;stop-opacity:1;"
+ offset="1"
+ id="stop1524" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient1525">
+ <stop
+ style="stop-color:#000;stop-opacity:1;"
+ offset="0"
+ id="stop1526" />
+ <stop
+ style="stop-color:#fff;stop-opacity:1;"
+ offset="1"
+ id="stop1527" />
+ </linearGradient>
+ <linearGradient
+ xlink:href="#linearGradient830"
+ id="linearGradient1528"
+ x1="1.5500000"
+ y1="0.52343750"
+ x2="0.20422535"
+ y2="-0.12195122"
+ spreadMethod="reflect" />
+ <linearGradient
+ xlink:href="#linearGradient830"
+ id="linearGradient1529"
+ x1="-0.31159419"
+ y1="0.19531250"
+ x2="0.77536231"
+ y2="0.94531250" />
+ <linearGradient
+ xlink:href="#linearGradient830"
+ id="linearGradient1530" />
+ <linearGradient
+ xlink:href="#linearGradient868"
+ id="linearGradient1531" />
+ </defs>
+ <sodipodi:namedview
+ id="namedview1532"
+ pagecolor="#ffffff"
+ bordercolor="#666666"
+ borderopacity="1.0"
+ inkscape:pageopacity="0.0"
+ inkscape:pageshadow="2"
+ inkscape:zoom="4.0000000"
+ inkscape:cx="79.132812"
+ inkscape:cy="69.358765"
+ inkscape:window-width="1022"
+ inkscape:window-height="701"
+ gridspacingy="1.0000000pt"
+ gridspacingx="1.0000000pt"
+ gridtolerance="1.0000000px"
+ inkscape:window-x="0"
+ inkscape:window-y="0" />
+ <defs
+ id="defs921">
+ <linearGradient
+ id="linearGradient922">
+ <stop
+ style="stop-color:#ffffff;stop-opacity:0.0000000;"
+ offset="0.0000000"
+ id="stop923" />
+ <stop
+ style="stop-color:#fff;stop-opacity:1;"
+ offset="1"
+ id="stop924" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient925">
+ <stop
+ style="stop-color:#19839a;stop-opacity:0.0000000;"
+ offset="0.0000000"
+ id="stop926" />
+ <stop
+ style="stop-color:#fff;stop-opacity:1;"
+ offset="1"
+ id="stop927" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient929">
+ <stop
+ style="stop-color:#ebffff;stop-opacity:0.0000000;"
+ offset="0.0000000"
+ id="stop930" />
+ <stop
+ style="stop-color:#fff;stop-opacity:1;"
+ offset="1"
+ id="stop931" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient932">
+ <stop
+ style="stop-color:#000;stop-opacity:1;"
+ offset="0"
+ id="stop933" />
+ <stop
+ style="stop-color:#fff;stop-opacity:1;"
+ offset="1"
+ id="stop934" />
+ </linearGradient>
+ <linearGradient
+ xlink:href="#linearGradient830"
+ id="linearGradient935"
+ x1="1.5500000"
+ y1="0.52343750"
+ x2="0.20422535"
+ y2="-0.12195122"
+ spreadMethod="reflect" />
+ <linearGradient
+ xlink:href="#linearGradient830"
+ id="linearGradient936"
+ x1="-0.31159419"
+ y1="0.19531250"
+ x2="0.77536231"
+ y2="0.94531250" />
+ <linearGradient
+ xlink:href="#linearGradient830"
+ id="linearGradient938" />
+ <linearGradient
+ xlink:href="#linearGradient868"
+ id="linearGradient939"
+ x1="0.39932632"
+ y1="0.50707734"
+ x2="0.64623892"
+ y2="0.60370040"
+ spreadMethod="reflect" />
+ </defs>
+ <sodipodi:namedview
+ id="namedview940"
+ pagecolor="#ffffff"
+ bordercolor="#666666"
+ borderopacity="1.0"
+ inkscape:pageopacity="0.0"
+ inkscape:pageshadow="2"
+ inkscape:zoom="4.0000000"
+ inkscape:cx="79.132812"
+ inkscape:cy="69.358765"
+ inkscape:window-width="1022"
+ inkscape:window-height="701"
+ gridspacingy="1.0000000pt"
+ gridspacingx="1.0000000pt"
+ gridtolerance="1.0000000px"
+ inkscape:window-x="0"
+ inkscape:window-y="0" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient830"
+ id="linearGradient1773"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="scale(1.846475,0.541572)"
+ spreadMethod="reflect"
+ x1="21.635329"
+ y1="9.6104371"
+ x2="3.4203537"
+ y2="0.87514110" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient830"
+ id="linearGradient1774"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.701614,0.000000,0.000000,1.095210,2.749537e-15,-22.63705)"
+ spreadMethod="reflect"
+ x1="23.537647"
+ y1="37.602750"
+ x2="3.7720042"
+ y2="28.123806" />
+ </defs>
+ <sodipodi:namedview
+ id="base"
+ pagecolor="#ffffff"
+ bordercolor="#666666"
+ borderopacity="1.0"
+ inkscape:pageopacity="0.0"
+ inkscape:pageshadow="2"
+ inkscape:zoom="32.000000"
+ inkscape:cx="6.6746645"
+ inkscape:cy="7.4813442"
+ inkscape:window-width="1016"
+ inkscape:window-height="692"
+ gridspacingy="1.0000000pt"
+ gridspacingx="1.0000000pt"
+ gridtolerance="1.0000000px"
+ inkscape:window-x="0"
+ inkscape:window-y="0"
+ showgrid="true"
+ snaptogrid="false"
+ inkscape:current-layer="svg1" />
+ <rect
+ style="fill:url(#linearGradient829);fill-opacity:0.75000000;fill-rule:evenodd;stroke-width:0.45652742pt;"
+ id="rect825"
+ width="137.68759"
+ height="66.465706"
+ ry="0.0000000"
+ x="359.81241"
+ y="197.28429" />
+ <rect
+ style="fill:url(#linearGradient829);fill-opacity:0.75000000;fill-rule:evenodd;stroke-width:0.45652742pt;"
+ id="rect846"
+ width="135.18759"
+ height="37.082668"
+ ry="0.0000000"
+ x="316.25000"
+ y="81.250000" />
+ <rect
+ style="fill:url(#linearGradient829);fill-opacity:0.75000000;fill-rule:evenodd;stroke:none;stroke-width:0.45652742pt;stroke-opacity:1.0000000;"
+ id="rect847"
+ width="135.18759"
+ height="47.111610"
+ ry="0.0000000"
+ x="255.00000"
+ y="157.88839" />
+ <path
+ sodipodi:type="arc"
+ style="fill:url(#linearGradient834);fill-opacity:0.75000000;fill-rule:evenodd;stroke:#000000;stroke-width:1.0000000pt;"
+ id="path833"
+ sodipodi:cx="541.27716"
+ sodipodi:cy="303.78741"
+ sodipodi:rx="172.74803"
+ sodipodi:ry="161.23149"
+ d="M 714.02519 303.78741 A 172.74803 161.23149 0 1 0 368.52913,303.78741 A 172.74803 161.23149 0 1 0 714.02519 303.78741 z"
+ transform="translate(224.5724,63.34093)" />
+ <path
+ sodipodi:type="arc"
+ style="fill:url(#linearGradient834);fill-opacity:0.75000000;fill-rule:evenodd;stroke:#000000;stroke-width:1.0000000pt;"
+ id="path1533"
+ sodipodi:cx="541.27716"
+ sodipodi:cy="303.78741"
+ sodipodi:rx="172.74803"
+ sodipodi:ry="161.23149"
+ d="M 714.02519 303.78741 A 172.74803 161.23149 0 1 0 368.52913,303.78741 A 172.74803 161.23149 0 1 0 714.02519 303.78741 z"
+ transform="translate(224.5724,63.34093)" />
+ <rect
+ style="fill:url(#linearGradient836);fill-opacity:0.75000000;fill-rule:evenodd;stroke:#ff0000;stroke-width:5.0000000;"
+ id="rect835"
+ width="495.39624"
+ height="385.66864"
+ x="-679.56819"
+ y="64.886958" />
+ <path
+ sodipodi:type="arc"
+ style="fill:url(#linearGradient834);fill-opacity:0.75000000;fill-rule:evenodd;stroke:#000000;stroke-width:1.0000000pt;"
+ id="path941"
+ sodipodi:cx="541.27716"
+ sodipodi:cy="303.78741"
+ sodipodi:rx="172.74803"
+ sodipodi:ry="161.23149"
+ d="M 714.02519 303.78741 A 172.74803 161.23149 0 1 0 368.52913,303.78741 A 172.74803 161.23149 0 1 0 714.02519 303.78741 z"
+ transform="translate(224.5724,63.34093)" />
+ <rect
+ style="fill:url(#linearGradient836);fill-opacity:0.75000000;fill-rule:evenodd;stroke:#ff0000;stroke-width:5.0000000;"
+ id="rect942"
+ width="495.39624"
+ height="385.66864"
+ x="-679.56819"
+ y="64.886958" />
+ <path
+ style="font-size:12.000000;fill:#8df2ff;fill-rule:evenodd;stroke-width:5.0000000;"
+ d="M 10.662893,8.9661054 L 10.662893,152.41231 L 155.79528,152.41231 L 155.79528,88.658436 C 157.32299,40.843037 125.58602,15.885505 102.67038,9.5101184 L 10.662893,8.9661054 z "
+ id="path1780"
+ sodipodi:nodetypes="cccccc"
+ transform="matrix(0.132588,0.000000,0.000000,0.134001,-0.711555,-0.583531)" />
+ <path
+ style="font-size:12.000000;fill:url(#linearGradient1762);fill-opacity:0.75000000;fill-rule:evenodd;stroke:#0083e3;stroke-width:1.2182600;"
+ d="M 0.63038442 0.67944183 L 12.032096 0.75041412 C 14.032942 0.50583897 18.565925 3.8014585 13.032518 8.3322463 C 16.533998 7.8430958 18.868318 6.6202197 19.36853 10.533424 L 19.404446 19.393563 L 0.63038442 19.393563 L 0.63038442 0.67944183 z "
+ id="path1781"
+ sodipodi:nodetypes="ccccccc" />
+ <g
+ id="g1196"
+ transform="matrix(0.225031,0.000000,0.000000,0.228044,2.568472,2.486405)">
+ <rect
+ style="font-size:12.000000;fill:#ffff00;fill-rule:evenodd;stroke:#ff0000;stroke-width:1.2396300"
+ id="rect1206"
+ width="26.249929"
+ height="26.188568"
+ x="0.66534913"
+ y="0.71917963" />
+ <rect
+ style="font-size:12.000000;fill:url(#linearGradient1213);fill-opacity:0.75000000;fill-rule:evenodd;stroke-width:0.45652699pt"
+ id="rect1207"
+ width="24.991924"
+ height="7.3301492"
+ ry="0.0000000"
+ x="1.2116134"
+ y="1.3678730" />
+ <text
+ xml:space="preserve"
+ style="font-size:12.000000;font-weight:normal;stroke-width:1.0000000pt;font-family:Bitstream Vera Sans"
+ x="2.5917132"
+ y="11.314754"
+ id="text838"
+ transform="scale(0.933669,0.722645)"><tspan
+ id="tspan839">ABC</tspan></text>
+ <path
+ style="font-size:12.000000;fill:none;fill-opacity:0.75000000;fill-rule:evenodd;stroke:#ff0000;stroke-width:1.2500000"
+ d="M 1.1533278,9.3908034 L 26.731652,9.3908034"
+ id="path842" />
+ <rect
+ style="font-size:12.000000;fill:url(#linearGradient1089);fill-opacity:0.75000000;fill-rule:evenodd;stroke-width:0.45652699pt"
+ id="rect1212"
+ width="24.991922"
+ height="16.085562"
+ ry="0.0000000"
+ x="1.3145113"
+ y="10.126090" />
+ </g>
+ <g
+ id="g1765"
+ transform="matrix(0.223484,0.000000,0.000000,0.223484,11.32810,11.30963)">
+ <rect
+ style="font-size:12.000000;fill:#ffff00;fill-rule:evenodd;stroke:#ff0000;stroke-width:1.2396300"
+ id="rect1766"
+ width="26.249929"
+ height="26.188568"
+ x="0.66534913"
+ y="0.71917963" />
+ <rect
+ style="font-size:12.000000;fill:url(#linearGradient1773);fill-opacity:0.75000000;fill-rule:evenodd;stroke-width:0.45652699pt"
+ id="rect1767"
+ width="24.991924"
+ height="7.3301492"
+ ry="0.0000000"
+ x="1.2116134"
+ y="1.3678730" />
+ <text
+ xml:space="preserve"
+ style="font-size:12.000000;font-weight:normal;stroke-width:1.0000000pt;font-family:Bitstream Vera Sans"
+ x="2.5917132"
+ y="11.314754"
+ id="text1768"
+ transform="scale(0.933669,0.722645)"><tspan
+ id="tspan1769">ABC</tspan></text>
+ <path
+ style="font-size:12.000000;fill:none;fill-opacity:0.75000000;fill-rule:evenodd;stroke:#ff0000;stroke-width:1.2500000"
+ d="M 1.1533278,9.3908034 L 26.731652,9.3908034"
+ id="path1771" />
+ <rect
+ style="font-size:12.000000;fill:url(#linearGradient1774);fill-opacity:0.75000000;fill-rule:evenodd;stroke-width:0.45652699pt"
+ id="rect1772"
+ width="24.991922"
+ height="16.085562"
+ ry="0.0000000"
+ x="1.3145113"
+ y="10.126090" />
+ </g>
+ <g
+ id="g1117"
+ transform="matrix(0.275357,0.000000,0.000000,0.264187,1.877265,8.790732)">
+ <path
+ style="font-size:12.000000;fill:none;fill-opacity:0.75000000;fill-rule:evenodd;stroke:#ff0000;stroke-width:2.0050871"
+ d="M 19.138844,-0.51630137 L 13.730893,9.7597702 L 7.6288725,-0.51630137"
+ id="path1009"
+ sodipodi:nodetypes="ccc" />
+ <rect
+ style="font-size:12.000000;fill:#ff0000;fill-opacity:1.0000000;fill-rule:evenodd;stroke:none;stroke-width:1.0000000pt"
+ id="rect1209"
+ width="2.4859223"
+ height="27.510872"
+ x="12.540097"
+ y="-0.010873318" />
+ </g>
+ <rect
+ style="font-size:12.000000;fill:#ff0000;fill-opacity:1.0000000;fill-rule:evenodd;stroke:none;stroke-width:1.0000000pt"
+ id="rect1367"
+ width="0.68451649"
+ height="5.3054056"
+ x="15.359846"
+ y="-11.284021"
+ transform="matrix(0.000000,1.000000,-1.000000,0.000000,0.000000,0.000000)" />
+</svg>
diff --git a/umbrello/umbrello/pics/sources/diag_sequence.svg b/umbrello/umbrello/pics/sources/diag_sequence.svg
new file mode 100644
index 00000000..654c9847
--- /dev/null
+++ b/umbrello/umbrello/pics/sources/diag_sequence.svg
@@ -0,0 +1,729 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 20010904//EN"
+"http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd">
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+<svg
+ id="svg1"
+ sodipodi:version="0.32"
+ inkscape:version="0.38.1"
+ width="128.00000pt"
+ height="128.00000pt"
+ sodipodi:docbase="/home/bartkozoltan/Documents/work/umbrello/new pics"
+ sodipodi:docname="diag_sequence.svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:xml="http://www.w3.org/XML/1998/namespace"
+ xmlns:xlink="http://www.w3.org/1999/xlink">
+ <defs
+ id="defs3">
+ <linearGradient
+ id="linearGradient1796">
+ <stop
+ style="stop-color:#ffff21;stop-opacity:0.0000000;"
+ offset="0.0000000"
+ id="stop1797" />
+ <stop
+ style="stop-color:#fff;stop-opacity:1;"
+ offset="1"
+ id="stop1798" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient1763">
+ <stop
+ style="stop-color:#ffffff;stop-opacity:0.0000000;"
+ offset="0.0000000"
+ id="stop1764" />
+ <stop
+ style="stop-color:#fff;stop-opacity:1;"
+ offset="1"
+ id="stop1765" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient830">
+ <stop
+ style="stop-color:#ebffff;stop-opacity:0.0000000;"
+ offset="0.0000000"
+ id="stop831" />
+ <stop
+ style="stop-color:#fff;stop-opacity:1;"
+ offset="1"
+ id="stop832" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient826">
+ <stop
+ style="stop-color:#000;stop-opacity:1;"
+ offset="0"
+ id="stop827" />
+ <stop
+ style="stop-color:#fff;stop-opacity:1;"
+ offset="1"
+ id="stop828" />
+ </linearGradient>
+ <linearGradient
+ xlink:href="#linearGradient830"
+ id="linearGradient829"
+ x1="1.5500000"
+ y1="0.52343750"
+ x2="0.20422535"
+ y2="-0.12195122"
+ spreadMethod="reflect" />
+ <linearGradient
+ xlink:href="#linearGradient830"
+ id="linearGradient834" />
+ <linearGradient
+ xlink:href="#linearGradient830"
+ id="linearGradient836" />
+ <linearGradient
+ xlink:href="#linearGradient1763"
+ id="linearGradient1762"
+ x1="-0.34579438"
+ y1="-0.16406250"
+ x2="0.71962619"
+ y2="0.80468750" />
+ <linearGradient
+ xlink:href="#linearGradient1796"
+ id="linearGradient1795"
+ x1="0.65555555"
+ y1="0.88281250"
+ x2="0.48888889"
+ y2="0.53906250"
+ spreadMethod="reflect" />
+ <defs
+ id="defs1348">
+ <linearGradient
+ id="linearGradient1349">
+ <stop
+ style="stop-color:#ebffff;stop-opacity:0.0000000;"
+ offset="0.0000000"
+ id="stop1350" />
+ <stop
+ style="stop-color:#fff;stop-opacity:1;"
+ offset="1"
+ id="stop1351" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient1352">
+ <stop
+ style="stop-color:#000;stop-opacity:1;"
+ offset="0"
+ id="stop1353" />
+ <stop
+ style="stop-color:#fff;stop-opacity:1;"
+ offset="1"
+ id="stop1354" />
+ </linearGradient>
+ <linearGradient
+ xlink:href="#linearGradient830"
+ id="linearGradient1355"
+ x1="1.5500000"
+ y1="0.52343750"
+ x2="0.20422535"
+ y2="-0.12195122"
+ spreadMethod="reflect" />
+ <linearGradient
+ xlink:href="#linearGradient830"
+ id="linearGradient1356"
+ x1="-0.31159419"
+ y1="0.19531250"
+ x2="0.77536231"
+ y2="0.94531250" />
+ <linearGradient
+ xlink:href="#linearGradient830"
+ id="linearGradient1357" />
+ </defs>
+ <sodipodi:namedview
+ id="namedview1358"
+ pagecolor="#ffffff"
+ bordercolor="#666666"
+ borderopacity="1.0"
+ inkscape:pageopacity="0.0"
+ inkscape:pageshadow="2"
+ inkscape:zoom="0.26725582"
+ inkscape:cx="87.469639"
+ inkscape:cy="55.703730"
+ inkscape:window-width="1022"
+ inkscape:window-height="701"
+ gridspacingy="1.0000000pt"
+ gridspacingx="1.0000000pt"
+ gridtolerance="1.0000000px"
+ inkscape:window-x="0"
+ inkscape:window-y="0" />
+ <defs
+ id="defs1445">
+ <linearGradient
+ id="linearGradient973">
+ <stop
+ style="stop-color:#0000ff;stop-opacity:0.0000000;"
+ offset="0.0000000"
+ id="stop974" />
+ <stop
+ style="stop-color:#fff;stop-opacity:1;"
+ offset="1"
+ id="stop975" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient868">
+ <stop
+ style="stop-color:#ffffff;stop-opacity:0.0000000;"
+ offset="0.0000000"
+ id="stop869" />
+ <stop
+ style="stop-color:#fff;stop-opacity:1;"
+ offset="1"
+ id="stop870" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient893">
+ <stop
+ style="stop-color:#19839a;stop-opacity:0.0000000;"
+ offset="0.0000000"
+ id="stop894" />
+ <stop
+ style="stop-color:#fff;stop-opacity:1;"
+ offset="1"
+ id="stop895" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient1455">
+ <stop
+ style="stop-color:#ebffff;stop-opacity:0.0000000;"
+ offset="0.0000000"
+ id="stop1456" />
+ <stop
+ style="stop-color:#fff;stop-opacity:1;"
+ offset="1"
+ id="stop1457" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient1458">
+ <stop
+ style="stop-color:#000;stop-opacity:1;"
+ offset="0"
+ id="stop1459" />
+ <stop
+ style="stop-color:#fff;stop-opacity:1;"
+ offset="1"
+ id="stop1460" />
+ </linearGradient>
+ <linearGradient
+ xlink:href="#linearGradient830"
+ id="linearGradient1461"
+ x1="1.5500000"
+ y1="0.52343750"
+ x2="0.20422535"
+ y2="-0.12195122"
+ spreadMethod="reflect" />
+ <linearGradient
+ xlink:href="#linearGradient830"
+ id="linearGradient1462"
+ x1="-0.31159419"
+ y1="0.19531250"
+ x2="0.77536231"
+ y2="0.94531250" />
+ <linearGradient
+ xlink:href="#linearGradient830"
+ id="linearGradient1463" />
+ <linearGradient
+ xlink:href="#linearGradient868"
+ id="linearGradient892" />
+ <linearGradient
+ xlink:href="#linearGradient973"
+ id="linearGradient926"
+ x1="1.5043305e-18"
+ y1="0.50000000"
+ x2="1.0000000"
+ y2="0.50000000" />
+ <linearGradient
+ xlink:href="#linearGradient868"
+ id="linearGradient928" />
+ <linearGradient
+ xlink:href="#linearGradient830"
+ id="linearGradient937"
+ x1="0.010563380"
+ y1="0.48571429"
+ x2="0.98943663"
+ y2="0.48571429"
+ spreadMethod="pad" />
+ <radialGradient
+ xlink:href="#linearGradient973"
+ id="radialGradient976"
+ cx="0.49275362"
+ cy="0.46875000"
+ r="0.80203730"
+ fx="0.49275362"
+ fy="0.46875000"
+ spreadMethod="reflect" />
+ </defs>
+ <sodipodi:namedview
+ id="namedview1469"
+ pagecolor="#ffffff"
+ bordercolor="#666666"
+ borderopacity="1.0"
+ inkscape:pageopacity="0.0"
+ inkscape:pageshadow="2"
+ inkscape:zoom="4.0000000"
+ inkscape:cx="79.132812"
+ inkscape:cy="66.817627"
+ inkscape:window-width="1022"
+ inkscape:window-height="701"
+ gridspacingy="1.0000000pt"
+ gridspacingx="1.0000000pt"
+ gridtolerance="1.0000000px"
+ inkscape:window-x="0"
+ inkscape:window-y="0" />
+ <defs
+ id="defs1515">
+ <linearGradient
+ id="linearGradient1516">
+ <stop
+ style="stop-color:#ffffff;stop-opacity:0.0000000;"
+ offset="0.0000000"
+ id="stop1517" />
+ <stop
+ style="stop-color:#fff;stop-opacity:1;"
+ offset="1"
+ id="stop1518" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient1519">
+ <stop
+ style="stop-color:#19839a;stop-opacity:0.0000000;"
+ offset="0.0000000"
+ id="stop1520" />
+ <stop
+ style="stop-color:#fff;stop-opacity:1;"
+ offset="1"
+ id="stop1521" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient1522">
+ <stop
+ style="stop-color:#ebffff;stop-opacity:0.0000000;"
+ offset="0.0000000"
+ id="stop1523" />
+ <stop
+ style="stop-color:#fff;stop-opacity:1;"
+ offset="1"
+ id="stop1524" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient1525">
+ <stop
+ style="stop-color:#000;stop-opacity:1;"
+ offset="0"
+ id="stop1526" />
+ <stop
+ style="stop-color:#fff;stop-opacity:1;"
+ offset="1"
+ id="stop1527" />
+ </linearGradient>
+ <linearGradient
+ xlink:href="#linearGradient830"
+ id="linearGradient1528"
+ x1="1.5500000"
+ y1="0.52343750"
+ x2="0.20422535"
+ y2="-0.12195122"
+ spreadMethod="reflect" />
+ <linearGradient
+ xlink:href="#linearGradient830"
+ id="linearGradient1529"
+ x1="-0.31159419"
+ y1="0.19531250"
+ x2="0.77536231"
+ y2="0.94531250" />
+ <linearGradient
+ xlink:href="#linearGradient830"
+ id="linearGradient1530" />
+ <linearGradient
+ xlink:href="#linearGradient868"
+ id="linearGradient1531" />
+ </defs>
+ <sodipodi:namedview
+ id="namedview1532"
+ pagecolor="#ffffff"
+ bordercolor="#666666"
+ borderopacity="1.0"
+ inkscape:pageopacity="0.0"
+ inkscape:pageshadow="2"
+ inkscape:zoom="4.0000000"
+ inkscape:cx="79.132812"
+ inkscape:cy="69.358765"
+ inkscape:window-width="1022"
+ inkscape:window-height="701"
+ gridspacingy="1.0000000pt"
+ gridspacingx="1.0000000pt"
+ gridtolerance="1.0000000px"
+ inkscape:window-x="0"
+ inkscape:window-y="0" />
+ <defs
+ id="defs921">
+ <linearGradient
+ id="linearGradient922">
+ <stop
+ style="stop-color:#ffffff;stop-opacity:0.0000000;"
+ offset="0.0000000"
+ id="stop923" />
+ <stop
+ style="stop-color:#fff;stop-opacity:1;"
+ offset="1"
+ id="stop924" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient925">
+ <stop
+ style="stop-color:#19839a;stop-opacity:0.0000000;"
+ offset="0.0000000"
+ id="stop926" />
+ <stop
+ style="stop-color:#fff;stop-opacity:1;"
+ offset="1"
+ id="stop927" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient929">
+ <stop
+ style="stop-color:#ebffff;stop-opacity:0.0000000;"
+ offset="0.0000000"
+ id="stop930" />
+ <stop
+ style="stop-color:#fff;stop-opacity:1;"
+ offset="1"
+ id="stop931" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient932">
+ <stop
+ style="stop-color:#000;stop-opacity:1;"
+ offset="0"
+ id="stop933" />
+ <stop
+ style="stop-color:#fff;stop-opacity:1;"
+ offset="1"
+ id="stop934" />
+ </linearGradient>
+ <linearGradient
+ xlink:href="#linearGradient830"
+ id="linearGradient935"
+ x1="1.5500000"
+ y1="0.52343750"
+ x2="0.20422535"
+ y2="-0.12195122"
+ spreadMethod="reflect" />
+ <linearGradient
+ xlink:href="#linearGradient830"
+ id="linearGradient936"
+ x1="-0.31159419"
+ y1="0.19531250"
+ x2="0.77536231"
+ y2="0.94531250" />
+ <linearGradient
+ xlink:href="#linearGradient830"
+ id="linearGradient938" />
+ <linearGradient
+ xlink:href="#linearGradient868"
+ id="linearGradient939"
+ x1="0.39932632"
+ y1="0.50707734"
+ x2="0.64623892"
+ y2="0.60370040"
+ spreadMethod="reflect" />
+ </defs>
+ <sodipodi:namedview
+ id="namedview940"
+ pagecolor="#ffffff"
+ bordercolor="#666666"
+ borderopacity="1.0"
+ inkscape:pageopacity="0.0"
+ inkscape:pageshadow="2"
+ inkscape:zoom="4.0000000"
+ inkscape:cx="79.132812"
+ inkscape:cy="69.358765"
+ inkscape:window-width="1022"
+ inkscape:window-height="701"
+ gridspacingy="1.0000000pt"
+ gridspacingx="1.0000000pt"
+ gridtolerance="1.0000000px"
+ inkscape:window-x="0"
+ inkscape:window-y="0" />
+ <defs
+ id="defs1253">
+ <linearGradient
+ id="linearGradient1254">
+ <stop
+ style="stop-color:#ebffff;stop-opacity:0.0000000;"
+ offset="0.0000000"
+ id="stop1255" />
+ <stop
+ style="stop-color:#fff;stop-opacity:1;"
+ offset="1"
+ id="stop1256" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient1257">
+ <stop
+ style="stop-color:#000;stop-opacity:1;"
+ offset="0"
+ id="stop1258" />
+ <stop
+ style="stop-color:#fff;stop-opacity:1;"
+ offset="1"
+ id="stop1259" />
+ </linearGradient>
+ <linearGradient
+ xlink:href="#linearGradient830"
+ id="linearGradient1260"
+ x1="1.5500000"
+ y1="0.52343750"
+ x2="0.20422535"
+ y2="-0.12195122"
+ spreadMethod="reflect" />
+ <linearGradient
+ xlink:href="#linearGradient830"
+ id="linearGradient1261"
+ x1="-0.31159419"
+ y1="0.19531250"
+ x2="0.77536231"
+ y2="0.94531250" />
+ <linearGradient
+ xlink:href="#linearGradient830"
+ id="linearGradient1262" />
+ </defs>
+ <sodipodi:namedview
+ id="namedview1263"
+ pagecolor="#ffffff"
+ bordercolor="#666666"
+ borderopacity="1.0"
+ inkscape:pageopacity="0.0"
+ inkscape:pageshadow="2"
+ inkscape:zoom="4.0000000"
+ inkscape:cx="96.390219"
+ inkscape:cy="55.703735"
+ inkscape:window-width="1022"
+ inkscape:window-height="701"
+ gridspacingy="1.0000000pt"
+ gridspacingx="1.0000000pt"
+ gridtolerance="1.0000000px"
+ inkscape:window-x="0"
+ inkscape:window-y="0" />
+ </defs>
+ <sodipodi:namedview
+ id="base"
+ pagecolor="#ffffff"
+ bordercolor="#666666"
+ borderopacity="1.0"
+ inkscape:pageopacity="0.0"
+ inkscape:pageshadow="2"
+ inkscape:zoom="4.0000000"
+ inkscape:cx="80.979755"
+ inkscape:cy="83.920441"
+ inkscape:window-width="1022"
+ inkscape:window-height="701"
+ gridspacingy="1.0000000pt"
+ gridspacingx="1.0000000pt"
+ gridtolerance="1.0000000px"
+ inkscape:window-x="0"
+ inkscape:window-y="0"
+ showgrid="false"
+ snaptogrid="false" />
+ <rect
+ style="fill:url(#linearGradient829);fill-opacity:0.75000000;fill-rule:evenodd;stroke-width:0.45652742pt;"
+ id="rect825"
+ width="137.68759"
+ height="66.465706"
+ ry="0.0000000"
+ x="359.81241"
+ y="197.28429" />
+ <rect
+ style="fill:url(#linearGradient829);fill-opacity:0.75000000;fill-rule:evenodd;stroke-width:0.45652742pt;"
+ id="rect846"
+ width="135.18759"
+ height="37.082668"
+ ry="0.0000000"
+ x="316.25000"
+ y="81.250000" />
+ <rect
+ style="fill:url(#linearGradient829);fill-opacity:0.75000000;fill-rule:evenodd;stroke:none;stroke-width:0.45652742pt;stroke-opacity:1.0000000;"
+ id="rect847"
+ width="135.18759"
+ height="47.111610"
+ ry="0.0000000"
+ x="255.00000"
+ y="157.88839" />
+ <g
+ id="g1441"
+ transform="translate(0.312500,0.000000)">
+ <path
+ style="fill:#8df2ff;fill-rule:evenodd;stroke-width:5.0000000;"
+ d="M 10.662893,8.9661054 L 10.662893,152.41231 L 155.79528,152.41231 L 155.79528,88.658436 C 157.32299,40.843037 125.58602,15.885505 102.67038,9.5101184 L 10.662893,8.9661054 z "
+ id="path1780"
+ sodipodi:nodetypes="cccccc"
+ transform="matrix(1.057150,0.000000,0.000000,1.065409,-5.232740,-3.908785)" />
+ <path
+ style="fill:url(#linearGradient1762);fill-opacity:0.75000000;fill-rule:evenodd;stroke:#0083e3;stroke-width:6.2179222;stroke-opacity:1.0000000;"
+ d="M 8.0588132,7.0930279 L 96.199432,7.6370399 C 111.66692,5.7623392 146.70903,31.023695 103.93317,65.752779 C 131.00127,62.003376 149.04667,52.629870 152.91354,82.625089 L 153.19119,150.53923 L 8.0588132,150.53923 L 8.0588132,7.0930279 z "
+ id="path1781"
+ sodipodi:nodetypes="ccccccc"
+ transform="matrix(1.057150,0.000000,0.000000,1.065409,-5.232740,-3.908785)" />
+ </g>
+ <path
+ style="fill:none;fill-rule:evenodd;stroke:#ff0000;stroke-opacity:1.0000000;stroke-width:5.0000000;stroke-linejoin:miter;stroke-linecap:butt;fill-opacity:0.75;stroke-dasharray:20.000000,5.0000000;stroke-dashoffset:0.0000000;"
+ d="M 45.937500,64.062500 L 47.187500,148.43750"
+ id="path1573"
+ sodipodi:nodetypes="cc" />
+ <g
+ id="g1752"
+ transform="translate(3.125000,4.375000)">
+ <rect
+ style="fill:#ffff00;fill-rule:evenodd;stroke:#ff0000;stroke-width:5.0000000;"
+ id="rect837"
+ width="76.129402"
+ height="56.001663"
+ x="10.354806"
+ y="11.023407" />
+ <rect
+ style="fill:url(#linearGradient829);fill-opacity:0.75000000;fill-rule:evenodd;stroke-width:0.45652742pt;"
+ id="rect1267"
+ width="70.641762"
+ height="50.840607"
+ ry="0.0000000"
+ x="12.340744"
+ y="12.871621" />
+ <text
+ xml:space="preserve"
+ style="font-size:12.000000;stroke-width:1.0000000pt;font-family:Luxi Sans;font-weight:bold;font-style:normal;font-stretch:normal;font-variant:normal;text-anchor:start;writing-mode:lr;"
+ x="6.2691227"
+ y="18.367592"
+ id="text838"
+ transform="scale(2.886490,2.443551)"
+ sodipodi:linespacing="100%"><tspan
+ x="6.2691226"
+ y="18.367592"
+ sodipodi:role="line"
+ id="tspan1005">A:B</tspan></text>
+ <path
+ style="fill:none;fill-opacity:0.75000000;fill-rule:evenodd;stroke:#000000;stroke-width:5.0000000;"
+ d="M 17.607313,53.592263 L 78.462038,53.592263"
+ id="path842" />
+ </g>
+ <g
+ id="g1332"
+ transform="matrix(0.635968,0.000000,0.000000,0.557565,45.87930,66.31573)">
+ <defs
+ id="defs1333">
+ <linearGradient
+ id="linearGradient1334">
+ <stop
+ style="stop-color:#ffffff;stop-opacity:0.0000000;"
+ offset="0.0000000"
+ id="stop1335" />
+ <stop
+ style="stop-color:#fff;stop-opacity:1;"
+ offset="1"
+ id="stop1336" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient1337">
+ <stop
+ style="stop-color:#19839a;stop-opacity:0.0000000;"
+ offset="0.0000000"
+ id="stop1338" />
+ <stop
+ style="stop-color:#fff;stop-opacity:1;"
+ offset="1"
+ id="stop1339" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient1340">
+ <stop
+ style="stop-color:#ebffff;stop-opacity:0.0000000;"
+ offset="0.0000000"
+ id="stop1341" />
+ <stop
+ style="stop-color:#fff;stop-opacity:1;"
+ offset="1"
+ id="stop1342" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient1343">
+ <stop
+ style="stop-color:#000;stop-opacity:1;"
+ offset="0"
+ id="stop1344" />
+ <stop
+ style="stop-color:#fff;stop-opacity:1;"
+ offset="1"
+ id="stop1345" />
+ </linearGradient>
+ <linearGradient
+ xlink:href="#linearGradient830"
+ id="linearGradient1346"
+ x1="1.5500000"
+ y1="0.52343750"
+ x2="0.20422535"
+ y2="-0.12195122"
+ spreadMethod="reflect" />
+ <linearGradient
+ xlink:href="#linearGradient830"
+ id="linearGradient1347"
+ x1="-0.31159419"
+ y1="0.19531250"
+ x2="0.77536231"
+ y2="0.94531250" />
+ <linearGradient
+ xlink:href="#linearGradient830"
+ id="linearGradient1348" />
+ <linearGradient
+ xlink:href="#linearGradient868"
+ id="linearGradient1350"
+ x1="-0.49264705"
+ y1="0.43750000"
+ x2="0.022058824"
+ y2="0.92187500" />
+ </defs>
+ <sodipodi:namedview
+ id="namedview1351"
+ pagecolor="#ffffff"
+ bordercolor="#666666"
+ borderopacity="1.0"
+ inkscape:pageopacity="0.0"
+ inkscape:pageshadow="2"
+ inkscape:zoom="0.25000000"
+ inkscape:cx="79.132812"
+ inkscape:cy="72.498291"
+ inkscape:window-width="1022"
+ inkscape:window-height="701"
+ gridspacingy="1.0000000pt"
+ gridspacingx="1.0000000pt"
+ gridtolerance="1.0000000px"
+ inkscape:window-x="0"
+ inkscape:window-y="0" />
+ <path
+ style="fill:none;fill-opacity:0.75000000;fill-rule:evenodd;stroke:#ff0000;stroke-width:11.939221;stroke-dashoffset:0.0000000;"
+ d="M 43.128730,142.68636 L 117.59907,33.942607"
+ id="path861"
+ sodipodi:nodetypes="cc"
+ transform="matrix(0.576132,0.451941,-0.865718,0.308049,103.0792,49.29771)" />
+ <path
+ style="fill:#ffff00;fill-rule:evenodd;stroke:#ff0000;stroke-width:8.9251652;"
+ d="M 119.08212,25.935929 L 72.532380,52.741368 L 116.08013,81.378318 L 119.08212,25.935929 z "
+ id="path874"
+ sodipodi:nodetypes="cccc"
+ transform="matrix(0.576132,0.451941,-0.865718,0.308049,103.0792,49.29771)" />
+ <path
+ style="fill:url(#linearGradient892);fill-rule:evenodd;stroke-width:12.500000;"
+ d="M 136.52988,111.65883 L 102.33395,102.23422 L 103.18710,121.71891 L 136.52988,111.65883 z "
+ id="path875"
+ sodipodi:nodetypes="cccc" />
+ <text
+ xml:space="preserve"
+ style="fill:black;fill-opacity:1;stroke:none;font-family:Bitstream Vera Sans;font-style:normal;font-weight:normal;font-size:12px;stroke-opacity:1;stroke-width:1pt;stroke-linejoin:miter;stroke-linecap:butt;"
+ x="0.90846729"
+ y="15.456690"
+ id="text1033"
+ transform="scale(8.480023,5.154386)"><tspan
+ id="tspan1034">f(x)</tspan></text>
+ </g>
+</svg>
diff --git a/umbrello/umbrello/pics/sources/diag_state.svg b/umbrello/umbrello/pics/sources/diag_state.svg
new file mode 100644
index 00000000..3d428ff4
--- /dev/null
+++ b/umbrello/umbrello/pics/sources/diag_state.svg
@@ -0,0 +1,629 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 20010904//EN"
+"http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd">
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+<svg
+ id="svg1"
+ sodipodi:version="0.32"
+ inkscape:version="0.37"
+ width="16pt"
+ height="16pt"
+ sodipodi:docbase="/home/jr/tmp/umbrello/icons/inkscape-svg"
+ sodipodi:docname="diag_state.svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:xml="http://www.w3.org/XML/1998/namespace"
+ xmlns:xlink="http://www.w3.org/1999/xlink">
+ <defs
+ id="defs3">
+ <linearGradient
+ id="linearGradient1796">
+ <stop
+ style="stop-color:#ffff21;stop-opacity:0.0000000;"
+ offset="0.0000000"
+ id="stop1797" />
+ <stop
+ style="stop-color:#fff;stop-opacity:1;"
+ offset="1"
+ id="stop1798" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient1763">
+ <stop
+ style="stop-color:#ffffff;stop-opacity:0.0000000;"
+ offset="0.0000000"
+ id="stop1764" />
+ <stop
+ style="stop-color:#fff;stop-opacity:1;"
+ offset="1"
+ id="stop1765" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient830">
+ <stop
+ style="stop-color:#ebffff;stop-opacity:0.0000000;"
+ offset="0.0000000"
+ id="stop831" />
+ <stop
+ style="stop-color:#fff;stop-opacity:1;"
+ offset="1"
+ id="stop832" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient826">
+ <stop
+ style="stop-color:#000;stop-opacity:1;"
+ offset="0"
+ id="stop827" />
+ <stop
+ style="stop-color:#fff;stop-opacity:1;"
+ offset="1"
+ id="stop828" />
+ </linearGradient>
+ <linearGradient
+ xlink:href="#linearGradient830"
+ id="linearGradient829"
+ x1="1.5500000"
+ y1="0.52343750"
+ x2="0.20422535"
+ y2="-0.12195122"
+ spreadMethod="reflect" />
+ <linearGradient
+ xlink:href="#linearGradient830"
+ id="linearGradient834" />
+ <linearGradient
+ xlink:href="#linearGradient830"
+ id="linearGradient836" />
+ <linearGradient
+ xlink:href="#linearGradient1763"
+ id="linearGradient1762"
+ x1="-0.34579438"
+ y1="-0.16406250"
+ x2="0.71962619"
+ y2="0.80468750" />
+ <linearGradient
+ xlink:href="#linearGradient1796"
+ id="linearGradient1795"
+ x1="0.65555555"
+ y1="0.88281250"
+ x2="0.48888889"
+ y2="0.53906250"
+ spreadMethod="reflect" />
+ <defs
+ id="defs1348">
+ <linearGradient
+ id="linearGradient1349">
+ <stop
+ style="stop-color:#ebffff;stop-opacity:0.0000000;"
+ offset="0.0000000"
+ id="stop1350" />
+ <stop
+ style="stop-color:#fff;stop-opacity:1;"
+ offset="1"
+ id="stop1351" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient1352">
+ <stop
+ style="stop-color:#000;stop-opacity:1;"
+ offset="0"
+ id="stop1353" />
+ <stop
+ style="stop-color:#fff;stop-opacity:1;"
+ offset="1"
+ id="stop1354" />
+ </linearGradient>
+ <linearGradient
+ xlink:href="#linearGradient830"
+ id="linearGradient1355"
+ x1="1.5500000"
+ y1="0.52343750"
+ x2="0.20422535"
+ y2="-0.12195122"
+ spreadMethod="reflect" />
+ <linearGradient
+ xlink:href="#linearGradient830"
+ id="linearGradient1356"
+ x1="-0.31159419"
+ y1="0.19531250"
+ x2="0.77536231"
+ y2="0.94531250" />
+ <linearGradient
+ xlink:href="#linearGradient830"
+ id="linearGradient1357" />
+ </defs>
+ <sodipodi:namedview
+ id="namedview1358"
+ pagecolor="#ffffff"
+ bordercolor="#666666"
+ borderopacity="1.0"
+ inkscape:pageopacity="0.0"
+ inkscape:pageshadow="2"
+ inkscape:zoom="0.26725582"
+ inkscape:cx="87.469639"
+ inkscape:cy="55.703730"
+ inkscape:window-width="1022"
+ inkscape:window-height="701"
+ gridspacingy="1.0000000pt"
+ gridspacingx="1.0000000pt"
+ gridtolerance="1.0000000px"
+ inkscape:window-x="0"
+ inkscape:window-y="0" />
+ <defs
+ id="defs1445">
+ <linearGradient
+ id="linearGradient973">
+ <stop
+ style="stop-color:#0000ff;stop-opacity:0.0000000;"
+ offset="0.0000000"
+ id="stop974" />
+ <stop
+ style="stop-color:#fff;stop-opacity:1;"
+ offset="1"
+ id="stop975" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient868">
+ <stop
+ style="stop-color:#ffffff;stop-opacity:0.0000000;"
+ offset="0.0000000"
+ id="stop869" />
+ <stop
+ style="stop-color:#fff;stop-opacity:1;"
+ offset="1"
+ id="stop870" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient893">
+ <stop
+ style="stop-color:#19839a;stop-opacity:0.0000000;"
+ offset="0.0000000"
+ id="stop894" />
+ <stop
+ style="stop-color:#fff;stop-opacity:1;"
+ offset="1"
+ id="stop895" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient1455">
+ <stop
+ style="stop-color:#ebffff;stop-opacity:0.0000000;"
+ offset="0.0000000"
+ id="stop1456" />
+ <stop
+ style="stop-color:#fff;stop-opacity:1;"
+ offset="1"
+ id="stop1457" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient1458">
+ <stop
+ style="stop-color:#000;stop-opacity:1;"
+ offset="0"
+ id="stop1459" />
+ <stop
+ style="stop-color:#fff;stop-opacity:1;"
+ offset="1"
+ id="stop1460" />
+ </linearGradient>
+ <linearGradient
+ xlink:href="#linearGradient830"
+ id="linearGradient1461"
+ x1="1.5500000"
+ y1="0.52343750"
+ x2="0.20422535"
+ y2="-0.12195122"
+ spreadMethod="reflect" />
+ <linearGradient
+ xlink:href="#linearGradient830"
+ id="linearGradient1462"
+ x1="-0.31159419"
+ y1="0.19531250"
+ x2="0.77536231"
+ y2="0.94531250" />
+ <linearGradient
+ xlink:href="#linearGradient830"
+ id="linearGradient1463" />
+ <linearGradient
+ xlink:href="#linearGradient868"
+ id="linearGradient892" />
+ <linearGradient
+ xlink:href="#linearGradient973"
+ id="linearGradient926"
+ x1="1.5043305e-18"
+ y1="0.50000000"
+ x2="1.0000000"
+ y2="0.50000000" />
+ <linearGradient
+ xlink:href="#linearGradient868"
+ id="linearGradient928" />
+ <linearGradient
+ xlink:href="#linearGradient830"
+ id="linearGradient937"
+ x1="0.010563380"
+ y1="0.48571429"
+ x2="0.98943663"
+ y2="0.48571429"
+ spreadMethod="pad" />
+ <radialGradient
+ xlink:href="#linearGradient973"
+ id="radialGradient976"
+ cx="0.49275362"
+ cy="0.46875000"
+ r="0.80203730"
+ fx="0.49275362"
+ fy="0.46875000"
+ spreadMethod="reflect" />
+ </defs>
+ <sodipodi:namedview
+ id="namedview1469"
+ pagecolor="#ffffff"
+ bordercolor="#666666"
+ borderopacity="1.0"
+ inkscape:pageopacity="0.0"
+ inkscape:pageshadow="2"
+ inkscape:zoom="4.0000000"
+ inkscape:cx="79.132812"
+ inkscape:cy="66.817627"
+ inkscape:window-width="1022"
+ inkscape:window-height="701"
+ gridspacingy="1.0000000pt"
+ gridspacingx="1.0000000pt"
+ gridtolerance="1.0000000px"
+ inkscape:window-x="0"
+ inkscape:window-y="0" />
+ <defs
+ id="defs1515">
+ <linearGradient
+ id="linearGradient1516">
+ <stop
+ style="stop-color:#ffffff;stop-opacity:0.0000000;"
+ offset="0.0000000"
+ id="stop1517" />
+ <stop
+ style="stop-color:#fff;stop-opacity:1;"
+ offset="1"
+ id="stop1518" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient1519">
+ <stop
+ style="stop-color:#19839a;stop-opacity:0.0000000;"
+ offset="0.0000000"
+ id="stop1520" />
+ <stop
+ style="stop-color:#fff;stop-opacity:1;"
+ offset="1"
+ id="stop1521" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient1522">
+ <stop
+ style="stop-color:#ebffff;stop-opacity:0.0000000;"
+ offset="0.0000000"
+ id="stop1523" />
+ <stop
+ style="stop-color:#fff;stop-opacity:1;"
+ offset="1"
+ id="stop1524" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient1525">
+ <stop
+ style="stop-color:#000;stop-opacity:1;"
+ offset="0"
+ id="stop1526" />
+ <stop
+ style="stop-color:#fff;stop-opacity:1;"
+ offset="1"
+ id="stop1527" />
+ </linearGradient>
+ <linearGradient
+ xlink:href="#linearGradient830"
+ id="linearGradient1528"
+ x1="1.5500000"
+ y1="0.52343750"
+ x2="0.20422535"
+ y2="-0.12195122"
+ spreadMethod="reflect" />
+ <linearGradient
+ xlink:href="#linearGradient830"
+ id="linearGradient1529"
+ x1="-0.31159419"
+ y1="0.19531250"
+ x2="0.77536231"
+ y2="0.94531250" />
+ <linearGradient
+ xlink:href="#linearGradient830"
+ id="linearGradient1530" />
+ <linearGradient
+ xlink:href="#linearGradient868"
+ id="linearGradient1531" />
+ </defs>
+ <sodipodi:namedview
+ id="namedview1532"
+ pagecolor="#ffffff"
+ bordercolor="#666666"
+ borderopacity="1.0"
+ inkscape:pageopacity="0.0"
+ inkscape:pageshadow="2"
+ inkscape:zoom="4.0000000"
+ inkscape:cx="79.132812"
+ inkscape:cy="69.358765"
+ inkscape:window-width="1022"
+ inkscape:window-height="701"
+ gridspacingy="1.0000000pt"
+ gridspacingx="1.0000000pt"
+ gridtolerance="1.0000000px"
+ inkscape:window-x="0"
+ inkscape:window-y="0" />
+ <defs
+ id="defs921">
+ <linearGradient
+ id="linearGradient922">
+ <stop
+ style="stop-color:#ffffff;stop-opacity:0.0000000;"
+ offset="0.0000000"
+ id="stop923" />
+ <stop
+ style="stop-color:#fff;stop-opacity:1;"
+ offset="1"
+ id="stop924" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient925">
+ <stop
+ style="stop-color:#19839a;stop-opacity:0.0000000;"
+ offset="0.0000000"
+ id="stop926" />
+ <stop
+ style="stop-color:#fff;stop-opacity:1;"
+ offset="1"
+ id="stop927" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient929">
+ <stop
+ style="stop-color:#ebffff;stop-opacity:0.0000000;"
+ offset="0.0000000"
+ id="stop930" />
+ <stop
+ style="stop-color:#fff;stop-opacity:1;"
+ offset="1"
+ id="stop931" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient932">
+ <stop
+ style="stop-color:#000;stop-opacity:1;"
+ offset="0"
+ id="stop933" />
+ <stop
+ style="stop-color:#fff;stop-opacity:1;"
+ offset="1"
+ id="stop934" />
+ </linearGradient>
+ <linearGradient
+ xlink:href="#linearGradient830"
+ id="linearGradient935"
+ x1="1.5500000"
+ y1="0.52343750"
+ x2="0.20422535"
+ y2="-0.12195122"
+ spreadMethod="reflect" />
+ <linearGradient
+ xlink:href="#linearGradient830"
+ id="linearGradient936"
+ x1="-0.31159419"
+ y1="0.19531250"
+ x2="0.77536231"
+ y2="0.94531250" />
+ <linearGradient
+ xlink:href="#linearGradient830"
+ id="linearGradient938" />
+ <linearGradient
+ xlink:href="#linearGradient868"
+ id="linearGradient939"
+ x1="0.39932632"
+ y1="0.50707734"
+ x2="0.64623892"
+ y2="0.60370040"
+ spreadMethod="reflect" />
+ </defs>
+ <sodipodi:namedview
+ id="namedview940"
+ pagecolor="#ffffff"
+ bordercolor="#666666"
+ borderopacity="1.0"
+ inkscape:pageopacity="0.0"
+ inkscape:pageshadow="2"
+ inkscape:zoom="4.0000000"
+ inkscape:cx="79.132812"
+ inkscape:cy="69.358765"
+ inkscape:window-width="1022"
+ inkscape:window-height="701"
+ gridspacingy="1.0000000pt"
+ gridspacingx="1.0000000pt"
+ gridtolerance="1.0000000px"
+ inkscape:window-x="0"
+ inkscape:window-y="0" />
+ </defs>
+ <sodipodi:namedview
+ id="base"
+ pagecolor="#ffffff"
+ bordercolor="#666666"
+ borderopacity="1.0"
+ inkscape:pageopacity="0.0"
+ inkscape:pageshadow="2"
+ inkscape:zoom="31.9999999"
+ inkscape:cx="6.67466737"
+ inkscape:cy="7.48134805"
+ inkscape:window-width="1016"
+ inkscape:window-height="693"
+ gridspacingy="1.0000000pt"
+ gridspacingx="1.0000000pt"
+ gridtolerance="1.0000000px"
+ inkscape:window-x="0"
+ inkscape:window-y="0"
+ showgrid="true"
+ snaptogrid="false" />
+ <rect
+ style="fill:url(#linearGradient829);fill-opacity:0.75000000;fill-rule:evenodd;stroke-width:0.45652742pt;"
+ id="rect825"
+ width="137.68759"
+ height="66.465706"
+ ry="0.0000000"
+ x="359.81241"
+ y="197.28429" />
+ <rect
+ style="fill:url(#linearGradient829);fill-opacity:0.75000000;fill-rule:evenodd;stroke-width:0.45652742pt;"
+ id="rect846"
+ width="135.18759"
+ height="37.082668"
+ ry="0.0000000"
+ x="316.25000"
+ y="81.250000" />
+ <rect
+ style="fill:url(#linearGradient829);fill-opacity:0.75000000;fill-rule:evenodd;stroke:none;stroke-width:0.45652742pt;stroke-opacity:1.0000000;"
+ id="rect847"
+ width="135.18759"
+ height="47.111610"
+ ry="0.0000000"
+ x="255.00000"
+ y="157.88839" />
+ <path
+ sodipodi:type="arc"
+ style="fill:url(#linearGradient834);fill-opacity:0.75000000;fill-rule:evenodd;stroke:#000000;stroke-width:1.0000000pt;"
+ id="path833"
+ sodipodi:cx="541.27716"
+ sodipodi:cy="303.78741"
+ sodipodi:rx="172.74803"
+ sodipodi:ry="161.23149"
+ d="M 714.02519 303.78741 A 172.74803 161.23149 0 1 0 368.52913,303.78741 A 172.74803 161.23149 0 1 0 714.02519 303.78741 z"
+ transform="translate(224.5724,63.34093)" />
+ <path
+ sodipodi:type="arc"
+ style="fill:url(#linearGradient834);fill-opacity:0.75000000;fill-rule:evenodd;stroke:#000000;stroke-width:1.0000000pt;"
+ id="path1533"
+ sodipodi:cx="541.27716"
+ sodipodi:cy="303.78741"
+ sodipodi:rx="172.74803"
+ sodipodi:ry="161.23149"
+ d="M 714.02519 303.78741 A 172.74803 161.23149 0 1 0 368.52913,303.78741 A 172.74803 161.23149 0 1 0 714.02519 303.78741 z"
+ transform="translate(224.5724,63.34093)" />
+ <rect
+ style="fill:url(#linearGradient836);fill-opacity:0.75000000;fill-rule:evenodd;stroke:#ff0000;stroke-width:5.0000000;"
+ id="rect835"
+ width="495.39624"
+ height="385.66864"
+ x="-679.56819"
+ y="64.886958" />
+ <path
+ sodipodi:type="arc"
+ style="fill:url(#linearGradient834);fill-opacity:0.75000000;fill-rule:evenodd;stroke:#000000;stroke-width:1.0000000pt;"
+ id="path941"
+ sodipodi:cx="541.27716"
+ sodipodi:cy="303.78741"
+ sodipodi:rx="172.74803"
+ sodipodi:ry="161.23149"
+ d="M 714.02519 303.78741 A 172.74803 161.23149 0 1 0 368.52913,303.78741 A 172.74803 161.23149 0 1 0 714.02519 303.78741 z"
+ transform="translate(224.5724,63.34093)" />
+ <rect
+ style="fill:url(#linearGradient836);fill-opacity:0.75000000;fill-rule:evenodd;stroke:#ff0000;stroke-width:5.0000000;"
+ id="rect942"
+ width="495.39624"
+ height="385.66864"
+ x="-679.56819"
+ y="64.886958" />
+ <g
+ id="g2088">
+ <path
+ style="font-size:12;fill:#8df2ff;fill-rule:evenodd;stroke-width:5;"
+ d="M 10.662893,8.9661054 L 10.662893,152.41231 L 155.79528,152.41231 L 155.79528,88.658436 C 157.32299,40.843037 125.58602,15.885505 102.67038,9.5101184 L 10.662893,8.9661054 z "
+ id="path1780"
+ sodipodi:nodetypes="cccccc"
+ transform="matrix(0.132588,0.000000,0.000000,0.134001,-0.711555,-0.583531)" />
+ <path
+ style="font-size:12;fill:url(#linearGradient1762);fill-opacity:0.75;fill-rule:evenodd;stroke:#0083e3;stroke-width:1.21826;"
+ d="M 0.63038442 0.67944183 L 12.032096 0.75041412 C 14.032942 0.50583897 18.565925 3.8014585 13.032518 8.3322463 C 16.533998 7.8430958 18.868318 6.6202197 19.36853 10.533424 L 19.404446 19.393563 L 0.63038442 19.393563 L 0.63038442 0.67944183 z "
+ id="path1781"
+ sodipodi:nodetypes="ccccccc" />
+ <g
+ id="g1567"
+ transform="matrix(6.409639e-2,0.000000,0.000000,8.090853e-2,0.672650,-1.499688)"
+ style="font-size:12;">
+ <path
+ sodipodi:type="arc"
+ style="fill:#ffff00;fill-rule:evenodd;stroke:#ff0000;stroke-width:6.5509048;"
+ id="path1536"
+ sodipodi:cx="63.437500"
+ sodipodi:cy="39.375000"
+ sodipodi:rx="31.250000"
+ sodipodi:ry="31.562500"
+ d="M 94.687500 39.375000 A 31.250000 31.562500 0 1 0 32.187500,39.375000 A 31.250000 31.562500 0 1 0 94.687500 39.375000 z"
+ transform="matrix(2.033142,0.000000,0.000000,1.146119,-49.35104,33.00004)" />
+ <path
+ sodipodi:type="arc"
+ style="fill:url(#linearGradient892);fill-opacity:0.75000000;fill-rule:evenodd;stroke-width:10.000000;"
+ id="path1537"
+ sodipodi:cx="63.437500"
+ sodipodi:cy="39.375000"
+ sodipodi:rx="31.250000"
+ sodipodi:ry="31.562500"
+ d="M 94.687500 39.375000 A 31.250000 31.562500 0 1 0 32.187500,39.375000 A 31.250000 31.562500 0 1 0 94.687500 39.375000 z"
+ transform="matrix(1.866513,0.000000,0.000000,0.989918,-38.73914,38.52544)" />
+ <text
+ xml:space="preserve"
+ style="font-size:12.000000;stroke-width:1.0000000pt;font-family:Bitstream Vera Sans;"
+ x="6.9204906"
+ y="27.309141"
+ id="text869"
+ transform="scale(4.148831,3.402401)"><tspan
+ id="tspan870">ABC</tspan></text>
+ </g>
+ <path
+ style="font-size:12;fill:none;fill-opacity:0.75;fill-rule:evenodd;stroke:#ff0000;stroke-width:0.554883;stroke-dashoffset:0;"
+ d="M 5.667023 7.9654895 L 5.728223 15.040277 L 8.727023 15.040277 "
+ id="path1573"
+ sodipodi:nodetypes="ccc" />
+ <path
+ style="font-size:12;fill:none;fill-opacity:0.75;fill-rule:evenodd;stroke:#ff0000;stroke-width:0.627984;"
+ d="M 6.9618605 13.625319 L 9.3134855 14.961668 L 7.040248 16.769669 "
+ id="path971"
+ sodipodi:nodetypes="ccc" />
+ <g
+ id="g972"
+ transform="matrix(6.409639e-2,0.000000,0.000000,8.090853e-2,9.147869,8.561800)"
+ style="font-size:12;">
+ <path
+ sodipodi:type="arc"
+ style="fill:#ffff00;fill-rule:evenodd;stroke:#ff0000;stroke-width:6.5509048;"
+ id="path973"
+ sodipodi:cx="63.437500"
+ sodipodi:cy="39.375000"
+ sodipodi:rx="31.250000"
+ sodipodi:ry="31.562500"
+ d="M 94.687500 39.375000 A 31.250000 31.562500 0 1 0 32.187500,39.375000 A 31.250000 31.562500 0 1 0 94.687500 39.375000 z"
+ transform="matrix(2.033142,0.000000,0.000000,1.146119,-49.35104,33.00004)" />
+ <path
+ sodipodi:type="arc"
+ style="fill:url(#linearGradient892);fill-opacity:0.75000000;fill-rule:evenodd;stroke-width:10.000000;"
+ id="path974"
+ sodipodi:cx="63.437500"
+ sodipodi:cy="39.375000"
+ sodipodi:rx="31.250000"
+ sodipodi:ry="31.562500"
+ d="M 94.687500 39.375000 A 31.250000 31.562500 0 1 0 32.187500,39.375000 A 31.250000 31.562500 0 1 0 94.687500 39.375000 z"
+ transform="matrix(1.866513,0.000000,0.000000,0.989918,-38.73914,38.52544)" />
+ <text
+ xml:space="preserve"
+ style="font-size:12.000000;stroke-width:1.0000000pt;font-family:Bitstream Vera Sans;"
+ x="6.9204906"
+ y="27.309141"
+ id="text975"
+ transform="scale(4.148831,3.402401)"><tspan
+ id="tspan976">ABC</tspan></text>
+ </g>
+ </g>
+</svg>
diff --git a/umbrello/umbrello/pics/sources/diag_usecase.svg b/umbrello/umbrello/pics/sources/diag_usecase.svg
new file mode 100644
index 00000000..9f1d6400
--- /dev/null
+++ b/umbrello/umbrello/pics/sources/diag_usecase.svg
@@ -0,0 +1,489 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 20010904//EN"
+"http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd">
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+<svg
+ id="svg1"
+ sodipodi:version="0.32"
+ inkscape:version="0.37"
+ width="16pt"
+ height="16pt"
+ sodipodi:docbase="/home/jr/tmp/umbrello/icons/inkscape-svg"
+ sodipodi:docname="diag_usecase.svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:xml="http://www.w3.org/XML/1998/namespace"
+ xmlns:xlink="http://www.w3.org/1999/xlink">
+ <defs
+ id="defs3">
+ <linearGradient
+ id="linearGradient1796">
+ <stop
+ style="stop-color:#ffff21;stop-opacity:0.0000000;"
+ offset="0.0000000"
+ id="stop1797" />
+ <stop
+ style="stop-color:#fff;stop-opacity:1;"
+ offset="1"
+ id="stop1798" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient1763">
+ <stop
+ style="stop-color:#ffffff;stop-opacity:0.0000000;"
+ offset="0.0000000"
+ id="stop1764" />
+ <stop
+ style="stop-color:#fff;stop-opacity:1;"
+ offset="1"
+ id="stop1765" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient830">
+ <stop
+ style="stop-color:#ebffff;stop-opacity:0.0000000;"
+ offset="0.0000000"
+ id="stop831" />
+ <stop
+ style="stop-color:#fff;stop-opacity:1;"
+ offset="1"
+ id="stop832" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient826">
+ <stop
+ style="stop-color:#000;stop-opacity:1;"
+ offset="0"
+ id="stop827" />
+ <stop
+ style="stop-color:#fff;stop-opacity:1;"
+ offset="1"
+ id="stop828" />
+ </linearGradient>
+ <linearGradient
+ xlink:href="#linearGradient830"
+ id="linearGradient829"
+ x1="1.5500000"
+ y1="0.52343750"
+ x2="0.20422535"
+ y2="-0.12195122"
+ spreadMethod="reflect" />
+ <linearGradient
+ xlink:href="#linearGradient830"
+ id="linearGradient834" />
+ <linearGradient
+ xlink:href="#linearGradient830"
+ id="linearGradient836" />
+ <linearGradient
+ xlink:href="#linearGradient1763"
+ id="linearGradient1762"
+ x1="-0.34579438"
+ y1="-0.16406250"
+ x2="0.71962619"
+ y2="0.80468750" />
+ <linearGradient
+ xlink:href="#linearGradient1796"
+ id="linearGradient1795"
+ x1="0.65555555"
+ y1="0.88281250"
+ x2="0.48888889"
+ y2="0.53906250"
+ spreadMethod="reflect" />
+ <defs
+ id="defs1348">
+ <linearGradient
+ id="linearGradient1349">
+ <stop
+ style="stop-color:#ebffff;stop-opacity:0.0000000;"
+ offset="0.0000000"
+ id="stop1350" />
+ <stop
+ style="stop-color:#fff;stop-opacity:1;"
+ offset="1"
+ id="stop1351" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient1352">
+ <stop
+ style="stop-color:#000;stop-opacity:1;"
+ offset="0"
+ id="stop1353" />
+ <stop
+ style="stop-color:#fff;stop-opacity:1;"
+ offset="1"
+ id="stop1354" />
+ </linearGradient>
+ <linearGradient
+ xlink:href="#linearGradient830"
+ id="linearGradient1355"
+ x1="1.5500000"
+ y1="0.52343750"
+ x2="0.20422535"
+ y2="-0.12195122"
+ spreadMethod="reflect" />
+ <linearGradient
+ xlink:href="#linearGradient830"
+ id="linearGradient1356"
+ x1="-0.31159419"
+ y1="0.19531250"
+ x2="0.77536231"
+ y2="0.94531250" />
+ <linearGradient
+ xlink:href="#linearGradient830"
+ id="linearGradient1357" />
+ </defs>
+ <sodipodi:namedview
+ id="namedview1358"
+ pagecolor="#ffffff"
+ bordercolor="#666666"
+ borderopacity="1.0"
+ inkscape:pageopacity="0.0"
+ inkscape:pageshadow="2"
+ inkscape:zoom="0.26725582"
+ inkscape:cx="87.469639"
+ inkscape:cy="55.703730"
+ inkscape:window-width="1022"
+ inkscape:window-height="701"
+ gridspacingy="1.0000000pt"
+ gridspacingx="1.0000000pt"
+ gridtolerance="1.0000000px"
+ inkscape:window-x="0"
+ inkscape:window-y="0" />
+ <defs
+ id="defs1445">
+ <linearGradient
+ id="linearGradient973">
+ <stop
+ style="stop-color:#0000ff;stop-opacity:0.0000000;"
+ offset="0.0000000"
+ id="stop974" />
+ <stop
+ style="stop-color:#fff;stop-opacity:1;"
+ offset="1"
+ id="stop975" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient868">
+ <stop
+ style="stop-color:#ffffff;stop-opacity:0.0000000;"
+ offset="0.0000000"
+ id="stop869" />
+ <stop
+ style="stop-color:#fff;stop-opacity:1;"
+ offset="1"
+ id="stop870" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient893">
+ <stop
+ style="stop-color:#19839a;stop-opacity:0.0000000;"
+ offset="0.0000000"
+ id="stop894" />
+ <stop
+ style="stop-color:#fff;stop-opacity:1;"
+ offset="1"
+ id="stop895" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient1455">
+ <stop
+ style="stop-color:#ebffff;stop-opacity:0.0000000;"
+ offset="0.0000000"
+ id="stop1456" />
+ <stop
+ style="stop-color:#fff;stop-opacity:1;"
+ offset="1"
+ id="stop1457" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient1458">
+ <stop
+ style="stop-color:#000;stop-opacity:1;"
+ offset="0"
+ id="stop1459" />
+ <stop
+ style="stop-color:#fff;stop-opacity:1;"
+ offset="1"
+ id="stop1460" />
+ </linearGradient>
+ <linearGradient
+ xlink:href="#linearGradient830"
+ id="linearGradient1461"
+ x1="1.5500000"
+ y1="0.52343750"
+ x2="0.20422535"
+ y2="-0.12195122"
+ spreadMethod="reflect" />
+ <linearGradient
+ xlink:href="#linearGradient830"
+ id="linearGradient1462"
+ x1="-0.31159419"
+ y1="0.19531250"
+ x2="0.77536231"
+ y2="0.94531250" />
+ <linearGradient
+ xlink:href="#linearGradient830"
+ id="linearGradient1463" />
+ <linearGradient
+ xlink:href="#linearGradient868"
+ id="linearGradient892" />
+ <linearGradient
+ xlink:href="#linearGradient973"
+ id="linearGradient926"
+ x1="1.5043305e-18"
+ y1="0.50000000"
+ x2="1.0000000"
+ y2="0.50000000" />
+ <linearGradient
+ xlink:href="#linearGradient868"
+ id="linearGradient928" />
+ <linearGradient
+ xlink:href="#linearGradient830"
+ id="linearGradient937"
+ x1="0.010563380"
+ y1="0.48571429"
+ x2="0.98943663"
+ y2="0.48571429"
+ spreadMethod="pad" />
+ <radialGradient
+ xlink:href="#linearGradient973"
+ id="radialGradient976"
+ cx="0.49275362"
+ cy="0.46875000"
+ r="0.80203730"
+ fx="0.49275362"
+ fy="0.46875000"
+ spreadMethod="reflect" />
+ </defs>
+ <sodipodi:namedview
+ id="namedview1469"
+ pagecolor="#ffffff"
+ bordercolor="#666666"
+ borderopacity="1.0"
+ inkscape:pageopacity="0.0"
+ inkscape:pageshadow="2"
+ inkscape:zoom="4.0000000"
+ inkscape:cx="79.132812"
+ inkscape:cy="66.817627"
+ inkscape:window-width="1022"
+ inkscape:window-height="701"
+ gridspacingy="1.0000000pt"
+ gridspacingx="1.0000000pt"
+ gridtolerance="1.0000000px"
+ inkscape:window-x="0"
+ inkscape:window-y="0" />
+ <defs
+ id="defs1515">
+ <linearGradient
+ id="linearGradient1516">
+ <stop
+ style="stop-color:#ffffff;stop-opacity:0.0000000;"
+ offset="0.0000000"
+ id="stop1517" />
+ <stop
+ style="stop-color:#fff;stop-opacity:1;"
+ offset="1"
+ id="stop1518" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient1519">
+ <stop
+ style="stop-color:#19839a;stop-opacity:0.0000000;"
+ offset="0.0000000"
+ id="stop1520" />
+ <stop
+ style="stop-color:#fff;stop-opacity:1;"
+ offset="1"
+ id="stop1521" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient1522">
+ <stop
+ style="stop-color:#ebffff;stop-opacity:0.0000000;"
+ offset="0.0000000"
+ id="stop1523" />
+ <stop
+ style="stop-color:#fff;stop-opacity:1;"
+ offset="1"
+ id="stop1524" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient1525">
+ <stop
+ style="stop-color:#000;stop-opacity:1;"
+ offset="0"
+ id="stop1526" />
+ <stop
+ style="stop-color:#fff;stop-opacity:1;"
+ offset="1"
+ id="stop1527" />
+ </linearGradient>
+ <linearGradient
+ xlink:href="#linearGradient830"
+ id="linearGradient1528"
+ x1="1.5500000"
+ y1="0.52343750"
+ x2="0.20422535"
+ y2="-0.12195122"
+ spreadMethod="reflect" />
+ <linearGradient
+ xlink:href="#linearGradient830"
+ id="linearGradient1529"
+ x1="-0.31159419"
+ y1="0.19531250"
+ x2="0.77536231"
+ y2="0.94531250" />
+ <linearGradient
+ xlink:href="#linearGradient830"
+ id="linearGradient1530" />
+ <linearGradient
+ xlink:href="#linearGradient868"
+ id="linearGradient1531" />
+ </defs>
+ <sodipodi:namedview
+ id="namedview1532"
+ pagecolor="#ffffff"
+ bordercolor="#666666"
+ borderopacity="1.0"
+ inkscape:pageopacity="0.0"
+ inkscape:pageshadow="2"
+ inkscape:zoom="4.0000000"
+ inkscape:cx="79.132812"
+ inkscape:cy="69.358765"
+ inkscape:window-width="1022"
+ inkscape:window-height="701"
+ gridspacingy="1.0000000pt"
+ gridspacingx="1.0000000pt"
+ gridtolerance="1.0000000px"
+ inkscape:window-x="0"
+ inkscape:window-y="0" />
+ </defs>
+ <sodipodi:namedview
+ id="base"
+ pagecolor="#ffffff"
+ bordercolor="#666666"
+ borderopacity="1.0"
+ inkscape:pageopacity="0.0"
+ inkscape:pageshadow="2"
+ inkscape:zoom="31.9999999"
+ inkscape:cx="11.2369790"
+ inkscape:cy="7.78464891"
+ inkscape:window-width="1016"
+ inkscape:window-height="693"
+ gridspacingy="1.0000000pt"
+ gridspacingx="1.0000000pt"
+ gridtolerance="1.0000000px"
+ inkscape:window-x="0"
+ inkscape:window-y="0"
+ showgrid="true"
+ snaptogrid="false" />
+ <rect
+ style="fill:url(#linearGradient829);fill-opacity:0.75000000;fill-rule:evenodd;stroke-width:0.45652742pt;"
+ id="rect825"
+ width="137.68759"
+ height="66.465706"
+ ry="0.0000000"
+ x="359.81241"
+ y="197.28429" />
+ <rect
+ style="fill:url(#linearGradient829);fill-opacity:0.75000000;fill-rule:evenodd;stroke-width:0.45652742pt;"
+ id="rect846"
+ width="135.18759"
+ height="37.082668"
+ ry="0.0000000"
+ x="316.25000"
+ y="81.250000" />
+ <rect
+ style="fill:url(#linearGradient829);fill-opacity:0.75000000;fill-rule:evenodd;stroke:none;stroke-width:0.45652742pt;stroke-opacity:1.0000000;"
+ id="rect847"
+ width="135.18759"
+ height="47.111610"
+ ry="0.0000000"
+ x="255.00000"
+ y="157.88839" />
+ <path
+ style="font-size:12;fill:#8df2ff;fill-rule:evenodd;stroke-width:5;"
+ d="M 0.70221666 0.81324909 L 0.70221666 20.035184 L 19.94503 20.035184 L 19.94503 11.492101 C 20.147586 5.0847898 15.939644 1.7404556 12.901305 0.88614738 L 0.70221666 0.81324909 z "
+ id="path1780"
+ sodipodi:nodetypes="cccccc" />
+ <path
+ style="font-size:12;fill:url(#linearGradient1762);fill-opacity:0.75;fill-rule:evenodd;stroke:#0083e3;stroke-width:1.21953;"
+ d="M 0.63038443 0.67944234 L 12.032095 0.75056278 C 14.032942 0.50547713 18.565925 3.8079757 13.032517 8.3482207 C 16.533998 7.8580492 18.868318 6.6326205 19.368529 10.553993 L 19.404447 19.432627 L 0.63038443 19.432627 L 0.63038443 0.67944234 z "
+ id="path1781"
+ sodipodi:nodetypes="ccccccc" />
+ <g
+ id="g1509"
+ transform="matrix(6.244386e-2,0.000000,0.000000,5.641895e-2,8.731110,9.897060)"
+ style="font-size:12;">
+ <path
+ style="fill:#ff0000;fill-rule:evenodd;stroke:#ff0000;stroke-width:5.0000000;"
+ d="M 25.093750,44.875000 L 29.375000,70.812500 L 75.375000,92.968750 L 74.906250,105.96875 L 9.4375000,130.71875 L 39.312500,151.71875 L 77.468750,118.50000 L 83.156250,118.43750 L 127.21875,152.31250 L 153.81250,127.56250 L 86.187500,106.68750 L 86.625000,93.218750 L 129.62500,88.812500 L 136.31250,62.625000 L 86.500000,81.250000 L 86.187500,55.250000 L 74.937500,55.375000 L 75.218750,78.562500 L 25.093750,44.875000 z "
+ id="path972"
+ sodipodi:nodetypes="ccccccccccccccccccc" />
+ <g
+ id="g909"
+ transform="matrix(0.813839,0.000000,0.000000,1.000000,22.06356,-5.625000)"
+ style="">
+ <path
+ sodipodi:type="arc"
+ style="fill:#ffff00;fill-rule:evenodd;stroke:#ff0000;stroke-width:10.800957;stroke-dasharray:none;"
+ id="path863"
+ sodipodi:cx="63.437500"
+ sodipodi:cy="39.375000"
+ sodipodi:rx="31.250000"
+ sodipodi:ry="31.562500"
+ d="M 94.687500 39.375000 A 31.250000 31.562500 0 1 0 32.187500,39.375000 A 31.250000 31.562500 0 1 0 94.687500 39.375000 z"
+ transform="matrix(0.841497,0.000000,0.000000,0.838191,19.68138,6.062272)" />
+ <path
+ sodipodi:type="arc"
+ style="fill:url(#linearGradient892);fill-opacity:0.75000000;fill-rule:evenodd;stroke-width:10.000000;"
+ id="path864"
+ sodipodi:cx="63.437500"
+ sodipodi:cy="39.375000"
+ sodipodi:rx="31.250000"
+ sodipodi:ry="31.562500"
+ d="M 94.687500 39.375000 A 31.250000 31.562500 0 1 0 32.187500,39.375000 A 31.250000 31.562500 0 1 0 94.687500 39.375000 z"
+ transform="matrix(0.741224,0.000000,0.000000,0.702062,25.43390,11.29160)" />
+ </g>
+ </g>
+ <g
+ id="g1567"
+ transform="matrix(6.409639e-2,0.000000,0.000000,8.090853e-2,1.063275,-1.460626)"
+ style="font-size:12;">
+ <path
+ sodipodi:type="arc"
+ style="fill:#ffff00;fill-rule:evenodd;stroke:#ff0000;stroke-width:6.5509048;"
+ id="path1536"
+ sodipodi:cx="63.437500"
+ sodipodi:cy="39.375000"
+ sodipodi:rx="31.250000"
+ sodipodi:ry="31.562500"
+ d="M 94.687500 39.375000 A 31.250000 31.562500 0 1 0 32.187500,39.375000 A 31.250000 31.562500 0 1 0 94.687500 39.375000 z"
+ transform="matrix(2.033142,0.000000,0.000000,1.146119,-49.35104,33.00004)" />
+ <path
+ sodipodi:type="arc"
+ style="fill:url(#linearGradient892);fill-opacity:0.75000000;fill-rule:evenodd;stroke-width:10.000000;"
+ id="path1537"
+ sodipodi:cx="63.437500"
+ sodipodi:cy="39.375000"
+ sodipodi:rx="31.250000"
+ sodipodi:ry="31.562500"
+ d="M 94.687500 39.375000 A 31.250000 31.562500 0 1 0 32.187500,39.375000 A 31.250000 31.562500 0 1 0 94.687500 39.375000 z"
+ transform="matrix(1.866513,0.000000,0.000000,0.989918,-38.73914,38.52544)" />
+ <text
+ xml:space="preserve"
+ style="font-size:12.000000;stroke-width:1.0000000pt;font-family:Bitstream Vera Sans;"
+ x="6.9204906"
+ y="27.309141"
+ id="text869"
+ transform="scale(4.148831,3.402401)"><tspan
+ id="tspan870">ABC</tspan></text>
+ </g>
+ <path
+ style="font-size:12;fill:none;fill-opacity:0.75;fill-rule:evenodd;stroke:#ff0000;stroke-width:7.5;stroke-dasharray:15 7.5 ;stroke-dashoffset:0;"
+ d="M 48.750000,68.437500 L 49.375000,123.43750 L 93.125000,123.43750"
+ id="path1573"
+ sodipodi:nodetypes="ccc"
+ transform="matrix(0.125420,0.000000,0.000000,0.125774,-0.133652,-5.284487e-2)" />
+</svg>
diff --git a/umbrello/umbrello/pics/sources/diagbase.svg b/umbrello/umbrello/pics/sources/diagbase.svg
new file mode 100644
index 00000000..44774402
--- /dev/null
+++ b/umbrello/umbrello/pics/sources/diagbase.svg
@@ -0,0 +1,189 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 20010904//EN"
+"http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd">
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+<svg
+ id="svg1"
+ sodipodi:version="0.32"
+ inkscape:version="0.38.1"
+ width="128.00000pt"
+ height="128.00000pt"
+ sodipodi:docbase="/home/bartkozoltan/Documents/work/umbrello/new pics"
+ sodipodi:docname="diagbase.svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:xml="http://www.w3.org/XML/1998/namespace"
+ xmlns:xlink="http://www.w3.org/1999/xlink">
+ <defs
+ id="defs3">
+ <linearGradient
+ id="linearGradient1796">
+ <stop
+ style="stop-color:#ffff21;stop-opacity:0.0000000;"
+ offset="0.0000000"
+ id="stop1797" />
+ <stop
+ style="stop-color:#fff;stop-opacity:1;"
+ offset="1"
+ id="stop1798" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient1763">
+ <stop
+ style="stop-color:#ffffff;stop-opacity:0.0000000;"
+ offset="0.0000000"
+ id="stop1764" />
+ <stop
+ style="stop-color:#fff;stop-opacity:1;"
+ offset="1"
+ id="stop1765" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient830">
+ <stop
+ style="stop-color:#ebffff;stop-opacity:0.0000000;"
+ offset="0.0000000"
+ id="stop831" />
+ <stop
+ style="stop-color:#fff;stop-opacity:1;"
+ offset="1"
+ id="stop832" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient826">
+ <stop
+ style="stop-color:#000;stop-opacity:1;"
+ offset="0"
+ id="stop827" />
+ <stop
+ style="stop-color:#fff;stop-opacity:1;"
+ offset="1"
+ id="stop828" />
+ </linearGradient>
+ <linearGradient
+ xlink:href="#linearGradient830"
+ id="linearGradient829"
+ x1="1.5500000"
+ y1="0.52343750"
+ x2="0.20422535"
+ y2="-0.12195122"
+ spreadMethod="reflect" />
+ <linearGradient
+ xlink:href="#linearGradient830"
+ id="linearGradient834"
+ x1="-0.31159419"
+ y1="0.19531250"
+ x2="0.77536231"
+ y2="0.94531250" />
+ <linearGradient
+ xlink:href="#linearGradient830"
+ id="linearGradient836" />
+ <linearGradient
+ xlink:href="#linearGradient1763"
+ id="linearGradient1762"
+ x1="-0.34579438"
+ y1="-0.16406250"
+ x2="0.71962619"
+ y2="0.80468750" />
+ <linearGradient
+ xlink:href="#linearGradient1796"
+ id="linearGradient1795"
+ x1="0.65555555"
+ y1="0.88281250"
+ x2="0.48888889"
+ y2="0.53906250"
+ spreadMethod="reflect" />
+ </defs>
+ <sodipodi:namedview
+ id="base"
+ pagecolor="#ffffff"
+ bordercolor="#666666"
+ borderopacity="1.0"
+ inkscape:pageopacity="0.0"
+ inkscape:pageshadow="2"
+ inkscape:zoom="4.0000000"
+ inkscape:cx="79.113403"
+ inkscape:cy="71.451782"
+ inkscape:window-width="1022"
+ inkscape:window-height="701"
+ gridspacingy="1.0000000pt"
+ gridspacingx="1.0000000pt"
+ gridtolerance="1.0000000px"
+ inkscape:window-x="0"
+ inkscape:window-y="0"
+ showgrid="true"
+ snaptogrid="true" />
+ <path
+ sodipodi:type="arc"
+ style="fill:url(#linearGradient834);fill-opacity:0.75000000;fill-rule:evenodd;stroke:#000000;stroke-width:1.0000000pt;"
+ id="path833"
+ sodipodi:cx="541.27716"
+ sodipodi:cy="303.78741"
+ sodipodi:rx="172.74803"
+ sodipodi:ry="161.23149"
+ d="M 714.02519 303.78741 A 172.74803 161.23149 0 1 0 368.52913,303.78741 A 172.74803 161.23149 0 1 0 714.02519 303.78741 z"
+ transform="translate(224.5724,63.34093)" />
+ <rect
+ style="fill:url(#linearGradient836);fill-opacity:0.75000000;fill-rule:evenodd;stroke:#ff0000;stroke-width:5.0000000;stroke-opacity:1.0000000;stroke-dasharray:none;"
+ id="rect835"
+ width="495.39624"
+ height="385.66864"
+ x="-679.56819"
+ y="64.886958" />
+ <rect
+ style="fill:url(#linearGradient829);fill-opacity:0.75000000;fill-rule:evenodd;stroke:#000000;stroke-width:0.45652742pt;stroke-opacity:1.0000000;"
+ id="rect841"
+ width="135.18759"
+ height="38.339100"
+ ry="0.0000000"
+ x="438.75000"
+ y="104.16090" />
+ <rect
+ style="fill:#ffff00;fill-rule:evenodd;stroke:#ff0000;stroke-width:3.5942383;"
+ id="rect837"
+ width="140.70964"
+ height="69.757812"
+ x="81.250000"
+ y="262.74219"
+ ry="0.0000000" />
+ <rect
+ style="fill:url(#linearGradient829);fill-opacity:0.75000000;fill-rule:evenodd;stroke-width:0.45652742pt;"
+ id="rect825"
+ width="137.68759"
+ height="66.465706"
+ ry="0.0000000"
+ x="359.81241"
+ y="197.28429" />
+ <rect
+ style="fill:url(#linearGradient829);fill-opacity:0.75000000;fill-rule:evenodd;stroke-width:0.45652742pt;"
+ id="rect846"
+ width="135.18759"
+ height="37.082668"
+ ry="0.0000000"
+ x="316.25000"
+ y="81.250000" />
+ <rect
+ style="fill:url(#linearGradient829);fill-opacity:0.75000000;fill-rule:evenodd;stroke:none;stroke-width:0.45652742pt;stroke-opacity:1.0000000;"
+ id="rect847"
+ width="135.18759"
+ height="47.111610"
+ ry="0.0000000"
+ x="255.00000"
+ y="157.88839" />
+ <path
+ style="fill:url(#linearGradient1762);fill-rule:evenodd;stroke:black;stroke-opacity:1;stroke-width:1pt;stroke-linejoin:miter;stroke-linecap:butt;fill-opacity:0.75;"
+ d="M 323.12500,279.37500 L 409.37500,279.37500 C 409.37500,279.37500 441.87500,288.12500 406.87500,305.00000 C 423.75000,297.50000 438.12500,303.75000 440.00000,313.75000 L 440.00000,348.75000 L 323.12500,349.37500 L 323.12500,279.37500 z "
+ id="path1761"
+ sodipodi:nodetypes="ccccccc" />
+ <path
+ style="fill:#8df2ff;fill-rule:evenodd;stroke-width:5.0000000;fill-opacity:1.0000000;"
+ d="M 10.662893,8.9661054 L 10.662893,152.41231 L 155.79528,152.41231 L 155.79528,88.658436 C 157.32299,40.843037 125.58602,15.885505 102.67038,9.5101184 L 10.662893,8.9661054 z "
+ id="path1780"
+ sodipodi:nodetypes="cccccc" />
+ <path
+ style="fill:url(#linearGradient1762);fill-opacity:0.75000000;fill-rule:evenodd;stroke:#2642d7;stroke-width:6.2179222;"
+ d="M 8.0588132,7.0930279 L 96.199432,7.6370399 C 111.66692,5.7623392 146.70903,31.023695 103.93317,65.752779 C 131.00127,62.003376 149.04667,52.629870 152.91354,82.625089 L 153.19119,150.53923 L 8.0588132,150.53923 L 8.0588132,7.0930279 z "
+ id="path1781"
+ sodipodi:nodetypes="ccccccc" />
+</svg>
diff --git a/umbrello/umbrello/pics/sources/end_state.svg b/umbrello/umbrello/pics/sources/end_state.svg
new file mode 100644
index 00000000..65d22943
--- /dev/null
+++ b/umbrello/umbrello/pics/sources/end_state.svg
@@ -0,0 +1,136 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 20010904//EN"
+"http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd">
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+<svg
+ id="svg1"
+ sodipodi:version="0.32"
+ inkscape:version="0.38.1"
+ width="128.00000pt"
+ height="128.00000pt"
+ sodipodi:docbase="/home/bartkozoltan/Documents/work/umbrello/new pics"
+ sodipodi:docname="final.svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:xlink="http://www.w3.org/1999/xlink">
+ <defs
+ id="defs3">
+ <linearGradient
+ id="linearGradient868">
+ <stop
+ style="stop-color:#ffffff;stop-opacity:0.0000000;"
+ offset="0.0000000"
+ id="stop869" />
+ <stop
+ style="stop-color:#fff;stop-opacity:1;"
+ offset="1"
+ id="stop870" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient893">
+ <stop
+ style="stop-color:#19839a;stop-opacity:0.0000000;"
+ offset="0.0000000"
+ id="stop894" />
+ <stop
+ style="stop-color:#fff;stop-opacity:1;"
+ offset="1"
+ id="stop895" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient830">
+ <stop
+ style="stop-color:#ebffff;stop-opacity:0.0000000;"
+ offset="0.0000000"
+ id="stop831" />
+ <stop
+ style="stop-color:#fff;stop-opacity:1;"
+ offset="1"
+ id="stop832" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient826">
+ <stop
+ style="stop-color:#000;stop-opacity:1;"
+ offset="0"
+ id="stop827" />
+ <stop
+ style="stop-color:#fff;stop-opacity:1;"
+ offset="1"
+ id="stop828" />
+ </linearGradient>
+ <linearGradient
+ xlink:href="#linearGradient830"
+ id="linearGradient829"
+ x1="1.5500000"
+ y1="0.52343750"
+ x2="0.20422535"
+ y2="-0.12195122"
+ spreadMethod="reflect" />
+ <linearGradient
+ xlink:href="#linearGradient830"
+ id="linearGradient834"
+ x1="-0.31159419"
+ y1="0.19531250"
+ x2="0.77536231"
+ y2="0.94531250" />
+ <linearGradient
+ xlink:href="#linearGradient830"
+ id="linearGradient836" />
+ <linearGradient
+ xlink:href="#linearGradient868"
+ id="linearGradient892" />
+ </defs>
+ <sodipodi:namedview
+ id="base"
+ pagecolor="#ffffff"
+ bordercolor="#666666"
+ borderopacity="1.0"
+ inkscape:pageopacity="0.0"
+ inkscape:pageshadow="2"
+ inkscape:zoom="4.0000000"
+ inkscape:cx="79.132812"
+ inkscape:cy="69.358765"
+ inkscape:window-width="1022"
+ inkscape:window-height="701"
+ gridspacingy="1.0000000pt"
+ gridspacingx="1.0000000pt"
+ gridtolerance="1.0000000px"
+ inkscape:window-x="0"
+ inkscape:window-y="0" />
+ <path
+ sodipodi:type="arc"
+ style="fill:none;fill-rule:evenodd;stroke:#ff0000;stroke-width:6.6418063;stroke-dasharray:none;"
+ id="path851"
+ sodipodi:cx="63.437500"
+ sodipodi:cy="39.375000"
+ sodipodi:rx="31.250000"
+ sodipodi:ry="31.562500"
+ d="M 94.687500 39.375000 A 31.250000 31.562500 0 1 0 32.187500,39.375000 A 31.250000 31.562500 0 1 0 94.687500 39.375000 z"
+ transform="matrix(1.897276,0.000000,0.000000,1.866883,-40.40849,6.907883)" />
+ <g
+ id="g862"
+ transform="matrix(0.661598,0.000000,0.000000,0.612172,25.66010,32.61122)">
+ <path
+ sodipodi:type="arc"
+ style="fill:#ff0000;fill-opacity:1.0000000;fill-rule:evenodd;stroke:#ff0000;stroke-width:10.000000;stroke-opacity:1.0000000;stroke-dasharray:none;"
+ id="path863"
+ sodipodi:cx="63.437500"
+ sodipodi:cy="39.375000"
+ sodipodi:rx="31.250000"
+ sodipodi:ry="31.562500"
+ d="M 94.687500 39.375000 A 31.250000 31.562500 0 1 0 32.187500,39.375000 A 31.250000 31.562500 0 1 0 94.687500 39.375000 z"
+ transform="matrix(1.663793,0.000000,0.000000,1.760684,-24.92188,9.110577)" />
+ <path
+ sodipodi:type="arc"
+ style="fill:url(#linearGradient892);fill-opacity:0.75000000;fill-rule:evenodd;stroke:none;stroke-width:10.000000;stroke-opacity:1.0000000;stroke-dasharray:none;"
+ id="path864"
+ sodipodi:cx="63.437500"
+ sodipodi:cy="39.375000"
+ sodipodi:rx="31.250000"
+ sodipodi:ry="31.562500"
+ d="M 94.687500 39.375000 A 31.250000 31.562500 0 1 0 32.187500,39.375000 A 31.250000 31.562500 0 1 0 94.687500 39.375000 z"
+ transform="matrix(1.331034,0.000000,0.000000,1.429466,-1.732780,22.15226)" />
+ </g>
+</svg>
diff --git a/umbrello/umbrello/pics/sources/entity.svg b/umbrello/umbrello/pics/sources/entity.svg
new file mode 100644
index 00000000..a40611eb
--- /dev/null
+++ b/umbrello/umbrello/pics/sources/entity.svg
@@ -0,0 +1,151 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 20010904//EN"
+"http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd">
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+<svg
+ id="svg1"
+ sodipodi:version="0.32"
+ inkscape:version="0.40"
+ width="22pt"
+ height="22pt"
+ sodipodi:docbase="/home/jr/devel/kdesdk/umbrello/umbrello/pics/sources"
+ sodipodi:docname="entity.svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:xml="http://www.w3.org/XML/1998/namespace"
+ xmlns:xlink="http://www.w3.org/1999/xlink"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:cc="http://web.resource.org/cc/"
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ inkscape:export-filename="/home/jr/devel/kdesdk/umbrello/umbrello/pics/entity.png"
+ inkscape:export-xdpi="72.000000"
+ inkscape:export-ydpi="72.000000">
+ <metadata
+ id="metadata23">
+ <rdf:RDF
+ id="RDF24">
+ <cc:Work
+ rdf:about=""
+ id="Work25">
+ <dc:format
+ id="format26">image/svg+xml</dc:format>
+ <dc:type
+ id="type28"
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+ </cc:Work>
+ </rdf:RDF>
+ </metadata>
+ <defs
+ id="defs3">
+ <linearGradient
+ id="linearGradient830">
+ <stop
+ style="stop-color:#ebffff;stop-opacity:0.0000000;"
+ offset="0.0000000"
+ id="stop831" />
+ <stop
+ style="stop-color:#fff;stop-opacity:1;"
+ offset="1"
+ id="stop832" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient826">
+ <stop
+ style="stop-color:#000;stop-opacity:1;"
+ offset="0"
+ id="stop827" />
+ <stop
+ style="stop-color:#fff;stop-opacity:1;"
+ offset="1"
+ id="stop828" />
+ </linearGradient>
+ <linearGradient
+ xlink:href="#linearGradient830"
+ id="linearGradient829"
+ x1="1.5500000"
+ y1="0.52343750"
+ x2="0.20422535"
+ y2="-0.12195122"
+ spreadMethod="reflect" />
+ <linearGradient
+ xlink:href="#linearGradient830"
+ id="linearGradient834"
+ x1="-0.31159419"
+ y1="0.19531250"
+ x2="0.77536231"
+ y2="0.94531250" />
+ <linearGradient
+ xlink:href="#linearGradient830"
+ id="linearGradient836" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient830"
+ id="linearGradient1089"
+ spreadMethod="reflect"
+ x1="23.537647"
+ y1="37.602750"
+ x2="3.7720042"
+ y2="28.123806"
+ gradientTransform="matrix(1.701614,0.000000,0.000000,1.095210,0.000000,-22.63705)"
+ gradientUnits="userSpaceOnUse" />
+ </defs>
+ <sodipodi:namedview
+ id="base"
+ pagecolor="#ffffff"
+ bordercolor="#666666"
+ borderopacity="1.0"
+ inkscape:pageopacity="0.0"
+ inkscape:pageshadow="2"
+ inkscape:zoom="17.104372"
+ inkscape:cx="12.250321"
+ inkscape:cy="20.076918"
+ inkscape:window-width="1016"
+ inkscape:window-height="692"
+ gridspacingy="1.0000000pt"
+ gridspacingx="1.0000000pt"
+ gridtolerance="1.0000000px"
+ inkscape:window-x="0"
+ inkscape:window-y="0"
+ snaptogrid="false"
+ showgrid="true"
+ inkscape:current-layer="svg1" />
+ <g
+ id="g1196">
+ <rect
+ style="font-size:12.000000;fill:#ffff00;fill-rule:evenodd;stroke:#ff0000;stroke-width:1.2396300;"
+ id="rect837"
+ width="26.24992934"
+ height="26.18856802"
+ x="0.66534913"
+ y="0.71917963" />
+ <rect
+ style="font-size:12.000000;fill:url(#linearGradient829);fill-opacity:0.75000000;fill-rule:evenodd;stroke-width:0.45652699pt;"
+ id="rect825"
+ width="24.99192419"
+ height="7.33014917"
+ ry="0"
+ x="1.21161342"
+ y="1.36787295" />
+ <text
+ xml:space="preserve"
+ style="font-size:12.000000;font-weight:normal;stroke-width:1.0000000pt;font-family:Bitstream Vera Sans;"
+ x="2.59171310"
+ y="11.3147535"
+ id="text838"
+ transform="scale(0.933669,0.722645)"><tspan
+ id="tspan839">ABC</tspan></text>
+ <path
+ style="font-size:12.000000;fill:none;fill-opacity:0.75000000;fill-rule:evenodd;stroke:#ff0000;stroke-width:1.2500000;"
+ d="M 1.1533278 9.3908034 L 26.731652 9.3908034 "
+ id="path842" />
+ <rect
+ style="font-size:12.000000;fill:url(#linearGradient1089);fill-opacity:0.75000000;fill-rule:evenodd;stroke-width:0.45652699pt"
+ id="rect847"
+ width="24.991922"
+ height="16.085562"
+ ry="0.0000000"
+ x="1.3145113"
+ y="10.126090" />
+ </g>
+</svg>
diff --git a/umbrello/umbrello/pics/sources/enum.svg b/umbrello/umbrello/pics/sources/enum.svg
new file mode 100644
index 00000000..ca09e448
--- /dev/null
+++ b/umbrello/umbrello/pics/sources/enum.svg
@@ -0,0 +1,114 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 20010904//EN"
+"http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd">
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+<svg
+ id="svg1"
+ sodipodi:version="0.32"
+ inkscape:version="0.37"
+ width="22pt"
+ height="22pt"
+ sodipodi:docbase="/home/jr/tmp/umbrello/icons/inkscape-svg"
+ sodipodi:docname="enum.svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:xml="http://www.w3.org/XML/1998/namespace"
+ xmlns:xlink="http://www.w3.org/1999/xlink">
+ <defs
+ id="defs3">
+ <linearGradient
+ id="linearGradient830">
+ <stop
+ style="stop-color:#ebffff;stop-opacity:0.0000000;"
+ offset="0.0000000"
+ id="stop831" />
+ <stop
+ style="stop-color:#fff;stop-opacity:1;"
+ offset="1"
+ id="stop832" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient826">
+ <stop
+ style="stop-color:#000;stop-opacity:1;"
+ offset="0"
+ id="stop827" />
+ <stop
+ style="stop-color:#fff;stop-opacity:1;"
+ offset="1"
+ id="stop828" />
+ </linearGradient>
+ <linearGradient
+ xlink:href="#linearGradient830"
+ id="linearGradient829"
+ x1="1.5500000"
+ y1="0.52343750"
+ x2="0.20422535"
+ y2="-0.12195122"
+ spreadMethod="reflect" />
+ <linearGradient
+ xlink:href="#linearGradient830"
+ id="linearGradient834"
+ x1="-0.31159419"
+ y1="0.19531250"
+ x2="0.77536231"
+ y2="0.94531250" />
+ <linearGradient
+ xlink:href="#linearGradient830"
+ id="linearGradient836" />
+ </defs>
+ <sodipodi:namedview
+ id="base"
+ pagecolor="#ffffff"
+ bordercolor="#666666"
+ borderopacity="1.0"
+ inkscape:pageopacity="0.0"
+ inkscape:pageshadow="2"
+ inkscape:zoom="22.6274170"
+ inkscape:cx="13.7972814"
+ inkscape:cy="11.0070359"
+ inkscape:window-width="1016"
+ inkscape:window-height="693"
+ gridspacingy="1.0000000pt"
+ gridspacingx="1.0000000pt"
+ gridtolerance="1.0000000px"
+ inkscape:window-x="0"
+ inkscape:window-y="0"
+ showgrid="true" />
+ <rect
+ style="font-size:12;fill:#ffff00;fill-rule:evenodd;stroke:#ff0000;stroke-width:1.23958;"
+ id="rect837"
+ width="26.26486117"
+ height="26.28001541"
+ x="0.61830062"
+ y="0.67129415" />
+ <rect
+ style="font-size:12;fill:url(#linearGradient829);fill-opacity:0.75;fill-rule:evenodd;stroke-width:0.456527pt;"
+ id="rect825"
+ width="24.94706100"
+ height="24.85842942"
+ ry="0"
+ x="1.36898315"
+ y="1.32233311" />
+ <text
+ xml:space="preserve"
+ style="font-size:12;font-weight:bold;font-stretch:normal;stroke-width:1pt;font-family:Bitstream Vera Sans Mono;font-style:normal;text-anchor:start;writing-mode:lr;"
+ x="1.94527822"
+ y="15.4448805"
+ id="text838"
+ transform="scale(0.671250,0.505970)"
+ sodipodi:linespacing="133%"><tspan
+ x="1.94527817"
+ y="15.4448805"
+ sodipodi:role="line"
+ id="tspan854">- ABC</tspan><tspan
+ x="1.94527817"
+ y="31.4048810"
+ sodipodi:role="line"
+ id="tspan856">- DEF</tspan><tspan
+ x="1.94527817"
+ y="47.3648815"
+ sodipodi:role="line"
+ id="tspan858">- IJK</tspan></text>
+</svg>
diff --git a/umbrello/umbrello/pics/sources/fork.svg b/umbrello/umbrello/pics/sources/fork.svg
new file mode 100644
index 00000000..c9e6c53b
--- /dev/null
+++ b/umbrello/umbrello/pics/sources/fork.svg
@@ -0,0 +1,115 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 20010904//EN"
+"http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd">
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+<svg
+ id="svg1"
+ sodipodi:version="0.32"
+ inkscape:version="0.37"
+ width="22pt"
+ height="22pt"
+ sodipodi:docbase="/home/jr/tmp/umbrello/icons/inkscape-svg"
+ sodipodi:docname="fork_join.svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:xlink="http://www.w3.org/1999/xlink">
+ <defs
+ id="defs3">
+ <linearGradient
+ id="linearGradient868">
+ <stop
+ style="stop-color:#ffffff;stop-opacity:0.0000000;"
+ offset="0.0000000"
+ id="stop869" />
+ <stop
+ style="stop-color:#fff;stop-opacity:1;"
+ offset="1"
+ id="stop870" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient893">
+ <stop
+ style="stop-color:#19839a;stop-opacity:0.0000000;"
+ offset="0.0000000"
+ id="stop894" />
+ <stop
+ style="stop-color:#fff;stop-opacity:1;"
+ offset="1"
+ id="stop895" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient830">
+ <stop
+ style="stop-color:#ebffff;stop-opacity:0.0000000;"
+ offset="0.0000000"
+ id="stop831" />
+ <stop
+ style="stop-color:#fff;stop-opacity:1;"
+ offset="1"
+ id="stop832" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient826">
+ <stop
+ style="stop-color:#000;stop-opacity:1;"
+ offset="0"
+ id="stop827" />
+ <stop
+ style="stop-color:#fff;stop-opacity:1;"
+ offset="1"
+ id="stop828" />
+ </linearGradient>
+ <linearGradient
+ xlink:href="#linearGradient830"
+ id="linearGradient829"
+ x1="1.5500000"
+ y1="0.52343750"
+ x2="0.20422535"
+ y2="-0.12195122"
+ spreadMethod="reflect" />
+ <linearGradient
+ xlink:href="#linearGradient830"
+ id="linearGradient834"
+ x1="-0.31159419"
+ y1="0.19531250"
+ x2="0.77536231"
+ y2="0.94531250" />
+ <linearGradient
+ xlink:href="#linearGradient830"
+ id="linearGradient836" />
+ <linearGradient
+ xlink:href="#linearGradient868"
+ id="linearGradient892"
+ x1="0.39932632"
+ y1="0.50707734"
+ x2="0.64623892"
+ y2="0.60370040"
+ spreadMethod="reflect" />
+ </defs>
+ <sodipodi:namedview
+ id="base"
+ pagecolor="#ffffff"
+ bordercolor="#666666"
+ borderopacity="1.0"
+ inkscape:pageopacity="0.0"
+ inkscape:pageshadow="2"
+ inkscape:zoom="22.6274170"
+ inkscape:cx="11.6871303"
+ inkscape:cy="11.8587637"
+ inkscape:window-width="1016"
+ inkscape:window-height="693"
+ gridspacingy="1.0000000pt"
+ gridspacingx="1.0000000pt"
+ gridtolerance="1.0000000px"
+ inkscape:window-x="0"
+ inkscape:window-y="0"
+ showgrid="true" />
+ <rect
+ style="font-size:12;fill:#ff0000;fill-opacity:0.75;fill-rule:evenodd;stroke:#ff0000;stroke-width:1.30478;"
+ id="rect903"
+ width="23.63188207"
+ height="3.75598452"
+ x="1.95761454"
+ y="11.92267035" />
+</svg>
diff --git a/umbrello/umbrello/pics/sources/generalise.svg b/umbrello/umbrello/pics/sources/generalise.svg
new file mode 100644
index 00000000..d43ed6c2
--- /dev/null
+++ b/umbrello/umbrello/pics/sources/generalise.svg
@@ -0,0 +1,127 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 20010904//EN"
+"http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd">
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+<svg
+ id="svg1"
+ sodipodi:version="0.32"
+ inkscape:version="0.37"
+ width="22pt"
+ height="22pt"
+ sodipodi:docbase="/home/jr/tmp/umbrello/icons/inkscape-svg"
+ sodipodi:docname="generalize.svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:xlink="http://www.w3.org/1999/xlink">
+ <defs
+ id="defs3">
+ <linearGradient
+ id="linearGradient868">
+ <stop
+ style="stop-color:#ffffff;stop-opacity:0.0000000;"
+ offset="0.0000000"
+ id="stop869" />
+ <stop
+ style="stop-color:#fff;stop-opacity:1;"
+ offset="1"
+ id="stop870" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient893">
+ <stop
+ style="stop-color:#19839a;stop-opacity:0.0000000;"
+ offset="0.0000000"
+ id="stop894" />
+ <stop
+ style="stop-color:#fff;stop-opacity:1;"
+ offset="1"
+ id="stop895" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient830">
+ <stop
+ style="stop-color:#ebffff;stop-opacity:0.0000000;"
+ offset="0.0000000"
+ id="stop831" />
+ <stop
+ style="stop-color:#fff;stop-opacity:1;"
+ offset="1"
+ id="stop832" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient826">
+ <stop
+ style="stop-color:#000;stop-opacity:1;"
+ offset="0"
+ id="stop827" />
+ <stop
+ style="stop-color:#fff;stop-opacity:1;"
+ offset="1"
+ id="stop828" />
+ </linearGradient>
+ <linearGradient
+ xlink:href="#linearGradient830"
+ id="linearGradient829"
+ x1="1.5500000"
+ y1="0.52343750"
+ x2="0.20422535"
+ y2="-0.12195122"
+ spreadMethod="reflect" />
+ <linearGradient
+ xlink:href="#linearGradient830"
+ id="linearGradient834"
+ x1="-0.31159419"
+ y1="0.19531250"
+ x2="0.77536231"
+ y2="0.94531250" />
+ <linearGradient
+ xlink:href="#linearGradient830"
+ id="linearGradient836" />
+ <linearGradient
+ xlink:href="#linearGradient868"
+ id="linearGradient892"
+ x1="-0.49264705"
+ y1="0.43750000"
+ x2="0.74305558"
+ y2="1.48437500" />
+ </defs>
+ <sodipodi:namedview
+ id="base"
+ pagecolor="#ffffff"
+ bordercolor="#666666"
+ borderopacity="1.0"
+ inkscape:pageopacity="0.0"
+ inkscape:pageshadow="2"
+ inkscape:zoom="22.6274170"
+ inkscape:cx="11.3902303"
+ inkscape:cy="10.2421455"
+ inkscape:window-width="1016"
+ inkscape:window-height="693"
+ gridspacingy="1.0000000pt"
+ gridspacingx="1.0000000pt"
+ gridtolerance="1.0000000px"
+ inkscape:window-x="0"
+ inkscape:window-y="0"
+ showgrid="true" />
+ <g
+ id="g907">
+ <path
+ style="font-size:12;fill:#ffff00;fill-rule:evenodd;stroke:#ff0000;stroke-width:1.63317;"
+ d="M 13.877015 1.8212949 L 18.663308 10.505802 L 8.8978064 10.489535 L 13.877015 1.8212949 z "
+ id="path874"
+ sodipodi:nodetypes="cccc" />
+ <path
+ style="font-size:12;fill:url(#linearGradient892);fill-rule:evenodd;stroke-width:12.5;"
+ d="M 13.846029 3.6304434 L 17.217581 9.7045394 L 10.441627 9.6475659 L 13.846029 3.6304434 z "
+ id="path875"
+ sodipodi:nodetypes="cccc" />
+ <rect
+ style="font-size:12;fill:#ff0000;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1pt;"
+ id="rect906"
+ width="2.54116492"
+ height="17.06999987"
+ x="12.54009724"
+ y="10.43000108" />
+ </g>
+</svg>
diff --git a/umbrello/umbrello/pics/sources/initial.svg b/umbrello/umbrello/pics/sources/initial.svg
new file mode 100644
index 00000000..2ab111b5
--- /dev/null
+++ b/umbrello/umbrello/pics/sources/initial.svg
@@ -0,0 +1,126 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 20010904//EN"
+"http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd">
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+<svg
+ id="svg1"
+ sodipodi:version="0.32"
+ inkscape:version="0.38.1"
+ width="128.00000pt"
+ height="128.00000pt"
+ sodipodi:docbase="/home/bartkozoltan/Documents/work/umbrello/new pics"
+ sodipodi:docname="initial.svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:xlink="http://www.w3.org/1999/xlink">
+ <defs
+ id="defs3">
+ <linearGradient
+ id="linearGradient868">
+ <stop
+ style="stop-color:#ffffff;stop-opacity:0.0000000;"
+ offset="0.0000000"
+ id="stop869" />
+ <stop
+ style="stop-color:#fff;stop-opacity:1;"
+ offset="1"
+ id="stop870" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient893">
+ <stop
+ style="stop-color:#19839a;stop-opacity:0.0000000;"
+ offset="0.0000000"
+ id="stop894" />
+ <stop
+ style="stop-color:#fff;stop-opacity:1;"
+ offset="1"
+ id="stop895" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient830">
+ <stop
+ style="stop-color:#ebffff;stop-opacity:0.0000000;"
+ offset="0.0000000"
+ id="stop831" />
+ <stop
+ style="stop-color:#fff;stop-opacity:1;"
+ offset="1"
+ id="stop832" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient826">
+ <stop
+ style="stop-color:#000;stop-opacity:1;"
+ offset="0"
+ id="stop827" />
+ <stop
+ style="stop-color:#fff;stop-opacity:1;"
+ offset="1"
+ id="stop828" />
+ </linearGradient>
+ <linearGradient
+ xlink:href="#linearGradient830"
+ id="linearGradient829"
+ x1="1.5500000"
+ y1="0.52343750"
+ x2="0.20422535"
+ y2="-0.12195122"
+ spreadMethod="reflect" />
+ <linearGradient
+ xlink:href="#linearGradient830"
+ id="linearGradient834"
+ x1="-0.31159419"
+ y1="0.19531250"
+ x2="0.77536231"
+ y2="0.94531250" />
+ <linearGradient
+ xlink:href="#linearGradient830"
+ id="linearGradient836" />
+ <linearGradient
+ xlink:href="#linearGradient868"
+ id="linearGradient892" />
+ </defs>
+ <sodipodi:namedview
+ id="base"
+ pagecolor="#ffffff"
+ bordercolor="#666666"
+ borderopacity="1.0"
+ inkscape:pageopacity="0.0"
+ inkscape:pageshadow="2"
+ inkscape:zoom="4.0000000"
+ inkscape:cx="79.132812"
+ inkscape:cy="69.358765"
+ inkscape:window-width="1022"
+ inkscape:window-height="701"
+ gridspacingy="1.0000000pt"
+ gridspacingx="1.0000000pt"
+ gridtolerance="1.0000000px"
+ inkscape:window-x="0"
+ inkscape:window-y="0" />
+ <g
+ id="g859"
+ transform="matrix(1.140332,0.000000,0.000000,1.060317,-11.98927,-2.752217)">
+ <path
+ sodipodi:type="arc"
+ style="fill:#ff0000;fill-opacity:1.0000000;fill-rule:evenodd;stroke:#ff0000;stroke-width:10.000000;stroke-opacity:1.0000000;stroke-dasharray:none;"
+ id="path851"
+ sodipodi:cx="63.437500"
+ sodipodi:cy="39.375000"
+ sodipodi:rx="31.250000"
+ sodipodi:ry="31.562500"
+ d="M 94.687500 39.375000 A 31.250000 31.562500 0 1 0 32.187500,39.375000 A 31.250000 31.562500 0 1 0 94.687500 39.375000 z"
+ transform="matrix(1.663793,0.000000,0.000000,1.760684,-24.92188,9.110577)" />
+ <path
+ sodipodi:type="arc"
+ style="fill:url(#linearGradient892);fill-opacity:0.75000000;fill-rule:evenodd;stroke:none;stroke-width:10.000000;stroke-opacity:1.0000000;stroke-dasharray:none;"
+ id="path858"
+ sodipodi:cx="63.437500"
+ sodipodi:cy="39.375000"
+ sodipodi:rx="31.250000"
+ sodipodi:ry="31.562500"
+ d="M 94.687500 39.375000 A 31.250000 31.562500 0 1 0 32.187500,39.375000 A 31.250000 31.562500 0 1 0 94.687500 39.375000 z"
+ transform="matrix(1.331034,0.000000,0.000000,1.429466,-1.732780,22.15226)" />
+ </g>
+</svg>
diff --git a/umbrello/umbrello/pics/sources/interface.svg b/umbrello/umbrello/pics/sources/interface.svg
new file mode 100644
index 00000000..00c0a274
--- /dev/null
+++ b/umbrello/umbrello/pics/sources/interface.svg
@@ -0,0 +1,130 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 20010904//EN"
+"http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd">
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+<svg
+ id="svg1"
+ sodipodi:version="0.32"
+ inkscape:version="0.37"
+ width="22pt"
+ height="22pt"
+ sodipodi:docbase="/home/jr/tmp/umbrello/icons/inkscape-svg"
+ sodipodi:docname="interface.svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:xml="http://www.w3.org/XML/1998/namespace"
+ xmlns:xlink="http://www.w3.org/1999/xlink">
+ <defs
+ id="defs3">
+ <linearGradient
+ id="linearGradient830">
+ <stop
+ style="stop-color:#ebffff;stop-opacity:0.0000000;"
+ offset="0.0000000"
+ id="stop831" />
+ <stop
+ style="stop-color:#fff;stop-opacity:1;"
+ offset="1"
+ id="stop832" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient826">
+ <stop
+ style="stop-color:#000;stop-opacity:1;"
+ offset="0"
+ id="stop827" />
+ <stop
+ style="stop-color:#fff;stop-opacity:1;"
+ offset="1"
+ id="stop828" />
+ </linearGradient>
+ <linearGradient
+ xlink:href="#linearGradient830"
+ id="linearGradient829"
+ x1="1.5500000"
+ y1="0.52343750"
+ x2="0.20422535"
+ y2="-0.12195122"
+ spreadMethod="reflect" />
+ <linearGradient
+ xlink:href="#linearGradient830"
+ id="linearGradient834"
+ x1="-0.31159419"
+ y1="0.19531250"
+ x2="0.77536231"
+ y2="0.94531250" />
+ <linearGradient
+ xlink:href="#linearGradient830"
+ id="linearGradient836" />
+ </defs>
+ <sodipodi:namedview
+ id="base"
+ pagecolor="#ffffff"
+ bordercolor="#666666"
+ borderopacity="1.0"
+ inkscape:pageopacity="0.0"
+ inkscape:pageshadow="2"
+ inkscape:zoom="22.6274170"
+ inkscape:cx="13.7972814"
+ inkscape:cy="11.3558311"
+ inkscape:window-width="1016"
+ inkscape:window-height="693"
+ gridspacingy="1.0000000pt"
+ gridspacingx="1.0000000pt"
+ gridtolerance="1.0000000px"
+ inkscape:window-x="0"
+ inkscape:window-y="0"
+ showgrid="true" />
+ <rect
+ style="font-size:12;fill:#ffff00;fill-rule:evenodd;stroke:#ff0000;stroke-width:1.227;"
+ id="rect837"
+ width="26.22858411"
+ height="18.73091698"
+ x="0.68923926"
+ y="4.44105864" />
+ <rect
+ style="font-size:12;fill:url(#linearGradient829);fill-opacity:0.75;fill-rule:evenodd;stroke-width:0.456527pt;"
+ id="rect825"
+ width="24.90570598"
+ height="9.89791008"
+ ry="0"
+ x="1.33175063"
+ y="5.06444607" />
+ <text
+ xml:space="preserve"
+ style="font-size:12;font-weight:bold;font-stretch:normal;stroke-width:1pt;font-family:Bitstream Vera Sans Mono;text-anchor:middle;font-style:normal;writing-mode:lr;"
+ x="15.8012514"
+ y="19.6672548"
+ id="text838"
+ transform="scale(0.882660,0.446496)"
+ sodipodi:linespacing="100%"><tspan
+ x="15.8012514"
+ y="19.6672554"
+ sodipodi:role="line"
+ id="tspan943">«xy»</tspan><tspan
+ x="15.8012514"
+ y="31.6672554"
+ sodipodi:role="line"
+ id="tspan945">ABC</tspan></text>
+ <path
+ style="font-size:12;fill:none;fill-opacity:0.75;fill-rule:evenodd;stroke:#ff0000;stroke-width:1.25;"
+ d="M 0.84533027 15.610254 L 26.618236 15.610254 "
+ id="path845" />
+ <rect
+ style="font-size:12;fill:url(#linearGradient829);fill-opacity:0.75;fill-rule:evenodd;stroke-width:0.456527pt;"
+ id="rect846"
+ width="25.07143413"
+ height="6.13441568"
+ ry="0"
+ x="1.29826760"
+ y="16.29058838" />
+ <rect
+ style="fill:url(#linearGradient829);fill-opacity:0.75000000;fill-rule:evenodd;stroke:none;stroke-width:0.45652742pt;stroke-opacity:1.0000000;"
+ id="rect847"
+ width="135.18759"
+ height="47.111610"
+ ry="0.0000000"
+ x="175.11363"
+ y="-1.7772827" />
+</svg>
diff --git a/umbrello/umbrello/pics/sources/join.svg b/umbrello/umbrello/pics/sources/join.svg
new file mode 100644
index 00000000..9bdd1f88
--- /dev/null
+++ b/umbrello/umbrello/pics/sources/join.svg
@@ -0,0 +1,175 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+<svg
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://web.resource.org/cc/"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:sodipodi="http://inkscape.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ inkscape:export-ydpi="90.000000"
+ inkscape:export-xdpi="90.000000"
+ inkscape:export-filename="F:\pics\join.png"
+ sodipodi:docbase="F:\pics"
+ sodipodi:docname="join.svg"
+ inkscape:version="0.40+cvs"
+ sodipodi:version="0.32"
+ version="1.0"
+ x="0.00000000"
+ y="0.00000000"
+ width="22.000000px"
+ height="22.000000px"
+ id="svg1">
+ <metadata
+ id="metadata39">
+ <rdf:RDF
+ id="RDF40">
+ <cc:Work
+ id="Work41"
+ rdf:about="">
+ <dc:format
+ id="format42">image/svg+xml</dc:format>
+ <dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage"
+ id="type43" />
+ </cc:Work>
+ </rdf:RDF>
+ </metadata>
+ <sodipodi:namedview
+ inkscape:current-layer="svg1"
+ inkscape:window-y="134"
+ inkscape:window-x="1483"
+ inkscape:cy="11.000000"
+ inkscape:cx="11.000000"
+ inkscape:zoom="23.500000"
+ inkscape:window-height="691"
+ inkscape:window-width="1035"
+ inkscape:pageshadow="2"
+ inkscape:pageopacity="0.0"
+ borderopacity="1.0"
+ bordercolor="#666666"
+ pagecolor="#ffffff"
+ id="base" />
+ <defs
+ id="defs3">
+ <marker
+ inkscape:stockid="Arrow2Mend"
+ orient="auto"
+ refY="0.0"
+ refX="0.0"
+ id="marker226"
+ style="overflow:visible;">
+ <path
+ sodipodi:nodetypes="cccc"
+ id="path227"
+ style="font-size:12.0;fill-rule:evenodd;stroke-width:0.62500000;stroke-linejoin:round;"
+ d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.9730900,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z "
+ transform="scale(0.6) rotate(180) translate(-5,0)" />
+ </marker>
+ <marker
+ inkscape:stockid="Arrow2Mend"
+ orient="auto"
+ refY="0.0"
+ refX="0.0"
+ id="marker224"
+ style="overflow:visible;">
+ <path
+ sodipodi:nodetypes="cccc"
+ id="path225"
+ style="font-size:12.0;fill-rule:evenodd;stroke-width:0.62500000;stroke-linejoin:round;"
+ d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.9730900,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z "
+ transform="scale(0.6) rotate(180) translate(-5,0)" />
+ </marker>
+ <marker
+ inkscape:stockid="Arrow2Mend"
+ orient="auto"
+ refY="0.0"
+ refX="0.0"
+ id="marker222"
+ style="overflow:visible;">
+ <path
+ sodipodi:nodetypes="cccc"
+ id="path223"
+ style="font-size:12.0;fill-rule:evenodd;stroke-width:0.62500000;stroke-linejoin:round;"
+ d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.9730900,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z "
+ transform="scale(0.6) rotate(180) translate(-5,0)" />
+ </marker>
+ <marker
+ inkscape:stockid="Arrow2Mend"
+ orient="auto"
+ refY="0.0"
+ refX="0.0"
+ id="marker556"
+ style="overflow:visible;">
+ <path
+ sodipodi:nodetypes="cccc"
+ id="path557"
+ style="font-size:12.0;fill-rule:evenodd;stroke-width:0.62500000;stroke-linejoin:round;"
+ d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.9730900,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z "
+ transform="scale(0.6) rotate(180) translate(-5,0)" />
+ </marker>
+ <marker
+ inkscape:stockid="Arrow2Mend"
+ orient="auto"
+ refY="0.0"
+ refX="0.0"
+ id="marker553"
+ style="overflow:visible;">
+ <path
+ sodipodi:nodetypes="cccc"
+ id="path554"
+ style="font-size:12.0;fill-rule:evenodd;stroke-width:0.62500000;stroke-linejoin:round;"
+ d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.9730900,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z "
+ transform="scale(0.6) rotate(180) translate(-5,0)" />
+ </marker>
+ <marker
+ inkscape:stockid="Arrow2Mend"
+ orient="auto"
+ refY="0.0"
+ refX="0.0"
+ id="Arrow2Mend"
+ style="overflow:visible;">
+ <path
+ sodipodi:nodetypes="cccc"
+ id="path454"
+ style="font-size:12.0;fill-rule:evenodd;stroke-width:0.62500000;stroke-linejoin:round;"
+ d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.9730900,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z "
+ transform="scale(0.6) rotate(180) translate(-5,0)" />
+ </marker>
+ <marker
+ inkscape:stockid="Arrow2Lend"
+ orient="auto"
+ refY="0.0"
+ refX="0.0"
+ id="Arrow2Lend"
+ style="overflow:visible;">
+ <path
+ sodipodi:nodetypes="cccc"
+ id="path455"
+ style="font-size:12.0;fill-rule:evenodd;stroke-width:0.62500000;stroke-linejoin:round;"
+ d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.9730900,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z "
+ transform="scale(1.1) rotate(180) translate(-5,0)" />
+ </marker>
+ </defs>
+ <g
+ transform="translate(-383.5096,-519.0587)"
+ id="g221">
+ <path
+ style="fill:none;fill-opacity:0.75000000;fill-rule:evenodd;stroke:#000000;stroke-width:2.0250001;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:4.0000000;stroke-opacity:1.0000000"
+ d="M 394.53323,522.08766 C 394.54111,537.47668 394.54111,537.47668 394.54111,537.47668 L 394.54111,537.47668"
+ id="path15" />
+ <path
+ style="fill:none;fill-opacity:0.75000000;fill-rule:evenodd;stroke:#000000;stroke-width:0.60290909px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1.0000000;marker-start:none;marker-mid:none;marker-end:url(#Arrow2Mend)"
+ d="M 396.01872,530.08052 L 401.76288,530.08052"
+ id="path16" />
+ <path
+ style="fill:none;fill-opacity:0.75000000;fill-rule:evenodd;stroke:#000000;stroke-width:0.60290909px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1.0000000;marker-start:none;marker-mid:none;marker-end:url(#Arrow2Mend)"
+ d="M 384.83078,534.45617 L 390.57494,534.45617"
+ id="path555" />
+ <path
+ style="fill:none;fill-opacity:0.75000000;fill-rule:evenodd;stroke:#000000;stroke-width:0.60290909px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1.0000000;marker-start:none;marker-mid:none;marker-end:url(#Arrow2Mend)"
+ d="M 384.83078,524.85406 L 390.57494,524.85406"
+ id="path558" />
+ </g>
+</svg>
diff --git a/umbrello/umbrello/pics/sources/junction.svg b/umbrello/umbrello/pics/sources/junction.svg
new file mode 100644
index 00000000..98ef166d
--- /dev/null
+++ b/umbrello/umbrello/pics/sources/junction.svg
@@ -0,0 +1,256 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+<svg
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://web.resource.org/cc/"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:sodipodi="http://inkscape.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ sodipodi:docbase="F:\pics"
+ sodipodi:docname="junction.svg"
+ inkscape:version="0.40+cvs"
+ sodipodi:version="0.32"
+ version="1.0"
+ x="0.00000000"
+ y="0.00000000"
+ width="22.000000px"
+ height="22.000000px"
+ id="svg1">
+ <metadata
+ id="metadata17">
+ <rdf:RDF
+ id="RDF18">
+ <cc:Work
+ id="Work19"
+ rdf:about="">
+ <dc:format
+ id="format20">image/svg+xml</dc:format>
+ <dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage"
+ id="type21" />
+ </cc:Work>
+ </rdf:RDF>
+ </metadata>
+ <sodipodi:namedview
+ inkscape:current-layer="svg1"
+ inkscape:window-y="511"
+ inkscape:window-x="2276"
+ inkscape:cy="11.000000"
+ inkscape:cx="11.000000"
+ inkscape:zoom="18.409091"
+ inkscape:window-height="579"
+ inkscape:window-width="692"
+ inkscape:pageshadow="2"
+ inkscape:pageopacity="0.0"
+ borderopacity="1.0"
+ bordercolor="#666666"
+ pagecolor="#ffffff"
+ id="base" />
+ <defs
+ id="defs3">
+ <marker
+ inkscape:stockid="Arrow2Mend"
+ orient="auto"
+ refY="0.0"
+ refX="0.0"
+ id="marker237"
+ style="overflow:visible;">
+ <path
+ sodipodi:nodetypes="cccc"
+ id="path239"
+ style="font-size:12.0;fill-rule:evenodd;stroke-width:0.62500000;stroke-linejoin:round;"
+ d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.9730900,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z "
+ transform="scale(0.6) rotate(180) translate(-5,0)" />
+ </marker>
+ <marker
+ inkscape:stockid="Arrow2Mend"
+ orient="auto"
+ refY="0.0"
+ refX="0.0"
+ id="marker235"
+ style="overflow:visible;">
+ <path
+ sodipodi:nodetypes="cccc"
+ id="path236"
+ style="font-size:12.0;fill-rule:evenodd;stroke-width:0.62500000;stroke-linejoin:round;"
+ d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.9730900,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z "
+ transform="scale(0.6) rotate(180) translate(-5,0)" />
+ </marker>
+ <marker
+ inkscape:stockid="Arrow2Mend"
+ orient="auto"
+ refY="0.0"
+ refX="0.0"
+ id="marker233"
+ style="overflow:visible;">
+ <path
+ sodipodi:nodetypes="cccc"
+ id="path234"
+ style="font-size:12.0;fill-rule:evenodd;stroke-width:0.62500000;stroke-linejoin:round;"
+ d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.9730900,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z "
+ transform="scale(0.6) rotate(180) translate(-5,0)" />
+ </marker>
+ <marker
+ inkscape:stockid="Arrow2Mend"
+ orient="auto"
+ refY="0.0"
+ refX="0.0"
+ id="marker231"
+ style="overflow:visible;">
+ <path
+ sodipodi:nodetypes="cccc"
+ id="path232"
+ style="font-size:12.0;fill-rule:evenodd;stroke-width:0.62500000;stroke-linejoin:round;"
+ d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.9730900,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z "
+ transform="scale(0.6) rotate(180) translate(-5,0)" />
+ </marker>
+ <marker
+ inkscape:stockid="Arrow2Mend"
+ orient="auto"
+ refY="0.0"
+ refX="0.0"
+ id="marker229"
+ style="overflow:visible;">
+ <path
+ sodipodi:nodetypes="cccc"
+ id="path230"
+ style="font-size:12.0;fill-rule:evenodd;stroke-width:0.62500000;stroke-linejoin:round;"
+ d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.9730900,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z "
+ transform="scale(0.6) rotate(180) translate(-5,0)" />
+ </marker>
+ <marker
+ inkscape:stockid="Arrow2Mend"
+ orient="auto"
+ refY="0.0"
+ refX="0.0"
+ id="marker1"
+ style="overflow:visible;">
+ <path
+ sodipodi:nodetypes="cccc"
+ id="path2"
+ style="font-size:12.0;fill-rule:evenodd;stroke-width:0.62500000;stroke-linejoin:round;"
+ d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.9730900,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z "
+ transform="scale(0.6) rotate(180) translate(-5,0)" />
+ </marker>
+ <marker
+ inkscape:stockid="Arrow2Mend"
+ orient="auto"
+ refY="0.0"
+ refX="0.0"
+ id="Arrow2Mend"
+ style="overflow:visible;">
+ <path
+ sodipodi:nodetypes="cccc"
+ id="path237"
+ style="font-size:12.0;fill-rule:evenodd;stroke-width:0.62500000;stroke-linejoin:round;"
+ d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.9730900,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z "
+ transform="scale(0.6) rotate(180) translate(-5,0)" />
+ </marker>
+ <marker
+ inkscape:stockid="Arrow2Lend"
+ orient="auto"
+ refY="0.0"
+ refX="0.0"
+ id="marker258"
+ style="overflow:visible;">
+ <path
+ sodipodi:nodetypes="cccc"
+ id="path259"
+ style="font-size:12.0;fill-rule:evenodd;stroke-width:0.62500000;stroke-linejoin:round;"
+ d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.9730900,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z "
+ transform="scale(1.1) rotate(180) translate(-5,0)" />
+ </marker>
+ <marker
+ inkscape:stockid="Arrow2Lend"
+ orient="auto"
+ refY="0.0"
+ refX="0.0"
+ id="marker255"
+ style="overflow:visible;">
+ <path
+ sodipodi:nodetypes="cccc"
+ id="path256"
+ style="font-size:12.0;fill-rule:evenodd;stroke-width:0.62500000;stroke-linejoin:round;"
+ d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.9730900,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z "
+ transform="scale(1.1) rotate(180) translate(-5,0)" />
+ </marker>
+ <marker
+ inkscape:stockid="Arrow2Lend"
+ orient="auto"
+ refY="0.0"
+ refX="0.0"
+ id="marker252"
+ style="overflow:visible;">
+ <path
+ sodipodi:nodetypes="cccc"
+ id="path253"
+ style="font-size:12.0;fill-rule:evenodd;stroke-width:0.62500000;stroke-linejoin:round;"
+ d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.9730900,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z "
+ transform="scale(1.1) rotate(180) translate(-5,0)" />
+ </marker>
+ <marker
+ inkscape:stockid="Arrow2Lend"
+ orient="auto"
+ refY="0.0"
+ refX="0.0"
+ id="marker249"
+ style="overflow:visible;">
+ <path
+ sodipodi:nodetypes="cccc"
+ id="path250"
+ style="font-size:12.0;fill-rule:evenodd;stroke-width:0.62500000;stroke-linejoin:round;"
+ d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.9730900,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z "
+ transform="scale(1.1) rotate(180) translate(-5,0)" />
+ </marker>
+ <marker
+ inkscape:stockid="Arrow2Lend"
+ orient="auto"
+ refY="0.0"
+ refX="0.0"
+ id="Arrow2Lend"
+ style="overflow:visible;">
+ <path
+ sodipodi:nodetypes="cccc"
+ id="path238"
+ style="font-size:12.0;fill-rule:evenodd;stroke-width:0.62500000;stroke-linejoin:round;"
+ d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.9730900,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z "
+ transform="scale(1.1) rotate(180) translate(-5,0)" />
+ </marker>
+ </defs>
+ <g
+ transform="translate(-383.5432,-518.5878)"
+ id="g228">
+ <path
+ transform="translate(-0.668501,-2.243091)"
+ d="M 398.73051 531.23523 A 3.5248239 3.5248239 0 1 1 391.68086,531.23523 A 3.5248239 3.5248239 0 1 1 398.73051 531.23523 z"
+ sodipodi:ry="3.5248239"
+ sodipodi:rx="3.5248239"
+ sodipodi:cy="531.23523"
+ sodipodi:cx="395.20569"
+ id="path45"
+ style="fill:#000000;fill-opacity:1.0000000;stroke:none;stroke-width:0.20000000;stroke-miterlimit:4.0000000;stroke-opacity:0.68161434"
+ sodipodi:type="arc" />
+ <path
+ id="path134"
+ d="M 386.54045,519.66500 L 390.14727,524.34150"
+ style="fill:none;fill-opacity:0.75000000;fill-rule:evenodd;stroke:#000000;stroke-width:0.61250001;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4.0000000;stroke-opacity:1.0000000;marker-end:url(#Arrow2Mend)" />
+ <path
+ id="path251"
+ d="M 402.60019,519.65950 L 398.99337,524.33600"
+ style="fill:none;fill-opacity:0.75000000;fill-rule:evenodd;stroke:#000000;stroke-width:0.61250001;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4.0000000;stroke-opacity:1.0000000;marker-end:url(#Arrow2Mend)" />
+ <path
+ id="path254"
+ d="M 394.57026,531.49266 L 394.66966,537.39766"
+ style="fill:none;fill-opacity:0.75000000;fill-rule:evenodd;stroke:#000000;stroke-width:0.61250001;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4.0000000;stroke-opacity:1.0000000;marker-end:url(#Arrow2Mend)" />
+ <path
+ id="path260"
+ d="M 396.98786,531.45492 L 400.59468,536.13142"
+ style="fill:none;fill-opacity:0.75000000;fill-rule:evenodd;stroke:#000000;stroke-width:0.61250001;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4.0000000;stroke-opacity:1.0000000;marker-end:url(#Arrow2Mend)" />
+ <path
+ id="path435"
+ d="M 392.59468,531.45492 L 388.98786,536.13142"
+ style="fill:none;fill-opacity:0.75000000;fill-rule:evenodd;stroke:#000000;stroke-width:0.61250001;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4.0000000;stroke-opacity:1.0000000;marker-end:url(#Arrow2Mend)" />
+ </g>
+</svg>
diff --git a/umbrello/umbrello/pics/sources/message-asynchronous.svg b/umbrello/umbrello/pics/sources/message-asynchronous.svg
new file mode 100644
index 00000000..7bb8054e
--- /dev/null
+++ b/umbrello/umbrello/pics/sources/message-asynchronous.svg
@@ -0,0 +1,133 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 20010904//EN"
+"http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd">
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+<svg
+ id="svg1"
+ sodipodi:version="0.32"
+ inkscape:version="0.37"
+ width="22pt"
+ height="22pt"
+ sodipodi:docbase="/home/jr/tmp/umbrello/icons/inkscape-svg"
+ sodipodi:docname="asynchro.svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:xml="http://www.w3.org/XML/1998/namespace"
+ xmlns:xlink="http://www.w3.org/1999/xlink">
+ <defs
+ id="defs3">
+ <linearGradient
+ id="linearGradient868">
+ <stop
+ style="stop-color:#ffffff;stop-opacity:0.0000000;"
+ offset="0.0000000"
+ id="stop869" />
+ <stop
+ style="stop-color:#fff;stop-opacity:1;"
+ offset="1"
+ id="stop870" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient893">
+ <stop
+ style="stop-color:#19839a;stop-opacity:0.0000000;"
+ offset="0.0000000"
+ id="stop894" />
+ <stop
+ style="stop-color:#fff;stop-opacity:1;"
+ offset="1"
+ id="stop895" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient830">
+ <stop
+ style="stop-color:#ebffff;stop-opacity:0.0000000;"
+ offset="0.0000000"
+ id="stop831" />
+ <stop
+ style="stop-color:#fff;stop-opacity:1;"
+ offset="1"
+ id="stop832" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient826">
+ <stop
+ style="stop-color:#000;stop-opacity:1;"
+ offset="0"
+ id="stop827" />
+ <stop
+ style="stop-color:#fff;stop-opacity:1;"
+ offset="1"
+ id="stop828" />
+ </linearGradient>
+ <linearGradient
+ xlink:href="#linearGradient830"
+ id="linearGradient829"
+ x1="1.5500000"
+ y1="0.52343750"
+ x2="0.20422535"
+ y2="-0.12195122"
+ spreadMethod="reflect" />
+ <linearGradient
+ xlink:href="#linearGradient830"
+ id="linearGradient834"
+ x1="-0.31159419"
+ y1="0.19531250"
+ x2="0.77536231"
+ y2="0.94531250" />
+ <linearGradient
+ xlink:href="#linearGradient830"
+ id="linearGradient836" />
+ <linearGradient
+ xlink:href="#linearGradient868"
+ id="linearGradient892"
+ x1="-0.49264705"
+ y1="0.43750000"
+ x2="0.022058824"
+ y2="0.92187500" />
+ </defs>
+ <sodipodi:namedview
+ id="base"
+ pagecolor="#ffffff"
+ bordercolor="#666666"
+ borderopacity="1.0"
+ inkscape:pageopacity="0.0"
+ inkscape:pageshadow="2"
+ inkscape:zoom="22.6274169"
+ inkscape:cx="12.5595019"
+ inkscape:cy="9.96780389"
+ inkscape:window-width="1016"
+ inkscape:window-height="693"
+ gridspacingy="1.0000000pt"
+ gridspacingx="1.0000000pt"
+ gridtolerance="1.0000000px"
+ inkscape:window-x="0"
+ inkscape:window-y="0"
+ showgrid="true" />
+ <path
+ style="font-size:12;fill:url(#linearGradient892);fill-rule:evenodd;stroke-width:12.5;"
+ d="M 23.25456 20.532266 L 17.245615 18.773952 L 17.395532 22.409137 L 23.25456 20.532266 z "
+ id="path875"
+ sodipodi:nodetypes="cccc" />
+ <text
+ xml:space="preserve"
+ style="font-size:12;font-weight:normal;stroke-width:1pt;font-family:Bitstream Vera Sans;"
+ x="-0.14150786"
+ y="14.0554683"
+ id="text1033"
+ transform="scale(1.409838,1.034795)"><tspan
+ id="tspan1034">f(x)</tspan></text>
+ <rect
+ style="font-size:12;fill:#ff0000;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1pt;"
+ id="rect923"
+ width="16.51757205"
+ height="1.32582528"
+ x="-0.05524272"
+ y="20.04223250" />
+ <path
+ style="font-size:12;fill:#ffff00;fill-rule:evenodd;stroke:#ff0000;stroke-width:1.14332;"
+ d="M 25.48674 20.457131 L 16.806844 18.331919 L 16.858498 23.071545 L 25.48674 20.457131 z "
+ id="path874"
+ sodipodi:nodetypes="cccc" />
+</svg>
diff --git a/umbrello/umbrello/pics/sources/message-synchronous.svg b/umbrello/umbrello/pics/sources/message-synchronous.svg
new file mode 100644
index 00000000..098a56b5
--- /dev/null
+++ b/umbrello/umbrello/pics/sources/message-synchronous.svg
@@ -0,0 +1,169 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 20010904//EN"
+"http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd">
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+<svg
+ id="svg1"
+ sodipodi:version="0.32"
+ inkscape:version="0.38.1"
+ width="128.00000pt"
+ height="128.00000pt"
+ sodipodi:docbase="/home/bartkozoltan/Documents/work/umbrello/new pics"
+ sodipodi:docname="synchro.svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:xml="http://www.w3.org/XML/1998/namespace"
+ xmlns:xlink="http://www.w3.org/1999/xlink">
+ <defs
+ id="defs3">
+ <linearGradient
+ id="linearGradient868">
+ <stop
+ style="stop-color:#ffffff;stop-opacity:0.0000000;"
+ offset="0.0000000"
+ id="stop869" />
+ <stop
+ style="stop-color:#fff;stop-opacity:1;"
+ offset="1"
+ id="stop870" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient893">
+ <stop
+ style="stop-color:#19839a;stop-opacity:0.0000000;"
+ offset="0.0000000"
+ id="stop894" />
+ <stop
+ style="stop-color:#fff;stop-opacity:1;"
+ offset="1"
+ id="stop895" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient830">
+ <stop
+ style="stop-color:#ebffff;stop-opacity:0.0000000;"
+ offset="0.0000000"
+ id="stop831" />
+ <stop
+ style="stop-color:#fff;stop-opacity:1;"
+ offset="1"
+ id="stop832" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient826">
+ <stop
+ style="stop-color:#000;stop-opacity:1;"
+ offset="0"
+ id="stop827" />
+ <stop
+ style="stop-color:#fff;stop-opacity:1;"
+ offset="1"
+ id="stop828" />
+ </linearGradient>
+ <linearGradient
+ xlink:href="#linearGradient830"
+ id="linearGradient829"
+ x1="1.5500000"
+ y1="0.52343750"
+ x2="0.20422535"
+ y2="-0.12195122"
+ spreadMethod="reflect" />
+ <linearGradient
+ xlink:href="#linearGradient830"
+ id="linearGradient834"
+ x1="-0.31159419"
+ y1="0.19531250"
+ x2="0.77536231"
+ y2="0.94531250" />
+ <linearGradient
+ xlink:href="#linearGradient830"
+ id="linearGradient836" />
+ <linearGradient
+ xlink:href="#linearGradient868"
+ id="linearGradient892"
+ x1="-0.49264705"
+ y1="0.43750000"
+ x2="0.72477067"
+ y2="1.3515625" />
+ <linearGradient
+ xlink:href="#linearGradient868"
+ id="linearGradient903" />
+ <linearGradient
+ xlink:href="#linearGradient868"
+ id="linearGradient905"
+ x1="-0.49264705"
+ y1="0.43750000"
+ x2="0.21100917"
+ y2="1.1328125" />
+ </defs>
+ <sodipodi:namedview
+ id="base"
+ pagecolor="#ffffff"
+ bordercolor="#666666"
+ borderopacity="1.0"
+ inkscape:pageopacity="0.0"
+ inkscape:pageshadow="2"
+ inkscape:zoom="4.0000000"
+ inkscape:cx="79.132812"
+ inkscape:cy="64.126236"
+ inkscape:window-width="1022"
+ inkscape:window-height="701"
+ gridspacingy="1.0000000pt"
+ gridspacingx="1.0000000pt"
+ gridtolerance="1.0000000px"
+ inkscape:window-x="0"
+ inkscape:window-y="0" />
+ <path
+ style="fill:none;fill-opacity:0.75000000;fill-rule:evenodd;stroke:#ff0000;stroke-width:6.3214993;stroke-dashoffset:0.0000000;"
+ d="M 7.4009479,65.202546 L 101.77436,65.315532"
+ id="path861"
+ sodipodi:nodetypes="cc" />
+ <path
+ style="fill:#ff0000;fill-rule:evenodd;stroke:#ff0000;stroke-width:4.7256370;fill-opacity:1.0000000;"
+ d="M 107.13596,64.029793 L 72.687667,54.881453 L 72.892707,75.283958 L 107.13596,64.029793 z "
+ id="path874"
+ sodipodi:nodetypes="cccc" />
+ <path
+ style="fill:url(#linearGradient905);fill-rule:evenodd;stroke-width:12.500000;"
+ d="M 98.388232,64.426032 L 74.840062,57.679774 L 75.427563,71.627168 L 98.388232,64.426032 z "
+ id="path875"
+ sodipodi:nodetypes="cccc" />
+ <text
+ xml:space="preserve"
+ style="font-size:12.000000;stroke-width:1.0000000pt;font-family:Bitstream Vera Sans;"
+ x="1.6763363"
+ y="11.255447"
+ id="text1033"
+ transform="scale(6.321334,3.689577)"><tspan
+ id="tspan1034">f(x)</tspan></text>
+ <rect
+ style="fill:#ffff00;fill-opacity:1.0000000;fill-rule:evenodd;stroke:#ff0000;stroke-width:5.0000000;stroke-dasharray:none;stroke-opacity:1.0000000;"
+ id="rect899"
+ width="29.375000"
+ height="74.574653"
+ x="115.93750"
+ y="62.400174" />
+ <path
+ style="fill:none;fill-opacity:0.75000000;fill-rule:evenodd;stroke:#ff0000;stroke-width:6.3214993;stroke-dashoffset:0.0000000;stroke-dasharray:12.642999,6.3214993;"
+ d="M 109.15604,135.11984 L 14.782623,135.23283"
+ id="path900"
+ sodipodi:nodetypes="cc" />
+ <path
+ style="fill:#ff0000;fill-rule:evenodd;stroke:#ff0000;stroke-width:4.7256370;fill-opacity:1.0000000;"
+ d="M 9.4210230,133.94709 L 43.869316,124.79875 L 43.664276,145.20126 L 9.4210230,133.94709 z "
+ id="path901"
+ sodipodi:nodetypes="cccc" />
+ <path
+ style="fill:url(#linearGradient892);fill-rule:evenodd;stroke-width:12.500000;"
+ d="M 18.168751,134.34333 L 41.716921,127.59707 L 41.129420,141.54447 L 18.168751,134.34333 z "
+ id="path902"
+ sodipodi:nodetypes="cccc" />
+ <rect
+ style="fill:url(#linearGradient903);fill-opacity:1.0000000;fill-rule:evenodd;stroke:none;stroke-width:5.0000000;stroke-dasharray:none;stroke-opacity:1.0000000;"
+ id="rect904"
+ width="25.000000"
+ height="69.574654"
+ x="117.50000"
+ y="65.212677" />
+</svg>
diff --git a/umbrello/umbrello/pics/sources/node.svg b/umbrello/umbrello/pics/sources/node.svg
new file mode 100644
index 00000000..ee76129a
--- /dev/null
+++ b/umbrello/umbrello/pics/sources/node.svg
@@ -0,0 +1,114 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 20010904//EN"
+"http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd">
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+<svg
+ id="svg1"
+ sodipodi:version="0.32"
+ inkscape:version="0.37"
+ width="22pt"
+ height="22pt"
+ sodipodi:docbase="/home/jr/tmp/umbrello/icons/inkscape-svg"
+ sodipodi:docname="node.svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:xml="http://www.w3.org/XML/1998/namespace"
+ xmlns:xlink="http://www.w3.org/1999/xlink">
+ <defs
+ id="defs3">
+ <linearGradient
+ id="linearGradient830">
+ <stop
+ style="stop-color:#ebffff;stop-opacity:0.0000000;"
+ offset="0.0000000"
+ id="stop831" />
+ <stop
+ style="stop-color:#fff;stop-opacity:1;"
+ offset="1"
+ id="stop832" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient826">
+ <stop
+ style="stop-color:#000;stop-opacity:1;"
+ offset="0"
+ id="stop827" />
+ <stop
+ style="stop-color:#fff;stop-opacity:1;"
+ offset="1"
+ id="stop828" />
+ </linearGradient>
+ <linearGradient
+ xlink:href="#linearGradient830"
+ id="linearGradient829"
+ x1="1.5500000"
+ y1="0.52343750"
+ x2="0.20422535"
+ y2="-0.12195122"
+ spreadMethod="reflect" />
+ <linearGradient
+ xlink:href="#linearGradient830"
+ id="linearGradient834"
+ x1="-0.31159419"
+ y1="0.19531250"
+ x2="0.77536231"
+ y2="0.94531250" />
+ <linearGradient
+ xlink:href="#linearGradient830"
+ id="linearGradient836" />
+ </defs>
+ <sodipodi:namedview
+ id="base"
+ pagecolor="#ffffff"
+ bordercolor="#666666"
+ borderopacity="1.0"
+ inkscape:pageopacity="0.0"
+ inkscape:pageshadow="2"
+ inkscape:zoom="22.6274170"
+ inkscape:cx="8.96789045"
+ inkscape:cy="11.0305950"
+ inkscape:window-width="1016"
+ inkscape:window-height="693"
+ gridspacingy="1.0000000pt"
+ gridspacingx="1.0000000pt"
+ gridtolerance="1.0000000px"
+ inkscape:window-x="0"
+ inkscape:window-y="0"
+ showgrid="true" />
+ <path
+ style="font-size:12;fill:#ffff00;fill-rule:evenodd;stroke:#ff0000;stroke-width:1.21561;"
+ d="M 10.627136 0.70957548 L 0.95934281 8.1782719 L 18.381224 8.3835186 L 26.830203 0.65256253 L 18.403285 8.8168169 L 18.403285 26.850013 L 26.929473 19.66068 L 26.835718 0.6867703 L 10.627136 0.70957548 z M 0.4850529 8.6343755 L 0.70565286 26.895623 L 18.259895 26.895623 L 18.259895 8.8624273 L 0.4850529 8.6343755 z "
+ id="path942"
+ sodipodi:nodetypes="cccccccccccccc" />
+ <rect
+ style="font-size:12;fill:url(#linearGradient829);fill-opacity:0.75;fill-rule:evenodd;stroke-width:0.456527pt;"
+ id="rect825"
+ width="16.51280659"
+ height="16.97894525"
+ ry="0"
+ x="1.10901392"
+ y="9.30482388" />
+ <path
+ style="font-size:12;fill:url(#linearGradient829);fill-opacity:0.75;fill-rule:evenodd;stroke-width:0.456527pt;"
+ d="M 18.887334 9.2865065 L 19.01291 25.592705 L 26.288674 19.298496 L 26.263384 2.0156589 L 18.887334 9.2865065 z "
+ id="path944"
+ sodipodi:nodetypes="ccccc" />
+ <path
+ style="font-size:12;fill:url(#linearGradient829);fill-opacity:0.75;fill-rule:evenodd;stroke-width:0.456527pt;"
+ d="M 11.035012 1.2781133 L 2.8924094 7.5753492 L 18.102003 7.784321 L 25.13882 1.2781133 L 11.035012 1.2781133 z "
+ id="path946"
+ sodipodi:nodetypes="ccccc" />
+ <text
+ xml:space="preserve"
+ style="font-size:12;font-weight:bold;font-stretch:normal;stroke-width:1pt;font-family:Bitstream Vera Sans Mono;font-style:normal;text-anchor:start;writing-mode:lr;"
+ x="2.47432498"
+ y="22.8059085"
+ id="text838"
+ transform="scale(0.963354,0.987729)"
+ sodipodi:linespacing="100%"><tspan
+ x="2.47432494"
+ y="22.8059082"
+ sodipodi:role="line"
+ id="tspan981">XY</tspan></text>
+</svg>
diff --git a/umbrello/umbrello/pics/sources/note.svg b/umbrello/umbrello/pics/sources/note.svg
new file mode 100644
index 00000000..314d3026
--- /dev/null
+++ b/umbrello/umbrello/pics/sources/note.svg
@@ -0,0 +1,164 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 20010904//EN"
+"http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd">
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+<svg
+ id="svg1"
+ sodipodi:version="0.32"
+ inkscape:version="0.37"
+ width="22pt"
+ height="22pt"
+ sodipodi:docbase="/home/jr/tmp/umbrello/icons/inkscape-svg"
+ sodipodi:docname="note.svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:xml="http://www.w3.org/XML/1998/namespace"
+ xmlns:xlink="http://www.w3.org/1999/xlink">
+ <defs
+ id="defs3">
+ <linearGradient
+ id="linearGradient1796">
+ <stop
+ style="stop-color:#ffff21;stop-opacity:0.0000000;"
+ offset="0.0000000"
+ id="stop1797" />
+ <stop
+ style="stop-color:#fff;stop-opacity:1;"
+ offset="1"
+ id="stop1798" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient1763">
+ <stop
+ style="stop-color:#ffff21;stop-opacity:0.0000000;"
+ offset="0.0000000"
+ id="stop1764" />
+ <stop
+ style="stop-color:#fff;stop-opacity:1;"
+ offset="1"
+ id="stop1765" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient830">
+ <stop
+ style="stop-color:#ebffff;stop-opacity:0.0000000;"
+ offset="0.0000000"
+ id="stop831" />
+ <stop
+ style="stop-color:#fff;stop-opacity:1;"
+ offset="1"
+ id="stop832" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient826">
+ <stop
+ style="stop-color:#000;stop-opacity:1;"
+ offset="0"
+ id="stop827" />
+ <stop
+ style="stop-color:#fff;stop-opacity:1;"
+ offset="1"
+ id="stop828" />
+ </linearGradient>
+ <linearGradient
+ xlink:href="#linearGradient830"
+ id="linearGradient829"
+ x1="1.5500000"
+ y1="0.52343750"
+ x2="0.20422535"
+ y2="-0.12195122"
+ spreadMethod="reflect" />
+ <linearGradient
+ xlink:href="#linearGradient830"
+ id="linearGradient834"
+ x1="-0.31159419"
+ y1="0.19531250"
+ x2="0.77536231"
+ y2="0.94531250" />
+ <linearGradient
+ xlink:href="#linearGradient830"
+ id="linearGradient836" />
+ <linearGradient
+ xlink:href="#linearGradient1763"
+ id="linearGradient1762"
+ x1="-0.34579438"
+ y1="-0.16406250"
+ x2="0.71962619"
+ y2="0.80468750" />
+ <linearGradient
+ xlink:href="#linearGradient1796"
+ id="linearGradient1795"
+ x1="0.65555555"
+ y1="0.88281250"
+ x2="0.48888889"
+ y2="0.53906250"
+ spreadMethod="reflect" />
+ </defs>
+ <sodipodi:namedview
+ id="base"
+ pagecolor="#ffffff"
+ bordercolor="#666666"
+ borderopacity="1.0"
+ inkscape:pageopacity="0.0"
+ inkscape:pageshadow="2"
+ inkscape:zoom="22.6274169"
+ inkscape:cx="13.7972814"
+ inkscape:cy="11.4517668"
+ inkscape:window-width="1016"
+ inkscape:window-height="693"
+ gridspacingy="1.0000000pt"
+ gridspacingx="1.0000000pt"
+ gridtolerance="1.0000000px"
+ inkscape:window-x="0"
+ inkscape:window-y="0"
+ showgrid="true"
+ snaptogrid="false" />
+ <rect
+ style="fill:url(#linearGradient829);fill-opacity:0.75000000;fill-rule:evenodd;stroke-width:0.45652742pt;"
+ id="rect825"
+ width="137.68759"
+ height="66.465706"
+ ry="0.0000000"
+ x="359.81241"
+ y="197.28429" />
+ <rect
+ style="fill:url(#linearGradient829);fill-opacity:0.75000000;fill-rule:evenodd;stroke-width:0.45652742pt;"
+ id="rect846"
+ width="135.18759"
+ height="37.082668"
+ ry="0.0000000"
+ x="316.25000"
+ y="81.250000" />
+ <rect
+ style="fill:url(#linearGradient829);fill-opacity:0.75000000;fill-rule:evenodd;stroke:none;stroke-width:0.45652742pt;stroke-opacity:1.0000000;"
+ id="rect847"
+ width="135.18759"
+ height="47.111610"
+ ry="0.0000000"
+ x="255.00000"
+ y="157.88839" />
+ <path
+ style="font-size:12;fill:#f6f600;fill-rule:evenodd;stroke-width:5;"
+ d="M 8.2733326,28.387267 L 8.2733326,124.03331 L 149.01926,124.03331 L 149.01926,81.523954 C 150.50079,49.641942 119.72304,33.000935 97.500000,28.750000 L 8.2733326,28.387267 z "
+ id="path1780"
+ sodipodi:nodetypes="cccccc"
+ transform="matrix(0.188023,0.000000,0.000000,0.198158,-0.994639,-2.576479)" />
+ <path
+ style="font-size:12;fill:url(#linearGradient1762);fill-opacity:0.75;fill-rule:evenodd;stroke:#fb0000;stroke-width:1.24062;"
+ d="M 0.67142325 3.0486851 L 16.642354 3.119935 C 19.445037 2.8744034 25.794609 6.1829098 18.043695 10.731414 C 22.94839 10.240351 26.218186 9.0126933 26.918857 12.941199 L 26.969167 21.835986 L 0.67142325 21.835986 L 0.67142325 3.0486851 z "
+ id="path1781"
+ sodipodi:nodetypes="ccccccc" />
+ <text
+ xml:space="preserve"
+ style="font-size:12;font-weight:bold;font-stretch:normal;stroke-width:1pt;font-family:Bitstream Vera Sans Mono;text-anchor:middle;font-style:normal;writing-mode:lr;"
+ x="12.9370291"
+ y="23.9665241"
+ id="text838"
+ transform="scale(1.068059,0.832361)"
+ sodipodi:linespacing="100%"><tspan
+ x="12.9370289"
+ y="23.9665241"
+ sodipodi:role="line"
+ id="tspan1022">XYZ</tspan></text>
+</svg>
diff --git a/umbrello/umbrello/pics/sources/object.svg b/umbrello/umbrello/pics/sources/object.svg
new file mode 100644
index 00000000..184f6228
--- /dev/null
+++ b/umbrello/umbrello/pics/sources/object.svg
@@ -0,0 +1,110 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 20010904//EN"
+"http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd">
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+<svg
+ id="svg1"
+ sodipodi:version="0.32"
+ inkscape:version="0.37"
+ width="22pt"
+ height="22pt"
+ sodipodi:docbase="/home/jr/tmp/umbrello/icons/inkscape-svg"
+ sodipodi:docname="object.svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:xml="http://www.w3.org/XML/1998/namespace"
+ xmlns:xlink="http://www.w3.org/1999/xlink">
+ <defs
+ id="defs3">
+ <linearGradient
+ id="linearGradient830">
+ <stop
+ style="stop-color:#ebffff;stop-opacity:0.0000000;"
+ offset="0.0000000"
+ id="stop831" />
+ <stop
+ style="stop-color:#fff;stop-opacity:1;"
+ offset="1"
+ id="stop832" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient826">
+ <stop
+ style="stop-color:#000;stop-opacity:1;"
+ offset="0"
+ id="stop827" />
+ <stop
+ style="stop-color:#fff;stop-opacity:1;"
+ offset="1"
+ id="stop828" />
+ </linearGradient>
+ <linearGradient
+ xlink:href="#linearGradient830"
+ id="linearGradient829"
+ x1="1.5500000"
+ y1="0.52343750"
+ x2="0.20422535"
+ y2="-0.12195122"
+ spreadMethod="reflect" />
+ <linearGradient
+ xlink:href="#linearGradient830"
+ id="linearGradient834"
+ x1="-0.31159419"
+ y1="0.19531250"
+ x2="0.77536231"
+ y2="0.94531250" />
+ <linearGradient
+ xlink:href="#linearGradient830"
+ id="linearGradient836" />
+ </defs>
+ <sodipodi:namedview
+ id="base"
+ pagecolor="#ffffff"
+ bordercolor="#666666"
+ borderopacity="1.0"
+ inkscape:pageopacity="0.0"
+ inkscape:pageshadow="2"
+ inkscape:zoom="22.6274170"
+ inkscape:cx="13.7972814"
+ inkscape:cy="11.7392690"
+ inkscape:window-width="1016"
+ inkscape:window-height="693"
+ gridspacingy="1.0000000pt"
+ gridspacingx="1.0000000pt"
+ gridtolerance="1.0000000px"
+ inkscape:window-x="0"
+ inkscape:window-y="0"
+ showgrid="true" />
+ <rect
+ style="font-size:12;fill:#ffff00;fill-rule:evenodd;stroke:#ff0000;stroke-width:1.22029;"
+ id="rect837"
+ width="26.29639788"
+ height="16.16913223"
+ x="0.59771752"
+ y="5.66733170" />
+ <rect
+ style="font-size:12;fill:url(#linearGradient829);fill-opacity:0.75;fill-rule:evenodd;stroke-width:0.456527pt;"
+ id="rect825"
+ width="24.69446781"
+ height="14.49439839"
+ ry="0"
+ x="1.18516719"
+ y="6.32596101" />
+ <text
+ xml:space="preserve"
+ style="font-size:12;font-weight:bold;font-stretch:normal;stroke-width:1pt;font-family:Bitstream Vera Sans Mono;font-style:normal;text-anchor:start;writing-mode:lr;"
+ x="2.18484960"
+ y="19.2367096"
+ id="text838"
+ transform="scale(1.061648,0.843136)"
+ sodipodi:linespacing="100%"><tspan
+ x="2.18484950"
+ y="19.2367096"
+ sodipodi:role="line"
+ id="tspan1049">A:B</tspan></text>
+ <path
+ style="font-size:12;fill:none;fill-opacity:0.75;fill-rule:evenodd;stroke:#000000;stroke-width:0.836365;"
+ d="M 2.5317946 18.322741 L 25.019316 18.322741 "
+ id="path842" />
+</svg>
diff --git a/umbrello/umbrello/pics/sources/package.svg b/umbrello/umbrello/pics/sources/package.svg
new file mode 100644
index 00000000..bbfe4d43
--- /dev/null
+++ b/umbrello/umbrello/pics/sources/package.svg
@@ -0,0 +1,121 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 20010904//EN"
+"http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd">
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+<svg
+ id="svg1"
+ sodipodi:version="0.32"
+ inkscape:version="0.37"
+ width="22pt"
+ height="22pt"
+ sodipodi:docbase="/home/jr/tmp/umbrello/icons/inkscape-svg"
+ sodipodi:docname="package.svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:xml="http://www.w3.org/XML/1998/namespace"
+ xmlns:xlink="http://www.w3.org/1999/xlink">
+ <defs
+ id="defs3">
+ <linearGradient
+ id="linearGradient830">
+ <stop
+ style="stop-color:#ebffff;stop-opacity:0.0000000;"
+ offset="0.0000000"
+ id="stop831" />
+ <stop
+ style="stop-color:#fff;stop-opacity:1;"
+ offset="1"
+ id="stop832" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient826">
+ <stop
+ style="stop-color:#000;stop-opacity:1;"
+ offset="0"
+ id="stop827" />
+ <stop
+ style="stop-color:#fff;stop-opacity:1;"
+ offset="1"
+ id="stop828" />
+ </linearGradient>
+ <linearGradient
+ xlink:href="#linearGradient830"
+ id="linearGradient829"
+ x1="1.5500000"
+ y1="0.52343750"
+ x2="0.20422535"
+ y2="-0.12195122"
+ spreadMethod="reflect" />
+ <linearGradient
+ xlink:href="#linearGradient830"
+ id="linearGradient834"
+ x1="-0.31159419"
+ y1="0.19531250"
+ x2="0.77536231"
+ y2="0.94531250" />
+ <linearGradient
+ xlink:href="#linearGradient830"
+ id="linearGradient836" />
+ </defs>
+ <sodipodi:namedview
+ id="base"
+ pagecolor="#ffffff"
+ bordercolor="#666666"
+ borderopacity="1.0"
+ inkscape:pageopacity="0.0"
+ inkscape:pageshadow="2"
+ inkscape:zoom="22.6274170"
+ inkscape:cx="13.7972814"
+ inkscape:cy="11.0296644"
+ inkscape:window-width="1016"
+ inkscape:window-height="693"
+ gridspacingy="1.0000000pt"
+ gridspacingx="1.0000000pt"
+ gridtolerance="1.0000000px"
+ inkscape:window-x="0"
+ inkscape:window-y="0"
+ showgrid="true" />
+ <rect
+ style="font-size:12;fill:#ffff00;fill-rule:evenodd;stroke:#ff0000;stroke-width:1.22372;"
+ id="rect837"
+ width="26.25515313"
+ height="18.67122459"
+ x="0.67679340"
+ y="8.24792004" />
+ <rect
+ style="font-size:12;fill:url(#linearGradient829);fill-opacity:0.75;fill-rule:evenodd;stroke-width:0.456527pt;"
+ id="rect825"
+ width="24.88985211"
+ height="17.23700789"
+ ry="0"
+ x="1.31681693"
+ y="8.87139037" />
+ <text
+ xml:space="preserve"
+ style="font-size:12;font-weight:bold;font-stretch:normal;stroke-width:1pt;font-family:Bitstream Vera Sans Mono;font-style:normal;text-anchor:start;writing-mode:lr;"
+ x="3.76967978"
+ y="24.3642572"
+ id="text838"
+ transform="scale(0.953250,0.970198)"
+ sodipodi:linespacing="133%"><tspan
+ x="3.76967978"
+ y="24.3642578"
+ sodipodi:role="line"
+ id="tspan1078">XYZ</tspan></text>
+ <rect
+ style="font-size:12;fill:#ffff00;fill-rule:evenodd;stroke:#ff0000;stroke-width:1.26017;"
+ id="rect879"
+ width="11.14999145"
+ height="7.45160484"
+ x="0.67036957"
+ y="0.69067132" />
+ <rect
+ style="font-size:12;fill:url(#linearGradient829);fill-opacity:0.75;fill-rule:evenodd;stroke-width:0.456527pt;"
+ id="rect880"
+ width="9.81101704"
+ height="6.12117195"
+ ry="0"
+ x="1.34353799"
+ y="1.39571142" />
+</svg>
diff --git a/umbrello/umbrello/pics/sources/relationship.svg b/umbrello/umbrello/pics/sources/relationship.svg
new file mode 100644
index 00000000..89981396
--- /dev/null
+++ b/umbrello/umbrello/pics/sources/relationship.svg
@@ -0,0 +1,243 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 20010904//EN"
+"http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd">
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+<svg
+ id="svg1"
+ sodipodi:version="0.32"
+ inkscape:version="0.40"
+ width="22pt"
+ height="22pt"
+ sodipodi:docbase="/home/jr/devel/kdesdk/umbrello/umbrello/pics/sources"
+ sodipodi:docname="relationship.svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:xlink="http://www.w3.org/1999/xlink"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:cc="http://web.resource.org/cc/"
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ inkscape:export-filename="/home/jr/devel/kdesdk/umbrello/umbrello/pics/sources/relationship.png"
+ inkscape:export-xdpi="72.000000"
+ inkscape:export-ydpi="72.000000">
+ <metadata
+ id="metadata42">
+ <rdf:RDF
+ id="RDF43">
+ <cc:Work
+ rdf:about=""
+ id="Work44">
+ <dc:format
+ id="format45">image/svg+xml</dc:format>
+ <dc:type
+ id="type47"
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+ </cc:Work>
+ </rdf:RDF>
+ </metadata>
+ <defs
+ id="defs3">
+ <linearGradient
+ id="linearGradient993">
+ <stop
+ offset="0.0000000"
+ style="stop-color:#ffffff;stop-opacity:0.0000000;"
+ id="stop995" />
+ <stop
+ offset="1.0000000"
+ style="stop-color:#ffffff;stop-opacity:1.0000000;"
+ id="stop994" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient868">
+ <stop
+ style="stop-color:#ffffff;stop-opacity:0.0000000;"
+ offset="0.0000000"
+ id="stop869" />
+ <stop
+ style="stop-color:#fff;stop-opacity:1;"
+ offset="1"
+ id="stop870" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient893">
+ <stop
+ style="stop-color:#19839a;stop-opacity:0.0000000;"
+ offset="0.0000000"
+ id="stop894" />
+ <stop
+ style="stop-color:#fff;stop-opacity:1;"
+ offset="1"
+ id="stop895" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient830">
+ <stop
+ style="stop-color:#ebffff;stop-opacity:0.0000000;"
+ offset="0.0000000"
+ id="stop831" />
+ <stop
+ style="stop-color:#fff;stop-opacity:1;"
+ offset="1"
+ id="stop832" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient826">
+ <stop
+ style="stop-color:#000;stop-opacity:1;"
+ offset="0"
+ id="stop827" />
+ <stop
+ style="stop-color:#fff;stop-opacity:1;"
+ offset="1"
+ id="stop828" />
+ </linearGradient>
+ <linearGradient
+ xlink:href="#linearGradient830"
+ id="linearGradient829"
+ x1="1.5500000"
+ y1="0.52343750"
+ x2="0.20422535"
+ y2="-0.12195122"
+ spreadMethod="reflect" />
+ <linearGradient
+ xlink:href="#linearGradient830"
+ id="linearGradient834"
+ x1="-0.31159419"
+ y1="0.19531250"
+ x2="0.77536231"
+ y2="0.94531250" />
+ <linearGradient
+ xlink:href="#linearGradient830"
+ id="linearGradient836" />
+ <linearGradient
+ xlink:href="#linearGradient868"
+ id="linearGradient892"
+ x1="1.8449316"
+ y1="0.98914021"
+ x2="0.14743590"
+ y2="0.67741936"
+ spreadMethod="reflect" />
+ <defs
+ id="defs940">
+ <linearGradient
+ id="linearGradient941"
+ x1="0.0000000"
+ y1="0.50000000"
+ x2="1.0000000"
+ y2="0.50000000"
+ gradientUnits="objectBoundingBox"
+ spreadMethod="pad"
+ xlink:href="#linearGradient993" />
+ <linearGradient
+ id="linearGradient944">
+ <stop
+ style="stop-color:#19839a;stop-opacity:0.0000000;"
+ offset="0.0000000"
+ id="stop945" />
+ <stop
+ style="stop-color:#fff;stop-opacity:1;"
+ offset="1"
+ id="stop946" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient947">
+ <stop
+ style="stop-color:#ebffff;stop-opacity:0.0000000;"
+ offset="0.0000000"
+ id="stop948" />
+ <stop
+ style="stop-color:#fff;stop-opacity:1;"
+ offset="1"
+ id="stop949" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient950">
+ <stop
+ style="stop-color:#000;stop-opacity:1;"
+ offset="0"
+ id="stop951" />
+ <stop
+ style="stop-color:#fff;stop-opacity:1;"
+ offset="1"
+ id="stop952" />
+ </linearGradient>
+ <linearGradient
+ xlink:href="#linearGradient830"
+ id="linearGradient953"
+ x1="1.5500000"
+ y1="0.52343750"
+ x2="0.20422535"
+ y2="-0.12195122"
+ spreadMethod="reflect" />
+ <linearGradient
+ xlink:href="#linearGradient830"
+ id="linearGradient954"
+ x1="-0.31159419"
+ y1="0.19531250"
+ x2="0.77536231"
+ y2="0.94531250" />
+ <linearGradient
+ xlink:href="#linearGradient830"
+ id="linearGradient955" />
+ <linearGradient
+ xlink:href="#linearGradient868"
+ id="linearGradient956"
+ x1="-0.49264705"
+ y1="0.43750000"
+ x2="0.022058824"
+ y2="0.92187500" />
+ </defs>
+ <sodipodi:namedview
+ id="namedview957"
+ pagecolor="#ffffff"
+ bordercolor="#666666"
+ borderopacity="1.0"
+ inkscape:pageopacity="0.0"
+ inkscape:pageshadow="2"
+ inkscape:zoom="4.0000000"
+ inkscape:cx="79.132843"
+ inkscape:cy="33.777672"
+ inkscape:window-width="1022"
+ inkscape:window-height="701"
+ gridspacingy="1.0000000pt"
+ gridspacingx="1.0000000pt"
+ gridtolerance="1.0000000px"
+ inkscape:window-x="0"
+ inkscape:window-y="0" />
+ </defs>
+ <sodipodi:namedview
+ id="base"
+ pagecolor="#ffffff"
+ bordercolor="#666666"
+ borderopacity="1.0"
+ inkscape:pageopacity="0.0"
+ inkscape:pageshadow="2"
+ inkscape:zoom="22.627417"
+ inkscape:cx="13.797281"
+ inkscape:cy="12.674791"
+ inkscape:window-width="1016"
+ inkscape:window-height="692"
+ gridspacingy="1.0000000pt"
+ gridspacingx="1.0000000pt"
+ gridtolerance="1.0000000px"
+ inkscape:window-x="0"
+ inkscape:window-y="0"
+ showgrid="true"
+ inkscape:current-layer="svg1" />
+ <g
+ id="g1117">
+ <path
+ style="font-size:12.000000;fill:none;fill-opacity:0.75000000;fill-rule:evenodd;stroke:#ff0000;stroke-width:2.0050871"
+ d="M 19.138844,-0.51630137 L 13.730893,9.7597702 L 7.6288725,-0.51630137"
+ id="path1009"
+ sodipodi:nodetypes="ccc" />
+ <rect
+ style="font-size:12.000000;fill:#ff0000;fill-opacity:1.0000000;fill-rule:evenodd;stroke:none;stroke-width:1.0000000pt"
+ id="rect1209"
+ width="2.4859223"
+ height="27.510872"
+ x="12.540097"
+ y="-0.010873318" />
+ </g>
+</svg>
diff --git a/umbrello/umbrello/pics/sources/shallow-history.svg b/umbrello/umbrello/pics/sources/shallow-history.svg
new file mode 100644
index 00000000..d5ce2653
--- /dev/null
+++ b/umbrello/umbrello/pics/sources/shallow-history.svg
@@ -0,0 +1,73 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+<svg
+ xmlns:xml="http://www.w3.org/XML/1998/namespace"
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://web.resource.org/cc/"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:sodipodi="http://inkscape.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ sodipodi:docbase="F:\pics"
+ sodipodi:docname="shallow-history.svg"
+ inkscape:version="0.40+cvs"
+ sodipodi:version="0.32"
+ version="1.0"
+ x="0.00000000"
+ y="0.00000000"
+ width="22.000000px"
+ height="22.000000px"
+ id="svg1">
+ <metadata
+ id="metadata17">
+ <rdf:RDF
+ id="RDF18">
+ <cc:Work
+ id="Work19"
+ rdf:about="">
+ <dc:format
+ id="format20">image/svg+xml</dc:format>
+ <dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage"
+ id="type21" />
+ </cc:Work>
+ </rdf:RDF>
+ </metadata>
+ <sodipodi:namedview
+ inkscape:current-layer="svg1"
+ inkscape:window-y="317"
+ inkscape:window-x="1889"
+ inkscape:cy="11.000000"
+ inkscape:cx="11.000000"
+ inkscape:zoom="18.409091"
+ inkscape:window-height="579"
+ inkscape:window-width="692"
+ inkscape:pageshadow="2"
+ inkscape:pageopacity="0.0"
+ borderopacity="1.0"
+ bordercolor="#666666"
+ pagecolor="#ffffff"
+ id="base" />
+ <defs
+ id="defs3" />
+ <g
+ transform="translate(-383.9018,-518.6851)"
+ id="g240">
+ <path
+ d="M 403.40652,529.87519 C 403.40652,534.58139 399.61097,538.39651 394.92893,538.39651 C 390.24688,538.39651 386.45133,534.58139 386.45133,529.87519 C 386.45133,525.16900 390.24688,521.35388 394.92893,521.35388 C 399.61097,521.35388 403.40652,525.16900 403.40652,529.87519 z "
+ style="fill:none;stroke:#d30000;stroke-width:1.2500000;stroke-miterlimit:4.0000000;stroke-opacity:1.0000000"
+ id="path21" />
+ <text
+ sodipodi:linespacing="100%"
+ x="390.11942"
+ y="534.23749"
+ style="font-size:12.000000;font-style:normal;font-weight:normal;fill:#000000;fill-opacity:1.0000000;stroke:none;stroke-width:1.0000000px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1.0000000;font-family:Bitstream Vera Sans;text-anchor:start;writing-mode:lr-tb"
+ id="text111"
+ xml:space="preserve"><tspan
+ id="tspan22"
+ sodipodi:role="line"
+ y="534.23749"
+ x="390.11942">H</tspan></text>
+ </g>
+</svg>
diff --git a/umbrello/umbrello/pics/sources/state-fork.svg b/umbrello/umbrello/pics/sources/state-fork.svg
new file mode 100644
index 00000000..9e12691a
--- /dev/null
+++ b/umbrello/umbrello/pics/sources/state-fork.svg
@@ -0,0 +1,172 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+<svg
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://web.resource.org/cc/"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:sodipodi="http://inkscape.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ sodipodi:docbase="F:\pics"
+ sodipodi:docname="state-fork.svg"
+ inkscape:version="0.40+cvs"
+ sodipodi:version="0.32"
+ version="1.0"
+ x="0.00000000"
+ y="0.00000000"
+ width="22.000000px"
+ height="22.000000px"
+ id="svg1">
+ <metadata
+ id="metadata39">
+ <rdf:RDF
+ id="RDF40">
+ <cc:Work
+ id="Work41"
+ rdf:about="">
+ <dc:format
+ id="format42">image/svg+xml</dc:format>
+ <dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage"
+ id="type43" />
+ </cc:Work>
+ </rdf:RDF>
+ </metadata>
+ <sodipodi:namedview
+ inkscape:current-layer="svg1"
+ inkscape:window-y="134"
+ inkscape:window-x="1483"
+ inkscape:cy="11.000000"
+ inkscape:cx="11.000000"
+ inkscape:zoom="23.500000"
+ inkscape:window-height="691"
+ inkscape:window-width="1035"
+ inkscape:pageshadow="2"
+ inkscape:pageopacity="0.0"
+ borderopacity="1.0"
+ bordercolor="#666666"
+ pagecolor="#ffffff"
+ id="base" />
+ <defs
+ id="defs3">
+ <marker
+ inkscape:stockid="Arrow2Mend"
+ orient="auto"
+ refY="0.0"
+ refX="0.0"
+ id="marker246"
+ style="overflow:visible;">
+ <path
+ sodipodi:nodetypes="cccc"
+ id="path247"
+ style="font-size:12.0;fill-rule:evenodd;stroke-width:0.62500000;stroke-linejoin:round;"
+ d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.9730900,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z "
+ transform="scale(0.6) rotate(180) translate(-5,0)" />
+ </marker>
+ <marker
+ inkscape:stockid="Arrow2Mend"
+ orient="auto"
+ refY="0.0"
+ refX="0.0"
+ id="marker244"
+ style="overflow:visible;">
+ <path
+ sodipodi:nodetypes="cccc"
+ id="path245"
+ style="font-size:12.0;fill-rule:evenodd;stroke-width:0.62500000;stroke-linejoin:round;"
+ d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.9730900,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z "
+ transform="scale(0.6) rotate(180) translate(-5,0)" />
+ </marker>
+ <marker
+ inkscape:stockid="Arrow2Mend"
+ orient="auto"
+ refY="0.0"
+ refX="0.0"
+ id="marker242"
+ style="overflow:visible;">
+ <path
+ sodipodi:nodetypes="cccc"
+ id="path243"
+ style="font-size:12.0;fill-rule:evenodd;stroke-width:0.62500000;stroke-linejoin:round;"
+ d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.9730900,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z "
+ transform="scale(0.6) rotate(180) translate(-5,0)" />
+ </marker>
+ <marker
+ inkscape:stockid="Arrow2Mend"
+ orient="auto"
+ refY="0.0"
+ refX="0.0"
+ id="marker556"
+ style="overflow:visible;">
+ <path
+ sodipodi:nodetypes="cccc"
+ id="path557"
+ style="font-size:12.0;fill-rule:evenodd;stroke-width:0.62500000;stroke-linejoin:round;"
+ d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.9730900,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z "
+ transform="scale(0.6) rotate(180) translate(-5,0)" />
+ </marker>
+ <marker
+ inkscape:stockid="Arrow2Mend"
+ orient="auto"
+ refY="0.0"
+ refX="0.0"
+ id="marker553"
+ style="overflow:visible;">
+ <path
+ sodipodi:nodetypes="cccc"
+ id="path554"
+ style="font-size:12.0;fill-rule:evenodd;stroke-width:0.62500000;stroke-linejoin:round;"
+ d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.9730900,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z "
+ transform="scale(0.6) rotate(180) translate(-5,0)" />
+ </marker>
+ <marker
+ inkscape:stockid="Arrow2Mend"
+ orient="auto"
+ refY="0.0"
+ refX="0.0"
+ id="Arrow2Mend"
+ style="overflow:visible;">
+ <path
+ sodipodi:nodetypes="cccc"
+ id="path454"
+ style="font-size:12.0;fill-rule:evenodd;stroke-width:0.62500000;stroke-linejoin:round;"
+ d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.9730900,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z "
+ transform="scale(0.6) rotate(180) translate(-5,0)" />
+ </marker>
+ <marker
+ inkscape:stockid="Arrow2Lend"
+ orient="auto"
+ refY="0.0"
+ refX="0.0"
+ id="Arrow2Lend"
+ style="overflow:visible;">
+ <path
+ sodipodi:nodetypes="cccc"
+ id="path455"
+ style="font-size:12.0;fill-rule:evenodd;stroke-width:0.62500000;stroke-linejoin:round;"
+ d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.9730900,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z "
+ transform="scale(1.1) rotate(180) translate(-5,0)" />
+ </marker>
+ </defs>
+ <g
+ transform="translate(-383.7683,-518.9311)"
+ id="g241">
+ <path
+ style="fill:none;fill-opacity:0.75000000;fill-rule:evenodd;stroke:#000000;stroke-width:2.0250001;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:4.0000000;stroke-opacity:1.0000000"
+ d="M 394.53323,522.08766 C 394.54111,537.47668 394.54111,537.47668 394.54111,537.47668 L 394.54111,537.47668"
+ id="path15" />
+ <path
+ style="fill:none;fill-opacity:0.75000000;fill-rule:evenodd;stroke:#000000;stroke-width:0.60290909px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1.0000000;marker-start:none;marker-mid:none;marker-end:url(#Arrow2Mend)"
+ d="M 384.86403,529.65511 L 390.60819,529.65511"
+ id="path16" />
+ <path
+ style="fill:none;fill-opacity:0.75000000;fill-rule:evenodd;stroke:#000000;stroke-width:0.60290909px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1.0000000;marker-start:none;marker-mid:none;marker-end:url(#Arrow2Mend)"
+ d="M 395.73687,534.45617 L 401.48103,534.45617"
+ id="path555" />
+ <path
+ style="fill:none;fill-opacity:0.75000000;fill-rule:evenodd;stroke:#000000;stroke-width:0.60290909px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1.0000000;marker-start:none;marker-mid:none;marker-end:url(#Arrow2Mend)"
+ d="M 395.73687,524.85406 L 401.48103,524.85406"
+ id="path558" />
+ </g>
+</svg>
diff --git a/umbrello/umbrello/pics/sources/subsystem.svg b/umbrello/umbrello/pics/sources/subsystem.svg
new file mode 100644
index 00000000..ca5f1ce7
--- /dev/null
+++ b/umbrello/umbrello/pics/sources/subsystem.svg
@@ -0,0 +1,135 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 20010904//EN"
+"http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd">
+<!-- Created with Sodipodi ("http://www.sodipodi.com/") -->
+<svg
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:xlink="http://www.w3.org/1999/xlink"
+ id="svg1"
+ sodipodi:version="0.34"
+ inkscape:version="0.37"
+ width="22pt"
+ height="22pt"
+ sodipodi:docname="subsystem.svg">
+ <defs
+ id="defs3">
+ <linearGradient
+ id="linearGradient830">
+ <stop
+ style="stop-color:#ebffff;stop-opacity:0.0000000;"
+ offset="0.0000000"
+ id="stop831" />
+ <stop
+ style="stop-color:#fff;stop-opacity:1;"
+ offset="1"
+ id="stop832" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient826">
+ <stop
+ style="stop-color:#000;stop-opacity:1;"
+ offset="0"
+ id="stop827" />
+ <stop
+ style="stop-color:#fff;stop-opacity:1;"
+ offset="1"
+ id="stop828" />
+ </linearGradient>
+ <linearGradient
+ xlink:href="#linearGradient830"
+ id="linearGradient829"
+ x1="1.5500000"
+ y1="0.52343750"
+ x2="0.20422535"
+ y2="-0.12195122"
+ spreadMethod="reflect" />
+ <linearGradient
+ xlink:href="#linearGradient830"
+ id="linearGradient834"
+ x1="-0.31159419"
+ y1="0.19531250"
+ x2="0.77536231"
+ y2="0.94531250" />
+ <linearGradient
+ xlink:href="#linearGradient830"
+ id="linearGradient836" />
+ </defs>
+ <sodipodi:namedview
+ id="base"
+ pagecolor="#ffffff"
+ bordercolor="#666666"
+ borderopacity="1.0"
+ inkscape:pageopacity="0.0"
+ inkscape:pageshadow="2"
+ inkscape:zoom="22.6274170"
+ inkscape:cx="13.7972814"
+ inkscape:cy="11.0296644"
+ inkscape:window-width="1016"
+ inkscape:window-height="693"
+ gridspacingy="1.0000000pt"
+ gridspacingx="1.0000000pt"
+ gridtolerance="1.0000000px"
+ inkscape:window-x="0"
+ inkscape:window-y="0"
+ showgrid="true" />
+ <rect
+ style="font-size:12;fill:#ffff00;fill-rule:evenodd;stroke:#ff0000;stroke-width:1.22372;"
+ id="rect837"
+ width="26.25515313"
+ height="18.67122459"
+ x="0.67679340"
+ y="8.24792004" />
+ <rect
+ style="font-size:12;fill:url(#linearGradient829);fill-opacity:0.75;fill-rule:evenodd;stroke-width:0.456527pt;"
+ id="rect825"
+ width="24.88985211"
+ height="17.23700789"
+ ry="0"
+ x="1.31681693"
+ y="8.87139037" />
+ <rect
+ style="font-size:12;fill:#ffff00;fill-rule:evenodd;stroke:#ff0000;stroke-width:1.26017;"
+ id="rect879"
+ width="11.14999145"
+ height="7.45160484"
+ x="0.67036957"
+ y="0.69067132" />
+ <rect
+ style="font-size:12;fill:url(#linearGradient829);fill-opacity:0.75;fill-rule:evenodd;stroke-width:0.456527pt;"
+ id="rect880"
+ width="9.81101704"
+ height="6.12117195"
+ ry="0"
+ x="1.34353799"
+ y="1.39571142" />
+ <rect
+ style="font-size:12;fill:#ff0000;fill-rule:evenodd;stroke-width:1;fill-opacity:1;"
+ id="rect624"
+ width="1.21451104"
+ height="4.94479527"
+ x="12.665616"
+ y="11.364354" />
+ <rect
+ style="font-size:12;fill:#ff0000;fill-rule:evenodd;stroke-width:1;fill-opacity:1;"
+ id="rect626"
+ width="8.84858036"
+ height="1.38801145"
+ x="8.84858036"
+ y="16.3091492" />
+ <rect
+ style="font-size:12;fill:#ff0000;fill-rule:evenodd;stroke-width:1;fill-opacity:1;"
+ id="rect627"
+ width="1.21451092"
+ height="6.2460556"
+ x="8.84858036"
+ y="17.6104107" />
+ <rect
+ style="font-size:12;fill:#ff0000;fill-rule:evenodd;stroke-width:1;fill-opacity:1;"
+ id="rect628"
+ width="1.38801193"
+ height="6.2460556"
+ x="16.3091488"
+ y="17.6104107" />
+</svg>
diff --git a/umbrello/umbrello/pics/sources/template.svg b/umbrello/umbrello/pics/sources/template.svg
new file mode 100644
index 00000000..5c299757
--- /dev/null
+++ b/umbrello/umbrello/pics/sources/template.svg
@@ -0,0 +1,146 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 20010904//EN"
+"http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd">
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+<svg
+ id="svg1"
+ sodipodi:version="0.32"
+ inkscape:version="0.37"
+ width="16pt"
+ height="16pt"
+ sodipodi:docbase="/home/jr/tmp/umbrello/icons/inkscape-svg"
+ sodipodi:docname="template.svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:xml="http://www.w3.org/XML/1998/namespace"
+ xmlns:xlink="http://www.w3.org/1999/xlink">
+ <defs
+ id="defs3">
+ <linearGradient
+ id="linearGradient830">
+ <stop
+ style="stop-color:#ebffff;stop-opacity:0.0000000;"
+ offset="0.0000000"
+ id="stop831" />
+ <stop
+ style="stop-color:#fff;stop-opacity:1;"
+ offset="1"
+ id="stop832" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient826">
+ <stop
+ style="stop-color:#000;stop-opacity:1;"
+ offset="0"
+ id="stop827" />
+ <stop
+ style="stop-color:#fff;stop-opacity:1;"
+ offset="1"
+ id="stop828" />
+ </linearGradient>
+ <linearGradient
+ xlink:href="#linearGradient830"
+ id="linearGradient829"
+ x1="1.5500000"
+ y1="0.52343750"
+ x2="0.20422535"
+ y2="-0.12195122"
+ spreadMethod="reflect" />
+ <linearGradient
+ xlink:href="#linearGradient830"
+ id="linearGradient834"
+ x1="-0.31159419"
+ y1="0.19531250"
+ x2="0.77536231"
+ y2="0.94531250" />
+ <linearGradient
+ xlink:href="#linearGradient830"
+ id="linearGradient836" />
+ </defs>
+ <sodipodi:namedview
+ id="base"
+ pagecolor="#ffffff"
+ bordercolor="#666666"
+ borderopacity="1.0"
+ inkscape:pageopacity="0.0"
+ inkscape:pageshadow="2"
+ inkscape:zoom="0.26725582"
+ inkscape:cx="87.469639"
+ inkscape:cy="55.703730"
+ inkscape:window-width="1022"
+ inkscape:window-height="701"
+ gridspacingy="1.0000000pt"
+ gridspacingx="1.0000000pt"
+ gridtolerance="1.0000000px"
+ inkscape:window-x="0"
+ inkscape:window-y="0"
+ showgrid="true"
+ snaptogrid="false" />
+ <rect
+ style="font-size:12.000;fill:#ffff00;fill-rule:evenodd;stroke:#ff0000;stroke-width:1.250131;"
+ id="rect837"
+ width="15.04155"
+ height="14.94933"
+ x="0.672622"
+ y="4.443538" />
+ <rect
+ style="font-size:12.000;fill:url(#linearGradient829);fill-opacity:0.750000;fill-rule:evenodd;stroke-width:0.456527;"
+ id="rect825"
+ width="14.62770"
+ height="4.262030"
+ ry="0"
+ x="1.220295"
+ y="5.096904" />
+ <text
+ xml:space="preserve"
+ style="font-size:12.000;font-weight:normal;font-family:Bitstream Vera Sans;"
+ x="2.58085157"
+ y="21.7099400"
+ id="text838"
+ transform="scale(0.457094,0.398859)"><tspan
+ id="tspan839">ABC</tspan></text>
+ <path
+ style="font-size:12.000;fill:none;fill-opacity:0.750000;fill-rule:evenodd;stroke:#ff0000;stroke-width:1.249990;"
+ d="M 0.585981 9.445099 L 15.29877 9.445099 "
+ id="path842" />
+ <path
+ style="font-size:12.000;fill:none;fill-opacity:0.750000;fill-rule:evenodd;stroke:#ff0000;stroke-width:1.249990;"
+ d="M 0.506163 14.38251 L 15.21895 14.38251 "
+ id="path845" />
+ <rect
+ style="font-size:12.000;fill:url(#linearGradient829);fill-opacity:0.750000;fill-rule:evenodd;stroke-width:0.456527;"
+ id="rect846"
+ width="13.89305"
+ height="3.689761"
+ ry="0"
+ x="1.307394"
+ y="10.00005" />
+ <rect
+ style="font-size:12.000;fill:url(#linearGradient829);fill-opacity:0.750000;fill-rule:evenodd;stroke-width:0.456527;"
+ id="rect847"
+ width="13.29614"
+ height="3.545959"
+ ry="0"
+ x="1.283363"
+ y="15.21296" />
+ <rect
+ style="font-size:12.000;fill:#ffff00;fill-rule:evenodd;stroke:#ff0000;stroke-width:1.2500;stroke-dasharray:none;"
+ id="rect632"
+ width="6.335767"
+ height="6.325978"
+ x="13.06549"
+ y="0.607178" />
+ <text
+ xml:space="preserve"
+ style="font-size:12.000;font-weight:normal;font-family:Bitstream Vera Sans;"
+ x="61.0662308"
+ y="-0.90945697"
+ id="text633"
+ transform="scale(0.222374,0.562059)"
+ sodipodi:linespacing="100%"><tspan
+ x="61.0662308"
+ y="11.0905430"
+ sodipodi:role="line"
+ id="tspan636">XYZ</tspan></text>
+</svg>
diff --git a/umbrello/umbrello/pics/sources/text.svg b/umbrello/umbrello/pics/sources/text.svg
new file mode 100644
index 00000000..24eba425
--- /dev/null
+++ b/umbrello/umbrello/pics/sources/text.svg
@@ -0,0 +1,91 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 20010904//EN"
+"http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd">
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+<svg
+ id="svg1"
+ sodipodi:version="0.32"
+ inkscape:version="0.37"
+ width="22pt"
+ height="22pt"
+ sodipodi:docbase="/home/jr/tmp/umbrello/icons/inkscape-svg"
+ sodipodi:docname="text.svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:xml="http://www.w3.org/XML/1998/namespace"
+ xmlns:xlink="http://www.w3.org/1999/xlink">
+ <defs
+ id="defs3">
+ <linearGradient
+ id="linearGradient830">
+ <stop
+ style="stop-color:#ebffff;stop-opacity:0.0000000;"
+ offset="0.0000000"
+ id="stop831" />
+ <stop
+ style="stop-color:#fff;stop-opacity:1;"
+ offset="1"
+ id="stop832" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient826">
+ <stop
+ style="stop-color:#000;stop-opacity:1;"
+ offset="0"
+ id="stop827" />
+ <stop
+ style="stop-color:#fff;stop-opacity:1;"
+ offset="1"
+ id="stop828" />
+ </linearGradient>
+ <linearGradient
+ xlink:href="#linearGradient830"
+ id="linearGradient829"
+ x1="1.5500000"
+ y1="0.52343750"
+ x2="0.20422535"
+ y2="-0.12195122"
+ spreadMethod="reflect" />
+ <linearGradient
+ xlink:href="#linearGradient830"
+ id="linearGradient834"
+ x1="-0.31159419"
+ y1="0.19531250"
+ x2="0.77536231"
+ y2="0.94531250" />
+ <linearGradient
+ xlink:href="#linearGradient830"
+ id="linearGradient836" />
+ </defs>
+ <sodipodi:namedview
+ id="base"
+ pagecolor="#ffffff"
+ bordercolor="#666666"
+ borderopacity="1.0"
+ inkscape:pageopacity="0.0"
+ inkscape:pageshadow="2"
+ inkscape:zoom="22.6274170"
+ inkscape:cx="7.69284241"
+ inkscape:cy="12.0771046"
+ inkscape:window-width="1016"
+ inkscape:window-height="693"
+ gridspacingy="1.0000000pt"
+ gridspacingx="1.0000000pt"
+ gridtolerance="1.0000000px"
+ inkscape:window-x="0"
+ inkscape:window-y="0"
+ showgrid="true" />
+ <text
+ xml:space="preserve"
+ style="fill:black;fill-opacity:1;stroke:none;font-family:Bitstream Vera Sans Mono;font-style:normal;font-weight:bold;font-size:12;stroke-opacity:1;stroke-width:1pt;stroke-linejoin:miter;stroke-linecap:butt;font-stretch:normal;font-variant:normal;text-anchor:middle;writing-mode:lr;"
+ x="10.5612742"
+ y="12.4468273"
+ id="text865"
+ transform="scale(1.305010,1.709686)"
+ sodipodi:linespacing="100%"><tspan
+ x="10.5612745"
+ y="12.4468269"
+ sodipodi:role="line"
+ id="tspan1162">XYZ</tspan></text>
+</svg>
diff --git a/umbrello/umbrello/pics/sources/uniassociation.svg b/umbrello/umbrello/pics/sources/uniassociation.svg
new file mode 100644
index 00000000..4fce2c33
--- /dev/null
+++ b/umbrello/umbrello/pics/sources/uniassociation.svg
@@ -0,0 +1,221 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 20010904//EN"
+"http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd">
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+<svg
+ id="svg1"
+ sodipodi:version="0.32"
+ inkscape:version="0.37"
+ width="22pt"
+ height="22pt"
+ sodipodi:docbase="/home/jr/tmp/umbrello/icons/inkscape-svg"
+ sodipodi:docname="uniassociation.svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:xlink="http://www.w3.org/1999/xlink">
+ <defs
+ id="defs3">
+ <linearGradient
+ id="linearGradient993">
+ <stop
+ offset="0.0000000"
+ style="stop-color:#ffffff;stop-opacity:0.0000000;"
+ id="stop995" />
+ <stop
+ offset="1.0000000"
+ style="stop-color:#ffffff;stop-opacity:1.0000000;"
+ id="stop994" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient868">
+ <stop
+ style="stop-color:#ffffff;stop-opacity:0.0000000;"
+ offset="0.0000000"
+ id="stop869" />
+ <stop
+ style="stop-color:#fff;stop-opacity:1;"
+ offset="1"
+ id="stop870" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient893">
+ <stop
+ style="stop-color:#19839a;stop-opacity:0.0000000;"
+ offset="0.0000000"
+ id="stop894" />
+ <stop
+ style="stop-color:#fff;stop-opacity:1;"
+ offset="1"
+ id="stop895" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient830">
+ <stop
+ style="stop-color:#ebffff;stop-opacity:0.0000000;"
+ offset="0.0000000"
+ id="stop831" />
+ <stop
+ style="stop-color:#fff;stop-opacity:1;"
+ offset="1"
+ id="stop832" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient826">
+ <stop
+ style="stop-color:#000;stop-opacity:1;"
+ offset="0"
+ id="stop827" />
+ <stop
+ style="stop-color:#fff;stop-opacity:1;"
+ offset="1"
+ id="stop828" />
+ </linearGradient>
+ <linearGradient
+ xlink:href="#linearGradient830"
+ id="linearGradient829"
+ x1="1.5500000"
+ y1="0.52343750"
+ x2="0.20422535"
+ y2="-0.12195122"
+ spreadMethod="reflect" />
+ <linearGradient
+ xlink:href="#linearGradient830"
+ id="linearGradient834"
+ x1="-0.31159419"
+ y1="0.19531250"
+ x2="0.77536231"
+ y2="0.94531250" />
+ <linearGradient
+ xlink:href="#linearGradient830"
+ id="linearGradient836" />
+ <linearGradient
+ xlink:href="#linearGradient868"
+ id="linearGradient892"
+ x1="1.8449316"
+ y1="0.98914021"
+ x2="0.14743590"
+ y2="0.67741936"
+ spreadMethod="reflect" />
+ <defs
+ id="defs940">
+ <linearGradient
+ id="linearGradient941"
+ x1="0.0000000"
+ y1="0.50000000"
+ x2="1.0000000"
+ y2="0.50000000"
+ gradientUnits="objectBoundingBox"
+ spreadMethod="pad"
+ xlink:href="#linearGradient993" />
+ <linearGradient
+ id="linearGradient944">
+ <stop
+ style="stop-color:#19839a;stop-opacity:0.0000000;"
+ offset="0.0000000"
+ id="stop945" />
+ <stop
+ style="stop-color:#fff;stop-opacity:1;"
+ offset="1"
+ id="stop946" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient947">
+ <stop
+ style="stop-color:#ebffff;stop-opacity:0.0000000;"
+ offset="0.0000000"
+ id="stop948" />
+ <stop
+ style="stop-color:#fff;stop-opacity:1;"
+ offset="1"
+ id="stop949" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient950">
+ <stop
+ style="stop-color:#000;stop-opacity:1;"
+ offset="0"
+ id="stop951" />
+ <stop
+ style="stop-color:#fff;stop-opacity:1;"
+ offset="1"
+ id="stop952" />
+ </linearGradient>
+ <linearGradient
+ xlink:href="#linearGradient830"
+ id="linearGradient953"
+ x1="1.5500000"
+ y1="0.52343750"
+ x2="0.20422535"
+ y2="-0.12195122"
+ spreadMethod="reflect" />
+ <linearGradient
+ xlink:href="#linearGradient830"
+ id="linearGradient954"
+ x1="-0.31159419"
+ y1="0.19531250"
+ x2="0.77536231"
+ y2="0.94531250" />
+ <linearGradient
+ xlink:href="#linearGradient830"
+ id="linearGradient955" />
+ <linearGradient
+ xlink:href="#linearGradient868"
+ id="linearGradient956"
+ x1="-0.49264705"
+ y1="0.43750000"
+ x2="0.022058824"
+ y2="0.92187500" />
+ </defs>
+ <sodipodi:namedview
+ id="namedview957"
+ pagecolor="#ffffff"
+ bordercolor="#666666"
+ borderopacity="1.0"
+ inkscape:pageopacity="0.0"
+ inkscape:pageshadow="2"
+ inkscape:zoom="4.0000000"
+ inkscape:cx="79.132843"
+ inkscape:cy="33.777672"
+ inkscape:window-width="1022"
+ inkscape:window-height="701"
+ gridspacingy="1.0000000pt"
+ gridspacingx="1.0000000pt"
+ gridtolerance="1.0000000px"
+ inkscape:window-x="0"
+ inkscape:window-y="0" />
+ </defs>
+ <sodipodi:namedview
+ id="base"
+ pagecolor="#ffffff"
+ bordercolor="#666666"
+ borderopacity="1.0"
+ inkscape:pageopacity="0.0"
+ inkscape:pageshadow="2"
+ inkscape:zoom="22.6274170"
+ inkscape:cx="13.7972814"
+ inkscape:cy="10.5907033"
+ inkscape:window-width="1016"
+ inkscape:window-height="693"
+ gridspacingy="1.0000000pt"
+ gridspacingx="1.0000000pt"
+ gridtolerance="1.0000000px"
+ inkscape:window-x="0"
+ inkscape:window-y="0"
+ showgrid="true" />
+ <g
+ id="g1210">
+ <path
+ style="font-size:12;fill:none;fill-opacity:0.75;fill-rule:evenodd;stroke:#ff0000;stroke-width:1.62628;"
+ d="M 18.100766 10.114902 L 13.714502 1.7802173 L 8.7652941 10.114902 "
+ id="path1009"
+ sodipodi:nodetypes="ccc" />
+ <rect
+ style="font-size:12;fill:#ff0000;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1pt;"
+ id="rect1209"
+ width="2.48592234"
+ height="25.08019308"
+ x="12.54009724"
+ y="2.41980620" />
+ </g>
+</svg>
diff --git a/umbrello/umbrello/pics/sources/usecase.svg b/umbrello/umbrello/pics/sources/usecase.svg
new file mode 100644
index 00000000..cd0851c5
--- /dev/null
+++ b/umbrello/umbrello/pics/sources/usecase.svg
@@ -0,0 +1,131 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 20010904//EN"
+"http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd">
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+<svg
+ id="svg1"
+ sodipodi:version="0.32"
+ inkscape:version="0.38.1"
+ width="128.00000pt"
+ height="128.00000pt"
+ sodipodi:docbase="/home/bartkozoltan/Documents/work/umbrello/new pics"
+ sodipodi:docname="usecase.svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:xml="http://www.w3.org/XML/1998/namespace"
+ xmlns:xlink="http://www.w3.org/1999/xlink">
+ <defs
+ id="defs3">
+ <linearGradient
+ id="linearGradient868">
+ <stop
+ style="stop-color:#ffffff;stop-opacity:0.0000000;"
+ offset="0.0000000"
+ id="stop869" />
+ <stop
+ style="stop-color:#fff;stop-opacity:1;"
+ offset="1"
+ id="stop870" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient893">
+ <stop
+ style="stop-color:#19839a;stop-opacity:0.0000000;"
+ offset="0.0000000"
+ id="stop894" />
+ <stop
+ style="stop-color:#fff;stop-opacity:1;"
+ offset="1"
+ id="stop895" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient830">
+ <stop
+ style="stop-color:#ebffff;stop-opacity:0.0000000;"
+ offset="0.0000000"
+ id="stop831" />
+ <stop
+ style="stop-color:#fff;stop-opacity:1;"
+ offset="1"
+ id="stop832" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient826">
+ <stop
+ style="stop-color:#000;stop-opacity:1;"
+ offset="0"
+ id="stop827" />
+ <stop
+ style="stop-color:#fff;stop-opacity:1;"
+ offset="1"
+ id="stop828" />
+ </linearGradient>
+ <linearGradient
+ xlink:href="#linearGradient830"
+ id="linearGradient829"
+ x1="1.5500000"
+ y1="0.52343750"
+ x2="0.20422535"
+ y2="-0.12195122"
+ spreadMethod="reflect" />
+ <linearGradient
+ xlink:href="#linearGradient830"
+ id="linearGradient834"
+ x1="-0.31159419"
+ y1="0.19531250"
+ x2="0.77536231"
+ y2="0.94531250" />
+ <linearGradient
+ xlink:href="#linearGradient830"
+ id="linearGradient836" />
+ <linearGradient
+ xlink:href="#linearGradient868"
+ id="linearGradient892" />
+ </defs>
+ <sodipodi:namedview
+ id="base"
+ pagecolor="#ffffff"
+ bordercolor="#666666"
+ borderopacity="1.0"
+ inkscape:pageopacity="0.0"
+ inkscape:pageshadow="2"
+ inkscape:zoom="4.0000000"
+ inkscape:cx="79.132812"
+ inkscape:cy="69.358765"
+ inkscape:window-width="1022"
+ inkscape:window-height="701"
+ gridspacingy="1.0000000pt"
+ gridspacingx="1.0000000pt"
+ gridtolerance="1.0000000px"
+ inkscape:window-x="0"
+ inkscape:window-y="0" />
+ <path
+ sodipodi:type="arc"
+ style="fill:#ffff00;fill-rule:evenodd;stroke:#ff0000;stroke-width:6.5509048;stroke-opacity:1.0000000;fill-opacity:1.0000000;stroke-dasharray:none;"
+ id="path863"
+ sodipodi:cx="63.437500"
+ sodipodi:cy="39.375000"
+ sodipodi:rx="31.250000"
+ sodipodi:ry="31.562500"
+ d="M 94.687500 39.375000 A 31.250000 31.562500 0 1 0 32.187500,39.375000 A 31.250000 31.562500 0 1 0 94.687500 39.375000 z"
+ transform="matrix(2.033142,0.000000,0.000000,1.146119,-49.35104,33.00004)" />
+ <path
+ sodipodi:type="arc"
+ style="fill:url(#linearGradient892);fill-opacity:0.75000000;fill-rule:evenodd;stroke-width:10.000000;"
+ id="path864"
+ sodipodi:cx="63.437500"
+ sodipodi:cy="39.375000"
+ sodipodi:rx="31.250000"
+ sodipodi:ry="31.562500"
+ d="M 94.687500 39.375000 A 31.250000 31.562500 0 1 0 32.187500,39.375000 A 31.250000 31.562500 0 1 0 94.687500 39.375000 z"
+ transform="matrix(1.866513,0.000000,0.000000,0.989918,-38.73914,38.52544)" />
+ <text
+ xml:space="preserve"
+ style="fill:black;fill-opacity:1;stroke:none;font-family:Bitstream Vera Sans;font-style:normal;font-weight:normal;font-size:12px;stroke-opacity:1;stroke-width:1pt;stroke-linejoin:miter;stroke-linecap:butt;"
+ x="6.9204906"
+ y="27.309141"
+ id="text869"
+ transform="scale(4.148831,3.402401)"><tspan
+ id="tspan870">ABC</tspan></text>
+</svg>
diff --git a/umbrello/umbrello/pics/startlogo.png b/umbrello/umbrello/pics/startlogo.png
new file mode 100644
index 00000000..29d6e15d
--- /dev/null
+++ b/umbrello/umbrello/pics/startlogo.png
Binary files differ
diff --git a/umbrello/umbrello/pics/state-fork.png b/umbrello/umbrello/pics/state-fork.png
new file mode 100644
index 00000000..5a3108a1
--- /dev/null
+++ b/umbrello/umbrello/pics/state-fork.png
Binary files differ
diff --git a/umbrello/umbrello/pics/subsystem.png b/umbrello/umbrello/pics/subsystem.png
new file mode 100644
index 00000000..a002b73e
--- /dev/null
+++ b/umbrello/umbrello/pics/subsystem.png
Binary files differ
diff --git a/umbrello/umbrello/pics/template.png b/umbrello/umbrello/pics/template.png
new file mode 100644
index 00000000..0993de43
--- /dev/null
+++ b/umbrello/umbrello/pics/template.png
Binary files differ
diff --git a/umbrello/umbrello/pics/text.png b/umbrello/umbrello/pics/text.png
new file mode 100644
index 00000000..77893ded
--- /dev/null
+++ b/umbrello/umbrello/pics/text.png
Binary files differ
diff --git a/umbrello/umbrello/pics/uniassociation.png b/umbrello/umbrello/pics/uniassociation.png
new file mode 100644
index 00000000..f4be9352
--- /dev/null
+++ b/umbrello/umbrello/pics/uniassociation.png
Binary files differ
diff --git a/umbrello/umbrello/pics/usecase.png b/umbrello/umbrello/pics/usecase.png
new file mode 100644
index 00000000..83201d44
--- /dev/null
+++ b/umbrello/umbrello/pics/usecase.png
Binary files differ
diff --git a/umbrello/umbrello/plugin.cpp b/umbrello/umbrello/plugin.cpp
new file mode 100644
index 00000000..1447afcd
--- /dev/null
+++ b/umbrello/umbrello/plugin.cpp
@@ -0,0 +1,167 @@
+/***************************************************************************
+ plugin.h
+ -------------------
+ begin : Mon Jan 13 2003
+ copyright : (C) 2003 by Andrew Sutton
+ email : ansutton@kent.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. *
+ * *
+ ***************************************************************************/
+
+// own header
+#include "plugin.h"
+
+// KDE includes
+#include <kdebug.h>
+#include <kapplication.h>
+#include <kconfig.h>
+
+// app includes
+#include "pluginloader.h"
+
+using namespace Umbrello;
+
+Plugin::Plugin(QObject *parent,
+ const char *name,
+ const QStringList & /* args */) :
+ QObject(parent, name),
+ Configurable(),
+ _ref(0),
+ _instanceName(name),
+ _config(NULL)
+{
+}
+
+Plugin::~Plugin()
+{
+}
+
+void
+Plugin::ref()
+{
+ _ref++;
+}
+
+void
+Plugin::unload()
+{
+ _ref--;
+ if(_ref == 0) {
+ // save the name
+ QString pluginName = _instanceName;
+
+ // shutdown and delete
+ shutdown();
+ delete this;
+
+ // once the object is destroyed, we can have the plugin loader unload
+ // the library.
+ PluginLoader::instance()->unloadPlugin(pluginName);
+ }
+}
+
+bool
+Plugin::init()
+{
+ bool ret = true;
+
+ // initialize this plugin first - then load other plugins
+ ret = onInit();
+ if(!ret) {
+ kdError() << "failed to initialize " << instanceName() << endl;
+ }
+
+ // configure on load plugins
+ if(ret) {
+ ret = configure();
+ if(!ret) {
+ kdError() << "failed configuration " << instanceName() << endl;
+ }
+ }
+
+ return true;
+}
+
+bool
+Plugin::shutdown()
+{
+ bool ret = true;
+
+ // always unload plugins, even if things are failing
+ unloadPlugins();
+
+ // shutdown this plugin
+ ret = onShutdown();
+ if(!ret) {
+ kdError() << "failed to shutdown " << instanceName() << endl;
+ }
+
+ return true;
+}
+
+QCString
+Plugin::instanceName() const
+{
+ return _instanceName;
+}
+
+KConfig *
+Plugin::config()
+{
+ return _config;
+}
+
+bool
+Plugin::onInit()
+{
+ return true;
+}
+
+bool
+Plugin::onShutdown()
+{
+ return true;
+}
+
+bool
+Plugin::configure()
+{
+ bool ret = true;
+
+ // grab the OnStartup map
+ KConfig *conf = config();
+ if(!conf) {
+ kdDebug() << "no configuration for " << instanceName() << endl;
+ ret = false;
+ }
+
+ if(ret) {
+ // set the config group to Load Actions
+ conf->setGroup("Load Actions");
+
+ // load standard plugins by default
+ loadPlugins(conf, "Load");
+
+ // only load GUI plugins if this is not a terminal app
+ if(KApplication::kApplication()->type() != QApplication::Tty) {
+ loadPlugins(conf, "LoadGUI");
+ }
+ }
+
+ return ret;
+}
+
+QString
+Plugin::category()
+{
+ return QString("miscellaneous");
+}
+
+#include "plugin.moc"
diff --git a/umbrello/umbrello/plugin.h b/umbrello/umbrello/plugin.h
new file mode 100644
index 00000000..8d1eacc8
--- /dev/null
+++ b/umbrello/umbrello/plugin.h
@@ -0,0 +1,163 @@
+/***************************************************************************
+ plugin.h
+ -------------------
+ begin : Mon Jan 13 2003
+ copyright : (C) 2003 by Andrew Sutton
+ email : ansutton@kent.edu
+ Bugs and comments to uml-devel@lists.sf.net or http://bugs.kde.org
+***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the 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 UMBRELLO_PLUGIN_H
+#define UMBRELLO_PLUGIN_H
+
+// Qt includes
+#include <qobject.h>
+
+// KDE includes
+#include <kgenericfactory.h>
+
+// local includes
+#include "configurable.h"
+
+// forward declarations
+class QStringList;
+class KConfig;
+
+/**
+ * This macro replaces the K_EXPORT_COMPONENT_FACTORY macro because of
+ * a simple defficiency for this application - the construction of the
+ * factory with a default instance name. This macro must be used in
+ * the .cpp file implementing the plugin.
+ *
+ *
+ * @param libname The name of the plugin. This corresponds to
+ * the name of the shared object without the ".so"
+ * extension.
+ * @param factory The type of factory. Typically, this will be
+ * KGenericFactory<> with the name of the plugin
+ * as the parameter.
+ */
+#define UMBRELLO_EXPORT_PLUGIN_FACTORY(libname, factory) \
+ extern "C" { KDE_EXPORT void *init_##libname() { return new factory(#libname); } }
+
+namespace Umbrello
+{
+// forward declarations
+class PluginLoader;
+
+/**
+ * @ingroup U2_Lib
+ *
+ * The Plugin class is the base class for all modular functionality in
+ * the core Umbrello library. Because Umbrello is a plugin architecture,
+ * this class is derived from many times. Plugins are created via the
+ * KLibFactory of the encapsulating shared library and created from some
+ * other functional object (application, tool or plugin). After the plugin
+ * has been created, the init method is called. Before unloading, the
+ * shutdown method is called. Derived plugins can implement specific
+ * startup/shutdown behavior by overloading the onInit and onShutdown
+ * methods respectively.
+ *
+ * By default, plugins use a configuration group called [LoadActions] in
+ * the config file. Entries in this group define any dependant or on-demand
+ * plugins that should be loaded in conjunction with this plugin. Known
+ * entries (actions) are "Load" and "LoadGUI". Because plugins can be used
+ * by both GUI and command line tools, they must be selective about some
+ * functionality. Specifically, during configuration, a plugin for a tool
+ * must not load GUI plugins.
+ *
+ * In order to provide application-like functionality, this class offers
+ * support for accessing the configuration records of the KInstance object
+ * corresponding to the shared library. Because the KInstance object is
+ * only available within the scope of the shared library, the configuration
+ * records must be set in the constructor of the derived plugin class. However,
+ * because the construction name is passed to this constructor (as are the
+ * parent object and args), we can simply capture the name when the object
+ * is constructed.
+ */
+class Plugin :
+ public QObject,
+ public Configurable
+{
+ Q_OBJECT
+ friend class PluginLoader;
+public:
+ /** Destroy a plugin.*/
+ virtual ~Plugin();
+
+ /** Return the instance name of the plugin */
+ QCString instanceName() const;
+
+ /** Return the configuration record for the plugin */
+ KConfig *config();
+
+ /** Return the category descriptor string */
+ virtual QString category();
+
+ /**
+ * Unload the plugin. This method actually only decrements
+ * the reference count. When the refcount is 0, the object
+ * calls shutdown and deletes itself.
+ */
+ void unload();
+
+protected:
+ /** Construct a plugin */
+ Plugin(QObject *parent, const char *name, const QStringList &args);
+
+ /** Can be reimplemented to define plugin specific startup behavior */
+ virtual bool onInit();
+
+ /** Can be reimplemented to define plugin specific shutdown behavior */
+ virtual bool onShutdown();
+
+private:
+ /**
+ * This method is called by the loader to initialize and configure the
+ * plugin. During initialization, any configured plugins are loaded.
+ * Before loading plugins, onInit is called to perform plugin specific
+ * initialization. This allows dependencies in the plugin chain.
+ *
+ * @return True on success, false on failure.
+ */
+ bool init();
+
+ /**
+ * This method is called by the loader to shutdown the plugin. During
+ * shutdown, any configured plugins are unloaded this occurs before
+ * plugin specific shutdown so as to reduce dependency errors.
+ *
+ * @return True on success, false on failure.
+ */
+ bool shutdown();
+
+ /**
+ * The configure method is called by init to parse the configuration
+ * file and load any plugins. Note that the libraries loaded depends
+ * on the GUI state of the application. If the application is type
+ * Qt::Tty, then we don't use the "loadGUI" action.
+ *
+ * @return True on success, false on failure.
+ */
+ virtual bool configure();
+
+ /** Add to the reference count */
+ void ref();
+
+protected:
+ uint _ref; ///< Reference counter
+ QCString _instanceName; ///< Instance name of the plugin
+ KConfig *_config; ///< Configuration record
+};
+}
+
+#endif
diff --git a/umbrello/umbrello/pluginloader.cpp b/umbrello/umbrello/pluginloader.cpp
new file mode 100644
index 00000000..db79bca1
--- /dev/null
+++ b/umbrello/umbrello/pluginloader.cpp
@@ -0,0 +1,177 @@
+/***************************************************************************
+ begin : Mon Jan 13 2003
+ copyright : (C) 2003 by Andrew Sutton
+ email : ansutton@kent.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. *
+ * *
+ ***************************************************************************/
+
+// own header
+#include "pluginloader.h"
+
+// Qt includes
+#include <qstring.h>
+
+// KDE includes
+#include <kdebug.h>
+#include <klibloader.h>
+
+// u2 includes
+#include "plugin.h"
+
+using namespace Umbrello;
+
+// static data
+PluginLoader *PluginLoader::_instance = NULL;
+
+PluginLoader::PluginLoader() :
+ _plugins(),
+ _categories()
+{
+ // preseed the categories
+ _categories["metamodel"] = PluginList();
+ _categories["storage"] = PluginList();
+ _categories["visual"] = PluginList();
+}
+
+PluginLoader::~PluginLoader()
+{
+}
+
+PluginLoader *
+PluginLoader::instance()
+{
+ if(!_instance) _instance = new PluginLoader;
+ return _instance;
+}
+
+Plugin *
+PluginLoader::loadPlugin(const QString &name)
+{
+ KLibrary *lib = NULL;
+ KLibFactory *factory = NULL;
+ Plugin *plugin = NULL;
+ PluginMap::iterator it;
+ bool success = true;
+
+ // if the plugin has already been loaded, increment
+ // its reference and return.
+ if((it = _plugins.find(name)) != _plugins.end()) {
+ plugin = it.data();
+ plugin->ref();
+ return plugin;
+ }
+
+ // use KLibLoader to get a reference to the library
+ lib = KLibLoader::self()->library(name.latin1());
+ if(!lib) {
+ kdError() << "failed loading plugin library " << name << endl;
+ success = false;
+ }
+
+ // get the factory from the library
+ if(success) {
+ factory = lib->factory();
+ if(!factory) {
+ kdError() << "failed to find factory for " << name << endl;
+ success = false;
+ }
+ }
+
+ // use the factory to create the plugin
+ if(success) {
+ plugin = dynamic_cast<Plugin *>(factory->create((QObject*)0, name.latin1()));
+ if(!plugin) {
+ kdError() << "failed to create a plugin object for " << name << endl;
+ success = false;
+ }
+ else {
+ // we have to register the plugin here, otherwise, we can get
+ // recursive loads
+ _plugins[name] = plugin;
+ _categories[plugin->category()].append(plugin);
+ }
+ }
+
+ // initialize the plugin
+ if(success && plugin) {
+ success = plugin->init();
+ if(!success) {
+ // on failure, delete the plugin. this should cause the
+ // library to unload.
+ kdError() << "failure initializing " << name << endl;
+ _categories[plugin->category()].remove(plugin);
+ _plugins.remove(name);
+ delete plugin;
+ }
+ }
+
+ // finally, finally connect to the destroyed signal and keep a
+ // reference to it
+ if(success) {
+ plugin->ref();
+ connect(plugin, SIGNAL(destroyed(QObject *)), SLOT(slotDestroyed(QObject *)));
+ }
+
+ return plugin;
+}
+
+Plugin *
+PluginLoader::findPlugin(const QString &name)
+{
+ Plugin *ret = NULL;
+ PluginMap::iterator it = _plugins.find(name);
+ if(it != _plugins.end()) {
+ ret = it.data();
+ }
+ return ret;
+}
+
+void
+PluginLoader::unloadPlugin(const QString &name)
+{
+ KLibLoader::self()->unloadLibrary(name.latin1());
+}
+
+const PluginLoader::PluginMap &
+PluginLoader::plugins() const
+{
+ return _plugins;
+}
+
+const PluginLoader::CategoryMap &
+PluginLoader::categories() const
+{
+ return _categories;
+}
+
+void
+PluginLoader::slotDestroyed(QObject *obj)
+{
+ Plugin *plugin = static_cast<Plugin *>(obj);
+
+ // we can't just use the name because its already been destroyed
+ // at this point. we have to iterate thru and find the reference
+ // by hand.
+
+ PluginMap::iterator end(_plugins.end());
+ for(PluginMap::iterator i = _plugins.begin(); i != end; ++i) {
+ Plugin *p = i.data();
+ if(p == plugin) {
+ kdDebug() << "unloading plugin " << i.key() << endl;
+
+ // remove it from the mapping
+ _plugins.remove(i);
+ break;
+ }
+ }
+}
+
+#include "pluginloader.moc"
diff --git a/umbrello/umbrello/pluginloader.h b/umbrello/umbrello/pluginloader.h
new file mode 100644
index 00000000..64ebed6f
--- /dev/null
+++ b/umbrello/umbrello/pluginloader.h
@@ -0,0 +1,132 @@
+/***************************************************************************
+ pluginloader.h
+ -------------------
+ begin : Mon Jan 13 2003
+ copyright : (C) 2003 by Andrew Sutton
+ email : ansutton@kent.edu
+ Bugs and comments to uml-devel@lists.sf.net or http://bugs.kde.org
+***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the 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 UMBRELLO_PLUGINLOADER_H
+#define UMBRELLO_PLUGINLOADER_H
+
+// Qt includes
+#include <qobject.h>
+#include <qvaluelist.h>
+#include <qmap.h>
+
+// forward declarations
+class QString;
+
+namespace Umbrello
+{
+// forward declarations
+class Plugin;
+
+/**
+ * @ingroup U2_Lib
+ *
+ * The plugin loader is an abstraction that sits on top of KLibLoader.
+ * Whereas plugins are specialized shared objects, the plugin must
+ * specialize the loading of those objects. Essentially, the plugin
+ * loader provides a single unit of functionality - loading plugins.
+ * In order to load a plugin, we must first load a shared library
+ * and then use the libraries factory to create the plugin. However,
+ * because a plugin is required to be a singleton, we must ensure
+ * that no plugin is ever created more than once. To that end, the
+ * loader must also retain a map of loaded plugins. When a loaded
+ * plugin is requested, we can increase its reference count.
+ *
+ * On the subject of unloading, we actually have very little to do.
+ * The unload method on a plugin is simply a reference decrementer.
+ * When it reaches 0, the object destroys itself. Being a QObject,
+ * it will emit the destroyed signal just before deletion, allowing
+ * the plugin loader to respond to the event and remove the plugin
+ * from its mapping.
+ *
+ * The PluginLoader also manages categories of plugins. The runtime
+ * categories actually reflect the directory structure of the build
+ * environment with each category represented by the name of a
+ * directory. The categories are "pre-seeded" at startup.
+ *
+ * @bug Plugins are not removed from their respective categories
+ * when they are destroyed. It may be acceptable to call
+ * Plugin::category() from slotDestroyed because the category()
+ * method doesn't reference any local variables - it just returns
+ * a string.
+ */
+class PluginLoader : public QObject
+{
+ Q_OBJECT
+public:
+ /** Destry the plugin loader */
+ ~PluginLoader();
+
+
+ /** Just a container of plugins */
+ typedef QValueList<Plugin *> PluginList;
+
+ /** The containment type for mapping plugins */
+ typedef QMap<QString, Plugin *> PluginMap;
+
+ /** Container of plugin categories */
+ typedef QMap<QString, PluginList> CategoryMap;
+
+ /** Singleton accessor */
+ static PluginLoader *instance();
+
+ /**
+ * Load a plugin. Test to see if the plugin already exists. If it
+ * does, just add a reference to it and continue on.
+ */
+ Plugin *loadPlugin(const QString &name);
+
+ /** Find a plugin */
+ Plugin *findPlugin(const QString &name);
+
+ /**
+ * Unload a plugin. Never use this method. It is only used by the deref
+ * method of a plugin to cause this class to unload the corresponding
+ * library. In fact, there is actually no corresponding plugin to unload,
+ * we just unload the library.
+ */
+ void unloadPlugin(const QString &name);
+
+ /**
+ * Get a reference to the plugin mapping. This method wraps everything
+ * in consts with the express purpose that no changes are made to the
+ * plugin map after using this method.
+ */
+ const PluginMap &plugins() const;
+
+ /** Get a reference to the plugin category mapping. */
+ const CategoryMap &categories() const;
+
+private slots:
+ /**
+ * This is used to connect to the destroyed signal emitted by plugins
+ * when they are finally deleted. The plugin loader uses this signal
+ * to remove the plugin from the plugin map.
+ */
+ void slotDestroyed(QObject *obj);
+
+private:
+ /** Private constructor - This must be created through the instance method */
+ PluginLoader();
+
+ static PluginLoader *_instance; ///< Singleton instance
+ PluginMap _plugins; ///< The plugin mapping
+ CategoryMap _categories; ///< Categories of plugins
+};
+}
+
+#endif
diff --git a/umbrello/umbrello/refactoring/Makefile.am b/umbrello/umbrello/refactoring/Makefile.am
new file mode 100644
index 00000000..4ab82c59
--- /dev/null
+++ b/umbrello/umbrello/refactoring/Makefile.am
@@ -0,0 +1,8 @@
+noinst_LTLIBRARIES = librefactoring.la
+
+INCLUDES = -I$(top_srcdir) -I$(top_builddir)/umbrello/umbrello/dialogs $(all_includes)
+
+librefactoring_la_METASOURCES = AUTO
+
+librefactoring_la_SOURCES = refactoringassistant.cpp
+
diff --git a/umbrello/umbrello/refactoring/refactoringassistant.cpp b/umbrello/umbrello/refactoring/refactoringassistant.cpp
new file mode 100644
index 00000000..0cbcf6aa
--- /dev/null
+++ b/umbrello/umbrello/refactoring/refactoringassistant.cpp
@@ -0,0 +1,701 @@
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * copyright (C) 2003 Luis De la Parra <lparrab@gmx.net> *
+ * copyright (C) 2004-2007 *
+ * Umbrello UML Modeller Authors <uml-devel@uml.sf.net> *
+ ***************************************************************************/
+
+#include "refactoringassistant.h"
+
+#include "../umlnamespace.h"
+#include "../umldoc.h"
+#include "../classifier.h"
+#include "../attribute.h"
+#include "../operation.h"
+#include "../dialogs/classpropdlg.h"
+#include "../dialogs/umloperationdialog.h"
+#include "../dialogs/umlattributedialog.h"
+#include "../object_factory.h"
+
+#include <qpoint.h>
+#include <qpopupmenu.h>
+
+#include <typeinfo>
+#include <kstandarddirs.h>
+#include <kiconloader.h>
+#include <klocale.h>
+#include <kmessagebox.h>
+#include <kdebug.h>
+
+using std::type_info;
+
+
+RefactoringAssistant::RefactoringAssistant( UMLDoc *doc, UMLClassifier *obj, QWidget *parent, const char *name ):
+ KListView( parent, name ), m_doc( doc )
+{
+ loadPixmaps();
+
+ setRootIsDecorated( true );
+ setAcceptDrops( true );
+ setDropVisualizer( false );
+ setItemsMovable( true );
+ setSelectionModeExt( Single );
+ setShowToolTips( true );
+ setTooltipColumn( 0 );
+ setDragEnabled( true );
+ setDropHighlighter( true );
+ setFullWidth( true );
+ setSorting( -1 );
+
+ addColumn("Name ");
+
+ m_menu = new QPopupMenu(this);
+
+ connect(this,SIGNAL(doubleClicked(QListViewItem*)),this,SLOT(itemExecuted(QListViewItem*)));
+ connect(this,SIGNAL(contextMenu(KListView*, QListViewItem*, const QPoint&)),
+ this,SLOT(showContextMenu(KListView*,QListViewItem*,const QPoint&)));
+
+ resize(300,400);
+
+ refactor( obj );
+}
+
+RefactoringAssistant::~RefactoringAssistant()
+{
+ m_umlObjectMap.clear();
+ clear();
+}
+
+void RefactoringAssistant::refactor( UMLClassifier *obj )
+{
+ clear();
+ m_umlObjectMap.clear();
+ m_umlObject = obj;
+ if (! m_umlObject )
+ {
+ return;
+ }
+
+ addClassifier( obj, 0, true, true, true );
+ QListViewItem *item = firstChild();
+ item->setOpen(true);
+ for( item = item->firstChild(); item ; item = item->nextSibling() )
+ item->setOpen(true);
+}
+
+
+UMLObject* RefactoringAssistant::findUMLObject( const QListViewItem *item )
+{
+ QListViewItem *i = const_cast<QListViewItem*>(item);
+ if( m_umlObjectMap.find(i) == m_umlObjectMap.end() )
+ {
+ kWarning()<<"RefactoringAssistant::findUMLObject( QListViewItem *item )"
+ <<"item with text "<<item->text(0)<<"not found in uml map!"<<endl;
+ return 0L;
+ }
+ return m_umlObjectMap[i];
+
+}
+
+QListViewItem* RefactoringAssistant::findListViewItem( const UMLObject *obj )
+{
+ UMLObjectMap::iterator end(m_umlObjectMap.end());
+ for( UMLObjectMap::iterator it(m_umlObjectMap.begin()) ; it != end ; ++it )
+ if( (*it).second == obj )
+ return (*it).first;
+ kWarning() << "RefactoringAssistant::findListViewItem:"
+ << "object id " << ID2STR(obj->getID())
+ << "does not have a ListItem" << endl;
+ return 0L;
+}
+
+
+void RefactoringAssistant::itemExecuted( QListViewItem *item )
+{
+ UMLObject *o = findUMLObject( item );
+ if(o) editProperties( );
+}
+
+void RefactoringAssistant::setVisibilityIcon( QListViewItem *item , const UMLObject *obj )
+{
+ switch(obj->getVisibility())
+ {
+ case Uml::Visibility::Public:
+ item->setPixmap(0,m_pixmaps.Public);
+ break;
+ case Uml::Visibility::Protected:
+ item->setPixmap(0,m_pixmaps.Protected);
+ break;
+ case Uml::Visibility::Private:
+ item->setPixmap(0,m_pixmaps.Private);
+ break;
+ case Uml::Visibility::Implementation:
+ item->setPixmap(0,m_pixmaps.Implementation);
+ break;
+ break;
+ }
+}
+
+void RefactoringAssistant::umlObjectModified( const UMLObject *obj )
+{
+ if( !obj )
+ obj = dynamic_cast<const UMLObject*>(sender());
+ QListViewItem *item = findListViewItem( obj );
+ if( !item )
+ return;
+ item->setText( 0, obj->getName() );
+ if( typeid(*obj) == typeid(UMLOperation) ||
+ typeid(*obj) == typeid(UMLAttribute) )
+ {
+ setVisibilityIcon( item, obj );
+ }
+}
+
+void RefactoringAssistant::operationAdded( UMLClassifierListItem *o )
+{
+ UMLOperation *op = static_cast<UMLOperation*>(o);
+ UMLClassifier *c = dynamic_cast<UMLClassifier*>(op->parent());
+ if(!c)
+ {
+ kWarning() << "RefactoringAssistant::operationAdded(" << op->getName()
+ << ") - Parent of operation is not a classifier!" << endl;
+ return;
+ }
+ QListViewItem *item = findListViewItem( c );
+ if( !item )
+ {
+ return;
+ }
+ for( QListViewItem *folder = item->firstChild(); folder; folder = folder->nextSibling() )
+ {
+ if( folder->text(1) == "operations" )
+ {
+ item = new KListViewItem( folder, op->getName() );
+ m_umlObjectMap[item] = op;
+ connect( op, SIGNAL( modified() ), this, SLOT( umlObjectModified() ) );
+ setVisibilityIcon( item, op );
+ break;
+ }
+ }
+}
+
+void RefactoringAssistant::operationRemoved( UMLClassifierListItem *o )
+{
+ UMLOperation *op = static_cast<UMLOperation*>(o);
+ QListViewItem *item = findListViewItem( op );
+ if( !item )
+ {
+ return;
+ }
+ disconnect( op, SIGNAL( modified() ), this, SLOT( umlObjectModified() ) );
+ m_umlObjectMap.erase(item);
+ delete item;
+}
+
+
+void RefactoringAssistant::attributeAdded( UMLClassifierListItem *a )
+{
+ UMLAttribute *att = static_cast<UMLAttribute*>(a);
+ UMLClassifier *c = dynamic_cast<UMLClassifier*>(att->parent());
+ if(!c)
+ {
+ kWarning() << "RefactoringAssistant::attributeAdded(" << att->getName()
+ << ") - Parent is not a class!" << endl;
+ return;
+ }
+ QListViewItem *item = findListViewItem( c );
+ if( !item )
+ {
+ return;
+ }
+ for( QListViewItem *folder = item->firstChild(); folder; folder = folder->nextSibling() )
+ {
+ if( folder->text(1) == "attributes" )
+ {
+ item = new KListViewItem( folder, att->getName() );
+ m_umlObjectMap[item] = att;
+ connect( att, SIGNAL( modified() ), this, SLOT( umlObjectModified() ) );
+ setVisibilityIcon( item, att );
+ break;
+ }
+ }
+}
+
+void RefactoringAssistant::attributeRemoved( UMLClassifierListItem *a )
+{
+ UMLAttribute *att = static_cast<UMLAttribute*>(a);
+ QListViewItem *item = findListViewItem( att );
+ if( !item )
+ {
+ return;
+ }
+ disconnect( att, SIGNAL( modified() ), this, SLOT( umlObjectModified() ) );
+ m_umlObjectMap.erase(item);
+ delete item;
+}
+
+void RefactoringAssistant::editProperties( )
+{
+ QListViewItem *item = selectedItem();
+ if( item )
+ {
+ UMLObject *o = findUMLObject( item );
+ if( o ) editProperties( o );
+ }
+}
+
+void RefactoringAssistant::editProperties( UMLObject *obj )
+{
+ KDialogBase *dia(0);
+ Uml::Object_Type t = obj->getBaseType();
+ if (t == Uml::ot_Class || t == Uml::ot_Interface)
+ {
+ dia = new ClassPropDlg(this,obj,0,true);
+ }
+ else if (t == Uml::ot_Operation)
+ {
+ dia = new UMLOperationDialog(this,static_cast<UMLOperation*>(obj));
+ }
+ else if (t == Uml::ot_Attribute)
+ {
+ dia = new UMLAttributeDialog(this,static_cast<UMLAttribute*>(obj));
+ }
+ else
+ {
+ kWarning()<<"RefactoringAssistant::editProperties( UMLObject *o ) caled for unknown type "<<typeid(*obj).name()<<endl;
+ return;
+ }
+ if( dia && dia->exec() )
+ {
+ // need to update something?
+ }
+ delete dia;
+}
+
+void RefactoringAssistant::showContextMenu(KListView* ,QListViewItem *item, const QPoint &p)
+{
+ m_menu->clear();
+ UMLObject *obj = findUMLObject( item );
+ if(obj)
+ {// Menu for UMLObjects
+ Uml::Object_Type t = obj->getBaseType();
+ if (t == Uml::ot_Class)
+ {
+ m_menu->insertItem(i18n("Add Base Class"),this,SLOT(addBaseClassifier()));
+ m_menu->insertItem(i18n("Add Derived Class"),this,SLOT(addDerivedClassifier()));
+ // m_menu->insertItem(i18n("Add Interface Implementation"),this,SLOT(addInterfaceImplementation()));
+ m_menu->insertItem(i18n("Add Operation"),this,SLOT(createOperation()));
+ m_menu->insertItem(i18n("Add Attribute"),this,SLOT(createAttribute()));
+ }
+ else if (t == Uml::ot_Interface)
+ {
+ m_menu->insertItem(i18n("Add Base Interface"),this,SLOT(addSuperClassifier()));
+ m_menu->insertItem(i18n("Add Derived Interface"),this,SLOT(addDerivedClassifier()));
+ m_menu->insertItem(i18n("Add Operation"),this,SLOT(createOperation()));
+ }
+ // else
+ // {
+ // kDebug()<<"No context menu for objects of type "<<typeid(*obj).name()<<endl;
+ // return;
+ // }
+ m_menu->insertSeparator();
+ m_menu->insertItem(i18n("Properties"),this,SLOT(editProperties()));
+ }
+ else
+ {//menu for other ViewItems
+ if( item->text(1) == "operations" )
+ {
+ m_menu->insertItem(i18n("Add Operation"),this,SLOT(createOperation()));
+ }
+ else if( item->text(1) == "attributes" )
+ {
+ m_menu->insertItem(i18n("Add Attribute"),this,SLOT(createAttribute()));
+ }
+ else
+ {
+ kWarning()<<"RefactoringAssistant::showContextMenu() "
+ <<"called for extraneous item"<<endl;
+ return;
+ }
+ }
+ m_menu->exec(p);
+}
+
+void RefactoringAssistant::addBaseClassifier()
+{
+ QListViewItem *item = selectedItem();
+ if(!item)
+ {
+ kWarning()<<"RefactoringAssistant::addBaseClassifier() "
+ <<"called with no item selected"<<endl;
+ return;
+ }
+ UMLObject *obj = findUMLObject( item );
+ if( !dynamic_cast<UMLClassifier*>(obj) )
+ {
+ kWarning()<<"RefactoringAssistant::addBaseClassifier() "
+ <<"called for a non-classifier object"<<endl;
+ return;
+ }
+
+ //classes have classes and interfaces interfaces as super/derived classifiers
+ Uml::Object_Type t = obj->getBaseType();
+ UMLClassifier *super = static_cast<UMLClassifier*>(Object_Factory::createUMLObject(t));
+ if(!super)
+ return;
+ m_doc->createUMLAssociation( obj, super, Uml::at_Generalization );
+ ////////////////////// Manually add the classifier to the assitant - would be nicer to do it with
+ ///////////////////// a signal, like operations and attributes
+ QListViewItem *baseFolder = item->firstChild();
+ while( baseFolder->text(0) != i18n("Base Classifiers") )
+ baseFolder = baseFolder->nextSibling();
+ if(!baseFolder)
+ {
+ kWarning()<<"Cannot find Base Folder"<<endl;
+ return;
+ }
+ item = new KListViewItem( baseFolder, super->getName() );
+ item->setPixmap(0,m_pixmaps.Generalization);
+ item->setExpandable( true );
+ m_umlObjectMap[item] = super;
+ addClassifier( super, item, true, false, true);
+ /////////////////////////
+}
+
+void RefactoringAssistant::addDerivedClassifier()
+{
+ QListViewItem *item = selectedItem();
+ if(!item)
+ {
+ kWarning()<<"RefactoringAssistant::addDerivedClassifier() "
+ <<"called with no item selected"<<endl;
+ return;
+ }
+ UMLObject *obj = findUMLObject( item );
+ if( !dynamic_cast<UMLClassifier*>(obj) )
+ {
+ kWarning()<<"RefactoringAssistant::addDerivedClassifier() "
+ <<"called for a non-classifier object"<<endl;
+ return;
+ }
+
+ //classes have classes and interfaces interfaces as super/derived classifiers
+ Uml::Object_Type t = obj->getBaseType();
+ UMLClassifier *derived = static_cast<UMLClassifier*>(Object_Factory::createUMLObject(t));
+ if(!derived)
+ return;
+ m_doc->createUMLAssociation( derived, obj, Uml::at_Generalization );
+
+ ////////////////////// Manually add the classifier to the assitant - would be nicer to do it with
+ ///////////////////// a signal, like operations and attributes
+ QListViewItem *derivedFolder = item->firstChild();
+ while( derivedFolder->text(0) != i18n("Derived Classifiers") )
+ derivedFolder = derivedFolder->nextSibling();
+ if(!derivedFolder)
+ {
+ kWarning()<<"Cannot find Derived Folder"<<endl;
+ return;
+ }
+ item = new KListViewItem( derivedFolder, derived->getName() );
+ item->setPixmap(0,m_pixmaps.Subclass);
+ item->setExpandable( true );
+ m_umlObjectMap[item] = derived;
+ addClassifier( derived, item, false, true, true);
+ /////////////////////////
+}
+
+void RefactoringAssistant::addInterfaceImplementation()
+{
+ kWarning()<<"RefactoringAssistant::addInterfaceImplementation()"
+ <<"not implemented... finish addSuperClassifier() first!!"<<endl;
+ return;
+ // QListViewItem *item = selectedListViewItem( );
+ // UMLObject *obj = findUMLObject( item );
+ // if( !dynamic_cast<UMLClassifier*>(obj) )
+ // return;
+ // UMLObject *n = Object_Factory::createUMLObject( Uml::ot_Interface) );
+ // if(!n)
+ // return;
+ // m_doc->createUMLAssociation( n, obj, Uml::at_Realization );
+ // //refresh, add classifier to assistant
+}
+
+void RefactoringAssistant::createOperation()
+{
+ QListViewItem *item = selectedItem();
+ if(!item)
+ {
+ kWarning()<<"RefactoringAssistant::createOperation() "
+ <<"called with no item selected"<<endl;
+ return;
+ }
+ UMLClassifier *c = dynamic_cast<UMLClassifier*>(findUMLObject( item ));
+ if( !c )
+ return;
+ c->createOperation();
+}
+
+void RefactoringAssistant::createAttribute()
+{
+ QListViewItem *item = selectedItem();
+ if(!item)
+ {
+ kWarning()<<"RefactoringAssistant::createAttribute() "
+ <<"called with no item selected"<<endl;
+ return;
+ }
+ UMLClassifier *c = dynamic_cast<UMLClassifier*>(findUMLObject( item ));
+ if( !c )
+ return;
+ c->createAttribute();
+}
+
+
+void RefactoringAssistant::addClassifier( UMLClassifier *classifier, QListViewItem *parent, bool addSuper, bool addSub, bool recurse)
+{
+ QListViewItem *classifierItem, *item;
+ if( parent )
+ {
+ classifierItem = parent;
+ }
+ else
+ {
+ classifierItem= new KListViewItem( this, classifier->getName() );
+ m_umlObjectMap[classifierItem] = classifier;
+ }
+
+ connect( classifier, SIGNAL( modified() ), this, SLOT( umlObjectModified() ) );
+
+ UMLClassifier *klass = dynamic_cast<UMLClassifier*>(classifier);
+ if( klass )
+ {// only Classes have attributes...
+ connect( classifier, SIGNAL(attributeAdded(UMLClassifierListItem*)),
+ this, SLOT(attributeAdded(UMLClassifierListItem*)));
+ connect( classifier, SIGNAL(attributeRemoved(UMLClassifierListItem*)),
+ this, SLOT(attributeRemoved(UMLClassifierListItem*)));
+
+ QListViewItem *attsFolder = new KListViewItem( classifierItem, i18n("Attributes"), "attributes" );
+ attsFolder->setPixmap(0,SmallIcon("folder_green_open"));
+ attsFolder->setExpandable( true );
+ UMLAttributeList atts = klass->getAttributeList();
+ for( UMLAttribute *att = atts.first(); att; att = atts.next() )
+ {
+ attributeAdded( att );
+ }
+
+ }
+
+ // add operations
+ connect( classifier, SIGNAL(operationAdded(UMLClassifierListItem*)),
+ this, SLOT(operationAdded(UMLClassifierListItem*)));
+ connect( classifier, SIGNAL(operationRemoved(UMLClassifierListItem*)),
+ this, SLOT(operationRemoved(UMLClassifierListItem*)));
+
+ QListViewItem *opsFolder = new KListViewItem( classifierItem, i18n("Operations"), "operations" );
+ opsFolder->setPixmap(0,SmallIcon("folder_blue_open"));
+ opsFolder->setExpandable( true );
+ UMLOperationList ops(classifier->getOpList());
+ for( UMLOperation *op = ops.first(); op ; op = ops.next() )
+ {
+ operationAdded( op );
+ }
+
+ //if add parents
+ if(addSuper)
+ {
+ QListViewItem *superFolder = new KListViewItem( classifierItem, i18n("Base Classifiers") );
+ superFolder->setExpandable( true );
+ UMLClassifierList super = classifier->findSuperClassConcepts();
+ for( UMLClassifier *cl = super.first(); cl ; cl = super.next() )
+ {
+ item = new KListViewItem( superFolder, cl->getName() );
+ item->setPixmap(0,m_pixmaps.Generalization);
+ item->setExpandable( true );
+ m_umlObjectMap[item] = cl;
+ if( recurse )
+ {
+ addClassifier( cl, item, true, false, true);
+ }
+
+ }
+ }
+ if(addSub)
+ {
+ //add derived classifiers
+ QListViewItem *derivedFolder = new KListViewItem( classifierItem, i18n("Derived Classifiers") );
+ derivedFolder->setExpandable( true );
+ UMLClassifierList derived = classifier->findSubClassConcepts();
+ for( UMLClassifier *d = derived.first(); d ; d = derived.next() )
+ {
+ item = new KListViewItem( derivedFolder, d->getName() );
+ item->setPixmap(0,m_pixmaps.Subclass);
+ item->setExpandable( true );
+ m_umlObjectMap[item] = d;
+ if( recurse )
+ {
+ addClassifier( d, item, false, true, true);
+ }
+
+ }
+ }
+}
+
+
+bool RefactoringAssistant::acceptDrag(QDropEvent *event) const
+{
+ //first check if we can accept drops at all, and if the operation
+ // is a move within the list itself
+ if( !acceptDrops() || !itemsMovable() || (event->source()!=viewport()))
+ {
+ return false;
+ }
+
+ RefactoringAssistant *me = const_cast<RefactoringAssistant*>(this);
+
+ //ok, check if the move is valid
+ QListViewItem *movingItem = 0, *afterme = 0, *parentItem = 0;
+ me->findDrop(event->pos(), parentItem, afterme);
+ for( movingItem = firstChild(); movingItem != 0; movingItem = movingItem->itemBelow() )
+ {
+ if( movingItem->isSelected() )
+ break;
+ }
+ if(!movingItem || !parentItem)
+ { kDebug()<<"moving/parent items not found - can't accept drag!"<<endl;
+ return false;
+ }
+
+ UMLObject *movingObject;
+ if( !(movingObject = me->findUMLObject(movingItem)) )
+ {
+ kDebug()<<"Moving object not found in uml map!"<<movingItem->text(0)<<endl;
+ return false;
+ }
+ Uml::Object_Type t = movingObject->getBaseType();
+ if (t != Uml::ot_Attribute && t != Uml::ot_Operation)
+ {
+ kDebug()<<"only operations and attributes are movable! - return false"<<endl;
+ return false;
+ }
+
+ kDebug()<<"parent item is "<<parentItem->text(0)<<endl;
+ UMLObject *parentObject = me->findUMLObject(parentItem);
+ if( parentObject && dynamic_cast<UMLClassifier*>(parentObject) )
+ {
+ //droping to a classifier, ok
+ }
+ else
+ {//parent is not a classifier, so maybe it's a folder.. check types
+ if( (parentItem->text(1) == "operations" && t == Uml::ot_Operation)
+ || (parentItem->text(1) == "attributes" && t == Uml::ot_Attribute))
+ {
+ parentObject = me->findUMLObject( parentItem->parent() );
+ }
+ else
+ {
+ kDebug()<<"moving to item "<<parentItem->text(0)<<" -- "<<parentItem->text(1)<<" not valid"<<endl;
+ return false;
+ }
+ }
+ if (dynamic_cast<UMLClassifier*>(parentObject) &&
+ (t == Uml::ot_Attribute || t == Uml::ot_Operation))
+ {
+ return true;
+ }
+
+ kDebug()<<"how did I get here? return false!!"<<endl;
+ return false;
+}
+
+
+void RefactoringAssistant::movableDropEvent (QListViewItem* parentItem, QListViewItem* afterme)
+{
+ //when dropping on a class, we have to put the item in the appropriate folder!
+ UMLObject *movingObject;
+ UMLClassifier *newClassifier;
+ QListViewItem *movingItem;
+
+ for( movingItem = firstChild(); movingItem != 0; movingItem = movingItem->itemBelow() )
+ {
+ if( movingItem->isSelected() )
+ break;
+ }
+ if( !movingItem || (movingItem == afterme) || !(movingObject = findUMLObject(movingItem)) )
+ {
+ kWarning()<<"Moving item not found or dropping after itself or item not found in uml obj map. aborting. (drop had already been accepted)"<<endl;
+ return;
+ }
+ Uml::Object_Type t = movingObject->getBaseType();
+ newClassifier = dynamic_cast<UMLClassifier*>( findUMLObject( parentItem ) );
+ if(!newClassifier)
+ {
+ if ((parentItem->text(1) == "operations" && t == Uml::ot_Operation)
+ || (parentItem->text(1) == "attributes" && t == Uml::ot_Attribute))
+ {
+ newClassifier = dynamic_cast<UMLClassifier*>( findUMLObject( parentItem->parent() ) );
+ }
+ if(!newClassifier)
+ {
+ kWarning()<<"New parent of object is not a Classifier - Drop had already been accepted - check!"<<endl;
+ return;
+ }
+ }
+ if (t == Uml::ot_Operation)
+ {kDebug()<<"moving operation"<<endl;
+ UMLOperation *op = static_cast<UMLOperation*>(movingObject);
+ if(newClassifier->checkOperationSignature(op->getName(), op->getParmList()))
+ {
+ QString msg = QString(i18n("An operation with that signature already exists in %1.\n")).arg(newClassifier->getName())
+ +
+ QString(i18n("Choose a different name or parameter list." ));
+ KMessageBox::error(this, msg, i18n("Operation Name Invalid"), false);
+ return;
+ }
+ UMLClassifier *oldClassifier = dynamic_cast<UMLClassifier*>(op->parent());
+ if(oldClassifier)
+ oldClassifier->removeOperation( op );
+ newClassifier->addOperation( op );
+ }
+ else if (t == Uml::ot_Attribute)
+ {kDebug()<<"moving attribute - not implemented"<<endl;
+ // UMLAttribute *att = static_cast<UMLAttribute*>(movingObject);
+ // if(!newClassifier->checkAttributeSignature(att))
+ // {
+ // QString msg = QString(i18n("An attribute with that signature already exists in %1.\n")).arg(newClassifier->getName())
+ // +
+ // QString(i18n("Choose a different name or parameter list." ));
+ // KMessageBox::error(this, msg, i18n("Operation Name Invalid"), false);
+ // return;
+ // }
+ // oldClassifier->removeAttribute( att );
+ // newClassifier->addAttribute( att );
+ }
+ //emit moved(moving, afterFirst, afterme);
+ emit moved();
+}
+
+void RefactoringAssistant::loadPixmaps()
+{
+ KStandardDirs *dirs = KGlobal::dirs();
+ QString dataDir = dirs -> findResourceDir( "data", "umbrello/pics/object.png" );
+ dataDir += "/umbrello/pics/";
+
+ m_pixmaps.Public.load( dataDir + "CVpublic_var.png" );
+ m_pixmaps.Protected.load( dataDir + "CVprotected_var.png" );
+ m_pixmaps.Private.load( dataDir + "CVprivate_var.png" );
+ m_pixmaps.Implementation.load( dataDir + "CVimplementation_var.png" );
+ m_pixmaps.Generalization.load( dataDir + "generalisation.png" );
+ m_pixmaps.Subclass.load( dataDir + "uniassociation.png" );
+
+
+}
+
+
+
+
+#include "refactoringassistant.moc"
diff --git a/umbrello/umbrello/refactoring/refactoringassistant.h b/umbrello/umbrello/refactoring/refactoringassistant.h
new file mode 100644
index 00000000..5d8bd79f
--- /dev/null
+++ b/umbrello/umbrello/refactoring/refactoringassistant.h
@@ -0,0 +1,89 @@
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * copyright (C) 2003 Luis De la Parra <lparrab@gmx.net> *
+ * copyright (C) 2004-2007 *
+ * Umbrello UML Modeller Authors <uml-devel@uml.sf.net> *
+ ***************************************************************************/
+
+
+#ifndef REFACTORING_ASSISTANT
+#define REFACTORING_ASSISTANT
+
+
+#include <klistview.h>
+#include <qpixmap.h>
+#include <map>
+
+
+class UMLObject;
+class UMLClassifier;
+class UMLClassifierListItem;
+class UMLDoc;
+
+class QPopupMenu;
+class QPoint;
+
+class RefactoringAssistant : public KListView
+{
+ Q_OBJECT
+public:
+ typedef std::map<QListViewItem*, UMLObject*> UMLObjectMap;
+
+ explicit RefactoringAssistant( UMLDoc *doc, UMLClassifier *obj = 0, QWidget *parent = 0, const char *name = 0 );
+ virtual ~RefactoringAssistant();
+
+ void refactor( UMLClassifier *obj );
+
+public slots:
+
+ void addBaseClassifier();
+ void addDerivedClassifier();
+ void addInterfaceImplementation();
+ void createOperation( );
+ void createAttribute( );
+ void editProperties( );
+
+ void umlObjectModified( const UMLObject *obj = 0 );
+
+ void operationAdded( UMLClassifierListItem *o );
+ void operationRemoved( UMLClassifierListItem *o );
+
+ void attributeAdded( UMLClassifierListItem *a );
+ void attributeRemoved( UMLClassifierListItem *a );
+
+ void itemExecuted( QListViewItem *item );
+ void showContextMenu( KListView*, QListViewItem*, const QPoint&);
+
+protected:
+ struct { QPixmap Public,
+ Protected,
+ Private,
+ Implementation,
+ Generalization,
+ Subclass;
+ } m_pixmaps;
+
+ UMLObject* findUMLObject( const QListViewItem* );
+ QListViewItem* findListViewItem( const UMLObject *obj );
+ void editProperties( UMLObject *obj );
+ void addClassifier( UMLClassifier *classifier, QListViewItem *parent = 0, bool addSuper = true, bool addSub = true, bool recurse = false );
+ void loadPixmaps();
+ virtual bool acceptDrag(QDropEvent *event) const;
+ virtual void movableDropEvent (QListViewItem* parent, QListViewItem* afterme);
+ void setVisibilityIcon( QListViewItem *item , const UMLObject *obj );
+ UMLClassifier *m_umlObject;
+ UMLDoc *m_doc;
+ QPopupMenu *m_menu;
+ UMLObjectMap m_umlObjectMap;
+
+
+};
+
+
+#endif
+
diff --git a/umbrello/umbrello/seqlinewidget.cpp b/umbrello/umbrello/seqlinewidget.cpp
new file mode 100644
index 00000000..a4be0216
--- /dev/null
+++ b/umbrello/umbrello/seqlinewidget.cpp
@@ -0,0 +1,124 @@
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * copyright (C) 2002-2007 *
+ * Umbrello UML Modeller Authors <uml-devel@uml.sf.net> *
+ ***************************************************************************/
+
+// own header
+#include "seqlinewidget.h"
+
+//kde includes
+#include <kcursor.h>
+#include <kdebug.h>
+//app includes
+#include "umlview.h"
+#include "objectwidget.h"
+#include "messagewidget.h"
+
+// class members
+int const SeqLineWidget::m_nMouseDownEpsilonX = 20;
+
+SeqLineWidget::SeqLineWidget( UMLView * pView, ObjectWidget * pObject ) : QCanvasLine( pView -> canvas() ) {
+ m_pView = pView;
+ m_pObject = pObject;
+ setPen( QPen( m_pObject->getLineColor(), 0, Qt::DashLine ) );
+ setZ( 0 );
+ setVisible( true );
+ m_DestructionBox.line1 = 0;
+ m_nLengthY = 250;
+ setupDestructionBox();
+}
+
+SeqLineWidget::~SeqLineWidget() {}
+
+int SeqLineWidget::onWidget( const QPoint & p ) {
+ int nOnWidget = 0;
+ QPoint sp = startPoint();
+ QPoint ep = endPoint();
+ //see if on widget ( for message creation )
+ if( sp.x() - m_nMouseDownEpsilonX < p.x()
+ && ep.x() + m_nMouseDownEpsilonX > p.x()
+ && sp.y() < p.y() && ep.y() + 3 > p.y() )
+ {
+ nOnWidget = 1;
+ }
+ return nOnWidget;
+}
+
+void SeqLineWidget::cleanup() {
+ cleanupDestructionBox();
+}
+
+void SeqLineWidget::setStartPoint( int startX, int startY ) {
+ int endX = startX;
+ int endY = startY + m_nLengthY;
+ QCanvasLine::setPoints( startX, startY, endX, endY );
+ moveDestructionBox();
+}
+
+void SeqLineWidget::cleanupDestructionBox() {
+ if ( m_DestructionBox.line1 ) {
+ delete m_DestructionBox.line1;
+ m_DestructionBox.line1 = 0;
+ delete m_DestructionBox.line2;
+ m_DestructionBox.line2 = 0;
+ }
+}
+
+void SeqLineWidget::setupDestructionBox() {
+ cleanupDestructionBox();
+ if( !m_pObject->getShowDestruction() ) {
+ return;
+ }
+ QRect rect;
+ rect.setX( m_pObject->getX() + m_pObject->getWidth() / 2 - 10 );
+ rect.setY( m_pObject->getY() + m_pObject->getHeight() + m_nLengthY );
+ rect.setWidth( 14 );
+ rect.setHeight( 14 );
+
+ m_DestructionBox.line1 = new QCanvasLine( m_pView->canvas() );
+ m_DestructionBox.setLine1Points(rect);
+ m_DestructionBox.line1->setVisible( true );
+ m_DestructionBox.line1->setPen( QPen(m_pObject->getLineColor(), 2) );
+ m_DestructionBox.line1->setZ( 3 );
+
+ m_DestructionBox.line2 = new QCanvasLine( m_pView -> canvas() );
+ m_DestructionBox.setLine2Points(rect);
+ m_DestructionBox.line2->setVisible( true );
+ m_DestructionBox.line2->setPen( QPen(m_pObject->getLineColor(), 2) );
+ m_DestructionBox.line2->setZ( 3 );
+}
+
+void SeqLineWidget::moveDestructionBox() {
+ if( !m_DestructionBox.line1 ) {
+ return;
+ }
+ QRect rect;
+ rect.setX( m_pObject->getX() + m_pObject->getWidth() / 2 - 7 );
+ rect.setY( m_pObject->getY() + m_pObject->getHeight() + m_nLengthY - 7 );
+ rect.setWidth( 14 );
+ rect.setHeight( 14 );
+ m_DestructionBox.setLine1Points(rect);
+ m_DestructionBox.setLine2Points(rect);
+}
+
+void SeqLineWidget::setEndOfLine(int yPosition) {
+ QPoint sp = startPoint();
+ int newY = yPosition;
+ m_nLengthY = yPosition - m_pObject->getY() - m_pObject->getHeight();
+ // normally the managing Objectwidget is responsible for the call of this function
+ // but to be sure - make a double check _against current position_
+ if ( m_nLengthY < 0 ) {
+ m_nLengthY = 0;
+ newY = m_pObject->getY() + m_pObject->getHeight();
+ }
+ setPoints( sp.x(), sp.y(), sp.x(), newY );
+ moveDestructionBox();
+ m_pView->resizeCanvasToItems();
+}
+
diff --git a/umbrello/umbrello/seqlinewidget.h b/umbrello/umbrello/seqlinewidget.h
new file mode 100644
index 00000000..1978fafd
--- /dev/null
+++ b/umbrello/umbrello/seqlinewidget.h
@@ -0,0 +1,135 @@
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * copyright (C) 2002-2007 *
+ * Umbrello UML Modeller Authors <uml-devel@uml.sf.net> *
+ ***************************************************************************/
+
+#ifndef SEQLINEWIDGET_H
+#define SEQLINEWIDGET_H
+
+#include <qcanvas.h>
+
+class UMLView;
+class ObjectWidget;
+
+/**
+ * @short Widget class for graphical representation of sequence lines
+ * @author Paul Hensgen
+ * Bugs and comments to uml-devel@lists.sf.net or http://bugs.kde.org
+ */
+class SeqLineWidget : public QCanvasLine {
+public:
+ /**
+ * Constructor.
+ */
+ SeqLineWidget( UMLView * pView, ObjectWidget * pObject );
+
+ /**
+ * Destructor.
+ */
+ ~SeqLineWidget();
+
+ /**
+ * Return whether on seq. line.
+ * Takes into account destruction box if shown.
+ *
+ * @param p The point to investigate.
+ * @return Non-zero if point is on this sequence line.
+ */
+ int onWidget(const QPoint & p);
+
+ /**
+ * Clean up anything before deletion.
+ */
+ void cleanup();
+
+ /**
+ * Set up destruction box.
+ */
+ void setupDestructionBox();
+
+ /**
+ * Set the start point of the line.
+ *
+ * @param startX X coordinate of the start point.
+ * @param startY Y coordinate of the start point.
+ */
+ void setStartPoint( int startX, int startY );
+
+ /**
+ * Gets the length of the line.
+ *
+ * @return Length of the line.
+ */
+ int getLineLength() {
+ return m_nLengthY;
+ }
+
+ /**
+ * Returns the @ref ObjectWidget associated with this sequence line.
+ *
+ * @return Pointer to the associated ObjectWidget.
+ */
+ ObjectWidget * getObjectWidget() {
+ return m_pObject;
+ }
+
+ /**
+ * Sets the y position of the bottom of the vertical line.
+ *
+ * @param yPosition The y coordinate for the bottom of the line.
+ */
+ void setEndOfLine(int yPosition);
+
+protected:
+ /**
+ * Clean up destruction box.
+ */
+ void cleanupDestructionBox();
+
+ /**
+ * Move destruction box.
+ */
+ void moveDestructionBox();
+
+ /**
+ * ObjectWidget associated with this sequence line.
+ */
+ ObjectWidget * m_pObject;
+
+ /**
+ * View displayed on.
+ */
+ UMLView * m_pView;
+
+ /// The destruction box.
+ struct DestructionBox {
+ QCanvasLine * line1;
+ QCanvasLine * line2;
+ void setLine1Points(QRect rect) {
+ line1->setPoints( rect.x(), rect.y(),
+ rect.x() + rect.width(), rect.y() + rect.height() );
+ }
+ void setLine2Points(QRect rect) {
+ line2->setPoints( rect.x(), rect.y() + rect.height(),
+ rect.x() + rect.width(), rect.y() );
+ }
+ } m_DestructionBox;
+
+ /**
+ * The length of the line.
+ */
+ int m_nLengthY;
+
+ /**
+ * Margin used for mouse clicks.
+ */
+ static int const m_nMouseDownEpsilonX;
+};
+
+#endif
diff --git a/umbrello/umbrello/statewidget.cpp b/umbrello/umbrello/statewidget.cpp
new file mode 100644
index 00000000..9d104234
--- /dev/null
+++ b/umbrello/umbrello/statewidget.cpp
@@ -0,0 +1,297 @@
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * copyright (C) 2002-2006 *
+ * Umbrello UML Modeller Authors <uml-devel@uml.sf.net> *
+ ***************************************************************************/
+
+// own header
+#include "statewidget.h"
+
+// qt includes
+#include <qevent.h>
+
+// kde includes
+#include <klocale.h>
+#include <kdebug.h>
+#include <kinputdialog.h>
+
+// app includes
+#include "uml.h"
+#include "umldoc.h"
+#include "docwindow.h"
+#include "umlwidget.h"
+#include "umlview.h"
+#include "dialogs/statedialog.h"
+#include "listpopupmenu.h"
+
+StateWidget::StateWidget(UMLView * view, StateType stateType, Uml::IDType id)
+ : UMLWidget(view, id) {
+ UMLWidget::setBaseType(Uml::wt_State);
+ m_StateType = stateType;
+ m_Text = "State";
+ updateComponentSize();
+}
+
+StateWidget::~StateWidget() {}
+
+void StateWidget::draw(QPainter & p, int offsetX, int offsetY) {
+ UMLWidget::setPen(p);
+ const int w = width();
+ const int h = height();
+ switch (m_StateType)
+ {
+ case Normal :
+ if(UMLWidget::getUseFillColour())
+ p.setBrush(UMLWidget::getFillColour());
+ {
+ const QFontMetrics &fm = getFontMetrics(FT_NORMAL);
+ const int fontHeight = fm.lineSpacing();
+ int textStartY = (h / 2) - (fontHeight / 2);
+ const int count = m_Activities.count();
+ if( count == 0 ) {
+ p.drawRoundRect(offsetX, offsetY, w, h, (h*40)/w, (w*40)/h);
+ p.setPen(Qt::black);
+ QFont font = UMLWidget::getFont();
+ font.setBold( false );
+ p.setFont( font );
+ p.drawText(offsetX + STATE_MARGIN, offsetY + textStartY,
+ w - STATE_MARGIN * 2, fontHeight,
+ Qt::AlignCenter, getName());
+ UMLWidget::setPen(p);
+ } else {
+ p.drawRoundRect(offsetX, offsetY, w, h, (h*40)/w, (w*40)/h);
+ textStartY = offsetY + STATE_MARGIN;
+ p.setPen(Qt::black);
+ QFont font = UMLWidget::getFont();
+ font.setBold( true );
+ p.setFont( font );
+ p.drawText(offsetX + STATE_MARGIN, textStartY, w - STATE_MARGIN * 2,
+ fontHeight, Qt::AlignCenter, getName());
+ font.setBold( false );
+ p.setFont( font );
+ UMLWidget::setPen(p);
+ int linePosY = textStartY + fontHeight;
+
+ QStringList::Iterator end(m_Activities.end());
+ for( QStringList::Iterator it(m_Activities.begin()); it != end; ++it ) {
+ textStartY += fontHeight;
+ p.drawLine( offsetX, linePosY, offsetX + w - 1, linePosY );
+ p.setPen(Qt::black);
+ p.drawText(offsetX + STATE_MARGIN, textStartY, w - STATE_MARGIN * 2 - 1,
+ fontHeight, Qt::AlignCenter, *it);
+ UMLWidget::setPen(p);
+ linePosY += fontHeight;
+ }//end for
+ }//end else
+ }
+ break;
+ case Initial :
+ p.setBrush( WidgetBase::getLineColor() );
+ p.drawEllipse( offsetX, offsetY, w, h );
+ break;
+ case End :
+ p.setBrush( WidgetBase::getLineColor() );
+ p.drawEllipse( offsetX, offsetY, w, h );
+ p.setBrush( Qt::white );
+ p.drawEllipse( offsetX + 1, offsetY + 1, w - 2, h - 2 );
+ p.setBrush( WidgetBase::getLineColor() );
+ p.drawEllipse( offsetX + 3, offsetY + 3, w - 6, h - 6 );
+ break;
+ default:
+ kWarning() << "Unknown state type:" << m_StateType << endl;
+ break;
+ }
+ if(m_bSelected)
+ drawSelected(&p, offsetX, offsetY);
+}
+
+QSize StateWidget::calculateSize() {
+ int width = 10, height = 10;
+ if ( m_StateType == Normal ) {
+ const QFontMetrics &fm = getFontMetrics(FT_BOLD);
+ const int fontHeight = fm.lineSpacing();
+ int textWidth = fm.width(getName());
+ const int count = m_Activities.count();
+ height = fontHeight;
+ if( count > 0 ) {
+ height = fontHeight * ( count + 1);
+
+ QStringList::Iterator end(m_Activities.end());
+ for( QStringList::Iterator it(m_Activities.begin()); it != end; ++it ) {
+ int w = fm.width( *it );
+ if( w > textWidth )
+ textWidth = w;
+ }//end for
+ }//end if
+ width = textWidth > STATE_WIDTH?textWidth:STATE_WIDTH;
+ height = height > STATE_HEIGHT?height:STATE_HEIGHT;
+ width += STATE_MARGIN * 2;
+ height += STATE_MARGIN * 2;
+ }
+
+ return QSize(width, height);
+}
+
+void StateWidget::setName(const QString &strName) {
+ m_Text = strName;
+ updateComponentSize();
+ adjustAssocs( getX(), getY() );
+}
+
+QString StateWidget::getName() const {
+ return m_Text;
+}
+
+StateWidget::StateType StateWidget::getStateType() const {
+ return m_StateType;
+}
+
+void StateWidget::setStateType( StateType stateType ) {
+ m_StateType = stateType;
+}
+
+void StateWidget::slotMenuSelection(int sel) {
+ bool done = false;
+ bool ok = false;
+ QString name = getName();
+
+ switch( sel ) {
+ case ListPopupMenu::mt_Rename:
+ name = KInputDialog::getText( i18n("Enter State Name"), i18n("Enter the name of the new state:"), getName(), &ok );
+ if( ok && name.length() > 0 )
+ setName( name );
+ done = true;
+ break;
+
+ case ListPopupMenu::mt_Properties:
+ showProperties();
+ done = true;
+ break;
+ case ListPopupMenu::mt_New_Activity:
+ name = KInputDialog::getText( i18n("Enter Activity"), i18n("Enter the name of the new activity:"), i18n("new activity"), &ok );
+ if( ok && name.length() > 0 )
+ addActivity( name );
+ done = true;
+ break;
+ }
+
+ if( !done )
+ UMLWidget::slotMenuSelection( sel );
+}
+
+bool StateWidget::addActivity( const QString &activity ) {
+ m_Activities.append( activity );
+ updateComponentSize();
+ return true;
+}
+
+bool StateWidget::removeActivity( const QString &activity ) {
+ int index = - 1;
+ if( ( index = m_Activities.findIndex( activity ) ) == -1 )
+ return false;
+ m_Activities.remove( m_Activities.at( index ) );
+ updateComponentSize();
+ return true;
+}
+
+void StateWidget::setActivities( QStringList & list ) {
+ m_Activities = list;
+ updateComponentSize();
+}
+
+QStringList & StateWidget::getActivityList() {
+ return m_Activities;
+}
+
+bool StateWidget::renameActivity( const QString &activity, const QString &newName ) {
+ int index = - 1;
+ if( ( index = m_Activities.findIndex( activity ) ) == -1 )
+ return false;
+ m_Activities[ index ] = newName;
+ return true;
+}
+
+void StateWidget::showProperties() {
+ DocWindow *docwindow = UMLApp::app()->getDocWindow();
+ docwindow->updateDocumentation(false);
+
+ StateDialog dialog(m_pView, this);
+ if (dialog.exec() && dialog.getChangesMade()) {
+ docwindow->showDocumentation(this, true);
+ UMLApp::app()->getDocument()->setModified(true);
+ }
+}
+
+bool StateWidget::isState(WorkToolBar::ToolBar_Buttons tbb, StateType& resultType)
+{
+ bool status = true;
+ switch (tbb) {
+ case WorkToolBar::tbb_Initial_State:
+ resultType = Initial;
+ break;
+ case WorkToolBar::tbb_State:
+ resultType = Normal;
+ break;
+ case WorkToolBar::tbb_End_State:
+ resultType = End;
+ break;
+ default:
+ status = false;
+ break;
+ }
+ return status;
+}
+
+void StateWidget::saveToXMI( QDomDocument & qDoc, QDomElement & qElement ) {
+ QDomElement stateElement = qDoc.createElement( "statewidget" );
+ UMLWidget::saveToXMI( qDoc, stateElement );
+ stateElement.setAttribute( "statename", m_Text );
+ stateElement.setAttribute( "documentation", m_Doc );
+ stateElement.setAttribute( "statetype", m_StateType );
+ //save states activities
+ QDomElement activitiesElement = qDoc.createElement( "Activities" );
+
+ QStringList::Iterator end(m_Activities.end());
+ for( QStringList::Iterator it(m_Activities.begin()); it != end; ++it ) {
+ QDomElement tempElement = qDoc.createElement( "Activity" );
+ tempElement.setAttribute( "name", *it );
+ activitiesElement.appendChild( tempElement );
+ }//end for
+ stateElement.appendChild( activitiesElement );
+ qElement.appendChild( stateElement );
+}
+
+bool StateWidget::loadFromXMI( QDomElement & qElement ) {
+ if( !UMLWidget::loadFromXMI( qElement ) )
+ return false;
+ m_Text = qElement.attribute( "statename", "" );
+ m_Doc = qElement.attribute( "documentation", "" );
+ QString type = qElement.attribute( "statetype", "1" );
+ m_StateType = (StateType)type.toInt();
+ //load states activities
+ QDomNode node = qElement.firstChild();
+ QDomElement tempElement = node.toElement();
+ if( !tempElement.isNull() && tempElement.tagName() == "Activities" ) {
+ QDomNode node = tempElement.firstChild();
+ QDomElement activityElement = node.toElement();
+ while( !activityElement.isNull() ) {
+ if( activityElement.tagName() == "Activity" ) {
+ QString name = activityElement.attribute( "name", "" );
+ if( !name.isEmpty() )
+ m_Activities.append( name );
+ }//end if
+ node = node.nextSibling();
+ activityElement = node.toElement();
+ }//end while
+ }//end if
+ return true;
+}
+
+
+#include "statewidget.moc"
+
diff --git a/umbrello/umbrello/statewidget.h b/umbrello/umbrello/statewidget.h
new file mode 100644
index 00000000..d214980b
--- /dev/null
+++ b/umbrello/umbrello/statewidget.h
@@ -0,0 +1,163 @@
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * copyright (C) 2002-2006 *
+ * Umbrello UML Modeller Authors <uml-devel@uml.sf.net> *
+***************************************************************************/
+
+#ifndef STATEWIDGET_H
+#define STATEWIDGET_H
+#include <qpainter.h>
+#include <qstringlist.h>
+#include "umlwidget.h"
+#include "worktoolbar.h"
+
+#define STATE_MARGIN 5
+#define STATE_WIDTH 30
+#define STATE_HEIGHT 10
+
+/**
+ * This class is the graphical version of a UML State.
+ *
+ * A StateWidget is created by a @ref UMLView. A StateWidget belongs to
+ * only one @ref UMLView instance.
+ * When the @ref UMLView instance that this class belongs to is destroyed,
+ * it will be automatically deleted.
+ *
+ * The StateWidget class inherits from the @ref UMLWidget class which adds
+ * most of the functionality to this class.
+ *
+ * @short A graphical version of a UML State.
+ * @author Paul Hensgen <phensgen@techie.com>
+ * Bugs and comments to uml-devel@lists.sf.net or http://bugs.kde.org
+ */
+class StateWidget : public UMLWidget {
+ Q_OBJECT
+public:
+
+ /// Enumeration that codes the different types of state.
+ enum StateType
+ {
+ Initial = 0,
+ Normal,
+ End
+ };
+
+ /**
+ * Creates a State widget.
+ *
+ * @param view The parent of the widget.
+ * @param stateType The type of state.
+ * @param id The ID to assign (-1 will prompt a new ID.)
+ */
+ explicit StateWidget( UMLView * view, StateType stateType = Normal, Uml::IDType id = Uml::id_None );
+
+ /**
+ * destructor
+ */
+ virtual ~StateWidget();
+
+ /**
+ * Overrides the standard paint event.
+ */
+ void draw(QPainter & p, int offsetX, int offsetY);
+
+ /**
+ * Sets the name of the State.
+ */
+ virtual void setName(const QString &strName);
+
+ /**
+ * Returns the name of the State.
+ */
+ virtual QString getName() const;
+
+ /**
+ * Returns the type of state.
+ */
+ StateType getStateType() const;
+
+ /**
+ * Sets the type of state.
+ */
+ void setStateType( StateType stateType );
+
+ /**
+ * Adds the given activity to the state.
+ */
+ bool addActivity( const QString &activity );
+
+ /**
+ * Removes the given activity from the state.
+ */
+ bool removeActivity( const QString &activity );
+
+ /**
+ * Renames the given activity.
+ */
+ bool renameActivity( const QString &activity, const QString &newName );
+
+ /**
+ * Sets the states activities to the ones given.
+ */
+ void setActivities( QStringList & list );
+
+ /**
+ * Returns the list of activities.
+ */
+ QStringList & getActivityList();
+
+ /**
+ * Show a properties dialog for a StateWidget.
+ */
+ void showProperties();
+
+ /**
+ * Returns true if the given toolbar button represents a State.
+ *
+ * @param tbb Input value of type WorkToolBar::ToolBar_Buttons.
+ * @param resultType Output value, the StateType that corresponds to tbb.
+ * Only set if the method returns true.
+ */
+ static bool isState( WorkToolBar::ToolBar_Buttons tbb,
+ StateType& resultType );
+
+ /**
+ * Creates the "statewidget" XMI element.
+ */
+ void saveToXMI( QDomDocument & qDoc, QDomElement & qElement );
+
+ /**
+ * Loads a "statewidget" XMI element.
+ */
+ bool loadFromXMI( QDomElement & qElement );
+
+protected:
+ /**
+ * Overrides method from UMLWidget
+ */
+ QSize calculateSize();
+
+ /**
+ * Type of state.
+ */
+ StateType m_StateType;
+
+ /**
+ * List of activities for the state.
+ */
+ QStringList m_Activities;
+
+public slots:
+
+ /**
+ * Captures any popup menu signals for menus it created.
+ */
+ void slotMenuSelection(int sel);
+};
+
+#endif
diff --git a/umbrello/umbrello/stereotype.cpp b/umbrello/umbrello/stereotype.cpp
new file mode 100644
index 00000000..5cd68f11
--- /dev/null
+++ b/umbrello/umbrello/stereotype.cpp
@@ -0,0 +1,94 @@
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * copyright (C) 2003-2006 *
+ * Umbrello UML Modeller Authors <uml-devel@uml.sf.net> *
+ ***************************************************************************/
+
+// own header
+#include "stereotype.h"
+
+// qt/kde includes
+#include <klocale.h>
+#include <kdebug.h>
+#include <kinputdialog.h>
+
+// local includes
+#include "umldoc.h"
+#include "uml.h"
+
+UMLStereotype::UMLStereotype(const QString &name, Uml::IDType id /* = Uml::id_None */)
+ : UMLObject( name, id ) {
+ m_BaseType = Uml::ot_Stereotype;
+ UMLStereotype * existing = UMLApp::app()->getDocument()->findStereotype(name);
+ if (existing) {
+ kError() << "UMLStereotype constructor: " << name << " already exists"
+ << kdBacktrace(25) << endl;
+ }
+ m_refCount = 0;
+}
+
+UMLStereotype::UMLStereotype() : UMLObject() {
+ m_BaseType = Uml::ot_Stereotype;
+ m_refCount = 0;
+}
+
+UMLStereotype::~UMLStereotype() {}
+
+bool UMLStereotype::operator==( UMLStereotype &rhs) {
+ if (this == &rhs) {
+ return true;
+ }
+
+ if ( !UMLObject::operator==( rhs ) ) {
+ return false;
+ }
+
+ return true;
+}
+
+void UMLStereotype::copyInto(UMLStereotype *rhs) const
+{
+ UMLObject::copyInto(rhs);
+}
+
+UMLObject* UMLStereotype::clone() const
+{
+ UMLStereotype *clone = new UMLStereotype();
+ copyInto(clone);
+
+ return clone;
+}
+
+
+void UMLStereotype::saveToXMI(QDomDocument& qDoc, QDomElement& qElement) {
+ //FIXME: uml13.dtd compliance
+ QDomElement stereotypeElement = UMLObject::save("UML:Stereotype", qDoc);
+ qElement.appendChild( stereotypeElement );
+}
+
+bool UMLStereotype::showPropertiesDialog(QWidget* parent) {
+ bool ok;
+ QString name = KInputDialog::getText(i18n("Stereotype"), i18n("Enter name:"), getName(),&ok, parent);
+ if (ok) {
+ setName(name);
+ }
+ return ok;
+}
+
+void UMLStereotype::incrRefCount() {
+ m_refCount++;
+}
+
+void UMLStereotype::decrRefCount() {
+ m_refCount--;
+}
+
+int UMLStereotype::refCount() const {
+ return m_refCount;
+}
+
diff --git a/umbrello/umbrello/stereotype.h b/umbrello/umbrello/stereotype.h
new file mode 100644
index 00000000..a836952f
--- /dev/null
+++ b/umbrello/umbrello/stereotype.h
@@ -0,0 +1,103 @@
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * copyright (C) 2003-2006 *
+ * Umbrello UML Modeller Authors <uml-devel@uml.sf.net> *
+ ***************************************************************************/
+
+#ifndef STEREOTYPE_H
+#define STEREOTYPE_H
+
+#include "umlobject.h"
+
+/**
+ * This class is used to set up information for a stereotype.
+ * Stereotypes are used essentially as properties of
+ * attributes and operations etc.
+ *
+ * @short Sets up stereotype information.
+ * @author Jonathan Riddell
+ * @author Oliver Kellogg
+ * Bugs and comments to uml-devel@lists.sf.net or http://bugs.kde.org
+ */
+
+class UMLStereotype : public UMLObject {
+public:
+ /**
+ * Sets up a stereotype.
+ *
+ * @param name The name of this UMLStereotype.
+ * @param id The unique id given to this UMLStereotype.
+ */
+ explicit UMLStereotype(const QString &name, Uml::IDType id = Uml::id_None);
+
+ /**
+ * Sets up a stereotype.
+ */
+ UMLStereotype();
+
+ /**
+ * Overloaded '==' operator
+ */
+ bool operator==(UMLStereotype &rhs);
+
+ /**
+ * destructor
+ */
+ virtual ~UMLStereotype();
+
+ /**
+ * Copy the internal presentation of this object into the new
+ * object.
+ */
+ virtual void copyInto(UMLStereotype *rhs) const;
+
+ /**
+ * Make a clone of this object.
+ */
+ virtual UMLObject* clone() const;
+
+ /**
+ * Increments the reference count for this stereotype.
+ */
+ void incrRefCount();
+
+ /**
+ * Decrements the reference count for this stereotype.
+ */
+ void decrRefCount();
+
+ /**
+ * Returns the reference count for this stereotype.
+ */
+ int refCount() const;
+
+ /**
+ * Saves to the <UML:StereoType> XMI element.
+ */
+ void saveToXMI(QDomDocument& qDoc, QDomElement& qElement);
+
+ /**
+ * Display the properties configuration dialog for the stereotype
+ * (just a line edit).
+ */
+ bool showPropertiesDialog(QWidget* parent);
+
+protected:
+ /**
+ * Each stereotype object is reference counted, i.e. client code
+ * manages it such that it comes into existence as soon as there is
+ * at least one user, and ceases existing when the number of users
+ * drops to 0.
+ * m_refCount reflects the number of users. It is externally managed,
+ * i.e. client code must take care to call incrRefCount() and
+ * decrRefCount() as appropriate.
+ */
+ int m_refCount;
+};
+
+#endif
diff --git a/umbrello/umbrello/template.cpp b/umbrello/umbrello/template.cpp
new file mode 100644
index 00000000..12d08fab
--- /dev/null
+++ b/umbrello/umbrello/template.cpp
@@ -0,0 +1,95 @@
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * copyright (C) 2003-2006 *
+ * Umbrello UML Modeller Authors <uml-devel@uml.sf.net> *
+ ***************************************************************************/
+
+// own header
+#include "template.h"
+
+// qt/kde includes
+#include <qregexp.h>
+#include <kdebug.h>
+
+// app includes
+#include "uml.h"
+#include "umldoc.h"
+#include "dialogs/umltemplatedialog.h"
+
+UMLTemplate::UMLTemplate(const UMLObject *parent, const QString& name,
+ Uml::IDType id, const QString& type)
+ : UMLClassifierListItem( parent, name, id ) {
+ setTypeName( type );
+ m_BaseType = Uml::ot_Template;
+}
+
+UMLTemplate::UMLTemplate(const UMLObject *parent)
+ : UMLClassifierListItem( parent ) {
+ m_BaseType = Uml::ot_Template;
+}
+
+UMLTemplate::~UMLTemplate() {}
+
+QString UMLTemplate::toString(Uml::Signature_Type /*sig = st_NoSig*/) {
+ if (m_pSecondary == NULL || m_pSecondary->getName() == "class") {
+ return getName();
+ } else {
+ return getName() + " : " + m_pSecondary->getName();
+ }
+}
+
+QString UMLTemplate::getTypeName() {
+ if (m_pSecondary == NULL)
+ return "class";
+ return m_pSecondary->getName();
+}
+
+bool UMLTemplate::operator==(UMLTemplate &rhs) {
+ if (this == &rhs) {
+ return true;
+ }
+ if ( !UMLObject::operator==( rhs ) ) {
+ return false;
+ }
+ if (m_pSecondary != rhs.m_pSecondary) {
+ return false;
+ }
+ return true;
+}
+
+void UMLTemplate::copyInto(UMLTemplate *rhs) const
+{
+ UMLClassifierListItem::copyInto(rhs);
+}
+
+UMLObject* UMLTemplate::clone() const
+{
+ UMLTemplate *clone = new UMLTemplate( (UMLTemplate*) parent());
+ copyInto(clone);
+
+ return clone;
+}
+
+
+void UMLTemplate::saveToXMI(QDomDocument& qDoc, QDomElement& qElement) {
+ //FIXME: uml13.dtd compliance
+ QDomElement attributeElement = UMLObject::save("UML:TemplateParameter", qDoc);
+ if (m_pSecondary)
+ attributeElement.setAttribute("type", ID2STR(m_pSecondary->getID()));
+ qElement.appendChild(attributeElement);
+}
+
+bool UMLTemplate::load(QDomElement& element) {
+ m_SecondaryId = element.attribute("type", "");
+ return true;
+}
+
+bool UMLTemplate::showPropertiesDialog(QWidget* parent) {
+ UMLTemplateDialog dialog(parent, this);
+ return dialog.exec();
+}
diff --git a/umbrello/umbrello/template.h b/umbrello/umbrello/template.h
new file mode 100644
index 00000000..1109411a
--- /dev/null
+++ b/umbrello/umbrello/template.h
@@ -0,0 +1,107 @@
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * copyright (C) 2003-2006 *
+ * Umbrello UML Modeller Authors <uml-devel@uml.sf.net> *
+ ***************************************************************************/
+
+#ifndef TEMPLATE_H
+#define TEMPLATE_H
+
+#include "classifierlistitem.h"
+
+/**
+ * This class holds information used by template classes, called
+ * paramaterised class in UML and a generic in Java. It has a
+ * type (usually just "class") and name.
+ *
+ * @short Sets up template information.
+ * @author Jonathan Riddell
+ * @see UMLObject
+ * Bugs and comments to uml-devel@lists.sf.net or http://bugs.kde.org
+ */
+
+class UMLTemplate : public UMLClassifierListItem {
+public:
+ /**
+ * Sets up a template.
+ *
+ * @param parent The parent of this UMLTemplate (i.e. its concept).
+ * @param name The name of this UMLTemplate.
+ * @param id The unique id given to this UMLTemplate.
+ * @param type The type of this UMLTemplate.
+ */
+ UMLTemplate(const UMLObject *parent, const QString& name,
+ Uml::IDType id = Uml::id_None, const QString& type = "class");
+
+ /**
+ * Sets up a template.
+ *
+ * @param parent The parent of this UMLTemplate (i.e. its concept).
+ */
+ UMLTemplate(const UMLObject *parent);
+
+ /**
+ * Overloaded '==' operator
+ */
+ bool operator==(UMLTemplate &rhs);
+
+ /**
+ * Copy the internal presentation of this object into the new
+ * object.
+ */
+ virtual void copyInto(UMLTemplate *rhs) const;
+
+ /**
+ * Make a clone of this object.
+ */
+ virtual UMLObject* clone() const;
+
+ /**
+ * destructor
+ */
+ virtual ~UMLTemplate();
+
+ /**
+ * Returns a string representation of the UMLTemplate.
+ *
+ * @param sig Currently unused.
+ * @return Returns a string representation of the UMLTemplate.
+ */
+ QString toString(Uml::Signature_Type sig = Uml::st_NoSig);
+
+ /**
+ * Overrides method from UMLClassifierListItem.
+ * Returns the type name of the UMLTemplate.
+ * If the template parameter is a class, there is no separate
+ * type object. In this case, getTypeName() returns "class".
+ *
+ * @return The type name of the UMLClassifierListItem.
+ */
+ virtual QString getTypeName();
+
+ /**
+ * Display the properties configuration dialog for the template.
+ *
+ * @return Success status.
+ */
+ bool showPropertiesDialog(QWidget* parent);
+
+ /**
+ * Writes the <UML:TemplateParameter> XMI element.
+ */
+ void saveToXMI(QDomDocument & qDoc, QDomElement & qElement);
+
+protected:
+ /**
+ * Loads the <UML:TemplateParameter> XMI element.
+ */
+ bool load(QDomElement & element);
+
+};
+
+#endif
diff --git a/umbrello/umbrello/textblock.cpp b/umbrello/umbrello/textblock.cpp
new file mode 100644
index 00000000..e9779875
--- /dev/null
+++ b/umbrello/umbrello/textblock.cpp
@@ -0,0 +1,320 @@
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * copyright (C) 2004-2007 *
+ * Umbrello UML Modeller Authors <uml-devel@uml.sf.net> *
+ ***************************************************************************/
+
+/* This code generated by:
+ * Author : thomas
+ * Date : Wed Jun 18 2003
+ */
+
+
+// own header
+#include "textblock.h"
+
+// qt/kde includes
+#include <qregexp.h>
+
+// local includes
+#include "codedocument.h"
+#include "codegenerator.h"
+#include "codegenerationpolicy.h"
+#include "uml.h"
+
+// Constructors/Destructors
+//
+
+TextBlock::TextBlock ( CodeDocument * parent, const QString & text )
+ : QObject ( (QObject *)parent, "textBlock")
+{
+ initFields(parent);
+ setText(text);
+}
+
+TextBlock::~TextBlock ( ) { }
+
+//
+// Methods
+//
+
+
+// Accessor methods
+//
+
+
+/**
+ * Set the value of the parent code document
+ * @param new_var the new value of m_parentDocument
+ */
+void TextBlock::setParentDocument ( CodeDocument * new_var ) {
+ m_parentDocument = new_var;
+}
+
+bool TextBlock::canDelete ( ) {
+ return m_canDelete;
+}
+
+/**
+ * Get the value of m_parentDocument
+ * @return the value of m_parentDocument
+ */
+CodeDocument * TextBlock::getParentDocument ( ) {
+ return m_parentDocument;
+}
+
+/**
+ * Set the value of m_text
+ * The actual text of this code block.
+ * @param new_var the new value of m_text
+ */
+void TextBlock::setText ( const QString &new_var ) {
+ m_text = new_var;
+}
+
+/**
+ * Add text to this object.
+ *
+ */
+void TextBlock::appendText ( const QString &new_text ) {
+ m_text = m_text + new_text;
+}
+
+/**
+ * Get the value of m_text
+ * The actual text of this code block.
+ * @return the value of m_text
+ */
+QString TextBlock::getText ( ) const {
+ return m_text;
+}
+
+/**
+ * Get the tag of this text block. This tag
+ * may be used to find this text block in the code document
+ * to which it belongs.
+ */
+QString TextBlock::getTag( ) const {
+ return m_tag;
+}
+
+/**
+ * Set the tag of this text block. This tag
+ * may be used to find this text block in the code document
+ * to which it belongs.
+ */
+void TextBlock::setTag ( const QString &value ) {
+ m_tag = value;
+}
+
+/**
+ * Set the value of m_writeOutText
+ * Whether or not to include the text of this TextBlock into a file.
+ * @param new_var the new value of m_writeOutText
+ */
+void TextBlock::setWriteOutText ( bool new_var ) {
+ m_writeOutText = new_var;
+}
+
+/**
+ * Get the value of m_writeOutText
+ * Whether or not to include the text of this TextBlock into a file.
+ * @return the value of m_writeOutText
+ */
+bool TextBlock::getWriteOutText ( ) {
+ return m_writeOutText;
+}
+
+/** Set how many times to indent this text block.
+ */
+void TextBlock::setIndentationLevel ( int level ) {
+ m_indentationLevel = level;
+}
+
+/** Get how many times to indent this text block.
+ * The amount of each indenatation is determined from the parent
+ * codedocument codegeneration policy.
+ */
+int TextBlock::getIndentationLevel ( ) {
+ return m_indentationLevel;
+}
+
+QString TextBlock::getNewLineEndingChars ( ) {
+ CodeGenerationPolicy * policy = UMLApp::app()->getCommonPolicy();
+ return policy->getNewLineEndingChars();
+}
+
+QString TextBlock::getIndentation() {
+ CodeGenerationPolicy * policy = UMLApp::app()->getCommonPolicy();
+ return policy->getIndentation();
+}
+
+QString TextBlock::getIndentationString ( int level ) {
+ if (!level)
+ level = m_indentationLevel;
+ QString indentAmount = getIndentation();
+ QString indentation = "";
+ for(int i=0; i<level; i++)
+ indentation.append(indentAmount);
+ return indentation;
+}
+
+// Other methods
+//
+
+/** Ush. These are terrifically bad and must one day go away.
+ * Both methods indicate the range of lines in this textblock
+ * which may be edited by the codeeditor (assuming that any are
+ * actually editable). The default case is no lines are editable.
+ * The line numbering starts with '0' and a '-1' means no line
+ * qualifies.
+ */
+int TextBlock::firstEditableLine() { return 0; }
+int TextBlock::lastEditableLine() { return 0; }
+
+QString TextBlock::getNewEditorLine ( int amount ) {
+ return getIndentationString(amount);
+}
+
+// will remove indenation from this text block.
+QString TextBlock::unformatText ( const QString & text, const QString & indent )
+{
+ QString output = text;
+ QString myIndent = indent;
+ if(myIndent.isEmpty())
+ myIndent = getIndentationString();
+
+ if(!output.isEmpty())
+ output.remove(QRegExp('^'+myIndent));
+
+ return output;
+}
+
+void TextBlock::release () {
+ this->disconnect();
+ //this->deleteLater();
+}
+
+QString TextBlock::formatMultiLineText ( const QString &work, const QString &linePrefix,
+ const QString& breakStr, bool addBreak, bool lastLineHasBreak ) {
+ QString output = "";
+ QString text = work;
+ QString endLine = getNewLineEndingChars();
+ int matches = text.contains(QRegExp(breakStr));
+ if(matches)
+ {
+ // check that last part of string matches, if not, then
+ // we have to tack on extra match
+ if(!text.contains(QRegExp(breakStr+"\\$")))
+ matches++;
+
+ for(int i=0; i < matches; i++)
+ {
+ QString line = text.section(QRegExp(breakStr),i,i);
+ output += linePrefix + line;
+ if((i != matches-1) || lastLineHasBreak)
+ output += endLine; // add break to line
+ }
+ } else {
+ output = linePrefix + text;
+ if(addBreak)
+ output += breakStr;
+ }
+
+ return output;
+}
+
+void TextBlock::setAttributesOnNode ( QDomDocument & doc, QDomElement & blockElement)
+{
+
+ QString endLine = UMLApp::app()->getCommonPolicy()->getNewLineEndingChars();
+
+ if (&doc != 0 ) {
+
+ blockElement.setAttribute("tag",getTag());
+
+ // only write these if different from defaults
+ if(getIndentationLevel())
+ blockElement.setAttribute("indentLevel",QString::number(getIndentationLevel()));
+ if(!m_text.isEmpty())
+ blockElement.setAttribute("text",encodeText(m_text,endLine));
+ if(!getWriteOutText())
+ blockElement.setAttribute("writeOutText",getWriteOutText()?"true":"false");
+ if(!canDelete())
+ blockElement.setAttribute("canDelete",canDelete()?"true":"false");
+
+ }
+
+}
+
+void TextBlock::setAttributesFromObject(TextBlock * obj)
+{
+
+ // DONT set tag here.
+ setIndentationLevel(obj->getIndentationLevel());
+ setText(obj->getText());
+ setWriteOutText(obj->getWriteOutText());
+ m_canDelete = obj->canDelete();
+
+}
+
+void TextBlock::setAttributesFromNode (QDomElement & root ) {
+
+ QString endLine = UMLApp::app()->getCommonPolicy()->getNewLineEndingChars();
+
+ setIndentationLevel(root.attribute("indentLevel","0").toInt());
+ setTag(root.attribute("tag",""));
+ setText(decodeText(root.attribute("text",""),endLine));
+ setWriteOutText(root.attribute("writeOutText","true") == "true" ? true : false);
+ m_canDelete = root.attribute("canDelete","true") == "true" ? true : false;
+
+}
+
+// encode text for XML storage
+// we simply convert all types of newLines to the "\n" or &#010;
+// entity.
+QString TextBlock::encodeText(const QString& text, const QString &endLine) {
+ QString encoded = text;
+ encoded.replace(QRegExp(endLine),"&#010;");
+ return encoded;
+}
+
+// encode text for XML storage
+// we simply convert all types of newLines to the "\n" or &#010;
+// entity.
+QString TextBlock::decodeText(const QString& text, const QString &endLine) {
+ QString decoded = text;
+ decoded.replace(QRegExp("&#010;"),endLine);
+ return decoded;
+}
+
+/**
+ * @return QString
+ */
+QString TextBlock::toString ( )
+{
+
+ // simple output method
+ if(m_writeOutText && !m_text.isEmpty())
+ {
+ QString endLine = UMLApp::app()->getCommonPolicy()->getNewLineEndingChars();
+ return formatMultiLineText(m_text, getIndentationString(), endLine);
+ } else
+ return "";
+}
+
+void TextBlock::initFields ( CodeDocument * parent ) {
+ m_canDelete = true;
+ m_writeOutText = true;
+ m_parentDocument = parent;
+ m_text = "";
+ m_tag = "";
+ m_indentationLevel = 0;
+}
+
+#include "textblock.moc"
diff --git a/umbrello/umbrello/textblock.h b/umbrello/umbrello/textblock.h
new file mode 100644
index 00000000..16dcd910
--- /dev/null
+++ b/umbrello/umbrello/textblock.h
@@ -0,0 +1,241 @@
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * copyright (C) 2004-2006 *
+ * Umbrello UML Modeller Authors <uml-devel@uml.sf.net> *
+ ***************************************************************************/
+
+/* This code generated by:
+ * Author : thomas
+ * Date : Wed Jun 18 2003
+ */
+
+
+
+#ifndef TEXTBLOCK_H
+#define TEXTBLOCK_H
+
+#include <qdom.h>
+#include <qobject.h>
+
+class CodeDocument;
+
+/**
+ * class TextBlock
+ * The fundemental unit of text within an output file containing code.
+ */
+
+class TextBlock : virtual public QObject {
+ friend class CodeGenObjectWithTextBlocks;
+ friend class ClassifierCodeDocument;
+ Q_OBJECT
+public:
+
+ // Constructors/Destructors
+ //
+
+ /**
+ * Constructors
+ */
+ explicit TextBlock ( CodeDocument * parent, const QString & text = "");
+
+ // destructor
+ ~TextBlock ( );
+
+ // Public attributes
+ //
+
+ // Public attribute accessor methods
+ //
+
+ /**
+ * Set the value of m_text
+ * The actual text of this code block.
+ * @param new_var the new value of m_text
+ */
+ void setText ( const QString &new_var );
+
+ /**
+ * Add text to this object.
+ *
+ */
+ void appendText ( const QString &new_text );
+
+ /**
+ * Get the value of m_text
+ * The actual text of this code block.
+ * @return the value of m_text
+ */
+ QString getText ( ) const;
+
+ /**
+ * Get the tag of this text block. This tag
+ * may be used to find this text block in the code document
+ * to which it belongs.
+ */
+ QString getTag( ) const;
+
+ /**
+ * Set the tag of this text block. This tag
+ * may be used to find this text block in the code document
+ * to which it belongs.
+ */
+ void setTag( const QString &value );
+
+ /**
+ * Get the value of m_parentDoc
+ * @return the value of m_parentDoc
+ */
+ CodeDocument * getParentDocument ( );
+
+ /**
+ * Set the value of m_writeOutText
+ * Whether or not to include the text of this TextBlock into a file.
+ * @param new_var the new value of m_writeOutText
+ */
+ void setWriteOutText ( bool new_var );
+
+ /**
+ * Get the value of m_writeOutText
+ * Whether or not to include the text of this TextBlock into a file.
+ * @return the value of m_writeOutText
+ */
+ bool getWriteOutText ( );
+
+ /** Set how many times to indent this text block.
+ * The amount of each indenatation is determined from the parent
+ * codedocument codegeneration policy.
+ */
+ void setIndentationLevel ( int level );
+
+ /** Get how many times to indent this text block.
+ * The amount of each indenatation is determined from the parent
+ * codedocument codegeneration policy.
+ */
+ int getIndentationLevel ( );
+
+ /** Get the actual amount of indentation for a given level of indentation.
+ */
+ QString getIndentationString ( int level = 0);
+
+ /** Get how much a single "level" of indentation will actually indent.
+ */
+ QString getIndentation();
+
+ QString getNewLineEndingChars ( );
+
+ /** Format a long text string to be more readable.
+ */
+ // should be static
+ QString formatMultiLineText ( const QString &text, const QString &linePrefix,
+ const QString& breakStr,
+ bool alwaysAddBreak = true, bool lastLineHasBreak = true);
+
+ /** UnFormat a long text string. Typically, this means removing
+ * the indentaion (linePrefix) and/or newline chars from each line.
+ * If an indentation isnt specified, then the current indentation is used.
+ */
+ virtual QString unformatText ( const QString & text, const QString & indent = "");
+
+ /**
+ * @return QString
+ */
+ virtual QString toString ( );
+
+ /** encode text for XML storage
+ * we simply convert all types of newLines to the "\n" or &#010;
+ * entity.
+ */
+ static QString encodeText(const QString& text , const QString &endChars);
+
+
+ /** decode text from XML storage
+ * We simply convert all newLine entity &#010; to chosen line ending.
+ */
+ static QString decodeText(const QString& text, const QString &endChars);
+
+ /**
+ * Save the XMI representation of this object
+ */
+ virtual void saveToXMI ( QDomDocument & doc, QDomElement & root ) = 0;
+
+ /**
+ * load params from the appropriate XMI element node.
+ */
+ virtual void loadFromXMI ( QDomElement & root ) = 0;
+
+ /** Determine if its OK to delete this textblock from the document.
+ * Used by the text editor to know if deletion could cause a crash of
+ * the program.
+ */
+ bool canDelete ();
+
+ /** set the class attributes from a passed object
+ */
+ virtual void setAttributesFromObject (TextBlock * obj);
+
+ /** Used by the CodeEditor. It provides it with an appropriate
+ * starting string for a new line of text within the given textblock
+ * (for example a string with the proper indentation).
+ * If the indentation amount is '0' the current indentationString will
+ * be used.
+ */
+ virtual QString getNewEditorLine( int indentAmount = 0 );
+
+ /** Ush. These are terrifically bad and must one day go away.
+ * Both methods indicate the range of lines in this textblock
+ * which may be edited by the codeeditor (assuming that any are
+ * actually editable). The default case is no lines are editable.
+ * The line numbering starts with '0' and a '-1' means no line
+ * qualifies.
+ */
+ virtual int firstEditableLine();
+ virtual int lastEditableLine();
+
+protected:
+
+ /** causes the text block to release all of its connections
+ * and any other text blocks that it 'owns'.
+ * needed to be called prior to deletion of the textblock.
+ */
+ virtual void release ();
+
+ /**
+ * Set the value of m_parentDocument
+ * @param new_var the new value of m_parentDoc
+ */
+ void setParentDocument ( CodeDocument * new_var );
+
+ /** set attributes of the node that represents this class
+ * in the XMI document.
+ */
+ virtual void setAttributesOnNode ( QDomDocument & doc, QDomElement & blockElement);
+
+ /** set the class attributes of this object from
+ * the passed element node.
+ */
+ virtual void setAttributesFromNode ( QDomElement & element);
+
+ bool m_canDelete;
+
+private:
+
+ // The actual text of this code block.
+ QString m_text;
+ QString m_tag;
+
+ // Whether or not to include the text of this TextBlock into a file.
+ bool m_writeOutText;
+
+ int m_indentationLevel;
+ CodeDocument * m_parentDocument;
+
+ void initFields ( CodeDocument * doc);
+
+};
+
+#endif // TEXTBLOCK_H
diff --git a/umbrello/umbrello/textblocklist.h b/umbrello/umbrello/textblocklist.h
new file mode 100644
index 00000000..48048b8b
--- /dev/null
+++ b/umbrello/umbrello/textblocklist.h
@@ -0,0 +1,23 @@
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * copyright (C) 2004-2007 *
+ * Umbrello UML Modeller Authors <uml-devel@uml.sf.net> *
+ ***************************************************************************/
+
+#ifndef _TEXTBLOCKLIST_H
+#define _TEXTBLOCKLIST_H
+
+#include <qptrlist.h>
+
+// forward declarations
+class TextBlock;
+
+typedef QPtrList<TextBlock> TextBlockList;
+typedef QPtrListIterator<TextBlock> TextBlockListIt;
+
+#endif
diff --git a/umbrello/umbrello/tips b/umbrello/umbrello/tips
new file mode 100644
index 00000000..504090f9
--- /dev/null
+++ b/umbrello/umbrello/tips
@@ -0,0 +1,129 @@
+<tip category="Umbrello">
+<html>
+<p>Welcome to Umbrello.</p>
+
+<p>UML diagrams let you design and document object oriented software. <a href="help:/umbrello">The Umbrello Handbook</a> is a good introduction to using UML.</p>
+</html>
+</tip>
+
+<tip category="Umbrello">
+<html>
+<p>Welcome to Umbrello 1.5. New in this version are association classes, Ruby code generation, externalizable folders, ability to change interfaces into classes, and more.</p>
+</html>
+</tip>
+
+<tip category="Umbrello">
+<html>
+<p>Tabbed Diagrams and Externalized Folders are mutually exclusive. If you need External Folders then deselect &quot;Use tabbed diagrams&quot; in the General Settings.</p>
+</html>
+</tip>
+
+<tip category="Umbrello">
+<html>
+<p>Most diagram items can not be resized, they will resize themselves to fit to their contents.
+Boxes, notes and sequence diagram messages can be resized, just click and drag on the red square.</p>
+</html>
+</tip>
+
+<tip category="Umbrello">
+<html>
+<p>If you want to add an already existing class to a diagram just drag its entry from the tree view.</p>
+</html>
+</tip>
+
+<tip category="Umbrello">
+<html>
+<p>Umbrello's refactoring agent lets you move operations between a class and its derived and base
+classes.
+Right click a class to open the refactoring agent.</p>
+</html>
+</tip>
+
+<tip category="Umbrello">
+<html>
+<p>Sequence diagram objects can have a destructor box and be drawn as actors. Double click one for
+the Properties dialogue.</p>
+</html>
+</tip>
+
+<tip category="Umbrello">
+<html>
+<p>Sequence diagram messages can act as constructors. Click on the object box (rather than the vertical line) to make it a constructor.</p>
+</html>
+</tip>
+
+<tip category="Umbrello">
+<html>
+<p>Sequence diagrams support messages to self. Click on the same vertical line again to create an automessage.</p>
+</html>
+</tip>
+
+<tip category="Umbrello">
+<html>
+<p>If on loading a foreign file nothing is displayed in the list view, try saving the model under a different name,
+closing, and reloading the saved file. Usually the list view is then properly populated.
+</p>
+</html>
+</tip>
+
+<tip category="Umbrello">
+<html>
+<p>Cut and Copy will also export the image to a PNG clipboard which can be pasted into KWord
+and other applications.</p>
+</html>
+</tip>
+
+<tip category="Umbrello">
+<html>
+<p>Associations do not have to be in straight lines, double clicking on one will create a movable point.</p>
+</html>
+</tip>
+
+<tip category="Umbrello">
+<html>
+<p>You can turn on autosaving in the Configure Umbrello dialog.</p>
+</html>
+</tip>
+
+<tip category="Umbrello">
+<html>
+<p>Is a feature missing that you need in Umbrello? Please let us know.
+Either add it to the bugs database with Report Bug from the Help menu
+or send it to the uml-devel mailing list.</p>
+<ul>
+<li><a href="http://uml.sf.net/contact.php">http://uml.sf.net/contact.php</a>.</li>
+</ul>
+</html>
+</tip>
+
+<tip category="Umbrello">
+<html>
+<p>You can delete all selected objects by pressing Del or Backspace.</p>
+</html>
+</tip>
+
+<tip category="Umbrello">
+<html>
+<p>If you've found a bug in Umbrello, please let us know.
+You can submit bugs with the Report Bug tool in the Help menu.</p>
+</html>
+</tip>
+
+<tip category="Umbrello">
+<html>
+<p>Pressing the Escape key sets the current tool to the select tool.
+Backspace jumps to the previously used tool.</p>
+</html>
+</tip>
+
+<tip category="Umbrello">
+<html>
+<p>You can select all objects by pressing Ctrl-A.</p>
+</html>
+</tip>
+
+<tip category="Umbrello">
+<html>
+<p>You can create and setup a new class using the New Class Wizard in the Code menu.</p>
+</html>
+</tip>
diff --git a/umbrello/umbrello/toolbarstate.cpp b/umbrello/umbrello/toolbarstate.cpp
new file mode 100644
index 00000000..339214a8
--- /dev/null
+++ b/umbrello/umbrello/toolbarstate.cpp
@@ -0,0 +1,260 @@
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * copyright (C) 2004-2006 *
+ * Umbrello UML Modeller Authors <uml-devel@uml.sf.net> *
+ ***************************************************************************/
+
+// own header
+#include "toolbarstate.h"
+
+// qt includes
+#include <qwmatrix.h> // need for inverseWorldMatrix.map
+
+// app includes
+#include "associationwidget.h"
+#include "messagewidget.h"
+#include "uml.h"
+#include "umlview.h"
+#include "umlwidget.h"
+
+ToolBarState::~ToolBarState() {
+ delete m_pMouseEvent;
+}
+
+void ToolBarState::init() {
+ m_pUMLView->viewport()->setMouseTracking(false);
+ m_pMouseEvent = 0;
+ m_currentWidget = 0;
+ m_currentAssociation = 0;
+
+ connect(m_pUMLView, SIGNAL(sigAssociationRemoved(AssociationWidget*)),
+ this, SLOT(slotAssociationRemoved(AssociationWidget*)));
+ connect(m_pUMLView, SIGNAL(sigWidgetRemoved(UMLWidget*)),
+ this, SLOT(slotWidgetRemoved(UMLWidget*)));
+}
+
+void ToolBarState::cleanBeforeChange() {
+ disconnect(m_pUMLView, SIGNAL(sigAssociationRemoved(AssociationWidget*)),
+ this, SLOT(slotAssociationRemoved(AssociationWidget*)));
+ disconnect(m_pUMLView, SIGNAL(sigWidgetRemoved(UMLWidget*)),
+ this, SLOT(slotWidgetRemoved(UMLWidget*)));
+}
+
+void ToolBarState::mousePress(QMouseEvent* ome) {
+ setMouseEvent(ome, QEvent::MouseButtonPress);
+
+ m_pUMLView->viewport()->setMouseTracking(true);
+
+ //TODO Doesn't another way of emiting the signal exist? A method only for
+ //that seems a bit dirty.
+ m_pUMLView->emitRemovePopupMenu();
+
+ // TODO: Check who needs this.
+ m_pUMLView->setPos(m_pMouseEvent->pos());
+
+ //TODO check why
+ m_pUMLView->setPaste(false);
+
+ setCurrentElement();
+
+ if (getCurrentWidget()) {
+ mousePressWidget();
+ } else if (getCurrentAssociation()) {
+ mousePressAssociation();
+ } else {
+ mousePressEmpty();
+ }
+}
+
+void ToolBarState::mouseRelease(QMouseEvent* ome) {
+ setMouseEvent(ome, QEvent::MouseButtonRelease);
+
+ // Set the position of the mouse
+ // TODO, should only be available in this state?
+ m_pUMLView->setPos(m_pMouseEvent->pos());
+
+ m_pUMLView->viewport()->setMouseTracking(false);
+
+ if (getCurrentWidget()) {
+ mouseReleaseWidget();
+ setCurrentWidget(0);
+ } else if (getCurrentAssociation()) {
+ mouseReleaseAssociation();
+ setCurrentAssociation(0);
+ } else {
+ mouseReleaseEmpty();
+ }
+
+ // Default, rightbutton changes the tool.
+ // The arrow tool overrides the changeTool() function.
+ changeTool();
+}
+
+void ToolBarState::mouseDoubleClick(QMouseEvent* ome) {
+ setMouseEvent(ome, QEvent::MouseButtonDblClick);
+
+ UMLWidget* currentWidget = m_pUMLView->getWidgetAt(m_pMouseEvent->pos());
+ AssociationWidget* currentAssociation = getAssociationAt(m_pMouseEvent->pos());
+ if (currentWidget) {
+ setCurrentWidget(currentWidget);
+ mouseDoubleClickWidget();
+ setCurrentWidget(0);
+ } else if (currentAssociation) {
+ setCurrentAssociation(currentAssociation);
+ mouseDoubleClickAssociation();
+ setCurrentAssociation(0);
+ } else {
+ mouseDoubleClickEmpty();
+ }
+}
+
+void ToolBarState::mouseMove(QMouseEvent* ome) {
+ setMouseEvent(ome, QEvent::MouseMove);
+
+ if (getCurrentWidget()) {
+ mouseMoveWidget();
+ } else if (getCurrentAssociation()) {
+ mouseMoveAssociation();
+ } else {
+ mouseMoveEmpty();
+ }
+
+ //Scrolls the view
+ int vx = ome->x();
+ int vy = ome->y();
+ int contsX = m_pUMLView->contentsX();
+ int contsY = m_pUMLView->contentsY();
+ int visw = m_pUMLView->visibleWidth();
+ int vish = m_pUMLView->visibleHeight();
+ int dtr = visw - (vx-contsX);
+ int dtb = vish - (vy-contsY);
+ int dtt = (vy-contsY);
+ int dtl = (vx-contsX);
+ if (dtr < 30) m_pUMLView->scrollBy(30-dtr,0);
+ if (dtb < 30) m_pUMLView->scrollBy(0,30-dtb);
+ if (dtl < 30) m_pUMLView->scrollBy(-(30-dtl),0);
+ if (dtt < 30) m_pUMLView->scrollBy(0,-(30-dtt));
+}
+
+void ToolBarState::slotAssociationRemoved(AssociationWidget* association) {
+ if (association == getCurrentAssociation()) {
+ setCurrentAssociation(0);
+ }
+}
+
+void ToolBarState::slotWidgetRemoved(UMLWidget* widget) {
+ if (widget == getCurrentWidget()) {
+ setCurrentWidget(0);
+ }
+}
+
+ToolBarState::ToolBarState(UMLView *umlView) : QObject(umlView), m_pUMLView(umlView) {
+ m_pMouseEvent = NULL;
+ init();
+}
+
+void ToolBarState::setCurrentElement() {
+ // Check associations.
+ AssociationWidget* association = getAssociationAt(m_pMouseEvent->pos());
+ if (association) {
+ setCurrentAssociation(association);
+ return;
+ }
+
+ // Check messages.
+ //TODO check why message widgets are treated different
+ MessageWidget* message = getMessageAt(m_pMouseEvent->pos());
+ if (message) {
+ setCurrentWidget(message);
+ return;
+ }
+
+ // Check widgets.
+ UMLWidget *widget = m_pUMLView->getWidgetAt(m_pMouseEvent->pos());
+ if (widget) {
+ setCurrentWidget(widget);
+ return;
+ }
+}
+
+void ToolBarState::mousePressAssociation() {
+}
+
+void ToolBarState::mousePressWidget() {
+}
+
+void ToolBarState::mousePressEmpty() {
+ m_pUMLView->clearSelected();
+}
+
+void ToolBarState::mouseReleaseAssociation() {
+}
+
+void ToolBarState::mouseReleaseWidget() {
+}
+
+void ToolBarState::mouseReleaseEmpty() {
+}
+
+void ToolBarState::mouseDoubleClickAssociation() {
+}
+
+void ToolBarState::mouseDoubleClickWidget() {
+}
+
+void ToolBarState::mouseDoubleClickEmpty() {
+ m_pUMLView->clearSelected();
+}
+
+void ToolBarState::mouseMoveAssociation() {
+}
+
+void ToolBarState::mouseMoveWidget() {
+}
+
+void ToolBarState::mouseMoveEmpty() {
+}
+
+void ToolBarState::changeTool() {
+ if (m_pMouseEvent->state() == Qt::RightButton) {
+ UMLApp::app()->getWorkToolBar()->setDefaultTool();
+ }
+}
+
+void ToolBarState::setMouseEvent(QMouseEvent* ome, const QEvent::Type &type) {
+ if (m_pMouseEvent) delete m_pMouseEvent;
+
+ m_pMouseEvent = new QMouseEvent(type, m_pUMLView->inverseWorldMatrix().map(ome->pos()),
+ ome->button(),ome->state());
+}
+
+MessageWidget* ToolBarState::getMessageAt(const QPoint& pos) {
+ MessageWidget* message = 0;
+ for (MessageWidgetListIt it(m_pUMLView->getMessageList());
+ (message = it.current()) != 0; ++it) {
+ if (message->isVisible() && message->onWidget(pos)) {
+ return message;
+ }
+ }
+
+ return message;
+}
+
+AssociationWidget* ToolBarState::getAssociationAt(const QPoint& pos) {
+ AssociationWidget* association = 0;
+ for (AssociationWidgetListIt it(m_pUMLView->getAssociationList());
+ (association = it.current()) != 0; ++it) {
+ if (association->onAssociation(pos)) {
+ return association;
+ }
+ }
+
+ return association;
+}
+
+#include "toolbarstate.moc"
diff --git a/umbrello/umbrello/toolbarstate.h b/umbrello/umbrello/toolbarstate.h
new file mode 100644
index 00000000..e005c021
--- /dev/null
+++ b/umbrello/umbrello/toolbarstate.h
@@ -0,0 +1,365 @@
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * copyright (C) 2004-2006 *
+ * Umbrello UML Modeller Authors <uml-devel@uml.sf.net> *
+ ***************************************************************************/
+
+#ifndef TOOLBARSTATE_H
+#define TOOLBARSTATE_H
+
+#include <qevent.h>
+#include <qobject.h>
+
+class QEvent;
+class QMouseEvent;
+
+class AssociationWidget;
+class MessageWidget;
+class UMLView;
+class UMLWidget;
+
+
+/**
+ * Base class for toolbar states.
+ * All toolbar states inherit directly or indirectly from this class. Toolbar
+ * states represent tools that work with the diagram (for example, to create
+ * widgets, make associations...). All the mouse events received in the diagram
+ * are delivered to the toolbar state currently active. The events are handled
+ * in the tool and it executes the needed actions.
+ *
+ * All the mouse event handlers can be overridden in subclasses. However, the
+ * behaviour of the main handlers shouldn't be modified (apart from extend it,
+ * that is, call the base implementation before any other actions in the derived
+ * method).
+ *
+ * In order to handle the events, each main handler has three protected
+ * "sub-handlers" named like the main handler with the suffixes "Association",
+ * "Wdiget" and "Empty". The events received in the main handlers are delivered
+ * to the suitable handler, depending on if the event happened on an association,
+ * on a widget or on an empty space of the diagram. Those methods are the ones to
+ * override or extend to specify the behaviour of the toolbar state.
+ *
+ * The mouse events received in main handlers are tweaked to use the inverse
+ * position. The modified event is saved in m_pMouseEvent. This is the event that
+ * must be used everywhere.
+ *
+ * The association or widget that will receive the events is set in press event.
+ * How they are set can be tweaked in subclasses overriding setCurrentElement().
+ * Once a press event happens, all the mouse events and the release event are sent
+ * to the same widget or association. Mouse events are delivered only when mouse
+ * tracking is enabled. It is enabled in press event, and disabled in release
+ * event. Also, it is disabled in the toolbar state initialization. Additionally,
+ * it can be enabled or disabled in other situations by subclasses if needed.
+ *
+ * After handling a release event, the tool is changed if needed. Default
+ * implementation sets the default tool if the button released was the right
+ * button. Subclasses can override this behaviour if needed.
+ *
+ * When a toolbar state is selected, method init is called to revert its state
+ * to the initial. Subclasses should extend that method as needed. Also, method
+ * cleanBeforeChange() is called before changing it to the new tool. Subclasses
+ * should extend that method as needed.
+ *
+ * @todo Handle, for example, left press, right press, left release, right
+ * release and other similar strange combinations?
+ */
+class ToolBarState: public QObject {
+ Q_OBJECT
+public:
+
+ /**
+ * Destroys this ToolBarState.
+ * Frees m_pMouseEvent.
+ */
+ virtual ~ToolBarState();
+
+ /**
+ * Goes back to the initial state.
+ * Subclasses can extend, but not override, this method as needed.
+ */
+ virtual void init();
+
+ /**
+ * Called when the current tool is changed to use another tool.
+ * Subclasses can extend, but not override, this method as needed.
+ * Default implementation does nothing.
+ */
+ virtual void cleanBeforeChange();
+
+ /**
+ * Handler for mouse press events.
+ * Mouse tracking is enabled, any pop up menu removed, the position of the
+ * cursor set and paste state disabled.
+ * Then, the current association or widget are set (if any), and events are
+ * delivered to the specific methods, depending on where the cursor was
+ * pressed.
+ *
+ * @param ome The received event.
+ * @see setCurrentElement()
+ */
+ virtual void mousePress(QMouseEvent *ome);
+
+ /**
+ * Handler for mouse release events.
+ * Mouse tracking is disabled and the position of the cursor set.
+ * The events are delivered to the specific methods, depending on where the
+ * cursor was released, and the current association or widget cleaned.
+ * Finally, the current tool is changed if needed.
+ *
+ * @param ome The received event.
+ */
+ virtual void mouseRelease(QMouseEvent* ome);
+
+ /**
+ * Handler for mouse double click events.
+ * The current association or widget is set (if any), and events are
+ * delivered to the specific methods, depending on where the cursor was pressed.
+ * After delivering the events, the current association or widget is cleaned.
+ *
+ * @param ome The received event.
+ */
+ virtual void mouseDoubleClick(QMouseEvent* ome);
+
+ /**
+ * Handler for mouse double click events.
+ * Events are delivered to the specific methods, depending on where the cursor
+ * was pressed. It uses the current widget or association set in press event,
+ * if any.
+ * Then, the view is scrolled if needed (if the cursor is moved in any of the
+ * 30 pixels width area from left, top, right or bottom sides, and there is
+ * more diagram currently not being shown in that direction).
+ * This method is only called when mouse tracking is enabled and the mouse
+ * is moved.
+ *
+ * @param ome The received event.
+ */
+ virtual void mouseMove(QMouseEvent* ome);
+
+public slots:
+
+ /**
+ * An association was removed from the UMLView.
+ * If the association removed was the current association, the current
+ * association is set to 0.
+ * It can be extended in subclasses if needed.
+ */
+ virtual void slotAssociationRemoved(AssociationWidget* association);
+
+ /**
+ * A widget was removed from the UMLView.
+ * If the widget removed was the current widget, the current widget is set
+ * to 0.
+ * It can be extended in subclasses if needed.
+ */
+ virtual void slotWidgetRemoved(UMLWidget* widget);
+
+protected:
+
+ /**
+ * Creates a new ToolBarState.
+ * UMLView is set as parent of this QObject, and name is left empty.
+ * Protected to avoid classes other than derived to create objects of this
+ * class.
+ *
+ * @param umlView The UMLView to use.
+ */
+ ToolBarState(UMLView *umlView);
+
+ /**
+ * Sets the current association or widget.
+ * It sets the current element when a press event happened. The element will
+ * be used until the next release event.
+ * Default implementation first checks for associations, then message widgets
+ * and then any other widgets.
+ * It can be overridden in subclasses if needed.
+ */
+ virtual void setCurrentElement();
+
+ /**
+ * Called when the press event happened on an association.
+ * Default implementation does nothing.
+ */
+ virtual void mousePressAssociation();
+
+ /**
+ * Called when the press event happened on a widget.
+ * Default implementation does nothing.
+ */
+ virtual void mousePressWidget();
+
+ /**
+ * Called when the press event happened on an empty space.
+ * Default implementation cleans the selection.
+ */
+ virtual void mousePressEmpty();
+
+ /**
+ * Called when the release event happened on an association.
+ * Default implementation does nothing.
+ */
+ virtual void mouseReleaseAssociation();
+
+ /**
+ * Called when the release event happened on a widget.
+ * Default implementation does nothing.
+ */
+ virtual void mouseReleaseWidget();
+
+ /**
+ * Called when the release event happened on an empty space.
+ * Default implementation does nothing.
+ */
+ virtual void mouseReleaseEmpty();
+
+ /**
+ * Called when the double click event happened on an association.
+ * Default implementation does nothing.
+ */
+ virtual void mouseDoubleClickAssociation();
+
+ /**
+ * Called when the double click event happened on a widget.
+ * Default implementation does nothing.
+ */
+ virtual void mouseDoubleClickWidget();
+
+ /**
+ * Called when the double click event happened on an empty space.
+ * Default implementation cleans the selection.
+ */
+ virtual void mouseDoubleClickEmpty();
+
+ /**
+ * Called when the move event happened when an association is
+ * currently available.
+ * Default implementation does nothing.
+ */
+ virtual void mouseMoveAssociation();
+
+ /**
+ * Called when the move event happened when a widget is
+ * currently available.
+ * Default implementation does nothing.
+ */
+ virtual void mouseMoveWidget();
+
+ /**
+ * Called when the move event happened when no association nor
+ * widget are currently available.
+ * Default implementation does nothing.
+ */
+ virtual void mouseMoveEmpty();
+
+ /**
+ * Changes the current tool to the default one if the right button was released.
+ * It can be overridden in subclasses if needed.
+ */
+ virtual void changeTool();
+
+ /**
+ * Returns the widget currently in use.
+ *
+ * @return The widget currently in use.
+ */
+ virtual UMLWidget* getCurrentWidget() {
+ return m_currentWidget;
+ }
+
+ /**
+ * Sets the widget currently in use.
+ * This method is called in main press events handler just before calling
+ * the press event for widgets handler.
+ * Default implementation is set the specified widget, although this
+ * behaviour can be overridden in subclasses if needed.
+ *
+ * @param currentWidget The widget to be set.
+ */
+ virtual void setCurrentWidget(UMLWidget* currentWidget) {
+ m_currentWidget = currentWidget;
+ }
+
+ /**
+ * Returns the association currently in use.
+ *
+ * @return The association currently in use.
+ */
+ virtual AssociationWidget* getCurrentAssociation() {
+ return m_currentAssociation;
+ }
+
+ /**
+ * Sets the association currently in use.
+ * This method is called in main press events handler just before calling
+ * the press event for associations handler.
+ * Default implementation is set the specified association, although this
+ * behaviour can be overridden in subclasses if needed.
+ *
+ * @param currentAssociation The association to be set.
+ */
+ virtual void setCurrentAssociation(AssociationWidget* currentAssociation) {
+ m_currentAssociation = currentAssociation;
+ }
+
+ /**
+ * Sets m_pMouseEvent as the equivalent of the received event after transforming it
+ * using the inverse world matrix in the UMLView.
+ * This method is called at the beginning of the main event handler methods.
+ *
+ * @param ome The mouse event to transform.
+ * @param type The type of the event.
+ */
+ void setMouseEvent(QMouseEvent* ome, const QEvent::Type &type);
+
+ /**
+ * Returns the AssociationWidget at the specified position, or null if there is none.
+ * If there are more than one association at this point, it returns the first found.
+ *
+ * @param pos The position to get the association.
+ * @return The AssociationWidget at the specified position, or null if there is none.
+ * @todo Better handling for associations at the same point
+ */
+ AssociationWidget* getAssociationAt(const QPoint& pos);
+
+ /**
+ * Returns the MessageWidget at the specified position, or null if there is none.
+ * The message is only returned if it is visible.
+ * If there are more than one message at this point, it returns the first found.
+ *
+ * @param pos The position to get the message.
+ * @return The MessageWidget at the specified position, or null if there is none.
+ * @todo Better handling for messages at the same point
+ */
+ MessageWidget* getMessageAt(const QPoint& pos);
+
+ /**
+ * The UMLView.
+ */
+ UMLView* m_pUMLView;
+
+ /**
+ * The mouse event currently in use.
+ * This event is the equivalent of the received event after transforming it
+ * using the inverse world matrix in the UMLView.
+ */
+ QMouseEvent* m_pMouseEvent;
+
+private:
+
+ /**
+ * The widget currently in use, if any.
+ */
+ UMLWidget* m_currentWidget;
+
+ /**
+ * The association currently in use, if any.
+ */
+ AssociationWidget* m_currentAssociation;
+
+};
+
+#endif //TOOLBARSTATE_H
diff --git a/umbrello/umbrello/toolbarstatearrow.cpp b/umbrello/umbrello/toolbarstatearrow.cpp
new file mode 100644
index 00000000..d8205350
--- /dev/null
+++ b/umbrello/umbrello/toolbarstatearrow.cpp
@@ -0,0 +1,134 @@
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * copyright (C) 2004-2006 *
+ * Umbrello UML Modeller Authors <uml-devel@uml.sf.net> *
+ ***************************************************************************/
+
+// own header
+#include "toolbarstatearrow.h"
+
+// app includes
+#include "associationwidget.h"
+#include "uml.h"
+#include "umlview.h"
+#include "umlwidget.h"
+
+ToolBarStateArrow::ToolBarStateArrow(UMLView *umlView): ToolBarState(umlView) {
+ m_selectionRect.setAutoDelete(true);
+
+ init();
+}
+
+ToolBarStateArrow::~ToolBarStateArrow() {
+}
+
+void ToolBarStateArrow::init() {
+ ToolBarState::init();
+
+ m_selectionRect.clear();
+}
+
+void ToolBarStateArrow::mousePressAssociation() {
+ getCurrentAssociation()->mousePressEvent(m_pMouseEvent);
+}
+
+void ToolBarStateArrow::mousePressWidget() {
+ getCurrentWidget()->mousePressEvent(m_pMouseEvent);
+}
+
+void ToolBarStateArrow::mousePressEmpty() {
+ if (m_pMouseEvent->button() != Qt::LeftButton) {
+ // Leave widgets selected upon RMB press on empty diagram area.
+ // The popup menu is activated upon RMB release.
+ return;
+ }
+ ToolBarState::mousePressEmpty();
+
+ // Starts the selection rectangle
+ if (m_selectionRect.count() == 0) {
+ m_startPosition = m_pMouseEvent->pos();
+
+ for (int i = 0; i < 4; i++) {
+ QCanvasLine* line = new QCanvasLine(m_pUMLView->canvas());
+ line->setPoints(m_pMouseEvent->x(), m_pMouseEvent->y(),
+ m_pMouseEvent->x(), m_pMouseEvent->y());
+ line->setPen(QPen(QColor("grey"), 0, Qt::DotLine));
+ line->setVisible(true);
+ line->setZ(100);
+ m_selectionRect.append(line);
+ }
+ }
+}
+
+void ToolBarStateArrow::mouseReleaseAssociation() {
+ getCurrentAssociation()->mouseReleaseEvent(m_pMouseEvent);
+}
+
+void ToolBarStateArrow::mouseReleaseWidget() {
+ getCurrentWidget()->mouseReleaseEvent(m_pMouseEvent);
+}
+
+void ToolBarStateArrow::mouseReleaseEmpty() {
+ if (m_selectionRect.count() == 4) {
+ m_selectionRect.clear();
+ } else if (m_pMouseEvent->button() == Qt::RightButton) {
+ m_pUMLView->setMenu();
+ }
+}
+
+void ToolBarStateArrow::mouseDoubleClickAssociation() {
+ getCurrentAssociation()->mouseDoubleClickEvent(m_pMouseEvent);
+}
+
+void ToolBarStateArrow::mouseDoubleClickWidget() {
+ getCurrentWidget()->mouseDoubleClickEvent(m_pMouseEvent);
+}
+
+void ToolBarStateArrow::mouseMoveAssociation() {
+ getCurrentAssociation()->mouseMoveEvent(m_pMouseEvent);
+}
+
+void ToolBarStateArrow::mouseMoveWidget() {
+ getCurrentWidget()->mouseMoveEvent(m_pMouseEvent);
+}
+
+void ToolBarStateArrow::mouseMoveEmpty() {
+ if (m_selectionRect.count() == 4) {
+ QCanvasLine* line = m_selectionRect.at(0);
+ line->setPoints(m_startPosition.x(), m_startPosition.y(),
+ m_pMouseEvent->x(), m_startPosition.y());
+
+ line = m_selectionRect.at(1);
+ line->setPoints(m_pMouseEvent->x(), m_startPosition.y(),
+ m_pMouseEvent->x(), m_pMouseEvent->y());
+
+ line = m_selectionRect.at(2);
+ line->setPoints(m_pMouseEvent->x(), m_pMouseEvent->y(),
+ m_startPosition.x(), m_pMouseEvent->y());
+
+ line = m_selectionRect.at(3);
+ line->setPoints(m_startPosition.x(), m_pMouseEvent->y(),
+ m_startPosition.x(), m_startPosition.y());
+
+ m_pUMLView->selectWidgets(m_startPosition.x(), m_startPosition.y(),
+ m_pMouseEvent->x(), m_pMouseEvent->y());
+ }
+}
+
+void ToolBarStateArrow::changeTool() {
+}
+
+void ToolBarStateArrow::setCurrentWidget(UMLWidget* currentWidget) {
+ if (currentWidget != 0 && getCurrentWidget() != 0) {
+ return;
+ }
+
+ ToolBarState::setCurrentWidget(currentWidget);
+}
+
+#include "toolbarstatearrow.moc"
diff --git a/umbrello/umbrello/toolbarstatearrow.h b/umbrello/umbrello/toolbarstatearrow.h
new file mode 100644
index 00000000..a2fab59f
--- /dev/null
+++ b/umbrello/umbrello/toolbarstatearrow.h
@@ -0,0 +1,158 @@
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * copyright (C) 2004-2006 *
+ * Umbrello UML Modeller Authors <uml-devel@uml.sf.net> *
+ ***************************************************************************/
+
+#ifndef TOOLBARSTATEARROW_H
+#define TOOLBARSTATEARROW_H
+
+
+#include "toolbarstate.h"
+
+#include "worktoolbar.h"
+
+class QMouseEvent;
+class UMLView;
+
+class QCanvasLine;
+
+/**
+ * Arrow tool for select, move and resize widgets and associations.
+ * Arrow tool delegates the event handling in the widgets and associations. When
+ * no widget nor association is being used,the arrow tool acts as a selecting
+ * tool that selects all the elements in the rectangle created when dragging the
+ * mouse.
+ *
+ * This is the default tool.
+ */
+class ToolBarStateArrow : public ToolBarState {
+ Q_OBJECT
+public:
+
+ /**
+ * Creates a new ToolBarStateArrow.
+ *
+ * @param umlView The UMLView to use.
+ */
+ ToolBarStateArrow(UMLView *umlView);
+
+ /**
+ * Destroys this ToolBarStateArrow.
+ */
+ virtual ~ToolBarStateArrow();
+
+ /**
+ * Goes back to the inital state.
+ */
+ virtual void init();
+
+protected:
+
+ /**
+ * Called when the press event happened on an association.
+ * Delivers the event to the association.
+ */
+ virtual void mousePressAssociation();
+
+ /**
+ * Called when the press event happened on a widget.
+ * Delivers the event to the widget.
+ */
+ virtual void mousePressWidget();
+
+ /**
+ * Called when the press event happened on an empty space.
+ * Calls base method and, if left button was pressed, prepares the selection
+ * rectangle.
+ */
+ virtual void mousePressEmpty();
+
+ /**
+ * Called when the release event happened on an association.
+ * Delivers the event to the association.
+ */
+ virtual void mouseReleaseAssociation();
+
+ /**
+ * Called when the release event happened on a widget.
+ * Delivers the event to the widget.
+ */
+ virtual void mouseReleaseWidget();
+
+ /**
+ * Called when the release event happened on an empty space.
+ * If selection rectangle is active, it is cleared. Else, if the right
+ * button was released, it shows the pop up menu for the diagram.
+ */
+ virtual void mouseReleaseEmpty();
+
+ /**
+ * Called when the double click event happened on an association.
+ * Delivers the event to the association.
+ */
+ virtual void mouseDoubleClickAssociation();
+
+ /**
+ * Called when the double click event happened on a widget.
+ * Delivers the event to the widget.
+ */
+ virtual void mouseDoubleClickWidget();
+
+ /**
+ * Called when the move event happened when an association is
+ * currently available.
+ * Delivers the event to the association.
+ */
+ virtual void mouseMoveAssociation();
+
+ /**
+ * Called when the move event happened when a widget is
+ * currently available.
+ * Delivers the event to the widget.
+ */
+ virtual void mouseMoveWidget();
+
+ /**
+ * Called when the move event happened when no association nor
+ * widget are currently available.
+ * Updates the selection rectangle to the new position and selectes all the
+ * widgets in the rectangle.
+ *
+ * @todo Fix selection
+ */
+ virtual void mouseMoveEmpty();
+
+ /**
+ * Sets the widget currently in use.
+ * It ensures that the widget is only set if there is no other widget set
+ * already.
+ * It avoids things like moving a big widget over a little one, clicking
+ * right button to cancel the movement and the little widget getting the
+ * event, thus not cancelling the movement in the big widget.
+ */
+ virtual void setCurrentWidget(UMLWidget* currentWidget);
+
+ /**
+ * Overriden from base class to do nothing, as arrow is the default tool.
+ */
+ virtual void changeTool();
+
+ /**
+ * The selection rectangle that contains the four lines of its borders.
+ */
+ QPtrList<QCanvasLine> m_selectionRect;
+
+ /**
+ * The start position of the selection rectangle.
+ */
+ QPoint m_startPosition;
+
+};
+
+#endif //TOOLBARSTATEARROW_H
diff --git a/umbrello/umbrello/toolbarstateassociation.cpp b/umbrello/umbrello/toolbarstateassociation.cpp
new file mode 100644
index 00000000..d36647dd
--- /dev/null
+++ b/umbrello/umbrello/toolbarstateassociation.cpp
@@ -0,0 +1,232 @@
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * copyright (C) 2004-2006 *
+ * Umbrello UML Modeller Authors <uml-devel@uml.sf.net> *
+ ***************************************************************************/
+
+// own header
+#include "toolbarstateassociation.h"
+
+// kde includes
+#include <kdebug.h>
+#include <klocale.h>
+#include <kmessagebox.h>
+
+// app includes
+#include "assocrules.h"
+#include "association.h"
+#include "associationwidget.h"
+#include "classifierwidget.h"
+#include "folder.h"
+#include "model_utils.h"
+#include "uml.h"
+#include "umlobject.h"
+#include "umlview.h"
+#include "umllistview.h"
+#include "umldoc.h"
+#include "umlwidget.h"
+
+using namespace Uml;
+
+ToolBarStateAssociation::ToolBarStateAssociation(UMLView *umlView) : ToolBarStatePool(umlView) {
+ m_firstWidget = 0;
+ m_associationLine = 0;
+}
+
+ToolBarStateAssociation::~ToolBarStateAssociation() {
+ delete m_associationLine;
+}
+
+void ToolBarStateAssociation::init() {
+ ToolBarStatePool::init();
+
+ cleanAssociation();
+}
+
+void ToolBarStateAssociation::cleanBeforeChange() {
+ ToolBarStatePool::cleanBeforeChange();
+
+ cleanAssociation();
+}
+
+void ToolBarStateAssociation::mouseMove(QMouseEvent* ome) {
+ ToolBarStatePool::mouseMove(ome);
+
+ if (m_associationLine) {
+ QPoint sp = m_associationLine->startPoint();
+ m_associationLine->setPoints(sp.x(), sp.y(), m_pMouseEvent->x(), m_pMouseEvent->y());
+ }
+}
+
+void ToolBarStateAssociation::slotWidgetRemoved(UMLWidget* widget) {
+ ToolBarState::slotWidgetRemoved(widget);
+
+ if (widget == m_firstWidget) {
+ cleanAssociation();
+ }
+}
+
+void ToolBarStateAssociation::mouseReleaseAssociation() {
+ if (m_pMouseEvent->button() != Qt::LeftButton ||
+ !m_firstWidget || m_firstWidget->getBaseType() != Uml::wt_Class) {
+ cleanAssociation();
+ return;
+ }
+
+ getCurrentAssociation()->createAssocClassLine(
+ static_cast<ClassifierWidget*>(m_firstWidget),
+ getCurrentAssociation()->getLinePath()->onLinePath(m_pMouseEvent->pos()));
+ cleanAssociation();
+}
+
+void ToolBarStateAssociation::mouseReleaseWidget() {
+ if (m_pMouseEvent->button() != Qt::LeftButton) {
+ cleanAssociation();
+ return;
+ }
+
+ // TODO In old code in ToolBarState there was a TODO that said: Should not
+ //be called by a Sequence message Association. Here's the check for that,
+ //although I don't know why it is needed, but it seems that it's not needed,
+ //as the old code worked fine without it...
+ if (getAssociationType() == at_Seq_Message) {
+ return;
+ }
+
+ if (!m_firstWidget) {
+ setFirstWidget();
+ } else {
+ setSecondWidget();
+ }
+}
+
+void ToolBarStateAssociation::mouseReleaseEmpty() {
+ cleanAssociation();
+}
+
+void ToolBarStateAssociation::setFirstWidget() {
+ UMLWidget* widget = getCurrentWidget();
+ Association_Type type = getAssociationType();
+
+ if (!AssocRules::allowAssociation(type, widget)) {
+ //TODO improve error feedback: tell the user what are the valid type of associations for
+ //that widget
+ KMessageBox::error(0, i18n("Incorrect use of associations."), i18n("Association Error"));
+ return;
+ }
+ //set up position
+ QPoint pos;
+ pos.setX(widget->getX() + (widget->getWidth() / 2));
+ pos.setY(widget->getY() + (widget->getHeight() / 2));
+ //TODO why is this needed?
+ m_pUMLView->setPos(pos);
+
+ m_firstWidget = widget;
+
+ m_associationLine = new QCanvasLine(m_pUMLView->canvas());
+ m_associationLine->setPoints(pos.x(), pos.y(), pos.x(), pos.y());
+ m_associationLine->setPen(QPen(m_pUMLView->getLineColor(), m_pUMLView->getLineWidth(), Qt::DashLine));
+
+ m_associationLine->setVisible(true);
+
+ m_pUMLView->viewport()->setMouseTracking(true);
+}
+
+void ToolBarStateAssociation::setSecondWidget() {
+ Association_Type type = getAssociationType();
+ UMLWidget* widgetA = m_firstWidget;
+ UMLWidget* widgetB = getCurrentWidget();
+ Widget_Type at = widgetA->getBaseType();
+ bool valid = true;
+ if (type == at_Generalization) {
+ type = AssocRules::isGeneralisationOrRealisation(widgetA, widgetB);
+ }
+ if (widgetA == widgetB) {
+ valid = AssocRules::allowSelf(type, at);
+ if (valid && type == at_Association) {
+ type = at_Association_Self;
+ }
+ } else {
+ valid = AssocRules::allowAssociation(type, widgetA, widgetB);
+ }
+ if (valid) {
+ AssociationWidget *temp = new AssociationWidget(m_pUMLView, widgetA, type, widgetB);
+ addAssociationInViewAndDoc(temp);
+ if (type == at_Containment) {
+ UMLListView *lv = UMLApp::app()->getListView();
+ UMLObject *newContainer = widgetA->getUMLObject();
+ UMLObject *objToBeMoved = widgetB->getUMLObject();
+ if (newContainer && objToBeMoved) {
+ UMLListViewItem *newLVParent = lv->findUMLObject(newContainer);
+ lv->moveObject(objToBeMoved->getID(),
+ Model_Utils::convert_OT_LVT(objToBeMoved),
+ newLVParent);
+ }
+ }
+ UMLApp::app()->getDocument()->setModified();
+ } else {
+ //TODO improve error feedback: tell the user what are the valid type of associations for
+ //the second widget using the first widget
+ KMessageBox::error(0, i18n("Incorrect use of associations."), i18n("Association Error"));
+ }
+
+ cleanAssociation();
+}
+
+Association_Type ToolBarStateAssociation::getAssociationType() {
+ Association_Type at;
+
+ switch(getButton()) {
+ case WorkToolBar::tbb_Anchor: at = at_Anchor; break;
+ case WorkToolBar::tbb_Association: at = at_Association; break;
+ case WorkToolBar::tbb_UniAssociation: at = at_UniAssociation; break;
+ case WorkToolBar::tbb_Generalization: at = at_Generalization; break;
+ case WorkToolBar::tbb_Composition: at = at_Composition; break;
+ case WorkToolBar::tbb_Aggregation: at = at_Aggregation; break;
+ case WorkToolBar::tbb_Relationship: at = at_Relationship; break;
+ case WorkToolBar::tbb_Dependency: at = at_Dependency; break;
+ case WorkToolBar::tbb_Containment: at = at_Containment; break;
+ case WorkToolBar::tbb_Seq_Message_Synchronous:
+ case WorkToolBar::tbb_Seq_Message_Asynchronous: at = at_Seq_Message; break;
+ case WorkToolBar::tbb_Coll_Message: at = at_Coll_Message; break;
+ case WorkToolBar::tbb_State_Transition: at = at_State; break;
+ case WorkToolBar::tbb_Activity_Transition: at = at_Activity; break;
+
+ default: at = at_Unknown; break;
+ }
+
+ return at;
+}
+
+void ToolBarStateAssociation::addAssociationInViewAndDoc(AssociationWidget* a) {
+ // append in view
+ if (m_pUMLView->addAssociation(a, false)) {
+ // if view went ok, then append in document
+ UMLAssociation *umla = a->getAssociation();
+ if (umla == NULL) {
+ // association without model representation in UMLDoc
+ return;
+ }
+ Uml::Model_Type m = Model_Utils::convert_DT_MT(m_pUMLView->getType());
+ UMLDoc *umldoc = UMLApp::app()->getDocument();
+ umla->setUMLPackage(umldoc->getRootFolder(m));
+ UMLApp::app()->getDocument()->addAssociation(umla);
+ } else {
+ kError() << "cannot addAssocInViewAndDoc(), deleting" << endl;
+ delete a;
+ }
+}
+
+void ToolBarStateAssociation::cleanAssociation() {
+ m_firstWidget = 0;
+
+ delete m_associationLine;
+ m_associationLine = 0;
+}
+
+#include "toolbarstateassociation.moc"
diff --git a/umbrello/umbrello/toolbarstateassociation.h b/umbrello/umbrello/toolbarstateassociation.h
new file mode 100644
index 00000000..1d6c5174
--- /dev/null
+++ b/umbrello/umbrello/toolbarstateassociation.h
@@ -0,0 +1,168 @@
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * copyright (C) 2004-2006 *
+ * Umbrello UML Modeller Authors <uml-devel@uml.sf.net> *
+ ***************************************************************************/
+
+#ifndef TOOLBARSTATEASSOCIATION_H
+#define TOOLBARSTATEASSOCIATION_H
+
+#include "toolbarstatepool.h"
+
+class QCanvasLine;
+
+/**
+ * Association tool to create associations between widgets.
+ * With association tool, two widgets are selected clicking with left button on
+ * them and an association of the needed type (depending on the association
+ * button selected) is created between the widgets. When the first widget is
+ * selected, a temporal visual association that follows the cursor movement is
+ * created until the second widget is selected or the association cancelled.
+ *
+ * Also, association tool can create association class: a classifier widget
+ * which is linked to an association. To do this, the classifier must be
+ * selected first and then the association must be selected. The association
+ * can't be selected first.
+ *
+ * An association can be cancelled using right button, which also returns to
+ * default tool, or with middle button, which only cancels the association
+ * without changing the tool being used.
+ *
+ * @todo refactor with common code in ToolBarStateMessages?
+ */
+class ToolBarStateAssociation : public ToolBarStatePool {
+ Q_OBJECT
+public:
+
+ /**
+ * Creates a new ToolBarStateAssociation.
+ *
+ * @param umlView The UMLView to use.
+ */
+ ToolBarStateAssociation(UMLView *umlView);
+
+ /**
+ * Destroys this ToolBarStateAssociation.
+ * Deletes the association line.
+ */
+ virtual ~ToolBarStateAssociation();
+
+ /**
+ * Goes back to the initial state.
+ */
+ virtual void init();
+
+ /**
+ * Called when the current tool is changed to use another tool.
+ * Executes base method and cleans the association.
+ */
+ virtual void cleanBeforeChange();
+
+ /**
+ * Called when a mouse event happened.
+ * It executes the base method and then updates the position of the
+ * association line, if any.
+ */
+ virtual void mouseMove(QMouseEvent* ome);
+
+public slots:
+
+ /**
+ * A widget was removed from the UMLView.
+ * If the widget removed was the current widget, the current widget is set
+ * to 0.
+ * Also, if it was the first widget, the association is cleaned.
+ */
+ virtual void slotWidgetRemoved(UMLWidget* widget);
+
+protected:
+
+ /**
+ * Called when the release event happened on an association.
+ * If the button pressed isn't left button, the association being created is
+ * cleaned. If it is left button, and the first widget is set and is a
+ * classifier widget, it creates an association class. Otherwise, the
+ * association being created is cleaned.
+ */
+ virtual void mouseReleaseAssociation();
+
+ /**
+ * Called when the release event happened on a widget.
+ * If the button pressed isn't left button, the association is cleaned. If
+ * it is left button, sets the first widget or the second, depending on
+ * whether the first widget is already set or not.
+ */
+ virtual void mouseReleaseWidget();
+
+ /**
+ * Called when the release event happened on an empty space.
+ * Cleans the association.
+ */
+ virtual void mouseReleaseEmpty();
+
+private:
+
+ /**
+ * Sets the first widget in the association using the current widget.
+ * If the widget can't be associated using the current type of association,
+ * an error is shown and the widget isn't set.
+ * Otherwise, the temporal visual association is created and the mouse
+ * tracking is enabled, so move events will be delivered.
+ */
+ void setFirstWidget();
+
+ /**
+ * Sets the second widget in the association using the current widget and
+ * creates the association.
+ * If the association between the two widgets using the current type of
+ * association, an error is shown and the association cancelled.
+ * Otherwise, the association is created and added to the view, and the tool
+ * is changed to the default tool.
+ *
+ * @todo Why change to the default tool? Shouldn't it better to stay on
+ * association and let the user change with a right click? The tool to
+ * create widgets doesn't change to default after creating a widget
+ */
+ void setSecondWidget();
+
+ /**
+ * Returns the association type of this tool.
+ *
+ * @return The association type of this tool.
+ */
+ Uml::Association_Type getAssociationType();
+
+ /**
+ * Adds an AssociationWidget to the association list and creates the
+ * corresponding UMLAssociation in the current UMLDoc.
+ * If the association can't be added, is deleted.
+ *
+ * @param association The AssociationWidget to add.
+ */
+ void addAssociationInViewAndDoc(AssociationWidget* association);
+
+ /**
+ * Cleans the first widget and the temporal association line, if any.
+ * Both are set to null, and the association line is also deleted.
+ */
+ void cleanAssociation();
+
+ /**
+ * The first widget in the association.
+ */
+ UMLWidget* m_firstWidget;
+
+ /**
+ * The association line shown while the first widget is selected and the
+ * second one wasn't selected yet.
+ */
+ QCanvasLine* m_associationLine;
+
+};
+
+#endif //TOOLBARSTATEASSOCIATION_H
diff --git a/umbrello/umbrello/toolbarstatefactory.cpp b/umbrello/umbrello/toolbarstatefactory.cpp
new file mode 100644
index 00000000..66cf89bb
--- /dev/null
+++ b/umbrello/umbrello/toolbarstatefactory.cpp
@@ -0,0 +1,96 @@
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * copyright (C) 2004-2006 *
+ * Umbrello UML Modeller Authors <uml-devel@uml.sf.net> *
+ ***************************************************************************/
+#include "toolbarstatefactory.h"
+
+#include "toolbarstate.h"
+#include "toolbarstatepool.h"
+#include "toolbarstateother.h"
+#include "toolbarstatearrow.h"
+#include "toolbarstatemessages.h"
+#include "toolbarstateassociation.h"
+
+#include "umlview.h"
+
+ToolBarStateFactory::ToolBarStateFactory(UMLView *umlView)
+{
+ m_pUMLView = umlView;
+
+ for (int i = 0; i < NR_OF_TOOLBAR_STATES; i++)
+ {
+ states[i] = NULL;
+ }
+}
+
+ToolBarStateFactory::~ToolBarStateFactory()
+{
+ for (int i = 0; i < NR_OF_TOOLBAR_STATES; i++)
+ {
+ if (states[i] != NULL) delete states[i];
+ }
+}
+
+
+ToolBarState* ToolBarStateFactory::getState(const WorkToolBar::ToolBar_Buttons &toolbarButton)
+{
+ int key = getKey(toolbarButton);
+
+ if (states[key] == NULL)
+ {
+ switch (key)
+ {
+ // When you add a new state, make sure you also increase the
+ // NR_OF_TOOLBAR_STATES
+ case 0: states[0] = new ToolBarStateOther(m_pUMLView); break;
+ case 1: states[1] = new ToolBarStateAssociation(m_pUMLView); break;
+ case 2: states[2] = new ToolBarStateMessages(m_pUMLView); break;
+
+ // This case has no pool.
+ case 3: states[3] = new ToolBarStateArrow(m_pUMLView); break;
+ }
+ }
+
+ // Make explicit the selected button. This is only necessary for states with a pool.
+ if (key <= 2) ((ToolBarStatePool *) states[key])->setButton(toolbarButton);
+
+ return states[key];
+}
+
+
+int ToolBarStateFactory::getKey(const WorkToolBar::ToolBar_Buttons &toolbarButton) const
+{
+ switch (toolbarButton)
+ {
+ // Associations
+ case WorkToolBar::tbb_Dependency: return 1;
+ case WorkToolBar::tbb_Aggregation: return 1;
+ case WorkToolBar::tbb_Relationship: return 1;
+ case WorkToolBar::tbb_Generalization: return 1;
+ case WorkToolBar::tbb_Association: return 1;
+ case WorkToolBar::tbb_UniAssociation: return 1;
+ case WorkToolBar::tbb_Composition: return 1;
+ case WorkToolBar::tbb_Containment: return 1;
+ case WorkToolBar::tbb_Anchor: return 1;
+ case WorkToolBar::tbb_Coll_Message: return 1;
+ case WorkToolBar::tbb_State_Transition: return 1;
+ case WorkToolBar::tbb_Activity_Transition: return 1;
+
+ // Messages
+ case WorkToolBar::tbb_Seq_Message_Synchronous: return 2;
+ case WorkToolBar::tbb_Seq_Message_Asynchronous: return 2;
+
+ // Arrow pointer
+ case WorkToolBar::tbb_Arrow: return 3;
+
+ // Other.
+ default: return 0;
+ }
+
+}
diff --git a/umbrello/umbrello/toolbarstatefactory.h b/umbrello/umbrello/toolbarstatefactory.h
new file mode 100644
index 00000000..b5c1ee4c
--- /dev/null
+++ b/umbrello/umbrello/toolbarstatefactory.h
@@ -0,0 +1,53 @@
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * copyright (C) 2004-2006 *
+ * Umbrello UML Modeller Authors <uml-devel@uml.sf.net> *
+ ***************************************************************************/
+
+#ifndef TOOLBARSTATEFACTORY_H
+#define TOOLBARSTATEFACTORY_H
+
+#include "toolbarstate.h"
+
+#include "worktoolbar.h"
+
+#define NR_OF_TOOLBAR_STATES 4
+
+class UMLView;
+
+
+/**
+ * The ToolBarStateFactory keeps track of all the toolbar states. For the first
+ * request, the factory creates a new state object. The next requests to this
+ * object, this factory will return the existing object.
+ *
+ * States that inherit from the ToolBarStatePool share multiple toolbar states.
+ * Therefore the setButton function is called. Internally the shared state object
+ * determines the exact behavior by itself.
+ */
+class ToolBarStateFactory
+{
+public:
+ // constructor.
+ ToolBarStateFactory(UMLView* umlView);
+
+ // Destructor
+ virtual ~ToolBarStateFactory();
+
+ ToolBarState* getState(const WorkToolBar::ToolBar_Buttons &toolbarButton);
+
+protected:
+ int getKey(const WorkToolBar::ToolBar_Buttons &toolbarButton) const;
+
+protected:
+ ToolBarState* states[NR_OF_TOOLBAR_STATES];
+
+ UMLView* m_pUMLView;
+};
+
+#endif //TOOLBARSTATEFACTORY_H
diff --git a/umbrello/umbrello/toolbarstatemessages.cpp b/umbrello/umbrello/toolbarstatemessages.cpp
new file mode 100644
index 00000000..36ffb005
--- /dev/null
+++ b/umbrello/umbrello/toolbarstatemessages.cpp
@@ -0,0 +1,169 @@
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * copyright (C) 2004-2006 *
+ * Umbrello UML Modeller Authors <uml-devel@uml.sf.net> *
+ ***************************************************************************/
+
+// own header
+#include "toolbarstatemessages.h"
+
+// kde includes
+#include <kdebug.h>
+
+// local includes
+#include "floatingtextwidget.h"
+#include "messagewidget.h"
+#include "objectwidget.h"
+#include "uml.h"
+#include "umldoc.h"
+#include "umlview.h"
+
+ToolBarStateMessages::ToolBarStateMessages(UMLView *umlView) : ToolBarStatePool(umlView) {
+ m_firstObject = 0;
+ m_messageLine = 0;
+}
+
+ToolBarStateMessages::~ToolBarStateMessages() {
+ delete m_messageLine;
+}
+
+void ToolBarStateMessages::init() {
+ ToolBarStatePool::init();
+
+ cleanMessage();
+}
+
+void ToolBarStateMessages::cleanBeforeChange() {
+ ToolBarStatePool::cleanBeforeChange();
+
+ cleanMessage();
+}
+
+void ToolBarStateMessages::mouseMove(QMouseEvent* ome) {
+ ToolBarStatePool::mouseMove(ome);
+
+ if (m_messageLine) {
+ QPoint sp = m_messageLine->startPoint();
+ m_messageLine->setPoints(sp.x(), sp.y(), m_pMouseEvent->x(), m_pMouseEvent->y());
+ }
+}
+
+void ToolBarStateMessages::slotWidgetRemoved(UMLWidget* widget) {
+ ToolBarState::slotWidgetRemoved(widget);
+
+ if (widget == m_firstObject) {
+ cleanMessage();
+ }
+}
+
+void ToolBarStateMessages::setCurrentElement() {
+ m_isObjectWidgetLine = false;
+
+ ObjectWidget* objectWidgetLine = m_pUMLView->onWidgetLine(m_pMouseEvent->pos());
+ if (objectWidgetLine) {
+ setCurrentWidget(objectWidgetLine);
+ m_isObjectWidgetLine = true;
+ return;
+ }
+
+ //commit 515177 fixed a setting creation messages only working properly at 100% zoom
+ //However, the applied patch doesn't seem to be necessary no more, so it was removed
+ //The widgets weren't got from UMLView, but from a method in this class similarto the
+ //one in UMLView but containing special code to handle the zoom
+ UMLWidget *widget = m_pUMLView->getWidgetAt(m_pMouseEvent->pos());
+ if (widget) {
+ setCurrentWidget(widget);
+ return;
+ }
+}
+
+void ToolBarStateMessages::mouseReleaseWidget() {
+ //TODO When an association between UMLObjects of invalid types is made, an error message
+ //is shown. Shouldn't also a message be used here?
+ if (m_pMouseEvent->button() != Qt::LeftButton ||
+ getCurrentWidget()->getBaseType() != Uml::wt_Object) {
+ cleanMessage();
+ return;
+ }
+
+ if (!m_isObjectWidgetLine && !m_firstObject) {
+ return;
+ }
+
+ if (!m_isObjectWidgetLine) {
+ setSecondWidget(static_cast<ObjectWidget*>(getCurrentWidget()), CreationMessage);
+ return;
+ }
+
+ if (!m_firstObject) {
+ setFirstWidget(static_cast<ObjectWidget*>(getCurrentWidget()));
+ } else {
+ setSecondWidget(static_cast<ObjectWidget*>(getCurrentWidget()), NormalMessage);
+ }
+}
+
+void ToolBarStateMessages::mouseReleaseEmpty() {
+ cleanMessage();
+}
+
+void ToolBarStateMessages::setFirstWidget(ObjectWidget* firstObject) {
+ m_firstObject = firstObject;
+
+ m_messageLine = new QCanvasLine(m_pUMLView->canvas());
+ m_messageLine->setPoints(m_pMouseEvent->x(), m_pMouseEvent->y(), m_pMouseEvent->x(), m_pMouseEvent->y());
+ m_messageLine->setPen(QPen(m_pUMLView->getLineColor(), m_pUMLView->getLineWidth(), Qt::DashLine));
+
+ m_messageLine->setVisible(true);
+
+ m_pUMLView->viewport()->setMouseTracking(true);
+}
+
+void ToolBarStateMessages::setSecondWidget(ObjectWidget* secondObject, MessageType messageType) {
+ Uml::Sequence_Message_Type msgType = getMessageType();
+
+ //TODO shouldn't start position in the first widget be used also for normal messages
+ //and not only for creation?
+ int y = m_pMouseEvent->y();
+ if (messageType == CreationMessage) {
+ msgType = Uml::sequence_message_creation;
+ y = m_messageLine->startPoint().y();
+ }
+
+ MessageWidget* message = new MessageWidget(m_pUMLView, m_firstObject,
+ secondObject, y, msgType);
+
+ cleanMessage();
+
+ m_pUMLView->getMessageList().append(message);
+
+ FloatingTextWidget *ft = message->getFloatingTextWidget();
+ //TODO cancel doesn't cancel the creation of the message, only cancels setting an operation.
+ //Shouldn't it cancel also the whole creation?
+ ft->showOpDlg();
+ message->setTextPosition();
+ m_pUMLView->getWidgetList().append(ft);
+
+ UMLApp::app()->getDocument()->setModified();
+}
+
+Uml::Sequence_Message_Type ToolBarStateMessages::getMessageType() {
+ if (getButton() == WorkToolBar::tbb_Seq_Message_Synchronous) {
+ return Uml::sequence_message_synchronous;
+ }
+
+ return Uml::sequence_message_asynchronous;
+}
+
+void ToolBarStateMessages::cleanMessage() {
+ m_firstObject = 0;
+
+ delete m_messageLine;
+ m_messageLine = 0;
+}
+
+#include "toolbarstatemessages.moc"
diff --git a/umbrello/umbrello/toolbarstatemessages.h b/umbrello/umbrello/toolbarstatemessages.h
new file mode 100644
index 00000000..f6b2cb79
--- /dev/null
+++ b/umbrello/umbrello/toolbarstatemessages.h
@@ -0,0 +1,187 @@
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * copyright (C) 2004-2006 *
+ * Umbrello UML Modeller Authors <uml-devel@uml.sf.net> *
+ ***************************************************************************/
+
+#ifndef TOOLBARSTATEMESSAGES_H
+#define TOOLBARSTATEMESSAGES_H
+
+#include "toolbarstatepool.h"
+#include <qpoint.h>
+
+class QCanvasLine;
+class ObjectWidget;
+
+/**
+ * Messages tool to create messages between objects in sequence diagrams.
+ * With messages tool, two objects are selected clicking with left button on
+ * them and a message of the needed type (depending on the message button
+ * selected) is created between the objects. When the first object is selected,
+ * a temporal visual message that follows the cursor movement is created until
+ * the second object is selected or the message cancelled.
+ *
+ * A message can be cancelled using right button, which also returns to default
+ * tool, or with middle button, which only cancels the message without changing
+ * the tool being used.
+ *
+ * The messages to create can be normal messages or creation messages. Normal
+ * messages are created clicking on the line of the two objects. Creation
+ * messages are created clicking in the line of the first object, and on the
+ * second object itself (not in its line).
+ *
+ * Associations aren't taken into account, and are treated as empty spaces.
+ * Moreover, widgets other than objects aren't neither taken into account.
+ *
+ * @todo refactor with common code in ToolBarStateAssociation?
+ * @todo sequence message lines should be handled by object widgets. Right now,
+ * they aren't taken into account in testOnWidget and an explicit check is
+ * needed. However, if onWidget in object widgets is changed to also check for
+ * the line, a way to make them prioritaries over other widgets in testOnWidget
+ * will be needed. For example, when creating a message clicking on an already
+ * created message,the message line must be got instead of the message, even if
+ * the message is smaller than the line.
+ */
+class ToolBarStateMessages : public ToolBarStatePool {
+ Q_OBJECT
+public:
+
+ /**
+ * Creates a new ToolBarStateMessages.
+ *
+ * @param umlView The UMLView to use.
+ */
+ ToolBarStateMessages(UMLView *umlView);
+
+ /**
+ * Destroys this ToolBarStateMessages.
+ */
+ virtual ~ToolBarStateMessages();
+
+ /**
+ * Goes back to the initial state.
+ */
+ virtual void init();
+
+ /**
+ * Called when the current tool is changed to use another tool.
+ * Executes base method and cleans the message.
+ */
+ virtual void cleanBeforeChange();
+
+ /**
+ * Called when a mouse event happened.
+ * It executes the base method and then updates the position of the
+ * message line, if any.
+ */
+ virtual void mouseMove(QMouseEvent* ome);
+
+public slots:
+
+ /**
+ * A widget was removed from the UMLView.
+ * If the widget removed was the current widget, the current widget is set
+ * to 0.
+ * Also, if it was the first object, the message is cleaned.
+ */
+ virtual void slotWidgetRemoved(UMLWidget* widget);
+
+protected:
+
+ /**
+ * Selects only widgets, but no associations.
+ * Overrides base class method.
+ * If the press event happened on the line of an object, the object is set
+ * as current widget. If the press event happened on a widget, the widget is
+ * set as current widget.
+ */
+ virtual void setCurrentElement();
+
+ /**
+ * Called when the release event happened on a widget.
+ * If the button pressed isn't left button or the widget isn't an object
+ * widget, the message is cleaned.
+ * If the release event didn't happen on the line of an object and the first
+ * object wasn't selected, nothing is done. If the first object was already
+ * selected, a creation message is made.
+ * If the event happened on the line of an object, the first object or the
+ * second are set, depending on whether the first object was already set or
+ * not.
+ */
+ virtual void mouseReleaseWidget();
+
+ /**
+ * Called when the release event happened on an empty space.
+ * Cleans the message.
+ * Empty spaces are not only actual empty spaces, but also associations.
+ */
+ virtual void mouseReleaseEmpty();
+
+protected:
+
+ /**
+ * The type of the message to create.
+ */
+ enum MessageType {
+ NormalMessage,
+ CreationMessage
+ };
+
+ /**
+ * Sets the first object of the message using the specified object.
+ * The temporal visual message is created and mouse tracking enabled, so
+ * mouse events will be delivered.
+ *
+ * @param firstObject The first object of the message.
+ */
+ void setFirstWidget(ObjectWidget* firstObject);
+
+ /**
+ * Sets the second object of the message using the specified widget and
+ * creates the message.
+ * The association is created and added to the view. The dialog to select
+ * the operation of the message is shown.
+ *
+ * @param secondObject The second object of the message.
+ * @param messageType The type of the message to create.
+ */
+ void setSecondWidget(ObjectWidget* secondObject, MessageType messageType);
+
+ /**
+ * Returns the message type of this tool.
+ *
+ * @return The message type of this tool.
+ */
+ Uml::Sequence_Message_Type getMessageType();
+
+ /**
+ * Cleans the first widget and the temporal message line, if any.
+ * Both are set to null, and the message line is also deleted.
+ */
+ void cleanMessage();
+
+ /**
+ * The first object in the message.
+ */
+ ObjectWidget* m_firstObject;
+
+ /**
+ * The message line shown while the first widget is selected and the
+ * second one wasn't selected yet.
+ */
+ QCanvasLine* m_messageLine;
+
+ /**
+ * If there is a current widget, it is true if the press event happened on
+ * the line of an object, or false if it happened on a normal UMLWidget.
+ */
+ bool m_isObjectWidgetLine;
+
+};
+
+#endif //TOOLBARSTATEMESSAGES_H
diff --git a/umbrello/umbrello/toolbarstateother.cpp b/umbrello/umbrello/toolbarstateother.cpp
new file mode 100644
index 00000000..f6161dbd
--- /dev/null
+++ b/umbrello/umbrello/toolbarstateother.cpp
@@ -0,0 +1,163 @@
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * copyright (C) 2004-2006 *
+ * Umbrello UML Modeller Authors <uml-devel@uml.sf.net> *
+ ***************************************************************************/
+
+// own header
+#include "toolbarstateother.h"
+
+// kde includes
+#include <kdebug.h>
+#include <klocale.h>
+#include <kinputdialog.h>
+
+// app includes
+#include "activitywidget.h"
+#include "boxwidget.h"
+#include "dialog_utils.h"
+#include "floatingtextwidget.h"
+#include "forkjoinwidget.h"
+#include "notewidget.h"
+#include "object_factory.h"
+#include "statewidget.h"
+#include "uml.h"
+#include "umlview.h"
+#include "umldoc.h"
+
+using namespace Uml;
+
+ToolBarStateOther::ToolBarStateOther(UMLView *umlView) : ToolBarStatePool(umlView) {
+}
+
+ToolBarStateOther::~ToolBarStateOther() {
+}
+
+void ToolBarStateOther::setCurrentElement() {
+}
+
+void ToolBarStateOther::mouseReleaseEmpty() {
+ if (m_pMouseEvent->button() == Qt::LeftButton) {
+ if (!newWidget()) {
+ // Is UMLObject?
+
+ m_pUMLView->setCreateObject(true);
+ Object_Factory::createUMLObject(getObjectType());
+ }
+
+ m_pUMLView->resizeCanvasToItems();
+ }
+}
+
+Uml::Object_Type ToolBarStateOther::getObjectType() {
+ Object_Type ot;
+
+ switch(getButton()) {
+ case WorkToolBar::tbb_Actor: ot = ot_Actor; break;
+ case WorkToolBar::tbb_UseCase: ot = ot_UseCase; break;
+ case WorkToolBar::tbb_Class: ot = ot_Class; break;
+ case WorkToolBar::tbb_Object: ot = ot_Class; break; // Object is a class.
+ case WorkToolBar::tbb_Package: ot = ot_Package; break;
+ case WorkToolBar::tbb_Component: ot = ot_Component; break;
+ case WorkToolBar::tbb_Node: ot = ot_Node; break;
+ case WorkToolBar::tbb_Artifact: ot = ot_Artifact; break;
+ case WorkToolBar::tbb_Interface: ot = ot_Interface; break;
+ case WorkToolBar::tbb_Enum: ot = ot_Enum; break;
+ case WorkToolBar::tbb_Entity: ot = ot_Entity; break;
+ case WorkToolBar::tbb_Datatype: ot = ot_Datatype; break;
+
+ default: ot = ot_UMLObject; break;
+ }
+
+ return ot;
+}
+
+// TODO: The name is a bit confusing.
+bool ToolBarStateOther::newWidget() {
+ UMLWidget* umlWidget = NULL;
+
+ switch (getButton()) {
+ case WorkToolBar::tbb_Note:
+ umlWidget = new NoteWidget(m_pUMLView);
+ break;
+
+ case WorkToolBar::tbb_Box:
+ umlWidget = new BoxWidget(m_pUMLView);
+ break;
+
+ case WorkToolBar::tbb_Text:
+ umlWidget = new FloatingTextWidget(m_pUMLView, tr_Floating, "");
+ break;
+
+ // Activity buttons
+ case WorkToolBar::tbb_Initial_Activity:
+ umlWidget = new ActivityWidget(m_pUMLView, ActivityWidget::Initial);
+ break;
+
+ case WorkToolBar::tbb_Activity:
+ umlWidget = new ActivityWidget(m_pUMLView, ActivityWidget::Normal);
+ break;
+
+ case WorkToolBar::tbb_End_Activity:
+ umlWidget = new ActivityWidget(m_pUMLView, ActivityWidget::End);
+ break;
+
+ case WorkToolBar::tbb_Branch:
+ umlWidget = new ActivityWidget(m_pUMLView, ActivityWidget::Branch);
+ break;
+
+ case WorkToolBar::tbb_Fork:
+ case WorkToolBar::tbb_StateFork:
+ umlWidget = new ForkJoinWidget(m_pUMLView);
+ break;
+
+ case WorkToolBar::tbb_Initial_State:
+ umlWidget = new StateWidget(m_pUMLView, StateWidget::Initial);
+ break;
+
+ case WorkToolBar::tbb_State:
+ umlWidget = new StateWidget(m_pUMLView, StateWidget::Normal);
+ break;
+
+ case WorkToolBar::tbb_End_State:
+ umlWidget = new StateWidget(m_pUMLView, StateWidget::End);
+ break;
+
+ default:
+ break;
+ }
+
+ // Return false if we didn't find a suitable widget.
+ if (umlWidget == NULL) {
+ return false;
+ }
+
+ // Special treatment for some buttons
+ if (getButton() == WorkToolBar::tbb_Activity) {
+ Dialog_Utils::askNameForWidget(
+ umlWidget, i18n("Enter Activity Name"),
+ i18n("Enter the name of the new activity:"), i18n("new activity"));
+ } else if (getButton() == WorkToolBar::tbb_State) {
+ Dialog_Utils::askNameForWidget(
+ umlWidget, i18n("Enter State Name"),
+ i18n("Enter the name of the new state:"), i18n("new state"));
+ } else if (getButton() == WorkToolBar::tbb_Text) {
+ // It is pretty invisible otherwise.
+ FloatingTextWidget* ft = (FloatingTextWidget*) umlWidget;
+ ft->changeTextDlg();
+ }
+
+ // Create the widget. Some setup functions can remove the widget.
+ if (umlWidget != NULL) {
+ m_pUMLView->setupNewWidget(umlWidget);
+ }
+
+ return true;
+}
+
+#include "toolbarstateother.moc"
diff --git a/umbrello/umbrello/toolbarstateother.h b/umbrello/umbrello/toolbarstateother.h
new file mode 100644
index 00000000..d5c6f412
--- /dev/null
+++ b/umbrello/umbrello/toolbarstateother.h
@@ -0,0 +1,83 @@
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * copyright (C) 2004-2006 *
+ * Umbrello UML Modeller Authors <uml-devel@uml.sf.net> *
+ ***************************************************************************/
+
+#ifndef TOOLBARSTATEOTHER_H
+#define TOOLBARSTATEOTHER_H
+
+#include "toolbarstatepool.h"
+
+/**
+ * Other tool creates almost all the objects (except associations and messages).
+ * Objects are created when left button is released, no matter if it was
+ * released on an association, on a widget or on an empty space.
+ *
+ * Associations and widgets aren't taken into account, and are treated as empty
+ * spaces.
+ */
+class ToolBarStateOther : public ToolBarStatePool {
+ Q_OBJECT
+public:
+
+ /**
+ * Creates a new ToolBarStateOther.
+ *
+ * @param umlView The UMLView to use.
+ */
+ ToolBarStateOther(UMLView *umlView);
+
+ /**
+ * Destroys this ToolBarStateOther.
+ */
+ virtual ~ToolBarStateOther();
+
+private:
+
+ /**
+ * Sets nothing.
+ * Overriden from base class to ignore associations and widgets and treat
+ * them as empty spaces to create widgets on it.
+ */
+ virtual void setCurrentElement();
+
+ /**
+ * Called when the release event happened on an empty space.
+ * Associations, widgets and actual empty spaces are all treated as empty
+ * spaces. It creates a new widget if the left button was released.
+ * The widget to create depends on the type of the toolbar button selected.
+ * If the widget is the visual representation of an UMLObject, the object
+ * factory handles its creation. Otherwise, the widget is created using
+ * newWidget().
+ * The UMLView is resized to fit on all the items.
+ */
+ virtual void mouseReleaseEmpty();
+
+ /**
+ * Returns the object type of this tool.
+ *
+ * @return The object type of this tool.
+ */
+ Uml::Object_Type getObjectType();
+
+ /**
+ * Creates and adds a new widget to the UMLView (if widgets of that type
+ * don't have an associated UMLObject).
+ * If the type of the widget doesn't use an UMLObject (for example, a note
+ * or a box), it creates the widget, adds it to the view and returns true.
+ * Otherwise, it returns false.
+ *
+ * @return True if the widget was created, false otherwise.
+ * @todo rename to something more clear
+ */
+ bool newWidget();
+
+};
+
+#endif //TOOLBARSTATEOTHER_H
diff --git a/umbrello/umbrello/toolbarstatepool.cpp b/umbrello/umbrello/toolbarstatepool.cpp
new file mode 100644
index 00000000..3bb2d04a
--- /dev/null
+++ b/umbrello/umbrello/toolbarstatepool.cpp
@@ -0,0 +1,30 @@
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * copyright (C) 2004-2006 *
+ * Umbrello UML Modeller Authors <uml-devel@uml.sf.net> *
+ ***************************************************************************/
+
+// own header
+#include "toolbarstatepool.h"
+
+ToolBarStatePool::~ToolBarStatePool() {
+}
+
+void ToolBarStatePool::setButton(const WorkToolBar::ToolBar_Buttons &button) {
+ if (button != m_ToolBarButton) {
+ m_ToolBarButton = button;
+
+ init(); // Go back to the initial state.
+ }
+}
+
+ToolBarStatePool::ToolBarStatePool(UMLView *umlView): ToolBarState(umlView) {
+ m_ToolBarButton = WorkToolBar::tbb_Arrow;
+}
+
+#include "toolbarstatepool.moc"
diff --git a/umbrello/umbrello/toolbarstatepool.h b/umbrello/umbrello/toolbarstatepool.h
new file mode 100644
index 00000000..6b33f9ea
--- /dev/null
+++ b/umbrello/umbrello/toolbarstatepool.h
@@ -0,0 +1,71 @@
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * copyright (C) 2004-2006 *
+ * Umbrello UML Modeller Authors <uml-devel@uml.sf.net> *
+ ***************************************************************************/
+
+#ifndef TOOLBARSTATEPOOL_H
+#define TOOLBARSTATEPOOL_H
+
+#include "toolbarstate.h"
+
+#include "worktoolbar.h"
+
+/**
+ * Base class for tools that can use the same state but with different button.
+ * This class only adds support to specify the button currently in use for a
+ * tool bar state.
+ */
+class ToolBarStatePool : public ToolBarState {
+ Q_OBJECT
+public:
+
+ /**
+ * Destroys this ToolBarStatePool.
+ */
+ virtual ~ToolBarStatePool();
+
+ /**
+ * Sets the current button and inits the tool.
+ * If the current button is the same to the button to set, the tool isn't
+ * initialized.
+ *
+ * @param button The button to set.
+ */
+ void setButton(const WorkToolBar::ToolBar_Buttons &button);
+
+ /**
+ * Returns the current button.
+ *
+ * @return The current button.
+ */
+ WorkToolBar::ToolBar_Buttons getButton() const {
+ return m_ToolBarButton;
+ }
+
+protected:
+
+ /**
+ * Creates a new ToolBarStatePool.
+ * Protected to avoid classes other than derived to create objects of this
+ * class.
+ *
+ * @param umlView The UMLView to use.
+ */
+ ToolBarStatePool(UMLView *umlView);
+
+private:
+
+ /**
+ * The current button of the tool.
+ */
+ WorkToolBar::ToolBar_Buttons m_ToolBarButton;
+
+};
+
+#endif //TOOLBARSTATEPOOL_H
diff --git a/umbrello/umbrello/umbrello.desktop b/umbrello/umbrello/umbrello.desktop
new file mode 100644
index 00000000..e414a8da
--- /dev/null
+++ b/umbrello/umbrello/umbrello.desktop
@@ -0,0 +1,57 @@
+# KDE Config File
+[Desktop Entry]
+Type=Application
+Exec=umbrello -caption "%c" %i %m
+Icon=umbrello
+DocPath=umbrello/index.html
+Terminal=false
+Name=Umbrello
+Name[hi]=अमà¥à¤¬à¤°à¥ˆà¤²à¥‹
+Name[ne]=अमà¥à¤¬à¥à¤°à¥‡à¤²à¥‹
+Name[pa]=ਉਮਬਰਿੱਲਓ
+Name[ta]= à®…à®®à¯à®°à®²à¯à®²à¯‹
+GenericName=UML Modeller
+GenericName[bs]=UML modeler
+GenericName[ca]=Modelador UML
+GenericName[cs]=UML modelář
+GenericName[cy]=Modelydd UML
+GenericName[da]=UML Modellering
+GenericName[de]=UML-Modellierer
+GenericName[el]=Μοντελοποιητής UML
+GenericName[eo]=UML-Modelilo
+GenericName[es]=Modelador de UML
+GenericName[et]=UML-i modelleerimise rakendus
+GenericName[eu]=UML modelatzailea
+GenericName[fa]=مدل‌ساز UML
+GenericName[fi]=UML-mallintaja
+GenericName[fr]=Modeleur UML
+GenericName[ga]=Múnlóir UML
+GenericName[gl]=Modelador de UML
+GenericName[hi]=यूà¤à¤®à¤à¤² मॉडलर
+GenericName[hu]=UML-modellező
+GenericName[it]=Modellatore UML
+GenericName[ja]=UML モデラー
+GenericName[ka]=UML მáƒáƒ“ელერი
+GenericName[kk]=UML үлгілегіші
+GenericName[ms]=Pemodel UML
+GenericName[nb]=UML-modelleringsprogram
+GenericName[nds]=UML-Modellmaker
+GenericName[ne]=यूà¤à¤®à¤à¤² मोडेलर
+GenericName[nl]=UML-modeller
+GenericName[nn]=UML-modelleringsprogram
+GenericName[pl]=Program do modelowania UML
+GenericName[pt]=Modelador de UML
+GenericName[pt_BR]=Modelador UML
+GenericName[ru]=СредÑтво UML моделированиÑ
+GenericName[sk]=Modelár UML
+GenericName[sl]=Mofdelirnik UML
+GenericName[sr]=UML моделар
+GenericName[sr@Latn]=UML modelar
+GenericName[sv]=UML-modellering
+GenericName[ta]=UML மோடெலà¯à®²à®¾à®°à¯
+GenericName[tg]=ВоÑитаи UML моделкунонӣ
+GenericName[tr]=UML Modelleyici
+GenericName[uk]=ЗаÑіб Ð¼Ð¾Ð´ÐµÐ»ÑŽÐ²Ð°Ð½Ð½Ñ UML
+GenericName[zh_CN]=UML 建模工具
+MimeType=application/x-uml;
+Categories=Qt;KDE;Development;
diff --git a/umbrello/umbrello/umbrelloui.rc b/umbrello/umbrello/umbrelloui.rc
new file mode 100644
index 00000000..f14efddd
--- /dev/null
+++ b/umbrello/umbrello/umbrelloui.rc
@@ -0,0 +1,58 @@
+<!DOCTYPE kpartgui>
+<kpartgui name="umbrello" version="11">
+<MenuBar>
+ <Menu name="file"><text>&amp;File</text>
+ <Menu name="file_export"><text>&amp;Export</text>
+ <Action name="file_export_docbook"/>
+ <Action name="file_export_xhtml"/>
+ </Menu>
+ </Menu>
+ <Menu name="edit"><text>&amp;Edit</text>
+ <Action name="delete_selected"/>
+ </Menu>
+ <Menu name="views"><text>&amp;Diagram</text>
+ <Menu name="new_view"><text>&amp;New</text>
+ <Action name="new_class_diagram"/>
+ <Action name="new_sequence_diagram"/>
+ <Action name="new_collaboration_diagram"/>
+ <Action name="new_use_case_diagram"/>
+ <Action name="new_state_diagram"/>
+ <Action name="new_activity_diagram"/>
+ <Action name="new_component_diagram"/>
+ <Action name="new_deployment_diagram"/>
+ <Action name="new_entityrelationship_diagram"/>
+ </Menu>
+ <Action name="view_clear_diagram"/>
+ <Action name="view_delete"/>
+ <Action name="view_export_image"/>
+ <Action name="view_export_image_all"/>
+ <Action name="autolayout" />
+ <Separator/>
+ <Menu name="show_view"><text>Sh&amp;ow</text>
+ <ActionList name="view_list">
+ </ActionList>
+ </Menu>
+ <Menu name="zoom_menu"><text>&amp;Zoom</text>
+ </Menu>
+ <Separator/>
+ <Action name="view_snap_to_grid"/>
+ <Action name="view_show_grid"/>
+ <Action name="view_properties"/>
+ </Menu>
+
+ <Menu name="code"><text>&amp;Code</text>
+ <Action name="import_class"/>
+ <Action name="generation_wizard"/>
+ <Action name="generate_all"/>
+ <Menu name="active_lang_menu"><text>Active &amp;Language</text>
+ </Menu>
+ <Separator/>
+ <Action name="create_default_datatypes"/>
+ <Action name="class_wizard"/>
+ </Menu>
+</MenuBar>
+<ToolBar name="mainToolBar">
+ <Action name="popup_zoom"/>
+ <Action name="zoom100"/>
+</ToolBar>
+</kpartgui>
diff --git a/umbrello/umbrello/uml.cpp b/umbrello/umbrello/uml.cpp
new file mode 100644
index 00000000..11a5b32a
--- /dev/null
+++ b/umbrello/umbrello/uml.cpp
@@ -0,0 +1,1708 @@
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * copyright (C) 2002-2006 *
+ * Umbrello UML Modeller Authors <uml-devel@uml.sf.net> *
+ ***************************************************************************/
+
+// own header
+#include "uml.h"
+
+// qt includes
+#include <qclipboard.h>
+#include <qpopupmenu.h>
+#include <qtimer.h>
+#include <qwidgetstack.h>
+#include <qslider.h>
+#include <qregexp.h>
+#include <qtoolbutton.h>
+
+// kde includes
+#include <kaction.h>
+#include <kapplication.h>
+#include <kconfig.h>
+#include <kcursor.h>
+#include <kdebug.h>
+#include <kfiledialog.h>
+#include <kiconloader.h>
+#include <klocale.h>
+#include <kprinter.h>
+#include <kmenubar.h>
+#include <kmessagebox.h>
+#include <kstandarddirs.h>
+#include <kstatusbar.h>
+#include <ktip.h>
+#include <ktabwidget.h>
+#include <ktoolbarbutton.h>
+#include <kpopupmenu.h>
+
+// app includes
+#include "aligntoolbar.h"
+#include "codeimport/classimport.h"
+#include "docwindow.h"
+#include "codegenerator.h"
+#include "codegenerationpolicy.h"
+#include "codegenerators/codegenfactory.h"
+#include "codegenerators/codegenpolicyext.h"
+#include "optionstate.h"
+#include "widget_utils.h"
+#include "umldoc.h"
+#include "umllistview.h"
+#include "umlviewlist.h"
+#include "worktoolbar.h"
+#ifdef HAVE_DOT
+# include "autolayout/autolayoutdlg.h" //dimitri
+#endif
+#include "model_utils.h"
+#include "clipboard/umlclipboard.h"
+#include "dialogs/classwizard.h"
+#include "dialogs/codegenerationwizard.h"
+#include "dialogs/codeviewerdialog.h"
+#include "dialogs/diagramprintpage.h"
+
+#include "refactoring/refactoringassistant.h"
+#include "codegenerators/simplecodegenerator.h"
+#include "umlviewimageexporter.h"
+#include "umlviewimageexporterall.h"
+
+#include "kplayerslideraction.h"
+
+#include "configurable.h"
+
+#include "cmdlineexportallviewsevent.h"
+
+#include "docgenerators/docbookgenerator.h"
+#include "docgenerators/xhtmlgenerator.h"
+
+UMLApp::UMLApp(QWidget* , const char* name):KDockMainWindow(0, name) {
+ s_instance = this;
+ m_pDocWindow = 0;
+ m_config = kapp->config();
+ m_listView = 0;
+ m_langSelect = NULL;
+ m_zoomSelect = NULL;
+ m_loading = false;
+ m_clipTimer = 0;
+ m_copyTimer = 0;
+ m_codegen = 0;
+ m_policyext = 0;
+ m_commoncodegenpolicy = 0;
+ m_xhtmlGenerator = 0;
+ m_activeLanguage = Uml::pl_Reserved;
+ ///////////////////////////////////////////////////////////////////
+ // call inits to invoke all other construction parts
+ readOptionState();
+ m_doc = new UMLDoc();
+ m_doc->init();
+ initActions(); //now calls initStatusBar() because it is affected by setupGUI()
+ initView();
+ initClip();
+ readOptions();
+ ///////////////////////////////////////////////////////////////////
+ // disable actions at startup
+ fileSave->setEnabled(true);
+ fileSaveAs->setEnabled(true);
+ enablePrint(false);
+ editCut->setEnabled(false);
+ editCopy->setEnabled(false);
+ editPaste->setEnabled(false);
+ editUndo->setEnabled(false);
+ editRedo->setEnabled(false);
+
+ //get a reference to the Code->Active Language and to the Diagram->Zoom menu
+ QPopupMenu* menu = findMenu( menuBar(), QString("code") );
+ m_langSelect = findMenu( menu, QString("active_lang_menu") );
+
+ //in case langSelect hasn't been initialized we create the Popup menu.
+ //it will be hidden, but at least we wont crash if someone takes the entry away from the ui.rc file
+ if (m_langSelect == NULL) {
+ m_langSelect = new QPopupMenu(this);
+ }
+
+ menu = findMenu( menuBar(), QString("views") );
+ m_zoomSelect = findMenu( menu, QString("zoom_menu") );
+
+ //in case zoomSelect hasn't been initialized we create the Popup menu.
+ //it will be hidden, but at least we wont crash if some one takes the entry away from the ui.rc file
+ if (m_zoomSelect == NULL) {
+ m_zoomSelect = new QPopupMenu(this);
+ }
+
+ //connect zoomSelect menu
+ m_zoomSelect->setCheckable(true);
+ connect(m_zoomSelect,SIGNAL(aboutToShow()),this,SLOT(setupZoomMenu()));
+ connect(m_zoomSelect,SIGNAL(activated(int)),this,SLOT(setZoom(int)));
+
+ m_refactoringAssist = 0L;
+
+ m_commoncodegenpolicy = new CodeGenerationPolicy(m_config);
+
+ m_imageExporterAll = new UMLViewImageExporterAll();
+}
+
+UMLApp::~UMLApp() {
+ delete m_imageExporterAll;
+
+ delete m_clipTimer;
+ delete m_copyTimer;
+
+ delete m_statusLabel;
+ delete m_refactoringAssist;
+}
+
+UMLApp* UMLApp::app()
+{
+ return s_instance;
+}
+
+void UMLApp::initActions() {
+ fileNew = KStdAction::openNew(this, SLOT(slotFileNew()), actionCollection());
+ fileOpen = KStdAction::open(this, SLOT(slotFileOpen()), actionCollection());
+ fileOpenRecent = KStdAction::openRecent(this, SLOT(slotFileOpenRecent(const KURL&)), actionCollection());
+ fileSave = KStdAction::save(this, SLOT(slotFileSave()), actionCollection());
+ fileSaveAs = KStdAction::saveAs(this, SLOT(slotFileSaveAs()), actionCollection());
+ fileClose = KStdAction::close(this, SLOT(slotFileClose()), actionCollection());
+ filePrint = KStdAction::print(this, SLOT(slotFilePrint()), actionCollection());
+ fileQuit = KStdAction::quit(this, SLOT(slotFileQuit()), actionCollection());
+ editUndo = KStdAction::undo(this, SLOT(slotEditUndo()), actionCollection());
+ editRedo = KStdAction::redo(this, SLOT(slotEditRedo()), actionCollection());
+ editCut = KStdAction::cut(this, SLOT(slotEditCut()), actionCollection());
+ editCopy = KStdAction::copy(this, SLOT(slotEditCopy()), actionCollection());
+ editPaste = KStdAction::paste(this, SLOT(slotEditPaste()), actionCollection());
+ createStandardStatusBarAction();
+ setStandardToolBarMenuEnabled(true);
+ selectAll = KStdAction::selectAll(this, SLOT( slotSelectAll() ), actionCollection());
+ fileExportDocbook = new KAction(i18n("&Export model to DocBook"), 0,
+ this, SLOT( slotFileExportDocbook() ),
+ actionCollection(), "file_export_docbook");
+ fileExportXhtml = new KAction(i18n("&Export model to XHTML"), 0,
+ this, SLOT( slotFileExportXhtml() ),
+ actionCollection(), "file_export_xhtml");
+
+ classWizard = new KAction(i18n("&New Class Wizard..."),0,this,SLOT(slotClassWizard()),
+ actionCollection(),"class_wizard");
+ new KAction(i18n("&Add Default Datatypes for Active Language"), 0, this,
+ SLOT(slotAddDefaultDatatypes()), actionCollection(), "create_default_datatypes");
+
+ preferences = KStdAction::preferences(this, SLOT( slotPrefs() ), actionCollection());
+
+ genWizard = new KAction(i18n("&Code Generation Wizard..."),0,this,SLOT(generationWizard()),
+ actionCollection(),"generation_wizard");
+ genAll = new KAction(i18n("&Generate All Code"),0,this,SLOT(generateAllCode()),
+ actionCollection(),"generate_all");
+
+ importClasses = new KAction(i18n("&Import Classes..."), SmallIconSet("source_cpp"), 0,
+ this,SLOT(slotImportClasses()), actionCollection(),"import_class");
+
+ fileNew->setToolTip(i18n("Creates a new document"));
+ fileOpen->setToolTip(i18n("Opens an existing document"));
+ fileOpenRecent->setToolTip(i18n("Opens a recently used file"));
+ fileSave->setToolTip(i18n("Saves the document"));
+ fileSaveAs->setToolTip(i18n("Saves the document as..."));
+ fileClose->setToolTip(i18n("Closes the document"));
+ filePrint ->setToolTip(i18n("Prints out the document"));
+ fileQuit->setToolTip(i18n("Quits the application"));
+ fileExportDocbook->setToolTip(i18n("Exports the model to the docbook format"));
+ fileExportXhtml->setToolTip(i18n("Exports the model to the XHTML format"));
+ editCut->setToolTip(i18n("Cuts the selected section and puts it to the clipboard"));
+ editCopy->setToolTip(i18n("Copies the selected section to the clipboard"));
+ editPaste->setToolTip(i18n("Pastes the contents of the clipboard"));
+ preferences->setToolTip( i18n( "Set the default program preferences") );
+
+ deleteSelectedWidget = new KAction( i18n("Delete &Selected"),
+ SmallIconSet("editdelete"),
+ KShortcut(Qt::Key_Delete), this,
+ SLOT( slotDeleteSelectedWidget() ), actionCollection(),
+ "delete_selected" );
+
+ // The different views
+ newDiagram = new KActionMenu(0, SmallIconSet("filenew"), actionCollection(), "new_view");
+ classDiagram = new KAction( i18n( "&Class Diagram..." ), SmallIconSet("umbrello_diagram_class"), 0,
+ this, SLOT( slotClassDiagram() ), actionCollection(), "new_class_diagram" );
+
+#if defined (HAVE_DOT)
+ autolayout = new KAction(i18n("&Autolayout..."),0,0,this,SLOT(slotAutolayout()),
+ actionCollection(),"autolayout");
+#endif
+ sequenceDiagram= new KAction( i18n( "&Sequence Diagram..." ), SmallIconSet("umbrello_diagram_sequence"), 0,
+ this, SLOT( slotSequenceDiagram() ), actionCollection(), "new_sequence_diagram" );
+
+ collaborationDiagram = new KAction( i18n( "C&ollaboration Diagram..." ), SmallIconSet("umbrello_diagram_collaboration"), 0,
+ this, SLOT( slotCollaborationDiagram() ), actionCollection(), "new_collaboration_diagram" );
+
+ useCaseDiagram= new KAction( i18n( "&Use Case Diagram..." ), SmallIconSet("umbrello_diagram_usecase"), 0,
+ this, SLOT( slotUseCaseDiagram() ), actionCollection(), "new_use_case_diagram" );
+
+ stateDiagram= new KAction( i18n( "S&tate Diagram..." ), SmallIconSet("umbrello_diagram_state"), 0,
+ this, SLOT( slotStateDiagram() ), actionCollection(), "new_state_diagram" );
+
+ activityDiagram= new KAction( i18n( "&Activity Diagram..." ), SmallIconSet("umbrello_diagram_activity"), 0,
+ this, SLOT( slotActivityDiagram() ), actionCollection(), "new_activity_diagram" );
+
+ componentDiagram = new KAction( i18n("Co&mponent Diagram..."), SmallIconSet("umbrello_diagram_component"), 0,
+ this, SLOT( slotComponentDiagram() ), actionCollection(),
+ "new_component_diagram" );
+
+ deploymentDiagram = new KAction( i18n("&Deployment Diagram..."), SmallIconSet("umbrello_diagram_deployment"), 0,
+ this, SLOT( slotDeploymentDiagram() ), actionCollection(),
+ "new_deployment_diagram" );
+
+ entityRelationshipDiagram = new KAction( i18n("&Entity Relationship Diagram..."), SmallIconSet("umbrello_diagram_entityrelationship"), 0,
+ this, SLOT( slotEntityRelationshipDiagram() ), actionCollection(),
+ "new_entityrelationship_diagram" );
+
+ viewClearDiagram = new KAction(i18n("&Clear Diagram"), SmallIconSet("editclear"), 0,
+ this, SLOT( slotCurrentViewClearDiagram() ), actionCollection(), "view_clear_diagram");
+ viewSnapToGrid = new KToggleAction(i18n("&Snap to Grid"), 0,
+ this, SLOT( slotCurrentViewToggleSnapToGrid() ), actionCollection(), "view_snap_to_grid");
+ viewShowGrid = new KToggleAction(i18n("S&how Grid"), 0,
+ this, SLOT( slotCurrentViewToggleShowGrid() ), actionCollection(), "view_show_grid");
+#if (KDE_VERSION_MINOR>=3) && (KDE_VERSION_MAJOR>=3)
+ viewShowGrid->setCheckedState(i18n("&Hide Grid"));
+#endif
+ deleteDiagram = new KAction(i18n("&Delete"), SmallIconSet("editdelete"), 0,
+ this, SLOT( slotDeleteDiagram() ), actionCollection(), "view_delete");
+ viewExportImage = new KAction(i18n("&Export as Picture..."), SmallIconSet("image"), 0,
+ this, SLOT( slotCurrentViewExportImage() ), actionCollection(), "view_export_image");
+ viewExportImageAll = new KAction(i18n("Export &All Diagrams as Pictures..."), SmallIconSet("image"), 0,
+ this, SLOT( slotAllViewsExportImage() ), actionCollection(), "view_export_image_all");
+ viewProperties = new KAction(i18n("&Properties"), SmallIconSet("info"), 0,
+ this, SLOT( slotCurrentViewProperties() ), actionCollection(), "view_properties");
+
+ viewSnapToGrid->setChecked(false);
+ viewShowGrid->setChecked(false);
+
+ viewClearDiagram->setEnabled(false);
+ viewSnapToGrid->setEnabled(false);
+ viewShowGrid->setEnabled(false);
+ deleteDiagram->setEnabled(false);
+ viewExportImage->setEnabled(false);
+ viewProperties->setEnabled(false);
+
+ zoomAction = new KPlayerPopupSliderAction(i18n("&Zoom Slider"), "viewmag", Key_F9,
+ this, SLOT(slotZoomSliderMoved(int)),
+ actionCollection(), "popup_zoom");
+ zoom100Action = new KAction(i18n( "Z&oom to 100%" ), "viewmag1", 0,
+ this, SLOT( slotZoom100() ), actionCollection(),
+ "zoom100");
+
+ KStdAction::tipOfDay( this, SLOT( tipOfTheDay() ), actionCollection() );
+
+ QString moveTabLeftString = i18n("&Move Tab Left");
+ QString moveTabRightString = i18n("&Move Tab Right");
+ moveTabLeft = new KAction(QApplication::reverseLayout() ? moveTabRightString : moveTabLeftString,
+ QApplication::reverseLayout() ? "forward" : "back",
+ QApplication::reverseLayout() ? Qt::CTRL+Qt::SHIFT+Qt::Key_Right : Qt::CTRL+Qt::SHIFT+Qt::Key_Left,
+ this, SLOT(slotMoveTabLeft()), actionCollection(),
+ "move_tab_left");
+ moveTabRight = new KAction(QApplication::reverseLayout() ? moveTabLeftString : moveTabRightString,
+ QApplication::reverseLayout() ? "back" : "forward",
+ QApplication::reverseLayout() ? Qt::CTRL+Qt::SHIFT+Qt::Key_Left : Qt::CTRL+Qt::SHIFT+Qt::Key_Right,
+ this, SLOT(slotMoveTabRight()), actionCollection(),
+ "move_tab_right");
+
+ QString selectTabLeftString = i18n("Select Diagram on Left");
+ QString selectTabRightString = i18n("Select Diagram on Right");
+ changeTabLeft = new KAction(QApplication::reverseLayout() ? selectTabRightString : selectTabLeftString,
+ QApplication::reverseLayout() ? Qt::SHIFT+Qt::Key_Right : Qt::SHIFT+Qt::Key_Left,
+ this, SLOT(slotChangeTabLeft()), actionCollection(), "previous_tab");
+ changeTabRight = new KAction(QApplication::reverseLayout() ? selectTabLeftString : selectTabRightString,
+ QApplication::reverseLayout() ? Qt::SHIFT+Qt::Key_Left : Qt::SHIFT+Qt::Key_Right,
+ this, SLOT(slotChangeTabRight()), actionCollection(), "next_tab");
+
+
+ initStatusBar(); //call this here because the statusBar is shown/hidden by setupGUI()
+
+ // use the absolute path to your umbrelloui.rc file for testing purpose in setupGUI();
+#if KDE_IS_VERSION(3,2,90)
+ setupGUI();
+#else
+ createGUI();
+#endif
+ QPopupMenu* menu = findMenu( menuBar(), QString("settings") );
+ menu->insertItem(i18n("&Windows"), dockHideShowMenu(), -1, 0);
+}
+
+void UMLApp::slotZoomSliderMoved(int value) {
+ int zoom = (int)(value*0.01);
+ getCurrentView()->setZoom(zoom*zoom);
+}
+
+void UMLApp::slotZoom100() {
+ setZoom(100);
+}
+
+void UMLApp::setZoom(int zoom) {
+ getCurrentView()->setZoom(zoom);
+}
+
+void UMLApp::setupZoomMenu() {
+ m_zoomSelect->clear();
+
+ //IMPORTANT: The ID's must match the zoom value (text)
+ m_zoomSelect->insertItem(i18n(" &33%"),33);
+ m_zoomSelect->insertItem(i18n(" &50%"),50);
+ m_zoomSelect->insertItem(i18n(" &75%"),75);
+ m_zoomSelect->insertItem(i18n("&100%"),100);
+ m_zoomSelect->insertItem(i18n("1&50%"),150);
+ m_zoomSelect->insertItem(i18n("&200%"),200);
+ m_zoomSelect->insertItem(i18n("3&00%"),300);
+
+
+ int zoom = getCurrentView()->currentZoom();
+ //if current zoom is not a "standard zoom" (because of zoom in / zoom out step
+ //we add it for information
+ switch(zoom){
+ case 33:
+ case 50:
+ case 75:
+ case 100:
+ case 150:
+ case 200:
+ case 300:
+ break;
+ default:
+ m_zoomSelect->insertSeparator();
+ m_zoomSelect->insertItem(QString::number(zoom)+" %",zoom);
+ }
+ m_zoomSelect->setItemChecked(zoom, true);
+}
+
+void UMLApp::initStatusBar() {
+ m_statusLabel = new KStatusBarLabel( i18n("Ready."), 0, statusBar() );
+ m_statusLabel->setFixedHeight( m_statusLabel->sizeHint().height() );
+
+ m_statusLabel->setFrameStyle( QFrame::NoFrame | QFrame::Plain );
+ m_statusLabel->setMargin( 0 );
+ m_statusLabel->setLineWidth(0);
+
+ statusBar()->addWidget( m_statusLabel, 1, false );
+
+ m_statusLabel->setAlignment(Qt::AlignLeft|Qt::AlignVCenter);
+
+ connect(m_doc, SIGNAL( sigWriteToStatusBar(const QString &) ), this, SLOT( slotStatusMsg(const QString &) ));
+}
+
+void UMLApp::initView() {
+ setCaption(m_doc->URL().fileName(),false);
+ m_view = NULL;
+ toolsbar = new WorkToolBar(this, "");
+ toolsbar->setLabel(i18n("Diagram Toolbar"));
+ addToolBar(toolsbar, Qt::DockTop, false);
+
+ m_alignToolBar = new AlignToolBar(this, "");
+ m_alignToolBar->setLabel(i18n("Alignment Toolbar"));
+ addToolBar(m_alignToolBar, Qt::DockTop, false);
+
+ m_mainDock = createDockWidget("maindock", 0L, 0L, "main dock");
+ m_newSessionButton = NULL;
+ m_diagramMenu = NULL;
+ m_closeDiagramButton = NULL;
+ Settings::OptionState& optionState = Settings::getOptionState();
+ if (optionState.generalState.tabdiagrams) {
+ m_viewStack = NULL;
+ m_tabWidget = new KTabWidget(m_mainDock, "tab_widget");
+
+#if KDE_IS_VERSION(3,3,89)
+ m_tabWidget->setAutomaticResizeTabs( true );
+#endif
+
+ m_newSessionButton = new KToolBarButton("tab_new", 0, m_tabWidget);
+ m_newSessionButton->setIconSet( SmallIcon( "tab_new" ) );
+ m_newSessionButton->adjustSize();
+ m_newSessionButton->setAutoRaise(true);
+ m_diagramMenu = new KPopupMenu(m_newSessionButton);
+
+ m_diagramMenu->insertItem(Widget_Utils::iconSet(Uml::dt_Class), i18n("Class Diagram..."), this, SLOT(slotClassDiagram()) );
+ m_diagramMenu->insertItem(Widget_Utils::iconSet(Uml::dt_Sequence), i18n("Sequence Diagram..."), this, SLOT(slotSequenceDiagram()) );
+ m_diagramMenu->insertItem(Widget_Utils::iconSet(Uml::dt_Collaboration), i18n("Collaboration Diagram..."), this, SLOT(slotCollaborationDiagram()) );
+ m_diagramMenu->insertItem(Widget_Utils::iconSet(Uml::dt_UseCase), i18n("Use Case Diagram..."), this, SLOT(slotUseCaseDiagram()) );
+ m_diagramMenu->insertItem(Widget_Utils::iconSet(Uml::dt_State), i18n("State Diagram..."), this, SLOT(slotStateDiagram()) );
+ m_diagramMenu->insertItem(Widget_Utils::iconSet(Uml::dt_Activity), i18n("Activity Diagram..."), this, SLOT(slotActivityDiagram()) );
+ m_diagramMenu->insertItem(Widget_Utils::iconSet(Uml::dt_Component), i18n("Component Diagram..."), this, SLOT(slotComponentDiagram()) );
+ m_diagramMenu->insertItem(Widget_Utils::iconSet(Uml::dt_Deployment), i18n("Deployment Diagram..."), this, SLOT(slotDeploymentDiagram()) );
+ m_diagramMenu->insertItem(Widget_Utils::iconSet(Uml::dt_EntityRelationship), i18n("Entity Relationship Diagram..."), this, SLOT(slotEntityRelationshipDiagram()) );
+ m_newSessionButton->setPopup(m_diagramMenu);
+ //FIXME why doesn't this work?
+ //m_newSessionButton->setPopup(newDiagram->popupMenu());
+
+ //m_closeDiagramButton = new KToolBarButton("tab_remove", 0, m_tabWidget);
+ m_closeDiagramButton = new QToolButton(m_tabWidget);
+ m_closeDiagramButton->setIconSet( SmallIcon("tab_remove") );
+ m_closeDiagramButton->adjustSize();
+
+ connect(m_closeDiagramButton, SIGNAL(clicked()), SLOT(slotDeleteDiagram()));
+ connect(m_tabWidget, SIGNAL(currentChanged(QWidget*)), SLOT(slotTabChanged(QWidget*)));
+ connect(m_tabWidget, SIGNAL(contextMenu(QWidget*,const QPoint&)), m_doc, SLOT(slotDiagramPopupMenu(QWidget*,const QPoint&)));
+ m_tabWidget->setCornerWidget( m_newSessionButton, TopLeft );
+ m_tabWidget->setCornerWidget( m_closeDiagramButton, TopRight );
+ m_newSessionButton->installEventFilter(this);
+
+ m_mainDock->setWidget(m_tabWidget);
+ }
+ else
+ {
+ m_tabWidget = NULL;
+ m_viewStack = new QWidgetStack(m_mainDock, "viewstack");
+ m_mainDock->setWidget(m_viewStack);
+ }
+ m_mainDock->setDockSite(KDockWidget::DockCorner);
+ m_mainDock->setEnableDocking(KDockWidget::DockNone);
+ setView(m_mainDock);
+ setMainDockWidget(m_mainDock);
+
+ m_listDock = createDockWidget( "Model", 0L, 0L, i18n("&Tree View") );
+ m_listView = new UMLListView(m_listDock ,"LISTVIEW");
+ //m_listView->setSorting(-1);
+ m_listView->setDocument(m_doc);
+ m_listView->init();
+ m_listDock->setWidget(m_listView);
+ m_listDock->setDockSite(KDockWidget::DockCorner);
+ m_listDock->manualDock(m_mainDock, KDockWidget::DockLeft, 20);
+
+ m_documentationDock = createDockWidget( "Documentation", 0L, 0L, i18n("&Documentation") );
+ m_pDocWindow = new DocWindow(m_doc, m_documentationDock, "DOCWINDOW");
+ m_documentationDock->setWidget(m_pDocWindow);
+ m_documentationDock->setDockSite(KDockWidget::DockCorner);
+ m_documentationDock->manualDock(m_listDock, KDockWidget::DockBottom, 80);
+
+ m_doc->setupSignals();//make sure gets signal from list view
+
+ readDockConfig(); //reposition all the DockWindows to their saved positions
+}
+
+void UMLApp::openDocumentFile(const KURL& url) {
+ slotStatusMsg(i18n("Opening file..."));
+
+ m_doc->openDocument( url);
+ fileOpenRecent->addURL( url );
+ slotStatusMsg(i18n("Ready."));
+ setCaption(m_doc->URL().fileName(), false);
+ enablePrint(true);
+}
+
+UMLDoc *UMLApp::getDocument() const {
+ return m_doc;
+}
+
+UMLListView* UMLApp::getListView() {
+ return m_listView;
+}
+
+
+void UMLApp::saveOptions() {
+ toolBar("mainToolBar")->saveSettings(m_config, "toolbar");
+ toolsbar->saveSettings(m_config, "workbar");
+ m_alignToolBar->saveSettings(m_config, "aligntoolbar");
+ fileOpenRecent->saveEntries(m_config,"Recent Files");
+ m_config->setGroup( "General Options" );
+ m_config->writeEntry( "Geometry", size() );
+
+ Settings::OptionState& optionState = Settings::getOptionState();
+ m_config->writeEntry( "undo", optionState.generalState.undo );
+ m_config->writeEntry( "tabdiagrams", optionState.generalState.tabdiagrams );
+ m_config->writeEntry( "newcodegen", optionState.generalState.newcodegen );
+ m_config->writeEntry( "angularlines", optionState.generalState.angularlines );
+ m_config->writeEntry( "autosave", optionState.generalState.autosave );
+ m_config->writeEntry( "time", optionState.generalState.time );
+ m_config->writeEntry( "autosavetime", optionState.generalState.autosavetime );
+ m_config->writeEntry( "autosavesuffix", optionState.generalState.autosavesuffix );
+
+ m_config->writeEntry( "logo", optionState.generalState.logo );
+ m_config->writeEntry( "loadlast", optionState.generalState.loadlast );
+
+ m_config->writeEntry( "diagram", optionState.generalState.diagram );
+ if( m_doc->URL().fileName() == i18n( "Untitled" ) ) {
+ m_config -> writeEntry( "lastFile", "" );
+ } else {
+ m_config -> writePathEntry( "lastFile", m_doc -> URL().prettyURL() );
+ }
+ m_config->writeEntry( "imageMimeType", getImageMimeType() );
+
+ m_config->setGroup( "TipOfDay");
+ optionState.generalState.tip = m_config -> readBoolEntry( "RunOnStart", true );
+ m_config->writeEntry( "RunOnStart", optionState.generalState.tip );
+
+ m_config->setGroup( "UI Options" );
+ m_config->writeEntry( "useFillColor", optionState.uiState.useFillColor );
+ m_config->writeEntry( "fillColor", optionState.uiState.fillColor );
+ m_config->writeEntry( "lineColor", optionState.uiState.lineColor );
+ m_config->writeEntry( "lineWidth", optionState.uiState.lineWidth );
+ m_config->writeEntry( "showDocWindow", m_documentationDock->isVisible() );
+ m_config->writeEntry( "font", optionState.uiState.font );
+
+ m_config->setGroup( "Class Options" );
+ m_config->writeEntry( "showVisibility", optionState.classState.showVisibility );
+ m_config->writeEntry( "showAtts", optionState.classState.showAtts);
+ m_config->writeEntry( "showOps", optionState.classState.showOps );
+ m_config->writeEntry( "showStereoType", optionState.classState.showStereoType );
+ m_config->writeEntry( "showAttSig", optionState.classState.showAttSig );
+ m_config->writeEntry( "ShowOpSig", optionState.classState.showOpSig );
+ m_config->writeEntry( "showPackage", optionState.classState.showPackage );
+ m_config->writeEntry( "defaultAttributeScope", optionState.classState.defaultAttributeScope);
+ m_config->writeEntry( "defaultOperationScope", optionState.classState.defaultOperationScope);
+
+ m_config -> setGroup( "Code Viewer Options" );
+ m_config->writeEntry( "height", optionState.codeViewerState.height );
+ m_config->writeEntry( "width", optionState.codeViewerState.width);
+ m_config->writeEntry( "font", optionState.codeViewerState.font);
+ m_config->writeEntry( "fontColor", optionState.codeViewerState.fontColor);
+ m_config->writeEntry( "paperColor", optionState.codeViewerState.paperColor);
+ m_config->writeEntry( "selectedColor", optionState.codeViewerState.selectedColor);
+ m_config->writeEntry( "editBlockColor", optionState.codeViewerState.editBlockColor);
+ m_config->writeEntry( "nonEditBlockColor", optionState.codeViewerState.nonEditBlockColor);
+ m_config->writeEntry( "umlObjectBlockColor", optionState.codeViewerState.umlObjectColor);
+ m_config->writeEntry( "blocksAreHighlighted", optionState.codeViewerState.blocksAreHighlighted);
+ m_config->writeEntry( "showHiddenBlocks", optionState.codeViewerState.showHiddenBlocks);
+ m_config->writeEntry( "hiddenColor", optionState.codeViewerState.hiddenColor);
+
+ // write the config for a language-specific code gen policy
+ if (m_policyext)
+ m_policyext->writeConfig(m_config);
+
+ // now write the basic defaults to the m_config file
+ m_commoncodegenpolicy->writeConfig(m_config);
+
+ // next, we record the activeLanguage in the Code Generation Group
+ if (m_codegen) {
+ m_config->setGroup("Code Generation");
+ m_config->writeEntry("activeLanguage", Model_Utils::progLangToString(m_codegen->getLanguage()));
+ }
+}
+
+void UMLApp::readOptions() {
+ // bar status settings
+ toolBar("mainToolBar")->applySettings(m_config, "toolbar");
+ // do config for work toolbar
+ toolsbar->applySettings(m_config, "workbar");
+ m_alignToolBar->applySettings(m_config, "aligntoolbar");
+ fileOpenRecent->loadEntries(m_config,"Recent Files");
+ m_config->setGroup("General Options");
+ setImageMimeType(m_config->readEntry("imageMimeType","image/png"));
+ QSize tmpQSize(630,460);
+ resize( m_config->readSizeEntry("Geometry", & tmpQSize) );
+}
+
+void UMLApp::saveProperties(KConfig *_config) {
+ if(m_doc->URL().fileName()!=i18n("Untitled") && !m_doc->isModified()) {
+ // saving to tempfile not necessary
+
+ } else {
+ KURL url=m_doc->URL();
+ _config->writePathEntry("filename", url.url());
+ _config->writeEntry("modified", m_doc->isModified());
+ QString tempname = kapp->tempSaveName(url.url());
+ QString tempurl= KURL::encode_string(tempname);
+
+ KURL _url(tempurl);
+ m_doc->saveDocument(_url);
+ }
+}
+
+void UMLApp::readProperties(KConfig* _config) {
+ QString filename = _config->readPathEntry("filename");
+ KURL url(filename);
+ bool modified = _config->readBoolEntry("modified", false);
+ if(modified) {
+ bool canRecover;
+ QString tempname = kapp->checkRecoverFile(filename, canRecover);
+ KURL _url(tempname);
+
+
+ if(canRecover) {
+ m_doc->openDocument(_url);
+ m_doc->setModified();
+ enablePrint(true);
+ setCaption(_url.fileName(),true);
+ QFile::remove
+ (tempname);
+ } else {
+ enablePrint(false);
+ }
+ } else {
+ if(!filename.isEmpty()) {
+ m_doc->openDocument(url);
+ enablePrint(true);
+ setCaption(url.fileName(),false);
+
+ } else {
+ enablePrint(false);
+ }
+ }
+}
+
+bool UMLApp::queryClose() {
+ writeDockConfig();
+ return m_doc->saveModified();
+}
+
+bool UMLApp::queryExit() {
+ saveOptions();
+ m_doc -> closeDocument();
+ return true;
+}
+
+void UMLApp::slotFileNew() {
+ slotStatusMsg(i18n("Creating new document..."));
+ if(m_doc->saveModified()) {
+ setDiagramMenuItemsState(false);
+ m_doc->newDocument();
+ setCaption(m_doc->URL().fileName(), false);
+ fileOpenRecent->setCurrentItem( -1 );
+ setModified(false);
+ enablePrint(false);
+ }
+ slotUpdateViews();
+ slotStatusMsg(i18n("Ready."));
+}
+
+void UMLApp::slotFileOpen() {
+ slotStatusMsg(i18n("Opening file..."));
+ m_loading = true;
+
+ if(!m_doc->saveModified()) {
+
+ // here saving wasn't successful
+
+ } else {
+ KURL url=KFileDialog::getOpenURL(":open-umbrello-file",
+ i18n("*.xmi *.xmi.tgz *.xmi.tar.bz2 *.mdl|All Supported Files (*.xmi, *.xmi.tgz, *.xmi.tar.bz2, *.mdl)\n"
+ "*.xmi|Uncompressed XMI Files (*.xmi)\n"
+ "*.xmi.tgz|Gzip Compressed XMI Files (*.xmi.tgz)\n"
+ "*.xmi.tar.bz2|Bzip2 Compressed XMI Files (*.xmi.tar.bz2)\n"
+ "*.mdl|Rose model files"), this, i18n("Open File"));
+ if(!url.isEmpty()) {
+ if(m_doc->openDocument(url))
+ fileOpenRecent->addURL( url );
+ enablePrint(true);
+ setCaption(m_doc->URL().fileName(), false);
+ }
+
+ }
+ slotUpdateViews();
+ m_loading = false;
+ slotStatusMsg(i18n("Ready."));
+}
+
+void UMLApp::slotFileOpenRecent(const KURL& url) {
+ slotStatusMsg(i18n("Opening file..."));
+ m_loading = true;
+
+ KURL oldURL = m_doc->URL();
+
+ if(!m_doc->saveModified()) {
+ // here saving wasn't successful
+ } else {
+ if(!m_doc->openDocument(url)) {
+ fileOpenRecent->removeURL(url);
+ fileOpenRecent->setCurrentItem( -1 );
+ } else {
+ fileOpenRecent->addURL(url);
+ }
+ enablePrint(true);
+ setCaption(m_doc->URL().fileName(), false);
+ }
+
+ m_loading = false;
+ slotUpdateViews();
+ slotStatusMsg(i18n("Ready."));
+}
+
+void UMLApp::slotFileSave() {
+ slotStatusMsg(i18n("Saving file..."));
+ if(m_doc->URL().fileName() == i18n("Untitled"))
+ slotFileSaveAs();
+ else
+ m_doc->saveDocument(m_doc -> URL());
+
+ slotStatusMsg(i18n("Ready."));
+}
+
+bool UMLApp::slotFileSaveAs()
+{
+ slotStatusMsg(i18n("Saving file with a new filename..."));
+ bool cont = true;
+ KURL url;
+ QString ext;
+ while(cont) {
+ url=KFileDialog::getSaveURL(":save-umbrello-file", i18n("*.xmi|XMI File\n*.xmi.tgz|Gzip Compressed XMI File\n*.xmi.tar.bz2|Bzip2 Compressed XMI File\n*|All Files"), this, i18n("Save As"));
+
+ if(url.isEmpty())
+ cont = false;
+ else {
+ QDir d = url.path(-1);
+
+ if(QFile::exists(d.path())) {
+ int want_save = KMessageBox::warningContinueCancel(this, i18n("The file %1 exists.\nDo you wish to overwrite it?").arg(url.path()), i18n("Warning"), i18n("Overwrite"));
+ if(want_save == KMessageBox::Continue)
+ cont = false;
+ } else
+ cont = false;
+
+ }
+ }
+ if(!url.isEmpty()) {
+ bool b = m_doc->saveDocument(url);
+ if (b) {
+ fileOpenRecent->addURL(url);
+ setCaption(url.fileName(),m_doc->isModified());
+ slotStatusMsg(i18n("Ready."));
+ }
+ return b;
+
+ } else {
+ slotStatusMsg(i18n("Ready."));
+ return false;
+ }
+}
+
+void UMLApp::slotFileClose() {
+ slotStatusMsg(i18n("Closing file..."));
+
+ slotFileNew();
+
+}
+
+void UMLApp::slotFilePrint()
+{
+ slotStatusMsg(i18n("Printing..."));
+
+ KPrinter printer;
+ printer.setFullPage(true);
+ DiagramPrintPage * selectPage = new DiagramPrintPage(0, m_doc);
+ printer.addDialogPage(selectPage);
+ QString msg;
+ if (printer.setup(this, i18n("Print %1").arg(m_doc->URL().prettyURL()))) {
+
+ m_doc -> print(&printer);
+ }
+ slotStatusMsg(i18n("Ready."));
+}
+
+void UMLApp::slotFileQuit() {
+ slotStatusMsg(i18n("Exiting..."));
+ if(m_doc->saveModified()) {
+ writeDockConfig();
+ saveOptions();
+ kapp->quit();
+ }
+ slotStatusMsg(i18n("Ready."));
+}
+
+void UMLApp::slotFileExportDocbook()
+{
+ DocbookGenerator().generateDocbookForProject();
+}
+
+void UMLApp::slotFileExportXhtml()
+{
+ if (m_xhtmlGenerator != 0)
+ {
+ return;
+ }
+ m_xhtmlGenerator = new XhtmlGenerator();
+ m_xhtmlGenerator->generateXhtmlForProject();
+ connect(m_xhtmlGenerator,SIGNAL(finished()),this,SLOT(slotXhtmlDocGenerationFinished()));
+}
+
+void UMLApp::slotEditUndo() {
+ m_doc->loadUndoData();
+ slotStatusMsg(i18n("Ready."));
+}
+
+void UMLApp::slotEditRedo() {
+ m_doc->loadRedoData();
+ slotStatusMsg(i18n("Ready."));
+}
+
+void UMLApp::slotEditCut() {
+ slotStatusMsg(i18n("Cutting selection..."));
+ //FIXME bug 59774 this fromview isn't very reliable.
+ //when cutting diagrams it is set to true even though it shouldn't be
+ bool fromview = (getCurrentView() && getCurrentView()->getSelectCount());
+ if ( editCutCopy(fromview) ) {
+ emit sigCutSuccessful();
+ slotDeleteSelectedWidget();
+ m_doc->setModified(true);
+ }
+ slotStatusMsg(i18n("Ready."));
+}
+
+void UMLApp::slotEditCopy() {
+ slotStatusMsg(i18n("Copying selection to clipboard..."));
+ bool fromview = (getCurrentView() && getCurrentView()->getSelectCount());
+ editCutCopy( fromview );
+ slotStatusMsg(i18n("Ready."));
+ m_doc -> setModified( true );
+}
+
+void UMLApp::slotEditPaste() {
+ slotStatusMsg(i18n("Inserting clipboard contents..."));
+ QMimeSource* data = QApplication::clipboard()->data();
+ UMLClipboard clipboard;
+ setCursor(KCursor::waitCursor());
+ if(!clipboard.paste(data)) {
+ KMessageBox::sorry( this, i18n("Umbrello could not paste the clipboard contents. "
+ "The objects in the clipboard may be of the wrong "
+ "type to be pasted here."), i18n("Paste Error") );
+ }
+ slotStatusMsg(i18n("Ready."));
+ setCursor(KCursor::arrowCursor());
+ editPaste->setEnabled(false);
+ m_doc -> setModified( true );
+}
+
+//Remove these once we stop supporting KDE 3.1
+// #if !KDE_IS_VERSION(3,1,90)
+
+void UMLApp::slotViewToolBar() {
+ slotStatusMsg(i18n("Toggling toolbar..."));
+
+ ///////////////////////////////////////////////////////////////////
+ // turn Toolbar on or off
+
+ if(!viewToolBar->isChecked()) {
+ toolBar("mainToolBar")->hide();
+ } else {
+ toolBar("mainToolBar")->show();
+ }
+
+ slotStatusMsg(i18n("Ready."));
+}
+
+void UMLApp::slotViewStatusBar() {
+ slotStatusMsg(i18n("Toggle the statusbar..."));
+ ///////////////////////////////////////////////////////////////////
+ //turn Statusbar on or off
+ if(!viewStatusBar->isChecked()) {
+ statusBar()->hide();
+ } else {
+ statusBar()->show();
+ }
+
+ slotStatusMsg(i18n("Ready."));
+}
+// #endif
+
+
+void UMLApp::slotStatusMsg(const QString &text) {
+ ///////////////////////////////////////////////////////////////////
+ // change status message permanently
+ statusBar()->clear();
+ m_statusLabel->setText( text );
+
+ m_statusLabel->repaint();
+}
+
+void UMLApp::slotClassDiagram() {
+ UMLFolder *root = m_doc->getRootFolder(Uml::mt_Logical);
+ getDocument()->createDiagram(root, Uml::dt_Class);
+}
+
+
+void UMLApp::slotSequenceDiagram() {
+ UMLFolder *root = m_doc->getRootFolder(Uml::mt_Logical);
+ m_doc->createDiagram(root, Uml::dt_Sequence);
+}
+
+void UMLApp::slotCollaborationDiagram() {
+ UMLFolder *root = m_doc->getRootFolder(Uml::mt_Logical);
+ m_doc->createDiagram(root, Uml::dt_Collaboration);
+}
+
+void UMLApp::slotUseCaseDiagram() {
+ UMLFolder *root = m_doc->getRootFolder(Uml::mt_UseCase);
+ m_doc->createDiagram(root, Uml::dt_UseCase);
+}
+
+void UMLApp::slotStateDiagram() {
+ UMLFolder *root = m_doc->getRootFolder(Uml::mt_Logical);
+ m_doc->createDiagram(root, Uml::dt_State);
+}
+
+void UMLApp::slotActivityDiagram() {
+ UMLFolder *root = m_doc->getRootFolder(Uml::mt_Logical);
+ m_doc->createDiagram(root, Uml::dt_Activity);
+}
+
+void UMLApp::slotComponentDiagram() {
+ UMLFolder *root = m_doc->getRootFolder(Uml::mt_Component);
+ m_doc->createDiagram(root, Uml::dt_Component );
+}
+
+void UMLApp::slotDeploymentDiagram() {
+ UMLFolder *root = m_doc->getRootFolder(Uml::mt_Deployment);
+ m_doc->createDiagram(root, Uml::dt_Deployment);
+}
+
+void UMLApp::slotEntityRelationshipDiagram() {
+ UMLFolder *root = m_doc->getRootFolder(Uml::mt_EntityRelationship);
+ m_doc->createDiagram(root, Uml::dt_EntityRelationship);
+}
+
+WorkToolBar* UMLApp::getWorkToolBar() {
+ return toolsbar;
+}
+
+void UMLApp::setModified(bool modified) {
+ //fileSave -> setEnabled(modified);
+
+ //if anything else needs to be done on a mofication, put it here
+
+ // printing should be possible whenever there is something to print
+ if ( m_loading == false && modified == true && getCurrentView() ) {
+ enablePrint(true);
+ }
+
+ if (m_loading == false) {
+ setCaption(m_doc->URL().fileName(), modified); //add disk icon to taskbar if modified
+ }
+}
+
+void UMLApp::enablePrint(bool enable) {
+ filePrint->setEnabled(enable);
+}
+
+void UMLApp::enableUndo(bool enable) {
+ editUndo->setEnabled(enable);
+}
+
+void UMLApp::enableRedo(bool enable) {
+ editRedo->setEnabled(enable);
+}
+
+/** initialize the QT's global clipboard support for the application */
+void UMLApp::initClip() {
+ QClipboard* clip = QApplication::clipboard();
+ connect(clip, SIGNAL(dataChanged()), this, SLOT(slotClipDataChanged()));
+
+ // Don't poll the X11 clipboard every second. This is a little expensive and resulted
+ // in very annoying umbrello slowdowns / hangs. Qt will notify us about clipboard
+ // changes anyway (see dataChanged() signal above), albeit only when a Qt application
+ // changes the clipboard. Work is in progress to make this work with other toolkits
+ // as well. (pfeiffer)
+ // m_clipTimer = new QTimer(this, "timer");
+ // m_clipTimer->start(1000, false);
+ // connect(m_clipTimer, SIGNAL(timeout()), this, SLOT(slotClipDataChanged()));
+
+ m_copyTimer = new QTimer(this, "copytimer");
+ m_copyTimer->start(500, false);
+ connect(m_copyTimer, SIGNAL(timeout()), this, SLOT(slotCopyChanged()));
+}
+
+bool UMLApp::canDecode(const QMimeSource* mimeSource) {
+ const char* f;
+ for (int i=0; (f=mimeSource->format(i)); i++) {
+ if ( !qstrnicmp(f,"application/x-uml-clip", 22) ) {
+ //FIXME need to test for clip1, clip2, clip3, clip4 or clip5
+ //(the only valid clip types)
+ return true;
+ }
+ }
+ return false;
+}
+
+void UMLApp::slotClipDataChanged() {
+ QMimeSource * data = QApplication::clipboard()->data();
+
+ //Pass the MimeSource to the Doc
+ editPaste->setEnabled( data && canDecode(data) );
+}
+
+void UMLApp::slotCopyChanged() {
+ if(m_listView->getSelectedCount() || (getCurrentView() && getCurrentView()->getSelectCount())) {
+ editCopy->setEnabled(true);
+ editCut->setEnabled(true);
+ } else {
+ editCopy->setEnabled(false);
+ editCut->setEnabled(false);
+ }
+}
+
+void UMLApp::slotPrefs() {
+ /* the KTipDialog may have changed the value */
+ m_config->setGroup("TipOfDay");
+ Settings::OptionState& optionState = Settings::getOptionState();
+ optionState.generalState.tip = m_config->readBoolEntry( "RunOnStart", true );
+
+ m_dlg = new SettingsDlg(this, &optionState);
+ connect(m_dlg, SIGNAL( applyClicked() ), this, SLOT( slotApplyPrefs() ) );
+
+ if ( m_dlg->exec() == QDialog::Accepted && m_dlg->getChangesApplied() ) {
+ slotApplyPrefs();
+ }
+
+ delete m_dlg;
+ m_dlg = NULL;
+}
+
+void UMLApp::slotApplyPrefs() {
+ if (m_dlg) {
+ /* we need this to sync both values */
+ m_config -> setGroup( "TipOfDay");
+ Settings::OptionState& optionState = Settings::getOptionState();
+ m_config -> writeEntry( "RunOnStart", optionState.generalState.tip );
+
+ m_doc -> settingsChanged( optionState );
+ const QString plStr = m_dlg->getCodeGenerationLanguage();
+ Uml::Programming_Language pl = Model_Utils::stringToProgLang(plStr);
+ setGenerator(pl);
+ }
+}
+
+bool UMLApp::getUndoEnabled() {
+ return editUndo->isEnabled();
+}
+
+bool UMLApp::getRedoEnabled() {
+ return editRedo->isEnabled();
+}
+
+bool UMLApp::getPasteState() {
+ return editPaste -> isEnabled();
+}
+
+bool UMLApp::getCutCopyState() {
+ return editCopy -> isEnabled();
+}
+
+bool UMLApp::editCutCopy( bool bFromView ) {
+ UMLClipboard clipboard;
+ QMimeSource * clipdata = 0;
+
+ if ((clipdata = clipboard.copy(bFromView)) != 0) {
+ QClipboard* clip = QApplication::clipboard();
+ clip->setData(clipdata);//the global clipboard takes ownership of the clipdata memory
+ connect(clip, SIGNAL(dataChanged()), this, SLOT(slotClipDataChanged()));
+ return true;
+ }
+ return false;
+}
+
+void UMLApp::readOptionState() {
+ m_config -> setGroup( "General Options" );
+ Settings::OptionState& optionState = Settings::getOptionState();
+ optionState.generalState.undo = m_config -> readBoolEntry( "undo", true );
+ optionState.generalState.tabdiagrams = m_config -> readBoolEntry("tabdiagrams", false);
+#if defined (WORK_ON_BUG_126262)
+ optionState.generalState.newcodegen = m_config -> readBoolEntry("newcodegen", false);
+#else
+ optionState.generalState.newcodegen = false;
+#endif
+ optionState.generalState.angularlines = m_config->readBoolEntry("angularlines", false);
+ optionState.generalState.autosave = m_config -> readBoolEntry( "autosave", true );
+ optionState.generalState.time = m_config -> readNumEntry( "time", 0 ); //old autosavetime value kept for compatibility
+ optionState.generalState.autosavetime = m_config -> readNumEntry( "autosavetime", 0 );
+ //if we don't have a "new" autosavetime value, convert the old one
+ if (optionState.generalState.autosavetime == 0) {
+ switch (optionState.generalState.time) {
+ case 0: optionState.generalState.autosavetime = 5; break;
+ case 1: optionState.generalState.autosavetime = 10; break;
+ case 2: optionState.generalState.autosavetime = 15; break;
+ case 3: optionState.generalState.autosavetime = 20; break;
+ case 4: optionState.generalState.autosavetime = 25; break;
+ default: optionState.generalState.autosavetime = 5; break;
+ }
+ }
+ // 2004-05-17 Achim Spangler: read new config entry for autosave sufix
+ optionState.generalState.autosavesuffix = m_config -> readEntry( "autosavesuffix", ".xmi" );
+
+ optionState.generalState.logo = m_config -> readBoolEntry( "logo", true );
+ optionState.generalState.loadlast = m_config -> readBoolEntry( "loadlast", true );
+
+ optionState.generalState.diagram = (Uml::Diagram_Type) m_config->readNumEntry("diagram", 1);
+ m_config -> setGroup( "TipOfDay");
+
+ optionState.generalState.tip = m_config -> readBoolEntry( "RunOnStart", true );
+
+ m_config -> setGroup( "UI Options" );
+ optionState.uiState.useFillColor = m_config -> readBoolEntry( "useFillColor", true );
+ QColor defaultYellow = QColor( 255, 255, 192 );
+ QColor red ( Qt::red );
+
+ optionState.uiState.fillColor = m_config -> readColorEntry( "fillColor", &defaultYellow );
+ optionState.uiState.lineColor = m_config -> readColorEntry( "lineColor", &red );
+ optionState.uiState.lineWidth = m_config -> readNumEntry( "lineWidth", 0 );
+ QFont font = ((QWidget *) this)->font() ;
+ optionState.uiState.font = m_config -> readFontEntry("font", &font );
+
+ m_config -> setGroup( "Class Options" );
+
+ optionState.classState.showVisibility = m_config -> readBoolEntry("showVisibility", true);
+ optionState.classState.showAtts = m_config -> readBoolEntry("showAtts", true);
+ optionState.classState.showOps = m_config -> readBoolEntry("showOps", true);
+ optionState.classState.showStereoType = m_config -> readBoolEntry("showStereoType", false);
+ optionState.classState.showAttSig = m_config -> readBoolEntry("showAttSig", true);
+ optionState.classState.showOpSig = m_config -> readBoolEntry("ShowOpSig", true);
+ optionState.classState.showPackage = m_config -> readBoolEntry("showPackage", false);
+ optionState.classState.defaultAttributeScope = (Uml::Visibility::Value) m_config -> readNumEntry("defaultAttributeScope", Uml::Visibility::Private);
+ optionState.classState.defaultOperationScope = (Uml::Visibility::Value) m_config -> readNumEntry("defaultOperationScope", Uml::Visibility::Public);
+
+ m_config -> setGroup( "Code Viewer Options" );
+
+ QColor defaultWhite = QColor( "white" );
+ QColor defaultBlack = QColor( "black" );
+ QColor defaultPink = QColor( "pink" );
+ QColor defaultGrey = QColor( "grey" );
+
+ optionState.codeViewerState.height = m_config -> readNumEntry( "height", 40 );
+ optionState.codeViewerState.width = m_config -> readNumEntry( "width", 80 );
+ optionState.codeViewerState.font = m_config -> readFontEntry("font", &font );
+ optionState.codeViewerState.showHiddenBlocks = m_config -> readBoolEntry( "showHiddenBlocks", false);
+ optionState.codeViewerState.blocksAreHighlighted = m_config -> readBoolEntry( "blocksAreHighlighted", false);
+ optionState.codeViewerState.selectedColor = m_config -> readColorEntry( "selectedColor", &defaultYellow );
+ optionState.codeViewerState.paperColor = m_config -> readColorEntry( "paperColor", &defaultWhite);
+ optionState.codeViewerState.fontColor = m_config -> readColorEntry( "fontColor", &defaultBlack);
+ optionState.codeViewerState.editBlockColor = m_config -> readColorEntry( "editBlockColor", &defaultPink);
+ optionState.codeViewerState.umlObjectColor = m_config -> readColorEntry( "umlObjectBlockColor", &defaultPink);
+ optionState.codeViewerState.nonEditBlockColor = m_config -> readColorEntry( "nonEditBlockColor", &defaultGrey);
+ optionState.codeViewerState.hiddenColor = m_config -> readColorEntry( "hiddenColor", &defaultGrey);
+
+}
+
+
+/** Call the code viewing assistant on a code document */
+void UMLApp::viewCodeDocument(UMLClassifier* classifier) {
+
+ CodeGenerator * currentGen = getGenerator();
+ if(currentGen && classifier) {
+ if(!dynamic_cast<SimpleCodeGenerator*>(currentGen))
+ {
+ CodeDocument *cdoc = currentGen->findCodeDocumentByClassifier(classifier);
+
+ if (cdoc) {
+ Settings::OptionState& optionState = Settings::getOptionState();
+ CodeViewerDialog * dialog = currentGen->getCodeViewerDialog(this,cdoc,optionState.codeViewerState);
+ dialog->exec();
+ optionState.codeViewerState = dialog->getState();
+ delete dialog;
+ dialog = NULL;
+ } else {
+ // shouldn't happen..
+ KMessageBox::sorry(0, i18n("Cannot view code until you generate some first."),i18n("Cannot View Code"));
+ }
+ } else {
+ KMessageBox::sorry(0, i18n("Cannot view code from simple code writer."),i18n("Cannot View Code"));
+ }
+ }
+
+}
+
+void UMLApp::refactor(UMLClassifier* classifier) {
+ if (!m_refactoringAssist) {
+ m_refactoringAssist = new RefactoringAssistant( m_doc, 0, 0, "refactoring_assistant" );
+ }
+ m_refactoringAssist->refactor(classifier);
+ m_refactoringAssist->show();
+}
+
+CodeGenerationPolicy *UMLApp::getCommonPolicy() {
+ return m_commoncodegenpolicy;
+}
+
+void UMLApp::setPolicyExt(CodeGenPolicyExt *policy) {
+ m_policyext = policy;
+}
+
+CodeGenPolicyExt *UMLApp::getPolicyExt() {
+ return m_policyext;
+}
+
+CodeGenerator *UMLApp::setGenerator(Uml::Programming_Language pl) {
+ if (pl == Uml::pl_Reserved) {
+ if (m_codegen) {
+ delete m_codegen;
+ m_codegen = NULL;
+ }
+ return NULL;
+ }
+ // does the code generator already exist?
+ // then simply return that
+ if (m_codegen) {
+ if (m_codegen->getLanguage() == pl)
+ return m_codegen;
+ delete m_codegen; // ATTENTION! remove all refs to it or its policy first
+ m_codegen = NULL;
+ }
+ m_activeLanguage = pl;
+ m_codegen = CodeGenFactory::createObject(pl);
+ updateLangSelectMenu(pl);
+
+ if (m_policyext)
+ m_policyext->setDefaults(m_config, false); // picks up language specific stuff
+ return m_codegen;
+}
+
+CodeGenerator* UMLApp::getGenerator() {
+ return m_codegen;
+}
+
+void UMLApp::generateAllCode() {
+ if (m_codegen) {
+ m_codegen->writeCodeToFile();
+ }
+}
+
+void UMLApp::generationWizard() {
+ CodeGenerationWizard wizard(0 /*classList*/);
+ wizard.exec();
+}
+
+void UMLApp::setActiveLanguage(int menuId) {
+
+ // only change the active language IF different from one we currently have
+ if (!m_langSelect->isItemChecked(menuId))
+ {
+ uint index = 0;
+ for(unsigned int i=0; i < m_langSelect->count(); i++) {
+ int id = m_langSelect->idAt(i);
+ m_langSelect->setItemChecked(id, false); //uncheck everything
+ if (id == menuId)
+ index = i;
+ }
+
+ m_langSelect->setItemChecked(menuId,true);
+ m_activeLanguage = (Uml::Programming_Language)index;
+
+ // update the generator
+ setGenerator(m_activeLanguage);
+ }
+}
+
+void UMLApp::setActiveLanguage( const QString &activeLanguage ) {
+
+ for(unsigned int j=0; j < m_langSelect->count(); j++) {
+ int id = m_langSelect->idAt(j);
+
+ if (m_langSelect->text(id) == activeLanguage &&
+ m_langSelect->isItemChecked(id))
+ return; // already set.. no need to do anything
+ }
+
+ for(unsigned int i=0; i < m_langSelect->count(); i++) {
+ bool isActiveLang = (m_langSelect->text(m_langSelect->idAt(i)) == activeLanguage);
+ //uncheck everything except the active language
+ m_langSelect->setItemChecked(m_langSelect->idAt(i), isActiveLang);
+ }
+
+ setGenerator(Model_Utils::stringToProgLang(activeLanguage));
+}
+
+Uml::Programming_Language UMLApp::getActiveLanguage() {
+ return m_activeLanguage;
+}
+
+bool UMLApp::activeLanguageIsCaseSensitive() {
+ return (m_activeLanguage != Uml::pl_Pascal &&
+ m_activeLanguage != Uml::pl_Ada &&
+ m_activeLanguage != Uml::pl_SQL);
+}
+
+QString UMLApp::activeLanguageScopeSeparator() {
+ Uml::Programming_Language pl = getActiveLanguage();
+ if (pl == Uml::pl_Ada ||
+ pl == Uml::pl_CSharp ||
+ pl == Uml::pl_Pascal ||
+ pl == Uml::pl_Java ||
+ pl == Uml::pl_JavaScript ||
+ pl == Uml::pl_Python) // CHECK: more?
+ return ".";
+ return "::";
+}
+
+void UMLApp::slotCurrentViewClearDiagram() {
+ getCurrentView()->clearDiagram();
+}
+
+void UMLApp::slotCurrentViewToggleSnapToGrid() {
+ getCurrentView()->toggleSnapToGrid();
+ viewSnapToGrid->setChecked( getCurrentView()->getSnapToGrid() );
+}
+
+void UMLApp::slotCurrentViewToggleShowGrid() {
+ getCurrentView()->toggleShowGrid();
+ viewShowGrid->setChecked( getCurrentView()->getShowSnapGrid() );
+}
+
+void UMLApp::slotCurrentViewExportImage() {
+ getCurrentView()->getImageExporter()->exportView();
+}
+
+void UMLApp::slotAllViewsExportImage() {
+ m_imageExporterAll->exportAllViews();
+}
+
+void UMLApp::slotCurrentViewProperties() {
+ getCurrentView()->showPropDialog();
+}
+
+void UMLApp::setDiagramMenuItemsState(bool bState) {
+ viewClearDiagram->setEnabled( bState );
+ viewSnapToGrid->setEnabled( bState );
+ viewShowGrid->setEnabled( bState );
+ deleteDiagram->setEnabled(bState);
+ viewExportImage->setEnabled( bState );
+ viewProperties->setEnabled( bState );
+ filePrint->setEnabled( bState );
+ if ( getCurrentView() ) {
+ viewSnapToGrid->setChecked( getCurrentView()->getSnapToGrid() );
+ viewShowGrid->setChecked( getCurrentView()->getShowSnapGrid() );
+ }
+}
+
+void UMLApp::slotUpdateViews() {
+ QPopupMenu* menu = findMenu( menuBar(), QString("views") );
+ if (!menu) {
+ kWarning() << "view menu not found" << endl;
+ return;
+ }
+
+ menu = findMenu( menu, QString("show_view") );
+ if (!menu) {
+ kWarning() << "show menu not found" << endl;
+ return;
+ }
+
+ menu->clear();
+
+ UMLViewList views = getDocument()->getViewIterator();
+ for(UMLView *view = views.first(); view; view = views.next()) {
+ menu->insertItem( view->getName(), view, SLOT( slotShowView() ) );
+ view->fileLoaded();
+ }
+}
+
+void UMLApp::slotImportClasses() {
+ m_doc->setLoading(true);
+ // File selection is separated from invocation of ClassImport::import()
+ // because the user might decide to choose a language different from
+ // the active language (by using the "All Files" option).
+ QString preselectedExtension;
+ const Uml::Programming_Language pl = m_codegen->getLanguage();
+ if (pl == Uml::pl_IDL) {
+ preselectedExtension = i18n("*.idl|IDL Files (*.idl)");
+ } else if (pl == Uml::pl_Python) {
+ preselectedExtension = i18n("*.py|Python Files (*.py)");
+ } else if (pl == Uml::pl_Java) {
+ preselectedExtension = i18n("*.java|Java Files (*.java)");
+ } else if (pl == Uml::pl_Pascal) {
+ preselectedExtension = i18n("*.pas|Pascal Files (*.pas)");
+ } else if (pl == Uml::pl_Ada) {
+ preselectedExtension = i18n("*.ads *.ada|Ada Files (*.ads *.ada)");
+ } else {
+ preselectedExtension = i18n("*.h *.hh *.hpp *.hxx *.H|Header Files (*.h *.hh *.hpp *.hxx *.H)");
+ }
+ preselectedExtension.append("\n*|" + i18n("All Files"));
+ QStringList fileList = KFileDialog::getOpenFileNames(":import-classes", preselectedExtension,
+ this, i18n("Select Code to Import") );
+ const QString& firstFile = fileList.first();
+ ClassImport *classImporter = ClassImport::createImporterByFileExt(firstFile);
+ classImporter->importFiles(fileList);
+ delete classImporter;
+ m_doc->setLoading(false);
+ //Modification is set after the import is made, because the file was modified when adding the classes
+ //Allowing undo of the whole class importing. I think it eats a lot of memory
+ //m_doc->setModified(true);
+ //Setting the modification, but without allowing undo
+ m_doc->setModified(true, false);
+}
+
+void UMLApp::slotClassWizard() {
+ ClassWizard dlg( m_doc );
+ dlg.exec();
+}
+
+void UMLApp::slotAddDefaultDatatypes() {
+ m_doc->addDefaultDatatypes();
+}
+
+void UMLApp::slotCurrentViewChanged() {
+ UMLView *view = getCurrentView();
+ if (view) {
+ connect(view, SIGNAL( sigShowGridToggled(bool) ),
+ this, SLOT( slotShowGridToggled(bool) ) );
+ connect(view, SIGNAL( sigSnapToGridToggled(bool) ),
+ this, SLOT( slotSnapToGridToggled(bool) ) );
+ }
+}
+void UMLApp::slotSnapToGridToggled(bool gridOn) {
+ viewSnapToGrid->setChecked(gridOn);
+}
+
+void UMLApp::slotShowGridToggled(bool gridOn) {
+ viewShowGrid->setChecked(gridOn);
+}
+
+void UMLApp::slotSelectAll() {
+ getCurrentView()->selectAll();
+}
+
+void UMLApp::slotDeleteSelectedWidget() {
+ if ( getCurrentView() ) {
+ getCurrentView()->deleteSelection();
+ } else {
+ kWarning() << " trying to delete widgets when there is no current view (see bug 59774)" << endl;
+ }
+}
+
+void UMLApp::slotDeleteDiagram() {
+ m_doc->removeDiagram( getCurrentView()->getID() );
+}
+
+Uml::Programming_Language UMLApp::getDefaultLanguage() {
+ m_config->setGroup("Code Generation");
+ QString activeLanguage = m_config->readEntry("activeLanguage", "C++");
+ return Model_Utils::stringToProgLang(activeLanguage);
+}
+
+void UMLApp::initGenerator() {
+ if (m_codegen) {
+ delete m_codegen;
+ m_codegen = NULL;
+ }
+ Uml::Programming_Language defaultLanguage = getDefaultLanguage();
+ setActiveLanguage(Model_Utils::progLangToString(defaultLanguage));
+ if (m_codegen == NULL)
+ setGenerator(defaultLanguage);
+ updateLangSelectMenu(defaultLanguage);
+}
+
+void UMLApp::updateLangSelectMenu(Uml::Programming_Language activeLanguage) {
+ m_langSelect->clear();
+ m_langSelect->setCheckable(true);
+ for (int i = 0; i < Uml::pl_Reserved; i++) {
+ QString language = Model_Utils::progLangToString((Uml::Programming_Language) i);
+ int id = m_langSelect->insertItem(language,this,SLOT(setActiveLanguage(int)));
+ const bool isActiveLanguage = (activeLanguage == i);
+ m_langSelect->setItemChecked(id, isActiveLanguage);
+ }
+}
+
+void UMLApp::tipOfTheDay()
+{
+ KTipDialog::showTip(this ,QString::null, true);
+}
+
+void UMLApp::keyPressEvent(QKeyEvent *e) {
+ switch(e->key()) {
+ case Qt::Key_Shift:
+ //toolsbar->setOldTool();
+ e->accept();
+ break;
+
+ default:
+ e->ignore();
+ }
+
+}
+
+void UMLApp::customEvent(QCustomEvent* e) {
+ if (e->type() == CmdLineExportAllViewsEvent::getType()) {
+ CmdLineExportAllViewsEvent* exportAllViewsEvent = static_cast<CmdLineExportAllViewsEvent*>(e);
+ exportAllViewsEvent->exportAllViews();
+ }
+}
+
+//TODO Move this to UMLWidgetController?
+void UMLApp::handleCursorKeyReleaseEvent(QKeyEvent* e) {
+ // in case we have selected something in the diagram, move it by one pixel
+ // to the direction pointed by the cursor key
+ if (m_view == NULL || !m_view->getSelectCount() || e->state() != Qt::AltButton) {
+ e->ignore();
+ return;
+ }
+ int dx = 0;
+ int dy = 0;
+ switch (e->key()) {
+ case Qt::Key_Left:
+ dx = -1;
+ break;
+ case Qt::Key_Right:
+ dx = 1;
+ break;
+ case Qt::Key_Up:
+ dy = -1;
+ break;
+ case Qt::Key_Down:
+ dy = 1;
+ break;
+ default:
+ e->ignore();
+ return;
+ }
+ m_view->moveSelectedBy(dx, dy);
+
+ // notify about modification only at the first key release of possible sequence of auto repeat key releases,
+ // this reduces the slow down caused by setModified() and makes the cursor moving of widgets smoother
+ if (!e->isAutoRepeat()) {
+ m_doc->setModified();
+ }
+ e->accept();
+}
+
+void UMLApp::keyReleaseEvent(QKeyEvent *e) {
+ switch(e->key()) {
+ case Qt::Key_Backspace:
+ if (!m_pDocWindow->isTyping())
+ toolsbar->setOldTool();
+ e->accept();
+ break;
+ case Qt::Key_Escape:
+ toolsbar->setDefaultTool();
+ e->accept();
+ break;
+ case Qt::Key_Left:
+ case Qt::Key_Right:
+ case Qt::Key_Up:
+ case Qt::Key_Down:
+ handleCursorKeyReleaseEvent(e);
+ break;
+ default:
+ e->ignore();
+ }
+
+}
+
+void UMLApp::newDocument() {
+ m_doc->newDocument();
+ Uml::Programming_Language defaultLanguage = getDefaultLanguage();
+ if (m_codegen) {
+ defaultLanguage = m_codegen->getLanguage();
+ delete m_codegen;
+ m_codegen = NULL;
+ }
+ setGenerator(defaultLanguage);
+ slotUpdateViews();
+}
+
+QWidget* UMLApp::getMainViewWidget() {
+ Settings::OptionState& optionState = Settings::getOptionState();
+ if (optionState.generalState.tabdiagrams)
+ return m_tabWidget;
+ return m_viewStack;
+}
+
+void UMLApp::setCurrentView(UMLView* view) {
+ m_view = view;
+ if (m_viewStack == NULL) {
+ kError() << "UMLApp::setCurrentView: m_viewStack is NULL" << endl;
+ return;
+ }
+ if (view == NULL) {
+ kDebug() << "UMLApp::setCurrentView: view is NULL" << endl;
+ return;
+ }
+ if (m_viewStack->id(view) < 0)
+ m_viewStack->addWidget(view);
+ m_viewStack->raiseWidget(view);
+ slotStatusMsg(view->getName());
+ UMLListViewItem* lvitem = m_listView->findView(view);
+ if (lvitem)
+ m_listView->setCurrentItem(lvitem);
+}
+
+UMLView* UMLApp::getCurrentView() {
+ return m_view;
+}
+
+QPopupMenu* UMLApp::findMenu(QMenuData* menu, const QString &name) {
+
+ if (menu) {
+ int menuCount = menu->count();
+
+ for (int i=0; i<menuCount; i++) {
+ int idAt = menu->idAt(i);
+ QPopupMenu* popupMenu = menu->findItem(idAt)->popup();
+ if (popupMenu) {
+ QString menuName = popupMenu->name();
+ if( menuName == name) {
+ return popupMenu;
+ }
+ }
+ }
+ }
+ return 0;
+}
+
+void UMLApp::slotTabChanged(QWidget* view) {
+ UMLView* umlview = ( UMLView* )view;
+ m_doc->changeCurrentView( umlview->getID() );
+}
+
+void UMLApp::slotChangeTabLeft() {
+ if (m_tabWidget) {
+ m_tabWidget->setCurrentPage( m_tabWidget->currentPageIndex() - 1 );
+ return;
+ }
+ UMLViewList views = m_doc->getViewIterator();
+ UMLView *currView = m_view;
+ if (views.find(currView) < 0) {
+ kError() << "UMLApp::slotChangeTabLeft(): currView not found in viewlist" << endl;
+ return;
+ }
+ if ((currView = views.prev()) != NULL)
+ setCurrentView(currView);
+ else
+ setCurrentView(views.last());
+}
+
+void UMLApp::slotChangeTabRight() {
+ if (m_tabWidget) {
+ m_tabWidget->setCurrentPage( m_tabWidget->currentPageIndex() + 1 );
+ return;
+ }
+ UMLViewList views = m_doc->getViewIterator();
+ UMLView *currView = m_view;
+ if (views.find(currView) < 0) {
+ kError() << "UMLApp::slotChangeTabRight(): currView not found in viewlist" << endl;
+ return;
+ }
+ if ((currView = views.next()) != NULL)
+ setCurrentView(currView);
+ else
+ setCurrentView(views.first());
+}
+
+void UMLApp::slotMoveTabLeft() {
+ //causes problems
+ //does strange things when moving right most diagram to the right
+ //doesn't save order in file
+ //m_tabWidget->moveTab( m_tabWidget->currentPageIndex(), m_tabWidget->currentPageIndex() - 1 );
+}
+
+void UMLApp::slotMoveTabRight() {
+ //causes problems
+ //m_tabWidget->moveTab( m_tabWidget->currentPageIndex(), m_tabWidget->currentPageIndex() + 1 );
+}
+
+void UMLApp::slotAutolayout(){
+#ifdef HAVE_DOT
+/*
+ QDialog* d = new AutolayoutDlg(getCurrentView());
+ d->show();
+ */
+#endif
+}
+
+void UMLApp::slotXhtmlDocGenerationFinished()
+{
+ delete m_xhtmlGenerator;
+ m_xhtmlGenerator = 0;
+}
+
+KTabWidget* UMLApp::tabWidget() {
+ return m_tabWidget;
+}
+
+QString UMLApp::getStatusBarMsg() {
+ return m_statusLabel->text();
+}
+
+//static pointer, holding the unique instance
+UMLApp* UMLApp::s_instance;
+
+#include "uml.moc"
diff --git a/umbrello/umbrello/uml.h b/umbrello/umbrello/uml.h
new file mode 100644
index 00000000..ee669d88
--- /dev/null
+++ b/umbrello/umbrello/uml.h
@@ -0,0 +1,1026 @@
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * copyright (C) 2002-2006 *
+ * Umbrello UML Modeller Authors <uml-devel@uml.sf.net> *
+ ***************************************************************************/
+
+#ifndef UML_H
+#define UML_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "umlnamespace.h"
+
+#include <qmap.h>
+#include <qdict.h>
+
+#include <kdockwidget.h>
+#include <kdeversion.h>
+#include <kurl.h>
+
+// forward declaration of the UML classes
+class AlignToolBar;
+class CodeDocument;
+class CodeGenerator;
+class CodeGenerationPolicy;
+class CodeGenPolicyExt;
+class DocWindow;
+class UMLClassifier;
+class UMLDoc;
+class UMLListView;
+class UMLView;
+class WorkToolBar;
+class SettingsDlg;
+class UMLViewImageExporterAll;
+class RefactoringAssistant;
+class KPlayerPopupSliderAction;
+class XhtmlGenerator;
+
+// KDE forward declarations
+class KActionMenu;
+class KRecentFilesAction;
+class KStatusBarLabel;
+class KToggleAction;
+class KDockWidget;
+class KTabWidget;
+class KToolBarButton;
+class KPopupMenu;
+
+// Qt forward declarations
+class QWidgetStack;
+class QMenuData;
+class QClipboard;
+class QToolButton;
+class QCustomEvent;
+
+/**
+ * The base class for UML application windows. It sets up the main
+ * window and reads the config file as well as providing a menubar, toolbar
+ * and statusbar. An instance of UMLView creates your center view, which is connected
+ * to the window's Doc object.
+ * UMLApp reimplements the methods that KMainWindow provides for main window handling and supports
+ * full session management as well as using KActions.
+ * @see KMainWindow
+ * @see KApplication
+ * @see KConfig
+ *
+ * @author Paul Hensgen <phensgen@techie.com>
+ * Bugs and comments to uml-devel@lists.sf.net or http://bugs.kde.org
+ */
+
+class UMLApp : public KDockMainWindow {
+ Q_OBJECT
+public:
+ /**
+ * Constructor. Calls all init functions to create the application.
+ */
+ UMLApp(QWidget* parent=0, const char* name=0);
+
+ /**
+ * Standard deconstructor.
+ */
+ ~UMLApp();
+
+ static UMLApp* app();
+
+ /**
+ * Opens a file specified by commandline option.
+ */
+ void openDocumentFile(const KURL& url=KURL());
+
+ /**
+ * Calls the UMLDoc method to create a new Document.
+ */
+ void newDocument();
+
+ /**
+ * Returns a pointer to the current document connected to the
+ * KMainWindow instance.
+ * Used by the View class to access the document object's methods.
+ */
+ UMLDoc *getDocument() const;
+
+ /**
+ * Returns a pointer to the list view.
+ *
+ * @return The listview being used.
+ */
+ UMLListView* getListView();
+
+ /**
+ * Returns the toolbar being used.
+ *
+ * @return The toolbar being used.
+ */
+ WorkToolBar* getWorkToolBar();
+
+ /**
+ * Sets whether the program has been modified.
+ * This will change how the program saves/exits.
+ *
+ * @param _m true - modified.
+ */
+ void setModified(bool _m);
+
+ /**
+ * Set whether to allow printing.
+ * It will enable/disable the menu/toolbar options.
+ *
+ * @param enable Set whether to allow printing.
+ */
+ void enablePrint(bool enable);
+
+ /**
+ * Set whether to allow printing.
+ * It will enable/disable the menu/toolbar options.
+ *
+ * @param enable Set whether to allow printing.
+ */
+ void enableUndo(bool enable);
+
+ /**
+ * Set whether to allow printing.
+ * It will enable/disable the menu/toolbar options.
+ *
+ * @param enable Set whether to allow printing.
+ */
+ void enableRedo(bool enable);
+
+ /**
+ * Returns a pointer to the documentation window.
+ *
+ * @return Pointer to the DocWindow.
+ */
+ DocWindow * getDocWindow() {
+ return m_pDocWindow;
+ }
+
+ /**
+ * Returns the undo state.
+ *
+ * @return True if Undo is enabled.
+ */
+ bool getUndoEnabled();
+
+ /**
+ * Returns the redo state.
+ *
+ * @return True if Redo is enabled.
+ */
+ bool getRedoEnabled();
+
+ /**
+ * Returns the paste state.
+ *
+ * @return True if Paste is enabled.
+ */
+ bool getPasteState();
+
+ /**
+ * Returns the state on Cut/Copy.
+ *
+ * @return True if Cut/Copy is enabled.
+ */
+ bool getCutCopyState();
+
+ /**
+ * Gets the appropriate CodeGenerator.
+ *
+ * @return Pointer to the CodeGenerator.
+ */
+ CodeGenerator* getGenerator();
+
+ /**
+ * Set the current generator for this app.
+ * If giveWarning is true, then a popup box warning that the
+ * code generation library is out-of-date will show if you
+ * attempt to set the generator to NULL.
+ *
+ * @param gen Pointer to the CodeGenerator to set.
+ * @param giveWarning True to enable out-of-date warning.
+ */
+ void setGenerator(CodeGenerator* gen, bool giveWarning = true);
+
+ /**
+ * Creates a new code generator for the given active language.
+ *
+ * @return Pointer to the CodeGenerator created.
+ */
+ CodeGenerator* createGenerator();
+
+ /**
+ * Auxiliary function for UMLDoc::loadExtensionsFromXMI():
+ * Return the code generator of the given language if it already
+ * exists; if it does not yet exist then create it and return
+ * the newly created generator. It is the caller's responsibility
+ * to load XMI into the newly created generator.
+ */
+ CodeGenerator *setGenerator(Uml::Programming_Language pl);
+
+ /**
+ * Call the refactoring assistant on a classifier.
+ *
+ * @param classifier Pointer to the classifier to refactor.
+ */
+ void refactor(UMLClassifier* classifier);
+
+ /**
+ * Call the code viewing assistant on a given UMLClassifier.
+ *
+ * @param classifier Pointer to the classifier to view.
+ */
+ void viewCodeDocument(UMLClassifier* classifier);
+
+ /**
+ * Sets the state of the view properties menu item.
+ *
+ * @param bState Boolean, true to enable the view properties item.
+ */
+ void setDiagramMenuItemsState(bool bState);
+
+ /**
+ * Returns the widget used as the parent for UMLViews.
+ * @return The main view widget.
+ */
+ QWidget* getMainViewWidget();
+
+ /**
+ * Puts this view to the top of the viewStack, i.e. makes it
+ * visible to the user.
+ *
+ * @param view Pointer to the UMLView to push.
+ */
+ void setCurrentView(UMLView* view);
+
+ /**
+ * Get the current view.
+ * This may return a null pointer (when no view was previously
+ * specified.)
+ *
+ */
+ UMLView* getCurrentView();
+
+ /**
+ * Sets the default mime type for all diagrams that are exported as
+ * images.
+ *
+ * @param mimeType The MIME type to set as the default.
+ */
+ void setImageMimeType(QString const & mimeType){m_imageMimeType=mimeType;};
+
+ /**
+ * Gets the default mime type for all diagrams that are exported as
+ * images.
+ *
+ * @return The default MIME type for images.
+ */
+ QString const & getImageMimeType()const{return m_imageMimeType;};
+
+ /**
+ * Carries out the cut/copy command with different action performed
+ * depending on if from view or list view.
+ * Cut/Copy are the same. It is up to the caller to delete/cut the selection..
+ *
+ * If the operation is successful, the signal sigCutSuccessful() is emitted.
+ *
+ * Callers should connect to this signal to know what to do next.
+ */
+ bool editCutCopy( bool bFromView );
+
+ /**
+ * Return the tab widget.
+ */
+ KTabWidget *tabWidget();
+
+ /**
+ * Returns the current text in the status bar.
+ *
+ * @return The text in the status bar.
+ */
+ QString getStatusBarMsg();
+
+ /**
+ * Returns the default code generation policy.
+ */
+ CodeGenerationPolicy *getCommonPolicy();
+
+ /**
+ * Sets the CodeGenPolicyExt object.
+ */
+ void setPolicyExt(CodeGenPolicyExt *policy);
+
+ /**
+ * Returns the CodeGenPolicyExt object.
+ */
+ CodeGenPolicyExt *getPolicyExt();
+
+protected:
+ virtual void keyPressEvent(QKeyEvent* e);
+ virtual void keyReleaseEvent(QKeyEvent* e);
+
+ /**
+ * Event handler to receive custom events.
+ * It handles events such as exporting all views from command line (in
+ * that case, it executes the exportAllViews method in the event).
+ */
+ virtual void customEvent(QCustomEvent* e);
+
+ /**
+ * Helper method for handling cursor key release events (refactoring).
+ */
+ void handleCursorKeyReleaseEvent(QKeyEvent* e);
+
+ /**
+ * 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();
+
+ /**
+ * Read general Options again and initialize all variables
+ * like the recent file list.
+ */
+ void readOptions();
+
+ /**
+ * Initializes the KActions of the application.
+ */
+ void initActions();
+
+ /**
+ * Sets up the statusbar for the main window by
+ * initialzing a statuslabel.
+ */
+ void initStatusBar();
+
+ /**
+ * Creates the centerwidget of the KMainWindow instance and
+ * sets it as the view.
+ */
+ void initView();
+
+ /**
+ * queryClose is called by KMainWindow on each closeEvent of a
+ * window. Counter to the default implementation (which only
+ * returns true), this calls saveModified() on the document object
+ * to ask if the document shall be saved if Modified; on cancel
+ * the closeEvent is rejected.
+ * @see KMainWindow#queryClose
+ * @see KMainWindow#closeEvent
+ *
+ * @return True if window may be closed.
+ */
+ virtual bool queryClose();
+
+ /**
+ * queryExit is called by KMainWindow when the last
+ * window of the application is going to be closed during
+ * the closeEvent(). In contrast to the default
+ * implementation that just returns true, this calls
+ * saveOptions() to save the settings of the last
+ * window's properties.
+ * @see KMainWindow#queryExit
+ * @see KMainWindow#closeEvent
+ *
+ * @return True if window may be closed.
+ */
+ virtual bool queryExit();
+
+ /**
+ * Saves the window properties for each open window
+ * during session end to the session config file,
+ * including saving the currently opened file by a
+ * temporary filename provided by KApplication.
+ * @see KMainWindow#saveProperties
+ */
+ virtual void saveProperties(KConfig *_cfg);
+
+ /**
+ * Reads the session config file and restores the
+ * application's state including the last opened files and
+ * documents by reading the temporary files saved by
+ * saveProperties()
+ * @see KMainWindow#readProperties
+ */
+ virtual void readProperties(KConfig *_cfg);
+
+ CodeGenerationPolicy * m_commoncodegenpolicy;
+
+ /**
+ * Updates the Menu for language selection and sets the
+ * active lanugage. If no active lanugage is found or if it is
+ * not one of the registered languages it tries to fall back
+ * to Cpp
+ */
+ void updateLangSelectMenu(Uml::Programming_Language activeLanguage);
+
+protected slots:
+
+ /**
+ * Show "Tip of the Day" dialog
+ */
+ void tipOfTheDay();
+
+public slots:
+
+ /**
+ * Reads the activeLanguage from the KConfig and calls updateLangSelectMenu()
+ */
+ void initGenerator();
+
+ /**
+ * Runs the code generation wizard.
+ */
+ void generationWizard();
+
+ /**
+ * Clears the document in the actual view to reuse it as the new
+ * document.
+ */
+ void slotFileNew();
+
+ /**
+ * Open a file and load it into the document.
+ */
+ void slotFileOpen();
+
+ /**
+ * Opens a file from the recent files menu.
+ */
+ void slotFileOpenRecent(const KURL& url);
+
+ /**
+ * Save a document.
+ */
+ void slotFileSave();
+
+ /**
+ * Save a document by a new filename.
+ */
+ bool slotFileSaveAs();
+
+ /**
+ * Asks for saving if the file is modified, then closes the current
+ * file and window.
+ */
+ void slotFileClose();
+
+ /**
+ * Print the current file.
+ */
+ void slotFilePrint();
+
+ /**
+ * 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
+ * aborts.
+ */
+ void slotFileQuit();
+
+ /**
+ * Exports the current model to docbook in a subdir of the
+ * current model directory named from the model name.
+ * @todo Let the user chose the destination directory and
+ * name, using network transparency.
+ */
+ void slotFileExportDocbook();
+
+ /**
+ * Exports the current model to XHTML in a subdir of the
+ * current model directory named from the model name.
+ * @todo Let the user chose the destination directory and
+ * name, using network transparency.
+ */
+ void slotFileExportXhtml();
+
+ /**
+ * Put the marked text/object into the clipboard and remove
+ * it from the document.
+ */
+ void slotEditCut();
+
+ /**
+ * Put the marked text/object into the clipboard.
+ */
+ void slotEditCopy();
+
+ /**
+ * Paste the clipboard into the document.
+ */
+ void slotEditPaste();
+
+ /**
+ * Toggles the toolbar.
+ * Deprecated. For compatibility with KDE 3.1, remove if we stop supporting KDE 3.1
+ */
+ void slotViewToolBar();
+
+ /**
+ * Toggles the statusbar.
+ * Deprecated. For compatibility with KDE 3.1, remove if we stop supporting KDE 3.1
+ */
+ void slotViewStatusBar();
+
+ /**
+ * Autolayouts the current class diagram
+ */
+ void slotAutolayout();
+
+ /**
+ * Changes the statusbar contents for the standard label
+ * permanently, used to indicate current actions.
+ * @param text The text that is displayed in the statusbar
+ */
+ void slotStatusMsg(const QString &text);
+
+ /**
+ * Create this view.
+ */
+ void slotClassDiagram();
+
+ /**
+ * Create this view.
+ */
+ void slotSequenceDiagram();
+
+ /**
+ * Create this view.
+ */
+ void slotCollaborationDiagram();
+
+ /**
+ * Create this view.
+ */
+ void slotUseCaseDiagram();
+
+ /**
+ * Create this view.
+ */
+ void slotStateDiagram();
+
+ /**
+ * Create this view.
+ */
+ void slotActivityDiagram();
+
+ /**
+ * Create this view.
+ */
+ void slotComponentDiagram();
+
+ /**
+ * Create this view.
+ */
+ void slotDeploymentDiagram();
+ /**
+ * Create this view.
+ */
+ void slotEntityRelationshipDiagram();
+
+ /**
+ * Notification of changed clipboard data.
+ */
+ void slotClipDataChanged();
+
+ /**
+ *
+ */
+ void slotCopyChanged();
+
+ /**
+ * Shows the global preferences dialog.
+ */
+ void slotPrefs();
+
+ /**
+ * Commits the changes from the global preferences dialog.
+ */
+ void slotApplyPrefs();
+
+ /**
+ * Register new views (aka diagram) with the GUI so they show up
+ * in the menu.
+ */
+ void slotUpdateViews();
+
+ /**
+ * Generate code for all classes.
+ */
+ void generateAllCode();
+
+ /**
+ * Set the language for which code will be generated.
+ *
+ * @param menuID the ID of the langSelect menu item for
+ * the relevant language.
+ */
+ void setActiveLanguage(int menuID);
+
+ /**
+ * Set the language for which code will be generated.
+ *
+ * @param activeLanguage The name of the language to set
+ */
+ void setActiveLanguage( const QString &activeLanguage );
+
+ /**
+ * Get the language for import and code generation.
+ */
+ Uml::Programming_Language getActiveLanguage();
+
+ /**
+ * Return true if the active language is case sensitive.
+ */
+ bool activeLanguageIsCaseSensitive();
+
+ /**
+ * Return the target language depedent scope separator.
+ */
+ QString activeLanguageScopeSeparator();
+
+ /**
+ * Return the default code generation language as configured by KConfig.
+ * If the activeLanguage is not found in the KConfig then use Uml::pl_Cpp
+ * as the default.
+ */
+ Uml::Programming_Language getDefaultLanguage();
+
+ /**
+ * Menu selection for clear current view.
+ */
+ void slotCurrentViewClearDiagram();
+
+ /**
+ * Menu selection for current view snap to grid property.
+ */
+ void slotCurrentViewToggleSnapToGrid();
+
+ /**
+ * Menu selection for current view show grid property.
+ */
+ void slotCurrentViewToggleShowGrid();
+
+ /**
+ * Menu selection for exporting current view as an image.
+ */
+ void slotCurrentViewExportImage();
+
+ /**
+ * Menu selection for exporting all views as images.
+ */
+ void slotAllViewsExportImage();
+
+ /**
+ * Menu selection for current view properties.
+ */
+ void slotCurrentViewProperties();
+
+ /**
+ * Import classes menu selection.
+ */
+ void slotImportClasses();
+
+ /**
+ * Class wizard menu selection.
+ */
+ void slotClassWizard();
+
+ /**
+ * Calls the active code generator to add its default datatypes
+ */
+ void slotAddDefaultDatatypes();
+
+ /**
+ * The displayed diagram has changed.
+ */
+ void slotCurrentViewChanged();
+
+ /**
+ * The snap to grid value has been changed.
+ */
+ void slotSnapToGridToggled(bool gridOn);
+
+ /**
+ * The show grid value has been changed.
+ */
+ void slotShowGridToggled(bool gridOn);
+
+ /**
+ * Select all widgets on the current diagram.
+ */
+ void slotSelectAll();
+
+ /**
+ * Deletes the selected widget.
+ */
+ void slotDeleteSelectedWidget();
+
+ /**
+ * Deletes the current diagram.
+ */
+ void slotDeleteDiagram();
+
+ /**
+ * Set the zoom factor of the current diagram.
+ *
+ * @param zoom Zoom factor in percentage.
+ */
+ void setZoom(int zoom);
+
+ /**
+ * Connected to by the KPlayerSliderAction zoomAction, a value of between 300
+ * and 2200 is scaled to zoom to between 9% and 525%.
+ * The min and max values of the slider are hard coded in KPlayerSliderAction for now.
+ * @param value Zoom factor before scaleing
+ */
+ void slotZoomSliderMoved(int value);
+
+ /**
+ * Set zoom to 100%
+ */
+ void slotZoom100();
+
+ /**
+ * Prepares the zoom menu for display.
+ */
+ void setupZoomMenu();
+
+ /**
+ * Reverts the document back to the state it was prior to the
+ * last action performed by the user.
+ */
+ void slotEditUndo();
+
+ /**
+ * Reverts the document back to the state it was prior to the
+ * last undo.
+ */
+ void slotEditRedo();
+
+ /**
+ * Searches for a menu with the given name
+ *
+ * @param menu The QPopupMenu or QMenuBar to search through.
+ * @param name The name of the menu to search for (name, not text)
+ */
+ QPopupMenu* findMenu(QMenuData* menu, const QString &name);
+
+ /**
+ * called when the tab has changed
+ */
+ void slotTabChanged(QWidget* view);
+
+ /**
+ * make the tab on the left of the current one the active one
+ */
+ void slotChangeTabLeft();
+
+ /**
+ * make the tab on the right of the current one the active one
+ */
+ void slotChangeTabRight();
+
+ /**
+ * Move the current tab left, not implemented
+ */
+ void slotMoveTabLeft();
+
+ /**
+ * Move the current tab right, not implemented
+ */
+ void slotMoveTabRight();
+
+ KConfig *getConfig() { return m_config; }
+
+ /**
+ * This slot deletes the current XHTML documentation generator as soon as
+ * this one signals that it has finished.
+ */
+ void slotXhtmlDocGenerationFinished();
+
+private:
+ static UMLApp* s_instance;
+
+ /**
+ * For selecting the active language.
+ */
+ QPopupMenu *m_langSelect;
+
+ /**
+ * Popup menu for zoom selection.
+ */
+ QPopupMenu *m_zoomSelect;
+
+ /**
+ * Active language.
+ */
+ Uml::Programming_Language m_activeLanguage;
+
+ /**
+ * Active code generator.
+ */
+ CodeGenerator *m_codegen;
+
+ /**
+ * Active policy extension.
+ * Only used for new code generators ({Cpp,Java,Ruby}CodeGenerator)
+ */
+ CodeGenPolicyExt *m_policyext;
+
+ /**
+ * Returns whether we can decode the given mimesource
+ */
+ static bool canDecode(const QMimeSource* mimeSource);
+
+ /**
+ * Reads from the config file the options state.
+ * Not in @ref readOptions as it needs to be read earlier than some
+ * of the other options, before some items are created.
+ */
+ void readOptionState();
+
+ /**
+ * Initialize Qt's global clipboard support for the application.
+ */
+ void initClip();
+
+ /**
+ * Initialize code generators at startup.
+ * Why is this important? Because IF we don't do this, then changes
+ * to the UML may not be synced with the saved code generation params
+ * for those languages which arent currently active.
+ */
+ void initSavedCodeGenerators();
+
+ /**
+ * The configuration object of the application.
+ */
+ KConfig* m_config;
+
+ /**
+ * View is the main widget which represents your working area.
+ * The View class should handle all events of the view widget.
+ * It is kept empty so you can create your view according to your
+ * application's needs by changing the view class.
+ */
+ UMLView* m_view;
+
+ /**
+ * doc represents your actual document and is created only once.
+ * It keeps information such as filename and does the loading and
+ * saving of your files.
+ */
+ UMLDoc* m_doc;
+
+ /**
+ * Listview shows the current open file.
+ */
+ UMLListView* m_listView;
+
+ /**
+ * The widget which shows the diagrams.
+ */
+ KDockWidget* m_mainDock;
+
+ /**
+ * Contains the UMLListView tree view.
+ */
+ KDockWidget* m_listDock;
+
+ /**
+ * Contains the documentation DocWindow widget.
+ */
+ KDockWidget* m_documentationDock;
+
+ /**
+ * Documentation window.
+ */
+ DocWindow* m_pDocWindow;
+
+ /** Refactoring assistant. */
+ RefactoringAssistant* m_refactoringAssist;
+
+ //KAction pointers to enable/disable actions
+ KAction* fileNew;
+ KAction* fileOpen;
+ KRecentFilesAction* fileOpenRecent;
+ KAction* fileSave;
+ KAction* fileSaveAs;
+ KAction* fileClose;
+ KAction* filePrint;
+ KAction* fileQuit;
+ KAction* fileExportDocbook;
+ KAction* fileExportXhtml;
+
+ KAction* editCut;
+ KAction* editCopy;
+ KAction* editPaste;
+ KAction* editUndo;
+ KAction* editRedo;
+ KAction* selectAll;
+ KAction* preferences;
+
+ KActionMenu* newDiagram;
+ KAction* classDiagram;
+ KAction* sequenceDiagram;
+ KAction* collaborationDiagram;
+ KAction* useCaseDiagram;
+ KAction* stateDiagram;
+ KAction* activityDiagram;
+ KAction* componentDiagram;
+ KAction* deploymentDiagram;
+ KAction* entityRelationshipDiagram;
+ KAction* viewClearDiagram;
+
+ KToggleAction* viewSnapToGrid;
+ KToggleAction* viewShowGrid;
+ KAction* viewExportImage;
+ KAction* viewExportImageAll;
+ KAction* viewProperties;
+
+ KAction* zoom100Action;
+ KPlayerPopupSliderAction* zoomAction;
+
+ KAction* genAll;
+ KAction* genWizard;
+ KAction* importClasses;
+ KAction* classWizard;
+ KAction* deleteSelectedWidget;
+ KAction* deleteDiagram;
+#ifdef HAVE_DOT
+ KAction* autolayout;
+#endif
+
+ KAction* changeTabLeft;
+ KAction* changeTabRight;
+ KAction* moveTabLeft;
+ KAction* moveTabRight;
+ KToolBarButton* m_newSessionButton;
+ KPopupMenu* m_diagramMenu;
+ QToolButton* m_closeDiagramButton;
+ KToggleAction* viewToolBar;
+ KToggleAction* viewStatusBar;
+ WorkToolBar* toolsbar;
+ QTimer* m_clipTimer;
+ QTimer* m_copyTimer;
+ AlignToolBar* m_alignToolBar;
+
+ KStatusBarLabel* m_statusLabel;
+
+ /**
+ * True if the application is opening an existing document
+ */
+ bool m_loading;
+
+ /**
+ * Shows, and is parent of, all the UMLViews (diagrams)
+ * if tabbed diagrams are not enabled.
+ */
+ QWidgetStack* m_viewStack;
+
+ /**
+ * Shows, and is parent of, all the UMLViews (diagrams)
+ * if tabbed diagrams are enabled.
+ */
+ KTabWidget* m_tabWidget;
+
+ /**
+ * Default mime type to use for image export.
+ */
+ QString m_imageMimeType;
+
+ /**
+ * the global UML settings dialog
+ */
+ SettingsDlg* m_dlg;
+
+ /**
+ * The UMLViewImageExporterAll used to export all the views.
+ */
+ UMLViewImageExporterAll* m_imageExporterAll;
+
+ /**
+ * The running XHTML documentation generator. null when no generation is
+ * running
+ */
+ XhtmlGenerator* m_xhtmlGenerator;
+
+signals:
+
+ /**
+ * Emitted when a cut operation is successful.
+ */
+ void sigCutSuccessful();
+};
+
+#endif // UML_H
diff --git a/umbrello/umbrello/umlassociationlist.h b/umbrello/umbrello/umlassociationlist.h
new file mode 100644
index 00000000..55810c7d
--- /dev/null
+++ b/umbrello/umbrello/umlassociationlist.h
@@ -0,0 +1,23 @@
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * copyright (C) 2004-2007 *
+ * Umbrello UML Modeller Authors <uml-devel@uml.sf.net> *
+ ***************************************************************************/
+
+#ifndef UMLASSOCIATIONLIST_H
+#define UMLASSOCIATIONLIST_H
+
+#include <qptrlist.h>
+
+// forward declaration
+class UMLAssociation;
+
+typedef QPtrList<UMLAssociation> UMLAssociationList;
+typedef QPtrListIterator<UMLAssociation> UMLAssociationListIt;
+
+#endif
diff --git a/umbrello/umbrello/umlattributelist.cpp b/umbrello/umbrello/umlattributelist.cpp
new file mode 100644
index 00000000..f335b7e7
--- /dev/null
+++ b/umbrello/umbrello/umlattributelist.cpp
@@ -0,0 +1,39 @@
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * copyright (C) 2004-2006 *
+ * Umbrello UML Modeller Authors <uml-devel@uml.sf.net> *
+ ***************************************************************************/
+
+#include "umlattributelist.h"
+#include "attribute.h"
+#include <kdebug.h>
+#include <klocale.h>
+
+void UMLAttributeList::copyInto(UMLAttributeList *rhs) const {
+ // Don't copy yourself.
+ if (rhs == this) return;
+
+ rhs->clear();
+
+ // Suffering from const; we shall not modify our object.
+ UMLAttributeList *tmp = new UMLAttributeList(*this);
+
+ UMLAttribute *item;
+ for (item = tmp->first(); item; item = tmp->next() )
+ {
+ rhs->append((UMLAttribute*)item->clone());
+ }
+ delete tmp;
+}
+
+
+UMLAttributeList* UMLAttributeList::clone() const {
+ UMLAttributeList *clone = new UMLAttributeList();
+ copyInto(clone);
+ return clone;
+}
diff --git a/umbrello/umbrello/umlattributelist.h b/umbrello/umbrello/umlattributelist.h
new file mode 100644
index 00000000..6dd25db2
--- /dev/null
+++ b/umbrello/umbrello/umlattributelist.h
@@ -0,0 +1,43 @@
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * copyright (C) 2004-2006 *
+ * Umbrello UML Modeller Authors <uml-devel@uml.sf.net> *
+ ***************************************************************************/
+
+#ifndef UMLATTRIBUTELIST_H
+#define UMLATTRIBUTELIST_H
+
+#include <qptrlist.h>
+
+#include "attribute.h"
+
+//typedef QPtrList<UMLAttribute> UMLAttributeList;
+typedef QPtrListIterator<UMLAttribute> UMLAttributeListIt;
+
+/**
+ * This sub-class adds copyInto and clone to the QPtrList<UMLAttribute>
+ * base class.
+ */
+class UMLAttributeList : public QPtrList<UMLAttribute>
+{
+public:
+
+ /**
+ * Copy the internal presentation of this object into the new
+ * object.
+ */
+ virtual void copyInto (UMLAttributeList *rhs) const;
+
+ /**
+ * Make a clone of this object.
+ */
+ virtual UMLAttributeList* clone() const;
+};
+
+
+#endif
diff --git a/umbrello/umbrello/umlcanvasobject.cpp b/umbrello/umbrello/umlcanvasobject.cpp
new file mode 100644
index 00000000..4b002228
--- /dev/null
+++ b/umbrello/umbrello/umlcanvasobject.cpp
@@ -0,0 +1,322 @@
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * copyright (C) 2003-2007 *
+ * Umbrello UML Modeller Authors <uml-devel@uml.sf.net> *
+ ***************************************************************************/
+
+// own header
+#include "umlcanvasobject.h"
+
+// qt/kde includes
+#include <kdebug.h>
+#include <klocale.h>
+
+// local includes
+#include "uml.h"
+#include "umldoc.h"
+#include "classifier.h"
+#include "association.h"
+#include "attribute.h"
+#include "operation.h"
+#include "template.h"
+#include "stereotype.h"
+#include "clipboard/idchangelog.h"
+
+UMLCanvasObject::UMLCanvasObject(const QString & name, Uml::IDType id)
+ : UMLObject(name, id)
+{
+ init();
+}
+
+UMLCanvasObject::~UMLCanvasObject() {
+ //removeAllAssociations();
+ /* No! This is way too late to do that.
+ It should have been called explicitly before destructing the
+ UMLCanvasObject.
+ Here is an example crash that happens if we rely on
+ removeAllAssociations() at this point:
+#4 0x415aac7f in __dynamic_cast () from /usr/lib/libstdc++.so.5
+#5 0x081acdbd in UMLCanvasObject::removeAllAssociations() (this=0x89e5b08)
+ at umlcanvasobject.cpp:83
+#6 0x081ac9fa in ~UMLCanvasObject (this=0x89e5b08) at umlcanvasobject.cpp:29
+#7 0x08193ffc in ~UMLPackage (this=0x89e5b08) at package.cpp:35
+#8 0x0813cbf6 in ~UMLClassifier (this=0x89e5b08) at classifier.cpp:40
+#9 0x081af3a6 in UMLDoc::closeDocument() (this=0x8468b10) at umldoc.cpp:284
+ */
+ if (associations())
+ kDebug() << "UMLCanvasObject destructor: FIXME: there are still associations()" << endl;
+}
+
+UMLAssociationList UMLCanvasObject::getSpecificAssocs(Uml::Association_Type assocType) {
+ UMLAssociationList list;
+ UMLObject *o;
+ for (UMLObjectListIt oit(m_List); (o = oit.current()) != NULL; ++oit) {
+ if (o->getBaseType() != Uml::ot_Association)
+ continue;
+ UMLAssociation *a = static_cast<UMLAssociation*>(o);
+ if (a->getAssocType() == assocType)
+ list.append(a);
+ }
+ return list;
+}
+
+bool UMLCanvasObject::addAssociationEnd(UMLAssociation* assoc) {
+ // add association only if not already present in list
+ if(!hasAssociation(assoc))
+ {
+ m_List.append( assoc );
+
+ // Don't emit signals during load from XMI
+ UMLObject::emitModified();
+ emit sigAssociationEndAdded(assoc);
+ return true;
+ }
+ return false;
+}
+
+bool UMLCanvasObject::hasAssociation(UMLAssociation* assoc) {
+ if(m_List.containsRef(assoc) > 0)
+ return true;
+ return false;
+}
+
+int UMLCanvasObject::removeAssociationEnd(UMLAssociation * assoc) {
+ if(!hasAssociation(assoc) || !m_List.remove(assoc)) {
+ kWarning() << "UMLCanvasObject::removeAssociation: "
+ << "can't find given assoc in list" << endl;
+ return -1;
+ }
+ UMLObject::emitModified();
+ emit sigAssociationEndRemoved(assoc);
+ return m_List.count();
+}
+
+void UMLCanvasObject::removeAllAssociationEnds() {
+ UMLObject *o;
+ for (UMLObjectListIt oit(m_List); (o = oit.current()) != NULL; ) {
+ if (o->getBaseType() != Uml::ot_Association) {
+ ++oit;
+ continue;
+ }
+ UMLAssociation *assoc = static_cast<UMLAssociation*>(o);
+ //umldoc->slotRemoveUMLObject(assoc);
+ UMLObject* objA = assoc->getObject(Uml::A);
+ UMLObject* objB = assoc->getObject(Uml::B);
+ UMLCanvasObject *roleAObj = dynamic_cast<UMLCanvasObject*>(objA);
+ if (roleAObj) {
+ roleAObj->removeAssociationEnd(assoc);
+ } else if (objA)
+ kDebug() << "UMLCanvasObject::removeAllAssociations(" << m_Name
+ << "): objA " << objA->getName() << " is not a UMLCanvasObject"
+ << endl;
+ else
+ kDebug() << "UMLCanvasObject::removeAllAssociations(" << m_Name
+ << "): objA is NULL" << endl;
+ UMLCanvasObject *roleBObj = dynamic_cast<UMLCanvasObject*>(objB);
+ if (roleBObj) {
+ roleBObj->removeAssociationEnd(assoc);
+ } else if (objB)
+ kDebug() << "UMLCanvasObject::removeAllAssociations(" << m_Name
+ << "): objB " << objB->getName() << " is not a UMLCanvasObject"
+ << endl;
+ else
+ kDebug() << "UMLCanvasObject::removeAllAssociations(" << m_Name
+ << "): objB is NULL" << endl;
+ m_List.remove(assoc);
+ }
+}
+
+void UMLCanvasObject::removeAllChildObjects() {
+ removeAllAssociationEnds();
+ m_List.setAutoDelete(true);
+ m_List.clear();
+ m_List.setAutoDelete(false);
+}
+
+QString UMLCanvasObject::uniqChildName( const Uml::Object_Type type,
+ const QString &prefix /* = QString() */ ) {
+ QString currentName = prefix;
+ if (currentName.isEmpty()) {
+ switch (type) {
+ case Uml::ot_Association:
+ currentName = i18n("new_association");
+ break;
+ case Uml::ot_Attribute:
+ currentName = i18n("new_attribute");
+ break;
+ case Uml::ot_Template:
+ currentName = i18n("new_template");
+ break;
+ case Uml::ot_Operation:
+ currentName = i18n("new_operation");
+ break;
+ case Uml::ot_EnumLiteral:
+ currentName = i18n("new_literal");
+ break;
+ case Uml::ot_EntityAttribute:
+ currentName = i18n("new_field");
+ break;
+ default:
+ kWarning() << "uniqChildName() called for unknown child type " << type << endl;
+ return "ERROR_in_UMLCanvasObject_uniqChildName";
+ }
+ }
+
+ QString name = currentName;
+ for (int number = 1; findChildObject(name); ++number) {
+ name = currentName + '_' + QString::number(number);
+ }
+ return name;
+}
+
+UMLObject * UMLCanvasObject::findChildObject(const QString &n, Uml::Object_Type t) {
+ const bool caseSensitive = UMLApp::app()->activeLanguageIsCaseSensitive();
+ UMLObject *obj;
+ for (UMLObjectListIt oit(m_List); (obj = oit.current()) != NULL; ++oit) {
+ if (t != Uml::ot_UMLObject && obj->getBaseType() != t)
+ continue;
+ if (caseSensitive) {
+ if (obj->getName() == n)
+ return obj;
+ } else if (obj->getName().lower() == n.lower()) {
+ return obj;
+ }
+ }
+ return NULL;
+}
+
+UMLObject* UMLCanvasObject::findChildObjectById(Uml::IDType id, bool /* considerAncestors */) {
+ UMLObject *o;
+ for (UMLObjectListIt oit(m_List); (o = oit.current()) != NULL; ++oit) {
+ if (o->getID() == id)
+ return o;
+ }
+ return 0;
+}
+
+void UMLCanvasObject::init() {
+ m_List.setAutoDelete(false);
+}
+
+bool UMLCanvasObject::operator==(UMLCanvasObject& rhs) {
+ if (this == &rhs) {
+ return true;
+ }
+ if ( !UMLObject::operator==(rhs) ) {
+ return false;
+ }
+ if ( m_List.count() != rhs.m_List.count() ) {
+ return false;
+ }
+ if ( &m_List != &(rhs.m_List) ) {
+ return false;
+ }
+ return true;
+}
+
+void UMLCanvasObject::copyInto(UMLCanvasObject *rhs) const
+{
+ UMLObject::copyInto(rhs);
+
+ // TODO Associations are not copied at the moment. This because
+ // the duplicate function (on umlwidgets) do not copy the associations.
+ //
+ //rhs->m_List = m_List;
+}
+
+int UMLCanvasObject::associations() {
+ int count = 0;
+ UMLObject *obj;
+ for (UMLObjectListIt oit(m_List); (obj = oit.current()) != NULL; ++oit) {
+ if (obj->getBaseType() == Uml::ot_Association)
+ count++;
+ }
+ return count;
+}
+
+UMLAssociationList UMLCanvasObject::getAssociations() {
+ UMLAssociationList assocs;
+ UMLObject *o;
+ for (UMLObjectListIt oit(m_List); (o = oit.current()) != NULL; ++oit) {
+ if (o->getBaseType() != Uml::ot_Association)
+ continue;
+ UMLAssociation *assoc = static_cast<UMLAssociation*>(o);
+ assocs.append(assoc);
+ }
+ return assocs;
+}
+
+UMLClassifierList UMLCanvasObject::getSuperClasses() {
+ UMLClassifierList list;
+ UMLAssociationList assocs = getAssociations();
+ for (UMLAssociation* a = assocs.first(); a; a = assocs.next()) {
+ if ((a->getAssocType() != Uml::at_Generalization &&
+ a->getAssocType() != Uml::at_Realization) ||
+ a->getObjectId(Uml::A) != getID() )
+ continue;
+ UMLClassifier *c = dynamic_cast<UMLClassifier*>(a->getObject(Uml::B));
+ if (c)
+ list.append(c);
+ else
+ kDebug() << "UMLCanvasObject::getSuperClasses(" << m_Name
+ << "): generalization's other end is not a "
+ << "UMLClassifier (id= " << ID2STR(a->getObjectId(Uml::B)) << ")"
+ << endl;
+ }
+ return list;
+}
+
+UMLClassifierList UMLCanvasObject::getSubClasses() {
+ UMLClassifierList list;
+ UMLAssociationList assocs = getAssociations();
+ for (UMLAssociation* a = assocs.first(); a; a = assocs.next()) {
+ if ((a->getAssocType() != Uml::at_Generalization &&
+ a->getAssocType() != Uml::at_Realization) ||
+ a->getObjectId(Uml::B) != getID() )
+ continue;
+ UMLClassifier *c = dynamic_cast<UMLClassifier*>(a->getObject(Uml::A));
+ if (c)
+ list.append(c);
+ else
+ kDebug() << "UMLCanvasObject::getSubClasses: specialization's"
+ << " other end is not a UMLClassifier"
+ << " (id=" << ID2STR(a->getObjectId(Uml::A)) << ")" << endl;
+ }
+ return list;
+}
+
+UMLAssociationList UMLCanvasObject::getRealizations() {
+ return getSpecificAssocs(Uml::at_Realization);
+}
+
+UMLAssociationList UMLCanvasObject::getAggregations() {
+ return getSpecificAssocs(Uml::at_Aggregation);
+}
+
+UMLAssociationList UMLCanvasObject::getCompositions() {
+ return getSpecificAssocs(Uml::at_Composition);
+}
+
+UMLAssociationList UMLCanvasObject::getRelationships() {
+ return getSpecificAssocs(Uml::at_Relationship);
+}
+
+bool UMLCanvasObject::resolveRef() {
+ bool overallSuccess = UMLObject::resolveRef();
+ for (UMLObjectListIt ait(m_List); ait.current(); ++ait) {
+ UMLObject *obj = ait.current();
+ if (! obj->resolveRef()) {
+ m_List.remove(obj);
+ overallSuccess = false;
+ }
+ }
+ return overallSuccess;
+}
+
+#include "umlcanvasobject.moc"
+
diff --git a/umbrello/umbrello/umlcanvasobject.h b/umbrello/umbrello/umlcanvasobject.h
new file mode 100644
index 00000000..626b9fe9
--- /dev/null
+++ b/umbrello/umbrello/umlcanvasobject.h
@@ -0,0 +1,249 @@
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * copyright (C) 2002-2007 *
+ * Umbrello UML Modeller Authors <uml-devel@uml.sf.net> *
+ ***************************************************************************/
+
+#ifndef CANVASOBJECT_H
+#define CANVASOBJECT_H
+
+#include "umlobject.h"
+#include "umlobjectlist.h"
+#include "umlclassifierlist.h"
+#include "umlassociationlist.h"
+
+
+/**
+ * This class contains the non-graphical information required for UMLObjects
+ * which appear as moveable widgets on the canvas.
+ *
+ * This class inherits from @ref UMLObject which contains most of the
+ * information.
+ * It is not instantiated itself, it's just used as a super class for
+ * actual model objects.
+ *
+ * @short Non-graphical information for a UMLCanvasObject.
+ * @author Jonathan Riddell
+ * @see UMLObject
+ * Bugs and comments to uml-devel@lists.sf.net or http://bugs.kde.org
+ */
+
+class UMLCanvasObject : public UMLObject {
+ Q_OBJECT
+public:
+ /**
+ * Sets up a UMLCanvasObject.
+ *
+ * @param name The name of the Concept.
+ * @param id The unique id of the Concept.
+ */
+ explicit UMLCanvasObject(const QString & name = "", Uml::IDType id = Uml::id_None);
+
+ /**
+ * Standard deconstructor.
+ */
+ virtual ~UMLCanvasObject();
+
+ /**
+ * Overloaded '==' operator
+ */
+ virtual bool operator==(UMLCanvasObject& rhs);
+
+ /**
+ * Copy the internal presentation of this object into the new
+ * object.
+ */
+ virtual void copyInto(UMLCanvasObject *rhs) const;
+
+ // The abstract method UMLObject::clone() is implemented
+ // in the classes inheriting from UMLCanvasObject.
+
+ /**
+ * Adds an association end to m_List.
+ *
+ * @param assoc The association to add.
+ * @todo change param type to UMLRole
+ */
+ bool addAssociationEnd(UMLAssociation* assoc);
+
+ /**
+ * Determine if this canvasobject has the given association.
+ *
+ * @param assoc The association to check.
+ */
+ bool hasAssociation(UMLAssociation* assoc);
+
+ /**
+ * Remove an association end from the CanvasObject.
+ *
+ * @param assoc The association to remove.
+ * @todo change param type to UMLRole
+ */
+ int removeAssociationEnd(UMLAssociation *assoc);
+
+ /**
+ * Remove all association ends from the CanvasObject.
+ */
+ void removeAllAssociationEnds();
+
+ /**
+ * Returns the number of associations for the CanvasObject.
+ * This is the sum of the aggregations and compositions.
+ *
+ * @return The number of associations for the Concept.
+ */
+ int associations();
+
+ /**
+ * Return the list of associations for the CanvasObject.
+ *
+ * @return The list of associations for the CanvasObject.
+ */
+ UMLAssociationList getAssociations();
+
+ /**
+ * Return the subset of m_List that matches the given type.
+ *
+ * @param assocType The Association_Type to match.
+ * @return The list of associations that match assocType.
+ */
+ UMLAssociationList getSpecificAssocs(Uml::Association_Type assocType);
+
+ /**
+ * Return a list of the superclasses of this concept.
+ * TODO: This overlaps with UMLClassifier::findSuperClassConcepts(),
+ * see if we can merge the two.
+ *
+ * @return The list of superclasses for the concept.
+ */
+ UMLClassifierList getSuperClasses();
+
+ /**
+ * Return a list of the classes that inherit from this concept.
+ * TODO: This overlaps with UMLClassifier::findSubClassConcepts(),
+ * see if we can merge the two.
+ *
+ * @return The list of classes inheriting from the concept.
+ */
+ UMLClassifierList getSubClasses();
+
+ /**
+ * Shorthand for getSpecificAssocs(Uml::at_Realization)
+ *
+ * @return The list of realizations for the Concept.
+ */
+ virtual UMLAssociationList getRealizations();
+
+ /**
+ * Shorthand for getSpecificAssocs(Uml::at_Aggregation)
+ *
+ * @return The list of aggregations for the Concept.
+ */
+ UMLAssociationList getAggregations();
+
+ /**
+ * Shorthand for getSpecificAssocs(Uml::at_Composition)
+ *
+ * @return The list of compositions for the Concept.
+ */
+ UMLAssociationList getCompositions();
+
+ /**
+ * Shorthand for getSpecificAssocs(Uml::at_Relationship)
+ *
+ * @return The list of relationships for the entity.
+ */
+ UMLAssociationList getRelationships();
+
+ /**
+ * Find a child object with the given name.
+ *
+ * @param n The name of the object to find.
+ * @param t The type to find (optional.) If not given then
+ * any object type will match.
+ * @return Pointer to the object found; NULL if none found.
+ */
+ virtual UMLObject *findChildObject(const QString &n, Uml::Object_Type t = Uml::ot_UMLObject);
+
+ /**
+ * Find an association.
+ *
+ * @param id The id of the object to find.
+ * @param considerAncestors boolean switch to consider ancestors while searching
+ * @return Pointer to the object found (NULL if not found.)
+ */
+ virtual UMLObject *findChildObjectById(Uml::IDType id, bool considerAncestors = false);
+
+ /**
+ * Returns a name for the new association, operation, template
+ * or attribute appended with a number if the default name is
+ * taken e.g. new_association, new_association_1 etc.
+ *
+ * @param type The object type for which to make a name.
+ * @param prefix Optional prefix to use for the name.
+ * If not given then uniqChildName() will choose the prefix
+ * internally based on the object type.
+ * @return Unique name string for the Object_Type given.
+ */
+ virtual QString uniqChildName(const Uml::Object_Type type,
+ const QString &prefix = QString());
+
+ virtual void removeAllChildObjects();
+
+ /**
+ * Return the list of subordinate items.
+ */
+ UMLObjectList subordinates() const {
+ return m_List;
+ }
+
+ /**
+ * Reimplementation of UMLObject method.
+ */
+ virtual bool resolveRef();
+
+ // The abstract method UMLObject::saveToXMI() is implemented
+ // in the classes inheriting from UMLCanvasObject.
+
+protected:
+
+ /**
+ * List of all the associations in this object.
+ * Inheriting classes add more types of objects that are possible in this list;
+ * for example, UMLClassifier adds operations, attributes, and templates.
+ *
+ * @todo Only a pointer to the appropriate assocation end object
+ * (UMLRole) should be saved here, not the entire UMLAssociation.
+ *
+ */
+ UMLObjectList m_List;
+
+private:
+
+ /**
+ * Initialises key variables of the class.
+ */
+ void init();
+
+signals:
+
+ /**
+ * Emit when new association is added.
+ * @param assoc Pointer to the association which has been added.
+ */
+ void sigAssociationEndAdded(UMLAssociation * assoc);
+
+ /**
+ * Emit when new association is removed.
+ * @param assoc Pointer to the association which has been removed.
+ */
+ void sigAssociationEndRemoved(UMLAssociation * assoc);
+
+};
+
+#endif
diff --git a/umbrello/umbrello/umlclassifierlist.h b/umbrello/umbrello/umlclassifierlist.h
new file mode 100644
index 00000000..45bd2b62
--- /dev/null
+++ b/umbrello/umbrello/umlclassifierlist.h
@@ -0,0 +1,23 @@
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * copyright (C) 2003-2006 *
+ * Umbrello UML Modeller Authors <uml-devel@uml.sf.net> *
+ ***************************************************************************/
+
+#ifndef UMLCLASSIFIERLIST_H
+#define UMLCLASSIFIERLIST_H
+
+#include <qptrlist.h>
+
+// forward declaration
+class UMLClassifier;
+
+typedef QPtrList<UMLClassifier> UMLClassifierList;
+typedef QPtrListIterator<UMLClassifier> UMLClassifierListIt;
+
+#endif
diff --git a/umbrello/umbrello/umlclassifierlistitemlist.cpp b/umbrello/umbrello/umlclassifierlistitemlist.cpp
new file mode 100644
index 00000000..1672c0cb
--- /dev/null
+++ b/umbrello/umbrello/umlclassifierlistitemlist.cpp
@@ -0,0 +1,42 @@
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * copyright (C) 2004-2006 *
+ * Umbrello UML Modeller Authors <uml-devel@uml.sf.net> *
+ ***************************************************************************/
+
+#include "umlclassifierlistitemlist.h"
+#include "classifierlistitem.h"
+#include <kdebug.h>
+#include <klocale.h>
+
+void UMLClassifierListItemList::copyInto(UMLClassifierListItemList *rhs) const {
+ // Prevent copying to yourself. (Can cause serious injuries)
+ if (rhs == this) return;
+
+ rhs->clear();
+
+ // Suffering from const; we shall not modify our object.
+ UMLClassifierListItemList *tmp = new UMLClassifierListItemList(*this);
+
+ UMLClassifierListItem *item;
+ for (item = tmp->first(); item; item = tmp->next() )
+ {
+ rhs->append((UMLClassifierListItem*)item->clone());
+ }
+ delete tmp;
+}
+
+
+UMLClassifierListItemList* UMLClassifierListItemList::clone() const {
+ UMLClassifierListItemList *clone = new UMLClassifierListItemList();
+ copyInto(clone);
+ return clone;
+}
+
+
+
diff --git a/umbrello/umbrello/umlclassifierlistitemlist.h b/umbrello/umbrello/umlclassifierlistitemlist.h
new file mode 100644
index 00000000..675e8d5c
--- /dev/null
+++ b/umbrello/umbrello/umlclassifierlistitemlist.h
@@ -0,0 +1,45 @@
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * copyright (C) 2004-2006 *
+ * Umbrello UML Modeller Authors <uml-devel@uml.sf.net> *
+ ***************************************************************************/
+
+#ifndef UMLCLASSIFIERLISTITEMLIST_H
+#define UMLCLASSIFIERLISTITEMLIST_H
+
+#include <qptrlist.h>
+
+// forward declaration
+class UMLClassifierListItem;
+
+//typedef QPtrList<UMLClassifierListItem> UMLClassifierListItemList;
+typedef QPtrListIterator<UMLClassifierListItem> UMLClassifierListItemListIt;
+
+/**
+ * This sub-class adds copyInto and clone to the QPtrList<UMLClassifierListItem>
+ * base class.
+ */
+class UMLClassifierListItemList : public QPtrList<UMLClassifierListItem>
+{
+
+public:
+
+ /**
+ * Copy the internal presentation of this object into the new
+ * object.
+ */
+ virtual void copyInto (UMLClassifierListItemList *rhs) const;
+
+ /**
+ * Make a clone of this object.
+ */
+ virtual UMLClassifierListItemList* clone() const;
+
+};
+
+#endif
diff --git a/umbrello/umbrello/umldoc.cpp b/umbrello/umbrello/umldoc.cpp
new file mode 100644
index 00000000..9783cfbd
--- /dev/null
+++ b/umbrello/umbrello/umldoc.cpp
@@ -0,0 +1,2356 @@
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * copyright (C) 2002-2007 *
+ * Umbrello UML Modeller Authors <uml-devel@uml.sf.net> *
+ ***************************************************************************/
+
+// own header
+#include "umldoc.h"
+
+// qt includes
+#include <qpainter.h>
+#include <qtimer.h>
+#include <qdatetime.h>
+#include <qbuffer.h>
+#include <qdir.h>
+#include <qregexp.h>
+#include <qlabel.h>
+
+// kde includes
+#include <kapplication.h>
+#include <kdeversion.h>
+#include <kdebug.h>
+#include <kio/job.h>
+#include <kio/netaccess.h>
+#include <klocale.h>
+#include <kmessagebox.h>
+#include <kmimetype.h>
+#include <kprinter.h>
+#include <ktar.h>
+#include <ktempdir.h>
+#include <ktempfile.h>
+#include <kiconloader.h>
+#include <kinputdialog.h>
+#include <ktabwidget.h>
+
+// app includes
+#include "uniqueid.h"
+#include "associationwidget.h"
+#include "association.h"
+#include "package.h"
+#include "folder.h"
+#include "codegenerator.h"
+#include "classifier.h"
+#include "enum.h"
+#include "entity.h"
+#include "docwindow.h"
+#include "operation.h"
+#include "attribute.h"
+#include "template.h"
+#include "enumliteral.h"
+#include "entityattribute.h"
+#include "stereotype.h"
+#include "classifierlistitem.h"
+#include "object_factory.h"
+#include "import_rose.h"
+#include "model_utils.h"
+#include "widget_utils.h"
+#include "uml.h"
+#include "umllistview.h"
+#include "umllistviewitem.h"
+#include "umlview.h"
+#include "clipboard/idchangelog.h"
+#include "dialogs/classpropdlg.h"
+#include "codegenerators/codegenfactory.h"
+#include "listpopupmenu.h"
+#include "version.h"
+
+#define XMI_FILE_VERSION UMBRELLO_VERSION
+// For the moment, the XMI_FILE_VERSION changes with each UMBRELLO_VERSION.
+// But someday that may stabilize ;)
+
+using namespace Uml;
+
+static const uint undoMax = 30;
+
+UMLDoc::UMLDoc() {
+ m_Name = i18n("UML Model");
+ m_modelID = "m1";
+ m_count = 0;
+ m_pChangeLog = 0;
+ m_Doc = "";
+ m_modified = false;
+ m_bLoading = false;
+ m_bTypesAreResolved = false;
+ m_pAutoSaveTimer = 0;
+ m_nViewID = Uml::id_None;
+ m_pTabPopupMenu = 0;
+ m_pCurrentRoot = NULL;
+}
+
+void UMLDoc::init() {
+ // Initialize predefined folders.
+ const QString nativeRootName[Uml::N_MODELTYPES] = {
+ "Logical View",
+ "Use Case View",
+ "Component View",
+ "Deployment View",
+ "Entity Relationship Model"
+ };
+ const QString localizedRootName[Uml::N_MODELTYPES] = {
+ i18n("Logical View"),
+ i18n("Use Case View"),
+ i18n("Component View"),
+ i18n("Deployment View"),
+ i18n("Entity Relationship Model")
+ };
+ for (int i = 0; i < Uml::N_MODELTYPES; i++) {
+ m_root[i] = new UMLFolder(nativeRootName[i], STR2ID(nativeRootName[i]));
+ m_root[i]->setLocalName(localizedRootName[i]);
+ }
+ m_datatypeRoot = new UMLFolder("Datatypes", "Datatypes");
+ m_datatypeRoot->setLocalName(i18n("Datatypes"));
+ m_datatypeRoot->setUMLPackage(m_root[Uml::mt_Logical]);
+ m_root[Uml::mt_Logical]->addObject(m_datatypeRoot);
+
+ // Connect signals.
+ UMLApp * pApp = UMLApp::app();
+ connect(this, SIGNAL(sigDiagramCreated(Uml::IDType)), pApp, SLOT(slotUpdateViews()));
+ connect(this, SIGNAL(sigDiagramRemoved(Uml::IDType)), pApp, SLOT(slotUpdateViews()));
+ connect(this, SIGNAL(sigDiagramRenamed(Uml::IDType)), pApp, SLOT(slotUpdateViews()));
+ connect(this, SIGNAL( sigCurrentViewChanged() ), pApp, SLOT( slotCurrentViewChanged() ) );
+}
+
+UMLDoc::~UMLDoc() {
+ delete m_pChangeLog;
+ m_pChangeLog = 0;
+}
+
+void UMLDoc::addView(UMLView *view) {
+ if (view == NULL) {
+ kError() << "UMLDoc::addView: argument is NULL" << endl;
+ return;
+ }
+ UMLFolder *f = view->getFolder();
+ if (f == NULL) {
+ kError() << "UMLDoc::addView: view folder is not set" << endl;
+ return;
+ }
+ f->addView(view);
+
+ UMLApp * pApp = UMLApp::app();
+ if ( pApp->getListView() )
+ connect(this, SIGNAL(sigObjectRemoved(UMLObject *)), view, SLOT(slotObjectRemoved(UMLObject *)));
+
+ pApp->setCurrentView(view);
+ if ( ! m_bLoading ) {
+ view -> show();
+ emit sigDiagramChanged(view ->getType());
+ }
+
+ Settings::OptionState optionState = Settings::getOptionState();
+ KTabWidget* tabWidget = NULL;
+ if (optionState.generalState.tabdiagrams) {
+ tabWidget = UMLApp::app()->tabWidget();
+ tabWidget->addTab(view, view->getName());
+ tabWidget->setTabIconSet(view, Widget_Utils::iconSet(view->getType()));
+ }
+ pApp->setDiagramMenuItemsState(true);
+ pApp->slotUpdateViews();
+ pApp->setCurrentView(view);
+ if (tabWidget) {
+ tabWidget->showPage(view);
+ tabWidget->setCurrentPage(tabWidget->currentPageIndex());
+ }
+}
+
+void UMLDoc::removeView(UMLView *view , bool enforceCurrentView ) {
+ if(!view)
+ {
+ kError()<<"UMLDoc::removeView(UMLView *view) called with view = 0"<<endl;
+ return;
+ }
+ if ( UMLApp::app()->getListView() ) {
+ disconnect(this,SIGNAL(sigObjectRemoved(UMLObject *)), view,SLOT(slotObjectRemoved(UMLObject *)));
+ }
+ view->hide();
+ //remove all widgets before deleting view
+ view->removeAllWidgets();
+ UMLFolder *f = view->getFolder();
+ if (f == NULL) {
+ kError() << "UMLDoc::removeView(" << view->getName()
+ << "): view->getFolder() returns NULL" << endl;
+ return;
+ }
+ f->removeView(view);
+ UMLView *currentView = UMLApp::app()->getCurrentView();
+ if (currentView == view)
+ {
+ UMLApp::app()->setCurrentView(NULL);
+ UMLViewList viewList;
+ m_root[mt_Logical]->appendViews(viewList);
+ UMLView* firstView = viewList.first();
+ if (!firstView && enforceCurrentView) //create a diagram
+ {
+ createDiagram(m_root[mt_Logical], dt_Class, false);
+ kapp->processEvents();
+ m_root[mt_Logical]->appendViews(viewList);
+ firstView = viewList.first();
+ }
+
+ if ( firstView )
+ {
+ changeCurrentView( firstView->getID() );
+ UMLApp::app()->setDiagramMenuItemsState(true);
+ }
+ }
+}
+
+void UMLDoc::setURL(const KURL &url) {
+ m_doc_url = url;
+ return;
+}
+
+const KURL& UMLDoc::URL() const {
+ return m_doc_url;
+}
+
+bool UMLDoc::saveModified() {
+ bool completed(true);
+ if (!m_modified)
+ return completed;
+
+ UMLApp *win = UMLApp::app();
+ int want_save = KMessageBox::warningYesNoCancel(win, i18n("The current file has been modified.\nDo you want to save it?"), i18n("Warning"),KStdGuiItem::save(),KStdGuiItem::discard());
+ switch(want_save) {
+ case KMessageBox::Yes:
+ if (m_doc_url.fileName() == i18n("Untitled")) {
+ if (win->slotFileSaveAs()) {
+ closeDocument();
+ completed=true;
+ } else {
+ completed=false;
+ }
+ } else {
+ saveDocument(URL());
+ closeDocument();
+ completed=true;
+ }
+ break;
+
+ case KMessageBox::No:
+ setModified(false);
+ closeDocument();
+ completed=true;
+ break;
+
+ case KMessageBox::Cancel:
+ completed=false;
+ break;
+
+ default:
+ completed=false;
+ break;
+ }
+ return completed;
+}
+
+void UMLDoc::closeDocument() {
+ UMLApp::app()->setGenerator(Uml::pl_Reserved); // delete the codegen
+ m_Doc = "";
+ DocWindow* dw = UMLApp::app()->getDocWindow();
+ if (dw) {
+ dw->newDocumentation();
+ }
+
+ UMLListView *listView = UMLApp::app()->getListView();
+ if (listView) {
+ listView->init();
+ // store old setting - for restore of last setting
+ bool m_bLoading_old = m_bLoading;
+ m_bLoading = true; // This is to prevent document becoming modified.
+ // For reference, here is an example of a call sequence that would
+ // otherwise result in futile addToUndoStack() calls:
+ // removeAllViews() =>
+ // UMLView::removeAllAssociations() =>
+ // UMLView::removeAssoc() =>
+ // UMLDoc::setModified(true, true) =>
+ // addToUndoStack().
+ removeAllViews();
+ m_bLoading = m_bLoading_old;
+ // Remove all objects from the predefined folders.
+ // @fixme With advanced code generation enabled, this crashes.
+ UMLObject *obj;
+ for (int i = 0; i < Uml::N_MODELTYPES; i++)
+ m_root[i]->removeAllObjects();
+ // Restore the datatype folder, it has been deleted above.
+ m_datatypeRoot = new UMLFolder("Datatypes", "Datatypes");
+ m_datatypeRoot->setLocalName(i18n("Datatypes"));
+ m_datatypeRoot->setUMLPackage(m_root[Uml::mt_Logical]);
+ m_root[Uml::mt_Logical]->addObject(m_datatypeRoot);
+ listView->theDatatypeFolder()->setUMLObject(m_datatypeRoot);
+ /* Remove any stereotypes.
+ if (m_stereoList.count() > 0) {
+ UMLStereotype *s;
+ for (UMLStereotypeListIt sit(m_stereoList); (s = sit.current()) != 0; ++sit)
+ delete s;
+ m_stereoList.clear();
+ }
+ */
+ }
+ m_bTypesAreResolved = false;
+}
+
+bool UMLDoc::newDocument() {
+ closeDocument();
+ UMLApp::app()->setCurrentView(NULL);
+ m_doc_url.setFileName(i18n("Untitled"));
+ //see if we need to start with a new diagram
+ Settings::OptionState optionState = Settings::getOptionState();
+ Uml::Diagram_Type dt = optionState.generalState.diagram;
+ Uml::Model_Type mt = Model_Utils::convert_DT_MT(dt);
+ if (mt == Uml::N_MODELTYPES) { // don't allow no diagram
+ dt = Uml::dt_Class;
+ mt = Uml::mt_Logical;
+ }
+ createDiagram(m_root[mt], dt, false);
+
+ UMLApp::app()->initGenerator();
+ addDefaultDatatypes();
+ addDefaultStereotypes();
+
+ setModified(false);
+ initSaveTimer();
+
+ UMLApp::app()->enableUndo(false);
+ clearUndoStack();
+ addToUndoStack();
+
+ return true;
+}
+
+bool UMLDoc::openDocument(const KURL& url, const char* /*format =0*/) {
+ if(url.fileName().length() == 0) {
+ newDocument();
+ return false;
+ }
+
+ m_doc_url = url;
+ QDir d = url.path(1);
+ closeDocument();
+ // IMPORTANT: set m_bLoading to true
+ // _AFTER_ the call of UMLDoc::closeDocument()
+ // as it sets m_bLoading to false afer it was temporarily
+ // changed to true to block recording of changes in redo-buffer
+ m_bLoading = true;
+ QString tmpfile;
+ KIO::NetAccess::download( url, tmpfile, UMLApp::app() );
+ QFile file( tmpfile );
+ if ( !file.exists() ) {
+ KMessageBox::error(0, i18n("The file %1 does not exist.").arg(d.path()), i18n("Load Error"));
+ m_doc_url.setFileName(i18n("Untitled"));
+ m_bLoading = false;
+ newDocument();
+ return false;
+ }
+
+ // status of XMI loading
+ bool status = false;
+
+ // check if the xmi file is a compressed archive like tar.bzip2 or tar.gz
+ QString filetype = m_doc_url.fileName(true);
+ QString mimetype = "";
+ if (filetype.find(QRegExp("\\.tgz$")) != -1)
+ {
+ mimetype = "application/x-gzip";
+ } else if (filetype.find(QRegExp("\\.tar.bz2$")) != -1) {
+ mimetype = "application/x-bzip2";
+ }
+
+ if (mimetype.isEmpty() == false)
+ {
+ KTar archive(tmpfile, mimetype);
+ if (archive.open(IO_ReadOnly) == false)
+ {
+ KMessageBox::error(0, i18n("The file %1 seems to be corrupted.").arg(d.path()), i18n("Load Error"));
+ m_doc_url.setFileName(i18n("Untitled"));
+ m_bLoading = false;
+ newDocument();
+ return false;
+ }
+
+ // get the root directory and all entries in
+ const KArchiveDirectory * rootDir = archive.directory();
+ QStringList entries = rootDir->entries();
+ QString entryMimeType;
+ bool foundXMI = false;
+ QStringList::Iterator it;
+ QStringList::Iterator end(entries.end());
+
+ // now go through all entries till we find an xmi file
+ for (it = entries.begin(); it != end; ++it)
+ {
+ // only check files, we do not go in subdirectories
+ if (rootDir->entry(*it)->isFile() == true)
+ {
+ // we found a file, check the mimetype
+ entryMimeType = KMimeType::findByPath(*it, 0, true)->name();
+ if (entryMimeType == "application/x-uml")
+ {
+ foundXMI = true;
+ break;
+ }
+ }
+ }
+
+ // if we found an XMI file, we have to extract it to a temporary file
+ if (foundXMI == true)
+ {
+ KTempDir tmp_dir;
+ KArchiveEntry * entry;
+ KArchiveFile * fileEntry;
+
+ // try to cast the file entry in the archive to an archive entry
+ entry = const_cast<KArchiveEntry*>(rootDir->entry(*it));
+ if (entry == 0)
+ {
+ KMessageBox::error(0, i18n("There was no XMI file found in the compressed file %1.").arg(d.path()), i18n("Load Error"));
+ m_doc_url.setFileName(i18n("Untitled"));
+ m_bLoading = false;
+ newDocument();
+ return false;
+ }
+
+ // now try to cast the archive entry to a file entry, so that we can
+ // extract the file
+ fileEntry = dynamic_cast<KArchiveFile*>(entry);
+ if (fileEntry == 0)
+ {
+ KMessageBox::error(0, i18n("There was no XMI file found in the compressed file %1.").arg(d.path()), i18n("Load Error"));
+ m_doc_url.setFileName(i18n("Untitled"));
+ m_bLoading = false;
+ newDocument();
+ return false;
+ }
+
+ // now we can extract the file to the temporary directory
+ fileEntry->copyTo(tmp_dir.name());
+
+ // now open the extracted file for reading
+ QFile xmi_file(tmp_dir.name() + *it);
+ if( !xmi_file.open( IO_ReadOnly ) )
+ {
+ KMessageBox::error(0, i18n("There was a problem loading the extracted file: %1").arg(d.path()), i18n("Load Error"));
+ m_doc_url.setFileName(i18n("Untitled"));
+ m_bLoading = false;
+ newDocument();
+ return false;
+ }
+ status = loadFromXMI( xmi_file, ENC_UNKNOWN );
+
+ // close the extracted file and the temporary directory
+ xmi_file.close();
+ tmp_dir.unlink();
+
+ } else {
+ KMessageBox::error(0, i18n("There was no XMI file found in the compressed file %1.").arg(d.path()), i18n("Load Error"));
+ m_doc_url.setFileName(i18n("Untitled"));
+ m_bLoading = false;
+ newDocument();
+ return false;
+ }
+
+ archive.close();
+ } else {
+ // no, it seems to be an ordinary file
+ if( !file.open( IO_ReadOnly ) ) {
+ KMessageBox::error(0, i18n("There was a problem loading file: %1").arg(d.path()), i18n("Load Error"));
+ m_doc_url.setFileName(i18n("Untitled"));
+ m_bLoading = false;
+ newDocument();
+ return false;
+ }
+ if (filetype.endsWith(".mdl"))
+ status = Import_Rose::loadFromMDL(file);
+ else
+ status = loadFromXMI( file, ENC_UNKNOWN );
+ }
+
+ file.close();
+ KIO::NetAccess::removeTempFile( tmpfile );
+ if( !status )
+ {
+ KMessageBox::error(0, i18n("There was a problem loading file: %1").arg(d.path()), i18n("Load Error"));
+ m_bLoading = false;
+ newDocument();
+ return false;
+ }
+ setModified(false);
+ m_bLoading = false;
+ initSaveTimer();
+
+ UMLApp::app()->enableUndo(false);
+ clearUndoStack();
+ addToUndoStack();
+ // for compatibility
+ addDefaultStereotypes();
+
+ return true;
+}
+
+bool UMLDoc::saveDocument(const KURL& url, const char * /* format */) {
+ m_doc_url = url;
+ QDir d = m_doc_url.path(1);
+ QFile file;
+ bool uploaded = true;
+
+ // first, we have to find out which format to use
+ QString strFileName = url.path(-1);
+ QFileInfo fileInfo(strFileName);
+ QString fileExt = fileInfo.extension();
+ QString fileFormat = "xmi";
+ if (fileExt == "xmi" || fileExt == "bak.xmi")
+ {
+ fileFormat = "xmi";
+ } else if (fileExt == "xmi.tgz" || fileExt == "bak.xmi.tgz") {
+ fileFormat = "tgz";
+ } else if (fileExt == "xmi.tar.bz2" || fileExt == "bak.xmi.tar.bz2") {
+ fileFormat = "bz2";
+ } else {
+ fileFormat = "xmi";
+ }
+
+ initSaveTimer();
+
+ if (fileFormat == "tgz" || fileFormat == "bz2")
+ {
+ KTar * archive;
+ KTempFile tmp_tgz_file;
+
+ // first we have to check if we are saving to a local or remote file
+ if (url.isLocalFile())
+ {
+ if (fileFormat == "tgz") // check tgz or bzip2
+ {
+ archive = new KTar(d.path(), "application/x-gzip");
+ } else {
+ archive = new KTar(d.path(), "application/x-bzip2");
+ }
+ } else {
+ if (fileFormat == "tgz") // check tgz or bzip2
+ {
+ archive = new KTar(tmp_tgz_file.name(), "application/x-gzip");
+ } else {
+ archive = new KTar(tmp_tgz_file.name(), "application/x-bzip2");
+ }
+ }
+
+ // now check if we can write to the file
+ if (archive->open(IO_WriteOnly) == false)
+ {
+ KMessageBox::error(0, i18n("There was a problem saving file: %1").arg(d.path()), i18n("Save Error"));
+ return false;
+ }
+
+ // we have to create a temporary xmi file
+ // we will add this file later to the archive
+ KTempFile tmp_xmi_file;
+ file.setName(tmp_xmi_file.name());
+ if( !file.open( IO_WriteOnly ) ) {
+ KMessageBox::error(0, i18n("There was a problem saving file: %1").arg(d.path()), i18n("Save Error"));
+ return false;
+ }
+ saveToXMI(file); // save XMI to this file...
+ file.close(); // ...and close it
+
+ // now add this file to the archive, but without the extension
+ QString tmpQString = url.fileName();
+ if (fileFormat == "tgz")
+ {
+ tmpQString.replace(QRegExp("\\.tgz$"), "");
+ } else {
+ tmpQString.replace(QRegExp("\\.tar\\.bz2$"), "");
+ }
+ archive->addLocalFile(tmp_xmi_file.name(), tmpQString);
+ archive->close();
+
+#if KDE_IS_VERSION(3,4,89)
+ if (!archive->closeSucceeded())
+ {
+ KMessageBox::error(0, i18n("There was a problem saving file: %1").arg(d.path()), i18n("Save Error"));
+ return false;
+ }
+#endif
+ // now the xmi file was added to the archive, so we can delete it
+ tmp_xmi_file.close();
+ tmp_xmi_file.unlink();
+
+ // now we have to check, if we have to upload the file
+ if ( !url.isLocalFile() ) {
+ uploaded = KIO::NetAccess::upload( tmp_tgz_file.name(), m_doc_url,
+ UMLApp::app() );
+ }
+
+ // now the archive was written to disk (or remote) so we can delete the
+ // objects
+ tmp_tgz_file.close();
+ tmp_tgz_file.unlink();
+ delete archive;
+
+ } else {
+ // save as normal uncompressed XMI
+
+ KTempFile tmpfile; // we need this tmp file if we are writing to a remote file
+
+ // save in _any_ case to a temp file
+ // -> if something goes wrong during saveToXmi, the
+ // original content is preserved
+ // ( e.g. if umbrello dies in the middle of the document model parsing
+ // for saveToXMI due to some problems )
+ /// @TODO insert some checks in saveToXMI to detect a failed save attempt
+ file.setName( tmpfile.name() );
+
+ // lets open the file for writing
+ if( !file.open( IO_WriteOnly ) ) {
+ KMessageBox::error(0, i18n("There was a problem saving file: %1").arg(d.path()), i18n("Save Error"));
+ return false;
+ }
+ saveToXMI(file); // save the xmi stuff to it
+ file.close();
+ tmpfile.close();
+
+ // if it is a remote file, we have to upload the tmp file
+ if ( !url.isLocalFile() ) {
+ uploaded = KIO::NetAccess::upload( tmpfile.name(), m_doc_url, UMLApp::app() );
+ } else {
+ // now remove the original file
+ if ( KIO::NetAccess::file_move( tmpfile.name(), d.path(), -1, true ) == false ) {
+ KMessageBox::error(0, i18n("There was a problem saving file: %1").arg(d.path()), i18n("Save Error"));
+ m_doc_url.setFileName(i18n("Untitled"));
+ return false;
+ }
+ }
+ }
+ if( !uploaded )
+ {
+ KMessageBox::error(0, i18n("There was a problem uploading file: %1").arg(d.path()), i18n("Save Error"));
+ m_doc_url.setFileName(i18n("Untitled"));
+ }
+ setModified(false);
+ return uploaded;
+}
+
+void UMLDoc::setupSignals() {
+ WorkToolBar *tb = UMLApp::app() -> getWorkToolBar();
+
+
+ connect(this, SIGNAL(sigDiagramChanged(Uml::Diagram_Type)), tb, SLOT(slotCheckToolBar(Uml::Diagram_Type)));
+ //new signals below
+
+ return;
+}
+
+UMLView * UMLDoc::findView(Uml::IDType id) {
+ UMLView *v = NULL;
+ for (int i = 0; i < Uml::N_MODELTYPES; i++) {
+ v = m_root[i]->findView(id);
+ if (v)
+ break;
+ }
+ return v;
+}
+
+UMLView * UMLDoc::findView(Uml::Diagram_Type type, const QString &name,
+ bool searchAllScopes /* =false */) {
+ Uml::Model_Type mt = Model_Utils::convert_DT_MT(type);
+ return m_root[mt]->findView(type, name, searchAllScopes);
+}
+
+UMLObject* UMLDoc::findObjectById(Uml::IDType id) {
+ UMLObject *o = NULL;
+ for (int i = 0; i < Uml::N_MODELTYPES; i++) {
+ if (id == m_root[i]->getID())
+ return m_root[i];
+ o = m_root[i]->findObjectById(id);
+ if (o)
+ return o;
+ }
+ o = findStereotypeById(id);
+ return o;
+}
+
+UMLStereotype * UMLDoc::findStereotypeById(Uml::IDType id) {
+ for (UMLStereotype *s = m_stereoList.first(); s; s = m_stereoList.next() ) {
+ if (s->getID() == id)
+ return s;
+ }
+ return NULL;
+}
+
+UMLObject* UMLDoc::findUMLObject(const QString &name,
+ Uml::Object_Type type /* = ot_UMLObject */,
+ UMLObject *currentObj /* = NULL */) {
+ UMLObject *o = m_datatypeRoot->findObject(name);
+ if (o)
+ return o;
+ for (int i = 0; i < Uml::N_MODELTYPES; i++) {
+ UMLObjectList list = m_root[i]->containedObjects();
+ o = Model_Utils::findUMLObject(list, name, type, currentObj);
+ if (o)
+ return o;
+ if ((type == ot_UMLObject || type == ot_Folder) &&
+ name == m_root[i]->getName())
+ return m_root[i];
+ }
+ return NULL;
+}
+
+UMLClassifier* UMLDoc::findUMLClassifier(const QString &name) {
+ //this is used only by code generator so we don't need to look at Datatypes
+ UMLObject * obj = findUMLObject(name);
+ return dynamic_cast<UMLClassifier*>(obj);
+}
+
+/**
+ * Adds a UMLObject thats already created but doesn't change
+ * any ids or signal. Used by the list view. Use
+ * AddUMLObjectPaste if pasting.
+ */
+bool UMLDoc::addUMLObject(UMLObject* object) {
+ Object_Type ot = object->getBaseType();
+ if (ot == ot_Attribute || ot == ot_Operation || ot == ot_EnumLiteral
+ || ot == ot_EntityAttribute || ot == ot_Template || ot == ot_Stereotype) {
+ kDebug() << "UMLDoc::addUMLObject(" << object->getName()
+ << "): not adding type " << ot << endl;
+ return false;
+ }
+ UMLPackage *pkg = object->getUMLPackage();
+ if (pkg == NULL) {
+ pkg = currentRoot();
+ kDebug() << "UMLDoc::addUMLObject(" << object->getName()
+ << "): no parent package set, assuming " << pkg->getName() << endl;
+ object->setUMLPackage( pkg );
+ }
+ return pkg->addObject(object);
+}
+
+void UMLDoc::addStereotype(const UMLStereotype *s) {
+ if (! m_stereoList.contains(s))
+ m_stereoList.append(s);
+}
+
+void UMLDoc::removeStereotype(const UMLStereotype *s) {
+ if (m_stereoList.contains(s))
+ m_stereoList.remove(s);
+}
+
+void UMLDoc::writeToStatusBar(const QString &text) {
+ emit sigWriteToStatusBar(text);
+}
+
+// simple removal of an object
+void UMLDoc::slotRemoveUMLObject(UMLObject* object) {
+ //m_objectList.remove(object);
+ UMLPackage *pkg = object->getUMLPackage();
+ if (pkg == NULL) {
+ kError() << "UMLDoc::slotRemoveUMLObject(" << object->getName()
+ << "): parent package is not set !" << endl;
+ return;
+ }
+ pkg->removeObject(object);
+}
+
+bool UMLDoc::isUnique(const QString &name)
+{
+ UMLListView *listView = UMLApp::app()->getListView();
+ UMLListViewItem *currentItem = (UMLListViewItem*)listView->currentItem();
+ UMLListViewItem *parentItem = 0;
+
+ // check for current item, if its a package, then we do a check on that
+ // otherwise, if current item exists, find its parent and check if thats
+ // a package..
+ if(currentItem)
+ {
+ // its possible that the current item *is* a package, then just
+ // do check now
+ if (Model_Utils::typeIsContainer(currentItem->getType()))
+ return isUnique (name, (UMLPackage*) currentItem->getUMLObject());
+ parentItem = (UMLListViewItem*)currentItem->parent();
+ }
+
+ // item is in a package so do check only in that
+ if (parentItem != NULL && Model_Utils::typeIsContainer(parentItem->getType())) {
+ UMLPackage *parentPkg = static_cast<UMLPackage*>(parentItem->getUMLObject());
+ return isUnique(name, parentPkg);
+ }
+
+ kError() << "UMLDoc::isUnique(" << name << "): Not currently in a package"
+ << endl;
+ /* Check against all objects that _don't_ have a parent package.
+ for (UMLObjectListIt oit(m_objectList); oit.current(); ++oit) {
+ UMLObject *obj = oit.current();
+ if (obj->getUMLPackage() == NULL && obj->getName() == name)
+ return false;
+ }
+ */
+ return true;
+}
+
+bool UMLDoc::isUnique(const QString &name, UMLPackage *package)
+{
+ // if a package, then only do check in that
+ if (package)
+ return (package->findObject(name) == NULL);
+
+ // Not currently in a package: ERROR
+ kError() << "UMLDoc::isUnique(2)(" << name << "): Not currently in a package"
+ << endl;
+ /* Check against all objects that _don't_ have a parent package.
+ for (UMLObjectListIt oit(m_objectList); oit.current(); ++oit) {
+ UMLObject *obj = oit.current();
+ if (obj->getUMLPackage() == NULL && obj->getName() == name)
+ return false;
+ }
+ */
+ return true;
+}
+
+UMLStereotype* UMLDoc::findStereotype(const QString &name) {
+ UMLStereotype *s;
+ for (UMLStereotypeListIt it(m_stereoList); (s = it.current()) != NULL; ++it) {
+ if (s->getName() == name)
+ return s;
+ }
+ return NULL;
+}
+
+UMLStereotype* UMLDoc::findOrCreateStereotype(const QString &name) {
+ UMLStereotype *s = findStereotype(name);
+ if (s != NULL) {
+ return s;
+ }
+ s = new UMLStereotype(name, STR2ID(name));
+ addStereotype(s);
+ //emit modified();
+ return s;
+}
+
+void UMLDoc::removeAssociation (UMLAssociation * assoc, bool doSetModified /*=true*/) {
+ if(!assoc)
+ return;
+
+ // Remove the UMLAssociation from m_objectList.
+ UMLPackage *pkg = assoc->getUMLPackage();
+ if (pkg == NULL) {
+ kError() << "UMLDoc::removeAssociation(" << assoc->getName()
+ << "): parent package is not set !" << endl;
+ return;
+ }
+ pkg->removeObject(assoc);
+
+ if (doSetModified) // so we will save our document
+ setModified(true, false);
+}
+
+UMLAssociation * UMLDoc::findAssociation(Uml::Association_Type assocType,
+ const UMLObject *roleAObj,
+ const UMLObject *roleBObj,
+ bool *swap)
+{
+ UMLAssociationList assocs = getAssociations();
+ UMLAssociation *a, *ret = NULL;
+ for (a = assocs.first(); a; a = assocs.next()) {
+ if (a->getAssocType() != assocType)
+ continue;
+ if (a->getObject(Uml::A) == roleAObj && a->getObject(Uml::B) == roleBObj)
+ return a;
+ if (a->getObject(Uml::A) == roleBObj && a->getObject(Uml::B) == roleAObj) {
+ ret = a;
+ }
+ }
+ if (swap)
+ *swap = (ret != NULL);
+ return ret;
+}
+
+// create AND add an association. Used by refactoring assistant.
+UMLAssociation* UMLDoc::createUMLAssociation(UMLObject *a, UMLObject *b, Uml::Association_Type type)
+{
+ bool swap;
+ UMLAssociation *assoc = findAssociation(type, a, b, &swap);
+ if (assoc == NULL) {
+ assoc = new UMLAssociation(type, a, b );
+ addAssociation(assoc);
+ }
+ return assoc;
+}
+
+void UMLDoc::addAssociation(UMLAssociation *Assoc)
+{
+ if (Assoc == NULL)
+ return;
+
+ // First, check that this association has not already been added.
+ // This may happen when loading old XMI files where all the association
+ // information was taken from the <UML:AssocWidget> tag.
+ UMLAssociationList assocs = getAssociations();
+ for (UMLAssociationListIt ait(assocs); ait.current(); ++ait) {
+ UMLAssociation *a = ait.current();
+ // check if its already been added (shouldn't be the case right now
+ // as UMLAssociations only belong to one associationwidget at a time)
+ if (a == Assoc)
+ {
+ kDebug() << "UMLDoc::addAssociation: duplicate addition attempted"
+ << endl;
+ return;
+ }
+ }
+
+ // If we get here it's really a new association.
+
+ // Add the UMLAssociation at the owning UMLPackage.
+ UMLPackage *pkg = Assoc->getUMLPackage();
+ if (pkg == NULL) {
+ kError() << "UMLDoc::addAssociation(" << Assoc->getName()
+ << "): parent package is not set !" << endl;
+ return;
+ }
+ pkg->addObject(Assoc);
+
+ // I don't believe this appropriate, UMLAssociations ARENT UMLWidgets -b.t.
+ // emit sigObjectCreated(o);
+
+ setModified(true);
+}
+
+QString UMLDoc::uniqViewName(const Uml::Diagram_Type type) {
+ QString dname;
+ if(type == dt_UseCase)
+ dname = i18n("use case diagram");
+ else if(type == dt_Class)
+ dname = i18n("class diagram");
+ else if(type == dt_Sequence)
+ dname = i18n("sequence diagram");
+ else if(type == dt_Collaboration)
+ dname = i18n("collaboration diagram");
+ else if( type == dt_State )
+ dname = i18n( "state diagram" );
+ else if( type == dt_Activity )
+ dname = i18n( "activity diagram" );
+ else if( type == dt_Component )
+ dname = i18n( "component diagram" );
+ else if( type == dt_Deployment )
+ dname = i18n( "deployment diagram" );
+ else if( type == dt_EntityRelationship )
+ dname = i18n( "entity relationship diagram" );
+ else {
+ kWarning() << "uniqViewName() called with unknown diagram type" << endl;
+ }
+ QString name = dname;
+ for (int number = 0; findView(type, name, true); ++number,
+ name = dname + '_' + QString::number(number))
+ ;
+ return name;
+}
+
+bool UMLDoc::loading() const {
+ return m_bLoading;
+}
+
+void UMLDoc::setLoading(bool state /* = true */) {
+ m_bLoading = state;
+}
+
+UMLView* UMLDoc::createDiagram(UMLFolder *folder, Uml::Diagram_Type type, bool askForName /*= true */) {
+ bool ok = true;
+ QString name,
+ dname = uniqViewName(type);
+
+ while(true) {
+ if (askForName) {
+ name = KInputDialog::getText(i18n("Name"), i18n("Enter name:"), dname, &ok, (QWidget*)UMLApp::app());
+ } else {
+ name = dname;
+ }
+ if (!ok) {
+ break;
+ }
+ if (name.length() == 0) {
+ KMessageBox::error(0, i18n("That is an invalid name for a diagram."), i18n("Invalid Name"));
+ } else if(!findView(type, name)) {
+ UMLView* temp = new UMLView(folder);
+ temp -> setOptionState( Settings::getOptionState() );
+ temp->setName( name );
+ temp->setType( type );
+ temp->setID( UniqueID::gen() );
+ addView(temp);
+ emit sigDiagramCreated( temp->getID() );
+ setModified(true, false);
+ UMLApp::app()->enablePrint(true);
+ changeCurrentView( temp->getID() );
+ return temp;
+ } else {
+ KMessageBox::error(0, i18n("A diagram is already using that name."), i18n("Not a Unique Name"));
+ }
+ }//end while
+ return 0;
+}
+
+void UMLDoc::renameDiagram(Uml::IDType id) {
+ bool ok = false;
+
+ UMLView *temp = findView(id);
+ Diagram_Type type = temp->getType();
+
+ QString oldName= temp->getName();
+ while(true) {
+ QString name = KInputDialog::getText(i18n("Name"), i18n("Enter name:"), oldName, &ok, (QWidget*)UMLApp::app());
+
+ if(!ok)
+ break;
+ if(name.length() == 0)
+ KMessageBox::error(0, i18n("That is an invalid name for a diagram."), i18n("Invalid Name"));
+ else if(!findView(type, name)) {
+ temp->setName(name);
+
+ emit sigDiagramRenamed(id);
+ setModified(true);
+ break;
+ } else
+ KMessageBox::error(0, i18n("A diagram is already using that name."), i18n("Not a Unique Name"));
+ }
+}
+
+void UMLDoc::renameUMLObject(UMLObject *o) {
+ bool ok = false;
+ QString oldName= o->getName();
+ while(true) {
+ QString name = KInputDialog::getText(i18n("Name"), i18n("Enter name:"), oldName, &ok, (QWidget*)UMLApp::app());
+ if(!ok)
+ break;
+ if(name.length() == 0)
+ KMessageBox::error(0, i18n("That is an invalid name."), i18n("Invalid Name"));
+ else if (isUnique(name)) {
+ o->setName(name);
+ setModified(true);
+ break;
+ } else {
+ KMessageBox::error(0, i18n("That name is already being used."), i18n("Not a Unique Name"));
+ }
+ }
+ return;
+}
+
+void UMLDoc::renameChildUMLObject(UMLObject *o) {
+ bool ok = false;
+ UMLClassifier* p = dynamic_cast<UMLClassifier *>(o->parent());
+ if(!p) {
+ kDebug() << "Can't create object, no parent found" << endl;
+ return;
+ }
+
+ QString oldName= o->getName();
+ while(true) {
+ QString name = KInputDialog::getText(i18n("Name"), i18n("Enter name:"), oldName, &ok, (QWidget*)UMLApp::app());
+ if(!ok)
+ break;
+ if(name.length() == 0)
+ KMessageBox::error(0, i18n("That is an invalid name."), i18n("Invalid Name"));
+ else {
+ if (p->findChildObject(name) == NULL
+ || ((o->getBaseType() == Uml::ot_Operation) && KMessageBox::warningYesNo( kapp -> mainWidget() ,
+ i18n( "The name you entered was not unique.\nIs this what you wanted?" ),
+ i18n( "Name Not Unique"),i18n("Use Name"),i18n("Enter New Name")) == KMessageBox::Yes) ) {
+ o->setName(name);
+ setModified(true);
+ break;
+ } else {
+ KMessageBox::error(0, i18n("That name is already being used."), i18n("Not a Unique Name"));
+ }
+ }
+ }
+}
+
+void UMLDoc::changeCurrentView(Uml::IDType id) {
+ UMLApp* pApp = UMLApp::app();
+ UMLView* w = findView(id);
+ if (w) {
+ pApp->setCurrentView(w);
+ emit sigDiagramChanged(w->getType());
+ pApp->setDiagramMenuItemsState( true );
+ setModified(true);
+ }
+ emit sigCurrentViewChanged();
+}
+
+void UMLDoc::removeDiagram(Uml::IDType id) {
+ UMLApp::app()->getDocWindow()->updateDocumentation(true);
+ UMLView* umlview = findView(id);
+ if(!umlview)
+ {
+ kError()<<"Request to remove diagram " << ID2STR(id) << ": Diagram not found!"<<endl;
+ return;
+ }
+ if (KMessageBox::warningContinueCancel(0, i18n("Are you sure you want to delete diagram %1?").arg(umlview->getName()), i18n("Delete Diagram"),KGuiItem( i18n("&Delete"), "editdelete")) == KMessageBox::Continue) {
+ removeView(umlview);
+ emit sigDiagramRemoved(id);
+ setModified(true);
+ /* if (infoWidget->isVisible()) {
+ emit sigDiagramChanged(dt_Undefined);
+ UMLApp::app()->enablePrint(false);
+ }
+ */ //FIXME sort out all the KActions for when there's no diagram
+ //also remove the buttons from the WorkToolBar, then get rid of infowidget
+ }
+}
+
+UMLFolder *UMLDoc::currentRoot() {
+ UMLView *currentView = UMLApp::app()->getCurrentView();
+ if (currentView == NULL) {
+ if (m_pCurrentRoot)
+ return m_pCurrentRoot;
+ kError() << "UMLDoc::currentRoot: m_pCurrentRoot is NULL" << endl;
+ return NULL;
+ }
+ UMLFolder *f = currentView->getFolder();
+ while (f->getUMLPackage()) {
+ f = static_cast<UMLFolder*>(f->getUMLPackage());
+ }
+ return f;
+}
+
+void UMLDoc::setCurrentRoot(Uml::Model_Type rootType) {
+ m_pCurrentRoot = m_root[rootType];
+}
+
+void UMLDoc::removeUMLObject(UMLObject* umlobject) {
+ UMLApp::app()->getDocWindow()->updateDocumentation(true);
+ Object_Type type = umlobject->getBaseType();
+
+ umlobject->setUMLStereotype(NULL); // triggers possible cleanup of UMLStereotype
+ if (dynamic_cast<UMLClassifierListItem*>(umlobject)) {
+ UMLClassifier* parent = dynamic_cast<UMLClassifier*>(umlobject->parent());
+ if (parent == NULL) {
+ kError() << "UMLDoc::removeUMLObject: parent of umlobject is NULL"
+ << endl;
+ return;
+ }
+ if (type == ot_Operation) {
+ parent->removeOperation(static_cast<UMLOperation*>(umlobject));
+ } else if (type == ot_EnumLiteral) {
+ UMLEnum *e = static_cast<UMLEnum*>(parent);
+ e->removeEnumLiteral(static_cast<UMLEnumLiteral*>(umlobject));
+ } else if (type == ot_EntityAttribute) {
+ UMLEntity *ent = static_cast<UMLEntity*>(parent);
+ ent->removeEntityAttribute(static_cast<UMLClassifierListItem*>(umlobject));
+ } else {
+ UMLClassifier* pClass = dynamic_cast<UMLClassifier*>(parent);
+ if (pClass == NULL) {
+ kError() << "UMLDoc::removeUMLObject: parent of umlobject has "
+ << "unexpected type " << parent->getBaseType() << endl;
+ return;
+ }
+ if (type == ot_Attribute) {
+ pClass->removeAttribute(static_cast<UMLAttribute*>(umlobject));
+ } else if (type == ot_Template) {
+ pClass->removeTemplate(static_cast<UMLTemplate*>(umlobject));
+ } else {
+ kError() << "UMLDoc::removeUMLObject: umlobject has "
+ << "unexpected type " << type << endl;
+ }
+ }
+ } else {
+ if (type == ot_Association) {
+ UMLAssociation *a = (UMLAssociation *)umlobject;
+ removeAssociation(a, false); // don't call setModified here, it's done below
+ } else {
+ UMLPackage* pkg = umlobject->getUMLPackage();
+ if (pkg) {
+ pkg->removeObject(umlobject);
+ } else {
+ kError() << "UMLDoc::removeUMLObject(" << umlobject->getName()
+ << "): parent package is not set !" << endl;
+ }
+ }
+ emit sigObjectRemoved(umlobject);
+ }
+ setModified(true);
+}
+
+void UMLDoc::signalUMLObjectCreated(UMLObject * o) {
+ emit sigObjectCreated(o);
+ /* This is the wrong place to do:
+ setModified(true);
+ Instead, that should be done by the callers when object creation and all
+ its side effects (e.g. new widget in view, new list view item, etc.) is
+ finalized.
+ */
+}
+
+void UMLDoc::setName(const QString& name) {
+ m_Name = name;
+}
+
+QString UMLDoc::getName() const {
+ return m_Name;
+}
+
+Uml::IDType UMLDoc::getModelID() const {
+ return m_modelID;
+}
+
+void UMLDoc::saveToXMI(QIODevice& file) {
+ QDomDocument doc;
+
+ QDomProcessingInstruction xmlHeading =
+ doc.createProcessingInstruction("xml", "version=\"1.0\" encoding=\"UTF-8\"");
+ doc.appendChild(xmlHeading);
+
+ QDomElement root = doc.createElement( "XMI" );
+ root.setAttribute( "xmi.version", "1.2" );
+ QDateTime now = QDateTime::currentDateTime();
+ root.setAttribute( "timestamp", now.toString(Qt::ISODate));
+ root.setAttribute( "verified", "false");
+ root.setAttribute( "xmlns:UML", "http://schema.omg.org/spec/UML/1.3");
+ doc.appendChild( root );
+
+ QDomElement header = doc.createElement( "XMI.header" );
+ QDomElement meta = doc.createElement( "XMI.metamodel" );
+ meta.setAttribute( "xmi.name", "UML" );
+ meta.setAttribute( "xmi.version", "1.3" );
+ meta.setAttribute( "href", "UML.xml" );
+ header.appendChild( meta );
+
+ /**
+ * bugs.kde.org/56184 comment by M. Alanen 2004-12-19:
+ * " XMI.model requires xmi.version. (or leave the whole XMI.model out,
+ * it's not required) "
+ QDomElement model = doc.createElement( "XMI.model" );
+ QFile* qfile = dynamic_cast<QFile*>(&file);
+ if (qfile) {
+ QString modelName = qfile->name();
+ modelName = modelName.section('/', -1 );
+ modelName = modelName.section('.', 0, 0);
+ model.setAttribute( "xmi.name", modelName );
+ model.setAttribute( "href", qfile->name() );
+ }
+ */
+
+ QDomElement documentation = doc.createElement( "XMI.documentation" );
+
+ // If we consider it useful we might add user and contact details
+ // QDomElement owner = doc.createElement( "XMI.owner" );
+ // owner.appendChild( doc.createTextNode( "Jens Kruger" ) ); // Add a User
+ // documentation.appendChild( owner );
+
+ // QDomElement contact = doc.createElement( "XMI.contact" );
+ // contact.appendChild( doc.createTextNode( "je.krueger@web.de" ) ); // add a contact
+ // documentation.appendChild( contact );
+
+ QDomElement exporter = doc.createElement( "XMI.exporter" );
+ exporter.appendChild( doc.createTextNode( "umbrello uml modeller http://uml.sf.net" ) );
+ documentation.appendChild( exporter );
+
+ QDomElement exporterVersion = doc.createElement( "XMI.exporterVersion" );
+ exporterVersion.appendChild( doc.createTextNode( XMI_FILE_VERSION ) );
+ documentation.appendChild( exporterVersion );
+
+ // all files are now saved with correct Unicode encoding, we add this
+ // information to the header, so that the file will be loaded correctly
+ QDomElement exporterEncoding = doc.createElement( "XMI.exporterEncoding" );
+ exporterEncoding.appendChild( doc.createTextNode( "UnicodeUTF8" ) );
+ documentation.appendChild( exporterEncoding );
+
+ header.appendChild( documentation );
+
+ /**
+ * See comment on <XMI.model> above
+ header.appendChild( model );
+ */
+ header.appendChild( meta );
+ root.appendChild( header );
+
+ QDomElement content = doc.createElement( "XMI.content" );
+
+ QDomElement contentNS = doc.createElement( "UML:Namespace.contents" );
+
+ QDomElement objectsElement = doc.createElement( "UML:Model" );
+ objectsElement.setAttribute( "xmi.id", ID2STR(m_modelID) );
+ objectsElement.setAttribute( "name", m_Name );
+ objectsElement.setAttribute( "isSpecification", "false" );
+ objectsElement.setAttribute( "isAbstract", "false" );
+ objectsElement.setAttribute( "isRoot", "false" );
+ objectsElement.setAttribute( "isLeaf", "false" );
+
+ QDomElement ownedNS = doc.createElement( "UML:Namespace.ownedElement" );
+
+ // Save stereotypes and toplevel datatypes first so that upon loading
+ // they are known first.
+ // There is a bug causing duplication of the same stereotype in m_stereoList.
+ // As a workaround, we use a string list to memorize which stereotype has been saved.
+ QStringList stereoNames;
+ QValueList<Uml::IDType> stereoIDs;
+ for (UMLStereotype *s = m_stereoList.first(); s; s = m_stereoList.next() ) {
+ QString stName = s->getName();
+ Uml::IDType stID = s->getID();
+ if (!stereoNames.contains(stName) && !stereoIDs.contains(stID)) {
+ s->saveToXMI(doc, ownedNS);
+ stereoNames.append(stName);
+ stereoIDs.append(stID);
+ } else {
+ kDebug() << "UMLDoc::saveToXMI: encountered duplicated stereotype "
+ << stName << " (id " << ID2STR(stID) << "), see bug 144924" << endl;
+ }
+ }
+ for (int i = 0; i < Uml::N_MODELTYPES; i++) {
+ m_root[i]->saveToXMI(doc, ownedNS);
+ }
+
+ objectsElement.appendChild( ownedNS );
+
+ content.appendChild( objectsElement );
+
+ root.appendChild( content );
+
+ // Save the XMI extensions: docsettings, diagrams, listview, and codegeneration.
+ QDomElement extensions = doc.createElement( "XMI.extensions" );
+ extensions.setAttribute( "xmi.extender", "umbrello" );
+
+ QDomElement docElement = doc.createElement( "docsettings" );
+ Uml::IDType viewID = Uml::id_None;
+ UMLView *currentView = UMLApp::app()->getCurrentView();
+ if (currentView)
+ viewID = currentView->getID();
+ docElement.setAttribute( "viewid", ID2STR(viewID) );
+ docElement.setAttribute( "documentation", m_Doc );
+ docElement.setAttribute( "uniqueid", ID2STR(UniqueID::get()) );
+ extensions.appendChild( docElement );
+
+ // save listview
+ UMLApp::app()->getListView()->saveToXMI(doc, extensions);
+
+ // save code generator
+ CodeGenerator *codegen = UMLApp::app()->getGenerator();
+ if (codegen) {
+ QDomElement codeGenElement = doc.createElement( "codegeneration" );
+ codegen->saveToXMI( doc, codeGenElement );
+ extensions.appendChild( codeGenElement );
+ }
+
+ root.appendChild( extensions );
+
+ QTextStream stream( &file );
+ stream.setEncoding(QTextStream::UnicodeUTF8);
+ stream << doc.toString();
+}
+
+short UMLDoc::getEncoding(QIODevice & file)
+{
+ QTextStream stream( &file );
+ stream.setEncoding(QTextStream::UnicodeUTF8);
+ QString data = stream.read();
+ QString error;
+ int line;
+ QDomDocument doc;
+ if( !doc.setContent( data, false, &error, &line ) )
+ {
+ kWarning()<<"Can't set content: "<<error<<" Line: "<<line<<endl;
+ return ENC_UNKNOWN;
+ }
+
+ // we start at the beginning and go to the point in the header where we can
+ // find out if the file was saved using Unicode
+ QDomNode node = doc.firstChild();
+ while (node.isComment() || node.isProcessingInstruction())
+ {
+ node = node.nextSibling();
+ }
+ QDomElement root = node.toElement();
+ if( root.isNull() )
+ {
+ return ENC_UNKNOWN;
+ }
+ // make sure it is an XMI file
+ if( root.tagName() != "XMI" )
+ {
+ return ENC_UNKNOWN;
+ }
+ node = node.firstChild();
+
+ if ( node.isNull() )
+ return ENC_UNKNOWN;
+
+ QDomElement element = node.toElement();
+ // check header
+ if( element.isNull() || element.tagName() != "XMI.header" )
+ return ENC_UNKNOWN;
+
+ QDomNode headerNode = node.firstChild();
+ while ( !headerNode.isNull() )
+ {
+ QDomElement headerElement = headerNode.toElement();
+ // the information if Unicode was used is now stored in the
+ // XMI.documentation section of the header
+ if (headerElement.isNull() ||
+ headerElement.tagName() != "XMI.documentation") {
+ headerNode = headerNode.nextSibling();
+ continue;
+ }
+ QDomNode docuNode = headerNode.firstChild();
+ while ( !docuNode.isNull() )
+ {
+ QDomElement docuElement = docuNode.toElement();
+ // a tag XMI.exporterEncoding was added since version 1.2 to
+ // mark a file as saved with Unicode
+ if (! docuElement.isNull() &&
+ docuElement.tagName() == "XMI.exporterEncoding")
+ {
+ // at the moment this if isn't really necessary, but maybe
+ // later we will have other encoding standards
+ if (docuElement.text() == QString("UnicodeUTF8"))
+ {
+ return ENC_UNICODE; // stop here
+ }
+ }
+ docuNode = docuNode.nextSibling();
+ }
+ break;
+ }
+ return ENC_OLD_ENC;
+}
+
+bool UMLDoc::loadFromXMI( QIODevice & file, short encode )
+{
+ // old Umbrello versions (version < 1.2) didn't save the XMI in Unicode
+ // this wasn't correct, because non Latin1 chars where lost
+ // to ensure backward compatibility we have to ensure to load the old files
+ // with non Unicode encoding
+ if (encode == ENC_UNKNOWN)
+ {
+ if ((encode = getEncoding(file)) == ENC_UNKNOWN)
+ return false;
+ file.reset();
+ }
+ QTextStream stream( &file );
+ if (encode == ENC_UNICODE)
+ {
+ stream.setEncoding(QTextStream::UnicodeUTF8);
+ }
+
+ QString data = stream.read();
+ kapp->processEvents(); // give UI events a chance
+ QString error;
+ int line;
+ QDomDocument doc;
+ if( !doc.setContent( data, false, &error, &line ) ) {
+ kWarning()<<"Can't set content:"<<error<<" Line:"<<line<<endl;
+ return false;
+ }
+ kapp->processEvents(); // give UI events a chance
+ QDomNode node = doc.firstChild();
+ //Before Umbrello 1.1-rc1 we didn't add a <?xml heading
+ //so we allow the option of this being missing
+ while (node.isComment() || node.isProcessingInstruction()) {
+ node = node.nextSibling();
+ }
+
+ QDomElement root = node.toElement();
+ if( root.isNull() ) {
+ return false;
+ }
+ // make sure it is an XMI file
+ if( root.tagName() != "XMI" ) {
+ return false;
+ }
+
+ m_nViewID = Uml::id_None;
+ for (node = node.firstChild(); !node.isNull(); node = node.nextSibling()) {
+ if (node.isComment())
+ continue;
+ QDomElement element = node.toElement();
+ if (element.isNull()) {
+ kDebug() << "loadFromXMI: skip empty elem" << endl;
+ continue;
+ }
+ bool recognized = false;
+ QString outerTag = element.tagName();
+ //check header
+ if (outerTag == "XMI.header") {
+ QDomNode headerNode = node.firstChild();
+ if ( !validateXMIHeader(headerNode) ) {
+ return false;
+ }
+ recognized = true;
+ } else if (outerTag == "XMI.extensions") {
+ QDomNode extensionsNode = node.firstChild();
+ while (! extensionsNode.isNull()) {
+ loadExtensionsFromXMI(extensionsNode);
+ extensionsNode = extensionsNode.nextSibling();
+ }
+ recognized = true;
+ }
+ if (outerTag != "XMI.content" ) {
+ if (!recognized)
+ kDebug() << "UMLDoc::loadFromXMI: skipping <"
+ << outerTag << ">" << endl;
+ continue;
+ }
+ bool seen_UMLObjects = false;
+ //process content
+ for (QDomNode child = node.firstChild(); !child.isNull();
+ child = child.nextSibling()) {
+ if (child.isComment())
+ continue;
+ element = child.toElement();
+ QString tag = element.tagName();
+ if (tag == "umlobjects" // for bkwd compat.
+ || tagEq(tag, "Subsystem")
+ || tagEq(tag, "Model") ) {
+ if( !loadUMLObjectsFromXMI( element ) ) {
+ kWarning() << "failed load on objects" << endl;
+ return false;
+ }
+ m_Name = element.attribute( "name", i18n("UML Model") );
+ UMLListView *lv = UMLApp::app()->getListView();
+ lv->setColumnText(0, m_Name);
+ seen_UMLObjects = true;
+ } else if (tagEq(tag, "Package") ||
+ tagEq(tag, "Class") ||
+ tagEq(tag, "Interface")) {
+ // These tests are only for foreign XMI files that
+ // are missing the <Model> tag (e.g. NSUML)
+ QDomElement parentElem = node.toElement();
+ if( !loadUMLObjectsFromXMI( parentElem ) ) {
+ kWarning() << "failed load on model objects" << endl;
+ return false;
+ }
+ seen_UMLObjects = true;
+ } else if (tagEq(tag, "TaggedValue")) {
+ // This tag is produced here, i.e. outside of <UML:Model>,
+ // by the Unisys.JCR.1 Rose-to-XMI tool.
+ if (! seen_UMLObjects) {
+ kDebug() << "skipping TaggedValue because not seen_UMLObjects"
+ << endl;
+ continue;
+ }
+ tag = element.attribute("tag", "");
+ if (tag != "documentation") {
+ continue;
+ }
+ QString modelElement = element.attribute("modelElement", "");
+ if (modelElement.isEmpty()) {
+ kDebug() << "skipping TaggedValue(documentation) because "
+ << "modelElement.isEmpty()" << endl;
+ continue;
+ }
+ UMLObject *o = findObjectById(STR2ID(modelElement));
+ if (o == NULL) {
+ kDebug() << "TaggedValue(documentation): cannot find object"
+ << " for modelElement " << modelElement << endl;
+ continue;
+ }
+ QString value = element.attribute("value", "");
+ if (! value.isEmpty())
+ o->setDoc(value);
+ } else {
+ // for backward compatibility
+ loadExtensionsFromXMI(child);
+ }
+ }
+ }
+#ifdef VERBOSE_DEBUGGING
+ kDebug() << "UMLDoc::m_objectList.count() is " << m_objectList.count() << endl;
+#endif
+ resolveTypes();
+ // set a default code generator if no <XMI.extensions><codegeneration> tag seen
+ if (UMLApp::app()->getGenerator() == NULL)
+ UMLApp::app()->setGenerator(UMLApp::app()->getDefaultLanguage());
+ emit sigWriteToStatusBar( i18n("Setting up the document...") );
+ kapp->processEvents(); // give UI events a chance
+ activateAllViews();
+
+ UMLView *viewToBeSet = NULL;
+ if (m_nViewID != Uml::id_None)
+ viewToBeSet = findView( m_nViewID );
+ if (viewToBeSet) {
+ changeCurrentView( m_nViewID );
+ Settings::OptionState optionState = Settings::getOptionState();
+ if (optionState.generalState.tabdiagrams) {
+ UMLApp::app()->tabWidget()->showPage(viewToBeSet);
+ }
+ } else {
+ createDiagram(m_root[mt_Logical], Uml::dt_Class, false);
+ m_pCurrentRoot = m_root[mt_Logical];
+ }
+ emit sigResetStatusbarProgress();
+ return true;
+}
+
+void UMLDoc::resolveTypes() {
+ // Resolve the types.
+ // This is done in a separate pass because of possible forward references.
+ if (m_bTypesAreResolved)
+ return;
+ m_bTypesAreResolved = true;
+ writeToStatusBar( i18n("Resolving object references...") );
+ for (int i = 0; i < Uml::N_MODELTYPES; i++) {
+ UMLFolder *obj = m_root[i];
+#ifdef VERBOSE_DEBUGGING
+ kDebug() << "UMLDoc: invoking resolveRef() for " << obj->getName()
+ << " (id=" << ID2STR(obj->getID()) << ")" << endl;
+#endif
+ obj->resolveRef();
+ }
+ kapp->processEvents(); // give UI events a chance
+}
+
+bool UMLDoc::validateXMIHeader(QDomNode& headerNode) {
+ QDomElement headerElement = headerNode.toElement();
+ while ( !headerNode.isNull() ) {
+ /* //Seems older Umbrello files used a different metamodel, so don't validate it for now
+ if( !headerElement.isNull() && headerElement.tagName() == "XMI.metamodel" ) {
+ String metamodel = headerElement.attribute("xmi.name", "");
+ if (metamodel != "UML") {
+ return false;
+ }
+ }
+ */
+ headerNode = headerNode.nextSibling();
+ headerElement = headerNode.toElement();
+ }
+ return true;
+}
+
+bool UMLDoc::loadUMLObjectsFromXMI(QDomElement& element) {
+ /* FIXME need a way to make status bar actually reflect
+ how much of the file has been loaded rather than just
+ counting to 10 (an arbitrary number)
+ emit sigResetStatusbarProgress();
+ emit sigSetStatusbarProgress( 0 );
+ emit sigSetStatusbarProgressSteps( 10 );
+ m_count = 0;
+ */
+ emit sigWriteToStatusBar( i18n("Loading UML elements...") );
+
+ for (QDomNode node = element.firstChild(); !node.isNull();
+ node = node.nextSibling()) {
+ if (node.isComment())
+ continue;
+ QDomElement tempElement = node.toElement();
+ QString type = tempElement.tagName();
+ if (tagEq(type, "Model")) {
+ bool foundUmbrelloRootFolder = false;
+ QString name = tempElement.attribute("name");
+ for (int i = 0; i < Uml::N_MODELTYPES; i++) {
+ if (name == m_root[i]->getName()) {
+ m_pCurrentRoot = m_root[i];
+ m_root[i]->loadFromXMI(tempElement);
+ foundUmbrelloRootFolder = true;
+ break;
+ }
+ }
+ if (foundUmbrelloRootFolder)
+ continue;
+ }
+ // From here on, it's support for stereotypes, pre 1.5.5 versions, and foreign files
+ if (tagEq(type, "Namespace.ownedElement") ||
+ tagEq(type, "Namespace.contents") ||
+ tagEq(type, "Model")) {
+ //CHECK: Umbrello currently assumes that nested elements
+ // are ownedElements anyway.
+ // Therefore the <UML:Namespace.ownedElement> tag is of no
+ // significance.
+ if( !loadUMLObjectsFromXMI( tempElement ) ) {
+ kWarning() << "failed load on " << type << endl;
+ return false;
+ }
+ continue;
+ }
+ if (Model_Utils::isCommonXMIAttribute(type))
+ continue;
+ if (! tempElement.hasAttribute("xmi.id")) {
+ QString idref = tempElement.attribute("xmi.idref", "");
+ if (! idref.isEmpty()) {
+ kDebug() << "resolution of xmi.idref " << idref
+ << " is not yet implemented" << endl;
+ } else {
+ kError() << "Cannot load " << type
+ << " because xmi.id is missing" << endl;
+ }
+ continue;
+ }
+ QString stID = tempElement.attribute("stereotype", "");
+ UMLObject *pObject = Object_Factory::makeObjectFromXMI(type, stID);
+ if( !pObject ) {
+ kWarning() << "Unknown type of umlobject to create: " << type << endl;
+ // We want a best effort, therefore this is handled as a
+ // soft error.
+ continue;
+ }
+ Uml::Object_Type ot = pObject->getBaseType();
+ // Set the parent root folder.
+ UMLPackage *pkg = NULL;
+ if (ot == Uml::ot_Datatype) {
+ pkg = m_datatypeRoot;
+ } else {
+ Uml::Model_Type guess = Model_Utils::guessContainer(pObject);
+ if (guess != Uml::N_MODELTYPES)
+ pkg = m_root[guess];
+ }
+ pObject->setUMLPackage(pkg);
+
+ bool status = pObject -> loadFromXMI( tempElement );
+ if ( !status ) {
+ //delete pObject;
+ // Unfortunately we cannot do this because the pObject
+ // may be still referenced by other model objects.
+ kError() << "loadFromXMI failed for " << pObject->getName() << " xmi.id="
+ << ID2STR(pObject->getID()) << endl;
+ continue;
+ }
+ pkg = pObject->getUMLPackage();
+ if (ot == ot_Stereotype) {
+ UMLStereotype *s = static_cast<UMLStereotype*>(pObject);
+ UMLStereotype *exist = findStereotype(pObject->getName());
+ if (exist) {
+ if (exist->getID() == pObject->getID()) {
+ delete pObject;
+ } else {
+ kDebug() << "Stereotype " << pObject->getName()
+ << "(id=" << ID2STR(pObject->getID())
+ << ") already exists with id="
+ << ID2STR(exist->getID()) << endl;
+ addStereotype(s);
+ }
+ } else {
+ addStereotype(s);
+ }
+ continue;
+ }
+ if (pkg == NULL)
+ kError() << "UMLDoc::loadUMLObjectsFromXMI: pkg is NULL for "
+ << pObject->getName() << " xmi.id="
+ << ID2STR(pObject->getID()) << endl;
+ else
+ pkg->addObject(pObject);
+
+ /* FIXME see comment at loadUMLObjectsFromXMI
+ emit sigSetStatusbarProgress( ++m_count );
+ */
+ }
+ return true;
+}
+
+void UMLDoc::setMainViewID(Uml::IDType viewID) {
+ m_nViewID = viewID;
+}
+
+void UMLDoc::loadExtensionsFromXMI(QDomNode& node) {
+ QDomElement element = node.toElement();
+ QString tag = element.tagName();
+
+ if (tag == "docsettings") {
+ QString viewID = element.attribute( "viewid", "-1" );
+ m_Doc = element.attribute( "documentation", "" );
+ QString uniqueid = element.attribute( "uniqueid", "0" );
+
+ m_nViewID = STR2ID(viewID);
+ UniqueID::set(STR2ID(uniqueid));
+ UMLApp::app()->getDocWindow() -> newDocumentation();
+
+ } else if (tag == "diagrams" || tag == "UISModelElement") {
+ // For backward compatibility only:
+ // Since version 1.5.5 diagrams are saved as part of the UMLFolder.
+ QDomNode diagramNode = node.firstChild();
+ if (tag == "UISModelElement") { // Unisys.IntegratePlus.2
+ element = diagramNode.toElement();
+ tag = element.tagName();
+ if (tag != "uisOwnedDiagram") {
+ kError() << "unknown child node " << tag << endl;
+ return;
+ }
+ diagramNode = diagramNode.firstChild();
+ }
+ if( !loadDiagramsFromXMI( diagramNode ) ) {
+ kWarning() << "failed load on diagrams" << endl;
+ }
+
+ } else if (tag == "listview") {
+ //FIXME: Need to resolveTypes() before loading listview,
+ // else listview items are duplicated.
+ resolveTypes();
+ if( !UMLApp::app()->getListView() -> loadFromXMI( element ) ) {
+ kWarning() << "failed load on listview" << endl;
+ }
+
+ } else if (tag == "codegeneration") {
+ QDomNode cgnode = node.firstChild();
+ QDomElement cgelement = cgnode.toElement();
+ while( !cgelement.isNull() ) {
+ QString nodeName = cgelement.tagName();
+ QString lang = cgelement.attribute("language","UNKNOWN");
+ Uml::Programming_Language pl = Model_Utils::stringToProgLang(lang);
+ CodeGenerator *g = UMLApp::app()->setGenerator(pl);
+ g->loadFromXMI(cgelement);
+ cgnode = cgnode.nextSibling();
+ cgelement = cgnode.toElement();
+ }
+ if (UMLApp::app()->getGenerator() == NULL)
+ UMLApp::app()->setGenerator(UMLApp::app()->getDefaultLanguage());
+ }
+}
+
+// For backward compatibility only:
+// Since version 1.5.5 diagrams are saved as part of the UMLFolder.
+bool UMLDoc::loadDiagramsFromXMI( QDomNode & node ) {
+ emit sigWriteToStatusBar( i18n("Loading diagrams...") );
+ emit sigResetStatusbarProgress();
+ emit sigSetStatusbarProgress( 0 );
+ emit sigSetStatusbarProgressSteps( 10 ); //FIX ME
+ QDomElement element = node.toElement();
+ if( element.isNull() )
+ return true;//return ok as it means there is no umlobjects
+ const Settings::OptionState state = Settings::getOptionState();
+ UMLView * pView = 0;
+ int count = 0;
+ while( !element.isNull() ) {
+ QString tag = element.tagName();
+ if (tag == "diagram" || tag == "UISDiagram") {
+ pView = new UMLView(NULL);
+ // IMPORTANT: Set OptionState of new UMLView _BEFORE_
+ // reading the corresponding diagram:
+ // + allow using per-diagram color and line-width settings
+ // + avoid crashes due to uninitialized values for lineWidth
+ pView -> setOptionState( state );
+ bool success = false;
+ if (tag == "UISDiagram") {
+ success = pView->loadUISDiagram(element);
+ } else {
+ success = pView->loadFromXMI(element);
+ }
+ if (!success) {
+ kWarning() << "failed load on viewdata loadfromXMI" << endl;
+ delete pView;
+ return false;
+ }
+ // Put diagram in default predefined folder.
+ // @todo pass in the parent folder - it might be a user defined one.
+ Uml::Model_Type mt = Model_Utils::convert_DT_MT(pView->getType());
+ pView->setFolder(m_root[mt]);
+ pView -> hide();
+ addView( pView );
+ emit sigSetStatusbarProgress( ++count );
+ kapp->processEvents(); // give UI events a chance
+ }
+ node = node.nextSibling();
+ element = node.toElement();
+ }
+ return true;
+}
+
+void UMLDoc::removeAllViews() {
+ for (int i = 0; i < Uml::N_MODELTYPES; i++)
+ m_root[i]->removeAllViews();
+ UMLApp::app()->setCurrentView(NULL);
+ emit sigDiagramChanged(dt_Undefined);
+ UMLApp::app()->setDiagramMenuItemsState(false);
+}
+
+UMLClassifierList UMLDoc::getConcepts(bool includeNested /* =true */) {
+ UMLClassifierList conceptList;
+ m_root[mt_Logical]->appendClassifiers(conceptList, includeNested);
+ return conceptList;
+}
+
+UMLClassifierList UMLDoc::getClasses(bool includeNested /* =true */) {
+ UMLClassifierList conceptList;
+ m_root[mt_Logical]->appendClasses(conceptList, includeNested);
+ return conceptList;
+}
+
+UMLClassifierList UMLDoc::getClassesAndInterfaces(bool includeNested /* =true */) {
+ UMLClassifierList conceptList;
+ m_root[mt_Logical]->appendClassesAndInterfaces(conceptList, includeNested);
+ return conceptList;
+}
+
+UMLClassifierList UMLDoc::getInterfaces(bool includeNested /* =true */) {
+ UMLClassifierList interfaceList;
+ m_root[mt_Logical]->appendInterfaces(interfaceList, includeNested);
+ return interfaceList;
+}
+
+UMLClassifierList UMLDoc::getDatatypes() {
+ UMLObjectList objects = m_datatypeRoot->containedObjects();
+ UMLClassifierList datatypeList;
+ UMLObject *obj;
+ for (UMLObjectListIt oit(objects); (obj = oit.current()) != NULL; ++oit) {
+ if (obj->getBaseType() == ot_Datatype) {
+ datatypeList.append(static_cast<UMLClassifier*>(obj));
+ }
+ }
+ return datatypeList;
+}
+
+UMLAssociationList UMLDoc::getAssociations() {
+ UMLAssociationList associationList;
+ for (int i = 0; i < Uml::N_MODELTYPES; i++) {
+ UMLAssociationList assocs = m_root[i]->getAssociations();
+ UMLAssociation *a;
+ for (UMLAssociationListIt ait(assocs); (a = ait.current()) != NULL; ++ait)
+ associationList.append(a);
+ }
+ return associationList;
+}
+
+void UMLDoc::print(KPrinter * pPrinter) {
+ UMLView * printView = 0;
+ int count = QString(pPrinter -> option("kde-uml-count")).toInt();
+ QPainter painter(pPrinter);
+ for(int i = 0;i < count;i++) {
+ if(i>0)
+ pPrinter -> newPage();
+ QString diagram = i18n("kde-uml-Diagram") + QString("%1").arg(i);
+ QString sID = pPrinter -> option(diagram);
+ Uml::IDType id = STR2ID(sID);
+ printView = findView(id);
+
+ if(printView)
+ printView ->print(pPrinter, painter);
+ printView = 0;
+ }
+ painter.end();
+}
+
+UMLViewList UMLDoc::getViewIterator() {
+ UMLViewList accumulator;
+ for (int i = 0; i < Uml::N_MODELTYPES; i++)
+ m_root[i]->appendViews(accumulator, true);
+ return accumulator;
+}
+
+void UMLDoc::setModified(bool modified /*=true*/, bool addToUndo /*=true*/) {
+ if(!m_bLoading) {
+ m_modified = modified;
+ UMLApp::app()->setModified(modified);
+
+ if (modified && addToUndo) {
+ addToUndoStack();
+ clearRedoStack();
+ }
+ }
+}
+
+bool UMLDoc::assignNewIDs(UMLObject* Obj) {
+ if(!Obj || !m_pChangeLog) {
+ kDebug() << "no Obj || Changelog" << endl;
+ return false;
+ }
+ Uml::IDType result = assignNewID(Obj->getID());
+ Obj->setID(result);
+
+ //If it is a CONCEPT then change the ids of all its operations and attributes
+ if(Obj->getBaseType() == ot_Class ) {
+ UMLClassifier *c = static_cast<UMLClassifier*>(Obj);
+ UMLClassifierListItemList attributes = c->getFilteredList(ot_Attribute);
+ for(UMLObject* listItem = attributes.first(); listItem; listItem = attributes.next()) {
+ result = assignNewID(listItem->getID());
+ listItem->setID(result);
+ }
+
+ UMLClassifierListItemList templates = c->getFilteredList(ot_Template);
+ for(UMLObject* listItem = templates.first(); listItem; listItem = templates.next()) {
+ result = assignNewID(listItem->getID());
+ listItem->setID(result);
+ }
+ }
+
+ if(Obj->getBaseType() == ot_Interface || Obj->getBaseType() == ot_Class ) {
+ UMLOperationList operations(((UMLClassifier*)Obj)->getOpList());
+ for(UMLObject* listItem = operations.first(); listItem; listItem = operations.next()) {
+ result = assignNewID(listItem->getID());
+ listItem->setID(result);
+ }
+ }
+
+ setModified(true);
+
+ return true;
+}
+
+UMLFolder *UMLDoc::getRootFolder(Uml::Model_Type mt) {
+ if (mt < Uml::mt_Logical || mt >= Uml::N_MODELTYPES) {
+ kError() << "UMLDoc::getRootFolder: illegal input value " << mt << endl;
+ return NULL;
+ }
+ return m_root[mt];
+}
+
+Uml::Model_Type UMLDoc::rootFolderType(UMLObject *obj) {
+ for (int i = 0; i < Uml::N_MODELTYPES; i++) {
+ const Uml::Model_Type m = (Uml::Model_Type)i;
+ if (obj == m_root[m])
+ return m;
+ }
+ return Uml::N_MODELTYPES;
+}
+
+/** Read property of IDChangeLog* m_pChangeLog. */
+IDChangeLog* UMLDoc::getChangeLog() {
+ return m_pChangeLog;
+}
+
+/** Opens a Paste session,
+Deletes the Old ChangeLog and Creates an empty one */
+
+void UMLDoc::beginPaste() {
+ if(m_pChangeLog) {
+ delete m_pChangeLog;
+ m_pChangeLog = 0;
+ }
+ m_pChangeLog = new IDChangeLog;
+}
+
+/** Closes a Paste session,
+Deletes the ChangeLog */
+void UMLDoc::endPaste() {
+ if(m_pChangeLog) {
+ delete m_pChangeLog;
+ m_pChangeLog = 0;
+ }
+}
+
+/** Assigns a New ID to an Object, and also logs the assignment to its internal
+ChangeLog */
+Uml::IDType UMLDoc::assignNewID(Uml::IDType OldID) {
+ Uml::IDType result = UniqueID::gen();
+ if (m_pChangeLog) {
+ m_pChangeLog->addIDChange(OldID, result);
+ }
+ return result;
+}
+
+/** Adds an already created UMLView to the document, it gets assigned a new ID.
+ If its name is already in use then the function appends a number to it to
+ differentiate it from the others; this number is incremental so if
+ number 1 is in use then it tries 2 and then 3 and so on */
+bool UMLDoc::addUMLView(UMLView * pView ) {
+ if(!pView || !m_pChangeLog)
+ return false;
+
+ int i = 0;
+ QString viewName = (QString)pView->getName();
+ QString name = viewName;
+ while( findView(pView->getType(), name) != NULL) {
+ name = viewName + '_' + QString::number(++i);
+ }
+ if(i) //If name was modified
+ pView->setName(name);
+ Uml::IDType result = assignNewID(pView->getID());
+ pView->setID(result);
+
+ pView->activateAfterLoad( true );
+ pView->endPartialWidgetPaste();
+ pView->setOptionState( Settings::getOptionState() );
+ addView(pView);
+ setModified(true);
+ return true;
+}
+
+void UMLDoc::activateAllViews() {
+ // store old setting - for restore of last setting
+ bool m_bLoading_old = m_bLoading;
+ m_bLoading = true; //this is to prevent document becoming modified when activating a view
+
+ for (int i = 0; i < Uml::N_MODELTYPES; i++)
+ m_root[i]->activateViews();
+ m_bLoading = m_bLoading_old;
+}
+
+void UMLDoc::settingsChanged(Settings::OptionState optionState) {
+ for (int i = 0; i < Uml::N_MODELTYPES; i++)
+ m_root[i]->setViewOptions(optionState);
+ initSaveTimer();
+}
+
+void UMLDoc::initSaveTimer() {
+ if( m_pAutoSaveTimer ) {
+ m_pAutoSaveTimer -> stop();
+ disconnect( m_pAutoSaveTimer, SIGNAL( timeout() ), this, SLOT( slotAutoSave() ) );
+ delete m_pAutoSaveTimer;
+ m_pAutoSaveTimer = 0;
+ }
+ Settings::OptionState optionState = Settings::getOptionState();
+ if( optionState.generalState.autosave ) {
+ m_pAutoSaveTimer = new QTimer(this, "_AUTOSAVETIMER_" );
+ connect( m_pAutoSaveTimer, SIGNAL( timeout() ), this, SLOT( slotAutoSave() ) );
+ m_pAutoSaveTimer->start( optionState.generalState.autosavetime * 60000, false );
+ }
+ return;
+}
+
+void UMLDoc::slotAutoSave() {
+ //Only save if modified.
+ if( !m_modified ) {
+ return;
+ }
+ KURL tempURL = m_doc_url;
+ if( tempURL.fileName() == i18n("Untitled") ) {
+ tempURL.setPath( QDir::homeDirPath() + i18n("/autosave%1").arg(".xmi") );
+ saveDocument( tempURL );
+ m_doc_url.setFileName( i18n("Untitled") );
+ m_modified = true;
+ UMLApp::app()->setModified( m_modified );
+ } else {
+ // 2004-05-17 Achim Spangler
+ KURL orgDocUrl = m_doc_url;
+ QString orgFileName = m_doc_url.fileName();
+ // don't overwrite manually saved file with autosave content
+ QString fileName = tempURL.fileName();
+ Settings::OptionState optionState = Settings::getOptionState();
+ fileName.replace( ".xmi", optionState.generalState.autosavesuffix );
+ tempURL.setFileName( fileName );
+ // End Achim Spangler
+
+ saveDocument( tempURL );
+ // 2004-05-17 Achim Spangler
+ // re-activate m_modified if autosave is writing to other file
+ // than the main project file -> autosave-suffix != ".xmi"
+ if ( ".xmi" != optionState.generalState.autosavesuffix ) {
+ m_modified = true;
+ UMLApp::app()->setModified( m_modified );
+ }
+ // restore original file name -
+ // UMLDoc::saveDocument() sets doc_url to filename which is given as autosave-filename
+ setURL( orgDocUrl );
+ UMLApp * pApp = UMLApp::app();
+ pApp->setCaption(orgFileName, isModified() );
+ // End Achim Spangler
+ }
+}
+
+void UMLDoc::signalDiagramRenamed(UMLView* pView ) {
+ Settings::OptionState optionState = Settings::getOptionState();
+ if (optionState.generalState.tabdiagrams)
+ UMLApp::app()->tabWidget()->setTabLabel( pView, pView->getName() );
+ emit sigDiagramRenamed( pView -> getID() );
+}
+
+void UMLDoc::addToUndoStack() {
+ Settings::OptionState optionState = Settings::getOptionState();
+ if (!m_bLoading && optionState.generalState.undo) {
+ QBuffer* buffer = new QBuffer();
+ buffer->open(IO_WriteOnly);
+ QDataStream* undoData = new QDataStream();
+ undoData->setDevice(buffer);
+ saveToXMI(*buffer);
+ buffer->close();
+ undoStack.prepend(undoData);
+
+ if (undoStack.count() > 1) {
+ UMLApp::app()->enableUndo(true);
+ }
+ }
+}
+
+void UMLDoc::clearUndoStack() {
+ undoStack.setAutoDelete(true);
+ undoStack.clear();
+ UMLApp::app()->enableRedo(false);
+ undoStack.setAutoDelete(false);
+ clearRedoStack();
+}
+
+void UMLDoc::clearRedoStack() {
+ redoStack.setAutoDelete(true);
+ redoStack.clear();
+ UMLApp::app()->enableRedo(false);
+ redoStack.setAutoDelete(false);
+}
+
+void UMLDoc::loadUndoData() {
+ if (undoStack.count() < 1) {
+ kWarning() << "no data in undostack" << endl;
+ return;
+ }
+ UMLView *currentView = UMLApp::app()->getCurrentView();
+ if (currentView == NULL) {
+ kWarning() << "UMLDoc::loadUndoData: currentView is NULL" << endl;
+ undoStack.setAutoDelete(true);
+ undoStack.clear();
+ undoStack.setAutoDelete(false);
+ UMLApp::app()->enableUndo(false);
+ return;
+ }
+ Uml::IDType currentViewID = currentView->getID();
+ // store old setting - for restore of last setting
+ bool m_bLoading_old = m_bLoading;
+ m_bLoading = true;
+ closeDocument();
+ redoStack.prepend( undoStack.take(0) );
+ QDataStream* undoData = undoStack.getFirst();
+ QBuffer* buffer = static_cast<QBuffer*>( undoData->device() );
+ buffer->open(IO_ReadOnly);
+ loadFromXMI(*buffer);
+ buffer->close();
+
+ setModified(true, false);
+ m_bLoading = m_bLoading_old;
+
+ undoStack.setAutoDelete(true);
+ if (undoStack.count() <= 1) {
+ UMLApp::app()->enableUndo(false);
+ }
+ if (redoStack.count() >= 1) {
+ UMLApp::app()->enableRedo(true);
+ }
+ while (undoStack.count() > undoMax) {
+ undoStack.removeLast();
+ }
+ undoStack.setAutoDelete(false);
+
+ currentView = UMLApp::app()->getCurrentView();
+ if (currentView) {
+ if (currentView->getID() != currentViewID)
+ changeCurrentView( currentView->getID() );
+ currentView->resizeCanvasToItems();
+ }
+}
+
+void UMLDoc::loadRedoData() {
+ if (redoStack.count() >= 1) {
+ UMLView *currentView = UMLApp::app()->getCurrentView();
+ Uml::IDType currentViewID = currentView->getID();
+ // store old setting - for restore of last setting
+ bool m_bLoading_old = m_bLoading;
+ m_bLoading = true;
+ closeDocument();
+ undoStack.prepend( redoStack.getFirst() );
+ QDataStream* redoData = redoStack.getFirst();
+ redoStack.removeFirst();
+ QBuffer* buffer = static_cast<QBuffer*>( redoData->device() );
+ buffer->open(IO_ReadOnly);
+ loadFromXMI(*buffer);
+ buffer->close();
+
+ setModified(true, false);
+ currentView = UMLApp::app()->getCurrentView();
+ currentView->resizeCanvasToItems();
+ m_bLoading = m_bLoading_old;
+
+ redoStack.setAutoDelete(true);
+ if (redoStack.count() < 1) {
+ UMLApp::app()->enableRedo(false);
+ }
+ if (undoStack.count() > 1) {
+ UMLApp::app()->enableUndo(true);
+ }
+ if (currentView->getID() != currentViewID) {
+ changeCurrentView(currentViewID);
+ }
+ redoStack.setAutoDelete(false);
+ } else {
+ kWarning() << "no data in redostack" << endl;
+ }
+}
+
+void UMLDoc::addDefaultDatatypes() {
+ CodeGenerator *cg = UMLApp::app()->getGenerator();
+ if (cg == NULL) {
+ kDebug() << "UMLDoc::addDefaultDatatypes: CodeGenerator is still NULL"
+ << endl;
+ return;
+ }
+ QStringList entries = cg->defaultDatatypes();
+ QStringList::Iterator end(entries.end());
+ for (QStringList::Iterator it = entries.begin(); it != end; ++it)
+ createDatatype(*it);
+}
+
+void UMLDoc::createDatatype(const QString &name) {
+ UMLObjectList datatypes = m_datatypeRoot->containedObjects();
+ UMLObject* umlobject = Model_Utils::findUMLObject(datatypes, name,
+ ot_Datatype, m_datatypeRoot);
+ if (!umlobject) {
+ Object_Factory::createUMLObject(ot_Datatype, name, m_datatypeRoot);
+ }
+ UMLApp::app()->getListView()->closeDatatypesFolder();
+}
+
+void UMLDoc::slotDiagramPopupMenu(QWidget* umlview, const QPoint& point) {
+ UMLView* view = (UMLView*) umlview;
+ if(m_pTabPopupMenu != 0) {
+ m_pTabPopupMenu->hide();
+ delete m_pTabPopupMenu;
+ m_pTabPopupMenu = 0;
+ }
+ Settings::OptionState optionState = Settings::getOptionState();
+ if (! optionState.generalState.tabdiagrams)
+ return;
+
+ Uml::ListView_Type type = lvt_Unknown;
+ switch( view->getType() ) {
+ case dt_Class:
+ type = lvt_Class_Diagram;
+ break;
+
+ case dt_UseCase:
+ type = lvt_UseCase_Diagram;
+ break;
+
+ case dt_Sequence:
+ type = lvt_Sequence_Diagram;
+ break;
+
+ case dt_Collaboration:
+ type = lvt_Collaboration_Diagram;
+ break;
+
+ case dt_State:
+ type = lvt_State_Diagram;
+ break;
+
+ case dt_Activity:
+ type = lvt_Activity_Diagram;
+ break;
+
+ case dt_Component:
+ type = lvt_Component_Diagram;
+ break;
+
+ case dt_Deployment:
+ type = lvt_Deployment_Diagram;
+ break;
+
+ case dt_EntityRelationship:
+ type = lvt_EntityRelationship_Diagram;
+ break;
+
+ default:
+ kWarning() << "unknown diagram type in slotDiagramPopupMenu()" << endl;
+ break;
+ }//end switch
+
+ m_pTabPopupMenu = new ListPopupMenu(UMLApp::app()->getMainViewWidget(), type);
+ m_pTabPopupMenu->popup(point);
+ connect(m_pTabPopupMenu, SIGNAL(activated(int)), view, SLOT(slotMenuSelection(int)));
+}
+
+void UMLDoc::addDefaultStereotypes() {
+ CodeGenerator *gen = UMLApp::app()->getGenerator();
+ if (gen)
+ gen->createDefaultStereotypes();
+}
+
+const UMLStereotypeList& UMLDoc::getStereotypes() {
+ return m_stereoList;
+}
+
+
+#include "umldoc.moc"
+
diff --git a/umbrello/umbrello/umldoc.h b/umbrello/umbrello/umldoc.h
new file mode 100644
index 00000000..2e936a3f
--- /dev/null
+++ b/umbrello/umbrello/umldoc.h
@@ -0,0 +1,920 @@
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * copyright (C) 2002-2007 *
+ * Umbrello UML Modeller Authors <uml-devel@uml.sf.net> *
+ ***************************************************************************/
+
+#ifndef UMLDOC_H
+#define UMLDOC_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+// system includes
+#include <typeinfo>
+
+// qt includes
+#include <qdatastream.h>
+#include <qmap.h>
+#include <qdict.h>
+#include <qptrstack.h>
+
+// kde includes
+#include <kurl.h>
+#include <kdockwidget.h>
+#include <kpopupmenu.h>
+
+// app includes
+#include "umlnamespace.h"
+#include "optionstate.h"
+#include "umlobjectlist.h"
+#include "umlassociationlist.h"
+#include "umlclassifierlist.h"
+#include "umlviewlist.h"
+#include "umlstereotypelist.h"
+
+#define ENC_UNKNOWN 0
+#define ENC_UNICODE 1
+#define ENC_OLD_ENC 2
+
+
+// forward declarations
+class QDomNode;
+class QFile;
+class QSplitter;
+
+class KPrinter;
+
+class DocWindow;
+class IDChangeLog;
+class ObjectWidget;
+class UMLWidget;
+class UMLPackage;
+class UMLFolder;
+
+/**
+ * UMLDoc provides a document object for a document-view model.
+ *
+ * The UMLDoc class provides a document object that can be used
+ * in conjunction with the classes UMLApp and UMLView to create
+ * a document-view model for standard KDE applications based on
+ * KApplication and KMainWindow. Thereby, the document object
+ * is created by the UMLApp instance and contains the document
+ * structure with the according methods for manipulation of the
+ * document data by UMLView objects. Also, UMLDoc contains the
+ * methods for serialization of the document data from and to
+ * files.
+ *
+ * @author Paul Hensgen <phensgen@techie.com>
+ * Bugs and comments to uml-devel@lists.sf.net or http://bugs.kde.org
+ */
+class UMLDoc : public QObject {
+ Q_OBJECT
+public:
+ /**
+ * Constructor for the fileclass of the application
+ */
+ UMLDoc();
+
+ /**
+ * Destructor for the fileclass of the application
+ */
+ ~UMLDoc();
+
+ /**
+ * Initialize the UMLDoc.
+ * To be called after the constructor, before anything else.
+ */
+ void init();
+
+ /**
+ * Adds a view to the document which represents the document
+ * contents. Usually this is your main view.
+ *
+ * @param view Pointer to the UMLView to add.
+ */
+ void addView(UMLView *view);
+
+ /**
+ * Removes a view from the list of currently connected views.
+ *
+ * @param view Pointer to the UMLView to remove.
+ * @param enforceOneView switch to determine if we have a current view or not.
+ * most of the time, we DO want this, except when exiting the program.
+ */
+ void removeView(UMLView *view , bool enforceOneView = true );
+
+ /**
+ * Sets m_nViewID.
+ */
+ void setMainViewID(Uml::IDType viewID);
+
+ /**
+ * Sets the modified flag for the document after a modifying
+ * action on the view connected to the document.
+ *
+ * @param _m The value to set the modified flag to.
+ * @param addToUndo Whether this is an action which should be
+ * added to the undo stack.
+ */
+ void setModified(bool _m=true, bool addToUndo=true);
+
+ /**
+ * Returns if the document is modified or not. Use this to
+ * determine if your document needs saving by the user on
+ * closing.
+ *
+ * @return True if this UMLDoc is modified.
+ */
+ bool isModified() {
+ return m_modified;
+ }
+
+ /**
+ * "save modified" - Asks the user for saving if the document
+ * is modified.
+ *
+ * @return True if document can be closed.
+ */
+ bool saveModified();
+
+ /**
+ * Initializes the document generally.
+ *
+ * @return True if operation successful.
+ */
+ bool newDocument();
+
+ /**
+ * Closes the current document.
+ */
+ void closeDocument();
+
+ /**
+ * Loads the document by filename and format and emits the
+ * updateViews() signal.
+ *
+ * @param url The filename in KURL format.
+ * @param format The format (optional.)
+ * @return True if operation successful.
+ */
+ bool openDocument(const KURL& url, const char *format=0);
+
+ /**
+ * Saves the document using the given filename and format.
+ *
+ * @param url The filename in KURL format.
+ * @param format The format (optional.)
+ * @return True if operation successful.
+ */
+ bool saveDocument(const KURL& url, const char *format=0);
+
+ /**
+ * Returns the KURL of the document.
+ *
+ * @return The KURL of this UMLDoc.
+ */
+ const KURL& URL() const;
+
+ /**
+ * Sets the URL of the document.
+ *
+ * @param url The KURL to set.
+ */
+ void setURL(const KURL& url);
+
+ /**
+ * Sets up the signals needed by the program for it to work.
+ */
+ void setupSignals();
+
+ /**
+ * Returns true if the given name is unique within its scope.
+ *
+ * @param name The name to check.
+ * @return True if name is unique.
+ */
+ bool isUnique(const QString &name);
+
+ /**
+ * Returns true if the given name is unique within its scope of given package.
+ *
+ * @param name The name to check.
+ * @package The UMLPackage in which we have to determine the unique-ness
+ * @return True if name is unique.
+ */
+ bool isUnique(const QString &name, UMLPackage *package);
+
+ /**
+ * Finds or creates a stereotype for the parent object.
+ */
+ UMLStereotype* findOrCreateStereotype(const QString &name);
+
+ /**
+ * Creates an association between two UMLObjects.
+ * NOTE: this method does not check if the association is valid / legal
+ *
+ * @param a The UMLObject "A" for the association (source)
+ * @param b The UMLObject "B" for the association (destination)
+ * @param type The association's type
+ * @return The Association created
+ */
+ UMLAssociation* createUMLAssociation(UMLObject *a, UMLObject *b, Uml::Association_Type type);
+
+ /**
+ * Adds an association.
+ *
+ * @param pAssoc Pointer to the UMLAssociation to add.
+ */
+ void addAssociation(UMLAssociation *pAssoc);
+
+ /**
+ * Removes an association.
+ *
+ * @param pAssoc Pointer to the UMLAssociation to remove.
+ * @param doSetModified Whether to mark the document as modified (default: true.)
+ */
+ void removeAssociation(UMLAssociation *pAssoc, bool doSetModified = true);
+
+ /**
+ * Finds an association.
+ *
+ * @param assocType Type of the UMLAssociation to seek.
+ * @param roleAObj Pointer to the role A UMLCanvasObject.
+ * @param roleBObj Pointer to the role B UMLCanvasObject.
+ * @param swap Optional pointer to boolean.
+ * The bool is set to true if the assocation
+ * matched with swapped roles, else it is set
+ * to false.
+ * @return Pointer to the UMLAssociation found or NULL if not found.
+ */
+ UMLAssociation * findAssociation(Uml::Association_Type assocType,
+ const UMLObject *roleAObj,
+ const UMLObject *roleBObj,
+ bool *swap = NULL);
+
+ /**
+ * Creates a diagram of the given type.
+ *
+ * @param folder The folder in which tp create the diagram.
+ * @param type The type of diagram to create.
+ * @param askForName If true shows a dialog box asking for name,
+ * else uses a default name.
+ * @return Pointer to the UMLView of the new diagram.
+ */
+ UMLView* createDiagram(UMLFolder *folder, Uml::Diagram_Type type, bool askForName = true);
+
+ /**
+ * Removes an @ref UMLObject from the current file. If this object
+ * is being represented on a diagram it will also delete all those
+ * representations.
+ *
+ * @param o Pointer to the UMLObject to delete.
+ */
+ void removeUMLObject(UMLObject*o);
+
+ /**
+ * Used to rename a document. This method takes care of everything.
+ * You just need to give the ID of the diagram to the method.
+ *
+ * @param id The ID of the diagram to rename.
+ */
+ void renameDiagram(Uml::IDType id);
+
+ /**
+ * Used to rename a @ref UMLObject. The @ref UMLObject is to be an
+ * actor, use case or concept.
+ *
+ * @param o The object to rename.
+ */
+ void renameUMLObject(UMLObject *o);
+
+ /**
+ * Used to rename an operation or attribute of a concept.
+ *
+ * @param o The attribute or operation to rename.
+ */
+ void renameChildUMLObject(UMLObject *o);
+
+
+ /**
+ * Changes the current view (diagram) to the view with the given ID.
+ *
+ * @param id The ID of the view to change to.
+ */
+ void changeCurrentView(Uml::IDType id);
+
+ /**
+ * Deletes a diagram from the current file.
+ *
+ * @param id The ID of the diagram to delete.
+ */
+ void removeDiagram(Uml::IDType id);
+
+ /**
+ * Used to find a reference to a @ref UMLObject by its ID.
+ *
+ * @param id The @ref UMLObject to find.
+ * @return Pointer to the UMLObject found, or NULL if not found.
+ */
+ UMLObject* findObjectById(Uml::IDType id);
+
+ /**
+ * Used to find a @ref UMLObject by its type and name.
+ *
+ * @param name The name of the @ref UMLObject to find.
+ * @param type Object_Type of the object to find (optional.)
+ * When the given type is ot_UMLObject the type is
+ * disregarded, i.e. the given name is the only
+ * search criterion.
+ * @param currentObj Object relative to which to search (optional.)
+ * If given then the enclosing scope(s) of this
+ * object are searched before the global scope.
+ * @return Pointer to the UMLObject found, or NULL if not found.
+ */
+ UMLObject* findUMLObject(const QString &name,
+ Uml::Object_Type type = Uml::ot_UMLObject,
+ UMLObject *currentObj = NULL);
+
+ /**
+ * Used to find a reference to a @ref UMLObject given its non-numeric
+ * ID string.
+ * Only used for intermediate processing while loading files
+ * containing objects with non-numeric xmi.id's.
+ *
+ * @param idStr The AuxId for the @ref UMLObject to find.
+ * @return Pointer to the UMLObject found, or NULL if not found.
+ */
+ UMLObject* findObjectByAuxId(const QString &idStr);
+
+ /**
+ * Used to find a @ref UMLClassifier by its name.
+ *
+ * @param name The name of the @ref UMLObject to find.
+ */
+ UMLClassifier * findUMLClassifier (const QString &name);
+
+ /**
+ * Finds a UMLStereotype by its name.
+ *
+ * @param name The name of the UMLStereotype to find.
+ * @return Pointer to the UMLStereotype found, or NULL if not found.
+ */
+ UMLStereotype * findStereotype(const QString &name);
+
+ /**
+ * Finds a view (diagram) by the ID given to method.
+ *
+ * @param id The ID of the view to search for.
+ * @return Pointer to the view found, or NULL if not found.
+ */
+ UMLView * findView(Uml::IDType id);
+
+ /**
+ * Finds a view (diagram) by the type and name given.
+ *
+ * @param type The type of view to find.
+ * @param name The name of the view to find.
+ * @param searchAllScopes Search in all subfolders (default: false.)
+ * @return Pointer to the view found, or NULL if not found.
+ */
+ UMLView * findView(Uml::Diagram_Type type, const QString &name,
+ bool searchAllScopes = false);
+
+ /**
+ * Set the name of this model.
+ */
+ void setName(const QString& name);
+
+ /**
+ * Return the name of this model.
+ */
+ QString getName() const;
+
+ /**
+ * Return the m_modelID (currently this a fixed value:
+ * Umbrello supports only a single document.)
+ */
+ Uml::IDType getModelID() const;
+
+ /**
+ * This method is called for saving the given model as a XMI file.
+ * It is virtual and calls the corresponding saveToXMI() functions
+ * of the derived classes.
+ *
+ * @param file The file to be saved to.
+ */
+ virtual void saveToXMI(QIODevice& file);
+
+ /**
+ * Checks the given XMI file if it was saved with correct Unicode
+ * encoding set or not.
+ *
+ * @param file The file to be checked.
+ */
+ short getEncoding(QIODevice & file);
+
+ /**
+ * Load a given XMI model from a file. If the encoding of the file
+ * is already known it can be passed to the function. If this info
+ * isn't given, loadFromXMI will check which encoding was used.
+ *
+ * @param file The file to be loaded.
+ * @param encode The encoding used.
+ */
+ virtual bool loadFromXMI(QIODevice& file, short encode = ENC_UNKNOWN);
+
+ /**
+ * Ensures the XMI file is a valid UML file.
+ * Currently only checks for metamodel=UML.
+ *
+ * @param headerNode The <XMI.header> node
+ */
+ bool validateXMIHeader(QDomNode& headerNode);
+
+ /**
+ * Loads all UML objects from XMI into the current UMLDoc.
+ *
+ * @return True if operation successful.
+ */
+ bool loadUMLObjectsFromXMI( QDomElement & element );
+
+ /**
+ * Loads umbrello specific extensions from XMI to the UMLDoc.
+ * The extension tags are: "docsettings", "diagrams", "listview",
+ * and "codegeneration".
+ */
+ void loadExtensionsFromXMI(QDomNode & node);
+
+ /**
+ * Loads all diagrams from XMI into the current UMLDoc.
+ *
+ * @return True if operation successful.
+ */
+ bool loadDiagramsFromXMI( QDomNode & node );
+
+ /**
+ * Signal a view/diagram has been renamed.
+ */
+ void signalDiagramRenamed(UMLView * pView );
+
+ /**
+ * Call to remove all the views (diagrams) in the current file.
+ */
+ void removeAllViews();
+
+ /**
+ * Signal that a UMLObject has been created.
+ *
+ * @param o The object that has been created.
+ */
+ void signalUMLObjectCreated(UMLObject * o);
+
+ /**
+ * Returns the datatype folder.
+ *
+ * @return Pointer to the predefined folder for datatypes.
+ */
+ UMLFolder * getDatatypeFolder() {
+ return m_datatypeRoot;
+ }
+
+ /**
+ * Returns a list of the concepts in this UMLDoc.
+ *
+ * @param includeNested Whether to include the concepts from
+ * nested packages (default: true.)
+ * @return List of UML concepts.
+ */
+ UMLClassifierList getConcepts(bool includeNested = true);
+
+ /**
+ * Returns a list of the classes in this UMLDoc.
+ *
+ * @param includeNested Whether to include the concepts from
+ * nested packages (default: true.)
+ * @return List of UML classes.
+ */
+ UMLClassifierList getClasses(bool includeNested = true);
+
+ /**
+ * Returns a list of the classes and interfaces in this UMLDoc.
+ *
+ * @param includeNested Whether to include the concepts from
+ * nested packages (default: true.)
+ * @return List of UML concepts.
+ */
+ UMLClassifierList getClassesAndInterfaces(bool includeNested = true);
+
+ /**
+ * Returns a list of the interfaces in this UMLDoc.
+ *
+ * @param includeNested Whether to include the concepts from
+ * nested packages (default: true.)
+ * @return List of UML interfaces.
+ */
+ UMLClassifierList getInterfaces(bool includeNested = true);
+
+ /**
+ * Returns a list of the datatypes in this UMLDoc.
+ *
+ * @return List of datatypes.
+ */
+ UMLClassifierList getDatatypes();
+
+ /**
+ * Returns a list of the associations in this UMLDoc.
+ *
+ * @return List of UML associations.
+ */
+ UMLAssociationList getAssociations();
+
+ /**
+ * Controls the printing of the program.
+ *
+ * @param pPrinter The printer (object) to use.
+ */
+ void print(KPrinter * pPrinter);
+
+ /**
+ * Return the list of views for this document.
+ *
+ * @return List of UML views.
+ */
+ UMLViewList getViewIterator();
+
+ /**
+ * Assigns an already created UMLObject a new ID.
+ * If the object is a classifier then the operations/attributes
+ * are also assigned new IDs.
+ *
+ * @param Obj Pointer to the UMLObject to add.
+ * @return True if operation successful.
+ */
+ bool assignNewIDs(UMLObject* Obj);
+
+ /**
+ * Adds a UMLObject thats already created but doesn't change
+ * any ids or signal. Use AddUMLObjectPaste if pasting.
+ *
+ * @param object The object to add.
+ * @return True if the object was actually added.
+ */
+ bool addUMLObject(UMLObject * object);
+
+ /**
+ * Adds an already created UMLView to the document, it gets
+ * assigned a new ID, if its name is already in use then the
+ * function appends a number to it to differentiate it from
+ * the others; this number is incremental so if number 1 is in
+ * use then it tries 2 and then 3 and so on
+ *
+ * @param pView Pointer to the UMLView to add.
+ * @return True if operation successful.
+ */
+ bool addUMLView(UMLView * pView );
+
+ /**
+ * Return the predefined root folder of the given type.
+ */
+ UMLFolder *getRootFolder(Uml::Model_Type mt);
+
+ /**
+ * Return the corresponding Model_Type if the given object
+ * is one of the root folders.
+ * When the given object is not one of the root folders then
+ * return Uml::N_MODELTYPES.
+ */
+ Uml::Model_Type rootFolderType(UMLObject *obj);
+
+ /**
+ * Return the currently selected root folder.
+ * This will be an element from the m_root[] array.
+ */
+ UMLFolder *currentRoot();
+
+ /**
+ * Set the current root folder.
+ *
+ * @param rootType The type of the root folder to set.
+ * The element from m_root[] which is indexed
+ * by this type is selected.
+ */
+ void setCurrentRoot(Uml::Model_Type rootType);
+
+ /**
+ * Read property of IDChangeLog* m_pChangeLog.
+ *
+ * @return Pointer to the IDChangeLog object.
+ */
+ virtual IDChangeLog* getChangeLog();
+
+ /**
+ * Closes a paste session, deletes the ChangeLog.
+ */
+ void endPaste();
+
+ /**
+ * Opens a Paste session, deletes the old ChangeLog and
+ * creates an empty one.
+ */
+ void beginPaste();
+
+ /**
+ * Assigns a New ID to an Object, and also logs the assignment
+ * to its internal ChangeLog.
+ *
+ * @param OldID The present ID of the object.
+ * @return The new ID assigned to the object.
+ */
+ Uml::IDType assignNewID(Uml::IDType OldID);
+
+ /**
+ * Returns the documentation for the project.
+ *
+ * @return The documentation text of this UMLDoc.
+ */
+ QString getDocumentation() const {
+ return m_Doc;
+ }
+
+ /**
+ * Sets the documentation for the project.
+ *
+ * @param doc The documentation to set for this UMLDoc.
+ */
+ void setDocumentation(const QString &doc) {
+ m_Doc = doc;
+ }
+
+ /**
+ * Activate all the diagrams/views after loading so all their
+ * widgets keep their IDs.
+ */
+ void activateAllViews();
+
+ /**
+ * Sets the default settings to the given settings.
+ */
+ void settingsChanged(Settings::OptionState optionState);
+
+
+ /**
+ * Returns the version of the old UML files.
+ */
+ int getFileVersion(void) {return version;}
+
+ /**
+ * Performs the undo function, loading the document back to the
+ * state is was before the last addToUndoStack()
+ */
+ void loadUndoData();
+
+ /**
+ * Performs the redo function, loading the document back to the
+ * state is was before the last undo()
+ */
+ void loadRedoData();
+
+ /**
+ * Takes an image of the document and adds it to the UndoStack.
+ * Implemented using the saveToXMI functions.
+ */
+ void addToUndoStack();
+
+ /**
+ * Removes all entries from the UndoStack and RedoStack and disables the
+ * undo and redo actions.
+ */
+ void clearUndoStack();
+
+ /**
+ * Removes all entries from the RedoStack and disables the
+ * redo action.
+ */
+ void clearRedoStack();
+
+ /**
+ * Returns a name for the new object, appended with a number
+ * if the default name is taken e.g. class diagram, class
+ * diagram_1 etc
+ */
+ QString uniqViewName(const Uml::Diagram_Type type);
+
+ /**
+ * Returns true when loading a document file.
+ */
+ bool loading() const;
+
+ /**
+ * Sets loading boolean flag to the value given.
+ */
+ void setLoading(bool state = true);
+
+ /**
+ * Calls the active code generator to create its default datatypes
+ */
+ void addDefaultDatatypes();
+
+ /**
+ * Add a datatype if it doesn't already exist.
+ * Used by code generators and attribute dialog.
+ */
+ void createDatatype(const QString &name);
+
+ /**
+ * Find a UMLStereotype by its unique ID.
+ */
+ UMLStereotype * findStereotypeById(Uml::IDType id);
+
+ /**
+ * Add a UMLStereotype to the application.
+ */
+ void addStereotype(const UMLStereotype *s);
+
+ /**
+ * Remove a UMLStereotype from the application.
+ */
+ void removeStereotype(const UMLStereotype *s);
+
+ /**
+ * Add a stereotype if it doesn't already exist.
+ * Used by code generators, operations and attribute dialog.
+ */
+ void addDefaultStereotypes();
+
+ /**
+ * Returns a list of the stereotypes in this UMLDoc.
+ *
+ * @return List of UML stereotypes.
+ */
+ const UMLStereotypeList& getStereotypes();
+
+ /**
+ * Write text to the status bar.
+ */
+ void writeToStatusBar(const QString &text);
+
+ /**
+ * Type resolution pass.
+ */
+ void resolveTypes();
+
+private:
+ /**
+ * Sets up the autosave timer.
+ */
+ void initSaveTimer();
+
+ /**
+ * Array of predefined root folders.
+ */
+ UMLFolder *m_root[Uml::N_MODELTYPES];
+ /**
+ * Predefined root folder for datatypes, contained in
+ * m_root[Uml::mt_Logical]
+ */
+ UMLFolder *m_datatypeRoot;
+
+ /**
+ * The UMLDoc is the sole owner of all stereotypes.
+ * UMLStereotype instances are reference counted.
+ * When an UMLStereotype is no longer referenced anywhere,
+ * its refcount drops to zero. It is then removed from the
+ * m_stereoList and it is physically deleted.
+ */
+ UMLStereotypeList m_stereoList;
+
+ QString m_Name; ///< name of this model as stored in the <UML:Model> tag
+ Uml::IDType m_modelID; ///< xmi.id of this model in the <UML:Model>
+ int m_count; ///< auxiliary counter for the progress bar
+ bool m_modified;
+ KURL m_doc_url;
+
+ /**
+ * Contains all the UMLObject id changes of paste session.
+ */
+ IDChangeLog* m_pChangeLog;
+
+ /**
+ * true if the we're loading a new document
+ */
+ bool m_bLoading;
+
+ /**
+ * Documentation for the project.
+ */
+ QString m_Doc;
+
+ /**
+ * Used for autosave
+ */
+ QTimer * m_pAutoSaveTimer;
+
+ /**
+ * Stores the version of old UML files.
+ */
+ int version;
+
+ /**
+ * The stack of images of the document added to each time
+ * something is changed. A QPtrList is used rather than a
+ * QPtrStack to be able to remove the ones off the bottom once
+ * the stack gets too big.
+ */
+ QPtrList<QDataStream> undoStack;
+
+ /**
+ * The stack of images of the document added to each time
+ * undo is called.
+ */
+ QPtrList<QDataStream> redoStack;
+
+ /**
+ * Auxiliary to <docsettings> processing
+ */
+ Uml::IDType m_nViewID;
+
+ /**
+ * True when type resolution pass has been executed.
+ */
+ bool m_bTypesAreResolved;
+
+ /**
+ * the context menu on the tabs,
+ * plugs into umlview::slotMenuSelection()
+ */
+ KPopupMenu* m_pTabPopupMenu;
+
+ /**
+ * Auxiliary variable for currentRoot():
+ * m_pCurrentRoot is only used if UMLApp::app()->getCurrentView()
+ * returns NULL.
+ */
+ UMLFolder * m_pCurrentRoot;
+
+public slots:
+
+ void slotRemoveUMLObject(UMLObject*o);
+
+ /**
+ * Called after a specified time to autosave the document.
+ */
+ void slotAutoSave();
+
+ /**
+ * Make a popup menu for the tabs
+ * signalled from tabWidget's contextMenu()
+ */
+ void slotDiagramPopupMenu(QWidget* umlview, const QPoint& point);
+
+signals:
+ void sigDiagramCreated(Uml::IDType id);
+ void sigDiagramRemoved(Uml::IDType id);
+ void sigDiagramRenamed(Uml::IDType t);
+ void sigDiagramChanged(Uml::Diagram_Type);
+
+ void sigObjectCreated(UMLObject *);
+ void sigObjectRemoved(UMLObject *);
+
+ /**
+ * Reset the status bar.
+ */
+ void sigResetStatusbarProgress();
+
+ /**
+ * Set the total range of the progressbar.
+ *
+ * @param totalSteps Total range of the progressbar (0..totalSteps)
+ */
+ void sigSetStatusbarProgressSteps(int totalSteps);
+
+
+ /**
+ * Set the progress position of the progressbar.
+ *
+ * @param stepPosition The step position to set.
+ */
+ void sigSetStatusbarProgress(int stepPosition);
+
+ /**
+ * Write text to the status bar.
+ */
+ void sigWriteToStatusBar(const QString &text);
+
+ /**
+ * The diagram being displayed has changed.
+ * UMLApp uses this to keep its menu items state up to date.
+ */
+ void sigCurrentViewChanged();
+
+
+};
+
+#endif // UMLDOC_H
diff --git a/umbrello/umbrello/umlentityattributelist.cpp b/umbrello/umbrello/umlentityattributelist.cpp
new file mode 100644
index 00000000..5855859a
--- /dev/null
+++ b/umbrello/umbrello/umlentityattributelist.cpp
@@ -0,0 +1,38 @@
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * copyright (C) 2004-2006 *
+ * Umbrello UML Modeller Authors <uml-devel@uml.sf.net> *
+ ***************************************************************************/
+
+#include "umlentityattributelist.h"
+#include "entityattribute.h"
+#include <kdebug.h>
+#include <klocale.h>
+
+void UMLEntityAttributeList::copyInto(UMLEntityAttributeList* rhs) const {
+ // Don't copy yourself.
+ if (rhs == this) return;
+
+ rhs->clear();
+
+ // Suffering from const; we shall not modify our object.
+ UMLEntityAttributeList* tmp = new UMLEntityAttributeList(*this);
+
+ UMLEntityAttribute* item;
+ for (item = tmp->first(); item; item = tmp->next() ) {
+ rhs->append((UMLEntityAttribute*)item->clone());
+ }
+ delete tmp;
+}
+
+
+UMLEntityAttributeList* UMLEntityAttributeList::clone() const {
+ UMLEntityAttributeList *clone = new UMLEntityAttributeList();
+ copyInto(clone);
+ return clone;
+}
diff --git a/umbrello/umbrello/umlentityattributelist.h b/umbrello/umbrello/umlentityattributelist.h
new file mode 100644
index 00000000..35c0a150
--- /dev/null
+++ b/umbrello/umbrello/umlentityattributelist.h
@@ -0,0 +1,44 @@
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * copyright (C) 2004-2006 *
+ * Umbrello UML Modeller Authors <uml-devel@uml.sf.net> *
+ ***************************************************************************/
+
+#ifndef UMLENTITYATTRIBUTELIST_H
+#define UMLENTITYATTRIBUTELIST_H
+
+#include <qptrlist.h>
+
+// forward declaration
+class UMLEntityAttribute;
+
+//typedef QPtrList<UMLEntityAttribute> UMLEntityAttributeList;
+typedef QPtrListIterator<UMLEntityAttribute> UMLEntityAttributeListIt;
+
+/**
+ * This sub-class adds copyInto and clone to the QPtrList<UMLEntityAttribute>
+ * base class.
+ */
+class UMLEntityAttributeList : public QPtrList<UMLEntityAttribute>
+{
+public:
+
+ /**
+ * Copy the internal presentation of this object into the new
+ * object.
+ */
+ virtual void copyInto (UMLEntityAttributeList* rhs) const;
+
+ /**
+ * Make a clone of this object.
+ */
+ virtual UMLEntityAttributeList* clone() const;
+};
+
+
+#endif
diff --git a/umbrello/umbrello/umlenumliterallist.h b/umbrello/umbrello/umlenumliterallist.h
new file mode 100644
index 00000000..60e03199
--- /dev/null
+++ b/umbrello/umbrello/umlenumliterallist.h
@@ -0,0 +1,23 @@
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * copyright (C) 2004-2007 *
+ * Umbrello UML Modeller Authors <uml-devel@uml.sf.net> *
+ ***************************************************************************/
+
+#ifndef UMLENUMLITERALLIST_H
+#define UMLENUMLITERALLIST_H
+
+#include <qptrlist.h>
+
+// forward declaration
+class UMLEnumLiteral;
+
+typedef QPtrList<UMLEnumLiteral> UMLEnumLiteralList;
+typedef QPtrListIterator<UMLEnumLiteral> UMLEnumLiteralListIt;
+
+#endif
diff --git a/umbrello/umbrello/umllistview.cpp b/umbrello/umbrello/umllistview.cpp
new file mode 100644
index 00000000..d12fed58
--- /dev/null
+++ b/umbrello/umbrello/umllistview.cpp
@@ -0,0 +1,2703 @@
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * copyright (C) 2002-2007 *
+ * Umbrello UML Modeller Authors <uml-devel@uml.sf.net> *
+ ***************************************************************************/
+
+// own header
+#include "umllistview.h"
+
+// qt/kde includes
+#include <qregexp.h>
+#include <qpoint.h>
+#include <qrect.h>
+#include <qevent.h>
+#include <qheader.h>
+#include <qtooltip.h>
+#include <kiconloader.h>
+#include <kapplication.h>
+#include <kdebug.h>
+#include <kfiledialog.h>
+#include <klocale.h>
+#include <kmessagebox.h>
+#include <kstandarddirs.h>
+#include <kinputdialog.h>
+
+// app includes
+#include "actor.h"
+#include "classifier.h"
+#include "package.h"
+#include "folder.h"
+#include "component.h"
+#include "node.h"
+#include "artifact.h"
+#include "enum.h"
+#include "enumliteral.h"
+#include "entity.h"
+#include "docwindow.h"
+#include "listpopupmenu.h"
+#include "template.h"
+#include "operation.h"
+#include "attribute.h"
+#include "entityattribute.h"
+#include "uml.h"
+#include "umldoc.h"
+#include "umllistviewitemlist.h"
+#include "umllistviewitem.h"
+#include "umlview.h"
+#include "umlviewimageexporter.h"
+#include "usecase.h"
+#include "model_utils.h"
+#include "uniqueid.h"
+#include "clipboard/idchangelog.h"
+#include "clipboard/umldrag.h"
+#include "dialogs/classpropdlg.h"
+#include "dialogs/umlattributedialog.h"
+#include "dialogs/umlentityattributedialog.h"
+#include "dialogs/umloperationdialog.h"
+#include "dialogs/umltemplatedialog.h"
+
+#ifdef WANT_LVTOOLTIP
+class LVToolTip : public QToolTip
+{
+public:
+ LVToolTip (QWidget* parent) : QToolTip (parent) {}
+ virtual ~LVToolTip () {}
+protected:
+ /**
+ * Reimplemented from QToolTip for internal reasons.
+ * At classifiers, only the method names are shown in the list view -
+ * we use a tooltip for the full signature display.
+ * Once KListView's tooltip overriding mechanism works, we can kick
+ * this class out.
+ */
+ virtual void maybeTip (const QPoint& pos) {
+ UMLListView *lv = UMLApp::app()->getListView();
+ UMLListViewItem * item = (UMLListViewItem*)lv->itemAt(pos);
+ if (item == NULL)
+ return;
+ UMLObject *obj = item->getUMLObject();
+ if (obj == NULL || obj->getBaseType() != Uml::ot_Operation)
+ return;
+ UMLOperation *op = static_cast<UMLOperation*>(obj);
+ QString text = op->toString(Uml::st_ShowSig);
+ QRect rect = lv->itemRect(item);
+ tip(rect, text);
+ }
+};
+#endif
+
+
+UMLListView::UMLListView(QWidget *parent, const char *name)
+ : KListView(parent,name), m_pMenu(0), m_doc(UMLApp::app()->getDocument())
+{
+ loadPixmaps();
+
+ //setup list view
+ setBackgroundColor(Qt::white);
+ setAcceptDrops(true);
+ setDropVisualizer(false);
+ setItemsMovable(true);
+ setItemsRenameable( true );
+ setSelectionModeExt(FileManager);
+ setFocusPolicy(QWidget::StrongFocus);
+ setDragEnabled(true);
+ setColumnWidthMode( 0, Manual );
+ setDefaultRenameAction( Accept );
+ setResizeMode( LastColumn );
+ header()->setClickEnabled(true);
+ //add columns and initial items
+ addColumn(m_doc->getName());
+
+#ifdef WANT_LVTOOLTIP
+ /* In KDE-3.3, we cannot use KListView's builtin mechanism for
+ overriding the tooltips. Instead, see the above class LVToolTip.
+ setShowToolTips( true );
+ setTooltipColumn( 0 );
+ */
+ (void) new LVToolTip(viewport());
+#endif
+ m_pMenu = NULL;
+ m_bStartedCut = m_bStartedCopy = false;
+ m_bIgnoreCancelRename = true;
+ m_bCreatingChildObject = false;
+ m_rv = NULL;
+ for (int i = 0; i < Uml::N_MODELTYPES; i++)
+ m_lv[i] = NULL;
+ m_datatypeFolder = NULL;
+ //setup slots/signals
+ connect(this, SIGNAL(dropped(QDropEvent *, QListViewItem *, QListViewItem *)),
+ this, SLOT(slotDropped(QDropEvent *, QListViewItem *, QListViewItem *)));
+ connect( this, SIGNAL( collapsed( QListViewItem * ) ),
+ this, SLOT( slotCollapsed( QListViewItem * ) ) );
+ connect( this, SIGNAL( expanded( QListViewItem * ) ), this, SLOT( slotExpanded( QListViewItem * ) ) );
+ connect( UMLApp::app(), SIGNAL( sigCutSuccessful() ), this, SLOT( slotCutSuccessful() ) );
+}
+
+UMLListView::~UMLListView() {}
+
+bool UMLListView::eventFilter(QObject *o, QEvent *e) {
+ if (e->type() != QEvent::MouseButtonPress || !o->isA("QHeader"))
+ return QListView::eventFilter(o, e);
+ QMouseEvent *me = static_cast<QMouseEvent*>(e);
+ if (me->button() == Qt::RightButton) {
+ if (m_pMenu) {
+ m_pMenu->hide();
+ disconnect(m_pMenu, SIGNAL(activated(int)), this, SLOT(popupMenuSel(int)));
+ delete m_pMenu;
+ }
+ m_pMenu = new ListPopupMenu(this, Uml::lvt_Model);
+ m_pMenu->popup(me->globalPos());
+ connect(m_pMenu, SIGNAL(activated(int)), this, SLOT(popupMenuSel(int)));
+ return true;
+ }
+ return QListView::eventFilter(o, e);
+}
+
+void UMLListView::contentsMousePressEvent(QMouseEvent *me) {
+ UMLView *currentView = UMLApp::app()->getCurrentView();
+ if (currentView)
+ currentView->clearSelected();
+ if( me -> state() != Qt::ShiftButton )
+ clearSelection();
+ QPoint pt = this->QScrollView::contentsToViewport( me->pos() );
+ UMLListViewItem * item = (UMLListViewItem*)itemAt(pt);
+ const Qt::ButtonState button = me->button();
+
+ if (!item || (button != Qt::RightButton && button != Qt::LeftButton)) {
+ UMLApp::app()->getDocWindow()->updateDocumentation(true);
+ return;
+ }
+
+ if (button == Qt::LeftButton) {
+ UMLObject *o = item->getUMLObject();
+ if (o)
+ UMLApp::app()->getDocWindow()->showDocumentation(o, false);
+ else
+ UMLApp::app()->getDocWindow()->updateDocumentation(true);
+ }
+ if (button == Qt::RightButton) {
+ if(m_pMenu != 0) {
+ m_pMenu->hide();
+ disconnect(m_pMenu, SIGNAL(activated(int)), this, SLOT(popupMenuSel(int)));
+ delete m_pMenu;
+ m_pMenu = 0;
+ }
+ const Uml::ListView_Type type = item->getType();
+ m_pMenu = new ListPopupMenu(this, type);
+ m_pMenu->popup(me->globalPos());
+ connect(m_pMenu, SIGNAL(activated(int)), this, SLOT(popupMenuSel(int)));
+ }//end if right button
+
+ this->KListView::contentsMousePressEvent(me);
+}
+
+void UMLListView::contentsMouseReleaseEvent(QMouseEvent *me) {
+ if (me->button() != Qt::LeftButton) {
+ this->KListView::contentsMouseReleaseEvent(me);
+ return;
+ }
+ const QPoint pt = this->QScrollView::contentsToViewport( me->pos() );
+ UMLListViewItem *item = dynamic_cast<UMLListViewItem*>(itemAt(pt));
+ if (item == NULL || !Model_Utils::typeIsDiagram(item->getType())) {
+ this->KListView::contentsMouseReleaseEvent(me);
+ return;
+ }
+ // Switch to diagram on mouse release - not on mouse press
+ // because the user might intend a drag-to-note.
+ m_doc->changeCurrentView( item->getID() );
+ UMLApp::app()->getDocWindow()->showDocumentation(m_doc->findView(item->getID()), false);
+ this->KListView::contentsMouseReleaseEvent(me);
+}
+
+void UMLListView::keyPressEvent(QKeyEvent *ke) {
+ UMLView *view = UMLApp::app()->getCurrentView();
+ if (view && view->getSelectCount()) {
+ // Widgets have been selected in the diagram area,
+ // assume they handle the keypress.
+ ke->accept(); // munge and do nothing
+ } else {
+ const int k = ke->key();
+ if (k == Qt::Key_Delete || k == Qt::Key_Backspace) {
+ // delete every selected item
+ UMLListViewItemList selecteditems;
+ getSelectedItemsRoot(selecteditems);
+ UMLListViewItemListIt it(selecteditems);
+ for (UMLListViewItem *item = 0; (item = it.current()); ++it) {
+ deleteItem(dynamic_cast<UMLListViewItem*>(item));
+ }
+ } else {
+ QListView::keyPressEvent(ke); // let parent handle it
+ }
+ }
+}
+
+void UMLListView::popupMenuSel(int sel) {
+ UMLListViewItem * temp = (UMLListViewItem*)currentItem();
+ if ( !temp ) {
+ kDebug() << "popupMenuSel invoked without currently selectedItem" << endl;
+ return;
+ }
+ UMLObject * object = temp -> getUMLObject();
+ Uml::ListView_Type lvt = temp -> getType();
+ Uml::Object_Type umlType = Uml::ot_UMLObject;
+ ListPopupMenu::Menu_Type menuType = (ListPopupMenu::Menu_Type)sel;
+ QString name;
+
+ switch (menuType) {
+ case ListPopupMenu::mt_Class:
+ addNewItem( temp, Uml::lvt_Class );
+ break;
+
+ case ListPopupMenu::mt_Package:
+ addNewItem(temp, Uml::lvt_Package);
+ break;
+
+ case ListPopupMenu::mt_Subsystem:
+ addNewItem(temp, Uml::lvt_Subsystem);
+ break;
+
+ case ListPopupMenu::mt_Component:
+ addNewItem(temp, Uml::lvt_Component);
+ break;
+
+ case ListPopupMenu::mt_Node:
+ addNewItem(temp, Uml::lvt_Node);
+ break;
+
+ case ListPopupMenu::mt_Artifact:
+ addNewItem(temp, Uml::lvt_Artifact);
+ break;
+
+ case ListPopupMenu::mt_Interface:
+ addNewItem(temp, Uml::lvt_Interface);
+ break;
+
+ case ListPopupMenu::mt_Enum:
+ addNewItem(temp, Uml::lvt_Enum);
+ break;
+
+ case ListPopupMenu::mt_EnumLiteral:
+ addNewItem(temp, Uml::lvt_EnumLiteral);
+ break;
+
+ case ListPopupMenu::mt_Template:
+ addNewItem(temp, Uml::lvt_Template);
+ break;
+
+ case ListPopupMenu::mt_Entity:
+ addNewItem(temp, Uml::lvt_Entity);
+ break;
+
+ case ListPopupMenu::mt_Datatype:
+ addNewItem(temp, Uml::lvt_Datatype);
+ break;
+
+ case ListPopupMenu::mt_Actor:
+ addNewItem( temp, Uml::lvt_Actor );
+ break;
+
+ case ListPopupMenu::mt_UseCase:
+ addNewItem( temp, Uml::lvt_UseCase );
+ break;
+
+ case ListPopupMenu::mt_Attribute:
+ addNewItem( temp, Uml::lvt_Attribute );
+ break;
+
+ case ListPopupMenu::mt_EntityAttribute:
+ addNewItem( temp, Uml::lvt_EntityAttribute );
+ break;
+
+ case ListPopupMenu::mt_Operation:
+ addNewItem( temp, Uml::lvt_Operation );
+ break;
+
+ case ListPopupMenu::mt_Import_Classes:
+ UMLApp::app()->slotImportClasses();
+ break;
+
+ case ListPopupMenu::mt_Expand_All:
+ expandAll(temp);
+ break;
+
+ case ListPopupMenu::mt_Collapse_All:
+ collapseAll(temp);
+ break;
+
+ case ListPopupMenu::mt_Export_Image:
+ m_doc->findView(temp->getID())->getImageExporter()->exportView();
+ break;
+
+ case ListPopupMenu::mt_Externalize_Folder:
+ {
+ UMLListViewItem *current = static_cast<UMLListViewItem*>(currentItem());
+ UMLFolder *modelFolder = dynamic_cast<UMLFolder*>(current->getUMLObject());
+ if (modelFolder == NULL) {
+ kError() << "UMLListView::popupMenuSel: modelFolder is NULL" << endl;
+ return;
+ }
+ // configure & show the file dialog
+ const QString rootDir(m_doc->URL().directory());
+ KFileDialog fileDialog(rootDir, "*.xml", this, ":externalize-folder", true);
+ fileDialog.setCaption(i18n("Externalize Folder"));
+ fileDialog.setOperationMode(KFileDialog::Other);
+ // set a sensible default filename
+ QString defaultFilename = current->getText().lower();
+ defaultFilename.replace(QRegExp("\\W+"), "_");
+ defaultFilename.append(".xml"); // default extension
+ fileDialog.setSelection(defaultFilename);
+ fileDialog.exec();
+ KURL selURL = fileDialog.selectedURL();
+ if (selURL.isEmpty())
+ return;
+ QString path = selURL.path();
+ QString fileName = path;
+ if (fileName.startsWith(rootDir)) {
+ fileName.remove(rootDir);
+ } else {
+ // This should be done using a KMessageBox but we currently
+ // cannot add new i18n strings.
+ kError() << "Folder " << path
+ << " must be relative to the main model directory, "
+ << rootDir << endl;
+ return;
+ }
+ QFile file(path);
+ // Warn if file exists.
+ if (file.exists()) {
+ // This should be done using a KMessageBox but we currently
+ // cannot add new i18n strings.
+ kWarning() << "file " << fileName << " already exists!" << endl;
+ kWarning() << "The existing file will be overwritten." << endl;
+ }
+ // Test if file is writable.
+ if (file.open(IO_WriteOnly)) {
+ file.close();
+ } else {
+ KMessageBox::error(0,
+ i18n("There was a problem saving file: %1").arg(fileName),
+ i18n("Save Error"));
+ return;
+ }
+ modelFolder->setFolderFile(fileName);
+ // Recompute text of the folder
+ QString folderText = current->getText();
+ folderText.remove( QRegExp("\\s*\\(.*$") );
+ folderText.append( " (" + fileName + ')' );
+ current->setText(folderText);
+ break;
+ }
+
+ case ListPopupMenu::mt_Internalize_Folder:
+ {
+ UMLListViewItem *current = static_cast<UMLListViewItem*>(currentItem());
+ UMLFolder *modelFolder = dynamic_cast<UMLFolder*>(current->getUMLObject());
+ if (modelFolder == NULL) {
+ kError() << "UMLListView::popupMenuSel: modelFolder is NULL" << endl;
+ return;
+ }
+ modelFolder->setFolderFile(QString::null);
+ // Recompute text of the folder
+ QString folderText = current->getText();
+ folderText.remove( QRegExp("\\s*\\(.*$") );
+ current->setText(folderText);
+ break;
+ }
+
+ case ListPopupMenu::mt_Model:
+ {
+ bool ok = false;
+ QString name = KInputDialog::getText( i18n("Enter Model Name"),
+ i18n("Enter the new name of the model:"),
+ m_doc->getName(), &ok, UMLApp::app() );
+ if (ok) {
+ setColumnText(0, name);
+ m_doc->setName(name);
+ }
+ break;
+ }
+
+ case ListPopupMenu::mt_Rename:
+ temp-> startRename(0);
+ break;
+
+ case ListPopupMenu::mt_Delete:
+ deleteItem(temp);
+
+ return;
+ break;
+
+ case ListPopupMenu::mt_Properties:
+ /* first check if we are on a diagram */
+ if( Model_Utils::typeIsDiagram(lvt) ) {
+ UMLView * pView = m_doc->findView( temp->getID() );
+ if( !pView ) {
+ return;
+ }
+ UMLApp::app()->getDocWindow()->updateDocumentation(false);
+ pView->showPropDialog();
+ UMLApp::app()->getDocWindow()->showDocumentation(pView, true);
+ temp->cancelRename(0);
+ return;
+ }
+
+ /* ok, we are on another object, so find out on which one */
+ umlType = object->getBaseType();
+
+ if ( Model_Utils::typeIsCanvasWidget(lvt) ) {
+ object->showProperties(ClassPropDlg::page_gen);
+ } else if(umlType == Uml::ot_Attribute) {
+ // show the attribute dialog
+ UMLAttribute* selectedAttribute = static_cast<UMLAttribute*>(object);
+ UMLAttributeDialog dialog( this, selectedAttribute );
+ dialog.exec();
+ } else if(umlType == Uml::ot_EntityAttribute) {
+ // show the attribute dialog
+ UMLEntityAttribute* selectedAttribute = static_cast<UMLEntityAttribute*>(object);
+ UMLEntityAttributeDialog dialog( this, selectedAttribute );
+ dialog.exec();
+ } else if(umlType == Uml::ot_Operation) {
+ // show the operation dialog
+ UMLOperation* selectedOperation = static_cast<UMLOperation*>(object);
+ UMLOperationDialog dialog( this, selectedOperation );
+ dialog.exec();
+ } else if(umlType == Uml::ot_Template) {
+ // show the template dialog
+ UMLTemplate* selectedTemplate = static_cast<UMLTemplate*>(object);
+ UMLTemplateDialog dialog( this, selectedTemplate );
+ dialog.exec();
+ } else {
+ kWarning() << "calling properties on unknown type" << endl;
+ }
+ temp -> cancelRename( 0 );
+ break;
+
+ case ListPopupMenu::mt_Logical_Folder:
+ addNewItem( temp, Uml::lvt_Logical_Folder );
+ break;
+
+ case ListPopupMenu::mt_UseCase_Folder:
+ addNewItem( temp, Uml::lvt_UseCase_Folder );
+ break;
+
+ case ListPopupMenu::mt_Component_Folder:
+ addNewItem(temp, Uml::lvt_Component_Folder);
+ break;
+
+ case ListPopupMenu::mt_Deployment_Folder:
+ addNewItem(temp, Uml::lvt_Deployment_Folder);
+ break;
+
+ case ListPopupMenu::mt_EntityRelationship_Folder:
+ addNewItem(temp, Uml::lvt_EntityRelationship_Folder);
+ break;
+
+ case ListPopupMenu::mt_Cut:
+ m_bStartedCut = true;
+ m_bStartedCopy = false;
+ UMLApp::app() -> slotEditCut();
+ break;
+
+ case ListPopupMenu::mt_Copy:
+ m_bStartedCut = false;
+ m_bStartedCopy = true;
+ UMLApp::app() -> slotEditCopy();
+ break;
+
+ case ListPopupMenu::mt_Paste:
+ UMLApp::app() -> slotEditPaste();
+ break;
+
+ default:
+ {
+ Uml::Diagram_Type dt = ListPopupMenu::convert_MT_DT(menuType);
+ if (dt == Uml::dt_Undefined) {
+ kWarning() << "UMLListView::popupMenuSel: unknown type"
+ << sel << endl;
+ } else {
+ UMLFolder *f = dynamic_cast<UMLFolder*>(object);
+ if (f == NULL)
+ kError() << "UMLListView::popupMenuSel(" << menuType
+ << "): current item's UMLObject is not a UMLFolder" << endl;
+ else
+ m_doc->createDiagram(f, dt);
+ }
+ }
+ break;
+ }//end switch
+}
+
+UMLListViewItem *UMLListView::findFolderForDiagram(Uml::Diagram_Type dt) {
+ UMLListViewItem *p = static_cast<UMLListViewItem*>(currentItem());
+ if (p && Model_Utils::typeIsFolder(p->getType())
+ && !Model_Utils::typeIsRootView(p->getType())) {
+ return p;
+ }
+ switch (dt) {
+ case Uml::dt_UseCase:
+ p = m_lv[Uml::mt_UseCase];
+ break;
+ case Uml::dt_Component:
+ p = m_lv[Uml::mt_Component];
+ break;
+ case Uml::dt_Deployment:
+ p = m_lv[Uml::mt_Deployment];
+ break;
+ case Uml::dt_EntityRelationship:
+ p = m_lv[Uml::mt_EntityRelationship];
+ break;
+ default:
+ p = m_lv[Uml::mt_Logical];
+ break;
+ }
+ return p;
+}
+
+void UMLListView::slotDiagramCreated( Uml::IDType id ) {
+ if( m_doc->loading() )
+ return;
+ UMLView *v = m_doc -> findView( id );
+ if (!v)
+ return;
+ const Uml::Diagram_Type dt = v->getType();
+ UMLListViewItem * temp = 0, *p = findFolderForDiagram(dt);
+ temp = new UMLListViewItem(p, v->getName(), Model_Utils::convert_DT_LVT(dt), id);
+ setSelected( temp, true );
+ UMLApp::app() -> getDocWindow() -> showDocumentation( v , false );
+}
+
+UMLListViewItem* UMLListView::determineParentItem(UMLObject* object) const {
+ UMLListViewItem* parentItem = NULL;
+ UMLListViewItem* current = (UMLListViewItem*) currentItem();
+ Uml::ListView_Type lvt = Uml::lvt_Unknown;
+ if (current)
+ lvt = current->getType();
+ Uml::Object_Type t = object->getBaseType();
+
+ switch (t) {
+ case Uml::ot_Attribute:
+ case Uml::ot_Operation:
+ case Uml::ot_Template:
+ case Uml::ot_EnumLiteral:
+ case Uml::ot_EntityAttribute:
+ //this will be handled by childObjectAdded
+ return NULL;
+ break;
+ case Uml::ot_Association:
+ case Uml::ot_Role:
+ case Uml::ot_Stereotype:
+ return NULL; // currently no representation in list view
+ break;
+ default:
+ {
+ UMLPackage *pkg = object->getUMLPackage();
+ if (pkg) {
+ UMLListViewItem* pkgItem = findUMLObject(pkg);
+ if (pkgItem == NULL)
+ kError() << "UMLListView::determineParentItem: could not find "
+ << "parent package " << pkg->getName() << endl;
+ else
+ parentItem = pkgItem;
+ } else if ((lvt == Uml::lvt_UseCase_Folder &&
+ (t == Uml::ot_Actor || t == Uml::ot_UseCase))
+ || (lvt == Uml::lvt_Component_Folder && t == Uml::ot_Component)
+ || (lvt == Uml::lvt_Deployment_Folder && t == Uml::ot_Node)
+ || (lvt == Uml::lvt_EntityRelationship_Folder && t == Uml::ot_Entity)) {
+ parentItem = current;
+ } else if (t == Uml::ot_Datatype) {
+ parentItem = m_datatypeFolder;
+ } else {
+ Uml::Model_Type guess = Model_Utils::guessContainer(object);
+ parentItem = m_lv[guess];
+ }
+ }
+ break;
+ }
+ return parentItem;
+}
+
+bool UMLListView::mayHaveChildItems(Uml::Object_Type type) {
+ bool retval = false;
+ switch (type) {
+ case Uml::ot_Class:
+ case Uml::ot_Interface:
+ case Uml::ot_Enum:
+ case Uml::ot_Entity: // CHECK: more?
+ retval = true;
+ break;
+ default:
+ break;
+ }
+ return retval;
+}
+
+void UMLListView::slotObjectCreated(UMLObject* object) {
+ if (m_bCreatingChildObject) {
+ // @todo eliminate futile signal traffic
+ // e.g. we get here thru various indirections from
+ // ClassifierListPage::slot{Up,Down}Clicked()
+ return;
+ }
+ UMLListViewItem* newItem = findUMLObject(object);
+ if (newItem) {
+ kDebug() << "UMLListView::slotObjectCreated(" << object->getName()
+ << ", id= " << ID2STR(object->getID())
+ << "): item already exists." << endl;
+ Uml::Icon_Type icon = Model_Utils::convert_LVT_IT(newItem->getType());
+ newItem->setIcon(icon);
+ return;
+ }
+ UMLListViewItem* parentItem = determineParentItem(object);
+ if (parentItem == NULL)
+ return;
+ Uml::Object_Type type = object->getBaseType();
+
+ connectNewObjectsSlots(object);
+ const Uml::ListView_Type lvt = Model_Utils::convert_OT_LVT(object);
+ QString name = object->getName();
+ if (type == Uml::ot_Folder) {
+ UMLFolder *f = static_cast<UMLFolder*>(object);
+ QString folderFile = f->getFolderFile();
+ if (!folderFile.isEmpty())
+ name.append(" (" + folderFile + ')');
+ }
+ newItem = new UMLListViewItem(parentItem, name, lvt, object);
+ if (mayHaveChildItems(type)) {
+ UMLClassifier *c = static_cast<UMLClassifier*>(object);
+ UMLClassifierListItemList cListItems = c->getFilteredList(Uml::ot_UMLObject);
+ UMLClassifierListItem *cli;
+ for (UMLClassifierListItemListIt it(cListItems); (cli = it.current()) != NULL; ++it)
+ childObjectAdded(cli, c);
+ }
+ if (m_doc->loading())
+ return;
+ ensureItemVisible(newItem);
+ newItem->setOpen(true);
+ clearSelection();
+ setSelected(newItem, true);
+ UMLApp::app()->getDocWindow()->showDocumentation(object, false);
+}
+
+void UMLListView::connectNewObjectsSlots(UMLObject* object) {
+ Uml::Object_Type type = object->getBaseType();
+ switch( type )
+ {
+ case Uml::ot_Class:
+ case Uml::ot_Interface:
+ {
+ UMLClassifier *c = static_cast<UMLClassifier*>(object);
+ connect(c, SIGNAL(attributeAdded(UMLClassifierListItem*)),
+ this, SLOT(childObjectAdded(UMLClassifierListItem*)));
+ connect(c, SIGNAL(attributeRemoved(UMLClassifierListItem*)),
+ this, SLOT(childObjectRemoved(UMLClassifierListItem*)));
+ connect(c, SIGNAL(operationAdded(UMLClassifierListItem*)),
+ this, SLOT(childObjectAdded(UMLClassifierListItem*)));
+ connect(c, SIGNAL(operationRemoved(UMLClassifierListItem*)),
+ this, SLOT(childObjectRemoved(UMLClassifierListItem*)));
+ connect(c, SIGNAL(templateAdded(UMLClassifierListItem*)),
+ this, SLOT(childObjectAdded(UMLClassifierListItem*)));
+ connect(c, SIGNAL(templateRemoved(UMLClassifierListItem*)),
+ this, SLOT(childObjectRemoved(UMLClassifierListItem*)));
+ connect(object,SIGNAL(modified()),this,SLOT(slotObjectChanged()));
+ }
+ break;
+ case Uml::ot_Enum:
+ {
+ UMLEnum *e = static_cast<UMLEnum*>(object);
+ connect(e, SIGNAL(enumLiteralAdded(UMLClassifierListItem*)),
+ this, SLOT(childObjectAdded(UMLClassifierListItem*)));
+ connect(e, SIGNAL(enumLiteralRemoved(UMLClassifierListItem*)),
+ this, SLOT(childObjectRemoved(UMLClassifierListItem*)));
+ }
+ connect(object,SIGNAL(modified()),this,SLOT(slotObjectChanged()));
+ break;
+ case Uml::ot_Entity:
+ {
+ UMLEntity *ent = static_cast<UMLEntity*>(object);
+ connect(ent, SIGNAL(entityAttributeAdded(UMLClassifierListItem*)),
+ this, SLOT(childObjectAdded(UMLClassifierListItem*)));
+ connect(ent, SIGNAL(entityAttributeRemoved(UMLClassifierListItem*)),
+ this, SLOT(childObjectRemoved(UMLClassifierListItem*)));
+ }
+ connect(object,SIGNAL(modified()),this,SLOT(slotObjectChanged()));
+ break;
+ case Uml::ot_Datatype:
+ case Uml::ot_Attribute:
+ case Uml::ot_Operation:
+ case Uml::ot_Template:
+ case Uml::ot_EnumLiteral:
+ case Uml::ot_EntityAttribute:
+ case Uml::ot_Package:
+ case Uml::ot_Actor:
+ case Uml::ot_UseCase:
+ case Uml::ot_Component:
+ case Uml::ot_Artifact:
+ case Uml::ot_Node:
+ case Uml::ot_Folder:
+ connect(object,SIGNAL(modified()),this,SLOT(slotObjectChanged()));
+ break;
+ case Uml::ot_UMLObject:
+ case Uml::ot_Association:
+ case Uml::ot_Stereotype:
+ break;
+ default:
+ kWarning() << "unknown type in connectNewObjectsSlots" << endl;
+ break;
+ }
+}
+
+void UMLListView::slotObjectChanged() {
+ if (m_doc->loading()) { //needed for class wizard
+ return;
+ }
+ UMLObject* obj = const_cast<UMLObject*>( dynamic_cast<const UMLObject*>(sender()) );
+ UMLListViewItem* item = findUMLObject(obj);
+ if(item) {
+ item->updateObject();
+ }
+}
+
+void UMLListView::childObjectAdded(UMLClassifierListItem* obj) {
+ UMLClassifier *parent = const_cast<UMLClassifier*>(dynamic_cast<const UMLClassifier*>(sender()));
+ childObjectAdded(obj, parent);
+}
+
+void UMLListView::childObjectAdded(UMLClassifierListItem* child, UMLClassifier* parent) {
+ if (m_bCreatingChildObject)
+ return;
+ const QString text = child->toString(Uml::st_SigNoVis);
+ UMLListViewItem *childItem = NULL;
+ UMLListViewItem *parentItem = findUMLObject(parent);
+ if (parentItem == NULL) {
+ kDebug() << "UMLListView::childObjectAdded(" << child->getName()
+ << "): parent " << parent->getName()
+ << " does not yet exist, creating it now." << endl;
+ const Uml::ListView_Type lvt = Model_Utils::convert_OT_LVT(parent);
+ parentItem = new UMLListViewItem(m_lv[Uml::mt_Logical], parent->getName(), lvt, parent);
+ } else {
+ childItem = parentItem->findChildObject(child);
+ }
+ if (childItem) {
+ childItem->setText(text);
+ } else {
+ const Uml::ListView_Type lvt = Model_Utils::convert_OT_LVT(child);
+ childItem = new UMLListViewItem(parentItem, text, lvt, child);
+ if (! m_doc->loading()) {
+ ensureItemVisible(childItem);
+ clearSelection();
+ setSelected(childItem, true);
+ }
+ connectNewObjectsSlots(child);
+ }
+}
+
+void UMLListView::childObjectRemoved(UMLClassifierListItem* obj) {
+ UMLClassifier *parent = const_cast<UMLClassifier*>(dynamic_cast<const UMLClassifier*>(sender()));
+ UMLListViewItem *parentItem = findUMLObject(parent);
+ if (parentItem == NULL) {
+ kError() << "UMLListView::childObjectRemoved(" << obj->getName()
+ << "): cannot find parent UMLListViewItem" << endl;
+ return;
+ }
+ parentItem->deleteChildItem(obj);
+}
+
+void UMLListView::slotDiagramRenamed(Uml::IDType id) {
+ UMLListViewItem* temp;
+ UMLView* v = m_doc->findView(id);
+ if ((temp = findView(v)) == NULL) {
+ kError() << "UMLListView::slotDiagramRenamed: UMLDoc::findView("
+ << ID2STR(id) << ") returns NULL" << endl;
+ return;
+ }
+ temp->setText( v->getName() );
+}
+
+void UMLListView::setDocument(UMLDoc *d) {
+ if( m_doc && m_doc != d)
+ {
+ //disconnect signals from old doc and reset view
+ }
+ m_doc = d;
+
+ connect(m_doc, SIGNAL(sigDiagramCreated(Uml::IDType)), this, SLOT(slotDiagramCreated(Uml::IDType)));
+ connect(m_doc, SIGNAL(sigDiagramRemoved(Uml::IDType)), this, SLOT(slotDiagramRemoved(Uml::IDType)));
+ connect(m_doc, SIGNAL(sigDiagramRenamed(Uml::IDType)), this, SLOT(slotDiagramRenamed(Uml::IDType)));
+ connect(m_doc, SIGNAL(sigObjectCreated(UMLObject *)), this, SLOT(slotObjectCreated(UMLObject *)));
+ connect(m_doc, SIGNAL(sigObjectRemoved(UMLObject *)), this, SLOT(slotObjectRemoved(UMLObject *)));
+}
+
+void UMLListView::slotObjectRemoved(UMLObject* object) {
+ if (m_doc->loading()) { //needed for class wizard
+ return;
+ }
+ disconnect(object,SIGNAL(modified()),this,SLOT(slotObjectChanged()));
+ UMLListViewItem* item = findItem(object->getID());
+ delete item;
+ UMLApp::app()->getDocWindow()->updateDocumentation(true);
+}
+
+void UMLListView::slotDiagramRemoved(Uml::IDType id) {
+ UMLListViewItem* item = findItem(id);
+ delete item;
+ UMLApp::app()->getDocWindow()->updateDocumentation(true);
+}
+
+QDragObject* UMLListView::dragObject() {
+ UMLListViewItemList selecteditems;
+ getSelectedItems(selecteditems);
+ selecteditems.setAutoDelete( false );
+ UMLListViewItemListIt it(selecteditems);
+ UMLListViewItem * item = 0;
+ UMLListViewItemList list;
+ list.setAutoDelete( false );
+ while((item=it.current()) != 0) {
+ ++it;
+ Uml::ListView_Type type = item->getType();
+ if (!Model_Utils::typeIsCanvasWidget(type) && !Model_Utils::typeIsDiagram(type)
+ && !Model_Utils::typeIsClassifierList(type)) {
+ return 0;
+ }
+ list.append(item);
+ }
+ UMLDrag *t = new UMLDrag(list, this);
+
+ return t;
+}
+
+void UMLListView::startDrag() {
+ QDragObject *o = dragObject();
+ if (o)
+ o->dragCopy();
+}
+
+UMLListViewItem * UMLListView::findUMLObjectInFolder(UMLListViewItem* folder, UMLObject* obj) {
+ UMLListViewItem *item = static_cast<UMLListViewItem *>(folder->firstChild());
+ while(item)
+ {
+ switch(item->getType())
+ {
+ case Uml::lvt_Actor :
+ case Uml::lvt_UseCase :
+ case Uml::lvt_Class :
+ case Uml::lvt_Package :
+ case Uml::lvt_Subsystem :
+ case Uml::lvt_Component :
+ case Uml::lvt_Node :
+ case Uml::lvt_Artifact :
+ case Uml::lvt_Interface :
+ case Uml::lvt_Datatype :
+ case Uml::lvt_Enum :
+ case Uml::lvt_Entity :
+ if(item->getUMLObject() == obj)
+ return item;
+ break;
+ case Uml::lvt_Logical_Folder :
+ case Uml::lvt_UseCase_Folder :
+ case Uml::lvt_Component_Folder :
+ case Uml::lvt_Deployment_Folder :
+ case Uml::lvt_EntityRelationship_Folder :
+ case Uml::lvt_Datatype_Folder :
+ {
+ UMLListViewItem *temp = findUMLObjectInFolder(item, obj);
+ if (temp)
+ return temp;
+ }
+ default:
+ break;
+ }
+ item = static_cast<UMLListViewItem *>(item->nextSibling());
+ }
+ return 0;
+}
+
+UMLListViewItem * UMLListView::findUMLObject(const UMLObject *p) const {
+ UMLListViewItem *item = static_cast<UMLListViewItem*>(firstChild());
+ while (item) {
+ UMLListViewItem *testItem = item->findUMLObject(p);
+ if (testItem)
+ return testItem;
+ item = static_cast<UMLListViewItem*>(item->nextSibling());
+ }
+ return item;
+}
+
+void UMLListView::changeIconOf(UMLObject *o, Uml::Icon_Type to) {
+ UMLListViewItem *item = findUMLObject(o);
+ if (item == NULL)
+ return;
+ item->setIcon(to);
+}
+
+UMLListViewItem* UMLListView::findView(UMLView* v) {
+ if (!v) {
+ kWarning() << "returning 0 from UMLListView::findView()" << endl;
+ return 0;
+ }
+ UMLListViewItem* item;
+ Uml::Diagram_Type dType = v->getType();
+ Uml::ListView_Type type = Model_Utils::convert_DT_LVT( dType );
+ Uml::IDType id = v->getID();
+ if (dType == Uml::dt_UseCase) {
+ item = m_lv[Uml::mt_UseCase];
+ } else if (dType == Uml::dt_Component) {
+ item = m_lv[Uml::mt_Component];
+ } else if (dType == Uml::dt_Deployment) {
+ item = m_lv[Uml::mt_Deployment];
+ } else if (dType == Uml::dt_EntityRelationship) {
+ item = m_lv[Uml::mt_EntityRelationship];
+ } else {
+ item = m_lv[Uml::mt_Logical];
+ }
+
+ UMLListViewItem* searchStartItem = (UMLListViewItem *)item->firstChild();
+
+ UMLListViewItem* foundItem = recursiveSearchForView(searchStartItem, type, id);
+
+ if (!foundItem) {
+ kWarning() << "returning 0 at UMLListView::findView" << endl;
+ }
+ return foundItem;
+}
+
+UMLListViewItem* UMLListView::recursiveSearchForView(UMLListViewItem* listViewItem,
+ Uml::ListView_Type type, Uml::IDType id) {
+ while (listViewItem) {
+ if ( Model_Utils::typeIsFolder(listViewItem->getType()) ) {
+ UMLListViewItem* child = (UMLListViewItem *)listViewItem->firstChild();
+ UMLListViewItem* resultListViewItem = recursiveSearchForView(child, type, id);
+ if (resultListViewItem) {
+ return resultListViewItem;
+ }
+ } else {
+ if(listViewItem->getType() == type && listViewItem->getID() == id) {
+ return listViewItem;
+ }
+ }
+ listViewItem = (UMLListViewItem*)listViewItem->nextSibling();
+ }
+ return 0;
+}
+
+UMLListViewItem* UMLListView::findItem(Uml::IDType id) {
+ UMLListViewItem *temp;
+ QListViewItemIterator it(this);
+ for( ; (temp = (UMLListViewItem*)it.current()); ++it ) {
+ UMLListViewItem * item = temp->findItem(id);
+ if (item)
+ return item;
+ }
+ return 0;
+}
+
+
+//
+// This method is called more than once during an instance's lifetime (by UMLDoc)!
+// So we must not allocate any memory before freeing the previously allocated one
+// or do connect()s.
+//
+void UMLListView::init() {
+ if (m_rv == NULL) {
+ m_rv = new UMLListViewItem(this, i18n("Views"), Uml::lvt_View);
+ for (int i = 0; i < Uml::N_MODELTYPES; i++) {
+ Uml::Model_Type mt = (Uml::Model_Type)i;
+ UMLFolder *sysFolder = m_doc->getRootFolder(mt);
+ Uml::ListView_Type lvt = Model_Utils::convert_MT_LVT(mt);
+ m_lv[i] = new UMLListViewItem(m_rv, sysFolder->getLocalName(), lvt, sysFolder);
+ }
+ } else {
+ for (int i = 0; i < Uml::N_MODELTYPES; i++)
+ deleteChildrenOf(m_lv[i]);
+ }
+ UMLFolder *datatypeFolder = m_doc->getDatatypeFolder();
+ m_datatypeFolder = new UMLListViewItem(m_lv[Uml::mt_Logical], datatypeFolder->getLocalName(),
+ Uml::lvt_Datatype_Folder, datatypeFolder);
+ m_rv->setOpen(true);
+ for (int i = 0; i < Uml::N_MODELTYPES; i++)
+ m_lv[i]->setOpen(true);
+ m_datatypeFolder->setOpen(false);
+
+ //setup misc.
+ delete m_pMenu;
+ m_pMenu = 0;
+ m_bStartedCut = m_bStartedCopy = false;
+ m_bIgnoreCancelRename = true;
+ m_bCreatingChildObject = false;
+}
+
+void UMLListView::setView(UMLView * v) {
+ if(!v)
+ return;
+ UMLListViewItem * temp = findView(v);
+ if(temp)
+ setSelected(temp, true);
+}
+
+void UMLListView::contentsMouseDoubleClickEvent(QMouseEvent * me) {
+ UMLListViewItem * item = static_cast<UMLListViewItem *>( currentItem() );
+ if( !item || me -> button() != Qt::LeftButton )
+ return;
+ //see if on view
+ Uml::ListView_Type lvType = item -> getType();
+ if( Model_Utils::typeIsDiagram(lvType) ) {
+ UMLView * pView = m_doc -> findView( item -> getID() );
+ if( !pView )
+ return;
+ UMLApp::app() -> getDocWindow() -> updateDocumentation( false );
+ pView -> showPropDialog();
+ UMLApp::app() -> getDocWindow() -> showDocumentation( pView, true );
+ item -> cancelRename( 0 );
+ return;
+ }
+ //else see if an object
+ UMLObject * object = item -> getUMLObject();
+ //continue only if we are on a UMLObject
+ if(!object)
+ return;
+
+
+ Uml::Object_Type type = object -> getBaseType();
+ int page = ClassPropDlg::page_gen;
+ if(type == Uml::ot_Attribute || type == Uml::ot_Operation)
+ object = (UMLObject *)object -> parent();
+ //set what page to show
+ if(type == Uml::ot_Attribute)
+ page = ClassPropDlg::page_att;
+ else if(type == Uml::ot_Operation)
+ page = ClassPropDlg::page_op;
+ //FIXME for entityattributes
+
+ if(object)
+ object->showProperties(page);
+ item -> cancelRename( 0 );//double click can cause it to go into rename mode.
+}
+
+
+bool UMLListView::acceptDrag(QDropEvent* event) const {
+ QPoint mousePoint = ((UMLListView*)this)->contentsToViewport( event->pos() );
+
+ UMLListViewItem* item = (UMLListViewItem*)itemAt(mousePoint);
+ if(!item) {
+ kDebug() << "UMLListView::acceptDrag: itemAt(mousePoint) returns NULL"
+ << endl;
+ return false;
+ }
+ ((QListView*)this)->setCurrentItem( (QListViewItem*)item );
+
+ UMLDrag::LvTypeAndID_List list;
+ if (! UMLDrag::getClip3TypeAndID(event, list)) {
+ kDebug() << "UMLListView::acceptDrag: UMLDrag::getClip3TypeAndID returns false"
+ << endl;
+ return false;
+ }
+
+ UMLDrag::LvTypeAndID_It it(list);
+ UMLDrag::LvTypeAndID * data = 0;
+ Uml::ListView_Type dstType = item->getType();
+ bool accept = true;
+ while(accept && ((data = it.current()) != 0)) {
+ ++it;
+ Uml::ListView_Type srcType = data->type;
+ switch (srcType) {
+ case Uml::lvt_Class:
+ case Uml::lvt_Package:
+ case Uml::lvt_Interface:
+ case Uml::lvt_Enum:
+ if (dstType == Uml::lvt_Logical_View ||
+ dstType == Uml::lvt_Class ||
+ dstType == Uml::lvt_Package) {
+ accept = !item->isOwnParent(data->id);
+ } else {
+ accept = (dstType == Uml::lvt_Logical_Folder);
+ }
+ break;
+ case Uml::lvt_Attribute:
+ if (dstType == Uml::lvt_Class) {
+ accept = !item->isOwnParent(data->id);
+ }
+ break;
+ case Uml::lvt_EntityAttribute:
+ if (dstType == Uml::lvt_Entity) {
+ accept = !item->isOwnParent(data->id);
+ }
+ break;
+ case Uml::lvt_Operation:
+ if (dstType == Uml::lvt_Class ||
+ dstType == Uml::lvt_Interface) {
+ accept = !item->isOwnParent(data->id);
+ }
+ break;
+ case Uml::lvt_Datatype:
+ accept = (dstType == Uml::lvt_Logical_Folder ||
+ dstType == Uml::lvt_Datatype_Folder ||
+ dstType == Uml::lvt_Class ||
+ dstType == Uml::lvt_Interface ||
+ dstType == Uml::lvt_Package);
+ break;
+ case Uml::lvt_Class_Diagram:
+ case Uml::lvt_Collaboration_Diagram:
+ case Uml::lvt_State_Diagram:
+ case Uml::lvt_Activity_Diagram:
+ case Uml::lvt_Sequence_Diagram:
+ accept = (dstType == Uml::lvt_Logical_Folder ||
+ dstType == Uml::lvt_Logical_View);
+ break;
+ case Uml::lvt_Logical_Folder:
+ if (dstType == Uml::lvt_Logical_Folder) {
+ accept = !item->isOwnParent(data->id);
+ } else {
+ accept = (dstType == Uml::lvt_Logical_View);
+ }
+ break;
+ case Uml::lvt_UseCase_Folder:
+ if (dstType == Uml::lvt_UseCase_Folder) {
+ accept = !item->isOwnParent(data->id);
+ } else {
+ accept = (dstType == Uml::lvt_UseCase_View);
+ }
+ break;
+ case Uml::lvt_Component_Folder:
+ if (dstType == Uml::lvt_Component_Folder) {
+ accept = !item->isOwnParent(data->id);
+ } else {
+ accept = (dstType == Uml::lvt_Component_View);
+ }
+ break;
+ case Uml::lvt_Deployment_Folder:
+ if (dstType == Uml::lvt_Deployment_Folder) {
+ accept = !item->isOwnParent(data->id);
+ } else {
+ accept = (dstType == Uml::lvt_Deployment_View);
+ }
+ break;
+ case Uml::lvt_EntityRelationship_Folder:
+ if (dstType == Uml::lvt_EntityRelationship_Folder) {
+ accept = !item->isOwnParent(data->id);
+ } else {
+ accept = (dstType == Uml::lvt_EntityRelationship_Model);
+ }
+ break;
+ case Uml::lvt_Actor:
+ case Uml::lvt_UseCase:
+ case Uml::lvt_UseCase_Diagram:
+ accept = (dstType == Uml::lvt_UseCase_Folder ||
+ dstType == Uml::lvt_UseCase_View);
+ break;
+ case Uml::lvt_Subsystem:
+ accept = (dstType == Uml::lvt_Component_Folder ||
+ dstType == Uml::lvt_Subsystem);
+ break;
+ case Uml::lvt_Component:
+ accept = (dstType == Uml::lvt_Component_Folder ||
+ dstType == Uml::lvt_Component ||
+ dstType == Uml::lvt_Subsystem);
+ break;
+ case Uml::lvt_Artifact:
+ case Uml::lvt_Component_Diagram:
+ accept = (dstType == Uml::lvt_Component_Folder ||
+ dstType == Uml::lvt_Component_View);
+ break;
+ case Uml::lvt_Node:
+ case Uml::lvt_Deployment_Diagram:
+ accept = (dstType == Uml::lvt_Deployment_Folder);
+ break;
+ case Uml::lvt_Entity:
+ case Uml::lvt_EntityRelationship_Diagram:
+ accept = (dstType == Uml::lvt_EntityRelationship_Folder);
+ break;
+ default:
+ accept = false;
+ break;
+ }
+ }
+
+ //kDebug() << "UMLListView::acceptDrag: dstType = " << dstType
+ // << ", accept=" << accept << endl;
+ return accept;
+}
+
+void UMLListView::addAtContainer(UMLListViewItem *item, UMLListViewItem *parent) {
+ UMLCanvasObject *o = static_cast<UMLCanvasObject*>(item->getUMLObject());
+ if (o == NULL) {
+ kDebug() << "UMLListView::addAtContainer(" << item->getText()
+ << "): item's UMLObject is NULL" << endl;
+ } else if (Model_Utils::typeIsContainer(parent->getType())) {
+ /**** TBC: Do this here?
+ If yes then remove that logic at the callers
+ and rename this method to moveAtContainer()
+ UMLPackage *oldPkg = o->getUMLPackage();
+ if (oldPkg)
+ oldPkg->removeObject(o);
+ *********/
+ UMLPackage *pkg = static_cast<UMLPackage*>(parent->getUMLObject());
+ o->setUMLPackage(pkg);
+ pkg->addObject(o);
+ } else {
+ kError() << "UMLListView::addAtContainer(" << item->getText()
+ << "): parent type is " << parent->getType() << endl;
+ }
+ UMLView *currentView = UMLApp::app()->getCurrentView();
+ if (currentView)
+ currentView->updateContainment(o);
+}
+
+UMLListViewItem * UMLListView::moveObject(Uml::IDType srcId, Uml::ListView_Type srcType,
+ UMLListViewItem *newParent) {
+ if (newParent == NULL)
+ return NULL;
+ UMLListViewItem * move = findItem( srcId );
+ if (move == NULL)
+ return NULL;
+
+ UMLObject *newParentObj = NULL;
+ // Remove the source object at the old parent package.
+ UMLObject *srcObj = m_doc->findObjectById(srcId);
+ if (srcObj) {
+ newParentObj = newParent->getUMLObject();
+ if (srcObj == newParentObj) {
+ kError() << "UMLListView::moveObject(" << srcObj->getName()
+ << "): Cannot move onto self" << endl;
+ return NULL;
+ }
+ UMLPackage *srcPkg = srcObj->getUMLPackage();
+ if (srcPkg) {
+ if (srcPkg == newParentObj) {
+ kError() << "UMLListView::moveObject(" << srcObj->getName()
+ << "): Object is already in target package" << endl;
+ return NULL;
+ }
+ srcPkg->removeObject(srcObj);
+ }
+ }
+
+ Uml::ListView_Type newParentType = newParent->getType();
+ kDebug() << "UMLListView::moveObject: newParentType is " << newParentType << endl;
+ UMLListViewItem *newItem = NULL;
+
+ //make sure trying to place in correct location
+ switch (srcType) {
+ case Uml::lvt_UseCase_Folder:
+ case Uml::lvt_Actor:
+ case Uml::lvt_UseCase:
+ case Uml::lvt_UseCase_Diagram:
+ if (newParentType == Uml::lvt_UseCase_Folder ||
+ newParentType == Uml::lvt_UseCase_View) {
+ newItem = move->deepCopy(newParent);
+ if (m_doc->loading()) // deletion is not safe while loading
+ move->setVisible(false); // (the <listview> XMI may be corrupted)
+ else
+ delete move;
+ addAtContainer(newItem, newParent);
+ }
+ break;
+ case Uml::lvt_Component_Folder:
+ case Uml::lvt_Artifact:
+ case Uml::lvt_Component_Diagram:
+ if (newParentType == Uml::lvt_Component_Folder ||
+ newParentType == Uml::lvt_Component_View) {
+ newItem = move->deepCopy(newParent);
+ if (m_doc->loading()) // deletion is not safe while loading
+ move->setVisible(false); // (the <listview> XMI may be corrupted)
+ else
+ delete move;
+ addAtContainer(newItem, newParent);
+ }
+ break;
+ case Uml::lvt_Subsystem:
+ if (newParentType == Uml::lvt_Component_Folder ||
+ newParentType == Uml::lvt_Component_View ||
+ newParentType == Uml::lvt_Subsystem) {
+ newItem = move->deepCopy(newParent);
+ if (m_doc->loading()) // deletion is not safe while loading
+ move->setVisible(false); // (the <listview> XMI may be corrupted)
+ else
+ delete move;
+ addAtContainer(newItem, newParent);
+ }
+ break;
+ case Uml::lvt_Component:
+ if (newParentType == Uml::lvt_Component_Folder ||
+ newParentType == Uml::lvt_Component_View ||
+ newParentType == Uml::lvt_Component ||
+ newParentType == Uml::lvt_Subsystem) {
+ newItem = move->deepCopy(newParent);
+ if (m_doc->loading()) // deletion is not safe while loading
+ move->setVisible(false); // (the <listview> XMI may be corrupted)
+ else
+ delete move;
+ addAtContainer(newItem, newParent);
+ }
+ break;
+ case Uml::lvt_Deployment_Folder:
+ case Uml::lvt_Node:
+ case Uml::lvt_Deployment_Diagram:
+ if (newParentType == Uml::lvt_Deployment_Folder ||
+ newParentType == Uml::lvt_Deployment_View) {
+ newItem = move->deepCopy(newParent);
+ if (m_doc->loading()) // deletion is not safe while loading
+ move->setVisible(false); // (the <listview> XMI may be corrupted)
+ else
+ delete move;
+ addAtContainer(newItem, newParent);
+ }
+ break;
+ case Uml::lvt_EntityRelationship_Folder:
+ case Uml::lvt_Entity:
+ case Uml::lvt_EntityRelationship_Diagram:
+ if (newParentType == Uml::lvt_EntityRelationship_Folder ||
+ newParentType == Uml::lvt_EntityRelationship_Model) {
+ newItem = move->deepCopy(newParent);
+ if (m_doc->loading()) // deletion is not safe while loading
+ move->setVisible(false); // (the <listview> XMI may be corrupted)
+ else
+ delete move;
+ addAtContainer(newItem, newParent);
+ }
+ break;
+ case Uml::lvt_Collaboration_Diagram:
+ case Uml::lvt_Class_Diagram:
+ case Uml::lvt_State_Diagram:
+ case Uml::lvt_Activity_Diagram:
+ case Uml::lvt_Sequence_Diagram:
+ case Uml::lvt_Logical_Folder:
+ if (newParentType == Uml::lvt_Logical_Folder ||
+ newParentType == Uml::lvt_Logical_View) {
+ newItem = move->deepCopy(newParent);
+ if (m_doc->loading()) // deletion is not safe while loading
+ move->setVisible(false); // (the <listview> XMI may be corrupted)
+ else
+ delete move;
+ addAtContainer(newItem, newParent);
+ }
+ break;
+ case Uml::lvt_Class:
+ case Uml::lvt_Package:
+ case Uml::lvt_Interface:
+ case Uml::lvt_Enum:
+ case Uml::lvt_Datatype:
+ if (newParentType == Uml::lvt_Logical_Folder ||
+ newParentType == Uml::lvt_Datatype_Folder ||
+ newParentType == Uml::lvt_Logical_View ||
+ newParentType == Uml::lvt_Class ||
+ newParentType == Uml::lvt_Interface ||
+ newParentType == Uml::lvt_Package) {
+ newItem = move->deepCopy(newParent);
+ if (m_doc->loading()) // deletion is not safe while loading
+ move->setVisible(false); // (the <listview> XMI may be corrupted)
+ else
+ delete move;
+ UMLCanvasObject *o = static_cast<UMLCanvasObject*>(newItem->getUMLObject());
+ if (o == NULL) {
+ kDebug() << "moveObject: newItem's UMLObject is NULL" << endl;
+ } else if (newParentObj == NULL) {
+ kError() << "UMLListView::moveObject(" << o->getName()
+ << "): newParentObj is NULL" << endl;
+ } else {
+ UMLPackage *pkg = static_cast<UMLPackage*>(newParentObj);
+ o->setUMLPackage( pkg );
+ pkg->addObject( o );
+ }
+ UMLView *currentView = UMLApp::app()->getCurrentView();
+ if (currentView)
+ currentView->updateContainment(o);
+ }
+ break;
+ case Uml::lvt_Attribute:
+ case Uml::lvt_Operation:
+ if (newParentType == Uml::lvt_Class ||
+ newParentType == Uml::lvt_Interface) {
+ // update list view
+
+ newItem = move->deepCopy(newParent);
+ // we don't delete move right away, it will be deleted in slots,
+ // called by subsequent steps
+ //delete move;
+
+ // update model objects
+ m_bCreatingChildObject = true;
+
+ UMLClassifier *oldParentClassifier = dynamic_cast<UMLClassifier*>(srcObj->parent());
+ UMLClassifier *newParentClassifier = dynamic_cast<UMLClassifier*>(newParentObj);
+ if (srcType == Uml::lvt_Attribute) {
+ UMLAttribute *att = dynamic_cast<UMLAttribute*>(srcObj);
+ // We can't use the existing 'att' directly
+ // because its parent is fixed to the old classifier
+ // and we have no way of changing that:
+ // QObject does not permit changing the parent().
+ if (att == NULL) {
+ kError() << "moveObject internal error: srcObj "
+ << srcObj->getName() << " is not a UMLAttribute" << endl;
+ } else if (oldParentClassifier->takeItem(att) == -1) {
+ kError() << "moveObject: oldParentClassifier->takeItem(att "
+ << att->getName() << ") returns NULL" << endl;
+ } else {
+ const QString& nm = att->getName();
+ UMLAttribute *newAtt = newParentClassifier->createAttribute(nm,
+ att->getType(),
+ att->getVisibility(),
+ att->getInitialValue());
+ newItem->setUMLObject(newAtt);
+ newParent->addClassifierListItem( newAtt, newItem );
+
+ connectNewObjectsSlots( newAtt );
+ // Let's not forget to update the DocWindow::m_pObject
+ // because the old one is about to be physically deleted !
+ UMLApp::app()->getDocWindow()->showDocumentation(newAtt, true);
+ delete att;
+ }
+ } else {
+ UMLOperation *op = dynamic_cast<UMLOperation*>(srcObj);
+ // We can't use the existing 'op' directly
+ // because its parent is fixed to the old classifier
+ // and we have no way of changing that:
+ // QObject does not permit changing the parent().
+ if (op && oldParentClassifier->takeItem(op) != -1) {
+ bool isExistingOp;
+ Model_Utils::NameAndType_List ntDummyList;
+ // We need to provide a dummy NameAndType_List
+ // else UMLClassifier::createOperation will
+ // bring up an operation dialog.
+ UMLOperation *newOp = newParentClassifier->createOperation(
+ op->getName(), &isExistingOp, &ntDummyList);
+ newOp->setType(op->getType());
+ newOp->setVisibility(op->getVisibility());
+ UMLAttributeList parmList = op->getParmList();
+ for (UMLAttributeListIt plit(parmList); plit.current(); ++plit) {
+ UMLAttribute *parm = plit.current();
+ UMLAttribute *newParm = new UMLAttribute(newParentClassifier,
+ parm->getName(),
+ Uml::id_None,
+ parm->getVisibility(),
+ parm->getType(),
+ parm->getInitialValue());
+ newParm->setParmKind(parm->getParmKind());
+ newOp->addParm(newParm);
+ }
+ newItem->setUMLObject(newOp);
+ newParent->addClassifierListItem( newOp, newItem );
+
+ connectNewObjectsSlots( newOp );
+
+ // Let's not forget to update the DocWindow::m_pObject
+ // because the old one is about to be physically deleted !
+ UMLApp::app()->getDocWindow()->showDocumentation(newOp, true);
+ delete op;
+ } else {
+ kError() << "moveObject: oldParentClassifier->takeItem(op) returns NULL"
+ << endl;
+ }
+ }
+ m_bCreatingChildObject = false;
+ }
+ break;
+ default:
+ break;
+ }
+ return newItem;
+}
+
+void UMLListView::slotDropped(QDropEvent* de, QListViewItem* /* parent */, QListViewItem* item) {
+ item = (UMLListViewItem *)currentItem();
+ if(!item) {
+ kDebug() << "UMLListView::slotDropped: item is NULL - doing nothing" << endl;
+ return;
+ }
+ UMLDrag::LvTypeAndID_List srcList;
+ if (! UMLDrag::getClip3TypeAndID(de, srcList)) {
+ return;
+ }
+ UMLListViewItem *newParent = (UMLListViewItem*)item;
+ kDebug() << "slotDropped: newParent->getText() is " << newParent->getText() << endl;
+ UMLDrag::LvTypeAndID_It it(srcList);
+ UMLDrag::LvTypeAndID * src = 0;
+ while((src = it.current()) != 0) {
+ ++it;
+ moveObject(src->id, src->type, newParent);
+ }
+}
+
+int UMLListView::getSelectedItems(UMLListViewItemList &ItemList) {
+ ItemList.setAutoDelete( false );
+ QListViewItemIterator it(this);
+ // iterate through all items of the list view
+ for ( ; it.current(); ++it ) {
+ if ( it.current()->isSelected() ) {
+ UMLListViewItem *item = (UMLListViewItem*)it.current();
+ ItemList.append(item);
+ }
+ }
+ kDebug() << "UMLListView::getSelectedItems: selItems = " << ItemList.count() << endl;
+
+ return (int)ItemList.count();
+}
+
+int UMLListView::getSelectedItemsRoot(UMLListViewItemList &ItemList) {
+ ItemList.setAutoDelete( false );
+ QListViewItemIterator it(this);
+
+ // iterate through all items of the list view
+ for ( ; it.current(); ++it ) {
+ if ( it.current()->isSelected() ) {
+ UMLListViewItem *item = (UMLListViewItem*)it.current();
+ // this is the trick, we select only the item with a parent unselected
+ // since we can't select a child and its grandfather without its parent
+ // we would be able to delete each item individually, without an invalid iterator
+ if (item && item->parent() && item->parent()->isSelected()==false) {
+ ItemList.append(item);
+ }
+ }
+ }
+ kDebug() << "UMLListView::getSelectedItemsRoot: selItems = " << ItemList.count() << endl;
+
+ return (int)ItemList.count();
+}
+
+UMLListViewItem* UMLListView::createDiagramItem(UMLView *v) {
+ Uml::ListView_Type lvt = Model_Utils::convert_DT_LVT(v->getType());
+ UMLListViewItem *parent = NULL;
+ UMLFolder *f = v->getFolder();
+ if (f) {
+ parent = findUMLObject(f);
+ if (parent == NULL)
+ kError() << "UMLListView::createDiagramItem(" << v->getName()
+ << "): findUMLObject(" << f->getName() << ") returns NULL"
+ << endl;
+ } else {
+ kDebug() << "UMLListView::createDiagramItem(" << v->getName()
+ << "): no parent folder set, using predefined folder" << endl;
+ }
+ if (parent == NULL) {
+ parent = determineParentItem(lvt);
+ lvt = Model_Utils::convert_DT_LVT(v->getType());
+ }
+ UMLListViewItem *item = new UMLListViewItem(parent, v->getName(), lvt, v->getID());
+ return item;
+}
+
+/** Creates a new UMLListViewItem from a UMLListViewItem,
+ if parent is null the ListView Decides who is going to be
+ the parent */
+UMLListViewItem* UMLListView::createItem(UMLListViewItem& Data, IDChangeLog& IDChanges,
+ UMLListViewItem* parent /*= 0*/) {
+ UMLObject* pObject = 0;
+ UMLListViewItem* item = 0;
+ Uml::ListView_Type lvt = Data.getType();
+ if(!parent) {
+ parent = determineParentItem(lvt);
+ if (!parent)
+ return 0;
+ }
+
+ switch(lvt) {
+ case Uml::lvt_Actor:
+ case Uml::lvt_UseCase:
+ case Uml::lvt_Class:
+ case Uml::lvt_Package:
+ case Uml::lvt_Subsystem:
+ case Uml::lvt_Component:
+ case Uml::lvt_Node:
+ case Uml::lvt_Artifact:
+ case Uml::lvt_Interface:
+ case Uml::lvt_Datatype:
+ case Uml::lvt_Enum:
+ case Uml::lvt_Entity:
+ case Uml::lvt_Logical_Folder:
+ case Uml::lvt_UseCase_Folder:
+ case Uml::lvt_Component_Folder:
+ case Uml::lvt_Deployment_Folder:
+ case Uml::lvt_EntityRelationship_Folder:
+ /***
+ int newID = IDChanges.findNewID(Data.getID());
+ //if there is no ListViewItem associated with the new ID,
+ //it could exist an Item already asocciated if the user chose to reuse an uml object
+ if(!(item = findItem(newID))) {
+ pObject = m_doc->findObjectById( IDChanges.findNewID(Data.getID()) );
+ item = new UMLListViewItem(parent, Data.getText(), lvt, pObject);
+ } ***/
+ pObject = m_doc->findObjectById( Data.getID() );
+ item = new UMLListViewItem(parent, Data.getText(), lvt, pObject);
+ break;
+ case Uml::lvt_Datatype_Folder:
+ item = new UMLListViewItem(parent, Data.getText(), lvt);
+ break;
+ case Uml::lvt_Attribute:
+ case Uml::lvt_EntityAttribute:
+ case Uml::lvt_Operation:
+ case Uml::lvt_Template:
+ case Uml::lvt_EnumLiteral:
+ {
+ UMLClassifier *pClass = static_cast<UMLClassifier*>(parent->getUMLObject());
+ Uml::IDType newID = IDChanges.findNewID( Data.getID() );
+ pObject = pClass->findChildObjectById(newID);
+ if (pObject) {
+ item = new UMLListViewItem( parent, Data.getText(), lvt, pObject );
+ } else {
+ item = 0;
+ }
+ break;
+ }
+ case Uml::lvt_UseCase_Diagram:
+ case Uml::lvt_Sequence_Diagram:
+ case Uml::lvt_Collaboration_Diagram:
+ case Uml::lvt_Class_Diagram:
+ case Uml::lvt_State_Diagram:
+ case Uml::lvt_Activity_Diagram:
+ case Uml::lvt_Component_Diagram:
+ case Uml::lvt_Deployment_Diagram:
+ case Uml::lvt_EntityRelationship_Diagram:
+ {
+ Uml::IDType newID = IDChanges.findNewID(Data.getID());
+ UMLView* v = m_doc->findView(newID);
+ if (v == NULL) {
+ return NULL;
+ }
+ const Uml::ListView_Type lvt = Model_Utils::convert_DT_LVT(v->getType());
+ item = new UMLListViewItem(parent, v->getName(), lvt, newID);
+ }
+ break;
+ default:
+ kWarning() << "createItem() called on unknown type" << endl;
+ break;
+ }
+ return item;
+}
+
+UMLListViewItem* UMLListView::determineParentItem(Uml::ListView_Type lvt) const {
+ UMLListViewItem* parent = 0;
+ switch (lvt) {
+ case Uml::lvt_Datatype:
+ parent = m_datatypeFolder;
+ break;
+ case Uml::lvt_Actor:
+ case Uml::lvt_UseCase:
+ case Uml::lvt_UseCase_Folder:
+ case Uml::lvt_UseCase_Diagram:
+ parent = m_lv[Uml::mt_UseCase];
+ break;
+ case Uml::lvt_Component_Diagram:
+ case Uml::lvt_Component:
+ case Uml::lvt_Artifact:
+ parent = m_lv[Uml::mt_Component];
+ break;
+ case Uml::lvt_Deployment_Diagram:
+ case Uml::lvt_Node:
+ parent = m_lv[Uml::mt_Deployment];
+ break;
+ case Uml::lvt_EntityRelationship_Diagram:
+ case Uml::lvt_Entity:
+ parent = m_lv[Uml::mt_EntityRelationship];
+ break;
+ default:
+ if (Model_Utils::typeIsDiagram(lvt) || !Model_Utils::typeIsClassifierList(lvt))
+ parent = m_lv[Uml::mt_Logical];
+ break;
+ }
+ return parent;
+}
+
+int UMLListView::getSelectedCount() {
+ QListViewItemIterator it(this);
+ int count = 0;
+ // iterate through all items of the list view
+ for ( ; it.current(); ++it ) {
+ if ( it.current()->isSelected() ) {
+ count++;
+ }
+ }
+
+ return count;
+}
+
+void UMLListView::focusOutEvent ( QFocusEvent * fe) {
+ QFocusEvent::Reason reason = fe->reason();
+ if (reason != QFocusEvent::Popup) {
+ clearSelection();
+ triggerUpdate();
+ }
+ //repaint();
+
+ QListView::focusOutEvent(fe);
+}
+
+Uml::ListView_Type UMLListView::rootViewType(UMLListViewItem *item) {
+ if (item == m_rv)
+ return Uml::lvt_View;
+ if (item == m_lv[Uml::mt_Logical])
+ return Uml::lvt_Logical_View;
+ if (item == m_lv[Uml::mt_UseCase])
+ return Uml::lvt_UseCase_View;
+ if (item == m_lv[Uml::mt_Component])
+ return Uml::lvt_Component_View;
+ if (item == m_lv[Uml::mt_Deployment])
+ return Uml::lvt_Deployment_View;
+ if (item == m_lv[Uml::mt_EntityRelationship])
+ return Uml::lvt_EntityRelationship_Model;
+ UMLListViewItem *parent = dynamic_cast<UMLListViewItem*>(item->parent());
+ if (parent)
+ return rootViewType(parent);
+ return Uml::lvt_Unknown;
+}
+
+QPixmap & UMLListView::getPixmap(Uml::Icon_Type type) {
+ if (type < Uml::it_Home || type >= Uml::N_ICONTYPES) {
+ kWarning() << "getPixmap() called on unknown icon " << type << endl;
+ // you'll know you have a problem if this shows up in the list
+ type = Uml::it_Home;
+ }
+ return m_Pixmaps[type];
+}
+
+void UMLListView::loadPixmaps() {
+ KStandardDirs * dirs = KGlobal::dirs();
+ QString dataDir = dirs -> findResourceDir("data", "umbrello/pics/object.png");
+ dataDir += "/umbrello/pics/";
+
+#define makeBarIcon(iconType, barIcon) m_Pixmaps[iconType] = BarIcon(barIcon)
+ makeBarIcon(Uml::it_Home, "folder_home");
+ makeBarIcon(Uml::it_Folder_Cyan, "folder");
+ makeBarIcon(Uml::it_Folder_Cyan_Open, "folder_open");
+ makeBarIcon(Uml::it_Folder_Green, "folder_green");
+ makeBarIcon(Uml::it_Folder_Green_Open, "folder_green_open");
+ makeBarIcon(Uml::it_Folder_Orange, "folder_orange");
+ makeBarIcon(Uml::it_Folder_Orange_Open, "folder_orange_open");
+ makeBarIcon(Uml::it_Folder_Grey, "folder_grey");
+ makeBarIcon(Uml::it_Folder_Grey_Open, "folder_grey_open");
+ makeBarIcon(Uml::it_Folder_Red, "folder_red");
+ makeBarIcon(Uml::it_Folder_Red_Open, "folder_red_open");
+ makeBarIcon(Uml::it_Folder_Violet, "folder_violet");
+ makeBarIcon(Uml::it_Folder_Violet_Open, "folder_violet_open");
+
+ makeBarIcon(Uml::it_Diagram_Activity, "umbrello_diagram_activity");
+ makeBarIcon(Uml::it_Diagram_Class, "umbrello_diagram_class");
+ makeBarIcon(Uml::it_Diagram_Component, "umbrello_diagram_component");
+ makeBarIcon(Uml::it_Diagram_State, "umbrello_diagram_state");
+ makeBarIcon(Uml::it_Diagram_Sequence, "umbrello_diagram_sequence");
+ makeBarIcon(Uml::it_Diagram_Deployment, "umbrello_diagram_deployment");
+ makeBarIcon(Uml::it_Diagram_EntityRelationship, "umbrello_diagram_deployment");
+ makeBarIcon(Uml::it_Diagram_Usecase, "umbrello_diagram_usecase");
+ makeBarIcon(Uml::it_Diagram_Collaboration, "umbrello_diagram_collaboration");
+#undef makeBarIcon
+
+#define loadPixmap(iconType, pngName) m_Pixmaps[iconType].load(dataDir + pngName)
+ loadPixmap(Uml::it_Diagram, "CVnamespace.png");
+ loadPixmap(Uml::it_Class, "class.png");
+ loadPixmap(Uml::it_Template, "template.png");
+ loadPixmap(Uml::it_Package, "package.png");
+ loadPixmap(Uml::it_Subsystem, "subsystem.png");
+ loadPixmap(Uml::it_Component, "component.png");
+ loadPixmap(Uml::it_Node, "node.png");
+ loadPixmap(Uml::it_Artifact, "artifact.png");
+ loadPixmap(Uml::it_Interface, "interface.png");
+ loadPixmap(Uml::it_Datatype, "datatype.png");
+ loadPixmap(Uml::it_Enum, "enum.png");
+ loadPixmap(Uml::it_Entity, "entity.png");
+ loadPixmap(Uml::it_Actor, "actor.png");
+ loadPixmap(Uml::it_UseCase, "usecase.png");
+ loadPixmap(Uml::it_Public_Method, "CVpublic_meth.png");
+ loadPixmap(Uml::it_Private_Method, "CVprivate_meth.png");
+ loadPixmap(Uml::it_Protected_Method, "CVprotected_meth.png");
+ loadPixmap(Uml::it_Public_Attribute, "CVpublic_var.png");
+ loadPixmap(Uml::it_Private_Attribute, "CVprivate_var.png");
+ loadPixmap(Uml::it_Protected_Attribute, "CVprotected_var.png");
+#undef loadPixmap
+}
+
+bool UMLListView::isExpandable(Uml::ListView_Type lvt) {
+ if (Model_Utils::typeIsRootView(lvt) || Model_Utils::typeIsFolder(lvt))
+ return true;
+ switch (lvt) {
+ case Uml::lvt_Package:
+ case Uml::lvt_Component:
+ case Uml::lvt_Subsystem:
+ return true;
+ break;
+ default:
+ break;
+ }
+ return false;
+}
+
+void UMLListView::slotExpanded( QListViewItem * item ) {
+ UMLListViewItem * myItem= static_cast<UMLListViewItem*>(item);
+ if (isExpandable(myItem->getType()))
+ myItem->updateFolder();
+}
+
+void UMLListView::slotCollapsed( QListViewItem * item ) {
+ UMLListViewItem * myItem = static_cast<UMLListViewItem*>(item);
+ if (isExpandable(myItem->getType()))
+ myItem->updateFolder();
+}
+
+void UMLListView::slotCutSuccessful() {
+ if( m_bStartedCut ) {
+ popupMenuSel( ListPopupMenu::mt_Delete );
+ //deletion code here
+ m_bStartedCut = false;
+ }
+}
+
+void UMLListView::addNewItem(UMLListViewItem *parentItem, Uml::ListView_Type type) {
+ if (type == Uml::lvt_Datatype) {
+ parentItem = m_datatypeFolder;
+ }
+
+ UMLListViewItem * newItem = NULL;
+ parentItem->setOpen( true );
+
+ Uml::Icon_Type icon = Model_Utils::convert_LVT_IT(type);
+
+ QString name;
+ if (Model_Utils::typeIsDiagram(type)) {
+ Uml::Diagram_Type dt = Model_Utils::convert_LVT_DT(type);
+ name = getUniqueDiagramName(dt);
+ newItem = new UMLListViewItem(parentItem, name, type, Uml::id_None);
+ } else {
+ Uml::Object_Type ot = Model_Utils::convert_LVT_OT(type);
+ if (ot == Uml::ot_UMLObject) {
+ kDebug() << "UMLListView::addNewItem: no UMLObject for listview type "
+ << type << endl;
+ return;
+ }
+ UMLPackage *parentPkg =
+ dynamic_cast<UMLPackage*>(parentItem->getUMLObject());
+ if (parentPkg == NULL) {
+ kError() << "UMLListView::addNewItem(type " << type
+ << "): parentPkg is NULL" << endl;
+ return;
+ }
+ if (Model_Utils::typeIsClassifierList(type)) {
+ UMLClassifier *parent = static_cast<UMLClassifier*>(parentPkg);
+ name = parent->uniqChildName(ot);
+ } else {
+ name = Model_Utils::uniqObjectName(ot, parentPkg);
+ }
+ newItem = new UMLListViewItem(parentItem, name, type, (UMLObject*)0);
+ }
+ m_bIgnoreCancelRename = false;
+ newItem->setIcon( icon );
+ newItem->setOpen( true );
+ newItem->setCreating( true );
+ newItem->startRename( 0 ); // calls QListView::ensureItemVisible()
+ // When the user accepts the rename operation, UMLListViewItem::okRename()
+ // is called (automatically by QListViewItem.)
+}
+
+bool UMLListView::itemRenamed( QListViewItem * item , int /*col*/ ) {
+ //if true the item was cancel before this message
+ if( m_bIgnoreCancelRename ) {
+ return true;
+ }
+ m_bIgnoreCancelRename = true;
+ UMLListViewItem * renamedItem = static_cast< UMLListViewItem *>( item ) ;
+ Uml::ListView_Type type = renamedItem -> getType();
+ QString newText = renamedItem -> text( 0 );
+ renamedItem -> setCreating( false );
+
+ // If the type is empty then delete it.
+ if (newText.isEmpty() || newText.contains(QRegExp("^\\s+$"))) {
+ KMessageBox::error(
+ kapp -> mainWidget(),
+ i18n( "The name you entered was invalid.\nCreation process has been canceled." ),
+ i18n( "Name Not Valid" ) );
+ return false;
+ }
+
+ if( !isUnique( renamedItem, newText ) ) {
+ //if operation ask if ok not to be unique i.e overloading
+ if( type == Uml::lvt_Operation ) {
+ if( KMessageBox::warningYesNo(
+ kapp -> mainWidget(),
+ i18n( "The name you entered was not unique.\nIs this what you wanted?" ),
+ i18n( "Name Not Unique" ), i18n("Use Name"), i18n("Enter New Name") ) == KMessageBox::No ) {
+ return false;
+ }
+ } else {
+ KMessageBox::error(
+ kapp -> mainWidget(),
+ i18n( "The name you entered was not unique!\nCreation process has been canceled." ),
+ i18n( "Name Not Unique" ) );
+ return false;
+ }
+ }
+
+ switch( type ) {
+ case Uml::lvt_Actor:
+ case Uml::lvt_Class:
+ case Uml::lvt_Package:
+ case Uml::lvt_Logical_Folder:
+ case Uml::lvt_UseCase_Folder:
+ case Uml::lvt_Component_Folder:
+ case Uml::lvt_Deployment_Folder:
+ case Uml::lvt_EntityRelationship_Folder:
+ case Uml::lvt_Subsystem:
+ case Uml::lvt_Component:
+ case Uml::lvt_Node:
+ case Uml::lvt_Artifact:
+ case Uml::lvt_Interface:
+ case Uml::lvt_Datatype:
+ case Uml::lvt_Enum:
+ case Uml::lvt_Entity:
+ case Uml::lvt_UseCase:
+ {
+ Uml::Object_Type ot = Model_Utils::convert_LVT_OT(type);
+ if (! ot) {
+ kError() << "UMLListView::itemRenamed() internal" << endl;
+ return false;
+ }
+ UMLObject *o = createUMLObject( renamedItem, ot );
+ if (type == Uml::lvt_Subsystem)
+ o->setStereotype("subsystem");
+ else if (Model_Utils::typeIsFolder(type))
+ o->setStereotype("folder");
+ }
+ break;
+
+ case Uml::lvt_Attribute:
+ case Uml::lvt_EntityAttribute:
+ case Uml::lvt_Operation:
+ case Uml::lvt_Template:
+ case Uml::lvt_EnumLiteral:
+ return createChildUMLObject( renamedItem, Model_Utils::convert_LVT_OT(type) );
+ break;
+
+ case Uml::lvt_Class_Diagram:
+ createDiagram( renamedItem, Uml::dt_Class );
+ break;
+
+ case Uml::lvt_UseCase_Diagram:
+ createDiagram( renamedItem, Uml::dt_UseCase );
+ break;
+
+ case Uml::lvt_Sequence_Diagram:
+ createDiagram( renamedItem, Uml::dt_Sequence );
+ break;
+
+ case Uml::lvt_Collaboration_Diagram:
+ createDiagram( renamedItem, Uml::dt_Collaboration );
+ break;
+
+ case Uml::lvt_State_Diagram:
+ createDiagram( renamedItem, Uml::dt_State );
+ break;
+
+ case Uml::lvt_Activity_Diagram:
+ createDiagram( renamedItem, Uml::dt_Activity );
+ break;
+
+ case Uml::lvt_Component_Diagram:
+ createDiagram( renamedItem, Uml::dt_Component );
+ break;
+
+ case Uml::lvt_Deployment_Diagram:
+ createDiagram( renamedItem, Uml::dt_Deployment );
+ break;
+
+ case Uml::lvt_EntityRelationship_Diagram:
+ createDiagram( renamedItem, Uml::dt_EntityRelationship );
+ break;
+
+ default:
+ break;
+ }
+ return true;
+}
+
+UMLObject *UMLListView::createUMLObject( UMLListViewItem * item, Uml::Object_Type type ) {
+ QString name = item -> text( 0 );
+ UMLObject * object = NULL;
+ switch( type ) {
+ case Uml::ot_UseCase:
+ object = new UMLUseCase( name );
+ break;
+
+ case Uml::ot_Actor:
+ object = new UMLActor( name );
+ break;
+
+ case Uml::ot_Class:
+ object = new UMLClassifier( name );
+ break;
+
+ case Uml::ot_Package:
+ object = new UMLPackage( name );
+ break;
+
+ case Uml::ot_Folder:
+ object = new UMLFolder( name );
+ break;
+
+ case Uml::ot_Component:
+ object = new UMLComponent( name );
+ break;
+
+ case Uml::ot_Node:
+ object = new UMLNode( name );
+ break;
+
+ case Uml::ot_Artifact:
+ object = new UMLArtifact( name );
+ break;
+
+ case Uml::ot_Interface:
+ {
+ UMLClassifier *c = new UMLClassifier(name);
+ c->setBaseType(Uml::ot_Interface);
+ object = c;
+ }
+ break;
+
+ case Uml::ot_Datatype:
+ {
+ UMLClassifier *c = new UMLClassifier(name);
+ c->setBaseType(Uml::ot_Datatype);
+ object = c;
+ }
+ break;
+
+ case Uml::ot_Enum:
+ object = new UMLEnum( name );
+ break;
+
+ case Uml::ot_Entity:
+ object = new UMLEntity( name );
+ break;
+
+ default:
+ kWarning() << "creating UML Object of unknown type" << endl;
+ return NULL;
+ }
+
+ UMLListViewItem * parentItem = static_cast<UMLListViewItem *>(item->parent());
+ const Uml::ListView_Type lvt = parentItem->getType();
+ if (! Model_Utils::typeIsContainer(lvt)) {
+ kError() << "UMLListView::createUMLObject(" << object->getName()
+ << "): parentItem (" << lvt << " is not a container" << endl;
+ delete object;
+ return NULL;
+ }
+ UMLPackage *pkg = static_cast<UMLPackage*>(parentItem->getUMLObject());
+ object->setUMLPackage(pkg);
+ pkg->addObject(object);
+ connectNewObjectsSlots(object);
+ item -> setUMLObject( object );
+ item -> setText( name );
+ return object;
+}
+
+bool UMLListView::createChildUMLObject( UMLListViewItem * item, Uml::Object_Type type ) {
+ m_bCreatingChildObject = true;
+ QString text = item->text( 0 );
+ UMLObject* parent = static_cast<UMLListViewItem *>( item->parent() )->getUMLObject();
+ if( !parent ) {
+ kError() << "UMLListView::createChildUMLObject: parent UMLObject is NULL" << endl;
+ m_bCreatingChildObject = false;
+ return false;
+ }
+
+ //kDebug() << "UMLListView::createChildUMLObject (" << text << ")" << endl;
+ UMLObject* newObject = NULL;
+ if ( type == Uml::ot_EnumLiteral ) {
+ UMLEnum *owningEnum = static_cast<UMLEnum*>(parent);
+ newObject = owningEnum->createEnumLiteral(text);
+
+ UMLEnumLiteral* enumLiteral = static_cast<UMLEnumLiteral*>(newObject);
+ text = enumLiteral->toString(Uml::st_SigNoVis);
+ } else if ( type == Uml::ot_Template ) {
+ UMLClassifier *owningClassifier = static_cast<UMLClassifier*>(parent);
+ Model_Utils::NameAndType nt;
+ Model_Utils::Parse_Status st = Model_Utils::parseTemplate(text, nt, owningClassifier);
+ if (st) {
+ KMessageBox::error( kapp->mainWidget(),
+ Model_Utils::psText(st),
+ i18n("Creation canceled") );
+ m_bCreatingChildObject = false;
+ return false;
+ }
+ newObject = owningClassifier->createTemplate(nt.m_name);
+ UMLTemplate *tmplParm = static_cast<UMLTemplate*>(newObject);
+ tmplParm->setType(nt.m_type);
+ text = tmplParm->toString(Uml::st_SigNoVis);
+ } else if (type == Uml::ot_Attribute || type == Uml::ot_EntityAttribute) {
+ UMLClassifier *owningClass = static_cast<UMLClassifier*>(parent);
+ Model_Utils::NameAndType nt;
+ Uml::Visibility vis;
+ Model_Utils::Parse_Status st;
+ st = Model_Utils::parseAttribute(text, nt, owningClass, &vis);
+ if (st) {
+ KMessageBox::error( kapp->mainWidget(),
+ Model_Utils::psText(st),
+ i18n("Creation canceled") );
+ m_bCreatingChildObject = false;
+ return false;
+ }
+ newObject = owningClass->createAttribute(nt.m_name, nt.m_type, vis, nt.m_initialValue);
+ UMLAttribute *att = static_cast<UMLAttribute*>(newObject);
+ att->setParmKind(nt.m_direction);
+ text = att->toString(Uml::st_SigNoVis);
+ } else if ( type == Uml::ot_Operation ) {
+ UMLClassifier *owningClassifier = static_cast<UMLClassifier*>(parent);
+ Model_Utils::OpDescriptor od;
+ Model_Utils::Parse_Status st = Model_Utils::parseOperation(text, od, owningClassifier);
+ if (st) {
+ KMessageBox::error( kapp->mainWidget(),
+ Model_Utils::psText(st),
+ i18n("Creation canceled") );
+ m_bCreatingChildObject = false;
+ return false;
+ }
+ bool isExistingOp = false;
+ newObject = owningClassifier->createOperation(od.m_name, &isExistingOp, &od.m_args);
+ if (newObject == NULL || isExistingOp) {
+ if (isExistingOp)
+ KMessageBox::error(
+ kapp -> mainWidget(),
+ i18n( "The name you entered was not unique!\nCreation process has been canceled." ),
+ i18n( "Name Not Unique" ) );
+ m_bCreatingChildObject = false;
+ return false;
+ }
+ UMLOperation *op = static_cast<UMLOperation*>(newObject);
+ if (od.m_pReturnType) {
+ op->setType(od.m_pReturnType);
+ }
+ text = op->toString(Uml::st_SigNoVis);
+ } else {
+ kError() << "UMLListView::createChildUMLObject called for type "
+ << type << " (ignored)" << endl;
+ m_bCreatingChildObject = false;
+ return false;
+ }
+
+ // make changes to the object visible to this umllistviewitem
+ connectNewObjectsSlots( newObject );
+ item->setUMLObject( newObject );
+ item->setText( text );
+ ensureItemVisible(item);
+
+ // as it's a ClassifierListItem add it to the childObjectMap of the parent
+ UMLClassifierListItem* classifierListItem = static_cast<UMLClassifierListItem*>( newObject );
+ static_cast<UMLListViewItem*>( item->parent() )->addClassifierListItem(classifierListItem, item );
+
+ m_bCreatingChildObject = false;
+
+ if (! m_doc->loading())
+ m_doc->setModified();
+ return true;
+}
+
+void UMLListView::createDiagram( UMLListViewItem * item, Uml::Diagram_Type type ) {
+ QString name = item -> text( 0 );
+ UMLView * view = m_doc -> findView( type, name );
+ if( view ) {
+ delete item;
+ return;
+ }
+ UMLListViewItem *parentItem = static_cast<UMLListViewItem*>(item->parent());
+ UMLFolder *parentFolder = dynamic_cast<UMLFolder*>(parentItem->getUMLObject());
+ if (parentFolder == NULL) {
+ kError() << "UMLListView::createDiagram(" << name
+ << "): parent UMLObject is not a UMLFolder" << endl;
+ delete item;
+ return;
+ }
+ view = new UMLView(parentFolder);
+ view->setName( name );
+ view->setType( type );
+ view->setID( UniqueID::gen() );
+ m_doc -> addView( view );
+ view -> setOptionState( Settings::getOptionState() );
+ item -> setID( view -> getID() );
+ item -> setText( name );
+ view->activate();
+ m_doc -> changeCurrentView( view -> getID() );
+}
+
+QString UMLListView::getUniqueDiagramName(Uml::Diagram_Type type) {
+ return m_doc->uniqViewName(type);
+}
+
+bool UMLListView::isUnique( UMLListViewItem * item, const QString &name ) {
+ UMLListViewItem * parentItem = static_cast<UMLListViewItem *>( item -> parent() );
+ Uml::ListView_Type type = item -> getType();
+ switch( type ) {
+ case Uml::lvt_Class_Diagram:
+ return !m_doc -> findView( Uml::dt_Class, name );
+ break;
+
+ case Uml::lvt_Sequence_Diagram:
+ return !m_doc -> findView( Uml::dt_Sequence, name );
+ break;
+
+ case Uml::lvt_UseCase_Diagram:
+ return !m_doc -> findView( Uml::dt_UseCase, name );
+ break;
+
+ case Uml::lvt_Collaboration_Diagram:
+ return !m_doc -> findView( Uml::dt_Collaboration, name );
+ break;
+
+ case Uml::lvt_State_Diagram:
+ return !m_doc -> findView( Uml::dt_State, name );
+ break;
+
+ case Uml::lvt_Activity_Diagram:
+ return !m_doc -> findView( Uml::dt_Activity, name );
+ break;
+
+ case Uml::lvt_Component_Diagram:
+ return !m_doc->findView(Uml::dt_Component, name);
+ break;
+
+ case Uml::lvt_Deployment_Diagram:
+ return !m_doc->findView(Uml::dt_Deployment, name);
+ break;
+
+ case Uml::lvt_EntityRelationship_Diagram:
+ return !m_doc->findView(Uml::dt_EntityRelationship, name);
+ break;
+
+ case Uml::lvt_Actor:
+ case Uml::lvt_UseCase:
+ case Uml::lvt_Node:
+ case Uml::lvt_Artifact:
+ return !m_doc->findUMLObject( name, Model_Utils::convert_LVT_OT(type) );
+ break;
+
+ case Uml::lvt_Class:
+ case Uml::lvt_Package:
+ case Uml::lvt_Interface:
+ case Uml::lvt_Datatype:
+ case Uml::lvt_Enum:
+ case Uml::lvt_Entity:
+ case Uml::lvt_Component:
+ case Uml::lvt_Subsystem:
+ case Uml::lvt_Logical_Folder:
+ case Uml::lvt_UseCase_Folder:
+ case Uml::lvt_Component_Folder:
+ case Uml::lvt_Deployment_Folder:
+ case Uml::lvt_EntityRelationship_Folder:
+ {
+ Uml::ListView_Type lvt = parentItem->getType();
+ if (!Model_Utils::typeIsContainer(lvt))
+ return (m_doc->findUMLObject(name) == NULL);
+ UMLPackage *pkg = static_cast<UMLPackage*>(parentItem->getUMLObject());
+ if (pkg == NULL) {
+ kError() << "UMLListView::isUnique: internal error - "
+ << "parent listviewitem is package but has no UMLObject" << endl;
+ return true;
+ }
+ return (pkg->findObject(name) == NULL);
+ break;
+ }
+
+ case Uml::lvt_Template:
+ case Uml::lvt_Attribute:
+ case Uml::lvt_EntityAttribute:
+ case Uml::lvt_Operation:
+ case Uml::lvt_EnumLiteral:
+ {
+ UMLClassifier *parent = static_cast<UMLClassifier*>(parentItem->getUMLObject());
+ return (parent->findChildObject(name) == NULL);
+ break;
+ }
+
+ default:
+ break;
+ }
+ return false;
+}
+
+void UMLListView::cancelRename( QListViewItem * item ) {
+ if( !m_bIgnoreCancelRename ) {
+ delete item;
+ m_bIgnoreCancelRename = true;
+ }
+}
+
+void UMLListView::saveToXMI( QDomDocument & qDoc, QDomElement & qElement) {
+ QDomElement listElement = qDoc.createElement( "listview" );
+ m_rv->saveToXMI(qDoc, listElement);
+ qElement.appendChild( listElement );
+}
+
+bool UMLListView::loadFromXMI( QDomElement & element ) {
+ /*
+ deleteChildrenOf( m_ucv );
+ deleteChildrenOf( m_lv );
+ deleteChildrenOf( m_cmpv );
+ deleteChildrenOf( m_dplv );
+ */
+ QDomNode node = element.firstChild();
+ QDomElement domElement = node.toElement();
+ m_doc->writeToStatusBar( i18n("Loading listview...") );
+ while( !domElement.isNull() ) {
+ if( domElement.tagName() == "listitem" ) {
+ QString type = domElement.attribute( "type", "-1" );
+ if( type == "-1" )
+ return false;
+ Uml::ListView_Type lvType = (Uml::ListView_Type)type.toInt();
+ if( lvType == Uml::lvt_View ) {
+ if( !loadChildrenFromXMI( m_rv, domElement ) )
+ return false;
+ } else
+ return false;
+ }
+ node = node.nextSibling();
+ domElement = node.toElement();
+
+ }//end while
+ return true;
+}
+
+bool UMLListView::loadChildrenFromXMI( UMLListViewItem * parent, QDomElement & element ) {
+ QDomNode node = element.firstChild();
+ QDomElement domElement = node.toElement();
+ const QString pfx("UMLListView::loadChildrenFromXMI: ");
+ while( !domElement.isNull() ) {
+ node = domElement.nextSibling();
+ if( domElement.tagName() != "listitem" ) {
+ domElement = node.toElement();
+ continue;
+ }
+ QString id = domElement.attribute( "id", "-1" );
+ QString type = domElement.attribute( "type", "-1" );
+ QString label = domElement.attribute( "label", "" );
+ QString open = domElement.attribute( "open", "1" );
+ if( type == "-1" )
+ return false;
+ Uml::ListView_Type lvType = (Uml::ListView_Type)type.toInt();
+ bool bOpen = (bool)open.toInt();
+ Uml::IDType nID = STR2ID(id);
+ UMLObject * pObject = 0;
+ UMLListViewItem * item = 0;
+ if (nID != Uml::id_None) {
+ // The following is an ad hoc hack for the copy/paste code.
+ // The clip still contains the old children although new
+ // UMLCLassifierListItems have already been created.
+ // If the IDChangeLog finds new IDs this means we are in
+ // copy/paste and need to adjust the child listitems to the
+ // new UMLCLassifierListItems.
+ IDChangeLog *idchanges = m_doc->getChangeLog();
+ if (idchanges != NULL) {
+ Uml::IDType newID = idchanges->findNewID(nID);
+ if (newID != Uml::id_None) {
+ kDebug() << pfx << " using id " << ID2STR(newID)
+ << " instead of " << ID2STR(nID) << endl;
+ nID = newID;
+ }
+ }
+ /************ End of hack for copy/paste code ************/
+
+ pObject = m_doc->findObjectById(nID);
+ if (pObject) {
+ if (label.isEmpty())
+ label = pObject->getName();
+ } else if (Model_Utils::typeIsFolder(lvType)) {
+ // Synthesize the UMLFolder here
+ UMLObject *umlParent = parent->getUMLObject();
+ UMLPackage *parentPkg = dynamic_cast<UMLPackage*>(umlParent);
+ if (parentPkg == NULL) {
+ kError() << pfx << "umlParent(" << umlParent << ") is not a UMLPackage"
+ << endl;
+ domElement = node.toElement();
+ continue;
+ }
+ UMLFolder *f = new UMLFolder(label, nID);
+ f->setUMLPackage(parentPkg);
+ parentPkg->addObject(f);
+ pObject = f;
+ item = new UMLListViewItem(parent, label, lvType, pObject);
+ // Moving all relevant UMLObjects to the new UMLFolder is done below,
+ // in the switch(lvType)
+ }
+ } else if (Model_Utils::typeIsRootView(lvType)) {
+ // Predefined folders did not have their ID set.
+ const Uml::Model_Type mt = Model_Utils::convert_LVT_MT(lvType);
+ nID = m_doc->getRootFolder(mt)->getID();
+ } else if (Model_Utils::typeIsFolder(lvType)) {
+ // Pre-1.2 format: Folders did not have their ID set.
+ // Pull a new ID now.
+ nID = UniqueID::get();
+ } else {
+ kError() << pfx << "item of type " << type << " has no ID, skipping." << endl;
+ domElement = node.toElement();
+ continue;
+ }
+
+ switch( lvType ) {
+ case Uml::lvt_Actor:
+ case Uml::lvt_UseCase:
+ case Uml::lvt_Class:
+ case Uml::lvt_Interface:
+ case Uml::lvt_Datatype:
+ case Uml::lvt_Enum:
+ case Uml::lvt_Entity:
+ case Uml::lvt_Package:
+ case Uml::lvt_Subsystem:
+ case Uml::lvt_Component:
+ case Uml::lvt_Node:
+ case Uml::lvt_Artifact:
+ case Uml::lvt_Logical_Folder:
+ case Uml::lvt_UseCase_Folder:
+ case Uml::lvt_Component_Folder:
+ case Uml::lvt_Deployment_Folder:
+ case Uml::lvt_EntityRelationship_Folder:
+ item = findItem(nID);
+ if (item == NULL) {
+ kError() << pfx << "INTERNAL ERROR: "
+ << "findItem(id " << ID2STR(nID) << ") returns NULL" << endl;
+ /*
+ if (pObject && pObject->getUMLPackage() &&
+ parent->getType() != Uml::lvt_Package) {
+ // Pre-1.2 file format:
+ // Objects were not nested in their packages.
+ // Synthesize the nesting here.
+ UMLPackage *umlpkg = pObject->getUMLPackage();
+ UMLListViewItem *pkgItem = findUMLObject(umlpkg);
+ if (pkgItem == NULL) {
+ kDebug() << pfx << "synthesizing ListViewItem for package "
+ << ID2STR(umlpkg->getID()) << endl;
+ pkgItem = new UMLListViewItem(parent, umlpkg->getName(),
+ Uml::lvt_Package, umlpkg);
+ pkgItem->setOpen(true);
+ }
+ item = new UMLListViewItem(pkgItem, label, lvType, pObject);
+ } else {
+ item = new UMLListViewItem(parent, label, lvType, pObject);
+ }
+ */
+ }
+ else if (parent != item->parent()) {
+ // The existing item was created by the slot event triggered
+ // by the loading of the corresponding model object from the
+ // XMI file.
+ // This early creation is done in order to support the loading
+ // of foreign XMI files that do not have the umbrello specific
+ // <listview> tag.
+ // However, now that we encountered the real <listview> info,
+ // we need to delete the existing item: Its parent is always
+ // one of the default predefined folders, but the actual
+ // listview item might be located in a user created folder.
+ // Thanks to Achim Spangler for spotting the problem.
+ UMLListViewItem *itmParent = dynamic_cast<UMLListViewItem*>(item->parent());
+ kDebug() << pfx << item->getText() << " parent "
+ << parent->getText() << " (" << parent << ") != "
+ << itmParent->getText() << " (" << itmParent << ")" << endl;
+ if (item == m_datatypeFolder && itmParent == m_lv[Uml::mt_Logical]) {
+ kDebug() << pfx << "Reparenting the Datatypes folder is prohibited" << endl;
+ } else {
+ UMLListViewItem *newItem = moveObject(nID, lvType, parent);
+ item = newItem;
+ if (item) {
+ kDebug() << pfx << "Attempted reparenting of " << item->getText()
+ << "(current parent: " << (itmParent ? itmParent->getText() : "NULL")
+ << ", new parent: " << parent->getText() << ")" << endl;
+ }
+ }
+ }
+ break;
+ case Uml::lvt_Attribute:
+ case Uml::lvt_EntityAttribute:
+ case Uml::lvt_Template:
+ case Uml::lvt_Operation:
+ case Uml::lvt_EnumLiteral:
+ item = findItem(nID);
+ if (item == NULL) {
+ kDebug() << pfx << "item " << ID2STR(nID) << " (of type "
+ << lvType << ") does not yet exist..." << endl;
+ UMLObject* umlObject = parent->getUMLObject();
+ if (!umlObject) {
+ kDebug() << "And also the parent->getUMLObject() does not exist" << endl;
+ return false;
+ }
+ if (nID == Uml::id_None) {
+ kWarning() << pfx << "lvtype " << lvType << " has id -1" << endl;
+ } else {
+ UMLClassifier *classifier = dynamic_cast<UMLClassifier*>(umlObject);
+ if (classifier) {
+ umlObject = classifier->findChildObjectById(nID);
+ if (umlObject) {
+ connectNewObjectsSlots(umlObject);
+ label = umlObject->getName();
+ item = new UMLListViewItem( parent, label, lvType, umlObject);
+ } else {
+ kDebug() << pfx << "lvtype " << lvType << " child object "
+ << ID2STR(nID) << " not found" << endl;
+ }
+ } else {
+ kDebug() << pfx << "cast to classifier object failed" << endl;
+ }
+ }
+ }
+ break;
+ case Uml::lvt_Logical_View:
+ item = m_lv[Uml::mt_Logical];
+ break;
+ case Uml::lvt_Datatype_Folder:
+ item = m_datatypeFolder;
+ break;
+ case Uml::lvt_UseCase_View:
+ item = m_lv[Uml::mt_UseCase];
+ break;
+ case Uml::lvt_Component_View:
+ item = m_lv[Uml::mt_Component];
+ break;
+ case Uml::lvt_Deployment_View:
+ item = m_lv[Uml::mt_Deployment];
+ break;
+ case Uml::lvt_EntityRelationship_Model:
+ item = m_lv[Uml::mt_EntityRelationship];
+ break;
+ default:
+ if (Model_Utils::typeIsDiagram(lvType)) {
+ item = new UMLListViewItem( parent, label, lvType, nID );
+ } else {
+ kError() << pfx << "INTERNAL ERROR: unexpected listview type "
+ << lvType << " (ID " << ID2STR(nID) << ")" << endl;
+ }
+ break;
+ }//end switch
+
+ if (item) {
+ item->setOpen( (bool)bOpen );
+ if ( !loadChildrenFromXMI(item, domElement) ) {
+ return false;
+ }
+ } else {
+ kWarning() << "unused list view item " << ID2STR(nID)
+ << " of lvtype " << lvType << endl;
+ }
+ domElement = node.toElement();
+ }//end while
+ return true;
+}
+
+/** Open all items in the list view*/
+void UMLListView::expandAll(QListViewItem *item) {
+ if(!item) item = firstChild();
+ for (item = item->firstChild(); item; item = item->nextSibling()) {
+ item->setOpen(true);
+ }
+}
+/** Close all items in the list view*/
+void UMLListView::collapseAll(QListViewItem *item) {
+ if(!item) item = firstChild();
+ for( item = item->firstChild(); item; item = item->nextSibling())
+ item->setOpen(false);
+}
+
+void UMLListView::setStartedCut(bool startedCut) {
+ m_bStartedCut = startedCut;
+}
+
+void UMLListView::setStartedCopy(bool startedCopy) {
+ m_bStartedCopy = startedCopy;
+}
+
+bool UMLListView::startedCopy() const {
+ return m_bStartedCopy;
+}
+
+UMLListViewItem *UMLListView::rootView(Uml::ListView_Type type) {
+ UMLListViewItem *theView = NULL;
+ switch (type) {
+ case Uml::lvt_View:
+ theView = m_rv;
+ break;
+ case Uml::lvt_Logical_View:
+ theView = m_lv[Uml::mt_Logical];
+ break;
+ case Uml::lvt_UseCase_View:
+ theView = m_lv[Uml::mt_UseCase];
+ break;
+ case Uml::lvt_Component_View:
+ theView = m_lv[Uml::mt_Component];
+ break;
+ case Uml::lvt_Deployment_View:
+ theView = m_lv[Uml::mt_Deployment];
+ break;
+ case Uml::lvt_EntityRelationship_Model:
+ theView = m_lv[Uml::mt_EntityRelationship];
+ break;
+ case Uml::lvt_Datatype_Folder: // @todo fix asymmetric naming
+ theView = m_datatypeFolder;
+ break;
+ default:
+ break;
+ }
+ return theView;
+}
+
+void UMLListView::deleteChildrenOf(QListViewItem* parent) {
+ if ( !parent ) {
+ return;
+ }
+ if (parent == m_lv[Uml::mt_Logical])
+ m_datatypeFolder = NULL;
+ while ( parent->firstChild() ) {
+ delete parent->firstChild();
+ }
+}
+
+void UMLListView::closeDatatypesFolder() {
+ m_datatypeFolder->setOpen(false);
+}
+
+
+bool UMLListView::deleteItem(UMLListViewItem *temp) {
+ if (!temp)
+ return false;
+ UMLObject *object = temp->getUMLObject();
+ Uml::ListView_Type lvt = temp->getType();
+ if ( Model_Utils::typeIsDiagram(lvt) ) {
+ m_doc->removeDiagram( temp->getID() );
+ } else if (temp == m_datatypeFolder) {
+ // we can't delete the datatypeFolder because umbrello will crash without a special handling
+ return false;
+ } else if (Model_Utils::typeIsCanvasWidget(lvt) || Model_Utils::typeIsClassifierList(lvt)) {
+ UMLPackage *nmSpc = dynamic_cast<UMLPackage*>(object);
+ if (nmSpc) {
+ UMLObjectList contained = nmSpc->containedObjects();
+ if (contained.count()) {
+ KMessageBox::error(
+ kapp->mainWidget(),
+ i18n("The folder must be emptied before it can be deleted."),
+ i18n("Folder Not Empty"));
+ return false;
+ }
+ }
+ UMLCanvasObject *canvasObj = dynamic_cast<UMLCanvasObject*>(object);
+ if (canvasObj) {
+ /**
+ * We cannot just delete canvasObj here: What if the object
+ * is still being used by others (for example, as a parameter
+ * or return type of an operation) ?
+ * Deletion should not have been permitted in the first place
+ * if the object still has users - but Umbrello is lacking
+ * that logic.
+ */
+ canvasObj->removeAllChildObjects();
+ }
+ if (object) {
+ m_doc->removeUMLObject(object);
+ // Physical deletion of `temp' will be done by Qt signal, see
+ // UMLDoc::removeUMLObject()
+ } else {
+ delete temp;
+ }
+ } else {
+ kWarning() << "umllistview::listpopupmenu::mt_Delete called with unknown type"
+ << endl;
+ }
+ return true;
+}
+
+
+#include "umllistview.moc"
diff --git a/umbrello/umbrello/umllistview.h b/umbrello/umbrello/umllistview.h
new file mode 100644
index 00000000..5656a537
--- /dev/null
+++ b/umbrello/umbrello/umllistview.h
@@ -0,0 +1,473 @@
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * copyright (C) 2002-2006 *
+ * Umbrello UML Modeller Authors <uml-devel@uml.sf.net> *
+ ***************************************************************************/
+
+#ifndef UMLLISTVIEW_H
+#define UMLLISTVIEW_H
+
+#include <qdom.h>
+#include <qpixmap.h>
+#include <klistview.h>
+#include "umlnamespace.h"
+#include "umllistviewitemlist.h"
+
+/**
+ * This is one of the main classes used in this program.
+ * Information is displayed here in a tree view. No objects are created
+ * here. A call to @ref UMLDoc make any additions/deletion or updates to
+ * objects. This class will then wait for a signal before updating the tree view.
+ *
+ * @short Displays the list view for the program.
+ * @author Paul Hensgen <phensgen@techie.com>
+ * Bugs and comments to uml-devel@lists.sf.net or http://bugs.kde.org
+ */
+
+class QMouseEvent;
+class QContextMenuEvent;
+class QKeyEvent;
+class IDChangeLog;
+class ListPopupMenu;
+class UMLClassifier;
+class UMLDoc;
+class UMLListViewItem;
+class UMLView;
+class UMLObject;
+class UMLClassifierListItem;
+
+class UMLListView : public KListView {
+ Q_OBJECT
+public:
+
+ /**
+ * Constructs the tree view.
+ *
+ * @param parent The parent to this.
+ * @param name The internal name for this class.
+ */
+ UMLListView(QWidget *parent,const char *name);
+
+ /**
+ * Standard deconstructor.
+ */
+ ~UMLListView();
+
+ /**
+ * Sets the document his is associated with. This is important as
+ * this is required as to setup the callbacks.
+ *
+ * @param d The document to associate with this class.
+ */
+ void setDocument(UMLDoc * d);
+
+ /**
+ * Carries out initalisation of attributes in class.
+ */
+ void init();
+
+ /**
+ * Set the current view to the given view.
+ *
+ * @param v The current view.
+ */
+ void setView(UMLView* v);
+
+ /**
+ * Get selected items.
+ *
+ * @param ItemList List of UMLListViewItems returned.
+ * @return The number of selected items.
+ */
+ int getSelectedItems(UMLListViewItemList &ItemList);
+
+ /**
+ * Get selected items, but only root elements selected (without children).
+ *
+ * @param ItemList List of UMLListViewItems returned.
+ * @return The number of selected items.
+ */
+ int getSelectedItemsRoot(UMLListViewItemList &ItemList);
+
+ /**
+ * Create a listview item for an existing diagram.
+ *
+ * @param v The existing diagram.
+ */
+ UMLListViewItem* createDiagramItem(UMLView *v);
+
+ /**
+ * CHECK - This is perhaps redundant since the
+ * UMLListViewItemData => UMLListViewItem merge.
+ * Creates a new UMLListViewItem from a UMLListViewItem, if
+ * parent is null the ListView Decides who is going to be the
+ * parent
+ */
+ UMLListViewItem* createItem(UMLListViewItem& Data, IDChangeLog& IDChanges,
+ UMLListViewItem* parent = 0);
+
+ /**
+ * Find the parent folder for a diagram.
+ * If the currently selected item in the list view is a folder
+ * then that folder is returned as the parent.
+ *
+ * @param dt The Diagram_Type of the diagram.
+ * The type will only be used if there is no currently
+ * selected item, or if the current item is not a folder.
+ * In that case the root folder which is suitable for the
+ * Diagram_Type is returned.
+ * @return Pointer to the parent UMLListViewItem for the diagram.
+ */
+ UMLListViewItem *findFolderForDiagram(Uml::Diagram_Type dt);
+
+ /**
+ * Determine the parent ListViewItem given an UMLObject.
+ *
+ * @param object Pointer to the UMLObject for which to look up the parent.
+ * @return Pointer to the parent UMLListViewItem chosen.
+ * Returns NULL on error (no parent could be determined.)
+ */
+ UMLListViewItem* determineParentItem(UMLObject* object) const;
+
+ /**
+ * Determine the parent ListViewItem given a ListView_Type.
+ * This parent is used for creating new UMLListViewItems.
+ *
+ * @param lvt The ListView_Type for which to lookup the parent.
+ * @return Pointer to the parent UMLListViewItem chosen.
+ */
+ UMLListViewItem* determineParentItem(Uml::ListView_Type lvt) const;
+
+ /**
+ * Return true if the given Object_Type permits child items.
+ * A "child item" is anything that qualifies as a UMLClassifierListItem,
+ * e.g. operations and attributes of classifiers.
+ */
+ static bool mayHaveChildItems(Uml::Object_Type type);
+
+ /**
+ * Return the amount of items selected.
+ */
+ int getSelectedCount();
+
+ /**
+ * Returns the correct pixmap for the given type.
+ */
+ QPixmap & getPixmap( Uml::Icon_Type type );
+
+ /**
+ * Returns the document pointer. Called by the UMLListViewItem class.
+ */
+ UMLDoc * getDocument() {
+ return m_doc;
+ }
+
+ /**
+ * Adds a new item to the tree of the given type under the given parent.
+ * Method will take care of signalling anyone needed on creation of new item.
+ * e.g. UMLDoc if an UMLObject is created.
+ */
+ void addNewItem(UMLListViewItem * parent, Uml::ListView_Type type);
+
+ /**
+ * Find an UMLObject in the listview.
+ *
+ * @param p Pointer to the object to find in the list view.
+ * @return Pointer to the UMLObject found or NULL if not found.
+ */
+ UMLListViewItem * findUMLObject(const UMLObject *p) const;
+
+ /**
+ * Searches through the tree for the item which represents the diagram given
+ * @param v the diagram to search for
+ * @return the item which represents the diagram
+ */
+ UMLListViewItem * findView(UMLView *v);
+
+ /**
+ * Searches through the tree for the item with the given ID.
+ *
+ * @param id The ID to search for.
+ * @return The item with the given ID or NULL if not found.
+ */
+ UMLListViewItem * findItem(Uml::IDType id);
+
+ /**
+ * Returns the corresponding view if the listview type is one of the root views,
+ * Root/Logical/UseCase/Component/Deployment/EntityRelation View.
+ */
+ UMLListViewItem *rootView(Uml::ListView_Type type);
+
+ /**
+ * Changes the icon for the given UMLObject to the given icon.
+ */
+ void changeIconOf(UMLObject *o, Uml::Icon_Type to);
+
+ /**
+ * Creates a UMLObject out of the given list view item.
+ */
+ UMLObject *createUMLObject( UMLListViewItem * item, Uml::Object_Type type );
+
+ /**
+ * Creates a child UMLObject out of the given list view item.
+ */
+ bool createChildUMLObject( UMLListViewItem * item, Uml::Object_Type type );
+
+ /**
+ * Creates a diagram out of the given list view item.
+ */
+ void createDiagram( UMLListViewItem * item, Uml::Diagram_Type type );
+
+ /**
+ * Returns a unique name for a diagram.
+ */
+ QString getUniqueDiagramName( Uml::Diagram_Type type );
+
+ /**
+ * Returns if the given name is unique for the given items type.
+ */
+ bool isUnique( UMLListViewItem * item, const QString &name );
+
+ /**
+ * Cancel rename event has occurred for the given item.
+ */
+ void cancelRename( QListViewItem * item );
+
+ /**
+ * Set the variable m_bStartedCut
+ * to indicate that selection should be deleted
+ * in slotCutSuccessful()
+ */
+ void setStartedCut(bool startedCut);
+
+ /**
+ * Set the variable m_bStartedCopy.
+ * NB: While m_bStartedCut is reset as soon as the Cut operation is done,
+ * the variable m_bStartedCopy is reset much later - upon pasting.
+ */
+ void setStartedCopy(bool startedCopy);
+
+ /**
+ * Return the variable m_bStartedCopy.
+ */
+ bool startedCopy() const;
+
+ /**
+ * Moves an object given is unique ID and listview type to an
+ * other listview parent item.
+ * Also takes care of the corresponding move in the model.
+ */
+ UMLListViewItem * moveObject(Uml::IDType srcId, Uml::ListView_Type srcType,
+ UMLListViewItem *newParent);
+
+ /**
+ * Called for informing the list view that an item was renamed.
+ */
+ bool itemRenamed(QListViewItem* item , int col);
+
+ void closeDatatypesFolder();
+
+ UMLListViewItem *theRootView() { return m_rv; }
+ UMLListViewItem *theLogicalView() { return m_lv[Uml::mt_Logical]; }
+ UMLListViewItem *theUseCaseView() { return m_lv[Uml::mt_UseCase]; }
+ UMLListViewItem *theComponentView() { return m_lv[Uml::mt_Component]; }
+ UMLListViewItem *theDeploymentView() { return m_lv[Uml::mt_Deployment]; }
+ UMLListViewItem *theDatatypeFolder() { return m_datatypeFolder; }
+
+ /**
+ * Determines the root listview type of the given UMLListViewItem.
+ * Starts at the given item, compares it against each of the
+ * predefined root views (Root, Logical, UseCase, Component,
+ * Deployment, EntityRelationship.) Returns the ListView_Type
+ * of the matching root view; if no match then continues the
+ * search using the item's parent, then grandparent, and so forth.
+ * Returns Uml::lvt_Unknown if no match at all is found.
+ */
+ Uml::ListView_Type rootViewType(UMLListViewItem *item);
+
+ void saveToXMI( QDomDocument & qDoc, QDomElement & qElement);
+
+ bool loadFromXMI( QDomElement & element );
+
+ bool loadChildrenFromXMI( UMLListViewItem * parent, QDomElement & element );
+
+protected:
+ UMLListViewItem* m_rv; // root view (home)
+ UMLListViewItem* m_lv[Uml::N_MODELTYPES]; // predefined list view roots
+ UMLListViewItem* m_datatypeFolder;
+ ListPopupMenu * m_pMenu;
+ QString oldText, message;
+ UMLDoc *m_doc;
+ bool m_bStartedCut, m_bStartedCopy, m_bIgnoreCancelRename;
+
+ /**
+ * Used when creating an attribute or an operation to stop it adding a second listViewItem
+ */
+ bool m_bCreatingChildObject;
+
+ QPixmap m_Pixmaps[Uml::N_ICONTYPES];
+
+ bool eventFilter(QObject *o, QEvent *e);
+ void contentsMouseReleaseEvent(QMouseEvent * me);
+ void contentsMousePressEvent(QMouseEvent *me);
+ void contentsMouseDoubleClickEvent(QMouseEvent * me);
+ void focusOutEvent ( QFocusEvent * fe);
+ QDragObject* dragObject();
+ void startDrag();
+ bool acceptDrag (QDropEvent* event) const;
+ void keyPressEvent(QKeyEvent *);
+
+ /**
+ * This methods looks for a object in a folder an its subfolders recursive.
+ * @param item The folder entry of the list view.
+ * @param o The object to be found in the folder.
+ *
+ * @return The object if found else a NULL pointer.
+ */
+ UMLListViewItem * findUMLObjectInFolder(UMLListViewItem *item, UMLObject *o);
+
+ /**
+ * Return true if the given list view type can be expanded/collapsed.
+ */
+ static bool isExpandable(Uml::ListView_Type lvt);
+
+ /**
+ * Loads the pixmaps to use in the list items.
+ */
+ void loadPixmaps();
+
+ /**
+ * Deletes all child-items of @p parent.
+ */
+ void deleteChildrenOf( QListViewItem *parent );
+
+ /**
+ * Delete a listview item.
+ * @param temp a non-null UMLListViewItem, for example:
+ (UMLListViewItem*)currentItem()
+ * @return true if correctly deleted
+ */
+ bool deleteItem( UMLListViewItem *temp );
+
+ /**
+ * Adds a new operation, attribute or template item to a classifier, identical to
+ * childObjectAdded(obj) but with an explicit parent.
+ * @param child the child object
+ * @param parent the parent object
+ */
+ void childObjectAdded(UMLClassifierListItem* child, UMLClassifier* parent);
+
+ /**
+ * Auxiliary method for moveObject(): Adds the model object at the proper
+ * new container (package if nested, UMLDoc if at global level), and
+ * updates the containment relationships in the model.
+ */
+ void addAtContainer(UMLListViewItem *item, UMLListViewItem *parent);
+
+public slots:
+
+ /**
+ * Creates a new item to represent a new diagram
+ * @param id the id of the new diagram
+ */
+ void slotDiagramCreated(Uml::IDType id);
+
+ /**
+ * renames a diagram in the list view
+ * @param id the id of the renamed diagram
+ */
+ void slotDiagramRenamed(Uml::IDType id);
+
+ /**
+ * Creates a new list view item and connects the appropriate signals/slots
+ * @param object the newly created object
+ */
+ void slotObjectCreated(UMLObject* object);
+
+ /**
+ * connect some signals into slots in the list view for newly created UMLObjects
+ */
+ void connectNewObjectsSlots(UMLObject* object);
+
+ /**
+ * Adds a new operation, attribute or template item to a classifier
+ * @param obj the child object
+ */
+ void childObjectAdded(UMLClassifierListItem* obj);
+
+ /**
+ * disconnects signals and removes the list view item
+ * @param object the object about to be removed
+ */
+ void slotObjectRemoved(UMLObject* object);
+
+ /**
+ * deletes the list view item
+ * @param obj the object to remove
+ */
+ void childObjectRemoved(UMLClassifierListItem* obj);
+
+ /**
+ * calls updateObject() on the item representing the sending object
+ * no parameters, uses sender() to work out which object called the slot
+ */
+ void slotObjectChanged();
+
+ /**
+ * removes the item representing a diagram
+ * @param id the id of the diagram
+ */
+ void slotDiagramRemoved(Uml::IDType id);
+
+ /**
+ * Called when a right mouse button menu has an item selected
+ */
+ void popupMenuSel(int sel);
+
+ /**
+ * Something has been dragged and dropped onto the list view
+ */
+ void slotDropped(QDropEvent* de, QListViewItem* parent, QListViewItem* item);
+
+ /**
+ * calls updateFolder() on the item to update the icon to open
+ */
+ void slotExpanded(QListViewItem* item);
+
+ /**
+ * calls updateFolder() on the item to update the icon to closed
+ */
+ void slotCollapsed(QListViewItem* item);
+
+ /**
+ * Open all items in the list view
+ */
+ void expandAll(QListViewItem *item);
+
+ /**
+ * Close all items in the list view
+ */
+ void collapseAll(QListViewItem *item);
+
+ /**
+ * Connects to the signal that @ref UMLApp emits when a
+ * cut operation is successful.
+ */
+ void slotCutSuccessful();
+
+private:
+ /**
+ * Searches the tree for a diagram (view).
+ * Used by findView().
+ */
+ UMLListViewItem* recursiveSearchForView(UMLListViewItem* folder,
+ Uml::ListView_Type type, Uml::IDType id);
+
+};
+
+#endif
diff --git a/umbrello/umbrello/umllistviewitem.cpp b/umbrello/umbrello/umllistviewitem.cpp
new file mode 100644
index 00000000..c24ac853
--- /dev/null
+++ b/umbrello/umbrello/umllistviewitem.cpp
@@ -0,0 +1,696 @@
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * copyright (C) 2002-2007 *
+ * Umbrello UML Modeller Authors <uml-devel@uml.sf.net> *
+ ***************************************************************************/
+
+// own header
+#include "umllistviewitem.h"
+
+// system includes
+#include <cstdlib>
+
+// qt/kde includes
+#include <qfile.h>
+#include <qregexp.h>
+#include <kapplication.h>
+#include <klocale.h>
+#include <kmessagebox.h>
+#include <kdebug.h>
+
+// app includes
+#include "folder.h"
+#include "classifier.h"
+#include "template.h"
+#include "attribute.h"
+#include "operation.h"
+#include "umldoc.h"
+#include "umllistview.h"
+#include "umlobjectlist.h"
+#include "umlview.h"
+#include "model_utils.h"
+#include "uniqueid.h"
+#include "uml.h"
+
+UMLListView* UMLListViewItem::s_pListView = 0;
+
+UMLListViewItem::UMLListViewItem( UMLListView * parent, const QString &name,
+ Uml::ListView_Type t, UMLObject* o)
+ : QListViewItem(parent, name) {
+ init(parent);
+ m_Type = t;
+ m_pObject = o;
+ if (o)
+ m_nId = o->getID();
+ setIcon(Uml::it_Home);
+ setText( name );
+ setRenameEnabled( 0, false );
+}
+
+UMLListViewItem::UMLListViewItem(UMLListView * parent)
+ : QListViewItem(parent) {
+ init(parent);
+ if (parent == NULL)
+ kDebug() << "UMLListViewItem constructor called with a NULL listview parent" << endl;
+}
+
+UMLListViewItem::UMLListViewItem(UMLListViewItem * parent)
+ : QListViewItem(parent) {
+ init();
+}
+
+UMLListViewItem::UMLListViewItem(UMLListViewItem * parent, const QString &name, Uml::ListView_Type t,UMLObject*o)
+ : QListViewItem(parent, name) {
+ init();
+ m_Type = t;
+ m_pObject = o;
+ if( !o ) {
+ m_nId = Uml::id_None;
+ updateFolder();
+ } else {
+ UMLClassifierListItem *umlchild = dynamic_cast<UMLClassifierListItem*>(o);
+ if (umlchild)
+ parent->addClassifierListItem(umlchild, this);
+ updateObject();
+ m_nId = o->getID();
+ }
+ setRenameEnabled( 0, !Model_Utils::typeIsRootView(t) );
+ setText( name );
+}
+
+UMLListViewItem::UMLListViewItem(UMLListViewItem * parent, const QString &name, Uml::ListView_Type t,Uml::IDType id)
+ : QListViewItem(parent, name) {
+ init();
+ m_Type = t;
+ m_nId = id;
+ switch (m_Type) {
+ case Uml::lvt_Collaboration_Diagram:
+ setIcon(Uml::it_Diagram_Collaboration);
+ break;
+ case Uml::lvt_Class_Diagram:
+ setIcon(Uml::it_Diagram_Class);
+ break;
+ case Uml::lvt_State_Diagram:
+ setIcon(Uml::it_Diagram_State);
+ break;
+ case Uml::lvt_Activity_Diagram:
+ setIcon(Uml::it_Diagram_Activity);
+ break;
+ case Uml::lvt_Sequence_Diagram:
+ setIcon(Uml::it_Diagram_Sequence);
+ break;
+ case Uml::lvt_Component_Diagram:
+ setIcon(Uml::it_Diagram_Component);
+ break;
+ case Uml::lvt_Deployment_Diagram:
+ setIcon(Uml::it_Diagram_Deployment);
+ break;
+ case Uml::lvt_UseCase_Diagram:
+ setIcon(Uml::it_Diagram_Usecase);
+ break;
+ default:
+ setIcon(Uml::it_Diagram);
+ }
+ /*
+ Constructor also used by folder so just make sure we don't need to
+ to set pixmap to folder. doesn't hurt diagrams.
+ */
+ updateFolder();
+ setText( name );
+ setRenameEnabled( 0, true );
+}
+
+UMLListViewItem::~UMLListViewItem() {}
+
+void UMLListViewItem::init(UMLListView * parent) {
+ m_Type = Uml::lvt_Unknown;
+ m_bCreating = false;
+ m_pObject = NULL;
+ m_nId = Uml::id_None;
+ m_nChildren = 0;
+ if (s_pListView == NULL && parent != NULL) {
+ kDebug() << "UMLListViewItem::init: s_pListView still NULL, setting it now "
+ << endl;
+ s_pListView = parent;
+ }
+}
+
+Uml::ListView_Type UMLListViewItem::getType() const {
+ return m_Type;
+}
+
+void UMLListViewItem::addClassifierListItem(UMLClassifierListItem *child, UMLListViewItem *childItem) {
+ m_comap[child] = childItem;
+}
+
+void UMLListViewItem::deleteChildItem(UMLClassifierListItem *child) {
+ UMLListViewItem *childItem = findChildObject(child);
+ if (childItem == NULL) {
+ kError() << "UMLListViewItem::deleteChildItem(" << child->getName()
+ << "): child listview item not found" << endl;
+ return;
+ }
+ m_comap.remove(child);
+ delete childItem;
+}
+
+Uml::IDType UMLListViewItem::getID() const {
+ if (m_pObject)
+ return m_pObject->getID();
+ return m_nId;
+}
+
+void UMLListViewItem::setID(Uml::IDType id) {
+ if (m_pObject) {
+ Uml::IDType oid = m_pObject->getID();
+ if (id != Uml::id_None && oid != id)
+ kDebug() << "UMLListViewItem::setID: new id " << ID2STR(id)
+ << " does not agree with object id " << ID2STR(oid) << endl;
+ }
+ m_nId = id;
+}
+
+bool UMLListViewItem::isOwnParent(Uml::IDType listViewItemID) {
+ QListViewItem *lvi = (QListViewItem*)s_pListView->findItem(listViewItemID);
+ if (lvi == NULL) {
+ kError() << "UMLListViewItem::isOwnParent: ListView->findItem("
+ << ID2STR(listViewItemID) << ") returns NULL" << endl;
+ return true;
+ }
+ for (QListViewItem *self = (QListViewItem*)this; self; self = self->parent()) {
+ if (lvi == self)
+ return true;
+ }
+ return false;
+}
+
+void UMLListViewItem::updateObject() {
+ if( m_pObject == NULL )
+ return;
+
+ Uml::Visibility scope = m_pObject->getVisibility();
+ Uml::Object_Type ot = m_pObject->getBaseType();
+ QString modelObjText = m_pObject->getName();
+ if (Model_Utils::isClassifierListitem(ot)) {
+ UMLClassifierListItem *pNarrowed = static_cast<UMLClassifierListItem*>(m_pObject);
+ modelObjText = pNarrowed->toString(Uml::st_SigNoVis);
+ }
+ setText(modelObjText);
+
+ Uml::Icon_Type icon = Uml::it_Home;
+ switch (ot) {
+ case Uml::ot_Package:
+ if (m_pObject->getStereotype() == "subsystem")
+ icon = Uml::it_Subsystem;
+ else
+ icon = Uml::it_Package;
+ break;
+/*
+ case Uml::ot_Folder:
+ {
+ Uml::ListView_Type lvt = Model_Utils::convert_OT_LVT(m_pObject);
+ icon = Model_Utils::convert_LVT_IT(lvt);
+ }
+ break;
+ */
+ case Uml::ot_Operation:
+ if (scope == Uml::Visibility::Public)
+ icon = Uml::it_Public_Method;
+ else if (scope == Uml::Visibility::Private)
+ icon = Uml::it_Private_Method;
+ else if (scope == Uml::Visibility::Implementation)
+ icon = Uml::it_Private_Method;
+ else
+ icon = Uml::it_Protected_Method;
+ break;
+
+ case Uml::ot_Attribute:
+ case Uml::ot_EntityAttribute:
+ if (scope == Uml::Visibility::Public)
+ icon = Uml::it_Public_Attribute;
+ else if (scope == Uml::Visibility::Private)
+ icon = Uml::it_Private_Attribute;
+ else if (scope == Uml::Visibility::Implementation)
+ icon = Uml::it_Private_Attribute;
+ else
+ icon = Uml::it_Protected_Attribute;
+ break;
+ default:
+ icon = Model_Utils::convert_LVT_IT(m_Type);
+ break;
+ }//end switch
+ if (icon)
+ setIcon(icon);
+}
+
+void UMLListViewItem::updateFolder() {
+ Uml::Icon_Type icon = Model_Utils::convert_LVT_IT(m_Type);
+ if (icon) {
+ if (Model_Utils::typeIsFolder(m_Type))
+ icon = (Uml::Icon_Type)((int)icon + (int)isOpen());
+ setIcon(icon);
+ }
+}
+
+void UMLListViewItem::setOpen( bool open ) {
+ QListViewItem::setOpen( open );
+ updateFolder();
+}
+
+void UMLListViewItem::setText(const QString &newText) {
+ m_Label = newText;
+ QListViewItem::setText(0, newText);
+}
+
+QString UMLListViewItem::getText() const {
+ return m_Label;
+}
+
+void UMLListViewItem::setIcon(Uml::Icon_Type iconType) {
+ setPixmap(0, s_pListView->getPixmap(iconType));
+}
+
+void UMLListViewItem::okRename( int col ) {
+ QListViewItem::okRename( col );
+ UMLDoc* doc = s_pListView->getDocument();
+ if (m_bCreating) {
+ m_bCreating = false;
+ QString savedLabel = m_Label;
+ m_Label = text(col);
+ if ( s_pListView->itemRenamed( this, col ) ) {
+ s_pListView->ensureItemVisible(this);
+ doc->setModified(true);
+ } else {
+ delete this;
+ }
+ return;
+ }
+ QString newText = text( col );
+ if ( newText == m_Label ) {
+ return;
+ }
+ if( newText.isEmpty() ) {
+ cancelRenameWithMsg();
+ return;
+ }
+ switch( m_Type ) {
+ case Uml::lvt_UseCase:
+ case Uml::lvt_Actor:
+ case Uml::lvt_Class:
+ case Uml::lvt_Package:
+ case Uml::lvt_UseCase_Folder:
+ case Uml::lvt_Logical_Folder:
+ case Uml::lvt_Component_Folder:
+ case Uml::lvt_Deployment_Folder:
+ case Uml::lvt_EntityRelationship_Folder:
+ case Uml::lvt_Interface:
+ case Uml::lvt_Datatype:
+ case Uml::lvt_Enum:
+ case Uml::lvt_EnumLiteral:
+ case Uml::lvt_Subsystem:
+ case Uml::lvt_Component:
+ case Uml::lvt_Node:
+ if (m_pObject == NULL || !doc->isUnique(newText)) {
+ cancelRenameWithMsg();
+ return;
+ }
+ m_pObject -> setName( newText );
+ doc->setModified(true);
+ m_Label = newText;
+ break;
+
+ case Uml::lvt_Operation:
+ {
+ if (m_pObject == NULL) {
+ cancelRenameWithMsg();
+ return;
+ }
+ UMLOperation *op = static_cast<UMLOperation*>(m_pObject);
+ UMLClassifier *parent = static_cast<UMLClassifier *>( op -> parent() );
+ Model_Utils::OpDescriptor od;
+ Model_Utils::Parse_Status st = Model_Utils::parseOperation(newText, od, parent);
+ if (st == Model_Utils::PS_OK) {
+ // TODO: Check that no operation with the exact same profile exists.
+ op->setName( od.m_name );
+ op->setType( od.m_pReturnType );
+ UMLAttributeList parmList = op->getParmList();
+ const unsigned newParmListCount = parmList.count();
+ if (newParmListCount > od.m_args.count()) {
+ // Remove parameters at end of of list that no longer exist.
+ for (unsigned i = od.m_args.count(); i < newParmListCount; i++) {
+ UMLAttribute *a = parmList.at(i);
+ op->removeParm(a, false);
+ }
+ }
+ Model_Utils::NameAndType_ListIt lit = od.m_args.begin();
+ for (unsigned i = 0; lit != od.m_args.end(); ++lit, ++i) {
+ const Model_Utils::NameAndType& nm_tp = *lit;
+ UMLAttribute *a;
+ if (i < newParmListCount) {
+ a = parmList.at(i);
+ } else {
+ a = new UMLAttribute(op);
+ a->setID( UniqueID::gen() );
+ }
+ a->setName(nm_tp.m_name);
+ a->setType(nm_tp.m_type);
+ a->setParmKind(nm_tp.m_direction);
+ a->setInitialValue(nm_tp.m_initialValue);
+ if (i >= newParmListCount) {
+ op->addParm(a);
+ }
+ }
+ m_Label = op->toString(Uml::st_SigNoVis);
+ } else {
+ KMessageBox::error( kapp->mainWidget(),
+ Model_Utils::psText(st),
+ i18n("Rename canceled") );
+ }
+ QListViewItem::setText(0, m_Label);
+ break;
+ }
+
+ case Uml::lvt_Attribute:
+ case Uml::lvt_EntityAttribute:
+ {
+ if (m_pObject == NULL) {
+ cancelRenameWithMsg();
+ return;
+ }
+ UMLClassifier *parent = static_cast<UMLClassifier*>(m_pObject->parent());
+ Model_Utils::NameAndType nt;
+ Uml::Visibility vis;
+ Model_Utils::Parse_Status st;
+ st = Model_Utils::parseAttribute(newText, nt, parent, &vis);
+ if (st == Model_Utils::PS_OK) {
+ UMLObject *exists = parent->findChildObject(newText);
+ if (exists) {
+ cancelRenameWithMsg();
+ return;
+ }
+ m_pObject->setName(nt.m_name);
+ UMLAttribute *pAtt = static_cast<UMLAttribute*>(m_pObject);
+ pAtt->setType(nt.m_type);
+ pAtt->setVisibility(vis);
+ pAtt->setParmKind(nt.m_direction);
+ pAtt->setInitialValue(nt.m_initialValue);
+ m_Label = pAtt->toString(Uml::st_SigNoVis);
+ } else {
+ KMessageBox::error( kapp->mainWidget(),
+ Model_Utils::psText(st),
+ i18n("Rename canceled") );
+ }
+ QListViewItem::setText(0, m_Label);
+ break;
+ }
+
+ case Uml::lvt_Template:
+ {
+ if (m_pObject == NULL) {
+ cancelRenameWithMsg();
+ return;
+ }
+ UMLClassifier *parent = static_cast<UMLClassifier*>(m_pObject->parent());
+ Model_Utils::NameAndType nt;
+ Model_Utils::Parse_Status st = Model_Utils::parseTemplate(newText, nt, parent);
+ if (st == Model_Utils::PS_OK) {
+ UMLObject *exists = parent->findChildObject(newText);
+ if (exists) {
+ cancelRenameWithMsg();
+ return;
+ }
+ m_pObject->setName(nt.m_name);
+ UMLTemplate *tmpl = static_cast<UMLTemplate*>(m_pObject);
+ tmpl->setType(nt.m_type);
+ m_Label = tmpl->toString(Uml::st_SigNoVis);
+ } else {
+ KMessageBox::error( kapp->mainWidget(),
+ Model_Utils::psText(st),
+ i18n("Rename canceled") );
+ }
+ QListViewItem::setText(0, m_Label);
+ break;
+ }
+
+ case Uml::lvt_UseCase_Diagram:
+ case Uml::lvt_Class_Diagram:
+ case Uml::lvt_Sequence_Diagram:
+ case Uml::lvt_Collaboration_Diagram:
+ case Uml::lvt_State_Diagram:
+ case Uml::lvt_Activity_Diagram:
+ case Uml::lvt_Component_Diagram:
+ case Uml::lvt_Deployment_Diagram:
+ {
+ UMLView *view = doc -> findView( getID() );
+ if (view == NULL) {
+ cancelRenameWithMsg();
+ return;
+ }
+ UMLView *anotherView = doc -> findView( view->getType(), newText );
+ if( anotherView && anotherView -> getID() == getID() )
+ anotherView = 0;
+ if (anotherView) {
+ cancelRenameWithMsg();
+ return;
+ }
+ view->setName( newText );
+ setText(newText);
+ doc->signalDiagramRenamed(view);
+ break;
+ }
+ default:
+ KMessageBox::error( kapp->mainWidget() ,
+ i18n("Renaming an item of listview type %1 is not yet implemented.").arg(m_Type),
+ i18n("Function Not Implemented") );
+ QListViewItem::setText(0, m_Label);
+ break;
+ }
+ doc->setModified(true);
+}
+
+void UMLListViewItem::cancelRenameWithMsg() {
+ KMessageBox::error( kapp->mainWidget() ,
+ i18n("The name you entered was invalid.\nRenaming process has been canceled."),
+ i18n("Name Not Valid") );
+ QListViewItem::setText(0, m_Label);
+}
+
+void UMLListViewItem::cancelRename(int col) {
+ QListViewItem::cancelRename(col);
+ if (m_bCreating) {
+ s_pListView->cancelRename(this);
+ }
+}
+
+// Sort the listview items by type and position within the corresponding list
+// of UMLObjects. If the item does not have an UMLObject then place it last.
+int UMLListViewItem::compare(QListViewItem *other, int col, bool ascending) const
+{
+ UMLListViewItem *ulvi = static_cast<UMLListViewItem*>(other);
+ Uml::ListView_Type ourType = getType();
+ Uml::ListView_Type otherType = ulvi->getType();
+
+ if ( ourType < otherType )
+ return -1;
+ if ( ourType > otherType )
+ return 1;
+ // ourType == otherType
+ const bool subItem = Model_Utils::typeIsClassifierList(ourType);
+ const int alphaOrder = key(col, ascending).compare(other->key(col, ascending));
+ int retval = 0;
+ QString dbgPfx = "compare(type=" + QString::number((int)ourType)
+ + ", self=" + getText() + ", other=" + ulvi->getText()
+ + "): return ";
+ UMLObject *otherObj = ulvi->getUMLObject();
+ if (m_pObject == NULL) {
+ retval = (subItem ? 1 : alphaOrder);
+#ifdef DEBUG_LVITEM_INSERTION_ORDER
+ kDebug() << dbgPfx << retval << " because (m_pObject==NULL)" << endl;
+#endif
+ return retval;
+ }
+ if (otherObj == NULL) {
+ retval = (subItem ? -1 : alphaOrder);
+#ifdef DEBUG_LVITEM_INSERTION_ORDER
+ kDebug() << dbgPfx << retval << " because (otherObj==NULL)" << endl;
+#endif
+ return retval;
+ }
+ UMLClassifier *ourParent = dynamic_cast<UMLClassifier*>(m_pObject->parent());
+ UMLClassifier *otherParent = dynamic_cast<UMLClassifier*>(otherObj->parent());
+ if (ourParent == NULL) {
+ retval = (subItem ? 1 : alphaOrder);
+#ifdef DEBUG_LVITEM_INSERTION_ORDER
+ kDebug() << dbgPfx << retval << " because (ourParent==NULL)" << endl;
+#endif
+ return retval;
+ }
+ if (otherParent == NULL) {
+ retval = (subItem ? -1 : alphaOrder);
+#ifdef DEBUG_LVITEM_INSERTION_ORDER
+ kDebug() << dbgPfx << retval << " because (otherParent==NULL)" << endl;
+#endif
+ return retval;
+ }
+ if (ourParent != otherParent) {
+ retval = (subItem ? 0 : alphaOrder);
+#ifdef DEBUG_LVITEM_INSERTION_ORDER
+ kDebug() << dbgPfx << retval << " because (ourParent != otherParent)" << endl;
+#endif
+ return retval;
+ }
+ UMLClassifierListItem *thisUmlItem = dynamic_cast<UMLClassifierListItem*>(m_pObject);
+ UMLClassifierListItem *otherUmlItem = dynamic_cast<UMLClassifierListItem*>(otherObj);
+ if (thisUmlItem == NULL) {
+ retval = (subItem ? 1 : alphaOrder);
+#ifdef DEBUG_LVITEM_INSERTION_ORDER
+ kDebug() << dbgPfx << retval << " because (thisUmlItem==NULL)" << endl;
+#endif
+ return retval;
+ }
+ if (otherUmlItem == NULL) {
+ retval = (subItem ? -1 : alphaOrder);
+#ifdef DEBUG_LVITEM_INSERTION_ORDER
+ kDebug() << dbgPfx << retval << " because (otherUmlItem==NULL)" << endl;
+#endif
+ return retval;
+ }
+ UMLClassifierListItemList items = ourParent->getFilteredList(thisUmlItem->getBaseType());
+ int myIndex = items.findRef(thisUmlItem);
+ int otherIndex = items.findRef(otherUmlItem);
+ if (myIndex < 0) {
+ retval = (subItem ? -1 : alphaOrder);
+ kError() << dbgPfx << retval << " because (myIndex < 0)" << endl;
+ return retval;
+ }
+ if (otherIndex < 0) {
+ retval = (subItem ? 1 : alphaOrder);
+ kError() << dbgPfx << retval << " because (otherIndex < 0)" << endl;
+ return retval;
+ }
+ return (myIndex < otherIndex ? -1 : myIndex > otherIndex ? 1 : 0);
+}
+
+UMLListViewItem* UMLListViewItem::deepCopy(UMLListViewItem *newParent) {
+ QString nm = getText();
+ Uml::ListView_Type t = getType();
+ UMLObject *o = getUMLObject();
+ UMLListViewItem* newItem;
+ if (o)
+ newItem = new UMLListViewItem(newParent, nm, t, o);
+ else
+ newItem = new UMLListViewItem(newParent, nm, t, m_nId);
+ UMLListViewItem *childItem = static_cast<UMLListViewItem*>(firstChild());
+ while (childItem) {
+ childItem->deepCopy(newItem);
+ childItem = static_cast<UMLListViewItem*>(childItem->nextSibling());
+ }
+ return newItem;
+}
+
+UMLListViewItem* UMLListViewItem::findUMLObject(const UMLObject *o) {
+ if (m_pObject == o)
+ return this;
+ UMLListViewItem *childItem = static_cast<UMLListViewItem*>(firstChild());
+ while (childItem) {
+ UMLListViewItem *inner = childItem->findUMLObject(o);
+ if (inner)
+ return inner;
+ childItem = static_cast<UMLListViewItem*>(childItem->nextSibling());
+ }
+ return NULL;
+}
+
+UMLListViewItem* UMLListViewItem::findChildObject(UMLClassifierListItem *cli) {
+ ChildObjectMap::iterator it = m_comap.find(cli);
+ if (it != m_comap.end()) {
+ return *it;
+ }
+ return NULL;
+}
+
+UMLListViewItem * UMLListViewItem::findItem(Uml::IDType id) {
+ if (getID() == id)
+ return this;
+ UMLListViewItem *childItem = static_cast<UMLListViewItem*>(firstChild());
+ while (childItem) {
+ UMLListViewItem *inner = childItem->findItem(id);
+ if (inner)
+ return inner;
+ childItem = static_cast<UMLListViewItem*>(childItem->nextSibling());
+ }
+ return NULL;
+}
+
+void UMLListViewItem::saveToXMI( QDomDocument & qDoc, QDomElement & qElement) {
+ QDomElement itemElement = qDoc.createElement( "listitem" );
+ Uml::IDType id = getID();
+ QString idStr = ID2STR(id);
+ //kDebug() << "UMLListViewItem::saveToXMI: id = " << idStr
+ // << ", type = " << m_Type << endl;
+ if (id != Uml::id_None)
+ itemElement.setAttribute( "id", idStr );
+ itemElement.setAttribute( "type", m_Type );
+ UMLFolder *extFolder = NULL;
+ if (m_pObject == NULL) {
+ if (! Model_Utils::typeIsDiagram(m_Type) && m_Type != Uml::lvt_View)
+ kError() << "UMLListViewItem::saveToXMI(" << m_Label
+ << "): m_pObject is NULL" << endl;
+ itemElement.setAttribute( "label", m_Label );
+ } else if (m_pObject->getID() == Uml::id_None) {
+ if (m_Label.isEmpty()) {
+ kDebug() << "UMLListViewItem::saveToXMI(): Skipping empty item"
+ << endl;
+ return;
+ }
+ kDebug() << "UMLListViewItem::saveToXMI(): saving local label "
+ << m_Label << " because umlobject ID is not set" << endl;
+ itemElement.setAttribute( "label", m_Label );
+ } else if (m_pObject->getBaseType() == Uml::ot_Folder) {
+ extFolder = static_cast<UMLFolder*>(m_pObject);
+ if (!extFolder->getFolderFile().isEmpty()) {
+ itemElement.setAttribute("open", "0");
+ qElement.appendChild(itemElement);
+ return;
+ }
+ }
+ itemElement.setAttribute("open", isOpen());
+ QDomElement folderRoot;
+ UMLListViewItem *childItem = static_cast<UMLListViewItem*>( firstChild() );
+ while (childItem) {
+ childItem->saveToXMI(qDoc, itemElement);
+ childItem = dynamic_cast<UMLListViewItem *> ( childItem->nextSibling() );
+ }
+ qElement.appendChild( itemElement );
+}
+
+bool UMLListViewItem::loadFromXMI(QDomElement& qElement) {
+ QString id = qElement.attribute( "id", "-1" );
+ QString type = qElement.attribute( "type", "-1" );
+ QString label = qElement.attribute( "label", "" );
+ QString open = qElement.attribute( "open", "1" );
+ if (!label.isEmpty())
+ setText( label );
+ else if (id == "-1") {
+ kError() << "UMLListViewItem::loadFromXMI: Item of type "
+ << type << " has neither ID nor label" << endl;
+ return false;
+ }
+
+ m_nChildren = qElement.childNodes().count();
+
+ m_nId = STR2ID(id);
+ if (m_nId != Uml::id_None)
+ m_pObject = s_pListView->getDocument()->findObjectById( m_nId );
+ m_Type = (Uml::ListView_Type)(type.toInt());
+ if (m_pObject)
+ updateObject();
+ setOpen( (bool)open.toInt() );
+ return true;
+}
+
diff --git a/umbrello/umbrello/umllistviewitem.h b/umbrello/umbrello/umllistviewitem.h
new file mode 100644
index 00000000..99cedf4e
--- /dev/null
+++ b/umbrello/umbrello/umllistviewitem.h
@@ -0,0 +1,285 @@
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * copyright (C) 2002-2006 *
+ * Umbrello UML Modeller Authors <uml-devel@uml.sf.net> *
+ * *
+ ***************************************************************************/
+
+#ifndef UMLLISTVIEWITEM_H
+#define UMLLISTVIEWITEM_H
+
+#include <qlistview.h>
+#include <qmap.h>
+#include <qdom.h>
+#include "umlnamespace.h"
+
+// forward declarations
+class UMLListView;
+class UMLObject;
+class UMLClassifierListItem;
+
+/**
+ * Items used by the class @ref UMLListView. This is needed as the type
+ * and object information is required to be stored.
+ *
+ * @short Items used by @ref UMLListView.
+ * @author Paul Hensgen <phensgen@techie.com>
+ * @see UMLListView
+ * Bugs and comments to uml-devel@lists.sf.net or http://bugs.kde.org
+ */
+
+class UMLListViewItem : public QListViewItem {
+public:
+ /**
+ * Sets up an instance.
+ *
+ * @param parent The parent to this instance.
+ * @param name The name of this instance.
+ * @param t The type of this instance.
+ * @param o The object it represents.
+ */
+ UMLListViewItem(UMLListView * parent, const QString &name, Uml::ListView_Type t, UMLObject*o=0);
+
+ /**
+ * Sets up an instance for subsequent loadFromXMI().
+ *
+ * @param parent The parent to this instance.
+ */
+ UMLListViewItem(UMLListView * parent);
+
+ /**
+ * Sets up an instance for subsequent loadFromXMI().
+ *
+ * @param parent The parent to this instance.
+ */
+ UMLListViewItem(UMLListViewItem * parent);
+
+ /**
+ * Sets up an instance.
+ *
+ * @param parent The parent to this instance.
+ * @param name The name of this instance.
+ * @param t The type of this instance.
+ * @param o The object it represents.
+ */
+ UMLListViewItem(UMLListViewItem * parent, const QString &name, Uml::ListView_Type t, UMLObject*o=0);
+
+ /**
+ * Sets up an instance.
+ *
+ * @param parent The parent to this instance.
+ * @param name The name of this instance.
+ * @param t The type of this instance.
+ * @param id The id of this instance.
+ */
+ UMLListViewItem(UMLListViewItem * parent, const QString &name, Uml::ListView_Type t, Uml::IDType id);
+
+ /**
+ * Standard deconstructor.
+ */
+ ~UMLListViewItem();
+
+ /**
+ * Returns the type this instance represents.
+ *
+ * @return The type this instance represents.
+ */
+ Uml::ListView_Type getType() const;
+
+ /**
+ * Sets the id this class represents.
+ * This only sets the ID locally, not at the UMLObject that is perhaps
+ * associated to this UMLListViewItem.
+ *
+ * @return The id this class represents.
+ */
+ void setID(Uml::IDType id);
+
+ /**
+ * Returns the id this class represents.
+ *
+ * @return The id this class represents.
+ */
+ Uml::IDType getID() const;
+
+ /**
+ * Set the UMLObject associated with this instance.
+ *
+ * @param obj The object this class represents.
+ */
+ void setUMLObject(UMLObject * obj) {
+ m_pObject = obj;
+ }
+
+ /**
+ * Return the UMLObject associated with this instance.
+ *
+ * @return The object this class represents.
+ */
+ UMLObject * getUMLObject() {
+ return m_pObject;
+ }
+
+ /**
+ * Returns true if the UMLListViewItem of the given ID is a parent of
+ * this UMLListViewItem.
+ */
+ bool isOwnParent(Uml::IDType listViewItemID);
+
+ /**
+ * Updates the representation of the object.
+ */
+ void updateObject();
+
+ /**
+ * Updates the icon on a folder.
+ */
+ void updateFolder();
+
+ /**
+ * Overrides default method.
+ * Will call default method but also makes sure correct icon is shown.
+ */
+ void setOpen( bool open );
+
+ /**
+ * Changes the current text and updates the tooltip.
+ */
+ void setText( const QString &text );
+
+ /**
+ * Returns the current text.
+ */
+ QString getText() const;
+
+ /**
+ * Sets if the item is in the middle of being created.
+ */
+ void setCreating( bool creating ) {
+ m_bCreating = creating;
+ }
+
+ /**
+ * Set the pixmap corresponding to the given Icon_Type.
+ */
+ void setIcon(Uml::Icon_Type iconType);
+
+ /**
+ * Overrides default method to make public.
+ */
+ void cancelRename( int col );
+
+ /**
+ * Adds the child listview item representing the given UMLClassifierListItem.
+ */
+ void addClassifierListItem(UMLClassifierListItem *child, UMLListViewItem *childItem);
+
+ /**
+ * Deletes the child listview item representing the given UMLClassifierListItem.
+ */
+ void deleteChildItem(UMLClassifierListItem *child);
+
+ /**
+ * Overrides the default sorting to sort by item type.
+ */
+ virtual int compare(QListViewItem *other, int col, bool ascending) const;
+
+ /**
+ * Returns the number of children of the UMLListViewItem
+ * containing this object
+ */
+ int childCount() const {
+ return m_nChildren;
+ }
+
+ /**
+ * Create a deep copy of this UMLListViewItem, but using the
+ * given parent instead of the parent of this UMLListViewItem.
+ * Return the new UMLListViewItem created.
+ */
+ UMLListViewItem* deepCopy(UMLListViewItem *newParent);
+
+ /**
+ * Find the UMLListViewItem that is related to the given UMLObject
+ * in the tree rooted at the current UMLListViewItem.
+ * Return a pointer to the item or NULL if not found.
+ */
+ UMLListViewItem* findUMLObject(const UMLObject *o);
+
+ /**
+ * Find the UMLListViewItem that represents the given UMLClassifierListItem
+ * in the children of the current UMLListViewItem. (Only makes sense if
+ * the current UMLListViewItem represents a UMLClassifier.)
+ * Return a pointer to the item or NULL if not found.
+ */
+ UMLListViewItem* findChildObject(UMLClassifierListItem *cli);
+
+ /**
+ * Find the UMLListViewItem of the given ID in the tree rooted at
+ * the current UMLListViewItem.
+ * Return a pointer to the item or NULL if not found.
+ *
+ * @param id The ID to search for.
+ * @return The item with the given ID or NULL if not found.
+ */
+ UMLListViewItem * findItem(Uml::IDType id);
+
+ /**
+ * saves the listview item to a "listitem" tag
+ */
+ void saveToXMI( QDomDocument& qDoc, QDomElement& qElement);
+
+ /**
+ * Loads a "listitem" tag, this is only used by the clipboard currently
+ */
+ bool loadFromXMI(QDomElement& qElement);
+
+protected:
+ /**
+ * Initializes key variables of the class.
+ */
+ void init(UMLListView * parent = 0);
+
+ /**
+ * This function is called if the user presses Enter during in-place renaming
+ * of the item in column col, reimplemented from QlistViewItem
+ */
+ void okRename( int col );
+
+ /**
+ * Auxiliary method for okRename().
+ */
+ void cancelRenameWithMsg();
+
+ /**
+ * This list view all the instance of this class are displayed on.
+ */
+ static UMLListView * s_pListView;
+
+ /**
+ * Flag used to set the state of creating.
+ */
+ bool m_bCreating;
+
+ /**
+ * Auxiliary map of child UMLLisViewItems keyed by UMLClassifierListItem.
+ * Used by findChildObject() for efficiency instead of looping using
+ * firstChild()/nextSibling() because the latter incur enforceItemVisible()
+ * and thus expensive sorting.
+ */
+ typedef QMap<UMLClassifierListItem*, UMLListViewItem*> ChildObjectMap;
+
+ Uml::ListView_Type m_Type;
+ Uml::IDType m_nId;
+ int m_nChildren;
+ UMLObject * m_pObject;
+ QString m_Label;
+ ChildObjectMap m_comap;
+};
+
+#endif
diff --git a/umbrello/umbrello/umllistviewitemlist.h b/umbrello/umbrello/umllistviewitemlist.h
new file mode 100644
index 00000000..49663163
--- /dev/null
+++ b/umbrello/umbrello/umllistviewitemlist.h
@@ -0,0 +1,29 @@
+/***************************************************************************
+ umllistviewitemlist.h - description
+ -------------------
+ begin : Sat Dec 29 2001
+ copyright : (C) 2001 by Gustavo Madrigal
+ email : gmadrigal@nextphere.com
+ Bugs and comments to uml-devel@lists.sf.net or http://bugs.kde.org
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the 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 UMLLISTVIEWITEMLIST_H
+#define UMLLISTVIEWITEMLIST_H
+
+#include <qptrlist.h>
+
+class UMLListViewItem;
+
+typedef QPtrList<UMLListViewItem> UMLListViewItemList;
+typedef QPtrListIterator<UMLListViewItem> UMLListViewItemListIt;
+
+#endif
diff --git a/umbrello/umbrello/umlnamespace.cpp b/umbrello/umbrello/umlnamespace.cpp
new file mode 100644
index 00000000..f2d81eeb
--- /dev/null
+++ b/umbrello/umbrello/umlnamespace.cpp
@@ -0,0 +1,76 @@
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * copyright (C) 2002-2006 *
+ * Umbrello UML Modeller Authors <uml-devel@uml.sf.net> *
+ ***************************************************************************/
+
+#include "umlnamespace.h"
+#include "qregexp.h"
+
+namespace Uml {
+
+bool tagEq (const QString& inTag, const QString& inPattern) {
+ QString tag = inTag;
+ QString pattern = inPattern;
+ tag.remove( QRegExp("^\\w+:") ); // remove leading "UML:" or other
+ int patSections = pattern.contains( '.' ) + 1;
+ QString tagEnd = tag.section( '.', -patSections );
+ return (tagEnd.lower() == pattern.lower());
+}
+
+QString Visibility::toString(Value value, bool mnemonic) {
+ switch (value) {
+ case Protected:
+ return (mnemonic ? "#" : "protected");
+ break;
+ case Private:
+ return (mnemonic ? "-" : "private");
+ break;
+ case Implementation:
+ return (mnemonic ? "~" : "implementation");
+ break;
+ case Public:
+ default:
+ return (mnemonic ? "+" : "public");
+ break;
+ }
+}
+
+Visibility Visibility::fromString(const QString& vis) {
+ if (vis == "public" || vis == "+")
+ return Visibility(Public);
+ else if (vis == "protected" || vis == "#")
+ return Visibility(Protected);
+ else if (vis == "private" || vis == "-")
+ return Visibility(Private);
+ else if (vis == "~")
+ return Visibility(Implementation);
+ else if (vis == "signals")
+ return Visibility(Protected);
+ else if (vis == "class")
+ return Visibility(Private);
+ else
+ return Visibility(Public);
+}
+
+Visibility::Visibility(): _v(Public) {
+}
+
+Visibility::Visibility(Value v): _v(v) {
+}
+
+QString Visibility::toString(bool mnemonic) const {
+ return toString(_v, mnemonic);
+}
+
+Visibility::operator Visibility::Value() const {
+ return _v;
+}
+
+} // end namespace Uml
+
diff --git a/umbrello/umbrello/umlnamespace.h b/umbrello/umbrello/umlnamespace.h
new file mode 100644
index 00000000..0c0ea2fd
--- /dev/null
+++ b/umbrello/umbrello/umlnamespace.h
@@ -0,0 +1,353 @@
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * copyright (C) 2002-2006 *
+ * Umbrello UML Modeller Authors <uml-devel@uml.sf.net> *
+ ***************************************************************************/
+
+#ifndef UMLNAMESPACE_H
+#define UMLNAMESPACE_H
+
+#include <string>
+#include <qstring.h>
+
+
+/**
+ *@author Paul Hensgen
+ * Bugs and comments to uml-devel@lists.sf.net or http://bugs.kde.org
+ */
+namespace Uml {
+
+enum Model_Type
+{
+ mt_Logical,
+ mt_UseCase,
+ mt_Component,
+ mt_Deployment,
+ mt_EntityRelationship,
+ N_MODELTYPES // must remain last
+};
+
+enum Object_Type
+{
+ ot_UMLObject = 100,
+ ot_Actor,
+ ot_UseCase,
+ ot_Package,
+ ot_Interface,
+ ot_Datatype,
+ ot_Enum,
+ ot_Class,
+ ot_Association,
+ ot_Attribute,
+ ot_Operation,
+ ot_EnumLiteral,
+ ot_Template,
+ ot_Component,
+ ot_Artifact,
+ ot_Node,
+ ot_Stereotype,
+ ot_Role,
+ ot_Entity,
+ ot_EntityAttribute,
+ ot_Folder
+};
+
+class Visibility {
+ public:
+ enum Value {
+ Public = 200,
+ Private,
+ Protected,
+ Implementation // objects marked with this are declared in the implementation file.
+ };
+ Visibility();
+ Visibility(Value v);
+ static QString toString(Value value, bool mnemonic);
+ static Visibility fromString(const QString& vis);
+ /**
+ * Convert Visibility value into QString representation.
+ *
+ * @param mnemonic If true then return a single character:
+ * "+" for public, "-" for private,
+ * "#" for protected or "~" for implementation
+ */
+ QString toString(bool mnemonic = false) const;
+ operator Value () const;
+ private:
+ Value _v;
+};
+
+enum Widget_Type
+{
+ wt_UMLWidget = 300, // does not have UMLObject representation
+ wt_Actor, // has UMLObject representation
+ wt_UseCase, // has UMLObject representation
+ wt_Class, // has UMLObject representation
+ wt_Interface, // has UMLObject representation
+ wt_Datatype, // has UMLObject representation
+ wt_Enum, // has UMLObject representation
+ wt_Entity, // has UMLObject representation
+ wt_Package, // has UMLObject representation
+ wt_Object, // has UMLObject representation
+ wt_Note, // does not have UMLObject representation
+ wt_Box, // does not have UMLObject representation
+ wt_Message, // does not have UMLObject representation
+ wt_Text, // does not have UMLObject representation
+ wt_State, // does not have UMLObject representation
+ wt_Activity, // does not have UMLObject representation
+ wt_Component, // has UMLObject representation
+ wt_Artifact, // has UMLObject representation
+ wt_Node, // has UMLObject representation
+ wt_Association, // has UMLObject representation
+ wt_ForkJoin // does not have UMLObject representation
+};
+
+enum Diagram_Type
+{
+ //the values in this enum are saved out to the file
+ //for file compatibility, only add new values to the end
+ dt_Undefined = 0,
+ dt_Class,
+ dt_UseCase,
+ dt_Sequence,
+ dt_Collaboration,
+ dt_State,
+ dt_Activity,
+ dt_Component,
+ dt_Deployment,
+ dt_EntityRelationship
+};
+
+enum Association_Type
+{
+ at_Generalization = 500,
+ at_Aggregation,
+ at_Dependency,
+ at_Association,
+ at_Association_Self,
+ at_Coll_Message,
+ at_Seq_Message,
+ at_Coll_Message_Self,
+ at_Seq_Message_Self,
+ at_Containment,
+ at_Composition,
+ at_Realization,
+ at_UniAssociation,
+ at_Anchor,
+ at_State,
+ at_Activity,
+ at_Relationship,
+ at_Unknown = - 1
+};
+
+enum Signature_Type
+{
+ st_NoSig = 600,
+ st_ShowSig,
+ st_SigNoVis,
+ st_NoSigNoVis
+};
+
+enum Text_Role
+{
+ tr_Floating = 700, //text widget on diagrams
+ tr_MultiA, //Text for Multiple A
+ tr_MultiB, //Text for Multiple B
+ tr_Name, //middle text on most associations
+ tr_Seq_Message, //message on seq diagram between two objects
+ tr_Seq_Message_Self, //message to self on seq diagram - feature not implemented yet
+ tr_Coll_Message, //message between two objects on a collab diagram
+ tr_Coll_Message_Self, //message to object self on collab diagram
+ tr_State,
+ tr_RoleAName, //RoleA text on associations
+ tr_RoleBName, //RoleB text on associations
+ tr_ChangeA, //Changeability A text on associations
+ tr_ChangeB //Changeability B text on associations
+};
+
+enum ListView_Type
+{
+ //the values in this enum are saved out to the file
+ //for file compatibility, only add new values to the end
+ lvt_View = 800,
+ lvt_Logical_View,
+ lvt_UseCase_View,
+ lvt_Logical_Folder,
+ lvt_UseCase_Folder,
+ lvt_UseCase_Diagram,
+ lvt_Collaboration_Diagram,
+ lvt_Class_Diagram,
+ lvt_State_Diagram,
+ lvt_Activity_Diagram,
+ lvt_Sequence_Diagram,
+ lvt_Actor,
+ lvt_UseCase,
+ lvt_Class,
+ lvt_Attribute,
+ lvt_Operation,
+ lvt_Template,
+ lvt_Interface,
+ lvt_Package,
+ lvt_Component_Diagram,
+ lvt_Component_Folder,
+ lvt_Component_View,
+ lvt_Component,
+ lvt_Diagrams, // currently unused
+ lvt_Artifact,
+ lvt_Deployment_Diagram,
+ lvt_Deployment_Folder,
+ lvt_Deployment_View,
+ lvt_Node,
+ lvt_Datatype,
+ lvt_Datatype_Folder,
+ lvt_Enum,
+ lvt_Entity,
+ lvt_EntityAttribute,
+ lvt_EntityRelationship_Diagram,
+ lvt_EntityRelationship_Folder,
+ lvt_EntityRelationship_Model,
+ lvt_Subsystem,
+ lvt_Model,
+ lvt_EnumLiteral,
+ lvt_Unknown = -1
+};
+
+enum Icon_Type
+{
+ it_Home = 0,
+ it_Folder_Cyan,
+ it_Folder_Cyan_Open,
+ it_Folder_Green,
+ it_Folder_Green_Open,
+ it_Folder_Grey,
+ it_Folder_Grey_Open,
+ it_Folder_Red,
+ it_Folder_Red_Open,
+ it_Folder_Violet,
+ it_Folder_Violet_Open,
+ it_Folder_Orange,
+ it_Folder_Orange_Open,
+ it_Diagram, //change to have different one for each type of diagram
+ it_Class,
+ it_Template,
+ it_Package,
+ it_Subsystem,
+ it_Component,
+ it_Node,
+ it_Artifact,
+ it_Interface,
+ it_Datatype,
+ it_Enum,
+ it_Entity,
+ it_Actor,
+ it_UseCase,
+ it_Public_Method,
+ it_Private_Method,
+ it_Protected_Method,
+ it_Public_Attribute,
+ it_Private_Attribute,
+ it_Protected_Attribute,
+ it_Diagram_Activity,
+ it_Diagram_Class,
+ it_Diagram_Collaboration,
+ it_Diagram_Component,
+ it_Diagram_Deployment,
+ it_Diagram_EntityRelationship,
+ it_Diagram_Sequence,
+ it_Diagram_State,
+ it_Diagram_Usecase,
+ N_ICONTYPES // must remain last
+};
+
+enum Changeability_Type
+{
+ chg_Changeable = 900,
+ chg_Frozen,
+ chg_AddOnly
+};
+
+enum Sequence_Message_Type
+{
+ //This is saved out to the file so only add new entries at the end
+ sequence_message_synchronous = 1000,
+ sequence_message_asynchronous,
+ sequence_message_creation
+};
+
+enum DBIndex_Type
+{
+ None = 1100,
+ Primary,
+ Index,
+ Unique
+};
+
+/**
+ * Constants used for indexing the roles of associations.
+ */
+enum Role_Type { A, B };
+
+/**
+ * Direction of operation parameters:
+ * in = operation uses the parameter as an input value
+ * out = operation fills the parameter as a return value
+ * inout = operation both reads and writes the parameter
+ * The numeric values of this enum are not currently saved to file.
+ */
+enum Parameter_Direction { pd_In, pd_InOut, pd_Out };
+
+/**
+ * Supported programming languages
+ */
+enum Programming_Language {
+ pl_ActionScript,
+ pl_Ada,
+ pl_Cpp,
+ pl_CSharp,
+ pl_D,
+ pl_IDL,
+ pl_Java,
+ pl_JavaScript,
+ pl_Pascal,
+ pl_Perl,
+ pl_PHP,
+ pl_PHP5,
+ pl_Python,
+ pl_Ruby,
+ pl_SQL,
+ pl_Tcl,
+ pl_XMLSchema,
+ pl_Reserved
+};
+
+/**
+ * The data type used for unique IDs.
+ */
+typedef std::string IDType;
+/**
+ * Reserved value for uninitialized/illegal ID.
+ */
+const IDType id_None = "-1";
+const IDType id_Reserved = "0";
+
+# define STR2ID(id) id.ascii()
+# define ID2STR(id) QString(id.c_str())
+
+// KDE4 compatibility
+# define kDebug kdDebug
+# define kWarning kdWarning
+# define kError kdError
+
+/**
+ * Function for comparing tags in XMI files.
+ */
+bool tagEq (const QString& tag, const QString& pattern);
+
+} // end namespace Uml
+
+#endif
diff --git a/umbrello/umbrello/umlobject.cpp b/umbrello/umbrello/umlobject.cpp
new file mode 100644
index 00000000..e28ed7da
--- /dev/null
+++ b/umbrello/umbrello/umlobject.cpp
@@ -0,0 +1,753 @@
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * copyright (C) 2002-2006 *
+ * Umbrello UML Modeller Authors <uml-devel@uml.sf.net> *
+ ***************************************************************************/
+
+// own header
+#include "umlobject.h"
+// qt/kde includes
+#include <qregexp.h>
+#include <kdebug.h>
+#include <kapplication.h>
+// app includes
+#include "uniqueid.h"
+#include "uml.h"
+#include "umldoc.h"
+#include "umllistview.h"
+#include "umllistviewitem.h"
+#include "package.h"
+#include "folder.h"
+#include "stereotype.h"
+#include "object_factory.h"
+#include "model_utils.h"
+#include "codeimport/import_utils.h"
+#include "docwindow.h"
+#include "dialogs/classpropdlg.h"
+
+UMLObject::UMLObject(const UMLObject * parent, const QString &name, Uml::IDType id)
+ : QObject(const_cast<UMLObject*>(parent), "UMLObject" ) {
+ init();
+ if (id == Uml::id_None)
+ m_nId = UniqueID::gen();
+ else
+ m_nId = id;
+ m_Name = name;
+}
+
+UMLObject::UMLObject(const QString &name, Uml::IDType id)
+ : QObject(UMLApp::app()->getDocument()) {
+ init();
+ if (id == Uml::id_None)
+ m_nId = UniqueID::gen();
+ else
+ m_nId = id;
+ m_Name = name;
+}
+
+UMLObject::UMLObject(const UMLObject * parent)
+ : QObject(const_cast<UMLObject*>(parent)) {
+ init();
+}
+
+UMLObject::~UMLObject() {
+}
+
+void UMLObject::init() {
+ m_BaseType = Uml::ot_UMLObject;
+ m_nId = Uml::id_None;
+ m_pUMLPackage = NULL;
+ m_Name = "";
+ m_Vis = Uml::Visibility::Public;
+ m_pStereotype = NULL;
+ m_Doc = "";
+ m_bAbstract = false;
+ m_bStatic = false;
+ m_bInPaste = false;
+ m_bCreationWasSignalled = false;
+ m_pSecondary = NULL;
+}
+
+bool UMLObject::showProperties(int page, bool assoc) {
+ DocWindow *docwindow = UMLApp::app()->getDocWindow();
+ docwindow->updateDocumentation(false);
+ ClassPropDlg* dlg = new ClassPropDlg((QWidget*)UMLApp::app(), this, page, assoc);
+ bool modified = false;
+ if (dlg->exec()) {
+ docwindow->showDocumentation(this, true);
+ UMLApp::app()->getDocument()->setModified(true);
+ modified = true;
+ }
+ dlg->close(true); //wipe from memory
+ return modified;
+}
+
+bool UMLObject::acceptAssociationType(Uml::Association_Type)
+{// A UMLObject accepts nothing. This should be reimplemented by the subclasses
+ return false;
+}
+
+void UMLObject::setID(Uml::IDType NewID) {
+ m_nId = NewID;
+ emitModified();
+}
+
+void UMLObject::setName(const QString &strName) {
+ m_Name = strName;
+ emitModified();
+}
+
+QString UMLObject::getName() const {
+ return m_Name;
+}
+
+QString UMLObject::getFullyQualifiedName(const QString& separator,
+ bool includeRoot /* = false */) const {
+ QString fqn;
+ if (m_pUMLPackage) {
+ bool skipPackage = false;
+ if (!includeRoot) {
+ UMLDoc *umldoc = UMLApp::app()->getDocument();
+ if (umldoc->rootFolderType(m_pUMLPackage) != Uml::N_MODELTYPES ||
+ m_pUMLPackage == umldoc->getDatatypeFolder())
+ skipPackage = true;
+ }
+ if (!skipPackage) {
+ QString tempSeparator = separator;
+ if (tempSeparator.isEmpty())
+ tempSeparator = UMLApp::app()->activeLanguageScopeSeparator();
+ fqn = m_pUMLPackage->getFullyQualifiedName(tempSeparator, includeRoot);
+ fqn.append(tempSeparator);
+ }
+ }
+ fqn.append(m_Name);
+ return fqn;
+}
+
+bool UMLObject::operator==(UMLObject & rhs ) {
+ if( this == &rhs )
+ return true;
+
+ //don't compare IDs, these are program specific and
+ //don't mean the objects are the same
+ //***** CHECK: Who put in this comment? What was the reason?
+ //***** Currently some operator== in umbrello compare the IDs
+ //***** while others don't.
+
+ if( m_Name != rhs.m_Name )
+ return false;
+
+ // Packages create different namespaces, therefore they should be
+ // part of the equality test.
+ if( m_pUMLPackage != rhs.m_pUMLPackage )
+ return false;
+
+ // Making the type part of an object's identity has its problems:
+ // Not all programming languages support declarations of the same
+ // name but different type.
+ // In such cases, the code generator is responsible for generating
+ // the appropriate error message.
+ if( m_BaseType != rhs.m_BaseType )
+ return false;
+
+ // The documentation should not be part of the equality test.
+ // If two objects are the same but differ only in their documentation,
+ // what does that mean?
+ //if( m_Doc != rhs.m_Doc )
+ // return false;
+
+ // The scope should not be part of the equality test.
+ // What does it mean if two objects are the same but differ in their
+ // scope? - I'm not aware of any programming language that would
+ // support that.
+ //if( m_Vis != rhs.m_Vis )
+ // return false;
+
+ // See comments above
+ //if( m_pStereotype != rhs.m_pStereotype )
+ // return false;
+
+ // See comments above
+ //if( m_bAbstract != rhs.m_bAbstract )
+ // return false;
+
+ // See comments above
+ //if( m_bStatic != rhs.m_bStatic )
+ // return false;
+
+ return true;
+}
+
+void UMLObject::copyInto(UMLObject *rhs) const
+{
+ // Data members with copy constructor
+ rhs->m_Doc = m_Doc;
+ rhs->m_pStereotype = m_pStereotype;
+ rhs->m_bAbstract = m_bAbstract;
+ rhs->m_bStatic = m_bStatic;
+ rhs->m_BaseType = m_BaseType;
+ rhs->m_Vis = m_Vis;
+ rhs->m_pUMLPackage = m_pUMLPackage;
+
+ // We don't want the same name existing twice.
+ rhs->m_Name = Model_Utils::uniqObjectName(m_BaseType, m_pUMLPackage, m_Name);
+
+ // Create a new ID.
+ rhs->m_nId = UniqueID::gen();
+
+ // Hope that the parent from QObject is okay.
+ if (rhs->parent() != parent())
+ kDebug() << "copyInto has a wrong parent" << endl;
+}
+
+
+bool UMLObject::getAbstract() const{
+ return m_bAbstract;
+}
+
+void UMLObject::setAbstract(bool bAbstract) {
+ m_bAbstract = bAbstract;
+ emitModified();
+}
+
+void UMLObject::setInPaste(bool bInPaste /* =true */) {
+ m_bInPaste = bInPaste;
+}
+
+/** Returns true if this UMLObject has classifier scope, otherwise false (the default). */
+bool UMLObject::getStatic() const
+{
+ return m_bStatic;
+}
+/** Sets the value for m_bStatic. */
+void UMLObject::setStatic(bool bStatic)
+{
+ m_bStatic = bStatic;
+ emitModified();
+}
+
+void UMLObject::emitModified()
+{
+ UMLDoc *umldoc = UMLApp::app()->getDocument();
+ if (! umldoc->loading())
+ emit modified();
+}
+
+void UMLObject::setDoc(const QString &d) {
+ m_Doc = d;
+ //emit modified(); No, this is done centrally at DocWindow::updateDocumentation()
+}
+
+Uml::Object_Type UMLObject::getBaseType() const {
+ return m_BaseType;
+}
+
+void UMLObject::setBaseType(Uml::Object_Type ot) {
+ m_BaseType = ot;
+}
+
+Uml::IDType UMLObject::getID() const {
+ return m_nId;
+}
+
+QString UMLObject::getDoc() const {
+ return m_Doc;
+}
+
+Uml::Visibility UMLObject::getVisibility() const {
+ return m_Vis;
+}
+
+void UMLObject::setVisibility(Uml::Visibility s) {
+ m_Vis = s;
+ emitModified();
+}
+
+void UMLObject::setUMLStereotype(UMLStereotype *stereo) {
+ if (stereo == m_pStereotype)
+ return;
+ if (stereo) {
+ stereo->incrRefCount();
+ }
+ if (m_pStereotype) {
+ m_pStereotype->decrRefCount();
+ if (m_pStereotype->refCount() == 0) {
+ UMLDoc *pDoc = UMLApp::app()->getDocument();
+ pDoc->removeStereotype(m_pStereotype);
+ delete m_pStereotype;
+ }
+ }
+ m_pStereotype = stereo;
+ // TODO: don't emit modified() if predefined folder
+ emitModified();
+}
+
+void UMLObject::setStereotype(const QString &_name) {
+ if (_name.isEmpty()) {
+ setUMLStereotype(NULL);
+ return;
+ }
+ UMLDoc *pDoc = UMLApp::app()->getDocument();
+ UMLStereotype *s = pDoc->findOrCreateStereotype(_name);
+ setUMLStereotype(s);
+}
+
+void UMLObject::setPackage(const QString &_name) {
+ UMLObject *pkgObj = NULL;
+ if (!_name.isEmpty()) {
+ UMLDoc* umldoc = UMLApp::app()->getDocument();
+ pkgObj = umldoc->findUMLObject(_name);
+ if (pkgObj == NULL) {
+ kDebug() << "UMLObject::setPackage: creating UMLPackage "
+ << _name << " for " << m_Name << endl;
+ pkgObj = Import_Utils::createUMLObject(Uml::ot_Package, _name);
+ } else {
+ const Uml::Object_Type ot = pkgObj->getBaseType();
+ if (ot != Uml::ot_Package && ot != Uml::ot_Folder && ot != Uml::ot_Component) {
+ kError() << "UMLObject::setPackage(" << m_Name << "): "
+ << "existing " << _name << " is not a container" << endl;
+ // This should not happen - if it does, there may be further problems.
+ // A container name should not overlap with another name in the same scope.
+ pkgObj = Import_Utils::createUMLObject(Uml::ot_Package, _name);
+ }
+ }
+ }
+ setUMLPackage( static_cast<UMLPackage *>(pkgObj) );
+}
+
+void UMLObject::setUMLPackage(UMLPackage* pPkg) {
+ m_pUMLPackage = pPkg;
+ emitModified();
+}
+
+const UMLStereotype * UMLObject::getUMLStereotype() {
+ return m_pStereotype;
+}
+
+QString UMLObject::getStereotype(bool includeAdornments /* = false */) const {
+ if (m_pStereotype == NULL)
+ return "";
+ QString name = m_pStereotype->getName();
+ if (includeAdornments)
+ name = QString::fromUtf8("«") + name + QString::fromUtf8("»");
+ return name;
+}
+
+QString UMLObject::getPackage(const QString& separator, bool includeRoot) {
+ QString tempSeparator = separator;
+ if (tempSeparator.isEmpty())
+ tempSeparator = UMLApp::app()->activeLanguageScopeSeparator();
+ QString fqn = getFullyQualifiedName(tempSeparator, includeRoot);
+ if (!fqn.contains(tempSeparator))
+ return "";
+ QString scope = fqn.left(fqn.length() - tempSeparator.length() - m_Name.length());
+ return scope;
+}
+
+UMLPackageList UMLObject::getPackages(bool includeRoot) const {
+ UMLPackageList pkgList;
+ UMLPackage* pkg = m_pUMLPackage;
+ while (pkg != NULL) {
+ pkgList.prepend(pkg);
+ pkg = pkg->getUMLPackage();
+ }
+ if (!includeRoot)
+ pkgList.removeFirst();
+ return pkgList;
+}
+
+UMLPackage* UMLObject::getUMLPackage() {
+ return m_pUMLPackage;
+}
+
+QString UMLObject::getSecondaryId() const {
+ return m_SecondaryId;
+}
+
+void UMLObject::setSecondaryId(const QString& id) {
+ m_SecondaryId = id;
+}
+
+QString UMLObject::getSecondaryFallback() const {
+ return m_SecondaryFallback;
+}
+
+void UMLObject::setSecondaryFallback(const QString& id) {
+ m_SecondaryFallback = id;
+}
+
+void UMLObject::maybeSignalObjectCreated() {
+ if (!m_bCreationWasSignalled &&
+ m_BaseType != Uml::ot_Stereotype &&
+ m_BaseType != Uml::ot_Association &&
+ m_BaseType != Uml::ot_Role) {
+ m_bCreationWasSignalled = true;
+ UMLDoc* umldoc = UMLApp::app()->getDocument();
+ umldoc->signalUMLObjectCreated(this);
+ }
+}
+
+bool UMLObject::resolveRef() {
+ if (m_pSecondary || (m_SecondaryId.isEmpty() && m_SecondaryFallback.isEmpty())) {
+ maybeSignalObjectCreated();
+ return true;
+ }
+#ifdef VERBOSE_DEBUGGING
+ kDebug() << "UMLObject::resolveRef(" << m_Name << "): m_SecondaryId is "
+ << m_SecondaryId << endl;
+#endif
+ UMLDoc *pDoc = UMLApp::app()->getDocument();
+ // In the new, XMI standard compliant save format,
+ // the type is the xmi.id of a UMLClassifier.
+ if (! m_SecondaryId.isEmpty()) {
+ m_pSecondary = pDoc->findObjectById(STR2ID(m_SecondaryId));
+ if (m_pSecondary != NULL) {
+ if (m_pSecondary->getBaseType() == Uml::ot_Stereotype) {
+ m_pStereotype = static_cast<UMLStereotype*>(m_pSecondary);
+ m_pStereotype->incrRefCount();
+ m_pSecondary = NULL;
+ }
+ m_SecondaryId = "";
+ maybeSignalObjectCreated();
+ return true;
+ }
+ if (m_SecondaryFallback.isEmpty()) {
+ kDebug() << "UMLObject::resolveRef: object with xmi.id=" << m_SecondaryId
+ << " not found, setting to undef" << endl;
+ UMLFolder *datatypes = pDoc->getDatatypeFolder();
+ m_pSecondary = Object_Factory::createUMLObject(Uml::ot_Datatype, "undef", datatypes, false);
+ return true;
+ }
+ }
+ if (m_SecondaryFallback.isEmpty()) {
+ kError() << "UMLObject::resolveRef(" << m_Name
+ << "): cannot find type with id "
+ << m_SecondaryId << endl;
+ return false;
+ }
+#ifdef VERBOSE_DEBUGGING
+ kDebug() << "UMLObject::resolveRef(" << m_Name
+ << "): could not resolve secondary ID " << m_SecondaryId
+ << ", using secondary fallback " << m_SecondaryFallback
+ << endl;
+#endif
+ m_SecondaryId = m_SecondaryFallback;
+ // Assume we're dealing with the older Umbrello format where
+ // the type name was saved in the "type" attribute rather
+ // than the xmi.id of the model object of the attribute type.
+ m_pSecondary = pDoc->findUMLObject( m_SecondaryId, Uml::ot_UMLObject, this );
+ if (m_pSecondary) {
+ m_SecondaryId = "";
+ maybeSignalObjectCreated();
+ return true;
+ }
+ // Work around Object_Factory::createUMLObject()'s incapability
+ // of on-the-fly scope creation:
+ if (m_SecondaryId.contains("::")) {
+ // TODO: Merge Import_Utils::createUMLObject() into Object_Factory::createUMLObject()
+ m_pSecondary = Import_Utils::createUMLObject(Uml::ot_UMLObject, m_SecondaryId, m_pUMLPackage);
+ if (m_pSecondary) {
+ if (Import_Utils::newUMLObjectWasCreated()) {
+ maybeSignalObjectCreated();
+ kapp->processEvents();
+ kDebug() << "UMLObject::resolveRef: Import_Utils::createUMLObject() "
+ << "created a new type for " << m_SecondaryId << endl;
+ } else {
+ kDebug() << "UMLObject::resolveRef: Import_Utils::createUMLObject() "
+ << "returned an existing type for " << m_SecondaryId << endl;
+ }
+ m_SecondaryId = "";
+ return true;
+ }
+ kError() << "UMLObject::resolveRef: Import_Utils::createUMLObject() "
+ << "failed to create a new type for " << m_SecondaryId << endl;
+ return false;
+ }
+ kDebug() << "UMLObject::resolveRef: Creating new type for " << m_SecondaryId << endl;
+ // This is very C++ specific - we rely on some '*' or
+ // '&' to decide it's a ref type. Plus, we don't recognize
+ // typedefs of ref types.
+ bool isReferenceType = ( m_SecondaryId.contains('*') ||
+ m_SecondaryId.contains('&') );
+ Uml::Object_Type ot = Uml::ot_Class;
+ if (isReferenceType) {
+ ot = Uml::ot_Datatype;
+ } else {
+ if (Model_Utils::isCommonDataType(m_SecondaryId))
+ ot = Uml::ot_Datatype;
+ }
+ m_pSecondary = Object_Factory::createUMLObject(ot, m_SecondaryId, NULL);
+ if (m_pSecondary == NULL)
+ return false;
+ m_SecondaryId = "";
+ maybeSignalObjectCreated();
+ //kapp->processEvents();
+ return true;
+}
+
+QDomElement UMLObject::save( const QString &tag, QDomDocument & qDoc ) {
+ /*
+ Call as the first action of saveToXMI() in child class:
+ This creates the QDomElement with which to work.
+ */
+ QDomElement qElement = qDoc.createElement(tag);
+ qElement.setAttribute( "isSpecification", "false" );
+ if (m_BaseType != Uml::ot_Association &&
+ m_BaseType != Uml::ot_Role &&
+ m_BaseType != Uml::ot_Attribute) {
+ qElement.setAttribute( "isLeaf", "false" );
+ qElement.setAttribute( "isRoot", "false" );
+ if (m_bAbstract)
+ qElement.setAttribute( "isAbstract", "true" );
+ else
+ qElement.setAttribute( "isAbstract", "false" );
+ }
+ qElement.setAttribute( "xmi.id", ID2STR(m_nId) );
+ qElement.setAttribute( "name", m_Name );
+ if (m_BaseType != Uml::ot_Operation &&
+ m_BaseType != Uml::ot_Role &&
+ m_BaseType != Uml::ot_Attribute) {
+ Uml::IDType nmSpc;
+ if (m_pUMLPackage)
+ nmSpc = m_pUMLPackage->getID();
+ else
+ nmSpc = UMLApp::app()->getDocument()->getModelID();
+ qElement.setAttribute( "namespace", ID2STR(nmSpc) );
+ }
+ if (! m_Doc.isEmpty())
+ qElement.setAttribute( "comment", m_Doc ); //CHECK: uml13.dtd compliance
+#ifdef XMI_FLAT_PACKAGES
+ if (m_pUMLPackage) //FIXME: uml13.dtd compliance
+ qElement.setAttribute( "package", m_pUMLPackage->getID() );
+#endif
+ QString visibility = m_Vis.toString(false);
+ qElement.setAttribute( "visibility", visibility);
+ if (m_pStereotype != NULL)
+ qElement.setAttribute( "stereotype", ID2STR(m_pStereotype->getID()) );
+ if (m_bStatic)
+ qElement.setAttribute( "ownerScope", "classifier" );
+ /* else
+ qElement.setAttribute( "ownerScope", "instance" );
+ *** ownerScope defaults to instance if not set **********/
+ return qElement;
+}
+
+bool UMLObject::load( QDomElement& ) {
+ // This body is not usually executed because child classes
+ // overwrite the load method.
+ return true;
+}
+
+bool UMLObject::loadStereotype(QDomElement & element) {
+ QString tag = element.tagName();
+ if (!Uml::tagEq(tag, "stereotype"))
+ return false;
+ QString stereo = element.attribute("xmi.value", "");
+ if (stereo.isEmpty() && element.hasChildNodes()) {
+ /* like so:
+ <UML:ModelElement.stereotype>
+ <UML:Stereotype xmi.idref = '07CD'/>
+ </UML:ModelElement.stereotype>
+ */
+ QDomNode stereoNode = element.firstChild();
+ QDomElement stereoElem = stereoNode.toElement();
+ tag = stereoElem.tagName();
+ if (Uml::tagEq(tag, "Stereotype")) {
+ stereo = stereoElem.attribute("xmi.idref", "");
+ }
+ }
+ if (stereo.isEmpty())
+ return false;
+ Uml::IDType stereoID = STR2ID(stereo);
+ UMLDoc *pDoc = UMLApp::app()->getDocument();
+ m_pStereotype = pDoc->findStereotypeById(stereoID);
+ if (m_pStereotype)
+ m_pStereotype->incrRefCount();
+ else
+ m_SecondaryId = stereo; // leave it to resolveRef()
+ return true;
+}
+
+bool UMLObject::loadFromXMI( QDomElement & element) {
+ UMLDoc* umldoc = UMLApp::app()->getDocument();
+ if (umldoc == NULL) {
+ kError() << "UMLObject::loadFromXMI: umldoc is NULL" << endl;
+ return false;
+ }
+ // Read the name first so that if we encounter a problem, the error
+ // message can say the name.
+ m_Name = element.attribute( "name", "" );
+ QString id = element.attribute( "xmi.id", "" );
+ if (id.isEmpty() || id == "-1") {
+ if (m_BaseType == Uml::ot_Role) {
+ // Before version 1.4, Umbrello did not save the xmi.id
+ // of UMLRole objects.
+ m_nId = UniqueID::gen();
+ } else {
+ kError() << "UMLObject::loadFromXMI(" << m_Name
+ << "): nonexistent or illegal xmi.id" << endl;
+ return false;
+ }
+ } else {
+ m_nId = STR2ID(id);
+ if (m_BaseType == Uml::ot_Role) {
+ // Some older Umbrello versions had a problem with xmi.id's
+ // of other objects being reused for the UMLRole, see e.g.
+ // attachment 21179 at http://bugs.kde.org/147988 .
+ // If the xmi.id is already being used then we generate a new one.
+ UMLObject *o = umldoc->findObjectById(m_nId);
+ if (o) {
+ kDebug() << "loadFromXMI(UMLRole): id " << id
+ << " is already in use, generating a new one." << endl;
+ m_nId = UniqueID::gen();
+ }
+ }
+ }
+
+ if (element.hasAttribute("documentation")) // for bkwd compat.
+ m_Doc = element.attribute( "documentation", "" );
+ else
+ m_Doc = element.attribute( "comment", "" ); //CHECK: need a UML:Comment?
+
+ m_Vis = Uml::Visibility::Public;
+ if (element.hasAttribute("scope")) { // for bkwd compat.
+ QString scope = element.attribute( "scope", "" );
+ if (scope == "instance_level") // nsuml compat.
+ m_bStatic = false;
+ else if (scope == "classifier_level") // nsuml compat.
+ m_bStatic = true;
+ else {
+ int nScope = scope.toInt();
+ if (nScope >= Uml::Visibility::Public && nScope <= Uml::Visibility::Protected)
+ m_Vis = (Uml::Visibility::Value)nScope;
+ else
+ kError() << "UMLObject::loadFromXMI(" << m_Name
+ << "): illegal scope" << endl; // soft error
+ }
+ } else {
+ QString visibility = element.attribute( "visibility", "public" );
+ if (visibility == "private"
+ || visibility == "private_vis") // for compatibility with other programs
+ m_Vis = Uml::Visibility::Private;
+ else if (visibility == "protected"
+ || visibility == "protected_vis") // for compatibility with other programs
+ m_Vis = Uml::Visibility::Protected;
+ else if (visibility == "implementation")
+ m_Vis = Uml::Visibility::Implementation;
+ }
+
+ QString stereo = element.attribute( "stereotype", "" );
+ if (!stereo.isEmpty()) {
+ Uml::IDType stereoID = STR2ID(stereo);
+ m_pStereotype = umldoc->findStereotypeById(stereoID);
+ if (m_pStereotype) {
+ m_pStereotype->incrRefCount();
+ } else {
+ kDebug() << "UMLObject::loadFromXMI(" << m_Name << "): "
+ << "UMLStereotype " << ID2STR(stereoID)
+ << " not found, creating now." << endl;
+ setStereotype(stereo);
+ }
+ }
+
+ if( element.hasAttribute("abstract") ) { // for bkwd compat.
+ QString abstract = element.attribute( "abstract", "0" );
+ m_bAbstract = (bool)abstract.toInt();
+ } else {
+ QString isAbstract = element.attribute( "isAbstract", "false" );
+ m_bAbstract = (isAbstract == "true");
+ }
+
+ if( element.hasAttribute("static") ) { // for bkwd compat.
+ QString staticScope = element.attribute( "static", "0" );
+ m_bStatic = (bool)staticScope.toInt();
+ } else {
+ QString ownerScope = element.attribute( "ownerScope", "instance" );
+ m_bStatic = (ownerScope == "classifier");
+ }
+
+ // If the node has child nodes, check whether attributes can be
+ // extracted from them.
+ if (element.hasChildNodes()) {
+ QDomNode node = element.firstChild();
+ if (node.isComment())
+ node = node.nextSibling();
+ QDomElement elem = node.toElement();
+ while( !elem.isNull() ) {
+ QString tag = elem.tagName();
+ if (Uml::tagEq(tag, "name")) {
+ m_Name = elem.attribute("xmi.value", "");
+ if (m_Name.isEmpty())
+ m_Name = elem.text();
+ } else if (Uml::tagEq(tag, "visibility")) {
+ QString vis = elem.attribute("xmi.value", "");
+ if (vis.isEmpty())
+ vis = elem.text();
+ if (vis == "private" || vis == "private_vis")
+ m_Vis = Uml::Visibility::Private;
+ else if (vis == "protected" || vis == "protected_vis")
+ m_Vis = Uml::Visibility::Protected;
+ else if (vis == "implementation")
+ m_Vis = Uml::Visibility::Implementation;
+ } else if (Uml::tagEq(tag, "isAbstract")) {
+ QString isAbstract = elem.attribute("xmi.value", "");
+ if (isAbstract.isEmpty())
+ isAbstract = elem.text();
+ m_bAbstract = (isAbstract == "true");
+ } else if (Uml::tagEq(tag, "ownerScope")) {
+ QString ownerScope = elem.attribute("xmi.value", "");
+ if (ownerScope.isEmpty())
+ ownerScope = elem.text();
+ m_bStatic = (ownerScope == "classifier");
+ } else {
+ loadStereotype(elem);
+ }
+ node = node.nextSibling();
+ if (node.isComment())
+ node = node.nextSibling();
+ elem = node.toElement();
+ }
+ }
+
+ // Operations, attributes, enum literals, templates, stereotypes,
+ // and association role objects get added and signaled elsewhere.
+ if (m_BaseType != Uml::ot_Operation && m_BaseType != Uml::ot_Attribute &&
+ m_BaseType != Uml::ot_EnumLiteral && m_BaseType != Uml::ot_EntityAttribute &&
+ m_BaseType != Uml::ot_Template && m_BaseType != Uml::ot_Stereotype &&
+ m_BaseType != Uml::ot_Role) {
+ if (m_bInPaste) {
+ m_pUMLPackage = NULL; // forget any old parent
+ UMLListView *listView = UMLApp::app()->getListView();
+ UMLListViewItem *parentItem = (UMLListViewItem*)listView->currentItem();
+ if (parentItem) {
+ Uml::ListView_Type lvt = parentItem->getType();
+ if (Model_Utils::typeIsContainer(lvt) ||
+ lvt == Uml::lvt_Class ||
+ lvt == Uml::lvt_Interface) {
+ UMLObject *o = parentItem->getUMLObject();
+ m_pUMLPackage = static_cast<UMLPackage*>( o );
+ }
+ }
+ }
+ if (m_pUMLPackage) {
+ m_pUMLPackage->addObject(this);
+ } else if (umldoc->rootFolderType(this) == Uml::N_MODELTYPES) {
+ // m_pUMLPackage is not set on the root folders.
+ kDebug() << "UMLObject::loadFromXMI(" << m_Name << "): m_pUMLPackage is not set"
+ << endl;
+ }
+ }
+ return load(element);
+}
+
+kdbgstream& operator<< (kdbgstream& s, const UMLObject& a) {
+ s << a.getName();
+ return s;
+}
+
+#include "umlobject.moc"
diff --git a/umbrello/umbrello/umlobject.h b/umbrello/umbrello/umlobject.h
new file mode 100644
index 00000000..d912bafc
--- /dev/null
+++ b/umbrello/umbrello/umlobject.h
@@ -0,0 +1,495 @@
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * copyright (C) 2002-2007 *
+ * Umbrello UML Modeller Authors <uml-devel@uml.sf.net> *
+ ***************************************************************************/
+
+#ifndef UMLOBJECT_H
+#define UMLOBJECT_H
+
+//qt includes
+#include <qobject.h>
+#include <qstring.h>
+#include <qdom.h>
+
+#include "umlnamespace.h"
+#include "umlpackagelist.h"
+
+class kdbgstream;
+class UMLStereotype;
+class UMLObject;
+
+/**
+ * This class is the non-graphical version of @ref UMLWidget. These are
+ * created and maintained in the class @ref UMLDoc. This class holds all
+ * the generic information needed for all UML objects.
+ *
+ * @short The base class for UML objects.
+ * @author Paul Hensgen <phensgen@techie.com>
+ * Bugs and comments to uml-devel@lists.sf.net or http://bugs.kde.org
+ */
+class UMLObject : public QObject {
+ Q_OBJECT
+public:
+
+ /**
+ * Creates a UMLObject.
+ *
+ * @param parent The parent of the object.
+ * @param name The name of the object.
+ * @param id The ID of the object (optional.) If omitted
+ * then a new ID will be assigned internally.
+ */
+ UMLObject(const UMLObject * parent, const QString &name, Uml::IDType id = Uml::id_None);
+
+ /**
+ * Creates a UMLObject.
+ *
+ * @param parent The parent of the object.
+ */
+ UMLObject(const UMLObject * parent);
+
+ /**
+ * Creates a UMLObject with a given name and unique ID.
+ *
+ * @param name The name of the object.
+ * @param id The unique ID of the object.
+ */
+ explicit UMLObject(const QString &name = "" , Uml::IDType id = Uml::id_None);
+
+ /**
+ * Overloaded '==' operator
+ */
+ virtual bool operator==(UMLObject & rhs );
+
+ /**
+ * Standard deconstructor.
+ */
+ virtual ~UMLObject();
+
+ /**
+ * Copy the internal presentation of this object into the new
+ * object.
+ */
+ virtual void copyInto(UMLObject *rhs) const;
+
+ /**
+ * Make a clone of this object.
+ * To be implemented by inheriting classes.
+ */
+ virtual UMLObject* clone() const = 0;
+
+ /**
+ * Returns the type of the object.
+ *
+ * @return Returns the type of the object.
+ */
+ Uml::Object_Type getBaseType() const;
+
+ /**
+ * Set the type of the object.
+ *
+ * @param ot The Uml::Object_Type to set.
+ */
+ virtual void setBaseType(Uml::Object_Type ot);
+
+ /**
+ * Returns the ID of the object.
+ *
+ * @return Returns the ID of the object.
+ */
+ virtual Uml::IDType getID() const;
+
+ /**
+ * Sets the documentation for the object.
+ *
+ * @param d The documentation for the object.
+ */
+ void setDoc(const QString &d);
+
+ /**
+ * Returns the documentation for the object.
+ *
+ * @return Returns the documentation for the object.
+ */
+ QString getDoc() const;
+
+ /**
+ * Returns the visibility of the object.
+ *
+ * @return Returns the visibility of the object.
+ */
+ Uml::Visibility getVisibility() const;
+
+ /**
+ * Sets the visibility of the object.
+ *
+ * @param s The visibility of the object.
+ */
+ virtual void setVisibility(Uml::Visibility s);
+
+ /**
+ * Sets the classes stereotype name.
+ * Internally uses setUMLStereotype().
+ *
+ * @param _name Sets the classes stereotype name.
+ */
+ void setStereotype(const QString &_name);
+
+ /**
+ * Sets the class' UMLStereotype. Adjusts the reference counts
+ * at the previously set stereotype and at the new stereotype.
+ * If the previously set UMLStereotype's reference count drops
+ * to zero then the UMLStereotype is removed at the UMLDoc and
+ * it is then physically deleted.
+ *
+ * @param s Sets the classes UMLStereotype.
+ */
+ void setUMLStereotype(UMLStereotype *s);
+
+ /**
+ * Sets the classes Package.
+ * DEPRECATED - use SetUMLPackage instead.
+ *
+ * @param _name The classes Package name.
+ */
+ void setPackage(const QString &_name);
+
+ /**
+ * Sets the UMLPackage in which this class is located.
+ *
+ * @param pPkg Pointer to the class' UMLPackage.
+ */
+ void setUMLPackage(UMLPackage* pPkg);
+
+ /**
+ * Returns the classes UMLStereotype object.
+ *
+ * @return Returns the classes UMLStereotype object.
+ */
+ const UMLStereotype * getUMLStereotype();
+
+ /**
+ * Returns the classes stereotype name.
+ * Returns an empty string if no stereotype object is set.
+ *
+ * @param includeAdornments Include surrounding angled brackets
+ * "«" and "»".
+ * @return Returns the classes stereotype name.
+ */
+ QString getStereotype(bool includeAdornments = false) const;
+
+ /**
+ * Return the package(s) in which this UMLObject is contained
+ * as a text.
+ *
+ * @param separator Separator string for joining together the
+ * individual package prefixes (optional.)
+ * If no separator is given then the separator
+ * of the currently selected language is used.
+ * @param includeRoot Whether to prefix the root folder name.
+ * Default: false.
+ * @return The UMLObject's enclosing package(s) as a text.
+ */
+ QString getPackage(const QString& separator = QString::null,
+ bool includeRoot = false);
+
+ /**
+ * Return a list of the packages in which this class is embedded.
+ * The outermost package is first in the list.
+ *
+ * @param includeRoot Whether to prefix the root folder name.
+ * Default: false.
+ * @return UMLPackageList of the containing packages.
+ */
+ UMLPackageList getPackages(bool includeRoot = false) const;
+
+ /**
+ * Returns the UMLPackage that this class is located in.
+ *
+ * @return Pointer to the UMLPackage of this class.
+ */
+ UMLPackage* getUMLPackage();
+
+ /**
+ * Assigns a new Id to the object
+ */
+ virtual void setID(Uml::IDType NewID);
+
+ /**
+ * Returns a copy of m_Name
+ */
+ QString getName() const;
+
+ /**
+ * Set the UMLObject's name
+ */
+ virtual void setName(const QString &strName);
+
+ /**
+ * Returns the fully qualified name, i.e. all package prefixes and then m_Name.
+ *
+ * @param separator The separator string to use (optional.)
+ * If not given then the separator is chosen according
+ * to the currently selected active programming language
+ * of import and code generation.
+ * @param includeRoot Whether to prefix the root folder name to the FQN.
+ * See UMLDoc::getRootFolder(). Default: false.
+ * @return The fully qualified name of this UMLObject.
+ */
+ virtual QString getFullyQualifiedName(const QString& separator = QString::null,
+ bool includeRoot = false) const;
+
+ /**
+ * Returns the abstract state of the object.
+ */
+ bool getAbstract() const;
+
+ /**
+ * Sets the abstract state of the object.
+ */
+ void setAbstract(bool bAbstract);
+
+ /**
+ * Sets the abstract state of the object.
+ */
+ void setInPaste(bool bInPaste = true);
+
+ /**
+ * This method is called if you wish to see the properties of a
+ * UMLObject. A dialog box will be displayed from which you
+ * can change the object's properties.
+ *
+ * @param page The page to show.
+ * @param assoc Whether to show association page.
+ * @return True if we modified the object.
+ */
+ bool showProperties(int page = 0, bool assoc = false);
+
+ /**
+ * Resolve referenced objects (if any.)
+ * Needs to be called after all UML objects are loaded from file.
+ * This needs to be done after all model objects are loaded because
+ * some of the xmi.id's might be forward references, i.e. they may
+ * identify model objects which were not yet loaded at the point of
+ * reference.
+ * The default implementation attempts resolution of the m_SecondaryId.
+ *
+ * @return True for success.
+ */
+ virtual bool resolveRef();
+
+ /**
+ * This method saves the XMI attributes of each specific model class.
+ * It needs to be implemented by each child class.
+ * For creating the QDomElement and saving the common XMI parts,
+ * it can use the save() method.
+ */
+ virtual void saveToXMI( QDomDocument & qDoc, QDomElement & qElement ) = 0;
+
+ /**
+ * This method loads the generic parts of the XMI common to most model
+ * classes. It is not usually reimplemented by child classes.
+ * Instead, it invokes the load() method which implements the loading
+ * of the specifics of each child class.
+ *
+ * @param element The QDomElement from which to load.
+ */
+ virtual bool loadFromXMI( QDomElement & element );
+
+ /**
+ * Analyzes the given QDomElement for a reference to a stereotype.
+ *
+ * @param element QDomElement to analyze.
+ * @return True if a stereotype reference was found, else false.
+ */
+ bool loadStereotype(QDomElement & element);
+
+ /**
+ * Returns true if this UMLObject has classifier scope,
+ * otherwise false (the default).
+ */
+ bool getStatic() const;
+
+
+ /**
+ * Sets the value for m_bStatic.
+ */
+ void setStatic(bool bStatic);
+
+ /**
+ * This should be reimplemented by subclasses if they wish to
+ * accept certain types of associations. Note that this only
+ * tells if this UMLObject can accept the association
+ * type. When creating an association another check is made to
+ * see if the association is valid. For example a UMLClass
+ * (UMLClassifier) can accept generalizations and should
+ * return true. If while creating a generalization the
+ * superclass is already subclassed from this, the association
+ * is not valid and will not be created. The default accepts
+ * nothing (returns false)
+ */
+ virtual bool acceptAssociationType(Uml::Association_Type);
+
+ /**
+ * Return secondary ID. Required by resolveRef().
+ */
+ QString getSecondaryId() const;
+
+ /**
+ * Set the secondary ID.
+ * Currently only required by petalTree2Uml(); all other setting of the
+ * m_SecondaryID is internal to the UMLObject class hierarchy.
+ */
+ void setSecondaryId(const QString& id);
+
+ /**
+ * Return secondary ID fallback.
+ * Required by resolveRef() for imported model files.
+ */
+ QString getSecondaryFallback() const;
+
+ /**
+ * Set the secondary ID fallback.
+ * Currently only used by petalTree2Uml().
+ */
+ void setSecondaryFallback(const QString& id);
+
+ /**
+ * Auxiliary to saveToXMI.
+ * Create a QDomElement with the given tag, and save the XMI attributes
+ * that are common to all child classes to the newly created element.
+ * This method does not need to be overridden by child classes.
+ */
+ QDomElement save( const QString &tag, QDomDocument & qDoc );
+
+public slots:
+ /**
+ * Forces the emission of the modified signal. Useful when
+ * updating several attributes at a time: you can block the
+ * signals, update all atts, and then force the signal.
+ */
+ void emitModified();
+
+signals:
+ /** Emitted when the UMLObject has changed. Note that some objects emit
+ * this signal when one of its children changes, for example, a UMLClass
+ * emits a modified() signal when one of its operation changes while the Operation
+ * itself emits the corresponding signal as well.
+ */
+ void modified();
+
+protected:
+ /**
+ * Initializes key variables of the class.
+ */
+ virtual void init();
+
+ /**
+ * Calls UMLDoc::signalUMLObjectCreated() if m_BaseType affords
+ * doing so.
+ */
+ void maybeSignalObjectCreated();
+
+ /**
+ * Auxiliary to loadFromXMI.
+ * This method is usually overridden by child classes.
+ * It is responsible for loading the specific XMI structure
+ * of the child class.
+ */
+ virtual bool load( QDomElement& element );
+
+ /**
+ * The object's id.
+ */
+ Uml::IDType m_nId;
+
+ /**
+ * The object's documentation.
+ */
+ QString m_Doc;
+
+ /**
+ * The package the object belongs to if applicable.
+ */
+ UMLPackage* m_pUMLPackage;
+
+ /**
+ * The stereotype of the object if applicable.
+ */
+ UMLStereotype* m_pStereotype;
+
+ /**
+ * The objects name.
+ */
+ QString m_Name;
+
+ /**
+ * The objects type.
+ */
+ Uml::Object_Type m_BaseType;
+
+ /**
+ * The objects visibility.
+ */
+ Uml::Visibility m_Vis;
+
+ /**
+ * The state of whether the object is abstract or not.
+ */
+ bool m_bAbstract;
+
+ /**
+ * This attribute holds whether the UMLObject has instance scope
+ * (false - the default) or classifier scope (true).
+ */
+ bool m_bStatic;
+
+ /**
+ * Caller sets this true when in paste operation.
+ */
+ bool m_bInPaste;
+
+ /**
+ * Auxiliary to maybeSignalObjectCreated().
+ */
+ bool m_bCreationWasSignalled;
+
+ /**
+ * Pointer to an associated object.
+ * Only a few of the classes inheriting from UMLObject use this.
+ * However, it needs to be here because of inheritance graph
+ * disjunctness.
+ */
+ UMLObject* m_pSecondary;
+
+ /**
+ * xmi.id of the secondary object for intermediate use during
+ * loading. The secondary ID is resolved to the m_pSecondary
+ * in the course of resolveRef() at the end of loading.
+ */
+ QString m_SecondaryId;
+
+ /**
+ * Last-chance backup for when m_SecondaryId is not found.
+ * Used by Rose import: MDL files specify both a "quidu"
+ * (which corresponds to m_SecondaryId) and the human readable
+ * fully qualified target name of a reference.
+ * In case the quidu is not found, the human readable name is
+ * used which we store in m_SecondaryFallback.
+ */
+ QString m_SecondaryFallback;
+};
+
+/**
+ * Print UML Object to kdgstream, so it can be used like
+ * kdWarn() << "This object shouldn't be here:" << illegalObject << endl;
+ */
+kdbgstream& operator<< (kdbgstream& s, const UMLObject& a);
+
+#endif
diff --git a/umbrello/umbrello/umlobjectlist.cpp b/umbrello/umbrello/umlobjectlist.cpp
new file mode 100644
index 00000000..f2850ebd
--- /dev/null
+++ b/umbrello/umbrello/umlobjectlist.cpp
@@ -0,0 +1,42 @@
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * copyright (C) 2002-2006 *
+ * Umbrello UML Modeller Authors <uml-devel@uml.sf.net> *
+ ***************************************************************************/
+
+#include "umlobjectlist.h"
+#include "umlobject.h"
+#include <kdebug.h>
+#include <klocale.h>
+
+void UMLObjectList::copyInto(UMLObjectList *rhs) const {
+ // Don't copy yourself.
+ if (rhs == this) return;
+
+ rhs->clear();
+
+ // Suffering from const; we shall not modify our object.
+ UMLObjectList *tmp = new UMLObjectList(*this);
+
+ UMLObject *item;
+ for (item = tmp->first(); item; item = tmp->next() )
+ {
+ rhs->append(item->clone());
+ }
+ delete tmp;
+}
+
+
+UMLObjectList* UMLObjectList::clone() const {
+ UMLObjectList *clone = new UMLObjectList();
+ copyInto(clone);
+ return clone;
+}
+
+
+
diff --git a/umbrello/umbrello/umlobjectlist.h b/umbrello/umbrello/umlobjectlist.h
new file mode 100644
index 00000000..d9d11c83
--- /dev/null
+++ b/umbrello/umbrello/umlobjectlist.h
@@ -0,0 +1,53 @@
+/***************************************************************************
+ umlobjectlist.h - description
+ -------------------
+ begin : Sat Dec 29 2001
+ copyright : (C) 2001 by Gustavo Madrigal
+ email : gmadrigal@nextphere.com
+ Bugs and comments to uml-devel@lists.sf.net or http://bugs.kde.org
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the 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 UMLOBJECTLIST_H
+#define UMLOBJECTLIST_H
+
+#include <qptrlist.h>
+
+// forward declarations
+class UMLObject;
+
+//typedef QPtrList<UMLObject> UMLObjectList;
+typedef QPtrListIterator<UMLObject> UMLObjectListIt;
+
+
+/**
+ * This sub-class adds copyInto and clone to the QPtrList<UMLObject>
+ * base class.
+ */
+class UMLObjectList : public QPtrList<UMLObject>
+{
+
+public:
+
+ /**
+ * Copy the internal presentation of this object into the new
+ * object.
+ */
+ virtual void copyInto (UMLObjectList *rhs) const;
+
+ /**
+ * Make a clone of this object.
+ */
+ virtual UMLObjectList* clone() const;
+};
+
+
+#endif
diff --git a/umbrello/umbrello/umloperationlist.h b/umbrello/umbrello/umloperationlist.h
new file mode 100644
index 00000000..dfb9007e
--- /dev/null
+++ b/umbrello/umbrello/umloperationlist.h
@@ -0,0 +1,23 @@
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * copyright (C) 2003-2007 *
+ * Umbrello UML Modeller Authors <uml-devel@uml.sf.net> *
+ ***************************************************************************/
+
+#ifndef UMLOPERATIONLIST_H
+#define UMLOPERATIONLIST_H
+
+#include <qptrlist.h>
+
+// forward declaration
+class UMLOperation;
+
+typedef QPtrList<UMLOperation> UMLOperationList;
+typedef QPtrListIterator<UMLOperation> UMLOperationListIt;
+
+#endif
diff --git a/umbrello/umbrello/umlpackagelist.h b/umbrello/umbrello/umlpackagelist.h
new file mode 100644
index 00000000..d74e8c33
--- /dev/null
+++ b/umbrello/umbrello/umlpackagelist.h
@@ -0,0 +1,22 @@
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * copyright (C) 2003-2007 *
+ * Umbrello UML Modeller Authors <uml-devel@uml.sf.net> *
+ ***************************************************************************/
+
+#ifndef UMLPACKAGELIST_H
+#define UMLPACKAGELIST_H
+
+#include <qptrlist.h>
+
+class UMLPackage;
+
+typedef QPtrList<UMLPackage> UMLPackageList;
+typedef QPtrListIterator<UMLPackage> UMLPackageListIt;
+
+#endif
diff --git a/umbrello/umbrello/umlrole.cpp b/umbrello/umbrello/umlrole.cpp
new file mode 100644
index 00000000..9b4449fc
--- /dev/null
+++ b/umbrello/umbrello/umlrole.cpp
@@ -0,0 +1,339 @@
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * copyright (C) 2003-2007 *
+ * Umbrello UML Modeller Authors <uml-devel@uml.sf.net> *
+ ***************************************************************************/
+
+// own header
+#include "umlrole.h"
+
+// qt/kde includes
+#include <kdebug.h>
+#include <qregexp.h>
+
+// local includes
+#include "association.h"
+#include "umldoc.h"
+#include "uml.h"
+
+
+// constructor
+UMLRole::UMLRole(UMLAssociation * parent, UMLObject * parentObj, Uml::Role_Type role)
+ : UMLObject(const_cast<UMLAssociation*>(parent))
+{
+ init(parent, parentObj, role);
+}
+
+UMLRole::~UMLRole() { }
+
+bool UMLRole::operator==(UMLRole &rhs) {
+ if (this == &rhs) {
+ return true;
+ }
+ return ( UMLObject::operator==( rhs ) &&
+ m_Changeability == rhs.m_Changeability &&
+ m_Multi == rhs.m_Multi &&
+ m_Name == rhs.m_Name
+ );
+}
+
+UMLAssociation * UMLRole::getParentAssociation () {
+ return m_pAssoc;
+}
+
+UMLObject* UMLRole::getObject() {
+ return m_pSecondary;
+}
+
+Uml::Changeability_Type UMLRole::getChangeability() const {
+ return m_Changeability;
+}
+
+QString UMLRole::getMultiplicity() const {
+ return m_Multi;
+}
+
+void UMLRole::setObject (UMLObject *obj) {
+ // because we will get the id of this role from the parent
+ // object, we CANT allow UMLRoles to take other UMLRoles as
+ // parent objects. In fact, there is probably good reason
+ // to only take UMLClassifiers here, but I'll leave it more open
+ // for the time being. -b.t.
+ if (obj && dynamic_cast<UMLRole*>(obj)) {
+ kError() << "UMLRole(" << ID2STR(m_nId) << ") cannot setObject() to another UMLRole("
+ << ID2STR(obj->getID()) << ")" << endl;
+ return;
+ }
+
+ m_pSecondary = obj;
+ UMLObject::emitModified();
+}
+
+void UMLRole::setChangeability (Uml::Changeability_Type value) {
+ m_Changeability = value;
+ UMLObject::emitModified();
+}
+
+void UMLRole::setMultiplicity ( const QString &multi ) {
+ m_Multi = multi;
+ UMLObject::emitModified();
+}
+
+Uml::Role_Type UMLRole::getRole() {
+ return m_role;
+}
+
+void UMLRole::init(UMLAssociation * parent, UMLObject * parentObj, Uml::Role_Type r) {
+ m_BaseType = Uml::ot_Role;
+ m_role = r;
+ m_pAssoc = parent;
+ m_pSecondary = parentObj;
+ m_Multi = "";
+ m_Name = "";
+ m_Changeability = Uml::chg_Changeable;
+
+ // connect this up to parent
+ connect(this,SIGNAL(modified()),parent,SIGNAL(modified()));
+}
+
+void UMLRole::saveToXMI( QDomDocument & qDoc, QDomElement & qElement ) {
+ QDomElement roleElement = UMLObject::save("UML:AssociationEnd", qDoc);
+ if (m_pSecondary)
+ roleElement.setAttribute( "type", ID2STR(m_pSecondary->getID()) );
+ else
+ kError() << "UMLRole::saveToXMI(id " << ID2STR(m_nId)
+ << "): m_pSecondary is NULL" << endl;
+ if (!m_Multi.isEmpty())
+ roleElement.setAttribute("multiplicity", m_Multi);
+ if (m_role == Uml::A) { // role aggregation based on parent type
+ // role A
+ switch (m_pAssoc->getAssocType()) {
+ case Uml::at_Composition:
+ roleElement.setAttribute("aggregation", "composite");
+ break;
+ case Uml::at_Aggregation:
+ roleElement.setAttribute("aggregation", "aggregate");
+ break;
+ default:
+ roleElement.setAttribute("aggregation", "none");
+ break;
+ }
+ if (m_pAssoc->getAssocType() == Uml::at_UniAssociation) {
+ // Normally the isNavigable attribute is "true".
+ // We set it to false on role A to indicate that
+ // role B gets an explicit arrowhead.
+ roleElement.setAttribute("isNavigable", "false");
+ } else {
+ roleElement.setAttribute("isNavigable", "true");
+ }
+ } else {
+ roleElement.setAttribute("aggregation", "none");
+ roleElement.setAttribute("isNavigable", "true");
+ //FIXME obviously this isn't standard XMI
+ if (m_pAssoc->getAssocType() == Uml::at_Relationship) {
+ roleElement.setAttribute("relationship", "true");
+ }
+ }
+
+ roleElement.setAttribute("visibility", getVisibility().toString(false));
+
+ switch (m_Changeability) {
+ case Uml::chg_Frozen:
+ roleElement.setAttribute("changeability", "frozen");
+ break;
+ case Uml::chg_AddOnly:
+ roleElement.setAttribute("changeability", "addOnly");
+ break;
+ case Uml::chg_Changeable:
+ roleElement.setAttribute("changeability", "changeable");
+ break;
+ }
+ qElement.appendChild( roleElement );
+}
+
+bool UMLRole::load( QDomElement & element ) {
+ UMLDoc * doc = UMLApp::app()->getDocument();
+ QString type = element.attribute("type", "");
+ if (!type.isEmpty()) {
+ if (!m_SecondaryId.isEmpty())
+ kWarning() << "UMLRole::load: overwriting old m_SecondaryId \""
+ << m_SecondaryId << " with new value \""
+ << type << "\"" << endl;
+ m_SecondaryId = type;
+ }
+ // Inspect child nodes - for multiplicity (and type if not set above.)
+ for (QDomNode node = element.firstChild(); !node.isNull(); node = node.nextSibling()) {
+ if (node.isComment())
+ continue;
+ QDomElement tempElement = node.toElement();
+ QString tag = tempElement.tagName();
+ if (Uml::tagEq(tag, "name")) {
+ m_Name = tempElement.text();
+ } else if (Uml::tagEq(tag, "AssociationEnd.multiplicity")) {
+ /**
+ * There are different ways in which the multiplicity might be given:
+ * - direct value in the <AssociationEnd.multiplicity> tag,
+ * - attributes "lower" and "upper" of a subordinate <MultiplicityRange>,
+ * - direct value in subordinate <MultiplicityRange.lower> and
+ * <MultiplicityRange.upper> tags
+ */
+ QDomNode n = tempElement.firstChild();
+ if (node.isNull() || tempElement.isNull() || n.isNull() ||
+ n.toElement().isNull()) {
+ m_Multi = tempElement.text().stripWhiteSpace();
+ continue;
+ }
+ tempElement = n.toElement();
+ tag = tempElement.tagName();
+ if (!Uml::tagEq(tag, "Multiplicity")) {
+ m_Multi = tempElement.text().stripWhiteSpace();
+ continue;
+ }
+ n = tempElement.firstChild();
+ tempElement = n.toElement();
+ tag = tempElement.tagName();
+ if (!Uml::tagEq(tag, "Multiplicity.range")) {
+ m_Multi = tempElement.text().stripWhiteSpace();
+ continue;
+ }
+ n = tempElement.firstChild();
+ tempElement = n.toElement();
+ tag = tempElement.tagName();
+ if (!Uml::tagEq(tag, "MultiplicityRange")) {
+ m_Multi = tempElement.text().stripWhiteSpace();
+ continue;
+ }
+ QString multiUpper;
+ if (tempElement.hasAttribute("lower")) {
+ m_Multi = tempElement.attribute("lower", "");
+ multiUpper = tempElement.attribute("upper", "");
+ if (!multiUpper.isEmpty()) {
+ if (!m_Multi.isEmpty())
+ m_Multi.append("..");
+ m_Multi.append(multiUpper);
+ }
+ continue;
+ }
+ n = tempElement.firstChild();
+ while (!n.isNull()) {
+ tempElement = n.toElement();
+ tag = tempElement.tagName();
+ if (Uml::tagEq(tag, "MultiplicityRange.lower")) {
+ m_Multi = tempElement.text();
+ } else if (Uml::tagEq(tag, "MultiplicityRange.upper")) {
+ multiUpper = tempElement.text();
+ }
+ n = n.nextSibling();
+ }
+ if (!multiUpper.isEmpty()) {
+ if (!m_Multi.isEmpty())
+ m_Multi.append("..");
+ m_Multi.append(multiUpper);
+ }
+ } else if (m_SecondaryId.isEmpty() &&
+ (Uml::tagEq(tag, "type") ||
+ Uml::tagEq(tag, "participant"))) {
+ m_SecondaryId = tempElement.attribute("xmi.id", "");
+ if (m_SecondaryId.isEmpty())
+ m_SecondaryId = tempElement.attribute("xmi.idref", "");
+ if (m_SecondaryId.isEmpty()) {
+ QDomNode inner = tempElement.firstChild();
+ QDomElement innerElem = inner.toElement();
+ m_SecondaryId = innerElem.attribute("xmi.id", "");
+ if (m_SecondaryId.isEmpty())
+ m_SecondaryId = innerElem.attribute("xmi.idref", "");
+ }
+ }
+ }
+ if (!m_Multi.isEmpty())
+ kDebug() << "UMLRole::load(" << m_Name << "): m_Multi is " << m_Multi << endl;
+ if (m_SecondaryId.isEmpty()) {
+ kError() << "UMLRole::load(" << m_Name << "): type not given or illegal" << endl;
+ return false;
+ }
+ UMLObject * obj;
+ obj = doc->findObjectById(STR2ID(m_SecondaryId));
+ if (obj) {
+ m_pSecondary = obj;
+ m_SecondaryId = "";
+ }
+
+ // block signals to prevent needless updating
+ blockSignals(true);
+ // Here comes the handling of the association type.
+ // This is open for discussion - I'm pretty sure there are better ways..
+
+ // Yeah, for one, setting the *parent* object parameters from here is sucky
+ // as hell. Why are we using roleA to store what is essentially a parent (association)
+ // parameter, eh? The UML13.dtd is pretty silly, but since that is what
+ // is driving us to that point, we have to go with it. Some analysis of
+ // the component roles/linked items needs to be done in order to get things
+ // right. *sigh* -b.t.
+
+ // Setting association type from the role (A)
+ // Determination of the "aggregation" attribute used to be done only
+ // when (m_role == Uml::A) but some XMI writers (e.g. StarUML) place
+ // the aggregation attribute at role B.
+ // The role end with the aggregation unequal to "none" wins.
+ QString aggregation = element.attribute("aggregation", "none");
+ if (aggregation == "composite")
+ m_pAssoc->setAssocType(Uml::at_Composition);
+ else if (aggregation == "shared" // UML1.3
+ || aggregation == "aggregate") // UML1.4
+ m_pAssoc->setAssocType(Uml::at_Aggregation);
+
+ if (!element.hasAttribute("isNavigable")) {
+ /* Backward compatibility mode: In Umbrello version 1.3.x the
+ logic for saving the isNavigable flag was wrong.
+ May happen on loading role A.
+ */
+ m_pAssoc->setOldLoadMode(true);
+ } else if (m_pAssoc->getOldLoadMode() == true) {
+ /* Here is the original logic:
+ " Role B:
+ If isNavigable is not given, we make no change to the
+ association type.
+ If isNavigable is given, and is "true", then we assume that
+ the association's other end (role A) is not navigable, and
+ therefore we change the association type to UniAssociation.
+ The case that isNavigable is given as "false" is ignored.
+ Combined with the association type logic for role A, this
+ allows us to support at_Association and at_UniAssociation. "
+ */
+ if (element.attribute("isNavigable") == "true")
+ m_pAssoc->setAssocType(Uml::at_UniAssociation);
+ } else if (element.attribute("isNavigable") == "false") {
+ m_pAssoc->setAssocType(Uml::at_UniAssociation);
+ }
+
+ //FIXME not standard XMI
+ if (element.hasAttribute("relationship")) {
+ if (element.attribute("relationship") == "true") {
+ m_pAssoc->setAssocType(Uml::at_Relationship);
+ }
+ }
+
+ if (m_Multi.isEmpty())
+ m_Multi = element.attribute("multiplicity", "");
+
+ // Changeability defaults to Changeable if it cant set it here..
+ m_Changeability = Uml::chg_Changeable;
+ QString changeability = element.attribute("changeability", "");
+ if (changeability.isEmpty())
+ element.attribute("changeable", ""); // for backward compatibility
+ if (changeability == "frozen")
+ m_Changeability = Uml::chg_Frozen;
+ else if (changeability == "addOnly")
+ m_Changeability = Uml::chg_AddOnly;
+
+ // finished config, now unblock
+ blockSignals(false);
+ return true;
+}
+
+#include "umlrole.moc"
diff --git a/umbrello/umbrello/umlrole.h b/umbrello/umbrello/umlrole.h
new file mode 100644
index 00000000..63fe42b2
--- /dev/null
+++ b/umbrello/umbrello/umlrole.h
@@ -0,0 +1,128 @@
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * copyright (C) 2003-2006 *
+ * Umbrello UML Modeller Authors <uml-devel@uml.sf.net> *
+ ***************************************************************************/
+
+#ifndef UMLROLE_H
+#define UMLROLE_H
+
+#include "umlobject.h"
+
+class UMLAssociation;
+
+/**
+ * This class contains the non-graphic representation of an association role.
+ *
+ * @author Brian Thomas <brian.thomas@gsfc.nasa.gov>
+ * @see UMLObject
+ */
+
+class UMLRole : public UMLObject {
+ Q_OBJECT
+public:
+ /**
+ * Sets up an association.
+ *
+ * @param parent The parent (association) of this UMLRole.
+ * @param parentUMLObject The Parent UML Object of this UMLRole
+ * @param role The Uml::Role_Type of this UMLRole
+ */
+ UMLRole (UMLAssociation * parent, UMLObject * parentUMLObject, Uml::Role_Type role);
+
+ /**
+ * Overloaded '==' operator
+ */
+ bool operator==(UMLRole & rhs);
+
+ /**
+ * Standard deconstructor.
+ */
+ virtual ~UMLRole();
+
+ /**
+ * Returns the UMLObject assigned to the role.
+ * @return Pointer to the UMLObject in role.
+ */
+ UMLObject* getObject();
+
+ /**
+ * Returns the Changeablity of the role.
+ *
+ * @return Changeability_Type of role.
+ */
+ Uml::Changeability_Type getChangeability() const;
+
+ /**
+ * Returns the multiplicity assigned to the role.
+ *
+ * @return The multiplicity assigned to the role.
+ */
+ QString getMultiplicity() const;
+
+ /**
+ * Sets the UMLObject playing the role in the association.
+ *
+ * @param obj Pointer to the UMLObject of role.
+ */
+ void setObject(UMLObject *obj);
+
+ /**
+ * Sets the changeability of the role.
+ *
+ * @param value Changeability_Type of role changeability.
+ */
+ void setChangeability (Uml::Changeability_Type value);
+
+ /**
+ * Sets the multiplicity of the role.
+ *
+ * @param multi The multiplicity of role.
+ */
+ void setMultiplicity ( const QString &multi );
+
+ UMLAssociation * getParentAssociation ();
+
+ /** get the 'id' of the role (NOT the parent object). This could be
+ * either Uml::A or Uml::B. Yes, it would be better if we
+ * could get along without this, but we need it to distinguish saved
+ * umlrole objects in the XMI for 'self' associations where both roles
+ * will point to the same underlying UMLObject.
+ */
+ Uml::Role_Type getRole();
+
+ /**
+ * Make a clone of this object.
+ * Not yet implemented.
+ */
+ UMLObject* clone() const { return NULL; }
+
+ /**
+ * Creates the <UML:AssociationEnd> XMI element.
+ */
+ void saveToXMI(QDomDocument& qDoc, QDomElement& qElement);
+
+protected:
+ /**
+ * Loads the <UML:AssociationEnd> XMI element.
+ * Auxiliary to UMLObject::loadFromXMI.
+ */
+ bool load(QDomElement& element);
+
+private:
+
+ /** do some initialization at construction time */
+ void init (UMLAssociation * parent, UMLObject * parentObj, Uml::Role_Type r);
+
+ UMLAssociation * m_pAssoc;
+ Uml::Role_Type m_role;
+ QString m_Multi;
+ Uml::Changeability_Type m_Changeability;
+};
+
+#endif
diff --git a/umbrello/umbrello/umlstereotypelist.h b/umbrello/umbrello/umlstereotypelist.h
new file mode 100644
index 00000000..acf2edd7
--- /dev/null
+++ b/umbrello/umbrello/umlstereotypelist.h
@@ -0,0 +1,23 @@
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * copyright (C) 2003-2007 *
+ * Umbrello UML Modeller Authors <uml-devel@uml.sf.net> *
+ ***************************************************************************/
+
+#ifndef UMLSTEREOTYPELIST_H
+#define UMLSTEREOTYPELIST_H
+
+#include <qptrlist.h>
+
+// forward declaration
+class UMLStereotype;
+
+typedef QPtrList<UMLStereotype> UMLStereotypeList;
+typedef QPtrListIterator<UMLStereotype> UMLStereotypeListIt;
+
+#endif
diff --git a/umbrello/umbrello/umltemplatelist.h b/umbrello/umbrello/umltemplatelist.h
new file mode 100644
index 00000000..aa7415a4
--- /dev/null
+++ b/umbrello/umbrello/umltemplatelist.h
@@ -0,0 +1,23 @@
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * copyright (C) 2004-2007 *
+ * Umbrello UML Modeller Authors <uml-devel@uml.sf.net> *
+ ***************************************************************************/
+
+#ifndef UMLTEMPLATELIST_H
+#define UMLTEMPLATELIST_H
+
+#include <qptrlist.h>
+
+// forward declaration
+class UMLTemplate;
+
+typedef QPtrList<UMLTemplate> UMLTemplateList;
+typedef QPtrListIterator<UMLTemplate> UMLTemplateListIt;
+
+#endif
diff --git a/umbrello/umbrello/umlview.cpp b/umbrello/umbrello/umlview.cpp
new file mode 100644
index 00000000..0b6a7935
--- /dev/null
+++ b/umbrello/umbrello/umlview.cpp
@@ -0,0 +1,3352 @@
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * copyright (C) 2002-2007 *
+ * Umbrello UML Modeller Authors <uml-devel@uml.sf.net> *
+ ***************************************************************************/
+
+// own header
+#include "umlview.h"
+
+// system includes
+#include <climits>
+#include <math.h>
+
+// include files for Qt
+#include <qpixmap.h>
+#include <qpicture.h>
+#include <qprinter.h>
+#include <qpainter.h>
+#include <qstring.h>
+#include <qstringlist.h>
+#include <qobjectlist.h>
+#include <qobjectdict.h>
+#include <qdragobject.h>
+#include <qpaintdevicemetrics.h>
+#include <qfileinfo.h>
+#include <qptrlist.h>
+#include <qcolor.h>
+#include <qwmatrix.h>
+#include <qregexp.h>
+
+//kde include files
+#include <ktempfile.h>
+#include <kio/netaccess.h>
+#include <kmessagebox.h>
+#include <kprinter.h>
+#include <kcursor.h>
+#include <kfiledialog.h>
+#include <kinputdialog.h>
+#include <klocale.h>
+#include <kdebug.h>
+
+// application specific includes
+#include "umlviewimageexporter.h"
+#include "listpopupmenu.h"
+#include "uml.h"
+#include "umldoc.h"
+#include "umlobject.h"
+#include "docwindow.h"
+#include "assocrules.h"
+#include "umlrole.h"
+#include "umlviewcanvas.h"
+#include "dialogs/classoptionspage.h"
+#include "dialogs/umlviewdialog.h"
+#include "clipboard/idchangelog.h"
+#include "clipboard/umldrag.h"
+#include "widget_factory.h"
+#include "floatingtextwidget.h"
+#include "classifierwidget.h"
+#include "classifier.h"
+#include "packagewidget.h"
+#include "package.h"
+#include "folder.h"
+#include "componentwidget.h"
+#include "nodewidget.h"
+#include "artifactwidget.h"
+#include "datatypewidget.h"
+#include "enumwidget.h"
+#include "entitywidget.h"
+#include "actorwidget.h"
+#include "usecasewidget.h"
+#include "notewidget.h"
+#include "boxwidget.h"
+#include "associationwidget.h"
+#include "objectwidget.h"
+#include "messagewidget.h"
+#include "statewidget.h"
+#include "forkjoinwidget.h"
+#include "activitywidget.h"
+#include "seqlinewidget.h"
+#include "uniqueid.h"
+#include "umllistviewitemlist.h"
+#include "umllistviewitem.h"
+#include "umllistview.h"
+#include "umlobjectlist.h"
+#include "association.h"
+#include "attribute.h"
+#include "model_utils.h"
+#include "object_factory.h"
+#include "umlwidget.h"
+#include "toolbarstatefactory.h"
+
+
+// control the manual DoubleBuffering of QCanvas
+// with a define, so that this memory X11 effect can
+// be tested more easily
+#define MANUAL_CONTROL_DOUBLE_BUFFERING
+
+// static members
+const int UMLView::defaultCanvasSize = 1300;
+
+using namespace Uml;
+
+
+// constructor
+UMLView::UMLView(UMLFolder *parentFolder) : QCanvasView(UMLApp::app()->getMainViewWidget()) {
+ init();
+ m_pDoc = UMLApp::app()->getDocument();
+ m_pFolder = parentFolder;
+}
+
+void UMLView::init() {
+ // Initialize loaded/saved data
+ m_nID = Uml::id_None;
+ m_pDoc = NULL;
+ m_Documentation = "";
+ m_Type = dt_Undefined;
+ m_bUseSnapToGrid = false;
+ m_bUseSnapComponentSizeToGrid = false;
+ m_bShowSnapGrid = false;
+ m_nSnapX = 10;
+ m_nSnapY = 10;
+ m_nZoom = 100;
+ m_nCanvasWidth = UMLView::defaultCanvasSize;
+ m_nCanvasHeight = UMLView::defaultCanvasSize;
+ m_nCollaborationId = 0;
+
+ // Initialize other data
+ m_AssociationList.setAutoDelete( true );
+
+ //Setup up booleans
+ m_bChildDisplayedDoc = false;
+ m_bPaste = false;
+ m_bActivated = false;
+ m_bCreateObject = false;
+ m_bDrawSelectedOnly = false;
+ m_bPopupShowing = false;
+ m_bStartedCut = false;
+ //clear pointers
+ m_PastePoint = QPoint(0, 0);
+ m_pIDChangesLog = 0;
+ m_pMenu = 0;
+
+ m_pImageExporter = new UMLViewImageExporter(this);
+
+ //setup graphical items
+ viewport() -> setBackgroundMode( Qt::NoBackground );
+ setCanvas( new UMLViewCanvas( this ) );
+ // don't set the quite frequent update rate for each
+ // diagram, as that causes also an update of invisible
+ // diagrams, which can cost high CPU load for many
+ // diagrams.
+ // Instead: set the updatePeriod to 20 on Show event,
+ // and switch update back off on Hide event
+ canvas() -> setUpdatePeriod( -1 );
+ resizeContents(defaultCanvasSize, defaultCanvasSize);
+ canvas() -> resize(defaultCanvasSize, defaultCanvasSize);
+ setAcceptDrops(true);
+ viewport() -> setAcceptDrops(true);
+ setDragAutoScroll(false);
+
+ viewport() -> setMouseTracking(false);
+
+ //setup signals
+ connect( this, SIGNAL(sigRemovePopupMenu()), this, SLOT(slotRemovePopupMenu() ) );
+ connect( UMLApp::app(), SIGNAL( sigCutSuccessful() ),
+ this, SLOT( slotCutSuccessful() ) );
+
+ // Create the ToolBarState factory. This class is not a singleton, because it
+ // needs a pointer to this object.
+ m_pToolBarStateFactory = new ToolBarStateFactory(this);
+ m_pToolBarState = m_pToolBarStateFactory->getState(WorkToolBar::tbb_Arrow);
+
+}
+
+UMLView::~UMLView() {
+ delete m_pImageExporter;
+
+ if(m_pIDChangesLog) {
+ delete m_pIDChangesLog;
+ m_pIDChangesLog = 0;
+ }
+
+ // before we can delete the QCanvas, all widgets must be explicitly
+ // removed
+ // otherwise the implicit remove of the contained widgets will cause
+ // events which would demand a valid connected QCanvas
+ // ==> this causes umbrello to crash for some - larger?? - projects
+ // first avoid all events, which would cause some update actions
+ // on deletion of each removed widget
+ blockSignals( true );
+ removeAllWidgets();
+
+ delete m_pToolBarStateFactory;
+ m_pToolBarStateFactory = NULL;
+
+ // Qt Doc for QCanvasView::~QCanvasView () states:
+ // "Destroys the canvas view. The associated canvas is not deleted."
+ // we should do it now
+ delete canvas();
+}
+
+QString UMLView::getName() const {
+ return m_Name;
+}
+
+void UMLView::setName(const QString &name) {
+ m_Name = name;
+}
+
+int UMLView::generateCollaborationId() {
+ return ++m_nCollaborationId;
+}
+
+void UMLView::print(KPrinter *pPrinter, QPainter & pPainter) {
+ int height, width;
+ //get the size of the page
+ pPrinter->setFullPage( true );
+ QPaintDeviceMetrics metrics(pPrinter);
+ QFontMetrics fm = pPainter.fontMetrics(); // use the painter font metrics, not the screen fm!
+ int fontHeight = fm.lineSpacing();
+ uint left, right, top, bottom;
+ // fetch printer margins individual for all four page sides, as at least top and bottom are not the same
+ pPrinter->margins ( &top, &left, &bottom, &right );
+ // give a little extra space at each side
+ left += 2;
+ right += 2;
+ top += 2;
+ bottom += 2;
+
+ if(pPrinter->orientation() == KPrinter::Landscape) {
+ // we are printing in LANDSCAPE --> swap marginX and marginY
+ uint right_old = right;
+ // the DiagramRight side is printed at PrintersTop
+ right = top;
+ // the DiagramTop side is printed at PrintersLeft
+ top = left;
+ // the DiagramLeft side is printed at PrintersBottom
+ left = bottom;
+ // the DiagramBottom side is printed at PrintersRight
+ bottom = right_old;
+ }
+
+ // The printer will probably use a different font with different font metrics,
+ // force the widgets to update accordingly on paint
+ forceUpdateWidgetFontMetrics(&pPainter);
+
+ width = metrics.width() - left - right;
+ height = metrics.height() - top - bottom;
+
+ //get the smallest rect holding the diagram
+ QRect rect = getDiagramRect();
+ //now draw to printer
+
+#if 0
+ int offsetX = 0, offsetY = 0, widthX = 0, heightY = 0;
+ // respect the margin
+ pPainter.translate(marginX, marginY);
+
+ // clip away everything outside of the margin
+ pPainter.setClipRect(marginX, marginY,
+ width, metrics.height() - marginY * 2);
+
+ //loop until all of the picture is printed
+ int numPagesX = (int)ceil((double)rect.width()/(double)width);
+ int numPagesY = (int)ceil((double)rect.height()/(double)height);
+ int page = 0;
+
+ // print the canvas to multiple pages
+ for (int pageY = 0; pageY < numPagesY; ++pageY) {
+ // tile vertically
+ offsetY = pageY * height + rect.y();
+ heightY = (pageY + 1) * height > rect.height()
+ ? rect.height() - pageY * height
+ : height;
+ for (int pageX = 0; pageX < numPagesX; ++pageX) {
+ // tile horizontally
+ offsetX = pageX * width + rect.x();
+ widthX = (pageX + 1) * width > rect.width()
+ ? rect.width() - pageX * width
+ : width;
+
+ // make sure the part of the diagram is painted at the correct
+ // place in the printout
+ pPainter.translate(-offsetX,-offsetY);
+ getDiagram(QRect(offsetX, offsetY,widthX, heightY),
+ pPainter);
+ // undo the translation so the coordinates for the painter
+ // correspond to the page again
+ pPainter.translate(offsetX,offsetY);
+
+ //draw foot note
+ QString string = i18n("Diagram: %2 Page %1").arg(page + 1).arg(getName());
+ QColor textColor(50, 50, 50);
+ pPainter.setPen(textColor);
+ pPainter.drawLine(0, height + 2, width, height + 2);
+ pPainter.drawText(0, height + 4, width, fontHeight, Qt::AlignLeft, string);
+
+ if(pageX+1 < numPagesX || pageY+1 < numPagesY) {
+ pPrinter -> newPage();
+ page++;
+ }
+ }
+ }
+#else
+ // be gentle - as described in Qt-Doc "The Coordinate System"
+ pPainter.save();
+
+ int diagramHeight = rect.height();
+ // + 4+fontHeight between diagram and footline as space-buffer
+ // + 2 between line and foot-text
+ // + 1 for foot-line
+ // + fontHeight for foot-text
+ // ==============
+ // (2*fontHeight) + 7
+ int footHeight = (2*fontHeight) + 7;
+ int footTop = rect.y() + diagramHeight + 4+fontHeight;
+ int drawHeight = diagramHeight + footHeight;
+
+ // set window of painter to dimensions of diagram
+ // set window to viewport relation so that x:y isn't changed
+ double dScaleX = (double)rect.width()/ (double)width;
+ double dScaleY = (double)drawHeight/ (double)height;
+ // select the scaling factor so that the larger dimension
+ // fits on the printer page -> use the larger scaling factor
+ // -> the virtual diagram window has some additional space at the
+ // shorter dimension
+ double dScaleUse = ( dScaleX > dScaleY )?dScaleX:dScaleY;
+
+ int windowWidth = (int)ceil(dScaleUse*width);
+ int windowHeight = (int)ceil(dScaleUse*height);
+#ifdef DEBUG_PRINTING
+ kDebug() << "drawHeight: " << drawHeight << ", width: " << rect.width()
+ << "\nPageHeight: " << height << ", PageWidht: " << width
+ << "\nScaleY: " << dScaleY << ", ScaleX: " << dScaleX
+ << "\ndScaleUse: " << dScaleUse
+ << "\nVirtualSize: Width: " << windowWidth << ", Height: " << windowHeight
+ << "\nFoot Top: " << footTop
+ << endl;
+#endif
+ // set virtual drawing area window - where diagram fits 100% in
+ pPainter.setWindow( rect.x(), rect.y(), windowWidth, windowHeight );
+
+ // set viewport - the physical mapping
+ // --> Qt's QPainter will map all drawed elements from diagram area ( window )
+ // to printer area ( viewport )
+ pPainter.setViewport( left, top, width, height );
+
+ // get Diagram
+ getDiagram(QRect(rect.x(), rect.y(), windowWidth, diagramHeight), pPainter);
+
+ //draw foot note
+ QString string = i18n("Diagram: %2 Page %1").arg( 1).arg(getName());
+ QColor textColor(50, 50, 50);
+ pPainter.setPen(textColor);
+ pPainter.drawLine(rect.x(), footTop , windowWidth, footTop);
+ pPainter.drawText(rect.x(), footTop + 3, windowWidth, fontHeight, Qt::AlignLeft, string);
+
+ // now restore scaling
+ pPainter.restore();
+
+#endif
+ // next painting will most probably be to a different device (i.e. the screen)
+ forceUpdateWidgetFontMetrics(0);
+}
+
+void UMLView::setupNewWidget(UMLWidget *w) {
+ w->setX( m_Pos.x() );
+ w->setY( m_Pos.y() );
+ w->setVisible( true );
+ w->setActivated();
+ w->setFont( getFont() );
+ w->slotColorChanged( getID() );
+ w->slotLineWidthChanged( getID() );
+ resizeCanvasToItems();
+ m_WidgetList.append( w );
+ m_pDoc->setModified();
+}
+
+void UMLView::contentsMouseReleaseEvent(QMouseEvent* ome) {
+ m_pToolBarState->mouseRelease(ome);
+}
+
+void UMLView::slotToolBarChanged(int c) {
+ m_pToolBarState->cleanBeforeChange();
+ m_pToolBarState = m_pToolBarStateFactory->getState((WorkToolBar::ToolBar_Buttons)c);
+ m_pToolBarState->init();
+
+ m_bPaste = false;
+}
+
+void UMLView::showEvent(QShowEvent* /*se*/) {
+
+# ifdef MANUAL_CONTROL_DOUBLE_BUFFERING
+ //kWarning() << "Show Event for " << getName() << endl;
+ canvas()->setDoubleBuffering( true );
+ // as the diagram gets now visible again,
+ // the update of the diagram elements shall be
+ // at the normal value of 20
+ canvas()-> setUpdatePeriod( 20 );
+# endif
+
+ UMLApp* theApp = UMLApp::app();
+ WorkToolBar* tb = theApp->getWorkToolBar();
+ connect(tb,SIGNAL(sigButtonChanged(int)), this, SLOT(slotToolBarChanged(int)));
+ connect(this,SIGNAL(sigResetToolBar()), tb, SLOT(slotResetToolBar()));
+ connect(m_pDoc, SIGNAL(sigObjectCreated(UMLObject *)),
+ this, SLOT(slotObjectCreated(UMLObject *)));
+ connect(this, SIGNAL(sigAssociationRemoved(AssociationWidget*)),
+ UMLApp::app()->getDocWindow(), SLOT(slotAssociationRemoved(AssociationWidget*)));
+ connect(this, SIGNAL(sigWidgetRemoved(UMLWidget*)),
+ UMLApp::app()->getDocWindow(), SLOT(slotWidgetRemoved(UMLWidget*)));
+ resetToolbar();
+
+}
+
+void UMLView::hideEvent(QHideEvent* /*he*/) {
+ UMLApp* theApp = UMLApp::app();
+ WorkToolBar* tb = theApp->getWorkToolBar();
+ disconnect(tb,SIGNAL(sigButtonChanged(int)), this, SLOT(slotToolBarChanged(int)));
+ disconnect(this,SIGNAL(sigResetToolBar()), tb, SLOT(slotResetToolBar()));
+ disconnect(m_pDoc, SIGNAL(sigObjectCreated(UMLObject *)), this, SLOT(slotObjectCreated(UMLObject *)));
+ disconnect(this, SIGNAL(sigAssociationRemoved(AssociationWidget*)),
+ UMLApp::app()->getDocWindow(), SLOT(slotAssociationRemoved(AssociationWidget*)));
+ disconnect(this, SIGNAL(sigWidgetRemoved(UMLWidget*)),
+ UMLApp::app()->getDocWindow(), SLOT(slotWidgetRemoved(UMLWidget*)));
+
+# ifdef MANUAL_CONTROL_DOUBLE_BUFFERING
+ //kWarning() << "Hide Event for " << getName() << endl;
+ canvas()->setDoubleBuffering( false );
+ // a periodic update of all - also invisible - diagrams
+ // can cause a very high CPU load if more than 100diagrams
+ // are inside a project - and this without any need
+ // => switch the update off for hidden diagrams
+ canvas()-> setUpdatePeriod( -1 );
+# endif
+}
+
+void UMLView::slotObjectCreated(UMLObject* o) {
+ m_bPaste = false;
+ //check to see if we want the message
+ //may be wanted by someone else e.g. list view
+ if (!m_bCreateObject) {
+ return;
+ }
+
+ UMLWidget* newWidget = Widget_Factory::createWidget(this, o);
+ if (newWidget == NULL)
+ return;
+ newWidget->setVisible( true );
+ newWidget->setActivated();
+ newWidget->setFont( getFont() );
+ newWidget->slotColorChanged( getID() );
+ newWidget->slotLineWidthChanged( getID() );
+ newWidget->updateComponentSize();
+ if (m_Type == Uml::dt_Sequence) {
+ // Set proper position on the sequence line widget which is
+ // attached to the object widget.
+ ObjectWidget *ow = dynamic_cast<ObjectWidget*>(newWidget);
+ if (ow)
+ ow->moveEvent(NULL);
+ }
+ m_bCreateObject = false;
+ m_WidgetList.append(newWidget);
+ switch (o->getBaseType()) {
+ case ot_Actor:
+ case ot_UseCase:
+ case ot_Class:
+ case ot_Package:
+ case ot_Component:
+ case ot_Node:
+ case ot_Artifact:
+ case ot_Interface:
+ case ot_Enum:
+ case ot_Entity:
+ case ot_Datatype:
+ createAutoAssociations(newWidget);
+ // We need to invoke createAutoAttributeAssociations()
+ // on all other widgets again because the newly created
+ // widget might saturate some latent attribute assocs.
+ for (UMLWidgetListIt it(m_WidgetList); it.current(); ++it) {
+ UMLWidget *w = it.current();
+ if (w != newWidget)
+ createAutoAttributeAssociations(w);
+ }
+ break;
+ default:
+ break;
+ }
+ resizeCanvasToItems();
+}
+
+void UMLView::slotObjectRemoved(UMLObject * o) {
+ m_bPaste = false;
+ Uml::IDType id = o->getID();
+ UMLWidgetListIt it( m_WidgetList );
+ UMLWidget *obj;
+
+ while ((obj = it.current()) != 0 ) {
+ ++it;
+ if(obj -> getID() != id)
+ continue;
+ removeWidget(obj);
+ }
+}
+
+void UMLView::contentsDragEnterEvent(QDragEnterEvent *e) {
+ UMLDrag::LvTypeAndID_List tidList;
+ if(!UMLDrag::getClip3TypeAndID(e, tidList)) {
+ return;
+ }
+ UMLDrag::LvTypeAndID_It tidIt(tidList);
+ UMLDrag::LvTypeAndID * tid = tidIt.current();
+ if (!tid) {
+ kDebug() << "UMLView::contentsDragEnterEvent: "
+ << "UMLDrag::getClip3TypeAndID returned empty list" << endl;
+ return;
+ }
+ ListView_Type lvtype = tid->type;
+ Uml::IDType id = tid->id;
+
+ Diagram_Type diagramType = getType();
+
+ UMLObject* temp = 0;
+ //if dragging diagram - might be a drag-to-note
+ if (Model_Utils::typeIsDiagram(lvtype)) {
+ e->accept(true);
+ return;
+ }
+ //can't drag anything onto state/activity diagrams
+ if( diagramType == dt_State || diagramType == dt_Activity) {
+ e->accept(false);
+ return;
+ }
+ //make sure can find UMLObject
+ if( !(temp = m_pDoc->findObjectById(id) ) ) {
+ kDebug() << "object " << ID2STR(id) << " not found" << endl;
+ e->accept(false);
+ return;
+ }
+ //make sure dragging item onto correct diagram
+ // concept - class,seq,coll diagram
+ // actor,usecase - usecase diagram
+ Object_Type ot = temp->getBaseType();
+ bool bAccept = true;
+ switch (diagramType) {
+ case dt_UseCase:
+ if ((widgetOnDiagram(id) && ot == ot_Actor) ||
+ (ot != ot_Actor && ot != ot_UseCase))
+ bAccept = false;
+ break;
+ case dt_Class:
+ if (widgetOnDiagram(id) ||
+ (ot != ot_Class &&
+ ot != ot_Package &&
+ ot != ot_Interface &&
+ ot != ot_Enum &&
+ ot != ot_Datatype)) {
+ bAccept = false;
+ }
+ break;
+ case dt_Sequence:
+ case dt_Collaboration:
+ if (ot != ot_Class &&
+ ot != ot_Interface &&
+ ot != ot_Actor)
+ bAccept = false;
+ break;
+ case dt_Deployment:
+ if (widgetOnDiagram(id))
+ bAccept = false;
+ else if (ot != ot_Interface &&
+ ot != ot_Package &&
+ ot != ot_Component &&
+ ot != ot_Class &&
+ ot != ot_Node)
+ bAccept = false;
+ else if (ot == ot_Package &&
+ temp->getStereotype() != "subsystem")
+ bAccept = false;
+ break;
+ case dt_Component:
+ if (widgetOnDiagram(id) ||
+ (ot != ot_Interface &&
+ ot != ot_Package &&
+ ot != ot_Component &&
+ ot != ot_Artifact &&
+ ot != ot_Class))
+ bAccept = false;
+ if (ot == ot_Class && !temp->getAbstract())
+ bAccept = false;
+ break;
+ case dt_EntityRelationship:
+ if (ot != ot_Entity)
+ bAccept = false;
+ break;
+ default:
+ break;
+ }
+ e->accept(bAccept);
+}
+
+void UMLView::contentsDropEvent(QDropEvent *e) {
+ UMLDrag::LvTypeAndID_List tidList;
+ if( !UMLDrag::getClip3TypeAndID(e, tidList) ) {
+ return;
+ }
+ UMLDrag::LvTypeAndID_It tidIt(tidList);
+ UMLDrag::LvTypeAndID * tid = tidIt.current();
+ if (!tid) {
+ kDebug() << "UMLView::contentsDropEvent: "
+ << "UMLDrag::getClip3TypeAndID returned empty list" << endl;
+ return;
+ }
+ ListView_Type lvtype = tid->type;
+ Uml::IDType id = tid->id;
+
+ if (Model_Utils::typeIsDiagram(lvtype)) {
+ UMLWidget *w = NULL;
+ for (w = m_WidgetList.first(); w; w = m_WidgetList.next()) {
+ if (w->getBaseType() == Uml::wt_Note && w->onWidget(e->pos()))
+ break;
+ }
+ if (w) {
+ NoteWidget *note = static_cast<NoteWidget*>(w);
+ note->setDiagramLink(id);
+ }
+ return;
+ }
+ UMLObject* o = m_pDoc->findObjectById(id);
+ if( !o ) {
+ kDebug() << "UMLView::contentsDropEvent: object id=" << ID2STR(id)
+ << " not found" << endl;
+ return;
+ }
+ m_bCreateObject = true;
+ m_Pos = (e->pos() * 100 ) / m_nZoom;
+
+ slotObjectCreated(o);
+
+ m_pDoc -> setModified(true);
+}
+
+ObjectWidget * UMLView::onWidgetLine( const QPoint &point ) {
+ UMLWidget *obj;
+ for (UMLWidgetListIt it(m_WidgetList); (obj = it.current()) != NULL; ++it) {
+ ObjectWidget *ow = dynamic_cast<ObjectWidget*>(obj);
+ if (ow == NULL)
+ continue;
+ SeqLineWidget *pLine = ow->getSeqLine();
+ if (pLine == NULL) {
+ kError() << "UMLView::onWidgetLine: SeqLineWidget of " << ow->getName()
+ << " (id=" << ID2STR(ow->getLocalID()) << ") is NULL" << endl;
+ continue;
+ }
+ if (pLine->onWidget(point))
+ return ow;
+ }
+ return 0;
+}
+
+UMLWidget *UMLView::getWidgetAt(const QPoint& p) {
+ int relativeSize = 10000; // start with an arbitrary large number
+ UMLWidget *obj, *retObj = NULL;
+ UMLWidgetListIt it(m_WidgetList);
+ for (UMLWidgetListIt it(m_WidgetList); (obj = it.current()) != NULL; ++it) {
+ const int s = obj->onWidget(p);
+ if (!s)
+ continue;
+ if (s < relativeSize) {
+ relativeSize = s;
+ retObj = obj;
+ }
+ }
+ return retObj;
+}
+
+void UMLView::checkMessages(ObjectWidget * w) {
+ if(getType() != dt_Sequence)
+ return;
+
+ MessageWidgetListIt it( m_MessageList );
+ MessageWidget *obj;
+ while ( (obj = it.current()) != 0 ) {
+ ++it;
+ if(! obj -> contains(w))
+ continue;
+ //make sure message doesn't have any associations
+ removeAssociations(obj);
+ obj -> cleanup();
+ //make sure not in selected list
+ m_SelectedList.remove(obj);
+ m_MessageList.remove(obj);
+ delete obj;
+ }
+}
+
+bool UMLView::widgetOnDiagram(Uml::IDType id) {
+ UMLWidget *obj;
+
+ UMLWidgetListIt it( m_WidgetList );
+ while ( (obj = it.current()) != 0 ) {
+ ++it;
+ if(id == obj -> getID())
+ return true;
+ }
+
+ MessageWidgetListIt mit( m_MessageList );
+ while ( (obj = (UMLWidget*)mit.current()) != 0 ) {
+ ++mit;
+ if(id == obj -> getID())
+ return true;
+ }
+
+ return false;
+}
+
+void UMLView::contentsMouseMoveEvent(QMouseEvent* ome) {
+ m_pToolBarState->mouseMove(ome);
+}
+
+// search both our UMLWidget AND MessageWidget lists
+UMLWidget * UMLView::findWidget( Uml::IDType id ) {
+
+ UMLWidgetListIt it( m_WidgetList );
+ UMLWidget * obj = NULL;
+ while ( (obj = it.current()) != 0 ) {
+ ++it;
+ // object widgets are special..the widget id is held by 'localId' attribute (crappy!)
+ if( obj -> getBaseType() == wt_Object ) {
+ if( static_cast<ObjectWidget *>( obj ) -> getLocalID() == id )
+ return obj;
+ } else if( obj -> getID() == id ) {
+ return obj;
+ }
+ }
+
+ MessageWidgetListIt mit( m_MessageList );
+ while ( (obj = (UMLWidget*)mit.current()) != 0 ) {
+ ++mit;
+ if( obj -> getID() == id )
+ return obj;
+ }
+
+ return 0;
+}
+
+
+
+AssociationWidget * UMLView::findAssocWidget( Uml::IDType id ) {
+ AssociationWidget *obj;
+ AssociationWidgetListIt it( m_AssociationList );
+ while ( (obj = it.current()) != 0 ) {
+ ++it;
+ UMLAssociation* umlassoc = obj -> getAssociation();
+ if ( umlassoc && umlassoc->getID() == id ) {
+ return obj;
+ }
+ }
+ return 0;
+}
+
+AssociationWidget * UMLView::findAssocWidget(UMLWidget *pWidgetA,
+ UMLWidget *pWidgetB, const QString& roleNameB) {
+ AssociationWidget *assoc;
+ AssociationWidgetListIt it(m_AssociationList);
+ while ((assoc = it.current()) != 0) {
+ ++it;
+ const Association_Type testType = assoc->getAssocType();
+ if (testType != Uml::at_Association &&
+ testType != Uml::at_UniAssociation &&
+ testType != Uml::at_Composition &&
+ testType != Uml::at_Aggregation)
+ continue;
+ if (pWidgetA->getID() == assoc->getWidgetID(A) &&
+ pWidgetB->getID() == assoc->getWidgetID(B) &&
+ assoc->getRoleName(Uml::B) == roleNameB)
+ return assoc;
+ }
+ return 0;
+}
+
+
+AssociationWidget * UMLView::findAssocWidget(Uml::Association_Type at,
+ UMLWidget *pWidgetA, UMLWidget *pWidgetB) {
+ AssociationWidget *assoc;
+ AssociationWidgetListIt it(m_AssociationList);
+ while ((assoc = it.current()) != 0) {
+ ++it;
+ Association_Type testType = assoc->getAssocType();
+ if (testType != at)
+ continue;
+ if (pWidgetA->getID() == assoc->getWidgetID(A) &&
+ pWidgetB->getID() == assoc->getWidgetID(B))
+ return assoc;
+ }
+ return 0;
+}
+
+void UMLView::removeWidget(UMLWidget * o) {
+ if(!o)
+ return;
+
+ emit sigWidgetRemoved(o);
+
+ removeAssociations(o);
+
+ Widget_Type t = o->getBaseType();
+ if(getType() == dt_Sequence && t == wt_Object)
+ checkMessages( static_cast<ObjectWidget*>(o) );
+
+ o -> cleanup();
+ m_SelectedList.remove(o);
+ disconnect( this, SIGNAL( sigRemovePopupMenu() ), o, SLOT( slotRemovePopupMenu() ) );
+ disconnect( this, SIGNAL( sigClearAllSelected() ), o, SLOT( slotClearAllSelected() ) );
+ disconnect( this, SIGNAL(sigColorChanged(Uml::IDType)), o, SLOT(slotColorChanged(Uml::IDType)));
+ if (t == wt_Message)
+ m_MessageList.remove(static_cast<MessageWidget*>(o));
+ else
+ m_WidgetList.remove(o);
+ m_pDoc->setModified();
+ delete o;
+}
+
+bool UMLView::getUseFillColor() const {
+ return m_Options.uiState.useFillColor;
+}
+
+void UMLView::setUseFillColor(bool ufc) {
+ m_Options.uiState.useFillColor = ufc;
+}
+
+QColor UMLView::getFillColor() const {
+ return m_Options.uiState.fillColor;
+}
+
+void UMLView::setFillColor(const QColor &color) {
+ m_Options.uiState.fillColor = color;
+ emit sigColorChanged( getID() );
+ canvas()->setAllChanged();
+}
+
+QColor UMLView::getLineColor() const {
+ return m_Options.uiState.lineColor;
+}
+
+void UMLView::setLineColor(const QColor &color) {
+ m_Options.uiState.lineColor = color;
+ emit sigColorChanged( getID() );
+ canvas() -> setAllChanged();
+}
+
+uint UMLView::getLineWidth() const {
+ return m_Options.uiState.lineWidth;
+}
+
+void UMLView::setLineWidth(uint width) {
+ m_Options.uiState.lineWidth = width;
+ emit sigLineWidthChanged( getID() );
+ canvas() -> setAllChanged();
+}
+
+void UMLView::contentsMouseDoubleClickEvent(QMouseEvent* ome) {
+ m_pToolBarState->mouseDoubleClick(ome);
+}
+
+QRect UMLView::getDiagramRect() {
+ int startx, starty, endx, endy;
+ startx = starty = INT_MAX;
+ endx = endy = 0;
+ UMLWidgetListIt it( m_WidgetList );
+ UMLWidget *obj;
+ while ( (obj = it.current()) != 0 ) {
+ ++it;
+ if (! obj->isVisible())
+ continue;
+ int objEndX = obj -> getX() + obj -> getWidth();
+ int objEndY = obj -> getY() + obj -> getHeight();
+ int objStartX = obj -> getX();
+ int objStartY = obj -> getY();
+ if (startx >= objStartX)
+ startx = objStartX;
+ if (starty >= objStartY)
+ starty = objStartY;
+ if(endx <= objEndX)
+ endx = objEndX;
+ if(endy <= objEndY)
+ endy = objEndY;
+ }
+ //if seq. diagram, make sure print all of the lines
+ if (getType() == dt_Sequence ) {
+ for (UMLWidgetListIt it(m_WidgetList); (obj = it.current()) != NULL; ++it) {
+ ObjectWidget *ow = dynamic_cast<ObjectWidget*>(obj);
+ if (ow == NULL)
+ continue;
+ int y = ow->getEndLineY();
+ if (endy < y)
+ endy = y;
+ }
+ }
+
+ /* now we need another look at the associations, because they are no
+ * UMLWidgets */
+ AssociationWidgetListIt assoc_it (m_AssociationList);
+ AssociationWidget * assoc_obj;
+ QRect rect;
+
+ while ((assoc_obj = assoc_it.current()) != 0)
+ {
+ /* get the rectangle around all segments of the assoc */
+ rect = assoc_obj->getAssocLineRectangle();
+
+ if (startx >= rect.x())
+ startx = rect.x();
+ if (starty >= rect.y())
+ starty = rect.y();
+ if (endx <= rect.x() + rect.width())
+ endx = rect.x() + rect.width();
+ if (endy <= rect.y() + rect.height())
+ endy = rect.y() + rect.height();
+ ++assoc_it; // next assoc
+ }
+
+ /* Margin causes problems of black border around the edge
+ // Margin:
+ startx -= 24;
+ starty -= 20;
+ endx += 24;
+ endy += 20;
+ */
+
+ return QRect(startx, starty, endx - startx, endy - starty);
+}
+
+void UMLView::setSelected(UMLWidget * w, QMouseEvent * /*me*/) {
+ //only add if wasn't in list
+ if(!m_SelectedList.remove(w))
+ m_SelectedList.append(w);
+ int count = m_SelectedList.count();
+ //only call once - if we select more, no need to keep clearing window
+
+ // if count == 1, widget will update the doc window with their data when selected
+ if( count == 2 )
+ updateDocumentation( true );//clear doc window
+
+ /* selection changed, we have to make sure the copy and paste items
+ * are correctly enabled/disabled */
+ UMLApp::app()->slotCopyChanged();
+}
+
+void UMLView::clearSelected() {
+ m_SelectedList.clear();
+ emit sigClearAllSelected();
+ //m_pDoc -> enableCutCopy(false);
+}
+
+//TODO Only used in MLApp::handleCursorKeyReleaseEvent
+void UMLView::moveSelectedBy(int dX, int dY) {
+ for (UMLWidget *w = m_SelectedList.first(); w; w = m_SelectedList.next())
+ w->moveBy(dX, dY);
+}
+
+void UMLView::selectionUseFillColor(bool useFC) {
+ UMLWidget * temp = 0;
+ for(temp=(UMLWidget *)m_SelectedList.first();temp;temp=(UMLWidget *)m_SelectedList.next())
+ temp -> setUseFillColour(useFC);
+}
+
+void UMLView::selectionSetFont( const QFont &font )
+{
+ UMLWidget * temp = 0;
+ for(temp=(UMLWidget *)m_SelectedList.first();temp;temp=(UMLWidget *)m_SelectedList.next())
+ temp -> setFont( font );
+}
+
+void UMLView::selectionSetLineColor( const QColor &color )
+{
+ UMLWidget * temp = 0;
+ for (temp = m_SelectedList.first(); temp; temp = m_SelectedList.next()) {
+ temp->setLineColor(color);
+ temp->setUsesDiagramLineColour(false);
+ }
+ AssociationWidgetList assoclist = getSelectedAssocs();
+ for (AssociationWidget *aw = assoclist.first(); aw; aw = assoclist.next()) {
+ aw->setLineColor(color);
+ aw->setUsesDiagramLineColour(false);
+ }
+}
+
+void UMLView::selectionSetLineWidth( uint width )
+{
+ UMLWidget * temp = 0;
+ for (temp = m_SelectedList.first(); temp; temp = m_SelectedList.next()) {
+ temp->setLineWidth(width);
+ temp->setUsesDiagramLineWidth(false);
+ }
+ AssociationWidgetList assoclist = getSelectedAssocs();
+ for (AssociationWidget *aw = assoclist.first(); aw; aw = assoclist.next()) {
+ aw->setLineWidth(width);
+ aw->setUsesDiagramLineWidth(false);
+ }
+}
+
+void UMLView::selectionSetFillColor( const QColor &color )
+{
+ UMLWidget * temp = 0;
+ for(temp=(UMLWidget *) m_SelectedList.first();
+ temp;
+ temp=(UMLWidget *)m_SelectedList.next()) {
+ temp -> setFillColour( color );
+ temp -> setUsesDiagramFillColour(false);
+ }
+}
+
+void UMLView::selectionToggleShow(int sel)
+{
+ // loop through all selected items
+ for(UMLWidget *temp = (UMLWidget *)m_SelectedList.first();
+ temp; temp=(UMLWidget *)m_SelectedList.next()) {
+ Widget_Type type = temp->getBaseType();
+ ClassifierWidget *cw = dynamic_cast<ClassifierWidget*>(temp);
+
+ // toggle the show setting sel
+ switch (sel)
+ {
+ // some setting are only available for class, some for interface and some
+ // for both
+ case ListPopupMenu::mt_Show_Attributes_Selection:
+ if (type == wt_Class)
+ cw -> toggleShowAtts();
+ break;
+ case ListPopupMenu::mt_Show_Operations_Selection:
+ if (cw)
+ cw -> toggleShowOps();
+ break;
+ case ListPopupMenu::mt_Visibility_Selection:
+ if (cw)
+ cw -> toggleShowVisibility();
+ break;
+ case ListPopupMenu::mt_DrawAsCircle_Selection:
+ if (type == wt_Interface)
+ cw -> toggleDrawAsCircle();
+ break;
+ case ListPopupMenu::mt_Show_Operation_Signature_Selection:
+ if (cw)
+ cw -> toggleShowOpSigs();
+ break;
+ case ListPopupMenu::mt_Show_Attribute_Signature_Selection:
+ if (type == wt_Class)
+ cw -> toggleShowAttSigs();
+ break;
+ case ListPopupMenu::mt_Show_Packages_Selection:
+ if (cw)
+ cw -> toggleShowPackage();
+ break;
+ case ListPopupMenu::mt_Show_Stereotypes_Selection:
+ if (type == wt_Class)
+ cw -> toggleShowStereotype();
+ break;
+ case ListPopupMenu::mt_Show_Public_Only_Selection:
+ if (cw)
+ cw -> toggleShowPublicOnly();
+ break;
+ default:
+ break;
+ } // switch (sel)
+ }
+}
+
+void UMLView::deleteSelection()
+{
+ /*
+ Don't delete text widget that are connect to associations as these will
+ be cleaned up by the associations.
+ */
+ UMLWidget * temp = 0;
+ for(temp=(UMLWidget *) m_SelectedList.first();
+ temp;
+ temp=(UMLWidget *)m_SelectedList.next())
+ {
+ if( temp -> getBaseType() == wt_Text &&
+ ((FloatingTextWidget *)temp) -> getRole() != tr_Floating )
+ {
+ m_SelectedList.remove(); // remove advances the iterator to the next position,
+ m_SelectedList.prev(); // let's allow for statement do the advancing
+ temp -> hide();
+ } else {
+ removeWidget(temp);
+ }
+ }
+
+ // Delete any selected associations.
+ AssociationWidgetListIt assoc_it( m_AssociationList );
+ AssociationWidget* assocwidget = 0;
+ while((assocwidget=assoc_it.current())) {
+ ++assoc_it;
+ if( assocwidget-> getSelected() )
+ removeAssoc(assocwidget);
+ // MARK
+ }
+
+ /* we also have to remove selected messages from sequence diagrams */
+ MessageWidget * cur_msgWgt;
+
+ /* loop through all messages and check the selection state */
+ for (cur_msgWgt = m_MessageList.first(); cur_msgWgt;
+ cur_msgWgt = m_MessageList.next())
+ {
+ if (cur_msgWgt->getSelected() == true)
+ {
+ removeWidget(cur_msgWgt); // Remove message - it is selected.
+ }
+ }
+
+ // sometimes we miss one widget, so call this function again to remove it as
+ // well
+ if (m_SelectedList.count() != 0)
+ deleteSelection();
+
+ //make sure list empty - it should be anyway, just a check.
+ m_SelectedList.clear();
+}
+
+void UMLView::selectAll()
+{
+ selectWidgets(0, 0, canvas()->width(), canvas()->height());
+}
+
+Uml::IDType UMLView::getLocalID() {
+ m_nLocalID = UniqueID::gen();
+ return m_nLocalID;
+}
+
+bool UMLView::isSavedInSeparateFile() {
+ if (getOptionState().generalState.tabdiagrams) {
+ // Umbrello currently does not support external folders
+ // when tabbed diagrams are enabled.
+ return false;
+ }
+ const QString msgPrefix("UMLView::isSavedInSeparateFile(" + getName() + "): ");
+ UMLListView *listView = UMLApp::app()->getListView();
+ UMLListViewItem *lvItem = listView->findItem(m_nID);
+ if (lvItem == NULL) {
+ kError() << msgPrefix
+ << "listView->findUMLObject(this) returns false" << endl;
+ return false;
+ }
+ UMLListViewItem *parentItem = dynamic_cast<UMLListViewItem*>( lvItem->parent() );
+ if (parentItem == NULL) {
+ kError() << msgPrefix
+ << "parent item in listview is not a UMLListViewItem (?)" << endl;
+ return false;
+ }
+ const Uml::ListView_Type lvt = parentItem->getType();
+ if (! Model_Utils::typeIsFolder(lvt))
+ return false;
+ UMLFolder *modelFolder = dynamic_cast<UMLFolder*>(parentItem->getUMLObject());
+ if (modelFolder == NULL) {
+ kError() << msgPrefix
+ << "parent model object is not a UMLFolder (?)" << endl;
+ return false;
+ }
+ QString folderFile = modelFolder->getFolderFile();
+ return !folderFile.isEmpty();
+}
+
+void UMLView::contentsMousePressEvent(QMouseEvent* ome) {
+ m_pToolBarState->mousePress(ome);
+ //TODO should be managed by widgets when are selected. Right now also has some
+ //problems, such as clicking on a widget, and clicking to move that widget shows
+ //documentation of the diagram instead of keeping the widget documentation.
+ //When should diagram documentation be shown? When clicking on an empty
+ //space in the diagram with arrow tool?
+ if (!m_bChildDisplayedDoc) {
+ UMLApp::app() -> getDocWindow() -> showDocumentation( this, true );
+ }
+ m_bChildDisplayedDoc = false;
+}
+
+void UMLView::makeSelected (UMLWidget * uw) {
+ if (uw == NULL)
+ return;
+ uw -> setSelected(true);
+ m_SelectedList.remove(uw); // make sure not in there
+ m_SelectedList.append(uw);
+}
+
+void UMLView::selectWidgetsOfAssoc (AssociationWidget * a) {
+ if (!a)
+ return;
+ a -> setSelected(true);
+ //select the two widgets
+ makeSelected( a->getWidget(A) );
+ makeSelected( a->getWidget(B) );
+ //select all the text
+ makeSelected( a->getMultiWidget(A) );
+ makeSelected( a->getMultiWidget(B) );
+ makeSelected( a->getRoleWidget(A) );
+ makeSelected( a->getRoleWidget(B) );
+ makeSelected( a->getChangeWidget(A) );
+ makeSelected( a->getChangeWidget(B) );
+}
+
+void UMLView::selectWidgets(int px, int py, int qx, int qy) {
+ clearSelected();
+
+ QRect rect;
+ if(px <= qx) {
+ rect.setLeft(px);
+ rect.setRight(qx);
+ } else {
+ rect.setLeft(qx);
+ rect.setRight(px);
+ }
+ if(py <= qy) {
+ rect.setTop(py);
+ rect.setBottom(qy);
+ } else {
+ rect.setTop(qy);
+ rect.setBottom(py);
+ }
+ UMLWidgetListIt it(m_WidgetList);
+ UMLWidget * temp = NULL;
+ while ( (temp = it.current()) != 0 ) {
+ int x = temp -> getX();
+ int y = temp -> getY();
+ int w = temp -> getWidth();
+ int h = temp -> getHeight();
+ QRect rect2(x, y, w, h);
+ ++it;
+ //see if any part of widget is in the rectangle
+ if( !rect.intersects(rect2) )
+ continue;
+ //if it is text that is part of an association then select the association
+ //and the objects that are connected to it.
+ if (temp -> getBaseType() == wt_Text) {
+ FloatingTextWidget *ft = static_cast<FloatingTextWidget*>(temp);
+ Text_Role t = ft -> getRole();
+ LinkWidget *lw = ft->getLink();
+ MessageWidget * mw = dynamic_cast<MessageWidget*>(lw);
+ if (mw) {
+ makeSelected( mw );
+ makeSelected( mw->getWidget(A) );
+ makeSelected( mw->getWidget(B) );
+ } else if (t != tr_Floating) {
+ AssociationWidget * a = dynamic_cast<AssociationWidget*>(lw);
+ if (a)
+ selectWidgetsOfAssoc( a );
+ }
+ } else if(temp -> getBaseType() == wt_Message) {
+ MessageWidget *mw = static_cast<MessageWidget*>(temp);
+ makeSelected( mw -> getWidget(A) );
+ makeSelected( mw -> getWidget(B) );
+ }
+ if(temp -> isVisible()) {
+ makeSelected( temp );
+ }
+ }
+ selectAssociations( true );
+
+ //now do the same for the messagewidgets
+ MessageWidgetListIt itw( m_MessageList );
+ MessageWidget *w = 0;
+ while ( (w = itw.current()) != 0 ) {
+ ++itw;
+ if ( w -> getWidget(A) -> getSelected() &&
+ w -> getWidget(B) -> getSelected() ) {
+ makeSelected( w );
+ }//end if
+ }//end while
+}
+
+void UMLView::getDiagram(const QRect &rect, QPixmap & diagram) {
+ QPixmap pixmap(rect.x() + rect.width(), rect.y() + rect.height());
+ QPainter painter(&pixmap);
+ getDiagram(canvas()->rect(),painter);
+ bitBlt(&diagram, QPoint(0, 0), &pixmap, rect);
+}
+
+void UMLView::getDiagram(const QRect &area, QPainter & painter) {
+ //TODO unselecting and selecting later doesn't work now as the selection is
+ //cleared in UMLViewImageExporter. Check if the anything else than the
+ //following is needed and, if it works, remove the clearSelected in
+ //UMLViewImageExporter and UMLViewImageExporterModel
+ UMLWidget* widget = 0;
+ for (widget=(UMLWidget*)m_SelectedList.first(); widget; widget=(UMLWidget*)m_SelectedList.next()) {
+ widget->setSelected(false);
+ }
+ AssociationWidgetList selectedAssociationsList = getSelectedAssocs();
+ AssociationWidget* association = 0;
+ for (association=selectedAssociationsList.first(); association;
+ association=selectedAssociationsList.next()) {
+ association->setSelected(false);
+ }
+
+ // we don't want to get the grid
+ bool showSnapGrid = getShowSnapGrid();
+ setShowSnapGrid(false);
+
+ canvas()->drawArea(area, &painter);
+
+ setShowSnapGrid(showSnapGrid);
+
+ canvas()->setAllChanged();
+ //select again
+ for (widget=(UMLWidget *)m_SelectedList.first(); widget; widget=(UMLWidget *)m_SelectedList.next()) {
+ widget->setSelected( true );
+ }
+ for (association=selectedAssociationsList.first(); association;
+ association=selectedAssociationsList.next()) {
+ association->setSelected(true);
+ }
+
+ return;
+}
+
+UMLViewImageExporter* UMLView::getImageExporter() {
+ return m_pImageExporter;
+}
+
+void UMLView::slotActivate() {
+ m_pDoc->changeCurrentView(getID());
+}
+
+UMLObjectList UMLView::getUMLObjects() {
+ UMLObjectList list;
+ for (UMLWidgetListIt it(m_WidgetList); it.current(); ++it) {
+ UMLWidget *w = it.current();
+ switch (w->getBaseType()) //use switch for easy future expansion
+ {
+ case wt_Actor:
+ case wt_Class:
+ case wt_Interface:
+ case wt_Package:
+ case wt_Component:
+ case wt_Node:
+ case wt_Artifact:
+ case wt_UseCase:
+ case wt_Object:
+ list.append( w->getUMLObject() );
+ break;
+ default:
+ break;
+ }
+ }
+ return list;
+}
+
+void UMLView::activate() {
+ UMLWidgetListIt it( m_WidgetList );
+ UMLWidget *obj;
+
+ //Activate Regular widgets then activate messages
+ while ( (obj = it.current()) != 0 ) {
+ ++it;
+ //If this UMLWidget is already activated or is a MessageWidget then skip it
+ if(obj->isActivated() || obj->getBaseType() == wt_Message)
+ continue;
+
+ if (obj->activate()) {
+ obj->setVisible(true);
+ } else {
+ m_WidgetList.remove(obj);
+ delete obj;
+ }
+ }//end while
+
+ MessageWidgetListIt it2( m_MessageList );
+ //Activate Message widgets
+ while ( (obj = (UMLWidget*)it2.current()) != 0 ) {
+ ++it2;
+ //If this MessageWidget is already activated then skip it
+ if(obj->isActivated())
+ continue;
+
+ obj->activate(m_pDoc->getChangeLog());
+ obj->setVisible( true );
+
+ }//end while
+
+ // Activate all association widgets
+ AssociationWidget *aw;
+ for (AssociationWidgetListIt ait(m_AssociationList);
+ (aw = ait.current()); ++ait) {
+ if (aw->activate()) {
+ if (m_PastePoint.x() != 0) {
+ int x = m_PastePoint.x() - m_Pos.x();
+ int y = m_PastePoint.y() - m_Pos.y();
+ aw->moveEntireAssoc(x, y);
+ }
+ } else {
+ m_AssociationList.remove(aw);
+ }
+ }
+}
+
+int UMLView::getSelectCount(bool filterText) const {
+ if (!filterText)
+ return m_SelectedList.count();
+ int counter = 0;
+ const UMLWidget * temp = 0;
+ for (UMLWidgetListIt iter(m_SelectedList); (temp = iter.current()) != 0; ++iter) {
+ if (temp->getBaseType() == wt_Text) {
+ const FloatingTextWidget *ft = static_cast<const FloatingTextWidget*>(temp);
+ if (ft->getRole() == tr_Floating)
+ counter++;
+ } else {
+ counter++;
+ }
+ }
+ return counter;
+}
+
+
+bool UMLView::getSelectedWidgets(UMLWidgetList &WidgetList, bool filterText /*= true*/) {
+ const UMLWidget * temp = 0;
+ for (UMLWidgetListIt it(m_SelectedList); (temp = it.current()) != NULL; ++it) {
+ if (filterText && temp->getBaseType() == wt_Text) {
+ const FloatingTextWidget *ft = static_cast<const FloatingTextWidget*>(temp);
+ if (ft->getRole() == tr_Floating)
+ WidgetList.append(temp);
+ } else {
+ WidgetList.append(temp);
+ }
+ }//end for
+ return true;
+}
+
+AssociationWidgetList UMLView::getSelectedAssocs() {
+ AssociationWidgetList assocWidgetList;
+ AssociationWidgetListIt assoc_it( m_AssociationList );
+ AssociationWidget* assocwidget = 0;
+ while((assocwidget=assoc_it.current())) {
+ ++assoc_it;
+ if( assocwidget -> getSelected() )
+ assocWidgetList.append(assocwidget);
+ }
+ return assocWidgetList;
+}
+
+bool UMLView::addWidget( UMLWidget * pWidget , bool isPasteOperation ) {
+ if( !pWidget ) {
+ return false;
+ }
+ Widget_Type type = pWidget->getBaseType();
+ if (isPasteOperation) {
+ if (type == Uml::wt_Message)
+ m_MessageList.append(static_cast<MessageWidget*>(pWidget));
+ else
+ m_WidgetList.append(pWidget);
+ return true;
+ }
+ if (!isPasteOperation && findWidget(pWidget->getID())) {
+ kError() << "UMLView::addWidget: Not adding "
+ << "(id=" << ID2STR(pWidget->getID())
+ << "/type=" << type << "/name=" << pWidget->getName()
+ << ") because it's already there" << endl;
+ return false;
+ }
+ //kDebug() << "UMLView::addWidget called for basetype " << type << endl;
+ IDChangeLog * log = m_pDoc -> getChangeLog();
+ if( isPasteOperation && (!log || !m_pIDChangesLog)) {
+ kError()<<" Cant addWidget to view in paste op because a log is not open"<<endl;
+ return false;
+ }
+ int wX = pWidget -> getX();
+ int wY = pWidget -> getY();
+ bool xIsOutOfRange = (wX <= 0 || wX >= FloatingTextWidget::restrictPositionMax);
+ bool yIsOutOfRange = (wY <= 0 || wY >= FloatingTextWidget::restrictPositionMax);
+ if (xIsOutOfRange || yIsOutOfRange) {
+ QString name = pWidget->getName();
+ if (name.isEmpty()) {
+ FloatingTextWidget *ft = dynamic_cast<FloatingTextWidget*>(pWidget);
+ if (ft)
+ name = ft->getDisplayText();
+ }
+ kDebug() << "UMLView::addWidget (" << name << " type="
+ << pWidget->getBaseType() << "): position (" << wX << ","
+ << wY << ") is out of range" << endl;
+ if (xIsOutOfRange) {
+ pWidget->setX(0);
+ wX = 0;
+ }
+ if (yIsOutOfRange) {
+ pWidget->setY(0);
+ wY = 0;
+ }
+ }
+ if( wX < m_Pos.x() )
+ m_Pos.setX( wX );
+ if( wY < m_Pos.y() )
+ m_Pos.setY( wY );
+
+ //see if we need a new id to match object
+ switch( type ) {
+
+ case wt_Class:
+ case wt_Package:
+ case wt_Component:
+ case wt_Node:
+ case wt_Artifact:
+ case wt_Interface:
+ case wt_Enum:
+ case wt_Entity:
+ case wt_Datatype:
+ case wt_Actor:
+ case wt_UseCase:
+ {
+ Uml::IDType id = pWidget -> getID();
+ Uml::IDType newID = log->findNewID( id );
+ if( newID == Uml::id_None ) { // happens after a cut
+ if (id == Uml::id_None)
+ return false;
+ newID = id; //don't stop paste
+ } else
+ pWidget -> setID( newID );
+ UMLObject * pObject = m_pDoc -> findObjectById( newID );
+ if( !pObject ) {
+ kDebug() << "addWidget: Can't find UMLObject for id "
+ << ID2STR(newID) << endl;
+ return false;
+ }
+ pWidget -> setUMLObject( pObject );
+ //make sure it doesn't already exist.
+ if (findWidget(newID)) {
+ kDebug() << "UMLView::addWidget: Not adding "
+ << "(id=" << ID2STR(pWidget->getID())
+ << "/type=" << pWidget->getBaseType()
+ << "/name=" << pWidget->getName()
+ << ") because it's already there" << endl;
+ delete pWidget; // Not nice but if _we_ don't do it nobody else will
+ return true;//don't stop paste just because widget found.
+ }
+ m_WidgetList.append( pWidget );
+ }
+ break;
+
+ case wt_Message:
+ case wt_Note:
+ case wt_Box:
+ case wt_Text:
+ case wt_State:
+ case wt_Activity:
+ {
+ Uml::IDType newID = m_pDoc->assignNewID( pWidget->getID() );
+ pWidget->setID(newID);
+ if (type != wt_Message) {
+ m_WidgetList.append( pWidget );
+ return true;
+ }
+ // CHECK
+ // Handling of wt_Message:
+ MessageWidget *pMessage = static_cast<MessageWidget *>( pWidget );
+ if (pMessage == NULL) {
+ kDebug() << "UMLView::addWidget(): pMessage is NULL" << endl;
+ return false;
+ }
+ ObjectWidget *objWidgetA = pMessage -> getWidget(A);
+ ObjectWidget *objWidgetB = pMessage -> getWidget(B);
+ Uml::IDType waID = objWidgetA -> getLocalID();
+ Uml::IDType wbID = objWidgetB -> getLocalID();
+ Uml::IDType newWAID = m_pIDChangesLog ->findNewID( waID );
+ Uml::IDType newWBID = m_pIDChangesLog ->findNewID( wbID );
+ if( newWAID == Uml::id_None || newWBID == Uml::id_None ) {
+ kDebug() << "Error with ids : " << ID2STR(newWAID)
+ << " " << ID2STR(newWBID) << endl;
+ return false;
+ }
+ // Assumption here is that the A/B objectwidgets and the textwidget
+ // are pristine in the sense that we may freely change their local IDs.
+ objWidgetA -> setLocalID( newWAID );
+ objWidgetB -> setLocalID( newWBID );
+ FloatingTextWidget *ft = pMessage->getFloatingTextWidget();
+ if (ft == NULL)
+ kDebug() << "UMLView::addWidget: FloatingTextWidget of Message is NULL" << endl;
+ else if (ft->getID() == Uml::id_None)
+ ft->setID( UniqueID::gen() );
+ else {
+ Uml::IDType newTextID = m_pDoc->assignNewID( ft->getID() );
+ ft->setID( newTextID );
+ }
+ m_MessageList.append( pMessage );
+ }
+ break;
+
+ case wt_Object:
+ {
+ ObjectWidget* pObjectWidget = static_cast<ObjectWidget*>(pWidget);
+ if (pObjectWidget == NULL) {
+ kDebug() << "UMLView::addWidget(): pObjectWidget is NULL" << endl;
+ return false;
+ }
+ Uml::IDType nNewLocalID = getLocalID();
+ Uml::IDType nOldLocalID = pObjectWidget -> getLocalID();
+ m_pIDChangesLog->addIDChange( nOldLocalID, nNewLocalID );
+ pObjectWidget -> setLocalID( nNewLocalID );
+ UMLObject *pObject = m_pDoc->findObjectById(pWidget->getID());
+ if( !pObject ) {
+ kDebug() << "addWidget::Can't find UMLObject" << endl;
+ return false;
+ }
+ pWidget -> setUMLObject( pObject );
+ m_WidgetList.append( pWidget );
+ }
+ break;
+
+ default:
+ kDebug() << "Trying to add an invalid widget type" << endl;
+ return false;
+ break;
+ }
+
+ return true;
+}
+
+// Add the association, and its child widgets to this view
+bool UMLView::addAssociation(AssociationWidget* pAssoc , bool isPasteOperation) {
+
+ if (!pAssoc) {
+ return false;
+ }
+ const Association_Type type = pAssoc->getAssocType();
+
+ if( isPasteOperation )
+ {
+ IDChangeLog * log = m_pDoc -> getChangeLog();
+
+ if(!log )
+ return false;
+
+ Uml::IDType ida = Uml::id_None, idb = Uml::id_None;
+ if( getType() == dt_Collaboration || getType() == dt_Sequence ) {
+ //check local log first
+ ida = m_pIDChangesLog->findNewID( pAssoc->getWidgetID(A) );
+ idb = m_pIDChangesLog->findNewID( pAssoc->getWidgetID(B) );
+ //if either is still not found and assoc type is anchor
+ //we are probably linking to a notewidet - else an error
+ if( ida == Uml::id_None && type == at_Anchor )
+ ida = log->findNewID(pAssoc->getWidgetID(A));
+ if( idb == Uml::id_None && type == at_Anchor )
+ idb = log->findNewID(pAssoc->getWidgetID(B));
+ } else {
+ Uml::IDType oldIdA = pAssoc->getWidgetID(A);
+ Uml::IDType oldIdB = pAssoc->getWidgetID(B);
+ ida = log->findNewID( oldIdA );
+ if (ida == Uml::id_None) { // happens after a cut
+ if (oldIdA == Uml::id_None)
+ return false;
+ ida = oldIdA;
+ }
+ idb = log->findNewID( oldIdB );
+ if (idb == Uml::id_None) { // happens after a cut
+ if (oldIdB == Uml::id_None)
+ return false;
+ idb = oldIdB;
+ }
+ }
+ if(ida == Uml::id_None || idb == Uml::id_None) {
+ return false;
+ }
+ // cant do this anymore.. may cause problem for pasting
+ // pAssoc->setWidgetID(ida, A);
+ // pAssoc->setWidgetID(idb, B);
+ pAssoc->setWidget(findWidget(ida), A);
+ pAssoc->setWidget(findWidget(idb), B);
+ }
+
+ UMLWidget * pWidgetA = findWidget(pAssoc->getWidgetID(A));
+ UMLWidget * pWidgetB = findWidget(pAssoc->getWidgetID(B));
+ //make sure valid widget ids
+ if (!pWidgetA || !pWidgetB) {
+ return false;
+ }
+
+ //make sure valid
+ if (!isPasteOperation && !m_pDoc->loading() &&
+ !AssocRules::allowAssociation(type, pWidgetA, pWidgetB, false)) {
+ kWarning() << "UMLView::addAssociation: allowAssociation returns false "
+ << "for AssocType " << type << endl;
+ return false;
+ }
+
+ //make sure there isn't already the same assoc
+ AssociationWidgetListIt assoc_it( m_AssociationList );
+ AssociationWidget* assocwidget = 0;
+ while((assocwidget=assoc_it.current())) {
+ ++assoc_it;
+ if( *pAssoc == *assocwidget )
+ // this is nuts. Paste operation wants to know if 'true'
+ // for duplicate, but loadFromXMI needs 'false' value
+ return (isPasteOperation? true: false);
+ }
+
+ m_AssociationList.append(pAssoc);
+
+ FloatingTextWidget *ft[5] = { pAssoc->getNameWidget(),
+ pAssoc->getRoleWidget(A),
+ pAssoc->getRoleWidget(B),
+ pAssoc->getMultiWidget(A),
+ pAssoc->getMultiWidget(B) };
+ for (int i = 0; i < 5; i++) {
+ FloatingTextWidget *flotxt = ft[i];
+ if (flotxt) {
+ flotxt->updateComponentSize();
+ addWidget(flotxt);
+ }
+ }
+
+ return true;
+}
+
+void UMLView::activateAfterLoad(bool bUseLog) {
+ if (m_bActivated)
+ return;
+ if( bUseLog ) {
+ beginPartialWidgetPaste();
+ }
+
+ //now activate them all
+ activate();
+
+ if( bUseLog ) {
+ endPartialWidgetPaste();
+ }
+ resizeCanvasToItems();
+ setZoom( getZoom() );
+ m_bActivated = true;
+}
+
+void UMLView::beginPartialWidgetPaste() {
+ delete m_pIDChangesLog;
+ m_pIDChangesLog = 0;
+
+ m_pIDChangesLog = new IDChangeLog();
+ m_bPaste = true;
+}
+
+void UMLView::endPartialWidgetPaste() {
+ delete m_pIDChangesLog;
+ m_pIDChangesLog = 0;
+
+ m_bPaste = false;
+}
+
+void UMLView::removeAssoc(AssociationWidget* pAssoc) {
+ if(!pAssoc)
+ return;
+
+ emit sigAssociationRemoved(pAssoc);
+
+ pAssoc->cleanup();
+ m_AssociationList.remove(pAssoc); // will delete our association
+ m_pDoc->setModified();
+}
+
+void UMLView::removeAssocInViewAndDoc(AssociationWidget* a) {
+ // For umbrello 1.2, UMLAssociations can only be removed in two ways:
+ // 1. Right click on the assocwidget in the view and select Delete
+ // 2. Go to the Class Properties page, select Associations, right click
+ // on the association and select Delete
+ if(!a)
+ return;
+ if (a->getAssocType() == at_Containment) {
+ UMLObject *objToBeMoved = a->getWidget(B)->getUMLObject();
+ if (objToBeMoved != NULL) {
+ UMLListView *lv = UMLApp::app()->getListView();
+ lv->moveObject( objToBeMoved->getID(),
+ Model_Utils::convert_OT_LVT(objToBeMoved),
+ lv->theLogicalView() );
+ // UMLListView::moveObject() will delete the containment
+ // AssociationWidget via UMLView::updateContainment().
+ } else {
+ kDebug() << "removeAssocInViewAndDoc(containment): "
+ << "objB is NULL" << endl;
+ }
+ } else {
+ // Remove assoc in doc.
+ m_pDoc->removeAssociation(a->getAssociation());
+ // Remove assoc in view.
+ removeAssoc(a);
+ }
+}
+
+/** Removes all the associations related to Widget */
+void UMLView::removeAssociations(UMLWidget* Widget) {
+ AssociationWidgetListIt assoc_it(m_AssociationList);
+ AssociationWidget* assocwidget = 0;
+ while((assocwidget=assoc_it.current())) {
+ ++assoc_it;
+ if(assocwidget->contains(Widget)) {
+ removeAssoc(assocwidget);
+ }
+ }
+}
+
+void UMLView::selectAssociations(bool bSelect) {
+ AssociationWidgetListIt assoc_it(m_AssociationList);
+ AssociationWidget* assocwidget = 0;
+ while((assocwidget=assoc_it.current())) {
+ ++assoc_it;
+ if(bSelect &&
+ assocwidget->getWidget(A) && assocwidget->getWidget(A)->getSelected() &&
+ assocwidget->getWidget(B) && assocwidget->getWidget(B)->getSelected() ) {
+ assocwidget->setSelected(true);
+ } else {
+ assocwidget->setSelected(false);
+ }
+ }//end while
+}
+
+void UMLView::getWidgetAssocs(UMLObject* Obj, AssociationWidgetList & Associations) {
+ if( ! Obj )
+ return;
+
+ AssociationWidgetListIt assoc_it(m_AssociationList);
+ AssociationWidget * assocwidget;
+ while((assocwidget = assoc_it.current())) {
+ if (assocwidget->getWidget(A)->getUMLObject() == Obj ||
+ assocwidget->getWidget(B)->getUMLObject() == Obj)
+ Associations.append(assocwidget);
+ ++assoc_it;
+ }//end while
+}
+
+void UMLView::closeEvent ( QCloseEvent * e ) {
+ QWidget::closeEvent(e);
+}
+
+void UMLView::removeAllAssociations() {
+ //Remove All association widgets
+ AssociationWidgetListIt assoc_it(m_AssociationList);
+ AssociationWidget* assocwidget = 0;
+ while((assocwidget=assoc_it.current()))
+ {
+ ++assoc_it;
+ removeAssoc(assocwidget);
+ }
+ m_AssociationList.clear();
+}
+
+
+void UMLView::removeAllWidgets() {
+ // Remove widgets.
+ UMLWidgetListIt it( m_WidgetList );
+ UMLWidget * temp = 0;
+ while ( (temp = it.current()) != 0 ) {
+ ++it;
+ // I had to take this condition back in, else umbrello
+ // crashes on exit. Still to be analyzed. --okellogg
+ if( !( temp -> getBaseType() == wt_Text &&
+ ((FloatingTextWidget *)temp)-> getRole() != tr_Floating ) ) {
+ removeWidget( temp );
+ }
+ }
+ m_WidgetList.clear();
+}
+
+void UMLView::showDocumentation( UMLObject * object, bool overwrite ) {
+ UMLApp::app() -> getDocWindow() -> showDocumentation( object, overwrite );
+ m_bChildDisplayedDoc = true;
+}
+
+void UMLView::showDocumentation( UMLWidget * widget, bool overwrite ) {
+ UMLApp::app() -> getDocWindow() -> showDocumentation( widget, overwrite );
+ m_bChildDisplayedDoc = true;
+}
+
+void UMLView::showDocumentation( AssociationWidget * widget, bool overwrite ) {
+ UMLApp::app() -> getDocWindow() -> showDocumentation( widget, overwrite );
+ m_bChildDisplayedDoc = true;
+}
+
+void UMLView::updateDocumentation( bool clear ) {
+ UMLApp::app() -> getDocWindow() -> updateDocumentation( clear );
+}
+
+void UMLView::updateContainment(UMLCanvasObject *self) {
+ if (self == NULL)
+ return;
+ // See if the object has a widget representation in this view.
+ // While we're at it, also see if the new parent has a widget here.
+ UMLWidget *selfWidget = NULL, *newParentWidget = NULL;
+ UMLPackage *newParent = self->getUMLPackage();
+ for (UMLWidgetListIt wit(m_WidgetList); wit.current(); ++wit) {
+ UMLWidget *w = wit.current();
+ UMLObject *o = w->getUMLObject();
+ if (o == self)
+ selfWidget = w;
+ else if (newParent != NULL && o == newParent)
+ newParentWidget = w;
+ }
+ if (selfWidget == NULL)
+ return;
+ // Remove possibly obsoleted containment association.
+ for (AssociationWidgetListIt it(m_AssociationList); it.current(); ++it) {
+ AssociationWidget *a = it.current();
+ if (a->getAssocType() != Uml::at_Containment)
+ continue;
+ // Container is at role A, containee at B.
+ // We only look at association for which we are B.
+ UMLWidget *wB = a->getWidget(B);
+ UMLObject *roleBObj = wB->getUMLObject();
+ if (roleBObj != self)
+ continue;
+ UMLWidget *wA = a->getWidget(A);
+ UMLObject *roleAObj = wA->getUMLObject();
+ if (roleAObj == newParent) {
+ // Wow, all done. Great!
+ return;
+ }
+ removeAssoc(a); // AutoDelete is true
+ // It's okay to break out because there can only be a single
+ // containing object.
+ break;
+ }
+ if (newParentWidget == NULL)
+ return;
+ // Create the new containment association.
+ AssociationWidget *a = new AssociationWidget(this, newParentWidget,
+ Uml::at_Containment, selfWidget);
+ a->calculateEndingPoints();
+ a->setActivated(true);
+ m_AssociationList.append(a);
+}
+
+void UMLView::createAutoAssociations( UMLWidget * widget ) {
+ if (widget == NULL ||
+ (m_Type != Uml::dt_Class &&
+ m_Type != Uml::dt_Component &&
+ m_Type != Uml::dt_Deployment &&
+ m_Type != Uml::dt_EntityRelationship))
+ return;
+ // Recipe:
+ // If this widget has an underlying UMLCanvasObject then
+ // for each of the UMLCanvasObject's UMLAssociations
+ // if umlassoc's "other" role has a widget representation on this view then
+ // if the AssocWidget does not already exist then
+ // if the assoc type is permitted in the current diagram type then
+ // create the AssocWidget
+ // end if
+ // end if
+ // end if
+ // end loop
+ // Do createAutoAttributeAssociations()
+ // if this object is capable of containing nested objects then
+ // for each of the object's containedObjects
+ // if the containedObject has a widget representation on this view then
+ // if the containedWidget is not physically located inside this widget
+ // create the containment AssocWidget
+ // end if
+ // end if
+ // end loop
+ // end if
+ // if the UMLCanvasObject has a parentPackage then
+ // if the parentPackage has a widget representation on this view then
+ // create the containment AssocWidget
+ // end if
+ // end if
+ // end if
+ UMLObject *tmpUmlObj = widget->getUMLObject();
+ if (tmpUmlObj == NULL)
+ return;
+ UMLCanvasObject *umlObj = dynamic_cast<UMLCanvasObject*>(tmpUmlObj);
+ if (umlObj == NULL)
+ return;
+ const UMLAssociationList& umlAssocs = umlObj->getAssociations();
+ UMLAssociationListIt it(umlAssocs);
+ UMLAssociation *assoc = NULL;
+ Uml::IDType myID = umlObj->getID();
+ while ((assoc = it.current()) != NULL) {
+ ++it;
+ UMLCanvasObject *other = NULL;
+ UMLObject *roleAObj = assoc->getObject(A);
+ if (roleAObj == NULL) {
+ kDebug() << "createAutoAssociations: roleA object is NULL at UMLAssoc "
+ << ID2STR(assoc->getID()) << endl;
+ continue;
+ }
+ UMLObject *roleBObj = assoc->getObject(B);
+ if (roleBObj == NULL) {
+ kDebug() << "createAutoAssociations: roleB object is NULL at UMLAssoc "
+ << ID2STR(assoc->getID()) << endl;
+ continue;
+ }
+ if (roleAObj->getID() == myID) {
+ other = static_cast<UMLCanvasObject*>(roleBObj);
+ } else if (roleBObj->getID() == myID) {
+ other = static_cast<UMLCanvasObject*>(roleAObj);
+ } else {
+ kDebug() << "createAutoAssociations: Can't find own object "
+ << ID2STR(myID) << " in UMLAssoc "
+ << ID2STR(assoc->getID()) << endl;
+ continue;
+ }
+ // Now that we have determined the "other" UMLObject, seek it in
+ // this view's UMLWidgets.
+ Uml::IDType otherID = other->getID();
+ UMLWidget *pOtherWidget;
+ UMLWidgetListIt wit(m_WidgetList);
+ while ((pOtherWidget = wit.current()) != NULL) {
+ ++wit;
+ if (pOtherWidget->getID() == otherID)
+ break;
+ }
+ if (pOtherWidget == NULL)
+ continue;
+ // Both objects are represented in this view:
+ // Assign widget roles as indicated by the UMLAssociation.
+ UMLWidget *widgetA, *widgetB;
+ if (myID == roleAObj->getID()) {
+ widgetA = widget;
+ widgetB = pOtherWidget;
+ } else {
+ widgetA = pOtherWidget;
+ widgetB = widget;
+ }
+ // Check that the assocwidget does not already exist.
+ Uml::Association_Type assocType = assoc->getAssocType();
+ AssociationWidget * assocwidget = findAssocWidget(assocType, widgetA, widgetB);
+ if (assocwidget) {
+ assocwidget->calculateEndingPoints(); // recompute assoc lines
+ continue;
+ }
+ // Check that the assoc is allowed.
+ if (!AssocRules::allowAssociation(assocType, widgetA, widgetB, false)) {
+ kDebug() << "createAutoAssociations: not transferring assoc "
+ << "of type " << assocType << endl;
+ continue;
+ }
+ // Create the AssociationWidget.
+ assocwidget = new AssociationWidget( this );
+ assocwidget->setWidget(widgetA, A);
+ assocwidget->setWidget(widgetB, B);
+ assocwidget->setAssocType(assocType);
+ assocwidget->setUMLObject(assoc);
+ // Call calculateEndingPoints() before setting the FloatingTexts
+ // because their positions are computed according to the
+ // assocwidget line positions.
+ assocwidget->calculateEndingPoints();
+ assocwidget->syncToModel();
+ assocwidget->setActivated(true);
+ if (! addAssociation(assocwidget))
+ delete assocwidget;
+ }
+ createAutoAttributeAssociations(widget);
+ // if this object is capable of containing nested objects then
+ Uml::Object_Type t = umlObj->getBaseType();
+ if (t == ot_Package || t == ot_Class || t == ot_Interface || t == ot_Component) {
+ // for each of the object's containedObjects
+ UMLPackage *umlPkg = static_cast<UMLPackage*>(umlObj);
+ UMLObjectList lst = umlPkg->containedObjects();
+ for (UMLObject *obj = lst.first(); obj; obj = lst.next()) {
+ // if the containedObject has a widget representation on this view then
+ Uml::IDType id = obj->getID();
+ for (UMLWidget *w = m_WidgetList.first(); w; w = m_WidgetList.next()) {
+ if (w->getID() != id)
+ continue;
+ // if the containedWidget is not physically located inside this widget
+ if (widget->rect().contains(w->rect()))
+ continue;
+ // create the containment AssocWidget
+ AssociationWidget *a = new AssociationWidget(this, widget,
+ at_Containment, w);
+ a->calculateEndingPoints();
+ a->setActivated(true);
+ if (! addAssociation(a))
+ delete a;
+ }
+ }
+ }
+ // if the UMLCanvasObject has a parentPackage then
+ UMLPackage *parent = umlObj->getUMLPackage();
+ if (parent == NULL)
+ return;
+ // if the parentPackage has a widget representation on this view then
+ Uml::IDType pkgID = parent->getID();
+ UMLWidget *pWidget;
+ UMLWidgetListIt wit(m_WidgetList);
+ while ((pWidget = wit.current()) != NULL) {
+ ++wit;
+ if (pWidget->getID() == pkgID)
+ break;
+ }
+ if (pWidget == NULL || pWidget->rect().contains(widget->rect()))
+ return;
+ // create the containment AssocWidget
+ AssociationWidget *a = new AssociationWidget(this, pWidget, at_Containment, widget);
+ a->calculateEndingPoints();
+ a->setActivated(true);
+ if (! addAssociation(a))
+ delete a;
+}
+
+void UMLView::createAutoAttributeAssociations(UMLWidget *widget) {
+ if (widget == NULL || m_Type != Uml::dt_Class)
+ return;
+
+ // Pseudocode:
+ // if the underlying model object is really a UMLClassifier then
+ // for each of the UMLClassifier's UMLAttributes
+ // if the attribute type has a widget representation on this view then
+ // if the AssocWidget does not already exist then
+ // if the current diagram type permits compositions then
+ // create a composition AssocWidget
+ // end if
+ // end if
+ // end if
+ // if the attribute type is a Datatype then
+ // if the Datatype is a reference (pointer) type then
+ // if the referenced type has a widget representation on this view then
+ // if the AssocWidget does not already exist then
+ // if the current diagram type permits aggregations then
+ // create an aggregation AssocWidget from the ClassifierWidget to the
+ // widget of the referenced type
+ // end if
+ // end if
+ // end if
+ // end if
+ // end if
+ // end loop
+ // end if
+ //
+ // Implementation:
+ UMLObject *tmpUmlObj = widget->getUMLObject();
+ if (tmpUmlObj == NULL)
+ return;
+ // if the underlying model object is really a UMLClassifier then
+ if (tmpUmlObj->getBaseType() == Uml::ot_Datatype) {
+ UMLClassifier *dt = static_cast<UMLClassifier*>(tmpUmlObj);
+ while (dt->originType() != NULL) {
+ tmpUmlObj = dt->originType();
+ if (tmpUmlObj->getBaseType() != Uml::ot_Datatype)
+ break;
+ dt = static_cast<UMLClassifier*>(tmpUmlObj);
+ }
+ }
+ if (tmpUmlObj->getBaseType() != Uml::ot_Class)
+ return;
+ UMLClassifier * klass = static_cast<UMLClassifier*>(tmpUmlObj);
+ // for each of the UMLClassifier's UMLAttributes
+ UMLAttributeList attrList = klass->getAttributeList();
+ for (UMLAttributeListIt ait(attrList); ait.current(); ++ait) {
+ UMLAttribute *attr = ait.current();
+ createAutoAttributeAssociation(attr->getType(), attr, widget);
+ /*
+ * The following code from attachment 19935 of http://bugs.kde.org/140669
+ * creates Aggregation/Composition to the template parameters.
+ * The current solution uses Dependency instead, see handling of template
+ * instantiation at Import_Utils::createUMLObject().
+ UMLClassifierList templateList = attr->getTemplateParams();
+ for (UMLClassifierListIt it(templateList); it.current(); ++it) {
+ createAutoAttributeAssociation(it,attr,widget);
+ }
+ */
+ }
+}
+
+void UMLView::createAutoAttributeAssociation(UMLClassifier *type, UMLAttribute *attr,
+ UMLWidget *widget /*, UMLClassifier * klass*/) {
+ if (type == NULL) {
+ // kDebug() << "UMLView::createAutoAttributeAssociations("
+ // << klass->getName() << "): type is NULL for "
+ // << "attribute " << attr->getName() << endl;
+ return;
+ }
+ Uml::Association_Type assocType = Uml::at_Composition;
+ UMLWidget *w = findWidget( type->getID() );
+ AssociationWidget *aw = NULL;
+ // if the attribute type has a widget representation on this view
+ if (w) {
+ aw = findAssocWidget(widget, w, attr->getName());
+ if ( aw == NULL &&
+ // if the current diagram type permits compositions
+ AssocRules::allowAssociation(assocType, widget, w, false) ) {
+ // Create a composition AssocWidget, or, if the attribute type is
+ // stereotyped <<CORBAInterface>>, create a UniAssociation widget.
+ if (type->getStereotype() == "CORBAInterface")
+ assocType = at_UniAssociation;
+ AssociationWidget *a = new AssociationWidget (this, widget, assocType, w, attr);
+ a->calculateEndingPoints();
+ a->setVisibility(attr->getVisibility(), B);
+ /*
+ if (assocType == at_Aggregation || assocType == at_UniAssociation)
+ a->setMulti("0..1", B);
+ */
+ a->setRoleName(attr->getName(), B);
+ a->setActivated(true);
+ if (! addAssociation(a))
+ delete a;
+ }
+ }
+ // if the attribute type is a Datatype then
+ if (type->getBaseType() == ot_Datatype) {
+ UMLClassifier *dt = static_cast<UMLClassifier*>(type);
+ // if the Datatype is a reference (pointer) type
+ if (dt->isReference()) {
+ //Uml::Association_Type assocType = Uml::at_Composition;
+ UMLClassifier *c = dt->originType();
+ UMLWidget *w = c ? findWidget( c->getID() ) : 0;
+ // if the referenced type has a widget representation on this view
+ if (w) {
+ aw = findAssocWidget(widget, w, attr->getName());
+ if (aw == NULL &&
+ // if the current diagram type permits aggregations
+ AssocRules::allowAssociation(at_Aggregation, widget, w, false)) {
+ // create an aggregation AssocWidget from the ClassifierWidget
+ // to the widget of the referenced type
+ AssociationWidget *a = new AssociationWidget
+ (this, widget, at_Aggregation, w, attr);
+ a->calculateEndingPoints();
+ a->setVisibility(attr->getVisibility(), B);
+ //a->setChangeability(true, B);
+ a->setMulti("0..1", B);
+ a->setRoleName(attr->getName(), B);
+ a->setActivated(true);
+ if (! addAssociation(a))
+ delete a;
+ }
+ }
+ }
+ }
+}
+
+void UMLView::findMaxBoundingRectangle(const FloatingTextWidget* ft, int& px, int& py, int& qx, int& qy)
+{
+ if (ft == NULL || !ft->isVisible())
+ return;
+
+ int x = ft -> getX();
+ int y = ft -> getY();
+ int x1 = x + ft -> getWidth() - 1;
+ int y1 = y + ft -> getHeight() - 1;
+
+ if (px == -1 || x < px)
+ px = x;
+ if (py == -1 || y < py)
+ py = y;
+ if (qx == -1 || x1 > qx)
+ qx = x1;
+ if (qy == -1 || y1 > qy)
+ qy = y1;
+}
+
+void UMLView::copyAsImage(QPixmap*& pix) {
+ //get the smallest rect holding the diagram
+ QRect rect = getDiagramRect();
+ QPixmap diagram( rect.width(), rect.height() );
+
+ //only draw what is selected
+ m_bDrawSelectedOnly = true;
+ selectAssociations(true);
+ getDiagram(rect, diagram);
+
+ //now get the selection cut
+ int px = -1, py = -1, qx = -1, qy = -1;
+
+ //first get the smallest rect holding the widgets
+ for (UMLWidget* temp = m_SelectedList.first(); temp; temp = m_SelectedList.next()) {
+ int x = temp -> getX();
+ int y = temp -> getY();
+ int x1 = x + temp -> width() - 1;
+ int y1 = y + temp -> height() - 1;
+ if(px == -1 || x < px) {
+ px = x;
+ }
+ if(py == -1 || y < py) {
+ py = y;
+ }
+ if(qx == -1 || x1 > qx) {
+ qx = x1;
+ }
+ if(qy == -1 || y1 > qy) {
+ qy = y1;
+ }
+ }
+
+ //also take into account any text lines in assocs or messages
+ AssociationWidget *a;
+ AssociationWidgetListIt assoc_it(m_AssociationList);
+
+ //get each type of associations
+ //This needs to be reimplemented to increase the rectangle
+ //if a part of any association is not included
+ while ((a = assoc_it.current()) != NULL) {
+ ++assoc_it;
+ if (! a->getSelected())
+ continue;
+ const FloatingTextWidget* multiA = const_cast<FloatingTextWidget*>(a->getMultiWidget(A));
+ const FloatingTextWidget* multiB = const_cast<FloatingTextWidget*>(a->getMultiWidget(B));
+ const FloatingTextWidget* roleA = const_cast<FloatingTextWidget*>(a->getRoleWidget(A));
+ const FloatingTextWidget* roleB = const_cast<FloatingTextWidget*>(a->getRoleWidget(B));
+ const FloatingTextWidget* changeA = const_cast<FloatingTextWidget*>(a->getChangeWidget(A));
+ const FloatingTextWidget* changeB = const_cast<FloatingTextWidget*>(a->getChangeWidget(B));
+ findMaxBoundingRectangle(multiA, px, py, qx, qy);
+ findMaxBoundingRectangle(multiB, px, py, qx, qy);
+ findMaxBoundingRectangle(roleA, px, py, qx, qy);
+ findMaxBoundingRectangle(roleB, px, py, qx, qy);
+ findMaxBoundingRectangle(changeA, px, py, qx, qy);
+ findMaxBoundingRectangle(changeB, px, py, qx, qy);
+ }//end while
+
+ QRect imageRect; //area with respect to getDiagramRect()
+ //i.e. all widgets on the canvas. Was previously with
+ //respect to whole canvas
+
+ imageRect.setLeft( px - rect.left() );
+ imageRect.setTop( py - rect.top() );
+ imageRect.setRight( qx - rect.left() );
+ imageRect.setBottom( qy - rect.top() );
+
+ pix = new QPixmap(imageRect.width(), imageRect.height());
+ bitBlt(pix, QPoint(0, 0), &diagram, imageRect);
+ m_bDrawSelectedOnly = false;
+}
+
+void UMLView::setMenu() {
+ slotRemovePopupMenu();
+ ListPopupMenu::Menu_Type menu = ListPopupMenu::mt_Undefined;
+ switch( getType() ) {
+ case dt_Class:
+ menu = ListPopupMenu::mt_On_Class_Diagram;
+ break;
+
+ case dt_UseCase:
+ menu = ListPopupMenu::mt_On_UseCase_Diagram;
+ break;
+
+ case dt_Sequence:
+ menu = ListPopupMenu::mt_On_Sequence_Diagram;
+ break;
+
+ case dt_Collaboration:
+ menu = ListPopupMenu::mt_On_Collaboration_Diagram;
+ break;
+
+ case dt_State:
+ menu = ListPopupMenu::mt_On_State_Diagram;
+ break;
+
+ case dt_Activity:
+ menu = ListPopupMenu::mt_On_Activity_Diagram;
+ break;
+
+ case dt_Component:
+ menu = ListPopupMenu::mt_On_Component_Diagram;
+ break;
+
+ case dt_Deployment:
+ menu = ListPopupMenu::mt_On_Deployment_Diagram;
+ break;
+
+ case dt_EntityRelationship:
+ menu = ListPopupMenu::mt_On_EntityRelationship_Diagram;
+ break;
+
+ default:
+ kWarning() << "setMenu() called on unknown diagram type" << endl;
+ menu = ListPopupMenu::mt_Undefined;
+ break;
+ }//end switch
+ if( menu != ListPopupMenu::mt_Undefined ) {
+ m_pMenu = new ListPopupMenu(this, menu, this);
+ connect(m_pMenu, SIGNAL(activated(int)), this, SLOT(slotMenuSelection(int)));
+ m_pMenu->popup( mapToGlobal( contentsToViewport(worldMatrix().map(m_Pos)) ) );
+ }
+}
+
+void UMLView::slotRemovePopupMenu() {
+ if(m_pMenu) {
+ disconnect(m_pMenu, SIGNAL(activated(int)), this, SLOT(slotMenuSelection(int)));
+ delete m_pMenu;
+ m_pMenu = 0;
+ }
+}
+
+void UMLView::slotMenuSelection(int sel) {
+ switch( (ListPopupMenu::Menu_Type)sel ) {
+ case ListPopupMenu::mt_Undo:
+ m_pDoc->loadUndoData();
+ break;
+
+ case ListPopupMenu::mt_Redo:
+ m_pDoc->loadRedoData();
+ break;
+
+ case ListPopupMenu::mt_Clear:
+ clearDiagram();
+ break;
+
+ case ListPopupMenu::mt_Export_Image:
+ m_pImageExporter->exportView();
+ break;
+
+ case ListPopupMenu::mt_FloatText:
+ {
+ FloatingTextWidget* ft = new FloatingTextWidget(this);
+ ft->changeTextDlg();
+ //if no text entered delete
+ if(!FloatingTextWidget::isTextValid(ft->getText())) {
+ delete ft;
+ } else {
+ ft->setID(UniqueID::gen());
+ setupNewWidget(ft);
+ }
+ }
+ break;
+
+ case ListPopupMenu::mt_UseCase:
+ m_bCreateObject = true;
+ Object_Factory::createUMLObject( ot_UseCase );
+ break;
+
+ case ListPopupMenu::mt_Actor:
+ m_bCreateObject = true;
+ Object_Factory::createUMLObject( ot_Actor );
+ break;
+
+ case ListPopupMenu::mt_Class:
+ case ListPopupMenu::mt_Object:
+ m_bCreateObject = true;
+ Object_Factory::createUMLObject( ot_Class);
+ break;
+
+ case ListPopupMenu::mt_Package:
+ m_bCreateObject = true;
+ Object_Factory::createUMLObject(ot_Package);
+ break;
+
+ case ListPopupMenu::mt_Component:
+ m_bCreateObject = true;
+ Object_Factory::createUMLObject(ot_Component);
+ break;
+
+ case ListPopupMenu::mt_Node:
+ m_bCreateObject = true;
+ Object_Factory::createUMLObject(ot_Node);
+ break;
+
+ case ListPopupMenu::mt_Artifact:
+ m_bCreateObject = true;
+ Object_Factory::createUMLObject(ot_Artifact);
+ break;
+
+ case ListPopupMenu::mt_Interface:
+ m_bCreateObject = true;
+ Object_Factory::createUMLObject(ot_Interface);
+ break;
+
+ case ListPopupMenu::mt_Enum:
+ m_bCreateObject = true;
+ Object_Factory::createUMLObject(ot_Enum);
+ break;
+
+ case ListPopupMenu::mt_Entity:
+ m_bCreateObject = true;
+ Object_Factory::createUMLObject(ot_Entity);
+ break;
+
+ case ListPopupMenu::mt_Datatype:
+ m_bCreateObject = true;
+ Object_Factory::createUMLObject(ot_Datatype);
+ break;
+
+ case ListPopupMenu::mt_Cut:
+ //FIXME make this work for diagram's right click menu
+ if ( m_SelectedList.count() &&
+ UMLApp::app()->editCutCopy(true) ) {
+ deleteSelection();
+ m_pDoc->setModified(true);
+ }
+ break;
+
+ case ListPopupMenu::mt_Copy:
+ //FIXME make this work for diagram's right click menu
+ m_SelectedList.count() && UMLApp::app()->editCutCopy(true);
+ break;
+
+ case ListPopupMenu::mt_Paste:
+ m_PastePoint = m_Pos;
+ m_Pos.setX( 2000 );
+ m_Pos.setY( 2000 );
+ UMLApp::app()->slotEditPaste();
+
+ m_PastePoint.setX( 0 );
+ m_PastePoint.setY( 0 );
+ break;
+
+ case ListPopupMenu::mt_Initial_State:
+ {
+ StateWidget* state = new StateWidget( this, StateWidget::Initial );
+ setupNewWidget( state );
+ }
+ break;
+
+ case ListPopupMenu::mt_End_State:
+ {
+ StateWidget* state = new StateWidget( this, StateWidget::End );
+ setupNewWidget( state );
+ }
+ break;
+
+ case ListPopupMenu::mt_State:
+ {
+ bool ok = false;
+ QString name = KInputDialog::getText( i18n("Enter State Name"),
+ i18n("Enter the name of the new state:"),
+ i18n("new state"), &ok, UMLApp::app() );
+ if ( ok ) {
+ StateWidget* state = new StateWidget( this );
+ state->setName( name );
+ setupNewWidget( state );
+ }
+ }
+ break;
+
+ case ListPopupMenu::mt_Initial_Activity:
+ {
+ ActivityWidget* activity = new ActivityWidget( this, ActivityWidget::Initial );
+ setupNewWidget(activity);
+ }
+ break;
+
+
+ case ListPopupMenu::mt_End_Activity:
+ {
+ ActivityWidget* activity = new ActivityWidget( this, ActivityWidget::End );
+ setupNewWidget(activity);
+ }
+ break;
+
+ case ListPopupMenu::mt_Branch:
+ {
+ ActivityWidget* activity = new ActivityWidget( this, ActivityWidget::Branch );
+ setupNewWidget(activity);
+ }
+ break;
+
+ case ListPopupMenu::mt_Activity:
+ {
+ bool ok = false;
+ QString name = KInputDialog::getText( i18n("Enter Activity Name"),
+ i18n("Enter the name of the new activity:"),
+ i18n("new activity"), &ok, UMLApp::app() );
+ if ( ok ) {
+ ActivityWidget* activity = new ActivityWidget( this, ActivityWidget::Normal );
+ activity->setName( name );
+ setupNewWidget(activity);
+ }
+ }
+ break;
+
+ case ListPopupMenu::mt_SnapToGrid:
+ toggleSnapToGrid();
+ m_pDoc->setModified();
+ break;
+
+ case ListPopupMenu::mt_ShowSnapGrid:
+ toggleShowGrid();
+ m_pDoc->setModified();
+ break;
+
+ case ListPopupMenu::mt_Properties:
+ if (showPropDialog() == true)
+ m_pDoc->setModified();
+ break;
+
+ case ListPopupMenu::mt_Delete:
+ m_pDoc->removeDiagram( getID() );
+ break;
+
+ case ListPopupMenu::mt_Rename:
+ {
+ bool ok = false;
+ QString name = KInputDialog::getText( i18n("Enter Diagram Name"),
+ i18n("Enter the new name of the diagram:"),
+ getName(), &ok, UMLApp::app() );
+ if (ok) {
+ setName(name);
+ m_pDoc->signalDiagramRenamed(this);
+ }
+ }
+ break;
+
+ default:
+ break;
+ }
+}
+
+void UMLView::slotCutSuccessful() {
+ if( m_bStartedCut ) {
+ deleteSelection();
+ m_bStartedCut = false;
+ }
+}
+
+void UMLView::slotShowView() {
+ m_pDoc -> changeCurrentView( getID() );
+}
+
+QPoint UMLView::getPastePoint() {
+ QPoint point = m_PastePoint;
+ point.setX( point.x() - m_Pos.x() );
+ point.setY( point.y() - m_Pos.y() );
+ return point;
+}
+
+void UMLView::resetPastePoint() {
+ m_PastePoint = m_Pos;
+}
+
+int UMLView::snappedX (int x) {
+ if (getSnapToGrid()) {
+ int gridX = getSnapX();
+ int modX = x % gridX;
+ x -= modX;
+ if (modX >= gridX / 2)
+ x += gridX;
+ }
+ return x;
+}
+
+int UMLView::snappedY (int y) {
+ if (getSnapToGrid()) {
+ int gridY = getSnapY();
+ int modY = y % gridY;
+ y -= modY;
+ if (modY >= gridY / 2)
+ y += gridY;
+ }
+ return y;
+}
+
+bool UMLView::showPropDialog() {
+ UMLViewDialog dlg( this, this );
+ if( dlg.exec() ) {
+ return true;
+ }
+ return false;
+}
+
+
+QFont UMLView::getFont() const {
+ return m_Options.uiState.font;
+}
+
+void UMLView::setFont(QFont font, bool changeAllWidgets /* = false */) {
+ m_Options.uiState.font = font;
+ if (!changeAllWidgets)
+ return;
+ for (UMLWidgetListIt wit(m_WidgetList); wit.current(); ++wit) {
+ UMLWidget *w = wit.current();
+ w->setFont(font);
+ }
+}
+
+void UMLView::setClassWidgetOptions( ClassOptionsPage * page ) {
+ UMLWidget * pWidget = 0;
+ UMLWidgetListIt wit( m_WidgetList );
+ while ( (pWidget = wit.current()) != 0 ) {
+ ++wit;
+ Uml::Widget_Type wt = pWidget->getBaseType();
+ if (wt == Uml::wt_Class || wt == Uml::wt_Interface) {
+ page -> setWidget( static_cast<ClassifierWidget *>(pWidget) );
+ page -> updateUMLWidget();
+ }
+ }
+}
+
+
+void UMLView::checkSelections() {
+ UMLWidget * pWA = 0, * pWB = 0, * pTemp = 0;
+ //check messages
+ for(pTemp=(UMLWidget *)m_SelectedList.first();pTemp;pTemp=(UMLWidget *)m_SelectedList.next()) {
+ if( pTemp->getBaseType() == wt_Message && pTemp -> getSelected() ) {
+ MessageWidget * pMessage = static_cast<MessageWidget *>( pTemp );
+ pWA = pMessage -> getWidget(A);
+ pWB = pMessage -> getWidget(B);
+ if( !pWA -> getSelected() ) {
+ pWA -> setSelectedFlag( true );
+ m_SelectedList.append( pWA );
+ }
+ if( !pWB -> getSelected() ) {
+ pWB -> setSelectedFlag( true );
+ m_SelectedList.append( pWB );
+ }
+ }//end if
+ }//end for
+ //check Associations
+ AssociationWidgetListIt it(m_AssociationList);
+ AssociationWidget * pAssoc = 0;
+ while((pAssoc = it.current())) {
+ ++it;
+ if( pAssoc -> getSelected() ) {
+ pWA = pAssoc -> getWidget(A);
+ pWB = pAssoc -> getWidget(B);
+ if( !pWA -> getSelected() ) {
+ pWA -> setSelectedFlag( true );
+ m_SelectedList.append( pWA );
+ }
+ if( !pWB -> getSelected() ) {
+ pWB -> setSelectedFlag( true );
+ m_SelectedList.append( pWB );
+ }
+ }//end if
+ }//end while
+}
+
+bool UMLView::checkUniqueSelection()
+{
+ // if there are no selected items, we return true
+ if (m_SelectedList.count() <= 0)
+ return true;
+
+ // get the first item and its base type
+ UMLWidget * pTemp = (UMLWidget *) m_SelectedList.first();
+ Widget_Type tmpType = pTemp -> getBaseType();
+
+ // check all selected items, if they have the same BaseType
+ for ( pTemp = (UMLWidget *) m_SelectedList.first();
+ pTemp;
+ pTemp = (UMLWidget *) m_SelectedList.next() ) {
+ if( pTemp->getBaseType() != tmpType)
+ {
+ return false; // the base types are different, the list is not unique
+ }
+ } // for ( through all selected items )
+
+ return true; // selected items are unique
+}
+
+void UMLView::clearDiagram() {
+ if( KMessageBox::Continue == KMessageBox::warningContinueCancel( this, i18n("You are about to delete "
+ "the entire diagram.\nAre you sure?"),
+ i18n("Delete Diagram?"),KGuiItem( i18n("&Delete"), "editdelete") ) ) {
+ removeAllWidgets();
+ }
+}
+
+void UMLView::toggleSnapToGrid() {
+ setSnapToGrid( !getSnapToGrid() );
+}
+
+void UMLView::toggleSnapComponentSizeToGrid() {
+ setSnapComponentSizeToGrid( !getSnapComponentSizeToGrid() );
+}
+
+void UMLView::toggleShowGrid() {
+ setShowSnapGrid( !getShowSnapGrid() );
+}
+
+void UMLView::setSnapToGrid(bool bSnap) {
+ m_bUseSnapToGrid = bSnap;
+ emit sigSnapToGridToggled( getSnapToGrid() );
+}
+
+void UMLView::setSnapComponentSizeToGrid(bool bSnap) {
+ m_bUseSnapComponentSizeToGrid = bSnap;
+ updateComponentSizes();
+ emit sigSnapComponentSizeToGridToggled( getSnapComponentSizeToGrid() );
+}
+
+bool UMLView::getShowSnapGrid() const {
+ return m_bShowSnapGrid;
+}
+
+void UMLView::setShowSnapGrid(bool bShow) {
+ m_bShowSnapGrid = bShow;
+ canvas()->setAllChanged();
+ emit sigShowGridToggled( getShowSnapGrid() );
+}
+
+bool UMLView::getShowOpSig() const {
+ return m_Options.classState.showOpSig;
+}
+
+void UMLView::setShowOpSig(bool bShowOpSig) {
+ m_Options.classState.showOpSig = bShowOpSig;
+}
+
+void UMLView::setZoom(int zoom) {
+ if (zoom < 10) {
+ zoom = 10;
+ } else if (zoom > 500) {
+ zoom = 500;
+ }
+
+ QWMatrix wm;
+ wm.scale(zoom/100.0,zoom/100.0);
+ setWorldMatrix(wm);
+
+ m_nZoom = currentZoom();
+ resizeCanvasToItems();
+}
+
+int UMLView::currentZoom() {
+ return (int)(worldMatrix().m11()*100.0);
+}
+
+void UMLView::zoomIn() {
+ QWMatrix wm = worldMatrix();
+ wm.scale(1.5,1.5); // adjust zooming step here
+ setZoom( (int)(wm.m11()*100.0) );
+}
+
+void UMLView::zoomOut() {
+ QWMatrix wm = worldMatrix();
+ wm.scale(2.0/3.0, 2.0/3.0); //adjust zooming step here
+ setZoom( (int)(wm.m11()*100.0) );
+}
+
+void UMLView::fileLoaded() {
+ setZoom( getZoom() );
+ resizeCanvasToItems();
+}
+
+void UMLView::setCanvasSize(int width, int height) {
+ setCanvasWidth(width);
+ setCanvasHeight(height);
+ canvas()->resize(width, height);
+}
+
+void UMLView::resizeCanvasToItems() {
+ QRect canvasSize = getDiagramRect();
+ int canvasWidth = canvasSize.right() + 5;
+ int canvasHeight = canvasSize.bottom() + 5;
+
+ //Find out the bottom right visible pixel and size to at least that
+ int contentsX, contentsY;
+ int contentsWMX, contentsWMY;
+ viewportToContents(viewport()->width(), viewport()->height(), contentsX, contentsY);
+ inverseWorldMatrix().map(contentsX, contentsY, &contentsWMX, &contentsWMY);
+
+ if (canvasWidth < contentsWMX) {
+ canvasWidth = contentsWMX;
+ }
+
+ if (canvasHeight < contentsWMY) {
+ canvasHeight = contentsWMY;
+ }
+
+ setCanvasSize(canvasWidth, canvasHeight);
+}
+
+void UMLView::show() {
+ QWidget::show();
+ resizeCanvasToItems();
+}
+
+void UMLView::updateComponentSizes() {
+ // update sizes of all components
+ UMLWidgetListIt it( m_WidgetList );
+ UMLWidget *obj;
+ while ( (obj=(UMLWidget*)it.current()) != 0 ) {
+ ++it;
+ obj->updateComponentSize();
+ }
+}
+
+/**
+ * Force the widget font metrics to be updated next time
+ * the widgets are drawn.
+ * This is necessary because the widget size might depend on the
+ * font metrics and the font metrics might change for different
+ * QPainter, i.e. font metrics for Display font and Printer font are
+ * usually different.
+ * Call this when you change the QPainter.
+ */
+void UMLView::forceUpdateWidgetFontMetrics(QPainter * painter) {
+ UMLWidgetListIt it( m_WidgetList );
+ UMLWidget *obj;
+
+ while ((obj = it.current()) != 0 ) {
+ ++it;
+ obj->forceUpdateFontMetrics(painter);
+ }
+}
+
+void UMLView::saveToXMI( QDomDocument & qDoc, QDomElement & qElement ) {
+ QDomElement viewElement = qDoc.createElement( "diagram" );
+ viewElement.setAttribute( "xmi.id", ID2STR(m_nID) );
+ viewElement.setAttribute( "name", getName() );
+ viewElement.setAttribute( "type", m_Type );
+ viewElement.setAttribute( "documentation", m_Documentation );
+ //optionstate uistate
+ viewElement.setAttribute( "fillcolor", m_Options.uiState.fillColor.name() );
+ viewElement.setAttribute( "linecolor", m_Options.uiState.lineColor.name() );
+ viewElement.setAttribute( "linewidth", m_Options.uiState.lineWidth );
+ viewElement.setAttribute( "usefillcolor", m_Options.uiState.useFillColor );
+ viewElement.setAttribute( "font", m_Options.uiState.font.toString() );
+ //optionstate classstate
+ viewElement.setAttribute( "showattsig", m_Options.classState.showAttSig );
+ viewElement.setAttribute( "showatts", m_Options.classState.showAtts);
+ viewElement.setAttribute( "showopsig", m_Options.classState.showOpSig );
+ viewElement.setAttribute( "showops", m_Options.classState.showOps );
+ viewElement.setAttribute( "showpackage", m_Options.classState.showPackage );
+ viewElement.setAttribute( "showscope", m_Options.classState.showVisibility );
+ viewElement.setAttribute( "showstereotype", m_Options.classState.showStereoType );
+ //misc
+ viewElement.setAttribute( "localid", ID2STR(m_nLocalID) );
+ viewElement.setAttribute( "showgrid", m_bShowSnapGrid );
+ viewElement.setAttribute( "snapgrid", m_bUseSnapToGrid );
+ viewElement.setAttribute( "snapcsgrid", m_bUseSnapComponentSizeToGrid );
+ viewElement.setAttribute( "snapx", m_nSnapX );
+ viewElement.setAttribute( "snapy", m_nSnapY );
+ viewElement.setAttribute( "zoom", m_nZoom );
+ viewElement.setAttribute( "canvasheight", m_nCanvasHeight );
+ viewElement.setAttribute( "canvaswidth", m_nCanvasWidth );
+ //now save all the widgets
+ UMLWidget * widget = 0;
+ UMLWidgetListIt w_it( m_WidgetList );
+ QDomElement widgetElement = qDoc.createElement( "widgets" );
+ while( ( widget = w_it.current() ) ) {
+ ++w_it;
+ // Having an exception is bad I know, but gotta work with
+ // system we are given.
+ // We DONT want to record any text widgets which are belonging
+ // to associations as they are recorded later in the "associations"
+ // section when each owning association is dumped. -b.t.
+ if (widget->getBaseType() != wt_Text ||
+ static_cast<FloatingTextWidget*>(widget)->getLink() == NULL)
+ widget->saveToXMI( qDoc, widgetElement );
+ }
+ viewElement.appendChild( widgetElement );
+ //now save the message widgets
+ MessageWidgetListIt m_it( m_MessageList );
+ QDomElement messageElement = qDoc.createElement( "messages" );
+ while( ( widget = m_it.current() ) ) {
+ ++m_it;
+ widget -> saveToXMI( qDoc, messageElement );
+ }
+ viewElement.appendChild( messageElement );
+ //now save the associations
+ QDomElement assocElement = qDoc.createElement( "associations" );
+ if ( m_AssociationList.count() ) {
+ // We guard against ( m_AssociationList.count() == 0 ) because
+ // this code could be reached as follows:
+ // ^ UMLView::saveToXMI()
+ // ^ UMLDoc::saveToXMI()
+ // ^ UMLDoc::addToUndoStack()
+ // ^ UMLDoc::setModified()
+ // ^ UMLDoc::createDiagram()
+ // ^ UMLDoc::newDocument()
+ // ^ UMLApp::newDocument()
+ // ^ main()
+ //
+ AssociationWidgetListIt a_it( m_AssociationList );
+ AssociationWidget * assoc = 0;
+ while( ( assoc = a_it.current() ) ) {
+ ++a_it;
+ assoc -> saveToXMI( qDoc, assocElement );
+ }
+ // kDebug() << "UMLView::saveToXMI() saved "
+ // << m_AssociationList.count() << " assocData." << endl;
+ }
+ viewElement.appendChild( assocElement );
+ qElement.appendChild( viewElement );
+}
+
+bool UMLView::loadFromXMI( QDomElement & qElement ) {
+ QString id = qElement.attribute( "xmi.id", "-1" );
+ m_nID = STR2ID(id);
+ if( m_nID == Uml::id_None )
+ return false;
+ setName( qElement.attribute( "name", "" ) );
+ QString type = qElement.attribute( "type", "0" );
+ m_Documentation = qElement.attribute( "documentation", "" );
+ QString localid = qElement.attribute( "localid", "0" );
+ //optionstate uistate
+ QString font = qElement.attribute( "font", "" );
+ if (!font.isEmpty()) {
+ m_Options.uiState.font.fromString( font );
+ m_Options.uiState.font.setUnderline(false);
+ }
+ QString fillcolor = qElement.attribute( "fillcolor", "" );
+ QString linecolor = qElement.attribute( "linecolor", "" );
+ QString linewidth = qElement.attribute( "linewidth", "" );
+ QString usefillcolor = qElement.attribute( "usefillcolor", "0" );
+ m_Options.uiState.useFillColor = (bool)usefillcolor.toInt();
+ //optionstate classstate
+ QString temp = qElement.attribute( "showattsig", "0" );
+ m_Options.classState.showAttSig = (bool)temp.toInt();
+ temp = qElement.attribute( "showatts", "0" );
+ m_Options.classState.showAtts = (bool)temp.toInt();
+ temp = qElement.attribute( "showopsig", "0" );
+ m_Options.classState.showOpSig = (bool)temp.toInt();
+ temp = qElement.attribute( "showops", "0" );
+ m_Options.classState.showOps = (bool)temp.toInt();
+ temp = qElement.attribute( "showpackage", "0" );
+ m_Options.classState.showPackage = (bool)temp.toInt();
+ temp = qElement.attribute( "showscope", "0" );
+ m_Options.classState.showVisibility = (bool)temp.toInt();
+ temp = qElement.attribute( "showstereotype", "0" );
+ m_Options.classState.showStereoType = (bool)temp.toInt();
+ //misc
+ QString showgrid = qElement.attribute( "showgrid", "0" );
+ m_bShowSnapGrid = (bool)showgrid.toInt();
+
+ QString snapgrid = qElement.attribute( "snapgrid", "0" );
+ m_bUseSnapToGrid = (bool)snapgrid.toInt();
+
+ QString snapcsgrid = qElement.attribute( "snapcsgrid", "0" );
+ m_bUseSnapComponentSizeToGrid = (bool)snapcsgrid.toInt();
+
+ QString snapx = qElement.attribute( "snapx", "10" );
+ m_nSnapX = snapx.toInt();
+
+ QString snapy = qElement.attribute( "snapy", "10" );
+ m_nSnapY = snapy.toInt();
+
+ QString zoom = qElement.attribute( "zoom", "100" );
+ m_nZoom = zoom.toInt();
+
+ QString height = qElement.attribute( "canvasheight", QString("%1").arg(UMLView::defaultCanvasSize) );
+ m_nCanvasHeight = height.toInt();
+
+ QString width = qElement.attribute( "canvaswidth", QString("%1").arg(UMLView::defaultCanvasSize) );
+ m_nCanvasWidth = width.toInt();
+
+ int nType = type.toInt();
+ if (nType == -1 || nType >= 400) {
+ // Pre 1.5.5 numeric values
+ // Values of "type" were changed in 1.5.5 to merge with Settings::Diagram
+ switch (nType) {
+ case 400:
+ m_Type = Uml::dt_UseCase;
+ break;
+ case 401:
+ m_Type = Uml::dt_Collaboration;
+ break;
+ case 402:
+ m_Type = Uml::dt_Class;
+ break;
+ case 403:
+ m_Type = Uml::dt_Sequence;
+ break;
+ case 404:
+ m_Type = Uml::dt_State;
+ break;
+ case 405:
+ m_Type = Uml::dt_Activity;
+ break;
+ case 406:
+ m_Type = Uml::dt_Component;
+ break;
+ case 407:
+ m_Type = Uml::dt_Deployment;
+ break;
+ case 408:
+ m_Type = Uml::dt_EntityRelationship;
+ break;
+ default:
+ m_Type = Uml::dt_Undefined;
+ break;
+ }
+ } else {
+ m_Type = (Uml::Diagram_Type)nType;
+ }
+ if( !fillcolor.isEmpty() )
+ m_Options.uiState.fillColor = QColor( fillcolor );
+ if( !linecolor.isEmpty() )
+ m_Options.uiState.lineColor = QColor( linecolor );
+ if( !linewidth.isEmpty() )
+ m_Options.uiState.lineWidth = linewidth.toInt();
+ m_nLocalID = STR2ID(localid);
+
+ QDomNode node = qElement.firstChild();
+ bool widgetsLoaded = false, messagesLoaded = false, associationsLoaded = false;
+ while (!node.isNull()) {
+ QDomElement element = node.toElement();
+ if (!element.isNull()) {
+ if (element.tagName() == "widgets")
+ widgetsLoaded = loadWidgetsFromXMI( element );
+ else if (element.tagName() == "messages")
+ messagesLoaded = loadMessagesFromXMI( element );
+ else if (element.tagName() == "associations")
+ associationsLoaded = loadAssociationsFromXMI( element );
+ }
+ node = node.nextSibling();
+ }
+
+ if (!widgetsLoaded) {
+ kWarning() << "failed umlview load on widgets" << endl;
+ return false;
+ }
+ if (!messagesLoaded) {
+ kWarning() << "failed umlview load on messages" << endl;
+ return false;
+ }
+ if (!associationsLoaded) {
+ kWarning() << "failed umlview load on associations" << endl;
+ return false;
+ }
+ return true;
+}
+
+bool UMLView::loadWidgetsFromXMI( QDomElement & qElement ) {
+ UMLWidget* widget = 0;
+ QDomNode node = qElement.firstChild();
+ QDomElement widgetElement = node.toElement();
+ while( !widgetElement.isNull() ) {
+ widget = loadWidgetFromXMI(widgetElement);
+ if (widget) {
+ m_WidgetList.append( widget );
+ // In the interest of best-effort loading, in case of a
+ // (widget == NULL) we still go on.
+ // The individual widget's loadFromXMI method should
+ // already have generated an error message to tell the
+ // user that something went wrong.
+ }
+ node = widgetElement.nextSibling();
+ widgetElement = node.toElement();
+ }
+
+ return true;
+}
+
+UMLWidget* UMLView::loadWidgetFromXMI(QDomElement& widgetElement) {
+
+ if ( !m_pDoc ) {
+ kWarning() << "UMLView::loadWidgetFromXMI(): m_pDoc is NULL" << endl;
+ return 0L;
+ }
+
+ QString tag = widgetElement.tagName();
+ QString idstr = widgetElement.attribute( "xmi.id", "-1" );
+ UMLWidget* widget = Widget_Factory::makeWidgetFromXMI(tag, idstr, this);
+ if (widget == NULL)
+ return NULL;
+ if (!widget->loadFromXMI(widgetElement)) {
+ widget->cleanup();
+ delete widget;
+ return 0;
+ }
+ return widget;
+}
+
+bool UMLView::loadMessagesFromXMI( QDomElement & qElement ) {
+ MessageWidget * message = 0;
+ QDomNode node = qElement.firstChild();
+ QDomElement messageElement = node.toElement();
+ while( !messageElement.isNull() ) {
+ QString tag = messageElement.tagName();
+ if (tag == "messagewidget" ||
+ tag == "UML:MessageWidget" ) { // for bkwd compatibility
+ message = new MessageWidget(this, sequence_message_asynchronous,
+ Uml::id_Reserved);
+ if( !message -> loadFromXMI( messageElement ) ) {
+ delete message;
+ return false;
+ }
+ m_MessageList.append( message );
+ FloatingTextWidget *ft = message->getFloatingTextWidget();
+ if (ft)
+ m_WidgetList.append( ft );
+ else if (message->getSequenceMessageType() != sequence_message_creation)
+ kDebug() << "UMLView::loadMessagesFromXMI: ft is NULL"
+ << " for message " << ID2STR(message->getID()) << endl;
+ }
+ node = messageElement.nextSibling();
+ messageElement = node.toElement();
+ }
+ return true;
+}
+
+bool UMLView::loadAssociationsFromXMI( QDomElement & qElement ) {
+ QDomNode node = qElement.firstChild();
+ QDomElement assocElement = node.toElement();
+ int countr = 0;
+ while( !assocElement.isNull() ) {
+ QString tag = assocElement.tagName();
+ if (tag == "assocwidget" ||
+ tag == "UML:AssocWidget") { // for bkwd compatibility
+ countr++;
+ AssociationWidget *assoc = new AssociationWidget(this);
+ if( !assoc->loadFromXMI( assocElement ) ) {
+ kError() << "couldn't loadFromXMI association widget:"
+ << assoc << ", bad XMI file? Deleting from umlview."
+ << endl;
+ delete assoc;
+ /* return false;
+ Returning false here is a little harsh when the
+ rest of the diagram might load okay.
+ */
+ } else {
+ if(!addAssociation(assoc, false))
+ {
+ kError()<<"Couldnt addAssociation("<<assoc<<") to umlview, deleting."<<endl;
+ // assoc->cleanup();
+ delete assoc;
+ //return false; // soften error.. may not be that bad
+ }
+ }
+ }
+ node = assocElement.nextSibling();
+ assocElement = node.toElement();
+ }
+ return true;
+}
+
+void UMLView::addObject(UMLObject *object)
+{
+ m_bCreateObject = true;
+ if (m_pDoc->addUMLObject(object))
+ m_pDoc->signalUMLObjectCreated(object); // m_bCreateObject is reset by slotObjectCreated()
+ else
+ m_bCreateObject = false;
+}
+
+bool UMLView::loadUisDiagramPresentation(QDomElement & qElement) {
+ for (QDomNode node = qElement.firstChild(); !node.isNull(); node = node.nextSibling()) {
+ QDomElement elem = node.toElement();
+ QString tag = elem.tagName();
+ if (! Uml::tagEq(tag, "Presentation")) {
+ kError() << "ignoring unknown UisDiagramPresentation tag "
+ << tag << endl;
+ continue;
+ }
+ QDomNode n = elem.firstChild();
+ QDomElement e = n.toElement();
+ QString idStr;
+ int x = 0, y = 0, w = 0, h = 0;
+ while (!e.isNull()) {
+ tag = e.tagName();
+ kDebug() << "Presentation: tag = " << tag << endl;
+ if (Uml::tagEq(tag, "Presentation.geometry")) {
+ QDomNode gnode = e.firstChild();
+ QDomElement gelem = gnode.toElement();
+ QString csv = gelem.text();
+ QStringList dim = QStringList::split(",", csv);
+ x = dim[0].toInt();
+ y = dim[1].toInt();
+ w = dim[2].toInt();
+ h = dim[3].toInt();
+ } else if (Uml::tagEq(tag, "Presentation.style")) {
+ // TBD
+ } else if (Uml::tagEq(tag, "Presentation.model")) {
+ QDomNode mnode = e.firstChild();
+ QDomElement melem = mnode.toElement();
+ idStr = melem.attribute("xmi.idref", "");
+ } else {
+ kDebug() << "UMLView::uisLoadFromXMI: ignoring tag "
+ << tag << endl;
+ }
+ n = n.nextSibling();
+ e = n.toElement();
+ }
+ Uml::IDType id = STR2ID(idStr);
+ UMLObject *o = m_pDoc->findObjectById(id);
+ if (o == NULL) {
+ kError() << "UMLView::uisLoadFromXMI: Cannot find object for id "
+ << idStr << endl;
+ } else {
+ Uml::Object_Type ot = o->getBaseType();
+ kDebug() << "Create widget for model object of type " << ot << endl;
+ UMLWidget *widget = NULL;
+ switch (ot) {
+ case Uml::ot_Class:
+ widget = new ClassifierWidget(this, static_cast<UMLClassifier*>(o));
+ break;
+ case Uml::ot_Association:
+ {
+ UMLAssociation *umla = static_cast<UMLAssociation*>(o);
+ Uml::Association_Type at = umla->getAssocType();
+ UMLObject* objA = umla->getObject(Uml::A);
+ UMLObject* objB = umla->getObject(Uml::B);
+ if (objA == NULL || objB == NULL) {
+ kError() << "intern err 1" << endl;
+ return false;
+ }
+ UMLWidget *wA = findWidget(objA->getID());
+ UMLWidget *wB = findWidget(objB->getID());
+ if (wA != NULL && wB != NULL) {
+ AssociationWidget *aw =
+ new AssociationWidget(this, wA, at, wB, umla);
+ aw->syncToModel();
+ m_AssociationList.append(aw);
+ } else {
+ kError() << "cannot create assocwidget from ("
+ << wA << ", " << wB << ")" << endl;
+ }
+ break;
+ }
+ case Uml::ot_Role:
+ {
+ UMLRole *robj = static_cast<UMLRole*>(o);
+ UMLAssociation *umla = robj->getParentAssociation();
+ // @todo properly display role names.
+ // For now, in order to get the role names displayed
+ // simply delete the participating diagram objects
+ // and drag them from the list view to the diagram.
+ break;
+ }
+ default:
+ kError() << "UMLView::uisLoadFromXMI: "
+ << "Cannot create widget of type "
+ << ot << endl;
+ }
+ if (widget) {
+ kDebug() << "Widget: x=" << x << ", y=" << y
+ << ", w=" << w << ", h=" << h << endl;
+ widget->setX(x);
+ widget->setY(y);
+ widget->setSize(w, h);
+ m_WidgetList.append(widget);
+ }
+ }
+ }
+ return true;
+}
+
+bool UMLView::loadUISDiagram(QDomElement & qElement) {
+ QString idStr = qElement.attribute( "xmi.id", "" );
+ if (idStr.isEmpty())
+ return false;
+ m_nID = STR2ID(idStr);
+ UMLListViewItem *ulvi = NULL;
+ for (QDomNode node = qElement.firstChild(); !node.isNull(); node = node.nextSibling()) {
+ if (node.isComment())
+ continue;
+ QDomElement elem = node.toElement();
+ QString tag = elem.tagName();
+ if (tag == "uisDiagramName") {
+ setName( elem.text() );
+ if (ulvi)
+ ulvi->setText( getName() );
+ } else if (tag == "uisDiagramStyle") {
+ QString diagramStyle = elem.text();
+ if (diagramStyle != "ClassDiagram") {
+ kError() << "UMLView::uisLoadFromXMI: diagram style " << diagramStyle
+ << " is not yet implemented" << endl;
+ continue;
+ }
+ m_pDoc->setMainViewID(m_nID);
+ m_Type = Uml::dt_Class;
+ UMLListView *lv = UMLApp::app()->getListView();
+ ulvi = new UMLListViewItem( lv->theLogicalView(), getName(),
+ Uml::lvt_Class_Diagram, m_nID );
+ } else if (tag == "uisDiagramPresentation") {
+ loadUisDiagramPresentation(elem);
+ } else if (tag != "uisToolName") {
+ kDebug() << "UMLView::uisLoadFromXMI: ignoring tag " << tag << endl;
+ }
+ }
+ return true;
+}
+
+
+#include "umlview.moc"
diff --git a/umbrello/umbrello/umlview.h b/umbrello/umbrello/umlview.h
new file mode 100644
index 00000000..99a39198
--- /dev/null
+++ b/umbrello/umbrello/umlview.h
@@ -0,0 +1,1255 @@
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * copyright (C) 2002-2007 *
+ * Umbrello UML Modeller Authors <uml-devel@uml.sf.net> *
+ ***************************************************************************/
+
+#ifndef UMLVIEW_H
+#define UMLVIEW_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+// system includes
+#include <kurl.h>
+#include <qdom.h>
+#include <qcanvas.h>
+
+//local includes
+#include "umlobjectlist.h"
+#include "umlwidgetlist.h"
+#include "associationwidgetlist.h"
+#include "messagewidgetlist.h"
+#include "optionstate.h"
+#include "worktoolbar.h"
+
+// forward declarations
+class ClassOptionsPage;
+class IDChangeLog;
+class ListPopupMenu;
+class FloatingTextWidget;
+class ObjectWidget;
+class UMLFolder;
+class UMLApp;
+class UMLDoc;
+class UMLAttribute;
+class UMLCanvasObject;
+class UMLClassifier;
+class UMLViewImageExporter;
+
+class KPrinter;
+class ToolBarState;
+class ToolBarStateFactory;
+
+/**
+ * UMLView instances represent diagrams.
+ * The UMLApp instance manages a QWidgetStack of UMLView instances.
+ * The visible diagram is at the top of stack.
+ * The UMLView class inherits from QCanvasView and it owns the
+ * objects displayed on its related QCanvas (see m_WidgetList.)
+ *
+ * @author Paul Hensgen <phensgen@techie.com>
+ * Bugs and comments to uml-devel@lists.sf.net or http://bugs.kde.org
+ */
+class UMLView : public QCanvasView {
+ Q_OBJECT
+public:
+ friend class UMLViewImageExporterModel;
+
+ /**
+ * Constructor
+ */
+ UMLView(UMLFolder *parentFolder);
+
+ /**
+ * Destructor
+ */
+ virtual ~UMLView();
+
+ // Accessors and other methods dealing with loaded/saved data
+
+ /**
+ * Return the UMLFolder in which this diagram lives.
+ */
+ UMLFolder *getFolder() {
+ return m_pFolder;
+ }
+
+ /**
+ * Set the UMLFolder in which this diagram lives.
+ */
+ void setFolder(UMLFolder *folder) {
+ m_pFolder = folder;
+ }
+
+ /**
+ * Return the documentation of the diagram.
+ */
+ QString getDoc() const {
+ return m_Documentation;
+ }
+
+ /**
+ * Set the documentation of the diagram.
+ */
+ void setDoc( const QString &doc ) {
+ m_Documentation = doc;
+ }
+
+ /**
+ * Return the name of the diagram.
+ */
+ QString getName() const;
+
+ /**
+ * Set the name of the diagram.
+ */
+ void setName(const QString &name);
+
+ /**
+ * Returns the type of the diagram.
+ */
+ Uml::Diagram_Type getType() const {
+ return m_Type;
+ }
+
+ /**
+ * Set the type of diagram.
+ */
+ void setType( Uml::Diagram_Type type ) {
+ m_Type = type;
+ }
+
+ /**
+ * Returns the fill color to use.
+ */
+ QColor getFillColor() const;
+
+ /**
+ * Set the background color.
+ *
+ * @param color The color to use.
+ */
+ void setFillColor( const QColor &color );
+
+ /**
+ * Returns the line color to use.
+ */
+ QColor getLineColor() const;
+
+ /**
+ * Sets the line color.
+ *
+ * @param color The color to use.
+ */
+ void setLineColor( const QColor &color );
+
+ /**
+ * Returns the line width to use.
+ */
+ uint getLineWidth() const;
+
+ /**
+ * Sets the line width.
+ *
+ * @param width The width to use.
+ */
+ void setLineWidth( uint width );
+
+ /**
+ * Returns the ID of the diagram.
+ */
+ Uml::IDType getID() const {
+ return m_nID;
+ }
+
+ /**
+ * Sets the ID of the diagram.
+ */
+ void setID( Uml::IDType id ) {
+ m_nID = id;
+ }
+
+ /**
+ * Returns the zoom of the diagram.
+ */
+ int getZoom() const {
+ return m_nZoom;
+ }
+
+ /**
+ * Sets the zoom of the diagram.
+ */
+ void setZoom(int zoom);
+
+ /**
+ * Returns the height of the diagram.
+ */
+ int getCanvasHeight() const {
+ return m_nCanvasHeight;
+ }
+
+ /**
+ * Sets the height of the diagram.
+ */
+ void setCanvasHeight(int height) {
+ m_nCanvasHeight = height;
+ }
+
+ /**
+ * Returns the width of the diagram.
+ */
+ int getCanvasWidth() const {
+ return m_nCanvasWidth;
+ }
+
+ /**
+ * Sets the height of the diagram.
+ */
+ void setCanvasWidth(int width) {
+ m_nCanvasWidth = width;
+ }
+
+ /**
+ * Return whether to use snap to grid.
+ */
+ bool getSnapToGrid() const {
+ return m_bUseSnapToGrid;
+ }
+
+ /**
+ * Sets whether to snap to grid.
+ */
+ void setSnapToGrid( bool bSnap );
+
+ /**
+ * Return whether to use snap to grid for component size.
+ */
+ bool getSnapComponentSizeToGrid() const {
+ return m_bUseSnapComponentSizeToGrid;
+ }
+
+ /**
+ * Returns the x grid size.
+ */
+ int getSnapX() const {
+ return m_nSnapX;
+ }
+
+ /**
+ * Returns the y grid size.
+ */
+ int getSnapY() const {
+ return m_nSnapY;
+ }
+
+ /**
+ * Returns the input coordinate with possible grid-snap applied.
+ */
+ int snappedX(int x);
+
+ /**
+ * Returns the input coordinate with possible grid-snap applied.
+ */
+ int snappedY(int y);
+
+ /**
+ * Returns whether to show snap grid or not.
+ */
+ bool getShowSnapGrid() const;
+
+ /**
+ * Sets whether to show snap grid.
+ */
+ void setShowSnapGrid( bool bShow );
+
+ /**
+ * Sets whether to snap to grid for component size.
+ */
+ void setSnapComponentSizeToGrid( bool bSnap );
+
+ /**
+ * Returns whether to use the fill/background color
+ */
+ bool getUseFillColor() const;
+
+ /**
+ * Sets whether to use the fill/background color
+ */
+ void setUseFillColor(bool ufc);
+
+ /**
+ * Returns the font to use
+ */
+ QFont getFont() const;
+
+ /**
+ * Sets the font for the view and optionally all the widgets on the view.
+ */
+ void setFont(QFont font, bool changeAllWidgets = false);
+
+ /**
+ * Returns whether to show operation signatures.
+ */
+ bool getShowOpSig() const;
+
+ /**
+ * Sets whether to show operation signatures.
+ */
+ void setShowOpSig(bool bShowOpSig);
+
+ /**
+ * Returns the options being used.
+ */
+ const Settings::OptionState& getOptionState() const {
+ return m_Options;
+ }
+
+ /**
+ * Sets the options to be used.
+ */
+ void setOptionState( const Settings::OptionState& options) {
+ m_Options = options;
+ }
+
+ /**
+ * Returns a reference to the association list.
+ */
+ AssociationWidgetList& getAssociationList() {
+ return m_AssociationList;
+ }
+
+ /**
+ * Returns a reference to the widget list.
+ */
+ UMLWidgetList& getWidgetList() {
+ return m_WidgetList;
+ }
+
+ /**
+ * Returns a reference to the message list.
+ */
+ MessageWidgetList& getMessageList() {
+ return m_MessageList;
+ }
+
+ // End of accessors and methods that only deal with loaded/saved data
+ ////////////////////////////////////////////////////////////////////////
+
+ /**
+ * return the current zoom factor
+ */
+ int currentZoom();
+
+ /**
+ * contains the implementation for printing functionality
+ */
+ void print(KPrinter *pPrinter, QPainter & pPainter);
+
+ /**
+ * Overrides the standard operation.
+ */
+ void hideEvent(QHideEvent *he);
+
+ /**
+ * Overrides the standard operation.
+ */
+ void showEvent(QShowEvent *se);
+
+ /**
+ * Sees if a message is relevant to the given widget. If it does delete it.
+ * @param w The widget to check messages against.
+ */
+ void checkMessages(ObjectWidget * w);
+
+ /**
+ * Finds a widget with the given ID.
+ *
+ * @param id The ID of the widget to find.
+ *
+ * @return Returns the widget found, returns 0 if no widget found.
+ */
+ UMLWidget * findWidget(Uml::IDType id);
+
+ /**
+ * Finds an association widget with the given ID.
+ *
+ * @param id The ID of the widget to find.
+ *
+ * @return Returns the widget found, returns 0 if no widget found.
+ */
+ AssociationWidget * findAssocWidget(Uml::IDType id);
+
+ /**
+ * Finds an association widget with the given type and widgets.
+ *
+ * @param at The Association_Type of the widget to find.
+ * @param pWidgetA Pointer to the UMLWidget of role A.
+ * @param pWidgetB Pointer to the UMLWidget of role B.
+ *
+ * @return Returns the widget found, returns 0 if no widget found.
+ */
+ AssociationWidget * findAssocWidget(Uml::Association_Type at,
+ UMLWidget *pWidgetA, UMLWidget *pWidgetB);
+
+ /**
+ * Finds an association widget with the given widgets and the given role B name.
+ * Considers the following association types:
+ * at_Association, at_UniAssociation, at_Composition, at_Aggregation
+ * This is used for seeking an attribute association.
+ *
+ * @param pWidgetA Pointer to the UMLWidget of role A.
+ * @param pWidgetB Pointer to the UMLWidget of role B.
+ * @param roleNameB Name at the B side of the association (the attribute name)
+ *
+ * @return Returns the widget found, returns 0 if no widget found.
+ */
+ AssociationWidget * findAssocWidget(UMLWidget *pWidgetA,
+ UMLWidget *pWidgetB, const QString& roleNameB);
+
+ /**
+ * Remove a widget from view.
+ *
+ * @param o The widget to remove.
+ */
+ void removeWidget(UMLWidget * o);
+
+ /**
+ * Sets a widget to a selected state and adds it to a list of selected widgets.
+ *
+ * @param w The widget to set to selected.
+ * @param me The mouse event containing the information about the selection.
+ */
+ void setSelected(UMLWidget * w, QMouseEvent * me);
+
+ /**
+ * Clear the selected widgets list.
+ */
+ void clearSelected();
+
+ /**
+ * Move all the selected widgets by a relative X and Y offset.
+ *
+ * @param dX The distance to move horizontally.
+ * @param dY The distance to move vertically.
+ */
+ void moveSelectedBy(int dX, int dY);
+
+ /**
+ * Return the amount of widgets selected.
+ *
+ * @param filterText When true, do NOT count floating text widgets that
+ * belong to other widgets (i.e. only count tr_Floating.)
+ * Default: Count all widgets.
+ * @return Number of widgets selected.
+ */
+ int getSelectCount(bool filterText = false) const;
+
+ /**
+ * Set the useFillColor variable to all selected widgets
+ *
+ * @param useFC The state to set the widget to.
+ */
+ void selectionUseFillColor(bool useFC);
+
+ /**
+ * Set the font for all the currently selected items.
+ */
+ void selectionSetFont( const QFont &font );
+
+ /**
+ * Set the line color for all the currently selected items.
+ */
+ void selectionSetLineColor( const QColor &color );
+
+ /**
+ * Set the line width for all the currently selected items.
+ */
+ void selectionSetLineWidth( uint width );
+
+ /**
+ * Set the fill color for all the currently selected items.
+ */
+ void selectionSetFillColor( const QColor &color );
+
+ /**
+ * Toggles the show setting sel of all selected items.
+ */
+ void selectionToggleShow(int sel);
+
+ /**
+ * Delete the selected widgets list and the widgets in it.
+ */
+ void deleteSelection();
+
+ /**
+ * Selects all widgets
+ */
+ void selectAll();
+
+ /**
+ * Return a unique ID for the diagram. Used by the @ref ObjectWidget class.
+ *
+ * @return Return a unique ID for the diagram.
+ */
+ Uml::IDType getLocalID();
+
+ /**
+ * Returns whether a widget is already on the diagram.
+ *
+ * @param id The id of the widget to check for.
+ *
+ * @return Returns true if the widget is already on the diagram, false if not.
+ */
+ bool widgetOnDiagram(Uml::IDType id);
+
+ /**
+ * Returns true if this diagram resides in an externalized folder.
+ * CHECK: It is probably cleaner to move this to the UMLListViewItem.
+ */
+ bool isSavedInSeparateFile();
+
+ /**
+ * Get the pos variable. Used internally to keep track of the cursor.
+ */
+ QPoint & getPos() {
+ return m_Pos;
+ }
+
+ /**
+ * Set the pos variable. Used internally to keep track of the cursor.
+ *
+ * @param _pos The position to set to.
+ */
+ void setPos(const QPoint &_pos) {
+ m_Pos = _pos;
+ }
+
+ /**
+ * Sets the popup menu to use when clicking on a diagram background
+ * (rather than a widget or listView).
+ */
+ void setMenu();
+
+ /**
+ * Reset the toolbar.
+ */
+ void resetToolbar() {
+ emit sigResetToolBar();
+ }
+
+ /**
+ * Returns the status on whether in a paste state.
+ *
+ * @return Returns the status on whether in a paste state.
+ */
+ bool getPaste() const {
+ return m_bPaste;
+ }
+
+ /**
+ * Sets the status on whether in a paste state.
+ */
+ void setPaste(bool paste) {
+ m_bPaste = paste;
+ }
+
+ /**
+ * Returns a List of all the UMLObjects(Use Cases, Concepts and Actors) in the View
+ */
+ UMLObjectList getUMLObjects();
+
+ /**
+ * Activate all the objects and associations after a load from the clipboard
+ */
+ void activate();
+
+ /**
+ * Returns a list with all the selected associations from the diagram
+ */
+ AssociationWidgetList getSelectedAssocs();
+
+ /**
+ * Fills the List with all the selected widgets from the diagram
+ * The list can be filled with all the selected widgets, or be filtered to prevent
+ * text widgets other than tr_Floating to be append.
+ *
+ * @param WidgetList The UMLWidgetList to fill.
+ * @param filterText Don't append the text, unless their role is tr_Floating
+ */
+ bool getSelectedWidgets(UMLWidgetList& WidgetList, bool filterText = true);
+
+ /**
+ * Activate the view after a load a new file
+ */
+ void activateAfterLoad( bool bUseLog = false );
+
+ void endPartialWidgetPaste();
+ void beginPartialWidgetPaste();
+
+ /**
+ * Removes a AssociationWidget from a diagram
+ * Physically deletes the AssociationWidget passed in.
+ *
+ * @param pAssoc Pointer to the AssociationWidget.
+ */
+ void removeAssoc(AssociationWidget* pAssoc);
+
+ /**
+ * Removes all the associations related to Widget
+ *
+ * @param pWidget Pointer to the widget to remove.
+ */
+ void removeAssociations(UMLWidget* pWidget);
+
+ /**
+ * Sets each association as selected if the widgets it associates are selected
+ */
+ void selectAssociations(bool bSelect);
+
+ /**
+ * Fills Associations with all the associations that includes a widget related to object
+ */
+ void getWidgetAssocs(UMLObject* Obj, AssociationWidgetList & Associations);
+
+ /**
+ * Removes All the associations of the diagram
+ */
+ void removeAllAssociations();
+
+ /**
+ * Removes All the widgets of the diagram
+ */
+ void removeAllWidgets();
+
+ /**
+ * Calls the same method in the DocWindow.
+ */
+ void showDocumentation( UMLObject * object, bool overwrite );
+
+ /**
+ * Calls the same method in the DocWindow.
+ */
+ void showDocumentation( UMLWidget * widget, bool overwrite );
+
+ /**
+ * Calls the same method in the DocWindow.
+ */
+ void showDocumentation( AssociationWidget * widget, bool overwrite );
+
+ /**
+ * Calls the same method in the DocWindow.
+ */
+ void updateDocumentation( bool clear );
+
+ /**
+ * Returns the PNG picture of the paste operation.
+ *
+ * @param rect the area of the diagram to copy
+ * @param diagram the class to store PNG picture of the paste operation.
+ */
+ void getDiagram(const QRect &rect, QPixmap & diagram);
+
+ /**
+ * Paint diagram to the paint device
+ */
+ void getDiagram(const QRect &area, QPainter & painter);
+
+ /**
+ * Returns the PNG picture of the paste operation.
+ */
+ void copyAsImage(QPixmap*& pix);
+
+ /**
+ * Returns the imageExporter used to export the view.
+ *
+ * @return The imageExporter used to export the view.
+ */
+ UMLViewImageExporter* getImageExporter();
+
+ /**
+ * Adds an association to the view from the given data.
+ * Use this method when pasting.
+ */
+ bool addAssociation( AssociationWidget* pAssoc , bool isPasteOperation = false);
+
+ /**
+ * Removes an AssociationWidget from the association list
+ * and removes the corresponding UMLAssociation from the current UMLDoc.
+ */
+ void removeAssocInViewAndDoc(AssociationWidget* assoc);
+
+ /**
+ * Adds a widget to the view from the given data.
+ * Use this method when pasting.
+ */
+ bool addWidget( UMLWidget * pWidget , bool isPasteOperation = false);
+
+ /**
+ * Returns the offset point at which to place the paste from clipboard.
+ * Just add the amount to your co-ords.
+ * Only call this straight after the event, the value won't stay valid.
+ * Should only be called by Assoc widgets at the moment. no one else needs it.
+ */
+ QPoint getPastePoint();
+
+ /**
+ * Reset the paste point.
+ */
+ void resetPastePoint();
+
+ /**
+ * Called by the view or any of its children when they start a cut
+ * operation.
+ */
+ void setStartedCut() {
+ m_bStartedCut = true;
+ }
+
+ /**
+ * Creates automatically any Associations that the given @ref UMLWidget
+ * may have on any diagram. This method is used when you just add the UMLWidget
+ * to a diagram.
+ */
+ void createAutoAssociations( UMLWidget * widget );
+
+ /**
+ * If the m_Type of the given widget is Uml::wt_Class then
+ * iterate through the class' attributes and create an
+ * association to each attribute type widget that is present
+ * on the current diagram.
+ */
+ void createAutoAttributeAssociations(UMLWidget *widget);
+
+ /**
+ * Refreshes containment association, i.e. removes possible old
+ * containment and adds new containment association if applicable.
+ *
+ * @param self Pointer to the contained object for which
+ * the association to the containing object is
+ * recomputed.
+ */
+ void updateContainment(UMLCanvasObject *self);
+
+ /**
+ * Sets the x grid size.
+ */
+ void setSnapX( int x) {
+ m_nSnapX = x;
+ canvas() -> setAllChanged();
+ }
+
+ /**
+ * Sets the y grid size.
+ */
+ void setSnapY( int y) {
+ m_nSnapY = y;
+ canvas() -> setAllChanged();
+ }
+
+ /**
+ * Shows the properties dialog for the view.
+ */
+ bool showPropDialog();
+
+ /**
+ * Sets some options for all the @ref ClassifierWidget on the view.
+ */
+ void setClassWidgetOptions( ClassOptionsPage * page );
+
+ /**
+ * Call before copying/cutting selected widgets. This will make sure
+ * any associations/message selected will make sure both the widgets
+ * widgets they are connected to are selected.
+ */
+ void checkSelections();
+
+ /**
+ * This function checks if the currently selected items have all the same
+ * type (class, interface, ...). If true, the selection is unique and true
+ * will be returned.
+ * If there are no items selected, the function will return always true.
+ */
+ bool checkUniqueSelection();
+
+ /**
+ * Asks for confirmation and clears everything on the diagram.
+ * Called from menus.
+ */
+ void clearDiagram();
+
+ /**
+ * Changes snap to grid boolean.
+ * Called from menus.
+ */
+ void toggleSnapToGrid();
+
+ /**
+ * Changes snap to grid for component size boolean.
+ * Called from menus.
+ */
+ void toggleSnapComponentSizeToGrid();
+
+ /**
+ * Changes show grid boolean.
+ * Called from menus.
+ */
+ void toggleShowGrid();
+
+ /**
+ * Changes the zoom to the currently set level (now loaded from file)
+ * Called from UMLApp::slotUpdateViews()
+ */
+ void fileLoaded();
+
+ /**
+ * Sets the diagram width and height in pixels
+ */
+ void setCanvasSize(int width, int height);
+
+ /**
+ * Sets the size of the canvas to just fit on all the items
+ */
+ void resizeCanvasToItems();
+
+ /**
+ * The width and height of a diagram canvas in pixels.
+ */
+ static const int defaultCanvasSize;
+
+ // Load/Save interface:
+
+ /**
+ * Creates the "diagram" tag and fills it with the contents of the diagram.
+ */
+ virtual void saveToXMI( QDomDocument & qDoc, QDomElement & qElement );
+
+ /**
+ * Loads the "diagram" tag.
+ */
+ virtual bool loadFromXMI( QDomElement & qElement );
+
+ /**
+ * Loads the "UISDiagram" tag of Unisys.IntegratePlus.2 generated files.
+ */
+ bool loadUISDiagram(QDomElement & qElement);
+
+ /**
+ * Loads a "widget" element from XMI, used by loadFromXMI() and the clipboard.
+ */
+ UMLWidget* loadWidgetFromXMI(QDomElement& widgetElement);
+
+ /**
+ * Add an object to the application, and update the view.
+ */
+ void addObject(UMLObject *object);
+
+ /**
+ * Selects all the widgets within an internally kept rectangle.
+ */
+ void selectWidgets(int px, int py, int qx, int qy);
+
+ /**
+ * Determine whether on a sequence diagram we have clicked on a line
+ * of an Object.
+ *
+ * @return The widget thats line was clicked on.
+ * Returns 0 if no line was clicked on.
+ */
+ ObjectWidget * onWidgetLine( const QPoint &point );
+
+ /**
+ * Return pointer to the first selected widget (for multi-selection)
+ */
+ UMLWidget* getFirstMultiSelectedWidget() {
+ return m_SelectedList.first();
+ }
+
+ /**
+ * Tests the given point against all widgets and returns the
+ * widget for which the point is within its bounding rectangle.
+ * In case of multiple matches, returns the smallest widget.
+ * Returns NULL if the point is not inside any widget.
+ * Does not use or modify the m_pOnWidget member.
+ */
+ UMLWidget *getWidgetAt(const QPoint& p);
+
+ /**
+ * Initialize and announce a newly created widget.
+ * Auxiliary to contentsMouseReleaseEvent().
+ */
+ void setupNewWidget(UMLWidget *w);
+
+ /**
+ * Return whether we are currently creating an object.
+ */
+ bool getCreateObject() const {
+ return m_bCreateObject;
+ }
+
+ /**
+ * Set whether we are currently creating an object.
+ */
+ void setCreateObject(bool bCreate) {
+ m_bCreateObject = bCreate;
+ }
+
+ /**
+ * Emit the sigRemovePopupMenu Qt signal.
+ */
+ void emitRemovePopupMenu() {
+ emit sigRemovePopupMenu();
+ }
+
+ /**
+ * Used for creating unique name of collaboration messages.
+ */
+ int generateCollaborationId();
+
+protected:
+
+ // Methods and members related to loading/saving
+
+ bool loadWidgetsFromXMI( QDomElement & qElement );
+
+ bool loadMessagesFromXMI( QDomElement & qElement );
+
+ bool loadAssociationsFromXMI( QDomElement & qElement );
+
+ bool loadUisDiagramPresentation(QDomElement & qElement);
+
+ /**
+ * Contains the unique ID to allocate to a widget that needs an
+ * ID for the view. @ref ObjectWidget is an example of this.
+ */
+ Uml::IDType m_nLocalID;
+
+ /**
+ * The ID of the view. Allocated by @ref UMLDoc
+ */
+ Uml::IDType m_nID;
+
+ /**
+ * The type of diagram to represent.
+ */
+ Uml::Diagram_Type m_Type;
+
+ /**
+ * The name of the diagram.
+ */
+ QString m_Name;
+
+ /**
+ * The documentation of the diagram.
+ */
+ QString m_Documentation;
+
+ /**
+ * Options used by view
+ */
+ Settings::OptionState m_Options;
+
+ /**
+ * Contains all the message widgets on the diagram.
+ */
+ MessageWidgetList m_MessageList;
+
+ /**
+ * Contains all the UMLWidgets on the diagram.
+ */
+ UMLWidgetList m_WidgetList;
+
+ /**
+ * Contains all the AssociationWidgets on the diagram.
+ */
+ AssociationWidgetList m_AssociationList;
+
+ /**
+ * The snap to grid x size.
+ */
+ int m_nSnapX;
+
+ /**
+ * The snap to grid y size.
+ */
+ int m_nSnapY;
+
+ /**
+ * Determines whether to use snap to grid. The default is off.
+ */
+ bool m_bUseSnapToGrid;
+
+ /**
+ * Determines whether to use snap to grid for component
+ * size. The default is off.
+ */
+ bool m_bUseSnapComponentSizeToGrid;
+
+ /**
+ * Determines whether to show the snap grid. The default will be on if the grid is on.
+ */
+ bool m_bShowSnapGrid;
+
+ /**
+ * The zoom level in percent, default 100
+ */
+ int m_nZoom;
+
+ /**
+ * Width of canvas in pixels
+ */
+ int m_nCanvasWidth;
+
+ /**
+ * Height of canvas in pixels
+ */
+ int m_nCanvasHeight;
+
+ // End of methods and members related to loading/saving
+ ////////////////////////////////////////////////////////////////////////
+
+ /**
+ * Override standard method.
+ */
+ void closeEvent ( QCloseEvent * e );
+
+ /**
+ * Override standard method.
+ */
+ void contentsDragEnterEvent(QDragEnterEvent* mouseEvent);
+
+ /**
+ * Override standard method.
+ */
+ void contentsDropEvent(QDropEvent* mouseEvent);
+
+
+ /**
+ * Gets the smallest area to print.
+ *
+ * @return Returns the smallest area to print.
+ */
+ QRect getDiagramRect();
+
+
+ /**
+ * Initializes key variables.
+ */
+ void init();
+
+ /**
+ * Overrides the standard operation.
+ * Calls the same method in the current tool bar state.
+ */
+ void contentsMouseReleaseEvent(QMouseEvent* mouseEvent);
+
+ /**
+ * Overrides the standard operation.
+ * Calls the same method in the current tool bar state.
+ */
+ void contentsMouseMoveEvent(QMouseEvent* mouseEvent);
+
+ /**
+ * Override standard method.
+ * Calls the same method in the current tool bar state.
+ */
+ void contentsMouseDoubleClickEvent(QMouseEvent* mouseEvent);
+
+ /**
+ * Override standard method.
+ * Calls the same method in the current tool bar state.
+ */
+ void contentsMousePressEvent(QMouseEvent* mouseEvent);
+
+
+ /**
+ * Selects all the widgets of the given association widget.
+ */
+ void selectWidgetsOfAssoc (AssociationWidget * a);
+
+ /**
+ * Calls setSelected on the given UMLWidget and enters
+ * it into the m_SelectedList while making sure it is
+ * there only once.
+ */
+ void makeSelected (UMLWidget * uw);
+
+ /**
+ * Updates the size of all components in this view.
+ */
+ void updateComponentSizes();
+
+ /**
+ * Find the maximum bounding rectangle of FloatingTextWidget widgets.
+ * Auxiliary to copyAsImage().
+ *
+ * @param ft Pointer to the FloatingTextWidget widget to consider.
+ * @param px X coordinate of lower left corner. This value will be
+ * updated if the X coordinate of the lower left corner
+ * of ft is smaller than the px value passed in.
+ * @param py Y coordinate of lower left corner. This value will be
+ * updated if the Y coordinate of the lower left corner
+ * of ft is smaller than the py value passed in.
+ * @param qx X coordinate of upper right corner. This value will be
+ * updated if the X coordinate of the upper right corner
+ * of ft is larger than the qx value passed in.
+ * @param qy Y coordinate of upper right corner. This value will be
+ * updated if the Y coordinate of the upper right corner
+ * of ft is larger than the qy value passed in.
+ */
+ void findMaxBoundingRectangle(const FloatingTextWidget* ft,
+ int& px, int& py, int& qx, int& qy);
+
+ void forceUpdateWidgetFontMetrics(QPainter *painter);
+
+ /**
+ * Used for creating unique name of collaboration messages.
+ */
+ int m_nCollaborationId;
+
+ QPoint m_Pos;
+ bool m_bCreateObject, m_bDrawSelectedOnly, m_bPaste;
+ ListPopupMenu * m_pMenu;
+ UMLWidgetList m_SelectedList;
+
+ /**
+ * Flag if view/children started cut operation.
+ */
+ bool m_bStartedCut;
+
+private:
+ /**
+ * The folder in which this UMLView is contained
+ */
+ UMLFolder *m_pFolder;
+
+ /**
+ * set to true when a child has used the showDocumentation method,
+ * thus when one clicks on a child widget.
+ * Reset to false when clicking in an empty region of the view.
+ */
+ bool m_bChildDisplayedDoc;
+
+ ToolBarStateFactory* m_pToolBarStateFactory;
+ ToolBarState* m_pToolBarState;
+
+ /**
+ * LocalID Changes Log for paste actions
+ */
+ IDChangeLog * m_pIDChangesLog;
+
+ /**
+ *
+ * True if the view was activated after the serialization(load)
+ */
+ bool m_bActivated;
+
+ /**
+ * Status of a popupmenu on view.
+ * true - a popup is on view
+ */
+ bool m_bPopupShowing;
+
+ /**
+ * The offset at which to paste the clipboard.
+ */
+ QPoint m_PastePoint;
+
+ /**
+ * Pointer to the UMLDoc
+ */
+ UMLDoc* m_pDoc;
+
+ /**
+ * The UMLViewImageExporter used to export the view.
+ */
+ UMLViewImageExporter* m_pImageExporter;
+
+ /**
+ * Create an association with the attribute attr associated with the UMLWidget
+ * widget if the UMLClassifier type is present on the current diagram.
+ */
+ void createAutoAttributeAssociation(UMLClassifier *type,
+ UMLAttribute *attr,
+ UMLWidget *widget);
+
+public slots:
+
+ void zoomIn();
+ void zoomOut();
+
+ /**
+ * Changes the current tool to the selected tool.
+ * The current tool is cleaned and the selected tool initialized.
+ */
+ void slotToolBarChanged(int c);
+ void slotObjectCreated(UMLObject * o);
+ void slotObjectRemoved(UMLObject * o);
+
+ /**
+ * When a menu selection has been made on the menu
+ * that this view created, this method gets called.
+ */
+ void slotMenuSelection(int sel);
+
+ /**
+ * This slot is entered when an event has occurred on the views display,
+ * most likely a mouse event. Before it sends out that mouse event everyone
+ * that displays a menu on the views surface (widgets and this ) thould remove any
+ * menu. This stops more then one menu bieing displayed.
+ */
+ void slotRemovePopupMenu();
+
+ /**
+ * makes this view the active view by asking the document to show us
+ */
+ void slotActivate();
+
+ /**
+ * Connects to the signal that @ref UMLApp emits when a cut operation
+ * is successful.
+ * If the view or a child started the operation the flag m_bStartedCut will
+ * be set and we can carry out any operation that is needed, like deleting the selected
+ * widgets for the cut operation.
+ */
+ void slotCutSuccessful();
+
+ /**
+ * Called by menu when to show the instance of the view.
+ */
+ void slotShowView();
+
+ /**
+ * Overrides standard method from QWidget to resize canvas when
+ * it's shown.
+ */
+ void show();
+
+signals:
+ void sigResetToolBar();
+ void sigColorChanged( Uml::IDType );
+ void sigRemovePopupMenu();
+ void sigClearAllSelected();
+ void sigLineWidthChanged( Uml::IDType );
+ void sigSnapToGridToggled(bool);
+ void sigSnapComponentSizeToGridToggled(bool);
+ void sigShowGridToggled(bool);
+
+ /**
+ * Emitted when an association is removed.
+ */
+ void sigAssociationRemoved(AssociationWidget*);
+
+ /**
+ * Emitted when a widget is removed.
+ */
+ void sigWidgetRemoved(UMLWidget*);
+};
+
+#endif // UMLVIEW_H
diff --git a/umbrello/umbrello/umlviewcanvas.cpp b/umbrello/umbrello/umlviewcanvas.cpp
new file mode 100644
index 00000000..15de4169
--- /dev/null
+++ b/umbrello/umbrello/umlviewcanvas.cpp
@@ -0,0 +1,41 @@
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * copyright (C) 2002-2007 *
+ * Umbrello UML Modeller Authors <uml-devel@uml.sf.net> *
+ ***************************************************************************/
+
+// own header
+#include "umlviewcanvas.h"
+
+// qt/kde includes
+#include <qpainter.h>
+
+// app includes
+#include "umlview.h"
+
+
+UMLViewCanvas::UMLViewCanvas( UMLView * pView ) : QCanvas( pView ) {
+ m_pView = pView;
+}
+
+UMLViewCanvas::~UMLViewCanvas() {}
+
+void UMLViewCanvas::drawBackground( QPainter & painter, const QRect & clip ) {
+ QCanvas::drawBackground( painter, clip );
+ if( m_pView -> getShowSnapGrid() ) {
+ painter.setPen( Qt::gray );
+ int gridX = m_pView -> getSnapX();
+ int gridY = m_pView -> getSnapY();
+ int numX = width() / gridX;
+ int numY = height() / gridY;
+ for( int x = 0; x <= numX; x++ )
+ for( int y = 0; y < numY; y++ )
+ painter.drawPoint( x * gridX, y * gridY );
+ }
+}
+
diff --git a/umbrello/umbrello/umlviewcanvas.h b/umbrello/umbrello/umlviewcanvas.h
new file mode 100644
index 00000000..78d7d4dd
--- /dev/null
+++ b/umbrello/umbrello/umlviewcanvas.h
@@ -0,0 +1,48 @@
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * copyright (C) 2002-2006 *
+ * Umbrello UML Modeller Authors <uml-devel@uml.sf.net> *
+ ***************************************************************************/
+
+#ifndef UMLVIEWCANVAS_H
+#define UMLVIEWCANVAS_H
+
+#include <qcanvas.h>
+
+/**
+ *@author Paul Hensgen
+ * Bugs and comments to uml-devel@lists.sf.net or http://bugs.kde.org
+ */
+class UMLView;
+
+class UMLViewCanvas : public QCanvas {
+public:
+ /**
+ * Constructor
+ */
+ UMLViewCanvas( UMLView * pView );
+
+ /**
+ * Deconstructor
+ */
+ virtual ~UMLViewCanvas();
+
+protected:
+
+ /**
+ * Overrides default method.
+ */
+ virtual void drawBackground( QPainter & painter, const QRect & clip );
+
+ /**
+ * The view the canvas is associated with.
+ */
+ UMLView * m_pView;
+};
+
+#endif
diff --git a/umbrello/umbrello/umlviewimageexporter.cpp b/umbrello/umbrello/umlviewimageexporter.cpp
new file mode 100644
index 00000000..251d0ffb
--- /dev/null
+++ b/umbrello/umbrello/umlviewimageexporter.cpp
@@ -0,0 +1,128 @@
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * copyright (C) 2006-2007 *
+ * Umbrello UML Modeller Authors <uml-devel@uml.sf.net> *
+ ***************************************************************************/
+
+// own header
+#include "umlviewimageexporter.h"
+
+// include files for Qt
+#include <qstring.h>
+#include <qstringlist.h>
+
+//kde include files
+#include <klocale.h>
+#include <kfiledialog.h>
+#include <kurl.h>
+#include <kmessagebox.h>
+#include <kio/netaccess.h>
+
+// application specific includes
+#include "umlviewimageexportermodel.h"
+#include "uml.h"
+#include "umldoc.h"
+#include "umlview.h"
+
+
+UMLViewImageExporter::UMLViewImageExporter(UMLView* view) {
+ m_view = view;
+ m_imageMimeType = UMLApp::app()->getImageMimeType();
+}
+
+void UMLViewImageExporter::exportView() {
+ if (!prepareExportView()) {
+ return;
+ }
+
+ UMLApp *app = UMLApp::app();
+
+ // export the view
+ app->getDocument()->writeToStatusBar(i18n("Exporting view..."));
+ QString error = UMLViewImageExporterModel().exportView(m_view,
+ UMLViewImageExporterModel::mimeTypeToImageType(m_imageMimeType), m_imageURL);
+ if (!error.isNull()) {
+ KMessageBox::error(app, i18n("An error happened when exporting the image:\n") + error);
+ }
+ app->getDocument()->writeToStatusBar(i18n("Ready."));
+}
+
+bool UMLViewImageExporter::prepareExportView() {
+ bool exportPrepared = false;
+
+ do {
+ if (!getParametersFromUser()) {
+ return false;
+ }
+
+ // check if the file exists
+ if (KIO::NetAccess::exists(m_imageURL, true, UMLApp::app())) {
+ int wantSave = KMessageBox::warningContinueCancel(0,
+ i18n("The selected file %1 exists.\nDo you want to overwrite it?").arg(m_imageURL.prettyURL()),
+ i18n("File Already Exists"), i18n("&Overwrite"));
+ if (wantSave == KMessageBox::Continue) {
+ exportPrepared = true;
+ }
+ } else {
+ exportPrepared = true;
+ }
+ } while (!exportPrepared);
+
+ return true;
+}
+
+bool UMLViewImageExporter::getParametersFromUser() {
+ UMLApp *app = UMLApp::app();
+
+ // configure & show the file dialog
+ KFileDialog fileDialog(QString::null, QString::null, m_view,
+ ":export-image", true);
+ prepareFileDialog(fileDialog);
+ fileDialog.exec();
+
+ if (fileDialog.selectedURL().isEmpty())
+ return false;
+ m_view->clearSelected(); // Thanks to Peter Soetens for the idea
+
+ // update image url and mime type
+ m_imageMimeType = fileDialog.currentMimeFilter();
+ app->setImageMimeType(m_imageMimeType);
+ m_imageURL = fileDialog.selectedURL();
+
+ // check if the extension is the extension of the mime type
+ QFileInfo info(m_imageURL.filename());
+ QString ext = info.extension(false);
+ QString extDef = UMLViewImageExporterModel::mimeTypeToImageType(m_imageMimeType);
+ if(ext != extDef) {
+ m_imageURL.setFileName(m_imageURL.fileName() + '.' + extDef);
+ }
+
+ return true;
+}
+
+void UMLViewImageExporter::prepareFileDialog(KFileDialog &fileDialog) {
+ // get all supported mime types
+ QStringList mimeTypes = UMLViewImageExporterModel::supportedMimeTypes();
+
+ fileDialog.setCaption(i18n("Save As"));
+ fileDialog.setOperationMode(KFileDialog::Saving);
+ fileDialog.setMimeFilter(mimeTypes, m_imageMimeType);
+
+ // set a sensible default filename
+ if (m_imageURL.isEmpty()) {
+ KURL docURL = UMLApp::app()->getDocument()->URL();
+ KURL directory = docURL;
+ directory.setPath(docURL.directory());
+
+ fileDialog.setURL(directory);
+ fileDialog.setSelection(m_view->getName() + '.' + UMLViewImageExporterModel::mimeTypeToImageType(m_imageMimeType));
+ } else {
+ fileDialog.setURL(m_imageURL);
+ fileDialog.setSelection(m_imageURL.fileName());
+ }
+}
diff --git a/umbrello/umbrello/umlviewimageexporter.h b/umbrello/umbrello/umlviewimageexporter.h
new file mode 100644
index 00000000..2400213b
--- /dev/null
+++ b/umbrello/umbrello/umlviewimageexporter.h
@@ -0,0 +1,122 @@
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * copyright (C) 2006-2007 *
+ * Umbrello UML Modeller Authors <uml-devel@uml.sf.net> *
+ ***************************************************************************/
+
+#ifndef UMLVIEWIMAGEEXPORTER_H
+#define UMLVIEWIMAGEEXPORTER_H
+
+#include <qstring.h>
+#include <kurl.h>
+
+class UMLView;
+class KFileDialog;
+
+/**
+ * Exports the view as an image.
+ * This class takes care of asking the user the needed parameters and
+ * then exports the view.
+ */
+class UMLViewImageExporter {
+public:
+
+ /**
+ * Constructor for UMLViewImageExporter
+ */
+ UMLViewImageExporter(UMLView* view);
+
+ /**
+ * Destructor for UMLViewImageExporter
+ */
+ virtual ~UMLViewImageExporter() {
+ }
+
+ /**
+ * Shows a save dialog to the user to get the needed parameters and then exports
+ * the view.
+ * If the selected file already exists, an overwrite confirmation
+ * dialog is shown. If the user doesn't want to overwrite the file,
+ * the save dialog is shown again.
+ * The dialog remembers values between calls (in the same application instance,
+ * although it's not persistent between Umbrello executions).
+ *
+ * The status bar shows an information message until the export finishes.
+ *
+ * If something went wrong while exporting, an error dialog is shown to the
+ * user with the error message explaining the problem that happened.
+ */
+ void exportView();
+
+ /**
+ * Returns the URL used to save the image.
+ *
+ * @return The URL used to save the image.
+ */
+ KURL getImageURL() const {
+ return m_imageURL;
+ }
+
+ /**
+ * Returns the mime type used to save the image.
+ *
+ * @return The mime type used to save the image.
+ */
+ QString getImageMimeType() const {
+ return m_imageMimeType;
+ }
+
+private:
+
+ /**
+ * The view to export.
+ */
+ UMLView* m_view;
+
+ /**
+ * The URL used to save the image.
+ */
+ KURL m_imageURL;
+
+ /**
+ * The mime type used to save the image.
+ */
+ QString m_imageMimeType;
+
+ /**
+ * Shows a save file dialog to the user to get the parameters used
+ * to export the view.
+ * If the selected file already exists, an overwrite confirmation
+ * dialog is shown. If the user doesn't want to overwrite the file,
+ * the save dialog is shown again.
+ *
+ * @return True if the user wants to save the image,
+ * false if the operation is cancelled.
+ */
+ bool prepareExportView();
+
+ /**
+ * Shows a save file dialog to the user to get the parameters used
+ * to export the view and updates the attributes with the parameters got.
+ *
+ * @return True if the user wants to save the image,
+ * false if the operation is cancelled.
+ */
+ bool getParametersFromUser();
+
+ /**
+ * Prepares the save file dialog.
+ * Sets the mime type filter, sensible default values...
+ *
+ * @param fileDialog The dialog to prepare.
+ */
+ void prepareFileDialog(KFileDialog &fileDialog);
+
+};
+
+#endif
diff --git a/umbrello/umbrello/umlviewimageexporterall.cpp b/umbrello/umbrello/umlviewimageexporterall.cpp
new file mode 100644
index 00000000..fceb6aa3
--- /dev/null
+++ b/umbrello/umbrello/umlviewimageexporterall.cpp
@@ -0,0 +1,74 @@
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * copyright (C) 2006-2007 *
+ * Umbrello UML Modeller Authors <uml-devel@uml.sf.net> *
+ ***************************************************************************/
+
+// own header
+#include "umlviewimageexporterall.h"
+
+// include files for Qt
+#include <qstring.h>
+#include <qstringlist.h>
+#include <qcheckbox.h>
+
+// kde include files
+#include <klocale.h>
+#include <kurl.h>
+#include <kurlrequester.h>
+#include <kfilefiltercombo.h>
+#include <kmessagebox.h>
+
+// application specific includes
+#include "dialogs/exportallviewsdialog.h"
+#include "umlviewimageexportermodel.h"
+#include "uml.h"
+#include "umldoc.h"
+
+UMLViewImageExporterAll::UMLViewImageExporterAll() {
+ m_dialog = new ExportAllViewsDialog(0, "exportAllViewsDialog", false, 0, UMLApp::app()->getImageMimeType());
+}
+
+UMLViewImageExporterAll::~UMLViewImageExporterAll() {
+ delete m_dialog;
+}
+
+void UMLViewImageExporterAll::exportAllViews() {
+ UMLApp* app = UMLApp::app();
+ UMLDoc* umlDoc = app->getDocument();
+
+ // default url can't be set when creating the action because the
+ // document wasn't loaded
+ if (m_dialog->m_kURL->url().isEmpty()) {
+ m_dialog->m_kURL->setURL(umlDoc->URL().directory());
+ }
+
+ if (m_dialog->exec() == QDialog::Rejected) {
+ return;
+ }
+
+ app->setImageMimeType(m_dialog->m_imageType->currentFilter());
+
+ // export all views
+ umlDoc->writeToStatusBar(i18n("Exporting all views..."));
+ QStringList errors = UMLViewImageExporterModel().exportAllViews(
+ UMLViewImageExporterModel::mimeTypeToImageType(m_dialog->m_imageType->currentFilter()),
+ KURL(m_dialog->m_kURL->url()), m_dialog->m_useFolders->isChecked());
+ if (!errors.empty()) {
+#if KDE_IS_VERSION(3,4,0)
+ KMessageBox::errorList(app, i18n("Some errors happened when exporting the images:"), errors);
+#else
+ QString errorsCaption;
+ for (QStringList::Iterator it = errors.begin(); it != errors.end(); ++it) {
+ errorsCaption += "\n" + *it;
+ }
+ KMessageBox::error(app, i18n("Some errors happened when exporting the images:") + errorsCaption);
+#endif
+ }
+ umlDoc->writeToStatusBar(i18n("Ready."));
+}
diff --git a/umbrello/umbrello/umlviewimageexporterall.h b/umbrello/umbrello/umlviewimageexporterall.h
new file mode 100644
index 00000000..d2368921
--- /dev/null
+++ b/umbrello/umbrello/umlviewimageexporterall.h
@@ -0,0 +1,58 @@
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * copyright (C) 2006-2007 *
+ * Umbrello UML Modeller Authors <uml-devel@uml.sf.net> *
+ ***************************************************************************/
+
+#ifndef UMLVIEWIMAGEEXPORTERALL_H
+#define UMLVIEWIMAGEEXPORTERALL_H
+
+class ExportAllViewsDialog;
+
+/**
+ * Exports all the views in the UML document as images.
+ * This class takes care of asking the user the needed parameters and
+ * then exports the views using UMLViewImageExporterModel.
+ */
+class UMLViewImageExporterAll {
+public:
+
+ /**
+ * Constructor for UMLViewImageExporterAll
+ */
+ UMLViewImageExporterAll();
+
+ /**
+ * Destructor for UMLViewImageExporterAll
+ */
+ virtual ~UMLViewImageExporterAll();
+
+ /**
+ * Shows a dialog to the user to get the needed parameters and then exports
+ * the views.
+ * The dialog remembers values between calls (in the same application instance,
+ * although it's not persistent between Umbrello executions).
+ *
+ * Once the export begins, it can't be stopped until it ends itself. The status
+ * bar shows an information message until the export finishes.
+ *
+ * If something went wrong while exporting, an error dialog is shown to the
+ * user with the error messages explaining the problems occurred.
+ */
+ void exportAllViews();
+
+private:
+
+ /**
+ * The dialog to get the needed parameters from the user.
+ */
+ ExportAllViewsDialog* m_dialog;
+
+};
+
+#endif
diff --git a/umbrello/umbrello/umlviewimageexportermodel.cpp b/umbrello/umbrello/umlviewimageexportermodel.cpp
new file mode 100644
index 00000000..e829a3f7
--- /dev/null
+++ b/umbrello/umbrello/umlviewimageexportermodel.cpp
@@ -0,0 +1,366 @@
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * copyright (C) 2006-2007 *
+ * Umbrello UML Modeller Authors <uml-devel@uml.sf.net> *
+ ***************************************************************************/
+
+// own header
+#include "umlviewimageexportermodel.h"
+
+// system includes
+#include <math.h>
+
+// include files for Qt
+#include <qstringlist.h>
+#include <qrect.h>
+#include <qimage.h>
+#include <qpicture.h>
+#include <qpainter.h>
+#include <qprinter.h>
+#include <qdir.h>
+#include <qregexp.h>
+
+// kde include files
+#include <kdebug.h>
+#include <klocale.h>
+#include <ktempfile.h>
+#include <kapplication.h>
+#include <kio/netaccess.h>
+
+// application specific includes
+#include "uml.h"
+#include "umldoc.h"
+#include "umlview.h"
+#include "umllistview.h"
+#include "umllistviewitem.h"
+
+static QStringList supportedImageTypesList;
+static QStringList supportedMimeTypesList;
+
+QStringList UMLViewImageExporterModel::supportedImageTypes() {
+ if (!supportedImageTypesList.size()) {
+ // specific supported formats
+ supportedImageTypesList << "eps";
+ supportedImageTypesList << "svg";
+
+ // QT supported formats
+ QStrList qImageFormats = QImage::outputFormats();
+ for (const char* format = qImageFormats.first(); format; format = qImageFormats.next()) {
+ supportedImageTypesList << QString(format).lower();
+ }
+ }
+
+ return supportedImageTypesList;
+}
+
+QStringList UMLViewImageExporterModel::supportedMimeTypes() {
+ if (!supportedMimeTypesList.size()) {
+ QStringList imageTypes = UMLViewImageExporterModel::supportedImageTypes();
+ for(QStringList::Iterator it = imageTypes.begin(); it != imageTypes.end(); ++it ) {
+ QString mimeType = imageTypeToMimeType(*it);
+ if (!mimeType.isNull())
+ supportedMimeTypesList.append(mimeType);
+ }
+ }
+
+ return supportedMimeTypesList;
+}
+
+QString UMLViewImageExporterModel::imageTypeToMimeType(const QString& imageType) {
+ const QString imgType = imageType.lower();
+ if (QString("bmp") == imgType) return "image/x-bmp";
+ if (QString("jpeg") == imgType) return "image/jpeg";
+ if (QString("pbm") == imgType) return "image/x-portable-bitmap";
+ if (QString("pgm") == imgType) return "image/x-portable-greymap";
+ if (QString("png") == imgType) return "image/png";
+ if (QString("ppm") == imgType) return "image/x-portable-pixmap";
+ if (QString("xbm") == imgType) return "image/x-xbm";
+ if (QString("xpm") == imgType) return "image/x-xpm";
+ if (QString("eps") == imgType) return "image/x-eps";
+ if (QString("svg") == imgType) return "image/svg+xml";
+ return QString::null;
+}
+
+QString UMLViewImageExporterModel::mimeTypeToImageType(const QString& mimeType) {
+ if (QString("image/x-bmp") == mimeType) return "bmp";
+ if (QString("image/jpeg") == mimeType) return "jpeg";
+ if (QString("image/x-portable-bitmap") == mimeType) return "pbm";
+ if (QString("image/x-portable-greymap") == mimeType) return "pgm";
+ if (QString("image/png") == mimeType) return "png";
+ if (QString("image/x-portable-pixmap") == mimeType) return "ppm";
+ if (QString("image/x-xbm") == mimeType) return "xbm";
+ if (QString("image/x-xpm") == mimeType) return "xpm";
+ if (QString("image/x-eps") == mimeType) return "eps";
+ if (QString("image/svg+xml") == mimeType) return "svg";
+ return QString::null;
+}
+
+QStringList UMLViewImageExporterModel::exportAllViews(const QString &imageType, const KURL &directory, bool useFolders) const {
+ UMLApp *app = UMLApp::app();
+
+ // contains all the error messages returned by exportView calls
+ QStringList errors;
+
+ UMLViewList views = app->getDocument()->getViewIterator();
+ for(UMLView *view = views.first(); view; view = views.next()) {
+ KURL url = directory;
+ url.addPath(getDiagramFileName(view, imageType, useFolders));
+
+ QString returnString = exportView(view, imageType, url);
+ if (!returnString.isNull()) {
+ errors.append(view->getName() + ": " + returnString);
+ }
+ }
+
+ return errors;
+}
+
+QString UMLViewImageExporterModel::exportView(UMLView* view, const QString &imageType, const KURL &url) const {
+ // create the needed directories
+ if (!prepareDirectory(url)) {
+ return i18n("Can not create directory: %1").arg(url.directory());
+ }
+
+ // The fileName will be used when exporting the image. If the url isn't local,
+ // the fileName is the name of a temporal local file to export the image to, and then
+ // upload it to its destiny
+ QString fileName;
+ // tmpFile needs to be unlinked before exiting the method!!!
+ KTempFile tmpFile;
+ if (url.isLocalFile()) {
+ fileName = url.path();
+ } else {
+ fileName = tmpFile.name();
+ }
+
+ // check that the diagram isn't empty
+ QRect rect = view->getDiagramRect();
+ if (rect.isEmpty()) {
+ tmpFile.unlink();
+ return i18n("Can not save an empty diagram");
+ }
+
+ // exporting the view to the file
+ if (!exportViewTo(view, imageType, fileName)) {
+ tmpFile.unlink();
+ return i18n("A problem occured while saving diagram in %1").arg(fileName);
+ }
+
+ // if the file wasn't local, upload the temp file to the target
+ if (!url.isLocalFile()) {
+ if (!KIO::NetAccess::upload(tmpFile.name(), url, UMLApp::app())) {
+ tmpFile.unlink();
+ return i18n("There was a problem saving file: %1").arg(url.path());
+ }
+ } //!isLocalFile
+
+ tmpFile.unlink();
+ return QString::null;
+}
+
+QString UMLViewImageExporterModel::getDiagramFileName(UMLView *view, const QString &imageType, bool useFolders /* = false */) const {
+ QString name = view->getName() + '.' + imageType.lower();
+
+ if (!useFolders) {
+ return name;
+ }
+
+ kapp->processEvents();
+ UMLListView *listView = UMLApp::app()->getListView();
+ UMLListViewItem* listViewItem = listView->findItem(view->getID());
+ // skip the name of the first item because it's the View
+ listViewItem = static_cast<UMLListViewItem*>(listViewItem->parent());
+
+ // Relies on the tree structure of the UMLListView. There are a base "Views" folder
+ // and five children, one for each view type (Logical, use case, components, deployment
+ // and entity relationship)
+ while (listView->rootView(listViewItem->getType()) == NULL) {
+ name.insert(0, listViewItem->getText() + '/');
+ listViewItem = static_cast<UMLListViewItem*>(listViewItem->parent());
+ if (listViewItem == NULL)
+ break;
+ }
+ return name;
+}
+
+bool UMLViewImageExporterModel::prepareDirectory(const KURL &url) const {
+ // the KURL is copied to get protocol, user and so on and then the path is cleaned
+ KURL directory = url;
+ directory.setPath("");
+
+ // creates the directory and any needed parent directories
+ QStringList dirs = QStringList::split(QDir::separator(), url.directory());
+ for (QStringList::ConstIterator it = dirs.begin() ; it != dirs.end(); ++it ) {
+ directory.addPath(*it);
+
+ if (!KIO::NetAccess::exists(directory, true, UMLApp::app())) {
+
+ if (!KIO::NetAccess::mkdir(directory, UMLApp::app())) {
+ return false;
+ }
+ }
+ }
+
+ return true;
+}
+
+bool UMLViewImageExporterModel::exportViewTo(UMLView* view, const QString &imageType, const QString &fileName) const {
+ // remove 'blue squares' from exported picture.
+ view->clearSelected();
+
+ QString imageMimeType = UMLViewImageExporterModel::imageTypeToMimeType(imageType);
+ if (imageMimeType == "image/x-eps") {
+ if (!exportViewToEps(view, fileName, true)) {
+ return false;
+ }
+ } else if (imageMimeType == "image/svg+xml") {
+ if (!exportViewToSvg(view, fileName)) {
+ return false;
+ }
+ } else {
+ if (!exportViewToPixmap(view, imageType, fileName)) {
+ return false;
+ }
+ }
+
+ return true;
+}
+
+bool UMLViewImageExporterModel::exportViewToEps(UMLView* view, const QString &fileName, bool isEPS) const {
+ bool exportSuccessful = true;
+
+ // print the image to a normal postscript file,
+ // do not clip so that everything ends up in the file
+ // regardless of "paper size"
+
+ // because we want to work with postscript
+ // user-coordinates, set to the resolution
+ // of the printer (which should be 72dpi here)
+ QPrinter *printer;
+
+ if (isEPS == false) {
+ printer = new QPrinter(QPrinter::PrinterResolution);
+ } else {
+ printer = new QPrinter(QPrinter::ScreenResolution);
+ }
+ printer->setOutputToFile(true);
+ printer->setOutputFileName(fileName);
+ printer->setColorMode(QPrinter::Color);
+
+ // do not call printer.setup(); because we want no user
+ // interaction here
+ QPainter *painter = new QPainter(printer);
+
+ // make sure the widget sizes will be according to the
+ // actually used printer font, important for getDiagramRect()
+ // and the actual painting
+ view->forceUpdateWidgetFontMetrics(painter);
+
+ QRect rect = view->getDiagramRect();
+ painter->translate(-rect.x(),-rect.y());
+ view->getDiagram(rect,*painter);
+
+ int resolution = printer->resolution();
+
+ // delete painter and printer before we try to open and fix the file
+ delete painter;
+ delete printer;
+ if (isEPS) {
+ // modify bounding box from screen to eps resolution.
+ rect.setWidth( int(ceil(rect.width() * 72.0/resolution)) );
+ rect.setHeight( int(ceil(rect.height() * 72.0/resolution)) );
+ exportSuccessful = fixEPS(fileName,rect);
+ }
+ // next painting will most probably be to a different device (i.e. the screen)
+ view->forceUpdateWidgetFontMetrics(0);
+
+ return exportSuccessful;
+}
+
+bool UMLViewImageExporterModel::fixEPS(const QString &fileName, const QRect& rect) const {
+ // now open the file and make a correct eps out of it
+ QFile epsfile(fileName);
+ if (! epsfile.open(IO_ReadOnly)) {
+ return false;
+ }
+ // read
+ QTextStream ts(&epsfile);
+ QString fileContent = ts.read();
+ epsfile.close();
+
+ // read information
+ QRegExp rx("%%BoundingBox:\\s*(-?[\\d\\.:]+)\\s*(-?[\\d\\.:]+)\\s*(-?[\\d\\.:]+)\\s*(-?[\\d\\.:]+)");
+ const int pos = rx.search(fileContent);
+ if (pos < 0) {
+ kError() << "UMLViewImageExporterModel::fixEPS(" << fileName
+ << "): cannot find %%BoundingBox" << endl;
+ return false;
+ }
+
+ // write new content to file
+ if (! epsfile.open(IO_WriteOnly | IO_Truncate)) {
+ kError() << "UMLViewImageExporterModel::fixEPS(" << fileName
+ << "): cannot open file for writing" << endl;
+ return false;
+ }
+
+ // be careful when rounding (ceil/floor) the BB, these roundings
+ // were mainly obtained experimentally...
+ const double epsleft = rx.cap(1).toFloat();
+ const double epstop = rx.cap(4).toFloat();
+ const int left = int(floor(epsleft));
+ const int right = int(ceil(epsleft)) + rect.width();
+ const int top = int(ceil(epstop)) + 1;
+ const int bottom = int(floor(epstop)) - rect.height() + 1;
+
+ // modify content
+ fileContent.replace(pos,rx.cap(0).length(),
+ QString("%%BoundingBox: %1 %2 %3 %4").arg(left).arg(bottom).arg(right).arg(top));
+
+ ts << fileContent;
+ epsfile.close();
+
+ return true;
+}
+
+bool UMLViewImageExporterModel::exportViewToSvg(UMLView* view, const QString &fileName) const {
+ bool exportSuccesful;
+
+ QPicture* diagram = new QPicture();
+
+ // do not call printer.setup(); because we want no user
+ // interaction here
+ QPainter* painter = new QPainter();
+ painter->begin( diagram );
+
+ // make sure the widget sizes will be according to the
+ // actually used printer font, important for getDiagramRect()
+ // and the actual painting
+ view->forceUpdateWidgetFontMetrics(painter);
+
+ QRect rect = view->getDiagramRect();
+ painter->translate(-rect.x(),-rect.y());
+ view->getDiagram(rect,*painter);
+ painter->end();
+ exportSuccesful = diagram->save(fileName, QString("SVG").ascii());
+
+ // delete painter and printer before we try to open and fix the file
+ delete painter;
+ delete diagram;
+ // next painting will most probably be to a different device (i.e. the screen)
+ view->forceUpdateWidgetFontMetrics(0);
+
+ return exportSuccesful;
+}
+
+bool UMLViewImageExporterModel::exportViewToPixmap(UMLView* view, const QString &imageType, const QString &fileName) const {
+ QRect rect = view->getDiagramRect();
+ QPixmap diagram(rect.width(), rect.height());
+ view->getDiagram(rect, diagram);
+ return diagram.save(fileName, imageType.upper().ascii());
+}
diff --git a/umbrello/umbrello/umlviewimageexportermodel.h b/umbrello/umbrello/umlviewimageexportermodel.h
new file mode 100644
index 00000000..d69796ac
--- /dev/null
+++ b/umbrello/umbrello/umlviewimageexportermodel.h
@@ -0,0 +1,214 @@
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * copyright (C) 2006-2007 *
+ * Umbrello UML Modeller Authors <uml-devel@uml.sf.net> *
+ ***************************************************************************/
+
+#ifndef UMLVIEWIMAGEEXPORTERMODEL_H
+#define UMLVIEWIMAGEEXPORTERMODEL_H
+
+#include <qstringlist.h>
+#include <qrect.h>
+
+// forward declarations
+class UMLView;
+
+// KDE forward declarations
+class KTempFile;
+class KURL;
+
+/**
+ * Exports an UMLView in various image formats.
+ * It can also export all the views in the current document.
+ *
+ * The methods in this class don't communicate with the user, so asking the format
+ * to save the images in, checking if the target file exists and so on must be done before
+ * calling those methods, if needed.
+ * The only exception is asking passwords for example when KIO slaves are used, as this
+ * operation is made automatically by the KIO classes.
+ */
+class UMLViewImageExporterModel {
+public:
+
+ /**
+ * Returns a QStringList containing all the supported image types to use when exporting.
+ * All the types will be lower case.
+ *
+ * @return A QStringList containing all the supported image types to use when exporting.
+ */
+ static QStringList supportedImageTypes();
+
+ /**
+ * Returns a QStringList containing all the supported mime types to use when exporting.
+ * All the types will be lower case.
+ *
+ * @return A QStringList containing all the supported mime types to use when exporting.
+ */
+ static QStringList supportedMimeTypes();
+
+ /**
+ * Returns the mime type for an image type.
+ * The supported image types are those that the diagrams can be exported to.
+ *
+ * @param imageType The type of the image.
+ * @return A QString with the equivalent mime type, or QString::null if
+ * it's unknown.
+ */
+ static QString imageTypeToMimeType(const QString& imageType);
+
+ /**
+ * Returns the image type for a mime type.
+ * The supported image types are those that the diagrams can be exported to.
+ *
+ * @param mimeType The mime type.
+ * @return A lowercase QString with the equivalent image type, or QString::null
+ * if it's unknown.
+ */
+ static QString mimeTypeToImageType(const QString& mimeType);
+
+ /**
+ * Constructor for UMLViewImageExporterModel.
+ */
+ UMLViewImageExporterModel() {
+ }
+
+ /**
+ * Destructor for UMLViewImageExporterModel.
+ */
+ virtual ~UMLViewImageExporterModel() {
+ }
+
+ /**
+ * Exports all the views in the document to the directory specified in the url
+ * using the 'imageType' for the images.
+ * The name of the exported images will be like their view's name and using the
+ * 'imageType' as extension.
+ *
+ * The views are stored in folders in the document. The same tree structure used
+ * in the document to store the views can be created in the target directory with
+ * 'useFolders'. Only the folders made by the user are created in the target
+ * directory (Logical view, use case view and so on aren't created).
+ *
+ * This method creates the specified target directory if needed. If there was an
+ * existing file with the same path as one to be created overwrites it without asking.
+ * The url used can be local or remote, using supported KIO slaves.
+ *
+ * @param imageType The type of the images the views will be exported to.
+ * @param directory The url of the directory where the images will be saved.
+ * @param useFolders If the tree structure of the views in the document must be created
+ * in the target directory.
+ * @return A QStringList with all the error messages that occurred during export.
+ * If the list is empty, all the views were exported successfully.
+ */
+ QStringList exportAllViews(const QString &imageType, const KURL &directory, bool useFolders) const;
+
+ /**
+ * Exports the view to the url using the 'imageType' for the image.
+ *
+ * This method creates the needed directories, if any. If there was an existing
+ * file in the specified url overwrites it without asking.
+ * The url used can be local or remote, using supported KIO slaves.
+ *
+ * If some problem occurs when exporting, an error message is returned.
+ *
+ * @param view The view to export.
+ * @param imageType The type of the image the view will be exported to.
+ * @param url The url where the image will be saved.
+ * @return The message error if some problem occurred when exporting, or
+ * QString::null if all went fine.
+ */
+ QString exportView(UMLView* view, const QString &imageType, const KURL &url) const;
+
+private:
+
+ /**
+ * Returns the name of the file where the view will be exported to.
+ * The name of the exported images will be like their view's name and using the
+ * 'imageType' as extension. It can also include the parent folders of the view.
+ *
+ * The views are stored in folders in the document. The same tree structure used
+ * in the document to store the views can be created with 'useFolders', so the file name
+ * will include recursively also its parent folders. Only the folders made by the user
+ * are included in the file name (Logical view, use case view and so on aren't created).
+ *
+ * @param view The view to export.
+ * @param imageType The type of the image the view will be exported to.
+ * @param useFolders If the tree structure of the views in the document must be included
+ * in the file name.
+ * @return The name of the file where the view will be exported to.
+ */
+ QString getDiagramFileName(UMLView *view, const QString &imageType, bool useFolders = false) const;
+
+ /**
+ * Creates, if it doesn't exist, the directory to save the file.
+ * It also creates all the needed parent directories.
+ *
+ * @param url The url where the image will be saved.
+ * @return True if the operation was successful,
+ * false if the directory didn't exist and couldn't be created.
+ */
+ bool prepareDirectory(const KURL &url) const;
+
+ /**
+ * Exports the view to the file 'fileName' as the specified type.
+ *
+ * @param view The view to export.
+ * @param imageType The type of the image the view will be exported to.
+ * @param fileName The name of the file where the image will be saved.
+ * @return True if the operation was successful,
+ * false if a problem occurred while exporting.
+ */
+ bool exportViewTo(UMLView* view, const QString &imageType, const QString &fileName) const;
+
+ /**
+ * Exports the view to the file 'fileName' as EPS.
+ *
+ * @param view The view to export.
+ * @param fileName The name of the file where the image will be saved.
+ * @param isEPS The file is an eps file and needs adjusting
+ * of the eps bounding box values.
+ * @return True if the operation was successful,
+ * false if a problem occurred while exporting.
+ */
+ bool exportViewToEps(UMLView* view, const QString &fileName, bool isEPS) const;
+
+ /**
+ * Fix the file 'fileName' to be a valid EPS containing the
+ * specified area (rect) of the diagram.
+ * Corrects the bounding box.
+ *
+ * @return True if the operation was successful,
+ * false if a problem occurred while exporting.
+ */
+ bool fixEPS(const QString &fileName, const QRect& rect) const;
+
+ /**
+ * Exports the view to the file 'fileName' as SVG.
+ *
+ * @param view The view to export.
+ * @param fileName The name of the file where the image will be saved.
+ * @return True if the operation was successful,
+ * false if a problem occurred while exporting.
+ */
+ bool exportViewToSvg(UMLView* view, const QString &fileName) const;
+
+ /**
+ * Exports the view to the file 'fileName' as a pixmap of the specified type.
+ * The valid types are those supported by QPixmap save method.
+ *
+ * @param view The view to export.
+ * @param imageType The type of the image the view will be exported to.
+ * @param fileName The name of the file where the image will be saved.
+ * @return True if the operation was successful,
+ * false if a problem occurred while exporting.
+ */
+ bool exportViewToPixmap(UMLView* view, const QString &imageType, const QString &fileName) const;
+
+};
+
+#endif
diff --git a/umbrello/umbrello/umlviewlist.h b/umbrello/umbrello/umlviewlist.h
new file mode 100644
index 00000000..90d5e199
--- /dev/null
+++ b/umbrello/umbrello/umlviewlist.h
@@ -0,0 +1,29 @@
+/***************************************************************************
+ umlviewlist.h - description
+ -------------------
+ begin : Sat Dec 29 2001
+ copyright : (C) 2001 by Gustavo Madrigal
+ email : gmadrigal@nextphere.com
+ Bugs and comments to uml-devel@lists.sf.net or http://bugs.kde.org
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the 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 UMLVIEWLIST_H
+#define UMLVIEWLIST_H
+
+//#include "umlview.h"
+
+class UMLView;
+
+typedef QPtrList<UMLView> UMLViewList;
+typedef QPtrListIterator<UMLView> UMLViewListIt;
+
+#endif
diff --git a/umbrello/umbrello/umlwidget.cpp b/umbrello/umbrello/umlwidget.cpp
new file mode 100644
index 00000000..3e947cd1
--- /dev/null
+++ b/umbrello/umbrello/umlwidget.cpp
@@ -0,0 +1,1025 @@
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * copyright (C) 2002-2007 *
+ * Umbrello UML Modeller Authors <uml-devel@uml.sf.net> *
+ ***************************************************************************/
+
+// own header file
+#include "umlwidget.h"
+// system includes
+#include <qpainter.h>
+#include <qcolor.h>
+#include <kdebug.h>
+#include <kcolordialog.h>
+#include <kfontdialog.h>
+#include <kmessagebox.h>
+// local includes
+#include "umlwidgetcontroller.h"
+#include "umlobject.h"
+#include "classifier.h"
+#include "uniqueid.h"
+#include "uml.h"
+#include "umldoc.h"
+#include "umlview.h"
+#include "umlclassifierlistitemlist.h"
+#include "codegenerator.h"
+#include "codegenerators/simplecodegenerator.h"
+#include "listpopupmenu.h"
+#include "associationwidget.h"
+#include "dialogs/settingsdlg.h"
+#include "codedocument.h"
+#include "floatingtextwidget.h"
+#include "docwindow.h"
+#include "dialogs/classpropdlg.h"
+#include "clipboard/idchangelog.h"
+
+using namespace Uml;
+
+
+UMLWidget::UMLWidget( UMLView * view, UMLObject * o, UMLWidgetController *widgetController /* = 0*/ )
+ : WidgetBase(view), QCanvasRectangle( view->canvas() ),
+ m_pMenu(0)
+{
+ if (widgetController) {
+ m_widgetController = widgetController;
+ } else {
+ m_widgetController = new UMLWidgetController(this);
+ }
+ init();
+ m_pObject = o;
+ if(m_pObject) {
+ connect( m_pObject, SIGNAL(modified()), this, SLOT(updateWidget()) );
+ m_nId = m_pObject->getID();
+ }
+}
+
+UMLWidget::UMLWidget(UMLView * view, Uml::IDType id /* = Uml::id_None */, UMLWidgetController *widgetController /* = 0*/)
+ : WidgetBase(view), QCanvasRectangle( view->canvas() ),
+ m_pMenu(0)
+{
+ if (widgetController) {
+ m_widgetController = widgetController;
+ } else {
+ m_widgetController = new UMLWidgetController(this);
+ }
+ init();
+ if (id == Uml::id_None)
+ m_nId = UniqueID::gen();
+ else
+ m_nId = id;
+}
+
+UMLWidget::~UMLWidget() {
+ //slotRemovePopupMenu();
+ delete m_widgetController;
+ cleanup();
+}
+
+UMLWidget& UMLWidget::operator=(const UMLWidget& other) {
+ if (this == &other)
+ return *this;
+
+ // assign members loaded/saved
+ m_bUseFillColour = other.m_bUseFillColour;
+ m_nId = other.m_nId;
+ m_Type = other.m_Type;
+ setX( other.getX() );
+ setY( other.getY() );
+ m_Assocs = other.m_Assocs;
+ m_Font = other.m_Font;
+ QCanvasRectangle::setSize( other.width(), other.height() );
+ m_bUsesDiagramFillColour = other.m_bUsesDiagramFillColour;
+ m_bUsesDiagramLineColour = other.m_bUsesDiagramLineColour;
+ m_bUsesDiagramLineWidth = other.m_bUsesDiagramLineWidth;
+ m_bUsesDiagramUseFillColour = other.m_bUsesDiagramUseFillColour;
+ m_LineColour = other.m_LineColour;
+ m_LineWidth = other.m_LineWidth;
+ m_FillColour = other.m_FillColour;
+ m_bIsInstance = other.m_bIsInstance;
+ m_instanceName = other.m_instanceName;
+
+ // assign volatile (non-saved) members
+ m_bSelected = other.m_bSelected;
+ m_bStartMove = other.m_bStartMove;
+ m_nPosX = other.m_nPosX;
+ m_pObject = other.m_pObject;
+ m_pView = other.m_pView;
+ m_pMenu = other.m_pMenu;
+ m_bResizable = other.m_bResizable;
+ for (unsigned i = 0; i < FT_INVALID; i++)
+ m_pFontMetrics[i] = other.m_pFontMetrics[i];
+ m_bActivated = other.m_bActivated;
+ m_bIgnoreSnapToGrid = other.m_bIgnoreSnapToGrid;
+ m_bIgnoreSnapComponentSizeToGrid = other.m_bIgnoreSnapComponentSizeToGrid;
+ return *this;
+}
+
+bool UMLWidget::operator==(const UMLWidget& other) {
+ if( this == &other )
+ return true;
+
+ if(m_Type != other.m_Type) {
+ return false;
+ }
+
+ if (getID() != other.getID())
+ return false;
+
+ /* Testing the associations is already an exaggeration, no?
+ The type and ID should uniquely identify an UMLWidget.
+ */
+ if (m_Assocs.count() != other.m_Assocs.count()) {
+ return false;
+ }
+
+ // if(getBaseType() != wt_Text) // DON'T do this for floatingtext widgets, an infinite loop will result
+ // {
+ AssociationWidgetListIt assoc_it( m_Assocs );
+ AssociationWidgetListIt assoc_it2( other.m_Assocs );
+ AssociationWidget * assoc = 0, *assoc2 = 0;
+ while ( ((assoc=assoc_it.current()) != 0) && ((assoc2=assoc_it2.current()) != 0)) {
+ ++assoc_it;
+ ++assoc_it2;
+ if(!(*assoc == *assoc2)) {
+ return false;
+ }
+ }
+ // }
+ return true;
+ // NOTE: In the comparison tests we are going to do, we don't need these values.
+ // They will actually stop things functioning correctly so if you change these, be aware of that.
+ /*
+ if(m_bUseFillColour != other.m_bUseFillColour)
+ return false;
+ if(m_nId != other.m_nId)
+ return false;
+ if( m_Font != other.m_Font )
+ return false;
+ if(m_nX != other.m_nX)
+ return false;
+ if(m_nY != other.m_nY)
+ return false;
+ */
+}
+
+void UMLWidget::mouseMoveEvent(QMouseEvent* me) {
+ m_widgetController->mouseMoveEvent(me);
+}
+
+void UMLWidget::mousePressEvent(QMouseEvent *me) {
+ m_widgetController->mousePressEvent(me);
+}
+
+void UMLWidget::updateWidget()
+{
+ updateComponentSize();
+ adjustAssocs( getX(), getY() ); //adjust assoc lines.
+ if (m_Type == Uml::wt_Class) {
+ m_pView->createAutoAttributeAssociations(this);
+ }
+ if(isVisible())
+ update();
+}
+
+QSize UMLWidget::calculateSize() {
+ return QSize(20, 20);
+}
+
+void UMLWidget::constrain(int& width, int& height) {
+ const QSize minSize = calculateSize();
+ if (width < minSize.width())
+ width = minSize.width();
+ if (height < minSize.height())
+ height = minSize.height();
+}
+
+void UMLWidget::mouseReleaseEvent(QMouseEvent *me) {
+ m_widgetController->mouseReleaseEvent(me);
+}
+
+void UMLWidget::init() {
+ m_nId = Uml::id_None;
+ m_bIsInstance = false;
+ if (m_pView) {
+ m_bUseFillColour = true;
+ m_bUsesDiagramFillColour = true;
+ m_bUsesDiagramUseFillColour = true;
+ const Settings::OptionState& optionState = m_pView->getOptionState();
+ m_FillColour = optionState.uiState.fillColor;
+ m_Font = optionState.uiState.font;
+ m_bShowStereotype = optionState.classState.showStereoType;
+ } else {
+ kError() << "UMLWidget::init: SERIOUS PROBLEM - m_pView is NULL" << endl;
+ m_bUseFillColour = false;
+ m_bUsesDiagramFillColour = false;
+ m_bUsesDiagramUseFillColour = false;
+ m_bShowStereotype = false;
+ }
+
+ for (int i = 0; i < (int)FT_INVALID; ++i)
+ m_pFontMetrics[(UMLWidget::FontType)i] = 0;
+
+ m_bResizable = true;
+
+ m_bSelected = false;
+ m_bStartMove = false;
+ m_bActivated = false;
+ m_bIgnoreSnapToGrid = false;
+ m_bIgnoreSnapComponentSizeToGrid = false;
+ m_pMenu = 0;
+ m_pDoc = UMLApp::app()->getDocument();
+ m_nPosX = 0;
+ connect( m_pView, SIGNAL( sigRemovePopupMenu() ), this, SLOT( slotRemovePopupMenu() ) );
+ connect( m_pView, SIGNAL( sigClearAllSelected() ), this, SLOT( slotClearAllSelected() ) );
+
+ connect( m_pView, SIGNAL(sigColorChanged(Uml::IDType)), this, SLOT(slotColorChanged(Uml::IDType)));
+ connect( m_pView, SIGNAL(sigLineWidthChanged(Uml::IDType)), this, SLOT(slotLineWidthChanged(Uml::IDType)));
+
+
+ // connect( m_pView, SIGNAL(sigColorChanged(int)), this, SLOT(slotColorChanged(int)));
+ m_pObject = NULL;
+ setZ(m_origZ = 2); // default for most widgets
+}
+
+void UMLWidget::slotMenuSelection(int sel) {
+ QFont font;
+ QColor newColour;
+ const Uml::Widget_Type wt = m_Type;
+ UMLWidget* widget = 0; // use for select the first object properties (fill, line color)
+
+ switch(sel) {
+ case ListPopupMenu::mt_Rename:
+ m_pDoc -> renameUMLObject(m_pObject);
+ // adjustAssocs( getX(), getY() );//adjust assoc lines
+ break;
+
+ case ListPopupMenu::mt_Delete:
+ //remove self from diagram
+ m_pView -> removeWidget(this);
+ break;
+
+ //UMLWidgetController::doMouseDoubleClick relies on this implementation
+ case ListPopupMenu::mt_Properties:
+ if (wt == wt_Actor || wt == wt_UseCase ||
+ wt == wt_Package || wt == wt_Interface || wt == wt_Datatype ||
+ wt == wt_Component || wt == wt_Artifact ||
+ wt == wt_Node || wt == wt_Enum || wt == wt_Entity ||
+ (wt == wt_Class && m_pView -> getType() == dt_Class)) {
+ showProperties();
+ } else if (wt == wt_Object) {
+ m_pObject->showProperties();
+ } else {
+ kWarning() << "making properties dialog for unknown widget type" << endl;
+ }
+ // adjustAssocs( getX(), getY() );//adjust assoc lines
+ break;
+
+ case ListPopupMenu::mt_Line_Color:
+ case ListPopupMenu::mt_Line_Color_Selection:
+ widget = m_pView->getFirstMultiSelectedWidget();
+ if (widget) { newColour = widget->getLineColor(); }
+ if( KColorDialog::getColor(newColour) ) {
+ m_pView -> selectionSetLineColor( newColour );
+ m_pDoc -> setModified(true);
+ }
+ break;
+
+ case ListPopupMenu::mt_Fill_Color:
+ case ListPopupMenu::mt_Fill_Color_Selection:
+ widget = m_pView->getFirstMultiSelectedWidget();
+ if (widget) { newColour = widget->getFillColour(); }
+ if ( KColorDialog::getColor(newColour) ) {
+ m_pView -> selectionSetFillColor( newColour );
+ m_pDoc -> setModified(true);
+ }
+ break;
+
+ case ListPopupMenu::mt_Use_Fill_Color:
+ m_bUseFillColour = !m_bUseFillColour;
+ m_bUsesDiagramUseFillColour = false;
+ m_pView->selectionUseFillColor( m_bUseFillColour );
+ break;
+ case ListPopupMenu::mt_Show_Attributes_Selection:
+ case ListPopupMenu::mt_Show_Operations_Selection:
+ case ListPopupMenu::mt_Visibility_Selection:
+ case ListPopupMenu::mt_DrawAsCircle_Selection:
+ case ListPopupMenu::mt_Show_Operation_Signature_Selection:
+ case ListPopupMenu::mt_Show_Attribute_Signature_Selection:
+ case ListPopupMenu::mt_Show_Packages_Selection:
+ case ListPopupMenu::mt_Show_Stereotypes_Selection:
+ case ListPopupMenu::mt_Show_Public_Only_Selection:
+ m_pView->selectionToggleShow(sel);
+ m_pDoc->setModified(true);
+ break;
+
+ case ListPopupMenu::mt_ViewCode: {
+ UMLClassifier *c = dynamic_cast<UMLClassifier*>(m_pObject);
+ if(c)
+ {
+ UMLApp::app()->viewCodeDocument(c);
+ }
+ break;
+ }
+
+ case ListPopupMenu::mt_Delete_Selection:
+ m_pView -> deleteSelection();
+ break;
+
+ case ListPopupMenu::mt_Change_Font:
+ font = getFont();
+ if( KFontDialog::getFont( font, false, m_pView ) )
+ {
+ setFont( font );
+ m_pDoc->setModified(true);
+ }
+ break;
+
+ case ListPopupMenu::mt_Change_Font_Selection:
+ font = getFont();
+ if( KFontDialog::getFont( font, false, m_pView ) )
+ {
+ m_pView -> selectionSetFont( font );
+ m_pDoc->setModified(true);
+ }
+ break;
+
+ case ListPopupMenu::mt_Cut:
+ m_pView -> setStartedCut();
+ UMLApp::app() -> slotEditCut();
+ break;
+
+ case ListPopupMenu::mt_Copy:
+ UMLApp::app() -> slotEditCopy();
+ break;
+
+ case ListPopupMenu::mt_Paste:
+ UMLApp::app() -> slotEditPaste();
+ break;
+
+ case ListPopupMenu::mt_Refactoring:
+ //check if we are operating on a classifier, or some other kind of UMLObject
+ if(dynamic_cast<UMLClassifier*>(m_pObject))
+ {
+ UMLApp::app()->refactor(static_cast<UMLClassifier*>(m_pObject));
+ }
+ break;
+
+ case ListPopupMenu::mt_Clone:
+ // In principle we clone all the uml objects.
+ {
+ UMLObject *pClone = m_pObject->clone();
+ m_pView->addObject(pClone);
+ }
+ break;
+
+ case ListPopupMenu::mt_Rename_MultiA:
+ case ListPopupMenu::mt_Rename_MultiB:
+ case ListPopupMenu::mt_Rename_Name:
+ case ListPopupMenu::mt_Rename_RoleAName:
+ case ListPopupMenu::mt_Rename_RoleBName:
+ {
+ FloatingTextWidget *ft = static_cast<FloatingTextWidget*>(this);
+ ft->handleRename();
+ break;
+ }
+ }
+}
+
+void UMLWidget::slotWidgetMoved(Uml::IDType /*id*/) {}
+
+void UMLWidget::slotColorChanged(Uml::IDType viewID) {
+ //only change if on the diagram concerned
+ if(m_pView->getID() != viewID) {
+ return;
+ }
+ if ( m_bUsesDiagramFillColour ) {
+ m_FillColour = m_pView->getFillColor();
+ }
+ if ( m_bUsesDiagramLineColour ) {
+ m_LineColour = m_pView->getLineColor();
+ }
+ if ( m_bUsesDiagramUseFillColour ) {
+ m_bUseFillColour = m_pView->getUseFillColor();
+ }
+ update();
+}
+
+void UMLWidget::slotLineWidthChanged(Uml::IDType viewID) {
+ //only change if on the diagram concerned
+ if(m_pView->getID() != viewID) {
+ return;
+ }
+ if ( m_bUsesDiagramLineWidth ) {
+ m_LineWidth = m_pView->getLineWidth();
+ }
+ update();
+}
+
+void UMLWidget::mouseDoubleClickEvent( QMouseEvent * me ) {
+ m_widgetController->mouseDoubleClickEvent(me);
+}
+
+void UMLWidget::setUseFillColour(bool fc) {
+ m_bUseFillColour = fc;
+ m_bUsesDiagramUseFillColour = false;
+ update();
+}
+
+void UMLWidget::setLineColor(const QColor &colour) {
+ WidgetBase::setLineColor(colour);
+ update();
+}
+
+void UMLWidget::setLineWidth(uint width) {
+ WidgetBase::setLineWidth(width);
+ update();
+}
+
+void UMLWidget::setFillColour(const QColor &colour) {
+ m_FillColour = colour;
+ m_bUsesDiagramFillColour = false;
+ update();
+}
+
+void UMLWidget::drawSelected(QPainter * p, int offsetX, int offsetY) {
+ int w = width();
+ int h = height();
+ int s = 4;
+ QBrush brush(Qt::blue);
+ p -> fillRect(offsetX, offsetY, s, s, brush);
+ p -> fillRect(offsetX, offsetY + h - s, s, s, brush);
+ p -> fillRect(offsetX + w - s, offsetY, s, s, brush);
+
+ // Draw the resize anchor in the lower right corner.
+ if (m_bResizable) {
+ brush.setColor(Qt::red);
+ const int right = offsetX + w;
+ const int bottom = offsetY + h;
+ p->drawLine(right - s, offsetY + h - 1, offsetX + w - 1, offsetY + h - s);
+ p->drawLine(right - (s*2), bottom - 1, right - 1, bottom - (s*2) );
+ p->drawLine(right - (s*3), bottom - 1, right - 1, bottom - (s*3) );
+ } else {
+ p->fillRect(offsetX + w - s, offsetY + h - s, s, s, brush);
+ }
+}
+
+bool UMLWidget::activate(IDChangeLog* /*ChangeLog = 0 */) {
+ if (widgetHasUMLObject(m_Type) && m_pObject == NULL) {
+ m_pObject = m_pDoc->findObjectById(m_nId);
+ if (m_pObject == NULL) {
+ kError() << "UMLWidget::activate: cannot find UMLObject with id="
+ << ID2STR(m_nId) << endl;
+ return false;
+ }
+ }
+ setFont(m_Font);
+ setSize(getWidth(), getHeight());
+ m_bActivated = true;
+ updateComponentSize();
+ if (m_pView->getPaste()) {
+ FloatingTextWidget * ft = 0;
+ QPoint point = m_pView -> getPastePoint();
+ int x = point.x() + getX();
+ int y = point.y() + getY();
+ x = x < 0?0:x;
+ y = y < 0?0:y;
+ if( m_pView -> getType() == dt_Sequence ) {
+ switch( getBaseType() ) {
+ case wt_Object:
+ case wt_Message:
+ setY( getY() );
+ setX( x );
+ break;
+
+ case wt_Text:
+ ft = static_cast<FloatingTextWidget *>( this );
+ if (ft->getRole() == tr_Seq_Message) {
+ setX( x );
+ setY( getY() );
+ } else {
+ setX( getX() );
+ setY( getY() );
+ }
+ break;
+
+ default:
+ setY( y );
+ break;
+ }//end switch base type
+ }//end if sequence
+ else {
+ setX( x );
+ setY( y );
+ }
+ }//end if pastepoint
+ else {
+ setX( getX() );
+ setY( getY() );
+ }
+ if ( m_pView -> getPaste() )
+ m_pView -> createAutoAssociations( this );
+ updateComponentSize();
+ return true;
+}
+
+/** Read property of bool m_bActivated. */
+bool UMLWidget::isActivated() {
+ return m_bActivated;
+}
+
+void UMLWidget::setActivated(bool Active /*=true*/) {
+ m_bActivated = Active;
+}
+
+void UMLWidget::addAssoc(AssociationWidget* pAssoc) {
+ if (pAssoc && !m_Assocs.contains(pAssoc)) {
+ m_Assocs.append(pAssoc);
+ }
+}
+
+void UMLWidget::removeAssoc(AssociationWidget* pAssoc) {
+ if(pAssoc) {
+ m_Assocs.remove(pAssoc);
+ }
+}
+
+void UMLWidget::adjustAssocs(int x, int y)
+{
+ // 2004-04-30: Achim Spangler
+ // don't adjust Assocs on file load, as
+ // the original positions, which are stored in XMI
+ // should be reproduced exactly
+ // ( don't try to reposition assocs as long
+ // as file is only partly loaded -> reposition
+ // could be misguided )
+ /// @todo avoid trigger of this event during load
+ if ( m_pDoc->loading() ) {
+ // don't recalculate the assocs during load of XMI
+ // -> return immediately without action
+ return;
+ }
+ AssociationWidgetListIt assoc_it(m_Assocs);
+ AssociationWidget* assocwidget = 0;
+ while ((assocwidget = assoc_it.current())) {
+ ++assoc_it;
+ assocwidget->saveIdealTextPositions();
+ }
+ assoc_it.toFirst();
+ while ((assocwidget = assoc_it.current())) {
+ ++assoc_it;
+ assocwidget->widgetMoved(this, x, y);
+ }
+}
+
+void UMLWidget::adjustUnselectedAssocs(int x, int y)
+{
+ AssociationWidgetListIt assoc_it(m_Assocs);
+ AssociationWidget* assocwidget = 0;
+ while ((assocwidget = assoc_it.current())) {
+ ++assoc_it;
+ if(!assocwidget->getSelected())
+ assocwidget->saveIdealTextPositions();
+ }
+ assoc_it.toFirst();
+ while ((assocwidget = assoc_it.current())) {
+ ++assoc_it;
+ if(!assocwidget->getSelected())
+ assocwidget->widgetMoved(this, x, y);
+ }
+}
+
+void UMLWidget::showProperties() {
+ // will already be selected so make sure docWindow updates the doc
+ // back it the widget
+ DocWindow *docwindow = UMLApp::app()->getDocWindow();
+ docwindow->updateDocumentation( false );
+ ClassPropDlg *dlg = new ClassPropDlg((QWidget*)UMLApp::app(), this);
+
+ if (dlg->exec()) {
+ docwindow->showDocumentation( getUMLObject() , true );
+ m_pDoc->setModified(true);
+ }
+ dlg->close(true); //wipe from memory
+}
+
+void UMLWidget::startPopupMenu( const QPoint &At) {
+ slotRemovePopupMenu();
+
+ //if in a multi- selection to a specific m_pMenu for that
+ // NEW: ask UMLView to count ONLY the widgets and not their floatingtextwidgets
+ int count = m_pView->getSelectCount(true);
+ //a MessageWidget when selected will select its text widget and vice versa
+ //so take that into account for popup menu.
+
+ // determine multi state
+ bool multi = (m_bSelected && count > 1);
+
+ // if multiple selected items have the same type
+ bool unique = false;
+
+ // if multiple items are selected, we have to check if they all have the same
+ // base type
+ if (multi == true)
+ unique = m_pView -> checkUniqueSelection();
+
+ // create the right click context menu
+ m_pMenu = new ListPopupMenu(m_pView, this, multi, unique);
+
+ // disable the "view code" menu for simple code generators
+ CodeGenerator * currentCG = UMLApp::app()->getGenerator();
+ if(currentCG && dynamic_cast<SimpleCodeGenerator*>(currentCG))
+ m_pMenu->setItemEnabled(ListPopupMenu::mt_ViewCode, false);
+
+ m_pMenu->popup(At);
+
+ connect(m_pMenu, SIGNAL(activated(int)), this, SLOT(slotMenuSelection(int)));
+}
+
+void UMLWidget::slotRemovePopupMenu() {
+ if(m_pMenu) {
+ disconnect(m_pMenu, SIGNAL(activated(int)), this, SLOT(slotMenuSelection(int)));
+ delete m_pMenu;
+ m_pMenu = 0;
+ }
+}
+
+int UMLWidget::onWidget(const QPoint & p) {
+ const int w = width();
+ const int h = height();
+ const int left = getX();
+ const int right = left + w;
+ const int top = getY();
+ const int bottom = top + h;
+ if (p.x() < left || p.x() > right ||
+ p.y() < top || p.y() > bottom) // Qt coord.sys. origin in top left corner
+ return 0;
+ return (w + h) / 2;
+}
+
+void UMLWidget::moveBy(int dx, int dy) {
+ int newX = getX() + dx;
+ int newY = getY() + dy;
+ setX(newX);
+ setY(newY);
+ adjustAssocs(newX, newY);
+}
+
+void UMLWidget::setPen(QPainter & p) {
+ p.setPen( QPen(m_LineColour, m_LineWidth) );
+}
+
+void UMLWidget::drawShape(QPainter &p ) {
+ draw( p, getX(), getY() );
+}
+
+void UMLWidget::setSelected(bool _select) {
+ const Uml::Widget_Type wt = m_Type;
+ if( _select ) {
+ if( m_pView -> getSelectCount() == 0 ) {
+ if ( widgetHasUMLObject(wt) ) {
+ m_pView->showDocumentation(m_pObject, false);
+ } else {
+ m_pView->showDocumentation(this, false);
+ }
+ }//end if
+ /* if (wt != wt_Text && wt != wt_Box) {
+ setZ(9);//keep text on top and boxes behind so don't touch Z value
+ } */
+ } else {
+ /* if (wt != wt_Text && wt != wt_Box) {
+ setZ(m_origZ);
+ } */
+ if( m_bSelected )
+ m_pView -> updateDocumentation( true );
+ }
+ m_bSelected = _select;
+
+ const QPoint pos(getX(), getY());
+ UMLWidget *bkgnd = m_pView->getWidgetAt(pos);
+ if (bkgnd && bkgnd != this && _select) {
+ kDebug() << "UMLWidget::setSelected: setting Z to "
+ << bkgnd->getZ() + 1 << ", SelectState: " << _select << endl;
+ setZ( bkgnd->getZ() + 1 );
+ } else {
+ setZ( m_origZ );
+ }
+
+ update();
+
+ /* selection changed, we have to make sure the copy and paste items
+ * are correctly enabled/disabled */
+ UMLApp::app()->slotCopyChanged();
+}
+
+void UMLWidget::slotClearAllSelected()
+{
+ setSelected( false );
+}
+
+void UMLWidget::setView(UMLView * v) {
+ //remove signals from old view - was probably 0 anyway
+ disconnect( m_pView, SIGNAL( sigRemovePopupMenu() ), this, SLOT( slotRemovePopupMenu() ) );
+ disconnect( m_pView, SIGNAL( sigClearAllSelected() ), this, SLOT( slotClearAllSelected() ) );
+ disconnect( m_pView, SIGNAL(sigColorChanged(Uml::IDType)), this, SLOT(slotColorChanged(Uml::IDType)));
+ disconnect( m_pView, SIGNAL(sigLineWidthChanged(Uml::IDType)), this, SLOT(slotLineWidthChanged(Uml::IDType)));
+ m_pView = v;
+ connect( m_pView, SIGNAL( sigRemovePopupMenu() ), this, SLOT( slotRemovePopupMenu() ) );
+ connect( m_pView, SIGNAL( sigClearAllSelected() ), this, SLOT( slotClearAllSelected() ) );
+ connect( m_pView, SIGNAL(sigColorChanged(Uml::IDType)), this, SLOT(slotColorChanged(Uml::IDType)));
+ connect( m_pView, SIGNAL(sigLineWidthChanged(Uml::IDType)), this, SLOT(slotLineWidthChanged(Uml::IDType)));
+}
+
+void UMLWidget::setX( int x ) {
+ if (!m_bIgnoreSnapToGrid) {
+ x = m_pView->snappedX(x);
+ }
+ QCanvasItem::setX( (double)x );
+}
+
+void UMLWidget::setY( int y ) {
+ if (!m_bIgnoreSnapToGrid){
+ y = m_pView->snappedX(y);
+ }
+ QCanvasItem::setY( (double)y );
+}
+
+void UMLWidget::setZ(int z) {
+ m_origZ = getZ();
+ QCanvasItem::setZ(z);
+}
+
+void UMLWidget::setName(const QString &strName) {
+ if (m_pObject)
+ m_pObject->setName(strName);
+ else
+ m_Text = strName;
+ updateComponentSize();
+ adjustAssocs( getX(), getY() );
+}
+
+QString UMLWidget::getName() const {
+ if (m_pObject)
+ return m_pObject->getName();
+ return m_Text;
+}
+
+void UMLWidget::cleanup() {
+}
+
+void UMLWidget::slotSnapToGrid( ) {
+ setX( getX() );
+ setY( getY() );
+}
+
+bool UMLWidget::widgetHasUMLObject(Uml::Widget_Type type) {
+ if (type == wt_Actor ||
+ type == wt_UseCase ||
+ type == wt_Class ||
+ type == wt_Interface ||
+ type == wt_Enum ||
+ type == wt_Datatype ||
+ type == wt_Package ||
+ type == wt_Component ||
+ type == wt_Node ||
+ type == wt_Artifact ||
+ type == wt_Object) {
+ return true;
+ } else {
+ return false;
+ }
+}
+
+void UMLWidget::setIgnoreSnapToGrid(bool to) {
+ m_bIgnoreSnapToGrid = to;
+}
+
+bool UMLWidget::getIgnoreSnapToGrid() const {
+ return m_bIgnoreSnapToGrid;
+}
+
+void UMLWidget::setSize(int width,int height) {
+ // snap to the next larger size that is a multiple of the grid
+ if (!m_bIgnoreSnapComponentSizeToGrid
+ && m_pView -> getSnapComponentSizeToGrid() )
+ {
+ // integer divisions
+ int numX = width / m_pView->getSnapX();
+ int numY = height / m_pView->getSnapY();
+ // snap to the next larger valid value
+ if (width > numX * m_pView->getSnapX())
+ width = (numX + 1) * m_pView->getSnapX();
+ if (height > numY * m_pView->getSnapY())
+ height = (numY + 1) * m_pView->getSnapY();
+ }
+
+ QCanvasRectangle::setSize(width,height);
+}
+
+void UMLWidget::updateComponentSize() {
+ if (m_pDoc->loading())
+ return;
+ const QSize minSize = calculateSize();
+ const int w = minSize.width();
+ const int h = minSize.height();
+ setSize(w, h);
+ adjustAssocs( getX(), getY() ); // adjust assoc lines
+}
+
+void UMLWidget::setDefaultFontMetrics(UMLWidget::FontType fontType) {
+ setupFontType(m_Font, fontType);
+ setFontMetrics(fontType, QFontMetrics(m_Font));
+}
+
+void UMLWidget::setupFontType(QFont &font, UMLWidget::FontType fontType) {
+ switch(fontType){
+ case FT_NORMAL:
+ font.setBold(false);
+ font.setItalic(false);
+ font.setUnderline(false);
+ break;
+ case FT_BOLD:
+ font.setBold(true);
+ font.setItalic(false);
+ font.setUnderline(false);
+ break;
+ case FT_ITALIC:
+ font.setBold(false);
+ font.setItalic(true);
+ font.setUnderline(false);
+ break;
+ case FT_UNDERLINE:
+ font.setBold(false);
+ font.setItalic(false);
+ font.setUnderline(true);
+ break;
+ case FT_BOLD_ITALIC:
+ font.setBold(true);
+ font.setItalic(true);
+ font.setUnderline(false);
+ break;
+ case FT_BOLD_UNDERLINE:
+ font.setBold(true);
+ font.setItalic(false);
+ font.setUnderline(true);
+ break;
+ case FT_ITALIC_UNDERLINE:
+ font.setBold(false);
+ font.setItalic(true);
+ font.setUnderline(true);
+ break;
+ case FT_BOLD_ITALIC_UNDERLINE:
+ font.setBold(true);
+ font.setItalic(true);
+ font.setUnderline(true);
+ break;
+ default: return;
+ }
+}
+
+void UMLWidget::setDefaultFontMetrics(UMLWidget::FontType fontType, QPainter &painter) {
+ setupFontType(m_Font, fontType);
+ painter.setFont(m_Font);
+ setFontMetrics(fontType, painter.fontMetrics());
+}
+
+//FIXME this is probably the source of problems with widgets not being wide enough
+QFontMetrics &UMLWidget::getFontMetrics(UMLWidget::FontType fontType) {
+ if (m_pFontMetrics[fontType] == 0) {
+ setDefaultFontMetrics(fontType);
+ }
+ return *m_pFontMetrics[fontType];
+}
+
+void UMLWidget::setFontMetrics(UMLWidget::FontType fontType, QFontMetrics fm) {
+ delete m_pFontMetrics[fontType];
+ m_pFontMetrics[fontType] = new QFontMetrics(fm);
+}
+
+QFont UMLWidget::getFont() const {
+ return m_Font;
+}
+
+void UMLWidget::setFont( QFont font ) {
+ m_Font = font;
+ forceUpdateFontMetrics(0);
+ if (m_pDoc->loading())
+ return;
+ update();
+}
+
+void UMLWidget::forceUpdateFontMetrics(QPainter *painter) {
+ if (painter == 0) {
+ for (int i = 0; i < (int)UMLWidget::FT_INVALID; ++i) {
+ if (m_pFontMetrics[(UMLWidget::FontType)i]!=0)
+ setDefaultFontMetrics((UMLWidget::FontType)i);
+ }
+ } else {
+ for (int i2 = 0; i2 < (int)UMLWidget::FT_INVALID; ++i2) {
+ if (m_pFontMetrics[(UMLWidget::FontType)i2]!=0)
+ setDefaultFontMetrics((UMLWidget::FontType)i2,*painter);
+ }
+ }
+ // calculate the size, based on the new font metric
+ updateComponentSize();
+}
+
+void UMLWidget::setShowStereotype(bool _status) {
+ m_bShowStereotype = _status;
+ updateComponentSize();
+ update();
+}
+
+bool UMLWidget::getShowStereotype() const {
+ return m_bShowStereotype;
+}
+
+void UMLWidget::moveEvent(QMoveEvent* /*me*/) {
+}
+
+void UMLWidget::saveToXMI( QDomDocument & qDoc, QDomElement & qElement ) {
+ /*
+ Call after required actions in child class.
+ Type must be set in the child class.
+ */
+ WidgetBase::saveToXMI(qDoc, qElement);
+ qElement.setAttribute( "xmi.id", ID2STR(getID()) );
+ qElement.setAttribute( "font", m_Font.toString() );
+ qElement.setAttribute( "usefillcolor", m_bUseFillColour );
+ qElement.setAttribute( "x", getX() );
+ qElement.setAttribute( "y", getY() );
+ qElement.setAttribute( "width", getWidth() );
+ qElement.setAttribute( "height", getHeight() );
+ // for consistency the following attributes now use american spelling for "color"
+ qElement.setAttribute( "usesdiagramfillcolor", m_bUsesDiagramFillColour );
+ qElement.setAttribute( "usesdiagramusefillcolor", m_bUsesDiagramUseFillColour );
+ if (m_bUsesDiagramFillColour) {
+ qElement.setAttribute( "fillcolor", "none" );
+ } else {
+ qElement.setAttribute( "fillcolor", m_FillColour.name() );
+ }
+ qElement.setAttribute("isinstance", m_bIsInstance);
+ if (!m_instanceName.isEmpty())
+ qElement.setAttribute("instancename", m_instanceName);
+ if (m_bShowStereotype)
+ qElement.setAttribute("showstereotype", m_bShowStereotype);
+}
+
+bool UMLWidget::loadFromXMI( QDomElement & qElement ) {
+ WidgetBase::loadFromXMI(qElement);
+ QString id = qElement.attribute( "xmi.id", "-1" );
+ QString font = qElement.attribute( "font", "" );
+ QString usefillcolor = qElement.attribute( "usefillcolor", "1" );
+ QString x = qElement.attribute( "x", "0" );
+ QString y = qElement.attribute( "y", "0" );
+ QString h = qElement.attribute( "height", "0" );
+ QString w = qElement.attribute( "width", "0" );
+ /*
+ For the next three *color attributes, there was a mixup of american and english spelling for "color".
+ So first we need to keep backward compatibility and try to retrieve the *colour attribute.
+ Next we overwrite this value if we find a *color, otherwise the former *colour is kept.
+ */
+ QString fillColour = qElement.attribute( "fillcolour", "none" );
+ fillColour = qElement.attribute( "fillcolor", fillColour );
+ QString usesDiagramFillColour = qElement.attribute( "usesdiagramfillcolour", "1" );
+ usesDiagramFillColour = qElement.attribute( "usesdiagramfillcolor", usesDiagramFillColour );
+ QString usesDiagramUseFillColour = qElement.attribute( "usesdiagramusefillcolour", "1" );
+ usesDiagramUseFillColour = qElement.attribute( "usesdiagramusefillcolor", usesDiagramUseFillColour );
+
+ m_nId = STR2ID(id);
+
+ if( !font.isEmpty() ) {
+ //QFont newFont;
+ m_Font.fromString(font);
+ //setFont(newFont);
+ } else {
+ kWarning() << "Using default font " << m_Font.toString()
+ << " for widget with xmi.id " << ID2STR(m_nId) << endl;
+ //setFont( m_Font );
+ }
+ m_bUseFillColour = (bool)usefillcolor.toInt();
+ m_bUsesDiagramFillColour = (bool)usesDiagramFillColour.toInt();
+ m_bUsesDiagramUseFillColour = (bool)usesDiagramUseFillColour.toInt();
+ setSize( w.toInt(), h.toInt() );
+ setX( x.toInt() );
+ setY( y.toInt() );
+ if (fillColour != "none") {
+ m_FillColour = QColor(fillColour);
+ }
+ QString isinstance = qElement.attribute("isinstance", "0");
+ m_bIsInstance = (bool)isinstance.toInt();
+ m_instanceName = qElement.attribute("instancename", "");
+ QString showstereo = qElement.attribute("showstereotype", "0");
+ m_bShowStereotype = (bool)showstereo.toInt();
+ return true;
+}
+
+UMLWidgetController* UMLWidget::getWidgetController() {
+ return m_widgetController;
+}
+
+#include "umlwidget.moc"
diff --git a/umbrello/umbrello/umlwidget.h b/umbrello/umbrello/umlwidget.h
new file mode 100644
index 00000000..7ed472a9
--- /dev/null
+++ b/umbrello/umbrello/umlwidget.h
@@ -0,0 +1,728 @@
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * copyright (C) 2002-2007 *
+ * Umbrello UML Modeller Authors <uml-devel@uml.sf.net> *
+ ***************************************************************************/
+
+#ifndef UMLWIDGET_H
+#define UMLWIDGET_H
+
+#include <qcanvas.h>
+#include <qdatetime.h>
+#include <qfont.h>
+
+#include "umlnamespace.h"
+#include "widgetbase.h"
+#include "associationwidgetlist.h"
+#include "optionstate.h"
+
+class UMLWidgetController;
+
+class UMLObject;
+class UMLView;
+class UMLDoc;
+class ListPopupMenu;
+class IDChangeLog;
+
+class QPainter;
+class QFont;
+class QFontMetrics;
+
+/**
+ * This is the base class for nearly all graphical widgets.
+ *
+ * @short The base class for graphical UML objects.
+ * @author Paul Hensgen <phensgen@techie.com>
+ * Bugs and comments to uml-devel@lists.sf.net or http://bugs.kde.org
+ */
+class UMLWidget : public WidgetBase, public QCanvasRectangle {
+ Q_OBJECT
+public:
+ friend class UMLWidgetController;
+
+ /**
+ * Creates a UMLWidget object.
+ *
+ * @param view The view to be displayed on.
+ * @param o The UMLObject to represent.
+ * @param widgetController The UMLWidgetController of this UMLWidget
+ */
+ UMLWidget( UMLView * view, UMLObject * o, UMLWidgetController *widgetController = 0 );
+
+ /**
+ * Creates a UMLWidget object.
+ *
+ * @param view The view to be displayed on.
+ * @param id The id of the widget.
+ * The default value (id_None) will prompt generation of a new ID.
+ * @param widgetController The UMLWidgetController of this UMLWidget
+ */
+ explicit UMLWidget( UMLView * view, Uml::IDType id = Uml::id_None, UMLWidgetController *widgetController = 0 );
+
+ /**
+ * Standard deconstructor
+ */
+ virtual ~UMLWidget();
+
+ /**
+ * Copy constructor
+ */
+ UMLWidget(const UMLWidget& other);
+
+ /**
+ * Assignment operator
+ */
+ virtual UMLWidget& operator=(const UMLWidget& other);
+
+ /**
+ * Overload '==' operator
+ */
+ virtual bool operator==(const UMLWidget& other);
+
+ /**
+ * Calls the method with the same name in UMLWidgetController.
+ * @see UMLWidgetController#mouseReleaseEvent
+ *
+ * @param me The QMouseEvent event.
+ */
+ virtual void mouseReleaseEvent(QMouseEvent * me);
+
+ /**
+ * Calls the method with the same name in UMLWidgetController.
+ * @see UMLWidgetController#mouseDoubleClickEvent
+ *
+ * @param me The QMouseEvent event.
+ */
+ virtual void mouseDoubleClickEvent(QMouseEvent *me);
+
+ /**
+ * Set the status of using fill color.
+ *
+ * @param fc the status of using fill color.
+ */
+ void setUseFillColour(bool fc);
+
+ /**
+ * Read property of bool m_bUseFillColour.
+ */
+ bool getUseFillColour() const {
+ return m_bUseFillColour;
+ }
+
+ /**
+ * Overrides the method from WidgetBase.
+ */
+ void setLineColor(const QColor &colour);
+
+ /**
+ * Overrides the method from WidgetBase.
+ */
+ void setLineWidth(uint width);
+
+ /**
+ * Sets the background fill colour
+ *
+ * @param colour the new fill colour
+ */
+ void setFillColour(const QColor &colour);
+
+ /**
+ * Read property of QColor m_FillColour.
+ */
+ QColor getFillColour() const {
+ return m_FillColour;
+ }
+
+ /**
+ * Calls the method with the same name in UMLWidgetController.
+ * @see UMLWidgetController#mouseMoveEvent
+ *
+ * @param me The QMouseEvent event.
+ */
+ virtual void mouseMoveEvent(QMouseEvent* me);
+
+ /**
+ * Returns whether this is a line of text.
+ * Used for transparency in printing.
+ *
+ * @return always false
+ */
+ virtual bool isText() {
+ return false;
+ }
+
+ /**
+ * Sets the state of whether the widget is selected.
+ *
+ * @param _select The state of whether the widget is selected.
+ */
+ virtual void setSelected(bool _select);
+
+ /**
+ * Returns the state of whether the widget is selected.
+ *
+ * @return Returns the state of whether the widget is selected.
+ */
+ bool getSelected() const {
+ return m_bSelected;
+ }
+
+ void setSelectedFlag(bool _select) {
+ m_bSelected = _select;
+ }
+
+ /**
+ * Sets the view the widget is on.
+ *
+ * @param v The view the widget is on.
+ */
+ void setView(UMLView * v);
+
+ /**
+ * Activate the object after serializing it from a QDataStream
+ *
+ * @param ChangeLog
+ * @return true for success
+ */
+ virtual bool activate(IDChangeLog* ChangeLog = 0);
+
+ /**
+ * Returns 0 if the given point is not in the boundaries of the widget,
+ * else returns a number which is proportional to the size of the widget.
+ *
+ * @param p Point to be checked.
+ *
+ * @return 0 if the given point is not in the boundaries of the widget;
+ * (width()+height())/2 if the point is within the boundaries.
+ */
+ virtual int onWidget(const QPoint & p);
+
+ /**
+ * Draws the UMLWidget on the given paint device
+ *
+ * @param p The painter for the drawing device
+ * @param offsetX x position to start the drawing.
+ * @param offsetY y position to start the drawing.
+ *
+ */
+ virtual void draw(QPainter & p, int offsetX, int offsetY) = 0;
+
+ /**
+ * Set the pen.
+ */
+ void setPen(QPainter & p);
+
+ /**
+ * Sets the font the widget is to use.
+ *
+ * @param font Font to be set.
+ */
+ virtual void setFont( QFont font );
+
+ /**
+ * Returns the font the widget is to use.
+ */
+ virtual QFont getFont() const;
+
+ /**
+ * Returns whether we triggered the update of position movement.
+ * If so, you probably don't want to move it.
+ *
+ * @return The moving state.
+ */
+ bool getStartMove() {
+ return m_bStartMove;
+ }
+
+ /**
+ * Sets the x-coordinate.
+ * Currently, the only class that reimplements this method is
+ * ObjectWidget.
+ *
+ * @param x The x-coordinate to be set.
+ */
+ virtual void setX( int x );
+
+ /**
+ * Sets the y-coordinate.
+ * Currently, the only class that reimplements this method is
+ * ObjectWidget.
+ *
+ * @param y The y-coordinate to be set.
+ */
+ virtual void setY( int y );
+
+ /**
+ * Sets the z-coordinate.
+ *
+ * @param z The z-coordinate to be set.
+ */
+ virtual void setZ( int z );
+
+ /**
+ * Gets the x-coordinate.
+ */
+ int getX() const {
+ return (int)QCanvasItem::x();
+ }
+
+ /**
+ * Gets the y-coordinate.
+ */
+ int getY() const {
+ return (int)QCanvasItem::y();
+ }
+
+ /**
+ * Gets the z-coordinate.
+ */
+ int getZ() const {
+ return (int)QCanvasItem::z();
+ }
+
+ /**
+ * Returns the height of widget.
+ */
+ int getHeight() const {
+ return QCanvasRectangle::height();
+ }
+
+ /**
+ * Returns the width of the widget.
+ */
+ int getWidth() const {
+ return QCanvasRectangle::width();
+ }
+
+ /**
+ * Sets the size.
+ * If m_pView->getSnapComponentSizeToGrid() is true, then
+ * set the next larger size that snaps to the grid.
+ */
+ void setSize(int width,int height);
+
+ /**
+ * Set m_bIgnoreSnapToGrid.
+ */
+ void setIgnoreSnapToGrid(bool to);
+
+ /**
+ * Return the value of m_bIgnoreSnapToGrid.
+ */
+ bool getIgnoreSnapToGrid() const;
+
+ /**
+ * Move the widget by an X and Y offset relative to
+ * the current position.
+ */
+ void moveBy(int dx, int dy);
+
+ /**
+ * Removes an already created association from the list of
+ * associations that include this UMLWidget
+ */
+ void removeAssoc(AssociationWidget* pAssoc);
+
+ /**
+ * Adds an already created association to the list of
+ * associations that include this UMLWidget
+ */
+ void addAssoc(AssociationWidget* pAssoc);
+
+ /**
+ * Returns the list of associations connected to this widget.
+ */
+ AssociationWidgetList & getAssocList() {
+ return m_Assocs;
+ }
+
+ /**
+ * Returns m_bUsesDiagramFillColour
+ */
+ bool getUsesDiagramFillColour() const {
+ return m_bUsesDiagramFillColour;
+ }
+
+ /**
+ * Returns m_bUsesDiagramUseFillColour
+ */
+ bool getUsesDiagramUseFillColour() const {
+ return m_bUsesDiagramUseFillColour;
+ }
+
+ /**
+ * Sets m_bUsesDiagramFillColour
+ */
+ void setUsesDiagramFillColour(bool usesDiagramFillColour) {
+ m_bUsesDiagramFillColour = usesDiagramFillColour;
+ }
+
+ /**
+ * Sets m_bUsesDiagramUseFillColour
+ */
+ void setUsesDiagramUseFillColour(bool usesDiagramUseFillColour) {
+ m_bUsesDiagramUseFillColour = usesDiagramUseFillColour;
+ }
+
+ /**
+ * Write property of bool m_bIsInstance
+ */
+ void setIsInstance(bool isInstance) {
+ m_bIsInstance = isInstance;
+ }
+
+ /**
+ * Read property of bool m_bIsInstance
+ */
+ bool getIsInstance() const {
+ return m_bIsInstance;
+ }
+
+ /**
+ * Write property of m_instanceName
+ */
+ void setInstanceName(const QString &instanceName) {
+ m_instanceName = instanceName;
+ }
+
+ /**
+ * Read property of m_instanceName
+ */
+ QString getInstanceName() const {
+ return m_instanceName;
+ }
+
+ /**
+ * Returns the status of whether to show Stereotype.
+ *
+ * @return True if stereotype is shown.
+ */
+ bool getShowStereotype() const;
+
+ /**
+ * Set the status of whether to show Stereotype.
+ *
+ * @param _status True if stereotype shall be shown.
+ */
+ virtual void setShowStereotype(bool _status);
+
+ /**
+ * Show a properties dialog for a UMLWidget.
+ */
+ virtual void showProperties();
+
+ /**
+ * Returns true if the Activate method has been called for this instance
+ *
+ * @return The activate status.
+ */
+ bool isActivated();
+
+ /**
+ * Sets the name in the corresponding UMLObject.
+ * Sets the local m_Text if m_pObject is NULL.
+ *
+ * @param strName The name to be set.
+ */
+ virtual void setName(const QString &strName);
+
+ /**
+ * Gets the name from the corresponding UMLObject.
+ * Returns the local m_Text if m_pObject is NULL.
+ *
+ * @return The currently set name.
+ */
+ virtual QString getName() const;
+
+ /**
+ * Starts the popup menu.
+ *
+ * @param At The Point where the diagram is to be coming up.
+ */
+ void startPopupMenu( const QPoint &At );
+
+ /**
+ * Adjusts associations with the given co-ordinates
+ *
+ * @param x The x-coordinate.
+ * @param y The y-coordinate.
+ */
+ virtual void adjustAssocs(int x, int y);
+
+ /**
+ * Adjusts all unselected associations with the given co-ordinates
+ *
+ * @param x The x-coordinate.
+ * @param y The y-coordinate.
+ */
+ void adjustUnselectedAssocs(int x, int y);
+
+ /**
+ * Set the m_bActivated flag of a widget but does not perform the Activate method
+ *
+ * @param Active Status of activation is to be set.
+ */
+ void setActivated(bool Active = true);
+
+ /**
+ * Used to cleanup any other widget it may need to delete.
+ * Used by child classes. This should be called before deleting a widget of a diagram.
+ */
+ virtual void cleanup();
+
+ /**
+ * Returns whether the widget type has an associated UMLObject
+ */
+ static bool widgetHasUMLObject(Uml::Widget_Type type);
+
+ /**
+ * Update the size of this widget.
+ */
+ void updateComponentSize();
+
+ /**
+ * @note For performance Reasons, only FontMetrics for already used
+ * font types are updated. Not yet used font types will not get a font metric
+ * and will get the same font metric as if painter was zero.
+ * This behaviour is acceptable, because diagrams will always be showed on Display
+ * first before a special painter like a printer device is used.
+ */
+ void forceUpdateFontMetrics(QPainter *painter);
+
+ /**
+ * Calls the method with the same name in UMLWidgetController.
+ * @see UMLWidgetController#mousePressEvent
+ *
+ * @param me The QMouseEvent event.
+ */
+ virtual void mousePressEvent(QMouseEvent *me);
+
+ /**
+ * Overrides the standard operation.
+ *
+ * @param me The move event.
+ */
+ virtual void moveEvent(QMoveEvent *me);
+
+ virtual void saveToXMI( QDomDocument & qDoc, QDomElement & qElement );
+
+ virtual bool loadFromXMI( QDomElement & qElement );
+
+ /**
+ * Returns the UMLWdigetController for this widget.
+ */
+ UMLWidgetController* getWidgetController();
+
+protected:
+ /**
+ * Apply possible constraints to the given candidate width and height.
+ * The default implementation calls calculateSize() and
+ * assigns the returned values if they are greater than the
+ * input values.
+ *
+ * @param width input value, may be modified by the constraint
+ * @param height input value, may be modified by the constraint
+ */
+ virtual void constrain(int& width, int& height);
+
+ /**
+ * Draws that the widget is selected.
+ *
+ * @param p Device on which is the selection is to be drawn.
+ * @param offsetX The x-coordinate for drawing.
+ * @param offsetY The y-coordinate for drawing.
+ */
+ virtual void drawSelected(QPainter * p, int offsetX, int offsetY);
+
+ /**
+ * Overrides default method.
+ *
+ * @param p Device on which the shape has to be drawn.
+ */
+ virtual void drawShape(QPainter &p );
+
+ /**
+ * Compute the minimum possible width and height.
+ * The default implementation returns width=20, height=20.
+ *
+ * @return QSize(mininum_width, minimum_height)
+ */
+ virtual QSize calculateSize();
+
+ typedef enum {
+ FT_NORMAL = 0,
+ FT_BOLD = 1,
+ FT_ITALIC = 2,
+ FT_UNDERLINE = 3,
+ FT_BOLD_ITALIC = 4,
+ FT_BOLD_UNDERLINE = 5,
+ FT_ITALIC_UNDERLINE = 6,
+ FT_BOLD_ITALIC_UNDERLINE = 7,
+ FT_INVALID = 8
+ } FontType;
+
+ /** Template Method, override this to set the default
+ * font metric.
+ */
+ virtual void setDefaultFontMetrics(UMLWidget::FontType fontType);
+ virtual void setDefaultFontMetrics(UMLWidget::FontType fontType, QPainter &painter);
+
+ /** Returns the font metric used by this object for Text which uses bold/italic fonts*/
+ QFontMetrics &getFontMetrics(UMLWidget::FontType fontType);
+ /** set the font metric to use */
+ void setFontMetrics(UMLWidget::FontType fontType, QFontMetrics fm);
+ void setupFontType(QFont &font, UMLWidget::FontType fontType);
+
+ /**
+ * Initializes key attributes of the class.
+ */
+ void init();
+
+ ///////////////// Data Loaded/Saved /////////////////////////////////
+
+ /**
+ * This flag indicates if the UMLWidget uses the Diagram FillColour
+ */
+ bool m_bUseFillColour;
+
+ /**
+ * true by default, false if the colours have
+ * been explicitly set for this widget
+ */
+ bool m_bUsesDiagramFillColour;
+ bool m_bUsesDiagramUseFillColour;
+
+ /**
+ * Color of the background of the widget
+ */
+ QColor m_FillColour;
+
+ /**
+ * A list of AssociationWidgets between the UMLWidget and other UMLWidgets in the diagram
+ */
+ AssociationWidgetList m_Assocs;
+
+ /**
+ * getName() returns the name from the UMLObject if this widget has an
+ * underlying UMLObject; if it does not, then getName() returns the local
+ * m_Text (notably the case for FloatingTextWidget.)
+ */
+ QString m_Text;
+
+ /**
+ * The font the widget will use.
+ */
+ QFont m_Font;
+
+ /**
+ * Holds whether this widget is a component instance (i.e. on a deployment diagram)
+ */
+ bool m_bIsInstance;
+
+ /**
+ * The instance name (used if on a deployment diagram)
+ */
+ QString m_instanceName;
+
+ /**
+ * Should the stereotype be displayed
+ */
+ bool m_bShowStereotype;
+
+ ///////////////// End of Data Loaded/Saved //////////////////////////
+
+ bool m_bSelected, m_bStartMove;
+
+ int m_nPosX, m_origZ;
+ ListPopupMenu *m_pMenu;
+ UMLDoc *m_pDoc; ///< shortcut for UMLApp::app()->getDocument()
+ bool m_bResizable;
+ QFontMetrics *m_pFontMetrics[FT_INVALID];
+
+ /**
+ * It is true if the Activate Function has been called for this
+ * class instance
+ */
+ bool m_bActivated;
+
+ /**
+ * Change Widget Behaviour
+ */
+ bool m_bIgnoreSnapToGrid;
+ bool m_bIgnoreSnapComponentSizeToGrid;
+
+ /**
+ * Controller for user interaction events.
+ */
+ UMLWidgetController *m_widgetController;
+
+public slots:
+
+ /**
+ * This slot is entered when an event has occurred on the views display,
+ * most likely a mouse event. Before it sends out that mouse event all
+ * children should make sure that they don't have a menu active or there
+ * could be more than one popup menu displayed.
+ */
+ virtual void slotRemovePopupMenu();
+
+ /**
+ * When a widget changes this slot captures that signal.
+ */
+ virtual void updateWidget();
+
+
+ /**
+ * Captures any popup menu signals for menus it created.
+ *
+ * @param sel The command which has to be executed.
+ */
+ virtual void slotMenuSelection(int sel);
+
+ /**
+ * Captures when another widget moves if it is link to it that signal.
+ *
+ * @param id The id of object behind the widget.
+ */
+ virtual void slotWidgetMoved(Uml::IDType id);
+
+ /**
+ * Captures a color change signal.
+ *
+ * @param viewID The id of the object behind the widget.
+ */
+ virtual void slotColorChanged(Uml::IDType viewID);
+
+ /**
+ * Captures a linewidth change signal.
+ *
+ * @param viewID The id of the object behind the widget.
+ */
+ virtual void slotLineWidthChanged(Uml::IDType viewID);
+
+ /**
+ * Captures a sigClearAllSelected signal sent by @ref UMLView
+ */
+ void slotClearAllSelected();
+
+ /**
+ * Tells the widget to snap to grid.
+ * Will use the grid settings of the @ref UMLView it belongs to.
+ */
+ void slotSnapToGrid();
+
+signals:
+ /**
+ * Emit when the widget moves its' position.
+ *
+ * @param id The id of the object behind the widget.
+ */
+ void sigWidgetMoved(Uml::IDType id);
+};
+
+#endif
diff --git a/umbrello/umbrello/umlwidgetcontroller.cpp b/umbrello/umbrello/umlwidgetcontroller.cpp
new file mode 100644
index 00000000..29ca98a1
--- /dev/null
+++ b/umbrello/umbrello/umlwidgetcontroller.cpp
@@ -0,0 +1,540 @@
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * copyright (C) 2006-2007 *
+ * Umbrello UML Modeller Authors <uml-devel@uml.sf.net> *
+ ***************************************************************************/
+
+// own header
+#include "umlwidgetcontroller.h"
+
+// qt includes
+#include <qevent.h>
+#include <qpoint.h>
+
+// kde includes
+#include <kcursor.h>
+#include <kdebug.h>
+#include <klocale.h>
+
+// app includes
+#include "umlwidget.h"
+#include "umlwidgetlist.h"
+#include "umlnamespace.h"
+#include "uml.h"
+#include "umldoc.h"
+#include "umlview.h"
+#include "umlobject.h"
+#include "listpopupmenu.h"
+#include "classifierwidget.h"
+#include "associationwidget.h"
+#include "messagewidget.h"
+
+using namespace Uml;
+
+UMLWidgetController::UMLWidgetController(UMLWidget *widget) {
+ m_widget = widget;
+
+ m_pressOffsetX = m_pressOffsetY = 0;
+ m_oldX = m_oldY = 0;
+ m_oldW = m_oldH = 0;
+ m_minSelectedX = m_minSelectedY = m_maxSelectedX = m_maxSelectedY = 0;
+
+ m_shiftPressed = false;
+ m_leftButtonDown = m_middleButtonDown = m_rightButtonDown = false;
+ m_inMoveArea = m_inResizeArea = 0;
+ m_wasSelected = m_moved = m_resized = 0;
+}
+
+UMLWidgetController::~UMLWidgetController() {
+}
+
+void UMLWidgetController::mousePressEvent(QMouseEvent *me) {
+ // If there is a button pressed already ignore other press events
+ if (m_leftButtonDown || m_middleButtonDown || m_rightButtonDown) {
+ return;
+ }
+
+ if (me->button() == Qt::LeftButton) {
+ m_leftButtonDown = true;
+ } else if (me->button() == Qt::RightButton) {
+ m_rightButtonDown = true;
+ } else {
+ m_middleButtonDown = true;
+ return;
+ }
+
+ //There is no harm in saving all the values of the widget even when
+ //they aren't going to be used
+ saveWidgetValues(me);
+
+ m_oldStatusBarMsg = UMLApp::app()->getStatusBarMsg();
+
+ if (me->state() == Qt::ShiftButton || me->state() == Qt::ControlButton) {
+ m_shiftPressed = true;
+
+ if (me->button() == Qt::LeftButton) {
+ m_inMoveArea = true;
+ }
+
+ if (!m_widget->m_bSelected) {
+ selectMultiple(me);
+ } else if (!m_rightButtonDown) {
+ m_wasSelected = false;
+ }
+ return;
+ }
+
+ m_shiftPressed = false;
+
+ int count = m_widget->m_pView->getSelectCount(true);
+ if (me->button() == Qt::LeftButton) {
+ if (m_widget->m_bSelected && count > 1) {
+ //Single selection is made in release event if the widget wasn't moved
+ m_inMoveArea = true;
+ lastUpdate.start();
+ return;
+ }
+
+ if (isInResizeArea(me)) {
+ m_inResizeArea = true;
+ } else {
+ m_inMoveArea = true;
+ }
+ }
+
+ //If widget wasn't selected, or it was selected but with other widgets also selected
+ if (!m_widget->m_bSelected || count > 1) {
+ selectSingle(me);
+ } else if (!m_rightButtonDown) {
+ m_wasSelected = false;
+ }
+}
+
+void UMLWidgetController::mouseMoveEvent(QMouseEvent* me) {
+ if (!m_leftButtonDown)
+ return;
+
+ if (m_inResizeArea) {
+ resize(me);
+ return;
+ }
+
+ if (!m_moved) {
+ UMLApp::app()->getDocument()->writeToStatusBar(i18n("Hold shift or ctrl to move in X axis. Hold shift and control to move in Y axis. Right button click to cancel move."));
+
+ m_moved = true;
+ //Maybe needed by AssociationWidget
+ m_widget->m_bStartMove = true;
+
+ setSelectionBounds();
+ }
+
+ QPoint position = getPosition(me);
+ int diffX = position.x() - m_widget->getX();
+ int diffY = position.y() - m_widget->getY();
+
+ if ((me->state() & Qt::ShiftButton) && (me->state() & Qt::ControlButton)) {
+ //Move in Y axis
+ diffX = 0;
+ } else if ((me->state() & Qt::ShiftButton) || (me->state() & Qt::ControlButton)) {
+ //Move in X axis
+ diffY = 0;
+ }
+
+ // kDebug() << "UMLWidgetController::mouseMoveEvent before constrainMovementForAllWidgets:"
+ // << " diffX=" << diffX << ", diffY=" << diffY << endl;
+ constrainMovementForAllWidgets(diffX, diffY);
+ // kDebug() << "UMLWidgetController::mouseMoveEvent after constrainMovementForAllWidgets:"
+ // << " diffX=" << diffX << ", diffY=" << diffY << endl;
+
+ //Nothing to move
+ if (diffX == 0 && diffY == 0) {
+ return;
+ }
+
+ UMLWidgetListIt it(m_selectedWidgetsList);
+ UMLWidget* widget;
+ it.toFirst();
+
+ bool update = false;
+ if (lastUpdate.elapsed() > 25) {
+ update = true;
+ lastUpdate.restart();
+
+ m_widget->adjustUnselectedAssocs(m_widget->getX(), m_widget->getY());
+ }
+
+ while ((widget = it.current()) != 0) {
+ ++it;
+ widget->getWidgetController()->moveWidgetBy(diffX, diffY);
+ }
+ // kDebug() << endl;
+
+ // Move any selected associations.
+ AssociationWidgetList awl = m_widget->m_pView->getSelectedAssocs();
+ AssociationWidget *aw = NULL;
+ for (AssociationWidgetListIt ai(awl); (aw = ai.current()) != NULL; ++ai) {
+ if (aw->getSelected()) {
+ aw->moveEntireAssoc(diffX, diffY);
+ }
+ }
+
+ m_widget->m_pView->resizeCanvasToItems();
+ updateSelectionBounds(diffX, diffY);
+}
+
+void UMLWidgetController::mouseReleaseEvent(QMouseEvent *me) {
+ if (me->button() != Qt::LeftButton && me->button() != Qt::RightButton) {
+ if (m_middleButtonDown) {
+ m_middleButtonDown = false;
+ resetSelection();
+ }
+ } else if (me->button() == Qt::LeftButton) {
+ if (m_leftButtonDown) {
+ m_leftButtonDown = false;
+
+ if (!m_moved && !m_resized) {
+ if (!m_shiftPressed && (m_widget->m_pView->getSelectCount(true) > 1)) {
+ selectSingle(me);
+ } else if (!m_wasSelected) {
+ deselect(me);
+ }
+ } else {
+ if (m_moved) {
+ m_moved = false;
+
+ //Ensure associations are updated (the timer could prevent the
+ //adjustment in the last move event before the release)
+ UMLWidgetListIt it(m_selectedWidgetsList);
+ UMLWidget* widget;
+ it.toFirst();
+ while ((widget = it.current()) != 0) {
+ ++it;
+ widget->adjustAssocs(widget->getX(), widget->getY());
+ }
+
+ m_widget->m_bStartMove = false;
+ } else {
+ m_resized = false;
+ }
+
+ if ((m_inMoveArea && wasPositionChanged()) ||
+ (m_inResizeArea && wasSizeChanged())) {
+ m_widget->m_pDoc->setModified(true);
+ }
+
+ UMLApp::app()->getDocument()->writeToStatusBar(m_oldStatusBarMsg);
+ }
+
+ if (m_inResizeArea) {
+ m_inResizeArea = false;
+ m_widget->m_pView->setCursor(KCursor::arrowCursor());
+ } else {
+ m_inMoveArea = false;
+ }
+ }
+ } else if (me->button() == Qt::RightButton) {
+ if (m_rightButtonDown) {
+ m_rightButtonDown = false;
+ showPopupMenu(me);
+ } else if (m_leftButtonDown) {
+ //Cancel move/edit
+ QMouseEvent move(QMouseEvent::MouseMove,
+ QPoint(m_oldX + m_pressOffsetX, m_oldY + m_pressOffsetY),
+ Qt::LeftButton, Qt::NoButton);
+ mouseMoveEvent(&move);
+ QMouseEvent release(QMouseEvent::MouseButtonRelease,
+ QPoint(m_oldX + m_pressOffsetX, m_oldY + m_pressOffsetY),
+ Qt::LeftButton, Qt::NoButton);
+ mouseReleaseEvent(&release);
+ }
+ }
+
+ //TODO Copied from old code. Does it really work as intended?
+ UMLWidget *bkgnd = m_widget->m_pView->getWidgetAt(me->pos());
+ if (bkgnd) {
+ //kDebug() << "UMLWidgetController::mouseReleaseEvent: setting Z to "
+ // << bkgnd->getZ() + 1 << endl;
+ m_widget->setZ(bkgnd->getZ() + 1);
+ } else {
+ m_widget->setZ(0);
+ }
+}
+
+void UMLWidgetController::mouseDoubleClickEvent(QMouseEvent *me) {
+ if (me->button() != Qt::LeftButton) {
+ return;
+ }
+
+ selectSingle(me);
+
+ doMouseDoubleClick(me);
+}
+
+bool UMLWidgetController::isInResizeArea(QMouseEvent *me) {
+ const int m = 10;
+
+ if (m_widget->m_bResizable &&
+ me->x() >= (m_widget->getX() + m_widget->width() - m) &&
+ me->y() >= (m_widget->getY() + m_widget->height() - m)) {
+ m_widget->m_pView->setCursor(getResizeCursor());
+ return true;
+ } else {
+ m_widget->m_pView->setCursor(KCursor::arrowCursor());
+ return false;
+ }
+}
+
+QCursor UMLWidgetController::getResizeCursor() {
+ return KCursor::sizeFDiagCursor();
+}
+
+void UMLWidgetController::resizeWidget(int newW, int newH) {
+ m_widget->setSize(newW, newH);
+}
+
+void UMLWidgetController::moveWidgetBy(int diffX, int diffY) {
+ m_widget->setX(m_widget->getX() + diffX);
+ m_widget->setY(m_widget->getY() + diffY);
+}
+
+void UMLWidgetController::constrainMovementForAllWidgets(int &/*diffX*/, int &/*diffY*/) {
+}
+
+void UMLWidgetController::doMouseDoubleClick(QMouseEvent *) {
+ if (!m_widget || !m_widget->m_pMenu)
+ return;
+ m_widget->slotMenuSelection(ListPopupMenu::mt_Properties);
+}
+
+void UMLWidgetController::resetSelection() {
+ m_widget->m_pView->clearSelected();
+ m_widget->m_pView->resetToolbar();
+ m_widget->setSelected(false);
+
+ m_wasSelected = false;
+}
+
+void UMLWidgetController::selectSingle(QMouseEvent *me) {
+ m_widget->m_pView->clearSelected();
+
+ //Adds the widget to the selected widgets list, but as it has been cleared
+ //only the current widget is selected
+ selectMultiple(me);
+}
+
+void UMLWidgetController::selectMultiple(QMouseEvent *me) {
+ m_widget->m_bSelected = true;
+ m_widget->setSelected(m_widget->m_bSelected);
+ m_widget->m_pView->setSelected(m_widget, me);
+
+ m_wasSelected = true;
+}
+
+void UMLWidgetController::deselect(QMouseEvent *me) {
+ m_widget->m_bSelected = false;
+ m_widget->setSelected(m_widget->m_bSelected);
+ m_widget->m_pView->setSelected(m_widget, me);
+ //m_wasSelected is false implicitly, no need to set it again
+}
+
+void UMLWidgetController::saveWidgetValues(QMouseEvent *me) {
+ m_pressOffsetX = me->x() - m_widget->getX();
+ m_pressOffsetY = me->y() - m_widget->getY();
+
+ m_oldX = m_widget->getX();
+ m_oldY = m_widget->getY();
+
+ m_oldW = m_widget->width();
+ m_oldH = m_widget->height();
+}
+
+void UMLWidgetController::setSelectionBounds() {
+ if (m_widget->m_pView->getSelectCount() > 0) {
+ m_selectedWidgetsList.clear();
+ m_widget->m_pView->getSelectedWidgets(m_selectedWidgetsList, false);
+
+ updateSelectionBounds(1, 1);
+ }
+}
+
+//TODO optimize it
+void UMLWidgetController::updateSelectionBounds(int diffX, int diffY) {
+ if (diffX != 0) {
+ m_minSelectedX = getSmallestX(m_selectedWidgetsList);
+ m_maxSelectedX = getBiggestX(m_selectedWidgetsList);
+ }
+ if (diffY != 0) {
+ m_minSelectedY = getSmallestY(m_selectedWidgetsList);
+ m_maxSelectedY = getBiggestY(m_selectedWidgetsList);
+ }
+}
+
+void UMLWidgetController::resize(QMouseEvent *me) {
+ UMLApp::app()->getDocument()->writeToStatusBar(i18n("Hold shift or ctrl to move in X axis. Hold shift and control to move in Y axis. Right button click to cancel resize."));
+
+ m_resized = true;
+
+ int newW = m_oldW + me->x() - m_widget->getX() - m_pressOffsetX;
+ int newH = m_oldH + me->y() - m_widget->getY() - m_pressOffsetY;
+
+ if ((me->state() & Qt::ShiftButton) && (me->state() & Qt::ControlButton)) {
+ //Move in Y axis
+ newW = m_oldW;
+ } else if ((me->state() & Qt::ShiftButton) || (me->state() & Qt::ControlButton)) {
+ //Move in X axis
+ newH = m_oldH;
+ }
+
+ m_widget->constrain(newW, newH);
+ resizeWidget(newW, newH);
+ m_widget->adjustAssocs(m_widget->getX(), m_widget->getY());
+
+ m_widget->m_pView->resizeCanvasToItems();
+}
+
+//TODO refactor with AlignToolbar method.
+int UMLWidgetController::getSmallestX(const UMLWidgetList &widgetList) {
+ UMLWidgetListIt it(widgetList);
+ UMLWidget* widget;
+
+ widget = it.toFirst();
+ // leave function upon empty widget list
+ if (NULL == widget) return 0;
+ int smallestX = widget->getX();
+ ++it;
+
+ while ((widget = it.current()) != 0) {
+ ++it;
+ if (smallestX > widget->getX())
+ smallestX = widget->getX();
+ }
+
+ return smallestX;
+}
+
+//TODO refactor with AlignToolbar method.
+int UMLWidgetController::getSmallestY(const UMLWidgetList &widgetList) {
+ UMLWidgetListIt it(widgetList);
+ UMLWidget* widget;
+
+ widget = it.toFirst();
+ // leave function upon empty widget list
+ if (NULL == widget) return 0;
+ int smallestY = widget->getY();
+ ++it;
+
+ while ((widget = it.current()) != 0) {
+ ++it;
+ if (smallestY > widget->getY())
+ smallestY = widget->getY();
+ }
+
+ return smallestY;
+}
+
+//TODO refactor with AlignToolbar method.
+int UMLWidgetController::getBiggestX(const UMLWidgetList &widgetList) {
+ UMLWidgetListIt it(widgetList);
+ UMLWidget* widget;
+
+ widget = it.toFirst();
+ // leave function upon empty widget list
+ if (NULL == widget) return 0;
+ int biggestX = widget->getX();
+ biggestX += it.current()->getWidth();
+ ++it;
+
+ while ((widget = it.current()) != 0) {
+ ++it;
+ if (biggestX < widget->getX() + widget->getWidth())
+ biggestX = widget->getX() + widget->getWidth();
+ }
+
+ return biggestX;
+}
+
+//TODO refactor with AlignToolbar method.
+int UMLWidgetController::getBiggestY(const UMLWidgetList &widgetList) {
+ UMLWidgetListIt it(widgetList);
+ UMLWidget* widget;
+
+ widget = it.toFirst();
+ // leave function upon empty widget list
+ if (NULL == widget) return 0;
+ int biggestY = widget->getY();
+ biggestY += it.current()->getHeight();
+ ++it;
+
+ while ((widget = it.current()) != 0) {
+ ++it;
+ if (biggestY < widget->getY() + widget->getHeight())
+ biggestY = widget->getY() + widget->getHeight();
+ }
+
+ return biggestY;
+}
+
+QPoint UMLWidgetController::getPosition(QMouseEvent* me) {
+ /*
+ kDebug() << "UMLWidgetController::getPosition: me->x=" << me->x()
+ << " m_widget->getX=" << m_widget->getX() << ", m_oldX=" << m_oldX
+ << ", m_pressOffsetX=" << m_pressOffsetX << endl;
+ kDebug() << "UMLWidgetController::getPosition: me->y=" << me->y()
+ << " m_widget->getY=" << m_widget->getY() << ", m_oldY=" << m_oldY
+ << ", m_pressOffsetY=" << m_pressOffsetY << endl;
+ */
+ int newX = me->x() + m_widget->getX() - m_oldX - m_pressOffsetX;
+ int newY = me->y() + m_widget->getY() - m_oldY - m_pressOffsetY;
+ int maxX = m_widget->m_pView->canvas()->width();
+ int maxY = m_widget->m_pView->canvas()->height();
+
+ m_oldX = newX;
+ m_oldY = newY;
+
+ if (newX + (m_minSelectedX - m_widget->getX()) < 0) {
+ //kDebug() << "UMLWidgetController::getPosition: got into cond.1" << endl;
+ newX = m_widget->getX() - m_minSelectedX;
+ }
+ if (newY + (m_minSelectedY - m_widget->getY()) < 0) {
+ //kDebug() << "UMLWidgetController::getPosition: got into cond.2" << endl;
+ newY = m_widget->getY() - m_minSelectedY;
+ }
+ if (newX + (m_maxSelectedX - m_widget->getX()) > maxX) {
+ //kDebug() << "UMLWidgetController::getPosition: got into cond.3" << endl;
+ newX = maxX - (m_maxSelectedX - m_widget->getX());
+ }
+ if (newY + (m_maxSelectedY - m_widget->getY()) > maxY) {
+ //kDebug() << "UMLWidgetController::getPosition: got into cond.4" << endl;
+ newY = maxY - (m_maxSelectedY - m_widget->getY());
+ }
+ return QPoint(newX, newY);
+}
+
+QPoint UMLWidgetController::getPositionDifference(QMouseEvent* me) {
+ QPoint newPoint = getPosition(me);
+ const int diffX = newPoint.x() - m_widget->getX();
+ const int diffY = newPoint.y() - m_widget->getY();
+ return QPoint(diffX, diffY);
+}
+
+void UMLWidgetController::showPopupMenu(QMouseEvent *me) {
+ //TODO why this condition?
+ if (m_widget->m_pMenu) {
+ return;
+ }
+ m_widget->startPopupMenu(me->globalPos());
+}
+
+bool UMLWidgetController::wasSizeChanged() {
+ return m_oldW != m_widget->getWidth() || m_oldH != m_widget->getHeight();
+}
+
+bool UMLWidgetController::wasPositionChanged() {
+ return m_oldX != m_widget->getX() || m_oldY != m_widget->getY();
+}
diff --git a/umbrello/umbrello/umlwidgetcontroller.h b/umbrello/umbrello/umlwidgetcontroller.h
new file mode 100644
index 00000000..552ea174
--- /dev/null
+++ b/umbrello/umbrello/umlwidgetcontroller.h
@@ -0,0 +1,476 @@
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * copyright (C) 2006 *
+ * Umbrello UML Modeller Authors <uml-devel@uml.sf.net> *
+ ***************************************************************************/
+
+#ifndef UMLWIDGETCONTROLLER_H
+#define UMLWIDGETCONTROLLER_H
+
+// qt includes
+#include <qdatetime.h>
+
+// app includes
+#include "umlwidgetlist.h"
+
+class QCursor;
+class QMouseEvent;
+class QMoveEvent;
+class QPoint;
+
+class UMLWidget;
+
+/**
+ * Controller for UMLWidget
+ * This class takes care of user interaction with UMLWidgets: select, deselect,
+ * move, resize...
+ * Those actions are done using events. There are handlers for mousePressEvent,
+ * mouseMoveEvent, mouseReleaseEvent and mouseDoubleClickEvent. There's more
+ * information about each of them in their respective documentation.
+ *
+ * Behaviour of this class can be customized overriding the handlers themselves
+ * (which isn't recommended) or, better, overriding the virtual protected
+ * methods.
+ *
+ * The area that is considered as "resize area" can be customized with
+ * isInResizeArea, so when there's a pressed button in this area, mouseMoveEvent
+ * will resize the widget.
+ * Also, if the resize area doesn't need to be modified, but the cursor to be
+ * used when the mouse is in that area can be done with getResizeCursor.
+ * When a widget is being resized, it's done using resizeWidget, so overriding
+ * it makes possible to, for example, constrain the resizing only in one axis
+ * no matter how the mouse was moved.
+ *
+ * Widget move can also be customized. The widgets are moved in mouseMoveEvent
+ * using the moveWidgetBy method of the controller of each selected widget.
+ * Overriding this method widget movement can be, for example, constrained to
+ * an axis, no matter if the widget is being moved explicitly or as part of a
+ * selection.
+ * On the other hand, the move of all the selected widgets can be constrained
+ * with constrainMovementForAllWidgets. This method, called in the controller
+ * that is handling the mouseMoveEvent, modifies the difference between the
+ * current position of the widgets and the new position to be moved to. For
+ * example, if a widget shouldn't be moved in X axis, it's receiving the
+ * mouseMoveEvents and there are other widgets selected, those other widgets
+ * shouldn't be allowed either to be moved in X axis.
+ *
+ * The behaviour when double clicking on the widget after it's selected can be
+ * customized with doMouseDoubleClick.
+ *
+ * @author Umbrello UML Modeller Authors <uml-devel@lists.sourceforge.net>
+ */
+class UMLWidgetController {
+public:
+
+ /**
+ * Constructor for UMLWidgetController.
+ *
+ * @param widget The widget which uses the controller.
+ */
+ UMLWidgetController(UMLWidget *widget);
+
+ /**
+ * Destructor for UMLWidgetController.
+ */
+ virtual ~UMLWidgetController();
+
+ /**
+ * Handles a mouse press event.
+ * It'll select the widget (or mark it to be deselected) and prepare it to
+ * be moved or resized. Go on reading for more info about this.
+ *
+ * Widget values and message bar status are saved.
+ *
+ * If shift or control buttons are pressed, we're in move area no matter
+ * where the button was pressed in the widget. Moreover, if the widget
+ * wasn't already selected, it's added to the selection. If already selected,
+ * it's marked to be deselected when releasing the button (provided it isn't
+ * moved).
+ * Also, if the widget is already selected with other widgets but shift nor
+ * control buttons are pressed, we're in move area. If finally we don't move
+ * the widget, it's selected and the other widgets deselected when releasing
+ * the left button.
+ *
+ * If shift nor control buttons are pressed, we're facing a single selection.
+ * Depending on the position of the cursor, we're in move or in resize area.
+ * If the widget wasn't selected (both when there are no widgets selected, or
+ * when there're other widgets selected but not the one receiving the press
+ * event) it's selected and the others deselected, if any. If already selected,
+ * it's marked to be deselected when releasing the button (provided it wasn't
+ * moved or resized).
+ *
+ * @param me The QMouseEvent event.
+ */
+ virtual void mousePressEvent(QMouseEvent *me);
+
+ /**
+ * Handles a mouse move event.
+ * It resizes or moves the widget, depending on where the cursor is pressed
+ * on the widget. Go on reading for more info about this.
+ *
+ * If resizing, the widget is resized using resizeWidget (where specific
+ * widget resize constrain can be applied), and then the associations are
+ * adjusted.
+ * The resizing can be constrained also to an specific axis using control
+ * and shift buttons. If on or another is pressed, it's constrained to X axis.
+ * If both are pressed, it's constrained to Y axis.
+ *
+ * If not resizing, the widget is being moved. If the move is being started,
+ * the selection bounds are set (which includes updating the list of selected
+ * widgets).
+ * The difference between the previous position of the selection and the new
+ * one is got (taking in account the selection bounds so widgets don't go
+ * beyond the canvas limits). Then, it's constrained to X or Y axis depending
+ * on shift and control buttons.
+ * A further constrain is made using constrainMovementForAllWidgets (for example,
+ * if the widget that receives the event can only be moved in Y axis, with this
+ * method the movement of all the widgets in the selection can be constrained to
+ * be moved only in Y axis).
+ * Then, all the selected widgets are moved using moveWidgetBy (where specific
+ * widget movement constrain can be applied) and, if an specific amount of time
+ * passed from the last move event, the associations are also updated (they're
+ * not updated always to be easy on the CPU). Finally, the canvas is resized,
+ * and selection bounds updated.
+ *
+ * @param me The QMouseEvent event.
+ */
+ virtual void mouseMoveEvent(QMouseEvent* me);
+
+ /**
+ * Handles a mouse release event.
+ * It selects or deselects the widget and cancels or confirms the move or
+ * resize. Go on reading for more info about this.
+ * No matter which tool is selected, Z position of widget is updated.
+ *
+ * Middle button release resets the selection.
+ * Left button release, if it wasn't moved nor resized, selects the widget
+ * and deselect the others if it wasn't selected and there were other widgets
+ * selected. If the widget was marked to be deselected, deselects it.
+ * If it was moved or resized, the document is set to modified if position
+ * or size changed. Also, if moved, all the associations are adjusted because
+ * the timer could have prevented the adjustment in the last move event before
+ * the release.
+ * If mouse was pressed in resize area, cursor is set again to normal cursor
+ * Right button release if right button was pressed shows the pop up menu for
+ * the widget.
+ * If left button was pressed, it cancels the move or resize with a mouse move
+ * event at the same position than the cursor was when pressed. Another left
+ * button release is also sent.
+ *
+ * @param me The QMouseEvent event.
+ */
+ virtual void mouseReleaseEvent(QMouseEvent * me);
+
+ /**
+ * Handles a mouse double click event.
+ * If the button wasn't left button it does nothing. Otherwise, it selects
+ * the widget (deselecting other selected widgets, if any) and executes
+ * doMouseDoubleClick.
+ * @see doMouseDoubleClick
+ *
+ * @param me The QMouseEvent event.
+ */
+ virtual void mouseDoubleClickEvent(QMouseEvent *me);
+
+protected:
+
+ /**
+ * Saves the values of the widget needed for move/resize.
+ * The values saved are: the offset from the cursor respect to the upper left
+ * corner of the widget in m_pressOffsetX/Y, the position in m_oldX/Y and the
+ * size in m_oldW/H.
+ *
+ * It can be overridden to save subclass specific values whenever a move or
+ * resize begins. However, parent method (that is, this method) must be
+ * called in the overridden method.
+ *
+ * @param me The QMouseEvent to get the offset from.
+ */
+ virtual void saveWidgetValues(QMouseEvent *me);
+
+ /**
+ * Checks if the mouse is in resize area (right bottom corner), and sets
+ * the cursor depending on that.
+ * The cursor used when resizing is gotten from getResizeCursor().
+ *
+ * @param me The QMouseEVent to check.
+ * @return true if the mouse is in resize area, false otherwise.
+ */
+ virtual bool isInResizeArea(QMouseEvent *me);
+
+ /**
+ * Returns the cursor to be shown when resizing the widget.
+ *
+ * Default cursor is KCursor::sizeFDiagCursor().
+ *
+ * @return The cursor to be shown when resizing the widget.
+ */
+ virtual QCursor getResizeCursor();
+
+ /**
+ * Resizes the widget.
+ * It's called from resize, after the values are constrained and before
+ * the associations are adjusted.
+ *
+ * Default behaviour is resize the widget using the new size values.
+ * @see resize
+ *
+ * @param newW The new width for the widget.
+ * @param newH The new height for the widget.
+ */
+ virtual void resizeWidget(int newW, int newH);
+
+ /**
+ * Moves the widget to a new position using the difference between the
+ * current position and the new position.
+ * This method doesn't adjust associations. It only moves the widget.
+ *
+ * It can be overridden to constrain movement of m_widget only in one axis even when
+ * the user isn't constraining the movement with shift or control buttons, for example.
+ * The movement policy set here is applied whenever the widget is moved, being it
+ * moving it explicitly, or as a part of a selection but not receiving directly the
+ * mouse events.
+ *
+ * Default behaviour is move the widget to the new position using the diffs.
+ * @see constrainMovementForAllWidgets
+ *
+ * @param diffX The difference between current X position and new X position.
+ * @param diffY The difference between current Y position and new Y position.
+ */
+ virtual void moveWidgetBy(int diffX, int diffY);
+
+ /**
+ * Modifies the value of the diffX and diffY variables used to move the widgets.
+ *
+ * It can be overridden to constrain movement of all the selected widgets only in one
+ * axis even when the user isn't constraining the movement with shift or control
+ * buttons, for example.
+ * The difference with moveWidgetBy is that the diff positions used here are
+ * applied to all the selected widgets instead of only to m_widget, and that
+ * moveWidgetBy, in fact, moves the widget, and here simply the diff positions
+ * are modified.
+ *
+ * Default behaviour is do nothing.
+ * @see moveWidgetBy
+ *
+ * @param diffX The difference between current X position and new X position.
+ * @param diffY The difference between current Y position and new Y position.
+ */
+ virtual void constrainMovementForAllWidgets(int &diffX, int &diffY);
+
+ /**
+ * Executes the action for double click in the widget.
+ * It's called only if the button used was left button.
+ * Before calling this method, the widget is selected.
+ *
+ * Default behaviour is show the properties dialog for the widget using
+ * m_widget->slotMenuSelection(ListPopupMenu::mt_Properties);
+ * If the widget doesn't have a property dialog (from the Widget_Type enum, those that
+ * don't have an UMLObject representation) there's no need to override
+ * the method, it simply does nothing.
+ *
+ * @param me The QMouseEvent which triggered the double click event.
+ */
+ virtual void doMouseDoubleClick(QMouseEvent *me);
+
+ /**
+ * Clears the selection, resets the toolbar and deselects the widget.
+ */
+ void resetSelection();
+
+ /**
+ * Selects the widget and clears the other selected widgets, if any.
+ *
+ * @param me The QMouseEvent which made the selection.
+ */
+ void selectSingle(QMouseEvent *me);
+
+ /**
+ * Selects the widget and adds it to the list of selected widgets.
+ *
+ * @param me The QMouseEvent which made the selection.
+ */
+ void selectMultiple(QMouseEvent *me);
+
+ /**
+ * Deselects the widget and removes it from the list of selected widgets.
+ *
+ * @param me The QMouseEvent which made the selection.
+ */
+ void deselect(QMouseEvent *me);
+
+ /**
+ * Fills m_selectedWidgetsList and sets the selection bounds ((m_min/m_max)X/Y attributes).
+ */
+ void setSelectionBounds();
+
+ /**
+ * Updates the selection bounds based on the movement made.
+ * If it was only a vertical movement, there's no need to update horizontal bounds,
+ * and vice versa.
+ *
+ * @param diffX The difference between current X position and new X position.
+ * @param diffY The difference between current Y position and new Y position.
+ */
+ void updateSelectionBounds(int diffX, int diffY);
+
+ /**
+ * Resizes the widget and adjusts the associations.
+ * It's called when a mouse move event happens and the cursor was
+ * in resize area when pressed.
+ * Resizing can be constrained to an specific axis using control and shift buttons.
+ *
+ * @param me The QMouseEvent to get the values from.
+ */
+ void resize(QMouseEvent *me);
+
+ /**
+ * Returns the smallest X position of all the widgets in the list.
+ *
+ * @param widgetList A list with UMLWidgets.
+ * @return The smallest X position.
+ */
+ int getSmallestX(const UMLWidgetList &widgetList);
+
+ /**
+ * Returns the smallest Y position of all the widgets in the list.
+ *
+ * @param widgetList A list with UMLWidgets.
+ * @return The smallest Y position.
+ */
+ int getSmallestY(const UMLWidgetList &widgetList);
+
+ /**
+ * Returns the biggest X position of all the widgets in the list.
+ *
+ * @param widgetList A list with UMLWidgets.
+ * @return The biggest X position.
+ */
+ int getBiggestX(const UMLWidgetList &widgetList);
+
+ /**
+ * Returns the biggest Y position of all the widgets in the list.
+ *
+ * @param widgetList A list with UMLWidgets.
+ * @return The biggest Y position.
+ */
+ int getBiggestY(const UMLWidgetList &widgetList);
+
+ /**
+ * Returns the adjusted position for the given mouse event.
+ * The adjusted position is computed using the current widget position
+ * m_widget->get{X,Y}(), the previous position m_old{X,Y}, and the
+ * mouse press offset m_pressOffset{X,Y}.
+ *
+ * @param me The QMouseEvent for which to get the adjusted position.
+ * @return A QPoint with the adjusted position.
+ */
+ QPoint getPosition(QMouseEvent *me);
+
+ /**
+ * Returns a QPoint with the new X and Y position difference of the mouse event
+ * respect to the position of the widget.
+ *
+ * @param me The QMouseEvent to get the position to compare.
+ * @return A QPoint with the position difference.
+ */
+ QPoint getPositionDifference(QMouseEvent *me);
+
+ /**
+ * Shows the widget popup menu where the mouse event points to.
+ *
+ * @param me The QMouseEvent which triggered the showing.
+ */
+ void showPopupMenu(QMouseEvent *me);
+
+ /**
+ * Checks if the size of the widget changed respect to the size that
+ * it had when press event was fired.
+ *
+ * @return true if was resized, false otherwise.
+ */
+ bool wasSizeChanged();
+
+ /**
+ * Checks if the position of the widget changed respect to the position that
+ * it had when press event was fired.
+ *
+ * @return true if was moved, false otherwise.
+ */
+ bool wasPositionChanged();
+
+ /**
+ * The widget which uses the controller.
+ */
+ UMLWidget *m_widget;
+
+ /**
+ * Timer that prevents excessive updates (be easy on the CPU).
+ */
+ QTime lastUpdate;
+
+ /**
+ * A list containing the selected widgets.
+ * It's filled by setSelectionBounds method. It must be filled again if
+ * selected widgets changed. It is cleared only in setSelectionBounds, just
+ * before filling it.
+ * Select, deselect and so on methods DON'T modify this list.
+ */
+ UMLWidgetList m_selectedWidgetsList;
+
+ /**
+ * The text in the status bar when the cursor was pressed.
+ */
+ QString m_oldStatusBarMsg;
+
+ /**
+ * The X/Y offset from the position of the cursor when it was pressed to the
+ * upper left corner of the widget.
+ */
+ int m_pressOffsetX, m_pressOffsetY;
+
+ /**
+ * The X/Y position the widget had when the movement started.
+ */
+ int m_oldX, m_oldY;
+
+ /**
+ * The width/height the widget had when the resize started.
+ */
+ int m_oldW, m_oldH;
+
+ /**
+ * The minimum/maximum X/Y position of all the selected widgets.
+ */
+ int m_minSelectedX, m_minSelectedY, m_maxSelectedX, m_maxSelectedY;
+
+ /**
+ * If shift or control button were pressed in mouse press event.
+ */
+ bool m_shiftPressed;
+
+ /**
+ * If the left/middle/right button is pressed.
+ */
+ bool m_leftButtonDown, m_middleButtonDown, m_rightButtonDown;
+
+ /**
+ * If cursor was in move/resize area when left button was pressed (and no
+ * other widgets were selected).
+ */
+ bool m_inMoveArea, m_inResizeArea;
+
+ /**
+ * If the widget was selected/moved/resized in the press and release cycle.
+ * Moved/resized is true if the widget was moved/resized even if the final
+ * position/size is the same as the starting one.
+ */
+ bool m_wasSelected, m_moved, m_resized;
+};
+
+#endif
diff --git a/umbrello/umbrello/umlwidgetlist.h b/umbrello/umbrello/umlwidgetlist.h
new file mode 100644
index 00000000..45a9db6b
--- /dev/null
+++ b/umbrello/umbrello/umlwidgetlist.h
@@ -0,0 +1,29 @@
+/***************************************************************************
+ umlwidgetlist.h - description
+ -------------------
+ begin : Sat Dec 29 2001
+ copyright : (C) 2001 by Gustavo Madrigal
+ email : gmadrigal@nextphere.com
+ Bugs and comments to uml-devel@lists.sf.net or http://bugs.kde.org
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the 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 UMLWIDGETLIST_H
+#define UMLWIDGETLIST_H
+
+#include <qptrlist.h>
+
+class UMLWidget;
+
+typedef QPtrList<UMLWidget> UMLWidgetList;
+typedef QPtrListIterator<UMLWidget> UMLWidgetListIt;
+
+#endif
diff --git a/umbrello/umbrello/uniqueid.cpp b/umbrello/umbrello/uniqueid.cpp
new file mode 100644
index 00000000..ce4dc117
--- /dev/null
+++ b/umbrello/umbrello/uniqueid.cpp
@@ -0,0 +1,57 @@
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * copyright (C) 2006 *
+ * Umbrello UML Modeller Authors <uml-devel@uml.sf.net> *
+ ***************************************************************************/
+
+// own header
+#include "uniqueid.h"
+
+// system includes
+#include <kapplication.h>
+
+namespace UniqueID {
+
+/**
+ * Each model object gets assigned a unique ID.
+ */
+Uml::IDType m_uniqueID;
+
+Uml::IDType gen() {
+ static char buf[20];
+ int length = 12;
+ int i = 0;
+ // Source: KDE4 kdelibs/kdecore/krandom.cpp KRandom::randomString()
+ while (length--) {
+ int r = kapp->random() % 62;
+ r += 48;
+ if (r > 57)
+ r += 7;
+ if (r > 90)
+ r += 6;
+ buf[i++] = char(r);
+ }
+ buf[i] = '\0';
+ m_uniqueID = std::string(buf);
+ return m_uniqueID;
+}
+
+void init() {
+ m_uniqueID = Uml::id_Reserved;
+}
+
+Uml::IDType get() {
+ return m_uniqueID;
+}
+
+void set(Uml::IDType id) {
+ m_uniqueID = id;
+}
+
+} // end namespace UniqueID
+
diff --git a/umbrello/umbrello/uniqueid.h b/umbrello/umbrello/uniqueid.h
new file mode 100644
index 00000000..7dcbd4bb
--- /dev/null
+++ b/umbrello/umbrello/uniqueid.h
@@ -0,0 +1,50 @@
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * copyright (C) 2006 *
+ * Umbrello UML Modeller Authors <uml-devel@uml.sf.net> *
+ ***************************************************************************/
+
+#ifndef UNIQUEID_H
+#define UNIQUEID_H
+
+#include "umlnamespace.h"
+
+namespace UniqueID {
+
+ /**
+ * MAIN FUNCTION: Return a new unique ID.
+ */
+ Uml::IDType gen();
+
+
+ /////////// auxiliary functions ////////////////////////////////////
+ // Only required by code that does special operations on unique IDs.
+ // NB Try to avoid these functions if possible because their
+ // implementation and/or programming interface may change.
+
+ /**
+ * Reinitialize the unique ID counter.
+ * Should not normally be required because the ID counter is
+ * initialized by default anyway.
+ */
+ void init();
+
+ /**
+ * Return the last generated unique ID without generating a new one.
+ */
+ Uml::IDType get();
+
+ /**
+ * Explicitly set a new ID value.
+ */
+ void set(Uml::IDType id);
+
+} // end namespace UniqueID
+
+#endif
+
diff --git a/umbrello/umbrello/usecase.cpp b/umbrello/umbrello/usecase.cpp
new file mode 100644
index 00000000..526f533b
--- /dev/null
+++ b/umbrello/umbrello/usecase.cpp
@@ -0,0 +1,40 @@
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * copyright (C) 2002-2006 *
+ * Umbrello UML Modeller Authors <uml-devel@uml.sf.net> *
+ ***************************************************************************/
+
+#include "usecase.h"
+
+UMLUseCase::UMLUseCase(const QString & name, Uml::IDType id)
+ : UMLCanvasObject(name, id) {
+ init();
+}
+
+UMLUseCase::~UMLUseCase() {}
+
+void UMLUseCase::init() {
+ m_BaseType = Uml::ot_UseCase;
+}
+
+UMLObject* UMLUseCase::clone() const {
+ UMLUseCase *clone = new UMLUseCase();
+ UMLObject::copyInto(clone);
+ return clone;
+}
+
+void UMLUseCase::saveToXMI(QDomDocument& qDoc, QDomElement& qElement) {
+ QDomElement usecaseElement = UMLObject::save("UML:UseCase", qDoc);
+ qElement.appendChild(usecaseElement);
+}
+
+bool UMLUseCase::load(QDomElement& ) {
+ return true;
+}
+
+
diff --git a/umbrello/umbrello/usecase.h b/umbrello/umbrello/usecase.h
new file mode 100644
index 00000000..5c262b10
--- /dev/null
+++ b/umbrello/umbrello/usecase.h
@@ -0,0 +1,63 @@
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * copyright (C) 2002-2006 *
+ * Umbrello UML Modeller Authors <uml-devel@uml.sf.net> *
+ ***************************************************************************/
+
+#ifndef USECASE_H
+#define USECASE_H
+
+#include "umlcanvasobject.h"
+
+/**
+ * This class contains the non-graphical information required for a UML UseCase.
+ * This class inherits from @ref UMLCanvasObject which contains most of the information.
+ *
+ * @short Information for a non-graphical UML UseCase.
+ * @author Paul Hensgen <phensgen@techie.com>
+ * Bugs and comments to uml-devel@lists.sf.net or http://bugs.kde.org
+ */
+
+class UMLUseCase : public UMLCanvasObject {
+public:
+ /**
+ * Creates a UseCase object
+ *
+ * @param name The name of the object.
+ * @param id The id of the object.
+ */
+ explicit UMLUseCase(const QString & name = "", Uml::IDType id = Uml::id_None);
+
+ /**
+ * Standard deconstructor
+ */
+ ~UMLUseCase();
+
+ /**
+ * Initializes key variables of the class.
+ */
+ virtual void init();
+
+ /**
+ * Make a clone of this object.
+ */
+ virtual UMLObject* clone() const;
+
+ /**
+ * Creates the <UML:UseCase> element.
+ */
+ void saveToXMI( QDomDocument & qDoc, QDomElement & qElement );
+
+protected:
+ /**
+ * Loads the <UML:UseCase> element (empty.)
+ */
+ bool load( QDomElement & element );
+};
+
+#endif
diff --git a/umbrello/umbrello/usecasewidget.cpp b/umbrello/umbrello/usecasewidget.cpp
new file mode 100644
index 00000000..f7564036
--- /dev/null
+++ b/umbrello/umbrello/usecasewidget.cpp
@@ -0,0 +1,72 @@
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * copyright (C) 2002-2006 *
+ * Umbrello UML Modeller Authors <uml-devel@uml.sf.net> *
+ ***************************************************************************/
+
+// own header file
+#include "usecasewidget.h"
+// system includes
+#include <qpainter.h>
+#include <kdebug.h>
+// local includes
+#include "usecase.h"
+#include "umlview.h"
+
+
+UseCaseWidget::UseCaseWidget(UMLView * view, UMLUseCase *o) : UMLWidget(view, o) {
+ UMLWidget::setBaseType(Uml::wt_UseCase);
+ //updateComponentSize(); Doing this during loadFromXMI() gives futile updates.
+ // Instead, it is done afterwards by UMLWidget::activate()
+}
+
+UseCaseWidget::~UseCaseWidget() {}
+
+void UseCaseWidget::draw(QPainter & p, int offsetX, int offsetY) {
+ UMLWidget::setPen(p);
+ if ( UMLWidget::getUseFillColour() )
+ p.setBrush( UMLWidget::getFillColour() );
+ QFont font = UMLWidget::getFont();
+ font.setUnderline(false);
+ font.setBold(false);
+ font.setItalic( m_pObject->getAbstract() );
+ p.setFont( font );
+ const QFontMetrics &fm = getFontMetrics(FT_NORMAL);
+ const int fontHeight = fm.lineSpacing();
+ const int w = width();
+ const int h = height();
+ //int middleX = w / 2;
+ const int textStartY = (h / 2) - (fontHeight / 2);
+
+ p.drawEllipse(offsetX, offsetY, w, h);
+ p.setPen(Qt::black);
+ p.drawText(offsetX + UC_MARGIN, offsetY + textStartY, w - UC_MARGIN * 2, fontHeight, Qt::AlignCenter, getName());
+ UMLWidget::setPen(p);
+ if(m_bSelected)
+ drawSelected(&p, offsetX, offsetY);
+}
+
+QSize UseCaseWidget::calculateSize() {
+ const UMLWidget::FontType ft = ( m_pObject->getAbstract() ? FT_BOLD_ITALIC : FT_BOLD );
+ const QFontMetrics &fm = UMLWidget::getFontMetrics(ft);
+ const int fontHeight = fm.lineSpacing();
+ const int textWidth = fm.width(getName());
+ int width = textWidth > UC_WIDTH?textWidth:UC_WIDTH;
+ int height = UC_HEIGHT + fontHeight + UC_MARGIN;
+
+ width += UC_MARGIN * 2;
+
+ return QSize(width, height);
+}
+
+void UseCaseWidget::saveToXMI( QDomDocument & qDoc, QDomElement & qElement ) {
+ QDomElement usecaseElement = qDoc.createElement( "usecasewidget" );
+ UMLWidget::saveToXMI( qDoc, usecaseElement );
+ qElement.appendChild( usecaseElement );
+}
+
diff --git a/umbrello/umbrello/usecasewidget.h b/umbrello/umbrello/usecasewidget.h
new file mode 100644
index 00000000..509ff7a5
--- /dev/null
+++ b/umbrello/umbrello/usecasewidget.h
@@ -0,0 +1,74 @@
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * copyright (C) 2002-2006 *
+ * Umbrello UML Modeller Authors <uml-devel@uml.sf.net> *
+ ***************************************************************************/
+
+#ifndef USECASEWIDGET_H
+#define USECASEWIDGET_H
+#include "umlwidget.h"
+
+#define UC_MARGIN 5
+#define UC_WIDTH 60
+#define UC_HEIGHT 30
+
+
+class UMLUseCase;
+
+/**
+ * This class is the graphical version of a UMLUseCase. A UseCaseWidget is created
+ * by a @ref UMLView. An UseCaseWidget belongs to only one @ref UMLView instance.
+ * When the @ref UMLView instance that this class belongs to, it will be automatically deleted.
+ *
+ * If the @ref UseCase class that this UseCaseWidget is displaying is deleted, the @ref UMLView will
+ * make sure that this instance is also deleted.
+ *
+ * The UseCaseWidget class inherits from the @ref UMLWidget class which adds most of the functionality
+ * to this class.
+ *
+ * @short A graphical version of a UMLUseCase.
+ * @author Paul Hensgen <phensgen@techie.com>
+ * Bugs and comments to uml-devel@lists.sf.net or http://bugs.kde.org
+ */
+class UseCaseWidget : public UMLWidget {
+public:
+
+ /**
+ * Creates a UseCase widget.
+ *
+ * @param view The parent of the widget.
+ * @param o The UMLObject to represent.
+ */
+ UseCaseWidget(UMLView * view, UMLUseCase *o);
+
+
+ /**
+ * destructor
+ */
+ virtual ~UseCaseWidget();
+
+ /**
+ * Overrides the standard paint event.
+ */
+ void draw(QPainter & p, int offsetX, int offsetY);
+
+ /**
+ * Saves this UseCase to file.
+ */
+ void saveToXMI( QDomDocument & qDoc, QDomElement & qElement );
+
+ // For loading we can use the loadFromXMI() inherited from UMLWidget.
+
+protected:
+ /**
+ * Overrides method from UMLWidget
+ */
+ QSize calculateSize();
+};
+
+#endif
diff --git a/umbrello/umbrello/widget_factory.cpp b/umbrello/umbrello/widget_factory.cpp
new file mode 100644
index 00000000..5bb8eeae
--- /dev/null
+++ b/umbrello/umbrello/widget_factory.cpp
@@ -0,0 +1,241 @@
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * copyright (C) 2006-2007 *
+ * Umbrello UML Modeller Authors <uml-devel@uml.sf.net> *
+ ***************************************************************************/
+
+// own header
+#include "widget_factory.h"
+
+// qt/kde includes
+#include <kdebug.h>
+
+// app includes
+#include "uml.h"
+#include "umldoc.h"
+#include "umlview.h"
+#include "object_factory.h"
+#include "floatingtextwidget.h"
+#include "classifierwidget.h"
+#include "classifier.h"
+#include "packagewidget.h"
+#include "package.h"
+#include "folder.h"
+#include "componentwidget.h"
+#include "component.h"
+#include "nodewidget.h"
+#include "node.h"
+#include "artifactwidget.h"
+#include "artifact.h"
+#include "datatypewidget.h"
+#include "enumwidget.h"
+#include "enum.h"
+#include "entitywidget.h"
+#include "entity.h"
+#include "actorwidget.h"
+#include "actor.h"
+#include "usecasewidget.h"
+#include "usecase.h"
+#include "notewidget.h"
+#include "boxwidget.h"
+#include "associationwidget.h"
+#include "messagewidget.h"
+#include "objectwidget.h"
+#include "statewidget.h"
+#include "forkjoinwidget.h"
+#include "activitywidget.h"
+#include "seqlinewidget.h"
+
+namespace Widget_Factory {
+
+UMLWidget *createWidget(UMLView *view, UMLObject *o) {
+ QPoint pos = view->getPos();
+ int y = pos.y();
+ Uml::Diagram_Type diagramType = view->getType();
+ Uml::Object_Type type = o->getBaseType();
+ UMLWidget *newWidget = NULL;
+ switch (type) {
+ case Uml::ot_Actor:
+ if (diagramType == Uml::dt_Sequence) {
+ ObjectWidget *ow = new ObjectWidget(view, o, view->getLocalID());
+ ow->setDrawAsActor(true);
+ y = ow->topMargin();
+ newWidget = ow;
+ } else
+ newWidget = new ActorWidget(view, static_cast<UMLActor*>(o));
+ break;
+ case Uml::ot_UseCase:
+ newWidget = new UseCaseWidget(view, static_cast<UMLUseCase*>(o));
+ break;
+ case Uml::ot_Package:
+ newWidget = new PackageWidget(view, static_cast<UMLPackage*>(o));
+ break;
+ case Uml::ot_Component:
+ newWidget = new ComponentWidget(view, static_cast<UMLComponent*>(o));
+ if (diagramType == Uml::dt_Deployment) {
+ newWidget->setIsInstance(true);
+ }
+ break;
+ case Uml::ot_Node:
+ newWidget = new NodeWidget(view, static_cast<UMLNode*>(o));
+ break;
+ case Uml::ot_Artifact:
+ newWidget = new ArtifactWidget(view, static_cast<UMLArtifact*>(o));
+ break;
+ case Uml::ot_Datatype:
+ newWidget = new DatatypeWidget(view, static_cast<UMLClassifier*>(o));
+ break;
+ case Uml::ot_Enum:
+ newWidget = new EnumWidget(view, static_cast<UMLEnum*>(o));
+ break;
+ case Uml::ot_Entity:
+ newWidget = new EntityWidget(view, static_cast<UMLEntity*>(o));
+ break;
+ case Uml::ot_Interface:
+ if (diagramType == Uml::dt_Sequence || diagramType == Uml::dt_Collaboration) {
+ ObjectWidget *ow = new ObjectWidget(view, o, view->getLocalID() );
+ if (diagramType == Uml::dt_Sequence) {
+ y = ow->topMargin();
+ }
+ newWidget = ow;
+ } else {
+ UMLClassifier *c = static_cast<UMLClassifier*>(o);
+ ClassifierWidget* interfaceWidget = new ClassifierWidget(view, c);
+ if (diagramType == Uml::dt_Component || diagramType == Uml::dt_Deployment) {
+ interfaceWidget->setDrawAsCircle(true);
+ }
+ newWidget = interfaceWidget;
+ }
+ break;
+ case Uml::ot_Class:
+ //see if we really want an object widget or class widget
+ if (diagramType == Uml::dt_Class || diagramType == Uml::dt_Component) {
+ UMLClassifier *c = static_cast<UMLClassifier*>(o);
+ ClassifierWidget *cw = new ClassifierWidget(view, c);
+ if (diagramType == Uml::dt_Component)
+ cw->setDrawAsCircle(true);
+ newWidget = cw;
+ } else {
+ ObjectWidget *ow = new ObjectWidget(view, o, view->getLocalID() );
+ if (diagramType == Uml::dt_Sequence) {
+ y = ow->topMargin();
+ }
+ newWidget = ow;
+ }
+ break;
+ default:
+ kWarning() << "trying to create an invalid widget" << endl;
+ }
+
+ if (newWidget) {
+ newWidget->setX( pos.x() );
+ newWidget->setY( y );
+ }
+ return newWidget;
+}
+
+bool validateObjType(Uml::Object_Type expected, UMLObject* &o, Uml::IDType id) {
+ if (o == NULL) {
+ kDebug() << "Widget_Factory::validateObjType: creating new object of type "
+ << expected << endl;
+ QString artificialName = "LOST_" + ID2STR(id);
+ o = Object_Factory::createUMLObject(expected, artificialName, NULL, false);
+ if (o == NULL)
+ return false;
+ o->setID(id);
+ UMLPackage *parentPkg = o->getUMLPackage();
+ parentPkg->addObject(o);
+ return true;
+ }
+ Uml::Object_Type actual = o->getBaseType();
+ if (actual == expected)
+ return true;
+ kError() << "validateObjType(" << o->getName()
+ << "): expected type " << expected << ", actual type "
+ << actual << endl;
+ return false;
+}
+
+UMLWidget* makeWidgetFromXMI(const QString& tag,
+ const QString& idStr, UMLView *view) {
+ UMLWidget *widget = NULL;
+
+ // Loading of widgets which do NOT represent any UMLObject,
+ // just graphic stuff with no real model information
+ //FIXME while boxes and texts are just diagram objects, activities and
+ // states should be UMLObjects
+ if (tag == "statewidget" || tag == "UML:StateWidget") {
+ widget = new StateWidget(view, StateWidget::Normal, Uml::id_Reserved);
+ } else if (tag == "notewidget" || tag == "UML:NoteWidget") {
+ widget = new NoteWidget(view, Uml::id_Reserved);
+ } else if (tag == "boxwidget") {
+ widget = new BoxWidget(view, Uml::id_Reserved);
+ } else if (tag == "floatingtext" || tag == "UML:FloatingTextWidget") {
+ widget = new FloatingTextWidget(view, Uml::tr_Floating, "", Uml::id_Reserved);
+ } else if (tag == "activitywidget" || tag == "UML:ActivityWidget") {
+ widget = new ActivityWidget(view, ActivityWidget::Initial, Uml::id_Reserved);
+ } else if (tag == "messagewidget") {
+ widget = new MessageWidget(view, Uml::sequence_message_asynchronous, Uml::id_Reserved);
+ } else if (tag == "forkjoin") {
+ widget = new ForkJoinWidget(view, false, Uml::id_Reserved);
+ } else {
+ // Loading of widgets which represent an UMLObject
+
+ // Find the UMLObject and create the Widget to represent it
+ Uml::IDType id = STR2ID(idStr);
+ UMLDoc *umldoc = UMLApp::app()->getDocument();
+ UMLObject *o = umldoc->findObjectById(id);
+ if (o == NULL) {
+ kDebug() << "makeWidgetFromXMI: cannot find object with id "
+ << ID2STR(id) << endl;
+ }
+
+ if (tag == "actorwidget" || tag == "UML:ActorWidget") {
+ if (validateObjType(Uml::ot_Actor, o, id))
+ widget = new ActorWidget(view, static_cast<UMLActor*>(o));
+ } else if (tag == "usecasewidget" || tag == "UML:UseCaseWidget") {
+ if (validateObjType(Uml::ot_UseCase, o, id))
+ widget = new UseCaseWidget(view, static_cast<UMLUseCase*>(o));
+ } else if (tag == "classwidget" || tag == "UML:ClassWidget") {
+ if (validateObjType(Uml::ot_Class, o, id))
+ widget = new ClassifierWidget(view, static_cast<UMLClassifier*>(o));
+ } else if (tag == "packagewidget") {
+ if (validateObjType(Uml::ot_Package, o, id))
+ widget = new PackageWidget(view, static_cast<UMLPackage*>(o));
+ } else if (tag == "componentwidget") {
+ if (validateObjType(Uml::ot_Component, o, id))
+ widget = new ComponentWidget(view, static_cast<UMLComponent*>(o));
+ } else if (tag == "nodewidget") {
+ if (validateObjType(Uml::ot_Node, o, id))
+ widget = new NodeWidget(view, static_cast<UMLNode*>(o));
+ } else if (tag == "artifactwidget") {
+ if (validateObjType(Uml::ot_Artifact, o, id))
+ widget = new ArtifactWidget(view, static_cast<UMLArtifact*>(o));
+ } else if (tag == "interfacewidget") {
+ if (validateObjType(Uml::ot_Interface, o, id))
+ widget = new ClassifierWidget(view, static_cast<UMLClassifier*>(o));
+ } else if (tag == "datatypewidget") {
+ if (validateObjType(Uml::ot_Datatype, o, id))
+ widget = new DatatypeWidget(view, static_cast<UMLClassifier*>(o));
+ } else if (tag == "enumwidget") {
+ if (validateObjType(Uml::ot_Enum, o, id))
+ widget = new EnumWidget(view, static_cast<UMLEnum*>(o));
+ } else if (tag == "entitywidget") {
+ if (validateObjType(Uml::ot_Entity, o, id))
+ widget = new EntityWidget(view, static_cast<UMLEntity*>(o));
+ } else if (tag == "objectwidget" || tag == "UML:ObjectWidget") {
+ widget = new ObjectWidget(view, o );
+ } else {
+ kWarning() << "Trying to create an unknown widget:" << tag << endl;
+ }
+ }
+ return widget;
+}
+
+} // end namespace Widget_Factory
+
diff --git a/umbrello/umbrello/widget_factory.h b/umbrello/umbrello/widget_factory.h
new file mode 100644
index 00000000..ed8c30b7
--- /dev/null
+++ b/umbrello/umbrello/widget_factory.h
@@ -0,0 +1,41 @@
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * copyright (C) 2006 *
+ * Umbrello UML Modeller Authors <uml-devel@uml.sf.net> *
+ ***************************************************************************/
+
+#ifndef WIDGET_FACTORY_H
+#define WIDGET_FACTORY_H
+
+#include <qstring.h>
+
+// forward declarations
+class UMLView;
+class UMLObject;
+class UMLWidget;
+
+/**
+ * Widget factory methods.
+ * Bugs and comments to uml-devel@lists.sf.net or http://bugs.kde.org
+ */
+namespace Widget_Factory {
+
+ /**
+ * Create a UMLWidget in the given view and representing the given document object.
+ */
+ UMLWidget *createWidget(UMLView *view, UMLObject *docObj);
+
+ /**
+ * Create a UMLWidget according to the given XMI tag.
+ */
+ UMLWidget* makeWidgetFromXMI(const QString& tag,
+ const QString& idStr, UMLView *view);
+
+} // end namespace Widget_Factory
+
+#endif
diff --git a/umbrello/umbrello/widget_utils.cpp b/umbrello/umbrello/widget_utils.cpp
new file mode 100644
index 00000000..b022d828
--- /dev/null
+++ b/umbrello/umbrello/widget_utils.cpp
@@ -0,0 +1,110 @@
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * copyright (C) 2004-2006 *
+ * Umbrello UML Modeller Authors <uml-devel@uml.sf.net> *
+ ***************************************************************************/
+
+// own header
+#include "widget_utils.h"
+
+// qt/kde includes
+#include <qcanvas.h>
+#include <qbrush.h>
+#include <qpen.h>
+#include <kiconloader.h>
+#include <kdebug.h>
+
+// app includes
+#include "uml.h"
+#include "umlview.h"
+#include "umlwidget.h"
+#include "objectwidget.h"
+
+namespace Widget_Utils {
+
+UMLWidget* findWidget(Uml::IDType id,
+ const UMLWidgetList& widgets,
+ const MessageWidgetList* pMessages /* = NULL */)
+{
+ UMLWidgetListIt it( widgets );
+ UMLWidget * obj = NULL;
+ while ( (obj = it.current()) != NULL ) {
+ ++it;
+ if (obj->getBaseType() == Uml::wt_Object) {
+ if (static_cast<ObjectWidget *>(obj)->getLocalID() == id)
+ return obj;
+ } else if (obj->getID() == id) {
+ return obj;
+ }
+ }
+
+ if (pMessages == NULL)
+ return NULL;
+
+ MessageWidgetListIt mit( *pMessages );
+ while ( (obj = (UMLWidget*)mit.current()) != NULL ) {
+ ++mit;
+ if( obj -> getID() == id )
+ return obj;
+ }
+ return NULL;
+}
+
+QIconSet iconSet(Uml::Diagram_Type dt) {
+ QIconSet diagramIconSet;
+ switch (dt) {
+ case Uml::dt_UseCase:
+ diagramIconSet = BarIconSet("umbrello_diagram_usecase");
+ break;
+ case Uml::dt_Collaboration:
+ diagramIconSet = BarIconSet("umbrello_diagram_collaboration");
+ break;
+ case Uml::dt_Class:
+ diagramIconSet = BarIconSet("umbrello_diagram_class");
+ break;
+ case Uml::dt_Sequence:
+ diagramIconSet = BarIconSet("umbrello_diagram_sequence");
+ break;
+ case Uml::dt_State:
+ diagramIconSet = BarIconSet("umbrello_diagram_state");
+ break;
+ case Uml::dt_Activity:
+ diagramIconSet = BarIconSet("umbrello_diagram_activity");
+ break;
+ case Uml::dt_Component:
+ diagramIconSet = BarIconSet("umbrello_diagram_component");
+ break;
+ case Uml::dt_Deployment:
+ diagramIconSet = BarIconSet("umbrello_diagram_deployment");
+ break;
+ case Uml::dt_EntityRelationship:
+ diagramIconSet = BarIconSet("umbrello_diagram_entityrelationship");
+ break;
+ default:
+ kDebug() << "Widget_Utils::iconSet: unknown diagram type " << dt << endl;
+ diagramIconSet = BarIconSet("unknown");
+ }
+ return diagramIconSet;
+}
+
+QCanvasRectangle *decoratePoint(const QPoint& p) {
+ const int SIZE = 4;
+ UMLView *currentView = UMLApp::app()->getCurrentView();
+ QCanvasRectangle *rect;
+ rect = new QCanvasRectangle(p.x() - SIZE / 2,
+ p.y() - SIZE / 2,
+ SIZE, SIZE, currentView->canvas());
+ rect->setBrush( QBrush(Qt::blue) );
+ rect->setPen( QPen(Qt::blue) );
+ rect->setVisible(true);
+ return rect;
+}
+
+
+} // namespace Widget_Utils
+
diff --git a/umbrello/umbrello/widget_utils.h b/umbrello/umbrello/widget_utils.h
new file mode 100644
index 00000000..419f9d99
--- /dev/null
+++ b/umbrello/umbrello/widget_utils.h
@@ -0,0 +1,52 @@
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * copyright (C) 2004-2006 *
+ * Umbrello UML Modeller Authors <uml-devel@uml.sf.net> *
+ ***************************************************************************/
+
+#ifndef WIDGET_UTILS_H
+#define WIDGET_UTILS_H
+
+#include <qiconset.h>
+#include <qpoint.h>
+#include "umlnamespace.h"
+#include "umlwidgetlist.h"
+#include "messagewidgetlist.h"
+
+// forward declarations
+class QCanvasRectangle;
+
+/**
+ * General purpose widget utilities.
+ * Bugs and comments to uml-devel@lists.sf.net or http://bugs.kde.org
+ */
+namespace Widget_Utils {
+
+/**
+ * Find the widget identified by the given ID in the given widget
+ * or message list.
+ *
+ * @param id The unique ID to find.
+ * @param widgets The UMLWidgetList to search in.
+ * @param pMessages Optional pointer to a MessageWidgetList to
+ * search in.
+ */
+UMLWidget* findWidget(Uml::IDType id,
+ const UMLWidgetList& widgets,
+ const MessageWidgetList* pMessages = NULL);
+
+/**
+ * Return the icon corresponding to the given Diagram_Type.
+ */
+QIconSet iconSet(Uml::Diagram_Type dt);
+
+QCanvasRectangle *decoratePoint(const QPoint& p);
+
+}
+
+#endif
diff --git a/umbrello/umbrello/widgetbase.cpp b/umbrello/umbrello/widgetbase.cpp
new file mode 100644
index 00000000..225f5848
--- /dev/null
+++ b/umbrello/umbrello/widgetbase.cpp
@@ -0,0 +1,136 @@
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * copyright (C) 2004-2007 *
+ * Umbrello UML Modeller Authors <uml-devel@uml.sf.net> *
+ ***************************************************************************/
+
+#include "widgetbase.h"
+
+#include <kdebug.h>
+#include "umlview.h"
+#include "umlobject.h"
+#include "optionstate.h"
+
+WidgetBase::WidgetBase(UMLView *view) : QObject(view) {
+ init(view);
+}
+
+void WidgetBase::init(UMLView *view, Uml::Widget_Type type /* = Uml::wt_UMLWidget */) {
+ m_pView = view;
+ m_Type = type;
+ m_pObject = NULL;
+ if (m_pView) {
+ m_bUsesDiagramLineColour = true;
+ m_bUsesDiagramLineWidth = true;
+ const Settings::OptionState& optionState = m_pView->getOptionState();
+ m_LineColour = optionState.uiState.lineColor;
+ m_LineWidth = optionState.uiState.lineWidth;
+ } else {
+ kError() << "WidgetBase constructor: SERIOUS PROBLEM - m_pView is NULL" << endl;
+ m_bUsesDiagramLineColour = false;
+ m_bUsesDiagramLineWidth = false;
+ m_LineColour = QColor("black");
+ m_LineWidth = 0; // initialize with 0 to have valid start condition
+ }
+}
+
+void WidgetBase::setBaseType( Uml::Widget_Type type ) {
+ m_Type = type;
+}
+
+Uml::Widget_Type WidgetBase::getBaseType() const {
+ return m_Type;
+}
+
+UMLObject *WidgetBase::getUMLObject() {
+ return m_pObject;
+}
+
+void WidgetBase::setUMLObject(UMLObject * o) {
+ m_pObject = o;
+}
+
+void WidgetBase::setID(Uml::IDType id) {
+ if (m_pObject) {
+ if (m_pObject->getID() != Uml::id_None)
+ kWarning() << "WidgetBase::setID(): changing old UMLObject "
+ << ID2STR(m_pObject->getID()) << " to "
+ << ID2STR(id) << endl;
+ m_pObject->setID(id);
+ }
+ m_nId = id;
+}
+
+Uml::IDType WidgetBase::getID() const {
+ if (m_pObject)
+ return m_pObject->getID();
+ return m_nId;
+}
+
+QString WidgetBase::getDoc() const {
+ if (m_pObject != NULL)
+ return m_pObject->getDoc();
+ return m_Doc;
+}
+
+void WidgetBase::setDoc( const QString &doc ) {
+ if (m_pObject != NULL)
+ m_pObject->setDoc( doc );
+ else
+ m_Doc = doc;
+}
+
+void WidgetBase::setLineColor(const QColor &colour) {
+ m_LineColour = colour;
+ m_bUsesDiagramLineColour = false;
+}
+
+void WidgetBase::setLineWidth(uint width) {
+ m_LineWidth = width;
+ m_bUsesDiagramLineWidth = false;
+}
+
+void WidgetBase::saveToXMI( QDomDocument & /*qDoc*/, QDomElement & qElement ) {
+ if (m_bUsesDiagramLineColour) {
+ qElement.setAttribute( "linecolor", "none" );
+ } else {
+ qElement.setAttribute( "linecolor", m_LineColour.name() );
+ }
+ if (m_bUsesDiagramLineWidth) {
+ qElement.setAttribute( "linewidth", "none" );
+ } else {
+ qElement.setAttribute( "linewidth", m_LineWidth );
+ }
+}
+
+bool WidgetBase::loadFromXMI( QDomElement & qElement ) {
+ // first load from "linecolour" and then overwrite with the "linecolor"
+ // attribute if that one is present. The "linecolour" name was a "typo" in
+ // earlier versions of Umbrello
+ QString lineColor = qElement.attribute( "linecolour", "none" );
+ lineColor = qElement.attribute( "linecolor", lineColor );
+
+ QString lineWidth = qElement.attribute( "linewidth", "none" );
+ if (lineColor != "none") {
+ setLineColor( QColor(lineColor) );
+ m_bUsesDiagramLineColour = false;
+ } else if (m_Type != Uml::wt_Box && m_pView != NULL) {
+ setLineColor( m_pView->getLineColor() );
+ m_bUsesDiagramLineColour = true;
+ }
+ if (lineWidth != "none") {
+ setLineWidth( lineWidth.toInt() );
+ m_bUsesDiagramLineWidth = false;
+ } else if ( m_pView ) {
+ setLineWidth( m_pView->getLineWidth() );
+ m_bUsesDiagramLineWidth = true;
+ }
+ return true;
+}
+
+#include "widgetbase.moc"
diff --git a/umbrello/umbrello/widgetbase.h b/umbrello/umbrello/widgetbase.h
new file mode 100644
index 00000000..5051418e
--- /dev/null
+++ b/umbrello/umbrello/widgetbase.h
@@ -0,0 +1,201 @@
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * copyright (C) 2004-2007 *
+ * Umbrello UML Modeller Authors <uml-devel@uml.sf.net> *
+ ***************************************************************************/
+
+#ifndef WIDGETBASE_H
+#define WIDGETBASE_H
+
+#include <qobject.h>
+#include <qcolor.h>
+#include <qdom.h>
+
+#include "umlnamespace.h"
+
+// forward declarations
+class UMLView;
+class UMLObject;
+
+/**
+ * @short Common base class for UMLWidget and AssociationWidget
+ * @author Oliver Kellogg <okellogg@users.sourceforge.net>
+ * Bugs and comments to uml-devel@lists.sf.net or http://bugs.kde.org
+ */
+class WidgetBase : public QObject {
+ Q_OBJECT
+public:
+ /**
+ * Creates a WidgetBase object.
+ *
+ * @param view The view to be displayed on.
+ */
+ WidgetBase(UMLView * view);
+
+ /**
+ * Standard deconstructor
+ */
+ virtual ~WidgetBase() {}
+
+ /**
+ * Write property of m_Type.
+ */
+ void setBaseType(Uml::Widget_Type type);
+
+ /**
+ * Read property of m_Type.
+ */
+ Uml::Widget_Type getBaseType() const;
+
+ /**
+ * Returns the @ref UMLObject set to represent.
+ *
+ * @return the UMLObject to represent.
+ */
+ UMLObject *getUMLObject();
+
+ /**
+ * Deliver a const pointer to the connected UMLView
+ * ( needed esp. by event handling of LinePath )
+ */
+ const UMLView *getUMLView() const { return m_pView; }
+
+ /**
+ * Sets the @ref UMLObject to represent.
+ *
+ * @param o The object to represent.
+ */
+ virtual void setUMLObject(UMLObject * o);
+
+ /**
+ * Used by some child classes to get documentation.
+ *
+ * @return The documentation from the UMLObject (if m_pObject is set.)
+ */
+ virtual QString getDoc() const;
+
+ /**
+ * Used by some child classes to set documentation.
+ *
+ * @param doc The documentation to be set in the UMLObject
+ * (if m_pObject is set.)
+ */
+ virtual void setDoc( const QString &doc );
+
+ /**
+ * Sets the line colour
+ *
+ * @param colour the new line colour
+ */
+ virtual void setLineColor(const QColor &colour);
+
+ /**
+ * Sets the line width
+ *
+ * @param width the new line width
+ */
+ virtual void setLineWidth(uint width);
+
+ /**
+ * Read property of m_LineColour.
+ */
+ QColor getLineColor() const {
+ return m_LineColour;
+ }
+
+ /**
+ * Read property of m_LineWidth.
+ */
+ uint getLineWidth() const {
+ return m_LineWidth;
+ }
+
+ /**
+ * Returns m_bUsesDiagramLineColour
+ */
+ bool getUsesDiagramLineColour() const {
+ return m_bUsesDiagramLineColour;
+ }
+
+ /**
+ * Returns m_bUsesDiagramLineWidth
+ */
+ bool getUsesDiagramLineWidth() const {
+ return m_bUsesDiagramLineWidth;
+ }
+
+ /**
+ * Sets m_bUsesDiagramLineColour
+ */
+ void setUsesDiagramLineColour(bool usesDiagramLineColour) {
+ m_bUsesDiagramLineColour = usesDiagramLineColour;
+ }
+
+ /**
+ * Sets m_bUsesDiagramLineWidth
+ */
+ void setUsesDiagramLineWidth(bool usesDiagramLineWidth) {
+ m_bUsesDiagramLineWidth = usesDiagramLineWidth;
+ }
+
+ /**
+ * Write property of m_nId.
+ */
+ void setID( Uml::IDType id );
+
+ /**
+ * Read property of m_nId.
+ */
+ Uml::IDType getID() const;
+
+ virtual void saveToXMI( QDomDocument & qDoc, QDomElement & qElement );
+
+ virtual bool loadFromXMI( QDomElement & qElement );
+
+protected:
+ /**
+ * Initialize members.
+ */
+ void init(UMLView *view, Uml::Widget_Type type = Uml::wt_UMLWidget);
+
+ /**
+ * Type of widget.
+ */
+ Uml::Widget_Type m_Type;
+
+ UMLView *m_pView;
+ UMLObject *m_pObject;
+ QString m_Doc; ///< Only used if m_pObject is not set.
+
+ /**
+ * This ID is only used when the widget does not have a
+ * corresponding UMLObject (i.e. the m_pObject pointer is NULL.)
+ * For UMLObjects, the ID from the UMLObject is used.
+ */
+ Uml::IDType m_nId;
+
+ /**
+ * Color of the lines of the widget. Is saved to XMI.
+ */
+ QColor m_LineColour;
+
+ /**
+ * Width of the lines of the widget. Is saved to XMI.
+ */
+ uint m_LineWidth;
+
+ /**
+ * true by default, false if the colours have
+ * been explicitly set for this widget.
+ * These are saved to XMI.
+ */
+ bool m_bUsesDiagramLineColour, m_bUsesDiagramLineWidth;
+
+};
+
+#endif
diff --git a/umbrello/umbrello/worktoolbar.cpp b/umbrello/umbrello/worktoolbar.cpp
new file mode 100644
index 00000000..0f27be80
--- /dev/null
+++ b/umbrello/umbrello/worktoolbar.cpp
@@ -0,0 +1,315 @@
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * copyright (C) 2002-2007 *
+ * Umbrello UML Modeller Authors <uml-devel@uml.sf.net> *
+ ***************************************************************************/
+
+// own header
+#include "worktoolbar.h"
+
+// qt/kde include files
+#include <qmainwindow.h>
+#include <kdebug.h>
+#include <klocale.h>
+#include <kstandarddirs.h>
+#include <ktoolbarbutton.h>
+
+// application specific includes
+#include "uml.h"
+#include "umldoc.h"
+#include "umlview.h"
+#include "worktoolbar.h"
+
+
+WorkToolBar::WorkToolBar(QMainWindow *parentWindow, const char*name)
+ : KToolBar(parentWindow,Qt::DockRight,false,name) {
+ m_CurrentButtonID = tbb_Undefined;
+ loadPixmaps();
+ m_Type = Uml::dt_Class; /* first time in just want it to load arrow,
+ needs anything but dt_Undefined */
+ setOrientation( Qt::Vertical );
+ setVerticalStretchable( true );
+ // initialize old tool map, everything starts with select tool (arrow)
+ m_map.insert(Uml::dt_UseCase,tbb_Arrow);
+ m_map.insert(Uml::dt_Collaboration,tbb_Arrow);
+ m_map.insert(Uml::dt_Class,tbb_Arrow);
+ m_map.insert(Uml::dt_Sequence,tbb_Arrow);
+ m_map.insert(Uml::dt_State,tbb_Arrow);
+ m_map.insert(Uml::dt_Activity,tbb_Arrow);
+ m_map.insert(Uml::dt_Undefined,tbb_Arrow);
+
+ slotCheckToolBar( Uml::dt_Undefined );
+ connect( this, SIGNAL( released( int ) ), this, SLOT( buttonChanged (int ) ) );
+}
+
+WorkToolBar::~WorkToolBar() {
+ disconnect(this, SIGNAL(released(int)),this,SLOT(buttonChanged(int)));
+}
+
+void WorkToolBar::insertHotBtn(ToolBar_Buttons tbb) {
+ insertButton(m_ToolButtons[tbb].Symbol, tbb, true, m_ToolButtons[tbb].Label);
+ setToggle(tbb, true);
+}
+
+void WorkToolBar::insertBasicAssociations() {
+ insertHotBtn(tbb_Association);
+ if (m_Type == Uml::dt_Class || m_Type == Uml::dt_UseCase) {
+ insertHotBtn(tbb_UniAssociation);
+ }
+ insertHotBtn(tbb_Dependency);
+ insertHotBtn(tbb_Generalization);
+}
+
+void WorkToolBar::slotCheckToolBar(Uml::Diagram_Type dt) {
+ if ( dt == m_Type )
+ return;
+ clear();
+ m_Type = dt;
+
+ if ( m_Type == Uml::dt_Undefined )
+ return;
+
+ //insert note, anchor and lines of text on all diagrams
+ insertHotBtn(tbb_Arrow);
+ toggleButton(tbb_Arrow);
+ m_CurrentButtonID = tbb_Arrow;
+
+ insertHotBtn(tbb_Note);
+ insertHotBtn(tbb_Anchor);
+ insertHotBtn(tbb_Text);
+ insertHotBtn(tbb_Box);
+
+ //insert diagram specific tools
+ switch (m_Type) {
+ case Uml::dt_UseCase:
+ insertHotBtn(tbb_Actor);
+ insertHotBtn(tbb_UseCase);
+ insertBasicAssociations();
+ break;
+
+ case Uml::dt_Class:
+ insertHotBtn(tbb_Class);
+ insertHotBtn(tbb_Interface);
+ insertHotBtn(tbb_Datatype);
+ insertHotBtn(tbb_Enum);
+ insertHotBtn(tbb_Package);
+ insertBasicAssociations();
+ insertHotBtn(tbb_Composition);
+ insertHotBtn(tbb_Aggregation);
+ insertHotBtn(tbb_Containment);
+ break;
+
+ case Uml::dt_Sequence:
+ insertHotBtn(tbb_Object);
+ insertHotBtn(tbb_Seq_Message_Synchronous);
+ insertHotBtn(tbb_Seq_Message_Asynchronous);
+ break;
+
+ case Uml::dt_Collaboration:
+ insertHotBtn(tbb_Object);
+ insertHotBtn(tbb_Coll_Message);
+ break;
+
+ case Uml::dt_State:
+ insertHotBtn(tbb_Initial_State);
+ insertHotBtn(tbb_State);
+ insertHotBtn(tbb_End_State);
+ insertHotBtn(tbb_State_Transition);
+ //insertHotBtn(tbb_DeepHistory); //NotYetImplemented
+ //insertHotBtn(tbb_ShallowHistory); //NotYetImplemented
+ //insertHotBtn(tbb_Join); //NotYetImplemented
+ insertHotBtn(tbb_StateFork);
+ //insertHotBtn(tbb_Junction); //NotYetImplemented
+ //insertHotBtn(tbb_Choice); //NotYetImplemented
+ //insertHotBtn(tbb_Andline); //NotYetImplemented
+ break;
+
+ case Uml::dt_Activity:
+ insertHotBtn(tbb_Initial_Activity);
+ insertHotBtn(tbb_Activity);
+ insertHotBtn(tbb_End_Activity);
+ insertHotBtn(tbb_Branch);
+ insertHotBtn(tbb_Fork);
+ insertHotBtn(tbb_Activity_Transition);
+ break;
+
+ case Uml::dt_Component:
+ insertHotBtn(tbb_Interface);
+ insertHotBtn(tbb_Component);
+ insertHotBtn(tbb_Artifact);
+ insertBasicAssociations();
+ break;
+
+ case Uml::dt_Deployment:
+ insertHotBtn(tbb_Object);
+ insertHotBtn(tbb_Interface);
+ insertHotBtn(tbb_Component);
+ insertHotBtn(tbb_Node);
+ insertBasicAssociations();
+ break;
+
+ case Uml::dt_EntityRelationship:
+ insertHotBtn(tbb_Entity);
+ insertHotBtn(tbb_Relationship);
+ break;
+
+ default:
+ kWarning() << "slotCheckToolBar() on unknown diagram type:"
+ << m_Type << endl;
+ break;
+ }
+}
+
+void WorkToolBar::buttonChanged(int b) {
+ UMLView* view = UMLApp::app()->getCurrentView();
+
+ //if trying to turn off arrow - stop it
+ ToolBar_Buttons tbb = (ToolBar_Buttons)b;
+ if (tbb == tbb_Arrow && m_CurrentButtonID == tbb_Arrow) {
+ toggleButton(tbb_Arrow);
+
+ // signal needed, in the case ( when switching diagrams ) that
+ // Arrow Button gets activated, but the toolBarState of the Views may be different
+ emit sigButtonChanged( m_CurrentButtonID );
+
+ view->setCursor( currentCursor() );
+ return;
+ }
+
+ //if toggling off a button set to arrow
+ if (tbb == m_CurrentButtonID) {
+ m_map[m_Type] = m_CurrentButtonID; // store old tool for this diagram type
+ toggleButton(tbb_Arrow);
+ m_CurrentButtonID = tbb_Arrow;
+ emit sigButtonChanged(m_CurrentButtonID);
+ view->setCursor( currentCursor() );
+ return;
+ }
+ m_map[m_Type] = m_CurrentButtonID;
+ toggleButton(m_CurrentButtonID);
+ m_CurrentButtonID = tbb;
+ emit sigButtonChanged(m_CurrentButtonID);
+ view->setCursor( currentCursor() );
+}
+
+QCursor WorkToolBar::currentCursor() {
+ return m_ToolButtons[m_CurrentButtonID].Cursor;
+}
+
+void WorkToolBar::slotResetToolBar() {
+ if (m_CurrentButtonID == tbb_Arrow)
+ return;//really shouldn't occur
+ toggleButton(m_CurrentButtonID);
+ m_CurrentButtonID = tbb_Arrow;
+ toggleButton(m_CurrentButtonID);
+ emit sigButtonChanged(m_CurrentButtonID);
+
+ QCursor curs;
+ curs.setShape(Qt::ArrowCursor);
+
+ UMLView* view = UMLApp::app()->getCurrentView();
+ if (view != NULL) {
+ view -> setCursor(curs);
+ }
+}
+
+void WorkToolBar::setOldTool() {
+ KToolBarButton *b = (KToolBarButton*) getWidget(m_map[m_Type]);
+ if (b)
+ b -> animateClick();
+}
+
+void WorkToolBar::setDefaultTool() {
+ KToolBarButton *b = (KToolBarButton*) getWidget(tbb_Arrow);
+ if (b)
+ b -> animateClick();
+}
+
+QPixmap WorkToolBar::load(const QString & fileName) {
+ QPixmap pxm;
+ pxm.load(fileName);
+ return pxm;
+}
+
+void WorkToolBar::loadPixmaps() {
+ const struct ButtonInfo {
+ const ToolBar_Buttons tbb;
+ const QString btnName;
+ const char *pngName;
+ } buttonInfo[] = {
+ { tbb_Object, i18n("Object"), "object.png" },
+ { tbb_Seq_Message_Synchronous, i18n("Synchronous Message"), "message-synchronous.png" },
+ { tbb_Seq_Message_Asynchronous, i18n("Asynchronous Message"), "message-asynchronous.png" },
+ { tbb_Association, i18n("Association"), "association.png" },
+ { tbb_Containment, i18n("Containment"), "containment.png" },
+ { tbb_Anchor, i18n("Anchor"), "anchor.png" },
+ { tbb_Text, i18n("Label"), "text.png" },
+ { tbb_Note, i18n("Note"), "note.png" },
+ { tbb_Box, i18n("Box"), "box.png" },
+ { tbb_Actor, i18n("Actor"), "actor.png" },
+ { tbb_Dependency, i18n("Dependency"), "dependency.png" },
+ { tbb_Aggregation, i18n("Aggregation"), "aggregation.png" },
+ { tbb_Relationship, i18n("Relationship"), "relationship.png" },
+ { tbb_UniAssociation, i18n("Directional Association"), "uniassociation.png" },
+ { tbb_Generalization, i18n("Implements (Generalisation/Realisation)"), "generalisation.png" },
+ { tbb_Composition, i18n("Composition"), "composition.png" },
+ { tbb_UseCase, i18n("Use Case"), "usecase.png" },
+ { tbb_Class, i18n("Class"), "class.png" },
+ { tbb_Initial_State, i18n("Initial State"), "initial_state.png" },
+ { tbb_End_State, i18n("End State"), "end_state.png" },
+ { tbb_Branch, i18n("Branch/Merge"), "branch.png" },
+ { tbb_Fork, i18n("Fork/Join"), "fork.png" },
+ { tbb_Package, i18n("Package"), "package.png" },
+ { tbb_Component, i18n("Component"), "component.png" },
+ { tbb_Node, i18n("Node"), "node.png" },
+ { tbb_Artifact, i18n("Artifact"), "artifact.png" },
+ { tbb_Interface, i18n("Interface"), "interface.png" },
+ { tbb_Datatype, i18n("Datatype"), "datatype.png" },
+ { tbb_Enum, i18n("Enum"), "enum.png" },
+ { tbb_Entity, i18n("Entity"), "entity.png" },
+ { tbb_DeepHistory, i18n("Deep History"), "deep-history.png" }, //NotYetImplemented
+ { tbb_ShallowHistory, i18n("Shallow History"), "shallow-history.png" }, //NotYetImplemented
+ { tbb_Join, i18n("Join"), "join.png" }, //NotYetImplemented
+ { tbb_StateFork, i18n("Fork"), "state-fork.png" },
+ { tbb_Junction, i18n("Junction"), "junction.png" }, //NotYetImplemented
+ { tbb_Choice, i18n("Choice"), "choice-round.png" }, //NotYetImplemented
+ //:TODO: let the user decide which symbol he wants (setting an option)
+ // { tbb_Choice, i18n("Choice"), "choice-rhomb.png" }, //NotYetImplemented
+ //{ tbb_Andline, i18n("And Line"), "andline.png" }, //NotYetImplemented
+ { tbb_State_Transition, i18n("State Transition"), "uniassociation.png" },
+ { tbb_Activity_Transition, i18n("Activity Transition"), "uniassociation.png" },
+ { tbb_Activity, i18n("Activity"), "usecase.png" },
+ { tbb_State, i18n("State"), "usecase.png" },
+ { tbb_End_Activity, i18n("End Activity"), "end_state.png" },
+ { tbb_Initial_Activity, i18n("Initial Activity"), "initial_state.png" },
+ { tbb_Coll_Message, i18n("Message"), "message-asynchronous.png" }
+ };
+ KStandardDirs * dirs = KGlobal::dirs();
+ QString dataDir = dirs->findResourceDir( "data", "umbrello/pics/object.png" );
+ dataDir += "/umbrello/pics/";
+ const size_t n_buttonInfos = sizeof(buttonInfo) / sizeof(ButtonInfo);
+
+ m_ToolButtons.insert(tbb_Undefined,
+ ToolButton(i18n("UNDEFINED"),
+ 0,
+ QCursor()) );
+ m_ToolButtons.insert(tbb_Arrow,
+ ToolButton(i18n("Select"),
+ load(dataDir + "arrow.png"),
+ QCursor()) );
+ kDebug() << "WorkToolBar::loadPixmaps: n_buttonInfos = " << n_buttonInfos << endl;
+ for (uint i = 0; i < n_buttonInfos; i++) {
+ const ButtonInfo& info = buttonInfo[i];
+ m_ToolButtons.insert(info.tbb,
+ ToolButton(info.btnName,
+ load(dataDir + info.pngName),
+ QCursor(load(dataDir + "cursor-" + info.pngName), 9, 9)));
+ }
+}
+
+#include "worktoolbar.moc"
diff --git a/umbrello/umbrello/worktoolbar.h b/umbrello/umbrello/worktoolbar.h
new file mode 100644
index 00000000..92012dde
--- /dev/null
+++ b/umbrello/umbrello/worktoolbar.h
@@ -0,0 +1,183 @@
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * copyright (C) 2002-2007 *
+ * Umbrello UML Modeller Authors <uml-devel@uml.sf.net> *
+ ***************************************************************************/
+
+#ifndef WORKTOOLBAR_H
+#define WORKTOOLBAR_H
+
+#include <qmap.h>
+#include <qpixmap.h>
+#include <qcursor.h>
+#include <ktoolbar.h>
+
+#include "umlnamespace.h"
+
+class QMainWindow;
+
+
+/**
+ * This is the toolbar that is displayed on the right-hand side of the program
+ * window. For each type of diagram it will change to suit that document.
+ *
+ * To add a new tool button do the following:
+ * - create a button pixmap (symbol)
+ * - create a cursor pixmap
+ * - add an element to the ToolBar_Buttons enum
+ * - adjust function loadPixmaps
+ * - adjust function slotCheckToolBar
+ *
+ * @short The toolbar that is different for each type of diagram.
+ * @author Paul Hensgen <phensgen@techie.com>
+ * Bugs and comments to uml-devel@lists.sf.net or http://bugs.kde.org
+ */
+
+
+class WorkToolBar : public KToolBar {
+ Q_OBJECT
+public:
+
+ /**
+ * Creates a work tool bar.
+ *
+ * @param parentWindow The parent of the toolbar.
+ */
+ WorkToolBar(QMainWindow *parentWindow, const char *name);
+
+ /**
+ * Standard deconstructor.
+ */
+ ~WorkToolBar();
+
+ /**
+ * Sets the current tool to the previously used Tool. This is just
+ * as if the user had pressed the button for the other tool.
+ */
+ void setOldTool();
+
+ /**
+ * Sets the current tool to the default tool. (select tool)
+ * Calling this function is as if the user had pressed the "arrow"
+ * button on the toolbar.
+ */
+ void setDefaultTool();
+
+ /**
+ * Enumeration of all available toolbar buttons.
+ */
+ enum ToolBar_Buttons
+ {
+ tbb_Undefined = -1,
+ tbb_Arrow,
+ tbb_Generalization,
+ tbb_Aggregation,
+ tbb_Dependency,
+ tbb_Association,
+ tbb_Containment,
+ tbb_Coll_Message,
+ tbb_Seq_Message_Synchronous,
+ tbb_Seq_Message_Asynchronous,
+ tbb_Composition,
+ tbb_Relationship,
+ tbb_UniAssociation,
+ tbb_State_Transition,
+ tbb_Activity_Transition,
+ tbb_Anchor,//keep anchor as last association until code uses better algorithm for testing
+ tbb_Note,
+ tbb_Box,
+ tbb_Text,
+ tbb_Actor,
+ tbb_UseCase,
+ tbb_Class,
+ tbb_Interface,
+ tbb_Datatype,
+ tbb_Enum,
+ tbb_Entity,
+ tbb_Package,
+ tbb_Component,
+ tbb_Node,
+ tbb_Artifact,
+ tbb_Object,
+ tbb_Initial_State,
+ tbb_State,
+ tbb_End_State,
+ tbb_Initial_Activity,
+ tbb_Activity,
+ tbb_End_Activity,
+ tbb_Branch,
+ tbb_Fork,
+ tbb_DeepHistory,
+ tbb_ShallowHistory,
+ tbb_Join,
+ tbb_StateFork,
+ tbb_Junction,
+ tbb_Choice,
+ tbb_Andline
+ };
+
+private:
+
+ typedef QMap<Uml::Diagram_Type,ToolBar_Buttons> OldToolMap;
+
+ /**
+ * This inner class holds label, symbol, and cursor of a tool button.
+ */
+ class ToolButton {
+ public:
+ QString Label;
+ QPixmap Symbol;
+ QCursor Cursor;
+ ToolButton() : Label(QString("?")), Symbol(QPixmap()), Cursor(QCursor()) { }
+ ToolButton(const QString& lbl, const QPixmap& smb, const QCursor& cur) :
+ Label(lbl), Symbol(smb), Cursor(cur) { }
+ };
+
+ typedef QMap<ToolBar_Buttons, ToolButton> ToolButtonMap;
+
+ ToolBar_Buttons m_CurrentButtonID;
+ OldToolMap m_map;
+ Uml::Diagram_Type m_Type;
+ ToolButtonMap m_ToolButtons;
+
+ /**
+ * Loads a pixmap from file
+ */
+ QPixmap load(const QString &fileName);
+
+ /**
+ * Loads toolbar icon and mouse cursor images from disk
+ */
+ void loadPixmaps();
+
+ /**
+ * Returns the current cursor depending on m_CurrentButtonID
+ */
+ QCursor currentCursor();
+
+ /**
+ * Inserts the button corresponding to the tbb value given
+ * and activates the toggle.
+ */
+ void insertHotBtn(ToolBar_Buttons tbb);
+
+ /**
+ * Inserts most associations, just reduces some string
+ * duplication (nice to translators)
+ */
+ void insertBasicAssociations();
+
+signals:
+ void sigButtonChanged(int);
+public slots:
+ void slotCheckToolBar(Uml::Diagram_Type dt);
+ void buttonChanged(int b);
+ void slotResetToolBar();
+};
+
+#endif
diff --git a/umbrello/umbrello/x-umbrello.desktop b/umbrello/umbrello/x-umbrello.desktop
new file mode 100644
index 00000000..d8aaeb50
--- /dev/null
+++ b/umbrello/umbrello/x-umbrello.desktop
@@ -0,0 +1,53 @@
+[Desktop Entry]
+Type=MimeType
+MimeType=application/x-uml
+Icon=umbrellofile
+DefaultApp=umbrello
+Patterns=*.xmi;*.XMI;*.xmi.tgz;*.xmi.tar.bz2;
+Comment=Umbrello UML Modeller File
+Comment[bg]=Файл Umbrello UML Modeller
+Comment[bs]=Umbrello UML modeler datoteka
+Comment[ca]=Fitxer de model UML
+Comment[cs]=Soubor UML modeláře Umbrello
+Comment[cy]=Ffeil Modelydd UML Umbrello
+Comment[da]=Umbrello UML-fil
+Comment[de]=Umbrello-Datei
+Comment[el]=ΑÏχείο μοντελοποιητή UML Umbrello
+Comment[eo]=Dosiero de Umbrello UML-Modelilo
+Comment[es]=Archivo del modeladore UML Umbrello
+Comment[et]=Umbrello UML-fail
+Comment[eu]=Umbrello UML modelatzaile fitxategia
+Comment[fa]=پروندۀ مدل‌ساز Umbrello UML
+Comment[fi]=Umbrello UML -mallinnustiedosto
+Comment[fr]=Fichier du modeleur UML Umbrello
+Comment[ga]=Comhad le haghaidh an Mhúnlóra UML Umbrello
+Comment[gl]=Ficheiro UML de Umbrello
+Comment[hi]=अमà¥à¤¬à¤°à¥ˆà¤²à¥‹ यूà¤à¤®à¤à¤² मॉडलर फ़ाइल
+Comment[hu]=Umbrello UML-fájl
+Comment[is]=Umbrello UML Modeller Skrá
+Comment[it]=File del modellatore UML Umbrello
+Comment[ja]=Umbrello UML モデラーファイル
+Comment[ka]=Umbrello UML მáƒáƒ“ელერის ფáƒáƒ˜áƒšáƒ˜
+Comment[kk]=Umbrello UML үлгілегішінің файлы
+Comment[lt]=Umbrello UML Modeller byla
+Comment[ms]=Fail Pemodel Umbrello UML
+Comment[nb]=Umbrello UML-modelleringsfil
+Comment[nds]=UML-Modellmaker-Datei vun Umbrello
+Comment[ne]=अमà¥à¤¬à¥à¤°à¥‡à¤²à¥‹ यूà¤à¤®à¤à¤² मोडेलर फाइल
+Comment[nl]=Umbrello UML Modeller-bestand
+Comment[nn]=Umbrello UML-modelleringsfil
+Comment[pl]=Plik modelera UML Umbrello
+Comment[pt]=Ficheiro do Modelador de UML Umbrello
+Comment[pt_BR]=Arquivo de Modelador UML Umbrello
+Comment[ru]=Файл Ð¼Ð¾Ð´ÐµÐ»Ð¸Ñ€Ð¾Ð²Ð°Ð½Ð¸Ñ UML Umbrello
+Comment[sk]=Súbor pre Umbrello modelár UML
+Comment[sl]=Datoteka za modelirnik Umbrello UML
+Comment[sr]=Фајл Umbrello-а, UML моделара
+Comment[sr@Latn]=Fajl Umbrello-a, UML modelara
+Comment[sv]=Umbrello UML-modelleringsfil
+Comment[ta]= à®…à®®à¯à®°à®²à¯à®²à¯‹ UML மாடà¯à®²à®°à¯ கோபà¯à®ªà¯
+Comment[tg]=Файли моделкунонии UML Umbrello
+Comment[tr]=Umbrello UML Modelleyici Dosyası
+Comment[uk]=Файл Ð¼Ð¾Ð´ÐµÐ»ÑŽÐ²Ð°Ð½Ð½Ñ UML Umbrello
+Comment[zh_CN]=Umbrello UML 建模工具文件
+Comment[zh_TW]=Umbrello UML Modeller 檔案
diff --git a/umbrello/uml.kdevprj b/umbrello/uml.kdevprj
new file mode 100644
index 00000000..284aee44
--- /dev/null
+++ b/umbrello/uml.kdevprj
@@ -0,0 +1,2154 @@
+[Config for BinMakefileAm]
+addcxxflags=
+bin_program=umbrello
+cflags=
+cppflags=
+cxxflags=\s-O0 -g3 -Wall
+ldadd=-lfl $(LIB_KDEPRINT) $(LIB_KDEUI) $(LIB_KDECORE) $(LIB_QT)
+ldflags=\s -Iuml/classparser -Iuml/dialogs -Iuml/clipboard
+
+[General]
+AMChanged=true
+author=Umbrello UML Modeller Authors
+configure_args=\s--build=i386-linux --host=i386-linux --target=i386-linux --prefix=/opt/kde3 --enable-debug\s
+email=uml-devel@lists.sourceforge.net
+kdevprj_version=1.3
+lfv_open_groups=
+make_options=\s-j1
+makefiles=uml.spec.in,Makefile.am,uml/Makefile.am,doc/Makefile.am,doc/en/Makefile.am,po/Makefile.am,uml/classparser/Makefile.am,uml/clipboard/Makefile.am,uml/dialogs/Makefile.am,uml/pics/Makefile.am,doc/en/pics/Makefile.am,uml/codegenerators/Makefile.am,uml/headings/Makefile.am,doc/de/Makefile.am,doc/de/pics/Makefile.am
+modifyMakefiles=true
+project_name=Umbrello
+project_type=normal_kde2
+short_info=Umbrello UML Modeller
+showNonProjectFiles=true
+sub_dir=uml/
+version=1.1rc1
+version_control=CVS
+workspace=1
+
+[KPP]
+kpp_appgrp=
+kpp_bldroot=
+kpp_icon=0
+kpp_license=5
+kpp_summary=
+kpp_url=
+kpp_version=1.1
+
+[LFV Groups]
+Headers=*.h,*.hh,*.hxx,*.hpp,*.H
+Others=*
+Sources=*.cpp,*.c,*.cc,*.C,*.cxx,*.ec,*.ecpp,*.lxx,*.l++,*.ll,*.l
+Translations=*.po
+User Interface=*.kdevdlg,*.ui,*.rc,*.dlg
+groups=Headers,Sources,User Interface,Translations,Others
+
+[Makefile.am]
+files=uml.kdevprj,admin,uml.spec.in
+sub_dirs=uml,po,doc
+type=normal
+
+[admin]
+dist=true
+install=false
+install_location=
+type=DATA
+
+[doc/Makefile.am]
+sub_dirs=en,de
+type=normal
+
+[doc/de/Makefile.am]
+files=doc/de/authors.docbook,doc/de/code_import_and_generation.docbook,doc/de/faq.docbook,doc/de/index.docbook,doc/de/installation.docbook,doc/de/introduction.docbook,doc/de/working_with_umbrello.docbook,doc/de/menu_reference.docbook,doc/de/other_features.docbook,doc/de/uml_basics.docbook
+sub_dirs=pics
+type=normal
+
+[doc/de/authors.docbook]
+dist=true
+install=false
+install_location=
+type=DATA
+
+[doc/de/code_import_and_generation.docbook]
+dist=true
+install=false
+install_location=
+type=DATA
+
+[doc/de/faq.docbook]
+dist=true
+install=false
+install_location=
+type=DATA
+
+[doc/de/index.docbook]
+dist=true
+install=false
+install_location=
+type=DATA
+
+[doc/de/installation.docbook]
+dist=true
+install=false
+install_location=
+type=DATA
+
+[doc/de/introduction.docbook]
+dist=true
+install=false
+install_location=
+type=DATA
+
+[doc/de/menu_reference.docbook]
+dist=true
+install=false
+install_location=
+type=DATA
+
+[doc/de/other_features.docbook]
+dist=true
+install=false
+install_location=
+type=DATA
+
+[doc/de/pics/Makefile.am]
+files=doc/de/pics/activity-diagram.png,doc/de/pics/add-remove-languages.png,doc/de/pics/aggregation.png,doc/de/pics/association.png,doc/de/pics/class-diagram.png,doc/de/pics/class.png,doc/de/pics/code-import.png,doc/de/pics/collaboration-diagram.png,doc/de/pics/composition.png,doc/de/pics/folders.png,doc/de/pics/generalization.png,doc/de/pics/generation-options.png,doc/de/pics/sequence-diagram.png,doc/de/pics/state-diagram.png,doc/de/pics/umbrello-main-screen.png,doc/de/pics/umbrello-ui-clean.png,doc/de/pics/umbrello-ui.png,doc/de/pics/use-case-diagram.png
+sub_dirs=
+type=normal
+
+[doc/de/pics/activity-diagram.png]
+dist=true
+install=true
+install_location=$$(kde_htmldir)/de/umbrello/pics/activity-diagram.png
+type=DATA
+
+[doc/de/pics/add-remove-languages.png]
+dist=true
+install=true
+install_location=$$(kde_htmldir)/de/umbrello/pics/add-remove-languages.png
+type=DATA
+
+[doc/de/pics/aggregation.png]
+dist=true
+install=true
+install_location=$$(kde_htmldir)/de/umbrello/pics/aggregation.png
+type=DATA
+
+[doc/de/pics/association.png]
+dist=true
+install=true
+install_location=$$(kde_htmldir)/de/umbrello/pics/association.png
+type=DATA
+
+[doc/de/pics/class-diagram.png]
+dist=true
+install=true
+install_location=$$(kde_htmldir)/de/umbrello/pics/class-diagram.png
+type=DATA
+
+[doc/de/pics/class.png]
+dist=true
+install=true
+install_location=$$(kde_htmldir)/de/umbrello/pics/class.png
+type=DATA
+
+[doc/de/pics/code-import.png]
+dist=true
+install=true
+install_location=$$(kde_htmldir)/de/umbrello/pics/code-import.png
+type=DATA
+
+[doc/de/pics/collaboration-diagram.png]
+dist=true
+install=true
+install_location=$$(kde_htmldir)/de/umbrello/pics/collaboration-diagram.png
+type=DATA
+
+[doc/de/pics/composition.png]
+dist=true
+install=true
+install_location=$$(kde_htmldir)/de/umbrello/pics/composition.png
+type=DATA
+
+[doc/de/pics/folders.png]
+dist=true
+install=true
+install_location=$$(kde_htmldir)/de/umbrello/pics/folders.png
+type=DATA
+
+[doc/de/pics/generalization.png]
+dist=true
+install=true
+install_location=$$(kde_htmldir)/de/umbrello/pics/generalization.png
+type=DATA
+
+[doc/de/pics/generation-options.png]
+dist=true
+install=true
+install_location=$$(kde_htmldir)/de/umbrello/pics/generation-options.png
+type=DATA
+
+[doc/de/pics/sequence-diagram.png]
+dist=true
+install=true
+install_location=$$(kde_htmldir)/de/umbrello/pics/sequence-diagram.png
+type=DATA
+
+[doc/de/pics/state-diagram.png]
+dist=true
+install=true
+install_location=$$(kde_htmldir)/de/umbrello/pics/state-diagram.png
+type=DATA
+
+[doc/de/pics/umbrello-main-screen.png]
+dist=true
+install=true
+install_location=$$(kde_htmldir)/de/umbrello/pics/umbrello-main-screen.png
+type=DATA
+
+[doc/de/pics/umbrello-ui-clean.png]
+dist=true
+install=true
+install_location=$$(kde_htmldir)/de/umbrello/pics/umbrello-ui-clean.png
+type=DATA
+
+[doc/de/pics/umbrello-ui.png]
+dist=true
+install=true
+install_location=$$(kde_htmldir)/de/umbrello/pics/umbrello-ui.png
+type=DATA
+
+[doc/de/pics/use-case-diagram.png]
+dist=true
+install=true
+install_location=$$(kde_htmldir)/de/umbrello/pics/use-case-diagram.png
+type=DATA
+
+[doc/de/uml_basics.docbook]
+dist=true
+install=false
+install_location=
+type=DATA
+
+[doc/de/working_with_umbrello.docbook]
+dist=true
+install=false
+install_location=
+type=DATA
+
+[doc/en/Makefile.am]
+files=doc/en/index.docbook,doc/en/introduction.docbook,doc/en/uml_basics.docbook,doc/en/installation.docbook,doc/en/faq.docbook,doc/en/menu_reference.docbook,doc/en/code_import_and_generation.docbook,doc/en/authors.docbook,doc/en/error_msgs.docbook,doc/en/working_with_umbrello.docbook,doc/en/other_features.docbook
+sub_dirs=pics
+type=normal
+
+[doc/en/authors.docbook]
+dist=true
+install=false
+install_location=
+type=DATA
+
+[doc/en/code_import_and_generation.docbook]
+dist=true
+install=false
+install_location=
+type=DATA
+
+[doc/en/error_msgs.docbook]
+dist=true
+install=false
+install_location=
+type=DATA
+
+[doc/en/faq.docbook]
+dist=true
+install=false
+install_location=
+type=DATA
+
+[doc/en/index.docbook]
+dist=true
+install=true
+install_location=$$(kde_htmldir)/en/umbrello/index.docbook
+type=DATA
+
+[doc/en/installation.docbook]
+dist=true
+install=false
+install_location=
+type=DATA
+
+[doc/en/introduction.docbook]
+dist=true
+install=false
+install_location=
+type=DATA
+
+[doc/en/menu_reference.docbook]
+dist=true
+install=false
+install_location=
+type=DATA
+
+[doc/en/other_features.docbook]
+dist=true
+install=false
+install_location=
+type=DATA
+
+[doc/en/pics/Makefile.am]
+files=doc/en/pics/add-remove-languages.png,doc/en/pics/aggregation.png,doc/en/pics/association.png,doc/en/pics/class-diagram.png,doc/en/pics/class.png,doc/en/pics/code-import.png,doc/en/pics/collaboration-diagram.png,doc/en/pics/composition.png,doc/en/pics/folders.png,doc/en/pics/generalization.png,doc/en/pics/generation-options.png,doc/en/pics/sequence-diagram.png,doc/en/pics/state-diagram.png,doc/en/pics/umbrello-main-screen.png,doc/en/pics/umbrello-ui.png,doc/en/pics/umbrello-ui-clean.png,doc/en/pics/activity-diagram.png,doc/en/pics/use-case-diagram.png
+sub_dirs=
+type=normal
+
+[doc/en/pics/activity-diagram.png]
+dist=true
+install=true
+install_location=$$(kde_htmldir)/en/umbrello/pics/activity-diagram.png
+type=DATA
+
+[doc/en/pics/add-remove-languages.png]
+dist=true
+install=true
+install_location=$$(kde_htmldir)/en/umbrello/pics/add-remove-languages.png
+type=DATA
+
+[doc/en/pics/aggregation.png]
+dist=true
+install=true
+install_location=$$(kde_htmldir)/en/umbrello/pics/aggregation.png
+type=DATA
+
+[doc/en/pics/association.png]
+dist=true
+install=true
+install_location=$$(kde_htmldir)/en/umbrello/pics/association.png
+type=DATA
+
+[doc/en/pics/class-diagram.png]
+dist=true
+install=true
+install_location=$$(kde_htmldir)/en/umbrello/pics/class-diagram.png
+type=DATA
+
+[doc/en/pics/class.png]
+dist=true
+install=true
+install_location=$$(kde_htmldir)/en/umbrello/pics/class.png
+type=DATA
+
+[doc/en/pics/code-import.png]
+dist=true
+install=true
+install_location=$$(kde_htmldir)/en/umbrello/pics/code-import.png
+type=DATA
+
+[doc/en/pics/collaboration-diagram.png]
+dist=true
+install=true
+install_location=$$(kde_htmldir)/en/umbrello/pics/collaboration-diagram.png
+type=DATA
+
+[doc/en/pics/composition.png]
+dist=true
+install=true
+install_location=$$(kde_htmldir)/en/umbrello/pics/composition.png
+type=DATA
+
+[doc/en/pics/folders.png]
+dist=true
+install=true
+install_location=$$(kde_htmldir)/en/umbrello/pics/folders.png
+type=DATA
+
+[doc/en/pics/generalization.png]
+dist=true
+install=true
+install_location=$$(kde_htmldir)/en/umbrello/pics/generalization.png
+type=DATA
+
+[doc/en/pics/generation-options.png]
+dist=true
+install=true
+install_location=$$(kde_htmldir)/en/umbrello/pics/generation-options.png
+type=DATA
+
+[doc/en/pics/sequence-diagram.png]
+dist=true
+install=true
+install_location=$$(kde_htmldir)/en/umbrello/pics/sequence-diagram.png
+type=DATA
+
+[doc/en/pics/state-diagram.png]
+dist=true
+install=true
+install_location=$$(kde_htmldir)/en/umbrello/pics/state-diagram.png
+type=DATA
+
+[doc/en/pics/umbrello-main-screen.png]
+dist=true
+install=true
+install_location=$$(kde_htmldir)/en/umbrello/pics/umbrello-main-screen.png
+type=DATA
+
+[doc/en/pics/umbrello-ui-clean.png]
+dist=true
+install=false
+install_location=
+type=DATA
+
+[doc/en/pics/umbrello-ui.png]
+dist=true
+install=true
+install_location=$$(kde_htmldir)/en/umbrello/pics/umbrello-ui.png
+type=DATA
+
+[doc/en/pics/use-case-diagram.png]
+dist=true
+install=true
+install_location=$$(kde_htmldir)/en/umbrello/pics/use-case-diagram.png
+type=DATA
+
+[doc/en/uml_basics.docbook]
+dist=true
+install=false
+install_location=
+type=DATA
+
+[doc/en/working_with_umbrello.docbook]
+dist=true
+install=false
+install_location=
+type=DATA
+
+[po/Makefile.am]
+sub_dirs=
+type=po
+
+[uml.kdevprj]
+dist=true
+install=false
+install_location=
+type=DATA
+
+[uml.spec.in]
+dist=true
+install=false
+install_location=
+type=DATA
+
+[uml/Makefile.am]
+files=uml/actor.h,uml/actorwidgetdata.h,uml/actorwidget.h,uml/associationwidgetdata.h,uml/associationwidgetdatalist.h,uml/associationwidget.h,uml/assocrules.h,uml/attribute.h,uml/concept.h,uml/conceptwidgetdata.h,uml/conceptwidget.h,uml/docwindow.h,uml/floatingtextdata.h,uml/floatingtext.h,uml/infowidget.h,uml/kstartuplogo.h,uml/linepath.h,uml/listpopupmenu.h,uml/messagewidgetdata.h,uml/messagewidget.h,uml/actor.cpp,uml/actorwidget.cpp,uml/actorwidgetdata.cpp,uml/associationwidget.cpp,uml/associationwidgetdata.cpp,uml/assocrules.cpp,uml/attribute.cpp,uml/concept.cpp,uml/conceptwidget.cpp,uml/conceptwidgetdata.cpp,uml/docwindow.cpp,uml/floatingtext.cpp,uml/floatingtextdata.cpp,uml/infowidget.cpp,uml/kstartuplogo.cpp,uml/linepath.cpp,uml/listpopupmenu.cpp,uml/main.cpp,uml/messagewidget.cpp,uml/messagewidgetdata.cpp,uml/notewidget.cpp,uml/notewidgetdata.cpp,uml/notewidgetdata.h,uml/notewidget.h,uml/objectwidget.cpp,uml/objectwidgetdata.cpp,uml/objectwidgetdata.h,uml/objectwidget.h,uml/operation.cpp,uml/operation.h,uml/statewidget.cpp,uml/statewidgetdata.cpp,uml/statewidgetdata.h,uml/statewidget.h,uml/uml.cpp,uml/umldoc.cpp,uml/umldoc.h,uml/uml.h,uml/umlnamespace.cpp,uml/umlnamespace.h,uml/umlobject.cpp,uml/umlobject.h,uml/umlobjectlist.h,uml/umlviewcanvas.cpp,uml/umlviewcanvas.h,uml/umlview.cpp,uml/umlviewdata.cpp,uml/umlviewdata.h,uml/umlview.h,uml/umlviewlist.h,uml/umlwidget.cpp,uml/umlwidgetdata.cpp,uml/umlwidgetdata.h,uml/umlwidget.h,uml/umlwidgetlist.h,uml/usecase.cpp,uml/usecase.h,uml/usecasewidget.cpp,uml/usecasewidgetdata.cpp,uml/usecasewidgetdata.h,uml/usecasewidget.h,uml/worktoolbar.cpp,uml/worktoolbar.h,uml/hi16-app-uml.png,uml/hi32-app-uml.png,uml/lo16-app-uml.png,uml/lo32-app-uml.png,uml/tips,uml/uml.desktop,uml/umlui.rc,uml/x-uml.desktop,uml/activitywidgetdata.cpp,uml/activitywidgetdata.h,uml/activitywidget.cpp,uml/activitywidget.h,uml/codegenerator.cpp,uml/codegenerator.h,uml/seqlinewidget.cpp,uml/seqlinewidget.h,uml/umllistview.cpp,uml/umllistview.h,uml/umllistviewitem.cpp,uml/umllistviewitem.h,uml/umllistviewitemdata.cpp,uml/umllistviewitemdata.h,uml/umllistviewitemdatalist.h,uml/classimport.cpp,uml/classimport.h,uml/umllistviewitemlist.h
+sub_dirs=classparser,clipboard,dialogs,pics,codegenerators,headings
+type=prog_main
+
+[uml/activitywidget.cpp]
+dist=true
+install=false
+install_location=
+type=SOURCE
+
+[uml/activitywidget.h]
+dist=true
+install=false
+install_location=
+type=HEADER
+
+[uml/activitywidgetdata.cpp]
+dist=true
+install=false
+install_location=
+type=SOURCE
+
+[uml/activitywidgetdata.h]
+dist=true
+install=false
+install_location=
+type=HEADER
+
+[uml/actor.cpp]
+dist=true
+install=false
+install_location=
+type=SOURCE
+
+[uml/actor.h]
+dist=true
+install=false
+install_location=
+type=HEADER
+
+[uml/actorwidget.cpp]
+dist=true
+install=false
+install_location=
+type=SOURCE
+
+[uml/actorwidget.h]
+dist=true
+install=false
+install_location=
+type=HEADER
+
+[uml/actorwidgetdata.cpp]
+dist=true
+install=false
+install_location=
+type=SOURCE
+
+[uml/actorwidgetdata.h]
+dist=true
+install=false
+install_location=
+type=HEADER
+
+[uml/associationwidget.cpp]
+dist=true
+install=false
+install_location=
+type=SOURCE
+
+[uml/associationwidget.h]
+dist=true
+install=false
+install_location=
+type=HEADER
+
+[uml/associationwidgetdata.cpp]
+dist=true
+install=false
+install_location=
+type=SOURCE
+
+[uml/associationwidgetdata.h]
+dist=true
+install=false
+install_location=
+type=HEADER
+
+[uml/associationwidgetdatalist.h]
+dist=true
+install=false
+install_location=
+type=HEADER
+
+[uml/assocrules.cpp]
+dist=true
+install=false
+install_location=
+type=SOURCE
+
+[uml/assocrules.h]
+dist=true
+install=false
+install_location=
+type=HEADER
+
+[uml/attribute.cpp]
+dist=true
+install=false
+install_location=
+type=SOURCE
+
+[uml/attribute.h]
+dist=true
+install=false
+install_location=
+type=HEADER
+
+[uml/classimport.cpp]
+dist=true
+install=false
+install_location=
+type=SOURCE
+
+[uml/classimport.h]
+dist=true
+install=false
+install_location=
+type=HEADER
+
+[uml/classparser/ClassParser.cc]
+dist=true
+install=false
+install_location=
+type=SOURCE
+
+[uml/classparser/ClassParser.h]
+dist=true
+install=false
+install_location=
+type=HEADER
+
+[uml/classparser/ClassStore.cc]
+dist=true
+install=false
+install_location=
+type=SOURCE
+
+[uml/classparser/ClassStore.h]
+dist=true
+install=false
+install_location=
+type=HEADER
+
+[uml/classparser/ClassTreeNode.cc]
+dist=true
+install=false
+install_location=
+type=SOURCE
+
+[uml/classparser/ClassTreeNode.h]
+dist=true
+install=false
+install_location=
+type=HEADER
+
+[uml/classparser/Makefile.am]
+files=uml/classparser/ClassParser.h,uml/classparser/ClassStore.h,uml/classparser/ClassTreeNode.h,uml/classparser/ParsedArgument.h,uml/classparser/ParsedAttribute.h,uml/classparser/ParsedClassContainer.h,uml/classparser/ParsedClass.h,uml/classparser/ParsedContainer.h,uml/classparser/ParsedItem.h,uml/classparser/ParsedMethod.h,uml/classparser/ParsedParent.h,uml/classparser/ParsedScopeContainer.h,uml/classparser/ParsedSignalSlot.h,uml/classparser/ParsedStruct.h,uml/classparser/PersistantClassStore.h,uml/classparser/ProgrammingByContract.h,uml/classparser/tokenizer.h,uml/classparser/ClassParser.cc,uml/classparser/ClassStore.cc,uml/classparser/ClassTreeNode.cc,uml/classparser/ParsedArgument.cc,uml/classparser/ParsedAttribute.cc,uml/classparser/ParsedClass.cc,uml/classparser/ParsedClassContainer.cc,uml/classparser/ParsedContainer.cc,uml/classparser/ParsedItem.cc,uml/classparser/ParsedMethod.cc,uml/classparser/ParsedParent.cc,uml/classparser/ParsedScopeContainer.cc,uml/classparser/ParsedSignalSlot.cc,uml/classparser/ParsedStruct.cc,uml/classparser/PersistantClassStore.cc,uml/classparser/tokenizer.cc
+sharedlib_LDFLAGS=
+sharedlib_rootname=
+sub_dirs=
+type=static_library
+
+[uml/classparser/ParsedArgument.cc]
+dist=true
+install=false
+install_location=
+type=SOURCE
+
+[uml/classparser/ParsedArgument.h]
+dist=true
+install=false
+install_location=
+type=HEADER
+
+[uml/classparser/ParsedAttribute.cc]
+dist=true
+install=false
+install_location=
+type=SOURCE
+
+[uml/classparser/ParsedAttribute.h]
+dist=true
+install=false
+install_location=
+type=HEADER
+
+[uml/classparser/ParsedClass.cc]
+dist=true
+install=false
+install_location=
+type=SOURCE
+
+[uml/classparser/ParsedClass.h]
+dist=true
+install=false
+install_location=
+type=HEADER
+
+[uml/classparser/ParsedClassContainer.cc]
+dist=true
+install=false
+install_location=
+type=SOURCE
+
+[uml/classparser/ParsedClassContainer.h]
+dist=true
+install=false
+install_location=
+type=HEADER
+
+[uml/classparser/ParsedContainer.cc]
+dist=true
+install=false
+install_location=
+type=SOURCE
+
+[uml/classparser/ParsedContainer.h]
+dist=true
+install=false
+install_location=
+type=HEADER
+
+[uml/classparser/ParsedItem.cc]
+dist=true
+install=false
+install_location=
+type=SOURCE
+
+[uml/classparser/ParsedItem.h]
+dist=true
+install=false
+install_location=
+type=HEADER
+
+[uml/classparser/ParsedMethod.cc]
+dist=true
+install=false
+install_location=
+type=SOURCE
+
+[uml/classparser/ParsedMethod.h]
+dist=true
+install=false
+install_location=
+type=HEADER
+
+[uml/classparser/ParsedParent.cc]
+dist=true
+install=false
+install_location=
+type=SOURCE
+
+[uml/classparser/ParsedParent.h]
+dist=true
+install=false
+install_location=
+type=HEADER
+
+[uml/classparser/ParsedScopeContainer.cc]
+dist=true
+install=false
+install_location=
+type=SOURCE
+
+[uml/classparser/ParsedScopeContainer.h]
+dist=true
+install=false
+install_location=
+type=HEADER
+
+[uml/classparser/ParsedSignalSlot.cc]
+dist=true
+install=false
+install_location=
+type=SOURCE
+
+[uml/classparser/ParsedSignalSlot.h]
+dist=true
+install=false
+install_location=
+type=HEADER
+
+[uml/classparser/ParsedStruct.cc]
+dist=true
+install=false
+install_location=
+type=SOURCE
+
+[uml/classparser/ParsedStruct.h]
+dist=true
+install=false
+install_location=
+type=HEADER
+
+[uml/classparser/PersistantClassStore.cc]
+dist=true
+install=false
+install_location=
+type=SOURCE
+
+[uml/classparser/PersistantClassStore.h]
+dist=true
+install=false
+install_location=
+type=HEADER
+
+[uml/classparser/ProgrammingByContract.h]
+dist=true
+install=false
+install_location=
+type=HEADER
+
+[uml/classparser/tokenizer.cc]
+dist=true
+install=false
+install_location=
+type=SOURCE
+
+[uml/classparser/tokenizer.h]
+dist=true
+install=false
+install_location=
+type=HEADER
+
+[uml/clipboard/Makefile.am]
+files=uml/clipboard/idchangelog.cpp,uml/clipboard/idchangelog.h,uml/clipboard/umlclipboard.cpp,uml/clipboard/umlclipboard.h,uml/clipboard/umldrag.cpp,uml/clipboard/umldrag.h
+sharedlib_LDFLAGS=-version-info 0:0:0
+sharedlib_rootname=clipboard
+sub_dirs=
+type=static_library
+
+[uml/clipboard/idchangelog.cpp]
+dist=true
+install=false
+install_location=
+type=SOURCE
+
+[uml/clipboard/idchangelog.h]
+dist=true
+install=false
+install_location=
+type=HEADER
+
+[uml/clipboard/umlclipboard.cpp]
+dist=true
+install=false
+install_location=
+type=SOURCE
+
+[uml/clipboard/umlclipboard.h]
+dist=true
+install=false
+install_location=
+type=HEADER
+
+[uml/clipboard/umldrag.cpp]
+dist=true
+install=false
+install_location=
+type=SOURCE
+
+[uml/clipboard/umldrag.h]
+dist=true
+install=false
+install_location=
+type=HEADER
+
+[uml/codegenerator.cpp]
+dist=true
+install=false
+install_location=
+type=SOURCE
+
+[uml/codegenerator.h]
+dist=true
+install=false
+install_location=
+type=HEADER
+
+[uml/codegenerators/Makefile.am]
+files=uml/codegenerators/cppwriter.cpp,uml/codegenerators/cppwriter.h,uml/codegenerators/factory.cpp,uml/codegenerators/javawriter.cpp,uml/codegenerators/javawriter.h,uml/codegenerators/phpwriter.cpp,uml/codegenerators/phpwriter.h
+sharedlib_LDFLAGS=-module
+sharedlib_rootname=codegenerator
+sub_dirs=
+type=shared_library
+
+[uml/codegenerators/cppwriter.cpp]
+dist=true
+install=false
+install_location=
+type=SOURCE
+
+[uml/codegenerators/cppwriter.h]
+dist=true
+install=false
+install_location=
+type=HEADER
+
+[uml/codegenerators/factory.cpp]
+dist=true
+install=false
+install_location=
+type=SOURCE
+
+[uml/codegenerators/javawriter.cpp]
+dist=true
+install=false
+install_location=
+type=SOURCE
+
+[uml/codegenerators/javawriter.h]
+dist=true
+install=false
+install_location=
+type=HEADER
+
+[uml/codegenerators/phpwriter.cpp]
+dist=true
+install=false
+install_location=
+type=SOURCE
+
+[uml/codegenerators/phpwriter.h]
+dist=true
+install=false
+install_location=
+type=HEADER
+
+[uml/concept.cpp]
+dist=true
+install=false
+install_location=
+type=SOURCE
+
+[uml/concept.h]
+dist=true
+install=false
+install_location=
+type=HEADER
+
+[uml/conceptwidget.cpp]
+dist=true
+install=false
+install_location=
+type=SOURCE
+
+[uml/conceptwidget.h]
+dist=true
+install=false
+install_location=
+type=HEADER
+
+[uml/conceptwidgetdata.cpp]
+dist=true
+install=false
+install_location=
+type=SOURCE
+
+[uml/conceptwidgetdata.h]
+dist=true
+install=false
+install_location=
+type=HEADER
+
+[uml/dialogs/Makefile.am]
+files=uml/dialogs/assocpage.cpp,uml/dialogs/assocpage.h,uml/dialogs/assocpropdlg.cpp,uml/dialogs/assocpropdlg.h,uml/dialogs/classattpage.cpp,uml/dialogs/classattpage.h,uml/dialogs/classgenpage.cpp,uml/dialogs/classgenpage.h,uml/dialogs/classopspage.cpp,uml/dialogs/classopspage.h,uml/dialogs/classoptionspage.cpp,uml/dialogs/classoptionspage.h,uml/dialogs/classpropdlg.cpp,uml/dialogs/classpropdlg.h,uml/dialogs/diagramprintpage.cpp,uml/dialogs/diagramprintpage.h,uml/dialogs/parmpropdlg.cpp,uml/dialogs/parmpropdlg.h,uml/dialogs/selectopdlg.cpp,uml/dialogs/selectopdlg.h,uml/dialogs/settingsdlg.cpp,uml/dialogs/settingsdlg.h,uml/dialogs/statedialog.cpp,uml/dialogs/statedialog.h,uml/dialogs/umlattributedialog.h,uml/dialogs/umloperationdialog.h,uml/dialogs/umlviewdialog.h,uml/dialogs/umlwidgetcolorpage.h,uml/dialogs/umlattributedialog.cpp,uml/dialogs/umloperationdialog.cpp,uml/dialogs/umlviewdialog.cpp,uml/dialogs/umlwidgetcolorpage.cpp,uml/dialogs/activitypage.cpp,uml/dialogs/activitypage.h,uml/dialogs/activitydialog.cpp,uml/dialogs/activitydialog.h,uml/dialogs/notedialog.cpp,uml/dialogs/notedialog.h,uml/dialogs/configcodegenerators.cpp,uml/dialogs/configcodegenerators.h,uml/dialogs/configgeneratorsbase.ui,uml/dialogs/classwizard.cpp,uml/dialogs/classwizard.h,uml/dialogs/sellanguagesbase.ui,uml/dialogs/selectlanguagesdlg.cpp,uml/dialogs/selectlanguagesdlg.h,uml/dialogs/codegenerationoptionsbase.ui,uml/dialogs/codegenerationwizardbase.ui,uml/dialogs/codegenerationoptionspage.cpp,uml/dialogs/codegenerationoptionspage.h,uml/dialogs/codegenerationwizard.cpp,uml/dialogs/codegenerationwizard.h,uml/dialogs/overwritedialogue.cpp,uml/dialogs/overwritedialogue.h
+sharedlib_LDFLAGS=-version-info 0:0:0
+sharedlib_rootname=dialogs
+sub_dirs=
+type=static_library
+
+[uml/dialogs/activitydialog.cpp]
+dist=true
+install=false
+install_location=
+type=SOURCE
+
+[uml/dialogs/activitydialog.h]
+dist=true
+install=false
+install_location=
+type=HEADER
+
+[uml/dialogs/activitypage.cpp]
+dist=true
+install=false
+install_location=
+type=SOURCE
+
+[uml/dialogs/activitypage.h]
+dist=true
+install=false
+install_location=
+type=HEADER
+
+[uml/dialogs/assocpage.cpp]
+dist=true
+install=false
+install_location=
+type=SOURCE
+
+[uml/dialogs/assocpage.h]
+dist=true
+install=false
+install_location=
+type=HEADER
+
+[uml/dialogs/assocpropdlg.cpp]
+dist=true
+install=false
+install_location=
+type=SOURCE
+
+[uml/dialogs/assocpropdlg.h]
+dist=true
+install=false
+install_location=
+type=HEADER
+
+[uml/dialogs/classattpage.cpp]
+dist=true
+install=false
+install_location=
+type=SOURCE
+
+[uml/dialogs/classattpage.h]
+dist=true
+install=false
+install_location=
+type=HEADER
+
+[uml/dialogs/classgenpage.cpp]
+dist=true
+install=false
+install_location=
+type=SOURCE
+
+[uml/dialogs/classgenpage.h]
+dist=true
+install=false
+install_location=
+type=HEADER
+
+[uml/dialogs/classopspage.cpp]
+dist=true
+install=false
+install_location=
+type=SOURCE
+
+[uml/dialogs/classopspage.h]
+dist=true
+install=false
+install_location=
+type=HEADER
+
+[uml/dialogs/classoptionspage.cpp]
+dist=true
+install=false
+install_location=
+type=SOURCE
+
+[uml/dialogs/classoptionspage.h]
+dist=true
+install=false
+install_location=
+type=HEADER
+
+[uml/dialogs/classpropdlg.cpp]
+dist=true
+install=false
+install_location=
+type=SOURCE
+
+[uml/dialogs/classpropdlg.h]
+dist=true
+install=false
+install_location=
+type=HEADER
+
+[uml/dialogs/classselectionpage.cpp]
+dist=true
+install=false
+install_location=
+type=SOURCE
+
+[uml/dialogs/classselectionpage.h]
+dist=false
+install=false
+install_location=
+type=HEADER
+
+[uml/dialogs/classwizard.cpp]
+dist=true
+install=false
+install_location=
+type=SOURCE
+
+[uml/dialogs/classwizard.h]
+dist=true
+install=false
+install_location=
+type=HEADER
+
+[uml/dialogs/codegenerationoptionsbase.ui]
+dist=true
+install=false
+install_location=
+type=SOURCE
+
+[uml/dialogs/codegenerationoptionspage.cpp]
+dist=true
+install=false
+install_location=
+type=SOURCE
+
+[uml/dialogs/codegenerationoptionspage.h]
+dist=true
+install=false
+install_location=
+type=HEADER
+
+[uml/dialogs/codegenerationwizard.cpp]
+dist=true
+install=false
+install_location=
+type=SOURCE
+
+[uml/dialogs/codegenerationwizard.h]
+dist=true
+install=false
+install_location=
+type=HEADER
+
+[uml/dialogs/codegenerationwizardbase.ui]
+dist=true
+install=false
+install_location=
+type=SOURCE
+
+[uml/dialogs/codegenwizard.cpp]
+dist=true
+install=false
+install_location=
+type=SOURCE
+
+[uml/dialogs/codegenwizard.h]
+dist=true
+install=false
+install_location=
+type=HEADER
+
+[uml/dialogs/codeoptionspage.cpp]
+dist=true
+install=false
+install_location=
+type=SOURCE
+
+[uml/dialogs/codeoptionspage.h]
+dist=true
+install=false
+install_location=
+type=HEADER
+
+[uml/dialogs/configcodegenerators.cpp]
+dist=true
+install=false
+install_location=
+type=SOURCE
+
+[uml/dialogs/configcodegenerators.h]
+dist=true
+install=false
+install_location=
+type=HEADER
+
+[uml/dialogs/configgeneratorsbase.ui]
+dist=true
+install=false
+install_location=
+type=SOURCE
+
+[uml/dialogs/diagramprintpage.cpp]
+dist=true
+install=false
+install_location=
+type=SOURCE
+
+[uml/dialogs/diagramprintpage.h]
+dist=true
+install=false
+install_location=
+type=HEADER
+
+[uml/dialogs/notedialog.cpp]
+dist=true
+install=false
+install_location=
+type=SOURCE
+
+[uml/dialogs/notedialog.h]
+dist=true
+install=false
+install_location=
+type=HEADER
+
+[uml/dialogs/overwritedialogue.cpp]
+dist=true
+install=false
+install_location=
+type=SOURCE
+
+[uml/dialogs/overwritedialogue.h]
+dist=true
+install=false
+install_location=
+type=HEADER
+
+[uml/dialogs/parmpropdlg.cpp]
+dist=true
+install=false
+install_location=
+type=SOURCE
+
+[uml/dialogs/parmpropdlg.h]
+dist=true
+install=false
+install_location=
+type=HEADER
+
+[uml/dialogs/selectlanguagesdlg.cpp]
+dist=true
+install=false
+install_location=
+type=SOURCE
+
+[uml/dialogs/selectlanguagesdlg.h]
+dist=true
+install=false
+install_location=
+type=HEADER
+
+[uml/dialogs/selectopdlg.cpp]
+dist=true
+install=false
+install_location=
+type=SOURCE
+
+[uml/dialogs/selectopdlg.h]
+dist=true
+install=false
+install_location=
+type=HEADER
+
+[uml/dialogs/sellanguagesbase.ui]
+dist=true
+install=false
+install_location=
+type=SOURCE
+
+[uml/dialogs/settingsdlg.cpp]
+dist=true
+install=false
+install_location=
+type=SOURCE
+
+[uml/dialogs/settingsdlg.h]
+dist=true
+install=false
+install_location=
+type=HEADER
+
+[uml/dialogs/statedialog.cpp]
+dist=true
+install=false
+install_location=
+type=SOURCE
+
+[uml/dialogs/statedialog.h]
+dist=true
+install=false
+install_location=
+type=HEADER
+
+[uml/dialogs/umlattributedialog.cpp]
+dist=true
+install=false
+install_location=
+type=SOURCE
+
+[uml/dialogs/umlattributedialog.h]
+dist=true
+install=false
+install_location=
+type=HEADER
+
+[uml/dialogs/umloperationdialog.cpp]
+dist=true
+install=false
+install_location=
+type=SOURCE
+
+[uml/dialogs/umloperationdialog.h]
+dist=true
+install=false
+install_location=
+type=HEADER
+
+[uml/dialogs/umlviewdialog.cpp]
+dist=true
+install=false
+install_location=
+type=SOURCE
+
+[uml/dialogs/umlviewdialog.h]
+dist=true
+install=false
+install_location=
+type=HEADER
+
+[uml/dialogs/umlwidgetcolorpage.cpp]
+dist=true
+install=false
+install_location=
+type=SOURCE
+
+[uml/dialogs/umlwidgetcolorpage.h]
+dist=true
+install=false
+install_location=
+type=HEADER
+
+[uml/docwindow.cpp]
+dist=true
+install=false
+install_location=
+type=SOURCE
+
+[uml/docwindow.h]
+dist=true
+install=false
+install_location=
+type=HEADER
+
+[uml/floatingtext.cpp]
+dist=true
+install=false
+install_location=
+type=SOURCE
+
+[uml/floatingtext.h]
+dist=true
+install=false
+install_location=
+type=HEADER
+
+[uml/floatingtextdata.cpp]
+dist=true
+install=false
+install_location=
+type=SOURCE
+
+[uml/floatingtextdata.h]
+dist=true
+install=false
+install_location=
+type=HEADER
+
+[uml/headings/Makefile.am]
+files=uml/headings/heading.java,uml/headings/heading.h,uml/headings/template.cpp,uml/headings/heading.php,uml/headings/heading.cpp
+sub_dirs=
+type=normal
+
+[uml/headings/heading.cpp]
+dist=true
+install=true
+install_location=$$(kde_datadir)/umbrello/headings/heading.cpp
+type=SOURCE
+
+[uml/headings/heading.h]
+dist=true
+install=true
+install_location=$$(kde_datadir)/umbrello/headings/heading.h
+type=DATA
+
+[uml/headings/heading.java]
+dist=true
+install=true
+install_location=$$(kde_datadir)/umbrello/headings/heading.java
+type=DATA
+
+[uml/headings/heading.php]
+dist=true
+install=true
+install_location=$$(kde_datadir)/umbrello/headings/heading.php
+type=DATA
+
+[uml/headings/template.cpp]
+dist=false
+install=false
+install_location=$$(kde_datadir)/umbrello/headings/template.cpp
+type=DATA
+
+[uml/hi16-app-uml.png]
+dist=true
+install=true
+install_location=$$(kde_icondir)/hicolor/16x16/apps/umbrello.png
+type=DATA
+
+[uml/hi32-app-uml.png]
+dist=true
+install=true
+install_location=$$(kde_icondir)/hicolor/32x32/apps/umbrello.png
+type=DATA
+
+[uml/infowidget.cpp]
+dist=true
+install=false
+install_location=
+type=SOURCE
+
+[uml/infowidget.h]
+dist=true
+install=false
+install_location=
+type=HEADER
+
+[uml/kstartuplogo.cpp]
+dist=true
+install=false
+install_location=
+type=SOURCE
+
+[uml/kstartuplogo.h]
+dist=true
+install=false
+install_location=
+type=HEADER
+
+[uml/linepath.cpp]
+dist=true
+install=false
+install_location=
+type=SOURCE
+
+[uml/linepath.h]
+dist=true
+install=false
+install_location=
+type=HEADER
+
+[uml/listpopupmenu.cpp]
+dist=true
+install=false
+install_location=
+type=SOURCE
+
+[uml/listpopupmenu.h]
+dist=true
+install=false
+install_location=
+type=HEADER
+
+[uml/lo16-app-uml.png]
+dist=true
+install=true
+install_location=$$(kde_icondir)/locolor/16x16/apps/umbrello.png
+type=DATA
+
+[uml/lo32-app-uml.png]
+dist=true
+install=true
+install_location=$$(kde_icondir)/locolor/32x32/apps/umbrello.png
+type=DATA
+
+[uml/main.cpp]
+dist=true
+install=false
+install_location=
+type=SOURCE
+
+[uml/messagewidget.cpp]
+dist=true
+install=false
+install_location=
+type=SOURCE
+
+[uml/messagewidget.h]
+dist=true
+install=false
+install_location=
+type=HEADER
+
+[uml/messagewidgetdata.cpp]
+dist=true
+install=false
+install_location=
+type=SOURCE
+
+[uml/messagewidgetdata.h]
+dist=true
+install=false
+install_location=
+type=HEADER
+
+[uml/notewidget.cpp]
+dist=true
+install=false
+install_location=
+type=SOURCE
+
+[uml/notewidget.h]
+dist=true
+install=false
+install_location=
+type=HEADER
+
+[uml/notewidgetdata.cpp]
+dist=true
+install=false
+install_location=
+type=SOURCE
+
+[uml/notewidgetdata.h]
+dist=true
+install=false
+install_location=
+type=HEADER
+
+[uml/objectwidget.cpp]
+dist=true
+install=false
+install_location=
+type=SOURCE
+
+[uml/objectwidget.h]
+dist=true
+install=false
+install_location=
+type=HEADER
+
+[uml/objectwidgetdata.cpp]
+dist=true
+install=false
+install_location=
+type=SOURCE
+
+[uml/objectwidgetdata.h]
+dist=true
+install=false
+install_location=
+type=HEADER
+
+[uml/operation.cpp]
+dist=true
+install=false
+install_location=
+type=SOURCE
+
+[uml/operation.h]
+dist=true
+install=false
+install_location=
+type=HEADER
+
+[uml/pics/CVglobal_meth.png]
+dist=true
+install=true
+install_location=$$(kde_datadir)/umbrello/pics/CVglobal_meth.png
+type=DATA
+
+[uml/pics/CVglobal_var.png]
+dist=true
+install=true
+install_location=$$(kde_datadir)/umbrello/pics/CVglobal_var.png
+type=DATA
+
+[uml/pics/CVnamespace.png]
+dist=true
+install=true
+install_location=$$(kde_datadir)/umbrello/pics/CVnamespace.png
+type=DATA
+
+[uml/pics/CVprivate_meth.png]
+dist=true
+install=true
+install_location=$$(kde_datadir)/umbrello/pics/CVprivate_meth.png
+type=DATA
+
+[uml/pics/CVprivate_signal.png]
+dist=true
+install=true
+install_location=$$(kde_datadir)/umbrello/pics/CVprivate_signal.png
+type=DATA
+
+[uml/pics/CVprivate_slot.png]
+dist=true
+install=true
+install_location=$$(kde_datadir)/umbrello/pics/CVprivate_slot.png
+type=DATA
+
+[uml/pics/CVprivate_var.png]
+dist=true
+install=true
+install_location=$$(kde_datadir)/umbrello/pics/CVprivate_var.png
+type=DATA
+
+[uml/pics/CVprotected_meth.png]
+dist=true
+install=true
+install_location=$$(kde_datadir)/umbrello/pics/CVprotected_meth.png
+type=DATA
+
+[uml/pics/CVprotected_signal.png]
+dist=true
+install=true
+install_location=$$(kde_datadir)/umbrello/pics/CVprotected_signal.png
+type=DATA
+
+[uml/pics/CVprotected_slot.png]
+dist=true
+install=true
+install_location=$$(kde_datadir)/umbrello/pics/CVprotected_slot.png
+type=DATA
+
+[uml/pics/CVprotected_var.png]
+dist=true
+install=true
+install_location=$$(kde_datadir)/umbrello/pics/CVprotected_var.png
+type=DATA
+
+[uml/pics/CVpublic_meth.png]
+dist=true
+install=true
+install_location=$$(kde_datadir)/umbrello/pics/CVpublic_meth.png
+type=DATA
+
+[uml/pics/CVpublic_signal.png]
+dist=true
+install=true
+install_location=$$(kde_datadir)/umbrello/pics/CVpublic_signal.png
+type=DATA
+
+[uml/pics/CVpublic_slot.png]
+dist=true
+install=true
+install_location=$$(kde_datadir)/umbrello/pics/CVpublic_slot.png
+type=DATA
+
+[uml/pics/CVpublic_var.png]
+dist=true
+install=true
+install_location=$$(kde_datadir)/umbrello/pics/CVpublic_var.png
+type=DATA
+
+[uml/pics/CVstruct.png]
+dist=true
+install=true
+install_location=$$(kde_datadir)/umbrello/pics/CVstruct.png
+type=DATA
+
+[uml/pics/Makefile.am]
+files=uml/pics/actor.xpm,uml/pics/aggregation.xpm,uml/pics/anchor.xpm,uml/pics/arrow.xpm,uml/pics/association.xpm,uml/pics/broom.xpm,uml/pics/case.xpm,uml/pics/classicon.xpm,uml/pics/component.xpm,uml/pics/composition.xpm,uml/pics/constraint.xpm,uml/pics/CVglobal_meth.png,uml/pics/CVglobal_var.png,uml/pics/CVnamespace.png,uml/pics/CVprivate_meth.png,uml/pics/CVprivate_signal.png,uml/pics/CVprivate_slot.png,uml/pics/CVprivate_var.png,uml/pics/CVprotected_meth.png,uml/pics/CVprotected_signal.png,uml/pics/CVprotected_slot.png,uml/pics/CVprotected_var.png,uml/pics/CVpublic_meth.png,uml/pics/CVpublic_signal.png,uml/pics/CVpublic_slot.png,uml/pics/CVpublic_var.png,uml/pics/CVstruct.png,uml/pics/dependency.xpm,uml/pics/end_state.xpm,uml/pics/folder_green_open.png,uml/pics/folder_green.png,uml/pics/folder_grey_open.png,uml/pics/folder_grey.png,uml/pics/folder_home.png,uml/pics/generalization.xpm,uml/pics/hline.xpm,uml/pics/implements.xpm,uml/pics/initial_state.xpm,uml/pics/interface.xpm,uml/pics/largepackage.xpm,uml/pics/lifeline.xpm,uml/pics/line.xpm,uml/pics/message.xpm,uml/pics/note.xpm,uml/pics/object.xpm,uml/pics/output_win.xpm,uml/pics/realizes.xpm,uml/pics/rectangle.xpm,uml/pics/smallpackage.xpm,uml/pics/snapshot.xpm,uml/pics/startlogo.png,uml/pics/text.xpm,uml/pics/umlclass_template.xpm,uml/pics/umlclass.xpm,uml/pics/uniassoc.xpm,uml/pics/usecaserelation.xpm,uml/pics/vline.xpm,uml/pics/branch.xpm,uml/pics/fork.xpm
+sub_dirs=
+type=normal
+
+[uml/pics/actor.xpm]
+dist=true
+install=true
+install_location=$$(kde_datadir)/umbrello/pics/actor.xpm
+type=DATA
+
+[uml/pics/aggregation.xpm]
+dist=true
+install=true
+install_location=$$(kde_datadir)/umbrello/pics/aggregation.xpm
+type=DATA
+
+[uml/pics/anchor.xpm]
+dist=true
+install=true
+install_location=$$(kde_datadir)/umbrello/pics/anchor.xpm
+type=DATA
+
+[uml/pics/arrow.xpm]
+dist=true
+install=true
+install_location=$$(kde_datadir)/umbrello/pics/arrow.xpm
+type=DATA
+
+[uml/pics/association.xpm]
+dist=true
+install=true
+install_location=$$(kde_datadir)/umbrello/pics/association.xpm
+type=DATA
+
+[uml/pics/branch.xpm]
+dist=true
+install=true
+install_location=$$(kde_datadir)/umbrello/pics/branch.xpm
+type=DATA
+
+[uml/pics/broom.xpm]
+dist=true
+install=true
+install_location=$$(kde_datadir)/umbrello/pics/broom.xpm
+type=DATA
+
+[uml/pics/case.xpm]
+dist=true
+install=true
+install_location=$$(kde_datadir)/umbrello/pics/case.xpm
+type=DATA
+
+[uml/pics/classicon.xpm]
+dist=true
+install=true
+install_location=$$(kde_datadir)/umbrello/pics/classicon.xpm
+type=DATA
+
+[uml/pics/component.xpm]
+dist=true
+install=true
+install_location=$$(kde_datadir)/umbrello/pics/component.xpm
+type=DATA
+
+[uml/pics/composition.xpm]
+dist=true
+install=true
+install_location=$$(kde_datadir)/umbrello/pics/composition.xpm
+type=DATA
+
+[uml/pics/constraint.xpm]
+dist=true
+install=true
+install_location=$$(kde_datadir)/umbrello/pics/constraint.xpm
+type=DATA
+
+[uml/pics/dependency.xpm]
+dist=true
+install=true
+install_location=$$(kde_datadir)/umbrello/pics/dependency.xpm
+type=DATA
+
+[uml/pics/end_state.xpm]
+dist=true
+install=true
+install_location=$$(kde_datadir)/umbrello/pics/end_state.xpm
+type=DATA
+
+[uml/pics/folder_green.png]
+dist=true
+install=true
+install_location=$$(kde_datadir)/umbrello/pics/folder_green.png
+type=DATA
+
+[uml/pics/folder_green_open.png]
+dist=true
+install=true
+install_location=$$(kde_datadir)/umbrello/pics/folder_green_open.png
+type=DATA
+
+[uml/pics/folder_grey.png]
+dist=true
+install=true
+install_location=$$(kde_datadir)/umbrello/pics/folder_grey.png
+type=DATA
+
+[uml/pics/folder_grey_open.png]
+dist=true
+install=true
+install_location=$$(kde_datadir)/umbrello/pics/folder_grey_open.png
+type=DATA
+
+[uml/pics/folder_home.png]
+dist=true
+install=true
+install_location=$$(kde_datadir)/umbrello/pics/folder_home.png
+type=DATA
+
+[uml/pics/fork.xpm]
+dist=true
+install=true
+install_location=$$(kde_datadir)/umbrello/pics/fork.xpm
+type=DATA
+
+[uml/pics/generalization.xpm]
+dist=true
+install=true
+install_location=$$(kde_datadir)/umbrello/pics/generalization.xpm
+type=DATA
+
+[uml/pics/hline.xpm]
+dist=true
+install=true
+install_location=$$(kde_datadir)/umbrello/pics/hline.xpm
+type=DATA
+
+[uml/pics/implements.xpm]
+dist=true
+install=true
+install_location=$$(kde_datadir)/umbrello/pics/implements.xpm
+type=DATA
+
+[uml/pics/initial_state.xpm]
+dist=true
+install=true
+install_location=$$(kde_datadir)/umbrello/pics/initial_state.xpm
+type=DATA
+
+[uml/pics/interface.xpm]
+dist=true
+install=true
+install_location=$$(kde_datadir)/umbrello/pics/interface.xpm
+type=DATA
+
+[uml/pics/largepackage.xpm]
+dist=true
+install=true
+install_location=$$(kde_datadir)/umbrello/pics/largepackage.xpm
+type=DATA
+
+[uml/pics/lifeline.xpm]
+dist=true
+install=true
+install_location=$$(kde_datadir)/umbrello/pics/lifeline.xpm
+type=DATA
+
+[uml/pics/line.xpm]
+dist=true
+install=true
+install_location=$$(kde_datadir)/umbrello/pics/line.xpm
+type=DATA
+
+[uml/pics/message.xpm]
+dist=true
+install=true
+install_location=$$(kde_datadir)/umbrello/pics/message.xpm
+type=DATA
+
+[uml/pics/note.xpm]
+dist=true
+install=true
+install_location=$$(kde_datadir)/umbrello/pics/note.xpm
+type=DATA
+
+[uml/pics/object.xpm]
+dist=true
+install=true
+install_location=$$(kde_datadir)/umbrello/pics/object.xpm
+type=DATA
+
+[uml/pics/output_win.xpm]
+dist=true
+install=true
+install_location=$$(kde_datadir)/umbrello/pics/output_win.xpm
+type=DATA
+
+[uml/pics/realizes.xpm]
+dist=true
+install=true
+install_location=$$(kde_datadir)/umbrello/pics/realizes.xpm
+type=DATA
+
+[uml/pics/rectangle.xpm]
+dist=true
+install=true
+install_location=$$(kde_datadir)/umbrello/pics/rectangle.xpm
+type=DATA
+
+[uml/pics/smallpackage.xpm]
+dist=true
+install=true
+install_location=$$(kde_datadir)/umbrello/pics/smallpackage.xpm
+type=DATA
+
+[uml/pics/snapshot.xpm]
+dist=true
+install=true
+install_location=$$(kde_datadir)/umbrello/pics/snapshot.xpm
+type=DATA
+
+[uml/pics/startlogo.png]
+dist=true
+install=true
+install_location=$$(kde_datadir)/umbrello/pics/startlogo.png
+type=DATA
+
+[uml/pics/text.xpm]
+dist=true
+install=true
+install_location=$$(kde_datadir)/umbrello/pics/text.xpm
+type=DATA
+
+[uml/pics/umlclass.xpm]
+dist=true
+install=true
+install_location=$$(kde_datadir)/umbrello/pics/umlclass.xpm
+type=DATA
+
+[uml/pics/umlclass_template.xpm]
+dist=true
+install=true
+install_location=$$(kde_datadir)/umbrello/pics/umlclass_template.xpm
+type=DATA
+
+[uml/pics/uniassoc.xpm]
+dist=true
+install=true
+install_location=$$(kde_datadir)/umbrello/pics/uniassoc.xpm
+type=DATA
+
+[uml/pics/usecaserelation.xpm]
+dist=true
+install=true
+install_location=$$(kde_datadir)/umbrello/pics/usecaserelation.xpm
+type=DATA
+
+[uml/pics/vline.xpm]
+dist=true
+install=true
+install_location=$$(kde_datadir)/umbrello/pics/vline.xpm
+type=DATA
+
+[uml/seqlinewidget.cpp]
+dist=true
+install=false
+install_location=
+type=SOURCE
+
+[uml/seqlinewidget.h]
+dist=true
+install=false
+install_location=
+type=HEADER
+
+[uml/statewidget.cpp]
+dist=true
+install=false
+install_location=
+type=SOURCE
+
+[uml/statewidget.h]
+dist=true
+install=false
+install_location=
+type=HEADER
+
+[uml/statewidgetdata.cpp]
+dist=true
+install=false
+install_location=
+type=SOURCE
+
+[uml/statewidgetdata.h]
+dist=true
+install=false
+install_location=
+type=HEADER
+
+[uml/tips]
+dist=true
+install=true
+install_location=$$(kde_datadir)/umbrello/tips
+type=DATA
+
+[uml/uml.cpp]
+dist=true
+install=false
+install_location=
+type=SOURCE
+
+[uml/uml.desktop]
+dist=true
+install=true
+install_location=$$(kde_appsdir)/Development/umbrello.desktop
+type=DATA
+
+[uml/uml.h]
+dist=true
+install=false
+install_location=
+type=HEADER
+
+[uml/umldoc.cpp]
+dist=true
+install=false
+install_location=
+type=SOURCE
+
+[uml/umldoc.h]
+dist=true
+install=false
+install_location=
+type=HEADER
+
+[uml/umllistview.cpp]
+dist=true
+install=false
+install_location=
+type=SOURCE
+
+[uml/umllistview.h]
+dist=true
+install=false
+install_location=
+type=HEADER
+
+[uml/umllistviewitem.cpp]
+dist=true
+install=false
+install_location=
+type=SOURCE
+
+[uml/umllistviewitem.h]
+dist=true
+install=false
+install_location=
+type=HEADER
+
+[uml/umllistviewitemdata.cpp]
+dist=true
+install=false
+install_location=
+type=SOURCE
+
+[uml/umllistviewitemdata.h]
+dist=true
+install=false
+install_location=
+type=HEADER
+
+[uml/umllistviewitemdatalist.h]
+dist=true
+install=false
+install_location=
+type=HEADER
+
+[uml/umllistviewitemlist.h]
+dist=true
+install=false
+install_location=
+type=HEADER
+
+[uml/umlnamespace.cpp]
+dist=true
+install=false
+install_location=
+type=SOURCE
+
+[uml/umlnamespace.h]
+dist=true
+install=false
+install_location=
+type=HEADER
+
+[uml/umlobject.cpp]
+dist=true
+install=false
+install_location=
+type=SOURCE
+
+[uml/umlobject.h]
+dist=true
+install=false
+install_location=
+type=HEADER
+
+[uml/umlobjectlist.h]
+dist=true
+install=false
+install_location=
+type=HEADER
+
+[uml/umlui.rc]
+dist=true
+install=true
+install_location=$$(kde_datadir)/umbrello/umbrelloui.rc
+type=DATA
+
+[uml/umlview.cpp]
+dist=true
+install=false
+install_location=
+type=SOURCE
+
+[uml/umlview.h]
+dist=true
+install=false
+install_location=
+type=HEADER
+
+[uml/umlviewcanvas.cpp]
+dist=true
+install=false
+install_location=
+type=SOURCE
+
+[uml/umlviewcanvas.h]
+dist=true
+install=false
+install_location=
+type=HEADER
+
+[uml/umlviewdata.cpp]
+dist=true
+install=false
+install_location=
+type=SOURCE
+
+[uml/umlviewdata.h]
+dist=true
+install=false
+install_location=
+type=HEADER
+
+[uml/umlviewlist.h]
+dist=true
+install=false
+install_location=
+type=HEADER
+
+[uml/umlwidget.cpp]
+dist=true
+install=false
+install_location=
+type=SOURCE
+
+[uml/umlwidget.h]
+dist=true
+install=false
+install_location=
+type=HEADER
+
+[uml/umlwidgetdata.cpp]
+dist=true
+install=false
+install_location=
+type=SOURCE
+
+[uml/umlwidgetdata.h]
+dist=true
+install=false
+install_location=
+type=HEADER
+
+[uml/umlwidgetlist.h]
+dist=true
+install=false
+install_location=
+type=HEADER
+
+[uml/usecase.cpp]
+dist=true
+install=false
+install_location=
+type=SOURCE
+
+[uml/usecase.h]
+dist=true
+install=false
+install_location=
+type=HEADER
+
+[uml/usecasewidget.cpp]
+dist=true
+install=false
+install_location=
+type=SOURCE
+
+[uml/usecasewidget.h]
+dist=true
+install=false
+install_location=
+type=HEADER
+
+[uml/usecasewidgetdata.cpp]
+dist=true
+install=false
+install_location=
+type=SOURCE
+
+[uml/usecasewidgetdata.h]
+dist=true
+install=false
+install_location=
+type=HEADER
+
+[uml/worktoolbar.cpp]
+dist=true
+install=false
+install_location=
+type=SOURCE
+
+[uml/worktoolbar.h]
+dist=true
+install=false
+install_location=
+type=HEADER
+
+[uml/x-uml.desktop]
+dist=true
+install=true
+install_location=$$(kde_mimedir)/application/x-uml.desktop
+type=DATA
diff --git a/umbrello/uml.lsm b/umbrello/uml.lsm
new file mode 100644
index 00000000..9c8af94f
--- /dev/null
+++ b/umbrello/uml.lsm
@@ -0,0 +1,14 @@
+Begin3
+Title: Umbrello UML Modeller
+Version: 1.5.8
+Entered-date:
+Description: A UML diagram Modeller
+Keywords: uml diagram modeller
+Author: Paul Hensgen <phensgen @ users.sourceforge.net>
+Maintained-by: Umbrello UML Modeller developers <uml-devel @ lists.sourceforge.net>
+Primary-site: http://uml.sf.net
+Home-page: http://uml.sf.net
+Original-site:
+Platforms: KDE 3.3+
+Copying-policy: GPL
+End